static int32_t sprdfb_dispc_init(struct sprdfb_device *dev) { pr_debug(KERN_INFO "sprdfb:[%s]\n",__FUNCTION__); /*set bg color*/ dispc_set_bg_color(0xFFFFFFFF); /*enable dithering*/ dispc_dithering_enable(true); /*use MSBs as img exp mode*/ dispc_set_exp_mode(0x0); if(dispc_ctx.is_first_frame){ dispc_layer_init(&(dev->fb->var)); }else{ dispc_layer_update(&(dev->fb->var)); } if(SPRDFB_PANEL_IF_DPI == dev->panel_if_type){ if(dispc_ctx.is_first_frame){ /*set dpi register update only with SW*/ dispc_set_bits(BIT(4), DISPC_DPI_CTRL); }else{ /*set dpi register update with SW & VSYNC*/ dispc_clear_bits(BIT(4), DISPC_DPI_CTRL); } /*enable dispc update done INT*/ dispc_write((1<<4), DISPC_INT_EN); }else{ /* enable dispc DONE INT*/ dispc_write((1<<0), DISPC_INT_EN); } dispc_set_bits(BIT(2), DISPC_INT_EN); dev->enable = 1; return 0; }
static int32_t sprdfb_dispc_refresh (struct sprdfb_device *dev) { FB_PRINT("sprdfb:[%s]\n",__FUNCTION__); uint32_t i; if(SPRDFB_PANEL_IF_DPI != dev->panel_if_type){ sprdfb_panel_invalidate(dev->panel); } sprdfb_panel_before_refresh(dev); if(SPRDFB_PANEL_IF_DPI == dev->panel_if_type){ //dispc_write(0x0, DISPC_OSD_CTRL); //dispc_write(0x0, DISPC_BG_COLOR); /*dpi register update*/ dispc_set_bits((1<<5), DISPC_DPI_CTRL); if(is_first_frame){ udelay(30); /*dpi register update with SW and VSync*/ dispc_clear_bits((1<<4), DISPC_DPI_CTRL); /* start refresh */ dispc_set_bits((1 << 4), DISPC_CTRL); is_first_frame = 0; }else{ for(i=0;i<1000;i++){ if(!(dispc_read(DISPC_INT_RAW) & (0x10))){ udelay(100); }else{ break; } } if(i >= 1000){ FB_PRINT("sprdfb:[%s] wait dispc update int time out!! (0x%x)\n", __FUNCTION__, dispc_read(DISPC_INT_RAW)); }else{ FB_PRINT("sprdfb:[%s] got dispc update int (0x%x)\n", __FUNCTION__, dispc_read(DISPC_INT_RAW)); } dispc_set_bits((1<<5), DISPC_INT_CLR); } }else{ /* start refresh */ dispc_set_bits((1 << 4), DISPC_CTRL); for(i=0;i<500;i++){ if(0x1 != (dispc_read(DISPC_INT_RAW) & (1<<0))){ udelay(1000); }else{ break; } } if(i >= 1000){ FB_PRINT("sprdfb:[%s] wait dispc done int time out!! (0x%x)\n", __FUNCTION__, dispc_read(DISPC_INT_RAW)); }else{ FB_PRINT("sprdfb:[%s] got dispc done int (0x%x)\n", __FUNCTION__, dispc_read(DISPC_INT_RAW)); } dispc_set_bits((1<<0), DISPC_INT_CLR); } sprdfb_panel_after_refresh(dev); return 0; }
static int32_t sprdfb_dispc_init(struct sprdfb_device *dev) { FB_PRINT("sprdfb:[%s]\n",__FUNCTION__); /*set bg color*/ dispc_set_bg_color(0xFFFFFFFF); /*enable dithering*/ dispc_dithering_enable(1); /*use MSBs as img exp mode*/ dispc_set_exp_mode(0x0); dispc_layer_init(dev); if(SPRDFB_PANEL_IF_DPI == dev->panel_if_type){ if(is_first_frame){ /*set dpi register update only with SW*/ dispc_set_bits((1<<4), DISPC_DPI_CTRL); }else{ /*set dpi register update with SW & VSYNC*/ dispc_clear_bits((1<<4), DISPC_DPI_CTRL); } /*enable dispc update done INT*/ // dispc_write((1<<4), DISPC_INT_EN); }else{ /* enable dispc DONE INT*/ // dispc_write((1<<0), DISPC_INT_EN); } return 0; }
static void dispc_pwr_enable(bool enable) { if(enable){ dispc_set_bits(BIT(7), DISPC_CTRL); }else{ dispc_clear_bits(BIT(7), DISPC_CTRL); } }
static void dispc_dithering_enable(bool enable) { if(enable){ dispc_set_bits(BIT(6), DISPC_CTRL); }else{ dispc_clear_bits(BIT(6), DISPC_CTRL); } }
static int32_t sprdfb_lcdc_early_init(struct sprdfb_device *dev) { int ret = 0; pr_debug(KERN_INFO "sprdfb:[%s]\n", __FUNCTION__); if(lcdc_ctx.is_inited){ printk(KERN_WARNING "sprdfb: lcdc early init warning!(has been inited)"); return 0; } lcdc_ctx.clk_lcdc = clk_get(NULL, "clk_lcd"); if (IS_ERR(lcdc_ctx.clk_lcdc)) { printk(KERN_WARNING "sprdfb: get clk_lcd fail!\n"); return 0; } else { pr_debug(KERN_INFO "sprdfb: get clk_lcd ok!\n"); } /*usesd to open dipsc matix clock*/ sci_glb_set(REG_AHB_MATRIX_CLOCK, (1<<LCDC_CORE_CLK_EN)); if(!dev->panel_ready){ ret = clk_enable(lcdc_ctx.clk_lcdc); if (ret) { printk(KERN_WARNING "sprdfb: enable clk_lcdc fail!\n"); return 0; } else { pr_debug(KERN_INFO "sprdfb: get clk_lcdc ok!\n"); } /*dispc must be enbale before lcdc enable*/ sprdfb_dispc_ctrl.early_init(dev); dispc_set_bits(BIT(3), DISPC_CTRL); lcdc_reset(); lcdc_module_enable(); lcdc_ctx.is_first_frame = true; }else{ lcdc_ctx.is_first_frame = false; } lcdc_ctx.vsync_done = 1; lcdc_ctx.vsync_waiter = 0; init_waitqueue_head(&(lcdc_ctx.vsync_queue)); lcdc_ctx.is_inited = true; ret = request_irq(IRQ_LCDC_INT, lcdc_isr, IRQF_DISABLED, "LCDC", &lcdc_ctx); if (ret) { printk(KERN_ERR "sprdfb: lcdc failed to request irq!\n"); clk_disable(lcdc_ctx.clk_lcdc); lcdc_ctx.is_inited = false; return -1; } return 0; }
static void dispc_run(void) { if(DISPC_IF_DPI == autotst_dispc_ctx.dispc_if){ /*dpi register update*/ dispc_set_bits(BIT(5), DISPC_DPI_CTRL); udelay(30); /*dpi register update with SW and VSync*/ dispc_clear_bits(BIT(4), DISPC_DPI_CTRL); /* start refresh */ dispc_set_bits((1 << 4), DISPC_CTRL); }else{ /* start refresh */ dispc_set_bits((1 << 4), DISPC_CTRL); } }
static void dispc_stop(void) { if(DISPC_IF_DPI == autotst_dispc_ctx.dispc_if){ /*dpi register update with SW only*/ dispc_set_bits(BIT(4), DISPC_DPI_CTRL); /* stop refresh */ dispc_clear_bits((1 << 4), DISPC_CTRL); } }
static void dispc_dithering_enable(uint16_t enable) { FB_PRINT("sprdfb:[%s]\n",__FUNCTION__); if(enable){ dispc_set_bits((1<<6), DISPC_CTRL); }else{ dispc_clear_bits((1<<6), DISPC_CTRL); } }
static void dispc_run(struct sprdfb_device *dev) { if(0 == dev->enable){ return; } #ifdef CONFIG_FB_ESD_SUPPORT down(&dev->ESD_lock); #endif if(SPRDFB_PANEL_IF_DPI == dev->panel_if_type){ if(!dispc_ctx.is_first_frame){ dispc_ctx.vsync_done = 0; dispc_ctx.vsync_waiter ++; } /*dpi register update*/ dispc_set_bits(BIT(5), DISPC_DPI_CTRL); udelay(30); if(dispc_ctx.is_first_frame){ /*dpi register update with SW and VSync*/ dispc_clear_bits(BIT(4), DISPC_DPI_CTRL); /* start refresh */ dispc_set_bits((1 << 4), DISPC_CTRL); dispc_ctx.is_first_frame = false; }else{ dispc_sync(dev); } }else{ dispc_ctx.vsync_done = 0; /* start refresh */ dispc_set_bits((1 << 4), DISPC_CTRL); } #ifdef CONFIG_FB_ESD_SUPPORT up(&dev->ESD_lock); #endif }
static void dispc_stop(struct sprdfb_device *dev) { if(SPRDFB_PANEL_IF_DPI == dev->panel_if_type){ /*dpi register update with SW only*/ dispc_set_bits(BIT(4), DISPC_DPI_CTRL); /* stop refresh */ dispc_clear_bits((1 << 4), DISPC_CTRL); dispc_ctx.is_first_frame = true; } }
static void mipi_dispc_init_config(struct panel_spec *panel) { uint32_t reg_val = dispc_read(DISPC_DPI_CTRL); pr_debug("autotst_dispc: [%s]\n", __FUNCTION__); if(NULL == panel){ printk(KERN_ERR "autotst_dispc: [%s] fail.(Invalid Param)\n", __FUNCTION__); return; } if(SPRDFB_PANEL_TYPE_MIPI != panel->type){ printk(KERN_ERR "autotst_dispc: [%s] fail.(not mcu panel)\n", __FUNCTION__); return; } if(SPRDFB_MIPI_MODE_CMD == panel->info.mipi->work_mode){ /*use edpi as interface*/ dispc_set_bits((1<<1), DISPC_CTRL); autotst_dispc_ctx.dispc_if = DISPC_IF_EDPI; }else{ /*use dpi as interface*/ dispc_clear_bits((3<<1), DISPC_CTRL); autotst_dispc_ctx.dispc_if = DISPC_IF_DPI; } /*h sync pol*/ if(SPRDFB_POLARITY_NEG == panel->info.mipi->h_sync_pol){ reg_val |= (1<<0); } /*v sync pol*/ if(SPRDFB_POLARITY_NEG == panel->info.mipi->v_sync_pol){ reg_val |= (1<<1); } /*de sync pol*/ if(SPRDFB_POLARITY_NEG == panel->info.mipi->de_pol){ reg_val |= (1<<2); } if(SPRDFB_MIPI_MODE_VIDEO == panel->info.mipi->work_mode){ #ifdef CONFIG_DPI_SINGLE_RUN /*single run mode*/ reg_val |= (1<<3); #endif }else{ if(!(panel->cap & PANEL_CAP_NOT_TEAR_SYNC)){ printk("autotst_dispc: mipi_dispc_init_config not support TE\n"); /*enable te*/ reg_val |= (1<<8); } /*te pol*/ if(SPRDFB_POLARITY_NEG == panel->info.mipi->te_pol){ reg_val |= (1<<9); } /*use external te*/ reg_val |= (1<<10); } /*dpi bits*/ switch(panel->info.rgb->video_bus_width){ case 16: break; case 18: reg_val |= (1 << 6); break; case 24: reg_val |= (2 << 6); break; default: break; } dispc_write(reg_val, DISPC_DPI_CTRL); pr_debug("autotst_dispc: [%s] DISPC_DPI_CTRL = %d\n", __FUNCTION__, dispc_read(DISPC_DPI_CTRL)); }
/*cs0*/ static void mcu_dispc_init_config(struct panel_spec *panel) { uint32_t reg_val = 0; pr_debug("autotst_dispc: [%s] for cs0\n", __FUNCTION__); if(NULL == panel){ printk(KERN_ERR "autotst_dispc: [%s] fail.(Invalid Param)\n", __FUNCTION__); return; } if(SPRDFB_PANEL_TYPE_MCU != panel->type){ printk(KERN_ERR "autotst_dispc: [%s] fail.(not mcu panel)\n", __FUNCTION__); return; } /*use dbi as interface*/ dispc_set_bits((2<<1), DISPC_CTRL); autotst_dispc_ctx.dispc_if = DISPC_IF_DBI; /* CS0 bus mode [BIT0]: 8080/6800 */ switch (panel->info.mcu->bus_mode) { case LCD_BUS_8080: break; case LCD_BUS_6800: reg_val |= 1; break; default: break; } /* CS0 bus width [BIT3:1] */ switch (panel->info.mcu->bus_width) { case 8: break; case 9: reg_val |= (1 << 1); break; case 16: reg_val |= (2 << 1); break; case 18: reg_val |= (3 << 1) ; break; case 24: reg_val |= (4 << 1); break; default: break; } /*CS0 pixel bits [BIT5:4]*/ switch (panel->info.mcu->bpp) { case 16: break; case 18: reg_val |= (1 << 4) ; break; case 24: reg_val |= (2 << 4); break; default: break; } #ifndef CONFIG_FB_NO_FMARK /*TE enable*/ reg_val |= (1 << 16); if(SPRDFB_POLARITY_NEG == panel->info.mcu->te_pol){ reg_val |= (1<< 17); } dispc_write(panel->info.mcu->te_sync_delay, DISPC_TE_SYNC_DELAY); #endif #ifdef CONFIG_LCD_CS_ALWAYS_LOW /*CS alway low mode*/ reg_val |= (1<<21); #else /*CS not alway low mode*/ #endif /*CS0 selected*/ dispc_write(reg_val, DISPC_DBI_CTRL); pr_debug("autotst_dispc: [%s] DISPC_DBI_CTRL = %d\n", __FUNCTION__, dispc_read(DISPC_DBI_CTRL)); }
int32_t autotst_dispc_init(int display_type) { int ret = 0; printk(KERN_INFO "autotst_dispc:[%s]\n",__FUNCTION__); //autotst_dsi_dump(); autotst_dispc_uninit(DISPLAY_TYPE_MIPI); ret = dispc_clk_init(); if(ret){ printk(KERN_WARNING "autotst_dispc: dispc_clk_init fail!\n"); return -1; } dispc_reset(); dispc_module_enable(); /*set bg color*/ dispc_set_bg_color(0xFFFFFFFF); /*enable dithering*/ dispc_dithering_enable(true); /*use MSBs as img exp mode*/ dispc_set_exp_mode(0x0); //enable DISPC Power Control dispc_pwr_enable(true); switch(display_type){ case DISPLAY_TYPE_MCU: autotst_panel = &lcd_dummy_mcu_spec; mcu_dispc_init_config(autotst_panel); mcu_dispc_set_timing(autotst_panel); break; case DISPLAY_TYPE_RGB: autotst_panel = &lcd_dummy_rgb_spec; rgb_dispc_init_config(autotst_panel); rgb_dispc_set_timing(autotst_panel); autotst_dispc_ctx.dispc_if = DISPC_IF_DPI; break; case DISPLAY_TYPE_MIPI: autotst_panel = &lcd_dummy_mipi_spec; mipi_dispc_init_config(autotst_panel); mipi_dispc_set_timing(autotst_panel); autotst_dsi_init(autotst_panel); break; default: printk("autotst_dispc:[%s] error display type (%d)\n", __FUNCTION__, display_type); } dispc_layer_init(autotst_panel); if(DISPC_IF_DPI == autotst_dispc_ctx.dispc_if){ if(1){ /*set dpi register update only with SW*/ dispc_set_bits(BIT(4), DISPC_DPI_CTRL); }else{ /*set dpi register update with SW & VSYNC*/ dispc_clear_bits(BIT(4), DISPC_DPI_CTRL); } /*enable dispc update done INT*/ //dispc_write((1<<4), DISPC_INT_EN); }else{ /* enable dispc DONE INT*/ //dispc_write((1<<0), DISPC_INT_EN); } //dispc_set_bits(BIT(2), DISPC_INT_EN); return 0; }
/*cs1*/ void mcu_dispc_init_config(struct panel_spec *panel) { uint32_t reg_val = 0; FB_PRINT("sprdfb: [%s] for cs1\n", __FUNCTION__); if(NULL == panel){ printf("sprdfb: [%s] fail.(Invalid Param)\n", __FUNCTION__); return; } if(SPRDFB_PANEL_TYPE_MCU != panel->type){ printf("sprdfb: [%s] fail.(not mcu panel)\n", __FUNCTION__); return; } /*use dbi as interface*/ dispc_set_bits((2<<1), DISPC_CTRL); /* CS1 bus mode [BIT8]: 8080/6800 */ switch (panel->info.mcu->bus_mode) { case LCD_BUS_8080: break; case LCD_BUS_6800: reg_val |= (1<<8); break; default: break; } /* CS1 bus width [BIT11:9] */ switch (panel->info.mcu->bus_width) { case 8: break; case 9: reg_val |= (1 << 9); break; case 16: reg_val |= (2 << 9); break; case 18: reg_val |= (3 << 9) ; break; case 24: reg_val |= (4 << 9); break; default: break; } /*CS1 pixel bits [BIT13:12]*/ switch (panel->info.mcu->bpp) { case 16: break; case 18: reg_val |= (1 << 12) ; break; case 24: reg_val |= (2 << 12); break; default: break; } #ifndef CONFIG_FB_NO_FMARK /*TE enable*/ reg_val |= (1 << 16); if(SPRDFB_POLARITY_NEG == panel->info.mcu->te_pol){ reg_val |= (1<< 17); } dispc_write(panel->info.mcu->te_sync_delay, DISPC_TE_SYNC_DELAY); #endif #ifdef CONFIG_LCD_CS_ALWAYS_LOW /*CS alway low mode*/ reg_val |= (1<<21); #else /*CS not alway low mode*/ #endif /*CS1 selected*/ reg_val |= (1 << 20); dispc_write(reg_val, DISPC_DBI_CTRL); FB_PRINT("sprdfb: [%s] DISPC_DBI_CTRL = %d\n", __FUNCTION__, dispc_read(DISPC_DBI_CTRL)); }
static irqreturn_t dispc_isr(int irq, void *data) { struct sprdfb_dispc_context *dispc_ctx = (struct sprdfb_dispc_context *)data; uint32_t reg_val; struct sprdfb_device *dev = dispc_ctx->dev; bool done = false; reg_val = dispc_read(DISPC_INT_STATUS); pr_debug("dispc_isr (0x%x)\n",reg_val ); if(reg_val & 0x04){ printk("Warning: dispc underflow (0x%x)!\n",reg_val); dispc_write(0x04, DISPC_INT_CLR); } if(NULL == dev){ return IRQ_HANDLED; } if((reg_val & 0x10) && (SPRDFB_PANEL_IF_DPI == dev->panel_if_type)){/*dispc update done isr*/ #if 0 if(dispc_ctx->is_first_frame){ /*dpi register update with SW and VSync*/ dispc_clear_bits(BIT(4), DISPC_DPI_CTRL); /* start refresh */ dispc_set_bits((1 << 4), DISPC_CTRL); dispc_ctx->is_first_frame = false; } #endif dispc_write(0x10, DISPC_INT_CLR); done = true; }else if ((reg_val & 0x1) && (SPRDFB_PANEL_IF_DPI != dev->panel_if_type)){ /* dispc done isr */ dispc_write(1, DISPC_INT_CLR); dispc_ctx->is_first_frame = false; done = true; } if(done){ dispc_ctx->vsync_done = 1; #ifdef CONFIG_FB_LCD_OVERLAY_SUPPORT if(SPRD_OVERLAY_STATUS_STARTED == dispc_ctx->overlay_state){ overlay_close(dev); } #endif #ifdef CONFIG_FB_DYNAMIC_CLK_SUPPORT if(SPRDFB_PANEL_IF_DPI != dev->panel_if_type){ clk_disable(dispc_ctx->clk_dispc); clk_disable(dispc_ctx->clk_dispc_dpi); clk_disable(dispc_ctx->clk_dispc_dbi); dispc_ctx->clk_open = false; } #endif if (dispc_ctx->vsync_waiter) { wake_up_interruptible_all(&(dispc_ctx->vsync_queue)); dispc_ctx->vsync_waiter = 0; } sprdfb_panel_after_refresh(dev); pr_debug(KERN_INFO "sprdfb: [%s]: Done INT, reg_val = %d !\n", __FUNCTION__, reg_val); } return IRQ_HANDLED; }