static int32_t sprdfb_mcu_panel_check(struct panel_spec *panel) { struct info_mcu* mcu_info = NULL; uint16_t rval = 1; if(NULL == panel){ printf("sprdfb: [%s] fail. (Invalid param)\n", __FUNCTION__); return 0; } if(SPRDFB_PANEL_TYPE_MCU != panel->type){ printf("sprdfb: [%s] fail. (not mcu param)\n", __FUNCTION__); return 0; } mcu_info = panel->info.mcu; FB_PRINT("sprdfb: [%s]: bus width= %d, bpp = %d\n",__FUNCTION__, mcu_info->bus_width, mcu_info->bpp); switch(mcu_info->bus_width){ case 8: if((16 != mcu_info->bpp) && (24 != mcu_info->bpp)){ rval = 0; } break; case 9: if(18 != mcu_info->bpp) { rval = 0; } break; case 16: if((16 != mcu_info->bpp) && (18 != mcu_info->bpp) && (24 != mcu_info->bpp)){ rval = 0; } break; case 18: if(18 != mcu_info->bpp){ rval = 0; } break; case 24: if(24 != mcu_info->bpp){ rval = 0; } break; default: rval = 0; break; } if(!rval){ FB_PRINT("sprdfb: mcu_panel_check return false!\n"); } return rval; }
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; }
/* dispc soft reset */ static void dispc_reset(void) { FB_PRINT("sprdfb:[%s]\n",__FUNCTION__); __raw_writel(__raw_readl(AHB_SOFT_RST) | (1<<DISPC_SOFT_RST), AHB_SOFT_RST); udelay(10); __raw_writel(__raw_readl(AHB_SOFT_RST) & (~(1<<DISPC_SOFT_RST)), AHB_SOFT_RST); }
static int32_t sprdfb_dispc_uninit(struct sprdfb_device *dev) { FB_PRINT("sprdfb:[%s]\n",__FUNCTION__); //disable DISPC clock __raw_bits_and(~(1<<22), AHB_CTL0); return 0; }
int32_t dsi_early_int(void) { FB_PRINT("sprdfb:[%s]\n", __FUNCTION__); if(dsi_ctx.is_inited){ FB_PRINT("sprdfb: dispc early init warning!(has been inited)"); return 0; } //TODO:Enable DSI clock dsi_reset(); memset(&(dsi_ctx.dsi_inst), 0, sizeof(dsi_ctx.dsi_inst)); dsi_ctx.is_inited = 1; return 0; }
static int32_t sprdfb_dsi_dcs_write(uint8_t *param, uint16_t param_length) { dsih_error_t result; result = mipi_dsih_dcs_wr_cmd(&(dsi_ctx.dsi_inst), 0, param, param_length); if(OK != result){ FB_PRINT("sprdfb: [%s] error (%d)\n", __FUNCTION__, result); return -1; } return 0; }
static void dispc_set_exp_mode(uint16_t exp_mode) { uint32_t reg_val = dispc_read(DISPC_CTRL); FB_PRINT("sprdfb:[%s]\n",__FUNCTION__); reg_val &= ~(0x3 << 16); reg_val |= (exp_mode << 16); dispc_write(reg_val, 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 int32_t sprdfb_dsi_dcs_read(uint8_t command, uint8_t bytes_to_read, uint8_t *read_buffer) { uint16_t result; result = mipi_dsih_dcs_rd_cmd(&(dsi_ctx.dsi_inst), 0, command, bytes_to_read, read_buffer); if(0 == result){ FB_PRINT("sprdfb: [%s] error (%d)\n", __FUNCTION__, result); return -1; } return 0; }
static void dispc_layer_init(struct sprdfb_device *dev) { uint32_t reg_val = 0; FB_PRINT("sprdfb:[%s]\n",__FUNCTION__); dispc_clear_bits((1<<0),DISPC_IMG_CTRL); dispc_clear_bits((1<<0),DISPC_OSD_CTRL); /******************* OSD layer setting **********************/ /*enable OSD layer*/ reg_val |= (1 << 0); /*disable color key */ /* alpha mode select - block alpha*/ reg_val |= (1 << 2); /* data format */ /* RGB565 */ reg_val |= (5 << 4); /* B2B3B0B1 */ reg_val |= (2 << 8); dispc_write(reg_val, DISPC_OSD_CTRL); /* OSD layer alpha value */ dispc_write(0xff, DISPC_OSD_ALPHA); /* OSD layer size */ reg_val = ( dev->panel->width& 0xfff) | ((dev->panel->height & 0xfff ) << 16); dispc_write(reg_val, DISPC_OSD_SIZE_XY); /* OSD layer start position */ dispc_write(0, DISPC_OSD_DISP_XY); /* OSD layer pitch */ reg_val = ( dev->panel->width & 0xfff) ; dispc_write(reg_val, DISPC_OSD_PITCH); /*OSD base address*/ dispc_write(dev->smem_start, DISPC_OSD_BASE_ADDR); /* OSD color_key value */ dispc_set_osd_ck(0x0); /* DISPC workplane size */ dispc_set_disp_size(dev); FB_PRINT("DISPC_OSD_CTRL: 0x%x\n", dispc_read(DISPC_OSD_CTRL)); FB_PRINT("DISPC_OSD_ALPHA: 0x%x\n", dispc_read(DISPC_OSD_ALPHA)); FB_PRINT("DISPC_OSD_SIZE_XY: 0x%x\n", dispc_read(DISPC_OSD_SIZE_XY)); FB_PRINT("DISPC_OSD_DISP_XY: 0x%x\n", dispc_read(DISPC_OSD_DISP_XY)); FB_PRINT("DISPC_OSD_PITCH: 0x%x\n", dispc_read(DISPC_OSD_PITCH)); FB_PRINT("DISPC_OSD_BASE_ADDR: 0x%x\n", dispc_read(DISPC_OSD_BASE_ADDR)); }
static inline int32_t dispc_set_disp_size(struct sprdfb_device *dev) { uint32_t reg_val; FB_PRINT("sprdfb:[%s]\n",__FUNCTION__); reg_val = (dev->panel->width& 0xfff) | ((dev->panel->height & 0xfff ) << 16); dispc_write(reg_val, DISPC_SIZE_XY); return 0; }
static int32_t sprdfb_dispc_early_init(struct sprdfb_device *dev) { FB_PRINT("sprdfb:[%s]\n", __FUNCTION__); //select DISPC clock source __raw_bits_and(~(1<<1), AHB_DISPC_CLK); //pll_src=256M __raw_bits_and(~(1<<2), AHB_DISPC_CLK); //set DISPC divdior __raw_bits_and(~(1<<3), AHB_DISPC_CLK); //div=0 __raw_bits_and(~(1<<4), AHB_DISPC_CLK); __raw_bits_and(~(1<<5), AHB_DISPC_CLK); //select DBI clock source __raw_bits_and(~(1<<9), AHB_DISPC_CLK); //pll_src=256M __raw_bits_and(~(1<<10), AHB_DISPC_CLK); //set DBI divdior __raw_bits_and(~(1<<11), AHB_DISPC_CLK); //div=0 __raw_bits_and(~(1<<12), AHB_DISPC_CLK); __raw_bits_and(~(1<<13), AHB_DISPC_CLK); //select DPI clock source __raw_bits_and(~(1<<17), AHB_DISPC_CLK); //pll_src=384M __raw_bits_and(~(1<<18), AHB_DISPC_CLK); //set DPI divdior __raw_bits_and(~(1<<19), AHB_DISPC_CLK); //div=10, dpi_clk = pll_src/(10+1) __raw_bits_or((1<<20), AHB_DISPC_CLK); __raw_bits_and(~(1<<21), AHB_DISPC_CLK); __raw_bits_or((1<<22), AHB_DISPC_CLK); __raw_bits_and(~(1<<23), AHB_DISPC_CLK); __raw_bits_and(~(1<<24), AHB_DISPC_CLK); __raw_bits_and(~(1<<25), AHB_DISPC_CLK); __raw_bits_and(~(1<<26), AHB_DISPC_CLK); //enable dispc matric clock __raw_bits_or((1<<9), AHB_CTL2); //core_clock_en __raw_bits_or((1<<11), AHB_CTL2); //matrix clock en //enable DISPC clock __raw_bits_or(1<<22, AHB_CTL0); printf("0x20900200 = 0x%x\n", __raw_readl(0x20900200)); printf("0x20900208 = 0x%x\n", __raw_readl(0x20900208)); printf("0x20900220 = 0x%x\n", __raw_readl(0x20900220)); dispc_reset(); dispc_module_enable(); is_first_frame = 1; return 0; }
static void dispc_module_enable(void) { FB_PRINT("sprdfb:[%s]\n",__FUNCTION__); /*dispc module enable */ dispc_write((1<<0), DISPC_CTRL); /*disable dispc INT*/ dispc_write(0x0, DISPC_INT_EN); /* clear dispc INT */ dispc_write(0x1F, DISPC_INT_CLR); }
int32_t sprdfb_dsi_uninit(struct sprdfb_device *dev) { dsih_error_t result; result = mipi_dsih_close(&(dsi_ctx.dsi_inst)); if(OK != result){ FB_PRINT("sprdfb: [%s]: sprdfb_dsi_uninit fail (%d)!\n", __FUNCTION__, result); return -1; } else { dsi_ctx.is_inited = 0; } dsi_core_write_function(DSI_CTL_BEGIN, R_DSI_HOST_PHY_IF_CTRL, 0); mdelay(3); return 0; }
void mcu_dispc_set_timing(struct sprdfb_device *dev, uint32_t type) { FB_PRINT("sprdfb: [%s] for cs0, type = %d\n", __FUNCTION__, type); switch (type) { case MCU_LCD_REGISTER_TIMING: dispc_write(dev->panel_timing.mcu_timing[MCU_LCD_REGISTER_TIMING],DISPC_DBI_TIMING0); break; case MCU_LCD_GRAM_TIMING: dispc_write(dev->panel_timing.mcu_timing[MCU_LCD_GRAM_TIMING],DISPC_DBI_TIMING0); break; default: break; } }
static int32_t dsi_edpi_setbuswidth(struct info_mipi * mipi) { dsih_color_coding_t color_coding = 0; switch(mipi->video_bus_width){ case 16: color_coding = COLOR_CODE_16BIT_CONFIG1; break; case 18: color_coding = COLOR_CODE_18BIT_CONFIG1; break; case 24: color_coding = COLOR_CODE_24BIT; break; default: FB_PRINT("sprdfb:[%s] fail, invalid video_bus_width\n", __FUNCTION__); break; } dsi_core_write_function(DSI_CTL_BEGIN, R_DSI_HOST_DPI_CFG, (uint32_t)(color_coding<<2)); return 0; }
static void sprdfb_mcu_panel_mount(struct sprdfb_device *dev) { struct timing_mcu* timing = NULL; if((NULL == dev) || (NULL == dev->panel)){ printf("sprdfb: [%s]: Invalid Param\n", __FUNCTION__); return; } FB_PRINT("sprdfb: [%s]\n",__FUNCTION__); dev->panel_if_type = SPRDFB_PANEL_IF_DBI; dev->panel->info.mcu->ops = &dispc_mcu_ops; if(NULL == dev->panel->ops->panel_readid){ dev->panel->ops->panel_readid = mcu_readid; } timing = dev->panel->info.mcu->timing; dev->panel_timing.mcu_timing[MCU_LCD_REGISTER_TIMING] = mcu_calc_timing(timing); timing++; dev->panel_timing.mcu_timing[MCU_LCD_GRAM_TIMING] = mcu_calc_timing(timing); }
/*cs0*/ void mcu_dispc_init_config(struct panel_spec *panel) { uint32_t reg_val = 0; FB_PRINT("sprdfb: [%s] for cs0\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); /* 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); FB_PRINT("sprdfb: [%s] DISPC_DBI_CTRL = %d\n", __FUNCTION__, dispc_read(DISPC_DBI_CTRL)); }
static inline void dispc_set_bg_color(uint32_t bg_color) { FB_PRINT("sprdfb:[%s]\n",__FUNCTION__); dispc_write(bg_color, DISPC_BG_COLOR); }
static inline void dispc_set_osd_ck(uint32_t ck_color) { FB_PRINT("sprdfb:[%s]\n",__FUNCTION__); dispc_write(ck_color, DISPC_OSD_CK); }
static uint32_t mcu_calc_timing(struct timing_mcu *timing) { uint32_t clk_rate; uint32_t rcss, rlpw, rhpw, wcss, wlpw, whpw; // struct clk * clk = NULL; if(NULL == timing){ FB_PRINT("sprdfb: [%s]: Invalid Param\n", __FUNCTION__); return 0; } // clk_get(NULL,"clk_dispc_dbi"); // clk_rate = clk_get_rate(clk) / 1000000; clk_rate = 250; // 250 MHz FB_PRINT("sprdfb: [%s] clk_rate: 0x%x\n", __FUNCTION__, clk_rate); /******************************************************** * we assume : t = ? ns, dispc_dbi = ? MHz so * 1ns need cycle : dispc_dbi /1000 * tns need cycles : t * dispc_dbi / 1000 * ********************************************************/ #define MAX_DBI_RWCSS_TIMING_VALUE 15 #define MAX_DBI_RWLPW_TIMING_VALUE 63 #define MAX_DBI_RWHPW_TIMING_VALUE 63 #define DBI_CYCLES(ns) (( (ns) * clk_rate + 1000 - 1)/ 1000) /* ceiling*/ rcss = DBI_CYCLES(timing->rcss); if (rcss > MAX_DBI_RWCSS_TIMING_VALUE) { rcss = MAX_DBI_RWCSS_TIMING_VALUE ; } rlpw = DBI_CYCLES(timing->rlpw); if (rlpw > MAX_DBI_RWLPW_TIMING_VALUE) { rlpw = MAX_DBI_RWLPW_TIMING_VALUE ; } rhpw = DBI_CYCLES (timing->rhpw); if (rhpw > MAX_DBI_RWHPW_TIMING_VALUE) { rhpw = MAX_DBI_RWHPW_TIMING_VALUE ; } wcss = DBI_CYCLES(timing->wcss); if (wcss > MAX_DBI_RWCSS_TIMING_VALUE) { wcss = MAX_DBI_RWCSS_TIMING_VALUE ; } wlpw = DBI_CYCLES(timing->wlpw); if (wlpw > MAX_DBI_RWLPW_TIMING_VALUE) { wlpw = MAX_DBI_RWLPW_TIMING_VALUE ; } #ifndef CONFIG_LCD_CS_ALWAYS_LOW /* dispc/lcdc will waste one cycle because CS pulse will use one cycle*/ whpw = DBI_CYCLES (timing->whpw) - 1; #else whpw = DBI_CYCLES (timing->whpw) ; #endif if (whpw > MAX_DBI_RWHPW_TIMING_VALUE) { whpw = MAX_DBI_RWHPW_TIMING_VALUE ; } return (whpw | (wlpw << 6) | (wcss << 12) | (rhpw << 16) |(rlpw << 22) | (rcss << 28)); }
int32_t sprdfb_dsi_init(struct sprdfb_device *dev) { dsih_error_t result = OK; dsih_ctrl_t* dsi_instance = &(dsi_ctx.dsi_inst); dphy_t *phy = &(dsi_instance->phy_instance); struct info_mipi * mipi = dev->panel->info.mipi; __raw_bits_or((1<<0), 0x2090021c); //enable dphy FB_PRINT("sprdfb:[%s]\n", __FUNCTION__); dsi_early_int(); phy->address = DSI_CTL_BEGIN; phy->core_read_function = dsi_core_read_function; phy->core_write_function = dsi_core_write_function; phy->log_error = dsi_log_error; phy->log_info = NULL; phy->reference_freq = DSI_PHY_REF_CLOCK; dsi_instance->address = DSI_CTL_BEGIN; dsi_instance->color_mode_polarity =mipi->color_mode_pol; dsi_instance->shut_down_polarity = mipi->shut_down_pol; dsi_instance->core_read_function = dsi_core_read_function; dsi_instance->core_write_function = dsi_core_write_function; dsi_instance->log_error = dsi_log_error; dsi_instance->log_info = NULL; /*in our rtl implementation, this is max rd time, not bta time and use 15bits*/ dsi_instance->max_bta_cycles = 0x6000;//10; dsi_instance->max_hs_to_lp_cycles = 4;//110; dsi_instance->max_lp_to_hs_cycles = 15;//10; dsi_instance->max_lanes = mipi->lan_number; if(SPRDFB_MIPI_MODE_CMD == mipi->work_mode){ dsi_edpi_init(); }/*else{ dsi_dpi_init(dev->panel); }*/ /* result = mipi_dsih_unregister_all_events(dsi_instance); if(OK != result){ FB_PRINT("sprdfb: [%s]: mipi_dsih_unregister_all_events fail (%d)!\n", __FUNCTION__, result); return -1; } */ dsi_core_write_function(DSI_CTL_BEGIN, R_DSI_HOST_ERROR_MSK0, 0x1fffff); dsi_core_write_function(DSI_CTL_BEGIN, R_DSI_HOST_ERROR_MSK1, 0x3ffff); result = mipi_dsih_open(dsi_instance); if(OK != result){ FB_PRINT("sprdfb: [%s]: mipi_dsih_open fail (%d)!\n", __FUNCTION__, result); return -1; } result = mipi_dsih_dphy_configure(phy, mipi->lan_number, mipi->phy_feq); if(OK != result){ FB_PRINT("sprdfb: [%s]: mipi_dsih_dphy_configure fail (%d)!\n", __FUNCTION__, result); return -1; } while(5 != (dsi_core_read_function(DSI_CTL_BEGIN, R_DSI_HOST_PHY_STATUS) & 5)); if(SPRDFB_MIPI_MODE_CMD == mipi->work_mode){ dsi_edpi_setbuswidth(mipi); } result = mipi_dsih_enable_rx(dsi_instance, 1); if(OK != result){ FB_PRINT("sprdfb: [%s]: mipi_dsih_enable_rx fail (%d)!\n", __FUNCTION__, result); return -1; } result = mipi_dsih_ecc_rx(dsi_instance, 1); if(OK != result){ FB_PRINT("sprdfb: [%s]: mipi_dsih_ecc_rx fail (%d)!\n", __FUNCTION__, result); return -1; } result = mipi_dsih_eotp_rx(dsi_instance, 1); if(OK != result){ FB_PRINT("sprdfb: [%s]: mipi_dsih_eotp_rx fail (%d)!\n", __FUNCTION__, result); return -1; } result = mipi_dsih_eotp_tx(dsi_instance, 1); if(OK != result){ FB_PRINT("sprdfb: [%s]: mipi_dsih_eotp_tx fail (%d)!\n", __FUNCTION__, result); return -1; } if(SPRDFB_MIPI_MODE_VIDEO == mipi->work_mode){ dsi_dpi_init(dev->panel); } return 0; }
static void dsi_log_error(const char * string) { FB_PRINT(string); }