diff options
Diffstat (limited to 'drivers/gpio/gpio-tegra186.c')
-rw-r--r-- | drivers/gpio/gpio-tegra186.c | 92 |
1 files changed, 87 insertions, 5 deletions
diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index b904de0b1784..80d08ddde40e 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -27,6 +27,22 @@ #define TEGRA186_GPIO_INT_ROUTE_MAPPING(p, x) (0x14 + (p) * 0x20 + (x) * 4) +#define TEGRA186_GPIO_VM 0x00 +#define TEGRA186_GPIO_VM_RW_MASK 0x03 +#define TEGRA186_GPIO_SCR 0x04 +#define TEGRA186_GPIO_SCR_PIN_SIZE 0x08 +#define TEGRA186_GPIO_SCR_PORT_SIZE 0x40 +#define TEGRA186_GPIO_SCR_SEC_WEN BIT(28) +#define TEGRA186_GPIO_SCR_SEC_REN BIT(27) +#define TEGRA186_GPIO_SCR_SEC_G1W BIT(9) +#define TEGRA186_GPIO_SCR_SEC_G1R BIT(1) +#define TEGRA186_GPIO_FULL_ACCESS (TEGRA186_GPIO_SCR_SEC_WEN | \ + TEGRA186_GPIO_SCR_SEC_REN | \ + TEGRA186_GPIO_SCR_SEC_G1R | \ + TEGRA186_GPIO_SCR_SEC_G1W) +#define TEGRA186_GPIO_SCR_SEC_ENABLE (TEGRA186_GPIO_SCR_SEC_WEN | \ + TEGRA186_GPIO_SCR_SEC_REN) + /* control registers */ #define TEGRA186_GPIO_ENABLE_CONFIG 0x00 #define TEGRA186_GPIO_ENABLE_CONFIG_ENABLE BIT(0) @@ -81,6 +97,7 @@ struct tegra_gpio_soc { unsigned int num_pin_ranges; const char *pinmux; bool has_gte; + bool has_vm_support; }; struct tegra_gpio { @@ -130,6 +147,58 @@ static void __iomem *tegra186_gpio_get_base(struct tegra_gpio *gpio, return gpio->base + offset + pin * 0x20; } +static void __iomem *tegra186_gpio_get_secure_base(struct tegra_gpio *gpio, + unsigned int pin) +{ + const struct tegra_gpio_port *port; + unsigned int offset; + + port = tegra186_gpio_get_port(gpio, &pin); + if (!port) + return NULL; + + offset = port->bank * 0x1000 + port->port * TEGRA186_GPIO_SCR_PORT_SIZE; + + return gpio->secure + offset + pin * TEGRA186_GPIO_SCR_PIN_SIZE; +} + +static inline bool tegra186_gpio_is_accessible(struct tegra_gpio *gpio, unsigned int pin) +{ + void __iomem *secure; + u32 value; + + secure = tegra186_gpio_get_secure_base(gpio, pin); + + if (gpio->soc->has_vm_support) { + value = readl(secure + TEGRA186_GPIO_VM); + if ((value & TEGRA186_GPIO_VM_RW_MASK) != TEGRA186_GPIO_VM_RW_MASK) + return false; + } + + value = __raw_readl(secure + TEGRA186_GPIO_SCR); + + if ((value & TEGRA186_GPIO_SCR_SEC_ENABLE) == 0) + return true; + + if ((value & TEGRA186_GPIO_FULL_ACCESS) == TEGRA186_GPIO_FULL_ACCESS) + return true; + + return false; +} + +static int tegra186_init_valid_mask(struct gpio_chip *chip, + unsigned long *valid_mask, unsigned int ngpios) +{ + struct tegra_gpio *gpio = gpiochip_get_data(chip); + unsigned int j; + + for (j = 0; j < ngpios; j++) { + if (!tegra186_gpio_is_accessible(gpio, j)) + clear_bit(j, valid_mask); + } + return 0; +} + static int tegra186_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) { @@ -816,6 +885,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev) gpio->gpio.set = tegra186_gpio_set; gpio->gpio.set_config = tegra186_gpio_set_config; gpio->gpio.add_pin_ranges = tegra186_gpio_add_pin_ranges; + gpio->gpio.init_valid_mask = tegra186_init_valid_mask; if (gpio->soc->has_gte) { gpio->gpio.en_hw_timestamp = tegra186_gpio_en_hw_ts; gpio->gpio.dis_hw_timestamp = tegra186_gpio_dis_hw_ts; @@ -894,11 +964,15 @@ static int tegra186_gpio_probe(struct platform_device *pdev) np = of_find_matching_node(NULL, tegra186_pmc_of_match); if (np) { - irq->parent_domain = irq_find_host(np); - of_node_put(np); - - if (!irq->parent_domain) - return -EPROBE_DEFER; + if (of_device_is_available(np)) { + irq->parent_domain = irq_find_host(np); + of_node_put(np); + + if (!irq->parent_domain) + return -EPROBE_DEFER; + } else { + of_node_put(np); + } } irq->map = devm_kcalloc(&pdev->dev, gpio->gpio.ngpio, @@ -958,6 +1032,7 @@ static const struct tegra_gpio_soc tegra186_main_soc = { .name = "tegra186-gpio", .instance = 0, .num_irqs_per_bank = 1, + .has_vm_support = false, }; #define TEGRA186_AON_GPIO_PORT(_name, _bank, _port, _pins) \ @@ -985,6 +1060,7 @@ static const struct tegra_gpio_soc tegra186_aon_soc = { .name = "tegra186-gpio-aon", .instance = 1, .num_irqs_per_bank = 1, + .has_vm_support = false, }; #define TEGRA194_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ @@ -1040,6 +1116,7 @@ static const struct tegra_gpio_soc tegra194_main_soc = { .num_pin_ranges = ARRAY_SIZE(tegra194_main_pin_ranges), .pin_ranges = tegra194_main_pin_ranges, .pinmux = "nvidia,tegra194-pinmux", + .has_vm_support = true, }; #define TEGRA194_AON_GPIO_PORT(_name, _bank, _port, _pins) \ @@ -1065,6 +1142,7 @@ static const struct tegra_gpio_soc tegra194_aon_soc = { .instance = 1, .num_irqs_per_bank = 8, .has_gte = true, + .has_vm_support = false, }; #define TEGRA234_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ @@ -1109,6 +1187,7 @@ static const struct tegra_gpio_soc tegra234_main_soc = { .name = "tegra234-gpio", .instance = 0, .num_irqs_per_bank = 8, + .has_vm_support = true, }; #define TEGRA234_AON_GPIO_PORT(_name, _bank, _port, _pins) \ @@ -1135,6 +1214,7 @@ static const struct tegra_gpio_soc tegra234_aon_soc = { .instance = 1, .num_irqs_per_bank = 8, .has_gte = true, + .has_vm_support = false, }; #define TEGRA241_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ @@ -1165,6 +1245,7 @@ static const struct tegra_gpio_soc tegra241_main_soc = { .name = "tegra241-gpio", .instance = 0, .num_irqs_per_bank = 8, + .has_vm_support = false, }; #define TEGRA241_AON_GPIO_PORT(_name, _bank, _port, _pins) \ @@ -1186,6 +1267,7 @@ static const struct tegra_gpio_soc tegra241_aon_soc = { .name = "tegra241-gpio-aon", .instance = 1, .num_irqs_per_bank = 8, + .has_vm_support = false, }; static const struct of_device_id tegra186_gpio_of_match[] = { |