File Index
Files and directories
Sign in
FILE

ppe.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/qualcomm/ppe/ppe.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
  4 */
  5
  6/* PPE platform device probe, DTSI parser and PPE clock initializations. */
  7
  8#include <linux/clk.h>
  9#include <linux/interconnect.h>
 10#include <linux/kernel.h>
 11#include <linux/module.h>
 12#include <linux/of.h>
 13#include <linux/platform_device.h>
 14#include <linux/regmap.h>
 15#include <linux/reset.h>
 16
 17#include "ppe.h"
 18#include "ppe_config.h"
 19#include "ppe_debugfs.h"
 20
 21#define PPE_PORT_MAX		8
 22#define PPE_CLK_RATE		353000000
 23
 24/* ICC clocks for enabling PPE device. The avg_bw and peak_bw with value 0
 25 * will be updated by the clock rate of PPE.
 26 */
 27static const struct icc_bulk_data ppe_icc_data[] = {
 28	{
 29		.name = "ppe",
 30		.avg_bw = 0,
 31		.peak_bw = 0,
 32	},
 33	{
 34		.name = "ppe_cfg",
 35		.avg_bw = 0,
 36		.peak_bw = 0,
 37	},
 38	{
 39		.name = "qos_gen",
 40		.avg_bw = 6000,
 41		.peak_bw = 6000,
 42	},
 43	{
 44		.name = "timeout_ref",
 45		.avg_bw = 6000,
 46		.peak_bw = 6000,
 47	},
 48	{
 49		.name = "nssnoc_memnoc",
 50		.avg_bw = 533333,
 51		.peak_bw = 533333,
 52	},
 53	{
 54		.name = "memnoc_nssnoc",
 55		.avg_bw = 533333,
 56		.peak_bw = 533333,
 57	},
 58	{
 59		.name = "memnoc_nssnoc_1",
 60		.avg_bw = 533333,
 61		.peak_bw = 533333,
 62	},
 63};
 64
 65static const struct regmap_range ppe_readable_ranges[] = {
 66	regmap_reg_range(0x0, 0x1ff),		/* Global */
 67	regmap_reg_range(0x400, 0x5ff),		/* LPI CSR */
 68	regmap_reg_range(0x1000, 0x11ff),	/* GMAC0 */
 69	regmap_reg_range(0x1200, 0x13ff),	/* GMAC1 */
 70	regmap_reg_range(0x1400, 0x15ff),	/* GMAC2 */
 71	regmap_reg_range(0x1600, 0x17ff),	/* GMAC3 */
 72	regmap_reg_range(0x1800, 0x19ff),	/* GMAC4 */
 73	regmap_reg_range(0x1a00, 0x1bff),	/* GMAC5 */
 74	regmap_reg_range(0xb000, 0xefff),	/* PRX CSR */
 75	regmap_reg_range(0xf000, 0x1efff),	/* IPE */
 76	regmap_reg_range(0x20000, 0x5ffff),	/* PTX CSR */
 77	regmap_reg_range(0x60000, 0x9ffff),	/* IPE L2 CSR */
 78	regmap_reg_range(0xb0000, 0xeffff),	/* IPO CSR */
 79	regmap_reg_range(0x100000, 0x17ffff),	/* IPE PC */
 80	regmap_reg_range(0x180000, 0x1bffff),	/* PRE IPO CSR */
 81	regmap_reg_range(0x1d0000, 0x1dffff),	/* Tunnel parser */
 82	regmap_reg_range(0x1e0000, 0x1effff),	/* Ingress parse */
 83	regmap_reg_range(0x200000, 0x2fffff),	/* IPE L3 */
 84	regmap_reg_range(0x300000, 0x3fffff),	/* IPE tunnel */
 85	regmap_reg_range(0x400000, 0x4fffff),	/* Scheduler */
 86	regmap_reg_range(0x500000, 0x503fff),	/* XGMAC0 */
 87	regmap_reg_range(0x504000, 0x507fff),	/* XGMAC1 */
 88	regmap_reg_range(0x508000, 0x50bfff),	/* XGMAC2 */
 89	regmap_reg_range(0x50c000, 0x50ffff),	/* XGMAC3 */
 90	regmap_reg_range(0x510000, 0x513fff),	/* XGMAC4 */
 91	regmap_reg_range(0x514000, 0x517fff),	/* XGMAC5 */
 92	regmap_reg_range(0x600000, 0x6fffff),	/* BM */
 93	regmap_reg_range(0x800000, 0x9fffff),	/* QM */
 94	regmap_reg_range(0xb00000, 0xbef800),	/* EDMA */
 95};
 96
 97static const struct regmap_access_table ppe_reg_table = {
 98	.yes_ranges = ppe_readable_ranges,
 99	.n_yes_ranges = ARRAY_SIZE(ppe_readable_ranges),
100};
101
102static const struct regmap_config regmap_config_ipq9574 = {
103	.reg_bits = 32,
104	.reg_stride = 4,
105	.val_bits = 32,
106	.rd_table = &ppe_reg_table,
107	.wr_table = &ppe_reg_table,
108	.max_register = 0xbef800,
109	.fast_io = true,
110};
111
112static int ppe_clock_init_and_reset(struct ppe_device *ppe_dev)
113{
114	unsigned long ppe_rate = ppe_dev->clk_rate;
115	struct device *dev = ppe_dev->dev;
116	struct reset_control *rstc;
117	struct clk_bulk_data *clks;
118	struct clk *clk;
119	int ret, i;
120
121	for (i = 0; i < ppe_dev->num_icc_paths; i++) {
122		ppe_dev->icc_paths[i].name = ppe_icc_data[i].name;
123		ppe_dev->icc_paths[i].avg_bw = ppe_icc_data[i].avg_bw ? :
124					       Bps_to_icc(ppe_rate);
125
126		/* PPE does not have an explicit peak bandwidth requirement,
127		 * so set the peak bandwidth to be equal to the average
128		 * bandwidth.
129		 */
130		ppe_dev->icc_paths[i].peak_bw = ppe_icc_data[i].peak_bw ? :
131						Bps_to_icc(ppe_rate);
132	}
133
134	ret = devm_of_icc_bulk_get(dev, ppe_dev->num_icc_paths,
135				   ppe_dev->icc_paths);
136	if (ret)
137		return ret;
138
139	ret = icc_bulk_set_bw(ppe_dev->num_icc_paths, ppe_dev->icc_paths);
140	if (ret)
141		return ret;
142
143	/* The PPE clocks have a common parent clock. Setting the clock
144	 * rate of "ppe" ensures the clock rate of all PPE clocks is
145	 * configured to the same rate.
146	 */
147	clk = devm_clk_get(dev, "ppe");
148	if (IS_ERR(clk))
149		return PTR_ERR(clk);
150
151	ret = clk_set_rate(clk, ppe_rate);
152	if (ret)
153		return ret;
154
155	ret = devm_clk_bulk_get_all_enabled(dev, &clks);
156	if (ret < 0)
157		return ret;
158
159	/* Reset the PPE. */
160	rstc = devm_reset_control_get_exclusive(dev, NULL);
161	if (IS_ERR(rstc))
162		return PTR_ERR(rstc);
163
164	ret = reset_control_assert(rstc);
165	if (ret)
166		return ret;
167
168	/* The delay 10 ms of assert is necessary for resetting PPE. */
169	usleep_range(10000, 11000);
170
171	return reset_control_deassert(rstc);
172}
173
174static int qcom_ppe_probe(struct platform_device *pdev)
175{
176	struct device *dev = &pdev->dev;
177	struct ppe_device *ppe_dev;
178	void __iomem *base;
179	int ret, num_icc;
180
181	num_icc = ARRAY_SIZE(ppe_icc_data);
182	ppe_dev = devm_kzalloc(dev, struct_size(ppe_dev, icc_paths, num_icc),
183			       GFP_KERNEL);
184	if (!ppe_dev)
185		return -ENOMEM;
186
187	base = devm_platform_ioremap_resource(pdev, 0);
188	if (IS_ERR(base))
189		return dev_err_probe(dev, PTR_ERR(base), "PPE ioremap failed\n");
190
191	ppe_dev->regmap = devm_regmap_init_mmio(dev, base, &regmap_config_ipq9574);
192	if (IS_ERR(ppe_dev->regmap))
193		return dev_err_probe(dev, PTR_ERR(ppe_dev->regmap),
194				     "PPE initialize regmap failed\n");
195	ppe_dev->dev = dev;
196	ppe_dev->clk_rate = PPE_CLK_RATE;
197	ppe_dev->num_ports = PPE_PORT_MAX;
198	ppe_dev->num_icc_paths = num_icc;
199
200	ret = ppe_clock_init_and_reset(ppe_dev);
201	if (ret)
202		return dev_err_probe(dev, ret, "PPE clock config failed\n");
203
204	ret = ppe_hw_config(ppe_dev);
205	if (ret)
206		return dev_err_probe(dev, ret, "PPE HW config failed\n");
207
208	ppe_debugfs_setup(ppe_dev);
209	platform_set_drvdata(pdev, ppe_dev);
210
211	return 0;
212}
213
214static void qcom_ppe_remove(struct platform_device *pdev)
215{
216	struct ppe_device *ppe_dev;
217
218	ppe_dev = platform_get_drvdata(pdev);
219	ppe_debugfs_teardown(ppe_dev);
220}
221
222static const struct of_device_id qcom_ppe_of_match[] = {
223	{ .compatible = "qcom,ipq9574-ppe" },
224	{}
225};
226MODULE_DEVICE_TABLE(of, qcom_ppe_of_match);
227
228static struct platform_driver qcom_ppe_driver = {
229	.driver = {
230		.name = "qcom_ppe",
231		.of_match_table = qcom_ppe_of_match,
232	},
233	.probe	= qcom_ppe_probe,
234	.remove = qcom_ppe_remove,
235};
236module_platform_driver(qcom_ppe_driver);
237
238MODULE_LICENSE("GPL");
239MODULE_DESCRIPTION("Qualcomm Technologies, Inc. IPQ PPE driver");
~/ Read-only file preview.