2 * PCIe host controller driver for HiSilicon SoCs
4 * Copyright (C) 2015 HiSilicon Co., Ltd. http://www.hisilicon.com
6 * Authors: Zhou Wang <wangzhou1@hisilicon.com>
7 * Dacai Zhu <zhudacai@hisilicon.com>
8 * Gabriele Paoloni <gabriele.paoloni@huawei.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
14 #include <linux/interrupt.h>
15 #include <linux/init.h>
16 #include <linux/mfd/syscon.h>
17 #include <linux/of_address.h>
18 #include <linux/of_pci.h>
19 #include <linux/platform_device.h>
20 #include <linux/of_device.h>
21 #include <linux/pci.h>
22 #include <linux/pci-acpi.h>
23 #include <linux/pci-ecam.h>
24 #include <linux/regmap.h>
27 #if defined(CONFIG_PCI_HISI) || (defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS))
29 static int hisi_pcie_rd_conf(struct pci_bus
*bus
, u32 devfn
, int where
,
32 struct pci_config_window
*cfg
= bus
->sysdata
;
33 int dev
= PCI_SLOT(devfn
);
35 if (bus
->number
== cfg
->busr
.start
) {
36 /* access only one slot on each root port */
38 return PCIBIOS_DEVICE_NOT_FOUND
;
40 return pci_generic_config_read32(bus
, devfn
, where
,
44 return pci_generic_config_read(bus
, devfn
, where
, size
, val
);
47 static int hisi_pcie_wr_conf(struct pci_bus
*bus
, u32 devfn
,
48 int where
, int size
, u32 val
)
50 struct pci_config_window
*cfg
= bus
->sysdata
;
51 int dev
= PCI_SLOT(devfn
);
53 if (bus
->number
== cfg
->busr
.start
) {
54 /* access only one slot on each root port */
56 return PCIBIOS_DEVICE_NOT_FOUND
;
58 return pci_generic_config_write32(bus
, devfn
, where
,
62 return pci_generic_config_write(bus
, devfn
, where
, size
, val
);
65 static void __iomem
*hisi_pcie_map_bus(struct pci_bus
*bus
, unsigned int devfn
,
68 struct pci_config_window
*cfg
= bus
->sysdata
;
69 void __iomem
*reg_base
= cfg
->priv
;
71 if (bus
->number
== cfg
->busr
.start
)
72 return reg_base
+ where
;
74 return pci_ecam_map_bus(bus
, devfn
, where
);
77 #if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
79 static int hisi_pcie_init(struct pci_config_window
*cfg
)
81 struct device
*dev
= cfg
->parent
;
82 struct acpi_device
*adev
= to_acpi_device(dev
);
83 struct acpi_pci_root
*root
= acpi_driver_data(adev
);
85 void __iomem
*reg_base
;
89 * Retrieve RC base and size from a HISI0081 device with _UID
90 * matching our segment.
92 res
= devm_kzalloc(dev
, sizeof(*res
), GFP_KERNEL
);
96 ret
= acpi_get_rc_resources(dev
, "HISI0081", root
->segment
, res
);
98 dev_err(dev
, "can't get rc base address\n");
102 reg_base
= devm_ioremap(dev
, res
->start
, resource_size(res
));
106 cfg
->priv
= reg_base
;
110 struct pci_ecam_ops hisi_pcie_ops
= {
112 .init
= hisi_pcie_init
,
114 .map_bus
= hisi_pcie_map_bus
,
115 .read
= hisi_pcie_rd_conf
,
116 .write
= hisi_pcie_wr_conf
,
122 #ifdef CONFIG_PCI_HISI
124 #include "pcie-designware.h"
126 #define PCIE_SUBCTRL_SYS_STATE4_REG 0x6818
127 #define PCIE_HIP06_CTRL_OFF 0x1000
128 #define PCIE_SYS_STATE4 (PCIE_HIP06_CTRL_OFF + 0x31c)
129 #define PCIE_LTSSM_LINKUP_STATE 0x11
130 #define PCIE_LTSSM_STATE_MASK 0x3F
132 #define to_hisi_pcie(x) dev_get_drvdata((x)->dev)
136 struct pcie_soc_ops
{
137 int (*hisi_pcie_link_up
)(struct hisi_pcie
*hisi_pcie
);
142 struct regmap
*subctrl
;
144 const struct pcie_soc_ops
*soc_ops
;
147 /* HipXX PCIe host only supports 32-bit config access */
148 static int hisi_pcie_cfg_read(struct pcie_port
*pp
, int where
, int size
,
153 void *walker
= ®_val
;
154 struct dw_pcie
*pci
= to_dw_pcie_from_pp(pp
);
156 walker
+= (where
& 0x3);
158 reg_val
= dw_pcie_readl_dbi(pci
, reg
);
161 *val
= *(u8 __force
*) walker
;
163 *val
= *(u16 __force
*) walker
;
167 return PCIBIOS_BAD_REGISTER_NUMBER
;
169 return PCIBIOS_SUCCESSFUL
;
172 /* HipXX PCIe host only supports 32-bit config access */
173 static int hisi_pcie_cfg_write(struct pcie_port
*pp
, int where
, int size
,
178 void *walker
= ®_val
;
179 struct dw_pcie
*pci
= to_dw_pcie_from_pp(pp
);
181 walker
+= (where
& 0x3);
184 dw_pcie_writel_dbi(pci
, reg
, val
);
185 else if (size
== 2) {
186 reg_val
= dw_pcie_readl_dbi(pci
, reg
);
187 *(u16 __force
*) walker
= val
;
188 dw_pcie_writel_dbi(pci
, reg
, reg_val
);
189 } else if (size
== 1) {
190 reg_val
= dw_pcie_readl_dbi(pci
, reg
);
191 *(u8 __force
*) walker
= val
;
192 dw_pcie_writel_dbi(pci
, reg
, reg_val
);
194 return PCIBIOS_BAD_REGISTER_NUMBER
;
196 return PCIBIOS_SUCCESSFUL
;
199 static int hisi_pcie_link_up_hip05(struct hisi_pcie
*hisi_pcie
)
203 regmap_read(hisi_pcie
->subctrl
, PCIE_SUBCTRL_SYS_STATE4_REG
+
204 0x100 * hisi_pcie
->port_id
, &val
);
206 return ((val
& PCIE_LTSSM_STATE_MASK
) == PCIE_LTSSM_LINKUP_STATE
);
209 static int hisi_pcie_link_up_hip06(struct hisi_pcie
*hisi_pcie
)
211 struct dw_pcie
*pci
= hisi_pcie
->pci
;
214 val
= dw_pcie_readl_dbi(pci
, PCIE_SYS_STATE4
);
216 return ((val
& PCIE_LTSSM_STATE_MASK
) == PCIE_LTSSM_LINKUP_STATE
);
219 static int hisi_pcie_link_up(struct dw_pcie
*pci
)
221 struct hisi_pcie
*hisi_pcie
= to_hisi_pcie(pci
);
223 return hisi_pcie
->soc_ops
->hisi_pcie_link_up(hisi_pcie
);
226 static struct dw_pcie_host_ops hisi_pcie_host_ops
= {
227 .rd_own_conf
= hisi_pcie_cfg_read
,
228 .wr_own_conf
= hisi_pcie_cfg_write
,
231 static int hisi_add_pcie_port(struct hisi_pcie
*hisi_pcie
,
232 struct platform_device
*pdev
)
234 struct dw_pcie
*pci
= hisi_pcie
->pci
;
235 struct pcie_port
*pp
= &pci
->pp
;
236 struct device
*dev
= &pdev
->dev
;
240 if (of_property_read_u32(dev
->of_node
, "port-id", &port_id
)) {
241 dev_err(dev
, "failed to read port-id\n");
245 dev_err(dev
, "Invalid port-id: %d\n", port_id
);
248 hisi_pcie
->port_id
= port_id
;
250 pp
->ops
= &hisi_pcie_host_ops
;
252 ret
= dw_pcie_host_init(pp
);
254 dev_err(dev
, "failed to initialize host\n");
261 static const struct dw_pcie_ops dw_pcie_ops
= {
262 .link_up
= hisi_pcie_link_up
,
265 static int hisi_pcie_probe(struct platform_device
*pdev
)
267 struct device
*dev
= &pdev
->dev
;
269 struct hisi_pcie
*hisi_pcie
;
270 struct resource
*reg
;
271 struct device_driver
*driver
;
274 hisi_pcie
= devm_kzalloc(dev
, sizeof(*hisi_pcie
), GFP_KERNEL
);
278 pci
= devm_kzalloc(dev
, sizeof(*pci
), GFP_KERNEL
);
283 pci
->ops
= &dw_pcie_ops
;
285 driver
= dev
->driver
;
287 hisi_pcie
->pci
= pci
;
289 hisi_pcie
->soc_ops
= of_device_get_match_data(dev
);
292 syscon_regmap_lookup_by_compatible("hisilicon,pcie-sas-subctrl");
293 if (IS_ERR(hisi_pcie
->subctrl
)) {
294 dev_err(dev
, "cannot get subctrl base\n");
295 return PTR_ERR(hisi_pcie
->subctrl
);
298 reg
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
, "rc_dbi");
299 pci
->dbi_base
= devm_ioremap_resource(dev
, reg
);
300 if (IS_ERR(pci
->dbi_base
))
301 return PTR_ERR(pci
->dbi_base
);
303 platform_set_drvdata(pdev
, hisi_pcie
);
305 ret
= hisi_add_pcie_port(hisi_pcie
, pdev
);
312 static struct pcie_soc_ops hip05_ops
= {
313 &hisi_pcie_link_up_hip05
316 static struct pcie_soc_ops hip06_ops
= {
317 &hisi_pcie_link_up_hip06
320 static const struct of_device_id hisi_pcie_of_match
[] = {
322 .compatible
= "hisilicon,hip05-pcie",
323 .data
= (void *) &hip05_ops
,
326 .compatible
= "hisilicon,hip06-pcie",
327 .data
= (void *) &hip06_ops
,
332 static struct platform_driver hisi_pcie_driver
= {
333 .probe
= hisi_pcie_probe
,
336 .of_match_table
= hisi_pcie_of_match
,
339 builtin_platform_driver(hisi_pcie_driver
);
341 static int hisi_pcie_almost_ecam_probe(struct platform_device
*pdev
)
343 struct device
*dev
= &pdev
->dev
;
344 struct pci_ecam_ops
*ops
;
346 ops
= (struct pci_ecam_ops
*)of_device_get_match_data(dev
);
347 return pci_host_common_probe(pdev
, ops
);
350 static int hisi_pcie_platform_init(struct pci_config_window
*cfg
)
352 struct device
*dev
= cfg
->parent
;
353 struct platform_device
*pdev
= to_platform_device(dev
);
354 struct resource
*res
;
355 void __iomem
*reg_base
;
357 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 1);
359 dev_err(dev
, "missing \"reg[1]\"property\n");
363 reg_base
= devm_ioremap(dev
, res
->start
, resource_size(res
));
367 cfg
->priv
= reg_base
;
371 struct pci_ecam_ops hisi_pcie_platform_ops
= {
373 .init
= hisi_pcie_platform_init
,
375 .map_bus
= hisi_pcie_map_bus
,
376 .read
= hisi_pcie_rd_conf
,
377 .write
= hisi_pcie_wr_conf
,
381 static const struct of_device_id hisi_pcie_almost_ecam_of_match
[] = {
383 .compatible
= "hisilicon,pcie-almost-ecam",
384 .data
= (void *) &hisi_pcie_platform_ops
,
389 static struct platform_driver hisi_pcie_almost_ecam_driver
= {
390 .probe
= hisi_pcie_almost_ecam_probe
,
392 .name
= "hisi-pcie-almost-ecam",
393 .of_match_table
= hisi_pcie_almost_ecam_of_match
,
396 builtin_platform_driver(hisi_pcie_almost_ecam_driver
);