* [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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 54/57] fbdev: sh_mobile_meram: Remove unneeded sanity checks
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
To: linux-fbdev
The meram_register(), meram_unregister() and meram_update() operations
check that the pointers they get from the caller are not NULL. Those
checks can be remove, as the caller already ensures that the pointers
are valid.
The platform sanity checks can also be removed, as the operations can't
be accessed without valid platform data anyway.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
drivers/video/sh_mobile_lcdcfb.c | 5 +----
drivers/video/sh_mobile_meram.c | 32 ++++++--------------------------
include/video/sh_mobile_meram.h | 15 +++++++--------
3 files changed, 14 insertions(+), 38 deletions(-)
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index e10a78a..edd195a 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -1070,14 +1070,11 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
if (ch->meram) {
struct sh_mobile_meram_info *mdev;
- int ret;
mdev = priv->meram_dev;
- ret = mdev->ops->meram_update(mdev, ch->meram,
+ mdev->ops->meram_update(mdev, ch->meram,
base_addr_y, base_addr_c,
&base_addr_y, &base_addr_c);
- if (ret)
- return ret;
}
ch->base_addr_y = base_addr_y;
diff --git a/drivers/video/sh_mobile_meram.c b/drivers/video/sh_mobile_meram.c
index aad8b0b..f0ae342 100644
--- a/drivers/video/sh_mobile_meram.c
+++ b/drivers/video/sh_mobile_meram.c
@@ -450,21 +450,15 @@ static void *sh_mobile_meram_register(struct sh_mobile_meram_info *pdata,
unsigned int *pitch)
{
struct sh_mobile_meram_fb_cache *cache;
- struct sh_mobile_meram_priv *priv;
- struct platform_device *pdev;
+ struct sh_mobile_meram_priv *priv = pdata->priv;
+ struct platform_device *pdev = pdata->pdev;
unsigned int out_pitch;
- if (!pdata || !pdata->priv || !pdata->pdev || !cfg)
- return ERR_PTR(-EINVAL);
-
if (pixelformat != SH_MOBILE_MERAM_PF_NV &&
pixelformat != SH_MOBILE_MERAM_PF_NV24 &&
pixelformat != SH_MOBILE_MERAM_PF_RGB)
return ERR_PTR(-EINVAL);
- priv = pdata->priv;
- pdev = pdata->pdev;
-
dev_dbg(&pdev->dev, "registering %dx%d (%s)", xres, yres,
!pixelformat ? "yuv" : "rgb");
@@ -499,16 +493,11 @@ err:
return cache;
}
-static int
+static void
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;
-
- if (!pdata || !pdata->priv || !data)
- return -EINVAL;
-
- priv = pdata->priv;
+ struct sh_mobile_meram_priv *priv = pdata->priv;
mutex_lock(&priv->lock);
@@ -520,22 +509,15 @@ sh_mobile_meram_unregister(struct sh_mobile_meram_info *pdata, void *data)
meram_free(priv, cache);
mutex_unlock(&priv->lock);
-
- return 0;
}
-static int
+static void
sh_mobile_meram_update(struct sh_mobile_meram_info *pdata, void *data,
unsigned long base_addr_y, unsigned long base_addr_c,
unsigned long *icb_addr_y, unsigned long *icb_addr_c)
{
struct sh_mobile_meram_fb_cache *cache = data;
- struct sh_mobile_meram_priv *priv;
-
- if (!pdata || !pdata->priv || !data)
- return -EINVAL;
-
- priv = pdata->priv;
+ struct sh_mobile_meram_priv *priv = pdata->priv;
mutex_lock(&priv->lock);
@@ -543,8 +525,6 @@ sh_mobile_meram_update(struct sh_mobile_meram_info *pdata, void *data,
meram_get_next_icb_addr(pdata, cache, icb_addr_y, icb_addr_c);
mutex_unlock(&priv->lock);
-
- return 0;
}
static struct sh_mobile_meram_ops sh_mobile_meram_ops = {
diff --git a/include/video/sh_mobile_meram.h b/include/video/sh_mobile_meram.h
index 51c98ca..089e6d3 100644
--- a/include/video/sh_mobile_meram.h
+++ b/include/video/sh_mobile_meram.h
@@ -44,16 +44,15 @@ struct sh_mobile_meram_ops {
unsigned int *pitch);
/* unregister usage of meram */
- int (*meram_unregister)(struct sh_mobile_meram_info *meram_dev,
- void *data);
+ void (*meram_unregister)(struct sh_mobile_meram_info *meram_dev,
+ void *data);
/* update meram settings */
- int (*meram_update)(struct sh_mobile_meram_info *meram_dev,
- void *data,
- unsigned long base_addr_y,
- unsigned long base_addr_c,
- unsigned long *icb_addr_y,
- unsigned long *icb_addr_c);
+ void (*meram_update)(struct sh_mobile_meram_info *meram_dev, void *data,
+ unsigned long base_addr_y,
+ unsigned long base_addr_c,
+ unsigned long *icb_addr_y,
+ unsigned long *icb_addr_c);
};
#endif /* __VIDEO_SH_MOBILE_MERAM_H__ */
--
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