Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 726cb3ba authored by Stephen Boyd's avatar Stephen Boyd Committed by Linus Walleij
Browse files

gpiolib: Support 'gpio-reserved-ranges' property



Some qcom platforms make some GPIOs or pins unavailable for use by
non-secure operating systems, and thus reading or writing the registers
for those pins will cause access control issues. Add support for a DT
property to describe the set of GPIOs that are available for use so that
higher level OSes are able to know what pins to avoid reading/writing.
Non-DT platforms can add support by directly updating the
chip->valid_mask.

Signed-off-by: default avatarStephen Boyd <sboyd@codeaurora.org>
Signed-off-by: default avatarStephen Boyd <swboyd@chromium.org>
Tested-by: default avatarTimur Tabi <timur@codeaurora.org>
Reviewed-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent ace56935
Loading
Loading
Loading
Loading
+24 −0
Original line number Original line Diff line number Diff line
@@ -511,6 +511,28 @@ void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc)
}
}
EXPORT_SYMBOL(of_mm_gpiochip_remove);
EXPORT_SYMBOL(of_mm_gpiochip_remove);


static void of_gpiochip_init_valid_mask(struct gpio_chip *chip)
{
	int len, i;
	u32 start, count;
	struct device_node *np = chip->of_node;

	len = of_property_count_u32_elems(np,  "gpio-reserved-ranges");
	if (len < 0 || len % 2 != 0)
		return;

	for (i = 0; i < len; i += 2) {
		of_property_read_u32_index(np, "gpio-reserved-ranges",
					   i, &start);
		of_property_read_u32_index(np, "gpio-reserved-ranges",
					   i + 1, &count);
		if (start >= chip->ngpio || start + count >= chip->ngpio)
			continue;

		bitmap_clear(chip->valid_mask, start, count);
	}
};

#ifdef CONFIG_PINCTRL
#ifdef CONFIG_PINCTRL
static int of_gpiochip_add_pin_range(struct gpio_chip *chip)
static int of_gpiochip_add_pin_range(struct gpio_chip *chip)
{
{
@@ -615,6 +637,8 @@ int of_gpiochip_add(struct gpio_chip *chip)
	if (chip->of_gpio_n_cells > MAX_PHANDLE_ARGS)
	if (chip->of_gpio_n_cells > MAX_PHANDLE_ARGS)
		return -EINVAL;
		return -EINVAL;


	of_gpiochip_init_valid_mask(chip);

	status = of_gpiochip_add_pin_range(chip);
	status = of_gpiochip_add_pin_range(chip);
	if (status)
	if (status)
		return status;
		return status;
+46 −0
Original line number Original line Diff line number Diff line
@@ -351,6 +351,43 @@ static unsigned long *gpiochip_allocate_mask(struct gpio_chip *chip)
	return p;
	return p;
}
}


static int gpiochip_init_valid_mask(struct gpio_chip *gpiochip)
{
#ifdef CONFIG_OF_GPIO
	int size;
	struct device_node *np = gpiochip->of_node;

	size = of_property_count_u32_elems(np,  "gpio-reserved-ranges");
	if (size > 0 && size % 2 == 0)
		gpiochip->need_valid_mask = true;
#endif

	if (!gpiochip->need_valid_mask)
		return 0;

	gpiochip->valid_mask = gpiochip_allocate_mask(gpiochip);
	if (!gpiochip->valid_mask)
		return -ENOMEM;

	return 0;
}

static void gpiochip_free_valid_mask(struct gpio_chip *gpiochip)
{
	kfree(gpiochip->valid_mask);
	gpiochip->valid_mask = NULL;
}

bool gpiochip_line_is_valid(const struct gpio_chip *gpiochip,
				unsigned int offset)
{
	/* No mask means all valid */
	if (likely(!gpiochip->valid_mask))
		return true;
	return test_bit(offset, gpiochip->valid_mask);
}
EXPORT_SYMBOL_GPL(gpiochip_line_is_valid);

/*
/*
 * GPIO line handle management
 * GPIO line handle management
 */
 */
@@ -1275,6 +1312,10 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
	if (status)
	if (status)
		goto err_remove_from_list;
		goto err_remove_from_list;


	status = gpiochip_init_valid_mask(chip);
	if (status)
		goto err_remove_irqchip_mask;

	status = gpiochip_add_irqchip(chip, lock_key, request_key);
	status = gpiochip_add_irqchip(chip, lock_key, request_key);
	if (status)
	if (status)
		goto err_remove_chip;
		goto err_remove_chip;
@@ -1304,6 +1345,8 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
	acpi_gpiochip_remove(chip);
	acpi_gpiochip_remove(chip);
	gpiochip_free_hogs(chip);
	gpiochip_free_hogs(chip);
	of_gpiochip_remove(chip);
	of_gpiochip_remove(chip);
	gpiochip_free_valid_mask(chip);
err_remove_irqchip_mask:
	gpiochip_irqchip_free_valid_mask(chip);
	gpiochip_irqchip_free_valid_mask(chip);
err_remove_from_list:
err_remove_from_list:
	spin_lock_irqsave(&gpio_lock, flags);
	spin_lock_irqsave(&gpio_lock, flags);
@@ -1360,6 +1403,7 @@ void gpiochip_remove(struct gpio_chip *chip)
	acpi_gpiochip_remove(chip);
	acpi_gpiochip_remove(chip);
	gpiochip_remove_pin_ranges(chip);
	gpiochip_remove_pin_ranges(chip);
	of_gpiochip_remove(chip);
	of_gpiochip_remove(chip);
	gpiochip_free_valid_mask(chip);
	/*
	/*
	 * We accept no more calls into the driver from this point, so
	 * We accept no more calls into the driver from this point, so
	 * NULL the driver data pointer
	 * NULL the driver data pointer
@@ -1536,6 +1580,8 @@ static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip)
bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
				unsigned int offset)
				unsigned int offset)
{
{
	if (!gpiochip_line_is_valid(gpiochip, offset))
		return false;
	/* No mask means all valid */
	/* No mask means all valid */
	if (likely(!gpiochip->irq.valid_mask))
	if (likely(!gpiochip->irq.valid_mask))
		return true;
		return true;
+16 −0
Original line number Original line Diff line number Diff line
@@ -288,6 +288,21 @@ struct gpio_chip {
	struct gpio_irq_chip irq;
	struct gpio_irq_chip irq;
#endif
#endif


	/**
	 * @need_valid_mask:
	 *
	 * If set core allocates @valid_mask with all bits set to one.
	 */
	bool need_valid_mask;

	/**
	 * @valid_mask:
	 *
	 * If not %NULL holds bitmask of GPIOs which are valid to be used
	 * from the chip.
	 */
	unsigned long *valid_mask;

#if defined(CONFIG_OF_GPIO)
#if defined(CONFIG_OF_GPIO)
	/*
	/*
	 * If CONFIG_OF is enabled, then all GPIO controllers described in the
	 * If CONFIG_OF is enabled, then all GPIO controllers described in the
@@ -384,6 +399,7 @@ bool gpiochip_line_is_open_source(struct gpio_chip *chip, unsigned int offset);


/* Sleep persistence inquiry for drivers */
/* Sleep persistence inquiry for drivers */
bool gpiochip_line_is_persistent(struct gpio_chip *chip, unsigned int offset);
bool gpiochip_line_is_persistent(struct gpio_chip *chip, unsigned int offset);
bool gpiochip_line_is_valid(const struct gpio_chip *chip, unsigned int offset);


/* get driver data */
/* get driver data */
void *gpiochip_get_data(struct gpio_chip *chip);
void *gpiochip_get_data(struct gpio_chip *chip);