1*54fd6939SJiyong Park /*
2*54fd6939SJiyong Park * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
3*54fd6939SJiyong Park *
4*54fd6939SJiyong Park * SPDX-License-Identifier: BSD-3-Clause
5*54fd6939SJiyong Park *
6*54fd6939SJiyong Park * ARM PL061 GPIO Driver.
7*54fd6939SJiyong Park * Reference to ARM DDI 0190B document.
8*54fd6939SJiyong Park *
9*54fd6939SJiyong Park */
10*54fd6939SJiyong Park
11*54fd6939SJiyong Park #include <assert.h>
12*54fd6939SJiyong Park #include <errno.h>
13*54fd6939SJiyong Park
14*54fd6939SJiyong Park #include <common/debug.h>
15*54fd6939SJiyong Park #include <drivers/arm/pl061_gpio.h>
16*54fd6939SJiyong Park #include <drivers/gpio.h>
17*54fd6939SJiyong Park #include <lib/cassert.h>
18*54fd6939SJiyong Park #include <lib/mmio.h>
19*54fd6939SJiyong Park #include <lib/utils.h>
20*54fd6939SJiyong Park
21*54fd6939SJiyong Park #if !PLAT_PL061_MAX_GPIOS
22*54fd6939SJiyong Park # define PLAT_PL061_MAX_GPIOS 32
23*54fd6939SJiyong Park #endif /* PLAT_PL061_MAX_GPIOS */
24*54fd6939SJiyong Park
25*54fd6939SJiyong Park CASSERT(PLAT_PL061_MAX_GPIOS > 0, assert_plat_pl061_max_gpios);
26*54fd6939SJiyong Park
27*54fd6939SJiyong Park #define MAX_GPIO_DEVICES ((PLAT_PL061_MAX_GPIOS + \
28*54fd6939SJiyong Park (GPIOS_PER_PL061 - 1)) / GPIOS_PER_PL061)
29*54fd6939SJiyong Park
30*54fd6939SJiyong Park #define PL061_GPIO_DIR 0x400
31*54fd6939SJiyong Park
32*54fd6939SJiyong Park #define GPIOS_PER_PL061 8
33*54fd6939SJiyong Park
34*54fd6939SJiyong Park static int pl061_get_direction(int gpio);
35*54fd6939SJiyong Park static void pl061_set_direction(int gpio, int direction);
36*54fd6939SJiyong Park static int pl061_get_value(int gpio);
37*54fd6939SJiyong Park static void pl061_set_value(int gpio, int value);
38*54fd6939SJiyong Park
39*54fd6939SJiyong Park static uintptr_t pl061_reg_base[MAX_GPIO_DEVICES];
40*54fd6939SJiyong Park
41*54fd6939SJiyong Park static const gpio_ops_t pl061_gpio_ops = {
42*54fd6939SJiyong Park .get_direction = pl061_get_direction,
43*54fd6939SJiyong Park .set_direction = pl061_set_direction,
44*54fd6939SJiyong Park .get_value = pl061_get_value,
45*54fd6939SJiyong Park .set_value = pl061_set_value,
46*54fd6939SJiyong Park };
47*54fd6939SJiyong Park
pl061_get_direction(int gpio)48*54fd6939SJiyong Park static int pl061_get_direction(int gpio)
49*54fd6939SJiyong Park {
50*54fd6939SJiyong Park uintptr_t base_addr;
51*54fd6939SJiyong Park unsigned int data, offset;
52*54fd6939SJiyong Park
53*54fd6939SJiyong Park assert((gpio >= 0) && (gpio < PLAT_PL061_MAX_GPIOS));
54*54fd6939SJiyong Park
55*54fd6939SJiyong Park base_addr = pl061_reg_base[gpio / GPIOS_PER_PL061];
56*54fd6939SJiyong Park offset = gpio % GPIOS_PER_PL061;
57*54fd6939SJiyong Park data = mmio_read_8(base_addr + PL061_GPIO_DIR);
58*54fd6939SJiyong Park if (data & BIT(offset))
59*54fd6939SJiyong Park return GPIO_DIR_OUT;
60*54fd6939SJiyong Park return GPIO_DIR_IN;
61*54fd6939SJiyong Park }
62*54fd6939SJiyong Park
pl061_set_direction(int gpio,int direction)63*54fd6939SJiyong Park static void pl061_set_direction(int gpio, int direction)
64*54fd6939SJiyong Park {
65*54fd6939SJiyong Park uintptr_t base_addr;
66*54fd6939SJiyong Park unsigned int data, offset;
67*54fd6939SJiyong Park
68*54fd6939SJiyong Park assert((gpio >= 0) && (gpio < PLAT_PL061_MAX_GPIOS));
69*54fd6939SJiyong Park
70*54fd6939SJiyong Park base_addr = pl061_reg_base[gpio / GPIOS_PER_PL061];
71*54fd6939SJiyong Park offset = gpio % GPIOS_PER_PL061;
72*54fd6939SJiyong Park if (direction == GPIO_DIR_OUT) {
73*54fd6939SJiyong Park data = mmio_read_8(base_addr + PL061_GPIO_DIR) | BIT(offset);
74*54fd6939SJiyong Park mmio_write_8(base_addr + PL061_GPIO_DIR, data);
75*54fd6939SJiyong Park } else {
76*54fd6939SJiyong Park data = mmio_read_8(base_addr + PL061_GPIO_DIR) & ~BIT(offset);
77*54fd6939SJiyong Park mmio_write_8(base_addr + PL061_GPIO_DIR, data);
78*54fd6939SJiyong Park }
79*54fd6939SJiyong Park }
80*54fd6939SJiyong Park
81*54fd6939SJiyong Park /*
82*54fd6939SJiyong Park * The offset of GPIODATA register is 0.
83*54fd6939SJiyong Park * The values read from GPIODATA are determined for each bit, by the mask bit
84*54fd6939SJiyong Park * derived from the address used to access the data register, PADDR[9:2].
85*54fd6939SJiyong Park * Bits that are 1 in the address mask cause the corresponding bits in GPIODATA
86*54fd6939SJiyong Park * to be read, and bits that are 0 in the address mask cause the corresponding
87*54fd6939SJiyong Park * bits in GPIODATA to be read as 0, regardless of their value.
88*54fd6939SJiyong Park */
pl061_get_value(int gpio)89*54fd6939SJiyong Park static int pl061_get_value(int gpio)
90*54fd6939SJiyong Park {
91*54fd6939SJiyong Park uintptr_t base_addr;
92*54fd6939SJiyong Park unsigned int offset;
93*54fd6939SJiyong Park
94*54fd6939SJiyong Park assert((gpio >= 0) && (gpio < PLAT_PL061_MAX_GPIOS));
95*54fd6939SJiyong Park
96*54fd6939SJiyong Park base_addr = pl061_reg_base[gpio / GPIOS_PER_PL061];
97*54fd6939SJiyong Park offset = gpio % GPIOS_PER_PL061;
98*54fd6939SJiyong Park if (mmio_read_8(base_addr + BIT(offset + 2)))
99*54fd6939SJiyong Park return GPIO_LEVEL_HIGH;
100*54fd6939SJiyong Park return GPIO_LEVEL_LOW;
101*54fd6939SJiyong Park }
102*54fd6939SJiyong Park
103*54fd6939SJiyong Park /*
104*54fd6939SJiyong Park * In order to write GPIODATA, the corresponding bits in the mask, resulting
105*54fd6939SJiyong Park * from the address bus, PADDR[9:2], must be HIGH. Otherwise the bit values
106*54fd6939SJiyong Park * remain unchanged by the write.
107*54fd6939SJiyong Park */
pl061_set_value(int gpio,int value)108*54fd6939SJiyong Park static void pl061_set_value(int gpio, int value)
109*54fd6939SJiyong Park {
110*54fd6939SJiyong Park uintptr_t base_addr;
111*54fd6939SJiyong Park int offset;
112*54fd6939SJiyong Park
113*54fd6939SJiyong Park assert((gpio >= 0) && (gpio < PLAT_PL061_MAX_GPIOS));
114*54fd6939SJiyong Park
115*54fd6939SJiyong Park base_addr = pl061_reg_base[gpio / GPIOS_PER_PL061];
116*54fd6939SJiyong Park offset = gpio % GPIOS_PER_PL061;
117*54fd6939SJiyong Park if (value == GPIO_LEVEL_HIGH)
118*54fd6939SJiyong Park mmio_write_8(base_addr + BIT(offset + 2), BIT(offset));
119*54fd6939SJiyong Park else
120*54fd6939SJiyong Park mmio_write_8(base_addr + BIT(offset + 2), 0);
121*54fd6939SJiyong Park }
122*54fd6939SJiyong Park
123*54fd6939SJiyong Park
124*54fd6939SJiyong Park /*
125*54fd6939SJiyong Park * Register the PL061 GPIO controller with a base address and the offset
126*54fd6939SJiyong Park * of start pin in this GPIO controller.
127*54fd6939SJiyong Park * This function is called after pl061_gpio_ops_init().
128*54fd6939SJiyong Park */
pl061_gpio_register(uintptr_t base_addr,int gpio_dev)129*54fd6939SJiyong Park void pl061_gpio_register(uintptr_t base_addr, int gpio_dev)
130*54fd6939SJiyong Park {
131*54fd6939SJiyong Park assert((gpio_dev >= 0) && (gpio_dev < MAX_GPIO_DEVICES));
132*54fd6939SJiyong Park
133*54fd6939SJiyong Park pl061_reg_base[gpio_dev] = base_addr;
134*54fd6939SJiyong Park }
135*54fd6939SJiyong Park
136*54fd6939SJiyong Park /*
137*54fd6939SJiyong Park * Initialize PL061 GPIO controller with the total GPIO numbers in SoC.
138*54fd6939SJiyong Park */
pl061_gpio_init(void)139*54fd6939SJiyong Park void pl061_gpio_init(void)
140*54fd6939SJiyong Park {
141*54fd6939SJiyong Park gpio_init(&pl061_gpio_ops);
142*54fd6939SJiyong Park }
143