@@ -213,6 +213,11 @@ enum {
};
#define VENDOR_ID_REG (LMI_BASE_ADDR + 0x44)
+#define PME_MSG_GEN_CTRL (LMI_BASE_ADDR + 0x220)
+#define SEND_SET_SLOT_POWER_LIMIT BIT(13)
+#define SEND_PME_TURN_OFF BIT(14)
+#define SLOT_POWER_LIMIT_DATA_SHIFT 16
+#define SLOT_POWER_LIMIT_DATA_MASK GENMASK(25, 16)
/* PCIe core controller registers */
#define CTRL_CORE_BASE_ADDR 0x18000
@@ -285,6 +290,8 @@ struct advk_pcie {
raw_spinlock_t msi_irq_lock;
DECLARE_BITMAP(msi_used, MSI_IRQ_NUM);
struct mutex msi_used_lock;
+ u8 slot_power_limit_value;
+ u8 slot_power_limit_scale;
int link_gen;
bool link_was_up;
struct timer_list link_irq_timer;
@@ -317,8 +324,9 @@ static inline bool advk_pcie_link_up(struct advk_pcie *pcie)
{
/* check if LTSSM is in normal operation - some L* state */
u8 ltssm_state = advk_pcie_ltssm_state(pcie);
+ u16 slotsta, slotctl;
+ u32 slotpwr, val;
bool link_is_up;
- u16 slotsta;
link_is_up = ltssm_state >= LTSSM_L0 && ltssm_state < LTSSM_DISABLED;
@@ -332,6 +340,27 @@ static inline bool advk_pcie_link_up(struct advk_pcie *pcie)
pcie->bridge.pcie_conf.slotsta = cpu_to_le16(slotsta);
mod_timer(&pcie->link_irq_timer, jiffies + 1);
+
+ /*
+ * According to PCIe Base specification 3.0, when transitioning
+ * from a non-DL_Up Status to a DL_Up Status, the Port must
+ * initiate the transmission of a Set_Slot_Power_Limit Message
+ * to the other component on the Link to convey the value
+ * programmed in the Slot Power Limit Scale and Value fields of
+ * the Slot Capabilities register. This transmission is optional
+ * if the Slot Capabilities register has not yet been
+ * initialized.
+ */
+ slotctl = le16_to_cpu(pcie->bridge.pcie_conf.slotctl);
+ slotpwr = FIELD_GET(PCI_EXP_SLTCAP_SPLV | PCI_EXP_SLTCAP_SPLS,
+ le32_to_cpu(pcie->bridge.pcie_conf.slotcap));
+ if (!(slotctl & PCI_EXP_SLTCTL_ASPL_DISABLE) && slotpwr) {
+ val = advk_readl(pcie, PME_MSG_GEN_CTRL);
+ val &= ~SLOT_POWER_LIMIT_DATA_MASK;
+ val |= slotpwr << SLOT_POWER_LIMIT_DATA_SHIFT;
+ val |= SEND_SET_SLOT_POWER_LIMIT;
+ advk_writel(pcie, val, PME_MSG_GEN_CTRL);
+ }
}
return link_is_up;
@@ -944,8 +973,9 @@ advk_pci_bridge_emul_pcie_conf_write(struct pci_bridge_emul *bridge,
case PCI_EXP_SLTCTL: {
u16 slotctl = le16_to_cpu(bridge->pcie_conf.slotctl);
- /* Only emulation of HPIE and DLLSCE bits is provided */
- slotctl &= PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_DLLSCE;
+ /* Only emulation of HPIE, DLLSCE and ASPLD bits is provided */
+ slotctl &= PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_DLLSCE |
+ PCI_EXP_SLTCTL_ASPL_DISABLE;
bridge->pcie_conf.slotctl = cpu_to_le16(slotctl);
break;
}
@@ -1109,9 +1139,13 @@ static int advk_sw_pci_bridge_init(struct advk_pcie *pcie)
* Set physical slot number to 1 since there is only one port and zero
* value is reserved for ports within the same silicon as Root Port
* which is not our case.
+ *
+ * Set slot power limit.
*/
slotcap = PCI_EXP_SLTCAP_NCCS | PCI_EXP_SLTCAP_HPC |
- FIELD_PREP(PCI_EXP_SLTCAP_PSN, 1);
+ FIELD_PREP(PCI_EXP_SLTCAP_PSN, 1) |
+ FIELD_PREP(PCI_EXP_SLTCAP_SPLV, pcie->slot_power_limit_value) |
+ FIELD_PREP(PCI_EXP_SLTCAP_SPLS, pcie->slot_power_limit_scale);
bridge->pcie_conf.slotcap = cpu_to_le32(slotcap);
bridge->pcie_conf.slotsta = cpu_to_le16(PCI_EXP_SLTSTA_PDS);
@@ -1837,6 +1871,7 @@ static int advk_pcie_probe(struct platform_device *pdev)
struct advk_pcie *pcie;
struct pci_host_bridge *bridge;
struct resource_entry *entry;
+ u32 slot_power_limit;
int ret, irq;
bridge = devm_pci_alloc_host_bridge(dev, sizeof(struct advk_pcie));
@@ -1957,6 +1992,14 @@ static int advk_pcie_probe(struct platform_device *pdev)
else
pcie->link_gen = ret;
+ slot_power_limit = of_pci_get_slot_power_limit(dev->of_node,
+ &pcie->slot_power_limit_value,
+ &pcie->slot_power_limit_scale);
+ if (slot_power_limit)
+ dev_info(dev, "Slot Power Limit: %u.%uW\n",
+ slot_power_limit / 1000,
+ (slot_power_limit / 100) % 10);
+
ret = advk_pcie_setup_phy(pcie);
if (ret)
return ret;