1/* 2 * Copyright (c) 2015, The Linux Foundation. All rights reserved. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 and 6 * only version 2 as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 */ 13 14#include "dsi.h" 15#include "dsi.xml.h" 16 17#define dsi_phy_read(offset) msm_readl((offset)) 18#define dsi_phy_write(offset, data) msm_writel((data), (offset)) 19 20struct dsi_dphy_timing { 21 u32 clk_pre; 22 u32 clk_post; 23 u32 clk_zero; 24 u32 clk_trail; 25 u32 clk_prepare; 26 u32 hs_exit; 27 u32 hs_zero; 28 u32 hs_prepare; 29 u32 hs_trail; 30 u32 hs_rqst; 31 u32 ta_go; 32 u32 ta_sure; 33 u32 ta_get; 34}; 35 36struct msm_dsi_phy { 37 void __iomem *base; 38 void __iomem *reg_base; 39 int id; 40 struct dsi_dphy_timing timing; 41 int (*enable)(struct msm_dsi_phy *phy, bool is_dual_panel, 42 const unsigned long bit_rate, const unsigned long esc_rate); 43 int (*disable)(struct msm_dsi_phy *phy); 44}; 45 46#define S_DIV_ROUND_UP(n, d) \ 47 (((n) >= 0) ? (((n) + (d) - 1) / (d)) : (((n) - (d) + 1) / (d))) 48 49static inline s32 linear_inter(s32 tmax, s32 tmin, s32 percent, 50 s32 min_result, bool even) 51{ 52 s32 v; 53 v = (tmax - tmin) * percent; 54 v = S_DIV_ROUND_UP(v, 100) + tmin; 55 if (even && (v & 0x1)) 56 return max_t(s32, min_result, v - 1); 57 else 58 return max_t(s32, min_result, v); 59} 60 61static void dsi_dphy_timing_calc_clk_zero(struct dsi_dphy_timing *timing, 62 s32 ui, s32 coeff, s32 pcnt) 63{ 64 s32 tmax, tmin, clk_z; 65 s32 temp; 66 67 /* reset */ 68 temp = 300 * coeff - ((timing->clk_prepare >> 1) + 1) * 2 * ui; 69 tmin = S_DIV_ROUND_UP(temp, ui) - 2; 70 if (tmin > 255) { 71 tmax = 511; 72 clk_z = linear_inter(2 * tmin, tmin, pcnt, 0, true); 73 } else { 74 tmax = 255; 75 clk_z = linear_inter(tmax, tmin, pcnt, 0, true); 76 } 77 78 /* adjust */ 79 temp = (timing->hs_rqst + timing->clk_prepare + clk_z) & 0x7; 80 timing->clk_zero = clk_z + 8 - temp; 81} 82 83static int dsi_dphy_timing_calc(struct dsi_dphy_timing *timing, 84 const unsigned long bit_rate, const unsigned long esc_rate) 85{ 86 s32 ui, lpx; 87 s32 tmax, tmin; 88 s32 pcnt0 = 10; 89 s32 pcnt1 = (bit_rate > 1200000000) ? 15 : 10; 90 s32 pcnt2 = 10; 91 s32 pcnt3 = (bit_rate > 180000000) ? 10 : 40; 92 s32 coeff = 1000; /* Precision, should avoid overflow */ 93 s32 temp; 94 95 if (!bit_rate || !esc_rate) 96 return -EINVAL; 97 98 ui = mult_frac(NSEC_PER_MSEC, coeff, bit_rate / 1000); 99 lpx = mult_frac(NSEC_PER_MSEC, coeff, esc_rate / 1000); 100 101 tmax = S_DIV_ROUND_UP(95 * coeff, ui) - 2; 102 tmin = S_DIV_ROUND_UP(38 * coeff, ui) - 2; 103 timing->clk_prepare = linear_inter(tmax, tmin, pcnt0, 0, true); 104 105 temp = lpx / ui; 106 if (temp & 0x1) 107 timing->hs_rqst = temp; 108 else 109 timing->hs_rqst = max_t(s32, 0, temp - 2); 110 111 /* Calculate clk_zero after clk_prepare and hs_rqst */ 112 dsi_dphy_timing_calc_clk_zero(timing, ui, coeff, pcnt2); 113 114 temp = 105 * coeff + 12 * ui - 20 * coeff; 115 tmax = S_DIV_ROUND_UP(temp, ui) - 2; 116 tmin = S_DIV_ROUND_UP(60 * coeff, ui) - 2; 117 timing->clk_trail = linear_inter(tmax, tmin, pcnt3, 0, true); 118 119 temp = 85 * coeff + 6 * ui; 120 tmax = S_DIV_ROUND_UP(temp, ui) - 2; 121 temp = 40 * coeff + 4 * ui; 122 tmin = S_DIV_ROUND_UP(temp, ui) - 2; 123 timing->hs_prepare = linear_inter(tmax, tmin, pcnt1, 0, true); 124 125 tmax = 255; 126 temp = ((timing->hs_prepare >> 1) + 1) * 2 * ui + 2 * ui; 127 temp = 145 * coeff + 10 * ui - temp; 128 tmin = S_DIV_ROUND_UP(temp, ui) - 2; 129 timing->hs_zero = linear_inter(tmax, tmin, pcnt2, 24, true); 130 131 temp = 105 * coeff + 12 * ui - 20 * coeff; 132 tmax = S_DIV_ROUND_UP(temp, ui) - 2; 133 temp = 60 * coeff + 4 * ui; 134 tmin = DIV_ROUND_UP(temp, ui) - 2; 135 timing->hs_trail = linear_inter(tmax, tmin, pcnt3, 0, true); 136 137 tmax = 255; 138 tmin = S_DIV_ROUND_UP(100 * coeff, ui) - 2; 139 timing->hs_exit = linear_inter(tmax, tmin, pcnt2, 0, true); 140 141 tmax = 63; 142 temp = ((timing->hs_exit >> 1) + 1) * 2 * ui; 143 temp = 60 * coeff + 52 * ui - 24 * ui - temp; 144 tmin = S_DIV_ROUND_UP(temp, 8 * ui) - 1; 145 timing->clk_post = linear_inter(tmax, tmin, pcnt2, 0, false); 146 147 tmax = 63; 148 temp = ((timing->clk_prepare >> 1) + 1) * 2 * ui; 149 temp += ((timing->clk_zero >> 1) + 1) * 2 * ui; 150 temp += 8 * ui + lpx; 151 tmin = S_DIV_ROUND_UP(temp, 8 * ui) - 1; 152 if (tmin > tmax) { 153 temp = linear_inter(2 * tmax, tmin, pcnt2, 0, false) >> 1; 154 timing->clk_pre = temp >> 1; 155 temp = (2 * tmax - tmin) * pcnt2; 156 } else { 157 timing->clk_pre = linear_inter(tmax, tmin, pcnt2, 0, false); 158 } 159 160 timing->ta_go = 3; 161 timing->ta_sure = 0; 162 timing->ta_get = 4; 163 164 DBG("PHY timings: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d", 165 timing->clk_pre, timing->clk_post, timing->clk_zero, 166 timing->clk_trail, timing->clk_prepare, timing->hs_exit, 167 timing->hs_zero, timing->hs_prepare, timing->hs_trail, 168 timing->hs_rqst); 169 170 return 0; 171} 172 173static void dsi_28nm_phy_regulator_ctrl(struct msm_dsi_phy *phy, bool enable) 174{ 175 void __iomem *base = phy->reg_base; 176 177 if (!enable) { 178 dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 0); 179 return; 180 } 181 182 dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x0); 183 dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 1); 184 dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_5, 0); 185 dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_3, 0); 186 dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_2, 0x3); 187 dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_1, 0x9); 188 dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x7); 189 dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_4, 0x20); 190} 191 192static int dsi_28nm_phy_enable(struct msm_dsi_phy *phy, bool is_dual_panel, 193 const unsigned long bit_rate, const unsigned long esc_rate) 194{ 195 struct dsi_dphy_timing *timing = &phy->timing; 196 int i; 197 void __iomem *base = phy->base; 198 199 DBG(""); 200 201 if (dsi_dphy_timing_calc(timing, bit_rate, esc_rate)) { 202 pr_err("%s: D-PHY timing calculation failed\n", __func__); 203 return -EINVAL; 204 } 205 206 dsi_phy_write(base + REG_DSI_28nm_PHY_STRENGTH_0, 0xff); 207 208 dsi_28nm_phy_regulator_ctrl(phy, true); 209 210 dsi_phy_write(base + REG_DSI_28nm_PHY_LDO_CNTRL, 0x00); 211 212 dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_0, 213 DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO(timing->clk_zero)); 214 dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_1, 215 DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL(timing->clk_trail)); 216 dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_2, 217 DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE(timing->clk_prepare)); 218 if (timing->clk_zero & BIT(8)) 219 dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_3, 220 DSI_28nm_PHY_TIMING_CTRL_3_CLK_ZERO_8); 221 dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_4, 222 DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT(timing->hs_exit)); 223 dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_5, 224 DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO(timing->hs_zero)); 225 dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_6, 226 DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE(timing->hs_prepare)); 227 dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_7, 228 DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL(timing->hs_trail)); 229 dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_8, 230 DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST(timing->hs_rqst)); 231 dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_9, 232 DSI_28nm_PHY_TIMING_CTRL_9_TA_GO(timing->ta_go) | 233 DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE(timing->ta_sure)); 234 dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_10, 235 DSI_28nm_PHY_TIMING_CTRL_10_TA_GET(timing->ta_get)); 236 dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_11, 237 DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD(0)); 238 239 dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_1, 0x00); 240 dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_0, 0x5f); 241 242 dsi_phy_write(base + REG_DSI_28nm_PHY_STRENGTH_1, 0x6); 243 244 for (i = 0; i < 4; i++) { 245 dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_0(i), 0); 246 dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_1(i), 0); 247 dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_2(i), 0); 248 dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_3(i), 0); 249 dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_DATAPATH(i), 0); 250 dsi_phy_write(base + REG_DSI_28nm_PHY_LN_DEBUG_SEL(i), 0); 251 dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_STR_0(i), 0x1); 252 dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_STR_1(i), 0x97); 253 } 254 dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(0), 0); 255 dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(1), 0x5); 256 dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(2), 0xa); 257 dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(3), 0xf); 258 259 dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_CFG_1, 0xc0); 260 dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_TEST_STR0, 0x1); 261 dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_TEST_STR1, 0xbb); 262 263 dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_0, 0x5f); 264 265 if (is_dual_panel && (phy->id != DSI_CLOCK_MASTER)) 266 dsi_phy_write(base + REG_DSI_28nm_PHY_GLBL_TEST_CTRL, 0x00); 267 else 268 dsi_phy_write(base + REG_DSI_28nm_PHY_GLBL_TEST_CTRL, 0x01); 269 270 return 0; 271} 272 273static int dsi_28nm_phy_disable(struct msm_dsi_phy *phy) 274{ 275 dsi_phy_write(phy->base + REG_DSI_28nm_PHY_CTRL_0, 0); 276 dsi_28nm_phy_regulator_ctrl(phy, false); 277 278 /* 279 * Wait for the registers writes to complete in order to 280 * ensure that the phy is completely disabled 281 */ 282 wmb(); 283 284 return 0; 285} 286 287#define dsi_phy_func_init(name) \ 288 do { \ 289 phy->enable = dsi_##name##_phy_enable; \ 290 phy->disable = dsi_##name##_phy_disable; \ 291 } while (0) 292 293struct msm_dsi_phy *msm_dsi_phy_init(struct platform_device *pdev, 294 enum msm_dsi_phy_type type, int id) 295{ 296 struct msm_dsi_phy *phy; 297 298 phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL); 299 if (!phy) 300 return NULL; 301 302 phy->base = msm_ioremap(pdev, "dsi_phy", "DSI_PHY"); 303 if (IS_ERR_OR_NULL(phy->base)) { 304 pr_err("%s: failed to map phy base\n", __func__); 305 return NULL; 306 } 307 phy->reg_base = msm_ioremap(pdev, "dsi_phy_regulator", "DSI_PHY_REG"); 308 if (IS_ERR_OR_NULL(phy->reg_base)) { 309 pr_err("%s: failed to map phy regulator base\n", __func__); 310 return NULL; 311 } 312 313 switch (type) { 314 case MSM_DSI_PHY_28NM: 315 dsi_phy_func_init(28nm); 316 break; 317 default: 318 pr_err("%s: unsupported type, %d\n", __func__, type); 319 return NULL; 320 } 321 322 phy->id = id; 323 324 return phy; 325} 326 327int msm_dsi_phy_enable(struct msm_dsi_phy *phy, bool is_dual_panel, 328 const unsigned long bit_rate, const unsigned long esc_rate) 329{ 330 if (!phy || !phy->enable) 331 return -EINVAL; 332 return phy->enable(phy, is_dual_panel, bit_rate, esc_rate); 333} 334 335int msm_dsi_phy_disable(struct msm_dsi_phy *phy) 336{ 337 if (!phy || !phy->disable) 338 return -EINVAL; 339 return phy->disable(phy); 340} 341 342void msm_dsi_phy_get_clk_pre_post(struct msm_dsi_phy *phy, 343 u32 *clk_pre, u32 *clk_post) 344{ 345 if (!phy) 346 return; 347 if (clk_pre) 348 *clk_pre = phy->timing.clk_pre; 349 if (clk_post) 350 *clk_post = phy->timing.clk_post; 351} 352 353