]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/hal/fr30/skmb91302/v2_0/src/ser.c
Initial revision
[karo-tx-redboot.git] / packages / hal / fr30 / skmb91302 / v2_0 / src / ser.c
1 //=============================================================================
2 //
3 //      ser.c
4 //
5 //      Simple (polling) driver for the Fujitsu MB91302 on-chip serial port
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):   larsi
44 // Contributors:
45 // Date:        2007-01-10
46 // Description: Simple driver for the MB91302 internal serial port
47 //
48 //####DESCRIPTIONEND####
49 //
50 //=============================================================================
51
52 #include <pkgconf/hal.h>
53 #include <pkgconf/system.h>
54 #include CYGBLD_HAL_PLATFORM_H
55
56 #include <cyg/hal/hal_arch.h>           // SAVE/RESTORE GP macros
57 #include <cyg/hal/hal_io.h>             // IO macros
58 #include <cyg/hal/hal_if.h>             // interface API
59 #include <cyg/hal/hal_intr.h>           // HAL_ENABLE/MASK/UNMASK_INTERRUPTS
60 #include <cyg/hal/hal_misc.h>           // Helper functions
61 #include <cyg/hal/drv_api.h>            // CYG_ISR_HANDLED
62
63 // We have no control over baud rate
64 // #if CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD==57600
65 // #define CYG_DEV_SERIAL_BAUD_DIVISOR    BAUD_57600
66 // #endif
67
68 // #ifndef CYG_DEV_SERIAL_BAUD_DIVISOR
69 // #error Missing/incorrect serial baud rate defined - CDL error?
70 // #endif
71
72 #define CYG_HAL_FR30_MB91301_SMR0     0x63
73 #define CYG_HAL_FR30_MB91301_SCR0     0x62
74 #define CYG_HAL_FR30_MB91301_SIDR0    0x61
75 #define CYG_HAL_FR30_MB91301_SODR0    0x61
76 #define CYG_HAL_FR30_MB91301_SSR0     0x60
77 #define CYG_HAL_FR30_MB91301_UTIM0    0x64
78 #define CYG_HAL_FR30_MB91301_UTIMR0   0x64
79 #define CYG_HAL_FR30_MB91301_DRCL     0x66
80 #define CYG_HAL_FR30_MB91301_UTIMC0   0x67
81
82
83 #define CYG_HAL_FR30_MB91301_SER0_BASE  0x60
84 #define CYG_HAL_FR30_MB91301_SER1_BASE  0x68
85 #define CYG_HAL_FR30_MB91301_SER2_BASE  0x70
86
87 #define CYG_HAL_FR30_MB91301_SMR_OFFSET     0x03
88 #define CYG_HAL_FR30_MB91301_SCR_OFFSET     0x02
89 #define CYG_HAL_FR30_MB91301_SIDR_OFFSET    0x01
90 #define CYG_HAL_FR30_MB91301_SODR_OFFSET    0x01
91 #define CYG_HAL_FR30_MB91301_SSR_OFFSET     0x00
92 #define CYG_HAL_FR30_MB91301_UTIM_OFFSET    0x04
93 #define CYG_HAL_FR30_MB91301_UTIMR_OFFSET   0x04
94 #define CYG_HAL_FR30_MB91301_DRCL_OFFSET    0x06
95 #define CYG_HAL_FR30_MB91301_UTIMC_OFFSET   0x07
96
97 #define CYG_HAL_FR30_MB91301_PDRG     0x10
98 #define CYG_HAL_FR30_MB91301_DDRG     0x400
99 #define CYG_HAL_FR30_MB91301_PFRG     0x410
100 #define CYG_HAL_FR30_MB91301_PDRJ     0x13
101 #define CYG_HAL_FR30_MB91301_DDRJ     0x403
102 #define CYG_HAL_FR30_MB91301_PFRJ     0x413
103
104
105 //-----------------------------------------------------------------------------
106 typedef struct {
107     cyg_uint8 base;
108     cyg_int32 msec_timeout;
109     int isr_vector;
110 } channel_data_t;
111
112 static channel_data_t channels[2] = {
113     {  CYG_HAL_FR30_MB91301_SER0_BASE, 1000, CYGNUM_HAL_INTERRUPT_UART0_RX},
114     {  CYG_HAL_FR30_MB91301_SER1_BASE, 1000, CYGNUM_HAL_INTERRUPT_UART1_RX}/*,
115     {  CYG_HAL_FR30_MB91301_SER2_BASE, 1000, CYGNUM_HAL_INTERRUPT_UART2_RX}*/
116 };
117
118 //-----------------------------------------------------------------------------
119 // function for calculating and setting the baudrate
120
121 static void cyg_hal_plf_serial_set_baudrate_internal(cyg_uint8 port, int baudrate){
122
123     float n, nn;
124     int t, tt;
125
126     n = (CYGHWR_HAL_FR30_MB91301_SYSTEM_CLOCK_MHZ * 1000000 / CYGHWR_HAL_FR30_MB91301_CLKP_DIVIDER) / (float) (32 * baudrate) - 1;
127     nn = (CYGHWR_HAL_FR30_MB91301_SYSTEM_CLOCK_MHZ * 1000000 / CYGHWR_HAL_FR30_MB91301_CLKP_DIVIDER) / (float) (32 * baudrate) - 1.5;
128
129     /* rounding */
130     t = n;
131     tt = nn;
132     if ( (n-t) > (1 - (n-t)) ) t++;
133     if ( (nn-tt) > (1 - (nn-tt)) ) tt++;
134
135     /* check which is better t or tt */
136
137     /* back calculation of baudrate from t and tt */
138     n = (CYGHWR_HAL_FR30_MB91301_SYSTEM_CLOCK_MHZ * 1000000 / CYGHWR_HAL_FR30_MB91301_CLKP_DIVIDER) / (float) ((2*t+2) * 16);
139     nn = (CYGHWR_HAL_FR30_MB91301_SYSTEM_CLOCK_MHZ * 1000000 / CYGHWR_HAL_FR30_MB91301_CLKP_DIVIDER) / (float) ((2*tt+3) * 16);
140
141     /* taking difference between wanted baudrate and back calculated br */
142     if ((baudrate - n) < 0)
143         n = n - baudrate;
144     else
145         n = baudrate - n;
146
147     if ((baudrate - nn) < 0)
148         nn = nn - baudrate;
149     else
150         nn = baudrate - nn;
151
152     /* and finally take the best */
153     if (n < nn){
154         /* UCC1 = 0 */
155         HAL_WRITE_UINT16(port + CYG_HAL_FR30_MB91301_UTIMR_OFFSET, t);
156         HAL_WRITE_UINT8(port + CYG_HAL_FR30_MB91301_UTIMC_OFFSET, 0x02);
157     } else {
158         /* UCC1 = 1 */
159         HAL_WRITE_UINT16(port + CYG_HAL_FR30_MB91301_UTIMR_OFFSET, tt);
160         HAL_WRITE_UINT8(port + CYG_HAL_FR30_MB91301_UTIMC_OFFSET, 0x82);
161     }
162 }
163
164 //-----------------------------------------------------------------------------
165 // The minimal init, get and put functions. All by polling.
166
167 void
168 cyg_hal_plf_serial_init_channel(void* __ch_data)
169 {
170     cyg_uint8 port;
171     cyg_uint8 value;
172
173     port = ((channel_data_t*)__ch_data)->base;
174
175     // set the port direction and function registers to serial
176     switch (port){
177         case CYG_HAL_FR30_MB91301_SER0_BASE:
178             HAL_READ_UINT8(CYG_HAL_FR30_MB91301_DDRJ, value);
179             value |= 0x6;
180             value &= ~0x1;
181             HAL_WRITE_UINT8(CYG_HAL_FR30_MB91301_DDRJ, value);
182             HAL_READ_UINT8(CYG_HAL_FR30_MB91301_PFRJ, value);
183             HAL_WRITE_UINT8(CYG_HAL_FR30_MB91301_PFRJ, value | 0x7);
184             if (CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_DEFAULT == 0){
185                 cyg_hal_plf_serial_set_baudrate_internal(port, CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD);
186             } else {
187                 cyg_hal_plf_serial_set_baudrate_internal(port, CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL_BAUD);
188             }
189             break;
190
191         case CYG_HAL_FR30_MB91301_SER1_BASE:
192             HAL_READ_UINT8(CYG_HAL_FR30_MB91301_DDRJ, value);
193             value |= 0x30;
194             value &= ~0x8;
195             HAL_WRITE_UINT8(CYG_HAL_FR30_MB91301_DDRJ, value);
196             HAL_READ_UINT8(CYG_HAL_FR30_MB91301_PFRJ, value);
197             HAL_WRITE_UINT8(CYG_HAL_FR30_MB91301_PFRJ, value | 0x38);
198             if (CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_DEFAULT == 1){
199                 cyg_hal_plf_serial_set_baudrate_internal(port, CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD);
200             } else {
201                 cyg_hal_plf_serial_set_baudrate_internal(port, CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL_BAUD);
202             }
203             break;
204 /*
205         case CYG_HAL_FR30_MB91301_SER2_BASE:
206             HAL_READ_UINT8(CYG_HAL_FR30_MB91301_DDRG, value);
207             HAL_WRITE_UINT8(CYG_HAL_FR30_MB91301_DDRG, value | 0x40);
208             HAL_READ_UINT8(CYG_HAL_FR30_MB91301_PFRG, value);
209             HAL_WRITE_UINT8(CYG_HAL_FR30_MB91301_PFRG, value | 0x60);
210             break;
211 */
212     }
213
214     // set up U-Timer
215 /*    HAL_WRITE_UINT8(port + CYG_HAL_FR30_MB91301_UTIMC_OFFSET, 0x02);
216     // 115200 bps
217     HAL_WRITE_UINT16(port + CYG_HAL_FR30_MB91301_UTIMR_OFFSET, 0x7);
218
219     cyg_hal_plf_serial_set_baudrate_internal(port, baudrate);
220 */
221     // setup UART
222     HAL_WRITE_UINT8(port + CYG_HAL_FR30_MB91301_SCR_OFFSET, 0x13);
223     HAL_WRITE_UINT8(port + CYG_HAL_FR30_MB91301_SMR_OFFSET, 0x30);
224 }
225
226 void
227 cyg_hal_plf_serial_putc(void* __ch_data, cyg_uint8 __ch)
228 {
229     cyg_uint8 ssr;
230     cyg_uint8 port;
231
232     port = ((channel_data_t*)__ch_data)->base;
233     // wait for tx rdy
234     do
235     {
236         HAL_READ_UINT8(port + CYG_HAL_FR30_MB91301_SSR_OFFSET, ssr);
237     } while (!(ssr & BIT3));
238     // Now, write it
239     HAL_WRITE_UINT8( port + CYG_HAL_FR30_MB91301_SODR_OFFSET, __ch );
240 }
241
242 static cyg_bool
243 cyg_hal_plf_serial_getc_nonblock(void* __ch_data, cyg_uint8* ch)
244 {
245     cyg_uint8 ssr;
246     cyg_uint8 port;
247
248     port = ((channel_data_t*)__ch_data)->base;
249     HAL_READ_UINT8(port + CYG_HAL_FR30_MB91301_SSR_OFFSET, ssr);
250     if (!(ssr & BIT4))
251         return false;
252
253     HAL_READ_UINT8(port + CYG_HAL_FR30_MB91301_SIDR_OFFSET, *ch);
254 //     hal_diag_led(port);
255     return true;
256 }
257
258 cyg_uint8
259 cyg_hal_plf_serial_getc(void* __ch_data)
260 {
261     cyg_uint8 ch;
262
263     while(!cyg_hal_plf_serial_getc_nonblock(__ch_data, &ch));
264     return ch;
265 }
266
267 static void
268 cyg_hal_plf_serial_write(void* __ch_data, const cyg_uint8* __buf, 
269                          cyg_uint32 __len)
270 {
271     while(__len-- > 0)
272         cyg_hal_plf_serial_putc(__ch_data, *__buf++);
273 }
274
275 static void
276 cyg_hal_plf_serial_read(void* __ch_data, cyg_uint8* __buf, cyg_uint32 __len)
277 {
278     while(__len-- > 0)
279         *__buf++ = cyg_hal_plf_serial_getc(__ch_data);
280 }
281
282
283 cyg_bool
284 cyg_hal_plf_serial_getc_timeout(void* __ch_data, cyg_uint8* ch)
285 {
286     int delay_count;
287     channel_data_t* chan;
288     cyg_bool res;
289
290     // Some of the diagnostic print code calls through here with no idea what the ch_data is.
291     // Go ahead and assume it is channels[0].
292     if (__ch_data == 0)
293       __ch_data = (void*)&channels[0];
294
295     chan = (channel_data_t*)__ch_data;
296
297     delay_count = chan->msec_timeout; // delay in 1000 us steps
298     for(;;) {
299         res = cyg_hal_plf_serial_getc_nonblock(__ch_data, ch);
300         if (res || 0 == delay_count--)
301             break;
302         CYGACC_CALL_IF_DELAY_US(1000);
303     }
304     return res;
305 }
306
307 static int
308 cyg_hal_plf_serial_control(void *__ch_data, __comm_control_cmd_t __func, ...)
309 {
310     static int irq_state = 0;
311     channel_data_t* chan;
312     int ret = 0;
313     cyg_uint8 port;
314     cyg_uint8 value;
315
316     // Some of the diagnostic print code calls through here with no idea what the ch_data is.
317     // Go ahead and assume it is channels[0].
318     if (__ch_data == 0)
319       __ch_data = (void*)&channels[0];
320
321     chan = (channel_data_t*)__ch_data;
322
323     switch (__func) {
324     case __COMMCTL_IRQ_ENABLE:
325         irq_state = 1;
326         port = ((channel_data_t*)__ch_data)->base;
327         HAL_READ_UINT8(port + CYG_HAL_FR30_MB91301_SSR_OFFSET, value);
328         HAL_WRITE_UINT8(port + CYG_HAL_FR30_MB91301_SSR_OFFSET, value | BIT1);
329         break;
330     case __COMMCTL_IRQ_DISABLE:
331         ret = irq_state;
332         irq_state = 0;
333         port = ((channel_data_t*)__ch_data)->base;
334         HAL_READ_UINT8(port + CYG_HAL_FR30_MB91301_SSR_OFFSET, value);
335         HAL_WRITE_UINT8(port + CYG_HAL_FR30_MB91301_SSR_OFFSET, value & ~BIT1);
336         break;
337     case __COMMCTL_DBG_ISR_VECTOR:
338         ret = chan->isr_vector;
339         break;
340     case __COMMCTL_SET_TIMEOUT:
341     {
342         va_list ap;
343
344         va_start(ap, __func);
345
346         ret = chan->msec_timeout;
347         chan->msec_timeout = va_arg(ap, cyg_uint32);
348
349         va_end(ap);
350     }
351     break;
352     case __COMMCTL_SETBAUD:
353     {
354         cyg_uint32 baud_rate;
355         cyg_uint16 n, nn;
356         va_list ap;
357
358         va_start(ap, __func);
359         baud_rate = va_arg(ap, cyg_uint32);
360         va_end(ap);
361         port = ((channel_data_t*)__ch_data)->base;
362         cyg_hal_plf_serial_set_baudrate_internal(port, baud_rate);
363     }
364     break;
365
366     case __COMMCTL_GETBAUD:
367         break;
368     default:
369         break;
370     }
371     return ret;
372 }
373
374 static int
375 cyg_hal_plf_serial_isr(void *__ch_data, int* __ctrlc, 
376                        CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
377 {
378     *__ctrlc = 0;
379     return 0;
380 }
381
382 static void
383 cyg_hal_plf_serial_init(void)
384 {
385     hal_virtual_comm_table_t* comm;
386     int i, cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
387
388 #define NUM_CHANNELS CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS
389     for (i = 0; i < NUM_CHANNELS; i++) {
390
391         // Disable interrupts.
392         HAL_INTERRUPT_MASK(channels[i].isr_vector);
393
394         // Init channels
395         cyg_hal_plf_serial_init_channel((void*)&channels[i]);
396         // Setup procs in the vector table
397
398         // Set COMM callbacks for channel
399         CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
400         comm = CYGACC_CALL_IF_CONSOLE_PROCS();
401         CYGACC_COMM_IF_CH_DATA_SET(*comm, &channels[i]);
402         CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_plf_serial_write);
403         CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_plf_serial_read);
404         CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_plf_serial_putc);
405         CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_plf_serial_getc);
406         CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_plf_serial_control);
407         CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_plf_serial_isr);
408         CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_plf_serial_getc_timeout);
409     }
410     // Restore original console
411     CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
412 }
413
414 void
415 cyg_hal_plf_comms_init(void)
416 {
417     static int initialized = 0;
418
419     if (initialized)
420         return;
421
422     initialized = 1;
423     cyg_hal_plf_serial_init();
424
425 }
426
427 //-----------------------------------------------------------------------------
428 // end of ser.c
429