Hi René, > Sorry Gabor for the following patch, but it seems your patchset was > against a other tree? Both of my patch sets was based on the 'mips-for-linux-next' branch of Ralf's 'upstream-sfr' tree: git://git.linux-mips.org/pub/scm/ralf/upstream-sfr.git > Because of the many failures I rebase'ed against 09521577ca7718b6c of the > linus tree and written anything from scratch. That was waste of time. The ath79 platform got a pile of changes recently, and those changes are not yet available in Linus' tree. If you were unsure about the tree, you should have asked earlier. > - The ar724x pci build only then SOC_AR724X and AR724X_PCI is set. > (new symbol AR724X_PCI) > - We have a shared PCI header file for both controllers. (Only AR724x > is included atm) > - We have a default irq map if the board pass no other map with > ar724x_pci_add_data. > - I added the fix for the 7240 controller bug, hopefully right. > Gabor, can you please test the patch? I can tell without testing that this is not working, see below. > > René > > diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig > index 4770741..e763661 100644 > --- a/arch/mips/ath79/Kconfig > +++ b/arch/mips/ath79/Kconfig > @@ -23,6 +23,16 @@ config ATH79_MACH_PB44 > Say 'Y' here if you want your kernel to support the > Atheros PB44 reference board. > > +config ATH79_MACH_UBNT_XM > + bool "Ubiquiti Networks XM (rev 1.0) board" > + select SOC_AR724X > + select ATH79_DEV_GPIO_BUTTONS > + select ATH79_DEV_LEDS_GPIO > + select ATH79_DEV_SPI > + help > + Say 'Y' here if you want your kernel to support the > + Ubiquiti Networks XM (rev 1.0) board. > + > endmenu > > config SOC_AR71XX > @@ -33,6 +43,7 @@ config SOC_AR71XX > config SOC_AR724X > select USB_ARCH_HAS_EHCI > select USB_ARCH_HAS_OHCI > + select HW_HAS_PCI > def_bool n > > config SOC_AR913X > @@ -52,4 +63,8 @@ config ATH79_DEV_LEDS_GPIO > config ATH79_DEV_SPI > def_bool n > > +config AR724X_PCI > + depends on PCI > + def_bool y > + > endif Why would we have to add yet another Kconfig symbol? The AR724X specific code is only build when both PCI and SOC_AR724X is selected (in Ralf's tree, and in linux-next). > diff --git a/arch/mips/ath79/Makefile b/arch/mips/ath79/Makefile > index c33d465..ac9f375 100644 > --- a/arch/mips/ath79/Makefile > +++ b/arch/mips/ath79/Makefile > @@ -26,3 +26,4 @@ obj-$(CONFIG_ATH79_DEV_SPI) += dev-spi.o > # > obj-$(CONFIG_ATH79_MACH_AP81) += mach-ap81.o > obj-$(CONFIG_ATH79_MACH_PB44) += mach-pb44.o > +obj-$(CONFIG_ATH79_MACH_UBNT_XM) += mach-ubnt-xm.o > diff --git a/arch/mips/ath79/mach-ubnt-xm.c b/arch/mips/ath79/mach-ubnt-xm.c > new file mode 100644 > index 0000000..6fadd0b > --- /dev/null > +++ b/arch/mips/ath79/mach-ubnt-xm.c > @@ -0,0 +1,121 @@ > +/* > + * Ubiquiti Networks XM (rev 1.0) board support > + * > + * Copyright (C) 2011 René Bolldorf <xsecute@xxxxxxxxxxxxxx> > + * > + * Derived from: mach-pb44.c > + * > + * 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/init.h> > +#include <linux/pci.h> > + > +#ifdef CONFIG_PCI > +#include <linux/ath9k_platform.h> > +#include <asm/mach-ath79/pci.h> > +#include <asm/mach-ath79/irq.h> > +#endif /* CONFIG_PCI */ > + > +#include "machtypes.h" > +#include "dev-gpio-buttons.h" > +#include "dev-leds-gpio.h" > +#include "dev-spi.h" > + > +#define UBNT_XM_GPIO_LED_L1 0 > +#define UBNT_XM_GPIO_LED_L2 1 > +#define UBNT_XM_GPIO_LED_L3 11 > +#define UBNT_XM_GPIO_LED_L4 7 > + > +#define UBNT_XM_GPIO_BTN_RESET 12 > + > +#define UBNT_XM_KEYS_POLL_INTERVAL 20 > +#define UBNT_XM_KEYS_DEBOUNCE_INTERVAL (3 * UBNT_XM_KEYS_POLL_INTERVAL) > + > +#define UBNT_XM_EEPROM_ADDR (u8 *) KSEG1ADDR(0x1fff1000) > + > +static struct gpio_led ubnt_xm_leds_gpio[] __initdata = { > + { > + .name = "ubnt-xm:red:link1", > + .gpio = UBNT_XM_GPIO_LED_L1, > + .active_low = 0, > + }, { > + .name = "ubnt-xm:orange:link2", > + .gpio = UBNT_XM_GPIO_LED_L2, > + .active_low = 0, > + }, { > + .name = "ubnt-xm:green:link3", > + .gpio = UBNT_XM_GPIO_LED_L3, > + .active_low = 0, > + }, { > + .name = "ubnt-xm:green:link4", > + .gpio = UBNT_XM_GPIO_LED_L4, > + .active_low = 0, > + }, > +}; > + > +static struct gpio_keys_button ubnt_xm_gpio_keys[] __initdata = { > + { > + .desc = "reset", > + .type = EV_KEY, > + .code = KEY_RESTART, > + .debounce_interval = UBNT_XM_KEYS_DEBOUNCE_INTERVAL, > + .gpio = UBNT_XM_GPIO_BTN_RESET, > + .active_low = 1, > + } > +}; > + > +static struct spi_board_info ubnt_xm_spi_info[] = { > + { > + .bus_num = 0, > + .chip_select = 0, > + .max_speed_hz = 25000000, > + .modalias = "mx25l6405d", > + } > +}; > + > +static struct ath79_spi_platform_data ubnt_xm_spi_data = { > + .bus_num = 0, > + .num_chipselect = 1, > +}; > + > +#ifdef CONFIG_PCI > +static struct ath9k_platform_data ubnt_xm_eeprom_data; > + > +static struct ath79_pci_data ubnt_xm_pci_data[] = { > + { > + .slot = 0, > + .pin = 1, > + .irq = ATH79_PCI_IRQ(0), > + .pdata = &ubnt_xm_eeprom_data, > + }, > +}; > +#endif /* CONFIG_PCI */ > + > +static void __init ubnt_xm_init(void) > +{ > + ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_xm_leds_gpio), > + ubnt_xm_leds_gpio); > + > + ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL, > + ARRAY_SIZE(ubnt_xm_gpio_keys), > + ubnt_xm_gpio_keys); > + > + ath79_register_spi(&ubnt_xm_spi_data, ubnt_xm_spi_info, > + ARRAY_SIZE(ubnt_xm_spi_info)); > + > +#ifdef CONFIG_PCI > + memcpy(ubnt_xm_eeprom_data.eeprom_data, UBNT_XM_EEPROM_ADDR, > + sizeof(ubnt_xm_eeprom_data.eeprom_data)); > + > + ar724x_pci_add_data(ubnt_xm_pci_data, ARRAY_SIZE(ubnt_xm_pci_data)); > +#endif /* CONFIG_PCI */ > + > +} > + > +MIPS_MACHINE(ATH79_MACH_UBNT_XM, > + "UBNT-XM", > + "Ubiquiti Networks XM (rev 1.0) board", > + ubnt_xm_init); > diff --git a/arch/mips/ath79/machtypes.h b/arch/mips/ath79/machtypes.h > index 3940fe4..35d5d5c 100644 > --- a/arch/mips/ath79/machtypes.h > +++ b/arch/mips/ath79/machtypes.h > @@ -18,6 +18,7 @@ enum ath79_mach_type { > ATH79_MACH_GENERIC = 0, > ATH79_MACH_AP81, /* Atheros AP81 reference board */ > ATH79_MACH_PB44, /* Atheros PB44 reference board */ > + ATH79_MACH_UBNT_XM, /* Ubiquiti Networks XM board rev 1.0 */ > }; > > #endif /* _ATH79_MACHTYPE_H */ > diff --git a/arch/mips/include/asm/mach-ath79/irq.h > b/arch/mips/include/asm/mach-ath79/irq.h > index 189bc6e..eb68e79 100644 > --- a/arch/mips/include/asm/mach-ath79/irq.h > +++ b/arch/mips/include/asm/mach-ath79/irq.h > @@ -10,11 +10,15 @@ > #define __ASM_MACH_ATH79_IRQ_H > > #define MIPS_CPU_IRQ_BASE 0 > -#define NR_IRQS 16 > +#define NR_IRQS 22 > This will conflict with other changes already in linux-next. > #define ATH79_MISC_IRQ_BASE 8 > #define ATH79_MISC_IRQ_COUNT 8 > > +#define ATH79_PCI_IRQ_BASE (ATH79_MISC_IRQ_BASE + ATH79_MISC_IRQ_COUNT) > +#define ATH79_PCI_IRQ_COUNT 6 > +#define ATH79_PCI_IRQ(_x) (ATH79_PCI_IRQ_BASE + (_x)) > + > #define ATH79_CPU_IRQ_IP2 (MIPS_CPU_IRQ_BASE + 2) > #define ATH79_CPU_IRQ_USB (MIPS_CPU_IRQ_BASE + 3) > #define ATH79_CPU_IRQ_GE0 (MIPS_CPU_IRQ_BASE + 4) > diff --git a/arch/mips/include/asm/mach-ath79/pci.h > b/arch/mips/include/asm/mach-ath79/pci.h > new file mode 100644 > index 0000000..f671174 > --- /dev/null > +++ b/arch/mips/include/asm/mach-ath79/pci.h > @@ -0,0 +1,24 @@ > +/* > + * Atheros 71xx/724x PCI support > + * > + * Copyright (C) 2011 René Bolldorf <xsecute@xxxxxxxxxxxxxx> > + * Copyright (C) 2009-2011 Gabor Juhos <juhosg@xxxxxxxxxxx> > + * > + * 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. > + */ > + > +#ifndef __ASM_MACH_ATH79_PCI_H > +#define __ASM_MACH_ATH79_PCI_H > + > +struct ath79_pci_data { > + uint8_t slot; > + uint8_t pin; > + int irq; > + void *pdata; > +}; > + > +void ar724x_pci_add_data(struct ath79_pci_data *data, int size); > + > +#endif /* __ASM_MACH_ATH79_PCI_H */ > diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile > index bb82cbd..6603594 100644 > --- a/arch/mips/pci/Makefile > +++ b/arch/mips/pci/Makefile > @@ -19,6 +19,7 @@ obj-$(CONFIG_BCM47XX) += pci-bcm47xx.o > obj-$(CONFIG_BCM63XX) += pci-bcm63xx.o fixup-bcm63xx.o \ > ops-bcm63xx.o > obj-$(CONFIG_MIPS_ALCHEMY) += pci-alchemy.o > +obj-$(CONFIG_AR724X_PCI) += pci-ar724x.o > > # > # These are still pretty much in the old state, watch, go blind. > diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c > new file mode 100644 > index 0000000..66974fa > --- /dev/null > +++ b/arch/mips/pci/pci-ar724x.c > @@ -0,0 +1,284 @@ > +/* > + * Atheros 724x PCI support > + * > + * Copyright (C) 2011 René Bolldorf <xsecute@xxxxxxxxxxxxxx> > + * Copyright (C) 2009-2011 Gabor Juhos <juhosg@xxxxxxxxxxx> > + * > + * 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/pci.h> > +#include <linux/irq.h> > +#include <asm/mach-ath79/ath79.h> > +#include <asm/mach-ath79/pci.h> > +#include <asm/mach-ath79/irq.h> > +#include <asm/mach-ath79/ar71xx_regs.h> > + > +#define AR724X_PCI_CFG_BASE 0x14000000 > +#define AR724X_PCI_CFG_SIZE 0x1000 > +#define AR724X_PCI_CTRL_BASE (AR71XX_APB_BASE + 0x000f0000) > +#define AR724X_PCI_CTRL_SIZE 0x100 > + > +#define AR724X_PCI_MEM_BASE 0x10000000 > +#define AR724X_PCI_MEM_SIZE 0x08000000 > + > +#define AR724X_PCI_REG_INT_STATUS 0x4c > +#define AR724X_PCI_REG_INT_MASK 0x50 > +#define AR724X_PCI_INT_DEV0 BIT(14) > + > +#define AR7240_BAR0_WAR_VALUE 0xffff > + > +static DEFINE_SPINLOCK(ar724x_pci_lock); > + > +static void __iomem *ar724x_pci_devcfg_base; > +static void __iomem *ar724x_pci_ctrl_base; > + > +static struct ath79_pci_data *pci_data; > +static int pci_data_size = -1; > + > +static u32 ar724x_pci_bar0_value; > +static bool ar724x_pci_bar0_is_cached; > + > +static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, > + int size, uint32_t *value) > +{ > + unsigned long flags; > + void __iomem *base; > + > + if (devfn) > + return PCIBIOS_DEVICE_NOT_FOUND; > + > + base = ar724x_pci_devcfg_base; > + > + spin_lock_irqsave(&ar724x_pci_lock, flags); > + > + switch (size) { > + case 1: > + *value = (__raw_readl(base + (where & ~3)) & 0xff); This is wrong. This will always return the least significant byte, instead of the right one. And the outermost parens are not needed. > + break; > + case 2: > + *value = (__raw_readl(base + (where & ~3)) & 0xffff); This is wrong as well. > + break; > + case 4: > + if (soc_is_ar7240() && where == PCI_BASE_ADDRESS_0 && > + ar724x_pci_bar0_is_cached) > + /* use the cached value */ > + *value = ar724x_pci_bar0_value; > + else > + *value = __raw_readl(base + where); > + break; > + default: > + spin_unlock_irqrestore(&ar724x_pci_lock, flags); > + > + return PCIBIOS_BAD_REGISTER_NUMBER; > + } > + > + spin_unlock_irqrestore(&ar724x_pci_lock, flags); > + > + return PCIBIOS_SUCCESSFUL; > +} > + > +static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, > + int size, uint32_t value) > +{ > + unsigned long flags; > + void __iomem *base; > + > + 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. > + */ > + ar724x_pci_bar0_is_cached = true; > + ar724x_pci_bar0_value = value; > + value = AR7240_BAR0_WAR_VALUE; > + } else { > + ar724x_pci_bar0_is_cached = false; > + } > + } > + > + base = ar724x_pci_devcfg_base; > + > + spin_lock_irqsave(&ar724x_pci_lock, flags); > + > + switch (size) { > + case 1: > + value = (__raw_readl(base + (where & ~3)) & 0xff); > + __raw_writel(value, base + (where & ~3)); Wrong. This reads the register, and masks out everything but the least significant byte, and writes the results back to the same register. It must modify the right byte intead. > + break; > + case 2: > + value = (__raw_readl(base + (where & ~3)) & 0xffff); > + __raw_writel(value, base + (where & ~3)); Also wrong (with words instead of bytes). > + break; > + case 4: > + __raw_writel(value, (base + where)); > + break; > + default: > + spin_unlock_irqrestore(&ar724x_pci_lock, flags); > + > + return PCIBIOS_BAD_REGISTER_NUMBER; > + } > + > + spin_unlock_irqrestore(&ar724x_pci_lock, flags); > + > + return PCIBIOS_SUCCESSFUL; > +} > + > +static struct pci_ops ar724x_pci_ops = { > + .read = ar724x_pci_read, > + .write = ar724x_pci_write, > +}; > + > +static struct resource ar724x_io_resource = { > + .name = "PCI IO space", > + .start = 0, > + .end = 0, > + .flags = IORESOURCE_IO, > +}; > + > +static struct resource ar724x_mem_resource = { > + .name = "PCI memory space", > + .start = AR724X_PCI_MEM_BASE, > + .end = AR724X_PCI_MEM_BASE + AR724X_PCI_MEM_SIZE - 1, > + .flags = IORESOURCE_MEM, > +}; > + > +static struct pci_controller ar724x_pci_controller = { > + .pci_ops = &ar724x_pci_ops, > + .io_resource = &ar724x_io_resource, > + .mem_resource = &ar724x_mem_resource, > +}; > + > +static void ar724x_pci_irq_mask(struct irq_data *data) > +{ > + void __iomem *base; > + u32 t; > + > + base = ar724x_pci_ctrl_base; > + > + switch (data->irq) { > + case ATH79_PCI_IRQ(0): > + t = __raw_readl(base + AR724X_PCI_REG_INT_MASK); > + __raw_writel(t & ~AR724X_PCI_INT_DEV0, > + base + AR724X_PCI_REG_INT_MASK); A __raw_readl is missing. > + > + t = __raw_readl(base + AR724X_PCI_REG_INT_STATUS); > + __raw_writel(t | AR724X_PCI_INT_DEV0, > + base + AR724X_PCI_REG_INT_STATUS); Here too. > + } > +} > + > +static void ar724x_pci_irq_unmask(struct irq_data *data) > +{ > + void __iomem *base; > + u32 t; > + > + base = ar724x_pci_ctrl_base; > + > + switch (data->irq) { > + case ATH79_PCI_IRQ(0): > + t = __raw_readl(base + AR724X_PCI_REG_INT_MASK); > + __raw_writel(t | AR724X_PCI_INT_DEV0, > + base + AR724X_PCI_REG_INT_MASK); And here also. > + } > +} > + > +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 __initconst struct ath79_pci_data ar724x_default_pci_data[] = { __initconst must be placed after []. > + { > + .slot = 0, > + .pin = 1, > + .irq = ATH79_PCI_IRQ(0), > + }, > +}; > + > +void ar724x_pci_add_data(struct ath79_pci_data *data, int size) > +{ > + pci_data = data; > + pci_data_size = size; > +} > + > +int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, > uint8_t pin) > +{ > + int irq = -1; > + int i; > + > + if (pci_data_size == -1) > + return irq; > + > + for (i = 0; i < pci_data_size; i++) { > + if ((pci_data[i].slot == slot) && (pci_data[i].pin == pin)) { > + if (pci_data[i].irq != 0) > + irq = pci_data[i].irq; > + break; Wrong indentation for the break statement. > + } > + } > + > + return irq; > +} > + > +int pcibios_plat_dev_init(struct pci_dev *dev) > +{ > + int i; > + > + if (pci_data_size == -1) > + return PCIBIOS_DEVICE_NOT_FOUND; > + > + for (i = 0; i < pci_data_size; i++) { > + if (pci_data[i].slot == PCI_SLOT(dev->devfn)) { > + if (pci_data[i].pdata != NULL) > + dev->dev.platform_data = pci_data[i].pdata; > + break; Ditto. > + } > + } > + > + return PCIBIOS_SUCCESSFUL; > +} > + > +static int __init ar724x_pcibios_init(void) > +{ > + int i; > + > + ar724x_pci_devcfg_base = ioremap_nocache(AR724X_PCI_CFG_BASE, > + AR724X_PCI_CFG_SIZE); ioremap can be used instead of ioremap_nocache. > + if (ar724x_pci_devcfg_base == NULL) > + return -ENOMEM; > + > + ar724x_pci_ctrl_base = ioremap_nocache(AR724X_PCI_CTRL_BASE, > + AR724X_PCI_CTRL_SIZE); > + if (ar724x_pci_ctrl_base == NULL) > + return -ENOMEM; ar724x_pci_devcfg_base must be unmapped if the second iomap call fails. > + > + if (pci_data == NULL) > + pci_data = ar724x_default_pci_data; > + pci_data_size = ARRAY_SIZE(ar724x_default_pci_data); Braces are missing from this if statement. The AR724X_PCI_IRQ_REG_INT_{MASK,STATUS} registers must be cleared here. > + > + for (i = ATH79_PCI_IRQ_BASE; > + i < ATH79_PCI_IRQ_BASE + ATH79_PCI_IRQ_COUNT; i++) > + irq_set_chip_and_handler(i, &ar724x_pci_irq_chip, > + handle_level_irq); The 'irq_set_chained_handler' call is missing here. And the ar724x_pci_irq_handler function is completely missing from the patch. > + > + register_pci_controller(&ar724x_pci_controller); > + > + return PCIBIOS_SUCCESSFUL; > +} > + > +arch_initcall(ar724x_pcibios_init); Regards, Gabor