| /* Copyright (c) 2018, The Linux Foundation. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following |
| * disclaimer in the documentation and/or other materials provided |
| * with the distribution. |
| * * Neither the name of The Linux Foundation nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| */ |
| #include <debug.h> |
| #include <bits.h> |
| #include <reg.h> |
| #include <err.h> |
| #include <smem.h> |
| #include <clock.h> |
| #include <mipi_dsi.h> |
| #include <platform/iomap.h> |
| #include <qtimer.h> |
| #include <arch/defines.h> |
| |
| #define VCO_REF_CLOCK_RATE 19200000 |
| |
| #define DSIPHY_T_TA_GO_TIM_COUNT 0x014 |
| #define DSIPHY_T_TA_SURE_TIM_COUNT 0x018 |
| #define DSIPHY_PLL_POWERUP_CTRL 0x034 |
| #define DSIPHY_PLL_PROP_CHRG_PUMP_CTRL 0x038 |
| #define DSIPHY_PLL_INTEG_CHRG_PUMP_CTRL 0x03c |
| #define DSIPHY_PLL_ANA_TST_LOCK_ST_OVR_CTRL 0x044 |
| #define DSIPHY_PLL_VCO_CTRL 0x048 |
| #define DSIPHY_PLL_GMP_CTRL_DIG_TST 0x04c |
| #define DSIPHY_PLL_PHA_ERR_CTRL_0 0x050 |
| #define DSIPHY_PLL_LOCK_FILTER 0x054 |
| #define DSIPHY_PLL_UNLOCK_FILTER 0x058 |
| #define DSIPHY_PLL_INPUT_DIV_PLL_OVR 0x05c |
| #define DSIPHY_PLL_LOOP_DIV_RATIO_0 0x060 |
| #define DSIPHY_PLL_INPUT_LOOP_DIV_RAT_CTRL 0x064 |
| #define DSIPHY_PLL_PRO_DLY_RELOCK 0x06c |
| #define DSIPHY_PLL_CHAR_PUMP_BIAS_CTRL 0x070 |
| #define DSIPHY_PLL_LOCK_DET_MODE_SEL 0x074 |
| #define DSIPHY_PLL_ANA_PROG_CTRL 0x07c |
| #define DSIPHY_HSTX_DRIV_INDATA_CTRL_CLKLANE 0x0c0 |
| #define DSIPHY_HSTX_DATAREV_CTRL_CLKLANE 0x0d4 |
| #define DSIPHY_HSTX_DRIV_INDATA_CTRL_LANE0 0x100 |
| #define DSIPHY_HS_FREQ_RAN_SEL 0x110 |
| #define DSIPHY_HSTX_READY_DLY_DATA_REV_CTRL_LANE0 0x114 |
| #define DSIPHY_HSTX_DRIV_INDATA_CTRL_LANE1 0x140 |
| #define DSIPHY_HSTX_READY_DLY_DATA_REV_CTRL_LANE1 0x154 |
| #define DSIPHY_HSTX_CLKLANE_REQSTATE_TIM_CTRL 0x180 |
| #define DSIPHY_HSTX_CLKLANE_HS0STATE_TIM_CTRL 0x188 |
| #define DSIPHY_HSTX_CLKLANE_TRALSTATE_TIM_CTRL 0x18c |
| #define DSIPHY_HSTX_CLKLANE_EXITSTATE_TIM_CTRL 0x190 |
| #define DSIPHY_HSTX_CLKLANE_CLKPOSTSTATE_TIM_CTRL 0x194 |
| #define DSIPHY_HSTX_DATALANE_REQSTATE_TIM_CTRL 0x1c0 |
| #define DSIPHY_HSTX_DATALANE_HS0STATE_TIM_CTRL 0x1c8 |
| #define DSIPHY_HSTX_DATALANE_TRAILSTATE_TIM_CTRL 0x1cc |
| #define DSIPHY_HSTX_DATALANE_EXITSTATE_TIM_CTRL 0x1d0 |
| #define DSIPHY_HSTX_DRIV_INDATA_CTRL_LANE2 0x200 |
| #define DSIPHY_HSTX_READY_DLY_DATA_REV_CTRL_LANE2 0x214 |
| #define DSIPHY_HSTX_READY_DLY_DATA_REV_CTRL_LANE3 0x254 |
| #define DSIPHY_HSTX_DRIV_INDATA_CTRL_LANE3 0x240 |
| #define DSIPHY_SLEWRATE_FSM_OVR_CTRL 0x280 |
| #define DSIPHY_SLEWRATE_DDL_LOOP_CTRL 0x28c |
| #define DSIPHY_SLEWRATE_DDL_CYC_FRQ_ADJ_0 0x290 |
| #define DSIPHY_PLL_PHA_ERR_CTRL_1 0x2e4 |
| #define DSIPHY_PLL_LOOP_DIV_RATIO_1 0x2e8 |
| #define DSIPHY_SLEWRATE_DDL_CYC_FRQ_ADJ_1 0x328 |
| #define DSIPHY_SSC0 0x394 |
| #define DSIPHY_SSC1 0x398 |
| #define DSIPHY_SSC2 0x39c |
| #define DSIPHY_SSC3 0x3a0 |
| #define DSIPHY_SSC4 0x3a4 |
| #define DSIPHY_SSC5 0x3a8 |
| #define DSIPHY_SSC6 0x3ac |
| #define DSIPHY_SSC10 0x360 |
| #define DSIPHY_SSC11 0x364 |
| #define DSIPHY_SSC12 0x368 |
| #define DSIPHY_SSC13 0x36c |
| #define DSIPHY_SSC14 0x370 |
| #define DSIPHY_SSC15 0x374 |
| #define DSIPHY_SSC7 0x3b0 |
| #define DSIPHY_SSC8 0x3b4 |
| #define DSIPHY_SSC9 0x3b8 |
| #define DSIPHY_STAT0 0x3e0 |
| #define DSIPHY_CTRL0 0x3e8 |
| #define DSIPHY_SYS_CTRL 0x3f0 |
| #define DSIPHY_PLL_CTRL 0x3f8 |
| #define DSIPHY_REQ_DLY 0x3fc |
| |
| struct dsi_pll_param { |
| uint32_t vco_freq; |
| uint32_t hsfreqrange; |
| uint32_t vco_cntrl; |
| uint32_t osc_freq_target; |
| uint32_t m_div; |
| uint32_t prop_cntrl; |
| uint32_t int_cntrl; |
| uint32_t gmp_cntrl; |
| uint32_t cpbias_cntrl; |
| |
| /* mux and dividers */ |
| uint32_t gp_div_mux; |
| uint32_t post_div_mux; |
| uint32_t pixel_divhf; |
| uint32_t fsm_ovr_ctrl; |
| |
| /* SSC parameters */ |
| uint32_t mpll_ssc_peak_i; |
| uint32_t mpll_stepsize_i; |
| uint32_t mpll_mint_i; |
| uint32_t mpll_frac_den; |
| uint32_t mpll_frac_quot_i; |
| uint32_t mpll_frac_rem; |
| }; |
| |
| static uint32_t __mdss_dsi_get_hsfreqrange(uint64_t target_freq) |
| { |
| uint64_t bitclk_rate_mhz = ((target_freq * 2) / 1000000); |
| |
| if (bitclk_rate_mhz >= 80 && bitclk_rate_mhz < 90) |
| return 0x00; |
| else if (bitclk_rate_mhz >= 90 && bitclk_rate_mhz < 100) |
| return 0x10; |
| else if (bitclk_rate_mhz >= 100 && bitclk_rate_mhz < 110) |
| return 0x20; |
| else if (bitclk_rate_mhz >= 110 && bitclk_rate_mhz < 120) |
| return 0x30; |
| else if (bitclk_rate_mhz >= 120 && bitclk_rate_mhz < 130) |
| return 0x01; |
| else if (bitclk_rate_mhz >= 130 && bitclk_rate_mhz < 140) |
| return 0x11; |
| else if (bitclk_rate_mhz >= 140 && bitclk_rate_mhz < 150) |
| return 0x21; |
| else if (bitclk_rate_mhz >= 150 && bitclk_rate_mhz < 160) |
| return 0x31; |
| else if (bitclk_rate_mhz >= 160 && bitclk_rate_mhz < 170) |
| return 0x02; |
| else if (bitclk_rate_mhz >= 170 && bitclk_rate_mhz < 180) |
| return 0x12; |
| else if (bitclk_rate_mhz >= 180 && bitclk_rate_mhz < 190) |
| return 0x22; |
| else if (bitclk_rate_mhz >= 190 && bitclk_rate_mhz < 205) |
| return 0x32; |
| else if (bitclk_rate_mhz >= 205 && bitclk_rate_mhz < 220) |
| return 0x03; |
| else if (bitclk_rate_mhz >= 220 && bitclk_rate_mhz < 235) |
| return 0x13; |
| else if (bitclk_rate_mhz >= 235 && bitclk_rate_mhz < 250) |
| return 0x23; |
| else if (bitclk_rate_mhz >= 250 && bitclk_rate_mhz < 275) |
| return 0x33; |
| else if (bitclk_rate_mhz >= 275 && bitclk_rate_mhz < 300) |
| return 0x04; |
| else if (bitclk_rate_mhz >= 300 && bitclk_rate_mhz < 325) |
| return 0x14; |
| else if (bitclk_rate_mhz >= 325 && bitclk_rate_mhz < 350) |
| return 0x25; |
| else if (bitclk_rate_mhz >= 350 && bitclk_rate_mhz < 400) |
| return 0x35; |
| else if (bitclk_rate_mhz >= 400 && bitclk_rate_mhz < 450) |
| return 0x05; |
| else if (bitclk_rate_mhz >= 450 && bitclk_rate_mhz < 500) |
| return 0x16; |
| else if (bitclk_rate_mhz >= 500 && bitclk_rate_mhz < 550) |
| return 0x26; |
| else if (bitclk_rate_mhz >= 550 && bitclk_rate_mhz < 600) |
| return 0x37; |
| else if (bitclk_rate_mhz >= 600 && bitclk_rate_mhz < 650) |
| return 0x07; |
| else if (bitclk_rate_mhz >= 650 && bitclk_rate_mhz < 700) |
| return 0x18; |
| else if (bitclk_rate_mhz >= 700 && bitclk_rate_mhz < 750) |
| return 0x28; |
| else if (bitclk_rate_mhz >= 750 && bitclk_rate_mhz < 800) |
| return 0x39; |
| else if (bitclk_rate_mhz >= 800 && bitclk_rate_mhz < 850) |
| return 0x09; |
| else if (bitclk_rate_mhz >= 850 && bitclk_rate_mhz < 900) |
| return 0x19; |
| else if (bitclk_rate_mhz >= 900 && bitclk_rate_mhz < 950) |
| return 0x29; |
| else if (bitclk_rate_mhz >= 950 && bitclk_rate_mhz < 1000) |
| return 0x3a; |
| else if (bitclk_rate_mhz >= 1000 && bitclk_rate_mhz < 1050) |
| return 0x0a; |
| else if (bitclk_rate_mhz >= 1050 && bitclk_rate_mhz < 1100) |
| return 0x1a; |
| else if (bitclk_rate_mhz >= 1100 && bitclk_rate_mhz < 1150) |
| return 0x2a; |
| else if (bitclk_rate_mhz >= 1150 && bitclk_rate_mhz < 1200) |
| return 0x3b; |
| else if (bitclk_rate_mhz >= 1200 && bitclk_rate_mhz < 1250) |
| return 0x0b; |
| else if (bitclk_rate_mhz >= 1250 && bitclk_rate_mhz < 1300) |
| return 0x1b; |
| else if (bitclk_rate_mhz >= 1300 && bitclk_rate_mhz < 1350) |
| return 0x2b; |
| else if (bitclk_rate_mhz >= 1350 && bitclk_rate_mhz < 1400) |
| return 0x3c; |
| else if (bitclk_rate_mhz >= 1400 && bitclk_rate_mhz < 1450) |
| return 0x0c; |
| else if (bitclk_rate_mhz >= 1450 && bitclk_rate_mhz < 1500) |
| return 0x1c; |
| else if (bitclk_rate_mhz >= 1500 && bitclk_rate_mhz < 1550) |
| return 0x2c; |
| else if (bitclk_rate_mhz >= 1550 && bitclk_rate_mhz < 1600) |
| return 0x3d; |
| else if (bitclk_rate_mhz >= 1600 && bitclk_rate_mhz < 1650) |
| return 0x0d; |
| else if (bitclk_rate_mhz >= 1650 && bitclk_rate_mhz < 1700) |
| return 0x1d; |
| else if (bitclk_rate_mhz >= 1700 && bitclk_rate_mhz < 1750) |
| return 0x2e; |
| else if (bitclk_rate_mhz >= 1750 && bitclk_rate_mhz < 1800) |
| return 0x3e; |
| else if (bitclk_rate_mhz >= 1800 && bitclk_rate_mhz < 1850) |
| return 0x0e; |
| else if (bitclk_rate_mhz >= 1850 && bitclk_rate_mhz < 1900) |
| return 0x1e; |
| else if (bitclk_rate_mhz >= 1900 && bitclk_rate_mhz < 1950) |
| return 0x2f; |
| else if (bitclk_rate_mhz >= 1950 && bitclk_rate_mhz < 2000) |
| return 0x3f; |
| else if (bitclk_rate_mhz >= 2000 && bitclk_rate_mhz < 2050) |
| return 0x0f; |
| else if (bitclk_rate_mhz >= 2050 && bitclk_rate_mhz < 2100) |
| return 0x40; |
| else if (bitclk_rate_mhz >= 2100 && bitclk_rate_mhz < 2150) |
| return 0x41; |
| else if (bitclk_rate_mhz >= 2150 && bitclk_rate_mhz < 2200) |
| return 0x42; |
| else if (bitclk_rate_mhz >= 2200 && bitclk_rate_mhz < 2250) |
| return 0x43; |
| else if (bitclk_rate_mhz >= 2250 && bitclk_rate_mhz < 2300) |
| return 0x44; |
| else if (bitclk_rate_mhz >= 2300 && bitclk_rate_mhz < 2350) |
| return 0x45; |
| else if (bitclk_rate_mhz >= 2350 && bitclk_rate_mhz < 2400) |
| return 0x46; |
| else if (bitclk_rate_mhz >= 2400 && bitclk_rate_mhz < 2450) |
| return 0x47; |
| else if (bitclk_rate_mhz >= 2450 && bitclk_rate_mhz < 2500) |
| return 0x48; |
| else |
| return 0x49; |
| } |
| |
| static void __mdss_dsi_get_pll_vco_cntrl(uint64_t target_freq, |
| uint32_t post_div_mux, uint32_t *vco_cntrl, uint32_t *cpbias_cntrl) |
| { |
| uint64_t target_freq_mhz = (target_freq / 1000000); |
| uint32_t p_div = BIT(post_div_mux); |
| |
| if (p_div == 1) { |
| *vco_cntrl = 0x00; |
| *cpbias_cntrl = 0; |
| } else if (p_div == 2) { |
| *vco_cntrl = 0x30; |
| *cpbias_cntrl = 1; |
| } else if (p_div == 4) { |
| *vco_cntrl = 0x10; |
| *cpbias_cntrl = 0; |
| } else if (p_div == 8) { |
| *vco_cntrl = 0x20; |
| *cpbias_cntrl = 0; |
| } else if (p_div == 16) { |
| *vco_cntrl = 0x30; |
| *cpbias_cntrl = 0; |
| } else { |
| *vco_cntrl = 0x00; |
| *cpbias_cntrl = 1; |
| } |
| |
| if (target_freq_mhz <= 1250 && target_freq_mhz >= 1092) |
| *vco_cntrl = *vco_cntrl | 2; |
| else if (target_freq_mhz < 1092 && target_freq_mhz >= 950) |
| *vco_cntrl = *vco_cntrl | 3; |
| else if (target_freq_mhz < 950 && target_freq_mhz >= 712) |
| *vco_cntrl = *vco_cntrl | 1; |
| else if (target_freq_mhz < 712 && target_freq_mhz >= 546) |
| *vco_cntrl = *vco_cntrl | 2; |
| else if (target_freq_mhz < 546 && target_freq_mhz >= 475) |
| *vco_cntrl = *vco_cntrl | 3; |
| else if (target_freq_mhz < 475 && target_freq_mhz >= 356) |
| *vco_cntrl = *vco_cntrl | 1; |
| else if (target_freq_mhz < 356 && target_freq_mhz >= 273) |
| *vco_cntrl = *vco_cntrl | 2; |
| else if (target_freq_mhz < 273 && target_freq_mhz >= 237) |
| *vco_cntrl = *vco_cntrl | 3; |
| else if (target_freq_mhz < 237 && target_freq_mhz >= 178) |
| *vco_cntrl = *vco_cntrl | 1; |
| else if (target_freq_mhz < 178 && target_freq_mhz >= 136) |
| *vco_cntrl = *vco_cntrl | 2; |
| else if (target_freq_mhz < 136 && target_freq_mhz >= 118) |
| *vco_cntrl = *vco_cntrl | 3; |
| else if (target_freq_mhz < 118 && target_freq_mhz >= 89) |
| *vco_cntrl = *vco_cntrl | 1; |
| else if (target_freq_mhz < 89 && target_freq_mhz >= 68) |
| *vco_cntrl = *vco_cntrl | 2; |
| else if (target_freq_mhz < 68 && target_freq_mhz >= 57) |
| *vco_cntrl = *vco_cntrl | 3; |
| else if (target_freq_mhz < 57 && target_freq_mhz >= 44) |
| *vco_cntrl = *vco_cntrl | 1; |
| else |
| *vco_cntrl = *vco_cntrl | 2; |
| } |
| |
| static uint32_t __mdss_dsi_get_osc_freq_target(uint64_t target_freq) |
| { |
| uint64_t target_freq_mhz = (target_freq / 1000000); |
| |
| if (target_freq_mhz <= 1000) |
| return 1315; |
| else if (target_freq_mhz > 1000 && target_freq_mhz <= 1500) |
| return 1839; |
| else |
| return 0; |
| } |
| |
| static uint64_t __mdss_dsi_pll_get_m_div(uint64_t vco_rate) |
| { |
| return ((vco_rate * 4) / VCO_REF_CLOCK_RATE); |
| } |
| |
| static uint32_t __mdss_dsi_get_fsm_ovr_ctrl(uint64_t target_freq) |
| { |
| uint64_t bitclk_rate_mhz = ((target_freq * 2) / 1000000); |
| |
| if (bitclk_rate_mhz > 1500 && bitclk_rate_mhz <= 2500) |
| return 0; |
| else |
| return BIT(6); |
| } |
| |
| static void mdss_dsi_pll_12nm_calc_reg(struct dsi_pll_param *param) |
| { |
| uint64_t target_freq = 0; |
| |
| target_freq = (param->vco_freq / BIT(param->post_div_mux)); |
| |
| param->hsfreqrange = __mdss_dsi_get_hsfreqrange(target_freq); |
| __mdss_dsi_get_pll_vco_cntrl(target_freq, param->post_div_mux, |
| ¶m->vco_cntrl, ¶m->cpbias_cntrl); |
| param->osc_freq_target = __mdss_dsi_get_osc_freq_target(target_freq); |
| param->m_div = (uint32_t) __mdss_dsi_pll_get_m_div(param->vco_freq); |
| param->fsm_ovr_ctrl = __mdss_dsi_get_fsm_ovr_ctrl(target_freq); |
| param->prop_cntrl = 0x05; |
| param->int_cntrl = 0x00; |
| param->gmp_cntrl = 0x1; |
| } |
| |
| static uint32_t __mdss_dsi_get_multi_intX100(uint64_t vco_rate, uint32_t *rem) |
| { |
| uint32_t reminder = 0; |
| uint64_t temp = 0; |
| const uint32_t quarterX100 = 25; |
| |
| temp = vco_rate / VCO_REF_CLOCK_RATE; |
| temp *= 100; |
| reminder = vco_rate % VCO_REF_CLOCK_RATE; |
| |
| /* |
| * Multiplication integer needs to be floored in steps of 0.25 |
| * Hence multi_intX100 needs to be rounded off in steps of 25 |
| */ |
| if (reminder < (VCO_REF_CLOCK_RATE / 4)) { |
| *rem = reminder; |
| return temp; |
| } else if (reminder >= (VCO_REF_CLOCK_RATE / 4) && |
| reminder < (VCO_REF_CLOCK_RATE / 2)) { |
| *rem = (reminder - (VCO_REF_CLOCK_RATE / 4)); |
| return (temp + quarterX100); |
| } else if (reminder >= (VCO_REF_CLOCK_RATE / 2) && |
| reminder < ((3 * VCO_REF_CLOCK_RATE) / 4)) { |
| *rem = (reminder - (VCO_REF_CLOCK_RATE / 2)); |
| return (temp + (quarterX100 * 2)); |
| } |
| |
| *rem = (reminder - ((3 * VCO_REF_CLOCK_RATE) / 4)); |
| return (temp + (quarterX100 * 3)); |
| } |
| |
| static uint32_t __calc_gcd(uint32_t num1, uint32_t num2) |
| { |
| if (num2 != 0) |
| return __calc_gcd(num2, (num1 % num2)); |
| else |
| return num1; |
| } |
| |
| static void mdss_dsi_pll_12nm_calc_ssc(struct mdss_dsi_pll_config *pd, |
| struct dsi_pll_param *param) |
| { |
| uint64_t multi_intX100 = 0, temp = 0; |
| uint32_t temp_rem1 = 0, temp_rem2 = 0; |
| const uint64_t power_2_17 = 131072, power_2_10 = 1024; |
| |
| multi_intX100 = __mdss_dsi_get_multi_intX100(param->vco_freq, |
| &temp_rem1); |
| |
| /* Calculation for mpll_ssc_peak_i */ |
| temp = (multi_intX100 * pd->ssc_ppm * power_2_17); |
| temp = (temp / 100); /* 100 div for multi_intX100 */ |
| param->mpll_ssc_peak_i = |
| (uint32_t) (temp / 1000000); /*10^6 for SSC PPM */ |
| |
| /* Calculation for mpll_stepsize_i */ |
| param->mpll_stepsize_i = (uint32_t) ((param->mpll_ssc_peak_i * |
| pd->ssc_freq * power_2_10) / VCO_REF_CLOCK_RATE); |
| |
| /* Calculation for mpll_mint_i */ |
| param->mpll_mint_i = (uint32_t) (((multi_intX100 * 4) / 100) - 32); |
| |
| /* Calculation for mpll_frac_den */ |
| param->mpll_frac_den = (uint32_t) (VCO_REF_CLOCK_RATE / |
| __calc_gcd(param->vco_freq, VCO_REF_CLOCK_RATE)); |
| |
| /* Calculation for mpll_frac_quot_i */ |
| temp = (temp_rem1 * power_2_17); |
| param->mpll_frac_quot_i = (uint32_t) (temp / VCO_REF_CLOCK_RATE); |
| temp_rem2 = temp % VCO_REF_CLOCK_RATE; |
| |
| /* Calculation for mpll_frac_rem */ |
| param->mpll_frac_rem = (uint32_t) (((uint64_t) temp_rem2 * |
| param->mpll_frac_den) / VCO_REF_CLOCK_RATE); |
| |
| dprintf(SPEW, "mpll_ssc_peak_i=%d mpll_stepsize_i=%d mpll_mint_i=%d\n", |
| param->mpll_ssc_peak_i, param->mpll_stepsize_i, |
| param->mpll_mint_i); |
| dprintf(SPEW, "mpll_frac_den=%d mpll_frac_quot_i=%d mpll_frac_rem=%d\n", |
| param->mpll_frac_den, param->mpll_frac_quot_i, |
| param->mpll_frac_rem); |
| } |
| |
| static void pll_db_commit_12nm_ssc(struct dsi_pll_param *param, |
| uint32_t phy_base) |
| { |
| uint32_t data = 0; |
| |
| writel_relaxed(0x27, phy_base + DSIPHY_SSC0); |
| |
| data = (param->mpll_mint_i & 0xff); |
| writel_relaxed(data, phy_base + DSIPHY_SSC7); |
| |
| data = ((param->mpll_mint_i & 0xff00) >> 8); |
| writel_relaxed(data, phy_base + DSIPHY_SSC8); |
| |
| data = (param->mpll_ssc_peak_i & 0xff); |
| writel_relaxed(data, phy_base + DSIPHY_SSC1); |
| |
| data = ((param->mpll_ssc_peak_i & 0xff00) >> 8); |
| writel_relaxed(data, phy_base + DSIPHY_SSC2); |
| |
| data = ((param->mpll_ssc_peak_i & 0xf0000) >> 16); |
| writel_relaxed(data, phy_base + DSIPHY_SSC3); |
| |
| data = (param->mpll_stepsize_i & 0xff); |
| writel_relaxed(data, phy_base + DSIPHY_SSC4); |
| |
| data = ((param->mpll_stepsize_i & 0xff00) >> 8); |
| writel_relaxed(data, phy_base + DSIPHY_SSC5); |
| |
| data = ((param->mpll_stepsize_i & 0x1f0000) >> 16); |
| writel_relaxed(data, phy_base + DSIPHY_SSC6); |
| |
| data = (param->mpll_frac_quot_i & 0xff); |
| writel_relaxed(data, phy_base + DSIPHY_SSC10); |
| |
| data = ((param->mpll_frac_quot_i & 0xff00) >> 8); |
| writel_relaxed(data, phy_base + DSIPHY_SSC11); |
| |
| data = (param->mpll_frac_rem & 0xff); |
| writel_relaxed(data, phy_base + DSIPHY_SSC12); |
| |
| data = ((param->mpll_frac_rem & 0xff00) >> 8); |
| writel_relaxed(data, phy_base + DSIPHY_SSC13); |
| |
| data = (param->mpll_frac_den & 0xff); |
| writel_relaxed(data, phy_base + DSIPHY_SSC14); |
| |
| data = ((param->mpll_frac_den & 0xff00) >> 8); |
| writel_relaxed(data, phy_base + DSIPHY_SSC15); |
| } |
| |
| static void pll_db_commit_12nm(struct dsi_pll_param *param, |
| uint32_t phy_base, bool ssc_en) |
| { |
| uint32_t data = 0; |
| |
| writel_relaxed(0x01, phy_base + DSIPHY_CTRL0); |
| writel_relaxed(0x05, phy_base + DSIPHY_PLL_CTRL); |
| writel_relaxed(0x01, phy_base + DSIPHY_SLEWRATE_DDL_LOOP_CTRL); |
| |
| data = ((param->hsfreqrange & 0x7f) | BIT(7)); |
| writel_relaxed(data, phy_base + DSIPHY_HS_FREQ_RAN_SEL); |
| |
| data = ((param->vco_cntrl & 0x3f) | BIT(6)); |
| writel_relaxed(data, phy_base + DSIPHY_PLL_VCO_CTRL); |
| |
| data = (param->osc_freq_target & 0x7f); |
| writel_relaxed(data, phy_base + DSIPHY_SLEWRATE_DDL_CYC_FRQ_ADJ_0); |
| |
| data = ((param->osc_freq_target & 0xf80) >> 7); |
| writel_relaxed(data, phy_base + DSIPHY_SLEWRATE_DDL_CYC_FRQ_ADJ_1); |
| writel_relaxed(0x30, phy_base + DSIPHY_PLL_INPUT_LOOP_DIV_RAT_CTRL); |
| |
| data = (param->m_div & 0x3f); |
| writel_relaxed(data, phy_base + DSIPHY_PLL_LOOP_DIV_RATIO_0); |
| |
| data = ((param->m_div & 0xfc0) >> 6); |
| writel_relaxed(data, phy_base + DSIPHY_PLL_LOOP_DIV_RATIO_1); |
| writel_relaxed(0x60, phy_base + DSIPHY_PLL_INPUT_DIV_PLL_OVR); |
| |
| data = (param->prop_cntrl & 0x3f); |
| writel_relaxed(data, phy_base + DSIPHY_PLL_PROP_CHRG_PUMP_CTRL); |
| |
| data = (param->int_cntrl & 0x3f); |
| writel_relaxed(data, phy_base + DSIPHY_PLL_INTEG_CHRG_PUMP_CTRL); |
| |
| data = ((param->gmp_cntrl & 0x3) << 4); |
| writel_relaxed(data, phy_base + DSIPHY_PLL_GMP_CTRL_DIG_TST); |
| |
| data = ((param->cpbias_cntrl & 0x1) << 6) | BIT(4); |
| writel_relaxed(data, phy_base + DSIPHY_PLL_CHAR_PUMP_BIAS_CTRL); |
| |
| data = ((param->gp_div_mux & 0x7) << 5) | 0x5; |
| writel_relaxed(data, phy_base + DSIPHY_PLL_CTRL); |
| |
| data = (param->pixel_divhf & 0x7f); |
| writel_relaxed(data, phy_base + DSIPHY_SSC9); |
| |
| writel_relaxed(0x03, phy_base + DSIPHY_PLL_ANA_PROG_CTRL); |
| writel_relaxed(0x50, phy_base + DSIPHY_PLL_ANA_TST_LOCK_ST_OVR_CTRL); |
| writel_relaxed(param->fsm_ovr_ctrl, |
| phy_base + DSIPHY_SLEWRATE_FSM_OVR_CTRL); |
| writel_relaxed(0x01, phy_base + DSIPHY_PLL_PHA_ERR_CTRL_0); |
| writel_relaxed(0x00, phy_base + DSIPHY_PLL_PHA_ERR_CTRL_1); |
| writel_relaxed(0xff, phy_base + DSIPHY_PLL_LOCK_FILTER); |
| writel_relaxed(0x03, phy_base + DSIPHY_PLL_UNLOCK_FILTER); |
| writel_relaxed(0x0c, phy_base + DSIPHY_PLL_PRO_DLY_RELOCK); |
| writel_relaxed(0x02, phy_base + DSIPHY_PLL_LOCK_DET_MODE_SEL); |
| |
| if (ssc_en) |
| pll_db_commit_12nm_ssc(param, phy_base); |
| |
| dmb(); /* make sure register committed */ |
| } |
| |
| static void mdss_dsi_phy_12nm_init(struct msm_panel_info *pinfo, |
| uint32_t phy_base) |
| { |
| uint32_t *timing = pinfo->mipi.mdss_dsi_phy_db->timing; |
| |
| /* Shutdown PHY initially */ |
| writel_relaxed(0x09, phy_base + DSIPHY_SYS_CTRL); |
| /* CTRL0: CFG_CLK_EN */ |
| writel_relaxed(0x1, phy_base + DSIPHY_CTRL0); |
| |
| /* DSI PHY clock lane timings */ |
| writel_relaxed((timing[0] | BIT(7)), |
| phy_base + DSIPHY_HSTX_CLKLANE_HS0STATE_TIM_CTRL); |
| writel_relaxed((timing[1] | BIT(6)), |
| phy_base + DSIPHY_HSTX_CLKLANE_TRALSTATE_TIM_CTRL); |
| writel_relaxed((timing[2] | BIT(6)), |
| phy_base + DSIPHY_HSTX_CLKLANE_CLKPOSTSTATE_TIM_CTRL); |
| writel_relaxed(timing[3], |
| phy_base + DSIPHY_HSTX_CLKLANE_REQSTATE_TIM_CTRL); |
| writel_relaxed((timing[7] | BIT(6) | BIT(7)), |
| phy_base + DSIPHY_HSTX_CLKLANE_EXITSTATE_TIM_CTRL); |
| |
| /* DSI PHY data lane timings */ |
| writel_relaxed((timing[4] | BIT(7)), |
| phy_base + DSIPHY_HSTX_DATALANE_HS0STATE_TIM_CTRL); |
| writel_relaxed((timing[5] | BIT(6)), |
| phy_base + DSIPHY_HSTX_DATALANE_TRAILSTATE_TIM_CTRL); |
| writel_relaxed(timing[6], |
| phy_base + DSIPHY_HSTX_DATALANE_REQSTATE_TIM_CTRL); |
| writel_relaxed((timing[7] | BIT(6) | BIT(7)), |
| phy_base + DSIPHY_HSTX_DATALANE_EXITSTATE_TIM_CTRL); |
| |
| writel_relaxed(0x03, phy_base + DSIPHY_T_TA_GO_TIM_COUNT); |
| writel_relaxed(0x01, phy_base + DSIPHY_T_TA_SURE_TIM_COUNT); |
| writel_relaxed(0x85, phy_base + DSIPHY_REQ_DLY); |
| |
| /* DSI lane control registers */ |
| writel_relaxed(0x00, phy_base + |
| DSIPHY_HSTX_READY_DLY_DATA_REV_CTRL_LANE0); |
| writel_relaxed(0x00, phy_base + |
| DSIPHY_HSTX_READY_DLY_DATA_REV_CTRL_LANE1); |
| writel_relaxed(0x00, phy_base + |
| DSIPHY_HSTX_READY_DLY_DATA_REV_CTRL_LANE2); |
| writel_relaxed(0x00, phy_base + |
| DSIPHY_HSTX_READY_DLY_DATA_REV_CTRL_LANE3); |
| writel_relaxed(0x00, phy_base + |
| DSIPHY_HSTX_DATAREV_CTRL_CLKLANE); |
| dmb(); /* make sure DSI PHY registers are programmed */ |
| } |
| |
| void mdss_dsi_auto_pll_12nm_config(struct msm_panel_info *pinfo) |
| { |
| struct mdss_dsi_pll_config *pd = pinfo->mipi.dsi_pll_config; |
| uint32_t phy_base = pinfo->mipi.phy_base; |
| uint32_t sphy_base = pinfo->mipi.sphy_base; |
| struct dsi_pll_param param = {0}; |
| |
| param.vco_freq = pd->vco_clock; |
| param.post_div_mux = pd->p_div_mux; |
| param.gp_div_mux = pd->gp_div_mux; |
| param.pixel_divhf = pd->divhf; |
| |
| mdss_dsi_phy_12nm_init(pinfo, phy_base); |
| if (pinfo->mipi.dual_dsi) |
| mdss_dsi_phy_12nm_init(pinfo, sphy_base); |
| |
| mdss_dsi_pll_12nm_calc_reg(¶m); |
| if (pd->ssc_en) |
| mdss_dsi_pll_12nm_calc_ssc(pd, ¶m); |
| pll_db_commit_12nm(¶m, phy_base, pd->ssc_en); |
| } |
| |
| static uint32_t is_pll_locked_12nm(uint32_t phy_base) |
| { |
| uint32_t cnt, status; |
| |
| /* check pll lock */ |
| for (cnt = 0; cnt < 50; cnt++) { |
| status = readl_relaxed(phy_base + DSIPHY_STAT0); |
| dprintf(SPEW, "%s: phy_base=%x cnt=%d status=%x\n", |
| __func__, phy_base, cnt, status); |
| status &= BIT(1); |
| if (status) |
| break; |
| udelay(500); |
| } |
| |
| return status; |
| } |
| |
| static void mdss_dsi_12nm_phy_hstx_drv_enable(uint32_t phy_base) |
| { |
| uint32_t data = BIT(2) | BIT(3); |
| |
| writel_relaxed(data, phy_base + DSIPHY_HSTX_DRIV_INDATA_CTRL_CLKLANE); |
| writel_relaxed(data, phy_base + DSIPHY_HSTX_DRIV_INDATA_CTRL_LANE0); |
| writel_relaxed(data, phy_base + DSIPHY_HSTX_DRIV_INDATA_CTRL_LANE1); |
| writel_relaxed(data, phy_base + DSIPHY_HSTX_DRIV_INDATA_CTRL_LANE2); |
| writel_relaxed(data, phy_base + DSIPHY_HSTX_DRIV_INDATA_CTRL_LANE3); |
| dmb(); /* make sure DSI PHY registers are programmed */ |
| } |
| |
| bool mdss_dsi_auto_pll_12nm_enable(struct msm_panel_info *pinfo) |
| { |
| struct mdss_dsi_pll_config *pd = pinfo->mipi.dsi_pll_config; |
| uint32_t phy_base = pinfo->mipi.phy_base; |
| uint32_t sphy_base = pinfo->mipi.sphy_base; |
| |
| writel_relaxed(0x49, phy_base + DSIPHY_SYS_CTRL); |
| dmb(); /* make sure register committed */ |
| udelay(5); /* h/w recommended delay */ |
| writel_relaxed(0xc9, phy_base + DSIPHY_SYS_CTRL); |
| dmb(); /* make sure register committed */ |
| udelay(50); /* h/w recommended delay */ |
| |
| if (!is_pll_locked_12nm(phy_base)) { |
| dprintf(SPEW, "DSI PLL lock failed!\n"); |
| return false; |
| } |
| |
| dprintf(SPEW, "DSI PLL Locked!\n"); |
| |
| /* Enable DSI PLL output to DSI controller */ |
| if (pd->ssc_en) |
| writel_relaxed(0x67, phy_base + DSIPHY_SSC0); |
| else |
| writel_relaxed(0x40, phy_base + DSIPHY_SSC0); |
| |
| mdss_dsi_12nm_phy_hstx_drv_enable(phy_base); |
| if (pinfo->mipi.dual_dsi) |
| mdss_dsi_12nm_phy_hstx_drv_enable(sphy_base); |
| return true; |
| } |