blob: 460afe171a2284ff9c4c22588d9bbb5f0514234a [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>
Abhi.Singh60b8a032024-06-25 13:43:27 -05004 * Copyright (c) 2024, Arm Limited. All rights reserved.
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +08005 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9#include <string.h>
10#include <assert.h>
11#include <lib/mmio.h>
12#include <drivers/delay_timer.h>
13#include <drivers/rpi3/gpio/rpi3_gpio.h>
Claus Pedersen785e66c2022-09-12 22:42:58 +000014#include <platform_def.h>
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +080015
Andre Przywara203e7c42020-03-11 16:10:40 +000016static uintptr_t reg_base;
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +080017
18static int rpi3_gpio_get_direction(int gpio);
19static void rpi3_gpio_set_direction(int gpio, int direction);
20static int rpi3_gpio_get_value(int gpio);
21static void rpi3_gpio_set_value(int gpio, int value);
22static void rpi3_gpio_set_pull(int gpio, int pull);
23
24static const gpio_ops_t rpi3_gpio_ops = {
25 .get_direction = rpi3_gpio_get_direction,
26 .set_direction = rpi3_gpio_set_direction,
27 .get_value = rpi3_gpio_get_value,
28 .set_value = rpi3_gpio_set_value,
29 .set_pull = rpi3_gpio_set_pull,
30};
31
32/**
33 * Get selection of GPIO pinmux settings.
34 *
35 * @param gpio The pin number of GPIO. From 0 to 53.
36 * @return The selection of pinmux. RPI3_GPIO_FUNC_INPUT: input,
37 * RPI3_GPIO_FUNC_OUTPUT: output,
38 * RPI3_GPIO_FUNC_ALT0: alt-0,
39 * RPI3_GPIO_FUNC_ALT1: alt-1,
40 * RPI3_GPIO_FUNC_ALT2: alt-2,
41 * RPI3_GPIO_FUNC_ALT3: alt-3,
42 * RPI3_GPIO_FUNC_ALT4: alt-4,
43 * RPI3_GPIO_FUNC_ALT5: alt-5
44 */
45int rpi3_gpio_get_select(int gpio)
46{
47 int ret;
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +080048 int regN = gpio / 10;
49 int shift = 3 * (gpio % 10);
50 uintptr_t reg_sel = reg_base + RPI3_GPIO_GPFSEL(regN);
51 uint32_t sel = mmio_read_32(reg_sel);
52
53 ret = (sel >> shift) & 0x07;
54
55 return ret;
56}
57
58/**
59 * Set selection of GPIO pinmux settings.
60 *
61 * @param gpio The pin number of GPIO. From 0 to 53.
62 * @param fsel The selection of pinmux. RPI3_GPIO_FUNC_INPUT: input,
63 * RPI3_GPIO_FUNC_OUTPUT: output,
64 * RPI3_GPIO_FUNC_ALT0: alt-0,
65 * RPI3_GPIO_FUNC_ALT1: alt-1,
66 * RPI3_GPIO_FUNC_ALT2: alt-2,
67 * RPI3_GPIO_FUNC_ALT3: alt-3,
68 * RPI3_GPIO_FUNC_ALT4: alt-4,
69 * RPI3_GPIO_FUNC_ALT5: alt-5
70 */
71void rpi3_gpio_set_select(int gpio, int fsel)
72{
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +080073 int regN = gpio / 10;
74 int shift = 3 * (gpio % 10);
75 uintptr_t reg_sel = reg_base + RPI3_GPIO_GPFSEL(regN);
76 uint32_t sel = mmio_read_32(reg_sel);
77 uint32_t mask = U(0x07) << shift;
78
79 sel = (sel & (~mask)) | ((fsel << shift) & mask);
80 mmio_write_32(reg_sel, sel);
81}
82
83static int rpi3_gpio_get_direction(int gpio)
84{
85 int result = rpi3_gpio_get_select(gpio);
86
87 if (result == RPI3_GPIO_FUNC_INPUT)
88 return GPIO_DIR_IN;
89 else if (result == RPI3_GPIO_FUNC_OUTPUT)
90 return GPIO_DIR_OUT;
91
92 return GPIO_DIR_IN;
93}
94
95static void rpi3_gpio_set_direction(int gpio, int direction)
96{
97 switch (direction) {
98 case GPIO_DIR_IN:
99 rpi3_gpio_set_select(gpio, RPI3_GPIO_FUNC_INPUT);
100 break;
101 case GPIO_DIR_OUT:
102 rpi3_gpio_set_select(gpio, RPI3_GPIO_FUNC_OUTPUT);
103 break;
104 }
105}
106
107static int rpi3_gpio_get_value(int gpio)
108{
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +0800109 int regN = gpio / 32;
110 int shift = gpio % 32;
111 uintptr_t reg_lev = reg_base + RPI3_GPIO_GPLEV(regN);
112 uint32_t value = mmio_read_32(reg_lev);
113
114 if ((value >> shift) & 0x01)
115 return GPIO_LEVEL_HIGH;
116 return GPIO_LEVEL_LOW;
117}
118
119static void rpi3_gpio_set_value(int gpio, int value)
120{
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +0800121 int regN = gpio / 32;
122 int shift = gpio % 32;
123 uintptr_t reg_set = reg_base + RPI3_GPIO_GPSET(regN);
Abhi.Singh60b8a032024-06-25 13:43:27 -0500124 uintptr_t reg_clr = reg_base + RPI3_GPIO_GPCLR(regN);
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +0800125
126 switch (value) {
127 case GPIO_LEVEL_LOW:
128 mmio_write_32(reg_clr, U(1) << shift);
129 break;
130 case GPIO_LEVEL_HIGH:
131 mmio_write_32(reg_set, U(1) << shift);
132 break;
133 }
134}
135
136static void rpi3_gpio_set_pull(int gpio, int pull)
137{
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +0800138 int regN = gpio / 32;
139 int shift = gpio % 32;
140 uintptr_t reg_pud = reg_base + RPI3_GPIO_GPPUD;
141 uintptr_t reg_clk = reg_base + RPI3_GPIO_GPPUDCLK(regN);
142
143 switch (pull) {
144 case GPIO_PULL_NONE:
145 mmio_write_32(reg_pud, 0x0);
146 break;
147 case GPIO_PULL_UP:
148 mmio_write_32(reg_pud, 0x2);
149 break;
150 case GPIO_PULL_DOWN:
151 mmio_write_32(reg_pud, 0x1);
152 break;
153 }
154 mdelay(150);
155 mmio_write_32(reg_clk, U(1) << shift);
156 mdelay(150);
157 mmio_write_32(reg_clk, 0x0);
158 mmio_write_32(reg_pud, 0x0);
159}
160
Andre Przywara203e7c42020-03-11 16:10:40 +0000161void rpi3_gpio_init(void)
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +0800162{
Andre Przywara203e7c42020-03-11 16:10:40 +0000163 reg_base = RPI3_GPIO_BASE;
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +0800164 gpio_init(&rpi3_gpio_ops);
165}