1 From 474b608dee5e6285dd1981b00ab568a2f7f15fd0 Mon Sep 17 00:00:00 2001
2 From: Samuel Holland <samuel@sholland.org>
3 Date: Wed, 10 Aug 2022 23:02:06 -0500
4 Subject: [PATCH 106/117] phy: allwinner: phy-sun6i-mipi-dphy: Add the A100
7 A100 features an updated DPHY, which moves PLL control inside the DPHY
8 register space (previously the PLL was controlled from the CCU). It also
9 requires a modified analog power-on sequence. This "combo PHY" can also
10 be used as an LVDS PHY, but that is not yet supported by the driver.
13 phy: allwinner: phy-sun6i-mipi-dphy: Add the A100 DPHY
14 This series adds support for the updated DPHY found in a couple of
15 recent Allwinner SoCs. The first three patches fix an omission in the
16 existing binding. The remaining patches add the new hardware variant.
19 Series-to: Kishon Vijay Abraham I <kishon@ti.com>
20 Series-to: Vinod Koul <vkoul@kernel.org>
21 Series-to: Chen-Yu Tsai <wens@csie.org>
22 Series-to: Jernej Skrabec <jernej.skrabec@gmail.com>
23 Series-to: Maxime Ripard <mripard@kernel.org>
24 Series-cc: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
26 Signed-off-by: Samuel Holland <samuel@sholland.org>
28 drivers/phy/allwinner/phy-sun6i-mipi-dphy.c | 143 +++++++++++++++++++-
29 1 file changed, 142 insertions(+), 1 deletion(-)
31 --- a/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c
32 +++ b/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c
35 #define SUN6I_DPHY_ANA0_REG 0x4c
36 #define SUN6I_DPHY_ANA0_REG_PWS BIT(31)
37 +#define SUN6I_DPHY_ANA0_REG_PWEND BIT(30)
38 +#define SUN6I_DPHY_ANA0_REG_PWENC BIT(29)
39 #define SUN6I_DPHY_ANA0_REG_DMPC BIT(28)
40 #define SUN6I_DPHY_ANA0_REG_DMPD(n) (((n) & 0xf) << 24)
41 +#define SUN6I_DPHY_ANA0_REG_SRXDT(n) (((n) & 0xf) << 20)
42 +#define SUN6I_DPHY_ANA0_REG_SRXCK(n) (((n) & 0xf) << 16)
43 +#define SUN6I_DPHY_ANA0_REG_SDIV2 BIT(15)
44 #define SUN6I_DPHY_ANA0_REG_SLV(n) (((n) & 7) << 12)
45 #define SUN6I_DPHY_ANA0_REG_DEN(n) (((n) & 0xf) << 8)
46 +#define SUN6I_DPHY_ANA0_REG_PLR(n) (((n) & 0xf) << 4)
47 #define SUN6I_DPHY_ANA0_REG_SFB(n) (((n) & 3) << 2)
48 +#define SUN6I_DPHY_ANA0_REG_RSD BIT(1)
49 +#define SUN6I_DPHY_ANA0_REG_SELSCK BIT(0)
51 #define SUN6I_DPHY_ANA1_REG 0x50
52 #define SUN6I_DPHY_ANA1_REG_VTTMODE BIT(31)
54 #define SUN6I_DPHY_ANA3_EN_LDOR BIT(18)
56 #define SUN6I_DPHY_ANA4_REG 0x5c
57 +#define SUN6I_DPHY_ANA4_REG_EN_MIPI BIT(31)
58 +#define SUN6I_DPHY_ANA4_REG_EN_COMTEST BIT(30)
59 +#define SUN6I_DPHY_ANA4_REG_COMTEST(n) (((n) & 3) << 28)
60 +#define SUN6I_DPHY_ANA4_REG_IB(n) (((n) & 3) << 25)
61 #define SUN6I_DPHY_ANA4_REG_DMPLVC BIT(24)
62 #define SUN6I_DPHY_ANA4_REG_DMPLVD(n) (((n) & 0xf) << 20)
63 +#define SUN6I_DPHY_ANA4_REG_VTT_SET(n) (((n) & 0x7) << 17)
64 #define SUN6I_DPHY_ANA4_REG_CKDV(n) (((n) & 0x1f) << 12)
65 #define SUN6I_DPHY_ANA4_REG_TMSC(n) (((n) & 3) << 10)
66 #define SUN6I_DPHY_ANA4_REG_TMSD(n) (((n) & 3) << 8)
69 #define SUN6I_DPHY_DBG5_REG 0xf4
71 +#define SUN50I_DPHY_TX_SLEW_REG0 0xf8
72 +#define SUN50I_DPHY_TX_SLEW_REG1 0xfc
73 +#define SUN50I_DPHY_TX_SLEW_REG2 0x100
75 +#define SUN50I_DPHY_PLL_REG0 0x104
76 +#define SUN50I_DPHY_PLL_REG0_CP36_EN BIT(23)
77 +#define SUN50I_DPHY_PLL_REG0_LDO_EN BIT(22)
78 +#define SUN50I_DPHY_PLL_REG0_EN_LVS BIT(21)
79 +#define SUN50I_DPHY_PLL_REG0_PLL_EN BIT(20)
80 +#define SUN50I_DPHY_PLL_REG0_P(n) (((n) & 0xf) << 16)
81 +#define SUN50I_DPHY_PLL_REG0_N(n) (((n) & 0xff) << 8)
82 +#define SUN50I_DPHY_PLL_REG0_NDET BIT(7)
83 +#define SUN50I_DPHY_PLL_REG0_TDIV BIT(6)
84 +#define SUN50I_DPHY_PLL_REG0_M0(n) (((n) & 3) << 4)
85 +#define SUN50I_DPHY_PLL_REG0_M1(n) ((n) & 0xf)
87 +#define SUN50I_DPHY_PLL_REG1 0x108
88 +#define SUN50I_DPHY_PLL_REG1_UNLOCK_MDSEL(n) (((n) & 3) << 14)
89 +#define SUN50I_DPHY_PLL_REG1_LOCKMDSEL BIT(13)
90 +#define SUN50I_DPHY_PLL_REG1_LOCKDET_EN BIT(12)
91 +#define SUN50I_DPHY_PLL_REG1_VSETA(n) (((n) & 0x7) << 9)
92 +#define SUN50I_DPHY_PLL_REG1_VSETD(n) (((n) & 0x7) << 6)
93 +#define SUN50I_DPHY_PLL_REG1_LPF_SW BIT(5)
94 +#define SUN50I_DPHY_PLL_REG1_ICP_SEL(n) (((n) & 3) << 3)
95 +#define SUN50I_DPHY_PLL_REG1_ATEST_SEL(n) (((n) & 3) << 1)
96 +#define SUN50I_DPHY_PLL_REG1_TEST_EN BIT(0)
98 +#define SUN50I_DPHY_PLL_REG2 0x10c
99 +#define SUN50I_DPHY_PLL_REG2_SDM_EN BIT(31)
100 +#define SUN50I_DPHY_PLL_REG2_FF_EN BIT(30)
101 +#define SUN50I_DPHY_PLL_REG2_SS_EN BIT(29)
102 +#define SUN50I_DPHY_PLL_REG2_SS_FRAC(n) (((n) & 0x1ff) << 20)
103 +#define SUN50I_DPHY_PLL_REG2_SS_INT(n) (((n) & 0xff) << 12)
104 +#define SUN50I_DPHY_PLL_REG2_FRAC(n) ((n) & 0xfff)
106 +#define SUN50I_COMBO_PHY_REG0 0x110
107 +#define SUN50I_COMBO_PHY_REG0_EN_TEST_COMBOLDO BIT(5)
108 +#define SUN50I_COMBO_PHY_REG0_EN_TEST_0P8 BIT(4)
109 +#define SUN50I_COMBO_PHY_REG0_EN_MIPI BIT(3)
110 +#define SUN50I_COMBO_PHY_REG0_EN_LVDS BIT(2)
111 +#define SUN50I_COMBO_PHY_REG0_EN_COMBOLDO BIT(1)
112 +#define SUN50I_COMBO_PHY_REG0_EN_CP BIT(0)
114 +#define SUN50I_COMBO_PHY_REG1 0x114
115 +#define SUN50I_COMBO_PHY_REG2_REG_VREF1P6(n) (((n) & 0x7) << 4)
116 +#define SUN50I_COMBO_PHY_REG2_REG_VREF0P8(n) ((n) & 0x7)
118 +#define SUN50I_COMBO_PHY_REG2 0x118
119 +#define SUN50I_COMBO_PHY_REG2_HS_STOP_DLY(n) ((n) & 0xff)
121 enum sun6i_dphy_direction {
122 SUN6I_DPHY_DIRECTION_TX,
123 SUN6I_DPHY_DIRECTION_RX,
124 @@ -196,6 +259,76 @@ static void sun6i_a31_mipi_dphy_tx_power
128 +static void sun50i_a100_mipi_dphy_tx_power_on(struct sun6i_dphy *dphy)
130 + unsigned long mipi_symbol_rate = dphy->config.hs_clk_rate;
131 + unsigned int div, n;
133 + regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG,
134 + SUN6I_DPHY_ANA4_REG_IB(2) |
135 + SUN6I_DPHY_ANA4_REG_DMPLVD(4) |
136 + SUN6I_DPHY_ANA4_REG_VTT_SET(3) |
137 + SUN6I_DPHY_ANA4_REG_CKDV(3) |
138 + SUN6I_DPHY_ANA4_REG_TMSD(1) |
139 + SUN6I_DPHY_ANA4_REG_TMSC(1) |
140 + SUN6I_DPHY_ANA4_REG_TXPUSD(2) |
141 + SUN6I_DPHY_ANA4_REG_TXPUSC(3) |
142 + SUN6I_DPHY_ANA4_REG_TXDNSD(2) |
143 + SUN6I_DPHY_ANA4_REG_TXDNSC(3));
145 + regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG,
146 + SUN6I_DPHY_ANA2_EN_CK_CPU,
147 + SUN6I_DPHY_ANA2_EN_CK_CPU);
149 + regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG,
150 + SUN6I_DPHY_ANA2_REG_ENIB,
151 + SUN6I_DPHY_ANA2_REG_ENIB);
153 + regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG,
154 + SUN6I_DPHY_ANA3_EN_LDOR |
155 + SUN6I_DPHY_ANA3_EN_LDOC |
156 + SUN6I_DPHY_ANA3_EN_LDOD);
158 + regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG,
159 + SUN6I_DPHY_ANA0_REG_PLR(4) |
160 + SUN6I_DPHY_ANA0_REG_SFB(1));
162 + regmap_write(dphy->regs, SUN50I_COMBO_PHY_REG0,
163 + SUN50I_COMBO_PHY_REG0_EN_CP);
165 + /* Choose a divider to limit the VCO frequency to around 2 GHz. */
166 + div = 16 >> order_base_2(DIV_ROUND_UP(mipi_symbol_rate, 264000000));
167 + n = mipi_symbol_rate * div / 24000000;
169 + regmap_write(dphy->regs, SUN50I_DPHY_PLL_REG0,
170 + SUN50I_DPHY_PLL_REG0_CP36_EN |
171 + SUN50I_DPHY_PLL_REG0_LDO_EN |
172 + SUN50I_DPHY_PLL_REG0_EN_LVS |
173 + SUN50I_DPHY_PLL_REG0_PLL_EN |
174 + SUN50I_DPHY_PLL_REG0_NDET |
175 + SUN50I_DPHY_PLL_REG0_P((div - 1) % 8) |
176 + SUN50I_DPHY_PLL_REG0_N(n) |
177 + SUN50I_DPHY_PLL_REG0_M0((div - 1) / 8) |
178 + SUN50I_DPHY_PLL_REG0_M1(2));
180 + /* Disable sigma-delta modulation. */
181 + regmap_write(dphy->regs, SUN50I_DPHY_PLL_REG2, 0);
183 + regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA4_REG,
184 + SUN6I_DPHY_ANA4_REG_EN_MIPI,
185 + SUN6I_DPHY_ANA4_REG_EN_MIPI);
187 + regmap_update_bits(dphy->regs, SUN50I_COMBO_PHY_REG0,
188 + SUN50I_COMBO_PHY_REG0_EN_MIPI |
189 + SUN50I_COMBO_PHY_REG0_EN_COMBOLDO,
190 + SUN50I_COMBO_PHY_REG0_EN_MIPI |
191 + SUN50I_COMBO_PHY_REG0_EN_COMBOLDO);
193 + regmap_write(dphy->regs, SUN50I_COMBO_PHY_REG2,
194 + SUN50I_COMBO_PHY_REG2_HS_STOP_DLY(20));
198 static int sun6i_dphy_tx_power_on(struct sun6i_dphy *dphy)
200 u8 lanes_mask = GENMASK(dphy->config.lanes - 1, 0);
201 @@ -408,7 +541,7 @@ static const struct regmap_config sun6i_
205 - .max_register = SUN6I_DPHY_DBG5_REG,
206 + .max_register = SUN50I_COMBO_PHY_REG2,
210 @@ -483,11 +616,19 @@ static const struct sun6i_dphy_variant s
214 +static const struct sun6i_dphy_variant sun50i_a100_mipi_dphy_variant = {
215 + .tx_power_on = sun50i_a100_mipi_dphy_tx_power_on,
218 static const struct of_device_id sun6i_dphy_of_table[] = {
220 .compatible = "allwinner,sun6i-a31-mipi-dphy",
221 .data = &sun6i_a31_mipi_dphy_variant,
224 + .compatible = "allwinner,sun50i-a100-mipi-dphy",
225 + .data = &sun50i_a100_mipi_dphy_variant,
229 MODULE_DEVICE_TABLE(of, sun6i_dphy_of_table);