📄 sm501fb.c
字号:
if (ret < 0) return ret; /* initialise the colour registers */ writel(par->cursor.sm_addr, par->cursor_regs + SM501_OFF_HWC_ADDR); writel(0x00, par->cursor_regs + SM501_OFF_HWC_LOC); writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_1_2); writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_3); sm501fb_sync_regs(info); return 0;}/* sm501fb_info_start * * fills the par structure claiming resources and remapping etc.*/static int sm501fb_start(struct sm501fb_info *info, struct platform_device *pdev){ struct resource *res; struct device *dev = &pdev->dev; int k; int ret; info->irq = ret = platform_get_irq(pdev, 0); if (ret < 0) { /* we currently do not use the IRQ */ dev_warn(dev, "no irq for device\n"); } /* allocate, reserve and remap resources for registers */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { dev_err(dev, "no resource definition for registers\n"); ret = -ENOENT; goto err_release; } info->regs_res = request_mem_region(res->start, res->end - res->start, pdev->name); if (info->regs_res == NULL) { dev_err(dev, "cannot claim registers\n"); ret = -ENXIO; goto err_release; } info->regs = ioremap(res->start, (res->end - res->start)+1); if (info->regs == NULL) { dev_err(dev, "cannot remap registers\n"); ret = -ENXIO; goto err_regs_res; } /* allocate, reserve resources for framebuffer */ res = platform_get_resource(pdev, IORESOURCE_MEM, 2); if (res == NULL) { dev_err(dev, "no memory resource defined\n"); ret = -ENXIO; goto err_regs_map; } info->fbmem_res = request_mem_region(res->start, (res->end - res->start)+1, pdev->name); if (info->fbmem_res == NULL) { dev_err(dev, "cannot claim framebuffer\n"); ret = -ENXIO; goto err_regs_map; } info->fbmem = ioremap(res->start, (res->end - res->start)+1); if (info->fbmem == NULL) { dev_err(dev, "cannot remap framebuffer\n"); goto err_mem_res; } info->fbmem_len = (res->end - res->start)+1; /* clear framebuffer 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++) writel(0, info->regs + SM501_DC_PANEL_PALETTE + (k * 4)); /* enable display controller */ sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1); /* setup cursors */ sm501_init_cursor(info->fb[HEAD_CRT], SM501_DC_CRT_HWC_ADDR); sm501_init_cursor(info->fb[HEAD_PANEL], SM501_DC_PANEL_HWC_ADDR); return 0; /* everything is setup */ err_mem_res: release_resource(info->fbmem_res); kfree(info->fbmem_res); err_regs_map: iounmap(info->regs); err_regs_res: release_resource(info->regs_res); kfree(info->regs_res); err_release: return ret;}static void sm501fb_stop(struct sm501fb_info *info){ /* disable display controller */ sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 0); iounmap(info->fbmem); release_resource(info->fbmem_res); kfree(info->fbmem_res); iounmap(info->regs); release_resource(info->regs_res); kfree(info->regs_res);}static int sm501fb_init_fb(struct fb_info *fb, enum sm501_controller head, const char *fbname){ struct sm501_platdata_fbsub *pd; struct sm501fb_par *par = fb->par; struct sm501fb_info *info = par->info; unsigned long ctrl; unsigned int enable; int ret; switch (head) { case HEAD_CRT: pd = info->pdata->fb_crt; ctrl = readl(info->regs + SM501_DC_CRT_CONTROL); enable = (ctrl & SM501_DC_CRT_CONTROL_ENABLE) ? 1 : 0; /* ensure we set the correct source register */ if (info->pdata->fb_route != SM501_FB_CRT_PANEL) { ctrl |= SM501_DC_CRT_CONTROL_SEL; writel(ctrl, info->regs + SM501_DC_CRT_CONTROL); } break; case HEAD_PANEL: pd = info->pdata->fb_pnl; ctrl = readl(info->regs + SM501_DC_PANEL_CONTROL); enable = (ctrl & SM501_DC_PANEL_CONTROL_EN) ? 1 : 0; break; default: pd = NULL; /* stop compiler warnings */ ctrl = 0; enable = 0; BUG(); } dev_info(info->dev, "fb %s %sabled at start\n", fbname, enable ? "en" : "dis"); /* check to see if our routing allows this */ if (head == HEAD_CRT && info->pdata->fb_route == SM501_FB_CRT_PANEL) { ctrl &= ~SM501_DC_CRT_CONTROL_SEL; writel(ctrl, info->regs + SM501_DC_CRT_CONTROL); enable = 0; } strlcpy(fb->fix.id, fbname, sizeof(fb->fix.id)); memcpy(&par->ops, (head == HEAD_CRT) ? &sm501fb_ops_crt : &sm501fb_ops_pnl, sizeof(struct fb_ops)); /* update ops dependant on what we've been passed */ if ((pd->flags & SM501FB_FLAG_USE_HWCURSOR) == 0) par->ops.fb_cursor = NULL; fb->fbops = &par->ops; fb->flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN; /* fixed data */ fb->fix.type = FB_TYPE_PACKED_PIXELS; fb->fix.type_aux = 0; fb->fix.xpanstep = 1; fb->fix.ypanstep = 1; fb->fix.ywrapstep = 0; fb->fix.accel = FB_ACCEL_NONE; /* screenmode */ fb->var.nonstd = 0; fb->var.activate = FB_ACTIVATE_NOW; fb->var.accel_flags = 0; 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 */ } else { if (pd->def_mode) { dev_info(info->dev, "using supplied mode\n"); fb_videomode_to_var(&fb->var, pd->def_mode); fb->var.bits_per_pixel = pd->def_bpp ? pd->def_bpp : 8; fb->var.xres_virtual = fb->var.xres; fb->var.yres_virtual = fb->var.yres; } else { ret = fb_find_mode(&fb->var, fb, NULL, NULL, 0, NULL, 8); if (ret == 0 || ret == 4) { dev_err(info->dev, "failed to get initial mode\n"); return -EINVAL; } } } /* initialise and set the palette */ fb_alloc_cmap(&fb->cmap, NR_PALETTE, 0); fb_set_cmap(&fb->cmap, fb); ret = (fb->fbops->fb_check_var)(&fb->var, fb); if (ret) dev_err(info->dev, "check_var() failed on initial setup?\n"); /* ensure we've activated our new configuration */ (fb->fbops->fb_set_par)(fb); return 0;}/* default platform data if none is supplied (ie, PCI device) */static struct sm501_platdata_fbsub sm501fb_pdata_crt = { .flags = (SM501FB_FLAG_USE_INIT_MODE | SM501FB_FLAG_USE_HWCURSOR | SM501FB_FLAG_USE_HWACCEL | SM501FB_FLAG_DISABLE_AT_EXIT),};static struct sm501_platdata_fbsub sm501fb_pdata_pnl = { .flags = (SM501FB_FLAG_USE_INIT_MODE | SM501FB_FLAG_USE_HWCURSOR | SM501FB_FLAG_USE_HWACCEL | SM501FB_FLAG_DISABLE_AT_EXIT),};static struct sm501_platdata_fb sm501fb_def_pdata = { .fb_route = SM501_FB_OWN, .fb_crt = &sm501fb_pdata_crt, .fb_pnl = &sm501fb_pdata_pnl,};static char driver_name_crt[] = "sm501fb-crt";static char driver_name_pnl[] = "sm501fb-panel";static int __devinit sm501fb_probe_one(struct sm501fb_info *info, enum sm501_controller head){ unsigned char *name = (head == HEAD_CRT) ? "crt" : "panel"; struct sm501_platdata_fbsub *pd; struct sm501fb_par *par; struct fb_info *fbi; pd = (head == HEAD_CRT) ? info->pdata->fb_crt : info->pdata->fb_pnl; /* Do not initialise if we've not been given any platform data */ if (pd == NULL) { dev_info(info->dev, "no data for fb %s (disabled)\n", name); return 0; } fbi = framebuffer_alloc(sizeof(struct sm501fb_par), info->dev); if (fbi == NULL) { dev_err(info->dev, "cannot allocate %s framebuffer\n", name); return -ENOMEM; } par = fbi->par; par->info = info; par->head = head; fbi->pseudo_palette = &par->pseudo_palette; info->fb[head] = fbi; return 0;}/* Free up anything allocated by sm501fb_init_fb */static void sm501_free_init_fb(struct sm501fb_info *info, enum sm501_controller head){ struct fb_info *fbi = info->fb[head]; fb_dealloc_cmap(&fbi->cmap);}static int __devinit sm501fb_start_one(struct sm501fb_info *info, enum sm501_controller head, const char *drvname){ struct fb_info *fbi = info->fb[head]; int ret; if (!fbi) return 0; ret = sm501fb_init_fb(info->fb[head], head, drvname); if (ret) { dev_err(info->dev, "cannot initialise fb %s\n", drvname); return ret; } ret = register_framebuffer(info->fb[head]); if (ret) { dev_err(info->dev, "failed to register fb %s\n", drvname); sm501_free_init_fb(info, head); return ret; } dev_info(info->dev, "fb%d: %s frame buffer\n", fbi->node, fbi->fix.id); return 0;}static int __devinit sm501fb_probe(struct platform_device *pdev){ struct sm501fb_info *info; struct device *dev = &pdev->dev; int ret; /* allocate our framebuffers */ info = kzalloc(sizeof(struct sm501fb_info), GFP_KERNEL); if (!info) { dev_err(dev, "failed to allocate state\n"); return -ENOMEM; } info->dev = dev = &pdev->dev; platform_set_drvdata(pdev, info); if (dev->parent->platform_data) { struct sm501_platdata *pd = dev->parent->platform_data; info->pdata = pd->fb; } if (info->pdata == NULL) { dev_info(dev, "using default configuration data\n"); info->pdata = &sm501fb_def_pdata; } /* 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; } if (info->fb[HEAD_PANEL] == NULL && info->fb[HEAD_CRT] == NULL) { dev_err(dev, "no framebuffers found\n"); goto err_alloc; } /* get the resources for both of the framebuffers */ ret = sm501fb_start(info, pdev); if (ret) { dev_err(dev, "cannot initialise SM501\n"); 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; } /* create device files */ ret = device_create_file(dev, &dev_attr_crt_src); if (ret) goto err_started_panel; ret = device_create_file(dev, &dev_attr_fbregs_pnl); if (ret) goto err_attached_crtsrc_file; ret = device_create_file(dev, &dev_attr_fbregs_crt); if (ret) goto err_attached_pnlregs_file; /* we registered, return ok */ return 0;err_attached_pnlregs_file: device_remove_file(dev, &dev_attr_fbregs_pnl);err_attached_crtsrc_file: device_remove_file(dev, &dev_attr_crt_src);err_started_panel: unregister_framebuffer(info->fb[HEAD_PANEL]); sm501_free_init_fb(info, HEAD_PANEL);err_started_crt: unregister_framebuffer(info->fb[HEAD_CRT]); sm501_free_init_fb(info, HEAD_CRT);err_started: sm501fb_stop(info);err_probed_panel: framebuffer_release(info->fb[HEAD_PANEL]);err_probed_crt: framebuffer_release(info->fb[HEAD_CRT]);err_alloc: kfree(info); return ret;}/* * Cleanup */static int sm501fb_remove(struct platform_device *pdev){ struct sm501fb_info *info = platform_get_drvdata(pdev); struct fb_info *fbinfo_crt = info->fb[0]; struct fb_info *fbinfo_pnl = info->fb[1]; device_remove_file(&pdev->dev, &dev_attr_fbregs_crt); device_remove_file(&pdev->dev, &dev_attr_fbregs_pnl); device_remove_file(&pdev->dev, &dev_attr_crt_src); sm501_free_init_fb(info, HEAD_CRT); sm501_free_init_fb(info, HEAD_PANEL); unregister_framebuffer(fbinfo_crt); unregister_framebuffer(fbinfo_pnl); sm501fb_stop(info); kfree(info); framebuffer_release(fbinfo_pnl); framebuffer_release(fbinfo_crt); return 0;}#ifdef CONFIG_PMstatic int sm501fb_suspend_fb(struct sm501fb_info *info, enum sm501_controller head){ struct fb_info *fbi = info->fb[head]; struct sm501fb_par *par = fbi->par; if (par->screen.size == 0) return 0; /* blank the relevant interface to ensure unit power minimised */ (par->ops.fb_blank)(FB_BLANK_POWERDOWN, fbi); /* tell console/fb driver we are suspending */ acquire_console_sem(); fb_set_suspend(fbi, 1); release_console_sem(); /* backup copies in case chip is powered down over suspend */ par->store_fb = vmalloc(par->screen.size); if (par->store_fb == NULL) { dev_err(info->dev, "no memory to store screen\n"); return -ENOMEM; } par->store_cursor = vmalloc(par->cursor.size); if (par->store_cursor == NULL) { dev_err(info->dev, "no memory to store cursor\n"); goto err_nocursor; } dev_dbg(info->dev, "suspending screen to %p\n", par->store_fb); dev_dbg(info->dev, "suspending cursor to %p\n", par->store_cursor); memcpy_fromio(par->store_fb, par->screen.k_addr, par->screen.size); memcpy_fromio(par->store_cursor, par->cursor.k_addr, par->cursor.size); return 0; err_nocursor: vfree(par->store_fb); par->store_fb = NULL; return -ENOMEM;}static void sm501fb_resume_fb(struct sm501fb_info *info, enum sm501_controller head){ struct fb_info *fbi = info->fb[head]; struct sm501fb_par *par = fbi->par; if (par->screen.size == 0) return; /* re-activate the configuration */ (par->ops.fb_set_par)(fbi); /* restore the data */ dev_dbg(info->dev, "restoring screen from %p\n", par->store_fb); dev_dbg(info->dev, "restoring cursor from %p\n", par->store_cursor); if (par->store_fb) memcpy_toio(par->screen.k_addr, par->store_fb, par->screen.size); if (par->store_cursor) memcpy_toio(par->cursor.k_addr, par->store_cursor, par->cursor.size); acquire_console_sem(); fb_set_suspend(fbi, 0); release_console_sem(); vfree(par->store_fb); vfree(par->store_cursor);}/* suspend and resume support */static int sm501fb_suspend(struct platform_device *pdev, pm_message_t state){ struct sm501fb_info *info = platform_get_drvdata(pdev); /* store crt control to resume with */ info->pm_crt_ctrl = readl(info->regs + SM501_DC_CRT_CONTROL); sm501fb_suspend_fb(info, HEAD_CRT); sm501fb_suspend_fb(info, HEAD_PANEL); /* turn off the clocks, in case the device is not powered down */ sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 0); return 0;}#define SM501_CRT_CTRL_SAVE (SM501_DC_CRT_CONTROL_TVP | \ SM501_DC_CRT_CONTROL_SEL)static int sm501fb_resume(struct platform_device *pdev){ struct sm501fb_info *info = platform_get_drvdata(pdev); unsigned long crt_ctrl; sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 1); /* restore the items we want to be saved for crt control */ crt_ctrl = readl(info->regs + SM501_DC_CRT_CONTROL); crt_ctrl &= ~SM501_CRT_CTRL_SAVE; crt_ctrl |= info->pm_crt_ctrl & SM501_CRT_CTRL_SAVE; writel(crt_ctrl, info->regs + SM501_DC_CRT_CONTROL); sm501fb_resume_fb(info, HEAD_CRT); sm501fb_resume_fb(info, HEAD_PANEL); return 0;}#else#define sm501fb_suspend NULL#define sm501fb_resume NULL#endifstatic struct platform_driver sm501fb_driver = { .probe = sm501fb_probe, .remove = sm501fb_remove, .suspend = sm501fb_suspend, .resume = sm501fb_resume, .driver = { .name = "sm501-fb", .owner = THIS_MODULE, },};static int __devinit sm501fb_init(void){ return platform_driver_register(&sm501fb_driver);}static void __exit sm501fb_cleanup(void){ platform_driver_unregister(&sm501fb_driver);}module_init(sm501fb_init);module_exit(sm501fb_cleanup);MODULE_AUTHOR("Ben Dooks, Vincent Sanders");MODULE_DESCRIPTION("SM501 Framebuffer driver");MODULE_LICENSE("GPL v2");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -