From: Hauke Mehrtens Date: Tue, 4 Feb 2014 22:54:29 +0000 (+0000) Subject: kernel: ssb: update ssb to a version from kernel 3.14-rc1 X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=7ae5ff92aeac2ed17f0d5fc9d1554f8eaa3a4d27;p=openwrt%2Fstaging%2Fmkresin.git kernel: ssb: update ssb to a version from kernel 3.14-rc1 Signed-off-by: Hauke Mehrtens SVN-Revision: 39464 --- diff --git a/target/linux/brcm47xx/patches-3.10/102-ssb-gpio-add-own-IRQ-domain.patch b/target/linux/brcm47xx/patches-3.10/102-ssb-gpio-add-own-IRQ-domain.patch deleted file mode 100644 index 9d3fe789ad..0000000000 --- a/target/linux/brcm47xx/patches-3.10/102-ssb-gpio-add-own-IRQ-domain.patch +++ /dev/null @@ -1,450 +0,0 @@ -From 5668cb19fea423cb6681f1efa8b130a26be2562e Mon Sep 17 00:00:00 2001 -From: Rafa? Mi?ecki -Date: Fri, 3 Jan 2014 09:55:29 +0100 -Subject: [PATCH] ssb: gpio: add own IRQ domain - -Signed-off-by: Rafa? Mi?ecki -Acked-by: Hauke Mehrtens ---- - drivers/ssb/Kconfig | 1 + - drivers/ssb/driver_gpio.c | 304 ++++++++++++++++++++++++++++++++++++++++++--- - drivers/ssb/main.c | 12 +- - include/linux/ssb/ssb.h | 1 + - 4 files changed, 297 insertions(+), 21 deletions(-) - ---- a/drivers/ssb/Kconfig -+++ b/drivers/ssb/Kconfig -@@ -169,6 +169,7 @@ config SSB_DRIVER_GIGE - config SSB_DRIVER_GPIO - bool "SSB GPIO driver" - depends on SSB && GPIOLIB -+ select IRQ_DOMAIN if SSB_EMBEDDED - help - Driver to provide access to the GPIO pins on the bus. - ---- a/drivers/ssb/driver_gpio.c -+++ b/drivers/ssb/driver_gpio.c -@@ -9,16 +9,40 @@ - */ - - #include -+#include -+#include -+#include - #include - #include - - #include "ssb_private.h" - -+ -+/************************************************** -+ * Shared -+ **************************************************/ -+ - static struct ssb_bus *ssb_gpio_get_bus(struct gpio_chip *chip) - { - return container_of(chip, struct ssb_bus, gpio); - } - -+#if IS_BUILTIN(CONFIG_SSB_EMBEDDED) -+static int ssb_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) -+{ -+ struct ssb_bus *bus = ssb_gpio_get_bus(chip); -+ -+ if (bus->bustype == SSB_BUSTYPE_SSB) -+ return irq_find_mapping(bus->irq_domain, gpio); -+ else -+ return -EINVAL; -+} -+#endif -+ -+/************************************************** -+ * ChipCommon -+ **************************************************/ -+ - static int ssb_gpio_chipco_get_value(struct gpio_chip *chip, unsigned gpio) - { - struct ssb_bus *bus = ssb_gpio_get_bus(chip); -@@ -74,19 +98,129 @@ static void ssb_gpio_chipco_free(struct - ssb_chipco_gpio_pullup(&bus->chipco, 1 << gpio, 0); - } - --static int ssb_gpio_chipco_to_irq(struct gpio_chip *chip, unsigned gpio) -+#if IS_BUILTIN(CONFIG_SSB_EMBEDDED) -+static void ssb_gpio_irq_chipco_mask(struct irq_data *d) - { -- struct ssb_bus *bus = ssb_gpio_get_bus(chip); -+ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); -+ int gpio = irqd_to_hwirq(d); - -- if (bus->bustype == SSB_BUSTYPE_SSB) -- return ssb_mips_irq(bus->chipco.dev) + 2; -- else -- return -EINVAL; -+ ssb_chipco_gpio_intmask(&bus->chipco, BIT(gpio), 0); -+} -+ -+static void ssb_gpio_irq_chipco_unmask(struct irq_data *d) -+{ -+ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); -+ int gpio = irqd_to_hwirq(d); -+ u32 val = ssb_chipco_gpio_in(&bus->chipco, BIT(gpio)); -+ -+ ssb_chipco_gpio_polarity(&bus->chipco, BIT(gpio), val); -+ ssb_chipco_gpio_intmask(&bus->chipco, BIT(gpio), BIT(gpio)); -+} -+ -+static struct irq_chip ssb_gpio_irq_chipco_chip = { -+ .name = "SSB-GPIO-CC", -+ .irq_mask = ssb_gpio_irq_chipco_mask, -+ .irq_unmask = ssb_gpio_irq_chipco_unmask, -+}; -+ -+static irqreturn_t ssb_gpio_irq_chipco_handler(int irq, void *dev_id) -+{ -+ struct ssb_bus *bus = dev_id; -+ struct ssb_chipcommon *chipco = &bus->chipco; -+ u32 val = chipco_read32(chipco, SSB_CHIPCO_GPIOIN); -+ u32 mask = chipco_read32(chipco, SSB_CHIPCO_GPIOIRQ); -+ u32 pol = chipco_read32(chipco, SSB_CHIPCO_GPIOPOL); -+ u32 irqs = (val ^ pol) & mask; -+ int gpio; -+ -+ if (!irqs) -+ return IRQ_NONE; -+ -+ for_each_set_bit(gpio, (unsigned long *)&irqs, bus->gpio.ngpio) -+ generic_handle_irq(ssb_gpio_to_irq(&bus->gpio, gpio)); -+ ssb_chipco_gpio_polarity(chipco, irqs, val & irqs); -+ -+ return IRQ_HANDLED; -+} -+ -+static int ssb_gpio_irq_chipco_domain_init(struct ssb_bus *bus) -+{ -+ struct ssb_chipcommon *chipco = &bus->chipco; -+ struct gpio_chip *chip = &bus->gpio; -+ int gpio, hwirq, err; -+ -+ if (bus->bustype != SSB_BUSTYPE_SSB) -+ return 0; -+ -+ bus->irq_domain = irq_domain_add_linear(NULL, chip->ngpio, -+ &irq_domain_simple_ops, chipco); -+ if (!bus->irq_domain) { -+ err = -ENODEV; -+ goto err_irq_domain; -+ } -+ for (gpio = 0; gpio < chip->ngpio; gpio++) { -+ int irq = irq_create_mapping(bus->irq_domain, gpio); -+ -+ irq_set_chip_data(irq, bus); -+ irq_set_chip_and_handler(irq, &ssb_gpio_irq_chipco_chip, -+ handle_simple_irq); -+ } -+ -+ hwirq = ssb_mips_irq(bus->chipco.dev) + 2; -+ err = request_irq(hwirq, ssb_gpio_irq_chipco_handler, IRQF_SHARED, -+ "gpio", bus); -+ if (err) -+ goto err_req_irq; -+ -+ ssb_chipco_gpio_intmask(&bus->chipco, ~0, 0); -+ chipco_set32(chipco, SSB_CHIPCO_IRQMASK, SSB_CHIPCO_IRQ_GPIO); -+ -+ return 0; -+ -+err_req_irq: -+ for (gpio = 0; gpio < chip->ngpio; gpio++) { -+ int irq = irq_find_mapping(bus->irq_domain, gpio); -+ -+ irq_dispose_mapping(irq); -+ } -+ irq_domain_remove(bus->irq_domain); -+err_irq_domain: -+ return err; -+} -+ -+static void ssb_gpio_irq_chipco_domain_exit(struct ssb_bus *bus) -+{ -+ struct ssb_chipcommon *chipco = &bus->chipco; -+ struct gpio_chip *chip = &bus->gpio; -+ int gpio; -+ -+ if (bus->bustype != SSB_BUSTYPE_SSB) -+ return; -+ -+ chipco_mask32(chipco, SSB_CHIPCO_IRQMASK, ~SSB_CHIPCO_IRQ_GPIO); -+ free_irq(ssb_mips_irq(bus->chipco.dev) + 2, chipco); -+ for (gpio = 0; gpio < chip->ngpio; gpio++) { -+ int irq = irq_find_mapping(bus->irq_domain, gpio); -+ -+ irq_dispose_mapping(irq); -+ } -+ irq_domain_remove(bus->irq_domain); -+} -+#else -+static int ssb_gpio_irq_chipco_domain_init(struct ssb_bus *bus) -+{ -+ return 0; -+} -+ -+static void ssb_gpio_irq_chipco_domain_exit(struct ssb_bus *bus) -+{ - } -+#endif - - static int ssb_gpio_chipco_init(struct ssb_bus *bus) - { - struct gpio_chip *chip = &bus->gpio; -+ int err; - - chip->label = "ssb_chipco_gpio"; - chip->owner = THIS_MODULE; -@@ -96,7 +230,8 @@ static int ssb_gpio_chipco_init(struct s - chip->set = ssb_gpio_chipco_set_value; - chip->direction_input = ssb_gpio_chipco_direction_input; - chip->direction_output = ssb_gpio_chipco_direction_output; -- chip->to_irq = ssb_gpio_chipco_to_irq; -+ if (IS_BUILTIN(CONFIG_SSB_EMBEDDED)) -+ chip->to_irq = ssb_gpio_to_irq; - chip->ngpio = 16; - /* There is just one SoC in one device and its GPIO addresses should be - * deterministic to address them more easily. The other buses could get -@@ -106,9 +241,23 @@ static int ssb_gpio_chipco_init(struct s - else - chip->base = -1; - -- return gpiochip_add(chip); -+ err = ssb_gpio_irq_chipco_domain_init(bus); -+ if (err) -+ return err; -+ -+ err = gpiochip_add(chip); -+ if (err) { -+ ssb_gpio_irq_chipco_domain_exit(bus); -+ return err; -+ } -+ -+ return 0; - } - -+/************************************************** -+ * EXTIF -+ **************************************************/ -+ - #ifdef CONFIG_SSB_DRIVER_EXTIF - - static int ssb_gpio_extif_get_value(struct gpio_chip *chip, unsigned gpio) -@@ -145,19 +294,127 @@ static int ssb_gpio_extif_direction_outp - return 0; - } - --static int ssb_gpio_extif_to_irq(struct gpio_chip *chip, unsigned gpio) -+#if IS_BUILTIN(CONFIG_SSB_EMBEDDED) -+static void ssb_gpio_irq_extif_mask(struct irq_data *d) - { -- struct ssb_bus *bus = ssb_gpio_get_bus(chip); -+ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); -+ int gpio = irqd_to_hwirq(d); - -- if (bus->bustype == SSB_BUSTYPE_SSB) -- return ssb_mips_irq(bus->extif.dev) + 2; -- else -- return -EINVAL; -+ ssb_extif_gpio_intmask(&bus->extif, BIT(gpio), 0); - } - -+static void ssb_gpio_irq_extif_unmask(struct irq_data *d) -+{ -+ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); -+ int gpio = irqd_to_hwirq(d); -+ u32 val = ssb_extif_gpio_in(&bus->extif, BIT(gpio)); -+ -+ ssb_extif_gpio_polarity(&bus->extif, BIT(gpio), val); -+ ssb_extif_gpio_intmask(&bus->extif, BIT(gpio), BIT(gpio)); -+} -+ -+static struct irq_chip ssb_gpio_irq_extif_chip = { -+ .name = "SSB-GPIO-EXTIF", -+ .irq_mask = ssb_gpio_irq_extif_mask, -+ .irq_unmask = ssb_gpio_irq_extif_unmask, -+}; -+ -+static irqreturn_t ssb_gpio_irq_extif_handler(int irq, void *dev_id) -+{ -+ struct ssb_bus *bus = dev_id; -+ struct ssb_extif *extif = &bus->extif; -+ u32 val = ssb_read32(extif->dev, SSB_EXTIF_GPIO_IN); -+ u32 mask = ssb_read32(extif->dev, SSB_EXTIF_GPIO_INTMASK); -+ u32 pol = ssb_read32(extif->dev, SSB_EXTIF_GPIO_INTPOL); -+ u32 irqs = (val ^ pol) & mask; -+ int gpio; -+ -+ if (!irqs) -+ return IRQ_NONE; -+ -+ for_each_set_bit(gpio, (unsigned long *)&irqs, bus->gpio.ngpio) -+ generic_handle_irq(ssb_gpio_to_irq(&bus->gpio, gpio)); -+ ssb_extif_gpio_polarity(extif, irqs, val & irqs); -+ -+ return IRQ_HANDLED; -+} -+ -+static int ssb_gpio_irq_extif_domain_init(struct ssb_bus *bus) -+{ -+ struct ssb_extif *extif = &bus->extif; -+ struct gpio_chip *chip = &bus->gpio; -+ int gpio, hwirq, err; -+ -+ if (bus->bustype != SSB_BUSTYPE_SSB) -+ return 0; -+ -+ bus->irq_domain = irq_domain_add_linear(NULL, chip->ngpio, -+ &irq_domain_simple_ops, extif); -+ if (!bus->irq_domain) { -+ err = -ENODEV; -+ goto err_irq_domain; -+ } -+ for (gpio = 0; gpio < chip->ngpio; gpio++) { -+ int irq = irq_create_mapping(bus->irq_domain, gpio); -+ -+ irq_set_chip_data(irq, bus); -+ irq_set_chip_and_handler(irq, &ssb_gpio_irq_extif_chip, -+ handle_simple_irq); -+ } -+ -+ hwirq = ssb_mips_irq(bus->extif.dev) + 2; -+ err = request_irq(hwirq, ssb_gpio_irq_extif_handler, IRQF_SHARED, -+ "gpio", bus); -+ if (err) -+ goto err_req_irq; -+ -+ ssb_extif_gpio_intmask(&bus->extif, ~0, 0); -+ -+ return 0; -+ -+err_req_irq: -+ for (gpio = 0; gpio < chip->ngpio; gpio++) { -+ int irq = irq_find_mapping(bus->irq_domain, gpio); -+ -+ irq_dispose_mapping(irq); -+ } -+ irq_domain_remove(bus->irq_domain); -+err_irq_domain: -+ return err; -+} -+ -+static void ssb_gpio_irq_extif_domain_exit(struct ssb_bus *bus) -+{ -+ struct ssb_extif *extif = &bus->extif; -+ struct gpio_chip *chip = &bus->gpio; -+ int gpio; -+ -+ if (bus->bustype != SSB_BUSTYPE_SSB) -+ return; -+ -+ free_irq(ssb_mips_irq(bus->extif.dev) + 2, extif); -+ for (gpio = 0; gpio < chip->ngpio; gpio++) { -+ int irq = irq_find_mapping(bus->irq_domain, gpio); -+ -+ irq_dispose_mapping(irq); -+ } -+ irq_domain_remove(bus->irq_domain); -+} -+#else -+static int ssb_gpio_irq_extif_domain_init(struct ssb_bus *bus) -+{ -+ return 0; -+} -+ -+static void ssb_gpio_irq_extif_domain_exit(struct ssb_bus *bus) -+{ -+} -+#endif -+ - static int ssb_gpio_extif_init(struct ssb_bus *bus) - { - struct gpio_chip *chip = &bus->gpio; -+ int err; - - chip->label = "ssb_extif_gpio"; - chip->owner = THIS_MODULE; -@@ -165,7 +422,8 @@ static int ssb_gpio_extif_init(struct ss - chip->set = ssb_gpio_extif_set_value; - chip->direction_input = ssb_gpio_extif_direction_input; - chip->direction_output = ssb_gpio_extif_direction_output; -- chip->to_irq = ssb_gpio_extif_to_irq; -+ if (IS_BUILTIN(CONFIG_SSB_EMBEDDED)) -+ chip->to_irq = ssb_gpio_to_irq; - chip->ngpio = 5; - /* There is just one SoC in one device and its GPIO addresses should be - * deterministic to address them more easily. The other buses could get -@@ -175,7 +433,17 @@ static int ssb_gpio_extif_init(struct ss - else - chip->base = -1; - -- return gpiochip_add(chip); -+ err = ssb_gpio_irq_extif_domain_init(bus); -+ if (err) -+ return err; -+ -+ err = gpiochip_add(chip); -+ if (err) { -+ ssb_gpio_irq_extif_domain_exit(bus); -+ return err; -+ } -+ -+ return 0; - } - - #else -@@ -185,6 +453,10 @@ static int ssb_gpio_extif_init(struct ss - } - #endif - -+/************************************************** -+ * Init -+ **************************************************/ -+ - int ssb_gpio_init(struct ssb_bus *bus) - { - if (ssb_chipco_available(&bus->chipco)) ---- a/drivers/ssb/main.c -+++ b/drivers/ssb/main.c -@@ -590,6 +590,13 @@ static int ssb_attach_queued_buses(void) - ssb_pcicore_init(&bus->pcicore); - if (bus->bustype == SSB_BUSTYPE_SSB) - ssb_watchdog_register(bus); -+ -+ err = ssb_gpio_init(bus); -+ if (err == -ENOTSUPP) -+ ssb_dbg("GPIO driver not activated\n"); -+ else if (err) -+ ssb_dbg("Error registering GPIO driver: %i\n", err); -+ - ssb_bus_may_powerdown(bus); - - err = ssb_devices_register(bus); -@@ -827,11 +834,6 @@ static int ssb_bus_register(struct ssb_b - ssb_chipcommon_init(&bus->chipco); - ssb_extif_init(&bus->extif); - ssb_mipscore_init(&bus->mipscore); -- err = ssb_gpio_init(bus); -- if (err == -ENOTSUPP) -- ssb_dbg("GPIO driver not activated\n"); -- else if (err) -- ssb_dbg("Error registering GPIO driver: %i\n", err); - err = ssb_fetch_invariants(bus, get_invariants); - if (err) { - ssb_bus_may_powerdown(bus); ---- a/include/linux/ssb/ssb.h -+++ b/include/linux/ssb/ssb.h -@@ -486,6 +486,7 @@ struct ssb_bus { - #endif /* EMBEDDED */ - #ifdef CONFIG_SSB_DRIVER_GPIO - struct gpio_chip gpio; -+ struct irq_domain *irq_domain; - #endif /* DRIVER_GPIO */ - - /* Internal-only stuff follows. Do not touch. */ diff --git a/target/linux/brcm47xx/patches-3.10/790-tg3-phylib.patch b/target/linux/brcm47xx/patches-3.10/790-tg3-phylib.patch index f533a0046a..f1c68ba667 100644 --- a/target/linux/brcm47xx/patches-3.10/790-tg3-phylib.patch +++ b/target/linux/brcm47xx/patches-3.10/790-tg3-phylib.patch @@ -195,33 +195,3 @@ netdev_info(dev, "attached PHY driver [%s] (mii_bus:phy_addr=%s)\n", phydev->drv->name, dev_name(&phydev->dev)); ---- a/include/linux/ssb/ssb_driver_gige.h -+++ b/include/linux/ssb/ssb_driver_gige.h -@@ -108,6 +108,16 @@ static inline int ssb_gige_get_macaddr(s - return 0; - } - -+/* Get the device phy address */ -+static inline int ssb_gige_get_phyaddr(struct pci_dev *pdev) -+{ -+ struct ssb_gige *dev = pdev_to_ssb_gige(pdev); -+ if (!dev) -+ return -ENODEV; -+ -+ return dev->dev->bus->sprom.et0phyaddr; -+} -+ - extern int ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev, - struct pci_dev *pdev); - extern int ssb_gige_map_irq(struct ssb_device *sdev, -@@ -174,6 +184,10 @@ static inline int ssb_gige_get_macaddr(s - { - return -ENODEV; - } -+static inline int ssb_gige_get_phyaddr(struct pci_dev *pdev) -+{ -+ return -ENODEV; -+} - - #endif /* CONFIG_SSB_DRIVER_GIGE */ - #endif /* LINUX_SSB_DRIVER_GIGE_H_ */ diff --git a/target/linux/generic/patches-3.10/020-ssb_update.patch b/target/linux/generic/patches-3.10/020-ssb_update.patch index 1605705251..4b0caa806a 100644 --- a/target/linux/generic/patches-3.10/020-ssb_update.patch +++ b/target/linux/generic/patches-3.10/020-ssb_update.patch @@ -16,6 +16,14 @@ default y config SSB_DRIVER_EXTIF +@@ -168,6 +168,7 @@ config SSB_DRIVER_GIGE + config SSB_DRIVER_GPIO + bool "SSB GPIO driver" + depends on SSB && GPIOLIB ++ select IRQ_DOMAIN if SSB_EMBEDDED + help + Driver to provide access to the GPIO pins on the bus. + --- a/drivers/ssb/driver_chipcommon_sflash.c +++ b/drivers/ssb/driver_chipcommon_sflash.c @@ -9,6 +9,19 @@ @@ -47,8 +55,12 @@ { "M25P20", 0x11, 0x10000, 4, }, { "M25P40", 0x12, 0x10000, 8, }, -@@ -27,7 +40,7 @@ static struct ssb_sflash_tbl_e ssb_sflas - { 0 }, +@@ -24,10 +37,10 @@ static struct ssb_sflash_tbl_e ssb_sflas + { "M25P32", 0x15, 0x10000, 64, }, + { "M25P64", 0x16, 0x10000, 128, }, + { "M25FL128", 0x17, 0x10000, 256, }, +- { 0 }, ++ { NULL }, }; -static struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = { @@ -56,8 +68,12 @@ { "SST25WF512", 1, 0x1000, 16, }, { "SST25VF512", 0x48, 0x1000, 16, }, { "SST25WF010", 2, 0x1000, 32, }, -@@ -45,7 +58,7 @@ static struct ssb_sflash_tbl_e ssb_sflas - { 0 }, +@@ -42,10 +55,10 @@ static struct ssb_sflash_tbl_e ssb_sflas + { "SST25VF016", 0x41, 0x1000, 512, }, + { "SST25VF032", 0x4a, 0x1000, 1024, }, + { "SST25VF064", 0x4b, 0x1000, 2048, }, +- { 0 }, ++ { NULL }, }; -static struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = { @@ -65,6 +81,15 @@ { "AT45DB011", 0xc, 256, 512, }, { "AT45DB021", 0x14, 256, 1024, }, { "AT45DB041", 0x1c, 256, 2048, }, +@@ -53,7 +66,7 @@ static struct ssb_sflash_tbl_e ssb_sflas + { "AT45DB161", 0x2c, 512, 4096, }, + { "AT45DB321", 0x34, 512, 8192, }, + { "AT45DB642", 0x3c, 1024, 8192, }, +- { 0 }, ++ { NULL }, + }; + + static void ssb_sflash_cmd(struct ssb_chipcommon *cc, u32 opcode) @@ -73,7 +86,8 @@ static void ssb_sflash_cmd(struct ssb_ch /* Initialize serial flash access */ int ssb_sflash_init(struct ssb_chipcommon *cc) @@ -101,6 +126,396 @@ - return -ENOTSUPP; + return 0; } +--- a/drivers/ssb/driver_gpio.c ++++ b/drivers/ssb/driver_gpio.c +@@ -9,16 +9,40 @@ + */ + + #include ++#include ++#include ++#include + #include + #include + + #include "ssb_private.h" + ++ ++/************************************************** ++ * Shared ++ **************************************************/ ++ + static struct ssb_bus *ssb_gpio_get_bus(struct gpio_chip *chip) + { + return container_of(chip, struct ssb_bus, gpio); + } + ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++static int ssb_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) ++{ ++ struct ssb_bus *bus = ssb_gpio_get_bus(chip); ++ ++ if (bus->bustype == SSB_BUSTYPE_SSB) ++ return irq_find_mapping(bus->irq_domain, gpio); ++ else ++ return -EINVAL; ++} ++#endif ++ ++/************************************************** ++ * ChipCommon ++ **************************************************/ ++ + static int ssb_gpio_chipco_get_value(struct gpio_chip *chip, unsigned gpio) + { + struct ssb_bus *bus = ssb_gpio_get_bus(chip); +@@ -74,19 +98,129 @@ static void ssb_gpio_chipco_free(struct + ssb_chipco_gpio_pullup(&bus->chipco, 1 << gpio, 0); + } + +-static int ssb_gpio_chipco_to_irq(struct gpio_chip *chip, unsigned gpio) ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++static void ssb_gpio_irq_chipco_mask(struct irq_data *d) + { +- struct ssb_bus *bus = ssb_gpio_get_bus(chip); ++ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); ++ int gpio = irqd_to_hwirq(d); + +- if (bus->bustype == SSB_BUSTYPE_SSB) +- return ssb_mips_irq(bus->chipco.dev) + 2; +- else +- return -EINVAL; ++ ssb_chipco_gpio_intmask(&bus->chipco, BIT(gpio), 0); ++} ++ ++static void ssb_gpio_irq_chipco_unmask(struct irq_data *d) ++{ ++ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); ++ int gpio = irqd_to_hwirq(d); ++ u32 val = ssb_chipco_gpio_in(&bus->chipco, BIT(gpio)); ++ ++ ssb_chipco_gpio_polarity(&bus->chipco, BIT(gpio), val); ++ ssb_chipco_gpio_intmask(&bus->chipco, BIT(gpio), BIT(gpio)); ++} ++ ++static struct irq_chip ssb_gpio_irq_chipco_chip = { ++ .name = "SSB-GPIO-CC", ++ .irq_mask = ssb_gpio_irq_chipco_mask, ++ .irq_unmask = ssb_gpio_irq_chipco_unmask, ++}; ++ ++static irqreturn_t ssb_gpio_irq_chipco_handler(int irq, void *dev_id) ++{ ++ struct ssb_bus *bus = dev_id; ++ struct ssb_chipcommon *chipco = &bus->chipco; ++ u32 val = chipco_read32(chipco, SSB_CHIPCO_GPIOIN); ++ u32 mask = chipco_read32(chipco, SSB_CHIPCO_GPIOIRQ); ++ u32 pol = chipco_read32(chipco, SSB_CHIPCO_GPIOPOL); ++ unsigned long irqs = (val ^ pol) & mask; ++ int gpio; ++ ++ if (!irqs) ++ return IRQ_NONE; ++ ++ for_each_set_bit(gpio, &irqs, bus->gpio.ngpio) ++ generic_handle_irq(ssb_gpio_to_irq(&bus->gpio, gpio)); ++ ssb_chipco_gpio_polarity(chipco, irqs, val & irqs); ++ ++ return IRQ_HANDLED; ++} ++ ++static int ssb_gpio_irq_chipco_domain_init(struct ssb_bus *bus) ++{ ++ struct ssb_chipcommon *chipco = &bus->chipco; ++ struct gpio_chip *chip = &bus->gpio; ++ int gpio, hwirq, err; ++ ++ if (bus->bustype != SSB_BUSTYPE_SSB) ++ return 0; ++ ++ bus->irq_domain = irq_domain_add_linear(NULL, chip->ngpio, ++ &irq_domain_simple_ops, chipco); ++ if (!bus->irq_domain) { ++ err = -ENODEV; ++ goto err_irq_domain; ++ } ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_create_mapping(bus->irq_domain, gpio); ++ ++ irq_set_chip_data(irq, bus); ++ irq_set_chip_and_handler(irq, &ssb_gpio_irq_chipco_chip, ++ handle_simple_irq); ++ } ++ ++ hwirq = ssb_mips_irq(bus->chipco.dev) + 2; ++ err = request_irq(hwirq, ssb_gpio_irq_chipco_handler, IRQF_SHARED, ++ "gpio", bus); ++ if (err) ++ goto err_req_irq; ++ ++ ssb_chipco_gpio_intmask(&bus->chipco, ~0, 0); ++ chipco_set32(chipco, SSB_CHIPCO_IRQMASK, SSB_CHIPCO_IRQ_GPIO); ++ ++ return 0; ++ ++err_req_irq: ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_find_mapping(bus->irq_domain, gpio); ++ ++ irq_dispose_mapping(irq); ++ } ++ irq_domain_remove(bus->irq_domain); ++err_irq_domain: ++ return err; ++} ++ ++static void ssb_gpio_irq_chipco_domain_exit(struct ssb_bus *bus) ++{ ++ struct ssb_chipcommon *chipco = &bus->chipco; ++ struct gpio_chip *chip = &bus->gpio; ++ int gpio; ++ ++ if (bus->bustype != SSB_BUSTYPE_SSB) ++ return; ++ ++ chipco_mask32(chipco, SSB_CHIPCO_IRQMASK, ~SSB_CHIPCO_IRQ_GPIO); ++ free_irq(ssb_mips_irq(bus->chipco.dev) + 2, chipco); ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_find_mapping(bus->irq_domain, gpio); ++ ++ irq_dispose_mapping(irq); ++ } ++ irq_domain_remove(bus->irq_domain); ++} ++#else ++static int ssb_gpio_irq_chipco_domain_init(struct ssb_bus *bus) ++{ ++ return 0; ++} ++ ++static void ssb_gpio_irq_chipco_domain_exit(struct ssb_bus *bus) ++{ + } ++#endif + + static int ssb_gpio_chipco_init(struct ssb_bus *bus) + { + struct gpio_chip *chip = &bus->gpio; ++ int err; + + chip->label = "ssb_chipco_gpio"; + chip->owner = THIS_MODULE; +@@ -96,7 +230,9 @@ static int ssb_gpio_chipco_init(struct s + chip->set = ssb_gpio_chipco_set_value; + chip->direction_input = ssb_gpio_chipco_direction_input; + chip->direction_output = ssb_gpio_chipco_direction_output; +- chip->to_irq = ssb_gpio_chipco_to_irq; ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++ chip->to_irq = ssb_gpio_to_irq; ++#endif + chip->ngpio = 16; + /* There is just one SoC in one device and its GPIO addresses should be + * deterministic to address them more easily. The other buses could get +@@ -106,9 +242,23 @@ static int ssb_gpio_chipco_init(struct s + else + chip->base = -1; + +- return gpiochip_add(chip); ++ err = ssb_gpio_irq_chipco_domain_init(bus); ++ if (err) ++ return err; ++ ++ err = gpiochip_add(chip); ++ if (err) { ++ ssb_gpio_irq_chipco_domain_exit(bus); ++ return err; ++ } ++ ++ return 0; + } + ++/************************************************** ++ * EXTIF ++ **************************************************/ ++ + #ifdef CONFIG_SSB_DRIVER_EXTIF + + static int ssb_gpio_extif_get_value(struct gpio_chip *chip, unsigned gpio) +@@ -145,19 +295,127 @@ static int ssb_gpio_extif_direction_outp + return 0; + } + +-static int ssb_gpio_extif_to_irq(struct gpio_chip *chip, unsigned gpio) ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++static void ssb_gpio_irq_extif_mask(struct irq_data *d) + { +- struct ssb_bus *bus = ssb_gpio_get_bus(chip); ++ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); ++ int gpio = irqd_to_hwirq(d); + +- if (bus->bustype == SSB_BUSTYPE_SSB) +- return ssb_mips_irq(bus->extif.dev) + 2; +- else +- return -EINVAL; ++ ssb_extif_gpio_intmask(&bus->extif, BIT(gpio), 0); ++} ++ ++static void ssb_gpio_irq_extif_unmask(struct irq_data *d) ++{ ++ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); ++ int gpio = irqd_to_hwirq(d); ++ u32 val = ssb_extif_gpio_in(&bus->extif, BIT(gpio)); ++ ++ ssb_extif_gpio_polarity(&bus->extif, BIT(gpio), val); ++ ssb_extif_gpio_intmask(&bus->extif, BIT(gpio), BIT(gpio)); ++} ++ ++static struct irq_chip ssb_gpio_irq_extif_chip = { ++ .name = "SSB-GPIO-EXTIF", ++ .irq_mask = ssb_gpio_irq_extif_mask, ++ .irq_unmask = ssb_gpio_irq_extif_unmask, ++}; ++ ++static irqreturn_t ssb_gpio_irq_extif_handler(int irq, void *dev_id) ++{ ++ struct ssb_bus *bus = dev_id; ++ struct ssb_extif *extif = &bus->extif; ++ u32 val = ssb_read32(extif->dev, SSB_EXTIF_GPIO_IN); ++ u32 mask = ssb_read32(extif->dev, SSB_EXTIF_GPIO_INTMASK); ++ u32 pol = ssb_read32(extif->dev, SSB_EXTIF_GPIO_INTPOL); ++ unsigned long irqs = (val ^ pol) & mask; ++ int gpio; ++ ++ if (!irqs) ++ return IRQ_NONE; ++ ++ for_each_set_bit(gpio, &irqs, bus->gpio.ngpio) ++ generic_handle_irq(ssb_gpio_to_irq(&bus->gpio, gpio)); ++ ssb_extif_gpio_polarity(extif, irqs, val & irqs); ++ ++ return IRQ_HANDLED; ++} ++ ++static int ssb_gpio_irq_extif_domain_init(struct ssb_bus *bus) ++{ ++ struct ssb_extif *extif = &bus->extif; ++ struct gpio_chip *chip = &bus->gpio; ++ int gpio, hwirq, err; ++ ++ if (bus->bustype != SSB_BUSTYPE_SSB) ++ return 0; ++ ++ bus->irq_domain = irq_domain_add_linear(NULL, chip->ngpio, ++ &irq_domain_simple_ops, extif); ++ if (!bus->irq_domain) { ++ err = -ENODEV; ++ goto err_irq_domain; ++ } ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_create_mapping(bus->irq_domain, gpio); ++ ++ irq_set_chip_data(irq, bus); ++ irq_set_chip_and_handler(irq, &ssb_gpio_irq_extif_chip, ++ handle_simple_irq); ++ } ++ ++ hwirq = ssb_mips_irq(bus->extif.dev) + 2; ++ err = request_irq(hwirq, ssb_gpio_irq_extif_handler, IRQF_SHARED, ++ "gpio", bus); ++ if (err) ++ goto err_req_irq; ++ ++ ssb_extif_gpio_intmask(&bus->extif, ~0, 0); ++ ++ return 0; ++ ++err_req_irq: ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_find_mapping(bus->irq_domain, gpio); ++ ++ irq_dispose_mapping(irq); ++ } ++ irq_domain_remove(bus->irq_domain); ++err_irq_domain: ++ return err; + } + ++static void ssb_gpio_irq_extif_domain_exit(struct ssb_bus *bus) ++{ ++ struct ssb_extif *extif = &bus->extif; ++ struct gpio_chip *chip = &bus->gpio; ++ int gpio; ++ ++ if (bus->bustype != SSB_BUSTYPE_SSB) ++ return; ++ ++ free_irq(ssb_mips_irq(bus->extif.dev) + 2, extif); ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_find_mapping(bus->irq_domain, gpio); ++ ++ irq_dispose_mapping(irq); ++ } ++ irq_domain_remove(bus->irq_domain); ++} ++#else ++static int ssb_gpio_irq_extif_domain_init(struct ssb_bus *bus) ++{ ++ return 0; ++} ++ ++static void ssb_gpio_irq_extif_domain_exit(struct ssb_bus *bus) ++{ ++} ++#endif ++ + static int ssb_gpio_extif_init(struct ssb_bus *bus) + { + struct gpio_chip *chip = &bus->gpio; ++ int err; + + chip->label = "ssb_extif_gpio"; + chip->owner = THIS_MODULE; +@@ -165,7 +423,9 @@ static int ssb_gpio_extif_init(struct ss + chip->set = ssb_gpio_extif_set_value; + chip->direction_input = ssb_gpio_extif_direction_input; + chip->direction_output = ssb_gpio_extif_direction_output; +- chip->to_irq = ssb_gpio_extif_to_irq; ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++ chip->to_irq = ssb_gpio_to_irq; ++#endif + chip->ngpio = 5; + /* There is just one SoC in one device and its GPIO addresses should be + * deterministic to address them more easily. The other buses could get +@@ -175,7 +435,17 @@ static int ssb_gpio_extif_init(struct ss + else + chip->base = -1; + +- return gpiochip_add(chip); ++ err = ssb_gpio_irq_extif_domain_init(bus); ++ if (err) ++ return err; ++ ++ err = gpiochip_add(chip); ++ if (err) { ++ ssb_gpio_irq_extif_domain_exit(bus); ++ return err; ++ } ++ ++ return 0; + } + + #else +@@ -185,6 +455,10 @@ static int ssb_gpio_extif_init(struct ss + } + #endif + ++/************************************************** ++ * Init ++ **************************************************/ ++ + int ssb_gpio_init(struct ssb_bus *bus) + { + if (ssb_chipco_available(&bus->chipco)) --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -553,6 +553,14 @@ static int ssb_devices_register(struct s @@ -118,6 +533,32 @@ return 0; error: /* Unwind the already registered devices. */ +@@ -582,6 +590,13 @@ static int ssb_attach_queued_buses(void) + ssb_pcicore_init(&bus->pcicore); + if (bus->bustype == SSB_BUSTYPE_SSB) + ssb_watchdog_register(bus); ++ ++ err = ssb_gpio_init(bus); ++ if (err == -ENOTSUPP) ++ ssb_dbg("GPIO driver not activated\n"); ++ else if (err) ++ ssb_dbg("Error registering GPIO driver: %i\n", err); ++ + ssb_bus_may_powerdown(bus); + + err = ssb_devices_register(bus); +@@ -819,11 +834,6 @@ static int ssb_bus_register(struct ssb_b + ssb_chipcommon_init(&bus->chipco); + ssb_extif_init(&bus->extif); + ssb_mipscore_init(&bus->mipscore); +- err = ssb_gpio_init(bus); +- if (err == -ENOTSUPP) +- ssb_dbg("GPIO driver not activated\n"); +- else if (err) +- ssb_dbg("Error registering GPIO driver: %i\n", err); + err = ssb_fetch_invariants(bus, get_invariants); + if (err) { + ssb_bus_may_powerdown(bus); --- a/drivers/ssb/pcihost_wrapper.c +++ b/drivers/ssb/pcihost_wrapper.c @@ -38,7 +38,7 @@ static int ssb_pcihost_resume(struct pci @@ -153,6 +594,46 @@ #ifdef CONFIG_SSB_DRIVER_EXTIF extern u32 ssb_extif_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, u32 ticks); extern u32 ssb_extif_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms); +--- a/include/linux/ssb/ssb.h ++++ b/include/linux/ssb/ssb.h +@@ -486,6 +486,7 @@ struct ssb_bus { + #endif /* EMBEDDED */ + #ifdef CONFIG_SSB_DRIVER_GPIO + struct gpio_chip gpio; ++ struct irq_domain *irq_domain; + #endif /* DRIVER_GPIO */ + + /* Internal-only stuff follows. Do not touch. */ +--- a/include/linux/ssb/ssb_driver_gige.h ++++ b/include/linux/ssb/ssb_driver_gige.h +@@ -108,6 +108,16 @@ static inline int ssb_gige_get_macaddr(s + return 0; + } + ++/* Get the device phy address */ ++static inline int ssb_gige_get_phyaddr(struct pci_dev *pdev) ++{ ++ struct ssb_gige *dev = pdev_to_ssb_gige(pdev); ++ if (!dev) ++ return -ENODEV; ++ ++ return dev->dev->bus->sprom.et0phyaddr; ++} ++ + extern int ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev, + struct pci_dev *pdev); + extern int ssb_gige_map_irq(struct ssb_device *sdev, +@@ -174,6 +184,10 @@ static inline int ssb_gige_get_macaddr(s + { + return -ENODEV; + } ++static inline int ssb_gige_get_phyaddr(struct pci_dev *pdev) ++{ ++ return -ENODEV; ++} + + #endif /* CONFIG_SSB_DRIVER_GIGE */ + #endif /* LINUX_SSB_DRIVER_GIGE_H_ */ --- a/include/linux/ssb/ssb_driver_mips.h +++ b/include/linux/ssb/ssb_driver_mips.h @@ -20,6 +20,18 @@ struct ssb_pflash { diff --git a/target/linux/generic/patches-3.12/020-ssb_update.patch b/target/linux/generic/patches-3.12/020-ssb_update.patch new file mode 100644 index 0000000000..a6c6d8f46c --- /dev/null +++ b/target/linux/generic/patches-3.12/020-ssb_update.patch @@ -0,0 +1,543 @@ +--- a/drivers/ssb/Kconfig ++++ b/drivers/ssb/Kconfig +@@ -168,6 +168,7 @@ config SSB_DRIVER_GIGE + config SSB_DRIVER_GPIO + bool "SSB GPIO driver" + depends on SSB && GPIOLIB ++ select IRQ_DOMAIN if SSB_EMBEDDED + help + Driver to provide access to the GPIO pins on the bus. + +--- a/drivers/ssb/driver_chipcommon_sflash.c ++++ b/drivers/ssb/driver_chipcommon_sflash.c +@@ -37,7 +37,7 @@ static const struct ssb_sflash_tbl_e ssb + { "M25P32", 0x15, 0x10000, 64, }, + { "M25P64", 0x16, 0x10000, 128, }, + { "M25FL128", 0x17, 0x10000, 256, }, +- { 0 }, ++ { NULL }, + }; + + static const struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = { +@@ -55,7 +55,7 @@ static const struct ssb_sflash_tbl_e ssb + { "SST25VF016", 0x41, 0x1000, 512, }, + { "SST25VF032", 0x4a, 0x1000, 1024, }, + { "SST25VF064", 0x4b, 0x1000, 2048, }, +- { 0 }, ++ { NULL }, + }; + + static const struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = { +@@ -66,7 +66,7 @@ static const struct ssb_sflash_tbl_e ssb + { "AT45DB161", 0x2c, 512, 4096, }, + { "AT45DB321", 0x34, 512, 8192, }, + { "AT45DB642", 0x3c, 1024, 8192, }, +- { 0 }, ++ { NULL }, + }; + + static void ssb_sflash_cmd(struct ssb_chipcommon *cc, u32 opcode) +--- a/drivers/ssb/driver_gpio.c ++++ b/drivers/ssb/driver_gpio.c +@@ -9,16 +9,40 @@ + */ + + #include ++#include ++#include ++#include + #include + #include + + #include "ssb_private.h" + ++ ++/************************************************** ++ * Shared ++ **************************************************/ ++ + static struct ssb_bus *ssb_gpio_get_bus(struct gpio_chip *chip) + { + return container_of(chip, struct ssb_bus, gpio); + } + ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++static int ssb_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) ++{ ++ struct ssb_bus *bus = ssb_gpio_get_bus(chip); ++ ++ if (bus->bustype == SSB_BUSTYPE_SSB) ++ return irq_find_mapping(bus->irq_domain, gpio); ++ else ++ return -EINVAL; ++} ++#endif ++ ++/************************************************** ++ * ChipCommon ++ **************************************************/ ++ + static int ssb_gpio_chipco_get_value(struct gpio_chip *chip, unsigned gpio) + { + struct ssb_bus *bus = ssb_gpio_get_bus(chip); +@@ -74,19 +98,129 @@ static void ssb_gpio_chipco_free(struct + ssb_chipco_gpio_pullup(&bus->chipco, 1 << gpio, 0); + } + +-static int ssb_gpio_chipco_to_irq(struct gpio_chip *chip, unsigned gpio) ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++static void ssb_gpio_irq_chipco_mask(struct irq_data *d) + { +- struct ssb_bus *bus = ssb_gpio_get_bus(chip); ++ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); ++ int gpio = irqd_to_hwirq(d); + +- if (bus->bustype == SSB_BUSTYPE_SSB) +- return ssb_mips_irq(bus->chipco.dev) + 2; +- else +- return -EINVAL; ++ ssb_chipco_gpio_intmask(&bus->chipco, BIT(gpio), 0); ++} ++ ++static void ssb_gpio_irq_chipco_unmask(struct irq_data *d) ++{ ++ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); ++ int gpio = irqd_to_hwirq(d); ++ u32 val = ssb_chipco_gpio_in(&bus->chipco, BIT(gpio)); ++ ++ ssb_chipco_gpio_polarity(&bus->chipco, BIT(gpio), val); ++ ssb_chipco_gpio_intmask(&bus->chipco, BIT(gpio), BIT(gpio)); ++} ++ ++static struct irq_chip ssb_gpio_irq_chipco_chip = { ++ .name = "SSB-GPIO-CC", ++ .irq_mask = ssb_gpio_irq_chipco_mask, ++ .irq_unmask = ssb_gpio_irq_chipco_unmask, ++}; ++ ++static irqreturn_t ssb_gpio_irq_chipco_handler(int irq, void *dev_id) ++{ ++ struct ssb_bus *bus = dev_id; ++ struct ssb_chipcommon *chipco = &bus->chipco; ++ u32 val = chipco_read32(chipco, SSB_CHIPCO_GPIOIN); ++ u32 mask = chipco_read32(chipco, SSB_CHIPCO_GPIOIRQ); ++ u32 pol = chipco_read32(chipco, SSB_CHIPCO_GPIOPOL); ++ unsigned long irqs = (val ^ pol) & mask; ++ int gpio; ++ ++ if (!irqs) ++ return IRQ_NONE; ++ ++ for_each_set_bit(gpio, &irqs, bus->gpio.ngpio) ++ generic_handle_irq(ssb_gpio_to_irq(&bus->gpio, gpio)); ++ ssb_chipco_gpio_polarity(chipco, irqs, val & irqs); ++ ++ return IRQ_HANDLED; ++} ++ ++static int ssb_gpio_irq_chipco_domain_init(struct ssb_bus *bus) ++{ ++ struct ssb_chipcommon *chipco = &bus->chipco; ++ struct gpio_chip *chip = &bus->gpio; ++ int gpio, hwirq, err; ++ ++ if (bus->bustype != SSB_BUSTYPE_SSB) ++ return 0; ++ ++ bus->irq_domain = irq_domain_add_linear(NULL, chip->ngpio, ++ &irq_domain_simple_ops, chipco); ++ if (!bus->irq_domain) { ++ err = -ENODEV; ++ goto err_irq_domain; ++ } ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_create_mapping(bus->irq_domain, gpio); ++ ++ irq_set_chip_data(irq, bus); ++ irq_set_chip_and_handler(irq, &ssb_gpio_irq_chipco_chip, ++ handle_simple_irq); ++ } ++ ++ hwirq = ssb_mips_irq(bus->chipco.dev) + 2; ++ err = request_irq(hwirq, ssb_gpio_irq_chipco_handler, IRQF_SHARED, ++ "gpio", bus); ++ if (err) ++ goto err_req_irq; ++ ++ ssb_chipco_gpio_intmask(&bus->chipco, ~0, 0); ++ chipco_set32(chipco, SSB_CHIPCO_IRQMASK, SSB_CHIPCO_IRQ_GPIO); ++ ++ return 0; ++ ++err_req_irq: ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_find_mapping(bus->irq_domain, gpio); ++ ++ irq_dispose_mapping(irq); ++ } ++ irq_domain_remove(bus->irq_domain); ++err_irq_domain: ++ return err; ++} ++ ++static void ssb_gpio_irq_chipco_domain_exit(struct ssb_bus *bus) ++{ ++ struct ssb_chipcommon *chipco = &bus->chipco; ++ struct gpio_chip *chip = &bus->gpio; ++ int gpio; ++ ++ if (bus->bustype != SSB_BUSTYPE_SSB) ++ return; ++ ++ chipco_mask32(chipco, SSB_CHIPCO_IRQMASK, ~SSB_CHIPCO_IRQ_GPIO); ++ free_irq(ssb_mips_irq(bus->chipco.dev) + 2, chipco); ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_find_mapping(bus->irq_domain, gpio); ++ ++ irq_dispose_mapping(irq); ++ } ++ irq_domain_remove(bus->irq_domain); ++} ++#else ++static int ssb_gpio_irq_chipco_domain_init(struct ssb_bus *bus) ++{ ++ return 0; ++} ++ ++static void ssb_gpio_irq_chipco_domain_exit(struct ssb_bus *bus) ++{ + } ++#endif + + static int ssb_gpio_chipco_init(struct ssb_bus *bus) + { + struct gpio_chip *chip = &bus->gpio; ++ int err; + + chip->label = "ssb_chipco_gpio"; + chip->owner = THIS_MODULE; +@@ -96,7 +230,9 @@ static int ssb_gpio_chipco_init(struct s + chip->set = ssb_gpio_chipco_set_value; + chip->direction_input = ssb_gpio_chipco_direction_input; + chip->direction_output = ssb_gpio_chipco_direction_output; +- chip->to_irq = ssb_gpio_chipco_to_irq; ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++ chip->to_irq = ssb_gpio_to_irq; ++#endif + chip->ngpio = 16; + /* There is just one SoC in one device and its GPIO addresses should be + * deterministic to address them more easily. The other buses could get +@@ -106,9 +242,23 @@ static int ssb_gpio_chipco_init(struct s + else + chip->base = -1; + +- return gpiochip_add(chip); ++ err = ssb_gpio_irq_chipco_domain_init(bus); ++ if (err) ++ return err; ++ ++ err = gpiochip_add(chip); ++ if (err) { ++ ssb_gpio_irq_chipco_domain_exit(bus); ++ return err; ++ } ++ ++ return 0; + } + ++/************************************************** ++ * EXTIF ++ **************************************************/ ++ + #ifdef CONFIG_SSB_DRIVER_EXTIF + + static int ssb_gpio_extif_get_value(struct gpio_chip *chip, unsigned gpio) +@@ -145,19 +295,127 @@ static int ssb_gpio_extif_direction_outp + return 0; + } + +-static int ssb_gpio_extif_to_irq(struct gpio_chip *chip, unsigned gpio) ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++static void ssb_gpio_irq_extif_mask(struct irq_data *d) + { +- struct ssb_bus *bus = ssb_gpio_get_bus(chip); ++ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); ++ int gpio = irqd_to_hwirq(d); + +- if (bus->bustype == SSB_BUSTYPE_SSB) +- return ssb_mips_irq(bus->extif.dev) + 2; +- else +- return -EINVAL; ++ ssb_extif_gpio_intmask(&bus->extif, BIT(gpio), 0); ++} ++ ++static void ssb_gpio_irq_extif_unmask(struct irq_data *d) ++{ ++ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); ++ int gpio = irqd_to_hwirq(d); ++ u32 val = ssb_extif_gpio_in(&bus->extif, BIT(gpio)); ++ ++ ssb_extif_gpio_polarity(&bus->extif, BIT(gpio), val); ++ ssb_extif_gpio_intmask(&bus->extif, BIT(gpio), BIT(gpio)); ++} ++ ++static struct irq_chip ssb_gpio_irq_extif_chip = { ++ .name = "SSB-GPIO-EXTIF", ++ .irq_mask = ssb_gpio_irq_extif_mask, ++ .irq_unmask = ssb_gpio_irq_extif_unmask, ++}; ++ ++static irqreturn_t ssb_gpio_irq_extif_handler(int irq, void *dev_id) ++{ ++ struct ssb_bus *bus = dev_id; ++ struct ssb_extif *extif = &bus->extif; ++ u32 val = ssb_read32(extif->dev, SSB_EXTIF_GPIO_IN); ++ u32 mask = ssb_read32(extif->dev, SSB_EXTIF_GPIO_INTMASK); ++ u32 pol = ssb_read32(extif->dev, SSB_EXTIF_GPIO_INTPOL); ++ unsigned long irqs = (val ^ pol) & mask; ++ int gpio; ++ ++ if (!irqs) ++ return IRQ_NONE; ++ ++ for_each_set_bit(gpio, &irqs, bus->gpio.ngpio) ++ generic_handle_irq(ssb_gpio_to_irq(&bus->gpio, gpio)); ++ ssb_extif_gpio_polarity(extif, irqs, val & irqs); ++ ++ return IRQ_HANDLED; ++} ++ ++static int ssb_gpio_irq_extif_domain_init(struct ssb_bus *bus) ++{ ++ struct ssb_extif *extif = &bus->extif; ++ struct gpio_chip *chip = &bus->gpio; ++ int gpio, hwirq, err; ++ ++ if (bus->bustype != SSB_BUSTYPE_SSB) ++ return 0; ++ ++ bus->irq_domain = irq_domain_add_linear(NULL, chip->ngpio, ++ &irq_domain_simple_ops, extif); ++ if (!bus->irq_domain) { ++ err = -ENODEV; ++ goto err_irq_domain; ++ } ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_create_mapping(bus->irq_domain, gpio); ++ ++ irq_set_chip_data(irq, bus); ++ irq_set_chip_and_handler(irq, &ssb_gpio_irq_extif_chip, ++ handle_simple_irq); ++ } ++ ++ hwirq = ssb_mips_irq(bus->extif.dev) + 2; ++ err = request_irq(hwirq, ssb_gpio_irq_extif_handler, IRQF_SHARED, ++ "gpio", bus); ++ if (err) ++ goto err_req_irq; ++ ++ ssb_extif_gpio_intmask(&bus->extif, ~0, 0); ++ ++ return 0; ++ ++err_req_irq: ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_find_mapping(bus->irq_domain, gpio); ++ ++ irq_dispose_mapping(irq); ++ } ++ irq_domain_remove(bus->irq_domain); ++err_irq_domain: ++ return err; + } + ++static void ssb_gpio_irq_extif_domain_exit(struct ssb_bus *bus) ++{ ++ struct ssb_extif *extif = &bus->extif; ++ struct gpio_chip *chip = &bus->gpio; ++ int gpio; ++ ++ if (bus->bustype != SSB_BUSTYPE_SSB) ++ return; ++ ++ free_irq(ssb_mips_irq(bus->extif.dev) + 2, extif); ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_find_mapping(bus->irq_domain, gpio); ++ ++ irq_dispose_mapping(irq); ++ } ++ irq_domain_remove(bus->irq_domain); ++} ++#else ++static int ssb_gpio_irq_extif_domain_init(struct ssb_bus *bus) ++{ ++ return 0; ++} ++ ++static void ssb_gpio_irq_extif_domain_exit(struct ssb_bus *bus) ++{ ++} ++#endif ++ + static int ssb_gpio_extif_init(struct ssb_bus *bus) + { + struct gpio_chip *chip = &bus->gpio; ++ int err; + + chip->label = "ssb_extif_gpio"; + chip->owner = THIS_MODULE; +@@ -165,7 +423,9 @@ static int ssb_gpio_extif_init(struct ss + chip->set = ssb_gpio_extif_set_value; + chip->direction_input = ssb_gpio_extif_direction_input; + chip->direction_output = ssb_gpio_extif_direction_output; +- chip->to_irq = ssb_gpio_extif_to_irq; ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++ chip->to_irq = ssb_gpio_to_irq; ++#endif + chip->ngpio = 5; + /* There is just one SoC in one device and its GPIO addresses should be + * deterministic to address them more easily. The other buses could get +@@ -175,7 +435,17 @@ static int ssb_gpio_extif_init(struct ss + else + chip->base = -1; + +- return gpiochip_add(chip); ++ err = ssb_gpio_irq_extif_domain_init(bus); ++ if (err) ++ return err; ++ ++ err = gpiochip_add(chip); ++ if (err) { ++ ssb_gpio_irq_extif_domain_exit(bus); ++ return err; ++ } ++ ++ return 0; + } + + #else +@@ -185,6 +455,10 @@ static int ssb_gpio_extif_init(struct ss + } + #endif + ++/************************************************** ++ * Init ++ **************************************************/ ++ + int ssb_gpio_init(struct ssb_bus *bus) + { + if (ssb_chipco_available(&bus->chipco)) +--- a/drivers/ssb/main.c ++++ b/drivers/ssb/main.c +@@ -374,7 +374,8 @@ static ssize_t \ + attrib##_show(struct device *dev, struct device_attribute *attr, char *buf) \ + { \ + return sprintf(buf, format_string, dev_to_ssb_dev(dev)->field); \ +-} ++} \ ++static DEVICE_ATTR_RO(attrib); + + ssb_config_attr(core_num, core_index, "%u\n") + ssb_config_attr(coreid, id.coreid, "0x%04x\n") +@@ -387,16 +388,18 @@ name_show(struct device *dev, struct dev + return sprintf(buf, "%s\n", + ssb_core_name(dev_to_ssb_dev(dev)->id.coreid)); + } ++static DEVICE_ATTR_RO(name); + +-static struct device_attribute ssb_device_attrs[] = { +- __ATTR_RO(name), +- __ATTR_RO(core_num), +- __ATTR_RO(coreid), +- __ATTR_RO(vendor), +- __ATTR_RO(revision), +- __ATTR_RO(irq), +- __ATTR_NULL, ++static struct attribute *ssb_device_attrs[] = { ++ &dev_attr_name.attr, ++ &dev_attr_core_num.attr, ++ &dev_attr_coreid.attr, ++ &dev_attr_vendor.attr, ++ &dev_attr_revision.attr, ++ &dev_attr_irq.attr, ++ NULL, + }; ++ATTRIBUTE_GROUPS(ssb_device); + + static struct bus_type ssb_bustype = { + .name = "ssb", +@@ -407,7 +410,7 @@ static struct bus_type ssb_bustype = { + .suspend = ssb_device_suspend, + .resume = ssb_device_resume, + .uevent = ssb_device_uevent, +- .dev_attrs = ssb_device_attrs, ++ .dev_groups = ssb_device_groups, + }; + + static void ssb_buses_lock(void) +@@ -590,6 +593,13 @@ static int ssb_attach_queued_buses(void) + ssb_pcicore_init(&bus->pcicore); + if (bus->bustype == SSB_BUSTYPE_SSB) + ssb_watchdog_register(bus); ++ ++ err = ssb_gpio_init(bus); ++ if (err == -ENOTSUPP) ++ ssb_dbg("GPIO driver not activated\n"); ++ else if (err) ++ ssb_dbg("Error registering GPIO driver: %i\n", err); ++ + ssb_bus_may_powerdown(bus); + + err = ssb_devices_register(bus); +@@ -827,11 +837,6 @@ static int ssb_bus_register(struct ssb_b + ssb_chipcommon_init(&bus->chipco); + ssb_extif_init(&bus->extif); + ssb_mipscore_init(&bus->mipscore); +- err = ssb_gpio_init(bus); +- if (err == -ENOTSUPP) +- ssb_dbg("GPIO driver not activated\n"); +- else if (err) +- ssb_dbg("Error registering GPIO driver: %i\n", err); + err = ssb_fetch_invariants(bus, get_invariants); + if (err) { + ssb_bus_may_powerdown(bus); +--- a/include/linux/ssb/ssb.h ++++ b/include/linux/ssb/ssb.h +@@ -486,6 +486,7 @@ struct ssb_bus { + #endif /* EMBEDDED */ + #ifdef CONFIG_SSB_DRIVER_GPIO + struct gpio_chip gpio; ++ struct irq_domain *irq_domain; + #endif /* DRIVER_GPIO */ + + /* Internal-only stuff follows. Do not touch. */ +--- a/include/linux/ssb/ssb_driver_gige.h ++++ b/include/linux/ssb/ssb_driver_gige.h +@@ -108,6 +108,16 @@ static inline int ssb_gige_get_macaddr(s + return 0; + } + ++/* Get the device phy address */ ++static inline int ssb_gige_get_phyaddr(struct pci_dev *pdev) ++{ ++ struct ssb_gige *dev = pdev_to_ssb_gige(pdev); ++ if (!dev) ++ return -ENODEV; ++ ++ return dev->dev->bus->sprom.et0phyaddr; ++} ++ + extern int ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev, + struct pci_dev *pdev); + extern int ssb_gige_map_irq(struct ssb_device *sdev, +@@ -174,6 +184,10 @@ static inline int ssb_gige_get_macaddr(s + { + return -ENODEV; + } ++static inline int ssb_gige_get_phyaddr(struct pci_dev *pdev) ++{ ++ return -ENODEV; ++} + + #endif /* CONFIG_SSB_DRIVER_GIGE */ + #endif /* LINUX_SSB_DRIVER_GIGE_H_ */ diff --git a/target/linux/generic/patches-3.13/020-ssb_update.patch b/target/linux/generic/patches-3.13/020-ssb_update.patch new file mode 100644 index 0000000000..4452644680 --- /dev/null +++ b/target/linux/generic/patches-3.13/020-ssb_update.patch @@ -0,0 +1,467 @@ +--- a/drivers/ssb/Kconfig ++++ b/drivers/ssb/Kconfig +@@ -168,6 +168,7 @@ config SSB_DRIVER_GIGE + config SSB_DRIVER_GPIO + bool "SSB GPIO driver" + depends on SSB && GPIOLIB ++ select IRQ_DOMAIN if SSB_EMBEDDED + help + Driver to provide access to the GPIO pins on the bus. + +--- a/drivers/ssb/driver_chipcommon_sflash.c ++++ b/drivers/ssb/driver_chipcommon_sflash.c +@@ -37,7 +37,7 @@ static const struct ssb_sflash_tbl_e ssb + { "M25P32", 0x15, 0x10000, 64, }, + { "M25P64", 0x16, 0x10000, 128, }, + { "M25FL128", 0x17, 0x10000, 256, }, +- { 0 }, ++ { NULL }, + }; + + static const struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = { +@@ -55,7 +55,7 @@ static const struct ssb_sflash_tbl_e ssb + { "SST25VF016", 0x41, 0x1000, 512, }, + { "SST25VF032", 0x4a, 0x1000, 1024, }, + { "SST25VF064", 0x4b, 0x1000, 2048, }, +- { 0 }, ++ { NULL }, + }; + + static const struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = { +@@ -66,7 +66,7 @@ static const struct ssb_sflash_tbl_e ssb + { "AT45DB161", 0x2c, 512, 4096, }, + { "AT45DB321", 0x34, 512, 8192, }, + { "AT45DB642", 0x3c, 1024, 8192, }, +- { 0 }, ++ { NULL }, + }; + + static void ssb_sflash_cmd(struct ssb_chipcommon *cc, u32 opcode) +--- a/drivers/ssb/driver_gpio.c ++++ b/drivers/ssb/driver_gpio.c +@@ -9,16 +9,40 @@ + */ + + #include ++#include ++#include ++#include + #include + #include + + #include "ssb_private.h" + ++ ++/************************************************** ++ * Shared ++ **************************************************/ ++ + static struct ssb_bus *ssb_gpio_get_bus(struct gpio_chip *chip) + { + return container_of(chip, struct ssb_bus, gpio); + } + ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++static int ssb_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) ++{ ++ struct ssb_bus *bus = ssb_gpio_get_bus(chip); ++ ++ if (bus->bustype == SSB_BUSTYPE_SSB) ++ return irq_find_mapping(bus->irq_domain, gpio); ++ else ++ return -EINVAL; ++} ++#endif ++ ++/************************************************** ++ * ChipCommon ++ **************************************************/ ++ + static int ssb_gpio_chipco_get_value(struct gpio_chip *chip, unsigned gpio) + { + struct ssb_bus *bus = ssb_gpio_get_bus(chip); +@@ -74,19 +98,129 @@ static void ssb_gpio_chipco_free(struct + ssb_chipco_gpio_pullup(&bus->chipco, 1 << gpio, 0); + } + +-static int ssb_gpio_chipco_to_irq(struct gpio_chip *chip, unsigned gpio) ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++static void ssb_gpio_irq_chipco_mask(struct irq_data *d) + { +- struct ssb_bus *bus = ssb_gpio_get_bus(chip); ++ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); ++ int gpio = irqd_to_hwirq(d); + +- if (bus->bustype == SSB_BUSTYPE_SSB) +- return ssb_mips_irq(bus->chipco.dev) + 2; +- else +- return -EINVAL; ++ ssb_chipco_gpio_intmask(&bus->chipco, BIT(gpio), 0); ++} ++ ++static void ssb_gpio_irq_chipco_unmask(struct irq_data *d) ++{ ++ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); ++ int gpio = irqd_to_hwirq(d); ++ u32 val = ssb_chipco_gpio_in(&bus->chipco, BIT(gpio)); ++ ++ ssb_chipco_gpio_polarity(&bus->chipco, BIT(gpio), val); ++ ssb_chipco_gpio_intmask(&bus->chipco, BIT(gpio), BIT(gpio)); ++} ++ ++static struct irq_chip ssb_gpio_irq_chipco_chip = { ++ .name = "SSB-GPIO-CC", ++ .irq_mask = ssb_gpio_irq_chipco_mask, ++ .irq_unmask = ssb_gpio_irq_chipco_unmask, ++}; ++ ++static irqreturn_t ssb_gpio_irq_chipco_handler(int irq, void *dev_id) ++{ ++ struct ssb_bus *bus = dev_id; ++ struct ssb_chipcommon *chipco = &bus->chipco; ++ u32 val = chipco_read32(chipco, SSB_CHIPCO_GPIOIN); ++ u32 mask = chipco_read32(chipco, SSB_CHIPCO_GPIOIRQ); ++ u32 pol = chipco_read32(chipco, SSB_CHIPCO_GPIOPOL); ++ unsigned long irqs = (val ^ pol) & mask; ++ int gpio; ++ ++ if (!irqs) ++ return IRQ_NONE; ++ ++ for_each_set_bit(gpio, &irqs, bus->gpio.ngpio) ++ generic_handle_irq(ssb_gpio_to_irq(&bus->gpio, gpio)); ++ ssb_chipco_gpio_polarity(chipco, irqs, val & irqs); ++ ++ return IRQ_HANDLED; ++} ++ ++static int ssb_gpio_irq_chipco_domain_init(struct ssb_bus *bus) ++{ ++ struct ssb_chipcommon *chipco = &bus->chipco; ++ struct gpio_chip *chip = &bus->gpio; ++ int gpio, hwirq, err; ++ ++ if (bus->bustype != SSB_BUSTYPE_SSB) ++ return 0; ++ ++ bus->irq_domain = irq_domain_add_linear(NULL, chip->ngpio, ++ &irq_domain_simple_ops, chipco); ++ if (!bus->irq_domain) { ++ err = -ENODEV; ++ goto err_irq_domain; ++ } ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_create_mapping(bus->irq_domain, gpio); ++ ++ irq_set_chip_data(irq, bus); ++ irq_set_chip_and_handler(irq, &ssb_gpio_irq_chipco_chip, ++ handle_simple_irq); ++ } ++ ++ hwirq = ssb_mips_irq(bus->chipco.dev) + 2; ++ err = request_irq(hwirq, ssb_gpio_irq_chipco_handler, IRQF_SHARED, ++ "gpio", bus); ++ if (err) ++ goto err_req_irq; ++ ++ ssb_chipco_gpio_intmask(&bus->chipco, ~0, 0); ++ chipco_set32(chipco, SSB_CHIPCO_IRQMASK, SSB_CHIPCO_IRQ_GPIO); ++ ++ return 0; ++ ++err_req_irq: ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_find_mapping(bus->irq_domain, gpio); ++ ++ irq_dispose_mapping(irq); ++ } ++ irq_domain_remove(bus->irq_domain); ++err_irq_domain: ++ return err; ++} ++ ++static void ssb_gpio_irq_chipco_domain_exit(struct ssb_bus *bus) ++{ ++ struct ssb_chipcommon *chipco = &bus->chipco; ++ struct gpio_chip *chip = &bus->gpio; ++ int gpio; ++ ++ if (bus->bustype != SSB_BUSTYPE_SSB) ++ return; ++ ++ chipco_mask32(chipco, SSB_CHIPCO_IRQMASK, ~SSB_CHIPCO_IRQ_GPIO); ++ free_irq(ssb_mips_irq(bus->chipco.dev) + 2, chipco); ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_find_mapping(bus->irq_domain, gpio); ++ ++ irq_dispose_mapping(irq); ++ } ++ irq_domain_remove(bus->irq_domain); ++} ++#else ++static int ssb_gpio_irq_chipco_domain_init(struct ssb_bus *bus) ++{ ++ return 0; ++} ++ ++static void ssb_gpio_irq_chipco_domain_exit(struct ssb_bus *bus) ++{ + } ++#endif + + static int ssb_gpio_chipco_init(struct ssb_bus *bus) + { + struct gpio_chip *chip = &bus->gpio; ++ int err; + + chip->label = "ssb_chipco_gpio"; + chip->owner = THIS_MODULE; +@@ -96,7 +230,9 @@ static int ssb_gpio_chipco_init(struct s + chip->set = ssb_gpio_chipco_set_value; + chip->direction_input = ssb_gpio_chipco_direction_input; + chip->direction_output = ssb_gpio_chipco_direction_output; +- chip->to_irq = ssb_gpio_chipco_to_irq; ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++ chip->to_irq = ssb_gpio_to_irq; ++#endif + chip->ngpio = 16; + /* There is just one SoC in one device and its GPIO addresses should be + * deterministic to address them more easily. The other buses could get +@@ -106,9 +242,23 @@ static int ssb_gpio_chipco_init(struct s + else + chip->base = -1; + +- return gpiochip_add(chip); ++ err = ssb_gpio_irq_chipco_domain_init(bus); ++ if (err) ++ return err; ++ ++ err = gpiochip_add(chip); ++ if (err) { ++ ssb_gpio_irq_chipco_domain_exit(bus); ++ return err; ++ } ++ ++ return 0; + } + ++/************************************************** ++ * EXTIF ++ **************************************************/ ++ + #ifdef CONFIG_SSB_DRIVER_EXTIF + + static int ssb_gpio_extif_get_value(struct gpio_chip *chip, unsigned gpio) +@@ -145,19 +295,127 @@ static int ssb_gpio_extif_direction_outp + return 0; + } + +-static int ssb_gpio_extif_to_irq(struct gpio_chip *chip, unsigned gpio) ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++static void ssb_gpio_irq_extif_mask(struct irq_data *d) + { +- struct ssb_bus *bus = ssb_gpio_get_bus(chip); ++ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); ++ int gpio = irqd_to_hwirq(d); + +- if (bus->bustype == SSB_BUSTYPE_SSB) +- return ssb_mips_irq(bus->extif.dev) + 2; +- else +- return -EINVAL; ++ ssb_extif_gpio_intmask(&bus->extif, BIT(gpio), 0); ++} ++ ++static void ssb_gpio_irq_extif_unmask(struct irq_data *d) ++{ ++ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); ++ int gpio = irqd_to_hwirq(d); ++ u32 val = ssb_extif_gpio_in(&bus->extif, BIT(gpio)); ++ ++ ssb_extif_gpio_polarity(&bus->extif, BIT(gpio), val); ++ ssb_extif_gpio_intmask(&bus->extif, BIT(gpio), BIT(gpio)); ++} ++ ++static struct irq_chip ssb_gpio_irq_extif_chip = { ++ .name = "SSB-GPIO-EXTIF", ++ .irq_mask = ssb_gpio_irq_extif_mask, ++ .irq_unmask = ssb_gpio_irq_extif_unmask, ++}; ++ ++static irqreturn_t ssb_gpio_irq_extif_handler(int irq, void *dev_id) ++{ ++ struct ssb_bus *bus = dev_id; ++ struct ssb_extif *extif = &bus->extif; ++ u32 val = ssb_read32(extif->dev, SSB_EXTIF_GPIO_IN); ++ u32 mask = ssb_read32(extif->dev, SSB_EXTIF_GPIO_INTMASK); ++ u32 pol = ssb_read32(extif->dev, SSB_EXTIF_GPIO_INTPOL); ++ unsigned long irqs = (val ^ pol) & mask; ++ int gpio; ++ ++ if (!irqs) ++ return IRQ_NONE; ++ ++ for_each_set_bit(gpio, &irqs, bus->gpio.ngpio) ++ generic_handle_irq(ssb_gpio_to_irq(&bus->gpio, gpio)); ++ ssb_extif_gpio_polarity(extif, irqs, val & irqs); ++ ++ return IRQ_HANDLED; ++} ++ ++static int ssb_gpio_irq_extif_domain_init(struct ssb_bus *bus) ++{ ++ struct ssb_extif *extif = &bus->extif; ++ struct gpio_chip *chip = &bus->gpio; ++ int gpio, hwirq, err; ++ ++ if (bus->bustype != SSB_BUSTYPE_SSB) ++ return 0; ++ ++ bus->irq_domain = irq_domain_add_linear(NULL, chip->ngpio, ++ &irq_domain_simple_ops, extif); ++ if (!bus->irq_domain) { ++ err = -ENODEV; ++ goto err_irq_domain; ++ } ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_create_mapping(bus->irq_domain, gpio); ++ ++ irq_set_chip_data(irq, bus); ++ irq_set_chip_and_handler(irq, &ssb_gpio_irq_extif_chip, ++ handle_simple_irq); ++ } ++ ++ hwirq = ssb_mips_irq(bus->extif.dev) + 2; ++ err = request_irq(hwirq, ssb_gpio_irq_extif_handler, IRQF_SHARED, ++ "gpio", bus); ++ if (err) ++ goto err_req_irq; ++ ++ ssb_extif_gpio_intmask(&bus->extif, ~0, 0); ++ ++ return 0; ++ ++err_req_irq: ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_find_mapping(bus->irq_domain, gpio); ++ ++ irq_dispose_mapping(irq); ++ } ++ irq_domain_remove(bus->irq_domain); ++err_irq_domain: ++ return err; + } + ++static void ssb_gpio_irq_extif_domain_exit(struct ssb_bus *bus) ++{ ++ struct ssb_extif *extif = &bus->extif; ++ struct gpio_chip *chip = &bus->gpio; ++ int gpio; ++ ++ if (bus->bustype != SSB_BUSTYPE_SSB) ++ return; ++ ++ free_irq(ssb_mips_irq(bus->extif.dev) + 2, extif); ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_find_mapping(bus->irq_domain, gpio); ++ ++ irq_dispose_mapping(irq); ++ } ++ irq_domain_remove(bus->irq_domain); ++} ++#else ++static int ssb_gpio_irq_extif_domain_init(struct ssb_bus *bus) ++{ ++ return 0; ++} ++ ++static void ssb_gpio_irq_extif_domain_exit(struct ssb_bus *bus) ++{ ++} ++#endif ++ + static int ssb_gpio_extif_init(struct ssb_bus *bus) + { + struct gpio_chip *chip = &bus->gpio; ++ int err; + + chip->label = "ssb_extif_gpio"; + chip->owner = THIS_MODULE; +@@ -165,7 +423,9 @@ static int ssb_gpio_extif_init(struct ss + chip->set = ssb_gpio_extif_set_value; + chip->direction_input = ssb_gpio_extif_direction_input; + chip->direction_output = ssb_gpio_extif_direction_output; +- chip->to_irq = ssb_gpio_extif_to_irq; ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++ chip->to_irq = ssb_gpio_to_irq; ++#endif + chip->ngpio = 5; + /* There is just one SoC in one device and its GPIO addresses should be + * deterministic to address them more easily. The other buses could get +@@ -175,7 +435,17 @@ static int ssb_gpio_extif_init(struct ss + else + chip->base = -1; + +- return gpiochip_add(chip); ++ err = ssb_gpio_irq_extif_domain_init(bus); ++ if (err) ++ return err; ++ ++ err = gpiochip_add(chip); ++ if (err) { ++ ssb_gpio_irq_extif_domain_exit(bus); ++ return err; ++ } ++ ++ return 0; + } + + #else +@@ -185,6 +455,10 @@ static int ssb_gpio_extif_init(struct ss + } + #endif + ++/************************************************** ++ * Init ++ **************************************************/ ++ + int ssb_gpio_init(struct ssb_bus *bus) + { + if (ssb_chipco_available(&bus->chipco)) +--- a/drivers/ssb/main.c ++++ b/drivers/ssb/main.c +@@ -593,6 +593,13 @@ static int ssb_attach_queued_buses(void) + ssb_pcicore_init(&bus->pcicore); + if (bus->bustype == SSB_BUSTYPE_SSB) + ssb_watchdog_register(bus); ++ ++ err = ssb_gpio_init(bus); ++ if (err == -ENOTSUPP) ++ ssb_dbg("GPIO driver not activated\n"); ++ else if (err) ++ ssb_dbg("Error registering GPIO driver: %i\n", err); ++ + ssb_bus_may_powerdown(bus); + + err = ssb_devices_register(bus); +@@ -830,11 +837,6 @@ static int ssb_bus_register(struct ssb_b + ssb_chipcommon_init(&bus->chipco); + ssb_extif_init(&bus->extif); + ssb_mipscore_init(&bus->mipscore); +- err = ssb_gpio_init(bus); +- if (err == -ENOTSUPP) +- ssb_dbg("GPIO driver not activated\n"); +- else if (err) +- ssb_dbg("Error registering GPIO driver: %i\n", err); + err = ssb_fetch_invariants(bus, get_invariants); + if (err) { + ssb_bus_may_powerdown(bus); +--- a/include/linux/ssb/ssb.h ++++ b/include/linux/ssb/ssb.h +@@ -486,6 +486,7 @@ struct ssb_bus { + #endif /* EMBEDDED */ + #ifdef CONFIG_SSB_DRIVER_GPIO + struct gpio_chip gpio; ++ struct irq_domain *irq_domain; + #endif /* DRIVER_GPIO */ + + /* Internal-only stuff follows. Do not touch. */