[PATCH 3/6] pinctrl: qcom: handle reserved ranges

Sumit Garg sumit.garg at linaro.org
Fri Nov 3 08:17:40 CET 2023


On Tue, 31 Oct 2023 at 19:52, Caleb Connolly <caleb.connolly at linaro.org> wrote:
>
> Some Qualcomm boards feature reserved ranges of pins which are protected
> by firmware. Attempting to read or write any registers associated with
> these pins results the board resetting.

Does any of the current Qcom boards supported in u-boot require this
feature? If not then you should introduce this feature alongside the
new Qcom boards requiring this feature.

-Sumit

>
> Add support for parsing these ranges from devicetree and ensure that the
> pinctrl and GPIO drivers don't try to interact with these pins.
>
> Signed-off-by: Caleb Connolly <caleb.connolly at linaro.org>
> ---
>  drivers/gpio/msm_gpio.c             | 15 +++++++++
>  drivers/pinctrl/qcom/pinctrl-qcom.c | 64 +++++++++++++++++++++++++++++++++++++
>  include/qcom-gpio.h                 | 15 +++++++++
>  3 files changed, 94 insertions(+)
>
> diff --git a/drivers/gpio/msm_gpio.c b/drivers/gpio/msm_gpio.c
> index 7d77776a25fd..7a09abdafb2e 100644
> --- a/drivers/gpio/msm_gpio.c
> +++ b/drivers/gpio/msm_gpio.c
> @@ -39,6 +39,9 @@ static int msm_gpio_direction_input(struct udevice *dev, unsigned int gpio)
>  {
>         struct msm_gpio_bank *priv = dev_get_priv(dev);
>
> +       if (msm_pinctrl_is_reserved(dev_get_parent(dev), gpio))
> +               return 0;
> +
>         /* Disable OE bit */
>         clrsetbits_le32(priv->base + GPIO_CONFIG_REG(dev, gpio),
>                         GPIO_OE_MASK, GPIO_OE_DISABLE);
> @@ -50,6 +53,9 @@ static int msm_gpio_set_value(struct udevice *dev, unsigned gpio, int value)
>  {
>         struct msm_gpio_bank *priv = dev_get_priv(dev);
>
> +       if (msm_pinctrl_is_reserved(dev_get_parent(dev), gpio))
> +               return 0;
> +
>         value = !!value;
>         /* set value */
>         writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_REG(dev, gpio));
> @@ -62,6 +68,9 @@ static int msm_gpio_direction_output(struct udevice *dev, unsigned gpio,
>  {
>         struct msm_gpio_bank *priv = dev_get_priv(dev);
>
> +       if (msm_pinctrl_is_reserved(dev_get_parent(dev), gpio))
> +               return 0;
> +
>         value = !!value;
>         /* set value */
>         writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_REG(dev, gpio));
> @@ -76,6 +85,9 @@ static int msm_gpio_get_value(struct udevice *dev, unsigned gpio)
>  {
>         struct msm_gpio_bank *priv = dev_get_priv(dev);
>
> +       if (msm_pinctrl_is_reserved(dev_get_parent(dev), gpio))
> +               return 0;
> +
>         return !!(readl(priv->base + GPIO_IN_OUT_REG(dev, gpio)) >> GPIO_IN);
>  }
>
> @@ -83,6 +95,9 @@ static int msm_gpio_get_function(struct udevice *dev, unsigned gpio)
>  {
>         struct msm_gpio_bank *priv = dev_get_priv(dev);
>
> +       if (msm_pinctrl_is_reserved(dev_get_parent(dev), gpio))
> +               return GPIOF_UNKNOWN;
> +
>         if (readl(priv->base + GPIO_CONFIG_REG(dev, gpio)) & GPIO_OE_ENABLE)
>                 return GPIOF_OUTPUT;
>
> diff --git a/drivers/pinctrl/qcom/pinctrl-qcom.c b/drivers/pinctrl/qcom/pinctrl-qcom.c
> index fb255f9572f4..92b35c198788 100644
> --- a/drivers/pinctrl/qcom/pinctrl-qcom.c
> +++ b/drivers/pinctrl/qcom/pinctrl-qcom.c
> @@ -20,9 +20,13 @@
>
>  #include "pinctrl-qcom.h"
>
> +#define MSM_PINCTRL_MAX_RESERVED_RANGES 32
> +
>  struct msm_pinctrl_priv {
>         phys_addr_t base;
>         struct msm_pinctrl_data *data;
> +       u32 reserved_ranges[MSM_PINCTRL_MAX_RESERVED_RANGES * 2];
> +       int reserved_ranges_count;
>  };
>
>  #define GPIO_CONFIG_REG(priv, x) \
> @@ -61,13 +65,53 @@ static const char *msm_get_function_name(struct udevice *dev,
>         return priv->data->get_function_name(dev, selector);
>  }
>
> +static int msm_pinctrl_parse_ranges(struct udevice *dev)
> +{
> +       struct msm_pinctrl_priv *priv = dev_get_priv(dev);
> +       int count;
> +
> +       if (ofnode_read_prop(dev_ofnode(dev), "gpio-reserved-ranges",
> +                            &count)) {
> +               if (count % 2 == 1) {
> +                       dev_err(dev, "gpio-reserved-ranges must be a multiple of 2\n");
> +                       return -EINVAL;
> +               }
> +               /* Size is in bytes, but we're indexing by ints */
> +               count /= 4;
> +
> +               if (count > MSM_PINCTRL_MAX_RESERVED_RANGES) {
> +                       dev_err(dev, "gpio-reserved-ranges must be less than %d (got %d)\n",
> +                               MSM_PINCTRL_MAX_RESERVED_RANGES, count);
> +                       return -EINVAL;
> +               }
> +
> +               priv->reserved_ranges_count = count;
> +               for (count = 0; count < priv->reserved_ranges_count; count++) {
> +                       if (ofnode_read_u32_index(dev_ofnode(dev), "gpio-reserved-ranges",
> +                                                 count, &priv->reserved_ranges[count])) {
> +                               dev_err(dev, "failed to read gpio-reserved-ranges[%d]\n", count);
> +                               return -EINVAL;
> +                       }
> +               }
> +       }
> +
> +       return 0;
> +}
> +
>  static int msm_pinctrl_probe(struct udevice *dev)
>  {
>         struct msm_pinctrl_priv *priv = dev_get_priv(dev);
> +       int ret;
>
>         priv->base = dev_read_addr(dev);
>         priv->data = (struct msm_pinctrl_data *)dev_get_driver_data(dev);
>
> +       ret = msm_pinctrl_parse_ranges(dev);
> +       if (ret) {
> +               printf("Couldn't parse reserved GPIO ranges!\n");
> +               return ret;
> +       }
> +
>         return priv->base == FDT_ADDR_T_NONE ? -EINVAL : 0;
>  }
>
> @@ -83,6 +127,9 @@ static int msm_pinmux_set(struct udevice *dev, unsigned int pin_selector,
>  {
>         struct msm_pinctrl_priv *priv = dev_get_priv(dev);
>
> +       if (msm_pinctrl_is_reserved(dev, pin_selector))
> +               return 0;
> +
>         clrsetbits_le32(priv->base + GPIO_CONFIG_REG(priv, pin_selector),
>                         TLMM_FUNC_SEL_MASK | TLMM_GPIO_DISABLE,
>                         priv->data->get_function_mux(func_selector) << 2);
> @@ -94,6 +141,9 @@ static int msm_pinconf_set(struct udevice *dev, unsigned int pin_selector,
>  {
>         struct msm_pinctrl_priv *priv = dev_get_priv(dev);
>
> +       if (msm_pinctrl_is_reserved(dev, pin_selector))
> +               return 0;
> +
>         switch (param) {
>         case PIN_CONFIG_DRIVE_STRENGTH:
>                 argument = (argument / 2) - 1;
> @@ -178,3 +228,17 @@ U_BOOT_DRIVER(qcom_pinctrl) = {
>         .ops            = &msm_pinctrl_ops,
>         .probe          = msm_pinctrl_probe,
>  };
> +
> +bool msm_pinctrl_is_reserved(struct udevice *dev, unsigned int pin)
> +{
> +       struct msm_pinctrl_priv *priv = dev_get_priv(dev);
> +       unsigned int i, start;
> +
> +       for (i = 0; i < priv->reserved_ranges_count; i += 2) {
> +               start = priv->reserved_ranges[i];
> +               if (pin >= start && pin < start + priv->reserved_ranges[i + 1])
> +                       return true;
> +       }
> +
> +       return false;
> +}
> diff --git a/include/qcom-gpio.h b/include/qcom-gpio.h
> index 8dac62f870b9..490a1de55f89 100644
> --- a/include/qcom-gpio.h
> +++ b/include/qcom-gpio.h
> @@ -25,4 +25,19 @@ static inline u32 qcom_pin_offset(const unsigned int *offs, unsigned int selecto
>         return out;
>  }
>
> +struct udevice;
> +
> +/**
> + * msm_pinctrl_is_reserved() - Check if a pin lies in a reserved range
> + *
> + * @dev: pinctrl device
> + * @pin: Pin number
> + *
> + * Returns: true if pin is reserved, otherwise false
> + *
> + * Call using dev_get_parent() from the GPIO device, it is a child of
> + * the pinctrl device.
> + */
> +bool msm_pinctrl_is_reserved(struct udevice *dev, unsigned int pin);
> +
>  #endif /* _QCOM_GPIO_H_ */
>
> --
> 2.42.0
>


More information about the U-Boot mailing list