fbdev: sh_mobile_meram: Allocate ICBs automatically

Started by Laurent Pinchart on Dec 13, 2011 · 3 messages from 2 authors · Last reply Dec 15, 2011

Subsystems (2)

Maintainers (2)

STALE5448d

open the first message on its own page

Message details and related content
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
Message details and related content
Hi Laurent,
On 2011/12/13 23:02, Laurent Pinchart wrote:
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>
---
So one concern that I have about this is in regards to sharing ICBs with
user-space drivers.  Since there are user space drivers (via UIO) for
blocks like the VEU, that may want to have access to MERAM, we need
a way to communicate which ICBs are free to user space.  With the
hard-coded platform data we could easily assume that kernel drivers
would use, for example, the upper 16 ICBs and so user-space drivers were
free to use the lower 16.

One simple temporary workaround might be to provide a range of useable
ICBs in the platform data.  The MERAM memory allocation range can always
easily be tweaked by using the meram_resources structure.

Thanks,
Damian
Message details and related content
Hi Damian,

On Thursday 15 December 2011 03:58:12 Damian Hobson-Garcia wrote:
Hi Laurent,

On 2011/12/13 23:02, Laurent Pinchart wrote:
quoted
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>
---
So one concern that I have about this is in regards to sharing ICBs with
user-space drivers. Since there are user space drivers (via UIO) for blocks
like the VEU, that may want to have access to MERAM, we need a way to
communicate which ICBs are free to user space. With the hard-coded platform
data we could easily assume that kernel drivers would use, for example, the
upper 16 ICBs and so user-space drivers were free to use the lower 16.
You're right, I forgot about that :-/
One simple temporary workaround might be to provide a range of useable ICBs
in the platform data. The MERAM memory allocation range can always easily be
tweaked by using the meram_resources structure.
That sounds good to me. I'll implement that.

-- 
Regards,

Laurent Pinchart
Keyboard shortcuts
hback out one level
jnext message in thread / next series-diff position
kprevious message in thread / previous series-diff position
ldrill in
Escclose help / fold thread tree
?toggle this help