diff options
Diffstat (limited to 'firmware/target/arm/imx31/gpio-imx31.c')
-rw-r--r-- | firmware/target/arm/imx31/gpio-imx31.c | 198 |
1 files changed, 105 insertions, 93 deletions
diff --git a/firmware/target/arm/imx31/gpio-imx31.c b/firmware/target/arm/imx31/gpio-imx31.c index e368d1ae07..7a7363be88 100644 --- a/firmware/target/arm/imx31/gpio-imx31.c +++ b/firmware/target/arm/imx31/gpio-imx31.c | |||
@@ -23,7 +23,8 @@ | |||
23 | #include "config.h" | 23 | #include "config.h" |
24 | #include "system.h" | 24 | #include "system.h" |
25 | #include "avic-imx31.h" | 25 | #include "avic-imx31.h" |
26 | #include "gpio-imx31.h" | 26 | #define DEFINE_GPIO_VECTOR_TABLE |
27 | #include "gpio-target.h" | ||
27 | 28 | ||
28 | /* UIE vector found in avic-imx31.c */ | 29 | /* UIE vector found in avic-imx31.c */ |
29 | extern void UIE_VECTOR(void); | 30 | extern void UIE_VECTOR(void); |
@@ -31,101 +32,91 @@ extern void UIE_VECTOR(void); | |||
31 | /* Event lists are allocated for the specific target */ | 32 | /* Event lists are allocated for the specific target */ |
32 | #if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS) | 33 | #if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS) |
33 | static __attribute__((interrupt("IRQ"))) void GPIO1_HANDLER(void); | 34 | static __attribute__((interrupt("IRQ"))) void GPIO1_HANDLER(void); |
34 | extern const struct gpio_event gpio1_events[GPIO1_NUM_EVENTS]; | ||
35 | #endif | 35 | #endif |
36 | 36 | ||
37 | #if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS) | 37 | #if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS) |
38 | static __attribute__((interrupt("IRQ"))) void GPIO2_HANDLER(void); | 38 | static __attribute__((interrupt("IRQ"))) void GPIO2_HANDLER(void); |
39 | extern const struct gpio_event gpio2_events[GPIO2_NUM_EVENTS]; | ||
40 | #endif | 39 | #endif |
41 | 40 | ||
42 | #if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS) | 41 | #if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS) |
43 | static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void); | 42 | static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void); |
44 | extern const struct gpio_event gpio3_events[GPIO3_NUM_EVENTS]; | ||
45 | #endif | 43 | #endif |
46 | 44 | ||
47 | #define DR (0x00 / sizeof (unsigned long)) /* 00h */ | 45 | static struct gpio_module_desc |
48 | #define GDIR (0x04 / sizeof (unsigned long)) /* 04h */ | ||
49 | #define PSR (0x08 / sizeof (unsigned long)) /* 08h */ | ||
50 | #define ICR (0x0C / sizeof (unsigned long)) /* 0Ch ICR1,2 */ | ||
51 | #define IMR (0x14 / sizeof (unsigned long)) /* 14h */ | ||
52 | #define ISR (0x18 / sizeof (unsigned long)) | ||
53 | |||
54 | static const struct gpio_module_desc | ||
55 | { | 46 | { |
56 | volatile unsigned long * const base; /* Module base address */ | 47 | volatile unsigned long * const base; /* Module base address */ |
57 | void (* const handler)(void); /* Interrupt function */ | 48 | void (* const handler)(void); /* Interrupt function */ |
58 | const struct gpio_event * const events; /* Event handler list */ | 49 | const struct gpio_event *events; /* Event handler list */ |
50 | unsigned long enabled; /* Enabled event mask */ | ||
59 | const uint8_t ints; /* AVIC int number */ | 51 | const uint8_t ints; /* AVIC int number */ |
60 | const uint8_t int_priority; /* AVIC int priority */ | 52 | const uint8_t int_priority; /* AVIC int priority */ |
61 | const uint8_t count; /* Number of events */ | 53 | uint8_t count; /* Number of events */ |
62 | } gpio_descs[GPIO_NUM_GPIO] = | 54 | } * const gpio_descs[] = |
63 | { | 55 | { |
64 | #if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS) | 56 | #if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS) |
65 | { | 57 | [GPIO1_NUM] = &(struct gpio_module_desc) { |
66 | .base = (unsigned long *)GPIO1_BASE_ADDR, | 58 | .base = (unsigned long *)GPIO1_BASE_ADDR, |
67 | .ints = INT_GPIO1, | 59 | .ints = INT_GPIO1, |
68 | .handler = GPIO1_HANDLER, | 60 | .handler = GPIO1_HANDLER, |
69 | .events = gpio1_events, | ||
70 | .count = GPIO1_NUM_EVENTS, | ||
71 | .int_priority = GPIO1_INT_PRIO | 61 | .int_priority = GPIO1_INT_PRIO |
72 | }, | 62 | }, |
73 | #endif | 63 | #endif |
74 | #if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS) | 64 | #if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS) |
75 | { | 65 | [GPIO2_NUM] = &(struct gpio_module_desc) { |
76 | .base = (unsigned long *)GPIO2_BASE_ADDR, | 66 | .base = (unsigned long *)GPIO2_BASE_ADDR, |
77 | .ints = INT_GPIO2, | 67 | .ints = INT_GPIO2, |
78 | .handler = GPIO2_HANDLER, | 68 | .handler = GPIO2_HANDLER, |
79 | .events = gpio2_events, | ||
80 | .count = GPIO2_NUM_EVENTS, | ||
81 | .int_priority = GPIO2_INT_PRIO | 69 | .int_priority = GPIO2_INT_PRIO |
82 | }, | 70 | }, |
83 | #endif | 71 | #endif |
84 | #if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS) | 72 | #if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS) |
85 | { | 73 | [GPIO3_NUM] = &(struct gpio_module_desc) { |
86 | .base = (unsigned long *)GPIO3_BASE_ADDR, | 74 | .base = (unsigned long *)GPIO3_BASE_ADDR, |
87 | .ints = INT_GPIO3, | 75 | .ints = INT_GPIO3, |
88 | .handler = GPIO3_HANDLER, | 76 | .handler = GPIO3_HANDLER, |
89 | .events = gpio3_events, | ||
90 | .count = GPIO3_NUM_EVENTS, | ||
91 | .int_priority = GPIO3_INT_PRIO, | 77 | .int_priority = GPIO3_INT_PRIO, |
92 | }, | 78 | }, |
93 | #endif | 79 | #endif |
94 | }; | 80 | }; |
95 | 81 | ||
82 | #define GPIO_MODULE_CNT ARRAYLEN(gpio_descs) | ||
83 | |||
84 | static const struct gpio_event * event_from_id( | ||
85 | const struct gpio_module_desc *desc, enum gpio_id id) | ||
86 | { | ||
87 | const struct gpio_event *events = desc->events; | ||
88 | for (unsigned int i = 0; i < desc->count; i++) | ||
89 | { | ||
90 | if (events[i].id == id) | ||
91 | return &events[i]; | ||
92 | } | ||
93 | |||
94 | return NULL; | ||
95 | } | ||
96 | |||
96 | static void gpio_call_events(enum gpio_module_number gpio) | 97 | static void gpio_call_events(enum gpio_module_number gpio) |
97 | { | 98 | { |
98 | const struct gpio_module_desc * const desc = &gpio_descs[gpio]; | 99 | const struct gpio_module_desc * const desc = gpio_descs[gpio]; |
99 | volatile unsigned long * const base = desc->base; | 100 | volatile unsigned long * const base = desc->base; |
100 | const struct gpio_event * event, *event_last; | ||
101 | 101 | ||
102 | event = desc->events; | 102 | /* Send only events that are not masked */ |
103 | event_last = event + desc->count; | 103 | unsigned long pnd = base[GPIO_ISR] & base[GPIO_IMR]; |
104 | 104 | ||
105 | /* Intersect pending and unmasked bits */ | 105 | if (pnd & ~desc->enabled) |
106 | unsigned long pnd = base[ISR] & base[IMR]; | 106 | UIE_VECTOR(); /* One or more aren't handled properly */ |
107 | 107 | ||
108 | /* Call each event handler in order */ | 108 | const struct gpio_event *event = desc->events; |
109 | /* .count is surely expected to be > 0 */ | ||
110 | do | ||
111 | { | ||
112 | unsigned long mask = event->mask; | ||
113 | 109 | ||
110 | while (pnd) | ||
111 | { | ||
112 | unsigned long mask = 1ul << (event->id % 32); | ||
114 | if (pnd & mask) | 113 | if (pnd & mask) |
115 | { | 114 | { |
116 | event->callback(); | 115 | event->callback(); |
117 | pnd &= ~mask; | 116 | pnd &= ~mask; |
118 | } | 117 | } |
119 | 118 | ||
120 | if (pnd == 0) | 119 | event++; |
121 | break; /* Teminate early if nothing more to service */ | ||
122 | } | ||
123 | while (++event < event_last); | ||
124 | |||
125 | if (pnd != 0) | ||
126 | { | ||
127 | /* One or more weren't handled */ | ||
128 | UIE_VECTOR(); | ||
129 | } | 120 | } |
130 | } | 121 | } |
131 | 122 | ||
@@ -152,69 +143,90 @@ static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void) | |||
152 | 143 | ||
153 | void INIT_ATTR gpio_init(void) | 144 | void INIT_ATTR gpio_init(void) |
154 | { | 145 | { |
155 | /* Mask-out GPIO interrupts - enable what's wanted later */ | 146 | for (unsigned int mod = 0; mod < GPIO_MODULE_CNT; mod++) |
156 | int i; | 147 | { |
157 | for (i = 0; i < GPIO_NUM_GPIO; i++) | 148 | struct gpio_module_desc * const desc = gpio_descs[mod]; |
158 | gpio_descs[i].base[IMR] = 0; | 149 | if (!desc) |
150 | continue; | ||
151 | |||
152 | /* Parse the event table per module. First contiguous run seen for a | ||
153 | * module is used. */ | ||
154 | const struct gpio_event *event = gpio_event_vector_tbl; | ||
155 | for (unsigned int i = 0; i < gpio_event_vector_tbl_len; i++, event++) | ||
156 | { | ||
157 | if (event->id / 32 == mod) | ||
158 | { | ||
159 | desc->events = event; | ||
160 | while (++desc->count < 32 && (++event)->id / 32 == mod); | ||
161 | break; | ||
162 | } | ||
163 | } | ||
164 | |||
165 | /* Mask-out GPIO interrupts - enable what's wanted later */ | ||
166 | desc->base[GPIO_IMR] = 0; | ||
167 | } | ||
159 | } | 168 | } |
160 | 169 | ||
161 | bool gpio_enable_event(enum gpio_event_ids id) | 170 | bool gpio_enable_event(enum gpio_id id, bool enable) |
162 | { | 171 | { |
163 | const struct gpio_module_desc * const desc = &gpio_descs[id >> 5]; | 172 | unsigned int mod = id / 32; |
164 | const struct gpio_event * const event = &desc->events[id & 31]; | ||
165 | volatile unsigned long * const base = desc->base; | ||
166 | volatile unsigned long *icr; | ||
167 | unsigned long mask, line; | ||
168 | unsigned long imr; | ||
169 | int shift; | ||
170 | 173 | ||
171 | int oldlevel = disable_irq_save(); | 174 | struct gpio_module_desc * const desc = gpio_descs[mod]; |
172 | 175 | ||
173 | imr = base[IMR]; | 176 | if (mod >= GPIO_MODULE_CNT || desc == NULL) |
177 | return false; | ||
174 | 178 | ||
175 | if (imr == 0) | 179 | const struct gpio_event * const event = event_from_id(desc, id); |
176 | { | 180 | if (!event) |
177 | /* First enabled interrupt for this GPIO */ | 181 | return false; |
178 | avic_enable_int(desc->ints, INT_TYPE_IRQ, desc->int_priority, | ||
179 | desc->handler); | ||
180 | } | ||
181 | |||
182 | /* Set the line sense */ | ||
183 | line = find_first_set_bit(event->mask); | ||
184 | icr = &base[ICR + (line >> 4)]; | ||
185 | shift = 2*(line & 15); | ||
186 | mask = GPIO_SENSE_CONFIG_MASK << shift; | ||
187 | 182 | ||
188 | *icr = (*icr & ~mask) | ((event->sense << shift) & mask); | 183 | volatile unsigned long * const base = desc->base; |
184 | unsigned long num = id % 32; | ||
185 | unsigned long mask = 1ul << num; | ||
189 | 186 | ||
190 | /* Unmask the line */ | 187 | unsigned long cpsr = disable_irq_save(); |
191 | base[IMR] = imr | event->mask; | ||
192 | 188 | ||
193 | restore_irq(oldlevel); | 189 | unsigned long imr = base[GPIO_IMR]; |
194 | 190 | ||
195 | return true; | 191 | if (enable) |
196 | } | 192 | { |
193 | if (desc->enabled == 0) | ||
194 | { | ||
195 | /* First enabled interrupt for this GPIO */ | ||
196 | avic_enable_int(desc->ints, INT_TYPE_IRQ, desc->int_priority, | ||
197 | desc->handler); | ||
198 | } | ||
197 | 199 | ||
198 | void gpio_disable_event(enum gpio_event_ids id) | 200 | /* Set the line sense */ |
199 | { | 201 | if (event->sense == GPIO_SENSE_EDGE_SEL) |
200 | const struct gpio_module_desc * const desc = &gpio_descs[id >> 5]; | 202 | { |
201 | const struct gpio_event * const event = &desc->events[id & 31]; | 203 | /* Interrupt configuration register is ignored */ |
202 | volatile unsigned long * const base = desc->base; | 204 | base[GPIO_EDGE_SEL] |= mask; |
203 | unsigned long imr; | 205 | } |
206 | else | ||
207 | { | ||
208 | volatile unsigned long *icrp = &base[GPIO_ICR + num / 16]; | ||
209 | unsigned int shift = 2*(num % 16); | ||
210 | bitmod32(icrp, event->sense << shift, 0x3 << shift); | ||
211 | base[GPIO_EDGE_SEL] &= ~mask; | ||
212 | } | ||
204 | 213 | ||
205 | int oldlevel = disable_irq_save(); | 214 | /* Unmask the line */ |
215 | desc->enabled |= mask; | ||
216 | imr |= mask; | ||
217 | } | ||
218 | else | ||
219 | { | ||
220 | imr &= ~mask; | ||
221 | desc->enabled &= ~mask; | ||
206 | 222 | ||
207 | /* Remove bit from mask */ | 223 | if (desc->enabled == 0) |
208 | imr = base[IMR] & ~event->mask; | 224 | avic_disable_int(desc->ints); /* No events remain enabled */ |
225 | } | ||
209 | 226 | ||
210 | /* Mask the line */ | 227 | base[GPIO_IMR] = imr; |
211 | base[IMR] = imr; | ||
212 | 228 | ||
213 | if (imr == 0) | 229 | restore_irq(cpsr); |
214 | { | ||
215 | /* No events remain enabled */ | ||
216 | avic_disable_int(desc->ints); | ||
217 | } | ||
218 | 230 | ||
219 | restore_irq(oldlevel); | 231 | return true; |
220 | } | 232 | } |