diff options
Diffstat (limited to 'drivers/video/s3c-fb.c')
-rw-r--r-- | drivers/video/s3c-fb.c | 133 |
1 files changed, 96 insertions, 37 deletions
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index 0c63b69b634..f3105160bf9 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c @@ -48,7 +48,8 @@ #undef writel #define writel(v, r) do { \ printk(KERN_DEBUG "%s: %08x => %p\n", __func__, (unsigned int)v, r); \ - __raw_writel(v, r); } while (0) + __raw_writel(v, r); \ +} while (0) #endif /* FB_S3C_DEBUG_REGWRITE */ /* irq_flags bits */ @@ -81,12 +82,14 @@ struct s3c_fb; * @palette: Address of palette memory, or 0 if none. * @has_prtcon: Set if has PRTCON register. * @has_shadowcon: Set if has SHADOWCON register. + * @has_blendcon: Set if has BLENDCON register. * @has_clksel: Set if VIDCON0 register has CLKSEL bit. + * @has_fixvclk: Set if VIDCON1 register has FIXVCLK bits. */ struct s3c_fb_variant { unsigned int is_2443:1; unsigned short nr_windows; - unsigned short vidtcon; + unsigned int vidtcon; unsigned short wincon; unsigned short winmap; unsigned short keycon; @@ -99,7 +102,9 @@ struct s3c_fb_variant { unsigned int has_prtcon:1; unsigned int has_shadowcon:1; + unsigned int has_blendcon:1; unsigned int has_clksel:1; + unsigned int has_fixvclk:1; }; /** @@ -186,7 +191,6 @@ struct s3c_fb_vsync { * struct s3c_fb - overall hardware state of the hardware * @slock: The spinlock protection for this data sturcture. * @dev: The device that we bound to, for printing, etc. - * @regs_res: The resource we claimed for the IO registers. * @bus_clk: The clk (hclk) feeding our interface and possibly pixclk. * @lcd_clk: The clk (sclk) feeding pixclk. * @regs: The mapped hardware registers. @@ -202,7 +206,6 @@ struct s3c_fb_vsync { struct s3c_fb { spinlock_t slock; struct device *dev; - struct resource *regs_res; struct clk *bus_clk; struct clk *lcd_clk; void __iomem *regs; @@ -565,7 +568,9 @@ static int s3c_fb_set_par(struct fb_info *info) writel(data, regs + sfb->variant.vidtcon + 4); data = VIDTCON2_LINEVAL(var->yres - 1) | - VIDTCON2_HOZVAL(var->xres - 1); + VIDTCON2_HOZVAL(var->xres - 1) | + VIDTCON2_LINEVAL_E(var->yres - 1) | + VIDTCON2_HOZVAL_E(var->xres - 1); writel(data, regs + sfb->variant.vidtcon + 8); } @@ -581,17 +586,23 @@ static int s3c_fb_set_par(struct fb_info *info) pagewidth = (var->xres * var->bits_per_pixel) >> 3; data = VIDW_BUF_SIZE_OFFSET(info->fix.line_length - pagewidth) | - VIDW_BUF_SIZE_PAGEWIDTH(pagewidth); + VIDW_BUF_SIZE_PAGEWIDTH(pagewidth) | + VIDW_BUF_SIZE_OFFSET_E(info->fix.line_length - pagewidth) | + VIDW_BUF_SIZE_PAGEWIDTH_E(pagewidth); writel(data, regs + sfb->variant.buf_size + (win_no * 4)); /* write 'OSD' registers to control position of framebuffer */ - data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0); + data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0) | + VIDOSDxA_TOPLEFT_X_E(0) | VIDOSDxA_TOPLEFT_Y_E(0); writel(data, regs + VIDOSD_A(win_no, sfb->variant)); data = VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(var->bits_per_pixel, var->xres - 1)) | - VIDOSDxB_BOTRIGHT_Y(var->yres - 1); + VIDOSDxB_BOTRIGHT_Y(var->yres - 1) | + VIDOSDxB_BOTRIGHT_X_E(s3c_fb_align_word(var->bits_per_pixel, + var->xres - 1)) | + VIDOSDxB_BOTRIGHT_Y_E(var->yres - 1); writel(data, regs + VIDOSD_B(win_no, sfb->variant)); @@ -692,6 +703,17 @@ static int s3c_fb_set_par(struct fb_info *info) writel(data, regs + sfb->variant.wincon + (win_no * 4)); writel(0x0, regs + sfb->variant.winmap + (win_no * 4)); + /* Set alpha value width */ + if (sfb->variant.has_blendcon) { + data = readl(sfb->regs + BLENDCON); + data &= ~BLENDCON_NEW_MASK; + if (var->transp.length > 4) + data |= BLENDCON_NEW_8BIT_ALPHA_VALUE; + else + data |= BLENDCON_NEW_4BIT_ALPHA_VALUE; + writel(data, sfb->regs + BLENDCON); + } + shadow_protect_win(win, 0); pm_runtime_put_sync(sfb->dev); @@ -1346,6 +1368,7 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) struct resource *res; int win; int ret = 0; + u32 reg; platid = platform_get_device_id(pdev); fbdrv = (struct s3c_fb_driverdata *)platid->driver_data; @@ -1361,7 +1384,7 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) return -EINVAL; } - sfb = kzalloc(sizeof(struct s3c_fb), GFP_KERNEL); + sfb = devm_kzalloc(dev, sizeof(struct s3c_fb), GFP_KERNEL); if (!sfb) { dev_err(dev, "no memory for framebuffers\n"); return -ENOMEM; @@ -1404,33 +1427,25 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) goto err_lcd_clk; } - sfb->regs_res = request_mem_region(res->start, resource_size(res), - dev_name(dev)); - if (!sfb->regs_res) { - dev_err(dev, "failed to claim register region\n"); - ret = -ENOENT; - goto err_lcd_clk; - } - - sfb->regs = ioremap(res->start, resource_size(res)); + sfb->regs = devm_request_and_ioremap(dev, res); if (!sfb->regs) { dev_err(dev, "failed to map registers\n"); ret = -ENXIO; - goto err_req_region; + goto err_lcd_clk; } res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res) { dev_err(dev, "failed to acquire irq resource\n"); ret = -ENOENT; - goto err_ioremap; + goto err_lcd_clk; } sfb->irq_no = res->start; - ret = request_irq(sfb->irq_no, s3c_fb_irq, + ret = devm_request_irq(dev, sfb->irq_no, s3c_fb_irq, 0, "s3c_fb", sfb); if (ret) { dev_err(dev, "irq request failed\n"); - goto err_ioremap; + goto err_lcd_clk; } dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs); @@ -1444,6 +1459,14 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) writel(pd->vidcon1, sfb->regs + VIDCON1); + /* set video clock running at under-run */ + if (sfb->variant.has_fixvclk) { + reg = readl(sfb->regs + VIDCON1); + reg &= ~VIDCON1_VCLK_MASK; + reg |= VIDCON1_VCLK_RUN; + writel(reg, sfb->regs + VIDCON1); + } + /* zero all windows before we do anything */ for (win = 0; win < fbdrv->variant.nr_windows; win++) @@ -1484,13 +1507,6 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) err_pm_runtime: pm_runtime_put_sync(sfb->dev); - free_irq(sfb->irq_no, sfb); - -err_ioremap: - iounmap(sfb->regs); - -err_req_region: - release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res)); err_lcd_clk: pm_runtime_disable(sfb->dev); @@ -1505,7 +1521,6 @@ err_bus_clk: clk_put(sfb->bus_clk); err_sfb: - kfree(sfb); return ret; } @@ -1527,10 +1542,6 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev) if (sfb->windows[win]) s3c_fb_release_win(sfb, sfb->windows[win]); - free_irq(sfb->irq_no, sfb); - - iounmap(sfb->regs); - if (!sfb->variant.has_clksel) { clk_disable(sfb->lcd_clk); clk_put(sfb->lcd_clk); @@ -1539,12 +1550,9 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev) clk_disable(sfb->bus_clk); clk_put(sfb->bus_clk); - release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res)); - pm_runtime_put_sync(sfb->dev); pm_runtime_disable(sfb->dev); - kfree(sfb); return 0; } @@ -1579,6 +1587,7 @@ static int s3c_fb_resume(struct device *dev) struct s3c_fb_platdata *pd = sfb->pdata; struct s3c_fb_win *win; int win_no; + u32 reg; clk_enable(sfb->bus_clk); @@ -1589,6 +1598,14 @@ static int s3c_fb_resume(struct device *dev) pd->setup_gpio(); writel(pd->vidcon1, sfb->regs + VIDCON1); + /* set video clock running at under-run */ + if (sfb->variant.has_fixvclk) { + reg = readl(sfb->regs + VIDCON1); + reg &= ~VIDCON1_VCLK_MASK; + reg |= VIDCON1_VCLK_RUN; + writel(reg, sfb->regs + VIDCON1); + } + /* zero all windows before we do anything */ for (win_no = 0; win_no < sfb->variant.nr_windows; win_no++) s3c_fb_clear_win(sfb, win_no); @@ -1819,6 +1836,7 @@ static struct s3c_fb_driverdata s3c_fb_data_s5pc100 = { }, .has_prtcon = 1, + .has_blendcon = 1, .has_clksel = 1, }, .win[0] = &s3c_fb_data_s5p_wins[0], @@ -1850,7 +1868,9 @@ static struct s3c_fb_driverdata s3c_fb_data_s5pv210 = { }, .has_shadowcon = 1, + .has_blendcon = 1, .has_clksel = 1, + .has_fixvclk = 1, }, .win[0] = &s3c_fb_data_s5p_wins[0], .win[1] = &s3c_fb_data_s5p_wins[1], @@ -1881,6 +1901,39 @@ static struct s3c_fb_driverdata s3c_fb_data_exynos4 = { }, .has_shadowcon = 1, + .has_blendcon = 1, + .has_fixvclk = 1, + }, + .win[0] = &s3c_fb_data_s5p_wins[0], + .win[1] = &s3c_fb_data_s5p_wins[1], + .win[2] = &s3c_fb_data_s5p_wins[2], + .win[3] = &s3c_fb_data_s5p_wins[3], + .win[4] = &s3c_fb_data_s5p_wins[4], +}; + +static struct s3c_fb_driverdata s3c_fb_data_exynos5 = { + .variant = { + .nr_windows = 5, + .vidtcon = VIDTCON0, + .wincon = WINCON(0), + .winmap = WINxMAP(0), + .keycon = WKEYCON, + .osd = VIDOSD_BASE, + .osd_stride = 16, + .buf_start = VIDW_BUF_START(0), + .buf_size = VIDW_BUF_SIZE(0), + .buf_end = VIDW_BUF_END(0), + + .palette = { + [0] = 0x2400, + [1] = 0x2800, + [2] = 0x2c00, + [3] = 0x3000, + [4] = 0x3400, + }, + .has_shadowcon = 1, + .has_blendcon = 1, + .has_fixvclk = 1, }, .win[0] = &s3c_fb_data_s5p_wins[0], .win[1] = &s3c_fb_data_s5p_wins[1], @@ -1944,6 +1997,9 @@ static struct s3c_fb_driverdata s3c_fb_data_s5p64x0 = { [1] = 0x2800, [2] = 0x2c00, }, + + .has_blendcon = 1, + .has_fixvclk = 1, }, .win[0] = &s3c_fb_data_s5p_wins[0], .win[1] = &s3c_fb_data_s5p_wins[1], @@ -1964,6 +2020,9 @@ static struct platform_device_id s3c_fb_driver_ids[] = { .name = "exynos4-fb", .driver_data = (unsigned long)&s3c_fb_data_exynos4, }, { + .name = "exynos5-fb", + .driver_data = (unsigned long)&s3c_fb_data_exynos5, + }, { .name = "s3c2443-fb", .driver_data = (unsigned long)&s3c_fb_data_s3c2443, }, { |