summaryrefslogtreecommitdiff
path: root/firmware/target/arm/s5l8702
diff options
context:
space:
mode:
authorCástor Muñoz <cmvidal@gmail.com>2016-05-22 01:12:35 +0200
committerCástor Muñoz <cmvidal@gmail.com>2016-05-25 12:44:55 +0200
commit88caf222ed1da8f88114b4aa3a615e72e3649ca1 (patch)
treeb5fa90da7324e77972569956f1bd0ab83353f5af /firmware/target/arm/s5l8702
parent3f17745930ab0bee11555ab35318121dbec8fab1 (diff)
downloadrockbox-88caf222ed1da8f88114b4aa3a615e72e3649ca1.tar.gz
rockbox-88caf222ed1da8f88114b4aa3a615e72e3649ca1.zip
iPod Classic: rework on external interrupts
Change-Id: I5be450adeb12b16070d9bfa31503e2ef350b2981
Diffstat (limited to 'firmware/target/arm/s5l8702')
-rw-r--r--firmware/target/arm/s5l8702/gpio-s5l8702.c193
-rw-r--r--firmware/target/arm/s5l8702/gpio-s5l8702.h126
-rw-r--r--firmware/target/arm/s5l8702/system-s5l8702.c1
3 files changed, 164 insertions, 156 deletions
diff --git a/firmware/target/arm/s5l8702/gpio-s5l8702.c b/firmware/target/arm/s5l8702/gpio-s5l8702.c
index 3b2c02861f..0f7a029fb6 100644
--- a/firmware/target/arm/s5l8702/gpio-s5l8702.c
+++ b/firmware/target/arm/s5l8702/gpio-s5l8702.c
@@ -23,11 +23,30 @@
23 23
24#include "config.h" 24#include "config.h"
25#include "system.h" 25#include "system.h"
26#include "gpio-s5l8702.h"
27#include "panic.h" 26#include "panic.h"
28 27
28#include "gpio-s5l8702.h"
29
30
29int rec_hw_ver; 31int rec_hw_ver;
30 32
33static uint32_t gpio_data[] =
34{
35 0x5322222F, 0xEEEEEE00, 0x2332EEEE, 0x3333E222,
36 0x33333333, 0x33333333, 0x3F000E33, 0xEEEEEEEE,
37 0xEEEEEEEE, 0xEEEEEEEE, 0xE0EEEEEE, 0xEE00EE0E,
38 0xEEEE0EEE, 0xEEEEEEEE, 0xEE2222EE, 0xEEEE0EEE
39};
40
41void INIT_ATTR gpio_preinit(void)
42{
43 for (int i = 0; i < 16; i++) {
44 PCON(i) = gpio_data[i];
45 PUNB(i) = 0;
46 PUNC(i) = 0;
47 }
48}
49
31void INIT_ATTR gpio_init(void) 50void INIT_ATTR gpio_init(void)
32{ 51{
33 /* Capture hardware versions: 52 /* Capture hardware versions:
@@ -44,9 +63,8 @@ void INIT_ATTR gpio_init(void)
44 */ 63 */
45 GPIOCMD = 0xe0700; 64 GPIOCMD = 0xe0700;
46 rec_hw_ver = (PDAT(14) & (1 << 7)) ? 0 : 1; 65 rec_hw_ver = (PDAT(14) & (1 << 7)) ? 0 : 1;
66 GPIOCMD = 0xe070e; /* restore default configuration */
47 67
48 /* default GPIO configuration */
49 GPIOCMD = 0xe070e;
50 if (rec_hw_ver == 0) { 68 if (rec_hw_ver == 0) {
51 GPIOCMD = 0xe060e; 69 GPIOCMD = 0xe060e;
52 } 70 }
@@ -56,31 +74,9 @@ void INIT_ATTR gpio_init(void)
56 GPIOCMD = 0xe0600; 74 GPIOCMD = 0xe0600;
57 PUNB(14) |= (1 << 6); 75 PUNB(14) |= (1 << 6);
58 } 76 }
59
60 /* TODO: initialize GPIO ports for minimum power consumption */
61} 77}
62 78
63
64/*
65 * XXX: disabled, not used and never tested!
66 */
67#if 0 79#if 0
68/* handlers list */
69#define GPIOIC_MAX_HANDLERS 2
70
71#define FLAG_TYPE_LEVEL (1 << 0)
72#define FLAG_AUTOFLIP (1 << 1)
73
74struct gpio_handler {
75 int gpio_n;
76 void (*isr)(void);
77 int flags;
78};
79static struct gpio_handler l_handlers[GPIOIC_MAX_HANDLERS] IDATA_ATTR;
80static int n_handlers = 0;
81
82
83/* API */
84uint32_t gpio_group_get(int group) 80uint32_t gpio_group_get(int group)
85{ 81{
86 uint32_t pcon = PCON(group); 82 uint32_t pcon = PCON(group);
@@ -103,131 +99,128 @@ void gpio_group_set(int group, uint32_t mask, uint32_t cfg)
103{ 99{
104 PCON(group) = (PCON(group) & ~mask) | (cfg & mask); 100 PCON(group) = (PCON(group) & ~mask) | (cfg & mask);
105} 101}
102#endif
106 103
107void gpio_int_register(int gpio_n, void *isr, int type, int level, int autoflip)
108{
109 if (n_handlers >= GPIOIC_MAX_HANDLERS)
110 panicf("gpio_int_register(): too many handlers!");
111 104
112 int group = IC_GROUP(gpio_n); 105/*
113 int index = IC_IDX(gpio_n); 106 * eINT API
107 */
108#ifndef EINT_MAX_HANDLERS
109#define EINT_MAX_HANDLERS 1
110#endif
111static struct eint_handler* l_handlers[EINT_MAX_HANDLERS] IDATA_ATTR;
114 112
113void INIT_ATTR eint_init(void)
114{
115 /* disable external interrupts */
116 for (int i = 0; i < EIC_N_GROUPS; i++)
117 EIC_INTEN(i) = 0;
118}
119
120void eint_register(struct eint_handler *h)
121{
122 int i;
115 int flags = disable_irq_save(); 123 int flags = disable_irq_save();
116 124
117 /* fill handler struct */ 125 for (i = 0; i < EINT_MAX_HANDLERS; i++) {
118 struct gpio_handler *handler = &l_handlers[n_handlers++]; 126 if (!l_handlers[i]) {
127 int group = EIC_GROUP(h->gpio_n);
128 int index = EIC_INDEX(h->gpio_n);
119 129
120 handler->gpio_n = gpio_n; 130 EIC_INTTYPE(group) |= (h->type << index);
121 handler->isr = isr; 131 EIC_INTLEVEL(group) |= (h->level << index);
122 handler->flags = (type ? FLAG_TYPE_LEVEL : 0) 132 EIC_INTSTAT(group) = (1 << index); /* clear */
123 | (autoflip ? FLAG_AUTOFLIP : 0); 133 EIC_INTEN(group) |= (1 << index); /* enable */
124 134
125 /* configure */ 135 /* XXX: valid only for gpio_n = 0..127 (IRQ_EXT0..IRQ_EXT3) */
126 GPIOIC_INTTYPE(group) |= 136 VIC0INTENABLE = 1 << (IRQ_EXT0 + (h->gpio_n >> 5));
127 (type ? GPIOIC_INTTYPE_LEVEL : GPIOIC_INTTYPE_EDGE) << index; 137
128 GPIOIC_INTLEVEL(group) |= 138 l_handlers[i] = h;
129 (level ? GPIOIC_INTLEVEL_HIGH : GPIOIC_INTLEVEL_LOW) << index; 139 break;
140 }
141 }
130 142
131 restore_irq(flags); 143 restore_irq(flags);
132 144
133 /* XXX: valid only for gpio_n = 0..127 (IRQ_EXT0..IRQ_EXT3) */ 145 if (i == EINT_MAX_HANDLERS)
134 VIC0INTENABLE = 1 << (IRQ_EXT0 + (gpio_n >> 5)); 146 panicf("%s(): too many handlers!", __func__);
135} 147}
136 148
137void gpio_int_enable(int gpio_n) 149void eint_unregister(struct eint_handler *h)
138{ 150{
139 int group = IC_GROUP(gpio_n);
140 uint32_t bit_mask = 1 << IC_IDX(gpio_n);
141
142 int flags = disable_irq_save(); 151 int flags = disable_irq_save();
143 GPIOIC_INTSTAT(group) = bit_mask; /* clear */
144 GPIOIC_INTEN(group) |= bit_mask; /* enable */
145 restore_irq(flags);
146}
147 152
148void gpio_int_disable(int gpio_n) 153 for (int i = 0; i < EINT_MAX_HANDLERS; i++) {
149{ 154 if (l_handlers[i] == h) {
150 int group = IC_GROUP(gpio_n); 155 int group = EIC_GROUP(h->gpio_n);
151 uint32_t bit_mask = 1 << IC_IDX(gpio_n); 156 int index = EIC_INDEX(h->gpio_n);
157
158 EIC_INTEN(group) &= ~(1 << index); /* disable */
159
160 /* XXX: valid only for gpio_n = 0..127 (IRQ_EXT0..IRQ_EXT3) */
161 if (EIC_INTEN(group) == 0)
162 VIC0INTENCLEAR = 1 << (IRQ_EXT0 + (h->gpio_n >> 5));
163
164 l_handlers[i] = NULL;
165 break;
166 }
167 }
152 168
153 int flags = disable_irq_save();
154 GPIOIC_INTEN(group) &= ~bit_mask; /* disable */
155 GPIOIC_INTSTAT(group) = bit_mask; /* clear */
156 restore_irq(flags); 169 restore_irq(flags);
157} 170}
158 171
159
160/* ISR */ 172/* ISR */
161void ICODE_ATTR gpio_handler(int group) 173void ICODE_ATTR eint_handler(int group)
162{ 174{
163 int i; 175 int i;
164 struct gpio_handler *handler; 176 uint32_t ints;
165 uint32_t ints, bit_mask;
166 177
167 ints = GPIOIC_INTSTAT(group) & GPIOIC_INTEN(group); 178 ints = EIC_INTSTAT(group) & EIC_INTEN(group);
168 179
169 for (i = 0; i < n_handlers; i++) { 180 for (i = 0; i < EINT_MAX_HANDLERS; i++) {
170 handler = &l_handlers[i]; 181 struct eint_handler *h = l_handlers[i];
171 182
172 if (IC_GROUP(handler->gpio_n) != group) 183 if (!h || (EIC_GROUP(h->gpio_n) != group))
173 continue; 184 continue;
174 185
175 bit_mask = 1 << IC_IDX(handler->gpio_n); 186 uint32_t bit = 1 << EIC_INDEX(h->gpio_n);
176 187
177 if (ints & bit_mask) { 188 if (ints & bit) {
178 if ((handler->flags & FLAG_TYPE_LEVEL) == 0) 189 /* Clear INTTYPE_EDGE interrupt, to clear INTTYPE_LEVEL
179 GPIOIC_INTSTAT(group) = bit_mask; /* clear */ 190 interrupts the source (line level) must be "cleared" */
191 if (h->type == EIC_INTTYPE_EDGE)
192 EIC_INTSTAT(group) = bit; /* clear */
180 193
181 if (handler->flags & FLAG_AUTOFLIP) 194 if (h->autoflip)
182 GPIOIC_INTLEVEL(group) ^= bit_mask; /* swap level */ 195 EIC_INTLEVEL(group) ^= bit; /* swap level */
183 196
184 if (handler->isr) 197 if (h->isr)
185 handler->isr(); /* exec GPIO handler */ 198 h->isr(h); /* exec GPIO handler */
186
187 GPIOIC_INTSTAT(group) = bit_mask; /* clear */
188 } 199 }
189 } 200 }
190} 201}
191 202
192void ICODE_ATTR INT_EXT0(void) 203void ICODE_ATTR INT_EXT0(void)
193{ 204{
194 gpio_handler(6); 205 eint_handler(6);
195} 206}
196 207
197void ICODE_ATTR INT_EXT1(void) 208void ICODE_ATTR INT_EXT1(void)
198{ 209{
199 gpio_handler(5); 210 eint_handler(5);
200} 211}
201 212
202void ICODE_ATTR INT_EXT2(void) 213void ICODE_ATTR INT_EXT2(void)
203{ 214{
204 gpio_handler(4); 215 eint_handler(4);
205} 216}
206 217
207void ICODE_ATTR INT_EXT3(void) 218void ICODE_ATTR INT_EXT3(void)
208{ 219{
209 gpio_handler(3); 220 eint_handler(3);
210} 221}
211 222
212void ICODE_ATTR INT_EXT6(void) 223void ICODE_ATTR INT_EXT6(void)
213{ 224{
214 gpio_handler(0); 225 eint_handler(0);
215}
216#endif
217
218static uint32_t gpio_data[16] =
219{
220 0x5322222F, 0xEEEEEE00, 0x2332EEEE, 0x3333E222,
221 0x33333333, 0x33333333, 0x3F000E33, 0xEEEEEEEE,
222 0xEEEEEEEE, 0xEEEEEEEE, 0xE0EEEEEE, 0xEE00EE0E,
223 0xEEEE0EEE, 0xEEEEEEEE, 0xEE2222EE, 0xEEEE0EEE
224};
225
226void gpio_preinit(void)
227{
228 for (int i = 0; i < 16; i++) {
229 PCON(i) = gpio_data[i];
230 PUNB(i) = 0;
231 PUNC(i) = 0;
232 }
233} 226}
diff --git a/firmware/target/arm/s5l8702/gpio-s5l8702.h b/firmware/target/arm/s5l8702/gpio-s5l8702.h
index 19bc36a139..9259fb05ef 100644
--- a/firmware/target/arm/s5l8702/gpio-s5l8702.h
+++ b/firmware/target/arm/s5l8702/gpio-s5l8702.h
@@ -23,6 +23,69 @@
23#define __GPIO_S5L8702_H__ 23#define __GPIO_S5L8702_H__
24#include <stdint.h> 24#include <stdint.h>
25 25
26
27#define REG32_PTR_T volatile uint32_t *
28
29/*
30 * s5l8702 External (GPIO) Interrupt Controller
31 *
32 * 7 groups of 32 interrupts, GPIO pins are seen as 'wired'
33 * to groups 6..3 in reverse order.
34 * On group 3, last four bits are dissbled (GPIO 124..127).
35 * All bits in groups 1 and 2 are disabled (not used).
36 * On group 0, all bits are masked except bits 0 and 2:
37 * bit 0: if unmasked, EINT6 is generated when ALVTCNT
38 * reachs ALVTEND.
39 * bit 2: if unmasked, EINT6 is generated when USB cable
40 * is plugged and/or(TBC) unplugged.
41 *
42 * IC_GROUP0..6 are connected to EINT6..0 of the VIC.
43 */
44#define EIC_N_GROUPS 7
45
46/* get EIC group and bit for a given GPIO port */
47#define EIC_GROUP(n) (6 - (n >> 5))
48#define EIC_INDEX(n) ((0x18 - (n & 0x18)) | (n & 0x7))
49
50/* SoC EINTs uses these 'gpio' numbers */
51#define GPIO_EINT_USB 0xd8
52#define GPIO_EINT_ALIVE 0xda
53
54/* probably a part of the system controller */
55#define EIC_BASE 0x39a00000
56
57#define EIC_INTLEVEL(g) (*((REG32_PTR_T)(EIC_BASE + 0x80 + 4*(g))))
58#define EIC_INTSTAT(g) (*((REG32_PTR_T)(EIC_BASE + 0xA0 + 4*(g))))
59#define EIC_INTEN(g) (*((REG32_PTR_T)(EIC_BASE + 0xC0 + 4*(g))))
60#define EIC_INTTYPE(g) (*((REG32_PTR_T)(EIC_BASE + 0xE0 + 4*(g))))
61
62#define EIC_INTLEVEL_LOW 0
63#define EIC_INTLEVEL_HIGH 1
64
65#define EIC_INTTYPE_EDGE 0
66#define EIC_INTTYPE_LEVEL 1
67
68
69struct eint_handler {
70 uint8_t gpio_n;
71 uint8_t type; /* EIC_INTTYPE_ */
72 uint8_t level; /* EIC_INTLEVEL_ */
73 uint8_t autoflip;
74 void (*isr)(struct eint_handler*);
75};
76
77void eint_register(struct eint_handler *h);
78void eint_unregister(struct eint_handler *h);
79void eint_init(void);
80
81void gpio_init(void);
82/* get/set configuration for GPIO groups (0..15) */
83uint32_t gpio_group_get(int group);
84void gpio_group_set(int group, uint32_t mask, uint32_t cfg);
85
86void gpio_preinit(void);
87
88
26/* This is very preliminary work in progress, ATM this region is called 89/* This is very preliminary work in progress, ATM this region is called
27 * system 'alive' because it seems there are similiarities when mixing 90 * system 'alive' because it seems there are similiarities when mixing
28 * concepts from: 91 * concepts from:
@@ -47,9 +110,6 @@
47 * +-->| 1/UNKDIV |--> Unknown 110 * +-->| 1/UNKDIV |--> Unknown
48 * |___________| 111 * |___________|
49 */ 112 */
50
51#define REG32_PTR_T volatile uint32_t *
52
53#define SYSALV_BASE 0x39a00000 113#define SYSALV_BASE 0x39a00000
54 114
55#define ALVCON (*((REG32_PTR_T)(SYSALV_BASE + 0x0))) 115#define ALVCON (*((REG32_PTR_T)(SYSALV_BASE + 0x0)))
@@ -81,67 +141,21 @@
81 141
82/* 142/*
83 * System Alive timer 143 * System Alive timer
84 */ 144 *
85/* ALVCOM_RUN_BIT starts/stops count on ALVTCNT, counter frequency 145 * ALVCOM_RUN_BIT starts/stops count on ALVTCNT, counter frequency
86 * is SClk / ALVTDIV. When count reachs ALVTEND then ALVTSTAT[0] 146 * is SClk / ALVTDIV. When count reachs ALVTEND then ALVTSTAT[0]
87 * and ALVUNK4[0] are set, optionally an interrupt is generated (see 147 * and ALVUNK4[0] are set, optionally an interrupt is generated (see
88 * GPIO_IC below). Writing 1 to ALVTCOM_RST_BIT clears ALVSTAT[0] 148 * GPIO_IC below). Writing 1 to ALVTCOM_RST_BIT clears ALVSTAT[0]
89 * and ALVUNK4[0] and initializes ALVTCNT to zero. 149 * and ALVUNK4[0] and initializes ALVTCNT to zero.
90 */ 150 */
91#define ALVTCOM (*((REG32_PTR_T)(SYSALV_BASE + 0x6c))) 151#define ALVTCOM (*((REG32_PTR_T)(SYSALV_BASE + 0x6c)))
92#define ALVTCOM_RUN_BIT (1 << 0) /* 0 -> Stop, 1 -> Start */ 152#define ALVTCOM_RUN_BIT (1 << 0) /* 0 -> Stop, 1 -> Start */
93#define ALVTCOM_RST_BIT (1 << 1) /* 1 -> Reset */ 153#define ALVTCOM_RST_BIT (1 << 1) /* 1 -> Reset */
94 154
95#define ALVTEND (*((REG32_PTR_T)(SYSALV_BASE + 0x70))) 155#define ALVTEND (*((REG32_PTR_T)(SYSALV_BASE + 0x70)))
96#define ALVTDIV (*((REG32_PTR_T)(SYSALV_BASE + 0x74))) 156#define ALVTDIV (*((REG32_PTR_T)(SYSALV_BASE + 0x74)))
97 157
98#define ALVTCNT (*((REG32_PTR_T)(SYSALV_BASE + 0x78))) 158#define ALVTCNT (*((REG32_PTR_T)(SYSALV_BASE + 0x78)))
99#define ALVTSTAT (*((REG32_PTR_T)(SYSALV_BASE + 0x7c))) 159#define ALVTSTAT (*((REG32_PTR_T)(SYSALV_BASE + 0x7c)))
100
101
102/*
103 * s5l8702 GPIO Interrupt Controller
104 */
105#define GPIOIC_BASE 0x39a00000 /* probably a part of the system controller */
106
107#define GPIOIC_INTLEVEL(g) (*((REG32_PTR_T)(GPIOIC_BASE + 0x80 + 4*(g))))
108#define GPIOIC_INTSTAT(g) (*((REG32_PTR_T)(GPIOIC_BASE + 0xA0 + 4*(g))))
109#define GPIOIC_INTEN(g) (*((REG32_PTR_T)(GPIOIC_BASE + 0xC0 + 4*(g))))
110#define GPIOIC_INTTYPE(g) (*((REG32_PTR_T)(GPIOIC_BASE + 0xE0 + 4*(g))))
111
112#define GPIOIC_INTLEVEL_LOW 0
113#define GPIOIC_INTLEVEL_HIGH 1
114
115#define GPIOIC_INTTYPE_EDGE 0
116#define GPIOIC_INTTYPE_LEVEL 1
117
118/* 7 groups of 32 interrupts, GPIO pins are seen as 'wired'
119 * to groups 6..3 in reverse order.
120 * On group 3, last four bits are dissbled (GPIO 124..127).
121 * All bits in groups 1 and 2 are disabled (not used).
122 * On group 0, all bits are masked except bits 0 and 2:
123 * bit 0: if unmasked, EINT6 is generated when ALVTCNT
124 * reachs ALVTEND.
125 * bit 2: if unmasked, EINT6 is generated when USB cable
126 * is plugged and/or(TBC) unplugged.
127 *
128 * IC_GROUP0..6 are connected to EINT6..0 of the VIC.
129 */
130
131/* get GPIOIC group and bit for a given GPIO port */
132#define IC_GROUP(n) (6 - (n >> 5))
133#define IC_IDX(n) ((0x18 - (n & 0x18)) | (n & 0x7))
134
135void gpio_init(void);
136void gpio_int_register(int gpio_n, void *isr,
137 int type, int level, int autoflip);
138void gpio_int_enable(int gpio_n);
139void gpio_int_disable(int gpio_n);
140
141/* get/set configuration for GPIO groups (0..15) */
142uint32_t gpio_group_get(int group);
143void gpio_group_set(int group, uint32_t mask, uint32_t cfg);
144
145void gpio_preinit(void);
146 160
147#endif /* __GPIO_S5L8702_H__ */ 161#endif /* __GPIO_S5L8702_H__ */
diff --git a/firmware/target/arm/s5l8702/system-s5l8702.c b/firmware/target/arm/s5l8702/system-s5l8702.c
index e94e12a153..cbe8bfcaf7 100644
--- a/firmware/target/arm/s5l8702/system-s5l8702.c
+++ b/firmware/target/arm/s5l8702/system-s5l8702.c
@@ -206,6 +206,7 @@ void system_init(void)
206 pmu_preinit(); 206 pmu_preinit();
207#endif 207#endif
208 gpio_init(); 208 gpio_init();
209 eint_init();
209 pmu_init(); 210 pmu_init();
210 dma_init(); 211 dma_init();
211#ifdef HAVE_SERIAL 212#ifdef HAVE_SERIAL