* [PATCH 1/2] sm501: support booting with splash screen on embedded devices
@ 2010-05-26 9:57 Anatolij Gustschin
2010-05-30 6:07 ` [PATCH 1/2] sm501: support booting with splash screen on embedded Ben Dooks
0 siblings, 1 reply; 2+ messages in thread
From: Anatolij Gustschin @ 2010-05-26 9:57 UTC (permalink / raw)
To: linux-fbdev
Change panel frame buffer to fb0 device and crt frame
buffer to fb1 device. This is done to be able to use pre-
initialized frame buffer on embedded devices. Firmware
initializes the LCD panel controller and shows a splash
image. We want to continue to display this image while
booting and do not want to copy bitmap data to new frame
buffer allocated by the driver for LCD panel. Therefore
we make panel interface to be fb0, read out the programmed
mode, setup fb info accordingly and do not clear the
frame buffer content if the display controller has been
previously enabled by the firmware.
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Cc: Ben Dooks <ben@simtec.co.uk>
Cc: Simtec Linux Team <linux@simtec.co.uk>
---
drivers/mfd/sm501.c | 17 ++++
drivers/video/sm501fb.c | 188 +++++++++++++++++++++++++++++++++++++++++------
include/linux/sm501.h | 3 +
3 files changed, 185 insertions(+), 23 deletions(-)
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
index bc9275c..a0f2feb 100644
--- a/drivers/mfd/sm501.c
+++ b/drivers/mfd/sm501.c
@@ -308,6 +308,23 @@ unsigned long sm501_modify_reg(struct device *dev,
EXPORT_SYMBOL_GPL(sm501_modify_reg);
+unsigned long sm501_read_reg(struct device *dev,
+ unsigned long reg)
+{
+ struct sm501_devdata *sm = dev_get_drvdata(dev);
+ unsigned long data;
+ unsigned long save;
+
+ spin_lock_irqsave(&sm->reg_lock, save);
+
+ data = readl(sm->regs + reg);
+
+ spin_unlock_irqrestore(&sm->reg_lock, save);
+
+ return data;
+}
+EXPORT_SYMBOL_GPL(sm501_read_reg);
+
/* sm501_unit_power
*
* alters the power active gate to set specific units on or off
diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c
index b7dc180..0b59112 100644
--- a/drivers/video/sm501fb.c
+++ b/drivers/video/sm501fb.c
@@ -92,6 +92,7 @@ struct sm501fb_par {
void *store_cursor;
void __iomem *cursor_regs;
struct sm501fb_info *info;
+ bool pre_init; /* pre-initialized disp. cfg. */
};
/* Helper functions */
@@ -160,12 +161,12 @@ static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
inf->fbmem_len = ptr; /* adjust available memory. */
break;
- case SM501_MEMF_PANEL:
+ case SM501_MEMF_CRT:
if (size > inf->fbmem_len)
return -ENOMEM;
ptr = inf->fbmem_len - size;
- fbi = inf->fb[HEAD_CRT];
+ fbi = inf->fb[HEAD_PANEL];
/* round down, some programs such as directfb do not draw
* 0,0 correctly unless the start is aligned to a page start.
@@ -179,13 +180,13 @@ static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
break;
- case SM501_MEMF_CRT:
+ case SM501_MEMF_PANEL:
ptr = 0;
/* check to see if we have panel memory allocated
* which would put an limit on available memory. */
- fbi = inf->fb[HEAD_PANEL];
+ fbi = inf->fb[HEAD_CRT];
if (fbi) {
par = fbi->par;
end = par->screen.k_addr ? par->screen.sm_addr : inf->fbmem_len;
@@ -469,6 +470,8 @@ static int sm501fb_set_par_common(struct fb_info *info,
mutex_lock(&info->mm_lock);
info->fix.smem_start = fbi->fbmem_res->start + par->screen.sm_addr;
info->fix.smem_len = smem_len;
+ info->fix.mmio_start = fbi->regs_res->start;
+ info->fix.mmio_len = resource_size(fbi->regs_res);
mutex_unlock(&info->mm_lock);
info->screen_base = fbi->fbmem + par->screen.sm_addr;
@@ -478,6 +481,14 @@ static int sm501fb_set_par_common(struct fb_info *info,
writel(par->screen.sm_addr | SM501_ADDR_FLIP, fbi->regs + head_addr);
+ /*
+ * To avoid flicker while booting we use pre-initialised
+ * configuration and do not reprogram the clock if the
+ * display controller has been initialized by the firmware.
+ */
+ if (par->pre_init)
+ return 0;
+
/* program CRT clock */
pixclock = sm501fb_ps_to_hz(var->pixclock);
@@ -1492,6 +1503,7 @@ static int sm501fb_start(struct sm501fb_info *info,
struct device *dev = &pdev->dev;
int k;
int ret;
+ u32 ctrl;
info->irq = ret = platform_get_irq(pdev, 0);
if (ret < 0) {
@@ -1576,8 +1588,20 @@ static int sm501fb_start(struct sm501fb_info *info,
info->fbmem_len = resource_size(res);
- /* clear framebuffer memory - avoids garbage data on unused fb */
- memset(info->fbmem, 0, info->fbmem_len);
+ /*
+ * Check if the display controller is enabled and
+ * do not clear the framebuffer content in this case
+ * as we want to display splash image as set by the
+ * firmware.
+ */
+ ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
+ ctrl &= SM501_DC_CRT_CONTROL_ENABLE;
+ ctrl |= readl(info->regs + SM501_DC_PANEL_CONTROL) &
+ SM501_DC_PANEL_CONTROL_EN;
+ if (!ctrl) {
+ /* clear fb memory - avoids garbage data on unused fb */
+ memset(info->fbmem, 0, info->fbmem_len);
+ }
/* clear palette ram - undefined at power on */
for (k = 0; k < (256 * 3); k++)
@@ -1635,6 +1659,123 @@ static void sm501fb_stop(struct sm501fb_info *info)
kfree(info->regs_res);
}
+/*
+ * sm501fb_disp_to_mode
+ *
+ * read the mode from the current display controller configuration
+*/
+static void sm501fb_disp_to_mode(struct fb_info *fb,
+ enum sm501_controller head)
+{
+ struct sm501fb_par *par = fb->par;
+ struct sm501fb_info *info = par->info;
+ unsigned long clock;
+ unsigned long clk_div;
+ unsigned long freq;
+ unsigned long div;
+ unsigned long ctrl;
+ unsigned long reg;
+ unsigned int ht, hde, hsw, hs;
+ unsigned int vt, vde, vsh, vs;
+ int div_val[] = { 1, 2, 4, 8, 16, 32, 64, 128 };
+
+ par->pre_init = true;
+
+ if (head = HEAD_PANEL)
+ ctrl = readl(info->regs + SM501_DC_PANEL_CONTROL);
+ else
+ ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
+
+ switch (ctrl & 0x3) {
+ case SM501_DC_PANEL_CONTROL_32BPP:
+ fb->var.bits_per_pixel = 32;
+ break;
+ case SM501_DC_PANEL_CONTROL_16BPP:
+ fb->var.bits_per_pixel = 16;
+ break;
+ default:
+ fb->var.bits_per_pixel = 8;
+ }
+
+ if (!(ctrl & SM501_DC_PANEL_CONTROL_HSP))
+ fb->var.sync |= FB_SYNC_HOR_HIGH_ACT;
+ if (!(ctrl & SM501_DC_PANEL_CONTROL_VSP))
+ fb->var.sync |= FB_SYNC_VERT_HIGH_ACT;
+
+ freq = 288000000;
+ clock = sm501_read_reg(info->dev->parent, SM501_CURRENT_CLOCK);
+ if (clock & (head = HEAD_PANEL ? 0x20000000 : 0x00100000))
+ freq = 336000000;
+
+ if (head = HEAD_PANEL)
+ clk_div = (clock >> 24) & 0x1f;
+ else
+ clk_div = (clock >> 16) & 0xf;
+
+ div = div_val[clk_div & 0x7];
+ if (clk_div & 0x8)
+ div *= 3;
+ else if (clk_div & 0x10)
+ div *= 5;
+
+ freq = freq / div / 2;
+ fb->var.pixclock = sm501fb_hz_to_ps(freq);
+ dev_dbg(info->dev, "freq %luHz, div %lu, pixclk(ps) %d\n",
+ freq, div, fb->var.pixclock);
+
+ reg = readl(info->regs + ((head = HEAD_PANEL) ?
+ SM501_DC_PANEL_H_TOT : SM501_DC_CRT_H_TOT));
+ ht = ((reg >> 16) & 0xfff) + 1;
+ hde = (reg & 0xfff) + 1;
+ reg = readl(info->regs + ((head = HEAD_PANEL) ?
+ SM501_DC_PANEL_H_SYNC : SM501_DC_CRT_H_SYNC));
+ hsw = (reg >> 16) & 0xff;
+ hs = (reg & 0xfff) + 1;
+
+ fb->var.right_margin = hs - hde;
+ fb->var.left_margin = ht - hde - fb->var.right_margin - hsw;
+ fb->var.hsync_len = hsw;
+
+ reg = readl(info->regs + ((head = HEAD_PANEL) ?
+ SM501_DC_PANEL_V_TOT : SM501_DC_CRT_V_TOT));
+ vt = ((reg >> 16) & 0x7ff) + 1;
+ vde = (reg & 0x7ff) + 1;
+ reg = readl(info->regs + ((head = HEAD_PANEL) ?
+ SM501_DC_PANEL_V_SYNC : SM501_DC_CRT_V_SYNC));
+ vsh = (reg >> 16) & 0x3f;
+ vs = (reg & 0x7ff) + 1;
+
+ fb->var.lower_margin = vs - vde;
+ fb->var.upper_margin = vt - vde - fb->var.lower_margin - vsh;
+ fb->var.vsync_len = vsh;
+
+ if (head = HEAD_PANEL) {
+ fb->var.xres + readl(info->regs + SM501_DC_PANEL_FB_WIDTH) >> 16;
+ fb->var.yres + readl(info->regs + SM501_DC_PANEL_FB_HEIGHT) >> 16;
+ } else {
+ reg = readl(info->regs + SM501_DC_CRT_FB_OFFSET);
+ fb->var.xres = (reg >> 16) / (fb->var.bits_per_pixel / 8);
+ fb->var.yres = vde;
+ }
+ fb->var.xres_virtual = fb->var.xres;
+ fb->var.yres_virtual = fb->var.yres;
+
+ dev_dbg(info->dev, "ctrl 0x%lx\n", ctrl);
+ dev_dbg(info->dev, "pixclock %d\n", fb->var.pixclock);
+ dev_dbg(info->dev, "bpp %d\n", fb->var.bits_per_pixel);
+ dev_dbg(info->dev, "xres %d\n", fb->var.xres);
+ dev_dbg(info->dev, "yres %d\n", fb->var.yres);
+ dev_dbg(info->dev, "right_margin %d\n", fb->var.right_margin);
+ dev_dbg(info->dev, "left_margin %d\n", fb->var.left_margin);
+ dev_dbg(info->dev, "lower_margin %d\n", fb->var.lower_margin);
+ dev_dbg(info->dev, "upper_margin %d\n", fb->var.upper_margin);
+ dev_dbg(info->dev, "hsync_len %d\n", fb->var.hsync_len);
+ dev_dbg(info->dev, "vsync_len %d\n", fb->var.vsync_len);
+ dev_dbg(info->dev, "sync %d\n", fb->var.sync);
+}
+
static int sm501fb_init_fb(struct fb_info *fb,
enum sm501_controller head,
const char *fbname)
@@ -1717,9 +1858,9 @@ static int sm501fb_init_fb(struct fb_info *fb,
fb->var.vmode = FB_VMODE_NONINTERLACED;
fb->var.bits_per_pixel = 16;
- if (enable && (pd->flags & SM501FB_FLAG_USE_INIT_MODE) && 0) {
- /* TODO read the mode from the current display */
-
+ if (enable && (pd->flags & SM501FB_FLAG_USE_INIT_MODE)) {
+ /* read the mode from the current display */
+ sm501fb_disp_to_mode(fb, head);
} else {
if (pd->def_mode) {
dev_info(info->dev, "using supplied mode\n");
@@ -1730,7 +1871,7 @@ static int sm501fb_init_fb(struct fb_info *fb,
fb->var.yres_virtual = fb->var.yres;
} else {
ret = fb_find_mode(&fb->var, fb,
- NULL, NULL, 0, NULL, 8);
+ "640x480@60", NULL, 0, NULL, 16);
if (ret = 0 || ret = 4) {
dev_err(info->dev,
@@ -1827,6 +1968,7 @@ static int __devinit sm501fb_start_one(struct sm501fb_info *info,
const char *drvname)
{
struct fb_info *fbi = info->fb[head];
+ struct sm501fb_par *par = fbi->par;
int ret;
if (!fbi)
@@ -1846,7 +1988,7 @@ static int __devinit sm501fb_start_one(struct sm501fb_info *info,
sm501_free_init_fb(info, head);
return ret;
}
-
+ (par->ops.fb_set_par)(fbi);
dev_info(info->dev, "fb%d: %s frame buffer\n", fbi->node, fbi->fix.id);
return 0;
@@ -1881,18 +2023,18 @@ static int __devinit sm501fb_probe(struct platform_device *pdev)
/* probe for the presence of each panel */
- ret = sm501fb_probe_one(info, HEAD_CRT);
- if (ret < 0) {
- dev_err(dev, "failed to probe CRT\n");
- goto err_alloc;
- }
-
ret = sm501fb_probe_one(info, HEAD_PANEL);
if (ret < 0) {
dev_err(dev, "failed to probe PANEL\n");
goto err_probed_crt;
}
+ ret = sm501fb_probe_one(info, HEAD_CRT);
+ if (ret < 0) {
+ dev_err(dev, "failed to probe CRT\n");
+ goto err_alloc;
+ }
+
if (info->fb[HEAD_PANEL] = NULL &&
info->fb[HEAD_CRT] = NULL) {
dev_err(dev, "no framebuffers found\n");
@@ -1907,18 +2049,18 @@ static int __devinit sm501fb_probe(struct platform_device *pdev)
goto err_probed_panel;
}
- ret = sm501fb_start_one(info, HEAD_CRT, driver_name_crt);
- if (ret) {
- dev_err(dev, "failed to start CRT\n");
- goto err_started;
- }
-
ret = sm501fb_start_one(info, HEAD_PANEL, driver_name_pnl);
if (ret) {
dev_err(dev, "failed to start Panel\n");
goto err_started_crt;
}
+ ret = sm501fb_start_one(info, HEAD_CRT, driver_name_crt);
+ if (ret) {
+ dev_err(dev, "failed to start CRT\n");
+ goto err_started;
+ }
+
/* create device files */
ret = device_create_file(dev, &dev_attr_crt_src);
diff --git a/include/linux/sm501.h b/include/linux/sm501.h
index 214f932..e705ba6 100644
--- a/include/linux/sm501.h
+++ b/include/linux/sm501.h
@@ -46,6 +46,9 @@ extern unsigned long sm501_modify_reg(struct device *dev,
unsigned long set,
unsigned long clear);
+extern unsigned long sm501_read_reg(struct device *dev,
+ unsigned long reg);
+
/* Platform data definitions */
--
1.6.2.5
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH 1/2] sm501: support booting with splash screen on embedded
2010-05-26 9:57 [PATCH 1/2] sm501: support booting with splash screen on embedded devices Anatolij Gustschin
@ 2010-05-30 6:07 ` Ben Dooks
0 siblings, 0 replies; 2+ messages in thread
From: Ben Dooks @ 2010-05-30 6:07 UTC (permalink / raw)
To: linux-fbdev
On 26/05/10 18:57, Anatolij Gustschin wrote:
> Change panel frame buffer to fb0 device and crt frame
> buffer to fb1 device. This is done to be able to use pre-
> initialized frame buffer on embedded devices. Firmware
> initializes the LCD panel controller and shows a splash
> image. We want to continue to display this image while
> booting and do not want to copy bitmap data to new frame
> buffer allocated by the driver for LCD panel. Therefore
> we make panel interface to be fb0, read out the programmed
> mode, setup fb info accordingly and do not clear the
> frame buffer content if the display controller has been
> previously enabled by the firmware.
>
> Signed-off-by: Anatolij Gustschin <agust@denx.de>
> Cc: Ben Dooks <ben@simtec.co.uk>
> Cc: Simtec Linux Team <linux@simtec.co.uk>
> ---
> drivers/mfd/sm501.c | 17 ++++
> drivers/video/sm501fb.c | 188 +++++++++++++++++++++++++++++++++++++++++------
> include/linux/sm501.h | 3 +
> 3 files changed, 185 insertions(+), 23 deletions(-)
>
> diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
> index bc9275c..a0f2feb 100644
> --- a/drivers/mfd/sm501.c
> +++ b/drivers/mfd/sm501.c
> @@ -308,6 +308,23 @@ unsigned long sm501_modify_reg(struct device *dev,
>
> EXPORT_SYMBOL_GPL(sm501_modify_reg);
>
> +unsigned long sm501_read_reg(struct device *dev,
> + unsigned long reg)
> +{
> + struct sm501_devdata *sm = dev_get_drvdata(dev);
> + unsigned long data;
> + unsigned long save;
> +
> + spin_lock_irqsave(&sm->reg_lock, save);
> +
> + data = readl(sm->regs + reg);
> +
> + spin_unlock_irqrestore(&sm->reg_lock, save);
> +
> + return data;
> +}
> +EXPORT_SYMBOL_GPL(sm501_read_reg);
I'm not sure why you need locking around a read
call. I don't think you even need it, the only
place this is being called from is within this
driver.
> /* sm501_unit_power
> *
> * alters the power active gate to set specific units on or off
> diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c
> index b7dc180..0b59112 100644
> --- a/drivers/video/sm501fb.c
> +++ b/drivers/video/sm501fb.c
> @@ -92,6 +92,7 @@ struct sm501fb_par {
> void *store_cursor;
> void __iomem *cursor_regs;
> struct sm501fb_info *info;
> + bool pre_init; /* pre-initialized disp. cfg. */
> };
>
> /* Helper functions */
> @@ -160,12 +161,12 @@ static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
> inf->fbmem_len = ptr; /* adjust available memory. */
> break;
>
> - case SM501_MEMF_PANEL:
> + case SM501_MEMF_CRT:
> if (size > inf->fbmem_len)
> return -ENOMEM;
>
> ptr = inf->fbmem_len - size;
> - fbi = inf->fb[HEAD_CRT];
> + fbi = inf->fb[HEAD_PANEL];
>
> /* round down, some programs such as directfb do not draw
> * 0,0 correctly unless the start is aligned to a page start.
> @@ -179,13 +180,13 @@ static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
>
> break;
>
> - case SM501_MEMF_CRT:
> + case SM501_MEMF_PANEL:
> ptr = 0;
>
> /* check to see if we have panel memory allocated
> * which would put an limit on available memory. */
>
> - fbi = inf->fb[HEAD_PANEL];
> + fbi = inf->fb[HEAD_CRT];
> if (fbi) {
> par = fbi->par;
> end = par->screen.k_addr ? par->screen.sm_addr : inf->fbmem_len;
> @@ -469,6 +470,8 @@ static int sm501fb_set_par_common(struct fb_info *info,
> mutex_lock(&info->mm_lock);
> info->fix.smem_start = fbi->fbmem_res->start + par->screen.sm_addr;
> info->fix.smem_len = smem_len;
> + info->fix.mmio_start = fbi->regs_res->start;
> + info->fix.mmio_len = resource_size(fbi->regs_res);
> mutex_unlock(&info->mm_lock);
>
> info->screen_base = fbi->fbmem + par->screen.sm_addr;
> @@ -478,6 +481,14 @@ static int sm501fb_set_par_common(struct fb_info *info,
>
> writel(par->screen.sm_addr | SM501_ADDR_FLIP, fbi->regs + head_addr);
>
> + /*
> + * To avoid flicker while booting we use pre-initialised
> + * configuration and do not reprogram the clock if the
> + * display controller has been initialized by the firmware.
> + */
> + if (par->pre_init)
> + return 0;
> +
> /* program CRT clock */
>
> pixclock = sm501fb_ps_to_hz(var->pixclock);
> @@ -1492,6 +1503,7 @@ static int sm501fb_start(struct sm501fb_info *info,
> struct device *dev = &pdev->dev;
> int k;
> int ret;
> + u32 ctrl;
>
> info->irq = ret = platform_get_irq(pdev, 0);
> if (ret < 0) {
> @@ -1576,8 +1588,20 @@ static int sm501fb_start(struct sm501fb_info *info,
>
> info->fbmem_len = resource_size(res);
>
> - /* clear framebuffer memory - avoids garbage data on unused fb */
> - memset(info->fbmem, 0, info->fbmem_len);
> + /*
> + * Check if the display controller is enabled and
> + * do not clear the framebuffer content in this case
> + * as we want to display splash image as set by the
> + * firmware.
> + */
> + ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
> + ctrl &= SM501_DC_CRT_CONTROL_ENABLE;
> + ctrl |= readl(info->regs + SM501_DC_PANEL_CONTROL) &
> + SM501_DC_PANEL_CONTROL_EN;
> + if (!ctrl) {
> + /* clear fb memory - avoids garbage data on unused fb */
> + memset(info->fbmem, 0, info->fbmem_len);
> + }
>
> /* clear palette ram - undefined at power on */
> for (k = 0; k < (256 * 3); k++)
> @@ -1635,6 +1659,123 @@ static void sm501fb_stop(struct sm501fb_info *info)
> kfree(info->regs_res);
> }
>
> +/*
> + * sm501fb_disp_to_mode
> + *
> + * read the mode from the current display controller configuration
> +*/
> +static void sm501fb_disp_to_mode(struct fb_info *fb,
> + enum sm501_controller head)
> +{
> + struct sm501fb_par *par = fb->par;
> + struct sm501fb_info *info = par->info;
> + unsigned long clock;
> + unsigned long clk_div;
> + unsigned long freq;
> + unsigned long div;
> + unsigned long ctrl;
> + unsigned long reg;
> + unsigned int ht, hde, hsw, hs;
> + unsigned int vt, vde, vsh, vs;
> + int div_val[] = { 1, 2, 4, 8, 16, 32, 64, 128 };
looks like a simple 1 << x would have done instead of this
table.
> + par->pre_init = true;
> +
> + if (head = HEAD_PANEL)
> + ctrl = readl(info->regs + SM501_DC_PANEL_CONTROL);
> + else
> + ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
> +
> + switch (ctrl & 0x3) {
> + case SM501_DC_PANEL_CONTROL_32BPP:
> + fb->var.bits_per_pixel = 32;
> + break;
> + case SM501_DC_PANEL_CONTROL_16BPP:
> + fb->var.bits_per_pixel = 16;
> + break;
> + default:
> + fb->var.bits_per_pixel = 8;
> + }
> +
> + if (!(ctrl & SM501_DC_PANEL_CONTROL_HSP))
> + fb->var.sync |= FB_SYNC_HOR_HIGH_ACT;
> + if (!(ctrl & SM501_DC_PANEL_CONTROL_VSP))
> + fb->var.sync |= FB_SYNC_VERT_HIGH_ACT;
> +
> + freq = 288000000;
Hmm, is this fixed for all SM501 devices?
> + clock = sm501_read_reg(info->dev->parent, SM501_CURRENT_CLOCK);
> + if (clock & (head = HEAD_PANEL ? 0x20000000 : 0x00100000))
> + freq = 336000000;
> +
> + if (head = HEAD_PANEL)
> + clk_div = (clock >> 24) & 0x1f;
> + else
> + clk_div = (clock >> 16) & 0xf;
> +
> + div = div_val[clk_div & 0x7];
> + if (clk_div & 0x8)
> + div *= 3;
> + else if (clk_div & 0x10)
> + div *= 5;
> +
> + freq = freq / div / 2;
> + fb->var.pixclock = sm501fb_hz_to_ps(freq);
> + dev_dbg(info->dev, "freq %luHz, div %lu, pixclk(ps) %d\n",
> + freq, div, fb->var.pixclock);
> +
> + reg = readl(info->regs + ((head = HEAD_PANEL) ?
> + SM501_DC_PANEL_H_TOT : SM501_DC_CRT_H_TOT));
> + ht = ((reg >> 16) & 0xfff) + 1;
> + hde = (reg & 0xfff) + 1;
> + reg = readl(info->regs + ((head = HEAD_PANEL) ?
> + SM501_DC_PANEL_H_SYNC : SM501_DC_CRT_H_SYNC));
> + hsw = (reg >> 16) & 0xff;
> + hs = (reg & 0xfff) + 1;
> +
> + fb->var.right_margin = hs - hde;
> + fb->var.left_margin = ht - hde - fb->var.right_margin - hsw;
> + fb->var.hsync_len = hsw;
> +
> + reg = readl(info->regs + ((head = HEAD_PANEL) ?
> + SM501_DC_PANEL_V_TOT : SM501_DC_CRT_V_TOT));
> + vt = ((reg >> 16) & 0x7ff) + 1;
> + vde = (reg & 0x7ff) + 1;
> + reg = readl(info->regs + ((head = HEAD_PANEL) ?
> + SM501_DC_PANEL_V_SYNC : SM501_DC_CRT_V_SYNC));
> + vsh = (reg >> 16) & 0x3f;
> + vs = (reg & 0x7ff) + 1;
> +
> + fb->var.lower_margin = vs - vde;
> + fb->var.upper_margin = vt - vde - fb->var.lower_margin - vsh;
> + fb->var.vsync_len = vsh;
> +
> + if (head = HEAD_PANEL) {
> + fb->var.xres > + readl(info->regs + SM501_DC_PANEL_FB_WIDTH) >> 16;
> + fb->var.yres > + readl(info->regs + SM501_DC_PANEL_FB_HEIGHT) >> 16;
> + } else {
> + reg = readl(info->regs + SM501_DC_CRT_FB_OFFSET);
> + fb->var.xres = (reg >> 16) / (fb->var.bits_per_pixel / 8);
> + fb->var.yres = vde;
> + }
> + fb->var.xres_virtual = fb->var.xres;
> + fb->var.yres_virtual = fb->var.yres;
> +
> + dev_dbg(info->dev, "ctrl 0x%lx\n", ctrl);
> + dev_dbg(info->dev, "pixclock %d\n", fb->var.pixclock);
> + dev_dbg(info->dev, "bpp %d\n", fb->var.bits_per_pixel);
> + dev_dbg(info->dev, "xres %d\n", fb->var.xres);
> + dev_dbg(info->dev, "yres %d\n", fb->var.yres);
> + dev_dbg(info->dev, "right_margin %d\n", fb->var.right_margin);
> + dev_dbg(info->dev, "left_margin %d\n", fb->var.left_margin);
> + dev_dbg(info->dev, "lower_margin %d\n", fb->var.lower_margin);
> + dev_dbg(info->dev, "upper_margin %d\n", fb->var.upper_margin);
> + dev_dbg(info->dev, "hsync_len %d\n", fb->var.hsync_len);
> + dev_dbg(info->dev, "vsync_len %d\n", fb->var.vsync_len);
> + dev_dbg(info->dev, "sync %d\n", fb->var.sync);
> +}
> +
> static int sm501fb_init_fb(struct fb_info *fb,
> enum sm501_controller head,
> const char *fbname)
> @@ -1717,9 +1858,9 @@ static int sm501fb_init_fb(struct fb_info *fb,
> fb->var.vmode = FB_VMODE_NONINTERLACED;
> fb->var.bits_per_pixel = 16;
>
> - if (enable && (pd->flags & SM501FB_FLAG_USE_INIT_MODE) && 0) {
> - /* TODO read the mode from the current display */
> -
> + if (enable && (pd->flags & SM501FB_FLAG_USE_INIT_MODE)) {
> + /* read the mode from the current display */
> + sm501fb_disp_to_mode(fb, head);
> } else {
> if (pd->def_mode) {
> dev_info(info->dev, "using supplied mode\n");
> @@ -1730,7 +1871,7 @@ static int sm501fb_init_fb(struct fb_info *fb,
> fb->var.yres_virtual = fb->var.yres;
> } else {
> ret = fb_find_mode(&fb->var, fb,
> - NULL, NULL, 0, NULL, 8);
> + "640x480@60", NULL, 0, NULL, 16);
>
> if (ret = 0 || ret = 4) {
> dev_err(info->dev,
> @@ -1827,6 +1968,7 @@ static int __devinit sm501fb_start_one(struct sm501fb_info *info,
> const char *drvname)
> {
> struct fb_info *fbi = info->fb[head];
> + struct sm501fb_par *par = fbi->par;
> int ret;
>
> if (!fbi)
> @@ -1846,7 +1988,7 @@ static int __devinit sm501fb_start_one(struct sm501fb_info *info,
> sm501_free_init_fb(info, head);
> return ret;
> }
> -
> + (par->ops.fb_set_par)(fbi);
> dev_info(info->dev, "fb%d: %s frame buffer\n", fbi->node, fbi->fix.id);
>
> return 0;
> @@ -1881,18 +2023,18 @@ static int __devinit sm501fb_probe(struct platform_device *pdev)
>
> /* probe for the presence of each panel */
I'd much rather see some form of swap panel/crt flag instead
of the changes being done.
> - ret = sm501fb_probe_one(info, HEAD_CRT);
> - if (ret < 0) {
> - dev_err(dev, "failed to probe CRT\n");
> - goto err_alloc;
> - }
> -
> ret = sm501fb_probe_one(info, HEAD_PANEL);
> if (ret < 0) {
> dev_err(dev, "failed to probe PANEL\n");
> goto err_probed_crt;
> }
>
> + ret = sm501fb_probe_one(info, HEAD_CRT);
> + if (ret < 0) {
> + dev_err(dev, "failed to probe CRT\n");
> + goto err_alloc;
> + }
> +
> if (info->fb[HEAD_PANEL] = NULL &&
> info->fb[HEAD_CRT] = NULL) {
> dev_err(dev, "no framebuffers found\n");
> @@ -1907,18 +2049,18 @@ static int __devinit sm501fb_probe(struct platform_device *pdev)
> goto err_probed_panel;
> }
>
> - ret = sm501fb_start_one(info, HEAD_CRT, driver_name_crt);
> - if (ret) {
> - dev_err(dev, "failed to start CRT\n");
> - goto err_started;
> - }
> -
> ret = sm501fb_start_one(info, HEAD_PANEL, driver_name_pnl);
> if (ret) {
> dev_err(dev, "failed to start Panel\n");
> goto err_started_crt;
> }
>
> + ret = sm501fb_start_one(info, HEAD_CRT, driver_name_crt);
> + if (ret) {
> + dev_err(dev, "failed to start CRT\n");
> + goto err_started;
> + }
> +
> /* create device files */
>
> ret = device_create_file(dev, &dev_attr_crt_src);
> diff --git a/include/linux/sm501.h b/include/linux/sm501.h
> index 214f932..e705ba6 100644
> --- a/include/linux/sm501.h
> +++ b/include/linux/sm501.h
> @@ -46,6 +46,9 @@ extern unsigned long sm501_modify_reg(struct device *dev,
> unsigned long set,
> unsigned long clear);
>
> +extern unsigned long sm501_read_reg(struct device *dev,
> + unsigned long reg);
> +
>
> /* Platform data definitions */
>
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2010-05-30 6:07 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-05-26 9:57 [PATCH 1/2] sm501: support booting with splash screen on embedded devices Anatolij Gustschin
2010-05-30 6:07 ` [PATCH 1/2] sm501: support booting with splash screen on embedded Ben Dooks
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).