Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2a618e03 authored by Laurent Pinchart's avatar Laurent Pinchart
Browse files

fbdev: sh_mobile_meram: Add struct sh_mobile_meram_icb



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: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
parent eb4f2304
Loading
Loading
Loading
Loading
+90 −88
Original line number Original line Diff line number Diff line
@@ -100,14 +100,38 @@ static unsigned long icb_regs[] = {
};
};
#define ICB_REGS_SIZE ARRAY_SIZE(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 {
struct sh_mobile_meram_priv {
	void __iomem *base;
	void __iomem *base;
	unsigned long regs[CMN_REGS_SIZE];

	struct mutex lock;
	struct mutex lock;
	unsigned long used_icb;
	unsigned long used_icb;
	unsigned int	used_meram_cache_regions;
	struct sh_mobile_meram_icb icbs[SH_MOBILE_MERAM_ICB_NUM];
	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];
};
};


/* settings */
/* 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,
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 used_start, used_end, meram_start, meram_end;
	unsigned int i;
	unsigned int i;
@@ -170,9 +194,12 @@ static inline int meram_check_overlap(struct sh_mobile_meram_priv *priv,
	    test_bit(new->cache_icb,  &priv->used_icb))
	    test_bit(new->cache_icb,  &priv->used_icb))
		return  1;
		return  1;


	for (i = 0; i < priv->used_meram_cache_regions; i++) {
	for (i = 0; i < SH_MOBILE_MERAM_ICB_NUM; i++) {
		used_start = MERAM_CACHE_START(priv->used_meram_cache[i]);
		if (!test_bit(i, &priv->used_icb))
		used_end   = MERAM_CACHE_END(priv->used_meram_cache[i]);
			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_start = new->meram_offset;
		meram_end   = new->meram_offset + new->meram_size;
		meram_end   = new->meram_offset + new->meram_size;


@@ -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,
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->marker_icb, &priv->used_icb);
	__set_bit(new->cache_icb, &priv->used_icb);
	__set_bit(new->cache_icb, &priv->used_icb);


	n = priv->used_meram_cache_regions;
	priv->icbs[new->marker_icb].region = MERAM_CACHE_SET(new->meram_offset,

	priv->used_meram_cache[n] = MERAM_CACHE_SET(new->meram_offset,
							     new->meram_size);
							     new->meram_size);

	priv->icbs[new->cache_icb].region = MERAM_CACHE_SET(new->meram_offset,
	priv->used_meram_cache_regions++;
							    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,
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->marker_icb, &priv->used_icb);
	__clear_bit(icb->cache_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;
		}
	}
}
}


/*
/*
@@ -253,46 +256,51 @@ static inline int is_nvcolor(int cspace)
 * set the next address to fetch
 * set the next address to fetch
 */
 */
static inline void meram_set_next_addr(struct sh_mobile_meram_priv *priv,
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_y,
				       unsigned long base_addr_c)
				       unsigned long base_addr_c)
{
{
	struct sh_mobile_meram_icb *icb = &priv->icbs[cfg->icb[0].marker_icb];
	unsigned long target;
	unsigned long target;


	cfg->current_reg ^= 1;
	icb->current_reg ^= 1;
	target = cfg->current_reg ? MExxSARB : MExxSARA;
	target = icb->current_reg ? MExxSARB : MExxSARA;


	/* set the next address to fetch */
	/* 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);
			base_addr_y);
	meram_write_icb(priv->base, cfg->icb[0].marker_icb, target,
	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,
		meram_write_icb(priv->base, cfg->icb[1].cache_icb,  target,
				base_addr_c);
				base_addr_c);
		meram_write_icb(priv->base, cfg->icb[1].marker_icb, target,
		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
 * get the next ICB address
 */
 */
static inline void meram_get_next_icb_addr(struct sh_mobile_meram_info *pdata,
static inline void
					   struct sh_mobile_meram_cfg *cfg,
meram_get_next_icb_addr(struct sh_mobile_meram_info *pdata,
					   unsigned long *icb_addr_y,
			const struct sh_mobile_meram_cfg *cfg,
					   unsigned long *icb_addr_c)
			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;
	unsigned long icb_offset;


	if (pdata->addr_mode == SH_MOBILE_MERAM_MODE0)
	if (pdata->addr_mode == SH_MOBILE_MERAM_MODE0)
		icb_offset = 0x80000000 | (cfg->current_reg << 29);
		icb_offset = 0x80000000 | (icb->current_reg << 29);
	else
	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);
	*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);
		*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,
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 xres, unsigned int yres,
		      unsigned int *out_pitch)
		      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);
	meram_write_icb(priv->base, icb->marker_icb, MExxSBSIZE, xpitch);


	/* save a cache unit size */
	/* 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
	 * 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,
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 */
	/* disable ICB */
	meram_write_icb(priv->base, icb->cache_icb,  MExxCTL,
	meram_write_icb(priv->base, icb->cache_icb,  MExxCTL,
			MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF);
			MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF);
	meram_write_icb(priv->base, icb->marker_icb, MExxCTL,
	meram_write_icb(priv->base, icb->marker_icb, MExxCTL,
			MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF);
			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,
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 xres, unsigned int yres,
				    unsigned int pixelformat,
				    unsigned int pixelformat,
				    unsigned long base_addr_y,
				    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);
	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 */
	/* make sure that there's no overlaps */
	if (meram_check_overlap(priv, &cfg->icb[0])) {
	if (meram_check_overlap(priv, &cfg->icb[0])) {
		dev_err(&pdev->dev, "conflicting config detected.");
		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 */
	/* we now register the ICB */
	cfg->pixelformat = pixelformat;
	meram_mark(priv, &cfg->icb[0], pixelformat);
	meram_mark(priv, &cfg->icb[0]);
	if (is_nvcolor(pixelformat))
	if (is_nvcolor(pixelformat))
		meram_mark(priv, &cfg->icb[1]);
		meram_mark(priv, &cfg->icb[1], pixelformat);


	/* initialize MERAM */
	/* initialize MERAM */
	meram_init(priv, &cfg->icb[0], xres, yres, &out_pitch);
	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,
		meram_init(priv, &cfg->icb[1], 2 * xres, (yres + 1) / 2,
			&out_pitch);
			&out_pitch);


	cfg->current_reg = 1;
	meram_set_next_addr(priv, cfg, base_addr_y, base_addr_c);
	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_get_next_icb_addr(pdata, cfg, icb_addr_y, icb_addr_c);


@@ -492,19 +495,21 @@ static int sh_mobile_meram_register(struct sh_mobile_meram_info *pdata,
}
}


static int sh_mobile_meram_unregister(struct sh_mobile_meram_info *pdata,
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_priv *priv;
	struct sh_mobile_meram_icb *icb;


	if (!pdata || !pdata->priv || !cfg)
	if (!pdata || !pdata->priv || !cfg)
		return -EINVAL;
		return -EINVAL;


	priv = pdata->priv;
	priv = pdata->priv;
	icb = &priv->icbs[cfg->icb[0].marker_icb];


	mutex_lock(&priv->lock);
	mutex_lock(&priv->lock);


	/* deinit & unmark */
	/* deinit & unmark */
	if (is_nvcolor(cfg->pixelformat)) {
	if (is_nvcolor(icb->pixelformat)) {
		meram_deinit(priv, &cfg->icb[1]);
		meram_deinit(priv, &cfg->icb[1]);
		meram_unmark(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,
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_y,
				  unsigned long base_addr_c,
				  unsigned long base_addr_c,
				  unsigned long *icb_addr_y,
				  unsigned long *icb_addr_y,
@@ -547,18 +552,17 @@ static int sh_mobile_meram_runtime_suspend(struct device *dev)
	unsigned int i, j;
	unsigned int i, j;


	for (i = 0; i < CMN_REGS_SIZE; i++)
	for (i = 0; i < CMN_REGS_SIZE; i++)
		priv->cmn_saved_regs[i] = meram_read_reg(priv->base,
		priv->regs[i] = meram_read_reg(priv->base, common_regs[i]);
			common_regs[i]);


	for (i = 0; i < 32; i++) {
	for (i = 0; i < 32; i++) {
		if (!test_bit(i, &priv->used_icb))
		if (!test_bit(i, &priv->used_icb))
			continue;
			continue;
		for (j = 0; j < ICB_REGS_SIZE; j++) {
		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]);
				meram_read_icb(priv->base, i, icb_regs[j]);
			/* Reset ICB on resume */
			/* Reset ICB on resume */
			if (icb_regs[j] == MExxCTL)
			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;
					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++) {
	for (i = 0; i < 32; i++) {
		if (!test_bit(i, &priv->used_icb))
		if (!test_bit(i, &priv->used_icb))
			continue;
			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],
			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++)
	for (i = 0; i < CMN_REGS_SIZE; i++)
		meram_write_reg(priv->base, common_regs[i],
		meram_write_reg(priv->base, common_regs[i], priv->regs[i]);
				priv->cmn_saved_regs[i]);
	return 0;
	return 0;
}
}


+4 −8
Original line number Original line Diff line number Diff line
@@ -30,14 +30,10 @@ struct sh_mobile_meram_icb_cfg {
	unsigned int cache_icb;		/* ICB # for Cache ICB */
	unsigned int cache_icb;		/* ICB # for Cache ICB */
	unsigned int meram_offset;	/* MERAM Buffer Offset to use */
	unsigned int meram_offset;	/* MERAM Buffer Offset to use */
	unsigned int meram_size;	/* MERAM Buffer Size 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_cfg {
	struct sh_mobile_meram_icb_cfg icb[2];
	struct sh_mobile_meram_icb_cfg icb[2];
	int				pixelformat;
	int				current_reg;
};
};


struct module;
struct module;
@@ -45,7 +41,7 @@ struct sh_mobile_meram_ops {
	struct module	*module;
	struct module	*module;
	/* register usage of meram */
	/* register usage of meram */
	int (*meram_register)(struct sh_mobile_meram_info *meram_dev,
	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 xres, unsigned int yres,
			      unsigned int pixelformat,
			      unsigned int pixelformat,
			      unsigned long base_addr_y,
			      unsigned long base_addr_y,
@@ -56,11 +52,11 @@ struct sh_mobile_meram_ops {


	/* unregister usage of meram */
	/* unregister usage of meram */
	int (*meram_unregister)(struct sh_mobile_meram_info *meram_dev,
	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 */
	/* update meram settings */
	int (*meram_update)(struct sh_mobile_meram_info *meram_dev,
	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_y,
			    unsigned long base_addr_c,
			    unsigned long base_addr_c,
			    unsigned long *icb_addr_y,
			    unsigned long *icb_addr_y,