Skip to content

Commit d609a8d

Browse files
Russell Kingbjorn-helgaas
authored andcommitted
PCI: mvebu: Improve clock/reset handling
Add an implementation to handle clock and reset handling that is compliant with the PCIe specification. The clock should be running and stable for 100us prior to reset being released, and we should re-assert reset prior to stopping the clock. Tested-by: Willy Tarreau <[email protected]> (Iomega iConnect Kirkwood, MiraBox Armada 370) Tested-by: Andrew Lunn <[email protected]> (D-Link DIR664 Kirkwood) Tested-by: Thomas Petazzoni <[email protected]> (Armada XP GP) Signed-off-by: Russell King <[email protected]> Signed-off-by: Bjorn Helgaas <[email protected]> Reviewed-by: Thomas Petazzoni <[email protected]>
1 parent 8a182c2 commit d609a8d

File tree

1 file changed

+43
-13
lines changed

1 file changed

+43
-13
lines changed

drivers/pci/host/pci-mvebu.c

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,6 +1042,46 @@ static int mvebu_pcie_parse_port(struct mvebu_pcie *pcie,
10421042
return ret;
10431043
}
10441044

1045+
/*
1046+
* Power up a PCIe port. PCIe requires the refclk to be stable for 100µs
1047+
* prior to releasing PERST. See table 2-4 in section 2.6.2 AC Specifications
1048+
* of the PCI Express Card Electromechanical Specification, 1.1.
1049+
*/
1050+
static int mvebu_pcie_powerup(struct mvebu_pcie_port *port)
1051+
{
1052+
int ret;
1053+
1054+
ret = clk_prepare_enable(port->clk);
1055+
if (ret < 0)
1056+
return ret;
1057+
1058+
if (port->reset_gpio) {
1059+
u32 reset_udelay = 20000;
1060+
1061+
of_property_read_u32(port->dn, "reset-delay-us",
1062+
&reset_udelay);
1063+
1064+
udelay(100);
1065+
1066+
gpiod_set_value_cansleep(port->reset_gpio, 0);
1067+
msleep(reset_udelay / 1000);
1068+
}
1069+
1070+
return 0;
1071+
}
1072+
1073+
/*
1074+
* Power down a PCIe port. Strictly, PCIe requires us to place the card
1075+
* in D3hot state before asserting PERST#.
1076+
*/
1077+
static void mvebu_pcie_powerdown(struct mvebu_pcie_port *port)
1078+
{
1079+
if (port->reset_gpio)
1080+
gpiod_set_value_cansleep(port->reset_gpio, 1);
1081+
1082+
clk_disable_unprepare(port->clk);
1083+
}
1084+
10451085
static int mvebu_pcie_probe(struct platform_device *pdev)
10461086
{
10471087
struct mvebu_pcie *pcie;
@@ -1114,26 +1154,16 @@ static int mvebu_pcie_probe(struct platform_device *pdev)
11141154
if (!child)
11151155
continue;
11161156

1117-
if (port->reset_gpio) {
1118-
u32 reset_udelay = 20000;
1119-
1120-
of_property_read_u32(child, "reset-delay-us",
1121-
&reset_udelay);
1122-
1123-
gpiod_set_value_cansleep(port->reset_gpio, 0);
1124-
msleep(reset_udelay / 1000);
1125-
}
1126-
1127-
ret = clk_prepare_enable(port->clk);
1128-
if (ret)
1157+
ret = mvebu_pcie_powerup(port);
1158+
if (ret < 0)
11291159
continue;
11301160

11311161
port->base = mvebu_pcie_map_registers(pdev, child, port);
11321162
if (IS_ERR(port->base)) {
11331163
dev_err(&pdev->dev, "%s: cannot map registers\n",
11341164
port->name);
11351165
port->base = NULL;
1136-
clk_disable_unprepare(port->clk);
1166+
mvebu_pcie_powerdown(port);
11371167
continue;
11381168
}
11391169

0 commit comments

Comments
 (0)