[PATCH 05/11] Adapt the existing imx fb driver to support runtime videomode selection
Juergen Beisert
jbe at pengutronix.de
Fri Nov 19 07:50:57 EST 2010
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 <jbe at pengutronix.de>
---
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
More information about the barebox
mailing list