📄 s1d13xxxfb.c
字号:
{4, 8, 16, -1}, {9, 12, 18, -1},};/** * s1d13xxxfb_fetch_hw_state - Configure the framebuffer according to * hardware setup. * @info: frame buffer structure * * We setup the framebuffer structures according to the current * hardware setup. On some machines, the BIOS will have filled * the chip registers with such info, on others, these values will * have been written in some init procedure. In any case, the * software values needs to match the hardware ones. This is what * this function ensures. * * Note: some of the hardcoded values here might need some love to * work on various chips, and might need to no longer be hardcoded. */static void __devinits1d13xxxfb_fetch_hw_state(struct fb_info *info){ struct fb_var_screeninfo *var = &info->var; struct fb_fix_screeninfo *fix = &info->fix; struct s1d13xxxfb_par *par = info->par; u8 panel, display; u16 offset; u32 xres, yres; u32 xres_virtual, yres_virtual; int bpp, lcd_bpp; int is_color, is_dual, is_tft; int lcd_enabled, crt_enabled; fix->type = FB_TYPE_PACKED_PIXELS; /* general info */ par->display = s1d13xxxfb_readreg(par, S1DREG_COM_DISP_MODE); crt_enabled = (par->display & 0x02) != 0; lcd_enabled = (par->display & 0x01) != 0; if (lcd_enabled && crt_enabled) printk(KERN_WARNING PFX "Warning: LCD and CRT detected, using LCD\n"); if (lcd_enabled) display = s1d13xxxfb_readreg(par, S1DREG_LCD_DISP_MODE); else /* CRT */ display = s1d13xxxfb_readreg(par, S1DREG_CRT_DISP_MODE); bpp = display & 0x07; switch (bpp) { case 2: /* 4 bpp */ case 3: /* 8 bpp */ var->bits_per_pixel = 8; var->red.offset = var->green.offset = var->blue.offset = 0; var->red.length = var->green.length = var->blue.length = 8; break; case 5: /* 16 bpp */ s1d13xxxfb_setup_truecolour(info); break; default: dbg("bpp: %i\n", bpp); } fb_alloc_cmap(&info->cmap, 256, 0); /* LCD info */ panel = s1d13xxxfb_readreg(par, S1DREG_PANEL_TYPE); is_color = (panel & 0x04) != 0; is_dual = (panel & 0x02) != 0; is_tft = (panel & 0x01) != 0; lcd_bpp = s1d13xxxfb_width_tab[is_tft][(panel >> 4) & 3]; if (lcd_enabled) { xres = (s1d13xxxfb_readreg(par, S1DREG_LCD_DISP_HWIDTH) + 1) * 8; yres = (s1d13xxxfb_readreg(par, S1DREG_LCD_DISP_VHEIGHT0) + ((s1d13xxxfb_readreg(par, S1DREG_LCD_DISP_VHEIGHT1) & 0x03) << 8) + 1); offset = (s1d13xxxfb_readreg(par, S1DREG_LCD_MEM_OFF0) + ((s1d13xxxfb_readreg(par, S1DREG_LCD_MEM_OFF1) & 0x7) << 8)); } else { /* crt */ xres = (s1d13xxxfb_readreg(par, S1DREG_CRT_DISP_HWIDTH) + 1) * 8; yres = (s1d13xxxfb_readreg(par, S1DREG_CRT_DISP_VHEIGHT0) + ((s1d13xxxfb_readreg(par, S1DREG_CRT_DISP_VHEIGHT1) & 0x03) << 8) + 1); offset = (s1d13xxxfb_readreg(par, S1DREG_CRT_MEM_OFF0) + ((s1d13xxxfb_readreg(par, S1DREG_CRT_MEM_OFF1) & 0x7) << 8)); } xres_virtual = offset * 16 / var->bits_per_pixel; yres_virtual = fix->smem_len / (offset * 2); var->xres = xres; var->yres = yres; var->xres_virtual = xres_virtual; var->yres_virtual = yres_virtual; var->xoffset = var->yoffset = 0; fix->line_length = offset * 2; var->grayscale = !is_color; var->activate = FB_ACTIVATE_NOW; dbg(PFX "bpp=%d, lcd_bpp=%d, " "crt_enabled=%d, lcd_enabled=%d\n", var->bits_per_pixel, lcd_bpp, crt_enabled, lcd_enabled); dbg(PFX "xres=%d, yres=%d, vxres=%d, vyres=%d " "is_color=%d, is_dual=%d, is_tft=%d\n", xres, yres, xres_virtual, yres_virtual, is_color, is_dual, is_tft);}static ints1d13xxxfb_remove(struct platform_device *pdev){ struct fb_info *info = platform_get_drvdata(pdev); struct s1d13xxxfb_par *par = NULL; if (info) { par = info->par; if (par && par->regs) { /* disable output & enable powersave */ s1d13xxxfb_writereg(par, S1DREG_COM_DISP_MODE, 0x00); s1d13xxxfb_writereg(par, S1DREG_PS_CNF, 0x11); iounmap(par->regs); } fb_dealloc_cmap(&info->cmap); if (info->screen_base) iounmap(info->screen_base); framebuffer_release(info); } release_mem_region(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start +1); release_mem_region(pdev->resource[1].start, pdev->resource[1].end - pdev->resource[1].start +1); return 0;}static int __devinits1d13xxxfb_probe(struct platform_device *pdev){ struct s1d13xxxfb_par *default_par; struct fb_info *info; struct s1d13xxxfb_pdata *pdata = NULL; int ret = 0; int i; u8 revision; dbg("probe called: device is %p\n", pdev); printk(KERN_INFO "Epson S1D13XXX FB Driver\n"); /* enable platform-dependent hardware glue, if any */ if (pdev->dev.platform_data) pdata = pdev->dev.platform_data; if (pdata && pdata->platform_init_video) pdata->platform_init_video(); if (pdev->num_resources != 2) { dev_err(&pdev->dev, "invalid num_resources: %i\n", pdev->num_resources); ret = -ENODEV; goto bail; } /* resource[0] is VRAM, resource[1] is registers */ if (pdev->resource[0].flags != IORESOURCE_MEM || pdev->resource[1].flags != IORESOURCE_MEM) { dev_err(&pdev->dev, "invalid resource type\n"); ret = -ENODEV; goto bail; } if (!request_mem_region(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start +1, "s1d13xxxfb mem")) { dev_dbg(&pdev->dev, "request_mem_region failed\n"); ret = -EBUSY; goto bail; } if (!request_mem_region(pdev->resource[1].start, pdev->resource[1].end - pdev->resource[1].start +1, "s1d13xxxfb regs")) { dev_dbg(&pdev->dev, "request_mem_region failed\n"); ret = -EBUSY; goto bail; } info = framebuffer_alloc(sizeof(struct s1d13xxxfb_par) + sizeof(u32) * 256, &pdev->dev); if (!info) { ret = -ENOMEM; goto bail; } platform_set_drvdata(pdev, info); default_par = info->par; default_par->regs = ioremap_nocache(pdev->resource[1].start, pdev->resource[1].end - pdev->resource[1].start +1); if (!default_par->regs) { printk(KERN_ERR PFX "unable to map registers\n"); ret = -ENOMEM; goto bail; } info->pseudo_palette = default_par->pseudo_palette; info->screen_base = ioremap_nocache(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start +1); if (!info->screen_base) { printk(KERN_ERR PFX "unable to map framebuffer\n"); ret = -ENOMEM; goto bail; } revision = s1d13xxxfb_readreg(default_par, S1DREG_REV_CODE) >> 2; ret = -ENODEV; for (i = 0; i < ARRAY_SIZE(s1d13xxxfb_revisions); i++) { if (revision == s1d13xxxfb_revisions[i]) ret = 0; } if (!ret) printk(KERN_INFO PFX "chip revision %i\n", revision); else { printk(KERN_INFO PFX "unknown chip revision %i\n", revision); goto bail; } info->fix = s1d13xxxfb_fix; info->fix.mmio_start = pdev->resource[1].start; info->fix.mmio_len = pdev->resource[1].end - pdev->resource[1].start +1; info->fix.smem_start = pdev->resource[0].start; info->fix.smem_len = pdev->resource[0].end - pdev->resource[0].start +1; printk(KERN_INFO PFX "regs mapped at 0x%p, fb %d KiB mapped at 0x%p\n", default_par->regs, info->fix.smem_len / 1024, info->screen_base); info->par = default_par; info->fbops = &s1d13xxxfb_fbops; info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; /* perform "manual" chip initialization, if needed */ if (pdata && pdata->initregs) s1d13xxxfb_runinit(info->par, pdata->initregs, pdata->initregssize); s1d13xxxfb_fetch_hw_state(info); if (register_framebuffer(info) < 0) { ret = -EINVAL; goto bail; } printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); return 0;bail: s1d13xxxfb_remove(pdev); return ret;}#ifdef CONFIG_PMstatic int s1d13xxxfb_suspend(struct platform_device *dev, pm_message_t state){ struct fb_info *info = platform_get_drvdata(dev); struct s1d13xxxfb_par *s1dfb = info->par; struct s1d13xxxfb_pdata *pdata = NULL; /* disable display */ lcd_enable(s1dfb, 0); crt_enable(s1dfb, 0); if (dev->dev.platform_data) pdata = dev->dev.platform_data;#if 0 if (!s1dfb->disp_save) s1dfb->disp_save = kmalloc(info->fix.smem_len, GFP_KERNEL); if (!s1dfb->disp_save) { printk(KERN_ERR PFX "no memory to save screen"); return -ENOMEM; } memcpy_fromio(s1dfb->disp_save, info->screen_base, info->fix.smem_len);#else s1dfb->disp_save = NULL;#endif if (!s1dfb->regs_save) s1dfb->regs_save = kmalloc(info->fix.mmio_len, GFP_KERNEL); if (!s1dfb->regs_save) { printk(KERN_ERR PFX "no memory to save registers"); return -ENOMEM; } /* backup all registers */ memcpy_fromio(s1dfb->regs_save, s1dfb->regs, info->fix.mmio_len); /* now activate power save mode */ s1d13xxxfb_writereg(s1dfb, S1DREG_PS_CNF, 0x11); if (pdata && pdata->platform_suspend_video) return pdata->platform_suspend_video(); else return 0;}static int s1d13xxxfb_resume(struct platform_device *dev){ struct fb_info *info = platform_get_drvdata(dev); struct s1d13xxxfb_par *s1dfb = info->par; struct s1d13xxxfb_pdata *pdata = NULL; /* awaken the chip */ s1d13xxxfb_writereg(s1dfb, S1DREG_PS_CNF, 0x10); /* do not let go until SDRAM "wakes up" */ while ((s1d13xxxfb_readreg(s1dfb, S1DREG_PS_STATUS) & 0x01)) udelay(10); if (dev->dev.platform_data) pdata = dev->dev.platform_data; if (s1dfb->regs_save) { /* will write RO regs, *should* get away with it :) */ memcpy_toio(s1dfb->regs, s1dfb->regs_save, info->fix.mmio_len); kfree(s1dfb->regs_save); } if (s1dfb->disp_save) { memcpy_toio(info->screen_base, s1dfb->disp_save, info->fix.smem_len); kfree(s1dfb->disp_save); /* XXX kmalloc()'d when? */ } if ((s1dfb->display & 0x01) != 0) lcd_enable(s1dfb, 1); if ((s1dfb->display & 0x02) != 0) crt_enable(s1dfb, 1); if (pdata && pdata->platform_resume_video) return pdata->platform_resume_video(); else return 0;}#endif /* CONFIG_PM */static struct platform_driver s1d13xxxfb_driver = { .probe = s1d13xxxfb_probe, .remove = s1d13xxxfb_remove,#ifdef CONFIG_PM .suspend = s1d13xxxfb_suspend, .resume = s1d13xxxfb_resume,#endif .driver = { .name = S1D_DEVICENAME, },};static int __inits1d13xxxfb_init(void){#ifndef MODULE if (fb_get_options("s1d13xxxfb", NULL)) return -ENODEV;#endif return platform_driver_register(&s1d13xxxfb_driver);}static void __exits1d13xxxfb_exit(void){ platform_driver_unregister(&s1d13xxxfb_driver);}module_init(s1d13xxxfb_init);module_exit(s1d13xxxfb_exit);MODULE_LICENSE("GPL");MODULE_DESCRIPTION("Framebuffer driver for S1D13xxx devices");MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>, Thibaut VARENE <varenet@parisc-linux.org>");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -