diff options
author | Jianguo Sun <sunjianguo1@huawei.com> | 2017-10-23 07:17:50 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2017-10-24 15:48:20 -0400 |
commit | bbd11bddb398c4278c06892bd6498da34c47a00a (patch) | |
tree | 1e2359db6d1fe7825871dc32d4c89db4412b44cb /drivers/pci/dwc | |
parent | 9e66317d3c92ddaab330c125dfe9d06eee268aff (diff) |
PCI: hisi: Add HiSilicon STB SoC PCIe controller driver
Add a HiSilicon STB SoC PCIe controller driver. This controller is based
on the DesignWare PCIe core.
Signed-off-by: Jianguo Sun <sunjianguo1@huawei.com>
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'drivers/pci/dwc')
-rw-r--r-- | drivers/pci/dwc/Kconfig | 10 | ||||
-rw-r--r-- | drivers/pci/dwc/Makefile | 1 | ||||
-rw-r--r-- | drivers/pci/dwc/pcie-histb.c | 470 |
3 files changed, 481 insertions, 0 deletions
diff --git a/drivers/pci/dwc/Kconfig b/drivers/pci/dwc/Kconfig index 22ec82fcdea2..113e09440f85 100644 --- a/drivers/pci/dwc/Kconfig +++ b/drivers/pci/dwc/Kconfig | |||
@@ -169,4 +169,14 @@ config PCIE_KIRIN | |||
169 | Say Y here if you want PCIe controller support | 169 | Say Y here if you want PCIe controller support |
170 | on HiSilicon Kirin series SoCs. | 170 | on HiSilicon Kirin series SoCs. |
171 | 171 | ||
172 | config PCIE_HISI_STB | ||
173 | bool "HiSilicon STB SoCs PCIe controllers" | ||
174 | depends on ARCH_HISI | ||
175 | depends on PCI | ||
176 | depends on PCI_MSI_IRQ_DOMAIN | ||
177 | select PCIEPORTBUS | ||
178 | select PCIE_DW_HOST | ||
179 | help | ||
180 | Say Y here if you want PCIe controller support on HiSilicon STB SoCs | ||
181 | |||
172 | endmenu | 182 | endmenu |
diff --git a/drivers/pci/dwc/Makefile b/drivers/pci/dwc/Makefile index c61be9738cce..54f56f6e9236 100644 --- a/drivers/pci/dwc/Makefile +++ b/drivers/pci/dwc/Makefile | |||
@@ -14,6 +14,7 @@ obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o | |||
14 | obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o | 14 | obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o |
15 | obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o | 15 | obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o |
16 | obj-$(CONFIG_PCIE_KIRIN) += pcie-kirin.o | 16 | obj-$(CONFIG_PCIE_KIRIN) += pcie-kirin.o |
17 | obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o | ||
17 | 18 | ||
18 | # The following drivers are for devices that use the generic ACPI | 19 | # The following drivers are for devices that use the generic ACPI |
19 | # pci_root.c driver but don't support standard ECAM config access. | 20 | # pci_root.c driver but don't support standard ECAM config access. |
diff --git a/drivers/pci/dwc/pcie-histb.c b/drivers/pci/dwc/pcie-histb.c new file mode 100644 index 000000000000..33b01b734d7d --- /dev/null +++ b/drivers/pci/dwc/pcie-histb.c | |||
@@ -0,0 +1,470 @@ | |||
1 | /* | ||
2 | * PCIe host controller driver for HiSilicon STB SoCs | ||
3 | * | ||
4 | * Copyright (C) 2016-2017 HiSilicon Co., Ltd. http://www.hisilicon.com | ||
5 | * | ||
6 | * Authors: Ruqiang Ju <juruqiang@hisilicon.com> | ||
7 | * Jianguo Sun <sunjianguo1@huawei.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/clk.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/of.h> | ||
20 | #include <linux/of_gpio.h> | ||
21 | #include <linux/pci.h> | ||
22 | #include <linux/phy/phy.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/resource.h> | ||
25 | #include <linux/reset.h> | ||
26 | |||
27 | #include "pcie-designware.h" | ||
28 | |||
29 | #define to_histb_pcie(x) dev_get_drvdata((x)->dev) | ||
30 | |||
31 | #define PCIE_SYS_CTRL0 0x0000 | ||
32 | #define PCIE_SYS_CTRL1 0x0004 | ||
33 | #define PCIE_SYS_CTRL7 0x001C | ||
34 | #define PCIE_SYS_CTRL13 0x0034 | ||
35 | #define PCIE_SYS_CTRL15 0x003C | ||
36 | #define PCIE_SYS_CTRL16 0x0040 | ||
37 | #define PCIE_SYS_CTRL17 0x0044 | ||
38 | |||
39 | #define PCIE_SYS_STAT0 0x0100 | ||
40 | #define PCIE_SYS_STAT4 0x0110 | ||
41 | |||
42 | #define PCIE_RDLH_LINK_UP BIT(5) | ||
43 | #define PCIE_XMLH_LINK_UP BIT(15) | ||
44 | #define PCIE_ELBI_SLV_DBI_ENABLE BIT(21) | ||
45 | #define PCIE_APP_LTSSM_ENABLE BIT(11) | ||
46 | |||
47 | #define PCIE_DEVICE_TYPE_MASK GENMASK(31, 28) | ||
48 | #define PCIE_WM_EP 0 | ||
49 | #define PCIE_WM_LEGACY BIT(1) | ||
50 | #define PCIE_WM_RC BIT(30) | ||
51 | |||
52 | #define PCIE_LTSSM_STATE_MASK GENMASK(5, 0) | ||
53 | #define PCIE_LTSSM_STATE_ACTIVE 0x11 | ||
54 | |||
55 | struct histb_pcie { | ||
56 | struct dw_pcie *pci; | ||
57 | struct clk *aux_clk; | ||
58 | struct clk *pipe_clk; | ||
59 | struct clk *sys_clk; | ||
60 | struct clk *bus_clk; | ||
61 | struct phy *phy; | ||
62 | struct reset_control *soft_reset; | ||
63 | struct reset_control *sys_reset; | ||
64 | struct reset_control *bus_reset; | ||
65 | void __iomem *ctrl; | ||
66 | int reset_gpio; | ||
67 | }; | ||
68 | |||
69 | static u32 histb_pcie_readl(struct histb_pcie *histb_pcie, u32 reg) | ||
70 | { | ||
71 | return readl(histb_pcie->ctrl + reg); | ||
72 | } | ||
73 | |||
74 | static void histb_pcie_writel(struct histb_pcie *histb_pcie, u32 reg, u32 val) | ||
75 | { | ||
76 | writel(val, histb_pcie->ctrl + reg); | ||
77 | } | ||
78 | |||
79 | static void histb_pcie_dbi_w_mode(struct pcie_port *pp, bool enable) | ||
80 | { | ||
81 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); | ||
82 | struct histb_pcie *hipcie = to_histb_pcie(pci); | ||
83 | u32 val; | ||
84 | |||
85 | val = histb_pcie_readl(hipcie, PCIE_SYS_CTRL0); | ||
86 | if (enable) | ||
87 | val |= PCIE_ELBI_SLV_DBI_ENABLE; | ||
88 | else | ||
89 | val &= ~PCIE_ELBI_SLV_DBI_ENABLE; | ||
90 | histb_pcie_writel(hipcie, PCIE_SYS_CTRL0, val); | ||
91 | } | ||
92 | |||
93 | static void histb_pcie_dbi_r_mode(struct pcie_port *pp, bool enable) | ||
94 | { | ||
95 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); | ||
96 | struct histb_pcie *hipcie = to_histb_pcie(pci); | ||
97 | u32 val; | ||
98 | |||
99 | val = histb_pcie_readl(hipcie, PCIE_SYS_CTRL1); | ||
100 | if (enable) | ||
101 | val |= PCIE_ELBI_SLV_DBI_ENABLE; | ||
102 | else | ||
103 | val &= ~PCIE_ELBI_SLV_DBI_ENABLE; | ||
104 | histb_pcie_writel(hipcie, PCIE_SYS_CTRL1, val); | ||
105 | } | ||
106 | |||
107 | static u32 histb_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base, | ||
108 | u32 reg, size_t size) | ||
109 | { | ||
110 | u32 val; | ||
111 | |||
112 | histb_pcie_dbi_r_mode(&pci->pp, true); | ||
113 | dw_pcie_read(base + reg, size, &val); | ||
114 | histb_pcie_dbi_r_mode(&pci->pp, false); | ||
115 | |||
116 | return val; | ||
117 | } | ||
118 | |||
119 | static void histb_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base, | ||
120 | u32 reg, size_t size, u32 val) | ||
121 | { | ||
122 | histb_pcie_dbi_w_mode(&pci->pp, true); | ||
123 | dw_pcie_write(base + reg, size, val); | ||
124 | histb_pcie_dbi_w_mode(&pci->pp, false); | ||
125 | } | ||
126 | |||
127 | static int histb_pcie_rd_own_conf(struct pcie_port *pp, int where, | ||
128 | int size, u32 *val) | ||
129 | { | ||
130 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); | ||
131 | int ret; | ||
132 | |||
133 | histb_pcie_dbi_r_mode(pp, true); | ||
134 | ret = dw_pcie_read(pci->dbi_base + where, size, val); | ||
135 | histb_pcie_dbi_r_mode(pp, false); | ||
136 | |||
137 | return ret; | ||
138 | } | ||
139 | |||
140 | static int histb_pcie_wr_own_conf(struct pcie_port *pp, int where, | ||
141 | int size, u32 val) | ||
142 | { | ||
143 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); | ||
144 | int ret; | ||
145 | |||
146 | histb_pcie_dbi_w_mode(pp, true); | ||
147 | ret = dw_pcie_write(pci->dbi_base + where, size, val); | ||
148 | histb_pcie_dbi_w_mode(pp, false); | ||
149 | |||
150 | return ret; | ||
151 | } | ||
152 | |||
153 | static int histb_pcie_link_up(struct dw_pcie *pci) | ||
154 | { | ||
155 | struct histb_pcie *hipcie = to_histb_pcie(pci); | ||
156 | u32 regval; | ||
157 | u32 status; | ||
158 | |||
159 | regval = histb_pcie_readl(hipcie, PCIE_SYS_STAT0); | ||
160 | status = histb_pcie_readl(hipcie, PCIE_SYS_STAT4); | ||
161 | status &= PCIE_LTSSM_STATE_MASK; | ||
162 | if ((regval & PCIE_XMLH_LINK_UP) && (regval & PCIE_RDLH_LINK_UP) && | ||
163 | (status == PCIE_LTSSM_STATE_ACTIVE)) | ||
164 | return 1; | ||
165 | |||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | static int histb_pcie_establish_link(struct pcie_port *pp) | ||
170 | { | ||
171 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); | ||
172 | struct histb_pcie *hipcie = to_histb_pcie(pci); | ||
173 | u32 regval; | ||
174 | |||
175 | if (dw_pcie_link_up(pci)) { | ||
176 | dev_info(pci->dev, "Link already up\n"); | ||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | /* PCIe RC work mode */ | ||
181 | regval = histb_pcie_readl(hipcie, PCIE_SYS_CTRL0); | ||
182 | regval &= ~PCIE_DEVICE_TYPE_MASK; | ||
183 | regval |= PCIE_WM_RC; | ||
184 | histb_pcie_writel(hipcie, PCIE_SYS_CTRL0, regval); | ||
185 | |||
186 | /* setup root complex */ | ||
187 | dw_pcie_setup_rc(pp); | ||
188 | |||
189 | /* assert LTSSM enable */ | ||
190 | regval = histb_pcie_readl(hipcie, PCIE_SYS_CTRL7); | ||
191 | regval |= PCIE_APP_LTSSM_ENABLE; | ||
192 | histb_pcie_writel(hipcie, PCIE_SYS_CTRL7, regval); | ||
193 | |||
194 | return dw_pcie_wait_for_link(pci); | ||
195 | } | ||
196 | |||
197 | static int histb_pcie_host_init(struct pcie_port *pp) | ||
198 | { | ||
199 | histb_pcie_establish_link(pp); | ||
200 | |||
201 | if (IS_ENABLED(CONFIG_PCI_MSI)) | ||
202 | dw_pcie_msi_init(pp); | ||
203 | |||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | static struct dw_pcie_host_ops histb_pcie_host_ops = { | ||
208 | .rd_own_conf = histb_pcie_rd_own_conf, | ||
209 | .wr_own_conf = histb_pcie_wr_own_conf, | ||
210 | .host_init = histb_pcie_host_init, | ||
211 | }; | ||
212 | |||
213 | static irqreturn_t histb_pcie_msi_irq_handler(int irq, void *arg) | ||
214 | { | ||
215 | struct pcie_port *pp = arg; | ||
216 | |||
217 | return dw_handle_msi_irq(pp); | ||
218 | } | ||
219 | |||
220 | static void histb_pcie_host_disable(struct histb_pcie *hipcie) | ||
221 | { | ||
222 | reset_control_assert(hipcie->soft_reset); | ||
223 | reset_control_assert(hipcie->sys_reset); | ||
224 | reset_control_assert(hipcie->bus_reset); | ||
225 | |||
226 | clk_disable_unprepare(hipcie->aux_clk); | ||
227 | clk_disable_unprepare(hipcie->pipe_clk); | ||
228 | clk_disable_unprepare(hipcie->sys_clk); | ||
229 | clk_disable_unprepare(hipcie->bus_clk); | ||
230 | |||
231 | if (gpio_is_valid(hipcie->reset_gpio)) | ||
232 | gpio_set_value_cansleep(hipcie->reset_gpio, 0); | ||
233 | } | ||
234 | |||
235 | static int histb_pcie_host_enable(struct pcie_port *pp) | ||
236 | { | ||
237 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); | ||
238 | struct histb_pcie *hipcie = to_histb_pcie(pci); | ||
239 | struct device *dev = pci->dev; | ||
240 | int ret; | ||
241 | |||
242 | /* power on PCIe device if have */ | ||
243 | if (gpio_is_valid(hipcie->reset_gpio)) | ||
244 | gpio_set_value_cansleep(hipcie->reset_gpio, 1); | ||
245 | |||
246 | ret = clk_prepare_enable(hipcie->bus_clk); | ||
247 | if (ret) { | ||
248 | dev_err(dev, "cannot prepare/enable bus clk\n"); | ||
249 | goto err_bus_clk; | ||
250 | } | ||
251 | |||
252 | ret = clk_prepare_enable(hipcie->sys_clk); | ||
253 | if (ret) { | ||
254 | dev_err(dev, "cannot prepare/enable sys clk\n"); | ||
255 | goto err_sys_clk; | ||
256 | } | ||
257 | |||
258 | ret = clk_prepare_enable(hipcie->pipe_clk); | ||
259 | if (ret) { | ||
260 | dev_err(dev, "cannot prepare/enable pipe clk\n"); | ||
261 | goto err_pipe_clk; | ||
262 | } | ||
263 | |||
264 | ret = clk_prepare_enable(hipcie->aux_clk); | ||
265 | if (ret) { | ||
266 | dev_err(dev, "cannot prepare/enable aux clk\n"); | ||
267 | goto err_aux_clk; | ||
268 | } | ||
269 | |||
270 | reset_control_assert(hipcie->soft_reset); | ||
271 | reset_control_deassert(hipcie->soft_reset); | ||
272 | |||
273 | reset_control_assert(hipcie->sys_reset); | ||
274 | reset_control_deassert(hipcie->sys_reset); | ||
275 | |||
276 | reset_control_assert(hipcie->bus_reset); | ||
277 | reset_control_deassert(hipcie->bus_reset); | ||
278 | |||
279 | return 0; | ||
280 | |||
281 | err_aux_clk: | ||
282 | clk_disable_unprepare(hipcie->aux_clk); | ||
283 | err_pipe_clk: | ||
284 | clk_disable_unprepare(hipcie->pipe_clk); | ||
285 | err_sys_clk: | ||
286 | clk_disable_unprepare(hipcie->sys_clk); | ||
287 | err_bus_clk: | ||
288 | clk_disable_unprepare(hipcie->bus_clk); | ||
289 | |||
290 | return ret; | ||
291 | } | ||
292 | |||
293 | static const struct dw_pcie_ops dw_pcie_ops = { | ||
294 | .read_dbi = histb_pcie_read_dbi, | ||
295 | .write_dbi = histb_pcie_write_dbi, | ||
296 | .link_up = histb_pcie_link_up, | ||
297 | }; | ||
298 | |||
299 | static int histb_pcie_probe(struct platform_device *pdev) | ||
300 | { | ||
301 | struct histb_pcie *hipcie; | ||
302 | struct dw_pcie *pci; | ||
303 | struct pcie_port *pp; | ||
304 | struct resource *res; | ||
305 | struct device_node *np = pdev->dev.of_node; | ||
306 | struct device *dev = &pdev->dev; | ||
307 | enum of_gpio_flags of_flags; | ||
308 | unsigned long flag = GPIOF_DIR_OUT; | ||
309 | int ret; | ||
310 | |||
311 | hipcie = devm_kzalloc(dev, sizeof(*hipcie), GFP_KERNEL); | ||
312 | if (!hipcie) | ||
313 | return -ENOMEM; | ||
314 | |||
315 | pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL); | ||
316 | if (!pci) | ||
317 | return -ENOMEM; | ||
318 | |||
319 | hipcie->pci = pci; | ||
320 | pp = &pci->pp; | ||
321 | pci->dev = dev; | ||
322 | pci->ops = &dw_pcie_ops; | ||
323 | |||
324 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "control"); | ||
325 | hipcie->ctrl = devm_ioremap_resource(dev, res); | ||
326 | if (IS_ERR(hipcie->ctrl)) { | ||
327 | dev_err(dev, "cannot get control reg base\n"); | ||
328 | return PTR_ERR(hipcie->ctrl); | ||
329 | } | ||
330 | |||
331 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rc-dbi"); | ||
332 | pci->dbi_base = devm_ioremap_resource(dev, res); | ||
333 | if (IS_ERR(pci->dbi_base)) { | ||
334 | dev_err(dev, "cannot get rc-dbi base\n"); | ||
335 | return PTR_ERR(pci->dbi_base); | ||
336 | } | ||
337 | |||
338 | hipcie->reset_gpio = of_get_named_gpio_flags(np, | ||
339 | "reset-gpios", 0, &of_flags); | ||
340 | if (of_flags & OF_GPIO_ACTIVE_LOW) | ||
341 | flag |= GPIOF_ACTIVE_LOW; | ||
342 | if (gpio_is_valid(hipcie->reset_gpio)) { | ||
343 | ret = devm_gpio_request_one(dev, hipcie->reset_gpio, | ||
344 | flag, "PCIe device power control"); | ||
345 | if (ret) { | ||
346 | dev_err(dev, "unable to request gpio\n"); | ||
347 | return ret; | ||
348 | } | ||
349 | } | ||
350 | |||
351 | hipcie->aux_clk = devm_clk_get(dev, "aux"); | ||
352 | if (IS_ERR(hipcie->aux_clk)) { | ||
353 | dev_err(dev, "Failed to get PCIe aux clk\n"); | ||
354 | return PTR_ERR(hipcie->aux_clk); | ||
355 | } | ||
356 | |||
357 | hipcie->pipe_clk = devm_clk_get(dev, "pipe"); | ||
358 | if (IS_ERR(hipcie->pipe_clk)) { | ||
359 | dev_err(dev, "Failed to get PCIe pipe clk\n"); | ||
360 | return PTR_ERR(hipcie->pipe_clk); | ||
361 | } | ||
362 | |||
363 | hipcie->sys_clk = devm_clk_get(dev, "sys"); | ||
364 | if (IS_ERR(hipcie->sys_clk)) { | ||
365 | dev_err(dev, "Failed to get PCIEe sys clk\n"); | ||
366 | return PTR_ERR(hipcie->sys_clk); | ||
367 | } | ||
368 | |||
369 | hipcie->bus_clk = devm_clk_get(dev, "bus"); | ||
370 | if (IS_ERR(hipcie->bus_clk)) { | ||
371 | dev_err(dev, "Failed to get PCIe bus clk\n"); | ||
372 | return PTR_ERR(hipcie->bus_clk); | ||
373 | } | ||
374 | |||
375 | hipcie->soft_reset = devm_reset_control_get(dev, "soft"); | ||
376 | if (IS_ERR(hipcie->soft_reset)) { | ||
377 | dev_err(dev, "couldn't get soft reset\n"); | ||
378 | return PTR_ERR(hipcie->soft_reset); | ||
379 | } | ||
380 | |||
381 | hipcie->sys_reset = devm_reset_control_get(dev, "sys"); | ||
382 | if (IS_ERR(hipcie->sys_reset)) { | ||
383 | dev_err(dev, "couldn't get sys reset\n"); | ||
384 | return PTR_ERR(hipcie->sys_reset); | ||
385 | } | ||
386 | |||
387 | hipcie->bus_reset = devm_reset_control_get(dev, "bus"); | ||
388 | if (IS_ERR(hipcie->bus_reset)) { | ||
389 | dev_err(dev, "couldn't get bus reset\n"); | ||
390 | return PTR_ERR(hipcie->bus_reset); | ||
391 | } | ||
392 | |||
393 | if (IS_ENABLED(CONFIG_PCI_MSI)) { | ||
394 | pp->msi_irq = platform_get_irq_byname(pdev, "msi"); | ||
395 | if (pp->msi_irq < 0) { | ||
396 | dev_err(dev, "Failed to get MSI IRQ\n"); | ||
397 | return pp->msi_irq; | ||
398 | } | ||
399 | |||
400 | ret = devm_request_irq(dev, pp->msi_irq, | ||
401 | histb_pcie_msi_irq_handler, | ||
402 | IRQF_SHARED, "histb-pcie-msi", pp); | ||
403 | if (ret) { | ||
404 | dev_err(dev, "cannot request MSI IRQ\n"); | ||
405 | return ret; | ||
406 | } | ||
407 | } | ||
408 | |||
409 | hipcie->phy = devm_phy_get(dev, "phy"); | ||
410 | if (IS_ERR(hipcie->phy)) { | ||
411 | dev_info(dev, "no pcie-phy found\n"); | ||
412 | hipcie->phy = NULL; | ||
413 | /* fall through here! | ||
414 | * if no pcie-phy found, phy init | ||
415 | * should be done under boot! | ||
416 | */ | ||
417 | } else { | ||
418 | phy_init(hipcie->phy); | ||
419 | } | ||
420 | |||
421 | pp->root_bus_nr = -1; | ||
422 | pp->ops = &histb_pcie_host_ops; | ||
423 | |||
424 | platform_set_drvdata(pdev, hipcie); | ||
425 | |||
426 | ret = histb_pcie_host_enable(pp); | ||
427 | if (ret) { | ||
428 | dev_err(dev, "failed to enable host\n"); | ||
429 | return ret; | ||
430 | } | ||
431 | |||
432 | ret = dw_pcie_host_init(pp); | ||
433 | if (ret) { | ||
434 | dev_err(dev, "failed to initialize host\n"); | ||
435 | return ret; | ||
436 | } | ||
437 | |||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | static int histb_pcie_remove(struct platform_device *pdev) | ||
442 | { | ||
443 | struct histb_pcie *hipcie = platform_get_drvdata(pdev); | ||
444 | |||
445 | histb_pcie_host_disable(hipcie); | ||
446 | |||
447 | if (hipcie->phy) | ||
448 | phy_exit(hipcie->phy); | ||
449 | |||
450 | return 0; | ||
451 | } | ||
452 | |||
453 | static const struct of_device_id histb_pcie_of_match[] = { | ||
454 | { .compatible = "hisilicon,hi3798cv200-pcie", }, | ||
455 | {}, | ||
456 | }; | ||
457 | MODULE_DEVICE_TABLE(of, histb_pcie_of_match); | ||
458 | |||
459 | static struct platform_driver histb_pcie_platform_driver = { | ||
460 | .probe = histb_pcie_probe, | ||
461 | .remove = histb_pcie_remove, | ||
462 | .driver = { | ||
463 | .name = "histb-pcie", | ||
464 | .of_match_table = histb_pcie_of_match, | ||
465 | }, | ||
466 | }; | ||
467 | module_platform_driver(histb_pcie_platform_driver); | ||
468 | |||
469 | MODULE_DESCRIPTION("HiSilicon STB PCIe host controller driver"); | ||
470 | MODULE_LICENSE("GPL v2"); | ||