int mdfld_dsi_dsr_update_panel_fb(struct mdfld_dsi_config *dsi_config) { struct mdfld_dsi_dsr *dsr; struct mdfld_dsi_pkg_sender *sender; int err = 0; if (!dsi_config) { DRM_ERROR("Invalid parameter\n"); return -EINVAL; } dsr = dsi_config->dsr; if (!IS_ANN(dev)) { /*if no dsr attached, return 0*/ if (!dsr) return 0; } PSB_DEBUG_ENTRY("\n"); if (dsi_config->type == MDFLD_DSI_ENCODER_DPI) return 0; mutex_lock(&dsi_config->context_lock); if (!dsi_config->dsi_hw_context.panel_on) { PSB_DEBUG_ENTRY( "if screen off, update fb is not allowed\n"); err = -EINVAL; goto update_fb_out; } /*no pending fb updates, go ahead to send out write_mem_start*/ PSB_DEBUG_ENTRY("send out write_mem_start\n"); sender = mdfld_dsi_get_pkg_sender(dsi_config); if (!sender) { DRM_ERROR("No sender\n"); err = -EINVAL; goto update_fb_out; } err = mdfld_dsi_send_dcs(sender, write_mem_start, NULL, 0, CMD_DATA_SRC_PIPE, MDFLD_DSI_SEND_PACKAGE); if (err) { DRM_ERROR("Failed to send write_mem_start"); err = -EINVAL; goto update_fb_out; } /*clear free count*/ dsr->free_count = 0; update_fb_out: mutex_unlock(&dsi_config->context_lock); return err; }
/* * _sysfs_support_fbc_show() - Return 1 if FBC/FBDC supported, else 0. * @kdev - Pointer to struct device * @attr - pointer to struct device_attribute * @buf - Pointer to output buffer to receive character string. * The buffer length is PAGE_SIZE bytes. */ static ssize_t _sysfs_support_fbc_show(struct device *kdev, struct device_attribute *attr, char *buf) { const int buflen = PAGE_SIZE; int support_fbc; /* Supported for Anniedale, but not for ANN A0 and ANN B0. */ if (!IS_ANN() || IS_ANN_A0() || IS_ANN_B0()) support_fbc = 0; else support_fbc = 1; return scnprintf(buf, buflen, "%d\n", support_fbc); }
static int jdi_cmd_drv_ic_init(struct mdfld_dsi_config *dsi_config) { struct mdfld_dsi_pkg_sender *sender = mdfld_dsi_get_pkg_sender(dsi_config); int err = 0; PSB_DEBUG_ENTRY("\n"); if (!sender) { DRM_ERROR("Cannot get sender\n"); return -EINVAL; } err = mdfld_dsi_send_mcs_short_hs(sender, exit_sleep_mode, 0, 0, MDFLD_DSI_SEND_PACKAGE); if (err) { DRM_ERROR("%s: %d: Exit Sleep Mode\n", __func__, __LINE__); goto ic_init_err; } msleep(120); err = mdfld_dsi_send_mcs_short_hs(sender, write_display_brightness, 0x0, 1, MDFLD_DSI_SEND_PACKAGE); if (err) { DRM_ERROR("%s: %d: Set Brightness\n", __func__, __LINE__); goto ic_init_err; } err = mdfld_dsi_send_mcs_short_hs(sender, write_ctrl_display, 0x24, 1, MDFLD_DSI_SEND_PACKAGE); if (err) { DRM_ERROR("%s: %d: Write Control Display\n", __func__, __LINE__); goto ic_init_err; } err = mdfld_dsi_send_mcs_short_hs(sender, write_ctrl_cabc, STILL_IMAGE, 1, MDFLD_DSI_SEND_PACKAGE); if (err) { DRM_ERROR("%s: %d: Write Control CABC\n", __func__, __LINE__); goto ic_init_err; } if (!IS_ANN(dev)) { err = mdfld_dsi_send_mcs_short_hs(sender, write_cabc_min_bright, 51, 1, MDFLD_DSI_SEND_PACKAGE); if (err) { DRM_ERROR("%s: %d: Write CABC minimum brightness\n", __func__, __LINE__); goto ic_init_err; } } err = mdfld_dsi_send_gen_short_hs(sender, access_protect, 4, 2, MDFLD_DSI_SEND_PACKAGE); if (err) { DRM_ERROR("%s: %d: Manufacture command protect on\n", __func__, __LINE__); goto ic_init_err; } err = mdfld_dsi_send_gen_long_lp(sender, jdi_timing_control, 21, MDFLD_DSI_SEND_PACKAGE); if (err) { DRM_ERROR("%s: %d: Set panel timing\n", __func__, __LINE__); goto ic_init_err; } msleep(20); err = mdfld_dsi_send_mcs_short_hs(sender, set_tear_on, 0x00, 1, MDFLD_DSI_SEND_PACKAGE); if (err) { DRM_ERROR("%s: %d: Set Tear On\n", __func__, __LINE__); goto ic_init_err; } err = mdfld_dsi_send_mcs_long_hs(sender, jdi_mcs_clumn_addr, 5, MDFLD_DSI_SEND_PACKAGE); if (err) { DRM_ERROR("%s: %d: Set Clumn Address\n", __func__, __LINE__); goto ic_init_err; } err = mdfld_dsi_send_mcs_long_hs(sender, jdi_mcs_page_addr, 5, MDFLD_DSI_SEND_PACKAGE); if (err) { DRM_ERROR("%s: %d: Set Page Address\n", __func__, __LINE__); goto ic_init_err; } return 0; ic_init_err: err = -EIO; return err; }
static void jdi_cmd_controller_init( struct mdfld_dsi_config *dsi_config) { struct mdfld_dsi_hw_context *hw_ctx = &dsi_config->dsi_hw_context; #ifdef ENABLE_CSC_GAMMA /*FIXME*/ struct drm_device *dev = dsi_config->dev; struct csc_setting csc = { .pipe = 0, .type = CSC_REG_SETTING, .enable_state = true, .data_len = CSC_REG_COUNT, .data.csc_reg_data = { 0xFFB0424, 0xFDF, 0x4320FF1, 0xFDC, 0xFF50FF5, 0x415} }; struct gamma_setting gamma = { .pipe = 0, .type = GAMMA_REG_SETTING, .enable_state = true, .data_len = GAMMA_10_BIT_TABLE_COUNT, .gamma_tableX100 = { 0x000000, 0x030303, 0x050505, 0x070707, 0x090909, 0x0C0C0C, 0x0E0E0E, 0x101010, 0x121212, 0x141414, 0x171717, 0x191919, 0x1B1B1B, 0x1D1D1D, 0x1F1F1F, 0x212121, 0x232323, 0x252525, 0x282828, 0x2A2A2A, 0x2C2C2C, 0x2E2E2E, 0x303030, 0x323232, 0x343434, 0x363636, 0x383838, 0x3A3A3A, 0x3C3C3C, 0x3E3E3E, 0x404040, 0x424242, 0x444444, 0x464646, 0x484848, 0x4A4A4A, 0x4C4C4C, 0x4E4E4E, 0x505050, 0x525252, 0x545454, 0x565656, 0x585858, 0x5A5A5A, 0x5C5C5C, 0x5E5E5E, 0x606060, 0x626262, 0x646464, 0x666666, 0x686868, 0x6A6A6A, 0x6C6C6C, 0x6E6E6E, 0x707070, 0x727272, 0x747474, 0x767676, 0x787878, 0x7A7A7A, 0x7C7C7C, 0x7E7E7E, 0x808080, 0x828282, 0x848484, 0x868686, 0x888888, 0x8A8A8A, 0x8C8C8C, 0x8E8E8E, 0x909090, 0x929292, 0x949494, 0x969696, 0x989898, 0x999999, 0x9B9B9B, 0x9D9D9D, 0x9F9F9F, 0xA1A1A1, 0xA3A3A3, 0xA5A5A5, 0xA7A7A7, 0xA9A9A9, 0xABABAB, 0xADADAD, 0xAFAFAF, 0xB1B1B1, 0xB3B3B3, 0xB5B5B5, 0xB6B6B6, 0xB8B8B8, 0xBABABA, 0xBCBCBC, 0xBEBEBE, 0xC0C0C0, 0xC2C2C2, 0xC4C4C4, 0xC6C6C6, 0xC8C8C8, 0xCACACA, 0xCCCCCC, 0xCECECE, 0xCFCFCF, 0xD1D1D1, 0xD3D3D3, 0xD5D5D5, 0xD7D7D7, 0xD9D9D9, 0xDBDBDB, 0xDDDDDD, 0xDFDFDF, 0xE1E1E1, 0xE3E3E3, 0xE4E4E4, 0xE6E6E6, 0xE8E8E8, 0xEAEAEA, 0xECECEC, 0xEEEEEE, 0xF0F0F0, 0xF2F2F2, 0xF4F4F4, 0xF6F6F6, 0xF7F7F7, 0xF9F9F9, 0xFBFBFB, 0xFDFDFD} }; #endif PSB_DEBUG_ENTRY("\n"); /*reconfig lane configuration*/ dsi_config->lane_count = 3; dsi_config->lane_config = MDFLD_DSI_DATA_LANE_4_0; /* FIXME: enable CSC and GAMMA */ /*dsi_config->enable_gamma_csc = ENABLE_GAMMA | ENABLE_CSC;*/ /* This is for 400 mhz. Set it to 0 for 800mhz */ hw_ctx->cck_div = 1; hw_ctx->pll_bypass_mode = 0; if (IS_ANN(dev)) { hw_ctx->mipi_control = 0x18; hw_ctx->intr_en = 0xFFFFFFFF; hw_ctx->hs_tx_timeout = 0xFFFFFF; hw_ctx->lp_rx_timeout = 0xFFFFFF; hw_ctx->device_reset_timer = 0xff; hw_ctx->turn_around_timeout = 0xffff; hw_ctx->high_low_switch_count = 0x20; hw_ctx->clk_lane_switch_time_cnt = 0x21000e; hw_ctx->lp_byteclk = 0x4; hw_ctx->dphy_param = 0x1b104315; hw_ctx->eot_disable = 0x1; hw_ctx->init_count = 0x7d0; hw_ctx->dbi_bw_ctrl = 1390; hw_ctx->hs_ls_dbi_enable = 0x0; hw_ctx->dsi_func_prg = ((DBI_DATA_WIDTH_OPT2 << 13) | dsi_config->lane_count); hw_ctx->mipi = SEL_FLOPPED_HSTX | PASS_FROM_SPHY_TO_AFE | BANDGAP_CHICKEN_BIT | TE_TRIGGER_GPIO_PIN; } else { hw_ctx->mipi_control = 0x0; hw_ctx->intr_en = 0xFFFFFFFF; hw_ctx->hs_tx_timeout = 0xFFFFFF; hw_ctx->lp_rx_timeout = 0xFFFFFF; hw_ctx->device_reset_timer = 0xffff; hw_ctx->turn_around_timeout = 0x1a; hw_ctx->high_low_switch_count = 0x21; hw_ctx->clk_lane_switch_time_cnt = 0x21000f; hw_ctx->lp_byteclk = 0x5; hw_ctx->dphy_param = 0x25155b1e; hw_ctx->eot_disable = 0x3; hw_ctx->init_count = 0xf0; hw_ctx->dbi_bw_ctrl = 1390; hw_ctx->hs_ls_dbi_enable = 0x0; hw_ctx->dsi_func_prg = ((DBI_DATA_WIDTH_OPT2 << 13) | dsi_config->lane_count); hw_ctx->mipi = PASS_FROM_SPHY_TO_AFE | BANDGAP_CHICKEN_BIT | TE_TRIGGER_GPIO_PIN; } hw_ctx->video_mode_format = 0xf; #ifdef ENABLE_CSC_GAMMA /*FIXME*/ if (dsi_config->enable_gamma_csc & ENABLE_CSC) { /* setting the tuned csc setting */ drm_psb_enable_color_conversion = 1; mdfld_intel_crtc_set_color_conversion(dev, &csc); } if (dsi_config->enable_gamma_csc & ENABLE_GAMMA) { /* setting the tuned gamma setting */ drm_psb_enable_gamma = 1; mdfld_intel_crtc_set_gamma(dev, &gamma); } #endif } static int jdi_cmd_panel_connection_detect( struct mdfld_dsi_config *dsi_config) { int status; int pipe = dsi_config->pipe; PSB_DEBUG_ENTRY("\n"); if (pipe == 0) { status = MDFLD_DSI_PANEL_CONNECTED; } else { DRM_INFO("%s: do NOT support dual panel\n", __func__); status = MDFLD_DSI_PANEL_DISCONNECTED; } return status; } static int jdi_cmd_power_on( struct mdfld_dsi_config *dsi_config) { struct mdfld_dsi_pkg_sender *sender = mdfld_dsi_get_pkg_sender(dsi_config); int err = 0; PSB_DEBUG_ENTRY("\n"); if (!sender) { DRM_ERROR("Failed to get DSI packet sender\n"); return -EINVAL; } err = mdfld_dsi_send_mcs_short_hs(sender, set_address_mode, 0x0, 1, MDFLD_DSI_SEND_PACKAGE); if (err) { DRM_ERROR("%s: %d: Set Address Mode\n", __func__, __LINE__); goto power_err; } usleep_range(20000, 20100); err = mdfld_dsi_send_mcs_short_hs(sender, set_pixel_format, 0x77, 1, MDFLD_DSI_SEND_PACKAGE); if (err) { DRM_ERROR("%s: %d: Set Pixel format\n", __func__, __LINE__); goto power_err; } /*turn on display*/ err = mdfld_dsi_send_dcs(sender, set_display_on, NULL, 0, CMD_DATA_SRC_SYSTEM_MEM, MDFLD_DSI_SEND_PACKAGE); if (err) { DRM_ERROR("faild to set_display_on mode\n"); goto power_err; } usleep_range(20000, 20100); power_err: return err; } static void __vpro2_power_ctrl(bool on) { u8 addr, value; addr = 0xad; if (intel_scu_ipc_ioread8(addr, &value)) DRM_ERROR("%s: %d: failed to read vPro2\n", __func__, __LINE__); /* Control vPROG2 power rail with 2.85v. */ if (on) value |= 0x1; else value &= ~0x1; if (intel_scu_ipc_iowrite8(addr, value)) DRM_ERROR("%s: %d: failed to write vPro2\n", __func__, __LINE__); }
bool enable_DSIPLL(struct drm_device *dev) { DRM_DRIVER_PRIVATE_T *dev_priv = dev->dev_private; struct mdfld_dsi_config *dsi_config = NULL; struct mdfld_dsi_hw_context *ctx = NULL; u32 guit_val = 0x0; u32 retry; if (!dev_priv) goto err_out; dsi_config = dev_priv->dsi_configs[0]; if (!dsi_config) goto err_out; ctx = &dsi_config->dsi_hw_context; if (IS_ANN(dev)) { int dspfreq; if ((get_panel_type(dev, 0) == JDI_7x12_CMD) || (get_panel_type(dev, 0) == JDI_7x12_VID)) dspfreq = DISPLAY_FREQ_FOR_200; else dspfreq = DISPLAY_FREQ_FOR_333; intel_mid_msgbus_write32(CCK_PORT, FUSE_OVERRIDE_FREQ_CNTRL_REG5, CKESC_GATE_EN | CKDP1X_GATE_EN | DISPLAY_FRE_EN | dspfreq); } /* Prepare DSI PLL register before enabling */ intel_mid_msgbus_write32(CCK_PORT, DSI_PLL_DIV_REG, 0); guit_val = intel_mid_msgbus_read32(CCK_PORT, DSI_PLL_CTRL_REG); guit_val &= ~(DPLL_VCO_ENABLE | _DSI_LDO_EN |_CLK_EN_MASK | _DSI_MUX_SEL_CCK_DSI0 | _DSI_MUX_SEL_CCK_DSI1); intel_mid_msgbus_write32(CCK_PORT, DSI_PLL_CTRL_REG, guit_val); udelay(1); /* Program PLL */ /*first set up the dpll and fp variables * dpll - will contain the following information * - the clock source - DSI vs HFH vs LFH PLL * - what clocks should be running DSI0, DSI1 * - and the divisor. * */ intel_mid_msgbus_write32(CCK_PORT, DSI_PLL_DIV_REG, ctx->fp); guit_val &= ~_P1_POST_DIV_MASK; /*clear the divisor bit*/ /* the ctx->dpll contains the divisor that we need to use as well as which clocks * need to start up */ guit_val |= ctx->dpll; guit_val &= ~_DSI_LDO_EN; /* We want to clear the LDO enable when programming*/ guit_val |= DPLL_VCO_ENABLE; /* Enable the DSI PLL */ /* For the CD clock (clock used by Display controller), we need to set * the DSI_CCK_PLL_SELECT bit (bit 11). This should already be set. But * setting it just in case */ if (dev_priv->bUseHFPLL) guit_val |= _DSI_CCK_PLL_SELECT; intel_mid_msgbus_write32(CCK_PORT, DSI_PLL_CTRL_REG, guit_val); /* Wait for DSI PLL lock */ retry = 10000; guit_val = intel_mid_msgbus_read32(CCK_PORT, DSI_PLL_CTRL_REG); while (((guit_val & _DSI_PLL_LOCK) != _DSI_PLL_LOCK) && (--retry)) { udelay(3); guit_val = intel_mid_msgbus_read32(CCK_PORT, DSI_PLL_CTRL_REG); if (!retry%1000) DRM_ERROR("DSI PLL taking too long to lock" "- retry count=%d\n", 10000-retry); } if (retry == 0) { DRM_ERROR("DSI PLL fails to lock\n"); return false; } return true; err_out: return false; }
/** * Setup Display Controller to turn on/off a video mode panel. * Most of the video mode MIPI panel should follow the power on/off * sequence in this function. * NOTE: do NOT modify this function for new panel Enabling. Register * new panel function callbacks to make this function available for a * new video mode panel */ static int __mdfld_dsi_dpi_set_power(struct drm_encoder *encoder, bool on) { struct mdfld_dsi_encoder *dsi_encoder; struct mdfld_dsi_connector *dsi_connector; struct mdfld_dsi_dpi_output *dpi_output; struct mdfld_dsi_config *dsi_config; struct panel_funcs *p_funcs; int pipe; struct drm_device *dev; struct drm_psb_private *dev_priv; if (!encoder) { DRM_ERROR("Invalid encoder\n"); return -EINVAL; } dsi_encoder = MDFLD_DSI_ENCODER(encoder); dpi_output = MDFLD_DSI_DPI_OUTPUT(dsi_encoder); dsi_config = mdfld_dsi_encoder_get_config(dsi_encoder); p_funcs = dpi_output->p_funcs; pipe = mdfld_dsi_encoder_get_pipe(dsi_encoder); dsi_connector = mdfld_dsi_encoder_get_connector(dsi_encoder); if (!dsi_connector) { DRM_ERROR("dsi_connector is NULL\n"); return -EINVAL; } dev = dsi_config->dev; dev_priv = dev->dev_private; if (dsi_connector->status != connector_status_connected) return 0; mutex_lock(&dsi_config->context_lock); if (dpi_output->first_boot && on) { if (dsi_config->dsi_hw_context.panel_on) { if (IS_ANN(dev)) ann_dc_setup(dsi_config); psb_enable_vblank(dev, dsi_config->pipe); /* don't need ISLAND c for non dual-dsi panel */ if (!is_dual_dsi(dev)) power_island_put(OSPM_DISPLAY_C); DRM_INFO("skip panle power setting for first boot! " "panel is already powered on\n"); goto fun_exit; } if (android_hdmi_is_connected(dev)) otm_hdmi_power_islands_off(); /* power down islands turned on by firmware */ power_island_put(OSPM_DISPLAY_A | OSPM_DISPLAY_C | OSPM_DISPLAY_MIO); } switch (on) { case true: /* panel is already on */ if (dsi_config->dsi_hw_context.panel_on) goto fun_exit; if (__dpi_panel_power_on(dsi_config, p_funcs, dpi_output->first_boot)) { DRM_ERROR("Faild to turn on panel\n"); goto set_power_err; } dsi_config->dsi_hw_context.panel_on = 1; /* for every dpi panel power on, clear the dpi underrun count */ dev_priv->pipea_dpi_underrun_count = 0; dev_priv->pipec_dpi_underrun_count = 0; break; case false: if (!dsi_config->dsi_hw_context.panel_on && !dpi_output->first_boot) goto fun_exit; if (__dpi_panel_power_off(dsi_config, p_funcs)) { DRM_ERROR("Faild to turn off panel\n"); goto set_power_err; } dsi_config->dsi_hw_context.panel_on = 0; break; default: break; } fun_exit: mutex_unlock(&dsi_config->context_lock); PSB_DEBUG_ENTRY("successfully\n"); return 0; set_power_err: mutex_unlock(&dsi_config->context_lock); PSB_DEBUG_ENTRY("unsuccessfully!!!!\n"); return -EAGAIN; }
/** * Power on sequence for video mode MIPI panel. * NOTE: do NOT modify this function */ static int __dpi_panel_power_on(struct mdfld_dsi_config *dsi_config, struct panel_funcs *p_funcs, bool first_boot) { u32 val = 0; struct mdfld_dsi_hw_registers *regs; struct mdfld_dsi_hw_context *ctx; struct drm_psb_private *dev_priv; struct drm_device *dev; int retry, reset_count = 10; int i; int err = 0; u32 power_island = 0; int offset = 0; PSB_DEBUG_ENTRY("\n"); if (!dsi_config) return -EINVAL; regs = &dsi_config->regs; ctx = &dsi_config->dsi_hw_context; dev = dsi_config->dev; dev_priv = dev->dev_private; power_island = pipe_to_island(dsi_config->pipe); if (power_island & (OSPM_DISPLAY_A | OSPM_DISPLAY_C)) power_island |= OSPM_DISPLAY_MIO; if (is_dual_dsi(dev)) power_island |= OSPM_DISPLAY_C; if (!power_island_get(power_island)) return -EAGAIN; if (android_hdmi_is_connected(dev) && first_boot) otm_hdmi_power_islands_on(); reset_recovery: --reset_count; /*HW-Reset*/ if (p_funcs && p_funcs->reset) p_funcs->reset(dsi_config); /* * Wait for DSI PLL locked on pipe, and only need to poll status of pipe * A as both MIPI pipes share the same DSI PLL. */ if (dsi_config->pipe == 0) { retry = 20000; while (!(REG_READ(regs->pipeconf_reg) & PIPECONF_DSIPLL_LOCK) && --retry) udelay(150); if (!retry) { DRM_ERROR("PLL failed to lock on pipe\n"); err = -EAGAIN; goto power_on_err; } } if (IS_ANN(dev)) { /* FIXME: reset the DC registers for ANN A0 */ ann_dc_setup(dsi_config); } __dpi_set_properties(dsi_config, PORT_A); /* update 0x650c[0] = 1 to fixed arbitration pattern * it is found display TLB request be blocked by display plane * memory requests, never goes out. This causes display controller * uses stale TLB data to do memory translation, getting wrong * memory address for data, and causing the flickering issue. */ REG_WRITE(GCI_CTRL, REG_READ(GCI_CTRL) | 1); /*Setup pipe timing*/ REG_WRITE(regs->htotal_reg, ctx->htotal); REG_WRITE(regs->hblank_reg, ctx->hblank); REG_WRITE(regs->hsync_reg, ctx->hsync); REG_WRITE(regs->vtotal_reg, ctx->vtotal); REG_WRITE(regs->vblank_reg, ctx->vblank); REG_WRITE(regs->vsync_reg, ctx->vsync); REG_WRITE(regs->pipesrc_reg, ctx->pipesrc); REG_WRITE(regs->dsppos_reg, ctx->dsppos); REG_WRITE(regs->dspstride_reg, ctx->dspstride); /*Setup plane*/ REG_WRITE(regs->dspsize_reg, ctx->dspsize); REG_WRITE(regs->dspsurf_reg, ctx->dspsurf); REG_WRITE(regs->dsplinoff_reg, ctx->dsplinoff); REG_WRITE(regs->vgacntr_reg, ctx->vgacntr); /*restore color_coef (chrome) */ for (i = 0; i < 6; i++) REG_WRITE(regs->color_coef_reg + (i<<2), csc_setting_save[i]); /* restore palette (gamma) */ for (i = 0; i < 256; i++) REG_WRITE(regs->palette_reg + (i<<2), gamma_setting_save[i]); /* restore dpst setting */ if (dev_priv->psb_dpst_state) { dpstmgr_reg_restore_locked(dev, dsi_config); psb_enable_pipestat(dev_priv, 0, PIPE_DPST_EVENT_ENABLE); } if (__dpi_config_port(dsi_config, p_funcs, PORT_A) != 0) { if (!reset_count) { err = -EAGAIN; goto power_on_err; } DRM_ERROR("Failed to init dsi controller, reset it!\n"); goto reset_recovery; } if (is_dual_dsi(dev)) { __dpi_set_properties(dsi_config, PORT_C); __dpi_config_port(dsi_config, p_funcs, PORT_C); } /** * Different panel may have different ways to have * drvIC initialized. Support it! */ if (p_funcs && p_funcs->drv_ic_init) { if (p_funcs->drv_ic_init(dsi_config)) { if (!reset_count) { err = -EAGAIN; goto power_on_err; } DRM_ERROR("Failed to init dsi controller, reset it!\n"); goto reset_recovery; } } /*Enable MIPI Port A*/ offset = 0x0; REG_WRITE(regs->mipi_reg + offset, (ctx->mipi | BIT31)); REG_WRITE(regs->dpi_control_reg + offset, BIT1); if (is_dual_dsi(dev)) { /*Enable MIPI Port C*/ offset = 0x1000; REG_WRITE(regs->mipi_reg + offset, (ctx->mipi | BIT31)); offset = 0x800; REG_WRITE(regs->dpi_control_reg + offset, BIT1); } /** * Different panel may have different ways to have * panel turned on. Support it! */ if (p_funcs && p_funcs->power_on) if (p_funcs->power_on(dsi_config)) { DRM_ERROR("Failed to power on panel\n"); err = -EAGAIN; goto power_on_err; } if (IS_ANN(dev)) { REG_WRITE(regs->ddl1_reg, ctx->ddl1); REG_WRITE(regs->ddl2_reg, ctx->ddl2); REG_WRITE(regs->ddl3_reg, ctx->ddl3); REG_WRITE(regs->ddl4_reg, ctx->ddl4); REG_WRITE(DSPARB2, ctx->dsparb2); REG_WRITE(DSPARB, ctx->dsparb); } /*Enable pipe*/ val = ctx->pipeconf; val &= ~0x000c0000; /** * Frame Start occurs on third HBLANK * after the start of VBLANK */ val |= BIT31 | BIT28; REG_WRITE(regs->pipeconf_reg, val); /*Wait for pipe enabling,when timing generator is wroking */ if (REG_READ(regs->mipi_reg) & BIT31) { retry = 10000; while (--retry && !(REG_READ(regs->pipeconf_reg) & BIT30)) udelay(3); if (!retry) { DRM_ERROR("Failed to enable pipe\n"); err = -EAGAIN; goto power_on_err; } } /*enable plane*/ val = ctx->dspcntr | BIT31; REG_WRITE(regs->dspcntr_reg, val); if (p_funcs && p_funcs->set_brightness) { if (p_funcs->set_brightness(dsi_config, ctx->lastbrightnesslevel)) DRM_ERROR("Failed to set panel brightness\n"); } else { DRM_ERROR("Failed to set panel brightness\n"); } if (p_funcs && p_funcs->drv_set_panel_mode) p_funcs->drv_set_panel_mode(dsi_config); psb_enable_vblank(dev, dsi_config->pipe); return err; power_on_err: power_island_put(power_island); return err; }
static void intel_dsi_dbi_update_fb(struct mdfld_dsi_dbi_output *dbi_output) { struct mdfld_dsi_pkg_sender *sender; struct drm_device *dev = dbi_output->dev; struct drm_crtc *crtc = dbi_output->base.base.crtc; struct psb_intel_crtc *psb_crtc = (crtc) ? to_psb_intel_crtc(crtc) : NULL; int pipe = dbi_output->channel_num ? 2 : 0; u32 dpll_reg = MRST_DPLL_A; u32 dspcntr_reg = DSPACNTR; u32 pipeconf_reg = PIPEACONF; u32 dsplinoff_reg = DSPALINOFF; u32 dspsurf_reg = DSPASURF; sender = mdfld_dsi_encoder_get_pkg_sender(&dbi_output->base); if (!sender) { DRM_ERROR("pkg sender is NULL\n"); return; } /* if mode setting on-going, back off */ if (!IS_ANN(dev)) { if ((dbi_output->mode_flags & MODE_SETTING_ON_GOING) || (psb_crtc && (psb_crtc->mode_flags & MODE_SETTING_ON_GOING)) || !(dbi_output->mode_flags & MODE_SETTING_ENCODER_DONE)) return; } if (pipe == 2) { dspcntr_reg = DSPCCNTR; pipeconf_reg = PIPECCONF; dsplinoff_reg = DSPCLINOFF; dspsurf_reg = DSPCSURF; } /* check DBI FIFO status */ if (is_panel_vid_or_cmd(dev) == MDFLD_DSI_ENCODER_DBI) { if (!(REG_READ(dspcntr_reg) & DISPLAY_PLANE_ENABLE) || !(REG_READ(pipeconf_reg) & DISPLAY_PLANE_ENABLE)) return; } else if (!(REG_READ(dpll_reg) & DPLL_VCO_ENABLE) || !(REG_READ(dspcntr_reg) & DISPLAY_PLANE_ENABLE) || !(REG_READ(pipeconf_reg) & DISPLAY_PLANE_ENABLE)) return; if (!IS_ANN(dev)) { /* refresh plane changes */ REG_WRITE(dsplinoff_reg, REG_READ(dsplinoff_reg)); REG_WRITE(dspsurf_reg, REG_READ(dspsurf_reg)); REG_READ(dspsurf_reg); } mdfld_dsi_send_dcs(sender, write_mem_start, NULL, 0, CMD_DATA_SRC_PIPE, MDFLD_DSI_SEND_PACKAGE); dbi_output->dsr_fb_update_done = true; mdfld_dsi_cmds_kick_out(sender); }
/** * Power on sequence for command mode MIPI panel. * NOTE: do NOT modify this function */ static int __dbi_panel_power_on(struct mdfld_dsi_config *dsi_config, struct panel_funcs *p_funcs) { struct mdfld_dsi_hw_registers *regs; struct mdfld_dsi_hw_context *ctx; struct drm_psb_private *dev_priv; struct drm_device *dev; int reset_count = 10; int err = 0; struct mdfld_dsi_pkg_sender *sender = mdfld_dsi_get_pkg_sender(dsi_config); struct mdfld_dbi_dsr_info *dsr_info; struct mdfld_dsi_dbi_output **dbi_outputs; struct mdfld_dsi_dbi_output *dbi_output; if (!sender) { DRM_ERROR("pkg sender is NULL\n"); return -EINVAL; } PSB_DEBUG_ENTRY("\n"); if (!dsi_config) return -EINVAL; regs = &dsi_config->regs; ctx = &dsi_config->dsi_hw_context; dev = dsi_config->dev; dev_priv = dev->dev_private; mdfld_dsi_dsr_forbid_locked(dsi_config); reset_recovery: --reset_count; err = 0; /*after entering dstb mode, need reset*/ if (p_funcs && p_funcs->exit_deep_standby) p_funcs->exit_deep_standby(dsi_config); if (__dbi_power_on(dsi_config)) { DRM_ERROR("Failed to init display controller!\n"); err = -EAGAIN; goto power_on_err; } /** * Different panel may have different ways to have * drvIC initialized. Support it! */ if (p_funcs && p_funcs->drv_ic_init) { if (p_funcs->drv_ic_init(dsi_config)) { DRM_ERROR("Failed to init dsi controller!\n"); err = -EAGAIN; goto power_on_err; } } /* Issue "write_mem_start" DSI command during power on. */ dsr_info = dev_priv->dbi_dsr_info; dbi_outputs = dsr_info->dbi_outputs; dbi_output = dsi_config->pipe ? dbi_outputs[1] : dbi_outputs[0]; if (!IS_ANN(dev)) intel_dsi_dbi_update_fb(dbi_output); /** * Different panel may have different ways to have * panel turned on. Support it! */ if (p_funcs && p_funcs->power_on) if (p_funcs->power_on(dsi_config)) { DRM_ERROR("Failed to power on panel\n"); err = -EAGAIN; goto power_on_err; } if (p_funcs && p_funcs->set_brightness) if (p_funcs->set_brightness(dsi_config, ctx->lastbrightnesslevel)) DRM_ERROR("Failed to set panel brightness\n"); if (p_funcs && p_funcs->drv_set_panel_mode) p_funcs->drv_set_panel_mode(dsi_config); /*wait for all FIFOs empty*/ mdfld_dsi_wait_for_fifos_empty(sender); if (is_dual_dsi(dev)) { sender->work_for_slave_panel = true; mdfld_dsi_wait_for_fifos_empty(sender); sender->work_for_slave_panel = false; } if (IS_ANN(dev)) intel_dsi_dbi_update_fb(dbi_output); power_on_err: if (err && reset_count) { DRM_ERROR("Failed to init panel, try reset it again!\n"); goto reset_recovery; } mdfld_dsi_dsr_allow_locked(dsi_config); return err; }
/* dbi interface power on*/ int __dbi_power_on(struct mdfld_dsi_config *dsi_config) { u32 val = 0; struct mdfld_dsi_hw_registers *regs; struct mdfld_dsi_hw_context *ctx; struct drm_psb_private *dev_priv; struct drm_device *dev; int retry; int err = 0; u32 power_island = 0; u32 sprite_reg_offset = 0; int i = 0; int offset = 0; PSB_DEBUG_ENTRY("\n"); if (!dsi_config) return -EINVAL; regs = &dsi_config->regs; ctx = &dsi_config->dsi_hw_context; dev = dsi_config->dev; dev_priv = dev->dev_private; power_island = pipe_to_island(dsi_config->pipe); if (power_island & (OSPM_DISPLAY_A | OSPM_DISPLAY_C)) power_island |= OSPM_DISPLAY_MIO; if (is_dual_dsi(dev)) power_island |= OSPM_DISPLAY_C; if (!power_island_get(power_island)) return -EAGAIN; /* * Wait for DSI PLL locked on pipe, and only need to poll status of pipe * A as both MIPI pipes share the same DSI PLL. */ if (dsi_config->pipe == 0) { retry = 20000; while (!(REG_READ(regs->pipeconf_reg) & PIPECONF_DSIPLL_LOCK) && --retry) udelay(150); if (!retry) { DRM_ERROR("PLL failed to lock on pipe\n"); err = -EAGAIN; goto power_on_err; } } if (IS_ANN(dev)) { /* FIXME: reset the DC registers for ANN A0 */ power_island_get(OSPM_DISPLAY_B | OSPM_DISPLAY_C); REG_WRITE(DSPCLK_GATE_D, 0x0); REG_WRITE(RAMCLK_GATE_D, 0xc0000 | (1 << 11)); // FIXME: delay 1us for RDB done signal REG_WRITE(PFIT_CONTROL, 0x20000000); REG_WRITE(DSPIEDCFGSHDW, 0x0); REG_WRITE(DSPARB2, 0x000A0200); REG_WRITE(DSPARB, 0x18040080); REG_WRITE(DSPFW1, 0x0F0F3F3F); REG_WRITE(DSPFW2, 0x5F2F0F3F); REG_WRITE(DSPFW3, 0x0); REG_WRITE(DSPFW4, 0x07071F1F); REG_WRITE(DSPFW5, 0x2F17071F); REG_WRITE(DSPFW6, 0x00001F3F); REG_WRITE(DSPFW7, 0x1F3F1F3F); REG_WRITE(DSPSRCTRL, 0x00080100); REG_WRITE(DSPCHICKENBIT, 0x20); REG_WRITE(FBDC_CHICKEN, 0x0C0C0C0C); REG_WRITE(CURACNTR, 0x0); REG_WRITE(CURBCNTR, 0x0); REG_WRITE(CURCCNTR, 0x0); REG_WRITE(IEP_OVA_CTRL, 0x0); REG_WRITE(IEP_OVA_CTRL, 0x0); REG_WRITE(DSPACNTR, 0x0); REG_WRITE(DSPBCNTR, 0x0); REG_WRITE(DSPCCNTR, 0x0); REG_WRITE(DSPDCNTR, 0x0); REG_WRITE(DSPECNTR, 0x0); REG_WRITE(DSPFCNTR, 0x0); power_island_put(OSPM_DISPLAY_B | OSPM_DISPLAY_C); } /*exit ULPS*/ if (__dbi_exit_ulps_locked(dsi_config, 0)) { DRM_ERROR("Failed to exit ULPS\n"); goto power_on_err; } /*update MIPI port config*/ REG_WRITE(regs->mipi_reg, ctx->mipi | REG_READ(regs->mipi_reg)); /*unready dsi adapter for re-programming*/ REG_WRITE(regs->device_ready_reg, REG_READ(regs->device_ready_reg) & ~(DSI_DEVICE_READY)); if (is_dual_dsi(dev)) { if (__dbi_exit_ulps_locked(dsi_config, 0x800)) { DRM_ERROR("Failed to exit ULPS\n"); goto power_on_err; } offset = 0x1000; REG_WRITE(regs->mipi_reg + offset, ctx->mipi | REG_READ(regs->mipi_reg + offset)); /*unready dsi adapter for re-programming*/ offset = 0x800; REG_WRITE(regs->device_ready_reg + offset, REG_READ(regs->device_ready_reg + offset) & ~(DSI_DEVICE_READY)); } /* * According to MIPI D-PHY spec, if clock stop feature is enabled (EOT * Disable), un-ready MIPI adapter needs to wait for 20 cycles from HS * to LP mode. Per calculation 1us is enough. */ if (ctx->eot_disable & CLOCK_STOP) udelay(1); __dbi_set_properties(dsi_config, PORT_A); /* update 0x650c[0] = 1 to fixed arbitration pattern * it is found display TLB request be blocked by display plane * memory requests, never goes out. This causes display controller * uses stale TLB data to do memory translation, getting wrong * memory address for data, and causing the flickering issue. */ REG_WRITE(GCI_CTRL, REG_READ(GCI_CTRL) | 1); /*Setup pipe timing*/ REG_WRITE(regs->htotal_reg, ctx->htotal); REG_WRITE(regs->hblank_reg, ctx->hblank); REG_WRITE(regs->hsync_reg, ctx->hsync); REG_WRITE(regs->vtotal_reg, ctx->vtotal); REG_WRITE(regs->vblank_reg, ctx->vblank); REG_WRITE(regs->vsync_reg, ctx->vsync); REG_WRITE(regs->pipesrc_reg, ctx->pipesrc); REG_WRITE(regs->dsppos_reg, ctx->dsppos); REG_WRITE(regs->dspstride_reg, ctx->dspstride); /*restore color_coef (chrome) */ for (i = 0; i < 6; i++) REG_WRITE(regs->color_coef_reg + (i<<2), csc_setting_save[i]); /* restore palette (gamma) */ for (i = 0; i < 256; i++) REG_WRITE(regs->palette_reg + (i<<2), gamma_setting_save[i]); /* restore dpst setting */ if (dev_priv->psb_dpst_state) { dpstmgr_reg_restore_locked(dev, dsi_config); psb_enable_pipestat(dev_priv, 0, PIPE_DPST_EVENT_ENABLE); } /*Setup plane*/ REG_WRITE(regs->dspsize_reg, ctx->dspsize); REG_WRITE(regs->dspsurf_reg, ctx->dspsurf); REG_WRITE(regs->dsplinoff_reg, ctx->dsplinoff); REG_WRITE(regs->vgacntr_reg, ctx->vgacntr); if (is_dual_dsi(dev)) __dbi_set_properties(dsi_config, PORT_C); /*enable plane*/ val = ctx->dspcntr | BIT31; REG_WRITE(regs->dspcntr_reg, val); if (ctx->sprite_dspcntr & BIT31) { if (dsi_config->pipe == 0) sprite_reg_offset = 0x3000; else if (dsi_config->pipe == 2) sprite_reg_offset = 0x1000; /* Set up Sprite Plane */ REG_WRITE(regs->dspsize_reg + sprite_reg_offset, ctx->sprite_dspsize); REG_WRITE(regs->dspsurf_reg + sprite_reg_offset, ctx->sprite_dspsurf); REG_WRITE(regs->dsplinoff_reg + sprite_reg_offset, ctx->sprite_dsplinoff); REG_WRITE(regs->dsppos_reg + sprite_reg_offset, ctx->sprite_dsppos); REG_WRITE(regs->dspstride_reg + sprite_reg_offset, ctx->sprite_dspstride); /* enable plane */ REG_WRITE(regs->dspcntr_reg + sprite_reg_offset, ctx->sprite_dspcntr); } /* Set up Overlay Plane */ if (ctx->ovaadd) PSB_WVDC32(ctx->ovaadd, OV_OVADD); if (ctx->ovcadd) PSB_WVDC32(ctx->ovcadd, OVC_OVADD); /*ready dsi adapter*/ REG_WRITE(regs->device_ready_reg, REG_READ(regs->device_ready_reg) | DSI_DEVICE_READY); mdelay(1); if (is_dual_dsi(dev)) { REG_WRITE(regs->device_ready_reg + offset, REG_READ(regs->device_ready_reg + offset) | DSI_DEVICE_READY); } if (IS_ANN(dev)) { REG_WRITE(regs->ddl1_reg, ctx->ddl1); REG_WRITE(regs->ddl2_reg, ctx->ddl2); REG_WRITE(regs->ddl3_reg, ctx->ddl3); REG_WRITE(regs->ddl4_reg, ctx->ddl4); REG_WRITE(DSPARB2, ctx->dsparb2); REG_WRITE(DSPARB, ctx->dsparb); } /*Enable pipe*/ val = ctx->pipeconf; val &= ~0x000c0000; val |= BIT31 | PIPEACONF_DSR; REG_WRITE(regs->pipeconf_reg, val); /*Wait for pipe enabling,when timing generator is working */ retry = 10000; while (--retry && !(REG_READ(regs->pipeconf_reg) & BIT30)) udelay(3); if (!retry) { DRM_ERROR("Failed to enable pipe\n"); err = -EAGAIN; goto power_on_err; } /* * Enable TE to trigger "write_mem_start" issuing * in non-normal boot modes. */ mdfld_enable_te(dev, dsi_config->pipe); return err; power_on_err: power_island_put(power_island); return err; }