ClearFog CX PCIE hotplug

Hi everyone,

I am having trouble getting PCIe hotplug to work on my SolidRun ClearFog CX board. I have tried writing to the PCI Express Capabilities Register (0x72) and the PCI Express Slot Capabilities Register (0x84) in u-boot-qoriq, and I have confirmed that the registers are set correctly using the lspci -vvv -s 0000:00:00.0 command.

 SltCap: AttnBtn- PwrCtrl- MRL- AttnInd- PwrInd- HotPlug+ Surprise+
     Slot #2, PowerLimit 0W; Interlock- NoCompl-

However, despite having HotPlug+ enabled in the SlotCap field, I am not able to get hotplug to work. Neither a hotplug eject nor a hotplug insert is detected by the system.

I am wondering if there is something else I need to do to enable hotplug functionality on this board. If anyone has experience with getting PCIe hotplug working on the ClearFog CX, I would greatly appreciate any advice or guidance you can offer. Thank you in advance for your help.

PS: the patch looks as follows:

diff --git a/drivers/pci/pcie_layerscape_rc.c b/drivers/pci/pcie_layerscape_rc.c
index 17969e2f23..b3fa690a43 100644
--- a/drivers/pci/pcie_layerscape_rc.c
+++ b/drivers/pci/pcie_layerscape_rc.c
@@ -231,6 +231,33 @@ static void ls_pcie_disable_bars(struct ls_pcie_rc *pcie_rc)
        dbi_writel(pcie, 0xfffffffe, PCIE_CS2_OFFSET + PCI_ROM_ADDRESS1);
 }

+/* Set slot implemented reg in PEX caps */
+static void ls_pcie_fix_slot(struct ls_pcie_rc *pcie_rc)
+{
+       struct ls_pcie *pcie = pcie_rc->pcie;
+
+       u16 val = readw(pcie->dbi + 0x72);
+       val = val | 0b100000000;
+
+       writew(val, pcie->dbi + 0x72);
+}
+
+/* Set slot implemented reg in PEX caps */
+static void ls_pcie_set_slot_caps(struct ls_pcie_rc *pcie_rc)
+{
+       struct ls_pcie *pcie = pcie_rc->pcie;
+
+       u32 oldval = readl(pcie->dbi + 0x84);
+       printf("fooooooo 0x%x foooooooooooooooooooooo\n", oldval);
+       u32 newval = oldval | (0b1 << 5);                               // set hot-plug surprise
+       newval |= (0b1 << 6);                                                   // set hot-plug capable
+       printf("set slot id %d\n", pcie->idx);
+       newval |= (pcie->idx & 0b1111111111111) << 19;  // set slot number
+       writel(newval, pcie->dbi + 0x84);
+       oldval = readl(pcie->dbi + 0x84);
+       printf("baaaaaar 0x%x baaaaaaaaaaaaaaaaaaaaar\n", oldval);
+}
+
 static void ls_pcie_setup_ctrl(struct ls_pcie_rc *pcie_rc)
 {
        struct ls_pcie *pcie = pcie_rc->pcie;
@@ -241,6 +268,8 @@ static void ls_pcie_setup_ctrl(struct ls_pcie_rc *pcie_rc)
        ls_pcie_fix_class(pcie_rc);
        ls_pcie_clear_multifunction(pcie_rc);
        ls_pcie_drop_msg_tlp(pcie_rc);
+       ls_pcie_fix_slot(pcie_rc);
+       ls_pcie_set_slot_caps(pcie_rc);
        ls_pcie_dbi_ro_wr_dis(pcie);

        ls_pcie_disable_bars(pcie_rc);

PCIe hotplug needs help beyond the PCIe controller. Generally implementations will have a hardware GPIO that gets pulled low when a card is inserted and is able to initiate the hotplug enumeration. Our designs do not have this implemented. Therefore the only way to re-enumerate the bus is by forcing a rescan of the PCIe bus from userspace once the card is inserted.