1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2016 Allwinnertech Co., Ltd.
4  * Copyright (C) 2017-2018 Bootlin
5  *
6  * Maxime Ripard <maxime.ripard@free-electrons.com>
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 
sun6i_dphy_init(struct sun6i_dphy * dphy,unsigned int lanes)84 int 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 
sun6i_dphy_power_on(struct sun6i_dphy * dphy,unsigned int lanes)120 int 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 
sun6i_dphy_power_off(struct sun6i_dphy * dphy)184 int 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 
sun6i_dphy_exit(struct sun6i_dphy * dphy)192 int 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 
201 static 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 
209 static const struct of_device_id sun6i_dphy_of_table[] = {
210 	{ .compatible = "allwinner,sun6i-a31-mipi-dphy" },
211 	{ }
212 };
213 
sun6i_dphy_probe(struct sun6i_dsi * dsi,struct device_node * node)214 int 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 
274 err_free_bus:
275 	regmap_mmio_detach_clk(dphy->regs);
276 	clk_put(dphy->bus_clk);
277 err_free_reset:
278 	reset_control_put(dphy->reset);
279 	return ret;
280 }
281 
sun6i_dphy_remove(struct sun6i_dsi * dsi)282 int 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