📄 jzlcd.c
字号:
lcd_palette_desc->databuf = (int)virt_to_phys((void *)lcd_palette); lcd_palette_desc->frame_id = (unsigned int)0xdeadbeaf; lcd_palette_desc->cmd = pal_size|LCD_CMD_PAL; /* Palette Descriptor */ /* Frame Descriptor 0 */ if (jzfb.bpp <= 8) lcd_frame_desc0->next_desc = (int)virt_to_phys(lcd_palette_desc); else lcd_frame_desc0->next_desc = (int)virt_to_phys(lcd_frame_desc0); lcd_frame_desc0->databuf = virt_to_phys((void *)lcd_frame[0]); lcd_frame_desc0->frame_id = (unsigned int)0xbeafbeaf; lcd_frame_desc0->cmd = LCD_CMD_SOFINT | LCD_CMD_EOFINT | frm_size; dma_cache_wback_inv((unsigned int)(lcd_palette_desc),0x10); dma_cache_wback_inv((unsigned int)(lcd_frame_desc0),0x10); if (!(dual_panel)) return; /* Frame Descriptor 1 */ lcd_frame_desc1->next_desc = (int)virt_to_phys(lcd_frame_desc1); lcd_frame_desc1->databuf = virt_to_phys((void *)(lcd_frame[0] + frm_size * 4)); lcd_frame_desc1->frame_id = (unsigned int)0xdeaddead; lcd_frame_desc1->cmd = LCD_CMD_SOFINT | LCD_CMD_EOFINT | frm_size; dma_cache_wback_inv((unsigned int)(lcd_frame_desc1),0x10);}static int lcd_hw_init(void){ unsigned int val = 0; unsigned int pclk; unsigned int stnH; int ret = 0; /* Setting Control register */ switch (jzfb.bpp) { case 1: val |= LCD_CTRL_BPP_1; break; case 2: val |= LCD_CTRL_BPP_2; break; case 4: val |= LCD_CTRL_BPP_4; break; case 8: val |= LCD_CTRL_BPP_8; break; case 15: val |= LCD_CTRL_RGB555; case 16: val |= LCD_CTRL_BPP_16; break;#if defined(CONFIG_SOC_JZ4740) case 17 ... 32: val |= LCD_CTRL_BPP_18_24; /* target is 4bytes/pixel */ break;#endif default: printk("The BPP %d is not supported\n", jzfb.bpp); val |= LCD_CTRL_BPP_16; break; } switch (jzfb.cfg & MODE_MASK) { case MODE_STN_MONO_DUAL: case MODE_STN_COLOR_DUAL: case MODE_STN_MONO_SINGLE: case MODE_STN_COLOR_SINGLE: switch (jzfb.bpp) { case 1: case 2: val |= LCD_CTRL_FRC_2; break; case 4: val |= LCD_CTRL_FRC_4; break; case 8: default: val |= LCD_CTRL_FRC_16; break; } break; } val |= LCD_CTRL_BST_16; /* Burst Length is 16WORD=64Byte */ switch (jzfb.cfg & MODE_MASK) { case MODE_STN_MONO_DUAL: case MODE_STN_COLOR_DUAL: case MODE_STN_MONO_SINGLE: case MODE_STN_COLOR_SINGLE: switch (jzfb.cfg & STN_DAT_PINMASK) {#define align2(n) (n)=((((n)+1)>>1)<<1)#define align4(n) (n)=((((n)+3)>>2)<<2)#define align8(n) (n)=((((n)+7)>>3)<<3) case STN_DAT_PIN1: /* Do not adjust the hori-param value. */ break; case STN_DAT_PIN2: align2(jzfb.hsw); align2(jzfb.elw); align2(jzfb.blw); break; case STN_DAT_PIN4: align4(jzfb.hsw); align4(jzfb.elw); align4(jzfb.blw); break; case STN_DAT_PIN8: align8(jzfb.hsw); align8(jzfb.elw); align8(jzfb.blw); break; } break; } val |= 1 << 26; /* Output FIFO underrun protection */ REG_LCD_CTRL = val; switch (jzfb.cfg & MODE_MASK) { case MODE_STN_MONO_DUAL: case MODE_STN_COLOR_DUAL: case MODE_STN_MONO_SINGLE: case MODE_STN_COLOR_SINGLE: if (((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL) || ((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL)) stnH = jzfb.h >> 1; else stnH = jzfb.h; REG_LCD_VSYNC = (0 << 16) | jzfb.vsw; REG_LCD_HSYNC = ((jzfb.blw+jzfb.w) << 16) | (jzfb.blw+jzfb.w+jzfb.hsw); /* Screen setting */ REG_LCD_VAT = ((jzfb.blw + jzfb.w + jzfb.hsw + jzfb.elw) << 16) | (stnH + jzfb.vsw + jzfb.bfw + jzfb.efw); REG_LCD_DAH = (jzfb.blw << 16) | (jzfb.blw + jzfb.w); REG_LCD_DAV = (0 << 16) | (stnH); /* AC BIAs signal */ REG_LCD_PS = (0 << 16) | (stnH+jzfb.vsw+jzfb.efw+jzfb.bfw); break; case MODE_TFT_GEN: case MODE_TFT_SHARP: case MODE_TFT_CASIO: case MODE_TFT_SAMSUNG: case MODE_8BIT_SERIAL_TFT: case MODE_TFT_18BIT: REG_LCD_VSYNC = (0 << 16) | jzfb.vsw;#if defined(CONFIG_JZLCD_INNOLUX_AT080TN42) REG_LCD_DAV = (0 << 16) | ( jzfb.h );#else REG_LCD_DAV = ((jzfb.vsw + jzfb.bfw) << 16) | (jzfb.vsw + jzfb.bfw + jzfb.h);#endif /*#if defined(CONFIG_JZLCD_INNOLUX_AT080TN42)*/ REG_LCD_VAT = (((jzfb.blw + jzfb.w + jzfb.elw + jzfb.hsw)) << 16) | (jzfb.vsw + jzfb.bfw + jzfb.h + jzfb.efw); REG_LCD_HSYNC = (0 << 16) | jzfb.hsw; REG_LCD_DAH = ((jzfb.hsw + jzfb.blw) << 16) | (jzfb.hsw + jzfb.blw + jzfb.w); break; } switch (jzfb.cfg & MODE_MASK) { case MODE_TFT_SAMSUNG: { unsigned int total, tp_s, tp_e, ckv_s, ckv_e; unsigned int rev_s, rev_e, inv_s, inv_e; total = jzfb.blw + jzfb.w + jzfb.elw + jzfb.hsw; tp_s = jzfb.blw + jzfb.w + 1; tp_e = tp_s + 1; ckv_s = tp_s - jz_clocks.pixclk/(1000000000/4100); ckv_e = tp_s + total; rev_s = tp_s - 11; /* -11.5 clk */ rev_e = rev_s + total; inv_s = tp_s; inv_e = inv_s + total; REG_LCD_CLS = (tp_s << 16) | tp_e; REG_LCD_PS = (ckv_s << 16) | ckv_e; REG_LCD_SPL = (rev_s << 16) | rev_e; REG_LCD_REV = (inv_s << 16) | inv_e; jzfb.cfg |= STFT_REVHI | STFT_SPLHI; break; } case MODE_TFT_SHARP: { unsigned int total, cls_s, cls_e, ps_s, ps_e; unsigned int spl_s, spl_e, rev_s, rev_e; total = jzfb.blw + jzfb.w + jzfb.elw + jzfb.hsw;#if !defined(CONFIG_JZLCD_INNOLUX_AT080TN42) spl_s = 1; spl_e = spl_s + 1; cls_s = 0; cls_e = total - 60; /* > 4us (pclk = 80ns) */ ps_s = cls_s; ps_e = cls_e; rev_s = total - 40; /* > 3us (pclk = 80ns) */ rev_e = rev_s + total; jzfb.cfg |= STFT_PSHI;#else /*#if defined(CONFIG_JZLCD_INNOLUX_AT080TN42)*/ spl_s = total - 5; /* LD */ spl_e = total - 3; cls_s = 32; /* CKV */ cls_e = 145; ps_s = 0; /* OEV */ ps_e = 45; rev_s = 0; /* POL */ rev_e = 0;#endif /*#if defined(CONFIG_JZLCD_INNOLUX_AT080TN42)*/ REG_LCD_SPL = (spl_s << 16) | spl_e; REG_LCD_CLS = (cls_s << 16) | cls_e; REG_LCD_PS = (ps_s << 16) | ps_e; REG_LCD_REV = (rev_s << 16) | rev_e; break; } case MODE_TFT_CASIO: break; } /* Configure the LCD panel */ REG_LCD_CFG = jzfb.cfg; /* Timing setting */ __cpm_stop_lcd(); val = jzfb.fclk; /* frame clk */ if ( (jzfb.cfg & MODE_MASK) != MODE_8BIT_SERIAL_TFT) { pclk = val * (jzfb.w + jzfb.hsw + jzfb.elw + jzfb.blw) * (jzfb.h + jzfb.vsw + jzfb.efw + jzfb.bfw); /* Pixclk */ } else { /* serial mode: Hsync period = 3*Width_Pixel */ pclk = val * (jzfb.w*3 + jzfb.hsw + jzfb.elw + jzfb.blw) * (jzfb.h + jzfb.vsw + jzfb.efw + jzfb.bfw); /* Pixclk */ } if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_SINGLE) || ((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL)) pclk = (pclk * 3); if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_SINGLE) || ((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) || ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_SINGLE) || ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL)) pclk = pclk >> ((jzfb.cfg & STN_DAT_PINMASK) >> 4); if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) || ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL)) pclk >>= 1;#if defined(CONFIG_SOC_JZ4730) val = __cpm_get_pllout() / pclk; REG_CPM_CFCR2 = val - 1; val = __cpm_get_pllout() / (pclk * 4); val = __cpm_divisor_encode(val); __cpm_set_lcdclk_div(val); REG_CPM_CFCR |= CPM_CFCR_UPE;#elif defined(CONFIG_SOC_JZ4740) val = ( __cpm_get_pllout2()) / pclk; val--; if ( val > 0x3ff ) { printk("pixel clock divid is too large, set it to 0x3ff\n"); val = 0x3ff; } __cpm_set_pixdiv(val); val = pclk * 3 ; /* LCDClock > 2.5*Pixclock */ val =__cpm_get_pllout() / val; if ( val > 0x1f ) { printk("lcd clock divide is too large, set it to 0x1f\n"); val = 0x1f; } __cpm_set_ldiv( val ); REG_CPM_CPCCR |= CPM_CPCCR_CE ; /* update divide */#else printk("drivers/video/Jzlcd.c, CONFIG_MIPS, please set chip type.\n");#endif /*#ifdef CONFIG_MIPS_JZ4730 */ jz_clocks.pixclk = __cpm_get_pixclk(); jz_clocks.lcdclk = __cpm_get_lcdclk(); printk("LCDC: PixClock:%d LcdClock:%d\n", jz_clocks.pixclk, jz_clocks.lcdclk); __cpm_start_lcd(); udelay(1000); return ret;}static irqreturn_t lcd_interrupt_handler(int irq, void *dev_id){ unsigned int state; state = REG_LCD_STATE; if (state & LCD_STATE_EOF) /* End of frame */ REG_LCD_STATE = state & ~LCD_STATE_EOF; if (state & LCD_STATE_IFU0) { dprintk("InFiFo0 underrun\n"); REG_LCD_STATE = state & ~LCD_STATE_IFU0; } if (state & LCD_STATE_OFU) { /* Out fifo underrun */ REG_LCD_STATE = state & ~LCD_STATE_OFU; dprintk("Out FiFo underrun.\n"); } return IRQ_HANDLED;}#ifdef CONFIG_PM/* * Suspend the LCDC. */static int jzfb_suspend(void){ __lcd_clr_ena(); /* Quick Disable */ __lcd_display_off(); __cpm_stop_lcd(); return 0;}/* * Resume the LCDC. */#ifdef CONFIG_SOC_JZ4730static int jzfb_resume(void){ __cpm_start_lcd(); __lcd_display_pin_init(); __lcd_display_on(); lcd_hw_init(); if (jzfb.bpp <= 8) REG_LCD_DA0 = virt_to_phys(lcd_palette_desc); else REG_LCD_DA0 = virt_to_phys(lcd_frame_desc0); if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) || ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL)) REG_LCD_DA1 = virt_to_phys(lcd_frame_desc1); __lcd_set_ena(); return 0;}#else/* * Resume the LCDC. */static int jzfb_resume(void){ __cpm_start_lcd(); __gpio_set_pin(GPIO_DISP_OFF_N); __lcd_special_on(); __lcd_set_ena(); mdelay(200); __lcd_set_backlight_level(80); return 0;}#endif /* CONFIG_MIPS_JZ4730 *//* * Power management hook. Note that we won't be called from IRQ context, * unlike the blank functions above, so we may sleep. */static int jzlcd_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data){ int ret; struct lcd_cfb_info *cfb = pm_dev->data; if (!cfb) return -EINVAL; switch (req) { case PM_SUSPEND: ret = jzfb_suspend(); break; case PM_RESUME: ret = jzfb_resume(); break; default: ret = -EINVAL; break; } return ret;}#else#define jzfb_suspend NULL#define jzfb_resume NULL#endif /* CONFIG_PM */static int __init jzfb_init(void){ struct lcd_cfb_info *cfb; int err = 0; /* In special mode, we only need init special pin, * as general lcd pin has init in uboot */#if defined(CONFIG_SOC_JZ4740) || defined(CONFIG_SOC_JZ4750) switch (jzfb.cfg & MODE_MASK) { case LCD_CFG_MODE_SPECIAL_TFT_1: case LCD_CFG_MODE_SPECIAL_TFT_2: case LCD_CFG_MODE_SPECIAL_TFT_3: __gpio_as_lcd_special(); break; default: ; }#endif __lcd_display_pin_init(); cfb = jzfb_alloc_fb_info(); if (!cfb) goto failed; err = jzfb_map_smem(cfb); if (err) goto failed; jzfb_set_var(&cfb->fb.var, -1, &cfb->fb); lcd_descriptor_init(); err = lcd_hw_init(); if (err) goto failed; if (jzfb.bpp <= 8) REG_LCD_DA0 = virt_to_phys(lcd_palette_desc); else REG_LCD_DA0 = virt_to_phys(lcd_frame_desc0); if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) || ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL)) REG_LCD_DA1 = virt_to_phys(lcd_frame_desc1); __lcd_set_ena(); if (request_irq(IRQ_LCD, lcd_interrupt_handler, IRQF_DISABLED, "lcd", 0)) { err = -EBUSY; goto failed; } __lcd_enable_ofu_intr(); /* enable OutFifo underrun */// __lcd_enable_ifu0_intr(); /* needn't enable InFifo underrun */#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) jzfb_rotate_change(rotate_angle); /* sleep n??? */#endif err = register_framebuffer(&cfb->fb); if (err < 0) { dprintk("jzfb_init(): register framebuffer err.\n"); goto failed; } printk("fb%d: %s frame buffer device, using %dK of video memory\n", cfb->fb.node, cfb->fb.fix.id, cfb->fb.fix.smem_len>>10);#ifdef CONFIG_PM /* * Note that the console registers this as well, but we want to * power down the display prior to sleeping. */ cfb->pm = pm_register(PM_SYS_DEV, PM_SYS_VGA, jzlcd_pm_callback); if (cfb->pm) cfb->pm->data = cfb;#endif __lcd_display_on(); return 0;failed: jzfb_unmap_smem(cfb); jzfb_free_fb_info(cfb); return err;}#if 0static int jzfb_remove(struct device *dev){ struct lcd_cfb_info *cfb = dev_get_drvdata(dev); jzfb_unmap_smem(cfb); jzfb_free_fb_info(cfb); return 0;}#endif#if 0static struct device_driver jzfb_driver = { .name = "jz-lcd", .bus = &platform_bus_type, .probe = jzfb_probe, .remove = jzfb_remove, .suspend = jzfb_suspend, .resume = jzfb_resume,};#endifstatic void __exit jzfb_cleanup(void){#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) kthread_stop(jzlcd_info->rotate_daemon_thread);#endif// driver_unregister(&jzfb_driver);// jzfb_remove();}module_init(jzfb_init);module_exit(jzfb_cleanup);MODULE_DESCRIPTION("JzSOC LCD Controller driver");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -