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