From 7caa4342ca5b37d2d178b464c16badd4228b3b7b Mon Sep 17 00:00:00 2001 From: Damian Date: Wed, 18 May 2011 11:10:07 +0000 Subject: sh_mobile_meram: MERAM framework for LCDC Based on the patch by Takanari Hayama Adds support framework necessary to use Media RAM (MERAM) caching functionality with the LCDC. The MERAM is accessed through up to 4 Interconnect Buffers (ICBs). ICB numbers and MERAM address ranges to use are specified in by filling in the .meram_cfg member of the LCDC platform data Signed-off-by: Damian Hobson-Garcia Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_lcdcfb.c | 103 +++++++++++++++++++++++++++++++++++---- 1 file changed, 94 insertions(+), 9 deletions(-) (limited to 'drivers/video/sh_mobile_lcdcfb.c') diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 9bcc61b..3a2cbd1 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -27,6 +27,7 @@ #include #include "sh_mobile_lcdcfb.h" +#include "sh_mobile_meram.h" #define SIDE_B_OFFSET 0x1000 #define MIRROR_OFFSET 0x2000 @@ -143,6 +144,7 @@ struct sh_mobile_lcdc_priv { unsigned long saved_shared_regs[NR_SHARED_REGS]; int started; int forced_bpp; /* 2 channel LCDC must share bpp setting */ + struct sh_mobile_meram_info *meram_dev; }; static bool banked(int reg_nr) @@ -564,6 +566,9 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) } for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { + unsigned long base_addr_y; + unsigned long base_addr_c = 0; + int pitch; ch = &priv->ch[k]; if (!priv->ch[k].enabled) @@ -598,16 +603,63 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) } lcdc_write_chan(ch, LDDFR, tmp); + base_addr_y = ch->info->fix.smem_start; + base_addr_c = base_addr_y + + ch->info->var.xres * + ch->info->var.yres_virtual; + pitch = ch->info->fix.line_length; + + /* test if we can enable meram */ + if (ch->cfg.meram_cfg && priv->meram_dev) { + struct sh_mobile_meram_cfg *cfg; + struct sh_mobile_meram_info *mdev; + unsigned long icb_addr_y, icb_addr_c; + int icb_pitch; + int pf; + + cfg = ch->cfg.meram_cfg; + mdev = priv->meram_dev; + /* we need to de-init configured ICBs before we + * we can re-initialize them. + */ + if (ch->meram_enabled) + mdev->ops->meram_unregister(mdev, cfg); + + ch->meram_enabled = 0; + + if (ch->info->var.nonstd) + pf = SH_MOBILE_MERAM_PF_NV; + else + pf = SH_MOBILE_MERAM_PF_RGB; + + ret = mdev->ops->meram_register(mdev, cfg, pitch, + ch->info->var.yres, + pf, + base_addr_y, + base_addr_c, + &icb_addr_y, + &icb_addr_c, + &icb_pitch); + if (!ret) { + /* set LDSA1R value */ + base_addr_y = icb_addr_y; + pitch = icb_pitch; + + /* set LDSA2R value if required */ + if (base_addr_c) + base_addr_c = icb_addr_c; + + ch->meram_enabled = 1; + } + } + /* point out our frame buffer */ - lcdc_write_chan(ch, LDSA1R, ch->info->fix.smem_start); + lcdc_write_chan(ch, LDSA1R, base_addr_y); if (ch->info->var.nonstd) - lcdc_write_chan(ch, LDSA2R, - ch->info->fix.smem_start + - ch->info->var.xres * - ch->info->var.yres_virtual); + lcdc_write_chan(ch, LDSA2R, base_addr_c); /* set line size */ - lcdc_write_chan(ch, LDMLSR, ch->info->fix.line_length); + lcdc_write_chan(ch, LDMLSR, pitch); /* setup deferred io if SYS bus */ tmp = ch->cfg.sys_bus_cfg.deferred_io_msec; @@ -692,6 +744,17 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) board_cfg->display_off(board_cfg->board_data); module_put(board_cfg->owner); } + + /* disable the meram */ + if (ch->meram_enabled) { + struct sh_mobile_meram_cfg *cfg; + 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; + } + } /* stop the lcdc */ @@ -875,9 +938,29 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, } else base_addr_c = 0; - lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y); - if (base_addr_c) - lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c); + if (!ch->meram_enabled) { + lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y); + if (base_addr_c) + lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c); + } else { + struct sh_mobile_meram_cfg *cfg; + struct sh_mobile_meram_info *mdev; + unsigned long icb_addr_y, icb_addr_c; + int ret; + + cfg = ch->cfg.meram_cfg; + mdev = priv->meram_dev; + ret = mdev->ops->meram_update(mdev, cfg, + base_addr_y, base_addr_c, + &icb_addr_y, &icb_addr_c); + if (ret) + return ret; + + lcdc_write_chan_mirror(ch, LDSA1R, icb_addr_y); + if (icb_addr_c) + lcdc_write_chan_mirror(ch, LDSA2R, icb_addr_c); + + } if (lcdc_chan_is_sublcd(ch)) lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS); @@ -1420,6 +1503,8 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) goto err1; } + priv->meram_dev = pdata->meram_dev; + for (i = 0; i < j; i++) { struct fb_var_screeninfo *var; const struct fb_videomode *lcd_cfg, *max_cfg = NULL; -- cgit v1.1 From 3fedd2ac7662a10ab2973d3b6f11cdce87b7171a Mon Sep 17 00:00:00 2001 From: Damian Date: Wed, 18 May 2011 11:10:08 +0000 Subject: sh_mobile_meram: Add support for NV24 framebuffers Since the NV24 framebuffer has a CbCr plane that is twice as wide as the Y plane, it needs to be handled as a special case. Signed-off-by: Damian Hobson-Garcia Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_lcdcfb.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/video/sh_mobile_lcdcfb.c') diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 3a2cbd1..1c652da 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -627,10 +627,14 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) ch->meram_enabled = 0; - if (ch->info->var.nonstd) - pf = SH_MOBILE_MERAM_PF_NV; - else + if (ch->info->var.nonstd) { + if (ch->info->var.bits_per_pixel == 24) + pf = SH_MOBILE_MERAM_PF_NV24; + else + pf = SH_MOBILE_MERAM_PF_NV; + } else { pf = SH_MOBILE_MERAM_PF_RGB; + } ret = mdev->ops->meram_register(mdev, cfg, pitch, ch->info->var.yres, -- cgit v1.1 From 69843ba7f24950f8ef5dadacfbfbd08f53e3455b Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 5 May 2011 16:32:36 +0000 Subject: fbdev: sh_mobile_lcdc: reduce scope of a variable The "ret" variable in sh_mobile_lcdc_start() is only used at one location, move its definition to the inner-most scope. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_lcdcfb.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/video/sh_mobile_lcdcfb.c') diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 9bcc61b..466834c 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -469,7 +469,6 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) int bpp = 0; unsigned long ldddsr; int k, m; - int ret = 0; /* enable clocks before accessing the hardware */ for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { @@ -538,11 +537,12 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) lcdc_write_chan(ch, LDPMR, 0); board_cfg = &ch->cfg.board_cfg; - if (board_cfg->setup_sys) - ret = board_cfg->setup_sys(board_cfg->board_data, ch, - &sh_mobile_lcdc_sys_bus_ops); - if (ret) - return ret; + if (board_cfg->setup_sys) { + int ret = board_cfg->setup_sys(board_cfg->board_data, + ch, &sh_mobile_lcdc_sys_bus_ops); + if (ret) + return ret; + } } /* word and long word swap */ -- cgit v1.1 From ebe5e12d00f4785092a9650845ad3451bbf4b311 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 5 May 2011 16:33:40 +0000 Subject: fbdev: sh_mobile_lcdc: remove runtime PM calls from the notifier The notifier function calls sh_mobile_lcdc_stop() and sh_mobile_lcdc_start(), which already take care about the runtime PM state. Remove redundant calls. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_lcdcfb.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/video/sh_mobile_lcdcfb.c') diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 466834c..04f2260 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -1288,7 +1288,6 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb, struct fb_info *info = event->info; struct sh_mobile_lcdc_chan *ch = info->par; struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg; - int ret; if (&ch->lcdc->notifier != nb) return NOTIFY_DONE; @@ -1302,7 +1301,6 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb, board_cfg->display_off(board_cfg->board_data); module_put(board_cfg->owner); } - pm_runtime_put(info->device); sh_mobile_lcdc_stop(ch->lcdc); break; case FB_EVENT_RESUME: @@ -1316,9 +1314,7 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb, module_put(board_cfg->owner); } - ret = sh_mobile_lcdc_start(ch->lcdc); - if (!ret) - pm_runtime_get_sync(info->device); + sh_mobile_lcdc_start(ch->lcdc); } return NOTIFY_OK; -- cgit v1.1