@@ -16,15 +16,28 @@
#include <linux/of_irq.h>
#include <linux/of_pci.h>
#include <linux/reset.h>
+#include <linux/pci.h>
#include <linux/platform_device.h>
#include <asm/mach-ralink/ralink_regs.h>
#include <asm/mach-ralink/mt7620.h>
+#define RALINK_MT7628_SPREAD_SPECTRUM
+
+/* region for IO port accesses */
#define RALINK_PCI_IO_MAP_BASE 0x10160000
-#define RALINK_PCI_MEMORY_BASE 0x0
-#define RALINK_INT_PCIE0 4
+/* region for indirect MEM accesses */
+#define RALINK_PCI_IND_MEM_MAP_BASE 0x10150000
+
+/*
+ * RAM address offset for PCIe MEM access from device
+ * 0 = direct mapping
+ */
+#define RALINK_PCI_BUSMASTER_OFFSET 0x0
+
+/* IRQ number for all interrupts from PCIe */
+#define RALINK_IRQ_PCIE0 4
#define RALINK_CLKCFG1 0x30
#define RALINK_GPIOMODE 0x60
@@ -43,12 +56,13 @@
#define PCIRST BIT(1)
#define RALINK_PCI_PCIENA 0x0C
+/* NOTICE on MT7628 this is called PCIINT0 */
#define PCIINT2 BIT(20)
#define RALINK_PCI_CONFIG_ADDR 0x20
#define RALINK_PCI_CONFIG_DATA_VIRT_REG 0x24
-#define RALINK_PCI_MEMBASE 0x28
-#define RALINK_PCI_IOBASE 0x2C
+#define RALINK_PCI_MEM_OFFSET 0x28
+#define RALINK_PCI_IO_OFFSET 0x2C
/* PCI RC registers */
#define RALINK_PCI0_BAR0SETUP_ADDR 0x10
@@ -70,7 +84,6 @@
#define DATA_SHIFT 0
#define ADDR_SHIFT 8
-
static void __iomem *bridge_base;
static void __iomem *pcie_base;
@@ -86,6 +99,15 @@ static inline u32 bridge_r32(unsigned reg)
return ioread32(bridge_base + reg);
}
+static inline void bridge_m32(u32 clr, u32 set, unsigned reg)
+{
+ u32 val = bridge_r32(reg);
+
+ val &= ~clr;
+ val |= set;
+ bridge_w32(val, reg);
+}
+
static inline void pcie_w32(u32 val, unsigned reg)
{
iowrite32(val, pcie_base + reg);
@@ -113,7 +135,7 @@ static int wait_pciephy_busy(void)
reg_value = pcie_r32(PCIEPHY0_CFG);
if (reg_value & BUSY)
- mdelay(100);
+ msleep(100);
else
break;
if (retry++ > WAITRETRY_MAX) {
@@ -129,7 +151,7 @@ static void pcie_phy(unsigned long addr, unsigned long val)
wait_pciephy_busy();
pcie_w32(WRITE_MODE | (val << DATA_SHIFT) | (addr << ADDR_SHIFT),
PCIEPHY0_CFG);
- mdelay(1);
+ msleep(1);
wait_pciephy_busy();
}
@@ -206,16 +228,86 @@ struct pci_ops mt7620_pci_ops = {
.write = pci_config_write,
};
-static struct resource mt7620_res_pci_mem1;
-static struct resource mt7620_res_pci_io1;
-struct pci_controller mt7620_controller = {
- .pci_ops = &mt7620_pci_ops,
- .mem_resource = &mt7620_res_pci_mem1,
- .mem_offset = 0x00000000UL,
- .io_resource = &mt7620_res_pci_io1,
- .io_offset = 0x00000000UL,
- .io_map_base = 0xa0000000,
-};
+unsigned long pci_address_to_pio(phys_addr_t address)
+{
+
+//get 0- 0xffff IO port value from physical address
+ return address - RALINK_PCI_IO_MAP_BASE;
+}
+
+void __iomem *__pci_ioport_map(struct pci_dev *dev,
+ unsigned long port, unsigned int nr)
+{
+ void __iomem * temp;
+
+//get iomem address for driver accesses from IO port value
+ temp = (void __iomem *) (mips_io_port_base + port);
+
+ return temp;
+}
+
+/*
+ * TODO change it to WARN or BUG
+ * if this irq occurs, the PCIe controller "crashed"
+ * otherwise it would meant link down normally
+ */
+static irqreturn_t mt7628_irq_handler_link(int irq, void *data)
+{
+ u32 val = 0;
+
+ pr_emerg("PCIe link down, unstable system due HW BUG\n");
+
+//TODO maybe call bug?
+//delete vvvv, not working!
+#if 0
+
+ pr_info("**PCIe link down event %08x %08x\n",
+ bridge_r32(0x08),
+ pcie_r32(0x7414)
+ );
+
+ /* voodoo from the SDK driver */
+ pcie_m32(~0xff, 0x5, RALINK_PCIEPHY_P0_CTL_OFFSET);
+
+ // spread spectrum enable
+ pcie_w32(0x10000000, 0x7414);
+
+ pci_config_read(NULL, 0, 0x70, 4, &val);
+ val |= 1 << (8+16);
+ pci_config_write(NULL, 0, 0x70, 4, val);
+
+ pci_config_read(NULL, 0, 0x84, 4, &val);
+pr_info("slotcap1=%08x\n",val);
+
+ val &= ~(1 << 6); //hotplug capable
+ val &= ~(1 << 5); //hotplug surprise
+ val &= ~(1 << 0); //no attn
+ val &= ~(1 << 1); //no power control
+ val &= ~(1 << 2); //no manual retention sensor
+ val &= ~(1 << 3); //no attention indicator
+ val &= ~(1 << 4); //no power indicator
+ val &= ~(1 << 17); //no electromech interlock
+ pci_config_write(NULL, 0, 0x84, 4, val);
+
+ pci_config_read(NULL, 0, 0x84, 4, &val);
+pr_info("slotcap2=%08x\n",val);
+
+ pci_config_read(NULL, 0, 0x88, 4, &val);
+pr_info("slotstat=%08x\n",val);
+ val |= 0xffbf1008; //clear states
+ pci_config_write(NULL, 0, 0x88, 4, val);
+
+ pci_config_read(NULL, 0, 0x70c, 4, &val);
+ val &= ~(0xff) << 8;
+ val |= 0x80 << 8;
+ pci_config_write(NULL, 0, 0x70c, 4, val);
+
+// bridge_w32(0xffffffff,0x08);
+// pr_info("aft fl=%08lx\n",bridge_r32(0x08));
+#endif
+ /* Nothing to do */
+ return IRQ_HANDLED;
+}
static int mt7620_pci_hw_init(struct platform_device *pdev)
{
@@ -227,7 +319,7 @@ static int mt7620_pci_hw_init(struct platform_device *pdev)
pcie_phy(0x68, 0xB4);
/* put core into reset */
- pcie_m32(0, PCIRST, RALINK_PCI_PCICFG_ADDR);
+ bridge_m32(0, PCIRST, RALINK_PCI_PCICFG_ADDR);
reset_control_assert(rstpcie0);
/* disable power and all clocks */
@@ -237,7 +329,7 @@ static int mt7620_pci_hw_init(struct platform_device *pdev)
/* bring core out of reset */
reset_control_deassert(rstpcie0);
rt_sysc_m32(0, RALINK_PCIE0_CLK_EN, RALINK_CLKCFG1);
- mdelay(100);
+ msleep(100);
if (!(rt_sysc_r32(PPLL_CFG1) & PDRV_SW_SET)) {
dev_err(&pdev->dev, "MT7620 PPLL unlock\n");
@@ -256,25 +348,59 @@ static int mt7620_pci_hw_init(struct platform_device *pdev)
static int mt7628_pci_hw_init(struct platform_device *pdev)
{
u32 val = 0;
+ int err;
+ int irq;
- /* bring the core out of reset */
+ /* put core into reset */
+ reset_control_assert(rstpcie0);
+
+ /* FIXME someone with mt7620: is there link down interrupt too? */
+ irq = of_irq_get(pdev->dev.of_node, 0);
+ if (irq <= 0) {
+ dev_err(&pdev->dev, "failed to get IRQ\n");
+ return irq ? irq : -EINVAL;
+ }
+
+ err = devm_request_irq(&pdev->dev, irq, mt7628_irq_handler_link,
+ 0, "PCIe link down", NULL);
+ if (err) {
+ dev_err(&pdev->dev, "failed to request IRQ %i\n", irq);
+ return err;
+ }
+
+ /* disable GPIO on PERST pinmux */
rt_sysc_m32(BIT(16), 0, RALINK_GPIOMODE);
+
+ /* bring the core out of reset, PERST is left asserted */
reset_control_deassert(rstpcie0);
/* enable the pci clk */
rt_sysc_m32(0, RALINK_PCIE0_CLK_EN, RALINK_CLKCFG1);
- mdelay(100);
- /* voodoo from the SDK driver */
+ /* voodoo from the SDK driver, phy LDO setting: 1..1.0V - 5..1.2V */
pcie_m32(~0xff, 0x5, RALINK_PCIEPHY_P0_CTL_OFFSET);
+#if defined(RALINK_MT7628_SPREAD_SPECTRUM)
+ /* spread spectrum enable */
+ pcie_w32(0x10000000, 0x7414);
+#endif
+
+ /* wait for clock stabilization */
+ msleep(100);
+
+ /* set "slot implemented" flag */
+ pci_config_read(NULL, 0, 0x70, 4, &val);
+ val |= 1 << (8 + 16);
+ pci_config_write(NULL, 0, 0x70, 4, val);
+
+ /* Increase N_FTS, undocumented */
pci_config_read(NULL, 0, 0x70c, 4, &val);
val &= ~(0xff) << 8;
val |= 0x50 << 8;
pci_config_write(NULL, 0, 0x70c, 4, val);
pci_config_read(NULL, 0, 0x70c, 4, &val);
- dev_err(&pdev->dev, "Port 0 N_FTS = %x\n", (unsigned int) val);
+ dev_info(&pdev->dev, "Port 0 N_FTS = %x\n", (unsigned int) val);
return 0;
}
@@ -285,6 +411,8 @@ static int mt7620_pci_probe(struct platform_device *pdev)
IORESOURCE_MEM, 0);
struct resource *pcie_res = platform_get_resource(pdev,
IORESOURCE_MEM, 1);
+ struct pci_host_bridge *bridge;
+ int err;
u32 val = 0;
rstpcie0 = devm_reset_control_get_exclusive(&pdev->dev, "pcie0");
@@ -299,50 +427,56 @@ static int mt7620_pci_probe(struct platform_device *pdev)
if (IS_ERR(pcie_base))
return PTR_ERR(pcie_base);
- iomem_resource.start = 0;
- iomem_resource.end = ~0;
- ioport_resource.start = 0;
- ioport_resource.end = ~0;
-
/* bring up the pci core */
switch (ralink_soc) {
case MT762X_SOC_MT7620A:
- if (mt7620_pci_hw_init(pdev))
- return -1;
+ err = mt7620_pci_hw_init(pdev);
+ if (err)
+ goto fail_and_disable;
break;
case MT762X_SOC_MT7628AN:
case MT762X_SOC_MT7688:
- if (mt7628_pci_hw_init(pdev))
- return -1;
+ err = mt7628_pci_hw_init(pdev);
+ if (err)
+ goto fail_and_disable;
break;
default:
dev_err(&pdev->dev, "pcie is not supported on this hardware\n");
- return -1;
+ err = -ENODEV;
+ goto fail_and_disable;
}
- mdelay(50);
- /* enable write access */
- pcie_m32(PCIRST, 0, RALINK_PCI_PCICFG_ADDR);
- mdelay(100);
+ /*
+ * deactivate PERST after power and clock stabilization
+ *
+ * FIXME if mt7620 leaves PERST asserted too,
+ * next wait can probably go away
+ */
+ msleep(50);
+ bridge_m32(PCIRST, 0, RALINK_PCI_PCICFG_ADDR);
+
+ /* wait until device enables link */
+ msleep(100);
/* check if there is a card present */
if ((pcie_r32(RALINK_PCI0_STATUS) & PCIE_LINK_UP_ST) == 0) {
- reset_control_assert(rstpcie0);
- rt_sysc_m32(RALINK_PCIE0_CLK_EN, 0, RALINK_CLKCFG1);
- if (ralink_soc == MT762X_SOC_MT7620A)
- rt_sysc_m32(LC_CKDRVPD, PDRV_SW_SET, PPLL_DRV);
- dev_err(&pdev->dev, "PCIE0 no card, disable it(RST&CLK)\n");
- return -1;
+ dev_err(&pdev->dev, "No card detected, disable PCIe core\n");
+ err = -ENODEV;
+ goto fail_and_disable;
}
- /* setup ranges */
- bridge_w32(0xffffffff, RALINK_PCI_MEMBASE);
- bridge_w32(RALINK_PCI_IO_MAP_BASE, RALINK_PCI_IOBASE);
+ /* offset of access in 0x1015xxxx will add to the reg val */
+ bridge_w32(0x30000000, RALINK_PCI_MEM_OFFSET); //a valid value
+
+ /* no offset for IO access */
+ bridge_w32(0, RALINK_PCI_IO_OFFSET);
+
+ /* default offset for busmaster = beginning of RAM */
+ pcie_w32(RALINK_PCI_BUSMASTER_OFFSET, RALINK_PCI0_IMBASEBAR0_ADDR);
- pcie_w32(0x7FFF0001, RALINK_PCI0_BAR0SETUP_ADDR);
- pcie_w32(RALINK_PCI_MEMORY_BASE, RALINK_PCI0_IMBASEBAR0_ADDR);
+ /* change default class (wifi adapter) */
pcie_w32(0x06040001, RALINK_PCI0_CLASS);
/* enable interrupts */
@@ -352,51 +486,45 @@ static int mt7620_pci_probe(struct platform_device *pdev)
pci_config_read(NULL, 0, 4, 4, &val);
pci_config_write(NULL, 0, 4, 4, val | 0x7);
- pci_load_of_ranges(&mt7620_controller, pdev->dev.of_node);
- register_pci_controller(&mt7620_controller);
+ /* don't start IO ports from 0 */
+ PCIBIOS_MIN_IO = 0x1000;
+ PCIBIOS_MIN_MEM = 0x20000000;
- return 0;
-}
+ set_io_port_base(KSEG1 + RALINK_PCI_IO_MAP_BASE);
-int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
-{
- u16 cmd;
- u32 val;
- int irq = 0;
-
- if ((dev->bus->number == 0) && (slot == 0)) {
- pcie_w32(0x7FFF0001, RALINK_PCI0_BAR0SETUP_ADDR);
- pci_config_write(dev->bus, 0, PCI_BASE_ADDRESS_0, 4,
- RALINK_PCI_MEMORY_BASE);
- pci_config_read(dev->bus, 0, PCI_BASE_ADDRESS_0, 4, &val);
- } else if ((dev->bus->number == 1) && (slot == 0x0)) {
- irq = RALINK_INT_PCIE0;
- } else {
- dev_err(&dev->dev, "no irq found - bus=0x%x, slot = 0x%x\n",
- dev->bus->number, slot);
- return 0;
+ bridge = devm_pci_alloc_host_bridge(&pdev->dev, 0);
+ if (!bridge) {
+ err = -ENOMEM;
+ goto fail_and_disable;
}
- dev_err(&dev->dev, "card - bus=0x%x, slot = 0x%x irq=%d\n",
- dev->bus->number, slot, irq);
-
- /* configure the cache line size to 0x14 */
- pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x14);
-
- /* configure latency timer to 0xff */
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xff);
- pci_read_config_word(dev, PCI_COMMAND, &cmd);
-
- /* setup the slot */
- cmd = cmd | PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
- pci_write_config_word(dev, PCI_COMMAND, cmd);
- pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
- return irq;
-}
+ err = pci_parse_request_of_pci_ranges(&pdev->dev, &bridge->windows, NULL);
+ if (err)
+ goto fail_and_disable;
+
+ bridge->dev.parent = &pdev->dev;
+ bridge->busnr = 0;
+ bridge->ops = &mt7620_pci_ops;
+ bridge->swizzle_irq = pci_common_swizzle;
+ bridge->map_irq = of_irq_parse_and_map_pci;
+
+ err = pci_host_probe(bridge);
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed to probe host %d\n", err);
+ pci_free_resource_list(&bridge->windows);
+ goto fail_and_disable;
+ }
-int pcibios_plat_dev_init(struct pci_dev *dev)
-{
return 0;
+
+fail_and_disable:
+#if 0
+ reset_control_assert(rstpcie0);
+ rt_sysc_m32(RALINK_PCIE0_CLK_EN, 0, RALINK_CLKCFG1);
+ if (ralink_soc == MT762X_SOC_MT7620A)
+ rt_sysc_m32(LC_CKDRVPD, PDRV_SW_SET, PPLL_DRV);
+#endif
+ return err;
}
static const struct of_device_id mt7620_pci_ids[] = {
@@ -414,7 +542,32 @@ static struct platform_driver mt7620_pci_driver = {
static int __init mt7620_pci_init(void)
{
- return platform_driver_register(&mt7620_pci_driver);
+ int ret;
+
+ ret = platform_driver_register(&mt7620_pci_driver);
+ return ret;
}
arch_initcall(mt7620_pci_init);
+
+static void mediatek_fixup_bar(struct pci_dev *dev) {
+pr_info("++++++ mediatek_fixup_bar dev=%px\n",dev);
+
+//TODO probably put it directly to init, here only if mt7620 work OK
+// dev->non_compliant_bars = true;
+
+ pcie_w32(0x0, RALINK_PCI0_BAR0SETUP_ADDR);
+ pcie_w32(0x0, RALINK_PCI0_BAR0SETUP_ADDR + 4);
+}
+DECLARE_PCI_FIXUP_EARLY(0x14c3, 0x0801, mediatek_fixup_bar);
+
+static void mediatek_fixup_final_bar(struct pci_dev *dev) {
+
+pr_info("++++++ MTK final fixup, BAR0 must-be-set bug\n");
+
+ pcie_w32(0x0FFF0001, RALINK_PCI0_BAR0SETUP_ADDR);
+ pcie_w32(0x0FFF0001, RALINK_PCI0_BAR0SETUP_ADDR);
+}
+
+//TODO for mt7620 ... or does it works there OK?
+DECLARE_PCI_FIXUP_FINAL(0x14c3, 0x0801, mediatek_fixup_final_bar);
@@ -38,8 +38,14 @@ choice
config SOC_MT7620
bool "MT7620/8"
+ select SYS_SUPPORTS_HIGHMEM
select CPU_MIPSR2_IRQ_VI
select HAVE_PCI
+# select COMMON_CLK
+ select CPU_HAS_PREFETCH
+ select PCI_DRIVERS_GENERIC
+ select NO_GENERIC_PCI_IOPORT_MAP
+
config SOC_MT7621
bool "MT7621"
@@ -3941,6 +3941,8 @@ unsigned long __weak pci_address_to_pio(phys_addr_t address)
*/
int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr)
{
+
+#if 0
#if defined(PCI_IOBASE) && defined(CONFIG_MMU)
unsigned long vaddr = (unsigned long)PCI_IOBASE + res->start;
@@ -3960,6 +3962,8 @@ int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr)
WARN_ONCE(1, "This architecture does not support memory mapped I/O\n");
return -ENODEV;
#endif
+#endif
+return 0;
}
EXPORT_SYMBOL(pci_remap_iospace);
Hello, I've finally managed to clean the code to publishable format. The code is RFC because I have few questions. Most likely for MT7620 SoC behavior and the fact I've had to change general PCI subsystem (one function). All functionality was tested on MT7628 SoC in vocore2 board. The changes (along with lots of new comments): 1) Renamed few registers, they had misleading name and they was wrongly used: #define RALINK_PCI_IO_MAP_BASE 0x10160000 -#define RALINK_PCI_MEMORY_BASE 0x0 ... -#define RALINK_PCI_MEMBASE 0x28 -#define RALINK_PCI_IOBASE 0x2C +#define RALINK_PCI_MEM_OFFSET 0x28 +#define RALINK_PCI_IO_OFFSET 0x2C ... - /* setup ranges */ - bridge_w32(0xffffffff, RALINK_PCI_MEMBASE); - bridge_w32(RALINK_PCI_IO_MAP_BASE, RALINK_PCI_IOBASE); + /* offset of access in 0x1015xxxx will add to the reg val */ + bridge_w32(0x30000000, RALINK_PCI_MEM_OFFSET); //a valid value + /* no offset for IO access */ + bridge_w32(0, RALINK_PCI_IO_OFFSET); The RALINK_PCI_IOBASE register is not for value 0x10160000, but more like for an offset. Any access in RALINK_PCI_IO_MAP_BASE area (0x10000 length) will generate IO transaction from 0 to 0xffff. RALINK_PCI_IOBASE can add an offset to this. 2) The probe error path was reworked so it will return things like -ENODEV instead just -1. Plus in the case of an error during hw initialization the driver will always reset the PCIe core. The "no card found" message was little reworked. Maybe we could change dev_err to just dev_info. It is error path, but the missing card is a valid state and the message is only informative. + +fail_and_disable: +#if 0 + reset_control_assert(rstpcie0); + rt_sysc_m32(RALINK_PCIE0_CLK_EN, 0, RALINK_CLKCFG1); + if (ralink_soc == MT762X_SOC_MT7620A) + rt_sysc_m32(LC_CKDRVPD, PDRV_SW_SET, PPLL_DRV); +#endif + return err; (if 0 is just for debug ;-) ) 3) non compliant BARs - pcie_w32(0x7FFF0001, RALINK_PCI0_BAR0SETUP_ADDR); This sets the BAR size of host bridge (which is not exactly used). The problem is the PCIe core is designed badly, so this value also sets the size of accessible RAM for PCIe busmaster (device access host RAM). If you want to access the whole RAM, you must set this to 256MB. The problem is this register allows BAR0 to be detected with the same size and PCI probe will assign 256MB windows to unused host bridge. The 256MB PCIe region is also the max size for MT7628 SoC (-> there is no space left for cards). I've workarounded this by setting the bar size to 0 in DECLARE_PCI_FIXUP_EARLY and later after PCI probing I set this to 256MB (ram size) in DECLARE_PCI_FIXUP_FINAL. RFC here: if the behavior of RALINK_PCI0_BAR0SETUP_ADDR is the same in MT7620 (as in MT7628), please let me know, maybe the first DECLARE_PCI_FIXUP_EARLY can be moved just to global probe(). Also send me the default VID/PID of MT7620 (maybe MT7688, but I assume these are same as MT7628). 4) Added missing reset assertion + some info about what is what - /* bring the core out of reset */ + /* put core into reset */ + reset_control_assert(rstpcie0); ... + /* disable GPIO on PERST pinmux */ rt_sysc_m32(BIT(16), 0, RALINK_GPIOMODE); + + /* bring the core out of reset, PERST is left asserted */ reset_control_deassert(rstpcie0); 5) I've added something like emergency interrupt handler. It seems the link down signal from the core is connected to the core reset, so if you unplug the card or the link is weak and it drops the PCIe core will reset, all registers/settings will be erased, interrupt and transactions disabled. This means any card and its driver will get probably locked up. + /* FIXME someone with mt7620: is there link down interrupt too? */ + irq = of_irq_get(pdev->dev.of_node, 0); + if (irq <= 0) { + dev_err(&pdev->dev, "failed to get IRQ\n"); + return irq ? irq : -EINVAL; + } + + err = devm_request_irq(&pdev->dev, irq, mt7628_irq_handler_link, + 0, "PCIe link down", NULL); + if (err) { + dev_err(&pdev->dev, "failed to request IRQ %i\n", irq); + return err; + } And the handler: +/* + * TODO change it to WARN or BUG + * if this irq occurs, the PCIe controller "crashed" + * otherwise it would meant link down normally + */ +static irqreturn_t mt7628_irq_handler_link(int irq, void *data) +{ + u32 val = 0; + + pr_emerg("PCIe link down, unstable system due HW BUG\n"); + +//TODO maybe call bug? +//delete vvvv, not working! +#if 0 + + pr_info("**PCIe link down event %08x %08x\n", + bridge_r32(0x08), + pcie_r32(0x7414) + ); + + /* voodoo from the SDK driver */ + pcie_m32(~0xff, 0x5, RALINK_PCIEPHY_P0_CTL_OFFSET); + + // spread spectrum enable + pcie_w32(0x10000000, 0x7414); + + pci_config_read(NULL, 0, 0x70, 4, &val); + val |= 1 << (8+16); + pci_config_write(NULL, 0, 0x70, 4, val); + + pci_config_read(NULL, 0, 0x84, 4, &val); +pr_info("slotcap1=%08x\n",val); + + val &= ~(1 << 6); //hotplug capable + val &= ~(1 << 5); //hotplug surprise + val &= ~(1 << 0); //no attn + val &= ~(1 << 1); //no power control + val &= ~(1 << 2); //no manual retention sensor + val &= ~(1 << 3); //no attention indicator + val &= ~(1 << 4); //no power indicator + val &= ~(1 << 17); //no electromech interlock + pci_config_write(NULL, 0, 0x84, 4, val); + + pci_config_read(NULL, 0, 0x84, 4, &val); +pr_info("slotcap2=%08x\n",val); + + pci_config_read(NULL, 0, 0x88, 4, &val); +pr_info("slotstat=%08x\n",val); + val |= 0xffbf1008; //clear states + pci_config_write(NULL, 0, 0x88, 4, val); + + pci_config_read(NULL, 0, 0x70c, 4, &val); + val &= ~(0xff) << 8; + val |= 0x80 << 8; + pci_config_write(NULL, 0, 0x70c, 4, val); + +// bridge_w32(0xffffffff,0x08); +// pr_info("aft fl=%08lx\n",bridge_r32(0x08)); +#endif + /* Nothing to do */ + return IRQ_HANDLED; +} This handler should probably end with a kernel panic and the system will get locked/non coherent after that. (The code remains were just hotplug tests - the SoC obviously don't supports them) RFC: does 7620 and 7688 behaves same? 6) Bugfixes: Register access in the wrong region. - pcie_m32(0, PCIRST, RALINK_PCI_PCICFG_ADDR); + bridge_m32(0, PCIRST, RALINK_PCI_PCICFG_ADDR); ... mdelay() to msleep() changes. - /* voodoo from the SDK driver */ + /* voodoo from the SDK driver, phy LDO setting: 1..1.0V - 5..1.2V */ ... be more descriptive from SDK driver. 7) Interrupt handling is now done from devicetree (function of_irq_parse_and_map_pci()), all devices shares IRQ 4 line of MIPS controller. There is no MSI (as from available documentations). 8) Dependency on pci-legacy was removed, the driver now uses the general driver/pci functions as: devm_pci_alloc_host_bridge() pci_parse_request_of_pci_ranges() pci_host_probe() The IO port mapping is done by new functions: +unsigned long pci_address_to_pio(phys_addr_t address) +{ + +//get 0- 0xffff IO port value from physical address + return address - RALINK_PCI_IO_MAP_BASE; +} + +void __iomem *__pci_ioport_map(struct pci_dev *dev, + unsigned long port, unsigned int nr) +{ + void __iomem * temp; + +//get iomem address for driver accesses from IO port value + temp = (void __iomem *) (mips_io_port_base + port); + + return temp; +} + The problem is with general pci_remap_iospace() function, the code will fail without defined PCI_IOBASE in arch/mips. As defining PCI_IOBASE would changed too much of the code in arch/mips I've just disabled the check in pci_remap_iospace(). This could be solved by defining pci_remap_iospace() as a weak function too. Anyway this is just RFC, so if you have some remarks about PCI_IOBASE support feel free to comment. The functionality was successfully tested with a real card. The example of devicetree node (present only in openwrt): pcie@10140000 { compatible = "mediatek,mt7620-pci"; reg = <0x10140000 0x100 0x10142000 0x8000>; #address-cells = <3>; #size-cells = <2>; resets = <&resetc 26>; reset-names = "pcie0"; interrupt-parent = <&intc>; interrupts = <16>; status = "okay"; device_type = "pci"; bus-range = <0x0 0xff>; ranges = < /* pci memory */ 0x02000000 0 0x20000000 0x20000000 0 0x10000000 /* io space, NOTICE start from 0x1000, some cards and kernel don't like 0 */ 0x01000000 0 0x00000000 0x10160000 0 0x00010000 /* pci memory, window offsetable by 0x28 reg */ // 0x02000000 0 0x30000000 0x10150000 0 0x00010000 >; #interrupt-cells = <1>; interrupt-map-mask = <0xf800 0 0 1>; interrupt-map = <0x0000 0 0 1 &cpuintc 4 3 >; }; Regards, Petr --- arch/mips/pci/pci-mt7620.c | 329 +++++++++++++++++++++++++++---------- arch/mips/ralink/Kconfig | 6 + drivers/pci/pci.c | 4 + 3 files changed, 251 insertions(+), 88 deletions(-)