1 // SPDX-License-Identifier: GPL-2.0
3 * PCIe host controller driver for Freescale Layerscape SoCs
5 * Copyright (C) 2014 Freescale Semiconductor.
7 * Author: Minghuan Lian <Minghuan.Lian@freescale.com>
10 #include <linux/kernel.h>
11 #include <linux/interrupt.h>
12 #include <linux/init.h>
13 #include <linux/of_pci.h>
14 #include <linux/of_platform.h>
15 #include <linux/of_irq.h>
16 #include <linux/of_address.h>
17 #include <linux/pci.h>
18 #include <linux/platform_device.h>
19 #include <linux/resource.h>
20 #include <linux/mfd/syscon.h>
21 #include <linux/regmap.h>
23 #include "pcie-designware.h"
25 /* PEX1/2 Misc Ports Status Register */
26 #define SCFG_PEXMSCPORTSR(pex_idx) (0x94 + (pex_idx) * 4)
27 #define LTSSM_STATE_SHIFT 20
28 #define LTSSM_STATE_MASK 0x3f
29 #define LTSSM_PCIE_L0 0x11 /* L0 state */
31 /* PEX Internal Configuration Registers */
32 #define PCIE_STRFMR1 0x71c /* Symbol Timer & Filter Mask Register1 */
33 #define PCIE_ABSERR 0x8d0 /* Bridge Slave Error Response Register */
34 #define PCIE_ABSERR_SETTING 0x9401 /* Forward error of non-posted request */
36 #define PCIE_IATU_NUM 6
38 struct ls_pcie_drvdata
{
42 const struct dw_pcie_host_ops
*ops
;
43 const struct dw_pcie_ops
*dw_pcie_ops
;
50 const struct ls_pcie_drvdata
*drvdata
;
54 #define to_ls_pcie(x) dev_get_drvdata((x)->dev)
56 static bool ls_pcie_is_bridge(struct ls_pcie
*pcie
)
58 struct dw_pcie
*pci
= pcie
->pci
;
61 header_type
= ioread8(pci
->dbi_base
+ PCI_HEADER_TYPE
);
64 return header_type
== PCI_HEADER_TYPE_BRIDGE
;
67 /* Clear multi-function bit */
68 static void ls_pcie_clear_multifunction(struct ls_pcie
*pcie
)
70 struct dw_pcie
*pci
= pcie
->pci
;
72 iowrite8(PCI_HEADER_TYPE_BRIDGE
, pci
->dbi_base
+ PCI_HEADER_TYPE
);
75 /* Drop MSG TLP except for Vendor MSG */
76 static void ls_pcie_drop_msg_tlp(struct ls_pcie
*pcie
)
79 struct dw_pcie
*pci
= pcie
->pci
;
81 val
= ioread32(pci
->dbi_base
+ PCIE_STRFMR1
);
83 iowrite32(val
, pci
->dbi_base
+ PCIE_STRFMR1
);
86 static int ls1021_pcie_link_up(struct dw_pcie
*pci
)
89 struct ls_pcie
*pcie
= to_ls_pcie(pci
);
94 regmap_read(pcie
->scfg
, SCFG_PEXMSCPORTSR(pcie
->index
), &state
);
95 state
= (state
>> LTSSM_STATE_SHIFT
) & LTSSM_STATE_MASK
;
97 if (state
< LTSSM_PCIE_L0
)
103 static int ls_pcie_link_up(struct dw_pcie
*pci
)
105 struct ls_pcie
*pcie
= to_ls_pcie(pci
);
108 state
= (ioread32(pcie
->lut
+ pcie
->drvdata
->lut_dbg
) >>
109 pcie
->drvdata
->ltssm_shift
) &
112 if (state
< LTSSM_PCIE_L0
)
118 /* Forward error response of outbound non-posted requests */
119 static void ls_pcie_fix_error_response(struct ls_pcie
*pcie
)
121 struct dw_pcie
*pci
= pcie
->pci
;
123 iowrite32(PCIE_ABSERR_SETTING
, pci
->dbi_base
+ PCIE_ABSERR
);
126 static int ls_pcie_host_init(struct pcie_port
*pp
)
128 struct dw_pcie
*pci
= to_dw_pcie_from_pp(pp
);
129 struct ls_pcie
*pcie
= to_ls_pcie(pci
);
131 ls_pcie_fix_error_response(pcie
);
133 dw_pcie_dbi_ro_wr_en(pci
);
134 ls_pcie_clear_multifunction(pcie
);
135 dw_pcie_dbi_ro_wr_dis(pci
);
137 ls_pcie_drop_msg_tlp(pcie
);
142 static int ls1021_pcie_host_init(struct pcie_port
*pp
)
144 struct dw_pcie
*pci
= to_dw_pcie_from_pp(pp
);
145 struct ls_pcie
*pcie
= to_ls_pcie(pci
);
146 struct device
*dev
= pci
->dev
;
150 pcie
->scfg
= syscon_regmap_lookup_by_phandle(dev
->of_node
,
152 if (IS_ERR(pcie
->scfg
)) {
153 ret
= PTR_ERR(pcie
->scfg
);
154 dev_err(dev
, "No syscfg phandle specified\n");
159 if (of_property_read_u32_array(dev
->of_node
,
160 "fsl,pcie-scfg", index
, 2)) {
164 pcie
->index
= index
[1];
166 return ls_pcie_host_init(pp
);
169 static const struct dw_pcie_host_ops ls1021_pcie_host_ops
= {
170 .host_init
= ls1021_pcie_host_init
,
173 static const struct dw_pcie_host_ops ls_pcie_host_ops
= {
174 .host_init
= ls_pcie_host_init
,
177 static const struct dw_pcie_ops dw_ls1021_pcie_ops
= {
178 .link_up
= ls1021_pcie_link_up
,
181 static const struct dw_pcie_ops dw_ls_pcie_ops
= {
182 .link_up
= ls_pcie_link_up
,
185 static const struct ls_pcie_drvdata ls1021_drvdata
= {
186 .ops
= &ls1021_pcie_host_ops
,
187 .dw_pcie_ops
= &dw_ls1021_pcie_ops
,
190 static const struct ls_pcie_drvdata ls1043_drvdata
= {
191 .lut_offset
= 0x10000,
194 .ops
= &ls_pcie_host_ops
,
195 .dw_pcie_ops
= &dw_ls_pcie_ops
,
198 static const struct ls_pcie_drvdata ls1046_drvdata
= {
199 .lut_offset
= 0x80000,
202 .ops
= &ls_pcie_host_ops
,
203 .dw_pcie_ops
= &dw_ls_pcie_ops
,
206 static const struct ls_pcie_drvdata ls2080_drvdata
= {
207 .lut_offset
= 0x80000,
210 .ops
= &ls_pcie_host_ops
,
211 .dw_pcie_ops
= &dw_ls_pcie_ops
,
214 static const struct ls_pcie_drvdata ls2088_drvdata
= {
215 .lut_offset
= 0x80000,
218 .ops
= &ls_pcie_host_ops
,
219 .dw_pcie_ops
= &dw_ls_pcie_ops
,
222 static const struct of_device_id ls_pcie_of_match
[] = {
223 { .compatible
= "fsl,ls1012a-pcie", .data
= &ls1046_drvdata
},
224 { .compatible
= "fsl,ls1021a-pcie", .data
= &ls1021_drvdata
},
225 { .compatible
= "fsl,ls1028a-pcie", .data
= &ls2088_drvdata
},
226 { .compatible
= "fsl,ls1043a-pcie", .data
= &ls1043_drvdata
},
227 { .compatible
= "fsl,ls1046a-pcie", .data
= &ls1046_drvdata
},
228 { .compatible
= "fsl,ls2080a-pcie", .data
= &ls2080_drvdata
},
229 { .compatible
= "fsl,ls2085a-pcie", .data
= &ls2080_drvdata
},
230 { .compatible
= "fsl,ls2088a-pcie", .data
= &ls2088_drvdata
},
231 { .compatible
= "fsl,ls1088a-pcie", .data
= &ls2088_drvdata
},
235 static int __init
ls_pcie_probe(struct platform_device
*pdev
)
237 struct device
*dev
= &pdev
->dev
;
239 struct ls_pcie
*pcie
;
240 struct resource
*dbi_base
;
242 pcie
= devm_kzalloc(dev
, sizeof(*pcie
), GFP_KERNEL
);
246 pci
= devm_kzalloc(dev
, sizeof(*pci
), GFP_KERNEL
);
250 pcie
->drvdata
= of_device_get_match_data(dev
);
253 pci
->ops
= pcie
->drvdata
->dw_pcie_ops
;
254 pci
->pp
.ops
= pcie
->drvdata
->ops
;
258 dbi_base
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
, "regs");
259 pci
->dbi_base
= devm_pci_remap_cfg_resource(dev
, dbi_base
);
260 if (IS_ERR(pci
->dbi_base
))
261 return PTR_ERR(pci
->dbi_base
);
263 pcie
->lut
= pci
->dbi_base
+ pcie
->drvdata
->lut_offset
;
265 if (!ls_pcie_is_bridge(pcie
))
268 platform_set_drvdata(pdev
, pcie
);
270 return dw_pcie_host_init(&pci
->pp
);
273 static struct platform_driver ls_pcie_driver
= {
275 .name
= "layerscape-pcie",
276 .of_match_table
= ls_pcie_of_match
,
277 .suppress_bind_attrs
= true,
280 builtin_platform_driver_probe(ls_pcie_driver
, ls_pcie_probe
);