blob: 364cda2ca0ef1bcb17d3b0adfe708bde16737c5a [file] [log] [blame]
Kelvin Zhangc4c3dd12021-12-24 20:59:18 +08001/*
yang.li24770372022-01-11 15:21:49 +08002 * Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved.
Kelvin Zhangc4c3dd12021-12-24 20:59:18 +08003 *
yang.li24770372022-01-11 15:21:49 +08004 * SPDX-License-Identifier: MIT
Kelvin Zhangc4c3dd12021-12-24 20:59:18 +08005 */
6
Xiaohu.Huang60950452022-03-12 22:51:01 +08007#include <stdio.h>
Kelvin Zhangc4c3dd12021-12-24 20:59:18 +08008#include "FreeRTOS.h"
9#include <register.h>
10#include <common.h>
11#include <task.h>
12#include <gpio.h>
Huqiang Qined61e052023-12-14 15:35:51 +080013#include <stdbool.h>
Kelvin Zhangc4c3dd12021-12-24 20:59:18 +080014#include "projdefs.h"
15#include "gpio_drv.h"
16#include "portmacro.h"
17
Huqiang Qin01aa7422024-12-05 13:44:41 +080018#define DRIVER_NAME "GPIO"
Kelvin Zhangc4c3dd12021-12-24 20:59:18 +080019
Huqiang Qined61e052023-12-14 15:35:51 +080020struct BankBackup {
21 uint32_t pinmux[4];
22 uint32_t oen;
23};
24
25static struct BankBackup stateBackup[BANK_NUM_MAX];
26
Kelvin Zhangc4c3dd12021-12-24 20:59:18 +080027static void prvEnterCritical(UBaseType_t *uxIsr)
28{
29 if (xPortIsIsrContext())
30 *uxIsr = taskENTER_CRITICAL_FROM_ISR();
31 else {
32 taskENTER_CRITICAL();
33 *uxIsr = 0;
34 }
35};
36
37static void prvExitCritical(UBaseType_t uxSaveIsr)
38{
39 if (xPortIsIsrContext())
40 taskEXIT_CRITICAL_FROM_ISR(uxSaveIsr);
41 else {
42 taskEXIT_CRITICAL();
43 (void)uxSaveIsr;
44 }
45};
46
xiaohu.huang2beac512022-05-07 15:10:04 +080047static inline void prvGpioRegWrite(uint32_t addr, uint32_t mask, uint32_t val)
Kelvin Zhangc4c3dd12021-12-24 20:59:18 +080048{
49 UBaseType_t uxSavedIsr;
50
51 prvEnterCritical(&uxSavedIsr);
52 REG32_UPDATE_BITS(addr, mask, val);
53 prvExitCritical(uxSavedIsr);
54}
55
xiaohu.huang2beac512022-05-07 15:10:04 +080056static inline void prvGpioCalcRegAndBit(const struct GpioBank *bk, uint8_t offset,
57 enum GpioRegType regType, uint16_t *reg, uint8_t *bit)
Kelvin Zhangc4c3dd12021-12-24 20:59:18 +080058{
59 *reg = bk->regs[regType].reg << 2;
60 *bit = bk->regs[regType].bit + offset;
61}
62
xiaohu.huang2beac512022-05-07 15:10:04 +080063static inline void prvGpioGetBankAndOffset(uint16_t gpio, const struct GpioBank **bk, uint8_t *off)
Kelvin Zhangc4c3dd12021-12-24 20:59:18 +080064{
xiaohu.huang2beac512022-05-07 15:10:04 +080065 const struct GpioBank *gpk;
Kelvin Zhangc4c3dd12021-12-24 20:59:18 +080066
67 gpk = pGetGpioBank();
68 *bk = &gpk[gpio >> 5];
69 *off = gpio % 32;
70}
71
72int xGpioSetDir(uint16_t gpio, enum GpioDirType dir)
73{
74 uint16_t reg;
75 uint8_t bit;
76 uint8_t offset;
xiaohu.huang2beac512022-05-07 15:10:04 +080077 const struct GpioBank *bk;
Kelvin Zhangc4c3dd12021-12-24 20:59:18 +080078
79 if (dir >= GPIO_DIR_INVALID) {
Huqiang Qin01aa7422024-12-05 13:44:41 +080080 printf("%s: INVAL DIR %d\n", DRIVER_NAME, dir);
Kelvin Zhangc4c3dd12021-12-24 20:59:18 +080081 return -pdFREERTOS_ERRNO_EINVAL;
82 }
83
84 prvGpioGetBankAndOffset(gpio, &bk, &offset);
85
86 prvGpioCalcRegAndBit(bk, offset, REG_DIR, &reg, &bit);
87
88 prvGpioRegWrite(bk->domain->rGpio + reg, BIT(bit), dir ? BIT(bit) : 0);
89
90 return 0;
91}
92
93int xGpioSetValue(uint16_t gpio, enum GpioOutLevelType level)
94{
95 uint16_t reg;
96 uint8_t bit;
97 uint8_t offset;
xiaohu.huang2beac512022-05-07 15:10:04 +080098 const struct GpioBank *bk;
Kelvin Zhangc4c3dd12021-12-24 20:59:18 +080099
100 if (level >= GPIO_LEVEL_INVALID) {
Huqiang Qin01aa7422024-12-05 13:44:41 +0800101 printf("%s: INVAL OUT %d\n", DRIVER_NAME, level);
Kelvin Zhangc4c3dd12021-12-24 20:59:18 +0800102 return -pdFREERTOS_ERRNO_EINVAL;
103 }
104
105 prvGpioGetBankAndOffset(gpio, &bk, &offset);
106
107 prvGpioCalcRegAndBit(bk, offset, REG_OUT, &reg, &bit);
108
xiaohu.huang2beac512022-05-07 15:10:04 +0800109 prvGpioRegWrite(bk->domain->rGpio + reg, BIT(bit), level ? BIT(bit) : 0);
Kelvin Zhangc4c3dd12021-12-24 20:59:18 +0800110
111 return 0;
112}
113
114int xGpioGetValue(uint16_t gpio)
115{
116 uint16_t reg;
117 uint8_t bit;
118 uint8_t offset;
xiaohu.huang2beac512022-05-07 15:10:04 +0800119 const struct GpioBank *bk;
Kelvin Zhangc4c3dd12021-12-24 20:59:18 +0800120
121 prvGpioGetBankAndOffset(gpio, &bk, &offset);
122
123 prvGpioCalcRegAndBit(bk, offset, REG_IN, &reg, &bit);
124
125 return !!(REG32((unsigned long)bk->domain->rGpio + reg) & BIT(bit));
126}
127
128int xPinconfSet(uint16_t gpio, uint32_t flags)
129{
130 uint16_t reg;
131 uint8_t bit;
132 uint8_t offset;
133 uint8_t ds_value = 0;
xiaohu.huang2beac512022-05-07 15:10:04 +0800134 const struct GpioBank *bk;
135 const struct GpioRegDesc *desc;
Kelvin Zhangc4c3dd12021-12-24 20:59:18 +0800136
137 prvGpioGetBankAndOffset(gpio, &bk, &offset);
138
139 prvGpioCalcRegAndBit(bk, offset, REG_PULLEN, &reg, &bit);
140
141 if (flags & PINF_CONFIG_BIAS_DISABLE) {
142 prvGpioRegWrite(bk->domain->rPullen + reg, BIT(bit), 0);
xiaohu.huang2beac512022-05-07 15:10:04 +0800143 } else if (flags & (PINF_CONFIG_BIAS_PULL_UP | PINF_CONFIG_BIAS_PULL_DOWN)) {
Kelvin Zhangc4c3dd12021-12-24 20:59:18 +0800144 prvGpioRegWrite(bk->domain->rPullen + reg, BIT(bit), BIT(bit));
145
146 prvGpioCalcRegAndBit(bk, offset, REG_PULL, &reg, &bit);
147 if (flags & PINF_CONFIG_BIAS_PULL_UP)
xiaohu.huang2beac512022-05-07 15:10:04 +0800148 prvGpioRegWrite(bk->domain->rPull + reg, BIT(bit), BIT(bit));
Kelvin Zhangc4c3dd12021-12-24 20:59:18 +0800149 else
150 prvGpioRegWrite(bk->domain->rPull + reg, BIT(bit), 0);
151 }
152
153 if ((flags & PINF_CONFIG_DRV_MASK) && &bk->regs[REG_DRV] != 0) {
Kelvin Zhangc4c3dd12021-12-24 20:59:18 +0800154 prvGpioCalcRegAndBit(bk, offset, REG_DRV, &reg, &bit);
155 desc = &bk->regs[REG_DRV];
156
157 reg = desc->reg + ((desc->bit + (offset << 1)) >> 5);
158 bit = (desc->bit + (offset << 1)) % 32;
159
160 if (flags & PINF_CONFIG_DRV_STRENGTH_0)
161 ds_value = 0;
162 else if (flags & PINF_CONFIG_DRV_STRENGTH_1)
163 ds_value = 1;
164 else if (flags & PINF_CONFIG_DRV_STRENGTH_2)
165 ds_value = 2;
166 else if (flags & PINF_CONFIG_DRV_STRENGTH_3)
167 ds_value = 3;
168
xiaohu.huang2beac512022-05-07 15:10:04 +0800169 prvGpioRegWrite(bk->domain->rDrv + (reg << 2), 0x3 << bit, ds_value << bit);
Kelvin Zhangc4c3dd12021-12-24 20:59:18 +0800170 }
171
172 return 0;
173}
174
175int xPinmuxSet(uint16_t gpio, enum PinMuxType func)
176{
177 uint16_t reg;
178 uint8_t bit;
179 uint8_t offset;
xiaohu.huang2beac512022-05-07 15:10:04 +0800180 const struct GpioBank *bk;
181 const struct GpioRegDesc *desc;
Kelvin Zhangc4c3dd12021-12-24 20:59:18 +0800182
183 if (func >= PIN_FUNC_INVALID) {
Huqiang Qin01aa7422024-12-05 13:44:41 +0800184 printf("%s: INVAL FUNC %d\n", DRIVER_NAME, func);
Kelvin Zhangc4c3dd12021-12-24 20:59:18 +0800185 return -pdFREERTOS_ERRNO_EINVAL;
186 }
187
188 prvGpioGetBankAndOffset(gpio, &bk, &offset);
189 desc = &bk->regs[REG_MUX];
190
191 reg = desc->reg + ((desc->bit + (offset << 2)) >> 5);
192 bit = (desc->bit + (offset << 2)) % 32;
193
194 prvGpioRegWrite(bk->domain->rMux + (reg << 2), 0xf << bit, func << bit);
195
196 return 0;
197}
Huqiang Qined61e052023-12-14 15:35:51 +0800198
199static void prvOenStateHandle(const struct GpioBank *bk, struct BankBackup *bbk, bool isBackup)
200{
201 uint8_t reg, bit, end;
202
203 bit = bk->regs[REG_DIR].bit;
204 end = bit + bk->pin_num;
205 reg = bk->regs[REG_DIR].reg;
206
207 while (bit < end) {
208 if (isBackup) {
209 bbk->oen &= ~(0x1 << bit);
210 bbk->oen |= REG32(bk->domain->rGpio + (reg << 2)) & (0x1 << bit);
211 prvGpioRegWrite(bk->domain->rGpio + (reg << 2), 0x1 << bit, 0x1 << bit);
212 } else {
213 prvGpioRegWrite(bk->domain->rGpio + (reg << 2), 0x1 << bit, bbk->oen);
214 }
215 bit++;
216 }
217}
218
219static void prvPinmuxStateHandle(const struct GpioBank *bk, struct BankBackup *bbk, bool isBackup)
220{
221 uint8_t reg, offset, bit, begin, end;
222
223 begin = bk->regs[REG_MUX].bit;
224 end = begin + bk->pin_num * 4;
225 reg = bk->regs[REG_MUX].reg;
226
227 while (begin < end) {
228 offset = begin >> 5;
229 bit = begin & 0x1f;
230 if (isBackup) {
231 bbk->pinmux[offset] &= ~(0xf << bit);
232 bbk->pinmux[offset] |= REG32(bk->domain->rMux + ((reg + offset) << 2)) &
233 (0xf << bit);
234 prvGpioRegWrite(bk->domain->rMux + ((reg + offset) << 2), 0xf << bit, 0);
235 } else {
236 prvGpioRegWrite(bk->domain->rMux + ((reg + offset) << 2), 0xf << bit,
237 bbk->pinmux[offset]);
238 }
239 begin += 4;
240 }
241}
242
243static int prvStrCaseCmp(const char *string1, const char *string2)
244{
245 char value;
246 char *lp = (char *)string1;
247 char *rp = (char *)string2;
248
249 while (*lp && *rp) {
250 value = ((*lp >= 'A' && *lp <= 'Z') ? (*lp - 'A' + 'a') : *lp) -
251 ((*rp >= 'A' && *rp <= 'Z') ? (*rp - 'A' + 'a') : *rp);
252 if (value)
253 return value;
254 lp++;
255 rp++;
256 }
257
258 return *lp - *rp;
259}
260
261static int prvBankCheck(const char *name, const struct GpioBank **bk)
262{
263 int index;
264 const struct GpioBank *gpk = pGetGpioBank();
265
266 /* Find bank */
267 for (index = 0; index < BANK_NUM_MAX; index++) {
268 if (!prvStrCaseCmp(gpk[index].name, name)) {
269 *bk = &gpk[index];
270 break;
271 }
272 }
273
274 if (index == BANK_NUM_MAX)
275 return -pdFREERTOS_ERRNO_ENXIO;
276
277 if (!(*bk)->pin_num)
278 return -pdFREERTOS_ERRNO_EINVAL;
279
280 return index;
281}
282
283int xBankStateBackup(const char *name)
284{
285 int index;
286 const struct GpioBank *bk;
287
288 index = prvBankCheck(name, &bk);
289 if (index < 0)
290 return index;
291
292 prvOenStateHandle(bk, &stateBackup[index], true);
293 prvPinmuxStateHandle(bk, &stateBackup[index], true);
294
295 return 0;
296}
297
298int xBankStateRestore(const char *name)
299{
300 int index;
301 const struct GpioBank *bk;
302
303 index = prvBankCheck(name, &bk);
304 if (index < 0)
305 return index;
306
307 prvPinmuxStateHandle(bk, &stateBackup[index], false);
308 prvOenStateHandle(bk, &stateBackup[index], false);
309
310 return 0;
311}