1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2021 Aidan MacDonald
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "gpio-x1000.h"
#if defined(EROS_QN)
# include "devicedata.h"
#endif
static const struct gpio_setting gpio_settings[PIN_COUNT] INITDATA_ATTR = {
#define DEFINE_GPIO(_name, _gpio, _func) \
{.gpio = _gpio, .func = _func},
#define DEFINE_PINGROUP(...)
#include "gpio-target.h"
#undef DEFINE_GPIO
#undef DEFINE_PINGROUP
};
static const struct pingroup_setting pingroup_settings[PINGROUP_COUNT] INITDATA_ATTR = {
#define DEFINE_GPIO(...)
#define DEFINE_PINGROUP(_name, _port, _pins, _func) \
{.port = _port, .pins = _pins, .func = _func},
#include "gpio-target.h"
#undef DEFINE_GPIO
#undef DEFINE_PINGROUP
};
#if 0 /* not needed for the time being */
static const char* const gpio_names[PIN_COUNT] = {
#define DEFINE_GPIO(_name, ...) #_name,
#define DEFINE_PINGROUP(...)
#include "gpio-target.h"
#undef DEFINE_GPIO
#undef DEFINE_PINGROUP
};
static const char* const pingroup_names[PINGROUP_COUNT] = {
#define DEFINE_GPIO(...)
#define DEFINE_PINGROUP(_name, ...) #_name,
#include "gpio-target.h"
#undef DEFINE_GPIO
#undef DEFINE_PINGROUP
};
#endif
void gpio_init(void)
{
#if defined(EROS_QN)
int devicever;
# if defined(BOOTLOADER)
devicever = EROSQN_VER;
# else
devicever = device_data.lcd_version;
# endif
#endif
/* Apply all initial GPIO settings */
for(int i = 0; i < PINGROUP_COUNT; ++i) {
const struct pingroup_setting* d = &pingroup_settings[i];
if(d->pins != 0)
gpioz_configure(d->port, d->pins, d->func);
}
for(int i = 0; i < PIN_COUNT; ++i) {
const struct gpio_setting* d = &gpio_settings[i];
#ifdef EROS_QN
// eros_qn only
// There surely has to be a nicer way to do this...
// Note: PIN_ indicates position in the list,
// GPIO_ indicates actual port/pin number
// (so if you want to go based on order of the list, use the PIN_ designator!)
if((d->gpio != GPIO_NONE) &&\
((i < PIN_HW1_START) ||\
(devicever <= 3 &&\
(i > PIN_HW1_START && i < PIN_HW1_END))\
||\
(devicever >= 4 &&\
(i > PIN_HW4_START && i < PIN_HW4_END))))
// if((d->gpio != GPIO_NONE) && (d->gpio != GPIO_BTN_POWER_HW1))
#else
// non-eros_qn devices
if(d->gpio != GPIO_NONE)
#endif
{
gpioz_configure(GPION_PORT(d->gpio), GPION_MASK(d->gpio), d->func);
}
}
/* Any GPIO pins left in an IRQ trigger state need to be switched off,
* because the drivers won't be ready to handle the interrupts until they
* get initialized later in the boot. */
for(int i = 0; i < 4; ++i) {
uint32_t intbits = REG_GPIO_INT(i);
if(intbits) {
gpioz_configure(i, intbits, GPIOF_INPUT);
jz_clr(GPIO_FLAG(i), intbits);
}
}
}
void gpioz_configure(int port, uint32_t pins, int func)
{
uint32_t intr = REG_GPIO_INT(port);
uint32_t mask = REG_GPIO_MSK(port);
uint32_t pat1 = REG_GPIO_PAT1(port);
uint32_t pat0 = REG_GPIO_PAT0(port);
/* Note: GPIO Z has _only_ set and clear registers, which are used to
* atomically manipulate the selected GPIO port when we write GID2LD.
* So there's not really any direct setting or clearing going on here...
*/
if(func & GPIO_F_INT) jz_set(GPIO_INT(GPIO_Z), (intr & pins) ^ pins);
else jz_clr(GPIO_INT(GPIO_Z), (~intr & pins) ^ pins);
if(func & GPIO_F_MASK) jz_set(GPIO_MSK(GPIO_Z), (mask & pins) ^ pins);
else jz_clr(GPIO_MSK(GPIO_Z), (~mask & pins) ^ pins);
if(func & GPIO_F_PAT1) jz_set(GPIO_PAT1(GPIO_Z), (pat1 & pins) ^ pins);
else jz_clr(GPIO_PAT1(GPIO_Z), (~pat1 & pins) ^ pins);
if(func & GPIO_F_PAT0) jz_set(GPIO_PAT0(GPIO_Z), (pat0 & pins) ^ pins);
else jz_clr(GPIO_PAT0(GPIO_Z), (~pat0 & pins) ^ pins);
REG_GPIO_Z_GID2LD = port;
if(func & GPIO_F_PULL)
jz_set(GPIO_PULL(port), pins);
else
jz_clr(GPIO_PULL(port), pins);
}
|