SUPERH platform development
 help / color / mirror / Atom feed
* [PATCH 53/57] fbdev: sh_mobile_meram: Don't perform update in register operation
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
  To: linux-fbdev

Remove the RGB or Y/C base address update from the meram_register()
operation, as this belongs to the meram_update() operation.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mobile_lcdcfb.c |    8 +++++---
 drivers/video/sh_mobile_meram.c  |   15 ++-------------
 include/video/sh_mobile_meram.h  |    4 ----
 3 files changed, 7 insertions(+), 20 deletions(-)

diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 4e9572c..e10a78a 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -880,11 +880,13 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 
 		meram = mdev->ops->meram_register(mdev, ch->cfg->meram_cfg,
 					ch->pitch, ch->yres, pixelformat,
-					ch->base_addr_y, ch->base_addr_c,
-					&ch->base_addr_y, &ch->base_addr_c,
 					&ch->pitch);
-		if (!IS_ERR(meram))
+		if (!IS_ERR(meram)) {
+			mdev->ops->meram_update(mdev, meram,
+					ch->base_addr_y, ch->base_addr_c,
+					&ch->base_addr_y, &ch->base_addr_c);
 			ch->meram = meram;
+		}
 	}
 
 	/* Start the LCDC. */
diff --git a/drivers/video/sh_mobile_meram.c b/drivers/video/sh_mobile_meram.c
index 01ae5b6..aad8b0b 100644
--- a/drivers/video/sh_mobile_meram.c
+++ b/drivers/video/sh_mobile_meram.c
@@ -447,10 +447,6 @@ 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 long base_addr_y,
-				      unsigned long base_addr_c,
-				      unsigned long *icb_addr_y,
-				      unsigned long *icb_addr_c,
 				      unsigned int *pitch)
 {
 	struct sh_mobile_meram_fb_cache *cache;
@@ -469,9 +465,8 @@ static void *sh_mobile_meram_register(struct sh_mobile_meram_info *pdata,
 	priv = pdata->priv;
 	pdev = pdata->pdev;
 
-	dev_dbg(&pdev->dev, "registering %dx%d (%s) (y=%08lx, c=%08lx)",
-		xres, yres, (!pixelformat) ? "yuv" : "rgb",
-		base_addr_y, base_addr_c);
+	dev_dbg(&pdev->dev, "registering %dx%d (%s)", xres, yres,
+		!pixelformat ? "yuv" : "rgb");
 
 	/* we can't handle wider than 8192px */
 	if (xres > 8192) {
@@ -499,12 +494,6 @@ static void *sh_mobile_meram_register(struct sh_mobile_meram_info *pdata,
 		meram_init(priv, &cache->planes[1], 2 * xres, (yres + 1) / 2,
 			&out_pitch);
 
-	meram_set_next_addr(priv, cache, base_addr_y, base_addr_c);
-	meram_get_next_icb_addr(pdata, cache, icb_addr_y, icb_addr_c);
-
-	dev_dbg(&pdev->dev, "registered - can access via y=%08lx, c=%08lx",
-		*icb_addr_y, *icb_addr_c);
-
 err:
 	mutex_unlock(&priv->lock);
 	return cache;
diff --git a/include/video/sh_mobile_meram.h b/include/video/sh_mobile_meram.h
index 8ff98eb..51c98ca 100644
--- a/include/video/sh_mobile_meram.h
+++ b/include/video/sh_mobile_meram.h
@@ -41,10 +41,6 @@ struct sh_mobile_meram_ops {
 				const struct sh_mobile_meram_cfg *cfg,
 				unsigned int xres, unsigned int yres,
 				unsigned int pixelformat,
-				unsigned long base_addr_y,
-				unsigned long base_addr_c,
-				unsigned long *icb_addr_y,
-				unsigned long *icb_addr_c,
 				unsigned int *pitch);
 
 	/* unregister usage of meram */
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 52/57] arm: mach-shmobile: Constify sh_mobile_meram_cfg structures
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
  To: linux-fbdev

The structures, passed to the sh_mobile_lcdcfb driver through platform
data, are read only by the driver. Make them const.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 arch/arm/mach-shmobile/board-ap4evb.c   |    5 +++--
 arch/arm/mach-shmobile/board-mackerel.c |    4 ++--
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c
index d6d9e0f..8dc6f4e 100644
--- a/arch/arm/mach-shmobile/board-ap4evb.c
+++ b/arch/arm/mach-shmobile/board-ap4evb.c
@@ -587,7 +587,8 @@ static const struct fb_videomode ap4evb_lcdc_modes[] = {
 #endif
 	},
 };
-static struct sh_mobile_meram_cfg lcd_meram_cfg = {
+
+static const struct sh_mobile_meram_cfg lcd_meram_cfg = {
 	.icb[0] = {
 		.meram_size     = 0x40,
 	},
@@ -852,7 +853,7 @@ static long ap4evb_clk_optimize(unsigned long target, unsigned long *best_freq,
 	return error;
 }
 
-static struct sh_mobile_meram_cfg hdmi_meram_cfg = {
+static const struct sh_mobile_meram_cfg hdmi_meram_cfg = {
 	.icb[0] = {
 		.meram_size     = 0x100,
 	},
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index 6e0db88..53b32c2 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -374,7 +374,7 @@ static int mackerel_get_brightness(void)
 	return gpio_get_value(GPIO_PORT31);
 }
 
-static struct sh_mobile_meram_cfg lcd_meram_cfg = {
+static const struct sh_mobile_meram_cfg lcd_meram_cfg = {
 	.icb[0] = {
 		.meram_size     = 0x40,
 	},
@@ -460,7 +460,7 @@ static struct platform_device hdmi_device = {
 	},
 };
 
-static struct sh_mobile_meram_cfg hdmi_meram_cfg = {
+static const struct sh_mobile_meram_cfg hdmi_meram_cfg = {
 	.icb[0] = {
 		.meram_size     = 0x100,
 	},
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 51/57] fbdev: sh_mobile_lcdc: Don't store copy of platform data
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
  To: linux-fbdev

Instead of copying the whole platform data structure to struct
sh_mobile_lcdc_chan, store a const pointer to the channel platform data.

MERAM configuration information needs to be changed at runtime, so copy
it to struct sh_mobile_lcdc_chan.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mobile_lcdcfb.c |   71 ++++++++++++++++++-------------------
 drivers/video/sh_mobile_lcdcfb.h |    3 +-
 include/video/sh_mobile_lcdc.h   |    2 +-
 3 files changed, 38 insertions(+), 38 deletions(-)

diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index c1f1e03..4e9572c 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -116,7 +116,7 @@ static bool banked(int reg_nr)
 
 static int lcdc_chan_is_sublcd(struct sh_mobile_lcdc_chan *chan)
 {
-	return chan->cfg.chan = LCDC_CHAN_SUBLCD;
+	return chan->cfg->chan = LCDC_CHAN_SUBLCD;
 }
 
 static void lcdc_write_chan(struct sh_mobile_lcdc_chan *chan,
@@ -289,7 +289,7 @@ static void sh_mobile_lcdc_deferred_io(struct fb_info *info,
 				       struct list_head *pagelist)
 {
 	struct sh_mobile_lcdc_chan *ch = info->par;
-	struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg.panel_cfg;
+	const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg;
 
 	/* enable clocks before accessing hardware */
 	sh_mobile_lcdc_clk_on(ch->lcdc);
@@ -336,7 +336,7 @@ static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info)
 
 static void sh_mobile_lcdc_display_on(struct sh_mobile_lcdc_chan *ch)
 {
-	struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg.panel_cfg;
+	const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg;
 	int ret;
 
 	if (ch->tx_dev) {
@@ -355,7 +355,7 @@ static void sh_mobile_lcdc_display_on(struct sh_mobile_lcdc_chan *ch)
 
 static void sh_mobile_lcdc_display_off(struct sh_mobile_lcdc_chan *ch)
 {
-	struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg.panel_cfg;
+	const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg;
 
 	if (panel->display_off)
 		panel->display_off();
@@ -642,16 +642,16 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
 	tmp = ch->ldmt1r_value;
 	tmp |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : LDMT1R_VPOL;
 	tmp |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : LDMT1R_HPOL;
-	tmp |= (ch->cfg.flags & LCDC_FLAGS_DWPOL) ? LDMT1R_DWPOL : 0;
-	tmp |= (ch->cfg.flags & LCDC_FLAGS_DIPOL) ? LDMT1R_DIPOL : 0;
-	tmp |= (ch->cfg.flags & LCDC_FLAGS_DAPOL) ? LDMT1R_DAPOL : 0;
-	tmp |= (ch->cfg.flags & LCDC_FLAGS_HSCNT) ? LDMT1R_HSCNT : 0;
-	tmp |= (ch->cfg.flags & LCDC_FLAGS_DWCNT) ? LDMT1R_DWCNT : 0;
+	tmp |= (ch->cfg->flags & LCDC_FLAGS_DWPOL) ? LDMT1R_DWPOL : 0;
+	tmp |= (ch->cfg->flags & LCDC_FLAGS_DIPOL) ? LDMT1R_DIPOL : 0;
+	tmp |= (ch->cfg->flags & LCDC_FLAGS_DAPOL) ? LDMT1R_DAPOL : 0;
+	tmp |= (ch->cfg->flags & LCDC_FLAGS_HSCNT) ? LDMT1R_HSCNT : 0;
+	tmp |= (ch->cfg->flags & LCDC_FLAGS_DWCNT) ? LDMT1R_DWCNT : 0;
 	lcdc_write_chan(ch, LDMT1R, tmp);
 
 	/* setup SYS bus */
-	lcdc_write_chan(ch, LDMT2R, ch->cfg.sys_bus_cfg.ldmt2r);
-	lcdc_write_chan(ch, LDMT3R, ch->cfg.sys_bus_cfg.ldmt3r);
+	lcdc_write_chan(ch, LDMT2R, ch->cfg->sys_bus_cfg.ldmt2r);
+	lcdc_write_chan(ch, LDMT3R, ch->cfg->sys_bus_cfg.ldmt3r);
 
 	/* horizontal configuration */
 	h_total = mode->xres + mode->hsync_len + mode->left_margin
@@ -715,7 +715,7 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 		/* Power supply */
 		lcdc_write_chan(ch, LDPMR, 0);
 
-		m = ch->cfg.clock_divider;
+		m = ch->cfg->clock_divider;
 		if (!m)
 			continue;
 
@@ -766,7 +766,7 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 		 * continuous read mode.
 		 */
 		if (ch->ldmt1r_value & LDMT1R_IFM &&
-		    ch->cfg.sys_bus_cfg.deferred_io_msec) {
+		    ch->cfg->sys_bus_cfg.deferred_io_msec) {
 			lcdc_write_chan(ch, LDSM1R, LDSM1R_OS);
 			lcdc_write(priv, _LDINTR, LDINTR_FE);
 		} else {
@@ -820,13 +820,13 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 	lcdc_wait_bit(priv, _LDCNT2R, LDCNT2R_BR, 0);
 
 	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
-		struct sh_mobile_lcdc_panel_cfg *panel;
+		const struct sh_mobile_lcdc_panel_cfg *panel;
 
 		ch = &priv->ch[k];
 		if (!ch->enabled)
 			continue;
 
-		panel = &ch->cfg.panel_cfg;
+		panel = &ch->cfg->panel_cfg;
 		if (panel->setup_sys) {
 			ret = panel->setup_sys(ch, &sh_mobile_lcdc_sys_bus_ops);
 			if (ret)
@@ -836,7 +836,6 @@ 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++) {
-		struct sh_mobile_meram_cfg *cfg;
 		int pixelformat;
 		void *meram;
 
@@ -848,8 +847,8 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 		ch->base_addr_c = ch->base_addr_y + ch->xres * ch->yres_virtual;
 
 		/* Enable MERAM if possible. */
-		cfg = ch->cfg.meram_cfg;
-		if (mdev = NULL || mdev->ops = NULL || cfg = NULL)
+		if (mdev = NULL || mdev->ops = NULL ||
+		    ch->cfg->meram_cfg = NULL)
 			continue;
 
 		/* we need to de-init configured ICBs before we can
@@ -879,8 +878,8 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 			break;
 		}
 
-		meram = mdev->ops->meram_register(mdev, cfg, ch->pitch,
-					ch->yres, pixelformat,
+		meram = mdev->ops->meram_register(mdev, ch->cfg->meram_cfg,
+					ch->pitch, ch->yres, pixelformat,
 					ch->base_addr_y, ch->base_addr_c,
 					&ch->base_addr_y, &ch->base_addr_c,
 					&ch->pitch);
@@ -899,7 +898,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 		if (!ch->enabled)
 			continue;
 
-		tmp = ch->cfg.sys_bus_cfg.deferred_io_msec;
+		tmp = ch->cfg->sys_bus_cfg.deferred_io_msec;
 		if (ch->ldmt1r_value & LDMT1R_IFM && tmp) {
 			ch->defio.deferred_io = sh_mobile_lcdc_deferred_io;
 			ch->defio.delay = msecs_to_jiffies(tmp);
@@ -1207,8 +1206,8 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in
 	 * distance between two modes is defined as the size of the
 	 * non-overlapping parts of the two rectangles.
 	 */
-	for (i = 0; i < ch->cfg.num_modes; ++i) {
-		const struct fb_videomode *mode = &ch->cfg.lcd_modes[i];
+	for (i = 0; i < ch->cfg->num_modes; ++i) {
+		const struct fb_videomode *mode = &ch->cfg->lcd_modes[i];
 		unsigned int dist;
 
 		/* We can only round up. */
@@ -1227,7 +1226,7 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in
 	}
 
 	/* If no available mode can be used, return an error. */
-	if (ch->cfg.num_modes != 0) {
+	if (ch->cfg->num_modes != 0) {
 		if (best_dist = (unsigned int)-1)
 			return -EINVAL;
 
@@ -1437,7 +1436,7 @@ sh_mobile_lcdc_channel_fb_register(struct sh_mobile_lcdc_chan *ch)
 		return ret;
 
 	dev_info(ch->lcdc->dev, "registered %s/%s as %dx%d %dbpp.\n",
-		 dev_name(ch->lcdc->dev), (ch->cfg.chan = LCDC_CHAN_MAINLCD) ?
+		 dev_name(ch->lcdc->dev), (ch->cfg->chan = LCDC_CHAN_MAINLCD) ?
 		 "mainlcd" : "sublcd", info->var.xres, info->var.yres,
 		 info->var.bits_per_pixel);
 
@@ -1522,8 +1521,8 @@ sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch,
 	 */
 	var = &info->var;
 	fb_videomode_to_var(var, mode);
-	var->width = ch->cfg.panel_cfg.width;
-	var->height = ch->cfg.panel_cfg.height;
+	var->width = ch->cfg->panel_cfg.width;
+	var->height = ch->cfg->panel_cfg.height;
 	var->yres_virtual = var->yres * 2;
 	var->activate = FB_ACTIVATE_NOW;
 
@@ -1555,14 +1554,14 @@ static int sh_mobile_lcdc_update_bl(struct backlight_device *bdev)
 	    bdev->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
 		brightness = 0;
 
-	return ch->cfg.bl_info.set_brightness(brightness);
+	return ch->cfg->bl_info.set_brightness(brightness);
 }
 
 static int sh_mobile_lcdc_get_brightness(struct backlight_device *bdev)
 {
 	struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev);
 
-	return ch->cfg.bl_info.get_brightness();
+	return ch->cfg->bl_info.get_brightness();
 }
 
 static int sh_mobile_lcdc_check_fb(struct backlight_device *bdev,
@@ -1583,7 +1582,7 @@ static struct backlight_device *sh_mobile_lcdc_bl_probe(struct device *parent,
 {
 	struct backlight_device *bl;
 
-	bl = backlight_device_register(ch->cfg.bl_info.name, parent, ch,
+	bl = backlight_device_register(ch->cfg->bl_info.name, parent, ch,
 				       &sh_mobile_lcdc_bl_ops, NULL);
 	if (IS_ERR(bl)) {
 		dev_err(parent, "unable to register backlight device: %ld\n",
@@ -1591,7 +1590,7 @@ static struct backlight_device *sh_mobile_lcdc_bl_probe(struct device *parent,
 		return NULL;
 	}
 
-	bl->props.max_brightness = ch->cfg.bl_info.max_brightness;
+	bl->props.max_brightness = ch->cfg->bl_info.max_brightness;
 	bl->props.brightness = bl->props.max_brightness;
 	backlight_update_status(bl);
 
@@ -1724,7 +1723,7 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
 
 		if (ch->tx_dev) {
 			ch->tx_dev->lcdc = NULL;
-			module_put(ch->cfg.tx_dev->dev.driver->owner);
+			module_put(ch->cfg->tx_dev->dev.driver->owner);
 		}
 
 		sh_mobile_lcdc_channel_fb_cleanup(ch);
@@ -1756,7 +1755,7 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
 static int __devinit
 sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
 {
-	int interface_type = ch->cfg.interface_type;
+	int interface_type = ch->cfg->interface_type;
 
 	switch (interface_type) {
 	case RGB8:
@@ -1799,7 +1798,7 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
 			    struct sh_mobile_lcdc_chan *ch)
 {
 	const struct sh_mobile_lcdc_format_info *format;
-	struct sh_mobile_lcdc_chan_cfg *cfg = &ch->cfg;
+	const struct sh_mobile_lcdc_chan_cfg *cfg = ch->cfg;
 	const struct fb_videomode *max_mode;
 	const struct fb_videomode *mode;
 	unsigned int num_modes;
@@ -1942,7 +1941,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
 		struct sh_mobile_lcdc_chan *ch = priv->ch + num_channels;
 
 		ch->lcdc = priv;
-		memcpy(&ch->cfg, &pdata->ch[i], sizeof(pdata->ch[i]));
+		ch->cfg = &pdata->ch[i];
 
 		error = sh_mobile_lcdc_check_interface(ch);
 		if (error) {
@@ -1954,7 +1953,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
 		ch->pan_offset = 0;
 
 		/* probe the backlight is there is one defined */
-		if (ch->cfg.bl_info.max_brightness)
+		if (ch->cfg->bl_info.max_brightness)
 			ch->bl = sh_mobile_lcdc_bl_probe(&pdev->dev, ch);
 
 		switch (pdata->ch[i].chan) {
diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h
index bf1707c..da1c26e 100644
--- a/drivers/video/sh_mobile_lcdcfb.h
+++ b/drivers/video/sh_mobile_lcdcfb.h
@@ -54,7 +54,7 @@ struct sh_mobile_lcdc_entity {
 struct sh_mobile_lcdc_chan {
 	struct sh_mobile_lcdc_priv *lcdc;
 	struct sh_mobile_lcdc_entity *tx_dev;
-	struct sh_mobile_lcdc_chan_cfg cfg;
+	const struct sh_mobile_lcdc_chan_cfg *cfg;
 
 	unsigned long *reg_offs;
 	unsigned long ldmt1r_value;
@@ -66,6 +66,7 @@ struct sh_mobile_lcdc_chan {
 
 	void *fb_mem;
 	unsigned long fb_size;
+
 	dma_addr_t dma_handle;
 	unsigned long pan_offset;
 
diff --git a/include/video/sh_mobile_lcdc.h b/include/video/sh_mobile_lcdc.h
index 5a6991d..53cbbd4 100644
--- a/include/video/sh_mobile_lcdc.h
+++ b/include/video/sh_mobile_lcdc.h
@@ -178,7 +178,7 @@ struct sh_mobile_lcdc_chan_cfg {
 	struct sh_mobile_lcdc_panel_cfg panel_cfg;
 	struct sh_mobile_lcdc_bl_info bl_info;
 	struct sh_mobile_lcdc_sys_bus_cfg sys_bus_cfg; /* only for SYSn I/F */
-	struct sh_mobile_meram_cfg *meram_cfg;
+	const struct sh_mobile_meram_cfg *meram_cfg;
 
 	struct platform_device *tx_dev;	/* HDMI/MIPI transmitter device */
 };
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 50/57] fbdev: sh_mobile_meram: Remove unused sh_mobile_meram_icb_cfg fields
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
  To: linux-fbdev

The marker_icb and cache_icb fields are not used anymore, remove them.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 include/video/sh_mobile_meram.h |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)

diff --git a/include/video/sh_mobile_meram.h b/include/video/sh_mobile_meram.h
index ea96b5a..8ff98eb 100644
--- a/include/video/sh_mobile_meram.h
+++ b/include/video/sh_mobile_meram.h
@@ -26,8 +26,6 @@ struct sh_mobile_meram_info {
 
 /* icb config */
 struct sh_mobile_meram_icb_cfg {
-	unsigned int marker_icb;	/* ICB # for Marker ICB */
-	unsigned int cache_icb;		/* ICB # for Cache ICB */
 	unsigned int meram_size;	/* MERAM Buffer Size to use */
 };
 
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 49/57] arm: mach-shmobile: Don't set MERAM ICB numbers in platform data
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
  To: linux-fbdev

The marker and cache ICBs are now allocated automatically, there's no
need to specify them manually anymore.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 arch/arm/mach-shmobile/board-ap4evb.c   |    8 --------
 arch/arm/mach-shmobile/board-mackerel.c |    8 --------
 2 files changed, 0 insertions(+), 16 deletions(-)

diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c
index d3896dc..d6d9e0f 100644
--- a/arch/arm/mach-shmobile/board-ap4evb.c
+++ b/arch/arm/mach-shmobile/board-ap4evb.c
@@ -589,13 +589,9 @@ static const struct fb_videomode ap4evb_lcdc_modes[] = {
 };
 static struct sh_mobile_meram_cfg lcd_meram_cfg = {
 	.icb[0] = {
-		.marker_icb     = 28,
-		.cache_icb      = 24,
 		.meram_size     = 0x40,
 	},
 	.icb[1] = {
-		.marker_icb     = 29,
-		.cache_icb      = 25,
 		.meram_size     = 0x40,
 	},
 };
@@ -858,13 +854,9 @@ static long ap4evb_clk_optimize(unsigned long target, unsigned long *best_freq,
 
 static struct sh_mobile_meram_cfg hdmi_meram_cfg = {
 	.icb[0] = {
-		.marker_icb     = 30,
-		.cache_icb      = 26,
 		.meram_size     = 0x100,
 	},
 	.icb[1] = {
-		.marker_icb     = 31,
-		.cache_icb      = 27,
 		.meram_size     = 0x100,
 	},
 };
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index d555d9e..6e0db88 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -376,13 +376,9 @@ static int mackerel_get_brightness(void)
 
 static struct sh_mobile_meram_cfg lcd_meram_cfg = {
 	.icb[0] = {
-		.marker_icb     = 28,
-		.cache_icb      = 24,
 		.meram_size     = 0x40,
 	},
 	.icb[1] = {
-		.marker_icb     = 29,
-		.cache_icb      = 25,
 		.meram_size     = 0x40,
 	},
 };
@@ -466,13 +462,9 @@ static struct platform_device hdmi_device = {
 
 static struct sh_mobile_meram_cfg hdmi_meram_cfg = {
 	.icb[0] = {
-		.marker_icb     = 30,
-		.cache_icb      = 26,
 		.meram_size     = 0x100,
 	},
 	.icb[1] = {
-		.marker_icb     = 31,
-		.cache_icb      = 27,
 		.meram_size     = 0x100,
 	},
 };
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 48/57] fbdev: sh_mobile_meram: Allocate ICBs automatically
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
  To: linux-fbdev

Instead of manually specifying the ICBs to use in platform data,
allocate them automatically at runtime.

The MERAM registration function now returns a pointer to an opaque MERAM
object, which is passed to the update and unregistration functions.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mobile_lcdcfb.c |   27 ++--
 drivers/video/sh_mobile_lcdcfb.h |    2 +-
 drivers/video/sh_mobile_meram.c  |  341 ++++++++++++++++++++------------------
 include/video/sh_mobile_meram.h  |   22 ++--
 4 files changed, 207 insertions(+), 185 deletions(-)

diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 453fc92..c1f1e03 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -838,6 +838,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
 		struct sh_mobile_meram_cfg *cfg;
 		int pixelformat;
+		void *meram;
 
 		ch = &priv->ch[k];
 		if (!ch->enabled)
@@ -854,9 +855,9 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 		/* we need to de-init configured ICBs before we can
 		 * re-initialize them.
 		 */
-		if (ch->meram_enabled) {
-			mdev->ops->meram_unregister(mdev, cfg);
-			ch->meram_enabled = 0;
+		if (ch->meram) {
+			mdev->ops->meram_unregister(mdev, ch->meram);
+			ch->meram = NULL;
 		}
 
 		switch (ch->format->fourcc) {
@@ -878,13 +879,13 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 			break;
 		}
 
-		ret = mdev->ops->meram_register(mdev, cfg, ch->pitch,
+		meram = mdev->ops->meram_register(mdev, cfg, ch->pitch,
 					ch->yres, pixelformat,
 					ch->base_addr_y, ch->base_addr_c,
 					&ch->base_addr_y, &ch->base_addr_c,
 					&ch->pitch);
-		if (!ret)
-			ch->meram_enabled = 1;
+		if (!IS_ERR(meram))
+			ch->meram = meram;
 	}
 
 	/* Start the LCDC. */
@@ -949,13 +950,11 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
 		sh_mobile_lcdc_display_off(ch);
 
 		/* disable the meram */
-		if (ch->meram_enabled) {
-			struct sh_mobile_meram_cfg *cfg;
+		if (ch->meram) {
 			struct sh_mobile_meram_info *mdev;
-			cfg = ch->cfg.meram_cfg;
 			mdev = priv->meram_dev;
-			mdev->ops->meram_unregister(mdev, cfg);
-			ch->meram_enabled = 0;
+			mdev->ops->meram_unregister(mdev, ch->meram);
+			ch->meram = 0;
 		}
 
 	}
@@ -1068,14 +1067,12 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
 			base_addr_c += var->xoffset;
 	}
 
-	if (ch->meram_enabled) {
-		struct sh_mobile_meram_cfg *cfg;
+	if (ch->meram) {
 		struct sh_mobile_meram_info *mdev;
 		int ret;
 
-		cfg = ch->cfg.meram_cfg;
 		mdev = priv->meram_dev;
-		ret = mdev->ops->meram_update(mdev, cfg,
+		ret = mdev->ops->meram_update(mdev, ch->meram,
 					base_addr_y, base_addr_c,
 					&base_addr_y, &base_addr_c);
 		if (ret)
diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h
index 19a4cd7..bf1707c 100644
--- a/drivers/video/sh_mobile_lcdcfb.h
+++ b/drivers/video/sh_mobile_lcdcfb.h
@@ -59,7 +59,7 @@ struct sh_mobile_lcdc_chan {
 	unsigned long *reg_offs;
 	unsigned long ldmt1r_value;
 	unsigned long enabled; /* ME and SE in LDCNT2R */
-	int meram_enabled;
+	void *meram;
 
 	struct mutex open_lock;		/* protects the use counter */
 	int use_count;
diff --git a/drivers/video/sh_mobile_meram.c b/drivers/video/sh_mobile_meram.c
index 7cd706d..01ae5b6 100644
--- a/drivers/video/sh_mobile_meram.c
+++ b/drivers/video/sh_mobile_meram.c
@@ -10,6 +10,7 @@
  */
 
 #include <linux/device.h>
+#include <linux/err.h>
 #include <linux/genalloc.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
@@ -107,13 +108,14 @@ static const unsigned long icb_regs[] = {
  * sh_mobile_meram_icb - MERAM ICB information
  * @regs: Registers cache
  * @offset: MERAM block offset
- * @size: MERAM block size in bytes
+ * @size: MERAM block size in KiB
  * @cache_unit: Bytes to cache per ICB
  * @pixelformat: Video pixel format of the data stored in the ICB
  * @current_reg: Which of Start Address Register A (0) or B (1) is in use
  */
 struct sh_mobile_meram_icb {
 	unsigned long regs[ICB_REGS_SIZE];
+	unsigned int index;
 	unsigned long offset;
 	unsigned int size;
 
@@ -124,6 +126,16 @@ struct sh_mobile_meram_icb {
 
 #define MERAM_ICB_NUM			32
 
+struct sh_mobile_meram_fb_plane {
+	struct sh_mobile_meram_icb *marker;
+	struct sh_mobile_meram_icb *cache;
+};
+
+struct sh_mobile_meram_fb_cache {
+	unsigned int nplanes;
+	struct sh_mobile_meram_fb_plane planes[2];
+};
+
 /*
  * sh_mobile_meram_priv - MERAM device
  * @base: Registers base address
@@ -184,54 +196,46 @@ static inline unsigned long meram_read_reg(void __iomem *base, unsigned int off)
  * Allocation
  */
 
-/* Check if there's no overlaps in MERAM allocation. */
-static int meram_check_overlap(struct sh_mobile_meram_priv *priv,
-			       const struct sh_mobile_meram_icb_cfg *new)
+/* 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)
 {
-	/* valid ICB? */
-	if (new->marker_icb & ~0x1f || new->cache_icb & ~0x1f)
-		return 1;
-
-	if (test_bit(new->marker_icb, &priv->used_icb) ||
-	    test_bit(new->cache_icb,  &priv->used_icb))
-		return  1;
+	unsigned long mem;
+	unsigned long idx;
 
-	return 0;
-}
+	idx = find_first_zero_bit(&priv->used_icb, 28);
+	if (idx = 28)
+		return -ENOMEM;
+	plane->cache = &priv->icbs[idx];
 
-/* Allocate memory for the ICBs and mark them as used. */
-static int meram_alloc(struct sh_mobile_meram_priv *priv,
-		       const struct sh_mobile_meram_icb_cfg *new,
-		       int pixelformat)
-{
-	struct sh_mobile_meram_icb *marker = &priv->icbs[new->marker_icb];
-	unsigned long mem;
+	idx = find_next_zero_bit(&priv->used_icb, 32, 28);
+	if (idx = 32)
+		return -ENOMEM;
+	plane->marker = &priv->icbs[idx];
 
-	mem = gen_pool_alloc(priv->pool, new->meram_size * 1024);
+	mem = gen_pool_alloc(priv->pool, size * 1024);
 	if (mem = 0)
 		return -ENOMEM;
 
-	__set_bit(new->marker_icb, &priv->used_icb);
-	__set_bit(new->cache_icb, &priv->used_icb);
+	__set_bit(plane->marker->index, &priv->used_icb);
+	__set_bit(plane->cache->index, &priv->used_icb);
 
-	marker->offset = mem - priv->meram;
-	marker->size = new->meram_size * 1024;
-	marker->current_reg = 1;
-	marker->pixelformat = pixelformat;
+	plane->marker->offset = mem - priv->meram;
+	plane->marker->size = size;
 
 	return 0;
 }
 
-/* Unmark the specified ICB as used. */
-static void meram_free(struct sh_mobile_meram_priv *priv,
-		       const struct sh_mobile_meram_icb_cfg *icb)
+/* Free ICBs and MERAM for a plane. */
+static void __meram_free(struct sh_mobile_meram_priv *priv,
+			 struct sh_mobile_meram_fb_plane *plane)
 {
-	struct sh_mobile_meram_icb *marker = &priv->icbs[icb->marker_icb];
+	gen_pool_free(priv->pool, priv->meram + plane->marker->offset,
+		      plane->marker->size * 1024);
 
-	gen_pool_free(priv->pool, priv->meram + marker->offset, marker->size);
-
-	__clear_bit(icb->marker_icb, &priv->used_icb);
-	__clear_bit(icb->cache_icb, &priv->used_icb);
+	__clear_bit(plane->marker->index, &priv->used_icb);
+	__clear_bit(plane->cache->index, &priv->used_icb);
 }
 
 /* Is this a YCbCr(NV12, NV16 or NV24) colorspace? */
@@ -243,42 +247,96 @@ 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,
-				const struct sh_mobile_meram_cfg *cfg,
+				struct sh_mobile_meram_fb_cache *cache,
 				unsigned long base_addr_y,
 				unsigned long base_addr_c)
 {
-	struct sh_mobile_meram_icb *icb = &priv->icbs[cfg->icb[0].marker_icb];
+	struct sh_mobile_meram_icb *icb = cache->planes[0].marker;
 	unsigned long target;
 
 	icb->current_reg ^= 1;
 	target = icb->current_reg ? MExxSARB : MExxSARA;
 
 	/* set the next address to fetch */
-	meram_write_icb(priv->base, cfg->icb[0].cache_icb, target,
+	meram_write_icb(priv->base, cache->planes[0].cache->index, target,
 			base_addr_y);
-	meram_write_icb(priv->base, cfg->icb[0].marker_icb, target,
-			base_addr_y +
-			priv->icbs[cfg->icb[0].marker_icb].cache_unit);
-
-	if (is_nvcolor(icb->pixelformat)) {
-		meram_write_icb(priv->base, cfg->icb[1].cache_icb,  target,
-				base_addr_c);
-		meram_write_icb(priv->base, cfg->icb[1].marker_icb, target,
-				base_addr_c +
-				priv->icbs[cfg->icb[1].marker_icb].cache_unit);
+	meram_write_icb(priv->base, cache->planes[0].marker->index, target,
+			base_addr_y + cache->planes[0].marker->cache_unit);
+
+	if (cache->nplanes = 2) {
+		meram_write_icb(priv->base, cache->planes[1].cache->index,
+				target, base_addr_c);
+		meram_write_icb(priv->base, cache->planes[1].marker->index,
+				target, base_addr_c +
+				cache->planes[1].marker->cache_unit);
 	}
 }
 
 /* Get the next ICB address. */
 static void
 meram_get_next_icb_addr(struct sh_mobile_meram_info *pdata,
-			const struct sh_mobile_meram_cfg *cfg,
+			struct sh_mobile_meram_fb_cache *cache,
 			unsigned long *icb_addr_y, unsigned long *icb_addr_c)
 {
-	struct sh_mobile_meram_priv *priv = pdata->priv;
-	struct sh_mobile_meram_icb *icb = &priv->icbs[cfg->icb[0].marker_icb];
+	struct sh_mobile_meram_icb *icb = cache->planes[0].marker;
 	unsigned long icb_offset;
 
 	if (pdata->addr_mode = SH_MOBILE_MERAM_MODE0)
@@ -286,9 +344,10 @@ meram_get_next_icb_addr(struct sh_mobile_meram_info *pdata,
 	else
 		icb_offset = 0xc0000000 | (icb->current_reg << 23);
 
-	*icb_addr_y = icb_offset | (cfg->icb[0].marker_icb << 24);
-	if (is_nvcolor(icb->pixelformat))
-		*icb_addr_c = icb_offset | (cfg->icb[1].marker_icb << 24);
+	*icb_addr_y = icb_offset | (cache->planes[0].marker->index << 24);
+	if (cache->nplanes = 2)
+		*icb_addr_c = icb_offset
+			    | (cache->planes[1].marker->index << 24);
 }
 
 #define MERAM_CALC_BYTECOUNT(x, y) \
@@ -296,11 +355,11 @@ meram_get_next_icb_addr(struct sh_mobile_meram_info *pdata,
 
 /* Initialize MERAM. */
 static int meram_init(struct sh_mobile_meram_priv *priv,
-		      const struct sh_mobile_meram_icb_cfg *icb,
+		      struct sh_mobile_meram_fb_plane *plane,
 		      unsigned int xres, unsigned int yres,
 		      unsigned int *out_pitch)
 {
-	struct sh_mobile_meram_icb *marker = &priv->icbs[icb->marker_icb];
+	struct sh_mobile_meram_icb *marker = plane->marker;
 	unsigned long total_byte_count = MERAM_CALC_BYTECOUNT(xres, yres);
 	unsigned long bnm;
 	unsigned int lcdc_pitch;
@@ -319,13 +378,13 @@ static int meram_init(struct sh_mobile_meram_priv *priv,
 		lcdc_pitch = xpitch = MERAM_LINE_WIDTH;
 		line_cnt = total_byte_count >> 11;
 		*out_pitch = xres;
-		save_lines = (icb->meram_size / 16 / MERAM_SEC_LINE);
+		save_lines = plane->marker->size / 16 / MERAM_SEC_LINE;
 		save_lines *= MERAM_SEC_LINE;
 	} else {
 		xpitch = xres;
 		line_cnt = yres;
 		*out_pitch = lcdc_pitch;
-		save_lines = icb->meram_size / (lcdc_pitch >> 10) / 2;
+		save_lines = plane->marker->size / (lcdc_pitch >> 10) / 2;
 		save_lines &= 0xff;
 	}
 	bnm = (save_lines - 1) << 16;
@@ -333,20 +392,20 @@ static int meram_init(struct sh_mobile_meram_priv *priv,
 	/* TODO: we better to check if we have enough MERAM buffer size */
 
 	/* set up ICB */
-	meram_write_icb(priv->base, icb->cache_icb,  MExxBSIZE,
+	meram_write_icb(priv->base, plane->cache->index,  MExxBSIZE,
 			MERAM_MExxBSIZE_VAL(0x0, line_cnt - 1, xpitch - 1));
-	meram_write_icb(priv->base, icb->marker_icb, MExxBSIZE,
+	meram_write_icb(priv->base, plane->marker->index, MExxBSIZE,
 			MERAM_MExxBSIZE_VAL(0xf, line_cnt - 1, xpitch - 1));
 
-	meram_write_icb(priv->base, icb->cache_icb,  MExxMNCF, bnm);
-	meram_write_icb(priv->base, icb->marker_icb, MExxMNCF, bnm);
+	meram_write_icb(priv->base, plane->cache->index,  MExxMNCF, bnm);
+	meram_write_icb(priv->base, plane->marker->index, MExxMNCF, bnm);
 
-	meram_write_icb(priv->base, icb->cache_icb,  MExxSBSIZE, xpitch);
-	meram_write_icb(priv->base, icb->marker_icb, MExxSBSIZE, xpitch);
+	meram_write_icb(priv->base, plane->cache->index,  MExxSBSIZE, xpitch);
+	meram_write_icb(priv->base, plane->marker->index, MExxSBSIZE, xpitch);
 
 	/* save a cache unit size */
-	priv->icbs[icb->cache_icb].cache_unit = xres * save_lines;
-	priv->icbs[icb->marker_icb].cache_unit = xres * save_lines;
+	plane->cache->cache_unit = xres * save_lines;
+	plane->marker->cache_unit = xres * save_lines;
 
 	/*
 	 * Set MERAM for framebuffer
@@ -354,13 +413,13 @@ static int meram_init(struct sh_mobile_meram_priv *priv,
 	 * we also chain the cache_icb and the marker_icb.
 	 * we also split the allocated MERAM buffer between two ICBs.
 	 */
-	meram_write_icb(priv->base, icb->cache_icb, MExxCTL,
-			MERAM_MExxCTL_VAL(icb->marker_icb, marker->offset) |
-			MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM |
+	meram_write_icb(priv->base, plane->cache->index, MExxCTL,
+			MERAM_MExxCTL_VAL(plane->marker->index, marker->offset)
+			| MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM |
 			MExxCTL_MD_FB);
-	meram_write_icb(priv->base, icb->marker_icb, MExxCTL,
-			MERAM_MExxCTL_VAL(icb->cache_icb, marker->offset +
-					  icb->meram_size / 2) |
+	meram_write_icb(priv->base, plane->marker->index, MExxCTL,
+			MERAM_MExxCTL_VAL(plane->cache->index, marker->offset +
+					  plane->marker->size / 2) |
 			MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM |
 			MExxCTL_MD_FB);
 
@@ -368,45 +427,44 @@ static int meram_init(struct sh_mobile_meram_priv *priv,
 }
 
 static void meram_deinit(struct sh_mobile_meram_priv *priv,
-			 const struct sh_mobile_meram_icb_cfg *icb)
+			 struct sh_mobile_meram_fb_plane *plane)
 {
 	/* disable ICB */
-	meram_write_icb(priv->base, icb->cache_icb,  MExxCTL,
+	meram_write_icb(priv->base, plane->cache->index,  MExxCTL,
 			MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF);
-	meram_write_icb(priv->base, icb->marker_icb, MExxCTL,
+	meram_write_icb(priv->base, plane->marker->index, MExxCTL,
 			MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF);
 
-	priv->icbs[icb->cache_icb].cache_unit = 0;
-	priv->icbs[icb->marker_icb].cache_unit = 0;
+	plane->cache->cache_unit = 0;
+	plane->marker->cache_unit = 0;
 }
 
 /* -----------------------------------------------------------------------------
  * Registration/unregistration
  */
 
-static int 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 long base_addr_y,
-				    unsigned long base_addr_c,
-				    unsigned long *icb_addr_y,
-				    unsigned long *icb_addr_c,
-				    unsigned int *pitch)
+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 long base_addr_y,
+				      unsigned long base_addr_c,
+				      unsigned long *icb_addr_y,
+				      unsigned long *icb_addr_c,
+				      unsigned int *pitch)
 {
-	struct platform_device *pdev;
+	struct sh_mobile_meram_fb_cache *cache;
 	struct sh_mobile_meram_priv *priv;
+	struct platform_device *pdev;
 	unsigned int out_pitch;
-	unsigned int n;
-	int error = 0;
 
 	if (!pdata || !pdata->priv || !pdata->pdev || !cfg)
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 
 	if (pixelformat != SH_MOBILE_MERAM_PF_NV &&
 	    pixelformat != SH_MOBILE_MERAM_PF_NV24 &&
 	    pixelformat != SH_MOBILE_MERAM_PF_RGB)
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 
 	priv = pdata->priv;
 	pdev = pdata->pdev;
@@ -418,120 +476,82 @@ static int sh_mobile_meram_register(struct sh_mobile_meram_info *pdata,
 	/* we can't handle wider than 8192px */
 	if (xres > 8192) {
 		dev_err(&pdev->dev, "width exceeding the limit (> 8192).");
-		return -EINVAL;
-	}
-
-	/* do we have at least one ICB config? */
-	if (cfg->icb[0].marker_icb < 0 || cfg->icb[0].cache_icb < 0) {
-		dev_err(&pdev->dev, "at least one ICB is required.");
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 	}
 
 	mutex_lock(&priv->lock);
 
-	/* make sure that there's no overlaps */
-	if (meram_check_overlap(priv, &cfg->icb[0])) {
-		dev_err(&pdev->dev, "conflicting config detected.");
-		error = -EINVAL;
-		goto err;
-	}
-	n = 1;
-
-	/* do the same if we have the second ICB set */
-	if (cfg->icb[1].marker_icb >= 0 && cfg->icb[1].cache_icb >= 0) {
-		if (meram_check_overlap(priv, &cfg->icb[1])) {
-			dev_err(&pdev->dev, "conflicting config detected.");
-			error = -EINVAL;
-			goto err;
-		}
-		n = 2;
-	}
-
-	if (is_nvcolor(pixelformat) && n != 2) {
-		dev_err(&pdev->dev, "requires two ICB sets for planar Y/C.");
-		error =  -EINVAL;
-		goto err;
-	}
-
 	/* We now register the ICBs and allocate the MERAM regions. */
-	error = meram_alloc(priv, &cfg->icb[0], pixelformat);
-	if (error < 0)
+	cache = meram_alloc(priv, cfg, pixelformat);
+	if (IS_ERR(cache)) {
+		dev_err(&pdev->dev, "MERAM allocation failed (%ld).",
+			PTR_ERR(cache));
 		goto err;
-
-	if (is_nvcolor(pixelformat)) {
-		error = meram_alloc(priv, &cfg->icb[1], pixelformat);
-		if (error < 0) {
-			meram_free(priv, &cfg->icb[0]);
-			goto err;
-		}
 	}
 
 	/* initialize MERAM */
-	meram_init(priv, &cfg->icb[0], xres, yres, &out_pitch);
+	meram_init(priv, &cache->planes[0], xres, yres, &out_pitch);
 	*pitch = out_pitch;
 	if (pixelformat = SH_MOBILE_MERAM_PF_NV)
-		meram_init(priv, &cfg->icb[1], xres, (yres + 1) / 2,
+		meram_init(priv, &cache->planes[1], xres, (yres + 1) / 2,
 			&out_pitch);
 	else if (pixelformat = SH_MOBILE_MERAM_PF_NV24)
-		meram_init(priv, &cfg->icb[1], 2 * xres, (yres + 1) / 2,
+		meram_init(priv, &cache->planes[1], 2 * xres, (yres + 1) / 2,
 			&out_pitch);
 
-	meram_set_next_addr(priv, cfg, base_addr_y, base_addr_c);
-	meram_get_next_icb_addr(pdata, cfg, icb_addr_y, icb_addr_c);
+	meram_set_next_addr(priv, cache, base_addr_y, base_addr_c);
+	meram_get_next_icb_addr(pdata, cache, icb_addr_y, icb_addr_c);
 
 	dev_dbg(&pdev->dev, "registered - can access via y=%08lx, c=%08lx",
 		*icb_addr_y, *icb_addr_c);
 
 err:
 	mutex_unlock(&priv->lock);
-	return error;
+	return cache;
 }
 
-static int sh_mobile_meram_unregister(struct sh_mobile_meram_info *pdata,
-				      const struct sh_mobile_meram_cfg *cfg)
+static int
+sh_mobile_meram_unregister(struct sh_mobile_meram_info *pdata, void *data)
 {
+	struct sh_mobile_meram_fb_cache *cache = data;
 	struct sh_mobile_meram_priv *priv;
-	struct sh_mobile_meram_icb *icb;
 
-	if (!pdata || !pdata->priv || !cfg)
+	if (!pdata || !pdata->priv || !data)
 		return -EINVAL;
 
 	priv = pdata->priv;
-	icb = &priv->icbs[cfg->icb[0].marker_icb];
 
 	mutex_lock(&priv->lock);
 
-	/* deinit & unmark */
-	if (is_nvcolor(icb->pixelformat)) {
-		meram_deinit(priv, &cfg->icb[1]);
-		meram_free(priv, &cfg->icb[1]);
-	}
-	meram_deinit(priv, &cfg->icb[0]);
-	meram_free(priv, &cfg->icb[0]);
+	/* deinit & free */
+	meram_deinit(priv, &cache->planes[0]);
+	if (cache->nplanes = 2)
+		meram_deinit(priv, &cache->planes[1]);
+
+	meram_free(priv, cache);
 
 	mutex_unlock(&priv->lock);
 
 	return 0;
 }
 
-static int sh_mobile_meram_update(struct sh_mobile_meram_info *pdata,
-				  const struct sh_mobile_meram_cfg *cfg,
-				  unsigned long base_addr_y,
-				  unsigned long base_addr_c,
-				  unsigned long *icb_addr_y,
-				  unsigned long *icb_addr_c)
+static int
+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)
 {
+	struct sh_mobile_meram_fb_cache *cache = data;
 	struct sh_mobile_meram_priv *priv;
 
-	if (!pdata || !pdata->priv || !cfg)
+	if (!pdata || !pdata->priv || !data)
 		return -EINVAL;
 
 	priv = pdata->priv;
 
 	mutex_lock(&priv->lock);
 
-	meram_set_next_addr(priv, cfg, base_addr_y, base_addr_c);
-	meram_get_next_icb_addr(pdata, cfg, icb_addr_y, icb_addr_c);
+	meram_set_next_addr(priv, cache, base_addr_y, base_addr_c);
+	meram_get_next_icb_addr(pdata, cache, icb_addr_y, icb_addr_c);
 
 	mutex_unlock(&priv->lock);
 
@@ -607,6 +627,7 @@ static int __devinit sh_mobile_meram_probe(struct platform_device *pdev)
 	struct sh_mobile_meram_info *pdata = pdev->dev.platform_data;
 	struct resource *regs;
 	struct resource *meram;
+	unsigned int i;
 	int error;
 
 	if (!pdata) {
@@ -629,6 +650,10 @@ static int __devinit sh_mobile_meram_probe(struct platform_device *pdev)
 
 	/* initialize private data */
 	mutex_init(&priv->lock);
+
+	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/include/video/sh_mobile_meram.h b/include/video/sh_mobile_meram.h
index f7700fc..ea96b5a 100644
--- a/include/video/sh_mobile_meram.h
+++ b/include/video/sh_mobile_meram.h
@@ -39,23 +39,23 @@ struct module;
 struct sh_mobile_meram_ops {
 	struct module	*module;
 	/* register usage of meram */
-	int (*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 long base_addr_y,
-			      unsigned long base_addr_c,
-			      unsigned long *icb_addr_y,
-			      unsigned long *icb_addr_c,
-			      unsigned int *pitch);
+	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 long base_addr_y,
+				unsigned long base_addr_c,
+				unsigned long *icb_addr_y,
+				unsigned long *icb_addr_c,
+				unsigned int *pitch);
 
 	/* unregister usage of meram */
 	int (*meram_unregister)(struct sh_mobile_meram_info *meram_dev,
-				const struct sh_mobile_meram_cfg *cfg);
+				void *data);
 
 	/* update meram settings */
 	int (*meram_update)(struct sh_mobile_meram_info *meram_dev,
-			    const struct sh_mobile_meram_cfg *cfg,
+			    void *data,
 			    unsigned long base_addr_y,
 			    unsigned long base_addr_c,
 			    unsigned long *icb_addr_y,
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 47/57] fbdev: sh_mobile_meram: Use genalloc to manage MERAM allocation
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
  To: linux-fbdev

Instead of requiring the users to hardcode MERAM allocation in platform
data, allocate blocks at runtime using genalloc.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 arch/arm/mach-shmobile/board-ap4evb.c   |    4 -
 arch/arm/mach-shmobile/board-mackerel.c |    4 -
 drivers/video/Kconfig                   |    1 +
 drivers/video/sh_mobile_meram.c         |  110 +++++++++++++++++++------------
 include/video/sh_mobile_meram.h         |    1 -
 5 files changed, 69 insertions(+), 51 deletions(-)

diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c
index a980645..d3896dc 100644
--- a/arch/arm/mach-shmobile/board-ap4evb.c
+++ b/arch/arm/mach-shmobile/board-ap4evb.c
@@ -591,13 +591,11 @@ static struct sh_mobile_meram_cfg lcd_meram_cfg = {
 	.icb[0] = {
 		.marker_icb     = 28,
 		.cache_icb      = 24,
-		.meram_offset   = 0x0,
 		.meram_size     = 0x40,
 	},
 	.icb[1] = {
 		.marker_icb     = 29,
 		.cache_icb      = 25,
-		.meram_offset   = 0x40,
 		.meram_size     = 0x40,
 	},
 };
@@ -862,13 +860,11 @@ static struct sh_mobile_meram_cfg hdmi_meram_cfg = {
 	.icb[0] = {
 		.marker_icb     = 30,
 		.cache_icb      = 26,
-		.meram_offset   = 0x80,
 		.meram_size     = 0x100,
 	},
 	.icb[1] = {
 		.marker_icb     = 31,
 		.cache_icb      = 27,
-		.meram_offset   = 0x180,
 		.meram_size     = 0x100,
 	},
 };
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index 0021994..d555d9e 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -378,13 +378,11 @@ static struct sh_mobile_meram_cfg lcd_meram_cfg = {
 	.icb[0] = {
 		.marker_icb     = 28,
 		.cache_icb      = 24,
-		.meram_offset   = 0x0,
 		.meram_size     = 0x40,
 	},
 	.icb[1] = {
 		.marker_icb     = 29,
 		.cache_icb      = 25,
-		.meram_offset   = 0x40,
 		.meram_size     = 0x40,
 	},
 };
@@ -470,13 +468,11 @@ static struct sh_mobile_meram_cfg hdmi_meram_cfg = {
 	.icb[0] = {
 		.marker_icb     = 30,
 		.cache_icb      = 26,
-		.meram_offset   = 0x80,
 		.meram_size     = 0x100,
 	},
 	.icb[1] = {
 		.marker_icb     = 31,
 		.cache_icb      = 27,
-		.meram_offset   = 0x180,
 		.meram_size     = 0x100,
 	},
 };
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index dcf0a82..e4c5a76 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2004,6 +2004,7 @@ config FB_SH_MOBILE_HDMI
 config FB_SH_MOBILE_MERAM
 	tristate "SuperH Mobile MERAM read ahead support for LCDC"
 	depends on FB_SH_MOBILE_LCDC
+	select GENERIC_ALLOCATOR
 	default y
 	---help---
 	  Enable MERAM support for the SH-Mobile LCD controller.
diff --git a/drivers/video/sh_mobile_meram.c b/drivers/video/sh_mobile_meram.c
index 30a3305..7cd706d 100644
--- a/drivers/video/sh_mobile_meram.c
+++ b/drivers/video/sh_mobile_meram.c
@@ -10,6 +10,7 @@
  */
 
 #include <linux/device.h>
+#include <linux/genalloc.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -105,15 +106,17 @@ static const unsigned long icb_regs[] = {
 /*
  * sh_mobile_meram_icb - MERAM ICB information
  * @regs: Registers cache
- * @region: Start and end addresses of the MERAM region
+ * @offset: MERAM block offset
+ * @size: MERAM block size in bytes
  * @cache_unit: Bytes to cache per ICB
  * @pixelformat: Video pixel format of the data stored in the ICB
  * @current_reg: Which of Start Address Register A (0) or B (1) is in use
  */
 struct sh_mobile_meram_icb {
 	unsigned long regs[ICB_REGS_SIZE];
+	unsigned long offset;
+	unsigned int size;
 
-	unsigned long region;
 	unsigned int cache_unit;
 	unsigned int pixelformat;
 	unsigned int current_reg;
@@ -124,21 +127,27 @@ struct sh_mobile_meram_icb {
 /*
  * sh_mobile_meram_priv - MERAM device
  * @base: Registers base address
+ * @meram: MERAM physical address
  * @regs: Registers cache
  * @lock: Protects used_icb and icbs
  * @used_icb: Bitmask of used ICBs
  * @icbs: ICBs
+ * @pool: Allocation pool to manage the MERAM
  */
 struct sh_mobile_meram_priv {
 	void __iomem *base;
+	unsigned long meram;
 	unsigned long regs[MERAM_REGS_SIZE];
 
 	struct mutex lock;
 	unsigned long used_icb;
 	struct sh_mobile_meram_icb icbs[MERAM_ICB_NUM];
+
+	struct gen_pool *pool;
 };
 
 /* settings */
+#define MERAM_GRANULARITY		1024
 #define MERAM_SEC_LINE			15
 #define MERAM_LINE_WIDTH		2048
 
@@ -175,18 +184,10 @@ static inline unsigned long meram_read_reg(void __iomem *base, unsigned int off)
  * Allocation
  */
 
-#define MERAM_CACHE_START(p)	 ((p) >> 16)
-#define MERAM_CACHE_END(p)	 ((p) & 0xffff)
-#define MERAM_CACHE_SET(o, s)	 ((((o) & 0xffff) << 16) | \
-				  (((o) + (s) - 1) & 0xffff))
-
 /* Check if there's no overlaps in MERAM allocation. */
 static int meram_check_overlap(struct sh_mobile_meram_priv *priv,
 			       const struct sh_mobile_meram_icb_cfg *new)
 {
-	unsigned int used_start, used_end, meram_start, meram_end;
-	unsigned int i;
-
 	/* valid ICB? */
 	if (new->marker_icb & ~0x1f || new->cache_icb & ~0x1f)
 		return 1;
@@ -195,43 +196,40 @@ static int meram_check_overlap(struct sh_mobile_meram_priv *priv,
 	    test_bit(new->cache_icb,  &priv->used_icb))
 		return  1;
 
-	for (i = 0; i < MERAM_ICB_NUM; i++) {
-		if (!test_bit(i, &priv->used_icb))
-			continue;
-
-		used_start = MERAM_CACHE_START(priv->icbs[i].region);
-		used_end   = MERAM_CACHE_END(priv->icbs[i].region);
-		meram_start = new->meram_offset;
-		meram_end   = new->meram_offset + new->meram_size;
-
-		if ((meram_start >= used_start && meram_start < used_end) ||
-		    (meram_end > used_start && meram_end < used_end))
-			return 1;
-	}
-
 	return 0;
 }
 
-/* Mark the specified ICB as used. */
-static void meram_mark(struct sh_mobile_meram_priv *priv,
+/* Allocate memory for the ICBs and mark them as used. */
+static int meram_alloc(struct sh_mobile_meram_priv *priv,
 		       const struct sh_mobile_meram_icb_cfg *new,
 		       int pixelformat)
 {
+	struct sh_mobile_meram_icb *marker = &priv->icbs[new->marker_icb];
+	unsigned long mem;
+
+	mem = gen_pool_alloc(priv->pool, new->meram_size * 1024);
+	if (mem = 0)
+		return -ENOMEM;
+
 	__set_bit(new->marker_icb, &priv->used_icb);
 	__set_bit(new->cache_icb, &priv->used_icb);
 
-	priv->icbs[new->marker_icb].region = MERAM_CACHE_SET(new->meram_offset,
-							     new->meram_size);
-	priv->icbs[new->cache_icb].region = MERAM_CACHE_SET(new->meram_offset,
-							    new->meram_size);
-	priv->icbs[new->marker_icb].current_reg = 1;
-	priv->icbs[new->marker_icb].pixelformat = pixelformat;
+	marker->offset = mem - priv->meram;
+	marker->size = new->meram_size * 1024;
+	marker->current_reg = 1;
+	marker->pixelformat = pixelformat;
+
+	return 0;
 }
 
 /* Unmark the specified ICB as used. */
-static void meram_unmark(struct sh_mobile_meram_priv *priv,
-			 const struct sh_mobile_meram_icb_cfg *icb)
+static void meram_free(struct sh_mobile_meram_priv *priv,
+		       const struct sh_mobile_meram_icb_cfg *icb)
 {
+	struct sh_mobile_meram_icb *marker = &priv->icbs[icb->marker_icb];
+
+	gen_pool_free(priv->pool, priv->meram + marker->offset, marker->size);
+
 	__clear_bit(icb->marker_icb, &priv->used_icb);
 	__clear_bit(icb->cache_icb, &priv->used_icb);
 }
@@ -302,6 +300,7 @@ static int meram_init(struct sh_mobile_meram_priv *priv,
 		      unsigned int xres, unsigned int yres,
 		      unsigned int *out_pitch)
 {
+	struct sh_mobile_meram_icb *marker = &priv->icbs[icb->marker_icb];
 	unsigned long total_byte_count = MERAM_CALC_BYTECOUNT(xres, yres);
 	unsigned long bnm;
 	unsigned int lcdc_pitch;
@@ -356,11 +355,11 @@ static int meram_init(struct sh_mobile_meram_priv *priv,
 	 * we also split the allocated MERAM buffer between two ICBs.
 	 */
 	meram_write_icb(priv->base, icb->cache_icb, MExxCTL,
-			MERAM_MExxCTL_VAL(icb->marker_icb, icb->meram_offset) |
+			MERAM_MExxCTL_VAL(icb->marker_icb, marker->offset) |
 			MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM |
 			MExxCTL_MD_FB);
 	meram_write_icb(priv->base, icb->marker_icb, MExxCTL,
-			MERAM_MExxCTL_VAL(icb->cache_icb, icb->meram_offset +
+			MERAM_MExxCTL_VAL(icb->cache_icb, marker->offset +
 					  icb->meram_size / 2) |
 			MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM |
 			MExxCTL_MD_FB);
@@ -454,10 +453,18 @@ static int sh_mobile_meram_register(struct sh_mobile_meram_info *pdata,
 		goto err;
 	}
 
-	/* we now register the ICB */
-	meram_mark(priv, &cfg->icb[0], pixelformat);
-	if (is_nvcolor(pixelformat))
-		meram_mark(priv, &cfg->icb[1], pixelformat);
+	/* We now register the ICBs and allocate the MERAM regions. */
+	error = meram_alloc(priv, &cfg->icb[0], pixelformat);
+	if (error < 0)
+		goto err;
+
+	if (is_nvcolor(pixelformat)) {
+		error = meram_alloc(priv, &cfg->icb[1], pixelformat);
+		if (error < 0) {
+			meram_free(priv, &cfg->icb[0]);
+			goto err;
+		}
+	}
 
 	/* initialize MERAM */
 	meram_init(priv, &cfg->icb[0], xres, yres, &out_pitch);
@@ -497,10 +504,10 @@ static int sh_mobile_meram_unregister(struct sh_mobile_meram_info *pdata,
 	/* deinit & unmark */
 	if (is_nvcolor(icb->pixelformat)) {
 		meram_deinit(priv, &cfg->icb[1]);
-		meram_unmark(priv, &cfg->icb[1]);
+		meram_free(priv, &cfg->icb[1]);
 	}
 	meram_deinit(priv, &cfg->icb[0]);
-	meram_unmark(priv, &cfg->icb[0]);
+	meram_free(priv, &cfg->icb[0]);
 
 	mutex_unlock(&priv->lock);
 
@@ -626,6 +633,7 @@ static int __devinit sh_mobile_meram_probe(struct platform_device *pdev)
 	pdata->priv = priv;
 	pdata->pdev = pdev;
 
+	/* Request memory regions and remap the registers. */
 	if (!request_mem_region(regs->start, resource_size(regs), pdev->name)) {
 		dev_err(&pdev->dev, "MERAM registers region already claimed\n");
 		error = -EBUSY;
@@ -646,6 +654,18 @@ static int __devinit sh_mobile_meram_probe(struct platform_device *pdev)
 		goto err_ioremap;
 	}
 
+	/* Create and initialize the MERAM memory pool. */
+	priv->pool = gen_pool_create(ilog2(MERAM_GRANULARITY), -1);
+	if (priv->pool = NULL) {
+		error = -ENOMEM;
+		goto err_genpool;
+	}
+
+	error = gen_pool_add(priv->pool, meram->start, resource_size(meram),
+			     -1);
+	if (error < 0)
+		goto err_genpool;
+
 	/* initialize ICB addressing mode */
 	if (pdata->addr_mode = SH_MOBILE_MERAM_MODE1)
 		meram_write_reg(priv->base, MEVCR1, MEVCR1_AMD1);
@@ -657,6 +677,10 @@ static int __devinit sh_mobile_meram_probe(struct platform_device *pdev)
 
 	return 0;
 
+err_genpool:
+	if (priv->pool)
+		gen_pool_destroy(priv->pool);
+	iounmap(priv->base);
 err_ioremap:
 	release_mem_region(meram->start, resource_size(meram));
 err_req_meram:
@@ -677,6 +701,8 @@ static int sh_mobile_meram_remove(struct platform_device *pdev)
 
 	pm_runtime_disable(&pdev->dev);
 
+	gen_pool_destroy(priv->pool);
+
 	iounmap(priv->base);
 	release_mem_region(meram->start, resource_size(meram));
 	release_mem_region(regs->start, resource_size(regs));
diff --git a/include/video/sh_mobile_meram.h b/include/video/sh_mobile_meram.h
index 05ca3f9..f7700fc 100644
--- a/include/video/sh_mobile_meram.h
+++ b/include/video/sh_mobile_meram.h
@@ -28,7 +28,6 @@ struct sh_mobile_meram_info {
 struct sh_mobile_meram_icb_cfg {
 	unsigned int marker_icb;	/* ICB # for Marker ICB */
 	unsigned int cache_icb;		/* ICB # for Cache ICB */
-	unsigned int meram_offset;	/* MERAM Buffer Offset to use */
 	unsigned int meram_size;	/* MERAM Buffer Size to use */
 };
 
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 46/57] fbdev: sh_mobile_meram: Divide the code into sections
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
  To: linux-fbdev

And rename a couple of constants to make prefixes more uniform.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mobile_meram.c |   98 +++++++++++++++++---------------------
 1 files changed, 44 insertions(+), 54 deletions(-)

diff --git a/drivers/video/sh_mobile_meram.c b/drivers/video/sh_mobile_meram.c
index 0c5b301..30a3305 100644
--- a/drivers/video/sh_mobile_meram.c
+++ b/drivers/video/sh_mobile_meram.c
@@ -9,16 +9,20 @@
  * for more details.
  */
 
+#include <linux/device.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/device.h>
+#include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
-#include <linux/io.h>
 #include <linux/slab.h>
-#include <linux/platform_device.h>
+
 #include <video/sh_mobile_meram.h>
 
-/* meram registers */
+/* -----------------------------------------------------------------------------
+ * MERAM registers
+ */
+
 #define MEVCR1			0x4
 #define MEVCR1_RST		(1 << 31)
 #define MEVCR1_WD		(1 << 30)
@@ -81,14 +85,12 @@
 	 ((yszm1) << MExxBSIZE_YSZM1_SHIFT) | \
 	 ((xszm1) << MExxBSIZE_XSZM1_SHIFT))
 
-#define SH_MOBILE_MERAM_ICB_NUM		32
-
 static const unsigned long common_regs[] = {
 	MEVCR1,
 	MEQSEL1,
 	MEQSEL2,
 };
-#define CMN_REGS_SIZE ARRAY_SIZE(common_regs)
+#define MERAM_REGS_SIZE ARRAY_SIZE(common_regs)
 
 static const unsigned long icb_regs[] = {
 	MExxCTL,
@@ -117,6 +119,8 @@ struct sh_mobile_meram_icb {
 	unsigned int current_reg;
 };
 
+#define MERAM_ICB_NUM			32
+
 /*
  * sh_mobile_meram_priv - MERAM device
  * @base: Registers base address
@@ -127,19 +131,19 @@ struct sh_mobile_meram_icb {
  */
 struct sh_mobile_meram_priv {
 	void __iomem *base;
-	unsigned long regs[CMN_REGS_SIZE];
+	unsigned long regs[MERAM_REGS_SIZE];
 
 	struct mutex lock;
 	unsigned long used_icb;
-	struct sh_mobile_meram_icb icbs[SH_MOBILE_MERAM_ICB_NUM];
+	struct sh_mobile_meram_icb icbs[MERAM_ICB_NUM];
 };
 
 /* settings */
-#define MERAM_SEC_LINE 15
-#define MERAM_LINE_WIDTH 2048
+#define MERAM_SEC_LINE			15
+#define MERAM_LINE_WIDTH		2048
 
-/*
- * MERAM/ICB access functions
+/* -----------------------------------------------------------------------------
+ * Registers access
  */
 
 #define MERAM_ICB_OFFSET(base, idx, off)	((base) + (off) + (idx) * 0x20)
@@ -167,8 +171,8 @@ static inline unsigned long meram_read_reg(void __iomem *base, unsigned int off)
 	return ioread32(base + off);
 }
 
-/*
- * register ICB
+/* -----------------------------------------------------------------------------
+ * Allocation
  */
 
 #define MERAM_CACHE_START(p)	 ((p) >> 16)
@@ -176,10 +180,7 @@ static inline unsigned long meram_read_reg(void __iomem *base, unsigned int off)
 #define MERAM_CACHE_SET(o, s)	 ((((o) & 0xffff) << 16) | \
 				  (((o) + (s) - 1) & 0xffff))
 
-/*
- * check if there's no overlaps in MERAM allocation.
- */
-
+/* Check if there's no overlaps in MERAM allocation. */
 static int meram_check_overlap(struct sh_mobile_meram_priv *priv,
 			       const struct sh_mobile_meram_icb_cfg *new)
 {
@@ -194,7 +195,7 @@ static int meram_check_overlap(struct sh_mobile_meram_priv *priv,
 	    test_bit(new->cache_icb,  &priv->used_icb))
 		return  1;
 
-	for (i = 0; i < SH_MOBILE_MERAM_ICB_NUM; i++) {
+	for (i = 0; i < MERAM_ICB_NUM; i++) {
 		if (!test_bit(i, &priv->used_icb))
 			continue;
 
@@ -211,10 +212,7 @@ static int meram_check_overlap(struct sh_mobile_meram_priv *priv,
 	return 0;
 }
 
-/*
- * mark the specified ICB as used
- */
-
+/* Mark the specified ICB as used. */
 static void meram_mark(struct sh_mobile_meram_priv *priv,
 		       const struct sh_mobile_meram_icb_cfg *new,
 		       int pixelformat)
@@ -230,10 +228,7 @@ static void meram_mark(struct sh_mobile_meram_priv *priv,
 	priv->icbs[new->marker_icb].pixelformat = pixelformat;
 }
 
-/*
- * unmark the specified ICB as used
- */
-
+/* Unmark the specified ICB as used. */
 static void meram_unmark(struct sh_mobile_meram_priv *priv,
 			 const struct sh_mobile_meram_icb_cfg *icb)
 {
@@ -241,9 +236,7 @@ static void meram_unmark(struct sh_mobile_meram_priv *priv,
 	__clear_bit(icb->cache_icb, &priv->used_icb);
 }
 
-/*
- * is this a YCbCr(NV12, NV16 or NV24) colorspace
- */
+/* Is this a YCbCr(NV12, NV16 or NV24) colorspace? */
 static int is_nvcolor(int cspace)
 {
 	if (cspace = SH_MOBILE_MERAM_PF_NV ||
@@ -252,9 +245,7 @@ static int is_nvcolor(int cspace)
 	return 0;
 }
 
-/*
- * set the next address to fetch
- */
+/* Set the next address to fetch. */
 static void meram_set_next_addr(struct sh_mobile_meram_priv *priv,
 				const struct sh_mobile_meram_cfg *cfg,
 				unsigned long base_addr_y,
@@ -282,9 +273,7 @@ static void meram_set_next_addr(struct sh_mobile_meram_priv *priv,
 	}
 }
 
-/*
- * get the next ICB address
- */
+/* Get the next ICB address. */
 static void
 meram_get_next_icb_addr(struct sh_mobile_meram_info *pdata,
 			const struct sh_mobile_meram_cfg *cfg,
@@ -307,10 +296,7 @@ meram_get_next_icb_addr(struct sh_mobile_meram_info *pdata,
 #define MERAM_CALC_BYTECOUNT(x, y) \
 	(((x) * (y) + (MERAM_LINE_WIDTH - 1)) & ~(MERAM_LINE_WIDTH - 1))
 
-/*
- * initialize MERAM
- */
-
+/* Initialize MERAM. */
 static int meram_init(struct sh_mobile_meram_priv *priv,
 		      const struct sh_mobile_meram_icb_cfg *icb,
 		      unsigned int xres, unsigned int yres,
@@ -395,8 +381,8 @@ static void meram_deinit(struct sh_mobile_meram_priv *priv,
 	priv->icbs[icb->marker_icb].cache_unit = 0;
 }
 
-/*
- * register the ICB
+/* -----------------------------------------------------------------------------
+ * Registration/unregistration
  */
 
 static int sh_mobile_meram_register(struct sh_mobile_meram_info *pdata,
@@ -545,13 +531,24 @@ static int sh_mobile_meram_update(struct sh_mobile_meram_info *pdata,
 	return 0;
 }
 
+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,
+};
+
+/* -----------------------------------------------------------------------------
+ * Power management
+ */
+
 static int sh_mobile_meram_runtime_suspend(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
 	unsigned int i, j;
 
-	for (i = 0; i < CMN_REGS_SIZE; i++)
+	for (i = 0; i < MERAM_REGS_SIZE; i++)
 		priv->regs[i] = meram_read_reg(priv->base, common_regs[i]);
 
 	for (i = 0; i < 32; i++) {
@@ -583,7 +580,7 @@ static int sh_mobile_meram_runtime_resume(struct device *dev)
 					priv->icbs[i].regs[j]);
 	}
 
-	for (i = 0; i < CMN_REGS_SIZE; i++)
+	for (i = 0; i < MERAM_REGS_SIZE; i++)
 		meram_write_reg(priv->base, common_regs[i], priv->regs[i]);
 	return 0;
 }
@@ -593,15 +590,8 @@ static const struct dev_pm_ops sh_mobile_meram_dev_pm_ops = {
 	.runtime_resume = sh_mobile_meram_runtime_resume,
 };
 
-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,
-};
-
-/*
- * initialize MERAM
+/* -----------------------------------------------------------------------------
+ * Probe/remove and driver init/exit
  */
 
 static int __devinit sh_mobile_meram_probe(struct platform_device *pdev)
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 45/57] fbdev: sh_mobile_meram: Don't inline everything
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
  To: linux-fbdev

Let the compiler decide which complex functions to inline, and constify
constant static arrays.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mobile_meram.c |   30 +++++++++++++++---------------
 1 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/drivers/video/sh_mobile_meram.c b/drivers/video/sh_mobile_meram.c
index cddb180..0c5b301 100644
--- a/drivers/video/sh_mobile_meram.c
+++ b/drivers/video/sh_mobile_meram.c
@@ -83,14 +83,14 @@
 
 #define SH_MOBILE_MERAM_ICB_NUM		32
 
-static unsigned long common_regs[] = {
+static const unsigned long common_regs[] = {
 	MEVCR1,
 	MEQSEL1,
 	MEQSEL2,
 };
 #define CMN_REGS_SIZE ARRAY_SIZE(common_regs)
 
-static unsigned long icb_regs[] = {
+static const unsigned long icb_regs[] = {
 	MExxCTL,
 	MExxBSIZE,
 	MExxMNCF,
@@ -180,8 +180,8 @@ static inline unsigned long meram_read_reg(void __iomem *base, unsigned int off)
  * check if there's no overlaps in MERAM allocation.
  */
 
-static inline int meram_check_overlap(struct sh_mobile_meram_priv *priv,
-				      const struct sh_mobile_meram_icb_cfg *new)
+static int meram_check_overlap(struct sh_mobile_meram_priv *priv,
+			       const struct sh_mobile_meram_icb_cfg *new)
 {
 	unsigned int used_start, used_end, meram_start, meram_end;
 	unsigned int i;
@@ -215,9 +215,9 @@ static inline int meram_check_overlap(struct sh_mobile_meram_priv *priv,
  * mark the specified ICB as used
  */
 
-static inline void meram_mark(struct sh_mobile_meram_priv *priv,
-			      const struct sh_mobile_meram_icb_cfg *new,
-			      int pixelformat)
+static void meram_mark(struct sh_mobile_meram_priv *priv,
+		       const struct sh_mobile_meram_icb_cfg *new,
+		       int pixelformat)
 {
 	__set_bit(new->marker_icb, &priv->used_icb);
 	__set_bit(new->cache_icb, &priv->used_icb);
@@ -234,8 +234,8 @@ static inline void meram_mark(struct sh_mobile_meram_priv *priv,
  * unmark the specified ICB as used
  */
 
-static inline void meram_unmark(struct sh_mobile_meram_priv *priv,
-				const struct sh_mobile_meram_icb_cfg *icb)
+static void meram_unmark(struct sh_mobile_meram_priv *priv,
+			 const struct sh_mobile_meram_icb_cfg *icb)
 {
 	__clear_bit(icb->marker_icb, &priv->used_icb);
 	__clear_bit(icb->cache_icb, &priv->used_icb);
@@ -244,7 +244,7 @@ static inline void meram_unmark(struct sh_mobile_meram_priv *priv,
 /*
  * is this a YCbCr(NV12, NV16 or NV24) colorspace
  */
-static inline int is_nvcolor(int cspace)
+static int is_nvcolor(int cspace)
 {
 	if (cspace = SH_MOBILE_MERAM_PF_NV ||
 	    cspace = SH_MOBILE_MERAM_PF_NV24)
@@ -255,10 +255,10 @@ static inline int is_nvcolor(int cspace)
 /*
  * set the next address to fetch
  */
-static inline void meram_set_next_addr(struct sh_mobile_meram_priv *priv,
-				       const struct sh_mobile_meram_cfg *cfg,
-				       unsigned long base_addr_y,
-				       unsigned long base_addr_c)
+static void meram_set_next_addr(struct sh_mobile_meram_priv *priv,
+				const struct sh_mobile_meram_cfg *cfg,
+				unsigned long base_addr_y,
+				unsigned long base_addr_c)
 {
 	struct sh_mobile_meram_icb *icb = &priv->icbs[cfg->icb[0].marker_icb];
 	unsigned long target;
@@ -285,7 +285,7 @@ static inline void meram_set_next_addr(struct sh_mobile_meram_priv *priv,
 /*
  * get the next ICB address
  */
-static inline void
+static void
 meram_get_next_icb_addr(struct sh_mobile_meram_info *pdata,
 			const struct sh_mobile_meram_cfg *cfg,
 			unsigned long *icb_addr_y, unsigned long *icb_addr_c)
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 44/57] fbdev: sh_mobile_meram: Add struct sh_mobile_meram_icb
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
  To: linux-fbdev

The new structure stores ICB parameters for ICBs.

Instead of modifying the struct sh_mobile_meram_cfg instances passed by
callers, store the ICB parameters internally and make the public API
take const pointers to sh_mobile_meram_cfg.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mobile_meram.c |  178 ++++++++++++++++++++-------------------
 include/video/sh_mobile_meram.h |   12 +--
 2 files changed, 94 insertions(+), 96 deletions(-)

diff --git a/drivers/video/sh_mobile_meram.c b/drivers/video/sh_mobile_meram.c
index 7af2ffe..cddb180 100644
--- a/drivers/video/sh_mobile_meram.c
+++ b/drivers/video/sh_mobile_meram.c
@@ -100,14 +100,38 @@ static unsigned long icb_regs[] = {
 };
 #define ICB_REGS_SIZE ARRAY_SIZE(icb_regs)
 
+/*
+ * sh_mobile_meram_icb - MERAM ICB information
+ * @regs: Registers cache
+ * @region: Start and end addresses of the MERAM region
+ * @cache_unit: Bytes to cache per ICB
+ * @pixelformat: Video pixel format of the data stored in the ICB
+ * @current_reg: Which of Start Address Register A (0) or B (1) is in use
+ */
+struct sh_mobile_meram_icb {
+	unsigned long regs[ICB_REGS_SIZE];
+
+	unsigned long region;
+	unsigned int cache_unit;
+	unsigned int pixelformat;
+	unsigned int current_reg;
+};
+
+/*
+ * sh_mobile_meram_priv - MERAM device
+ * @base: Registers base address
+ * @regs: Registers cache
+ * @lock: Protects used_icb and icbs
+ * @used_icb: Bitmask of used ICBs
+ * @icbs: ICBs
+ */
 struct sh_mobile_meram_priv {
-	void __iomem	*base;
-	struct mutex	lock;
-	unsigned long	used_icb;
-	unsigned int	used_meram_cache_regions;
-	unsigned long	used_meram_cache[SH_MOBILE_MERAM_ICB_NUM];
-	unsigned long	cmn_saved_regs[CMN_REGS_SIZE];
-	unsigned long	icb_saved_regs[ICB_REGS_SIZE * SH_MOBILE_MERAM_ICB_NUM];
+	void __iomem *base;
+	unsigned long regs[CMN_REGS_SIZE];
+
+	struct mutex lock;
+	unsigned long used_icb;
+	struct sh_mobile_meram_icb icbs[SH_MOBILE_MERAM_ICB_NUM];
 };
 
 /* settings */
@@ -157,7 +181,7 @@ static inline unsigned long meram_read_reg(void __iomem *base, unsigned int off)
  */
 
 static inline int meram_check_overlap(struct sh_mobile_meram_priv *priv,
-				      struct sh_mobile_meram_icb_cfg *new)
+				      const struct sh_mobile_meram_icb_cfg *new)
 {
 	unsigned int used_start, used_end, meram_start, meram_end;
 	unsigned int i;
@@ -167,17 +191,20 @@ static inline int meram_check_overlap(struct sh_mobile_meram_priv *priv,
 		return 1;
 
 	if (test_bit(new->marker_icb, &priv->used_icb) ||
-			test_bit(new->cache_icb,  &priv->used_icb))
+	    test_bit(new->cache_icb,  &priv->used_icb))
 		return  1;
 
-	for (i = 0; i < priv->used_meram_cache_regions; i++) {
-		used_start = MERAM_CACHE_START(priv->used_meram_cache[i]);
-		used_end   = MERAM_CACHE_END(priv->used_meram_cache[i]);
+	for (i = 0; i < SH_MOBILE_MERAM_ICB_NUM; i++) {
+		if (!test_bit(i, &priv->used_icb))
+			continue;
+
+		used_start = MERAM_CACHE_START(priv->icbs[i].region);
+		used_end   = MERAM_CACHE_END(priv->icbs[i].region);
 		meram_start = new->meram_offset;
 		meram_end   = new->meram_offset + new->meram_size;
 
 		if ((meram_start >= used_start && meram_start < used_end) ||
-			(meram_end > used_start && meram_end < used_end))
+		    (meram_end > used_start && meram_end < used_end))
 			return 1;
 	}
 
@@ -189,22 +216,18 @@ static inline int meram_check_overlap(struct sh_mobile_meram_priv *priv,
  */
 
 static inline void meram_mark(struct sh_mobile_meram_priv *priv,
-			      struct sh_mobile_meram_icb_cfg *new)
+			      const struct sh_mobile_meram_icb_cfg *new,
+			      int pixelformat)
 {
-	unsigned int n;
-
-	if (new->marker_icb < 0 || new->cache_icb < 0)
-		return;
-
 	__set_bit(new->marker_icb, &priv->used_icb);
 	__set_bit(new->cache_icb, &priv->used_icb);
 
-	n = priv->used_meram_cache_regions;
-
-	priv->used_meram_cache[n] = MERAM_CACHE_SET(new->meram_offset,
-						    new->meram_size);
-
-	priv->used_meram_cache_regions++;
+	priv->icbs[new->marker_icb].region = MERAM_CACHE_SET(new->meram_offset,
+							     new->meram_size);
+	priv->icbs[new->cache_icb].region = MERAM_CACHE_SET(new->meram_offset,
+							    new->meram_size);
+	priv->icbs[new->marker_icb].current_reg = 1;
+	priv->icbs[new->marker_icb].pixelformat = pixelformat;
 }
 
 /*
@@ -212,30 +235,10 @@ static inline void meram_mark(struct sh_mobile_meram_priv *priv,
  */
 
 static inline void meram_unmark(struct sh_mobile_meram_priv *priv,
-				struct sh_mobile_meram_icb_cfg *icb)
+				const struct sh_mobile_meram_icb_cfg *icb)
 {
-	unsigned long pattern;
-	unsigned int i;
-
-	if (icb->marker_icb < 0 || icb->cache_icb < 0)
-		return;
-
 	__clear_bit(icb->marker_icb, &priv->used_icb);
 	__clear_bit(icb->cache_icb, &priv->used_icb);
-
-	pattern = MERAM_CACHE_SET(icb->meram_offset, icb->meram_size);
-	for (i = 0; i < priv->used_meram_cache_regions; i++) {
-		if (priv->used_meram_cache[i] = pattern) {
-			while (i < priv->used_meram_cache_regions - 1) {
-				priv->used_meram_cache[i] -					priv->used_meram_cache[i + 1] ;
-				i++;
-			}
-			priv->used_meram_cache[i] = 0;
-			priv->used_meram_cache_regions--;
-			break;
-		}
-	}
 }
 
 /*
@@ -244,7 +247,7 @@ static inline void meram_unmark(struct sh_mobile_meram_priv *priv,
 static inline int is_nvcolor(int cspace)
 {
 	if (cspace = SH_MOBILE_MERAM_PF_NV ||
-			cspace = SH_MOBILE_MERAM_PF_NV24)
+	    cspace = SH_MOBILE_MERAM_PF_NV24)
 		return 1;
 	return 0;
 }
@@ -253,46 +256,51 @@ static inline int is_nvcolor(int cspace)
  * set the next address to fetch
  */
 static inline void meram_set_next_addr(struct sh_mobile_meram_priv *priv,
-				       struct sh_mobile_meram_cfg *cfg,
+				       const struct sh_mobile_meram_cfg *cfg,
 				       unsigned long base_addr_y,
 				       unsigned long base_addr_c)
 {
+	struct sh_mobile_meram_icb *icb = &priv->icbs[cfg->icb[0].marker_icb];
 	unsigned long target;
 
-	cfg->current_reg ^= 1;
-	target = cfg->current_reg ? MExxSARB : MExxSARA;
+	icb->current_reg ^= 1;
+	target = icb->current_reg ? MExxSARB : MExxSARA;
 
 	/* set the next address to fetch */
-	meram_write_icb(priv->base, cfg->icb[0].cache_icb,  target,
+	meram_write_icb(priv->base, cfg->icb[0].cache_icb, target,
 			base_addr_y);
 	meram_write_icb(priv->base, cfg->icb[0].marker_icb, target,
-			base_addr_y + cfg->icb[0].cache_unit);
+			base_addr_y +
+			priv->icbs[cfg->icb[0].marker_icb].cache_unit);
 
-	if (is_nvcolor(cfg->pixelformat)) {
+	if (is_nvcolor(icb->pixelformat)) {
 		meram_write_icb(priv->base, cfg->icb[1].cache_icb,  target,
 				base_addr_c);
 		meram_write_icb(priv->base, cfg->icb[1].marker_icb, target,
-				base_addr_c + cfg->icb[1].cache_unit);
+				base_addr_c +
+				priv->icbs[cfg->icb[1].marker_icb].cache_unit);
 	}
 }
 
 /*
  * get the next ICB address
  */
-static inline void meram_get_next_icb_addr(struct sh_mobile_meram_info *pdata,
-					   struct sh_mobile_meram_cfg *cfg,
-					   unsigned long *icb_addr_y,
-					   unsigned long *icb_addr_c)
+static inline void
+meram_get_next_icb_addr(struct sh_mobile_meram_info *pdata,
+			const struct sh_mobile_meram_cfg *cfg,
+			unsigned long *icb_addr_y, unsigned long *icb_addr_c)
 {
+	struct sh_mobile_meram_priv *priv = pdata->priv;
+	struct sh_mobile_meram_icb *icb = &priv->icbs[cfg->icb[0].marker_icb];
 	unsigned long icb_offset;
 
 	if (pdata->addr_mode = SH_MOBILE_MERAM_MODE0)
-		icb_offset = 0x80000000 | (cfg->current_reg << 29);
+		icb_offset = 0x80000000 | (icb->current_reg << 29);
 	else
-		icb_offset = 0xc0000000 | (cfg->current_reg << 23);
+		icb_offset = 0xc0000000 | (icb->current_reg << 23);
 
 	*icb_addr_y = icb_offset | (cfg->icb[0].marker_icb << 24);
-	if (is_nvcolor(cfg->pixelformat))
+	if (is_nvcolor(icb->pixelformat))
 		*icb_addr_c = icb_offset | (cfg->icb[1].marker_icb << 24);
 }
 
@@ -304,7 +312,7 @@ static inline void meram_get_next_icb_addr(struct sh_mobile_meram_info *pdata,
  */
 
 static int meram_init(struct sh_mobile_meram_priv *priv,
-		      struct sh_mobile_meram_icb_cfg *icb,
+		      const struct sh_mobile_meram_icb_cfg *icb,
 		      unsigned int xres, unsigned int yres,
 		      unsigned int *out_pitch)
 {
@@ -352,7 +360,8 @@ static int meram_init(struct sh_mobile_meram_priv *priv,
 	meram_write_icb(priv->base, icb->marker_icb, MExxSBSIZE, xpitch);
 
 	/* save a cache unit size */
-	icb->cache_unit = xres * save_lines;
+	priv->icbs[icb->cache_icb].cache_unit = xres * save_lines;
+	priv->icbs[icb->marker_icb].cache_unit = xres * save_lines;
 
 	/*
 	 * Set MERAM for framebuffer
@@ -374,14 +383,16 @@ static int meram_init(struct sh_mobile_meram_priv *priv,
 }
 
 static void meram_deinit(struct sh_mobile_meram_priv *priv,
-			 struct sh_mobile_meram_icb_cfg *icb)
+			 const struct sh_mobile_meram_icb_cfg *icb)
 {
 	/* disable ICB */
 	meram_write_icb(priv->base, icb->cache_icb,  MExxCTL,
 			MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF);
 	meram_write_icb(priv->base, icb->marker_icb, MExxCTL,
 			MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF);
-	icb->cache_unit = 0;
+
+	priv->icbs[icb->cache_icb].cache_unit = 0;
+	priv->icbs[icb->marker_icb].cache_unit = 0;
 }
 
 /*
@@ -389,7 +400,7 @@ static void meram_deinit(struct sh_mobile_meram_priv *priv,
  */
 
 static int sh_mobile_meram_register(struct sh_mobile_meram_info *pdata,
-				    struct sh_mobile_meram_cfg *cfg,
+				    const struct sh_mobile_meram_cfg *cfg,
 				    unsigned int xres, unsigned int yres,
 				    unsigned int pixelformat,
 				    unsigned long base_addr_y,
@@ -433,12 +444,6 @@ static int sh_mobile_meram_register(struct sh_mobile_meram_info *pdata,
 
 	mutex_lock(&priv->lock);
 
-	if (priv->used_meram_cache_regions + 2 > SH_MOBILE_MERAM_ICB_NUM) {
-		dev_err(&pdev->dev, "no more ICB available.");
-		error = -EINVAL;
-		goto err;
-	}
-
 	/* make sure that there's no overlaps */
 	if (meram_check_overlap(priv, &cfg->icb[0])) {
 		dev_err(&pdev->dev, "conflicting config detected.");
@@ -464,10 +469,9 @@ static int sh_mobile_meram_register(struct sh_mobile_meram_info *pdata,
 	}
 
 	/* we now register the ICB */
-	cfg->pixelformat = pixelformat;
-	meram_mark(priv, &cfg->icb[0]);
+	meram_mark(priv, &cfg->icb[0], pixelformat);
 	if (is_nvcolor(pixelformat))
-		meram_mark(priv, &cfg->icb[1]);
+		meram_mark(priv, &cfg->icb[1], pixelformat);
 
 	/* initialize MERAM */
 	meram_init(priv, &cfg->icb[0], xres, yres, &out_pitch);
@@ -479,7 +483,6 @@ static int sh_mobile_meram_register(struct sh_mobile_meram_info *pdata,
 		meram_init(priv, &cfg->icb[1], 2 * xres, (yres + 1) / 2,
 			&out_pitch);
 
-	cfg->current_reg = 1;
 	meram_set_next_addr(priv, cfg, base_addr_y, base_addr_c);
 	meram_get_next_icb_addr(pdata, cfg, icb_addr_y, icb_addr_c);
 
@@ -492,19 +495,21 @@ err:
 }
 
 static int sh_mobile_meram_unregister(struct sh_mobile_meram_info *pdata,
-				      struct sh_mobile_meram_cfg *cfg)
+				      const struct sh_mobile_meram_cfg *cfg)
 {
 	struct sh_mobile_meram_priv *priv;
+	struct sh_mobile_meram_icb *icb;
 
 	if (!pdata || !pdata->priv || !cfg)
 		return -EINVAL;
 
 	priv = pdata->priv;
+	icb = &priv->icbs[cfg->icb[0].marker_icb];
 
 	mutex_lock(&priv->lock);
 
 	/* deinit & unmark */
-	if (is_nvcolor(cfg->pixelformat)) {
+	if (is_nvcolor(icb->pixelformat)) {
 		meram_deinit(priv, &cfg->icb[1]);
 		meram_unmark(priv, &cfg->icb[1]);
 	}
@@ -517,7 +522,7 @@ static int sh_mobile_meram_unregister(struct sh_mobile_meram_info *pdata,
 }
 
 static int sh_mobile_meram_update(struct sh_mobile_meram_info *pdata,
-				  struct sh_mobile_meram_cfg *cfg,
+				  const struct sh_mobile_meram_cfg *cfg,
 				  unsigned long base_addr_y,
 				  unsigned long base_addr_c,
 				  unsigned long *icb_addr_y,
@@ -547,18 +552,17 @@ static int sh_mobile_meram_runtime_suspend(struct device *dev)
 	unsigned int i, j;
 
 	for (i = 0; i < CMN_REGS_SIZE; i++)
-		priv->cmn_saved_regs[i] = meram_read_reg(priv->base,
-			common_regs[i]);
+		priv->regs[i] = meram_read_reg(priv->base, common_regs[i]);
 
 	for (i = 0; i < 32; i++) {
 		if (!test_bit(i, &priv->used_icb))
 			continue;
 		for (j = 0; j < ICB_REGS_SIZE; j++) {
-			priv->icb_saved_regs[i * ICB_REGS_SIZE + j] +			priv->icbs[i].regs[j]  				meram_read_icb(priv->base, i, icb_regs[j]);
 			/* Reset ICB on resume */
 			if (icb_regs[j] = MExxCTL)
-				priv->icb_saved_regs[i * ICB_REGS_SIZE + j] |+				priv->icbs[i].regs[j] | 					MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF;
 		}
 	}
@@ -574,15 +578,13 @@ static int sh_mobile_meram_runtime_resume(struct device *dev)
 	for (i = 0; i < 32; i++) {
 		if (!test_bit(i, &priv->used_icb))
 			continue;
-		for (j = 0; j < ICB_REGS_SIZE; j++) {
+		for (j = 0; j < ICB_REGS_SIZE; j++)
 			meram_write_icb(priv->base, i, icb_regs[j],
-			priv->icb_saved_regs[i * ICB_REGS_SIZE + j]);
-		}
+					priv->icbs[i].regs[j]);
 	}
 
 	for (i = 0; i < CMN_REGS_SIZE; i++)
-		meram_write_reg(priv->base, common_regs[i],
-				priv->cmn_saved_regs[i]);
+		meram_write_reg(priv->base, common_regs[i], priv->regs[i]);
 	return 0;
 }
 
diff --git a/include/video/sh_mobile_meram.h b/include/video/sh_mobile_meram.h
index 6755e3f..05ca3f9 100644
--- a/include/video/sh_mobile_meram.h
+++ b/include/video/sh_mobile_meram.h
@@ -30,14 +30,10 @@ struct sh_mobile_meram_icb_cfg {
 	unsigned int cache_icb;		/* ICB # for Cache ICB */
 	unsigned int meram_offset;	/* MERAM Buffer Offset to use */
 	unsigned int meram_size;	/* MERAM Buffer Size to use */
-
-	unsigned int cache_unit;	/* bytes to cache per ICB */
 };
 
 struct sh_mobile_meram_cfg {
-	struct sh_mobile_meram_icb_cfg	icb[2];
-	int				pixelformat;
-	int				current_reg;
+	struct sh_mobile_meram_icb_cfg icb[2];
 };
 
 struct module;
@@ -45,7 +41,7 @@ struct sh_mobile_meram_ops {
 	struct module	*module;
 	/* register usage of meram */
 	int (*meram_register)(struct sh_mobile_meram_info *meram_dev,
-			      struct sh_mobile_meram_cfg *cfg,
+			      const struct sh_mobile_meram_cfg *cfg,
 			      unsigned int xres, unsigned int yres,
 			      unsigned int pixelformat,
 			      unsigned long base_addr_y,
@@ -56,11 +52,11 @@ struct sh_mobile_meram_ops {
 
 	/* unregister usage of meram */
 	int (*meram_unregister)(struct sh_mobile_meram_info *meram_dev,
-				struct sh_mobile_meram_cfg *cfg);
+				const struct sh_mobile_meram_cfg *cfg);
 
 	/* update meram settings */
 	int (*meram_update)(struct sh_mobile_meram_info *meram_dev,
-			    struct sh_mobile_meram_cfg *cfg,
+			    const struct sh_mobile_meram_cfg *cfg,
 			    unsigned long base_addr_y,
 			    unsigned long base_addr_c,
 			    unsigned long *icb_addr_y,
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 43/57] fbdev: sh_mobile_meram: Make current_reg field store the current reg set
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
  To: linux-fbdev

Make sure current_reg = 0/1 always mean register set A/B through all
the code.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mobile_meram.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/video/sh_mobile_meram.c b/drivers/video/sh_mobile_meram.c
index 548f700..7af2ffe 100644
--- a/drivers/video/sh_mobile_meram.c
+++ b/drivers/video/sh_mobile_meram.c
@@ -259,8 +259,8 @@ static inline void meram_set_next_addr(struct sh_mobile_meram_priv *priv,
 {
 	unsigned long target;
 
-	target = (cfg->current_reg) ? MExxSARA : MExxSARB;
 	cfg->current_reg ^= 1;
+	target = cfg->current_reg ? MExxSARB : MExxSARA;
 
 	/* set the next address to fetch */
 	meram_write_icb(priv->base, cfg->icb[0].cache_icb,  target,
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 42/57] fbdev: sh_mobile_meram: Make variables unsigned where applicable
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
  To: linux-fbdev

Many variables, such as loop counters, sizes and offsets, should be
unsigned integers. Make them so.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mobile_meram.c |   80 +++++++++++++++++++++------------------
 include/video/sh_mobile_meram.h |    6 ++-
 2 files changed, 47 insertions(+), 39 deletions(-)

diff --git a/drivers/video/sh_mobile_meram.c b/drivers/video/sh_mobile_meram.c
index 2ad5a45..548f700 100644
--- a/drivers/video/sh_mobile_meram.c
+++ b/drivers/video/sh_mobile_meram.c
@@ -104,7 +104,7 @@ struct sh_mobile_meram_priv {
 	void __iomem	*base;
 	struct mutex	lock;
 	unsigned long	used_icb;
-	int		used_meram_cache_regions;
+	unsigned int	used_meram_cache_regions;
 	unsigned long	used_meram_cache[SH_MOBILE_MERAM_ICB_NUM];
 	unsigned long	cmn_saved_regs[CMN_REGS_SIZE];
 	unsigned long	icb_saved_regs[ICB_REGS_SIZE * SH_MOBILE_MERAM_ICB_NUM];
@@ -120,24 +120,25 @@ struct sh_mobile_meram_priv {
 
 #define MERAM_ICB_OFFSET(base, idx, off)	((base) + (off) + (idx) * 0x20)
 
-static inline void meram_write_icb(void __iomem *base, int idx, int off,
-	unsigned long val)
+static inline void meram_write_icb(void __iomem *base, unsigned int idx,
+				   unsigned int off, unsigned long val)
 {
 	iowrite32(val, MERAM_ICB_OFFSET(base, idx, off));
 }
 
-static inline unsigned long meram_read_icb(void __iomem *base, int idx, int off)
+static inline unsigned long meram_read_icb(void __iomem *base, unsigned int idx,
+					   unsigned int off)
 {
 	return ioread32(MERAM_ICB_OFFSET(base, idx, off));
 }
 
-static inline void meram_write_reg(void __iomem *base, int off,
-		unsigned long val)
+static inline void meram_write_reg(void __iomem *base, unsigned int off,
+				   unsigned long val)
 {
 	iowrite32(val, base + off);
 }
 
-static inline unsigned long meram_read_reg(void __iomem *base, int off)
+static inline unsigned long meram_read_reg(void __iomem *base, unsigned int off)
 {
 	return ioread32(base + off);
 }
@@ -158,8 +159,8 @@ static inline unsigned long meram_read_reg(void __iomem *base, int off)
 static inline int meram_check_overlap(struct sh_mobile_meram_priv *priv,
 				      struct sh_mobile_meram_icb_cfg *new)
 {
-	int i;
-	int used_start, used_end, meram_start, meram_end;
+	unsigned int used_start, used_end, meram_start, meram_end;
+	unsigned int i;
 
 	/* valid ICB? */
 	if (new->marker_icb & ~0x1f || new->cache_icb & ~0x1f)
@@ -190,7 +191,7 @@ static inline int meram_check_overlap(struct sh_mobile_meram_priv *priv,
 static inline void meram_mark(struct sh_mobile_meram_priv *priv,
 			      struct sh_mobile_meram_icb_cfg *new)
 {
-	int n;
+	unsigned int n;
 
 	if (new->marker_icb < 0 || new->cache_icb < 0)
 		return;
@@ -213,8 +214,8 @@ static inline void meram_mark(struct sh_mobile_meram_priv *priv,
 static inline void meram_unmark(struct sh_mobile_meram_priv *priv,
 				struct sh_mobile_meram_icb_cfg *icb)
 {
-	int i;
 	unsigned long pattern;
+	unsigned int i;
 
 	if (icb->marker_icb < 0 || icb->cache_icb < 0)
 		return;
@@ -304,12 +305,15 @@ static inline void meram_get_next_icb_addr(struct sh_mobile_meram_info *pdata,
 
 static int meram_init(struct sh_mobile_meram_priv *priv,
 		      struct sh_mobile_meram_icb_cfg *icb,
-		      int xres, int yres, int *out_pitch)
+		      unsigned int xres, unsigned int yres,
+		      unsigned int *out_pitch)
 {
 	unsigned long total_byte_count = MERAM_CALC_BYTECOUNT(xres, yres);
 	unsigned long bnm;
-	int lcdc_pitch, xpitch, line_cnt;
-	int save_lines;
+	unsigned int lcdc_pitch;
+	unsigned int xpitch;
+	unsigned int line_cnt;
+	unsigned int save_lines;
 
 	/* adjust pitch to 1024, 2048, 4096 or 8192 */
 	lcdc_pitch = (xres - 1) | 1023;
@@ -386,16 +390,18 @@ static void meram_deinit(struct sh_mobile_meram_priv *priv,
 
 static int sh_mobile_meram_register(struct sh_mobile_meram_info *pdata,
 				    struct sh_mobile_meram_cfg *cfg,
-				    int xres, int yres, int pixelformat,
+				    unsigned int xres, unsigned int yres,
+				    unsigned int pixelformat,
 				    unsigned long base_addr_y,
 				    unsigned long base_addr_c,
 				    unsigned long *icb_addr_y,
 				    unsigned long *icb_addr_c,
-				    int *pitch)
+				    unsigned int *pitch)
 {
 	struct platform_device *pdev;
 	struct sh_mobile_meram_priv *priv;
-	int n, out_pitch;
+	unsigned int out_pitch;
+	unsigned int n;
 	int error = 0;
 
 	if (!pdata || !pdata->priv || !pdata->pdev || !cfg)
@@ -538,21 +544,21 @@ static int sh_mobile_meram_runtime_suspend(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
-	int k, j;
+	unsigned int i, j;
 
-	for (k = 0; k < CMN_REGS_SIZE; k++)
-		priv->cmn_saved_regs[k] = meram_read_reg(priv->base,
-			common_regs[k]);
+	for (i = 0; i < CMN_REGS_SIZE; i++)
+		priv->cmn_saved_regs[i] = meram_read_reg(priv->base,
+			common_regs[i]);
 
-	for (j = 0; j < 32; j++) {
-		if (!test_bit(j, &priv->used_icb))
+	for (i = 0; i < 32; i++) {
+		if (!test_bit(i, &priv->used_icb))
 			continue;
-		for (k = 0; k < ICB_REGS_SIZE; k++) {
-			priv->icb_saved_regs[j * ICB_REGS_SIZE + k] -				meram_read_icb(priv->base, j, icb_regs[k]);
+		for (j = 0; j < ICB_REGS_SIZE; j++) {
+			priv->icb_saved_regs[i * ICB_REGS_SIZE + j] +				meram_read_icb(priv->base, i, icb_regs[j]);
 			/* Reset ICB on resume */
-			if (icb_regs[k] = MExxCTL)
-				priv->icb_saved_regs[j * ICB_REGS_SIZE + k] |+			if (icb_regs[j] = MExxCTL)
+				priv->icb_saved_regs[i * ICB_REGS_SIZE + j] | 					MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF;
 		}
 	}
@@ -563,20 +569,20 @@ static int sh_mobile_meram_runtime_resume(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
-	int k, j;
+	unsigned int i, j;
 
-	for (j = 0; j < 32; j++) {
-		if (!test_bit(j, &priv->used_icb))
+	for (i = 0; i < 32; i++) {
+		if (!test_bit(i, &priv->used_icb))
 			continue;
-		for (k = 0; k < ICB_REGS_SIZE; k++) {
-			meram_write_icb(priv->base, j, icb_regs[k],
-			priv->icb_saved_regs[j * ICB_REGS_SIZE + k]);
+		for (j = 0; j < ICB_REGS_SIZE; j++) {
+			meram_write_icb(priv->base, i, icb_regs[j],
+			priv->icb_saved_regs[i * ICB_REGS_SIZE + j]);
 		}
 	}
 
-	for (k = 0; k < CMN_REGS_SIZE; k++)
-		meram_write_reg(priv->base, common_regs[k],
-			priv->cmn_saved_regs[k]);
+	for (i = 0; i < CMN_REGS_SIZE; i++)
+		meram_write_reg(priv->base, common_regs[i],
+				priv->cmn_saved_regs[i]);
 	return 0;
 }
 
diff --git a/include/video/sh_mobile_meram.h b/include/video/sh_mobile_meram.h
index caae558..6755e3f 100644
--- a/include/video/sh_mobile_meram.h
+++ b/include/video/sh_mobile_meram.h
@@ -46,11 +46,13 @@ struct sh_mobile_meram_ops {
 	/* register usage of meram */
 	int (*meram_register)(struct sh_mobile_meram_info *meram_dev,
 			      struct sh_mobile_meram_cfg *cfg,
-			      int xres, int yres, int pixelformat,
+			      unsigned int xres, unsigned int yres,
+			      unsigned int pixelformat,
 			      unsigned long base_addr_y,
 			      unsigned long base_addr_c,
 			      unsigned long *icb_addr_y,
-			      unsigned long *icb_addr_c, int *pitch);
+			      unsigned long *icb_addr_c,
+			      unsigned int *pitch);
 
 	/* unregister usage of meram */
 	int (*meram_unregister)(struct sh_mobile_meram_info *meram_dev,
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 41/57] fbdev: sh_mobile_meram: Add _cfg suffix to struct sh_mobile_meram_icb
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
  To: linux-fbdev

The structure describe ICB configuration, no ICB objects themselves.
Rename it to sh_mobile_meram_icb_cfg in preparation for the addition of
an ICB structure.

All the structure fields are unsigned integers, make them so.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mobile_meram.c |   10 +++++-----
 include/video/sh_mobile_meram.h |   14 +++++++-------
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/video/sh_mobile_meram.c b/drivers/video/sh_mobile_meram.c
index dbf5c43..2ad5a45 100644
--- a/drivers/video/sh_mobile_meram.c
+++ b/drivers/video/sh_mobile_meram.c
@@ -156,7 +156,7 @@ static inline unsigned long meram_read_reg(void __iomem *base, int off)
  */
 
 static inline int meram_check_overlap(struct sh_mobile_meram_priv *priv,
-				      struct sh_mobile_meram_icb *new)
+				      struct sh_mobile_meram_icb_cfg *new)
 {
 	int i;
 	int used_start, used_end, meram_start, meram_end;
@@ -188,7 +188,7 @@ static inline int meram_check_overlap(struct sh_mobile_meram_priv *priv,
  */
 
 static inline void meram_mark(struct sh_mobile_meram_priv *priv,
-			      struct sh_mobile_meram_icb *new)
+			      struct sh_mobile_meram_icb_cfg *new)
 {
 	int n;
 
@@ -211,7 +211,7 @@ static inline void meram_mark(struct sh_mobile_meram_priv *priv,
  */
 
 static inline void meram_unmark(struct sh_mobile_meram_priv *priv,
-				struct sh_mobile_meram_icb *icb)
+				struct sh_mobile_meram_icb_cfg *icb)
 {
 	int i;
 	unsigned long pattern;
@@ -303,7 +303,7 @@ static inline void meram_get_next_icb_addr(struct sh_mobile_meram_info *pdata,
  */
 
 static int meram_init(struct sh_mobile_meram_priv *priv,
-		      struct sh_mobile_meram_icb *icb,
+		      struct sh_mobile_meram_icb_cfg *icb,
 		      int xres, int yres, int *out_pitch)
 {
 	unsigned long total_byte_count = MERAM_CALC_BYTECOUNT(xres, yres);
@@ -370,7 +370,7 @@ static int meram_init(struct sh_mobile_meram_priv *priv,
 }
 
 static void meram_deinit(struct sh_mobile_meram_priv *priv,
-			struct sh_mobile_meram_icb *icb)
+			 struct sh_mobile_meram_icb_cfg *icb)
 {
 	/* disable ICB */
 	meram_write_icb(priv->base, icb->cache_icb,  MExxCTL,
diff --git a/include/video/sh_mobile_meram.h b/include/video/sh_mobile_meram.h
index af602d6..caae558 100644
--- a/include/video/sh_mobile_meram.h
+++ b/include/video/sh_mobile_meram.h
@@ -25,17 +25,17 @@ struct sh_mobile_meram_info {
 };
 
 /* icb config */
-struct sh_mobile_meram_icb {
-	int marker_icb;		/* ICB # for Marker ICB */
-	int cache_icb;		/* ICB # for Cache ICB */
-	int meram_offset;	/* MERAM Buffer Offset to use */
-	int meram_size;		/* MERAM Buffer Size to use */
+struct sh_mobile_meram_icb_cfg {
+	unsigned int marker_icb;	/* ICB # for Marker ICB */
+	unsigned int cache_icb;		/* ICB # for Cache ICB */
+	unsigned int meram_offset;	/* MERAM Buffer Offset to use */
+	unsigned int meram_size;	/* MERAM Buffer Size to use */
 
-	int cache_unit;		/* bytes to cache per ICB */
+	unsigned int cache_unit;	/* bytes to cache per ICB */
 };
 
 struct sh_mobile_meram_cfg {
-	struct sh_mobile_meram_icb	icb[2];
+	struct sh_mobile_meram_icb_cfg	icb[2];
 	int				pixelformat;
 	int				current_reg;
 };
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 40/57] fbdev: sh_mobile_meram: Request memory regions for memory resources
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
  To: linux-fbdev

Make sure the registers and MERAM spaces are reserved before using them.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mobile_meram.c |   53 +++++++++++++++++++++++++++-----------
 1 files changed, 37 insertions(+), 16 deletions(-)

diff --git a/drivers/video/sh_mobile_meram.c b/drivers/video/sh_mobile_meram.c
index f45d83e..dbf5c43 100644
--- a/drivers/video/sh_mobile_meram.c
+++ b/drivers/video/sh_mobile_meram.c
@@ -596,13 +596,12 @@ static struct sh_mobile_meram_ops sh_mobile_meram_ops = {
  * initialize MERAM
  */
 
-static int sh_mobile_meram_remove(struct platform_device *pdev);
-
 static int __devinit sh_mobile_meram_probe(struct platform_device *pdev)
 {
 	struct sh_mobile_meram_priv *priv;
 	struct sh_mobile_meram_info *pdata = pdev->dev.platform_data;
-	struct resource *res;
+	struct resource *regs;
+	struct resource *meram;
 	int error;
 
 	if (!pdata) {
@@ -610,8 +609,9 @@ static int __devinit sh_mobile_meram_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
+	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	meram = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (regs = NULL || meram = NULL) {
 		dev_err(&pdev->dev, "cannot get platform resources\n");
 		return -ENOENT;
 	}
@@ -622,32 +622,50 @@ static int __devinit sh_mobile_meram_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	}
 
-	platform_set_drvdata(pdev, priv);
-
 	/* initialize private data */
 	mutex_init(&priv->lock);
-	priv->base = ioremap_nocache(res->start, resource_size(res));
+	pdata->ops = &sh_mobile_meram_ops;
+	pdata->priv = priv;
+	pdata->pdev = pdev;
+
+	if (!request_mem_region(regs->start, resource_size(regs), pdev->name)) {
+		dev_err(&pdev->dev, "MERAM registers region already claimed\n");
+		error = -EBUSY;
+		goto err_req_regs;
+	}
+
+	if (!request_mem_region(meram->start, resource_size(meram),
+				pdev->name)) {
+		dev_err(&pdev->dev, "MERAM memory region already claimed\n");
+		error = -EBUSY;
+		goto err_req_meram;
+	}
+
+	priv->base = ioremap_nocache(regs->start, resource_size(regs));
 	if (!priv->base) {
 		dev_err(&pdev->dev, "ioremap failed\n");
 		error = -EFAULT;
-		goto err;
+		goto err_ioremap;
 	}
-	pdata->ops = &sh_mobile_meram_ops;
-	pdata->priv = priv;
-	pdata->pdev = pdev;
 
 	/* initialize ICB addressing mode */
 	if (pdata->addr_mode = SH_MOBILE_MERAM_MODE1)
 		meram_write_reg(priv->base, MEVCR1, MEVCR1_AMD1);
 
+	platform_set_drvdata(pdev, priv);
 	pm_runtime_enable(&pdev->dev);
 
 	dev_info(&pdev->dev, "sh_mobile_meram initialized.");
 
 	return 0;
 
-err:
-	sh_mobile_meram_remove(pdev);
+err_ioremap:
+	release_mem_region(meram->start, resource_size(meram));
+err_req_meram:
+	release_mem_region(regs->start, resource_size(regs));
+err_req_regs:
+	mutex_destroy(&priv->lock);
+	kfree(priv);
 
 	return error;
 }
@@ -656,11 +674,14 @@ err:
 static int sh_mobile_meram_remove(struct platform_device *pdev)
 {
 	struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
+	struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	struct resource *meram = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 
 	pm_runtime_disable(&pdev->dev);
 
-	if (priv->base)
-		iounmap(priv->base);
+	iounmap(priv->base);
+	release_mem_region(meram->start, resource_size(meram));
+	release_mem_region(regs->start, resource_size(regs));
 
 	mutex_destroy(&priv->lock);
 
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 39/57] arm: mach-shmobile: Split MERAM resources into regs and meram
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
  To: linux-fbdev

The MERAM resource currently combines both the registers space and the
MERAM space. Only the register space needs to be ioremapped, split the
resource to make that possible.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 arch/arm/mach-shmobile/board-ap4evb.c   |   14 ++++++++++----
 arch/arm/mach-shmobile/board-mackerel.c |    8 +++++++-
 2 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c
index 5e876c7..a980645 100644
--- a/arch/arm/mach-shmobile/board-ap4evb.c
+++ b/arch/arm/mach-shmobile/board-ap4evb.c
@@ -258,10 +258,16 @@ static struct sh_mobile_meram_info meram_info = {
 
 static struct resource meram_resources[] = {
 	[0] = {
-		.name   = "MERAM",
-		.start  = 0xe8000000,
-		.end    = 0xe81fffff,
-		.flags  = IORESOURCE_MEM,
+		.name	= "regs",
+		.start	= 0xe8000000,
+		.end	= 0xe807ffff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.name	= "meram",
+		.start	= 0xe8080000,
+		.end	= 0xe81fffff,
+		.flags	= IORESOURCE_MEM,
 	},
 };
 
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index b0f19fd..0021994 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -323,8 +323,14 @@ static struct sh_mobile_meram_info mackerel_meram_info = {
 
 static struct resource meram_resources[] = {
 	[0] = {
-		.name	= "MERAM",
+		.name	= "regs",
 		.start	= 0xe8000000,
+		.end	= 0xe807ffff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.name	= "meram",
+		.start	= 0xe8080000,
 		.end	= 0xe81fffff,
 		.flags	= IORESOURCE_MEM,
 	},
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 38/57] fbdev: sh_mobile_lcdc: Pass channel pointer to sh_mobile_wait_for_vsync
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
  To: linux-fbdev

The sh_mobile_wait_for_vsync() function isn't related to the fbdev API,
make it generic by passing a channel pointer instead of an fb_info
pointer.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mobile_lcdcfb.c |   47 ++++++++++++++++++-------------------
 1 files changed, 23 insertions(+), 24 deletions(-)

diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 8e85b3c..453fc92 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -583,6 +583,26 @@ 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)
+{
+	unsigned long ldintr;
+	int ret;
+
+	/* Enable VSync End interrupt and be careful not to acknowledge any
+	 * pending interrupt.
+	 */
+	ldintr = lcdc_read(ch->lcdc, _LDINTR);
+	ldintr |= LDINTR_VEE | LDINTR_STATUS_MASK;
+	lcdc_write(ch->lcdc, _LDINTR, ldintr);
+
+	ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion,
+							msecs_to_jiffies(100));
+	if (!ret)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
 static void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv,
 				      int start)
 {
@@ -1081,27 +1101,6 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
 	return 0;
 }
 
-static int sh_mobile_wait_for_vsync(struct fb_info *info)
-{
-	struct sh_mobile_lcdc_chan *ch = info->par;
-	unsigned long ldintr;
-	int ret;
-
-	/* Enable VSync End interrupt and be careful not to acknowledge any
-	 * pending interrupt.
-	 */
-	ldintr = lcdc_read(ch->lcdc, _LDINTR);
-	ldintr |= LDINTR_VEE | LDINTR_STATUS_MASK;
-	lcdc_write(ch->lcdc, _LDINTR, ldintr);
-
-	ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion,
-							msecs_to_jiffies(100));
-	if (!ret)
-		return -ETIMEDOUT;
-
-	return 0;
-}
-
 static int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd,
 		       unsigned long arg)
 {
@@ -1109,7 +1108,7 @@ static int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd,
 
 	switch (cmd) {
 	case FBIO_WAITFORVSYNC:
-		retval = sh_mobile_wait_for_vsync(info);
+		retval = sh_mobile_wait_for_vsync(info->par);
 		break;
 
 	default:
@@ -1385,8 +1384,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(info);
-			sh_mobile_wait_for_vsync(info);
+			sh_mobile_wait_for_vsync(ch);
+			sh_mobile_wait_for_vsync(ch);
 		}
 		sh_mobile_lcdc_clk_off(p);
 	}
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 37/57] fbdev: sh_mobile_lcdc: Store configuration in channel structure
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
  To: linux-fbdev

Store the frame buffer configuration (colorspace, visible/virtual
horizontal and vertical resolutions and line pitch) in the
sh_mobile_lcdc_chan structure, and use it instead of accessing fb_info.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mobile_lcdcfb.c |  109 +++++++++++++++++++-------------------
 drivers/video/sh_mobile_lcdcfb.h |    8 +++-
 2 files changed, 61 insertions(+), 56 deletions(-)

diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index d00774b..8e85b3c 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -273,7 +273,7 @@ static int sh_mobile_lcdc_sginit(struct fb_info *info,
 				  struct list_head *pagelist)
 {
 	struct sh_mobile_lcdc_chan *ch = info->par;
-	unsigned int nr_pages_max = info->fix.smem_len >> PAGE_SHIFT;
+	unsigned int nr_pages_max = ch->fb_size >> PAGE_SHIFT;
 	struct page *page;
 	int nr_pages = 0;
 
@@ -539,17 +539,6 @@ static int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var)
 	return var->grayscale > 1;
 }
 
-static bool sh_mobile_format_is_yuv(const struct fb_var_screeninfo *var)
-{
-	const struct sh_mobile_lcdc_format_info *format;
-
-	if (var->grayscale <= 1)
-		return false;
-
-	format = sh_mobile_format_info(var->grayscale);
-	return format ? format->yuv : false;
-}
-
 /* -----------------------------------------------------------------------------
  * Start, stop and IRQ
  */
@@ -648,7 +637,7 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
 	h_total = mode->xres + mode->hsync_len + mode->left_margin
 		+ mode->right_margin;
 	tmp = h_total / 8; /* HTCN */
-	tmp |= (min(mode->xres, var->xres) / 8) << 16; /* HDCN */
+	tmp |= (min(mode->xres, ch->xres) / 8) << 16; /* HDCN */
 	lcdc_write_chan(ch, LDHCNR, tmp);
 
 	hsync_pos = mode->xres + mode->right_margin;
@@ -659,7 +648,7 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
 	/* vertical configuration */
 	tmp = mode->yres + mode->vsync_len + mode->upper_margin
 	    + mode->lower_margin; /* VTLN */
-	tmp |= min(mode->yres, var->yres) << 16; /* VDLN */
+	tmp |= min(mode->yres, ch->yres) << 16; /* VDLN */
 	lcdc_write_chan(ch, LDVLNR, tmp);
 
 	tmp = mode->yres + mode->lower_margin; /* VSYNP */
@@ -736,7 +725,7 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 		tmp = ch->format->lddfr;
 
 		if (ch->format->yuv) {
-			switch (ch->info->var.colorspace) {
+			switch (ch->colorspace) {
 			case V4L2_COLORSPACE_REC709:
 				tmp |= LDDFR_CF1;
 				break;
@@ -834,11 +823,8 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 		if (!ch->enabled)
 			continue;
 
-		ch->base_addr_y = ch->info->fix.smem_start;
-		ch->base_addr_c = ch->base_addr_y
-				+ ch->info->var.xres
-				* ch->info->var.yres_virtual;
-		ch->pitch = ch->info->fix.line_length;
+		ch->base_addr_y = ch->dma_handle;
+		ch->base_addr_c = ch->base_addr_y + ch->xres * ch->yres_virtual;
 
 		/* Enable MERAM if possible. */
 		cfg = ch->cfg.meram_cfg;
@@ -873,7 +859,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 		}
 
 		ret = mdev->ops->meram_register(mdev, cfg, ch->pitch,
-					ch->info->var.yres, pixelformat,
+					ch->yres, pixelformat,
 					ch->base_addr_y, ch->base_addr_c,
 					&ch->base_addr_y, &ch->base_addr_c,
 					&ch->pitch);
@@ -1035,14 +1021,12 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
 	unsigned long new_pan_offset;
 	unsigned long base_addr_y, base_addr_c;
 	unsigned long c_offset;
-	bool yuv = sh_mobile_format_is_yuv(&info->var);
 
-	if (!yuv)
-		new_pan_offset = var->yoffset * info->fix.line_length
-			       + var->xoffset * (info->var.bits_per_pixel / 8);
+	if (!ch->format->yuv)
+		new_pan_offset = var->yoffset * ch->pitch
+			       + var->xoffset * (ch->format->bpp / 8);
 	else
-		new_pan_offset = var->yoffset * info->fix.line_length
-			       + var->xoffset;
+		new_pan_offset = var->yoffset * ch->pitch + var->xoffset;
 
 	if (new_pan_offset = ch->pan_offset)
 		return 0;	/* No change, do nothing */
@@ -1051,12 +1035,11 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
 
 	/* Set the source address for the next refresh */
 	base_addr_y = ch->dma_handle + new_pan_offset;
-	if (yuv) {
+	if (ch->format->yuv) {
 		/* Set y offset */
-		c_offset = var->yoffset * info->fix.line_length
-			 * (info->var.bits_per_pixel - 8) / 8;
-		base_addr_c = ch->dma_handle
-			    + info->var.xres * info->var.yres_virtual
+		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)
@@ -1083,7 +1066,7 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
 	ch->base_addr_c = base_addr_c;
 
 	lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);
-	if (yuv)
+	if (ch->format->yuv)
 		lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c);
 
 	if (lcdc_chan_is_sublcd(ch))
@@ -1335,24 +1318,28 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in
 static int sh_mobile_set_par(struct fb_info *info)
 {
 	struct sh_mobile_lcdc_chan *ch = info->par;
-	u32 line_length = info->fix.line_length;
 	int ret;
 
 	sh_mobile_lcdc_stop(ch->lcdc);
 
-	if (sh_mobile_format_is_yuv(&info->var))
-		info->fix.line_length = info->var.xres;
-	else
-		info->fix.line_length = info->var.xres
-				      * info->var.bits_per_pixel / 8;
-
 	ch->format = sh_mobile_format_info(sh_mobile_format_fourcc(&info->var));
+	ch->colorspace = info->var.colorspace;
+
+	ch->xres = info->var.xres;
+	ch->xres_virtual = info->var.xres_virtual;
+	ch->yres = info->var.yres;
+	ch->yres_virtual = info->var.yres_virtual;
+
+	if (ch->format->yuv)
+		ch->pitch = info->var.xres;
+	else
+		ch->pitch = info->var.xres * ch->format->bpp / 8;
 
 	ret = sh_mobile_lcdc_start(ch->lcdc);
-	if (ret < 0) {
+	if (ret < 0)
 		dev_err(info->dev, "%s: unable to restart LCDC\n", __func__);
-		info->fix.line_length = line_length;
-	}
+
+	info->fix.line_length = ch->pitch;
 
 	if (sh_mobile_format_is_fourcc(&info->var)) {
 		info->fix.type = FB_TYPE_FOURCC;
@@ -1381,8 +1368,8 @@ static int sh_mobile_lcdc_blank(int blank, struct fb_info *info)
 	/* blank the screen? */
 	if (blank > FB_BLANK_UNBLANK && ch->blank_status = FB_BLANK_UNBLANK) {
 		struct fb_fillrect rect = {
-			.width = info->var.xres,
-			.height = info->var.yres,
+			.width = ch->xres,
+			.height = ch->yres,
 		};
 		sh_mobile_lcdc_fillrect(info, &rect);
 	}
@@ -1522,6 +1509,13 @@ sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch,
 	info->fix = sh_mobile_lcdc_fix;
 	info->fix.smem_start = ch->dma_handle;
 	info->fix.smem_len = ch->fb_size;
+	info->fix.line_length = ch->pitch;
+
+	if (ch->format->yuv)
+		info->fix.visual = FB_VISUAL_FOURCC;
+	else
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+
 	if (ch->format->fourcc = V4L2_PIX_FMT_NV12 ||
 	    ch->format->fourcc = V4L2_PIX_FMT_NV21)
 		info->fix.ypanstep = 2;
@@ -1549,14 +1543,6 @@ sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch,
 	if (ret)
 		return ret;
 
-	if (ch->format->yuv) {
-		info->fix.line_length = var->xres;
-		info->fix.visual = FB_VISUAL_FOURCC;
-	} else {
-		info->fix.line_length = var->xres * ch->format->bpp / 8;
-		info->fix.visual = FB_VISUAL_TRUECOLOR;
-	}
-
 	return 0;
 }
 
@@ -1834,8 +1820,6 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
 		return -EINVAL;
 	}
 
-	ch->format = format;
-
 	/* Iterate through the modes to validate them and find the highest
 	 * resolution.
 	 */
@@ -1873,6 +1857,21 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
 		num_modes = cfg->num_modes;
 	}
 
+	/* Use the first mode as default. */
+	ch->format = format;
+	ch->xres = mode->xres;
+	ch->xres_virtual = mode->xres;
+	ch->yres = mode->yres;
+	ch->yres_virtual = mode->yres * 2;
+
+	if (!format->yuv) {
+		ch->colorspace = V4L2_COLORSPACE_SRGB;
+		ch->pitch = ch->xres * format->bpp / 8;
+	} else {
+		ch->colorspace = V4L2_COLORSPACE_REC709;
+		ch->pitch = ch->xres;
+	}
+
 	ch->display.width = cfg->panel_cfg.width;
 	ch->display.height = cfg->panel_cfg.height;
 	ch->display.mode = *mode;
diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h
index cc22b9e..19a4cd7 100644
--- a/drivers/video/sh_mobile_lcdcfb.h
+++ b/drivers/video/sh_mobile_lcdcfb.h
@@ -74,9 +74,15 @@ struct sh_mobile_lcdc_chan {
 	struct completion vsync_completion;
 
 	const struct sh_mobile_lcdc_format_info *format;
+	u32 colorspace;
+	unsigned int xres;
+	unsigned int xres_virtual;
+	unsigned int yres;
+	unsigned int yres_virtual;
+	unsigned int pitch;
+
 	unsigned long base_addr_y;
 	unsigned long base_addr_c;
-	unsigned int pitch;
 
 	int (*notify)(struct sh_mobile_lcdc_chan *ch,
 		      enum sh_mobile_lcdc_entity_event event,
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 36/57] fbdev: sh_mobile_lcdc: Pass physical device pointer to DMA functions
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
  To: linux-fbdev

The dma_map_sg() and dma_unmap_sg() functions need a pointer to the
physical device.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mobile_lcdcfb.c |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index f6bc18e..d00774b 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -313,11 +313,12 @@ static void sh_mobile_lcdc_deferred_io(struct fb_info *info,
 		unsigned int nr_pages = sh_mobile_lcdc_sginit(info, pagelist);
 
 		/* trigger panel update */
-		dma_map_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
+		dma_map_sg(ch->lcdc->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
 		if (panel->start_transfer)
 			panel->start_transfer(ch, &sh_mobile_lcdc_sys_bus_ops);
 		lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG);
-		dma_unmap_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
+		dma_unmap_sg(ch->lcdc->dev, ch->sglist, nr_pages,
+			     DMA_TO_DEVICE);
 	} else {
 		if (panel->start_transfer)
 			panel->start_transfer(ch, &sh_mobile_lcdc_sys_bus_ops);
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 35/57] fbdev: sh_mobile_lcdc: Split fb init/cleanup from channel init/cleanup
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
  To: linux-fbdev

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mobile_lcdcfb.c |  285 +++++++++++++++++++++-----------------
 drivers/video/sh_mobile_lcdcfb.h |    2 +
 2 files changed, 159 insertions(+), 128 deletions(-)

diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 9829e01..f6bc18e 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -1424,6 +1424,141 @@ static struct fb_ops sh_mobile_lcdc_ops = {
 	.fb_set_par	= sh_mobile_set_par,
 };
 
+static void
+sh_mobile_lcdc_channel_fb_unregister(struct sh_mobile_lcdc_chan *ch)
+{
+	if (ch->info && ch->info->dev)
+		unregister_framebuffer(ch->info);
+}
+
+static int __devinit
+sh_mobile_lcdc_channel_fb_register(struct sh_mobile_lcdc_chan *ch)
+{
+	struct fb_info *info = ch->info;
+	int ret;
+
+	if (info->fbdefio) {
+		ch->sglist = vmalloc(sizeof(struct scatterlist) *
+				     ch->fb_size >> PAGE_SHIFT);
+		if (!ch->sglist) {
+			dev_err(ch->lcdc->dev, "cannot allocate sglist\n");
+			return -ENOMEM;
+		}
+	}
+
+	info->bl_dev = ch->bl;
+
+	ret = register_framebuffer(info);
+	if (ret < 0)
+		return ret;
+
+	dev_info(ch->lcdc->dev, "registered %s/%s as %dx%d %dbpp.\n",
+		 dev_name(ch->lcdc->dev), (ch->cfg.chan = LCDC_CHAN_MAINLCD) ?
+		 "mainlcd" : "sublcd", info->var.xres, info->var.yres,
+		 info->var.bits_per_pixel);
+
+	/* deferred io mode: disable clock to save power */
+	if (info->fbdefio || info->state = FBINFO_STATE_SUSPENDED)
+		sh_mobile_lcdc_clk_off(ch->lcdc);
+
+	return ret;
+}
+
+static void
+sh_mobile_lcdc_channel_fb_cleanup(struct sh_mobile_lcdc_chan *ch)
+{
+	struct fb_info *info = ch->info;
+
+	if (!info || !info->device)
+		return;
+
+	if (ch->sglist)
+		vfree(ch->sglist);
+
+	fb_dealloc_cmap(&info->cmap);
+	framebuffer_release(info);
+}
+
+static int __devinit
+sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch,
+			       const struct fb_videomode *mode,
+			       unsigned int num_modes)
+{
+	struct sh_mobile_lcdc_priv *priv = ch->lcdc;
+	struct fb_var_screeninfo *var;
+	struct fb_info *info;
+	int ret;
+
+	/* Allocate and initialize the frame buffer device. Create the modes
+	 * list and allocate the color map.
+	 */
+	info = framebuffer_alloc(0, priv->dev);
+	if (info = NULL) {
+		dev_err(priv->dev, "unable to allocate fb_info\n");
+		return -ENOMEM;
+	}
+
+	ch->info = info;
+
+	info->flags = FBINFO_FLAG_DEFAULT;
+	info->fbops = &sh_mobile_lcdc_ops;
+	info->device = priv->dev;
+	info->screen_base = ch->fb_mem;
+	info->pseudo_palette = &ch->pseudo_palette;
+	info->par = ch;
+
+	fb_videomode_to_modelist(mode, num_modes, &info->modelist);
+
+	ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);
+	if (ret < 0) {
+		dev_err(priv->dev, "unable to allocate cmap\n");
+		return ret;
+	}
+
+	/* Initialize fixed screen information. Restrict pan to 2 lines steps
+	 * for NV12 and NV21.
+	 */
+	info->fix = sh_mobile_lcdc_fix;
+	info->fix.smem_start = ch->dma_handle;
+	info->fix.smem_len = ch->fb_size;
+	if (ch->format->fourcc = V4L2_PIX_FMT_NV12 ||
+	    ch->format->fourcc = V4L2_PIX_FMT_NV21)
+		info->fix.ypanstep = 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.
+	 */
+	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->activate = FB_ACTIVATE_NOW;
+
+	/* Use the legacy API by default for RGB formats, and the FOURCC API
+	 * for YUV formats.
+	 */
+	if (!ch->format->yuv)
+		var->bits_per_pixel = ch->format->bpp;
+	else
+		var->grayscale = ch->format->fourcc;
+
+	ret = sh_mobile_check_var(var, info);
+	if (ret)
+		return ret;
+
+	if (ch->format->yuv) {
+		info->fix.line_length = var->xres;
+		info->fix.visual = FB_VISUAL_FOURCC;
+	} else {
+		info->fix.line_length = var->xres * ch->format->bpp / 8;
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+	}
+
+	return 0;
+}
+
 /* -----------------------------------------------------------------------------
  * Backlight
  */
@@ -1592,37 +1727,28 @@ 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);
-	struct fb_info *info;
 	int i;
 
 	fb_unregister_client(&priv->notifier);
 
 	for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
-		if (priv->ch[i].info && priv->ch[i].info->dev)
-			unregister_framebuffer(priv->ch[i].info);
+		sh_mobile_lcdc_channel_fb_unregister(&priv->ch[i]);
 
 	sh_mobile_lcdc_stop(priv);
 
 	for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
 		struct sh_mobile_lcdc_chan *ch = &priv->ch[i];
 
-		info = ch->info;
-		if (!info || !info->device)
-			continue;
-
 		if (ch->tx_dev) {
 			ch->tx_dev->lcdc = NULL;
 			module_put(ch->cfg.tx_dev->dev.driver->owner);
 		}
 
-		if (ch->sglist)
-			vfree(ch->sglist);
+		sh_mobile_lcdc_channel_fb_cleanup(ch);
 
-		if (info->screen_base)
-			dma_free_coherent(&pdev->dev, info->fix.smem_len,
-					  info->screen_base, ch->dma_handle);
-		fb_dealloc_cmap(&info->cmap);
-		framebuffer_release(info);
+		if (ch->fb_mem)
+			dma_free_coherent(&pdev->dev, ch->fb_size,
+					  ch->fb_mem, ch->dma_handle);
 	}
 
 	for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
@@ -1693,13 +1819,9 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
 	struct sh_mobile_lcdc_chan_cfg *cfg = &ch->cfg;
 	const struct fb_videomode *max_mode;
 	const struct fb_videomode *mode;
-	struct fb_var_screeninfo *var;
-	struct fb_info *info;
+	unsigned int num_modes;
 	unsigned int max_size;
-	int num_modes;
-	void *buf;
-	int ret;
-	int i;
+	unsigned int i;
 
 	mutex_init(&ch->open_lock);
 	ch->notify = sh_mobile_lcdc_display_notify;
@@ -1713,19 +1835,6 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
 
 	ch->format = format;
 
-	/* Allocate the frame buffer device. */
-	ch->info = framebuffer_alloc(0, priv->dev);
-	if (!ch->info) {
-		dev_err(priv->dev, "unable to allocate fb_info\n");
-		return -ENOMEM;
-	}
-
-	info = ch->info;
-	info->fbops = &sh_mobile_lcdc_ops;
-	info->par = ch;
-	info->pseudo_palette = &ch->pseudo_palette;
-	info->flags = FBINFO_FLAG_DEFAULT;
-
 	/* Iterate through the modes to validate them and find the highest
 	 * resolution.
 	 */
@@ -1755,7 +1864,6 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
 		dev_dbg(priv->dev, "Found largest videomode %ux%u\n",
 			max_mode->xres, max_mode->yres);
 
-	/* Create the mode list. */
 	if (cfg->lcd_modes = NULL) {
 		mode = &default_720p;
 		num_modes = 1;
@@ -1764,7 +1872,18 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
 		num_modes = cfg->num_modes;
 	}
 
-	fb_videomode_to_modelist(mode, num_modes, &info->modelist);
+	ch->display.width = cfg->panel_cfg.width;
+	ch->display.height = cfg->panel_cfg.height;
+	ch->display.mode = *mode;
+
+	/* Allocate frame buffer memory. */
+	ch->fb_size = max_size * format->bpp / 8 * 2;
+	ch->fb_mem = dma_alloc_coherent(priv->dev, ch->fb_size, &ch->dma_handle,
+					GFP_KERNEL);
+	if (ch->fb_mem = NULL) {
+		dev_err(priv->dev, "unable to allocate buffer\n");
+		return -ENOMEM;
+	}
 
 	/* Initialize the transmitter device if present. */
 	if (cfg->tx_dev) {
@@ -1779,76 +1898,7 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
 		ch->tx_dev->def_mode = *mode;
 	}
 
-	/* 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.
-	 */
-	var = &info->var;
-	fb_videomode_to_var(var, mode);
-	var->width = cfg->panel_cfg.width;
-	var->height = cfg->panel_cfg.height;
-	var->yres_virtual = var->yres * 2;
-	var->activate = FB_ACTIVATE_NOW;
-
-	/* Use the legacy API by default for RGB formats, and the FOURCC API
-	 * for YUV formats.
-	 */
-	if (!format->yuv)
-		var->bits_per_pixel = format->bpp;
-	else
-		var->grayscale = cfg->fourcc;
-
-	/* Make sure the memory size check won't fail. smem_len is initialized
-	 * later based on var.
-	 */
-	info->fix.smem_len = UINT_MAX;
-	ret = sh_mobile_check_var(var, info);
-	if (ret)
-		return ret;
-
-	max_size = max_size * var->bits_per_pixel / 8 * 2;
-
-	/* Allocate frame buffer memory and color map. */
-	buf = dma_alloc_coherent(priv->dev, max_size, &ch->dma_handle,
-				 GFP_KERNEL);
-	if (!buf) {
-		dev_err(priv->dev, "unable to allocate buffer\n");
-		return -ENOMEM;
-	}
-
-	ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);
-	if (ret < 0) {
-		dev_err(priv->dev, "unable to allocate cmap\n");
-		dma_free_coherent(priv->dev, max_size, buf, ch->dma_handle);
-		return ret;
-	}
-
-	/* Initialize fixed screen information. Restrict pan to 2 lines steps
-	 * for NV12 and NV21.
-	 */
-	info->fix = sh_mobile_lcdc_fix;
-	info->fix.smem_start = ch->dma_handle;
-	info->fix.smem_len = max_size;
-	if (cfg->fourcc = V4L2_PIX_FMT_NV12 ||
-	    cfg->fourcc = V4L2_PIX_FMT_NV21)
-		info->fix.ypanstep = 2;
-
-	if (format->yuv) {
-		info->fix.line_length = var->xres;
-		info->fix.visual = FB_VISUAL_FOURCC;
-	} else {
-		info->fix.line_length = var->xres * var->bits_per_pixel / 8;
-		info->fix.visual = FB_VISUAL_TRUECOLOR;
-	}
-
-	info->screen_base = buf;
-	info->device = priv->dev;
-
-	ch->display.width = cfg->panel_cfg.width;
-	ch->display.height = cfg->panel_cfg.height;
-	ch->display.mode = *mode;
-
-	return 0;
+	return sh_mobile_lcdc_channel_fb_init(ch, mode, num_modes);
 }
 
 static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
@@ -1964,31 +2014,10 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
 
 	for (i = 0; i < num_channels; i++) {
 		struct sh_mobile_lcdc_chan *ch = priv->ch + i;
-		struct fb_info *info = ch->info;
-
-		if (info->fbdefio) {
-			ch->sglist = vmalloc(sizeof(struct scatterlist) *
-					info->fix.smem_len >> PAGE_SHIFT);
-			if (!ch->sglist) {
-				dev_err(&pdev->dev, "cannot allocate sglist\n");
-				goto err1;
-			}
-		}
 
-		info->bl_dev = ch->bl;
-
-		error = register_framebuffer(info);
-		if (error < 0)
+		error = sh_mobile_lcdc_channel_fb_register(ch);
+		if (error)
 			goto err1;
-
-		dev_info(&pdev->dev, "registered %s/%s as %dx%d %dbpp.\n",
-			 pdev->name, (ch->cfg.chan = LCDC_CHAN_MAINLCD) ?
-			 "mainlcd" : "sublcd", info->var.xres, info->var.yres,
-			 info->var.bits_per_pixel);
-
-		/* deferred io mode: disable clock to save power */
-		if (info->fbdefio || info->state = FBINFO_STATE_SUSPENDED)
-			sh_mobile_lcdc_clk_off(priv);
 	}
 
 	/* Failure ignored */
diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h
index 5ef7559..cc22b9e 100644
--- a/drivers/video/sh_mobile_lcdcfb.h
+++ b/drivers/video/sh_mobile_lcdcfb.h
@@ -64,6 +64,8 @@ struct sh_mobile_lcdc_chan {
 	struct mutex open_lock;		/* protects the use counter */
 	int use_count;
 
+	void *fb_mem;
+	unsigned long fb_size;
 	dma_addr_t dma_handle;
 	unsigned long pan_offset;
 
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 34/57] fbdev: sh_mobile_lcdc: Store the format in struct sh_mobile_lcdc_chan
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
  To: linux-fbdev

Store the active format in the channel structure, and use it instead of
parsing info->var all over the place when the format is needed.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mobile_lcdcfb.c |   21 ++++++++++-----------
 drivers/video/sh_mobile_lcdcfb.h |    4 +++-
 2 files changed, 13 insertions(+), 12 deletions(-)

diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index c6b6b9d..9829e01 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -726,20 +726,15 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 
 	/* Setup geometry, format, frame buffer memory and operation mode. */
 	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
-		const struct sh_mobile_lcdc_format_info *format;
-		u32 fourcc;
-
 		ch = &priv->ch[k];
 		if (!ch->enabled)
 			continue;
 
 		sh_mobile_lcdc_geometry(ch);
 
-		fourcc = sh_mobile_format_fourcc(&ch->info->var);
-		format = sh_mobile_format_info(fourcc);
-		tmp = format->lddfr;
+		tmp = ch->format->lddfr;
 
-		if (format->yuv) {
+		if (ch->format->yuv) {
 			switch (ch->info->var.colorspace) {
 			case V4L2_COLORSPACE_REC709:
 				tmp |= LDDFR_CF1;
@@ -753,7 +748,7 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 		lcdc_write_chan(ch, LDDFR, tmp);
 		lcdc_write_chan(ch, LDMLSR, ch->pitch);
 		lcdc_write_chan(ch, LDSA1R, ch->base_addr_y);
-		if (format->yuv)
+		if (ch->format->yuv)
 			lcdc_write_chan(ch, LDSA2R, ch->base_addr_c);
 
 		/* When using deferred I/O mode, configure the LCDC for one-shot
@@ -770,7 +765,7 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 	}
 
 	/* Word and long word swap. */
-	switch (sh_mobile_format_fourcc(&priv->ch[0].info->var)) {
+	switch (priv->ch[0].format->fourcc) {
 	case V4L2_PIX_FMT_RGB565:
 	case V4L2_PIX_FMT_NV21:
 	case V4L2_PIX_FMT_NV61:
@@ -857,7 +852,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 			ch->meram_enabled = 0;
 		}
 
-		switch (sh_mobile_format_fourcc(&ch->info->var)) {
+		switch (ch->format->fourcc) {
 		case V4L2_PIX_FMT_NV12:
 		case V4L2_PIX_FMT_NV21:
 		case V4L2_PIX_FMT_NV16:
@@ -1063,7 +1058,7 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
 			    + info->var.xres * info->var.yres_virtual
 			    + c_offset;
 		/* Set x offset */
-		if (sh_mobile_format_fourcc(&info->var) = V4L2_PIX_FMT_NV24)
+		if (ch->format->fourcc = V4L2_PIX_FMT_NV24)
 			base_addr_c += 2 * var->xoffset;
 		else
 			base_addr_c += var->xoffset;
@@ -1350,6 +1345,8 @@ static int sh_mobile_set_par(struct fb_info *info)
 		info->fix.line_length = info->var.xres
 				      * info->var.bits_per_pixel / 8;
 
+	ch->format = sh_mobile_format_info(sh_mobile_format_fourcc(&info->var));
+
 	ret = sh_mobile_lcdc_start(ch->lcdc);
 	if (ret < 0) {
 		dev_err(info->dev, "%s: unable to restart LCDC\n", __func__);
@@ -1714,6 +1711,8 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
 		return -EINVAL;
 	}
 
+	ch->format = format;
+
 	/* Allocate the frame buffer device. */
 	ch->info = framebuffer_alloc(0, priv->dev);
 	if (!ch->info) {
diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h
index 8e0d009..5ef7559 100644
--- a/drivers/video/sh_mobile_lcdcfb.h
+++ b/drivers/video/sh_mobile_lcdcfb.h
@@ -17,9 +17,10 @@ enum { LDDCKPAT1R, LDDCKPAT2R, LDMT1R, LDMT2R, LDMT3R, LDDFR, LDSM1R,
 struct backlight_device;
 struct fb_info;
 struct module;
+struct sh_mobile_lcdc_chan;
 struct sh_mobile_lcdc_entity;
+struct sh_mobile_lcdc_format_info;
 struct sh_mobile_lcdc_priv;
-struct sh_mobile_lcdc_chan;
 
 #define SH_MOBILE_LCDC_DISPLAY_DISCONNECTED	0
 #define SH_MOBILE_LCDC_DISPLAY_CONNECTED	1
@@ -70,6 +71,7 @@ struct sh_mobile_lcdc_chan {
 	wait_queue_head_t frame_end_wait;
 	struct completion vsync_completion;
 
+	const struct sh_mobile_lcdc_format_info *format;
 	unsigned long base_addr_y;
 	unsigned long base_addr_c;
 	unsigned int pitch;
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 33/57] fbdev: sh_mobile_lcdc: Add sh_mobile_format_info() function
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
  To: linux-fbdev

The function returns a pointer to a structure describing a format based
on its fourcc. Use the function where applicable instead of hardcoded
switch-case statements.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mobile_lcdcfb.c |  174 ++++++++++++++++++++++----------------
 1 files changed, 102 insertions(+), 72 deletions(-)

diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 3bc82ae..c6b6b9d 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -447,6 +447,75 @@ static int sh_mobile_lcdc_display_notify(struct sh_mobile_lcdc_chan *ch,
  * Format helpers
  */
 
+struct sh_mobile_lcdc_format_info {
+	u32 fourcc;
+	unsigned int bpp;
+	bool yuv;
+	u32 lddfr;
+};
+
+static const struct sh_mobile_lcdc_format_info sh_mobile_format_infos[] = {
+	{
+		.fourcc = V4L2_PIX_FMT_RGB565,
+		.bpp = 12,
+		.yuv = false,
+		.lddfr = LDDFR_PKF_RGB16,
+	}, {
+		.fourcc = V4L2_PIX_FMT_BGR24,
+		.bpp = 24,
+		.yuv = false,
+		.lddfr = LDDFR_PKF_RGB24,
+	}, {
+		.fourcc = V4L2_PIX_FMT_BGR32,
+		.bpp = 32,
+		.yuv = false,
+		.lddfr = LDDFR_PKF_ARGB32,
+	}, {
+		.fourcc = V4L2_PIX_FMT_NV12,
+		.bpp = 12,
+		.yuv = true,
+		.lddfr = LDDFR_CC | LDDFR_YF_420,
+	}, {
+		.fourcc = V4L2_PIX_FMT_NV21,
+		.bpp = 12,
+		.yuv = true,
+		.lddfr = LDDFR_CC | LDDFR_YF_420,
+	}, {
+		.fourcc = V4L2_PIX_FMT_NV16,
+		.bpp = 16,
+		.yuv = true,
+		.lddfr = LDDFR_CC | LDDFR_YF_422,
+	}, {
+		.fourcc = V4L2_PIX_FMT_NV61,
+		.bpp = 16,
+		.yuv = true,
+		.lddfr = LDDFR_CC | LDDFR_YF_422,
+	}, {
+		.fourcc = V4L2_PIX_FMT_NV24,
+		.bpp = 24,
+		.yuv = true,
+		.lddfr = LDDFR_CC | LDDFR_YF_444,
+	}, {
+		.fourcc = V4L2_PIX_FMT_NV42,
+		.bpp = 24,
+		.yuv = true,
+		.lddfr = LDDFR_CC | LDDFR_YF_444,
+	},
+};
+
+static const struct sh_mobile_lcdc_format_info *
+sh_mobile_format_info(u32 fourcc)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(sh_mobile_format_infos); ++i) {
+		if (sh_mobile_format_infos[i].fourcc = fourcc)
+			return &sh_mobile_format_infos[i];
+	}
+
+	return NULL;
+}
+
 static int sh_mobile_format_fourcc(const struct fb_var_screeninfo *var)
 {
 	if (var->grayscale > 1)
@@ -471,21 +540,13 @@ static int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var)
 
 static bool sh_mobile_format_is_yuv(const struct fb_var_screeninfo *var)
 {
+	const struct sh_mobile_lcdc_format_info *format;
+
 	if (var->grayscale <= 1)
 		return false;
 
-	switch (var->grayscale) {
-	case V4L2_PIX_FMT_NV12:
-	case V4L2_PIX_FMT_NV21:
-	case V4L2_PIX_FMT_NV16:
-	case V4L2_PIX_FMT_NV61:
-	case V4L2_PIX_FMT_NV24:
-	case V4L2_PIX_FMT_NV42:
-		return true;
-
-	default:
-		return false;
-	}
+	format = sh_mobile_format_info(var->grayscale);
+	return format ? format->yuv : false;
 }
 
 /* -----------------------------------------------------------------------------
@@ -665,37 +726,20 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 
 	/* Setup geometry, format, frame buffer memory and operation mode. */
 	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
+		const struct sh_mobile_lcdc_format_info *format;
+		u32 fourcc;
+
 		ch = &priv->ch[k];
 		if (!ch->enabled)
 			continue;
 
 		sh_mobile_lcdc_geometry(ch);
 
-		switch (sh_mobile_format_fourcc(&ch->info->var)) {
-		case V4L2_PIX_FMT_RGB565:
-			tmp = LDDFR_PKF_RGB16;
-			break;
-		case V4L2_PIX_FMT_BGR24:
-			tmp = LDDFR_PKF_RGB24;
-			break;
-		case V4L2_PIX_FMT_BGR32:
-			tmp = LDDFR_PKF_ARGB32;
-			break;
-		case V4L2_PIX_FMT_NV12:
-		case V4L2_PIX_FMT_NV21:
-			tmp = LDDFR_CC | LDDFR_YF_420;
-			break;
-		case V4L2_PIX_FMT_NV16:
-		case V4L2_PIX_FMT_NV61:
-			tmp = LDDFR_CC | LDDFR_YF_422;
-			break;
-		case V4L2_PIX_FMT_NV24:
-		case V4L2_PIX_FMT_NV42:
-			tmp = LDDFR_CC | LDDFR_YF_444;
-			break;
-		}
+		fourcc = sh_mobile_format_fourcc(&ch->info->var);
+		format = sh_mobile_format_info(fourcc);
+		tmp = format->lddfr;
 
-		if (sh_mobile_format_is_yuv(&ch->info->var)) {
+		if (format->yuv) {
 			switch (ch->info->var.colorspace) {
 			case V4L2_COLORSPACE_REC709:
 				tmp |= LDDFR_CF1;
@@ -709,7 +753,7 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 		lcdc_write_chan(ch, LDDFR, tmp);
 		lcdc_write_chan(ch, LDMLSR, ch->pitch);
 		lcdc_write_chan(ch, LDSA1R, ch->base_addr_y);
-		if (sh_mobile_format_is_yuv(&ch->info->var))
+		if (format->yuv)
 			lcdc_write_chan(ch, LDSA2R, ch->base_addr_c);
 
 		/* When using deferred I/O mode, configure the LCDC for one-shot
@@ -1225,32 +1269,17 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in
 		var->yres_virtual = var->yres;
 
 	if (sh_mobile_format_is_fourcc(var)) {
-		switch (var->grayscale) {
-		case V4L2_PIX_FMT_NV12:
-		case V4L2_PIX_FMT_NV21:
-			var->bits_per_pixel = 12;
-			break;
-		case V4L2_PIX_FMT_RGB565:
-		case V4L2_PIX_FMT_NV16:
-		case V4L2_PIX_FMT_NV61:
-			var->bits_per_pixel = 16;
-			break;
-		case V4L2_PIX_FMT_BGR24:
-		case V4L2_PIX_FMT_NV24:
-		case V4L2_PIX_FMT_NV42:
-			var->bits_per_pixel = 24;
-			break;
-		case V4L2_PIX_FMT_BGR32:
-			var->bits_per_pixel = 32;
-			break;
-		default:
+		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 (!sh_mobile_format_is_yuv(var))
+		if (!format->yuv)
 			var->colorspace = V4L2_COLORSPACE_SRGB;
 		else if (var->colorspace != V4L2_COLORSPACE_REC709)
 			var->colorspace = V4L2_COLORSPACE_JPEG;
@@ -1663,6 +1692,7 @@ static int __devinit
 sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
 			    struct sh_mobile_lcdc_chan *ch)
 {
+	const struct sh_mobile_lcdc_format_info *format;
 	struct sh_mobile_lcdc_chan_cfg *cfg = &ch->cfg;
 	const struct fb_videomode *max_mode;
 	const struct fb_videomode *mode;
@@ -1677,6 +1707,13 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
 	mutex_init(&ch->open_lock);
 	ch->notify = sh_mobile_lcdc_display_notify;
 
+	/* Validate the format. */
+	format = sh_mobile_format_info(cfg->fourcc);
+	if (format = NULL) {
+		dev_err(priv->dev, "Invalid FOURCC %08x.\n", cfg->fourcc);
+		return -EINVAL;
+	}
+
 	/* Allocate the frame buffer device. */
 	ch->info = framebuffer_alloc(0, priv->dev);
 	if (!ch->info) {
@@ -1754,20 +1791,13 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
 	var->yres_virtual = var->yres * 2;
 	var->activate = FB_ACTIVATE_NOW;
 
-	switch (cfg->fourcc) {
-	case V4L2_PIX_FMT_RGB565:
-		var->bits_per_pixel = 16;
-		break;
-	case V4L2_PIX_FMT_BGR24:
-		var->bits_per_pixel = 24;
-		break;
-	case V4L2_PIX_FMT_BGR32:
-		var->bits_per_pixel = 32;
-		break;
-	default:
+	/* Use the legacy API by default for RGB formats, and the FOURCC API
+	 * for YUV formats.
+	 */
+	if (!format->yuv)
+		var->bits_per_pixel = format->bpp;
+	else
 		var->grayscale = cfg->fourcc;
-		break;
-	}
 
 	/* Make sure the memory size check won't fail. smem_len is initialized
 	 * later based on var.
@@ -1804,7 +1834,7 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
 	    cfg->fourcc = V4L2_PIX_FMT_NV21)
 		info->fix.ypanstep = 2;
 
-	if (sh_mobile_format_is_yuv(var)) {
+	if (format->yuv) {
 		info->fix.line_length = var->xres;
 		info->fix.visual = FB_VISUAL_FOURCC;
 	} else {
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 32/57] fbdev: sh_mobile_lcdc: Reorganize the sh_mobile_lcdc_chan structure
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
  To: linux-fbdev

Group fields by purpose, and make the separation between core fields and
FB-related fields clear.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mobile_lcdcfb.h |   39 ++++++++++++++++++++++---------------
 1 files changed, 23 insertions(+), 16 deletions(-)

diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h
index c175387..8e0d009 100644
--- a/drivers/video/sh_mobile_lcdcfb.h
+++ b/drivers/video/sh_mobile_lcdcfb.h
@@ -53,30 +53,22 @@ struct sh_mobile_lcdc_entity {
 struct sh_mobile_lcdc_chan {
 	struct sh_mobile_lcdc_priv *lcdc;
 	struct sh_mobile_lcdc_entity *tx_dev;
+	struct sh_mobile_lcdc_chan_cfg cfg;
 
 	unsigned long *reg_offs;
 	unsigned long ldmt1r_value;
 	unsigned long enabled; /* ME and SE in LDCNT2R */
-	struct sh_mobile_lcdc_chan_cfg cfg;
-	u32 pseudo_palette[PALETTE_NR];
-	struct fb_info *info;
-	struct backlight_device *bl;
+	int meram_enabled;
+
+	struct mutex open_lock;		/* protects the use counter */
+	int use_count;
+
 	dma_addr_t dma_handle;
-	struct fb_deferred_io defio;
-	struct scatterlist *sglist;
-	unsigned long frame_end;
 	unsigned long pan_offset;
+
+	unsigned long frame_end;
 	wait_queue_head_t frame_end_wait;
 	struct completion vsync_completion;
-	struct {
-		unsigned int width;
-		unsigned int height;
-		struct fb_videomode mode;
-	} display;
-	int use_count;
-	int blank_status;
-	struct mutex open_lock;		/* protects the use counter */
-	int meram_enabled;
 
 	unsigned long base_addr_y;
 	unsigned long base_addr_c;
@@ -86,6 +78,21 @@ struct sh_mobile_lcdc_chan {
 		      enum sh_mobile_lcdc_entity_event event,
 		      const struct fb_videomode *mode,
 		      const struct fb_monspecs *monspec);
+
+	/* Backlight */
+	struct backlight_device *bl;
+
+	/* FB */
+	struct fb_info *info;
+	u32 pseudo_palette[PALETTE_NR];
+	struct {
+		unsigned int width;
+		unsigned int height;
+		struct fb_videomode mode;
+	} display;
+	struct fb_deferred_io defio;
+	struct scatterlist *sglist;
+	int blank_status;
 };
 
 #endif
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 31/57] fbdev: sh_mobile_lcdc: Rename (lcd|num)_cfg (lcd|num)_modes
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
  To: linux-fbdev

The struct sh_mobile_lcdc_chan_cfg platform data contains a list of
video modes. Name the lcd_cfg and num_cfg fields to reflect that they
describe video modes.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 arch/arm/mach-shmobile/board-ag5evm.c   |    4 +-
 arch/arm/mach-shmobile/board-ap4evb.c   |    4 +-
 arch/arm/mach-shmobile/board-mackerel.c |    4 +-
 arch/sh/boards/mach-ap325rxa/setup.c    |    4 +-
 arch/sh/boards/mach-ecovec24/setup.c    |    8 +++---
 arch/sh/boards/mach-kfr2r09/setup.c     |    4 +-
 arch/sh/boards/mach-migor/setup.c       |    8 +++---
 arch/sh/boards/mach-se/7724/setup.c     |    8 +++---
 drivers/video/sh_mipi_dsi.c             |   38 +++++++++++++++---------------
 drivers/video/sh_mobile_lcdcfb.c        |   20 ++++++++--------
 include/video/sh_mobile_lcdc.h          |    4 +-
 11 files changed, 53 insertions(+), 53 deletions(-)

diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c
index cdf45db..5a12444 100644
--- a/arch/arm/mach-shmobile/board-ag5evm.c
+++ b/arch/arm/mach-shmobile/board-ag5evm.c
@@ -260,8 +260,8 @@ static struct sh_mobile_lcdc_info lcdc0_info = {
 		.clock_divider = 1,
 		.flags = LCDC_FLAGS_DWPOL,
 		.fourcc = V4L2_PIX_FMT_RGB565,
-		.lcd_cfg = lcdc0_modes,
-		.num_cfg = ARRAY_SIZE(lcdc0_modes),
+		.lcd_modes = lcdc0_modes,
+		.num_modes = ARRAY_SIZE(lcdc0_modes),
 		.panel_cfg = {
 			.width = 44,
 			.height = 79,
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c
index 26f30c8..5e876c7 100644
--- a/arch/arm/mach-shmobile/board-ap4evb.c
+++ b/arch/arm/mach-shmobile/board-ap4evb.c
@@ -601,8 +601,8 @@ static struct sh_mobile_lcdc_info lcdc_info = {
 	.ch[0] = {
 		.chan = LCDC_CHAN_MAINLCD,
 		.fourcc = V4L2_PIX_FMT_RGB565,
-		.lcd_cfg = ap4evb_lcdc_modes,
-		.num_cfg = ARRAY_SIZE(ap4evb_lcdc_modes),
+		.lcd_modes = ap4evb_lcdc_modes,
+		.num_modes = ARRAY_SIZE(ap4evb_lcdc_modes),
 		.meram_cfg = &lcd_meram_cfg,
 #ifdef CONFIG_AP4EVB_QHD
 		.tx_dev = &mipidsi0_device,
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index c0e95e5..b0f19fd 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -389,8 +389,8 @@ static struct sh_mobile_lcdc_info lcdc_info = {
 	.ch[0] = {
 		.chan = LCDC_CHAN_MAINLCD,
 		.fourcc = V4L2_PIX_FMT_RGB565,
-		.lcd_cfg = mackerel_lcdc_modes,
-		.num_cfg = ARRAY_SIZE(mackerel_lcdc_modes),
+		.lcd_modes = mackerel_lcdc_modes,
+		.num_modes = ARRAY_SIZE(mackerel_lcdc_modes),
 		.interface_type		= RGB24,
 		.clock_divider		= 3,
 		.flags			= 0,
diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c
index bdcc291..79f2c7c 100644
--- a/arch/sh/boards/mach-ap325rxa/setup.c
+++ b/arch/sh/boards/mach-ap325rxa/setup.c
@@ -210,8 +210,8 @@ static struct sh_mobile_lcdc_info lcdc_info = {
 		.fourcc = V4L2_PIX_FMT_RGB565,
 		.interface_type = RGB18,
 		.clock_divider = 1,
-		.lcd_cfg = ap325rxa_lcdc_modes,
-		.num_cfg = ARRAY_SIZE(ap325rxa_lcdc_modes),
+		.lcd_modes = ap325rxa_lcdc_modes,
+		.num_modes = ARRAY_SIZE(ap325rxa_lcdc_modes),
 		.panel_cfg = {
 			.width = 152,	/* 7.0 inch */
 			.height = 91,
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index 881d2f0..aa2ac50 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -1148,8 +1148,8 @@ static int __init arch_setup(void)
 		/* DVI */
 		lcdc_info.clock_source			= LCDC_CLK_EXTERNAL;
 		lcdc_info.ch[0].clock_divider		= 1;
-		lcdc_info.ch[0].lcd_cfg			= ecovec_dvi_modes;
-		lcdc_info.ch[0].num_cfg			= ARRAY_SIZE(ecovec_dvi_modes);
+		lcdc_info.ch[0].lcd_modes		= ecovec_dvi_modes;
+		lcdc_info.ch[0].num_modes		= ARRAY_SIZE(ecovec_dvi_modes);
 
 		gpio_set_value(GPIO_PTA2, 1);
 		gpio_set_value(GPIO_PTU1, 1);
@@ -1157,8 +1157,8 @@ static int __init arch_setup(void)
 		/* Panel */
 		lcdc_info.clock_source			= LCDC_CLK_PERIPHERAL;
 		lcdc_info.ch[0].clock_divider		= 2;
-		lcdc_info.ch[0].lcd_cfg			= ecovec_lcd_modes;
-		lcdc_info.ch[0].num_cfg			= ARRAY_SIZE(ecovec_lcd_modes);
+		lcdc_info.ch[0].lcd_modes		= ecovec_lcd_modes;
+		lcdc_info.ch[0].num_modes		= ARRAY_SIZE(ecovec_lcd_modes);
 
 		gpio_set_value(GPIO_PTR1, 1);
 
diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c
index 615cb4b..cb453af 100644
--- a/arch/sh/boards/mach-kfr2r09/setup.c
+++ b/arch/sh/boards/mach-kfr2r09/setup.c
@@ -150,8 +150,8 @@ static struct sh_mobile_lcdc_info kfr2r09_sh_lcdc_info = {
 		.interface_type = SYS18,
 		.clock_divider = 6,
 		.flags = LCDC_FLAGS_DWPOL,
-		.lcd_cfg = kfr2r09_lcdc_modes,
-		.num_cfg = ARRAY_SIZE(kfr2r09_lcdc_modes),
+		.lcd_modes = kfr2r09_lcdc_modes,
+		.num_modes = ARRAY_SIZE(kfr2r09_lcdc_modes),
 		.panel_cfg = {
 			.width = 35,
 			.height = 58,
diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c
index d42da46..2ad619c 100644
--- a/arch/sh/boards/mach-migor/setup.c
+++ b/arch/sh/boards/mach-migor/setup.c
@@ -247,8 +247,8 @@ static struct sh_mobile_lcdc_info sh_mobile_lcdc_info = {
 		.fourcc = V4L2_PIX_FMT_RGB565,
 		.interface_type = RGB16,
 		.clock_divider = 2,
-		.lcd_cfg = migor_lcd_modes,
-		.num_cfg = ARRAY_SIZE(migor_lcd_modes),
+		.lcd_modes = migor_lcd_modes,
+		.num_modes = ARRAY_SIZE(migor_lcd_modes),
 		.panel_cfg = { /* 7.0 inch */
 			.width = 152,
 			.height = 91,
@@ -261,8 +261,8 @@ static struct sh_mobile_lcdc_info sh_mobile_lcdc_info = {
 		.fourcc = V4L2_PIX_FMT_RGB565,
 		.interface_type = SYS16A,
 		.clock_divider = 10,
-		.lcd_cfg = migor_lcd_modes,
-		.num_cfg = ARRAY_SIZE(migor_lcd_modes),
+		.lcd_modes = migor_lcd_modes,
+		.num_modes = ARRAY_SIZE(migor_lcd_modes),
 		.panel_cfg = {
 			.width = 49,	/* 2.4 inch */
 			.height = 37,
diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c
index 7251ebb..3d61810 100644
--- a/arch/sh/boards/mach-se/7724/setup.c
+++ b/arch/sh/boards/mach-se/7724/setup.c
@@ -903,12 +903,12 @@ static int __init devices_setup(void)
 
 	if (sw & SW41_B) {
 		/* 720p */
-		lcdc_info.ch[0].lcd_cfg	= lcdc_720p_modes;
-		lcdc_info.ch[0].num_cfg	= ARRAY_SIZE(lcdc_720p_modes);
+		lcdc_info.ch[0].lcd_modes = lcdc_720p_modes;
+		lcdc_info.ch[0].num_modes = ARRAY_SIZE(lcdc_720p_modes);
 	} else {
 		/* VGA */
-		lcdc_info.ch[0].lcd_cfg	= lcdc_vga_modes;
-		lcdc_info.ch[0].num_cfg	= ARRAY_SIZE(lcdc_vga_modes);
+		lcdc_info.ch[0].lcd_modes = lcdc_vga_modes;
+		lcdc_info.ch[0].num_modes = ARRAY_SIZE(lcdc_vga_modes);
 	}
 
 	if (sw & SW41_A) {
diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c
index 5ff3742..42ad0f7 100644
--- a/drivers/video/sh_mipi_dsi.c
+++ b/drivers/video/sh_mipi_dsi.c
@@ -147,77 +147,77 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi,
 		pctype = 0;
 		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24;
 		pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
-		linelength = ch->lcd_cfg[0].xres * 3;
+		linelength = ch->lcd_modes[0].xres * 3;
 		yuv = false;
 		break;
 	case MIPI_RGB565:
 		pctype = 1;
 		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16;
 		pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
-		linelength = ch->lcd_cfg[0].xres * 2;
+		linelength = ch->lcd_modes[0].xres * 2;
 		yuv = false;
 		break;
 	case MIPI_RGB666_LP:
 		pctype = 2;
 		datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
 		pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
-		linelength = ch->lcd_cfg[0].xres * 3;
+		linelength = ch->lcd_modes[0].xres * 3;
 		yuv = false;
 		break;
 	case MIPI_RGB666:
 		pctype = 3;
 		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18;
 		pixfmt = MIPI_DCS_PIXEL_FMT_18BIT;
-		linelength = (ch->lcd_cfg[0].xres * 18 + 7) / 8;
+		linelength = (ch->lcd_modes[0].xres * 18 + 7) / 8;
 		yuv = false;
 		break;
 	case MIPI_BGR888:
 		pctype = 8;
 		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24;
 		pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
-		linelength = ch->lcd_cfg[0].xres * 3;
+		linelength = ch->lcd_modes[0].xres * 3;
 		yuv = false;
 		break;
 	case MIPI_BGR565:
 		pctype = 9;
 		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16;
 		pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
-		linelength = ch->lcd_cfg[0].xres * 2;
+		linelength = ch->lcd_modes[0].xres * 2;
 		yuv = false;
 		break;
 	case MIPI_BGR666_LP:
 		pctype = 0xa;
 		datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
 		pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
-		linelength = ch->lcd_cfg[0].xres * 3;
+		linelength = ch->lcd_modes[0].xres * 3;
 		yuv = false;
 		break;
 	case MIPI_BGR666:
 		pctype = 0xb;
 		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18;
 		pixfmt = MIPI_DCS_PIXEL_FMT_18BIT;
-		linelength = (ch->lcd_cfg[0].xres * 18 + 7) / 8;
+		linelength = (ch->lcd_modes[0].xres * 18 + 7) / 8;
 		yuv = false;
 		break;
 	case MIPI_YUYV:
 		pctype = 4;
 		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16;
 		pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
-		linelength = ch->lcd_cfg[0].xres * 2;
+		linelength = ch->lcd_modes[0].xres * 2;
 		yuv = true;
 		break;
 	case MIPI_UYVY:
 		pctype = 5;
 		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16;
 		pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
-		linelength = ch->lcd_cfg[0].xres * 2;
+		linelength = ch->lcd_modes[0].xres * 2;
 		yuv = true;
 		break;
 	case MIPI_YUV420_L:
 		pctype = 6;
 		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12;
 		pixfmt = MIPI_DCS_PIXEL_FMT_12BIT;
-		linelength = (ch->lcd_cfg[0].xres * 12 + 7) / 8;
+		linelength = (ch->lcd_modes[0].xres * 12 + 7) / 8;
 		yuv = true;
 		break;
 	case MIPI_YUV420:
@@ -225,7 +225,7 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi,
 		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12;
 		pixfmt = MIPI_DCS_PIXEL_FMT_12BIT;
 		/* Length of U/V line */
-		linelength = (ch->lcd_cfg[0].xres + 1) / 2;
+		linelength = (ch->lcd_modes[0].xres + 1) / 2;
 		yuv = true;
 		break;
 	default:
@@ -294,7 +294,7 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi,
 	 */
 	iowrite32(0x00000006, mipi->linkbase + DTCTR);
 	/* VSYNC width = 2 (<< 17) */
-	iowrite32((ch->lcd_cfg[0].vsync_len << pdata->vsynw_offset) |
+	iowrite32((ch->lcd_modes[0].vsync_len << pdata->vsynw_offset) |
 		  (pdata->clksrc << 16) | (pctype << 12) | datatype,
 		  mipi->linkbase + VMCTR1);
 
@@ -328,7 +328,7 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi,
 	top = linelength << 16; /* RGBLEN */
 	bottom = 0x00000001;
 	if (pdata->flags & SH_MIPI_DSI_HSABM) /* HSALEN */
-		bottom = (pdata->lane * ch->lcd_cfg[0].hsync_len) - 10;
+		bottom = (pdata->lane * ch->lcd_modes[0].hsync_len) - 10;
 	iowrite32(top | bottom , mipi->linkbase + VMLEN1);
 
 	/*
@@ -348,18 +348,18 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi,
 		div = 2;
 
 	if (pdata->flags & SH_MIPI_DSI_HFPBM) {	/* HBPLEN */
-		top = ch->lcd_cfg[0].hsync_len + ch->lcd_cfg[0].left_margin;
+		top = ch->lcd_modes[0].hsync_len + ch->lcd_modes[0].left_margin;
 		top = ((pdata->lane * top / div) - 10) << 16;
 	}
 	if (pdata->flags & SH_MIPI_DSI_HBPBM) { /* HFPLEN */
-		bottom = ch->lcd_cfg[0].right_margin;
+		bottom = ch->lcd_modes[0].right_margin;
 		bottom = (pdata->lane * bottom / div) - 12;
 	}
 
-	bpp = linelength / ch->lcd_cfg[0].xres; /* byte / pixel */
+	bpp = linelength / ch->lcd_modes[0].xres; /* byte / pixel */
 	if ((pdata->lane / div) > bpp) {
-		tmp = ch->lcd_cfg[0].xres / bpp; /* output cycle */
-		tmp = ch->lcd_cfg[0].xres - tmp; /* (input - output) cycle */
+		tmp = ch->lcd_modes[0].xres / bpp; /* output cycle */
+		tmp = ch->lcd_modes[0].xres - tmp; /* (input - output) cycle */
 		delay = (pdata->lane * tmp);
 	}
 
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index d672a3f..3bc82ae 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -1188,8 +1188,8 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in
 	 * distance between two modes is defined as the size of the
 	 * non-overlapping parts of the two rectangles.
 	 */
-	for (i = 0; i < ch->cfg.num_cfg; ++i) {
-		const struct fb_videomode *mode = &ch->cfg.lcd_cfg[i];
+	for (i = 0; i < ch->cfg.num_modes; ++i) {
+		const struct fb_videomode *mode = &ch->cfg.lcd_modes[i];
 		unsigned int dist;
 
 		/* We can only round up. */
@@ -1208,7 +1208,7 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in
 	}
 
 	/* If no available mode can be used, return an error. */
-	if (ch->cfg.num_cfg != 0) {
+	if (ch->cfg.num_modes != 0) {
 		if (best_dist = (unsigned int)-1)
 			return -EINVAL;
 
@@ -1669,7 +1669,7 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
 	struct fb_var_screeninfo *var;
 	struct fb_info *info;
 	unsigned int max_size;
-	int num_cfg;
+	int num_modes;
 	void *buf;
 	int ret;
 	int i;
@@ -1696,7 +1696,7 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
 	max_mode = NULL;
 	max_size = 0;
 
-	for (i = 0, mode = cfg->lcd_cfg; i < cfg->num_cfg; i++, mode++) {
+	for (i = 0, mode = cfg->lcd_modes; i < cfg->num_modes; i++, mode++) {
 		unsigned int size = mode->yres * mode->xres;
 
 		/* NV12/NV21 buffers must have even number of lines */
@@ -1720,15 +1720,15 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
 			max_mode->xres, max_mode->yres);
 
 	/* Create the mode list. */
-	if (cfg->lcd_cfg = NULL) {
+	if (cfg->lcd_modes = NULL) {
 		mode = &default_720p;
-		num_cfg = 1;
+		num_modes = 1;
 	} else {
-		mode = cfg->lcd_cfg;
-		num_cfg = cfg->num_cfg;
+		mode = cfg->lcd_modes;
+		num_modes = cfg->num_modes;
 	}
 
-	fb_videomode_to_modelist(mode, num_cfg, &info->modelist);
+	fb_videomode_to_modelist(mode, num_modes, &info->modelist);
 
 	/* Initialize the transmitter device if present. */
 	if (cfg->tx_dev) {
diff --git a/include/video/sh_mobile_lcdc.h b/include/video/sh_mobile_lcdc.h
index 84163e4..5a6991d 100644
--- a/include/video/sh_mobile_lcdc.h
+++ b/include/video/sh_mobile_lcdc.h
@@ -173,8 +173,8 @@ struct sh_mobile_lcdc_chan_cfg {
 	int interface_type; /* selects RGBn or SYSn I/F, see above */
 	int clock_divider;
 	unsigned long flags; /* LCDC_FLAGS_... */
-	const struct fb_videomode *lcd_cfg;
-	int num_cfg;
+	const struct fb_videomode *lcd_modes;
+	int num_modes;
 	struct sh_mobile_lcdc_panel_cfg panel_cfg;
 	struct sh_mobile_lcdc_bl_info bl_info;
 	struct sh_mobile_lcdc_sys_bus_cfg sys_bus_cfg; /* only for SYSn I/F */
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 30/57] fbdev: sh_mobile_lcdc: Store display mode in a struct fb_videomode
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
  To: linux-fbdev

Embed struct fb_videomode instead of struct fb_var_screeninfo in struct
sh_mobile_lcdc_chan to store the display mode.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mobile_lcdcfb.c |   73 ++++++++++++++++++++------------------
 drivers/video/sh_mobile_lcdcfb.h |    6 +++-
 2 files changed, 43 insertions(+), 36 deletions(-)

diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index c5acae7..d672a3f 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -367,21 +367,17 @@ static bool
 sh_mobile_lcdc_must_reconfigure(struct sh_mobile_lcdc_chan *ch,
 				const struct fb_videomode *new_mode)
 {
-	struct fb_var_screeninfo *old_var = &ch->display_var;
-	struct fb_videomode old_mode;
-
-	fb_var_to_videomode(&old_mode, old_var);
-
 	dev_dbg(ch->info->dev, "Old %ux%u, new %ux%u\n",
-		old_mode.xres, old_mode.yres, new_mode->xres, new_mode->yres);
+		ch->display.mode.xres, ch->display.mode.yres,
+		new_mode->xres, new_mode->yres);
 
 	/* It can be a different monitor with an equal video-mode */
-	if (fb_mode_is_equal(&old_mode, new_mode))
+	if (fb_mode_is_equal(&ch->display.mode, new_mode))
 		return false;
 
 	dev_dbg(ch->info->dev, "Switching %u -> %u lines\n",
-		old_mode.yres, new_mode->yres);
-	fb_videomode_to_var(old_var, new_mode);
+		ch->display.mode.yres, new_mode->yres);
+	ch->display.mode = *new_mode;
 
 	return true;
 }
@@ -400,8 +396,8 @@ static int sh_mobile_lcdc_display_notify(struct sh_mobile_lcdc_chan *ch,
 		if (lock_fb_info(info)) {
 			console_lock();
 
-			ch->display_var.width = monspec->max_x * 10;
-			ch->display_var.height = monspec->max_y * 10;
+			ch->display.width = monspec->max_x * 10;
+			ch->display.height = monspec->max_y * 10;
 
 			if (!sh_mobile_lcdc_must_reconfigure(ch, mode) &&
 			    info->state = FBINFO_STATE_RUNNING) {
@@ -567,7 +563,8 @@ static void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv,
 
 static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
 {
-	struct fb_var_screeninfo *var = &ch->info->var, *display_var = &ch->display_var;
+	const struct fb_var_screeninfo *var = &ch->info->var;
+	const struct fb_videomode *mode = &ch->display.mode;
 	unsigned long h_total, hsync_pos, display_h_total;
 	u32 tmp;
 
@@ -586,34 +583,32 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
 	lcdc_write_chan(ch, LDMT3R, ch->cfg.sys_bus_cfg.ldmt3r);
 
 	/* horizontal configuration */
-	h_total = display_var->xres + display_var->hsync_len +
-		display_var->left_margin + display_var->right_margin;
+	h_total = mode->xres + mode->hsync_len + mode->left_margin
+		+ mode->right_margin;
 	tmp = h_total / 8; /* HTCN */
-	tmp |= (min(display_var->xres, var->xres) / 8) << 16; /* HDCN */
+	tmp |= (min(mode->xres, var->xres) / 8) << 16; /* HDCN */
 	lcdc_write_chan(ch, LDHCNR, tmp);
 
-	hsync_pos = display_var->xres + display_var->right_margin;
+	hsync_pos = mode->xres + mode->right_margin;
 	tmp = hsync_pos / 8; /* HSYNP */
-	tmp |= (display_var->hsync_len / 8) << 16; /* HSYNW */
+	tmp |= (mode->hsync_len / 8) << 16; /* HSYNW */
 	lcdc_write_chan(ch, LDHSYNR, tmp);
 
 	/* vertical configuration */
-	tmp = display_var->yres + display_var->vsync_len +
-		display_var->upper_margin + display_var->lower_margin; /* VTLN */
-	tmp |= min(display_var->yres, var->yres) << 16; /* VDLN */
+	tmp = mode->yres + mode->vsync_len + mode->upper_margin
+	    + mode->lower_margin; /* VTLN */
+	tmp |= min(mode->yres, var->yres) << 16; /* VDLN */
 	lcdc_write_chan(ch, LDVLNR, tmp);
 
-	tmp = display_var->yres + display_var->lower_margin; /* VSYNP */
-	tmp |= display_var->vsync_len << 16; /* VSYNW */
+	tmp = mode->yres + mode->lower_margin; /* VSYNP */
+	tmp |= mode->vsync_len << 16; /* VSYNW */
 	lcdc_write_chan(ch, LDVSYNR, tmp);
 
 	/* Adjust horizontal synchronisation for HDMI */
-	display_h_total = display_var->xres + display_var->hsync_len +
-		display_var->left_margin + display_var->right_margin;
-	tmp = ((display_var->xres & 7) << 24) |
-		((display_h_total & 7) << 16) |
-		((display_var->hsync_len & 7) << 8) |
-		(hsync_pos & 7);
+	display_h_total = mode->xres + mode->hsync_len + mode->left_margin
+			+ mode->right_margin;
+	tmp = ((mode->xres & 7) << 24) | ((display_h_total & 7) << 16)
+	    | ((mode->hsync_len & 7) << 8) | (hsync_pos & 7);
 	lcdc_write_chan(ch, LDHAJR, tmp);
 }
 
@@ -1104,7 +1099,8 @@ static int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd,
 static void sh_mobile_fb_reconfig(struct fb_info *info)
 {
 	struct sh_mobile_lcdc_chan *ch = info->par;
-	struct fb_videomode mode1, mode2;
+	struct fb_var_screeninfo var;
+	struct fb_videomode mode;
 	struct fb_event event;
 	int evnt = FB_EVENT_MODE_CHANGE_ALL;
 
@@ -1112,14 +1108,18 @@ static void sh_mobile_fb_reconfig(struct fb_info *info)
 		/* More framebuffer users are active */
 		return;
 
-	fb_var_to_videomode(&mode1, &ch->display_var);
-	fb_var_to_videomode(&mode2, &info->var);
+	fb_var_to_videomode(&mode, &info->var);
 
-	if (fb_mode_is_equal(&mode1, &mode2))
+	if (fb_mode_is_equal(&ch->display.mode, &mode))
 		return;
 
 	/* Display has been re-plugged, framebuffer is free now, reconfigure */
-	if (fb_set_var(info, &ch->display_var) < 0)
+	fb_videomode_to_var(&var, &ch->display.mode);
+	var.width = ch->display.width;
+	var.height = ch->display.height;
+	var.activate = FB_ACTIVATE_NOW;
+
+	if (fb_set_var(info, &var) < 0)
 		/* Couldn't reconfigure, hopefully, can continue as before */
 		return;
 
@@ -1129,7 +1129,7 @@ static void sh_mobile_fb_reconfig(struct fb_info *info)
 	 * user event, we have to call the chain ourselves.
 	 */
 	event.info = info;
-	event.data = &mode1;
+	event.data = &ch->display.mode;
 	fb_notifier_call_chain(evnt, &event);
 }
 
@@ -1814,7 +1814,10 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
 
 	info->screen_base = buf;
 	info->device = priv->dev;
-	ch->display_var = *var;
+
+	ch->display.width = cfg->panel_cfg.width;
+	ch->display.height = cfg->panel_cfg.height;
+	ch->display.mode = *mode;
 
 	return 0;
 }
diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h
index 9c91fae..c175387 100644
--- a/drivers/video/sh_mobile_lcdcfb.h
+++ b/drivers/video/sh_mobile_lcdcfb.h
@@ -68,7 +68,11 @@ struct sh_mobile_lcdc_chan {
 	unsigned long pan_offset;
 	wait_queue_head_t frame_end_wait;
 	struct completion vsync_completion;
-	struct fb_var_screeninfo display_var;
+	struct {
+		unsigned int width;
+		unsigned int height;
+		struct fb_videomode mode;
+	} display;
 	int use_count;
 	int blank_status;
 	struct mutex open_lock;		/* protects the use counter */
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 29/57] fbdev: sh_mobile_hdmi: Don't access LCDC fb_info
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
  To: linux-fbdev

The LCDC fb_info structure is only used to retrieve the default video
mode in case none of the modes advertised by EDID information is
acceptable. Pass a pointer to the default mode through the
sh_mobile_lcdc_entity structure instead.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mobile_hdmi.c   |   34 ++++++++++++++--------------------
 drivers/video/sh_mobile_lcdcfb.c |   24 +++++++++++++-----------
 drivers/video/sh_mobile_lcdcfb.h |    1 +
 3 files changed, 28 insertions(+), 31 deletions(-)

diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c
index 37f935f..eafb19d 100644
--- a/drivers/video/sh_mobile_hdmi.c
+++ b/drivers/video/sh_mobile_hdmi.c
@@ -734,12 +734,11 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate,
 			     unsigned long *parent_rate)
 {
 	struct sh_mobile_lcdc_chan *ch = hdmi->entity.lcdc;
-	struct fb_info *info = ch ? ch->info : NULL;
 	const struct fb_videomode *mode, *found = NULL;
-	const struct fb_modelist *modelist = NULL;
 	unsigned int f_width = 0, f_height = 0, f_refresh = 0;
 	unsigned long found_rate_error = ULONG_MAX; /* silly compiler... */
 	bool scanning = false, preferred_bad = false;
+	bool use_edid_mode = false;
 	u8 edid[128];
 	char *forced;
 	int i;
@@ -864,25 +863,19 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate,
 
 		found = mode;
 		found_rate_error = rate_error;
+		use_edid_mode = true;
 	}
 
 	/*
-	 * TODO 1: if no ->info is present, postpone running the config until
-	 * after ->info first gets registered.
+	 * TODO 1: if no default mode is present, postpone running the config
+	 * until after the LCDC channel is initialized.
 	 * TODO 2: consider registering the HDMI platform device from the LCDC
-	 * driver, and passing ->info with HDMI platform data.
+	 * driver.
 	 */
-	if (info && !found) {
-		modelist = info->modelist.next &&
-			!list_empty(&info->modelist) ?
-			list_entry(info->modelist.next,
-				   struct fb_modelist, list) :
-			NULL;
-
-		if (modelist) {
-			found = &modelist->mode;
-			found_rate_error = sh_hdmi_rate_error(hdmi, found, hdmi_rate, parent_rate);
-		}
+	if (!found && hdmi->entity.def_mode.xres != 0) {
+		found = &hdmi->entity.def_mode;
+		found_rate_error = sh_hdmi_rate_error(hdmi, found, hdmi_rate,
+						      parent_rate);
 	}
 
 	/* No cookie today */
@@ -906,10 +899,11 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate,
 	else
 		hdmi->preprogrammed_vic = 0;
 
-	dev_dbg(hdmi->dev, "Using %s %s mode %ux%u@%uHz (%luHz), clock error %luHz\n",
-		modelist ? "default" : "EDID", hdmi->preprogrammed_vic ? "VIC" : "external",
-		found->xres, found->yres, found->refresh,
-		PICOS2KHZ(found->pixclock) * 1000, found_rate_error);
+	dev_dbg(hdmi->dev, "Using %s %s mode %ux%u@%uHz (%luHz), "
+		"clock error %luHz\n", use_edid_mode ? "EDID" : "default",
+		hdmi->preprogrammed_vic ? "VIC" : "external", found->xres,
+		found->yres, found->refresh, PICOS2KHZ(found->pixclock) * 1000,
+		found_rate_error);
 
 	hdmi->mode = *found;
 	sh_hdmi_external_video_param(hdmi);
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 4ec216e..c5acae7 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -1690,17 +1690,6 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
 	info->pseudo_palette = &ch->pseudo_palette;
 	info->flags = FBINFO_FLAG_DEFAULT;
 
-	if (cfg->tx_dev) {
-		if (!cfg->tx_dev->dev.driver ||
-		    !try_module_get(cfg->tx_dev->dev.driver->owner)) {
-			dev_warn(priv->dev, "unable to get transmitter "
-				 "device\n");
-			return -EINVAL;
-		}
-		ch->tx_dev = platform_get_drvdata(cfg->tx_dev);
-		ch->tx_dev->lcdc = ch;
-	}
-
 	/* Iterate through the modes to validate them and find the highest
 	 * resolution.
 	 */
@@ -1741,6 +1730,19 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
 
 	fb_videomode_to_modelist(mode, num_cfg, &info->modelist);
 
+	/* Initialize the transmitter device if present. */
+	if (cfg->tx_dev) {
+		if (!cfg->tx_dev->dev.driver ||
+		    !try_module_get(cfg->tx_dev->dev.driver->owner)) {
+			dev_warn(priv->dev, "unable to get transmitter "
+				 "device\n");
+			return -EINVAL;
+		}
+		ch->tx_dev = platform_get_drvdata(cfg->tx_dev);
+		ch->tx_dev->lcdc = ch;
+		ch->tx_dev->def_mode = *mode;
+	}
+
 	/* 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.
diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h
index 10086ae..9c91fae 100644
--- a/drivers/video/sh_mobile_lcdcfb.h
+++ b/drivers/video/sh_mobile_lcdcfb.h
@@ -40,6 +40,7 @@ struct sh_mobile_lcdc_entity {
 	struct module *owner;
 	const struct sh_mobile_lcdc_entity_ops *ops;
 	struct sh_mobile_lcdc_chan *lcdc;
+	struct fb_videomode def_mode;
 };
 
 /*
-- 
1.7.3.4


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox