Message ID | 20240803-qps615-v2-7-9560b7c71369@quicinc.com |
---|---|
State | New |
Headers | show |
Series | PCI: Enable Power and configure the QPS615 PCIe switch | expand |
On Sat, Aug 03, 2024 at 08:52:53AM +0530, Krishna chaitanya chundru wrote: > For the switches like QPS615 which needs to configure it before > the PCIe link is established. > > if the link is not up assert the PERST# and disable LTSSM bit so > that PCIe controller will not participate in the link training > as part of host_stop_link(). > > De-assert the PERST# and enable LTSSM bit back in host_start_link(). > > Introduce ltssm_disable function op to stop the link training. pcie-qcom.c is a driver for a PCIe host controller. Apparently QPS615 is a switch in a hierarchy that could be below any PCIe host controller, so I'm missing the connection with pcie-qcom.c. Does this fix a problem that only occurs with pcie-qcom.c? What happens if you put a QPS615 below some other controller? > Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com> > --- > drivers/pci/controller/dwc/pcie-qcom.c | 39 ++++++++++++++++++++++++++++++++++ > 1 file changed, 39 insertions(+) > > diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c > index 0180edf3310e..f4a6df53139c 100644 > --- a/drivers/pci/controller/dwc/pcie-qcom.c > +++ b/drivers/pci/controller/dwc/pcie-qcom.c > @@ -233,6 +233,7 @@ struct qcom_pcie_ops { > void (*host_post_init)(struct qcom_pcie *pcie); > void (*deinit)(struct qcom_pcie *pcie); > void (*ltssm_enable)(struct qcom_pcie *pcie); > + void (*ltssm_disable)(struct qcom_pcie *pcie); > int (*config_sid)(struct qcom_pcie *pcie); > }; > > @@ -555,6 +556,41 @@ static int qcom_pcie_post_init_1_0_0(struct qcom_pcie *pcie) > return 0; > } > > +static int qcom_pcie_host_start_link(struct dw_pcie *pci) > +{ > + struct qcom_pcie *pcie = to_qcom_pcie(pci); > + > + if (!dw_pcie_link_up(pcie->pci)) { > + qcom_ep_reset_deassert(pcie); > + > + if (pcie->cfg->ops->ltssm_enable) > + pcie->cfg->ops->ltssm_enable(pcie); > + } > + > + return 0; > +} > + > +static void qcom_pcie_host_stop_link(struct dw_pcie *pci) > +{ > + struct qcom_pcie *pcie = to_qcom_pcie(pci); > + > + if (!dw_pcie_link_up(pcie->pci)) { > + qcom_ep_reset_assert(pcie); > + > + if (pcie->cfg->ops->ltssm_disable) > + pcie->cfg->ops->ltssm_disable(pcie); > + } > +} > + > +static void qcom_pcie_2_3_2_ltssm_disable(struct qcom_pcie *pcie) > +{ > + u32 val; > + > + val = readl(pcie->parf + PARF_LTSSM); > + val &= ~LTSSM_EN; > + writel(val, pcie->parf + PARF_LTSSM); > +} > + > static void qcom_pcie_2_3_2_ltssm_enable(struct qcom_pcie *pcie) > { > u32 val; > @@ -1306,6 +1342,7 @@ static const struct qcom_pcie_ops ops_1_9_0 = { > .host_post_init = qcom_pcie_host_post_init_2_7_0, > .deinit = qcom_pcie_deinit_2_7_0, > .ltssm_enable = qcom_pcie_2_3_2_ltssm_enable, > + .ltssm_disable = qcom_pcie_2_3_2_ltssm_disable, > .config_sid = qcom_pcie_config_sid_1_9_0, > }; > > @@ -1363,6 +1400,8 @@ static const struct qcom_pcie_cfg cfg_sc8280xp = { > static const struct dw_pcie_ops dw_pcie_ops = { > .link_up = qcom_pcie_link_up, > .start_link = qcom_pcie_start_link, > + .host_start_link = qcom_pcie_host_start_link, > + .host_stop_link = qcom_pcie_host_stop_link, > }; > > static int qcom_pcie_icc_init(struct qcom_pcie *pcie) > > -- > 2.34.1 >
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 0180edf3310e..f4a6df53139c 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -233,6 +233,7 @@ struct qcom_pcie_ops { void (*host_post_init)(struct qcom_pcie *pcie); void (*deinit)(struct qcom_pcie *pcie); void (*ltssm_enable)(struct qcom_pcie *pcie); + void (*ltssm_disable)(struct qcom_pcie *pcie); int (*config_sid)(struct qcom_pcie *pcie); }; @@ -555,6 +556,41 @@ static int qcom_pcie_post_init_1_0_0(struct qcom_pcie *pcie) return 0; } +static int qcom_pcie_host_start_link(struct dw_pcie *pci) +{ + struct qcom_pcie *pcie = to_qcom_pcie(pci); + + if (!dw_pcie_link_up(pcie->pci)) { + qcom_ep_reset_deassert(pcie); + + if (pcie->cfg->ops->ltssm_enable) + pcie->cfg->ops->ltssm_enable(pcie); + } + + return 0; +} + +static void qcom_pcie_host_stop_link(struct dw_pcie *pci) +{ + struct qcom_pcie *pcie = to_qcom_pcie(pci); + + if (!dw_pcie_link_up(pcie->pci)) { + qcom_ep_reset_assert(pcie); + + if (pcie->cfg->ops->ltssm_disable) + pcie->cfg->ops->ltssm_disable(pcie); + } +} + +static void qcom_pcie_2_3_2_ltssm_disable(struct qcom_pcie *pcie) +{ + u32 val; + + val = readl(pcie->parf + PARF_LTSSM); + val &= ~LTSSM_EN; + writel(val, pcie->parf + PARF_LTSSM); +} + static void qcom_pcie_2_3_2_ltssm_enable(struct qcom_pcie *pcie) { u32 val; @@ -1306,6 +1342,7 @@ static const struct qcom_pcie_ops ops_1_9_0 = { .host_post_init = qcom_pcie_host_post_init_2_7_0, .deinit = qcom_pcie_deinit_2_7_0, .ltssm_enable = qcom_pcie_2_3_2_ltssm_enable, + .ltssm_disable = qcom_pcie_2_3_2_ltssm_disable, .config_sid = qcom_pcie_config_sid_1_9_0, }; @@ -1363,6 +1400,8 @@ static const struct qcom_pcie_cfg cfg_sc8280xp = { static const struct dw_pcie_ops dw_pcie_ops = { .link_up = qcom_pcie_link_up, .start_link = qcom_pcie_start_link, + .host_start_link = qcom_pcie_host_start_link, + .host_stop_link = qcom_pcie_host_stop_link, }; static int qcom_pcie_icc_init(struct qcom_pcie *pcie)
For the switches like QPS615 which needs to configure it before the PCIe link is established. if the link is not up assert the PERST# and disable LTSSM bit so that PCIe controller will not participate in the link training as part of host_stop_link(). De-assert the PERST# and enable LTSSM bit back in host_start_link(). Introduce ltssm_disable function op to stop the link training. Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com> --- drivers/pci/controller/dwc/pcie-qcom.c | 39 ++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+)