This patch series add slot support to pci-mvebu.c driver.
It is based on branch pci/mvebu of git repository:
https://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/pci.git
Changes in v2:
* Dropped patch with PCI_EXP_SLTCAP_*_SHIFT macros as it is not needed anymore
* Dropped patch "ARM: dts: turris-omnia: Set PCIe slot-power-limit-milliwatt properties" which was applied
* Added support for PCIe 6.0 slot power limit encodings
* Round down slot power limit value
* Fix handling of slot power limit with scale x1.0 (0x00 value)
* Use FIELD_PREP instead of _SHIFT macros
* Changed commit message to Bjorn's suggestion
* Changed comments in the code to match PCIe spec
* Preserve user settings of PCI_EXP_SLTCTL_ASPL_DISABLE bit
Pali Rohár (4):
PCI: Add PCI_EXP_SLTCTL_ASPL_DISABLE macro
dt-bindings: Add 'slot-power-limit-milliwatt' PCIe port property
PCI: Add function for parsing 'slot-power-limit-milliwatt' DT property
PCI: mvebu: Add support for sending Set_Slot_Power_Limit message
Documentation/devicetree/bindings/pci/pci.txt | 6 ++
drivers/pci/controller/pci-mvebu.c | 96 ++++++++++++++++++-
drivers/pci/of.c | 64 +++++++++++++
drivers/pci/pci.h | 15 +++
include/uapi/linux/pci_regs.h | 1 +
5 files changed, 177 insertions(+), 5 deletions(-)
--
2.20.1
If DT supplies the 'slot-power-limit-milliwatt' property, program
the value in the Slot Power Limit in the Slot Capabilities register
and program the Root Port to send a Set_Slot_Power_Limit Message
when the Link transitions to DL_Up.
Signed-off-by: Pali Rohár <[email protected]>
---
Changes in v2:
* Fix handling of slot power limit with scale x1.0 (0x00 value)
* Use FIELD_PREP instead of _SHIFT macros
* Changed commit message to Bjorn's suggestion
* Changed comments in the code to match PCIe spec
* Preserve user settings of PCI_EXP_SLTCTL_ASPL_DISABLE bit
---
drivers/pci/controller/pci-mvebu.c | 96 ++++++++++++++++++++++++++++--
1 file changed, 91 insertions(+), 5 deletions(-)
diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c
index a75d2b9196f9..26ae7c29fece 100644
--- a/drivers/pci/controller/pci-mvebu.c
+++ b/drivers/pci/controller/pci-mvebu.c
@@ -8,6 +8,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio.h>
@@ -66,6 +67,12 @@
#define PCIE_STAT_BUS 0xff00
#define PCIE_STAT_DEV 0x1f0000
#define PCIE_STAT_LINK_DOWN BIT(0)
+#define PCIE_SSPL_OFF 0x1a0c
+#define PCIE_SSPL_VALUE_SHIFT 0
+#define PCIE_SSPL_VALUE_MASK GENMASK(7, 0)
+#define PCIE_SSPL_SCALE_SHIFT 8
+#define PCIE_SSPL_SCALE_MASK GENMASK(9, 8)
+#define PCIE_SSPL_ENABLE BIT(16)
#define PCIE_RC_RTSTA 0x1a14
#define PCIE_DEBUG_CTRL 0x1a60
#define PCIE_DEBUG_SOFT_RESET BIT(20)
@@ -111,6 +118,8 @@ struct mvebu_pcie_port {
struct mvebu_pcie_window iowin;
u32 saved_pcie_stat;
struct resource regs;
+ u8 slot_power_limit_value;
+ u8 slot_power_limit_scale;
struct irq_domain *intx_irq_domain;
raw_spinlock_t irq_lock;
int intx_irq;
@@ -239,7 +248,7 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie_port *port)
static void mvebu_pcie_setup_hw(struct mvebu_pcie_port *port)
{
- u32 ctrl, lnkcap, cmd, dev_rev, unmask;
+ u32 ctrl, lnkcap, cmd, dev_rev, unmask, sspl;
/* Setup PCIe controller to Root Complex mode. */
ctrl = mvebu_readl(port, PCIE_CTRL_OFF);
@@ -292,6 +301,20 @@ static void mvebu_pcie_setup_hw(struct mvebu_pcie_port *port)
/* Point PCIe unit MBUS decode windows to DRAM space. */
mvebu_pcie_setup_wins(port);
+ /*
+ * Program Root Port to automatically send Set_Slot_Power_Limit
+ * PCIe Message when changing status from Dl_Down to Dl_Up and valid
+ * slot power limit was specified.
+ */
+ sspl = mvebu_readl(port, PCIE_SSPL_OFF);
+ sspl &= ~(PCIE_SSPL_VALUE_MASK | PCIE_SSPL_SCALE_MASK | PCIE_SSPL_ENABLE);
+ if (port->slot_power_limit_value) {
+ sspl |= port->slot_power_limit_value << PCIE_SSPL_VALUE_SHIFT;
+ sspl |= port->slot_power_limit_scale << PCIE_SSPL_SCALE_SHIFT;
+ sspl |= PCIE_SSPL_ENABLE;
+ }
+ mvebu_writel(port, sspl, PCIE_SSPL_OFF);
+
/* Mask all interrupt sources. */
mvebu_writel(port, ~PCIE_INT_ALL_MASK, PCIE_INT_UNMASK_OFF);
@@ -628,9 +651,23 @@ mvebu_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge,
(PCI_EXP_LNKSTA_DLLLA << 16) : 0);
break;
- case PCI_EXP_SLTCTL:
- *value = PCI_EXP_SLTSTA_PDS << 16;
+ case PCI_EXP_SLTCTL: {
+ u16 slotsta = le16_to_cpu(bridge->pcie_conf.slotsta);
+ u32 val = 0;
+ /*
+ * When slot power limit was not specified in DT then
+ * ASPL_DISABLE bit is stored only in emulated config space.
+ * Otherwise reflect status of PCIE_SSPL_ENABLE bit in HW.
+ */
+ if (!port->slot_power_limit_value)
+ val |= slotctl & PCI_EXP_SLTCTL_ASPL_DISABLE;
+ else if (!(mvebu_readl(port, PCIE_SSPL_OFF) & PCIE_SSPL_ENABLE))
+ val |= PCI_EXP_SLTCTL_ASPL_DISABLE;
+ /* This callback is 32-bit and in high bits is slot status. */
+ val |= slotsta << 16;
+ *value = val;
break;
+ }
case PCI_EXP_RTSTA:
*value = mvebu_readl(port, PCIE_RC_RTSTA);
@@ -774,6 +811,22 @@ mvebu_pci_bridge_emul_pcie_conf_write(struct pci_bridge_emul *bridge,
mvebu_writel(port, new, PCIE_CAP_PCIEXP + PCI_EXP_LNKCTL);
break;
+ case PCI_EXP_SLTCTL:
+ /*
+ * Allow to change PCIE_SSPL_ENABLE bit only when slot power
+ * limit was specified in DT and configured into HW.
+ */
+ if ((mask & PCI_EXP_SLTCTL_ASPL_DISABLE) &&
+ port->slot_power_limit_value) {
+ u32 sspl = mvebu_readl(port, PCIE_SSPL_OFF);
+ if (new & PCI_EXP_SLTCTL_ASPL_DISABLE)
+ sspl &= ~PCIE_SSPL_ENABLE;
+ else
+ sspl |= PCIE_SSPL_ENABLE;
+ mvebu_writel(port, sspl, PCIE_SSPL_OFF);
+ }
+ break;
+
case PCI_EXP_RTSTA:
/*
* PME Status bit in Root Status Register (PCIE_RC_RTSTA)
@@ -868,8 +921,26 @@ static int mvebu_pci_bridge_emul_init(struct mvebu_pcie_port *port)
/*
* Older mvebu hardware provides PCIe Capability structure only in
* version 1. New hardware provides it in version 2.
+ * Enable slot support which is emulated.
*/
- bridge->pcie_conf.cap = cpu_to_le16(pcie_cap_ver);
+ bridge->pcie_conf.cap = cpu_to_le16(pcie_cap_ver | PCI_EXP_FLAGS_SLOT);
+
+ /*
+ * Set Presence Detect State bit permanently as there is no support for
+ * unplugging PCIe card from the slot. Assume that PCIe card is always
+ * connected in slot.
+ *
+ * Set physical slot number to port+1 as mvebu ports are indexed from
+ * zero and zero value is reserved for ports within the same silicon
+ * as Root Port which is not mvebu case.
+ *
+ * Also set correct slot power limit.
+ */
+ bridge->pcie_conf.slotcap = cpu_to_le32(
+ FIELD_PREP(PCI_EXP_SLTCAP_SPLV, port->slot_power_limit_value) |
+ FIELD_PREP(PCI_EXP_SLTCAP_SPLS, port->slot_power_limit_scale) |
+ FIELD_PREP(PCI_EXP_SLTCAP_PSN, port->port+1));
+ bridge->pcie_conf.slotsta = cpu_to_le16(PCI_EXP_SLTSTA_PDS);
bridge->subsystem_vendor_id = ssdev_id & 0xffff;
bridge->subsystem_id = ssdev_id >> 16;
@@ -1191,6 +1262,7 @@ static int mvebu_pcie_parse_port(struct mvebu_pcie *pcie,
{
struct device *dev = &pcie->pdev->dev;
enum of_gpio_flags flags;
+ u32 slot_power_limit;
int reset_gpio, ret;
u32 num_lanes;
@@ -1291,6 +1363,15 @@ static int mvebu_pcie_parse_port(struct mvebu_pcie *pcie,
port->reset_gpio = gpio_to_desc(reset_gpio);
}
+ slot_power_limit = of_pci_get_slot_power_limit(child,
+ &port->slot_power_limit_value,
+ &port->slot_power_limit_scale);
+ if (slot_power_limit)
+ dev_info(dev, "%s: Slot power limit %u.%uW\n",
+ port->name,
+ slot_power_limit / 1000,
+ (slot_power_limit / 100) % 10);
+
port->clk = of_clk_get_by_name(child, NULL);
if (IS_ERR(port->clk)) {
dev_err(dev, "%s: cannot get clock\n", port->name);
@@ -1587,7 +1668,7 @@ static int mvebu_pcie_remove(struct platform_device *pdev)
{
struct mvebu_pcie *pcie = platform_get_drvdata(pdev);
struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
- u32 cmd;
+ u32 cmd, sspl;
int i;
/* Remove PCI bus with all devices. */
@@ -1624,6 +1705,11 @@ static int mvebu_pcie_remove(struct platform_device *pdev)
/* Free config space for emulated root bridge. */
pci_bridge_emul_cleanup(&port->bridge);
+ /* Disable sending Set_Slot_Power_Limit PCIe Message. */
+ sspl = mvebu_readl(port, PCIE_SSPL_OFF);
+ sspl &= ~(PCIE_SSPL_VALUE_MASK | PCIE_SSPL_SCALE_MASK | PCIE_SSPL_ENABLE);
+ mvebu_writel(port, sspl, PCIE_SSPL_OFF);
+
/* Disable and clear BARs and windows. */
mvebu_pcie_disable_wins(port);
--
2.20.1
Hello Bjorn! Could you look if v2 changes are now fine?
On Wednesday 02 March 2022 15:57:29 Pali Rohár wrote:
> This patch series add slot support to pci-mvebu.c driver.
>
> It is based on branch pci/mvebu of git repository:
> https://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/pci.git
>
> Changes in v2:
> * Dropped patch with PCI_EXP_SLTCAP_*_SHIFT macros as it is not needed anymore
> * Dropped patch "ARM: dts: turris-omnia: Set PCIe slot-power-limit-milliwatt properties" which was applied
> * Added support for PCIe 6.0 slot power limit encodings
> * Round down slot power limit value
> * Fix handling of slot power limit with scale x1.0 (0x00 value)
> * Use FIELD_PREP instead of _SHIFT macros
> * Changed commit message to Bjorn's suggestion
> * Changed comments in the code to match PCIe spec
> * Preserve user settings of PCI_EXP_SLTCTL_ASPL_DISABLE bit
>
> Pali Rohár (4):
> PCI: Add PCI_EXP_SLTCTL_ASPL_DISABLE macro
> dt-bindings: Add 'slot-power-limit-milliwatt' PCIe port property
> PCI: Add function for parsing 'slot-power-limit-milliwatt' DT property
> PCI: mvebu: Add support for sending Set_Slot_Power_Limit message
>
> Documentation/devicetree/bindings/pci/pci.txt | 6 ++
> drivers/pci/controller/pci-mvebu.c | 96 ++++++++++++++++++-
> drivers/pci/of.c | 64 +++++++++++++
> drivers/pci/pci.h | 15 +++
> include/uapi/linux/pci_regs.h | 1 +
> 5 files changed, 177 insertions(+), 5 deletions(-)
>
> --
> 2.20.1
>
PING?
On Tuesday 08 March 2022 12:38:31 Pali Rohár wrote:
> Hello Bjorn! Could you look if v2 changes are now fine?
>
> On Wednesday 02 March 2022 15:57:29 Pali Rohár wrote:
> > This patch series add slot support to pci-mvebu.c driver.
> >
> > It is based on branch pci/mvebu of git repository:
> > https://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/pci.git
> >
> > Changes in v2:
> > * Dropped patch with PCI_EXP_SLTCAP_*_SHIFT macros as it is not needed anymore
> > * Dropped patch "ARM: dts: turris-omnia: Set PCIe slot-power-limit-milliwatt properties" which was applied
> > * Added support for PCIe 6.0 slot power limit encodings
> > * Round down slot power limit value
> > * Fix handling of slot power limit with scale x1.0 (0x00 value)
> > * Use FIELD_PREP instead of _SHIFT macros
> > * Changed commit message to Bjorn's suggestion
> > * Changed comments in the code to match PCIe spec
> > * Preserve user settings of PCI_EXP_SLTCTL_ASPL_DISABLE bit
> >
> > Pali Rohár (4):
> > PCI: Add PCI_EXP_SLTCTL_ASPL_DISABLE macro
> > dt-bindings: Add 'slot-power-limit-milliwatt' PCIe port property
> > PCI: Add function for parsing 'slot-power-limit-milliwatt' DT property
> > PCI: mvebu: Add support for sending Set_Slot_Power_Limit message
> >
> > Documentation/devicetree/bindings/pci/pci.txt | 6 ++
> > drivers/pci/controller/pci-mvebu.c | 96 ++++++++++++++++++-
> > drivers/pci/of.c | 64 +++++++++++++
> > drivers/pci/pci.h | 15 +++
> > include/uapi/linux/pci_regs.h | 1 +
> > 5 files changed, 177 insertions(+), 5 deletions(-)
> >
> > --
> > 2.20.1
> >
On Mon, Mar 21, 2022 at 07:29:08PM +0100, Pali Roh?r wrote:
> PING?
Sorry, my fault. I reviewed v1 of this patch, so obviously Lorenzo
would wait for me to chime in here.
> On Tuesday 08 March 2022 12:38:31 Pali Roh?r wrote:
> > Hello Bjorn! Could you look if v2 changes are now fine?
> >
> > On Wednesday 02 March 2022 15:57:29 Pali Roh?r wrote:
> > > This patch series add slot support to pci-mvebu.c driver.
> > >
> > > It is based on branch pci/mvebu of git repository:
> > > https://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/pci.git
> > >
> > > Changes in v2:
> > > * Dropped patch with PCI_EXP_SLTCAP_*_SHIFT macros as it is not needed anymore
> > > * Dropped patch "ARM: dts: turris-omnia: Set PCIe slot-power-limit-milliwatt properties" which was applied
> > > * Added support for PCIe 6.0 slot power limit encodings
> > > * Round down slot power limit value
> > > * Fix handling of slot power limit with scale x1.0 (0x00 value)
> > > * Use FIELD_PREP instead of _SHIFT macros
> > > * Changed commit message to Bjorn's suggestion
> > > * Changed comments in the code to match PCIe spec
> > > * Preserve user settings of PCI_EXP_SLTCTL_ASPL_DISABLE bit
> > >
> > > Pali Roh?r (4):
> > > PCI: Add PCI_EXP_SLTCTL_ASPL_DISABLE macro
> > > dt-bindings: Add 'slot-power-limit-milliwatt' PCIe port property
> > > PCI: Add function for parsing 'slot-power-limit-milliwatt' DT property
> > > PCI: mvebu: Add support for sending Set_Slot_Power_Limit message
> > >
> > > Documentation/devicetree/bindings/pci/pci.txt | 6 ++
> > > drivers/pci/controller/pci-mvebu.c | 96 ++++++++++++++++++-
> > > drivers/pci/of.c | 64 +++++++++++++
> > > drivers/pci/pci.h | 15 +++
> > > include/uapi/linux/pci_regs.h | 1 +
> > > 5 files changed, 177 insertions(+), 5 deletions(-)
> > >
> > > --
> > > 2.20.1
> > >
>
> _______________________________________________
> linux-arm-kernel mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Wed, Mar 02, 2022 at 03:57:33PM +0100, Pali Roh?r wrote:
> If DT supplies the 'slot-power-limit-milliwatt' property, program
> the value in the Slot Power Limit in the Slot Capabilities register
> and program the Root Port to send a Set_Slot_Power_Limit Message
> when the Link transitions to DL_Up.
>
> Signed-off-by: Pali Roh?r <[email protected]>
I didn't review this carefully but have no objection.
> ---
> Changes in v2:
> * Fix handling of slot power limit with scale x1.0 (0x00 value)
> * Use FIELD_PREP instead of _SHIFT macros
> * Changed commit message to Bjorn's suggestion
> * Changed comments in the code to match PCIe spec
> * Preserve user settings of PCI_EXP_SLTCTL_ASPL_DISABLE bit
> ---
> drivers/pci/controller/pci-mvebu.c | 96 ++++++++++++++++++++++++++++--
> 1 file changed, 91 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c
> index a75d2b9196f9..26ae7c29fece 100644
> --- a/drivers/pci/controller/pci-mvebu.c
> +++ b/drivers/pci/controller/pci-mvebu.c
> @@ -8,6 +8,7 @@
> #include <linux/kernel.h>
> #include <linux/module.h>
> #include <linux/pci.h>
> +#include <linux/bitfield.h>
> #include <linux/clk.h>
> #include <linux/delay.h>
> #include <linux/gpio.h>
> @@ -66,6 +67,12 @@
> #define PCIE_STAT_BUS 0xff00
> #define PCIE_STAT_DEV 0x1f0000
> #define PCIE_STAT_LINK_DOWN BIT(0)
> +#define PCIE_SSPL_OFF 0x1a0c
> +#define PCIE_SSPL_VALUE_SHIFT 0
> +#define PCIE_SSPL_VALUE_MASK GENMASK(7, 0)
> +#define PCIE_SSPL_SCALE_SHIFT 8
> +#define PCIE_SSPL_SCALE_MASK GENMASK(9, 8)
> +#define PCIE_SSPL_ENABLE BIT(16)
> #define PCIE_RC_RTSTA 0x1a14
> #define PCIE_DEBUG_CTRL 0x1a60
> #define PCIE_DEBUG_SOFT_RESET BIT(20)
> @@ -111,6 +118,8 @@ struct mvebu_pcie_port {
> struct mvebu_pcie_window iowin;
> u32 saved_pcie_stat;
> struct resource regs;
> + u8 slot_power_limit_value;
> + u8 slot_power_limit_scale;
> struct irq_domain *intx_irq_domain;
> raw_spinlock_t irq_lock;
> int intx_irq;
> @@ -239,7 +248,7 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie_port *port)
>
> static void mvebu_pcie_setup_hw(struct mvebu_pcie_port *port)
> {
> - u32 ctrl, lnkcap, cmd, dev_rev, unmask;
> + u32 ctrl, lnkcap, cmd, dev_rev, unmask, sspl;
>
> /* Setup PCIe controller to Root Complex mode. */
> ctrl = mvebu_readl(port, PCIE_CTRL_OFF);
> @@ -292,6 +301,20 @@ static void mvebu_pcie_setup_hw(struct mvebu_pcie_port *port)
> /* Point PCIe unit MBUS decode windows to DRAM space. */
> mvebu_pcie_setup_wins(port);
>
> + /*
> + * Program Root Port to automatically send Set_Slot_Power_Limit
> + * PCIe Message when changing status from Dl_Down to Dl_Up and valid
> + * slot power limit was specified.
> + */
> + sspl = mvebu_readl(port, PCIE_SSPL_OFF);
> + sspl &= ~(PCIE_SSPL_VALUE_MASK | PCIE_SSPL_SCALE_MASK | PCIE_SSPL_ENABLE);
> + if (port->slot_power_limit_value) {
> + sspl |= port->slot_power_limit_value << PCIE_SSPL_VALUE_SHIFT;
> + sspl |= port->slot_power_limit_scale << PCIE_SSPL_SCALE_SHIFT;
> + sspl |= PCIE_SSPL_ENABLE;
> + }
> + mvebu_writel(port, sspl, PCIE_SSPL_OFF);
> +
> /* Mask all interrupt sources. */
> mvebu_writel(port, ~PCIE_INT_ALL_MASK, PCIE_INT_UNMASK_OFF);
>
> @@ -628,9 +651,23 @@ mvebu_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge,
> (PCI_EXP_LNKSTA_DLLLA << 16) : 0);
> break;
>
> - case PCI_EXP_SLTCTL:
> - *value = PCI_EXP_SLTSTA_PDS << 16;
> + case PCI_EXP_SLTCTL: {
> + u16 slotsta = le16_to_cpu(bridge->pcie_conf.slotsta);
> + u32 val = 0;
> + /*
> + * When slot power limit was not specified in DT then
> + * ASPL_DISABLE bit is stored only in emulated config space.
> + * Otherwise reflect status of PCIE_SSPL_ENABLE bit in HW.
> + */
> + if (!port->slot_power_limit_value)
> + val |= slotctl & PCI_EXP_SLTCTL_ASPL_DISABLE;
> + else if (!(mvebu_readl(port, PCIE_SSPL_OFF) & PCIE_SSPL_ENABLE))
> + val |= PCI_EXP_SLTCTL_ASPL_DISABLE;
> + /* This callback is 32-bit and in high bits is slot status. */
> + val |= slotsta << 16;
> + *value = val;
> break;
> + }
>
> case PCI_EXP_RTSTA:
> *value = mvebu_readl(port, PCIE_RC_RTSTA);
> @@ -774,6 +811,22 @@ mvebu_pci_bridge_emul_pcie_conf_write(struct pci_bridge_emul *bridge,
> mvebu_writel(port, new, PCIE_CAP_PCIEXP + PCI_EXP_LNKCTL);
> break;
>
> + case PCI_EXP_SLTCTL:
> + /*
> + * Allow to change PCIE_SSPL_ENABLE bit only when slot power
> + * limit was specified in DT and configured into HW.
> + */
> + if ((mask & PCI_EXP_SLTCTL_ASPL_DISABLE) &&
> + port->slot_power_limit_value) {
> + u32 sspl = mvebu_readl(port, PCIE_SSPL_OFF);
> + if (new & PCI_EXP_SLTCTL_ASPL_DISABLE)
> + sspl &= ~PCIE_SSPL_ENABLE;
> + else
> + sspl |= PCIE_SSPL_ENABLE;
> + mvebu_writel(port, sspl, PCIE_SSPL_OFF);
> + }
> + break;
> +
> case PCI_EXP_RTSTA:
> /*
> * PME Status bit in Root Status Register (PCIE_RC_RTSTA)
> @@ -868,8 +921,26 @@ static int mvebu_pci_bridge_emul_init(struct mvebu_pcie_port *port)
> /*
> * Older mvebu hardware provides PCIe Capability structure only in
> * version 1. New hardware provides it in version 2.
> + * Enable slot support which is emulated.
> */
> - bridge->pcie_conf.cap = cpu_to_le16(pcie_cap_ver);
> + bridge->pcie_conf.cap = cpu_to_le16(pcie_cap_ver | PCI_EXP_FLAGS_SLOT);
> +
> + /*
> + * Set Presence Detect State bit permanently as there is no support for
> + * unplugging PCIe card from the slot. Assume that PCIe card is always
> + * connected in slot.
> + *
> + * Set physical slot number to port+1 as mvebu ports are indexed from
> + * zero and zero value is reserved for ports within the same silicon
> + * as Root Port which is not mvebu case.
> + *
> + * Also set correct slot power limit.
> + */
> + bridge->pcie_conf.slotcap = cpu_to_le32(
> + FIELD_PREP(PCI_EXP_SLTCAP_SPLV, port->slot_power_limit_value) |
> + FIELD_PREP(PCI_EXP_SLTCAP_SPLS, port->slot_power_limit_scale) |
> + FIELD_PREP(PCI_EXP_SLTCAP_PSN, port->port+1));
> + bridge->pcie_conf.slotsta = cpu_to_le16(PCI_EXP_SLTSTA_PDS);
>
> bridge->subsystem_vendor_id = ssdev_id & 0xffff;
> bridge->subsystem_id = ssdev_id >> 16;
> @@ -1191,6 +1262,7 @@ static int mvebu_pcie_parse_port(struct mvebu_pcie *pcie,
> {
> struct device *dev = &pcie->pdev->dev;
> enum of_gpio_flags flags;
> + u32 slot_power_limit;
> int reset_gpio, ret;
> u32 num_lanes;
>
> @@ -1291,6 +1363,15 @@ static int mvebu_pcie_parse_port(struct mvebu_pcie *pcie,
> port->reset_gpio = gpio_to_desc(reset_gpio);
> }
>
> + slot_power_limit = of_pci_get_slot_power_limit(child,
> + &port->slot_power_limit_value,
> + &port->slot_power_limit_scale);
> + if (slot_power_limit)
> + dev_info(dev, "%s: Slot power limit %u.%uW\n",
> + port->name,
> + slot_power_limit / 1000,
> + (slot_power_limit / 100) % 10);
> +
> port->clk = of_clk_get_by_name(child, NULL);
> if (IS_ERR(port->clk)) {
> dev_err(dev, "%s: cannot get clock\n", port->name);
> @@ -1587,7 +1668,7 @@ static int mvebu_pcie_remove(struct platform_device *pdev)
> {
> struct mvebu_pcie *pcie = platform_get_drvdata(pdev);
> struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
> - u32 cmd;
> + u32 cmd, sspl;
> int i;
>
> /* Remove PCI bus with all devices. */
> @@ -1624,6 +1705,11 @@ static int mvebu_pcie_remove(struct platform_device *pdev)
> /* Free config space for emulated root bridge. */
> pci_bridge_emul_cleanup(&port->bridge);
>
> + /* Disable sending Set_Slot_Power_Limit PCIe Message. */
> + sspl = mvebu_readl(port, PCIE_SSPL_OFF);
> + sspl &= ~(PCIE_SSPL_VALUE_MASK | PCIE_SSPL_SCALE_MASK | PCIE_SSPL_ENABLE);
> + mvebu_writel(port, sspl, PCIE_SSPL_OFF);
> +
> /* Disable and clear BARs and windows. */
> mvebu_pcie_disable_wins(port);
>
> --
> 2.20.1
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Wed, Mar 02, 2022 at 03:57:33PM +0100, Pali Roh?r wrote:
> If DT supplies the 'slot-power-limit-milliwatt' property, program
> the value in the Slot Power Limit in the Slot Capabilities register
> and program the Root Port to send a Set_Slot_Power_Limit Message
> when the Link transitions to DL_Up.
>
> Signed-off-by: Pali Roh?r <[email protected]>
> ---
> Changes in v2:
> * Fix handling of slot power limit with scale x1.0 (0x00 value)
> * Use FIELD_PREP instead of _SHIFT macros
> * Changed commit message to Bjorn's suggestion
> * Changed comments in the code to match PCIe spec
> * Preserve user settings of PCI_EXP_SLTCTL_ASPL_DISABLE bit
> ---
> drivers/pci/controller/pci-mvebu.c | 96 ++++++++++++++++++++++++++++--
> 1 file changed, 91 insertions(+), 5 deletions(-)
Reviewed-by: Rob Herring <[email protected]>