Add a API for dwc suspend/resume.
In layerscape platform call this api.
Frank Li (4):
PCI: layerscape: Add function pointer for exit_from_l2()
PCI: layerscape: Add suspend/resume for ls1021a
PCI: layerscape: Rename pf_* as pf_lut_*
PCI: layerscape: Add suspend/resume for ls1043a
drivers/pci/controller/dwc/pci-layerscape.c | 191 +++++++++++++++++---
1 file changed, 170 insertions(+), 21 deletions(-)
--
2.34.1
Since difference SoCs require different sequence for exiting L2, let's add
a separate "exit_from_l2()" callback. This callback can be used to execute
SoC specific sequence.
Change ls_pcie_exit_from_l2() return value from void to int. Return error
if exit_from_l2() failure at exit resume flow.
Reviewed-by: Manivannan Sadhasivam <[email protected]>
Signed-off-by: Frank Li <[email protected]>
---
Notes:
Change from v3 to v4
- update commit message
Add mani's review by tag
Change from v2 to v3
- fixed according to mani's feedback
1. update commit message
2. move dw_pcie_host_ops to next patch
3. check return value from exit_from_l2()
Change from v1 to v2
- change subject 'a' to 'A'
Change from v1 to v2
- change subject 'a' to 'A'
drivers/pci/controller/dwc/pci-layerscape.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c
index 37956e09c65bd..aea89926bcc4f 100644
--- a/drivers/pci/controller/dwc/pci-layerscape.c
+++ b/drivers/pci/controller/dwc/pci-layerscape.c
@@ -39,6 +39,7 @@
struct ls_pcie_drvdata {
const u32 pf_off;
+ int (*exit_from_l2)(struct dw_pcie_rp *pp);
bool pm_support;
};
@@ -125,7 +126,7 @@ static void ls_pcie_send_turnoff_msg(struct dw_pcie_rp *pp)
dev_err(pcie->pci->dev, "PME_Turn_off timeout\n");
}
-static void ls_pcie_exit_from_l2(struct dw_pcie_rp *pp)
+static int ls_pcie_exit_from_l2(struct dw_pcie_rp *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct ls_pcie *pcie = to_ls_pcie(pci);
@@ -150,6 +151,8 @@ static void ls_pcie_exit_from_l2(struct dw_pcie_rp *pp)
10000);
if (ret)
dev_err(pcie->pci->dev, "L2 exit timeout\n");
+
+ return ret;
}
static int ls_pcie_host_init(struct dw_pcie_rp *pp)
@@ -180,6 +183,7 @@ static const struct ls_pcie_drvdata ls1021a_drvdata = {
static const struct ls_pcie_drvdata layerscape_drvdata = {
.pf_off = 0xc0000,
.pm_support = true,
+ .exit_from_l2 = ls_pcie_exit_from_l2,
};
static const struct of_device_id ls_pcie_of_match[] = {
@@ -247,11 +251,14 @@ static int ls_pcie_suspend_noirq(struct device *dev)
static int ls_pcie_resume_noirq(struct device *dev)
{
struct ls_pcie *pcie = dev_get_drvdata(dev);
+ int ret;
if (!pcie->drvdata->pm_support)
return 0;
- ls_pcie_exit_from_l2(&pcie->pci->pp);
+ ret = pcie->drvdata->exit_from_l2(&pcie->pci->pp);
+ if (ret)
+ return ret;
return dw_pcie_resume_noirq(pcie->pci);
}
--
2.34.1
'pf' and 'lut' is just difference name in difference chips, but basic it is
a MMIO base address plus an offset.
Rename it to avoid duplicate pf_* and lut_* in driver.
Signed-off-by: Frank Li <[email protected]>
---
Notes:
pf_lut is better than pf_* or lut* because some chip use 'pf', some chip
use 'lut'.
change from v1 to v4
- new patch at v3
drivers/pci/controller/dwc/pci-layerscape.c | 34 ++++++++++-----------
1 file changed, 17 insertions(+), 17 deletions(-)
diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c
index 42bca2c3b5c3e..590e07bb27002 100644
--- a/drivers/pci/controller/dwc/pci-layerscape.c
+++ b/drivers/pci/controller/dwc/pci-layerscape.c
@@ -44,7 +44,7 @@
#define PCIE_IATU_NUM 6
struct ls_pcie_drvdata {
- const u32 pf_off;
+ const u32 pf_lut_off;
const struct dw_pcie_host_ops *ops;
int (*exit_from_l2)(struct dw_pcie_rp *pp);
bool scfg_support;
@@ -54,13 +54,13 @@ struct ls_pcie_drvdata {
struct ls_pcie {
struct dw_pcie *pci;
const struct ls_pcie_drvdata *drvdata;
- void __iomem *pf_base;
+ void __iomem *pf_lut_base;
struct regmap *scfg;
int index;
bool big_endian;
};
-#define ls_pcie_pf_readl_addr(addr) ls_pcie_pf_readl(pcie, addr)
+#define ls_pcie_pf_lut_readl_addr(addr) ls_pcie_pf_lut_readl(pcie, addr)
#define to_ls_pcie(x) dev_get_drvdata((x)->dev)
static bool ls_pcie_is_bridge(struct ls_pcie *pcie)
@@ -101,20 +101,20 @@ static void ls_pcie_fix_error_response(struct ls_pcie *pcie)
iowrite32(PCIE_ABSERR_SETTING, pci->dbi_base + PCIE_ABSERR);
}
-static u32 ls_pcie_pf_readl(struct ls_pcie *pcie, u32 off)
+static u32 ls_pcie_pf_lut_readl(struct ls_pcie *pcie, u32 off)
{
if (pcie->big_endian)
- return ioread32be(pcie->pf_base + off);
+ return ioread32be(pcie->pf_lut_base + off);
- return ioread32(pcie->pf_base + off);
+ return ioread32(pcie->pf_lut_base + off);
}
-static void ls_pcie_pf_writel(struct ls_pcie *pcie, u32 off, u32 val)
+static void ls_pcie_pf_lut_writel(struct ls_pcie *pcie, u32 off, u32 val)
{
if (pcie->big_endian)
- iowrite32be(val, pcie->pf_base + off);
+ iowrite32be(val, pcie->pf_lut_base + off);
else
- iowrite32(val, pcie->pf_base + off);
+ iowrite32(val, pcie->pf_lut_base + off);
}
static void ls_pcie_send_turnoff_msg(struct dw_pcie_rp *pp)
@@ -124,11 +124,11 @@ static void ls_pcie_send_turnoff_msg(struct dw_pcie_rp *pp)
u32 val;
int ret;
- val = ls_pcie_pf_readl(pcie, LS_PCIE_PF_MCR);
+ val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_PF_MCR);
val |= PF_MCR_PTOMR;
- ls_pcie_pf_writel(pcie, LS_PCIE_PF_MCR, val);
+ ls_pcie_pf_lut_writel(pcie, LS_PCIE_PF_MCR, val);
- ret = readx_poll_timeout(ls_pcie_pf_readl_addr, LS_PCIE_PF_MCR,
+ ret = readx_poll_timeout(ls_pcie_pf_lut_readl_addr, LS_PCIE_PF_MCR,
val, !(val & PF_MCR_PTOMR),
PCIE_PME_TO_L2_TIMEOUT_US/10,
PCIE_PME_TO_L2_TIMEOUT_US);
@@ -147,15 +147,15 @@ static int ls_pcie_exit_from_l2(struct dw_pcie_rp *pp)
* Set PF_MCR_EXL2S bit in LS_PCIE_PF_MCR register for the link
* to exit L2 state.
*/
- val = ls_pcie_pf_readl(pcie, LS_PCIE_PF_MCR);
+ val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_PF_MCR);
val |= PF_MCR_EXL2S;
- ls_pcie_pf_writel(pcie, LS_PCIE_PF_MCR, val);
+ ls_pcie_pf_lut_writel(pcie, LS_PCIE_PF_MCR, val);
/*
* L2 exit timeout of 10ms is not defined in the specifications,
* it was chosen based on empirical observations.
*/
- ret = readx_poll_timeout(ls_pcie_pf_readl_addr, LS_PCIE_PF_MCR,
+ ret = readx_poll_timeout(ls_pcie_pf_lut_readl_addr, LS_PCIE_PF_MCR,
val, !(val & PF_MCR_EXL2S),
1000,
10000);
@@ -243,7 +243,7 @@ static const struct ls_pcie_drvdata ls1021a_drvdata = {
};
static const struct ls_pcie_drvdata layerscape_drvdata = {
- .pf_off = 0xc0000,
+ .pf_lut_off = 0xc0000,
.pm_support = true,
.exit_from_l2 = ls_pcie_exit_from_l2,
};
@@ -293,7 +293,7 @@ static int ls_pcie_probe(struct platform_device *pdev)
pcie->big_endian = of_property_read_bool(dev->of_node, "big-endian");
- pcie->pf_base = pci->dbi_base + pcie->drvdata->pf_off;
+ pcie->pf_lut_base = pci->dbi_base + pcie->drvdata->pf_lut_off;
if (pcie->drvdata->scfg_support) {
pcie->scfg = syscon_regmap_lookup_by_phandle(dev->of_node, "fsl,pcie-scfg");
--
2.34.1
ls1021a add suspend/resume support.
In the suspend path, PME_Turn_Off message is sent to the endpoint to
transition the link to L2/L3_Ready state. In this SoC, there is no way to
check if the controller has received the PME_To_Ack from the endpoint or
not. So to be on the safer side, the driver just waits for
PCIE_PME_TO_L2_TIMEOUT_US before asserting the SoC specific PMXMTTURNOFF
bit to complete the PME_Turn_Off handshake. This link would then enter
L2/L3 state depending on the VAUX supply.
In the resume path, the link is brought back from L2 to L0 by doing a
software reset.
Signed-off-by: Frank Li <[email protected]>
---
Notes:
Change from v3 to v4
- update commit message.
- it is reset a glue logic part for PCI controller.
- use regmap_write_bits() to reduce code change.
Change from v2 to v3
- update according to mani's feedback
change from v1 to v2
- change subject 'a' to 'A'
drivers/pci/controller/dwc/pci-layerscape.c | 83 ++++++++++++++++++++-
1 file changed, 82 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c
index aea89926bcc4f..42bca2c3b5c3e 100644
--- a/drivers/pci/controller/dwc/pci-layerscape.c
+++ b/drivers/pci/controller/dwc/pci-layerscape.c
@@ -35,11 +35,19 @@
#define PF_MCR_PTOMR BIT(0)
#define PF_MCR_EXL2S BIT(1)
+/* LS1021A PEXn PM Write Control Register */
+#define SCFG_PEXPMWRCR(idx) (0x5c + (idx) * 0x64)
+#define PMXMTTURNOFF BIT(31)
+#define SCFG_PEXSFTRSTCR 0x190
+#define PEXSR(idx) BIT(idx)
+
#define PCIE_IATU_NUM 6
struct ls_pcie_drvdata {
const u32 pf_off;
+ const struct dw_pcie_host_ops *ops;
int (*exit_from_l2)(struct dw_pcie_rp *pp);
+ bool scfg_support;
bool pm_support;
};
@@ -47,6 +55,8 @@ struct ls_pcie {
struct dw_pcie *pci;
const struct ls_pcie_drvdata *drvdata;
void __iomem *pf_base;
+ struct regmap *scfg;
+ int index;
bool big_endian;
};
@@ -171,13 +181,65 @@ static int ls_pcie_host_init(struct dw_pcie_rp *pp)
return 0;
}
+static void scfg_pcie_send_turnoff_msg(struct regmap *scfg, u32 reg, u32 mask)
+{
+ /* Send PME_Turn_Off message */
+ regmap_write_bits(scfg, reg, mask, mask);
+
+ /*
+ * There is no specific register to check for PME_To_Ack from endpoint.
+ * So on the safe side, wait for PCIE_PME_TO_L2_TIMEOUT_US.
+ */
+ mdelay(PCIE_PME_TO_L2_TIMEOUT_US/1000);
+
+ /*
+ * Layerscape hardware reference manual recommends clearing the PMXMTTURNOFF bit
+ * to complete the PME_Turn_Off handshake.
+ */
+ regmap_write_bits(scfg, reg, mask, 0);
+}
+
+static void ls1021a_pcie_send_turnoff_msg(struct dw_pcie_rp *pp)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct ls_pcie *pcie = to_ls_pcie(pci);
+
+ scfg_pcie_send_turnoff_msg(pcie->scfg, SCFG_PEXPMWRCR(pcie->index), PMXMTTURNOFF);
+}
+
+static int scfg_pcie_exit_from_l2(struct regmap *scfg, u32 reg, u32 mask)
+{
+ /* Only way exit from l2 is that do software reset */
+ regmap_write_bits(scfg, reg, mask, mask);
+
+ regmap_write_bits(scfg, reg, mask, 0);
+
+ return 0;
+}
+
+static int ls1021a_pcie_exit_from_l2(struct dw_pcie_rp *pp)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct ls_pcie *pcie = to_ls_pcie(pci);
+
+ return scfg_pcie_exit_from_l2(pcie->scfg, SCFG_PEXSFTRSTCR, PEXSR(pcie->index));
+}
+
static const struct dw_pcie_host_ops ls_pcie_host_ops = {
.host_init = ls_pcie_host_init,
.pme_turn_off = ls_pcie_send_turnoff_msg,
};
+static const struct dw_pcie_host_ops ls1021a_pcie_host_ops = {
+ .host_init = ls_pcie_host_init,
+ .pme_turn_off = ls1021a_pcie_send_turnoff_msg,
+};
+
static const struct ls_pcie_drvdata ls1021a_drvdata = {
- .pm_support = false,
+ .pm_support = true,
+ .scfg_support = true,
+ .ops = &ls1021a_pcie_host_ops,
+ .exit_from_l2 = ls1021a_pcie_exit_from_l2,
};
static const struct ls_pcie_drvdata layerscape_drvdata = {
@@ -205,6 +267,8 @@ static int ls_pcie_probe(struct platform_device *pdev)
struct dw_pcie *pci;
struct ls_pcie *pcie;
struct resource *dbi_base;
+ u32 index[2];
+ int ret;
pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
if (!pcie)
@@ -220,6 +284,7 @@ static int ls_pcie_probe(struct platform_device *pdev)
pci->pp.ops = &ls_pcie_host_ops;
pcie->pci = pci;
+ pci->pp.ops = pcie->drvdata->ops ? pcie->drvdata->ops : &ls_pcie_host_ops;
dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base);
@@ -230,6 +295,22 @@ static int ls_pcie_probe(struct platform_device *pdev)
pcie->pf_base = pci->dbi_base + pcie->drvdata->pf_off;
+ if (pcie->drvdata->scfg_support) {
+ pcie->scfg = syscon_regmap_lookup_by_phandle(dev->of_node, "fsl,pcie-scfg");
+ if (IS_ERR(pcie->scfg)) {
+ dev_err(dev, "No syscfg phandle specified\n");
+ return PTR_ERR(pcie->scfg);
+ }
+
+ ret = of_property_read_u32_array(dev->of_node, "fsl,pcie-scfg", index, 2);
+ if (ret) {
+ pcie->scfg = NULL;
+ return ret;
+ }
+
+ pcie->index = index[1];
+ }
+
if (!ls_pcie_is_bridge(pcie))
return -ENODEV;
--
2.34.1
In the suspend path, PME_Turn_Off message is sent to the endpoint to
transition the link to L2/L3_Ready state. In this SoC, there is no way to
check if the controller has received the PME_To_Ack from the endpoint or
not. So to be on the safer side, the driver just waits for
PCIE_PME_TO_L2_TIMEOUT_US before asserting the SoC specific PMXMTTURNOFF
bit to complete the PME_Turn_Off handshake. This link would then enter
L2/L3 state depending on the VAUX supply.
In the resume path, the link is brought back from L2 to L0 by doing a
software reset.
Signed-off-by: Frank Li <[email protected]>
---
Notes:
Change from v3 to v4
- Call scfg_pcie_send_turnoff_msg() shared with ls1021a
- update commit message
Change from v2 to v3
- Remove ls_pcie_lut_readl(writel) function
Change from v1 to v2
- Update subject 'a' to 'A'
drivers/pci/controller/dwc/pci-layerscape.c | 63 ++++++++++++++++++++-
1 file changed, 62 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c
index 590e07bb27002..d39700b3afaaa 100644
--- a/drivers/pci/controller/dwc/pci-layerscape.c
+++ b/drivers/pci/controller/dwc/pci-layerscape.c
@@ -41,6 +41,15 @@
#define SCFG_PEXSFTRSTCR 0x190
#define PEXSR(idx) BIT(idx)
+/* LS1043A PEX PME control register */
+#define SCFG_PEXPMECR 0x144
+#define PEXPME(idx) BIT(31 - (idx) * 4)
+
+/* LS1043A PEX LUT debug register */
+#define LS_PCIE_LDBG 0x7fc
+#define LDBG_SR BIT(30)
+#define LDBG_WE BIT(31)
+
#define PCIE_IATU_NUM 6
struct ls_pcie_drvdata {
@@ -225,6 +234,45 @@ static int ls1021a_pcie_exit_from_l2(struct dw_pcie_rp *pp)
return scfg_pcie_exit_from_l2(pcie->scfg, SCFG_PEXSFTRSTCR, PEXSR(pcie->index));
}
+static void ls1043a_pcie_send_turnoff_msg(struct dw_pcie_rp *pp)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct ls_pcie *pcie = to_ls_pcie(pci);
+
+ scfg_pcie_send_turnoff_msg(pcie->scfg, SCFG_PEXPMECR, PEXPME(pcie->index));
+}
+
+static int ls1043a_pcie_exit_from_l2(struct dw_pcie_rp *pp)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct ls_pcie *pcie = to_ls_pcie(pci);
+ u32 val;
+
+ /*
+ * Only way let PEX module exit L2 is do a software reset.
+ * LDBG_WE: allows the user to have write access to the PEXDBG[SR] for both setting and
+ * clearing the soft reset on the PEX module.
+ * LDBG_SR: When SR is set to 1, the PEX module enters soft reset.
+ */
+ val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
+ val |= LDBG_WE;
+ ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
+
+ val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
+ val |= LDBG_SR;
+ ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
+
+ val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
+ val &= ~LDBG_SR;
+ ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
+
+ val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
+ val &= ~LDBG_WE;
+ ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
+
+ return 0;
+}
+
static const struct dw_pcie_host_ops ls_pcie_host_ops = {
.host_init = ls_pcie_host_init,
.pme_turn_off = ls_pcie_send_turnoff_msg,
@@ -242,6 +290,19 @@ static const struct ls_pcie_drvdata ls1021a_drvdata = {
.exit_from_l2 = ls1021a_pcie_exit_from_l2,
};
+static const struct dw_pcie_host_ops ls1043a_pcie_host_ops = {
+ .host_init = ls_pcie_host_init,
+ .pme_turn_off = ls1043a_pcie_send_turnoff_msg,
+};
+
+static const struct ls_pcie_drvdata ls1043a_drvdata = {
+ .pf_lut_off = 0x10000,
+ .pm_support = true,
+ .scfg_support = true,
+ .ops = &ls1043a_pcie_host_ops,
+ .exit_from_l2 = ls1043a_pcie_exit_from_l2,
+};
+
static const struct ls_pcie_drvdata layerscape_drvdata = {
.pf_lut_off = 0xc0000,
.pm_support = true,
@@ -252,7 +313,7 @@ static const struct of_device_id ls_pcie_of_match[] = {
{ .compatible = "fsl,ls1012a-pcie", .data = &layerscape_drvdata },
{ .compatible = "fsl,ls1021a-pcie", .data = &ls1021a_drvdata },
{ .compatible = "fsl,ls1028a-pcie", .data = &layerscape_drvdata },
- { .compatible = "fsl,ls1043a-pcie", .data = &ls1021a_drvdata },
+ { .compatible = "fsl,ls1043a-pcie", .data = &ls1043a_drvdata },
{ .compatible = "fsl,ls1046a-pcie", .data = &layerscape_drvdata },
{ .compatible = "fsl,ls2080a-pcie", .data = &layerscape_drvdata },
{ .compatible = "fsl,ls2085a-pcie", .data = &layerscape_drvdata },
--
2.34.1
On Wed, Nov 29, 2023 at 04:44:10PM -0500, Frank Li wrote:
> ls1021a add suspend/resume support.
>
"Add suspend/resume support for Layerscape LS1021a"
> In the suspend path, PME_Turn_Off message is sent to the endpoint to
> transition the link to L2/L3_Ready state. In this SoC, there is no way to
> check if the controller has received the PME_To_Ack from the endpoint or
> not. So to be on the safer side, the driver just waits for
> PCIE_PME_TO_L2_TIMEOUT_US before asserting the SoC specific PMXMTTURNOFF
> bit to complete the PME_Turn_Off handshake. This link would then enter
"Then the link would enter L2/L3 state depending on the VAUX supply."
> L2/L3 state depending on the VAUX supply.
>
> In the resume path, the link is brought back from L2 to L0 by doing a
> software reset.
>
> Signed-off-by: Frank Li <[email protected]>
Couple of comments below. But the patch is looking good now. Thanks for the
update.
> ---
>
> Notes:
> Change from v3 to v4
> - update commit message.
> - it is reset a glue logic part for PCI controller.
> - use regmap_write_bits() to reduce code change.
>
> Change from v2 to v3
> - update according to mani's feedback
> change from v1 to v2
> - change subject 'a' to 'A'
>
> drivers/pci/controller/dwc/pci-layerscape.c | 83 ++++++++++++++++++++-
> 1 file changed, 82 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c
> index aea89926bcc4f..42bca2c3b5c3e 100644
> --- a/drivers/pci/controller/dwc/pci-layerscape.c
> +++ b/drivers/pci/controller/dwc/pci-layerscape.c
> @@ -35,11 +35,19 @@
> #define PF_MCR_PTOMR BIT(0)
> #define PF_MCR_EXL2S BIT(1)
>
> +/* LS1021A PEXn PM Write Control Register */
> +#define SCFG_PEXPMWRCR(idx) (0x5c + (idx) * 0x64)
> +#define PMXMTTURNOFF BIT(31)
> +#define SCFG_PEXSFTRSTCR 0x190
> +#define PEXSR(idx) BIT(idx)
> +
> #define PCIE_IATU_NUM 6
>
> struct ls_pcie_drvdata {
> const u32 pf_off;
> + const struct dw_pcie_host_ops *ops;
> int (*exit_from_l2)(struct dw_pcie_rp *pp);
> + bool scfg_support;
> bool pm_support;
> };
>
> @@ -47,6 +55,8 @@ struct ls_pcie {
> struct dw_pcie *pci;
> const struct ls_pcie_drvdata *drvdata;
> void __iomem *pf_base;
> + struct regmap *scfg;
> + int index;
> bool big_endian;
> };
>
> @@ -171,13 +181,65 @@ static int ls_pcie_host_init(struct dw_pcie_rp *pp)
> return 0;
> }
>
> +static void scfg_pcie_send_turnoff_msg(struct regmap *scfg, u32 reg, u32 mask)
> +{
> + /* Send PME_Turn_Off message */
> + regmap_write_bits(scfg, reg, mask, mask);
> +
> + /*
> + * There is no specific register to check for PME_To_Ack from endpoint.
> + * So on the safe side, wait for PCIE_PME_TO_L2_TIMEOUT_US.
> + */
> + mdelay(PCIE_PME_TO_L2_TIMEOUT_US/1000);
> +
> + /*
> + * Layerscape hardware reference manual recommends clearing the PMXMTTURNOFF bit
> + * to complete the PME_Turn_Off handshake.
> + */
> + regmap_write_bits(scfg, reg, mask, 0);
> +}
> +
> +static void ls1021a_pcie_send_turnoff_msg(struct dw_pcie_rp *pp)
> +{
> + struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> + struct ls_pcie *pcie = to_ls_pcie(pci);
> +
> + scfg_pcie_send_turnoff_msg(pcie->scfg, SCFG_PEXPMWRCR(pcie->index), PMXMTTURNOFF);
> +}
> +
> +static int scfg_pcie_exit_from_l2(struct regmap *scfg, u32 reg, u32 mask)
> +{
> + /* Only way exit from l2 is that do software reset */
"Only way exit from L2 is by doing a software reset of the controller"
I really hope that the reset is not a global controller reset i.e., not
resetting all CSRs.
> + regmap_write_bits(scfg, reg, mask, mask);
> +
No need of a newline.
> + regmap_write_bits(scfg, reg, mask, 0);
> +
> + return 0;
> +}
> +
> +static int ls1021a_pcie_exit_from_l2(struct dw_pcie_rp *pp)
> +{
> + struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> + struct ls_pcie *pcie = to_ls_pcie(pci);
> +
> + return scfg_pcie_exit_from_l2(pcie->scfg, SCFG_PEXSFTRSTCR, PEXSR(pcie->index));
> +}
> +
> static const struct dw_pcie_host_ops ls_pcie_host_ops = {
> .host_init = ls_pcie_host_init,
> .pme_turn_off = ls_pcie_send_turnoff_msg,
> };
>
> +static const struct dw_pcie_host_ops ls1021a_pcie_host_ops = {
> + .host_init = ls_pcie_host_init,
> + .pme_turn_off = ls1021a_pcie_send_turnoff_msg,
> +};
> +
> static const struct ls_pcie_drvdata ls1021a_drvdata = {
> - .pm_support = false,
> + .pm_support = true,
> + .scfg_support = true,
> + .ops = &ls1021a_pcie_host_ops,
> + .exit_from_l2 = ls1021a_pcie_exit_from_l2,
> };
>
> static const struct ls_pcie_drvdata layerscape_drvdata = {
> @@ -205,6 +267,8 @@ static int ls_pcie_probe(struct platform_device *pdev)
> struct dw_pcie *pci;
> struct ls_pcie *pcie;
> struct resource *dbi_base;
> + u32 index[2];
> + int ret;
>
> pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
> if (!pcie)
> @@ -220,6 +284,7 @@ static int ls_pcie_probe(struct platform_device *pdev)
> pci->pp.ops = &ls_pcie_host_ops;
>
> pcie->pci = pci;
> + pci->pp.ops = pcie->drvdata->ops ? pcie->drvdata->ops : &ls_pcie_host_ops;
pp.ops is already assigned to &ls_pcie_host_ops above. But I think for
consistency, you should pass ls_pcie_host_ops to the "ops" member of
layerscape_drvdata and just use:
pci->pp.ops = pcie->drvdata->ops;
It looks a lot cleaner.
>
> dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
> pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base);
> @@ -230,6 +295,22 @@ static int ls_pcie_probe(struct platform_device *pdev)
>
> pcie->pf_base = pci->dbi_base + pcie->drvdata->pf_off;
>
> + if (pcie->drvdata->scfg_support) {
> + pcie->scfg = syscon_regmap_lookup_by_phandle(dev->of_node, "fsl,pcie-scfg");
> + if (IS_ERR(pcie->scfg)) {
> + dev_err(dev, "No syscfg phandle specified\n");
> + return PTR_ERR(pcie->scfg);
> + }
> +
> + ret = of_property_read_u32_array(dev->of_node, "fsl,pcie-scfg", index, 2);
> + if (ret) {
> + pcie->scfg = NULL;
No need to set it to NULL in the case of probe failure.
- Mani
--
மணிவண்ணன் சதாசிவம்
On Wed, Nov 29, 2023 at 04:44:11PM -0500, Frank Li wrote:
> 'pf' and 'lut' is just difference name in difference chips, but basic it is
> a MMIO base address plus an offset.
>
> Rename it to avoid duplicate pf_* and lut_* in driver.
>
> Signed-off-by: Frank Li <[email protected]>
Reviewed-by: Manivannan Sadhasivam <[email protected]>
Can you fix the name in pci-layerscape-ep.c also?
- Mani
> ---
>
> Notes:
> pf_lut is better than pf_* or lut* because some chip use 'pf', some chip
> use 'lut'.
>
> change from v1 to v4
> - new patch at v3
>
> drivers/pci/controller/dwc/pci-layerscape.c | 34 ++++++++++-----------
> 1 file changed, 17 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c
> index 42bca2c3b5c3e..590e07bb27002 100644
> --- a/drivers/pci/controller/dwc/pci-layerscape.c
> +++ b/drivers/pci/controller/dwc/pci-layerscape.c
> @@ -44,7 +44,7 @@
> #define PCIE_IATU_NUM 6
>
> struct ls_pcie_drvdata {
> - const u32 pf_off;
> + const u32 pf_lut_off;
> const struct dw_pcie_host_ops *ops;
> int (*exit_from_l2)(struct dw_pcie_rp *pp);
> bool scfg_support;
> @@ -54,13 +54,13 @@ struct ls_pcie_drvdata {
> struct ls_pcie {
> struct dw_pcie *pci;
> const struct ls_pcie_drvdata *drvdata;
> - void __iomem *pf_base;
> + void __iomem *pf_lut_base;
> struct regmap *scfg;
> int index;
> bool big_endian;
> };
>
> -#define ls_pcie_pf_readl_addr(addr) ls_pcie_pf_readl(pcie, addr)
> +#define ls_pcie_pf_lut_readl_addr(addr) ls_pcie_pf_lut_readl(pcie, addr)
> #define to_ls_pcie(x) dev_get_drvdata((x)->dev)
>
> static bool ls_pcie_is_bridge(struct ls_pcie *pcie)
> @@ -101,20 +101,20 @@ static void ls_pcie_fix_error_response(struct ls_pcie *pcie)
> iowrite32(PCIE_ABSERR_SETTING, pci->dbi_base + PCIE_ABSERR);
> }
>
> -static u32 ls_pcie_pf_readl(struct ls_pcie *pcie, u32 off)
> +static u32 ls_pcie_pf_lut_readl(struct ls_pcie *pcie, u32 off)
> {
> if (pcie->big_endian)
> - return ioread32be(pcie->pf_base + off);
> + return ioread32be(pcie->pf_lut_base + off);
>
> - return ioread32(pcie->pf_base + off);
> + return ioread32(pcie->pf_lut_base + off);
> }
>
> -static void ls_pcie_pf_writel(struct ls_pcie *pcie, u32 off, u32 val)
> +static void ls_pcie_pf_lut_writel(struct ls_pcie *pcie, u32 off, u32 val)
> {
> if (pcie->big_endian)
> - iowrite32be(val, pcie->pf_base + off);
> + iowrite32be(val, pcie->pf_lut_base + off);
> else
> - iowrite32(val, pcie->pf_base + off);
> + iowrite32(val, pcie->pf_lut_base + off);
> }
>
> static void ls_pcie_send_turnoff_msg(struct dw_pcie_rp *pp)
> @@ -124,11 +124,11 @@ static void ls_pcie_send_turnoff_msg(struct dw_pcie_rp *pp)
> u32 val;
> int ret;
>
> - val = ls_pcie_pf_readl(pcie, LS_PCIE_PF_MCR);
> + val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_PF_MCR);
> val |= PF_MCR_PTOMR;
> - ls_pcie_pf_writel(pcie, LS_PCIE_PF_MCR, val);
> + ls_pcie_pf_lut_writel(pcie, LS_PCIE_PF_MCR, val);
>
> - ret = readx_poll_timeout(ls_pcie_pf_readl_addr, LS_PCIE_PF_MCR,
> + ret = readx_poll_timeout(ls_pcie_pf_lut_readl_addr, LS_PCIE_PF_MCR,
> val, !(val & PF_MCR_PTOMR),
> PCIE_PME_TO_L2_TIMEOUT_US/10,
> PCIE_PME_TO_L2_TIMEOUT_US);
> @@ -147,15 +147,15 @@ static int ls_pcie_exit_from_l2(struct dw_pcie_rp *pp)
> * Set PF_MCR_EXL2S bit in LS_PCIE_PF_MCR register for the link
> * to exit L2 state.
> */
> - val = ls_pcie_pf_readl(pcie, LS_PCIE_PF_MCR);
> + val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_PF_MCR);
> val |= PF_MCR_EXL2S;
> - ls_pcie_pf_writel(pcie, LS_PCIE_PF_MCR, val);
> + ls_pcie_pf_lut_writel(pcie, LS_PCIE_PF_MCR, val);
>
> /*
> * L2 exit timeout of 10ms is not defined in the specifications,
> * it was chosen based on empirical observations.
> */
> - ret = readx_poll_timeout(ls_pcie_pf_readl_addr, LS_PCIE_PF_MCR,
> + ret = readx_poll_timeout(ls_pcie_pf_lut_readl_addr, LS_PCIE_PF_MCR,
> val, !(val & PF_MCR_EXL2S),
> 1000,
> 10000);
> @@ -243,7 +243,7 @@ static const struct ls_pcie_drvdata ls1021a_drvdata = {
> };
>
> static const struct ls_pcie_drvdata layerscape_drvdata = {
> - .pf_off = 0xc0000,
> + .pf_lut_off = 0xc0000,
> .pm_support = true,
> .exit_from_l2 = ls_pcie_exit_from_l2,
> };
> @@ -293,7 +293,7 @@ static int ls_pcie_probe(struct platform_device *pdev)
>
> pcie->big_endian = of_property_read_bool(dev->of_node, "big-endian");
>
> - pcie->pf_base = pci->dbi_base + pcie->drvdata->pf_off;
> + pcie->pf_lut_base = pci->dbi_base + pcie->drvdata->pf_lut_off;
>
> if (pcie->drvdata->scfg_support) {
> pcie->scfg = syscon_regmap_lookup_by_phandle(dev->of_node, "fsl,pcie-scfg");
> --
> 2.34.1
>
--
மணிவண்ணன் சதாசிவம்
On Wed, Nov 29, 2023 at 04:44:12PM -0500, Frank Li wrote:
> In the suspend path, PME_Turn_Off message is sent to the endpoint to
> transition the link to L2/L3_Ready state. In this SoC, there is no way to
> check if the controller has received the PME_To_Ack from the endpoint or
> not. So to be on the safer side, the driver just waits for
> PCIE_PME_TO_L2_TIMEOUT_US before asserting the SoC specific PMXMTTURNOFF
> bit to complete the PME_Turn_Off handshake. This link would then enter
> L2/L3 state depending on the VAUX supply.
>
> In the resume path, the link is brought back from L2 to L0 by doing a
> software reset.
>
Same comment on the patch description as on patch 2/4.
> Signed-off-by: Frank Li <[email protected]>
> ---
>
> Notes:
> Change from v3 to v4
> - Call scfg_pcie_send_turnoff_msg() shared with ls1021a
> - update commit message
>
> Change from v2 to v3
> - Remove ls_pcie_lut_readl(writel) function
>
> Change from v1 to v2
> - Update subject 'a' to 'A'
>
> drivers/pci/controller/dwc/pci-layerscape.c | 63 ++++++++++++++++++++-
> 1 file changed, 62 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c
> index 590e07bb27002..d39700b3afaaa 100644
> --- a/drivers/pci/controller/dwc/pci-layerscape.c
> +++ b/drivers/pci/controller/dwc/pci-layerscape.c
> @@ -41,6 +41,15 @@
> #define SCFG_PEXSFTRSTCR 0x190
> #define PEXSR(idx) BIT(idx)
>
> +/* LS1043A PEX PME control register */
> +#define SCFG_PEXPMECR 0x144
> +#define PEXPME(idx) BIT(31 - (idx) * 4)
> +
> +/* LS1043A PEX LUT debug register */
> +#define LS_PCIE_LDBG 0x7fc
> +#define LDBG_SR BIT(30)
> +#define LDBG_WE BIT(31)
> +
> #define PCIE_IATU_NUM 6
>
> struct ls_pcie_drvdata {
> @@ -225,6 +234,45 @@ static int ls1021a_pcie_exit_from_l2(struct dw_pcie_rp *pp)
> return scfg_pcie_exit_from_l2(pcie->scfg, SCFG_PEXSFTRSTCR, PEXSR(pcie->index));
> }
>
> +static void ls1043a_pcie_send_turnoff_msg(struct dw_pcie_rp *pp)
> +{
> + struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> + struct ls_pcie *pcie = to_ls_pcie(pci);
> +
> + scfg_pcie_send_turnoff_msg(pcie->scfg, SCFG_PEXPMECR, PEXPME(pcie->index));
> +}
> +
> +static int ls1043a_pcie_exit_from_l2(struct dw_pcie_rp *pp)
> +{
> + struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> + struct ls_pcie *pcie = to_ls_pcie(pci);
> + u32 val;
> +
> + /*
> + * Only way let PEX module exit L2 is do a software reset.
Can you expand PEX? What is it used for?
Also if the reset is only for the PEX module, please use the same comment in
both patches 2 and 4. Patch 2 doesn't mention PEX in the comment.
- Mani
> + * LDBG_WE: allows the user to have write access to the PEXDBG[SR] for both setting and
> + * clearing the soft reset on the PEX module.
> + * LDBG_SR: When SR is set to 1, the PEX module enters soft reset.
> + */
> + val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
> + val |= LDBG_WE;
> + ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
> +
> + val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
> + val |= LDBG_SR;
> + ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
> +
> + val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
> + val &= ~LDBG_SR;
> + ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
> +
> + val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
> + val &= ~LDBG_WE;
> + ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
> +
> + return 0;
> +}
> +
> static const struct dw_pcie_host_ops ls_pcie_host_ops = {
> .host_init = ls_pcie_host_init,
> .pme_turn_off = ls_pcie_send_turnoff_msg,
> @@ -242,6 +290,19 @@ static const struct ls_pcie_drvdata ls1021a_drvdata = {
> .exit_from_l2 = ls1021a_pcie_exit_from_l2,
> };
>
> +static const struct dw_pcie_host_ops ls1043a_pcie_host_ops = {
> + .host_init = ls_pcie_host_init,
> + .pme_turn_off = ls1043a_pcie_send_turnoff_msg,
> +};
> +
> +static const struct ls_pcie_drvdata ls1043a_drvdata = {
> + .pf_lut_off = 0x10000,
> + .pm_support = true,
> + .scfg_support = true,
> + .ops = &ls1043a_pcie_host_ops,
> + .exit_from_l2 = ls1043a_pcie_exit_from_l2,
> +};
> +
> static const struct ls_pcie_drvdata layerscape_drvdata = {
> .pf_lut_off = 0xc0000,
> .pm_support = true,
> @@ -252,7 +313,7 @@ static const struct of_device_id ls_pcie_of_match[] = {
> { .compatible = "fsl,ls1012a-pcie", .data = &layerscape_drvdata },
> { .compatible = "fsl,ls1021a-pcie", .data = &ls1021a_drvdata },
> { .compatible = "fsl,ls1028a-pcie", .data = &layerscape_drvdata },
> - { .compatible = "fsl,ls1043a-pcie", .data = &ls1021a_drvdata },
> + { .compatible = "fsl,ls1043a-pcie", .data = &ls1043a_drvdata },
> { .compatible = "fsl,ls1046a-pcie", .data = &layerscape_drvdata },
> { .compatible = "fsl,ls2080a-pcie", .data = &layerscape_drvdata },
> { .compatible = "fsl,ls2085a-pcie", .data = &layerscape_drvdata },
> --
> 2.34.1
>
--
மணிவண்ணன் சதாசிவம்
On Thu, Nov 30, 2023 at 10:21:00PM +0530, Manivannan Sadhasivam wrote:
> On Wed, Nov 29, 2023 at 04:44:12PM -0500, Frank Li wrote:
> > In the suspend path, PME_Turn_Off message is sent to the endpoint to
> > transition the link to L2/L3_Ready state. In this SoC, there is no way to
> > check if the controller has received the PME_To_Ack from the endpoint or
> > not. So to be on the safer side, the driver just waits for
> > PCIE_PME_TO_L2_TIMEOUT_US before asserting the SoC specific PMXMTTURNOFF
> > bit to complete the PME_Turn_Off handshake. This link would then enter
> > L2/L3 state depending on the VAUX supply.
> >
> > In the resume path, the link is brought back from L2 to L0 by doing a
> > software reset.
> >
>
> Same comment on the patch description as on patch 2/4.
>
> > Signed-off-by: Frank Li <[email protected]>
> > ---
> >
> > Notes:
> > Change from v3 to v4
> > - Call scfg_pcie_send_turnoff_msg() shared with ls1021a
> > - update commit message
> >
> > Change from v2 to v3
> > - Remove ls_pcie_lut_readl(writel) function
> >
> > Change from v1 to v2
> > - Update subject 'a' to 'A'
> >
> > drivers/pci/controller/dwc/pci-layerscape.c | 63 ++++++++++++++++++++-
> > 1 file changed, 62 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c
> > index 590e07bb27002..d39700b3afaaa 100644
> > --- a/drivers/pci/controller/dwc/pci-layerscape.c
> > +++ b/drivers/pci/controller/dwc/pci-layerscape.c
> > @@ -41,6 +41,15 @@
> > #define SCFG_PEXSFTRSTCR 0x190
> > #define PEXSR(idx) BIT(idx)
> >
> > +/* LS1043A PEX PME control register */
> > +#define SCFG_PEXPMECR 0x144
> > +#define PEXPME(idx) BIT(31 - (idx) * 4)
> > +
> > +/* LS1043A PEX LUT debug register */
> > +#define LS_PCIE_LDBG 0x7fc
> > +#define LDBG_SR BIT(30)
> > +#define LDBG_WE BIT(31)
> > +
> > #define PCIE_IATU_NUM 6
> >
> > struct ls_pcie_drvdata {
> > @@ -225,6 +234,45 @@ static int ls1021a_pcie_exit_from_l2(struct dw_pcie_rp *pp)
> > return scfg_pcie_exit_from_l2(pcie->scfg, SCFG_PEXSFTRSTCR, PEXSR(pcie->index));
> > }
> >
> > +static void ls1043a_pcie_send_turnoff_msg(struct dw_pcie_rp *pp)
> > +{
> > + struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> > + struct ls_pcie *pcie = to_ls_pcie(pci);
> > +
> > + scfg_pcie_send_turnoff_msg(pcie->scfg, SCFG_PEXPMECR, PEXPME(pcie->index));
> > +}
> > +
> > +static int ls1043a_pcie_exit_from_l2(struct dw_pcie_rp *pp)
> > +{
> > + struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> > + struct ls_pcie *pcie = to_ls_pcie(pci);
> > + u32 val;
> > +
> > + /*
> > + * Only way let PEX module exit L2 is do a software reset.
>
> Can you expand PEX? What is it used for?
>
> Also if the reset is only for the PEX module, please use the same comment in
> both patches 2 and 4. Patch 2 doesn't mention PEX in the comment.
After read spec again, I think PEX is pci express. So it should software
reset controller. I don't know what exactly did in the chip. But without
below code, PCIe can't exit L2/L3.
Any harmful if dwc controller reset? Anyway these code works well with
intel network card.
Frank
>
> - Mani
>
> > + * LDBG_WE: allows the user to have write access to the PEXDBG[SR] for both setting and
> > + * clearing the soft reset on the PEX module.
> > + * LDBG_SR: When SR is set to 1, the PEX module enters soft reset.
> > + */
> > + val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
> > + val |= LDBG_WE;
> > + ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
> > +
> > + val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
> > + val |= LDBG_SR;
> > + ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
> > +
> > + val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
> > + val &= ~LDBG_SR;
> > + ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
> > +
> > + val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
> > + val &= ~LDBG_WE;
> > + ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
> > +
> > + return 0;
> > +}
> > +
> > static const struct dw_pcie_host_ops ls_pcie_host_ops = {
> > .host_init = ls_pcie_host_init,
> > .pme_turn_off = ls_pcie_send_turnoff_msg,
> > @@ -242,6 +290,19 @@ static const struct ls_pcie_drvdata ls1021a_drvdata = {
> > .exit_from_l2 = ls1021a_pcie_exit_from_l2,
> > };
> >
> > +static const struct dw_pcie_host_ops ls1043a_pcie_host_ops = {
> > + .host_init = ls_pcie_host_init,
> > + .pme_turn_off = ls1043a_pcie_send_turnoff_msg,
> > +};
> > +
> > +static const struct ls_pcie_drvdata ls1043a_drvdata = {
> > + .pf_lut_off = 0x10000,
> > + .pm_support = true,
> > + .scfg_support = true,
> > + .ops = &ls1043a_pcie_host_ops,
> > + .exit_from_l2 = ls1043a_pcie_exit_from_l2,
> > +};
> > +
> > static const struct ls_pcie_drvdata layerscape_drvdata = {
> > .pf_lut_off = 0xc0000,
> > .pm_support = true,
> > @@ -252,7 +313,7 @@ static const struct of_device_id ls_pcie_of_match[] = {
> > { .compatible = "fsl,ls1012a-pcie", .data = &layerscape_drvdata },
> > { .compatible = "fsl,ls1021a-pcie", .data = &ls1021a_drvdata },
> > { .compatible = "fsl,ls1028a-pcie", .data = &layerscape_drvdata },
> > - { .compatible = "fsl,ls1043a-pcie", .data = &ls1021a_drvdata },
> > + { .compatible = "fsl,ls1043a-pcie", .data = &ls1043a_drvdata },
> > { .compatible = "fsl,ls1046a-pcie", .data = &layerscape_drvdata },
> > { .compatible = "fsl,ls2080a-pcie", .data = &layerscape_drvdata },
> > { .compatible = "fsl,ls2085a-pcie", .data = &layerscape_drvdata },
> > --
> > 2.34.1
> >
>
> --
> மணிவண்ணன் சதாசிவம்
On Thu, Nov 30, 2023 at 03:17:39PM -0500, Frank Li wrote:
> On Thu, Nov 30, 2023 at 10:21:00PM +0530, Manivannan Sadhasivam wrote:
> > On Wed, Nov 29, 2023 at 04:44:12PM -0500, Frank Li wrote:
> > > In the suspend path, PME_Turn_Off message is sent to the endpoint to
> > > transition the link to L2/L3_Ready state. In this SoC, there is no way to
> > > check if the controller has received the PME_To_Ack from the endpoint or
> > > not. So to be on the safer side, the driver just waits for
> > > PCIE_PME_TO_L2_TIMEOUT_US before asserting the SoC specific PMXMTTURNOFF
> > > bit to complete the PME_Turn_Off handshake. This link would then enter
> > > L2/L3 state depending on the VAUX supply.
> > >
> > > In the resume path, the link is brought back from L2 to L0 by doing a
> > > software reset.
> > >
> >
> > Same comment on the patch description as on patch 2/4.
> >
> > > Signed-off-by: Frank Li <[email protected]>
> > > ---
> > >
> > > Notes:
> > > Change from v3 to v4
> > > - Call scfg_pcie_send_turnoff_msg() shared with ls1021a
> > > - update commit message
> > >
> > > Change from v2 to v3
> > > - Remove ls_pcie_lut_readl(writel) function
> > >
> > > Change from v1 to v2
> > > - Update subject 'a' to 'A'
> > >
> > > drivers/pci/controller/dwc/pci-layerscape.c | 63 ++++++++++++++++++++-
> > > 1 file changed, 62 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c
> > > index 590e07bb27002..d39700b3afaaa 100644
> > > --- a/drivers/pci/controller/dwc/pci-layerscape.c
> > > +++ b/drivers/pci/controller/dwc/pci-layerscape.c
> > > @@ -41,6 +41,15 @@
> > > #define SCFG_PEXSFTRSTCR 0x190
> > > #define PEXSR(idx) BIT(idx)
> > >
> > > +/* LS1043A PEX PME control register */
> > > +#define SCFG_PEXPMECR 0x144
> > > +#define PEXPME(idx) BIT(31 - (idx) * 4)
> > > +
> > > +/* LS1043A PEX LUT debug register */
> > > +#define LS_PCIE_LDBG 0x7fc
> > > +#define LDBG_SR BIT(30)
> > > +#define LDBG_WE BIT(31)
> > > +
> > > #define PCIE_IATU_NUM 6
> > >
> > > struct ls_pcie_drvdata {
> > > @@ -225,6 +234,45 @@ static int ls1021a_pcie_exit_from_l2(struct dw_pcie_rp *pp)
> > > return scfg_pcie_exit_from_l2(pcie->scfg, SCFG_PEXSFTRSTCR, PEXSR(pcie->index));
> > > }
> > >
> > > +static void ls1043a_pcie_send_turnoff_msg(struct dw_pcie_rp *pp)
> > > +{
> > > + struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> > > + struct ls_pcie *pcie = to_ls_pcie(pci);
> > > +
> > > + scfg_pcie_send_turnoff_msg(pcie->scfg, SCFG_PEXPMECR, PEXPME(pcie->index));
> > > +}
> > > +
> > > +static int ls1043a_pcie_exit_from_l2(struct dw_pcie_rp *pp)
> > > +{
> > > + struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> > > + struct ls_pcie *pcie = to_ls_pcie(pci);
> > > + u32 val;
> > > +
> > > + /*
> > > + * Only way let PEX module exit L2 is do a software reset.
> >
> > Can you expand PEX? What is it used for?
> >
> > Also if the reset is only for the PEX module, please use the same comment in
> > both patches 2 and 4. Patch 2 doesn't mention PEX in the comment.
>
> After read spec again, I think PEX is pci express. So it should software
> reset controller. I don't know what exactly did in the chip. But without
> below code, PCIe can't exit L2/L3.
>
> Any harmful if dwc controller reset? Anyway these code works well with
> intel network card.
Sorry, sent too quick. It is PCIe express wrapper
Copy from spec:
"PEXLDBG[SR]. Once set the
PEXLDBG[SR] will enable the soft reset to the PEX wrapper."
Frank
>
> Frank
>
> >
> > - Mani
> >
> > > + * LDBG_WE: allows the user to have write access to the PEXDBG[SR] for both setting and
> > > + * clearing the soft reset on the PEX module.
> > > + * LDBG_SR: When SR is set to 1, the PEX module enters soft reset.
> > > + */
> > > + val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
> > > + val |= LDBG_WE;
> > > + ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
> > > +
> > > + val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
> > > + val |= LDBG_SR;
> > > + ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
> > > +
> > > + val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
> > > + val &= ~LDBG_SR;
> > > + ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
> > > +
> > > + val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
> > > + val &= ~LDBG_WE;
> > > + ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
> > > +
> > > + return 0;
> > > +}
> > > +
> > > static const struct dw_pcie_host_ops ls_pcie_host_ops = {
> > > .host_init = ls_pcie_host_init,
> > > .pme_turn_off = ls_pcie_send_turnoff_msg,
> > > @@ -242,6 +290,19 @@ static const struct ls_pcie_drvdata ls1021a_drvdata = {
> > > .exit_from_l2 = ls1021a_pcie_exit_from_l2,
> > > };
> > >
> > > +static const struct dw_pcie_host_ops ls1043a_pcie_host_ops = {
> > > + .host_init = ls_pcie_host_init,
> > > + .pme_turn_off = ls1043a_pcie_send_turnoff_msg,
> > > +};
> > > +
> > > +static const struct ls_pcie_drvdata ls1043a_drvdata = {
> > > + .pf_lut_off = 0x10000,
> > > + .pm_support = true,
> > > + .scfg_support = true,
> > > + .ops = &ls1043a_pcie_host_ops,
> > > + .exit_from_l2 = ls1043a_pcie_exit_from_l2,
> > > +};
> > > +
> > > static const struct ls_pcie_drvdata layerscape_drvdata = {
> > > .pf_lut_off = 0xc0000,
> > > .pm_support = true,
> > > @@ -252,7 +313,7 @@ static const struct of_device_id ls_pcie_of_match[] = {
> > > { .compatible = "fsl,ls1012a-pcie", .data = &layerscape_drvdata },
> > > { .compatible = "fsl,ls1021a-pcie", .data = &ls1021a_drvdata },
> > > { .compatible = "fsl,ls1028a-pcie", .data = &layerscape_drvdata },
> > > - { .compatible = "fsl,ls1043a-pcie", .data = &ls1021a_drvdata },
> > > + { .compatible = "fsl,ls1043a-pcie", .data = &ls1043a_drvdata },
> > > { .compatible = "fsl,ls1046a-pcie", .data = &layerscape_drvdata },
> > > { .compatible = "fsl,ls2080a-pcie", .data = &layerscape_drvdata },
> > > { .compatible = "fsl,ls2085a-pcie", .data = &layerscape_drvdata },
> > > --
> > > 2.34.1
> > >
> >
> > --
> > மணிவண்ணன் சதாசிவம்
On Thu, Nov 30, 2023 at 03:17:39PM -0500, Frank Li wrote:
> On Thu, Nov 30, 2023 at 10:21:00PM +0530, Manivannan Sadhasivam wrote:
> > On Wed, Nov 29, 2023 at 04:44:12PM -0500, Frank Li wrote:
> > > In the suspend path, PME_Turn_Off message is sent to the endpoint to
> > > transition the link to L2/L3_Ready state. In this SoC, there is no way to
> > > check if the controller has received the PME_To_Ack from the endpoint or
> > > not. So to be on the safer side, the driver just waits for
> > > PCIE_PME_TO_L2_TIMEOUT_US before asserting the SoC specific PMXMTTURNOFF
> > > bit to complete the PME_Turn_Off handshake. This link would then enter
> > > L2/L3 state depending on the VAUX supply.
> > >
> > > In the resume path, the link is brought back from L2 to L0 by doing a
> > > software reset.
> > >
> >
> > Same comment on the patch description as on patch 2/4.
> >
> > > Signed-off-by: Frank Li <[email protected]>
> > > ---
> > >
> > > Notes:
> > > Change from v3 to v4
> > > - Call scfg_pcie_send_turnoff_msg() shared with ls1021a
> > > - update commit message
> > >
> > > Change from v2 to v3
> > > - Remove ls_pcie_lut_readl(writel) function
> > >
> > > Change from v1 to v2
> > > - Update subject 'a' to 'A'
> > >
> > > drivers/pci/controller/dwc/pci-layerscape.c | 63 ++++++++++++++++++++-
> > > 1 file changed, 62 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c
> > > index 590e07bb27002..d39700b3afaaa 100644
> > > --- a/drivers/pci/controller/dwc/pci-layerscape.c
> > > +++ b/drivers/pci/controller/dwc/pci-layerscape.c
> > > @@ -41,6 +41,15 @@
> > > #define SCFG_PEXSFTRSTCR 0x190
> > > #define PEXSR(idx) BIT(idx)
> > >
> > > +/* LS1043A PEX PME control register */
> > > +#define SCFG_PEXPMECR 0x144
> > > +#define PEXPME(idx) BIT(31 - (idx) * 4)
> > > +
> > > +/* LS1043A PEX LUT debug register */
> > > +#define LS_PCIE_LDBG 0x7fc
> > > +#define LDBG_SR BIT(30)
> > > +#define LDBG_WE BIT(31)
> > > +
> > > #define PCIE_IATU_NUM 6
> > >
> > > struct ls_pcie_drvdata {
> > > @@ -225,6 +234,45 @@ static int ls1021a_pcie_exit_from_l2(struct dw_pcie_rp *pp)
> > > return scfg_pcie_exit_from_l2(pcie->scfg, SCFG_PEXSFTRSTCR, PEXSR(pcie->index));
> > > }
> > >
> > > +static void ls1043a_pcie_send_turnoff_msg(struct dw_pcie_rp *pp)
> > > +{
> > > + struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> > > + struct ls_pcie *pcie = to_ls_pcie(pci);
> > > +
> > > + scfg_pcie_send_turnoff_msg(pcie->scfg, SCFG_PEXPMECR, PEXPME(pcie->index));
> > > +}
> > > +
> > > +static int ls1043a_pcie_exit_from_l2(struct dw_pcie_rp *pp)
> > > +{
> > > + struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> > > + struct ls_pcie *pcie = to_ls_pcie(pci);
> > > + u32 val;
> > > +
> > > + /*
> > > + * Only way let PEX module exit L2 is do a software reset.
> >
> > Can you expand PEX? What is it used for?
> >
> > Also if the reset is only for the PEX module, please use the same comment in
> > both patches 2 and 4. Patch 2 doesn't mention PEX in the comment.
>
> After read spec again, I think PEX is pci express. So it should software
> reset controller. I don't know what exactly did in the chip. But without
> below code, PCIe can't exit L2/L3.
>
> Any harmful if dwc controller reset? Anyway these code works well with
> intel network card.
If it is a DWC controller reset, then we need to program all CSRs like DBI
etc... But from your reply it seems like the reset is limited to some module,
so it is fine.
- Mani
>
> Frank
>
> >
> > - Mani
> >
> > > + * LDBG_WE: allows the user to have write access to the PEXDBG[SR] for both setting and
> > > + * clearing the soft reset on the PEX module.
> > > + * LDBG_SR: When SR is set to 1, the PEX module enters soft reset.
> > > + */
> > > + val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
> > > + val |= LDBG_WE;
> > > + ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
> > > +
> > > + val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
> > > + val |= LDBG_SR;
> > > + ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
> > > +
> > > + val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
> > > + val &= ~LDBG_SR;
> > > + ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
> > > +
> > > + val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
> > > + val &= ~LDBG_WE;
> > > + ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
> > > +
> > > + return 0;
> > > +}
> > > +
> > > static const struct dw_pcie_host_ops ls_pcie_host_ops = {
> > > .host_init = ls_pcie_host_init,
> > > .pme_turn_off = ls_pcie_send_turnoff_msg,
> > > @@ -242,6 +290,19 @@ static const struct ls_pcie_drvdata ls1021a_drvdata = {
> > > .exit_from_l2 = ls1021a_pcie_exit_from_l2,
> > > };
> > >
> > > +static const struct dw_pcie_host_ops ls1043a_pcie_host_ops = {
> > > + .host_init = ls_pcie_host_init,
> > > + .pme_turn_off = ls1043a_pcie_send_turnoff_msg,
> > > +};
> > > +
> > > +static const struct ls_pcie_drvdata ls1043a_drvdata = {
> > > + .pf_lut_off = 0x10000,
> > > + .pm_support = true,
> > > + .scfg_support = true,
> > > + .ops = &ls1043a_pcie_host_ops,
> > > + .exit_from_l2 = ls1043a_pcie_exit_from_l2,
> > > +};
> > > +
> > > static const struct ls_pcie_drvdata layerscape_drvdata = {
> > > .pf_lut_off = 0xc0000,
> > > .pm_support = true,
> > > @@ -252,7 +313,7 @@ static const struct of_device_id ls_pcie_of_match[] = {
> > > { .compatible = "fsl,ls1012a-pcie", .data = &layerscape_drvdata },
> > > { .compatible = "fsl,ls1021a-pcie", .data = &ls1021a_drvdata },
> > > { .compatible = "fsl,ls1028a-pcie", .data = &layerscape_drvdata },
> > > - { .compatible = "fsl,ls1043a-pcie", .data = &ls1021a_drvdata },
> > > + { .compatible = "fsl,ls1043a-pcie", .data = &ls1043a_drvdata },
> > > { .compatible = "fsl,ls1046a-pcie", .data = &layerscape_drvdata },
> > > { .compatible = "fsl,ls2080a-pcie", .data = &layerscape_drvdata },
> > > { .compatible = "fsl,ls2085a-pcie", .data = &layerscape_drvdata },
> > > --
> > > 2.34.1
> > >
> >
> > --
> > மணிவண்ணன் சதாசிவம்
--
மணிவண்ணன் சதாசிவம்
On Thu, Nov 30, 2023 at 03:22:14PM -0500, Frank Li wrote:
> On Thu, Nov 30, 2023 at 03:17:39PM -0500, Frank Li wrote:
> > On Thu, Nov 30, 2023 at 10:21:00PM +0530, Manivannan Sadhasivam wrote:
> > > On Wed, Nov 29, 2023 at 04:44:12PM -0500, Frank Li wrote:
> > > > In the suspend path, PME_Turn_Off message is sent to the endpoint to
> > > > transition the link to L2/L3_Ready state. In this SoC, there is no way to
> > > > check if the controller has received the PME_To_Ack from the endpoint or
> > > > not. So to be on the safer side, the driver just waits for
> > > > PCIE_PME_TO_L2_TIMEOUT_US before asserting the SoC specific PMXMTTURNOFF
> > > > bit to complete the PME_Turn_Off handshake. This link would then enter
> > > > L2/L3 state depending on the VAUX supply.
> > > >
> > > > In the resume path, the link is brought back from L2 to L0 by doing a
> > > > software reset.
> > > >
> > >
> > > Same comment on the patch description as on patch 2/4.
> > >
> > > > Signed-off-by: Frank Li <[email protected]>
> > > > ---
> > > >
> > > > Notes:
> > > > Change from v3 to v4
> > > > - Call scfg_pcie_send_turnoff_msg() shared with ls1021a
> > > > - update commit message
> > > >
> > > > Change from v2 to v3
> > > > - Remove ls_pcie_lut_readl(writel) function
> > > >
> > > > Change from v1 to v2
> > > > - Update subject 'a' to 'A'
> > > >
> > > > drivers/pci/controller/dwc/pci-layerscape.c | 63 ++++++++++++++++++++-
> > > > 1 file changed, 62 insertions(+), 1 deletion(-)
> > > >
> > > > diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c
> > > > index 590e07bb27002..d39700b3afaaa 100644
> > > > --- a/drivers/pci/controller/dwc/pci-layerscape.c
> > > > +++ b/drivers/pci/controller/dwc/pci-layerscape.c
> > > > @@ -41,6 +41,15 @@
> > > > #define SCFG_PEXSFTRSTCR 0x190
> > > > #define PEXSR(idx) BIT(idx)
> > > >
> > > > +/* LS1043A PEX PME control register */
> > > > +#define SCFG_PEXPMECR 0x144
> > > > +#define PEXPME(idx) BIT(31 - (idx) * 4)
> > > > +
> > > > +/* LS1043A PEX LUT debug register */
> > > > +#define LS_PCIE_LDBG 0x7fc
> > > > +#define LDBG_SR BIT(30)
> > > > +#define LDBG_WE BIT(31)
> > > > +
> > > > #define PCIE_IATU_NUM 6
> > > >
> > > > struct ls_pcie_drvdata {
> > > > @@ -225,6 +234,45 @@ static int ls1021a_pcie_exit_from_l2(struct dw_pcie_rp *pp)
> > > > return scfg_pcie_exit_from_l2(pcie->scfg, SCFG_PEXSFTRSTCR, PEXSR(pcie->index));
> > > > }
> > > >
> > > > +static void ls1043a_pcie_send_turnoff_msg(struct dw_pcie_rp *pp)
> > > > +{
> > > > + struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> > > > + struct ls_pcie *pcie = to_ls_pcie(pci);
> > > > +
> > > > + scfg_pcie_send_turnoff_msg(pcie->scfg, SCFG_PEXPMECR, PEXPME(pcie->index));
> > > > +}
> > > > +
> > > > +static int ls1043a_pcie_exit_from_l2(struct dw_pcie_rp *pp)
> > > > +{
> > > > + struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> > > > + struct ls_pcie *pcie = to_ls_pcie(pci);
> > > > + u32 val;
> > > > +
> > > > + /*
> > > > + * Only way let PEX module exit L2 is do a software reset.
> > >
> > > Can you expand PEX? What is it used for?
> > >
> > > Also if the reset is only for the PEX module, please use the same comment in
> > > both patches 2 and 4. Patch 2 doesn't mention PEX in the comment.
> >
> > After read spec again, I think PEX is pci express. So it should software
> > reset controller. I don't know what exactly did in the chip. But without
> > below code, PCIe can't exit L2/L3.
> >
> > Any harmful if dwc controller reset? Anyway these code works well with
> > intel network card.
>
> Sorry, sent too quick. It is PCIe express wrapper
>
> Copy from spec:
>
> "PEXLDBG[SR]. Once set the
> PEXLDBG[SR] will enable the soft reset to the PEX wrapper."
>
Okay. Please use the below comment in both patches 2 and 4:
/* Reset the PEX wrapper to bring the link out of L2 */
- Mani
> Frank
>
> >
> > Frank
> >
> > >
> > > - Mani
> > >
> > > > + * LDBG_WE: allows the user to have write access to the PEXDBG[SR] for both setting and
> > > > + * clearing the soft reset on the PEX module.
> > > > + * LDBG_SR: When SR is set to 1, the PEX module enters soft reset.
> > > > + */
> > > > + val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
> > > > + val |= LDBG_WE;
> > > > + ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
> > > > +
> > > > + val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
> > > > + val |= LDBG_SR;
> > > > + ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
> > > > +
> > > > + val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
> > > > + val &= ~LDBG_SR;
> > > > + ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
> > > > +
> > > > + val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
> > > > + val &= ~LDBG_WE;
> > > > + ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > static const struct dw_pcie_host_ops ls_pcie_host_ops = {
> > > > .host_init = ls_pcie_host_init,
> > > > .pme_turn_off = ls_pcie_send_turnoff_msg,
> > > > @@ -242,6 +290,19 @@ static const struct ls_pcie_drvdata ls1021a_drvdata = {
> > > > .exit_from_l2 = ls1021a_pcie_exit_from_l2,
> > > > };
> > > >
> > > > +static const struct dw_pcie_host_ops ls1043a_pcie_host_ops = {
> > > > + .host_init = ls_pcie_host_init,
> > > > + .pme_turn_off = ls1043a_pcie_send_turnoff_msg,
> > > > +};
> > > > +
> > > > +static const struct ls_pcie_drvdata ls1043a_drvdata = {
> > > > + .pf_lut_off = 0x10000,
> > > > + .pm_support = true,
> > > > + .scfg_support = true,
> > > > + .ops = &ls1043a_pcie_host_ops,
> > > > + .exit_from_l2 = ls1043a_pcie_exit_from_l2,
> > > > +};
> > > > +
> > > > static const struct ls_pcie_drvdata layerscape_drvdata = {
> > > > .pf_lut_off = 0xc0000,
> > > > .pm_support = true,
> > > > @@ -252,7 +313,7 @@ static const struct of_device_id ls_pcie_of_match[] = {
> > > > { .compatible = "fsl,ls1012a-pcie", .data = &layerscape_drvdata },
> > > > { .compatible = "fsl,ls1021a-pcie", .data = &ls1021a_drvdata },
> > > > { .compatible = "fsl,ls1028a-pcie", .data = &layerscape_drvdata },
> > > > - { .compatible = "fsl,ls1043a-pcie", .data = &ls1021a_drvdata },
> > > > + { .compatible = "fsl,ls1043a-pcie", .data = &ls1043a_drvdata },
> > > > { .compatible = "fsl,ls1046a-pcie", .data = &layerscape_drvdata },
> > > > { .compatible = "fsl,ls2080a-pcie", .data = &layerscape_drvdata },
> > > > { .compatible = "fsl,ls2085a-pcie", .data = &layerscape_drvdata },
> > > > --
> > > > 2.34.1
> > > >
> > >
> > > --
> > > மணிவண்ணன் சதாசிவம்
--
மணிவண்ணன் சதாசிவம்