1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (c) 2022 MediaTek Inc. |
4 | * Author: Jianjun Wang <jianjun.wang@mediatek.com> |
5 | */ |
6 | |
7 | #include <linux/bitfield.h> |
8 | #include <linux/module.h> |
9 | #include <linux/nvmem-consumer.h> |
10 | #include <linux/of.h> |
11 | #include <linux/phy/phy.h> |
12 | #include <linux/platform_device.h> |
13 | #include <linux/slab.h> |
14 | |
15 | #include "phy-mtk-io.h" |
16 | |
17 | #define PEXTP_ANA_GLB_00_REG 0x9000 |
18 | /* Internal Resistor Selection of TX Bias Current */ |
19 | #define EFUSE_GLB_INTR_SEL GENMASK(28, 24) |
20 | |
21 | #define PEXTP_ANA_LN0_TRX_REG 0xa000 |
22 | |
23 | #define PEXTP_ANA_TX_REG 0x04 |
24 | /* TX PMOS impedance selection */ |
25 | #define EFUSE_LN_TX_PMOS_SEL GENMASK(5, 2) |
26 | /* TX NMOS impedance selection */ |
27 | #define EFUSE_LN_TX_NMOS_SEL GENMASK(11, 8) |
28 | |
29 | #define PEXTP_ANA_RX_REG 0x3c |
30 | /* RX impedance selection */ |
31 | #define EFUSE_LN_RX_SEL GENMASK(3, 0) |
32 | |
33 | #define PEXTP_ANA_LANE_OFFSET 0x100 |
34 | |
35 | /** |
36 | * struct mtk_pcie_lane_efuse - eFuse data for each lane |
37 | * @tx_pmos: TX PMOS impedance selection data |
38 | * @tx_nmos: TX NMOS impedance selection data |
39 | * @rx_data: RX impedance selection data |
40 | * @lane_efuse_supported: software eFuse data is supported for this lane |
41 | */ |
42 | struct mtk_pcie_lane_efuse { |
43 | u32 tx_pmos; |
44 | u32 tx_nmos; |
45 | u32 rx_data; |
46 | bool lane_efuse_supported; |
47 | }; |
48 | |
49 | /** |
50 | * struct mtk_pcie_phy_data - phy data for each SoC |
51 | * @num_lanes: supported lane numbers |
52 | * @sw_efuse_supported: support software to load eFuse data |
53 | */ |
54 | struct mtk_pcie_phy_data { |
55 | int num_lanes; |
56 | bool sw_efuse_supported; |
57 | }; |
58 | |
59 | /** |
60 | * struct mtk_pcie_phy - PCIe phy driver main structure |
61 | * @dev: pointer to device |
62 | * @phy: pointer to generic phy |
63 | * @sif_base: IO mapped register base address of system interface |
64 | * @data: pointer to SoC dependent data |
65 | * @sw_efuse_en: software eFuse enable status |
66 | * @efuse_glb_intr: internal resistor selection of TX bias current data |
67 | * @efuse: pointer to eFuse data for each lane |
68 | */ |
69 | struct mtk_pcie_phy { |
70 | struct device *dev; |
71 | struct phy *phy; |
72 | void __iomem *sif_base; |
73 | const struct mtk_pcie_phy_data *data; |
74 | |
75 | bool sw_efuse_en; |
76 | u32 efuse_glb_intr; |
77 | struct mtk_pcie_lane_efuse *efuse; |
78 | }; |
79 | |
80 | static void mtk_pcie_efuse_set_lane(struct mtk_pcie_phy *pcie_phy, |
81 | unsigned int lane) |
82 | { |
83 | struct mtk_pcie_lane_efuse *data = &pcie_phy->efuse[lane]; |
84 | void __iomem *addr; |
85 | |
86 | if (!data->lane_efuse_supported) |
87 | return; |
88 | |
89 | addr = pcie_phy->sif_base + PEXTP_ANA_LN0_TRX_REG + |
90 | lane * PEXTP_ANA_LANE_OFFSET; |
91 | |
92 | mtk_phy_update_field(addr + PEXTP_ANA_TX_REG, EFUSE_LN_TX_PMOS_SEL, |
93 | data->tx_pmos); |
94 | |
95 | mtk_phy_update_field(addr + PEXTP_ANA_TX_REG, EFUSE_LN_TX_NMOS_SEL, |
96 | data->tx_nmos); |
97 | |
98 | mtk_phy_update_field(addr + PEXTP_ANA_RX_REG, EFUSE_LN_RX_SEL, |
99 | data->rx_data); |
100 | } |
101 | |
102 | /** |
103 | * mtk_pcie_phy_init() - Initialize the phy |
104 | * @phy: the phy to be initialized |
105 | * |
106 | * Initialize the phy by setting the efuse data. |
107 | * The hardware settings will be reset during suspend, it should be |
108 | * reinitialized when the consumer calls phy_init() again on resume. |
109 | */ |
110 | static int mtk_pcie_phy_init(struct phy *phy) |
111 | { |
112 | struct mtk_pcie_phy *pcie_phy = phy_get_drvdata(phy); |
113 | int i; |
114 | |
115 | if (!pcie_phy->sw_efuse_en) |
116 | return 0; |
117 | |
118 | /* Set global data */ |
119 | mtk_phy_update_field(pcie_phy->sif_base + PEXTP_ANA_GLB_00_REG, |
120 | EFUSE_GLB_INTR_SEL, pcie_phy->efuse_glb_intr); |
121 | |
122 | for (i = 0; i < pcie_phy->data->num_lanes; i++) |
123 | mtk_pcie_efuse_set_lane(pcie_phy, lane: i); |
124 | |
125 | return 0; |
126 | } |
127 | |
128 | static const struct phy_ops mtk_pcie_phy_ops = { |
129 | .init = mtk_pcie_phy_init, |
130 | .owner = THIS_MODULE, |
131 | }; |
132 | |
133 | static int mtk_pcie_efuse_read_for_lane(struct mtk_pcie_phy *pcie_phy, |
134 | unsigned int lane) |
135 | { |
136 | struct mtk_pcie_lane_efuse *efuse = &pcie_phy->efuse[lane]; |
137 | struct device *dev = pcie_phy->dev; |
138 | char efuse_id[16]; |
139 | int ret; |
140 | |
141 | snprintf(buf: efuse_id, size: sizeof(efuse_id), fmt: "tx_ln%d_pmos" , lane); |
142 | ret = nvmem_cell_read_variable_le_u32(dev, cell_id: efuse_id, val: &efuse->tx_pmos); |
143 | if (ret) |
144 | return dev_err_probe(dev, err: ret, fmt: "Failed to read %s\n" , efuse_id); |
145 | |
146 | snprintf(buf: efuse_id, size: sizeof(efuse_id), fmt: "tx_ln%d_nmos" , lane); |
147 | ret = nvmem_cell_read_variable_le_u32(dev, cell_id: efuse_id, val: &efuse->tx_nmos); |
148 | if (ret) |
149 | return dev_err_probe(dev, err: ret, fmt: "Failed to read %s\n" , efuse_id); |
150 | |
151 | snprintf(buf: efuse_id, size: sizeof(efuse_id), fmt: "rx_ln%d" , lane); |
152 | ret = nvmem_cell_read_variable_le_u32(dev, cell_id: efuse_id, val: &efuse->rx_data); |
153 | if (ret) |
154 | return dev_err_probe(dev, err: ret, fmt: "Failed to read %s\n" , efuse_id); |
155 | |
156 | if (!(efuse->tx_pmos || efuse->tx_nmos || efuse->rx_data)) |
157 | return dev_err_probe(dev, err: -EINVAL, |
158 | fmt: "No eFuse data found for lane%d, but dts enable it\n" , |
159 | lane); |
160 | |
161 | efuse->lane_efuse_supported = true; |
162 | |
163 | return 0; |
164 | } |
165 | |
166 | static int mtk_pcie_read_efuse(struct mtk_pcie_phy *pcie_phy) |
167 | { |
168 | struct device *dev = pcie_phy->dev; |
169 | bool nvmem_enabled; |
170 | int ret, i; |
171 | |
172 | /* nvmem data is optional */ |
173 | nvmem_enabled = device_property_present(dev, propname: "nvmem-cells" ); |
174 | if (!nvmem_enabled) |
175 | return 0; |
176 | |
177 | ret = nvmem_cell_read_variable_le_u32(dev, cell_id: "glb_intr" , |
178 | val: &pcie_phy->efuse_glb_intr); |
179 | if (ret) |
180 | return dev_err_probe(dev, err: ret, fmt: "Failed to read glb_intr\n" ); |
181 | |
182 | pcie_phy->sw_efuse_en = true; |
183 | |
184 | pcie_phy->efuse = devm_kzalloc(dev, size: pcie_phy->data->num_lanes * |
185 | sizeof(*pcie_phy->efuse), GFP_KERNEL); |
186 | if (!pcie_phy->efuse) |
187 | return -ENOMEM; |
188 | |
189 | for (i = 0; i < pcie_phy->data->num_lanes; i++) { |
190 | ret = mtk_pcie_efuse_read_for_lane(pcie_phy, lane: i); |
191 | if (ret) |
192 | return ret; |
193 | } |
194 | |
195 | return 0; |
196 | } |
197 | |
198 | static int mtk_pcie_phy_probe(struct platform_device *pdev) |
199 | { |
200 | struct device *dev = &pdev->dev; |
201 | struct phy_provider *provider; |
202 | struct mtk_pcie_phy *pcie_phy; |
203 | int ret; |
204 | |
205 | pcie_phy = devm_kzalloc(dev, size: sizeof(*pcie_phy), GFP_KERNEL); |
206 | if (!pcie_phy) |
207 | return -ENOMEM; |
208 | |
209 | pcie_phy->sif_base = devm_platform_ioremap_resource_byname(pdev, name: "sif" ); |
210 | if (IS_ERR(ptr: pcie_phy->sif_base)) |
211 | return dev_err_probe(dev, err: PTR_ERR(ptr: pcie_phy->sif_base), |
212 | fmt: "Failed to map phy-sif base\n" ); |
213 | |
214 | pcie_phy->phy = devm_phy_create(dev, node: dev->of_node, ops: &mtk_pcie_phy_ops); |
215 | if (IS_ERR(ptr: pcie_phy->phy)) |
216 | return dev_err_probe(dev, err: PTR_ERR(ptr: pcie_phy->phy), |
217 | fmt: "Failed to create PCIe phy\n" ); |
218 | |
219 | pcie_phy->dev = dev; |
220 | pcie_phy->data = of_device_get_match_data(dev); |
221 | if (!pcie_phy->data) |
222 | return dev_err_probe(dev, err: -EINVAL, fmt: "Failed to get phy data\n" ); |
223 | |
224 | if (pcie_phy->data->sw_efuse_supported) { |
225 | /* |
226 | * Failed to read the efuse data is not a fatal problem, |
227 | * ignore the failure and keep going. |
228 | */ |
229 | ret = mtk_pcie_read_efuse(pcie_phy); |
230 | if (ret == -EPROBE_DEFER || ret == -ENOMEM) |
231 | return ret; |
232 | } |
233 | |
234 | phy_set_drvdata(phy: pcie_phy->phy, data: pcie_phy); |
235 | |
236 | provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); |
237 | if (IS_ERR(ptr: provider)) |
238 | return dev_err_probe(dev, err: PTR_ERR(ptr: provider), |
239 | fmt: "PCIe phy probe failed\n" ); |
240 | |
241 | return 0; |
242 | } |
243 | |
244 | static const struct mtk_pcie_phy_data mt8195_data = { |
245 | .num_lanes = 2, |
246 | .sw_efuse_supported = true, |
247 | }; |
248 | |
249 | static const struct of_device_id mtk_pcie_phy_of_match[] = { |
250 | { .compatible = "mediatek,mt8195-pcie-phy" , .data = &mt8195_data }, |
251 | { }, |
252 | }; |
253 | MODULE_DEVICE_TABLE(of, mtk_pcie_phy_of_match); |
254 | |
255 | static struct platform_driver mtk_pcie_phy_driver = { |
256 | .probe = mtk_pcie_phy_probe, |
257 | .driver = { |
258 | .name = "mtk-pcie-phy" , |
259 | .of_match_table = mtk_pcie_phy_of_match, |
260 | }, |
261 | }; |
262 | module_platform_driver(mtk_pcie_phy_driver); |
263 | |
264 | MODULE_DESCRIPTION("MediaTek PCIe PHY driver" ); |
265 | MODULE_AUTHOR("Jianjun Wang <jianjun.wang@mediatek.com>" ); |
266 | MODULE_LICENSE("GPL" ); |
267 | |