[PATCH v2] pinctrl: qcom: handle reserved ranges
Sumit Garg
sumit.garg at kernel.org
Thu Apr 10 11:19:07 CEST 2025
On Thu, Apr 10, 2025 at 10:52:38AM +0200, neil.armstrong at linaro.org wrote:
> From: Caleb Connolly <caleb.connolly at linaro.org>
>
> 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.
>
> 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>
> Signed-off-by: Neil Armstrong <neil.armstrong at linaro.org>
> ---
> Changes in v2:
> - Switch to bitmap
> - Link to v1: https://lore.kernel.org/r/20250401-topic-sm8x50-pinctrl-reserved-ranges-v1-1-0fe88b491707@linaro.org
> ---
> arch/arm/mach-snapdragon/include/mach/gpio.h | 15 +++++++
> drivers/gpio/msm_gpio.c | 9 ++++
> drivers/pinctrl/qcom/pinctrl-qcom.c | 67 ++++++++++++++++++++++++++++
> 3 files changed, 91 insertions(+)
Reviewed-by: Sumit Garg <sumit.garg at oss.qualcomm.com>
-Sumit
>
> diff --git a/arch/arm/mach-snapdragon/include/mach/gpio.h b/arch/arm/mach-snapdragon/include/mach/gpio.h
> index cc8f405e20b4392cf9226b805bc85b73aedd9134..11e8104baf2328f5bf82cb318459a237168f6978 100644
> --- a/arch/arm/mach-snapdragon/include/mach/gpio.h
> +++ b/arch/arm/mach-snapdragon/include/mach/gpio.h
> @@ -46,4 +46,19 @@ static inline bool qcom_is_special_pin(const struct msm_pin_data *pindata, unsig
> return pindata->special_pins_start && pin >= pindata->special_pins_start;
> }
>
> +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_ */
> diff --git a/drivers/gpio/msm_gpio.c b/drivers/gpio/msm_gpio.c
> index cea073b329777d4e03fbfa86415041a825f65aad..647a616a29374fcf12099509c51fb6e96b19f9f5 100644
> --- a/drivers/gpio/msm_gpio.c
> +++ b/drivers/gpio/msm_gpio.c
> @@ -151,6 +151,9 @@ static int msm_gpio_direction_output(struct udevice *dev, unsigned int gpio,
>
> static int msm_gpio_set_flags(struct udevice *dev, unsigned int gpio, ulong flags)
> {
> + if (msm_pinctrl_is_reserved(dev_get_parent(dev), gpio))
> + return -EPERM;
> +
> if (flags & GPIOD_IS_OUT_ACTIVE) {
> return msm_gpio_direction_output(dev, gpio, 1);
> } else if (flags & GPIOD_IS_OUT) {
> @@ -186,6 +189,9 @@ static int msm_gpio_get_value(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 -EPERM;
> +
> if (qcom_is_special_pin(priv->pin_data, gpio))
> return msm_gpio_get_value_special(priv, gpio);
>
> @@ -196,6 +202,9 @@ static int msm_gpio_get_function(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 GPIOF_UNKNOWN;
> +
> /* Always NOP for special pins, assume they're in the correct state */
> if (qcom_is_special_pin(priv->pin_data, gpio))
> return 0;
> diff --git a/drivers/pinctrl/qcom/pinctrl-qcom.c b/drivers/pinctrl/qcom/pinctrl-qcom.c
> index 24d031947a3c00da352fee8b50d5ad38e2d93dfa..c95db56bc47ed3183822fcef2721fc00262b6182 100644
> --- a/drivers/pinctrl/qcom/pinctrl-qcom.c
> +++ b/drivers/pinctrl/qcom/pinctrl-qcom.c
> @@ -15,14 +15,18 @@
> #include <asm/gpio.h>
> #include <dm/pinctrl.h>
> #include <linux/bitops.h>
> +#include <linux/bitmap.h>
> #include <linux/bug.h>
> #include <mach/gpio.h>
>
> #include "pinctrl-qcom.h"
>
> +#define MSM_PINCTRL_MAX_PINS 256
> +
> struct msm_pinctrl_priv {
> phys_addr_t base;
> struct msm_pinctrl_data *data;
> + DECLARE_BITMAP(reserved_map, MSM_PINCTRL_MAX_PINS);
> };
>
> #define GPIO_CONFIG_REG(priv, x) \
> @@ -71,13 +75,60 @@ 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);
> + ofnode node = dev_ofnode(dev);
> + int ret, count, i;
> + u32 *ranges;
> +
> + if (ofnode_read_prop(node, "gpio-reserved-ranges", &count)) {
> + if (count % 2 == 1) {
> + dev_err(dev, "gpio-reserved-ranges must be a multiple of 2\n");
> + return -EINVAL;
> + }
> +
> + ranges = malloc(count);
> + if (!ranges)
> + return -ENOMEM;
> +
> + ret = ofnode_read_u32_array(node, "gpio-reserved-ranges", ranges, count / 4);
> + if (ret) {
> + dev_err(dev, "failed to read gpio-reserved-ranges array (%d)\n", ret);
> + return ret;
> + }
> +
> + for (i = 0; i < count / 4; i += 2) {
> + if (ranges[i] >= MSM_PINCTRL_MAX_PINS ||
> + (ranges[i] + ranges[i + 1]) >= MSM_PINCTRL_MAX_PINS) {
> + dev_err(dev, "invalid reserved-range (%d;%d)\n",
> + ranges[i], ranges[i + 1]);
> + return -EINVAL;
> + }
> +
> + bitmap_set(priv->reserved_map, ranges[i], ranges[i + 1]);
> + }
> +
> + free(ranges);
> + }
> +
> + 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;
> }
>
> @@ -97,6 +148,9 @@ static int msm_pinmux_set(struct udevice *dev, unsigned int pin_selector,
> if (func < 0)
> return func;
>
> + if (msm_pinctrl_is_reserved(dev, pin_selector))
> + return -EPERM;
> +
> /* Always NOP for special pins, assume they're in the correct state */
> if (qcom_is_special_pin(&priv->data->pin_data, pin_selector))
> return 0;
> @@ -145,6 +199,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 -EPERM;
> +
> if (qcom_is_special_pin(&priv->data->pin_data, pin_selector))
> return msm_pinconf_set_special(priv, pin_selector, param, argument);
>
> @@ -241,3 +298,13 @@ U_BOOT_DRIVER(pinctrl_qcom) = {
> .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);
> +
> + if (pin >= MSM_PINCTRL_MAX_PINS)
> + return false;
> +
> + return test_bit(pin, priv->reserved_map);
> +}
>
> ---
> base-commit: 5ca70325b64f760bf4190f206a0e88dda495e3d2
> change-id: 20250401-topic-sm8x50-pinctrl-reserved-ranges-b93cad6cafb3
>
> Best regards,
> --
> Neil Armstrong <neil.armstrong at linaro.org>
>
More information about the U-Boot
mailing list