8872005376d525df0720201af35e98b94b26e495
[openwrt/staging/stintel.git] /
1 From a29ee27a42fc208ef1cd99f5014d57dbfe1af3dd Mon Sep 17 00:00:00 2001
2 From: Luo Jie <quic_luoj@quicinc.com>
3 Date: Tue, 26 Dec 2023 17:11:35 +0800
4 Subject: [PATCH 18/50] net: ethernet: qualcomm: Add PPE driver for IPQ9574 SoC
5
6 The PPE (Packet Process Engine) hardware block is available
7 on Qualcomm IPQ SoC that support PPE architecture, such as
8 IPQ9574.
9
10 The PPE in IPQ9574 includes six integrated ethernet MAC
11 (for 6 PPE ports), buffer management, queue management and
12 scheduler functions. The MACs can connect with the external
13 PHY or switch devices using the UNIPHY PCS block available
14 in the SoC.
15
16 The PPE also includes various packet processing offload
17 capabilities such as L3 routing and L2 bridging, VLAN and
18 tunnel processing offload. It also includes Ethernet DMA (EDMA)
19 function for transferring packets between ARM cores and PPE
20 ethernet ports.
21
22 This patch adds the base source files and Makefiles for the PPE
23 driver such as platform driver registration, clock initialization,
24 and PPE reset routines.
25
26 Change-Id: I73166b5d4bb7e3c42ec6e0ac178a75528a25ef30
27 Signed-off-by: Luo Jie <quic_luoj@quicinc.com>
28 ---
29 drivers/net/ethernet/qualcomm/Kconfig | 15 ++
30 drivers/net/ethernet/qualcomm/Makefile | 1 +
31 drivers/net/ethernet/qualcomm/ppe/Makefile | 7 +
32 drivers/net/ethernet/qualcomm/ppe/ppe.c | 225 +++++++++++++++++++++
33 drivers/net/ethernet/qualcomm/ppe/ppe.h | 36 ++++
34 5 files changed, 284 insertions(+)
35 create mode 100644 drivers/net/ethernet/qualcomm/ppe/Makefile
36 create mode 100644 drivers/net/ethernet/qualcomm/ppe/ppe.c
37 create mode 100644 drivers/net/ethernet/qualcomm/ppe/ppe.h
38
39 diff --git a/drivers/net/ethernet/qualcomm/Kconfig b/drivers/net/ethernet/qualcomm/Kconfig
40 index 9210ff360fdc..8cc24da48777 100644
41 --- a/drivers/net/ethernet/qualcomm/Kconfig
42 +++ b/drivers/net/ethernet/qualcomm/Kconfig
43 @@ -61,6 +61,21 @@ config QCOM_EMAC
44 low power, Receive-Side Scaling (RSS), and IEEE 1588-2008
45 Precision Clock Synchronization Protocol.
46
47 +config QCOM_PPE
48 + tristate "Qualcomm Technologies, Inc. PPE Ethernet support"
49 + depends on HAS_IOMEM && OF
50 + depends on COMMON_CLK
51 + select REGMAP_MMIO
52 + help
53 + This driver supports the Qualcomm Technologies, Inc. packet
54 + process engine (PPE) available with IPQ SoC. The PPE houses
55 + the ethernet MACs, Ethernet DMA (EDMA) and switch core that
56 + supports L3 flow offload, L2 switch function, RSS and tunnel
57 + offload.
58 +
59 + To compile this driver as a module, choose M here. The module
60 + will be called qcom-ppe.
61 +
62 source "drivers/net/ethernet/qualcomm/rmnet/Kconfig"
63
64 endif # NET_VENDOR_QUALCOMM
65 diff --git a/drivers/net/ethernet/qualcomm/Makefile b/drivers/net/ethernet/qualcomm/Makefile
66 index 9250976dd884..166a59aea363 100644
67 --- a/drivers/net/ethernet/qualcomm/Makefile
68 +++ b/drivers/net/ethernet/qualcomm/Makefile
69 @@ -11,4 +11,5 @@ qcauart-objs := qca_uart.o
70
71 obj-y += emac/
72
73 +obj-$(CONFIG_QCOM_PPE) += ppe/
74 obj-$(CONFIG_RMNET) += rmnet/
75 diff --git a/drivers/net/ethernet/qualcomm/ppe/Makefile b/drivers/net/ethernet/qualcomm/ppe/Makefile
76 new file mode 100644
77 index 000000000000..63d50d3b4f2e
78 --- /dev/null
79 +++ b/drivers/net/ethernet/qualcomm/ppe/Makefile
80 @@ -0,0 +1,7 @@
81 +# SPDX-License-Identifier: GPL-2.0-only
82 +#
83 +# Makefile for the device driver of PPE (Packet Process Engine) in IPQ SoC
84 +#
85 +
86 +obj-$(CONFIG_QCOM_PPE) += qcom-ppe.o
87 +qcom-ppe-objs := ppe.o
88 diff --git a/drivers/net/ethernet/qualcomm/ppe/ppe.c b/drivers/net/ethernet/qualcomm/ppe/ppe.c
89 new file mode 100644
90 index 000000000000..14998ac771c7
91 --- /dev/null
92 +++ b/drivers/net/ethernet/qualcomm/ppe/ppe.c
93 @@ -0,0 +1,225 @@
94 +// SPDX-License-Identifier: GPL-2.0-only
95 +/*
96 + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
97 + */
98 +
99 +/* PPE platform device probe, DTSI parser and PPE clock initializations. */
100 +
101 +#include <linux/clk.h>
102 +#include <linux/interconnect.h>
103 +#include <linux/kernel.h>
104 +#include <linux/module.h>
105 +#include <linux/of.h>
106 +#include <linux/platform_device.h>
107 +#include <linux/regmap.h>
108 +#include <linux/reset.h>
109 +
110 +#include "ppe.h"
111 +
112 +#define PPE_PORT_MAX 8
113 +#define PPE_CLK_RATE 353000000
114 +
115 +/* ICC clocks for enabling PPE device. The avg and peak with value 0
116 + * will be decided by the clock rate of PPE.
117 + */
118 +static const struct icc_bulk_data ppe_icc_data[] = {
119 + {
120 + .name = "ppe",
121 + .avg_bw = 0,
122 + .peak_bw = 0,
123 + },
124 + {
125 + .name = "ppe_cfg",
126 + .avg_bw = 0,
127 + .peak_bw = 0,
128 + },
129 + {
130 + .name = "qos_gen",
131 + .avg_bw = 6000,
132 + .peak_bw = 6000,
133 + },
134 + {
135 + .name = "timeout_ref",
136 + .avg_bw = 6000,
137 + .peak_bw = 6000,
138 + },
139 + {
140 + .name = "nssnoc_memnoc",
141 + .avg_bw = 533333,
142 + .peak_bw = 533333,
143 + },
144 + {
145 + .name = "memnoc_nssnoc",
146 + .avg_bw = 533333,
147 + .peak_bw = 533333,
148 + },
149 + {
150 + .name = "memnoc_nssnoc_1",
151 + .avg_bw = 533333,
152 + .peak_bw = 533333,
153 + },
154 +};
155 +
156 +static const struct regmap_range ppe_readable_ranges[] = {
157 + regmap_reg_range(0x0, 0x1ff), /* Global */
158 + regmap_reg_range(0x400, 0x5ff), /* LPI CSR */
159 + regmap_reg_range(0x1000, 0x11ff), /* GMAC0 */
160 + regmap_reg_range(0x1200, 0x13ff), /* GMAC1 */
161 + regmap_reg_range(0x1400, 0x15ff), /* GMAC2 */
162 + regmap_reg_range(0x1600, 0x17ff), /* GMAC3 */
163 + regmap_reg_range(0x1800, 0x19ff), /* GMAC4 */
164 + regmap_reg_range(0x1a00, 0x1bff), /* GMAC5 */
165 + regmap_reg_range(0xb000, 0xefff), /* PRX CSR */
166 + regmap_reg_range(0xf000, 0x1efff), /* IPE */
167 + regmap_reg_range(0x20000, 0x5ffff), /* PTX CSR */
168 + regmap_reg_range(0x60000, 0x9ffff), /* IPE L2 CSR */
169 + regmap_reg_range(0xb0000, 0xeffff), /* IPO CSR */
170 + regmap_reg_range(0x100000, 0x17ffff), /* IPE PC */
171 + regmap_reg_range(0x180000, 0x1bffff), /* PRE IPO CSR */
172 + regmap_reg_range(0x1d0000, 0x1dffff), /* Tunnel parser */
173 + regmap_reg_range(0x1e0000, 0x1effff), /* Ingress parse */
174 + regmap_reg_range(0x200000, 0x2fffff), /* IPE L3 */
175 + regmap_reg_range(0x300000, 0x3fffff), /* IPE tunnel */
176 + regmap_reg_range(0x400000, 0x4fffff), /* Scheduler */
177 + regmap_reg_range(0x500000, 0x503fff), /* XGMAC0 */
178 + regmap_reg_range(0x504000, 0x507fff), /* XGMAC1 */
179 + regmap_reg_range(0x508000, 0x50bfff), /* XGMAC2 */
180 + regmap_reg_range(0x50c000, 0x50ffff), /* XGMAC3 */
181 + regmap_reg_range(0x510000, 0x513fff), /* XGMAC4 */
182 + regmap_reg_range(0x514000, 0x517fff), /* XGMAC5 */
183 + regmap_reg_range(0x600000, 0x6fffff), /* BM */
184 + regmap_reg_range(0x800000, 0x9fffff), /* QM */
185 + regmap_reg_range(0xb00000, 0xbef800), /* EDMA */
186 +};
187 +
188 +static const struct regmap_access_table ppe_reg_table = {
189 + .yes_ranges = ppe_readable_ranges,
190 + .n_yes_ranges = ARRAY_SIZE(ppe_readable_ranges),
191 +};
192 +
193 +static const struct regmap_config regmap_config_ipq9574 = {
194 + .reg_bits = 32,
195 + .reg_stride = 4,
196 + .val_bits = 32,
197 + .rd_table = &ppe_reg_table,
198 + .wr_table = &ppe_reg_table,
199 + .max_register = 0xbef800,
200 + .fast_io = true,
201 +};
202 +
203 +static int ppe_clock_init_and_reset(struct ppe_device *ppe_dev)
204 +{
205 + unsigned long ppe_rate = ppe_dev->clk_rate;
206 + struct device *dev = ppe_dev->dev;
207 + struct reset_control *rstc;
208 + struct clk_bulk_data *clks;
209 + struct clk *clk;
210 + int ret, i;
211 +
212 + for (i = 0; i < ppe_dev->num_icc_paths; i++) {
213 + ppe_dev->icc_paths[i].name = ppe_icc_data[i].name;
214 + ppe_dev->icc_paths[i].avg_bw = ppe_icc_data[i].avg_bw ? :
215 + Bps_to_icc(ppe_rate);
216 + ppe_dev->icc_paths[i].peak_bw = ppe_icc_data[i].peak_bw ? :
217 + Bps_to_icc(ppe_rate);
218 + }
219 +
220 + ret = devm_of_icc_bulk_get(dev, ppe_dev->num_icc_paths,
221 + ppe_dev->icc_paths);
222 + if (ret)
223 + return ret;
224 +
225 + ret = icc_bulk_set_bw(ppe_dev->num_icc_paths, ppe_dev->icc_paths);
226 + if (ret)
227 + return ret;
228 +
229 + /* PPE clocks take the same clock tree, which work on the same
230 + * clock rate. Setting the clock rate of "ppe" ensures the clock
231 + * rate of all PPE clocks configured as same.
232 + */
233 + clk = devm_clk_get(dev, "ppe");
234 + if (IS_ERR(clk))
235 + return PTR_ERR(clk);
236 +
237 + ret = clk_set_rate(clk, ppe_rate);
238 + if (ret)
239 + return ret;
240 +
241 + ret = devm_clk_bulk_get_all_enabled(dev, &clks);
242 + if (ret < 0)
243 + return ret;
244 +
245 + rstc = devm_reset_control_get_exclusive(dev, NULL);
246 + if (IS_ERR(rstc))
247 + return PTR_ERR(rstc);
248 +
249 + /* Reset PPE, the delay 100ms of assert and deassert is necessary
250 + * for resetting PPE.
251 + */
252 + ret = reset_control_assert(rstc);
253 + if (ret)
254 + return ret;
255 +
256 + msleep(100);
257 + ret = reset_control_deassert(rstc);
258 + if (ret)
259 + return ret;
260 +
261 + msleep(100);
262 +
263 + return 0;
264 +}
265 +
266 +static int qcom_ppe_probe(struct platform_device *pdev)
267 +{
268 + struct device *dev = &pdev->dev;
269 + struct ppe_device *ppe_dev;
270 + void __iomem *base;
271 + int ret, num_icc;
272 +
273 + num_icc = ARRAY_SIZE(ppe_icc_data);
274 + ppe_dev = devm_kzalloc(dev,
275 + struct_size(ppe_dev, icc_paths, num_icc),
276 + GFP_KERNEL);
277 + if (!ppe_dev)
278 + return dev_err_probe(dev, -ENOMEM, "PPE alloc memory failed\n");
279 +
280 + base = devm_platform_ioremap_resource(pdev, 0);
281 + if (IS_ERR(base))
282 + return dev_err_probe(dev, PTR_ERR(base), "PPE ioremap failed\n");
283 +
284 + ppe_dev->regmap = devm_regmap_init_mmio(dev, base, &regmap_config_ipq9574);
285 + if (IS_ERR(ppe_dev->regmap))
286 + return dev_err_probe(dev, PTR_ERR(ppe_dev->regmap),
287 + "PPE initialize regmap failed\n");
288 + ppe_dev->dev = dev;
289 + ppe_dev->clk_rate = PPE_CLK_RATE;
290 + ppe_dev->num_ports = PPE_PORT_MAX;
291 + ppe_dev->num_icc_paths = num_icc;
292 +
293 + ret = ppe_clock_init_and_reset(ppe_dev);
294 + if (ret)
295 + return dev_err_probe(dev, ret, "PPE clock config failed\n");
296 +
297 + platform_set_drvdata(pdev, ppe_dev);
298 +
299 + return 0;
300 +}
301 +
302 +static const struct of_device_id qcom_ppe_of_match[] = {
303 + { .compatible = "qcom,ipq9574-ppe" },
304 + {},
305 +};
306 +MODULE_DEVICE_TABLE(of, qcom_ppe_of_match);
307 +
308 +static struct platform_driver qcom_ppe_driver = {
309 + .driver = {
310 + .name = "qcom_ppe",
311 + .of_match_table = qcom_ppe_of_match,
312 + },
313 + .probe = qcom_ppe_probe,
314 +};
315 +module_platform_driver(qcom_ppe_driver);
316 +
317 +MODULE_LICENSE("GPL");
318 +MODULE_DESCRIPTION("Qualcomm IPQ PPE driver");
319 diff --git a/drivers/net/ethernet/qualcomm/ppe/ppe.h b/drivers/net/ethernet/qualcomm/ppe/ppe.h
320 new file mode 100644
321 index 000000000000..733d77f4063d
322 --- /dev/null
323 +++ b/drivers/net/ethernet/qualcomm/ppe/ppe.h
324 @@ -0,0 +1,36 @@
325 +/* SPDX-License-Identifier: GPL-2.0-only
326 + *
327 + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
328 + */
329 +
330 +#ifndef __PPE_H__
331 +#define __PPE_H__
332 +
333 +#include <linux/compiler.h>
334 +#include <linux/interconnect.h>
335 +
336 +struct device;
337 +struct regmap;
338 +
339 +/**
340 + * struct ppe_device - PPE device private data.
341 + * @dev: PPE device structure.
342 + * @regmap: PPE register map.
343 + * @clk_rate: PPE clock rate.
344 + * @num_ports: Number of PPE ports.
345 + * @num_icc_paths: Number of interconnect paths.
346 + * @icc_paths: Interconnect path array.
347 + *
348 + * PPE device is the instance of PPE hardware, which is used to
349 + * configure PPE packet process modules such as BM (buffer management),
350 + * QM (queue management), and scheduler.
351 + */
352 +struct ppe_device {
353 + struct device *dev;
354 + struct regmap *regmap;
355 + unsigned long clk_rate;
356 + unsigned int num_ports;
357 + unsigned int num_icc_paths;
358 + struct icc_bulk_data icc_paths[] __counted_by(num_icc_paths);
359 +};
360 +#endif
361 --
362 2.45.2
363