Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpio: tegra186: Support multiple interrupts per bank

Tegra194 and later support more than a single interrupt per bank. This
is primarily useful for virtualization but can also be helpful for more
fine-grained CPU affinity control. To keep things simple for now, route
all pins to the first interrupt.

For backwards-compatibility, support old device trees that specify only
one interrupt per bank by counting the interrupts at probe time.

Signed-off-by: Thierry Reding <treding@nvidia.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>

authored by

Thierry Reding and committed by
Bartosz Golaszewski
21038680 ca038748

+41 -7
+41 -7
drivers/gpio/gpio-tegra186.c
··· 69 69 const char *name; 70 70 unsigned int instance; 71 71 72 + unsigned int num_irqs_per_bank; 73 + 72 74 const struct tegra186_pin_range *pin_ranges; 73 75 unsigned int num_pin_ranges; 74 76 const char *pinmux; ··· 454 452 struct irq_domain *domain = gpio->gpio.irq.domain; 455 453 struct irq_chip *chip = irq_desc_get_chip(desc); 456 454 unsigned int parent = irq_desc_get_irq(desc); 457 - unsigned int i, offset = 0; 455 + unsigned int i, j, offset = 0; 458 456 459 457 chained_irq_enter(chip, desc); 460 458 ··· 467 465 base = gpio->base + port->bank * 0x1000 + port->port * 0x200; 468 466 469 467 /* skip ports that are not associated with this bank */ 470 - if (parent != gpio->irq[port->bank]) 468 + for (j = 0; j < gpio->num_irqs_per_bank; j++) { 469 + if (parent == gpio->irq[port->bank * gpio->num_irqs_per_bank + j]) 470 + break; 471 + } 472 + 473 + if (j == gpio->num_irqs_per_bank) 471 474 goto skip; 472 475 473 476 value = readl(base + TEGRA186_GPIO_INTERRUPT_STATUS(1)); ··· 574 567 575 568 static void tegra186_gpio_init_route_mapping(struct tegra_gpio *gpio) 576 569 { 570 + struct device *dev = gpio->gpio.parent; 577 571 unsigned int i, j; 578 572 u32 value; 579 573 ··· 593 585 */ 594 586 if ((value & TEGRA186_GPIO_CTL_SCR_SEC_REN) == 0 && 595 587 (value & TEGRA186_GPIO_CTL_SCR_SEC_WEN) == 0) { 596 - for (j = 0; j < 8; j++) { 588 + /* 589 + * On Tegra194 and later, each pin can be routed to one or more 590 + * interrupts. 591 + */ 592 + for (j = 0; j < gpio->num_irqs_per_bank; j++) { 593 + dev_dbg(dev, "programming default interrupt routing for port %s\n", 594 + port->name); 595 + 597 596 offset = TEGRA186_GPIO_INT_ROUTE_MAPPING(p, j); 598 597 599 - value = readl(base + offset); 600 - value = BIT(port->pins) - 1; 601 - writel(value, base + offset); 598 + /* 599 + * By default we only want to route GPIO pins to IRQ 0. This works 600 + * only under the assumption that we're running as the host kernel 601 + * and hence all GPIO pins are owned by Linux. 602 + * 603 + * For cases where Linux is the guest OS, the hypervisor will have 604 + * to configure the interrupt routing and pass only the valid 605 + * interrupts via device tree. 606 + */ 607 + if (j == 0) { 608 + value = readl(base + offset); 609 + value = BIT(port->pins) - 1; 610 + writel(value, base + offset); 611 + } 602 612 } 603 613 } 604 614 } ··· 635 609 goto error; 636 610 637 611 gpio->num_irqs_per_bank = gpio->num_irq / gpio->num_banks; 612 + 613 + if (gpio->num_irqs_per_bank > gpio->soc->num_irqs_per_bank) 614 + goto error; 638 615 639 616 return 0; 640 617 ··· 795 766 irq->parents = gpio->irq; 796 767 } 797 768 798 - tegra186_gpio_init_route_mapping(gpio); 769 + if (gpio->soc->num_irqs_per_bank > 1) 770 + tegra186_gpio_init_route_mapping(gpio); 799 771 800 772 np = of_find_matching_node(NULL, tegra186_pmc_of_match); 801 773 if (np) { ··· 863 833 .ports = tegra186_main_ports, 864 834 .name = "tegra186-gpio", 865 835 .instance = 0, 836 + .num_irqs_per_bank = 1, 866 837 }; 867 838 868 839 #define TEGRA186_AON_GPIO_PORT(_name, _bank, _port, _pins) \ ··· 890 859 .ports = tegra186_aon_ports, 891 860 .name = "tegra186-gpio-aon", 892 861 .instance = 1, 862 + .num_irqs_per_bank = 1, 893 863 }; 894 864 895 865 #define TEGRA194_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ ··· 942 910 .ports = tegra194_main_ports, 943 911 .name = "tegra194-gpio", 944 912 .instance = 0, 913 + .num_irqs_per_bank = 8, 945 914 .num_pin_ranges = ARRAY_SIZE(tegra194_main_pin_ranges), 946 915 .pin_ranges = tegra194_main_pin_ranges, 947 916 .pinmux = "nvidia,tegra194-pinmux", ··· 969 936 .ports = tegra194_aon_ports, 970 937 .name = "tegra194-gpio-aon", 971 938 .instance = 1, 939 + .num_irqs_per_bank = 8, 972 940 }; 973 941 974 942 static const struct of_device_id tegra186_gpio_of_match[] = {