📄 mbxfb.c
字号:
switch (alpha->overlay_colorkey_mode) { case MBXFB_COLORKEY_DISABLED: break; case MBXFB_COLORKEY_PREVIOUS: vscadr |= VSCADR_COLKEY_EN; break; case MBXFB_COLORKEY_CURRENT: vscadr |= VSCADR_COLKEY_EN | VSCADR_COLKEYSRC; break; default: return -EINVAL; } switch (alpha->overlay_blend_mode) { case MBXFB_ALPHABLEND_NONE: vscadr |= VSCADR_BLEND_NONE; break; case MBXFB_ALPHABLEND_GLOBAL: vscadr |= VSCADR_BLEND_GLOB; break; case MBXFB_ALPHABLEND_PIXEL: vscadr |= VSCADR_BLEND_PIX; break; default: return -EINVAL; } switch (alpha->graphics_colorkey_mode) { case MBXFB_COLORKEY_DISABLED: break; case MBXFB_COLORKEY_PREVIOUS: gscadr |= GSCADR_COLKEY_EN; break; case MBXFB_COLORKEY_CURRENT: gscadr |= GSCADR_COLKEY_EN | GSCADR_COLKEYSRC; break; default: return -EINVAL; } switch (alpha->graphics_blend_mode) { case MBXFB_ALPHABLEND_NONE: gscadr |= GSCADR_BLEND_NONE; break; case MBXFB_ALPHABLEND_GLOBAL: gscadr |= GSCADR_BLEND_GLOB; break; case MBXFB_ALPHABLEND_PIXEL: gscadr |= GSCADR_BLEND_PIX; break; default: return -EINVAL; } write_reg_dly(vbbase, VBBASE); write_reg_dly(gbbase, GBBASE); write_reg_dly(vcmsk, VCMSK); write_reg_dly(gdrctrl, GDRCTRL); write_reg_dly(gscadr, GSCADR); write_reg_dly(vscadr, VSCADR); return 0;}static int mbxfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg){ struct mbxfb_overlaySetup setup; struct mbxfb_planeorder porder; struct mbxfb_alphaCtl alpha; struct mbxfb_reg reg; int res; __u32 tmp; switch (cmd) { case MBXFB_IOCX_OVERLAY: if (copy_from_user(&setup, (void __user*)arg, sizeof(struct mbxfb_overlaySetup))) return -EFAULT; res = mbxfb_setupOverlay(&setup); if (res) return res; if (copy_to_user((void __user*)arg, &setup, sizeof(struct mbxfb_overlaySetup))) return -EFAULT; return 0; case MBXFB_IOCS_PLANEORDER: if (copy_from_user(&porder, (void __user*)arg, sizeof(struct mbxfb_planeorder))) return -EFAULT; return mbxfb_ioctl_planeorder(&porder); case MBXFB_IOCS_ALPHA: if (copy_from_user(&alpha, (void __user*)arg, sizeof(struct mbxfb_alphaCtl))) return -EFAULT; return mbxfb_ioctl_alphactl(&alpha); case MBXFB_IOCS_REG: if (copy_from_user(®, (void __user*)arg, sizeof(struct mbxfb_reg))) return -EFAULT; if (reg.addr >= 0x10000) /* regs are from 0x3fe0000 to 0x3feffff */ return -EINVAL; tmp = readl(virt_base_2700 + reg.addr); tmp &= ~reg.mask; tmp |= reg.val & reg.mask; writel(tmp, virt_base_2700 + reg.addr); return 0; case MBXFB_IOCX_REG: if (copy_from_user(®, (void __user*)arg, sizeof(struct mbxfb_reg))) return -EFAULT; if (reg.addr >= 0x10000) /* regs are from 0x3fe0000 to 0x3feffff */ return -EINVAL; reg.val = readl(virt_base_2700 + reg.addr); if (copy_to_user((void __user*)arg, ®, sizeof(struct mbxfb_reg))) return -EFAULT; return 0; } return -EINVAL;}static struct fb_ops mbxfb_ops = { .owner = THIS_MODULE, .fb_check_var = mbxfb_check_var, .fb_set_par = mbxfb_set_par, .fb_setcolreg = mbxfb_setcolreg, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, .fb_blank = mbxfb_blank, .fb_ioctl = mbxfb_ioctl,};/* Enable external SDRAM controller. Assume that all clocks are active by now.*/static void __devinit setup_memc(struct fb_info *fbi){ unsigned long tmp; int i; /* FIXME: use platfrom specific parameters */ /* setup SDRAM controller */ write_reg_dly((LMCFG_LMC_DS | LMCFG_LMC_TS | LMCFG_LMD_TS | LMCFG_LMA_TS), LMCFG); write_reg_dly(LMPWR_MC_PWR_ACT, LMPWR); /* setup SDRAM timings */ write_reg_dly((Lmtim_Tras(7) | Lmtim_Trp(3) | Lmtim_Trcd(3) | Lmtim_Trc(9) | Lmtim_Tdpl(2)), LMTIM); /* setup SDRAM refresh rate */ write_reg_dly(0xc2b, LMREFRESH); /* setup SDRAM type parameters */ write_reg_dly((LMTYPE_CASLAT_3 | LMTYPE_BKSZ_2 | LMTYPE_ROWSZ_11 | LMTYPE_COLSZ_8), LMTYPE); /* enable memory controller */ write_reg_dly(LMPWR_MC_PWR_ACT, LMPWR); /* perform dummy reads */ for ( i = 0; i < 16; i++ ) { tmp = readl(fbi->screen_base); }}static void enable_clocks(struct fb_info *fbi){ /* enable clocks */ write_reg_dly(SYSCLKSRC_PLL_2, SYSCLKSRC); write_reg_dly(PIXCLKSRC_PLL_1, PIXCLKSRC); write_reg_dly(0x00000000, CLKSLEEP); /* PLL output = (Frefclk * M) / (N * 2^P ) * * M: 0x17, N: 0x3, P: 0x0 == 100 Mhz! * M: 0xb, N: 0x1, P: 0x1 == 71 Mhz * */ write_reg_dly((Core_Pll_M(0xb) | Core_Pll_N(0x1) | Core_Pll_P(0x1) | CORE_PLL_EN), COREPLL); write_reg_dly((Disp_Pll_M(0x1b) | Disp_Pll_N(0x7) | Disp_Pll_P(0x1) | DISP_PLL_EN), DISPPLL); write_reg_dly(0x00000000, VOVRCLK); write_reg_dly(PIXCLK_EN, PIXCLK); write_reg_dly(MEMCLK_EN, MEMCLK); write_reg_dly(0x00000001, M24CLK); write_reg_dly(0x00000001, MBXCLK); write_reg_dly(SDCLK_EN, SDCLK); write_reg_dly(0x00000001, PIXCLKDIV);}static void __devinit setup_graphics(struct fb_info *fbi){ unsigned long gsctrl; unsigned long vscadr; gsctrl = GSCTRL_GAMMA_EN | Gsctrl_Width(fbi->var.xres) | Gsctrl_Height(fbi->var.yres); switch (fbi->var.bits_per_pixel) { case 16: if (fbi->var.green.length == 5) gsctrl |= GSCTRL_GPIXFMT_ARGB1555; else gsctrl |= GSCTRL_GPIXFMT_RGB565; break; case 24: gsctrl |= GSCTRL_GPIXFMT_RGB888; break; case 32: gsctrl |= GSCTRL_GPIXFMT_ARGB8888; break; } write_reg_dly(gsctrl, GSCTRL); write_reg_dly(0x00000000, GBBASE); write_reg_dly(0x00ffffff, GDRCTRL); write_reg_dly((GSCADR_STR_EN | Gscadr_Gbase_Adr(0x6000)), GSCADR); write_reg_dly(0x00000000, GPLUT); vscadr = readl(VSCADR); vscadr &= ~(FMsk(VSCADR_BLEND_POS) | FMsk(VSCADR_BLEND_M)); vscadr |= VSCADR_BLEND_VID | VSCADR_BLEND_NONE; write_reg_dly(vscadr, VSCADR);}static void __devinit setup_display(struct fb_info *fbi){ unsigned long dsctrl = 0; dsctrl = DSCTRL_BLNK_POL; if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT) dsctrl |= DSCTRL_HS_POL; if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT) dsctrl |= DSCTRL_VS_POL; write_reg_dly(dsctrl, DSCTRL); write_reg_dly(0xd0303010, DMCTRL); write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);}static void __devinit enable_controller(struct fb_info *fbi){ u32 svctrl, shctrl; write_reg_dly(SYSRST_RST, SYSRST); /* setup a timeout, raise drive strength */ write_reg_dly(0xffffff0c, SYSCFG); enable_clocks(fbi); setup_memc(fbi); setup_graphics(fbi); setup_display(fbi); shctrl = readl(SHCTRL); shctrl &= ~(FMsk(SHCTRL_HINITIAL)); shctrl |= Shctrl_Hinitial(4<<11); writel(shctrl, SHCTRL); svctrl = Svctrl_Initial1(1<<10) | Svctrl_Initial2(1<<10); writel(svctrl, SVCTRL); writel(SPOCTRL_H_SC_BP | SPOCTRL_V_SC_BP | SPOCTRL_VORDER_4TAP , SPOCTRL); /* Those coefficients are good for scaling up. For scaling * down, the application has to calculate them. */ write_reg(0xff000100, VSCOEFF0); write_reg(0xfdfcfdfe, VSCOEFF1); write_reg(0x170d0500, VSCOEFF2); write_reg(0x3d372d22, VSCOEFF3); write_reg(0x00000040, VSCOEFF4); write_reg(0xff010100, HSCOEFF0); write_reg(0x00000000, HSCOEFF1); write_reg(0x02010000, HSCOEFF2); write_reg(0x01020302, HSCOEFF3); write_reg(0xf9fbfe00, HSCOEFF4); write_reg(0xfbf7f6f7, HSCOEFF5); write_reg(0x1c110700, HSCOEFF6); write_reg(0x3e393127, HSCOEFF7); write_reg(0x00000040, HSCOEFF8);}#ifdef CONFIG_PM/* * Power management hooks. Note that we won't be called from IRQ context, * unlike the blank functions above, so we may sleep. */static int mbxfb_suspend(struct platform_device *dev, pm_message_t state){ /* make frame buffer memory enter self-refresh mode */ write_reg_dly(LMPWR_MC_PWR_SRM, LMPWR); while (LMPWRSTAT != LMPWRSTAT_MC_PWR_SRM) ; /* empty statement */ /* reset the device, since it's initial state is 'mostly sleeping' */ write_reg_dly(SYSRST_RST, SYSRST); return 0;}static int mbxfb_resume(struct platform_device *dev){ struct fb_info *fbi = platform_get_drvdata(dev); enable_clocks(fbi);/* setup_graphics(fbi); *//* setup_display(fbi); */ write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL); return 0;}#else#define mbxfb_suspend NULL#define mbxfb_resume NULL#endif/* debugfs entries */#ifndef CONFIG_FB_MBX_DEBUG#define mbxfb_debugfs_init(x) do {} while(0)#define mbxfb_debugfs_remove(x) do {} while(0)#endif#define res_size(_r) (((_r)->end - (_r)->start) + 1)static int __devinit mbxfb_probe(struct platform_device *dev){ int ret; struct fb_info *fbi; struct mbxfb_info *mfbi; struct mbxfb_platform_data *pdata; dev_dbg(&dev->dev, "mbxfb_probe\n"); pdata = dev->dev.platform_data; if (!pdata) { dev_err(&dev->dev, "platform data is required\n"); return -EINVAL; } fbi = framebuffer_alloc(sizeof(struct mbxfb_info), &dev->dev); if (fbi == NULL) { dev_err(&dev->dev, "framebuffer_alloc failed\n"); return -ENOMEM; } mfbi = fbi->par; fbi->pseudo_palette = mfbi->pseudo_palette; if (pdata->probe) mfbi->platform_probe = pdata->probe; if (pdata->remove) mfbi->platform_remove = pdata->remove; mfbi->fb_res = platform_get_resource(dev, IORESOURCE_MEM, 0); mfbi->reg_res = platform_get_resource(dev, IORESOURCE_MEM, 1); if (!mfbi->fb_res || !mfbi->reg_res) { dev_err(&dev->dev, "no resources found\n"); ret = -ENODEV; goto err1; } mfbi->fb_req = request_mem_region(mfbi->fb_res->start, res_size(mfbi->fb_res), dev->name); if (mfbi->fb_req == NULL) { dev_err(&dev->dev, "failed to claim framebuffer memory\n"); ret = -EINVAL; goto err1; } mfbi->fb_phys_addr = mfbi->fb_res->start; mfbi->reg_req = request_mem_region(mfbi->reg_res->start, res_size(mfbi->reg_res), dev->name); if (mfbi->reg_req == NULL) { dev_err(&dev->dev, "failed to claim Marathon registers\n"); ret = -EINVAL; goto err2; } mfbi->reg_phys_addr = mfbi->reg_res->start; mfbi->reg_virt_addr = ioremap_nocache(mfbi->reg_phys_addr, res_size(mfbi->reg_req)); if (!mfbi->reg_virt_addr) { dev_err(&dev->dev, "failed to ioremap Marathon registers\n"); ret = -EINVAL; goto err3; } virt_base_2700 = (unsigned long)mfbi->reg_virt_addr; mfbi->fb_virt_addr = ioremap_nocache(mfbi->fb_phys_addr, res_size(mfbi->fb_req)); if (!mfbi->reg_virt_addr) { dev_err(&dev->dev, "failed to ioremap frame buffer\n"); ret = -EINVAL; goto err4; } fbi->screen_base = (char __iomem *)(mfbi->fb_virt_addr + 0x60000); fbi->screen_size = pdata->memsize; fbi->fbops = &mbxfb_ops; fbi->var = mbxfb_default; fbi->fix = mbxfb_fix; fbi->fix.smem_start = mfbi->fb_phys_addr + 0x60000; fbi->fix.smem_len = pdata->memsize; fbi->fix.line_length = mbxfb_default.xres_virtual * mbxfb_default.bits_per_pixel / 8; ret = fb_alloc_cmap(&fbi->cmap, 256, 0); if (ret < 0) { dev_err(&dev->dev, "fb_alloc_cmap failed\n"); ret = -EINVAL; goto err5; } platform_set_drvdata(dev, fbi); printk(KERN_INFO "fb%d: mbx frame buffer device\n", fbi->node); if (mfbi->platform_probe) mfbi->platform_probe(fbi); enable_controller(fbi); mbxfb_debugfs_init(fbi); ret = register_framebuffer(fbi); if (ret < 0) { dev_err(&dev->dev, "register_framebuffer failed\n"); ret = -EINVAL; goto err6; } return 0;err6: fb_dealloc_cmap(&fbi->cmap);err5: iounmap(mfbi->fb_virt_addr);err4: iounmap(mfbi->reg_virt_addr);err3: release_mem_region(mfbi->reg_res->start, res_size(mfbi->reg_res));err2: release_mem_region(mfbi->fb_res->start, res_size(mfbi->fb_res));err1: framebuffer_release(fbi); return ret;}static int __devexit mbxfb_remove(struct platform_device *dev){ struct fb_info *fbi = platform_get_drvdata(dev); write_reg_dly(SYSRST_RST, SYSRST); mbxfb_debugfs_remove(fbi); if (fbi) { struct mbxfb_info *mfbi = fbi->par; unregister_framebuffer(fbi); if (mfbi) { if (mfbi->platform_remove) mfbi->platform_remove(fbi); if (mfbi->fb_virt_addr) iounmap(mfbi->fb_virt_addr); if (mfbi->reg_virt_addr) iounmap(mfbi->reg_virt_addr); if (mfbi->reg_req) release_mem_region(mfbi->reg_req->start, res_size(mfbi->reg_req)); if (mfbi->fb_req) release_mem_region(mfbi->fb_req->start, res_size(mfbi->fb_req)); } framebuffer_release(fbi); } return 0;}static struct platform_driver mbxfb_driver = { .probe = mbxfb_probe, .remove = mbxfb_remove, .suspend = mbxfb_suspend, .resume = mbxfb_resume, .driver = { .name = "mbx-fb", },};int __devinit mbxfb_init(void){ return platform_driver_register(&mbxfb_driver);}static void __devexit mbxfb_exit(void){ platform_driver_unregister(&mbxfb_driver);}module_init(mbxfb_init);module_exit(mbxfb_exit);MODULE_DESCRIPTION("loadable framebuffer driver for Marathon device");MODULE_AUTHOR("Mike Rapoport, Compulab");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -