* [PATCH 01/11] Separate framebuffer platformdata and the videomode
2010-11-19 12:50 [PATCHv3] Add dynamic video initialization to barebox Juergen Beisert
@ 2010-11-19 12:50 ` Juergen Beisert
2010-11-19 12:50 ` [PATCH 02/11] Add more flags for sync control Juergen Beisert
` (9 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Juergen Beisert @ 2010-11-19 12:50 UTC (permalink / raw)
To: barebox
This patch separates the imx platformdata and its videomode in two structures,
in order to support more than one defined videomode in the boardfile. This
is intended to support runtime videomode selection later on. It also uses
now the same videomode setup style than the imx-fpu based systems (like the
i.MX35).
Signed-off-by: Juergen Beisert <jbe@pengutronix.de>
---
arch/arm/boards/eukrea_cpuimx25/eukrea_cpuimx25.c | 28 +++++++++--------
arch/arm/boards/eukrea_cpuimx27/eukrea_cpuimx27.c | 28 +++++++++--------
arch/arm/boards/guf-neso/board.c | 28 +++++++++--------
arch/arm/boards/imx21ads/imx21ads.c | 34 +++++++++++----------
arch/arm/boards/pcm038/pcm038.c | 28 +++++++++--------
arch/arm/mach-imx/include/mach/imxfb.h | 2 +-
drivers/video/imx.c | 6 ++--
7 files changed, 82 insertions(+), 72 deletions(-)
diff --git a/arch/arm/boards/eukrea_cpuimx25/eukrea_cpuimx25.c b/arch/arm/boards/eukrea_cpuimx25/eukrea_cpuimx25.c
index 3048c3f..2b53766 100644
--- a/arch/arm/boards/eukrea_cpuimx25/eukrea_cpuimx25.c
+++ b/arch/arm/boards/eukrea_cpuimx25/eukrea_cpuimx25.c
@@ -107,20 +107,22 @@ struct imx_nand_platform_data nand_info = {
.hw_ecc = 1,
};
+static struct fb_videomode cmo_display = {
+ .name = "CMO-QVGA",
+ .refresh = 60,
+ .xres = 320,
+ .yres = 240,
+ .pixclock = KHZ2PICOS(6500),
+ .hsync_len = 30,
+ .left_margin = 38,
+ .right_margin = 20,
+ .vsync_len = 3,
+ .upper_margin = 15,
+ .lower_margin = 4,
+};
+
static struct imx_fb_videomode imxfb_mode = {
- .mode = {
- .name = "CMO-QVGA",
- .refresh = 60,
- .xres = 320,
- .yres = 240,
- .pixclock = KHZ2PICOS(6500),
- .hsync_len = 30,
- .left_margin = 38,
- .right_margin = 20,
- .vsync_len = 3,
- .upper_margin = 15,
- .lower_margin = 4,
- },
+ .mode = &cmo_display,
.pcr = 0xCAD08B80,
.bpp = 16,
};
diff --git a/arch/arm/boards/eukrea_cpuimx27/eukrea_cpuimx27.c b/arch/arm/boards/eukrea_cpuimx27/eukrea_cpuimx27.c
index 4567cba..3ee1057 100644
--- a/arch/arm/boards/eukrea_cpuimx27/eukrea_cpuimx27.c
+++ b/arch/arm/boards/eukrea_cpuimx27/eukrea_cpuimx27.c
@@ -167,20 +167,22 @@ static void eukrea_cpuimx27_mmu_init(void)
#endif
#ifdef CONFIG_DRIVER_VIDEO_IMX
+static struct fb_videomode cmo_display = {
+ .name = "CMO-QVGA",
+ .refresh = 60,
+ .xres = 320,
+ .yres = 240,
+ .pixclock = 156000,
+ .hsync_len = 30,
+ .left_margin = 38,
+ .right_margin = 20,
+ .vsync_len = 3,
+ .upper_margin = 15,
+ .lower_margin = 4,
+};
+
static struct imx_fb_videomode imxfb_mode = {
- .mode = {
- .name = "CMO-QVGA",
- .refresh = 60,
- .xres = 320,
- .yres = 240,
- .pixclock = 156000,
- .hsync_len = 30,
- .left_margin = 38,
- .right_margin = 20,
- .vsync_len = 3,
- .upper_margin = 15,
- .lower_margin = 4,
- },
+ .mode = &cmo_display,
.pcr = 0xFAD08B80,
.bpp = 16,};
diff --git a/arch/arm/boards/guf-neso/board.c b/arch/arm/boards/guf-neso/board.c
index d371dd6..fba43bb 100644
--- a/arch/arm/boards/guf-neso/board.c
+++ b/arch/arm/boards/guf-neso/board.c
@@ -78,20 +78,22 @@ static struct imx_nand_platform_data nand_info = {
.flash_bbt = 1,
};
+static struct fb_videomode cpt_display = {
+ .name = "CPT CLAA070LC0JCT",
+ .refresh = 60,
+ .xres = 800,
+ .yres = 480,
+ .pixclock = KHZ2PICOS(27000),
+ .hsync_len = 1, /* DE only sync */
+ .left_margin = 50,
+ .right_margin = 50,
+ .vsync_len = 1, /* DE only sync */
+ .upper_margin = 10,
+ .lower_margin = 10,
+};
+
static struct imx_fb_videomode imxfb_mode = {
- .mode = {
- .name = "CPT CLAA070LC0JCT",
- .refresh = 60,
- .xres = 800,
- .yres = 480,
- .pixclock = KHZ2PICOS(27000),
- .hsync_len = 1, /* DE only sync */
- .left_margin = 50,
- .right_margin = 50,
- .vsync_len = 1, /* DE only sync */
- .upper_margin = 10,
- .lower_margin = 10,
- },
+ .mode = &cpt_display,
/*
* - TFT style panel
* - clk enabled while idle
diff --git a/arch/arm/boards/imx21ads/imx21ads.c b/arch/arm/boards/imx21ads/imx21ads.c
index 3942581..8e145c7 100644
--- a/arch/arm/boards/imx21ads/imx21ads.c
+++ b/arch/arm/boards/imx21ads/imx21ads.c
@@ -73,24 +73,26 @@ static struct device_d cs8900_dev = {
// IRQ is connected to UART3_RTS
};
+static struct fb_videomode sharp_display = {
+ .name = "Sharp-LQ035Q7",
+ .refresh = 60,
+ .xres = 240,
+ .yres = 320,
+ .pixclock = 188679,
+ .left_margin = 6,
+ .right_margin = 16,
+ .upper_margin = 8,
+ .lower_margin = 10,
+ .hsync_len = 2,
+ .vsync_len = 1,
+ .sync = 0,
+ .vmode = FB_VMODE_NONINTERLACED,
+ .flag = 0,
+};
+
/* Sharp LQ035Q7DB02 QVGA display */
static struct imx_fb_videomode imx_fb_modedata = {
- .mode = {
- .name = "Sharp-LQ035Q7",
- .refresh = 60,
- .xres = 240,
- .yres = 320,
- .pixclock = 188679,
- .left_margin = 6,
- .right_margin = 16,
- .upper_margin = 8,
- .lower_margin = 10,
- .hsync_len = 2,
- .vsync_len = 1,
- .sync = 0,
- .vmode = FB_VMODE_NONINTERLACED,
- .flag = 0,
- },
+ .mode = &sharp_display,
.pcr = 0xfb108bc7,
.bpp = 16,
};
diff --git a/arch/arm/boards/pcm038/pcm038.c b/arch/arm/boards/pcm038/pcm038.c
index 1dbc6b6..8cbb551 100644
--- a/arch/arm/boards/pcm038/pcm038.c
+++ b/arch/arm/boards/pcm038/pcm038.c
@@ -107,20 +107,22 @@ static struct imx_nand_platform_data nand_info = {
.flash_bbt = 1,
};
+static struct fb_videomode sharp_display = {
+ .name = "Sharp-LQ035Q7",
+ .refresh = 60,
+ .xres = 240,
+ .yres = 320,
+ .pixclock = 188679, /* in ps (5.3MHz) */
+ .hsync_len = 7,
+ .left_margin = 5,
+ .right_margin = 16,
+ .vsync_len = 1,
+ .upper_margin = 7,
+ .lower_margin = 9,
+};
+
static struct imx_fb_videomode imxfb_mode = {
- .mode = {
- .name = "Sharp-LQ035Q7",
- .refresh = 60,
- .xres = 240,
- .yres = 320,
- .pixclock = 188679, /* in ps (5.3MHz) */
- .hsync_len = 7,
- .left_margin = 5,
- .right_margin = 16,
- .vsync_len = 1,
- .upper_margin = 7,
- .lower_margin = 9,
- },
+ .mode = &sharp_display,
/*
* - HSYNC active high
* - VSYNC active high
diff --git a/arch/arm/mach-imx/include/mach/imxfb.h b/arch/arm/mach-imx/include/mach/imxfb.h
index b71b7f4..a75ad99 100644
--- a/arch/arm/mach-imx/include/mach/imxfb.h
+++ b/arch/arm/mach-imx/include/mach/imxfb.h
@@ -53,7 +53,7 @@
#define DMACR_TM(x) ((x) & 0xf)
struct imx_fb_videomode {
- struct fb_videomode mode;
+ struct fb_videomode *mode;
u32 pcr;
unsigned char bpp;
};
diff --git a/drivers/video/imx.c b/drivers/video/imx.c
index ac51858..6ccd77e 100644
--- a/drivers/video/imx.c
+++ b/drivers/video/imx.c
@@ -555,9 +555,9 @@ static int imxfb_probe(struct device_d *dev)
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->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;
--
1.7.2.3
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 02/11] Add more flags for sync control
2010-11-19 12:50 [PATCHv3] Add dynamic video initialization to barebox Juergen Beisert
2010-11-19 12:50 ` [PATCH 01/11] Separate framebuffer platformdata and the videomode Juergen Beisert
@ 2010-11-19 12:50 ` Juergen Beisert
2010-11-19 12:50 ` [PATCH 03/11] Bring in dynamic videomode selection at runtime Juergen Beisert
` (8 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Juergen Beisert @ 2010-11-19 12:50 UTC (permalink / raw)
To: barebox
In order to make video mode setup and initializing a runtime job (currently
it is a compile time job) this patch tries to make the 'fb_videomode' structure
more generic. It should also carry special settings required only for some LC
displays. So, I add some additional sync flags to control the DE and CLCK to
the display (something a regular CRT do not know). Also the possibility to
stop the clock when outside active display data (required for (C)STN).
Further suggestions for useful flags?
Signed-off-by: Juergen Beisert <jbe@pengutronix.de>
---
include/fb.h | 10 ++++++++++
1 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/include/fb.h b/include/fb.h
index 379f931..218b244 100644
--- a/include/fb.h
+++ b/include/fb.h
@@ -17,11 +17,21 @@
/* vtotal = 144d/288n/576i => PAL */
/* vtotal = 121d/242n/484i => NTSC */
#define FB_SYNC_ON_GREEN 32 /* sync on green */
+/* LC display related settings */
+#define FB_SYNC_DE_HIGH_ACT (1 << 6)
+#define FB_SYNC_CLK_INVERT (1 << 7)
+#define FB_SYNC_DATA_INVERT (1 << 8)
+#define FB_SYNC_CLK_IDLE_EN (1 << 9)
+#define FB_SYNC_SWAP_RGB (1 << 10)
+#define FB_SYNC_CLK_SEL_EN (1 << 11)
+#define FB_SYNC_SHARP_MODE (1 << 31)
#define FB_VMODE_NONINTERLACED 0 /* non interlaced */
#define FB_VMODE_INTERLACED 1 /* interlaced */
#define FB_VMODE_DOUBLE 2 /* double scan */
#define FB_VMODE_ODD_FLD_FIRST 4 /* interlaced: top line first */
+/* LC display related settings */
+#define FB_VMODE_DUAL_SCAN 8
#define FB_VMODE_MASK 255
#define FB_VMODE_YWRAP 256 /* ywrap instead of panning */
--
1.7.2.3
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 03/11] Bring in dynamic videomode selection at runtime
2010-11-19 12:50 [PATCHv3] Add dynamic video initialization to barebox Juergen Beisert
2010-11-19 12:50 ` [PATCH 01/11] Separate framebuffer platformdata and the videomode Juergen Beisert
2010-11-19 12:50 ` [PATCH 02/11] Add more flags for sync control Juergen Beisert
@ 2010-11-19 12:50 ` Juergen Beisert
2010-11-19 12:50 ` [PATCH 04/11] Add verbose framebuffer device info Juergen Beisert
` (7 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Juergen Beisert @ 2010-11-19 12:50 UTC (permalink / raw)
To: barebox
This patch mostly rewrites all parts of /drivers/video/fb.c. As it changes
the API to the drivers, it must be done in one step to keep the repository
bisectable. But to do it in one step makes the patches itself unreadable.
So, I decided to do it in a few steps, only for the review. All patches marked
with a "patch n of m" should be merged, prior the final commit onto the
repository.
This step brings in the required function for dynamic videomode selection at
runtime.
This is patch 1 of 4 to keep the repository bisectable.
Signed-off-by: Juergen Beisert <jbe@pengutronix.de>
---
drivers/video/fb.c | 201 +++++++++++++++++++++++++++++++++++++++++++++-------
include/fb.h | 31 ++++----
2 files changed, 192 insertions(+), 40 deletions(-)
diff --git a/drivers/video/fb.c b/drivers/video/fb.c
index ab2c5eb..5806dbe 100644
--- a/drivers/video/fb.c
+++ b/drivers/video/fb.c
@@ -1,3 +1,4 @@
+#include <init.h>
#include <common.h>
#include <fb.h>
#include <errno.h>
@@ -5,9 +6,14 @@
#include <getopt.h>
#include <fcntl.h>
#include <fs.h>
+#include <malloc.h>
+#include <xfuncs.h>
+
+#define to_fb_info(x) (container_of(x, struct fb_info, fb_dev))
static int fb_ioctl(struct cdev* cdev, int req, void *data)
{
+ struct fb_host *host = cdev->dev->platform_data;
struct fb_info *info = cdev->priv;
switch (req) {
@@ -15,10 +21,10 @@ static int fb_ioctl(struct cdev* cdev, int req, void *data)
memcpy(data, info, sizeof(*info));
break;
case FBIO_ENABLE:
- info->fbops->fb_enable(info);
+ host->fb_enable(cdev->priv);
break;
case FBIO_DISABLE:
- info->fbops->fb_disable(info);
+ host->fb_disable(cdev->priv);
break;
default:
return -ENOSYS;
@@ -27,15 +33,47 @@ static int fb_ioctl(struct cdev* cdev, int req, void *data)
return 0;
}
-static int fb_enable_set(struct device_d *dev, struct param_d *param,
- const char *val)
+static int fb_check_if_already_initialized(struct device_d *fb_dev)
+{
+ struct fb_info *info = to_fb_info(fb_dev);
+
+ if (info->enabled) {
+ dev_err(&info->fb_dev, "Video output is active. Cannot change "
+ "until disabled\n");
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+static int fb_cdepth_set(struct device_d *fb_dev, struct param_d *param, const char *val)
{
- struct fb_info *info = dev->priv;
+ struct fb_info *info = to_fb_info(fb_dev);
+ unsigned cdepth;
+ int rc;
+
+ rc = fb_check_if_already_initialized(fb_dev);
+ if (rc != 0)
+ return rc;
+
+ cdepth = simple_strtoul(val, NULL, 0);
+ if (cdepth != 0)
+ info->bits_per_pixel = cdepth;
+ else
+ return -EINVAL;
+
+ return dev_param_set_generic(fb_dev, param, val);
+}
+
+static int fb_enable_set(struct device_d *fb_dev, struct param_d *param, const char *val)
+{
+ struct fb_info *info = to_fb_info(fb_dev);
+ struct fb_host *host = info->host;
int enable;
char *new;
if (!val)
- return dev_param_set_generic(dev, param, NULL);
+ return dev_param_set_generic(fb_dev, param, NULL);
enable = simple_strtoul(val, NULL, 0);
@@ -43,20 +81,79 @@ static int fb_enable_set(struct device_d *dev, struct param_d *param,
return 0;
if (enable) {
- info->fbops->fb_enable(info);
+ host->fb_enable(info);
new = "1";
} else {
- info->fbops->fb_disable(info);
+ host->fb_disable(info);
new = "0";
}
- dev_param_set_generic(dev, param, new);
-
info->enabled = !!enable;
+ return dev_param_set_generic(fb_dev, param, new);
+}
+
+static void fb_list_modes(struct fb_host *host)
+{
+ unsigned u;
+
+ printf(" Supported video mode(s):\n");
+ for (u = 0; u < host->mode_cnt; u++)
+ printf(" '%s'\n", host->mode[u].name);
+}
+
+static int fb_activate_mode(struct device_d *fb_dev, const struct fb_videomode *mode)
+{
+ struct fb_info *info = to_fb_info(fb_dev);
+ struct fb_host *host = info->host;
+ int rc;
+
+ rc = host->fb_mode(info, mode);
+ if (rc != 0)
+ return rc;
+
+ info->active_mode = mode;
+ /*
+ * At this point of time we know the remaining information we need
+ * for the cdev and fb_info structure.
+ */
+ info->cdev.size = fb_dev->size;
+ info->xres = mode->xres;
+ info->yres = mode->yres;
+
return 0;
}
+static int fb_mode_set(struct device_d *fb_dev, struct param_d *param, const char *name)
+{
+ struct fb_host *host = fb_dev->platform_data;
+ unsigned u;
+ int rc;
+
+ pr_debug("%s called\n", __func__);
+
+ rc = fb_check_if_already_initialized(fb_dev);
+ if (rc != 0)
+ return rc;
+
+ /* Search for the requested video mode by name */
+ for (u = 0; u < host->mode_cnt; u++) {
+ if (!strcmp(host->mode[u].name, name))
+ break;
+ }
+ if (u >= host->mode_cnt) {
+ fb_list_modes(host); /* no mode with 'name' found */
+ return -ENODEV;
+ } else {
+ rc = fb_activate_mode(fb_dev, &host->mode[u]);
+ }
+
+ if (rc == 0)
+ dev_param_set_generic(fb_dev, param, name);
+
+ return rc;
+}
+
static struct file_operations fb_ops = {
.read = mem_read,
.write = mem_write,
@@ -65,31 +162,85 @@ static struct file_operations fb_ops = {
.ioctl = fb_ioctl,
};
-int register_framebuffer(struct fb_info *info)
+static int add_fb_parameter(struct fb_info *info)
+{
+ char cd[10];
+
+ /** @todo provide base address parameter for the user. Useful? */
+
+ dev_add_param(&info->fb_dev, "cdepth", fb_cdepth_set, NULL, 0);
+ if (info->bits_per_pixel == 0) {
+ dev_set_param(&info->fb_dev, "cdepth", "16");
+ info->bits_per_pixel = 16;
+ } else {
+ sprintf(cd, "%u", info->bits_per_pixel);
+ dev_set_param(&info->fb_dev, "cdepth", cd);
+ }
+
+ /* default is 'none' */
+ dev_add_param(&info->fb_dev, "mode", fb_mode_set, NULL, 0);
+
+ /* default is '0' for 'no output enabled' */
+ dev_add_param(&info->fb_dev, "enable", fb_enable_set, NULL, 0);
+
+ return 0;
+}
+
+static int fb_probe(struct device_d *fb_dev)
{
int id = get_free_deviceid("fb");
- struct device_d *dev;
+ struct fb_info *info = to_fb_info(fb_dev);
+ struct fb_host *host = info->host;
+
+ fb_dev->priv = &info->cdev; /* pointer forward */
+ info->cdev.dev = fb_dev; /* pointer backward */
+ info->cdev.priv = info; /* pointer backward */
info->cdev.ops = &fb_ops;
info->cdev.name = asprintf("fb%d", id);
- info->cdev.size = info->xres * info->yres * (info->bits_per_pixel >> 3);
- info->cdev.dev = &info->dev;
- info->cdev.priv = info;
- info->cdev.dev->map_base = (unsigned long)info->screen_base;
- info->cdev.dev->size = info->cdev.size;
- dev = &info->dev;
- dev->priv = info;
- dev->id = id;
+ info->host = host;
- sprintf(dev->name, "fb");
+ /* setup defaults */
+ if (host->bits_per_pixel != 0)
+ info->bits_per_pixel = host->bits_per_pixel;
+ else
+ info->bits_per_pixel = 16;
- register_device(&info->dev);
- dev_add_param(dev, "enable", fb_enable_set, NULL, 0);
- dev_set_param(dev, "enable", "0");
+ add_fb_parameter(info);
devfs_create(&info->cdev);
-
return 0;
}
+static struct driver_d fb_driver = {
+ .name = "framebuffer",
+ .probe = fb_probe,
+};
+
+static int framebuffer_init(void)
+{
+ return register_driver(&fb_driver);
+}
+
+device_initcall(framebuffer_init);
+
+struct device_d *register_framebuffer(struct fb_host *host)
+{
+ struct fb_info *fb_info;
+ int rc;
+
+ fb_info = xzalloc(sizeof(struct fb_info));
+
+ strcpy(fb_info->fb_dev.name, fb_driver.name);
+ fb_info->host = fb_info->fb_dev.platform_data = (void*)host;
+
+ rc = register_device(&fb_info->fb_dev);
+ if (rc != 0) {
+ pr_debug("Cannot register framebuffer device\n");
+ free(fb_info);
+ return NULL;
+ }
+
+ return &fb_info->fb_dev;
+}
diff --git a/include/fb.h b/include/fb.h
index 218b244..36b2a74 100644
--- a/include/fb.h
+++ b/include/fb.h
@@ -77,25 +77,26 @@ struct fb_bitfield {
struct fb_info;
-struct fb_ops {
- /* set color register */
- int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,
- unsigned blue, unsigned transp, struct fb_info *info);
- void (*fb_enable)(struct fb_info *info);
- void (*fb_disable)(struct fb_info *info);
-};
-
-struct fb_info {
- struct fb_videomode *mode;
+struct fb_host {
+ const struct fb_videomode *mode;
+ unsigned mode_cnt;
- struct fb_ops *fbops;
- struct device_d dev; /* This is this fb device */
+ struct device_d *hw_dev;
- void *screen_base;
+ /* callbacks into the video hardware driver */
+ int (*fb_setcolreg)(struct fb_info*, unsigned, unsigned, unsigned, unsigned, unsigned);
+ int (*fb_mode)(struct fb_info*, const struct fb_videomode*);
+ void (*fb_enable)(struct fb_info*);
+ void (*fb_disable)(struct fb_info*);
- void *priv;
+ unsigned bits_per_pixel;
+};
+struct fb_info {
+ struct fb_host *host;
+ struct device_d fb_dev;
struct cdev cdev;
+ const struct fb_videomode *active_mode;
u32 xres; /* visible resolution */
u32 yres;
@@ -111,7 +112,7 @@ struct fb_info {
int enabled;
};
-int register_framebuffer(struct fb_info *info);
+struct device_d *register_framebuffer(struct fb_host*);
#define FBIOGET_SCREENINFO _IOR('F', 1, loff_t)
#define FBIO_ENABLE _IO('F', 2)
--
1.7.2.3
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 04/11] Add verbose framebuffer device info
2010-11-19 12:50 [PATCHv3] Add dynamic video initialization to barebox Juergen Beisert
` (2 preceding siblings ...)
2010-11-19 12:50 ` [PATCH 03/11] Bring in dynamic videomode selection at runtime Juergen Beisert
@ 2010-11-19 12:50 ` Juergen Beisert
2010-11-19 12:50 ` [PATCH 05/11] Adapt the existing imx fb driver to support runtime videomode selection Juergen Beisert
` (6 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Juergen Beisert @ 2010-11-19 12:50 UTC (permalink / raw)
To: barebox
This is patch 2 of 4 to keep the repository bisectable.
Signed-off-by: Juergen Beisert <jbe@pengutronix.de>
---
drivers/video/Kconfig | 10 ++++++++++
drivers/video/fb.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 59 insertions(+), 0 deletions(-)
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 7a89a3f..b600444 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -5,6 +5,16 @@ menuconfig VIDEO
if VIDEO
+comment "runtime options"
+
+config VIDEO_INFO_VERBOSE
+ bool "Verbose video info"
+ help
+ Say 'y' here to be more verbose when running the 'devinfo' command
+ on the framebuffer device.
+
+comment "drivers"
+
config DRIVER_VIDEO_IMX
bool "i.MX framebuffer driver"
depends on ARCH_IMX1 || ARCH_IMX21 || ARCH_IMX25 || ARCH_IMX27
diff --git a/drivers/video/fb.c b/drivers/video/fb.c
index 5806dbe..d1ba85a 100644
--- a/drivers/video/fb.c
+++ b/drivers/video/fb.c
@@ -162,6 +162,54 @@ static struct file_operations fb_ops = {
.ioctl = fb_ioctl,
};
+static void fb_info(struct device_d *fb_dev)
+{
+ struct fb_info *info = to_fb_info(fb_dev);
+
+ printf(" Video/Mode info:\n");
+ printf(" Video output %senabled\n", info->enabled != 0 ? "" : "not ");
+ printf(" Current video mode:\n");
+ if (info->active_mode != NULL) {
+ printf(" Name: %s\n", info->active_mode->name);
+#ifdef CONFIG_VIDEO_INFO_VERBOSE
+ if (info->active_mode->refresh == 0)
+ printf(" Refresh rate: undefined\n");
+ else
+ printf(" Refresh rate: %u Hz\n",
+ info->active_mode->refresh);
+ printf(" Horizontal active pixel: %u\n",
+ info->active_mode->xres);
+ printf(" Vertical active lines: %u\n",
+ info->active_mode->yres);
+ printf(" Pixel clock: %u kHz\n",
+ PICOS2KHZ(info->active_mode->pixclock));
+ printf(" Left/Right margin (pixel): %u/%u\n",
+ info->active_mode->left_margin,
+ info->active_mode->right_margin);
+ printf(" Upper/Lower margin (lines): %u/%u\n",
+ info->active_mode->upper_margin,
+ info->active_mode->lower_margin);
+ printf(" HSYNC length in pixel: %u, polarity: %s\n",
+ info->active_mode->hsync_len,
+ (info->active_mode->sync & FB_SYNC_HOR_HIGH_ACT) ?
+ "high" : "low");
+ printf(" VSYNC length in lines: %u, polarity: %s\n",
+ info->active_mode->vsync_len,
+ (info->active_mode->sync & FB_SYNC_VERT_HIGH_ACT) ?
+ "high" : "low");
+ printf(" Colour depth: %u bpp\n", info->bits_per_pixel);
+ printf(" Framebuffer size is: %u bytes\n", info->cdev.size);
+ /** @todo Add the remaining information from fb_videomode.
+ * How valuable they are?
+ */
+#endif
+ } else {
+ printf (" No video mode selected yet\n");
+ }
+
+ fb_list_modes(info->host);
+}
+
static int add_fb_parameter(struct fb_info *info)
{
char cd[10];
@@ -216,6 +264,7 @@ static int fb_probe(struct device_d *fb_dev)
static struct driver_d fb_driver = {
.name = "framebuffer",
.probe = fb_probe,
+ .info = fb_info,
};
static int framebuffer_init(void)
--
1.7.2.3
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 05/11] Adapt the existing imx fb driver to support runtime videomode selection
2010-11-19 12:50 [PATCHv3] Add dynamic video initialization to barebox Juergen Beisert
` (3 preceding siblings ...)
2010-11-19 12:50 ` [PATCH 04/11] Add verbose framebuffer device info Juergen Beisert
@ 2010-11-19 12:50 ` Juergen Beisert
2010-11-19 12:50 ` [PATCH 06/11] Adapt the existing imx-ipu " Juergen Beisert
` (5 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Juergen Beisert @ 2010-11-19 12:50 UTC (permalink / raw)
To: barebox
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@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
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 06/11] Adapt the existing imx-ipu fb driver to support runtime videomode selection
2010-11-19 12:50 [PATCHv3] Add dynamic video initialization to barebox Juergen Beisert
` (4 preceding siblings ...)
2010-11-19 12:50 ` [PATCH 05/11] Adapt the existing imx fb driver to support runtime videomode selection Juergen Beisert
@ 2010-11-19 12:50 ` Juergen Beisert
2010-11-19 12:50 ` [PATCH 07/11] Remove variable size restrictions Juergen Beisert
` (4 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Juergen Beisert @ 2010-11-19 12:50 UTC (permalink / raw)
To: barebox
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 4 of 4 to keep the repository bisectable.
Signed-off-by: Juergen Beisert <jbe@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 | 217 +++++++++++++----------
4 files changed, 125 insertions(+), 108 deletions(-)
diff --git a/arch/arm/boards/freescale-mx35-3-stack/3stack.c b/arch/arm/boards/freescale-mx35-3-stack/3stack.c
index 127bfb4..d2b8262 100644
--- a/arch/arm/boards/freescale-mx35-3-stack/3stack.c
+++ b/arch/arm/boards/freescale-mx35-3-stack/3stack.c
@@ -126,7 +126,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 2191bc8..c504440 100644
--- a/arch/arm/boards/pcm043/pcm043.c
+++ b/arch/arm/boards/pcm043/pcm043.c
@@ -111,7 +111,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 c38082d..866d711 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)
+static int sdc_init_panel(struct fb_info *fb_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(fb_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 *fb_info,
enum ipu_channel channel, void *fbmem)
{
+ struct ipu_fb_info *fbi = fb_info_to_imxfb_info(fb_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 * ((fb_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(fb_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 fb_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 *fb_info, enum ipu_channel channel)
{
+ struct ipu_fb_info *fbi = fb_info_to_imxfb_info(fb_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(fb_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 *fb_info,
enum ipu_channel channel, void *buf)
{
+ struct ipu_fb_info *fbi = fb_info_to_imxfb_info(fb_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 *fb_info, enum ipu_channel channel,
void *buf)
{
+ struct ipu_fb_info *fbi = fb_info_to_imxfb_info(fb_info);
int ret;
- ipu_init_channel_buffer(fbi, channel, buf);
+ ipu_init_channel_buffer(fb_info, channel, buf);
/* ipu_idmac.c::ipu_submit_channel_buffers() */
- ret = ipu_update_channel_buffer(fbi, channel, buf);
+ ret = ipu_update_channel_buffer(fb_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(fb_info, channel);
return ret;
}
-static void sdc_enable_channel(struct ipu_fb_info *fbi, void *fbmem)
+static void sdc_enable_channel(struct fb_info *fb_info, void *fbmem)
{
+ struct ipu_fb_info *fbi = fb_info_to_imxfb_info(fb_info);
int ret;
u32 reg;
- ret = idmac_tx_submit(fbi, IDMAC_SDC_0, fbmem);
+ ret = idmac_tx_submit(fb_info, IDMAC_SDC_0, fbmem);
/* mx3fb.c::sdc_fb_init() */
if (ret >= 0) {
@@ -722,11 +730,75 @@ static void sdc_enable_channel(struct ipu_fb_info *fbi, void *fbmem)
mdelay(2);
}
+static void imxfb_init_info(struct fb_info *fb_info,
+ const struct fb_videomode *mode)
+{
+ struct imx_ipu_fb_rgb *rgb;
+
+ fb_info->xres = mode->xres;
+ fb_info->yres = mode->yres;
+
+ switch (fb_info->bits_per_pixel) {
+ case 32:
+ rgb = &def_rgb_32;
+ break;
+ case 24:
+ rgb = &def_rgb_24;
+ break;
+ case 16:
+ default:
+ rgb = &def_rgb_16;
+ break;
+ }
+
+ /*
+ * Copy the RGB parameters for this display
+ * from the machine specific parameters.
+ */
+ fb_info->red = rgb->red;
+ fb_info->green = rgb->green;
+ fb_info->blue = rgb->blue;
+ fb_info->transp = rgb->transp;
+}
+
+static void imxfb_memory_mmgt(struct fb_info *fb_info, unsigned size)
+{
+ if ((fb_info->fb_dev.size < size) && (fb_info->fb_dev.size != 0)) {
+ free((void*)fb_info->fb_dev.map_base);
+ fb_info->fb_dev.map_base = 0;
+ fb_info->fb_dev.size = 0;
+ }
+ if (fb_info->fb_dev.size == 0) {
+ fb_info->fb_dev.map_base = (resource_size_t)xzalloc(size);
+ fb_info->fb_dev.size = size;
+ }
+}
+
+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);
+
+ imxfb_memory_mmgt(fb_info, size);
+
+ fbi->mode = mode;
+
+ imxfb_init_info(fb_info, mode);
+
+ return 0;
+}
+
/* References in this function refer to respective Linux kernel sources */
-static void ipu_fb_enable(struct fb_info *info)
+static void ipu_fb_enable(struct fb_info *fb_info)
{
- struct ipu_fb_info *fbi = info->priv;
- struct fb_videomode *mode = info->mode;
+ struct ipu_fb_info *fbi = fb_info_to_imxfb_info(fb_info);
+ const struct fb_videomode *mode = fbi->mode;
u32 reg;
/* pcm037.c::mxc_board_init() */
@@ -779,12 +851,12 @@ static void ipu_fb_enable(struct fb_info *info)
~(SDC_COM_GWSEL | SDC_COM_KEY_COLOR_G);
reg_write(fbi, reg, SDC_COM_CONF);
- sdc_init_panel(info, IPU_PIX_FMT_RGB666);
+ sdc_init_panel(fb_info, IPU_PIX_FMT_RGB666);
reg_write(fbi, (mode->left_margin << 16) | mode->upper_margin,
SDC_BG_POS);
- sdc_enable_channel(fbi, info->screen_base);
+ sdc_enable_channel(fb_info, (void*)fb_info->fb_dev.map_base);
/*
* Linux driver calls sdc_set_brightness() here again,
@@ -796,7 +868,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;
if (fbi->enable)
@@ -807,85 +879,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 void imxfb_init_info(struct fb_info *info, struct fb_videomode *mode,
- int bpp)
-{
- struct imx_ipu_fb_rgb *rgb;
-
- info->mode = mode;
- info->xres = mode->xres;
- info->yres = mode->yres;
- info->bits_per_pixel = bpp;
-
- switch (info->bits_per_pixel) {
- case 32:
- rgb = &def_rgb_32;
- break;
- case 24:
- rgb = &def_rgb_24;
- break;
- case 16:
- default:
- rgb = &def_rgb_16;
- break;
- }
-
- /*
- * Copy the RGB parameters for this display
- * from the machine specific parameters.
- */
- info->red = rgb->red;
- info->green = rgb->green;
- info->blue = rgb->blue;
- info->transp = rgb->transp;
-}
-
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->fbops = &imxfb_ops;
- fbi->enable = pdata->enable;
- imxfb_init_info(info, pdata->mode, pdata->bpp);
+ /* 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;
dev_info(dev, "i.MX Framebuffer driver\n");
- /*
- * 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);
-
- ret = register_framebuffer(&fbi->info);
- if (ret < 0) {
+ fb_dev = register_framebuffer(&fbi->fb_host);
+ 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@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 07/11] Remove variable size restrictions
2010-11-19 12:50 [PATCHv3] Add dynamic video initialization to barebox Juergen Beisert
` (5 preceding siblings ...)
2010-11-19 12:50 ` [PATCH 06/11] Adapt the existing imx-ipu " Juergen Beisert
@ 2010-11-19 12:50 ` Juergen Beisert
2010-11-19 12:51 ` [PATCH 08/11] Add doxygen documentation to the framebfuffer code Juergen Beisert
` (3 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Juergen Beisert @ 2010-11-19 12:50 UTC (permalink / raw)
To: barebox
There is no really need for restricted variable types in these structures.
Replace them by standard C types with the same behaviour.
Signed-off-by: Juergen Beisert <jbe@pengutronix.de>
---
include/fb.h | 41 ++++++++++++++++++++---------------------
1 files changed, 20 insertions(+), 21 deletions(-)
diff --git a/include/fb.h b/include/fb.h
index 36b2a74..a1bd147 100644
--- a/include/fb.h
+++ b/include/fb.h
@@ -43,19 +43,19 @@
struct fb_videomode {
const char *name; /* optional */
- u32 refresh; /* optional */
- u32 xres;
- u32 yres;
- u32 pixclock;
- u32 left_margin;
- u32 right_margin;
- u32 upper_margin;
- u32 lower_margin;
- u32 hsync_len;
- u32 vsync_len;
- u32 sync;
- u32 vmode;
- u32 flag;
+ unsigned refresh; /* optional */
+ unsigned xres;
+ unsigned yres;
+ unsigned pixclock;
+ unsigned left_margin;
+ unsigned right_margin;
+ unsigned upper_margin;
+ unsigned lower_margin;
+ unsigned hsync_len;
+ unsigned vsync_len;
+ unsigned sync;
+ unsigned vmode;
+ unsigned flag;
};
/* Interpretation of offset for color fields: All offsets are from the right,
@@ -69,10 +69,9 @@ struct fb_videomode {
* of available palette entries (i.e. # of entries = 1 << length).
*/
struct fb_bitfield {
- u32 offset; /* beginning of bitfield */
- u32 length; /* length of bitfield */
- u32 msb_right; /* != 0 : Most significant bit is */
- /* right */
+ unsigned offset; /* beginning of bitfield */
+ unsigned length; /* length of bitfield */
+ int msb_right; /* != 0 : Most significant bit is right */
};
struct fb_info;
@@ -98,11 +97,11 @@ struct fb_info {
struct cdev cdev;
const struct fb_videomode *active_mode;
- u32 xres; /* visible resolution */
- u32 yres;
- u32 bits_per_pixel; /* guess what */
+ unsigned xres; /* visible resolution */
+ unsigned yres;
+ unsigned bits_per_pixel; /* guess what */
- u32 grayscale; /* != 0 Graylevels instead of colors */
+ int grayscale; /* != 0 Graylevels instead of colors */
struct fb_bitfield red; /* bitfield in fb mem if true color, */
struct fb_bitfield green; /* else only length is significant */
--
1.7.2.3
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 08/11] Add doxygen documentation to the framebfuffer code
2010-11-19 12:50 [PATCHv3] Add dynamic video initialization to barebox Juergen Beisert
` (6 preceding siblings ...)
2010-11-19 12:50 ` [PATCH 07/11] Remove variable size restrictions Juergen Beisert
@ 2010-11-19 12:51 ` Juergen Beisert
2010-11-19 12:51 ` [PATCH 09/11] Provide more driver specific data in a videomode Juergen Beisert
` (2 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Juergen Beisert @ 2010-11-19 12:51 UTC (permalink / raw)
To: barebox
Add some (hopefully) helpful documentation to the source code.
Signed-off-by: Juergen Beisert <jbe@pengutronix.de>
---
Documentation/developers_manual.dox | 1 +
Documentation/users_manual.dox | 1 +
drivers/video/fb.c | 202 +++++++++++++++++++++++++++++++++++
include/fb.h | 97 +++++++++++------
4 files changed, 269 insertions(+), 32 deletions(-)
diff --git a/Documentation/developers_manual.dox b/Documentation/developers_manual.dox
index 2f7d360..69a0872 100644
--- a/Documentation/developers_manual.dox
+++ b/Documentation/developers_manual.dox
@@ -20,5 +20,6 @@ This part of the documentation is intended for developers of @a barebox.
@li @subpage barebox_simul
@li @subpage io_access_functions
@li @subpage mcfv4e_MCDlib
+@li @subpage fb_for_developers
*/
diff --git a/Documentation/users_manual.dox b/Documentation/users_manual.dox
index ea47b18..58ec6e9 100644
--- a/Documentation/users_manual.dox
+++ b/Documentation/users_manual.dox
@@ -14,5 +14,6 @@ you find a lot of nice tricks on these pages to make your life easier.
@li @subpage readline_parser
@li @subpage x86_bootloader
@li @subpage net_netconsole
+@li @subpage fb_for_users
*/
diff --git a/drivers/video/fb.c b/drivers/video/fb.c
index d1ba85a..e330cd1 100644
--- a/drivers/video/fb.c
+++ b/drivers/video/fb.c
@@ -33,6 +33,11 @@ static int fb_ioctl(struct cdev* cdev, int req, void *data)
return 0;
}
+/**
+ * Check if the video output is already enabled
+ * @param fb_dev The framebuffer device to check
+ * @return 0 if the video output is still disabled, -EPERM if enabled
+ */
static int fb_check_if_already_initialized(struct device_d *fb_dev)
{
struct fb_info *info = to_fb_info(fb_dev);
@@ -46,6 +51,9 @@ static int fb_check_if_already_initialized(struct device_d *fb_dev)
return 0;
}
+/**
+ * Change colour depth via device parameter
+ */
static int fb_cdepth_set(struct device_d *fb_dev, struct param_d *param, const char *val)
{
struct fb_info *info = to_fb_info(fb_dev);
@@ -65,6 +73,9 @@ static int fb_cdepth_set(struct device_d *fb_dev, struct param_d *param, const c
return dev_param_set_generic(fb_dev, param, val);
}
+/**
+ * Enable/disable video output via device parameter
+ */
static int fb_enable_set(struct device_d *fb_dev, struct param_d *param, const char *val)
{
struct fb_info *info = to_fb_info(fb_dev);
@@ -93,6 +104,10 @@ static int fb_enable_set(struct device_d *fb_dev, struct param_d *param, const c
return dev_param_set_generic(fb_dev, param, new);
}
+/**
+ * Output the list of supported video modes in this framebuffer
+ * @param host Platformdata of the hardware video device
+ */
static void fb_list_modes(struct fb_host *host)
{
unsigned u;
@@ -102,6 +117,14 @@ static void fb_list_modes(struct fb_host *host)
printf(" '%s'\n", host->mode[u].name);
}
+/**
+ * Call the video hardware driver to initialize the given video mode
+ * @param fb_dev Framebuffer device
+ * @param mode Mode description to initialize
+ * @return 0 on success
+ *
+ * @note This call does not imply enabling the video output device!
+ */
static int fb_activate_mode(struct device_d *fb_dev, const struct fb_videomode *mode)
{
struct fb_info *info = to_fb_info(fb_dev);
@@ -124,6 +147,13 @@ static int fb_activate_mode(struct device_d *fb_dev, const struct fb_videomode *
return 0;
}
+/**
+ * Setup the requested video mode via device parameter
+ * @param dev Device instance
+ * @param param FIXME
+ * @param name Video mode name to activate
+ * @return 0 on success
+ */
static int fb_mode_set(struct device_d *fb_dev, struct param_d *param, const char *name)
{
struct fb_host *host = fb_dev->platform_data;
@@ -210,6 +240,11 @@ static void fb_info(struct device_d *fb_dev)
fb_list_modes(info->host);
}
+/**
+ * Add controlling parameters to the framebuffer device
+ * @param dev Device instance
+ * @return 0 on success
+ */
static int add_fb_parameter(struct fb_info *info)
{
char cd[10];
@@ -274,6 +309,11 @@ static int framebuffer_init(void)
device_initcall(framebuffer_init);
+/**
+ * Create a new framebuffer device
+ * @param pinfo Video device's platform data for this framebuffer device
+ * @return Pointer to the newly created device or NULL on failure
+ */
struct device_d *register_framebuffer(struct fb_host *host)
{
struct fb_info *fb_info;
@@ -293,3 +333,165 @@ struct device_d *register_framebuffer(struct fb_host *host)
return &fb_info->fb_dev;
}
+
+/**
+@page fb_for_users Framebuffer handling for users
+
+@section delayed_fb Framebuffer setup
+
+If the platform supports more than one video output device, its possible to select
+one of the supported ones at runtime. To do so, no videomode setup happens when
+the graphics driver gets registered. The device offers the 'mode' parameter to
+support specifiying the correct output device. But keep in mind that there will
+be also no framebuffer memory until the output video hardware and its videomode
+get specified. This is important to know, if you want to paint some nice splash
+screen.
+
+Running the @b devinfo command on the framebuffer0 device will output:
+@verbatim
+barebox:/ devinfo framebuffer0
+base : 0x00000000
+size : 0x00000000
+driver: framebuffer
+
+ Video/Mode info:
+ Video output not enabled
+ Current video mode:
+ No video mode selected yet
+ Supported video mode(s):
+ 'QVGA'
+ 'VGA'
+Parameters:
+ cdepth = 16
+ mode = <NULL>
+ enable = <NULL>
+@endverbatim
+
+@note As long @b devinfo reports a @b base or @b size of zero there is
+@b no framebuffer memory yet!
+
+This framebuffer device is not initialized yet. As shown in the list, it
+supports two video modes: 'QVGA' and 'VGA'.
+
+So, the user can first specifiy the video output device with (for example)
+@verbatim
+barebox:/ framebuffer0.mode="QVGA"
+@endverbatim
+
+After this the @b devinfo command's output changes to:
+@verbatim
+barebox:/ devinfo framebuffer0
+base : 0x31fc0000
+size : 0x00040000
+driver: framebuffer
+
+ Video/Mode info:
+ Video output not enabled
+ Current video mode:
+ Name: QVGA
+ Refresh rate: 60 Hz
+ Horizontal active pixel: 320
+ Vertical active lines: 240
+ Pixel clock: 6500 kHz
+ Left/Right margin (pixel): 20/20
+ Upper/Lower margin (lines): 10/10
+ HSYNC length in pixel: 10, polarity: high
+ VSYNC length in lines: 5, polarity: high
+ Colour depth: 16 bpp
+ Supported video mode(s):
+ 'QVGA'
+ 'VGA'
+Parameters:
+ cdepth = 16
+ mode = QVGA
+ enable = <NULL>
+@endverbatim
+As one can see, the framebuffer has a @b base, a @b size and a @b mode
+configuration now.
+@note Take care if setting a video mode fails. In this case @b base and @b size
+will kept at zero!
+
+With this setting its possible to paint some kind of image into the framebuffer
+memory and enabling the video output as the final step at runtime
+@verbatim
+barebox:/ framebuffer0.enable=1
+@endverbatim
+The video output is fully enabled now:
+@verbatim
+barebox:/ devinfo framebuffer0
+base : 0x31fc0000
+size : 0x00040000
+driver: framebuffer
+
+ Video/Mode info:
+ Video output enabled
+ Current video mode:
+ Name: QVGA
+ Refresh rate: 60 Hz
+ Horizontal active pixel: 320
+ Vertical active lines: 240
+ Pixel clock: 6500 kHz
+ Left/Right margin (pixel): 20/20
+ Upper/Lower margin (lines): 10/10
+ HSYNC length in pixel: 10, polarity: high
+ VSYNC length in lines: 5, polarity: high
+ Colour depth: 16 bpp
+ Supported video mode(s):
+ 'QVGA'
+ 'VGA'
+Parameters:
+ cdepth = 16
+ mode = QVGA
+ enable = 1
+@endverbatim
+
+@section other_fb_params Other framebuffer parameter
+@verbatim
+framebuffer0.cdepth=[1 | 4 | 8 | 16 | 24 | 32]
+@endverbatim
+
+Colour depth to be used with the framebuffer. Its unit is "bit per pixel" and
+the default value is 16 bits per pixel (means "RGB565" format). This value can
+only be changed if the video output is disabled.
+
+@note The possible values from the list above are hardware dependend.
+
+@note The default colour depth value may also depend on the hardware
+*/
+
+/**
+@page fb_for_developers Framebuffer handling for developers
+
+@section fb_platform_dev For the platform developer
+
+If you provide more than one video output device description use an array of
+this type. In this case the 'mode_cnt' entry must contain the count of existing
+array entries (> 1). Give each video output device description entry an unique
+name, because a user will select the required output device by this name
+at runtime.
+
+@section fb_driver_dev For the video hardware driver developer:
+
+Don't initialize a special video mode in your probe function (e.g. don't
+allocate any framebuffer memory and so on). The framework will call back your
+exported fb_mode() function to do so (immediately or delayed).
+
+Don't enable video output in your probe or exported fb_mode() function. Also
+do not switch on any LCD or backlight if any. The framework will call your
+exported fb_enable() function to do so.
+
+If your hardware cannot handle the default 16 bit colour depth, change the
+'bits_per_pixel' field prior registering your framebuffer.
+
+When your exported fb_mode() function is called, calculate the amount of memory
+you need for the requested video mode and colour depth, save this value to
+framebuffer's info struct in field 'fb_dev->size' and allocate the memory with
+this size for the framebuffer. Store the basepointer to this area into
+framebuffer's info struct in field 'fb_dev->map_base'.
+
+@note To support flickerless splash screen into the Linux kernel, your driver
+should support a fixed framebuffer memory. Fixed in location and size. The platform
+should hold the Linux kernel to not touch this memory in any way. Instead the
+kernel based video hardware driver should inherit the fixed settings.
+
+*/
diff --git a/include/fb.h b/include/fb.h
index a1bd147..7e01e87 100644
--- a/include/fb.h
+++ b/include/fb.h
@@ -18,19 +18,27 @@
/* vtotal = 121d/242n/484i => NTSC */
#define FB_SYNC_ON_GREEN 32 /* sync on green */
/* LC display related settings */
+/** LC display uses active high data enable signal */
#define FB_SYNC_DE_HIGH_ACT (1 << 6)
+/** LC display will latch its data at clock's rising edge */
#define FB_SYNC_CLK_INVERT (1 << 7)
+/** output RGB data inverted */
#define FB_SYNC_DATA_INVERT (1 << 8)
+/** Stop clock if no data is sent (required for passive displays) */
#define FB_SYNC_CLK_IDLE_EN (1 << 9)
+/** swap RGB to BGR */
#define FB_SYNC_SWAP_RGB (1 << 10)
+/** FIXME */
#define FB_SYNC_CLK_SEL_EN (1 << 11)
+/** enable special signals for SHARP displays (_very_ hardware specific) */
#define FB_SYNC_SHARP_MODE (1 << 31)
-#define FB_VMODE_NONINTERLACED 0 /* non interlaced */
-#define FB_VMODE_INTERLACED 1 /* interlaced */
+#define FB_VMODE_NONINTERLACED 0 /** non interlaced */
+#define FB_VMODE_INTERLACED 1 /** interlaced */
#define FB_VMODE_DOUBLE 2 /* double scan */
-#define FB_VMODE_ODD_FLD_FIRST 4 /* interlaced: top line first */
+#define FB_VMODE_ODD_FLD_FIRST 4 /** interlaced: top line first */
/* LC display related settings */
+/** output two screen parts at once (required for passive displays) */
#define FB_VMODE_DUAL_SCAN 8
#define FB_VMODE_MASK 255
@@ -42,19 +50,24 @@
#define KHZ2PICOS(a) (1000000000UL/(a))
struct fb_videomode {
- const char *name; /* optional */
- unsigned refresh; /* optional */
- unsigned xres;
- unsigned yres;
- unsigned pixclock;
- unsigned left_margin;
- unsigned right_margin;
- unsigned upper_margin;
- unsigned lower_margin;
- unsigned hsync_len;
- unsigned vsync_len;
- unsigned sync;
- unsigned vmode;
+ const char *name; /**< always required and must be unique */
+ unsigned refresh; /**< frame refresh rate in [Hz] (optional) */
+ unsigned xres; /**< visible horizontal pixel */
+ unsigned yres; /**< visible vertical pixel */
+ unsigned pixclock; /**< pixel clock period in [ps]. Refer
+ PICOS2KHZ/KHZ2PICOS macros */
+ unsigned left_margin; /**< distance in pixels between ending active HSYNC
+ and starting visible line content */
+ unsigned right_margin; /**< distance in pixels between ending visible line
+ content and starting active HSYNC */
+ unsigned upper_margin; /**< distance in lines between ending active VSYNC
+ and the first line with visible content */
+ unsigned lower_margin; /**< distance in lines between last line with
+ visible content and starting active VSYNC */
+ unsigned hsync_len; /**< HSYNC's active length in pixels */
+ unsigned vsync_len; /**< VSYNC's active lenght in lines */
+ unsigned sync; /**< sync information, refer FB_SYNC_* macros */
+ unsigned vmode; /**< video mode information, refer FB_VMODE_* macros */
unsigned flag;
};
@@ -69,18 +82,33 @@ struct fb_videomode {
* of available palette entries (i.e. # of entries = 1 << length).
*/
struct fb_bitfield {
- unsigned offset; /* beginning of bitfield */
- unsigned length; /* length of bitfield */
- int msb_right; /* != 0 : Most significant bit is right */
+ unsigned offset; /**< beginning of bitfield */
+ unsigned length; /**< length of bitfield */
+ int msb_right; /**< != 0 : Most significant bit is right */
};
struct fb_info;
+/**
+ * Framebuffer device's platform information
+ *
+ * The video hardware driver must set the following fields:
+ * - 'fb_mode' function to setup a specific video mode
+ * - 'fb_enable' function to activate the video output
+ * - 'fb_disable' function to deactivate the video output
+ * - 'fb_setcolreg' function to ???????? FIXME
+ *
+ * The video hardware driver can set default values for the following fields:
+ * - 'mode' if the driver supports only specific video modes.
+ * - 'mode_cnt' must be set, if 'mode_list' is given
+ * - 'bits_per_pixel' if the video hardware driver defaults to another bpp than 16
+ */
struct fb_host {
- const struct fb_videomode *mode;
- unsigned mode_cnt;
+ /* information about possible video mode(s) */
+ const struct fb_videomode *mode; /**< Array of modes */
+ unsigned mode_cnt; /**< count of entries in 'mode'. */
- struct device_d *hw_dev;
+ struct device_d *hw_dev; /**< the host device */
/* callbacks into the video hardware driver */
int (*fb_setcolreg)(struct fb_info*, unsigned, unsigned, unsigned, unsigned, unsigned);
@@ -88,25 +116,30 @@ struct fb_host {
void (*fb_enable)(struct fb_info*);
void (*fb_disable)(struct fb_info*);
- unsigned bits_per_pixel;
+ unsigned bits_per_pixel; /**< default bpp, 0 = use framebuffer's default */
};
+/**
+ * Framebuffer's runtime information
+ */
struct fb_info {
- struct fb_host *host;
- struct device_d fb_dev;
+ struct fb_host *host; /**< host data this fb is based on */
+ struct device_d fb_dev; /**< the framebuffer device */
struct cdev cdev;
+ /* information about current video mode */
+ /** the currently active video mode if set. Can be NULL = no video mode set yet */
const struct fb_videomode *active_mode;
- unsigned xres; /* visible resolution */
- unsigned yres;
- unsigned bits_per_pixel; /* guess what */
+ unsigned xres; /**< visible horizontal pixel count */
+ unsigned yres; /**< visible vertical line count */
+ unsigned bits_per_pixel; /**< visible colour depth */
- int grayscale; /* != 0 Graylevels instead of colors */
+ int grayscale; /**< != 0 Graylevels instead of colors */
- struct fb_bitfield red; /* bitfield in fb mem if true color, */
- struct fb_bitfield green; /* else only length is significant */
+ struct fb_bitfield red; /**< bitfield in fb mem if true color, */
+ struct fb_bitfield green; /**< else only length is significant */
struct fb_bitfield blue;
- struct fb_bitfield transp; /* transparency */
+ struct fb_bitfield transp; /**< transparency */
int enabled;
};
--
1.7.2.3
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 09/11] Provide more driver specific data in a videomode
2010-11-19 12:50 [PATCHv3] Add dynamic video initialization to barebox Juergen Beisert
` (7 preceding siblings ...)
2010-11-19 12:51 ` [PATCH 08/11] Add doxygen documentation to the framebfuffer code Juergen Beisert
@ 2010-11-19 12:51 ` Juergen Beisert
2010-11-19 12:51 ` [PATCH 10/11] Add a video driver for S3C2440 bases platforms Juergen Beisert
2010-11-19 12:51 ` [PATCH 11/11] STM378x: Add video driver for this platform Juergen Beisert
10 siblings, 0 replies; 12+ messages in thread
From: Juergen Beisert @ 2010-11-19 12:51 UTC (permalink / raw)
To: barebox
In order to support more than one videomode in a binary barebox, some drivers
need more specific data to setup the requested video mode in a correct manner.
This patch adds the 'priv' field to the generic videomode description to give
any platform a chance to forward some video hardware specific information on
a per videomode base.
This is currently i.MX21/i.MX25/i.MX27 specific.
BTW: At least the 'pcr' value could be generated at runtime from the 'sync'
field in 'struct fb_videomode'.
Signed-off-by: Juergen Beisert <jbe@pengutronix.de>
---
arch/arm/boards/eukrea_cpuimx25/eukrea_cpuimx25.c | 21 +++++-----
arch/arm/boards/eukrea_cpuimx27/eukrea_cpuimx27.c | 21 +++++-----
arch/arm/boards/guf-neso/board.c | 45 +++++++++++----------
arch/arm/boards/imx21ads/imx21ads.c | 24 ++++++------
arch/arm/boards/pcm038/pcm038.c | 40 +++++++++---------
arch/arm/mach-imx/include/mach/imxfb.h | 20 +++++----
drivers/video/imx.c | 19 +++++----
include/fb.h | 2 +
8 files changed, 99 insertions(+), 93 deletions(-)
diff --git a/arch/arm/boards/eukrea_cpuimx25/eukrea_cpuimx25.c b/arch/arm/boards/eukrea_cpuimx25/eukrea_cpuimx25.c
index 2b53766..a2bbaa3 100644
--- a/arch/arm/boards/eukrea_cpuimx25/eukrea_cpuimx25.c
+++ b/arch/arm/boards/eukrea_cpuimx25/eukrea_cpuimx25.c
@@ -107,7 +107,14 @@ struct imx_nand_platform_data nand_info = {
.hw_ecc = 1,
};
-static struct fb_videomode cmo_display = {
+static const struct imx_fb_driver_data driver_data = {
+ .pwmr = 0x00A903FF,
+ .lscr1 = 0x00120300,
+ .dmacr = 0x80040060,
+ .pcr = 0xCAD08B80,
+};
+
+static const struct fb_videomode cmo_display = {
.name = "CMO-QVGA",
.refresh = 60,
.xres = 320,
@@ -121,17 +128,9 @@ static struct fb_videomode cmo_display = {
.lower_margin = 4,
};
-static struct imx_fb_videomode imxfb_mode = {
- .mode = &cmo_display,
- .pcr = 0xCAD08B80,
- .bpp = 16,
-};
-
static struct imx_fb_platform_data eukrea_cpuimx25_fb_data = {
- .mode = &imxfb_mode,
- .pwmr = 0x00A903FF,
- .lscr1 = 0x00120300,
- .dmacr = 0x80040060,
+ .mode = &cmo_display,
+ .mode_cnt = 1,
};
#ifdef CONFIG_USB
diff --git a/arch/arm/boards/eukrea_cpuimx27/eukrea_cpuimx27.c b/arch/arm/boards/eukrea_cpuimx27/eukrea_cpuimx27.c
index 3ee1057..b162611 100644
--- a/arch/arm/boards/eukrea_cpuimx27/eukrea_cpuimx27.c
+++ b/arch/arm/boards/eukrea_cpuimx27/eukrea_cpuimx27.c
@@ -167,7 +167,14 @@ static void eukrea_cpuimx27_mmu_init(void)
#endif
#ifdef CONFIG_DRIVER_VIDEO_IMX
-static struct fb_videomode cmo_display = {
+static const struct imx_fb_driver_data driver_data = {
+ .pwmr = 0x00A903FF,
+ .lscr1 = 0x00120300,
+ .dmacr = 0x00020010,
+ .pcr = 0xFAD08B80,
+};
+
+static const struct fb_videomode cmo_display = {
.name = "CMO-QVGA",
.refresh = 60,
.xres = 320,
@@ -179,18 +186,12 @@ static struct fb_videomode cmo_display = {
.vsync_len = 3,
.upper_margin = 15,
.lower_margin = 4,
+ .priv = &driver_data,
};
-static struct imx_fb_videomode imxfb_mode = {
- .mode = &cmo_display,
- .pcr = 0xFAD08B80,
- .bpp = 16,};
-
static struct imx_fb_platform_data eukrea_cpuimx27_fb_data = {
- .mode = &imxfb_mode,
- .pwmr = 0x00A903FF,
- .lscr1 = 0x00120300,
- .dmacr = 0x00020010,
+ .mode = &cmo_display,
+ .mode_cnt = 1,
};
static struct device_d imxfb_dev = {
diff --git a/arch/arm/boards/guf-neso/board.c b/arch/arm/boards/guf-neso/board.c
index fba43bb..0c7a9fa 100644
--- a/arch/arm/boards/guf-neso/board.c
+++ b/arch/arm/boards/guf-neso/board.c
@@ -78,22 +78,11 @@ static struct imx_nand_platform_data nand_info = {
.flash_bbt = 1,
};
-static struct fb_videomode cpt_display = {
- .name = "CPT CLAA070LC0JCT",
- .refresh = 60,
- .xres = 800,
- .yres = 480,
- .pixclock = KHZ2PICOS(27000),
- .hsync_len = 1, /* DE only sync */
- .left_margin = 50,
- .right_margin = 50,
- .vsync_len = 1, /* DE only sync */
- .upper_margin = 10,
- .lower_margin = 10,
-};
-
-static struct imx_fb_videomode imxfb_mode = {
- .mode = &cpt_display,
+static const struct imx_fb_driver_data driver_data = {
+ .pwmr = 0x00000000, /* doesn't matter */
+ .lscr1 = 0x00120300, /* doesn't matter */
+ /* dynamic mode -> using the reset values (as recommended in the datasheet) */
+ .dmacr = (0 << 31) | (4 << 16) | 96,
/*
* - TFT style panel
* - clk enabled while idle
@@ -109,7 +98,21 @@ static struct imx_fb_videomode imxfb_mode = {
PCR_SCLK_SEL |
PCR_LPPOL |
PCR_FLMPOL,
- .bpp = 16, /* TODO 32 bit does not work: The 'green' component is lacking in this mode */
+};
+
+static struct fb_videomode cpt_display = {
+ .name = "CPT CLAA070LC0JCT",
+ .refresh = 60,
+ .xres = 800,
+ .yres = 480,
+ .pixclock = KHZ2PICOS(27000),
+ .hsync_len = 1, /* DE only sync */
+ .left_margin = 50,
+ .right_margin = 50,
+ .vsync_len = 1, /* DE only sync */
+ .upper_margin = 10,
+ .lower_margin = 10,
+ .priv = &driver_data,
};
static void neso_fb_enable(int enable)
@@ -119,12 +122,10 @@ static void neso_fb_enable(int enable)
}
static struct imx_fb_platform_data neso_fb_data = {
- .mode = &imxfb_mode,
- .pwmr = 0x00000000, /* doesn't matter */
- .lscr1 = 0x00120300, /* doesn't matter */
- /* dynamic mode -> using the reset values (as recommended in the datasheet) */
- .dmacr = (0 << 31) | (4 << 16) | 96,
+ .mode = &cpt_display,
+ .mode_cnt = 1,
.enable = neso_fb_enable,
+ .bpp = 16, /* TODO 32 bit does not work: The 'green' component is lacking in this mode */
.framebuffer_ovl = (void *)0xa7f00000,
};
diff --git a/arch/arm/boards/imx21ads/imx21ads.c b/arch/arm/boards/imx21ads/imx21ads.c
index 8e145c7..299a3cd 100644
--- a/arch/arm/boards/imx21ads/imx21ads.c
+++ b/arch/arm/boards/imx21ads/imx21ads.c
@@ -73,7 +73,14 @@ static struct device_d cs8900_dev = {
// IRQ is connected to UART3_RTS
};
-static struct fb_videomode sharp_display = {
+static const struct imx_fb_driver_data driver_data = {
+ .pwmr = 0x00a903ff,
+ .lscr1 = 0x00120300,
+ .dmacr = 0x00020008,
+ .pcr = 0xfb108bc7,
+};
+
+static const struct fb_videomode sharp_display = {
.name = "Sharp-LQ035Q7",
.refresh = 60,
.xres = 240,
@@ -88,23 +95,16 @@ static struct fb_videomode sharp_display = {
.sync = 0,
.vmode = FB_VMODE_NONINTERLACED,
.flag = 0,
-};
-
-/* Sharp LQ035Q7DB02 QVGA display */
-static struct imx_fb_videomode imx_fb_modedata = {
- .mode = &sharp_display,
- .pcr = 0xfb108bc7,
- .bpp = 16,
+ .priv = &driver_data,
};
static struct imx_fb_platform_data imx_fb_data = {
- .mode = &imx_fb_modedata,
+/* Sharp LQ035Q7DB02 QVGA display */
+ .mode = &sharp_display,
+ .mode_cnt = 1,
.cmap_greyscale = 0,
.cmap_inverse = 0,
.cmap_static = 0,
- .pwmr = 0x00a903ff,
- .lscr1 = 0x00120300,
- .dmacr = 0x00020008,
};
static int imx21ads_timing_init(void)
diff --git a/arch/arm/boards/pcm038/pcm038.c b/arch/arm/boards/pcm038/pcm038.c
index 8cbb551..d5269f1 100644
--- a/arch/arm/boards/pcm038/pcm038.c
+++ b/arch/arm/boards/pcm038/pcm038.c
@@ -107,7 +107,23 @@ static struct imx_nand_platform_data nand_info = {
.flash_bbt = 1,
};
-static struct fb_videomode sharp_display = {
+static const struct imx_fb_driver_data driver_data = {
+ /*
+ * - HSYNC active high
+ * - VSYNC active high
+ * - clk notenabled while idle
+ * - clock not inverted
+ * - data not inverted
+ * - data enable low active
+ * - enable sharp mode
+ */
+ .pwmr = 0x00A903FF,
+ .lscr1 = 0x00120300,
+ .dmacr = 0x00020010,
+ .pcr = 0xF00080C0,
+};
+
+static const struct fb_videomode sharp_display = {
.name = "Sharp-LQ035Q7",
.refresh = 60,
.xres = 240,
@@ -119,28 +135,12 @@ static struct fb_videomode sharp_display = {
.vsync_len = 1,
.upper_margin = 7,
.lower_margin = 9,
-};
-
-static struct imx_fb_videomode imxfb_mode = {
- .mode = &sharp_display,
- /*
- * - HSYNC active high
- * - VSYNC active high
- * - clk notenabled while idle
- * - clock not inverted
- * - data not inverted
- * - data enable low active
- * - enable sharp mode
- */
- .pcr = 0xF00080C0,
- .bpp = 16,
+ .priv = &driver_data,
};
static struct imx_fb_platform_data pcm038_fb_data = {
- .mode = &imxfb_mode,
- .pwmr = 0x00A903FF,
- .lscr1 = 0x00120300,
- .dmacr = 0x00020010,
+ .mode = &sharp_display,
+ .mode_cnt = 1,
};
#ifdef CONFIG_USB
diff --git a/arch/arm/mach-imx/include/mach/imxfb.h b/arch/arm/mach-imx/include/mach/imxfb.h
index 4a890a7..f2083c4 100644
--- a/arch/arm/mach-imx/include/mach/imxfb.h
+++ b/arch/arm/mach-imx/include/mach/imxfb.h
@@ -52,28 +52,30 @@
#define DMACR_HM(x) (((x) & 0xf) << 16)
#define DMACR_TM(x) ((x) & 0xf)
-struct imx_fb_videomode {
- struct fb_videomode *mode;
- u32 pcr;
- unsigned char bpp;
+/**
+ * Videomode dependent, but driver specific data
+ */
+struct imx_fb_driver_data {
+ uint32_t pwmr; /**< refer datasheet: LPCCR register */
+ uint32_t lscr1; /**< refer datasheet: LSCR register */
+ uint32_t dmacr; /**< refer datasheet: LDCR register */
+ uint32_t pcr; /**< refer datasheet: LPCR register */
};
/**
* Define relevant framebuffer information
*/
struct imx_fb_platform_data {
- struct imx_fb_videomode *mode;
+ const struct fb_videomode *mode;
unsigned mode_cnt; /**< number of entries in 'mode' */
+ unsigned char bpp; /**< preferred colour depth for this device */
+
u_int cmap_greyscale:1,
cmap_inverse:1,
cmap_static:1,
unused:29;
- u_int pwmr;
- u_int lscr1;
- u_int dmacr;
-
/** force a memory area to be used, else NULL for dynamic allocation */
void *framebuffer;
/** force a memory area to be used, else NULL for dynamic allocation */
diff --git a/drivers/video/imx.c b/drivers/video/imx.c
index b13f39d..69ba3e7 100644
--- a/drivers/video/imx.c
+++ b/drivers/video/imx.c
@@ -332,6 +332,7 @@ static int imxfb_initialize_mode(struct fb_info *info,
unsigned long lcd_clk;
unsigned long long tmp;
struct imxfb_info *fbi = fb_info_to_imxfb_info(info);
+ const struct imx_fb_driver_data *drv_data = mode->priv;
u32 pcr;
unsigned size;
@@ -342,6 +343,11 @@ static int imxfb_initialize_mode(struct fb_info *info,
imxfb_memory_mmgt(info, size, MAIN_FBUFFER);
+ fbi->pcr = drv_data->pcr;
+ fbi->pwmr = drv_data->pwmr;
+ fbi->lscr1 = drv_data->lscr1;
+ fbi->dmacr = drv_data->dmacr;
+
/* physical screen start address */
writel(VPW_VPW(mode->xres * info->bits_per_pixel / 8 / 4),
fbi->regs + LCDC_VPW);
@@ -541,7 +547,7 @@ static int imxfb_register_overlay(struct imxfb_info *fbi,
overlay->fb_setcolreg = imxfb_overlay_setcolreg;
/* add runtime video info */
- overlay->mode = pdata->mode->mode;
+ overlay->mode = pdata->mode;
overlay->mode_cnt = 1; /* no choice */
overlay_dev = register_framebuffer(overlay);
@@ -591,17 +597,12 @@ static int imxfb_probe(struct device_d *dev)
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;
/* 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 */
+ fbi->fb_host.mode = pdata->mode;
+ fbi->fb_host.mode_cnt = pdata->mode_cnt;
+ fbi->fb_host.bits_per_pixel = pdata->bpp;
fb_dev = register_framebuffer(&fbi->fb_host);
if (dev == NULL) {
diff --git a/include/fb.h b/include/fb.h
index 7e01e87..a9ad447 100644
--- a/include/fb.h
+++ b/include/fb.h
@@ -69,6 +69,8 @@ struct fb_videomode {
unsigned sync; /**< sync information, refer FB_SYNC_* macros */
unsigned vmode; /**< video mode information, refer FB_VMODE_* macros */
unsigned flag;
+
+ const void *priv; /**< video driver related information */
};
/* Interpretation of offset for color fields: All offsets are from the right,
--
1.7.2.3
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 10/11] Add a video driver for S3C2440 bases platforms
2010-11-19 12:50 [PATCHv3] Add dynamic video initialization to barebox Juergen Beisert
` (8 preceding siblings ...)
2010-11-19 12:51 ` [PATCH 09/11] Provide more driver specific data in a videomode Juergen Beisert
@ 2010-11-19 12:51 ` Juergen Beisert
2010-11-19 12:51 ` [PATCH 11/11] STM378x: Add video driver for this platform Juergen Beisert
10 siblings, 0 replies; 12+ messages in thread
From: Juergen Beisert @ 2010-11-19 12:51 UTC (permalink / raw)
To: barebox; +Cc: Juergen Beisert
From: Juergen Beisert <juergen@kreuzholzen.de>
Signed-off-by: Juergen Beisert <juergen@kreuzholzen.de>
---
arch/arm/mach-s3c24xx/include/mach/fb.h | 40 +++
drivers/video/Kconfig | 6 +
drivers/video/Makefile | 1 +
drivers/video/s3c.c | 474 +++++++++++++++++++++++++++++++
4 files changed, 521 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-s3c24xx/include/mach/fb.h
create mode 100644 drivers/video/s3c.c
diff --git a/arch/arm/mach-s3c24xx/include/mach/fb.h b/arch/arm/mach-s3c24xx/include/mach/fb.h
new file mode 100644
index 0000000..eec6164
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/include/mach/fb.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 Juergen Beisert
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#ifndef __MACH_FB_H_
+# define __MACH_FB_H_
+
+#include <fb.h>
+
+struct s3c_fb_platform_data {
+
+ const struct fb_videomode *mode_list;
+ unsigned mode_cnt;
+
+ int passive_display; /**< enable support for STN or CSTN displays */
+
+ void *framebuffer; /**< force framebuffer base address */
+ unsigned size; /**< force framebuffer size */
+
+ /** hook to enable backlight and stuff */
+ void (*enable)(int);
+};
+
+#endif /* __MACH_FB_H_ */
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index b600444..f43c100 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -30,4 +30,10 @@ config DRIVER_VIDEO_IMX_IPU
Add support for the IPU framebuffer device found on
i.MX31 and i.MX35 CPUs.
+config S3C_VIDEO
+ bool "S3C244x framebuffer driver"
+ depends on ARCH_S3C24xx
+ help
+ Add support for the S3C244x LCD controller.
+
endif
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 179f0c4..4287fc8 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -2,3 +2,4 @@ obj-$(CONFIG_VIDEO) += fb.o
obj-$(CONFIG_DRIVER_VIDEO_IMX) += imx.o
obj-$(CONFIG_DRIVER_VIDEO_IMX_IPU) += imx-ipu-fb.o
+obj-$(CONFIG_S3C_VIDEO) += s3c.o
diff --git a/drivers/video/s3c.c b/drivers/video/s3c.c
new file mode 100644
index 0000000..c831ebd
--- /dev/null
+++ b/drivers/video/s3c.c
@@ -0,0 +1,474 @@
+/*
+ * Copyright (C) 2010 Juergen Beisert
+ *
+ * This driver is based on a patch found in the web:
+ * (C) Copyright 2006 by OpenMoko, Inc.
+ * Author: Harald Welte <laforge at openmoko.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <fb.h>
+#include <driver.h>
+#include <malloc.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <mach/gpio.h>
+#include <mach/s3c24xx-generic.h>
+#include <mach/s3c24x0-clocks.h>
+#include <mach/fb.h>
+
+#define LCDCON1 0x00
+# define PNRMODE(x) (((x) & 3) << 5)
+# define BPPMODE(x) (((x) & 0xf) << 1)
+# define SET_CLKVAL(x) (((x) & 0x3ff) << 8)
+# define GET_CLKVAL(x) (((x) >> 8) & 0x3ff)
+# define ENVID (1 << 0)
+
+#define LCDCON2 0x04
+# define SET_VBPD(x) (((x) & 0xff) << 24)
+# define SET_LINEVAL(x) (((x) & 0x3ff) << 14)
+# define SET_VFPD(x) (((x) & 0xff) << 6)
+# define SET_VSPW(x) ((x) & 0x3f)
+
+#define LCDCON3 0x08
+# define SET_HBPD(x) (((x) & 0x7f) << 19)
+# define SET_HOZVAL(x) (((x) & 0x7ff) << 8)
+# define SET_HFPD(x) ((x) & 0xff)
+
+#define LCDCON4 0x0c
+# define SET_HSPW(x) ((x) & 0xff)
+
+#define LCDCON5 0x10
+# define BPP24BL (1 << 12)
+# define FRM565 (1 << 11)
+# define INV_CLK (1 << 10)
+# define INV_HS (1 << 9)
+# define INV_VS (1 << 8)
+# define INV_DTA (1 << 7)
+# define INV_DE (1 << 6)
+# define INV_PWREN (1 << 5)
+# define INV_LEND (1 << 4) /* FIXME */
+# define ENA_PWREN (1 << 3)
+# define ENA_LEND (1 << 2) /* FIXME */
+# define BSWP (1 << 1)
+# define HWSWP (1 << 0)
+
+#define LCDSADDR1 0x14
+# define SET_LCDBANK(x) (((x) & 0x1ff) << 21)
+# define GET_LCDBANK(x) (((x) >> 21) & 0x1ff)
+# define SET_LCDBASEU(x) ((x) & 0x1fffff)
+# define GET_LCDBASEU(x) ((x) & 0x1fffff)
+
+#define LCDSADDR2 0x18
+# define SET_LCDBASEL(x) ((x) & 0x1fffff)
+# define GET_LCDBASEL(x) ((x) & 0x1fffff)
+
+#define LCDSADDR3 0x1c
+# define SET_OFFSIZE(x) (((x) & 0x7ff) << 11)
+# define GET_OFFSIZE(x) (((x) >> 11) & 0x7ff)
+# define SET_PAGE_WIDTH(x) ((x) & 0x3ff)
+# define GET_PAGE_WIDTH(x) ((x) & 0x3ff)
+
+#define RED_LUT 0x20
+#define GREEN_LUT 0x24
+#define BLUE_LUT 0x28
+
+#define DITHMODE 0x4c
+
+#define TPAL 0x50
+
+#define LCDINTPND 0x54
+
+#define LCDSRCPND 0x58
+
+#define LCDINTMSK 0x5c
+# define FIWSEL (1 << 2)
+
+#define TCONSEL 0x60
+
+#define RED 0
+#define GREEN 1
+#define BLUE 2
+#define TRANSP 3
+
+struct s3cfb_host {
+ struct fb_host fb_data;
+ struct device_d *hw_dev;
+ struct s3c_fb_platform_data *pdata; /* shortcut to hw_dev->platform_data */
+ void __iomem *base;
+};
+
+#define fb_info_to_s3cfb_host(x) ((struct s3cfb_host*)((x)->host))
+
+/* the RGB565 true colour mode */
+static const struct fb_bitfield def_rgb565[] = {
+ [RED] = {
+ .offset = 11,
+ .length = 5,
+ },
+ [GREEN] = {
+ .offset = 5,
+ .length = 6,
+ },
+ [BLUE] = {
+ .offset = 0,
+ .length = 5,
+ },
+ [TRANSP] = { /* no support for transparency */
+ .length = 0,
+ }
+};
+
+/* the RGB888 true colour mode */
+static const struct fb_bitfield def_rgb888[] = {
+ [RED] = {
+ .offset = 16,
+ .length = 8,
+ },
+ [GREEN] = {
+ .offset = 8,
+ .length = 8,
+ },
+ [BLUE] = {
+ .offset = 0,
+ .length = 8,
+ },
+ [TRANSP] = { /* no support for transparency */
+ .length = 0,
+ }
+};
+
+/**
+ * @param fb_info Framebuffer information
+ */
+static void s3cfb_enable_controller(struct fb_info *fb_info)
+{
+ struct s3cfb_host *fbh = fb_info_to_s3cfb_host(fb_info);
+ struct s3c_fb_platform_data *pdata = fbh->pdata;
+ uint32_t con1;
+
+ con1 = readl(fbh->base + LCDCON1);
+
+ con1 |= ENVID;
+
+ writel(con1, fbh->base + LCDCON1);
+
+ if (pdata->enable)
+ pdata->enable(1);
+}
+
+/**
+ * @param fb_info Framebuffer information
+ */
+static void s3cfb_disable_controller(struct fb_info *fb_info)
+{
+ struct s3cfb_host *fbh = fb_info_to_s3cfb_host(fb_info);
+ struct s3c_fb_platform_data *pdata = fbh->pdata;
+ uint32_t con1;
+
+ if (pdata->enable)
+ pdata->enable(0);
+
+ con1 = readl(fbh->base + LCDCON1);
+
+ con1 &= ~ENVID;
+
+ writel(con1, fbh->base + LCDCON1);
+}
+
+/**
+ * Framebuffer memory management
+ * @param fb_info Framebuffer information
+ * @param size Requested framebuffer size in bytes
+ * @return 0 on success
+ *
+ * If the user forces a fixed memory location, try to map the framebuffer into
+ * it. If it does not match, report an error. If no fixed memory location
+ * exists do memory allocation in a dynamic manner.
+ */
+static int s3cfb_memory_mmgt(struct fb_info *fb_info, unsigned size)
+{
+ struct s3cfb_host *fbh = fb_info_to_s3cfb_host(fb_info);
+ struct s3c_fb_platform_data *pdata = fbh->pdata;
+
+ if (pdata->framebuffer != NULL) {
+ /* fixed memory location */
+ if (pdata->size < size)
+ return -EINVAL;
+ fb_info->fb_dev.map_base = (resource_size_t)pdata->framebuffer;
+ fb_info->fb_dev.size = size;
+ } else {
+ /* dynamic memory location */
+ if ((fb_info->fb_dev.size < size) &&
+ (fb_info->fb_dev.size != 0)) {
+ free((void*)fb_info->fb_dev.map_base);
+ fb_info->fb_dev.map_base = 0;
+ fb_info->fb_dev.size = 0;
+ }
+ if (fb_info->fb_dev.size == 0) {
+ /* allocate more space on platform request */
+ if (pdata->size > size)
+ size = pdata->size;
+ fb_info->fb_dev.map_base =
+ (resource_size_t)xzalloc(size);
+ fb_info->fb_dev.size = size;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Prepare the video hardware for a specified video mode
+ * @param fb_info Framebuffer information
+ * @param mode The video mode description to setup
+ * @return 0 on success
+ */
+static int s3cfb_initialize_mode(struct fb_info *fb_info,
+ const struct fb_videomode *mode)
+{
+ struct s3cfb_host *fbh = fb_info_to_s3cfb_host(fb_info);
+ struct s3c_fb_platform_data *pdata = fbh->pdata;
+ unsigned size, hclk, div;
+ int rc;
+ uint32_t con1, con2, con3, con4, con5 = 0;
+
+ if (pdata->passive_display != 0) {
+ dev_err(fbh->hw_dev,
+ "Passive displays are currently not supported\n");
+ return -EINVAL;
+ }
+
+ /*
+ * we need at least this amount of memory for the framebuffer
+ */
+ size = mode->xres * mode->yres * (fb_info->bits_per_pixel >> 3);
+
+ rc = s3cfb_memory_mmgt(fb_info, size);
+ if (rc != 0) {
+ dev_err(fbh->hw_dev, "Cannot allocate framebuffer memory\n");
+ return rc;
+ }
+
+ /* its useful to enable the unit's clock */
+ s3c244x_mod_clock(CLK_LCDC, 1);
+
+ /* ensure video output is _off_ */
+ writel(0x00000000, fbh->base + LCDCON1);
+
+ hclk = s3c24xx_get_hclk() / 1000U; /* hclk in kHz */
+ div = hclk / PICOS2KHZ(mode->pixclock);
+ if (div < 3)
+ div = 3;
+ /* pixel clock is: (hclk) / ((div + 1) * 2) */
+ div += 1;
+ div >>= 1;
+ div -= 1;
+
+ con1 = PNRMODE(3) | SET_CLKVAL(div); /* PNRMODE=3 is TFT */
+
+ switch (fb_info->bits_per_pixel) {
+#if 0
+ /** @todo S3C2440: Add CLUT based videomodes */
+ case 1:
+ con1 |= BPPMODE(8);
+ break;
+ case 2:
+ con1 |= BPPMODE(9);
+ break;
+ case 4:
+ con1 |= BPPMODE(10);
+ break;
+ case 8:
+ con1 |= BPPMODE(11);
+ break;
+#endif
+ case 16:
+ con1 |= BPPMODE(12);
+ con5 |= FRM565;
+ fb_info->red = def_rgb565[RED];
+ fb_info->green = def_rgb565[GREEN];
+ fb_info->blue = def_rgb565[BLUE];
+ fb_info->transp = def_rgb565[TRANSP];
+ break;
+ case 24:
+ con1 |= BPPMODE(13);
+ /** @todo S3C2440: Define the correct byte order
+ * for 24 bpp in memory (BPP24BL)
+ */
+ con5 |= BPP24BL;
+ fb_info->red = def_rgb888[RED];
+ fb_info->green = def_rgb888[GREEN];
+ fb_info->blue = def_rgb888[BLUE];
+ fb_info->transp = def_rgb888[TRANSP];
+ break;
+ default:
+ dev_err(fbh->hw_dev, "Invalid bits per pixel value: %u\n",
+ fb_info->bits_per_pixel);
+ return -EINVAL;
+ }
+
+ /* 'normal' in register description means positive logic */
+ if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
+ con5 |= INV_HS;
+ if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
+ con5 |= INV_VS;
+ if (!(mode->sync & FB_SYNC_DE_HIGH_ACT))
+ con5 |= INV_DE;
+ if (mode->sync & FB_SYNC_CLK_INVERT)
+ con5 |= INV_CLK; /* display should latch at the rising edge */
+ if (mode->sync & FB_SYNC_SWAP_RGB)
+ con5 |= HWSWP;
+
+ /** @todo S3C2440: LCD power enable via platform data */
+
+ /* vertical timing */
+ con2 = SET_VBPD(mode->upper_margin - 1) |
+ SET_LINEVAL(mode->yres - 1) |
+ SET_VFPD(mode->lower_margin - 1) |
+ SET_VSPW(mode->vsync_len - 1);
+
+ /* horizontal timing */
+ con3 = SET_HBPD(mode->left_margin - 1) |
+ SET_HOZVAL(mode->xres - 1) |
+ SET_HFPD(mode->right_margin - 1);
+ con4 = SET_HSPW(mode->hsync_len - 1);
+
+ /* basic timing setup */
+ writel(con1, fbh->base + LCDCON1);
+ writel(con2, fbh->base + LCDCON2);
+ writel(con3, fbh->base + LCDCON3);
+ writel(con4, fbh->base + LCDCON4);
+ writel(con5, fbh->base + LCDCON5);
+
+ /* framebuffer memory setup */
+ writel(((uint32_t)fb_info->fb_dev.map_base) >> 1,
+ fbh->base + LCDSADDR1);
+
+ writel(SET_LCDBASEL(((uint32_t)fb_info->fb_dev.map_base + size) >> 1),
+ fbh->base + LCDSADDR2);
+
+ writel(SET_OFFSIZE(0) |
+ SET_PAGE_WIDTH((mode->xres * fb_info->bits_per_pixel) >> 4),
+ fbh->base + LCDSADDR3);
+
+ writel(FIWSEL, fbh->base + LCDINTMSK);
+
+ return 0;
+}
+
+/**
+ * Print some information about the current hardware state
+ * @param hw_dev S3C video device
+ */
+#ifdef CONFIG_VIDEO_INFO_VERBOSE
+static void s3cfb_info(struct device_d *hw_dev)
+{
+ uint32_t con1, addr1, addr2, addr3;
+
+ con1 = readl(hw_dev->map_base + LCDCON1);
+ addr1 = readl(hw_dev->map_base + LCDSADDR1);
+ addr2 = readl(hw_dev->map_base + LCDSADDR2);
+ addr3 = readl(hw_dev->map_base + LCDSADDR3);
+
+ printf(" Video hardware info:\n");
+ printf(" Video clock is running at %u Hz\n",
+ s3c24xx_get_hclk() / ((GET_CLKVAL(con1) + 1) * 2));
+ printf(" Video memory bank starts at 0x%08X\n",
+ GET_LCDBANK(addr1) << 22);
+ printf(" Video memory bank offset: 0x%08X\n",
+ GET_LCDBASEU(addr1));
+ printf(" Video memory end: 0x%08X\n",
+ GET_LCDBASEU(addr2));
+ printf(" Virtual screen offset size: %u half words\n",
+ GET_OFFSIZE(addr3));
+ printf(" Virtual screen page width: %u half words\n",
+ GET_PAGE_WIDTH(addr3));
+}
+#endif
+
+/*
+ * There is only one video hardware instance available.
+ * It makes no sense to dynamically allocate this data
+ */
+static struct s3cfb_host host_data = {
+ .fb_data.fb_mode = s3cfb_initialize_mode,
+ .fb_data.fb_enable = s3cfb_enable_controller,
+ .fb_data.fb_disable = s3cfb_disable_controller,
+};
+
+static int s3cfb_probe(struct device_d *hw_dev)
+{
+ struct s3c_fb_platform_data *pdata = hw_dev->platform_data;
+ struct device_d *fb_dev;
+
+ if (pdata == NULL) {
+ dev_err(hw_dev, "Framebuffer driver missing platform data");
+ return -ENODEV;
+ }
+
+ /* enable unit's clock */
+ s3c244x_mod_clock(CLK_LCDC, 1);
+
+ writel(0, hw_dev->map_base + LCDCON1);
+
+ /** @todo S3C2440: LCD power disable via platform data */
+ writel(0, hw_dev->map_base + LCDCON5);
+
+ /* disable it again until user request */
+ s3c244x_mod_clock(CLK_LCDC, 0);
+
+ /* add runtime hardware info */
+ host_data.hw_dev = hw_dev;
+ host_data.base = (void*)hw_dev->map_base;
+
+ /* add runtime video info */
+ host_data.fb_data.mode = pdata->mode_list;
+ host_data.fb_data.mode_cnt = pdata->mode_cnt;
+
+ fb_dev = register_framebuffer(&host_data.fb_data);
+ if (fb_dev == NULL) {
+ dev_err(hw_dev, "Failed to register framebuffer\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct driver_d s3cfb_driver = {
+ .name = "s3cfb",
+ .probe = s3cfb_probe,
+#ifdef CONFIG_VIDEO_INFO_VERBOSE
+ .info = s3cfb_info,
+#endif
+};
+
+static int s3cfb_init(void)
+{
+ return register_driver(&s3cfb_driver);
+}
+
+device_initcall(s3cfb_init);
+
+/**
+ * The S3C244x LCD controller supports passive (CSTN/STN) and active (TFT)
+ * LC displays
+ *
+ * The driver itself currently supports only active TFT LC displays in the
+ * follwing manner:
+ *
+ * * True colours
+ * - 16 bpp
+ * - 24 bpp
+ */
--
1.7.2.3
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 11/11] STM378x: Add video driver for this platform
2010-11-19 12:50 [PATCHv3] Add dynamic video initialization to barebox Juergen Beisert
` (9 preceding siblings ...)
2010-11-19 12:51 ` [PATCH 10/11] Add a video driver for S3C2440 bases platforms Juergen Beisert
@ 2010-11-19 12:51 ` Juergen Beisert
10 siblings, 0 replies; 12+ messages in thread
From: Juergen Beisert @ 2010-11-19 12:51 UTC (permalink / raw)
To: barebox
Signed-off-by: Juergen Beisert <jbe@pengutronix.de>
---
arch/arm/mach-stm/include/mach/fb.h | 33 ++
drivers/video/Kconfig | 7 +
drivers/video/Makefile | 1 +
drivers/video/stm.c | 646 +++++++++++++++++++++++++++++++++++
4 files changed, 687 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-stm/include/mach/fb.h
create mode 100644 drivers/video/stm.c
diff --git a/arch/arm/mach-stm/include/mach/fb.h b/arch/arm/mach-stm/include/mach/fb.h
new file mode 100644
index 0000000..6def0c1
--- /dev/null
+++ b/arch/arm/mach-stm/include/mach/fb.h
@@ -0,0 +1,33 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MACH_FB_H
+# define __MACH_FB_H
+
+#include <fb.h>
+
+#define STMLCDIF_8BIT 1 /** pixel data bus to the display is of 8 bit width */
+#define STMLCDIF_16BIT 0 /** pixel data bus to the display is of 16 bit width */
+#define STMLCDIF_18BIT 2 /** pixel data bus to the display is of 18 bit width */
+#define STMLCDIF_24BIT 3 /** pixel data bus to the display is of 24 bit width */
+
+struct imx_fb_videomode {
+ struct fb_videomode *mode_list;
+ unsigned mode_count;
+ void *framebuffer; /**< force fixed framebuffer address if != NULL */
+ unsigned size; /**< force fixed size if != NULL */
+
+ unsigned dotclk_delay; /**< refer manual HW_LCDIF_VDCTRL4 register */
+ unsigned ld_intf_width; /**< refer STMLCDIF_* macros */
+};
+
+#endif /* __MACH_FB_H */
+
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index f43c100..7174451 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -36,4 +36,11 @@ config S3C_VIDEO
help
Add support for the S3C244x LCD controller.
+config DRIVER_VIDEO_STM
+ bool "i.MX23/28 framebuffer driver"
+ depends on ARCH_STM
+ help
+ Say 'Y' here to enable framebuffer and spash screen support for
+ i.MX23 and i.MX28 based systems.
+
endif
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 4287fc8..0ddb81e 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -1,5 +1,6 @@
obj-$(CONFIG_VIDEO) += fb.o
+obj-$(CONFIG_DRIVER_VIDEO_STM) += stm.o
obj-$(CONFIG_DRIVER_VIDEO_IMX) += imx.o
obj-$(CONFIG_DRIVER_VIDEO_IMX_IPU) += imx-ipu-fb.o
obj-$(CONFIG_S3C_VIDEO) += s3c.o
diff --git a/drivers/video/stm.c b/drivers/video/stm.c
new file mode 100644
index 0000000..747dc04
--- /dev/null
+++ b/drivers/video/stm.c
@@ -0,0 +1,646 @@
+/*
+ * Copyright (C) 2010 Juergen Beisert, Pengutronix
+ *
+ * This code is based on:
+ * Author: Vitaly Wool <vital@embeddedalley.com>
+ *
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/**
+ * @file
+ * @brief LCDIF driver for i.MX23 and i.MX28 (i.MX23 untested yet)
+ *
+ * The LCDIF support four modes of operation
+ * - MPU interface (to drive smart displays) -> not supported yet
+ * - VSYNC interface (like MPU interface plus Vsync) -> not supported yet
+ * - Dotclock interface (to drive LC displays with RGB data and sync signals)
+ * - DVI (to drive ITU-R BT656) -> not supported yet
+ *
+ * This driver depends on a correct setup of the pins used for this purpose
+ * (platform specific).
+ *
+ * For the developer: Don't forget to set the data bus width to the display
+ * in the imx_fb_videomode structure. You will else end up with ugly colours.
+ * If you fight against jitter you can vary the clock delay. This is a feature
+ * of the i.MX28 and you can vary it between 2 ns ... 8 ns in 2 ns steps. Give
+ * the required value in the imx_fb_videomode structure.
+ */
+
+/* #define DEBUG */
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <malloc.h>
+#include <errno.h>
+#include <xfuncs.h>
+#include <asm/io.h>
+#include <mach/clock.h>
+#include <mach/fb.h>
+
+#define HW_LCDIF_CTRL 0x00
+# define CTRL_SFTRST (1 << 31)
+# define CTRL_CLKGATE (1 << 30)
+# define CTRL_BYPASS_COUNT (1 << 19)
+# define CTRL_VSYNC_MODE (1 << 18)
+# define CTRL_DOTCLK_MODE (1 << 17)
+# define CTRL_DATA_SELECT (1 << 16)
+# define SET_BUS_WIDTH(x) (((x) & 0x3) << 10)
+# define SET_WORD_LENGTH(x) (((x) & 0x3) << 8)
+# define GET_WORD_LENGTH(x) (((x) >> 8) & 0x3)
+# define CTRL_MASTER (1 << 5)
+# define CTRL_DF16 (1 << 3)
+# define CTRL_DF18 (1 << 2)
+# define CTRL_DF24 (1 << 1)
+# define CTRL_RUN (1 << 0)
+
+#define HW_LCDIF_CTRL1 0x10
+# define CTRL1_FIFO_CLEAR (1 << 21)
+# define SET_BYTE_PACKAGING(x) (((x) & 0xf) << 16)
+# define GET_BYTE_PACKAGING(x) (((x) >> 16) & 0xf)
+
+#ifdef CONFIG_ARCH_IMX28
+#define HW_LCDIF_CTRL2 0x20
+#define HW_LCDIF_TRANSFER_COUNT 0x30
+#endif
+#ifdef CONFIG_ARCH_IMX23
+#define HW_LCDIF_TRANSFER_COUNT 0x20
+#endif
+# define SET_VCOUNT(x) (((x) & 0xffff) << 16)
+# define SET_HCOUNT(x) ((x) & 0xffff)
+
+#ifdef CONFIG_ARCH_IMX28
+#define HW_LCDIF_CUR_BUF 0x40
+#define HW_LCDIF_NEXT_BUF 0x50
+#endif
+#ifdef CONFIG_ARCH_IMX23
+#define HW_LCDIF_CUR_BUF 0x30
+#define HW_LCDIF_NEXT_BUF 0x40
+#endif
+
+#define HW_LCDIF_TIMING 0x60
+# define SET_CMD_HOLD(x) (((x) & 0xff) << 24)
+# define SET_CMD_SETUP(x) (((x) & 0xff) << 16)
+# define SET_DATA_HOLD(x) (((x) & 0xff) << 8)
+# define SET_DATA_SETUP(x) ((x) & 0xff))
+
+#define HW_LCDIF_VDCTRL0 0x70
+# define VDCTRL0_ENABLE_PRESENT (1 << 28)
+# define VDCTRL0_VSYNC_POL (1 << 27) /* 0 = low active, 1 = high active */
+# define VDCTRL0_HSYNC_POL (1 << 26) /* 0 = low active, 1 = high active */
+# define VDCTRL0_DOTCLK_POL (1 << 25) /* 0 = output@falling, capturing@rising edge */
+# define VDCTRL0_ENABLE_POL (1 << 24) /* 0 = low active, 1 = high active */
+# define VDCTRL0_VSYNC_PERIOD_UNIT (1 << 21)
+# define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT (1 << 20)
+# define VDCTRL0_HALF_LINE (1 << 19)
+# define VDCTRL0_HALF_LINE_MODE (1 << 18)
+# define SET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff)
+
+#define HW_LCDIF_VDCTRL1 0x80
+
+#define HW_LCDIF_VDCTRL2 0x90
+#ifdef CONFIG_ARCH_IMX28
+# define SET_HSYNC_PULSE_WIDTH(x) (((x) & 0x3fff) << 18)
+#endif
+#ifdef CONFIG_ARCH_IMX23
+# define SET_HSYNC_PULSE_WIDTH(x) (((x) & 0xff) << 24)
+#endif
+# define SET_HSYNC_PERIOD(x) ((x) & 0x3ffff)
+
+#define HW_LCDIF_VDCTRL3 0xa0
+# define VDCTRL3_MUX_SYNC_SIGNALS (1 << 29)
+# define VDCTRL3_VSYNC_ONLY (1 << 28)
+# define SET_HOR_WAIT_CNT(x) (((x) & 0xfff) << 16)
+# define SET_VERT_WAIT_CNT(x) ((x) & 0xffff)
+
+#define HW_LCDIF_VDCTRL4 0xb0
+#ifdef CONFIG_ARCH_IMX28
+# define SET_DOTCLK_DLY(x) (((x) & 0x7) << 29)
+#endif
+# define VDCTRL4_SYNC_SIGNALS_ON (1 << 18)
+# define SET_DOTCLK_H_VALID_DATA_CNT(x) ((x) & 0x3ffff)
+
+#define HW_LCDIF_DVICTRL0 0xc0
+#define HW_LCDIF_DVICTRL1 0xd0
+#define HW_LCDIF_DVICTRL2 0xe0
+#define HW_LCDIF_DVICTRL3 0xf0
+#define HW_LCDIF_DVICTRL4 0x100
+
+#ifdef CONFIG_ARCH_IMX28
+#define HW_LCDIF_DATA 0x180
+#endif
+#ifdef CONFIG_ARCH_IMX23
+#define HW_LCDIF_DATA 0x1b0
+#endif
+
+#ifdef CONFIG_ARCH_IMX28
+#define HW_LCDIF_DEBUG0 0x1d0
+#endif
+#ifdef CONFIG_ARCH_IMX23
+#define HW_LCDIF_DEBUG0 0x1f0
+#endif
+# define DEBUG_HSYNC (1 < 26)
+# define DEBUG_VSYNC (1 < 25)
+
+#define RED 0
+#define GREEN 1
+#define BLUE 2
+#define TRANSP 3
+
+struct imxfb_host {
+ struct fb_host fb_data;
+ struct device_d *hw_dev;
+ struct imx_fb_videomode *pdata;
+ void __iomem *base;
+};
+
+#define fb_info_to_imxfb_host(x) ((struct imxfb_host*)((x)->host))
+
+/* the RGB565 true colour mode */
+static const struct fb_bitfield def_rgb565[] = {
+ [RED] = {
+ .offset = 11,
+ .length = 5,
+ },
+ [GREEN] = {
+ .offset = 5,
+ .length = 6,
+ },
+ [BLUE] = {
+ .offset = 0,
+ .length = 5,
+ },
+ [TRANSP] = { /* no support for transparency */
+ .length = 0,
+ }
+};
+
+/* the RGB666 true colour mode */
+static const struct fb_bitfield def_rgb666[] = {
+ [RED] = {
+ .offset = 16,
+ .length = 6,
+ },
+ [GREEN] = {
+ .offset = 8,
+ .length = 6,
+ },
+ [BLUE] = {
+ .offset = 0,
+ .length = 6,
+ },
+ [TRANSP] = { /* no support for transparency */
+ .length = 0,
+ }
+};
+
+/* the RGB888 true colour mode */
+static const struct fb_bitfield def_rgb888[] = {
+ [RED] = {
+ .offset = 16,
+ .length = 8,
+ },
+ [GREEN] = {
+ .offset = 8,
+ .length = 8,
+ },
+ [BLUE] = {
+ .offset = 0,
+ .length = 8,
+ },
+ [TRANSP] = { /* no support for transparency */
+ .length = 0,
+ }
+};
+
+/**
+ * Just calculate the amount of required bytes per line
+ * @param ppl Used pixel per line
+ * @param bpp Bits per pixel
+ * @return Byte count
+ *
+ * @note This routine expects a non packed pixel mode
+ * (e.g. four bytes per pixel in 24 bpp mode).
+ */
+static inline unsigned calc_line_length(unsigned ppl, unsigned bpp)
+{
+ if (bpp == 24)
+ bpp = 32;
+ return (ppl * bpp) >> 3;
+}
+
+/**
+ * Framebuffer memory management
+ * @param fb_info Framebuffer information
+ * @param size Requested framebuffer size in bytes
+ * @return 0 on success
+ *
+ * If the user forces a fixed memory location, try to map the framebuffer into
+ * it. If it does not match, report an error. If no fixed memory location
+ * exists do memory allocation in a dynamic manner.
+ */
+static int stmfb_memory_mmgt(struct fb_info *fb_info, unsigned size)
+{
+ struct imxfb_host *fbh = fb_info_to_imxfb_host(fb_info);
+ struct imx_fb_videomode *pdata = fbh->pdata;
+
+ if (pdata->framebuffer != NULL) {
+ /* fixed memory location */
+ if (pdata->size < size)
+ return -EINVAL;
+ fb_info->fb_dev.map_base = (resource_size_t)pdata->framebuffer;
+ fb_info->fb_dev.size = size;
+ } else {
+ /* dynamic memory location */
+ if ((fb_info->fb_dev.size < size) &&
+ (fb_info->fb_dev.size != 0)) {
+ free((void*)fb_info->fb_dev.map_base);
+ fb_info->fb_dev.map_base = 0;
+ fb_info->fb_dev.size = 0;
+ }
+ if (fb_info->fb_dev.size == 0) {
+ /* allocate more space on platform request */
+ if (pdata->size > size)
+ size = pdata->size;
+ fb_info->fb_dev.map_base =
+ (resource_size_t)xzalloc(size);
+ fb_info->fb_dev.size = size;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Prepare the video hardware for a specified video mode
+ * @param fb_info Framebuffer information
+ * @param mode The video mode description to initialize
+ * @return 0 on success
+ *
+ * Dotclock mode:
+ * One line of pixels or one frame in the i.MX23/i.MX28 is defined to:
+ * @verbatim
+ * |<---------------------- one line period -------------------------------->|
+ * |<- HSync length ->|
+ * |<----- Start of line --->|
+ * |<-------- active line data ------>|
+ *
+ * |<------------------------ frame period --------------------------------->|
+ * |<- VSync length ->|
+ * |<--- Start of 1. line -->|
+ * |<---------- active lines -------->|
+ * @endverbatim
+ * Based on the values from struct fb_videomode:
+ * - "one line period" = left_margin + xres + right_margin + hsync_len
+ * - "HSync length" = hsync_len
+ * - "Start of line" = hsync_len + left_margin
+ * - "active line data" = xres
+ */
+static int stmfb_initialize_mode(struct fb_info *fb_info,
+ const struct fb_videomode *mode)
+{
+ struct imxfb_host *fbh = fb_info_to_imxfb_host(fb_info);
+ struct imx_fb_videomode *pdata = fbh->pdata;
+ uint32_t reg;
+ int rc;
+ unsigned size;
+
+ /*
+ * we need at least this amount of memory for the framebuffer
+ */
+ size = calc_line_length(mode->xres, fb_info->bits_per_pixel) *
+ mode->yres;
+
+ rc = stmfb_memory_mmgt(fb_info, size);
+ if (rc != 0) {
+ dev_err(fbh->hw_dev, "Cannot allocate framebuffer memory\n");
+ return rc;
+ }
+
+ /** @todo ensure HCLK is active at this point of time! */
+
+ size = imx_set_lcdifclk(PICOS2KHZ(mode->pixclock));
+ if (size == 0) {
+ dev_dbg(fbh->hw_dev, "Unable to set a valid pixel clock\n");
+ return -EINVAL;
+ }
+
+ /*
+ * bring the controller out of reset and
+ * configure it into DOTCLOCK mode
+ */
+ reg = CTRL_BYPASS_COUNT | /* always in DOTCLOCK mode */
+ CTRL_DOTCLK_MODE;
+ writel(reg, fbh->base + HW_LCDIF_CTRL);
+
+ /* master mode only */
+ reg |= CTRL_MASTER;
+
+ /*
+ * Configure videomode and interface mode
+ */
+ reg |= SET_BUS_WIDTH(pdata->ld_intf_width);
+ switch (fb_info->bits_per_pixel) {
+ case 8:
+ reg |= SET_WORD_LENGTH(1);
+ /** @todo refer manual page 2046 for 8 bpp modes */
+ dev_dbg(fbh->hw_dev, "8 bpp mode not supported yet\n");
+ break;
+ case 16:
+ pr_debug("Setting up an RGB565 mode\n");
+ reg |= SET_WORD_LENGTH(0);
+ reg &= ~CTRL_DF16; /* we assume RGB565 */
+ writel(SET_BYTE_PACKAGING(0xf), fbh->base + HW_LCDIF_CTRL1);
+ fb_info->red = def_rgb565[RED];
+ fb_info->green = def_rgb565[GREEN];
+ fb_info->blue = def_rgb565[BLUE];
+ fb_info->transp = def_rgb565[TRANSP];
+ break;
+ case 24:
+ case 32:
+ pr_debug("Setting up an RGB888/666 mode\n");
+ reg |= SET_WORD_LENGTH(3);
+ switch (pdata->ld_intf_width) {
+ case STMLCDIF_8BIT:
+ dev_dbg(fbh->hw_dev,
+ "Unsupported LCD bus width mapping\n");
+ break;
+ case STMLCDIF_16BIT:
+ case STMLCDIF_18BIT:
+ /* 24 bit to 18 bit mapping
+ * which means: ignore the upper 2 bits in
+ * each colour component
+ */
+ reg |= CTRL_DF24;
+ fb_info->red = def_rgb666[RED];
+ fb_info->green = def_rgb666[GREEN];
+ fb_info->blue = def_rgb666[BLUE];
+ fb_info->transp = def_rgb666[TRANSP];
+ break;
+ case STMLCDIF_24BIT:
+ /* real 24 bit */
+ fb_info->red = def_rgb888[RED];
+ fb_info->green = def_rgb888[GREEN];
+ fb_info->blue = def_rgb888[BLUE];
+ fb_info->transp = def_rgb888[TRANSP];
+ break;
+ }
+ /* do not use packed pixels = one pixel per word instead */
+ writel(SET_BYTE_PACKAGING(0x7), fbh->base + HW_LCDIF_CTRL1);
+ break;
+ default:
+ dev_dbg(fbh->hw_dev, "Unhandled colour depth of %u\n",
+ fb_info->bits_per_pixel);
+ return -EINVAL;
+ }
+ writel(reg, fbh->base + HW_LCDIF_CTRL);
+ pr_debug("Setting up CTRL to %08X\n", reg);
+
+ writel(SET_VCOUNT(mode->yres) |
+ SET_HCOUNT(mode->xres), fbh->base + HW_LCDIF_TRANSFER_COUNT);
+
+ reg = VDCTRL0_ENABLE_PRESENT | /* always in DOTCLOCK mode */
+ VDCTRL0_VSYNC_PERIOD_UNIT |
+ VDCTRL0_VSYNC_PULSE_WIDTH_UNIT;
+ if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
+ reg |= VDCTRL0_HSYNC_POL;
+ if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
+ reg |= VDCTRL0_VSYNC_POL;
+ if (mode->sync & FB_SYNC_DE_HIGH_ACT)
+ reg |= VDCTRL0_ENABLE_POL;
+ if (mode->sync & FB_SYNC_CLK_INVERT)
+ reg |= VDCTRL0_DOTCLK_POL;
+
+ reg |= SET_VSYNC_PULSE_WIDTH(mode->vsync_len);
+ writel(reg, fbh->base + HW_LCDIF_VDCTRL0);
+ pr_debug("Setting up VDCTRL0 to %08X\n", reg);
+
+ /* frame length in lines */
+ writel(mode->upper_margin + mode->vsync_len + mode->lower_margin +
+ mode->yres,
+ fbh->base + HW_LCDIF_VDCTRL1);
+
+ /* line length in units of clocks or pixels */
+ writel(SET_HSYNC_PULSE_WIDTH(mode->hsync_len) |
+ SET_HSYNC_PERIOD(mode->left_margin + mode->hsync_len +
+ mode->right_margin + mode->xres),
+ fbh->base + HW_LCDIF_VDCTRL2);
+
+ writel(SET_HOR_WAIT_CNT(mode->left_margin + mode->hsync_len) |
+ SET_VERT_WAIT_CNT(mode->upper_margin + mode->vsync_len),
+ fbh->base + HW_LCDIF_VDCTRL3);
+
+ writel(
+#ifdef CONFIG_ARCH_IMX28
+ SET_DOTCLK_DLY(pdata->dotclk_delay) |
+#endif
+ SET_DOTCLK_H_VALID_DATA_CNT(mode->xres),
+ fbh->base + HW_LCDIF_VDCTRL4);
+
+ writel((uint32_t)fb_info->fb_dev.map_base,
+ fbh->base + HW_LCDIF_CUR_BUF);
+ /* always show one framebuffer only */
+ writel((uint32_t)fb_info->fb_dev.map_base,
+ fbh->base + HW_LCDIF_NEXT_BUF);
+
+ return 0;
+}
+
+/**
+ * @param fb_info Framebuffer information
+ */
+static void stmfb_enable_controller(struct fb_info *fb_info)
+{
+ struct imxfb_host *fbh = fb_info_to_imxfb_host(fb_info);
+ uint32_t reg, last_reg;
+ unsigned loop, edges;
+
+ /*
+ * Sometimes some data is still present in the FIFO. This leads into
+ * a correct but shifted picture. Clearing the FIFO helps
+ */
+ writel(CTRL1_FIFO_CLEAR, fbh->base + HW_LCDIF_CTRL1 + 4);
+
+ /* if it was disabled, re-enable the mode again */
+ reg = readl(fbh->base + HW_LCDIF_CTRL);
+ reg |= CTRL_DOTCLK_MODE;
+ writel(reg, fbh->base + HW_LCDIF_CTRL);
+
+ /* enable the SYNC signals first, then the DMA enginge */
+ reg = readl(fbh->base + HW_LCDIF_VDCTRL4);
+ reg |= VDCTRL4_SYNC_SIGNALS_ON;
+ writel(reg, fbh->base + HW_LCDIF_VDCTRL4);
+
+ /*
+ * Give the attached LC display or monitor a chance to sync into
+ * our signals.
+ * Wait for at least 2 VSYNCs = four VSYNC edges
+ */
+ edges = 4;
+
+ while (edges != 0) {
+ loop = 800;
+ last_reg = readl(fbh->base + HW_LCDIF_DEBUG0) & DEBUG_VSYNC;
+ do {
+ reg = readl(fbh->base + HW_LCDIF_DEBUG0) & DEBUG_VSYNC;
+ if (reg != last_reg);
+ break;
+ last_reg = reg;
+ loop--;
+ } while (loop != 0);
+ edges--;
+ }
+
+ /* stop FIFO reset */
+ writel(CTRL1_FIFO_CLEAR, fbh->base + HW_LCDIF_CTRL1 + 8);
+ /* start the engine right now */
+ writel(CTRL_RUN, fbh->base + HW_LCDIF_CTRL + 4);
+}
+
+/**
+ * @param fb_info Framebuffer information
+ */
+static void stmfb_disable_controller(struct fb_info *fb_info)
+{
+ struct imxfb_host *fbh = fb_info_to_imxfb_host(fb_info);
+ unsigned loop;
+ uint32_t reg;
+
+ /*
+ * Even if we disable the controller here, it will still continue
+ * until its FIFOs are running out of data
+ */
+ reg = readl(fbh->base + HW_LCDIF_CTRL);
+ reg &= ~CTRL_DOTCLK_MODE;
+ writel(reg, fbh->base + HW_LCDIF_CTRL);
+
+ loop = 1000;
+ while (loop) {
+ reg = readl(fbh->base + HW_LCDIF_CTRL);
+ if (!(reg & CTRL_RUN))
+ break;
+ loop--;
+ }
+
+ reg = readl(fbh->base + HW_LCDIF_VDCTRL4);
+ reg &= ~VDCTRL4_SYNC_SIGNALS_ON;
+ writel(reg, fbh->base + HW_LCDIF_VDCTRL4);
+}
+
+/**
+ * Print some information about the current hardware state
+ * @param hw_dev STM video device
+ */
+static void stmfb_info(struct device_d *hw_dev)
+{
+ uint32_t reg;
+
+ printf(" STM video hardware:\n");
+ printf(" Pixel clock: %u kHz\n", imx_get_lcdifclk());
+
+ reg = readl(hw_dev->map_base + HW_LCDIF_CTRL);
+ switch (GET_WORD_LENGTH(reg)) {
+ case 0:
+ printf(" 16 bpp mode with %s colour scheme\n",
+ reg & CTRL_DF16 ? "ARGB1555" : "RGB565");
+ switch (GET_BYTE_PACKAGING(readl(hw_dev->map_base +
+ HW_LCDIF_CTRL1))) {
+ case 0xf:
+ printf(" One pixel per halfword\n");
+ break;
+ case 0x3:
+ printf(" One pixel per word\n");
+ break;
+ default:
+ printf("Unknown pixel packaging: %u\n",
+ GET_BYTE_PACKAGING(readl(hw_dev->map_base +
+ HW_LCDIF_CTRL1)));
+ }
+ break;
+ case 1:
+ case 2:
+ printf("Unsupported bpp mode yet!\n");
+ break;
+ case 3:
+ printf(" 24 bpp mode with %s colour scheme\n",
+ reg & CTRL_DF24 ? "RGB666" : "RGB888");
+ switch (GET_BYTE_PACKAGING(readl(hw_dev->map_base +
+ HW_LCDIF_CTRL1))) {
+ case 0x7:
+ printf(" One pixel per word (xRGB xRGB xRGB ...)\n");
+ break;
+ case 0xf:
+ printf("Packed pixel format per word "
+ "(RGBR GBRG BRGB ...)\n");
+ break;
+ default:
+ printf("Unknown pixel packaging: %u\n",
+ GET_BYTE_PACKAGING(readl(hw_dev->map_base +
+ HW_LCDIF_CTRL1)));
+ }
+ break;
+ }
+}
+
+/*
+ * There is only one video hardware instance available.
+ * It makes no sense to dynamically allocate this data
+ */
+static struct imxfb_host host_data = {
+ .fb_data.fb_mode = stmfb_initialize_mode,
+ .fb_data.fb_enable = stmfb_enable_controller,
+ .fb_data.fb_disable = stmfb_disable_controller,
+ .fb_data.bits_per_pixel = 16,
+};
+
+static int stmfb_probe(struct device_d *hw_dev)
+{
+ struct imx_fb_videomode *pdata = hw_dev->platform_data;
+ struct device_d *fb_dev;
+
+ if (pdata == NULL) {
+ dev_err(hw_dev, "No platform data. Giving up\n");
+ return -ENODEV;
+ }
+
+ /* add runtime hardware info */
+ host_data.hw_dev = hw_dev;
+ host_data.pdata = pdata;
+ host_data.base = (void*)hw_dev->map_base;
+
+ /* add runtime video info */
+ host_data.fb_data.mode = pdata->mode_list;
+ host_data.fb_data.mode_cnt = pdata->mode_count;
+
+ fb_dev = register_framebuffer(&host_data.fb_data);
+ if (fb_dev == NULL) {
+ dev_err(hw_dev, "Failed to register framebuffer\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct driver_d stmfb_driver = {
+ .name = "stmfb",
+ .probe = stmfb_probe,
+ .info = stmfb_info,
+};
+
+static int stmfb_init(void)
+{
+ return register_driver(&stmfb_driver);
+}
+
+device_initcall(stmfb_init);
--
1.7.2.3
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 12+ messages in thread