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