Mercurial > ecos
comparison packages/hal/sh/sh4/current/src/sh4_scif.c @ 134:d2f49caf9e38 ecos-sw-2000-11-03
Merge from eCos master repository on 2000-11-03-09:00:49-GMT
| author | jlarmour |
|---|---|
| date | Fri, 03 Nov 2000 21:17:40 +0000 |
| parents | |
| children | 25e238959bae |
comparison
equal
deleted
inserted
replaced
| 133:98d71f4d8243 | 134:d2f49caf9e38 |
|---|---|
| 1 //============================================================================= | |
| 2 // | |
| 3 // sh4_scif.c | |
| 4 // | |
| 5 // Simple driver for the SH4 Serial Communication Interface with FIFO | |
| 6 // | |
| 7 //============================================================================= | |
| 8 //####COPYRIGHTBEGIN#### | |
| 9 // | |
| 10 // ------------------------------------------- | |
| 11 // The contents of this file are subject to the Red Hat eCos Public License | |
| 12 // Version 1.1 (the "License"); you may not use this file except in | |
| 13 // compliance with the License. You may obtain a copy of the License at | |
| 14 // http://www.redhat.com/ | |
| 15 // | |
| 16 // Software distributed under the License is distributed on an "AS IS" | |
| 17 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the | |
| 18 // License for the specific language governing rights and limitations under | |
| 19 // the License. | |
| 20 // | |
| 21 // The Original Code is eCos - Embedded Configurable Operating System, | |
| 22 // released September 30, 1998. | |
| 23 // | |
| 24 // The Initial Developer of the Original Code is Red Hat. | |
| 25 // Portions created by Red Hat are | |
| 26 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc. | |
| 27 // All Rights Reserved. | |
| 28 // ------------------------------------------- | |
| 29 // | |
| 30 //####COPYRIGHTEND#### | |
| 31 //============================================================================= | |
| 32 //#####DESCRIPTIONBEGIN#### | |
| 33 // | |
| 34 // Author(s): jskov | |
| 35 // Contributors:Haruki Kashiwaya | |
| 36 // Date: 2000-08-09 | |
| 37 // Description: Simple driver for the SH Serial Communication Interface | |
| 38 // The driver can be used for the SCIF modules. | |
| 39 // Clients of this file can configure the behavior with: | |
| 40 // CYGNUM_SCIF_PORTS: number of SCI ports | |
| 41 // | |
| 42 //####DESCRIPTIONEND#### | |
| 43 // | |
| 44 //============================================================================= | |
| 45 | |
| 46 #include <pkgconf/hal.h> | |
| 47 | |
| 48 #ifdef CYGNUM_HAL_SH_SH4_SCIF_PORTS | |
| 49 | |
| 50 #include <cyg/hal/hal_io.h> // IO macros | |
| 51 #include <cyg/hal/drv_api.h> // CYG_ISR_HANDLED | |
| 52 #include <cyg/hal/hal_misc.h> // Helper functions | |
| 53 #include <cyg/hal/hal_intr.h> // HAL_ENABLE/MASK/UNMASK_INTERRUPTS | |
| 54 #include <cyg/hal/hal_arch.h> // SAVE/RESTORE GP | |
| 55 #include <cyg/hal/hal_if.h> // Calling-if API | |
| 56 #include <cyg/hal/sh_regs.h> // serial register definitions | |
| 57 #include <cyg/hal/sh_stub.h> // target_register_t | |
| 58 | |
| 59 #include <cyg/hal/sh4_scif.h> // our header | |
| 60 | |
| 61 //-------------------------------------------------------------------------- | |
| 62 | |
| 63 void | |
| 64 cyg_hal_plf_scif_init_channel(const channel_data_t* chan) | |
| 65 { | |
| 66 cyg_uint8* base = chan->base; | |
| 67 cyg_uint16 tmp; | |
| 68 cyg_uint16 sr; | |
| 69 | |
| 70 // Disable everything. | |
| 71 HAL_WRITE_UINT16(base+_REG_SCSCR, 0); | |
| 72 | |
| 73 // Reset FIFO. | |
| 74 HAL_WRITE_UINT16(base+_REG_SCFCR, | |
| 75 CYGARC_REG_SCFCR2_TFRST|CYGARC_REG_SCFCR2_RFRST); | |
| 76 | |
| 77 // 8-1-no parity. | |
| 78 HAL_WRITE_UINT16(base+_REG_SCSMR, 0); | |
| 79 | |
| 80 // Set speed to 38400 | |
| 81 HAL_READ_UINT16(base+_REG_SCSMR, tmp); | |
| 82 tmp &= ~CYGARC_REG_SCSMR2_CKSx_MASK; | |
| 83 tmp |= CYGARC_SCBRR_CKSx(38400); | |
| 84 HAL_WRITE_UINT16(base+_REG_SCSMR, tmp); | |
| 85 HAL_WRITE_UINT8(base+_REG_SCBRR, CYGARC_SCBRR_N(38400)); | |
| 86 | |
| 87 // Let things settle: Here we should should wait the equivalent of | |
| 88 // one bit interval, i.e. 1/38400 second, but until we have | |
| 89 // something like the Linux delay loop, it's hard to do reliably. So | |
| 90 // just move on and hope for the best (this is unlikely to cause | |
| 91 // problems since the CPU has just come out of reset anyway). | |
| 92 | |
| 93 // Clear status register (read back first). | |
| 94 HAL_READ_UINT16(base+_REG_SCFSR, sr); | |
| 95 HAL_WRITE_UINT16(base+_REG_SCFSR, 0); | |
| 96 | |
| 97 // Bring FIFO out of reset and set to trigger on every char in | |
| 98 // FIFO (or C-c input would not be processed). | |
| 99 HAL_WRITE_UINT16(base+_REG_SCFCR, | |
| 100 CYGARC_REG_SCFCR2_RTRG_1|CYGARC_REG_SCFCR2_TTRG_1); | |
| 101 | |
| 102 // Leave Tx/Rx interrupts disabled, but enable Tx/Rx | |
| 103 HAL_WRITE_UINT16(base+_REG_SCSCR, | |
| 104 CYGARC_REG_SCSCR2_TE|CYGARC_REG_SCSCR2_RE); | |
| 105 } | |
| 106 | |
| 107 static cyg_bool | |
| 108 cyg_hal_plf_scif_getc_nonblock(void* __ch_data, cyg_uint8* ch) | |
| 109 { | |
| 110 cyg_uint8* base = ((channel_data_t*)__ch_data)->base; | |
| 111 cyg_uint16 fdr, sr; | |
| 112 | |
| 113 HAL_READ_UINT16(base+_REG_SCFDR, fdr); | |
| 114 if ((fdr & CYGARC_REG_SCFDR2_RCOUNT_MASK) == 0) | |
| 115 return false; | |
| 116 | |
| 117 HAL_READ_UINT8(base+_REG_SCFRDR, *ch); | |
| 118 | |
| 119 // Clear FIFO full flag (read before clearing) | |
| 120 HAL_READ_UINT16(base+_REG_SCFSR, sr); | |
| 121 HAL_WRITE_UINT16(base+_REG_SCFSR, | |
| 122 CYGARC_REG_SCSSR2_CLEARMASK & ~CYGARC_REG_SCSSR2_RDF); | |
| 123 | |
| 124 return true; | |
| 125 } | |
| 126 | |
| 127 cyg_uint8 | |
| 128 cyg_hal_plf_scif_getc(void* __ch_data) | |
| 129 { | |
| 130 cyg_uint8 ch; | |
| 131 CYGARC_HAL_SAVE_GP(); | |
| 132 | |
| 133 while(!cyg_hal_plf_scif_getc_nonblock(__ch_data, &ch)); | |
| 134 | |
| 135 CYGARC_HAL_RESTORE_GP(); | |
| 136 return ch; | |
| 137 } | |
| 138 | |
| 139 void | |
| 140 cyg_hal_plf_scif_putc(void* __ch_data, cyg_uint8 c) | |
| 141 { | |
| 142 cyg_uint8* base = ((channel_data_t*)__ch_data)->base; | |
| 143 cyg_uint16 fdr, sr; | |
| 144 CYGARC_HAL_SAVE_GP(); | |
| 145 | |
| 146 do { | |
| 147 HAL_READ_UINT16(base+_REG_SCFDR, fdr); | |
| 148 } while (((fdr & CYGARC_REG_SCFDR2_TCOUNT_MASK) >> CYGARC_REG_SCFDR2_TCOUNT_shift) == 16); | |
| 149 | |
| 150 HAL_WRITE_UINT8(base+_REG_SCFTDR, c); | |
| 151 | |
| 152 // Clear FIFO-empty/transmit end flags (read back SR first) | |
| 153 HAL_READ_UINT16(base+_REG_SCFSR, sr); | |
| 154 HAL_WRITE_UINT16(base+_REG_SCFSR, CYGARC_REG_SCSSR2_CLEARMASK | |
| 155 & ~(CYGARC_REG_SCSSR2_TDFE | CYGARC_REG_SCSSR2_TEND )); | |
| 156 | |
| 157 // Hang around until the character has been safely sent. | |
| 158 do { | |
| 159 HAL_READ_UINT16(base+_REG_SCFDR, fdr); | |
| 160 } while ((fdr & CYGARC_REG_SCFDR2_TCOUNT_MASK) != 0); | |
| 161 | |
| 162 CYGARC_HAL_RESTORE_GP(); | |
| 163 } | |
| 164 | |
| 165 #if defined(CYGSEM_HAL_VIRTUAL_VECTOR_DIAG) \ | |
| 166 || defined(CYGPRI_HAL_IMPLEMENTS_IF_SERVICES) | |
| 167 | |
| 168 static channel_data_t channels[CYGNUM_HAL_SH_SH4_SCIF_PORTS]; | |
| 169 | |
| 170 static void | |
| 171 cyg_hal_plf_scif_write(void* __ch_data, const cyg_uint8* __buf, | |
| 172 cyg_uint32 __len) | |
| 173 { | |
| 174 CYGARC_HAL_SAVE_GP(); | |
| 175 | |
| 176 while(__len-- > 0) | |
| 177 cyg_hal_plf_scif_putc(__ch_data, *__buf++); | |
| 178 | |
| 179 CYGARC_HAL_RESTORE_GP(); | |
| 180 } | |
| 181 | |
| 182 static void | |
| 183 cyg_hal_plf_scif_read(void* __ch_data, cyg_uint8* __buf, cyg_uint32 __len) | |
| 184 { | |
| 185 CYGARC_HAL_SAVE_GP(); | |
| 186 | |
| 187 while(__len-- > 0) | |
| 188 *__buf++ = cyg_hal_plf_scif_getc(__ch_data); | |
| 189 | |
| 190 CYGARC_HAL_RESTORE_GP(); | |
| 191 } | |
| 192 | |
| 193 cyg_bool | |
| 194 cyg_hal_plf_scif_getc_timeout(void* __ch_data, cyg_uint8* ch) | |
| 195 { | |
| 196 channel_data_t* chan = (channel_data_t*)__ch_data; | |
| 197 int delay_count; | |
| 198 cyg_bool res; | |
| 199 CYGARC_HAL_SAVE_GP(); | |
| 200 | |
| 201 delay_count = chan->msec_timeout * 10; // delay in .1 ms steps | |
| 202 | |
| 203 for(;;) { | |
| 204 res = cyg_hal_plf_scif_getc_nonblock(__ch_data, ch); | |
| 205 if (res || 0 == delay_count--) | |
| 206 break; | |
| 207 | |
| 208 CYGACC_CALL_IF_DELAY_US(100); | |
| 209 } | |
| 210 | |
| 211 CYGARC_HAL_RESTORE_GP(); | |
| 212 return res; | |
| 213 } | |
| 214 | |
| 215 static int | |
| 216 cyg_hal_plf_scif_control(void *__ch_data, __comm_control_cmd_t __func, ...) | |
| 217 { | |
| 218 static int irq_state = 0; | |
| 219 channel_data_t* chan = (channel_data_t*)__ch_data; | |
| 220 cyg_uint8 scr; | |
| 221 int ret = 0; | |
| 222 CYGARC_HAL_SAVE_GP(); | |
| 223 | |
| 224 switch (__func) { | |
| 225 case __COMMCTL_IRQ_ENABLE: | |
| 226 irq_state = 1; | |
| 227 HAL_INTERRUPT_UNMASK(chan->isr_vector); | |
| 228 HAL_READ_UINT16(chan->base+_REG_SCSCR, scr); | |
| 229 scr |= CYGARC_REG_SCSCR2_RIE; | |
| 230 HAL_WRITE_UINT16(chan->base+_REG_SCSCR, scr); | |
| 231 break; | |
| 232 case __COMMCTL_IRQ_DISABLE: | |
| 233 ret = irq_state; | |
| 234 irq_state = 0; | |
| 235 HAL_INTERRUPT_UNMASK(chan->isr_vector); | |
| 236 HAL_READ_UINT16(chan->base+_REG_SCSCR, scr); | |
| 237 scr &= ~CYGARC_REG_SCSCR2_RIE; | |
| 238 HAL_WRITE_UINT16(chan->base+_REG_SCSCR, scr); | |
| 239 break; | |
| 240 case __COMMCTL_DBG_ISR_VECTOR: | |
| 241 ret = chan->isr_vector; | |
| 242 break; | |
| 243 case __COMMCTL_SET_TIMEOUT: | |
| 244 { | |
| 245 va_list ap; | |
| 246 | |
| 247 va_start(ap, __func); | |
| 248 | |
| 249 ret = chan->msec_timeout; | |
| 250 chan->msec_timeout = va_arg(ap, cyg_uint32); | |
| 251 | |
| 252 va_end(ap); | |
| 253 } | |
| 254 default: | |
| 255 break; | |
| 256 } | |
| 257 CYGARC_HAL_RESTORE_GP(); | |
| 258 return ret; | |
| 259 } | |
| 260 | |
| 261 static int | |
| 262 cyg_hal_plf_scif_isr(void *__ch_data, int* __ctrlc, | |
| 263 CYG_ADDRWORD __vector, CYG_ADDRWORD __data) | |
| 264 { | |
| 265 cyg_uint8 c; | |
| 266 cyg_uint16 fdr, sr; | |
| 267 cyg_uint8* base = ((channel_data_t*)__ch_data)->base; | |
| 268 int res = 0; | |
| 269 CYGARC_HAL_SAVE_GP(); | |
| 270 | |
| 271 *__ctrlc = 0; | |
| 272 HAL_READ_UINT16(base+_REG_SCFDR, fdr); | |
| 273 if ((fdr & CYGARC_REG_SCFDR2_RCOUNT_MASK) != 0) { | |
| 274 HAL_READ_UINT8(base+_REG_SCFRDR, c); | |
| 275 | |
| 276 // Clear buffer full flag (read back first). | |
| 277 HAL_READ_UINT16(base+_REG_SCFSR, sr); | |
| 278 HAL_WRITE_UINT16(base+_REG_SCFSR, | |
| 279 CYGARC_REG_SCSSR2_CLEARMASK & ~CYGARC_REG_SCSSR2_RDF); | |
| 280 | |
| 281 if( cyg_hal_is_break( &c , 1 ) ) | |
| 282 *__ctrlc = 1; | |
| 283 | |
| 284 res = CYG_ISR_HANDLED; | |
| 285 } | |
| 286 | |
| 287 CYGARC_HAL_RESTORE_GP(); | |
| 288 return res; | |
| 289 } | |
| 290 | |
| 291 void | |
| 292 cyg_hal_plf_scif_init(int scif_index, int comm_index, | |
| 293 int rcv_vect, cyg_uint8* base) | |
| 294 { | |
| 295 channel_data_t* chan = &channels[scif_index]; | |
| 296 hal_virtual_comm_table_t* comm; | |
| 297 int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT); | |
| 298 | |
| 299 // Initialize channel table | |
| 300 chan->base = base; | |
| 301 chan->isr_vector = rcv_vect; | |
| 302 chan->msec_timeout = 1000; | |
| 303 | |
| 304 // Disable interrupts. | |
| 305 HAL_INTERRUPT_MASK(chan->isr_vector); | |
| 306 | |
| 307 // Init channel | |
| 308 cyg_hal_plf_scif_init_channel(chan); | |
| 309 | |
| 310 // Setup procs in the vector table | |
| 311 | |
| 312 // Initialize channel procs | |
| 313 CYGACC_CALL_IF_SET_CONSOLE_COMM(comm_index); | |
| 314 comm = CYGACC_CALL_IF_CONSOLE_PROCS(); | |
| 315 CYGACC_COMM_IF_CH_DATA_SET(*comm, chan); | |
| 316 CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_plf_scif_write); | |
| 317 CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_plf_scif_read); | |
| 318 CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_plf_scif_putc); | |
| 319 CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_plf_scif_getc); | |
| 320 CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_plf_scif_control); | |
| 321 CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_plf_scif_isr); | |
| 322 CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_plf_scif_getc_timeout); | |
| 323 | |
| 324 // Restore original console | |
| 325 CYGACC_CALL_IF_SET_CONSOLE_COMM(cur); | |
| 326 } | |
| 327 | |
| 328 #endif // CYGSEM_HAL_VIRTUAL_VECTOR_DIAG || CYGPRI_HAL_IMPLEMENTS_IF_SERVICES | |
| 329 | |
| 330 #endif // CYGNUM_HAL_SH_SH4_SCIF_PORTS | |
| 331 | |
| 332 //----------------------------------------------------------------------------- | |
| 333 // end of sh4_scif.c |
