This change checks if we have the necessary permission to access the GPIO. For devices that have support for virtualisation we need to check both the TEGRA186_GPIO_VM_REG and the TEGRA186_GPIO_SCR_REG registers. For device that do not have virtualisation support for GPIOs we only need to check the TEGRA186_GPIO_SCR_REG register. Signed-off-by: Manish Bhardwaj <mbhardwaj@xxxxxxxxxx> Signed-off-by: Prathamesh Shete <pshete@xxxxxxxxxx> --- drivers/gpio/gpio-tegra186.c | 71 ++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index 54d9fa7da9c1..e6fc3c9b1e9f 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -26,6 +26,22 @@ #define TEGRA186_GPIO_INT_ROUTE_MAPPING(p, x) (0x14 + (p) * 0x20 + (x) * 4) +#define TEGRA186_GPIO_VM_REG 0x00 +#define TEGRA186_GPIO_VM_RW_MASK 0x03 +#define TEGRA186_GPIO_SCR_REG 0x04 +#define TEGRA186_GPIO_SCR_DIFF 0x08 +#define TEGRA186_GPIO_SCR_BASE_DIFF 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) @@ -77,6 +93,7 @@ struct tegra_gpio_soc { unsigned int num_irqs_per_bank; const struct tegra186_pin_range *pin_ranges; + bool has_vm_support; unsigned int num_pin_ranges; const char *pinmux; bool has_gte; @@ -129,6 +146,45 @@ 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_BASE_DIFF; + + return gpio->secure + offset + pin * TEGRA186_GPIO_SCR_DIFF; +} + +static inline bool tegra186_gpio_is_accessible(struct tegra_gpio *gpio, u32 pin) +{ + void __iomem *secure; + u32 val; + + secure = tegra186_gpio_get_secure_base(gpio, pin); + + if (gpio->soc->has_vm_support) { + val = readl(secure + TEGRA186_GPIO_VM_REG); + if ((val & TEGRA186_GPIO_VM_RW_MASK) != TEGRA186_GPIO_VM_RW_MASK) + return false; + } + + val = __raw_readl(secure + TEGRA186_GPIO_SCR_REG); + + if ((val & TEGRA186_GPIO_SCR_SEC_ENABLE) == 0) + return true; + + if ((val & TEGRA186_GPIO_FULL_ACCESS) == TEGRA186_GPIO_FULL_ACCESS) + return true; + + return false; +} + static int tegra186_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) { @@ -136,6 +192,9 @@ static int tegra186_gpio_get_direction(struct gpio_chip *chip, void __iomem *base; u32 value; + if (!tegra186_gpio_is_accessible(gpio, offset)) + return -EPERM; + base = tegra186_gpio_get_base(gpio, offset); if (WARN_ON(base == NULL)) return -ENODEV; @@ -154,6 +213,9 @@ static int tegra186_gpio_direction_input(struct gpio_chip *chip, void __iomem *base; u32 value; + if (!tegra186_gpio_is_accessible(gpio, offset)) + return -EPERM; + base = tegra186_gpio_get_base(gpio, offset); if (WARN_ON(base == NULL)) return -ENODEV; @@ -177,6 +239,9 @@ static int tegra186_gpio_direction_output(struct gpio_chip *chip, void __iomem *base; u32 value; + if (!tegra186_gpio_is_accessible(gpio, offset)) + return -EPERM; + /* configure output level first */ chip->set(chip, offset, level); @@ -293,6 +358,10 @@ static void tegra186_gpio_set(struct gpio_chip *chip, unsigned int offset, void __iomem *base; u32 value; + if (!tegra186_gpio_is_accessible(gpio, offset)){ + pr_err("GPIO not accessible\n"); + return; + } base = tegra186_gpio_get_base(gpio, offset); if (WARN_ON(base == NULL)) return; @@ -1042,6 +1111,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) \ @@ -1067,6 +1137,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) \ -- 2.17.1