History

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.

Samuel Holland committed 3 years ago

Commit 4d0c2161 parent 3fd490a1 file · +142 −1Browse files

Showing the changes to drivers/phy/allwinner (1 of 1 file). Show all

Unified · Split

drivers/phy/allwinner/phy-sun6i-mipi-dphy.c+142−1
@@ -70,11 +70,19 @@ · 69 unmodified lines
70 70
71#define SUN6I_DPHY_ANA0_REG 0x4c71#define SUN6I_DPHY_ANA0_REG 0x4c
72#define SUN6I_DPHY_ANA0_REG_PWS BIT(31)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#define SUN6I_DPHY_ANA0_REG_DMPC BIT(28)75#define SUN6I_DPHY_ANA0_REG_DMPC BIT(28)
74#define SUN6I_DPHY_ANA0_REG_DMPD(n) (((n) & 0xf) << 24)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#define SUN6I_DPHY_ANA0_REG_SLV(n) (((n) & 7) << 12)80#define SUN6I_DPHY_ANA0_REG_SLV(n) (((n) & 7) << 12)
76#define SUN6I_DPHY_ANA0_REG_DEN(n) (((n) & 0xf) << 8)81#define SUN6I_DPHY_ANA0_REG_DEN(n) (((n) & 0xf) << 8)
82#define SUN6I_DPHY_ANA0_REG_PLR(n) (((n) & 0xf) << 4)
77#define SUN6I_DPHY_ANA0_REG_SFB(n) (((n) & 3) << 2)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#define SUN6I_DPHY_ANA1_REG 0x5087#define SUN6I_DPHY_ANA1_REG 0x50
80#define SUN6I_DPHY_ANA1_REG_VTTMODE BIT(31)88#define SUN6I_DPHY_ANA1_REG_VTTMODE BIT(31)
@@ -97,8 +105,13 @@ · 16 unmodified lines
97#define SUN6I_DPHY_ANA3_EN_LDOR BIT(18)105#define SUN6I_DPHY_ANA3_EN_LDOR BIT(18)
98 106
99#define SUN6I_DPHY_ANA4_REG 0x5c107#define SUN6I_DPHY_ANA4_REG 0x5c
108#define SUN6I_DPHY_ANA4_REG_EN_MIPI BIT(31)
109#define SUN6I_DPHY_ANA4_REG_EN_COMTEST BIT(30)
110#define SUN6I_DPHY_ANA4_REG_COMTEST(n) (((n) & 3) << 28)
111#define SUN6I_DPHY_ANA4_REG_IB(n) (((n) & 3) << 25)
100#define SUN6I_DPHY_ANA4_REG_DMPLVC BIT(24)112#define SUN6I_DPHY_ANA4_REG_DMPLVC BIT(24)
101#define SUN6I_DPHY_ANA4_REG_DMPLVD(n) (((n) & 0xf) << 20)113#define SUN6I_DPHY_ANA4_REG_DMPLVD(n) (((n) & 0xf) << 20)
114#define SUN6I_DPHY_ANA4_REG_VTT_SET(n) (((n) & 0x7) << 17)
102#define SUN6I_DPHY_ANA4_REG_CKDV(n) (((n) & 0x1f) << 12)115#define SUN6I_DPHY_ANA4_REG_CKDV(n) (((n) & 0x1f) << 12)
103#define SUN6I_DPHY_ANA4_REG_TMSC(n) (((n) & 3) << 10)116#define SUN6I_DPHY_ANA4_REG_TMSC(n) (((n) & 3) << 10)
104#define SUN6I_DPHY_ANA4_REG_TMSD(n) (((n) & 3) << 8)117#define SUN6I_DPHY_ANA4_REG_TMSD(n) (((n) & 3) << 8)
@@ -109,6 +122,56 @@ · 4 unmodified lines
109 122
110#define SUN6I_DPHY_DBG5_REG 0xf4123#define SUN6I_DPHY_DBG5_REG 0xf4
111 124
125#define SUN50I_DPHY_TX_SLEW_REG0 0xf8
126#define SUN50I_DPHY_TX_SLEW_REG1 0xfc
127#define SUN50I_DPHY_TX_SLEW_REG2 0x100
128
129#define SUN50I_DPHY_PLL_REG0 0x104
130#define SUN50I_DPHY_PLL_REG0_CP36_EN BIT(23)
131#define SUN50I_DPHY_PLL_REG0_LDO_EN BIT(22)
132#define SUN50I_DPHY_PLL_REG0_EN_LVS BIT(21)
133#define SUN50I_DPHY_PLL_REG0_PLL_EN BIT(20)
134#define SUN50I_DPHY_PLL_REG0_P(n) (((n) & 0xf) << 16)
135#define SUN50I_DPHY_PLL_REG0_N(n) (((n) & 0xff) << 8)
136#define SUN50I_DPHY_PLL_REG0_NDET BIT(7)
137#define SUN50I_DPHY_PLL_REG0_TDIV BIT(6)
138#define SUN50I_DPHY_PLL_REG0_M0(n) (((n) & 3) << 4)
139#define SUN50I_DPHY_PLL_REG0_M1(n) ((n) & 0xf)
140
141#define SUN50I_DPHY_PLL_REG1 0x108
142#define SUN50I_DPHY_PLL_REG1_UNLOCK_MDSEL(n) (((n) & 3) << 14)
143#define SUN50I_DPHY_PLL_REG1_LOCKMDSEL BIT(13)
144#define SUN50I_DPHY_PLL_REG1_LOCKDET_EN BIT(12)
145#define SUN50I_DPHY_PLL_REG1_VSETA(n) (((n) & 0x7) << 9)
146#define SUN50I_DPHY_PLL_REG1_VSETD(n) (((n) & 0x7) << 6)
147#define SUN50I_DPHY_PLL_REG1_LPF_SW BIT(5)
148#define SUN50I_DPHY_PLL_REG1_ICP_SEL(n) (((n) & 3) << 3)
149#define SUN50I_DPHY_PLL_REG1_ATEST_SEL(n) (((n) & 3) << 1)
150#define SUN50I_DPHY_PLL_REG1_TEST_EN BIT(0)
151
152#define SUN50I_DPHY_PLL_REG2 0x10c
153#define SUN50I_DPHY_PLL_REG2_SDM_EN BIT(31)
154#define SUN50I_DPHY_PLL_REG2_FF_EN BIT(30)
155#define SUN50I_DPHY_PLL_REG2_SS_EN BIT(29)
156#define SUN50I_DPHY_PLL_REG2_SS_FRAC(n) (((n) & 0x1ff) << 20)
157#define SUN50I_DPHY_PLL_REG2_SS_INT(n) (((n) & 0xff) << 12)
158#define SUN50I_DPHY_PLL_REG2_FRAC(n) ((n) & 0xfff)
159
160#define SUN50I_COMBO_PHY_REG0 0x110
161#define SUN50I_COMBO_PHY_REG0_EN_TEST_COMBOLDO BIT(5)
162#define SUN50I_COMBO_PHY_REG0_EN_TEST_0P8 BIT(4)
163#define SUN50I_COMBO_PHY_REG0_EN_MIPI BIT(3)
164#define SUN50I_COMBO_PHY_REG0_EN_LVDS BIT(2)
165#define SUN50I_COMBO_PHY_REG0_EN_COMBOLDO BIT(1)
166#define SUN50I_COMBO_PHY_REG0_EN_CP BIT(0)
167
168#define SUN50I_COMBO_PHY_REG1 0x114
169#define SUN50I_COMBO_PHY_REG2_REG_VREF1P6(n) (((n) & 0x7) << 4)
170#define SUN50I_COMBO_PHY_REG2_REG_VREF0P8(n) ((n) & 0x7)
171
172#define SUN50I_COMBO_PHY_REG2 0x118
173#define SUN50I_COMBO_PHY_REG2_HS_STOP_DLY(n) ((n) & 0xff)
174
112enum sun6i_dphy_direction {175enum sun6i_dphy_direction {
113 SUN6I_DPHY_DIRECTION_TX,176 SUN6I_DPHY_DIRECTION_TX,
114 SUN6I_DPHY_DIRECTION_RX,177 SUN6I_DPHY_DIRECTION_RX,
@@ -196,6 +259,76 @@ static void sun6i_a31_mipi_dphy_tx_power_on(struct sun6i_dphy *dphy) · 81 unmodified lines
196 udelay(1);259 udelay(1);
197}260}
198 261
262static void sun50i_a100_mipi_dphy_tx_power_on(struct sun6i_dphy *dphy)
263{
264 unsigned long mipi_symbol_rate = dphy->config.hs_clk_rate;
265 unsigned int div, n;
266
267 regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG,
268 SUN6I_DPHY_ANA4_REG_IB(2) |
269 SUN6I_DPHY_ANA4_REG_DMPLVD(4) |
270 SUN6I_DPHY_ANA4_REG_VTT_SET(3) |
271 SUN6I_DPHY_ANA4_REG_CKDV(3) |
272 SUN6I_DPHY_ANA4_REG_TMSD(1) |
273 SUN6I_DPHY_ANA4_REG_TMSC(1) |
274 SUN6I_DPHY_ANA4_REG_TXPUSD(2) |
275 SUN6I_DPHY_ANA4_REG_TXPUSC(3) |
276 SUN6I_DPHY_ANA4_REG_TXDNSD(2) |
277 SUN6I_DPHY_ANA4_REG_TXDNSC(3));
278
279 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG,
280 SUN6I_DPHY_ANA2_EN_CK_CPU,
281 SUN6I_DPHY_ANA2_EN_CK_CPU);
282
283 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG,
284 SUN6I_DPHY_ANA2_REG_ENIB,
285 SUN6I_DPHY_ANA2_REG_ENIB);
286
287 regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG,
288 SUN6I_DPHY_ANA3_EN_LDOR |
289 SUN6I_DPHY_ANA3_EN_LDOC |
290 SUN6I_DPHY_ANA3_EN_LDOD);
291
292 regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG,
293 SUN6I_DPHY_ANA0_REG_PLR(4) |
294 SUN6I_DPHY_ANA0_REG_SFB(1));
295
296 regmap_write(dphy->regs, SUN50I_COMBO_PHY_REG0,
297 SUN50I_COMBO_PHY_REG0_EN_CP);
298
299 /* Choose a divider to limit the VCO frequency to around 2 GHz. */
300 div = 16 >> order_base_2(DIV_ROUND_UP(mipi_symbol_rate, 264000000));
301 n = mipi_symbol_rate * div / 24000000;
302
303 regmap_write(dphy->regs, SUN50I_DPHY_PLL_REG0,
304 SUN50I_DPHY_PLL_REG0_CP36_EN |
305 SUN50I_DPHY_PLL_REG0_LDO_EN |
306 SUN50I_DPHY_PLL_REG0_EN_LVS |
307 SUN50I_DPHY_PLL_REG0_PLL_EN |
308 SUN50I_DPHY_PLL_REG0_NDET |
309 SUN50I_DPHY_PLL_REG0_P((div - 1) % 8) |
310 SUN50I_DPHY_PLL_REG0_N(n) |
311 SUN50I_DPHY_PLL_REG0_M0((div - 1) / 8) |
312 SUN50I_DPHY_PLL_REG0_M1(2));
313
314 /* Disable sigma-delta modulation. */
315 regmap_write(dphy->regs, SUN50I_DPHY_PLL_REG2, 0);
316
317 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA4_REG,
318 SUN6I_DPHY_ANA4_REG_EN_MIPI,
319 SUN6I_DPHY_ANA4_REG_EN_MIPI);
320
321 regmap_update_bits(dphy->regs, SUN50I_COMBO_PHY_REG0,
322 SUN50I_COMBO_PHY_REG0_EN_MIPI |
323 SUN50I_COMBO_PHY_REG0_EN_COMBOLDO,
324 SUN50I_COMBO_PHY_REG0_EN_MIPI |
325 SUN50I_COMBO_PHY_REG0_EN_COMBOLDO);
326
327 regmap_write(dphy->regs, SUN50I_COMBO_PHY_REG2,
328 SUN50I_COMBO_PHY_REG2_HS_STOP_DLY(20));
329 udelay(1);
330}
331
199static int sun6i_dphy_tx_power_on(struct sun6i_dphy *dphy)332static int sun6i_dphy_tx_power_on(struct sun6i_dphy *dphy)
200{333{
201 u8 lanes_mask = GENMASK(dphy->config.lanes - 1, 0);334 u8 lanes_mask = GENMASK(dphy->config.lanes - 1, 0);
@@ -408,7 +541,7 @@ static const struct regmap_config sun6i_dphy_regmap_config = { · 206 unmodified lines
408 .reg_bits = 32,541 .reg_bits = 32,
409 .val_bits = 32,542 .val_bits = 32,
410 .reg_stride = 4,543 .reg_stride = 4,
411 .max_register = SUN6I_DPHY_DBG5_REG,544 .max_register = SUN50I_COMBO_PHY_REG2,
412 .name = "mipi-dphy",545 .name = "mipi-dphy",
413};546};
414 547
@@ -484,11 +617,19 @@ static const struct sun6i_dphy_variant sun6i_a31_mipi_dphy_variant = { · 69 unmodified lines
484 .rx_supported = true,617 .rx_supported = true,
485};618};
486 619
620static const struct sun6i_dphy_variant sun50i_a100_mipi_dphy_variant = {
621 .tx_power_on = sun50i_a100_mipi_dphy_tx_power_on,
622};
623
487static const struct of_device_id sun6i_dphy_of_table[] = {624static const struct of_device_id sun6i_dphy_of_table[] = {
488 {625 {
489 .compatible = "allwinner,sun6i-a31-mipi-dphy",626 .compatible = "allwinner,sun6i-a31-mipi-dphy",
490 .data = &sun6i_a31_mipi_dphy_variant,627 .data = &sun6i_a31_mipi_dphy_variant,
491 },628 },
629 {
630 .compatible = "allwinner,sun50i-a100-mipi-dphy",
631 .data = &sun50i_a100_mipi_dphy_variant,
632 },
492 { }633 { }
493};634};
494MODULE_DEVICE_TABLE(of, sun6i_dphy_of_table);635MODULE_DEVICE_TABLE(of, sun6i_dphy_of_table);