gpio: tegra186: Check GPIO pin permission before access.
authorPrathamesh Shete <pshete@nvidia.com>
Wed, 24 May 2023 10:50:21 +0000 (16:20 +0530)
committerBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Fri, 26 May 2023 12:29:00 +0000 (14:29 +0200)
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@nvidia.com>
Signed-off-by: Prathamesh Shete <pshete@nvidia.com>
Acked-by: Thierry Reding <treding@nvidia.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Jon Hunter <jonathanh@nvidia.com>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
drivers/gpio/gpio-tegra186.c

index b904de0..464b0ea 100644 (file)
 
 #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;
@@ -958,6 +1028,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 +1056,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 +1112,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 +1138,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 +1183,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 +1210,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 +1241,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 +1263,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[] = {