diff --git a/msm/dsi/dsi_ctrl.c b/msm/dsi/dsi_ctrl.c index 81eeaca187..f607fa7bc8 100644 --- a/msm/dsi/dsi_ctrl.c +++ b/msm/dsi/dsi_ctrl.c @@ -865,6 +865,7 @@ static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl, { int rc = 0; u32 num_of_lanes = 0; + u32 bits_per_symbol = 16, num_of_symbols = 7; /* For Cphy */ u32 bpp, frame_time_us, byte_intf_clk_div; u64 h_period, v_period, bit_rate, pclk_rate, bit_rate_per_lane, byte_clk_rate, byte_intf_clk_rate; @@ -895,6 +896,10 @@ static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl, if (config->bit_clk_rate_hz_override != 0) { bit_rate = config->bit_clk_rate_hz_override * num_of_lanes; + if (host_cfg->phy_type == DSI_PHY_TYPE_CPHY) { + bit_rate *= bits_per_symbol; + do_div(bit_rate, num_of_symbols); + } } else if (config->panel_mode == DSI_OP_CMD_MODE) { /* Calculate the bit rate needed to match dsi transfer time */ bit_rate = min_dsi_clk_hz * frame_time_us; @@ -906,16 +911,29 @@ static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl, bit_rate = h_period * v_period * timing->refresh_rate * bpp; } - bit_rate_per_lane = bit_rate; - do_div(bit_rate_per_lane, num_of_lanes); + pclk_rate = bit_rate; do_div(pclk_rate, bpp); - byte_clk_rate = bit_rate_per_lane; - do_div(byte_clk_rate, 8); - byte_intf_clk_rate = byte_clk_rate; - byte_intf_clk_div = host_cfg->byte_intf_clk_div; - do_div(byte_intf_clk_rate, byte_intf_clk_div); - + if (host_cfg->phy_type == DSI_PHY_TYPE_DPHY) { + bit_rate_per_lane = bit_rate; + do_div(bit_rate_per_lane, num_of_lanes); + byte_clk_rate = bit_rate_per_lane; + do_div(byte_clk_rate, 8); + byte_intf_clk_rate = byte_clk_rate; + byte_intf_clk_div = host_cfg->byte_intf_clk_div; + do_div(byte_intf_clk_rate, byte_intf_clk_div); + config->bit_clk_rate_hz = byte_clk_rate * 8; + } else { + do_div(bit_rate, bits_per_symbol); + bit_rate *= num_of_symbols; + bit_rate_per_lane = bit_rate; + do_div(bit_rate_per_lane, num_of_lanes); + byte_clk_rate = bit_rate_per_lane; + do_div(byte_clk_rate, 7); + /* For CPHY, byte_intf_clk is same as byte_clk */ + byte_intf_clk_rate = byte_clk_rate; + config->bit_clk_rate_hz = byte_clk_rate * 7; + } DSI_CTRL_DEBUG(dsi_ctrl, "bit_clk_rate = %llu, bit_clk_rate_per_lane = %llu\n", bit_rate, bit_rate_per_lane); DSI_CTRL_DEBUG(dsi_ctrl, "byte_clk_rate = %llu, byte_intf_clk = %llu\n", @@ -923,10 +941,9 @@ static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl, DSI_CTRL_DEBUG(dsi_ctrl, "pclk_rate = %llu\n", pclk_rate); dsi_ctrl->clk_freq.byte_clk_rate = byte_clk_rate; + dsi_ctrl->clk_freq.byte_intf_clk_rate = byte_intf_clk_rate; dsi_ctrl->clk_freq.pix_clk_rate = pclk_rate; dsi_ctrl->clk_freq.esc_clk_rate = config->esc_clk_rate_hz; - dsi_ctrl->clk_freq.byte_intf_clk_rate = byte_intf_clk_rate; - config->bit_clk_rate_hz = dsi_ctrl->clk_freq.byte_clk_rate * 8; rc = dsi_clk_set_link_frequencies(clk_handle, dsi_ctrl->clk_freq, dsi_ctrl->cell_index); diff --git a/msm/dsi/dsi_ctrl_hw_cmn.c b/msm/dsi/dsi_ctrl_hw_cmn.c index 340938e4f2..40b7a031aa 100644 --- a/msm/dsi/dsi_ctrl_hw_cmn.c +++ b/msm/dsi/dsi_ctrl_hw_cmn.c @@ -135,6 +135,9 @@ void dsi_ctrl_hw_cmn_host_setup(struct dsi_ctrl_hw *ctrl, DSI_W32(ctrl, DSI_CTRL, reg_value); + if (cfg->phy_type == DSI_PHY_TYPE_CPHY) + DSI_W32(ctrl, DSI_CPHY_MODE_CTRL, BIT(0)); + if (ctrl->phy_isolation_enabled) DSI_W32(ctrl, DSI_DEBUG_CTRL, BIT(28)); DSI_CTRL_HW_DBG(ctrl, "Host configuration complete\n"); diff --git a/msm/dsi/dsi_ctrl_reg.h b/msm/dsi/dsi_ctrl_reg.h index d27d4ffe24..bdc7b65fd4 100644 --- a/msm/dsi/dsi_ctrl_reg.h +++ b/msm/dsi/dsi_ctrl_reg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ #ifndef _DSI_CTRL_REG_H_ @@ -144,6 +144,7 @@ #define DSI_SECURE_DISPLAY_STATUS (0x02CC) #define DSI_SECURE_DISPLAY_BLOCK_COMMAND_COLOR (0x02D0) #define DSI_SECURE_DISPLAY_BLOCK_VIDEO_COLOR (0x02D4) +#define DSI_CPHY_MODE_CTRL (0x02D8) #define DSI_LOGICAL_LANE_SWAP_CTRL (0x0310) #define DSI_SPLIT_LINK (0x0330) diff --git a/msm/dsi/dsi_defs.h b/msm/dsi/dsi_defs.h index f8ebdc2a95..d54e9f8616 100644 --- a/msm/dsi/dsi_defs.h +++ b/msm/dsi/dsi_defs.h @@ -469,6 +469,7 @@ struct dsi_split_link_config { * true. * @ext_bridge_mode: External bridge is connected. * @force_hs_clk_lane: Send continuous clock to the panel. + * @phy_type: DPHY/CPHY is enabled for this panel. * @dsi_split_link_config: Split Link Configuration. * @byte_intf_clk_div: Determines the factor for calculating byte intf clock. */ @@ -493,6 +494,7 @@ struct dsi_host_common_cfg { bool append_tx_eot; bool ext_bridge_mode; bool force_hs_clk_lane; + enum dsi_phy_type phy_type; struct dsi_split_link_config split_link; u32 byte_intf_clk_div; }; diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index afba80ab63..31691ee015 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -2316,6 +2316,20 @@ static int dsi_display_set_clk_src(struct dsi_display *display) int i; struct dsi_display_ctrl *m_ctrl, *ctrl; + /* + * For CPHY mode, the parent of mux_clks need to be set + * to Cphy_clks to have correct dividers for byte and + * pixel clocks. + */ + if (display->panel->host_config.phy_type == DSI_PHY_TYPE_CPHY) { + rc = dsi_clk_update_parent(&display->clock_info.cphy_clks, + &display->clock_info.mux_clks); + if (rc) { + DSI_ERR("failed update mux parent to shadow\n"); + return rc; + } + } + /* * In case of split DSI usecases, the clock for master controller should * be enabled before the other controller. Master controller in the @@ -2382,8 +2396,12 @@ static void dsi_display_toggle_resync_fifo(struct dsi_display *display) /* * After retime buffer synchronization we need to turn of clk_en_sel - * bit on each phy. + * bit on each phy. Avoid this for Cphy. */ + + if (display->panel->host_config.phy_type == DSI_PHY_TYPE_CPHY) + return; + display_for_each_ctrl(i, display) { ctrl = &display->ctrl[i]; dsi_phy_reset_clk_en_sel(ctrl->phy); @@ -3038,10 +3056,12 @@ static int dsi_display_clocks_init(struct dsi_display *display) const char *clk_name; const char *src_byte = "src_byte", *src_pixel = "src_pixel"; const char *mux_byte = "mux_byte", *mux_pixel = "mux_pixel"; + const char *cphy_byte = "cphy_byte", *cphy_pixel = "cphy_pixel"; const char *shadow_byte = "shadow_byte", *shadow_pixel = "shadow_pixel"; struct clk *dsi_clk; struct dsi_clk_link_set *src = &display->clock_info.src_clks; struct dsi_clk_link_set *mux = &display->clock_info.mux_clks; + struct dsi_clk_link_set *cphy = &display->clock_info.cphy_clks; struct dsi_clk_link_set *shadow = &display->clock_info.shadow_clks; struct dsi_dyn_clk_caps *dyn_clk_caps = &(display->panel->dyn_clk_caps); char *dsi_clock_name; @@ -3076,6 +3096,15 @@ static int dsi_display_clocks_init(struct dsi_display *display) goto error; } + if (dsi_display_check_prefix(cphy_byte, clk_name)) { + cphy->byte_clk = NULL; + goto error; + } + if (dsi_display_check_prefix(cphy_pixel, clk_name)) { + cphy->pixel_clk = NULL; + goto error; + } + if (dyn_clk_caps->dyn_clk_support && (display->panel->panel_mode == DSI_OP_VIDEO_MODE)) { @@ -3107,6 +3136,16 @@ static int dsi_display_clocks_init(struct dsi_display *display) continue; } + if (dsi_display_check_prefix(cphy_byte, clk_name)) { + cphy->byte_clk = dsi_clk; + continue; + } + + if (dsi_display_check_prefix(cphy_pixel, clk_name)) { + cphy->pixel_clk = dsi_clk; + continue; + } + if (dsi_display_check_prefix(mux_byte, clk_name)) { mux->byte_clk = dsi_clk; continue; @@ -3729,6 +3768,8 @@ static int dsi_display_res_init(struct dsi_display *display) phy->cfg.force_clk_lane_hs = display->panel->host_config.force_hs_clk_lane; + phy->cfg.phy_type = + display->panel->host_config.phy_type; } rc = dsi_display_parse_lane_map(display); @@ -3942,6 +3983,7 @@ static int dsi_display_update_dsi_bitrate(struct dsi_display *display, u32 num_of_lanes = 0, bpp, byte_intf_clk_div; u64 bit_rate, pclk_rate, bit_rate_per_lane, byte_clk_rate, byte_intf_clk_rate; + u32 bits_per_symbol = 16, num_of_symbols = 7; /* For Cphy */ struct dsi_host_common_cfg *host_cfg; mutex_lock(&ctrl->ctrl_lock); @@ -3969,11 +4011,24 @@ static int dsi_display_update_dsi_bitrate(struct dsi_display *display, do_div(bit_rate_per_lane, num_of_lanes); pclk_rate = bit_rate; do_div(pclk_rate, bpp); - byte_clk_rate = bit_rate_per_lane; - do_div(byte_clk_rate, 8); - byte_intf_clk_rate = byte_clk_rate; - byte_intf_clk_div = host_cfg->byte_intf_clk_div; - do_div(byte_intf_clk_rate, byte_intf_clk_div); + if (host_cfg->phy_type == DSI_PHY_TYPE_DPHY) { + bit_rate_per_lane = bit_rate; + do_div(bit_rate_per_lane, num_of_lanes); + byte_clk_rate = bit_rate_per_lane; + do_div(byte_clk_rate, 8); + byte_intf_clk_rate = byte_clk_rate; + byte_intf_clk_div = host_cfg->byte_intf_clk_div; + do_div(byte_intf_clk_rate, byte_intf_clk_div); + } else { + do_div(bit_rate, bits_per_symbol); + bit_rate *= num_of_symbols; + bit_rate_per_lane = bit_rate; + do_div(bit_rate_per_lane, num_of_lanes); + byte_clk_rate = bit_rate_per_lane; + do_div(byte_clk_rate, 7); + /* For CPHY, byte_intf_clk is same as byte_clk */ + byte_intf_clk_rate = byte_clk_rate; + } DSI_DEBUG("bit_clk_rate = %llu, bit_clk_rate_per_lane = %llu\n", bit_rate, bit_rate_per_lane); diff --git a/msm/dsi/dsi_display.h b/msm/dsi/dsi_display.h index a287f4fe3a..d8840d8fe5 100644 --- a/msm/dsi/dsi_display.h +++ b/msm/dsi/dsi_display.h @@ -111,6 +111,7 @@ struct dsi_display_boot_param { struct dsi_display_clk_info { struct dsi_clk_link_set src_clks; struct dsi_clk_link_set mux_clks; + struct dsi_clk_link_set cphy_clks; struct dsi_clk_link_set shadow_clks; }; diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index f69bbd7e76..add10e9172 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -1043,6 +1043,7 @@ static int dsi_panel_parse_misc_host_config(struct dsi_host_common_cfg *host, { u32 val = 0; int rc = 0; + bool panel_cphy_mode = false; rc = utils->read_u32(utils->data, "qcom,mdss-dsi-t-clk-post", &val); if (!rc) { @@ -1068,6 +1069,11 @@ static int dsi_panel_parse_misc_host_config(struct dsi_host_common_cfg *host, host->force_hs_clk_lane = utils->read_bool(utils->data, "qcom,mdss-dsi-force-clock-lane-hs"); + panel_cphy_mode = utils->read_bool(utils->data, + "qcom,panel-cphy-mode"); + host->phy_type = panel_cphy_mode ? DSI_PHY_TYPE_CPHY + : DSI_PHY_TYPE_DPHY; + return 0; } diff --git a/msm/dsi/dsi_phy_hw.h b/msm/dsi/dsi_phy_hw.h index 7700520c24..45536843d2 100644 --- a/msm/dsi/dsi_phy_hw.h +++ b/msm/dsi/dsi_phy_hw.h @@ -100,6 +100,7 @@ struct dsi_phy_per_lane_cfgs { * @pll_source: PLL source. * @lane_map: DSI logical to PHY lane mapping. * @force_clk_lane_hs:Boolean whether to force clock lane in HS mode. + * @phy_type: Phy-type (Dphy/Cphy). * @bit_clk_rate_hz: DSI bit clk rate in HZ. */ struct dsi_phy_cfg { @@ -111,6 +112,7 @@ struct dsi_phy_cfg { enum dsi_phy_pll_source pll_source; struct dsi_lane_map lane_map; bool force_clk_lane_hs; + enum dsi_phy_type phy_type; unsigned long bit_clk_rate_hz; }; diff --git a/msm/dsi/dsi_phy_hw_v4_0.c b/msm/dsi/dsi_phy_hw_v4_0.c index 442a9b4599..3f456736d4 100644 --- a/msm/dsi/dsi_phy_hw_v4_0.c +++ b/msm/dsi/dsi_phy_hw_v4_0.c @@ -205,18 +205,115 @@ void dsi_phy_hw_v4_0_commit_phy_timing(struct dsi_phy_hw *phy, } /** - * enable() - Enable PHY hardware + * cphy_enable() - Enable CPHY hardware * @phy: Pointer to DSI PHY hardware object. * @cfg: Per lane configurations for timing, strength and lane * configurations. */ -void dsi_phy_hw_v4_0_enable(struct dsi_phy_hw *phy, +static void dsi_phy_hw_cphy_enable(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg) +{ + struct dsi_phy_per_lane_cfgs *timing = &cfg->timing; + u32 data; + u32 minor_ver = 0; + /* For C-PHY, no low power settings for lower clk rate */ + u32 vreg_ctrl_0 = 0x51; + u32 glbl_str_swi_cal_sel_ctrl = 0; + u32 glbl_hstx_str_ctrl_0 = 0; + u32 glbl_rescode_top_ctrl = 0; + u32 glbl_rescode_bot_ctrl = 0; + + if (phy->version == DSI_PHY_VERSION_4_1) { + glbl_rescode_top_ctrl = 0x00; + glbl_rescode_bot_ctrl = 0x3C; + glbl_str_swi_cal_sel_ctrl = 0x00; + glbl_hstx_str_ctrl_0 = 0x88; + } else { + glbl_str_swi_cal_sel_ctrl = 0x03; + glbl_hstx_str_ctrl_0 = 0x66; + glbl_rescode_top_ctrl = 0x03; + glbl_rescode_bot_ctrl = 0x3c; + } + + /* de-assert digital and pll power down */ + data = BIT(6) | BIT(5); + DSI_W32(phy, DSIPHY_CMN_CTRL_0, data); + + /* Assert PLL core reset */ + DSI_W32(phy, DSIPHY_CMN_PLL_CNTRL, 0x00); + + /* turn off resync FIFO */ + DSI_W32(phy, DSIPHY_CMN_RBUF_CTRL, 0x00); + + /* program CMN_CTRL_4 for minor_ver 2 chipsets*/ + minor_ver = DSI_R32(phy, DSIPHY_CMN_REVISION_ID0); + minor_ver = minor_ver & (0xf0); + if (minor_ver == 0x20) + DSI_W32(phy, DSIPHY_CMN_CTRL_4, 0x04); + + /* Configure PHY lane swap */ + dsi_phy_hw_v4_0_lane_swap_config(phy, &cfg->lane_map); + + DSI_W32(phy, DSIPHY_CMN_GLBL_CTRL, BIT(6)); + + /* Enable LDO */ + DSI_W32(phy, DSIPHY_CMN_VREG_CTRL_0, vreg_ctrl_0); + DSI_W32(phy, DSIPHY_CMN_VREG_CTRL_1, 0x55); + DSI_W32(phy, DSIPHY_CMN_GLBL_STR_SWI_CAL_SEL_CTRL, + glbl_str_swi_cal_sel_ctrl); + DSI_W32(phy, DSIPHY_CMN_GLBL_HSTX_STR_CTRL_0, glbl_hstx_str_ctrl_0); + DSI_W32(phy, DSIPHY_CMN_GLBL_PEMPH_CTRL_0, 0x11); + DSI_W32(phy, DSIPHY_CMN_GLBL_PEMPH_CTRL_1, 0x01); + DSI_W32(phy, DSIPHY_CMN_GLBL_RESCODE_OFFSET_TOP_CTRL, + glbl_rescode_top_ctrl); + DSI_W32(phy, DSIPHY_CMN_GLBL_RESCODE_OFFSET_BOT_CTRL, + glbl_rescode_bot_ctrl); + DSI_W32(phy, DSIPHY_CMN_GLBL_LPTX_STR_CTRL, 0x55); + + /* Remove power down from all blocks */ + DSI_W32(phy, DSIPHY_CMN_CTRL_0, 0x7f); + + DSI_W32(phy, DSIPHY_CMN_LANE_CTRL0, 0x17); + + switch (cfg->pll_source) { + case DSI_PLL_SOURCE_STANDALONE: + case DSI_PLL_SOURCE_NATIVE: + data = 0x0; /* internal PLL */ + break; + case DSI_PLL_SOURCE_NON_NATIVE: + data = 0x1; /* external PLL */ + break; + default: + break; + } + DSI_W32(phy, DSIPHY_CMN_CLK_CFG1, (data << 2)); /* set PLL src */ + + /* DSI PHY timings */ + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_0, timing->lane_v4[0]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_4, timing->lane_v4[4]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_5, timing->lane_v4[5]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_6, timing->lane_v4[6]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_7, timing->lane_v4[7]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_8, timing->lane_v4[8]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_9, timing->lane_v4[9]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_10, timing->lane_v4[10]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_11, timing->lane_v4[11]); + + /* DSI lane settings */ + dsi_phy_hw_v4_0_lane_settings(phy, cfg); + + DSI_PHY_DBG(phy, "C-Phy enabled\n"); +} + +/** + * dphy_enable() - Enable DPHY hardware + * @phy: Pointer to DSI PHY hardware object. + * @cfg: Per lane configurations for timing, strength and lane + * configurations. + */ +static void dsi_phy_hw_dphy_enable(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg) { - int rc = 0; - u32 status; - u32 const delay_us = 5; - u32 const timeout_us = 1000; struct dsi_phy_per_lane_cfgs *timing = &cfg->timing; u32 data; u32 minor_ver = 0; @@ -227,17 +324,6 @@ void dsi_phy_hw_v4_0_enable(struct dsi_phy_hw *phy, u32 glbl_rescode_top_ctrl = 0; u32 glbl_rescode_bot_ctrl = 0; - if (dsi_phy_hw_v4_0_is_pll_on(phy)) - DSI_PHY_WARN(phy, "PLL turned on before configuring PHY\n"); - - /* wait for REFGEN READY */ - rc = readl_poll_timeout_atomic(phy->base + DSIPHY_CMN_PHY_STATUS, - status, (status & BIT(0)), delay_us, timeout_us); - if (rc) { - DSI_PHY_ERR(phy, "Ref gen not ready. Aborting\n"); - return; - } - /* Alter PHY configurations if data rate less than 1.5GHZ*/ if (cfg->bit_clk_rate_hz <= 1500000000) less_than_1500_mhz = true; @@ -322,7 +408,39 @@ void dsi_phy_hw_v4_0_enable(struct dsi_phy_hw *phy, /* DSI lane settings */ dsi_phy_hw_v4_0_lane_settings(phy, cfg); - DSI_PHY_DBG(phy, "Phy enabled\n"); + DSI_PHY_DBG(phy, "D-Phy enabled\n"); +} + +/** + * enable() - Enable PHY hardware + * @phy: Pointer to DSI PHY hardware object. + * @cfg: Per lane configurations for timing, strength and lane + * configurations. + */ +void dsi_phy_hw_v4_0_enable(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg) +{ + int rc = 0; + u32 status; + u32 const delay_us = 5; + u32 const timeout_us = 1000; + + if (dsi_phy_hw_v4_0_is_pll_on(phy)) + pr_warn("PLL turned on before configuring PHY\n"); + + /* wait for REFGEN READY */ + rc = readl_poll_timeout_atomic(phy->base + DSIPHY_CMN_PHY_STATUS, + status, (status & BIT(0)), delay_us, timeout_us); + if (rc) { + DSI_PHY_ERR(phy, "Ref gen not ready. Aborting\n"); + return; + } + + if (cfg->phy_type == DSI_PHY_TYPE_CPHY) + dsi_phy_hw_cphy_enable(phy, cfg); + else /* Default PHY type is DPHY */ + dsi_phy_hw_dphy_enable(phy, cfg); + } /**