[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