1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2008-2018 Fuzhou Rockchip Electronics Co., Ltd 4 * 5 * Author: Wyon Bi <bivvy.bi@rock-chips.com> 6 */ 7 8 #include <config.h> 9 #include <common.h> 10 #include <errno.h> 11 #include <dm.h> 12 #include <div64.h> 13 #include <asm/io.h> 14 #include <linux/ioport.h> 15 #include <linux/iopoll.h> 16 #include <linux/math64.h> 17 18 #include "rk628.h" 19 #include "rk628_cru.h" 20 #include "rk628_combtxphy.h" 21 22 static void rk628_combtxphy_dsi_power_on(struct rk628 *rk628) 23 { 24 struct rk628_combtxphy *combtxphy = &rk628->combtxphy; 25 u32 val = 0; 26 int ret; 27 28 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0, SW_BUS_WIDTH_MASK | 29 SW_GVI_LVDS_EN_MASK | SW_MIPI_DSI_EN_MASK, 30 SW_BUS_WIDTH_8BIT | SW_MIPI_DSI_EN); 31 32 if (combtxphy->flags & COMBTXPHY_MODULEA_EN) 33 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0, 34 SW_MODULEA_EN_MASK, SW_MODULEA_EN); 35 36 if (combtxphy->flags & COMBTXPHY_MODULEB_EN) 37 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0, 38 SW_MODULEB_EN_MASK, SW_MODULEB_EN); 39 40 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0, SW_PD_PLL, SW_PD_PLL); 41 42 if (combtxphy->frac_div) 43 rk628_i2c_update_bits(rk628, COMBTXPHY_CON8, SW_SSC_DEPTH_MASK | SW_SSC_EN_MASK, 44 SW_SSC_DEPTH(0) | SW_SSC_EN(1)); 45 46 rk628_i2c_write(rk628, COMBTXPHY_CON5, 47 SW_REF_DIV(combtxphy->ref_div - 1) | 48 SW_PLL_FB_DIV(combtxphy->fb_div) | 49 SW_PLL_FRAC_DIV(combtxphy->frac_div) | 50 SW_RATE(combtxphy->rate_div / 2)); 51 52 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0, SW_PD_PLL, 0); 53 54 ret = rk628_read_poll_timeout(rk628, GRF_DPHY0_STATUS, val, 55 val & DPHY_PHYLOCK, 0, 1000); 56 if (ret < 0) 57 printf("rk628 phy is not lock\n"); 58 59 rk628_i2c_update_bits(rk628, COMBTXPHY_CON9, 60 SW_DSI_FSET_EN_MASK | SW_DSI_RCAL_EN_MASK, 61 SW_DSI_FSET_EN | SW_DSI_RCAL_EN(1)); 62 63 if (rk628->version == RK628F_VERSION) { 64 rk628_i2c_update_bits(rk628, COMBTXPHY_CON6, 65 SW_PLL_CTL_CON0_MASK, 66 SW_PLL_CTL_CON0(1)); 67 rk628_i2c_update_bits(rk628, COMBTXPHY_CON9, 68 SW_DSI_LPTX_SR_TRIM_MASK | 69 SW_DSI_HSTX_AMP_TRIM_MASK, 70 SW_DSI_LPTX_SR_TRIM(0) | 71 SW_DSI_HSTX_AMP_TRIM(4)); 72 } 73 74 udelay(400); 75 } 76 77 static void rk628_combtxphy_lvds_power_on(struct rk628 *rk628) 78 { 79 80 struct rk628_combtxphy *combtxphy = &rk628->combtxphy; 81 u32 val; 82 int ret; 83 84 /* Adjust terminal resistance 133 ohm, bypass 0.95v ldo for driver. */ 85 if (rk628->version == RK628F_VERSION) 86 val = TX_COM_VOLT_ADJ(3); 87 else 88 val = TX_COM_VOLT_ADJ(0); 89 rk628_i2c_update_bits(rk628, COMBTXPHY_CON7, 90 SW_TX_RTERM_MASK | SW_TX_MODE_MASK | 91 BYPASS_095V_LDO_MASK | TX_COM_VOLT_ADJ_MASK, 92 SW_TX_RTERM(6) | SW_TX_MODE(3) | 93 BYPASS_095V_LDO(1) | val); 94 95 rk628_i2c_write(rk628, COMBTXPHY_CON10, TX7_CKDRV_EN | TX2_CKDRV_EN); 96 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0, 97 SW_BUS_WIDTH_MASK | SW_GVI_LVDS_EN_MASK | 98 SW_MIPI_DSI_EN_MASK, 99 SW_BUS_WIDTH_7BIT | SW_GVI_LVDS_EN); 100 101 if (combtxphy->flags & COMBTXPHY_MODULEA_EN) 102 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0, 103 SW_MODULEA_EN_MASK, SW_MODULEA_EN); 104 105 if (combtxphy->flags & COMBTXPHY_MODULEB_EN) 106 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0, 107 SW_MODULEB_EN_MASK, SW_MODULEB_EN); 108 109 rk628_i2c_write(rk628, COMBTXPHY_CON5, 110 SW_REF_DIV(combtxphy->ref_div - 1) | 111 SW_PLL_FB_DIV(combtxphy->fb_div) | 112 SW_PLL_FRAC_DIV(combtxphy->frac_div) | 113 SW_RATE(combtxphy->rate_div / 2)); 114 115 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0, 116 SW_PD_PLL, 0); 117 118 ret = rk628_read_poll_timeout(rk628, GRF_DPHY0_STATUS, val, 119 val & DPHY_PHYLOCK, 0, 1000); 120 if (ret < 0) 121 printf("rk628 phy is not lock\n"); 122 123 udelay(200); 124 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0, SW_TX_IDLE_MASK | SW_TX_PD_MASK, 0); 125 } 126 127 static void rk628_combtxphy_gvi_power_on(struct rk628 *rk628) 128 { 129 struct rk628_combtxphy *combtxphy = &rk628->combtxphy; 130 int ref_div = 0; 131 132 if (combtxphy->ref_div % 2) { 133 ref_div = combtxphy->ref_div - 1; 134 } else { 135 ref_div = BIT(4); 136 ref_div |= combtxphy->ref_div / 2 - 1; 137 } 138 139 rk628_i2c_write(rk628, COMBTXPHY_CON5, 140 SW_REF_DIV(ref_div) | 141 SW_PLL_FB_DIV(combtxphy->fb_div) | 142 SW_PLL_FRAC_DIV(combtxphy->frac_div) | 143 SW_RATE(combtxphy->rate_div / 2)); 144 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0, 145 SW_BUS_WIDTH_MASK | SW_GVI_LVDS_EN_MASK | 146 SW_MIPI_DSI_EN_MASK | 147 SW_MODULEB_EN_MASK | SW_MODULEA_EN_MASK, 148 SW_BUS_WIDTH_10BIT | SW_GVI_LVDS_EN | 149 SW_MODULEB_EN | SW_MODULEA_EN); 150 151 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0, 152 SW_PD_PLL | SW_TX_PD_MASK, 0); 153 udelay(200); 154 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0, 155 SW_TX_IDLE_MASK, 0); 156 } 157 158 void rk628_combtxphy_power_on(struct rk628 *rk628) 159 { 160 struct rk628_combtxphy *combtxphy = &rk628->combtxphy; 161 162 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0, 163 SW_TX_IDLE_MASK | SW_TX_PD_MASK | 164 SW_PD_PLL_MASK, SW_TX_IDLE(0x3ff) | 165 SW_TX_PD(0x3ff) | SW_PD_PLL); 166 167 switch (combtxphy->mode) { 168 case RK628_PHY_MODE_VIDEO_MIPI: 169 170 rk628_i2c_update_bits(rk628, GRF_POST_PROC_CON, 171 SW_TXPHY_REFCLK_SEL_MASK, 172 SW_TXPHY_REFCLK_SEL(0)); 173 rk628_combtxphy_dsi_power_on(rk628); 174 break; 175 case RK628_PHY_MODE_VIDEO_LVDS: 176 rk628_i2c_update_bits(rk628, GRF_POST_PROC_CON, 177 SW_TXPHY_REFCLK_SEL_MASK, 178 SW_TXPHY_REFCLK_SEL(1)); 179 rk628_combtxphy_lvds_power_on(rk628); 180 break; 181 case RK628_PHY_MODE_VIDEO_GVI: 182 rk628_i2c_update_bits(rk628, GRF_POST_PROC_CON, 183 SW_TXPHY_REFCLK_SEL_MASK, 184 SW_TXPHY_REFCLK_SEL(2)); 185 rk628_combtxphy_gvi_power_on(rk628); 186 break; 187 default: 188 break; 189 }; 190 } 191 192 void rk628_combtxphy_power_off(struct rk628 *rk628) 193 { 194 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0, SW_TX_IDLE_MASK | 195 SW_TX_PD_MASK | SW_PD_PLL_MASK | 196 SW_MODULEB_EN_MASK | SW_MODULEA_EN_MASK, 197 SW_TX_IDLE(0x3ff) | SW_TX_PD(0x3ff) | SW_PD_PLL); 198 } 199 200 void rk628_combtxphy_set_bus_width(struct rk628 *rk628, u32 bus_width) 201 { 202 rk628->combtxphy.bus_width = bus_width; 203 } 204 205 u32 rk628_combtxphy_get_bus_width(struct rk628 *rk628) 206 { 207 return rk628->combtxphy.bus_width; 208 } 209 210 void rk628_combtxphy_set_gvi_division_mode(struct rk628 *rk628, bool division) 211 { 212 rk628->combtxphy.division_mode = division; 213 } 214 215 void rk628_combtxphy_set_mode(struct rk628 *rk628, enum rk628_phy_mode mode) 216 { 217 struct rk628_combtxphy *combtxphy = &rk628->combtxphy; 218 unsigned int fvco, fpfd, fin = 24; 219 220 switch (mode) { 221 case RK628_PHY_MODE_VIDEO_MIPI: 222 { 223 int bus_width = rk628_combtxphy_get_bus_width(rk628); 224 unsigned int fhsc = bus_width >> 8; 225 unsigned int flags = bus_width & 0xff; 226 227 combtxphy->flags = flags; 228 229 /* 230 * the VCO can work from 1.5GHz to 3GHz. 231 * fhsc: 80 ~ 374, fvco: 640 ~ 2992 232 * fhsc: 375 ~ 749, fvco: 1500 ~ 2996 233 * fhsc: 750 ~ 1500, fvco: 1500 ~ 3000 234 */ 235 if (fhsc < 80 || fhsc > 1500) 236 return; 237 else if (fhsc < 375) 238 combtxphy->rate_div = 4; 239 else if (fhsc < 750) 240 combtxphy->rate_div = 2; 241 else 242 combtxphy->rate_div = 1; 243 244 fvco = fhsc * 2 * combtxphy->rate_div; 245 246 /* 247 * the reference clock at PFD(FPFD = ref_clk / ref_div) about 248 * 25MHz is recommende, FPFD must range from 16MHz to 35MHz, 249 * here to find the best ref_div. 250 */ 251 combtxphy->ref_div = 1; 252 253 /* 254 * fvco = fin * (fb_div + frac_div / 1024) * 8 / ref_div 255 */ 256 combtxphy->fb_div = fvco * combtxphy->ref_div / 8 / fin; 257 combtxphy->frac_div = 1024 * fvco * combtxphy->ref_div / 8 / fin; 258 combtxphy->frac_div -= 1024 * combtxphy->fb_div; 259 260 /* 261 * get the actually frequency 262 */ 263 fvco = fin * (1024 * combtxphy->fb_div + combtxphy->frac_div) * 8; 264 fvco = DIV_ROUND_UP(fvco, 1024 * combtxphy->ref_div); 265 fhsc = fvco / 2 / combtxphy->rate_div; 266 combtxphy->bus_width = fhsc; 267 268 break; 269 } 270 case RK628_PHY_MODE_VIDEO_LVDS: 271 { 272 int bus_width = rk628_combtxphy_get_bus_width(rk628); 273 unsigned int flags = bus_width & 0xff; 274 unsigned int rate = (bus_width >> 8) * 7; 275 276 combtxphy->flags = flags; 277 combtxphy->ref_div = 1; 278 combtxphy->fb_div = 14; 279 combtxphy->frac_div = 0; 280 281 if (rate < 500) 282 combtxphy->rate_div = 4; 283 else if (rate < 1000) 284 combtxphy->rate_div = 2; 285 else 286 combtxphy->rate_div = 1; 287 break; 288 } 289 case RK628_PHY_MODE_VIDEO_GVI: 290 { 291 unsigned int i, delta_freq, best_delta_freq, fb_div; 292 unsigned int bus_width = rk628_combtxphy_get_bus_width(rk628); 293 unsigned long ref_clk; 294 unsigned long long pre_clk; 295 296 if (bus_width < 500000 || bus_width > 4000000) 297 return; 298 else if (bus_width < 1000000) 299 combtxphy->rate_div = 4; 300 else if (bus_width < 2000000) 301 combtxphy->rate_div = 2; 302 else 303 combtxphy->rate_div = 1; 304 fvco = bus_width * combtxphy->rate_div; 305 ref_clk = rk628_cru_clk_get_rate(rk628, CGU_SCLK_VOP); 306 ref_clk = DIV_ROUND_CLOSEST(ref_clk, 1000); /* khz */ 307 308 if (combtxphy->division_mode) 309 ref_clk /= 2; 310 /* 311 * the reference clock at PFD(FPFD = ref_clk / ref_div) about 312 * 25MHz is recommende, FPFD must range from 16MHz to 35MHz, 313 * here to find the best rev_div. 314 */ 315 best_delta_freq = ref_clk; 316 for (i = 1; i <= 32; i++) { 317 fpfd = ref_clk / i; 318 delta_freq = abs(fpfd - 25000); 319 if (delta_freq < best_delta_freq) { 320 best_delta_freq = delta_freq; 321 combtxphy->ref_div = i; 322 } 323 } 324 325 /* 326 * ref_clk / ref_div * 8 * fb_div = FVCO 327 */ 328 pre_clk = (unsigned long long)fvco * combtxphy->ref_div / 8 * 1024; 329 do_div(pre_clk, ref_clk); 330 fb_div = pre_clk / 1024; 331 332 /* 333 * get the actually frequency 334 */ 335 bus_width = ref_clk / combtxphy->ref_div * 8; 336 bus_width *= fb_div; 337 bus_width /= combtxphy->rate_div; 338 339 combtxphy->frac_div = 0; 340 combtxphy->fb_div = fb_div; 341 342 combtxphy->bus_width = bus_width; 343 break; 344 } 345 default: 346 break; 347 } 348 349 combtxphy->mode = mode; 350 } 351