blob: 55a8832c3e77d9c2b797f7242eadc78985c7e9ff [file] [log] [blame]
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +08001/*
2 * Copyright (c) 2019, Linaro Limited
3 * Copyright (c) 2019, Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8#include <string.h>
9#include <assert.h>
10#include <lib/mmio.h>
11#include <drivers/delay_timer.h>
12#include <drivers/rpi3/gpio/rpi3_gpio.h>
Claus Pedersen785e66c2022-09-12 22:42:58 +000013#include <platform_def.h>
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +080014
Andre Przywara203e7c42020-03-11 16:10:40 +000015static uintptr_t reg_base;
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +080016
17static int rpi3_gpio_get_direction(int gpio);
18static void rpi3_gpio_set_direction(int gpio, int direction);
19static int rpi3_gpio_get_value(int gpio);
20static void rpi3_gpio_set_value(int gpio, int value);
21static void rpi3_gpio_set_pull(int gpio, int pull);
22
23static const gpio_ops_t rpi3_gpio_ops = {
24 .get_direction = rpi3_gpio_get_direction,
25 .set_direction = rpi3_gpio_set_direction,
26 .get_value = rpi3_gpio_get_value,
27 .set_value = rpi3_gpio_set_value,
28 .set_pull = rpi3_gpio_set_pull,
29};
30
31/**
32 * Get selection of GPIO pinmux settings.
33 *
34 * @param gpio The pin number of GPIO. From 0 to 53.
35 * @return The selection of pinmux. RPI3_GPIO_FUNC_INPUT: input,
36 * RPI3_GPIO_FUNC_OUTPUT: output,
37 * RPI3_GPIO_FUNC_ALT0: alt-0,
38 * RPI3_GPIO_FUNC_ALT1: alt-1,
39 * RPI3_GPIO_FUNC_ALT2: alt-2,
40 * RPI3_GPIO_FUNC_ALT3: alt-3,
41 * RPI3_GPIO_FUNC_ALT4: alt-4,
42 * RPI3_GPIO_FUNC_ALT5: alt-5
43 */
44int rpi3_gpio_get_select(int gpio)
45{
46 int ret;
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +080047 int regN = gpio / 10;
48 int shift = 3 * (gpio % 10);
49 uintptr_t reg_sel = reg_base + RPI3_GPIO_GPFSEL(regN);
50 uint32_t sel = mmio_read_32(reg_sel);
51
52 ret = (sel >> shift) & 0x07;
53
54 return ret;
55}
56
57/**
58 * Set selection of GPIO pinmux settings.
59 *
60 * @param gpio The pin number of GPIO. From 0 to 53.
61 * @param fsel The selection of pinmux. RPI3_GPIO_FUNC_INPUT: input,
62 * RPI3_GPIO_FUNC_OUTPUT: output,
63 * RPI3_GPIO_FUNC_ALT0: alt-0,
64 * RPI3_GPIO_FUNC_ALT1: alt-1,
65 * RPI3_GPIO_FUNC_ALT2: alt-2,
66 * RPI3_GPIO_FUNC_ALT3: alt-3,
67 * RPI3_GPIO_FUNC_ALT4: alt-4,
68 * RPI3_GPIO_FUNC_ALT5: alt-5
69 */
70void rpi3_gpio_set_select(int gpio, int fsel)
71{
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +080072 int regN = gpio / 10;
73 int shift = 3 * (gpio % 10);
74 uintptr_t reg_sel = reg_base + RPI3_GPIO_GPFSEL(regN);
75 uint32_t sel = mmio_read_32(reg_sel);
76 uint32_t mask = U(0x07) << shift;
77
78 sel = (sel & (~mask)) | ((fsel << shift) & mask);
79 mmio_write_32(reg_sel, sel);
80}
81
82static int rpi3_gpio_get_direction(int gpio)
83{
84 int result = rpi3_gpio_get_select(gpio);
85
86 if (result == RPI3_GPIO_FUNC_INPUT)
87 return GPIO_DIR_IN;
88 else if (result == RPI3_GPIO_FUNC_OUTPUT)
89 return GPIO_DIR_OUT;
90
91 return GPIO_DIR_IN;
92}
93
94static void rpi3_gpio_set_direction(int gpio, int direction)
95{
96 switch (direction) {
97 case GPIO_DIR_IN:
98 rpi3_gpio_set_select(gpio, RPI3_GPIO_FUNC_INPUT);
99 break;
100 case GPIO_DIR_OUT:
101 rpi3_gpio_set_select(gpio, RPI3_GPIO_FUNC_OUTPUT);
102 break;
103 }
104}
105
106static int rpi3_gpio_get_value(int gpio)
107{
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +0800108 int regN = gpio / 32;
109 int shift = gpio % 32;
110 uintptr_t reg_lev = reg_base + RPI3_GPIO_GPLEV(regN);
111 uint32_t value = mmio_read_32(reg_lev);
112
113 if ((value >> shift) & 0x01)
114 return GPIO_LEVEL_HIGH;
115 return GPIO_LEVEL_LOW;
116}
117
118static void rpi3_gpio_set_value(int gpio, int value)
119{
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +0800120 int regN = gpio / 32;
121 int shift = gpio % 32;
122 uintptr_t reg_set = reg_base + RPI3_GPIO_GPSET(regN);
123 uintptr_t reg_clr = reg_base + RPI3_GPIO_GPSET(regN);
124
125 switch (value) {
126 case GPIO_LEVEL_LOW:
127 mmio_write_32(reg_clr, U(1) << shift);
128 break;
129 case GPIO_LEVEL_HIGH:
130 mmio_write_32(reg_set, U(1) << shift);
131 break;
132 }
133}
134
135static void rpi3_gpio_set_pull(int gpio, int pull)
136{
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +0800137 int regN = gpio / 32;
138 int shift = gpio % 32;
139 uintptr_t reg_pud = reg_base + RPI3_GPIO_GPPUD;
140 uintptr_t reg_clk = reg_base + RPI3_GPIO_GPPUDCLK(regN);
141
142 switch (pull) {
143 case GPIO_PULL_NONE:
144 mmio_write_32(reg_pud, 0x0);
145 break;
146 case GPIO_PULL_UP:
147 mmio_write_32(reg_pud, 0x2);
148 break;
149 case GPIO_PULL_DOWN:
150 mmio_write_32(reg_pud, 0x1);
151 break;
152 }
153 mdelay(150);
154 mmio_write_32(reg_clk, U(1) << shift);
155 mdelay(150);
156 mmio_write_32(reg_clk, 0x0);
157 mmio_write_32(reg_pud, 0x0);
158}
159
Andre Przywara203e7c42020-03-11 16:10:40 +0000160void rpi3_gpio_init(void)
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +0800161{
Andre Przywara203e7c42020-03-11 16:10:40 +0000162 reg_base = RPI3_GPIO_BASE;
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +0800163 gpio_init(&rpi3_gpio_ops);
164}