2 * PCIe host controller driver for Freescale Layerscape SoCs
4 * Copyright (C) 2014 Freescale Semiconductor.
6 * Author: Minghuan Lian <Minghuan.Lian@freescale.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
13 #include <linux/kernel.h>
14 #include <linux/delay.h>
15 #include <linux/interrupt.h>
16 #include <linux/module.h>
17 #include <linux/of_pci.h>
18 #include <linux/of_platform.h>
19 #include <linux/of_irq.h>
20 #include <linux/of_address.h>
21 #include <linux/pci.h>
22 #include <linux/platform_device.h>
23 #include <linux/resource.h>
24 #include <linux/mfd/syscon.h>
25 #include <linux/regmap.h>
27 #include "pcie-designware.h"
29 /* PEX1/2 Misc Ports Status Register */
30 #define SCFG_PEXMSCPORTSR(pex_idx) (0x94 + (pex_idx) * 4)
31 #define LTSSM_STATE_SHIFT 20
32 #define LTSSM_STATE_MASK 0x3f
33 #define LTSSM_PCIE_L0 0x11 /* L0 state */
35 /* Symbol Timer Register and Filter Mask Register 1 */
36 #define PCIE_STRFMR1 0x71c
39 struct list_head node
;
49 #define to_ls_pcie(x) container_of(x, struct ls_pcie, pp)
51 static int ls_pcie_link_up(struct pcie_port
*pp
)
54 struct ls_pcie
*pcie
= to_ls_pcie(pp
);
56 regmap_read(pcie
->scfg
, SCFG_PEXMSCPORTSR(pcie
->index
), &state
);
57 state
= (state
>> LTSSM_STATE_SHIFT
) & LTSSM_STATE_MASK
;
59 if (state
< LTSSM_PCIE_L0
)
65 static void ls_pcie_host_init(struct pcie_port
*pp
)
67 struct ls_pcie
*pcie
= to_ls_pcie(pp
);
73 while (!ls_pcie_link_up(pp
)) {
74 usleep_range(100, 1000);
77 dev_err(pp
->dev
, "phy link never came up\n");
83 * LS1021A Workaround for internal TKT228622
84 * to fix the INTx hang issue
86 val
= ioread32(pcie
->dbi
+ PCIE_STRFMR1
);
88 iowrite32(val
, pcie
->dbi
+ PCIE_STRFMR1
);
91 static struct pcie_host_ops ls_pcie_host_ops
= {
92 .link_up
= ls_pcie_link_up
,
93 .host_init
= ls_pcie_host_init
,
96 static int ls_add_pcie_port(struct ls_pcie
*pcie
)
103 pp
->dbi_base
= pcie
->dbi
;
104 pp
->root_bus_nr
= -1;
105 pp
->ops
= &ls_pcie_host_ops
;
107 ret
= dw_pcie_host_init(pp
);
109 dev_err(pp
->dev
, "failed to initialize host\n");
116 static int __init
ls_pcie_probe(struct platform_device
*pdev
)
118 struct ls_pcie
*pcie
;
119 struct resource
*dbi_base
;
123 pcie
= devm_kzalloc(&pdev
->dev
, sizeof(*pcie
), GFP_KERNEL
);
127 pcie
->dev
= &pdev
->dev
;
129 dbi_base
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
, "regs");
131 dev_err(&pdev
->dev
, "missing *regs* space\n");
135 pcie
->dbi
= devm_ioremap_resource(&pdev
->dev
, dbi_base
);
136 if (IS_ERR(pcie
->dbi
))
137 return PTR_ERR(pcie
->dbi
);
139 pcie
->scfg
= syscon_regmap_lookup_by_phandle(pdev
->dev
.of_node
,
141 if (IS_ERR(pcie
->scfg
)) {
142 dev_err(&pdev
->dev
, "No syscfg phandle specified\n");
143 return PTR_ERR(pcie
->scfg
);
146 ret
= of_property_read_u32_array(pdev
->dev
.of_node
,
147 "fsl,pcie-scfg", index
, 2);
150 pcie
->index
= index
[1];
152 ret
= ls_add_pcie_port(pcie
);
156 platform_set_drvdata(pdev
, pcie
);
161 static const struct of_device_id ls_pcie_of_match
[] = {
162 { .compatible
= "fsl,ls1021a-pcie" },
165 MODULE_DEVICE_TABLE(of
, ls_pcie_of_match
);
167 static struct platform_driver ls_pcie_driver
= {
169 .name
= "layerscape-pcie",
170 .owner
= THIS_MODULE
,
171 .of_match_table
= ls_pcie_of_match
,
175 module_platform_driver_probe(ls_pcie_driver
, ls_pcie_probe
);
177 MODULE_AUTHOR("Minghuan Lian <Minghuan.Lian@freescale.com>");
178 MODULE_DESCRIPTION("Freescale Layerscape PCIe host controller driver");
179 MODULE_LICENSE("GPL v2");