197fb5e8dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 25c829028SHai Li /* 35c829028SHai Li * Copyright (c) 2015, The Linux Foundation. All rights reserved. 45c829028SHai Li */ 55c829028SHai Li 6d6d1439eSDmitry Baryshkov #include <linux/clk.h> 7d6d1439eSDmitry Baryshkov #include <linux/clk-provider.h> 8d6d1439eSDmitry Baryshkov 95c829028SHai Li #include "dsi_phy.h" 105c829028SHai Li #include "dsi.xml.h" 115c829028SHai Li 12d6d1439eSDmitry Baryshkov /* 13d6d1439eSDmitry Baryshkov * DSI PLL 28nm - clock diagram (eg: DSI0): 14d6d1439eSDmitry Baryshkov * 15d6d1439eSDmitry Baryshkov * dsi0analog_postdiv_clk 16d6d1439eSDmitry Baryshkov * | dsi0indirect_path_div2_clk 17d6d1439eSDmitry Baryshkov * | | 18d6d1439eSDmitry Baryshkov * +------+ | +----+ | |\ dsi0byte_mux 19d6d1439eSDmitry Baryshkov * dsi0vco_clk --o--| DIV1 |--o--| /2 |--o--| \ | 20d6d1439eSDmitry Baryshkov * | +------+ +----+ | m| | +----+ 21d6d1439eSDmitry Baryshkov * | | u|--o--| /4 |-- dsi0pllbyte 22d6d1439eSDmitry Baryshkov * | | x| +----+ 23d6d1439eSDmitry Baryshkov * o--------------------------| / 24d6d1439eSDmitry Baryshkov * | |/ 25d6d1439eSDmitry Baryshkov * | +------+ 26d6d1439eSDmitry Baryshkov * o----------| DIV3 |------------------------- dsi0pll 27d6d1439eSDmitry Baryshkov * +------+ 28d6d1439eSDmitry Baryshkov */ 29d6d1439eSDmitry Baryshkov 30d6d1439eSDmitry Baryshkov #define POLL_MAX_READS 10 31d6d1439eSDmitry Baryshkov #define POLL_TIMEOUT_US 50 32d6d1439eSDmitry Baryshkov 33d6d1439eSDmitry Baryshkov #define VCO_REF_CLK_RATE 19200000 34d6d1439eSDmitry Baryshkov #define VCO_MIN_RATE 350000000 35d6d1439eSDmitry Baryshkov #define VCO_MAX_RATE 750000000 36d6d1439eSDmitry Baryshkov 3780d2229bSDmitry Baryshkov /* v2.0.0 28nm LP implementation */ 3880d2229bSDmitry Baryshkov #define DSI_PHY_28NM_QUIRK_PHY_LP BIT(0) 3980d2229bSDmitry Baryshkov 40d6d1439eSDmitry Baryshkov #define LPFR_LUT_SIZE 10 41d6d1439eSDmitry Baryshkov struct lpfr_cfg { 42d6d1439eSDmitry Baryshkov unsigned long vco_rate; 43d6d1439eSDmitry Baryshkov u32 resistance; 44d6d1439eSDmitry Baryshkov }; 45d6d1439eSDmitry Baryshkov 46d6d1439eSDmitry Baryshkov /* Loop filter resistance: */ 47d6d1439eSDmitry Baryshkov static const struct lpfr_cfg lpfr_lut[LPFR_LUT_SIZE] = { 48d6d1439eSDmitry Baryshkov { 479500000, 8 }, 49d6d1439eSDmitry Baryshkov { 480000000, 11 }, 50d6d1439eSDmitry Baryshkov { 575500000, 8 }, 51d6d1439eSDmitry Baryshkov { 576000000, 12 }, 52d6d1439eSDmitry Baryshkov { 610500000, 8 }, 53d6d1439eSDmitry Baryshkov { 659500000, 9 }, 54d6d1439eSDmitry Baryshkov { 671500000, 10 }, 55d6d1439eSDmitry Baryshkov { 672000000, 14 }, 56d6d1439eSDmitry Baryshkov { 708500000, 10 }, 57d6d1439eSDmitry Baryshkov { 750000000, 11 }, 58d6d1439eSDmitry Baryshkov }; 59d6d1439eSDmitry Baryshkov 60d6d1439eSDmitry Baryshkov struct pll_28nm_cached_state { 61d6d1439eSDmitry Baryshkov unsigned long vco_rate; 62d6d1439eSDmitry Baryshkov u8 postdiv3; 63d6d1439eSDmitry Baryshkov u8 postdiv1; 64d6d1439eSDmitry Baryshkov u8 byte_mux; 65d6d1439eSDmitry Baryshkov }; 66d6d1439eSDmitry Baryshkov 67d6d1439eSDmitry Baryshkov struct dsi_pll_28nm { 68007687c3SDmitry Baryshkov struct clk_hw clk_hw; 69d6d1439eSDmitry Baryshkov 70d6d1439eSDmitry Baryshkov int id; 71d6d1439eSDmitry Baryshkov struct platform_device *pdev; 72007687c3SDmitry Baryshkov 73007687c3SDmitry Baryshkov struct msm_dsi_phy *phy; 74007687c3SDmitry Baryshkov 75d6d1439eSDmitry Baryshkov struct pll_28nm_cached_state cached_state; 76d6d1439eSDmitry Baryshkov }; 77d6d1439eSDmitry Baryshkov 78007687c3SDmitry Baryshkov #define to_pll_28nm(x) container_of(x, struct dsi_pll_28nm, clk_hw) 79d6d1439eSDmitry Baryshkov 80d6d1439eSDmitry Baryshkov static bool pll_28nm_poll_for_ready(struct dsi_pll_28nm *pll_28nm, 81d6d1439eSDmitry Baryshkov u32 nb_tries, u32 timeout_us) 82d6d1439eSDmitry Baryshkov { 83d6d1439eSDmitry Baryshkov bool pll_locked = false; 84d6d1439eSDmitry Baryshkov u32 val; 85d6d1439eSDmitry Baryshkov 86d6d1439eSDmitry Baryshkov while (nb_tries--) { 87*b7cf8a54SDmitry Baryshkov val = dsi_phy_read(pll_28nm->phy->pll_base + REG_DSI_28nm_PHY_PLL_STATUS); 88d6d1439eSDmitry Baryshkov pll_locked = !!(val & DSI_28nm_PHY_PLL_STATUS_PLL_RDY); 89d6d1439eSDmitry Baryshkov 90d6d1439eSDmitry Baryshkov if (pll_locked) 91d6d1439eSDmitry Baryshkov break; 92d6d1439eSDmitry Baryshkov 93d6d1439eSDmitry Baryshkov udelay(timeout_us); 94d6d1439eSDmitry Baryshkov } 95d6d1439eSDmitry Baryshkov DBG("DSI PLL is %slocked", pll_locked ? "" : "*not* "); 96d6d1439eSDmitry Baryshkov 97d6d1439eSDmitry Baryshkov return pll_locked; 98d6d1439eSDmitry Baryshkov } 99d6d1439eSDmitry Baryshkov 100d6d1439eSDmitry Baryshkov static void pll_28nm_software_reset(struct dsi_pll_28nm *pll_28nm) 101d6d1439eSDmitry Baryshkov { 102*b7cf8a54SDmitry Baryshkov void __iomem *base = pll_28nm->phy->pll_base; 103d6d1439eSDmitry Baryshkov 104d6d1439eSDmitry Baryshkov /* 105d6d1439eSDmitry Baryshkov * Add HW recommended delays after toggling the software 106d6d1439eSDmitry Baryshkov * reset bit off and back on. 107d6d1439eSDmitry Baryshkov */ 108e55b3fbbSDmitry Baryshkov dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_TEST_CFG, 109d6d1439eSDmitry Baryshkov DSI_28nm_PHY_PLL_TEST_CFG_PLL_SW_RESET, 1); 110e55b3fbbSDmitry Baryshkov dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_TEST_CFG, 0x00, 1); 111d6d1439eSDmitry Baryshkov } 112d6d1439eSDmitry Baryshkov 113d6d1439eSDmitry Baryshkov /* 114d6d1439eSDmitry Baryshkov * Clock Callbacks 115d6d1439eSDmitry Baryshkov */ 116d6d1439eSDmitry Baryshkov static int dsi_pll_28nm_clk_set_rate(struct clk_hw *hw, unsigned long rate, 117d6d1439eSDmitry Baryshkov unsigned long parent_rate) 118d6d1439eSDmitry Baryshkov { 119007687c3SDmitry Baryshkov struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw); 120d6d1439eSDmitry Baryshkov struct device *dev = &pll_28nm->pdev->dev; 121*b7cf8a54SDmitry Baryshkov void __iomem *base = pll_28nm->phy->pll_base; 122d6d1439eSDmitry Baryshkov unsigned long div_fbx1000, gen_vco_clk; 123d6d1439eSDmitry Baryshkov u32 refclk_cfg, frac_n_mode, frac_n_value; 124d6d1439eSDmitry Baryshkov u32 sdm_cfg0, sdm_cfg1, sdm_cfg2, sdm_cfg3; 125d6d1439eSDmitry Baryshkov u32 cal_cfg10, cal_cfg11; 126d6d1439eSDmitry Baryshkov u32 rem; 127d6d1439eSDmitry Baryshkov int i; 128d6d1439eSDmitry Baryshkov 129d6d1439eSDmitry Baryshkov VERB("rate=%lu, parent's=%lu", rate, parent_rate); 130d6d1439eSDmitry Baryshkov 131d6d1439eSDmitry Baryshkov /* Force postdiv2 to be div-4 */ 132e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV2_CFG, 3); 133d6d1439eSDmitry Baryshkov 134d6d1439eSDmitry Baryshkov /* Configure the Loop filter resistance */ 135d6d1439eSDmitry Baryshkov for (i = 0; i < LPFR_LUT_SIZE; i++) 136d6d1439eSDmitry Baryshkov if (rate <= lpfr_lut[i].vco_rate) 137d6d1439eSDmitry Baryshkov break; 138d6d1439eSDmitry Baryshkov if (i == LPFR_LUT_SIZE) { 139d6d1439eSDmitry Baryshkov DRM_DEV_ERROR(dev, "unable to get loop filter resistance. vco=%lu\n", 140d6d1439eSDmitry Baryshkov rate); 141d6d1439eSDmitry Baryshkov return -EINVAL; 142d6d1439eSDmitry Baryshkov } 143e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_LPFR_CFG, lpfr_lut[i].resistance); 144d6d1439eSDmitry Baryshkov 145d6d1439eSDmitry Baryshkov /* Loop filter capacitance values : c1 and c2 */ 146e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_LPFC1_CFG, 0x70); 147e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_LPFC2_CFG, 0x15); 148d6d1439eSDmitry Baryshkov 149d6d1439eSDmitry Baryshkov rem = rate % VCO_REF_CLK_RATE; 150d6d1439eSDmitry Baryshkov if (rem) { 151d6d1439eSDmitry Baryshkov refclk_cfg = DSI_28nm_PHY_PLL_REFCLK_CFG_DBLR; 152d6d1439eSDmitry Baryshkov frac_n_mode = 1; 153d6d1439eSDmitry Baryshkov div_fbx1000 = rate / (VCO_REF_CLK_RATE / 500); 154d6d1439eSDmitry Baryshkov gen_vco_clk = div_fbx1000 * (VCO_REF_CLK_RATE / 500); 155d6d1439eSDmitry Baryshkov } else { 156d6d1439eSDmitry Baryshkov refclk_cfg = 0x0; 157d6d1439eSDmitry Baryshkov frac_n_mode = 0; 158d6d1439eSDmitry Baryshkov div_fbx1000 = rate / (VCO_REF_CLK_RATE / 1000); 159d6d1439eSDmitry Baryshkov gen_vco_clk = div_fbx1000 * (VCO_REF_CLK_RATE / 1000); 160d6d1439eSDmitry Baryshkov } 161d6d1439eSDmitry Baryshkov 162d6d1439eSDmitry Baryshkov DBG("refclk_cfg = %d", refclk_cfg); 163d6d1439eSDmitry Baryshkov 164d6d1439eSDmitry Baryshkov rem = div_fbx1000 % 1000; 165d6d1439eSDmitry Baryshkov frac_n_value = (rem << 16) / 1000; 166d6d1439eSDmitry Baryshkov 167d6d1439eSDmitry Baryshkov DBG("div_fb = %lu", div_fbx1000); 168d6d1439eSDmitry Baryshkov DBG("frac_n_value = %d", frac_n_value); 169d6d1439eSDmitry Baryshkov 170d6d1439eSDmitry Baryshkov DBG("Generated VCO Clock: %lu", gen_vco_clk); 171d6d1439eSDmitry Baryshkov rem = 0; 172e55b3fbbSDmitry Baryshkov sdm_cfg1 = dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1); 173d6d1439eSDmitry Baryshkov sdm_cfg1 &= ~DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET__MASK; 174d6d1439eSDmitry Baryshkov if (frac_n_mode) { 175d6d1439eSDmitry Baryshkov sdm_cfg0 = 0x0; 176d6d1439eSDmitry Baryshkov sdm_cfg0 |= DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV(0); 177d6d1439eSDmitry Baryshkov sdm_cfg1 |= DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET( 178d6d1439eSDmitry Baryshkov (u32)(((div_fbx1000 / 1000) & 0x3f) - 1)); 179d6d1439eSDmitry Baryshkov sdm_cfg3 = frac_n_value >> 8; 180d6d1439eSDmitry Baryshkov sdm_cfg2 = frac_n_value & 0xff; 181d6d1439eSDmitry Baryshkov } else { 182d6d1439eSDmitry Baryshkov sdm_cfg0 = DSI_28nm_PHY_PLL_SDM_CFG0_BYP; 183d6d1439eSDmitry Baryshkov sdm_cfg0 |= DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV( 184d6d1439eSDmitry Baryshkov (u32)(((div_fbx1000 / 1000) & 0x3f) - 1)); 185d6d1439eSDmitry Baryshkov sdm_cfg1 |= DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET(0); 186d6d1439eSDmitry Baryshkov sdm_cfg2 = 0; 187d6d1439eSDmitry Baryshkov sdm_cfg3 = 0; 188d6d1439eSDmitry Baryshkov } 189d6d1439eSDmitry Baryshkov 190d6d1439eSDmitry Baryshkov DBG("sdm_cfg0=%d", sdm_cfg0); 191d6d1439eSDmitry Baryshkov DBG("sdm_cfg1=%d", sdm_cfg1); 192d6d1439eSDmitry Baryshkov DBG("sdm_cfg2=%d", sdm_cfg2); 193d6d1439eSDmitry Baryshkov DBG("sdm_cfg3=%d", sdm_cfg3); 194d6d1439eSDmitry Baryshkov 195d6d1439eSDmitry Baryshkov cal_cfg11 = (u32)(gen_vco_clk / (256 * 1000000)); 196d6d1439eSDmitry Baryshkov cal_cfg10 = (u32)((gen_vco_clk % (256 * 1000000)) / 1000000); 197d6d1439eSDmitry Baryshkov DBG("cal_cfg10=%d, cal_cfg11=%d", cal_cfg10, cal_cfg11); 198d6d1439eSDmitry Baryshkov 199e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CHGPUMP_CFG, 0x02); 200e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG3, 0x2b); 201e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG4, 0x06); 202e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x0d); 203d6d1439eSDmitry Baryshkov 204e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1, sdm_cfg1); 205e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG2, 206d6d1439eSDmitry Baryshkov DSI_28nm_PHY_PLL_SDM_CFG2_FREQ_SEED_7_0(sdm_cfg2)); 207e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG3, 208d6d1439eSDmitry Baryshkov DSI_28nm_PHY_PLL_SDM_CFG3_FREQ_SEED_15_8(sdm_cfg3)); 209e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG4, 0x00); 210d6d1439eSDmitry Baryshkov 211d6d1439eSDmitry Baryshkov /* Add hardware recommended delay for correct PLL configuration */ 212007687c3SDmitry Baryshkov if (pll_28nm->phy->cfg->quirks & DSI_PHY_28NM_QUIRK_PHY_LP) 21389da8153SDmitry Baryshkov udelay(1000); 21489da8153SDmitry Baryshkov else 21589da8153SDmitry Baryshkov udelay(1); 216d6d1439eSDmitry Baryshkov 217e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_REFCLK_CFG, refclk_cfg); 218e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_PWRGEN_CFG, 0x00); 219e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_VCOLPF_CFG, 0x31); 220e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG0, sdm_cfg0); 221e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG0, 0x12); 222e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG6, 0x30); 223e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG7, 0x00); 224e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG8, 0x60); 225e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG9, 0x00); 226e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG10, cal_cfg10 & 0xff); 227e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG11, cal_cfg11 & 0xff); 228e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_EFUSE_CFG, 0x20); 229d6d1439eSDmitry Baryshkov 230d6d1439eSDmitry Baryshkov return 0; 231d6d1439eSDmitry Baryshkov } 232d6d1439eSDmitry Baryshkov 233d6d1439eSDmitry Baryshkov static int dsi_pll_28nm_clk_is_enabled(struct clk_hw *hw) 234d6d1439eSDmitry Baryshkov { 235007687c3SDmitry Baryshkov struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw); 236d6d1439eSDmitry Baryshkov 237d6d1439eSDmitry Baryshkov return pll_28nm_poll_for_ready(pll_28nm, POLL_MAX_READS, 238d6d1439eSDmitry Baryshkov POLL_TIMEOUT_US); 239d6d1439eSDmitry Baryshkov } 240d6d1439eSDmitry Baryshkov 241d6d1439eSDmitry Baryshkov static unsigned long dsi_pll_28nm_clk_recalc_rate(struct clk_hw *hw, 242d6d1439eSDmitry Baryshkov unsigned long parent_rate) 243d6d1439eSDmitry Baryshkov { 244007687c3SDmitry Baryshkov struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw); 245*b7cf8a54SDmitry Baryshkov void __iomem *base = pll_28nm->phy->pll_base; 246d6d1439eSDmitry Baryshkov u32 sdm0, doubler, sdm_byp_div; 247d6d1439eSDmitry Baryshkov u32 sdm_dc_off, sdm_freq_seed, sdm2, sdm3; 248d6d1439eSDmitry Baryshkov u32 ref_clk = VCO_REF_CLK_RATE; 249d6d1439eSDmitry Baryshkov unsigned long vco_rate; 250d6d1439eSDmitry Baryshkov 251d6d1439eSDmitry Baryshkov VERB("parent_rate=%lu", parent_rate); 252d6d1439eSDmitry Baryshkov 253d6d1439eSDmitry Baryshkov /* Check to see if the ref clk doubler is enabled */ 254e55b3fbbSDmitry Baryshkov doubler = dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_REFCLK_CFG) & 255d6d1439eSDmitry Baryshkov DSI_28nm_PHY_PLL_REFCLK_CFG_DBLR; 256d6d1439eSDmitry Baryshkov ref_clk += (doubler * VCO_REF_CLK_RATE); 257d6d1439eSDmitry Baryshkov 258d6d1439eSDmitry Baryshkov /* see if it is integer mode or sdm mode */ 259e55b3fbbSDmitry Baryshkov sdm0 = dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG0); 260d6d1439eSDmitry Baryshkov if (sdm0 & DSI_28nm_PHY_PLL_SDM_CFG0_BYP) { 261d6d1439eSDmitry Baryshkov /* integer mode */ 262d6d1439eSDmitry Baryshkov sdm_byp_div = FIELD( 263e55b3fbbSDmitry Baryshkov dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG0), 264d6d1439eSDmitry Baryshkov DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV) + 1; 265d6d1439eSDmitry Baryshkov vco_rate = ref_clk * sdm_byp_div; 266d6d1439eSDmitry Baryshkov } else { 267d6d1439eSDmitry Baryshkov /* sdm mode */ 268d6d1439eSDmitry Baryshkov sdm_dc_off = FIELD( 269e55b3fbbSDmitry Baryshkov dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1), 270d6d1439eSDmitry Baryshkov DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET); 271d6d1439eSDmitry Baryshkov DBG("sdm_dc_off = %d", sdm_dc_off); 272e55b3fbbSDmitry Baryshkov sdm2 = FIELD(dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG2), 273d6d1439eSDmitry Baryshkov DSI_28nm_PHY_PLL_SDM_CFG2_FREQ_SEED_7_0); 274e55b3fbbSDmitry Baryshkov sdm3 = FIELD(dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG3), 275d6d1439eSDmitry Baryshkov DSI_28nm_PHY_PLL_SDM_CFG3_FREQ_SEED_15_8); 276d6d1439eSDmitry Baryshkov sdm_freq_seed = (sdm3 << 8) | sdm2; 277d6d1439eSDmitry Baryshkov DBG("sdm_freq_seed = %d", sdm_freq_seed); 278d6d1439eSDmitry Baryshkov 279d6d1439eSDmitry Baryshkov vco_rate = (ref_clk * (sdm_dc_off + 1)) + 280d6d1439eSDmitry Baryshkov mult_frac(ref_clk, sdm_freq_seed, BIT(16)); 281d6d1439eSDmitry Baryshkov DBG("vco rate = %lu", vco_rate); 282d6d1439eSDmitry Baryshkov } 283d6d1439eSDmitry Baryshkov 284d6d1439eSDmitry Baryshkov DBG("returning vco rate = %lu", vco_rate); 285d6d1439eSDmitry Baryshkov 286d6d1439eSDmitry Baryshkov return vco_rate; 287d6d1439eSDmitry Baryshkov } 288d6d1439eSDmitry Baryshkov 289007687c3SDmitry Baryshkov static int _dsi_pll_28nm_vco_prepare_hpm(struct dsi_pll_28nm *pll_28nm) 290d6d1439eSDmitry Baryshkov { 291d6d1439eSDmitry Baryshkov struct device *dev = &pll_28nm->pdev->dev; 292*b7cf8a54SDmitry Baryshkov void __iomem *base = pll_28nm->phy->pll_base; 293d6d1439eSDmitry Baryshkov u32 max_reads = 5, timeout_us = 100; 294d6d1439eSDmitry Baryshkov bool locked; 295d6d1439eSDmitry Baryshkov u32 val; 296d6d1439eSDmitry Baryshkov int i; 297d6d1439eSDmitry Baryshkov 298d6d1439eSDmitry Baryshkov DBG("id=%d", pll_28nm->id); 299d6d1439eSDmitry Baryshkov 300d6d1439eSDmitry Baryshkov pll_28nm_software_reset(pll_28nm); 301d6d1439eSDmitry Baryshkov 302d6d1439eSDmitry Baryshkov /* 303d6d1439eSDmitry Baryshkov * PLL power up sequence. 304d6d1439eSDmitry Baryshkov * Add necessary delays recommended by hardware. 305d6d1439eSDmitry Baryshkov */ 306d6d1439eSDmitry Baryshkov val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B; 307e55b3fbbSDmitry Baryshkov dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 1); 308d6d1439eSDmitry Baryshkov 309d6d1439eSDmitry Baryshkov val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B; 310e55b3fbbSDmitry Baryshkov dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200); 311d6d1439eSDmitry Baryshkov 312d6d1439eSDmitry Baryshkov val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B; 313e55b3fbbSDmitry Baryshkov dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500); 314d6d1439eSDmitry Baryshkov 315d6d1439eSDmitry Baryshkov val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE; 316e55b3fbbSDmitry Baryshkov dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 600); 317d6d1439eSDmitry Baryshkov 318d6d1439eSDmitry Baryshkov for (i = 0; i < 2; i++) { 319d6d1439eSDmitry Baryshkov /* DSI Uniphy lock detect setting */ 320e55b3fbbSDmitry Baryshkov dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 321d6d1439eSDmitry Baryshkov 0x0c, 100); 322e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x0d); 323d6d1439eSDmitry Baryshkov 324d6d1439eSDmitry Baryshkov /* poll for PLL ready status */ 325d6d1439eSDmitry Baryshkov locked = pll_28nm_poll_for_ready(pll_28nm, 326d6d1439eSDmitry Baryshkov max_reads, timeout_us); 327d6d1439eSDmitry Baryshkov if (locked) 328d6d1439eSDmitry Baryshkov break; 329d6d1439eSDmitry Baryshkov 330d6d1439eSDmitry Baryshkov pll_28nm_software_reset(pll_28nm); 331d6d1439eSDmitry Baryshkov 332d6d1439eSDmitry Baryshkov /* 333d6d1439eSDmitry Baryshkov * PLL power up sequence. 334d6d1439eSDmitry Baryshkov * Add necessary delays recommended by hardware. 335d6d1439eSDmitry Baryshkov */ 336d6d1439eSDmitry Baryshkov val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B; 337e55b3fbbSDmitry Baryshkov dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 1); 338d6d1439eSDmitry Baryshkov 339d6d1439eSDmitry Baryshkov val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B; 340e55b3fbbSDmitry Baryshkov dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200); 341d6d1439eSDmitry Baryshkov 342d6d1439eSDmitry Baryshkov val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B; 343e55b3fbbSDmitry Baryshkov dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 250); 344d6d1439eSDmitry Baryshkov 345d6d1439eSDmitry Baryshkov val &= ~DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B; 346e55b3fbbSDmitry Baryshkov dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200); 347d6d1439eSDmitry Baryshkov 348d6d1439eSDmitry Baryshkov val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B; 349e55b3fbbSDmitry Baryshkov dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500); 350d6d1439eSDmitry Baryshkov 351d6d1439eSDmitry Baryshkov val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE; 352e55b3fbbSDmitry Baryshkov dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 600); 353d6d1439eSDmitry Baryshkov } 354d6d1439eSDmitry Baryshkov 355d6d1439eSDmitry Baryshkov if (unlikely(!locked)) 356d6d1439eSDmitry Baryshkov DRM_DEV_ERROR(dev, "DSI PLL lock failed\n"); 357d6d1439eSDmitry Baryshkov else 358d6d1439eSDmitry Baryshkov DBG("DSI PLL Lock success"); 359d6d1439eSDmitry Baryshkov 360d6d1439eSDmitry Baryshkov return locked ? 0 : -EINVAL; 361d6d1439eSDmitry Baryshkov } 362d6d1439eSDmitry Baryshkov 36362d5325dSDmitry Baryshkov static int dsi_pll_28nm_vco_prepare_hpm(struct clk_hw *hw) 3646a58cfecSDmitry Baryshkov { 365007687c3SDmitry Baryshkov struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw); 3666a58cfecSDmitry Baryshkov int i, ret; 3676a58cfecSDmitry Baryshkov 368007687c3SDmitry Baryshkov if (unlikely(pll_28nm->phy->pll_on)) 3696a58cfecSDmitry Baryshkov return 0; 37062d5325dSDmitry Baryshkov 37162d5325dSDmitry Baryshkov for (i = 0; i < 3; i++) { 372007687c3SDmitry Baryshkov ret = _dsi_pll_28nm_vco_prepare_hpm(pll_28nm); 37362d5325dSDmitry Baryshkov if (!ret) { 374007687c3SDmitry Baryshkov pll_28nm->phy->pll_on = true; 37562d5325dSDmitry Baryshkov return 0; 37662d5325dSDmitry Baryshkov } 3776a58cfecSDmitry Baryshkov } 3786a58cfecSDmitry Baryshkov 3796a58cfecSDmitry Baryshkov return ret; 3806a58cfecSDmitry Baryshkov } 3816a58cfecSDmitry Baryshkov 38262d5325dSDmitry Baryshkov static int dsi_pll_28nm_vco_prepare_lp(struct clk_hw *hw) 383d6d1439eSDmitry Baryshkov { 384007687c3SDmitry Baryshkov struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw); 385d6d1439eSDmitry Baryshkov struct device *dev = &pll_28nm->pdev->dev; 386*b7cf8a54SDmitry Baryshkov void __iomem *base = pll_28nm->phy->pll_base; 387d6d1439eSDmitry Baryshkov bool locked; 388d6d1439eSDmitry Baryshkov u32 max_reads = 10, timeout_us = 50; 389d6d1439eSDmitry Baryshkov u32 val; 390d6d1439eSDmitry Baryshkov 391d6d1439eSDmitry Baryshkov DBG("id=%d", pll_28nm->id); 392d6d1439eSDmitry Baryshkov 393007687c3SDmitry Baryshkov if (unlikely(pll_28nm->phy->pll_on)) 39462d5325dSDmitry Baryshkov return 0; 39562d5325dSDmitry Baryshkov 396d6d1439eSDmitry Baryshkov pll_28nm_software_reset(pll_28nm); 397d6d1439eSDmitry Baryshkov 398d6d1439eSDmitry Baryshkov /* 399d6d1439eSDmitry Baryshkov * PLL power up sequence. 400d6d1439eSDmitry Baryshkov * Add necessary delays recommended by hardware. 401d6d1439eSDmitry Baryshkov */ 402e55b3fbbSDmitry Baryshkov dsi_phy_write_ndelay(base + REG_DSI_28nm_PHY_PLL_CAL_CFG1, 0x34, 500); 403d6d1439eSDmitry Baryshkov 404d6d1439eSDmitry Baryshkov val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B; 405e55b3fbbSDmitry Baryshkov dsi_phy_write_ndelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500); 406d6d1439eSDmitry Baryshkov 407d6d1439eSDmitry Baryshkov val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B; 408e55b3fbbSDmitry Baryshkov dsi_phy_write_ndelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500); 409d6d1439eSDmitry Baryshkov 410d6d1439eSDmitry Baryshkov val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B | 411d6d1439eSDmitry Baryshkov DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE; 412e55b3fbbSDmitry Baryshkov dsi_phy_write_ndelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500); 413d6d1439eSDmitry Baryshkov 414d6d1439eSDmitry Baryshkov /* DSI PLL toggle lock detect setting */ 415e55b3fbbSDmitry Baryshkov dsi_phy_write_ndelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x04, 500); 416e55b3fbbSDmitry Baryshkov dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x05, 512); 417d6d1439eSDmitry Baryshkov 418d6d1439eSDmitry Baryshkov locked = pll_28nm_poll_for_ready(pll_28nm, max_reads, timeout_us); 419d6d1439eSDmitry Baryshkov 42062d5325dSDmitry Baryshkov if (unlikely(!locked)) { 421d6d1439eSDmitry Baryshkov DRM_DEV_ERROR(dev, "DSI PLL lock failed\n"); 42262d5325dSDmitry Baryshkov return -EINVAL; 423d6d1439eSDmitry Baryshkov } 424d6d1439eSDmitry Baryshkov 42562d5325dSDmitry Baryshkov DBG("DSI PLL lock success"); 426007687c3SDmitry Baryshkov pll_28nm->phy->pll_on = true; 42762d5325dSDmitry Baryshkov 42862d5325dSDmitry Baryshkov return 0; 42962d5325dSDmitry Baryshkov } 43062d5325dSDmitry Baryshkov 43162d5325dSDmitry Baryshkov static void dsi_pll_28nm_vco_unprepare(struct clk_hw *hw) 432d6d1439eSDmitry Baryshkov { 433007687c3SDmitry Baryshkov struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw); 434d6d1439eSDmitry Baryshkov 435d6d1439eSDmitry Baryshkov DBG("id=%d", pll_28nm->id); 43662d5325dSDmitry Baryshkov 437007687c3SDmitry Baryshkov if (unlikely(!pll_28nm->phy->pll_on)) 43862d5325dSDmitry Baryshkov return; 43962d5325dSDmitry Baryshkov 440*b7cf8a54SDmitry Baryshkov dsi_phy_write(pll_28nm->phy->pll_base + REG_DSI_28nm_PHY_PLL_GLB_CFG, 0x00); 44162d5325dSDmitry Baryshkov 442007687c3SDmitry Baryshkov pll_28nm->phy->pll_on = false; 443007687c3SDmitry Baryshkov } 444007687c3SDmitry Baryshkov 445007687c3SDmitry Baryshkov static long dsi_pll_28nm_clk_round_rate(struct clk_hw *hw, 446007687c3SDmitry Baryshkov unsigned long rate, unsigned long *parent_rate) 447007687c3SDmitry Baryshkov { 448007687c3SDmitry Baryshkov struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw); 449007687c3SDmitry Baryshkov 450007687c3SDmitry Baryshkov if (rate < pll_28nm->phy->cfg->min_pll_rate) 451007687c3SDmitry Baryshkov return pll_28nm->phy->cfg->min_pll_rate; 452007687c3SDmitry Baryshkov else if (rate > pll_28nm->phy->cfg->max_pll_rate) 453007687c3SDmitry Baryshkov return pll_28nm->phy->cfg->max_pll_rate; 454007687c3SDmitry Baryshkov else 455007687c3SDmitry Baryshkov return rate; 456d6d1439eSDmitry Baryshkov } 457d6d1439eSDmitry Baryshkov 45862d5325dSDmitry Baryshkov static const struct clk_ops clk_ops_dsi_pll_28nm_vco_hpm = { 459007687c3SDmitry Baryshkov .round_rate = dsi_pll_28nm_clk_round_rate, 46062d5325dSDmitry Baryshkov .set_rate = dsi_pll_28nm_clk_set_rate, 46162d5325dSDmitry Baryshkov .recalc_rate = dsi_pll_28nm_clk_recalc_rate, 46262d5325dSDmitry Baryshkov .prepare = dsi_pll_28nm_vco_prepare_hpm, 46362d5325dSDmitry Baryshkov .unprepare = dsi_pll_28nm_vco_unprepare, 46462d5325dSDmitry Baryshkov .is_enabled = dsi_pll_28nm_clk_is_enabled, 46562d5325dSDmitry Baryshkov }; 46662d5325dSDmitry Baryshkov 46762d5325dSDmitry Baryshkov static const struct clk_ops clk_ops_dsi_pll_28nm_vco_lp = { 468007687c3SDmitry Baryshkov .round_rate = dsi_pll_28nm_clk_round_rate, 46962d5325dSDmitry Baryshkov .set_rate = dsi_pll_28nm_clk_set_rate, 47062d5325dSDmitry Baryshkov .recalc_rate = dsi_pll_28nm_clk_recalc_rate, 47162d5325dSDmitry Baryshkov .prepare = dsi_pll_28nm_vco_prepare_lp, 47262d5325dSDmitry Baryshkov .unprepare = dsi_pll_28nm_vco_unprepare, 47362d5325dSDmitry Baryshkov .is_enabled = dsi_pll_28nm_clk_is_enabled, 47462d5325dSDmitry Baryshkov }; 47562d5325dSDmitry Baryshkov 47662d5325dSDmitry Baryshkov /* 47762d5325dSDmitry Baryshkov * PLL Callbacks 47862d5325dSDmitry Baryshkov */ 47962d5325dSDmitry Baryshkov 4802a831d9eSDmitry Baryshkov static void dsi_28nm_pll_save_state(struct msm_dsi_phy *phy) 481d6d1439eSDmitry Baryshkov { 482007687c3SDmitry Baryshkov struct dsi_pll_28nm *pll_28nm = to_pll_28nm(phy->vco_hw); 483d6d1439eSDmitry Baryshkov struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state; 484*b7cf8a54SDmitry Baryshkov void __iomem *base = pll_28nm->phy->pll_base; 485d6d1439eSDmitry Baryshkov 486d6d1439eSDmitry Baryshkov cached_state->postdiv3 = 487e55b3fbbSDmitry Baryshkov dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG); 488d6d1439eSDmitry Baryshkov cached_state->postdiv1 = 489e55b3fbbSDmitry Baryshkov dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG); 490e55b3fbbSDmitry Baryshkov cached_state->byte_mux = dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_VREG_CFG); 491007687c3SDmitry Baryshkov if (dsi_pll_28nm_clk_is_enabled(phy->vco_hw)) 492007687c3SDmitry Baryshkov cached_state->vco_rate = clk_hw_get_rate(phy->vco_hw); 493d6d1439eSDmitry Baryshkov else 494d6d1439eSDmitry Baryshkov cached_state->vco_rate = 0; 495d6d1439eSDmitry Baryshkov } 496d6d1439eSDmitry Baryshkov 4972a831d9eSDmitry Baryshkov static int dsi_28nm_pll_restore_state(struct msm_dsi_phy *phy) 498d6d1439eSDmitry Baryshkov { 499007687c3SDmitry Baryshkov struct dsi_pll_28nm *pll_28nm = to_pll_28nm(phy->vco_hw); 500d6d1439eSDmitry Baryshkov struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state; 501*b7cf8a54SDmitry Baryshkov void __iomem *base = pll_28nm->phy->pll_base; 502d6d1439eSDmitry Baryshkov int ret; 503d6d1439eSDmitry Baryshkov 504007687c3SDmitry Baryshkov ret = dsi_pll_28nm_clk_set_rate(phy->vco_hw, 505d6d1439eSDmitry Baryshkov cached_state->vco_rate, 0); 506d6d1439eSDmitry Baryshkov if (ret) { 507d6d1439eSDmitry Baryshkov DRM_DEV_ERROR(&pll_28nm->pdev->dev, 508d6d1439eSDmitry Baryshkov "restore vco rate failed. ret=%d\n", ret); 509d6d1439eSDmitry Baryshkov return ret; 510d6d1439eSDmitry Baryshkov } 511d6d1439eSDmitry Baryshkov 512e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG, 513d6d1439eSDmitry Baryshkov cached_state->postdiv3); 514e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG, 515d6d1439eSDmitry Baryshkov cached_state->postdiv1); 516e55b3fbbSDmitry Baryshkov dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_VREG_CFG, 517d6d1439eSDmitry Baryshkov cached_state->byte_mux); 518d6d1439eSDmitry Baryshkov 519d6d1439eSDmitry Baryshkov return 0; 520d6d1439eSDmitry Baryshkov } 521d6d1439eSDmitry Baryshkov 5225d134596SDmitry Baryshkov static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm, struct clk_hw **provided_clocks) 523d6d1439eSDmitry Baryshkov { 524d6d1439eSDmitry Baryshkov char clk_name[32], parent1[32], parent2[32], vco_name[32]; 525d6d1439eSDmitry Baryshkov struct clk_init_data vco_init = { 526d6d1439eSDmitry Baryshkov .parent_names = (const char *[]){ "xo" }, 527d6d1439eSDmitry Baryshkov .num_parents = 1, 528d6d1439eSDmitry Baryshkov .name = vco_name, 529d6d1439eSDmitry Baryshkov .flags = CLK_IGNORE_UNUSED, 530d6d1439eSDmitry Baryshkov }; 531d6d1439eSDmitry Baryshkov struct device *dev = &pll_28nm->pdev->dev; 532613cbd1dSDmitry Baryshkov struct clk_hw *hw; 533613cbd1dSDmitry Baryshkov int ret; 534d6d1439eSDmitry Baryshkov 535d6d1439eSDmitry Baryshkov DBG("%d", pll_28nm->id); 536d6d1439eSDmitry Baryshkov 537007687c3SDmitry Baryshkov if (pll_28nm->phy->cfg->quirks & DSI_PHY_28NM_QUIRK_PHY_LP) 53862d5325dSDmitry Baryshkov vco_init.ops = &clk_ops_dsi_pll_28nm_vco_lp; 53962d5325dSDmitry Baryshkov else 54062d5325dSDmitry Baryshkov vco_init.ops = &clk_ops_dsi_pll_28nm_vco_hpm; 54162d5325dSDmitry Baryshkov 542d6d1439eSDmitry Baryshkov snprintf(vco_name, 32, "dsi%dvco_clk", pll_28nm->id); 543007687c3SDmitry Baryshkov pll_28nm->clk_hw.init = &vco_init; 544007687c3SDmitry Baryshkov ret = devm_clk_hw_register(dev, &pll_28nm->clk_hw); 545613cbd1dSDmitry Baryshkov if (ret) 546613cbd1dSDmitry Baryshkov return ret; 547d6d1439eSDmitry Baryshkov 548d6d1439eSDmitry Baryshkov snprintf(clk_name, 32, "dsi%danalog_postdiv_clk", pll_28nm->id); 549d6d1439eSDmitry Baryshkov snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->id); 550613cbd1dSDmitry Baryshkov hw = devm_clk_hw_register_divider(dev, clk_name, 551d6d1439eSDmitry Baryshkov parent1, CLK_SET_RATE_PARENT, 552*b7cf8a54SDmitry Baryshkov pll_28nm->phy->pll_base + 553d6d1439eSDmitry Baryshkov REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG, 554d6d1439eSDmitry Baryshkov 0, 4, 0, NULL); 555613cbd1dSDmitry Baryshkov if (IS_ERR(hw)) 556613cbd1dSDmitry Baryshkov return PTR_ERR(hw); 557d6d1439eSDmitry Baryshkov 558d6d1439eSDmitry Baryshkov snprintf(clk_name, 32, "dsi%dindirect_path_div2_clk", pll_28nm->id); 559d6d1439eSDmitry Baryshkov snprintf(parent1, 32, "dsi%danalog_postdiv_clk", pll_28nm->id); 560613cbd1dSDmitry Baryshkov hw = devm_clk_hw_register_fixed_factor(dev, clk_name, 561d6d1439eSDmitry Baryshkov parent1, CLK_SET_RATE_PARENT, 562d6d1439eSDmitry Baryshkov 1, 2); 563613cbd1dSDmitry Baryshkov if (IS_ERR(hw)) 564613cbd1dSDmitry Baryshkov return PTR_ERR(hw); 565d6d1439eSDmitry Baryshkov 566d6d1439eSDmitry Baryshkov snprintf(clk_name, 32, "dsi%dpll", pll_28nm->id); 567d6d1439eSDmitry Baryshkov snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->id); 568613cbd1dSDmitry Baryshkov hw = devm_clk_hw_register_divider(dev, clk_name, 569*b7cf8a54SDmitry Baryshkov parent1, 0, pll_28nm->phy->pll_base + 570d6d1439eSDmitry Baryshkov REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG, 571d6d1439eSDmitry Baryshkov 0, 8, 0, NULL); 572613cbd1dSDmitry Baryshkov if (IS_ERR(hw)) 573613cbd1dSDmitry Baryshkov return PTR_ERR(hw); 574613cbd1dSDmitry Baryshkov provided_clocks[DSI_PIXEL_PLL_CLK] = hw; 575d6d1439eSDmitry Baryshkov 576d6d1439eSDmitry Baryshkov snprintf(clk_name, 32, "dsi%dbyte_mux", pll_28nm->id); 577d6d1439eSDmitry Baryshkov snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->id); 578d6d1439eSDmitry Baryshkov snprintf(parent2, 32, "dsi%dindirect_path_div2_clk", pll_28nm->id); 579613cbd1dSDmitry Baryshkov hw = devm_clk_hw_register_mux(dev, clk_name, 580d6d1439eSDmitry Baryshkov ((const char *[]){ 581d6d1439eSDmitry Baryshkov parent1, parent2 582*b7cf8a54SDmitry Baryshkov }), 2, CLK_SET_RATE_PARENT, pll_28nm->phy->pll_base + 583d6d1439eSDmitry Baryshkov REG_DSI_28nm_PHY_PLL_VREG_CFG, 1, 1, 0, NULL); 584613cbd1dSDmitry Baryshkov if (IS_ERR(hw)) 585613cbd1dSDmitry Baryshkov return PTR_ERR(hw); 586d6d1439eSDmitry Baryshkov 587d6d1439eSDmitry Baryshkov snprintf(clk_name, 32, "dsi%dpllbyte", pll_28nm->id); 588d6d1439eSDmitry Baryshkov snprintf(parent1, 32, "dsi%dbyte_mux", pll_28nm->id); 589613cbd1dSDmitry Baryshkov hw = devm_clk_hw_register_fixed_factor(dev, clk_name, 590d6d1439eSDmitry Baryshkov parent1, CLK_SET_RATE_PARENT, 1, 4); 591613cbd1dSDmitry Baryshkov if (IS_ERR(hw)) 592613cbd1dSDmitry Baryshkov return PTR_ERR(hw); 593613cbd1dSDmitry Baryshkov provided_clocks[DSI_BYTE_PLL_CLK] = hw; 594d6d1439eSDmitry Baryshkov 595d6d1439eSDmitry Baryshkov return 0; 596d6d1439eSDmitry Baryshkov } 597d6d1439eSDmitry Baryshkov 59893cf7d62SDmitry Baryshkov static int dsi_pll_28nm_init(struct msm_dsi_phy *phy) 599d6d1439eSDmitry Baryshkov { 60093cf7d62SDmitry Baryshkov struct platform_device *pdev = phy->pdev; 60193cf7d62SDmitry Baryshkov int id = phy->id; 602d6d1439eSDmitry Baryshkov struct dsi_pll_28nm *pll_28nm; 603d6d1439eSDmitry Baryshkov int ret; 604d6d1439eSDmitry Baryshkov 605d6d1439eSDmitry Baryshkov if (!pdev) 60693cf7d62SDmitry Baryshkov return -ENODEV; 607d6d1439eSDmitry Baryshkov 608d6d1439eSDmitry Baryshkov pll_28nm = devm_kzalloc(&pdev->dev, sizeof(*pll_28nm), GFP_KERNEL); 609d6d1439eSDmitry Baryshkov if (!pll_28nm) 61093cf7d62SDmitry Baryshkov return -ENOMEM; 611d6d1439eSDmitry Baryshkov 612d6d1439eSDmitry Baryshkov pll_28nm->pdev = pdev; 613d6d1439eSDmitry Baryshkov pll_28nm->id = id; 614007687c3SDmitry Baryshkov pll_28nm->phy = phy; 615d6d1439eSDmitry Baryshkov 6165d134596SDmitry Baryshkov ret = pll_28nm_register(pll_28nm, phy->provided_clocks->hws); 617d6d1439eSDmitry Baryshkov if (ret) { 618d6d1439eSDmitry Baryshkov DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret); 61993cf7d62SDmitry Baryshkov return ret; 620d6d1439eSDmitry Baryshkov } 621d6d1439eSDmitry Baryshkov 622007687c3SDmitry Baryshkov phy->vco_hw = &pll_28nm->clk_hw; 623d6d1439eSDmitry Baryshkov 62493cf7d62SDmitry Baryshkov return 0; 62593cf7d62SDmitry Baryshkov } 626d6d1439eSDmitry Baryshkov 6275c829028SHai Li static void dsi_28nm_dphy_set_timing(struct msm_dsi_phy *phy, 6285c829028SHai Li struct msm_dsi_dphy_timing *timing) 6295c829028SHai Li { 6305c829028SHai Li void __iomem *base = phy->base; 6315c829028SHai Li 6325c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_0, 6335c829028SHai Li DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO(timing->clk_zero)); 6345c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_1, 6355c829028SHai Li DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL(timing->clk_trail)); 6365c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_2, 6375c829028SHai Li DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE(timing->clk_prepare)); 6385c829028SHai Li if (timing->clk_zero & BIT(8)) 6395c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_3, 6405c829028SHai Li DSI_28nm_PHY_TIMING_CTRL_3_CLK_ZERO_8); 6415c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_4, 6425c829028SHai Li DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT(timing->hs_exit)); 6435c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_5, 6445c829028SHai Li DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO(timing->hs_zero)); 6455c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_6, 6465c829028SHai Li DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE(timing->hs_prepare)); 6475c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_7, 6485c829028SHai Li DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL(timing->hs_trail)); 6495c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_8, 6505c829028SHai Li DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST(timing->hs_rqst)); 6515c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_9, 6525c829028SHai Li DSI_28nm_PHY_TIMING_CTRL_9_TA_GO(timing->ta_go) | 6535c829028SHai Li DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE(timing->ta_sure)); 6545c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_10, 6555c829028SHai Li DSI_28nm_PHY_TIMING_CTRL_10_TA_GET(timing->ta_get)); 6565c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_11, 6575c829028SHai Li DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD(0)); 6585c829028SHai Li } 6595c829028SHai Li 66049c4868aSStephan Gerhold static void dsi_28nm_phy_regulator_enable_dcdc(struct msm_dsi_phy *phy) 6615c829028SHai Li { 6625c829028SHai Li void __iomem *base = phy->reg_base; 6635c829028SHai Li 6645c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x0); 6655c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 1); 6665c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_5, 0); 6675c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_3, 0); 6685c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_2, 0x3); 6695c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_1, 0x9); 6705c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x7); 6715c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_4, 0x20); 67249c4868aSStephan Gerhold dsi_phy_write(phy->base + REG_DSI_28nm_PHY_LDO_CNTRL, 0x00); 67349c4868aSStephan Gerhold } 67449c4868aSStephan Gerhold 67549c4868aSStephan Gerhold static void dsi_28nm_phy_regulator_enable_ldo(struct msm_dsi_phy *phy) 67649c4868aSStephan Gerhold { 67749c4868aSStephan Gerhold void __iomem *base = phy->reg_base; 67849c4868aSStephan Gerhold 67949c4868aSStephan Gerhold dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x0); 68049c4868aSStephan Gerhold dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 0); 68149c4868aSStephan Gerhold dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_5, 0x7); 68249c4868aSStephan Gerhold dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_3, 0); 68349c4868aSStephan Gerhold dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_2, 0x1); 68449c4868aSStephan Gerhold dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_1, 0x1); 68549c4868aSStephan Gerhold dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_4, 0x20); 68649c4868aSStephan Gerhold 68780d2229bSDmitry Baryshkov if (phy->cfg->quirks & DSI_PHY_28NM_QUIRK_PHY_LP) 68849c4868aSStephan Gerhold dsi_phy_write(phy->base + REG_DSI_28nm_PHY_LDO_CNTRL, 0x05); 68949c4868aSStephan Gerhold else 69049c4868aSStephan Gerhold dsi_phy_write(phy->base + REG_DSI_28nm_PHY_LDO_CNTRL, 0x0d); 69149c4868aSStephan Gerhold } 69249c4868aSStephan Gerhold 69349c4868aSStephan Gerhold static void dsi_28nm_phy_regulator_ctrl(struct msm_dsi_phy *phy, bool enable) 69449c4868aSStephan Gerhold { 69549c4868aSStephan Gerhold if (!enable) { 69649c4868aSStephan Gerhold dsi_phy_write(phy->reg_base + 69749c4868aSStephan Gerhold REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 0); 69849c4868aSStephan Gerhold return; 69949c4868aSStephan Gerhold } 70049c4868aSStephan Gerhold 70149c4868aSStephan Gerhold if (phy->regulator_ldo_mode) 70249c4868aSStephan Gerhold dsi_28nm_phy_regulator_enable_ldo(phy); 70349c4868aSStephan Gerhold else 70449c4868aSStephan Gerhold dsi_28nm_phy_regulator_enable_dcdc(phy); 7055c829028SHai Li } 7065c829028SHai Li 7075c829028SHai Li static int dsi_28nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id, 708b62aa70aSHai Li struct msm_dsi_phy_clk_request *clk_req) 7095c829028SHai Li { 7105c829028SHai Li struct msm_dsi_dphy_timing *timing = &phy->timing; 7115c829028SHai Li int i; 7125c829028SHai Li void __iomem *base = phy->base; 7135c829028SHai Li 7145c829028SHai Li DBG(""); 7155c829028SHai Li 716b62aa70aSHai Li if (msm_dsi_dphy_timing_calc(timing, clk_req)) { 7176a41da17SMamta Shukla DRM_DEV_ERROR(&phy->pdev->dev, 7185c829028SHai Li "%s: D-PHY timing calculation failed\n", __func__); 7195c829028SHai Li return -EINVAL; 7205c829028SHai Li } 7215c829028SHai Li 7225c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_STRENGTH_0, 0xff); 7235c829028SHai Li 7245c829028SHai Li dsi_28nm_phy_regulator_ctrl(phy, true); 7255c829028SHai Li 7265c829028SHai Li dsi_28nm_dphy_set_timing(phy, timing); 7275c829028SHai Li 7285c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_1, 0x00); 7295c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_0, 0x5f); 7305c829028SHai Li 7315c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_STRENGTH_1, 0x6); 7325c829028SHai Li 7335c829028SHai Li for (i = 0; i < 4; i++) { 7345c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_0(i), 0); 7355c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_1(i), 0); 7365c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_2(i), 0); 7375c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_3(i), 0); 738e01b1bfdSHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(i), 0); 7395c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_DATAPATH(i), 0); 7405c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_LN_DEBUG_SEL(i), 0); 7415c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_STR_0(i), 0x1); 7425c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_STR_1(i), 0x97); 7435c829028SHai Li } 7445c829028SHai Li 745e01b1bfdSHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_CFG_4, 0); 7465c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_CFG_1, 0xc0); 7475c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_TEST_STR0, 0x1); 7485c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_TEST_STR1, 0xbb); 7495c829028SHai Li 7505c829028SHai Li dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_0, 0x5f); 7515c829028SHai Li 7525c829028SHai Li msm_dsi_phy_set_src_pll(phy, src_pll_id, 7535c829028SHai Li REG_DSI_28nm_PHY_GLBL_TEST_CTRL, 7545c829028SHai Li DSI_28nm_PHY_GLBL_TEST_CTRL_BITCLK_HS_SEL); 7555c829028SHai Li 7565c829028SHai Li return 0; 7575c829028SHai Li } 7585c829028SHai Li 7595c829028SHai Li static void dsi_28nm_phy_disable(struct msm_dsi_phy *phy) 7605c829028SHai Li { 7615c829028SHai Li dsi_phy_write(phy->base + REG_DSI_28nm_PHY_CTRL_0, 0); 7625c829028SHai Li dsi_28nm_phy_regulator_ctrl(phy, false); 7635c829028SHai Li 7645c829028SHai Li /* 7655c829028SHai Li * Wait for the registers writes to complete in order to 7665c829028SHai Li * ensure that the phy is completely disabled 7675c829028SHai Li */ 7685c829028SHai Li wmb(); 7695c829028SHai Li } 7705c829028SHai Li 7715c829028SHai Li const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_cfgs = { 7725c829028SHai Li .src_pll_truthtable = { {true, true}, {false, true} }, 773266a4e58SDmitry Baryshkov .has_phy_regulator = true, 7745c829028SHai Li .reg_cfg = { 7755c829028SHai Li .num = 1, 7765c829028SHai Li .regs = { 777f377d597SArchit Taneja {"vddio", 100000, 100}, 7785c829028SHai Li }, 7795c829028SHai Li }, 7805c829028SHai Li .ops = { 7815c829028SHai Li .enable = dsi_28nm_phy_enable, 7825c829028SHai Li .disable = dsi_28nm_phy_disable, 78393cf7d62SDmitry Baryshkov .pll_init = dsi_pll_28nm_init, 7842a831d9eSDmitry Baryshkov .save_pll_state = dsi_28nm_pll_save_state, 7852a831d9eSDmitry Baryshkov .restore_pll_state = dsi_28nm_pll_restore_state, 7865c829028SHai Li }, 787076437c9SDmitry Baryshkov .min_pll_rate = VCO_MIN_RATE, 788076437c9SDmitry Baryshkov .max_pll_rate = VCO_MAX_RATE, 78932280d66SArchit Taneja .io_start = { 0xfd922b00, 0xfd923100 }, 79032280d66SArchit Taneja .num_dsi_phy = 2, 7915c829028SHai Li }; 7925c829028SHai Li 793332d6084SAngeloGioacchino Del Regno const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_famb_cfgs = { 794332d6084SAngeloGioacchino Del Regno .src_pll_truthtable = { {true, true}, {false, true} }, 795266a4e58SDmitry Baryshkov .has_phy_regulator = true, 796332d6084SAngeloGioacchino Del Regno .reg_cfg = { 797332d6084SAngeloGioacchino Del Regno .num = 1, 798332d6084SAngeloGioacchino Del Regno .regs = { 799332d6084SAngeloGioacchino Del Regno {"vddio", 100000, 100}, 800332d6084SAngeloGioacchino Del Regno }, 801332d6084SAngeloGioacchino Del Regno }, 802332d6084SAngeloGioacchino Del Regno .ops = { 803332d6084SAngeloGioacchino Del Regno .enable = dsi_28nm_phy_enable, 804332d6084SAngeloGioacchino Del Regno .disable = dsi_28nm_phy_disable, 80593cf7d62SDmitry Baryshkov .pll_init = dsi_pll_28nm_init, 8062a831d9eSDmitry Baryshkov .save_pll_state = dsi_28nm_pll_save_state, 8072a831d9eSDmitry Baryshkov .restore_pll_state = dsi_28nm_pll_restore_state, 808332d6084SAngeloGioacchino Del Regno }, 809076437c9SDmitry Baryshkov .min_pll_rate = VCO_MIN_RATE, 810076437c9SDmitry Baryshkov .max_pll_rate = VCO_MAX_RATE, 811332d6084SAngeloGioacchino Del Regno .io_start = { 0x1a94400, 0x1a96400 }, 812332d6084SAngeloGioacchino Del Regno .num_dsi_phy = 2, 813332d6084SAngeloGioacchino Del Regno }; 814332d6084SAngeloGioacchino Del Regno 8155c829028SHai Li const struct msm_dsi_phy_cfg dsi_phy_28nm_lp_cfgs = { 8165c829028SHai Li .src_pll_truthtable = { {true, true}, {true, true} }, 817266a4e58SDmitry Baryshkov .has_phy_regulator = true, 8185c829028SHai Li .reg_cfg = { 8195c829028SHai Li .num = 1, 8205c829028SHai Li .regs = { 821f377d597SArchit Taneja {"vddio", 100000, 100}, /* 1.8 V */ 8225c829028SHai Li }, 8235c829028SHai Li }, 8245c829028SHai Li .ops = { 8255c829028SHai Li .enable = dsi_28nm_phy_enable, 8265c829028SHai Li .disable = dsi_28nm_phy_disable, 82793cf7d62SDmitry Baryshkov .pll_init = dsi_pll_28nm_init, 8282a831d9eSDmitry Baryshkov .save_pll_state = dsi_28nm_pll_save_state, 8292a831d9eSDmitry Baryshkov .restore_pll_state = dsi_28nm_pll_restore_state, 8305c829028SHai Li }, 831076437c9SDmitry Baryshkov .min_pll_rate = VCO_MIN_RATE, 832076437c9SDmitry Baryshkov .max_pll_rate = VCO_MAX_RATE, 83332280d66SArchit Taneja .io_start = { 0x1a98500 }, 83432280d66SArchit Taneja .num_dsi_phy = 1, 83580d2229bSDmitry Baryshkov .quirks = DSI_PHY_28NM_QUIRK_PHY_LP, 8365c829028SHai Li }; 8375c829028SHai Li 838