/* * Copyright (C) 2012 Spreadtrum Communications Inc. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include #include #include #include #include #include #ifdef CONFIG_OF #include #include #include #endif #include "sprdfb_chip_common.h" #include "sprdfb.h" #include "sprdfb_panel.h" #if (defined(CONFIG_FB_SCX30G) || defined(CONFIG_FB_SCX35L)) #define FB_DSIH_VERSION_1P21A #endif #ifdef FB_DSIH_VERSION_1P21A #include "dsi_1_21a/mipi_dsih_local.h" #include "dsi_1_21a/mipi_dsih_dphy.h" #include "dsi_1_21a/mipi_dsih_hal.h" #include "dsi_1_21a/mipi_dsih_api.h" #else #include "dsi_1_10a/mipi_dsih_local.h" #include "dsi_1_10a/mipi_dsih_dphy.h" #include "dsi_1_10a/mipi_dsih_hal.h" #include "dsi_1_10a/mipi_dsih_api.h" #endif #define DSI_PHY_REF_CLOCK (26*1000) #define DSI_EDPI_CFG (0x6c) struct sprdfb_dsi_context { struct clk *clk_dsi; bool is_inited; uint32_t status;/*0- normal, 1- uninit, 2-abnormal*/ struct sprdfb_device *dev; dsih_ctrl_t dsi_inst; }; static struct sprdfb_dsi_context dsi_ctx; #ifdef CONFIG_OF unsigned long g_dsi_base_addr = 0; EXPORT_SYMBOL(g_dsi_base_addr); #endif static int32_t sprdfb_dsi_set_lp_mode(void); static int32_t sprdfb_dsi_set_ulps_mode(void); static uint32_t dsi_core_read_function(unsigned long addr, uint32_t offset) { return __raw_readl(addr + offset); } static void dsi_core_write_function(unsigned long addr, uint32_t offset, uint32_t data) { // __raw_writel(data, addr + offset); __raw_writel(data, (addr + offset)); } void dsi_core_or_function(unsigned long addr,unsigned int data) { __raw_writel((__raw_readl(addr) | data), addr); } void dsi_core_and_function(unsigned long addr,unsigned int data) { __raw_writel((__raw_readl(addr) & data), addr); } void dsi_irq_trick(void) { /*enable ack_with_err_0 interrupt*/ DSI_INT_MASK0_SET(0, 0); } //static uint32_t sot_ever_happened = 0; static irqreturn_t dsi_isr0(int irq, void *data) { #ifdef FB_DSIH_VERSION_1P21A uint32_t reg_val = dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_INT_ST0); #else uint32_t reg_val = dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_ST0); #endif printk(KERN_ERR "sprdfb: [%s](0x%x)!\n", __FUNCTION__, reg_val); /* printk("Warning: sot_ever_happened:(0x%x)!\n",sot_ever_happened); */ if(reg_val & 0x1) { /* //sot_ever_happened = 1; mask = dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_MSK0); mask |= 0x1; dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_MSK0, mask); */ DSI_INT_MASK0_SET(0, 1); } //dsi_irq_trick(0,reg_val); return IRQ_HANDLED; } static irqreturn_t dsi_isr1(int irq, void *data) { #ifdef FB_DSIH_VERSION_1P21A uint32_t reg_val = dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_INT_ST1); #else uint32_t reg_val = dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_ST1); #endif uint32_t i = 0; struct sprdfb_dsi_context *dsi_ctx = (struct sprdfb_dsi_context *)data; struct sprdfb_device *dev = dsi_ctx->dev; dsih_ctrl_t* dsi_instance = &(dsi_ctx->dsi_inst); dphy_t *phy = &(dsi_instance->phy_instance); struct panel_spec* panel = dev->panel; struct info_mipi * mipi = panel->info.mipi; printk(KERN_ERR "sprdfb: [%s](0x%x)!\n", __FUNCTION__, reg_val); if(BIT(7) == (reg_val & BIT(7))){ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_PWR_UP, 0); /*need delay 1us*/ printk("sprdfb: reset dsi host!\n"); printk("sprdfb: mipi->lan_number:%d ,mipi->phy_feq:%d \n",mipi->lan_number,mipi->phy_feq); if(NULL == phy){ printk("sprdfb: the phy is null \n"); //dsi_irq_trick(1,reg_val); return IRQ_NONE; } mipi_dsih_dphy_configure(phy, mipi->lan_number, mipi->phy_feq); {/*for debug*/ for(i=0;i<256;i+=16){ printk("sprdfb: %x: 0x%x, 0x%x, 0x%x, 0x%x\n", i, dsi_core_read_function(SPRD_MIPI_DSIC_BASE, i), dsi_core_read_function(SPRD_MIPI_DSIC_BASE, i+4), dsi_core_read_function(SPRD_MIPI_DSIC_BASE, i+8), dsi_core_read_function(SPRD_MIPI_DSIC_BASE, i+12)); } printk("**************************\n"); } dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_PWR_UP, 1); } //dsi_irq_trick(1,reg_val); return IRQ_HANDLED; } static irqreturn_t dsi_isr2(int irq, void *data) { uint32_t reg_val = 0; struct sprdfb_dsi_context *dsi_ctx = (struct sprdfb_dsi_context *)data; struct sprdfb_device *dev = dsi_ctx->dev; printk(KERN_ERR "sprdfb: [%s](0x%x)!\n", __FUNCTION__, reg_val); if(MIPI_PLL_TYPE_1 == dev->capability.mipi_pll_type) /* for PikeL / Pike */ { reg_val = dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_MIPI_PLL_INT_STS); if(BIT(0) == (reg_val & BIT(0))) { dsi_core_or_function(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_MIPI_PLL_INT_CLR, BIT(0)); printk("sprdfb: [%s], mipi pll interrupt!\n",__FUNCTION__); dsi_core_and_function(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_MIPI_PLL_INT_MSK, 0xFFFFFFFE); } } else if(MIPI_PLL_TYPE_2 == dev->capability.mipi_pll_type) /* for Sharkl64 / SharklT8*/ { dsi_core_or_function(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_MIPI_PLL_INT_CLR, BIT(0)); printk("sprdfb: [%s], mipi pll interrupt!\n",__FUNCTION__); dsi_core_or_function(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_MIPI_PLL_INT_EN, BIT(0)); } return IRQ_HANDLED; } static void dsi_reset(void) { sci_glb_set(DSI_AHB_SOFT_RST, BIT_DSI_SOFT_RST); udelay(10); sci_glb_clr(DSI_AHB_SOFT_RST, BIT_DSI_SOFT_RST); } 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: printk(KERN_ERR "sprdfb: [%s] fail, invalid video_bus_width\n", __FUNCTION__); return 0; } #ifdef FB_DSIH_VERSION_1P21A dsi_core_and_function((SPRD_MIPI_DSIC_BASE+R_DSI_HOST_DPI_COLOR_CODE),0xfffffff0); dsi_core_or_function((SPRD_MIPI_DSIC_BASE+R_DSI_HOST_DPI_COLOR_CODE),color_coding); #else dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_DPI_CFG, ((uint32_t)color_coding<<2)); #endif return 0; } static int32_t dsi_edpi_init(void) { #ifdef FB_DSIH_VERSION_1P21A dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_EDPI_CMD_SIZE, 0x500); #else dsi_core_write_function(SPRD_MIPI_DSIC_BASE, DSI_EDPI_CFG, 0x10500); #endif return 0; } int32_t dsi_dpi_init(struct sprdfb_device *dev) { dsih_dpi_video_t dpi_param = {0}; dsih_error_t result; struct panel_spec* panel = dev->panel; struct info_mipi * mipi = panel->info.mipi; dpi_param.no_of_lanes = mipi->lan_number; dpi_param.byte_clock = mipi->phy_feq / 8; #ifndef CONFIG_SC_FPGA dpi_param.pixel_clock = dev->dpi_clock/1000; #else dpi_param.pixel_clock = 6500; #endif #ifdef FB_DSIH_VERSION_1P21A dpi_param.max_hs_to_lp_cycles = 4;//110; dpi_param.max_lp_to_hs_cycles = 15;//10; dpi_param.max_clk_hs_to_lp_cycles = 4;//110; dpi_param.max_clk_lp_to_hs_cycles = 15;//10; #endif switch(mipi->video_bus_width){ case 16: dpi_param.color_coding = COLOR_CODE_16BIT_CONFIG1; break; case 18: dpi_param.color_coding = COLOR_CODE_18BIT_CONFIG1; break; case 24: dpi_param.color_coding = COLOR_CODE_24BIT; break; default: printk(KERN_ERR "sprdfb: [%s] fail, invalid video_bus_width\n", __FUNCTION__); break; } if(SPRDFB_POLARITY_POS == mipi ->h_sync_pol){ dpi_param.h_polarity = 1; } if(SPRDFB_POLARITY_POS == mipi ->v_sync_pol){ dpi_param.v_polarity = 1; } if(SPRDFB_POLARITY_POS == mipi ->de_pol){ dpi_param.data_en_polarity = 1; } dpi_param.h_active_pixels = panel->width; dpi_param.h_sync_pixels = mipi->timing->hsync; dpi_param.h_back_porch_pixels = mipi->timing->hbp; dpi_param.h_total_pixels = panel->width + mipi->timing->hsync + mipi->timing->hbp + mipi->timing->hfp; dpi_param.v_active_lines = panel->height; dpi_param.v_sync_lines = mipi->timing->vsync; dpi_param.v_back_porch_lines = mipi->timing->vbp; dpi_param.v_total_lines = panel->height + mipi->timing->vsync + mipi->timing->vbp + mipi->timing->vfp; dpi_param.receive_ack_packets = 0; dpi_param.video_mode = VIDEO_BURST_WITH_SYNC_PULSES; dpi_param.virtual_channel = 0; #ifndef CONFIG_FB_LCD_ILI9486S1_MIPI dpi_param.is_18_loosely = 0; #else dpi_param.is_18_loosely = 1; #endif result = mipi_dsih_dpi_video(&(dsi_ctx.dsi_inst), &dpi_param); if(result != OK){ printk(KERN_ERR "sprdfb: [%s] mipi_dsih_dpi_video fail (%d)!\n", __FUNCTION__, result); return -1; } return 0; } static void dsi_log_error(const char * string) { printk(string); } static int32_t dsi_module_init(struct sprdfb_device *dev) { int ret = 0; dsih_ctrl_t* dsi_instance = &(dsi_ctx.dsi_inst); dphy_t *phy = &(dsi_instance->phy_instance); struct info_mipi * mipi = dev->panel->info.mipi; int irq_num_1, irq_num_2, irq_num_3; pr_debug(KERN_INFO "sprdfb: [%s]\n", __FUNCTION__); if(dsi_ctx.is_inited){ printk(KERN_INFO "sprdfb: dsi_module_init. is_inited==true!"); return 0; } else{ printk(KERN_INFO "sprdfb: dsi_module_init. call only once!"); } phy->address = SPRD_MIPI_DSIC_BASE; 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 = SPRD_MIPI_DSIC_BASE; //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; #ifndef FB_DSIH_VERSION_1P21A dsi_instance->max_hs_to_lp_cycles = 4;//110; dsi_instance->max_lp_to_hs_cycles = 15;//10; #endif //dsi_instance->max_lanes = mipi->lan_number; #ifdef CONFIG_OF irq_num_1 = irq_of_parse_and_map(dev->of_dev->of_node, 1); #else irq_num_1 = IRQ_DSI_INTN0; #endif printk("sprdfb: dsi irq_num_1 = %d\n", irq_num_1); // ret = request_irq(IRQ_DSI_INTN0, dsi_isr0, IRQF_DISABLED, "DSI_INT0", &dsi_ctx); ret = request_irq(irq_num_1, dsi_isr0, IRQF_DISABLED, "DSI_INT0", &dsi_ctx); if (ret) { printk(KERN_ERR "sprdfb: dsi failed to request irq int0!\n"); // clk_disable(dsi_ctx.clk_dsi); }else{ printk(KERN_ERR "sprdfb: dsi request irq int0 OK!\n"); } #ifdef CONFIG_OF irq_num_2 = irq_of_parse_and_map(dev->of_dev->of_node, 2); #else irq_num_2 = IRQ_DSI_INTN1; #endif printk("sprdfb: dsi irq_num_2 = %d\n", irq_num_2); // ret = request_irq(IRQ_DSI_INTN1, dsi_isr1, IRQF_DISABLED, "DSI_INT1", &dsi_ctx); ret = request_irq(irq_num_2, dsi_isr1, IRQF_DISABLED, "DSI_INT1", &dsi_ctx); if (ret) { printk(KERN_ERR "sprdfb: dsi failed to request irq int1!\n"); // clk_disable(dsi_ctx.clk_dsi); }else{ printk(KERN_ERR "sprdfb: dsi request irq int1 OK!\n"); } if((dev->capability.mipi_pll_type > MIPI_PLL_TYPE_NONE) && (dev->capability.mipi_pll_type < MIPI_PLL_TYPE_LIMIT)) { #ifdef CONFIG_OF irq_num_3 = irq_of_parse_and_map(dev->of_dev->of_node, 3); #else irq_num_3 = IRQ_DSI_INTN2; #endif printk("sprdfb: dsi irq_num_3 = %d\n", irq_num_3); ret = request_irq(irq_num_3, dsi_isr2, IRQF_DISABLED, "DSI_INT2", &dsi_ctx); if (ret) { printk(KERN_ERR "sprdfb: dsi failed to request irq int2!\n"); }else{ printk(KERN_ERR "sprdfb: dsi request irq int2 OK!\n"); } if(MIPI_PLL_TYPE_1 == dev->capability.mipi_pll_type) { dsi_core_and_function(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_MIPI_PLL_INT_MSK, 0xFFFFFFFE); } else if (MIPI_PLL_TYPE_2 == dev->capability.mipi_pll_type) { dsi_core_and_function(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_MIPI_PLL_INT_MSK, 0xFFFFFFFE); dsi_core_or_function(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_MIPI_PLL_INT_EN, BIT(0)); } } dsi_ctx.is_inited = true; return 0; } #ifdef CONFIG_FB_DYNAMIC_FREQ_SCALING int sprdfb_dsi_chg_dphy_freq(struct sprdfb_device *fb_dev, u32 dphy_freq) { dsih_error_t result = OK; dsih_ctrl_t *ctrl = &(dsi_ctx.dsi_inst); struct info_mipi *mipi = fb_dev->panel->info.mipi; if (ctrl->status == INITIALIZED) { pr_info("Let's do update D-PHY frequency(%u)\n", dphy_freq); ctrl->phy_instance.phy_keep_work = true; result = mipi_dsih_dphy_configure(&ctrl->phy_instance, mipi->lan_number, dphy_freq); if (result != OK) { pr_err("[%s]: mipi_dsih_dphy_configure fail (%d)\n", __func__, result); ctrl->phy_instance.phy_keep_work = false; return -1; } ctrl->phy_instance.phy_keep_work = false; } mipi->phy_feq = dphy_freq; return 0; } #else int sprdfb_dsi_chg_dphy_freq(struct sprdfb_device *fb_dev, u32 dphy_freq) { return -EINVAL; } #endif int32_t sprdfb_dsih_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; int wait_count = 0; #ifdef FB_DSIH_VERSION_1P21A dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_INT_MSK0, 0x1fffff); dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_INT_MSK1, 0x3ffff); #else dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_MSK0, 0x1fffff); dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_MSK1, 0x3ffff); #endif 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){ printk(KERN_ERR "sprdfb: [%s]: mipi_dsih_unregister_all_events fail (%d)!\n", __FUNCTION__, result); return -1; } */ // dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_MSK0, 0x1fffff); // dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_MSK1, 0x3ffff); dsi_instance->phy_feq = dev->panel->info.mipi->phy_feq; dsi_instance->max_lanes = dev->panel->info.mipi->lan_number; dsi_instance->color_mode_polarity =dev->panel->info.mipi->color_mode_pol; dsi_instance->shut_down_polarity = dev->panel->info.mipi->shut_down_pol; result = mipi_dsih_open(dsi_instance); if(OK != result){ printk(KERN_ERR "sprdfb: [%s]: mipi_dsih_open fail (%d)!\n", __FUNCTION__, result); dsi_ctx.status = 1; return -1; } result = mipi_dsih_dphy_configure(phy, mipi->lan_number, mipi->phy_feq); if(OK != result){ printk(KERN_ERR "sprdfb: [%s]: mipi_dsih_dphy_configure fail (%d)!\n", __FUNCTION__, result); dsi_ctx.status = 1; return -1; } while(5 != (dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_PHY_STATUS) & 5) && (wait_count < 100000)){ udelay(3); if(0x0 == ++wait_count%1000){ printk("sprdfb: [%s] warning: busy waiting!\n", __FUNCTION__); } } if(wait_count >= 100000){ printk("sprdfb: [%s] Errior: dsi phy can't be locked!!!\n", __FUNCTION__); } if(wait_count >= 100000){ printk("sprdfb: [%s] Errior: dsi phy can't be locked!!!\n", __FUNCTION__); } if(SPRDFB_MIPI_MODE_CMD == mipi->work_mode){ dsi_edpi_setbuswidth(mipi); } result = mipi_dsih_enable_rx(dsi_instance, 1); if(OK != result){ printk(KERN_ERR "sprdfb: [%s]: mipi_dsih_enable_rx fail (%d)!\n", __FUNCTION__, result); dsi_ctx.status = 1; return -1; } result = mipi_dsih_ecc_rx(dsi_instance, 1); if(OK != result){ printk(KERN_ERR "sprdfb: [%s]: mipi_dsih_ecc_rx fail (%d)!\n", __FUNCTION__, result); dsi_ctx.status = 1; return -1; } result = mipi_dsih_eotp_rx(dsi_instance, 1); if(OK != result){ printk(KERN_ERR "sprdfb: [%s]: mipi_dsih_eotp_rx fail (%d)!\n", __FUNCTION__, result); dsi_ctx.status = 1; return -1; } result = mipi_dsih_eotp_tx(dsi_instance, 1); if(OK != result){ printk(KERN_ERR "sprdfb: [%s]: mipi_dsih_eotp_tx fail (%d)!\n", __FUNCTION__, result); dsi_ctx.status = 1; return -1; } if(SPRDFB_MIPI_MODE_VIDEO == mipi->work_mode){ dsi_dpi_init(dev); } #ifdef FB_DSIH_VERSION_1P21A mipi_dsih_dphy_enable_nc_clk(&(dsi_instance->phy_instance), false); #endif dsi_ctx.status = 0; return 0; } int32_t sprdfb_dsi_init(struct sprdfb_device *dev) { dsih_error_t result = OK; dsih_ctrl_t* dsi_instance = &(dsi_ctx.dsi_inst); #ifdef CONFIG_OF struct resource r; #endif dsi_ctx.dev = dev; #ifdef CONFIG_OF if(0 == g_dsi_base_addr){ if(0 != of_address_to_resource(dev->of_dev->of_node, 1, &r)){ printk(KERN_ERR "sprdfb: sprdfb_dsi_init fail. (can't get register base address)\n"); return -1; } g_dsi_base_addr = (unsigned long)ioremap_nocache(r.start, resource_size(&r)); } if (0 == g_dsi_base_addr){ printk("sprdfb: g_dsi_base_addr = 0!(0x%ul)\n", r.start); return -ENOMEM; } printk("sprdfb: set g_dsi_base_addr = 0x%lx\n", g_dsi_base_addr); #endif if(!dsi_ctx.is_inited){ //init if(dev->panel_ready){ //panel ready printk(KERN_INFO "sprdfb: [%s]: dsi has alread initialized\n", __FUNCTION__); dsi_instance->status = INITIALIZED; dsi_instance->phy_instance.status = INITIALIZED; dsi_module_init(dev); #ifdef FB_DSIH_VERSION_1P21A dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_INT_MSK0, 0x0); dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_INT_MSK1, 0x800); #else dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_MSK0, 0x0); dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_MSK1, 0x800); #endif }else{ //panel not ready printk(KERN_INFO "sprdfb: [%s]: dsi is not initialized\n", __FUNCTION__); dsi_enable(); dsi_reset(); dsi_module_init(dev); result=sprdfb_dsih_init(dev); } }else{ //resume printk(KERN_INFO "sprdfb: [%s]: resume\n", __FUNCTION__); dsi_enable(); dsi_reset(); result=sprdfb_dsih_init(dev); } return result; } int32_t sprdfb_dsi_uninit(struct sprdfb_device *dev) { dsih_error_t result; dsih_ctrl_t* dsi_instance = &(dsi_ctx.dsi_inst); printk(KERN_INFO "sprdfb: [%s], dev_id = %d\n",__FUNCTION__, dev->dev_id); #ifdef FB_DSIH_VERSION_1P21A mipi_dsih_dphy_enable_hs_clk(&(dsi_instance->phy_instance), false); #else dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_PHY_IF_CTRL, 0); #endif result = mipi_dsih_close(&(dsi_ctx.dsi_inst)); dsi_instance->status = NOT_INITIALIZED; dsi_ctx.status = 1; if(OK != result){ printk(KERN_ERR "sprdfb: [%s]: sprdfb_dsi_uninit fail (%d)!\n", __FUNCTION__, result); return -1; } msleep(10); dsi_disable(); return 0; } int32_t sprdfb_dsi_suspend(struct sprdfb_device *dev) { dsih_ctrl_t* dsi_instance = &(dsi_ctx.dsi_inst); printk(KERN_INFO "sprdfb: [%s], dev_id = %d\n",__FUNCTION__, dev->dev_id); // sprdfb_dsi_uninit(dev); // mipi_dsih_dphy_close(&(dsi_instance->phy_instance)); // mipi_dsih_dphy_shutdown(&(dsi_instance->phy_instance), 0); mipi_dsih_hal_power(dsi_instance, 0); return 0; } int32_t sprdfb_dsi_resume(struct sprdfb_device *dev) { dsih_ctrl_t* dsi_instance = &(dsi_ctx.dsi_inst); #if 0 dsih_error_t result = OK; dphy_t *phy = &(dsi_instance->phy_instance); struct info_mipi * mipi = dev->panel->info.mipi; #endif printk(KERN_INFO "sprdfb: [%s], dev_id = %d\n",__FUNCTION__, dev->dev_id); #if 0 result = mipi_dsih_dphy_open(&(dsi_instance->phy_instance)); if(0 != result){ printk("Jessica: mipi_dsih_dphy_open fail!(%d)\n",result); } udelay(100); #endif // mipi_dsih_dphy_shutdown(&(dsi_instance->phy_instance), 1); mipi_dsih_hal_power(dsi_instance, 1); #if 0 result = mipi_dsih_dphy_configure(phy, mipi->lan_number, mipi->phy_feq); if(OK != result){ printk(KERN_ERR "sprdfb: [%s]: mipi_dsih_dphy_configure fail (%d)!\n", __FUNCTION__, result); return -1; } #endif return 0; } int32_t sprdfb_dsi_ready(struct sprdfb_device *dev) { struct info_mipi * mipi = dev->panel->info.mipi; if(SPRDFB_MIPI_MODE_CMD == mipi->work_mode){ mipi_dsih_cmd_mode(&(dsi_ctx.dsi_inst), 1); #ifdef FB_DSIH_VERSION_1P21A mipi_dsih_dphy_enable_hs_clk(&(dsi_ctx.dsi_inst.phy_instance), true); dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_CMD_MODE_CFG, 0x0); #else dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_CMD_MODE_CFG, 0x1); dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_PHY_IF_CTRL, 0x1); #endif }else{ #ifdef FB_DSIH_VERSION_1P21A mipi_dsih_dphy_enable_hs_clk(&(dsi_ctx.dsi_inst.phy_instance), true); #else dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_PHY_IF_CTRL, 0x1); #endif mipi_dsih_video_mode(&(dsi_ctx.dsi_inst), 1); dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_PWR_UP, 0); udelay(100); dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_PWR_UP, 1); usleep_range(3000, 3500); #ifdef FB_DSIH_VERSION_1P21A dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_INT_ST0); dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_INT_ST1); #else dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_ST0); dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_ST1); #endif } #ifdef FB_DSIH_VERSION_1P21A dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_INT_MSK0, 0x0); dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_INT_MSK1, 0x800); #else dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_MSK0, 0x0); dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_MSK1, 0x800); #endif return 0; } int32_t sprdfb_dsi_before_panel_reset(struct sprdfb_device *dev) { sprdfb_dsi_set_lp_mode(); return 0; } int32_t sprdfb_dsi_enter_ulps(struct sprdfb_device *dev) { sprdfb_dsi_set_ulps_mode(); return 0; } uint32_t sprdfb_dsi_get_status(struct sprdfb_device *dev) { return dsi_ctx.status; } static int32_t sprdfb_dsi_set_cmd_mode(void) { mipi_dsih_cmd_mode(&(dsi_ctx.dsi_inst), 1); return 0; } static int32_t sprdfb_dsi_set_video_mode(void) { mipi_dsih_video_mode(&(dsi_ctx.dsi_inst), 1); return 0; } static int32_t sprdfb_dsi_set_lp_mode(void) { #ifndef FB_DSIH_VERSION_1P21A uint32_t reg_val; #endif pr_debug(KERN_INFO "sprdfb: [%s]\n",__FUNCTION__); mipi_dsih_cmd_mode(&(dsi_ctx.dsi_inst), 1); #ifdef FB_DSIH_VERSION_1P21A dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_CMD_MODE_CFG, 0x01ffff00); mipi_dsih_dphy_enable_hs_clk(&(dsi_ctx.dsi_inst.phy_instance), false); #else dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_CMD_MODE_CFG, 0x1fff); reg_val = dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_PHY_IF_CTRL); reg_val = reg_val & (~(BIT(0))); dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_PHY_IF_CTRL, reg_val); #endif return 0; } static int32_t sprdfb_dsi_set_hs_mode(void) { pr_debug(KERN_INFO "sprdfb: [%s]\n",__FUNCTION__); mipi_dsih_cmd_mode(&(dsi_ctx.dsi_inst), 1); #ifdef FB_DSIH_VERSION_1P21A dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_CMD_MODE_CFG, 0x0); mipi_dsih_dphy_enable_hs_clk(&(dsi_ctx.dsi_inst.phy_instance), true); #else dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_CMD_MODE_CFG, 0x1); dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_PHY_IF_CTRL, 0x1); #endif return 0; } static int32_t sprdfb_dsi_set_ulps_mode(void) { mipi_dsih_ulps_mode(&(dsi_ctx.dsi_inst), 1); return 0; } static int32_t sprdfb_dsi_set_data_lp_mode(void) { // pr_debug(KERN_INFO "sprdfb: [%s]\n",__FUNCTION__); dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_CMD_MODE_CFG, 0x1fff); return 0; } static int32_t sprdfb_dsi_set_data_hs_mode(void) { int active_mode = mipi_dsih_active_mode(&(dsi_ctx.dsi_inst)); // pr_debug(KERN_INFO "sprdfb: [%s]\n",__FUNCTION__); // printk("aoke sprdfb: set data hs mode active_mode=%d\n",active_mode); if(1==active_mode){ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_CMD_MODE_CFG, 0x1); }else{ dsi_core_write_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_CMD_MODE_CFG, 0x0); } return 0; } static int32_t sprdfb_dsi_gen_write(uint8_t *param, uint16_t param_length) { dsih_error_t result; result = mipi_dsih_gen_wr_cmd(&(dsi_ctx.dsi_inst), 0, param, param_length); if(OK != result){ printk(KERN_ERR "sprdfb: [%s] error (%d)\n", __FUNCTION__, result); return -1; } return 0; } #define LCM_SEND(len) ((1 << 24)| len) #define LCM_TAG_MASK ((1 << 24) -1) static unsigned char set_bl_seq[] = { #ifndef CONFIG_MACH_TSHARK2TABE 0x51, 0xFF #else 0xF5, 0x8B #endif }; void backlight_control(int brigtness) { set_bl_seq[1] = brigtness; sprdfb_dsi_gen_write(set_bl_seq, LCM_SEND(2) & LCM_TAG_MASK); } EXPORT_SYMBOL(backlight_control); static int32_t sprdfb_dsi_gen_read(uint8_t *param, uint16_t param_length, uint8_t bytes_to_read, uint8_t *read_buffer) { uint16_t result; uint32_t reg_val, reg_val_1, reg_val_2; result = mipi_dsih_gen_rd_cmd(&(dsi_ctx.dsi_inst), 0, param, param_length, bytes_to_read, read_buffer); reg_val = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_PHY_STATUS); #ifdef FB_DSIH_VERSION_1P21A reg_val_1 = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_INT_ST0); reg_val_2 = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_INT_ST1); #else reg_val_1 = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_ERROR_ST0); reg_val_2 = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_ERROR_ST1); #endif if(0 != (reg_val & 0x2)){ printk("sprdfb: [%s] mipi read hang (0x%x)!\n", __FUNCTION__, reg_val); dsi_ctx.status = 2; result = 0; } if(0 != (reg_val_1 & 0x701)){ printk("sprdfb: [%s] mipi read status error!(0x%x, 0x%x)\n", __FUNCTION__, reg_val_1, reg_val_2); result = 0; } if(0 == result){ printk(KERN_ERR "sprdfb: [%s] return error (%d)\n", __FUNCTION__, result); return -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){ printk(KERN_ERR "sprdfb: [%s] error (%d)\n", __FUNCTION__, result); return -1; } return 0; } static int32_t sprdfb_dsi_dcs_read(uint8_t command, uint8_t bytes_to_read, uint8_t *read_buffer) { uint16_t result; uint32_t reg_val, reg_val_1, reg_val_2; result = mipi_dsih_dcs_rd_cmd(&(dsi_ctx.dsi_inst), 0, command, bytes_to_read, read_buffer); reg_val = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_PHY_STATUS); #ifdef FB_DSIH_VERSION_1P21A reg_val_1 = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_INT_ST0); reg_val_2 = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_INT_ST1); #else reg_val_1 = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_ERROR_ST0); reg_val_2 = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_ERROR_ST1); #endif if(0 != (reg_val & 0x2)){ printk("sprdfb: [%s] mipi read hang (0x%x)!\n", __FUNCTION__, reg_val); dsi_ctx.status = 2; result = 0; } if(0 != (reg_val_1 & 0x701)){ printk("sprdfb: [%s] mipi read status error!(0x%x, 0x%x)\n", __FUNCTION__, reg_val_1, reg_val_2); result = 0; } if(0 == result){ printk(KERN_ERR "sprdfb: [%s] return error (%d)\n", __FUNCTION__, result); return -1; } return 0; } static int32_t sprd_dsi_force_write(uint8_t data_type, uint8_t *p_params, uint16_t param_length) { int32_t iRtn = 0; iRtn = mipi_dsih_gen_wr_packet(&(dsi_ctx.dsi_inst), 0, data_type, p_params, param_length); return iRtn; } static int32_t sprd_dsi_force_read(uint8_t command, uint8_t bytes_to_read, uint8_t * read_buffer) { int32_t iRtn = 0; uint32_t reg_val, reg_val_1, reg_val_2; iRtn = mipi_dsih_gen_rd_packet(&(dsi_ctx.dsi_inst), 0, 6, 0, command, bytes_to_read, read_buffer); reg_val = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_PHY_STATUS); #ifdef FB_DSIH_VERSION_1P21A reg_val_1 = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_INT_ST0); reg_val_2 = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_INT_ST1); #else reg_val_1 = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_ERROR_ST0); reg_val_2 = dispc_glb_read(SPRD_MIPI_DSIC_BASE + R_DSI_HOST_ERROR_ST1); #endif if(0 != (reg_val & 0x2)){ printk("sprdfb: [%s] mipi read hang (0x%x)!\n", __FUNCTION__, reg_val); dsi_ctx.status = 2; iRtn = 0; } if(0 != (reg_val_1 & 0x701)){ printk("sprdfb: [%s] mipi read status error!(0x%x, 0x%x)\n", __FUNCTION__, reg_val_1, reg_val_2); iRtn = 0; } if(0 == iRtn){ printk(KERN_ERR "sprdfb: [%s] return error (%d)\n", __FUNCTION__, iRtn); return -1; } return 0; } static int32_t sprd_dsi_eotp_set(uint8_t rx_en, uint8_t tx_en) { dsih_ctrl_t *curInstancePtr = &(dsi_ctx.dsi_inst); if(0 == rx_en) mipi_dsih_eotp_rx(curInstancePtr, 0); else if(1 == rx_en) mipi_dsih_eotp_rx(curInstancePtr, 1); if(0 == tx_en) mipi_dsih_eotp_tx(curInstancePtr, 0); else if(1 == tx_en) mipi_dsih_eotp_tx(curInstancePtr, 1); return 0; } struct ops_mipi sprdfb_mipi_ops = { .mipi_set_cmd_mode = sprdfb_dsi_set_cmd_mode, .mipi_set_video_mode = sprdfb_dsi_set_video_mode, .mipi_set_lp_mode = sprdfb_dsi_set_lp_mode, .mipi_set_hs_mode = sprdfb_dsi_set_hs_mode, .mipi_set_data_lp_mode = sprdfb_dsi_set_data_lp_mode, .mipi_set_data_hs_mode = sprdfb_dsi_set_data_hs_mode, .mipi_gen_write = sprdfb_dsi_gen_write, .mipi_gen_read = sprdfb_dsi_gen_read, .mipi_dcs_write = sprdfb_dsi_dcs_write, .mipi_dcs_read = sprdfb_dsi_dcs_read, .mipi_force_write = sprd_dsi_force_write, .mipi_force_read = sprd_dsi_force_read, .mipi_eotp_set = sprd_dsi_eotp_set, };