aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/dwc/pci-imx6.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/dwc/pci-imx6.c')
-rw-r--r--drivers/pci/dwc/pci-imx6.c72
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)
252static int imx6q_pcie_abort_handler(unsigned long addr, 254static 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
258static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) 287static 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
288static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie) 327static 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);
413err_pcie_bus: 461err_pcie_bus:
414 clk_disable_unprepare(imx6_pcie->pcie_phy); 462 clk_disable_unprepare(imx6_pcie->pcie_phy);
463err_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
417static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie) 472static 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
605static struct dw_pcie_host_ops imx6_pcie_host_ops = { 660static 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}