xref: /optee_os/core/drivers/pl061_gpio.c (revision ce72d0c6f7525ad81180e13d03660b83041d9eb6)
1*ce72d0c6SVictor Chong /*
2*ce72d0c6SVictor Chong  * Copyright (c) 2016, Linaro Limited
3*ce72d0c6SVictor Chong  * All rights reserved.
4*ce72d0c6SVictor Chong  *
5*ce72d0c6SVictor Chong  * Redistribution and use in source and binary forms, with or without
6*ce72d0c6SVictor Chong  * modification, are permitted provided that the following conditions are met:
7*ce72d0c6SVictor Chong  *
8*ce72d0c6SVictor Chong  * 1. Redistributions of source code must retain the above copyright notice,
9*ce72d0c6SVictor Chong  * this list of conditions and the following disclaimer.
10*ce72d0c6SVictor Chong  *
11*ce72d0c6SVictor Chong  * 2. Redistributions in binary form must reproduce the above copyright notice,
12*ce72d0c6SVictor Chong  * this list of conditions and the following disclaimer in the documentation
13*ce72d0c6SVictor Chong  * and/or other materials provided with the distribution.
14*ce72d0c6SVictor Chong  *
15*ce72d0c6SVictor Chong  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16*ce72d0c6SVictor Chong  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*ce72d0c6SVictor Chong  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*ce72d0c6SVictor Chong  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19*ce72d0c6SVictor Chong  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20*ce72d0c6SVictor Chong  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21*ce72d0c6SVictor Chong  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22*ce72d0c6SVictor Chong  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23*ce72d0c6SVictor Chong  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24*ce72d0c6SVictor Chong  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25*ce72d0c6SVictor Chong  * POSSIBILITY OF SUCH DAMAGE.
26*ce72d0c6SVictor Chong  */
27*ce72d0c6SVictor Chong 
28*ce72d0c6SVictor Chong #include <assert.h>
29*ce72d0c6SVictor Chong #include <trace.h>
30*ce72d0c6SVictor Chong #include <gpio.h>
31*ce72d0c6SVictor Chong #include <io.h>
32*ce72d0c6SVictor Chong #include <util.h>
33*ce72d0c6SVictor Chong #include <drivers/pl061_gpio.h>
34*ce72d0c6SVictor Chong 
35*ce72d0c6SVictor Chong #ifndef PLAT_PL061_MAX_GPIOS
36*ce72d0c6SVictor Chong # define PLAT_PL061_MAX_GPIOS	32
37*ce72d0c6SVictor Chong #endif	/* PLAT_PL061_MAX_GPIOS */
38*ce72d0c6SVictor Chong 
39*ce72d0c6SVictor Chong #define MAX_GPIO_DEVICES	((PLAT_PL061_MAX_GPIOS + \
40*ce72d0c6SVictor Chong 	(GPIOS_PER_PL061 - 1)) / GPIOS_PER_PL061)
41*ce72d0c6SVictor Chong 
42*ce72d0c6SVictor Chong #define PL061_GPIO_DIR		0x400
43*ce72d0c6SVictor Chong 
44*ce72d0c6SVictor Chong #define GPIOS_PER_PL061		8
45*ce72d0c6SVictor Chong 
46*ce72d0c6SVictor Chong static enum gpio_dir pl061_get_direction(unsigned int gpio_pin);
47*ce72d0c6SVictor Chong static void pl061_set_direction(unsigned int gpio_pin, enum gpio_dir direction);
48*ce72d0c6SVictor Chong static enum gpio_level pl061_get_value(unsigned int gpio_pin);
49*ce72d0c6SVictor Chong static void pl061_set_value(unsigned int gpio_pin, enum gpio_level value);
50*ce72d0c6SVictor Chong 
51*ce72d0c6SVictor Chong static vaddr_t pl061_reg_base[MAX_GPIO_DEVICES];
52*ce72d0c6SVictor Chong 
53*ce72d0c6SVictor Chong static const struct gpio_ops pl061_gpio_ops = {
54*ce72d0c6SVictor Chong 	.get_direction	= pl061_get_direction,
55*ce72d0c6SVictor Chong 	.set_direction	= pl061_set_direction,
56*ce72d0c6SVictor Chong 	.get_value	= pl061_get_value,
57*ce72d0c6SVictor Chong 	.set_value	= pl061_set_value,
58*ce72d0c6SVictor Chong };
59*ce72d0c6SVictor Chong 
60*ce72d0c6SVictor Chong static enum gpio_dir pl061_get_direction(unsigned int gpio_pin)
61*ce72d0c6SVictor Chong {
62*ce72d0c6SVictor Chong 	vaddr_t base_addr;
63*ce72d0c6SVictor Chong 	uint8_t data;
64*ce72d0c6SVictor Chong 	unsigned int offset;
65*ce72d0c6SVictor Chong 
66*ce72d0c6SVictor Chong 	assert(gpio_pin < PLAT_PL061_MAX_GPIOS);
67*ce72d0c6SVictor Chong 
68*ce72d0c6SVictor Chong 	base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061];
69*ce72d0c6SVictor Chong 	offset = gpio_pin % GPIOS_PER_PL061;
70*ce72d0c6SVictor Chong 	data = read8(base_addr + PL061_GPIO_DIR);
71*ce72d0c6SVictor Chong 	if (data & BIT(offset))
72*ce72d0c6SVictor Chong 		return GPIO_DIR_OUT;
73*ce72d0c6SVictor Chong 	return GPIO_DIR_IN;
74*ce72d0c6SVictor Chong }
75*ce72d0c6SVictor Chong 
76*ce72d0c6SVictor Chong static void pl061_set_direction(unsigned int gpio_pin, enum gpio_dir direction)
77*ce72d0c6SVictor Chong {
78*ce72d0c6SVictor Chong 	vaddr_t base_addr;
79*ce72d0c6SVictor Chong 	uint8_t data;
80*ce72d0c6SVictor Chong 	unsigned int offset;
81*ce72d0c6SVictor Chong 
82*ce72d0c6SVictor Chong 	assert(gpio_pin < PLAT_PL061_MAX_GPIOS);
83*ce72d0c6SVictor Chong 
84*ce72d0c6SVictor Chong 	base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061];
85*ce72d0c6SVictor Chong 	offset = gpio_pin % GPIOS_PER_PL061;
86*ce72d0c6SVictor Chong 	if (direction == GPIO_DIR_OUT) {
87*ce72d0c6SVictor Chong 		data = read8(base_addr + PL061_GPIO_DIR) | BIT(offset);
88*ce72d0c6SVictor Chong 		write8(base_addr + PL061_GPIO_DIR, data);
89*ce72d0c6SVictor Chong 	} else {
90*ce72d0c6SVictor Chong 		data = read8(base_addr + PL061_GPIO_DIR) & ~BIT(offset);
91*ce72d0c6SVictor Chong 		write8(base_addr + PL061_GPIO_DIR, data);
92*ce72d0c6SVictor Chong 	}
93*ce72d0c6SVictor Chong }
94*ce72d0c6SVictor Chong 
95*ce72d0c6SVictor Chong /*
96*ce72d0c6SVictor Chong  * The offset of GPIODATA register is 0.
97*ce72d0c6SVictor Chong  * The values read from GPIODATA are determined for each bit, by the mask bit
98*ce72d0c6SVictor Chong  * derived from the address used to access the data register, PADDR[9:2].
99*ce72d0c6SVictor Chong  * Bits that are 1 in the address mask cause the corresponding bits in GPIODATA
100*ce72d0c6SVictor Chong  * to be read, and bits that are 0 in the address mask cause the corresponding
101*ce72d0c6SVictor Chong  * bits in GPIODATA to be read as 0, regardless of their value.
102*ce72d0c6SVictor Chong  */
103*ce72d0c6SVictor Chong static enum gpio_level pl061_get_value(unsigned int gpio_pin)
104*ce72d0c6SVictor Chong {
105*ce72d0c6SVictor Chong 	vaddr_t base_addr;
106*ce72d0c6SVictor Chong 	unsigned int offset;
107*ce72d0c6SVictor Chong 
108*ce72d0c6SVictor Chong 	assert(gpio_pin < PLAT_PL061_MAX_GPIOS);
109*ce72d0c6SVictor Chong 
110*ce72d0c6SVictor Chong 	base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061];
111*ce72d0c6SVictor Chong 	offset = gpio_pin % GPIOS_PER_PL061;
112*ce72d0c6SVictor Chong 	if (read8(base_addr + BIT(offset + 2)))
113*ce72d0c6SVictor Chong 		return GPIO_LEVEL_HIGH;
114*ce72d0c6SVictor Chong 	return GPIO_LEVEL_LOW;
115*ce72d0c6SVictor Chong }
116*ce72d0c6SVictor Chong 
117*ce72d0c6SVictor Chong /*
118*ce72d0c6SVictor Chong  * In order to write GPIODATA, the corresponding bits in the mask, resulting
119*ce72d0c6SVictor Chong  * from the address bus, PADDR[9:2], must be HIGH. Otherwise the bit values
120*ce72d0c6SVictor Chong  * remain unchanged by the write.
121*ce72d0c6SVictor Chong  */
122*ce72d0c6SVictor Chong static void pl061_set_value(unsigned int gpio_pin, enum gpio_level value)
123*ce72d0c6SVictor Chong {
124*ce72d0c6SVictor Chong 	vaddr_t base_addr;
125*ce72d0c6SVictor Chong 	unsigned int offset;
126*ce72d0c6SVictor Chong 
127*ce72d0c6SVictor Chong 	assert(gpio_pin < PLAT_PL061_MAX_GPIOS);
128*ce72d0c6SVictor Chong 
129*ce72d0c6SVictor Chong 	base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061];
130*ce72d0c6SVictor Chong 	offset = gpio_pin % GPIOS_PER_PL061;
131*ce72d0c6SVictor Chong 	if (value == GPIO_LEVEL_HIGH)
132*ce72d0c6SVictor Chong 		write8(base_addr + BIT(offset + 2), BIT(offset));
133*ce72d0c6SVictor Chong 	else
134*ce72d0c6SVictor Chong 		write8(base_addr + BIT(offset + 2), 0);
135*ce72d0c6SVictor Chong }
136*ce72d0c6SVictor Chong 
137*ce72d0c6SVictor Chong 
138*ce72d0c6SVictor Chong /*
139*ce72d0c6SVictor Chong  * Register the PL061 GPIO controller with a base address and the offset
140*ce72d0c6SVictor Chong  * of start pin in this GPIO controller.
141*ce72d0c6SVictor Chong  * This function is called after pl061_gpio_ops_init().
142*ce72d0c6SVictor Chong  */
143*ce72d0c6SVictor Chong void pl061_gpio_register(vaddr_t base_addr, unsigned int gpio_dev)
144*ce72d0c6SVictor Chong {
145*ce72d0c6SVictor Chong 	assert(gpio_dev < MAX_GPIO_DEVICES);
146*ce72d0c6SVictor Chong 
147*ce72d0c6SVictor Chong 	pl061_reg_base[gpio_dev] = base_addr;
148*ce72d0c6SVictor Chong }
149*ce72d0c6SVictor Chong 
150*ce72d0c6SVictor Chong /*
151*ce72d0c6SVictor Chong  * Initialize PL061 GPIO controller with the total GPIO numbers in SoC.
152*ce72d0c6SVictor Chong  */
153*ce72d0c6SVictor Chong void pl061_gpio_init(void)
154*ce72d0c6SVictor Chong {
155*ce72d0c6SVictor Chong 	COMPILE_TIME_ASSERT(PLAT_PL061_MAX_GPIOS > 0);
156*ce72d0c6SVictor Chong 	gpio_init(&pl061_gpio_ops);
157*ce72d0c6SVictor Chong }
158