* [PATCH v4 1/6] PCI: spacemit-k1: Add device data support
2026-07-09 4:00 [PATCH v4 0/6] riscv: spacemit: Add PCIe RC controller support for K3 Inochi Amaoto
@ 2026-07-09 4:00 ` Inochi Amaoto
2026-07-09 7:09 ` Andy Shevchenko
2026-07-10 16:01 ` Alex Elder
2026-07-09 4:00 ` [PATCH v4 2/6] PCI: spacemit-k1: Add multiple PHY handles support Inochi Amaoto
` (4 subsequent siblings)
5 siblings, 2 replies; 21+ messages in thread
From: Inochi Amaoto @ 2026-07-09 4:00 UTC (permalink / raw)
To: Jingoo Han, Manivannan Sadhasivam, Bjorn Helgaas,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Yixun Lan, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christian Bruel,
Inochi Amaoto, Frank Li, Nam Cao, Qiang Yu,
Krishna Chaitanya Chundru, Xincheng Zhang, Alex Elder,
Siddharth Vadapalli, Andy Shevchenko, Vidya Sagar, Neil Armstrong,
Gustavo Pimentel
Cc: linux-pci, devicetree, linux-kernel, linux-riscv, spacemit,
Yixun Lan, Longbin Li
To reuse the K1 PCIe driver logic for K3 PCIe controller, add device
data to handle the K1 specific logic and make room for the incoming
logic for K3.
Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
---
drivers/pci/controller/dwc/pcie-spacemit-k1.c | 30 ++++++++++++++++---
1 file changed, 26 insertions(+), 4 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-spacemit-k1.c b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
index be20a520255b..f6ae8ff3589a 100644
--- a/drivers/pci/controller/dwc/pcie-spacemit-k1.c
+++ b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
@@ -49,8 +49,17 @@
#define PCIE_CONTROL_LOGIC 0x0004
#define PCIE_SOFT_RESET BIT(0)
+struct k1_pcie;
+
+struct k1_pcie_device_data {
+ const struct dw_pcie_host_ops *host_ops;
+ const struct dw_pcie_ops *ops;
+ int (*parse_port)(struct k1_pcie *k1);
+};
+
struct k1_pcie {
struct dw_pcie pci;
+ const struct k1_pcie_device_data *data;
struct phy *phy;
void __iomem *link;
struct regmap *pmu; /* Errors ignored; MMIO-backed regmap */
@@ -278,14 +287,21 @@ static int k1_pcie_parse_port(struct k1_pcie *k1)
static int k1_pcie_probe(struct platform_device *pdev)
{
+ const struct k1_pcie_device_data *data;
struct device *dev = &pdev->dev;
struct k1_pcie *k1;
int ret;
+ data = device_get_match_data(dev);
+ if (!data)
+ return -ENODEV;
+
k1 = devm_kzalloc(dev, sizeof(*k1), GFP_KERNEL);
if (!k1)
return -ENOMEM;
+ k1->data = data;
+
k1->pmu = syscon_regmap_lookup_by_phandle_args(dev_of_node(dev),
SYSCON_APMU, 1,
&k1->pmu_off);
@@ -299,11 +315,11 @@ static int k1_pcie_probe(struct platform_device *pdev)
"failed to map \"link\" registers\n");
k1->pci.dev = dev;
- k1->pci.ops = &k1_pcie_ops;
+ k1->pci.ops = data->ops;
k1->pci.pp.num_vectors = MAX_MSI_IRQS;
dw_pcie_cap_set(&k1->pci, REQ_RES);
- k1->pci.pp.ops = &k1_pcie_host_ops;
+ k1->pci.pp.ops = data->host_ops;
/* Hold the PHY in reset until we start the link */
regmap_set_bits(k1->pmu, k1->pmu_off + PCIE_CLK_RESET_CONTROL,
@@ -320,7 +336,7 @@ static int k1_pcie_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, k1);
- ret = k1_pcie_parse_port(k1);
+ ret = data->parse_port(k1);
if (ret)
return dev_err_probe(dev, ret, "failed to parse root port\n");
@@ -338,8 +354,14 @@ static void k1_pcie_remove(struct platform_device *pdev)
dw_pcie_host_deinit(&k1->pci.pp);
}
+static const struct k1_pcie_device_data k1_pcie_device_data = {
+ .host_ops = &k1_pcie_host_ops,
+ .ops = &k1_pcie_ops,
+ .parse_port = k1_pcie_parse_port,
+};
+
static const struct of_device_id k1_pcie_of_match_table[] = {
- { .compatible = "spacemit,k1-pcie", },
+ { .compatible = "spacemit,k1-pcie", .data = &k1_pcie_device_data},
{ }
};
--
2.55.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 21+ messages in thread* Re: [PATCH v4 1/6] PCI: spacemit-k1: Add device data support
2026-07-09 4:00 ` [PATCH v4 1/6] PCI: spacemit-k1: Add device data support Inochi Amaoto
@ 2026-07-09 7:09 ` Andy Shevchenko
2026-07-10 16:01 ` Alex Elder
1 sibling, 0 replies; 21+ messages in thread
From: Andy Shevchenko @ 2026-07-09 7:09 UTC (permalink / raw)
To: Inochi Amaoto
Cc: Jingoo Han, Manivannan Sadhasivam, Bjorn Helgaas,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Yixun Lan, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christian Bruel,
Frank Li, Nam Cao, Qiang Yu, Krishna Chaitanya Chundru,
Xincheng Zhang, Alex Elder, Siddharth Vadapalli, Vidya Sagar,
Neil Armstrong, Gustavo Pimentel, linux-pci, devicetree,
linux-kernel, linux-riscv, spacemit, Yixun Lan, Longbin Li
On Thu, Jul 09, 2026 at 12:00:21PM +0800, Inochi Amaoto wrote:
> To reuse the K1 PCIe driver logic for K3 PCIe controller, add device
> data to handle the K1 specific logic and make room for the incoming
> logic for K3.
...
> static const struct of_device_id k1_pcie_of_match_table[] = {
> - { .compatible = "spacemit,k1-pcie", },
> + { .compatible = "spacemit,k1-pcie", .data = &k1_pcie_device_data},
Missing space before }.
> { }
> };
--
With Best Regards,
Andy Shevchenko
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH v4 1/6] PCI: spacemit-k1: Add device data support
2026-07-09 4:00 ` [PATCH v4 1/6] PCI: spacemit-k1: Add device data support Inochi Amaoto
2026-07-09 7:09 ` Andy Shevchenko
@ 2026-07-10 16:01 ` Alex Elder
1 sibling, 0 replies; 21+ messages in thread
From: Alex Elder @ 2026-07-10 16:01 UTC (permalink / raw)
To: Inochi Amaoto, Jingoo Han, Manivannan Sadhasivam, Bjorn Helgaas,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Yixun Lan, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christian Bruel,
Frank Li, Nam Cao, Qiang Yu, Krishna Chaitanya Chundru,
Xincheng Zhang, Siddharth Vadapalli, Andy Shevchenko, Vidya Sagar,
Neil Armstrong, Gustavo Pimentel
Cc: linux-pci, devicetree, linux-kernel, linux-riscv, spacemit,
Yixun Lan, Longbin Li
On 7/8/26 11:00 PM, Inochi Amaoto wrote:
> To reuse the K1 PCIe driver logic for K3 PCIe controller, add device
> data to handle the K1 specific logic and make room for the incoming
> logic for K3.
>
> Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
I have two suggestions/questions, but I think this looks
good overall (please add the space that Andy suggested).
If you drop the data field in the k1_pcie structure you
can keep this tag:
Reviewed-by: Alex Elder <elder@riscstar.com>
> ---
> drivers/pci/controller/dwc/pcie-spacemit-k1.c | 30 ++++++++++++++++---
> 1 file changed, 26 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-spacemit-k1.c b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> index be20a520255b..f6ae8ff3589a 100644
> --- a/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> +++ b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> @@ -49,8 +49,17 @@
> #define PCIE_CONTROL_LOGIC 0x0004
> #define PCIE_SOFT_RESET BIT(0)
>
> +struct k1_pcie;
> +
> +struct k1_pcie_device_data {
> + const struct dw_pcie_host_ops *host_ops;
> + const struct dw_pcie_ops *ops;
> + int (*parse_port)(struct k1_pcie *k1);
> +};
> +
> struct k1_pcie {
> struct dw_pcie pci;
> + const struct k1_pcie_device_data *data;
Is it strictly necessary to keep a copy of the data
pointer in the k1_pcie structure?
It can be convenient to do so if you reuse the fields
in that structure rather than duplicating them, but
often the constant platform data is meant only for
initialization, and never needed after that.
> struct phy *phy;
> void __iomem *link;
> struct regmap *pmu; /* Errors ignored; MMIO-backed regmap */
> @@ -278,14 +287,21 @@ static int k1_pcie_parse_port(struct k1_pcie *k1)
>
> static int k1_pcie_probe(struct platform_device *pdev)
> {
> + const struct k1_pcie_device_data *data;
> struct device *dev = &pdev->dev;
> struct k1_pcie *k1;
> int ret;
>
> + data = device_get_match_data(dev);
> + if (!data)
> + return -ENODEV;
> +
> k1 = devm_kzalloc(dev, sizeof(*k1), GFP_KERNEL);
> if (!k1)
> return -ENOMEM;
>
> + k1->data = data;
> +
> k1->pmu = syscon_regmap_lookup_by_phandle_args(dev_of_node(dev),
> SYSCON_APMU, 1,
> &k1->pmu_off);
> @@ -299,11 +315,11 @@ static int k1_pcie_probe(struct platform_device *pdev)
> "failed to map \"link\" registers\n");
>
> k1->pci.dev = dev;
> - k1->pci.ops = &k1_pcie_ops;
> + k1->pci.ops = data->ops;
> k1->pci.pp.num_vectors = MAX_MSI_IRQS;
> dw_pcie_cap_set(&k1->pci, REQ_RES);
>
> - k1->pci.pp.ops = &k1_pcie_host_ops;
> + k1->pci.pp.ops = data->host_ops;
>
> /* Hold the PHY in reset until we start the link */
> regmap_set_bits(k1->pmu, k1->pmu_off + PCIE_CLK_RESET_CONTROL,
> @@ -320,7 +336,7 @@ static int k1_pcie_probe(struct platform_device *pdev)
>
> platform_set_drvdata(pdev, k1);
>
> - ret = k1_pcie_parse_port(k1);
> + ret = data->parse_port(k1);
> if (ret)
> return dev_err_probe(dev, ret, "failed to parse root port\n");
>
> @@ -338,8 +354,14 @@ static void k1_pcie_remove(struct platform_device *pdev)
> dw_pcie_host_deinit(&k1->pci.pp);
> }
>
> +static const struct k1_pcie_device_data k1_pcie_device_data = {
> + .host_ops = &k1_pcie_host_ops,
> + .ops = &k1_pcie_ops,
> + .parse_port = k1_pcie_parse_port,
> +};
> +
> static const struct of_device_id k1_pcie_of_match_table[] = {
> - { .compatible = "spacemit,k1-pcie", },
> + { .compatible = "spacemit,k1-pcie", .data = &k1_pcie_device_data},
In addition to the missing space that Andy mentioned,
adding a comma means the line won't need to change
when you add another entry to the array.
> { }
> };
>
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v4 2/6] PCI: spacemit-k1: Add multiple PHY handles support
2026-07-09 4:00 [PATCH v4 0/6] riscv: spacemit: Add PCIe RC controller support for K3 Inochi Amaoto
2026-07-09 4:00 ` [PATCH v4 1/6] PCI: spacemit-k1: Add device data support Inochi Amaoto
@ 2026-07-09 4:00 ` Inochi Amaoto
2026-07-09 7:16 ` Andy Shevchenko
2026-07-10 16:01 ` Alex Elder
2026-07-09 4:00 ` [PATCH v4 3/6] PCI: spacemit-k1: Add device id update helper Inochi Amaoto
` (3 subsequent siblings)
5 siblings, 2 replies; 21+ messages in thread
From: Inochi Amaoto @ 2026-07-09 4:00 UTC (permalink / raw)
To: Jingoo Han, Manivannan Sadhasivam, Bjorn Helgaas,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Yixun Lan, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christian Bruel,
Inochi Amaoto, Frank Li, Nam Cao, Qiang Yu,
Krishna Chaitanya Chundru, Xincheng Zhang, Alex Elder,
Siddharth Vadapalli, Andy Shevchenko, Vidya Sagar, Neil Armstrong,
Gustavo Pimentel
Cc: linux-pci, devicetree, linux-kernel, linux-riscv, spacemit,
Yixun Lan, Longbin Li
The PCIe controller on Spacemit K3 may use multiple PHYs at the
same time. The feature is not support by the current driver.
So extend the PHY definition to support multiple PHY handles.
Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
---
drivers/pci/controller/dwc/pcie-spacemit-k1.c | 70 ++++++++++++++++---
1 file changed, 59 insertions(+), 11 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-spacemit-k1.c b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
index f6ae8ff3589a..e22ecbd09579 100644
--- a/drivers/pci/controller/dwc/pcie-spacemit-k1.c
+++ b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
@@ -55,12 +55,14 @@ struct k1_pcie_device_data {
const struct dw_pcie_host_ops *host_ops;
const struct dw_pcie_ops *ops;
int (*parse_port)(struct k1_pcie *k1);
+ unsigned int max_phy_count;
};
struct k1_pcie {
struct dw_pcie pci;
const struct k1_pcie_device_data *data;
- struct phy *phy;
+ struct phy **phy;
+ unsigned int phy_count;
void __iomem *link;
struct regmap *pmu; /* Errors ignored; MMIO-backed regmap */
u32 pmu_off;
@@ -119,6 +121,54 @@ static void k1_pcie_disable_resources(struct k1_pcie *k1)
clk_bulk_disable_unprepare(ARRAY_SIZE(pci->app_clks), pci->app_clks);
}
+static int k1_pcie_get_phy_handle(struct k1_pcie *k1, struct device_node *node)
+{
+ const struct k1_pcie_device_data *data = k1->data;
+ struct device *dev = k1->pci.dev;
+ unsigned int i;
+
+ k1->phy = devm_kmalloc_array(dev, data->max_phy_count,
+ sizeof(*k1->phy), GFP_KERNEL);
+ if (!k1->phy)
+ return -ENOMEM;
+
+ for (i = 0; i < data->max_phy_count; i++) {
+ k1->phy[i] = devm_of_phy_get_by_index(dev, node, i);
+ if (IS_ERR(k1->phy[i])) {
+ if (PTR_ERR(k1->phy[i]) == -ENODEV)
+ break;
+
+ return PTR_ERR(k1->phy[i]);
+ }
+ }
+
+ k1->phy_count = i;
+ if (k1->phy_count == 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int k1_pcie_enable_phy(struct k1_pcie *k1)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < k1->phy_count; i++) {
+ ret = phy_init(k1->phy[i]);
+ if (ret)
+ goto err_phy;
+ }
+
+ return 0;
+
+err_phy:
+ while (i--)
+ phy_exit(k1->phy[i]);
+
+ return ret;
+}
+
/* FIXME: Disable ASPM L1 to avoid errors reported on some NVMe drives */
static void k1_pcie_disable_aspm_l1(struct k1_pcie *k1)
{
@@ -174,7 +224,7 @@ static int k1_pcie_init(struct dw_pcie_rp *pp)
*/
regmap_set_bits(k1->pmu, reset_ctrl, DEVICE_TYPE_RC | PCIE_AUX_PWR_DET);
- ret = phy_init(k1->phy);
+ ret = k1_pcie_enable_phy(k1);
if (ret) {
k1_pcie_disable_resources(k1);
@@ -194,12 +244,14 @@ static void k1_pcie_deinit(struct dw_pcie_rp *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct k1_pcie *k1 = to_k1_pcie(pci);
+ int i;
/* Assert fundamental reset (drive PERST# low) */
regmap_set_bits(k1->pmu, k1->pmu_off + PCIE_CLK_RESET_CONTROL,
PCIE_RC_PERST);
- phy_exit(k1->phy);
+ for (i = 0; i < k1->phy_count; i++)
+ phy_exit(k1->phy[i]);
k1_pcie_disable_resources(k1);
}
@@ -266,23 +318,18 @@ static int k1_pcie_parse_port(struct k1_pcie *k1)
{
struct device *dev = k1->pci.dev;
struct device_node *root_port;
- struct phy *phy;
+ int ret;
/* We assume only one root port */
root_port = of_get_next_available_child(dev_of_node(dev), NULL);
if (!root_port)
return -EINVAL;
- phy = devm_of_phy_get(dev, root_port, NULL);
+ ret = k1_pcie_get_phy_handle(k1, root_port);
of_node_put(root_port);
- if (IS_ERR(phy))
- return PTR_ERR(phy);
-
- k1->phy = phy;
-
- return 0;
+ return ret;
}
static int k1_pcie_probe(struct platform_device *pdev)
@@ -358,6 +405,7 @@ static const struct k1_pcie_device_data k1_pcie_device_data = {
.host_ops = &k1_pcie_host_ops,
.ops = &k1_pcie_ops,
.parse_port = k1_pcie_parse_port,
+ .max_phy_count = 1,
};
static const struct of_device_id k1_pcie_of_match_table[] = {
--
2.55.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 21+ messages in thread* Re: [PATCH v4 2/6] PCI: spacemit-k1: Add multiple PHY handles support
2026-07-09 4:00 ` [PATCH v4 2/6] PCI: spacemit-k1: Add multiple PHY handles support Inochi Amaoto
@ 2026-07-09 7:16 ` Andy Shevchenko
2026-07-10 1:57 ` Inochi Amaoto
2026-07-10 12:51 ` Alex Elder
2026-07-10 16:01 ` Alex Elder
1 sibling, 2 replies; 21+ messages in thread
From: Andy Shevchenko @ 2026-07-09 7:16 UTC (permalink / raw)
To: Inochi Amaoto
Cc: Jingoo Han, Manivannan Sadhasivam, Bjorn Helgaas,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Yixun Lan, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christian Bruel,
Frank Li, Nam Cao, Qiang Yu, Krishna Chaitanya Chundru,
Xincheng Zhang, Alex Elder, Siddharth Vadapalli, Vidya Sagar,
Neil Armstrong, Gustavo Pimentel, linux-pci, devicetree,
linux-kernel, linux-riscv, spacemit, Yixun Lan, Longbin Li
On Thu, Jul 09, 2026 at 12:00:22PM +0800, Inochi Amaoto wrote:
> The PCIe controller on Spacemit K3 may use multiple PHYs at the
> same time. The feature is not support by the current driver.
> So extend the PHY definition to support multiple PHY handles.
...
> struct k1_pcie {
> struct dw_pcie pci;
> const struct k1_pcie_device_data *data;
> - struct phy *phy;
> + struct phy **phy;
Should it be annotated by __counted_by_ptr() ?
> + unsigned int phy_count;
Ah, you allocate much more memory than possible PHYs... Can you redesign and
use the above annotation?
> void __iomem *link;
> struct regmap *pmu; /* Errors ignored; MMIO-backed regmap */
> u32 pmu_off;
> }
...
> +static int k1_pcie_get_phy_handle(struct k1_pcie *k1, struct device_node *node)
> +{
> + const struct k1_pcie_device_data *data = k1->data;
> + struct device *dev = k1->pci.dev;
> + unsigned int i;
> +
> + k1->phy = devm_kmalloc_array(dev, data->max_phy_count,
> + sizeof(*k1->phy), GFP_KERNEL);
> + if (!k1->phy)
> + return -ENOMEM;
> +
> + for (i = 0; i < data->max_phy_count; i++) {
> + k1->phy[i] = devm_of_phy_get_by_index(dev, node, i);
> + if (IS_ERR(k1->phy[i])) {
> + if (PTR_ERR(k1->phy[i]) == -ENODEV)
> + break;
> +
> + return PTR_ERR(k1->phy[i]);
> + }
if (PTR_ERR(k1->phy[i]) == -ENODEV)
break;
if (IS_ERR(k1->phy[i]))
return PTR_ERR(k1->phy[i]);
> + }
> + k1->phy_count = i;
> + if (k1->phy_count == 0)
> + return -EINVAL;
> +
> + return 0;
This doesn't seem correct to me, I would expect phy_count to be assigned only
when it's valid. (Yes, perhaps 0 is the same as it was, but semantically it's
different 0 in this case.)
See also above. Do we have some PHY API that just counts provided PHYs?
If not, that what you should probably add first, before this patch.
> +}
> +
> +static int k1_pcie_enable_phy(struct k1_pcie *k1)
> +{
> + unsigned int i;
> + int ret;
> +
> + for (i = 0; i < k1->phy_count; i++) {
> + ret = phy_init(k1->phy[i]);
> + if (ret)
> + goto err_phy;
> + }
> +
> + return 0;
> +
> +err_phy:
> + while (i--)
> + phy_exit(k1->phy[i]);
> +
> + return ret;
> +}
...
> static void k1_pcie_deinit(struct dw_pcie_rp *pp)
> {
> struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> struct k1_pcie *k1 = to_k1_pcie(pci);
> + int i;
>
> /* Assert fundamental reset (drive PERST# low) */
> regmap_set_bits(k1->pmu, k1->pmu_off + PCIE_CLK_RESET_CONTROL,
> PCIE_RC_PERST);
>
> - phy_exit(k1->phy);
> + for (i = 0; i < k1->phy_count; i++)
for (unsigned int i = 0; i < k1->phy_count; i++)
> + phy_exit(k1->phy[i]);
>
> k1_pcie_disable_resources(k1);
> }
--
With Best Regards,
Andy Shevchenko
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH v4 2/6] PCI: spacemit-k1: Add multiple PHY handles support
2026-07-09 7:16 ` Andy Shevchenko
@ 2026-07-10 1:57 ` Inochi Amaoto
2026-07-10 8:07 ` Andy Shevchenko
2026-07-10 12:51 ` Alex Elder
1 sibling, 1 reply; 21+ messages in thread
From: Inochi Amaoto @ 2026-07-10 1:57 UTC (permalink / raw)
To: Andy Shevchenko, Inochi Amaoto
Cc: Jingoo Han, Manivannan Sadhasivam, Bjorn Helgaas,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Yixun Lan, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christian Bruel,
Frank Li, Nam Cao, Qiang Yu, Krishna Chaitanya Chundru,
Xincheng Zhang, Alex Elder, Siddharth Vadapalli, Vidya Sagar,
Neil Armstrong, Gustavo Pimentel, linux-pci, devicetree,
linux-kernel, linux-riscv, spacemit, Yixun Lan, Longbin Li
On Thu, Jul 09, 2026 at 10:16:28AM +0300, Andy Shevchenko wrote:
> On Thu, Jul 09, 2026 at 12:00:22PM +0800, Inochi Amaoto wrote:
> > The PCIe controller on Spacemit K3 may use multiple PHYs at the
> > same time. The feature is not support by the current driver.
> > So extend the PHY definition to support multiple PHY handles.
>
> ...
>
> > struct k1_pcie {
> > struct dw_pcie pci;
> > const struct k1_pcie_device_data *data;
> > - struct phy *phy;
> > + struct phy **phy;
>
> Should it be annotated by __counted_by_ptr() ?
>
Yes, I think it can, this is something I have missed.
> > + unsigned int phy_count;
>
> Ah, you allocate much more memory than possible PHYs... Can you redesign and
> use the above annotation?
>
IIRC use the annotation does not reduce this memory usage...
> > void __iomem *link;
> > struct regmap *pmu; /* Errors ignored; MMIO-backed regmap */
> > u32 pmu_off;
>
> > }
>
> ...
>
> > +static int k1_pcie_get_phy_handle(struct k1_pcie *k1, struct device_node *node)
> > +{
> > + const struct k1_pcie_device_data *data = k1->data;
> > + struct device *dev = k1->pci.dev;
> > + unsigned int i;
> > +
> > + k1->phy = devm_kmalloc_array(dev, data->max_phy_count,
> > + sizeof(*k1->phy), GFP_KERNEL);
> > + if (!k1->phy)
> > + return -ENOMEM;
> > +
> > + for (i = 0; i < data->max_phy_count; i++) {
> > + k1->phy[i] = devm_of_phy_get_by_index(dev, node, i);
>
> > + if (IS_ERR(k1->phy[i])) {
> > + if (PTR_ERR(k1->phy[i]) == -ENODEV)
> > + break;
> > +
> > + return PTR_ERR(k1->phy[i]);
> > + }
>
> if (PTR_ERR(k1->phy[i]) == -ENODEV)
> break;
> if (IS_ERR(k1->phy[i]))
> return PTR_ERR(k1->phy[i]);
>
Yeah, this is more clear. Thanks.
>
> > + }
>
> > + k1->phy_count = i;
> > + if (k1->phy_count == 0)
> > + return -EINVAL;
> > +
> > + return 0;
>
> This doesn't seem correct to me, I would expect phy_count to be assigned only
> when it's valid. (Yes, perhaps 0 is the same as it was, but semantically it's
> different 0 in this case.)
>
I guess you think 0 is a valid number? I can not understand what you thing
Assign this to 0 if there is no phy is fine to me, which shows there is 0
vaild phy found.
> See also above. Do we have some PHY API that just counts provided PHYs?
> If not, that what you should probably add first, before this patch.
>
I have not found any api for this. But the actual problem is, how the api
is designed. I have checked both the array bulk api for reset and clock,
it seems like it is much more than this patch...
> > +}
> > +
> > +static int k1_pcie_enable_phy(struct k1_pcie *k1)
> > +{
> > + unsigned int i;
> > + int ret;
> > +
> > + for (i = 0; i < k1->phy_count; i++) {
> > + ret = phy_init(k1->phy[i]);
> > + if (ret)
> > + goto err_phy;
> > + }
> > +
> > + return 0;
> > +
> > +err_phy:
> > + while (i--)
> > + phy_exit(k1->phy[i]);
> > +
> > + return ret;
> > +}
>
> ...
>
> > static void k1_pcie_deinit(struct dw_pcie_rp *pp)
> > {
> > struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> > struct k1_pcie *k1 = to_k1_pcie(pci);
>
> > + int i;
> >
> > /* Assert fundamental reset (drive PERST# low) */
> > regmap_set_bits(k1->pmu, k1->pmu_off + PCIE_CLK_RESET_CONTROL,
> > PCIE_RC_PERST);
> >
> > - phy_exit(k1->phy);
>
> > + for (i = 0; i < k1->phy_count; i++)
>
> for (unsigned int i = 0; i < k1->phy_count; i++)
>
I agree with the unsigned int, but I guess this definition is not
allowed in linux.
> > + phy_exit(k1->phy[i]);
> >
> > k1_pcie_disable_resources(k1);
> > }
>
> --
> With Best Regards,
> Andy Shevchenko
>
>
Regards,
Inochi
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH v4 2/6] PCI: spacemit-k1: Add multiple PHY handles support
2026-07-10 1:57 ` Inochi Amaoto
@ 2026-07-10 8:07 ` Andy Shevchenko
2026-07-10 10:55 ` Inochi Amaoto
0 siblings, 1 reply; 21+ messages in thread
From: Andy Shevchenko @ 2026-07-10 8:07 UTC (permalink / raw)
To: Inochi Amaoto
Cc: Jingoo Han, Manivannan Sadhasivam, Bjorn Helgaas,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Yixun Lan, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christian Bruel,
Frank Li, Nam Cao, Qiang Yu, Krishna Chaitanya Chundru,
Xincheng Zhang, Alex Elder, Siddharth Vadapalli, Vidya Sagar,
Neil Armstrong, Gustavo Pimentel, linux-pci, devicetree,
linux-kernel, linux-riscv, spacemit, Yixun Lan, Longbin Li
On Fri, Jul 10, 2026 at 09:57:05AM +0800, Inochi Amaoto wrote:
> On Thu, Jul 09, 2026 at 10:16:28AM +0300, Andy Shevchenko wrote:
> > On Thu, Jul 09, 2026 at 12:00:22PM +0800, Inochi Amaoto wrote:
...
> > > struct k1_pcie {
> > > struct dw_pcie pci;
> > > const struct k1_pcie_device_data *data;
> > > - struct phy *phy;
> > > + struct phy **phy;
> >
> > Should it be annotated by __counted_by_ptr() ?
>
> Yes, I think it can, this is something I have missed.
>
> > > + unsigned int phy_count;
> >
> > Ah, you allocate much more memory than possible PHYs... Can you redesign and
> > use the above annotation?
>
> IIRC use the annotation does not reduce this memory usage...
It's about how you allocate it, the code uses max_phy_count instead of
phy_count.
> > > void __iomem *link;
> > > struct regmap *pmu; /* Errors ignored; MMIO-backed regmap */
> > > u32 pmu_off;
> >
> > > }
...
> > > + k1->phy_count = i;
> > > + if (k1->phy_count == 0)
> > > + return -EINVAL;
> > > +
> > > + return 0;
> >
> > This doesn't seem correct to me, I would expect phy_count to be assigned only
> > when it's valid. (Yes, perhaps 0 is the same as it was, but semantically it's
> > different 0 in this case.)
>
> I guess you think 0 is a valid number? I can not understand what you thing
> Assign this to 0 if there is no phy is fine to me, which shows there is 0
> vaild phy found.
Isn't it already 0? Semantically code is wrong in a flow (not in the result).
> > See also above. Do we have some PHY API that just counts provided PHYs?
> > If not, that what you should probably add first, before this patch.
>
> I have not found any api for this. But the actual problem is, how the api
> is designed. I have checked both the array bulk api for reset and clock,
> it seems like it is much more than this patch...
Yeah, I looked at the phy-core and I think it will be hard to implement.
So, the idea is then is to reallocate the pointer each time you get a new PHY.
In this case the phy_count will reflect the actual memory consumption by phy.
...
> > > + for (i = 0; i < k1->phy_count; i++)
> >
> > for (unsigned int i = 0; i < k1->phy_count; i++)
> >
>
> I agree with the unsigned int, but I guess this definition is not
> allowed in linux.
It's allowed and it's encouraged even by Linus. As long as iterator is local,
use this syntax sugar and reduce its scope. It hardens the code.
> > > + phy_exit(k1->phy[i]);
--
With Best Regards,
Andy Shevchenko
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH v4 2/6] PCI: spacemit-k1: Add multiple PHY handles support
2026-07-10 8:07 ` Andy Shevchenko
@ 2026-07-10 10:55 ` Inochi Amaoto
2026-07-10 12:42 ` Alex Elder
0 siblings, 1 reply; 21+ messages in thread
From: Inochi Amaoto @ 2026-07-10 10:55 UTC (permalink / raw)
To: Andy Shevchenko, Inochi Amaoto
Cc: Jingoo Han, Manivannan Sadhasivam, Bjorn Helgaas,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Yixun Lan, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christian Bruel,
Frank Li, Nam Cao, Qiang Yu, Krishna Chaitanya Chundru,
Xincheng Zhang, Alex Elder, Siddharth Vadapalli, Vidya Sagar,
Neil Armstrong, Gustavo Pimentel, linux-pci, devicetree,
linux-kernel, linux-riscv, spacemit, Yixun Lan, Longbin Li
On Fri, Jul 10, 2026 at 11:07:40AM +0300, Andy Shevchenko wrote:
> On Fri, Jul 10, 2026 at 09:57:05AM +0800, Inochi Amaoto wrote:
> > On Thu, Jul 09, 2026 at 10:16:28AM +0300, Andy Shevchenko wrote:
> > > On Thu, Jul 09, 2026 at 12:00:22PM +0800, Inochi Amaoto wrote:
>
> ...
>
> > > > struct k1_pcie {
> > > > struct dw_pcie pci;
> > > > const struct k1_pcie_device_data *data;
> > > > - struct phy *phy;
> > > > + struct phy **phy;
> > >
> > > Should it be annotated by __counted_by_ptr() ?
> >
> > Yes, I think it can, this is something I have missed.
> >
> > > > + unsigned int phy_count;
> > >
> > > Ah, you allocate much more memory than possible PHYs... Can you redesign and
> > > use the above annotation?
> >
> > IIRC use the annotation does not reduce this memory usage...
>
> It's about how you allocate it, the code uses max_phy_count instead of
> phy_count.
>
> > > > void __iomem *link;
> > > > struct regmap *pmu; /* Errors ignored; MMIO-backed regmap */
> > > > u32 pmu_off;
> > >
> > > > }
>
> ...
>
> > > > + k1->phy_count = i;
> > > > + if (k1->phy_count == 0)
> > > > + return -EINVAL;
> > > > +
> > > > + return 0;
> > >
> > > This doesn't seem correct to me, I would expect phy_count to be assigned only
> > > when it's valid. (Yes, perhaps 0 is the same as it was, but semantically it's
> > > different 0 in this case.)
> >
> > I guess you think 0 is a valid number? I can not understand what you thing
> > Assign this to 0 if there is no phy is fine to me, which shows there is 0
> > vaild phy found.
>
> Isn't it already 0? Semantically code is wrong in a flow (not in the result).
>
In fact it is already 0 here. But I am not understand why you thing is wrong.
Could you explain it in detail? (Maybe you think it is not good to return
-EINVAL?)
> > > See also above. Do we have some PHY API that just counts provided PHYs?
> > > If not, that what you should probably add first, before this patch.
> >
> > I have not found any api for this. But the actual problem is, how the api
> > is designed. I have checked both the array bulk api for reset and clock,
> > it seems like it is much more than this patch...
>
> Yeah, I looked at the phy-core and I think it will be hard to implement.
> So, the idea is then is to reallocate the pointer each time you get a new PHY.
> In this case the phy_count will reflect the actual memory consumption by phy.
>
Emmm, I think it is kind of buggy and not necessary. In most case
this array is not long actually, so allocate some pointer should be
fine and be an acceptable cost.
> ...
>
> > > > + for (i = 0; i < k1->phy_count; i++)
> > >
> > > for (unsigned int i = 0; i < k1->phy_count; i++)
> > >
> >
> > I agree with the unsigned int, but I guess this definition is not
> > allowed in linux.
>
> It's allowed and it's encouraged even by Linus. As long as iterator is local,
> use this syntax sugar and reduce its scope. It hardens the code.
>
Could you give me a reference url to check, I have not found this
on the coding-style.
https://www.kernel.org/doc/html/latest/process/coding-style.html
> > > > + phy_exit(k1->phy[i]);
>
> --
> With Best Regards,
> Andy Shevchenko
>
>
Regards,
Inochi
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH v4 2/6] PCI: spacemit-k1: Add multiple PHY handles support
2026-07-10 10:55 ` Inochi Amaoto
@ 2026-07-10 12:42 ` Alex Elder
0 siblings, 0 replies; 21+ messages in thread
From: Alex Elder @ 2026-07-10 12:42 UTC (permalink / raw)
To: Inochi Amaoto, Andy Shevchenko
Cc: Jingoo Han, Manivannan Sadhasivam, Bjorn Helgaas,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Yixun Lan, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christian Bruel,
Frank Li, Nam Cao, Qiang Yu, Krishna Chaitanya Chundru,
Xincheng Zhang, Siddharth Vadapalli, Vidya Sagar, Neil Armstrong,
Gustavo Pimentel, linux-pci, devicetree, linux-kernel,
linux-riscv, spacemit, Yixun Lan, Longbin Li
On 7/10/26 5:55 AM, Inochi Amaoto wrote:
>>>>> + k1->phy_count = i;
>>>>> + if (k1->phy_count == 0)
>>>>> + return -EINVAL;
>>>>> +
>>>>> + return 0;
>>>> This doesn't seem correct to me, I would expect phy_count to be assigned only
>>>> when it's valid. (Yes, perhaps 0 is the same as it was, but semantically it's
>>>> different 0 in this case.)
>>> I guess you think 0 is a valid number? I can not understand what you thing
>>> Assign this to 0 if there is no phy is fine to me, which shows there is 0
>>> vaild phy found.
>> Isn't it already 0? Semantically code is wrong in a flow (not in the result).
>>
> In fact it is already 0 here. But I am not understand why you thing is wrong.
> Could you explain it in detail? (Maybe you think it is not good to return
> -EINVAL?)
What Andy is saying is that assigning the value of phy_count
before checking that it is valid is not the expected order of
things.
The point is about best practice, not about the end result.
Best practice would be "don't touch anything if the return
value will indicate an error."
And therefore, better coding practice would be to check for
a bad value, and only after that has been done should you
assign the k1->phy_count value.
-Alex
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v4 2/6] PCI: spacemit-k1: Add multiple PHY handles support
2026-07-09 7:16 ` Andy Shevchenko
2026-07-10 1:57 ` Inochi Amaoto
@ 2026-07-10 12:51 ` Alex Elder
1 sibling, 0 replies; 21+ messages in thread
From: Alex Elder @ 2026-07-10 12:51 UTC (permalink / raw)
To: Andy Shevchenko, Inochi Amaoto
Cc: Jingoo Han, Manivannan Sadhasivam, Bjorn Helgaas,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Yixun Lan, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christian Bruel,
Frank Li, Nam Cao, Qiang Yu, Krishna Chaitanya Chundru,
Xincheng Zhang, Siddharth Vadapalli, Vidya Sagar, Neil Armstrong,
Gustavo Pimentel, linux-pci, devicetree, linux-kernel,
linux-riscv, spacemit, Yixun Lan, Longbin Li
On 7/9/26 2:16 AM, Andy Shevchenko wrote:
>> + if (IS_ERR(k1->phy[i])) {
>> + if (PTR_ERR(k1->phy[i]) == -ENODEV)
>> + break;
>> +
>> + return PTR_ERR(k1->phy[i]);
>> + }
> if (PTR_ERR(k1->phy[i]) == -ENODEV)
> break;
> if (IS_ERR(k1->phy[i]))
> return PTR_ERR(k1->phy[i]);
I'm not sure this is a huge improvement. Checking IS_ERR()
before using PTR_ERR() is comforting (a little along the
lines of the other issue you mentioned--assigning a result
before checking for an error). Anyway, it's a little bit
of an ugly construct no matter how you do it. Here's another
possible way to do it.
k1->phy[i] = devm_of_phy_get_by_index(dev, node, i);
if (!IS_ERR(k1->phy[i]))
continue;
ret = PTR_ERR(k1->phy[i]);
if (ret == -ENODEV)
break;
return ret;
-Alex
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v4 2/6] PCI: spacemit-k1: Add multiple PHY handles support
2026-07-09 4:00 ` [PATCH v4 2/6] PCI: spacemit-k1: Add multiple PHY handles support Inochi Amaoto
2026-07-09 7:16 ` Andy Shevchenko
@ 2026-07-10 16:01 ` Alex Elder
1 sibling, 0 replies; 21+ messages in thread
From: Alex Elder @ 2026-07-10 16:01 UTC (permalink / raw)
To: Inochi Amaoto, Jingoo Han, Manivannan Sadhasivam, Bjorn Helgaas,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Yixun Lan, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christian Bruel,
Frank Li, Nam Cao, Qiang Yu, Krishna Chaitanya Chundru,
Xincheng Zhang, Siddharth Vadapalli, Andy Shevchenko, Vidya Sagar,
Neil Armstrong, Gustavo Pimentel
Cc: linux-pci, devicetree, linux-kernel, linux-riscv, spacemit,
Yixun Lan, Longbin Li
On 7/8/26 11:00 PM, Inochi Amaoto wrote:
> The PCIe controller on Spacemit K3 may use multiple PHYs at the
s/use/uses/
> same time. The feature is not support by the current driver.
s/support/supported/
> So extend the PHY definition to support multiple PHY handles.
>
> Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
> ---
> drivers/pci/controller/dwc/pcie-spacemit-k1.c | 70 ++++++++++++++++---
> 1 file changed, 59 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-spacemit-k1.c b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> index f6ae8ff3589a..e22ecbd09579 100644
> --- a/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> +++ b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> @@ -55,12 +55,14 @@ struct k1_pcie_device_data {
> const struct dw_pcie_host_ops *host_ops;
> const struct dw_pcie_ops *ops;
> int (*parse_port)(struct k1_pcie *k1);
> + unsigned int max_phy_count;
Is the name "max_phy_count" meant to suggest that there
could be fewer "actual" PHYs than the number provided in
this field? If not--if it is simply "the number of PHYs
this platform uses"--then just call this phy_count.
> };
>
> struct k1_pcie {
> struct dw_pcie pci;
> const struct k1_pcie_device_data *data;
> - struct phy *phy;
> + struct phy **phy;
> + unsigned int phy_count;
If this is always the same as what's in data->max_phy_count,
you don't need to replicate the value here (since you're
also keeping the data pointer in this structure). (But it
looks like it might be less than max_phy_count.)
I believe I suggested making this structure use a flexible
array member for the PHYs. If that's possible, it should
go at the end of the structure, and the way you allocate
it needs to change.
> void __iomem *link;
> struct regmap *pmu; /* Errors ignored; MMIO-backed regmap */
> u32 pmu_off;
> @@ -119,6 +121,54 @@ static void k1_pcie_disable_resources(struct k1_pcie *k1)
> clk_bulk_disable_unprepare(ARRAY_SIZE(pci->app_clks), pci->app_clks);
> }
>
> +static int k1_pcie_get_phy_handle(struct k1_pcie *k1, struct device_node *node)
I would call this k1_pci_get_phy_handles() (or perhaps
just k1_pci_get_phys()). Or even k1_pci_phy_get_all().
The name you have seems like you're just getting one handle.
> +{
> + const struct k1_pcie_device_data *data = k1->data;
> + struct device *dev = k1->pci.dev;
> + unsigned int i;
> +
> + k1->phy = devm_kmalloc_array(dev, data->max_phy_count,
> + sizeof(*k1->phy), GFP_KERNEL);
Use kzalloc not kmalloc. Even if you're initializing all fields
now, a future change might not (and in that case having it zeroed
is safest).
Also, if you find fewer than max_phy_count PHYs, I think it
would be better to only allocate as many needed. If you
used a flexible array size, you would need to count the
number of entries before allocating it. It would require
changing the structure a bit--providing a single function
that would allocate the k1_pcie structure after doing that,
and most likely initializing the phy array within the same
function.
> + if (!k1->phy)
> + return -ENOMEM;
> +
> + for (i = 0; i < data->max_phy_count; i++) {
> + k1->phy[i] = devm_of_phy_get_by_index(dev, node, i);
> + if (IS_ERR(k1->phy[i])) {
If this returns -ENODEV, you are done getting PHYs. So
max_phy_count could be more than the "actual" number.
Is that reasonable? You indicate that at least one PHY
must be found below, but is it OK for a platform to
define fewer than some expected number of PHYs?
(Maybe it is.)
> + if (PTR_ERR(k1->phy[i]) == -ENODEV)
> + break;
> +
> + return PTR_ERR(k1->phy[i]);
> + }
> + }
> +
> + k1->phy_count = i;
> + if (k1->phy_count == 0)
> + return -EINVAL;
> +
> + return 0;
> +}
> +
> +static int k1_pcie_enable_phy(struct k1_pcie *k1)
I would call this k1_pcie_enable_phys(). But actually,
because what you're calling within this is phy_init(),
I'd probably call it k1_pcie_init_phys(), or possibly
k1_pcie_phy_init_all().
> +{
> + unsigned int i;
> + int ret;
> +
> + for (i = 0; i < k1->phy_count; i++) {
> + ret = phy_init(k1->phy[i]);
> + if (ret)
> + goto err_phy;
> + }
> +
> + return 0;
> +
> +err_phy:
> + while (i--)
> + phy_exit(k1->phy[i]);
> +
> + return ret;
> +}
> +
> /* FIXME: Disable ASPM L1 to avoid errors reported on some NVMe drives */
> static void k1_pcie_disable_aspm_l1(struct k1_pcie *k1)
> {
> @@ -174,7 +224,7 @@ static int k1_pcie_init(struct dw_pcie_rp *pp)
> */
> regmap_set_bits(k1->pmu, reset_ctrl, DEVICE_TYPE_RC | PCIE_AUX_PWR_DET);
>
> - ret = phy_init(k1->phy);
> + ret = k1_pcie_enable_phy(k1);
> if (ret) {
> k1_pcie_disable_resources(k1);
>
> @@ -194,12 +244,14 @@ static void k1_pcie_deinit(struct dw_pcie_rp *pp)
> {
> struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> struct k1_pcie *k1 = to_k1_pcie(pci);
> + int i;
>
> /* Assert fundamental reset (drive PERST# low) */
> regmap_set_bits(k1->pmu, k1->pmu_off + PCIE_CLK_RESET_CONTROL,
> PCIE_RC_PERST);
>
> - phy_exit(k1->phy);
> + for (i = 0; i < k1->phy_count; i++)
> + phy_exit(k1->phy[i]);
Please create an inverse of k1_pcie_enable_phy(), like
k1_pcie_disable_phy(), to encapsulate this code.
>
> k1_pcie_disable_resources(k1);
> }
> @@ -266,23 +318,18 @@ static int k1_pcie_parse_port(struct k1_pcie *k1)
> {
> struct device *dev = k1->pci.dev;
> struct device_node *root_port;
> - struct phy *phy;
> + int ret;
>
> /* We assume only one root port */
Maybe you could get and put the root_port within
k1_pcie_get_phy_handle(), since that's the only
place it's needed.
-Alex
> root_port = of_get_next_available_child(dev_of_node(dev), NULL);
> if (!root_port)
> return -EINVAL;
>
> - phy = devm_of_phy_get(dev, root_port, NULL);
> + ret = k1_pcie_get_phy_handle(k1, root_port);
>
> of_node_put(root_port);
>
> - if (IS_ERR(phy))
> - return PTR_ERR(phy);
> -
> - k1->phy = phy;
> -
> - return 0;
> + return ret;
> }
>
> static int k1_pcie_probe(struct platform_device *pdev)
> @@ -358,6 +405,7 @@ static const struct k1_pcie_device_data k1_pcie_device_data = {
> .host_ops = &k1_pcie_host_ops,
> .ops = &k1_pcie_ops,
> .parse_port = k1_pcie_parse_port,
> + .max_phy_count = 1,
> };
>
> static const struct of_device_id k1_pcie_of_match_table[] = {
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v4 3/6] PCI: spacemit-k1: Add device id update helper
2026-07-09 4:00 [PATCH v4 0/6] riscv: spacemit: Add PCIe RC controller support for K3 Inochi Amaoto
2026-07-09 4:00 ` [PATCH v4 1/6] PCI: spacemit-k1: Add device data support Inochi Amaoto
2026-07-09 4:00 ` [PATCH v4 2/6] PCI: spacemit-k1: Add multiple PHY handles support Inochi Amaoto
@ 2026-07-09 4:00 ` Inochi Amaoto
2026-07-10 16:01 ` Alex Elder
2026-07-09 4:00 ` [PATCH v4 4/6] dt-bindings: PCI: snps,dw-pcie: Add msi-parent for MSI handle check Inochi Amaoto
` (2 subsequent siblings)
5 siblings, 1 reply; 21+ messages in thread
From: Inochi Amaoto @ 2026-07-09 4:00 UTC (permalink / raw)
To: Jingoo Han, Manivannan Sadhasivam, Bjorn Helgaas,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Yixun Lan, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christian Bruel,
Inochi Amaoto, Frank Li, Nam Cao, Qiang Yu,
Krishna Chaitanya Chundru, Xincheng Zhang, Alex Elder,
Siddharth Vadapalli, Andy Shevchenko, Vidya Sagar, Neil Armstrong,
Gustavo Pimentel
Cc: linux-pci, devicetree, linux-kernel, linux-riscv, spacemit,
Yixun Lan, Longbin Li
Both K1 and K3 needs to set vendor id and device id, add a helper function
to simplify this.
Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
---
drivers/pci/controller/dwc/pcie-spacemit-k1.c | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-spacemit-k1.c b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
index e22ecbd09579..31aac056b68e 100644
--- a/drivers/pci/controller/dwc/pcie-spacemit-k1.c
+++ b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
@@ -56,6 +56,7 @@ struct k1_pcie_device_data {
const struct dw_pcie_ops *ops;
int (*parse_port)(struct k1_pcie *k1);
unsigned int max_phy_count;
+ unsigned int device_id;
};
struct k1_pcie {
@@ -186,6 +187,16 @@ static void k1_pcie_disable_aspm_l1(struct k1_pcie *k1)
dw_pcie_dbi_ro_wr_dis(pci);
}
+static void k1_pcie_set_device_id(struct k1_pcie *k1)
+{
+ struct dw_pcie *pci = &k1->pci;
+
+ dw_pcie_dbi_ro_wr_en(pci);
+ dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, PCI_VENDOR_ID_SPACEMIT);
+ dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, k1->data->device_id);
+ dw_pcie_dbi_ro_wr_dis(pci);
+}
+
static int k1_pcie_init(struct dw_pcie_rp *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
@@ -201,10 +212,7 @@ static int k1_pcie_init(struct dw_pcie_rp *pp)
return ret;
/* Set the PCI vendor and device ID */
- dw_pcie_dbi_ro_wr_en(pci);
- dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, PCI_VENDOR_ID_SPACEMIT);
- dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, PCI_DEVICE_ID_SPACEMIT_K1);
- dw_pcie_dbi_ro_wr_dis(pci);
+ k1_pcie_set_device_id(k1);
/*
* Start by asserting fundamental reset (drive PERST# low). The
@@ -406,6 +414,7 @@ static const struct k1_pcie_device_data k1_pcie_device_data = {
.ops = &k1_pcie_ops,
.parse_port = k1_pcie_parse_port,
.max_phy_count = 1,
+ .device_id = PCI_DEVICE_ID_SPACEMIT_K1,
};
static const struct of_device_id k1_pcie_of_match_table[] = {
--
2.55.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 21+ messages in thread* Re: [PATCH v4 3/6] PCI: spacemit-k1: Add device id update helper
2026-07-09 4:00 ` [PATCH v4 3/6] PCI: spacemit-k1: Add device id update helper Inochi Amaoto
@ 2026-07-10 16:01 ` Alex Elder
0 siblings, 0 replies; 21+ messages in thread
From: Alex Elder @ 2026-07-10 16:01 UTC (permalink / raw)
To: Inochi Amaoto, Jingoo Han, Manivannan Sadhasivam, Bjorn Helgaas,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Yixun Lan, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christian Bruel,
Frank Li, Nam Cao, Qiang Yu, Krishna Chaitanya Chundru,
Xincheng Zhang, Siddharth Vadapalli, Andy Shevchenko, Vidya Sagar,
Neil Armstrong, Gustavo Pimentel
Cc: linux-pci, devicetree, linux-kernel, linux-riscv, spacemit,
Yixun Lan, Longbin Li
On 7/8/26 11:00 PM, Inochi Amaoto wrote:
> Both K1 and K3 needs to set vendor id and device id, add a helper function
s/needs/need/
> to simplify this.
I think someone might have commented on this, but I expected to find
that the next patch would fill in the code that's needed to support
K3, but that patch is at the end of your series.
The reason I say it here is that I wondered while looking at this
one why it was needed to create this helper function. I now know
that k3_pcie_init() will call it (but I had to find that in the
last patch, which was later than I expected).
Your series should start with DT binding changes, then code changes,
and (often) end with DTS changes.
Anyway, this looks good.
Reviewed-by: Alex Elder <elder@riscstar.com>
> Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
> ---
> drivers/pci/controller/dwc/pcie-spacemit-k1.c | 17 +++++++++++++----
> 1 file changed, 13 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-spacemit-k1.c b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> index e22ecbd09579..31aac056b68e 100644
> --- a/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> +++ b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> @@ -56,6 +56,7 @@ struct k1_pcie_device_data {
> const struct dw_pcie_ops *ops;
> int (*parse_port)(struct k1_pcie *k1);
> unsigned int max_phy_count;
> + unsigned int device_id;
> };
>
> struct k1_pcie {
> @@ -186,6 +187,16 @@ static void k1_pcie_disable_aspm_l1(struct k1_pcie *k1)
> dw_pcie_dbi_ro_wr_dis(pci);
> }
>
> +static void k1_pcie_set_device_id(struct k1_pcie *k1)
> +{
> + struct dw_pcie *pci = &k1->pci;
> +
> + dw_pcie_dbi_ro_wr_en(pci);
> + dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, PCI_VENDOR_ID_SPACEMIT);
> + dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, k1->data->device_id);
> + dw_pcie_dbi_ro_wr_dis(pci);
> +}
> +
> static int k1_pcie_init(struct dw_pcie_rp *pp)
> {
> struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> @@ -201,10 +212,7 @@ static int k1_pcie_init(struct dw_pcie_rp *pp)
> return ret;
>
> /* Set the PCI vendor and device ID */
> - dw_pcie_dbi_ro_wr_en(pci);
> - dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, PCI_VENDOR_ID_SPACEMIT);
> - dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, PCI_DEVICE_ID_SPACEMIT_K1);
> - dw_pcie_dbi_ro_wr_dis(pci);
> + k1_pcie_set_device_id(k1);
>
> /*
> * Start by asserting fundamental reset (drive PERST# low). The
> @@ -406,6 +414,7 @@ static const struct k1_pcie_device_data k1_pcie_device_data = {
> .ops = &k1_pcie_ops,
> .parse_port = k1_pcie_parse_port,
> .max_phy_count = 1,
> + .device_id = PCI_DEVICE_ID_SPACEMIT_K1,
> };
>
> static const struct of_device_id k1_pcie_of_match_table[] = {
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v4 4/6] dt-bindings: PCI: snps,dw-pcie: Add msi-parent for MSI handle check
2026-07-09 4:00 [PATCH v4 0/6] riscv: spacemit: Add PCIe RC controller support for K3 Inochi Amaoto
` (2 preceding siblings ...)
2026-07-09 4:00 ` [PATCH v4 3/6] PCI: spacemit-k1: Add device id update helper Inochi Amaoto
@ 2026-07-09 4:00 ` Inochi Amaoto
2026-07-10 16:01 ` Alex Elder
2026-07-09 4:00 ` [PATCH v4 5/6] dt-bindings: PCI: spacemit: Introduce Spacemit K3 PCIe host controller Inochi Amaoto
2026-07-09 4:00 ` [PATCH v4 6/6] PCI: spacemit-k1: Add Spacemit K3 PCIe host controller support Inochi Amaoto
5 siblings, 1 reply; 21+ messages in thread
From: Inochi Amaoto @ 2026-07-09 4:00 UTC (permalink / raw)
To: Jingoo Han, Manivannan Sadhasivam, Bjorn Helgaas,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Yixun Lan, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christian Bruel,
Inochi Amaoto, Frank Li, Nam Cao, Qiang Yu,
Krishna Chaitanya Chundru, Xincheng Zhang, Alex Elder,
Siddharth Vadapalli, Andy Shevchenko, Vidya Sagar, Neil Armstrong,
Gustavo Pimentel
Cc: linux-pci, devicetree, linux-kernel, linux-riscv, spacemit,
Yixun Lan, Longbin Li
The IMSIC device on RISC-V based system does not require ID
remapping for MSI. So this device only needs "msi-parent"
property for IMSIC-based SoC, and the "msi-map" is not a
necessary property.
Add new condition for MSI handling on IMSIC based SoC.
Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
Acked-by: Rob Herring (Arm) <robh@kernel.org>
---
Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml b/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml
index b3216141881c..91bbbc8924f6 100644
--- a/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml
@@ -27,8 +27,11 @@ allOf:
- $ref: /schemas/pci/snps,dw-pcie-common.yaml#
- if:
not:
- required:
- - msi-map
+ anyOf:
+ - required:
+ - msi-map
+ - required:
+ - msi-parent
then:
properties:
interrupt-names:
--
2.55.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 21+ messages in thread* Re: [PATCH v4 4/6] dt-bindings: PCI: snps,dw-pcie: Add msi-parent for MSI handle check
2026-07-09 4:00 ` [PATCH v4 4/6] dt-bindings: PCI: snps,dw-pcie: Add msi-parent for MSI handle check Inochi Amaoto
@ 2026-07-10 16:01 ` Alex Elder
0 siblings, 0 replies; 21+ messages in thread
From: Alex Elder @ 2026-07-10 16:01 UTC (permalink / raw)
To: Inochi Amaoto, Jingoo Han, Manivannan Sadhasivam, Bjorn Helgaas,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Yixun Lan, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christian Bruel,
Frank Li, Nam Cao, Qiang Yu, Krishna Chaitanya Chundru,
Xincheng Zhang, Siddharth Vadapalli, Andy Shevchenko, Vidya Sagar,
Neil Armstrong, Gustavo Pimentel
Cc: linux-pci, devicetree, linux-kernel, linux-riscv, spacemit,
Yixun Lan, Longbin Li
On 7/8/26 11:00 PM, Inochi Amaoto wrote:
> The IMSIC device on RISC-V based system does not require ID
> remapping for MSI. So this device only needs "msi-parent"
> property for IMSIC-based SoC, and the "msi-map" is not a
> necessary property.
>
> Add new condition for MSI handling on IMSIC based SoC.
>
> Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
> Acked-by: Rob Herring (Arm) <robh@kernel.org>
I have nothing to add here. -Alex
> ---
> Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml | 7 +++++--
> 1 file changed, 5 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml b/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml
> index b3216141881c..91bbbc8924f6 100644
> --- a/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml
> +++ b/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml
> @@ -27,8 +27,11 @@ allOf:
> - $ref: /schemas/pci/snps,dw-pcie-common.yaml#
> - if:
> not:
> - required:
> - - msi-map
> + anyOf:
> + - required:
> + - msi-map
> + - required:
> + - msi-parent
> then:
> properties:
> interrupt-names:
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v4 5/6] dt-bindings: PCI: spacemit: Introduce Spacemit K3 PCIe host controller
2026-07-09 4:00 [PATCH v4 0/6] riscv: spacemit: Add PCIe RC controller support for K3 Inochi Amaoto
` (3 preceding siblings ...)
2026-07-09 4:00 ` [PATCH v4 4/6] dt-bindings: PCI: snps,dw-pcie: Add msi-parent for MSI handle check Inochi Amaoto
@ 2026-07-09 4:00 ` Inochi Amaoto
2026-07-10 16:01 ` Alex Elder
2026-07-09 4:00 ` [PATCH v4 6/6] PCI: spacemit-k1: Add Spacemit K3 PCIe host controller support Inochi Amaoto
5 siblings, 1 reply; 21+ messages in thread
From: Inochi Amaoto @ 2026-07-09 4:00 UTC (permalink / raw)
To: Jingoo Han, Manivannan Sadhasivam, Bjorn Helgaas,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Yixun Lan, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christian Bruel,
Inochi Amaoto, Frank Li, Nam Cao, Qiang Yu,
Krishna Chaitanya Chundru, Xincheng Zhang, Alex Elder,
Siddharth Vadapalli, Andy Shevchenko, Vidya Sagar, Neil Armstrong,
Gustavo Pimentel
Cc: linux-pci, devicetree, linux-kernel, linux-riscv, spacemit,
Yixun Lan, Longbin Li
Add binding support for the PCIe controller on the SpacemiT K3 SoC.
This controller is almost a standard Synopsys DesignWare PCIe IP,
with some extra link and reset state control.
Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
---
.../bindings/pci/spacemit,k1-pcie-host.yaml | 50 ++++++++++++++++---
1 file changed, 43 insertions(+), 7 deletions(-)
diff --git a/Documentation/devicetree/bindings/pci/spacemit,k1-pcie-host.yaml b/Documentation/devicetree/bindings/pci/spacemit,k1-pcie-host.yaml
index c4c00b5fcdc0..54817d6fd9af 100644
--- a/Documentation/devicetree/bindings/pci/spacemit,k1-pcie-host.yaml
+++ b/Documentation/devicetree/bindings/pci/spacemit,k1-pcie-host.yaml
@@ -14,26 +14,29 @@ description: >
PCIe IP. The controller uses the DesignWare built-in MSI interrupt
controller, and supports 256 MSIs.
-allOf:
- - $ref: /schemas/pci/snps,dw-pcie.yaml#
-
properties:
compatible:
- const: spacemit,k1-pcie
+ enum:
+ - spacemit,k1-pcie
+ - spacemit,k3-pcie
reg:
+ minItems: 4
items:
- description: DesignWare PCIe registers
- description: ATU address space
- description: PCIe configuration space
- description: Link control registers
+ - description: Data Bus Interface (DBI) shadow registers.
reg-names:
+ minItems: 4
items:
- const: dbi
- const: atu
- const: config
- const: link
+ - const: dbi2
clocks:
items:
@@ -66,6 +69,8 @@ properties:
interrupt-names:
const: msi
+ msi-parent: true
+
spacemit,apmu:
$ref: /schemas/types.yaml#/definitions/phandle-array
description:
@@ -84,7 +89,8 @@ patternProperties:
properties:
phys:
- maxItems: 1
+ minItems: 1
+ maxItems: 6
vpcie3v3-supply:
description:
@@ -96,13 +102,43 @@ patternProperties:
unevaluatedProperties: false
+allOf:
+ - $ref: /schemas/pci/snps,dw-pcie.yaml#
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: spacemit,k1-pcie
+ then:
+ properties:
+ reg:
+ maxItems: 4
+
+ reg-names:
+ maxItems: 4
+
+ patternProperties:
+ '^pcie@':
+ properties:
+ phys:
+ maxItems: 1
+
+ required:
+ - interrupts
+ - interrupt-names
+ else:
+ properties:
+ reg:
+ minItems: 5
+
+ reg-names:
+ minItems: 5
+
required:
- clocks
- clock-names
- resets
- reset-names
- - interrupts
- - interrupt-names
- spacemit,apmu
unevaluatedProperties: false
--
2.55.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 21+ messages in thread* Re: [PATCH v4 5/6] dt-bindings: PCI: spacemit: Introduce Spacemit K3 PCIe host controller
2026-07-09 4:00 ` [PATCH v4 5/6] dt-bindings: PCI: spacemit: Introduce Spacemit K3 PCIe host controller Inochi Amaoto
@ 2026-07-10 16:01 ` Alex Elder
0 siblings, 0 replies; 21+ messages in thread
From: Alex Elder @ 2026-07-10 16:01 UTC (permalink / raw)
To: Inochi Amaoto, Jingoo Han, Manivannan Sadhasivam, Bjorn Helgaas,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Yixun Lan, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christian Bruel,
Frank Li, Nam Cao, Qiang Yu, Krishna Chaitanya Chundru,
Xincheng Zhang, Siddharth Vadapalli, Andy Shevchenko, Vidya Sagar,
Neil Armstrong, Gustavo Pimentel
Cc: linux-pci, devicetree, linux-kernel, linux-riscv, spacemit,
Yixun Lan, Longbin Li
On 7/8/26 11:00 PM, Inochi Amaoto wrote:
> Add binding support for the PCIe controller on the SpacemiT K3 SoC.
> This controller is almost a standard Synopsys DesignWare PCIe IP,
> with some extra link and reset state control.
>
> Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
This looks OK to me. What I see is that K3 does not require
the interrupts and interrupt-names properties, allows up to
six PHYs (not just one), and adds a dbi2 register that is not
used by K1.
I might have missed it, but I don't see where the dbi2 register
is used by the K3 code you have added. In pcie-designware.c,
I see that if no "dbi2" resource is found, memory at offset
4096 from the "dbi" base is used. Does that apply for K3?
If so, maybe there's no need to define dbi2.
-Alex
> ---
> .../bindings/pci/spacemit,k1-pcie-host.yaml | 50 ++++++++++++++++---
> 1 file changed, 43 insertions(+), 7 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/pci/spacemit,k1-pcie-host.yaml b/Documentation/devicetree/bindings/pci/spacemit,k1-pcie-host.yaml
> index c4c00b5fcdc0..54817d6fd9af 100644
> --- a/Documentation/devicetree/bindings/pci/spacemit,k1-pcie-host.yaml
> +++ b/Documentation/devicetree/bindings/pci/spacemit,k1-pcie-host.yaml
> @@ -14,26 +14,29 @@ description: >
> PCIe IP. The controller uses the DesignWare built-in MSI interrupt
> controller, and supports 256 MSIs.
>
> -allOf:
> - - $ref: /schemas/pci/snps,dw-pcie.yaml#
> -
> properties:
> compatible:
> - const: spacemit,k1-pcie
> + enum:
> + - spacemit,k1-pcie
> + - spacemit,k3-pcie
>
> reg:
> + minItems: 4
> items:
> - description: DesignWare PCIe registers
> - description: ATU address space
> - description: PCIe configuration space
> - description: Link control registers
> + - description: Data Bus Interface (DBI) shadow registers.
>
> reg-names:
> + minItems: 4
> items:
> - const: dbi
> - const: atu
> - const: config
> - const: link
> + - const: dbi2
>
> clocks:
> items:
> @@ -66,6 +69,8 @@ properties:
> interrupt-names:
> const: msi
>
> + msi-parent: true
> +
> spacemit,apmu:
> $ref: /schemas/types.yaml#/definitions/phandle-array
> description:
> @@ -84,7 +89,8 @@ patternProperties:
>
> properties:
> phys:
> - maxItems: 1
> + minItems: 1
> + maxItems: 6
>
> vpcie3v3-supply:
> description:
> @@ -96,13 +102,43 @@ patternProperties:
>
> unevaluatedProperties: false
>
> +allOf:
> + - $ref: /schemas/pci/snps,dw-pcie.yaml#
> + - if:
> + properties:
> + compatible:
> + contains:
> + const: spacemit,k1-pcie
> + then:
> + properties:
> + reg:
> + maxItems: 4
> +
> + reg-names:
> + maxItems: 4
> +
> + patternProperties:
> + '^pcie@':
> + properties:
> + phys:
> + maxItems: 1
> +
> + required:
> + - interrupts
> + - interrupt-names
> + else:
> + properties:
> + reg:
> + minItems: 5
> +
> + reg-names:
> + minItems: 5
> +
> required:
> - clocks
> - clock-names
> - resets
> - reset-names
> - - interrupts
> - - interrupt-names
> - spacemit,apmu
>
> unevaluatedProperties: false
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v4 6/6] PCI: spacemit-k1: Add Spacemit K3 PCIe host controller support
2026-07-09 4:00 [PATCH v4 0/6] riscv: spacemit: Add PCIe RC controller support for K3 Inochi Amaoto
` (4 preceding siblings ...)
2026-07-09 4:00 ` [PATCH v4 5/6] dt-bindings: PCI: spacemit: Introduce Spacemit K3 PCIe host controller Inochi Amaoto
@ 2026-07-09 4:00 ` Inochi Amaoto
2026-07-09 7:21 ` Andy Shevchenko
2026-07-10 16:01 ` Alex Elder
5 siblings, 2 replies; 21+ messages in thread
From: Inochi Amaoto @ 2026-07-09 4:00 UTC (permalink / raw)
To: Jingoo Han, Manivannan Sadhasivam, Bjorn Helgaas,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Yixun Lan, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christian Bruel,
Inochi Amaoto, Frank Li, Nam Cao, Qiang Yu,
Krishna Chaitanya Chundru, Xincheng Zhang, Alex Elder,
Siddharth Vadapalli, Andy Shevchenko, Vidya Sagar, Neil Armstrong,
Gustavo Pimentel
Cc: linux-pci, devicetree, linux-kernel, linux-riscv, spacemit,
Yixun Lan, Longbin Li
The PCIe controller on Spacemit K3 is almost a standard Synopsys
DesignWare PCIe IP with extra link and reset control. Unlike
the PCIe controller on K1, this controller supports external MSI
interrupt controller and can use multiple PHYs at the same time.
Add driver to support PCIe controller on Spacemit K3 PCIe.
Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
---
drivers/pci/controller/dwc/Kconfig | 4 +-
drivers/pci/controller/dwc/pcie-spacemit-k1.c | 126 ++++++++++++++++++
2 files changed, 128 insertions(+), 2 deletions(-)
diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
index aa0b784c85b4..dacbac5cc35c 100644
--- a/drivers/pci/controller/dwc/Kconfig
+++ b/drivers/pci/controller/dwc/Kconfig
@@ -440,7 +440,7 @@ config PCIE_SOPHGO_DW
Sophgo SoCs.
config PCIE_SPACEMIT_K1
- tristate "SpacemiT K1 PCIe controller (host mode)"
+ tristate "SpacemiT PCIe controller (host mode)"
depends on ARCH_SPACEMIT || COMPILE_TEST
depends on HAS_IOMEM
select PCIE_DW_HOST
@@ -448,7 +448,7 @@ config PCIE_SPACEMIT_K1
default ARCH_SPACEMIT
help
Enables support for the DesignWare based PCIe controller in
- the SpacemiT K1 SoC operating in host mode. Three controllers
+ the SpacemiT SoC operating in host mode. Three controllers
are available on the K1 SoC; the first of these shares a PHY
with a USB 3.0 host controller (one or the other can be used).
diff --git a/drivers/pci/controller/dwc/pcie-spacemit-k1.c b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
index 31aac056b68e..680acc93f539 100644
--- a/drivers/pci/controller/dwc/pcie-spacemit-k1.c
+++ b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
@@ -23,6 +23,7 @@
#define PCI_VENDOR_ID_SPACEMIT 0x201f
#define PCI_DEVICE_ID_SPACEMIT_K1 0x0001
+#define PCI_DEVICE_ID_SPACEMIT_K3 0x0002
/* Offsets and field definitions for link management registers */
#define K1_PHY_AHB_IRQ_EN 0x0000
@@ -32,8 +33,18 @@
#define SMLH_LINK_UP BIT(1)
#define RDLH_LINK_UP BIT(12)
+#define INTR_STATUS 0x0010
+
#define INTR_ENABLE 0x0014
#define MSI_CTRL_INT BIT(11)
+#define RDLH_LINK_UP_INT BIT(20)
+
+#define K3_PHY_AHB_IRQSTATUS_INTX 0x0008
+
+#define K3_ADDR_INTR_STATUS1 0x0018
+
+#define K3_CACHE_MSTR_AWCACHE_MODE GENMASK(14, 11)
+#define K3_CACHE_MSTR_AWCACHE_BEHAVIOR 0xf
/* Some controls require APMU regmap access */
#define SYSCON_APMU "spacemit,apmu"
@@ -48,6 +59,9 @@
#define PCIE_CONTROL_LOGIC 0x0004
#define PCIE_SOFT_RESET BIT(0)
+#define PCIE_PERSTN_OE BIT(24)
+#define PCIE_PERSTN_OUT BIT(25)
+#define PCIE_IGNORE_PERSTN BIT(31)
struct k1_pcie;
@@ -340,6 +354,109 @@ static int k1_pcie_parse_port(struct k1_pcie *k1)
return ret;
}
+static int k3_pcie_init(struct dw_pcie_rp *pp)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct k1_pcie *k1 = to_k1_pcie(pci);
+ u32 reset_ctrl = k1->pmu_off + PCIE_CLK_RESET_CONTROL;
+ u32 val;
+ int ret;
+
+ regmap_clear_bits(k1->pmu, reset_ctrl, LTSSM_EN);
+
+ k1_pcie_toggle_soft_reset(k1);
+
+ ret = k1_pcie_enable_resources(k1);
+ if (ret)
+ return ret;
+
+ regmap_set_bits(k1->pmu, reset_ctrl, PCIE_AUX_PWR_DET);
+ regmap_clear_bits(k1->pmu, reset_ctrl, APP_HOLD_PHY_RST);
+
+ ret = k1_pcie_enable_phy(k1);
+ if (ret) {
+ k1_pcie_disable_resources(k1);
+ return ret;
+ }
+
+ /* K3: Set IGNORE_PERSTN and drive PERSTN_OE high (assert reset) */
+ regmap_set_bits(k1->pmu, k1->pmu_off + PCIE_CONTROL_LOGIC,
+ PCIE_IGNORE_PERSTN | PCIE_PERSTN_OE | PCIE_PERSTN_OUT);
+ usleep_range(1000, 2000);
+ regmap_clear_bits(k1->pmu, k1->pmu_off + PCIE_CONTROL_LOGIC, PCIE_PERSTN_OUT);
+
+ msleep(PCIE_T_PVPERL_MS);
+
+ /*
+ * Put the controller in root complex mode, and indicate that
+ * Vaux (3.3v) is present.
+ */
+ regmap_set_bits(k1->pmu, k1->pmu_off + PCIE_CONTROL_LOGIC,
+ PCIE_PERSTN_OUT | PCIE_PERSTN_OE);
+
+ val = dw_pcie_readl_dbi(pci, GEN3_EQ_CONTROL_OFF);
+ val = u32_replace_bits(val, BIT(7),
+ GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC);
+ dw_pcie_writel_dbi(pci, GEN3_EQ_CONTROL_OFF, val);
+
+ k1_pcie_set_device_id(k1);
+
+ /* Finally, as a workaround, disable ASPM L1 */
+ k1_pcie_disable_aspm_l1(k1);
+
+ return 0;
+}
+
+static int k3_pcie_msi_host_init(struct dw_pcie_rp *pp)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ u32 val;
+
+ dw_pcie_dbi_ro_wr_en(pci);
+
+ val = dw_pcie_readl_dbi(pci, COHERENCY_CONTROL_3_OFF);
+ val = u32_replace_bits(val, K3_CACHE_MSTR_AWCACHE_BEHAVIOR,
+ K3_CACHE_MSTR_AWCACHE_MODE);
+ dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_3_OFF, val);
+
+ dw_pcie_dbi_ro_wr_dis(pci);
+
+ return 0;
+}
+
+static const struct dw_pcie_host_ops k3_pcie_host_ops = {
+ .init = k3_pcie_init,
+ .deinit = k1_pcie_deinit,
+ .msi_init = k3_pcie_msi_host_init,
+};
+
+static const struct dw_pcie_ops k3_pcie_ops = {
+ .link_up = k1_pcie_link_up,
+ .start_link = k1_pcie_start_link,
+ .stop_link = k1_pcie_stop_link,
+};
+
+static void k3_pcie_clear_irq_status(struct k1_pcie *k1,
+ u32 *status0, u32 *status1, u32 *status2)
+{
+ *status0 = readl_relaxed(k1->link + K3_PHY_AHB_IRQSTATUS_INTX);
+ *status1 = readl_relaxed(k1->link + INTR_STATUS);
+ *status2 = readl_relaxed(k1->link + K3_ADDR_INTR_STATUS1);
+
+ writel_relaxed(*status0, k1->link + K3_PHY_AHB_IRQSTATUS_INTX);
+ writel_relaxed(*status1, k1->link + INTR_STATUS);
+ writel_relaxed(*status2, k1->link + K3_ADDR_INTR_STATUS1);
+}
+
+static int k3_pcie_parse_port(struct k1_pcie *k1)
+{
+ u32 status0, status1, status2;
+
+ k3_pcie_clear_irq_status(k1, &status0, &status1, &status2);
+
+ return k1_pcie_parse_port(k1);
+}
+
static int k1_pcie_probe(struct platform_device *pdev)
{
const struct k1_pcie_device_data *data;
@@ -417,8 +534,17 @@ static const struct k1_pcie_device_data k1_pcie_device_data = {
.device_id = PCI_DEVICE_ID_SPACEMIT_K1,
};
+static const struct k1_pcie_device_data k3_pcie_device_data = {
+ .host_ops = &k3_pcie_host_ops,
+ .ops = &k3_pcie_ops,
+ .parse_port = k3_pcie_parse_port,
+ .max_phy_count = 6,
+ .device_id = PCI_DEVICE_ID_SPACEMIT_K3,
+};
+
static const struct of_device_id k1_pcie_of_match_table[] = {
{ .compatible = "spacemit,k1-pcie", .data = &k1_pcie_device_data},
+ { .compatible = "spacemit,k3-pcie", .data = &k3_pcie_device_data},
{ }
};
--
2.55.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 21+ messages in thread* Re: [PATCH v4 6/6] PCI: spacemit-k1: Add Spacemit K3 PCIe host controller support
2026-07-09 4:00 ` [PATCH v4 6/6] PCI: spacemit-k1: Add Spacemit K3 PCIe host controller support Inochi Amaoto
@ 2026-07-09 7:21 ` Andy Shevchenko
2026-07-10 16:01 ` Alex Elder
1 sibling, 0 replies; 21+ messages in thread
From: Andy Shevchenko @ 2026-07-09 7:21 UTC (permalink / raw)
To: Inochi Amaoto
Cc: Jingoo Han, Manivannan Sadhasivam, Bjorn Helgaas,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Yixun Lan, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christian Bruel,
Frank Li, Nam Cao, Qiang Yu, Krishna Chaitanya Chundru,
Xincheng Zhang, Alex Elder, Siddharth Vadapalli, Vidya Sagar,
Neil Armstrong, Gustavo Pimentel, linux-pci, devicetree,
linux-kernel, linux-riscv, spacemit, Yixun Lan, Longbin Li
On Thu, Jul 09, 2026 at 12:00:26PM +0800, Inochi Amaoto wrote:
> The PCIe controller on Spacemit K3 is almost a standard Synopsys
> DesignWare PCIe IP with extra link and reset control. Unlike
> the PCIe controller on K1, this controller supports external MSI
> interrupt controller and can use multiple PHYs at the same time.
>
> Add driver to support PCIe controller on Spacemit K3 PCIe.
...
> + /* K3: Set IGNORE_PERSTN and drive PERSTN_OE high (assert reset) */
> + regmap_set_bits(k1->pmu, k1->pmu_off + PCIE_CONTROL_LOGIC,
> + PCIE_IGNORE_PERSTN | PCIE_PERSTN_OE | PCIE_PERSTN_OUT);
> + usleep_range(1000, 2000);
fsleep(1 * USEC_PER_MSEC)
> + regmap_clear_bits(k1->pmu, k1->pmu_off + PCIE_CONTROL_LOGIC, PCIE_PERSTN_OUT);
> +
> + msleep(PCIE_T_PVPERL_MS);
If PCIE_T_PVPERL_MS is too small, msleep() maybe not a good choice,
perhaps
fsleep(PCIE_T_PVPERL_MS * USEC_PER_MSEC)
...
> + val = u32_replace_bits(val, BIT(7),
> + GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC);
It's perfectly a single line.
...
> static const struct of_device_id k1_pcie_of_match_table[] = {
> { .compatible = "spacemit,k1-pcie", .data = &k1_pcie_device_data},
> + { .compatible = "spacemit,k3-pcie", .data = &k3_pcie_device_data},
Missed space.
> { }
> };
I don't see (and haven't checked) the context, do you have
MODULE_DEVICE_TABLE() for this?
--
With Best Regards,
Andy Shevchenko
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH v4 6/6] PCI: spacemit-k1: Add Spacemit K3 PCIe host controller support
2026-07-09 4:00 ` [PATCH v4 6/6] PCI: spacemit-k1: Add Spacemit K3 PCIe host controller support Inochi Amaoto
2026-07-09 7:21 ` Andy Shevchenko
@ 2026-07-10 16:01 ` Alex Elder
1 sibling, 0 replies; 21+ messages in thread
From: Alex Elder @ 2026-07-10 16:01 UTC (permalink / raw)
To: Inochi Amaoto, Jingoo Han, Manivannan Sadhasivam, Bjorn Helgaas,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Yixun Lan, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Christian Bruel,
Frank Li, Nam Cao, Qiang Yu, Krishna Chaitanya Chundru,
Xincheng Zhang, Siddharth Vadapalli, Andy Shevchenko, Vidya Sagar,
Neil Armstrong, Gustavo Pimentel
Cc: linux-pci, devicetree, linux-kernel, linux-riscv, spacemit,
Yixun Lan, Longbin Li
On 7/8/26 11:00 PM, Inochi Amaoto wrote:
> The PCIe controller on Spacemit K3 is almost a standard Synopsys
> DesignWare PCIe IP with extra link and reset control. Unlike
> the PCIe controller on K1, this controller supports external MSI
> interrupt controller and can use multiple PHYs at the same time.
>
> Add driver to support PCIe controller on Spacemit K3 PCIe.
I think it would be good to summarize how the K3 differs from
the K1 here as well, since they're sharing code. It looks
like it supports up to 6 PHYs, not just 1 (as the K1 does).
> Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
> ---
> drivers/pci/controller/dwc/Kconfig | 4 +-
> drivers/pci/controller/dwc/pcie-spacemit-k1.c | 126 ++++++++++++++++++
> 2 files changed, 128 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
> index aa0b784c85b4..dacbac5cc35c 100644
> --- a/drivers/pci/controller/dwc/Kconfig
> +++ b/drivers/pci/controller/dwc/Kconfig
> @@ -440,7 +440,7 @@ config PCIE_SOPHGO_DW
> Sophgo SoCs.
>
> config PCIE_SPACEMIT_K1
> - tristate "SpacemiT K1 PCIe controller (host mode)"
> + tristate "SpacemiT PCIe controller (host mode)"
> depends on ARCH_SPACEMIT || COMPILE_TEST
> depends on HAS_IOMEM
> select PCIE_DW_HOST
> @@ -448,7 +448,7 @@ config PCIE_SPACEMIT_K1
> default ARCH_SPACEMIT
> help
> Enables support for the DesignWare based PCIe controller in
> - the SpacemiT K1 SoC operating in host mode. Three controllers
> + the SpacemiT SoC operating in host mode. Three controllers
> are available on the K1 SoC; the first of these shares a PHY
> with a USB 3.0 host controller (one or the other can be used).
>
> diff --git a/drivers/pci/controller/dwc/pcie-spacemit-k1.c b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> index 31aac056b68e..680acc93f539 100644
> --- a/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> +++ b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> @@ -23,6 +23,7 @@
>
> #define PCI_VENDOR_ID_SPACEMIT 0x201f
> #define PCI_DEVICE_ID_SPACEMIT_K1 0x0001
> +#define PCI_DEVICE_ID_SPACEMIT_K3 0x0002
>
> /* Offsets and field definitions for link management registers */
> #define K1_PHY_AHB_IRQ_EN 0x0000
> @@ -32,8 +33,18 @@
> #define SMLH_LINK_UP BIT(1)
> #define RDLH_LINK_UP BIT(12)
>
> +#define INTR_STATUS 0x0010
This register offset should probably be named K3_PHY_INTR_STATUS
(or maybe it's just K3_INTR_STATUS?). I see that INTR_ENABLE
doesn't have a prefix, and I don't know why--that should have
a similar name. (Please fix that in your next version as well;
I think it's OK to included it with this patch with a simple
mention in the patch description.)
> +
> #define INTR_ENABLE 0x0014
> #define MSI_CTRL_INT BIT(11)
> +#define RDLH_LINK_UP_INT BIT(20)
> +
> +#define K3_PHY_AHB_IRQSTATUS_INTX 0x0008
So is this enabling INTX support? If so, you should do that
first in a separate patch that only applies to K1 (and that
should be verified to work correctly). If all you're doing
is ensuring the status is cleared, that's OK here, but if
you don't enable it I'm not sure it matters.
> +
> +#define K3_ADDR_INTR_STATUS1 0x0018
> +
> +#define K3_CACHE_MSTR_AWCACHE_MODE GENMASK(14, 11)
> +#define K3_CACHE_MSTR_AWCACHE_BEHAVIOR 0xf
>
> /* Some controls require APMU regmap access */
> #define SYSCON_APMU "spacemit,apmu"
> @@ -48,6 +59,9 @@
>
> #define PCIE_CONTROL_LOGIC 0x0004
> #define PCIE_SOFT_RESET BIT(0)
> +#define PCIE_PERSTN_OE BIT(24)
> +#define PCIE_PERSTN_OUT BIT(25)
> +#define PCIE_IGNORE_PERSTN BIT(31)
>
> struct k1_pcie;
>
> @@ -340,6 +354,109 @@ static int k1_pcie_parse_port(struct k1_pcie *k1)
> return ret;
> }
>
I ask a few questions in this function; I'm basically
asking "are you *sure* this must be different for K3
than K1?" Because for the most part this function looks
very similar to k1_pcie_init().
> +static int k3_pcie_init(struct dw_pcie_rp *pp)
> +{
> + struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> + struct k1_pcie *k1 = to_k1_pcie(pci);
> + u32 reset_ctrl = k1->pmu_off + PCIE_CLK_RESET_CONTROL;
> + u32 val;
> + int ret;
> +
> + regmap_clear_bits(k1->pmu, reset_ctrl, LTSSM_EN);
Would it be OK to clear this bit in the reset control
register for K1 as well?
> +
> + k1_pcie_toggle_soft_reset(k1);
> +
> + ret = k1_pcie_enable_resources(k1);
> + if (ret)
> + return ret;
> +
> + regmap_set_bits(k1->pmu, reset_ctrl, PCIE_AUX_PWR_DET);
> + regmap_clear_bits(k1->pmu, reset_ctrl, APP_HOLD_PHY_RST);
> +
> + ret = k1_pcie_enable_phy(k1);
> + if (ret) {
> + k1_pcie_disable_resources(k1);
> + return ret;
> + }
> +
The handling of PERSTN looks different for K3 than K1. Could you
implement a helper function that abstracts the differences?
I don't really understand what's happening here, but if it's
comparable to this for K1:
/* Deassert fundamental reset (drive PERST# high) */
regmap_clear_bits(k1->pmu, reset_ctrl, PCIE_RC_PERST);
...then a callback function (similar to parse_port) in the device
data might be able to be called for both platforms, allowing
the init function to be common for both.
> + /* K3: Set IGNORE_PERSTN and drive PERSTN_OE high (assert reset) */
> + regmap_set_bits(k1->pmu, k1->pmu_off + PCIE_CONTROL_LOGIC,
> + PCIE_IGNORE_PERSTN | PCIE_PERSTN_OE | PCIE_PERSTN_OUT);
> + usleep_range(1000, 2000);
> + regmap_clear_bits(k1->pmu, k1->pmu_off + PCIE_CONTROL_LOGIC, PCIE_PERSTN_OUT);
> +
> + msleep(PCIE_T_PVPERL_MS);
> +
> + /*
> + * Put the controller in root complex mode, and indicate that
> + * Vaux (3.3v) is present.
Here too, you could abstract what's happening and that might
allow the init function to be common for both (all) platforms.
> + */
> + regmap_set_bits(k1->pmu, k1->pmu_off + PCIE_CONTROL_LOGIC,
> + PCIE_PERSTN_OUT | PCIE_PERSTN_OE);
> +
> + val = dw_pcie_readl_dbi(pci, GEN3_EQ_CONTROL_OFF);
> + val = u32_replace_bits(val, BIT(7),
> + GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC);
> + dw_pcie_writel_dbi(pci, GEN3_EQ_CONTROL_OFF, val);
> +
> + k1_pcie_set_device_id(k1);
This is done earlier in k1_pcie_init(). Could it be done at the
same time for both platforms?
> +
> + /* Finally, as a workaround, disable ASPM L1 */
> + k1_pcie_disable_aspm_l1(k1);
> +
> + return 0;
> +}
> +
> +static int k3_pcie_msi_host_init(struct dw_pcie_rp *pp)
Why is this needed for K3, but not for K1? Does this
enable any functionality that K1 could use and benefit
from?
> +{
> + struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> + u32 val;
> +
> + dw_pcie_dbi_ro_wr_en(pci);
> +
> + val = dw_pcie_readl_dbi(pci, COHERENCY_CONTROL_3_OFF);
> + val = u32_replace_bits(val, K3_CACHE_MSTR_AWCACHE_BEHAVIOR,
> + K3_CACHE_MSTR_AWCACHE_MODE);
> + dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_3_OFF, val);
> +
> + dw_pcie_dbi_ro_wr_dis(pci);
> +
> + return 0;
> +}
> +
> +static const struct dw_pcie_host_ops k3_pcie_host_ops = {
> + .init = k3_pcie_init,
> + .deinit = k1_pcie_deinit,
> + .msi_init = k3_pcie_msi_host_init,
> +};
> +
> +static const struct dw_pcie_ops k3_pcie_ops = {
This is identical to k1_pcie_ops, so isn't needed.
> + .link_up = k1_pcie_link_up,
> + .start_link = k1_pcie_start_link,
> + .stop_link = k1_pcie_stop_link,
> +};
> +
> +static void k3_pcie_clear_irq_status(struct k1_pcie *k1,
> + u32 *status0, u32 *status1, u32 *status2)
I don't see any value in this helper function, at
least not based on how it's used now. It is used
exactly once, to clear (by writing) three interrupt
status registers. Just do that inline.
Even if you want to use this helper function in a
second place (when handling the itnerrupt), don't
pass in these status arguments, they're not needed
in the caller. Just define them here.
Also you could read/write each register, and use
a single local variable (status) to hold the value
read and written.
> +{
> + *status0 = readl_relaxed(k1->link + K3_PHY_AHB_IRQSTATUS_INTX);
> + *status1 = readl_relaxed(k1->link + INTR_STATUS);
> + *status2 = readl_relaxed(k1->link + K3_ADDR_INTR_STATUS1);
> +
> + writel_relaxed(*status0, k1->link + K3_PHY_AHB_IRQSTATUS_INTX);
> + writel_relaxed(*status1, k1->link + INTR_STATUS);
> + writel_relaxed(*status2, k1->link + K3_ADDR_INTR_STATUS1);
> +}
> +
> +static int k3_pcie_parse_port(struct k1_pcie *k1)
> +{
> + u32 status0, status1, status2;
> +
> + k3_pcie_clear_irq_status(k1, &status0, &status1, &status2);
Is it really necessary to clear the IRQ status *only* for K3?
It seems like it would be a good idea (or at least harmless)
to do it for K1 as well. And in that case, it should just be
added to the existing k1_pcie_parse_port() function.
> +
> + return k1_pcie_parse_port(k1);
> +}
> +
> static int k1_pcie_probe(struct platform_device *pdev)
> {
> const struct k1_pcie_device_data *data;
> @@ -417,8 +534,17 @@ static const struct k1_pcie_device_data k1_pcie_device_data = {
> .device_id = PCI_DEVICE_ID_SPACEMIT_K1,
> };
>
> +static const struct k1_pcie_device_data k3_pcie_device_data = {
> + .host_ops = &k3_pcie_host_ops,
> + .ops = &k3_pcie_ops,
I think ops could just point to k1_pcie_ops here.
-Alex
> + .parse_port = k3_pcie_parse_port,
> + .max_phy_count = 6,
> + .device_id = PCI_DEVICE_ID_SPACEMIT_K3,
> +};
> +
> static const struct of_device_id k1_pcie_of_match_table[] = {
> { .compatible = "spacemit,k1-pcie", .data = &k1_pcie_device_data},
> + { .compatible = "spacemit,k3-pcie", .data = &k3_pcie_device_data},
> { }
> };
>
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 21+ messages in thread