diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2017-07-04 12:00:57 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2017-07-04 12:00:57 -0400 |
commit | 097d05704e5952307b86ffef310a2a1e04f814b2 (patch) | |
tree | a683f923dcf984f89ccd13d29b500c68f9763ba9 | |
parent | 8a08e7eada357e853ff448482208a5ee7b94201a (diff) | |
parent | ea7f4491e9773fbd1f57a3f38b9b9cd92090ba9b (diff) |
Merge branch 'pci/host-mediatek' into next
* pci/host-mediatek:
dt-bindings: PCI: Add documentation for MediaTek PCIe
PCI: mediatek: Add MediaTek PCIe host controller support
-rw-r--r-- | Documentation/devicetree/bindings/pci/mediatek,mt7623-pcie.txt | 130 | ||||
-rw-r--r-- | MAINTAINERS | 8 | ||||
-rw-r--r-- | drivers/pci/host/Kconfig | 11 | ||||
-rw-r--r-- | drivers/pci/host/Makefile | 1 | ||||
-rw-r--r-- | drivers/pci/host/pcie-mediatek.c | 554 |
5 files changed, 704 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/pci/mediatek,mt7623-pcie.txt b/Documentation/devicetree/bindings/pci/mediatek,mt7623-pcie.txt new file mode 100644 index 000000000000..fe80dda9bf73 --- /dev/null +++ b/Documentation/devicetree/bindings/pci/mediatek,mt7623-pcie.txt | |||
@@ -0,0 +1,130 @@ | |||
1 | MediaTek Gen2 PCIe controller which is available on MT7623 series SoCs | ||
2 | |||
3 | PCIe subsys supports single root complex (RC) with 3 Root Ports. Each root | ||
4 | ports supports a Gen2 1-lane Link and has PIPE interface to PHY. | ||
5 | |||
6 | Required properties: | ||
7 | - compatible: Should contain "mediatek,mt7623-pcie". | ||
8 | - device_type: Must be "pci" | ||
9 | - reg: Base addresses and lengths of the PCIe controller. | ||
10 | - #address-cells: Address representation for root ports (must be 3) | ||
11 | - #size-cells: Size representation for root ports (must be 2) | ||
12 | - #interrupt-cells: Size representation for interrupts (must be 1) | ||
13 | - interrupt-map-mask and interrupt-map: Standard PCI IRQ mapping properties | ||
14 | Please refer to the standard PCI bus binding document for a more detailed | ||
15 | explanation. | ||
16 | - clocks: Must contain an entry for each entry in clock-names. | ||
17 | See ../clocks/clock-bindings.txt for details. | ||
18 | - clock-names: Must include the following entries: | ||
19 | - free_ck :for reference clock of PCIe subsys | ||
20 | - sys_ck0 :for clock of Port0 | ||
21 | - sys_ck1 :for clock of Port1 | ||
22 | - sys_ck2 :for clock of Port2 | ||
23 | - resets: Must contain an entry for each entry in reset-names. | ||
24 | See ../reset/reset.txt for details. | ||
25 | - reset-names: Must include the following entries: | ||
26 | - pcie-rst0 :port0 reset | ||
27 | - pcie-rst1 :port1 reset | ||
28 | - pcie-rst2 :port2 reset | ||
29 | - phys: List of PHY specifiers (used by generic PHY framework). | ||
30 | - phy-names : Must be "pcie-phy0", "pcie-phy1", "pcie-phyN".. based on the | ||
31 | number of PHYs as specified in *phys* property. | ||
32 | - power-domains: A phandle and power domain specifier pair to the power domain | ||
33 | which is responsible for collapsing and restoring power to the peripheral. | ||
34 | - bus-range: Range of bus numbers associated with this controller. | ||
35 | - ranges: Ranges for the PCI memory and I/O regions. | ||
36 | |||
37 | In addition, the device tree node must have sub-nodes describing each | ||
38 | PCIe port interface, having the following mandatory properties: | ||
39 | |||
40 | Required properties: | ||
41 | - device_type: Must be "pci" | ||
42 | - reg: Only the first four bytes are used to refer to the correct bus number | ||
43 | and device number. | ||
44 | - #address-cells: Must be 3 | ||
45 | - #size-cells: Must be 2 | ||
46 | - #interrupt-cells: Must be 1 | ||
47 | - interrupt-map-mask and interrupt-map: Standard PCI IRQ mapping properties | ||
48 | Please refer to the standard PCI bus binding document for a more detailed | ||
49 | explanation. | ||
50 | - ranges: Sub-ranges distributed from the PCIe controller node. An empty | ||
51 | property is sufficient. | ||
52 | - num-lanes: Number of lanes to use for this port. | ||
53 | |||
54 | Examples: | ||
55 | |||
56 | hifsys: syscon@1a000000 { | ||
57 | compatible = "mediatek,mt7623-hifsys", | ||
58 | "mediatek,mt2701-hifsys", | ||
59 | "syscon"; | ||
60 | reg = <0 0x1a000000 0 0x1000>; | ||
61 | #clock-cells = <1>; | ||
62 | #reset-cells = <1>; | ||
63 | }; | ||
64 | |||
65 | pcie: pcie-controller@1a140000 { | ||
66 | compatible = "mediatek,mt7623-pcie"; | ||
67 | device_type = "pci"; | ||
68 | reg = <0 0x1a140000 0 0x1000>, /* PCIe shared registers */ | ||
69 | <0 0x1a142000 0 0x1000>, /* Port0 registers */ | ||
70 | <0 0x1a143000 0 0x1000>, /* Port1 registers */ | ||
71 | <0 0x1a144000 0 0x1000>; /* Port2 registers */ | ||
72 | #address-cells = <3>; | ||
73 | #size-cells = <2>; | ||
74 | #interrupt-cells = <1>; | ||
75 | interrupt-map-mask = <0xf800 0 0 0>; | ||
76 | interrupt-map = <0x0000 0 0 0 &sysirq GIC_SPI 193 IRQ_TYPE_LEVEL_LOW>, | ||
77 | <0x0800 0 0 0 &sysirq GIC_SPI 194 IRQ_TYPE_LEVEL_LOW>, | ||
78 | <0x1000 0 0 0 &sysirq GIC_SPI 195 IRQ_TYPE_LEVEL_LOW>; | ||
79 | clocks = <&topckgen CLK_TOP_ETHIF_SEL>, | ||
80 | <&hifsys CLK_HIFSYS_PCIE0>, | ||
81 | <&hifsys CLK_HIFSYS_PCIE1>, | ||
82 | <&hifsys CLK_HIFSYS_PCIE2>; | ||
83 | clock-names = "free_ck", "sys_ck0", "sys_ck1", "sys_ck2"; | ||
84 | resets = <&hifsys MT2701_HIFSYS_PCIE0_RST>, | ||
85 | <&hifsys MT2701_HIFSYS_PCIE1_RST>, | ||
86 | <&hifsys MT2701_HIFSYS_PCIE2_RST>; | ||
87 | reset-names = "pcie-rst0", "pcie-rst1", "pcie-rst2"; | ||
88 | phys = <&pcie0_phy>, <&pcie1_phy>, <&pcie2_phy>; | ||
89 | phy-names = "pcie-phy0", "pcie-phy1", "pcie-phy2"; | ||
90 | power-domains = <&scpsys MT2701_POWER_DOMAIN_HIF>; | ||
91 | bus-range = <0x00 0xff>; | ||
92 | ranges = <0x81000000 0 0x1a160000 0 0x1a160000 0 0x00010000 /* I/O space */ | ||
93 | 0x83000000 0 0x60000000 0 0x60000000 0 0x10000000>; /* memory space */ | ||
94 | |||
95 | pcie@0,0 { | ||
96 | device_type = "pci"; | ||
97 | reg = <0x0000 0 0 0 0>; | ||
98 | #address-cells = <3>; | ||
99 | #size-cells = <2>; | ||
100 | #interrupt-cells = <1>; | ||
101 | interrupt-map-mask = <0 0 0 0>; | ||
102 | interrupt-map = <0 0 0 0 &sysirq GIC_SPI 193 IRQ_TYPE_LEVEL_LOW>; | ||
103 | ranges; | ||
104 | num-lanes = <1>; | ||
105 | }; | ||
106 | |||
107 | pcie@1,0 { | ||
108 | device_type = "pci"; | ||
109 | reg = <0x0800 0 0 0 0>; | ||
110 | #address-cells = <3>; | ||
111 | #size-cells = <2>; | ||
112 | #interrupt-cells = <1>; | ||
113 | interrupt-map-mask = <0 0 0 0>; | ||
114 | interrupt-map = <0 0 0 0 &sysirq GIC_SPI 194 IRQ_TYPE_LEVEL_LOW>; | ||
115 | ranges; | ||
116 | num-lanes = <1>; | ||
117 | }; | ||
118 | |||
119 | pcie@2,0 { | ||
120 | device_type = "pci"; | ||
121 | reg = <0x1000 0 0 0 0>; | ||
122 | #address-cells = <3>; | ||
123 | #size-cells = <2>; | ||
124 | #interrupt-cells = <1>; | ||
125 | interrupt-map-mask = <0 0 0 0>; | ||
126 | interrupt-map = <0 0 0 0 &sysirq GIC_SPI 195 IRQ_TYPE_LEVEL_LOW>; | ||
127 | ranges; | ||
128 | num-lanes = <1>; | ||
129 | }; | ||
130 | }; | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 3a9f9d3db437..ed26c0b2eeb5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -9965,6 +9965,14 @@ S: Supported | |||
9965 | F: Documentation/devicetree/bindings/pci/pci-thunder-* | 9965 | F: Documentation/devicetree/bindings/pci/pci-thunder-* |
9966 | F: drivers/pci/host/pci-thunder-* | 9966 | F: drivers/pci/host/pci-thunder-* |
9967 | 9967 | ||
9968 | PCIE DRIVER FOR MEDIATEK | ||
9969 | M: Ryder Lee <ryder.lee@mediatek.com> | ||
9970 | L: linux-pci@vger.kernel.org | ||
9971 | L: linux-mediatek@lists.infradead.org | ||
9972 | S: Supported | ||
9973 | F: Documentation/devicetree/bindings/pci/mediatek* | ||
9974 | F: drivers/pci/host/*mediatek* | ||
9975 | |||
9968 | PCMCIA SUBSYSTEM | 9976 | PCMCIA SUBSYSTEM |
9969 | P: Linux PCMCIA Team | 9977 | P: Linux PCMCIA Team |
9970 | L: linux-pcmcia@lists.infradead.org | 9978 | L: linux-pcmcia@lists.infradead.org |
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index 7f47cd5e10a5..0cd5b30dccb1 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig | |||
@@ -180,6 +180,17 @@ config PCIE_ROCKCHIP | |||
180 | There is 1 internal PCIe port available to support GEN2 with | 180 | There is 1 internal PCIe port available to support GEN2 with |
181 | 4 slots. | 181 | 4 slots. |
182 | 182 | ||
183 | config PCIE_MEDIATEK | ||
184 | bool "MediaTek PCIe controller" | ||
185 | depends on ARM && (ARCH_MEDIATEK || COMPILE_TEST) | ||
186 | depends on OF | ||
187 | depends on PCI | ||
188 | select PCIEPORTBUS | ||
189 | help | ||
190 | Say Y here if you want to enable PCIe controller support on | ||
191 | MT7623 series SoCs. There is one single root complex with 3 root | ||
192 | ports available. Each port supports Gen2 lane x1. | ||
193 | |||
183 | config VMD | 194 | config VMD |
184 | depends on PCI_MSI && X86_64 && SRCU | 195 | depends on PCI_MSI && X86_64 && SRCU |
185 | tristate "Intel Volume Management Device Driver" | 196 | tristate "Intel Volume Management Device Driver" |
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index cab879578003..b10d104c85fd 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile | |||
@@ -18,6 +18,7 @@ obj-$(CONFIG_PCIE_IPROC_BCMA) += pcie-iproc-bcma.o | |||
18 | obj-$(CONFIG_PCIE_ALTERA) += pcie-altera.o | 18 | obj-$(CONFIG_PCIE_ALTERA) += pcie-altera.o |
19 | obj-$(CONFIG_PCIE_ALTERA_MSI) += pcie-altera-msi.o | 19 | obj-$(CONFIG_PCIE_ALTERA_MSI) += pcie-altera-msi.o |
20 | obj-$(CONFIG_PCIE_ROCKCHIP) += pcie-rockchip.o | 20 | obj-$(CONFIG_PCIE_ROCKCHIP) += pcie-rockchip.o |
21 | obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o | ||
21 | obj-$(CONFIG_VMD) += vmd.o | 22 | obj-$(CONFIG_VMD) += vmd.o |
22 | 23 | ||
23 | # The following drivers are for devices that use the generic ACPI | 24 | # The following drivers are for devices that use the generic ACPI |
diff --git a/drivers/pci/host/pcie-mediatek.c b/drivers/pci/host/pcie-mediatek.c new file mode 100644 index 000000000000..5a9d8589ea0b --- /dev/null +++ b/drivers/pci/host/pcie-mediatek.c | |||
@@ -0,0 +1,554 @@ | |||
1 | /* | ||
2 | * MediaTek PCIe host controller driver. | ||
3 | * | ||
4 | * Copyright (c) 2017 MediaTek Inc. | ||
5 | * Author: Ryder Lee <ryder.lee@mediatek.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/clk.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/of_address.h> | ||
21 | #include <linux/of_pci.h> | ||
22 | #include <linux/of_platform.h> | ||
23 | #include <linux/pci.h> | ||
24 | #include <linux/phy/phy.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/pm_runtime.h> | ||
27 | #include <linux/reset.h> | ||
28 | |||
29 | /* PCIe shared registers */ | ||
30 | #define PCIE_SYS_CFG 0x00 | ||
31 | #define PCIE_INT_ENABLE 0x0c | ||
32 | #define PCIE_CFG_ADDR 0x20 | ||
33 | #define PCIE_CFG_DATA 0x24 | ||
34 | |||
35 | /* PCIe per port registers */ | ||
36 | #define PCIE_BAR0_SETUP 0x10 | ||
37 | #define PCIE_CLASS 0x34 | ||
38 | #define PCIE_LINK_STATUS 0x50 | ||
39 | |||
40 | #define PCIE_PORT_INT_EN(x) BIT(20 + (x)) | ||
41 | #define PCIE_PORT_PERST(x) BIT(1 + (x)) | ||
42 | #define PCIE_PORT_LINKUP BIT(0) | ||
43 | #define PCIE_BAR_MAP_MAX GENMASK(31, 16) | ||
44 | |||
45 | #define PCIE_BAR_ENABLE BIT(0) | ||
46 | #define PCIE_REVISION_ID BIT(0) | ||
47 | #define PCIE_CLASS_CODE (0x60400 << 8) | ||
48 | #define PCIE_CONF_REG(regn) (((regn) & GENMASK(7, 2)) | \ | ||
49 | ((((regn) >> 8) & GENMASK(3, 0)) << 24)) | ||
50 | #define PCIE_CONF_FUN(fun) (((fun) << 8) & GENMASK(10, 8)) | ||
51 | #define PCIE_CONF_DEV(dev) (((dev) << 11) & GENMASK(15, 11)) | ||
52 | #define PCIE_CONF_BUS(bus) (((bus) << 16) & GENMASK(23, 16)) | ||
53 | #define PCIE_CONF_ADDR(regn, fun, dev, bus) \ | ||
54 | (PCIE_CONF_REG(regn) | PCIE_CONF_FUN(fun) | \ | ||
55 | PCIE_CONF_DEV(dev) | PCIE_CONF_BUS(bus)) | ||
56 | |||
57 | /* MediaTek specific configuration registers */ | ||
58 | #define PCIE_FTS_NUM 0x70c | ||
59 | #define PCIE_FTS_NUM_MASK GENMASK(15, 8) | ||
60 | #define PCIE_FTS_NUM_L0(x) ((x) & 0xff << 8) | ||
61 | |||
62 | #define PCIE_FC_CREDIT 0x73c | ||
63 | #define PCIE_FC_CREDIT_MASK (GENMASK(31, 31) | GENMASK(28, 16)) | ||
64 | #define PCIE_FC_CREDIT_VAL(x) ((x) << 16) | ||
65 | |||
66 | /** | ||
67 | * struct mtk_pcie_port - PCIe port information | ||
68 | * @base: IO mapped register base | ||
69 | * @list: port list | ||
70 | * @pcie: pointer to PCIe host info | ||
71 | * @reset: pointer to port reset control | ||
72 | * @sys_ck: pointer to bus clock | ||
73 | * @phy: pointer to phy control block | ||
74 | * @lane: lane count | ||
75 | * @index: port index | ||
76 | */ | ||
77 | struct mtk_pcie_port { | ||
78 | void __iomem *base; | ||
79 | struct list_head list; | ||
80 | struct mtk_pcie *pcie; | ||
81 | struct reset_control *reset; | ||
82 | struct clk *sys_ck; | ||
83 | struct phy *phy; | ||
84 | u32 lane; | ||
85 | u32 index; | ||
86 | }; | ||
87 | |||
88 | /** | ||
89 | * struct mtk_pcie - PCIe host information | ||
90 | * @dev: pointer to PCIe device | ||
91 | * @base: IO mapped register base | ||
92 | * @free_ck: free-run reference clock | ||
93 | * @io: IO resource | ||
94 | * @pio: PIO resource | ||
95 | * @mem: non-prefetchable memory resource | ||
96 | * @busn: bus range | ||
97 | * @offset: IO / Memory offset | ||
98 | * @ports: pointer to PCIe port information | ||
99 | */ | ||
100 | struct mtk_pcie { | ||
101 | struct device *dev; | ||
102 | void __iomem *base; | ||
103 | struct clk *free_ck; | ||
104 | |||
105 | struct resource io; | ||
106 | struct resource pio; | ||
107 | struct resource mem; | ||
108 | struct resource busn; | ||
109 | struct { | ||
110 | resource_size_t mem; | ||
111 | resource_size_t io; | ||
112 | } offset; | ||
113 | struct list_head ports; | ||
114 | }; | ||
115 | |||
116 | static inline bool mtk_pcie_link_up(struct mtk_pcie_port *port) | ||
117 | { | ||
118 | return !!(readl(port->base + PCIE_LINK_STATUS) & PCIE_PORT_LINKUP); | ||
119 | } | ||
120 | |||
121 | static void mtk_pcie_subsys_powerdown(struct mtk_pcie *pcie) | ||
122 | { | ||
123 | struct device *dev = pcie->dev; | ||
124 | |||
125 | clk_disable_unprepare(pcie->free_ck); | ||
126 | |||
127 | if (dev->pm_domain) { | ||
128 | pm_runtime_put_sync(dev); | ||
129 | pm_runtime_disable(dev); | ||
130 | } | ||
131 | } | ||
132 | |||
133 | static void mtk_pcie_port_free(struct mtk_pcie_port *port) | ||
134 | { | ||
135 | struct mtk_pcie *pcie = port->pcie; | ||
136 | struct device *dev = pcie->dev; | ||
137 | |||
138 | devm_iounmap(dev, port->base); | ||
139 | list_del(&port->list); | ||
140 | devm_kfree(dev, port); | ||
141 | } | ||
142 | |||
143 | static void mtk_pcie_put_resources(struct mtk_pcie *pcie) | ||
144 | { | ||
145 | struct mtk_pcie_port *port, *tmp; | ||
146 | |||
147 | list_for_each_entry_safe(port, tmp, &pcie->ports, list) { | ||
148 | phy_power_off(port->phy); | ||
149 | clk_disable_unprepare(port->sys_ck); | ||
150 | mtk_pcie_port_free(port); | ||
151 | } | ||
152 | |||
153 | mtk_pcie_subsys_powerdown(pcie); | ||
154 | } | ||
155 | |||
156 | static void __iomem *mtk_pcie_map_bus(struct pci_bus *bus, | ||
157 | unsigned int devfn, int where) | ||
158 | { | ||
159 | struct pci_host_bridge *host = pci_find_host_bridge(bus); | ||
160 | struct mtk_pcie *pcie = pci_host_bridge_priv(host); | ||
161 | |||
162 | writel(PCIE_CONF_ADDR(where, PCI_FUNC(devfn), PCI_SLOT(devfn), | ||
163 | bus->number), pcie->base + PCIE_CFG_ADDR); | ||
164 | |||
165 | return pcie->base + PCIE_CFG_DATA + (where & 3); | ||
166 | } | ||
167 | |||
168 | static struct pci_ops mtk_pcie_ops = { | ||
169 | .map_bus = mtk_pcie_map_bus, | ||
170 | .read = pci_generic_config_read, | ||
171 | .write = pci_generic_config_write, | ||
172 | }; | ||
173 | |||
174 | static void mtk_pcie_configure_rc(struct mtk_pcie_port *port) | ||
175 | { | ||
176 | struct mtk_pcie *pcie = port->pcie; | ||
177 | u32 func = PCI_FUNC(port->index << 3); | ||
178 | u32 slot = PCI_SLOT(port->index << 3); | ||
179 | u32 val; | ||
180 | |||
181 | /* enable interrupt */ | ||
182 | val = readl(pcie->base + PCIE_INT_ENABLE); | ||
183 | val |= PCIE_PORT_INT_EN(port->index); | ||
184 | writel(val, pcie->base + PCIE_INT_ENABLE); | ||
185 | |||
186 | /* map to all DDR region. We need to set it before cfg operation. */ | ||
187 | writel(PCIE_BAR_MAP_MAX | PCIE_BAR_ENABLE, | ||
188 | port->base + PCIE_BAR0_SETUP); | ||
189 | |||
190 | /* configure class code and revision ID */ | ||
191 | writel(PCIE_CLASS_CODE | PCIE_REVISION_ID, port->base + PCIE_CLASS); | ||
192 | |||
193 | /* configure FC credit */ | ||
194 | writel(PCIE_CONF_ADDR(PCIE_FC_CREDIT, func, slot, 0), | ||
195 | pcie->base + PCIE_CFG_ADDR); | ||
196 | val = readl(pcie->base + PCIE_CFG_DATA); | ||
197 | val &= ~PCIE_FC_CREDIT_MASK; | ||
198 | val |= PCIE_FC_CREDIT_VAL(0x806c); | ||
199 | writel(PCIE_CONF_ADDR(PCIE_FC_CREDIT, func, slot, 0), | ||
200 | pcie->base + PCIE_CFG_ADDR); | ||
201 | writel(val, pcie->base + PCIE_CFG_DATA); | ||
202 | |||
203 | /* configure RC FTS number to 250 when it leaves L0s */ | ||
204 | writel(PCIE_CONF_ADDR(PCIE_FTS_NUM, func, slot, 0), | ||
205 | pcie->base + PCIE_CFG_ADDR); | ||
206 | val = readl(pcie->base + PCIE_CFG_DATA); | ||
207 | val &= ~PCIE_FTS_NUM_MASK; | ||
208 | val |= PCIE_FTS_NUM_L0(0x50); | ||
209 | writel(PCIE_CONF_ADDR(PCIE_FTS_NUM, func, slot, 0), | ||
210 | pcie->base + PCIE_CFG_ADDR); | ||
211 | writel(val, pcie->base + PCIE_CFG_DATA); | ||
212 | } | ||
213 | |||
214 | static void mtk_pcie_assert_ports(struct mtk_pcie_port *port) | ||
215 | { | ||
216 | struct mtk_pcie *pcie = port->pcie; | ||
217 | u32 val; | ||
218 | |||
219 | /* assert port PERST_N */ | ||
220 | val = readl(pcie->base + PCIE_SYS_CFG); | ||
221 | val |= PCIE_PORT_PERST(port->index); | ||
222 | writel(val, pcie->base + PCIE_SYS_CFG); | ||
223 | |||
224 | /* de-assert port PERST_N */ | ||
225 | val = readl(pcie->base + PCIE_SYS_CFG); | ||
226 | val &= ~PCIE_PORT_PERST(port->index); | ||
227 | writel(val, pcie->base + PCIE_SYS_CFG); | ||
228 | |||
229 | /* PCIe v2.0 need at least 100ms delay to train from Gen1 to Gen2 */ | ||
230 | msleep(100); | ||
231 | } | ||
232 | |||
233 | static void mtk_pcie_enable_ports(struct mtk_pcie_port *port) | ||
234 | { | ||
235 | struct device *dev = port->pcie->dev; | ||
236 | int err; | ||
237 | |||
238 | err = clk_prepare_enable(port->sys_ck); | ||
239 | if (err) { | ||
240 | dev_err(dev, "failed to enable port%d clock\n", port->index); | ||
241 | goto err_sys_clk; | ||
242 | } | ||
243 | |||
244 | reset_control_assert(port->reset); | ||
245 | reset_control_deassert(port->reset); | ||
246 | |||
247 | err = phy_power_on(port->phy); | ||
248 | if (err) { | ||
249 | dev_err(dev, "failed to power on port%d phy\n", port->index); | ||
250 | goto err_phy_on; | ||
251 | } | ||
252 | |||
253 | mtk_pcie_assert_ports(port); | ||
254 | |||
255 | /* if link up, then setup root port configuration space */ | ||
256 | if (mtk_pcie_link_up(port)) { | ||
257 | mtk_pcie_configure_rc(port); | ||
258 | return; | ||
259 | } | ||
260 | |||
261 | dev_info(dev, "Port%d link down\n", port->index); | ||
262 | |||
263 | phy_power_off(port->phy); | ||
264 | err_phy_on: | ||
265 | clk_disable_unprepare(port->sys_ck); | ||
266 | err_sys_clk: | ||
267 | mtk_pcie_port_free(port); | ||
268 | } | ||
269 | |||
270 | static int mtk_pcie_parse_ports(struct mtk_pcie *pcie, | ||
271 | struct device_node *node, | ||
272 | int index) | ||
273 | { | ||
274 | struct mtk_pcie_port *port; | ||
275 | struct resource *regs; | ||
276 | struct device *dev = pcie->dev; | ||
277 | struct platform_device *pdev = to_platform_device(dev); | ||
278 | char name[10]; | ||
279 | int err; | ||
280 | |||
281 | port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); | ||
282 | if (!port) | ||
283 | return -ENOMEM; | ||
284 | |||
285 | err = of_property_read_u32(node, "num-lanes", &port->lane); | ||
286 | if (err) { | ||
287 | dev_err(dev, "missing num-lanes property\n"); | ||
288 | return err; | ||
289 | } | ||
290 | |||
291 | regs = platform_get_resource(pdev, IORESOURCE_MEM, index + 1); | ||
292 | port->base = devm_ioremap_resource(dev, regs); | ||
293 | if (IS_ERR(port->base)) { | ||
294 | dev_err(dev, "failed to map port%d base\n", index); | ||
295 | return PTR_ERR(port->base); | ||
296 | } | ||
297 | |||
298 | snprintf(name, sizeof(name), "sys_ck%d", index); | ||
299 | port->sys_ck = devm_clk_get(dev, name); | ||
300 | if (IS_ERR(port->sys_ck)) { | ||
301 | dev_err(dev, "failed to get port%d clock\n", index); | ||
302 | return PTR_ERR(port->sys_ck); | ||
303 | } | ||
304 | |||
305 | snprintf(name, sizeof(name), "pcie-rst%d", index); | ||
306 | port->reset = devm_reset_control_get_optional(dev, name); | ||
307 | if (PTR_ERR(port->reset) == -EPROBE_DEFER) | ||
308 | return PTR_ERR(port->reset); | ||
309 | |||
310 | /* some platforms may use default PHY setting */ | ||
311 | snprintf(name, sizeof(name), "pcie-phy%d", index); | ||
312 | port->phy = devm_phy_optional_get(dev, name); | ||
313 | if (IS_ERR(port->phy)) | ||
314 | return PTR_ERR(port->phy); | ||
315 | |||
316 | port->index = index; | ||
317 | port->pcie = pcie; | ||
318 | |||
319 | INIT_LIST_HEAD(&port->list); | ||
320 | list_add_tail(&port->list, &pcie->ports); | ||
321 | |||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | static int mtk_pcie_subsys_powerup(struct mtk_pcie *pcie) | ||
326 | { | ||
327 | struct device *dev = pcie->dev; | ||
328 | struct platform_device *pdev = to_platform_device(dev); | ||
329 | struct resource *regs; | ||
330 | int err; | ||
331 | |||
332 | /* get shared registers */ | ||
333 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
334 | pcie->base = devm_ioremap_resource(dev, regs); | ||
335 | if (IS_ERR(pcie->base)) { | ||
336 | dev_err(dev, "failed to map shared register\n"); | ||
337 | return PTR_ERR(pcie->base); | ||
338 | } | ||
339 | |||
340 | pcie->free_ck = devm_clk_get(dev, "free_ck"); | ||
341 | if (IS_ERR(pcie->free_ck)) { | ||
342 | if (PTR_ERR(pcie->free_ck) == -EPROBE_DEFER) | ||
343 | return -EPROBE_DEFER; | ||
344 | |||
345 | pcie->free_ck = NULL; | ||
346 | } | ||
347 | |||
348 | if (dev->pm_domain) { | ||
349 | pm_runtime_enable(dev); | ||
350 | pm_runtime_get_sync(dev); | ||
351 | } | ||
352 | |||
353 | /* enable top level clock */ | ||
354 | err = clk_prepare_enable(pcie->free_ck); | ||
355 | if (err) { | ||
356 | dev_err(dev, "failed to enable free_ck\n"); | ||
357 | goto err_free_ck; | ||
358 | } | ||
359 | |||
360 | return 0; | ||
361 | |||
362 | err_free_ck: | ||
363 | if (dev->pm_domain) { | ||
364 | pm_runtime_put_sync(dev); | ||
365 | pm_runtime_disable(dev); | ||
366 | } | ||
367 | |||
368 | return err; | ||
369 | } | ||
370 | |||
371 | static int mtk_pcie_setup(struct mtk_pcie *pcie) | ||
372 | { | ||
373 | struct device *dev = pcie->dev; | ||
374 | struct device_node *node = dev->of_node, *child; | ||
375 | struct of_pci_range_parser parser; | ||
376 | struct of_pci_range range; | ||
377 | struct resource res; | ||
378 | struct mtk_pcie_port *port, *tmp; | ||
379 | int err; | ||
380 | |||
381 | if (of_pci_range_parser_init(&parser, node)) { | ||
382 | dev_err(dev, "missing \"ranges\" property\n"); | ||
383 | return -EINVAL; | ||
384 | } | ||
385 | |||
386 | for_each_of_pci_range(&parser, &range) { | ||
387 | err = of_pci_range_to_resource(&range, node, &res); | ||
388 | if (err < 0) | ||
389 | return err; | ||
390 | |||
391 | switch (res.flags & IORESOURCE_TYPE_BITS) { | ||
392 | case IORESOURCE_IO: | ||
393 | pcie->offset.io = res.start - range.pci_addr; | ||
394 | |||
395 | memcpy(&pcie->pio, &res, sizeof(res)); | ||
396 | pcie->pio.name = node->full_name; | ||
397 | |||
398 | pcie->io.start = range.cpu_addr; | ||
399 | pcie->io.end = range.cpu_addr + range.size - 1; | ||
400 | pcie->io.flags = IORESOURCE_MEM; | ||
401 | pcie->io.name = "I/O"; | ||
402 | |||
403 | memcpy(&res, &pcie->io, sizeof(res)); | ||
404 | break; | ||
405 | |||
406 | case IORESOURCE_MEM: | ||
407 | pcie->offset.mem = res.start - range.pci_addr; | ||
408 | |||
409 | memcpy(&pcie->mem, &res, sizeof(res)); | ||
410 | pcie->mem.name = "non-prefetchable"; | ||
411 | break; | ||
412 | } | ||
413 | } | ||
414 | |||
415 | err = of_pci_parse_bus_range(node, &pcie->busn); | ||
416 | if (err < 0) { | ||
417 | dev_err(dev, "failed to parse bus ranges property: %d\n", err); | ||
418 | pcie->busn.name = node->name; | ||
419 | pcie->busn.start = 0; | ||
420 | pcie->busn.end = 0xff; | ||
421 | pcie->busn.flags = IORESOURCE_BUS; | ||
422 | } | ||
423 | |||
424 | for_each_available_child_of_node(node, child) { | ||
425 | int index; | ||
426 | |||
427 | err = of_pci_get_devfn(child); | ||
428 | if (err < 0) { | ||
429 | dev_err(dev, "failed to parse devfn: %d\n", err); | ||
430 | return err; | ||
431 | } | ||
432 | |||
433 | index = PCI_SLOT(err); | ||
434 | |||
435 | err = mtk_pcie_parse_ports(pcie, child, index); | ||
436 | if (err) | ||
437 | return err; | ||
438 | } | ||
439 | |||
440 | err = mtk_pcie_subsys_powerup(pcie); | ||
441 | if (err) | ||
442 | return err; | ||
443 | |||
444 | /* enable each port, and then check link status */ | ||
445 | list_for_each_entry_safe(port, tmp, &pcie->ports, list) | ||
446 | mtk_pcie_enable_ports(port); | ||
447 | |||
448 | /* power down PCIe subsys if slots are all empty (link down) */ | ||
449 | if (list_empty(&pcie->ports)) | ||
450 | mtk_pcie_subsys_powerdown(pcie); | ||
451 | |||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | static int mtk_pcie_request_resources(struct mtk_pcie *pcie) | ||
456 | { | ||
457 | struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie); | ||
458 | struct list_head *windows = &host->windows; | ||
459 | struct device *dev = pcie->dev; | ||
460 | int err; | ||
461 | |||
462 | pci_add_resource_offset(windows, &pcie->pio, pcie->offset.io); | ||
463 | pci_add_resource_offset(windows, &pcie->mem, pcie->offset.mem); | ||
464 | pci_add_resource(windows, &pcie->busn); | ||
465 | |||
466 | err = devm_request_pci_bus_resources(dev, windows); | ||
467 | if (err < 0) | ||
468 | return err; | ||
469 | |||
470 | pci_remap_iospace(&pcie->pio, pcie->io.start); | ||
471 | |||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | static int mtk_pcie_register_host(struct pci_host_bridge *host) | ||
476 | { | ||
477 | struct mtk_pcie *pcie = pci_host_bridge_priv(host); | ||
478 | struct pci_bus *child; | ||
479 | int err; | ||
480 | |||
481 | host->busnr = pcie->busn.start; | ||
482 | host->dev.parent = pcie->dev; | ||
483 | host->ops = &mtk_pcie_ops; | ||
484 | host->map_irq = of_irq_parse_and_map_pci; | ||
485 | host->swizzle_irq = pci_common_swizzle; | ||
486 | |||
487 | err = pci_scan_root_bus_bridge(host); | ||
488 | if (err < 0) | ||
489 | return err; | ||
490 | |||
491 | pci_bus_size_bridges(host->bus); | ||
492 | pci_bus_assign_resources(host->bus); | ||
493 | |||
494 | list_for_each_entry(child, &host->bus->children, node) | ||
495 | pcie_bus_configure_settings(child); | ||
496 | |||
497 | pci_bus_add_devices(host->bus); | ||
498 | |||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | static int mtk_pcie_probe(struct platform_device *pdev) | ||
503 | { | ||
504 | struct device *dev = &pdev->dev; | ||
505 | struct mtk_pcie *pcie; | ||
506 | struct pci_host_bridge *host; | ||
507 | int err; | ||
508 | |||
509 | host = devm_pci_alloc_host_bridge(dev, sizeof(*pcie)); | ||
510 | if (!host) | ||
511 | return -ENOMEM; | ||
512 | |||
513 | pcie = pci_host_bridge_priv(host); | ||
514 | |||
515 | pcie->dev = dev; | ||
516 | platform_set_drvdata(pdev, pcie); | ||
517 | INIT_LIST_HEAD(&pcie->ports); | ||
518 | |||
519 | err = mtk_pcie_setup(pcie); | ||
520 | if (err) | ||
521 | return err; | ||
522 | |||
523 | err = mtk_pcie_request_resources(pcie); | ||
524 | if (err) | ||
525 | goto put_resources; | ||
526 | |||
527 | err = mtk_pcie_register_host(host); | ||
528 | if (err) | ||
529 | goto put_resources; | ||
530 | |||
531 | return 0; | ||
532 | |||
533 | put_resources: | ||
534 | if (!list_empty(&pcie->ports)) | ||
535 | mtk_pcie_put_resources(pcie); | ||
536 | |||
537 | return err; | ||
538 | } | ||
539 | |||
540 | static const struct of_device_id mtk_pcie_ids[] = { | ||
541 | { .compatible = "mediatek,mt7623-pcie"}, | ||
542 | { .compatible = "mediatek,mt2701-pcie"}, | ||
543 | {}, | ||
544 | }; | ||
545 | |||
546 | static struct platform_driver mtk_pcie_driver = { | ||
547 | .probe = mtk_pcie_probe, | ||
548 | .driver = { | ||
549 | .name = "mtk-pcie", | ||
550 | .of_match_table = mtk_pcie_ids, | ||
551 | .suppress_bind_attrs = true, | ||
552 | }, | ||
553 | }; | ||
554 | builtin_platform_driver(mtk_pcie_driver); | ||