diff options
author | Ryder Lee <ryder.lee@mediatek.com> | 2017-08-10 02:34:54 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2017-08-30 09:23:55 -0400 |
commit | e10b7a184ccf883a456c8683fa2e53eddd3aeb9c (patch) | |
tree | 8191e1844128b43883c44232b51e957154bf26b5 | |
parent | 608fcac7ce31b9644bf0e71810f5a033693c17b0 (diff) |
PCI: mediatek: Use readl_poll_timeout() to wait for Gen2 training
Wait for Gen2 training with readl_poll_timeout(), and simplify the hardware
assert logical by merging it into a new mtk_pcie_startup_port() interface.
Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
Signed-off-by: Honghui Zhang <honghui.zhang@mediatek.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
-rw-r--r-- | drivers/pci/host/pcie-mediatek.c | 52 |
1 files changed, 22 insertions, 30 deletions
diff --git a/drivers/pci/host/pcie-mediatek.c b/drivers/pci/host/pcie-mediatek.c index 9c9f89bcf24c..f4e42266eaa7 100644 --- a/drivers/pci/host/pcie-mediatek.c +++ b/drivers/pci/host/pcie-mediatek.c | |||
@@ -16,6 +16,7 @@ | |||
16 | 16 | ||
17 | #include <linux/clk.h> | 17 | #include <linux/clk.h> |
18 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
19 | #include <linux/iopoll.h> | ||
19 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
20 | #include <linux/of_address.h> | 21 | #include <linux/of_address.h> |
21 | #include <linux/of_pci.h> | 22 | #include <linux/of_pci.h> |
@@ -113,11 +114,6 @@ struct mtk_pcie { | |||
113 | struct list_head ports; | 114 | struct list_head ports; |
114 | }; | 115 | }; |
115 | 116 | ||
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) | 117 | static void mtk_pcie_subsys_powerdown(struct mtk_pcie *pcie) |
122 | { | 118 | { |
123 | struct device *dev = pcie->dev; | 119 | struct device *dev = pcie->dev; |
@@ -171,12 +167,30 @@ static struct pci_ops mtk_pcie_ops = { | |||
171 | .write = pci_generic_config_write, | 167 | .write = pci_generic_config_write, |
172 | }; | 168 | }; |
173 | 169 | ||
174 | static void mtk_pcie_configure_rc(struct mtk_pcie_port *port) | 170 | static int mtk_pcie_startup_port(struct mtk_pcie_port *port) |
175 | { | 171 | { |
176 | struct mtk_pcie *pcie = port->pcie; | 172 | struct mtk_pcie *pcie = port->pcie; |
177 | u32 func = PCI_FUNC(port->index << 3); | 173 | u32 func = PCI_FUNC(port->index << 3); |
178 | u32 slot = PCI_SLOT(port->index << 3); | 174 | u32 slot = PCI_SLOT(port->index << 3); |
179 | u32 val; | 175 | u32 val; |
176 | int err; | ||
177 | |||
178 | /* assert port PERST_N */ | ||
179 | val = readl(pcie->base + PCIE_SYS_CFG); | ||
180 | val |= PCIE_PORT_PERST(port->index); | ||
181 | writel(val, pcie->base + PCIE_SYS_CFG); | ||
182 | |||
183 | /* de-assert port PERST_N */ | ||
184 | val = readl(pcie->base + PCIE_SYS_CFG); | ||
185 | val &= ~PCIE_PORT_PERST(port->index); | ||
186 | writel(val, pcie->base + PCIE_SYS_CFG); | ||
187 | |||
188 | /* 100ms timeout value should be enough for Gen1/2 training */ | ||
189 | err = readl_poll_timeout(port->base + PCIE_LINK_STATUS, val, | ||
190 | !!(val & PCIE_PORT_LINKUP), 20, | ||
191 | 100 * USEC_PER_MSEC); | ||
192 | if (err) | ||
193 | return -ETIMEDOUT; | ||
180 | 194 | ||
181 | /* enable interrupt */ | 195 | /* enable interrupt */ |
182 | val = readl(pcie->base + PCIE_INT_ENABLE); | 196 | val = readl(pcie->base + PCIE_INT_ENABLE); |
@@ -209,25 +223,8 @@ static void mtk_pcie_configure_rc(struct mtk_pcie_port *port) | |||
209 | writel(PCIE_CONF_ADDR(PCIE_FTS_NUM, func, slot, 0), | 223 | writel(PCIE_CONF_ADDR(PCIE_FTS_NUM, func, slot, 0), |
210 | pcie->base + PCIE_CFG_ADDR); | 224 | pcie->base + PCIE_CFG_ADDR); |
211 | writel(val, pcie->base + PCIE_CFG_DATA); | 225 | writel(val, pcie->base + PCIE_CFG_DATA); |
212 | } | ||
213 | 226 | ||
214 | static void mtk_pcie_assert_ports(struct mtk_pcie_port *port) | 227 | return 0; |
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 | } | 228 | } |
232 | 229 | ||
233 | static void mtk_pcie_enable_ports(struct mtk_pcie_port *port) | 230 | static void mtk_pcie_enable_ports(struct mtk_pcie_port *port) |
@@ -250,13 +247,8 @@ static void mtk_pcie_enable_ports(struct mtk_pcie_port *port) | |||
250 | goto err_phy_on; | 247 | goto err_phy_on; |
251 | } | 248 | } |
252 | 249 | ||
253 | mtk_pcie_assert_ports(port); | 250 | if (!mtk_pcie_startup_port(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; | 251 | return; |
259 | } | ||
260 | 252 | ||
261 | dev_info(dev, "Port%d link down\n", port->index); | 253 | dev_info(dev, "Port%d link down\n", port->index); |
262 | 254 | ||