diff options
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/s3c-fb.c | 208 |
1 files changed, 180 insertions, 28 deletions
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index f9d0170b241..e700cfd5002 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c @@ -1,7 +1,7 @@ /* linux/drivers/video/s3c-fb.c * * Copyright 2008 Openmoko Inc. - * Copyright 2008 Simtec Electronics + * Copyright 2008-2010 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> * http://armlinux.simtec.co.uk/ * @@ -36,9 +36,9 @@ * output timings and as the control for the output power-down state. */ -/* note, some of the functions that get called are derived from including - * <mach/regs-fb.h> as they are specific to the architecture that the code - * is being built for. +/* note, the previous use of <mach/regs-fb.h> to get platform specific data + * has been replaced by using the platform device name to pick the correct + * configuration data for the system. */ #ifdef CONFIG_FB_S3C_DEBUG_REGWRITE @@ -50,11 +50,52 @@ struct s3c_fb; +#define VALID_BPP(x) (1 << ((x) - 1)) + +/** + * struct s3c_fb_variant - fb variant information + * @nr_windows: The number of windows. + * @palette: Address of palette memory, or 0 if none. + */ +struct s3c_fb_variant { + unsigned short nr_windows; + unsigned short palette[S3C_FB_MAX_WIN]; +}; + +/** + * struct s3c_fb_win_variant + * @has_osd_c: Set if has OSD C register. + * @has_osd_d: Set if has OSD D register. + * @palette_sz: Size of palette in entries. + * @palette_16bpp: Set if palette is 16bits wide. + * @valid_bpp: 1 bit per BPP setting to show valid bits-per-pixel. + * + * valid_bpp bit x is set if (x+1)BPP is supported. + */ +struct s3c_fb_win_variant { + unsigned int has_osd_c:1; + unsigned int has_osd_d:1; + unsigned int palette_16bpp:1; + unsigned short palette_sz; + u32 valid_bpp; +}; + +/** + * struct s3c_fb_driverdata - per-device type driver data for init time. + * @variant: The variant information for this driver. + * @win: The window information for each window. + */ +struct s3c_fb_driverdata { + struct s3c_fb_variant variant; + struct s3c_fb_win_variant *win[S3C_FB_MAX_WIN]; +}; + /** * struct s3c_fb_win - per window private data for each framebuffer. * @windata: The platform data supplied for the window configuration. * @parent: The hardware that this window is part of. * @fbinfo: Pointer pack to the framebuffer info for this window. + * @varint: The variant information for this window. * @palette_buffer: Buffer/cache to hold palette entries. * @pseudo_palette: For use in TRUECOLOUR modes for entries 0..15/ * @index: The window number of this window. @@ -65,6 +106,7 @@ struct s3c_fb_win { struct s3c_fb *parent; struct fb_info *fbinfo; struct s3c_fb_palette palette; + struct s3c_fb_win_variant variant; u32 *palette_buffer; u32 pseudo_palette[16]; @@ -77,6 +119,7 @@ struct s3c_fb_win { * @regs_res: The resource we claimed for the IO registers. * @bus_clk: The clk (hclk) feeding our interface and possibly pixclk. * @regs: The mapped hardware registers. + * @variant: Variant information for this hardware. * @enabled: A bitmask of enabled hardware windows. * @pdata: The platform configuration data passed with the device. * @windows: The hardware windows that have been claimed. @@ -86,6 +129,7 @@ struct s3c_fb { struct resource *regs_res; struct clk *bus_clk; void __iomem *regs; + struct s3c_fb_variant variant; unsigned char enabled; @@ -94,15 +138,13 @@ struct s3c_fb { }; /** - * s3c_fb_win_has_palette() - determine if a mode has a palette - * @win: The window number being queried. - * @bpp: The number of bits per pixel to test. - * - * Work out if the given window supports palletised data at the specified bpp. + * s3c_fb_validate_win_bpp - validate the bits-per-pixel for this mode. + * @win: The device window. + * @bpp: The bit depth. */ -static int s3c_fb_win_has_palette(unsigned int win, unsigned int bpp) +static bool s3c_fb_validate_win_bpp(struct s3c_fb_win *win, unsigned int bpp) { - return s3c_fb_win_pal_size(win) <= (1 << bpp); + return win->variant.valid_bpp & VALID_BPP(bpp); } /** @@ -125,7 +167,7 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var, var->xres_virtual = max((unsigned int)windata->virtual_x, var->xres); var->yres_virtual = max((unsigned int)windata->virtual_y, var->yres); - if (!s3c_fb_validate_win_bpp(win->index, var->bits_per_pixel)) { + if (!s3c_fb_validate_win_bpp(win, var->bits_per_pixel)) { dev_dbg(sfb->dev, "win %d: unsupported bpp %d\n", win->index, var->bits_per_pixel); return -EINVAL; @@ -140,7 +182,7 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var, case 2: case 4: case 8: - if (!s3c_fb_win_has_palette(win->index, var->bits_per_pixel)) { + if (sfb->variant.palette[win->index] != 0) { /* non palletised, A:1,R:2,G:3,B:2 mode */ var->red.offset = 4; var->green.offset = 2; @@ -282,7 +324,7 @@ static int s3c_fb_set_par(struct fb_info *info) info->fix.visual = FB_VISUAL_TRUECOLOR; break; case 8: - if (s3c_fb_win_has_palette(win_no, 8)) + if (win->variant.palette_sz >= 256) info->fix.visual = FB_VISUAL_PSEUDOCOLOR; else info->fix.visual = FB_VISUAL_TRUECOLOR; @@ -364,7 +406,7 @@ static int s3c_fb_set_par(struct fb_info *info) VIDISD14C_ALPHA1_G(0xf) | VIDISD14C_ALPHA1_B(0xf); - if (s3c_fb_has_osd_d(win_no)) { + if (win->variant.has_osd_d) { writel(data, regs + VIDOSD_D(win_no)); writel(osdc_data, regs + VIDOSD_C(win_no)); } else @@ -471,7 +513,7 @@ static void s3c_fb_update_palette(struct s3c_fb *sfb, void __iomem *palreg; u32 palcon; - palreg = sfb->regs + s3c_fb_pal_reg(win->index, reg); + palreg = sfb->regs + sfb->variant.palette[win->index]; dev_dbg(sfb->dev, "%s: win %d, reg %d (%p): %08x\n", __func__, win->index, reg, palreg, value); @@ -481,10 +523,10 @@ static void s3c_fb_update_palette(struct s3c_fb *sfb, palcon = readl(sfb->regs + WPALCON); writel(palcon | WPALCON_PAL_UPDATE, sfb->regs + WPALCON); - if (s3c_fb_pal_is16(win->index)) - writew(value, palreg); + if (win->variant.palette_16bpp) + writew(value, palreg + (reg * 2)); else - writel(value, palreg); + writel(value, palreg + (reg * 4)); writel(palcon, sfb->regs + WPALCON); } @@ -533,7 +575,7 @@ static int s3c_fb_setcolreg(unsigned regno, break; case FB_VISUAL_PSEUDOCOLOR: - if (regno < s3c_fb_win_pal_size(win->index)) { + if (regno < win->variant.palette_sz) { val = chan_to_field(red, &win->palette.r); val |= chan_to_field(green, &win->palette.g); val |= chan_to_field(blue, &win->palette.b); @@ -736,12 +778,14 @@ static void s3c_fb_release_win(struct s3c_fb *sfb, struct s3c_fb_win *win) /** * s3c_fb_probe_win() - register an hardware window * @sfb: The base resources for the hardware + * @variant: The variant information for this window. * @res: Pointer to where to place the resultant window. * * Allocate and do the basic initialisation for one of the hardware's graphics * windows. */ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no, + struct s3c_fb_win_variant *variant, struct s3c_fb_win **res) { struct fb_var_screeninfo *var; @@ -754,7 +798,7 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no, dev_dbg(sfb->dev, "probing window %d\n", win_no); - palette_size = s3c_fb_win_pal_size(win_no); + palette_size = variant->palette_sz * 4; fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) + palette_size * sizeof(u32), sfb->dev); @@ -772,6 +816,7 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no, win = fbinfo->par; var = &fbinfo->var; + win->variant = *variant; win->fbinfo = fbinfo; win->parent = sfb; win->windata = windata; @@ -809,7 +854,7 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no, /* create initial colour map */ - ret = fb_alloc_cmap(&fbinfo->cmap, s3c_fb_win_pal_size(win_no), 1); + ret = fb_alloc_cmap(&fbinfo->cmap, win->variant.palette_sz, 1); if (ret == 0) fb_set_cmap(&fbinfo->cmap, fbinfo); else @@ -852,6 +897,7 @@ static void s3c_fb_clear_win(struct s3c_fb *sfb, int win) static int __devinit s3c_fb_probe(struct platform_device *pdev) { + struct s3c_fb_driverdata *fbdrv; struct device *dev = &pdev->dev; struct s3c_fb_platdata *pd; struct s3c_fb *sfb; @@ -859,6 +905,13 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) int win; int ret = 0; + fbdrv = (struct s3c_fb_driverdata *)platform_get_device_id(pdev)->driver_data; + + if (fbdrv->variant.nr_windows > S3C_FB_MAX_WIN) { + dev_err(dev, "too many windows, cannot attach\n"); + return -EINVAL; + } + pd = pdev->dev.platform_data; if (!pd) { dev_err(dev, "no platform data specified\n"); @@ -873,6 +926,7 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) sfb->dev = dev; sfb->pdata = pd; + sfb->variant = fbdrv->variant; sfb->bus_clk = clk_get(dev, "lcd"); if (IS_ERR(sfb->bus_clk)) { @@ -914,22 +968,23 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) /* zero all windows before we do anything */ - for (win = 0; win < S3C_FB_MAX_WIN; win++) + for (win = 0; win < fbdrv->variant.nr_windows; win++) s3c_fb_clear_win(sfb, win); /* initialise colour key controls */ - for (win = 0; win < (S3C_FB_MAX_WIN - 1); win++) { + for (win = 0; win < (fbdrv->variant.nr_windows - 1); win++) { writel(0xffffff, sfb->regs + WxKEYCONy(win, 0)); writel(0xffffff, sfb->regs + WxKEYCONy(win, 1)); } /* we have the register setup, start allocating framebuffers */ - for (win = 0; win < S3C_FB_MAX_WIN; win++) { + for (win = 0; win < fbdrv->variant.nr_windows; win++) { if (!pd->win[win]) continue; - ret = s3c_fb_probe_win(sfb, win, &sfb->windows[win]); + ret = s3c_fb_probe_win(sfb, win, fbdrv->win[win], + &sfb->windows[win]); if (ret < 0) { dev_err(dev, "failed to create window %d\n", win); for (; win >= 0; win--) @@ -1020,10 +1075,10 @@ static int s3c_fb_resume(struct platform_device *pdev) writel(pd->vidcon1, sfb->regs + VIDCON1); /* zero all windows before we do anything */ - for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) + for (win_no = 0; win_no < sfb->variant.nr_windows; win_no++) s3c_fb_clear_win(sfb, win_no); - for (win_no = 0; win_no < S3C_FB_MAX_WIN - 1; win_no++) { + for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) { writel(0xffffff, sfb->regs + WxKEYCONy(win_no, 1)); writel(0xffffff, sfb->regs + WxKEYCONy(win_no, 1)); } @@ -1045,11 +1100,108 @@ static int s3c_fb_resume(struct platform_device *pdev) #define s3c_fb_resume NULL #endif + +#define VALID_BPP124 (VALID_BPP(1) | VALID_BPP(2) | VALID_BPP(4)) +#define VALID_BPP1248 (VALID_BPP124 | VALID_BPP(8)) + +static struct s3c_fb_win_variant s3c_fb_data_64xx_wins[] __devinitdata = { + [0] = { + .has_osd_c = 1, + .palette_sz = 256, + .valid_bpp = VALID_BPP1248 | VALID_BPP(16) | VALID_BPP(24), + }, + [1] = { + .has_osd_c = 1, + .has_osd_d = 1, + .palette_sz = 256, + .valid_bpp = (VALID_BPP1248 | VALID_BPP(16) | + VALID_BPP(18) | VALID_BPP(19) | + VALID_BPP(24) | VALID_BPP(25)), + }, + [2] = { + .has_osd_c = 1, + .has_osd_d = 1, + .palette_sz = 16, + .palette_16bpp = 1, + .valid_bpp = (VALID_BPP1248 | VALID_BPP(16) | + VALID_BPP(18) | VALID_BPP(19) | + VALID_BPP(24) | VALID_BPP(25)), + }, + [3] = { + .has_osd_c = 1, + .has_osd_d = 1, + .palette_sz = 16, + .palette_16bpp = 1, + .valid_bpp = (VALID_BPP124 | VALID_BPP(16) | + VALID_BPP(18) | VALID_BPP(19) | + VALID_BPP(24) | VALID_BPP(25)), + }, + [4] = { + .has_osd_c = 1, + .palette_sz = 4, + .palette_16bpp = 1, + .valid_bpp = (VALID_BPP(1) | VALID_BPP(2) | + VALID_BPP(16) | VALID_BPP(18) | + VALID_BPP(24) | VALID_BPP(25)), + }, +}; + +static struct s3c_fb_driverdata s3c_fb_data_64xx __devinitdata = { + .variant = { + .nr_windows = 5, + + .palette = { + [0] = 0x400, + [1] = 0x800, + [2] = 0x300, + [3] = 0x320, + [4] = 0x340, + }, + }, + .win[0] = &s3c_fb_data_64xx_wins[0], + .win[1] = &s3c_fb_data_64xx_wins[1], + .win[2] = &s3c_fb_data_64xx_wins[2], + .win[3] = &s3c_fb_data_64xx_wins[3], + .win[4] = &s3c_fb_data_64xx_wins[4], +}; + +static struct s3c_fb_driverdata s3c_fb_data_s5p __devinitdata = { + .variant = { + .nr_windows = 5, + + .palette = { + [0] = 0x2400, + [1] = 0x2800, + [2] = 0x2c00, + [3] = 0x3000, + [4] = 0x3400, + }, + }, + .win[0] = &s3c_fb_data_64xx_wins[0], + .win[1] = &s3c_fb_data_64xx_wins[1], + .win[2] = &s3c_fb_data_64xx_wins[2], + .win[3] = &s3c_fb_data_64xx_wins[3], + .win[4] = &s3c_fb_data_64xx_wins[4], +}; + +static struct platform_device_id s3c_fb_driver_ids[] = { + { + .name = "s3c-fb", + .driver_data = (unsigned long)&s3c_fb_data_64xx, + }, { + .name = "s5p-fb", + .driver_data = (unsigned long)&s3c_fb_data_s5p, + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, s3c_fb_driver_ids); + static struct platform_driver s3c_fb_driver = { .probe = s3c_fb_probe, .remove = __devexit_p(s3c_fb_remove), .suspend = s3c_fb_suspend, .resume = s3c_fb_resume, + .id_table = s3c_fb_driver_ids, .driver = { .name = "s3c-fb", .owner = THIS_MODULE, |