Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

phy: allwinner: phy-sun6i-mipi-dphy: Add the A100 DPHY variant

A100 features an updated DPHY, which moves PLL control inside the DPHY
register space (previously the PLL was controlled from the CCU). It also
requires a modified analog power-on sequence. This "combo PHY" can also
be used as an LVDS PHY, but that is not yet supported by the driver.

Signed-off-by: Samuel Holland <samuel@sholland.org>
Link: https://lore.kernel.org/r/20221114022113.31694-9-samuel@sholland.org
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Samuel Holland and committed by
Vinod Koul
4d0c2165 3fd490a7

+142 -1
+142 -1
drivers/phy/allwinner/phy-sun6i-mipi-dphy.c
··· 70 70 71 71 #define SUN6I_DPHY_ANA0_REG 0x4c 72 72 #define SUN6I_DPHY_ANA0_REG_PWS BIT(31) 73 + #define SUN6I_DPHY_ANA0_REG_PWEND BIT(30) 74 + #define SUN6I_DPHY_ANA0_REG_PWENC BIT(29) 73 75 #define SUN6I_DPHY_ANA0_REG_DMPC BIT(28) 74 76 #define SUN6I_DPHY_ANA0_REG_DMPD(n) (((n) & 0xf) << 24) 77 + #define SUN6I_DPHY_ANA0_REG_SRXDT(n) (((n) & 0xf) << 20) 78 + #define SUN6I_DPHY_ANA0_REG_SRXCK(n) (((n) & 0xf) << 16) 79 + #define SUN6I_DPHY_ANA0_REG_SDIV2 BIT(15) 75 80 #define SUN6I_DPHY_ANA0_REG_SLV(n) (((n) & 7) << 12) 76 81 #define SUN6I_DPHY_ANA0_REG_DEN(n) (((n) & 0xf) << 8) 82 + #define SUN6I_DPHY_ANA0_REG_PLR(n) (((n) & 0xf) << 4) 77 83 #define SUN6I_DPHY_ANA0_REG_SFB(n) (((n) & 3) << 2) 84 + #define SUN6I_DPHY_ANA0_REG_RSD BIT(1) 85 + #define SUN6I_DPHY_ANA0_REG_SELSCK BIT(0) 78 86 79 87 #define SUN6I_DPHY_ANA1_REG 0x50 80 88 #define SUN6I_DPHY_ANA1_REG_VTTMODE BIT(31) ··· 105 97 #define SUN6I_DPHY_ANA3_EN_LDOR BIT(18) 106 98 107 99 #define SUN6I_DPHY_ANA4_REG 0x5c 100 + #define SUN6I_DPHY_ANA4_REG_EN_MIPI BIT(31) 101 + #define SUN6I_DPHY_ANA4_REG_EN_COMTEST BIT(30) 102 + #define SUN6I_DPHY_ANA4_REG_COMTEST(n) (((n) & 3) << 28) 103 + #define SUN6I_DPHY_ANA4_REG_IB(n) (((n) & 3) << 25) 108 104 #define SUN6I_DPHY_ANA4_REG_DMPLVC BIT(24) 109 105 #define SUN6I_DPHY_ANA4_REG_DMPLVD(n) (((n) & 0xf) << 20) 106 + #define SUN6I_DPHY_ANA4_REG_VTT_SET(n) (((n) & 0x7) << 17) 110 107 #define SUN6I_DPHY_ANA4_REG_CKDV(n) (((n) & 0x1f) << 12) 111 108 #define SUN6I_DPHY_ANA4_REG_TMSC(n) (((n) & 3) << 10) 112 109 #define SUN6I_DPHY_ANA4_REG_TMSD(n) (((n) & 3) << 8) ··· 121 108 #define SUN6I_DPHY_ANA4_REG_TXPUSD(n) ((n) & 3) 122 109 123 110 #define SUN6I_DPHY_DBG5_REG 0xf4 111 + 112 + #define SUN50I_DPHY_TX_SLEW_REG0 0xf8 113 + #define SUN50I_DPHY_TX_SLEW_REG1 0xfc 114 + #define SUN50I_DPHY_TX_SLEW_REG2 0x100 115 + 116 + #define SUN50I_DPHY_PLL_REG0 0x104 117 + #define SUN50I_DPHY_PLL_REG0_CP36_EN BIT(23) 118 + #define SUN50I_DPHY_PLL_REG0_LDO_EN BIT(22) 119 + #define SUN50I_DPHY_PLL_REG0_EN_LVS BIT(21) 120 + #define SUN50I_DPHY_PLL_REG0_PLL_EN BIT(20) 121 + #define SUN50I_DPHY_PLL_REG0_P(n) (((n) & 0xf) << 16) 122 + #define SUN50I_DPHY_PLL_REG0_N(n) (((n) & 0xff) << 8) 123 + #define SUN50I_DPHY_PLL_REG0_NDET BIT(7) 124 + #define SUN50I_DPHY_PLL_REG0_TDIV BIT(6) 125 + #define SUN50I_DPHY_PLL_REG0_M0(n) (((n) & 3) << 4) 126 + #define SUN50I_DPHY_PLL_REG0_M1(n) ((n) & 0xf) 127 + 128 + #define SUN50I_DPHY_PLL_REG1 0x108 129 + #define SUN50I_DPHY_PLL_REG1_UNLOCK_MDSEL(n) (((n) & 3) << 14) 130 + #define SUN50I_DPHY_PLL_REG1_LOCKMDSEL BIT(13) 131 + #define SUN50I_DPHY_PLL_REG1_LOCKDET_EN BIT(12) 132 + #define SUN50I_DPHY_PLL_REG1_VSETA(n) (((n) & 0x7) << 9) 133 + #define SUN50I_DPHY_PLL_REG1_VSETD(n) (((n) & 0x7) << 6) 134 + #define SUN50I_DPHY_PLL_REG1_LPF_SW BIT(5) 135 + #define SUN50I_DPHY_PLL_REG1_ICP_SEL(n) (((n) & 3) << 3) 136 + #define SUN50I_DPHY_PLL_REG1_ATEST_SEL(n) (((n) & 3) << 1) 137 + #define SUN50I_DPHY_PLL_REG1_TEST_EN BIT(0) 138 + 139 + #define SUN50I_DPHY_PLL_REG2 0x10c 140 + #define SUN50I_DPHY_PLL_REG2_SDM_EN BIT(31) 141 + #define SUN50I_DPHY_PLL_REG2_FF_EN BIT(30) 142 + #define SUN50I_DPHY_PLL_REG2_SS_EN BIT(29) 143 + #define SUN50I_DPHY_PLL_REG2_SS_FRAC(n) (((n) & 0x1ff) << 20) 144 + #define SUN50I_DPHY_PLL_REG2_SS_INT(n) (((n) & 0xff) << 12) 145 + #define SUN50I_DPHY_PLL_REG2_FRAC(n) ((n) & 0xfff) 146 + 147 + #define SUN50I_COMBO_PHY_REG0 0x110 148 + #define SUN50I_COMBO_PHY_REG0_EN_TEST_COMBOLDO BIT(5) 149 + #define SUN50I_COMBO_PHY_REG0_EN_TEST_0P8 BIT(4) 150 + #define SUN50I_COMBO_PHY_REG0_EN_MIPI BIT(3) 151 + #define SUN50I_COMBO_PHY_REG0_EN_LVDS BIT(2) 152 + #define SUN50I_COMBO_PHY_REG0_EN_COMBOLDO BIT(1) 153 + #define SUN50I_COMBO_PHY_REG0_EN_CP BIT(0) 154 + 155 + #define SUN50I_COMBO_PHY_REG1 0x114 156 + #define SUN50I_COMBO_PHY_REG2_REG_VREF1P6(n) (((n) & 0x7) << 4) 157 + #define SUN50I_COMBO_PHY_REG2_REG_VREF0P8(n) ((n) & 0x7) 158 + 159 + #define SUN50I_COMBO_PHY_REG2 0x118 160 + #define SUN50I_COMBO_PHY_REG2_HS_STOP_DLY(n) ((n) & 0xff) 124 161 125 162 enum sun6i_dphy_direction { 126 163 SUN6I_DPHY_DIRECTION_TX, ··· 256 193 SUN6I_DPHY_ANA3_EN_LDOR | 257 194 SUN6I_DPHY_ANA3_EN_LDOC | 258 195 SUN6I_DPHY_ANA3_EN_LDOD); 196 + udelay(1); 197 + } 198 + 199 + static void sun50i_a100_mipi_dphy_tx_power_on(struct sun6i_dphy *dphy) 200 + { 201 + unsigned long mipi_symbol_rate = dphy->config.hs_clk_rate; 202 + unsigned int div, n; 203 + 204 + regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG, 205 + SUN6I_DPHY_ANA4_REG_IB(2) | 206 + SUN6I_DPHY_ANA4_REG_DMPLVD(4) | 207 + SUN6I_DPHY_ANA4_REG_VTT_SET(3) | 208 + SUN6I_DPHY_ANA4_REG_CKDV(3) | 209 + SUN6I_DPHY_ANA4_REG_TMSD(1) | 210 + SUN6I_DPHY_ANA4_REG_TMSC(1) | 211 + SUN6I_DPHY_ANA4_REG_TXPUSD(2) | 212 + SUN6I_DPHY_ANA4_REG_TXPUSC(3) | 213 + SUN6I_DPHY_ANA4_REG_TXDNSD(2) | 214 + SUN6I_DPHY_ANA4_REG_TXDNSC(3)); 215 + 216 + regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG, 217 + SUN6I_DPHY_ANA2_EN_CK_CPU, 218 + SUN6I_DPHY_ANA2_EN_CK_CPU); 219 + 220 + regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG, 221 + SUN6I_DPHY_ANA2_REG_ENIB, 222 + SUN6I_DPHY_ANA2_REG_ENIB); 223 + 224 + regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG, 225 + SUN6I_DPHY_ANA3_EN_LDOR | 226 + SUN6I_DPHY_ANA3_EN_LDOC | 227 + SUN6I_DPHY_ANA3_EN_LDOD); 228 + 229 + regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG, 230 + SUN6I_DPHY_ANA0_REG_PLR(4) | 231 + SUN6I_DPHY_ANA0_REG_SFB(1)); 232 + 233 + regmap_write(dphy->regs, SUN50I_COMBO_PHY_REG0, 234 + SUN50I_COMBO_PHY_REG0_EN_CP); 235 + 236 + /* Choose a divider to limit the VCO frequency to around 2 GHz. */ 237 + div = 16 >> order_base_2(DIV_ROUND_UP(mipi_symbol_rate, 264000000)); 238 + n = mipi_symbol_rate * div / 24000000; 239 + 240 + regmap_write(dphy->regs, SUN50I_DPHY_PLL_REG0, 241 + SUN50I_DPHY_PLL_REG0_CP36_EN | 242 + SUN50I_DPHY_PLL_REG0_LDO_EN | 243 + SUN50I_DPHY_PLL_REG0_EN_LVS | 244 + SUN50I_DPHY_PLL_REG0_PLL_EN | 245 + SUN50I_DPHY_PLL_REG0_NDET | 246 + SUN50I_DPHY_PLL_REG0_P((div - 1) % 8) | 247 + SUN50I_DPHY_PLL_REG0_N(n) | 248 + SUN50I_DPHY_PLL_REG0_M0((div - 1) / 8) | 249 + SUN50I_DPHY_PLL_REG0_M1(2)); 250 + 251 + /* Disable sigma-delta modulation. */ 252 + regmap_write(dphy->regs, SUN50I_DPHY_PLL_REG2, 0); 253 + 254 + regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA4_REG, 255 + SUN6I_DPHY_ANA4_REG_EN_MIPI, 256 + SUN6I_DPHY_ANA4_REG_EN_MIPI); 257 + 258 + regmap_update_bits(dphy->regs, SUN50I_COMBO_PHY_REG0, 259 + SUN50I_COMBO_PHY_REG0_EN_MIPI | 260 + SUN50I_COMBO_PHY_REG0_EN_COMBOLDO, 261 + SUN50I_COMBO_PHY_REG0_EN_MIPI | 262 + SUN50I_COMBO_PHY_REG0_EN_COMBOLDO); 263 + 264 + regmap_write(dphy->regs, SUN50I_COMBO_PHY_REG2, 265 + SUN50I_COMBO_PHY_REG2_HS_STOP_DLY(20)); 259 266 udelay(1); 260 267 } 261 268 ··· 541 408 .reg_bits = 32, 542 409 .val_bits = 32, 543 410 .reg_stride = 4, 544 - .max_register = SUN6I_DPHY_DBG5_REG, 411 + .max_register = SUN50I_COMBO_PHY_REG2, 545 412 .name = "mipi-dphy", 546 413 }; 547 414 ··· 617 484 .rx_supported = true, 618 485 }; 619 486 487 + static const struct sun6i_dphy_variant sun50i_a100_mipi_dphy_variant = { 488 + .tx_power_on = sun50i_a100_mipi_dphy_tx_power_on, 489 + }; 490 + 620 491 static const struct of_device_id sun6i_dphy_of_table[] = { 621 492 { 622 493 .compatible = "allwinner,sun6i-a31-mipi-dphy", 623 494 .data = &sun6i_a31_mipi_dphy_variant, 495 + }, 496 + { 497 + .compatible = "allwinner,sun50i-a100-mipi-dphy", 498 + .data = &sun50i_a100_mipi_dphy_variant, 624 499 }, 625 500 { } 626 501 };