From: Kevin.xie Date: Thu, 13 Oct 2022 02:53:59 +0000 (+0800) Subject: drivers: pci: Support runtime pm & release when found empty slot in probe. X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d38610f5403cb4dfc6674249d382a70f3559c563;p=platform%2Fkernel%2Flinux-starfive.git drivers: pci: Support runtime pm & release when found empty slot in probe. Used PLDA link up/down status in probe to indicate the slot situations. Signed-off-by: Kevin.xie --- diff --git a/arch/riscv/boot/dts/starfive/jh7110-common.dtsi b/arch/riscv/boot/dts/starfive/jh7110-common.dtsi index 50d926d887ee..14c35acd8f4e 100644 --- a/arch/riscv/boot/dts/starfive/jh7110-common.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110-common.dtsi @@ -586,18 +586,20 @@ }; &pcie0 { - pinctrl-names = "perst-default", "perst-active", "power-active"; + pinctrl-names = "perst-default", "perst-active", "power-default", "power-active"; pinctrl-0 = <&pcie0_perst_default>; pinctrl-1 = <&pcie0_perst_active>; - pinctrl-2 = <&pcie0_power_active>; + pinctrl-2 = <&pcie0_power_default>; + pinctrl-3 = <&pcie0_power_active>; status = "disabled"; }; &pcie1 { - pinctrl-names = "perst-default", "perst-active", "power-active"; + pinctrl-names = "perst-default", "perst-active", "power-default", "power-active"; pinctrl-0 = <&pcie1_perst_default>; pinctrl-1 = <&pcie1_perst_active>; - pinctrl-2 = <&pcie1_power_active>; + pinctrl-2 = <&pcie1_power_default>; + pinctrl-3 = <&pcie1_power_active>; status = "disabled"; }; diff --git a/arch/riscv/boot/dts/starfive/jh7110-evb-pinctrl.dtsi b/arch/riscv/boot/dts/starfive/jh7110-evb-pinctrl.dtsi index f5df4f7eb5e9..507a536edaff 100644 --- a/arch/riscv/boot/dts/starfive/jh7110-evb-pinctrl.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110-evb-pinctrl.dtsi @@ -1335,6 +1335,16 @@ }; }; + pcie0_power_default: pcie0_power_default { + power-pins { + starfive,pins = ; + starfive,pinmux = ; + starfive,pin-ioconfig = ; + starfive,pin-gpio-dout = ; + starfive,pin-gpio-doen = ; + }; + }; + pcie0_power_active: pcie0_power_active { power-pins { starfive,pins = ; @@ -1365,6 +1375,16 @@ }; }; + pcie1_power_default: pcie1_power_default { + power-pins { + starfive,pins = ; + starfive,pinmux = ; + starfive,pin-ioconfig = ; + starfive,pin-gpio-dout = ; + starfive,pin-gpio-doen = ; + }; + }; + pcie1_power_active: pcie1_power_active { power-pins { starfive,pins = ; diff --git a/arch/riscv/boot/dts/starfive/jh7110.dtsi b/arch/riscv/boot/dts/starfive/jh7110.dtsi index fa591d0225ca..fdb4a7e05ffe 100644 --- a/arch/riscv/boot/dts/starfive/jh7110.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi @@ -1512,7 +1512,7 @@ 0x9 0x40000000 0x0 0x10000000>; reg-names = "reg", "config"; device_type = "pci"; - starfive,stg-syscon = <&stg_syscon 0xc0 0xc4 0x130>; + starfive,stg-syscon = <&stg_syscon 0xc0 0xc4 0x130 0x1b8>; bus-range = <0x0 0xff>; ranges = <0x82000000 0x0 0x30000000 0x0 0x30000000 0x0 0x08000000>, <0xc3000000 0x9 0x00000000 0x9 0x00000000 0x0 0x40000000>; @@ -1551,7 +1551,7 @@ 0x9 0xc0000000 0x0 0x10000000>; reg-names = "reg", "config"; device_type = "pci"; - starfive,stg-syscon = <&stg_syscon 0x270 0x274 0x2e0>; + starfive,stg-syscon = <&stg_syscon 0x270 0x274 0x2e0 0x368>; bus-range = <0x0 0xff>; ranges = <0x82000000 0x0 0x38000000 0x0 0x38000000 0x0 0x08000000>, <0xc3000000 0x9 0x80000000 0x9 0x80000000 0x0 0x40000000>; diff --git a/drivers/pci/controller/pcie-plda.c b/drivers/pci/controller/pcie-plda.c index 92794b819fdd..213808ed958c 100644 --- a/drivers/pci/controller/pcie-plda.c +++ b/drivers/pci/controller/pcie-plda.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,10 @@ #define PLDA_EP_ENABLE 0 #define PLDA_RP_ENABLE 1 +#define PLDA_LINK_UP 1 +#define PLDA_LINK_DOWN 0 + +#define PLDA_DATA_LINK_ACTIVE BIT(5) #define PREF_MEM_WIN_64_SUPPORT BIT(3) #define PMSG_LTR_SUPPORT BIT(2) #define PDLA_LINK_SPEED_GEN2 BIT(12) @@ -139,6 +144,7 @@ struct plda_pcie { u32 stg_arfun; u32 stg_awfun; u32 stg_rp_nep; + u32 stg_lnksta; int irq; struct irq_domain *legacy_irq_domain; struct pci_host_bridge *bridge; @@ -150,6 +156,7 @@ struct plda_pcie { struct pinctrl *pinctrl; struct pinctrl_state *perst_state_def; struct pinctrl_state *perst_state_active; + struct pinctrl_state *power_state_def; struct pinctrl_state *power_state_active; }; @@ -593,7 +600,7 @@ static int plda_pcie_parse_dt(struct plda_pcie *pcie) } ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, - "starfive,stg-syscon", 3, 0, &args); + "starfive,stg-syscon", 4, 0, &args); if (ret < 0) { dev_err(&pdev->dev, "Failed to parse starfive,stg-syscon\n"); return -EINVAL; @@ -607,6 +614,7 @@ static int plda_pcie_parse_dt(struct plda_pcie *pcie) pcie->stg_arfun = args.args[0]; pcie->stg_awfun = args.args[1]; pcie->stg_rp_nep = args.args[2]; + pcie->stg_lnksta = args.args[3]; /* Clear all interrupts */ plda_writel(pcie, 0xffffffff, ISTATUS_LOCAL); @@ -734,10 +742,17 @@ int plda_pinctrl_init(struct plda_pcie *pcie) return -EINVAL; } + pcie->power_state_def + = pinctrl_lookup_state(pcie->pinctrl, "power-default"); + if (IS_ERR_OR_NULL(pcie->power_state_def)) { + dev_err(dev, "Failed to get the power-default pinctrl handle\n"); + return -EINVAL; + } + pcie->power_state_active = pinctrl_lookup_state(pcie->pinctrl, "power-active"); if (IS_ERR_OR_NULL(pcie->power_state_active)) { - dev_err(dev, "Failed to get the power-default pinctrl handle\n"); + dev_err(dev, "Failed to get the power-active pinctrl handle\n"); return -EINVAL; } @@ -828,7 +843,32 @@ static void plda_pcie_hw_init(struct plda_pcie *pcie) if (ret) dev_err(dev, "Cannot set reset pin to high\n"); } +} + +static int plda_pcie_is_link_up(struct plda_pcie *pcie) +{ + struct device *dev = &pcie->pdev->dev; + int ret; + u32 stg_reg_val; + + /* 100ms timeout value should be enough for Gen1/2 training */ + ret = regmap_read_poll_timeout(pcie->reg_syscon, + pcie->stg_lnksta, + stg_reg_val, + stg_reg_val & PLDA_DATA_LINK_ACTIVE, + 10 * 1000, 100 * 1000); + + /* If the link is down (no device in slot), then exit. */ + if (ret == -ETIMEDOUT) { + dev_info(dev, "Port link down, exit.\n"); + return PLDA_LINK_DOWN; + } else if (ret == 0) { + dev_info(dev, "Port link up.\n"); + return PLDA_LINK_UP; + } + dev_warn(dev, "Read stg_linksta failed.\n"); + return ret; } static int plda_pcie_probe(struct platform_device *pdev) @@ -893,6 +933,9 @@ static int plda_pcie_probe(struct platform_device *pdev) goto exit; } + pm_runtime_enable(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); + /* Set default bus ops */ bridge->ops = &plda_pcie_ops; bridge->sysdata = pcie; @@ -900,20 +943,40 @@ static int plda_pcie_probe(struct platform_device *pdev) plda_pcie_hw_init(pcie); + if (plda_pcie_is_link_up(pcie) == PLDA_LINK_DOWN) + goto release; + ret = pci_host_probe(bridge); if (ret < 0) { dev_err(&pdev->dev, "Failed to pci host probe: %d\n", ret); - goto exit; + goto release; } if (IS_ENABLED(CONFIG_PCI_MSI)) { ret = plda_pcie_enable_msi(pcie, bus); - if (ret < 0) + if (ret < 0) { dev_err(&pdev->dev, "Failed to enable MSI support: %d\n", ret); + goto release; + } } exit: return ret; + +release: + if (pcie->power_state_def && + pinctrl_select_state(pcie->pinctrl, pcie->power_state_def)) + dev_err(dev, "Cannot set power pin to low\n"); + plda_clk_rst_deinit(pcie); + + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + pci_free_host_bridge(pcie->bridge); + devm_kfree(&pdev->dev, pcie); + platform_set_drvdata(pdev, NULL); + + return ret; } static int plda_pcie_remove(struct platform_device *pdev) @@ -927,7 +990,6 @@ static int plda_pcie_remove(struct platform_device *pdev) return 0; } - static const struct of_device_id plda_pcie_of_match[] = { { .compatible = "plda,pci-xpressrich3-axi"}, { .compatible = "starfive,jh7110-pcie"},