1
2
3
4
5
6
7
8
9#include <linux/bitops.h>
10#include <linux/clk.h>
11#include <linux/of_address.h>
12#include <linux/regmap.h>
13#include <linux/reset.h>
14
15#include "sun6i_mipi_dsi.h"
16
17#define SUN6I_DPHY_GCTL_REG 0x00
18#define SUN6I_DPHY_GCTL_LANE_NUM(n) ((((n) - 1) & 3) << 4)
19#define SUN6I_DPHY_GCTL_EN BIT(0)
20
21#define SUN6I_DPHY_TX_CTL_REG 0x04
22#define SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT BIT(28)
23
24#define SUN6I_DPHY_TX_TIME0_REG 0x10
25#define SUN6I_DPHY_TX_TIME0_HS_TRAIL(n) (((n) & 0xff) << 24)
26#define SUN6I_DPHY_TX_TIME0_HS_PREPARE(n) (((n) & 0xff) << 16)
27#define SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(n) ((n) & 0xff)
28
29#define SUN6I_DPHY_TX_TIME1_REG 0x14
30#define SUN6I_DPHY_TX_TIME1_CLK_POST(n) (((n) & 0xff) << 24)
31#define SUN6I_DPHY_TX_TIME1_CLK_PRE(n) (((n) & 0xff) << 16)
32#define SUN6I_DPHY_TX_TIME1_CLK_ZERO(n) (((n) & 0xff) << 8)
33#define SUN6I_DPHY_TX_TIME1_CLK_PREPARE(n) ((n) & 0xff)
34
35#define SUN6I_DPHY_TX_TIME2_REG 0x18
36#define SUN6I_DPHY_TX_TIME2_CLK_TRAIL(n) ((n) & 0xff)
37
38#define SUN6I_DPHY_TX_TIME3_REG 0x1c
39
40#define SUN6I_DPHY_TX_TIME4_REG 0x20
41#define SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(n) (((n) & 0xff) << 8)
42#define SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(n) ((n) & 0xff)
43
44#define SUN6I_DPHY_ANA0_REG 0x4c
45#define SUN6I_DPHY_ANA0_REG_PWS BIT(31)
46#define SUN6I_DPHY_ANA0_REG_DMPC BIT(28)
47#define SUN6I_DPHY_ANA0_REG_DMPD(n) (((n) & 0xf) << 24)
48#define SUN6I_DPHY_ANA0_REG_SLV(n) (((n) & 7) << 12)
49#define SUN6I_DPHY_ANA0_REG_DEN(n) (((n) & 0xf) << 8)
50
51#define SUN6I_DPHY_ANA1_REG 0x50
52#define SUN6I_DPHY_ANA1_REG_VTTMODE BIT(31)
53#define SUN6I_DPHY_ANA1_REG_CSMPS(n) (((n) & 3) << 28)
54#define SUN6I_DPHY_ANA1_REG_SVTT(n) (((n) & 0xf) << 24)
55
56#define SUN6I_DPHY_ANA2_REG 0x54
57#define SUN6I_DPHY_ANA2_EN_P2S_CPU(n) (((n) & 0xf) << 24)
58#define SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK GENMASK(27, 24)
59#define SUN6I_DPHY_ANA2_EN_CK_CPU BIT(4)
60#define SUN6I_DPHY_ANA2_REG_ENIB BIT(1)
61
62#define SUN6I_DPHY_ANA3_REG 0x58
63#define SUN6I_DPHY_ANA3_EN_VTTD(n) (((n) & 0xf) << 28)
64#define SUN6I_DPHY_ANA3_EN_VTTD_MASK GENMASK(31, 28)
65#define SUN6I_DPHY_ANA3_EN_VTTC BIT(27)
66#define SUN6I_DPHY_ANA3_EN_DIV BIT(26)
67#define SUN6I_DPHY_ANA3_EN_LDOC BIT(25)
68#define SUN6I_DPHY_ANA3_EN_LDOD BIT(24)
69#define SUN6I_DPHY_ANA3_EN_LDOR BIT(18)
70
71#define SUN6I_DPHY_ANA4_REG 0x5c
72#define SUN6I_DPHY_ANA4_REG_DMPLVC BIT(24)
73#define SUN6I_DPHY_ANA4_REG_DMPLVD(n) (((n) & 0xf) << 20)
74#define SUN6I_DPHY_ANA4_REG_CKDV(n) (((n) & 0x1f) << 12)
75#define SUN6I_DPHY_ANA4_REG_TMSC(n) (((n) & 3) << 10)
76#define SUN6I_DPHY_ANA4_REG_TMSD(n) (((n) & 3) << 8)
77#define SUN6I_DPHY_ANA4_REG_TXDNSC(n) (((n) & 3) << 6)
78#define SUN6I_DPHY_ANA4_REG_TXDNSD(n) (((n) & 3) << 4)
79#define SUN6I_DPHY_ANA4_REG_TXPUSC(n) (((n) & 3) << 2)
80#define SUN6I_DPHY_ANA4_REG_TXPUSD(n) ((n) & 3)
81
82#define SUN6I_DPHY_DBG5_REG 0xf4
83
84int sun6i_dphy_init(struct sun6i_dphy *dphy, unsigned int lanes)
85{
86 reset_control_deassert(dphy->reset);
87 clk_prepare_enable(dphy->mod_clk);
88 clk_set_rate_exclusive(dphy->mod_clk, 150000000);
89
90 regmap_write(dphy->regs, SUN6I_DPHY_TX_CTL_REG,
91 SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT);
92
93 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME0_REG,
94 SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(14) |
95 SUN6I_DPHY_TX_TIME0_HS_PREPARE(6) |
96 SUN6I_DPHY_TX_TIME0_HS_TRAIL(10));
97
98 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME1_REG,
99 SUN6I_DPHY_TX_TIME1_CLK_PREPARE(7) |
100 SUN6I_DPHY_TX_TIME1_CLK_ZERO(50) |
101 SUN6I_DPHY_TX_TIME1_CLK_PRE(3) |
102 SUN6I_DPHY_TX_TIME1_CLK_POST(10));
103
104 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME2_REG,
105 SUN6I_DPHY_TX_TIME2_CLK_TRAIL(30));
106
107 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME3_REG, 0);
108
109 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME4_REG,
110 SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(3) |
111 SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(3));
112
113 regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG,
114 SUN6I_DPHY_GCTL_LANE_NUM(lanes) |
115 SUN6I_DPHY_GCTL_EN);
116
117 return 0;
118}
119
120int sun6i_dphy_power_on(struct sun6i_dphy *dphy, unsigned int lanes)
121{
122 u8 lanes_mask = GENMASK(lanes - 1, 0);
123
124 regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG,
125 SUN6I_DPHY_ANA0_REG_PWS |
126 SUN6I_DPHY_ANA0_REG_DMPC |
127 SUN6I_DPHY_ANA0_REG_SLV(7) |
128 SUN6I_DPHY_ANA0_REG_DMPD(lanes_mask) |
129 SUN6I_DPHY_ANA0_REG_DEN(lanes_mask));
130
131 regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG,
132 SUN6I_DPHY_ANA1_REG_CSMPS(1) |
133 SUN6I_DPHY_ANA1_REG_SVTT(7));
134
135 regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG,
136 SUN6I_DPHY_ANA4_REG_CKDV(1) |
137 SUN6I_DPHY_ANA4_REG_TMSC(1) |
138 SUN6I_DPHY_ANA4_REG_TMSD(1) |
139 SUN6I_DPHY_ANA4_REG_TXDNSC(1) |
140 SUN6I_DPHY_ANA4_REG_TXDNSD(1) |
141 SUN6I_DPHY_ANA4_REG_TXPUSC(1) |
142 SUN6I_DPHY_ANA4_REG_TXPUSD(1) |
143 SUN6I_DPHY_ANA4_REG_DMPLVC |
144 SUN6I_DPHY_ANA4_REG_DMPLVD(lanes_mask));
145
146 regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG,
147 SUN6I_DPHY_ANA2_REG_ENIB);
148 udelay(5);
149
150 regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG,
151 SUN6I_DPHY_ANA3_EN_LDOR |
152 SUN6I_DPHY_ANA3_EN_LDOC |
153 SUN6I_DPHY_ANA3_EN_LDOD);
154 udelay(1);
155
156 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG,
157 SUN6I_DPHY_ANA3_EN_VTTC |
158 SUN6I_DPHY_ANA3_EN_VTTD_MASK,
159 SUN6I_DPHY_ANA3_EN_VTTC |
160 SUN6I_DPHY_ANA3_EN_VTTD(lanes_mask));
161 udelay(1);
162
163 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG,
164 SUN6I_DPHY_ANA3_EN_DIV,
165 SUN6I_DPHY_ANA3_EN_DIV);
166 udelay(1);
167
168 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG,
169 SUN6I_DPHY_ANA2_EN_CK_CPU,
170 SUN6I_DPHY_ANA2_EN_CK_CPU);
171 udelay(1);
172
173 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG,
174 SUN6I_DPHY_ANA1_REG_VTTMODE,
175 SUN6I_DPHY_ANA1_REG_VTTMODE);
176
177 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG,
178 SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK,
179 SUN6I_DPHY_ANA2_EN_P2S_CPU(lanes_mask));
180
181 return 0;
182}
183
184int sun6i_dphy_power_off(struct sun6i_dphy *dphy)
185{
186 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG,
187 SUN6I_DPHY_ANA1_REG_VTTMODE, 0);
188
189 return 0;
190}
191
192int sun6i_dphy_exit(struct sun6i_dphy *dphy)
193{
194 clk_rate_exclusive_put(dphy->mod_clk);
195 clk_disable_unprepare(dphy->mod_clk);
196 reset_control_assert(dphy->reset);
197
198 return 0;
199}
200
201static struct regmap_config sun6i_dphy_regmap_config = {
202 .reg_bits = 32,
203 .val_bits = 32,
204 .reg_stride = 4,
205 .max_register = SUN6I_DPHY_DBG5_REG,
206 .name = "mipi-dphy",
207};
208
209static const struct of_device_id sun6i_dphy_of_table[] = {
210 { .compatible = "allwinner,sun6i-a31-mipi-dphy" },
211 { }
212};
213
214int sun6i_dphy_probe(struct sun6i_dsi *dsi, struct device_node *node)
215{
216 struct sun6i_dphy *dphy;
217 struct resource res;
218 void __iomem *regs;
219 int ret;
220
221 if (!of_match_node(sun6i_dphy_of_table, node)) {
222 dev_err(dsi->dev, "Incompatible D-PHY\n");
223 return -EINVAL;
224 }
225
226 dphy = devm_kzalloc(dsi->dev, sizeof(*dphy), GFP_KERNEL);
227 if (!dphy)
228 return -ENOMEM;
229
230 ret = of_address_to_resource(node, 0, &res);
231 if (ret) {
232 dev_err(dsi->dev, "phy: Couldn't get our resources\n");
233 return ret;
234 }
235
236 regs = devm_ioremap_resource(dsi->dev, &res);
237 if (IS_ERR(regs)) {
238 dev_err(dsi->dev, "Couldn't map the DPHY encoder registers\n");
239 return PTR_ERR(regs);
240 }
241
242 dphy->regs = devm_regmap_init_mmio(dsi->dev, regs,
243 &sun6i_dphy_regmap_config);
244 if (IS_ERR(dphy->regs)) {
245 dev_err(dsi->dev, "Couldn't create the DPHY encoder regmap\n");
246 return PTR_ERR(dphy->regs);
247 }
248
249 dphy->reset = of_reset_control_get_shared(node, NULL);
250 if (IS_ERR(dphy->reset)) {
251 dev_err(dsi->dev, "Couldn't get our reset line\n");
252 return PTR_ERR(dphy->reset);
253 }
254
255 dphy->bus_clk = of_clk_get_by_name(node, "bus");
256 if (IS_ERR(dphy->bus_clk)) {
257 dev_err(dsi->dev, "Couldn't get the DPHY bus clock\n");
258 ret = PTR_ERR(dphy->bus_clk);
259 goto err_free_reset;
260 }
261 regmap_mmio_attach_clk(dphy->regs, dphy->bus_clk);
262
263 dphy->mod_clk = of_clk_get_by_name(node, "mod");
264 if (IS_ERR(dphy->mod_clk)) {
265 dev_err(dsi->dev, "Couldn't get the DPHY mod clock\n");
266 ret = PTR_ERR(dphy->mod_clk);
267 goto err_free_bus;
268 }
269
270 dsi->dphy = dphy;
271
272 return 0;
273
274err_free_bus:
275 regmap_mmio_detach_clk(dphy->regs);
276 clk_put(dphy->bus_clk);
277err_free_reset:
278 reset_control_put(dphy->reset);
279 return ret;
280}
281
282int sun6i_dphy_remove(struct sun6i_dsi *dsi)
283{
284 struct sun6i_dphy *dphy = dsi->dphy;
285
286 regmap_mmio_detach_clk(dphy->regs);
287 clk_put(dphy->mod_clk);
288 clk_put(dphy->bus_clk);
289 reset_control_put(dphy->reset);
290
291 return 0;
292}
293