From 4a2371772146b30113c9c837eb32b64f18376c0d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 15 Mar 2012 12:40:47 +0100 Subject: sh_mobile_meram: Rename operations to cache_[alloc|free|update] The MERAM operations meram_register, meram_unregister and meram_update handle LCDC cache. In preparation for "raw" MERAM allocation, rename them to more appropriate names. Signed-off-by: Laurent Pinchart --- drivers/video/sh_mobile_lcdcfb.c | 32 ++++--- drivers/video/sh_mobile_lcdcfb.h | 2 +- drivers/video/sh_mobile_meram.c | 176 +++++++++++++++++++-------------------- 3 files changed, 102 insertions(+), 108 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 98e81b31fbc4..e593e8188720 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -1104,7 +1104,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) /* Compute frame buffer base address and pitch for each channel. */ for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { int pixelformat; - void *meram; + void *cache; ch = &priv->ch[k]; if (!ch->enabled) @@ -1119,12 +1119,10 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) ch->cfg->meram_cfg == NULL) continue; - /* we need to de-init configured ICBs before we can - * re-initialize them. - */ - if (ch->meram) { - mdev->ops->meram_unregister(mdev, ch->meram); - ch->meram = NULL; + /* Free the allocated MERAM cache. */ + if (ch->cache) { + mdev->ops->cache_free(mdev, ch->cache); + ch->cache = NULL; } switch (ch->format->fourcc) { @@ -1146,14 +1144,14 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) break; } - meram = mdev->ops->meram_register(mdev, ch->cfg->meram_cfg, + cache = mdev->ops->cache_alloc(mdev, ch->cfg->meram_cfg, ch->pitch, ch->yres, pixelformat, &ch->line_size); - if (!IS_ERR(meram)) { - mdev->ops->meram_update(mdev, meram, + if (!IS_ERR(cache)) { + mdev->ops->cache_update(mdev, cache, ch->base_addr_y, ch->base_addr_c, &ch->base_addr_y, &ch->base_addr_c); - ch->meram = meram; + ch->cache = cache; } } @@ -1223,12 +1221,12 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) sh_mobile_lcdc_display_off(ch); - /* disable the meram */ - if (ch->meram) { + /* Free the MERAM cache. */ + if (ch->cache) { struct sh_mobile_meram_info *mdev; mdev = priv->meram_dev; - mdev->ops->meram_unregister(mdev, ch->meram); - ch->meram = 0; + mdev->ops->cache_free(mdev, ch->cache); + ch->cache = 0; } } @@ -1839,11 +1837,11 @@ static int sh_mobile_lcdc_pan(struct fb_var_screeninfo *var, base_addr_c += var->xoffset; } - if (ch->meram) { + if (ch->cache) { struct sh_mobile_meram_info *mdev; mdev = priv->meram_dev; - mdev->ops->meram_update(mdev, ch->meram, + mdev->ops->cache_update(mdev, ch->cache, base_addr_y, base_addr_c, &base_addr_y, &base_addr_c); } diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h index 5c3bddd2cb72..e53cd1171072 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 */ - void *meram; + void *cache; 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 82ba830bf95d..4aa3fcb87f17 100644 --- a/drivers/video/sh_mobile_meram.c +++ b/drivers/video/sh_mobile_meram.c @@ -194,13 +194,13 @@ static inline unsigned long meram_read_reg(void __iomem *base, unsigned int off) } /* ----------------------------------------------------------------------------- - * Allocation + * LCDC cache planes allocation, init, cleanup and free */ /* Allocate ICBs and MERAM for a plane. */ -static int __meram_alloc(struct sh_mobile_meram_priv *priv, - struct sh_mobile_meram_fb_plane *plane, - size_t size) +static int meram_plane_alloc(struct sh_mobile_meram_priv *priv, + struct sh_mobile_meram_fb_plane *plane, + size_t size) { unsigned long mem; unsigned long idx; @@ -229,8 +229,8 @@ static int __meram_alloc(struct sh_mobile_meram_priv *priv, } /* Free ICBs and MERAM for a plane. */ -static void __meram_free(struct sh_mobile_meram_priv *priv, - struct sh_mobile_meram_fb_plane *plane) +static void meram_plane_free(struct sh_mobile_meram_priv *priv, + struct sh_mobile_meram_fb_plane *plane) { gen_pool_free(priv->pool, priv->meram + plane->marker->offset, plane->marker->size * 1024); @@ -248,62 +248,6 @@ static int is_nvcolor(int cspace) return 0; } -/* Allocate memory for the ICBs and mark them as used. */ -static struct sh_mobile_meram_fb_cache * -meram_alloc(struct sh_mobile_meram_priv *priv, - const struct sh_mobile_meram_cfg *cfg, - int pixelformat) -{ - struct sh_mobile_meram_fb_cache *cache; - unsigned int nplanes = is_nvcolor(pixelformat) ? 2 : 1; - int ret; - - if (cfg->icb[0].meram_size == 0) - return ERR_PTR(-EINVAL); - - if (nplanes == 2 && cfg->icb[1].meram_size == 0) - return ERR_PTR(-EINVAL); - - cache = kzalloc(sizeof(*cache), GFP_KERNEL); - if (cache == NULL) - return ERR_PTR(-ENOMEM); - - cache->nplanes = nplanes; - - ret = __meram_alloc(priv, &cache->planes[0], cfg->icb[0].meram_size); - if (ret < 0) - goto error; - - cache->planes[0].marker->current_reg = 1; - cache->planes[0].marker->pixelformat = pixelformat; - - if (cache->nplanes == 1) - return cache; - - ret = __meram_alloc(priv, &cache->planes[1], cfg->icb[1].meram_size); - if (ret < 0) { - __meram_free(priv, &cache->planes[0]); - goto error; - } - - return cache; - -error: - kfree(cache); - return ERR_PTR(-ENOMEM); -} - -/* Unmark the specified ICB as used. */ -static void meram_free(struct sh_mobile_meram_priv *priv, - struct sh_mobile_meram_fb_cache *cache) -{ - __meram_free(priv, &cache->planes[0]); - if (cache->nplanes == 2) - __meram_free(priv, &cache->planes[1]); - - kfree(cache); -} - /* Set the next address to fetch. */ static void meram_set_next_addr(struct sh_mobile_meram_priv *priv, struct sh_mobile_meram_fb_cache *cache, @@ -355,10 +299,10 @@ meram_get_next_icb_addr(struct sh_mobile_meram_info *pdata, (((x) * (y) + (MERAM_LINE_WIDTH - 1)) & ~(MERAM_LINE_WIDTH - 1)) /* Initialize MERAM. */ -static int meram_init(struct sh_mobile_meram_priv *priv, - struct sh_mobile_meram_fb_plane *plane, - unsigned int xres, unsigned int yres, - unsigned int *out_pitch) +static int meram_plane_init(struct sh_mobile_meram_priv *priv, + struct sh_mobile_meram_fb_plane *plane, + unsigned int xres, unsigned int yres, + unsigned int *out_pitch) { struct sh_mobile_meram_icb *marker = plane->marker; unsigned long total_byte_count = MERAM_CALC_BYTECOUNT(xres, yres); @@ -427,8 +371,8 @@ static int meram_init(struct sh_mobile_meram_priv *priv, return 0; } -static void meram_deinit(struct sh_mobile_meram_priv *priv, - struct sh_mobile_meram_fb_plane *plane) +static void meram_plane_cleanup(struct sh_mobile_meram_priv *priv, + struct sh_mobile_meram_fb_plane *plane) { /* disable ICB */ meram_write_icb(priv->base, plane->cache->index, MExxCTL, @@ -441,18 +385,60 @@ static void meram_deinit(struct sh_mobile_meram_priv *priv, } /* ----------------------------------------------------------------------------- - * Registration/unregistration + * LCDC cache operations */ -static void *sh_mobile_meram_register(struct sh_mobile_meram_info *pdata, - const struct sh_mobile_meram_cfg *cfg, - unsigned int xres, unsigned int yres, - unsigned int pixelformat, - unsigned int *pitch) +/* Allocate memory for the ICBs and mark them as used. */ +static struct sh_mobile_meram_fb_cache * +meram_cache_alloc(struct sh_mobile_meram_priv *priv, + const struct sh_mobile_meram_cfg *cfg, + int pixelformat) +{ + unsigned int nplanes = is_nvcolor(pixelformat) ? 2 : 1; + struct sh_mobile_meram_fb_cache *cache; + int ret; + + cache = kzalloc(sizeof(*cache), GFP_KERNEL); + if (cache == NULL) + return ERR_PTR(-ENOMEM); + + cache->nplanes = nplanes; + + ret = meram_plane_alloc(priv, &cache->planes[0], + cfg->icb[0].meram_size); + if (ret < 0) + goto error; + + cache->planes[0].marker->current_reg = 1; + cache->planes[0].marker->pixelformat = pixelformat; + + if (cache->nplanes == 1) + return cache; + + ret = meram_plane_alloc(priv, &cache->planes[1], + cfg->icb[1].meram_size); + if (ret < 0) { + meram_plane_free(priv, &cache->planes[0]); + goto error; + } + + return cache; + +error: + kfree(cache); + return ERR_PTR(-ENOMEM); +} + +static void *sh_mobile_cache_alloc(struct sh_mobile_meram_info *pdata, + const struct sh_mobile_meram_cfg *cfg, + unsigned int xres, unsigned int yres, + unsigned int pixelformat, + unsigned int *pitch) { struct sh_mobile_meram_fb_cache *cache; struct sh_mobile_meram_priv *priv = pdata->priv; struct platform_device *pdev = pdata->pdev; + unsigned int nplanes = is_nvcolor(pixelformat) ? 2 : 1; unsigned int out_pitch; if (pixelformat != SH_MOBILE_MERAM_PF_NV && @@ -469,10 +455,16 @@ static void *sh_mobile_meram_register(struct sh_mobile_meram_info *pdata, return ERR_PTR(-EINVAL); } + if (cfg->icb[0].meram_size == 0) + return ERR_PTR(-EINVAL); + + if (nplanes == 2 && cfg->icb[1].meram_size == 0) + return ERR_PTR(-EINVAL); + mutex_lock(&priv->lock); /* We now register the ICBs and allocate the MERAM regions. */ - cache = meram_alloc(priv, cfg, pixelformat); + cache = meram_cache_alloc(priv, cfg, pixelformat); if (IS_ERR(cache)) { dev_err(&pdev->dev, "MERAM allocation failed (%ld).", PTR_ERR(cache)); @@ -480,14 +472,14 @@ static void *sh_mobile_meram_register(struct sh_mobile_meram_info *pdata, } /* initialize MERAM */ - meram_init(priv, &cache->planes[0], xres, yres, &out_pitch); + meram_plane_init(priv, &cache->planes[0], xres, yres, &out_pitch); *pitch = out_pitch; if (pixelformat == SH_MOBILE_MERAM_PF_NV) - meram_init(priv, &cache->planes[1], xres, (yres + 1) / 2, - &out_pitch); + meram_plane_init(priv, &cache->planes[1], + xres, (yres + 1) / 2, &out_pitch); else if (pixelformat == SH_MOBILE_MERAM_PF_NV24) - meram_init(priv, &cache->planes[1], 2 * xres, (yres + 1) / 2, - &out_pitch); + meram_plane_init(priv, &cache->planes[1], + 2 * xres, (yres + 1) / 2, &out_pitch); err: mutex_unlock(&priv->lock); @@ -495,25 +487,29 @@ err: } static void -sh_mobile_meram_unregister(struct sh_mobile_meram_info *pdata, void *data) +sh_mobile_cache_free(struct sh_mobile_meram_info *pdata, void *data) { struct sh_mobile_meram_fb_cache *cache = data; struct sh_mobile_meram_priv *priv = pdata->priv; mutex_lock(&priv->lock); - /* deinit & free */ - meram_deinit(priv, &cache->planes[0]); - if (cache->nplanes == 2) - meram_deinit(priv, &cache->planes[1]); + /* Cleanup and free. */ + meram_plane_cleanup(priv, &cache->planes[0]); + meram_plane_free(priv, &cache->planes[0]); - meram_free(priv, cache); + if (cache->nplanes == 2) { + meram_plane_cleanup(priv, &cache->planes[1]); + meram_plane_free(priv, &cache->planes[1]); + } + + kfree(cache); mutex_unlock(&priv->lock); } static void -sh_mobile_meram_update(struct sh_mobile_meram_info *pdata, void *data, +sh_mobile_cache_update(struct sh_mobile_meram_info *pdata, void *data, unsigned long base_addr_y, unsigned long base_addr_c, unsigned long *icb_addr_y, unsigned long *icb_addr_c) { @@ -530,9 +526,9 @@ sh_mobile_meram_update(struct sh_mobile_meram_info *pdata, void *data, 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, + .cache_alloc = sh_mobile_cache_alloc, + .cache_free = sh_mobile_cache_free, + .cache_update = sh_mobile_cache_update, }; /* ----------------------------------------------------------------------------- -- cgit v1.2.3 From 6e729b416b44296f5ed503b40ac58c2bffb43caf Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 15 Mar 2012 12:40:47 +0100 Subject: sh_mobile_meram: Use direct function calls for the public API There's no reason to use abstract operation pointers to implement the MERAM API. Replace them by direct function calls. Signed-off-by: Laurent Pinchart --- drivers/video/sh_mobile_lcdcfb.c | 27 ++++++++++----------------- drivers/video/sh_mobile_meram.c | 40 ++++++++++++++++++++-------------------- 2 files changed, 30 insertions(+), 37 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index e593e8188720..9da4b1b619e6 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -1115,13 +1115,12 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) ch->line_size = ch->pitch; /* Enable MERAM if possible. */ - if (mdev == NULL || mdev->ops == NULL || - ch->cfg->meram_cfg == NULL) + if (mdev == NULL || ch->cfg->meram_cfg == NULL) continue; /* Free the allocated MERAM cache. */ if (ch->cache) { - mdev->ops->cache_free(mdev, ch->cache); + sh_mobile_meram_cache_free(mdev, ch->cache); ch->cache = NULL; } @@ -1144,11 +1143,11 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) break; } - cache = mdev->ops->cache_alloc(mdev, ch->cfg->meram_cfg, + cache = sh_mobile_meram_cache_alloc(mdev, ch->cfg->meram_cfg, ch->pitch, ch->yres, pixelformat, &ch->line_size); if (!IS_ERR(cache)) { - mdev->ops->cache_update(mdev, cache, + sh_mobile_meram_cache_update(mdev, cache, ch->base_addr_y, ch->base_addr_c, &ch->base_addr_y, &ch->base_addr_c); ch->cache = cache; @@ -1223,9 +1222,7 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) /* Free the MERAM cache. */ if (ch->cache) { - struct sh_mobile_meram_info *mdev; - mdev = priv->meram_dev; - mdev->ops->cache_free(mdev, ch->cache); + sh_mobile_meram_cache_free(priv->meram_dev, ch->cache); ch->cache = 0; } @@ -1808,7 +1805,7 @@ static int sh_mobile_lcdc_pan(struct fb_var_screeninfo *var, struct sh_mobile_lcdc_priv *priv = ch->lcdc; unsigned long ldrcntr; unsigned long new_pan_offset; - unsigned long base_addr_y, base_addr_c; + unsigned long base_addr_y, base_addr_c = 0; unsigned long c_offset; if (!ch->format->yuv) @@ -1837,14 +1834,10 @@ static int sh_mobile_lcdc_pan(struct fb_var_screeninfo *var, base_addr_c += var->xoffset; } - if (ch->cache) { - struct sh_mobile_meram_info *mdev; - - mdev = priv->meram_dev; - mdev->ops->cache_update(mdev, ch->cache, - base_addr_y, base_addr_c, - &base_addr_y, &base_addr_c); - } + if (ch->cache) + sh_mobile_meram_cache_update(priv->meram_dev, ch->cache, + base_addr_y, base_addr_c, + &base_addr_y, &base_addr_c); ch->base_addr_y = base_addr_y; ch->base_addr_c = base_addr_c; diff --git a/drivers/video/sh_mobile_meram.c b/drivers/video/sh_mobile_meram.c index 4aa3fcb87f17..fdb6fc1decb0 100644 --- a/drivers/video/sh_mobile_meram.c +++ b/drivers/video/sh_mobile_meram.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -429,11 +430,10 @@ error: return ERR_PTR(-ENOMEM); } -static void *sh_mobile_cache_alloc(struct sh_mobile_meram_info *pdata, - const struct sh_mobile_meram_cfg *cfg, - unsigned int xres, unsigned int yres, - unsigned int pixelformat, - unsigned int *pitch) +void *sh_mobile_meram_cache_alloc(struct sh_mobile_meram_info *pdata, + const struct sh_mobile_meram_cfg *cfg, + unsigned int xres, unsigned int yres, + unsigned int pixelformat, unsigned int *pitch) { struct sh_mobile_meram_fb_cache *cache; struct sh_mobile_meram_priv *priv = pdata->priv; @@ -441,6 +441,9 @@ static void *sh_mobile_cache_alloc(struct sh_mobile_meram_info *pdata, unsigned int nplanes = is_nvcolor(pixelformat) ? 2 : 1; unsigned int out_pitch; + if (priv == NULL) + return ERR_PTR(-ENODEV); + if (pixelformat != SH_MOBILE_MERAM_PF_NV && pixelformat != SH_MOBILE_MERAM_PF_NV24 && pixelformat != SH_MOBILE_MERAM_PF_RGB) @@ -485,9 +488,10 @@ err: mutex_unlock(&priv->lock); return cache; } +EXPORT_SYMBOL_GPL(sh_mobile_meram_cache_alloc); -static void -sh_mobile_cache_free(struct sh_mobile_meram_info *pdata, void *data) +void +sh_mobile_meram_cache_free(struct sh_mobile_meram_info *pdata, void *data) { struct sh_mobile_meram_fb_cache *cache = data; struct sh_mobile_meram_priv *priv = pdata->priv; @@ -507,11 +511,14 @@ sh_mobile_cache_free(struct sh_mobile_meram_info *pdata, void *data) mutex_unlock(&priv->lock); } - -static void -sh_mobile_cache_update(struct sh_mobile_meram_info *pdata, void *data, - unsigned long base_addr_y, unsigned long base_addr_c, - unsigned long *icb_addr_y, unsigned long *icb_addr_c) +EXPORT_SYMBOL_GPL(sh_mobile_meram_cache_free); + +void +sh_mobile_meram_cache_update(struct sh_mobile_meram_info *pdata, void *data, + unsigned long base_addr_y, + unsigned long base_addr_c, + unsigned long *icb_addr_y, + unsigned long *icb_addr_c) { struct sh_mobile_meram_fb_cache *cache = data; struct sh_mobile_meram_priv *priv = pdata->priv; @@ -523,13 +530,7 @@ sh_mobile_cache_update(struct sh_mobile_meram_info *pdata, void *data, mutex_unlock(&priv->lock); } - -static struct sh_mobile_meram_ops sh_mobile_meram_ops = { - .module = THIS_MODULE, - .cache_alloc = sh_mobile_cache_alloc, - .cache_free = sh_mobile_cache_free, - .cache_update = sh_mobile_cache_update, -}; +EXPORT_SYMBOL_GPL(sh_mobile_meram_cache_update); /* ----------------------------------------------------------------------------- * Power management @@ -620,7 +621,6 @@ static int __devinit sh_mobile_meram_probe(struct platform_device *pdev) for (i = 0; i < MERAM_ICB_NUM; ++i) priv->icbs[i].index = i; - pdata->ops = &sh_mobile_meram_ops; pdata->priv = priv; pdata->pdev = pdev; -- cgit v1.2.3 From 239921ec1d969e904676f444a92e6d68a928d98c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 15 Mar 2012 13:18:17 +0100 Subject: sh_mobile_meram: Add direct MERAM allocation API The API can be used to allocate and free MERAM blocks directly, without going through ICBs. Signed-off-by: Laurent Pinchart --- drivers/video/sh_mobile_meram.c | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/sh_mobile_meram.c b/drivers/video/sh_mobile_meram.c index fdb6fc1decb0..7a0ba8bb3fbe 100644 --- a/drivers/video/sh_mobile_meram.c +++ b/drivers/video/sh_mobile_meram.c @@ -194,6 +194,21 @@ static inline unsigned long meram_read_reg(void __iomem *base, unsigned int off) return ioread32(base + off); } +/* ----------------------------------------------------------------------------- + * MERAM allocation and free + */ + +static unsigned long meram_alloc(struct sh_mobile_meram_priv *priv, size_t size) +{ + return gen_pool_alloc(priv->pool, size); +} + +static void meram_free(struct sh_mobile_meram_priv *priv, unsigned long mem, + size_t size) +{ + gen_pool_free(priv->pool, mem, size); +} + /* ----------------------------------------------------------------------------- * LCDC cache planes allocation, init, cleanup and free */ @@ -216,7 +231,7 @@ static int meram_plane_alloc(struct sh_mobile_meram_priv *priv, return -ENOMEM; plane->marker = &priv->icbs[idx]; - mem = gen_pool_alloc(priv->pool, size * 1024); + mem = meram_alloc(priv, size * 1024); if (mem == 0) return -ENOMEM; @@ -233,8 +248,8 @@ static int meram_plane_alloc(struct sh_mobile_meram_priv *priv, static void meram_plane_free(struct sh_mobile_meram_priv *priv, struct sh_mobile_meram_fb_plane *plane) { - gen_pool_free(priv->pool, priv->meram + plane->marker->offset, - plane->marker->size * 1024); + meram_free(priv, priv->meram + plane->marker->offset, + plane->marker->size * 1024); __clear_bit(plane->marker->index, &priv->used_icb); __clear_bit(plane->cache->index, &priv->used_icb); @@ -386,9 +401,27 @@ static void meram_plane_cleanup(struct sh_mobile_meram_priv *priv, } /* ----------------------------------------------------------------------------- - * LCDC cache operations + * MERAM operations */ +unsigned long sh_mobile_meram_alloc(struct sh_mobile_meram_info *pdata, + size_t size) +{ + struct sh_mobile_meram_priv *priv = pdata->priv; + + return meram_alloc(priv, size); +} +EXPORT_SYMBOL_GPL(sh_mobile_meram_alloc); + +void sh_mobile_meram_free(struct sh_mobile_meram_info *pdata, unsigned long mem, + size_t size) +{ + struct sh_mobile_meram_priv *priv = pdata->priv; + + meram_free(priv, mem, size); +} +EXPORT_SYMBOL_GPL(sh_mobile_meram_free); + /* Allocate memory for the ICBs and mark them as used. */ static struct sh_mobile_meram_fb_cache * meram_cache_alloc(struct sh_mobile_meram_priv *priv, -- cgit v1.2.3 From 0c75c4e073a8ec35bfd6c8adcceb2b896f2063e2 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 15 Mar 2012 18:34:05 +0100 Subject: fbdev: sh_mobile_lcdc: Destroy mutex at remove time Add a missing mutex_destroy() call when the driver is unbound from the device. Signed-off-by: Laurent Pinchart --- drivers/video/sh_mobile_lcdcfb.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 9da4b1b619e6..644c2309a49a 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -2444,8 +2444,11 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev) } for (i = 0; i < ARRAY_SIZE(priv->ch); i++) { - if (priv->ch[i].bl) - sh_mobile_lcdc_bl_remove(priv->ch[i].bl); + struct sh_mobile_lcdc_chan *ch = &priv->ch[i]; + + if (ch->bl) + sh_mobile_lcdc_bl_remove(ch->bl); + mutex_destroy(&ch->open_lock); } if (priv->dot_clk) { -- cgit v1.2.3 From 16ca21c9a9f64577221c47d8d2f00d13b880aefa Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 18 Jul 2012 16:29:20 +0200 Subject: fbdev: sh_mobile_lcdc: Fix line pitch computation Line pitch depends on the virtual horizontal resolution, compute it accordingly. Signed-off-by: Laurent Pinchart --- drivers/video/sh_mobile_lcdcfb.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 644c2309a49a..67877ccadacb 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -1580,9 +1580,9 @@ static int sh_mobile_lcdc_overlay_set_par(struct fb_info *info) ovl->yres_virtual = info->var.yres_virtual; if (ovl->format->yuv) - ovl->pitch = info->var.xres; + ovl->pitch = info->var.xres_virtual; else - ovl->pitch = info->var.xres * ovl->format->bpp / 8; + ovl->pitch = info->var.xres_virtual * ovl->format->bpp / 8; sh_mobile_lcdc_overlay_setup(ovl); @@ -2024,9 +2024,9 @@ static int sh_mobile_lcdc_set_par(struct fb_info *info) ch->yres_virtual = info->var.yres_virtual; if (ch->format->yuv) - ch->pitch = info->var.xres; + ch->pitch = info->var.xres_virtual; else - ch->pitch = info->var.xres * ch->format->bpp / 8; + ch->pitch = info->var.xres_virtual * ch->format->bpp / 8; ret = sh_mobile_lcdc_start(ch->lcdc); if (ret < 0) @@ -2539,9 +2539,9 @@ sh_mobile_lcdc_overlay_init(struct sh_mobile_lcdc_priv *priv, ovl->yres_virtual = ovl->yres * 2; if (!format->yuv) - ovl->pitch = ovl->xres * format->bpp / 8; + ovl->pitch = ovl->xres_virtual * format->bpp / 8; else - ovl->pitch = ovl->xres; + ovl->pitch = ovl->xres_virtual; /* Allocate frame buffer memory. */ ovl->fb_size = ovl->cfg->max_xres * ovl->cfg->max_yres @@ -2628,10 +2628,10 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv, if (!format->yuv) { ch->colorspace = V4L2_COLORSPACE_SRGB; - ch->pitch = ch->xres * format->bpp / 8; + ch->pitch = ch->xres_virtual * format->bpp / 8; } else { ch->colorspace = V4L2_COLORSPACE_REC709; - ch->pitch = ch->xres; + ch->pitch = ch->xres_virtual; } ch->display.width = cfg->panel_cfg.width; -- cgit v1.2.3 From bd5f2c6911c210af52fa4dc4cf504043ff8a4971 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 18 Jul 2012 16:59:16 +0200 Subject: fbdev: sh_mobile_lcdc: Use channel configuration to initialize fb device Copy the x and y virtual resolutions from the channel information instead of recomputing them. Signed-off-by: Laurent Pinchart --- drivers/video/sh_mobile_lcdcfb.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 67877ccadacb..68011b5596c5 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -2214,14 +2214,14 @@ sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch, 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. + * default. */ var = &info->var; fb_videomode_to_var(var, mode); var->width = ch->cfg->panel_cfg.width; var->height = ch->cfg->panel_cfg.height; - var->yres_virtual = var->yres * 2; + var->xres_virtual = ch->xres_virtual; + var->yres_virtual = ch->yres_virtual; var->activate = FB_ACTIVATE_NOW; /* Use the legacy API by default for RGB formats, and the FOURCC API @@ -2619,7 +2619,9 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv, num_modes = cfg->num_modes; } - /* Use the first mode as default. */ + /* Use the first mode as default. The default Y virtual resolution is + * twice the panel size to allow for double-buffering. + */ ch->format = format; ch->xres = mode->xres; ch->xres_virtual = mode->xres; -- cgit v1.2.3 From 15dede882e564601947f2ce4b647742c0351be6d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 18 Jul 2012 17:09:04 +0200 Subject: fbdev: sh_mobile_lcdc: Support horizontal panning Signed-off-by: Laurent Pinchart --- drivers/video/sh_mobile_lcdcfb.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 68011b5596c5..d82c1dedc467 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -1493,7 +1493,7 @@ static const struct fb_fix_screeninfo sh_mobile_lcdc_overlay_fix = { .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_TRUECOLOR, .accel = FB_ACCEL_NONE, - .xpanstep = 0, + .xpanstep = 1, .ypanstep = 1, .ywrapstep = 0, .capabilities = FB_CAP_FOURCC, @@ -1714,9 +1714,14 @@ sh_mobile_lcdc_overlay_fb_init(struct sh_mobile_lcdc_overlay *ovl) else info->fix.visual = FB_VISUAL_TRUECOLOR; - if (ovl->format->fourcc == V4L2_PIX_FMT_NV12 || - ovl->format->fourcc == V4L2_PIX_FMT_NV21) + switch (ovl->format->fourcc) { + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: info->fix.ypanstep = 2; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + info->fix.xpanstep = 2; + } /* Initialize variable screen information. */ var = &info->var; @@ -1771,7 +1776,7 @@ static const struct fb_fix_screeninfo sh_mobile_lcdc_fix = { .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_TRUECOLOR, .accel = FB_ACCEL_NONE, - .xpanstep = 0, + .xpanstep = 1, .ypanstep = 1, .ywrapstep = 0, .capabilities = FB_CAP_FOURCC, @@ -2209,9 +2214,14 @@ sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch, else info->fix.visual = FB_VISUAL_TRUECOLOR; - if (ch->format->fourcc == V4L2_PIX_FMT_NV12 || - ch->format->fourcc == V4L2_PIX_FMT_NV21) + switch (ch->format->fourcc) { + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: info->fix.ypanstep = 2; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + info->fix.xpanstep = 2; + } /* Initialize variable screen information using the first mode as * default. -- cgit v1.2.3 From 8be7c66995bf06769dc4c5f7a62f3cd62a627e7e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 19 Jul 2012 02:29:52 +0200 Subject: fbdev: sh_mobile_lcdc: Fix overlay registers update during pan operation Updating overlay registers require switching to overlay update mode. This was correctly done when configuring the overlay format and size, but not when updating the base address registers during pan operation. Fix it. Signed-off-by: Laurent Pinchart --- drivers/video/sh_mobile_lcdcfb.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/video') diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index d82c1dedc467..a5027099fb4c 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -1539,9 +1539,14 @@ static int sh_mobile_lcdc_overlay_pan(struct fb_var_screeninfo *var, ovl->base_addr_c = base_addr_c; } + lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index)); + lcdc_write_overlay(ovl, LDBnBSAYR(ovl->index), ovl->base_addr_y); lcdc_write_overlay(ovl, LDBnBSACR(ovl->index), ovl->base_addr_c); + lcdc_write(ovl->channel->lcdc, LDBCR, + LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index)); + ovl->pan_offset = pan_offset; return 0; -- cgit v1.2.3 From a4aa25f6e7885a42c90fe5f0a965403df6cbc943 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 15 Mar 2012 18:15:37 +0100 Subject: fbdev: sh_mobile_lcdc: Fix pan offset computation in YUV mode The chroma plane offset in memory is equal to the luma plane maximum size. Fix offset computations. Signed-off-by: Laurent Pinchart --- drivers/video/sh_mobile_lcdcfb.c | 110 ++++++++++++++++++--------------------- drivers/video/sh_mobile_lcdcfb.h | 3 +- 2 files changed, 54 insertions(+), 59 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index a5027099fb4c..8cb653b107cc 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -161,7 +161,7 @@ enum sh_mobile_lcdc_overlay_mode { * @dma_handle: Frame buffer DMA address * @base_addr_y: Overlay base address (RGB or luma component) * @base_addr_c: Overlay base address (chroma component) - * @pan_offset: Current pan offset in bytes + * @pan_y_offset: Panning linear offset in bytes (luma component) * @format: Current pixelf format * @xres: Horizontal visible resolution * @xres_virtual: Horizontal total resolution @@ -191,7 +191,7 @@ struct sh_mobile_lcdc_overlay { dma_addr_t dma_handle; unsigned long base_addr_y; unsigned long base_addr_c; - unsigned long pan_offset; + unsigned long pan_y_offset; const struct sh_mobile_lcdc_format_info *format; unsigned int xres; @@ -873,8 +873,8 @@ static void sh_mobile_lcdc_overlay_setup(struct sh_mobile_lcdc_overlay *ovl) } ovl->base_addr_y = ovl->dma_handle; - ovl->base_addr_c = ovl->base_addr_y + ovl->xres - * ovl->yres_virtual; + ovl->base_addr_c = ovl->dma_handle + + ovl->xres_virtual * ovl->yres_virtual; switch (ovl->mode) { case LCDC_OVERLAY_BLEND: @@ -1111,7 +1111,8 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) continue; ch->base_addr_y = ch->dma_handle; - ch->base_addr_c = ch->base_addr_y + ch->xres * ch->yres_virtual; + ch->base_addr_c = ch->dma_handle + + ch->xres_virtual * ch->yres_virtual; ch->line_size = ch->pitch; /* Enable MERAM if possible. */ @@ -1505,39 +1506,36 @@ static int sh_mobile_lcdc_overlay_pan(struct fb_var_screeninfo *var, struct sh_mobile_lcdc_overlay *ovl = info->par; unsigned long base_addr_y; unsigned long base_addr_c; - unsigned long pan_offset; + unsigned long y_offset; unsigned long c_offset; - if (!ovl->format->yuv) - pan_offset = var->yoffset * ovl->pitch - + var->xoffset * (ovl->format->bpp / 8); - else - pan_offset = var->yoffset * ovl->pitch + var->xoffset; + if (!ovl->format->yuv) { + y_offset = (var->yoffset * ovl->xres_virtual + var->xoffset) + * ovl->format->bpp / 8; + c_offset = 0; + } else { + unsigned int xsub = ovl->format->bpp < 24 ? 2 : 1; + unsigned int ysub = ovl->format->bpp < 16 ? 2 : 1; + + y_offset = var->yoffset * ovl->xres_virtual + var->xoffset; + c_offset = var->yoffset / ysub * ovl->xres_virtual * 2 / xsub + + var->xoffset * 2 / xsub; + } - if (pan_offset == ovl->pan_offset) - return 0; /* No change, do nothing */ + /* If the Y offset hasn't changed, the C offset hasn't either. There's + * nothing to do in that case. + */ + if (y_offset == ovl->pan_y_offset) + return 0; /* Set the source address for the next refresh */ - base_addr_y = ovl->dma_handle + pan_offset; + base_addr_y = ovl->dma_handle + y_offset; + base_addr_c = ovl->dma_handle + ovl->xres_virtual * ovl->yres_virtual + + c_offset; ovl->base_addr_y = base_addr_y; - ovl->base_addr_c = base_addr_y; - - if (ovl->format->yuv) { - /* Set Y offset */ - c_offset = var->yoffset * ovl->pitch - * (ovl->format->bpp - 8) / 8; - base_addr_c = ovl->dma_handle - + ovl->xres * ovl->yres_virtual - + c_offset; - /* Set X offset */ - if (ovl->format->fourcc == V4L2_PIX_FMT_NV24) - base_addr_c += 2 * var->xoffset; - else - base_addr_c += var->xoffset; - - ovl->base_addr_c = base_addr_c; - } + ovl->base_addr_c = base_addr_c; + ovl->pan_y_offset = y_offset; lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index)); @@ -1547,8 +1545,6 @@ static int sh_mobile_lcdc_overlay_pan(struct fb_var_screeninfo *var, lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index)); - ovl->pan_offset = pan_offset; - return 0; } @@ -1814,35 +1810,33 @@ static int sh_mobile_lcdc_pan(struct fb_var_screeninfo *var, struct sh_mobile_lcdc_chan *ch = info->par; struct sh_mobile_lcdc_priv *priv = ch->lcdc; unsigned long ldrcntr; - unsigned long new_pan_offset; - unsigned long base_addr_y, base_addr_c = 0; + unsigned long base_addr_y, base_addr_c; + unsigned long y_offset; unsigned long c_offset; - if (!ch->format->yuv) - new_pan_offset = var->yoffset * ch->pitch - + var->xoffset * (ch->format->bpp / 8); - else - new_pan_offset = var->yoffset * ch->pitch + var->xoffset; + if (!ch->format->yuv) { + y_offset = (var->yoffset * ch->xres_virtual + var->xoffset) + * ch->format->bpp / 8; + c_offset = 0; + } else { + unsigned int xsub = ch->format->bpp < 24 ? 2 : 1; + unsigned int ysub = ch->format->bpp < 16 ? 2 : 1; - if (new_pan_offset == ch->pan_offset) - return 0; /* No change, do nothing */ + y_offset = var->yoffset * ch->xres_virtual + var->xoffset; + c_offset = var->yoffset / ysub * ch->xres_virtual * 2 / xsub + + var->xoffset * 2 / xsub; + } - ldrcntr = lcdc_read(priv, _LDRCNTR); + /* If the Y offset hasn't changed, the C offset hasn't either. There's + * nothing to do in that case. + */ + if (y_offset == ch->pan_y_offset) + return 0; /* Set the source address for the next refresh */ - base_addr_y = ch->dma_handle + new_pan_offset; - if (ch->format->yuv) { - /* Set y offset */ - c_offset = var->yoffset * ch->pitch - * (ch->format->bpp - 8) / 8; - base_addr_c = ch->dma_handle + ch->xres * ch->yres_virtual - + c_offset; - /* Set x offset */ - if (ch->format->fourcc == V4L2_PIX_FMT_NV24) - base_addr_c += 2 * var->xoffset; - else - base_addr_c += var->xoffset; - } + base_addr_y = ch->dma_handle + y_offset; + base_addr_c = ch->dma_handle + ch->xres_virtual * ch->yres_virtual + + c_offset; if (ch->cache) sh_mobile_meram_cache_update(priv->meram_dev, ch->cache, @@ -1851,17 +1845,18 @@ static int sh_mobile_lcdc_pan(struct fb_var_screeninfo *var, ch->base_addr_y = base_addr_y; ch->base_addr_c = base_addr_c; + ch->pan_y_offset = y_offset; lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y); if (ch->format->yuv) lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c); + ldrcntr = lcdc_read(priv, _LDRCNTR); if (lcdc_chan_is_sublcd(ch)) lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS); else lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_MRS); - ch->pan_offset = new_pan_offset; sh_mobile_lcdc_deferred_io_touch(info); @@ -2734,7 +2729,6 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) } init_waitqueue_head(&ch->frame_end_wait); init_completion(&ch->vsync_completion); - ch->pan_offset = 0; /* probe the backlight is there is one defined */ if (ch->cfg->bl_info.max_brightness) diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h index e53cd1171072..0f92f6544b94 100644 --- a/drivers/video/sh_mobile_lcdcfb.h +++ b/drivers/video/sh_mobile_lcdcfb.h @@ -47,6 +47,7 @@ struct sh_mobile_lcdc_entity { /* * struct sh_mobile_lcdc_chan - LCDC display channel * + * @pan_y_offset: Panning linear offset in bytes (luma component) * @base_addr_y: Frame buffer viewport base address (luma component) * @base_addr_c: Frame buffer viewport base address (chroma component) * @pitch: Frame buffer line pitch @@ -68,7 +69,7 @@ struct sh_mobile_lcdc_chan { unsigned long fb_size; dma_addr_t dma_handle; - unsigned long pan_offset; + unsigned long pan_y_offset; unsigned long frame_end; wait_queue_head_t frame_end_wait; -- cgit v1.2.3