]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/hal/arm/sa11x0/ipaq/v2_0/src/atmel_support.c
Initial revision
[karo-tx-redboot.git] / packages / hal / arm / sa11x0 / ipaq / v2_0 / src / atmel_support.c
1 //==========================================================================
2 //
3 //        atmel_support.c
4 //
5 //        SA1110/iPAQ - Atmel micro-controller support routines
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):     gthomas
44 // Contributors:  gthomas
45 // Date:          2001-02-27
46 // Description:   Simple Atmel support
47 //####DESCRIPTIONEND####
48
49 #include <pkgconf/system.h>
50 #include <pkgconf/hal.h>
51
52 #ifdef CYGPKG_REDBOOT
53 #include <redboot.h>
54 #endif
55
56 #include <cyg/infra/diag.h>
57 #include <cyg/hal/hal_if.h>       // Virtual vector functions
58 #include <cyg/hal/hal_io.h>       // IO macros
59 #include <cyg/hal/hal_arch.h>     // Register state info
60 #include <cyg/hal/hal_intr.h>     // HAL interrupt macros
61
62 #include <cyg/hal/hal_sa11x0.h>   // Board definitions
63 #include <cyg/hal/ipaq.h>
64 #include <cyg/hal/hal_cache.h>
65
66 #ifdef CYGPKG_IO
67 // Need to export interrupt driven interfaces
68 #include <cyg/hal/drv_api.h>
69 #define ATMEL_INT CYGNUM_HAL_INTERRUPT_UART1
70 static cyg_interrupt atmel_interrupt;
71 static cyg_handle_t  atmel_interrupt_handle;
72 #endif
73
74 #include <cyg/hal/atmel_support.h>        // Interfaces, commands
75
76 externC void *memcpy(void *, const void *, size_t);
77
78 struct sa11x0_serial {
79   volatile cyg_uint32 utcr0;
80   volatile cyg_uint32 utcr1;
81   volatile cyg_uint32 utcr2;
82   volatile cyg_uint32 utcr3;
83   volatile cyg_uint32 pad0010;
84   volatile cyg_uint32 utdr;
85   volatile cyg_uint32 pad0018;
86   volatile cyg_uint32 utsr0;
87   volatile cyg_uint32 utsr1;
88 };
89
90 #define ATMEL_PUTQ_SIZE 32
91 unsigned char atmel_putq[ATMEL_PUTQ_SIZE];
92 int atmel_putq_put, atmel_putq_get;
93
94 bool atmel_use_ints;
95
96 void
97 atmel_putc(unsigned char c)
98 {
99     atmel_putq[atmel_putq_put++] = c;
100     if (atmel_putq_put == ATMEL_PUTQ_SIZE) {
101         atmel_putq_put = 0;
102     }
103 }
104
105 static atmel_handler *handlers[NUM_ATMEL_CMDS];
106
107 static void
108 null_handler(atmel_pkt *pkt)
109 {
110     diag_printf("Atmel - packet ignored: %x\n", pkt->data[0]);
111     diag_dump_buf(pkt->data, 16);
112 }
113
114 //
115 // Register a handler for a particular packet type
116 //
117 void 
118 atmel_register(int cmd, atmel_handler *fun)
119 {
120     handlers[cmd] = fun;
121 }
122
123 //
124 // This routine is called to process an input character from the
125 // Atmel micro-controller.  Since command packets are multiple
126 // characters, this routine has to keep state for the packet.  Once
127 // a complete packet is received, the appropriate handler function
128 // will be called (if the checksum matches)
129 //
130 static void
131 atmel_in(unsigned char ch)
132 {
133     static atmel_pkt pkt;
134     static unsigned char cksum;
135     static bool sof = false;
136
137     if (!sof) {
138         // Wait for start of packet (SOF)
139         if (ch != SOF) {
140             return;  // Just ignore out of order characters
141         }
142         sof = true;
143         pkt.size = 0;
144         return;
145     }
146     if (pkt.size == 0) {
147         // First byte of packet - command+length;
148         pkt.len = (ch & 0x0F) + 1;
149         cksum = 0;
150     }
151     pkt.data[pkt.size++] = ch;
152     if (pkt.size > pkt.len) {
153         // End of packet data
154         if (cksum == ch) {
155             (*handlers[pkt.data[0] >> 4])(&pkt);
156         }
157         sof = false;
158     } else {
159         cksum += ch;
160     }
161 }
162
163 //
164 // This [internal] routine is used to handle data from the Atmel micro-controller
165 //
166 static void
167 atmel_poll(void)
168 {
169     volatile struct sa11x0_serial *base = (volatile struct sa11x0_serial *)SA11X0_UART1_BASE;
170     unsigned char ch;
171
172     while ((base->utsr1 & SA11X0_UART_RX_FIFO_NOT_EMPTY) != 0) {
173         ch = (char)base->utdr;
174         atmel_in(ch);
175     }
176 }
177
178 //
179 // This [internal] routine is used to send data to the Atmel micro-controller
180 //
181 static void
182 atmel_flush(void)
183 {
184     volatile struct sa11x0_serial *base = (volatile struct sa11x0_serial *)SA11X0_UART1_BASE;
185
186 #ifdef CYGPKG_IO
187     cyg_drv_isr_lock();
188 #endif
189     while (atmel_putq_get != atmel_putq_put) {
190         if ((base->utsr1 & SA11X0_UART_TX_FIFO_NOT_FULL) == 0) {
191             // Wait forever if in non-interrupt mode
192             if (atmel_use_ints) {
193                 break;
194             }
195         } else {
196             base->utdr = atmel_putq[atmel_putq_get++];
197             if (atmel_putq_get == ATMEL_PUTQ_SIZE) {
198                 atmel_putq_get = 0;
199             }
200         }
201     }
202 #ifdef CYGPKG_IO
203     cyg_drv_isr_unlock();
204 #endif
205 }
206
207 #ifdef CYGPKG_IO
208
209 // Low level interrupt handler (ISR)
210 static cyg_uint32 
211 atmel_ISR(cyg_vector_t vector, cyg_addrword_t data)
212 {
213     cyg_drv_interrupt_mask(vector);
214     cyg_drv_interrupt_acknowledge(vector);
215     return CYG_ISR_CALL_DSR;  // Cause DSR to be run
216 }
217
218 // High level interrupt handler (DSR)
219 static void       
220 atmel_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
221 {
222     volatile struct sa11x0_serial *base = (volatile struct sa11x0_serial *)SA11X0_UART1_BASE;
223     unsigned int stat0 = base->utsr0;
224
225     if (stat0 & SA11X0_UART_TX_SERVICE_REQUEST) {
226         atmel_flush();
227     }
228     if (stat0 & (SA11X0_UART_RX_SERVICE_REQUEST|SA11X0_UART_RX_IDLE)) {
229         atmel_poll();
230         base->utsr0 = SA11X0_UART_RX_IDLE;  // Need to clear this manually
231     }
232     cyg_drv_interrupt_unmask(vector);
233 }
234
235 //
236 // Connect/disconnect interrupt processing
237 //
238 void
239 atmel_interrupt_mode(bool enable)
240 {
241     volatile struct sa11x0_serial *base = (volatile struct sa11x0_serial *)SA11X0_UART1_BASE;
242
243     if (enable) {
244         // Enable the receiver (with interrupts) and the transmitter.
245         base->utcr3 = SA11X0_UART_RX_ENABLED |
246                       SA11X0_UART_TX_ENABLED |
247                       SA11X0_UART_RX_FIFO_INT_ENABLED;
248         cyg_drv_interrupt_unmask(ATMEL_INT);
249     } else {
250         cyg_drv_interrupt_mask(ATMEL_INT);
251     }
252     atmel_use_ints = enable;
253 }
254 #endif
255
256 //
257 // Set up the Atmel micro-controller environment
258 //
259 void
260 atmel_init(void)
261 {
262     volatile struct sa11x0_serial *base = (volatile struct sa11x0_serial *)SA11X0_UART1_BASE;
263     cyg_uint32 brd;
264     int i;
265     static bool _init = false;
266
267     if (_init) return;
268
269     // Disable Receiver and Transmitter (clears FIFOs)
270     base->utcr3 = SA11X0_UART_RX_DISABLED | SA11X0_UART_TX_DISABLED;
271
272     // Clear sticky (writable) status bits.
273     base->utsr0 = SA11X0_UART_RX_IDLE | SA11X0_UART_RX_BEGIN_OF_BREAK |
274                   SA11X0_UART_RX_END_OF_BREAK;
275
276     // Set UART to 8N1 (8 data bits, no partity, 1 stop bit)
277     base->utcr0 = SA11X0_UART_PARITY_DISABLED | SA11X0_UART_STOP_BITS_1 |
278                   SA11X0_UART_DATA_BITS_8;
279
280     // Set the desired baud rate.
281     brd = SA11X0_UART_BAUD_RATE_DIVISOR(115200);
282     base->utcr1 = (brd >> 8) & SA11X0_UART_H_BAUD_RATE_DIVISOR_MASK;
283     base->utcr2 = brd & SA11X0_UART_L_BAUD_RATE_DIVISOR_MASK;
284
285     // Enable the receiver and the transmitter.
286     base->utcr3 = SA11X0_UART_RX_ENABLED | SA11X0_UART_TX_ENABLED;
287
288     // Set up character queues
289     atmel_putq_put = atmel_putq_get = 0;
290     atmel_use_ints = false;
291
292     // Set up handlers
293     for (i = 0;  i < NUM_ATMEL_CMDS;  i++) {
294         atmel_register(i, null_handler);
295     }
296
297 #ifdef CYGPKG_IO
298     cyg_drv_interrupt_create(ATMEL_INT,
299                              99,                     // Priority - unused
300                              (cyg_addrword_t)base,   // Data item passed to interrupt handler
301                              atmel_ISR,
302                              atmel_DSR,
303                              &atmel_interrupt_handle,
304                              &atmel_interrupt);
305     cyg_drv_interrupt_attach(atmel_interrupt_handle);
306 #endif
307
308     _init = true;
309 }
310
311 static void
312 atmel_pkt_send(atmel_pkt *pkt)
313 {
314     int i;
315
316     for (i = 0;  i < pkt->len;  i++) {
317         atmel_putc(pkt->data[i]);
318     }
319     atmel_flush();
320 }
321
322 bool
323 atmel_send(int cmd, unsigned char *data, int len)
324 {
325     atmel_pkt pkt;
326     unsigned char cksum, *dp;
327     int i;
328
329     dp = pkt.data;
330     *dp++ = SOF;
331     *dp++ = cksum = (cmd << 4) | len;
332     for (i = 0;  i < len;  i++) {
333         *dp++ = data[i];
334         cksum += data[i];
335     }
336     *dp = cksum;
337     pkt.len = len + 3;
338     atmel_pkt_send(&pkt);
339     return true;
340 }
341
342 #define MAX_TS_EVENTS      32
343 static struct ts_event ts_event_list[MAX_TS_EVENTS];
344 static int num_ts_events = 0;
345 static int ts_event_get, ts_event_put;
346
347 static void
348 ts_event_handler(atmel_pkt *pkt)
349 {
350     unsigned char *buf = pkt->data;
351     static bool up = true;
352     static int down_count = 0;
353     struct ts_event *tse;
354
355     if (num_ts_events == MAX_TS_EVENTS) {
356         return;
357     }
358     if ((buf[0] & 0x0F) == 0) {
359         // Stylus up
360         up = true;
361         down_count = 0;
362         tse = &ts_event_list[ts_event_put++];
363         if (ts_event_put == MAX_TS_EVENTS) {
364             ts_event_put = 0;
365         }
366         num_ts_events++;
367         tse->x = (buf[1] << 8) | buf[2];
368         tse->y = (buf[3] << 8) | buf[4];
369         tse->up = up;
370     } else {
371         up = false;
372         if (down_count++ == 0) {
373             // First 'down' event
374         } else {
375         }
376         {
377             tse = &ts_event_list[ts_event_put++];
378             if (ts_event_put == MAX_TS_EVENTS) {
379                 ts_event_put = 0;
380             }
381             num_ts_events++;
382             tse->x = (buf[1] << 8) | buf[2];
383             tse->y = (buf[3] << 8) | buf[4];
384             tse->up = up;
385         }
386     }
387 }
388
389 bool
390 ts_get_event(struct ts_event *tse)
391 {
392     static bool _init = false;
393
394     if (!_init) {
395         atmel_register(ATMEL_CMD_TOUCH, ts_event_handler);
396         atmel_register(ATMEL_CMD_UNKNOWN, ts_event_handler);
397         _init = true;
398     }
399
400     if (num_ts_events == 0) {
401         atmel_poll();
402     }
403     if (num_ts_events) {
404         num_ts_events--;
405         memcpy(tse, &ts_event_list[ts_event_get++], sizeof(*tse));
406         if (ts_event_get == MAX_TS_EVENTS) {
407             ts_event_get = 0;
408         }
409         return true;
410     } else {
411         return false;
412     }
413 }
414
415 #define MAX_KEY_EVENTS     8
416 static struct key_event key_event_list[MAX_KEY_EVENTS];
417 static int num_key_events = 0;
418 static int key_event_get, key_event_put;
419
420 static void
421 kbd_event_handler(atmel_pkt *pkt)
422 {
423     unsigned char *buf = pkt->data;
424     struct key_event *ke;
425
426     if (num_key_events == MAX_KEY_EVENTS) {
427         return;
428     }
429 //    printf("Keybd = %x\n", buf[1]);
430     ke = &key_event_list[key_event_put++];
431     if (key_event_put == MAX_KEY_EVENTS) {
432         key_event_put = 0;
433     }
434     ke->button_info = buf[1];
435     num_key_events++;
436 }
437
438 bool
439 key_get_event(struct key_event *ke)
440 {
441     static bool _init = false;
442
443     if (!_init) {
444         atmel_register(ATMEL_CMD_KEYBD, kbd_event_handler);
445         _init = true;
446     }
447
448     if (num_key_events == 0) {
449         atmel_poll();
450     }
451     if (num_key_events) {
452         num_key_events--;
453         memcpy(ke, &key_event_list[key_event_get++], sizeof(*ke));
454         if (key_event_get == MAX_KEY_EVENTS) {
455             key_event_get = 0;
456         }
457         return true;
458     } else {
459         return false;
460     }
461 }
462
463 #ifdef CYGPKG_REDBOOT
464
465 void
466 atmel_check(bool is_idle)
467 {
468 }
469 RedBoot_idle(atmel_check, RedBoot_BEFORE_NETIO);
470 #endif