]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/hal/arm/aim711/v2_0/src/aim711_misc.c
Initial revision
[karo-tx-redboot.git] / packages / hal / arm / aim711 / v2_0 / src / aim711_misc.c
1 //==========================================================================
2 //
3 //      aim711_misc.c
4 //
5 //      HAL misc board support code for ARM Industrial Module AIM 711
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, jskov, r.cassebohm
45 //               Michael Checky <Michael_Checky@ThermoKing.com>
46 //               Grant Edwards <grante@visi.com>
47 // Date:         2001-07-31
48 // Purpose:      HAL board support
49 // Description:  Implementations of HAL board interfaces
50 //
51 //####DESCRIPTIONEND####
52 //
53 //========================================================================*/
54
55 #include <pkgconf/hal.h>
56
57 #include <cyg/infra/cyg_type.h>         // base types
58 #include <cyg/infra/cyg_trac.h>         // tracing macros
59 #include <cyg/infra/cyg_ass.h>          // assertion macros
60 #include <cyg/infra/diag.h>             // diag_printf()
61
62 #include <cyg/hal/hal_io.h>             // IO macros
63 #include <cyg/hal/hal_arch.h>           // Register state info
64 #include <cyg/hal/hal_diag.h>
65 #include <cyg/hal/hal_cache.h>
66 #include <cyg/hal/hal_intr.h>           // necessary?
67 #include <cyg/hal/hal_if.h>             // calling interface
68 #include <cyg/hal/hal_misc.h>           // helper functions
69 #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
70 #include <cyg/hal/drv_api.h>            // HAL ISR support
71 #endif
72
73 #include <pkgconf/system.h>
74
75 #ifndef MIN
76 #define MIN(_x_,_y_) ((_x_) < (_y_) ? (_x_) : (_y_))
77 #endif
78 #ifndef MAX
79 #define MAX(_x_,_y_) ((_x_) > (_y_) ? (_x_) : (_y_))
80 #endif
81
82 //======================================================================
83 // Use Timer0 for kernel clock
84
85 static cyg_uint32 _period;
86
87 #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
88 #if 0 // Not supported yet
89 static cyg_interrupt abort_interrupt;
90 static cyg_handle_t  abort_interrupt_handle;
91
92 // This ISR is called only for the Abort button interrupt
93 static int
94 ks32c_abort_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs)
95 {
96     cyg_hal_user_break((CYG_ADDRWORD*)regs);
97     cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_EXT2);
98     return 0;  // No need to run DSR
99 }
100 #endif
101 #endif
102
103 void hal_clock_initialize(cyg_uint32 period)
104 {
105     cyg_uint32 tmod, clkcon;
106
107     // Disable timer 0
108     HAL_READ_UINT32(KS32C_TMOD, tmod);
109     tmod &= ~(KS32C_TMOD_TE0);
110     HAL_WRITE_UINT32(KS32C_TMOD, 0);
111
112     tmod &= ~(KS32C_TMOD_TMD0 | KS32C_TMOD_TCLR0);
113     tmod |= KS32C_TMOD_TE0;
114
115     // Set counter
116     HAL_READ_UINT32(KS32C_CLKCON, clkcon);
117     period = period/((clkcon & 0xffff) + 1);
118     HAL_WRITE_UINT32(KS32C_TDATA0, period);
119
120     // And enable timer
121     HAL_WRITE_UINT32(KS32C_TMOD, tmod);
122
123     _period = period;
124
125 #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
126 #if 0 // Not supported yet
127     cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_EXT2,
128                              99,           // Priority
129                              0,            // Data item passed to interrupt handler
130                              ks32c_abort_isr,
131                              0,
132                              &abort_interrupt_handle,
133                              &abort_interrupt);
134     cyg_drv_interrupt_attach(abort_interrupt_handle);
135     cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_EXT2);
136 #endif
137 #endif
138 }
139
140 void hal_clock_reset(cyg_uint32 vector, cyg_uint32 period)
141 {
142     _period = period;
143 }
144
145 void hal_clock_read(cyg_uint32 *pvalue)
146 {
147     cyg_uint32 value;
148
149     HAL_READ_UINT32(KS32C_TCNT0, value);
150     *pvalue = _period - value;
151 }
152
153 static void
154 hal_ks32c_i2c_init(void);
155
156 //======================================================================
157 // Interrupt controller stuff
158
159 void hal_hardware_init(void)
160 {
161     cyg_uint32 intmask, syscfg, val;
162
163     // Setup external IO timing
164     // Timing for Ext0 is for external 16550 UART, all other are default values
165     val = ( KS32C_EXTACON_INIT(1,1,3,0) << KS32C_EXTACON0_EXT0_shift ) \
166             | ( KS32C_EXTACON_INIT(1,1,3,1) << KS32C_EXTACON0_EXT1_shift );
167     HAL_WRITE_UINT32(KS32C_EXTACON0, val);
168     val = ( KS32C_EXTACON_INIT(1,1,3,1) << KS32C_EXTACON1_EXT2_shift ) \
169             | ( KS32C_EXTACON_INIT(1,1,3,1) << KS32C_EXTACON1_EXT3_shift );
170     HAL_WRITE_UINT32(KS32C_EXTACON1, val);
171
172     // Setup GPIO ports
173     HAL_READ_UINT32(KS32C_IOPMOD, val);
174     val |= (AIM711_GPIO_DOUT0_DAK0|AIM711_GPIO_DOUT1_DAK1 \
175             |AIM711_GPIO_DOUT2_TO0|AIM711_GPIO_DOUT3_TO1 \
176             |AIM711_GPIO_POWERLED);
177     HAL_WRITE_UINT32(KS32C_IOPMOD, val);
178
179     // Make Power LED on
180     AIM711_GPIO_SET(AIM711_GPIO_POWERLED);
181
182     // Enable XIRQ0 for external 16550 UART
183     HAL_READ_UINT32(KS32C_IOPCON, val);
184     val &= ~( KS32C_IOPCON_XIRQ_MASK << KS32C_IOPCON_XIRQ0_shift );
185     val |= ( KS32C_IOPCON_XIRQ_LEVEL|KS32C_IOPCON_XIRQ_AKTIV_HI| \
186             KS32C_IOPCON_XIRQ_ENABLE ) << KS32C_IOPCON_XIRQ0_shift ;
187     HAL_WRITE_UINT32(KS32C_IOPCON, val);
188
189     // Set up eCos/ROM interfaces
190     hal_if_init();
191
192     // Enable cache
193     HAL_READ_UINT32(KS32C_SYSCFG, syscfg);
194     syscfg &= ~KS32C_SYSCFG_CM_MASK;
195     syscfg |= KS32C_SYSCFG_CM_0R_8C|KS32C_SYSCFG_WE;
196     HAL_WRITE_UINT32(KS32C_SYSCFG, syscfg);
197     HAL_UCACHE_INVALIDATE_ALL();
198     HAL_UCACHE_ENABLE();
199
200     // Setup I2C bus
201     hal_ks32c_i2c_init();
202
203     // Clear global interrupt mask bit
204     HAL_READ_UINT32(KS32C_INTMSK, intmask);
205     intmask &= ~KS32C_INTMSK_GLOBAL;
206     HAL_WRITE_UINT32(KS32C_INTMSK, intmask);
207 }
208
209 // This routine is called to respond to a hardware interrupt (IRQ).  It
210 // should interrogate the hardware and return the IRQ vector number.
211
212 int hal_IRQ_handler(void)
213 {
214     // Do hardware-level IRQ handling
215     cyg_uint32 irq_status;
216     HAL_READ_UINT32(KS32C_INTOFFSET_IRQ, irq_status);
217     irq_status = irq_status / 4;
218     if (CYGNUM_HAL_ISR_MAX >= irq_status)
219         return irq_status;
220     // It's a bit bogus to test for FIQs after IRQs, but we use the
221     // latter more, so don't impose the overhead of checking for FIQs
222     HAL_READ_UINT32(KS32C_INTOFFSET_FIQ, irq_status);
223     irq_status = irq_status / 4;
224     if (CYGNUM_HAL_ISR_MAX >= irq_status)
225         return irq_status;
226     return CYGNUM_HAL_INTERRUPT_NONE;
227 }
228
229 // -------------------------------------------------------------------------
230 //
231 // Interrupt control
232 //
233
234 void hal_interrupt_mask(int vector)
235 {
236     cyg_uint32 mask, old_mask;
237     HAL_READ_UINT32(KS32C_INTMSK, mask);
238     old_mask = mask;
239     mask |= (1<<vector);
240     HAL_WRITE_UINT32(KS32C_INTMSK, mask);
241 }
242
243 void hal_interrupt_unmask(int vector)
244 {
245     cyg_uint32 mask, old_mask;
246     HAL_READ_UINT32(KS32C_INTMSK, mask);
247     old_mask = mask;
248     mask &= ~(1<<vector);
249     HAL_WRITE_UINT32(KS32C_INTMSK, mask);
250 }
251
252 void hal_interrupt_acknowledge(int vector)
253 {
254     HAL_WRITE_UINT32(KS32C_INTPND, (1<<vector));
255 }
256
257 void hal_interrupt_configure(int vector, int level, int up)
258 {
259 }
260
261 void hal_interrupt_set_level(int vector, int level)
262 {
263 }
264
265 void hal_show_IRQ(int vector, int data, int handler)
266 {
267 }
268
269 // -------------------------------------------------------------------------
270 //
271 // Delay for some number of micro-seconds
272 //
273 void hal_delay_us(cyg_int32 usecs)
274 {
275     cyg_uint32 count;
276     cyg_uint32 ticks = ((CYGNUM_HAL_RTC_PERIOD*CYGNUM_HAL_RTC_DENOMINATOR)/1000000) * usecs;
277     cyg_uint32 tmod;
278
279     // Disable timer 1
280     HAL_READ_UINT32(KS32C_TMOD, tmod);
281     tmod &= ~(KS32C_TMOD_TE1);
282     HAL_WRITE_UINT32(KS32C_TMOD, tmod);
283
284     tmod &= ~(KS32C_TMOD_TMD1 | KS32C_TMOD_TCLR1);
285     tmod |= KS32C_TMOD_TE1;
286
287     // Clear pending flag
288     HAL_WRITE_UINT32(KS32C_INTPND, (1 << CYGNUM_HAL_INTERRUPT_TIMER1));
289
290     // Set counter
291     HAL_WRITE_UINT32(KS32C_TDATA1, ticks);
292
293     // And enable timer
294     HAL_WRITE_UINT32(KS32C_TMOD, tmod);
295
296     // Wait for timer to underflow. Can't test the timer completion
297     // bit without actually enabling the interrupt. So instead watch
298     // the counter.
299     ticks /= 2;                         // wait for this threshold
300
301     // Wait till timer counts below threshold
302     do {
303         HAL_READ_UINT32(KS32C_TCNT1, count);
304     } while (count >= ticks);
305     // then wait for it to be reloaded
306     do {
307         HAL_READ_UINT32(KS32C_TCNT1, count);
308     } while (count < ticks);
309
310     // Then disable timer 1 again
311     tmod &= ~KS32C_TMOD_TE1;
312     HAL_WRITE_UINT32(KS32C_TMOD, tmod);
313 }
314
315 // -------------------------------------------------------------------------
316 //
317 // To reset the AIM 711, set P3 to low, which is connected to the reset
318 // logic 
319 //
320 void hal_reset(void)
321 {
322     cyg_uint32 value;
323     CYG_INTERRUPT_STATE old;
324
325     CYGACC_CALL_IF_DELAY_US(100000);
326
327     // Set P3 to output
328     HAL_READ_UINT32(KS32C_IOPMOD, value);
329     value |= AIM711_GPIO_RESET;
330     HAL_WRITE_UINT32(KS32C_IOPMOD, value);
331
332     // Set P3 to low
333     AIM711_GPIO_CLR(AIM711_GPIO_RESET);
334
335     HAL_DISABLE_INTERRUPTS(old);
336     while (1)
337     ;
338 }
339
340 //----------------------------------------------------------------------
341 //
342 // I2C Support
343 //
344
345 #include <string.h>
346 #include <cyg/hal/drv_api.h>
347
348 #ifdef CYGPKG_ERROR
349 #include <errno.h>
350 #define I2C_STATUS_SUCCESS      (ENOERR)
351 #define I2C_STATUS_MUTEX        (-EINTR)
352 #define I2C_STATUS_BUSY         (-EBUSY)
353 #define I2C_STATUS_ADDR_NAK     (-1000)
354 #define I2C_STATUS_DATA_NAK     (-1001)
355 #else
356 #define I2C_STATUS_SUCCESS      (0)
357 #define I2C_STATUS_MUTEX        (-1)
358 #define I2C_STATUS_BUSY         (-1)
359 #define I2C_STATUS_ADDR_NAK     (-1)
360 #define I2C_STATUS_DATA_NAK     (-1)
361 #endif
362
363 static cyg_drv_mutex_t i2c_mutex;
364
365 //  Initialize the I2C bus controller.
366 static void
367 hal_ks32c_i2c_init(void)
368 {
369     cyg_uint32 prescale = KS32C_I2C_FREQ(100000);
370
371     // reset the bus controller
372     HAL_WRITE_UINT32(KS32C_I2CCON, KS32C_I2C_CON_RESET);
373
374     // set the bus frequency
375     HAL_WRITE_UINT32(KS32C_I2CPS, prescale);
376
377     cyg_drv_mutex_init(&i2c_mutex);
378 }
379
380 #define RETURN(_x_) \
381     CYG_MACRO_START                             \
382     diag_printf("%s: line %d error=%d\n",__FUNCTION__,__LINE__,(_x_)); \
383     return (_x_); \
384     CYG_MACRO_END
385
386 //  Transfer the I2C messages.
387 int
388 hal_ks32c_i2c_transfer(cyg_uint32 nmsg, hal_ks32c_i2c_msg_t* pmsgs)
389 {
390     cyg_uint32 i2ccon;
391
392     // serialize access to the I2C bus
393     if (!cyg_drv_mutex_lock(&i2c_mutex))
394     {
395         RETURN(I2C_STATUS_MUTEX);
396     }
397
398     // is the bus free ?
399     do
400     {
401         HAL_READ_UINT32(KS32C_I2CCON, i2ccon);
402     } while (i2ccon & KS32C_I2C_CON_BUSY);
403
404     // transfer the messages
405     for (; nmsg > 0; --nmsg, ++pmsgs)
406     {
407         // generate the start condition
408         HAL_WRITE_UINT32(KS32C_I2CCON, KS32C_I2C_CON_START);
409
410         // send the device address
411         HAL_WRITE_UINT32(KS32C_I2CBUF, pmsgs->devaddr);
412         do
413         {
414             HAL_READ_UINT32(KS32C_I2CCON, i2ccon);
415         } while ((i2ccon & KS32C_I2C_CON_BF) == 0);
416
417         // check if the slave ACK'ed the device address
418         if (i2ccon & KS32C_I2C_CON_LRB)
419         {
420             // generate the stop condition
421             HAL_WRITE_UINT32(KS32C_I2CCON, KS32C_I2C_CON_STOP);
422             cyg_drv_mutex_unlock(&i2c_mutex);
423             RETURN(I2C_STATUS_ADDR_NAK);
424         }
425
426         // read the message ?
427         if (pmsgs->devaddr & KS32C_I2C_RD)
428         {
429             cyg_uint8* pbuf = pmsgs->pbuf;
430             cyg_uint32 bufsize = pmsgs->bufsize;
431             cyg_uint32 i2cbuf;
432
433             // read more than one byte ?
434             if (--bufsize > 0)
435             {
436                 // enable ACK
437                 HAL_WRITE_UINT32(KS32C_I2CCON, KS32C_I2C_CON_ACK);
438
439                 while (bufsize-- > 0)
440                 {
441                     do
442                     {
443                         HAL_READ_UINT32(KS32C_I2CCON, i2ccon);
444                     } while ((i2ccon & KS32C_I2C_CON_BF) == 0);
445
446                     // read the data byte
447                     HAL_READ_UINT32(KS32C_I2CBUF, i2cbuf);
448                     *pbuf++ = i2cbuf;
449                 }
450             }
451
452             // disable ACK
453             HAL_WRITE_UINT32(KS32C_I2CCON, 0);
454             do
455             {
456                 HAL_READ_UINT32(KS32C_I2CCON, i2ccon);
457             } while ((i2ccon & KS32C_I2C_CON_BF) == 0);
458
459             // read the data byte
460             HAL_READ_UINT32(KS32C_I2CBUF, i2cbuf);
461             *pbuf++ = i2cbuf;
462         }
463
464         // write the message
465         else
466         {
467             cyg_uint32 i;
468
469             for (i = 0; i < pmsgs->bufsize; ++i)
470             {
471                 HAL_WRITE_UINT32(KS32C_I2CBUF, pmsgs->pbuf[i]);
472                 do
473                 {
474                     HAL_READ_UINT32(KS32C_I2CCON, i2ccon);
475                 } while ((i2ccon & KS32C_I2C_CON_BF) == 0);
476
477                 // check if the slave ACK'ed the data byte
478                 if (i2ccon & KS32C_I2C_CON_LRB)
479                 {
480                     // generate the stop condition
481                     HAL_WRITE_UINT32(KS32C_I2CCON, KS32C_I2C_CON_STOP);
482                     cyg_drv_mutex_unlock(&i2c_mutex);
483                     RETURN(I2C_STATUS_DATA_NAK);
484                 }
485             }
486         }
487
488         // generate a restart condition ?
489         if (nmsg > 1)
490         {
491             HAL_WRITE_UINT32(KS32C_I2CCON, KS32C_I2C_CON_RESTART);
492         }
493     }
494
495     // generate the stop condition
496     HAL_WRITE_UINT32(KS32C_I2CCON, KS32C_I2C_CON_STOP);
497
498     cyg_drv_mutex_unlock(&i2c_mutex);
499     return I2C_STATUS_SUCCESS;
500 }
501
502 //----------------------------------------------------------------------
503 //
504 // EEPROM Support
505 //
506
507 int hal_aim711_eeprom_write(cyg_uint8 *buf, int offset, int len)
508 {
509     cyg_uint8 addr_page[1 + AIM711_EEPROM_PAGESIZE];
510     cyg_uint8 const* pbufbyte = (cyg_uint8 const*)buf;
511     hal_ks32c_i2c_msg_t msg;
512     cyg_uint8 addr;
513     cyg_uint32 bufsize;
514  
515     if (offset > AIM711_EEPROM_SIZE)
516         RETURN(-1);
517
518     if (len > (AIM711_EEPROM_SIZE - offset))
519         len = (AIM711_EEPROM_SIZE - offset);
520
521     addr = offset;
522     bufsize = len;
523
524     msg.devaddr = AIM711_EEPROM_ADDR | KS32C_I2C_WR;
525     msg.pbuf = addr_page;
526
527     while (bufsize > 0)
528     {
529         cyg_uint32 nbytes;
530         int status;
531
532         // write at most a page at a time
533         nbytes = MIN(bufsize, AIM711_EEPROM_PAGESIZE);
534
535         // don't cross a page boundary
536         if (addr%AIM711_EEPROM_PAGESIZE)
537         {
538             nbytes = MIN(nbytes, AIM711_EEPROM_PAGESIZE - addr%AIM711_EEPROM_PAGESIZE);
539         }
540
541         // build the write message
542         addr_page[0] = addr;
543         memcpy(&addr_page[1], pbufbyte, nbytes);
544         msg.bufsize = nbytes + 1;
545         addr += nbytes;
546         pbufbyte += nbytes;
547         bufsize -= nbytes;
548
549         // transfer the message
550         status = hal_ks32c_i2c_transfer(1, &msg);
551         if (status != I2C_STATUS_SUCCESS)
552         {
553             RETURN(status);
554         }
555
556         // delay 10 msec
557         CYGACC_CALL_IF_DELAY_US(10000);
558     }
559
560     return len;
561 }
562
563 int hal_aim711_eeprom_read(cyg_uint8 *buf, int offset, int len)
564 {
565     hal_ks32c_i2c_msg_t msgs[2];
566     int status;
567     cyg_uint8 toffset;
568  
569     if (offset > AIM711_EEPROM_SIZE)
570         RETURN(-1);
571
572     if (len > (AIM711_EEPROM_SIZE - offset))
573         len = (AIM711_EEPROM_SIZE - offset);
574
575     toffset = offset;
576
577     // write message to set the address
578     msgs[0].devaddr = AIM711_EEPROM_ADDR | KS32C_I2C_WR;
579     msgs[0].pbuf = &toffset;
580     msgs[0].bufsize = sizeof(toffset);
581
582     // read message
583     msgs[1].devaddr = AIM711_EEPROM_ADDR | KS32C_I2C_RD;
584     msgs[1].pbuf = buf;
585     msgs[1].bufsize = len;
586
587     // transfer the messages
588     status = hal_ks32c_i2c_transfer(2, msgs);
589
590     if (status < 0)
591         RETURN(status);
592
593     return len;
594 }
595
596 //-----------------------------------------------------------------------------
597 //
598