diff options
Diffstat (limited to 'drivers/pci/dwc/pci-imx6.c')
-rw-r--r-- | drivers/pci/dwc/pci-imx6.c | 72 |
1 files changed, 67 insertions, 5 deletions
diff --git a/drivers/pci/dwc/pci-imx6.c b/drivers/pci/dwc/pci-imx6.c index a98cba55c7f0..bf5c3616e344 100644 --- a/drivers/pci/dwc/pci-imx6.c +++ b/drivers/pci/dwc/pci-imx6.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/pci.h> | 24 | #include <linux/pci.h> |
25 | #include <linux/platform_device.h> | 25 | #include <linux/platform_device.h> |
26 | #include <linux/regmap.h> | 26 | #include <linux/regmap.h> |
27 | #include <linux/regulator/consumer.h> | ||
27 | #include <linux/resource.h> | 28 | #include <linux/resource.h> |
28 | #include <linux/signal.h> | 29 | #include <linux/signal.h> |
29 | #include <linux/types.h> | 30 | #include <linux/types.h> |
@@ -59,6 +60,7 @@ struct imx6_pcie { | |||
59 | u32 tx_swing_full; | 60 | u32 tx_swing_full; |
60 | u32 tx_swing_low; | 61 | u32 tx_swing_low; |
61 | int link_gen; | 62 | int link_gen; |
63 | struct regulator *vpcie; | ||
62 | }; | 64 | }; |
63 | 65 | ||
64 | /* Parameters for the waiting for PCIe PHY PLL to lock on i.MX7 */ | 66 | /* Parameters for the waiting for PCIe PHY PLL to lock on i.MX7 */ |
@@ -252,11 +254,40 @@ static void imx6_pcie_reset_phy(struct imx6_pcie *imx6_pcie) | |||
252 | static int imx6q_pcie_abort_handler(unsigned long addr, | 254 | static int imx6q_pcie_abort_handler(unsigned long addr, |
253 | unsigned int fsr, struct pt_regs *regs) | 255 | unsigned int fsr, struct pt_regs *regs) |
254 | { | 256 | { |
255 | return 0; | 257 | unsigned long pc = instruction_pointer(regs); |
258 | unsigned long instr = *(unsigned long *)pc; | ||
259 | int reg = (instr >> 12) & 15; | ||
260 | |||
261 | /* | ||
262 | * If the instruction being executed was a read, | ||
263 | * make it look like it read all-ones. | ||
264 | */ | ||
265 | if ((instr & 0x0c100000) == 0x04100000) { | ||
266 | unsigned long val; | ||
267 | |||
268 | if (instr & 0x00400000) | ||
269 | val = 255; | ||
270 | else | ||
271 | val = -1; | ||
272 | |||
273 | regs->uregs[reg] = val; | ||
274 | regs->ARM_pc += 4; | ||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | if ((instr & 0x0e100090) == 0x00100090) { | ||
279 | regs->uregs[reg] = -1; | ||
280 | regs->ARM_pc += 4; | ||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | return 1; | ||
256 | } | 285 | } |
257 | 286 | ||
258 | static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) | 287 | static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) |
259 | { | 288 | { |
289 | struct device *dev = imx6_pcie->pci->dev; | ||
290 | |||
260 | switch (imx6_pcie->variant) { | 291 | switch (imx6_pcie->variant) { |
261 | case IMX7D: | 292 | case IMX7D: |
262 | reset_control_assert(imx6_pcie->pciephy_reset); | 293 | reset_control_assert(imx6_pcie->pciephy_reset); |
@@ -283,6 +314,14 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) | |||
283 | IMX6Q_GPR1_PCIE_REF_CLK_EN, 0 << 16); | 314 | IMX6Q_GPR1_PCIE_REF_CLK_EN, 0 << 16); |
284 | break; | 315 | break; |
285 | } | 316 | } |
317 | |||
318 | if (imx6_pcie->vpcie && regulator_is_enabled(imx6_pcie->vpcie) > 0) { | ||
319 | int ret = regulator_disable(imx6_pcie->vpcie); | ||
320 | |||
321 | if (ret) | ||
322 | dev_err(dev, "failed to disable vpcie regulator: %d\n", | ||
323 | ret); | ||
324 | } | ||
286 | } | 325 | } |
287 | 326 | ||
288 | static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie) | 327 | static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie) |
@@ -349,10 +388,19 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) | |||
349 | struct device *dev = pci->dev; | 388 | struct device *dev = pci->dev; |
350 | int ret; | 389 | int ret; |
351 | 390 | ||
391 | if (imx6_pcie->vpcie && !regulator_is_enabled(imx6_pcie->vpcie)) { | ||
392 | ret = regulator_enable(imx6_pcie->vpcie); | ||
393 | if (ret) { | ||
394 | dev_err(dev, "failed to enable vpcie regulator: %d\n", | ||
395 | ret); | ||
396 | return; | ||
397 | } | ||
398 | } | ||
399 | |||
352 | ret = clk_prepare_enable(imx6_pcie->pcie_phy); | 400 | ret = clk_prepare_enable(imx6_pcie->pcie_phy); |
353 | if (ret) { | 401 | if (ret) { |
354 | dev_err(dev, "unable to enable pcie_phy clock\n"); | 402 | dev_err(dev, "unable to enable pcie_phy clock\n"); |
355 | return; | 403 | goto err_pcie_phy; |
356 | } | 404 | } |
357 | 405 | ||
358 | ret = clk_prepare_enable(imx6_pcie->pcie_bus); | 406 | ret = clk_prepare_enable(imx6_pcie->pcie_bus); |
@@ -412,6 +460,13 @@ err_pcie: | |||
412 | clk_disable_unprepare(imx6_pcie->pcie_bus); | 460 | clk_disable_unprepare(imx6_pcie->pcie_bus); |
413 | err_pcie_bus: | 461 | err_pcie_bus: |
414 | clk_disable_unprepare(imx6_pcie->pcie_phy); | 462 | clk_disable_unprepare(imx6_pcie->pcie_phy); |
463 | err_pcie_phy: | ||
464 | if (imx6_pcie->vpcie && regulator_is_enabled(imx6_pcie->vpcie) > 0) { | ||
465 | ret = regulator_disable(imx6_pcie->vpcie); | ||
466 | if (ret) | ||
467 | dev_err(dev, "failed to disable vpcie regulator: %d\n", | ||
468 | ret); | ||
469 | } | ||
415 | } | 470 | } |
416 | 471 | ||
417 | static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie) | 472 | static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie) |
@@ -602,7 +657,7 @@ static int imx6_pcie_link_up(struct dw_pcie *pci) | |||
602 | PCIE_PHY_DEBUG_R1_XMLH_LINK_UP; | 657 | PCIE_PHY_DEBUG_R1_XMLH_LINK_UP; |
603 | } | 658 | } |
604 | 659 | ||
605 | static struct dw_pcie_host_ops imx6_pcie_host_ops = { | 660 | static const struct dw_pcie_host_ops imx6_pcie_host_ops = { |
606 | .host_init = imx6_pcie_host_init, | 661 | .host_init = imx6_pcie_host_init, |
607 | }; | 662 | }; |
608 | 663 | ||
@@ -775,6 +830,13 @@ static int imx6_pcie_probe(struct platform_device *pdev) | |||
775 | if (ret) | 830 | if (ret) |
776 | imx6_pcie->link_gen = 1; | 831 | imx6_pcie->link_gen = 1; |
777 | 832 | ||
833 | imx6_pcie->vpcie = devm_regulator_get_optional(&pdev->dev, "vpcie"); | ||
834 | if (IS_ERR(imx6_pcie->vpcie)) { | ||
835 | if (PTR_ERR(imx6_pcie->vpcie) == -EPROBE_DEFER) | ||
836 | return -EPROBE_DEFER; | ||
837 | imx6_pcie->vpcie = NULL; | ||
838 | } | ||
839 | |||
778 | platform_set_drvdata(pdev, imx6_pcie); | 840 | platform_set_drvdata(pdev, imx6_pcie); |
779 | 841 | ||
780 | ret = imx6_add_pcie_port(imx6_pcie, pdev); | 842 | ret = imx6_add_pcie_port(imx6_pcie, pdev); |
@@ -819,8 +881,8 @@ static int __init imx6_pcie_init(void) | |||
819 | * we can install the handler here without risking it | 881 | * we can install the handler here without risking it |
820 | * accessing some uninitialized driver state. | 882 | * accessing some uninitialized driver state. |
821 | */ | 883 | */ |
822 | hook_fault_code(16 + 6, imx6q_pcie_abort_handler, SIGBUS, 0, | 884 | hook_fault_code(8, imx6q_pcie_abort_handler, SIGBUS, 0, |
823 | "imprecise external abort"); | 885 | "external abort on non-linefetch"); |
824 | 886 | ||
825 | return platform_driver_register(&imx6_pcie_driver); | 887 | return platform_driver_register(&imx6_pcie_driver); |
826 | } | 888 | } |