]>
Commit | Line | Data |
---|---|---|
235bad02 RL |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Copyright (c) 2015 - 2019 MediaTek Inc. | |
4 | * Author: Chunfeng Yun <[email protected]> | |
5 | * Ryder Lee <[email protected]> | |
6 | */ | |
7 | ||
8 | #include <common.h> | |
9 | #include <clk.h> | |
10 | #include <dm.h> | |
11 | #include <generic-phy.h> | |
12 | #include <mapmem.h> | |
13 | #include <asm/io.h> | |
14 | ||
15 | #include <dt-bindings/phy/phy.h> | |
16 | ||
17 | /* version V1 sub-banks offset base address */ | |
18 | /* banks shared by multiple phys */ | |
19 | #define SSUSB_SIFSLV_V1_SPLLC 0x000 /* shared by u3 phys */ | |
20 | #define SSUSB_SIFSLV_V1_CHIP 0x300 /* shared by u3 phys */ | |
21 | /* u3/pcie/sata phy banks */ | |
22 | #define SSUSB_SIFSLV_V1_U3PHYD 0x000 | |
23 | #define SSUSB_SIFSLV_V1_U3PHYA 0x200 | |
24 | ||
25 | #define U3P_U3_CHIP_GPIO_CTLD 0x0c | |
26 | #define P3C_REG_IP_SW_RST BIT(31) | |
27 | #define P3C_MCU_BUS_CK_GATE_EN BIT(30) | |
28 | #define P3C_FORCE_IP_SW_RST BIT(29) | |
29 | ||
30 | #define U3P_U3_CHIP_GPIO_CTLE 0x10 | |
31 | #define P3C_RG_SWRST_U3_PHYD BIT(25) | |
32 | #define P3C_RG_SWRST_U3_PHYD_FORCE_EN BIT(24) | |
33 | ||
34 | #define U3P_U3_PHYA_REG0 0x000 | |
35 | #define P3A_RG_CLKDRV_OFF GENMASK(3, 2) | |
36 | #define P3A_RG_CLKDRV_OFF_VAL(x) ((0x3 & (x)) << 2) | |
37 | ||
38 | #define U3P_U3_PHYA_REG1 0x004 | |
39 | #define P3A_RG_CLKDRV_AMP GENMASK(31, 29) | |
40 | #define P3A_RG_CLKDRV_AMP_VAL(x) ((0x7 & (x)) << 29) | |
41 | ||
42 | #define U3P_U3_PHYA_DA_REG0 0x100 | |
43 | #define P3A_RG_XTAL_EXT_PE2H GENMASK(17, 16) | |
44 | #define P3A_RG_XTAL_EXT_PE2H_VAL(x) ((0x3 & (x)) << 16) | |
45 | #define P3A_RG_XTAL_EXT_PE1H GENMASK(13, 12) | |
46 | #define P3A_RG_XTAL_EXT_PE1H_VAL(x) ((0x3 & (x)) << 12) | |
47 | #define P3A_RG_XTAL_EXT_EN_U3 GENMASK(11, 10) | |
48 | #define P3A_RG_XTAL_EXT_EN_U3_VAL(x) ((0x3 & (x)) << 10) | |
49 | ||
50 | #define U3P_U3_PHYA_DA_REG4 0x108 | |
51 | #define P3A_RG_PLL_DIVEN_PE2H GENMASK(21, 19) | |
52 | #define P3A_RG_PLL_BC_PE2H GENMASK(7, 6) | |
53 | #define P3A_RG_PLL_BC_PE2H_VAL(x) ((0x3 & (x)) << 6) | |
54 | ||
55 | #define U3P_U3_PHYA_DA_REG5 0x10c | |
56 | #define P3A_RG_PLL_BR_PE2H GENMASK(29, 28) | |
57 | #define P3A_RG_PLL_BR_PE2H_VAL(x) ((0x3 & (x)) << 28) | |
58 | #define P3A_RG_PLL_IC_PE2H GENMASK(15, 12) | |
59 | #define P3A_RG_PLL_IC_PE2H_VAL(x) ((0xf & (x)) << 12) | |
60 | ||
61 | #define U3P_U3_PHYA_DA_REG6 0x110 | |
62 | #define P3A_RG_PLL_IR_PE2H GENMASK(19, 16) | |
63 | #define P3A_RG_PLL_IR_PE2H_VAL(x) ((0xf & (x)) << 16) | |
64 | ||
65 | #define U3P_U3_PHYA_DA_REG7 0x114 | |
66 | #define P3A_RG_PLL_BP_PE2H GENMASK(19, 16) | |
67 | #define P3A_RG_PLL_BP_PE2H_VAL(x) ((0xf & (x)) << 16) | |
68 | ||
69 | #define U3P_U3_PHYA_DA_REG20 0x13c | |
70 | #define P3A_RG_PLL_DELTA1_PE2H GENMASK(31, 16) | |
71 | #define P3A_RG_PLL_DELTA1_PE2H_VAL(x) ((0xffff & (x)) << 16) | |
72 | ||
73 | #define U3P_U3_PHYA_DA_REG25 0x148 | |
74 | #define P3A_RG_PLL_DELTA_PE2H GENMASK(15, 0) | |
75 | #define P3A_RG_PLL_DELTA_PE2H_VAL(x) (0xffff & (x)) | |
76 | ||
77 | #define U3P_U3_PHYD_RXDET1 0x128 | |
78 | #define P3D_RG_RXDET_STB2_SET GENMASK(17, 9) | |
79 | #define P3D_RG_RXDET_STB2_SET_VAL(x) ((0x1ff & (x)) << 9) | |
80 | ||
81 | #define U3P_U3_PHYD_RXDET2 0x12c | |
82 | #define P3D_RG_RXDET_STB2_SET_P3 GENMASK(8, 0) | |
83 | #define P3D_RG_RXDET_STB2_SET_P3_VAL(x) (0x1ff & (x)) | |
84 | ||
85 | struct u3phy_banks { | |
86 | void __iomem *spllc; | |
87 | void __iomem *chip; | |
88 | void __iomem *phyd; /* include u3phyd_bank2 */ | |
89 | void __iomem *phya; /* include u3phya_da */ | |
90 | }; | |
91 | ||
92 | struct mtk_phy_instance { | |
93 | void __iomem *port_base; | |
94 | const struct device_node *np; | |
95 | ||
96 | struct u3phy_banks u3_banks; | |
97 | ||
98 | /* reference clock of anolog phy */ | |
99 | struct clk ref_clk; | |
100 | u32 index; | |
101 | u8 type; | |
102 | }; | |
103 | ||
104 | struct mtk_tphy { | |
105 | void __iomem *sif_base; | |
106 | struct mtk_phy_instance **phys; | |
107 | int nphys; | |
108 | }; | |
109 | ||
110 | static void pcie_phy_instance_init(struct mtk_tphy *tphy, | |
111 | struct mtk_phy_instance *instance) | |
112 | { | |
113 | struct u3phy_banks *u3_banks = &instance->u3_banks; | |
114 | ||
115 | clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_DA_REG0, | |
116 | P3A_RG_XTAL_EXT_PE1H | P3A_RG_XTAL_EXT_PE2H, | |
117 | P3A_RG_XTAL_EXT_PE1H_VAL(0x2) | | |
118 | P3A_RG_XTAL_EXT_PE2H_VAL(0x2)); | |
119 | ||
120 | /* ref clk drive */ | |
121 | clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_REG1, P3A_RG_CLKDRV_AMP, | |
122 | P3A_RG_CLKDRV_AMP_VAL(0x4)); | |
123 | clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_REG0, P3A_RG_CLKDRV_OFF, | |
124 | P3A_RG_CLKDRV_OFF_VAL(0x1)); | |
125 | ||
126 | /* SSC delta -5000ppm */ | |
127 | clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_DA_REG20, | |
128 | P3A_RG_PLL_DELTA1_PE2H, | |
129 | P3A_RG_PLL_DELTA1_PE2H_VAL(0x3c)); | |
130 | ||
131 | clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_DA_REG25, | |
132 | P3A_RG_PLL_DELTA_PE2H, | |
133 | P3A_RG_PLL_DELTA_PE2H_VAL(0x36)); | |
134 | ||
135 | /* change pll BW 0.6M */ | |
136 | clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_DA_REG5, | |
137 | P3A_RG_PLL_BR_PE2H | P3A_RG_PLL_IC_PE2H, | |
138 | P3A_RG_PLL_BR_PE2H_VAL(0x1) | | |
139 | P3A_RG_PLL_IC_PE2H_VAL(0x1)); | |
140 | clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_DA_REG4, | |
141 | P3A_RG_PLL_DIVEN_PE2H | P3A_RG_PLL_BC_PE2H, | |
142 | P3A_RG_PLL_BC_PE2H_VAL(0x3)); | |
143 | ||
144 | clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_DA_REG6, | |
145 | P3A_RG_PLL_IR_PE2H, P3A_RG_PLL_IR_PE2H_VAL(0x2)); | |
146 | clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_DA_REG7, | |
147 | P3A_RG_PLL_BP_PE2H, P3A_RG_PLL_BP_PE2H_VAL(0xa)); | |
148 | ||
149 | /* Tx Detect Rx Timing: 10us -> 5us */ | |
150 | clrsetbits_le32(u3_banks->phyd + U3P_U3_PHYD_RXDET1, | |
151 | P3D_RG_RXDET_STB2_SET, | |
152 | P3D_RG_RXDET_STB2_SET_VAL(0x10)); | |
153 | clrsetbits_le32(u3_banks->phyd + U3P_U3_PHYD_RXDET2, | |
154 | P3D_RG_RXDET_STB2_SET_P3, | |
155 | P3D_RG_RXDET_STB2_SET_P3_VAL(0x10)); | |
156 | ||
157 | /* wait for PCIe subsys register to active */ | |
158 | udelay(3000); | |
159 | } | |
160 | ||
161 | static void pcie_phy_instance_power_on(struct mtk_tphy *tphy, | |
162 | struct mtk_phy_instance *instance) | |
163 | { | |
164 | struct u3phy_banks *bank = &instance->u3_banks; | |
165 | ||
166 | clrbits_le32(bank->chip + U3P_U3_CHIP_GPIO_CTLD, | |
167 | P3C_FORCE_IP_SW_RST | P3C_REG_IP_SW_RST); | |
168 | clrbits_le32(bank->chip + U3P_U3_CHIP_GPIO_CTLE, | |
169 | P3C_RG_SWRST_U3_PHYD_FORCE_EN | P3C_RG_SWRST_U3_PHYD); | |
170 | } | |
171 | ||
172 | static void pcie_phy_instance_power_off(struct mtk_tphy *tphy, | |
173 | struct mtk_phy_instance *instance) | |
174 | ||
175 | { | |
176 | struct u3phy_banks *bank = &instance->u3_banks; | |
177 | ||
178 | setbits_le32(bank->chip + U3P_U3_CHIP_GPIO_CTLD, | |
179 | P3C_FORCE_IP_SW_RST | P3C_REG_IP_SW_RST); | |
180 | setbits_le32(bank->chip + U3P_U3_CHIP_GPIO_CTLE, | |
181 | P3C_RG_SWRST_U3_PHYD_FORCE_EN | P3C_RG_SWRST_U3_PHYD); | |
182 | } | |
183 | ||
184 | static void phy_v1_banks_init(struct mtk_tphy *tphy, | |
185 | struct mtk_phy_instance *instance) | |
186 | { | |
187 | struct u3phy_banks *u3_banks = &instance->u3_banks; | |
188 | ||
189 | switch (instance->type) { | |
190 | case PHY_TYPE_PCIE: | |
191 | u3_banks->spllc = tphy->sif_base + SSUSB_SIFSLV_V1_SPLLC; | |
192 | u3_banks->chip = tphy->sif_base + SSUSB_SIFSLV_V1_CHIP; | |
193 | u3_banks->phyd = instance->port_base + SSUSB_SIFSLV_V1_U3PHYD; | |
194 | u3_banks->phya = instance->port_base + SSUSB_SIFSLV_V1_U3PHYA; | |
195 | break; | |
196 | default: | |
197 | return; | |
198 | } | |
199 | } | |
200 | ||
201 | static int mtk_phy_init(struct phy *phy) | |
202 | { | |
203 | struct mtk_tphy *tphy = dev_get_priv(phy->dev); | |
204 | struct mtk_phy_instance *instance = tphy->phys[phy->id]; | |
205 | int ret; | |
206 | ||
207 | /* we may use a fixed-clock here */ | |
208 | ret = clk_enable(&instance->ref_clk); | |
209 | if (ret && ret != -ENOSYS) | |
210 | return ret; | |
211 | ||
212 | switch (instance->type) { | |
213 | case PHY_TYPE_PCIE: | |
214 | pcie_phy_instance_init(tphy, instance); | |
215 | break; | |
216 | default: | |
217 | return -EINVAL; | |
218 | } | |
219 | ||
220 | return 0; | |
221 | } | |
222 | ||
223 | static int mtk_phy_power_on(struct phy *phy) | |
224 | { | |
225 | struct mtk_tphy *tphy = dev_get_priv(phy->dev); | |
226 | struct mtk_phy_instance *instance = tphy->phys[phy->id]; | |
227 | ||
228 | pcie_phy_instance_power_on(tphy, instance); | |
229 | ||
230 | return 0; | |
231 | } | |
232 | ||
233 | static int mtk_phy_power_off(struct phy *phy) | |
234 | { | |
235 | struct mtk_tphy *tphy = dev_get_priv(phy->dev); | |
236 | struct mtk_phy_instance *instance = tphy->phys[phy->id]; | |
237 | ||
238 | pcie_phy_instance_power_off(tphy, instance); | |
239 | ||
240 | return 0; | |
241 | } | |
242 | ||
243 | static int mtk_phy_exit(struct phy *phy) | |
244 | { | |
245 | struct mtk_tphy *tphy = dev_get_priv(phy->dev); | |
246 | struct mtk_phy_instance *instance = tphy->phys[phy->id]; | |
247 | ||
248 | clk_disable(&instance->ref_clk); | |
249 | ||
250 | return 0; | |
251 | } | |
252 | ||
253 | static int mtk_phy_xlate(struct phy *phy, | |
254 | struct ofnode_phandle_args *args) | |
255 | { | |
256 | struct mtk_tphy *tphy = dev_get_priv(phy->dev); | |
257 | struct mtk_phy_instance *instance = NULL; | |
258 | const struct device_node *phy_np = ofnode_to_np(args->node); | |
259 | u32 index; | |
260 | ||
261 | if (!phy_np) { | |
262 | dev_err(phy->dev, "null pointer phy node\n"); | |
263 | return -EINVAL; | |
264 | } | |
265 | ||
266 | if (args->args_count < 1) { | |
267 | dev_err(phy->dev, "invalid number of cells in 'phy' property\n"); | |
268 | return -EINVAL; | |
269 | } | |
270 | ||
271 | for (index = 0; index < tphy->nphys; index++) | |
272 | if (phy_np == tphy->phys[index]->np) { | |
273 | instance = tphy->phys[index]; | |
274 | break; | |
275 | } | |
276 | ||
277 | if (!instance) { | |
278 | dev_err(phy->dev, "failed to find appropriate phy\n"); | |
279 | return -EINVAL; | |
280 | } | |
281 | ||
282 | phy->id = index; | |
283 | instance->type = args->args[1]; | |
284 | if (!(instance->type == PHY_TYPE_USB2 || | |
285 | instance->type == PHY_TYPE_USB3 || | |
286 | instance->type == PHY_TYPE_PCIE || | |
287 | instance->type == PHY_TYPE_SATA)) { | |
288 | dev_err(phy->dev, "unsupported device type\n"); | |
289 | return -EINVAL; | |
290 | } | |
291 | ||
292 | phy_v1_banks_init(tphy, instance); | |
293 | ||
294 | return 0; | |
295 | } | |
296 | ||
297 | static const struct phy_ops mtk_tphy_ops = { | |
298 | .init = mtk_phy_init, | |
299 | .exit = mtk_phy_exit, | |
300 | .power_on = mtk_phy_power_on, | |
301 | .power_off = mtk_phy_power_off, | |
302 | .of_xlate = mtk_phy_xlate, | |
303 | }; | |
304 | ||
305 | static int mtk_tphy_probe(struct udevice *dev) | |
306 | { | |
307 | struct mtk_tphy *tphy = dev_get_priv(dev); | |
308 | ofnode subnode; | |
309 | int index = 0; | |
310 | ||
311 | dev_for_each_subnode(subnode, dev) | |
312 | tphy->nphys++; | |
313 | ||
314 | tphy->phys = devm_kcalloc(dev, tphy->nphys, sizeof(*tphy->phys), | |
315 | GFP_KERNEL); | |
316 | if (!tphy->phys) | |
317 | return -ENOMEM; | |
318 | ||
319 | tphy->sif_base = dev_read_addr_ptr(dev); | |
320 | if (!tphy->sif_base) | |
321 | return -ENOENT; | |
322 | ||
323 | dev_for_each_subnode(subnode, dev) { | |
324 | struct mtk_phy_instance *instance; | |
325 | fdt_addr_t addr; | |
326 | int err; | |
327 | ||
328 | instance = devm_kzalloc(dev, sizeof(*instance), GFP_KERNEL); | |
329 | if (!instance) | |
330 | return -ENOMEM; | |
331 | ||
332 | addr = ofnode_get_addr(subnode); | |
333 | if (addr == FDT_ADDR_T_NONE) | |
334 | return -ENOMEM; | |
335 | ||
336 | instance->port_base = map_sysmem(addr, 0); | |
337 | instance->index = index; | |
338 | instance->np = ofnode_to_np(subnode); | |
339 | tphy->phys[index] = instance; | |
340 | index++; | |
341 | ||
342 | err = clk_get_by_index_nodev(subnode, 0, &instance->ref_clk); | |
343 | if (err) | |
344 | return err; | |
345 | } | |
346 | ||
347 | return 0; | |
348 | } | |
349 | ||
350 | static const struct udevice_id mtk_tphy_id_table[] = { | |
351 | { .compatible = "mediatek,generic-tphy-v1", }, | |
352 | { } | |
353 | }; | |
354 | ||
355 | U_BOOT_DRIVER(mtk_tphy) = { | |
356 | .name = "mtk-tphy", | |
357 | .id = UCLASS_PHY, | |
358 | .of_match = mtk_tphy_id_table, | |
359 | .ops = &mtk_tphy_ops, | |
360 | .probe = mtk_tphy_probe, | |
361 | .priv_auto_alloc_size = sizeof(struct mtk_tphy), | |
362 | }; |