2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-12-22 20:23:57 +08:00
linux-next/arch/mips/pci/pci-ar724x.c
Mathias Kresin 0316b05311
MIPS: ath79: get PCIe controller out of reset
The ar724x pci driver expects the PCIe controller to be brought out of
reset by the bootloader.

At least the AVM Fritz 300E bootloader doesn't take care of releasing
the different PCIe controller related resets which causes an endless
hang as soon as either the PCIE Reset register (0x180f0018) or the PCI
Application Control register (0x180f0000) is read from.

Do the full "PCIE Root Complex Initialization Sequence" if the PCIe
host controller is still in reset during probing.

The QCA u-boot sleeps 10ms after the PCIE Application Control bit is
set to ready. It has been shown that 10ms might not be enough time if
PCIe should be used right after setting the bit. During my tests it
took up to 20ms till the link was up. Giving the link up to 100ms
should work for all cases.

Signed-off-by: Mathias Kresin <dev@kresin.me>
Signed-off-by: John Crispin <john@phrozen.org>
Signed-off-by: Paul Burton <paul.burton@mips.com>
Patchwork: https://patchwork.linux-mips.org/patch/19916/
Cc: James Hogan <jhogan@kernel.org>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: linux-mips@linux-mips.org
2018-07-24 19:08:06 -07:00

454 lines
10 KiB
C

/*
* Atheros AR724X PCI host controller driver
*
* Copyright (C) 2011 René Bolldorf <xsecute@googlemail.com>
* Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*/
#include <linux/irq.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <asm/mach-ath79/ath79.h>
#include <asm/mach-ath79/ar71xx_regs.h>
#define AR724X_PCI_REG_APP 0x00
#define AR724X_PCI_REG_RESET 0x18
#define AR724X_PCI_REG_INT_STATUS 0x4c
#define AR724X_PCI_REG_INT_MASK 0x50
#define AR724X_PCI_APP_LTSSM_ENABLE BIT(0)
#define AR724X_PCI_RESET_LINK_UP BIT(0)
#define AR724X_PCI_INT_DEV0 BIT(14)
#define AR724X_PCI_IRQ_COUNT 1
#define AR7240_BAR0_WAR_VALUE 0xffff
#define AR724X_PCI_CMD_INIT (PCI_COMMAND_MEMORY | \
PCI_COMMAND_MASTER | \
PCI_COMMAND_INVALIDATE | \
PCI_COMMAND_PARITY | \
PCI_COMMAND_SERR | \
PCI_COMMAND_FAST_BACK)
struct ar724x_pci_controller {
void __iomem *devcfg_base;
void __iomem *ctrl_base;
void __iomem *crp_base;
int irq;
int irq_base;
bool link_up;
bool bar0_is_cached;
u32 bar0_value;
struct pci_controller pci_controller;
struct resource io_res;
struct resource mem_res;
};
static inline bool ar724x_pci_check_link(struct ar724x_pci_controller *apc)
{
u32 reset;
reset = __raw_readl(apc->ctrl_base + AR724X_PCI_REG_RESET);
return reset & AR724X_PCI_RESET_LINK_UP;
}
static inline struct ar724x_pci_controller *
pci_bus_to_ar724x_controller(struct pci_bus *bus)
{
struct pci_controller *hose;
hose = (struct pci_controller *) bus->sysdata;
return container_of(hose, struct ar724x_pci_controller, pci_controller);
}
static int ar724x_pci_local_write(struct ar724x_pci_controller *apc,
int where, int size, u32 value)
{
void __iomem *base;
u32 data;
int s;
WARN_ON(where & (size - 1));
if (!apc->link_up)
return PCIBIOS_DEVICE_NOT_FOUND;
base = apc->crp_base;
data = __raw_readl(base + (where & ~3));
switch (size) {
case 1:
s = ((where & 3) * 8);
data &= ~(0xff << s);
data |= ((value & 0xff) << s);
break;
case 2:
s = ((where & 2) * 8);
data &= ~(0xffff << s);
data |= ((value & 0xffff) << s);
break;
case 4:
data = value;
break;
default:
return PCIBIOS_BAD_REGISTER_NUMBER;
}
__raw_writel(data, base + (where & ~3));
/* flush write */
__raw_readl(base + (where & ~3));
return PCIBIOS_SUCCESSFUL;
}
static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where,
int size, uint32_t *value)
{
struct ar724x_pci_controller *apc;
void __iomem *base;
u32 data;
apc = pci_bus_to_ar724x_controller(bus);
if (!apc->link_up)
return PCIBIOS_DEVICE_NOT_FOUND;
if (devfn)
return PCIBIOS_DEVICE_NOT_FOUND;
base = apc->devcfg_base;
data = __raw_readl(base + (where & ~3));
switch (size) {
case 1:
if (where & 1)
data >>= 8;
if (where & 2)
data >>= 16;
data &= 0xff;
break;
case 2:
if (where & 2)
data >>= 16;
data &= 0xffff;
break;
case 4:
break;
default:
return PCIBIOS_BAD_REGISTER_NUMBER;
}
if (where == PCI_BASE_ADDRESS_0 && size == 4 &&
apc->bar0_is_cached) {
/* use the cached value */
*value = apc->bar0_value;
} else {
*value = data;
}
return PCIBIOS_SUCCESSFUL;
}
static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where,
int size, uint32_t value)
{
struct ar724x_pci_controller *apc;
void __iomem *base;
u32 data;
int s;
apc = pci_bus_to_ar724x_controller(bus);
if (!apc->link_up)
return PCIBIOS_DEVICE_NOT_FOUND;
if (devfn)
return PCIBIOS_DEVICE_NOT_FOUND;
if (soc_is_ar7240() && where == PCI_BASE_ADDRESS_0 && size == 4) {
if (value != 0xffffffff) {
/*
* WAR for a hw issue. If the BAR0 register of the
* device is set to the proper base address, the
* memory space of the device is not accessible.
*
* Cache the intended value so it can be read back,
* and write a SoC specific constant value to the
* BAR0 register in order to make the device memory
* accessible.
*/
apc->bar0_is_cached = true;
apc->bar0_value = value;
value = AR7240_BAR0_WAR_VALUE;
} else {
apc->bar0_is_cached = false;
}
}
base = apc->devcfg_base;
data = __raw_readl(base + (where & ~3));
switch (size) {
case 1:
s = ((where & 3) * 8);
data &= ~(0xff << s);
data |= ((value & 0xff) << s);
break;
case 2:
s = ((where & 2) * 8);
data &= ~(0xffff << s);
data |= ((value & 0xffff) << s);
break;
case 4:
data = value;
break;
default:
return PCIBIOS_BAD_REGISTER_NUMBER;
}
__raw_writel(data, base + (where & ~3));
/* flush write */
__raw_readl(base + (where & ~3));
return PCIBIOS_SUCCESSFUL;
}
static struct pci_ops ar724x_pci_ops = {
.read = ar724x_pci_read,
.write = ar724x_pci_write,
};
static void ar724x_pci_irq_handler(struct irq_desc *desc)
{
struct ar724x_pci_controller *apc;
void __iomem *base;
u32 pending;
apc = irq_desc_get_handler_data(desc);
base = apc->ctrl_base;
pending = __raw_readl(base + AR724X_PCI_REG_INT_STATUS) &
__raw_readl(base + AR724X_PCI_REG_INT_MASK);
if (pending & AR724X_PCI_INT_DEV0)
generic_handle_irq(apc->irq_base + 0);
else
spurious_interrupt();
}
static void ar724x_pci_irq_unmask(struct irq_data *d)
{
struct ar724x_pci_controller *apc;
void __iomem *base;
int offset;
u32 t;
apc = irq_data_get_irq_chip_data(d);
base = apc->ctrl_base;
offset = apc->irq_base - d->irq;
switch (offset) {
case 0:
t = __raw_readl(base + AR724X_PCI_REG_INT_MASK);
__raw_writel(t | AR724X_PCI_INT_DEV0,
base + AR724X_PCI_REG_INT_MASK);
/* flush write */
__raw_readl(base + AR724X_PCI_REG_INT_MASK);
}
}
static void ar724x_pci_irq_mask(struct irq_data *d)
{
struct ar724x_pci_controller *apc;
void __iomem *base;
int offset;
u32 t;
apc = irq_data_get_irq_chip_data(d);
base = apc->ctrl_base;
offset = apc->irq_base - d->irq;
switch (offset) {
case 0:
t = __raw_readl(base + AR724X_PCI_REG_INT_MASK);
__raw_writel(t & ~AR724X_PCI_INT_DEV0,
base + AR724X_PCI_REG_INT_MASK);
/* flush write */
__raw_readl(base + AR724X_PCI_REG_INT_MASK);
t = __raw_readl(base + AR724X_PCI_REG_INT_STATUS);
__raw_writel(t | AR724X_PCI_INT_DEV0,
base + AR724X_PCI_REG_INT_STATUS);
/* flush write */
__raw_readl(base + AR724X_PCI_REG_INT_STATUS);
}
}
static struct irq_chip ar724x_pci_irq_chip = {
.name = "AR724X PCI ",
.irq_mask = ar724x_pci_irq_mask,
.irq_unmask = ar724x_pci_irq_unmask,
.irq_mask_ack = ar724x_pci_irq_mask,
};
static void ar724x_pci_irq_init(struct ar724x_pci_controller *apc,
int id)
{
void __iomem *base;
int i;
base = apc->ctrl_base;
__raw_writel(0, base + AR724X_PCI_REG_INT_MASK);
__raw_writel(0, base + AR724X_PCI_REG_INT_STATUS);
apc->irq_base = ATH79_PCI_IRQ_BASE + (id * AR724X_PCI_IRQ_COUNT);
for (i = apc->irq_base;
i < apc->irq_base + AR724X_PCI_IRQ_COUNT; i++) {
irq_set_chip_and_handler(i, &ar724x_pci_irq_chip,
handle_level_irq);
irq_set_chip_data(i, apc);
}
irq_set_chained_handler_and_data(apc->irq, ar724x_pci_irq_handler,
apc);
}
static void ar724x_pci_hw_init(struct ar724x_pci_controller *apc)
{
u32 ppl, app;
int wait = 0;
/* deassert PCIe host controller and PCIe PHY reset */
ath79_device_reset_clear(AR724X_RESET_PCIE);
ath79_device_reset_clear(AR724X_RESET_PCIE_PHY);
/* remove the reset of the PCIE PLL */
ppl = ath79_pll_rr(AR724X_PLL_REG_PCIE_CONFIG);
ppl &= ~AR724X_PLL_REG_PCIE_CONFIG_PPL_RESET;
ath79_pll_wr(AR724X_PLL_REG_PCIE_CONFIG, ppl);
/* deassert bypass for the PCIE PLL */
ppl = ath79_pll_rr(AR724X_PLL_REG_PCIE_CONFIG);
ppl &= ~AR724X_PLL_REG_PCIE_CONFIG_PPL_BYPASS;
ath79_pll_wr(AR724X_PLL_REG_PCIE_CONFIG, ppl);
/* set PCIE Application Control to ready */
app = __raw_readl(apc->ctrl_base + AR724X_PCI_REG_APP);
app |= AR724X_PCI_APP_LTSSM_ENABLE;
__raw_writel(app, apc->ctrl_base + AR724X_PCI_REG_APP);
/* wait up to 100ms for PHY link up */
do {
mdelay(10);
wait++;
} while (wait < 10 && !ar724x_pci_check_link(apc));
}
static int ar724x_pci_probe(struct platform_device *pdev)
{
struct ar724x_pci_controller *apc;
struct resource *res;
int id;
id = pdev->id;
if (id == -1)
id = 0;
apc = devm_kzalloc(&pdev->dev, sizeof(struct ar724x_pci_controller),
GFP_KERNEL);
if (!apc)
return -ENOMEM;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctrl_base");
apc->ctrl_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(apc->ctrl_base))
return PTR_ERR(apc->ctrl_base);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg_base");
apc->devcfg_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(apc->devcfg_base))
return PTR_ERR(apc->devcfg_base);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "crp_base");
apc->crp_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(apc->crp_base))
return PTR_ERR(apc->crp_base);
apc->irq = platform_get_irq(pdev, 0);
if (apc->irq < 0)
return -EINVAL;
res = platform_get_resource_byname(pdev, IORESOURCE_IO, "io_base");
if (!res)
return -EINVAL;
apc->io_res.parent = res;
apc->io_res.name = "PCI IO space";
apc->io_res.start = res->start;
apc->io_res.end = res->end;
apc->io_res.flags = IORESOURCE_IO;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem_base");
if (!res)
return -EINVAL;
apc->mem_res.parent = res;
apc->mem_res.name = "PCI memory space";
apc->mem_res.start = res->start;
apc->mem_res.end = res->end;
apc->mem_res.flags = IORESOURCE_MEM;
apc->pci_controller.pci_ops = &ar724x_pci_ops;
apc->pci_controller.io_resource = &apc->io_res;
apc->pci_controller.mem_resource = &apc->mem_res;
/*
* Do the full PCIE Root Complex Initialization Sequence if the PCIe
* host controller is in reset.
*/
if (ath79_reset_rr(AR724X_RESET_REG_RESET_MODULE) & AR724X_RESET_PCIE)
ar724x_pci_hw_init(apc);
apc->link_up = ar724x_pci_check_link(apc);
if (!apc->link_up)
dev_warn(&pdev->dev, "PCIe link is down\n");
ar724x_pci_irq_init(apc, id);
ar724x_pci_local_write(apc, PCI_COMMAND, 4, AR724X_PCI_CMD_INIT);
register_pci_controller(&apc->pci_controller);
return 0;
}
static struct platform_driver ar724x_pci_driver = {
.probe = ar724x_pci_probe,
.driver = {
.name = "ar724x-pci",
},
};
static int __init ar724x_pci_init(void)
{
return platform_driver_register(&ar724x_pci_driver);
}
postcore_initcall(ar724x_pci_init);