📄 pxafb.c
字号:
goto decode_mode; } if (lcd_conn == LCD_MONO_STN_8BPP) fbi->lccr0 |= LCCR0_DPD; fbi->lccr0 |= (lcd_conn & LCD_ALTERNATE_MAPPING) ? LCCR0_LDDALT : 0; fbi->lccr3 = LCCR3_Acb((inf->lcd_conn >> 10) & 0xff); fbi->lccr3 |= (lcd_conn & LCD_BIAS_ACTIVE_LOW) ? LCCR3_OEP : 0; fbi->lccr3 |= (lcd_conn & LCD_PCLK_EDGE_FALL) ? LCCR3_PCP : 0;decode_mode: pxafb_setmode(&fbi->fb.var, &inf->modes[0]); /* decide video memory size as follows: * 1. default to mode of maximum resolution * 2. allow platform to override * 3. allow module parameter to override */ for (i = 0, m = &inf->modes[0]; i < inf->num_modes; i++, m++) fbi->video_mem_size = max_t(size_t, fbi->video_mem_size, m->xres * m->yres * m->bpp / 8); if (inf->video_mem_size > fbi->video_mem_size) fbi->video_mem_size = inf->video_mem_size; if (video_mem_size > fbi->video_mem_size) fbi->video_mem_size = video_mem_size;}static struct pxafb_info * __devinit pxafb_init_fbinfo(struct device *dev){ struct pxafb_info *fbi; void *addr; struct pxafb_mach_info *inf = dev->platform_data; /* Alloc the pxafb_info and pseudo_palette in one step */ fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(u32) * 16, GFP_KERNEL); if (!fbi) return NULL; memset(fbi, 0, sizeof(struct pxafb_info)); fbi->dev = dev; fbi->clk = clk_get(dev, NULL); if (IS_ERR(fbi->clk)) { kfree(fbi); return NULL; } strcpy(fbi->fb.fix.id, PXA_NAME); fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS; fbi->fb.fix.type_aux = 0; fbi->fb.fix.xpanstep = 0; fbi->fb.fix.ypanstep = 1; fbi->fb.fix.ywrapstep = 0; fbi->fb.fix.accel = FB_ACCEL_NONE; fbi->fb.var.nonstd = 0; fbi->fb.var.activate = FB_ACTIVATE_NOW; fbi->fb.var.height = -1; fbi->fb.var.width = -1; fbi->fb.var.accel_flags = FB_ACCELF_TEXT; fbi->fb.var.vmode = FB_VMODE_NONINTERLACED; fbi->fb.fbops = &pxafb_ops; fbi->fb.flags = FBINFO_DEFAULT; fbi->fb.node = -1; addr = fbi; addr = addr + sizeof(struct pxafb_info); fbi->fb.pseudo_palette = addr; fbi->state = C_STARTUP; fbi->task_state = (u_char)-1; pxafb_decode_mach_info(fbi, inf); init_waitqueue_head(&fbi->ctrlr_wait); INIT_WORK(&fbi->task, pxafb_task); mutex_init(&fbi->ctrlr_lock); init_completion(&fbi->disable_done); return fbi;}#ifdef CONFIG_FB_PXA_PARAMETERSstatic int __devinit parse_opt_mode(struct device *dev, const char *this_opt){ struct pxafb_mach_info *inf = dev->platform_data; const char *name = this_opt+5; unsigned int namelen = strlen(name); int res_specified = 0, bpp_specified = 0; unsigned int xres = 0, yres = 0, bpp = 0; int yres_specified = 0; int i; for (i = namelen-1; i >= 0; i--) { switch (name[i]) { case '-': namelen = i; if (!bpp_specified && !yres_specified) { bpp = simple_strtoul(&name[i+1], NULL, 0); bpp_specified = 1; } else goto done; break; case 'x': if (!yres_specified) { yres = simple_strtoul(&name[i+1], NULL, 0); yres_specified = 1; } else goto done; break; case '0' ... '9': break; default: goto done; } } if (i < 0 && yres_specified) { xres = simple_strtoul(name, NULL, 0); res_specified = 1; }done: if (res_specified) { dev_info(dev, "overriding resolution: %dx%d\n", xres, yres); inf->modes[0].xres = xres; inf->modes[0].yres = yres; } if (bpp_specified) switch (bpp) { case 1: case 2: case 4: case 8: case 16: inf->modes[0].bpp = bpp; dev_info(dev, "overriding bit depth: %d\n", bpp); break; default: dev_err(dev, "Depth %d is not valid\n", bpp); return -EINVAL; } return 0;}static int __devinit parse_opt(struct device *dev, char *this_opt){ struct pxafb_mach_info *inf = dev->platform_data; struct pxafb_mode_info *mode = &inf->modes[0]; char s[64]; s[0] = '\0'; if (!strncmp(this_opt, "vmem:", 5)) { video_mem_size = memparse(this_opt + 5, NULL); } else if (!strncmp(this_opt, "mode:", 5)) { return parse_opt_mode(dev, this_opt); } else if (!strncmp(this_opt, "pixclock:", 9)) { mode->pixclock = simple_strtoul(this_opt+9, NULL, 0); sprintf(s, "pixclock: %ld\n", mode->pixclock); } else if (!strncmp(this_opt, "left:", 5)) { mode->left_margin = simple_strtoul(this_opt+5, NULL, 0); sprintf(s, "left: %u\n", mode->left_margin); } else if (!strncmp(this_opt, "right:", 6)) { mode->right_margin = simple_strtoul(this_opt+6, NULL, 0); sprintf(s, "right: %u\n", mode->right_margin); } else if (!strncmp(this_opt, "upper:", 6)) { mode->upper_margin = simple_strtoul(this_opt+6, NULL, 0); sprintf(s, "upper: %u\n", mode->upper_margin); } else if (!strncmp(this_opt, "lower:", 6)) { mode->lower_margin = simple_strtoul(this_opt+6, NULL, 0); sprintf(s, "lower: %u\n", mode->lower_margin); } else if (!strncmp(this_opt, "hsynclen:", 9)) { mode->hsync_len = simple_strtoul(this_opt+9, NULL, 0); sprintf(s, "hsynclen: %u\n", mode->hsync_len); } else if (!strncmp(this_opt, "vsynclen:", 9)) { mode->vsync_len = simple_strtoul(this_opt+9, NULL, 0); sprintf(s, "vsynclen: %u\n", mode->vsync_len); } else if (!strncmp(this_opt, "hsync:", 6)) { if (simple_strtoul(this_opt+6, NULL, 0) == 0) { sprintf(s, "hsync: Active Low\n"); mode->sync &= ~FB_SYNC_HOR_HIGH_ACT; } else { sprintf(s, "hsync: Active High\n"); mode->sync |= FB_SYNC_HOR_HIGH_ACT; } } else if (!strncmp(this_opt, "vsync:", 6)) { if (simple_strtoul(this_opt+6, NULL, 0) == 0) { sprintf(s, "vsync: Active Low\n"); mode->sync &= ~FB_SYNC_VERT_HIGH_ACT; } else { sprintf(s, "vsync: Active High\n"); mode->sync |= FB_SYNC_VERT_HIGH_ACT; } } else if (!strncmp(this_opt, "dpc:", 4)) { if (simple_strtoul(this_opt+4, NULL, 0) == 0) { sprintf(s, "double pixel clock: false\n"); inf->lccr3 &= ~LCCR3_DPC; } else { sprintf(s, "double pixel clock: true\n"); inf->lccr3 |= LCCR3_DPC; } } else if (!strncmp(this_opt, "outputen:", 9)) { if (simple_strtoul(this_opt+9, NULL, 0) == 0) { sprintf(s, "output enable: active low\n"); inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnL; } else { sprintf(s, "output enable: active high\n"); inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnH; } } else if (!strncmp(this_opt, "pixclockpol:", 12)) { if (simple_strtoul(this_opt+12, NULL, 0) == 0) { sprintf(s, "pixel clock polarity: falling edge\n"); inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixFlEdg; } else { sprintf(s, "pixel clock polarity: rising edge\n"); inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixRsEdg; } } else if (!strncmp(this_opt, "color", 5)) { inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Color; } else if (!strncmp(this_opt, "mono", 4)) { inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Mono; } else if (!strncmp(this_opt, "active", 6)) { inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Act; } else if (!strncmp(this_opt, "passive", 7)) { inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Pas; } else if (!strncmp(this_opt, "single", 6)) { inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Sngl; } else if (!strncmp(this_opt, "dual", 4)) { inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Dual; } else if (!strncmp(this_opt, "4pix", 4)) { inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_4PixMono; } else if (!strncmp(this_opt, "8pix", 4)) { inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_8PixMono; } else { dev_err(dev, "unknown option: %s\n", this_opt); return -EINVAL; } if (s[0] != '\0') dev_info(dev, "override %s", s); return 0;}static int __devinit pxafb_parse_options(struct device *dev, char *options){ char *this_opt; int ret; if (!options || !*options) return 0; dev_dbg(dev, "options are \"%s\"\n", options ? options : "null"); /* could be made table driven or similar?... */ while ((this_opt = strsep(&options, ",")) != NULL) { ret = parse_opt(dev, this_opt); if (ret) return ret; } return 0;}static char g_options[256] __devinitdata = "";#ifndef MODULEstatic int __init pxafb_setup_options(void){ char *options = NULL; if (fb_get_options("pxafb", &options)) return -ENODEV; if (options) strlcpy(g_options, options, sizeof(g_options)); return 0;}#else#define pxafb_setup_options() (0)module_param_string(options, g_options, sizeof(g_options), 0);MODULE_PARM_DESC(options, "LCD parameters (see Documentation/fb/pxafb.txt)");#endif#else#define pxafb_parse_options(...) (0)#define pxafb_setup_options() (0)#endif#ifdef DEBUG_VAR/* Check for various illegal bit-combinations. Currently only * a warning is given. */static void __devinit pxafb_check_options(struct device *dev, struct pxafb_mach_info *inf){ if (inf->lcd_conn) return; if (inf->lccr0 & LCCR0_INVALID_CONFIG_MASK) dev_warn(dev, "machine LCCR0 setting contains " "illegal bits: %08x\n", inf->lccr0 & LCCR0_INVALID_CONFIG_MASK); if (inf->lccr3 & LCCR3_INVALID_CONFIG_MASK) dev_warn(dev, "machine LCCR3 setting contains " "illegal bits: %08x\n", inf->lccr3 & LCCR3_INVALID_CONFIG_MASK); if (inf->lccr0 & LCCR0_DPD && ((inf->lccr0 & LCCR0_PAS) != LCCR0_Pas || (inf->lccr0 & LCCR0_SDS) != LCCR0_Sngl || (inf->lccr0 & LCCR0_CMS) != LCCR0_Mono)) dev_warn(dev, "Double Pixel Data (DPD) mode is " "only valid in passive mono" " single panel mode\n"); if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Act && (inf->lccr0 & LCCR0_SDS) == LCCR0_Dual) dev_warn(dev, "Dual panel only valid in passive mode\n"); if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Pas && (inf->modes->upper_margin || inf->modes->lower_margin)) dev_warn(dev, "Upper and lower margins must be 0 in " "passive mode\n");}#else#define pxafb_check_options(...) do {} while (0)#endifstatic int __devinit pxafb_probe(struct platform_device *dev){ struct pxafb_info *fbi; struct pxafb_mach_info *inf; struct resource *r; int irq, ret; dev_dbg(&dev->dev, "pxafb_probe\n"); inf = dev->dev.platform_data; ret = -ENOMEM; fbi = NULL; if (!inf) goto failed; ret = pxafb_parse_options(&dev->dev, g_options); if (ret < 0) goto failed; pxafb_check_options(&dev->dev, inf); dev_dbg(&dev->dev, "got a %dx%dx%d LCD\n", inf->modes->xres, inf->modes->yres, inf->modes->bpp); if (inf->modes->xres == 0 || inf->modes->yres == 0 || inf->modes->bpp == 0) { dev_err(&dev->dev, "Invalid resolution or bit depth\n"); ret = -EINVAL; goto failed; } fbi = pxafb_init_fbinfo(&dev->dev); if (!fbi) { /* only reason for pxafb_init_fbinfo to fail is kmalloc */ dev_err(&dev->dev, "Failed to initialize framebuffer device\n"); ret = -ENOMEM; goto failed; } fbi->backlight_power = inf->pxafb_backlight_power; fbi->lcd_power = inf->pxafb_lcd_power; r = platform_get_resource(dev, IORESOURCE_MEM, 0); if (r == NULL) { dev_err(&dev->dev, "no I/O memory resource defined\n"); ret = -ENODEV; goto failed_fbi; } r = request_mem_region(r->start, r->end - r->start + 1, dev->name); if (r == NULL) { dev_err(&dev->dev, "failed to request I/O memory\n"); ret = -EBUSY; goto failed_fbi; } fbi->mmio_base = ioremap(r->start, r->end - r->start + 1); if (fbi->mmio_base == NULL) { dev_err(&dev->dev, "failed to map I/O memory\n"); ret = -EBUSY; goto failed_free_res; } fbi->dma_buff_size = PAGE_ALIGN(sizeof(struct pxafb_dma_buff)); fbi->dma_buff = dma_alloc_coherent(fbi->dev, fbi->dma_buff_size, &fbi->dma_buff_phys, GFP_KERNEL); if (fbi->dma_buff == NULL) { dev_err(&dev->dev, "failed to allocate memory for DMA\n"); ret = -ENOMEM; goto failed_free_io; } ret = pxafb_init_video_memory(fbi); if (ret) { dev_err(&dev->dev, "Failed to allocate video RAM: %d\n", ret); ret = -ENOMEM; goto failed_free_dma; } irq = platform_get_irq(dev, 0); if (irq < 0) { dev_err(&dev->dev, "no IRQ defined\n"); ret = -ENODEV; goto failed_free_mem; } ret = request_irq(irq, pxafb_handle_irq, IRQF_DISABLED, "LCD", fbi); if (ret) { dev_err(&dev->dev, "request_irq failed: %d\n", ret); ret = -EBUSY; goto failed_free_mem; } ret = pxafb_smart_init(fbi); if (ret) { dev_err(&dev->dev, "failed to initialize smartpanel\n"); goto failed_free_irq; } /* * This makes sure that our colour bitfield * descriptors are correctly initialised. */ ret = pxafb_check_var(&fbi->fb.var, &fbi->fb); if (ret) { dev_err(&dev->dev, "failed to get suitable mode\n"); goto failed_free_irq; } ret = pxafb_set_par(&fbi->fb); if (ret) { dev_err(&dev->dev, "Failed to set parameters\n"); goto failed_free_irq; } platform_set_drvdata(dev, fbi); ret = register_framebuffer(&fbi->fb); if (ret < 0) { dev_err(&dev->dev, "Failed to register framebuffer device: %d\n", ret); goto failed_free_cmap; } pxafb_overlay_init(fbi);#ifdef CONFIG_CPU_FREQ fbi->freq_transition.notifier_call = pxafb_freq_transition; fbi->freq_policy.notifier_call = pxafb_freq_policy; cpufreq_register_notifier(&fbi->freq_transition, CPUFREQ_TRANSITION_NOTIFIER); cpufreq_register_notifier(&fbi->freq_policy, CPUFREQ_POLICY_NOTIFIER);#endif /* * Ok, now enable the LCD controller */ set_ctrlr_state(fbi, C_ENABLE); return 0;failed_free_cmap: if (fbi->fb.cmap.len) fb_dealloc_cmap(&fbi->fb.cmap);failed_free_irq: free_irq(irq, fbi);failed_free_mem: free_pages_exact(fbi->video_mem, fbi->video_mem_size);failed_free_dma: dma_free_coherent(&dev->dev, fbi->dma_buff_size, fbi->dma_buff, fbi->dma_buff_phys);failed_free_io: iounmap(fbi->mmio_base);failed_free_res: release_mem_region(r->start, r->end - r->start + 1);failed_fbi: clk_put(fbi->clk); platform_set_drvdata(dev, NULL); kfree(fbi);failed: return ret;}static int __devexit pxafb_remove(struct platform_device *dev){ struct pxafb_info *fbi = platform_get_drvdata(dev); struct resource *r; int irq; struct fb_info *info; if (!fbi) return 0; info = &fbi->fb; pxafb_overlay_exit(fbi); unregister_framebuffer(info); pxafb_disable_controller(fbi); if (fbi->fb.cmap.len) fb_dealloc_cmap(&fbi->fb.cmap); irq = platform_get_irq(dev, 0); free_irq(irq, fbi); free_pages_exact(fbi->video_mem, fbi->video_mem_size); dma_free_writecombine(&dev->dev, fbi->dma_buff_size, fbi->dma_buff, fbi->dma_buff_phys); iounmap(fbi->mmio_base); r = platform_get_resource(dev, IORESOURCE_MEM, 0); release_mem_region(r->start, r->end - r->start + 1); clk_put(fbi->clk); kfree(fbi); return 0;}static struct platform_driver pxafb_driver = { .probe = pxafb_probe, .remove = __devexit_p(pxafb_remove), .suspend = pxafb_suspend, .resume = pxafb_resume, .driver = { .owner = THIS_MODULE, .name = "pxa2xx-fb", },};static int __init pxafb_init(void){ if (pxafb_setup_options()) return -EINVAL; return platform_driver_register(&pxafb_driver);}static void __exit pxafb_exit(void){ platform_driver_unregister(&pxafb_driver);}module_init(pxafb_init);module_exit(pxafb_exit);MODULE_DESCRIPTION("loadable framebuffer driver for PXA");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -