fbdev updates for 3.7

It includes:
 - large updates for OMAP
   - basic OMAP5 DSS support for DPI and DSI outputs
   - large cleanups and restructuring
 - some update to Exynos and da8xx-fb
 - removal of the pnx4008 driver (arch removed)
 - various other small patches
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.12 (GNU/Linux)
 
 iQIcBAABAgAGBQJQdz+EAAoJECSVL5KnPj1PyiMP/R84rSfGUbDIh0Cr6g1Snk76
 h2/1i19TuEgJAWH1q0lnwhqMC3yYmkA1Hz3ulT35KS+/L3IEgUosOESrxZIJhxHI
 f55pk3v8dueN0rx3OhCknLT7hGpVsI4vSN+3yf9LetDp3qt8UVwKLFzVij1VF/MS
 b1wA+RBe1IYMR0bB6pK0AgMZZiBkQMta5rKs5IfDDi8kMgMT4+V8l/iFmt2Ue833
 VxdPw+3reKshBXKTkQt1Usv4JRtG7OgwpRmFhxOo+ag0dxPLeUe/3wZG54qfOywF
 7jK+mnxmW8oZxLkGBvygrmzd40MH6H09N7i/IKVQ0GZoHgAqWWe7VvWahpg8LzwB
 ynktwWZ3Va98p5u/BIafBr0ZOU30mPL8N0aqR3HU7H12Wq21HtwcF+ewiT4vnMc8
 CKzt6VL0qY1tOOdzJzmICzvXGkbBGfj9YOUptJALCIa3bLwZodyQ/bKq8V/bHdTg
 2yyUmVhVf/r5qLermjQN8TjFMpRf2SNwTUUYvhUNwZ4yZMVWZgjjhtAlGGFCA/Bs
 qMRuNpbHMedhzNV4py418Xe3Hwg6TLPuWSWGJ67SG8hxsYy2hq7GebSsXXdC7xG9
 N5DMpA88IQR2nLwkr/pslFqjRsUI6ULvIfxibHEoNjQ0GOY9f+hEWbdHBZPI+0Gv
 Ea9d7nyhmYTZgvRcd9U0
 =EJUS
 -----END PGP SIGNATURE-----

Merge tag 'fbdev-updates-for-3.7' of git://github.com/schandinat/linux-2.6

Pull fbdev updates from Florian Tobias Schandinat:
 "This includes:
   - large updates for OMAP
     - basic OMAP5 DSS support for DPI and DSI outputs
     - large cleanups and restructuring
   - some update to Exynos and da8xx-fb
   - removal of the pnx4008 driver (arch removed)
   - various other small patches"

Fix up some trivial conflicts (mostly just include line changes, but
also some due to the renaming of the deferred work functions by Tejun).

* tag 'fbdev-updates-for-3.7' of git://github.com/schandinat/linux-2.6: (193 commits)
  gbefb: fix compile error
  video: mark nuc900fb_map_video_memory as __devinit
  video/mx3fb: set .owner to prevent module unloading while being used
  video: exynos_dp: use clk_prepare_enable and clk_disable_unprepare
  drivers/video/exynos/exynos_mipi_dsi.c: fix error return code
  drivers/video/savage/savagefb_driver.c: fix error return code
  video: s3c-fb: use clk_prepare_enable and clk_disable_unprepare
  da8xx-fb: save and restore LCDC context across suspend/resume cycle
  da8xx-fb: add pm_runtime support
  video/udlfb: fix line counting in fb_write
  OMAPDSS: add missing include for string.h
  OMAPDSS: DISPC: Configure color conversion coefficients for writeback
  OMAPDSS: DISPC: Add manager like functions for writeback
  OMAPDSS: DISPC: Configure writeback FIFOs
  OMAPDSS: DISPC: Configure writeback specific parameters in dispc_wb_setup()
  OMAPDSS: DISPC: Configure overlay-like parameters in dispc_wb_setup
  OMAPDSS: DISPC: Add function to set channel in for writeback
  OMAPDSS: DISPC: Don't set chroma resampling bit for writeback
  OMAPDSS: DISPC: Downscale chroma if plane is writeback
  OMAPDSS: DISPC: Configure input and output sizes for writeback
  ...
This commit is contained in:
Linus Torvalds 2012-10-12 10:21:02 +09:00
commit 5f76945a9c
127 changed files with 5347 additions and 4718 deletions

View file

@ -2139,21 +2139,6 @@ config FB_UDL
mplayer -vo fbdev. Supports all USB 2.0 era DisplayLink devices.
To compile as a module, choose M here: the module name is udlfb.
config FB_PNX4008_DUM
tristate "Display Update Module support on Philips PNX4008 board"
depends on FB && ARCH_PNX4008
---help---
Say Y here to enable support for PNX4008 Display Update Module (DUM)
config FB_PNX4008_DUM_RGB
tristate "RGB Framebuffer support on Philips PNX4008 board"
depends on FB_PNX4008_DUM
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
---help---
Say Y here to enable support for PNX4008 RGB Framebuffer
config FB_IBM_GXT4500
tristate "Framebuffer support for IBM GXT4500P adaptor"
depends on FB && PPC

View file

@ -127,8 +127,6 @@ obj-$(CONFIG_FB_S3C) += s3c-fb.o
obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o
obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o
obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o
obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/
obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/
obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o
obj-$(CONFIG_FB_PS3) += ps3fb.o
obj-$(CONFIG_FB_SM501) += sm501fb.o

View file

@ -949,7 +949,6 @@ static int round_down_bpp = 1; /* for mode probing */
static int amifb_ilbm = 0; /* interleaved or normal bitplanes */
static int amifb_inverse = 0;
static u32 amifb_hfmin __initdata; /* monitor hfreq lower limit (Hz) */
static u32 amifb_hfmax __initdata; /* monitor hfreq upper limit (Hz) */
@ -2355,7 +2354,6 @@ static int __init amifb_setup(char *options)
if (!*this_opt)
continue;
if (!strcmp(this_opt, "inverse")) {
amifb_inverse = 1;
fb_invert_cmaps();
} else if (!strcmp(this_opt, "ilbm"))
amifb_ilbm = 1;

View file

@ -552,6 +552,7 @@ static int __devinit arcfb_probe(struct platform_device *dev)
"arcfb", info)) {
printk(KERN_INFO
"arcfb: Failed req IRQ %d\n", par->irq);
retval = -EBUSY;
goto err1;
}
}

View file

@ -931,8 +931,10 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
}
info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
if (!info->screen_base)
if (!info->screen_base) {
ret = -ENOMEM;
goto release_intmem;
}
/*
* Don't clear the framebuffer -- someone may have set
@ -960,6 +962,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
sinfo->mmio = ioremap(info->fix.mmio_start, info->fix.mmio_len);
if (!sinfo->mmio) {
dev_err(dev, "cannot map LCDC registers\n");
ret = -ENOMEM;
goto release_mem;
}

View file

@ -760,18 +760,20 @@ static int __devinit bfin_lq035_probe(struct platform_device *pdev)
bfin_lq035_fb.flags = FBINFO_DEFAULT;
bfin_lq035_fb.pseudo_palette = kzalloc(sizeof(u32) * 16, GFP_KERNEL);
bfin_lq035_fb.pseudo_palette = devm_kzalloc(&pdev->dev,
sizeof(u32) * 16,
GFP_KERNEL);
if (bfin_lq035_fb.pseudo_palette == NULL) {
pr_err("failed to allocate pseudo_palette\n");
ret = -ENOMEM;
goto out_palette;
goto out_table;
}
if (fb_alloc_cmap(&bfin_lq035_fb.cmap, NBR_PALETTE, 0) < 0) {
pr_err("failed to allocate colormap (%d entries)\n",
NBR_PALETTE);
ret = -EFAULT;
goto out_cmap;
goto out_table;
}
if (register_framebuffer(&bfin_lq035_fb) < 0) {
@ -804,9 +806,6 @@ out_lcd:
unregister_framebuffer(&bfin_lq035_fb);
out_reg:
fb_dealloc_cmap(&bfin_lq035_fb.cmap);
out_cmap:
kfree(bfin_lq035_fb.pseudo_palette);
out_palette:
out_table:
dma_free_coherent(NULL, TOTAL_VIDEO_MEM_SIZE, fb_buffer, 0);
fb_buffer = NULL;
@ -834,7 +833,6 @@ static int __devexit bfin_lq035_remove(struct platform_device *pdev)
free_dma(CH_PPI);
kfree(bfin_lq035_fb.pseudo_palette);
fb_dealloc_cmap(&bfin_lq035_fb.cmap);

View file

@ -525,6 +525,7 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
info = fbinfo->par;
info->fb = fbinfo;
info->dev = &pdev->dev;
spin_lock_init(&info->lock);
platform_set_drvdata(pdev, fbinfo);
@ -601,7 +602,8 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
fbinfo->fbops = &bfin_bf54x_fb_ops;
fbinfo->pseudo_palette = kzalloc(sizeof(u32) * 16, GFP_KERNEL);
fbinfo->pseudo_palette = devm_kzalloc(&pdev->dev, sizeof(u32) * 16,
GFP_KERNEL);
if (!fbinfo->pseudo_palette) {
printk(KERN_ERR DRIVER_NAME
"Fail to allocate pseudo_palette\n");
@ -616,7 +618,7 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
"Fail to allocate colormap (%d entries)\n",
BFIN_LCD_NBR_PALETTE_ENTRIES);
ret = -EFAULT;
goto out5;
goto out4;
}
if (request_ports(info)) {
@ -671,8 +673,6 @@ out7:
free_ports(info);
out6:
fb_dealloc_cmap(&fbinfo->cmap);
out5:
kfree(fbinfo->pseudo_palette);
out4:
dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer,
info->dma_handle);
@ -699,7 +699,6 @@ static int __devexit bfin_bf54x_remove(struct platform_device *pdev)
dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer,
info->dma_handle);
kfree(fbinfo->pseudo_palette);
fb_dealloc_cmap(&fbinfo->cmap);
#ifndef NO_BL_SUPPORT

View file

@ -577,6 +577,7 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
info = fbinfo->par;
info->fb = fbinfo;
info->dev = &pdev->dev;
spin_lock_init(&info->lock);
info->disp_info = pdev->dev.platform_data;
@ -853,17 +854,7 @@ static struct platform_driver bfin_lq035q1_driver = {
},
};
static int __init bfin_lq035q1_driver_init(void)
{
return platform_driver_register(&bfin_lq035q1_driver);
}
module_init(bfin_lq035q1_driver_init);
static void __exit bfin_lq035q1_driver_cleanup(void)
{
platform_driver_unregister(&bfin_lq035q1_driver);
}
module_exit(bfin_lq035q1_driver_cleanup);
module_platform_driver(bfin_lq035q1_driver);
MODULE_DESCRIPTION("Blackfin TFT LCD Driver");
MODULE_LICENSE("GPL");

View file

@ -447,6 +447,7 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev)
info = fbinfo->par;
info->fb = fbinfo;
info->dev = &pdev->dev;
spin_lock_init(&info->lock);
platform_set_drvdata(pdev, fbinfo);

View file

@ -319,8 +319,10 @@ static int __devinit bw2_probe(struct platform_device *op)
info->screen_base = of_ioremap(&op->resource[0], 0,
info->fix.smem_len, "bw2 ram");
if (!info->screen_base)
if (!info->screen_base) {
err = -ENOMEM;
goto out_unmap_regs;
}
bw2_blank(FB_BLANK_UNBLANK, info);

View file

@ -398,7 +398,8 @@ static int __devinit cg3_probe(struct platform_device *op)
goto out_unmap_screen;
}
if (fb_alloc_cmap(&info->cmap, 256, 0))
err = fb_alloc_cmap(&info->cmap, 256, 0);
if (err)
goto out_unmap_screen;
fb_set_cmap(&info->cmap, info);

View file

@ -348,7 +348,8 @@ static int __devinit cobalt_lcdfb_probe(struct platform_device *dev)
}
info->screen_size = resource_size(res);
info->screen_base = ioremap(res->start, info->screen_size);
info->screen_base = devm_ioremap(&dev->dev, res->start,
info->screen_size);
info->fbops = &cobalt_lcd_fbops;
info->fix = cobalt_lcdfb_fix;
info->fix.smem_start = res->start;
@ -359,7 +360,6 @@ static int __devinit cobalt_lcdfb_probe(struct platform_device *dev)
retval = register_framebuffer(info);
if (retval < 0) {
iounmap(info->screen_base);
framebuffer_release(info);
return retval;
}
@ -380,7 +380,6 @@ static int __devexit cobalt_lcdfb_remove(struct platform_device *dev)
info = platform_get_drvdata(dev);
if (info) {
iounmap(info->screen_base);
unregister_framebuffer(info);
framebuffer_release(info);
}

View file

@ -1092,7 +1092,7 @@ static const unsigned char fontdata_mini_4x6[FONTDATAMAX] = {
/*{*/ /* Char 124: '|' */
0x44, /*= [ * ] */
0x44, /*= [ * ] */
0x00, /*= [ ] */
0x44, /*= [ * ] */
0x44, /*= [ * ] */
0x44, /*= [ * ] */
0x00, /*= [ ] */

View file

@ -127,7 +127,7 @@ static const unsigned char fontdata_sun8x16[FONTDATAMAX] = {
/*y*/ 0x00,0x00,0x00,0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7e,0x06,0x0c,0xf8,0x00,
/*z*/ 0x00,0x00,0x00,0x00,0x00,0xfe,0xcc,0x18,0x30,0x60,0xc6,0xfe,0x00,0x00,0x00,0x00,
/*{*/ 0x00,0x00,0x0e,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0e,0x00,0x00,0x00,0x00,
/*|*/ 0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
/*|*/ 0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
/*}*/ 0x00,0x00,0x70,0x18,0x18,0x18,0x0e,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00,
/*~*/ 0x00,0x00,0x76,0xdc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
/* */ 0x00,0x00,0x00,0x00,0x10,0x38,0x6c,0xc6,0xc6,0xc6,0xfe,0x00,0x00,0x00,0x00,0x00,

View file

@ -1804,8 +1804,10 @@ cyberpro_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
cfb->irq = dev->irq;
cfb->region = pci_ioremap_bar(dev, 0);
if (!cfb->region)
if (!cfb->region) {
err = -ENOMEM;
goto failed_ioremap;
}
cfb->regs = cfb->region + MMIO_OFFSET;
cfb->fb.device = &dev->dev;

View file

@ -26,7 +26,9 @@
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <linux/pm_runtime.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <linux/clk.h>
#include <linux/cpufreq.h>
#include <linux/console.h>
@ -48,6 +50,7 @@
#define LCD_PL_LOAD_DONE BIT(6)
#define LCD_FIFO_UNDERFLOW BIT(5)
#define LCD_SYNC_LOST BIT(2)
#define LCD_FRAME_DONE BIT(0)
/* LCD DMA Control Register */
#define LCD_DMA_BURST_SIZE(x) ((x) << 4)
@ -86,6 +89,8 @@
#define LCD_V2_LIDD_CLK_EN BIT(1)
#define LCD_V2_CORE_CLK_EN BIT(0)
#define LCD_V2_LPP_B10 26
#define LCD_V2_TFT_24BPP_MODE BIT(25)
#define LCD_V2_TFT_24BPP_UNPACK BIT(26)
/* LCD Raster Timing 2 Register */
#define LCD_AC_BIAS_TRANSITIONS_PER_INT(x) ((x) << 16)
@ -135,6 +140,8 @@ static void __iomem *da8xx_fb_reg_base;
static struct resource *lcdc_regs;
static unsigned int lcd_revision;
static irq_handler_t lcdc_irq_handler;
static wait_queue_head_t frame_done_wq;
static int frame_done_flag;
static inline unsigned int lcdc_read(unsigned int addr)
{
@ -156,7 +163,6 @@ struct da8xx_fb_par {
unsigned int dma_end;
struct clk *lcdc_clk;
int irq;
unsigned short pseudo_palette[16];
unsigned int palette_sz;
unsigned int pxl_clk;
int blank;
@ -175,6 +181,7 @@ struct da8xx_fb_par {
unsigned int lcd_fck_rate;
#endif
void (*panel_power_ctrl)(int);
u32 pseudo_palette[16];
};
/* Variable Screen Information */
@ -288,13 +295,26 @@ static inline void lcd_enable_raster(void)
}
/* Disable the Raster Engine of the LCD Controller */
static inline void lcd_disable_raster(void)
static inline void lcd_disable_raster(bool wait_for_frame_done)
{
u32 reg;
int ret;
reg = lcdc_read(LCD_RASTER_CTRL_REG);
if (reg & LCD_RASTER_ENABLE)
lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG);
else
/* return if already disabled */
return;
if ((wait_for_frame_done == true) && (lcd_revision == LCD_VERSION_2)) {
frame_done_flag = 0;
ret = wait_event_interruptible_timeout(frame_done_wq,
frame_done_flag != 0,
msecs_to_jiffies(50));
if (ret == 0)
pr_err("LCD Controller timed out\n");
}
}
static void lcd_blit(int load_mode, struct da8xx_fb_par *par)
@ -321,7 +341,8 @@ static void lcd_blit(int load_mode, struct da8xx_fb_par *par)
} else {
reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) |
LCD_V2_END_OF_FRAME0_INT_ENA |
LCD_V2_END_OF_FRAME1_INT_ENA;
LCD_V2_END_OF_FRAME1_INT_ENA |
LCD_FRAME_DONE;
lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG);
}
reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE;
@ -499,6 +520,9 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
{
u32 reg;
if (bpp > 16 && lcd_revision == LCD_VERSION_1)
return -EINVAL;
/* Set the Panel Width */
/* Pixels per line = (PPL + 1)*16 */
if (lcd_revision == LCD_VERSION_1) {
@ -542,14 +566,19 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(1 << 8);
if (raster_order)
reg |= LCD_RASTER_ORDER;
lcdc_write(reg, LCD_RASTER_CTRL_REG);
par->palette_sz = 16 * 2;
switch (bpp) {
case 1:
case 2:
case 4:
case 16:
par->palette_sz = 16 * 2;
break;
case 24:
reg |= LCD_V2_TFT_24BPP_MODE;
case 32:
reg |= LCD_V2_TFT_24BPP_UNPACK;
break;
case 8:
@ -560,9 +589,12 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
return -EINVAL;
}
lcdc_write(reg, LCD_RASTER_CTRL_REG);
return 0;
}
#define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16)
static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
struct fb_info *info)
@ -578,13 +610,38 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
if (info->fix.visual == FB_VISUAL_DIRECTCOLOR)
return 1;
if (info->var.bits_per_pixel == 4) {
if (regno > 15)
return 1;
if (info->var.bits_per_pixel > 16 && lcd_revision == LCD_VERSION_1)
return -EINVAL;
if (info->var.grayscale) {
pal = regno;
} else {
switch (info->fix.visual) {
case FB_VISUAL_TRUECOLOR:
red = CNVT_TOHW(red, info->var.red.length);
green = CNVT_TOHW(green, info->var.green.length);
blue = CNVT_TOHW(blue, info->var.blue.length);
break;
case FB_VISUAL_PSEUDOCOLOR:
switch (info->var.bits_per_pixel) {
case 4:
if (regno > 15)
return -EINVAL;
if (info->var.grayscale) {
pal = regno;
} else {
red >>= 4;
green >>= 8;
blue >>= 12;
pal = red & 0x0f00;
pal |= green & 0x00f0;
pal |= blue & 0x000f;
}
if (regno == 0)
pal |= 0x2000;
palette[regno] = pal;
break;
case 8:
red >>= 4;
green >>= 8;
blue >>= 12;
@ -592,36 +649,36 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
pal = (red & 0x0f00);
pal |= (green & 0x00f0);
pal |= (blue & 0x000f);
if (palette[regno] != pal) {
update_hw = 1;
palette[regno] = pal;
}
break;
}
if (regno == 0)
pal |= 0x2000;
palette[regno] = pal;
break;
}
} else if (info->var.bits_per_pixel == 8) {
red >>= 4;
green >>= 8;
blue >>= 12;
/* Truecolor has hardware independent palette */
if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
u32 v;
pal = (red & 0x0f00);
pal |= (green & 0x00f0);
pal |= (blue & 0x000f);
if (regno > 15)
return -EINVAL;
if (palette[regno] != pal) {
update_hw = 1;
palette[regno] = pal;
v = (red << info->var.red.offset) |
(green << info->var.green.offset) |
(blue << info->var.blue.offset);
switch (info->var.bits_per_pixel) {
case 16:
((u16 *) (info->pseudo_palette))[regno] = v;
break;
case 24:
case 32:
((u32 *) (info->pseudo_palette))[regno] = v;
break;
}
} else if ((info->var.bits_per_pixel == 16) && regno < 16) {
red >>= (16 - info->var.red.length);
red <<= info->var.red.offset;
green >>= (16 - info->var.green.length);
green <<= info->var.green.offset;
blue >>= (16 - info->var.blue.length);
blue <<= info->var.blue.offset;
par->pseudo_palette[regno] = red | green | blue;
if (palette[0] != 0x4000) {
update_hw = 1;
palette[0] = 0x4000;
@ -634,11 +691,12 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
return 0;
}
#undef CNVT_TOHW
static void lcd_reset(struct da8xx_fb_par *par)
{
/* Disable the Raster if previously Enabled */
lcd_disable_raster();
lcd_disable_raster(false);
/* DMA has to be disabled */
lcdc_write(0, LCD_DMA_CTRL_REG);
@ -734,7 +792,7 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg)
u32 stat = lcdc_read(LCD_MASKED_STAT_REG);
if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
lcd_disable_raster();
lcd_disable_raster(false);
lcdc_write(stat, LCD_MASKED_STAT_REG);
lcd_enable_raster();
} else if (stat & LCD_PL_LOAD_DONE) {
@ -744,7 +802,7 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg)
* interrupt via the following write to the status register. If
* this is done after then one gets multiple PL done interrupts.
*/
lcd_disable_raster();
lcd_disable_raster(false);
lcdc_write(stat, LCD_MASKED_STAT_REG);
@ -775,6 +833,14 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg)
par->vsync_flag = 1;
wake_up_interruptible(&par->vsync_wait);
}
/* Set only when controller is disabled and at the end of
* active frame
*/
if (stat & BIT(0)) {
frame_done_flag = 1;
wake_up_interruptible(&frame_done_wq);
}
}
lcdc_write(0, LCD_END_OF_INT_IND_REG);
@ -789,7 +855,7 @@ static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg)
u32 reg_ras;
if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
lcd_disable_raster();
lcd_disable_raster(false);
lcdc_write(stat, LCD_STAT_REG);
lcd_enable_raster();
} else if (stat & LCD_PL_LOAD_DONE) {
@ -799,7 +865,7 @@ static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg)
* interrupt via the following write to the status register. If
* this is done after then one gets multiple PL done interrupts.
*/
lcd_disable_raster();
lcd_disable_raster(false);
lcdc_write(stat, LCD_STAT_REG);
@ -842,6 +908,9 @@ static int fb_check_var(struct fb_var_screeninfo *var,
{
int err = 0;
if (var->bits_per_pixel > 16 && lcd_revision == LCD_VERSION_1)
return -EINVAL;
switch (var->bits_per_pixel) {
case 1:
case 8:
@ -877,6 +946,26 @@ static int fb_check_var(struct fb_var_screeninfo *var,
var->transp.length = 0;
var->nonstd = 0;
break;
case 24:
var->red.offset = 16;
var->red.length = 8;
var->green.offset = 8;
var->green.length = 8;
var->blue.offset = 0;
var->blue.length = 8;
var->nonstd = 0;
break;
case 32:
var->transp.offset = 24;
var->transp.length = 8;
var->red.offset = 16;
var->red.length = 8;
var->green.offset = 8;
var->green.length = 8;
var->blue.offset = 0;
var->blue.length = 8;
var->nonstd = 0;
break;
default:
err = -EINVAL;
}
@ -898,9 +987,10 @@ static int lcd_da8xx_cpufreq_transition(struct notifier_block *nb,
if (val == CPUFREQ_POSTCHANGE) {
if (par->lcd_fck_rate != clk_get_rate(par->lcdc_clk)) {
par->lcd_fck_rate = clk_get_rate(par->lcdc_clk);
lcd_disable_raster();
lcd_disable_raster(true);
lcd_calc_clk_divider(par);
lcd_enable_raster();
if (par->blank == FB_BLANK_UNBLANK)
lcd_enable_raster();
}
}
@ -935,7 +1025,7 @@ static int __devexit fb_remove(struct platform_device *dev)
if (par->panel_power_ctrl)
par->panel_power_ctrl(0);
lcd_disable_raster();
lcd_disable_raster(true);
lcdc_write(0, LCD_RASTER_CTRL_REG);
/* disable DMA */
@ -948,8 +1038,8 @@ static int __devexit fb_remove(struct platform_device *dev)
dma_free_coherent(NULL, par->vram_size, par->vram_virt,
par->vram_phys);
free_irq(par->irq, par);
clk_disable(par->lcdc_clk);
clk_put(par->lcdc_clk);
pm_runtime_put_sync(&dev->dev);
pm_runtime_disable(&dev->dev);
framebuffer_release(info);
iounmap(da8xx_fb_reg_base);
release_mem_region(lcdc_regs->start, resource_size(lcdc_regs));
@ -1051,7 +1141,7 @@ static int cfb_blank(int blank, struct fb_info *info)
if (par->panel_power_ctrl)
par->panel_power_ctrl(0);
lcd_disable_raster();
lcd_disable_raster(true);
break;
default:
ret = -EINVAL;
@ -1183,9 +1273,9 @@ static int __devinit fb_probe(struct platform_device *device)
ret = -ENODEV;
goto err_ioremap;
}
ret = clk_enable(fb_clk);
if (ret)
goto err_clk_put;
pm_runtime_enable(&device->dev);
pm_runtime_get_sync(&device->dev);
/* Determine LCD IP Version */
switch (lcdc_read(LCD_PID_REG)) {
@ -1213,7 +1303,7 @@ static int __devinit fb_probe(struct platform_device *device)
if (i == ARRAY_SIZE(known_lcd_panels)) {
dev_err(&device->dev, "GLCD: No valid panel found\n");
ret = -ENODEV;
goto err_clk_disable;
goto err_pm_runtime_disable;
} else
dev_info(&device->dev, "GLCD: Found %s panel\n",
fb_pdata->type);
@ -1225,7 +1315,7 @@ static int __devinit fb_probe(struct platform_device *device)
if (!da8xx_fb_info) {
dev_dbg(&device->dev, "Memory allocation failed for fb_info\n");
ret = -ENOMEM;
goto err_clk_disable;
goto err_pm_runtime_disable;
}
par = da8xx_fb_info->par;
@ -1356,8 +1446,10 @@ static int __devinit fb_probe(struct platform_device *device)
if (lcd_revision == LCD_VERSION_1)
lcdc_irq_handler = lcdc_irq_handler_rev01;
else
else {
init_waitqueue_head(&frame_done_wq);
lcdc_irq_handler = lcdc_irq_handler_rev02;
}
ret = request_irq(par->irq, lcdc_irq_handler, 0,
DRIVER_NAME, par);
@ -1385,11 +1477,9 @@ err_release_fb_mem:
err_release_fb:
framebuffer_release(da8xx_fb_info);
err_clk_disable:
clk_disable(fb_clk);
err_clk_put:
clk_put(fb_clk);
err_pm_runtime_disable:
pm_runtime_put_sync(&device->dev);
pm_runtime_disable(&device->dev);
err_ioremap:
iounmap(da8xx_fb_reg_base);
@ -1401,6 +1491,69 @@ err_request_mem:
}
#ifdef CONFIG_PM
struct lcdc_context {
u32 clk_enable;
u32 ctrl;
u32 dma_ctrl;
u32 raster_timing_0;
u32 raster_timing_1;
u32 raster_timing_2;
u32 int_enable_set;
u32 dma_frm_buf_base_addr_0;
u32 dma_frm_buf_ceiling_addr_0;
u32 dma_frm_buf_base_addr_1;
u32 dma_frm_buf_ceiling_addr_1;
u32 raster_ctrl;
} reg_context;
static void lcd_context_save(void)
{
if (lcd_revision == LCD_VERSION_2) {
reg_context.clk_enable = lcdc_read(LCD_CLK_ENABLE_REG);
reg_context.int_enable_set = lcdc_read(LCD_INT_ENABLE_SET_REG);
}
reg_context.ctrl = lcdc_read(LCD_CTRL_REG);
reg_context.dma_ctrl = lcdc_read(LCD_DMA_CTRL_REG);
reg_context.raster_timing_0 = lcdc_read(LCD_RASTER_TIMING_0_REG);
reg_context.raster_timing_1 = lcdc_read(LCD_RASTER_TIMING_1_REG);
reg_context.raster_timing_2 = lcdc_read(LCD_RASTER_TIMING_2_REG);
reg_context.dma_frm_buf_base_addr_0 =
lcdc_read(LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
reg_context.dma_frm_buf_ceiling_addr_0 =
lcdc_read(LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
reg_context.dma_frm_buf_base_addr_1 =
lcdc_read(LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
reg_context.dma_frm_buf_ceiling_addr_1 =
lcdc_read(LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
reg_context.raster_ctrl = lcdc_read(LCD_RASTER_CTRL_REG);
return;
}
static void lcd_context_restore(void)
{
if (lcd_revision == LCD_VERSION_2) {
lcdc_write(reg_context.clk_enable, LCD_CLK_ENABLE_REG);
lcdc_write(reg_context.int_enable_set, LCD_INT_ENABLE_SET_REG);
}
lcdc_write(reg_context.ctrl, LCD_CTRL_REG);
lcdc_write(reg_context.dma_ctrl, LCD_DMA_CTRL_REG);
lcdc_write(reg_context.raster_timing_0, LCD_RASTER_TIMING_0_REG);
lcdc_write(reg_context.raster_timing_1, LCD_RASTER_TIMING_1_REG);
lcdc_write(reg_context.raster_timing_2, LCD_RASTER_TIMING_2_REG);
lcdc_write(reg_context.dma_frm_buf_base_addr_0,
LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
lcdc_write(reg_context.dma_frm_buf_ceiling_addr_0,
LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
lcdc_write(reg_context.dma_frm_buf_base_addr_1,
LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
lcdc_write(reg_context.dma_frm_buf_ceiling_addr_1,
LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
lcdc_write(reg_context.raster_ctrl, LCD_RASTER_CTRL_REG);
return;
}
static int fb_suspend(struct platform_device *dev, pm_message_t state)
{
struct fb_info *info = platform_get_drvdata(dev);
@ -1411,8 +1564,9 @@ static int fb_suspend(struct platform_device *dev, pm_message_t state)
par->panel_power_ctrl(0);
fb_set_suspend(info, 1);
lcd_disable_raster();
clk_disable(par->lcdc_clk);
lcd_disable_raster(true);
lcd_context_save();
pm_runtime_put_sync(&dev->dev);
console_unlock();
return 0;
@ -1423,11 +1577,14 @@ static int fb_resume(struct platform_device *dev)
struct da8xx_fb_par *par = info->par;
console_lock();
clk_enable(par->lcdc_clk);
lcd_enable_raster();
pm_runtime_get_sync(&dev->dev);
lcd_context_restore();
if (par->blank == FB_BLANK_UNBLANK) {
lcd_enable_raster();
if (par->panel_power_ctrl)
par->panel_power_ctrl(1);
if (par->panel_power_ctrl)
par->panel_power_ctrl(1);
}
fb_set_suspend(info, 0);
console_unlock();

View file

@ -529,7 +529,8 @@ static int __devinit ep93xxfb_probe(struct platform_device *pdev)
* any of the framebuffer registers.
*/
fbi->res = res;
fbi->mmio_base = ioremap(res->start, resource_size(res));
fbi->mmio_base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
if (!fbi->mmio_base) {
err = -ENXIO;
goto failed_resource;
@ -553,20 +554,20 @@ static int __devinit ep93xxfb_probe(struct platform_device *pdev)
if (err == 0) {
dev_err(info->dev, "No suitable video mode found\n");
err = -EINVAL;
goto failed_mode;
goto failed_resource;
}
if (mach_info->setup) {
err = mach_info->setup(pdev);
if (err)
goto failed_mode;
goto failed_resource;
}
err = ep93xxfb_check_var(&info->var, info);
if (err)
goto failed_check;
fbi->clk = clk_get(info->dev, NULL);
fbi->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(fbi->clk)) {
err = PTR_ERR(fbi->clk);
fbi->clk = NULL;
@ -578,19 +579,15 @@ static int __devinit ep93xxfb_probe(struct platform_device *pdev)
err = register_framebuffer(info);
if (err)
goto failed;
goto failed_check;
dev_info(info->dev, "registered. Mode = %dx%d-%d\n",
info->var.xres, info->var.yres, info->var.bits_per_pixel);
return 0;
failed:
clk_put(fbi->clk);
failed_check:
if (fbi->mach_info->teardown)
fbi->mach_info->teardown(pdev);
failed_mode:
iounmap(fbi->mmio_base);
failed_resource:
ep93xxfb_dealloc_videomem(info);
failed_videomem:
@ -609,8 +606,6 @@ static int __devexit ep93xxfb_remove(struct platform_device *pdev)
unregister_framebuffer(info);
clk_disable(fbi->clk);
clk_put(fbi->clk);
iounmap(fbi->mmio_base);
ep93xxfb_dealloc_videomem(info);
fb_dealloc_cmap(&info->cmap);

View file

@ -29,6 +29,9 @@ static int exynos_dp_init_dp(struct exynos_dp_device *dp)
exynos_dp_swreset(dp);
exynos_dp_init_analog_param(dp);
exynos_dp_init_interrupt(dp);
/* SW defined function Normal operation */
exynos_dp_enable_sw_function(dp);
@ -260,7 +263,7 @@ static void exynos_dp_set_lane_lane_pre_emphasis(struct exynos_dp_device *dp,
static void exynos_dp_link_start(struct exynos_dp_device *dp)
{
u8 buf[5];
u8 buf[4];
int lane;
int lane_count;
@ -295,10 +298,10 @@ static void exynos_dp_link_start(struct exynos_dp_device *dp)
exynos_dp_set_training_pattern(dp, TRAINING_PTN1);
/* Set RX training pattern */
buf[0] = DPCD_SCRAMBLING_DISABLED |
DPCD_TRAINING_PATTERN_1;
exynos_dp_write_byte_to_dpcd(dp,
DPCD_ADDR_TRAINING_PATTERN_SET, buf[0]);
DPCD_ADDR_TRAINING_PATTERN_SET,
DPCD_SCRAMBLING_DISABLED |
DPCD_TRAINING_PATTERN_1);
for (lane = 0; lane < lane_count; lane++)
buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 |
@ -308,7 +311,7 @@ static void exynos_dp_link_start(struct exynos_dp_device *dp)
lane_count, buf);
}
static unsigned char exynos_dp_get_lane_status(u8 link_status[6], int lane)
static unsigned char exynos_dp_get_lane_status(u8 link_status[2], int lane)
{
int shift = (lane & 1) * 4;
u8 link_value = link_status[lane>>1];
@ -316,7 +319,7 @@ static unsigned char exynos_dp_get_lane_status(u8 link_status[6], int lane)
return (link_value >> shift) & 0xf;
}
static int exynos_dp_clock_recovery_ok(u8 link_status[6], int lane_count)
static int exynos_dp_clock_recovery_ok(u8 link_status[2], int lane_count)
{
int lane;
u8 lane_status;
@ -329,22 +332,23 @@ static int exynos_dp_clock_recovery_ok(u8 link_status[6], int lane_count)
return 0;
}
static int exynos_dp_channel_eq_ok(u8 link_status[6], int lane_count)
static int exynos_dp_channel_eq_ok(u8 link_align[3], int lane_count)
{
int lane;
u8 lane_align;
u8 lane_status;
lane_align = link_status[2];
lane_align = link_align[2];
if ((lane_align & DPCD_INTERLANE_ALIGN_DONE) == 0)
return -EINVAL;
for (lane = 0; lane < lane_count; lane++) {
lane_status = exynos_dp_get_lane_status(link_status, lane);
lane_status = exynos_dp_get_lane_status(link_align, lane);
lane_status &= DPCD_CHANNEL_EQ_BITS;
if (lane_status != DPCD_CHANNEL_EQ_BITS)
return -EINVAL;
}
return 0;
}
@ -417,69 +421,17 @@ static unsigned int exynos_dp_get_lane_link_training(
static void exynos_dp_reduce_link_rate(struct exynos_dp_device *dp)
{
if (dp->link_train.link_rate == LINK_RATE_2_70GBPS) {
/* set to reduced bit rate */
dp->link_train.link_rate = LINK_RATE_1_62GBPS;
dev_err(dp->dev, "set to bandwidth %.2x\n",
dp->link_train.link_rate);
dp->link_train.lt_state = START;
} else {
exynos_dp_training_pattern_dis(dp);
/* set enhanced mode if available */
exynos_dp_set_enhanced_mode(dp);
dp->link_train.lt_state = FAILED;
}
}
exynos_dp_training_pattern_dis(dp);
exynos_dp_set_enhanced_mode(dp);
static void exynos_dp_get_adjust_train(struct exynos_dp_device *dp,
u8 adjust_request[2])
{
int lane;
int lane_count;
u8 voltage_swing;
u8 pre_emphasis;
u8 training_lane;
lane_count = dp->link_train.lane_count;
for (lane = 0; lane < lane_count; lane++) {
voltage_swing = exynos_dp_get_adjust_request_voltage(
adjust_request, lane);
pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
adjust_request, lane);
training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
DPCD_PRE_EMPHASIS_SET(pre_emphasis);
if (voltage_swing == VOLTAGE_LEVEL_3 ||
pre_emphasis == PRE_EMPHASIS_LEVEL_3) {
training_lane |= DPCD_MAX_SWING_REACHED;
training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED;
}
dp->link_train.training_lane[lane] = training_lane;
}
}
static int exynos_dp_check_max_cr_loop(struct exynos_dp_device *dp,
u8 voltage_swing)
{
int lane;
int lane_count;
lane_count = dp->link_train.lane_count;
for (lane = 0; lane < lane_count; lane++) {
if (voltage_swing == VOLTAGE_LEVEL_3 ||
dp->link_train.cr_loop[lane] == MAX_CR_LOOP)
return -EINVAL;
}
return 0;
dp->link_train.lt_state = FAILED;
}
static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp)
{
u8 data;
u8 link_status[6];
u8 link_status[2];
int lane;
int lane_count;
u8 buf[5];
u8 adjust_request[2];
u8 voltage_swing;
@ -488,100 +440,154 @@ static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp)
usleep_range(100, 101);
exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS,
6, link_status);
lane_count = dp->link_train.lane_count;
exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS,
2, link_status);
if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) {
/* set training pattern 2 for EQ */
exynos_dp_set_training_pattern(dp, TRAINING_PTN2);
adjust_request[0] = link_status[4];
adjust_request[1] = link_status[5];
exynos_dp_get_adjust_train(dp, adjust_request);
buf[0] = DPCD_SCRAMBLING_DISABLED |
DPCD_TRAINING_PATTERN_2;
exynos_dp_write_byte_to_dpcd(dp,
DPCD_ADDR_TRAINING_PATTERN_SET,
buf[0]);
for (lane = 0; lane < lane_count; lane++) {
exynos_dp_set_lane_link_training(dp,
dp->link_train.training_lane[lane],
lane);
buf[lane] = dp->link_train.training_lane[lane];
exynos_dp_write_byte_to_dpcd(dp,
DPCD_ADDR_TRAINING_LANE0_SET + lane,
buf[lane]);
}
dp->link_train.lt_state = EQUALIZER_TRAINING;
} else {
exynos_dp_read_byte_from_dpcd(dp,
DPCD_ADDR_ADJUST_REQUEST_LANE0_1,
&data);
adjust_request[0] = data;
exynos_dp_read_byte_from_dpcd(dp,
DPCD_ADDR_ADJUST_REQUEST_LANE2_3,
&data);
adjust_request[1] = data;
for (lane = 0; lane < lane_count; lane++) {
training_lane = exynos_dp_get_lane_link_training(
dp, lane);
exynos_dp_read_bytes_from_dpcd(dp,
DPCD_ADDR_ADJUST_REQUEST_LANE0_1,
2, adjust_request);
voltage_swing = exynos_dp_get_adjust_request_voltage(
adjust_request, lane);
pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
adjust_request, lane);
if ((DPCD_VOLTAGE_SWING_GET(training_lane) == voltage_swing) &&
(DPCD_PRE_EMPHASIS_GET(training_lane) == pre_emphasis))
dp->link_train.cr_loop[lane]++;
training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
DPCD_PRE_EMPHASIS_SET(pre_emphasis);
if (voltage_swing == VOLTAGE_LEVEL_3)
training_lane |= DPCD_MAX_SWING_REACHED;
if (pre_emphasis == PRE_EMPHASIS_LEVEL_3)
training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED;
dp->link_train.training_lane[lane] = training_lane;
exynos_dp_set_lane_link_training(dp,
dp->link_train.training_lane[lane],
lane);
}
if (exynos_dp_check_max_cr_loop(dp, voltage_swing) != 0) {
exynos_dp_reduce_link_rate(dp);
} else {
exynos_dp_get_adjust_train(dp, adjust_request);
exynos_dp_write_byte_to_dpcd(dp,
DPCD_ADDR_TRAINING_PATTERN_SET,
DPCD_SCRAMBLING_DISABLED |
DPCD_TRAINING_PATTERN_2);
for (lane = 0; lane < lane_count; lane++) {
exynos_dp_set_lane_link_training(dp,
dp->link_train.training_lane[lane],
lane);
buf[lane] = dp->link_train.training_lane[lane];
exynos_dp_write_byte_to_dpcd(dp,
DPCD_ADDR_TRAINING_LANE0_SET + lane,
buf[lane]);
exynos_dp_write_bytes_to_dpcd(dp,
DPCD_ADDR_TRAINING_LANE0_SET,
lane_count,
dp->link_train.training_lane);
dev_info(dp->dev, "Link Training Clock Recovery success\n");
dp->link_train.lt_state = EQUALIZER_TRAINING;
} else {
for (lane = 0; lane < lane_count; lane++) {
training_lane = exynos_dp_get_lane_link_training(
dp, lane);
exynos_dp_read_bytes_from_dpcd(dp,
DPCD_ADDR_ADJUST_REQUEST_LANE0_1,
2, adjust_request);
voltage_swing = exynos_dp_get_adjust_request_voltage(
adjust_request, lane);
pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
adjust_request, lane);
if (voltage_swing == VOLTAGE_LEVEL_3 ||
pre_emphasis == PRE_EMPHASIS_LEVEL_3) {
dev_err(dp->dev, "voltage or pre emphasis reached max level\n");
goto reduce_link_rate;
}
if ((DPCD_VOLTAGE_SWING_GET(training_lane) ==
voltage_swing) &&
(DPCD_PRE_EMPHASIS_GET(training_lane) ==
pre_emphasis)) {
dp->link_train.cr_loop[lane]++;
if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP) {
dev_err(dp->dev, "CR Max loop\n");
goto reduce_link_rate;
}
}
training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
DPCD_PRE_EMPHASIS_SET(pre_emphasis);
if (voltage_swing == VOLTAGE_LEVEL_3)
training_lane |= DPCD_MAX_SWING_REACHED;
if (pre_emphasis == PRE_EMPHASIS_LEVEL_3)
training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED;
dp->link_train.training_lane[lane] = training_lane;
exynos_dp_set_lane_link_training(dp,
dp->link_train.training_lane[lane], lane);
}
exynos_dp_write_bytes_to_dpcd(dp,
DPCD_ADDR_TRAINING_LANE0_SET,
lane_count,
dp->link_train.training_lane);
}
return 0;
reduce_link_rate:
exynos_dp_reduce_link_rate(dp);
return -EIO;
}
static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp)
{
u8 link_status[6];
u8 link_status[2];
u8 link_align[3];
int lane;
int lane_count;
u8 buf[5];
u32 reg;
u8 adjust_request[2];
u8 voltage_swing;
u8 pre_emphasis;
u8 training_lane;
usleep_range(400, 401);
exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS,
6, link_status);
lane_count = dp->link_train.lane_count;
if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) {
adjust_request[0] = link_status[4];
adjust_request[1] = link_status[5];
exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS,
2, link_status);
if (exynos_dp_channel_eq_ok(link_status, lane_count) == 0) {
if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) {
link_align[0] = link_status[0];
link_align[1] = link_status[1];
exynos_dp_read_byte_from_dpcd(dp,
DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED,
&link_align[2]);
for (lane = 0; lane < lane_count; lane++) {
exynos_dp_read_bytes_from_dpcd(dp,
DPCD_ADDR_ADJUST_REQUEST_LANE0_1,
2, adjust_request);
voltage_swing = exynos_dp_get_adjust_request_voltage(
adjust_request, lane);
pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
adjust_request, lane);
training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
DPCD_PRE_EMPHASIS_SET(pre_emphasis);
if (voltage_swing == VOLTAGE_LEVEL_3)
training_lane |= DPCD_MAX_SWING_REACHED;
if (pre_emphasis == PRE_EMPHASIS_LEVEL_3)
training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED;
dp->link_train.training_lane[lane] = training_lane;
}
if (exynos_dp_channel_eq_ok(link_align, lane_count) == 0) {
/* traing pattern Set to Normal */
exynos_dp_training_pattern_dis(dp);
@ -596,39 +602,42 @@ static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp)
dp->link_train.lane_count = reg;
dev_dbg(dp->dev, "final lane count = %.2x\n",
dp->link_train.lane_count);
/* set enhanced mode if available */
exynos_dp_set_enhanced_mode(dp);
dp->link_train.lt_state = FINISHED;
} else {
/* not all locked */
dp->link_train.eq_loop++;
if (dp->link_train.eq_loop > MAX_EQ_LOOP) {
exynos_dp_reduce_link_rate(dp);
} else {
exynos_dp_get_adjust_train(dp, adjust_request);
for (lane = 0; lane < lane_count; lane++) {
exynos_dp_set_lane_link_training(dp,
dp->link_train.training_lane[lane],
lane);
buf[lane] = dp->link_train.training_lane[lane];
exynos_dp_write_byte_to_dpcd(dp,
DPCD_ADDR_TRAINING_LANE0_SET + lane,
buf[lane]);
}
dev_err(dp->dev, "EQ Max loop\n");
goto reduce_link_rate;
}
for (lane = 0; lane < lane_count; lane++)
exynos_dp_set_lane_link_training(dp,
dp->link_train.training_lane[lane],
lane);
exynos_dp_write_bytes_to_dpcd(dp,
DPCD_ADDR_TRAINING_LANE0_SET,
lane_count,
dp->link_train.training_lane);
}
} else {
exynos_dp_reduce_link_rate(dp);
goto reduce_link_rate;
}
return 0;
reduce_link_rate:
exynos_dp_reduce_link_rate(dp);
return -EIO;
}
static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp,
u8 *bandwidth)
u8 *bandwidth)
{
u8 data;
@ -641,7 +650,7 @@ static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp,
}
static void exynos_dp_get_max_rx_lane_count(struct exynos_dp_device *dp,
u8 *lane_count)
u8 *lane_count)
{
u8 data;
@ -693,13 +702,7 @@ static void exynos_dp_init_training(struct exynos_dp_device *dp,
static int exynos_dp_sw_link_training(struct exynos_dp_device *dp)
{
int retval = 0;
int training_finished;
/* Turn off unnecessary lane */
if (dp->link_train.lane_count == 1)
exynos_dp_set_analog_power_down(dp, CH1_BLOCK, 1);
training_finished = 0;
int training_finished = 0;
dp->link_train.lt_state = START;
@ -710,10 +713,14 @@ static int exynos_dp_sw_link_training(struct exynos_dp_device *dp)
exynos_dp_link_start(dp);
break;
case CLOCK_RECOVERY:
exynos_dp_process_clock_recovery(dp);
retval = exynos_dp_process_clock_recovery(dp);
if (retval)
dev_err(dp->dev, "LT CR failed!\n");
break;
case EQUALIZER_TRAINING:
exynos_dp_process_equalizer_training(dp);
retval = exynos_dp_process_equalizer_training(dp);
if (retval)
dev_err(dp->dev, "LT EQ failed!\n");
break;
case FINISHED:
training_finished = 1;
@ -872,40 +879,33 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev)
dp->dev = &pdev->dev;
dp->clock = clk_get(&pdev->dev, "dp");
dp->clock = devm_clk_get(&pdev->dev, "dp");
if (IS_ERR(dp->clock)) {
dev_err(&pdev->dev, "failed to get clock\n");
return PTR_ERR(dp->clock);
}
clk_enable(dp->clock);
clk_prepare_enable(dp->clock);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "failed to get registers\n");
ret = -EINVAL;
goto err_clock;
}
dp->reg_base = devm_request_and_ioremap(&pdev->dev, res);
if (!dp->reg_base) {
dev_err(&pdev->dev, "failed to ioremap\n");
ret = -ENOMEM;
goto err_clock;
return -ENOMEM;
}
dp->irq = platform_get_irq(pdev, 0);
if (!dp->irq) {
dev_err(&pdev->dev, "failed to get irq\n");
ret = -ENODEV;
goto err_clock;
return -ENODEV;
}
ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler, 0,
"exynos-dp", dp);
if (ret) {
dev_err(&pdev->dev, "failed to request irq\n");
goto err_clock;
return ret;
}
dp->video_info = pdata->video_info;
@ -917,7 +917,7 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev)
ret = exynos_dp_detect_hpd(dp);
if (ret) {
dev_err(&pdev->dev, "unable to detect hpd\n");
goto err_clock;
return ret;
}
exynos_dp_handle_edid(dp);
@ -926,7 +926,7 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev)
dp->video_info->link_rate);
if (ret) {
dev_err(&pdev->dev, "unable to do link train\n");
goto err_clock;
return ret;
}
exynos_dp_enable_scramble(dp, 1);
@ -940,17 +940,12 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev)
ret = exynos_dp_config_video(dp, dp->video_info);
if (ret) {
dev_err(&pdev->dev, "unable to config video\n");
goto err_clock;
return ret;
}
platform_set_drvdata(pdev, dp);
return 0;
err_clock:
clk_put(dp->clock);
return ret;
}
static int __devexit exynos_dp_remove(struct platform_device *pdev)
@ -961,8 +956,7 @@ static int __devexit exynos_dp_remove(struct platform_device *pdev)
if (pdata && pdata->phy_exit)
pdata->phy_exit();
clk_disable(dp->clock);
clk_put(dp->clock);
clk_disable_unprepare(dp->clock);
return 0;
}
@ -977,7 +971,7 @@ static int exynos_dp_suspend(struct device *dev)
if (pdata && pdata->phy_exit)
pdata->phy_exit();
clk_disable(dp->clock);
clk_disable_unprepare(dp->clock);
return 0;
}
@ -991,7 +985,7 @@ static int exynos_dp_resume(struct device *dev)
if (pdata && pdata->phy_init)
pdata->phy_init();
clk_enable(dp->clock);
clk_prepare_enable(dp->clock);
exynos_dp_init_dp(dp);

View file

@ -43,7 +43,7 @@ void exynos_dp_init_interrupt(struct exynos_dp_device *dp);
void exynos_dp_reset(struct exynos_dp_device *dp);
void exynos_dp_swreset(struct exynos_dp_device *dp);
void exynos_dp_config_interrupt(struct exynos_dp_device *dp);
u32 exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp);
enum pll_status exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp);
void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable);
void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp,
enum analog_power_block block,
@ -105,7 +105,7 @@ u32 exynos_dp_get_lane1_link_training(struct exynos_dp_device *dp);
u32 exynos_dp_get_lane2_link_training(struct exynos_dp_device *dp);
u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp);
void exynos_dp_reset_macro(struct exynos_dp_device *dp);
int exynos_dp_init_video(struct exynos_dp_device *dp);
void exynos_dp_init_video(struct exynos_dp_device *dp);
void exynos_dp_set_video_color_format(struct exynos_dp_device *dp,
u32 color_depth,
@ -144,7 +144,7 @@ void exynos_dp_disable_scrambling(struct exynos_dp_device *dp);
#define DPCD_ADDR_TRAINING_PATTERN_SET 0x0102
#define DPCD_ADDR_TRAINING_LANE0_SET 0x0103
#define DPCD_ADDR_LANE0_1_STATUS 0x0202
#define DPCD_ADDR_LANE_ALIGN__STATUS_UPDATED 0x0204
#define DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED 0x0204
#define DPCD_ADDR_ADJUST_REQUEST_LANE0_1 0x0206
#define DPCD_ADDR_ADJUST_REQUEST_LANE2_3 0x0207
#define DPCD_ADDR_TEST_REQUEST 0x0218

View file

@ -77,7 +77,7 @@ void exynos_dp_init_analog_param(struct exynos_dp_device *dp)
writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_3);
reg = PD_RING_OSC | AUX_TERMINAL_CTRL_50_OHM |
TX_CUR1_2X | TX_CUR_8_MA;
TX_CUR1_2X | TX_CUR_16_MA;
writel(reg, dp->reg_base + EXYNOS_DP_PLL_FILTER_CTL_1);
reg = CH3_AMP_400_MV | CH2_AMP_400_MV |
@ -148,9 +148,6 @@ void exynos_dp_reset(struct exynos_dp_device *dp)
writel(0x2, dp->reg_base + EXYNOS_DP_M_AUD_GEN_FILTER_TH);
writel(0x00000101, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
exynos_dp_init_analog_param(dp);
exynos_dp_init_interrupt(dp);
}
void exynos_dp_swreset(struct exynos_dp_device *dp)
@ -179,7 +176,7 @@ void exynos_dp_config_interrupt(struct exynos_dp_device *dp)
writel(reg, dp->reg_base + EXYNOS_DP_INT_STA_MASK);
}
u32 exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp)
enum pll_status exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp)
{
u32 reg;
@ -401,6 +398,7 @@ int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp)
{
int reg;
int retval = 0;
int timeout_loop = 0;
/* Enable AUX CH operation */
reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
@ -409,8 +407,15 @@ int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp)
/* Is AUX CH command reply received? */
reg = readl(dp->reg_base + EXYNOS_DP_INT_STA);
while (!(reg & RPLY_RECEIV))
while (!(reg & RPLY_RECEIV)) {
timeout_loop++;
if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
dev_err(dp->dev, "AUX CH command reply failed!\n");
return -ETIMEDOUT;
}
reg = readl(dp->reg_base + EXYNOS_DP_INT_STA);
usleep_range(10, 11);
}
/* Clear interrupt source for AUX CH command reply */
writel(RPLY_RECEIV, dp->reg_base + EXYNOS_DP_INT_STA);
@ -471,7 +476,8 @@ int exynos_dp_write_byte_to_dpcd(struct exynos_dp_device *dp,
if (retval == 0)
break;
else
dev_err(dp->dev, "Aux Transaction fail!\n");
dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
__func__);
}
return retval;
@ -511,7 +517,8 @@ int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp,
if (retval == 0)
break;
else
dev_err(dp->dev, "Aux Transaction fail!\n");
dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
__func__);
}
/* Read data buffer */
@ -575,7 +582,8 @@ int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp,
if (retval == 0)
break;
else
dev_err(dp->dev, "Aux Transaction fail!\n");
dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
__func__);
}
start_offset += cur_data_count;
@ -632,7 +640,8 @@ int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp,
if (retval == 0)
break;
else
dev_err(dp->dev, "Aux Transaction fail!\n");
dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
__func__);
}
for (cur_data_idx = 0; cur_data_idx < cur_data_count;
@ -677,7 +686,7 @@ int exynos_dp_select_i2c_device(struct exynos_dp_device *dp,
/* Start AUX transaction */
retval = exynos_dp_start_aux_transaction(dp);
if (retval != 0)
dev_err(dp->dev, "Aux Transaction fail!\n");
dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__);
return retval;
}
@ -717,7 +726,8 @@ int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp,
if (retval == 0)
break;
else
dev_err(dp->dev, "Aux Transaction fail!\n");
dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
__func__);
}
/* Read data */
@ -777,7 +787,9 @@ int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp,
if (retval == 0)
break;
else
dev_err(dp->dev, "Aux Transaction fail!\n");
dev_dbg(dp->dev,
"%s: Aux Transaction fail!\n",
__func__);
}
/* Check if Rx sends defer */
reg = readl(dp->reg_base + EXYNOS_DP_AUX_RX_COMM);
@ -883,7 +895,9 @@ void exynos_dp_set_lane0_pre_emphasis(struct exynos_dp_device *dp, u32 level)
{
u32 reg;
reg = level << PRE_EMPHASIS_SET_SHIFT;
reg = readl(dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
reg &= ~PRE_EMPHASIS_SET_MASK;
reg |= level << PRE_EMPHASIS_SET_SHIFT;
writel(reg, dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
}
@ -891,7 +905,9 @@ void exynos_dp_set_lane1_pre_emphasis(struct exynos_dp_device *dp, u32 level)
{
u32 reg;
reg = level << PRE_EMPHASIS_SET_SHIFT;
reg = readl(dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
reg &= ~PRE_EMPHASIS_SET_MASK;
reg |= level << PRE_EMPHASIS_SET_SHIFT;
writel(reg, dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
}
@ -899,7 +915,9 @@ void exynos_dp_set_lane2_pre_emphasis(struct exynos_dp_device *dp, u32 level)
{
u32 reg;
reg = level << PRE_EMPHASIS_SET_SHIFT;
reg = readl(dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
reg &= ~PRE_EMPHASIS_SET_MASK;
reg |= level << PRE_EMPHASIS_SET_SHIFT;
writel(reg, dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
}
@ -907,7 +925,9 @@ void exynos_dp_set_lane3_pre_emphasis(struct exynos_dp_device *dp, u32 level)
{
u32 reg;
reg = level << PRE_EMPHASIS_SET_SHIFT;
reg = readl(dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
reg &= ~PRE_EMPHASIS_SET_MASK;
reg |= level << PRE_EMPHASIS_SET_SHIFT;
writel(reg, dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
}
@ -994,7 +1014,7 @@ void exynos_dp_reset_macro(struct exynos_dp_device *dp)
writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST);
}
int exynos_dp_init_video(struct exynos_dp_device *dp)
void exynos_dp_init_video(struct exynos_dp_device *dp)
{
u32 reg;
@ -1012,8 +1032,6 @@ int exynos_dp_init_video(struct exynos_dp_device *dp)
reg = VID_HRES_TH(2) | VID_VRES_TH(0);
writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_8);
return 0;
}
void exynos_dp_set_video_color_format(struct exynos_dp_device *dp,

View file

@ -187,7 +187,7 @@
#define PD_RING_OSC (0x1 << 6)
#define AUX_TERMINAL_CTRL_50_OHM (0x2 << 4)
#define TX_CUR1_2X (0x1 << 2)
#define TX_CUR_8_MA (0x2 << 0)
#define TX_CUR_16_MA (0x3 << 0)
/* EXYNOS_DP_TX_AMP_TUNING_CTL */
#define CH3_AMP_400_MV (0x0 << 24)
@ -285,6 +285,7 @@
#define SW_TRAINING_PATTERN_SET_NORMAL (0x0 << 0)
/* EXYNOS_DP_LN0_LINK_TRAINING_CTL */
#define PRE_EMPHASIS_SET_MASK (0x3 << 3)
#define PRE_EMPHASIS_SET_SHIFT (3)
/* EXYNOS_DP_DEBUG_CTL */

View file

@ -205,7 +205,8 @@ int exynos_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev)
return 0;
}
struct mipi_dsim_ddi *exynos_mipi_dsi_find_lcd_device(struct mipi_dsim_lcd_driver *lcd_drv)
static struct mipi_dsim_ddi *exynos_mipi_dsi_find_lcd_device(
struct mipi_dsim_lcd_driver *lcd_drv)
{
struct mipi_dsim_ddi *dsim_ddi, *next;
struct mipi_dsim_lcd_device *lcd_dev;
@ -265,7 +266,8 @@ int exynos_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv)
}
struct mipi_dsim_ddi *exynos_mipi_dsi_bind_lcd_ddi(struct mipi_dsim_device *dsim,
static struct mipi_dsim_ddi *exynos_mipi_dsi_bind_lcd_ddi(
struct mipi_dsim_device *dsim,
const char *name)
{
struct mipi_dsim_ddi *dsim_ddi, *next;
@ -373,6 +375,7 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev)
dsim->clock = clk_get(&pdev->dev, "dsim0");
if (IS_ERR(dsim->clock)) {
dev_err(&pdev->dev, "failed to get dsim clock source\n");
ret = -ENODEV;
goto err_clock_get;
}
@ -381,6 +384,7 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "failed to get io memory region\n");
ret = -ENODEV;
goto err_platform_get;
}
@ -405,6 +409,7 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev)
dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name);
if (!dsim_ddi) {
dev_err(&pdev->dev, "mipi_dsim_ddi object not found.\n");
ret = -EINVAL;
goto err_bind;
}

View file

@ -79,11 +79,6 @@ irqreturn_t exynos_mipi_dsi_interrupt_handler(int irq, void *dev_id)
struct mipi_dsim_device *dsim = dev_id;
unsigned int intsrc, intmsk;
if (dsim == NULL) {
dev_err(dsim->dev, "%s: wrong parameter\n", __func__);
return IRQ_NONE;
}
intsrc = exynos_mipi_dsi_read_interrupt(dsim);
intmsk = exynos_mipi_dsi_read_interrupt_mask(dsim);
intmsk = ~intmsk & intsrc;
@ -288,9 +283,6 @@ int exynos_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id,
mutex_unlock(&dsim->lock);
return -EINVAL;
}
mutex_unlock(&dsim->lock);
return 0;
}
static unsigned int exynos_mipi_dsi_long_data_rd(struct mipi_dsim_device *dsim,

View file

@ -1501,8 +1501,8 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev)
unsigned int i;
int ret;
data = dma_alloc_coherent(&pdev->dev, sizeof(struct fsl_diu_data),
&dma_addr, GFP_DMA | __GFP_ZERO);
data = dmam_alloc_coherent(&pdev->dev, sizeof(struct fsl_diu_data),
&dma_addr, GFP_DMA | __GFP_ZERO);
if (!data)
return -ENOMEM;
data->dma_addr = dma_addr;
@ -1628,9 +1628,6 @@ error:
iounmap(data->diu_reg);
dma_free_coherent(&pdev->dev, sizeof(struct fsl_diu_data), data,
data->dma_addr);
return ret;
}
@ -1648,9 +1645,6 @@ static int fsl_diu_remove(struct platform_device *pdev)
iounmap(data->diu_reg);
dma_free_coherent(&pdev->dev, sizeof(struct fsl_diu_data), data,
data->dma_addr);
return 0;
}

View file

@ -20,6 +20,7 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/io.h>
#ifdef CONFIG_X86
#include <asm/mtrr.h>
@ -28,7 +29,6 @@
#include <asm/addrspace.h>
#endif
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/tlbflush.h>
#include <video/gbe.h>
@ -1156,7 +1156,8 @@ static int __devinit gbefb_probe(struct platform_device *p_dev)
goto out_release_framebuffer;
}
gbe = (struct sgi_gbe *) ioremap(GBE_BASE, sizeof(struct sgi_gbe));
gbe = (struct sgi_gbe *) devm_ioremap(&p_dev->dev, GBE_BASE,
sizeof(struct sgi_gbe));
if (!gbe) {
printk(KERN_ERR "gbefb: couldn't map mmio region\n");
ret = -ENXIO;
@ -1170,12 +1171,13 @@ static int __devinit gbefb_probe(struct platform_device *p_dev)
if (!gbe_tiles.cpu) {
printk(KERN_ERR "gbefb: couldn't allocate tiles table\n");
ret = -ENOMEM;
goto out_unmap;
goto out_release_mem_region;
}
if (gbe_mem_phys) {
/* memory was allocated at boot time */
gbe_mem = ioremap_nocache(gbe_mem_phys, gbe_mem_size);
gbe_mem = devm_ioremap_nocache(&p_dev->dev, gbe_mem_phys,
gbe_mem_size);
if (!gbe_mem) {
printk(KERN_ERR "gbefb: couldn't map framebuffer\n");
ret = -ENOMEM;
@ -1241,13 +1243,9 @@ static int __devinit gbefb_probe(struct platform_device *p_dev)
out_gbe_unmap:
if (gbe_dma_addr)
dma_free_coherent(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys);
else
iounmap(gbe_mem);
out_tiles_free:
dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t),
(void *)gbe_tiles.cpu, gbe_tiles.dma);
out_unmap:
iounmap(gbe);
out_release_mem_region:
release_mem_region(GBE_BASE, sizeof(struct sgi_gbe));
out_release_framebuffer:
@ -1264,12 +1262,9 @@ static int __devexit gbefb_remove(struct platform_device* p_dev)
gbe_turn_off();
if (gbe_dma_addr)
dma_free_coherent(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys);
else
iounmap(gbe_mem);
dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t),
(void *)gbe_tiles.cpu, gbe_tiles.dma);
release_mem_region(GBE_BASE, sizeof(struct sgi_gbe));
iounmap(gbe);
gbefb_remove_sysfs(&p_dev->dev);
framebuffer_release(info);

View file

@ -210,6 +210,7 @@ static int __devinit hpfb_init_one(unsigned long phys_base,
unsigned long virt_base)
{
unsigned long fboff, fb_width, fb_height, fb_start;
int ret;
fb_regs = virt_base;
fboff = (in_8(fb_regs + HPFB_FBOMSB) << 8) | in_8(fb_regs + HPFB_FBOLSB);
@ -290,19 +291,29 @@ static int __devinit hpfb_init_one(unsigned long phys_base,
fb_info.var = hpfb_defined;
fb_info.screen_base = (char *)fb_start;
fb_alloc_cmap(&fb_info.cmap, 1 << hpfb_defined.bits_per_pixel, 0);
ret = fb_alloc_cmap(&fb_info.cmap, 1 << hpfb_defined.bits_per_pixel, 0);
if (ret < 0)
goto unmap_screen_base;
if (register_framebuffer(&fb_info) < 0) {
fb_dealloc_cmap(&fb_info.cmap);
iounmap(fb_info.screen_base);
fb_info.screen_base = NULL;
return 1;
}
ret = register_framebuffer(&fb_info);
if (ret < 0)
goto dealloc_cmap;
printk(KERN_INFO "fb%d: %s frame buffer device\n",
fb_info.node, fb_info.fix.id);
return 0;
dealloc_cmap:
fb_dealloc_cmap(&fb_info.cmap);
unmap_screen_base:
if (fb_info.screen_base) {
iounmap(fb_info.screen_base);
fb_info.screen_base = NULL;
}
return ret;
}
/*
@ -345,6 +356,9 @@ static void __devexit hpfb_remove_one(struct dio_dev *d)
if (d->scode >= DIOII_SCBASE)
iounmap((void *)fb_regs);
release_mem_region(d->resource.start, resource_size(&d->resource));
fb_dealloc_cmap(&fb_info.cmap);
if (fb_info.screen_base)
iounmap(fb_info.screen_base);
}
static struct dio_device_id hpfb_dio_tbl[] = {

View file

@ -803,6 +803,7 @@ static int __init imxfb_probe(struct platform_device *pdev)
fbi->regs = ioremap(res->start, resource_size(res));
if (fbi->regs == NULL) {
dev_err(&pdev->dev, "Cannot map frame buffer registers\n");
ret = -ENOMEM;
goto failed_ioremap;
}

View file

@ -632,23 +632,10 @@ static int __devinit jzfb_probe(struct platform_device *pdev)
return -ENXIO;
}
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
dev_err(&pdev->dev, "Failed to get register memory resource\n");
return -ENXIO;
}
mem = request_mem_region(mem->start, resource_size(mem), pdev->name);
if (!mem) {
dev_err(&pdev->dev, "Failed to request register memory region\n");
return -EBUSY;
}
fb = framebuffer_alloc(sizeof(struct jzfb), &pdev->dev);
if (!fb) {
dev_err(&pdev->dev, "Failed to allocate framebuffer device\n");
ret = -ENOMEM;
goto err_release_mem_region;
return -ENOMEM;
}
fb->fbops = &jzfb_ops;
@ -657,27 +644,26 @@ static int __devinit jzfb_probe(struct platform_device *pdev)
jzfb = fb->par;
jzfb->pdev = pdev;
jzfb->pdata = pdata;
jzfb->mem = mem;
jzfb->ldclk = clk_get(&pdev->dev, "lcd");
jzfb->ldclk = devm_clk_get(&pdev->dev, "lcd");
if (IS_ERR(jzfb->ldclk)) {
ret = PTR_ERR(jzfb->ldclk);
dev_err(&pdev->dev, "Failed to get lcd clock: %d\n", ret);
goto err_framebuffer_release;
}
jzfb->lpclk = clk_get(&pdev->dev, "lcd_pclk");
jzfb->lpclk = devm_clk_get(&pdev->dev, "lcd_pclk");
if (IS_ERR(jzfb->lpclk)) {
ret = PTR_ERR(jzfb->lpclk);
dev_err(&pdev->dev, "Failed to get lcd pixel clock: %d\n", ret);
goto err_put_ldclk;
goto err_framebuffer_release;
}
jzfb->base = ioremap(mem->start, resource_size(mem));
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
jzfb->base = devm_request_and_ioremap(&pdev->dev, mem);
if (!jzfb->base) {
dev_err(&pdev->dev, "Failed to ioremap register memory region\n");
ret = -EBUSY;
goto err_put_lpclk;
goto err_framebuffer_release;
}
platform_set_drvdata(pdev, jzfb);
@ -693,7 +679,7 @@ static int __devinit jzfb_probe(struct platform_device *pdev)
ret = jzfb_alloc_devmem(jzfb);
if (ret) {
dev_err(&pdev->dev, "Failed to allocate video memory\n");
goto err_iounmap;
goto err_framebuffer_release;
}
fb->fix = jzfb_fix;
@ -734,16 +720,8 @@ err_free_devmem:
fb_dealloc_cmap(&fb->cmap);
jzfb_free_devmem(jzfb);
err_iounmap:
iounmap(jzfb->base);
err_put_lpclk:
clk_put(jzfb->lpclk);
err_put_ldclk:
clk_put(jzfb->ldclk);
err_framebuffer_release:
framebuffer_release(fb);
err_release_mem_region:
release_mem_region(mem->start, resource_size(mem));
return ret;
}
@ -756,17 +734,11 @@ static int __devexit jzfb_remove(struct platform_device *pdev)
jz_gpio_bulk_free(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
jz_gpio_bulk_free(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
iounmap(jzfb->base);
release_mem_region(jzfb->mem->start, resource_size(jzfb->mem));
fb_dealloc_cmap(&jzfb->fb->cmap);
jzfb_free_devmem(jzfb);
platform_set_drvdata(pdev, NULL);
clk_put(jzfb->lpclk);
clk_put(jzfb->ldclk);
framebuffer_release(jzfb->fb);
return 0;

View file

@ -1052,12 +1052,14 @@ static int __devinit mb862xx_pci_probe(struct pci_dev *pdev,
break;
default:
/* should never occur */
ret = -EIO;
goto rel_reg;
}
par->fb_base = ioremap(par->fb_base_phys, par->mapped_vram);
if (par->fb_base == NULL) {
dev_err(dev, "Cannot map framebuffer\n");
ret = -EIO;
goto rel_reg;
}
@ -1073,11 +1075,13 @@ static int __devinit mb862xx_pci_probe(struct pci_dev *pdev,
dev_dbg(dev, "mmio phys 0x%llx 0x%lx\n",
(unsigned long long)par->mmio_base_phys, (ulong)par->mmio_len);
if (mb862xx_pci_gdc_init(par))
ret = mb862xx_pci_gdc_init(par);
if (ret)
goto io_unmap;
if (request_irq(par->irq, mb862xx_intr, IRQF_SHARED,
DRV_NAME, (void *)par)) {
ret = request_irq(par->irq, mb862xx_intr, IRQF_SHARED,
DRV_NAME, (void *)par);
if (ret) {
dev_err(dev, "Cannot request irq\n");
goto io_unmap;
}

View file

@ -26,8 +26,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <linux/io.h>
#include <video/mbxfb.h>
@ -939,8 +938,9 @@ static int __devinit mbxfb_probe(struct platform_device *dev)
}
mfbi->reg_phys_addr = mfbi->reg_res->start;
mfbi->reg_virt_addr = ioremap_nocache(mfbi->reg_phys_addr,
res_size(mfbi->reg_req));
mfbi->reg_virt_addr = devm_ioremap_nocache(&dev->dev,
mfbi->reg_phys_addr,
res_size(mfbi->reg_req));
if (!mfbi->reg_virt_addr) {
dev_err(&dev->dev, "failed to ioremap Marathon registers\n");
ret = -EINVAL;
@ -948,12 +948,12 @@ static int __devinit mbxfb_probe(struct platform_device *dev)
}
virt_base_2700 = mfbi->reg_virt_addr;
mfbi->fb_virt_addr = ioremap_nocache(mfbi->fb_phys_addr,
res_size(mfbi->fb_req));
mfbi->fb_virt_addr = devm_ioremap_nocache(&dev->dev, mfbi->fb_phys_addr,
res_size(mfbi->fb_req));
if (!mfbi->fb_virt_addr) {
dev_err(&dev->dev, "failed to ioremap frame buffer\n");
ret = -EINVAL;
goto err4;
goto err3;
}
fbi->screen_base = (char __iomem *)(mfbi->fb_virt_addr + 0x60000);
@ -971,7 +971,7 @@ static int __devinit mbxfb_probe(struct platform_device *dev)
if (ret < 0) {
dev_err(&dev->dev, "fb_alloc_cmap failed\n");
ret = -EINVAL;
goto err5;
goto err3;
}
platform_set_drvdata(dev, fbi);
@ -996,10 +996,6 @@ static int __devinit mbxfb_probe(struct platform_device *dev)
err6:
fb_dealloc_cmap(&fbi->cmap);
err5:
iounmap(mfbi->fb_virt_addr);
err4:
iounmap(mfbi->reg_virt_addr);
err3:
release_mem_region(mfbi->reg_res->start, res_size(mfbi->reg_res));
err2:
@ -1026,10 +1022,7 @@ static int __devexit mbxfb_remove(struct platform_device *dev)
if (mfbi->platform_remove)
mfbi->platform_remove(fbi);
if (mfbi->fb_virt_addr)
iounmap(mfbi->fb_virt_addr);
if (mfbi->reg_virt_addr)
iounmap(mfbi->reg_virt_addr);
if (mfbi->reg_req)
release_mem_region(mfbi->reg_req->start,
res_size(mfbi->reg_req));

View file

@ -26,9 +26,6 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/sched.h>
#include <mach/msm_iomap.h>
#include <mach/irqs.h>
#include <mach/board.h>
#include <linux/platform_data/video-msm_fb.h>
#include "mddi_hw.h"

View file

@ -189,8 +189,9 @@ static int mddi_nt35399_probe(struct platform_device *pdev)
int ret;
struct panel_info *panel = kzalloc(sizeof(struct panel_info),
GFP_KERNEL);
struct panel_info *panel = devm_kzalloc(&pdev->dev,
sizeof(struct panel_info),
GFP_KERNEL);
printk(KERN_DEBUG "%s: enter.\n", __func__);
@ -233,7 +234,6 @@ static int mddi_nt35399_remove(struct platform_device *pdev)
struct panel_info *panel = platform_get_drvdata(pdev);
setup_vsync(panel, 0);
kfree(panel);
return 0;
}

View file

@ -25,7 +25,6 @@
#include <linux/major.h>
#include <linux/slab.h>
#include <mach/msm_iomap.h>
#include <linux/platform_data/video-msm_fb.h>
#include <linux/platform_device.h>
#include <linux/export.h>

View file

@ -15,7 +15,6 @@
#ifndef _MDP_HW_H_
#define _MDP_HW_H_
#include <mach/msm_iomap.h>
#include <linux/platform_data/video-msm_fb.h>
struct mdp_info {

View file

@ -1568,7 +1568,8 @@ static int mx3fb_remove(struct platform_device *dev)
static struct platform_driver mx3fb_driver = {
.driver = {
.name = MX3FB_NAME,
.name = MX3FB_NAME,
.owner = THIS_MODULE,
},
.probe = mx3fb_probe,
.remove = mx3fb_remove,

View file

@ -387,7 +387,7 @@ static int nuc900fb_init_registers(struct fb_info *info)
* The buffer should be a non-cached, non-buffered, memory region
* to allow palette and pixel writes without flushing the cache.
*/
static int __init nuc900fb_map_video_memory(struct fb_info *info)
static int __devinit nuc900fb_map_video_memory(struct fb_info *info)
{
struct nuc900fb_info *fbi = info->par;
dma_addr_t map_dma;

View file

@ -27,7 +27,6 @@
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <plat/dma.h>
#include "omapfb.h"
#define HWA742_REV_CODE_REG 0x0

View file

@ -23,7 +23,6 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include <plat/fpga.h>
#include "omapfb.h"
static int palmte_panel_init(struct lcd_panel *panel,

View file

@ -131,15 +131,6 @@ static void omapfb_rqueue_unlock(struct omapfb_device *fbdev)
* LCD controller and LCD DMA
* ---------------------------------------------------------------------------
*/
/* Lookup table to map elem size to elem type. */
static const int dma_elem_type[] = {
0,
OMAP_DMA_DATA_TYPE_S8,
OMAP_DMA_DATA_TYPE_S16,
0,
OMAP_DMA_DATA_TYPE_S32,
};
/*
* Allocate resources needed for LCD controller and LCD DMA operations. Video
* memory is allocated from system memory according to the virtual display

View file

@ -600,6 +600,9 @@ static int acx_panel_power_on(struct omap_dss_device *dssdev)
mutex_lock(&md->mutex);
omapdss_sdi_set_timings(dssdev, &dssdev->panel.timings);
omapdss_sdi_set_datapairs(dssdev, dssdev->phy.sdi.datapairs);
r = omapdss_sdi_display_enable(dssdev);
if (r) {
pr_err("%s sdi enable failed\n", __func__);
@ -731,18 +734,9 @@ static int acx_panel_resume(struct omap_dss_device *dssdev)
static void acx_panel_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
int r;
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
omapdss_sdi_display_disable(dssdev);
omapdss_sdi_set_timings(dssdev, timings);
dssdev->panel.timings = *timings;
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
r = omapdss_sdi_display_enable(dssdev);
if (r)
dev_err(&dssdev->dev, "%s enable failed\n", __func__);
}
}
static int acx_panel_check_timings(struct omap_dss_device *dssdev,

View file

@ -545,6 +545,8 @@ struct panel_drv_data {
struct omap_dss_device *dssdev;
struct panel_config *panel_config;
struct mutex lock;
};
static inline struct panel_generic_dpi_data
@ -563,6 +565,9 @@ static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev)
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
return 0;
omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings);
omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines);
r = omapdss_dpi_display_enable(dssdev);
if (r)
goto err0;
@ -634,6 +639,8 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev)
drv_data->dssdev = dssdev;
drv_data->panel_config = panel_config;
mutex_init(&drv_data->lock);
dev_set_drvdata(&dssdev->dev, drv_data);
return 0;
@ -652,56 +659,108 @@ static void __exit generic_dpi_panel_remove(struct omap_dss_device *dssdev)
static int generic_dpi_panel_enable(struct omap_dss_device *dssdev)
{
int r = 0;
struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
int r;
mutex_lock(&drv_data->lock);
r = generic_dpi_panel_power_on(dssdev);
if (r)
return r;
goto err;
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
err:
mutex_unlock(&drv_data->lock);
return 0;
return r;
}
static void generic_dpi_panel_disable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
mutex_lock(&drv_data->lock);
generic_dpi_panel_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
mutex_unlock(&drv_data->lock);
}
static int generic_dpi_panel_suspend(struct omap_dss_device *dssdev)
{
struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
mutex_lock(&drv_data->lock);
generic_dpi_panel_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
mutex_unlock(&drv_data->lock);
return 0;
}
static int generic_dpi_panel_resume(struct omap_dss_device *dssdev)
{
int r = 0;
struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
int r;
mutex_lock(&drv_data->lock);
r = generic_dpi_panel_power_on(dssdev);
if (r)
return r;
goto err;
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
return 0;
err:
mutex_unlock(&drv_data->lock);
return r;
}
static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
dpi_set_timings(dssdev, timings);
struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
mutex_lock(&drv_data->lock);
omapdss_dpi_set_timings(dssdev, timings);
dssdev->panel.timings = *timings;
mutex_unlock(&drv_data->lock);
}
static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
mutex_lock(&drv_data->lock);
*timings = dssdev->panel.timings;
mutex_unlock(&drv_data->lock);
}
static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
return dpi_check_timings(dssdev, timings);
struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
int r;
mutex_lock(&drv_data->lock);
r = dpi_check_timings(dssdev, timings);
mutex_unlock(&drv_data->lock);
return r;
}
static struct omap_dss_driver dpi_driver = {
@ -714,6 +773,7 @@ static struct omap_dss_driver dpi_driver = {
.resume = generic_dpi_panel_resume,
.set_timings = generic_dpi_panel_set_timings,
.get_timings = generic_dpi_panel_get_timings,
.check_timings = generic_dpi_panel_check_timings,
.driver = {

View file

@ -55,6 +55,9 @@ static int lb035q02_panel_power_on(struct omap_dss_device *dssdev)
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
return 0;
omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings);
omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines);
r = omapdss_dpi_display_enable(dssdev);
if (r)
goto err0;

View file

@ -150,11 +150,17 @@ static void blizzard_ctrl_setup_update(struct omap_dss_device *dssdev,
BLIZZARD_SRC_WRITE_LCD :
BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE;
omap_rfbi_configure(dssdev, 16, 8);
omapdss_rfbi_set_pixel_size(dssdev, 16);
omapdss_rfbi_set_data_lines(dssdev, 8);
omap_rfbi_configure(dssdev);
blizzard_write(BLIZZARD_INPUT_WIN_X_START_0, tmp, 18);
omap_rfbi_configure(dssdev, 16, 16);
omapdss_rfbi_set_pixel_size(dssdev, 16);
omapdss_rfbi_set_data_lines(dssdev, 16);
omap_rfbi_configure(dssdev);
}
static void mipid_transfer(struct spi_device *spi, int cmd, const u8 *wbuf,
@ -297,6 +303,12 @@ static int n8x0_panel_power_on(struct omap_dss_device *dssdev)
goto err_plat_en;
}
omapdss_rfbi_set_size(dssdev, dssdev->panel.timings.x_res,
dssdev->panel.timings.y_res);
omapdss_rfbi_set_pixel_size(dssdev, dssdev->ctrl.pixel_size);
omapdss_rfbi_set_data_lines(dssdev, dssdev->phy.rfbi.data_lines);
omapdss_rfbi_set_interface_timings(dssdev, &dssdev->ctrl.rfbi_timings);
r = omapdss_rfbi_display_enable(dssdev);
if (r)
goto err_rfbi_en;
@ -477,6 +489,7 @@ static int n8x0_panel_probe(struct omap_dss_device *dssdev)
dssdev->panel.timings.y_res = 480;
dssdev->ctrl.pixel_size = 16;
dssdev->ctrl.rfbi_timings = n8x0_panel_timings;
dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
memset(&props, 0, sizeof(props));
props.max_brightness = 127;
@ -625,17 +638,25 @@ static int n8x0_panel_update(struct omap_dss_device *dssdev,
u16 x, u16 y, u16 w, u16 h)
{
struct panel_drv_data *ddata = get_drv_data(dssdev);
u16 dw, dh;
dev_dbg(&dssdev->dev, "update\n");
dw = dssdev->panel.timings.x_res;
dh = dssdev->panel.timings.y_res;
if (x != 0 || y != 0 || w != dw || h != dh) {
dev_err(&dssdev->dev, "invaid update region %d, %d, %d, %d\n",
x, y, w, h);
return -EINVAL;
}
mutex_lock(&ddata->lock);
rfbi_bus_lock();
omap_rfbi_prepare_update(dssdev, &x, &y, &w, &h);
blizzard_ctrl_setup_update(dssdev, x, y, w, h);
omap_rfbi_update(dssdev, x, y, w, h, update_done, NULL);
omap_rfbi_update(dssdev, update_done, NULL);
mutex_unlock(&ddata->lock);

View file

@ -175,6 +175,9 @@ static int nec_8048_panel_power_on(struct omap_dss_device *dssdev)
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
return 0;
omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings);
omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines);
r = omapdss_dpi_display_enable(dssdev);
if (r)
goto err0;

View file

@ -377,6 +377,10 @@ static int picodlp_panel_power_on(struct omap_dss_device *dssdev)
* then only i2c commands can be successfully sent to dpp2600
*/
msleep(1000);
omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings);
omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines);
r = omapdss_dpi_display_enable(dssdev);
if (r) {
dev_err(&dssdev->dev, "failed to enable DPI\n");

View file

@ -142,6 +142,9 @@ static int sharp_ls_power_on(struct omap_dss_device *dssdev)
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
return 0;
omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings);
omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines);
r = omapdss_dpi_display_enable(dssdev);
if (r)
goto err0;

View file

@ -121,6 +121,18 @@ struct taal_data {
struct omap_dss_device *dssdev;
/* panel specific HW info */
struct panel_config *panel_config;
/* panel HW configuration from DT or platform data */
int reset_gpio;
int ext_te_gpio;
bool use_dsi_backlight;
struct omap_dsi_pin_config pin_config;
/* runtime variables */
bool enabled;
u8 rotate;
bool mirror;
@ -145,16 +157,8 @@ struct taal_data {
bool ulps_enabled;
unsigned ulps_timeout;
struct delayed_work ulps_work;
struct panel_config *panel_config;
};
static inline struct nokia_dsi_panel_data
*get_panel_data(const struct omap_dss_device *dssdev)
{
return (struct nokia_dsi_panel_data *) dssdev->data;
}
static void taal_esd_work(struct work_struct *work);
static void taal_ulps_work(struct work_struct *work);
@ -371,7 +375,6 @@ static void taal_cancel_ulps_work(struct omap_dss_device *dssdev)
static int taal_enter_ulps(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
int r;
if (td->ulps_enabled)
@ -383,7 +386,8 @@ static int taal_enter_ulps(struct omap_dss_device *dssdev)
if (r)
goto err;
disable_irq(gpio_to_irq(panel_data->ext_te_gpio));
if (gpio_is_valid(td->ext_te_gpio))
disable_irq(gpio_to_irq(td->ext_te_gpio));
omapdss_dsi_display_disable(dssdev, false, true);
@ -405,7 +409,6 @@ err:
static int taal_exit_ulps(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
int r;
if (!td->ulps_enabled)
@ -425,7 +428,8 @@ static int taal_exit_ulps(struct omap_dss_device *dssdev)
goto err2;
}
enable_irq(gpio_to_irq(panel_data->ext_te_gpio));
if (gpio_is_valid(td->ext_te_gpio))
enable_irq(gpio_to_irq(td->ext_te_gpio));
taal_queue_ulps_work(dssdev);
@ -438,7 +442,8 @@ err2:
r = taal_panel_reset(dssdev);
if (!r) {
enable_irq(gpio_to_irq(panel_data->ext_te_gpio));
if (gpio_is_valid(td->ext_te_gpio))
enable_irq(gpio_to_irq(td->ext_te_gpio));
td->ulps_enabled = false;
}
err1:
@ -835,94 +840,135 @@ static struct attribute_group taal_attr_group = {
static void taal_hw_reset(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
if (panel_data->reset_gpio == -1)
if (!gpio_is_valid(td->reset_gpio))
return;
gpio_set_value(panel_data->reset_gpio, 1);
gpio_set_value(td->reset_gpio, 1);
if (td->panel_config->reset_sequence.high)
udelay(td->panel_config->reset_sequence.high);
/* reset the panel */
gpio_set_value(panel_data->reset_gpio, 0);
gpio_set_value(td->reset_gpio, 0);
/* assert reset */
if (td->panel_config->reset_sequence.low)
udelay(td->panel_config->reset_sequence.low);
gpio_set_value(panel_data->reset_gpio, 1);
gpio_set_value(td->reset_gpio, 1);
/* wait after releasing reset */
if (td->panel_config->sleep.hw_reset)
msleep(td->panel_config->sleep.hw_reset);
}
static void taal_probe_pdata(struct taal_data *td,
const struct nokia_dsi_panel_data *pdata)
{
td->reset_gpio = pdata->reset_gpio;
if (pdata->use_ext_te)
td->ext_te_gpio = pdata->ext_te_gpio;
else
td->ext_te_gpio = -1;
td->esd_interval = pdata->esd_interval;
td->ulps_timeout = pdata->ulps_timeout;
td->use_dsi_backlight = pdata->use_dsi_backlight;
td->pin_config = pdata->pin_config;
}
static int taal_probe(struct omap_dss_device *dssdev)
{
struct backlight_properties props;
struct taal_data *td;
struct backlight_device *bldev = NULL;
struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
struct panel_config *panel_config = NULL;
int r, i;
const char *panel_name;
dev_dbg(&dssdev->dev, "probe\n");
if (!panel_data || !panel_data->name) {
r = -EINVAL;
goto err;
td = devm_kzalloc(&dssdev->dev, sizeof(*td), GFP_KERNEL);
if (!td)
return -ENOMEM;
dev_set_drvdata(&dssdev->dev, td);
td->dssdev = dssdev;
if (dssdev->data) {
const struct nokia_dsi_panel_data *pdata = dssdev->data;
taal_probe_pdata(td, pdata);
panel_name = pdata->name;
} else {
return -ENODEV;
}
if (panel_name == NULL)
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(panel_configs); i++) {
if (strcmp(panel_data->name, panel_configs[i].name) == 0) {
panel_config = &panel_configs[i];
if (strcmp(panel_name, panel_configs[i].name) == 0) {
td->panel_config = &panel_configs[i];
break;
}
}
if (!panel_config) {
r = -EINVAL;
goto err;
}
if (!td->panel_config)
return -EINVAL;
dssdev->panel.timings = panel_config->timings;
dssdev->panel.timings = td->panel_config->timings;
dssdev->panel.dsi_pix_fmt = OMAP_DSS_DSI_FMT_RGB888;
td = kzalloc(sizeof(*td), GFP_KERNEL);
if (!td) {
r = -ENOMEM;
goto err;
}
td->dssdev = dssdev;
td->panel_config = panel_config;
td->esd_interval = panel_data->esd_interval;
td->ulps_enabled = false;
td->ulps_timeout = panel_data->ulps_timeout;
dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
mutex_init(&td->lock);
atomic_set(&td->do_update, 0);
if (gpio_is_valid(td->reset_gpio)) {
r = devm_gpio_request_one(&dssdev->dev, td->reset_gpio,
GPIOF_OUT_INIT_LOW, "taal rst");
if (r) {
dev_err(&dssdev->dev, "failed to request reset gpio\n");
return r;
}
}
if (gpio_is_valid(td->ext_te_gpio)) {
r = devm_gpio_request_one(&dssdev->dev, td->ext_te_gpio,
GPIOF_IN, "taal irq");
if (r) {
dev_err(&dssdev->dev, "GPIO request failed\n");
return r;
}
r = devm_request_irq(&dssdev->dev, gpio_to_irq(td->ext_te_gpio),
taal_te_isr,
IRQF_TRIGGER_RISING,
"taal vsync", dssdev);
if (r) {
dev_err(&dssdev->dev, "IRQ request failed\n");
return r;
}
INIT_DEFERRABLE_WORK(&td->te_timeout_work,
taal_te_timeout_work_callback);
dev_dbg(&dssdev->dev, "Using GPIO TE\n");
}
td->workqueue = create_singlethread_workqueue("taal_esd");
if (td->workqueue == NULL) {
dev_err(&dssdev->dev, "can't create ESD workqueue\n");
r = -ENOMEM;
goto err_wq;
return -ENOMEM;
}
INIT_DEFERRABLE_WORK(&td->esd_work, taal_esd_work);
INIT_DELAYED_WORK(&td->ulps_work, taal_ulps_work);
dev_set_drvdata(&dssdev->dev, td);
if (gpio_is_valid(panel_data->reset_gpio)) {
r = gpio_request_one(panel_data->reset_gpio, GPIOF_OUT_INIT_LOW,
"taal rst");
if (r) {
dev_err(&dssdev->dev, "failed to request reset gpio\n");
goto err_rst_gpio;
}
}
taal_hw_reset(dssdev);
if (panel_data->use_dsi_backlight) {
if (td->use_dsi_backlight) {
memset(&props, 0, sizeof(struct backlight_properties));
props.max_brightness = 255;
@ -943,31 +989,6 @@ static int taal_probe(struct omap_dss_device *dssdev)
taal_bl_update_status(bldev);
}
if (panel_data->use_ext_te) {
int gpio = panel_data->ext_te_gpio;
r = gpio_request_one(gpio, GPIOF_IN, "taal irq");
if (r) {
dev_err(&dssdev->dev, "GPIO request failed\n");
goto err_gpio;
}
r = request_irq(gpio_to_irq(gpio), taal_te_isr,
IRQF_TRIGGER_RISING,
"taal vsync", dssdev);
if (r) {
dev_err(&dssdev->dev, "IRQ request failed\n");
gpio_free(gpio);
goto err_irq;
}
INIT_DEFERRABLE_WORK(&td->te_timeout_work,
taal_te_timeout_work_callback);
dev_dbg(&dssdev->dev, "Using GPIO TE\n");
}
r = omap_dsi_request_vc(dssdev, &td->channel);
if (r) {
dev_err(&dssdev->dev, "failed to get virtual channel\n");
@ -991,29 +1012,16 @@ static int taal_probe(struct omap_dss_device *dssdev)
err_vc_id:
omap_dsi_release_vc(dssdev, td->channel);
err_req_vc:
if (panel_data->use_ext_te)
free_irq(gpio_to_irq(panel_data->ext_te_gpio), dssdev);
err_irq:
if (panel_data->use_ext_te)
gpio_free(panel_data->ext_te_gpio);
err_gpio:
if (bldev != NULL)
backlight_device_unregister(bldev);
err_bl:
if (gpio_is_valid(panel_data->reset_gpio))
gpio_free(panel_data->reset_gpio);
err_rst_gpio:
destroy_workqueue(td->workqueue);
err_wq:
kfree(td);
err:
return r;
}
static void __exit taal_remove(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
struct backlight_device *bldev;
dev_dbg(&dssdev->dev, "remove\n");
@ -1021,12 +1029,6 @@ static void __exit taal_remove(struct omap_dss_device *dssdev)
sysfs_remove_group(&dssdev->dev.kobj, &taal_attr_group);
omap_dsi_release_vc(dssdev, td->channel);
if (panel_data->use_ext_te) {
int gpio = panel_data->ext_te_gpio;
free_irq(gpio_to_irq(gpio), dssdev);
gpio_free(gpio);
}
bldev = td->bldev;
if (bldev != NULL) {
bldev->props.power = FB_BLANK_POWERDOWN;
@ -1040,26 +1042,31 @@ static void __exit taal_remove(struct omap_dss_device *dssdev)
/* reset, to be sure that the panel is in a valid state */
taal_hw_reset(dssdev);
if (gpio_is_valid(panel_data->reset_gpio))
gpio_free(panel_data->reset_gpio);
kfree(td);
}
static int taal_power_on(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
u8 id1, id2, id3;
int r;
r = omapdss_dsi_configure_pins(dssdev, &panel_data->pin_config);
r = omapdss_dsi_configure_pins(dssdev, &td->pin_config);
if (r) {
dev_err(&dssdev->dev, "failed to configure DSI pins\n");
goto err0;
};
omapdss_dsi_set_size(dssdev, dssdev->panel.timings.x_res,
dssdev->panel.timings.y_res);
omapdss_dsi_set_pixel_format(dssdev, OMAP_DSS_DSI_FMT_RGB888);
omapdss_dsi_set_operation_mode(dssdev, OMAP_DSS_DSI_CMD_MODE);
r = omapdss_dsi_set_clocks(dssdev, 216000000, 10000000);
if (r) {
dev_err(&dssdev->dev, "failed to set HS and LP clocks\n");
goto err0;
}
r = omapdss_dsi_display_enable(dssdev);
if (r) {
dev_err(&dssdev->dev, "failed to enable DSI\n");
@ -1356,7 +1363,6 @@ static int taal_update(struct omap_dss_device *dssdev,
u16 x, u16 y, u16 w, u16 h)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
int r;
dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h);
@ -1380,7 +1386,7 @@ static int taal_update(struct omap_dss_device *dssdev,
if (r)
goto err;
if (td->te_enabled && panel_data->use_ext_te) {
if (td->te_enabled && gpio_is_valid(td->ext_te_gpio)) {
schedule_delayed_work(&td->te_timeout_work,
msecs_to_jiffies(250));
atomic_set(&td->do_update, 1);
@ -1419,7 +1425,6 @@ static int taal_sync(struct omap_dss_device *dssdev)
static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
int r;
if (enable)
@ -1427,7 +1432,7 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable)
else
r = taal_dcs_write_0(td, MIPI_DCS_SET_TEAR_OFF);
if (!panel_data->use_ext_te)
if (!gpio_is_valid(td->ext_te_gpio))
omapdss_dsi_enable_te(dssdev, enable);
if (td->panel_config->sleep.enable_te)
@ -1487,6 +1492,7 @@ static int taal_get_te(struct omap_dss_device *dssdev)
static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
u16 dw, dh;
int r;
dev_dbg(&dssdev->dev, "rotate %d\n", rotate);
@ -1508,6 +1514,16 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
goto err;
}
if (rotate == 0 || rotate == 2) {
dw = dssdev->panel.timings.x_res;
dh = dssdev->panel.timings.y_res;
} else {
dw = dssdev->panel.timings.y_res;
dh = dssdev->panel.timings.x_res;
}
omapdss_dsi_set_size(dssdev, dw, dh);
td->rotate = rotate;
dsi_bus_unlock(dssdev);
@ -1726,7 +1742,6 @@ static void taal_esd_work(struct work_struct *work)
struct taal_data *td = container_of(work, struct taal_data,
esd_work.work);
struct omap_dss_device *dssdev = td->dssdev;
struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
u8 state1, state2;
int r;
@ -1773,7 +1788,7 @@ static void taal_esd_work(struct work_struct *work)
}
/* Self-diagnostics result is also shown on TE GPIO line. We need
* to re-enable TE after self diagnostics */
if (td->te_enabled && panel_data->use_ext_te) {
if (td->te_enabled && gpio_is_valid(td->ext_te_gpio)) {
r = taal_dcs_write_1(td, MIPI_DCS_SET_TEAR_ON, 0);
if (r)
goto err;

View file

@ -65,6 +65,9 @@ static int tfp410_power_on(struct omap_dss_device *dssdev)
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
return 0;
omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings);
omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines);
r = omapdss_dpi_display_enable(dssdev);
if (r)
goto err0;
@ -116,8 +119,8 @@ static int tfp410_probe(struct omap_dss_device *dssdev)
}
if (gpio_is_valid(ddata->pd_gpio)) {
r = gpio_request_one(ddata->pd_gpio, GPIOF_OUT_INIT_LOW,
"tfp410 pd");
r = devm_gpio_request_one(&dssdev->dev, ddata->pd_gpio,
GPIOF_OUT_INIT_LOW, "tfp410 pd");
if (r) {
dev_err(&dssdev->dev, "Failed to request PD GPIO %d\n",
ddata->pd_gpio);
@ -132,8 +135,7 @@ static int tfp410_probe(struct omap_dss_device *dssdev)
if (!adapter) {
dev_err(&dssdev->dev, "Failed to get I2C adapter, bus %d\n",
i2c_bus_num);
r = -EINVAL;
goto err_i2c;
return -EINVAL;
}
ddata->i2c_adapter = adapter;
@ -142,10 +144,6 @@ static int tfp410_probe(struct omap_dss_device *dssdev)
dev_set_drvdata(&dssdev->dev, ddata);
return 0;
err_i2c:
if (gpio_is_valid(ddata->pd_gpio))
gpio_free(ddata->pd_gpio);
return r;
}
static void __exit tfp410_remove(struct omap_dss_device *dssdev)
@ -157,9 +155,6 @@ static void __exit tfp410_remove(struct omap_dss_device *dssdev)
if (ddata->i2c_adapter)
i2c_put_adapter(ddata->i2c_adapter);
if (gpio_is_valid(ddata->pd_gpio))
gpio_free(ddata->pd_gpio);
dev_set_drvdata(&dssdev->dev, NULL);
mutex_unlock(&ddata->lock);
@ -231,7 +226,8 @@ static void tfp410_set_timings(struct omap_dss_device *dssdev,
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
mutex_lock(&ddata->lock);
dpi_set_timings(dssdev, timings);
omapdss_dpi_set_timings(dssdev, timings);
dssdev->panel.timings = *timings;
mutex_unlock(&ddata->lock);
}

View file

@ -337,6 +337,9 @@ static int tpo_td043_enable_dss(struct omap_dss_device *dssdev)
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
return 0;
omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings);
omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines);
r = omapdss_dpi_display_enable(dssdev);
if (r)
goto err0;
@ -480,7 +483,9 @@ static void tpo_td043_remove(struct omap_dss_device *dssdev)
static void tpo_td043_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
dpi_set_timings(dssdev, timings);
omapdss_dpi_set_timings(dssdev, timings);
dssdev->panel.timings = *timings;
}
static int tpo_td043_check_timings(struct omap_dss_device *dssdev,

View file

@ -84,7 +84,7 @@ config OMAP2_DSS_SDI
config OMAP2_DSS_DSI
bool "DSI support"
depends on ARCH_OMAP3 || ARCH_OMAP4
depends on ARCH_OMAP3 || ARCH_OMAP4 || ARCH_OMAP5
default n
help
MIPI DSI (Display Serial Interface) support.

View file

@ -1,9 +1,9 @@
obj-$(CONFIG_OMAP2_DSS) += omapdss.o
omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \
manager.o overlay.o apply.o
manager.o manager-sysfs.o overlay.o overlay-sysfs.o output.o apply.o
omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o
omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o
omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o venc_panel.o
omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o
omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o
omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi.o \

View file

@ -111,9 +111,6 @@ static struct {
struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS];
struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS];
bool fifo_merge_dirty;
bool fifo_merge;
bool irq_enabled;
} dss_data;
@ -424,17 +421,25 @@ static void wait_pending_extra_info_updates(void)
int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
{
unsigned long timeout = msecs_to_jiffies(500);
struct mgr_priv_data *mp;
struct mgr_priv_data *mp = get_mgr_priv(mgr);
u32 irq;
unsigned long flags;
int r;
int i;
struct omap_dss_device *dssdev = mgr->device;
if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
return 0;
spin_lock_irqsave(&data_lock, flags);
if (mgr_manual_update(mgr))
if (mgr_manual_update(mgr)) {
spin_unlock_irqrestore(&data_lock, flags);
return 0;
}
if (!mp->enabled) {
spin_unlock_irqrestore(&data_lock, flags);
return 0;
}
spin_unlock_irqrestore(&data_lock, flags);
r = dispc_runtime_get();
if (r)
@ -442,10 +447,8 @@ int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
irq = dispc_mgr_get_vsync_irq(mgr->id);
mp = get_mgr_priv(mgr);
i = 0;
while (1) {
unsigned long flags;
bool shadow_dirty, dirty;
spin_lock_irqsave(&data_lock, flags);
@ -489,21 +492,30 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
{
unsigned long timeout = msecs_to_jiffies(500);
struct ovl_priv_data *op;
struct omap_dss_device *dssdev;
struct mgr_priv_data *mp;
u32 irq;
unsigned long flags;
int r;
int i;
if (!ovl->manager)
return 0;
dssdev = ovl->manager->device;
mp = get_mgr_priv(ovl->manager);
if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
return 0;
spin_lock_irqsave(&data_lock, flags);
if (ovl_manual_update(ovl))
if (ovl_manual_update(ovl)) {
spin_unlock_irqrestore(&data_lock, flags);
return 0;
}
if (!mp->enabled) {
spin_unlock_irqrestore(&data_lock, flags);
return 0;
}
spin_unlock_irqrestore(&data_lock, flags);
r = dispc_runtime_get();
if (r)
@ -514,7 +526,6 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
op = get_ovl_priv(ovl);
i = 0;
while (1) {
unsigned long flags;
bool shadow_dirty, dirty;
spin_lock_irqsave(&data_lock, flags);
@ -573,7 +584,7 @@ static void dss_ovl_write_regs(struct omap_overlay *ovl)
replication = dss_ovl_use_replication(mp->lcd_config, oi->color_mode);
r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings);
r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings, false);
if (r) {
/*
* We can't do much here, as this function can be called from
@ -677,40 +688,11 @@ static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr)
mp->shadow_extra_info_dirty = true;
}
static void dss_write_regs_common(void)
{
const int num_mgrs = omap_dss_get_num_overlay_managers();
int i;
if (!dss_data.fifo_merge_dirty)
return;
for (i = 0; i < num_mgrs; ++i) {
struct omap_overlay_manager *mgr;
struct mgr_priv_data *mp;
mgr = omap_dss_get_overlay_manager(i);
mp = get_mgr_priv(mgr);
if (mp->enabled) {
if (dss_data.fifo_merge_dirty) {
dispc_enable_fifomerge(dss_data.fifo_merge);
dss_data.fifo_merge_dirty = false;
}
if (mp->updating)
mp->shadow_info_dirty = true;
}
}
}
static void dss_write_regs(void)
{
const int num_mgrs = omap_dss_get_num_overlay_managers();
int i;
dss_write_regs_common();
for (i = 0; i < num_mgrs; ++i) {
struct omap_overlay_manager *mgr;
struct mgr_priv_data *mp;
@ -799,8 +781,6 @@ void dss_mgr_start_update(struct omap_overlay_manager *mgr)
dss_mgr_write_regs(mgr);
dss_mgr_write_regs_extra(mgr);
dss_write_regs_common();
mp->updating = true;
if (!dss_data.irq_enabled && need_isr())
@ -984,20 +964,11 @@ static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl,
op->extra_info_dirty = true;
}
static void dss_apply_fifo_merge(bool use_fifo_merge)
{
if (dss_data.fifo_merge == use_fifo_merge)
return;
dss_data.fifo_merge = use_fifo_merge;
dss_data.fifo_merge_dirty = true;
}
static void dss_ovl_setup_fifo(struct omap_overlay *ovl,
bool use_fifo_merge)
static void dss_ovl_setup_fifo(struct omap_overlay *ovl)
{
struct ovl_priv_data *op = get_ovl_priv(ovl);
u32 fifo_low, fifo_high;
bool use_fifo_merge = false;
if (!op->enabled && !op->enabling)
return;
@ -1008,8 +979,7 @@ static void dss_ovl_setup_fifo(struct omap_overlay *ovl,
dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high);
}
static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr,
bool use_fifo_merge)
static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr)
{
struct omap_overlay *ovl;
struct mgr_priv_data *mp;
@ -1020,10 +990,10 @@ static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr,
return;
list_for_each_entry(ovl, &mgr->overlays, list)
dss_ovl_setup_fifo(ovl, use_fifo_merge);
dss_ovl_setup_fifo(ovl);
}
static void dss_setup_fifos(bool use_fifo_merge)
static void dss_setup_fifos(void)
{
const int num_mgrs = omap_dss_get_num_overlay_managers();
struct omap_overlay_manager *mgr;
@ -1031,91 +1001,15 @@ static void dss_setup_fifos(bool use_fifo_merge)
for (i = 0; i < num_mgrs; ++i) {
mgr = omap_dss_get_overlay_manager(i);
dss_mgr_setup_fifos(mgr, use_fifo_merge);
dss_mgr_setup_fifos(mgr);
}
}
static int get_num_used_managers(void)
{
const int num_mgrs = omap_dss_get_num_overlay_managers();
struct omap_overlay_manager *mgr;
struct mgr_priv_data *mp;
int i;
int enabled_mgrs;
enabled_mgrs = 0;
for (i = 0; i < num_mgrs; ++i) {
mgr = omap_dss_get_overlay_manager(i);
mp = get_mgr_priv(mgr);
if (!mp->enabled)
continue;
enabled_mgrs++;
}
return enabled_mgrs;
}
static int get_num_used_overlays(void)
{
const int num_ovls = omap_dss_get_num_overlays();
struct omap_overlay *ovl;
struct ovl_priv_data *op;
struct mgr_priv_data *mp;
int i;
int enabled_ovls;
enabled_ovls = 0;
for (i = 0; i < num_ovls; ++i) {
ovl = omap_dss_get_overlay(i);
op = get_ovl_priv(ovl);
if (!op->enabled && !op->enabling)
continue;
mp = get_mgr_priv(ovl->manager);
if (!mp->enabled)
continue;
enabled_ovls++;
}
return enabled_ovls;
}
static bool get_use_fifo_merge(void)
{
int enabled_mgrs = get_num_used_managers();
int enabled_ovls = get_num_used_overlays();
if (!dss_has_feature(FEAT_FIFO_MERGE))
return false;
/*
* In theory the only requirement for fifomerge is enabled_ovls <= 1.
* However, if we have two managers enabled and set/unset the fifomerge,
* we need to set the GO bits in particular sequence for the managers,
* and wait in between.
*
* This is rather difficult as new apply calls can happen at any time,
* so we simplify the problem by requiring also that enabled_mgrs <= 1.
* In practice this shouldn't matter, because when only one overlay is
* enabled, most likely only one output is enabled.
*/
return enabled_mgrs <= 1 && enabled_ovls <= 1;
}
int dss_mgr_enable(struct omap_overlay_manager *mgr)
{
struct mgr_priv_data *mp = get_mgr_priv(mgr);
unsigned long flags;
int r;
bool fifo_merge;
mutex_lock(&apply_lock);
@ -1133,23 +1027,11 @@ int dss_mgr_enable(struct omap_overlay_manager *mgr)
goto err;
}
/* step 1: setup fifos/fifomerge before enabling the manager */
fifo_merge = get_use_fifo_merge();
dss_setup_fifos(fifo_merge);
dss_apply_fifo_merge(fifo_merge);
dss_setup_fifos();
dss_write_regs();
dss_set_go_bits();
spin_unlock_irqrestore(&data_lock, flags);
/* wait until fifo config is in */
wait_pending_extra_info_updates();
/* step 2: enable the manager */
spin_lock_irqsave(&data_lock, flags);
if (!mgr_manual_update(mgr))
mp->updating = true;
@ -1174,7 +1056,6 @@ void dss_mgr_disable(struct omap_overlay_manager *mgr)
{
struct mgr_priv_data *mp = get_mgr_priv(mgr);
unsigned long flags;
bool fifo_merge;
mutex_lock(&apply_lock);
@ -1189,16 +1070,8 @@ void dss_mgr_disable(struct omap_overlay_manager *mgr)
mp->updating = false;
mp->enabled = false;
fifo_merge = get_use_fifo_merge();
dss_setup_fifos(fifo_merge);
dss_apply_fifo_merge(fifo_merge);
dss_write_regs();
dss_set_go_bits();
spin_unlock_irqrestore(&data_lock, flags);
wait_pending_extra_info_updates();
out:
mutex_unlock(&apply_lock);
}
@ -1237,29 +1110,29 @@ void dss_mgr_get_info(struct omap_overlay_manager *mgr,
spin_unlock_irqrestore(&data_lock, flags);
}
int dss_mgr_set_device(struct omap_overlay_manager *mgr,
struct omap_dss_device *dssdev)
int dss_mgr_set_output(struct omap_overlay_manager *mgr,
struct omap_dss_output *output)
{
int r;
mutex_lock(&apply_lock);
if (dssdev->manager) {
DSSERR("display '%s' already has a manager '%s'\n",
dssdev->name, dssdev->manager->name);
if (mgr->output) {
DSSERR("manager %s is already connected to an output\n",
mgr->name);
r = -EINVAL;
goto err;
}
if ((mgr->supported_displays & dssdev->type) == 0) {
DSSERR("display '%s' does not support manager '%s'\n",
dssdev->name, mgr->name);
if ((mgr->supported_outputs & output->id) == 0) {
DSSERR("output does not support manager %s\n",
mgr->name);
r = -EINVAL;
goto err;
}
dssdev->manager = mgr;
mgr->device = dssdev;
output->manager = mgr;
mgr->output = output;
mutex_unlock(&apply_lock);
@ -1269,40 +1142,46 @@ err:
return r;
}
int dss_mgr_unset_device(struct omap_overlay_manager *mgr)
int dss_mgr_unset_output(struct omap_overlay_manager *mgr)
{
int r;
struct mgr_priv_data *mp = get_mgr_priv(mgr);
unsigned long flags;
mutex_lock(&apply_lock);
if (!mgr->device) {
DSSERR("failed to unset display, display not set.\n");
if (!mgr->output) {
DSSERR("failed to unset output, output not set\n");
r = -EINVAL;
goto err;
}
/*
* Don't allow currently enabled displays to have the overlay manager
* pulled out from underneath them
*/
if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) {
spin_lock_irqsave(&data_lock, flags);
if (mp->enabled) {
DSSERR("output can't be unset when manager is enabled\n");
r = -EINVAL;
goto err;
goto err1;
}
mgr->device->manager = NULL;
mgr->device = NULL;
spin_unlock_irqrestore(&data_lock, flags);
mgr->output->manager = NULL;
mgr->output = NULL;
mutex_unlock(&apply_lock);
return 0;
err1:
spin_unlock_irqrestore(&data_lock, flags);
err:
mutex_unlock(&apply_lock);
return r;
}
static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr,
struct omap_video_timings *timings)
const struct omap_video_timings *timings)
{
struct mgr_priv_data *mp = get_mgr_priv(mgr);
@ -1311,24 +1190,22 @@ static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr,
}
void dss_mgr_set_timings(struct omap_overlay_manager *mgr,
struct omap_video_timings *timings)
const struct omap_video_timings *timings)
{
unsigned long flags;
mutex_lock(&apply_lock);
struct mgr_priv_data *mp = get_mgr_priv(mgr);
spin_lock_irqsave(&data_lock, flags);
if (mp->updating) {
DSSERR("cannot set timings for %s: manager needs to be disabled\n",
mgr->name);
goto out;
}
dss_apply_mgr_timings(mgr, timings);
dss_write_regs();
dss_set_go_bits();
out:
spin_unlock_irqrestore(&data_lock, flags);
wait_pending_extra_info_updates();
mutex_unlock(&apply_lock);
}
static void dss_apply_mgr_lcd_config(struct omap_overlay_manager *mgr,
@ -1346,7 +1223,7 @@ void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr,
unsigned long flags;
struct mgr_priv_data *mp = get_mgr_priv(mgr);
mutex_lock(&apply_lock);
spin_lock_irqsave(&data_lock, flags);
if (mp->enabled) {
DSSERR("cannot apply lcd config for %s: manager needs to be disabled\n",
@ -1354,19 +1231,9 @@ void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr,
goto out;
}
spin_lock_irqsave(&data_lock, flags);
dss_apply_mgr_lcd_config(mgr, config);
dss_write_regs();
dss_set_go_bits();
spin_unlock_irqrestore(&data_lock, flags);
wait_pending_extra_info_updates();
out:
mutex_unlock(&apply_lock);
spin_unlock_irqrestore(&data_lock, flags);
}
int dss_ovl_set_info(struct omap_overlay *ovl,
@ -1483,6 +1350,13 @@ int dss_ovl_unset_manager(struct omap_overlay *ovl)
goto err;
}
spin_unlock_irqrestore(&data_lock, flags);
/* wait for pending extra_info updates to ensure the ovl is disabled */
wait_pending_extra_info_updates();
spin_lock_irqsave(&data_lock, flags);
op->channel = -1;
ovl->manager = NULL;
@ -1517,7 +1391,6 @@ int dss_ovl_enable(struct omap_overlay *ovl)
{
struct ovl_priv_data *op = get_ovl_priv(ovl);
unsigned long flags;
bool fifo_merge;
int r;
mutex_lock(&apply_lock);
@ -1527,7 +1400,7 @@ int dss_ovl_enable(struct omap_overlay *ovl)
goto err1;
}
if (ovl->manager == NULL || ovl->manager->device == NULL) {
if (ovl->manager == NULL || ovl->manager->output == NULL) {
r = -EINVAL;
goto err1;
}
@ -1543,22 +1416,7 @@ int dss_ovl_enable(struct omap_overlay *ovl)
goto err2;
}
/* step 1: configure fifos/fifomerge for currently enabled ovls */
fifo_merge = get_use_fifo_merge();
dss_setup_fifos(fifo_merge);
dss_apply_fifo_merge(fifo_merge);
dss_write_regs();
dss_set_go_bits();
spin_unlock_irqrestore(&data_lock, flags);
/* wait for fifo configs to go in */
wait_pending_extra_info_updates();
/* step 2: enable the overlay */
spin_lock_irqsave(&data_lock, flags);
dss_setup_fifos();
op->enabling = false;
dss_apply_ovl_enable(ovl, true);
@ -1568,9 +1426,6 @@ int dss_ovl_enable(struct omap_overlay *ovl)
spin_unlock_irqrestore(&data_lock, flags);
/* wait for overlay to be enabled */
wait_pending_extra_info_updates();
mutex_unlock(&apply_lock);
return 0;
@ -1586,7 +1441,6 @@ int dss_ovl_disable(struct omap_overlay *ovl)
{
struct ovl_priv_data *op = get_ovl_priv(ovl);
unsigned long flags;
bool fifo_merge;
int r;
mutex_lock(&apply_lock);
@ -1596,39 +1450,19 @@ int dss_ovl_disable(struct omap_overlay *ovl)
goto err;
}
if (ovl->manager == NULL || ovl->manager->device == NULL) {
if (ovl->manager == NULL || ovl->manager->output == NULL) {
r = -EINVAL;
goto err;
}
/* step 1: disable the overlay */
spin_lock_irqsave(&data_lock, flags);
dss_apply_ovl_enable(ovl, false);
dss_write_regs();
dss_set_go_bits();
spin_unlock_irqrestore(&data_lock, flags);
/* wait for the overlay to be disabled */
wait_pending_extra_info_updates();
/* step 2: configure fifos/fifomerge */
spin_lock_irqsave(&data_lock, flags);
fifo_merge = get_use_fifo_merge();
dss_setup_fifos(fifo_merge);
dss_apply_fifo_merge(fifo_merge);
dss_write_regs();
dss_set_go_bits();
spin_unlock_irqrestore(&data_lock, flags);
/* wait for fifo config to go in */
wait_pending_extra_info_updates();
mutex_unlock(&apply_lock);
return 0;

View file

@ -33,6 +33,7 @@
#include <linux/device.h>
#include <linux/regulator/consumer.h>
#include <linux/suspend.h>
#include <linux/slab.h>
#include <video/omapdss.h>
@ -57,6 +58,11 @@ bool dss_debug;
module_param_named(debug, dss_debug, bool, 0644);
#endif
const char *dss_get_default_display_name(void)
{
return core.default_display_name;
}
/* REGULATORS */
struct regulator *dss_get_vdds_dsi(void)
@ -347,17 +353,14 @@ static int dss_driver_probe(struct device *dev)
int r;
struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver);
struct omap_dss_device *dssdev = to_dss_device(dev);
bool force;
DSSDBG("driver_probe: dev %s/%s, drv %s\n",
dev_name(dev), dssdev->driver_name,
dssdrv->driver.name);
dss_init_device(core.pdev, dssdev);
force = core.default_display_name &&
strcmp(core.default_display_name, dssdev->name) == 0;
dss_recheck_connections(dssdev, force);
r = dss_init_device(core.pdev, dssdev);
if (r)
return r;
r = dssdrv->probe(dssdev);
@ -416,54 +419,44 @@ void omap_dss_unregister_driver(struct omap_dss_driver *dssdriver)
EXPORT_SYMBOL(omap_dss_unregister_driver);
/* DEVICE */
static void reset_device(struct device *dev, int check)
{
u8 *dev_p = (u8 *)dev;
u8 *dev_end = dev_p + sizeof(*dev);
void *saved_pdata;
saved_pdata = dev->platform_data;
if (check) {
/*
* Check if there is any other setting than platform_data
* in struct device; warn that these will be reset by our
* init.
*/
dev->platform_data = NULL;
while (dev_p < dev_end) {
if (*dev_p) {
WARN("%s: struct device fields will be "
"discarded\n",
__func__);
break;
}
dev_p++;
}
}
memset(dev, 0, sizeof(*dev));
dev->platform_data = saved_pdata;
}
static void omap_dss_dev_release(struct device *dev)
{
reset_device(dev, 0);
struct omap_dss_device *dssdev = to_dss_device(dev);
kfree(dssdev);
}
int omap_dss_register_device(struct omap_dss_device *dssdev,
struct device *parent, int disp_num)
{
WARN_ON(!dssdev->driver_name);
static int disp_num_counter;
struct omap_dss_device *dss_alloc_and_init_device(struct device *parent)
{
struct omap_dss_device *dssdev;
dssdev = kzalloc(sizeof(*dssdev), GFP_KERNEL);
if (!dssdev)
return NULL;
reset_device(&dssdev->dev, 1);
dssdev->dev.bus = &dss_bus_type;
dssdev->dev.parent = parent;
dssdev->dev.release = omap_dss_dev_release;
dev_set_name(&dssdev->dev, "display%d", disp_num);
return device_register(&dssdev->dev);
dev_set_name(&dssdev->dev, "display%d", disp_num_counter++);
device_initialize(&dssdev->dev);
return dssdev;
}
void omap_dss_unregister_device(struct omap_dss_device *dssdev)
int dss_add_device(struct omap_dss_device *dssdev)
{
return device_add(&dssdev->dev);
}
void dss_put_device(struct omap_dss_device *dssdev)
{
put_device(&dssdev->dev);
}
void dss_unregister_device(struct omap_dss_device *dssdev)
{
device_unregister(&dssdev->dev);
}
@ -471,15 +464,25 @@ void omap_dss_unregister_device(struct omap_dss_device *dssdev)
static int dss_unregister_dss_dev(struct device *dev, void *data)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
omap_dss_unregister_device(dssdev);
dss_unregister_device(dssdev);
return 0;
}
void omap_dss_unregister_child_devices(struct device *parent)
void dss_unregister_child_devices(struct device *parent)
{
device_for_each_child(parent, NULL, dss_unregister_dss_dev);
}
void dss_copy_device_pdata(struct omap_dss_device *dst,
const struct omap_dss_device *src)
{
u8 *d = (u8 *)dst;
u8 *s = (u8 *)src;
size_t dsize = sizeof(struct device);
memcpy(d + dsize, s + dsize, sizeof(struct omap_dss_device) - dsize);
}
/* BUS */
static int __init omap_dss_bus_register(void)
{

File diff suppressed because it is too large Load diff

View file

@ -36,6 +36,7 @@
#define DISPC_CONTROL2 0x0238
#define DISPC_CONFIG2 0x0620
#define DISPC_DIVISOR 0x0804
#define DISPC_GLOBAL_BUFFER 0x0800
#define DISPC_CONTROL3 0x0848
#define DISPC_CONFIG3 0x084C
@ -355,6 +356,8 @@ static inline u16 DISPC_OVL_BASE(enum omap_plane plane)
return 0x014C;
case OMAP_DSS_VIDEO3:
return 0x0300;
case OMAP_DSS_WB:
return 0x0500;
default:
BUG();
return 0;
@ -370,6 +373,7 @@ static inline u16 DISPC_BA0_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x0000;
case OMAP_DSS_VIDEO3:
case OMAP_DSS_WB:
return 0x0008;
default:
BUG();
@ -385,6 +389,7 @@ static inline u16 DISPC_BA1_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x0004;
case OMAP_DSS_VIDEO3:
case OMAP_DSS_WB:
return 0x000C;
default:
BUG();
@ -404,6 +409,8 @@ static inline u16 DISPC_BA0_UV_OFFSET(enum omap_plane plane)
return 0x04BC;
case OMAP_DSS_VIDEO3:
return 0x0310;
case OMAP_DSS_WB:
return 0x0118;
default:
BUG();
return 0;
@ -422,6 +429,8 @@ static inline u16 DISPC_BA1_UV_OFFSET(enum omap_plane plane)
return 0x04C0;
case OMAP_DSS_VIDEO3:
return 0x0314;
case OMAP_DSS_WB:
return 0x011C;
default:
BUG();
return 0;
@ -451,6 +460,7 @@ static inline u16 DISPC_SIZE_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x000C;
case OMAP_DSS_VIDEO3:
case OMAP_DSS_WB:
return 0x00A8;
default:
BUG();
@ -467,6 +477,7 @@ static inline u16 DISPC_ATTR_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x0010;
case OMAP_DSS_VIDEO3:
case OMAP_DSS_WB:
return 0x0070;
default:
BUG();
@ -486,6 +497,8 @@ static inline u16 DISPC_ATTR2_OFFSET(enum omap_plane plane)
return 0x04DC;
case OMAP_DSS_VIDEO3:
return 0x032C;
case OMAP_DSS_WB:
return 0x0310;
default:
BUG();
return 0;
@ -501,6 +514,7 @@ static inline u16 DISPC_FIFO_THRESH_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x0014;
case OMAP_DSS_VIDEO3:
case OMAP_DSS_WB:
return 0x008C;
default:
BUG();
@ -517,6 +531,7 @@ static inline u16 DISPC_FIFO_SIZE_STATUS_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x0018;
case OMAP_DSS_VIDEO3:
case OMAP_DSS_WB:
return 0x0088;
default:
BUG();
@ -533,6 +548,7 @@ static inline u16 DISPC_ROW_INC_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x001C;
case OMAP_DSS_VIDEO3:
case OMAP_DSS_WB:
return 0x00A4;
default:
BUG();
@ -549,6 +565,7 @@ static inline u16 DISPC_PIX_INC_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x0020;
case OMAP_DSS_VIDEO3:
case OMAP_DSS_WB:
return 0x0098;
default:
BUG();
@ -598,6 +615,7 @@ static inline u16 DISPC_FIR_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x0024;
case OMAP_DSS_VIDEO3:
case OMAP_DSS_WB:
return 0x0090;
default:
BUG();
@ -617,6 +635,8 @@ static inline u16 DISPC_FIR2_OFFSET(enum omap_plane plane)
return 0x055C;
case OMAP_DSS_VIDEO3:
return 0x0424;
case OMAP_DSS_WB:
return 0x290;
default:
BUG();
return 0;
@ -633,6 +653,7 @@ static inline u16 DISPC_PIC_SIZE_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x0028;
case OMAP_DSS_VIDEO3:
case OMAP_DSS_WB:
return 0x0094;
default:
BUG();
@ -651,6 +672,7 @@ static inline u16 DISPC_ACCU0_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x002C;
case OMAP_DSS_VIDEO3:
case OMAP_DSS_WB:
return 0x0000;
default:
BUG();
@ -670,6 +692,8 @@ static inline u16 DISPC_ACCU2_0_OFFSET(enum omap_plane plane)
return 0x0560;
case OMAP_DSS_VIDEO3:
return 0x0428;
case OMAP_DSS_WB:
return 0x0294;
default:
BUG();
return 0;
@ -686,6 +710,7 @@ static inline u16 DISPC_ACCU1_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x0030;
case OMAP_DSS_VIDEO3:
case OMAP_DSS_WB:
return 0x0004;
default:
BUG();
@ -705,6 +730,8 @@ static inline u16 DISPC_ACCU2_1_OFFSET(enum omap_plane plane)
return 0x0564;
case OMAP_DSS_VIDEO3:
return 0x042C;
case OMAP_DSS_WB:
return 0x0298;
default:
BUG();
return 0;
@ -722,6 +749,7 @@ static inline u16 DISPC_FIR_COEF_H_OFFSET(enum omap_plane plane, u16 i)
case OMAP_DSS_VIDEO2:
return 0x0034 + i * 0x8;
case OMAP_DSS_VIDEO3:
case OMAP_DSS_WB:
return 0x0010 + i * 0x8;
default:
BUG();
@ -742,6 +770,8 @@ static inline u16 DISPC_FIR_COEF_H2_OFFSET(enum omap_plane plane, u16 i)
return 0x0568 + i * 0x8;
case OMAP_DSS_VIDEO3:
return 0x0430 + i * 0x8;
case OMAP_DSS_WB:
return 0x02A0 + i * 0x8;
default:
BUG();
return 0;
@ -759,6 +789,7 @@ static inline u16 DISPC_FIR_COEF_HV_OFFSET(enum omap_plane plane, u16 i)
case OMAP_DSS_VIDEO2:
return 0x0038 + i * 0x8;
case OMAP_DSS_VIDEO3:
case OMAP_DSS_WB:
return 0x0014 + i * 0x8;
default:
BUG();
@ -779,6 +810,8 @@ static inline u16 DISPC_FIR_COEF_HV2_OFFSET(enum omap_plane plane, u16 i)
return 0x056C + i * 0x8;
case OMAP_DSS_VIDEO3:
return 0x0434 + i * 0x8;
case OMAP_DSS_WB:
return 0x02A4 + i * 0x8;
default:
BUG();
return 0;
@ -795,6 +828,7 @@ static inline u16 DISPC_CONV_COEF_OFFSET(enum omap_plane plane, u16 i)
case OMAP_DSS_VIDEO1:
case OMAP_DSS_VIDEO2:
case OMAP_DSS_VIDEO3:
case OMAP_DSS_WB:
return 0x0074 + i * 0x4;
default:
BUG();
@ -814,6 +848,7 @@ static inline u16 DISPC_FIR_COEF_V_OFFSET(enum omap_plane plane, u16 i)
case OMAP_DSS_VIDEO2:
return 0x00B4 + i * 0x4;
case OMAP_DSS_VIDEO3:
case OMAP_DSS_WB:
return 0x0050 + i * 0x4;
default:
BUG();
@ -834,6 +869,8 @@ static inline u16 DISPC_FIR_COEF_V2_OFFSET(enum omap_plane plane, u16 i)
return 0x05A8 + i * 0x4;
case OMAP_DSS_VIDEO3:
return 0x0470 + i * 0x4;
case OMAP_DSS_WB:
return 0x02E0 + i * 0x4;
default:
BUG();
return 0;

View file

@ -142,7 +142,11 @@ static ssize_t display_timings_store(struct device *dev,
if (r)
return r;
dssdev->driver->disable(dssdev);
dssdev->driver->set_timings(dssdev, &t);
r = dssdev->driver->enable(dssdev);
if (r)
return r;
return size;
}
@ -316,26 +320,117 @@ void omapdss_default_get_timings(struct omap_dss_device *dssdev,
}
EXPORT_SYMBOL(omapdss_default_get_timings);
void dss_init_device(struct platform_device *pdev,
/*
* Connect dssdev to a manager if the manager is free or if force is specified.
* Connect all overlays to that manager if they are free or if force is
* specified.
*/
static int dss_init_connections(struct omap_dss_device *dssdev, bool force)
{
struct omap_dss_output *out;
struct omap_overlay_manager *mgr;
int i, r;
out = omapdss_get_output_from_dssdev(dssdev);
WARN_ON(dssdev->output);
WARN_ON(out->device);
r = omapdss_output_set_device(out, dssdev);
if (r) {
DSSERR("failed to connect output to new device\n");
return r;
}
mgr = omap_dss_get_overlay_manager(dssdev->channel);
if (mgr->output && !force)
return 0;
if (mgr->output)
mgr->unset_output(mgr);
r = mgr->set_output(mgr, out);
if (r) {
DSSERR("failed to connect manager to output of new device\n");
/* remove the output-device connection we just made */
omapdss_output_unset_device(out);
return r;
}
for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
struct omap_overlay *ovl = omap_dss_get_overlay(i);
if (!ovl->manager || force) {
if (ovl->manager)
ovl->unset_manager(ovl);
r = ovl->set_manager(ovl, mgr);
if (r) {
DSSERR("failed to set initial overlay\n");
return r;
}
}
}
return 0;
}
static void dss_uninit_connections(struct omap_dss_device *dssdev)
{
if (dssdev->output) {
struct omap_overlay_manager *mgr = dssdev->output->manager;
if (mgr)
mgr->unset_output(mgr);
omapdss_output_unset_device(dssdev->output);
}
}
int dss_init_device(struct platform_device *pdev,
struct omap_dss_device *dssdev)
{
struct device_attribute *attr;
int i;
int r;
int i, r;
const char *def_disp_name = dss_get_default_display_name();
bool force;
force = def_disp_name && strcmp(def_disp_name, dssdev->name) == 0;
dss_init_connections(dssdev, force);
/* create device sysfs files */
i = 0;
while ((attr = display_sysfs_attrs[i++]) != NULL) {
r = device_create_file(&dssdev->dev, attr);
if (r)
if (r) {
for (i = i - 2; i >= 0; i--) {
attr = display_sysfs_attrs[i];
device_remove_file(&dssdev->dev, attr);
}
dss_uninit_connections(dssdev);
DSSERR("failed to create sysfs file\n");
return r;
}
}
/* create display? sysfs links */
r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj,
dev_name(&dssdev->dev));
if (r)
if (r) {
while ((attr = display_sysfs_attrs[i++]) != NULL)
device_remove_file(&dssdev->dev, attr);
dss_uninit_connections(dssdev);
DSSERR("failed to create sysfs display link\n");
return r;
}
return 0;
}
void dss_uninit_device(struct platform_device *pdev,
@ -349,8 +444,7 @@ void dss_uninit_device(struct platform_device *pdev,
while ((attr = display_sysfs_attrs[i++]) != NULL)
device_remove_file(&dssdev->dev, attr);
if (dssdev->manager)
dssdev->manager->unset_device(dssdev->manager);
dss_uninit_connections(dssdev);
}
static int dss_suspend_device(struct device *dev, void *data)

View file

@ -29,17 +29,24 @@
#include <linux/errno.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/string.h>
#include <video/omapdss.h>
#include <plat/cpu.h>
#include "dss.h"
#include "dss_features.h"
static struct {
struct regulator *vdds_dsi_reg;
struct platform_device *dsidev;
struct mutex lock;
struct omap_video_timings timings;
struct dss_lcd_mgr_config mgr_config;
int data_lines;
struct omap_dss_output output;
} dpi;
static struct platform_device *dpi_get_dsidev(enum omap_dss_clk_source clk)
@ -121,7 +128,8 @@ static int dpi_set_dispc_clk(struct omap_dss_device *dssdev,
static int dpi_set_mode(struct omap_dss_device *dssdev)
{
struct omap_video_timings *t = &dssdev->panel.timings;
struct omap_video_timings *t = &dpi.timings;
struct omap_overlay_manager *mgr = dssdev->output->manager;
int lck_div = 0, pck_div = 0;
unsigned long fck = 0;
unsigned long pck;
@ -146,37 +154,44 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
t->pixel_clock = pck;
}
dss_mgr_set_timings(dssdev->manager, t);
dss_mgr_set_timings(mgr, t);
return 0;
}
static void dpi_config_lcd_manager(struct omap_dss_device *dssdev)
{
struct omap_overlay_manager *mgr = dssdev->output->manager;
dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
dpi.mgr_config.stallmode = false;
dpi.mgr_config.fifohandcheck = false;
dpi.mgr_config.video_port_width = dssdev->phy.dpi.data_lines;
dpi.mgr_config.video_port_width = dpi.data_lines;
dpi.mgr_config.lcden_sig_polarity = 0;
dss_mgr_set_lcd_config(dssdev->manager, &dpi.mgr_config);
dss_mgr_set_lcd_config(mgr, &dpi.mgr_config);
}
int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
{
struct omap_dss_output *out = dssdev->output;
int r;
if (cpu_is_omap34xx() && !dpi.vdds_dsi_reg) {
mutex_lock(&dpi.lock);
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi.vdds_dsi_reg) {
DSSERR("no VDSS_DSI regulator\n");
return -ENODEV;
r = -ENODEV;
goto err_no_reg;
}
if (dssdev->manager == NULL) {
DSSERR("failed to enable display: no manager\n");
return -ENODEV;
if (out == NULL || out->manager == NULL) {
DSSERR("failed to enable display: no output/manager\n");
r = -ENODEV;
goto err_no_out_mgr;
}
r = omap_dss_start_device(dssdev);
@ -185,7 +200,7 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
goto err_start_dev;
}
if (cpu_is_omap34xx()) {
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) {
r = regulator_enable(dpi.vdds_dsi_reg);
if (r)
goto err_reg_enable;
@ -195,6 +210,10 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
if (r)
goto err_get_dispc;
r = dss_dpi_select_source(dssdev->channel);
if (r)
goto err_src_sel;
if (dpi_use_dsi_pll(dssdev)) {
r = dsi_runtime_get(dpi.dsidev);
if (r)
@ -213,10 +232,12 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
mdelay(2);
r = dss_mgr_enable(dssdev->manager);
r = dss_mgr_enable(out->manager);
if (r)
goto err_mgr_enable;
mutex_unlock(&dpi.lock);
return 0;
err_mgr_enable:
@ -227,20 +248,28 @@ err_dsi_pll_init:
if (dpi_use_dsi_pll(dssdev))
dsi_runtime_put(dpi.dsidev);
err_get_dsi:
err_src_sel:
dispc_runtime_put();
err_get_dispc:
if (cpu_is_omap34xx())
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
regulator_disable(dpi.vdds_dsi_reg);
err_reg_enable:
omap_dss_stop_device(dssdev);
err_start_dev:
err_no_out_mgr:
err_no_reg:
mutex_unlock(&dpi.lock);
return r;
}
EXPORT_SYMBOL(omapdss_dpi_display_enable);
void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
{
dss_mgr_disable(dssdev->manager);
struct omap_overlay_manager *mgr = dssdev->output->manager;
mutex_lock(&dpi.lock);
dss_mgr_disable(mgr);
if (dpi_use_dsi_pll(dssdev)) {
dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
@ -250,44 +279,39 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
dispc_runtime_put();
if (cpu_is_omap34xx())
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
regulator_disable(dpi.vdds_dsi_reg);
omap_dss_stop_device(dssdev);
mutex_unlock(&dpi.lock);
}
EXPORT_SYMBOL(omapdss_dpi_display_disable);
void dpi_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
void omapdss_dpi_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
int r;
DSSDBG("dpi_set_timings\n");
dssdev->panel.timings = *timings;
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
r = dispc_runtime_get();
if (r)
return;
dpi_set_mode(dssdev);
mutex_lock(&dpi.lock);
dispc_runtime_put();
} else {
dss_mgr_set_timings(dssdev->manager, timings);
}
dpi.timings = *timings;
mutex_unlock(&dpi.lock);
}
EXPORT_SYMBOL(dpi_set_timings);
EXPORT_SYMBOL(omapdss_dpi_set_timings);
int dpi_check_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
int r;
struct omap_overlay_manager *mgr = dssdev->output->manager;
int lck_div, pck_div;
unsigned long fck;
unsigned long pck;
struct dispc_clock_info dispc_cinfo;
if (dss_mgr_check_timings(dssdev->manager, timings))
if (dss_mgr_check_timings(mgr, timings))
return -EINVAL;
if (timings->pixel_clock == 0)
@ -325,11 +349,22 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
}
EXPORT_SYMBOL(dpi_check_timings);
void omapdss_dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
{
mutex_lock(&dpi.lock);
dpi.data_lines = data_lines;
mutex_unlock(&dpi.lock);
}
EXPORT_SYMBOL(omapdss_dpi_set_data_lines);
static int __init dpi_init_display(struct omap_dss_device *dssdev)
{
DSSDBG("init_display\n");
if (cpu_is_omap34xx() && dpi.vdds_dsi_reg == NULL) {
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) &&
dpi.vdds_dsi_reg == NULL) {
struct regulator *vdds_dsi;
vdds_dsi = dss_get_vdds_dsi();
@ -351,10 +386,14 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev)
return 0;
}
static void __init dpi_probe_pdata(struct platform_device *pdev)
static struct omap_dss_device * __init dpi_find_dssdev(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
int i, r;
const char *def_disp_name = dss_get_default_display_name();
struct omap_dss_device *def_dssdev;
int i;
def_dssdev = NULL;
for (i = 0; i < pdata->num_devices; ++i) {
struct omap_dss_device *dssdev = pdata->devices[i];
@ -362,21 +401,75 @@ static void __init dpi_probe_pdata(struct platform_device *pdev)
if (dssdev->type != OMAP_DISPLAY_TYPE_DPI)
continue;
r = dpi_init_display(dssdev);
if (r) {
DSSERR("device %s init failed: %d\n", dssdev->name, r);
continue;
}
if (def_dssdev == NULL)
def_dssdev = dssdev;
r = omap_dss_register_device(dssdev, &pdev->dev, i);
if (r)
DSSERR("device %s register failed: %d\n",
dssdev->name, r);
if (def_disp_name != NULL &&
strcmp(dssdev->name, def_disp_name) == 0) {
def_dssdev = dssdev;
break;
}
}
return def_dssdev;
}
static void __init dpi_probe_pdata(struct platform_device *dpidev)
{
struct omap_dss_device *plat_dssdev;
struct omap_dss_device *dssdev;
int r;
plat_dssdev = dpi_find_dssdev(dpidev);
if (!plat_dssdev)
return;
dssdev = dss_alloc_and_init_device(&dpidev->dev);
if (!dssdev)
return;
dss_copy_device_pdata(dssdev, plat_dssdev);
r = dpi_init_display(dssdev);
if (r) {
DSSERR("device %s init failed: %d\n", dssdev->name, r);
dss_put_device(dssdev);
return;
}
r = dss_add_device(dssdev);
if (r) {
DSSERR("device %s register failed: %d\n", dssdev->name, r);
dss_put_device(dssdev);
return;
}
}
static void __init dpi_init_output(struct platform_device *pdev)
{
struct omap_dss_output *out = &dpi.output;
out->pdev = pdev;
out->id = OMAP_DSS_OUTPUT_DPI;
out->type = OMAP_DISPLAY_TYPE_DPI;
dss_register_output(out);
}
static void __exit dpi_uninit_output(struct platform_device *pdev)
{
struct omap_dss_output *out = &dpi.output;
dss_unregister_output(out);
}
static int __init omap_dpi_probe(struct platform_device *pdev)
{
mutex_init(&dpi.lock);
dpi_init_output(pdev);
dpi_probe_pdata(pdev);
return 0;
@ -384,7 +477,9 @@ static int __init omap_dpi_probe(struct platform_device *pdev)
static int __exit omap_dpi_remove(struct platform_device *pdev)
{
omap_dss_unregister_child_devices(&pdev->dev);
dss_unregister_child_devices(&pdev->dev);
dpi_uninit_output(pdev);
return 0;
}

File diff suppressed because it is too large Load diff

View file

@ -31,11 +31,11 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/gfp.h>
#include <video/omapdss.h>
#include <plat/cpu.h>
#include <plat/clock.h>
#include "dss.h"
#include "dss_features.h"
@ -65,6 +65,13 @@ struct dss_reg {
static int dss_runtime_get(void);
static void dss_runtime_put(void);
struct dss_features {
u8 fck_div_max;
u8 dss_fck_multiplier;
const char *clk_name;
int (*dpi_select_source)(enum omap_channel channel);
};
static struct {
struct platform_device *pdev;
void __iomem *base;
@ -83,6 +90,8 @@ static struct {
bool ctx_valid;
u32 ctx[DSS_SZ_REGS / sizeof(u32)];
const struct dss_features *feat;
} dss;
static const char * const dss_generic_clk_source_names[] = {
@ -144,7 +153,7 @@ static void dss_restore_context(void)
#undef SR
#undef RR
void dss_sdi_init(u8 datapairs)
void dss_sdi_init(int datapairs)
{
u32 l;
@ -236,7 +245,6 @@ const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src)
return dss_generic_clk_source_names[clk_src];
}
void dss_dump_clocks(struct seq_file *s)
{
unsigned long dpll4_ck_rate;
@ -259,18 +267,10 @@ void dss_dump_clocks(struct seq_file *s)
seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate);
if (cpu_is_omap3630() || cpu_is_omap44xx())
seq_printf(s, "%s (%s) = %lu / %lu = %lu\n",
fclk_name, fclk_real_name,
dpll4_ck_rate,
dpll4_ck_rate / dpll4_m4_ck_rate,
fclk_rate);
else
seq_printf(s, "%s (%s) = %lu / %lu * 2 = %lu\n",
fclk_name, fclk_real_name,
dpll4_ck_rate,
dpll4_ck_rate / dpll4_m4_ck_rate,
fclk_rate);
seq_printf(s, "%s (%s) = %lu / %lu * %d = %lu\n",
fclk_name, fclk_real_name, dpll4_ck_rate,
dpll4_ck_rate / dpll4_m4_ck_rate,
dss.feat->dss_fck_multiplier, fclk_rate);
} else {
seq_printf(s, "%s (%s) = %lu\n",
fclk_name, fclk_real_name,
@ -431,31 +431,6 @@ enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
}
}
/* calculate clock rates using dividers in cinfo */
int dss_calc_clock_rates(struct dss_clock_info *cinfo)
{
if (dss.dpll4_m4_ck) {
unsigned long prate;
u16 fck_div_max = 16;
if (cpu_is_omap3630() || cpu_is_omap44xx())
fck_div_max = 32;
if (cinfo->fck_div > fck_div_max || cinfo->fck_div == 0)
return -EINVAL;
prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
cinfo->fck = prate / cinfo->fck_div;
} else {
if (cinfo->fck_div != 0)
return -EINVAL;
cinfo->fck = clk_get_rate(dss.dss_clk);
}
return 0;
}
int dss_set_clock_div(struct dss_clock_info *cinfo)
{
if (dss.dpll4_m4_ck) {
@ -478,26 +453,6 @@ int dss_set_clock_div(struct dss_clock_info *cinfo)
return 0;
}
int dss_get_clock_div(struct dss_clock_info *cinfo)
{
cinfo->fck = clk_get_rate(dss.dss_clk);
if (dss.dpll4_m4_ck) {
unsigned long prate;
prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
if (cpu_is_omap3630() || cpu_is_omap44xx())
cinfo->fck_div = prate / (cinfo->fck);
else
cinfo->fck_div = prate / (cinfo->fck / 2);
} else {
cinfo->fck_div = 0;
}
return 0;
}
unsigned long dss_get_dpll4_rate(void)
{
if (dss.dpll4_m4_ck)
@ -515,7 +470,7 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
unsigned long fck, max_dss_fck;
u16 fck_div, fck_div_max = 16;
u16 fck_div;
int match = 0;
int min_fck_per_pck;
@ -525,9 +480,8 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
fck = clk_get_rate(dss.dss_clk);
if (req_pck == dss.cache_req_pck &&
((cpu_is_omap34xx() && prate == dss.cache_prate) ||
dss.cache_dss_cinfo.fck == fck)) {
if (req_pck == dss.cache_req_pck && prate == dss.cache_prate &&
dss.cache_dss_cinfo.fck == fck) {
DSSDBG("dispc clock info found from cache.\n");
*dss_cinfo = dss.cache_dss_cinfo;
*dispc_cinfo = dss.cache_dispc_cinfo;
@ -564,16 +518,10 @@ retry:
goto found;
} else {
if (cpu_is_omap3630() || cpu_is_omap44xx())
fck_div_max = 32;
for (fck_div = fck_div_max; fck_div > 0; --fck_div) {
for (fck_div = dss.feat->fck_div_max; fck_div > 0; --fck_div) {
struct dispc_clock_info cur_dispc;
if (fck_div_max == 32)
fck = prate / fck_div;
else
fck = prate / fck_div * 2;
fck = prate / fck_div * dss.feat->dss_fck_multiplier;
if (fck > max_dss_fck)
continue;
@ -648,9 +596,18 @@ void dss_set_dac_pwrdn_bgz(bool enable)
REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */
}
void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select hdmi)
void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select src)
{
REG_FLD_MOD(DSS_CONTROL, hdmi, 15, 15); /* VENC_HDMI_SWITCH */
enum omap_display_type dp;
dp = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT);
/* Complain about invalid selections */
WARN_ON((src == DSS_VENC_TV_CLK) && !(dp & OMAP_DISPLAY_TYPE_VENC));
WARN_ON((src == DSS_HDMI_M_PCLK) && !(dp & OMAP_DISPLAY_TYPE_HDMI));
/* Select only if we have options */
if ((dp & OMAP_DISPLAY_TYPE_VENC) && (dp & OMAP_DISPLAY_TYPE_HDMI))
REG_FLD_MOD(DSS_CONTROL, src, 15, 15); /* VENC_HDMI_SWITCH */
}
enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void)
@ -661,9 +618,71 @@ enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void)
if ((displays & OMAP_DISPLAY_TYPE_HDMI) == 0)
return DSS_VENC_TV_CLK;
if ((displays & OMAP_DISPLAY_TYPE_VENC) == 0)
return DSS_HDMI_M_PCLK;
return REG_GET(DSS_CONTROL, 15, 15);
}
static int dss_dpi_select_source_omap2_omap3(enum omap_channel channel)
{
if (channel != OMAP_DSS_CHANNEL_LCD)
return -EINVAL;
return 0;
}
static int dss_dpi_select_source_omap4(enum omap_channel channel)
{
int val;
switch (channel) {
case OMAP_DSS_CHANNEL_LCD2:
val = 0;
break;
case OMAP_DSS_CHANNEL_DIGIT:
val = 1;
break;
default:
return -EINVAL;
}
REG_FLD_MOD(DSS_CONTROL, val, 17, 17);
return 0;
}
static int dss_dpi_select_source_omap5(enum omap_channel channel)
{
int val;
switch (channel) {
case OMAP_DSS_CHANNEL_LCD:
val = 1;
break;
case OMAP_DSS_CHANNEL_LCD2:
val = 2;
break;
case OMAP_DSS_CHANNEL_LCD3:
val = 3;
break;
case OMAP_DSS_CHANNEL_DIGIT:
val = 0;
break;
default:
return -EINVAL;
}
REG_FLD_MOD(DSS_CONTROL, val, 17, 16);
return 0;
}
int dss_dpi_select_source(enum omap_channel channel)
{
return dss.feat->dpi_select_source(channel);
}
static int dss_get_clocks(void)
{
struct clk *clk;
@ -678,22 +697,11 @@ static int dss_get_clocks(void)
dss.dss_clk = clk;
if (cpu_is_omap34xx()) {
clk = clk_get(NULL, "dpll4_m4_ck");
if (IS_ERR(clk)) {
DSSERR("Failed to get dpll4_m4_ck\n");
r = PTR_ERR(clk);
goto err;
}
} else if (cpu_is_omap44xx()) {
clk = clk_get(NULL, "dpll_per_m5x2_ck");
if (IS_ERR(clk)) {
DSSERR("Failed to get dpll_per_m5x2_ck\n");
r = PTR_ERR(clk);
goto err;
}
} else { /* omap24xx */
clk = NULL;
clk = clk_get(NULL, dss.feat->clk_name);
if (IS_ERR(clk)) {
DSSERR("Failed to get %s\n", dss.feat->clk_name);
r = PTR_ERR(clk);
goto err;
}
dss.dpll4_m4_ck = clk;
@ -749,6 +757,71 @@ void dss_debug_dump_clocks(struct seq_file *s)
}
#endif
static const struct dss_features omap24xx_dss_feats __initconst = {
.fck_div_max = 16,
.dss_fck_multiplier = 2,
.clk_name = NULL,
.dpi_select_source = &dss_dpi_select_source_omap2_omap3,
};
static const struct dss_features omap34xx_dss_feats __initconst = {
.fck_div_max = 16,
.dss_fck_multiplier = 2,
.clk_name = "dpll4_m4_ck",
.dpi_select_source = &dss_dpi_select_source_omap2_omap3,
};
static const struct dss_features omap3630_dss_feats __initconst = {
.fck_div_max = 32,
.dss_fck_multiplier = 1,
.clk_name = "dpll4_m4_ck",
.dpi_select_source = &dss_dpi_select_source_omap2_omap3,
};
static const struct dss_features omap44xx_dss_feats __initconst = {
.fck_div_max = 32,
.dss_fck_multiplier = 1,
.clk_name = "dpll_per_m5x2_ck",
.dpi_select_source = &dss_dpi_select_source_omap4,
};
static const struct dss_features omap54xx_dss_feats __initconst = {
.fck_div_max = 64,
.dss_fck_multiplier = 1,
.clk_name = "dpll_per_h12x2_ck",
.dpi_select_source = &dss_dpi_select_source_omap5,
};
static int __init dss_init_features(struct device *dev)
{
const struct dss_features *src;
struct dss_features *dst;
dst = devm_kzalloc(dev, sizeof(*dst), GFP_KERNEL);
if (!dst) {
dev_err(dev, "Failed to allocate local DSS Features\n");
return -ENOMEM;
}
if (cpu_is_omap24xx())
src = &omap24xx_dss_feats;
else if (cpu_is_omap34xx())
src = &omap34xx_dss_feats;
else if (cpu_is_omap3630())
src = &omap3630_dss_feats;
else if (cpu_is_omap44xx())
src = &omap44xx_dss_feats;
else if (soc_is_omap54xx())
src = &omap54xx_dss_feats;
else
return -ENODEV;
memcpy(dst, src, sizeof(*dst));
dss.feat = dst;
return 0;
}
/* DSS HW IP initialisation */
static int __init omap_dsshw_probe(struct platform_device *pdev)
{
@ -758,6 +831,10 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
dss.pdev = pdev;
r = dss_init_features(&dss.pdev->dev);
if (r)
return r;
dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0);
if (!dss_mem) {
DSSERR("can't get IORESOURCE_MEM DSS\n");

View file

@ -113,6 +113,17 @@ enum dss_dsi_content_type {
DSS_DSI_CONTENT_GENERIC,
};
enum dss_writeback_channel {
DSS_WB_LCD1_MGR = 0,
DSS_WB_LCD2_MGR = 1,
DSS_WB_TV_MGR = 2,
DSS_WB_OVL0 = 3,
DSS_WB_OVL1 = 4,
DSS_WB_OVL2 = 5,
DSS_WB_OVL3 = 6,
DSS_WB_LCD3_MGR = 7,
};
struct dss_clock_info {
/* rates that we get with dividers below */
unsigned long fck;
@ -175,6 +186,7 @@ struct seq_file;
struct platform_device;
/* core */
const char *dss_get_default_display_name(void);
struct bus_type *dss_get_bus(void);
struct regulator *dss_get_vdds_dsi(void);
struct regulator *dss_get_vdds_sdi(void);
@ -184,10 +196,13 @@ void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask);
int dss_set_min_bus_tput(struct device *dev, unsigned long tput);
int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *));
int omap_dss_register_device(struct omap_dss_device *dssdev,
struct device *parent, int disp_num);
void omap_dss_unregister_device(struct omap_dss_device *dssdev);
void omap_dss_unregister_child_devices(struct device *parent);
struct omap_dss_device *dss_alloc_and_init_device(struct device *parent);
int dss_add_device(struct omap_dss_device *dssdev);
void dss_unregister_device(struct omap_dss_device *dssdev);
void dss_unregister_child_devices(struct device *parent);
void dss_put_device(struct omap_dss_device *dssdev);
void dss_copy_device_pdata(struct omap_dss_device *dst,
const struct omap_dss_device *src);
/* apply */
void dss_apply_init(void);
@ -205,8 +220,11 @@ void dss_mgr_get_info(struct omap_overlay_manager *mgr,
int dss_mgr_set_device(struct omap_overlay_manager *mgr,
struct omap_dss_device *dssdev);
int dss_mgr_unset_device(struct omap_overlay_manager *mgr);
int dss_mgr_set_output(struct omap_overlay_manager *mgr,
struct omap_dss_output *output);
int dss_mgr_unset_output(struct omap_overlay_manager *mgr);
void dss_mgr_set_timings(struct omap_overlay_manager *mgr,
struct omap_video_timings *timings);
const struct omap_video_timings *timings);
void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr,
const struct dss_lcd_mgr_config *config);
const struct omap_video_timings *dss_mgr_get_timings(struct omap_overlay_manager *mgr);
@ -222,12 +240,17 @@ int dss_ovl_set_manager(struct omap_overlay *ovl,
struct omap_overlay_manager *mgr);
int dss_ovl_unset_manager(struct omap_overlay *ovl);
/* output */
void dss_register_output(struct omap_dss_output *out);
void dss_unregister_output(struct omap_dss_output *out);
struct omap_dss_output *omapdss_get_output_from_dssdev(struct omap_dss_device *dssdev);
/* display */
int dss_suspend_all_devices(void);
int dss_resume_all_devices(void);
void dss_disable_all_devices(void);
void dss_init_device(struct platform_device *pdev,
int dss_init_device(struct platform_device *pdev,
struct omap_dss_device *dssdev);
void dss_uninit_device(struct platform_device *pdev,
struct omap_dss_device *dssdev);
@ -254,22 +277,29 @@ static inline bool dss_mgr_is_lcd(enum omap_channel id)
return false;
}
int dss_manager_kobj_init(struct omap_overlay_manager *mgr,
struct platform_device *pdev);
void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr);
/* overlay */
void dss_init_overlays(struct platform_device *pdev);
void dss_uninit_overlays(struct platform_device *pdev);
void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr);
void dss_recheck_connections(struct omap_dss_device *dssdev, bool force);
int dss_ovl_simple_check(struct omap_overlay *ovl,
const struct omap_overlay_info *info);
int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info,
const struct omap_video_timings *mgr_timings);
bool dss_ovl_use_replication(struct dss_lcd_mgr_config config,
enum omap_color_mode mode);
int dss_overlay_kobj_init(struct omap_overlay *ovl,
struct platform_device *pdev);
void dss_overlay_kobj_uninit(struct omap_overlay *ovl);
/* DSS */
int dss_init_platform_driver(void) __init;
void dss_uninit_platform_driver(void);
int dss_dpi_select_source(enum omap_channel channel);
void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select);
enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void);
const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src);
@ -279,7 +309,7 @@ void dss_dump_clocks(struct seq_file *s);
void dss_debug_dump_clocks(struct seq_file *s);
#endif
void dss_sdi_init(u8 datapairs);
void dss_sdi_init(int datapairs);
int dss_sdi_enable(void);
void dss_sdi_disable(void);
@ -296,9 +326,7 @@ void dss_set_venc_output(enum omap_dss_venc_type type);
void dss_set_dac_pwrdn_bgz(bool enable);
unsigned long dss_get_dpll4_rate(void);
int dss_calc_clock_rates(struct dss_clock_info *cinfo);
int dss_set_clock_div(struct dss_clock_info *cinfo);
int dss_get_clock_div(struct dss_clock_info *cinfo);
int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
struct dispc_clock_info *dispc_cinfo);
@ -427,8 +455,9 @@ void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high);
void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane,
u32 *fifo_low, u32 *fifo_high, bool use_fifomerge,
bool manual_update);
int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
bool replication, const struct omap_video_timings *mgr_timings);
int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi,
bool replication, const struct omap_video_timings *mgr_timings,
bool mem_to_mem);
int dispc_ovl_enable(enum omap_plane plane, bool enable);
void dispc_ovl_set_channel_out(enum omap_plane plane,
enum omap_channel channel);
@ -457,6 +486,15 @@ int dispc_mgr_get_clock_div(enum omap_channel channel,
void dispc_mgr_setup(enum omap_channel channel,
struct omap_overlay_manager_info *info);
u32 dispc_wb_get_framedone_irq(void);
bool dispc_wb_go_busy(void);
void dispc_wb_go(void);
void dispc_wb_enable(bool enable);
bool dispc_wb_is_enabled(void);
void dispc_wb_set_channel_in(enum dss_writeback_channel channel);
int dispc_wb_setup(const struct omap_dss_writeback_info *wi,
bool mem_to_mem, const struct omap_video_timings *timings);
/* VENC */
#ifdef CONFIG_OMAP2_DSS_VENC
int venc_init_platform_driver(void) __init;
@ -469,6 +507,20 @@ static inline unsigned long venc_get_pixel_clock(void)
return 0;
}
#endif
int omapdss_venc_display_enable(struct omap_dss_device *dssdev);
void omapdss_venc_display_disable(struct omap_dss_device *dssdev);
void omapdss_venc_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings);
int omapdss_venc_check_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings);
u32 omapdss_venc_get_wss(struct omap_dss_device *dssdev);
int omapdss_venc_set_wss(struct omap_dss_device *dssdev, u32 wss);
void omapdss_venc_set_type(struct omap_dss_device *dssdev,
enum omap_dss_venc_type type);
void omapdss_venc_invert_vid_out_polarity(struct omap_dss_device *dssdev,
bool invert_polarity);
int venc_panel_init(void);
void venc_panel_exit(void);
/* HDMI */
#ifdef CONFIG_OMAP4_DSS_HDMI
@ -484,7 +536,8 @@ static inline unsigned long hdmi_get_pixel_clock(void)
#endif
int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev);
void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev);
void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev);
void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev,
struct omap_video_timings *timings);
int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
struct omap_video_timings *timings);
int omapdss_hdmi_read_edid(u8 *buf, int len);

View file

@ -46,7 +46,9 @@ struct omap_dss_features {
const int num_mgrs;
const int num_ovls;
const int num_wbs;
const enum omap_display_type *supported_displays;
const enum omap_dss_output_id *supported_outputs;
const enum omap_color_mode *supported_color_modes;
const enum omap_overlay_caps *overlay_caps;
const char * const *clksrc_names;
@ -106,6 +108,21 @@ static const struct dss_reg_field omap4_dss_reg_fields[] = {
[FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 },
};
static const struct dss_reg_field omap5_dss_reg_fields[] = {
[FEAT_REG_FIRHINC] = { 12, 0 },
[FEAT_REG_FIRVINC] = { 28, 16 },
[FEAT_REG_FIFOLOWTHRESHOLD] = { 15, 0 },
[FEAT_REG_FIFOHIGHTHRESHOLD] = { 31, 16 },
[FEAT_REG_FIFOSIZE] = { 15, 0 },
[FEAT_REG_HORIZONTALACCU] = { 10, 0 },
[FEAT_REG_VERTICALACCU] = { 26, 16 },
[FEAT_REG_DISPC_CLK_SWITCH] = { 9, 7 },
[FEAT_REG_DSIPLL_REGN] = { 8, 1 },
[FEAT_REG_DSIPLL_REGM] = { 20, 9 },
[FEAT_REG_DSIPLL_REGM_DISPC] = { 25, 21 },
[FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 },
};
static const enum omap_display_type omap2_dss_supported_displays[] = {
/* OMAP_DSS_CHANNEL_LCD */
OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI,
@ -144,6 +161,76 @@ static const enum omap_display_type omap4_dss_supported_displays[] = {
OMAP_DISPLAY_TYPE_DSI,
};
static const enum omap_display_type omap5_dss_supported_displays[] = {
/* OMAP_DSS_CHANNEL_LCD */
OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
OMAP_DISPLAY_TYPE_DSI,
/* OMAP_DSS_CHANNEL_DIGIT */
OMAP_DISPLAY_TYPE_HDMI | OMAP_DISPLAY_TYPE_DPI,
/* OMAP_DSS_CHANNEL_LCD2 */
OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
OMAP_DISPLAY_TYPE_DSI,
};
static const enum omap_dss_output_id omap2_dss_supported_outputs[] = {
/* OMAP_DSS_CHANNEL_LCD */
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI,
/* OMAP_DSS_CHANNEL_DIGIT */
OMAP_DSS_OUTPUT_VENC,
};
static const enum omap_dss_output_id omap3430_dss_supported_outputs[] = {
/* OMAP_DSS_CHANNEL_LCD */
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
OMAP_DSS_OUTPUT_SDI | OMAP_DSS_OUTPUT_DSI1,
/* OMAP_DSS_CHANNEL_DIGIT */
OMAP_DSS_OUTPUT_VENC,
};
static const enum omap_dss_output_id omap3630_dss_supported_outputs[] = {
/* OMAP_DSS_CHANNEL_LCD */
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
OMAP_DSS_OUTPUT_DSI1,
/* OMAP_DSS_CHANNEL_DIGIT */
OMAP_DSS_OUTPUT_VENC,
};
static const enum omap_dss_output_id omap4_dss_supported_outputs[] = {
/* OMAP_DSS_CHANNEL_LCD */
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
OMAP_DSS_OUTPUT_DSI1,
/* OMAP_DSS_CHANNEL_DIGIT */
OMAP_DSS_OUTPUT_VENC | OMAP_DSS_OUTPUT_HDMI |
OMAP_DSS_OUTPUT_DPI,
/* OMAP_DSS_CHANNEL_LCD2 */
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
OMAP_DSS_OUTPUT_DSI2,
};
static const enum omap_dss_output_id omap5_dss_supported_outputs[] = {
/* OMAP_DSS_CHANNEL_LCD */
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
OMAP_DSS_OUTPUT_DSI1 | OMAP_DSS_OUTPUT_DSI2,
/* OMAP_DSS_CHANNEL_DIGIT */
OMAP_DSS_OUTPUT_HDMI | OMAP_DSS_OUTPUT_DPI,
/* OMAP_DSS_CHANNEL_LCD2 */
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
OMAP_DSS_OUTPUT_DSI1,
/* OMAP_DSS_CHANNEL_LCD3 */
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
OMAP_DSS_OUTPUT_DSI2,
};
static const enum omap_color_mode omap2_dss_supported_color_modes[] = {
/* OMAP_DSS_GFX */
OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
@ -224,58 +311,80 @@ static const enum omap_color_mode omap4_dss_supported_color_modes[] = {
OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
OMAP_DSS_COLOR_RGBX32,
/* OMAP_DSS_WB */
OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 |
OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 |
OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U |
OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY |
OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
OMAP_DSS_COLOR_RGBX32,
};
static const enum omap_overlay_caps omap2_dss_overlay_caps[] = {
/* OMAP_DSS_GFX */
0,
OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
/* OMAP_DSS_VIDEO1 */
OMAP_DSS_OVL_CAP_SCALE,
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
OMAP_DSS_OVL_CAP_REPLICATION,
/* OMAP_DSS_VIDEO2 */
OMAP_DSS_OVL_CAP_SCALE,
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
OMAP_DSS_OVL_CAP_REPLICATION,
};
static const enum omap_overlay_caps omap3430_dss_overlay_caps[] = {
/* OMAP_DSS_GFX */
OMAP_DSS_OVL_CAP_GLOBAL_ALPHA,
OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_POS |
OMAP_DSS_OVL_CAP_REPLICATION,
/* OMAP_DSS_VIDEO1 */
OMAP_DSS_OVL_CAP_SCALE,
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
OMAP_DSS_OVL_CAP_REPLICATION,
/* OMAP_DSS_VIDEO2 */
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA,
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
};
static const enum omap_overlay_caps omap3630_dss_overlay_caps[] = {
/* OMAP_DSS_GFX */
OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA,
OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA |
OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
/* OMAP_DSS_VIDEO1 */
OMAP_DSS_OVL_CAP_SCALE,
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
OMAP_DSS_OVL_CAP_REPLICATION,
/* OMAP_DSS_VIDEO2 */
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA,
OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_POS |
OMAP_DSS_OVL_CAP_REPLICATION,
};
static const enum omap_overlay_caps omap4_dss_overlay_caps[] = {
/* OMAP_DSS_GFX */
OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA |
OMAP_DSS_OVL_CAP_ZORDER,
OMAP_DSS_OVL_CAP_ZORDER | OMAP_DSS_OVL_CAP_POS |
OMAP_DSS_OVL_CAP_REPLICATION,
/* OMAP_DSS_VIDEO1 */
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER,
OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
/* OMAP_DSS_VIDEO2 */
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER,
OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
/* OMAP_DSS_VIDEO3 */
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER,
OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
};
static const char * const omap2_dss_clk_source_names[] = {
@ -298,6 +407,14 @@ static const char * const omap4_dss_clk_source_names[] = {
[OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "PLL2_CLK2",
};
static const char * const omap5_dss_clk_source_names[] = {
[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DPLL_DSI1_A_CLK1",
[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DPLL_DSI1_A_CLK2",
[OMAP_DSS_CLK_SRC_FCK] = "DSS_CLK",
[OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "DPLL_DSI1_C_CLK1",
[OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "DPLL_DSI1_C_CLK2",
};
static const struct dss_param_range omap2_dss_param_range[] = {
[FEAT_PARAM_DSS_FCK] = { 0, 173000000 },
[FEAT_PARAM_DSS_PCD] = { 2, 255 },
@ -326,6 +443,7 @@ static const struct dss_param_range omap3_dss_param_range[] = {
[FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 4) - 1 },
[FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 },
[FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1},
[FEAT_PARAM_DSI_FCK] = { 0, 173000000 },
[FEAT_PARAM_DOWNSCALE] = { 1, 4 },
[FEAT_PARAM_LINEWIDTH] = { 1, 1024 },
[FEAT_PARAM_MGR_WIDTH] = { 1, 2048 },
@ -341,6 +459,23 @@ static const struct dss_param_range omap4_dss_param_range[] = {
[FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 },
[FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 },
[FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 },
[FEAT_PARAM_DSI_FCK] = { 0, 170000000 },
[FEAT_PARAM_DOWNSCALE] = { 1, 4 },
[FEAT_PARAM_LINEWIDTH] = { 1, 2048 },
[FEAT_PARAM_MGR_WIDTH] = { 1, 2048 },
[FEAT_PARAM_MGR_HEIGHT] = { 1, 2048 },
};
static const struct dss_param_range omap5_dss_param_range[] = {
[FEAT_PARAM_DSS_FCK] = { 0, 200000000 },
[FEAT_PARAM_DSS_PCD] = { 1, 255 },
[FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 },
[FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 },
[FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 },
[FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 },
[FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 },
[FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 },
[FEAT_PARAM_DSI_FCK] = { 0, 170000000 },
[FEAT_PARAM_DOWNSCALE] = { 1, 4 },
[FEAT_PARAM_LINEWIDTH] = { 1, 2048 },
[FEAT_PARAM_MGR_WIDTH] = { 1, 2048 },
@ -373,6 +508,26 @@ static const enum dss_feat_id omap3430_dss_feat_list[] = {
FEAT_ALPHA_FIXED_ZORDER,
FEAT_FIFO_MERGE,
FEAT_OMAP3_DSI_FIFO_BUG,
FEAT_DPI_USES_VDDS_DSI,
};
static const enum dss_feat_id am35xx_dss_feat_list[] = {
FEAT_LCDENABLEPOL,
FEAT_LCDENABLESIGNAL,
FEAT_PCKFREEENABLE,
FEAT_FUNCGATED,
FEAT_LINEBUFFERSPLIT,
FEAT_ROWREPEATENABLE,
FEAT_RESIZECONF,
FEAT_DSI_PLL_FREQSEL,
FEAT_DSI_REVERSE_TXCLKESC,
FEAT_VENC_REQUIRES_TV_DAC_CLK,
FEAT_CPR,
FEAT_PRELOAD,
FEAT_FIR_COEF_V,
FEAT_ALPHA_FIXED_ZORDER,
FEAT_FIFO_MERGE,
FEAT_OMAP3_DSI_FIFO_BUG,
};
static const enum dss_feat_id omap3630_dss_feat_list[] = {
@ -447,6 +602,28 @@ static const enum dss_feat_id omap4_dss_feat_list[] = {
FEAT_BURST_2D,
};
static const enum dss_feat_id omap5_dss_feat_list[] = {
FEAT_MGR_LCD2,
FEAT_CORE_CLK_DIV,
FEAT_LCD_CLK_SRC,
FEAT_DSI_DCS_CMD_CONFIG_VC,
FEAT_DSI_VC_OCP_WIDTH,
FEAT_DSI_GNQ,
FEAT_HDMI_CTS_SWMODE,
FEAT_HDMI_AUDIO_USE_MCLK,
FEAT_HANDLE_UV_SEPARATE,
FEAT_ATTR2,
FEAT_CPR,
FEAT_PRELOAD,
FEAT_FIR_COEF_V,
FEAT_ALPHA_FREE_ZORDER,
FEAT_FIFO_MERGE,
FEAT_BURST_2D,
FEAT_DSI_PLL_SELFREQDCO,
FEAT_DSI_PLL_REFSEL,
FEAT_DSI_PHY_DCC,
};
/* OMAP2 DSS Features */
static const struct omap_dss_features omap2_dss_features = {
.reg_fields = omap2_dss_reg_fields,
@ -458,6 +635,7 @@ static const struct omap_dss_features omap2_dss_features = {
.num_mgrs = 2,
.num_ovls = 3,
.supported_displays = omap2_dss_supported_displays,
.supported_outputs = omap2_dss_supported_outputs,
.supported_color_modes = omap2_dss_supported_color_modes,
.overlay_caps = omap2_dss_overlay_caps,
.clksrc_names = omap2_dss_clk_source_names,
@ -478,6 +656,31 @@ static const struct omap_dss_features omap3430_dss_features = {
.num_mgrs = 2,
.num_ovls = 3,
.supported_displays = omap3430_dss_supported_displays,
.supported_outputs = omap3430_dss_supported_outputs,
.supported_color_modes = omap3_dss_supported_color_modes,
.overlay_caps = omap3430_dss_overlay_caps,
.clksrc_names = omap3_dss_clk_source_names,
.dss_params = omap3_dss_param_range,
.supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB,
.buffer_size_unit = 1,
.burst_size_unit = 8,
};
/*
* AM35xx DSS Features. This is basically OMAP3 DSS Features without the
* vdds_dsi regulator.
*/
static const struct omap_dss_features am35xx_dss_features = {
.reg_fields = omap3_dss_reg_fields,
.num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
.features = am35xx_dss_feat_list,
.num_features = ARRAY_SIZE(am35xx_dss_feat_list),
.num_mgrs = 2,
.num_ovls = 3,
.supported_displays = omap3430_dss_supported_displays,
.supported_outputs = omap3430_dss_supported_outputs,
.supported_color_modes = omap3_dss_supported_color_modes,
.overlay_caps = omap3430_dss_overlay_caps,
.clksrc_names = omap3_dss_clk_source_names,
@ -497,6 +700,7 @@ static const struct omap_dss_features omap3630_dss_features = {
.num_mgrs = 2,
.num_ovls = 3,
.supported_displays = omap3630_dss_supported_displays,
.supported_outputs = omap3630_dss_supported_outputs,
.supported_color_modes = omap3_dss_supported_color_modes,
.overlay_caps = omap3630_dss_overlay_caps,
.clksrc_names = omap3_dss_clk_source_names,
@ -517,7 +721,9 @@ static const struct omap_dss_features omap4430_es1_0_dss_features = {
.num_mgrs = 3,
.num_ovls = 4,
.num_wbs = 1,
.supported_displays = omap4_dss_supported_displays,
.supported_outputs = omap4_dss_supported_outputs,
.supported_color_modes = omap4_dss_supported_color_modes,
.overlay_caps = omap4_dss_overlay_caps,
.clksrc_names = omap4_dss_clk_source_names,
@ -537,7 +743,9 @@ static const struct omap_dss_features omap4430_es2_0_1_2_dss_features = {
.num_mgrs = 3,
.num_ovls = 4,
.num_wbs = 1,
.supported_displays = omap4_dss_supported_displays,
.supported_outputs = omap4_dss_supported_outputs,
.supported_color_modes = omap4_dss_supported_color_modes,
.overlay_caps = omap4_dss_overlay_caps,
.clksrc_names = omap4_dss_clk_source_names,
@ -557,7 +765,9 @@ static const struct omap_dss_features omap4_dss_features = {
.num_mgrs = 3,
.num_ovls = 4,
.num_wbs = 1,
.supported_displays = omap4_dss_supported_displays,
.supported_outputs = omap4_dss_supported_outputs,
.supported_color_modes = omap4_dss_supported_color_modes,
.overlay_caps = omap4_dss_overlay_caps,
.clksrc_names = omap4_dss_clk_source_names,
@ -567,6 +777,27 @@ static const struct omap_dss_features omap4_dss_features = {
.burst_size_unit = 16,
};
/* OMAP5 DSS Features */
static const struct omap_dss_features omap5_dss_features = {
.reg_fields = omap5_dss_reg_fields,
.num_reg_fields = ARRAY_SIZE(omap5_dss_reg_fields),
.features = omap5_dss_feat_list,
.num_features = ARRAY_SIZE(omap5_dss_feat_list),
.num_mgrs = 3,
.num_ovls = 4,
.supported_displays = omap5_dss_supported_displays,
.supported_outputs = omap5_dss_supported_outputs,
.supported_color_modes = omap4_dss_supported_color_modes,
.overlay_caps = omap4_dss_overlay_caps,
.clksrc_names = omap5_dss_clk_source_names,
.dss_params = omap5_dss_param_range,
.supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER,
.buffer_size_unit = 16,
.burst_size_unit = 16,
};
#if defined(CONFIG_OMAP4_DSS_HDMI)
/* HDMI OMAP4 Functions*/
static const struct ti_hdmi_ip_ops omap4_hdmi_functions = {
@ -612,6 +843,11 @@ int dss_feat_get_num_ovls(void)
return omap_current_dss_features->num_ovls;
}
int dss_feat_get_num_wbs(void)
{
return omap_current_dss_features->num_wbs;
}
unsigned long dss_feat_get_param_min(enum dss_range_param param)
{
return omap_current_dss_features->dss_params[param].min;
@ -627,6 +863,11 @@ enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel
return omap_current_dss_features->supported_displays[channel];
}
enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel)
{
return omap_current_dss_features->supported_outputs[channel];
}
enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane)
{
return omap_current_dss_features->supported_color_modes[plane];
@ -694,8 +935,13 @@ void dss_features_init(void)
omap_current_dss_features = &omap2_dss_features;
else if (cpu_is_omap3630())
omap_current_dss_features = &omap3630_dss_features;
else if (cpu_is_omap34xx())
omap_current_dss_features = &omap3430_dss_features;
else if (cpu_is_omap34xx()) {
if (soc_is_am35xx()) {
omap_current_dss_features = &am35xx_dss_features;
} else {
omap_current_dss_features = &omap3430_dss_features;
}
}
else if (omap_rev() == OMAP4430_REV_ES1_0)
omap_current_dss_features = &omap4430_es1_0_dss_features;
else if (omap_rev() == OMAP4430_REV_ES2_0 ||
@ -704,6 +950,8 @@ void dss_features_init(void)
omap_current_dss_features = &omap4430_es2_0_1_2_dss_features;
else if (cpu_is_omap44xx())
omap_current_dss_features = &omap4_dss_features;
else if (soc_is_omap54xx())
omap_current_dss_features = &omap5_dss_features;
else
DSSWARN("Unsupported OMAP version");
}

View file

@ -50,6 +50,7 @@ enum dss_feat_id {
FEAT_DSI_VC_OCP_WIDTH,
FEAT_DSI_REVERSE_TXCLKESC,
FEAT_DSI_GNQ,
FEAT_DPI_USES_VDDS_DSI,
FEAT_HDMI_CTS_SWMODE,
FEAT_HDMI_AUDIO_USE_MCLK,
FEAT_HANDLE_UV_SEPARATE,
@ -64,6 +65,9 @@ enum dss_feat_id {
/* An unknown HW bug causing the normal FIFO thresholds not to work */
FEAT_OMAP3_DSI_FIFO_BUG,
FEAT_BURST_2D,
FEAT_DSI_PLL_SELFREQDCO,
FEAT_DSI_PLL_REFSEL,
FEAT_DSI_PHY_DCC,
};
/* DSS register field id */
@ -91,6 +95,7 @@ enum dss_range_param {
FEAT_PARAM_DSIPLL_REGM_DSI,
FEAT_PARAM_DSIPLL_FINT,
FEAT_PARAM_DSIPLL_LPDIV,
FEAT_PARAM_DSI_FCK,
FEAT_PARAM_DOWNSCALE,
FEAT_PARAM_LINEWIDTH,
FEAT_PARAM_MGR_WIDTH,
@ -100,9 +105,11 @@ enum dss_range_param {
/* DSS Feature Functions */
int dss_feat_get_num_mgrs(void);
int dss_feat_get_num_ovls(void);
int dss_feat_get_num_wbs(void);
unsigned long dss_feat_get_param_min(enum dss_range_param param);
unsigned long dss_feat_get_param_max(enum dss_range_param param);
enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel);
enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel);
enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane);
enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane);
bool dss_feat_color_mode_supported(enum omap_plane plane,

View file

@ -32,6 +32,8 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <video/omapdss.h>
#include "ti_hdmi.h"
@ -61,6 +63,13 @@ static struct {
struct hdmi_ip_data ip_data;
struct clk *sys_clk;
struct regulator *vdda_hdmi_dac_reg;
int ct_cp_hpd_gpio;
int ls_oe_gpio;
int hpd_gpio;
struct omap_dss_output output;
} hdmi;
/*
@ -314,12 +323,47 @@ static void hdmi_runtime_put(void)
static int __init hdmi_init_display(struct omap_dss_device *dssdev)
{
int r;
struct gpio gpios[] = {
{ hdmi.ct_cp_hpd_gpio, GPIOF_OUT_INIT_LOW, "hdmi_ct_cp_hpd" },
{ hdmi.ls_oe_gpio, GPIOF_OUT_INIT_LOW, "hdmi_ls_oe" },
{ hdmi.hpd_gpio, GPIOF_DIR_IN, "hdmi_hpd" },
};
DSSDBG("init_display\n");
dss_init_hdmi_ip_ops(&hdmi.ip_data);
if (hdmi.vdda_hdmi_dac_reg == NULL) {
struct regulator *reg;
reg = devm_regulator_get(&hdmi.pdev->dev, "vdda_hdmi_dac");
if (IS_ERR(reg)) {
DSSERR("can't get VDDA_HDMI_DAC regulator\n");
return PTR_ERR(reg);
}
hdmi.vdda_hdmi_dac_reg = reg;
}
r = gpio_request_array(gpios, ARRAY_SIZE(gpios));
if (r)
return r;
return 0;
}
static void __exit hdmi_uninit_display(struct omap_dss_device *dssdev)
{
DSSDBG("uninit_display\n");
gpio_free(hdmi.ct_cp_hpd_gpio);
gpio_free(hdmi.ls_oe_gpio);
gpio_free(hdmi.hpd_gpio);
}
static const struct hdmi_config *hdmi_find_timing(
const struct hdmi_config *timings_arr,
int len)
@ -459,32 +503,30 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
static int hdmi_power_on(struct omap_dss_device *dssdev)
{
int r;
const struct hdmi_config *timing;
struct omap_video_timings *p;
struct omap_overlay_manager *mgr = dssdev->output->manager;
unsigned long phy;
gpio_set_value(hdmi.ct_cp_hpd_gpio, 1);
gpio_set_value(hdmi.ls_oe_gpio, 1);
/* wait 300us after CT_CP_HPD for the 5V power output to reach 90% */
udelay(300);
r = regulator_enable(hdmi.vdda_hdmi_dac_reg);
if (r)
goto err_vdac_enable;
r = hdmi_runtime_get();
if (r)
return r;
goto err_runtime_get;
dss_mgr_disable(dssdev->manager);
dss_mgr_disable(mgr);
p = &dssdev->panel.timings;
p = &hdmi.ip_data.cfg.timings;
DSSDBG("hdmi_power_on x_res= %d y_res = %d\n",
dssdev->panel.timings.x_res,
dssdev->panel.timings.y_res);
DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
timing = hdmi_get_timings();
if (timing == NULL) {
/* HDMI code 4 corresponds to 640 * 480 VGA */
hdmi.ip_data.cfg.cm.code = 4;
/* DVI mode 1 corresponds to HDMI 0 to DVI */
hdmi.ip_data.cfg.cm.mode = HDMI_DVI;
hdmi.ip_data.cfg = vesa_timings[0];
} else {
hdmi.ip_data.cfg = *timing;
}
phy = p->pixel_clock;
hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data);
@ -495,13 +537,13 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
r = hdmi.ip_data.ops->pll_enable(&hdmi.ip_data);
if (r) {
DSSDBG("Failed to lock PLL\n");
goto err;
goto err_pll_enable;
}
r = hdmi.ip_data.ops->phy_enable(&hdmi.ip_data);
if (r) {
DSSDBG("Failed to start PHY\n");
goto err;
goto err_phy_enable;
}
hdmi.ip_data.ops->video_configure(&hdmi.ip_data);
@ -521,13 +563,13 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
dispc_enable_gamma_table(0);
/* tv size */
dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings);
dss_mgr_set_timings(mgr, p);
r = hdmi.ip_data.ops->video_enable(&hdmi.ip_data);
if (r)
goto err_vid_enable;
r = dss_mgr_enable(dssdev->manager);
r = dss_mgr_enable(mgr);
if (r)
goto err_mgr_enable;
@ -537,20 +579,33 @@ err_mgr_enable:
hdmi.ip_data.ops->video_disable(&hdmi.ip_data);
err_vid_enable:
hdmi.ip_data.ops->phy_disable(&hdmi.ip_data);
err_phy_enable:
hdmi.ip_data.ops->pll_disable(&hdmi.ip_data);
err:
err_pll_enable:
hdmi_runtime_put();
err_runtime_get:
regulator_disable(hdmi.vdda_hdmi_dac_reg);
err_vdac_enable:
gpio_set_value(hdmi.ct_cp_hpd_gpio, 0);
gpio_set_value(hdmi.ls_oe_gpio, 0);
return -EIO;
}
static void hdmi_power_off(struct omap_dss_device *dssdev)
{
dss_mgr_disable(dssdev->manager);
struct omap_overlay_manager *mgr = dssdev->output->manager;
dss_mgr_disable(mgr);
hdmi.ip_data.ops->video_disable(&hdmi.ip_data);
hdmi.ip_data.ops->phy_disable(&hdmi.ip_data);
hdmi.ip_data.ops->pll_disable(&hdmi.ip_data);
hdmi_runtime_put();
regulator_disable(hdmi.vdda_hdmi_dac_reg);
gpio_set_value(hdmi.ct_cp_hpd_gpio, 0);
gpio_set_value(hdmi.ls_oe_gpio, 0);
}
int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
@ -567,25 +622,22 @@ int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
}
void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev)
void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
struct hdmi_cm cm;
const struct hdmi_config *t;
cm = hdmi_get_code(&dssdev->panel.timings);
hdmi.ip_data.cfg.cm.code = cm.code;
hdmi.ip_data.cfg.cm.mode = cm.mode;
mutex_lock(&hdmi.lock);
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
int r;
cm = hdmi_get_code(timings);
hdmi.ip_data.cfg.cm = cm;
hdmi_power_off(dssdev);
t = hdmi_get_timings();
if (t != NULL)
hdmi.ip_data.cfg = *t;
r = hdmi_power_on(dssdev);
if (r)
DSSERR("failed to power on device\n");
} else {
dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings);
}
mutex_unlock(&hdmi.lock);
}
static void hdmi_dump_regs(struct seq_file *s)
@ -640,20 +692,20 @@ bool omapdss_hdmi_detect(void)
int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev)
{
struct omap_dss_hdmi_data *priv = dssdev->data;
struct omap_dss_output *out = dssdev->output;
int r = 0;
DSSDBG("ENTER hdmi_display_enable\n");
mutex_lock(&hdmi.lock);
if (dssdev->manager == NULL) {
DSSERR("failed to enable display: no manager\n");
if (out == NULL || out->manager == NULL) {
DSSERR("failed to enable display: no output/manager\n");
r = -ENODEV;
goto err0;
}
hdmi.ip_data.hpd_gpio = priv->hpd_gpio;
hdmi.ip_data.hpd_gpio = hdmi.hpd_gpio;
r = omap_dss_start_device(dssdev);
if (r) {
@ -661,26 +713,15 @@ int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev)
goto err0;
}
if (dssdev->platform_enable) {
r = dssdev->platform_enable(dssdev);
if (r) {
DSSERR("failed to enable GPIO's\n");
goto err1;
}
}
r = hdmi_power_on(dssdev);
if (r) {
DSSERR("failed to power on device\n");
goto err2;
goto err1;
}
mutex_unlock(&hdmi.lock);
return 0;
err2:
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
err1:
omap_dss_stop_device(dssdev);
err0:
@ -696,9 +737,6 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev)
hdmi_power_off(dssdev);
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
omap_dss_stop_device(dssdev);
mutex_unlock(&hdmi.lock);
@ -869,10 +907,14 @@ int hdmi_audio_config(struct omap_dss_audio *audio)
#endif
static void __init hdmi_probe_pdata(struct platform_device *pdev)
static struct omap_dss_device * __init hdmi_find_dssdev(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
int r, i;
const char *def_disp_name = dss_get_default_display_name();
struct omap_dss_device *def_dssdev;
int i;
def_dssdev = NULL;
for (i = 0; i < pdata->num_devices; ++i) {
struct omap_dss_device *dssdev = pdata->devices[i];
@ -880,17 +922,76 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev)
if (dssdev->type != OMAP_DISPLAY_TYPE_HDMI)
continue;
r = hdmi_init_display(dssdev);
if (r) {
DSSERR("device %s init failed: %d\n", dssdev->name, r);
continue;
}
if (def_dssdev == NULL)
def_dssdev = dssdev;
r = omap_dss_register_device(dssdev, &pdev->dev, i);
if (r)
DSSERR("device %s register failed: %d\n",
dssdev->name, r);
if (def_disp_name != NULL &&
strcmp(dssdev->name, def_disp_name) == 0) {
def_dssdev = dssdev;
break;
}
}
return def_dssdev;
}
static void __init hdmi_probe_pdata(struct platform_device *pdev)
{
struct omap_dss_device *plat_dssdev;
struct omap_dss_device *dssdev;
struct omap_dss_hdmi_data *priv;
int r;
plat_dssdev = hdmi_find_dssdev(pdev);
if (!plat_dssdev)
return;
dssdev = dss_alloc_and_init_device(&pdev->dev);
if (!dssdev)
return;
dss_copy_device_pdata(dssdev, plat_dssdev);
priv = dssdev->data;
hdmi.ct_cp_hpd_gpio = priv->ct_cp_hpd_gpio;
hdmi.ls_oe_gpio = priv->ls_oe_gpio;
hdmi.hpd_gpio = priv->hpd_gpio;
dssdev->channel = OMAP_DSS_CHANNEL_DIGIT;
r = hdmi_init_display(dssdev);
if (r) {
DSSERR("device %s init failed: %d\n", dssdev->name, r);
dss_put_device(dssdev);
return;
}
r = dss_add_device(dssdev);
if (r) {
DSSERR("device %s register failed: %d\n", dssdev->name, r);
dss_put_device(dssdev);
return;
}
}
static void __init hdmi_init_output(struct platform_device *pdev)
{
struct omap_dss_output *out = &hdmi.output;
out->pdev = pdev;
out->id = OMAP_DSS_OUTPUT_HDMI;
out->type = OMAP_DISPLAY_TYPE_HDMI;
dss_register_output(out);
}
static void __exit hdmi_uninit_output(struct platform_device *pdev)
{
struct omap_dss_output *out = &hdmi.output;
dss_unregister_output(out);
}
/* HDMI HW IP initialisation */
@ -929,23 +1030,37 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev)
hdmi.ip_data.core_av_offset = HDMI_CORE_AV;
hdmi.ip_data.pll_offset = HDMI_PLLCTRL;
hdmi.ip_data.phy_offset = HDMI_PHY;
mutex_init(&hdmi.ip_data.lock);
hdmi_panel_init();
dss_debugfs_create_file("hdmi", hdmi_dump_regs);
hdmi_init_output(pdev);
hdmi_probe_pdata(pdev);
return 0;
}
static int __exit hdmi_remove_child(struct device *dev, void *data)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
hdmi_uninit_display(dssdev);
return 0;
}
static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
{
omap_dss_unregister_child_devices(&pdev->dev);
device_for_each_child(&pdev->dev, NULL, hdmi_remove_child);
dss_unregister_child_devices(&pdev->dev);
hdmi_panel_exit();
hdmi_uninit_output(pdev);
pm_runtime_disable(&pdev->dev);
hdmi_put_clocks();

View file

@ -41,17 +41,34 @@ static struct {
static int hdmi_panel_probe(struct omap_dss_device *dssdev)
{
/* Initialize default timings to VGA in DVI mode */
const struct omap_video_timings default_timings = {
.x_res = 640,
.y_res = 480,
.pixel_clock = 25175,
.hsw = 96,
.hfp = 16,
.hbp = 48,
.vsw = 2,
.vfp = 11,
.vbp = 31,
.vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
.hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
.interlace = false,
};
DSSDBG("ENTER hdmi_panel_probe\n");
dssdev->panel.timings = (struct omap_video_timings)
{ 640, 480, 25175, 96, 16, 48, 2, 11, 31,
OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
false,
};
dssdev->panel.timings = default_timings;
DSSDBG("hdmi_panel_probe x_res= %d y_res = %d\n",
dssdev->panel.timings.x_res,
dssdev->panel.timings.y_res);
omapdss_hdmi_display_set_timing(dssdev, &dssdev->panel.timings);
return 0;
}
@ -228,6 +245,8 @@ static int hdmi_panel_enable(struct omap_dss_device *dssdev)
goto err;
}
omapdss_hdmi_display_set_timing(dssdev, &dssdev->panel.timings);
r = omapdss_hdmi_display_enable(dssdev);
if (r) {
DSSERR("failed to power on\n");
@ -336,8 +355,8 @@ static void hdmi_set_timings(struct omap_dss_device *dssdev,
*/
hdmi_panel_audio_disable(dssdev);
omapdss_hdmi_display_set_timing(dssdev, timings);
dssdev->panel.timings = *timings;
omapdss_hdmi_display_set_timing(dssdev);
mutex_unlock(&hdmi.lock);
}

View file

@ -0,0 +1,512 @@
/*
* Copyright (C) 2009 Nokia Corporation
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
*
* Some code and ideas taken from drivers/video/omap/ driver
* by Imre Deak.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "MANAGER"
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/jiffies.h>
#include <video/omapdss.h>
#include "dss.h"
#include "dss_features.h"
static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name);
}
static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf)
{
struct omap_dss_device *dssdev = mgr->get_device(mgr);
return snprintf(buf, PAGE_SIZE, "%s\n", dssdev ?
dssdev->name : "<none>");
}
static ssize_t manager_display_store(struct omap_overlay_manager *mgr,
const char *buf, size_t size)
{
int r = 0;
size_t len = size;
struct omap_dss_device *dssdev = NULL;
int match(struct omap_dss_device *dssdev, void *data)
{
const char *str = data;
return sysfs_streq(dssdev->name, str);
}
if (buf[size-1] == '\n')
--len;
if (len > 0)
dssdev = omap_dss_find_device((void *)buf, match);
if (len > 0 && dssdev == NULL)
return -EINVAL;
if (dssdev)
DSSDBG("display %s found\n", dssdev->name);
if (mgr->output) {
r = mgr->unset_output(mgr);
if (r) {
DSSERR("failed to unset current output\n");
goto put_device;
}
}
if (dssdev) {
struct omap_dss_output *out = dssdev->output;
/*
* a registered device should have an output connected to it
* already
*/
if (!out) {
DSSERR("device has no output connected to it\n");
goto put_device;
}
r = mgr->set_output(mgr, out);
if (r) {
DSSERR("failed to set manager output\n");
goto put_device;
}
r = mgr->apply(mgr);
if (r) {
DSSERR("failed to apply dispc config\n");
goto put_device;
}
}
put_device:
if (dssdev)
omap_dss_put_device(dssdev);
return r ? r : size;
}
static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr,
char *buf)
{
struct omap_overlay_manager_info info;
mgr->get_manager_info(mgr, &info);
return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color);
}
static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,
const char *buf, size_t size)
{
struct omap_overlay_manager_info info;
u32 color;
int r;
r = kstrtouint(buf, 0, &color);
if (r)
return r;
mgr->get_manager_info(mgr, &info);
info.default_color = color;
r = mgr->set_manager_info(mgr, &info);
if (r)
return r;
r = mgr->apply(mgr);
if (r)
return r;
return size;
}
static const char *trans_key_type_str[] = {
"gfx-destination",
"video-source",
};
static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr,
char *buf)
{
enum omap_dss_trans_key_type key_type;
struct omap_overlay_manager_info info;
mgr->get_manager_info(mgr, &info);
key_type = info.trans_key_type;
BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str));
return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]);
}
static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr,
const char *buf, size_t size)
{
enum omap_dss_trans_key_type key_type;
struct omap_overlay_manager_info info;
int r;
for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
key_type < ARRAY_SIZE(trans_key_type_str); key_type++) {
if (sysfs_streq(buf, trans_key_type_str[key_type]))
break;
}
if (key_type == ARRAY_SIZE(trans_key_type_str))
return -EINVAL;
mgr->get_manager_info(mgr, &info);
info.trans_key_type = key_type;
r = mgr->set_manager_info(mgr, &info);
if (r)
return r;
r = mgr->apply(mgr);
if (r)
return r;
return size;
}
static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr,
char *buf)
{
struct omap_overlay_manager_info info;
mgr->get_manager_info(mgr, &info);
return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key);
}
static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,
const char *buf, size_t size)
{
struct omap_overlay_manager_info info;
u32 key_value;
int r;
r = kstrtouint(buf, 0, &key_value);
if (r)
return r;
mgr->get_manager_info(mgr, &info);
info.trans_key = key_value;
r = mgr->set_manager_info(mgr, &info);
if (r)
return r;
r = mgr->apply(mgr);
if (r)
return r;
return size;
}
static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr,
char *buf)
{
struct omap_overlay_manager_info info;
mgr->get_manager_info(mgr, &info);
return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled);
}
static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,
const char *buf, size_t size)
{
struct omap_overlay_manager_info info;
bool enable;
int r;
r = strtobool(buf, &enable);
if (r)
return r;
mgr->get_manager_info(mgr, &info);
info.trans_enabled = enable;
r = mgr->set_manager_info(mgr, &info);
if (r)
return r;
r = mgr->apply(mgr);
if (r)
return r;
return size;
}
static ssize_t manager_alpha_blending_enabled_show(
struct omap_overlay_manager *mgr, char *buf)
{
struct omap_overlay_manager_info info;
mgr->get_manager_info(mgr, &info);
WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER));
return snprintf(buf, PAGE_SIZE, "%d\n",
info.partial_alpha_enabled);
}
static ssize_t manager_alpha_blending_enabled_store(
struct omap_overlay_manager *mgr,
const char *buf, size_t size)
{
struct omap_overlay_manager_info info;
bool enable;
int r;
WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER));
r = strtobool(buf, &enable);
if (r)
return r;
mgr->get_manager_info(mgr, &info);
info.partial_alpha_enabled = enable;
r = mgr->set_manager_info(mgr, &info);
if (r)
return r;
r = mgr->apply(mgr);
if (r)
return r;
return size;
}
static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr,
char *buf)
{
struct omap_overlay_manager_info info;
mgr->get_manager_info(mgr, &info);
return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable);
}
static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr,
const char *buf, size_t size)
{
struct omap_overlay_manager_info info;
int r;
bool enable;
if (!dss_has_feature(FEAT_CPR))
return -ENODEV;
r = strtobool(buf, &enable);
if (r)
return r;
mgr->get_manager_info(mgr, &info);
if (info.cpr_enable == enable)
return size;
info.cpr_enable = enable;
r = mgr->set_manager_info(mgr, &info);
if (r)
return r;
r = mgr->apply(mgr);
if (r)
return r;
return size;
}
static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr,
char *buf)
{
struct omap_overlay_manager_info info;
mgr->get_manager_info(mgr, &info);
return snprintf(buf, PAGE_SIZE,
"%d %d %d %d %d %d %d %d %d\n",
info.cpr_coefs.rr,
info.cpr_coefs.rg,
info.cpr_coefs.rb,
info.cpr_coefs.gr,
info.cpr_coefs.gg,
info.cpr_coefs.gb,
info.cpr_coefs.br,
info.cpr_coefs.bg,
info.cpr_coefs.bb);
}
static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr,
const char *buf, size_t size)
{
struct omap_overlay_manager_info info;
struct omap_dss_cpr_coefs coefs;
int r, i;
s16 *arr;
if (!dss_has_feature(FEAT_CPR))
return -ENODEV;
if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd",
&coefs.rr, &coefs.rg, &coefs.rb,
&coefs.gr, &coefs.gg, &coefs.gb,
&coefs.br, &coefs.bg, &coefs.bb) != 9)
return -EINVAL;
arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb,
coefs.gr, coefs.gg, coefs.gb,
coefs.br, coefs.bg, coefs.bb };
for (i = 0; i < 9; ++i) {
if (arr[i] < -512 || arr[i] > 511)
return -EINVAL;
}
mgr->get_manager_info(mgr, &info);
info.cpr_coefs = coefs;
r = mgr->set_manager_info(mgr, &info);
if (r)
return r;
r = mgr->apply(mgr);
if (r)
return r;
return size;
}
struct manager_attribute {
struct attribute attr;
ssize_t (*show)(struct omap_overlay_manager *, char *);
ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t);
};
#define MANAGER_ATTR(_name, _mode, _show, _store) \
struct manager_attribute manager_attr_##_name = \
__ATTR(_name, _mode, _show, _store)
static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL);
static MANAGER_ATTR(display, S_IRUGO|S_IWUSR,
manager_display_show, manager_display_store);
static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR,
manager_default_color_show, manager_default_color_store);
static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR,
manager_trans_key_type_show, manager_trans_key_type_store);
static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR,
manager_trans_key_value_show, manager_trans_key_value_store);
static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR,
manager_trans_key_enabled_show,
manager_trans_key_enabled_store);
static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR,
manager_alpha_blending_enabled_show,
manager_alpha_blending_enabled_store);
static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR,
manager_cpr_enable_show,
manager_cpr_enable_store);
static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR,
manager_cpr_coef_show,
manager_cpr_coef_store);
static struct attribute *manager_sysfs_attrs[] = {
&manager_attr_name.attr,
&manager_attr_display.attr,
&manager_attr_default_color.attr,
&manager_attr_trans_key_type.attr,
&manager_attr_trans_key_value.attr,
&manager_attr_trans_key_enabled.attr,
&manager_attr_alpha_blending_enabled.attr,
&manager_attr_cpr_enable.attr,
&manager_attr_cpr_coef.attr,
NULL
};
static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct omap_overlay_manager *manager;
struct manager_attribute *manager_attr;
manager = container_of(kobj, struct omap_overlay_manager, kobj);
manager_attr = container_of(attr, struct manager_attribute, attr);
if (!manager_attr->show)
return -ENOENT;
return manager_attr->show(manager, buf);
}
static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr,
const char *buf, size_t size)
{
struct omap_overlay_manager *manager;
struct manager_attribute *manager_attr;
manager = container_of(kobj, struct omap_overlay_manager, kobj);
manager_attr = container_of(attr, struct manager_attribute, attr);
if (!manager_attr->store)
return -ENOENT;
return manager_attr->store(manager, buf, size);
}
static const struct sysfs_ops manager_sysfs_ops = {
.show = manager_attr_show,
.store = manager_attr_store,
};
static struct kobj_type manager_ktype = {
.sysfs_ops = &manager_sysfs_ops,
.default_attrs = manager_sysfs_attrs,
};
int dss_manager_kobj_init(struct omap_overlay_manager *mgr,
struct platform_device *pdev)
{
return kobject_init_and_add(&mgr->kobj, &manager_ktype,
&pdev->dev.kobj, "manager%d", mgr->id);
}
void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr)
{
kobject_del(&mgr->kobj);
kobject_put(&mgr->kobj);
}

View file

@ -36,463 +36,15 @@
static int num_managers;
static struct omap_overlay_manager *managers;
static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf)
static inline struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr)
{
return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name);
return mgr->output ? mgr->output->device : NULL;
}
static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n",
mgr->device ? mgr->device->name : "<none>");
}
static ssize_t manager_display_store(struct omap_overlay_manager *mgr,
const char *buf, size_t size)
{
int r = 0;
size_t len = size;
struct omap_dss_device *dssdev = NULL;
int match(struct omap_dss_device *dssdev, void *data)
{
const char *str = data;
return sysfs_streq(dssdev->name, str);
}
if (buf[size-1] == '\n')
--len;
if (len > 0)
dssdev = omap_dss_find_device((void *)buf, match);
if (len > 0 && dssdev == NULL)
return -EINVAL;
if (dssdev)
DSSDBG("display %s found\n", dssdev->name);
if (mgr->device) {
r = mgr->unset_device(mgr);
if (r) {
DSSERR("failed to unset display\n");
goto put_device;
}
}
if (dssdev) {
r = mgr->set_device(mgr, dssdev);
if (r) {
DSSERR("failed to set manager\n");
goto put_device;
}
r = mgr->apply(mgr);
if (r) {
DSSERR("failed to apply dispc config\n");
goto put_device;
}
}
put_device:
if (dssdev)
omap_dss_put_device(dssdev);
return r ? r : size;
}
static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr,
char *buf)
{
struct omap_overlay_manager_info info;
mgr->get_manager_info(mgr, &info);
return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color);
}
static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,
const char *buf, size_t size)
{
struct omap_overlay_manager_info info;
u32 color;
int r;
r = kstrtouint(buf, 0, &color);
if (r)
return r;
mgr->get_manager_info(mgr, &info);
info.default_color = color;
r = mgr->set_manager_info(mgr, &info);
if (r)
return r;
r = mgr->apply(mgr);
if (r)
return r;
return size;
}
static const char *trans_key_type_str[] = {
"gfx-destination",
"video-source",
};
static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr,
char *buf)
{
enum omap_dss_trans_key_type key_type;
struct omap_overlay_manager_info info;
mgr->get_manager_info(mgr, &info);
key_type = info.trans_key_type;
BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str));
return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]);
}
static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr,
const char *buf, size_t size)
{
enum omap_dss_trans_key_type key_type;
struct omap_overlay_manager_info info;
int r;
for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
key_type < ARRAY_SIZE(trans_key_type_str); key_type++) {
if (sysfs_streq(buf, trans_key_type_str[key_type]))
break;
}
if (key_type == ARRAY_SIZE(trans_key_type_str))
return -EINVAL;
mgr->get_manager_info(mgr, &info);
info.trans_key_type = key_type;
r = mgr->set_manager_info(mgr, &info);
if (r)
return r;
r = mgr->apply(mgr);
if (r)
return r;
return size;
}
static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr,
char *buf)
{
struct omap_overlay_manager_info info;
mgr->get_manager_info(mgr, &info);
return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key);
}
static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,
const char *buf, size_t size)
{
struct omap_overlay_manager_info info;
u32 key_value;
int r;
r = kstrtouint(buf, 0, &key_value);
if (r)
return r;
mgr->get_manager_info(mgr, &info);
info.trans_key = key_value;
r = mgr->set_manager_info(mgr, &info);
if (r)
return r;
r = mgr->apply(mgr);
if (r)
return r;
return size;
}
static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr,
char *buf)
{
struct omap_overlay_manager_info info;
mgr->get_manager_info(mgr, &info);
return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled);
}
static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,
const char *buf, size_t size)
{
struct omap_overlay_manager_info info;
bool enable;
int r;
r = strtobool(buf, &enable);
if (r)
return r;
mgr->get_manager_info(mgr, &info);
info.trans_enabled = enable;
r = mgr->set_manager_info(mgr, &info);
if (r)
return r;
r = mgr->apply(mgr);
if (r)
return r;
return size;
}
static ssize_t manager_alpha_blending_enabled_show(
struct omap_overlay_manager *mgr, char *buf)
{
struct omap_overlay_manager_info info;
mgr->get_manager_info(mgr, &info);
WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER));
return snprintf(buf, PAGE_SIZE, "%d\n",
info.partial_alpha_enabled);
}
static ssize_t manager_alpha_blending_enabled_store(
struct omap_overlay_manager *mgr,
const char *buf, size_t size)
{
struct omap_overlay_manager_info info;
bool enable;
int r;
WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER));
r = strtobool(buf, &enable);
if (r)
return r;
mgr->get_manager_info(mgr, &info);
info.partial_alpha_enabled = enable;
r = mgr->set_manager_info(mgr, &info);
if (r)
return r;
r = mgr->apply(mgr);
if (r)
return r;
return size;
}
static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr,
char *buf)
{
struct omap_overlay_manager_info info;
mgr->get_manager_info(mgr, &info);
return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable);
}
static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr,
const char *buf, size_t size)
{
struct omap_overlay_manager_info info;
int r;
bool enable;
if (!dss_has_feature(FEAT_CPR))
return -ENODEV;
r = strtobool(buf, &enable);
if (r)
return r;
mgr->get_manager_info(mgr, &info);
if (info.cpr_enable == enable)
return size;
info.cpr_enable = enable;
r = mgr->set_manager_info(mgr, &info);
if (r)
return r;
r = mgr->apply(mgr);
if (r)
return r;
return size;
}
static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr,
char *buf)
{
struct omap_overlay_manager_info info;
mgr->get_manager_info(mgr, &info);
return snprintf(buf, PAGE_SIZE,
"%d %d %d %d %d %d %d %d %d\n",
info.cpr_coefs.rr,
info.cpr_coefs.rg,
info.cpr_coefs.rb,
info.cpr_coefs.gr,
info.cpr_coefs.gg,
info.cpr_coefs.gb,
info.cpr_coefs.br,
info.cpr_coefs.bg,
info.cpr_coefs.bb);
}
static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr,
const char *buf, size_t size)
{
struct omap_overlay_manager_info info;
struct omap_dss_cpr_coefs coefs;
int r, i;
s16 *arr;
if (!dss_has_feature(FEAT_CPR))
return -ENODEV;
if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd",
&coefs.rr, &coefs.rg, &coefs.rb,
&coefs.gr, &coefs.gg, &coefs.gb,
&coefs.br, &coefs.bg, &coefs.bb) != 9)
return -EINVAL;
arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb,
coefs.gr, coefs.gg, coefs.gb,
coefs.br, coefs.bg, coefs.bb };
for (i = 0; i < 9; ++i) {
if (arr[i] < -512 || arr[i] > 511)
return -EINVAL;
}
mgr->get_manager_info(mgr, &info);
info.cpr_coefs = coefs;
r = mgr->set_manager_info(mgr, &info);
if (r)
return r;
r = mgr->apply(mgr);
if (r)
return r;
return size;
}
struct manager_attribute {
struct attribute attr;
ssize_t (*show)(struct omap_overlay_manager *, char *);
ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t);
};
#define MANAGER_ATTR(_name, _mode, _show, _store) \
struct manager_attribute manager_attr_##_name = \
__ATTR(_name, _mode, _show, _store)
static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL);
static MANAGER_ATTR(display, S_IRUGO|S_IWUSR,
manager_display_show, manager_display_store);
static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR,
manager_default_color_show, manager_default_color_store);
static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR,
manager_trans_key_type_show, manager_trans_key_type_store);
static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR,
manager_trans_key_value_show, manager_trans_key_value_store);
static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR,
manager_trans_key_enabled_show,
manager_trans_key_enabled_store);
static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR,
manager_alpha_blending_enabled_show,
manager_alpha_blending_enabled_store);
static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR,
manager_cpr_enable_show,
manager_cpr_enable_store);
static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR,
manager_cpr_coef_show,
manager_cpr_coef_store);
static struct attribute *manager_sysfs_attrs[] = {
&manager_attr_name.attr,
&manager_attr_display.attr,
&manager_attr_default_color.attr,
&manager_attr_trans_key_type.attr,
&manager_attr_trans_key_value.attr,
&manager_attr_trans_key_enabled.attr,
&manager_attr_alpha_blending_enabled.attr,
&manager_attr_cpr_enable.attr,
&manager_attr_cpr_coef.attr,
NULL
};
static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct omap_overlay_manager *manager;
struct manager_attribute *manager_attr;
manager = container_of(kobj, struct omap_overlay_manager, kobj);
manager_attr = container_of(attr, struct manager_attribute, attr);
if (!manager_attr->show)
return -ENOENT;
return manager_attr->show(manager, buf);
}
static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr,
const char *buf, size_t size)
{
struct omap_overlay_manager *manager;
struct manager_attribute *manager_attr;
manager = container_of(kobj, struct omap_overlay_manager, kobj);
manager_attr = container_of(attr, struct manager_attribute, attr);
if (!manager_attr->store)
return -ENOENT;
return manager_attr->store(manager, buf, size);
}
static const struct sysfs_ops manager_sysfs_ops = {
.show = manager_attr_show,
.store = manager_attr_store,
};
static struct kobj_type manager_ktype = {
.sysfs_ops = &manager_sysfs_ops,
.default_attrs = manager_sysfs_attrs,
};
static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
{
unsigned long timeout = msecs_to_jiffies(500);
struct omap_dss_device *dssdev = mgr->get_device(mgr);
u32 irq;
int r;
@ -500,9 +52,9 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
if (r)
return r;
if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC)
if (dssdev->type == OMAP_DISPLAY_TYPE_VENC)
irq = DISPC_IRQ_EVSYNC_ODD;
else if (mgr->device->type == OMAP_DISPLAY_TYPE_HDMI)
else if (dssdev->type == OMAP_DISPLAY_TYPE_HDMI)
irq = DISPC_IRQ_EVSYNC_EVEN;
else
irq = dispc_mgr_get_vsync_irq(mgr->id);
@ -547,23 +99,24 @@ int dss_init_overlay_managers(struct platform_device *pdev)
break;
}
mgr->set_device = &dss_mgr_set_device;
mgr->unset_device = &dss_mgr_unset_device;
mgr->set_output = &dss_mgr_set_output;
mgr->unset_output = &dss_mgr_unset_output;
mgr->apply = &omap_dss_mgr_apply;
mgr->set_manager_info = &dss_mgr_set_info;
mgr->get_manager_info = &dss_mgr_get_info;
mgr->wait_for_go = &dss_mgr_wait_for_go;
mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;
mgr->get_device = &dss_mgr_get_device;
mgr->caps = 0;
mgr->supported_displays =
dss_feat_get_supported_displays(mgr->id);
mgr->supported_outputs =
dss_feat_get_supported_outputs(mgr->id);
INIT_LIST_HEAD(&mgr->overlays);
r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
&pdev->dev.kobj, "manager%d", i);
r = dss_manager_kobj_init(mgr, pdev);
if (r)
DSSERR("failed to create sysfs file\n");
}
@ -577,9 +130,7 @@ void dss_uninit_overlay_managers(struct platform_device *pdev)
for (i = 0; i < num_managers; ++i) {
struct omap_overlay_manager *mgr = &managers[i];
kobject_del(&mgr->kobj);
kobject_put(&mgr->kobj);
dss_manager_kobj_uninit(mgr);
}
kfree(managers);

View file

@ -0,0 +1,148 @@
/*
* Copyright (C) 2012 Texas Instruments Ltd
* Author: Archit Taneja <archit@ti.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <video/omapdss.h>
#include "dss.h"
static LIST_HEAD(output_list);
static DEFINE_MUTEX(output_lock);
int omapdss_output_set_device(struct omap_dss_output *out,
struct omap_dss_device *dssdev)
{
int r;
mutex_lock(&output_lock);
if (out->device) {
DSSERR("output already has device %s connected to it\n",
out->device->name);
r = -EINVAL;
goto err;
}
if (out->type != dssdev->type) {
DSSERR("output type and display type don't match\n");
r = -EINVAL;
goto err;
}
out->device = dssdev;
dssdev->output = out;
mutex_unlock(&output_lock);
return 0;
err:
mutex_unlock(&output_lock);
return r;
}
EXPORT_SYMBOL(omapdss_output_set_device);
int omapdss_output_unset_device(struct omap_dss_output *out)
{
int r;
mutex_lock(&output_lock);
if (!out->device) {
DSSERR("output doesn't have a device connected to it\n");
r = -EINVAL;
goto err;
}
if (out->device->state != OMAP_DSS_DISPLAY_DISABLED) {
DSSERR("device %s is not disabled, cannot unset device\n",
out->device->name);
r = -EINVAL;
goto err;
}
out->device->output = NULL;
out->device = NULL;
mutex_unlock(&output_lock);
return 0;
err:
mutex_unlock(&output_lock);
return r;
}
EXPORT_SYMBOL(omapdss_output_unset_device);
void dss_register_output(struct omap_dss_output *out)
{
list_add_tail(&out->list, &output_list);
}
void dss_unregister_output(struct omap_dss_output *out)
{
list_del(&out->list);
}
struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id)
{
struct omap_dss_output *out;
list_for_each_entry(out, &output_list, list) {
if (out->id == id)
return out;
}
return NULL;
}
struct omap_dss_output *omapdss_get_output_from_dssdev(struct omap_dss_device *dssdev)
{
struct omap_dss_output *out = NULL;
enum omap_dss_output_id id;
switch (dssdev->type) {
case OMAP_DISPLAY_TYPE_DPI:
out = omap_dss_get_output(OMAP_DSS_OUTPUT_DPI);
break;
case OMAP_DISPLAY_TYPE_DBI:
out = omap_dss_get_output(OMAP_DSS_OUTPUT_DBI);
break;
case OMAP_DISPLAY_TYPE_SDI:
out = omap_dss_get_output(OMAP_DSS_OUTPUT_SDI);
break;
case OMAP_DISPLAY_TYPE_VENC:
out = omap_dss_get_output(OMAP_DSS_OUTPUT_VENC);
break;
case OMAP_DISPLAY_TYPE_HDMI:
out = omap_dss_get_output(OMAP_DSS_OUTPUT_HDMI);
break;
case OMAP_DISPLAY_TYPE_DSI:
id = dssdev->phy.dsi.module == 0 ? OMAP_DSS_OUTPUT_DSI1 :
OMAP_DSS_OUTPUT_DSI2;
out = omap_dss_get_output(id);
break;
default:
break;
}
return out;
}

View file

@ -0,0 +1,456 @@
/*
* Copyright (C) 2009 Nokia Corporation
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
*
* Some code and ideas taken from drivers/video/omap/ driver
* by Imre Deak.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "OVERLAY"
#include <linux/module.h>
#include <linux/err.h>
#include <linux/sysfs.h>
#include <linux/kobject.h>
#include <linux/platform_device.h>
#include <video/omapdss.h>
#include "dss.h"
#include "dss_features.h"
static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name);
}
static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n",
ovl->manager ? ovl->manager->name : "<none>");
}
static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
size_t size)
{
int i, r;
struct omap_overlay_manager *mgr = NULL;
struct omap_overlay_manager *old_mgr;
int len = size;
if (buf[size-1] == '\n')
--len;
if (len > 0) {
for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
mgr = omap_dss_get_overlay_manager(i);
if (sysfs_streq(buf, mgr->name))
break;
mgr = NULL;
}
}
if (len > 0 && mgr == NULL)
return -EINVAL;
if (mgr)
DSSDBG("manager %s found\n", mgr->name);
if (mgr == ovl->manager)
return size;
old_mgr = ovl->manager;
r = dispc_runtime_get();
if (r)
return r;
/* detach old manager */
if (old_mgr) {
r = ovl->unset_manager(ovl);
if (r) {
DSSERR("detach failed\n");
goto err;
}
r = old_mgr->apply(old_mgr);
if (r)
goto err;
}
if (mgr) {
r = ovl->set_manager(ovl, mgr);
if (r) {
DSSERR("Failed to attach overlay\n");
goto err;
}
r = mgr->apply(mgr);
if (r)
goto err;
}
dispc_runtime_put();
return size;
err:
dispc_runtime_put();
return r;
}
static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf)
{
struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info);
return snprintf(buf, PAGE_SIZE, "%d,%d\n",
info.width, info.height);
}
static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf)
{
struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info);
return snprintf(buf, PAGE_SIZE, "%d\n", info.screen_width);
}
static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf)
{
struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info);
return snprintf(buf, PAGE_SIZE, "%d,%d\n",
info.pos_x, info.pos_y);
}
static ssize_t overlay_position_store(struct omap_overlay *ovl,
const char *buf, size_t size)
{
int r;
char *last;
struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info);
info.pos_x = simple_strtoul(buf, &last, 10);
++last;
if (last - buf >= size)
return -EINVAL;
info.pos_y = simple_strtoul(last, &last, 10);
r = ovl->set_overlay_info(ovl, &info);
if (r)
return r;
if (ovl->manager) {
r = ovl->manager->apply(ovl->manager);
if (r)
return r;
}
return size;
}
static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf)
{
struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info);
return snprintf(buf, PAGE_SIZE, "%d,%d\n",
info.out_width, info.out_height);
}
static ssize_t overlay_output_size_store(struct omap_overlay *ovl,
const char *buf, size_t size)
{
int r;
char *last;
struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info);
info.out_width = simple_strtoul(buf, &last, 10);
++last;
if (last - buf >= size)
return -EINVAL;
info.out_height = simple_strtoul(last, &last, 10);
r = ovl->set_overlay_info(ovl, &info);
if (r)
return r;
if (ovl->manager) {
r = ovl->manager->apply(ovl->manager);
if (r)
return r;
}
return size;
}
static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl));
}
static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
size_t size)
{
int r;
bool enable;
r = strtobool(buf, &enable);
if (r)
return r;
if (enable)
r = ovl->enable(ovl);
else
r = ovl->disable(ovl);
if (r)
return r;
return size;
}
static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf)
{
struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info);
return snprintf(buf, PAGE_SIZE, "%d\n",
info.global_alpha);
}
static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
const char *buf, size_t size)
{
int r;
u8 alpha;
struct omap_overlay_info info;
if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
return -ENODEV;
r = kstrtou8(buf, 0, &alpha);
if (r)
return r;
ovl->get_overlay_info(ovl, &info);
info.global_alpha = alpha;
r = ovl->set_overlay_info(ovl, &info);
if (r)
return r;
if (ovl->manager) {
r = ovl->manager->apply(ovl->manager);
if (r)
return r;
}
return size;
}
static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl,
char *buf)
{
struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info);
return snprintf(buf, PAGE_SIZE, "%d\n",
info.pre_mult_alpha);
}
static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,
const char *buf, size_t size)
{
int r;
u8 alpha;
struct omap_overlay_info info;
if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
return -ENODEV;
r = kstrtou8(buf, 0, &alpha);
if (r)
return r;
ovl->get_overlay_info(ovl, &info);
info.pre_mult_alpha = alpha;
r = ovl->set_overlay_info(ovl, &info);
if (r)
return r;
if (ovl->manager) {
r = ovl->manager->apply(ovl->manager);
if (r)
return r;
}
return size;
}
static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf)
{
struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info);
return snprintf(buf, PAGE_SIZE, "%d\n", info.zorder);
}
static ssize_t overlay_zorder_store(struct omap_overlay *ovl,
const char *buf, size_t size)
{
int r;
u8 zorder;
struct omap_overlay_info info;
if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
return -ENODEV;
r = kstrtou8(buf, 0, &zorder);
if (r)
return r;
ovl->get_overlay_info(ovl, &info);
info.zorder = zorder;
r = ovl->set_overlay_info(ovl, &info);
if (r)
return r;
if (ovl->manager) {
r = ovl->manager->apply(ovl->manager);
if (r)
return r;
}
return size;
}
struct overlay_attribute {
struct attribute attr;
ssize_t (*show)(struct omap_overlay *, char *);
ssize_t (*store)(struct omap_overlay *, const char *, size_t);
};
#define OVERLAY_ATTR(_name, _mode, _show, _store) \
struct overlay_attribute overlay_attr_##_name = \
__ATTR(_name, _mode, _show, _store)
static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL);
static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR,
overlay_manager_show, overlay_manager_store);
static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL);
static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL);
static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR,
overlay_position_show, overlay_position_store);
static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR,
overlay_output_size_show, overlay_output_size_store);
static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
overlay_enabled_show, overlay_enabled_store);
static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,
overlay_global_alpha_show, overlay_global_alpha_store);
static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR,
overlay_pre_mult_alpha_show,
overlay_pre_mult_alpha_store);
static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR,
overlay_zorder_show, overlay_zorder_store);
static struct attribute *overlay_sysfs_attrs[] = {
&overlay_attr_name.attr,
&overlay_attr_manager.attr,
&overlay_attr_input_size.attr,
&overlay_attr_screen_width.attr,
&overlay_attr_position.attr,
&overlay_attr_output_size.attr,
&overlay_attr_enabled.attr,
&overlay_attr_global_alpha.attr,
&overlay_attr_pre_mult_alpha.attr,
&overlay_attr_zorder.attr,
NULL
};
static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct omap_overlay *overlay;
struct overlay_attribute *overlay_attr;
overlay = container_of(kobj, struct omap_overlay, kobj);
overlay_attr = container_of(attr, struct overlay_attribute, attr);
if (!overlay_attr->show)
return -ENOENT;
return overlay_attr->show(overlay, buf);
}
static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr,
const char *buf, size_t size)
{
struct omap_overlay *overlay;
struct overlay_attribute *overlay_attr;
overlay = container_of(kobj, struct omap_overlay, kobj);
overlay_attr = container_of(attr, struct overlay_attribute, attr);
if (!overlay_attr->store)
return -ENOENT;
return overlay_attr->store(overlay, buf, size);
}
static const struct sysfs_ops overlay_sysfs_ops = {
.show = overlay_attr_show,
.store = overlay_attr_store,
};
static struct kobj_type overlay_ktype = {
.sysfs_ops = &overlay_sysfs_ops,
.default_attrs = overlay_sysfs_attrs,
};
int dss_overlay_kobj_init(struct omap_overlay *ovl,
struct platform_device *pdev)
{
return kobject_init_and_add(&ovl->kobj, &overlay_ktype,
&pdev->dev.kobj, "overlay%d", ovl->id);
}
void dss_overlay_kobj_uninit(struct omap_overlay *ovl)
{
kobject_del(&ovl->kobj);
kobject_put(&ovl->kobj);
}

View file

@ -26,13 +26,11 @@
#include <linux/module.h>
#include <linux/err.h>
#include <linux/sysfs.h>
#include <linux/kobject.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <video/omapdss.h>
#include <plat/cpu.h>
#include "dss.h"
#include "dss_features.h"
@ -40,417 +38,13 @@
static int num_overlays;
static struct omap_overlay *overlays;
static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf)
static inline struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl)
{
return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name);
return ovl->manager ?
(ovl->manager->output ? ovl->manager->output->device : NULL) :
NULL;
}
static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n",
ovl->manager ? ovl->manager->name : "<none>");
}
static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
size_t size)
{
int i, r;
struct omap_overlay_manager *mgr = NULL;
struct omap_overlay_manager *old_mgr;
int len = size;
if (buf[size-1] == '\n')
--len;
if (len > 0) {
for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
mgr = omap_dss_get_overlay_manager(i);
if (sysfs_streq(buf, mgr->name))
break;
mgr = NULL;
}
}
if (len > 0 && mgr == NULL)
return -EINVAL;
if (mgr)
DSSDBG("manager %s found\n", mgr->name);
if (mgr == ovl->manager)
return size;
old_mgr = ovl->manager;
r = dispc_runtime_get();
if (r)
return r;
/* detach old manager */
if (old_mgr) {
r = ovl->unset_manager(ovl);
if (r) {
DSSERR("detach failed\n");
goto err;
}
r = old_mgr->apply(old_mgr);
if (r)
goto err;
}
if (mgr) {
r = ovl->set_manager(ovl, mgr);
if (r) {
DSSERR("Failed to attach overlay\n");
goto err;
}
r = mgr->apply(mgr);
if (r)
goto err;
}
dispc_runtime_put();
return size;
err:
dispc_runtime_put();
return r;
}
static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf)
{
struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info);
return snprintf(buf, PAGE_SIZE, "%d,%d\n",
info.width, info.height);
}
static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf)
{
struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info);
return snprintf(buf, PAGE_SIZE, "%d\n", info.screen_width);
}
static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf)
{
struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info);
return snprintf(buf, PAGE_SIZE, "%d,%d\n",
info.pos_x, info.pos_y);
}
static ssize_t overlay_position_store(struct omap_overlay *ovl,
const char *buf, size_t size)
{
int r;
char *last;
struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info);
info.pos_x = simple_strtoul(buf, &last, 10);
++last;
if (last - buf >= size)
return -EINVAL;
info.pos_y = simple_strtoul(last, &last, 10);
r = ovl->set_overlay_info(ovl, &info);
if (r)
return r;
if (ovl->manager) {
r = ovl->manager->apply(ovl->manager);
if (r)
return r;
}
return size;
}
static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf)
{
struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info);
return snprintf(buf, PAGE_SIZE, "%d,%d\n",
info.out_width, info.out_height);
}
static ssize_t overlay_output_size_store(struct omap_overlay *ovl,
const char *buf, size_t size)
{
int r;
char *last;
struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info);
info.out_width = simple_strtoul(buf, &last, 10);
++last;
if (last - buf >= size)
return -EINVAL;
info.out_height = simple_strtoul(last, &last, 10);
r = ovl->set_overlay_info(ovl, &info);
if (r)
return r;
if (ovl->manager) {
r = ovl->manager->apply(ovl->manager);
if (r)
return r;
}
return size;
}
static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl));
}
static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
size_t size)
{
int r;
bool enable;
r = strtobool(buf, &enable);
if (r)
return r;
if (enable)
r = ovl->enable(ovl);
else
r = ovl->disable(ovl);
if (r)
return r;
return size;
}
static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf)
{
struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info);
return snprintf(buf, PAGE_SIZE, "%d\n",
info.global_alpha);
}
static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
const char *buf, size_t size)
{
int r;
u8 alpha;
struct omap_overlay_info info;
if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
return -ENODEV;
r = kstrtou8(buf, 0, &alpha);
if (r)
return r;
ovl->get_overlay_info(ovl, &info);
info.global_alpha = alpha;
r = ovl->set_overlay_info(ovl, &info);
if (r)
return r;
if (ovl->manager) {
r = ovl->manager->apply(ovl->manager);
if (r)
return r;
}
return size;
}
static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl,
char *buf)
{
struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info);
return snprintf(buf, PAGE_SIZE, "%d\n",
info.pre_mult_alpha);
}
static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,
const char *buf, size_t size)
{
int r;
u8 alpha;
struct omap_overlay_info info;
if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
return -ENODEV;
r = kstrtou8(buf, 0, &alpha);
if (r)
return r;
ovl->get_overlay_info(ovl, &info);
info.pre_mult_alpha = alpha;
r = ovl->set_overlay_info(ovl, &info);
if (r)
return r;
if (ovl->manager) {
r = ovl->manager->apply(ovl->manager);
if (r)
return r;
}
return size;
}
static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf)
{
struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info);
return snprintf(buf, PAGE_SIZE, "%d\n", info.zorder);
}
static ssize_t overlay_zorder_store(struct omap_overlay *ovl,
const char *buf, size_t size)
{
int r;
u8 zorder;
struct omap_overlay_info info;
if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
return -ENODEV;
r = kstrtou8(buf, 0, &zorder);
if (r)
return r;
ovl->get_overlay_info(ovl, &info);
info.zorder = zorder;
r = ovl->set_overlay_info(ovl, &info);
if (r)
return r;
if (ovl->manager) {
r = ovl->manager->apply(ovl->manager);
if (r)
return r;
}
return size;
}
struct overlay_attribute {
struct attribute attr;
ssize_t (*show)(struct omap_overlay *, char *);
ssize_t (*store)(struct omap_overlay *, const char *, size_t);
};
#define OVERLAY_ATTR(_name, _mode, _show, _store) \
struct overlay_attribute overlay_attr_##_name = \
__ATTR(_name, _mode, _show, _store)
static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL);
static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR,
overlay_manager_show, overlay_manager_store);
static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL);
static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL);
static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR,
overlay_position_show, overlay_position_store);
static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR,
overlay_output_size_show, overlay_output_size_store);
static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
overlay_enabled_show, overlay_enabled_store);
static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,
overlay_global_alpha_show, overlay_global_alpha_store);
static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR,
overlay_pre_mult_alpha_show,
overlay_pre_mult_alpha_store);
static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR,
overlay_zorder_show, overlay_zorder_store);
static struct attribute *overlay_sysfs_attrs[] = {
&overlay_attr_name.attr,
&overlay_attr_manager.attr,
&overlay_attr_input_size.attr,
&overlay_attr_screen_width.attr,
&overlay_attr_position.attr,
&overlay_attr_output_size.attr,
&overlay_attr_enabled.attr,
&overlay_attr_global_alpha.attr,
&overlay_attr_pre_mult_alpha.attr,
&overlay_attr_zorder.attr,
NULL
};
static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct omap_overlay *overlay;
struct overlay_attribute *overlay_attr;
overlay = container_of(kobj, struct omap_overlay, kobj);
overlay_attr = container_of(attr, struct overlay_attribute, attr);
if (!overlay_attr->show)
return -ENOENT;
return overlay_attr->show(overlay, buf);
}
static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr,
const char *buf, size_t size)
{
struct omap_overlay *overlay;
struct overlay_attribute *overlay_attr;
overlay = container_of(kobj, struct omap_overlay, kobj);
overlay_attr = container_of(attr, struct overlay_attribute, attr);
if (!overlay_attr->store)
return -ENOENT;
return overlay_attr->store(overlay, buf, size);
}
static const struct sysfs_ops overlay_sysfs_ops = {
.show = overlay_attr_show,
.store = overlay_attr_store,
};
static struct kobj_type overlay_ktype = {
.sysfs_ops = &overlay_sysfs_ops,
.default_attrs = overlay_sysfs_attrs,
};
int omap_dss_get_num_overlays(void)
{
return num_overlays;
@ -507,97 +101,25 @@ void dss_init_overlays(struct platform_device *pdev)
ovl->set_overlay_info = &dss_ovl_set_info;
ovl->get_overlay_info = &dss_ovl_get_info;
ovl->wait_for_go = &dss_mgr_wait_for_go_ovl;
ovl->get_device = &dss_ovl_get_device;
ovl->caps = dss_feat_get_overlay_caps(ovl->id);
ovl->supported_modes =
dss_feat_get_supported_color_modes(ovl->id);
r = kobject_init_and_add(&ovl->kobj, &overlay_ktype,
&pdev->dev.kobj, "overlay%d", i);
r = dss_overlay_kobj_init(ovl, pdev);
if (r)
DSSERR("failed to create sysfs file\n");
}
}
/* connect overlays to the new device, if not already connected. if force
* selected, connect always. */
void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
{
int i;
struct omap_overlay_manager *lcd_mgr;
struct omap_overlay_manager *tv_mgr;
struct omap_overlay_manager *lcd2_mgr = NULL;
struct omap_overlay_manager *lcd3_mgr = NULL;
struct omap_overlay_manager *mgr = NULL;
lcd_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_LCD);
tv_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_DIGIT);
if (dss_has_feature(FEAT_MGR_LCD3))
lcd3_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_LCD3);
if (dss_has_feature(FEAT_MGR_LCD2))
lcd2_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_LCD2);
if (dssdev->channel == OMAP_DSS_CHANNEL_LCD3) {
if (!lcd3_mgr->device || force) {
if (lcd3_mgr->device)
lcd3_mgr->unset_device(lcd3_mgr);
lcd3_mgr->set_device(lcd3_mgr, dssdev);
mgr = lcd3_mgr;
}
} else if (dssdev->channel == OMAP_DSS_CHANNEL_LCD2) {
if (!lcd2_mgr->device || force) {
if (lcd2_mgr->device)
lcd2_mgr->unset_device(lcd2_mgr);
lcd2_mgr->set_device(lcd2_mgr, dssdev);
mgr = lcd2_mgr;
}
} else if (dssdev->type != OMAP_DISPLAY_TYPE_VENC
&& dssdev->type != OMAP_DISPLAY_TYPE_HDMI) {
if (!lcd_mgr->device || force) {
if (lcd_mgr->device)
lcd_mgr->unset_device(lcd_mgr);
lcd_mgr->set_device(lcd_mgr, dssdev);
mgr = lcd_mgr;
}
}
if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
|| dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
if (!tv_mgr->device || force) {
if (tv_mgr->device)
tv_mgr->unset_device(tv_mgr);
tv_mgr->set_device(tv_mgr, dssdev);
mgr = tv_mgr;
}
}
if (mgr) {
dispc_runtime_get();
for (i = 0; i < dss_feat_get_num_ovls(); i++) {
struct omap_overlay *ovl;
ovl = omap_dss_get_overlay(i);
if (!ovl->manager || force) {
if (ovl->manager)
ovl->unset_manager(ovl);
ovl->set_manager(ovl, mgr);
}
}
dispc_runtime_put();
}
}
void dss_uninit_overlays(struct platform_device *pdev)
{
int i;
for (i = 0; i < num_overlays; ++i) {
struct omap_overlay *ovl = &overlays[i];
kobject_del(&ovl->kobj);
kobject_put(&ovl->kobj);
dss_overlay_kobj_uninit(ovl);
}
kfree(overlays);

View file

@ -111,6 +111,13 @@ static struct {
struct omap_dss_device *dssdev[2];
struct semaphore bus_lock;
struct omap_video_timings timings;
int pixel_size;
int data_lines;
struct rfbi_timings intf_timings;
struct omap_dss_output output;
} rfbi;
static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val)
@ -300,30 +307,23 @@ void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
}
EXPORT_SYMBOL(omap_rfbi_write_pixels);
static int rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width,
u16 height, void (*callback)(void *data), void *data)
static int rfbi_transfer_area(struct omap_dss_device *dssdev,
void (*callback)(void *data), void *data)
{
u32 l;
int r;
struct omap_video_timings timings = {
.hsw = 1,
.hfp = 1,
.hbp = 1,
.vsw = 1,
.vfp = 0,
.vbp = 0,
.x_res = width,
.y_res = height,
};
struct omap_overlay_manager *mgr = dssdev->output->manager;
u16 width = rfbi.timings.x_res;
u16 height = rfbi.timings.y_res;
/*BUG_ON(callback == 0);*/
BUG_ON(rfbi.framedone_callback != NULL);
DSSDBG("rfbi_transfer_area %dx%d\n", width, height);
dss_mgr_set_timings(dssdev->manager, &timings);
dss_mgr_set_timings(mgr, &rfbi.timings);
r = dss_mgr_enable(dssdev->manager);
r = dss_mgr_enable(mgr);
if (r)
return r;
@ -770,63 +770,46 @@ static int rfbi_configure(int rfbi_module, int bpp, int lines)
return 0;
}
int omap_rfbi_configure(struct omap_dss_device *dssdev, int pixel_size,
int data_lines)
int omap_rfbi_configure(struct omap_dss_device *dssdev)
{
return rfbi_configure(dssdev->phy.rfbi.channel, pixel_size, data_lines);
return rfbi_configure(dssdev->phy.rfbi.channel, rfbi.pixel_size,
rfbi.data_lines);
}
EXPORT_SYMBOL(omap_rfbi_configure);
int omap_rfbi_prepare_update(struct omap_dss_device *dssdev,
u16 *x, u16 *y, u16 *w, u16 *h)
int omap_rfbi_update(struct omap_dss_device *dssdev, void (*callback)(void *),
void *data)
{
u16 dw, dh;
struct omap_video_timings timings = {
.hsw = 1,
.hfp = 1,
.hbp = 1,
.vsw = 1,
.vfp = 0,
.vbp = 0,
.x_res = *w,
.y_res = *h,
};
dssdev->driver->get_resolution(dssdev, &dw, &dh);
if (*x > dw || *y > dh)
return -EINVAL;
if (*x + *w > dw)
return -EINVAL;
if (*y + *h > dh)
return -EINVAL;
if (*w == 1)
return -EINVAL;
if (*w == 0 || *h == 0)
return -EINVAL;
dss_mgr_set_timings(dssdev->manager, &timings);
return 0;
}
EXPORT_SYMBOL(omap_rfbi_prepare_update);
int omap_rfbi_update(struct omap_dss_device *dssdev,
u16 x, u16 y, u16 w, u16 h,
void (*callback)(void *), void *data)
{
int r;
r = rfbi_transfer_area(dssdev, w, h, callback, data);
return r;
return rfbi_transfer_area(dssdev, callback, data);
}
EXPORT_SYMBOL(omap_rfbi_update);
void omapdss_rfbi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h)
{
rfbi.timings.x_res = w;
rfbi.timings.y_res = h;
}
EXPORT_SYMBOL(omapdss_rfbi_set_size);
void omapdss_rfbi_set_pixel_size(struct omap_dss_device *dssdev, int pixel_size)
{
rfbi.pixel_size = pixel_size;
}
EXPORT_SYMBOL(omapdss_rfbi_set_pixel_size);
void omapdss_rfbi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
{
rfbi.data_lines = data_lines;
}
EXPORT_SYMBOL(omapdss_rfbi_set_data_lines);
void omapdss_rfbi_set_interface_timings(struct omap_dss_device *dssdev,
struct rfbi_timings *timings)
{
rfbi.intf_timings = *timings;
}
EXPORT_SYMBOL(omapdss_rfbi_set_interface_timings);
static void rfbi_dump_regs(struct seq_file *s)
{
#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r))
@ -869,6 +852,7 @@ static void rfbi_dump_regs(struct seq_file *s)
static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev)
{
struct omap_overlay_manager *mgr = dssdev->output->manager;
struct dss_lcd_mgr_config mgr_config;
mgr_config.io_pad_mode = DSS_IO_PAD_MODE_RFBI;
@ -877,18 +861,40 @@ static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev)
/* Do we need fifohandcheck for RFBI? */
mgr_config.fifohandcheck = false;
mgr_config.video_port_width = dssdev->ctrl.pixel_size;
mgr_config.video_port_width = rfbi.pixel_size;
mgr_config.lcden_sig_polarity = 0;
dss_mgr_set_lcd_config(dssdev->manager, &mgr_config);
dss_mgr_set_lcd_config(mgr, &mgr_config);
/*
* Set rfbi.timings with default values, the x_res and y_res fields
* are expected to be already configured by the panel driver via
* omapdss_rfbi_set_size()
*/
rfbi.timings.hsw = 1;
rfbi.timings.hfp = 1;
rfbi.timings.hbp = 1;
rfbi.timings.vsw = 1;
rfbi.timings.vfp = 0;
rfbi.timings.vbp = 0;
rfbi.timings.interlace = false;
rfbi.timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
rfbi.timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
rfbi.timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
rfbi.timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH;
rfbi.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES;
dss_mgr_set_timings(mgr, &rfbi.timings);
}
int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
{
struct omap_dss_output *out = dssdev->output;
int r;
if (dssdev->manager == NULL) {
DSSERR("failed to enable display: no manager\n");
if (out == NULL || out->manager == NULL) {
DSSERR("failed to enable display: no output/manager\n");
return -ENODEV;
}
@ -911,13 +917,10 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
rfbi_config_lcd_manager(dssdev);
rfbi_configure(dssdev->phy.rfbi.channel,
dssdev->ctrl.pixel_size,
dssdev->phy.rfbi.data_lines);
rfbi_set_timings(dssdev->phy.rfbi.channel,
&dssdev->ctrl.rfbi_timings);
rfbi_configure(dssdev->phy.rfbi.channel, rfbi.pixel_size,
rfbi.data_lines);
rfbi_set_timings(dssdev->phy.rfbi.channel, &rfbi.intf_timings);
return 0;
err1:
@ -941,14 +944,17 @@ EXPORT_SYMBOL(omapdss_rfbi_display_disable);
static int __init rfbi_init_display(struct omap_dss_device *dssdev)
{
rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev;
dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
return 0;
}
static void __init rfbi_probe_pdata(struct platform_device *pdev)
static struct omap_dss_device * __init rfbi_find_dssdev(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
int i, r;
const char *def_disp_name = dss_get_default_display_name();
struct omap_dss_device *def_dssdev;
int i;
def_dssdev = NULL;
for (i = 0; i < pdata->num_devices; ++i) {
struct omap_dss_device *dssdev = pdata->devices[i];
@ -956,17 +962,67 @@ static void __init rfbi_probe_pdata(struct platform_device *pdev)
if (dssdev->type != OMAP_DISPLAY_TYPE_DBI)
continue;
r = rfbi_init_display(dssdev);
if (r) {
DSSERR("device %s init failed: %d\n", dssdev->name, r);
continue;
}
if (def_dssdev == NULL)
def_dssdev = dssdev;
r = omap_dss_register_device(dssdev, &pdev->dev, i);
if (r)
DSSERR("device %s register failed: %d\n",
dssdev->name, r);
if (def_disp_name != NULL &&
strcmp(dssdev->name, def_disp_name) == 0) {
def_dssdev = dssdev;
break;
}
}
return def_dssdev;
}
static void __init rfbi_probe_pdata(struct platform_device *rfbidev)
{
struct omap_dss_device *plat_dssdev;
struct omap_dss_device *dssdev;
int r;
plat_dssdev = rfbi_find_dssdev(rfbidev);
if (!plat_dssdev)
return;
dssdev = dss_alloc_and_init_device(&rfbidev->dev);
if (!dssdev)
return;
dss_copy_device_pdata(dssdev, plat_dssdev);
r = rfbi_init_display(dssdev);
if (r) {
DSSERR("device %s init failed: %d\n", dssdev->name, r);
dss_put_device(dssdev);
return;
}
r = dss_add_device(dssdev);
if (r) {
DSSERR("device %s register failed: %d\n", dssdev->name, r);
dss_put_device(dssdev);
return;
}
}
static void __init rfbi_init_output(struct platform_device *pdev)
{
struct omap_dss_output *out = &rfbi.output;
out->pdev = pdev;
out->id = OMAP_DSS_OUTPUT_DBI;
out->type = OMAP_DISPLAY_TYPE_DBI;
dss_register_output(out);
}
static void __exit rfbi_uninit_output(struct platform_device *pdev)
{
struct omap_dss_output *out = &rfbi.output;
dss_unregister_output(out);
}
/* RFBI HW IP initialisation */
@ -1020,6 +1076,8 @@ static int __init omap_rfbihw_probe(struct platform_device *pdev)
dss_debugfs_create_file("rfbi", rfbi_dump_regs);
rfbi_init_output(pdev);
rfbi_probe_pdata(pdev);
return 0;
@ -1031,8 +1089,12 @@ err_runtime_get:
static int __exit omap_rfbihw_remove(struct platform_device *pdev)
{
omap_dss_unregister_child_devices(&pdev->dev);
dss_unregister_child_devices(&pdev->dev);
rfbi_uninit_output(pdev);
pm_runtime_disable(&pdev->dev);
return 0;
}

View file

@ -25,6 +25,7 @@
#include <linux/regulator/consumer.h>
#include <linux/export.h>
#include <linux/platform_device.h>
#include <linux/string.h>
#include <video/omapdss.h>
#include "dss.h"
@ -34,10 +35,16 @@ static struct {
struct regulator *vdds_sdi_reg;
struct dss_lcd_mgr_config mgr_config;
struct omap_video_timings timings;
int datapairs;
struct omap_dss_output output;
} sdi;
static void sdi_config_lcd_manager(struct omap_dss_device *dssdev)
{
struct omap_overlay_manager *mgr = dssdev->output->manager;
sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
sdi.mgr_config.stallmode = false;
@ -46,19 +53,20 @@ static void sdi_config_lcd_manager(struct omap_dss_device *dssdev)
sdi.mgr_config.video_port_width = 24;
sdi.mgr_config.lcden_sig_polarity = 1;
dss_mgr_set_lcd_config(dssdev->manager, &sdi.mgr_config);
dss_mgr_set_lcd_config(mgr, &sdi.mgr_config);
}
int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
{
struct omap_video_timings *t = &dssdev->panel.timings;
struct omap_dss_output *out = dssdev->output;
struct omap_video_timings *t = &sdi.timings;
struct dss_clock_info dss_cinfo;
struct dispc_clock_info dispc_cinfo;
unsigned long pck;
int r;
if (dssdev->manager == NULL) {
DSSERR("failed to enable display: no manager\n");
if (out == NULL || out->manager == NULL) {
DSSERR("failed to enable display: no output/manager\n");
return -ENODEV;
}
@ -77,8 +85,8 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
goto err_get_dispc;
/* 15.5.9.1.2 */
dssdev->panel.timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
dssdev->panel.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
r = dss_calc_clock_div(t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo);
if (r)
@ -97,7 +105,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
}
dss_mgr_set_timings(dssdev->manager, t);
dss_mgr_set_timings(out->manager, t);
r = dss_set_clock_div(&dss_cinfo);
if (r)
@ -116,16 +124,15 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
* need to care about the shadow register mechanism for pck-free. The
* exact reason for this is unknown.
*/
dispc_mgr_set_clock_div(dssdev->manager->id,
&sdi.mgr_config.clock_info);
dispc_mgr_set_clock_div(out->manager->id, &sdi.mgr_config.clock_info);
dss_sdi_init(dssdev->phy.sdi.datapairs);
dss_sdi_init(sdi.datapairs);
r = dss_sdi_enable();
if (r)
goto err_sdi_enable;
mdelay(2);
r = dss_mgr_enable(dssdev->manager);
r = dss_mgr_enable(out->manager);
if (r)
goto err_mgr_enable;
@ -148,7 +155,9 @@ EXPORT_SYMBOL(omapdss_sdi_display_enable);
void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
{
dss_mgr_disable(dssdev->manager);
struct omap_overlay_manager *mgr = dssdev->output->manager;
dss_mgr_disable(mgr);
dss_sdi_disable();
@ -160,6 +169,19 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
}
EXPORT_SYMBOL(omapdss_sdi_display_disable);
void omapdss_sdi_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
sdi.timings = *timings;
}
EXPORT_SYMBOL(omapdss_sdi_set_timings);
void omapdss_sdi_set_datapairs(struct omap_dss_device *dssdev, int datapairs)
{
sdi.datapairs = datapairs;
}
EXPORT_SYMBOL(omapdss_sdi_set_datapairs);
static int __init sdi_init_display(struct omap_dss_device *dssdev)
{
DSSDBG("SDI init\n");
@ -180,10 +202,14 @@ static int __init sdi_init_display(struct omap_dss_device *dssdev)
return 0;
}
static void __init sdi_probe_pdata(struct platform_device *pdev)
static struct omap_dss_device * __init sdi_find_dssdev(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
int i, r;
const char *def_disp_name = dss_get_default_display_name();
struct omap_dss_device *def_dssdev;
int i;
def_dssdev = NULL;
for (i = 0; i < pdata->num_devices; ++i) {
struct omap_dss_device *dssdev = pdata->devices[i];
@ -191,21 +217,73 @@ static void __init sdi_probe_pdata(struct platform_device *pdev)
if (dssdev->type != OMAP_DISPLAY_TYPE_SDI)
continue;
r = sdi_init_display(dssdev);
if (r) {
DSSERR("device %s init failed: %d\n", dssdev->name, r);
continue;
}
if (def_dssdev == NULL)
def_dssdev = dssdev;
r = omap_dss_register_device(dssdev, &pdev->dev, i);
if (r)
DSSERR("device %s register failed: %d\n",
dssdev->name, r);
if (def_disp_name != NULL &&
strcmp(dssdev->name, def_disp_name) == 0) {
def_dssdev = dssdev;
break;
}
}
return def_dssdev;
}
static void __init sdi_probe_pdata(struct platform_device *sdidev)
{
struct omap_dss_device *plat_dssdev;
struct omap_dss_device *dssdev;
int r;
plat_dssdev = sdi_find_dssdev(sdidev);
if (!plat_dssdev)
return;
dssdev = dss_alloc_and_init_device(&sdidev->dev);
if (!dssdev)
return;
dss_copy_device_pdata(dssdev, plat_dssdev);
r = sdi_init_display(dssdev);
if (r) {
DSSERR("device %s init failed: %d\n", dssdev->name, r);
dss_put_device(dssdev);
return;
}
r = dss_add_device(dssdev);
if (r) {
DSSERR("device %s register failed: %d\n", dssdev->name, r);
dss_put_device(dssdev);
return;
}
}
static void __init sdi_init_output(struct platform_device *pdev)
{
struct omap_dss_output *out = &sdi.output;
out->pdev = pdev;
out->id = OMAP_DSS_OUTPUT_SDI;
out->type = OMAP_DISPLAY_TYPE_SDI;
dss_register_output(out);
}
static void __exit sdi_uninit_output(struct platform_device *pdev)
{
struct omap_dss_output *out = &sdi.output;
dss_unregister_output(out);
}
static int __init omap_sdi_probe(struct platform_device *pdev)
{
sdi_init_output(pdev);
sdi_probe_pdata(pdev);
return 0;
@ -213,7 +291,9 @@ static int __init omap_sdi_probe(struct platform_device *pdev)
static int __exit omap_sdi_remove(struct platform_device *pdev)
{
omap_dss_unregister_child_devices(&pdev->dev);
dss_unregister_child_devices(&pdev->dev);
sdi_uninit_output(pdev);
return 0;
}

View file

@ -36,7 +36,6 @@
#include <linux/pm_runtime.h>
#include <video/omapdss.h>
#include <plat/cpu.h>
#include "dss.h"
#include "dss_features.h"
@ -300,6 +299,12 @@ static struct {
struct regulator *vdda_dac_reg;
struct clk *tv_dac_clk;
struct omap_video_timings timings;
enum omap_dss_venc_type type;
bool invert_polarity;
struct omap_dss_output output;
} venc;
static inline void venc_write_reg(int idx, u32 val)
@ -424,65 +429,67 @@ static const struct venc_config *venc_timings_to_config(
static int venc_power_on(struct omap_dss_device *dssdev)
{
struct omap_overlay_manager *mgr = dssdev->output->manager;
u32 l;
int r;
venc_reset();
venc_write_config(venc_timings_to_config(&dssdev->panel.timings));
r = venc_runtime_get();
if (r)
goto err0;
dss_set_venc_output(dssdev->phy.venc.type);
venc_reset();
venc_write_config(venc_timings_to_config(&venc.timings));
dss_set_venc_output(venc.type);
dss_set_dac_pwrdn_bgz(1);
l = 0;
if (dssdev->phy.venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE)
if (venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE)
l |= 1 << 1;
else /* S-Video */
l |= (1 << 0) | (1 << 2);
if (dssdev->phy.venc.invert_polarity == false)
if (venc.invert_polarity == false)
l |= 1 << 3;
venc_write_reg(VENC_OUTPUT_CONTROL, l);
dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings);
dss_mgr_set_timings(mgr, &venc.timings);
r = regulator_enable(venc.vdda_dac_reg);
if (r)
goto err;
goto err1;
if (dssdev->platform_enable)
dssdev->platform_enable(dssdev);
r = dss_mgr_enable(dssdev->manager);
r = dss_mgr_enable(mgr);
if (r)
goto err;
goto err2;
return 0;
err:
err2:
regulator_disable(venc.vdda_dac_reg);
err1:
venc_write_reg(VENC_OUTPUT_CONTROL, 0);
dss_set_dac_pwrdn_bgz(0);
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
regulator_disable(venc.vdda_dac_reg);
venc_runtime_put();
err0:
return r;
}
static void venc_power_off(struct omap_dss_device *dssdev)
{
struct omap_overlay_manager *mgr = dssdev->output->manager;
venc_write_reg(VENC_OUTPUT_CONTROL, 0);
dss_set_dac_pwrdn_bgz(0);
dss_mgr_disable(dssdev->manager);
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
dss_mgr_disable(mgr);
regulator_disable(venc.vdda_dac_reg);
venc_runtime_put();
}
unsigned long venc_get_pixel_clock(void)
@ -491,171 +498,83 @@ unsigned long venc_get_pixel_clock(void)
return 13500000;
}
static ssize_t display_output_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
int omapdss_venc_display_enable(struct omap_dss_device *dssdev)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
const char *ret;
struct omap_dss_output *out = dssdev->output;
int r;
switch (dssdev->phy.venc.type) {
case OMAP_DSS_VENC_TYPE_COMPOSITE:
ret = "composite";
break;
case OMAP_DSS_VENC_TYPE_SVIDEO:
ret = "svideo";
break;
default:
return -EINVAL;
}
return snprintf(buf, PAGE_SIZE, "%s\n", ret);
}
static ssize_t display_output_type_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
enum omap_dss_venc_type new_type;
if (sysfs_streq("composite", buf))
new_type = OMAP_DSS_VENC_TYPE_COMPOSITE;
else if (sysfs_streq("svideo", buf))
new_type = OMAP_DSS_VENC_TYPE_SVIDEO;
else
return -EINVAL;
DSSDBG("venc_display_enable\n");
mutex_lock(&venc.venc_lock);
if (dssdev->phy.venc.type != new_type) {
dssdev->phy.venc.type = new_type;
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
venc_power_off(dssdev);
venc_power_on(dssdev);
}
if (out == NULL || out->manager == NULL) {
DSSERR("Failed to enable display: no output/manager\n");
r = -ENODEV;
goto err0;
}
mutex_unlock(&venc.venc_lock);
return size;
}
static DEVICE_ATTR(output_type, S_IRUGO | S_IWUSR,
display_output_type_show, display_output_type_store);
/* driver */
static int venc_panel_probe(struct omap_dss_device *dssdev)
{
dssdev->panel.timings = omap_dss_pal_timings;
return device_create_file(&dssdev->dev, &dev_attr_output_type);
}
static void venc_panel_remove(struct omap_dss_device *dssdev)
{
device_remove_file(&dssdev->dev, &dev_attr_output_type);
}
static int venc_panel_enable(struct omap_dss_device *dssdev)
{
int r = 0;
DSSDBG("venc_enable_display\n");
mutex_lock(&venc.venc_lock);
r = omap_dss_start_device(dssdev);
if (r) {
DSSERR("failed to start device\n");
goto err0;
}
if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
r = -EINVAL;
goto err1;
}
if (dssdev->platform_enable)
dssdev->platform_enable(dssdev);
r = venc_runtime_get();
if (r)
goto err1;
r = venc_power_on(dssdev);
if (r)
goto err2;
goto err1;
venc.wss_data = 0;
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
mutex_unlock(&venc.venc_lock);
return 0;
err2:
venc_runtime_put();
err1:
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
omap_dss_stop_device(dssdev);
err0:
mutex_unlock(&venc.venc_lock);
return r;
}
static void venc_panel_disable(struct omap_dss_device *dssdev)
void omapdss_venc_display_disable(struct omap_dss_device *dssdev)
{
DSSDBG("venc_disable_display\n");
DSSDBG("venc_display_disable\n");
mutex_lock(&venc.venc_lock);
if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
goto end;
if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) {
/* suspended is the same as disabled with venc */
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
goto end;
}
venc_power_off(dssdev);
venc_runtime_put();
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
omap_dss_stop_device(dssdev);
end:
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
mutex_unlock(&venc.venc_lock);
}
static int venc_panel_suspend(struct omap_dss_device *dssdev)
{
venc_panel_disable(dssdev);
return 0;
}
static int venc_panel_resume(struct omap_dss_device *dssdev)
{
return venc_panel_enable(dssdev);
}
static void venc_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
void omapdss_venc_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
DSSDBG("venc_set_timings\n");
mutex_lock(&venc.venc_lock);
/* Reset WSS data when the TV standard changes. */
if (memcmp(&dssdev->panel.timings, timings, sizeof(*timings)))
if (memcmp(&venc.timings, timings, sizeof(*timings)))
venc.wss_data = 0;
dssdev->panel.timings = *timings;
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
/* turn the venc off and on to get new timings to use */
venc_panel_disable(dssdev);
venc_panel_enable(dssdev);
} else {
dss_mgr_set_timings(dssdev->manager, timings);
}
venc.timings = *timings;
mutex_unlock(&venc.venc_lock);
}
static int venc_check_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
int omapdss_venc_check_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
DSSDBG("venc_check_timings\n");
@ -668,13 +587,13 @@ static int venc_check_timings(struct omap_dss_device *dssdev,
return -EINVAL;
}
static u32 venc_get_wss(struct omap_dss_device *dssdev)
u32 omapdss_venc_get_wss(struct omap_dss_device *dssdev)
{
/* Invert due to VENC_L21_WC_CTL:INV=1 */
return (venc.wss_data >> 8) ^ 0xfffff;
}
static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
int omapdss_venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
{
const struct venc_config *config;
int r;
@ -683,7 +602,7 @@ static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
mutex_lock(&venc.venc_lock);
config = venc_timings_to_config(&dssdev->panel.timings);
config = venc_timings_to_config(&venc.timings);
/* Invert due to VENC_L21_WC_CTL:INV=1 */
venc.wss_data = (wss ^ 0xfffff) << 8;
@ -703,30 +622,25 @@ err:
return r;
}
static struct omap_dss_driver venc_driver = {
.probe = venc_panel_probe,
.remove = venc_panel_remove,
void omapdss_venc_set_type(struct omap_dss_device *dssdev,
enum omap_dss_venc_type type)
{
mutex_lock(&venc.venc_lock);
.enable = venc_panel_enable,
.disable = venc_panel_disable,
.suspend = venc_panel_suspend,
.resume = venc_panel_resume,
venc.type = type;
.get_resolution = omapdss_default_get_resolution,
.get_recommended_bpp = omapdss_default_get_recommended_bpp,
mutex_unlock(&venc.venc_lock);
}
.set_timings = venc_set_timings,
.check_timings = venc_check_timings,
void omapdss_venc_invert_vid_out_polarity(struct omap_dss_device *dssdev,
bool invert_polarity)
{
mutex_lock(&venc.venc_lock);
.get_wss = venc_get_wss,
.set_wss = venc_set_wss,
venc.invert_polarity = invert_polarity;
.driver = {
.name = "venc",
.owner = THIS_MODULE,
},
};
/* driver end */
mutex_unlock(&venc.venc_lock);
}
static int __init venc_init_display(struct omap_dss_device *dssdev)
{
@ -752,11 +666,6 @@ static void venc_dump_regs(struct seq_file *s)
{
#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r))
if (cpu_is_omap44xx()) {
seq_printf(s, "VENC currently disabled on OMAP44xx\n");
return;
}
if (venc_runtime_get())
return;
@ -832,10 +741,14 @@ static void venc_put_clocks(void)
clk_put(venc.tv_dac_clk);
}
static void __init venc_probe_pdata(struct platform_device *pdev)
static struct omap_dss_device * __init venc_find_dssdev(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
int r, i;
const char *def_disp_name = dss_get_default_display_name();
struct omap_dss_device *def_dssdev;
int i;
def_dssdev = NULL;
for (i = 0; i < pdata->num_devices; ++i) {
struct omap_dss_device *dssdev = pdata->devices[i];
@ -843,17 +756,69 @@ static void __init venc_probe_pdata(struct platform_device *pdev)
if (dssdev->type != OMAP_DISPLAY_TYPE_VENC)
continue;
r = venc_init_display(dssdev);
if (r) {
DSSERR("device %s init failed: %d\n", dssdev->name, r);
continue;
}
if (def_dssdev == NULL)
def_dssdev = dssdev;
r = omap_dss_register_device(dssdev, &pdev->dev, i);
if (r)
DSSERR("device %s register failed: %d\n",
dssdev->name, r);
if (def_disp_name != NULL &&
strcmp(dssdev->name, def_disp_name) == 0) {
def_dssdev = dssdev;
break;
}
}
return def_dssdev;
}
static void __init venc_probe_pdata(struct platform_device *vencdev)
{
struct omap_dss_device *plat_dssdev;
struct omap_dss_device *dssdev;
int r;
plat_dssdev = venc_find_dssdev(vencdev);
if (!plat_dssdev)
return;
dssdev = dss_alloc_and_init_device(&vencdev->dev);
if (!dssdev)
return;
dss_copy_device_pdata(dssdev, plat_dssdev);
dssdev->channel = OMAP_DSS_CHANNEL_DIGIT;
r = venc_init_display(dssdev);
if (r) {
DSSERR("device %s init failed: %d\n", dssdev->name, r);
dss_put_device(dssdev);
return;
}
r = dss_add_device(dssdev);
if (r) {
DSSERR("device %s register failed: %d\n", dssdev->name, r);
dss_put_device(dssdev);
return;
}
}
static void __init venc_init_output(struct platform_device *pdev)
{
struct omap_dss_output *out = &venc.output;
out->pdev = pdev;
out->id = OMAP_DSS_OUTPUT_VENC;
out->type = OMAP_DISPLAY_TYPE_VENC;
dss_register_output(out);
}
static void __exit venc_uninit_output(struct platform_device *pdev)
{
struct omap_dss_output *out = &venc.output;
dss_unregister_output(out);
}
/* VENC HW IP initialisation */
@ -897,17 +862,19 @@ static int __init omap_venchw_probe(struct platform_device *pdev)
venc_runtime_put();
r = omap_dss_register_driver(&venc_driver);
r = venc_panel_init();
if (r)
goto err_reg_panel_driver;
goto err_panel_init;
dss_debugfs_create_file("venc", venc_dump_regs);
venc_init_output(pdev);
venc_probe_pdata(pdev);
return 0;
err_reg_panel_driver:
err_panel_init:
err_runtime_get:
pm_runtime_disable(&pdev->dev);
venc_put_clocks();
@ -916,14 +883,16 @@ err_runtime_get:
static int __exit omap_venchw_remove(struct platform_device *pdev)
{
omap_dss_unregister_child_devices(&pdev->dev);
dss_unregister_child_devices(&pdev->dev);
if (venc.vdda_dac_reg != NULL) {
regulator_put(venc.vdda_dac_reg);
venc.vdda_dac_reg = NULL;
}
omap_dss_unregister_driver(&venc_driver);
venc_panel_exit();
venc_uninit_output(pdev);
pm_runtime_disable(&pdev->dev);
venc_put_clocks();
@ -971,16 +940,10 @@ static struct platform_driver omap_venchw_driver = {
int __init venc_init_platform_driver(void)
{
if (cpu_is_omap44xx())
return 0;
return platform_driver_probe(&omap_venchw_driver, omap_venchw_probe);
}
void __exit venc_uninit_platform_driver(void)
{
if (cpu_is_omap44xx())
return;
platform_driver_unregister(&omap_venchw_driver);
}

View file

@ -0,0 +1,251 @@
/*
* Copyright (C) 2009 Nokia Corporation
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
*
* VENC panel driver
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/mutex.h>
#include <linux/module.h>
#include <video/omapdss.h>
#include "dss.h"
static struct {
struct mutex lock;
} venc_panel;
static ssize_t display_output_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
const char *ret;
switch (dssdev->phy.venc.type) {
case OMAP_DSS_VENC_TYPE_COMPOSITE:
ret = "composite";
break;
case OMAP_DSS_VENC_TYPE_SVIDEO:
ret = "svideo";
break;
default:
return -EINVAL;
}
return snprintf(buf, PAGE_SIZE, "%s\n", ret);
}
static ssize_t display_output_type_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
enum omap_dss_venc_type new_type;
if (sysfs_streq("composite", buf))
new_type = OMAP_DSS_VENC_TYPE_COMPOSITE;
else if (sysfs_streq("svideo", buf))
new_type = OMAP_DSS_VENC_TYPE_SVIDEO;
else
return -EINVAL;
mutex_lock(&venc_panel.lock);
if (dssdev->phy.venc.type != new_type) {
dssdev->phy.venc.type = new_type;
omapdss_venc_set_type(dssdev, new_type);
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
omapdss_venc_display_disable(dssdev);
omapdss_venc_display_enable(dssdev);
}
}
mutex_unlock(&venc_panel.lock);
return size;
}
static DEVICE_ATTR(output_type, S_IRUGO | S_IWUSR,
display_output_type_show, display_output_type_store);
static int venc_panel_probe(struct omap_dss_device *dssdev)
{
/* set default timings to PAL */
const struct omap_video_timings default_timings = {
.x_res = 720,
.y_res = 574,
.pixel_clock = 13500,
.hsw = 64,
.hfp = 12,
.hbp = 68,
.vsw = 5,
.vfp = 5,
.vbp = 41,
.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH,
.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH,
.interlace = true,
};
mutex_init(&venc_panel.lock);
dssdev->panel.timings = default_timings;
return device_create_file(&dssdev->dev, &dev_attr_output_type);
}
static void venc_panel_remove(struct omap_dss_device *dssdev)
{
device_remove_file(&dssdev->dev, &dev_attr_output_type);
}
static int venc_panel_enable(struct omap_dss_device *dssdev)
{
int r;
dev_dbg(&dssdev->dev, "venc_panel_enable\n");
mutex_lock(&venc_panel.lock);
if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
r = -EINVAL;
goto err;
}
omapdss_venc_set_timings(dssdev, &dssdev->panel.timings);
omapdss_venc_set_type(dssdev, dssdev->phy.venc.type);
omapdss_venc_invert_vid_out_polarity(dssdev,
dssdev->phy.venc.invert_polarity);
r = omapdss_venc_display_enable(dssdev);
if (r)
goto err;
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
mutex_unlock(&venc_panel.lock);
return 0;
err:
mutex_unlock(&venc_panel.lock);
return r;
}
static void venc_panel_disable(struct omap_dss_device *dssdev)
{
dev_dbg(&dssdev->dev, "venc_panel_disable\n");
mutex_lock(&venc_panel.lock);
if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
goto end;
if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) {
/* suspended is the same as disabled with venc */
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
goto end;
}
omapdss_venc_display_disable(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
end:
mutex_unlock(&venc_panel.lock);
}
static int venc_panel_suspend(struct omap_dss_device *dssdev)
{
venc_panel_disable(dssdev);
return 0;
}
static int venc_panel_resume(struct omap_dss_device *dssdev)
{
return venc_panel_enable(dssdev);
}
static void venc_panel_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
dev_dbg(&dssdev->dev, "venc_panel_set_timings\n");
mutex_lock(&venc_panel.lock);
omapdss_venc_set_timings(dssdev, timings);
dssdev->panel.timings = *timings;
mutex_unlock(&venc_panel.lock);
}
static int venc_panel_check_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
dev_dbg(&dssdev->dev, "venc_panel_check_timings\n");
return omapdss_venc_check_timings(dssdev, timings);
}
static u32 venc_panel_get_wss(struct omap_dss_device *dssdev)
{
dev_dbg(&dssdev->dev, "venc_panel_get_wss\n");
return omapdss_venc_get_wss(dssdev);
}
static int venc_panel_set_wss(struct omap_dss_device *dssdev, u32 wss)
{
dev_dbg(&dssdev->dev, "venc_panel_set_wss\n");
return omapdss_venc_set_wss(dssdev, wss);
}
static struct omap_dss_driver venc_driver = {
.probe = venc_panel_probe,
.remove = venc_panel_remove,
.enable = venc_panel_enable,
.disable = venc_panel_disable,
.suspend = venc_panel_suspend,
.resume = venc_panel_resume,
.get_resolution = omapdss_default_get_resolution,
.get_recommended_bpp = omapdss_default_get_recommended_bpp,
.set_timings = venc_panel_set_timings,
.check_timings = venc_panel_check_timings,
.get_wss = venc_panel_get_wss,
.set_wss = venc_panel_set_wss,
.driver = {
.name = "venc",
.owner = THIS_MODULE,
},
};
int venc_panel_init(void)
{
return omap_dss_register_driver(&venc_driver);
}
void venc_panel_exit(void)
{
omap_dss_unregister_driver(&venc_driver);
}

View file

@ -599,6 +599,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_device *fbdev = ofbi->fbdev;
struct omap_dss_device *display = fb2display(fbi);
struct omap_overlay_manager *mgr;
union {
struct omapfb_update_window_old uwnd_o;
@ -786,12 +787,14 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
case OMAPFB_WAITFORVSYNC:
DBG("ioctl WAITFORVSYNC\n");
if (!display) {
if (!display && !display->output && !display->output->manager) {
r = -EINVAL;
break;
}
r = display->manager->wait_for_vsync(display->manager);
mgr = display->output->manager;
r = mgr->wait_for_vsync(mgr);
break;
case OMAPFB_WAITFORGO:

View file

@ -1593,6 +1593,20 @@ static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev)
return 0;
}
static void omapfb_clear_fb(struct fb_info *fbi)
{
const struct fb_fillrect rect = {
.dx = 0,
.dy = 0,
.width = fbi->var.xres_virtual,
.height = fbi->var.yres_virtual,
.color = 0,
.rop = ROP_COPY,
};
cfb_fillrect(fbi, &rect);
}
int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
{
struct omapfb_info *ofbi = FB2OFB(fbi);
@ -1662,6 +1676,8 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
goto err;
}
omapfb_clear_fb(fbi);
return 0;
err:
omapfb_free_fbmem(fbi);
@ -1946,6 +1962,16 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
}
}
for (i = 0; i < fbdev->num_fbs; i++) {
struct fb_info *fbi = fbdev->fbs[i];
struct omapfb_info *ofbi = FB2OFB(fbi);
if (ofbi->region->size == 0)
continue;
omapfb_clear_fb(fbi);
}
DBG("fb_infos initialized\n");
for (i = 0; i < fbdev->num_fbs; i++) {
@ -2354,6 +2380,7 @@ static int __init omapfb_probe(struct platform_device *pdev)
struct omap_overlay *ovl;
struct omap_dss_device *def_display;
struct omap_dss_device *dssdev;
struct omap_dss_device *ovl_device;
DBG("omapfb_probe\n");
@ -2427,8 +2454,9 @@ static int __init omapfb_probe(struct platform_device *pdev)
/* gfx overlay should be the default one. find a display
* connected to that, and use it as default display */
ovl = omap_dss_get_overlay(0);
if (ovl->manager && ovl->manager->device) {
def_display = ovl->manager->device;
ovl_device = ovl->get_device(ovl);
if (ovl_device) {
def_display = ovl_device;
} else {
dev_warn(&pdev->dev, "cannot find default display\n");
def_display = NULL;

View file

@ -148,8 +148,9 @@ static inline struct omap_dss_device *fb2display(struct fb_info *fbi)
/* XXX: returns the display connected to first attached overlay */
for (i = 0; i < ofbi->num_overlays; i++) {
if (ofbi->overlays[i]->manager)
return ofbi->overlays[i]->manager->device;
struct omap_overlay *ovl = ofbi->overlays[i];
return ovl->get_device(ovl);
}
return NULL;

View file

@ -34,7 +34,6 @@
#include <asm/setup.h>
#include <plat/vram.h>
#include <plat/dma.h>
#ifdef DEBUG
#define DBG(format, ...) pr_debug("VRAM: " format, ## __VA_ARGS__)
@ -250,59 +249,6 @@ int omap_vram_reserve(unsigned long paddr, size_t size)
}
EXPORT_SYMBOL(omap_vram_reserve);
static void _omap_vram_dma_cb(int lch, u16 ch_status, void *data)
{
struct completion *compl = data;
complete(compl);
}
static int _omap_vram_clear(u32 paddr, unsigned pages)
{
struct completion compl;
unsigned elem_count;
unsigned frame_count;
int r;
int lch;
init_completion(&compl);
r = omap_request_dma(OMAP_DMA_NO_DEVICE, "VRAM DMA",
_omap_vram_dma_cb,
&compl, &lch);
if (r) {
pr_err("VRAM: request_dma failed for memory clear\n");
return -EBUSY;
}
elem_count = pages * PAGE_SIZE / 4;
frame_count = 1;
omap_set_dma_transfer_params(lch, OMAP_DMA_DATA_TYPE_S32,
elem_count, frame_count,
OMAP_DMA_SYNC_ELEMENT,
0, 0);
omap_set_dma_dest_params(lch, 0, OMAP_DMA_AMODE_POST_INC,
paddr, 0, 0);
omap_set_dma_color_mode(lch, OMAP_DMA_CONSTANT_FILL, 0x000000);
omap_start_dma(lch);
if (wait_for_completion_timeout(&compl, msecs_to_jiffies(1000)) == 0) {
omap_stop_dma(lch);
pr_err("VRAM: dma timeout while clearing memory\n");
r = -EIO;
goto err;
}
r = 0;
err:
omap_free_dma(lch);
return r;
}
static int _omap_vram_alloc(unsigned pages, unsigned long *paddr)
{
struct vram_region *rm;
@ -337,8 +283,6 @@ found:
*paddr = start;
_omap_vram_clear(start, pages);
return 0;
}

View file

@ -1,7 +0,0 @@
#
# Makefile for the new PNX4008 framebuffer device driver
#
obj-$(CONFIG_FB_PNX4008_DUM) += sdum.o
obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnxrgbfb.o

View file

@ -1,211 +0,0 @@
/*
* linux/drivers/video/pnx4008/dum.h
*
* Internal header for SDUM
*
* 2005 (c) Koninklijke Philips N.V. This file is licensed under
* the terms of the GNU General Public License version 2. This program
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
*/
#ifndef __PNX008_DUM_H__
#define __PNX008_DUM_H__
#include <mach/platform.h>
#define PNX4008_DUMCONF_VA_BASE IO_ADDRESS(PNX4008_DUMCONF_BASE)
#define PNX4008_DUM_MAIN_VA_BASE IO_ADDRESS(PNX4008_DUM_MAINCFG_BASE)
/* DUM CFG ADDRESSES */
#define DUM_CH_BASE_ADR (PNX4008_DUMCONF_VA_BASE + 0x00)
#define DUM_CH_MIN_ADR (PNX4008_DUMCONF_VA_BASE + 0x00)
#define DUM_CH_MAX_ADR (PNX4008_DUMCONF_VA_BASE + 0x04)
#define DUM_CH_CONF_ADR (PNX4008_DUMCONF_VA_BASE + 0x08)
#define DUM_CH_STAT_ADR (PNX4008_DUMCONF_VA_BASE + 0x0C)
#define DUM_CH_CTRL_ADR (PNX4008_DUMCONF_VA_BASE + 0x10)
#define CH_MARG (0x100 / sizeof(u32))
#define DUM_CH_MIN(i) (*((volatile u32 *)DUM_CH_MIN_ADR + (i) * CH_MARG))
#define DUM_CH_MAX(i) (*((volatile u32 *)DUM_CH_MAX_ADR + (i) * CH_MARG))
#define DUM_CH_CONF(i) (*((volatile u32 *)DUM_CH_CONF_ADR + (i) * CH_MARG))
#define DUM_CH_STAT(i) (*((volatile u32 *)DUM_CH_STAT_ADR + (i) * CH_MARG))
#define DUM_CH_CTRL(i) (*((volatile u32 *)DUM_CH_CTRL_ADR + (i) * CH_MARG))
#define DUM_CONF_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x00)
#define DUM_CTRL_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x04)
#define DUM_STAT_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x08)
#define DUM_DECODE_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x0C)
#define DUM_COM_BASE_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x10)
#define DUM_SYNC_C_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x14)
#define DUM_CLK_DIV_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x18)
#define DUM_DIRTY_LOW_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x20)
#define DUM_DIRTY_HIGH_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x24)
#define DUM_FORMAT_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x28)
#define DUM_WTCFG1_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x30)
#define DUM_RTCFG1_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x34)
#define DUM_WTCFG2_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x38)
#define DUM_RTCFG2_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x3C)
#define DUM_TCFG_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x40)
#define DUM_OUTP_FORMAT1_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x44)
#define DUM_OUTP_FORMAT2_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x48)
#define DUM_SYNC_MODE_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x4C)
#define DUM_SYNC_OUT_C_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x50)
#define DUM_CONF (*(volatile u32 *)(DUM_CONF_ADR))
#define DUM_CTRL (*(volatile u32 *)(DUM_CTRL_ADR))
#define DUM_STAT (*(volatile u32 *)(DUM_STAT_ADR))
#define DUM_DECODE (*(volatile u32 *)(DUM_DECODE_ADR))
#define DUM_COM_BASE (*(volatile u32 *)(DUM_COM_BASE_ADR))
#define DUM_SYNC_C (*(volatile u32 *)(DUM_SYNC_C_ADR))
#define DUM_CLK_DIV (*(volatile u32 *)(DUM_CLK_DIV_ADR))
#define DUM_DIRTY_LOW (*(volatile u32 *)(DUM_DIRTY_LOW_ADR))
#define DUM_DIRTY_HIGH (*(volatile u32 *)(DUM_DIRTY_HIGH_ADR))
#define DUM_FORMAT (*(volatile u32 *)(DUM_FORMAT_ADR))
#define DUM_WTCFG1 (*(volatile u32 *)(DUM_WTCFG1_ADR))
#define DUM_RTCFG1 (*(volatile u32 *)(DUM_RTCFG1_ADR))
#define DUM_WTCFG2 (*(volatile u32 *)(DUM_WTCFG2_ADR))
#define DUM_RTCFG2 (*(volatile u32 *)(DUM_RTCFG2_ADR))
#define DUM_TCFG (*(volatile u32 *)(DUM_TCFG_ADR))
#define DUM_OUTP_FORMAT1 (*(volatile u32 *)(DUM_OUTP_FORMAT1_ADR))
#define DUM_OUTP_FORMAT2 (*(volatile u32 *)(DUM_OUTP_FORMAT2_ADR))
#define DUM_SYNC_MODE (*(volatile u32 *)(DUM_SYNC_MODE_ADR))
#define DUM_SYNC_OUT_C (*(volatile u32 *)(DUM_SYNC_OUT_C_ADR))
/* DUM SLAVE ADDRESSES */
#define DUM_SLAVE_WRITE_ADR (PNX4008_DUM_MAINCFG_BASE + 0x0000000)
#define DUM_SLAVE_READ1_I_ADR (PNX4008_DUM_MAINCFG_BASE + 0x1000000)
#define DUM_SLAVE_READ1_R_ADR (PNX4008_DUM_MAINCFG_BASE + 0x1000004)
#define DUM_SLAVE_READ2_I_ADR (PNX4008_DUM_MAINCFG_BASE + 0x1000008)
#define DUM_SLAVE_READ2_R_ADR (PNX4008_DUM_MAINCFG_BASE + 0x100000C)
#define DUM_SLAVE_WRITE_W ((volatile u32 *)(DUM_SLAVE_WRITE_ADR))
#define DUM_SLAVE_WRITE_HW ((volatile u16 *)(DUM_SLAVE_WRITE_ADR))
#define DUM_SLAVE_READ1_I ((volatile u8 *)(DUM_SLAVE_READ1_I_ADR))
#define DUM_SLAVE_READ1_R ((volatile u16 *)(DUM_SLAVE_READ1_R_ADR))
#define DUM_SLAVE_READ2_I ((volatile u8 *)(DUM_SLAVE_READ2_I_ADR))
#define DUM_SLAVE_READ2_R ((volatile u16 *)(DUM_SLAVE_READ2_R_ADR))
/* Sony display register addresses */
#define DISP_0_REG (0x00)
#define DISP_1_REG (0x01)
#define DISP_CAL_REG (0x20)
#define DISP_ID_REG (0x2A)
#define DISP_XMIN_L_REG (0x30)
#define DISP_XMIN_H_REG (0x31)
#define DISP_YMIN_REG (0x32)
#define DISP_XMAX_L_REG (0x34)
#define DISP_XMAX_H_REG (0x35)
#define DISP_YMAX_REG (0x36)
#define DISP_SYNC_EN_REG (0x38)
#define DISP_SYNC_RISE_L_REG (0x3C)
#define DISP_SYNC_RISE_H_REG (0x3D)
#define DISP_SYNC_FALL_L_REG (0x3E)
#define DISP_SYNC_FALL_H_REG (0x3F)
#define DISP_PIXEL_REG (0x0B)
#define DISP_DUMMY1_REG (0x28)
#define DISP_DUMMY2_REG (0x29)
#define DISP_TIMING_REG (0x98)
#define DISP_DUMP_REG (0x99)
/* Sony display constants */
#define SONY_ID1 (0x22)
#define SONY_ID2 (0x23)
/* Philips display register addresses */
#define PH_DISP_ORIENT_REG (0x003)
#define PH_DISP_YPOINT_REG (0x200)
#define PH_DISP_XPOINT_REG (0x201)
#define PH_DISP_PIXEL_REG (0x202)
#define PH_DISP_YMIN_REG (0x406)
#define PH_DISP_YMAX_REG (0x407)
#define PH_DISP_XMIN_REG (0x408)
#define PH_DISP_XMAX_REG (0x409)
/* Misc constants */
#define NO_VALID_DISPLAY_FOUND (0)
#define DISPLAY2_IS_NOT_CONNECTED (0)
/* register values */
#define V_BAC_ENABLE (BIT(0))
#define V_BAC_DISABLE_IDLE (BIT(1))
#define V_BAC_DISABLE_TRIG (BIT(2))
#define V_DUM_RESET (BIT(3))
#define V_MUX_RESET (BIT(4))
#define BAC_ENABLED (BIT(0))
#define BAC_DISABLED 0
/* Sony LCD commands */
#define V_LCD_STANDBY_OFF ((BIT(25)) | (0 << 16) | DISP_0_REG)
#define V_LCD_USE_9BIT_BUS ((BIT(25)) | (2 << 16) | DISP_1_REG)
#define V_LCD_SYNC_RISE_L ((BIT(25)) | (0 << 16) | DISP_SYNC_RISE_L_REG)
#define V_LCD_SYNC_RISE_H ((BIT(25)) | (0 << 16) | DISP_SYNC_RISE_H_REG)
#define V_LCD_SYNC_FALL_L ((BIT(25)) | (160 << 16) | DISP_SYNC_FALL_L_REG)
#define V_LCD_SYNC_FALL_H ((BIT(25)) | (0 << 16) | DISP_SYNC_FALL_H_REG)
#define V_LCD_SYNC_ENABLE ((BIT(25)) | (128 << 16) | DISP_SYNC_EN_REG)
#define V_LCD_DISPLAY_ON ((BIT(25)) | (64 << 16) | DISP_0_REG)
enum {
PAD_NONE,
PAD_512,
PAD_1024
};
enum {
RGB888,
RGB666,
RGB565,
BGR565,
ARGB1555,
ABGR1555,
ARGB4444,
ABGR4444
};
struct dum_setup {
int sync_neg_edge;
int round_robin;
int mux_int;
int synced_dirty_flag_int;
int dirty_flag_int;
int error_int;
int pf_empty_int;
int sf_empty_int;
int bac_dis_int;
u32 dirty_base_adr;
u32 command_base_adr;
u32 sync_clk_div;
int sync_output;
u32 sync_restart_val;
u32 set_sync_high;
u32 set_sync_low;
};
struct dum_ch_setup {
int disp_no;
u32 xmin;
u32 ymin;
u32 xmax;
u32 ymax;
int xmirror;
int ymirror;
int rotate;
u32 minadr;
u32 maxadr;
u32 dirtybuffer;
int pad;
int format;
int hwdirty;
int slave_trans;
};
struct disp_window {
u32 xmin_l;
u32 xmin_h;
u32 ymin;
u32 xmax_l;
u32 xmax_h;
u32 ymax;
};
#endif /* #ifndef __PNX008_DUM_H__ */

View file

@ -1,43 +0,0 @@
/*
* Copyright (C) 2005 Philips Semiconductors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA, or http://www.gnu.org/licenses/gpl.html
*/
#define QCIF_W (176)
#define QCIF_H (144)
#define CIF_W (352)
#define CIF_H (288)
#define LCD_X_RES 208
#define LCD_Y_RES 320
#define LCD_X_PAD 256
#define LCD_BBP 4 /* Bytes Per Pixel */
#define DISP_MAX_X_SIZE (320)
#define DISP_MAX_Y_SIZE (208)
#define RETURNVAL_BASE (0x400)
enum fb_ioctl_returntype {
ENORESOURCESLEFT = RETURNVAL_BASE,
ERESOURCESNOTFREED,
EPROCNOTOWNER,
EFBNOTOWNER,
ECOPYFAILED,
EIOREMAPFAILED,
};

View file

@ -1,198 +0,0 @@
/*
* drivers/video/pnx4008/pnxrgbfb.c
*
* PNX4008's framebuffer support
*
* Author: Grigory Tolstolytkin <gtolstolytkin@ru.mvista.com>
* Based on Philips Semiconductors's code
*
* Copyrght (c) 2005 MontaVista Software, Inc.
* Copyright (c) 2005 Philips Semiconductors
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include "sdum.h"
#include "fbcommon.h"
static u32 colreg[16];
static struct fb_var_screeninfo rgbfb_var __initdata = {
.xres = LCD_X_RES,
.yres = LCD_Y_RES,
.xres_virtual = LCD_X_RES,
.yres_virtual = LCD_Y_RES,
.bits_per_pixel = 32,
.red.offset = 16,
.red.length = 8,
.green.offset = 8,
.green.length = 8,
.blue.offset = 0,
.blue.length = 8,
.left_margin = 0,
.right_margin = 0,
.upper_margin = 0,
.lower_margin = 0,
.vmode = FB_VMODE_NONINTERLACED,
};
static struct fb_fix_screeninfo rgbfb_fix __initdata = {
.id = "RGBFB",
.line_length = LCD_X_RES * LCD_BBP,
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_TRUECOLOR,
.xpanstep = 0,
.ypanstep = 0,
.ywrapstep = 0,
.accel = FB_ACCEL_NONE,
};
static int channel_owned;
static int no_cursor(struct fb_info *info, struct fb_cursor *cursor)
{
return 0;
}
static int rgbfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *info)
{
if (regno > 15)
return 1;
colreg[regno] = ((red & 0xff00) << 8) | (green & 0xff00) |
((blue & 0xff00) >> 8);
return 0;
}
static int rgbfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
return pnx4008_sdum_mmap(info, vma, NULL);
}
static struct fb_ops rgbfb_ops = {
.fb_mmap = rgbfb_mmap,
.fb_setcolreg = rgbfb_setcolreg,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
};
static int rgbfb_remove(struct platform_device *pdev)
{
struct fb_info *info = platform_get_drvdata(pdev);
if (info) {
unregister_framebuffer(info);
fb_dealloc_cmap(&info->cmap);
framebuffer_release(info);
platform_set_drvdata(pdev, NULL);
}
pnx4008_free_dum_channel(channel_owned, pdev->id);
pnx4008_set_dum_exit_notification(pdev->id);
return 0;
}
static int __devinit rgbfb_probe(struct platform_device *pdev)
{
struct fb_info *info;
struct dumchannel_uf chan_uf;
int ret;
char *option;
info = framebuffer_alloc(sizeof(u32) * 16, &pdev->dev);
if (!info) {
ret = -ENOMEM;
goto err;
}
pnx4008_get_fb_addresses(FB_TYPE_RGB, (void **)&info->screen_base,
(dma_addr_t *) &rgbfb_fix.smem_start,
&rgbfb_fix.smem_len);
if ((ret = pnx4008_alloc_dum_channel(pdev->id)) < 0)
goto err0;
else {
channel_owned = ret;
chan_uf.channelnr = channel_owned;
chan_uf.dirty = (u32 *) NULL;
chan_uf.source = (u32 *) rgbfb_fix.smem_start;
chan_uf.x_offset = 0;
chan_uf.y_offset = 0;
chan_uf.width = LCD_X_RES;
chan_uf.height = LCD_Y_RES;
if ((ret = pnx4008_put_dum_channel_uf(chan_uf, pdev->id))< 0)
goto err1;
if ((ret =
pnx4008_set_dum_channel_sync(channel_owned, CONF_SYNC_ON,
pdev->id)) < 0)
goto err1;
if ((ret =
pnx4008_set_dum_channel_dirty_detect(channel_owned,
CONF_DIRTYDETECTION_ON,
pdev->id)) < 0)
goto err1;
}
if (!fb_get_options("pnxrgbfb", &option) && option &&
!strcmp(option, "nocursor"))
rgbfb_ops.fb_cursor = no_cursor;
info->node = -1;
info->flags = FBINFO_FLAG_DEFAULT;
info->fbops = &rgbfb_ops;
info->fix = rgbfb_fix;
info->var = rgbfb_var;
info->screen_size = rgbfb_fix.smem_len;
info->pseudo_palette = info->par;
info->par = NULL;
ret = fb_alloc_cmap(&info->cmap, 256, 0);
if (ret < 0)
goto err1;
ret = register_framebuffer(info);
if (ret < 0)
goto err2;
platform_set_drvdata(pdev, info);
return 0;
err2:
fb_dealloc_cmap(&info->cmap);
err1:
pnx4008_free_dum_channel(channel_owned, pdev->id);
err0:
framebuffer_release(info);
err:
return ret;
}
static struct platform_driver rgbfb_driver = {
.driver = {
.name = "pnx4008-rgbfb",
},
.probe = rgbfb_probe,
.remove = rgbfb_remove,
};
module_platform_driver(rgbfb_driver);
MODULE_LICENSE("GPL");

View file

@ -1,861 +0,0 @@
/*
* drivers/video/pnx4008/sdum.c
*
* Display Update Master support
*
* Authors: Grigory Tolstolytkin <gtolstolytkin@ru.mvista.com>
* Vitaly Wool <vitalywool@gmail.com>
* Based on Philips Semiconductors's code
*
* Copyrght (c) 2005-2006 MontaVista Software, Inc.
* Copyright (c) 2005 Philips Semiconductors
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/clk.h>
#include <linux/gfp.h>
#include <asm/uaccess.h>
#include <asm/gpio.h>
#include "sdum.h"
#include "fbcommon.h"
#include "dum.h"
/* Framebuffers we have */
static struct pnx4008_fb_addr {
int fb_type;
long addr_offset;
long fb_length;
} fb_addr[] = {
[0] = {
FB_TYPE_YUV, 0, 0xB0000
},
[1] = {
FB_TYPE_RGB, 0xB0000, 0x50000
},
};
static struct dum_data {
u32 lcd_phys_start;
u32 lcd_virt_start;
u32 slave_phys_base;
u32 *slave_virt_base;
int fb_owning_channel[MAX_DUM_CHANNELS];
struct dumchannel_uf chan_uf_store[MAX_DUM_CHANNELS];
} dum_data;
/* Different local helper functions */
static u32 nof_pixels_dx(struct dum_ch_setup *ch_setup)
{
return (ch_setup->xmax - ch_setup->xmin + 1);
}
static u32 nof_pixels_dy(struct dum_ch_setup *ch_setup)
{
return (ch_setup->ymax - ch_setup->ymin + 1);
}
static u32 nof_pixels_dxy(struct dum_ch_setup *ch_setup)
{
return (nof_pixels_dx(ch_setup) * nof_pixels_dy(ch_setup));
}
static u32 nof_bytes(struct dum_ch_setup *ch_setup)
{
u32 r = nof_pixels_dxy(ch_setup);
switch (ch_setup->format) {
case RGB888:
case RGB666:
r *= 4;
break;
default:
r *= 2;
break;
}
return r;
}
static u32 build_command(int disp_no, u32 reg, u32 val)
{
return ((disp_no << 26) | BIT(25) | (val << 16) | (disp_no << 10) |
(reg << 0));
}
static u32 build_double_index(int disp_no, u32 val)
{
return ((disp_no << 26) | (val << 16) | (disp_no << 10) | (val << 0));
}
static void build_disp_window(struct dum_ch_setup * ch_setup, struct disp_window * dw)
{
dw->ymin = ch_setup->ymin;
dw->ymax = ch_setup->ymax;
dw->xmin_l = ch_setup->xmin & 0xFF;
dw->xmin_h = (ch_setup->xmin & BIT(8)) >> 8;
dw->xmax_l = ch_setup->xmax & 0xFF;
dw->xmax_h = (ch_setup->xmax & BIT(8)) >> 8;
}
static int put_channel(struct dumchannel chan)
{
int i = chan.channelnr;
if (i < 0 || i > MAX_DUM_CHANNELS)
return -EINVAL;
else {
DUM_CH_MIN(i) = chan.dum_ch_min;
DUM_CH_MAX(i) = chan.dum_ch_max;
DUM_CH_CONF(i) = chan.dum_ch_conf;
DUM_CH_CTRL(i) = chan.dum_ch_ctrl;
}
return 0;
}
static void clear_channel(int channr)
{
struct dumchannel chan;
chan.channelnr = channr;
chan.dum_ch_min = 0;
chan.dum_ch_max = 0;
chan.dum_ch_conf = 0;
chan.dum_ch_ctrl = 0;
put_channel(chan);
}
static int put_cmd_string(struct cmdstring cmds)
{
u16 *cmd_str_virtaddr;
u32 *cmd_ptr0_virtaddr;
u32 cmd_str_physaddr;
int i = cmds.channelnr;
if (i < 0 || i > MAX_DUM_CHANNELS)
return -EINVAL;
else if ((cmd_ptr0_virtaddr =
(int *)ioremap_nocache(DUM_COM_BASE,
sizeof(int) * MAX_DUM_CHANNELS)) ==
NULL)
return -EIOREMAPFAILED;
else {
cmd_str_physaddr = ioread32(&cmd_ptr0_virtaddr[cmds.channelnr]);
if ((cmd_str_virtaddr =
(u16 *) ioremap_nocache(cmd_str_physaddr,
sizeof(cmds))) == NULL) {
iounmap(cmd_ptr0_virtaddr);
return -EIOREMAPFAILED;
} else {
int t;
for (t = 0; t < 8; t++)
iowrite16(*((u16 *)&cmds.prestringlen + t),
cmd_str_virtaddr + t);
for (t = 0; t < cmds.prestringlen / 2; t++)
iowrite16(*((u16 *)&cmds.precmd + t),
cmd_str_virtaddr + t + 8);
for (t = 0; t < cmds.poststringlen / 2; t++)
iowrite16(*((u16 *)&cmds.postcmd + t),
cmd_str_virtaddr + t + 8 +
cmds.prestringlen / 2);
iounmap(cmd_ptr0_virtaddr);
iounmap(cmd_str_virtaddr);
}
}
return 0;
}
static u32 dum_ch_setup(int ch_no, struct dum_ch_setup * ch_setup)
{
struct cmdstring cmds_c;
struct cmdstring *cmds = &cmds_c;
struct disp_window dw;
int standard;
u32 orientation = 0;
struct dumchannel chan = { 0 };
int ret;
if ((ch_setup->xmirror) || (ch_setup->ymirror) || (ch_setup->rotate)) {
standard = 0;
orientation = BIT(1); /* always set 9-bit-bus */
if (ch_setup->xmirror)
orientation |= BIT(4);
if (ch_setup->ymirror)
orientation |= BIT(3);
if (ch_setup->rotate)
orientation |= BIT(0);
} else
standard = 1;
cmds->channelnr = ch_no;
/* build command string header */
if (standard) {
cmds->prestringlen = 32;
cmds->poststringlen = 0;
} else {
cmds->prestringlen = 48;
cmds->poststringlen = 16;
}
cmds->format =
(u16) ((ch_setup->disp_no << 4) | (BIT(3)) | (ch_setup->format));
cmds->reserved = 0x0;
cmds->startaddr_low = (ch_setup->minadr & 0xFFFF);
cmds->startaddr_high = (ch_setup->minadr >> 16);
if ((ch_setup->minadr == 0) && (ch_setup->maxadr == 0)
&& (ch_setup->xmin == 0)
&& (ch_setup->ymin == 0) && (ch_setup->xmax == 0)
&& (ch_setup->ymax == 0)) {
cmds->pixdatlen_low = 0;
cmds->pixdatlen_high = 0;
} else {
u32 nbytes = nof_bytes(ch_setup);
cmds->pixdatlen_low = (nbytes & 0xFFFF);
cmds->pixdatlen_high = (nbytes >> 16);
}
if (ch_setup->slave_trans)
cmds->pixdatlen_high |= BIT(15);
/* build pre-string */
build_disp_window(ch_setup, &dw);
if (standard) {
cmds->precmd[0] =
build_command(ch_setup->disp_no, DISP_XMIN_L_REG, 0x99);
cmds->precmd[1] =
build_command(ch_setup->disp_no, DISP_XMIN_L_REG,
dw.xmin_l);
cmds->precmd[2] =
build_command(ch_setup->disp_no, DISP_XMIN_H_REG,
dw.xmin_h);
cmds->precmd[3] =
build_command(ch_setup->disp_no, DISP_YMIN_REG, dw.ymin);
cmds->precmd[4] =
build_command(ch_setup->disp_no, DISP_XMAX_L_REG,
dw.xmax_l);
cmds->precmd[5] =
build_command(ch_setup->disp_no, DISP_XMAX_H_REG,
dw.xmax_h);
cmds->precmd[6] =
build_command(ch_setup->disp_no, DISP_YMAX_REG, dw.ymax);
cmds->precmd[7] =
build_double_index(ch_setup->disp_no, DISP_PIXEL_REG);
} else {
if (dw.xmin_l == ch_no)
cmds->precmd[0] =
build_command(ch_setup->disp_no, DISP_XMIN_L_REG,
0x99);
else
cmds->precmd[0] =
build_command(ch_setup->disp_no, DISP_XMIN_L_REG,
ch_no);
cmds->precmd[1] =
build_command(ch_setup->disp_no, DISP_XMIN_L_REG,
dw.xmin_l);
cmds->precmd[2] =
build_command(ch_setup->disp_no, DISP_XMIN_H_REG,
dw.xmin_h);
cmds->precmd[3] =
build_command(ch_setup->disp_no, DISP_YMIN_REG, dw.ymin);
cmds->precmd[4] =
build_command(ch_setup->disp_no, DISP_XMAX_L_REG,
dw.xmax_l);
cmds->precmd[5] =
build_command(ch_setup->disp_no, DISP_XMAX_H_REG,
dw.xmax_h);
cmds->precmd[6] =
build_command(ch_setup->disp_no, DISP_YMAX_REG, dw.ymax);
cmds->precmd[7] =
build_command(ch_setup->disp_no, DISP_1_REG, orientation);
cmds->precmd[8] =
build_double_index(ch_setup->disp_no, DISP_PIXEL_REG);
cmds->precmd[9] =
build_double_index(ch_setup->disp_no, DISP_PIXEL_REG);
cmds->precmd[0xA] =
build_double_index(ch_setup->disp_no, DISP_PIXEL_REG);
cmds->precmd[0xB] =
build_double_index(ch_setup->disp_no, DISP_PIXEL_REG);
cmds->postcmd[0] =
build_command(ch_setup->disp_no, DISP_1_REG, BIT(1));
cmds->postcmd[1] =
build_command(ch_setup->disp_no, DISP_DUMMY1_REG, 1);
cmds->postcmd[2] =
build_command(ch_setup->disp_no, DISP_DUMMY1_REG, 2);
cmds->postcmd[3] =
build_command(ch_setup->disp_no, DISP_DUMMY1_REG, 3);
}
if ((ret = put_cmd_string(cmds_c)) != 0) {
return ret;
}
chan.channelnr = cmds->channelnr;
chan.dum_ch_min = ch_setup->dirtybuffer + ch_setup->minadr;
chan.dum_ch_max = ch_setup->dirtybuffer + ch_setup->maxadr;
chan.dum_ch_conf = 0x002;
chan.dum_ch_ctrl = 0x04;
put_channel(chan);
return 0;
}
static u32 display_open(int ch_no, int auto_update, u32 * dirty_buffer,
u32 * frame_buffer, u32 xpos, u32 ypos, u32 w, u32 h)
{
struct dum_ch_setup k;
int ret;
/* keep width & height within display area */
if ((xpos + w) > DISP_MAX_X_SIZE)
w = DISP_MAX_X_SIZE - xpos;
if ((ypos + h) > DISP_MAX_Y_SIZE)
h = DISP_MAX_Y_SIZE - ypos;
/* assume 1 display only */
k.disp_no = 0;
k.xmin = xpos;
k.ymin = ypos;
k.xmax = xpos + (w - 1);
k.ymax = ypos + (h - 1);
/* adjust min and max values if necessary */
if (k.xmin > DISP_MAX_X_SIZE - 1)
k.xmin = DISP_MAX_X_SIZE - 1;
if (k.ymin > DISP_MAX_Y_SIZE - 1)
k.ymin = DISP_MAX_Y_SIZE - 1;
if (k.xmax > DISP_MAX_X_SIZE - 1)
k.xmax = DISP_MAX_X_SIZE - 1;
if (k.ymax > DISP_MAX_Y_SIZE - 1)
k.ymax = DISP_MAX_Y_SIZE - 1;
k.xmirror = 0;
k.ymirror = 0;
k.rotate = 0;
k.minadr = (u32) frame_buffer;
k.maxadr = (u32) frame_buffer + (((w - 1) << 10) | ((h << 2) - 2));
k.pad = PAD_1024;
k.dirtybuffer = (u32) dirty_buffer;
k.format = RGB888;
k.hwdirty = 0;
k.slave_trans = 0;
ret = dum_ch_setup(ch_no, &k);
return ret;
}
static void lcd_reset(void)
{
u32 *dum_pio_base = (u32 *)IO_ADDRESS(PNX4008_PIO_BASE);
udelay(1);
iowrite32(BIT(19), &dum_pio_base[2]);
udelay(1);
iowrite32(BIT(19), &dum_pio_base[1]);
udelay(1);
}
static int dum_init(struct platform_device *pdev)
{
struct clk *clk;
/* enable DUM clock */
clk = clk_get(&pdev->dev, "dum_ck");
if (IS_ERR(clk)) {
printk(KERN_ERR "pnx4008_dum: Unable to access DUM clock\n");
return PTR_ERR(clk);
}
clk_set_rate(clk, 1);
clk_put(clk);
DUM_CTRL = V_DUM_RESET;
/* set priority to "round-robin". All other params to "false" */
DUM_CONF = BIT(9);
/* Display 1 */
DUM_WTCFG1 = PNX4008_DUM_WT_CFG;
DUM_RTCFG1 = PNX4008_DUM_RT_CFG;
DUM_TCFG = PNX4008_DUM_T_CFG;
return 0;
}
static void dum_chan_init(void)
{
int i = 0, ch = 0;
u32 *cmdptrs;
u32 *cmdstrings;
DUM_COM_BASE =
CMDSTRING_BASEADDR + BYTES_PER_CMDSTRING * NR_OF_CMDSTRINGS;
if ((cmdptrs =
(u32 *) ioremap_nocache(DUM_COM_BASE,
sizeof(u32) * NR_OF_CMDSTRINGS)) == NULL)
return;
for (ch = 0; ch < NR_OF_CMDSTRINGS; ch++)
iowrite32(CMDSTRING_BASEADDR + BYTES_PER_CMDSTRING * ch,
cmdptrs + ch);
for (ch = 0; ch < MAX_DUM_CHANNELS; ch++)
clear_channel(ch);
/* Clear the cmdstrings */
cmdstrings =
(u32 *)ioremap_nocache(*cmdptrs,
BYTES_PER_CMDSTRING * NR_OF_CMDSTRINGS);
if (!cmdstrings)
goto out;
for (i = 0; i < NR_OF_CMDSTRINGS * BYTES_PER_CMDSTRING / sizeof(u32);
i++)
iowrite32(0, cmdstrings + i);
iounmap((u32 *)cmdstrings);
out:
iounmap((u32 *)cmdptrs);
}
static void lcd_init(void)
{
lcd_reset();
DUM_OUTP_FORMAT1 = 0; /* RGB666 */
udelay(1);
iowrite32(V_LCD_STANDBY_OFF, dum_data.slave_virt_base);
udelay(1);
iowrite32(V_LCD_USE_9BIT_BUS, dum_data.slave_virt_base);
udelay(1);
iowrite32(V_LCD_SYNC_RISE_L, dum_data.slave_virt_base);
udelay(1);
iowrite32(V_LCD_SYNC_RISE_H, dum_data.slave_virt_base);
udelay(1);
iowrite32(V_LCD_SYNC_FALL_L, dum_data.slave_virt_base);
udelay(1);
iowrite32(V_LCD_SYNC_FALL_H, dum_data.slave_virt_base);
udelay(1);
iowrite32(V_LCD_SYNC_ENABLE, dum_data.slave_virt_base);
udelay(1);
iowrite32(V_LCD_DISPLAY_ON, dum_data.slave_virt_base);
udelay(1);
}
/* Interface exported to framebuffer drivers */
int pnx4008_get_fb_addresses(int fb_type, void **virt_addr,
dma_addr_t *phys_addr, int *fb_length)
{
int i;
int ret = -1;
for (i = 0; i < ARRAY_SIZE(fb_addr); i++)
if (fb_addr[i].fb_type == fb_type) {
*virt_addr = (void *)(dum_data.lcd_virt_start +
fb_addr[i].addr_offset);
*phys_addr =
dum_data.lcd_phys_start + fb_addr[i].addr_offset;
*fb_length = fb_addr[i].fb_length;
ret = 0;
break;
}
return ret;
}
EXPORT_SYMBOL(pnx4008_get_fb_addresses);
int pnx4008_alloc_dum_channel(int dev_id)
{
int i = 0;
while ((i < MAX_DUM_CHANNELS) && (dum_data.fb_owning_channel[i] != -1))
i++;
if (i == MAX_DUM_CHANNELS)
return -ENORESOURCESLEFT;
else {
dum_data.fb_owning_channel[i] = dev_id;
return i;
}
}
EXPORT_SYMBOL(pnx4008_alloc_dum_channel);
int pnx4008_free_dum_channel(int channr, int dev_id)
{
if (channr < 0 || channr > MAX_DUM_CHANNELS)
return -EINVAL;
else if (dum_data.fb_owning_channel[channr] != dev_id)
return -EFBNOTOWNER;
else {
clear_channel(channr);
dum_data.fb_owning_channel[channr] = -1;
}
return 0;
}
EXPORT_SYMBOL(pnx4008_free_dum_channel);
int pnx4008_put_dum_channel_uf(struct dumchannel_uf chan_uf, int dev_id)
{
int i = chan_uf.channelnr;
int ret;
if (i < 0 || i > MAX_DUM_CHANNELS)
return -EINVAL;
else if (dum_data.fb_owning_channel[i] != dev_id)
return -EFBNOTOWNER;
else if ((ret =
display_open(chan_uf.channelnr, 0, chan_uf.dirty,
chan_uf.source, chan_uf.y_offset,
chan_uf.x_offset, chan_uf.height,
chan_uf.width)) != 0)
return ret;
else {
dum_data.chan_uf_store[i].dirty = chan_uf.dirty;
dum_data.chan_uf_store[i].source = chan_uf.source;
dum_data.chan_uf_store[i].x_offset = chan_uf.x_offset;
dum_data.chan_uf_store[i].y_offset = chan_uf.y_offset;
dum_data.chan_uf_store[i].width = chan_uf.width;
dum_data.chan_uf_store[i].height = chan_uf.height;
}
return 0;
}
EXPORT_SYMBOL(pnx4008_put_dum_channel_uf);
int pnx4008_set_dum_channel_sync(int channr, int val, int dev_id)
{
if (channr < 0 || channr > MAX_DUM_CHANNELS)
return -EINVAL;
else if (dum_data.fb_owning_channel[channr] != dev_id)
return -EFBNOTOWNER;
else {
if (val == CONF_SYNC_ON) {
DUM_CH_CONF(channr) |= CONF_SYNCENABLE;
DUM_CH_CONF(channr) |= DUM_CHANNEL_CFG_SYNC_MASK |
DUM_CHANNEL_CFG_SYNC_MASK_SET;
} else if (val == CONF_SYNC_OFF)
DUM_CH_CONF(channr) &= ~CONF_SYNCENABLE;
else
return -EINVAL;
}
return 0;
}
EXPORT_SYMBOL(pnx4008_set_dum_channel_sync);
int pnx4008_set_dum_channel_dirty_detect(int channr, int val, int dev_id)
{
if (channr < 0 || channr > MAX_DUM_CHANNELS)
return -EINVAL;
else if (dum_data.fb_owning_channel[channr] != dev_id)
return -EFBNOTOWNER;
else {
if (val == CONF_DIRTYDETECTION_ON)
DUM_CH_CONF(channr) |= CONF_DIRTYENABLE;
else if (val == CONF_DIRTYDETECTION_OFF)
DUM_CH_CONF(channr) &= ~CONF_DIRTYENABLE;
else
return -EINVAL;
}
return 0;
}
EXPORT_SYMBOL(pnx4008_set_dum_channel_dirty_detect);
#if 0 /* Functions not used currently, but likely to be used in future */
static int get_channel(struct dumchannel *p_chan)
{
int i = p_chan->channelnr;
if (i < 0 || i > MAX_DUM_CHANNELS)
return -EINVAL;
else {
p_chan->dum_ch_min = DUM_CH_MIN(i);
p_chan->dum_ch_max = DUM_CH_MAX(i);
p_chan->dum_ch_conf = DUM_CH_CONF(i);
p_chan->dum_ch_stat = DUM_CH_STAT(i);
p_chan->dum_ch_ctrl = 0; /* WriteOnly control register */
}
return 0;
}
int pnx4008_get_dum_channel_uf(struct dumchannel_uf *p_chan_uf, int dev_id)
{
int i = p_chan_uf->channelnr;
if (i < 0 || i > MAX_DUM_CHANNELS)
return -EINVAL;
else if (dum_data.fb_owning_channel[i] != dev_id)
return -EFBNOTOWNER;
else {
p_chan_uf->dirty = dum_data.chan_uf_store[i].dirty;
p_chan_uf->source = dum_data.chan_uf_store[i].source;
p_chan_uf->x_offset = dum_data.chan_uf_store[i].x_offset;
p_chan_uf->y_offset = dum_data.chan_uf_store[i].y_offset;
p_chan_uf->width = dum_data.chan_uf_store[i].width;
p_chan_uf->height = dum_data.chan_uf_store[i].height;
}
return 0;
}
EXPORT_SYMBOL(pnx4008_get_dum_channel_uf);
int pnx4008_get_dum_channel_config(int channr, int dev_id)
{
int ret;
struct dumchannel chan;
if (channr < 0 || channr > MAX_DUM_CHANNELS)
return -EINVAL;
else if (dum_data.fb_owning_channel[channr] != dev_id)
return -EFBNOTOWNER;
else {
chan.channelnr = channr;
if ((ret = get_channel(&chan)) != 0)
return ret;
}
return (chan.dum_ch_conf & DUM_CHANNEL_CFG_MASK);
}
EXPORT_SYMBOL(pnx4008_get_dum_channel_config);
int pnx4008_force_update_dum_channel(int channr, int dev_id)
{
if (channr < 0 || channr > MAX_DUM_CHANNELS)
return -EINVAL;
else if (dum_data.fb_owning_channel[channr] != dev_id)
return -EFBNOTOWNER;
else
DUM_CH_CTRL(channr) = CTRL_SETDIRTY;
return 0;
}
EXPORT_SYMBOL(pnx4008_force_update_dum_channel);
#endif
int pnx4008_sdum_mmap(struct fb_info *info, struct vm_area_struct *vma,
struct device *dev)
{
unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
if (off < info->fix.smem_len) {
vma->vm_pgoff += 1;
return dma_mmap_writecombine(dev, vma,
(void *)dum_data.lcd_virt_start,
dum_data.lcd_phys_start,
FB_DMA_SIZE);
}
return -EINVAL;
}
EXPORT_SYMBOL(pnx4008_sdum_mmap);
int pnx4008_set_dum_exit_notification(int dev_id)
{
int i;
for (i = 0; i < MAX_DUM_CHANNELS; i++)
if (dum_data.fb_owning_channel[i] == dev_id)
return -ERESOURCESNOTFREED;
return 0;
}
EXPORT_SYMBOL(pnx4008_set_dum_exit_notification);
/* Platform device driver for DUM */
static int sdum_suspend(struct platform_device *pdev, pm_message_t state)
{
int retval = 0;
struct clk *clk;
clk = clk_get(0, "dum_ck");
if (!IS_ERR(clk)) {
clk_set_rate(clk, 0);
clk_put(clk);
} else
retval = PTR_ERR(clk);
/* disable BAC */
DUM_CTRL = V_BAC_DISABLE_IDLE;
/* LCD standby & turn off display */
lcd_reset();
return retval;
}
static int sdum_resume(struct platform_device *pdev)
{
int retval = 0;
struct clk *clk;
clk = clk_get(0, "dum_ck");
if (!IS_ERR(clk)) {
clk_set_rate(clk, 1);
clk_put(clk);
} else
retval = PTR_ERR(clk);
/* wait for BAC disable */
DUM_CTRL = V_BAC_DISABLE_TRIG;
while (DUM_CTRL & BAC_ENABLED)
udelay(10);
/* re-init LCD */
lcd_init();
/* enable BAC and reset MUX */
DUM_CTRL = V_BAC_ENABLE;
udelay(1);
DUM_CTRL = V_MUX_RESET;
return 0;
}
static int __devinit sdum_probe(struct platform_device *pdev)
{
int ret = 0, i = 0;
/* map frame buffer */
dum_data.lcd_virt_start = (u32) dma_alloc_writecombine(&pdev->dev,
FB_DMA_SIZE,
&dum_data.lcd_phys_start,
GFP_KERNEL);
if (!dum_data.lcd_virt_start) {
ret = -ENOMEM;
goto out_3;
}
/* map slave registers */
dum_data.slave_phys_base = PNX4008_DUM_SLAVE_BASE;
dum_data.slave_virt_base =
(u32 *) ioremap_nocache(dum_data.slave_phys_base, sizeof(u32));
if (dum_data.slave_virt_base == NULL) {
ret = -ENOMEM;
goto out_2;
}
/* initialize DUM and LCD display */
ret = dum_init(pdev);
if (ret)
goto out_1;
dum_chan_init();
lcd_init();
DUM_CTRL = V_BAC_ENABLE;
udelay(1);
DUM_CTRL = V_MUX_RESET;
/* set decode address and sync clock divider */
DUM_DECODE = dum_data.lcd_phys_start & DUM_DECODE_MASK;
DUM_CLK_DIV = PNX4008_DUM_CLK_DIV;
for (i = 0; i < MAX_DUM_CHANNELS; i++)
dum_data.fb_owning_channel[i] = -1;
/*setup wakeup interrupt */
start_int_set_rising_edge(SE_DISP_SYNC_INT);
start_int_ack(SE_DISP_SYNC_INT);
start_int_umask(SE_DISP_SYNC_INT);
return 0;
out_1:
iounmap((void *)dum_data.slave_virt_base);
out_2:
dma_free_writecombine(&pdev->dev, FB_DMA_SIZE,
(void *)dum_data.lcd_virt_start,
dum_data.lcd_phys_start);
out_3:
return ret;
}
static int sdum_remove(struct platform_device *pdev)
{
struct clk *clk;
start_int_mask(SE_DISP_SYNC_INT);
clk = clk_get(0, "dum_ck");
if (!IS_ERR(clk)) {
clk_set_rate(clk, 0);
clk_put(clk);
}
iounmap((void *)dum_data.slave_virt_base);
dma_free_writecombine(&pdev->dev, FB_DMA_SIZE,
(void *)dum_data.lcd_virt_start,
dum_data.lcd_phys_start);
return 0;
}
static struct platform_driver sdum_driver = {
.driver = {
.name = "pnx4008-sdum",
},
.probe = sdum_probe,
.remove = sdum_remove,
.suspend = sdum_suspend,
.resume = sdum_resume,
};
module_platform_driver(sdum_driver);
MODULE_LICENSE("GPL");

View file

@ -1,136 +0,0 @@
/*
* Copyright (C) 2005 Philips Semiconductors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA, or http://www.gnu.org/licenses/gpl.html
*/
#define MAX_DUM_CHANNELS 64
#define RGB_MEM_WINDOW(x) (0x10000000 + (x)*0x00100000)
#define QCIF_OFFSET(x) (((x) == 0) ? 0x00000: ((x) == 1) ? 0x30000: -1)
#define CIF_OFFSET(x) (((x) == 0) ? 0x00000: ((x) == 1) ? 0x60000: -1)
#define CTRL_SETDIRTY (0x00000001)
#define CONF_DIRTYENABLE (0x00000020)
#define CONF_SYNCENABLE (0x00000004)
#define DIRTY_ENABLED(conf) ((conf) & 0x0020)
#define SYNC_ENABLED(conf) ((conf) & 0x0004)
/* Display 1 & 2 Write Timing Configuration */
#define PNX4008_DUM_WT_CFG 0x00372000
/* Display 1 & 2 Read Timing Configuration */
#define PNX4008_DUM_RT_CFG 0x00003A47
/* DUM Transit State Timing Configuration */
#define PNX4008_DUM_T_CFG 0x1D /* 29 HCLK cycles */
/* DUM Sync count clock divider */
#define PNX4008_DUM_CLK_DIV 0x02DD
/* Memory size for framebuffer, allocated through dma_alloc_writecombine().
* Must be PAGE aligned
*/
#define FB_DMA_SIZE (PAGE_ALIGN(SZ_1M + PAGE_SIZE))
#define OFFSET_RGBBUFFER (0xB0000)
#define OFFSET_YUVBUFFER (0x00000)
#define YUVBUFFER (lcd_video_start + OFFSET_YUVBUFFER)
#define RGBBUFFER (lcd_video_start + OFFSET_RGBBUFFER)
#define CMDSTRING_BASEADDR (0x00C000) /* iram */
#define BYTES_PER_CMDSTRING (0x80)
#define NR_OF_CMDSTRINGS (64)
#define MAX_NR_PRESTRINGS (0x40)
#define MAX_NR_POSTSTRINGS (0x40)
/* various mask definitions */
#define DUM_CLK_ENABLE 0x01
#define DUM_CLK_DISABLE 0
#define DUM_DECODE_MASK 0x1FFFFFFF
#define DUM_CHANNEL_CFG_MASK 0x01FF
#define DUM_CHANNEL_CFG_SYNC_MASK 0xFFFE00FF
#define DUM_CHANNEL_CFG_SYNC_MASK_SET 0x0CA00
#define SDUM_RETURNVAL_BASE (0x500)
#define CONF_SYNC_OFF (0x602)
#define CONF_SYNC_ON (0x603)
#define CONF_DIRTYDETECTION_OFF (0x600)
#define CONF_DIRTYDETECTION_ON (0x601)
struct dumchannel_uf {
int channelnr;
u32 *dirty;
u32 *source;
u32 x_offset;
u32 y_offset;
u32 width;
u32 height;
};
enum {
FB_TYPE_YUV,
FB_TYPE_RGB
};
struct cmdstring {
int channelnr;
uint16_t prestringlen;
uint16_t poststringlen;
uint16_t format;
uint16_t reserved;
uint16_t startaddr_low;
uint16_t startaddr_high;
uint16_t pixdatlen_low;
uint16_t pixdatlen_high;
u32 precmd[MAX_NR_PRESTRINGS];
u32 postcmd[MAX_NR_POSTSTRINGS];
};
struct dumchannel {
int channelnr;
int dum_ch_min;
int dum_ch_max;
int dum_ch_conf;
int dum_ch_stat;
int dum_ch_ctrl;
};
int pnx4008_alloc_dum_channel(int dev_id);
int pnx4008_free_dum_channel(int channr, int dev_id);
int pnx4008_get_dum_channel_uf(struct dumchannel_uf *pChan_uf, int dev_id);
int pnx4008_put_dum_channel_uf(struct dumchannel_uf chan_uf, int dev_id);
int pnx4008_set_dum_channel_sync(int channr, int val, int dev_id);
int pnx4008_set_dum_channel_dirty_detect(int channr, int val, int dev_id);
int pnx4008_force_dum_update_channel(int channr, int dev_id);
int pnx4008_get_dum_channel_config(int channr, int dev_id);
int pnx4008_sdum_mmap(struct fb_info *info, struct vm_area_struct *vma, struct device *dev);
int pnx4008_set_dum_exit_notification(int dev_id);
int pnx4008_get_fb_addresses(int fb_type, void **virt_addr,
dma_addr_t * phys_addr, int *fb_length);

View file

@ -1034,6 +1034,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
if (status) {
dev_err(&dev->core, "%s: lv1_gpu_memory_allocate failed: %d\n",
__func__, status);
retval = -ENOMEM;
goto err_close_device;
}
dev_dbg(&dev->core, "ddr:lpar:0x%llx\n", ddr_lpar);
@ -1046,6 +1047,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
dev_err(&dev->core,
"%s: lv1_gpu_context_allocate failed: %d\n", __func__,
status);
retval = -ENOMEM;
goto err_gpu_memory_free;
}
@ -1053,6 +1055,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024);
if (!dinfo) {
dev_err(&dev->core, "%s: ioremap failed\n", __func__);
retval = -ENOMEM;
goto err_gpu_context_free;
}
@ -1121,8 +1124,10 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
}
info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core);
if (!info)
if (!info) {
retval = -ENOMEM;
goto err_context_fb_close;
}
par = info->par;
par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */

View file

@ -25,8 +25,8 @@
#include <linux/interrupt.h>
#include <linux/pm_runtime.h>
#include <video/samsung_fimd.h>
#include <mach/map.h>
#include <plat/regs-fb-v4.h>
#include <plat/fb.h>
/* This driver will export a number of framebuffer interfaces depending
@ -1398,35 +1398,28 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
spin_lock_init(&sfb->slock);
sfb->bus_clk = clk_get(dev, "lcd");
sfb->bus_clk = devm_clk_get(dev, "lcd");
if (IS_ERR(sfb->bus_clk)) {
dev_err(dev, "failed to get bus clock\n");
ret = PTR_ERR(sfb->bus_clk);
goto err_sfb;
return PTR_ERR(sfb->bus_clk);
}
clk_enable(sfb->bus_clk);
clk_prepare_enable(sfb->bus_clk);
if (!sfb->variant.has_clksel) {
sfb->lcd_clk = clk_get(dev, "sclk_fimd");
sfb->lcd_clk = devm_clk_get(dev, "sclk_fimd");
if (IS_ERR(sfb->lcd_clk)) {
dev_err(dev, "failed to get lcd clock\n");
ret = PTR_ERR(sfb->lcd_clk);
goto err_bus_clk;
}
clk_enable(sfb->lcd_clk);
clk_prepare_enable(sfb->lcd_clk);
}
pm_runtime_enable(sfb->dev);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "failed to find registers\n");
ret = -ENOENT;
goto err_lcd_clk;
}
sfb->regs = devm_request_and_ioremap(dev, res);
if (!sfb->regs) {
dev_err(dev, "failed to map registers\n");
@ -1510,16 +1503,12 @@ err_pm_runtime:
err_lcd_clk:
pm_runtime_disable(sfb->dev);
if (!sfb->variant.has_clksel) {
clk_disable(sfb->lcd_clk);
clk_put(sfb->lcd_clk);
}
if (!sfb->variant.has_clksel)
clk_disable_unprepare(sfb->lcd_clk);
err_bus_clk:
clk_disable(sfb->bus_clk);
clk_put(sfb->bus_clk);
clk_disable_unprepare(sfb->bus_clk);
err_sfb:
return ret;
}
@ -1541,13 +1530,10 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev)
if (sfb->windows[win])
s3c_fb_release_win(sfb, sfb->windows[win]);
if (!sfb->variant.has_clksel) {
clk_disable(sfb->lcd_clk);
clk_put(sfb->lcd_clk);
}
if (!sfb->variant.has_clksel)
clk_disable_unprepare(sfb->lcd_clk);
clk_disable(sfb->bus_clk);
clk_put(sfb->bus_clk);
clk_disable_unprepare(sfb->bus_clk);
pm_runtime_put_sync(sfb->dev);
pm_runtime_disable(sfb->dev);
@ -1575,9 +1561,9 @@ static int s3c_fb_suspend(struct device *dev)
}
if (!sfb->variant.has_clksel)
clk_disable(sfb->lcd_clk);
clk_disable_unprepare(sfb->lcd_clk);
clk_disable(sfb->bus_clk);
clk_disable_unprepare(sfb->bus_clk);
pm_runtime_put_sync(sfb->dev);
@ -1595,10 +1581,10 @@ static int s3c_fb_resume(struct device *dev)
pm_runtime_get_sync(sfb->dev);
clk_enable(sfb->bus_clk);
clk_prepare_enable(sfb->bus_clk);
if (!sfb->variant.has_clksel)
clk_enable(sfb->lcd_clk);
clk_prepare_enable(sfb->lcd_clk);
/* setup gpio and output polarity controls */
pd->setup_gpio();
@ -1654,9 +1640,9 @@ static int s3c_fb_runtime_suspend(struct device *dev)
struct s3c_fb *sfb = platform_get_drvdata(pdev);
if (!sfb->variant.has_clksel)
clk_disable(sfb->lcd_clk);
clk_disable_unprepare(sfb->lcd_clk);
clk_disable(sfb->bus_clk);
clk_disable_unprepare(sfb->bus_clk);
return 0;
}
@ -1667,10 +1653,10 @@ static int s3c_fb_runtime_resume(struct device *dev)
struct s3c_fb *sfb = platform_get_drvdata(pdev);
struct s3c_fb_platdata *pd = sfb->pdata;
clk_enable(sfb->bus_clk);
clk_prepare_enable(sfb->bus_clk);
if (!sfb->variant.has_clksel)
clk_enable(sfb->lcd_clk);
clk_prepare_enable(sfb->lcd_clk);
/* setup gpio and output polarity controls */
pd->setup_gpio();

View file

@ -11,6 +11,8 @@
* Driver based on skeletonfb.c, sa1100fb.c and others.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/err.h>
@ -48,7 +50,11 @@ static int debug = 1;
static int debug;
#endif
#define dprintk(msg...) if (debug) printk(KERN_DEBUG "s3c2410fb: " msg);
#define dprintk(msg...) \
do { \
if (debug) \
pr_debug(msg); \
} while (0)
/* useful functions */
@ -598,11 +604,11 @@ static int s3c2410fb_debug_store(struct device *dev,
if (strnicmp(buf, "on", 2) == 0 ||
strnicmp(buf, "1", 1) == 0) {
debug = 1;
printk(KERN_DEBUG "s3c2410fb: Debug On");
dev_dbg(dev, "s3c2410fb: Debug On");
} else if (strnicmp(buf, "off", 3) == 0 ||
strnicmp(buf, "0", 1) == 0) {
debug = 0;
printk(KERN_DEBUG "s3c2410fb: Debug Off");
dev_dbg(dev, "s3c2410fb: Debug Off");
} else {
return -EINVAL;
}
@ -921,7 +927,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
info->clk = clk_get(NULL, "lcd");
if (IS_ERR(info->clk)) {
printk(KERN_ERR "failed to get lcd clock source\n");
dev_err(&pdev->dev, "failed to get lcd clock source\n");
ret = PTR_ERR(info->clk);
goto release_irq;
}
@ -929,7 +935,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
clk_enable(info->clk);
dprintk("got and enabled clock\n");
usleep_range(1000, 1000);
usleep_range(1000, 1100);
info->clk_rate = clk_get_rate(info->clk);
@ -947,7 +953,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
/* Initialize video memory */
ret = s3c2410fb_map_video_memory(fbinfo);
if (ret) {
printk(KERN_ERR "Failed to allocate video RAM: %d\n", ret);
dev_err(&pdev->dev, "Failed to allocate video RAM: %d\n", ret);
ret = -ENOMEM;
goto release_clock;
}
@ -970,7 +976,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
ret = register_framebuffer(fbinfo);
if (ret < 0) {
printk(KERN_ERR "Failed to register framebuffer device: %d\n",
dev_err(&pdev->dev, "Failed to register framebuffer device: %d\n",
ret);
goto free_cpufreq;
}
@ -978,9 +984,9 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
/* create device files */
ret = device_create_file(&pdev->dev, &dev_attr_debug);
if (ret)
printk(KERN_ERR "failed to add debug attribute\n");
dev_err(&pdev->dev, "failed to add debug attribute\n");
printk(KERN_INFO "fb%d: %s frame buffer device\n",
dev_info(&pdev->dev, "fb%d: %s frame buffer device\n",
fbinfo->node, fbinfo->fix.id);
return 0;
@ -1028,7 +1034,7 @@ static int __devexit s3c2410fb_remove(struct platform_device *pdev)
s3c2410fb_cpufreq_deregister(info);
s3c2410fb_lcd_enable(info, 0);
usleep_range(1000, 1000);
usleep_range(1000, 1100);
s3c2410fb_unmap_video_memory(fbinfo);
@ -1065,7 +1071,7 @@ static int s3c2410fb_suspend(struct platform_device *dev, pm_message_t state)
* the LCD DMA engine is not going to get back on the bus
* before the clock goes off again (bjd) */
usleep_range(1000, 1000);
usleep_range(1000, 1100);
clk_disable(info->clk);
return 0;
@ -1077,7 +1083,7 @@ static int s3c2410fb_resume(struct platform_device *dev)
struct s3c2410fb_info *info = fbinfo->par;
clk_enable(info->clk);
usleep_range(1000, 1000);
usleep_range(1000, 1100);
s3c2410fb_init_registers(fbinfo);
@ -1134,8 +1140,8 @@ static void __exit s3c2410fb_cleanup(void)
module_init(s3c2410fb_init);
module_exit(s3c2410fb_cleanup);
MODULE_AUTHOR("Arnaud Patard <[email protected]>, "
"Ben Dooks <[email protected]>");
MODULE_AUTHOR("Arnaud Patard <[email protected]>");
MODULE_AUTHOR("Ben Dooks <[email protected]>");
MODULE_DESCRIPTION("Framebuffer driver for the s3c2410");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:s3c2410-lcd");

View file

@ -2266,8 +2266,10 @@ static int __devinit savagefb_probe(struct pci_dev* dev,
lpitch = info->var.xres_virtual*((info->var.bits_per_pixel + 7) >> 3);
info->var.yres_virtual = info->fix.smem_len/lpitch;
if (info->var.yres_virtual < info->var.yres)
if (info->var.yres_virtual < info->var.yres) {
err = -ENOMEM;
goto failed;
}
#if defined(CONFIG_FB_SAVAGE_ACCEL)
/*

View file

@ -65,7 +65,7 @@ sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr, unsigned char modeno,
}
#endif
if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) {;
if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) {
printk(KERN_ERR "Could not find mode %x\n", ModeNo);
return 65000;
}

View file

@ -141,8 +141,10 @@ static int __devinit gfb_probe(struct platform_device *op)
gp->fb_base = of_ioremap(&op->resource[6], 0,
gp->fb_size, "gfb fb");
if (!gp->fb_base)
if (!gp->fb_base) {
err = -ENOMEM;
goto err_release_fb;
}
err = gfb_set_fbinfo(gp);
if (err)

View file

@ -181,8 +181,10 @@ static int __devinit s3d_pci_register(struct pci_dev *pdev,
sp->fb_size = info->fix.line_length * sp->height;
sp->fb_base = ioremap(sp->fb_base_phys, sp->fb_size);
if (!sp->fb_base)
if (!sp->fb_base) {
err = -ENOMEM;
goto err_release_pci;
}
err = s3d_set_fbinfo(sp);
if (err)

View file

@ -298,8 +298,10 @@ static int __devinit e3d_pci_register(struct pci_dev *pdev,
goto err_release_fb;
}
ep->ramdac = ioremap(ep->regs_base_phys + 0x8000, 0x1000);
if (!ep->ramdac)
if (!ep->ramdac) {
err = -ENOMEM;
goto err_release_pci1;
}
ep->fb8_0_off = readl(ep->ramdac + RAMDAC_VID_8FB_0);
ep->fb8_0_off -= ep->fb_base_reg;
@ -343,8 +345,10 @@ static int __devinit e3d_pci_register(struct pci_dev *pdev,
ep->fb_size = info->fix.line_length * ep->height;
ep->fb_base = ioremap(ep->fb_base_phys, ep->fb_size);
if (!ep->fb_base)
if (!ep->fb_base) {
err = -ENOMEM;
goto err_release_pci0;
}
err = e3d_set_fbinfo(ep);
if (err)

View file

@ -646,7 +646,7 @@ static ssize_t dlfb_ops_write(struct fb_info *info, const char __user *buf,
result = fb_sys_write(info, buf, count, ppos);
if (result > 0) {
int start = max((int)(offset / info->fix.line_length) - 1, 0);
int start = max((int)(offset / info->fix.line_length), 0);
int lines = min((u32)((result / info->fix.line_length) + 1),
(u32)info->var.yres);

View file

@ -659,6 +659,8 @@ static int __devinit uvesafb_vbe_getedid(struct uvesafb_ktask *task,
task->t.flags = TF_BUF_RET | TF_BUF_ESDI;
task->t.buf_len = EDID_LENGTH;
task->buf = kzalloc(EDID_LENGTH, GFP_KERNEL);
if (!task->buf)
return -ENOMEM;
err = uvesafb_exec(task);

View file

@ -1167,8 +1167,7 @@ void vmlfb_unregister_subsys(struct vml_sys *sys)
list_for_each_entry_safe(entry, next, &global_has_mode, head) {
printk(KERN_DEBUG MODULE_NAME ": subsys disable pipe\n");
vmlfb_disable_pipe(entry);
list_del(&entry->head);
list_add_tail(&entry->head, &global_no_mode);
list_move_tail(&entry->head, &global_no_mode);
}
mutex_unlock(&vml_mutex);
}

View file

@ -25,6 +25,7 @@
#include <linux/kernel.h>
#include <linux/via-core.h>
#include <asm/olpc.h>
#include "via_clock.h"
#include "global.h"
#include "debug.h"
@ -289,6 +290,10 @@ static void dummy_set_pll(struct via_pll_config config)
printk(KERN_INFO "Using undocumented set PLL.\n%s", via_slap);
}
static void noop_set_clock_state(u8 state)
{
}
void via_clock_init(struct via_clock *clock, int gfx_chip)
{
switch (gfx_chip) {
@ -346,4 +351,18 @@ void via_clock_init(struct via_clock *clock, int gfx_chip)
break;
}
if (machine_is_olpc()) {
/* The OLPC XO-1.5 cannot suspend/resume reliably if the
* IGA1/IGA2 clocks are set as on or off (memory rot
* occasionally happens during suspend under such
* configurations).
*
* The only known stable scenario is to leave this bits as-is,
* which in their default states are documented to enable the
* clock only when it is needed.
*/
clock->set_primary_clock_state = noop_set_clock_state;
clock->set_secondary_clock_state = noop_set_clock_state;
}
}