GNU Linux-libre 4.19.245-gnu1
[releases.git] / drivers / gpu / drm / sun4i / sun6i_mipi_dphy.c
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
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
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
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
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
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
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 }