diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-08-01 10:45:12 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-08-01 10:45:12 -0700 | 
| commit | d4fdc32517efaab0493c134d5cc070c252d51275 (patch) | |
| tree | 7b70d93a65fa1b74f84af835cd941c3f2c55019a | |
| parent | 9a51cf28a3377689edfe190b9590da7d46e8f3fb (diff) | |
| parent | a0239073fd75489d25575cf3aaf71ab55b416020 (diff) | |
Merge tag 'fbdev-updates-for-3.6' of git://github.com/schandinat/linux-2.6
Pull fbdev updates from Florian Tobias Schandinat:
 - large updates for OMAP
   - support for LCD3 overlay manager (omap5)
   - omapdss output cleanup
   - removal of passive matrix LCD support as there are no drivers for
     such panels for DSS or DSS2 and nobody complained (cleanup)
 - large updates for SH Mobile
   - overlay support
   - separating MERAM (cache) from framebuffer driver
 - some updates for Exynos and da8xx-fb
 - various other small patches
* tag 'fbdev-updates-for-3.6' of git://github.com/schandinat/linux-2.6: (78 commits)
  da8xx-fb: fix compile issue due to missing include
  fbdev: Make pixel_to_pat() failure mode more friendly
  da8xx-fb: do not turn ON LCD backlight unless LCDC is enabled
  fbdev: sh_mobile_lcdc: Fix vertical panning step
  video: exynos mipi dsi: Fix mipi dsi regulators handling issue
  video: da8xx-fb: do clock reset of revision 2 LCDC before enabling
  arm: da850: configure LCDC fifo threshold
  video: da8xx-fb: configure FIFO threshold to reduce underflow errors
  video: da8xx-fb: fix flicker due to 1 frame delay in updated frame
  video: da8xx-fb rev2: fix disabling of palette completion interrupt
  da8xx-fb: add missing FB_BLANK operations
  video: exynos_dp: use usleep_range instead of delay
  video: exynos_dp: check the only INTERLANE_ALIGN_DONE bit during Link Training
  fb: epson1355fb: Fix section mismatch
  video: exynos_dp: fix wrong DPCD address during Link Training
  video/smscufx: fix line counting in fb_write
  aty128fb: Fix coding style issues
  fbdev: sh_mobile_lcdc: Fix pan offset computation in YUV mode
  fbdev: sh_mobile_lcdc: Fix overlay registers update during pan operation
  fbdev: sh_mobile_lcdc: Support horizontal panning
  ...
55 files changed, 2609 insertions, 1126 deletions
| diff --git a/Documentation/ABI/testing/sysfs-devices-platform-sh_mobile_lcdc_fb b/Documentation/ABI/testing/sysfs-devices-platform-sh_mobile_lcdc_fb new file mode 100644 index 000000000000..2107082426da --- /dev/null +++ b/Documentation/ABI/testing/sysfs-devices-platform-sh_mobile_lcdc_fb @@ -0,0 +1,44 @@ +What:		/sys/devices/platform/sh_mobile_lcdc_fb.[0-3]/graphics/fb[0-9]/ovl_alpha +Date:		May 2012 +Contact:	Laurent Pinchart <laurent.pinchart@ideasonboard.com> +Description: +		This file is only available on fb[0-9] devices corresponding +		to overlay planes. + +		Stores the alpha blending value for the overlay. Values range +		from 0 (transparent) to 255 (opaque). The value is ignored if +		the mode is not set to Alpha Blending. + +What:		/sys/devices/platform/sh_mobile_lcdc_fb.[0-3]/graphics/fb[0-9]/ovl_mode +Date:		May 2012 +Contact:	Laurent Pinchart <laurent.pinchart@ideasonboard.com> +Description: +		This file is only available on fb[0-9] devices corresponding +		to overlay planes. + +		Selects the composition mode for the overlay. Possible values +		are + +		0 - Alpha Blending +		1 - ROP3 + +What:		/sys/devices/platform/sh_mobile_lcdc_fb.[0-3]/graphics/fb[0-9]/ovl_position +Date:		May 2012 +Contact:	Laurent Pinchart <laurent.pinchart@ideasonboard.com> +Description: +		This file is only available on fb[0-9] devices corresponding +		to overlay planes. + +		Stores the x,y overlay position on the display in pixels. The +		position format is `[0-9]+,[0-9]+'. + +What:		/sys/devices/platform/sh_mobile_lcdc_fb.[0-3]/graphics/fb[0-9]/ovl_rop3 +Date:		May 2012 +Contact:	Laurent Pinchart <laurent.pinchart@ideasonboard.com> +Description: +		This file is only available on fb[0-9] devices corresponding +		to overlay planes. + +		Stores the raster operation (ROP3) for the overlay. Values +		range from 0 to 255. The value is ignored if the mode is not +		set to ROP3. diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c index d1624a315c9a..783eab6845c4 100644 --- a/arch/arm/mach-davinci/devices-da8xx.c +++ b/arch/arm/mach-davinci/devices-da8xx.c @@ -546,6 +546,7 @@ static struct lcd_ctrl_config lcd_cfg = {  	.sync_edge		= 0,  	.sync_ctrl		= 1,  	.raster_order		= 0, +	.fifo_th		= 6,  };  struct da8xx_lcdc_platform_data sharp_lcd035q3dg01_pdata = { diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c index 5fb47a14f4ba..af1ed7d24a1f 100644 --- a/arch/arm/mach-omap2/display.c +++ b/arch/arm/mach-omap2/display.c @@ -37,6 +37,7 @@  #define DISPC_CONTROL		0x0040  #define DISPC_CONTROL2		0x0238 +#define DISPC_CONTROL3		0x0848  #define DISPC_IRQSTATUS		0x0018  #define DSS_SYSCONFIG		0x10 @@ -52,6 +53,7 @@  #define EVSYNC_EVEN_IRQ_SHIFT	2  #define EVSYNC_ODD_IRQ_SHIFT	3  #define FRAMEDONE2_IRQ_SHIFT	22 +#define FRAMEDONE3_IRQ_SHIFT	30  #define FRAMEDONETV_IRQ_SHIFT	24  /* @@ -376,7 +378,7 @@ int __init omap_display_init(struct omap_dss_board_info *board_data)  static void dispc_disable_outputs(void)  {  	u32 v, irq_mask = 0; -	bool lcd_en, digit_en, lcd2_en = false; +	bool lcd_en, digit_en, lcd2_en = false, lcd3_en = false;  	int i;  	struct omap_dss_dispc_dev_attr *da;  	struct omap_hwmod *oh; @@ -405,7 +407,13 @@ static void dispc_disable_outputs(void)  		lcd2_en = v & LCD_EN_MASK;  	} -	if (!(lcd_en | digit_en | lcd2_en)) +	/* store value of LCDENABLE for LCD3 */ +	if (da->manager_count > 3) { +		v = omap_hwmod_read(oh, DISPC_CONTROL3); +		lcd3_en = v & LCD_EN_MASK; +	} + +	if (!(lcd_en | digit_en | lcd2_en | lcd3_en))  		return; /* no managers currently enabled */  	/* @@ -426,10 +434,12 @@ static void dispc_disable_outputs(void)  	if (lcd2_en)  		irq_mask |= 1 << FRAMEDONE2_IRQ_SHIFT; +	if (lcd3_en) +		irq_mask |= 1 << FRAMEDONE3_IRQ_SHIFT;  	/*  	 * clear any previous FRAMEDONE, FRAMEDONETV, -	 * EVSYNC_EVEN/ODD or FRAMEDONE2 interrupts +	 * EVSYNC_EVEN/ODD, FRAMEDONE2 or FRAMEDONE3 interrupts  	 */  	omap_hwmod_write(irq_mask, oh, DISPC_IRQSTATUS); @@ -445,12 +455,19 @@ static void dispc_disable_outputs(void)  		omap_hwmod_write(v, oh, DISPC_CONTROL2);  	} +	/* disable LCD3 manager */ +	if (da->manager_count > 3) { +		v = omap_hwmod_read(oh, DISPC_CONTROL3); +		v &= ~LCD_EN_MASK; +		omap_hwmod_write(v, oh, DISPC_CONTROL3); +	} +  	i = 0;  	while ((omap_hwmod_read(oh, DISPC_IRQSTATUS) & irq_mask) !=  	       irq_mask) {  		i++;  		if (i > FRAMEDONE_IRQ_TIMEOUT) { -			pr_err("didn't get FRAMEDONE1/2 or TV interrupt\n"); +			pr_err("didn't get FRAMEDONE1/2/3 or TV interrupt\n");  			break;  		}  		mdelay(1); diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index b0b2ac335347..747442d2c0f6 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -90,7 +90,8 @@  #undef DEBUG  #ifdef DEBUG -#define DBG(fmt, args...)		printk(KERN_DEBUG "aty128fb: %s " fmt, __func__, ##args); +#define DBG(fmt, args...) \ +	printk(KERN_DEBUG "aty128fb: %s " fmt, __func__, ##args);  #else  #define DBG(fmt, args...)  #endif @@ -449,8 +450,9 @@ static int aty128_decode_var(struct fb_var_screeninfo *var,                               struct aty128fb_par *par);  #if 0  static void __devinit aty128_get_pllinfo(struct aty128fb_par *par, -				      void __iomem *bios); -static void __devinit __iomem *aty128_map_ROM(struct pci_dev *pdev, const struct aty128fb_par *par); +					 void __iomem *bios); +static void __devinit __iomem *aty128_map_ROM(struct pci_dev *pdev, +					      const struct aty128fb_par *par);  #endif  static void aty128_timings(struct aty128fb_par *par);  static void aty128_init_engine(struct aty128fb_par *par); @@ -779,7 +781,8 @@ static u32 depth_to_dst(u32 depth)  #ifndef __sparc__ -static void __iomem * __devinit aty128_map_ROM(const struct aty128fb_par *par, struct pci_dev *dev) +static void __iomem * __devinit aty128_map_ROM(const struct aty128fb_par *par, +					       struct pci_dev *dev)  {  	u16 dptr;  	u8 rom_type; @@ -811,13 +814,14 @@ static void __iomem * __devinit aty128_map_ROM(const struct aty128fb_par *par, s  	/* Look for the PCI data to check the ROM type */  	dptr = BIOS_IN16(0x18); -	/* Check the PCI data signature. If it's wrong, we still assume a normal x86 ROM -	 * for now, until I've verified this works everywhere. The goal here is more -	 * to phase out Open Firmware images. +	/* Check the PCI data signature. If it's wrong, we still assume a normal +	 * x86 ROM for now, until I've verified this works everywhere. +	 * The goal here is more to phase out Open Firmware images.  	 * -	 * Currently, we only look at the first PCI data, we could iteratre and deal with -	 * them all, and we should use fb_bios_start relative to start of image and not -	 * relative start of ROM, but so far, I never found a dual-image ATI card +	 * Currently, we only look at the first PCI data, we could iteratre and +	 * deal with them all, and we should use fb_bios_start relative to start +	 * of image and not relative start of ROM, but so far, I never found a +	 * dual-image ATI card.  	 *  	 * typedef struct {  	 * 	u32	signature;	+ 0x00 @@ -852,7 +856,8 @@ static void __iomem * __devinit aty128_map_ROM(const struct aty128fb_par *par, s  		printk(KERN_INFO "aty128fb: Found HP PA-RISC ROM Image\n");  		goto failed;  	default: -		printk(KERN_INFO "aty128fb: Found unknown type %d ROM Image\n", rom_type); +		printk(KERN_INFO "aty128fb: Found unknown type %d ROM Image\n", +		       rom_type);  		goto failed;  	}   anyway: @@ -863,7 +868,8 @@ static void __iomem * __devinit aty128_map_ROM(const struct aty128fb_par *par, s  	return NULL;  } -static void __devinit aty128_get_pllinfo(struct aty128fb_par *par, unsigned char __iomem *bios) +static void __devinit aty128_get_pllinfo(struct aty128fb_par *par, +					 unsigned char __iomem *bios)  {  	unsigned int bios_hdr;  	unsigned int bios_pll; @@ -1247,10 +1253,13 @@ static int aty128_crtc_to_var(const struct aty128_crtc *crtc,  static void aty128_set_crt_enable(struct aty128fb_par *par, int on)  {  	if (on) { -		aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) | CRT_CRTC_ON); -		aty_st_le32(DAC_CNTL, (aty_ld_le32(DAC_CNTL) | DAC_PALETTE2_SNOOP_EN)); +		aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) | +			    CRT_CRTC_ON); +		aty_st_le32(DAC_CNTL, (aty_ld_le32(DAC_CNTL) | +			    DAC_PALETTE2_SNOOP_EN));  	} else -		aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) & ~CRT_CRTC_ON); +		aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) & +			    ~CRT_CRTC_ON);  }  static void aty128_set_lcd_enable(struct aty128fb_par *par, int on) @@ -1281,7 +1290,8 @@ static void aty128_set_lcd_enable(struct aty128fb_par *par, int on)  	}  } -static void aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par) +static void aty128_set_pll(struct aty128_pll *pll, +			   const struct aty128fb_par *par)  {  	u32 div3; @@ -1366,7 +1376,8 @@ static int aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll,  } -static int aty128_pll_to_var(const struct aty128_pll *pll, struct fb_var_screeninfo *var) +static int aty128_pll_to_var(const struct aty128_pll *pll, +			     struct fb_var_screeninfo *var)  {  	var->pixclock = 100000000 / pll->vclk; @@ -1512,7 +1523,8 @@ static int aty128fb_set_par(struct fb_info *info)   *  encode/decode the User Defined Part of the Display   */ -static int aty128_decode_var(struct fb_var_screeninfo *var, struct aty128fb_par *par) +static int aty128_decode_var(struct fb_var_screeninfo *var, +			     struct aty128fb_par *par)  {  	int err;  	struct aty128_crtc crtc; @@ -1559,7 +1571,8 @@ static int aty128_encode_var(struct fb_var_screeninfo *var,  }            -static int aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +static int aty128fb_check_var(struct fb_var_screeninfo *var, +			      struct fb_info *info)  {  	struct aty128fb_par par;  	int err; @@ -1575,7 +1588,8 @@ static int aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *inf  /*   *  Pan or Wrap the Display   */ -static int aty128fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fb)  +static int aty128fb_pan_display(struct fb_var_screeninfo *var, +				struct fb_info *fb)  {  	struct aty128fb_par *par = fb->par;  	u32 xoffset, yoffset; @@ -1594,7 +1608,8 @@ static int aty128fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *f  	par->crtc.xoffset = xoffset;  	par->crtc.yoffset = yoffset; -	offset = ((yoffset * par->crtc.vxres + xoffset)*(par->crtc.bpp >> 3)) & ~7; +	offset = ((yoffset * par->crtc.vxres + xoffset) * (par->crtc.bpp >> 3)) +									  & ~7;  	if (par->crtc.bpp == 24)  		offset += 8 * (offset % 3); /* Must be multiple of 8 and 3 */ @@ -1620,11 +1635,13 @@ static void aty128_st_pal(u_int regno, u_int red, u_int green, u_int blue,  		 * do mirroring  		 */ -		aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PALETTE_ACCESS_CNTL); +		aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | +			    DAC_PALETTE_ACCESS_CNTL);  		aty_st_8(PALETTE_INDEX, regno);  		aty_st_le32(PALETTE_DATA, (red<<16)|(green<<8)|blue);  #endif -		aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~DAC_PALETTE_ACCESS_CNTL); +		aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & +			    ~DAC_PALETTE_ACCESS_CNTL);  	}  	aty_st_8(PALETTE_INDEX, regno); @@ -1753,7 +1770,8 @@ static int aty128_bl_update_status(struct backlight_device *bd)  			aty_st_le32(LVDS_GEN_CNTL, reg);  		}  		reg &= ~LVDS_BL_MOD_LEVEL_MASK; -		reg |= (aty128_bl_get_level_brightness(par, level) << LVDS_BL_MOD_LEVEL_SHIFT); +		reg |= (aty128_bl_get_level_brightness(par, level) << +			LVDS_BL_MOD_LEVEL_SHIFT);  #ifdef BACKLIGHT_LVDS_OFF  		reg |= LVDS_ON | LVDS_EN;  		reg &= ~LVDS_DISPLAY_DIS; @@ -1764,7 +1782,8 @@ static int aty128_bl_update_status(struct backlight_device *bd)  #endif  	} else {  		reg &= ~LVDS_BL_MOD_LEVEL_MASK; -		reg |= (aty128_bl_get_level_brightness(par, 0) << LVDS_BL_MOD_LEVEL_SHIFT); +		reg |= (aty128_bl_get_level_brightness(par, 0) << +			LVDS_BL_MOD_LEVEL_SHIFT);  #ifdef BACKLIGHT_LVDS_OFF  		reg |= LVDS_DISPLAY_DIS;  		aty_st_le32(LVDS_GEN_CNTL, reg); @@ -1869,7 +1888,8 @@ static void aty128_early_resume(void *data)  }  #endif /* CONFIG_PPC_PMAC */ -static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent) +static int __devinit aty128_init(struct pci_dev *pdev, +				 const struct pci_device_id *ent)  {  	struct fb_info *info = pci_get_drvdata(pdev);  	struct aty128fb_par *par = info->par; @@ -1887,7 +1907,8 @@ static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_i  	/* range check to make sure */  	if (ent->driver_data < ARRAY_SIZE(r128_family)) -	    strlcat(video_card, r128_family[ent->driver_data], sizeof(video_card)); +		strlcat(video_card, r128_family[ent->driver_data], +			sizeof(video_card));  	printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] ", video_card, chip_rev); @@ -1911,11 +1932,11 @@ static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_i  		/* Indicate sleep capability */  		if (par->chip_gen == rage_M3) {  			pmac_call_feature(PMAC_FTR_DEVICE_CAN_WAKE, NULL, 0, 1); -#if 0 /* Disable the early video resume hack for now as it's causing problems, among -       * others we now rely on the PCI core restoring the config space for us, which -       * isn't the case with that hack, and that code path causes various things to -       * be called with interrupts off while they shouldn't. I'm leaving the code in -       * as it can be useful for debugging purposes +#if 0 /* Disable the early video resume hack for now as it's causing problems, +       * among others we now rely on the PCI core restoring the config space +       * for us, which isn't the case with that hack, and that code path causes +       * various things to be called with interrupts off while they shouldn't. +       * I'm leaving the code in as it can be useful for debugging purposes         */  			pmac_set_early_video_resume(aty128_early_resume, par);  #endif @@ -1953,11 +1974,11 @@ static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_i  				default_vmode = VMODE_1152_768_60;  			if (default_cmode > 16)  -			    default_cmode = CMODE_32; +				default_cmode = CMODE_32;  			else if (default_cmode > 8)  -			    default_cmode = CMODE_16; +				default_cmode = CMODE_16;  			else  -			    default_cmode = CMODE_8; +				default_cmode = CMODE_8;  			if (mac_vmode_to_var(default_vmode, default_cmode, &var))  				var = default_var; @@ -2018,7 +2039,8 @@ static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_i  #ifdef CONFIG_PCI  /* register a card    ++ajoshi */ -static int __devinit aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +static int __devinit aty128_probe(struct pci_dev *pdev, +				  const struct pci_device_id *ent)  {  	unsigned long fb_addr, reg_addr;  	struct aty128fb_par *par; @@ -2318,39 +2340,39 @@ static inline void aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,  				   u_int width, u_int height,  				   struct fb_info_aty128 *par)  { -    u32 save_dp_datatype, save_dp_cntl, dstval; +	u32 save_dp_datatype, save_dp_cntl, dstval; -    if (!width || !height) -        return; +	if (!width || !height) +		return; -    dstval = depth_to_dst(par->current_par.crtc.depth); -    if (dstval == DST_24BPP) { -        srcx *= 3; -        dstx *= 3; -        width *= 3; -    } else if (dstval == -EINVAL) { -        printk("aty128fb: invalid depth or RGBA\n"); -        return; -    } +	dstval = depth_to_dst(par->current_par.crtc.depth); +	if (dstval == DST_24BPP) { +		srcx *= 3; +		dstx *= 3; +		width *= 3; +	} else if (dstval == -EINVAL) { +		printk("aty128fb: invalid depth or RGBA\n"); +		return; +	} -    wait_for_fifo(2, par); -    save_dp_datatype = aty_ld_le32(DP_DATATYPE); -    save_dp_cntl     = aty_ld_le32(DP_CNTL); +	wait_for_fifo(2, par); +	save_dp_datatype = aty_ld_le32(DP_DATATYPE); +	save_dp_cntl     = aty_ld_le32(DP_CNTL); -    wait_for_fifo(6, par); -    aty_st_le32(SRC_Y_X, (srcy << 16) | srcx); -    aty_st_le32(DP_MIX, ROP3_SRCCOPY | DP_SRC_RECT); -    aty_st_le32(DP_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM); -    aty_st_le32(DP_DATATYPE, save_dp_datatype | dstval | SRC_DSTCOLOR); +	wait_for_fifo(6, par); +	aty_st_le32(SRC_Y_X, (srcy << 16) | srcx); +	aty_st_le32(DP_MIX, ROP3_SRCCOPY | DP_SRC_RECT); +	aty_st_le32(DP_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM); +	aty_st_le32(DP_DATATYPE, save_dp_datatype | dstval | SRC_DSTCOLOR); -    aty_st_le32(DST_Y_X, (dsty << 16) | dstx); -    aty_st_le32(DST_HEIGHT_WIDTH, (height << 16) | width); +	aty_st_le32(DST_Y_X, (dsty << 16) | dstx); +	aty_st_le32(DST_HEIGHT_WIDTH, (height << 16) | width); -    par->blitter_may_be_busy = 1; +	par->blitter_may_be_busy = 1; -    wait_for_fifo(2, par); -    aty_st_le32(DP_DATATYPE, save_dp_datatype); -    aty_st_le32(DP_CNTL, save_dp_cntl);  +	wait_for_fifo(2, par); +	aty_st_le32(DP_DATATYPE, save_dp_datatype); +	aty_st_le32(DP_CNTL, save_dp_cntl);  } @@ -2358,17 +2380,17 @@ static inline void aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,       * Text mode accelerated functions       */ -static void fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx, -			int height, int width) +static void fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, +			       int dx, int height, int width)  { -    sx     *= fontwidth(p); -    sy     *= fontheight(p); -    dx     *= fontwidth(p); -    dy     *= fontheight(p); -    width  *= fontwidth(p); -    height *= fontheight(p); +	sx     *= fontwidth(p); +	sy     *= fontheight(p); +	dx     *= fontwidth(p); +	dy     *= fontheight(p); +	width  *= fontwidth(p); +	height *= fontheight(p); -    aty128_rectcopy(sx, sy, dx, dy, width, height, +	aty128_rectcopy(sx, sy, dx, dy, width, height,  			(struct fb_info_aty128 *)p->fb_info);  }  #endif /* 0 */ diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c index 47118c75a4c0..7ae9d53f2bf1 100644 --- a/drivers/video/da8xx-fb.c +++ b/drivers/video/da8xx-fb.c @@ -30,7 +30,10 @@  #include <linux/clk.h>  #include <linux/cpufreq.h>  #include <linux/console.h> +#include <linux/spinlock.h>  #include <linux/slab.h> +#include <linux/delay.h> +#include <linux/lcm.h>  #include <video/da8xx-fb.h>  #include <asm/div64.h> @@ -160,6 +163,13 @@ struct da8xx_fb_par {  	wait_queue_head_t	vsync_wait;  	int			vsync_flag;  	int			vsync_timeout; +	spinlock_t		lock_for_chan_update; + +	/* +	 * LCDC has 2 ping pong DMA channels, channel 0 +	 * and channel 1. +	 */ +	unsigned int		which_dma_channel_done;  #ifdef CONFIG_CPU_FREQ  	struct notifier_block	freq_transition;  	unsigned int		lcd_fck_rate; @@ -260,10 +270,18 @@ static inline void lcd_enable_raster(void)  {  	u32 reg; +	/* Put LCDC in reset for several cycles */ +	if (lcd_revision == LCD_VERSION_2) +		/* Write 1 to reset LCDC */ +		lcdc_write(LCD_CLK_MAIN_RESET, LCD_CLK_RESET_REG); +	mdelay(1); +  	/* Bring LCDC out of reset */  	if (lcd_revision == LCD_VERSION_2)  		lcdc_write(0, LCD_CLK_RESET_REG); +	mdelay(1); +	/* Above reset sequence doesnot reset register context */  	reg = lcdc_read(LCD_RASTER_CTRL_REG);  	if (!(reg & LCD_RASTER_ENABLE))  		lcdc_write(reg | LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); @@ -277,10 +295,6 @@ static inline void lcd_disable_raster(void)  	reg = lcdc_read(LCD_RASTER_CTRL_REG);  	if (reg & LCD_RASTER_ENABLE)  		lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); - -	if (lcd_revision == LCD_VERSION_2) -		/* Write 1 to reset LCDC */ -		lcdc_write(LCD_CLK_MAIN_RESET, LCD_CLK_RESET_REG);  }  static void lcd_blit(int load_mode, struct da8xx_fb_par *par) @@ -344,8 +358,8 @@ static void lcd_blit(int load_mode, struct da8xx_fb_par *par)  	lcd_enable_raster();  } -/* Configure the Burst Size of DMA */ -static int lcd_cfg_dma(int burst_size) +/* Configure the Burst Size and fifo threhold of DMA */ +static int lcd_cfg_dma(int burst_size, int fifo_th)  {  	u32 reg; @@ -369,6 +383,9 @@ static int lcd_cfg_dma(int burst_size)  	default:  		return -EINVAL;  	} + +	reg |= (fifo_th << 8); +  	lcdc_write(reg, LCD_DMA_CTRL_REG);  	return 0; @@ -670,8 +687,8 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,  		lcdc_write((lcdc_read(LCD_RASTER_TIMING_2_REG) &  			~LCD_INVERT_PIXEL_CLOCK), LCD_RASTER_TIMING_2_REG); -	/* Configure the DMA burst size. */ -	ret = lcd_cfg_dma(cfg->dma_burst_sz); +	/* Configure the DMA burst size and fifo threshold. */ +	ret = lcd_cfg_dma(cfg->dma_burst_sz, cfg->fifo_th);  	if (ret < 0)  		return ret; @@ -715,7 +732,6 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg)  {  	struct da8xx_fb_par *par = arg;  	u32 stat = lcdc_read(LCD_MASKED_STAT_REG); -	u32 reg_int;  	if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {  		lcd_disable_raster(); @@ -732,10 +748,8 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg)  		lcdc_write(stat, LCD_MASKED_STAT_REG); -		/* Disable PL completion inerrupt */ -		reg_int = lcdc_read(LCD_INT_ENABLE_CLR_REG) | -		       (LCD_V2_PL_INT_ENA); -		lcdc_write(reg_int, LCD_INT_ENABLE_CLR_REG); +		/* Disable PL completion interrupt */ +		lcdc_write(LCD_V2_PL_INT_ENA, LCD_INT_ENABLE_CLR_REG);  		/* Setup and start data loading mode */  		lcd_blit(LOAD_DATA, par); @@ -743,6 +757,7 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg)  		lcdc_write(stat, LCD_MASKED_STAT_REG);  		if (stat & LCD_END_OF_FRAME0) { +			par->which_dma_channel_done = 0;  			lcdc_write(par->dma_start,  				   LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);  			lcdc_write(par->dma_end, @@ -752,6 +767,7 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg)  		}  		if (stat & LCD_END_OF_FRAME1) { +			par->which_dma_channel_done = 1;  			lcdc_write(par->dma_start,  				   LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);  			lcdc_write(par->dma_end, @@ -798,6 +814,7 @@ static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg)  		lcdc_write(stat, LCD_STAT_REG);  		if (stat & LCD_END_OF_FRAME0) { +			par->which_dma_channel_done = 0;  			lcdc_write(par->dma_start,  				   LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);  			lcdc_write(par->dma_end, @@ -807,6 +824,7 @@ static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg)  		}  		if (stat & LCD_END_OF_FRAME1) { +			par->which_dma_channel_done = 1;  			lcdc_write(par->dma_start,  				   LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);  			lcdc_write(par->dma_end, @@ -1021,11 +1039,14 @@ static int cfb_blank(int blank, struct fb_info *info)  	par->blank = blank;  	switch (blank) {  	case FB_BLANK_UNBLANK: +		lcd_enable_raster(); +  		if (par->panel_power_ctrl)  			par->panel_power_ctrl(1); - -		lcd_enable_raster();  		break; +	case FB_BLANK_NORMAL: +	case FB_BLANK_VSYNC_SUSPEND: +	case FB_BLANK_HSYNC_SUSPEND:  	case FB_BLANK_POWERDOWN:  		if (par->panel_power_ctrl)  			par->panel_power_ctrl(0); @@ -1052,6 +1073,7 @@ static int da8xx_pan_display(struct fb_var_screeninfo *var,  	struct fb_fix_screeninfo    *fix = &fbi->fix;  	unsigned int end;  	unsigned int start; +	unsigned long irq_flags;  	if (var->xoffset != fbi->var.xoffset ||  			var->yoffset != fbi->var.yoffset) { @@ -1069,6 +1091,21 @@ static int da8xx_pan_display(struct fb_var_screeninfo *var,  			end	= start + fbi->var.yres * fix->line_length - 1;  			par->dma_start	= start;  			par->dma_end	= end; +			spin_lock_irqsave(&par->lock_for_chan_update, +					irq_flags); +			if (par->which_dma_channel_done == 0) { +				lcdc_write(par->dma_start, +					   LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); +				lcdc_write(par->dma_end, +					   LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); +			} else if (par->which_dma_channel_done == 1) { +				lcdc_write(par->dma_start, +					   LCD_DMA_FRM_BUF_BASE_ADDR_1_REG); +				lcdc_write(par->dma_end, +					   LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG); +			} +			spin_unlock_irqrestore(&par->lock_for_chan_update, +					irq_flags);  		}  	} @@ -1114,6 +1151,7 @@ static int __devinit fb_probe(struct platform_device *device)  	struct da8xx_fb_par *par;  	resource_size_t len;  	int ret, i; +	unsigned long ulcm;  	if (fb_pdata == NULL) {  		dev_err(&device->dev, "Can not get platform data\n"); @@ -1209,7 +1247,8 @@ static int __devinit fb_probe(struct platform_device *device)  	/* allocate frame buffer */  	par->vram_size = lcdc_info->width * lcdc_info->height * lcd_cfg->bpp; -	par->vram_size = PAGE_ALIGN(par->vram_size/8); +	ulcm = lcm((lcdc_info->width * lcd_cfg->bpp)/8, PAGE_SIZE); +	par->vram_size = roundup(par->vram_size/8, ulcm);  	par->vram_size = par->vram_size * LCD_NUM_BUFFERS;  	par->vram_virt = dma_alloc_coherent(NULL, @@ -1296,6 +1335,8 @@ static int __devinit fb_probe(struct platform_device *device)  	/* initialize the vsync wait queue */  	init_waitqueue_head(&par->vsync_wait);  	par->vsync_timeout = HZ / 5; +	par->which_dma_channel_done = -1; +	spin_lock_init(&par->lock_for_chan_update);  	/* Register the Frame Buffer  */  	if (register_framebuffer(da8xx_fb_info) < 0) { @@ -1382,11 +1423,12 @@ 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(); +  	if (par->panel_power_ctrl)  		par->panel_power_ctrl(1); -	clk_enable(par->lcdc_clk); -	lcd_enable_raster();  	fb_set_suspend(info, 0);  	console_unlock(); diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c index a268cbf1cbea..68b9b511ce80 100644 --- a/drivers/video/epson1355fb.c +++ b/drivers/video/epson1355fb.c @@ -477,11 +477,11 @@ static __init unsigned int get_fb_size(struct fb_info *info)  	return size;  } -static int epson1355_width_tab[2][4] __initdata = +static int epson1355_width_tab[2][4] __devinitdata =      { {4, 8, 16, -1}, {9, 12, 16, -1} }; -static int epson1355_bpp_tab[8] __initdata = { 1, 2, 4, 8, 15, 16 }; +static int epson1355_bpp_tab[8] __devinitdata = { 1, 2, 4, 8, 15, 16 }; -static void __init fetch_hw_state(struct fb_info *info, struct epson1355_par *par) +static void __devinit fetch_hw_state(struct fb_info *info, struct epson1355_par *par)  {  	struct fb_var_screeninfo *var = &info->var;  	struct fb_fix_screeninfo *fix = &info->fix; @@ -601,7 +601,7 @@ static int epson1355fb_remove(struct platform_device *dev)  	return 0;  } -int __devinit epson1355fb_probe(struct platform_device *dev) +static int __devinit epson1355fb_probe(struct platform_device *dev)  {  	struct epson1355_par *default_par;  	struct fb_info *info; diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c index a36b2d28280e..c6c016a506ce 100644 --- a/drivers/video/exynos/exynos_dp_core.c +++ b/drivers/video/exynos/exynos_dp_core.c @@ -47,7 +47,7 @@ static int exynos_dp_detect_hpd(struct exynos_dp_device *dp)  	exynos_dp_init_hpd(dp); -	udelay(200); +	usleep_range(200, 210);  	while (exynos_dp_get_plug_in_status(dp) != 0) {  		timeout_loop++; @@ -55,7 +55,7 @@ static int exynos_dp_detect_hpd(struct exynos_dp_device *dp)  			dev_err(dp->dev, "failed to get hpd plug status\n");  			return -ETIMEDOUT;  		} -		udelay(10); +		usleep_range(10, 11);  	}  	return 0; @@ -304,7 +304,7 @@ static void exynos_dp_link_start(struct exynos_dp_device *dp)  		buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 |  			    DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0;  	exynos_dp_write_bytes_to_dpcd(dp, -		DPCD_ADDR_TRAINING_PATTERN_SET, +		DPCD_ADDR_TRAINING_LANE0_SET,  		lane_count, buf);  } @@ -336,7 +336,7 @@ static int exynos_dp_channel_eq_ok(u8 link_status[6], int lane_count)  	u8 lane_status;  	lane_align = link_status[2]; -	if ((lane_align == DPCD_INTERLANE_ALIGN_DONE) == 0) +	if ((lane_align & DPCD_INTERLANE_ALIGN_DONE) == 0)  		return -EINVAL;  	for (lane = 0; lane < lane_count; lane++) { @@ -407,6 +407,9 @@ static unsigned int exynos_dp_get_lane_link_training(  	case 3:  		reg = exynos_dp_get_lane3_link_training(dp);  		break; +	default: +		WARN_ON(1); +		return 0;  	}  	return reg; @@ -483,7 +486,7 @@ static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp)  	u8 pre_emphasis;  	u8 training_lane; -	udelay(100); +	usleep_range(100, 101);  	exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS,  				6, link_status); @@ -501,7 +504,7 @@ static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp)  		buf[0] = DPCD_SCRAMBLING_DISABLED |  			 DPCD_TRAINING_PATTERN_2;  		exynos_dp_write_byte_to_dpcd(dp, -			DPCD_ADDR_TRAINING_LANE0_SET, +			DPCD_ADDR_TRAINING_PATTERN_SET,  			buf[0]);  		for (lane = 0; lane < lane_count; lane++) { @@ -568,7 +571,7 @@ static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp)  	u8 adjust_request[2]; -	udelay(400); +	usleep_range(400, 401);  	exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS,  				6, link_status); @@ -736,7 +739,7 @@ static int exynos_dp_set_link_train(struct exynos_dp_device *dp,  		if (retval == 0)  			break; -		udelay(100); +		usleep_range(100, 110);  	}  	return retval; @@ -770,7 +773,7 @@ static int exynos_dp_config_video(struct exynos_dp_device *dp,  			return -ETIMEDOUT;  		} -		udelay(1); +		usleep_range(1, 2);  	}  	/* Set to use the register calculated M/N video */ @@ -804,7 +807,7 @@ static int exynos_dp_config_video(struct exynos_dp_device *dp,  			return -ETIMEDOUT;  		} -		mdelay(1); +		usleep_range(1000, 1001);  	}  	if (retval != 0) diff --git a/drivers/video/exynos/exynos_dp_core.h b/drivers/video/exynos/exynos_dp_core.h index 1e0f998e0c9f..8526e548c385 100644 --- a/drivers/video/exynos/exynos_dp_core.h +++ b/drivers/video/exynos/exynos_dp_core.h @@ -85,10 +85,6 @@ void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype);  void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype);  void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count);  void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count); -void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype); -void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype); -void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count); -void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count);  void exynos_dp_enable_enhanced_mode(struct exynos_dp_device *dp, bool enable);  void exynos_dp_set_training_pattern(struct exynos_dp_device *dp,  				 enum pattern_set pattern); diff --git a/drivers/video/exynos/exynos_dp_reg.c b/drivers/video/exynos/exynos_dp_reg.c index bcb0e3ae1e9d..2db5b9aa250a 100644 --- a/drivers/video/exynos/exynos_dp_reg.c +++ b/drivers/video/exynos/exynos_dp_reg.c @@ -122,7 +122,7 @@ void exynos_dp_reset(struct exynos_dp_device *dp)  		LS_CLK_DOMAIN_FUNC_EN_N;  	writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2); -	udelay(20); +	usleep_range(20, 30);  	exynos_dp_lane_swap(dp, 0); @@ -988,7 +988,7 @@ void exynos_dp_reset_macro(struct exynos_dp_device *dp)  	writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST);  	/* 10 us is the minimum reset time. */ -	udelay(10); +	usleep_range(10, 20);  	reg &= ~MACRO_RST;  	writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST); diff --git a/drivers/video/exynos/exynos_mipi_dsi.c b/drivers/video/exynos/exynos_mipi_dsi.c index 9908e75ae761..4bc2b8a5dd8b 100644 --- a/drivers/video/exynos/exynos_mipi_dsi.c +++ b/drivers/video/exynos/exynos_mipi_dsi.c @@ -154,7 +154,7 @@ static int exynos_mipi_dsi_blank_mode(struct mipi_dsim_device *dsim, int power)  		if (client_drv && client_drv->power_on)  			client_drv->power_on(client_dev, 1); -		exynos_mipi_regulator_disable(dsim); +		exynos_mipi_regulator_enable(dsim);  		/* enable MIPI-DSI PHY. */  		if (dsim->pd->phy_enable) diff --git a/drivers/video/exynos/s6e8ax0.h b/drivers/video/exynos/s6e8ax0.h deleted file mode 100644 index 1f1b270484b0..000000000000 --- a/drivers/video/exynos/s6e8ax0.h +++ /dev/null @@ -1,21 +0,0 @@ -/* linux/drivers/video/backlight/s6e8ax0.h - * - * MIPI-DSI based s6e8ax0 AMOLED LCD Panel definitions. - * - * Copyright (c) 2011 Samsung Electronics - * - * Inki Dae, <inki.dae@samsung.com> - * Donghwa Lee <dh09.lee@samsung.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. -*/ - -#ifndef _S6E8AX0_H -#define _S6E8AX0_H - -extern void s6e8ax0_init(void); - -#endif - diff --git a/drivers/video/fb_draw.h b/drivers/video/fb_draw.h index 04c01faaf772..624ee115f129 100644 --- a/drivers/video/fb_draw.h +++ b/drivers/video/fb_draw.h @@ -3,6 +3,7 @@  #include <asm/types.h>  #include <linux/fb.h> +#include <linux/bug.h>      /*       *  Compose two values, using a bitmask as decision value @@ -41,7 +42,8 @@ pixel_to_pat( u32 bpp, u32 pixel)  	case 32:  		return 0x0000000100000001ul*pixel;  	default: -		panic("pixel_to_pat(): unsupported pixelformat\n"); +		WARN(1, "pixel_to_pat(): unsupported pixelformat %d\n", bpp); +		return 0;      }  }  #else @@ -66,7 +68,8 @@ pixel_to_pat( u32 bpp, u32 pixel)  	case 32:  		return 0x00000001ul*pixel;  	default: -		panic("pixel_to_pat(): unsupported pixelformat\n"); +		WARN(1, "pixel_to_pat(): unsupported pixelformat %d\n", bpp); +		return 0;      }  }  #endif diff --git a/drivers/video/grvga.c b/drivers/video/grvga.c index da066c210923..5245f9a71892 100644 --- a/drivers/video/grvga.c +++ b/drivers/video/grvga.c @@ -354,7 +354,7 @@ static int __devinit grvga_probe(struct platform_device *dev)  	 */  	if (fb_get_options("grvga", &options)) {  		retval = -ENODEV; -		goto err; +		goto free_fb;  	}  	if (!options || !*options) @@ -370,7 +370,7 @@ static int __devinit grvga_probe(struct platform_device *dev)  			if (grvga_parse_custom(this_opt, &info->var) < 0) {  				dev_err(&dev->dev, "Failed to parse custom mode (%s).\n", this_opt);  				retval = -EINVAL; -				goto err1; +				goto free_fb;  			}  		} else if (!strncmp(this_opt, "addr", 4))  			grvga_fix_addr = simple_strtoul(this_opt + 5, NULL, 16); @@ -387,10 +387,11 @@ static int __devinit grvga_probe(struct platform_device *dev)  	info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK | FBINFO_HWACCEL_YPAN;  	info->fix.smem_len = grvga_mem_size; -	if (!request_mem_region(dev->resource[0].start, resource_size(&dev->resource[0]), "grlib-svgactrl regs")) { +	if (!devm_request_mem_region(&dev->dev, dev->resource[0].start, +		    resource_size(&dev->resource[0]), "grlib-svgactrl regs")) {  		dev_err(&dev->dev, "registers already mapped\n");  		retval = -EBUSY; -		goto err; +		goto free_fb;  	}  	par->regs = of_ioremap(&dev->resource[0], 0, @@ -400,14 +401,14 @@ static int __devinit grvga_probe(struct platform_device *dev)  	if (!par->regs) {  		dev_err(&dev->dev, "failed to map registers\n");  		retval = -ENOMEM; -		goto err1; +		goto free_fb;  	}  	retval = fb_alloc_cmap(&info->cmap, 256, 0);  	if (retval < 0) {  		dev_err(&dev->dev, "failed to allocate mem with fb_alloc_cmap\n");  		retval = -ENOMEM; -		goto err2; +		goto unmap_regs;  	}  	if (mode_opt) { @@ -415,7 +416,7 @@ static int __devinit grvga_probe(struct platform_device *dev)  				      grvga_modedb, sizeof(grvga_modedb), &grvga_modedb[0], 8);  		if (!retval || retval == 4) {  			retval = -EINVAL; -			goto err3; +			goto dealloc_cmap;  		}  	} @@ -427,10 +428,11 @@ static int __devinit grvga_probe(struct platform_device *dev)  		physical_start = grvga_fix_addr; -		if (!request_mem_region(physical_start, grvga_mem_size, dev->name)) { +		if (!devm_request_mem_region(&dev->dev, physical_start, +					     grvga_mem_size, dev->name)) {  			dev_err(&dev->dev, "failed to request memory region\n");  			retval = -ENOMEM; -			goto err3; +			goto dealloc_cmap;  		}  		virtual_start = (unsigned long) ioremap(physical_start, grvga_mem_size); @@ -438,7 +440,7 @@ static int __devinit grvga_probe(struct platform_device *dev)  		if (!virtual_start) {  			dev_err(&dev->dev, "error mapping framebuffer memory\n");  			retval = -ENOMEM; -			goto err4; +			goto dealloc_cmap;  		}  	} else {	/* Allocate frambuffer memory */ @@ -451,7 +453,7 @@ static int __devinit grvga_probe(struct platform_device *dev)  				"unable to allocate framebuffer memory (%lu bytes)\n",  				grvga_mem_size);  			retval = -ENOMEM; -			goto err3; +			goto dealloc_cmap;  		}  		physical_start = dma_map_single(&dev->dev, (void *)virtual_start, grvga_mem_size, DMA_TO_DEVICE); @@ -484,7 +486,7 @@ static int __devinit grvga_probe(struct platform_device *dev)  	retval = register_framebuffer(info);  	if (retval < 0) {  		dev_err(&dev->dev, "failed to register framebuffer\n"); -		goto err4; +		goto free_mem;  	}  	__raw_writel(physical_start, &par->regs->fb_pos); @@ -493,21 +495,18 @@ static int __devinit grvga_probe(struct platform_device *dev)  	return 0; -err4: +free_mem:  	dev_set_drvdata(&dev->dev, NULL); -	if (grvga_fix_addr) { -		release_mem_region(physical_start, grvga_mem_size); +	if (grvga_fix_addr)  		iounmap((void *)virtual_start); -	} else +	else  		kfree((void *)virtual_start); -err3: +dealloc_cmap:  	fb_dealloc_cmap(&info->cmap); -err2: +unmap_regs:  	of_iounmap(&dev->resource[0], par->regs,  		   resource_size(&dev->resource[0])); -err1: -	release_mem_region(dev->resource[0].start, resource_size(&dev->resource[0])); -err: +free_fb:  	framebuffer_release(info);  	return retval; @@ -524,12 +523,10 @@ static int __devexit grvga_remove(struct platform_device *device)  		of_iounmap(&device->resource[0], par->regs,  			   resource_size(&device->resource[0])); -		release_mem_region(device->resource[0].start, resource_size(&device->resource[0])); -		if (!par->fb_alloced) { -			release_mem_region(info->fix.smem_start, info->fix.smem_len); +		if (!par->fb_alloced)  			iounmap(info->screen_base); -		} else +		else  			kfree((void *)info->screen_base);  		framebuffer_release(info); diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c index eec0d7b748eb..c89f8a8d36d2 100644 --- a/drivers/video/mx3fb.c +++ b/drivers/video/mx3fb.c @@ -269,7 +269,7 @@ struct mx3fb_info {  	dma_cookie_t			cookie;  	struct scatterlist		sg[2]; -	u32				sync;	/* preserve var->sync flags */ +	struct fb_var_screeninfo	cur_var; /* current var info */  };  static void mx3fb_dma_done(void *); @@ -698,9 +698,29 @@ static void mx3fb_dma_done(void *arg)  	complete(&mx3_fbi->flip_cmpl);  } +static bool mx3fb_must_set_par(struct fb_info *fbi) +{ +	struct mx3fb_info *mx3_fbi = fbi->par; +	struct fb_var_screeninfo old_var = mx3_fbi->cur_var; +	struct fb_var_screeninfo new_var = fbi->var; + +	if ((fbi->var.activate & FB_ACTIVATE_FORCE) && +	    (fbi->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) +		return true; + +	/* +	 * Ignore xoffset and yoffset update, +	 * because pan display handles this case. +	 */ +	old_var.xoffset = new_var.xoffset; +	old_var.yoffset = new_var.yoffset; + +	return !!memcmp(&old_var, &new_var, sizeof(struct fb_var_screeninfo)); +} +  static int __set_par(struct fb_info *fbi, bool lock)  { -	u32 mem_len; +	u32 mem_len, cur_xoffset, cur_yoffset;  	struct ipu_di_signal_cfg sig_cfg;  	enum ipu_panel mode = IPU_PANEL_TFT;  	struct mx3fb_info *mx3_fbi = fbi->par; @@ -780,8 +800,25 @@ static int __set_par(struct fb_info *fbi, bool lock)  	video->out_height	= fbi->var.yres;  	video->out_stride	= fbi->var.xres_virtual; -	if (mx3_fbi->blank == FB_BLANK_UNBLANK) +	if (mx3_fbi->blank == FB_BLANK_UNBLANK) {  		sdc_enable_channel(mx3_fbi); +		/* +		 * sg[0] points to fb smem_start address +		 * and is actually active in controller. +		 */ +		mx3_fbi->cur_var.xoffset = 0; +		mx3_fbi->cur_var.yoffset = 0; +	} + +	/* +	 * Preserve xoffset and yoffest in case they are +	 * inactive in controller as fb is blanked. +	 */ +	cur_xoffset = mx3_fbi->cur_var.xoffset; +	cur_yoffset = mx3_fbi->cur_var.yoffset; +	mx3_fbi->cur_var = fbi->var; +	mx3_fbi->cur_var.xoffset = cur_xoffset; +	mx3_fbi->cur_var.yoffset = cur_yoffset;  	return 0;  } @@ -802,7 +839,7 @@ static int mx3fb_set_par(struct fb_info *fbi)  	mutex_lock(&mx3_fbi->mutex); -	ret = __set_par(fbi, true); +	ret = mx3fb_must_set_par(fbi) ? __set_par(fbi, true) : 0;  	mutex_unlock(&mx3_fbi->mutex); @@ -901,8 +938,8 @@ static int mx3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)  	var->grayscale = 0;  	/* Preserve sync flags */ -	var->sync |= mx3_fbi->sync; -	mx3_fbi->sync |= var->sync; +	var->sync |= mx3_fbi->cur_var.sync; +	mx3_fbi->cur_var.sync |= var->sync;  	return 0;  } @@ -1043,8 +1080,8 @@ static int mx3fb_pan_display(struct fb_var_screeninfo *var,  		return -EINVAL;  	} -	if (fbi->var.xoffset == var->xoffset && -	    fbi->var.yoffset == var->yoffset) +	if (mx3_fbi->cur_var.xoffset == var->xoffset && +	    mx3_fbi->cur_var.yoffset == var->yoffset)  		return 0;	/* No change, do nothing */  	y_bottom = var->yoffset; @@ -1127,6 +1164,8 @@ static int mx3fb_pan_display(struct fb_var_screeninfo *var,  	else  		fbi->var.vmode &= ~FB_VMODE_YWRAP; +	mx3_fbi->cur_var = fbi->var; +  	mutex_unlock(&mx3_fbi->mutex);  	dev_dbg(fbi->device, "Update complete\n"); diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c index ad741c3d1ae1..eaeed4340e04 100644 --- a/drivers/video/omap2/displays/panel-acx565akm.c +++ b/drivers/video/omap2/displays/panel-acx565akm.c @@ -487,6 +487,13 @@ static struct omap_video_timings acx_panel_timings = {  	.vfp		= 3,  	.vsw		= 3,  	.vbp		= 4, + +	.vsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +	.hsync_level	= OMAPDSS_SIG_ACTIVE_LOW, + +	.data_pclk_edge	= OMAPDSS_DRIVE_SIG_RISING_EDGE, +	.de_level	= OMAPDSS_SIG_ACTIVE_HIGH, +	.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,  };  static int acx_panel_probe(struct omap_dss_device *dssdev) @@ -498,8 +505,7 @@ static int acx_panel_probe(struct omap_dss_device *dssdev)  	struct backlight_properties props;  	dev_dbg(&dssdev->dev, "%s\n", __func__); -	dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | -					OMAP_DSS_LCD_IHS; +  	/* FIXME AC bias ? */  	dssdev->panel.timings = acx_panel_timings; diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c index e42f9dc22123..bc5af2500eb9 100644 --- a/drivers/video/omap2/displays/panel-generic-dpi.c +++ b/drivers/video/omap2/displays/panel-generic-dpi.c @@ -40,12 +40,6 @@  struct panel_config {  	struct omap_video_timings timings; -	int acbi;	/* ac-bias pin transitions per interrupt */ -	/* Unit: line clocks */ -	int acb;	/* ac-bias pin frequency */ - -	enum omap_panel_config config; -  	int power_on_delay;  	int power_off_delay; @@ -73,11 +67,13 @@ static struct panel_config generic_dpi_panels[] = {  			.vsw		= 11,  			.vfp		= 3,  			.vbp		= 2, + +			.vsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.hsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.data_pclk_edge	= OMAPDSS_DRIVE_SIG_RISING_EDGE, +			.de_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,  		}, -		.acbi			= 0x0, -		.acb			= 0x0, -		.config			= OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | -					OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IEO,  		.power_on_delay		= 50,  		.power_off_delay	= 100,  		.name			= "sharp_lq", @@ -98,11 +94,13 @@ static struct panel_config generic_dpi_panels[] = {  			.vsw		= 1,  			.vfp		= 1,  			.vbp		= 1, + +			.vsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.hsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.data_pclk_edge	= OMAPDSS_DRIVE_SIG_RISING_EDGE, +			.de_level	= OMAPDSS_SIG_ACTIVE_HIGH, +			.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,  		}, -		.acbi			= 0x0, -		.acb			= 0x28, -		.config			= OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | -						OMAP_DSS_LCD_IHS,  		.power_on_delay		= 50,  		.power_off_delay	= 100,  		.name			= "sharp_ls", @@ -123,12 +121,13 @@ static struct panel_config generic_dpi_panels[] = {  			.vfp		= 4,  			.vsw		= 2,  			.vbp		= 2, + +			.vsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.hsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.data_pclk_edge	= OMAPDSS_DRIVE_SIG_FALLING_EDGE, +			.de_level	= OMAPDSS_SIG_ACTIVE_HIGH, +			.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_FALLING_EDGE,  		}, -		.acbi			= 0x0, -		.acb			= 0x0, -		.config			= OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | -					OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC | -					OMAP_DSS_LCD_ONOFF,  		.power_on_delay		= 0,  		.power_off_delay	= 0,  		.name			= "toppoly_tdo35s", @@ -149,11 +148,13 @@ static struct panel_config generic_dpi_panels[] = {  			.vfp		= 4,  			.vsw		= 10,  			.vbp		= 12 - 10, + +			.vsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.hsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.data_pclk_edge	= OMAPDSS_DRIVE_SIG_RISING_EDGE, +			.de_level	= OMAPDSS_SIG_ACTIVE_HIGH, +			.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,  		}, -		.acbi			= 0x0, -		.acb			= 0x0, -		.config			= OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | -						OMAP_DSS_LCD_IHS,  		.power_on_delay		= 0,  		.power_off_delay	= 0,  		.name			= "samsung_lte430wq_f0c", @@ -174,11 +175,13 @@ static struct panel_config generic_dpi_panels[] = {  			.vsw		= 2,  			.vfp		= 4,  			.vbp		= 11, + +			.vsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.hsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.data_pclk_edge	= OMAPDSS_DRIVE_SIG_RISING_EDGE, +			.de_level	= OMAPDSS_SIG_ACTIVE_HIGH, +			.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,  		}, -		.acbi			= 0x0, -		.acb			= 0x0, -		.config			= OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | -						OMAP_DSS_LCD_IHS,  		.power_on_delay		= 0,  		.power_off_delay	= 0,  		.name			= "seiko_70wvw1tz3", @@ -199,11 +202,13 @@ static struct panel_config generic_dpi_panels[] = {  			.vsw		= 10,  			.vfp		= 2,  			.vbp		= 2, + +			.vsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.hsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.data_pclk_edge	= OMAPDSS_DRIVE_SIG_RISING_EDGE, +			.de_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,  		}, -		.acbi			= 0x0, -		.acb			= 0x0, -		.config			= OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | -					  OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IEO,  		.power_on_delay		= 0,  		.power_off_delay	= 0,  		.name			= "powertip_ph480272t", @@ -224,11 +229,13 @@ static struct panel_config generic_dpi_panels[] = {  			.vsw		= 3,  			.vfp		= 12,  			.vbp		= 25, + +			.vsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.hsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.data_pclk_edge	= OMAPDSS_DRIVE_SIG_RISING_EDGE, +			.de_level	= OMAPDSS_SIG_ACTIVE_HIGH, +			.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,  		}, -		.acbi			= 0x0, -		.acb			= 0x28, -		.config			= OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | -					  OMAP_DSS_LCD_IHS,  		.power_on_delay		= 0,  		.power_off_delay	= 0,  		.name			= "innolux_at070tn83", @@ -249,9 +256,13 @@ static struct panel_config generic_dpi_panels[] = {  			.vsw		= 1,  			.vfp		= 2,  			.vbp		= 7, + +			.vsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.hsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.data_pclk_edge	= OMAPDSS_DRIVE_SIG_RISING_EDGE, +			.de_level	= OMAPDSS_SIG_ACTIVE_HIGH, +			.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,  		}, -		.config			= OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | -						OMAP_DSS_LCD_IHS,  		.name			= "nec_nl2432dr22-11b",  	}, @@ -270,9 +281,13 @@ static struct panel_config generic_dpi_panels[] = {  			.vsw		= 1,  			.vfp		= 1,  			.vbp		= 1, -		}, -		.config			= OMAP_DSS_LCD_TFT, +			.vsync_level	= OMAPDSS_SIG_ACTIVE_HIGH, +			.hsync_level	= OMAPDSS_SIG_ACTIVE_HIGH, +			.data_pclk_edge	= OMAPDSS_DRIVE_SIG_RISING_EDGE, +			.de_level	= OMAPDSS_SIG_ACTIVE_HIGH, +			.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, +		},  		.name			= "h4",  	}, @@ -291,10 +306,13 @@ static struct panel_config generic_dpi_panels[] = {  			.vsw		= 10,  			.vfp		= 2,  			.vbp		= 2, -		}, -		.config			= OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | -						OMAP_DSS_LCD_IHS, +			.vsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.hsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.data_pclk_edge	= OMAPDSS_DRIVE_SIG_RISING_EDGE, +			.de_level	= OMAPDSS_SIG_ACTIVE_HIGH, +			.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, +		},  		.name			= "apollon",  	},  	/* FocalTech ETM070003DH6 */ @@ -312,9 +330,13 @@ static struct panel_config generic_dpi_panels[] = {  			.vsw		= 3,  			.vfp		= 13,  			.vbp		= 29, + +			.vsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.hsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.data_pclk_edge	= OMAPDSS_DRIVE_SIG_RISING_EDGE, +			.de_level	= OMAPDSS_SIG_ACTIVE_HIGH, +			.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,  		}, -		.config			= OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | -					  OMAP_DSS_LCD_IHS,  		.name			= "focaltech_etm070003dh6",  	}, @@ -333,11 +355,13 @@ static struct panel_config generic_dpi_panels[] = {  			.vsw		= 23,  			.vfp		= 1,  			.vbp		= 1, + +			.vsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.hsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.data_pclk_edge	= OMAPDSS_DRIVE_SIG_FALLING_EDGE, +			.de_level	= OMAPDSS_SIG_ACTIVE_HIGH, +			.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,  		}, -		.acbi			= 0x0, -		.acb			= 0x0, -		.config			= OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | -					  OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC,  		.power_on_delay		= 0,  		.power_off_delay	= 0,  		.name			= "microtips_umsh_8173md", @@ -358,9 +382,13 @@ static struct panel_config generic_dpi_panels[] = {  			.vsw		= 10,  			.vfp		= 4,  			.vbp		= 2, -		}, -		.config			= OMAP_DSS_LCD_TFT, +			.vsync_level	= OMAPDSS_SIG_ACTIVE_HIGH, +			.hsync_level	= OMAPDSS_SIG_ACTIVE_HIGH, +			.data_pclk_edge	= OMAPDSS_DRIVE_SIG_RISING_EDGE, +			.de_level	= OMAPDSS_SIG_ACTIVE_HIGH, +			.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, +		},  		.name			= "ortustech_com43h4m10xtc",  	}, @@ -379,11 +407,13 @@ static struct panel_config generic_dpi_panels[] = {  			.vsw		= 10,  			.vfp		= 12,  			.vbp		= 23, -		}, -		.acb			= 0x0, -		.config			= OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | -					  OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IEO, +			.vsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.hsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.data_pclk_edge	= OMAPDSS_DRIVE_SIG_RISING_EDGE, +			.de_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, +		},  		.name			= "innolux_at080tn52",  	}, @@ -401,8 +431,13 @@ static struct panel_config generic_dpi_panels[] = {  			.vsw		= 1,  			.vfp		= 26,  			.vbp		= 1, + +			.vsync_level	= OMAPDSS_SIG_ACTIVE_HIGH, +			.hsync_level	= OMAPDSS_SIG_ACTIVE_HIGH, +			.data_pclk_edge	= OMAPDSS_DRIVE_SIG_RISING_EDGE, +			.de_level	= OMAPDSS_SIG_ACTIVE_HIGH, +			.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,  		}, -		.config			= OMAP_DSS_LCD_TFT,  		.name			= "mitsubishi_aa084sb01",  	},  	/* EDT ET0500G0DH6 */ @@ -419,8 +454,13 @@ static struct panel_config generic_dpi_panels[] = {  			.vsw		= 2,  			.vfp		= 35,  			.vbp		= 10, + +			.vsync_level	= OMAPDSS_SIG_ACTIVE_HIGH, +			.hsync_level	= OMAPDSS_SIG_ACTIVE_HIGH, +			.data_pclk_edge	= OMAPDSS_DRIVE_SIG_RISING_EDGE, +			.de_level	= OMAPDSS_SIG_ACTIVE_HIGH, +			.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,  		}, -		.config			= OMAP_DSS_LCD_TFT,  		.name			= "edt_et0500g0dh6",  	}, @@ -439,9 +479,13 @@ static struct panel_config generic_dpi_panels[] = {  			.vsw		= 2,  			.vfp		= 10,  			.vbp		= 33, + +			.vsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.hsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.data_pclk_edge	= OMAPDSS_DRIVE_SIG_FALLING_EDGE, +			.de_level	= OMAPDSS_SIG_ACTIVE_HIGH, +			.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,  		}, -		.config			= OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | -					  OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC,  		.name			= "primeview_pd050vl1",  	}, @@ -460,9 +504,13 @@ static struct panel_config generic_dpi_panels[] = {  			.vsw		= 2,  			.vfp		= 10,  			.vbp		= 33, + +			.vsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.hsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.data_pclk_edge	= OMAPDSS_DRIVE_SIG_FALLING_EDGE, +			.de_level	= OMAPDSS_SIG_ACTIVE_HIGH, +			.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,  		}, -		.config			= OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | -					  OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC,  		.name			= "primeview_pm070wl4",  	}, @@ -481,9 +529,13 @@ static struct panel_config generic_dpi_panels[] = {  			.vsw		= 4,  			.vfp		= 1,  			.vbp		= 23, + +			.vsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.hsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +			.data_pclk_edge	= OMAPDSS_DRIVE_SIG_FALLING_EDGE, +			.de_level	= OMAPDSS_SIG_ACTIVE_HIGH, +			.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,  		}, -		.config			= OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | -					  OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC,  		.name			= "primeview_pd104slf",  	},  }; @@ -573,10 +625,7 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev)  	if (!panel_config)  		return -EINVAL; -	dssdev->panel.config = panel_config->config;  	dssdev->panel.timings = panel_config->timings; -	dssdev->panel.acb = panel_config->acb; -	dssdev->panel.acbi = panel_config->acbi;  	drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);  	if (!drv_data) diff --git a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c index 0841cc2b3f77..802807798846 100644 --- a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c +++ b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c @@ -40,6 +40,12 @@ static struct omap_video_timings lb035q02_timings = {  	.vsw		= 2,  	.vfp		= 4,  	.vbp		= 18, + +	.vsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +	.hsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +	.data_pclk_edge	= OMAPDSS_DRIVE_SIG_RISING_EDGE, +	.de_level	= OMAPDSS_SIG_ACTIVE_HIGH, +	.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,  };  static int lb035q02_panel_power_on(struct omap_dss_device *dssdev) @@ -82,8 +88,6 @@ static int lb035q02_panel_probe(struct omap_dss_device *dssdev)  	struct lb035q02_data *ld;  	int r; -	dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | -		OMAP_DSS_LCD_IHS;  	dssdev->panel.timings = lb035q02_timings;  	ld = kzalloc(sizeof(*ld), GFP_KERNEL); diff --git a/drivers/video/omap2/displays/panel-n8x0.c b/drivers/video/omap2/displays/panel-n8x0.c index 4a34cdc1371b..e6c115373c00 100644 --- a/drivers/video/omap2/displays/panel-n8x0.c +++ b/drivers/video/omap2/displays/panel-n8x0.c @@ -473,7 +473,6 @@ static int n8x0_panel_probe(struct omap_dss_device *dssdev)  	mutex_init(&ddata->lock); -	dssdev->panel.config = OMAP_DSS_LCD_TFT;  	dssdev->panel.timings.x_res = 800;  	dssdev->panel.timings.y_res = 480;  	dssdev->ctrl.pixel_size = 16; diff --git a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c index 8b38b39213f4..b122b0f31c43 100644 --- a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c +++ b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c @@ -76,6 +76,12 @@ static struct omap_video_timings nec_8048_panel_timings = {  	.vfp		= 3,  	.vsw		= 1,  	.vbp		= 4, + +	.vsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +	.hsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +	.data_pclk_edge	= OMAPDSS_DRIVE_SIG_RISING_EDGE, +	.de_level	= OMAPDSS_SIG_ACTIVE_HIGH, +	.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_RISING_EDGE,  };  static int nec_8048_bl_update_status(struct backlight_device *bl) @@ -116,9 +122,6 @@ static int nec_8048_panel_probe(struct omap_dss_device *dssdev)  	struct backlight_properties props;  	int r; -	dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | -				OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_RF | -				OMAP_DSS_LCD_ONOFF;  	dssdev->panel.timings = nec_8048_panel_timings;  	necd = kzalloc(sizeof(*necd), GFP_KERNEL); diff --git a/drivers/video/omap2/displays/panel-picodlp.c b/drivers/video/omap2/displays/panel-picodlp.c index 98ebdaddab5a..2d35bd388860 100644 --- a/drivers/video/omap2/displays/panel-picodlp.c +++ b/drivers/video/omap2/displays/panel-picodlp.c @@ -69,6 +69,12 @@ static struct omap_video_timings pico_ls_timings = {  	.vsw		= 2,  	.vfp		= 3,  	.vbp		= 14, + +	.vsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +	.hsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +	.data_pclk_edge	= OMAPDSS_DRIVE_SIG_RISING_EDGE, +	.de_level	= OMAPDSS_SIG_ACTIVE_HIGH, +	.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_FALLING_EDGE,  };  static inline struct picodlp_panel_data @@ -414,9 +420,6 @@ static int picodlp_panel_probe(struct omap_dss_device *dssdev)  	struct i2c_client *picodlp_i2c_client;  	int r = 0, picodlp_adapter_id; -	dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_ONOFF | -				OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IVS; -	dssdev->panel.acb = 0x0;  	dssdev->panel.timings = pico_ls_timings;  	picod =  kzalloc(sizeof(struct picodlp_data), GFP_KERNEL); diff --git a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c index ba38b3ad17d6..bd86ba9ccf76 100644 --- a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c +++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c @@ -44,6 +44,12 @@ static struct omap_video_timings sharp_ls_timings = {  	.vsw		= 1,  	.vfp		= 1,  	.vbp		= 1, + +	.vsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +	.hsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +	.data_pclk_edge	= OMAPDSS_DRIVE_SIG_RISING_EDGE, +	.de_level	= OMAPDSS_SIG_ACTIVE_HIGH, +	.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,  };  static int sharp_ls_bl_update_status(struct backlight_device *bl) @@ -86,9 +92,6 @@ static int sharp_ls_panel_probe(struct omap_dss_device *dssdev)  	struct sharp_data *sd;  	int r; -	dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | -		OMAP_DSS_LCD_IHS; -	dssdev->panel.acb = 0x28;  	dssdev->panel.timings = sharp_ls_timings;  	sd = kzalloc(sizeof(*sd), GFP_KERNEL); diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 901576eb5a84..3f5acc7771da 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -882,7 +882,6 @@ static int taal_probe(struct omap_dss_device *dssdev)  		goto err;  	} -	dssdev->panel.config = OMAP_DSS_LCD_TFT;  	dssdev->panel.timings = panel_config->timings;  	dssdev->panel.dsi_pix_fmt = OMAP_DSS_DSI_FMT_RGB888; diff --git a/drivers/video/omap2/displays/panel-tfp410.c b/drivers/video/omap2/displays/panel-tfp410.c index bff306e041ca..40cc0cfa5d17 100644 --- a/drivers/video/omap2/displays/panel-tfp410.c +++ b/drivers/video/omap2/displays/panel-tfp410.c @@ -39,6 +39,12 @@ static const struct omap_video_timings tfp410_default_timings = {  	.vfp		= 3,  	.vsw		= 4,  	.vbp		= 7, + +	.vsync_level	= OMAPDSS_SIG_ACTIVE_HIGH, +	.hsync_level	= OMAPDSS_SIG_ACTIVE_HIGH, +	.data_pclk_edge	= OMAPDSS_DRIVE_SIG_RISING_EDGE, +	.de_level	= OMAPDSS_SIG_ACTIVE_HIGH, +	.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,  };  struct panel_drv_data { @@ -95,7 +101,6 @@ static int tfp410_probe(struct omap_dss_device *dssdev)  		return -ENOMEM;  	dssdev->panel.timings = tfp410_default_timings; -	dssdev->panel.config = OMAP_DSS_LCD_TFT;  	ddata->dssdev = dssdev;  	mutex_init(&ddata->lock); diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c index 4b6448b3c31f..fa7baa650ae0 100644 --- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c +++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c @@ -267,6 +267,12 @@ static const struct omap_video_timings tpo_td043_timings = {  	.vsw		= 1,  	.vfp		= 39,  	.vbp		= 34, + +	.vsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +	.hsync_level	= OMAPDSS_SIG_ACTIVE_LOW, +	.data_pclk_edge	= OMAPDSS_DRIVE_SIG_FALLING_EDGE, +	.de_level	= OMAPDSS_SIG_ACTIVE_HIGH, +	.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,  };  static int tpo_td043_power_on(struct tpo_td043_device *tpo_td043) @@ -423,8 +429,6 @@ static int tpo_td043_probe(struct omap_dss_device *dssdev)  		return -ENODEV;  	} -	dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IHS | -				OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IPC;  	dssdev->panel.timings = tpo_td043_timings;  	dssdev->ctrl.pixel_size = 24; diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig index 43324e5ed25f..b337a8469fd8 100644 --- a/drivers/video/omap2/dss/Kconfig +++ b/drivers/video/omap2/dss/Kconfig @@ -52,7 +52,7 @@ config OMAP2_DSS_RFBI  	  DBI is a bus between the host processor and a peripheral,  	  such as a display or a framebuffer chip. -	  See http://www.mipi.org/ for DBI spesifications. +	  See http://www.mipi.org/ for DBI specifications.  config OMAP2_DSS_VENC  	bool "VENC support" @@ -92,7 +92,7 @@ config OMAP2_DSS_DSI  	  DSI is a high speed half-duplex serial interface between the host  	  processor and a peripheral, such as a display or a framebuffer chip. -	  See http://www.mipi.org/ for DSI spesifications. +	  See http://www.mipi.org/ for DSI specifications.  config OMAP2_DSS_MIN_FCK_PER_PCK  	int "Minimum FCK/PCK ratio (for scaling)" diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c index ab22cc224f3e..0fefc68372b9 100644 --- a/drivers/video/omap2/dss/apply.c +++ b/drivers/video/omap2/dss/apply.c @@ -104,6 +104,7 @@ struct mgr_priv_data {  	bool shadow_extra_info_dirty;  	struct omap_video_timings timings; +	struct dss_lcd_mgr_config lcd_config;  };  static struct { @@ -137,6 +138,7 @@ static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr)  void dss_apply_init(void)  {  	const int num_ovls = dss_feat_get_num_ovls(); +	struct mgr_priv_data *mp;  	int i;  	spin_lock_init(&data_lock); @@ -168,16 +170,35 @@ void dss_apply_init(void)  		op->user_info = op->info;  	} + +	/* +	 * Initialize some of the lcd_config fields for TV manager, this lets +	 * us prevent checking if the manager is LCD or TV at some places +	 */ +	mp = &dss_data.mgr_priv_data_array[OMAP_DSS_CHANNEL_DIGIT]; + +	mp->lcd_config.video_port_width = 24; +	mp->lcd_config.clock_info.lck_div = 1; +	mp->lcd_config.clock_info.pck_div = 1;  } +/* + * A LCD manager's stallmode decides whether it is in manual or auto update. TV + * manager is always auto update, stallmode field for TV manager is false by + * default + */  static bool ovl_manual_update(struct omap_overlay *ovl)  { -	return ovl->manager->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; +	struct mgr_priv_data *mp = get_mgr_priv(ovl->manager); + +	return mp->lcd_config.stallmode;  }  static bool mgr_manual_update(struct omap_overlay_manager *mgr)  { -	return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; +	struct mgr_priv_data *mp = get_mgr_priv(mgr); + +	return mp->lcd_config.stallmode;  }  static int dss_check_settings_low(struct omap_overlay_manager *mgr, @@ -214,7 +235,7 @@ static int dss_check_settings_low(struct omap_overlay_manager *mgr,  		ois[ovl->id] = oi;  	} -	return dss_mgr_check(mgr, mi, &mp->timings, ois); +	return dss_mgr_check(mgr, mi, &mp->timings, &mp->lcd_config, ois);  }  /* @@ -537,7 +558,7 @@ static void dss_ovl_write_regs(struct omap_overlay *ovl)  {  	struct ovl_priv_data *op = get_ovl_priv(ovl);  	struct omap_overlay_info *oi; -	bool ilace, replication; +	bool replication;  	struct mgr_priv_data *mp;  	int r; @@ -550,11 +571,9 @@ static void dss_ovl_write_regs(struct omap_overlay *ovl)  	mp = get_mgr_priv(ovl->manager); -	replication = dss_use_replication(ovl->manager->device, oi->color_mode); - -	ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC; +	replication = dss_ovl_use_replication(mp->lcd_config, oi->color_mode); -	r = dispc_ovl_setup(ovl->id, oi, ilace, replication, &mp->timings); +	r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings);  	if (r) {  		/*  		 * We can't do much here, as this function can be called from @@ -635,6 +654,24 @@ static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr)  	dispc_mgr_set_timings(mgr->id, &mp->timings); +	/* lcd_config parameters */ +	if (dss_mgr_is_lcd(mgr->id)) { +		dispc_mgr_set_io_pad_mode(mp->lcd_config.io_pad_mode); + +		dispc_mgr_enable_stallmode(mgr->id, mp->lcd_config.stallmode); +		dispc_mgr_enable_fifohandcheck(mgr->id, +			mp->lcd_config.fifohandcheck); + +		dispc_mgr_set_clock_div(mgr->id, &mp->lcd_config.clock_info); + +		dispc_mgr_set_tft_data_lines(mgr->id, +			mp->lcd_config.video_port_width); + +		dispc_lcd_enable_signal_polarity(mp->lcd_config.lcden_sig_polarity); + +		dispc_mgr_set_lcd_type_tft(mgr->id); +	} +  	mp->extra_info_dirty = false;  	if (mp->updating)  		mp->shadow_extra_info_dirty = true; @@ -1294,6 +1331,44 @@ void dss_mgr_set_timings(struct omap_overlay_manager *mgr,  	mutex_unlock(&apply_lock);  } +static void dss_apply_mgr_lcd_config(struct omap_overlay_manager *mgr, +		const struct dss_lcd_mgr_config *config) +{ +	struct mgr_priv_data *mp = get_mgr_priv(mgr); + +	mp->lcd_config = *config; +	mp->extra_info_dirty = true; +} + +void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr, +		const struct dss_lcd_mgr_config *config) +{ +	unsigned long flags; +	struct mgr_priv_data *mp = get_mgr_priv(mgr); + +	mutex_lock(&apply_lock); + +	if (mp->enabled) { +		DSSERR("cannot apply lcd config for %s: manager needs to be disabled\n", +			mgr->name); +		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); +} +  int dss_ovl_set_info(struct omap_overlay *ovl,  		struct omap_overlay_info *info)  { diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 397d4eee11bb..5b289c5f695b 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -119,6 +119,97 @@ enum omap_color_component {  	DISPC_COLOR_COMPONENT_UV		= 1 << 1,  }; +enum mgr_reg_fields { +	DISPC_MGR_FLD_ENABLE, +	DISPC_MGR_FLD_STNTFT, +	DISPC_MGR_FLD_GO, +	DISPC_MGR_FLD_TFTDATALINES, +	DISPC_MGR_FLD_STALLMODE, +	DISPC_MGR_FLD_TCKENABLE, +	DISPC_MGR_FLD_TCKSELECTION, +	DISPC_MGR_FLD_CPR, +	DISPC_MGR_FLD_FIFOHANDCHECK, +	/* used to maintain a count of the above fields */ +	DISPC_MGR_FLD_NUM, +}; + +static const struct { +	const char *name; +	u32 vsync_irq; +	u32 framedone_irq; +	u32 sync_lost_irq; +	struct reg_field reg_desc[DISPC_MGR_FLD_NUM]; +} mgr_desc[] = { +	[OMAP_DSS_CHANNEL_LCD] = { +		.name		= "LCD", +		.vsync_irq	= DISPC_IRQ_VSYNC, +		.framedone_irq	= DISPC_IRQ_FRAMEDONE, +		.sync_lost_irq	= DISPC_IRQ_SYNC_LOST, +		.reg_desc	= { +			[DISPC_MGR_FLD_ENABLE]		= { DISPC_CONTROL,  0,  0 }, +			[DISPC_MGR_FLD_STNTFT]		= { DISPC_CONTROL,  3,  3 }, +			[DISPC_MGR_FLD_GO]		= { DISPC_CONTROL,  5,  5 }, +			[DISPC_MGR_FLD_TFTDATALINES]	= { DISPC_CONTROL,  9,  8 }, +			[DISPC_MGR_FLD_STALLMODE]	= { DISPC_CONTROL, 11, 11 }, +			[DISPC_MGR_FLD_TCKENABLE]	= { DISPC_CONFIG,  10, 10 }, +			[DISPC_MGR_FLD_TCKSELECTION]	= { DISPC_CONFIG,  11, 11 }, +			[DISPC_MGR_FLD_CPR]		= { DISPC_CONFIG,  15, 15 }, +			[DISPC_MGR_FLD_FIFOHANDCHECK]	= { DISPC_CONFIG,  16, 16 }, +		}, +	}, +	[OMAP_DSS_CHANNEL_DIGIT] = { +		.name		= "DIGIT", +		.vsync_irq	= DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN, +		.framedone_irq	= 0, +		.sync_lost_irq	= DISPC_IRQ_SYNC_LOST_DIGIT, +		.reg_desc	= { +			[DISPC_MGR_FLD_ENABLE]		= { DISPC_CONTROL,  1,  1 }, +			[DISPC_MGR_FLD_STNTFT]		= { }, +			[DISPC_MGR_FLD_GO]		= { DISPC_CONTROL,  6,  6 }, +			[DISPC_MGR_FLD_TFTDATALINES]	= { }, +			[DISPC_MGR_FLD_STALLMODE]	= { }, +			[DISPC_MGR_FLD_TCKENABLE]	= { DISPC_CONFIG,  12, 12 }, +			[DISPC_MGR_FLD_TCKSELECTION]	= { DISPC_CONFIG,  13, 13 }, +			[DISPC_MGR_FLD_CPR]		= { }, +			[DISPC_MGR_FLD_FIFOHANDCHECK]	= { DISPC_CONFIG,  16, 16 }, +		}, +	}, +	[OMAP_DSS_CHANNEL_LCD2] = { +		.name		= "LCD2", +		.vsync_irq	= DISPC_IRQ_VSYNC2, +		.framedone_irq	= DISPC_IRQ_FRAMEDONE2, +		.sync_lost_irq	= DISPC_IRQ_SYNC_LOST2, +		.reg_desc	= { +			[DISPC_MGR_FLD_ENABLE]		= { DISPC_CONTROL2,  0,  0 }, +			[DISPC_MGR_FLD_STNTFT]		= { DISPC_CONTROL2,  3,  3 }, +			[DISPC_MGR_FLD_GO]		= { DISPC_CONTROL2,  5,  5 }, +			[DISPC_MGR_FLD_TFTDATALINES]	= { DISPC_CONTROL2,  9,  8 }, +			[DISPC_MGR_FLD_STALLMODE]	= { DISPC_CONTROL2, 11, 11 }, +			[DISPC_MGR_FLD_TCKENABLE]	= { DISPC_CONFIG2,  10, 10 }, +			[DISPC_MGR_FLD_TCKSELECTION]	= { DISPC_CONFIG2,  11, 11 }, +			[DISPC_MGR_FLD_CPR]		= { DISPC_CONFIG2,  15, 15 }, +			[DISPC_MGR_FLD_FIFOHANDCHECK]	= { DISPC_CONFIG2,  16, 16 }, +		}, +	}, +	[OMAP_DSS_CHANNEL_LCD3] = { +		.name		= "LCD3", +		.vsync_irq	= DISPC_IRQ_VSYNC3, +		.framedone_irq	= DISPC_IRQ_FRAMEDONE3, +		.sync_lost_irq	= DISPC_IRQ_SYNC_LOST3, +		.reg_desc	= { +			[DISPC_MGR_FLD_ENABLE]		= { DISPC_CONTROL3,  0,  0 }, +			[DISPC_MGR_FLD_STNTFT]		= { DISPC_CONTROL3,  3,  3 }, +			[DISPC_MGR_FLD_GO]		= { DISPC_CONTROL3,  5,  5 }, +			[DISPC_MGR_FLD_TFTDATALINES]	= { DISPC_CONTROL3,  9,  8 }, +			[DISPC_MGR_FLD_STALLMODE]	= { DISPC_CONTROL3, 11, 11 }, +			[DISPC_MGR_FLD_TCKENABLE]	= { DISPC_CONFIG3,  10, 10 }, +			[DISPC_MGR_FLD_TCKSELECTION]	= { DISPC_CONFIG3,  11, 11 }, +			[DISPC_MGR_FLD_CPR]		= { DISPC_CONFIG3,  15, 15 }, +			[DISPC_MGR_FLD_FIFOHANDCHECK]	= { DISPC_CONFIG3,  16, 16 }, +		}, +	}, +}; +  static void _omap_dispc_set_irqs(void);  static inline void dispc_write_reg(const u16 idx, u32 val) @@ -131,6 +222,18 @@ static inline u32 dispc_read_reg(const u16 idx)  	return __raw_readl(dispc.base + idx);  } +static u32 mgr_fld_read(enum omap_channel channel, enum mgr_reg_fields regfld) +{ +	const struct reg_field rfld = mgr_desc[channel].reg_desc[regfld]; +	return REG_GET(rfld.reg, rfld.high, rfld.low); +} + +static void mgr_fld_write(enum omap_channel channel, +					enum mgr_reg_fields regfld, int val) { +	const struct reg_field rfld = mgr_desc[channel].reg_desc[regfld]; +	REG_FLD_MOD(rfld.reg, val, rfld.high, rfld.low); +} +  #define SR(reg) \  	dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg)  #define RR(reg) \ @@ -153,6 +256,10 @@ static void dispc_save_context(void)  		SR(CONTROL2);  		SR(CONFIG2);  	} +	if (dss_has_feature(FEAT_MGR_LCD3)) { +		SR(CONTROL3); +		SR(CONFIG3); +	}  	for (i = 0; i < dss_feat_get_num_mgrs(); i++) {  		SR(DEFAULT_COLOR(i)); @@ -266,6 +373,8 @@ static void dispc_restore_context(void)  		RR(GLOBAL_ALPHA);  	if (dss_has_feature(FEAT_MGR_LCD2))  		RR(CONFIG2); +	if (dss_has_feature(FEAT_MGR_LCD3)) +		RR(CONFIG3);  	for (i = 0; i < dss_feat_get_num_mgrs(); i++) {  		RR(DEFAULT_COLOR(i)); @@ -351,6 +460,8 @@ static void dispc_restore_context(void)  	RR(CONTROL);  	if (dss_has_feature(FEAT_MGR_LCD2))  		RR(CONTROL2); +	if (dss_has_feature(FEAT_MGR_LCD3)) +		RR(CONTROL3);  	/* clear spurious SYNC_LOST_DIGIT interrupts */  	dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT); @@ -387,101 +498,41 @@ void dispc_runtime_put(void)  	WARN_ON(r < 0 && r != -ENOSYS);  } -static inline bool dispc_mgr_is_lcd(enum omap_channel channel) -{ -	if (channel == OMAP_DSS_CHANNEL_LCD || -			channel == OMAP_DSS_CHANNEL_LCD2) -		return true; -	else -		return false; -} -  u32 dispc_mgr_get_vsync_irq(enum omap_channel channel)  { -	switch (channel) { -	case OMAP_DSS_CHANNEL_LCD: -		return DISPC_IRQ_VSYNC; -	case OMAP_DSS_CHANNEL_LCD2: -		return DISPC_IRQ_VSYNC2; -	case OMAP_DSS_CHANNEL_DIGIT: -		return DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; -	default: -		BUG(); -		return 0; -	} +	return mgr_desc[channel].vsync_irq;  }  u32 dispc_mgr_get_framedone_irq(enum omap_channel channel)  { -	switch (channel) { -	case OMAP_DSS_CHANNEL_LCD: -		return DISPC_IRQ_FRAMEDONE; -	case OMAP_DSS_CHANNEL_LCD2: -		return DISPC_IRQ_FRAMEDONE2; -	case OMAP_DSS_CHANNEL_DIGIT: -		return 0; -	default: -		BUG(); -		return 0; -	} +	return mgr_desc[channel].framedone_irq;  }  bool dispc_mgr_go_busy(enum omap_channel channel)  { -	int bit; - -	if (dispc_mgr_is_lcd(channel)) -		bit = 5; /* GOLCD */ -	else -		bit = 6; /* GODIGIT */ - -	if (channel == OMAP_DSS_CHANNEL_LCD2) -		return REG_GET(DISPC_CONTROL2, bit, bit) == 1; -	else -		return REG_GET(DISPC_CONTROL, bit, bit) == 1; +	return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1;  }  void dispc_mgr_go(enum omap_channel channel)  { -	int bit;  	bool enable_bit, go_bit; -	if (dispc_mgr_is_lcd(channel)) -		bit = 0; /* LCDENABLE */ -	else -		bit = 1; /* DIGITALENABLE */ -  	/* if the channel is not enabled, we don't need GO */ -	if (channel == OMAP_DSS_CHANNEL_LCD2) -		enable_bit = REG_GET(DISPC_CONTROL2, bit, bit) == 1; -	else -		enable_bit = REG_GET(DISPC_CONTROL, bit, bit) == 1; +	enable_bit = mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE) == 1;  	if (!enable_bit)  		return; -	if (dispc_mgr_is_lcd(channel)) -		bit = 5; /* GOLCD */ -	else -		bit = 6; /* GODIGIT */ - -	if (channel == OMAP_DSS_CHANNEL_LCD2) -		go_bit = REG_GET(DISPC_CONTROL2, bit, bit) == 1; -	else -		go_bit = REG_GET(DISPC_CONTROL, bit, bit) == 1; +	go_bit = mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1;  	if (go_bit) {  		DSSERR("GO bit not down for channel %d\n", channel);  		return;  	} -	DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" : -		(channel == OMAP_DSS_CHANNEL_LCD2 ? "LCD2" : "DIGIT")); +	DSSDBG("GO %s\n", mgr_desc[channel].name); -	if (channel == OMAP_DSS_CHANNEL_LCD2) -		REG_FLD_MOD(DISPC_CONTROL2, 1, bit, bit); -	else -		REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit); +	mgr_fld_write(channel, DISPC_MGR_FLD_GO, 1);  }  static void dispc_ovl_write_firh_reg(enum omap_plane plane, int reg, u32 value) @@ -832,6 +883,15 @@ void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel)  			chan = 0;  			chan2 = 1;  			break; +		case OMAP_DSS_CHANNEL_LCD3: +			if (dss_has_feature(FEAT_MGR_LCD3)) { +				chan = 0; +				chan2 = 2; +			} else { +				BUG(); +				return; +			} +			break;  		default:  			BUG();  			return; @@ -867,7 +927,14 @@ static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane)  	val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); -	if (dss_has_feature(FEAT_MGR_LCD2)) { +	if (dss_has_feature(FEAT_MGR_LCD3)) { +		if (FLD_GET(val, 31, 30) == 0) +			channel = FLD_GET(val, shift, shift); +		else if (FLD_GET(val, 31, 30) == 1) +			channel = OMAP_DSS_CHANNEL_LCD2; +		else +			channel = OMAP_DSS_CHANNEL_LCD3; +	} else if (dss_has_feature(FEAT_MGR_LCD2)) {  		if (FLD_GET(val, 31, 30) == 0)  			channel = FLD_GET(val, shift, shift);  		else @@ -922,16 +989,10 @@ void dispc_enable_gamma_table(bool enable)  static void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable)  { -	u16 reg; - -	if (channel == OMAP_DSS_CHANNEL_LCD) -		reg = DISPC_CONFIG; -	else if (channel == OMAP_DSS_CHANNEL_LCD2) -		reg = DISPC_CONFIG2; -	else +	if (channel == OMAP_DSS_CHANNEL_DIGIT)  		return; -	REG_FLD_MOD(reg, enable, 15, 15); +	mgr_fld_write(channel, DISPC_MGR_FLD_CPR, enable);  }  static void dispc_mgr_set_cpr_coef(enum omap_channel channel, @@ -939,7 +1000,7 @@ static void dispc_mgr_set_cpr_coef(enum omap_channel channel,  {  	u32 coef_r, coef_g, coef_b; -	if (!dispc_mgr_is_lcd(channel)) +	if (!dss_mgr_is_lcd(channel))  		return;  	coef_r = FLD_VAL(coefs->rr, 31, 22) | FLD_VAL(coefs->rg, 20, 11) | @@ -1798,7 +1859,7 @@ static int check_horiz_timing_omap3(enum omap_channel channel,  	nonactive = t->x_res + t->hfp + t->hsw + t->hbp - out_width;  	pclk = dispc_mgr_pclk_rate(channel); -	if (dispc_mgr_is_lcd(channel)) +	if (dss_mgr_is_lcd(channel))  		lclk = dispc_mgr_lclk_rate(channel);  	else  		lclk = dispc_fclk_rate(); @@ -2086,8 +2147,7 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,  }  int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, -		bool ilace, bool replication, -		const struct omap_video_timings *mgr_timings) +		bool replication, const struct omap_video_timings *mgr_timings)  {  	struct omap_overlay *ovl = omap_dss_get_overlay(plane);  	bool five_taps = true; @@ -2103,6 +2163,7 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,  	u16 out_width, out_height;  	enum omap_channel channel;  	int x_predecim = 1, y_predecim = 1; +	bool ilace = mgr_timings->interlace;  	channel = dispc_ovl_get_channel_out(plane); @@ -2254,14 +2315,9 @@ static void dispc_disable_isr(void *data, u32 mask)  static void _enable_lcd_out(enum omap_channel channel, bool enable)  { -	if (channel == OMAP_DSS_CHANNEL_LCD2) { -		REG_FLD_MOD(DISPC_CONTROL2, enable ? 1 : 0, 0, 0); -		/* flush posted write */ -		dispc_read_reg(DISPC_CONTROL2); -	} else { -		REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0); -		dispc_read_reg(DISPC_CONTROL); -	} +	mgr_fld_write(channel, DISPC_MGR_FLD_ENABLE, enable); +	/* flush posted write */ +	mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);  }  static void dispc_mgr_enable_lcd_out(enum omap_channel channel, bool enable) @@ -2274,12 +2330,9 @@ static void dispc_mgr_enable_lcd_out(enum omap_channel channel, bool enable)  	/* When we disable LCD output, we need to wait until frame is done.  	 * Otherwise the DSS is still working, and turning off the clocks  	 * prevents DSS from going to OFF mode */ -	is_on = channel == OMAP_DSS_CHANNEL_LCD2 ? -			REG_GET(DISPC_CONTROL2, 0, 0) : -			REG_GET(DISPC_CONTROL, 0, 0); +	is_on = mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE); -	irq = channel == OMAP_DSS_CHANNEL_LCD2 ? DISPC_IRQ_FRAMEDONE2 : -			DISPC_IRQ_FRAMEDONE; +	irq = mgr_desc[channel].framedone_irq;  	if (!enable && is_on) {  		init_completion(&frame_done_completion); @@ -2384,21 +2437,12 @@ static void dispc_mgr_enable_digit_out(bool enable)  bool dispc_mgr_is_enabled(enum omap_channel channel)  { -	if (channel == OMAP_DSS_CHANNEL_LCD) -		return !!REG_GET(DISPC_CONTROL, 0, 0); -	else if (channel == OMAP_DSS_CHANNEL_DIGIT) -		return !!REG_GET(DISPC_CONTROL, 1, 1); -	else if (channel == OMAP_DSS_CHANNEL_LCD2) -		return !!REG_GET(DISPC_CONTROL2, 0, 0); -	else { -		BUG(); -		return false; -	} +	return !!mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);  }  void dispc_mgr_enable(enum omap_channel channel, bool enable)  { -	if (dispc_mgr_is_lcd(channel)) +	if (dss_mgr_is_lcd(channel))  		dispc_mgr_enable_lcd_out(channel, enable);  	else if (channel == OMAP_DSS_CHANNEL_DIGIT)  		dispc_mgr_enable_digit_out(enable); @@ -2432,36 +2476,13 @@ void dispc_pck_free_enable(bool enable)  void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable)  { -	if (channel == OMAP_DSS_CHANNEL_LCD2) -		REG_FLD_MOD(DISPC_CONFIG2, enable ? 1 : 0, 16, 16); -	else -		REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16); +	mgr_fld_write(channel, DISPC_MGR_FLD_FIFOHANDCHECK, enable);  } -void dispc_mgr_set_lcd_display_type(enum omap_channel channel, -		enum omap_lcd_display_type type) +void dispc_mgr_set_lcd_type_tft(enum omap_channel channel)  { -	int mode; - -	switch (type) { -	case OMAP_DSS_LCD_DISPLAY_STN: -		mode = 0; -		break; - -	case OMAP_DSS_LCD_DISPLAY_TFT: -		mode = 1; -		break; - -	default: -		BUG(); -		return; -	} - -	if (channel == OMAP_DSS_CHANNEL_LCD2) -		REG_FLD_MOD(DISPC_CONTROL2, mode, 3, 3); -	else -		REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3); +	mgr_fld_write(channel, DISPC_MGR_FLD_STNTFT, 1);  }  void dispc_set_loadmode(enum omap_dss_load_mode mode) @@ -2479,24 +2500,14 @@ static void dispc_mgr_set_trans_key(enum omap_channel ch,  		enum omap_dss_trans_key_type type,  		u32 trans_key)  { -	if (ch == OMAP_DSS_CHANNEL_LCD) -		REG_FLD_MOD(DISPC_CONFIG, type, 11, 11); -	else if (ch == OMAP_DSS_CHANNEL_DIGIT) -		REG_FLD_MOD(DISPC_CONFIG, type, 13, 13); -	else /* OMAP_DSS_CHANNEL_LCD2 */ -		REG_FLD_MOD(DISPC_CONFIG2, type, 11, 11); +	mgr_fld_write(ch, DISPC_MGR_FLD_TCKSELECTION, type);  	dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key);  }  static void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable)  { -	if (ch == OMAP_DSS_CHANNEL_LCD) -		REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10); -	else if (ch == OMAP_DSS_CHANNEL_DIGIT) -		REG_FLD_MOD(DISPC_CONFIG, enable, 12, 12); -	else /* OMAP_DSS_CHANNEL_LCD2 */ -		REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10); +	mgr_fld_write(ch, DISPC_MGR_FLD_TCKENABLE, enable);  }  static void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, @@ -2547,10 +2558,7 @@ void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines)  		return;  	} -	if (channel == OMAP_DSS_CHANNEL_LCD2) -		REG_FLD_MOD(DISPC_CONTROL2, code, 9, 8); -	else -		REG_FLD_MOD(DISPC_CONTROL, code, 9, 8); +	mgr_fld_write(channel, DISPC_MGR_FLD_TFTDATALINES, code);  }  void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode) @@ -2584,10 +2592,7 @@ void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode)  void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable)  { -	if (channel == OMAP_DSS_CHANNEL_LCD2) -		REG_FLD_MOD(DISPC_CONTROL2, enable, 11, 11); -	else -		REG_FLD_MOD(DISPC_CONTROL, enable, 11, 11); +	mgr_fld_write(channel, DISPC_MGR_FLD_STALLMODE, enable);  }  static bool _dispc_mgr_size_ok(u16 width, u16 height) @@ -2627,7 +2632,7 @@ bool dispc_mgr_timings_ok(enum omap_channel channel,  	timings_ok = _dispc_mgr_size_ok(timings->x_res, timings->y_res); -	if (dispc_mgr_is_lcd(channel)) +	if (dss_mgr_is_lcd(channel))  		timings_ok =  timings_ok && _dispc_lcd_timings_ok(timings->hsw,  						timings->hfp, timings->hbp,  						timings->vsw, timings->vfp, @@ -2637,9 +2642,16 @@ bool dispc_mgr_timings_ok(enum omap_channel channel,  }  static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw, -		int hfp, int hbp, int vsw, int vfp, int vbp) +		int hfp, int hbp, int vsw, int vfp, int vbp, +		enum omap_dss_signal_level vsync_level, +		enum omap_dss_signal_level hsync_level, +		enum omap_dss_signal_edge data_pclk_edge, +		enum omap_dss_signal_level de_level, +		enum omap_dss_signal_edge sync_pclk_edge) +  { -	u32 timing_h, timing_v; +	u32 timing_h, timing_v, l; +	bool onoff, rf, ipc;  	if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {  		timing_h = FLD_VAL(hsw-1, 5, 0) | FLD_VAL(hfp-1, 15, 8) | @@ -2657,6 +2669,44 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw,  	dispc_write_reg(DISPC_TIMING_H(channel), timing_h);  	dispc_write_reg(DISPC_TIMING_V(channel), timing_v); + +	switch (data_pclk_edge) { +	case OMAPDSS_DRIVE_SIG_RISING_EDGE: +		ipc = false; +		break; +	case OMAPDSS_DRIVE_SIG_FALLING_EDGE: +		ipc = true; +		break; +	case OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES: +	default: +		BUG(); +	} + +	switch (sync_pclk_edge) { +	case OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES: +		onoff = false; +		rf = false; +		break; +	case OMAPDSS_DRIVE_SIG_FALLING_EDGE: +		onoff = true; +		rf = false; +		break; +	case OMAPDSS_DRIVE_SIG_RISING_EDGE: +		onoff = true; +		rf = true; +		break; +	default: +		BUG(); +	}; + +	l = dispc_read_reg(DISPC_POL_FREQ(channel)); +	l |= FLD_VAL(onoff, 17, 17); +	l |= FLD_VAL(rf, 16, 16); +	l |= FLD_VAL(de_level, 15, 15); +	l |= FLD_VAL(ipc, 14, 14); +	l |= FLD_VAL(hsync_level, 13, 13); +	l |= FLD_VAL(vsync_level, 12, 12); +	dispc_write_reg(DISPC_POL_FREQ(channel), l);  }  /* change name to mode? */ @@ -2674,9 +2724,10 @@ void dispc_mgr_set_timings(enum omap_channel channel,  		return;  	} -	if (dispc_mgr_is_lcd(channel)) { +	if (dss_mgr_is_lcd(channel)) {  		_dispc_mgr_set_lcd_timings(channel, t.hsw, t.hfp, t.hbp, t.vsw, -				t.vfp, t.vbp); +				t.vfp, t.vbp, t.vsync_level, t.hsync_level, +				t.data_pclk_edge, t.de_level, t.sync_pclk_edge);  		xtot = t.x_res + t.hfp + t.hsw + t.hbp;  		ytot = t.y_res + t.vfp + t.vsw + t.vbp; @@ -2687,14 +2738,13 @@ void dispc_mgr_set_timings(enum omap_channel channel,  		DSSDBG("pck %u\n", timings->pixel_clock);  		DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",  			t.hsw, t.hfp, t.hbp, t.vsw, t.vfp, t.vbp); +		DSSDBG("vsync_level %d hsync_level %d data_pclk_edge %d de_level %d sync_pclk_edge %d\n", +			t.vsync_level, t.hsync_level, t.data_pclk_edge, +			t.de_level, t.sync_pclk_edge);  		DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);  	} else { -		enum dss_hdmi_venc_clk_source_select source; - -		source = dss_get_hdmi_venc_clk_source(); - -		if (source == DSS_VENC_TV_CLK) +		if (t.interlace == true)  			t.y_res /= 2;  	} @@ -2780,7 +2830,7 @@ unsigned long dispc_mgr_pclk_rate(enum omap_channel channel)  {  	unsigned long r; -	if (dispc_mgr_is_lcd(channel)) { +	if (dss_mgr_is_lcd(channel)) {  		int pcd;  		u32 l; @@ -2821,12 +2871,32 @@ unsigned long dispc_core_clk_rate(void)  	return fclk / lcd;  } -void dispc_dump_clocks(struct seq_file *s) +static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel channel)  {  	int lcd, pcd; +	enum omap_dss_clk_source lcd_clk_src; + +	seq_printf(s, "- %s -\n", mgr_desc[channel].name); + +	lcd_clk_src = dss_get_lcd_clk_source(channel); + +	seq_printf(s, "%s clk source = %s (%s)\n", mgr_desc[channel].name, +		dss_get_generic_clk_source_name(lcd_clk_src), +		dss_feat_get_clk_source_name(lcd_clk_src)); + +	dispc_mgr_get_lcd_divisor(channel, &lcd, &pcd); + +	seq_printf(s, "lck\t\t%-16lulck div\t%u\n", +		dispc_mgr_lclk_rate(channel), lcd); +	seq_printf(s, "pck\t\t%-16lupck div\t%u\n", +		dispc_mgr_pclk_rate(channel), pcd); +} + +void dispc_dump_clocks(struct seq_file *s) +{ +	int lcd;  	u32 l;  	enum omap_dss_clk_source dispc_clk_src = dss_get_dispc_clk_source(); -	enum omap_dss_clk_source lcd_clk_src;  	if (dispc_runtime_get())  		return; @@ -2847,36 +2917,13 @@ void dispc_dump_clocks(struct seq_file *s)  		seq_printf(s, "lck\t\t%-16lulck div\t%u\n",  				(dispc_fclk_rate()/lcd), lcd);  	} -	seq_printf(s, "- LCD1 -\n"); - -	lcd_clk_src = dss_get_lcd_clk_source(OMAP_DSS_CHANNEL_LCD); - -	seq_printf(s, "lcd1_clk source = %s (%s)\n", -		dss_get_generic_clk_source_name(lcd_clk_src), -		dss_feat_get_clk_source_name(lcd_clk_src)); - -	dispc_mgr_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD, &lcd, &pcd); - -	seq_printf(s, "lck\t\t%-16lulck div\t%u\n", -			dispc_mgr_lclk_rate(OMAP_DSS_CHANNEL_LCD), lcd); -	seq_printf(s, "pck\t\t%-16lupck div\t%u\n", -			dispc_mgr_pclk_rate(OMAP_DSS_CHANNEL_LCD), pcd); -	if (dss_has_feature(FEAT_MGR_LCD2)) { -		seq_printf(s, "- LCD2 -\n"); - -		lcd_clk_src = dss_get_lcd_clk_source(OMAP_DSS_CHANNEL_LCD2); -		seq_printf(s, "lcd2_clk source = %s (%s)\n", -			dss_get_generic_clk_source_name(lcd_clk_src), -			dss_feat_get_clk_source_name(lcd_clk_src)); +	dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD); -		dispc_mgr_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD2, &lcd, &pcd); - -		seq_printf(s, "lck\t\t%-16lulck div\t%u\n", -				dispc_mgr_lclk_rate(OMAP_DSS_CHANNEL_LCD2), lcd); -		seq_printf(s, "pck\t\t%-16lupck div\t%u\n", -				dispc_mgr_pclk_rate(OMAP_DSS_CHANNEL_LCD2), pcd); -	} +	if (dss_has_feature(FEAT_MGR_LCD2)) +		dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD2); +	if (dss_has_feature(FEAT_MGR_LCD3)) +		dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD3);  	dispc_runtime_put();  } @@ -2929,6 +2976,12 @@ void dispc_dump_irqs(struct seq_file *s)  		PIS(ACBIAS_COUNT_STAT2);  		PIS(SYNC_LOST2);  	} +	if (dss_has_feature(FEAT_MGR_LCD3)) { +		PIS(FRAMEDONE3); +		PIS(VSYNC3); +		PIS(ACBIAS_COUNT_STAT3); +		PIS(SYNC_LOST3); +	}  #undef PIS  }  #endif @@ -2940,6 +2993,7 @@ static void dispc_dump_regs(struct seq_file *s)  		[OMAP_DSS_CHANNEL_LCD]		= "LCD",  		[OMAP_DSS_CHANNEL_DIGIT]	= "TV",  		[OMAP_DSS_CHANNEL_LCD2]		= "LCD2", +		[OMAP_DSS_CHANNEL_LCD3]		= "LCD3",  	};  	const char *ovl_names[] = {  		[OMAP_DSS_GFX]		= "GFX", @@ -2972,6 +3026,10 @@ static void dispc_dump_regs(struct seq_file *s)  		DUMPREG(DISPC_CONTROL2);  		DUMPREG(DISPC_CONFIG2);  	} +	if (dss_has_feature(FEAT_MGR_LCD3)) { +		DUMPREG(DISPC_CONTROL3); +		DUMPREG(DISPC_CONFIG3); +	}  #undef DUMPREG @@ -3093,41 +3151,8 @@ static void dispc_dump_regs(struct seq_file *s)  #undef DUMPREG  } -static void _dispc_mgr_set_pol_freq(enum omap_channel channel, bool onoff, -		bool rf, bool ieo, bool ipc, bool ihs, bool ivs, u8 acbi, -		u8 acb) -{ -	u32 l = 0; - -	DSSDBG("onoff %d rf %d ieo %d ipc %d ihs %d ivs %d acbi %d acb %d\n", -			onoff, rf, ieo, ipc, ihs, ivs, acbi, acb); - -	l |= FLD_VAL(onoff, 17, 17); -	l |= FLD_VAL(rf, 16, 16); -	l |= FLD_VAL(ieo, 15, 15); -	l |= FLD_VAL(ipc, 14, 14); -	l |= FLD_VAL(ihs, 13, 13); -	l |= FLD_VAL(ivs, 12, 12); -	l |= FLD_VAL(acbi, 11, 8); -	l |= FLD_VAL(acb, 7, 0); - -	dispc_write_reg(DISPC_POL_FREQ(channel), l); -} - -void dispc_mgr_set_pol_freq(enum omap_channel channel, -		enum omap_panel_config config, u8 acbi, u8 acb) -{ -	_dispc_mgr_set_pol_freq(channel, (config & OMAP_DSS_LCD_ONOFF) != 0, -			(config & OMAP_DSS_LCD_RF) != 0, -			(config & OMAP_DSS_LCD_IEO) != 0, -			(config & OMAP_DSS_LCD_IPC) != 0, -			(config & OMAP_DSS_LCD_IHS) != 0, -			(config & OMAP_DSS_LCD_IVS) != 0, -			acbi, acb); -} -  /* with fck as input clock rate, find dispc dividers that produce req_pck */ -void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck, +void dispc_find_clk_divs(unsigned long req_pck, unsigned long fck,  		struct dispc_clock_info *cinfo)  {  	u16 pcd_min, pcd_max; @@ -3138,9 +3163,6 @@ void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck,  	pcd_min = dss_feat_get_param_min(FEAT_PARAM_DSS_PCD);  	pcd_max = dss_feat_get_param_max(FEAT_PARAM_DSS_PCD); -	if (!is_tft) -		pcd_min = 3; -  	best_pck = 0;  	best_ld = 0;  	best_pd = 0; @@ -3192,15 +3214,13 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,  	return 0;  } -int dispc_mgr_set_clock_div(enum omap_channel channel, +void dispc_mgr_set_clock_div(enum omap_channel channel,  		struct dispc_clock_info *cinfo)  {  	DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div);  	DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div);  	dispc_mgr_set_lcd_divisor(channel, cinfo->lck_div, cinfo->pck_div); - -	return 0;  }  int dispc_mgr_get_clock_div(enum omap_channel channel, @@ -3354,6 +3374,8 @@ static void print_irq_status(u32 status)  	PIS(SYNC_LOST_DIGIT);  	if (dss_has_feature(FEAT_MGR_LCD2))  		PIS(SYNC_LOST2); +	if (dss_has_feature(FEAT_MGR_LCD3)) +		PIS(SYNC_LOST3);  #undef PIS  	printk("\n"); @@ -3450,12 +3472,6 @@ static void dispc_error_worker(struct work_struct *work)  		DISPC_IRQ_VID3_FIFO_UNDERFLOW,  	}; -	static const unsigned sync_lost_bits[] = { -		DISPC_IRQ_SYNC_LOST, -		DISPC_IRQ_SYNC_LOST_DIGIT, -		DISPC_IRQ_SYNC_LOST2, -	}; -  	spin_lock_irqsave(&dispc.irq_lock, flags);  	errors = dispc.error_irqs;  	dispc.error_irqs = 0; @@ -3484,7 +3500,7 @@ static void dispc_error_worker(struct work_struct *work)  		unsigned bit;  		mgr = omap_dss_get_overlay_manager(i); -		bit = sync_lost_bits[i]; +		bit = mgr_desc[i].sync_lost_irq;  		if (bit & errors) {  			struct omap_dss_device *dssdev = mgr->device; @@ -3603,6 +3619,8 @@ static void _omap_dispc_initialize_irq(void)  	dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;  	if (dss_has_feature(FEAT_MGR_LCD2))  		dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2; +	if (dss_has_feature(FEAT_MGR_LCD3)) +		dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST3;  	if (dss_feat_get_num_ovls() > 3)  		dispc.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW; diff --git a/drivers/video/omap2/dss/dispc.h b/drivers/video/omap2/dss/dispc.h index f278080e1063..92d8a9be86fc 100644 --- a/drivers/video/omap2/dss/dispc.h +++ b/drivers/video/omap2/dss/dispc.h @@ -36,6 +36,8 @@  #define DISPC_CONTROL2			0x0238  #define DISPC_CONFIG2			0x0620  #define DISPC_DIVISOR			0x0804 +#define DISPC_CONTROL3                  0x0848 +#define DISPC_CONFIG3                   0x084C  /* DISPC overlay registers */  #define DISPC_OVL_BA0(n)		(DISPC_OVL_BASE(n) + \ @@ -118,6 +120,8 @@ static inline u16 DISPC_DEFAULT_COLOR(enum omap_channel channel)  		return 0x0050;  	case OMAP_DSS_CHANNEL_LCD2:  		return 0x03AC; +	case OMAP_DSS_CHANNEL_LCD3: +		return 0x0814;  	default:  		BUG();  		return 0; @@ -133,6 +137,8 @@ static inline u16 DISPC_TRANS_COLOR(enum omap_channel channel)  		return 0x0058;  	case OMAP_DSS_CHANNEL_LCD2:  		return 0x03B0; +	case OMAP_DSS_CHANNEL_LCD3: +		return 0x0818;  	default:  		BUG();  		return 0; @@ -149,6 +155,8 @@ static inline u16 DISPC_TIMING_H(enum omap_channel channel)  		return 0;  	case OMAP_DSS_CHANNEL_LCD2:  		return 0x0400; +	case OMAP_DSS_CHANNEL_LCD3: +		return 0x0840;  	default:  		BUG();  		return 0; @@ -165,6 +173,8 @@ static inline u16 DISPC_TIMING_V(enum omap_channel channel)  		return 0;  	case OMAP_DSS_CHANNEL_LCD2:  		return 0x0404; +	case OMAP_DSS_CHANNEL_LCD3: +		return 0x0844;  	default:  		BUG();  		return 0; @@ -181,6 +191,8 @@ static inline u16 DISPC_POL_FREQ(enum omap_channel channel)  		return 0;  	case OMAP_DSS_CHANNEL_LCD2:  		return 0x0408; +	case OMAP_DSS_CHANNEL_LCD3: +		return 0x083C;  	default:  		BUG();  		return 0; @@ -197,6 +209,8 @@ static inline u16 DISPC_DIVISORo(enum omap_channel channel)  		return 0;  	case OMAP_DSS_CHANNEL_LCD2:  		return 0x040C; +	case OMAP_DSS_CHANNEL_LCD3: +		return 0x0838;  	default:  		BUG();  		return 0; @@ -213,6 +227,8 @@ static inline u16 DISPC_SIZE_MGR(enum omap_channel channel)  		return 0x0078;  	case OMAP_DSS_CHANNEL_LCD2:  		return 0x03CC; +	case OMAP_DSS_CHANNEL_LCD3: +		return 0x0834;  	default:  		BUG();  		return 0; @@ -229,6 +245,8 @@ static inline u16 DISPC_DATA_CYCLE1(enum omap_channel channel)  		return 0;  	case OMAP_DSS_CHANNEL_LCD2:  		return 0x03C0; +	case OMAP_DSS_CHANNEL_LCD3: +		return 0x0828;  	default:  		BUG();  		return 0; @@ -245,6 +263,8 @@ static inline u16 DISPC_DATA_CYCLE2(enum omap_channel channel)  		return 0;  	case OMAP_DSS_CHANNEL_LCD2:  		return 0x03C4; +	case OMAP_DSS_CHANNEL_LCD3: +		return 0x082C;  	default:  		BUG();  		return 0; @@ -261,6 +281,8 @@ static inline u16 DISPC_DATA_CYCLE3(enum omap_channel channel)  		return 0;  	case OMAP_DSS_CHANNEL_LCD2:  		return 0x03C8; +	case OMAP_DSS_CHANNEL_LCD3: +		return 0x0830;  	default:  		BUG();  		return 0; @@ -277,6 +299,8 @@ static inline u16 DISPC_CPR_COEF_R(enum omap_channel channel)  		return 0;  	case OMAP_DSS_CHANNEL_LCD2:  		return 0x03BC; +	case OMAP_DSS_CHANNEL_LCD3: +		return 0x0824;  	default:  		BUG();  		return 0; @@ -293,6 +317,8 @@ static inline u16 DISPC_CPR_COEF_G(enum omap_channel channel)  		return 0;  	case OMAP_DSS_CHANNEL_LCD2:  		return 0x03B8; +	case OMAP_DSS_CHANNEL_LCD3: +		return 0x0820;  	default:  		BUG();  		return 0; @@ -309,6 +335,8 @@ static inline u16 DISPC_CPR_COEF_B(enum omap_channel channel)  		return 0;  	case OMAP_DSS_CHANNEL_LCD2:  		return 0x03B4; +	case OMAP_DSS_CHANNEL_LCD3: +		return 0x081C;  	default:  		BUG();  		return 0; diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index 249010630370..5bd957e85505 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c @@ -116,7 +116,7 @@ static ssize_t display_timings_store(struct device *dev,  		struct device_attribute *attr, const char *buf, size_t size)  {  	struct omap_dss_device *dssdev = to_dss_device(dev); -	struct omap_video_timings t; +	struct omap_video_timings t = dssdev->panel.timings;  	int r, found;  	if (!dssdev->driver->set_timings || !dssdev->driver->check_timings) @@ -316,44 +316,6 @@ void omapdss_default_get_timings(struct omap_dss_device *dssdev,  }  EXPORT_SYMBOL(omapdss_default_get_timings); -/* Checks if replication logic should be used. Only use for active matrix, - * when overlay is in RGB12U or RGB16 mode, and LCD interface is - * 18bpp or 24bpp */ -bool dss_use_replication(struct omap_dss_device *dssdev, -		enum omap_color_mode mode) -{ -	int bpp; - -	if (mode != OMAP_DSS_COLOR_RGB12U && mode != OMAP_DSS_COLOR_RGB16) -		return false; - -	if (dssdev->type == OMAP_DISPLAY_TYPE_DPI && -			(dssdev->panel.config & OMAP_DSS_LCD_TFT) == 0) -		return false; - -	switch (dssdev->type) { -	case OMAP_DISPLAY_TYPE_DPI: -		bpp = dssdev->phy.dpi.data_lines; -		break; -	case OMAP_DISPLAY_TYPE_HDMI: -	case OMAP_DISPLAY_TYPE_VENC: -	case OMAP_DISPLAY_TYPE_SDI: -		bpp = 24; -		break; -	case OMAP_DISPLAY_TYPE_DBI: -		bpp = dssdev->ctrl.pixel_size; -		break; -	case OMAP_DISPLAY_TYPE_DSI: -		bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); -		break; -	default: -		BUG(); -		return false; -	} - -	return bpp > 16; -} -  void dss_init_device(struct platform_device *pdev,  		struct omap_dss_device *dssdev)  { diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 8c2056c9537b..3266be23fc0d 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -38,6 +38,8 @@  static struct {  	struct regulator *vdds_dsi_reg;  	struct platform_device *dsidev; + +	struct dss_lcd_mgr_config mgr_config;  } dpi;  static struct platform_device *dpi_get_dsidev(enum omap_dss_clk_source clk) @@ -64,7 +66,7 @@ static bool dpi_use_dsi_pll(struct omap_dss_device *dssdev)  		return false;  } -static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, bool is_tft, +static int dpi_set_dsi_clk(struct omap_dss_device *dssdev,  		unsigned long pck_req, unsigned long *fck, int *lck_div,  		int *pck_div)  { @@ -72,8 +74,8 @@ static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, bool is_tft,  	struct dispc_clock_info dispc_cinfo;  	int r; -	r = dsi_pll_calc_clock_div_pck(dpi.dsidev, is_tft, pck_req, -			&dsi_cinfo, &dispc_cinfo); +	r = dsi_pll_calc_clock_div_pck(dpi.dsidev, pck_req, &dsi_cinfo, +			&dispc_cinfo);  	if (r)  		return r; @@ -83,11 +85,7 @@ static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, bool is_tft,  	dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); -	r = dispc_mgr_set_clock_div(dssdev->manager->id, &dispc_cinfo); -	if (r) { -		dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); -		return r; -	} +	dpi.mgr_config.clock_info = dispc_cinfo;  	*fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk;  	*lck_div = dispc_cinfo.lck_div; @@ -96,7 +94,7 @@ static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, bool is_tft,  	return 0;  } -static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, bool is_tft, +static int dpi_set_dispc_clk(struct omap_dss_device *dssdev,  		unsigned long pck_req, unsigned long *fck, int *lck_div,  		int *pck_div)  { @@ -104,7 +102,7 @@ static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, bool is_tft,  	struct dispc_clock_info dispc_cinfo;  	int r; -	r = dss_calc_clock_div(is_tft, pck_req, &dss_cinfo, &dispc_cinfo); +	r = dss_calc_clock_div(pck_req, &dss_cinfo, &dispc_cinfo);  	if (r)  		return r; @@ -112,9 +110,7 @@ static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, bool is_tft,  	if (r)  		return r; -	r = dispc_mgr_set_clock_div(dssdev->manager->id, &dispc_cinfo); -	if (r) -		return r; +	dpi.mgr_config.clock_info = dispc_cinfo;  	*fck = dss_cinfo.fck;  	*lck_div = dispc_cinfo.lck_div; @@ -129,20 +125,14 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)  	int lck_div = 0, pck_div = 0;  	unsigned long fck = 0;  	unsigned long pck; -	bool is_tft;  	int r = 0; -	dispc_mgr_set_pol_freq(dssdev->manager->id, dssdev->panel.config, -			dssdev->panel.acbi, dssdev->panel.acb); - -	is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0; -  	if (dpi_use_dsi_pll(dssdev)) -		r = dpi_set_dsi_clk(dssdev, is_tft, t->pixel_clock * 1000, -				&fck, &lck_div, &pck_div); +		r = dpi_set_dsi_clk(dssdev, t->pixel_clock * 1000, &fck, +				&lck_div, &pck_div);  	else -		r = dpi_set_dispc_clk(dssdev, is_tft, t->pixel_clock * 1000, -				&fck, &lck_div, &pck_div); +		r = dpi_set_dispc_clk(dssdev, t->pixel_clock * 1000, &fck, +				&lck_div, &pck_div);  	if (r)  		return r; @@ -161,19 +151,18 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)  	return 0;  } -static void dpi_basic_init(struct omap_dss_device *dssdev) +static void dpi_config_lcd_manager(struct omap_dss_device *dssdev)  { -	bool is_tft; +	dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; + +	dpi.mgr_config.stallmode = false; +	dpi.mgr_config.fifohandcheck = false; -	is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0; +	dpi.mgr_config.video_port_width = dssdev->phy.dpi.data_lines; -	dispc_mgr_set_io_pad_mode(DSS_IO_PAD_MODE_BYPASS); -	dispc_mgr_enable_stallmode(dssdev->manager->id, false); +	dpi.mgr_config.lcden_sig_polarity = 0; -	dispc_mgr_set_lcd_display_type(dssdev->manager->id, is_tft ? -			OMAP_DSS_LCD_DISPLAY_TFT : OMAP_DSS_LCD_DISPLAY_STN); -	dispc_mgr_set_tft_data_lines(dssdev->manager->id, -			dssdev->phy.dpi.data_lines); +	dss_mgr_set_lcd_config(dssdev->manager, &dpi.mgr_config);  }  int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) @@ -206,8 +195,6 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)  	if (r)  		goto err_get_dispc; -	dpi_basic_init(dssdev); -  	if (dpi_use_dsi_pll(dssdev)) {  		r = dsi_runtime_get(dpi.dsidev);  		if (r) @@ -222,6 +209,8 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)  	if (r)  		goto err_set_mode; +	dpi_config_lcd_manager(dssdev); +  	mdelay(2);  	r = dss_mgr_enable(dssdev->manager); @@ -292,7 +281,6 @@ EXPORT_SYMBOL(dpi_set_timings);  int dpi_check_timings(struct omap_dss_device *dssdev,  			struct omap_video_timings *timings)  { -	bool is_tft;  	int r;  	int lck_div, pck_div;  	unsigned long fck; @@ -305,11 +293,9 @@ int dpi_check_timings(struct omap_dss_device *dssdev,  	if (timings->pixel_clock == 0)  		return -EINVAL; -	is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0; -  	if (dpi_use_dsi_pll(dssdev)) {  		struct dsi_clock_info dsi_cinfo; -		r = dsi_pll_calc_clock_div_pck(dpi.dsidev, is_tft, +		r = dsi_pll_calc_clock_div_pck(dpi.dsidev,  				timings->pixel_clock * 1000,  				&dsi_cinfo, &dispc_cinfo); @@ -319,7 +305,7 @@ int dpi_check_timings(struct omap_dss_device *dssdev,  		fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk;  	} else {  		struct dss_clock_info dss_cinfo; -		r = dss_calc_clock_div(is_tft, timings->pixel_clock * 1000, +		r = dss_calc_clock_div(timings->pixel_clock * 1000,  				&dss_cinfo, &dispc_cinfo);  		if (r) diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 14ce8cc079e3..b07e8864f82f 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -331,6 +331,8 @@ struct dsi_data {  	unsigned num_lanes_used;  	unsigned scp_clk_refcount; + +	struct dss_lcd_mgr_config mgr_config;  };  struct dsi_packet_sent_handler_data { @@ -1085,9 +1087,9 @@ static inline void dsi_enable_pll_clock(struct platform_device *dsidev,  	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);  	if (enable) -		clk_enable(dsi->sys_clk); +		clk_prepare_enable(dsi->sys_clk);  	else -		clk_disable(dsi->sys_clk); +		clk_disable_unprepare(dsi->sys_clk);  	if (enable && dsi->pll_locked) {  		if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1) @@ -1316,7 +1318,7 @@ static int dsi_calc_clock_rates(struct platform_device *dsidev,  	return 0;  } -int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, bool is_tft, +int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev,  		unsigned long req_pck, struct dsi_clock_info *dsi_cinfo,  		struct dispc_clock_info *dispc_cinfo)  { @@ -1335,8 +1337,8 @@ int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, bool is_tft,  			dsi->cache_cinfo.clkin == dss_sys_clk) {  		DSSDBG("DSI clock info found from cache\n");  		*dsi_cinfo = dsi->cache_cinfo; -		dispc_find_clk_divs(is_tft, req_pck, -			dsi_cinfo->dsi_pll_hsdiv_dispc_clk, dispc_cinfo); +		dispc_find_clk_divs(req_pck, dsi_cinfo->dsi_pll_hsdiv_dispc_clk, +			dispc_cinfo);  		return 0;  	} @@ -1402,7 +1404,7 @@ retry:  				match = 1; -				dispc_find_clk_divs(is_tft, req_pck, +				dispc_find_clk_divs(req_pck,  						cur.dsi_pll_hsdiv_dispc_clk,  						&cur_dispc); @@ -3631,17 +3633,14 @@ static void dsi_config_vp_num_line_buffers(struct omap_dss_device *dssdev)  static void dsi_config_vp_sync_events(struct omap_dss_device *dssdev)  {  	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); -	int de_pol = dssdev->panel.dsi_vm_data.vp_de_pol; -	int hsync_pol = dssdev->panel.dsi_vm_data.vp_hsync_pol; -	int vsync_pol = dssdev->panel.dsi_vm_data.vp_vsync_pol;  	bool vsync_end = dssdev->panel.dsi_vm_data.vp_vsync_end;  	bool hsync_end = dssdev->panel.dsi_vm_data.vp_hsync_end;  	u32 r;  	r = dsi_read_reg(dsidev, DSI_CTRL); -	r = FLD_MOD(r, de_pol, 9, 9);		/* VP_DE_POL */ -	r = FLD_MOD(r, hsync_pol, 10, 10);	/* VP_HSYNC_POL */ -	r = FLD_MOD(r, vsync_pol, 11, 11);	/* VP_VSYNC_POL */ +	r = FLD_MOD(r, 1, 9, 9);		/* VP_DE_POL */ +	r = FLD_MOD(r, 1, 10, 10);		/* VP_HSYNC_POL */ +	r = FLD_MOD(r, 1, 11, 11);		/* VP_VSYNC_POL */  	r = FLD_MOD(r, 1, 15, 15);		/* VP_VSYNC_START */  	r = FLD_MOD(r, vsync_end, 16, 16);	/* VP_VSYNC_END */  	r = FLD_MOD(r, 1, 17, 17);		/* VP_HSYNC_START */ @@ -4340,52 +4339,101 @@ EXPORT_SYMBOL(omap_dsi_update);  /* Display funcs */ +static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev) +{ +	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); +	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); +	struct dispc_clock_info dispc_cinfo; +	int r; +	unsigned long long fck; + +	fck = dsi_get_pll_hsdiv_dispc_rate(dsidev); + +	dispc_cinfo.lck_div = dssdev->clocks.dispc.channel.lck_div; +	dispc_cinfo.pck_div = dssdev->clocks.dispc.channel.pck_div; + +	r = dispc_calc_clock_rates(fck, &dispc_cinfo); +	if (r) { +		DSSERR("Failed to calc dispc clocks\n"); +		return r; +	} + +	dsi->mgr_config.clock_info = dispc_cinfo; + +	return 0; +} +  static int dsi_display_init_dispc(struct omap_dss_device *dssdev)  { +	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); +	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); +	struct omap_video_timings timings;  	int r; +	u32 irq = 0;  	if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) {  		u16 dw, dh; -		u32 irq; -		struct omap_video_timings timings = { -			.hsw		= 1, -			.hfp		= 1, -			.hbp		= 1, -			.vsw		= 1, -			.vfp		= 0, -			.vbp		= 0, -		};  		dssdev->driver->get_resolution(dssdev, &dw, &dh); +  		timings.x_res = dw;  		timings.y_res = dh; +		timings.hsw = 1; +		timings.hfp = 1; +		timings.hbp = 1; +		timings.vsw = 1; +		timings.vfp = 0; +		timings.vbp = 0; -		irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ? -			DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2; +		irq = dispc_mgr_get_framedone_irq(dssdev->manager->id);  		r = omap_dispc_register_isr(dsi_framedone_irq_callback,  			(void *) dssdev, irq);  		if (r) {  			DSSERR("can't get FRAMEDONE irq\n"); -			return r; +			goto err;  		} -		dispc_mgr_enable_stallmode(dssdev->manager->id, true); -		dispc_mgr_enable_fifohandcheck(dssdev->manager->id, 1); - -		dss_mgr_set_timings(dssdev->manager, &timings); +		dsi->mgr_config.stallmode = true; +		dsi->mgr_config.fifohandcheck = true;  	} else { -		dispc_mgr_enable_stallmode(dssdev->manager->id, false); -		dispc_mgr_enable_fifohandcheck(dssdev->manager->id, 0); +		timings = dssdev->panel.timings; -		dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings); +		dsi->mgr_config.stallmode = false; +		dsi->mgr_config.fifohandcheck = false;  	} -		dispc_mgr_set_lcd_display_type(dssdev->manager->id, -			OMAP_DSS_LCD_DISPLAY_TFT); -		dispc_mgr_set_tft_data_lines(dssdev->manager->id, -			dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt)); +	/* +	 * override interlace, logic level and edge related parameters in +	 * omap_video_timings with default values +	 */ +	timings.interlace = false; +	timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH; +	timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH; +	timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; +	timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH; +	timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; + +	dss_mgr_set_timings(dssdev->manager, &timings); + +	r = dsi_configure_dispc_clocks(dssdev); +	if (r) +		goto err1; + +	dsi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; +	dsi->mgr_config.video_port_width = +			dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); +	dsi->mgr_config.lcden_sig_polarity = 0; + +	dss_mgr_set_lcd_config(dssdev->manager, &dsi->mgr_config); +  	return 0; +err1: +	if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) +		omap_dispc_unregister_isr(dsi_framedone_irq_callback, +			(void *) dssdev, irq); +err: +	return r;  }  static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev) @@ -4393,8 +4441,7 @@ static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev)  	if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) {  		u32 irq; -		irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ? -			DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2; +		irq = dispc_mgr_get_framedone_irq(dssdev->manager->id);  		omap_dispc_unregister_isr(dsi_framedone_irq_callback,  			(void *) dssdev, irq); @@ -4426,33 +4473,6 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)  	return 0;  } -static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev) -{ -	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); -	struct dispc_clock_info dispc_cinfo; -	int r; -	unsigned long long fck; - -	fck = dsi_get_pll_hsdiv_dispc_rate(dsidev); - -	dispc_cinfo.lck_div = dssdev->clocks.dispc.channel.lck_div; -	dispc_cinfo.pck_div = dssdev->clocks.dispc.channel.pck_div; - -	r = dispc_calc_clock_rates(fck, &dispc_cinfo); -	if (r) { -		DSSERR("Failed to calc dispc clocks\n"); -		return r; -	} - -	r = dispc_mgr_set_clock_div(dssdev->manager->id, &dispc_cinfo); -	if (r) { -		DSSERR("Failed to set dispc clocks\n"); -		return r; -	} - -	return 0; -} -  static int dsi_display_init_dsi(struct omap_dss_device *dssdev)  {  	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); @@ -4474,10 +4494,6 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)  	DSSDBG("PLL OK\n"); -	r = dsi_configure_dispc_clocks(dssdev); -	if (r) -		goto err2; -  	r = dsi_cio_init(dssdev);  	if (r)  		goto err2; diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index d2b57197b292..04b4586113e3 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -388,7 +388,8 @@ void dss_select_lcd_clk_source(enum omap_channel channel,  		dsi_wait_pll_hsdiv_dispc_active(dsidev);  		break;  	case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: -		BUG_ON(channel != OMAP_DSS_CHANNEL_LCD2); +		BUG_ON(channel != OMAP_DSS_CHANNEL_LCD2 && +		       channel != OMAP_DSS_CHANNEL_LCD3);  		b = 1;  		dsidev = dsi_get_dsidev_from_id(1);  		dsi_wait_pll_hsdiv_dispc_active(dsidev); @@ -398,10 +399,12 @@ void dss_select_lcd_clk_source(enum omap_channel channel,  		return;  	} -	pos = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 12; +	pos = channel == OMAP_DSS_CHANNEL_LCD ? 0 : +	     (channel == OMAP_DSS_CHANNEL_LCD2 ? 12 : 19);  	REG_FLD_MOD(DSS_CONTROL, b, pos, pos);	/* LCDx_CLK_SWITCH */ -	ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1; +	ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : +	    (channel == OMAP_DSS_CHANNEL_LCD2 ? 1 : 2);  	dss.lcd_clk_source[ix] = clk_src;  } @@ -418,7 +421,8 @@ enum omap_dss_clk_source dss_get_dsi_clk_source(int dsi_module)  enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)  {  	if (dss_has_feature(FEAT_LCD_CLK_SRC)) { -		int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1; +		int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : +			(channel == OMAP_DSS_CHANNEL_LCD2 ? 1 : 2);  		return dss.lcd_clk_source[ix];  	} else {  		/* LCD_CLK source is the same as DISPC_FCLK source for @@ -502,8 +506,7 @@ unsigned long dss_get_dpll4_rate(void)  		return 0;  } -int dss_calc_clock_div(bool is_tft, unsigned long req_pck, -		struct dss_clock_info *dss_cinfo, +int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,  		struct dispc_clock_info *dispc_cinfo)  {  	unsigned long prate; @@ -551,7 +554,7 @@ retry:  		fck = clk_get_rate(dss.dss_clk);  		fck_div = 1; -		dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc); +		dispc_find_clk_divs(req_pck, fck, &cur_dispc);  		match = 1;  		best_dss.fck = fck; @@ -581,7 +584,7 @@ retry:  			match = 1; -			dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc); +			dispc_find_clk_divs(req_pck, fck, &cur_dispc);  			if (abs(cur_dispc.pck - req_pck) <  					abs(best_dispc.pck - req_pck)) { diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index dd1092ceaeef..f67afe76f217 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -152,6 +152,25 @@ struct dsi_clock_info {  	u16 lp_clk_div;  }; +struct reg_field { +	u16 reg; +	u8 high; +	u8 low; +}; + +struct dss_lcd_mgr_config { +	enum dss_io_pad_mode io_pad_mode; + +	bool stallmode; +	bool fifohandcheck; + +	struct dispc_clock_info clock_info; + +	int video_port_width; + +	int lcden_sig_polarity; +}; +  struct seq_file;  struct platform_device; @@ -188,6 +207,8 @@ int dss_mgr_set_device(struct omap_overlay_manager *mgr,  int dss_mgr_unset_device(struct omap_overlay_manager *mgr);  void dss_mgr_set_timings(struct omap_overlay_manager *mgr,  		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);  bool dss_ovl_is_enabled(struct omap_overlay *ovl); @@ -210,8 +231,6 @@ void 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); -bool dss_use_replication(struct omap_dss_device *dssdev, -		enum omap_color_mode mode);  /* manager */  int dss_init_overlay_managers(struct platform_device *pdev); @@ -223,8 +242,18 @@ int dss_mgr_check_timings(struct omap_overlay_manager *mgr,  int dss_mgr_check(struct omap_overlay_manager *mgr,  		struct omap_overlay_manager_info *info,  		const struct omap_video_timings *mgr_timings, +		const struct dss_lcd_mgr_config *config,  		struct omap_overlay_info **overlay_infos); +static inline bool dss_mgr_is_lcd(enum omap_channel id) +{ +	if (id == OMAP_DSS_CHANNEL_LCD || id == OMAP_DSS_CHANNEL_LCD2 || +			id == OMAP_DSS_CHANNEL_LCD3) +		return true; +	else +		return false; +} +  /* overlay */  void dss_init_overlays(struct platform_device *pdev);  void dss_uninit_overlays(struct platform_device *pdev); @@ -234,6 +263,8 @@ 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);  /* DSS */  int dss_init_platform_driver(void) __init; @@ -268,8 +299,7 @@ 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(bool is_tft, unsigned long req_pck, -		struct dss_clock_info *dss_cinfo, +int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,  		struct dispc_clock_info *dispc_cinfo);  /* SDI */ @@ -296,7 +326,7 @@ u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt);  unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev);  int dsi_pll_set_clock_div(struct platform_device *dsidev,  		struct dsi_clock_info *cinfo); -int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, bool is_tft, +int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev,  		unsigned long req_pck, struct dsi_clock_info *cinfo,  		struct dispc_clock_info *dispc_cinfo);  int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk, @@ -330,7 +360,7 @@ static inline int dsi_pll_set_clock_div(struct platform_device *dsidev,  	return -ENODEV;  }  static inline int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, -		bool is_tft, unsigned long req_pck, +		unsigned long req_pck,  		struct dsi_clock_info *dsi_cinfo,  		struct dispc_clock_info *dispc_cinfo)  { @@ -387,7 +417,7 @@ void dispc_set_loadmode(enum omap_dss_load_mode mode);  bool dispc_mgr_timings_ok(enum omap_channel channel,  		const struct omap_video_timings *timings);  unsigned long dispc_fclk_rate(void); -void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck, +void dispc_find_clk_divs(unsigned long req_pck, unsigned long fck,  		struct dispc_clock_info *cinfo);  int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,  		struct dispc_clock_info *cinfo); @@ -398,8 +428,7 @@ 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 ilace, bool replication, -		const struct omap_video_timings *mgr_timings); +		bool replication, const struct omap_video_timings *mgr_timings);  int dispc_ovl_enable(enum omap_plane plane, bool enable);  void dispc_ovl_set_channel_out(enum omap_plane plane,  		enum omap_channel channel); @@ -415,16 +444,13 @@ bool dispc_mgr_is_channel_enabled(enum omap_channel channel);  void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode);  void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable);  void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines); -void dispc_mgr_set_lcd_display_type(enum omap_channel channel, -		enum omap_lcd_display_type type); +void dispc_mgr_set_lcd_type_tft(enum omap_channel channel);  void dispc_mgr_set_timings(enum omap_channel channel,  		struct omap_video_timings *timings); -void dispc_mgr_set_pol_freq(enum omap_channel channel, -		enum omap_panel_config config, u8 acbi, u8 acb);  unsigned long dispc_mgr_lclk_rate(enum omap_channel channel);  unsigned long dispc_mgr_pclk_rate(enum omap_channel channel);  unsigned long dispc_core_clk_rate(void); -int dispc_mgr_set_clock_div(enum omap_channel channel, +void dispc_mgr_set_clock_div(enum omap_channel channel,  		struct dispc_clock_info *cinfo);  int dispc_mgr_get_clock_div(enum omap_channel channel,  		struct dispc_clock_info *cinfo); diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index bdf469f080e7..996ffcbfed58 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h @@ -24,9 +24,9 @@  #include "ti_hdmi.h"  #endif -#define MAX_DSS_MANAGERS	3 +#define MAX_DSS_MANAGERS	4  #define MAX_DSS_OVERLAYS	4 -#define MAX_DSS_LCD_MANAGERS	2 +#define MAX_DSS_LCD_MANAGERS	3  #define MAX_NUM_DSI		2  /* DSS has feature id */ @@ -36,6 +36,7 @@ enum dss_feat_id {  	FEAT_PCKFREEENABLE,  	FEAT_FUNCGATED,  	FEAT_MGR_LCD2, +	FEAT_MGR_LCD3,  	FEAT_LINEBUFFERSPLIT,  	FEAT_ROWREPEATENABLE,  	FEAT_RESIZECONF, diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 26a2430a7028..060216fdc578 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -78,43 +78,214 @@ static struct {   */  static const struct hdmi_config cea_timings[] = { -{ {640, 480, 25200, 96, 16, 48, 2, 10, 33, 0, 0, 0}, {1, HDMI_HDMI} }, -{ {720, 480, 27027, 62, 16, 60, 6, 9, 30, 0, 0, 0}, {2, HDMI_HDMI} }, -{ {1280, 720, 74250, 40, 110, 220, 5, 5, 20, 1, 1, 0}, {4, HDMI_HDMI} }, -{ {1920, 540, 74250, 44, 88, 148, 5, 2, 15, 1, 1, 1}, {5, HDMI_HDMI} }, -{ {1440, 240, 27027, 124, 38, 114, 3, 4, 15, 0, 0, 1}, {6, HDMI_HDMI} }, -{ {1920, 1080, 148500, 44, 88, 148, 5, 4, 36, 1, 1, 0}, {16, HDMI_HDMI} }, -{ {720, 576, 27000, 64, 12, 68, 5, 5, 39, 0, 0, 0}, {17, HDMI_HDMI} }, -{ {1280, 720, 74250, 40, 440, 220, 5, 5, 20, 1, 1, 0}, {19, HDMI_HDMI} }, -{ {1920, 540, 74250, 44, 528, 148, 5, 2, 15, 1, 1, 1}, {20, HDMI_HDMI} }, -{ {1440, 288, 27000, 126, 24, 138, 3, 2, 19, 0, 0, 1}, {21, HDMI_HDMI} }, -{ {1440, 576, 54000, 128, 24, 136, 5, 5, 39, 0, 0, 0}, {29, HDMI_HDMI} }, -{ {1920, 1080, 148500, 44, 528, 148, 5, 4, 36, 1, 1, 0}, {31, HDMI_HDMI} }, -{ {1920, 1080, 74250, 44, 638, 148, 5, 4, 36, 1, 1, 0}, {32, HDMI_HDMI} }, -{ {2880, 480, 108108, 248, 64, 240, 6, 9, 30, 0, 0, 0}, {35, HDMI_HDMI} }, -{ {2880, 576, 108000, 256, 48, 272, 5, 5, 39, 0, 0, 0}, {37, HDMI_HDMI} }, +	{ +		{ 640, 480, 25200, 96, 16, 48, 2, 10, 33, +			OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, +			false, }, +		{ 1, HDMI_HDMI }, +	}, +	{ +		{ 720, 480, 27027, 62, 16, 60, 6, 9, 30, +			OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, +			false, }, +		{ 2, HDMI_HDMI }, +	}, +	{ +		{ 1280, 720, 74250, 40, 110, 220, 5, 5, 20, +			OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, +			false, }, +		{ 4, HDMI_HDMI }, +	}, +	{ +		{ 1920, 540, 74250, 44, 88, 148, 5, 2, 15, +			OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, +			true, }, +		{ 5, HDMI_HDMI }, +	}, +	{ +		{ 1440, 240, 27027, 124, 38, 114, 3, 4, 15, +			OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, +			true, }, +		{ 6, HDMI_HDMI }, +	}, +	{ +		{ 1920, 1080, 148500, 44, 88, 148, 5, 4, 36, +			OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, +			false, }, +		{ 16, HDMI_HDMI }, +	}, +	{ +		{ 720, 576, 27000, 64, 12, 68, 5, 5, 39, +			OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, +			false, }, +		{ 17, HDMI_HDMI }, +	}, +	{ +		{ 1280, 720, 74250, 40, 440, 220, 5, 5, 20, +			OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, +			false, }, +		{ 19, HDMI_HDMI }, +	}, +	{ +		{ 1920, 540, 74250, 44, 528, 148, 5, 2, 15, +			OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, +			true, }, +		{ 20, HDMI_HDMI }, +	}, +	{ +		{ 1440, 288, 27000, 126, 24, 138, 3, 2, 19, +			OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, +			true, }, +		{ 21, HDMI_HDMI }, +	}, +	{ +		{ 1440, 576, 54000, 128, 24, 136, 5, 5, 39, +			OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, +			false, }, +		{ 29, HDMI_HDMI }, +	}, +	{ +		{ 1920, 1080, 148500, 44, 528, 148, 5, 4, 36, +			OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, +			false, }, +		{ 31, HDMI_HDMI }, +	}, +	{ +		{ 1920, 1080, 74250, 44, 638, 148, 5, 4, 36, +			OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, +			false, }, +		{ 32, HDMI_HDMI }, +	}, +	{ +		{ 2880, 480, 108108, 248, 64, 240, 6, 9, 30, +			OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, +			false, }, +		{ 35, HDMI_HDMI }, +	}, +	{ +		{ 2880, 576, 108000, 256, 48, 272, 5, 5, 39, +			OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, +			false, }, +		{ 37, HDMI_HDMI }, +	},  }; +  static const struct hdmi_config vesa_timings[] = {  /* VESA From Here */ -{ {640, 480, 25175, 96, 16, 48, 2 , 11, 31, 0, 0, 0}, {4, HDMI_DVI} }, -{ {800, 600, 40000, 128, 40, 88, 4 , 1, 23, 1, 1, 0}, {9, HDMI_DVI} }, -{ {848, 480, 33750, 112, 16, 112, 8 , 6, 23, 1, 1, 0}, {0xE, HDMI_DVI} }, -{ {1280, 768, 79500, 128, 64, 192, 7 , 3, 20, 1, 0, 0}, {0x17, HDMI_DVI} }, -{ {1280, 800, 83500, 128, 72, 200, 6 , 3, 22, 1, 0, 0}, {0x1C, HDMI_DVI} }, -{ {1360, 768, 85500, 112, 64, 256, 6 , 3, 18, 1, 1, 0}, {0x27, HDMI_DVI} }, -{ {1280, 960, 108000, 112, 96, 312, 3 , 1, 36, 1, 1, 0}, {0x20, HDMI_DVI} }, -{ {1280, 1024, 108000, 112, 48, 248, 3 , 1, 38, 1, 1, 0}, {0x23, HDMI_DVI} }, -{ {1024, 768, 65000, 136, 24, 160, 6, 3, 29, 0, 0, 0}, {0x10, HDMI_DVI} }, -{ {1400, 1050, 121750, 144, 88, 232, 4, 3, 32, 1, 0, 0}, {0x2A, HDMI_DVI} }, -{ {1440, 900, 106500, 152, 80, 232, 6, 3, 25, 1, 0, 0}, {0x2F, HDMI_DVI} }, -{ {1680, 1050, 146250, 176 , 104, 280, 6, 3, 30, 1, 0, 0}, {0x3A, HDMI_DVI} }, -{ {1366, 768, 85500, 143, 70, 213, 3, 3, 24, 1, 1, 0}, {0x51, HDMI_DVI} }, -{ {1920, 1080, 148500, 44, 148, 80, 5, 4, 36, 1, 1, 0}, {0x52, HDMI_DVI} }, -{ {1280, 768, 68250, 32, 48, 80, 7, 3, 12, 0, 1, 0}, {0x16, HDMI_DVI} }, -{ {1400, 1050, 101000, 32, 48, 80, 4, 3, 23, 0, 1, 0}, {0x29, HDMI_DVI} }, -{ {1680, 1050, 119000, 32, 48, 80, 6, 3, 21, 0, 1, 0}, {0x39, HDMI_DVI} }, -{ {1280, 800, 79500, 32, 48, 80, 6, 3, 14, 0, 1, 0}, {0x1B, HDMI_DVI} }, -{ {1280, 720, 74250, 40, 110, 220, 5, 5, 20, 1, 1, 0}, {0x55, HDMI_DVI} } +	{ +		{ 640, 480, 25175, 96, 16, 48, 2, 11, 31, +			OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, +			false, }, +		{ 4, HDMI_DVI }, +	}, +	{ +		{ 800, 600, 40000, 128, 40, 88, 4, 1, 23, +			OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, +			false, }, +		{ 9, HDMI_DVI }, +	}, +	{ +		{ 848, 480, 33750, 112, 16, 112, 8, 6, 23, +			OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, +			false, }, +		{ 0xE, HDMI_DVI }, +	}, +	{ +		{ 1280, 768, 79500, 128, 64, 192, 7, 3, 20, +			OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW, +			false, }, +		{ 0x17, HDMI_DVI }, +	}, +	{ +		{ 1280, 800, 83500, 128, 72, 200, 6, 3, 22, +			OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW, +			false, }, +		{ 0x1C, HDMI_DVI }, +	}, +	{ +		{ 1360, 768, 85500, 112, 64, 256, 6, 3, 18, +			OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, +			false, }, +		{ 0x27, HDMI_DVI }, +	}, +	{ +		{ 1280, 960, 108000, 112, 96, 312, 3, 1, 36, +			OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, +			false, }, +		{ 0x20, HDMI_DVI }, +	}, +	{ +		{ 1280, 1024, 108000, 112, 48, 248, 3, 1, 38, +			OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, +			false, }, +		{ 0x23, HDMI_DVI }, +	}, +	{ +		{ 1024, 768, 65000, 136, 24, 160, 6, 3, 29, +			OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, +			false, }, +		{ 0x10, HDMI_DVI }, +	}, +	{ +		{ 1400, 1050, 121750, 144, 88, 232, 4, 3, 32, +			OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW, +			false, }, +		{ 0x2A, HDMI_DVI }, +	}, +	{ +		{ 1440, 900, 106500, 152, 80, 232, 6, 3, 25, +			OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW, +			false, }, +		{ 0x2F, HDMI_DVI }, +	}, +	{ +		{ 1680, 1050, 146250, 176 , 104, 280, 6, 3, 30, +			OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW, +			false, }, +		{ 0x3A, HDMI_DVI }, +	}, +	{ +		{ 1366, 768, 85500, 143, 70, 213, 3, 3, 24, +			OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, +			false, }, +		{ 0x51, HDMI_DVI }, +	}, +	{ +		{ 1920, 1080, 148500, 44, 148, 80, 5, 4, 36, +			OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, +			false, }, +		{ 0x52, HDMI_DVI }, +	}, +	{ +		{ 1280, 768, 68250, 32, 48, 80, 7, 3, 12, +			OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH, +			false, }, +		{ 0x16, HDMI_DVI }, +	}, +	{ +		{ 1400, 1050, 101000, 32, 48, 80, 4, 3, 23, +			OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH, +			false, }, +		{ 0x29, HDMI_DVI }, +	}, +	{ +		{ 1680, 1050, 119000, 32, 48, 80, 6, 3, 21, +			OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH, +			false, }, +		{ 0x39, HDMI_DVI }, +	}, +	{ +		{ 1280, 800, 79500, 32, 48, 80, 6, 3, 14, +			OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH, +			false, }, +		{ 0x1B, HDMI_DVI }, +	}, +	{ +		{ 1280, 720, 74250, 40, 110, 220, 5, 5, 20, +			OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, +			false, }, +		{ 0x55, HDMI_DVI }, +	},  };  static int hdmi_runtime_get(void) @@ -179,7 +350,7 @@ static const struct hdmi_config *hdmi_get_timings(void)  }  static bool hdmi_timings_compare(struct omap_video_timings *timing1, -				const struct hdmi_video_timings *timing2) +				const struct omap_video_timings *timing2)  {  	int timing1_vsync, timing1_hsync, timing2_vsync, timing2_hsync; @@ -758,6 +929,7 @@ 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(); @@ -785,7 +957,7 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)  static int hdmi_runtime_suspend(struct device *dev)  { -	clk_disable(hdmi.sys_clk); +	clk_disable_unprepare(hdmi.sys_clk);  	dispc_runtime_put(); @@ -800,7 +972,7 @@ static int hdmi_runtime_resume(struct device *dev)  	if (r < 0)  		return r; -	clk_enable(hdmi.sys_clk); +	clk_prepare_enable(hdmi.sys_clk);  	return 0;  } diff --git a/drivers/video/omap2/dss/hdmi_panel.c b/drivers/video/omap2/dss/hdmi_panel.c index 1179e3c4b1c7..e10844faadf9 100644 --- a/drivers/video/omap2/dss/hdmi_panel.c +++ b/drivers/video/omap2/dss/hdmi_panel.c @@ -43,10 +43,11 @@ static int hdmi_panel_probe(struct omap_dss_device *dssdev)  {  	DSSDBG("ENTER hdmi_panel_probe\n"); -	dssdev->panel.config = OMAP_DSS_LCD_TFT | -			OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS; - -	dssdev->panel.timings = (struct omap_video_timings){640, 480, 25175, 96, 16, 48, 2 , 11, 31}; +	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, +			};  	DSSDBG("hdmi_panel_probe x_res= %d y_res = %d\n",  		dssdev->panel.timings.x_res, diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 0cbcde4c688a..53710fadc82d 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -500,16 +500,12 @@ 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 (mgr->device->type == OMAP_DISPLAY_TYPE_VENC)  		irq = DISPC_IRQ_EVSYNC_ODD; -	} else if (mgr->device->type == OMAP_DISPLAY_TYPE_HDMI) { +	else if (mgr->device->type == OMAP_DISPLAY_TYPE_HDMI)  		irq = DISPC_IRQ_EVSYNC_EVEN; -	} else { -		if (mgr->id == OMAP_DSS_CHANNEL_LCD) -			irq = DISPC_IRQ_VSYNC; -		else -			irq = DISPC_IRQ_VSYNC2; -	} +	else +		irq = dispc_mgr_get_vsync_irq(mgr->id);  	r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); @@ -545,6 +541,10 @@ int dss_init_overlay_managers(struct platform_device *pdev)  			mgr->name = "lcd2";  			mgr->id = OMAP_DSS_CHANNEL_LCD2;  			break; +		case 3: +			mgr->name = "lcd3"; +			mgr->id = OMAP_DSS_CHANNEL_LCD3; +			break;  		}  		mgr->set_device = &dss_mgr_set_device; @@ -665,9 +665,40 @@ int dss_mgr_check_timings(struct omap_overlay_manager *mgr,  	return 0;  } +static int dss_mgr_check_lcd_config(struct omap_overlay_manager *mgr, +		const struct dss_lcd_mgr_config *config) +{ +	struct dispc_clock_info cinfo = config->clock_info; +	int dl = config->video_port_width; +	bool stallmode = config->stallmode; +	bool fifohandcheck = config->fifohandcheck; + +	if (cinfo.lck_div < 1 || cinfo.lck_div > 255) +		return -EINVAL; + +	if (cinfo.pck_div < 1 || cinfo.pck_div > 255) +		return -EINVAL; + +	if (dl != 12 && dl != 16 && dl != 18 && dl != 24) +		return -EINVAL; + +	/* fifohandcheck should be used only with stallmode */ +	if (stallmode == false && fifohandcheck == true) +		return -EINVAL; + +	/* +	 * io pad mode can be only checked by using dssdev connected to the +	 * manager. Ignore checking these for now, add checks when manager +	 * is capable of holding information related to the connected interface +	 */ + +	return 0; +} +  int dss_mgr_check(struct omap_overlay_manager *mgr,  		struct omap_overlay_manager_info *info,  		const struct omap_video_timings *mgr_timings, +		const struct dss_lcd_mgr_config *lcd_config,  		struct omap_overlay_info **overlay_infos)  {  	struct omap_overlay *ovl; @@ -683,6 +714,10 @@ int dss_mgr_check(struct omap_overlay_manager *mgr,  	if (r)  		return r; +	r = dss_mgr_check_lcd_config(mgr, lcd_config); +	if (r) +		return r; +  	list_for_each_entry(ovl, &mgr->overlays, list) {  		struct omap_overlay_info *oi;  		int r; diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index b0ba60f88dd2..952c6fad9a81 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c @@ -528,14 +528,24 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)  	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_OVL_MGR_LCD); -	tv_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_TV); +	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_OVL_MGR_LCD2); +		lcd2_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_LCD2); -	if (dssdev->channel == 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); @@ -677,3 +687,16 @@ int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info,  	return 0;  } + +/* + * Checks if replication logic should be used. Only use when overlay is in + * RGB12U or RGB16 mode, and video port width interface is 18bpp or 24bpp + */ +bool dss_ovl_use_replication(struct dss_lcd_mgr_config config, +		enum omap_color_mode mode) +{ +	if (mode != OMAP_DSS_COLOR_RGB12U && mode != OMAP_DSS_COLOR_RGB16) +		return false; + +	return config.video_port_width > 16; +} diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index 7985fa12b9b4..7c087424b634 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c @@ -300,10 +300,11 @@ void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,  }  EXPORT_SYMBOL(omap_rfbi_write_pixels); -static void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width, +static int rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width,  		u16 height, void (*callback)(void *data), void *data)  {  	u32 l; +	int r;  	struct omap_video_timings timings = {  		.hsw		= 1,  		.hfp		= 1, @@ -322,7 +323,9 @@ static void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width,  	dss_mgr_set_timings(dssdev->manager, &timings); -	dispc_mgr_enable(dssdev->manager->id, true); +	r = dss_mgr_enable(dssdev->manager); +	if (r) +		return r;  	rfbi.framedone_callback = callback;  	rfbi.framedone_callback_data = data; @@ -335,6 +338,8 @@ static void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width,  		l = FLD_MOD(l, 1, 4, 4); /* ITE */  	rfbi_write_reg(RFBI_CONTROL, l); + +	return 0;  }  static void framedone_callback(void *data, u32 mask) @@ -814,8 +819,11 @@ int omap_rfbi_update(struct omap_dss_device *dssdev,  		u16 x, u16 y, u16 w, u16 h,  		void (*callback)(void *), void *data)  { -	rfbi_transfer_area(dssdev, w, h, callback, data); -	return 0; +	int r; + +	r = rfbi_transfer_area(dssdev, w, h, callback, data); + +	return r;  }  EXPORT_SYMBOL(omap_rfbi_update); @@ -859,6 +867,22 @@ static void rfbi_dump_regs(struct seq_file *s)  #undef DUMPREG  } +static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev) +{ +	struct dss_lcd_mgr_config mgr_config; + +	mgr_config.io_pad_mode = DSS_IO_PAD_MODE_RFBI; + +	mgr_config.stallmode = true; +	/* Do we need fifohandcheck for RFBI? */ +	mgr_config.fifohandcheck = false; + +	mgr_config.video_port_width = dssdev->ctrl.pixel_size; +	mgr_config.lcden_sig_polarity = 0; + +	dss_mgr_set_lcd_config(dssdev->manager, &mgr_config); +} +  int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)  {  	int r; @@ -885,13 +909,7 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)  		goto err1;  	} -	dispc_mgr_set_lcd_display_type(dssdev->manager->id, -			OMAP_DSS_LCD_DISPLAY_TFT); - -	dispc_mgr_set_io_pad_mode(DSS_IO_PAD_MODE_RFBI); -	dispc_mgr_enable_stallmode(dssdev->manager->id, true); - -	dispc_mgr_set_tft_data_lines(dssdev->manager->id, dssdev->ctrl.pixel_size); +	rfbi_config_lcd_manager(dssdev);  	rfbi_configure(dssdev->phy.rfbi.channel,  			       dssdev->ctrl.pixel_size, diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index 3a43dc2a9b46..5d31699fbd3c 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -32,19 +32,21 @@  static struct {  	bool update_enabled;  	struct regulator *vdds_sdi_reg; -} sdi; -static void sdi_basic_init(struct omap_dss_device *dssdev) +	struct dss_lcd_mgr_config mgr_config; +} sdi; +static void sdi_config_lcd_manager(struct omap_dss_device *dssdev)  { -	dispc_mgr_set_io_pad_mode(DSS_IO_PAD_MODE_BYPASS); -	dispc_mgr_enable_stallmode(dssdev->manager->id, false); +	sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; + +	sdi.mgr_config.stallmode = false; +	sdi.mgr_config.fifohandcheck = false; -	dispc_mgr_set_lcd_display_type(dssdev->manager->id, -			OMAP_DSS_LCD_DISPLAY_TFT); +	sdi.mgr_config.video_port_width = 24; +	sdi.mgr_config.lcden_sig_polarity = 1; -	dispc_mgr_set_tft_data_lines(dssdev->manager->id, 24); -	dispc_lcd_enable_signal_polarity(1); +	dss_mgr_set_lcd_config(dssdev->manager, &sdi.mgr_config);  }  int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) @@ -52,8 +54,6 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)  	struct omap_video_timings *t = &dssdev->panel.timings;  	struct dss_clock_info dss_cinfo;  	struct dispc_clock_info dispc_cinfo; -	u16 lck_div, pck_div; -	unsigned long fck;  	unsigned long pck;  	int r; @@ -76,24 +76,17 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)  	if (r)  		goto err_get_dispc; -	sdi_basic_init(dssdev); -  	/* 15.5.9.1.2 */ -	dssdev->panel.config |= OMAP_DSS_LCD_RF | OMAP_DSS_LCD_ONOFF; - -	dispc_mgr_set_pol_freq(dssdev->manager->id, dssdev->panel.config, -			dssdev->panel.acbi, dssdev->panel.acb); +	dssdev->panel.timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; +	dssdev->panel.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; -	r = dss_calc_clock_div(1, t->pixel_clock * 1000, -			&dss_cinfo, &dispc_cinfo); +	r = dss_calc_clock_div(t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo);  	if (r)  		goto err_calc_clock_div; -	fck = dss_cinfo.fck; -	lck_div = dispc_cinfo.lck_div; -	pck_div = dispc_cinfo.pck_div; +	sdi.mgr_config.clock_info = dispc_cinfo; -	pck = fck / lck_div / pck_div / 1000; +	pck = dss_cinfo.fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div / 1000;  	if (pck != t->pixel_clock) {  		DSSWARN("Could not find exact pixel clock. Requested %d kHz, " @@ -110,9 +103,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)  	if (r)  		goto err_set_dss_clock_div; -	r = dispc_mgr_set_clock_div(dssdev->manager->id, &dispc_cinfo); -	if (r) -		goto err_set_dispc_clock_div; +	sdi_config_lcd_manager(dssdev);  	dss_sdi_init(dssdev->phy.sdi.datapairs);  	r = dss_sdi_enable(); @@ -129,7 +120,6 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)  err_mgr_enable:  	dss_sdi_disable();  err_sdi_enable: -err_set_dispc_clock_div:  err_set_dss_clock_div:  err_calc_clock_div:  	dispc_runtime_put(); diff --git a/drivers/video/omap2/dss/ti_hdmi.h b/drivers/video/omap2/dss/ti_hdmi.h index e734cb444bc7..b046c208cb97 100644 --- a/drivers/video/omap2/dss/ti_hdmi.h +++ b/drivers/video/omap2/dss/ti_hdmi.h @@ -42,30 +42,13 @@ enum hdmi_clk_refsel {  	HDMI_REFSEL_SYSCLK = 3  }; -/* HDMI timing structure */ -struct hdmi_video_timings { -	u16 x_res; -	u16 y_res; -	/* Unit: KHz */ -	u32 pixel_clock; -	u16 hsw; -	u16 hfp; -	u16 hbp; -	u16 vsw; -	u16 vfp; -	u16 vbp; -	bool vsync_pol; -	bool hsync_pol; -	bool interlace; -}; -  struct hdmi_cm {  	int	code;  	int	mode;  };  struct hdmi_config { -	struct hdmi_video_timings timings; +	struct omap_video_timings timings;  	struct hdmi_cm cm;  }; @@ -177,7 +160,7 @@ struct hdmi_ip_data {  	/* ti_hdmi_4xxx_ip private data. These should be in a separate struct */  	int hpd_gpio; -	bool phy_tx_enabled; +	struct mutex lock;  };  int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data);  void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data); diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c index 4dae1b291079..c23b85a20cdc 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c @@ -157,6 +157,10 @@ static int hdmi_pll_init(struct hdmi_ip_data *ip_data)  /* PHY_PWR_CMD */  static int hdmi_set_phy_pwr(struct hdmi_ip_data *ip_data, enum hdmi_phy_pwr val)  { +	/* Return if already the state */ +	if (REG_GET(hdmi_wp_base(ip_data), HDMI_WP_PWR_CTRL, 5, 4) == val) +		return 0; +  	/* Command for power control of HDMI PHY */  	REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_PWR_CTRL, val, 7, 6); @@ -231,21 +235,13 @@ void ti_hdmi_4xxx_pll_disable(struct hdmi_ip_data *ip_data)  static int hdmi_check_hpd_state(struct hdmi_ip_data *ip_data)  { -	unsigned long flags;  	bool hpd;  	int r; -	/* this should be in ti_hdmi_4xxx_ip private data */ -	static DEFINE_SPINLOCK(phy_tx_lock); -	spin_lock_irqsave(&phy_tx_lock, flags); +	mutex_lock(&ip_data->lock);  	hpd = gpio_get_value(ip_data->hpd_gpio); -	if (hpd == ip_data->phy_tx_enabled) { -		spin_unlock_irqrestore(&phy_tx_lock, flags); -		return 0; -	} -  	if (hpd)  		r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_TXON);  	else @@ -257,9 +253,8 @@ static int hdmi_check_hpd_state(struct hdmi_ip_data *ip_data)  		goto err;  	} -	ip_data->phy_tx_enabled = hpd;  err: -	spin_unlock_irqrestore(&phy_tx_lock, flags); +	mutex_unlock(&ip_data->lock);  	return r;  } @@ -327,7 +322,6 @@ void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data)  	free_irq(gpio_to_irq(ip_data->hpd_gpio), ip_data);  	hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); -	ip_data->phy_tx_enabled = false;  }  static int hdmi_core_ddc_init(struct hdmi_ip_data *ip_data) @@ -747,11 +741,15 @@ static void hdmi_wp_video_config_format(struct hdmi_ip_data *ip_data,  static void hdmi_wp_video_config_interface(struct hdmi_ip_data *ip_data)  {  	u32 r; +	bool vsync_pol, hsync_pol;  	pr_debug("Enter hdmi_wp_video_config_interface\n"); +	vsync_pol = ip_data->cfg.timings.vsync_level == OMAPDSS_SIG_ACTIVE_HIGH; +	hsync_pol = ip_data->cfg.timings.hsync_level == OMAPDSS_SIG_ACTIVE_HIGH; +  	r = hdmi_read_reg(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG); -	r = FLD_MOD(r, ip_data->cfg.timings.vsync_pol, 7, 7); -	r = FLD_MOD(r, ip_data->cfg.timings.hsync_pol, 6, 6); +	r = FLD_MOD(r, vsync_pol, 7, 7); +	r = FLD_MOD(r, hsync_pol, 6, 6);  	r = FLD_MOD(r, ip_data->cfg.timings.interlace, 3, 3);  	r = FLD_MOD(r, 1, 1, 0); /* HDMI_TIMING_MASTER_24BIT */  	hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, r); diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 3907c8b6ecbc..3a220877461a 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c @@ -272,6 +272,8 @@ const struct omap_video_timings omap_dss_pal_timings = {  	.vsw		= 5,  	.vfp		= 5,  	.vbp		= 41, + +	.interlace	= true,  };  EXPORT_SYMBOL(omap_dss_pal_timings); @@ -285,6 +287,8 @@ const struct omap_video_timings omap_dss_ntsc_timings = {  	.vsw		= 6,  	.vfp		= 6,  	.vbp		= 31, + +	.interlace	= true,  };  EXPORT_SYMBOL(omap_dss_ntsc_timings); @@ -930,7 +934,7 @@ static int __exit omap_venchw_remove(struct platform_device *pdev)  static int venc_runtime_suspend(struct device *dev)  {  	if (venc.tv_dac_clk) -		clk_disable(venc.tv_dac_clk); +		clk_disable_unprepare(venc.tv_dac_clk);  	dispc_runtime_put(); @@ -946,7 +950,7 @@ static int venc_runtime_resume(struct device *dev)  		return r;  	if (venc.tv_dac_clk) -		clk_enable(venc.tv_dac_clk); +		clk_prepare_enable(venc.tv_dac_clk);  	return 0;  } diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 3450ea0966c9..08ec1a7103f2 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -733,6 +733,12 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)  		var->lower_margin = timings.vfp;  		var->hsync_len = timings.hsw;  		var->vsync_len = timings.vsw; +		var->sync |= timings.hsync_level == OMAPDSS_SIG_ACTIVE_HIGH ? +				FB_SYNC_HOR_HIGH_ACT : 0; +		var->sync |= timings.vsync_level == OMAPDSS_SIG_ACTIVE_HIGH ? +				FB_SYNC_VERT_HIGH_ACT : 0; +		var->vmode = timings.interlace ? +				FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED;  	} else {  		var->pixclock = 0;  		var->left_margin = 0; @@ -741,12 +747,10 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)  		var->lower_margin = 0;  		var->hsync_len = 0;  		var->vsync_len = 0; +		var->sync = 0; +		var->vmode = FB_VMODE_NONINTERLACED;  	} -	/* TODO: get these from panel->config */ -	var->vmode              = FB_VMODE_NONINTERLACED; -	var->sync               = 0; -  	return 0;  } @@ -1993,6 +1997,7 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)  }  static int omapfb_mode_to_timings(const char *mode_str, +		struct omap_dss_device *display,  		struct omap_video_timings *timings, u8 *bpp)  {  	struct fb_info *fbi; @@ -2046,6 +2051,14 @@ static int omapfb_mode_to_timings(const char *mode_str,  		goto err;  	} +	if (display->driver->get_timings) { +		display->driver->get_timings(display, timings); +	} else { +		timings->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; +		timings->de_level = OMAPDSS_SIG_ACTIVE_HIGH; +		timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; +	} +  	timings->pixel_clock = PICOS2KHZ(var->pixclock);  	timings->hbp = var->left_margin;  	timings->hfp = var->right_margin; @@ -2055,6 +2068,13 @@ static int omapfb_mode_to_timings(const char *mode_str,  	timings->vsw = var->vsync_len;  	timings->x_res = var->xres;  	timings->y_res = var->yres; +	timings->hsync_level = var->sync & FB_SYNC_HOR_HIGH_ACT ? +				OMAPDSS_SIG_ACTIVE_HIGH : +				OMAPDSS_SIG_ACTIVE_LOW; +	timings->vsync_level = var->sync & FB_SYNC_VERT_HIGH_ACT ? +				OMAPDSS_SIG_ACTIVE_HIGH : +				OMAPDSS_SIG_ACTIVE_LOW; +	timings->interlace = var->vmode & FB_VMODE_INTERLACED;  	switch (var->bits_per_pixel) {  	case 16: @@ -2085,7 +2105,7 @@ static int omapfb_set_def_mode(struct omapfb2_device *fbdev,  	struct omap_video_timings timings, temp_timings;  	struct omapfb_display_data *d; -	r = omapfb_mode_to_timings(mode_str, &timings, &bpp); +	r = omapfb_mode_to_timings(mode_str, display, &timings, &bpp);  	if (r)  		return r; @@ -2178,8 +2198,17 @@ static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)  }  static void fb_videomode_to_omap_timings(struct fb_videomode *m, +		struct omap_dss_device *display,  		struct omap_video_timings *t)  { +	if (display->driver->get_timings) { +		display->driver->get_timings(display, t); +	} else { +		t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; +		t->de_level = OMAPDSS_SIG_ACTIVE_HIGH; +		t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; +	} +  	t->x_res = m->xres;  	t->y_res = m->yres;  	t->pixel_clock = PICOS2KHZ(m->pixclock); @@ -2189,6 +2218,13 @@ static void fb_videomode_to_omap_timings(struct fb_videomode *m,  	t->vsw = m->vsync_len;  	t->vfp = m->lower_margin;  	t->vbp = m->upper_margin; +	t->hsync_level = m->sync & FB_SYNC_HOR_HIGH_ACT ? +				OMAPDSS_SIG_ACTIVE_HIGH : +				OMAPDSS_SIG_ACTIVE_LOW; +	t->vsync_level = m->sync & FB_SYNC_VERT_HIGH_ACT ? +				OMAPDSS_SIG_ACTIVE_HIGH : +				OMAPDSS_SIG_ACTIVE_LOW; +	t->interlace = m->vmode & FB_VMODE_INTERLACED;  }  static int omapfb_find_best_mode(struct omap_dss_device *display, @@ -2231,7 +2267,7 @@ static int omapfb_find_best_mode(struct omap_dss_device *display,  		if (m->xres == 2880 || m->xres == 1440)  			continue; -		fb_videomode_to_omap_timings(m, &t); +		fb_videomode_to_omap_timings(m, display, &t);  		r = display->driver->check_timings(display, &t);  		if (r == 0 && best_xres < m->xres) { @@ -2245,7 +2281,8 @@ static int omapfb_find_best_mode(struct omap_dss_device *display,  		goto err2;  	} -	fb_videomode_to_omap_timings(&specs->modedb[best_idx], timings); +	fb_videomode_to_omap_timings(&specs->modedb[best_idx], display, +		timings);  	r = 0; diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index 2c80246b18b8..1d007366b917 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -84,7 +84,7 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64",  			"S3 Virge/VX", "S3 Virge/DX", "S3 Virge/GX",  			"S3 Virge/GX2", "S3 Virge/GX2+", "",  			"S3 Trio3D/1X", "S3 Trio3D/2X", "S3 Trio3D/2X", -			"S3 Trio3D"}; +			"S3 Trio3D", "S3 Virge/MX"};  #define CHIP_UNKNOWN		0x00  #define CHIP_732_TRIO32		0x01 @@ -105,6 +105,7 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64",  #define CHIP_362_TRIO3D_2X	0x11  #define CHIP_368_TRIO3D_2X	0x12  #define CHIP_365_TRIO3D		0x13 +#define CHIP_260_VIRGE_MX	0x14  #define CHIP_XXX_TRIO		0x80  #define CHIP_XXX_TRIO64V2_DXGX	0x81 @@ -280,7 +281,8 @@ static int __devinit s3fb_setup_ddc_bus(struct fb_info *info)  	 */  /*	vga_wseq(par->state.vgabase, 0x08, 0x06); - not needed, already unlocked */  	if (par->chip == CHIP_357_VIRGE_GX2 || -	    par->chip == CHIP_359_VIRGE_GX2P) +	    par->chip == CHIP_359_VIRGE_GX2P || +	    par->chip == CHIP_260_VIRGE_MX)  		svga_wseq_mask(par->state.vgabase, 0x0d, 0x01, 0x03);  	else  		svga_wseq_mask(par->state.vgabase, 0x0d, 0x00, 0x03); @@ -487,7 +489,8 @@ static void s3_set_pixclock(struct fb_info *info, u32 pixclock)  	    par->chip == CHIP_359_VIRGE_GX2P ||  	    par->chip == CHIP_360_TRIO3D_1X ||  	    par->chip == CHIP_362_TRIO3D_2X || -	    par->chip == CHIP_368_TRIO3D_2X) { +	    par->chip == CHIP_368_TRIO3D_2X || +	    par->chip == CHIP_260_VIRGE_MX) {  		vga_wseq(par->state.vgabase, 0x12, (n - 2) | ((r & 3) << 6));	/* n and two bits of r */  		vga_wseq(par->state.vgabase, 0x29, r >> 2); /* remaining highest bit of r */  	} else @@ -690,7 +693,8 @@ static int s3fb_set_par(struct fb_info *info)  	    par->chip != CHIP_359_VIRGE_GX2P &&  	    par->chip != CHIP_360_TRIO3D_1X &&  	    par->chip != CHIP_362_TRIO3D_2X && -	    par->chip != CHIP_368_TRIO3D_2X) { +	    par->chip != CHIP_368_TRIO3D_2X && +	    par->chip != CHIP_260_VIRGE_MX) {  		vga_wcrt(par->state.vgabase, 0x54, 0x18); /* M parameter */  		vga_wcrt(par->state.vgabase, 0x60, 0xff); /* N parameter */  		vga_wcrt(par->state.vgabase, 0x61, 0xff); /* L parameter */ @@ -739,7 +743,8 @@ static int s3fb_set_par(struct fb_info *info)  	    par->chip == CHIP_368_TRIO3D_2X ||  	    par->chip == CHIP_365_TRIO3D    ||  	    par->chip == CHIP_375_VIRGE_DX  || -	    par->chip == CHIP_385_VIRGE_GX) { +	    par->chip == CHIP_385_VIRGE_GX  || +	    par->chip == CHIP_260_VIRGE_MX) {  		dbytes = info->var.xres * ((bpp+7)/8);  		vga_wcrt(par->state.vgabase, 0x91, (dbytes + 7) / 8);  		vga_wcrt(par->state.vgabase, 0x90, (((dbytes + 7) / 8) >> 8) | 0x80); @@ -751,7 +756,8 @@ static int s3fb_set_par(struct fb_info *info)  	    par->chip == CHIP_359_VIRGE_GX2P ||  	    par->chip == CHIP_360_TRIO3D_1X ||  	    par->chip == CHIP_362_TRIO3D_2X || -	    par->chip == CHIP_368_TRIO3D_2X) +	    par->chip == CHIP_368_TRIO3D_2X || +	    par->chip == CHIP_260_VIRGE_MX)  		vga_wcrt(par->state.vgabase, 0x34, 0x00);  	else	/* enable Data Transfer Position Control (DTPC) */  		vga_wcrt(par->state.vgabase, 0x34, 0x10); @@ -807,7 +813,8 @@ static int s3fb_set_par(struct fb_info *info)  		    par->chip == CHIP_359_VIRGE_GX2P ||  		    par->chip == CHIP_360_TRIO3D_1X ||  		    par->chip == CHIP_362_TRIO3D_2X || -		    par->chip == CHIP_368_TRIO3D_2X) +		    par->chip == CHIP_368_TRIO3D_2X || +		    par->chip == CHIP_260_VIRGE_MX)  			svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0xF0);  		else {  			svga_wcrt_mask(par->state.vgabase, 0x67, 0x10, 0xF0); @@ -837,7 +844,8 @@ static int s3fb_set_par(struct fb_info *info)  			    par->chip != CHIP_359_VIRGE_GX2P &&  			    par->chip != CHIP_360_TRIO3D_1X &&  			    par->chip != CHIP_362_TRIO3D_2X && -			    par->chip != CHIP_368_TRIO3D_2X) +			    par->chip != CHIP_368_TRIO3D_2X && +			    par->chip != CHIP_260_VIRGE_MX)  				hmul = 2;  		}  		break; @@ -864,7 +872,8 @@ static int s3fb_set_par(struct fb_info *info)  			    par->chip != CHIP_359_VIRGE_GX2P &&  			    par->chip != CHIP_360_TRIO3D_1X &&  			    par->chip != CHIP_362_TRIO3D_2X && -			    par->chip != CHIP_368_TRIO3D_2X) +			    par->chip != CHIP_368_TRIO3D_2X && +			    par->chip != CHIP_260_VIRGE_MX)  				hmul = 2;  		}  		break; @@ -1208,7 +1217,8 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i  			break;  		}  	} else if (par->chip == CHIP_357_VIRGE_GX2 || -		   par->chip == CHIP_359_VIRGE_GX2P) { +		   par->chip == CHIP_359_VIRGE_GX2P || +		   par->chip == CHIP_260_VIRGE_MX) {  		switch ((regval & 0xC0) >> 6) {  		case 1: /* 4MB */  			info->screen_size = 4 << 20; @@ -1515,6 +1525,7 @@ static struct pci_device_id s3_devices[] __devinitdata = {  	{PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A12), .driver_data = CHIP_359_VIRGE_GX2P},  	{PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A13), .driver_data = CHIP_36X_TRIO3D_1X_2X},  	{PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8904), .driver_data = CHIP_365_TRIO3D}, +	{PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8C01), .driver_data = CHIP_260_VIRGE_MX},  	{0, 0, 0, 0, 0, 0, 0}  }; diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c index 4c6b84488561..3951fdae5f68 100644 --- a/drivers/video/sh_mipi_dsi.c +++ b/drivers/video/sh_mipi_dsi.c @@ -127,8 +127,7 @@ static void sh_mipi_shutdown(struct platform_device *pdev)  	sh_mipi_dsi_enable(mipi, false);  } -static int __init sh_mipi_setup(struct sh_mipi *mipi, -				struct sh_mipi_dsi_info *pdata) +static int sh_mipi_setup(struct sh_mipi *mipi, struct sh_mipi_dsi_info *pdata)  {  	void __iomem *base = mipi->base;  	struct sh_mobile_lcdc_chan_cfg *ch = pdata->lcd_chan; @@ -551,7 +550,7 @@ efindslot:  	return ret;  } -static int __exit sh_mipi_remove(struct platform_device *pdev) +static int __devexit sh_mipi_remove(struct platform_device *pdev)  {  	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	struct resource *res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); @@ -592,7 +591,7 @@ static int __exit sh_mipi_remove(struct platform_device *pdev)  }  static struct platform_driver sh_mipi_driver = { -	.remove		= __exit_p(sh_mipi_remove), +	.remove		= __devexit_p(sh_mipi_remove),  	.shutdown	= sh_mipi_shutdown,  	.driver = {  		.name	= "sh-mipi-dsi", diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index e672698bd820..699487c287b2 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -12,6 +12,7 @@  #include <linux/backlight.h>  #include <linux/clk.h>  #include <linux/console.h> +#include <linux/ctype.h>  #include <linux/dma-mapping.h>  #include <linux/delay.h>  #include <linux/gpio.h> @@ -32,12 +33,176 @@  #include "sh_mobile_lcdcfb.h" +/* ---------------------------------------------------------------------------- + * Overlay register definitions + */ + +#define LDBCR			0xb00 +#define LDBCR_UPC(n)		(1 << ((n) + 16)) +#define LDBCR_UPF(n)		(1 << ((n) + 8)) +#define LDBCR_UPD(n)		(1 << ((n) + 0)) +#define LDBnBSIFR(n)		(0xb20 + (n) * 0x20 + 0x00) +#define LDBBSIFR_EN		(1 << 31) +#define LDBBSIFR_VS		(1 << 29) +#define LDBBSIFR_BRSEL		(1 << 28) +#define LDBBSIFR_MX		(1 << 27) +#define LDBBSIFR_MY		(1 << 26) +#define LDBBSIFR_CV3		(3 << 24) +#define LDBBSIFR_CV2		(2 << 24) +#define LDBBSIFR_CV1		(1 << 24) +#define LDBBSIFR_CV0		(0 << 24) +#define LDBBSIFR_CV_MASK	(3 << 24) +#define LDBBSIFR_LAY_MASK	(0xff << 16) +#define LDBBSIFR_LAY_SHIFT	16 +#define LDBBSIFR_ROP3_MASK	(0xff << 16) +#define LDBBSIFR_ROP3_SHIFT	16 +#define LDBBSIFR_AL_PL8		(3 << 14) +#define LDBBSIFR_AL_PL1		(2 << 14) +#define LDBBSIFR_AL_PK		(1 << 14) +#define LDBBSIFR_AL_1		(0 << 14) +#define LDBBSIFR_AL_MASK	(3 << 14) +#define LDBBSIFR_SWPL		(1 << 10) +#define LDBBSIFR_SWPW		(1 << 9) +#define LDBBSIFR_SWPB		(1 << 8) +#define LDBBSIFR_RY		(1 << 7) +#define LDBBSIFR_CHRR_420	(2 << 0) +#define LDBBSIFR_CHRR_422	(1 << 0) +#define LDBBSIFR_CHRR_444	(0 << 0) +#define LDBBSIFR_RPKF_ARGB32	(0x00 << 0) +#define LDBBSIFR_RPKF_RGB16	(0x03 << 0) +#define LDBBSIFR_RPKF_RGB24	(0x0b << 0) +#define LDBBSIFR_RPKF_MASK	(0x1f << 0) +#define LDBnBSSZR(n)		(0xb20 + (n) * 0x20 + 0x04) +#define LDBBSSZR_BVSS_MASK	(0xfff << 16) +#define LDBBSSZR_BVSS_SHIFT	16 +#define LDBBSSZR_BHSS_MASK	(0xfff << 0) +#define LDBBSSZR_BHSS_SHIFT	0 +#define LDBnBLOCR(n)		(0xb20 + (n) * 0x20 + 0x08) +#define LDBBLOCR_CVLC_MASK	(0xfff << 16) +#define LDBBLOCR_CVLC_SHIFT	16 +#define LDBBLOCR_CHLC_MASK	(0xfff << 0) +#define LDBBLOCR_CHLC_SHIFT	0 +#define LDBnBSMWR(n)		(0xb20 + (n) * 0x20 + 0x0c) +#define LDBBSMWR_BSMWA_MASK	(0xffff << 16) +#define LDBBSMWR_BSMWA_SHIFT	16 +#define LDBBSMWR_BSMW_MASK	(0xffff << 0) +#define LDBBSMWR_BSMW_SHIFT	0 +#define LDBnBSAYR(n)		(0xb20 + (n) * 0x20 + 0x10) +#define LDBBSAYR_FG1A_MASK	(0xff << 24) +#define LDBBSAYR_FG1A_SHIFT	24 +#define LDBBSAYR_FG1R_MASK	(0xff << 16) +#define LDBBSAYR_FG1R_SHIFT	16 +#define LDBBSAYR_FG1G_MASK	(0xff << 8) +#define LDBBSAYR_FG1G_SHIFT	8 +#define LDBBSAYR_FG1B_MASK	(0xff << 0) +#define LDBBSAYR_FG1B_SHIFT	0 +#define LDBnBSACR(n)		(0xb20 + (n) * 0x20 + 0x14) +#define LDBBSACR_FG2A_MASK	(0xff << 24) +#define LDBBSACR_FG2A_SHIFT	24 +#define LDBBSACR_FG2R_MASK	(0xff << 16) +#define LDBBSACR_FG2R_SHIFT	16 +#define LDBBSACR_FG2G_MASK	(0xff << 8) +#define LDBBSACR_FG2G_SHIFT	8 +#define LDBBSACR_FG2B_MASK	(0xff << 0) +#define LDBBSACR_FG2B_SHIFT	0 +#define LDBnBSAAR(n)		(0xb20 + (n) * 0x20 + 0x18) +#define LDBBSAAR_AP_MASK	(0xff << 24) +#define LDBBSAAR_AP_SHIFT	24 +#define LDBBSAAR_R_MASK		(0xff << 16) +#define LDBBSAAR_R_SHIFT	16 +#define LDBBSAAR_GY_MASK	(0xff << 8) +#define LDBBSAAR_GY_SHIFT	8 +#define LDBBSAAR_B_MASK		(0xff << 0) +#define LDBBSAAR_B_SHIFT	0 +#define LDBnBPPCR(n)		(0xb20 + (n) * 0x20 + 0x1c) +#define LDBBPPCR_AP_MASK	(0xff << 24) +#define LDBBPPCR_AP_SHIFT	24 +#define LDBBPPCR_R_MASK		(0xff << 16) +#define LDBBPPCR_R_SHIFT	16 +#define LDBBPPCR_GY_MASK	(0xff << 8) +#define LDBBPPCR_GY_SHIFT	8 +#define LDBBPPCR_B_MASK		(0xff << 0) +#define LDBBPPCR_B_SHIFT	0 +#define LDBnBBGCL(n)		(0xb10 + (n) * 0x04) +#define LDBBBGCL_BGA_MASK	(0xff << 24) +#define LDBBBGCL_BGA_SHIFT	24 +#define LDBBBGCL_BGR_MASK	(0xff << 16) +#define LDBBBGCL_BGR_SHIFT	16 +#define LDBBBGCL_BGG_MASK	(0xff << 8) +#define LDBBBGCL_BGG_SHIFT	8 +#define LDBBBGCL_BGB_MASK	(0xff << 0) +#define LDBBBGCL_BGB_SHIFT	0 +  #define SIDE_B_OFFSET 0x1000  #define MIRROR_OFFSET 0x2000  #define MAX_XRES 1920  #define MAX_YRES 1080 +enum sh_mobile_lcdc_overlay_mode { +	LCDC_OVERLAY_BLEND, +	LCDC_OVERLAY_ROP3, +}; + +/* + * struct sh_mobile_lcdc_overlay - LCDC display overlay + * + * @channel: LCDC channel this overlay belongs to + * @cfg: Overlay configuration + * @info: Frame buffer device + * @index: Overlay index (0-3) + * @base: Overlay registers base address + * @enabled: True if the overlay is enabled + * @mode: Overlay blending mode (alpha blend or ROP3) + * @alpha: Global alpha blending value (0-255, for alpha blending mode) + * @rop3: Raster operation (for ROP3 mode) + * @fb_mem: Frame buffer virtual memory address + * @fb_size: Frame buffer size in bytes + * @dma_handle: Frame buffer DMA address + * @base_addr_y: Overlay base address (RGB or luma component) + * @base_addr_c: Overlay base address (chroma component) + * @pan_y_offset: Panning linear offset in bytes (luma component) + * @format: Current pixelf format + * @xres: Horizontal visible resolution + * @xres_virtual: Horizontal total resolution + * @yres: Vertical visible resolution + * @yres_virtual: Vertical total resolution + * @pitch: Overlay line pitch + * @pos_x: Horizontal overlay position + * @pos_y: Vertical overlay position + */ +struct sh_mobile_lcdc_overlay { +	struct sh_mobile_lcdc_chan *channel; + +	const struct sh_mobile_lcdc_overlay_cfg *cfg; +	struct fb_info *info; + +	unsigned int index; +	unsigned long base; + +	bool enabled; +	enum sh_mobile_lcdc_overlay_mode mode; +	unsigned int alpha; +	unsigned int rop3; + +	void *fb_mem; +	unsigned long fb_size; + +	dma_addr_t dma_handle; +	unsigned long base_addr_y; +	unsigned long base_addr_c; +	unsigned long pan_y_offset; + +	const struct sh_mobile_lcdc_format_info *format; +	unsigned int xres; +	unsigned int xres_virtual; +	unsigned int yres; +	unsigned int yres_virtual; +	unsigned int pitch; +	int pos_x; +	int pos_y; +}; +  struct sh_mobile_lcdc_priv {  	void __iomem *base;  	int irq; @@ -45,7 +210,10 @@ struct sh_mobile_lcdc_priv {  	struct device *dev;  	struct clk *dot_clk;  	unsigned long lddckr; +  	struct sh_mobile_lcdc_chan ch[2]; +	struct sh_mobile_lcdc_overlay overlays[4]; +  	struct notifier_block notifier;  	int started;  	int forced_fourcc; /* 2 channel LCDC must share fourcc setting */ @@ -141,6 +309,13 @@ static unsigned long lcdc_read_chan(struct sh_mobile_lcdc_chan *chan,  	return ioread32(chan->lcdc->base + chan->reg_offs[reg_nr]);  } +static void lcdc_write_overlay(struct sh_mobile_lcdc_overlay *ovl, +			       int reg, unsigned long data) +{ +	iowrite32(data, ovl->channel->lcdc->base + reg); +	iowrite32(data, ovl->channel->lcdc->base + reg + SIDE_B_OFFSET); +} +  static void lcdc_write(struct sh_mobile_lcdc_priv *priv,  		       unsigned long reg_offs, unsigned long data)  { @@ -384,8 +559,8 @@ sh_mobile_lcdc_must_reconfigure(struct sh_mobile_lcdc_chan *ch,  	return true;  } -static int sh_mobile_check_var(struct fb_var_screeninfo *var, -			       struct fb_info *info); +static int sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var, +				    struct fb_info *info);  static int sh_mobile_lcdc_display_notify(struct sh_mobile_lcdc_chan *ch,  					 enum sh_mobile_lcdc_entity_event event, @@ -439,7 +614,7 @@ static int sh_mobile_lcdc_display_notify(struct sh_mobile_lcdc_chan *ch,  		fb_videomode_to_var(&var, mode);  		var.bits_per_pixel = info->var.bits_per_pixel;  		var.grayscale = info->var.grayscale; -		ret = sh_mobile_check_var(&var, info); +		ret = sh_mobile_lcdc_check_var(&var, info);  		break;  	} @@ -585,7 +760,7 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)  	return IRQ_HANDLED;  } -static int sh_mobile_wait_for_vsync(struct sh_mobile_lcdc_chan *ch) +static int sh_mobile_lcdc_wait_for_vsync(struct sh_mobile_lcdc_chan *ch)  {  	unsigned long ldintr;  	int ret; @@ -685,8 +860,98 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)  	lcdc_write_chan(ch, LDHAJR, tmp);  } +static void sh_mobile_lcdc_overlay_setup(struct sh_mobile_lcdc_overlay *ovl) +{ +	u32 format = 0; + +	if (!ovl->enabled) { +		lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index)); +		lcdc_write_overlay(ovl, LDBnBSIFR(ovl->index), 0); +		lcdc_write(ovl->channel->lcdc, LDBCR, +			   LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index)); +		return; +	} + +	ovl->base_addr_y = ovl->dma_handle; +	ovl->base_addr_c = ovl->dma_handle +			 + ovl->xres_virtual * ovl->yres_virtual; + +	switch (ovl->mode) { +	case LCDC_OVERLAY_BLEND: +		format = LDBBSIFR_EN | (ovl->alpha << LDBBSIFR_LAY_SHIFT); +		break; + +	case LCDC_OVERLAY_ROP3: +		format = LDBBSIFR_EN | LDBBSIFR_BRSEL +		       | (ovl->rop3 << LDBBSIFR_ROP3_SHIFT); +		break; +	} + +	switch (ovl->format->fourcc) { +	case V4L2_PIX_FMT_RGB565: +	case V4L2_PIX_FMT_NV21: +	case V4L2_PIX_FMT_NV61: +	case V4L2_PIX_FMT_NV42: +		format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW; +		break; +	case V4L2_PIX_FMT_BGR24: +	case V4L2_PIX_FMT_NV12: +	case V4L2_PIX_FMT_NV16: +	case V4L2_PIX_FMT_NV24: +		format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW | LDBBSIFR_SWPB; +		break; +	case V4L2_PIX_FMT_BGR32: +	default: +		format |= LDBBSIFR_SWPL; +		break; +	} + +	switch (ovl->format->fourcc) { +	case V4L2_PIX_FMT_RGB565: +		format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB16; +		break; +	case V4L2_PIX_FMT_BGR24: +		format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB24; +		break; +	case V4L2_PIX_FMT_BGR32: +		format |= LDBBSIFR_AL_PK | LDBBSIFR_RY | LDDFR_PKF_ARGB32; +		break; +	case V4L2_PIX_FMT_NV12: +	case V4L2_PIX_FMT_NV21: +		format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_420; +		break; +	case V4L2_PIX_FMT_NV16: +	case V4L2_PIX_FMT_NV61: +		format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_422; +		break; +	case V4L2_PIX_FMT_NV24: +	case V4L2_PIX_FMT_NV42: +		format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_444; +		break; +	} + +	lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index)); + +	lcdc_write_overlay(ovl, LDBnBSIFR(ovl->index), format); + +	lcdc_write_overlay(ovl, LDBnBSSZR(ovl->index), +		(ovl->yres << LDBBSSZR_BVSS_SHIFT) | +		(ovl->xres << LDBBSSZR_BHSS_SHIFT)); +	lcdc_write_overlay(ovl, LDBnBLOCR(ovl->index), +		(ovl->pos_y << LDBBLOCR_CVLC_SHIFT) | +		(ovl->pos_x << LDBBLOCR_CHLC_SHIFT)); +	lcdc_write_overlay(ovl, LDBnBSMWR(ovl->index), +		ovl->pitch << LDBBSMWR_BSMW_SHIFT); + +	lcdc_write_overlay(ovl, LDBnBSAYR(ovl->index), ovl->base_addr_y); +	lcdc_write_overlay(ovl, LDBnBSACR(ovl->index), ovl->base_addr_c); + +	lcdc_write(ovl->channel->lcdc, LDBCR, +		   LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index)); +} +  /* - * __sh_mobile_lcdc_start - Configure and tart the LCDC + * __sh_mobile_lcdc_start - Configure and start the LCDC   * @priv: LCDC device   *   * Configure all enabled channels and start the LCDC device. All external @@ -839,27 +1104,25 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)  	/* Compute frame buffer base address and pitch for each channel. */  	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {  		int pixelformat; -		void *meram; +		void *cache;  		ch = &priv->ch[k];  		if (!ch->enabled)  			continue;  		ch->base_addr_y = ch->dma_handle; -		ch->base_addr_c = ch->base_addr_y + ch->xres * ch->yres_virtual; +		ch->base_addr_c = ch->dma_handle +				+ ch->xres_virtual * ch->yres_virtual;  		ch->line_size = ch->pitch;  		/* Enable MERAM if possible. */ -		if (mdev == NULL || mdev->ops == NULL || -		    ch->cfg->meram_cfg == NULL) +		if (mdev == NULL || ch->cfg->meram_cfg == NULL)  			continue; -		/* we need to de-init configured ICBs before we can -		 * re-initialize them. -		 */ -		if (ch->meram) { -			mdev->ops->meram_unregister(mdev, ch->meram); -			ch->meram = NULL; +		/* Free the allocated MERAM cache. */ +		if (ch->cache) { +			sh_mobile_meram_cache_free(mdev, ch->cache); +			ch->cache = NULL;  		}  		switch (ch->format->fourcc) { @@ -881,17 +1144,22 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)  			break;  		} -		meram = mdev->ops->meram_register(mdev, ch->cfg->meram_cfg, +		cache = sh_mobile_meram_cache_alloc(mdev, ch->cfg->meram_cfg,  					ch->pitch, ch->yres, pixelformat,  					&ch->line_size); -		if (!IS_ERR(meram)) { -			mdev->ops->meram_update(mdev, meram, +		if (!IS_ERR(cache)) { +			sh_mobile_meram_cache_update(mdev, cache,  					ch->base_addr_y, ch->base_addr_c,  					&ch->base_addr_y, &ch->base_addr_c); -			ch->meram = meram; +			ch->cache = cache;  		}  	} +	for (k = 0; k < ARRAY_SIZE(priv->overlays); ++k) { +		struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[k]; +		sh_mobile_lcdc_overlay_setup(ovl); +	} +  	/* Start the LCDC. */  	__sh_mobile_lcdc_start(priv); @@ -953,12 +1221,10 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)  		sh_mobile_lcdc_display_off(ch); -		/* disable the meram */ -		if (ch->meram) { -			struct sh_mobile_meram_info *mdev; -			mdev = priv->meram_dev; -			mdev->ops->meram_unregister(mdev, ch->meram); -			ch->meram = 0; +		/* Free the MERAM cache. */ +		if (ch->cache) { +			sh_mobile_meram_cache_free(priv->meram_dev, ch->cache); +			ch->cache = 0;  		}  	} @@ -975,8 +1241,511 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)  			sh_mobile_lcdc_clk_off(priv);  } +static int __sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var, +				      struct fb_info *info) +{ +	if (var->xres > MAX_XRES || var->yres > MAX_YRES) +		return -EINVAL; + +	/* Make sure the virtual resolution is at least as big as the visible +	 * resolution. +	 */ +	if (var->xres_virtual < var->xres) +		var->xres_virtual = var->xres; +	if (var->yres_virtual < var->yres) +		var->yres_virtual = var->yres; + +	if (sh_mobile_format_is_fourcc(var)) { +		const struct sh_mobile_lcdc_format_info *format; + +		format = sh_mobile_format_info(var->grayscale); +		if (format == NULL) +			return -EINVAL; +		var->bits_per_pixel = format->bpp; + +		/* Default to RGB and JPEG color-spaces for RGB and YUV formats +		 * respectively. +		 */ +		if (!format->yuv) +			var->colorspace = V4L2_COLORSPACE_SRGB; +		else if (var->colorspace != V4L2_COLORSPACE_REC709) +			var->colorspace = V4L2_COLORSPACE_JPEG; +	} else { +		if (var->bits_per_pixel <= 16) {		/* RGB 565 */ +			var->bits_per_pixel = 16; +			var->red.offset = 11; +			var->red.length = 5; +			var->green.offset = 5; +			var->green.length = 6; +			var->blue.offset = 0; +			var->blue.length = 5; +			var->transp.offset = 0; +			var->transp.length = 0; +		} else if (var->bits_per_pixel <= 24) {		/* RGB 888 */ +			var->bits_per_pixel = 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->transp.offset = 0; +			var->transp.length = 0; +		} else if (var->bits_per_pixel <= 32) {		/* RGBA 888 */ +			var->bits_per_pixel = 32; +			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->transp.offset = 24; +			var->transp.length = 8; +		} else +			return -EINVAL; + +		var->red.msb_right = 0; +		var->green.msb_right = 0; +		var->blue.msb_right = 0; +		var->transp.msb_right = 0; +	} + +	/* Make sure we don't exceed our allocated memory. */ +	if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 > +	    info->fix.smem_len) +		return -EINVAL; + +	return 0; +} + +/* ----------------------------------------------------------------------------- + * Frame buffer operations - Overlays + */ + +static ssize_t +overlay_alpha_show(struct device *dev, struct device_attribute *attr, char *buf) +{ +	struct fb_info *info = dev_get_drvdata(dev); +	struct sh_mobile_lcdc_overlay *ovl = info->par; + +	return scnprintf(buf, PAGE_SIZE, "%u\n", ovl->alpha); +} + +static ssize_t +overlay_alpha_store(struct device *dev, struct device_attribute *attr, +		    const char *buf, size_t count) +{ +	struct fb_info *info = dev_get_drvdata(dev); +	struct sh_mobile_lcdc_overlay *ovl = info->par; +	unsigned int alpha; +	char *endp; + +	alpha = simple_strtoul(buf, &endp, 10); +	if (isspace(*endp)) +		endp++; + +	if (endp - buf != count) +		return -EINVAL; + +	if (alpha > 255) +		return -EINVAL; + +	if (ovl->alpha != alpha) { +		ovl->alpha = alpha; + +		if (ovl->mode == LCDC_OVERLAY_BLEND && ovl->enabled) +			sh_mobile_lcdc_overlay_setup(ovl); +	} + +	return count; +} + +static ssize_t +overlay_mode_show(struct device *dev, struct device_attribute *attr, char *buf) +{ +	struct fb_info *info = dev_get_drvdata(dev); +	struct sh_mobile_lcdc_overlay *ovl = info->par; + +	return scnprintf(buf, PAGE_SIZE, "%u\n", ovl->mode); +} + +static ssize_t +overlay_mode_store(struct device *dev, struct device_attribute *attr, +		   const char *buf, size_t count) +{ +	struct fb_info *info = dev_get_drvdata(dev); +	struct sh_mobile_lcdc_overlay *ovl = info->par; +	unsigned int mode; +	char *endp; + +	mode = simple_strtoul(buf, &endp, 10); +	if (isspace(*endp)) +		endp++; + +	if (endp - buf != count) +		return -EINVAL; + +	if (mode != LCDC_OVERLAY_BLEND && mode != LCDC_OVERLAY_ROP3) +		return -EINVAL; + +	if (ovl->mode != mode) { +		ovl->mode = mode; + +		if (ovl->enabled) +			sh_mobile_lcdc_overlay_setup(ovl); +	} + +	return count; +} + +static ssize_t +overlay_position_show(struct device *dev, struct device_attribute *attr, +		      char *buf) +{ +	struct fb_info *info = dev_get_drvdata(dev); +	struct sh_mobile_lcdc_overlay *ovl = info->par; + +	return scnprintf(buf, PAGE_SIZE, "%d,%d\n", ovl->pos_x, ovl->pos_y); +} + +static ssize_t +overlay_position_store(struct device *dev, struct device_attribute *attr, +		       const char *buf, size_t count) +{ +	struct fb_info *info = dev_get_drvdata(dev); +	struct sh_mobile_lcdc_overlay *ovl = info->par; +	char *endp; +	int pos_x; +	int pos_y; + +	pos_x = simple_strtol(buf, &endp, 10); +	if (*endp != ',') +		return -EINVAL; + +	pos_y = simple_strtol(endp + 1, &endp, 10); +	if (isspace(*endp)) +		endp++; + +	if (endp - buf != count) +		return -EINVAL; + +	if (ovl->pos_x != pos_x || ovl->pos_y != pos_y) { +		ovl->pos_x = pos_x; +		ovl->pos_y = pos_y; + +		if (ovl->enabled) +			sh_mobile_lcdc_overlay_setup(ovl); +	} + +	return count; +} + +static ssize_t +overlay_rop3_show(struct device *dev, struct device_attribute *attr, char *buf) +{ +	struct fb_info *info = dev_get_drvdata(dev); +	struct sh_mobile_lcdc_overlay *ovl = info->par; + +	return scnprintf(buf, PAGE_SIZE, "%u\n", ovl->rop3); +} + +static ssize_t +overlay_rop3_store(struct device *dev, struct device_attribute *attr, +		    const char *buf, size_t count) +{ +	struct fb_info *info = dev_get_drvdata(dev); +	struct sh_mobile_lcdc_overlay *ovl = info->par; +	unsigned int rop3; +	char *endp; + +	rop3 = !!simple_strtoul(buf, &endp, 10); +	if (isspace(*endp)) +		endp++; + +	if (endp - buf != count) +		return -EINVAL; + +	if (rop3 > 255) +		return -EINVAL; + +	if (ovl->rop3 != rop3) { +		ovl->rop3 = rop3; + +		if (ovl->mode == LCDC_OVERLAY_ROP3 && ovl->enabled) +			sh_mobile_lcdc_overlay_setup(ovl); +	} + +	return count; +} + +static const struct device_attribute overlay_sysfs_attrs[] = { +	__ATTR(ovl_alpha, S_IRUGO|S_IWUSR, +	       overlay_alpha_show, overlay_alpha_store), +	__ATTR(ovl_mode, S_IRUGO|S_IWUSR, +	       overlay_mode_show, overlay_mode_store), +	__ATTR(ovl_position, S_IRUGO|S_IWUSR, +	       overlay_position_show, overlay_position_store), +	__ATTR(ovl_rop3, S_IRUGO|S_IWUSR, +	       overlay_rop3_show, overlay_rop3_store), +}; + +static const struct fb_fix_screeninfo sh_mobile_lcdc_overlay_fix  = { +	.id =		"SH Mobile LCDC", +	.type =		FB_TYPE_PACKED_PIXELS, +	.visual =	FB_VISUAL_TRUECOLOR, +	.accel =	FB_ACCEL_NONE, +	.xpanstep =	1, +	.ypanstep =	1, +	.ywrapstep =	0, +	.capabilities =	FB_CAP_FOURCC, +}; + +static int sh_mobile_lcdc_overlay_pan(struct fb_var_screeninfo *var, +				    struct fb_info *info) +{ +	struct sh_mobile_lcdc_overlay *ovl = info->par; +	unsigned long base_addr_y; +	unsigned long base_addr_c; +	unsigned long y_offset; +	unsigned long c_offset; + +	if (!ovl->format->yuv) { +		y_offset = (var->yoffset * ovl->xres_virtual + var->xoffset) +			 * ovl->format->bpp / 8; +		c_offset = 0; +	} else { +		unsigned int xsub = ovl->format->bpp < 24 ? 2 : 1; +		unsigned int ysub = ovl->format->bpp < 16 ? 2 : 1; + +		y_offset = var->yoffset * ovl->xres_virtual + var->xoffset; +		c_offset = var->yoffset / ysub * ovl->xres_virtual * 2 / xsub +			 + var->xoffset * 2 / xsub; +	} + +	/* If the Y offset hasn't changed, the C offset hasn't either. There's +	 * nothing to do in that case. +	 */ +	if (y_offset == ovl->pan_y_offset) +		return 0; + +	/* Set the source address for the next refresh */ +	base_addr_y = ovl->dma_handle + y_offset; +	base_addr_c = ovl->dma_handle + ovl->xres_virtual * ovl->yres_virtual +		    + c_offset; + +	ovl->base_addr_y = base_addr_y; +	ovl->base_addr_c = base_addr_c; +	ovl->pan_y_offset = y_offset; + +	lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index)); + +	lcdc_write_overlay(ovl, LDBnBSAYR(ovl->index), ovl->base_addr_y); +	lcdc_write_overlay(ovl, LDBnBSACR(ovl->index), ovl->base_addr_c); + +	lcdc_write(ovl->channel->lcdc, LDBCR, +		   LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index)); + +	return 0; +} + +static int sh_mobile_lcdc_overlay_ioctl(struct fb_info *info, unsigned int cmd, +				      unsigned long arg) +{ +	struct sh_mobile_lcdc_overlay *ovl = info->par; + +	switch (cmd) { +	case FBIO_WAITFORVSYNC: +		return sh_mobile_lcdc_wait_for_vsync(ovl->channel); + +	default: +		return -ENOIOCTLCMD; +	} +} + +static int sh_mobile_lcdc_overlay_check_var(struct fb_var_screeninfo *var, +					  struct fb_info *info) +{ +	return __sh_mobile_lcdc_check_var(var, info); +} + +static int sh_mobile_lcdc_overlay_set_par(struct fb_info *info) +{ +	struct sh_mobile_lcdc_overlay *ovl = info->par; + +	ovl->format = +		sh_mobile_format_info(sh_mobile_format_fourcc(&info->var)); + +	ovl->xres = info->var.xres; +	ovl->xres_virtual = info->var.xres_virtual; +	ovl->yres = info->var.yres; +	ovl->yres_virtual = info->var.yres_virtual; + +	if (ovl->format->yuv) +		ovl->pitch = info->var.xres_virtual; +	else +		ovl->pitch = info->var.xres_virtual * ovl->format->bpp / 8; + +	sh_mobile_lcdc_overlay_setup(ovl); + +	info->fix.line_length = ovl->pitch; + +	if (sh_mobile_format_is_fourcc(&info->var)) { +		info->fix.type = FB_TYPE_FOURCC; +		info->fix.visual = FB_VISUAL_FOURCC; +	} else { +		info->fix.type = FB_TYPE_PACKED_PIXELS; +		info->fix.visual = FB_VISUAL_TRUECOLOR; +	} + +	return 0; +} + +/* Overlay blanking. Disable the overlay when blanked. */ +static int sh_mobile_lcdc_overlay_blank(int blank, struct fb_info *info) +{ +	struct sh_mobile_lcdc_overlay *ovl = info->par; + +	ovl->enabled = !blank; +	sh_mobile_lcdc_overlay_setup(ovl); + +	/* Prevent the backlight from receiving a blanking event by returning +	 * a non-zero value. +	 */ +	return 1; +} + +static struct fb_ops sh_mobile_lcdc_overlay_ops = { +	.owner          = THIS_MODULE, +	.fb_read        = fb_sys_read, +	.fb_write       = fb_sys_write, +	.fb_fillrect	= sys_fillrect, +	.fb_copyarea	= sys_copyarea, +	.fb_imageblit	= sys_imageblit, +	.fb_blank	= sh_mobile_lcdc_overlay_blank, +	.fb_pan_display = sh_mobile_lcdc_overlay_pan, +	.fb_ioctl       = sh_mobile_lcdc_overlay_ioctl, +	.fb_check_var	= sh_mobile_lcdc_overlay_check_var, +	.fb_set_par	= sh_mobile_lcdc_overlay_set_par, +}; + +static void +sh_mobile_lcdc_overlay_fb_unregister(struct sh_mobile_lcdc_overlay *ovl) +{ +	struct fb_info *info = ovl->info; + +	if (info == NULL || info->dev == NULL) +		return; + +	unregister_framebuffer(ovl->info); +} + +static int __devinit +sh_mobile_lcdc_overlay_fb_register(struct sh_mobile_lcdc_overlay *ovl) +{ +	struct sh_mobile_lcdc_priv *lcdc = ovl->channel->lcdc; +	struct fb_info *info = ovl->info; +	unsigned int i; +	int ret; + +	if (info == NULL) +		return 0; + +	ret = register_framebuffer(info); +	if (ret < 0) +		return ret; + +	dev_info(lcdc->dev, "registered %s/overlay %u as %dx%d %dbpp.\n", +		 dev_name(lcdc->dev), ovl->index, info->var.xres, +		 info->var.yres, info->var.bits_per_pixel); + +	for (i = 0; i < ARRAY_SIZE(overlay_sysfs_attrs); ++i) { +		ret = device_create_file(info->dev, &overlay_sysfs_attrs[i]); +		if (ret < 0) +			return ret; +	} + +	return 0; +} + +static void +sh_mobile_lcdc_overlay_fb_cleanup(struct sh_mobile_lcdc_overlay *ovl) +{ +	struct fb_info *info = ovl->info; + +	if (info == NULL || info->device == NULL) +		return; + +	framebuffer_release(info); +} + +static int __devinit +sh_mobile_lcdc_overlay_fb_init(struct sh_mobile_lcdc_overlay *ovl) +{ +	struct sh_mobile_lcdc_priv *priv = ovl->channel->lcdc; +	struct fb_var_screeninfo *var; +	struct fb_info *info; + +	/* Allocate and initialize the frame buffer device. */ +	info = framebuffer_alloc(0, priv->dev); +	if (info == NULL) { +		dev_err(priv->dev, "unable to allocate fb_info\n"); +		return -ENOMEM; +	} + +	ovl->info = info; + +	info->flags = FBINFO_FLAG_DEFAULT; +	info->fbops = &sh_mobile_lcdc_overlay_ops; +	info->device = priv->dev; +	info->screen_base = ovl->fb_mem; +	info->par = ovl; + +	/* Initialize fixed screen information. Restrict pan to 2 lines steps +	 * for NV12 and NV21. +	 */ +	info->fix = sh_mobile_lcdc_overlay_fix; +	snprintf(info->fix.id, sizeof(info->fix.id), +		 "SH Mobile LCDC Overlay %u", ovl->index); +	info->fix.smem_start = ovl->dma_handle; +	info->fix.smem_len = ovl->fb_size; +	info->fix.line_length = ovl->pitch; + +	if (ovl->format->yuv) +		info->fix.visual = FB_VISUAL_FOURCC; +	else +		info->fix.visual = FB_VISUAL_TRUECOLOR; + +	switch (ovl->format->fourcc) { +	case V4L2_PIX_FMT_NV12: +	case V4L2_PIX_FMT_NV21: +		info->fix.ypanstep = 2; +	case V4L2_PIX_FMT_NV16: +	case V4L2_PIX_FMT_NV61: +		info->fix.xpanstep = 2; +	} + +	/* Initialize variable screen information. */ +	var = &info->var; +	memset(var, 0, sizeof(*var)); +	var->xres = ovl->xres; +	var->yres = ovl->yres; +	var->xres_virtual = ovl->xres_virtual; +	var->yres_virtual = ovl->yres_virtual; +	var->activate = FB_ACTIVATE_NOW; + +	/* Use the legacy API by default for RGB formats, and the FOURCC API +	 * for YUV formats. +	 */ +	if (!ovl->format->yuv) +		var->bits_per_pixel = ovl->format->bpp; +	else +		var->grayscale = ovl->format->fourcc; + +	return sh_mobile_lcdc_overlay_check_var(var, info); +} +  /* ----------------------------------------------------------------------------- - * Frame buffer operations + * Frame buffer operations - main frame buffer   */  static int sh_mobile_lcdc_setcolreg(u_int regno, @@ -1003,12 +1772,12 @@ static int sh_mobile_lcdc_setcolreg(u_int regno,  	return 0;  } -static struct fb_fix_screeninfo sh_mobile_lcdc_fix  = { +static const struct fb_fix_screeninfo sh_mobile_lcdc_fix  = {  	.id =		"SH Mobile LCDC",  	.type =		FB_TYPE_PACKED_PIXELS,  	.visual =	FB_VISUAL_TRUECOLOR,  	.accel =	FB_ACCEL_NONE, -	.xpanstep =	0, +	.xpanstep =	1,  	.ypanstep =	1,  	.ywrapstep =	0,  	.capabilities =	FB_CAP_FOURCC, @@ -1035,78 +1804,74 @@ static void sh_mobile_lcdc_imageblit(struct fb_info *info,  	sh_mobile_lcdc_deferred_io_touch(info);  } -static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, -				     struct fb_info *info) +static int sh_mobile_lcdc_pan(struct fb_var_screeninfo *var, +			      struct fb_info *info)  {  	struct sh_mobile_lcdc_chan *ch = info->par;  	struct sh_mobile_lcdc_priv *priv = ch->lcdc;  	unsigned long ldrcntr; -	unsigned long new_pan_offset;  	unsigned long base_addr_y, base_addr_c; +	unsigned long y_offset;  	unsigned long c_offset; -	if (!ch->format->yuv) -		new_pan_offset = var->yoffset * ch->pitch -			       + var->xoffset * (ch->format->bpp / 8); -	else -		new_pan_offset = var->yoffset * ch->pitch + var->xoffset; +	if (!ch->format->yuv) { +		y_offset = (var->yoffset * ch->xres_virtual + var->xoffset) +			 * ch->format->bpp / 8; +		c_offset = 0; +	} else { +		unsigned int xsub = ch->format->bpp < 24 ? 2 : 1; +		unsigned int ysub = ch->format->bpp < 16 ? 2 : 1; -	if (new_pan_offset == ch->pan_offset) -		return 0;	/* No change, do nothing */ +		y_offset = var->yoffset * ch->xres_virtual + var->xoffset; +		c_offset = var->yoffset / ysub * ch->xres_virtual * 2 / xsub +			 + var->xoffset * 2 / xsub; +	} -	ldrcntr = lcdc_read(priv, _LDRCNTR); +	/* If the Y offset hasn't changed, the C offset hasn't either. There's +	 * nothing to do in that case. +	 */ +	if (y_offset == ch->pan_y_offset) +		return 0;  	/* Set the source address for the next refresh */ -	base_addr_y = ch->dma_handle + new_pan_offset; -	if (ch->format->yuv) { -		/* Set y offset */ -		c_offset = var->yoffset * ch->pitch -			 * (ch->format->bpp - 8) / 8; -		base_addr_c = ch->dma_handle + ch->xres * ch->yres_virtual -			    + c_offset; -		/* Set x offset */ -		if (ch->format->fourcc == V4L2_PIX_FMT_NV24) -			base_addr_c += 2 * var->xoffset; -		else -			base_addr_c += var->xoffset; -	} +	base_addr_y = ch->dma_handle + y_offset; +	base_addr_c = ch->dma_handle + ch->xres_virtual * ch->yres_virtual +		    + c_offset; -	if (ch->meram) { -		struct sh_mobile_meram_info *mdev; - -		mdev = priv->meram_dev; -		mdev->ops->meram_update(mdev, ch->meram, -					base_addr_y, base_addr_c, -					&base_addr_y, &base_addr_c); -	} +	if (ch->cache) +		sh_mobile_meram_cache_update(priv->meram_dev, ch->cache, +					     base_addr_y, base_addr_c, +					     &base_addr_y, &base_addr_c);  	ch->base_addr_y = base_addr_y;  	ch->base_addr_c = base_addr_c; +	ch->pan_y_offset = y_offset;  	lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);  	if (ch->format->yuv)  		lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c); +	ldrcntr = lcdc_read(priv, _LDRCNTR);  	if (lcdc_chan_is_sublcd(ch))  		lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS);  	else  		lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_MRS); -	ch->pan_offset = new_pan_offset;  	sh_mobile_lcdc_deferred_io_touch(info);  	return 0;  } -static int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd, -		       unsigned long arg) +static int sh_mobile_lcdc_ioctl(struct fb_info *info, unsigned int cmd, +				unsigned long arg)  { +	struct sh_mobile_lcdc_chan *ch = info->par;  	int retval;  	switch (cmd) {  	case FBIO_WAITFORVSYNC: -		retval = sh_mobile_wait_for_vsync(info->par); +		retval = sh_mobile_lcdc_wait_for_vsync(ch);  		break;  	default: @@ -1158,7 +1923,7 @@ static void sh_mobile_fb_reconfig(struct fb_info *info)   * Locking: both .fb_release() and .fb_open() are called with info->lock held if   * user == 1, or with console sem held, if user == 0.   */ -static int sh_mobile_release(struct fb_info *info, int user) +static int sh_mobile_lcdc_release(struct fb_info *info, int user)  {  	struct sh_mobile_lcdc_chan *ch = info->par; @@ -1179,7 +1944,7 @@ static int sh_mobile_release(struct fb_info *info, int user)  	return 0;  } -static int sh_mobile_open(struct fb_info *info, int user) +static int sh_mobile_lcdc_open(struct fb_info *info, int user)  {  	struct sh_mobile_lcdc_chan *ch = info->par; @@ -1192,7 +1957,8 @@ static int sh_mobile_open(struct fb_info *info, int user)  	return 0;  } -static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +static int sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var, +				    struct fb_info *info)  {  	struct sh_mobile_lcdc_chan *ch = info->par;  	struct sh_mobile_lcdc_priv *p = ch->lcdc; @@ -1200,9 +1966,7 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in  	unsigned int best_xres = 0;  	unsigned int best_yres = 0;  	unsigned int i; - -	if (var->xres > MAX_XRES || var->yres > MAX_YRES) -		return -EINVAL; +	int ret;  	/* If board code provides us with a list of available modes, make sure  	 * we use one of them. Find the mode closest to the requested one. The @@ -1237,73 +2001,9 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in  		var->yres = best_yres;  	} -	/* Make sure the virtual resolution is at least as big as the visible -	 * resolution. -	 */ -	if (var->xres_virtual < var->xres) -		var->xres_virtual = var->xres; -	if (var->yres_virtual < var->yres) -		var->yres_virtual = var->yres; - -	if (sh_mobile_format_is_fourcc(var)) { -		const struct sh_mobile_lcdc_format_info *format; - -		format = sh_mobile_format_info(var->grayscale); -		if (format == NULL) -			return -EINVAL; -		var->bits_per_pixel = format->bpp; - -		/* Default to RGB and JPEG color-spaces for RGB and YUV formats -		 * respectively. -		 */ -		if (!format->yuv) -			var->colorspace = V4L2_COLORSPACE_SRGB; -		else if (var->colorspace != V4L2_COLORSPACE_REC709) -			var->colorspace = V4L2_COLORSPACE_JPEG; -	} else { -		if (var->bits_per_pixel <= 16) {		/* RGB 565 */ -			var->bits_per_pixel = 16; -			var->red.offset = 11; -			var->red.length = 5; -			var->green.offset = 5; -			var->green.length = 6; -			var->blue.offset = 0; -			var->blue.length = 5; -			var->transp.offset = 0; -			var->transp.length = 0; -		} else if (var->bits_per_pixel <= 24) {		/* RGB 888 */ -			var->bits_per_pixel = 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->transp.offset = 0; -			var->transp.length = 0; -		} else if (var->bits_per_pixel <= 32) {		/* RGBA 888 */ -			var->bits_per_pixel = 32; -			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->transp.offset = 24; -			var->transp.length = 8; -		} else -			return -EINVAL; - -		var->red.msb_right = 0; -		var->green.msb_right = 0; -		var->blue.msb_right = 0; -		var->transp.msb_right = 0; -	} - -	/* Make sure we don't exceed our allocated memory. */ -	if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 > -	    info->fix.smem_len) -		return -EINVAL; +	ret = __sh_mobile_lcdc_check_var(var, info); +	if (ret < 0) +		return ret;  	/* only accept the forced_fourcc for dual channel configurations */  	if (p->forced_fourcc && @@ -1313,7 +2013,7 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in  	return 0;  } -static int sh_mobile_set_par(struct fb_info *info) +static int sh_mobile_lcdc_set_par(struct fb_info *info)  {  	struct sh_mobile_lcdc_chan *ch = info->par;  	int ret; @@ -1329,9 +2029,9 @@ static int sh_mobile_set_par(struct fb_info *info)  	ch->yres_virtual = info->var.yres_virtual;  	if (ch->format->yuv) -		ch->pitch = info->var.xres; +		ch->pitch = info->var.xres_virtual;  	else -		ch->pitch = info->var.xres * ch->format->bpp / 8; +		ch->pitch = info->var.xres_virtual * ch->format->bpp / 8;  	ret = sh_mobile_lcdc_start(ch->lcdc);  	if (ret < 0) @@ -1383,8 +2083,8 @@ static int sh_mobile_lcdc_blank(int blank, struct fb_info *info)  		 * mode will reenable the clocks and update the screen in time,  		 * so it does not need this. */  		if (!info->fbdefio) { -			sh_mobile_wait_for_vsync(ch); -			sh_mobile_wait_for_vsync(ch); +			sh_mobile_lcdc_wait_for_vsync(ch); +			sh_mobile_lcdc_wait_for_vsync(ch);  		}  		sh_mobile_lcdc_clk_off(p);  	} @@ -1402,12 +2102,12 @@ static struct fb_ops sh_mobile_lcdc_ops = {  	.fb_copyarea	= sh_mobile_lcdc_copyarea,  	.fb_imageblit	= sh_mobile_lcdc_imageblit,  	.fb_blank	= sh_mobile_lcdc_blank, -	.fb_pan_display = sh_mobile_fb_pan_display, -	.fb_ioctl       = sh_mobile_ioctl, -	.fb_open	= sh_mobile_open, -	.fb_release	= sh_mobile_release, -	.fb_check_var	= sh_mobile_check_var, -	.fb_set_par	= sh_mobile_set_par, +	.fb_pan_display = sh_mobile_lcdc_pan, +	.fb_ioctl       = sh_mobile_lcdc_ioctl, +	.fb_open	= sh_mobile_lcdc_open, +	.fb_release	= sh_mobile_lcdc_release, +	.fb_check_var	= sh_mobile_lcdc_check_var, +	.fb_set_par	= sh_mobile_lcdc_set_par,  };  static void @@ -1514,19 +2214,24 @@ sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch,  	else  		info->fix.visual = FB_VISUAL_TRUECOLOR; -	if (ch->format->fourcc == V4L2_PIX_FMT_NV12 || -	    ch->format->fourcc == V4L2_PIX_FMT_NV21) +	switch (ch->format->fourcc) { +	case V4L2_PIX_FMT_NV12: +	case V4L2_PIX_FMT_NV21:  		info->fix.ypanstep = 2; +	case V4L2_PIX_FMT_NV16: +	case V4L2_PIX_FMT_NV61: +		info->fix.xpanstep = 2; +	}  	/* Initialize variable screen information using the first mode as -	 * default. The default Y virtual resolution is twice the panel size to -	 * allow for double-buffering. +	 * default.  	 */  	var = &info->var;  	fb_videomode_to_var(var, mode);  	var->width = ch->cfg->panel_cfg.width;  	var->height = ch->cfg->panel_cfg.height; -	var->yres_virtual = var->yres * 2; +	var->xres_virtual = ch->xres_virtual; +	var->yres_virtual = ch->yres_virtual;  	var->activate = FB_ACTIVATE_NOW;  	/* Use the legacy API by default for RGB formats, and the FOURCC API @@ -1537,7 +2242,7 @@ sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch,  	else  		var->grayscale = ch->format->fourcc; -	ret = sh_mobile_check_var(var, info); +	ret = sh_mobile_lcdc_check_var(var, info);  	if (ret)  		return ret; @@ -1712,15 +2417,27 @@ static const struct fb_videomode default_720p __devinitconst = {  static int sh_mobile_lcdc_remove(struct platform_device *pdev)  {  	struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev); -	int i; +	unsigned int i;  	fb_unregister_client(&priv->notifier); +	for (i = 0; i < ARRAY_SIZE(priv->overlays); i++) +		sh_mobile_lcdc_overlay_fb_unregister(&priv->overlays[i]);  	for (i = 0; i < ARRAY_SIZE(priv->ch); i++)  		sh_mobile_lcdc_channel_fb_unregister(&priv->ch[i]);  	sh_mobile_lcdc_stop(priv); +	for (i = 0; i < ARRAY_SIZE(priv->overlays); i++) { +		struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i]; + +		sh_mobile_lcdc_overlay_fb_cleanup(ovl); + +		if (ovl->fb_mem) +			dma_free_coherent(&pdev->dev, ovl->fb_size, +					  ovl->fb_mem, ovl->dma_handle); +	} +  	for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {  		struct sh_mobile_lcdc_chan *ch = &priv->ch[i]; @@ -1737,8 +2454,11 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)  	}  	for (i = 0; i < ARRAY_SIZE(priv->ch); i++) { -		if (priv->ch[i].bl) -			sh_mobile_lcdc_bl_remove(priv->ch[i].bl); +		struct sh_mobile_lcdc_chan *ch = &priv->ch[i]; + +		if (ch->bl) +			sh_mobile_lcdc_bl_remove(ch->bl); +		mutex_destroy(&ch->open_lock);  	}  	if (priv->dot_clk) { @@ -1796,6 +2516,61 @@ static int __devinit sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *  }  static int __devinit +sh_mobile_lcdc_overlay_init(struct sh_mobile_lcdc_priv *priv, +			  struct sh_mobile_lcdc_overlay *ovl) +{ +	const struct sh_mobile_lcdc_format_info *format; +	int ret; + +	if (ovl->cfg->fourcc == 0) +		return 0; + +	/* Validate the format. */ +	format = sh_mobile_format_info(ovl->cfg->fourcc); +	if (format == NULL) { +		dev_err(priv->dev, "Invalid FOURCC %08x\n", ovl->cfg->fourcc); +		return -EINVAL; +	} + +	ovl->enabled = false; +	ovl->mode = LCDC_OVERLAY_BLEND; +	ovl->alpha = 255; +	ovl->rop3 = 0; +	ovl->pos_x = 0; +	ovl->pos_y = 0; + +	/* The default Y virtual resolution is twice the panel size to allow for +	 * double-buffering. +	 */ +	ovl->format = format; +	ovl->xres = ovl->cfg->max_xres; +	ovl->xres_virtual = ovl->xres; +	ovl->yres = ovl->cfg->max_yres; +	ovl->yres_virtual = ovl->yres * 2; + +	if (!format->yuv) +		ovl->pitch = ovl->xres_virtual * format->bpp / 8; +	else +		ovl->pitch = ovl->xres_virtual; + +	/* Allocate frame buffer memory. */ +	ovl->fb_size = ovl->cfg->max_xres * ovl->cfg->max_yres +		       * format->bpp / 8 * 2; +	ovl->fb_mem = dma_alloc_coherent(priv->dev, ovl->fb_size, +					   &ovl->dma_handle, GFP_KERNEL); +	if (!ovl->fb_mem) { +		dev_err(priv->dev, "unable to allocate buffer\n"); +		return -ENOMEM; +	} + +	ret = sh_mobile_lcdc_overlay_fb_init(ovl); +	if (ret < 0) +		return ret; + +	return 0; +} + +static int __devinit  sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,  			    struct sh_mobile_lcdc_chan *ch)  { @@ -1854,7 +2629,9 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,  		num_modes = cfg->num_modes;  	} -	/* Use the first mode as default. */ +	/* Use the first mode as default. The default Y virtual resolution is +	 * twice the panel size to allow for double-buffering. +	 */  	ch->format = format;  	ch->xres = mode->xres;  	ch->xres_virtual = mode->xres; @@ -1863,10 +2640,10 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,  	if (!format->yuv) {  		ch->colorspace = V4L2_COLORSPACE_SRGB; -		ch->pitch = ch->xres * format->bpp / 8; +		ch->pitch = ch->xres_virtual * format->bpp / 8;  	} else {  		ch->colorspace = V4L2_COLORSPACE_REC709; -		ch->pitch = ch->xres; +		ch->pitch = ch->xres_virtual;  	}  	ch->display.width = cfg->panel_cfg.width; @@ -1952,7 +2729,6 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)  		}  		init_waitqueue_head(&ch->frame_end_wait);  		init_completion(&ch->vsync_completion); -		ch->pan_offset = 0;  		/* probe the backlight is there is one defined */  		if (ch->cfg->bl_info.max_brightness) @@ -2003,6 +2779,17 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)  			goto err1;  	} +	for (i = 0; i < ARRAY_SIZE(pdata->overlays); i++) { +		struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i]; + +		ovl->cfg = &pdata->overlays[i]; +		ovl->channel = &priv->ch[0]; + +		error = sh_mobile_lcdc_overlay_init(priv, ovl); +		if (error) +			goto err1; +	} +  	error = sh_mobile_lcdc_start(priv);  	if (error) {  		dev_err(&pdev->dev, "unable to start hardware\n"); @@ -2017,6 +2804,14 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)  			goto err1;  	} +	for (i = 0; i < ARRAY_SIZE(pdata->overlays); i++) { +		struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i]; + +		error = sh_mobile_lcdc_overlay_fb_register(ovl); +		if (error) +			goto err1; +	} +  	/* Failure ignored */  	priv->notifier.notifier_call = sh_mobile_lcdc_notify;  	fb_register_client(&priv->notifier); diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h index 5c3bddd2cb72..0f92f6544b94 100644 --- a/drivers/video/sh_mobile_lcdcfb.h +++ b/drivers/video/sh_mobile_lcdcfb.h @@ -47,6 +47,7 @@ struct sh_mobile_lcdc_entity {  /*   * struct sh_mobile_lcdc_chan - LCDC display channel   * + * @pan_y_offset: Panning linear offset in bytes (luma component)   * @base_addr_y: Frame buffer viewport base address (luma component)   * @base_addr_c: Frame buffer viewport base address (chroma component)   * @pitch: Frame buffer line pitch @@ -59,7 +60,7 @@ struct sh_mobile_lcdc_chan {  	unsigned long *reg_offs;  	unsigned long ldmt1r_value;  	unsigned long enabled; /* ME and SE in LDCNT2R */ -	void *meram; +	void *cache;  	struct mutex open_lock;		/* protects the use counter */  	int use_count; @@ -68,7 +69,7 @@ struct sh_mobile_lcdc_chan {  	unsigned long fb_size;  	dma_addr_t dma_handle; -	unsigned long pan_offset; +	unsigned long pan_y_offset;  	unsigned long frame_end;  	wait_queue_head_t frame_end_wait; diff --git a/drivers/video/sh_mobile_meram.c b/drivers/video/sh_mobile_meram.c index 82ba830bf95d..7a0ba8bb3fbe 100644 --- a/drivers/video/sh_mobile_meram.c +++ b/drivers/video/sh_mobile_meram.c @@ -11,6 +11,7 @@  #include <linux/device.h>  #include <linux/err.h> +#include <linux/export.h>  #include <linux/genalloc.h>  #include <linux/io.h>  #include <linux/kernel.h> @@ -194,13 +195,28 @@ static inline unsigned long meram_read_reg(void __iomem *base, unsigned int off)  }  /* ----------------------------------------------------------------------------- - * Allocation + * MERAM allocation and free + */ + +static unsigned long meram_alloc(struct sh_mobile_meram_priv *priv, size_t size) +{ +	return gen_pool_alloc(priv->pool, size); +} + +static void meram_free(struct sh_mobile_meram_priv *priv, unsigned long mem, +		       size_t size) +{ +	gen_pool_free(priv->pool, mem, size); +} + +/* ----------------------------------------------------------------------------- + * LCDC cache planes allocation, init, cleanup and free   */  /* Allocate ICBs and MERAM for a plane. */ -static int __meram_alloc(struct sh_mobile_meram_priv *priv, -			 struct sh_mobile_meram_fb_plane *plane, -			 size_t size) +static int meram_plane_alloc(struct sh_mobile_meram_priv *priv, +			     struct sh_mobile_meram_fb_plane *plane, +			     size_t size)  {  	unsigned long mem;  	unsigned long idx; @@ -215,7 +231,7 @@ static int __meram_alloc(struct sh_mobile_meram_priv *priv,  		return -ENOMEM;  	plane->marker = &priv->icbs[idx]; -	mem = gen_pool_alloc(priv->pool, size * 1024); +	mem = meram_alloc(priv, size * 1024);  	if (mem == 0)  		return -ENOMEM; @@ -229,11 +245,11 @@ static int __meram_alloc(struct sh_mobile_meram_priv *priv,  }  /* Free ICBs and MERAM for a plane. */ -static void __meram_free(struct sh_mobile_meram_priv *priv, -			 struct sh_mobile_meram_fb_plane *plane) +static void meram_plane_free(struct sh_mobile_meram_priv *priv, +			     struct sh_mobile_meram_fb_plane *plane)  { -	gen_pool_free(priv->pool, priv->meram + plane->marker->offset, -		      plane->marker->size * 1024); +	meram_free(priv, priv->meram + plane->marker->offset, +		   plane->marker->size * 1024);  	__clear_bit(plane->marker->index, &priv->used_icb);  	__clear_bit(plane->cache->index, &priv->used_icb); @@ -248,62 +264,6 @@ static int is_nvcolor(int cspace)  	return 0;  } -/* Allocate memory for the ICBs and mark them as used. */ -static struct sh_mobile_meram_fb_cache * -meram_alloc(struct sh_mobile_meram_priv *priv, -	    const struct sh_mobile_meram_cfg *cfg, -	    int pixelformat) -{ -	struct sh_mobile_meram_fb_cache *cache; -	unsigned int nplanes = is_nvcolor(pixelformat) ? 2 : 1; -	int ret; - -	if (cfg->icb[0].meram_size == 0) -		return ERR_PTR(-EINVAL); - -	if (nplanes == 2 && cfg->icb[1].meram_size == 0) -		return ERR_PTR(-EINVAL); - -	cache = kzalloc(sizeof(*cache), GFP_KERNEL); -	if (cache == NULL) -		return ERR_PTR(-ENOMEM); - -	cache->nplanes = nplanes; - -	ret = __meram_alloc(priv, &cache->planes[0], cfg->icb[0].meram_size); -	if (ret < 0) -		goto error; - -	cache->planes[0].marker->current_reg = 1; -	cache->planes[0].marker->pixelformat = pixelformat; - -	if (cache->nplanes == 1) -		return cache; - -	ret = __meram_alloc(priv, &cache->planes[1], cfg->icb[1].meram_size); -	if (ret < 0) { -		__meram_free(priv, &cache->planes[0]); -		goto error; -	} - -	return cache; - -error: -	kfree(cache); -	return ERR_PTR(-ENOMEM); -} - -/* Unmark the specified ICB as used. */ -static void meram_free(struct sh_mobile_meram_priv *priv, -		       struct sh_mobile_meram_fb_cache *cache) -{ -	__meram_free(priv, &cache->planes[0]); -	if (cache->nplanes == 2) -		__meram_free(priv, &cache->planes[1]); - -	kfree(cache); -} -  /* Set the next address to fetch. */  static void meram_set_next_addr(struct sh_mobile_meram_priv *priv,  				struct sh_mobile_meram_fb_cache *cache, @@ -355,10 +315,10 @@ meram_get_next_icb_addr(struct sh_mobile_meram_info *pdata,  	(((x) * (y) + (MERAM_LINE_WIDTH - 1)) & ~(MERAM_LINE_WIDTH - 1))  /* Initialize MERAM. */ -static int meram_init(struct sh_mobile_meram_priv *priv, -		      struct sh_mobile_meram_fb_plane *plane, -		      unsigned int xres, unsigned int yres, -		      unsigned int *out_pitch) +static int meram_plane_init(struct sh_mobile_meram_priv *priv, +			    struct sh_mobile_meram_fb_plane *plane, +			    unsigned int xres, unsigned int yres, +			    unsigned int *out_pitch)  {  	struct sh_mobile_meram_icb *marker = plane->marker;  	unsigned long total_byte_count = MERAM_CALC_BYTECOUNT(xres, yres); @@ -427,8 +387,8 @@ static int meram_init(struct sh_mobile_meram_priv *priv,  	return 0;  } -static void meram_deinit(struct sh_mobile_meram_priv *priv, -			 struct sh_mobile_meram_fb_plane *plane) +static void meram_plane_cleanup(struct sh_mobile_meram_priv *priv, +				struct sh_mobile_meram_fb_plane *plane)  {  	/* disable ICB */  	meram_write_icb(priv->base, plane->cache->index,  MExxCTL, @@ -441,20 +401,82 @@ static void meram_deinit(struct sh_mobile_meram_priv *priv,  }  /* ----------------------------------------------------------------------------- - * Registration/unregistration + * MERAM operations   */ -static void *sh_mobile_meram_register(struct sh_mobile_meram_info *pdata, -				      const struct sh_mobile_meram_cfg *cfg, -				      unsigned int xres, unsigned int yres, -				      unsigned int pixelformat, -				      unsigned int *pitch) +unsigned long sh_mobile_meram_alloc(struct sh_mobile_meram_info *pdata, +				    size_t size) +{ +	struct sh_mobile_meram_priv *priv = pdata->priv; + +	return meram_alloc(priv, size); +} +EXPORT_SYMBOL_GPL(sh_mobile_meram_alloc); + +void sh_mobile_meram_free(struct sh_mobile_meram_info *pdata, unsigned long mem, +			  size_t size) +{ +	struct sh_mobile_meram_priv *priv = pdata->priv; + +	meram_free(priv, mem, size); +} +EXPORT_SYMBOL_GPL(sh_mobile_meram_free); + +/* Allocate memory for the ICBs and mark them as used. */ +static struct sh_mobile_meram_fb_cache * +meram_cache_alloc(struct sh_mobile_meram_priv *priv, +		  const struct sh_mobile_meram_cfg *cfg, +		  int pixelformat) +{ +	unsigned int nplanes = is_nvcolor(pixelformat) ? 2 : 1; +	struct sh_mobile_meram_fb_cache *cache; +	int ret; + +	cache = kzalloc(sizeof(*cache), GFP_KERNEL); +	if (cache == NULL) +		return ERR_PTR(-ENOMEM); + +	cache->nplanes = nplanes; + +	ret = meram_plane_alloc(priv, &cache->planes[0], +				cfg->icb[0].meram_size); +	if (ret < 0) +		goto error; + +	cache->planes[0].marker->current_reg = 1; +	cache->planes[0].marker->pixelformat = pixelformat; + +	if (cache->nplanes == 1) +		return cache; + +	ret = meram_plane_alloc(priv, &cache->planes[1], +				cfg->icb[1].meram_size); +	if (ret < 0) { +		meram_plane_free(priv, &cache->planes[0]); +		goto error; +	} + +	return cache; + +error: +	kfree(cache); +	return ERR_PTR(-ENOMEM); +} + +void *sh_mobile_meram_cache_alloc(struct sh_mobile_meram_info *pdata, +				  const struct sh_mobile_meram_cfg *cfg, +				  unsigned int xres, unsigned int yres, +				  unsigned int pixelformat, unsigned int *pitch)  {  	struct sh_mobile_meram_fb_cache *cache;  	struct sh_mobile_meram_priv *priv = pdata->priv;  	struct platform_device *pdev = pdata->pdev; +	unsigned int nplanes = is_nvcolor(pixelformat) ? 2 : 1;  	unsigned int out_pitch; +	if (priv == NULL) +		return ERR_PTR(-ENODEV); +  	if (pixelformat != SH_MOBILE_MERAM_PF_NV &&  	    pixelformat != SH_MOBILE_MERAM_PF_NV24 &&  	    pixelformat != SH_MOBILE_MERAM_PF_RGB) @@ -469,10 +491,16 @@ static void *sh_mobile_meram_register(struct sh_mobile_meram_info *pdata,  		return ERR_PTR(-EINVAL);  	} +	if (cfg->icb[0].meram_size == 0) +		return ERR_PTR(-EINVAL); + +	if (nplanes == 2 && cfg->icb[1].meram_size == 0) +		return ERR_PTR(-EINVAL); +  	mutex_lock(&priv->lock);  	/* We now register the ICBs and allocate the MERAM regions. */ -	cache = meram_alloc(priv, cfg, pixelformat); +	cache = meram_cache_alloc(priv, cfg, pixelformat);  	if (IS_ERR(cache)) {  		dev_err(&pdev->dev, "MERAM allocation failed (%ld).",  			PTR_ERR(cache)); @@ -480,42 +508,50 @@ static void *sh_mobile_meram_register(struct sh_mobile_meram_info *pdata,  	}  	/* initialize MERAM */ -	meram_init(priv, &cache->planes[0], xres, yres, &out_pitch); +	meram_plane_init(priv, &cache->planes[0], xres, yres, &out_pitch);  	*pitch = out_pitch;  	if (pixelformat == SH_MOBILE_MERAM_PF_NV) -		meram_init(priv, &cache->planes[1], xres, (yres + 1) / 2, -			&out_pitch); +		meram_plane_init(priv, &cache->planes[1], +				 xres, (yres + 1) / 2, &out_pitch);  	else if (pixelformat == SH_MOBILE_MERAM_PF_NV24) -		meram_init(priv, &cache->planes[1], 2 * xres, (yres + 1) / 2, -			&out_pitch); +		meram_plane_init(priv, &cache->planes[1], +				 2 * xres, (yres + 1) / 2, &out_pitch);  err:  	mutex_unlock(&priv->lock);  	return cache;  } +EXPORT_SYMBOL_GPL(sh_mobile_meram_cache_alloc); -static void -sh_mobile_meram_unregister(struct sh_mobile_meram_info *pdata, void *data) +void +sh_mobile_meram_cache_free(struct sh_mobile_meram_info *pdata, void *data)  {  	struct sh_mobile_meram_fb_cache *cache = data;  	struct sh_mobile_meram_priv *priv = pdata->priv;  	mutex_lock(&priv->lock); -	/* deinit & free */ -	meram_deinit(priv, &cache->planes[0]); -	if (cache->nplanes == 2) -		meram_deinit(priv, &cache->planes[1]); +	/* Cleanup and free. */ +	meram_plane_cleanup(priv, &cache->planes[0]); +	meram_plane_free(priv, &cache->planes[0]); -	meram_free(priv, cache); +	if (cache->nplanes == 2) { +		meram_plane_cleanup(priv, &cache->planes[1]); +		meram_plane_free(priv, &cache->planes[1]); +	} + +	kfree(cache);  	mutex_unlock(&priv->lock);  } +EXPORT_SYMBOL_GPL(sh_mobile_meram_cache_free); -static void -sh_mobile_meram_update(struct sh_mobile_meram_info *pdata, void *data, -		       unsigned long base_addr_y, unsigned long base_addr_c, -		       unsigned long *icb_addr_y, unsigned long *icb_addr_c) +void +sh_mobile_meram_cache_update(struct sh_mobile_meram_info *pdata, void *data, +			     unsigned long base_addr_y, +			     unsigned long base_addr_c, +			     unsigned long *icb_addr_y, +			     unsigned long *icb_addr_c)  {  	struct sh_mobile_meram_fb_cache *cache = data;  	struct sh_mobile_meram_priv *priv = pdata->priv; @@ -527,13 +563,7 @@ sh_mobile_meram_update(struct sh_mobile_meram_info *pdata, void *data,  	mutex_unlock(&priv->lock);  } - -static struct sh_mobile_meram_ops sh_mobile_meram_ops = { -	.module			= THIS_MODULE, -	.meram_register		= sh_mobile_meram_register, -	.meram_unregister	= sh_mobile_meram_unregister, -	.meram_update		= sh_mobile_meram_update, -}; +EXPORT_SYMBOL_GPL(sh_mobile_meram_cache_update);  /* -----------------------------------------------------------------------------   * Power management @@ -624,7 +654,6 @@ static int __devinit sh_mobile_meram_probe(struct platform_device *pdev)  	for (i = 0; i < MERAM_ICB_NUM; ++i)  		priv->icbs[i].index = i; -	pdata->ops = &sh_mobile_meram_ops;  	pdata->priv = priv;  	pdata->pdev = pdev; diff --git a/drivers/video/smscufx.c b/drivers/video/smscufx.c index 26f864289498..5533a32c6ca1 100644 --- a/drivers/video/smscufx.c +++ b/drivers/video/smscufx.c @@ -904,7 +904,7 @@ static ssize_t ufx_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); diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c index 90a2e30272ad..2f6b2b835f88 100644 --- a/drivers/video/w100fb.c +++ b/drivers/video/w100fb.c @@ -1567,6 +1567,18 @@ static void w100_suspend(u32 mode)  		val = readl(remapped_regs + mmPLL_CNTL);  		val |= 0x00000004;  /* bit2=1 */  		writel(val, remapped_regs + mmPLL_CNTL); + +		writel(0x00000000, remapped_regs + mmLCDD_CNTL1); +		writel(0x00000000, remapped_regs + mmLCDD_CNTL2); +		writel(0x00000000, remapped_regs + mmGENLCD_CNTL1); +		writel(0x00000000, remapped_regs + mmGENLCD_CNTL2); +		writel(0x00000000, remapped_regs + mmGENLCD_CNTL3); + +		val = readl(remapped_regs + mmMEM_EXT_CNTL); +		val |= 0xF0000000; +		val &= ~(0x00000001); +		writel(val, remapped_regs + mmMEM_EXT_CNTL); +  		writel(0x0000001d, remapped_regs + mmPWRMGT_CNTL);  	}  } diff --git a/include/video/da8xx-fb.h b/include/video/da8xx-fb.h index 89d43b3d4cb9..5a0e4f9efb53 100644 --- a/include/video/da8xx-fb.h +++ b/include/video/da8xx-fb.h @@ -82,6 +82,9 @@ struct lcd_ctrl_config {  	/* Raster Data Order Select: 1=Most-to-least 0=Least-to-most */  	unsigned char raster_order; + +	/* DMA FIFO threshold */ +	int fifo_th;  };  struct lcd_sync_arg { diff --git a/include/video/omapdss.h b/include/video/omapdss.h index c8e59b4a3364..a6267a2d292b 100644 --- a/include/video/omapdss.h +++ b/include/video/omapdss.h @@ -48,6 +48,10 @@  #define DISPC_IRQ_FRAMEDONEWB		(1 << 23)  #define DISPC_IRQ_FRAMEDONETV		(1 << 24)  #define DISPC_IRQ_WBBUFFEROVERFLOW	(1 << 25) +#define DISPC_IRQ_FRAMEDONE3		(1 << 26) +#define DISPC_IRQ_VSYNC3		(1 << 27) +#define DISPC_IRQ_ACBIAS_COUNT_STAT3	(1 << 28) +#define DISPC_IRQ_SYNC_LOST3		(1 << 29)  struct omap_dss_device;  struct omap_overlay_manager; @@ -75,6 +79,7 @@ enum omap_channel {  	OMAP_DSS_CHANNEL_LCD	= 0,  	OMAP_DSS_CHANNEL_DIGIT	= 1,  	OMAP_DSS_CHANNEL_LCD2	= 2, +	OMAP_DSS_CHANNEL_LCD3	= 3,  };  enum omap_color_mode { @@ -99,11 +104,6 @@ enum omap_color_mode {  	OMAP_DSS_COLOR_XRGB16_1555	= 1 << 18, /* xRGB16 - 1555 */  }; -enum omap_lcd_display_type { -	OMAP_DSS_LCD_DISPLAY_STN, -	OMAP_DSS_LCD_DISPLAY_TFT, -}; -  enum omap_dss_load_mode {  	OMAP_DSS_LOAD_CLUT_AND_FRAME	= 0,  	OMAP_DSS_LOAD_CLUT_ONLY		= 1, @@ -121,15 +121,15 @@ enum omap_rfbi_te_mode {  	OMAP_DSS_RFBI_TE_MODE_2 = 2,  }; -enum omap_panel_config { -	OMAP_DSS_LCD_IVS		= 1<<0, -	OMAP_DSS_LCD_IHS		= 1<<1, -	OMAP_DSS_LCD_IPC		= 1<<2, -	OMAP_DSS_LCD_IEO		= 1<<3, -	OMAP_DSS_LCD_RF			= 1<<4, -	OMAP_DSS_LCD_ONOFF		= 1<<5, +enum omap_dss_signal_level { +	OMAPDSS_SIG_ACTIVE_HIGH	= 0, +	OMAPDSS_SIG_ACTIVE_LOW	= 1, +}; -	OMAP_DSS_LCD_TFT		= 1<<20, +enum omap_dss_signal_edge { +	OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, +	OMAPDSS_DRIVE_SIG_RISING_EDGE, +	OMAPDSS_DRIVE_SIG_FALLING_EDGE,  };  enum omap_dss_venc_type { @@ -167,13 +167,6 @@ enum omap_dss_audio_state {  	OMAP_DSS_AUDIO_PLAYING,  }; -/* XXX perhaps this should be removed */ -enum omap_dss_overlay_managers { -	OMAP_DSS_OVL_MGR_LCD, -	OMAP_DSS_OVL_MGR_TV, -	OMAP_DSS_OVL_MGR_LCD2, -}; -  enum omap_dss_rotation_type {  	OMAP_DSS_ROT_DMA	= 1 << 0,  	OMAP_DSS_ROT_VRFB	= 1 << 1, @@ -268,9 +261,6 @@ struct omap_dss_dsi_videomode_data {  	int hfp_blanking_mode;  	/* Video port sync events */ -	int vp_de_pol; -	int vp_hsync_pol; -	int vp_vsync_pol;  	bool vp_vsync_end;  	bool vp_hsync_end; @@ -346,6 +336,19 @@ struct omap_video_timings {  	u16 vfp;	/* Vertical front porch */  	/* Unit: line clocks */  	u16 vbp;	/* Vertical back porch */ + +	/* Vsync logic level */ +	enum omap_dss_signal_level vsync_level; +	/* Hsync logic level */ +	enum omap_dss_signal_level hsync_level; +	/* Interlaced or Progressive timings */ +	bool interlace; +	/* Pixel clock edge to drive LCD data */ +	enum omap_dss_signal_edge data_pclk_edge; +	/* Data enable logic level */ +	enum omap_dss_signal_level de_level; +	/* Pixel clock edges to drive HSYNC and VSYNC signals */ +	enum omap_dss_signal_edge sync_pclk_edge;  };  #ifdef CONFIG_OMAP2_DSS_VENC @@ -559,8 +562,6 @@ struct omap_dss_device {  		/* Unit: line clocks */  		int acb;	/* ac-bias pin frequency */ -		enum omap_panel_config config; -  		enum omap_dss_dsi_pixel_format dsi_pix_fmt;  		enum omap_dss_dsi_mode dsi_mode;  		struct omap_dss_dsi_videomode_data dsi_vm_data; diff --git a/include/video/sh_mobile_lcdc.h b/include/video/sh_mobile_lcdc.h index 7571b27a0ba1..ff43ffc1aab2 100644 --- a/include/video/sh_mobile_lcdc.h +++ b/include/video/sh_mobile_lcdc.h @@ -166,6 +166,12 @@ struct sh_mobile_lcdc_bl_info {  	int (*get_brightness)(void);  }; +struct sh_mobile_lcdc_overlay_cfg { +	int fourcc; +	unsigned int max_xres; +	unsigned int max_yres; +}; +  struct sh_mobile_lcdc_chan_cfg {  	int chan;  	int fourcc; @@ -186,6 +192,7 @@ struct sh_mobile_lcdc_chan_cfg {  struct sh_mobile_lcdc_info {  	int clock_source;  	struct sh_mobile_lcdc_chan_cfg ch[2]; +	struct sh_mobile_lcdc_overlay_cfg overlays[4];  	struct sh_mobile_meram_info *meram_dev;  }; diff --git a/include/video/sh_mobile_meram.h b/include/video/sh_mobile_meram.h index 29b2fd3b147e..062e6e7f955c 100644 --- a/include/video/sh_mobile_meram.h +++ b/include/video/sh_mobile_meram.h @@ -15,7 +15,6 @@ enum {  struct sh_mobile_meram_priv; -struct sh_mobile_meram_ops;  /*   * struct sh_mobile_meram_info - MERAM platform data @@ -24,7 +23,6 @@ struct sh_mobile_meram_ops;  struct sh_mobile_meram_info {  	int				addr_mode;  	u32				reserved_icbs; -	struct sh_mobile_meram_ops	*ops;  	struct sh_mobile_meram_priv	*priv;  	struct platform_device		*pdev;  }; @@ -38,26 +36,59 @@ struct sh_mobile_meram_cfg {  	struct sh_mobile_meram_icb_cfg icb[2];  }; -struct module; -struct sh_mobile_meram_ops { -	struct module	*module; -	/* register usage of meram */ -	void *(*meram_register)(struct sh_mobile_meram_info *meram_dev, -				const struct sh_mobile_meram_cfg *cfg, -				unsigned int xres, unsigned int yres, -				unsigned int pixelformat, -				unsigned int *pitch); +#if defined(CONFIG_FB_SH_MOBILE_MERAM) || \ +    defined(CONFIG_FB_SH_MOBILE_MERAM_MODULE) +unsigned long sh_mobile_meram_alloc(struct sh_mobile_meram_info *meram_dev, +				    size_t size); +void sh_mobile_meram_free(struct sh_mobile_meram_info *meram_dev, +			  unsigned long mem, size_t size); +void *sh_mobile_meram_cache_alloc(struct sh_mobile_meram_info *dev, +				  const struct sh_mobile_meram_cfg *cfg, +				  unsigned int xres, unsigned int yres, +				  unsigned int pixelformat, +				  unsigned int *pitch); +void sh_mobile_meram_cache_free(struct sh_mobile_meram_info *dev, void *data); +void sh_mobile_meram_cache_update(struct sh_mobile_meram_info *dev, void *data, +				  unsigned long base_addr_y, +				  unsigned long base_addr_c, +				  unsigned long *icb_addr_y, +				  unsigned long *icb_addr_c); +#else +static inline unsigned long +sh_mobile_meram_alloc(struct sh_mobile_meram_info *meram_dev, size_t size) +{ +	return 0; +} -	/* unregister usage of meram */ -	void (*meram_unregister)(struct sh_mobile_meram_info *meram_dev, -				 void *data); +static inline void +sh_mobile_meram_free(struct sh_mobile_meram_info *meram_dev, +		     unsigned long mem, size_t size) +{ +} -	/* update meram settings */ -	void (*meram_update)(struct sh_mobile_meram_info *meram_dev, void *data, +static inline void * +sh_mobile_meram_cache_alloc(struct sh_mobile_meram_info *dev, +			    const struct sh_mobile_meram_cfg *cfg, +			    unsigned int xres, unsigned int yres, +			    unsigned int pixelformat, +			    unsigned int *pitch) +{ +	return ERR_PTR(-ENODEV); +} + +static inline void +sh_mobile_meram_cache_free(struct sh_mobile_meram_info *dev, void *data) +{ +} + +static inline void +sh_mobile_meram_cache_update(struct sh_mobile_meram_info *dev, void *data,  			     unsigned long base_addr_y,  			     unsigned long base_addr_c,  			     unsigned long *icb_addr_y, -			     unsigned long *icb_addr_c); -}; +			     unsigned long *icb_addr_c) +{ +} +#endif  #endif /* __VIDEO_SH_MOBILE_MERAM_H__  */ | 
