[PATCH 07/11] Adapt the existing imx-ipu fb driver to support runtime videomode selection
Sascha Hauer
s.hauer at pengutronix.de
Fri Oct 22 13:43:04 EDT 2010
On Fri, Oct 22, 2010 at 06:53:21PM +0200, Juergen Beisert wrote:
> Adapt the API to the new framebuffer videomode selection at runtime. If the new
> feature is not used, there is no visible change at runtime for platforms using
> this driver.
This conflicts with the ipu fb patch I posted today.
Sascha
>
> NOTE: Due to the lack of hardware, this is compile time tested only.
>
> This is patch 5 of 7 to keep the repository bisectable.
>
> Signed-off-by: Juergen Beisert <jbe at pengutronix.de>
> ---
> arch/arm/boards/freescale-mx35-3-stack/3stack.c | 2 +-
> arch/arm/boards/pcm043/pcm043.c | 2 +-
> arch/arm/mach-imx/include/mach/imx-ipu-fb.h | 12 +--
> drivers/video/imx-ipu-fb.c | 156 +++++++++++++---------
> 4 files changed, 96 insertions(+), 76 deletions(-)
>
> diff --git a/arch/arm/boards/freescale-mx35-3-stack/3stack.c b/arch/arm/boards/freescale-mx35-3-stack/3stack.c
> index d6699cd..fb40f50 100644
> --- a/arch/arm/boards/freescale-mx35-3-stack/3stack.c
> +++ b/arch/arm/boards/freescale-mx35-3-stack/3stack.c
> @@ -139,7 +139,7 @@ static struct fb_videomode CTP_CLAA070LC0ACW = {
> .lower_margin = 10, /* whole frame should have 500 lines */
> .hsync_len = 1, /* note: DE only display */
> .vsync_len = 1, /* note: DE only display */
> - .sync = FB_SYNC_CLK_IDLE_EN | FB_SYNC_OE_ACT_HIGH,
> + .sync = FB_SYNC_CLK_IDLE_EN | FB_SYNC_DE_HIGH_ACT,
> .vmode = FB_VMODE_NONINTERLACED,
> .flag = 0,
> };
> diff --git a/arch/arm/boards/pcm043/pcm043.c b/arch/arm/boards/pcm043/pcm043.c
> index 5932f95..7e63cc5 100644
> --- a/arch/arm/boards/pcm043/pcm043.c
> +++ b/arch/arm/boards/pcm043/pcm043.c
> @@ -124,7 +124,7 @@ static struct fb_videomode pcm043_fb_mode = {
> .lower_margin = 40,
> .hsync_len = 96,
> .vsync_len = 1,
> - .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_OE_ACT_HIGH,
> + .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_DE_HIGH_ACT,
> .vmode = FB_VMODE_NONINTERLACED,
> .flag = 0,
> };
> diff --git a/arch/arm/mach-imx/include/mach/imx-ipu-fb.h b/arch/arm/mach-imx/include/mach/imx-ipu-fb.h
> index 8e1cc87..ce95243 100644
> --- a/arch/arm/mach-imx/include/mach/imx-ipu-fb.h
> +++ b/arch/arm/mach-imx/include/mach/imx-ipu-fb.h
> @@ -12,20 +12,12 @@
>
> #include <fb.h>
>
> -/* Proprietary FB_SYNC_ flags */
> -#define FB_SYNC_OE_ACT_HIGH 0x80000000
> -#define FB_SYNC_CLK_INVERT 0x40000000
> -#define FB_SYNC_DATA_INVERT 0x20000000
> -#define FB_SYNC_CLK_IDLE_EN 0x10000000
> -#define FB_SYNC_SHARP_MODE 0x08000000
> -#define FB_SYNC_SWAP_RGB 0x04000000
> -#define FB_SYNC_CLK_SEL_EN 0x02000000
> -
> /*
> - * struct mx3fb_platform_data - mx3fb platform data
> + * struct imx_ipu_fb_platform_data - imx-ipu-fb's platform data
> */
> struct imx_ipu_fb_platform_data {
> struct fb_videomode *mode;
> + unsigned mode_cnt; /**< number of entries in 'mode' */
> unsigned char bpp;
> void __iomem *framebuffer;
> /** hook to enable backlight and stuff */
> diff --git a/drivers/video/imx-ipu-fb.c b/drivers/video/imx-ipu-fb.c
> index 2c25b81..426defc 100644
> --- a/drivers/video/imx-ipu-fb.c
> +++ b/drivers/video/imx-ipu-fb.c
> @@ -34,12 +34,12 @@
> #include <mach/clock.h>
>
> struct ipu_fb_info {
> + struct fb_host fb_host; /**< myself */
> void __iomem *regs;
>
> void (*enable)(int enable);
>
> - struct fb_info info;
> - struct device_d *dev;
> + const struct fb_videomode *mode; /**< requested videomodue */
> };
>
> /* IPU DMA Controller channel definitions. */
> @@ -413,29 +413,30 @@ static inline void reg_write(struct ipu_fb_info *fbi, u32 value,
> writel(value, fbi->regs + reg);
> }
>
> +#define fb_info_to_imxfb_info(x) ((struct ipu_fb_info*)((x)->host))
> +
> /*
> * sdc_init_panel() - initialize a synchronous LCD panel.
> - * @width: width of panel in pixels.
> - * @height: height of panel in pixels.
> - * @pixel_fmt: pixel format of buffer as FOURCC ASCII code.
> + * @param info The framebuffer to work on
> + * @param pixel_fmt pixel format of buffer as FOURCC ASCII code.
> * @return: 0 on success or negative error code on failure.
> */
> static int sdc_init_panel(struct fb_info *info, enum pixel_fmt pixel_fmt)
> {
> - struct ipu_fb_info *fbi = info->priv;
> - struct fb_videomode *mode = info->mode;
> + struct ipu_fb_info *fbi = fb_info_to_imxfb_info(info);
> + const struct fb_videomode *mode = fbi->mode;
> u32 reg, old_conf, div;
> enum ipu_panel panel = IPU_PANEL_TFT;
> unsigned long pixel_clk;
>
> /* Init panel size and blanking periods */
> reg = ((mode->hsync_len - 1) << 26) |
> - ((info->xres + mode->left_margin + mode->right_margin +
> + ((mode->xres + mode->left_margin + mode->right_margin +
> mode->hsync_len - 1) << 16);
> reg_write(fbi, reg, SDC_HOR_CONF);
>
> reg = ((mode->vsync_len - 1) << 26) | SDC_V_SYNC_WIDTH_L |
> - ((info->yres + mode->upper_margin + mode->lower_margin +
> + ((mode->yres + mode->upper_margin + mode->lower_margin +
> mode->vsync_len - 1) << 16);
> reg_write(fbi, reg, SDC_VER_CONF);
>
> @@ -448,7 +449,7 @@ static int sdc_init_panel(struct fb_info *info, enum pixel_fmt pixel_fmt)
> old_conf |= DI_D3_CLK_POL;
> if (mode->sync & FB_SYNC_DATA_INVERT)
> old_conf |= DI_D3_DATA_POL;
> - if (mode->sync & FB_SYNC_OE_ACT_HIGH)
> + if (mode->sync & FB_SYNC_DE_HIGH_ACT)
> old_conf |= DI_D3_DRDY_SHARP_POL;
> reg_write(fbi, old_conf, DI_DISP_SIG_POL);
>
> @@ -483,12 +484,12 @@ static int sdc_init_panel(struct fb_info *info, enum pixel_fmt pixel_fmt)
> div = imx_get_lcdclk() * 16 / pixel_clk;
>
> if (div < 0x40) { /* Divider less than 4 */
> - dev_dbg(&info->dev,
> + dev_dbg(fbi->fb_host.hw_dev,
> "InitPanel() - Pixel clock divider less than 4\n");
> div = 0x40;
> }
>
> - dev_dbg(&info->dev, "pixel clk = %u, divider %u.%u\n",
> + dev_dbg(fbi->fb_host.hw_dev, "pixel clk = %u, divider %u.%u\n",
> pixel_clk, div >> 4, (div & 7) * 125);
>
> /*
> @@ -588,19 +589,20 @@ static u32 dma_param_addr(enum ipu_channel channel)
> return 0x10000 | (channel << 4);
> }
>
> -static void ipu_init_channel_buffer(struct ipu_fb_info *fbi,
> +static void ipu_init_channel_buffer(struct fb_info *info,
> enum ipu_channel channel, void *fbmem)
> {
> + struct ipu_fb_info *fbi = fb_info_to_imxfb_info(info);
> union chan_param_mem params = {};
> u32 reg;
> u32 stride_bytes;
>
> - stride_bytes = fbi->info.xres * ((fbi->info.bits_per_pixel + 7) / 8);
> + stride_bytes = fbi->mode->xres * ((info->bits_per_pixel + 7) / 8);
> stride_bytes = (stride_bytes + 3) & ~3;
>
> /* Build parameter memory data for DMA channel */
> - ipu_ch_param_set_size(¶ms, bpp_to_pixfmt(fbi->info.bits_per_pixel),
> - fbi->info.xres, fbi->info.yres, stride_bytes);
> + ipu_ch_param_set_size(¶ms, bpp_to_pixfmt(info->bits_per_pixel),
> + fbi->mode->xres, fbi->mode->yres, stride_bytes);
> ipu_ch_param_set_buffer(¶ms, fbmem, NULL);
> params.pp.bam = 0;
> /* Some channels (rotation) have restriction on burst length */
> @@ -622,9 +624,10 @@ static void ipu_init_channel_buffer(struct ipu_fb_info *fbi,
> reg_write(fbi, reg, IPU_CHA_DB_MODE_SEL);
> }
>
> -static void ipu_channel_set_priority(struct ipu_fb_info *fbi,
> +static void ipu_channel_set_priority(struct fb_info *fb_info,
> enum ipu_channel channel, int prio)
> {
> + struct ipu_fb_info *fbi = fb_info_to_imxfb_info(fb_info);
> u32 reg;
>
> reg = reg_read(fbi, IDMAC_CHA_PRI);
> @@ -639,11 +642,13 @@ static void ipu_channel_set_priority(struct ipu_fb_info *fbi,
>
> /*
> * ipu_enable_channel() - enable an IPU channel.
> + * @param info The framebuffer to work on
> * @channel: channel ID.
> * @return: 0 on success or negative error code on failure.
> */
> -static int ipu_enable_channel(struct ipu_fb_info *fbi, enum ipu_channel channel)
> +static int ipu_enable_channel(struct fb_info *info, enum ipu_channel channel)
> {
> + struct ipu_fb_info *fbi = fb_info_to_imxfb_info(info);
> u32 reg;
>
> /* Reset to buffer 0 */
> @@ -651,7 +656,7 @@ static int ipu_enable_channel(struct ipu_fb_info *fbi, enum ipu_channel channel)
>
> switch (channel) {
> case IDMAC_SDC_0:
> - ipu_channel_set_priority(fbi, channel, 1);
> + ipu_channel_set_priority(info, channel, 1);
> break;
> default:
> break;
> @@ -663,9 +668,10 @@ static int ipu_enable_channel(struct ipu_fb_info *fbi, enum ipu_channel channel)
> return 0;
> }
>
> -static int ipu_update_channel_buffer(struct ipu_fb_info *fbi,
> +static int ipu_update_channel_buffer(struct fb_info *info,
> enum ipu_channel channel, void *buf)
> {
> + struct ipu_fb_info *fbi = fb_info_to_imxfb_info(info);
> u32 reg;
>
> reg = reg_read(fbi, IPU_CHA_BUF0_RDY);
> @@ -679,16 +685,17 @@ static int ipu_update_channel_buffer(struct ipu_fb_info *fbi,
> return 0;
> }
>
> -static int idmac_tx_submit(struct ipu_fb_info *fbi, enum ipu_channel channel,
> +static int idmac_tx_submit(struct fb_info *info, enum ipu_channel channel,
> void *buf)
> {
> + struct ipu_fb_info *fbi = fb_info_to_imxfb_info(info);
> int ret;
>
> - ipu_init_channel_buffer(fbi, channel, buf);
> + ipu_init_channel_buffer(info, channel, buf);
>
>
> /* ipu_idmac.c::ipu_submit_channel_buffers() */
> - ret = ipu_update_channel_buffer(fbi, channel, buf);
> + ret = ipu_update_channel_buffer(info, channel, buf);
> if (ret < 0)
> return ret;
>
> @@ -697,16 +704,17 @@ static int idmac_tx_submit(struct ipu_fb_info *fbi, enum ipu_channel channel,
> reg_write(fbi, 1UL << channel, IPU_CHA_BUF0_RDY);
>
>
> - ret = ipu_enable_channel(fbi, channel);
> + ret = ipu_enable_channel(info, channel);
> return ret;
> }
>
> -static void sdc_enable_channel(struct ipu_fb_info *fbi, void *fbmem)
> +static void sdc_enable_channel(struct fb_info *info, void *fbmem)
> {
> + struct ipu_fb_info *fbi = fb_info_to_imxfb_info(info);
> int ret;
> u32 reg;
>
> - ret = idmac_tx_submit(fbi, IDMAC_SDC_0, fbmem);
> + ret = idmac_tx_submit(info, IDMAC_SDC_0, fbmem);
>
> /* mx3fb.c::sdc_fb_init() */
> if (ret >= 0) {
> @@ -724,13 +732,14 @@ static void sdc_enable_channel(struct ipu_fb_info *fbi, void *fbmem)
>
> /*
> * mx3fb_set_par() - set framebuffer parameters and change the operating mode.
> + * @param info The framebuffer to work on
> * @return: 0 on success or negative error code on failure.
> */
> static int mx3fb_set_par(struct fb_info *info)
> {
> - struct ipu_fb_info *fbi = info->priv;
> + struct ipu_fb_info *fbi = fb_info_to_imxfb_info(info);
> struct imx_ipu_fb_rgb *rgb;
> - struct fb_videomode *mode = info->mode;
> + const struct fb_videomode *mode = fbi->mode;
> int ret;
>
> ret = sdc_init_panel(info, IPU_PIX_FMT_RGB666);
> @@ -766,10 +775,45 @@ static int mx3fb_set_par(struct fb_info *info)
> return 0;
> }
>
> +static int ipu_fb_initialize_mode(struct fb_info *fb_info, const struct fb_videomode *mode)
> +{
> + struct ipu_fb_info *fbi = fb_info_to_imxfb_info(fb_info);
> + unsigned size;
> +
> + /*
> + * we need at least this amount of memory for the framebuffer
> + */
> + size = mode->xres * mode->yres * (fb_info->bits_per_pixel >> 3);
> + if (fb_info->fb_dev->size != 0) {
> + if (size > fb_info->fb_dev->size) {
> + pr_err("Cannot initialize video mode '%s': Its too large. "
> + "Required bytes are %u, available only %u\n",
> + mode->name, size, fb_info->fb_dev->size);
> + return -EINVAL;
> + }
> + } else
> + fb_info->fb_dev->size = size;
> +
> + /*
> + * if no framebuffer memory was specified yet, allocate one,
> + * and allocate more memory, on user request
> + */
> + if (fb_info->fb_dev->map_base == 0U /* FIXME should be 'NULL'*/)
> + fb_info->fb_dev->map_base = (unsigned long)xzalloc(fb_info->fb_dev->size);
> +
> +#if 0
> + /* FIXME why here? Its also called in ipu_fb_enable() */
> + sdc_enable_channel(fbi, fb_info->fb_dev->map_base);
> +#endif
> + fbi->mode = mode;
> +
> + return 0;
> +}
> +
> /* References in this function refer to respective Linux kernel sources */
> static void ipu_fb_enable(struct fb_info *info)
> {
> - struct ipu_fb_info *fbi = info->priv;
> + struct ipu_fb_info *fbi = fb_info_to_imxfb_info(info);
>
> u32 reg;
>
> @@ -825,7 +869,7 @@ static void ipu_fb_enable(struct fb_info *info)
>
> mx3fb_set_par(info);
>
> - sdc_enable_channel(fbi, info->screen_base);
> + sdc_enable_channel(info, (void*)info->fb_dev->map_base);
>
> /*
> * Linux driver calls sdc_set_brightness() here again,
> @@ -837,7 +881,7 @@ static void ipu_fb_enable(struct fb_info *info)
>
> static void ipu_fb_disable(struct fb_info *info)
> {
> - struct ipu_fb_info *fbi = info->priv;
> + struct ipu_fb_info *fbi = fb_info_to_imxfb_info(info);
> u32 reg;
>
> printf("%s\n", __func__);
> @@ -850,54 +894,38 @@ static void ipu_fb_disable(struct fb_info *info)
> reg_write(fbi, reg, SDC_COM_CONF);
> }
>
> -static struct fb_ops imxfb_ops = {
> - .fb_enable = ipu_fb_enable,
> - .fb_disable = ipu_fb_disable,
> -};
> -
> static int imxfb_probe(struct device_d *dev)
> {
> struct ipu_fb_info *fbi;
> - struct fb_info *info;
> + struct device_d *fb_dev;
> const struct imx_ipu_fb_platform_data *pdata = dev->platform_data;
> - int ret;
>
> if (!pdata)
> return -ENODEV;
>
> fbi = xzalloc(sizeof(*fbi));
> - info = &fbi->info;
> +
> + /* add runtime hardware info */
> + fbi->fb_host.hw_dev = dev;
> + fbi->fb_host.fb_mode = ipu_fb_initialize_mode;
> + fbi->fb_host.fb_enable = ipu_fb_enable;
> + fbi->fb_host.fb_disable = ipu_fb_disable;
> + fbi->fb_host.fb_setcolreg = NULL;
>
> fbi->regs = (void *)dev->map_base;
> - fbi->dev = dev;
> - info->priv = fbi;
> - info->mode = pdata->mode;
> - info->xres = pdata->mode->xres;
> - info->yres = pdata->mode->yres;
> - info->bits_per_pixel = pdata->bpp;
> - info->fbops = &imxfb_ops;
> - fbi->enable = pdata->enable;
>
> - dev_info(dev, "i.MX Framebuffer driver\n");
> + /* add runtime video info */
> + fbi->fb_host.mode = pdata->mode;
> + /* to be backward compatible */
> + fbi->fb_host.mode_cnt = pdata->mode_cnt == 0 ? 1 : pdata->mode_cnt;
> + fbi->fb_host.bits_per_pixel = pdata->bpp;
>
> - /*
> - * Use a given frambuffer or reserve some
> - * memory for screen usage
> - */
> - fbi->info.screen_base = pdata->framebuffer;
> - if (fbi->info.screen_base == NULL) {
> - fbi->info.screen_base = malloc(info->xres * info->yres *
> - (info->bits_per_pixel >> 3));
> - if (!fbi->info.screen_base)
> - return -ENOMEM;
> - }
> -
> - sdc_enable_channel(fbi, info->screen_base);
> + dev_info(dev, "i.MX Framebuffer driver\n");
>
> - ret = register_framebuffer(&fbi->info);
> - if (ret < 0) {
> + fb_dev = register_framebuffer(&fbi->fb_host, pdata->framebuffer, 0);
> + if (fb_dev == NULL) {
> dev_err(dev, "failed to register framebuffer\n");
> - return ret;
> + return -EINVAL;
> }
>
> return 0;
> --
> 1.7.2.3
>
>
> _______________________________________________
> barebox mailing list
> barebox at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
>
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
More information about the barebox
mailing list