📄 epson1356fb.c
字号:
e1356fb_install_cmap(display, &(info->fb_info)); } } return 0;}static inte1356fb_pan_display(struct fb_var_screeninfo* var, int con, struct fb_info* fb){ struct fb_info_e1356* info = (struct fb_info_e1356*)fb; struct e1356fb_par* par = &info->current_par; //DPRINTK("\n"); if (info->fix.nopan) return -EINVAL; if ((int)var->xoffset < 0 || var->xoffset + par->width > par->width_virt || (int)var->yoffset < 0 || var->yoffset + par->height > par->height_virt) return -EINVAL; if (con == currcon) do_pan_var(var, info); fb_display[con].var.xoffset = var->xoffset; fb_display[con].var.yoffset = var->yoffset; return 0;}static inte1356fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *fb){ struct fb_info_e1356* info = (struct fb_info_e1356*)fb; struct display *d = (con<0) ? fb->disp : fb_display + con; //DPRINTK("\n"); if (con == currcon) { /* current console? */ return fb_get_cmap(cmap, kspc, e1356fb_getcolreg, fb); } else if (d->cmap.len) { /* non default colormap? */ fb_copy_cmap(&d->cmap, cmap, kspc ? 0 : 2); } else { fb_copy_cmap(fb_default_cmap(info->current_par.cmap_len), cmap, kspc ? 0 : 2); } return 0;}static inte1356fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *fb){ struct display *d = (con<0) ? fb->disp : fb_display + con; struct fb_info_e1356 *info = (struct fb_info_e1356*)fb; int cmap_len = (info->current_par.bpp == 8) ? 256 : 16; //DPRINTK("\n"); if (d->cmap.len!=cmap_len) { int err; if ((err = fb_alloc_cmap(&d->cmap, cmap_len, 0))) return err; } if (con == currcon) { /* current console? */ return fb_set_cmap(cmap, kspc, e1356fb_setcolreg, fb); } else { fb_copy_cmap(cmap, &d->cmap, kspc ? 0 : 1); } return 0;}static inte1356fb_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg, int con, struct fb_info *fb){ struct fb_info_e1356 *info = (struct fb_info_e1356*)fb; blt_info_t blt; u16* src = NULL; int ret=0; switch (cmd) { case FBIO_SED1356_BITBLT: if (copy_from_user(&blt, (void *)arg, sizeof(blt_info_t))) return -EFAULT; if (blt.src) { if ((ret = verify_area(VERIFY_READ, (void*)blt.src, blt.srcsize))) return ret; if ((src = (u16*)kmalloc(blt.srcsize, GFP_KERNEL)) == NULL) return -ENOMEM; if (copy_from_user(src, (void *)blt.src, blt.srcsize)) return -EFAULT; blt.src = src; } ret = doBlt(&info->current_par, info, &blt); if (src) kfree(src); break; default: return -EINVAL; } return ret;}static inte1356fb_mmap(struct fb_info *fb, struct file *file, struct vm_area_struct *vma){ struct fb_info_e1356 *info = (struct fb_info_e1356*)fb; unsigned int len; phys_t start=0, off; if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) { DPRINTK("invalid vma->vm_pgoff\n"); return -EINVAL; } #ifdef SHADOW_FRAME_BUFFER if (!info->shadow.fb) { int order = 0; while (info->fb_size > (PAGE_SIZE * (1 << order))) order++; info->shadow.fb = (void*)__get_free_pages(GFP_KERNEL, order); if (!info->shadow.fb) { DPRINTK("shadow fb alloc failed\n"); return -ENXIO; } memset(info->shadow.fb, 0, info->fb_size); init_timer(&info->shadow.timer); info->shadow.timer.function = do_write_shadow_fb; info->shadow.timer.data = (unsigned long)info; } mod_timer(&info->shadow.timer, jiffies+HZ/2); start = virt_to_phys(info->shadow.fb) & PAGE_MASK;#else start = info->fix.membase_phys & PAGE_MASK;#endif len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fb_size); off = vma->vm_pgoff << PAGE_SHIFT; if ((vma->vm_end - vma->vm_start + off) > len) { DPRINTK("invalid vma\n"); return -EINVAL; } off += start; vma->vm_pgoff = off >> PAGE_SHIFT; pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK;#ifdef SHADOW_FRAME_BUFFER vma->vm_flags |= VM_RESERVED; pgprot_val(vma->vm_page_prot) &= ~_CACHE_UNCACHED;#else pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED;#endif /* This is an IO map - tell maydump to skip this VMA */ vma->vm_flags |= VM_IO; // FIXME: shouldn't have to do this. If the pages are marked writeable, // the TLB fault handlers should set these. pgprot_val(vma->vm_page_prot) |= (_PAGE_DIRTY | _PAGE_VALID); /* * The SED1356 has only a 16-bit wide data bus, and some * embedded platforms, such as the Pb1000, do not automatically * split 32-bit word accesses to the framebuffer into * seperate half-word accesses. Hence the upper half-word * never gets to the framebuffer. The following solution is * to intentionally return a non-32-bit-aligned VA. As long * as the user app assumes (and doesn't check) that the returned * VA is 32-bit aligned, all (assumed aligned) 32-bit accesses * will actually be unaligned and will get trapped by the MIPS * unaligned exception handler. This handler will emulate the * load/store instructions by splitting up the load/store * into two 16-bit load/stores. (This emulation is currently * enabled by default, but may be disabled in the future, when * alignment problems in user-level programs get fixed. When * that happens, this solution won't work anymore, unless the * process that mmap's the fb also calls sysmips(MIPS_FIXADE, 1), * which turns address-error emulation back on). * * Furthermore, this solution only seems to work for TinyX * (Xfbdev). Others, like Qt/E, do snoop the returned VA * and compensate, or do originally unaligned 32-bit accesses * which then become aligned, hence breaking this solution. */ if (info->fix.mmunalign) vma->vm_start += 2; if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; info->mmaped = 1; return 0;}int __inite1356fb_init(void){ struct fb_var_screeninfo var; struct e1356fb_fix * epfix = &fb_info.fix; e1356_reg_t* reg; void* regbase; char* name = "SED1356"; int periodMCLK, periodBCLK; int dram_timing, rr_div, mclk_src; u8 rev_code, btmp, mclk_cfg; if (options) { e1356fb_setup(options, 0); } // clear out fb_info memset(&fb_info, 0, sizeof(struct fb_info_e1356)); // copy boot options fb_info.fix = boot_fix; fb_info.default_par = boot_par; fb_info.regbase_size = E1356_REG_SIZE; if (!epfix->system) { printk(KERN_ERR "e1356/86fb: no valid system found\n"); return -ENODEV; } if (epfix->system == SYS_SDU1356) { // it's the SDU1356B0C PCI eval card. struct pci_dev *pdev = NULL; if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; if (!(pdev = pci_find_device(PCI_VENDOR_ID_EPSON, PCI_DEVICE_ID_EPSON_SDU1356, pdev))) return -ENODEV; if (pci_enable_device(pdev)) return -ENODEV; epfix->regbase_phys = pci_resource_start(pdev, 0); epfix->membase_phys = epfix->regbase_phys + E1356_REG_SIZE; } fb_info.regbase_virt = ioremap_nocache(epfix->regbase_phys, E1356_REG_SIZE); if (!fb_info.regbase_virt) { printk("e1356fb: Can't remap %s register area.\n", name); return -ENXIO; } regbase = fb_info.regbase_virt; reg = &fb_info.reg; // Initialize the register pointers reg->basic = (reg_basic_t*) (regbase + REG_BASE_BASIC); reg->genio = (reg_genio_t*) (regbase + REG_BASE_GENIO); reg->md_cfg = (reg_mdcfg_t*) (regbase + REG_BASE_MDCFG); reg->clk_cfg = (reg_clkcfg_t*) (regbase + REG_BASE_CLKCFG); reg->mem_cfg = (reg_memcfg_t*) (regbase + REG_BASE_MEMCFG); reg->panel_cfg = (reg_panelcfg_t*)(regbase + REG_BASE_PANELCFG); reg->lcd_cfg = (reg_dispcfg_t*) (regbase + REG_BASE_LCD_DISPCFG); reg->crttv_cfg = (reg_dispcfg_t*) (regbase + REG_BASE_CRTTV_DISPCFG); reg->lcd_mode = (reg_dispmode_t*)(regbase + REG_BASE_LCD_DISPMODE); reg->crttv_mode = (reg_dispmode_t*)(regbase + REG_BASE_CRTTV_DISPMODE); reg->lcd_inkcurs = (reg_inkcurs_t*) (regbase + REG_BASE_LCD_INKCURS); reg->crttv_inkcurs = (reg_inkcurs_t*) (regbase + REG_BASE_CRTTV_INKCURS); reg->bitblt = (reg_bitblt_t*) (regbase + REG_BASE_BITBLT); reg->lut = (reg_lut_t*) (regbase + REG_BASE_LUT); reg->pwr_save = (reg_pwrsave_t*) (regbase + REG_BASE_PWRSAVE); reg->misc = (reg_misc_t*) (regbase + REG_BASE_MISC); reg->mediaplug = (reg_mediaplug_t*)(regbase + REG_BASE_MEDIAPLUG); reg->bitblt_data = (u16*) (regbase + REG_BASE_BITBLT_DATA); // Enable all register access writeb(0, ®->basic->misc); rev_code = readb(®->basic->rev_code); if ((rev_code >> 2) == 0x04) { printk("Found EPSON1356 Display Controller\n"); } else if ((rev_code >> 2) == 0x07) { printk("Found EPSON13806 Display Controller\n"); } else { iounmap(fb_info.regbase_virt); printk("e1356/806fb: %s not found, rev_code=0x%02x.\n", name, rev_code); return -ENODEV; } fb_info.chip_rev = rev_code & 0x03; // Determine frame-buffer size switch (readb(®->md_cfg->md_cfg_stat0) >> 6) { case 0: case 2: fb_info.fb_size = 0x80000; /* 512K bytes */ break; case 1: if ((rev_code >> 2) == 7) /* 806 */ fb_info.fb_size = 0x140000; /* 1.2M bytes */ else fb_info.fb_size = 0x200000; /* 2M bytes */ break; default: fb_info.fb_size = 0x200000; /* 2M bytes */ break; } fb_info.membase_virt = ioremap_nocache(epfix->membase_phys, fb_info.fb_size); if (!fb_info.membase_virt) { printk("e1356fb: Can't remap %s framebuffer.\n", name); iounmap(fb_info.regbase_virt); return -ENXIO; } printk("e1356/806fb: Detected %dKB framebuffer\n", (unsigned)fb_info.fb_size/1000);#ifdef CONFIG_MTRR if (!epfix->nomtrr) { fb_info.mtrr_idx = mtrr_add(epfix->membase_phys, fb_info.fb_size, MTRR_TYPE_WRCOMB, 1); printk("e1356fb: MTRR's turned on\n"); }#endif if (!boot_fix.noaccel) { /* Allocate a page for string BLTs. A 4K page is enough for a 256 character string at an 8x16 font. */ fb_info.putcs_buffer = (void*)__get_free_pages(GFP_KERNEL, 0); if (fb_info.putcs_buffer == NULL) { printk("e1356fb: Can't allocate putcs buffer\n"); goto unmap_ret_enxio; } } // Begin SED1356 initialization // disable display while initializing writeb(0, ®->misc->disp_mode); // Set the GPIO1 and 2 to inputs writeb(0, ®->genio->gpio_cfg); writeb(0, ®->genio->gpio_ctrl); if (fb_info.chip_rev == 7) /* 806 */ writeb(0, ®->genio->gpio_ctrl2); /* * Program the clocks */#ifdef CONFIG_SOC_AU1X00 if ((epfix->system == SYS_PB1000) || (epfix->system == SYS_PB1500)) epfix->busclk = get_au1x00_lcd_clock();#endif if (epfix->busclk > 80000) { printk("e1356fb: specified busclk too high\n"); goto ret_enxio; } epfix->mclk = mclk_cfg = 0; if (epfix->system == SYS_PB1500) { epfix->mclk = epfix->busclk; mclk_cfg = 0x01; } else { // Find the highest allowable MCLK if (epfix->busclk <= MAX_PIXCLOCK && epfix->busclk > epfix->mclk) { epfix->mclk = epfix->busclk; mclk_cfg = 0x01; } if (epfix->clki <= MAX_PIXCLOCK && epfix->clki > epfix->mclk) { epfix->mclk = epfix->clki; mclk_cfg = 0x00; } if (epfix->busclk/2 <= MAX_PIXCLOCK && epfix->busclk/2 > epfix->mclk) { epfix->mclk = epfix->busclk/2; mclk_cfg = 0x11; } if (epfix->clki/2 <= MAX_PIXCLOCK && epfix->clki/2 > epfix->mclk) { epfix->mclk = epfix->clki/2; mclk_cfg = 0x10; } } if (!epfix->mclk) { printk("e1356fb: couldn't find an allowable MCLK!\n"); goto ret_enxio; } // When changing mclk src, you must first set bit 4 to 1. writeb(readb(®->clk_cfg->mem_clk_cfg) | 0x10, ®->clk_cfg->mem_clk_cfg); writeb(mclk_cfg, ®->clk_cfg->mem_clk_cfg); printk("e1356fb: clocks (kHz): busclk=%d mclk=%d clki=%d clki2=%d\n", epfix->busclk, epfix->mclk, epfix->clki, epfix->clki2); // Set max pixel clock switch (epfix->disp_type) { case DISP_TYPE_LCD: case DISP_TYPE_TFT: case DISP_TYPE_CRT: fb_info.max_pixclock = epfix->mclk; break; case DISP_TYPE_NTSC: case DISP_TYPE_PAL: fb_info.max_pixclock = (epfix->disp_type == DISP_TYPE_NTSC) ? NTSC_PIXCLOCK : PAL_PIXCLOCK; if (epfix->tv_filt & TV_FILT_FLICKER) fb_info.max_pixclock *= 2; break; default: printk("e1356fb: invalid specified display type\n"); goto ret_enxio; } periodMCLK = 1000000L / epfix->mclk; // in nano-seconds periodBCLK = 1000000L / epfix->busclk; // in nano-seconds if (readb(®->md_cfg->md_cfg_stat1) & (1<<4)) periodBCLK *= 2; if ((epfix->system == SYS_PB1000) || (epfix->system == SYS_PB1500)) writeb(0x00, ®->clk_cfg->cpu2mem_wait_sel); else if (periodMCLK - 4 > periodBCLK) writeb(0x02, ®->clk_cfg->cpu2mem_wait_sel); else if (2*periodMCLK - 4 > periodBCLK) writeb(0x01, ®->clk_cfg->cpu2mem_wait_sel); else writeb(0x00, ®->clk_cfg->cpu2mem_wait_sel); // Program memory config if (epfix->mem_type < MEM_TYPE_EDO_2CAS || epfix->mem_type > MEM_TYPE_EMBEDDED_SDRAM) { printk("e1356fb: bad memory type specified\n"); goto ret_enxio; } writeb((u8)epfix->mem_type, ®->mem_cfg->mem_cfg); // calc closest refresh rate rr_div = 7; mclk_src = (mclk_cfg & 1) ? epfix->busclk : epfix->clki; while ((mclk_src >> (6 + rr_div)) < epfix->mem_refresh) if (--rr_div < 0) { printk("e1356fb: can't set specified refresh rate\n"); goto ret_enxio; } DPRINTK("refresh rate = %d kHz\n", (mclk_src >> (6 + rr_div))); // add Suspend-Mode Refresh
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -