From mboxrd@z Thu Jan 1 00:00:00 1970 Return-path: Received: from metis.ext.pengutronix.de ([2001:6f8:1178:4:290:27ff:fe1d:cc33]) by canuck.infradead.org with esmtps (Exim 4.72 #1 (Red Hat Linux)) id 1PJQQz-0001bx-Kd for barebox@lists.infradead.org; Fri, 19 Nov 2010 12:51:26 +0000 From: Juergen Beisert Date: Fri, 19 Nov 2010 13:50:57 +0100 Message-Id: <1290171063-28870-6-git-send-email-jbe@pengutronix.de> In-Reply-To: <1290171063-28870-1-git-send-email-jbe@pengutronix.de> References: <1290171063-28870-1-git-send-email-jbe@pengutronix.de> List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: barebox-bounces@lists.infradead.org Errors-To: barebox-bounces+u.kleine-koenig=pengutronix.de@lists.infradead.org Subject: [PATCH 05/11] Adapt the existing imx fb driver to support runtime videomode selection To: barebox@lists.infradead.org Adapt the API to the new framebuffer videomode selection at runtime. NOTE: Due to the lack of hardware, this is compile time tested only. This is patch 3 of 4 to keep the repository bisectable. Signed-off-by: Juergen Beisert --- arch/arm/mach-imx/include/mach/imxfb.h | 1 + drivers/video/imx.c | 209 ++++++++++++++++++------------- 2 files changed, 122 insertions(+), 88 deletions(-) diff --git a/arch/arm/mach-imx/include/mach/imxfb.h b/arch/arm/mach-imx/include/mach/imxfb.h index a75ad99..4a890a7 100644 --- a/arch/arm/mach-imx/include/mach/imxfb.h +++ b/arch/arm/mach-imx/include/mach/imxfb.h @@ -63,6 +63,7 @@ struct imx_fb_videomode { */ struct imx_fb_platform_data { struct imx_fb_videomode *mode; + unsigned mode_cnt; /**< number of entries in 'mode' */ u_int cmap_greyscale:1, cmap_inverse:1, diff --git a/drivers/video/imx.c b/drivers/video/imx.c index 6ccd77e..b13f39d 100644 --- a/drivers/video/imx.c +++ b/drivers/video/imx.c @@ -125,6 +125,9 @@ #define LCDC_LGWDCR 0x68 +#define MAIN_FBUFFER 0 +#define OVRLY_FBUFFER 1 + /* * These are the bitfields for each * display depth that we support. @@ -137,6 +140,7 @@ struct imxfb_rgb { }; struct imxfb_info { + struct fb_host fb_host; /**< myself */ void __iomem *regs; u_int pcr; @@ -147,16 +151,17 @@ struct imxfb_info { cmap_static:1, unused:30; - struct imx_fb_videomode *mode; - - struct fb_info info; - struct device_d *dev; - void (*enable)(int enable); - struct fb_info overlay; + struct fb_host fb_overlay; }; +#define fb_overlay_to_imxfb_info(x) \ + (container_of((struct fb_host*)(x->host), struct imxfb_info, fb_overlay)) +#define fb_overlay_dev_to_imxfb_info(x) \ + (container_of((struct fb_host*)(x->platform_data), struct imxfb_info, fb_overlay)) +#define fb_info_to_imxfb_info(x) ((struct imxfb_info*)((x)->host)) + #define IMX_NAME "IMX" /* @@ -204,11 +209,10 @@ static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf) return chan << bf->offset; } - -static int imxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int trans, struct fb_info *info) +static int imxfb_setcolreg(struct fb_info *info, u_int regno, u_int red, + u_int green, u_int blue, u_int trans) { - struct imxfb_info *fbi = info->priv; + struct imxfb_info *fbi = fb_info_to_imxfb_info(info); int ret = 1; u32 val; @@ -247,7 +251,7 @@ static int imxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, static void imxfb_enable_controller(struct fb_info *info) { - struct imxfb_info *fbi = info->priv; + struct imxfb_info *fbi = fb_info_to_imxfb_info(info); writel(RMCR_LCDC_EN, fbi->regs + LCDC_RMCR); #ifdef CONFIG_ARCH_IMX21 @@ -269,7 +273,7 @@ static void imxfb_enable_controller(struct fb_info *info) static void imxfb_disable_controller(struct fb_info *info) { - struct imxfb_info *fbi = info->priv; + struct imxfb_info *fbi = fb_info_to_imxfb_info(info); if (fbi->enable) fbi->enable(0); @@ -290,19 +294,53 @@ static void imxfb_disable_controller(struct fb_info *info) #endif } +static void imxfb_memory_mmgt(struct fb_info *info, unsigned size, int buf) +{ + struct imx_fb_platform_data *pdata = + info->host->hw_dev->platform_data; + void *base_address = buf == MAIN_FBUFFER ? + pdata->framebuffer : pdata->framebuffer_ovl; + + if (base_address != NULL) { + /* fixed memory location */ + info->fb_dev.map_base = (resource_size_t)base_address; + /** @todo how large is this space? */ + info->fb_dev.size = size; + } else { + /* dynamic memory location */ + if ((info->fb_dev.size < size) && (info->fb_dev.size != 0)) { + free((void*)info->fb_dev.map_base); + info->fb_dev.map_base = 0; + info->fb_dev.size = 0; + } + if (info->fb_dev.size == 0) { + info->fb_dev.map_base = (resource_size_t)xzalloc(size); + info->fb_dev.size = size; + } + } +} + /* * imxfb_activate_var(): * Configures LCD Controller based on entries in var parameter. Settings are * only written to the controller if changes were made. */ -static int imxfb_activate_var(struct fb_info *info) +static int imxfb_initialize_mode(struct fb_info *info, + const struct fb_videomode *mode) { - struct fb_videomode *mode = info->mode; struct imxfb_rgb *rgb; unsigned long lcd_clk; unsigned long long tmp; - struct imxfb_info *fbi = info->priv; + struct imxfb_info *fbi = fb_info_to_imxfb_info(info); u32 pcr; + unsigned size; + + /* + * we need at least this amount of memory for the framebuffer + */ + size = mode->xres * mode->yres * (info->bits_per_pixel >> 3); + + imxfb_memory_mmgt(info, size, MAIN_FBUFFER); /* physical screen start address */ writel(VPW_VPW(mode->xres * info->bits_per_pixel / 8 / 4), @@ -318,13 +356,13 @@ static int imxfb_activate_var(struct fb_info *info) VCR_V_WAIT_2(mode->upper_margin), fbi->regs + LCDC_VCR); - writel(SIZE_XMAX(info->xres) | SIZE_YMAX(info->yres), + writel(SIZE_XMAX(mode->xres) | SIZE_YMAX(mode->yres), fbi->regs + LCDC_SIZE); writel(fbi->pwmr, fbi->regs + LCDC_PWMR); writel(fbi->lscr1, fbi->regs + LCDC_LSCR1); writel(fbi->dmacr, fbi->regs + LCDC_DMACR); - writel((unsigned long)fbi->info.screen_base, fbi->regs + LCDC_SSA); + writel((uint32_t)info->fb_dev.map_base, fbi->regs + LCDC_SSA); /* panning offset 0 (0 pixel offset) */ writel(0x0, fbi->regs + LCDC_POS); @@ -386,16 +424,10 @@ static int imxfb_activate_var(struct fb_info *info) return 0; } -static struct fb_ops imxfb_ops = { - .fb_setcolreg = imxfb_setcolreg, - .fb_enable = imxfb_enable_controller, - .fb_disable = imxfb_disable_controller, -}; - #ifdef CONFIG_IMXFB_DRIVER_VIDEO_IMX_OVERLAY static void imxfb_overlay_enable_controller(struct fb_info *overlay) { - struct imxfb_info *fbi = overlay->priv; + struct imxfb_info *fbi = fb_overlay_to_imxfb_info(overlay); unsigned int tmp; tmp = readl(fbi->regs + LCDC_LGWCR); @@ -405,7 +437,7 @@ static void imxfb_overlay_enable_controller(struct fb_info *overlay) static void imxfb_overlay_disable_controller(struct fb_info *overlay) { - struct imxfb_info *fbi = overlay->priv; + struct imxfb_info *fbi = fb_overlay_to_imxfb_info(overlay); unsigned int tmp; tmp = readl(fbi->regs + LCDC_LGWCR); @@ -413,23 +445,16 @@ static void imxfb_overlay_disable_controller(struct fb_info *overlay) writel(tmp , fbi->regs + LCDC_LGWCR); } -static int imxfb_overlay_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int trans, struct fb_info *info) +static int imxfb_overlay_setcolreg(struct fb_info *overlay, u_int regno, + u_int red, u_int green, u_int blue, u_int trans) { return 0; } -static struct fb_ops imxfb_overlay_ops = { - .fb_setcolreg = imxfb_overlay_setcolreg, - .fb_enable = imxfb_overlay_enable_controller, - .fb_disable = imxfb_overlay_disable_controller, -}; - static int imxfb_alpha_set(struct device_d *dev, struct param_d *param, const char *val) { - struct fb_info *overlay = dev->priv; - struct imxfb_info *fbi = overlay->priv; + struct imxfb_info *fbi = fb_overlay_dev_to_imxfb_info(dev); int alpha; char alphastr[16]; unsigned int tmp; @@ -452,32 +477,23 @@ static int imxfb_alpha_set(struct device_d *dev, struct param_d *param, return 0; } -static int imxfb_register_overlay(struct imxfb_info *fbi, void *fb) +static int imxfb_overlay_mode(struct fb_info *overlay, + const struct fb_videomode *mode) { - struct fb_info *overlay; + struct imxfb_info *fbi = fb_overlay_to_imxfb_info(overlay); struct imxfb_rgb *rgb; - int ret; + unsigned size; - overlay = &fbi->overlay; + /* we need at least this amount of memory for the framebuffer */ + size = mode->xres * mode->yres * (overlay->bits_per_pixel >> 3); - overlay->priv = fbi; - overlay->mode = fbi->info.mode; - overlay->xres = fbi->info.xres; - overlay->yres = fbi->info.yres; - overlay->bits_per_pixel = fbi->info.bits_per_pixel; - overlay->fbops = &imxfb_overlay_ops; + imxfb_memory_mmgt(overlay, size, OVRLY_FBUFFER); - if (fb) - overlay->screen_base = fb; - else - overlay->screen_base = xzalloc(overlay->xres * overlay->yres * - (overlay->bits_per_pixel >> 3)); - - writel((unsigned long)overlay->screen_base, fbi->regs + LCDC_LGWSAR); - writel(SIZE_XMAX(overlay->xres) | SIZE_YMAX(overlay->yres), + writel((uint32_t)overlay->fb_dev.map_base, fbi->regs + LCDC_LGWSAR); + writel(SIZE_XMAX(mode->xres) | SIZE_YMAX(mode->yres), fbi->regs + LCDC_LGWSR); - writel(VPW_VPW(overlay->xres * overlay->bits_per_pixel / 8 / 4), - fbi->regs + LCDC_LGWVPWR); + writel(VPW_VPW(mode->xres * overlay->bits_per_pixel / 8 / 4), + fbi->regs + LCDC_LGWVPWR); writel(0, fbi->regs + LCDC_LGWPR); writel(LGWCR_GWAV(0x0), fbi->regs + LCDC_LGWCR); @@ -506,14 +522,36 @@ static int imxfb_register_overlay(struct imxfb_info *fbi, void *fb) overlay->blue = rgb->blue; overlay->transp = rgb->transp; - ret = register_framebuffer(overlay); - if (ret < 0) { - dev_err(fbi->dev, "failed to register framebuffer\n"); - return ret; + return 0; +} + +static int imxfb_register_overlay(struct imxfb_info *fbi, + struct device_d *hw_dev, struct imx_fb_platform_data *pdata) +{ + struct fb_host *overlay; + struct device_d *overlay_dev; + + overlay = &fbi->fb_overlay; + + /* add runtime hardware info */ + overlay->hw_dev = hw_dev; /* same as the master device */ + overlay->fb_mode = imxfb_overlay_mode; + overlay->fb_enable = imxfb_overlay_enable_controller; + overlay->fb_disable = imxfb_overlay_disable_controller; + overlay->fb_setcolreg = imxfb_overlay_setcolreg; + + /* add runtime video info */ + overlay->mode = pdata->mode->mode; + overlay->mode_cnt = 1; /* no choice */ + + overlay_dev = register_framebuffer(overlay); + if (overlay_dev == NULL) { + dev_err(hw_dev, "failed to register overlay framebuffer\n"); + return -EINVAL; } - dev_add_param(&overlay->dev, "alpha", imxfb_alpha_set, NULL, 0); - dev_set_param(&overlay->dev, "alpha", "0"); + dev_add_param(overlay_dev, "alpha", imxfb_alpha_set, NULL, 0); + dev_set_param(overlay_dev, "alpha", "0"); return 0; } @@ -522,13 +560,13 @@ static int imxfb_register_overlay(struct imxfb_info *fbi, void *fb) static int imxfb_probe(struct device_d *dev) { struct imxfb_info *fbi; - struct fb_info *info; + struct device_d *fb_dev; struct imx_fb_platform_data *pdata = dev->platform_data; - int ret; if (!pdata) return -ENODEV; + /* TODO should be done when enabling the video output */ #ifdef CONFIG_ARCH_IMX21 PCCR0 &= ~(PCCR0_PERCLK3_EN | PCCR0_HCLK_LCDC_EN); #endif @@ -544,40 +582,35 @@ static int imxfb_probe(struct device_d *dev) #endif fbi = xzalloc(sizeof(*fbi)); - info = &fbi->info; - fbi->mode = pdata->mode; - fbi->regs = (void *)dev->map_base; + /* add runtime hardware info */ + fbi->fb_host.hw_dev = dev; + fbi->fb_host.fb_mode = imxfb_initialize_mode; + fbi->fb_host.fb_enable = imxfb_enable_controller; + fbi->fb_host.fb_disable = imxfb_disable_controller; + fbi->fb_host.fb_setcolreg = imxfb_setcolreg; + + fbi->regs = (void*)dev->map_base; fbi->pcr = pdata->mode->pcr; fbi->pwmr = pdata->pwmr; fbi->lscr1 = pdata->lscr1; fbi->dmacr = pdata->dmacr; fbi->enable = pdata->enable; - fbi->dev = dev; - info->priv = fbi; - info->mode = pdata->mode->mode; - info->xres = pdata->mode->mode->xres; - info->yres = pdata->mode->mode->yres; - info->bits_per_pixel = pdata->mode->bpp; - info->fbops = &imxfb_ops; - - dev_info(dev, "i.MX Framebuffer driver\n"); - - if (pdata->framebuffer) - fbi->info.screen_base = pdata->framebuffer; - else - fbi->info.screen_base = xzalloc(info->xres * info->yres * - (info->bits_per_pixel >> 3)); - - imxfb_activate_var(&fbi->info); - - ret = register_framebuffer(&fbi->info); - if (ret < 0) { + + /* add runtime video info */ + fbi->fb_host.mode = pdata->mode->mode; + /* to be backward compatible */ + fbi->fb_host.mode_cnt = pdata->mode_cnt == 0 ? 1 : pdata->mode_cnt; + fbi->fb_host.bits_per_pixel = 16; /* RGB565, the default */ + + fb_dev = register_framebuffer(&fbi->fb_host); + if (dev == NULL) { dev_err(dev, "failed to register framebuffer\n"); - return ret; + return -EINVAL; } + #ifdef CONFIG_IMXFB_DRIVER_VIDEO_IMX_OVERLAY - imxfb_register_overlay(fbi, pdata->framebuffer_ovl); + imxfb_register_overlay(fbi, fb_dev, pdata); #endif return 0; } -- 1.7.2.3 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox