File Index
Files and directories
Sign in
FILE

pcie-sophgo.c

File preview with syntax highlighting.

linux-6.19.14/drivers/pci/controller/dwc/pcie-sophgo.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Sophgo DesignWare based PCIe host controller driver
  4 */
  5
  6#include <linux/bits.h>
  7#include <linux/clk.h>
  8#include <linux/irqchip/chained_irq.h>
  9#include <linux/irqdomain.h>
 10#include <linux/module.h>
 11#include <linux/property.h>
 12#include <linux/platform_device.h>
 13
 14#include "pcie-designware.h"
 15
 16#define to_sophgo_pcie(x)		dev_get_drvdata((x)->dev)
 17
 18#define PCIE_INT_SIGNAL			0xc48
 19#define PCIE_INT_EN			0xca0
 20
 21#define PCIE_INT_SIGNAL_INTX		GENMASK(8, 5)
 22
 23#define PCIE_INT_EN_INTX		GENMASK(4, 1)
 24#define PCIE_INT_EN_INT_MSI		BIT(5)
 25
 26struct sophgo_pcie {
 27	struct dw_pcie		pci;
 28	void __iomem		*app_base;
 29	struct clk_bulk_data	*clks;
 30	unsigned int		clk_cnt;
 31	struct irq_domain	*irq_domain;
 32};
 33
 34static int sophgo_pcie_readl_app(struct sophgo_pcie *sophgo, u32 reg)
 35{
 36	return readl_relaxed(sophgo->app_base + reg);
 37}
 38
 39static void sophgo_pcie_writel_app(struct sophgo_pcie *sophgo, u32 val, u32 reg)
 40{
 41	writel_relaxed(val, sophgo->app_base + reg);
 42}
 43
 44static void sophgo_pcie_intx_handler(struct irq_desc *desc)
 45{
 46	struct dw_pcie_rp *pp = irq_desc_get_handler_data(desc);
 47	struct irq_chip *chip = irq_desc_get_chip(desc);
 48	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
 49	struct sophgo_pcie *sophgo = to_sophgo_pcie(pci);
 50	unsigned long hwirq, reg;
 51
 52	chained_irq_enter(chip, desc);
 53
 54	reg = sophgo_pcie_readl_app(sophgo, PCIE_INT_SIGNAL);
 55	reg = FIELD_GET(PCIE_INT_SIGNAL_INTX, reg);
 56
 57	for_each_set_bit(hwirq, &reg, PCI_NUM_INTX)
 58		generic_handle_domain_irq(sophgo->irq_domain, hwirq);
 59
 60	chained_irq_exit(chip, desc);
 61}
 62
 63static void sophgo_intx_irq_mask(struct irq_data *d)
 64{
 65	struct dw_pcie_rp *pp = irq_data_get_irq_chip_data(d);
 66	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
 67	struct sophgo_pcie *sophgo = to_sophgo_pcie(pci);
 68	unsigned long flags;
 69	u32 val;
 70
 71	raw_spin_lock_irqsave(&pp->lock, flags);
 72
 73	val = sophgo_pcie_readl_app(sophgo, PCIE_INT_EN);
 74	val &= ~FIELD_PREP(PCIE_INT_EN_INTX, BIT(d->hwirq));
 75	sophgo_pcie_writel_app(sophgo, val, PCIE_INT_EN);
 76
 77	raw_spin_unlock_irqrestore(&pp->lock, flags);
 78};
 79
 80static void sophgo_intx_irq_unmask(struct irq_data *d)
 81{
 82	struct dw_pcie_rp *pp = irq_data_get_irq_chip_data(d);
 83	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
 84	struct sophgo_pcie *sophgo = to_sophgo_pcie(pci);
 85	unsigned long flags;
 86	u32 val;
 87
 88	raw_spin_lock_irqsave(&pp->lock, flags);
 89
 90	val = sophgo_pcie_readl_app(sophgo, PCIE_INT_EN);
 91	val |= FIELD_PREP(PCIE_INT_EN_INTX, BIT(d->hwirq));
 92	sophgo_pcie_writel_app(sophgo, val, PCIE_INT_EN);
 93
 94	raw_spin_unlock_irqrestore(&pp->lock, flags);
 95};
 96
 97static struct irq_chip sophgo_intx_irq_chip = {
 98	.name			= "INTx",
 99	.irq_mask		= sophgo_intx_irq_mask,
100	.irq_unmask		= sophgo_intx_irq_unmask,
101};
102
103static int sophgo_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
104				irq_hw_number_t hwirq)
105{
106	irq_set_chip_and_handler(irq, &sophgo_intx_irq_chip, handle_level_irq);
107	irq_set_chip_data(irq, domain->host_data);
108
109	return 0;
110}
111
112static const struct irq_domain_ops intx_domain_ops = {
113	.map = sophgo_pcie_intx_map,
114};
115
116static int sophgo_pcie_init_irq_domain(struct dw_pcie_rp *pp)
117{
118	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
119	struct sophgo_pcie *sophgo = to_sophgo_pcie(pci);
120	struct device *dev = sophgo->pci.dev;
121	struct fwnode_handle *intc;
122	int irq;
123
124	intc = device_get_named_child_node(dev, "interrupt-controller");
125	if (!intc) {
126		dev_err(dev, "missing child interrupt-controller node\n");
127		return -ENODEV;
128	}
129
130	irq = fwnode_irq_get(intc, 0);
131	if (irq < 0) {
132		dev_err(dev, "failed to get INTx irq number\n");
133		fwnode_handle_put(intc);
134		return irq;
135	}
136
137	sophgo->irq_domain = irq_domain_create_linear(intc, PCI_NUM_INTX,
138						      &intx_domain_ops, pp);
139	fwnode_handle_put(intc);
140	if (!sophgo->irq_domain) {
141		dev_err(dev, "failed to get a INTx irq domain\n");
142		return -EINVAL;
143	}
144
145	return irq;
146}
147
148static void sophgo_pcie_msi_enable(struct dw_pcie_rp *pp)
149{
150	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
151	struct sophgo_pcie *sophgo = to_sophgo_pcie(pci);
152	unsigned long flags;
153	u32 val;
154
155	raw_spin_lock_irqsave(&pp->lock, flags);
156
157	val = sophgo_pcie_readl_app(sophgo, PCIE_INT_EN);
158	val |= PCIE_INT_EN_INT_MSI;
159	sophgo_pcie_writel_app(sophgo, val, PCIE_INT_EN);
160
161	raw_spin_unlock_irqrestore(&pp->lock, flags);
162}
163
164static void sophgo_pcie_disable_l0s_l1(struct dw_pcie_rp *pp)
165{
166	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
167	u32 offset, val;
168
169	offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
170
171	dw_pcie_dbi_ro_wr_en(pci);
172
173	val = dw_pcie_readl_dbi(pci, PCI_EXP_LNKCAP + offset);
174	val &= ~(PCI_EXP_LNKCAP_ASPM_L0S | PCI_EXP_LNKCAP_ASPM_L1);
175	dw_pcie_writel_dbi(pci, PCI_EXP_LNKCAP + offset, val);
176
177	dw_pcie_dbi_ro_wr_dis(pci);
178}
179
180static int sophgo_pcie_host_init(struct dw_pcie_rp *pp)
181{
182	int irq;
183
184	irq = sophgo_pcie_init_irq_domain(pp);
185	if (irq < 0)
186		return irq;
187
188	irq_set_chained_handler_and_data(irq, sophgo_pcie_intx_handler, pp);
189
190	sophgo_pcie_disable_l0s_l1(pp);
191
192	sophgo_pcie_msi_enable(pp);
193
194	return 0;
195}
196
197static const struct dw_pcie_host_ops sophgo_pcie_host_ops = {
198	.init = sophgo_pcie_host_init,
199};
200
201static int sophgo_pcie_clk_init(struct sophgo_pcie *sophgo)
202{
203	struct device *dev = sophgo->pci.dev;
204	int ret;
205
206	ret = devm_clk_bulk_get_all_enabled(dev, &sophgo->clks);
207	if (ret < 0)
208		return dev_err_probe(dev, ret, "failed to get clocks\n");
209
210	sophgo->clk_cnt = ret;
211
212	return 0;
213}
214
215static int sophgo_pcie_resource_get(struct platform_device *pdev,
216				    struct sophgo_pcie *sophgo)
217{
218	sophgo->app_base = devm_platform_ioremap_resource_byname(pdev, "app");
219	if (IS_ERR(sophgo->app_base))
220		return dev_err_probe(&pdev->dev, PTR_ERR(sophgo->app_base),
221				     "failed to map app registers\n");
222
223	return 0;
224}
225
226static int sophgo_pcie_configure_rc(struct sophgo_pcie *sophgo)
227{
228	struct dw_pcie_rp *pp;
229
230	pp = &sophgo->pci.pp;
231	pp->ops = &sophgo_pcie_host_ops;
232
233	return dw_pcie_host_init(pp);
234}
235
236static int sophgo_pcie_probe(struct platform_device *pdev)
237{
238	struct device *dev = &pdev->dev;
239	struct sophgo_pcie *sophgo;
240	int ret;
241
242	sophgo = devm_kzalloc(dev, sizeof(*sophgo), GFP_KERNEL);
243	if (!sophgo)
244		return -ENOMEM;
245
246	platform_set_drvdata(pdev, sophgo);
247
248	sophgo->pci.dev = dev;
249
250	ret = sophgo_pcie_resource_get(pdev, sophgo);
251	if (ret)
252		return ret;
253
254	ret = sophgo_pcie_clk_init(sophgo);
255	if (ret)
256		return ret;
257
258	return sophgo_pcie_configure_rc(sophgo);
259}
260
261static const struct of_device_id sophgo_pcie_of_match[] = {
262	{ .compatible = "sophgo,sg2044-pcie" },
263	{ }
264};
265MODULE_DEVICE_TABLE(of, sophgo_pcie_of_match);
266
267static struct platform_driver sophgo_pcie_driver = {
268	.driver = {
269		.name = "sophgo-pcie",
270		.of_match_table = sophgo_pcie_of_match,
271		.suppress_bind_attrs = true,
272	},
273	.probe = sophgo_pcie_probe,
274};
275builtin_platform_driver(sophgo_pcie_driver);
~/ Read-only file preview.