* [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
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox