xref: /optee_os/core/drivers/ls_gpio.c (revision bce2f88ab347b28f4149dacef2ad48ac67a500b6)
116c13b4dSManish Tomar // SPDX-License-Identifier: BSD-2-Clause
216c13b4dSManish Tomar /*
316c13b4dSManish Tomar  * Copyright 2021 NXP
416c13b4dSManish Tomar  *
516c13b4dSManish Tomar  * Driver for GPIO Controller
616c13b4dSManish Tomar  *
716c13b4dSManish Tomar  */
816c13b4dSManish Tomar 
916c13b4dSManish Tomar #include <assert.h>
1016c13b4dSManish Tomar #include <drivers/ls_gpio.h>
1116c13b4dSManish Tomar #include <io.h>
1216c13b4dSManish Tomar #include <kernel/boot.h>
1316c13b4dSManish Tomar #include <kernel/dt.h>
1416c13b4dSManish Tomar #include <libfdt.h>
1516c13b4dSManish Tomar #include <mm/core_memprot.h>
1616c13b4dSManish Tomar 
1716c13b4dSManish Tomar static const char * const gpio_controller_map[] = {
1816c13b4dSManish Tomar 	 "/soc/gpio@2300000",
1916c13b4dSManish Tomar 	 "/soc/gpio@2310000",
2016c13b4dSManish Tomar 	 "/soc/gpio@2320000",
2116c13b4dSManish Tomar 	 "/soc/gpio@2330000"
2216c13b4dSManish Tomar };
2316c13b4dSManish Tomar 
2416c13b4dSManish Tomar /*
2516c13b4dSManish Tomar  * Get value from GPIO controller
2616c13b4dSManish Tomar  * chip:        pointer to GPIO controller chip instance
2716c13b4dSManish Tomar  * gpio_pin:    pin from which value needs to be read
2816c13b4dSManish Tomar  */
ls_gpio_get_value(struct gpio_chip * chip,unsigned int gpio_pin)294bb7a11eSClément Léger static enum gpio_level ls_gpio_get_value(struct gpio_chip *chip,
3016c13b4dSManish Tomar 					 unsigned int gpio_pin)
3116c13b4dSManish Tomar {
3216c13b4dSManish Tomar 	vaddr_t gpio_data_addr = 0;
3316c13b4dSManish Tomar 	uint32_t data = 0;
3416c13b4dSManish Tomar 	struct ls_gpio_chip_data *gc_data = container_of(chip,
3516c13b4dSManish Tomar 						      struct ls_gpio_chip_data,
3616c13b4dSManish Tomar 						      chip);
3716c13b4dSManish Tomar 
3816c13b4dSManish Tomar 	assert(gpio_pin <= MAX_GPIO_PINS);
3916c13b4dSManish Tomar 
4016c13b4dSManish Tomar 	gpio_data_addr = gc_data->gpio_base + GPIODAT;
4116c13b4dSManish Tomar 	data = io_read32(gpio_data_addr);
4216c13b4dSManish Tomar 
4316c13b4dSManish Tomar 	if (data & PIN_SHIFT(gpio_pin))
4416c13b4dSManish Tomar 		return GPIO_LEVEL_HIGH;
4516c13b4dSManish Tomar 	else
4616c13b4dSManish Tomar 		return GPIO_LEVEL_LOW;
4716c13b4dSManish Tomar }
4816c13b4dSManish Tomar 
4916c13b4dSManish Tomar /*
5016c13b4dSManish Tomar  * Set value for GPIO controller
5116c13b4dSManish Tomar  * chip:        pointer to GPIO controller chip instance
5216c13b4dSManish Tomar  * gpio_pin:    pin to which value needs to be write
5316c13b4dSManish Tomar  * value:       value needs to be written to the pin
5416c13b4dSManish Tomar  */
ls_gpio_set_value(struct gpio_chip * chip,unsigned int gpio_pin,enum gpio_level value)554bb7a11eSClément Léger static void ls_gpio_set_value(struct gpio_chip *chip, unsigned int gpio_pin,
5616c13b4dSManish Tomar 			      enum gpio_level value)
5716c13b4dSManish Tomar {
5816c13b4dSManish Tomar 	vaddr_t gpio_data_addr = 0;
5916c13b4dSManish Tomar 	struct ls_gpio_chip_data *gc_data = container_of(chip,
6016c13b4dSManish Tomar 						      struct ls_gpio_chip_data,
6116c13b4dSManish Tomar 						      chip);
6216c13b4dSManish Tomar 
6316c13b4dSManish Tomar 	assert(gpio_pin <= MAX_GPIO_PINS);
6416c13b4dSManish Tomar 
6516c13b4dSManish Tomar 	gpio_data_addr = gc_data->gpio_base + GPIODAT;
6616c13b4dSManish Tomar 
6716c13b4dSManish Tomar 	if (value == GPIO_LEVEL_HIGH)
6816c13b4dSManish Tomar 		/* if value is high then set pin value */
6916c13b4dSManish Tomar 		io_setbits32(gpio_data_addr, PIN_SHIFT(gpio_pin));
7016c13b4dSManish Tomar 	else
7116c13b4dSManish Tomar 		/* if value is low then clear pin value */
7216c13b4dSManish Tomar 		io_clrbits32(gpio_data_addr, PIN_SHIFT(gpio_pin));
7316c13b4dSManish Tomar }
7416c13b4dSManish Tomar 
7516c13b4dSManish Tomar /*
7616c13b4dSManish Tomar  * Get direction from GPIO controller
7716c13b4dSManish Tomar  * chip:        pointer to GPIO controller chip instance
7816c13b4dSManish Tomar  * gpio_pin:    pin from which direction needs to be read
7916c13b4dSManish Tomar  */
ls_gpio_get_direction(struct gpio_chip * chip,unsigned int gpio_pin)804bb7a11eSClément Léger static enum gpio_dir ls_gpio_get_direction(struct gpio_chip *chip,
8116c13b4dSManish Tomar 					   unsigned int gpio_pin)
8216c13b4dSManish Tomar {
8316c13b4dSManish Tomar 	vaddr_t gpio_dir_addr = 0;
8416c13b4dSManish Tomar 	uint32_t data = 0;
8516c13b4dSManish Tomar 	struct ls_gpio_chip_data *gc_data = container_of(chip,
8616c13b4dSManish Tomar 						      struct ls_gpio_chip_data,
8716c13b4dSManish Tomar 						      chip);
8816c13b4dSManish Tomar 
8916c13b4dSManish Tomar 	assert(gpio_pin <= MAX_GPIO_PINS);
9016c13b4dSManish Tomar 
9116c13b4dSManish Tomar 	gpio_dir_addr = gc_data->gpio_base + GPIODIR;
9216c13b4dSManish Tomar 	data = io_read32(gpio_dir_addr);
9316c13b4dSManish Tomar 
9416c13b4dSManish Tomar 	if (data & PIN_SHIFT(gpio_pin))
9516c13b4dSManish Tomar 		return GPIO_DIR_OUT;
9616c13b4dSManish Tomar 	else
9716c13b4dSManish Tomar 		return GPIO_DIR_IN;
9816c13b4dSManish Tomar }
9916c13b4dSManish Tomar 
10016c13b4dSManish Tomar /*
10116c13b4dSManish Tomar  * Set direction for GPIO controller
10216c13b4dSManish Tomar  * chip:        pointer to GPIO controller chip instance
10316c13b4dSManish Tomar  * gpio_pin:    pin on which direction needs to be set
10416c13b4dSManish Tomar  * direction:   direction which needs to be set on pin
10516c13b4dSManish Tomar  */
ls_gpio_set_direction(struct gpio_chip * chip,unsigned int gpio_pin,enum gpio_dir direction)1064bb7a11eSClément Léger static void ls_gpio_set_direction(struct gpio_chip *chip, unsigned int gpio_pin,
10716c13b4dSManish Tomar 				  enum gpio_dir direction)
10816c13b4dSManish Tomar {
10916c13b4dSManish Tomar 	vaddr_t gpio_dir_addr = 0;
11016c13b4dSManish Tomar 	struct ls_gpio_chip_data *gc_data = container_of(chip,
11116c13b4dSManish Tomar 						      struct ls_gpio_chip_data,
11216c13b4dSManish Tomar 						      chip);
11316c13b4dSManish Tomar 
11416c13b4dSManish Tomar 	assert(gpio_pin <= MAX_GPIO_PINS);
11516c13b4dSManish Tomar 
11616c13b4dSManish Tomar 	gpio_dir_addr = gc_data->gpio_base + GPIODIR;
11716c13b4dSManish Tomar 
11816c13b4dSManish Tomar 	if (direction == GPIO_DIR_OUT)
11916c13b4dSManish Tomar 		io_setbits32(gpio_dir_addr, PIN_SHIFT(gpio_pin));
12016c13b4dSManish Tomar 	else
12116c13b4dSManish Tomar 		io_clrbits32(gpio_dir_addr, PIN_SHIFT(gpio_pin));
12216c13b4dSManish Tomar }
12316c13b4dSManish Tomar 
12416c13b4dSManish Tomar /*
12516c13b4dSManish Tomar  * Get interrupt from GPIO controller
12616c13b4dSManish Tomar  * chip:        pointer to GPIO controller chip instance
12716c13b4dSManish Tomar  * gpio_pin:    pin from which interrupt value needs to be read
12816c13b4dSManish Tomar  */
gpio_get_interrupt(struct gpio_chip * chip,unsigned int gpio_pin)12916c13b4dSManish Tomar static enum gpio_interrupt gpio_get_interrupt(struct gpio_chip *chip,
13016c13b4dSManish Tomar 					      unsigned int gpio_pin)
13116c13b4dSManish Tomar {
13216c13b4dSManish Tomar 	vaddr_t gpio_ier_addr = 0;
13316c13b4dSManish Tomar 	uint32_t data = 0;
13416c13b4dSManish Tomar 	struct ls_gpio_chip_data *gc_data = container_of(chip,
13516c13b4dSManish Tomar 						      struct ls_gpio_chip_data,
13616c13b4dSManish Tomar 						      chip);
13716c13b4dSManish Tomar 
13816c13b4dSManish Tomar 	assert(gpio_pin <= MAX_GPIO_PINS);
13916c13b4dSManish Tomar 
14016c13b4dSManish Tomar 	gpio_ier_addr = gc_data->gpio_base + GPIOIER;
14116c13b4dSManish Tomar 	data = io_read32(gpio_ier_addr);
14216c13b4dSManish Tomar 
14316c13b4dSManish Tomar 	if (data & PIN_SHIFT(gpio_pin))
14416c13b4dSManish Tomar 		return GPIO_INTERRUPT_ENABLE;
14516c13b4dSManish Tomar 	else
14616c13b4dSManish Tomar 		return GPIO_INTERRUPT_DISABLE;
14716c13b4dSManish Tomar }
14816c13b4dSManish Tomar 
14916c13b4dSManish Tomar /*
15016c13b4dSManish Tomar  * Set interrupt event for GPIO controller
15116c13b4dSManish Tomar  * chip:        pointer to GPIO controller chip instance
15216c13b4dSManish Tomar  * gpio_pin:    pin on which interrupt value needs to be set
15316c13b4dSManish Tomar  * interrupt:   interrupt valie which needs to be set on pin
15416c13b4dSManish Tomar  */
gpio_set_interrupt(struct gpio_chip * chip,unsigned int gpio_pin,enum gpio_interrupt interrupt)15516c13b4dSManish Tomar static void gpio_set_interrupt(struct gpio_chip *chip, unsigned int gpio_pin,
15616c13b4dSManish Tomar 			       enum gpio_interrupt interrupt)
15716c13b4dSManish Tomar {
15816c13b4dSManish Tomar 	vaddr_t gpio_ier_addr = 0;
15916c13b4dSManish Tomar 	struct ls_gpio_chip_data *gc_data = container_of(chip,
16016c13b4dSManish Tomar 						      struct ls_gpio_chip_data,
16116c13b4dSManish Tomar 						      chip);
16216c13b4dSManish Tomar 
16316c13b4dSManish Tomar 	assert(gpio_pin <= MAX_GPIO_PINS);
16416c13b4dSManish Tomar 
16516c13b4dSManish Tomar 	gpio_ier_addr = gc_data->gpio_base + GPIOIER;
16616c13b4dSManish Tomar 
16716c13b4dSManish Tomar 	if (interrupt == GPIO_INTERRUPT_ENABLE)
16816c13b4dSManish Tomar 		io_setbits32(gpio_ier_addr, PIN_SHIFT(gpio_pin));
16916c13b4dSManish Tomar 	else
17016c13b4dSManish Tomar 		io_clrbits32(gpio_ier_addr, PIN_SHIFT(gpio_pin));
17116c13b4dSManish Tomar }
17216c13b4dSManish Tomar 
17316c13b4dSManish Tomar /*
17416c13b4dSManish Tomar  * Extract information for GPIO Controller from the DTB
17516c13b4dSManish Tomar  * gpio_data:	GPIO controller chip instance
17616c13b4dSManish Tomar  */
get_info_from_device_tree(struct ls_gpio_chip_data * gpio_data)17716c13b4dSManish Tomar static TEE_Result get_info_from_device_tree(struct ls_gpio_chip_data *gpio_data)
17816c13b4dSManish Tomar {
17916c13b4dSManish Tomar 	size_t size = 0;
18016c13b4dSManish Tomar 	int node = 0;
18116c13b4dSManish Tomar 	vaddr_t ctrl_base = 0;
18216c13b4dSManish Tomar 	void *fdt = NULL;
18316c13b4dSManish Tomar 
18416c13b4dSManish Tomar 	/*
18516c13b4dSManish Tomar 	 * First get the GPIO Controller base address from the DTB
18616c13b4dSManish Tomar 	 * if DTB present and if the GPIO Controller defined in it.
18716c13b4dSManish Tomar 	 */
18816c13b4dSManish Tomar 	fdt = get_embedded_dt();
18916c13b4dSManish Tomar 	if (!fdt) {
190*bce2f88aSVincent Mailhol 		EMSG("Unable to get the Embedded DTB, GPIO init failed");
19116c13b4dSManish Tomar 		return TEE_ERROR_GENERIC;
19216c13b4dSManish Tomar 	}
19316c13b4dSManish Tomar 
19416c13b4dSManish Tomar 	node = fdt_path_offset(fdt, gpio_controller_map
19516c13b4dSManish Tomar 			       [gpio_data->gpio_controller]);
19616c13b4dSManish Tomar 	if (node > 0) {
197a5d5bbc8SVesa Jääskeläinen 		if (dt_map_dev(fdt, node, &ctrl_base, &size,
198a5d5bbc8SVesa Jääskeläinen 			       DT_MAP_AUTO) < 0) {
19916c13b4dSManish Tomar 			EMSG("Unable to get virtual address");
20016c13b4dSManish Tomar 			return TEE_ERROR_GENERIC;
20116c13b4dSManish Tomar 		}
20216c13b4dSManish Tomar 	} else {
20316c13b4dSManish Tomar 		EMSG("Unable to get gpio offset node");
20416c13b4dSManish Tomar 		return TEE_ERROR_ITEM_NOT_FOUND;
20516c13b4dSManish Tomar 	}
20616c13b4dSManish Tomar 
20716c13b4dSManish Tomar 	gpio_data->gpio_base = ctrl_base;
20816c13b4dSManish Tomar 
20916c13b4dSManish Tomar 	return TEE_SUCCESS;
21016c13b4dSManish Tomar }
21116c13b4dSManish Tomar 
21216c13b4dSManish Tomar static const struct gpio_ops ls_gpio_ops = {
2134bb7a11eSClément Léger 	.get_direction = ls_gpio_get_direction,
2144bb7a11eSClément Léger 	.set_direction = ls_gpio_set_direction,
2154bb7a11eSClément Léger 	.get_value = ls_gpio_get_value,
2164bb7a11eSClément Léger 	.set_value = ls_gpio_set_value,
21716c13b4dSManish Tomar 	.get_interrupt = gpio_get_interrupt,
21816c13b4dSManish Tomar 	.set_interrupt = gpio_set_interrupt,
21916c13b4dSManish Tomar };
22016c13b4dSManish Tomar DECLARE_KEEP_PAGER(ls_gpio_ops);
22116c13b4dSManish Tomar 
ls_gpio_init(struct ls_gpio_chip_data * gpio_data)22216c13b4dSManish Tomar TEE_Result ls_gpio_init(struct ls_gpio_chip_data *gpio_data)
22316c13b4dSManish Tomar {
22416c13b4dSManish Tomar 	TEE_Result status = TEE_ERROR_GENERIC;
22516c13b4dSManish Tomar 
22616c13b4dSManish Tomar 	/*
22716c13b4dSManish Tomar 	 * First get the GPIO Controller base address from the DTB,
22816c13b4dSManish Tomar 	 * if DTB present and if the GPIO Controller defined in it.
22916c13b4dSManish Tomar 	 */
23016c13b4dSManish Tomar 	status = get_info_from_device_tree(gpio_data);
23116c13b4dSManish Tomar 	if (status == TEE_SUCCESS) {
23216c13b4dSManish Tomar 		/* set GPIO Input Buffer Enable register */
23316c13b4dSManish Tomar 		io_setbits32(gpio_data->gpio_base + GPIOIBE, UINT32_MAX);
23416c13b4dSManish Tomar 
23516c13b4dSManish Tomar 		/* generic GPIO chip handle */
23616c13b4dSManish Tomar 		gpio_data->chip.ops = &ls_gpio_ops;
23716c13b4dSManish Tomar 	} else {
23816c13b4dSManish Tomar 		EMSG("Unable to get info from device tree");
23916c13b4dSManish Tomar 	}
24016c13b4dSManish Tomar 
24116c13b4dSManish Tomar 	return status;
24216c13b4dSManish Tomar }
243