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