filename | src/sh4/scif.c |
changeset | 20:3ffb66aa25c7 |
next | 21:fda269b432a7 |
author | nkeynes |
date | Thu Dec 22 13:28:16 2005 +0000 (17 years ago) |
permissions | -rw-r--r-- |
last change | Add scif.c (oops) Convert interrupts to be level-triggered rather than edge-triggered (although shouldn't be any visible difference) |
file | annotate | diff | log | raw |
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +00001.2 +++ b/src/sh4/scif.c Thu Dec 22 13:28:16 2005 +00001.3 @@ -0,0 +1,567 @@1.4 +/**1.5 + * $Id: scif.c,v 1.1 2005-12-22 13:28:16 nkeynes Exp $1.6 + * SCIF (Serial Communication Interface with FIFO) implementation - part of the1.7 + * SH4 standard on-chip peripheral set. The SCIF is hooked up to the DCs1.8 + * external serial port1.9 + *1.10 + * Copyright (c) 2005 Nathan Keynes.1.11 + *1.12 + * This program is free software; you can redistribute it and/or modify1.13 + * it under the terms of the GNU General Public License as published by1.14 + * the Free Software Foundation; either version 2 of the License, or1.15 + * (at your option) any later version.1.16 + *1.17 + * This program is distributed in the hope that it will be useful,1.18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of1.19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1.20 + * GNU General Public License for more details.1.21 + */1.22 +1.23 +#include <glib.h>1.24 +#include "dream.h"1.25 +#include "mem.h"1.26 +#include "sh4core.h"1.27 +#include "sh4mmio.h"1.28 +#include "intc.h"1.29 +#include "clock.h"1.30 +#include "serial.h"1.31 +#include "modules.h"1.32 +1.33 +void SCIF_set_break(void);1.34 +1.35 +/************************* External serial interface ************************/1.36 +1.37 +/**1.38 + * Note: serial_* operations are called from outside the SH4, and as such are1.39 + * named relative to the external serial device. SCIF_* operations are only1.40 + * called internally to the SH4 and so are named relative to the CPU.1.41 + */1.42 +1.43 +/**1.44 + * Storage space for inbound/outbound data blocks. It's a little more1.45 + * convenient for serial consumers to be able to deal with block-sized pieces1.46 + * rather than a byte at a time, even if it makes all this look rather1.47 + * complicated.1.48 + *1.49 + * Currently there's no limit on the number of blocks that can be queued up.1.50 + */1.51 +typedef struct serial_data_block {1.52 + uint32_t length;1.53 + uint32_t offset;1.54 + struct serial_data_block *next;1.55 + char data[];1.56 +} *serial_data_block_t;1.57 +1.58 +serial_data_block_t serial_recvq_head = NULL, serial_recvq_tail = NULL;1.59 +serial_device_t serial_device = NULL;1.60 +1.61 +void serial_attach_device( serial_device_t dev )1.62 +{1.63 + if( serial_device != NULL )1.64 + serial_detach_device();1.65 + serial_device = dev;1.66 +}1.67 +1.68 +1.69 +void serial_detach_device( void )1.70 +{1.71 + serial_device = NULL;1.72 +}1.73 +1.74 +/**1.75 + * Add a block of data to the serial receive queue. The data will be received1.76 + * by the CPU at the appropriate baud rate.1.77 + */1.78 +void serial_transmit_data( char *data, int length ) {1.79 + if( length == 0 )1.80 + return;1.81 + serial_data_block_t block =1.82 + g_malloc( sizeof( struct serial_data_block ) + length );1.83 + block->length = length;1.84 + block->offset = 0;1.85 + block->next = NULL;1.86 + memcpy( block->data, data, length );1.87 +1.88 + if( serial_recvq_head == NULL ) {1.89 + serial_recvq_head = serial_recvq_tail = block;1.90 + } else {1.91 + serial_recvq_tail->next = block;1.92 + serial_recvq_tail = block;1.93 + }1.94 +}1.95 +1.96 +/**1.97 + * Dequeue a byte from the serial input queue1.98 + */1.99 +static int serial_transmit_dequeue( ) {1.100 + if( serial_recvq_head != NULL ) {1.101 + uint8_t val = serial_recvq_head->data[serial_recvq_head->offset++];1.102 + if( serial_recvq_head->offset >= serial_recvq_head->length ) {1.103 + serial_data_block_t next = serial_recvq_head->next;1.104 + g_free( serial_recvq_head );1.105 + serial_recvq_head = next;1.106 + if( next == NULL )1.107 + serial_recvq_tail = NULL;1.108 + }1.109 + return (int)(unsigned int)val;1.110 + }1.111 + return -1;1.112 +1.113 +}1.114 +1.115 +void serial_transmit_break() {1.116 + SCIF_set_break();1.117 +}1.118 +1.119 +/********************************* SCIF *************************************/1.120 +1.121 +#define FIFO_LENGTH 161.122 +#define FIFO_ARR_LENGTH (FIFO_LENGTH+1)1.123 +1.124 +/* Serial control register flags */1.125 +#define SCSCR2_TIE 0x801.126 +#define SCSCR2_RIE 0x401.127 +#define SCSCR2_TE 0x201.128 +#define SCSCR2_RE 0x101.129 +#define SCSCR2_REIE 0x081.130 +#define SCSCR2_CKE 0x021.131 +1.132 +#define IS_TRANSMIT_IRQ_ENABLED() (MMIO_READ(SCIF,SCSCR2) & SCSCR2_TIE)1.133 +#define IS_RECEIVE_IRQ_ENABLED() (MMIO_READ(SCIF,SCSCR2) & SCSCR2_RIE)1.134 +#define IS_RECEIVE_ERROR_IRQ_ENABLED() (MMIO_READ(SCIF,SCSCR2) & (SCSCR2_RIE|SCSCR2_REIE))1.135 +/* Receive is enabled if the RE bit is set in SCSCR2, and the ORER bit is cleared in SCLSR2 */1.136 +#define IS_RECEIVE_ENABLED() ( (MMIO_READ(SCIF,SCSCR2) & SCSCR2_RE) && (MMIO_READ(SCIF,SCLSR2) & SCLSR2_ORER == 0) )1.137 +/* Transmit is enabled if the TE bit is set in SCSCR2 */1.138 +#define IS_TRANSMIT_ENABLED() (MMIO_READ(SCIF,SCSCR2) & SCSCR2_TE)1.139 +#define IS_LOOPBACK_ENABLED() (MMIO_READ(SCIF,SCFCR2) & SCFCR2_LOOP)1.140 +1.141 +/* Serial status register flags */1.142 +#define SCFSR2_ER 0x801.143 +#define SCFSR2_TEND 0x401.144 +#define SCFSR2_TDFE 0x201.145 +#define SCFSR2_BRK 0x101.146 +#define SCFSR2_RDF 0x021.147 +#define SCFSR2_DR 0x011.148 +1.149 +/* FIFO control register flags */1.150 +#define SCFCR2_MCE 0x081.151 +#define SCFCR2_TFRST 0x041.152 +#define SCFCR2_RFRST 0x021.153 +#define SCFCR2_LOOP 0x011.154 +1.155 +/* Line Status Register */1.156 +#define SCLSR2_ORER 0x011.157 +1.158 +struct SCIF_fifo {1.159 + int head;1.160 + int tail;1.161 + int trigger;1.162 + uint8_t data[FIFO_ARR_LENGTH];1.163 +};1.164 +1.165 +void SCIF_save_state( FILE *f )1.166 +{1.167 +1.168 +1.169 +}1.170 +1.171 +int SCIF_load_state( FILE *f )1.172 +{1.173 + return 0;1.174 +}1.175 +1.176 +int SCIF_recvq_triggers[4] = {1, 4, 8, 14};1.177 +struct SCIF_fifo SCIF_recvq = {0,0,1};1.178 +1.179 +int SCIF_sendq_triggers[4] = {8, 4, 2, 1};1.180 +struct SCIF_fifo SCIF_sendq = {0,0,8};1.181 +1.182 +static inline uint8_t SCIF_recvq_size( )1.183 +{1.184 + int val = SCIF_recvq.tail - SCIF_recvq.head;1.185 + if( val < 0 ) {1.186 + val = FIFO_ARR_LENGTH - SCIF_recvq.head + SCIF_recvq.tail;1.187 + }1.188 + return val;1.189 +}1.190 +1.191 +int SCIF_recvq_dequeue( gboolean clearFlags )1.192 +{1.193 + uint8_t result;1.194 + uint32_t tmp, length;1.195 + if( SCIF_recvq.head == SCIF_recvq.tail )1.196 + return -1; /* No data */1.197 + result = SCIF_recvq.data[SCIF_recvq.head++];1.198 + if( SCIF_recvq.head > FIFO_LENGTH )1.199 + SCIF_recvq.head = 0;1.200 +1.201 + /* Update data count register */1.202 + tmp = MMIO_READ( SCIF, SCFDR2 ) & 0xF0;1.203 + length = SCIF_recvq_size();1.204 + MMIO_WRITE( SCIF, SCFDR2, tmp | length );1.205 +1.206 + /* Clear flags (if requested ) */1.207 + if( clearFlags && length < SCIF_recvq.trigger ) {1.208 + tmp = SCFSR2_RDF;1.209 + if( length == 0 )1.210 + tmp |= SCFSR2_DR;1.211 + tmp = MMIO_READ( SCIF, SCFSR2 ) & (~tmp);1.212 + MMIO_WRITE( SCIF, SCFSR2, tmp );1.213 + /* If both flags are cleared, clear the interrupt as well */1.214 + if( tmp & (SCFSR2_DR|SCFSR2_RDF) == 0 )1.215 + intc_clear_interrupt( INT_SCIF_RXI );1.216 + }1.217 +1.218 + return (int)(unsigned int)result;1.219 +}1.220 +1.221 +gboolean SCIF_recvq_enqueue( uint8_t value )1.222 +{1.223 + uint32_t tmp, length;1.224 + int newpos = SCIF_recvq.tail + 1;1.225 + if( newpos > FIFO_LENGTH )1.226 + newpos = 0;1.227 + if( newpos == SCIF_recvq.head ) {1.228 + /* FIFO full - set ORER and discard the value */1.229 + MMIO_WRITE( SCIF, SCLSR2, SCLSR2_ORER );1.230 + if( IS_RECEIVE_ERROR_IRQ_ENABLED() )1.231 + intc_raise_interrupt( INT_SCIF_ERI );1.232 + return FALSE;1.233 + }1.234 + SCIF_recvq.data[SCIF_recvq.tail] = value;1.235 +1.236 + /* Update data count register */1.237 + tmp = MMIO_READ( SCIF, SCFDR2 ) & 0xF0;1.238 + length = SCIF_recvq_size();1.239 + MMIO_WRITE( SCIF, SCFDR2, tmp | length );1.240 +1.241 + /* Update status register */1.242 + tmp = MMIO_READ( SCIF, SCFSR2 );1.243 + if( length >= SCIF_recvq.trigger ) {1.244 + tmp |= SCFSR2_RDF;1.245 + if( IS_RECEIVE_IRQ_ENABLED() )1.246 + intc_raise_interrupt( INT_SCIF_RXI );1.247 + }1.248 + MMIO_WRITE( SCIF, SCFSR2, tmp );1.249 + return TRUE;1.250 +}1.251 +1.252 +1.253 +/**1.254 + * Reset the receive FIFO to its initial state. Manual is unclear as to1.255 + * whether this also clears flags/interrupts, but we're assuming here that1.256 + * it does until proven otherwise.1.257 + */1.258 +void SCIF_recvq_clear( void )1.259 +{1.260 + SCIF_recvq.head = SCIF_recvq.tail = 0;1.261 + MMIO_WRITE( SCIF, SCFDR2, MMIO_READ( SCIF, SCFDR2 ) & 0xF0 );1.262 + MMIO_WRITE( SCIF, SCFSR2, MMIO_READ( SCIF, SCFSR2 ) & ~(SCFSR2_DR|SCFSR2_RDF) );1.263 + intc_clear_interrupt( INT_SCIF_RXI );1.264 +}1.265 +1.266 +static inline uint8_t SCIF_sendq_size( )1.267 +{1.268 + int val = SCIF_sendq.tail - SCIF_sendq.head;1.269 + if( val < 0 ) {1.270 + val = FIFO_ARR_LENGTH - SCIF_sendq.head + SCIF_sendq.tail;1.271 + }1.272 + return val;1.273 +}1.274 +1.275 +/**1.276 + * Dequeue one byte from the SCIF transmit queue (ie transmit the byte),1.277 + * updating all status flags as required.1.278 + * @return The byte dequeued, or -1 if the queue is empty.1.279 + */1.280 +int SCIF_sendq_dequeue( )1.281 +{1.282 + uint8_t result;1.283 + uint32_t tmp, length;1.284 + if( SCIF_sendq.head == SCIF_sendq.tail )1.285 + return -1; /* No data */1.286 +1.287 + /* Update queue head pointer */1.288 + result = SCIF_sendq.data[SCIF_sendq.head++];1.289 + if( SCIF_sendq.head > FIFO_LENGTH )1.290 + SCIF_sendq.head = 0;1.291 +1.292 + /* Update data count register */1.293 + tmp = MMIO_READ( SCIF, SCFDR2 ) & 0x0F;1.294 + length = SCIF_sendq_size();1.295 + MMIO_WRITE( SCIF, SCFDR2, tmp | (length << 8) );1.296 +1.297 + /* Update status register */1.298 + if( length <= SCIF_sendq.trigger ) {1.299 + tmp = MMIO_READ( SCIF, SCFSR2 ) | SCFSR2_TDFE;1.300 + if( length == 0 )1.301 + tmp |= SCFSR2_TEND; /* Transmission ended - no data waiting */1.302 + if( IS_TRANSMIT_IRQ_ENABLED() )1.303 + intc_raise_interrupt( INT_SCIF_TXI );1.304 + MMIO_WRITE( SCIF, SCFSR2, tmp );1.305 + }1.306 + return (int)(unsigned int)result;1.307 +}1.308 +1.309 +/**1.310 + * Enqueue a single byte in the SCIF transmit queue. If the queue is full,1.311 + * the value will be discarded.1.312 + * @param value to be queued.1.313 + * @param clearFlags TRUE if the TEND/TDFE flags should be cleared1.314 + * if the queue exceeds the trigger level. (According to the manual,1.315 + * DMAC writes will clear the flag, whereas regular SH4 writes do NOT1.316 + * automatically clear it. Go figure).1.317 + * @return gboolean TRUE if the value was queued, FALSE if the queue was1.318 + * full.1.319 + */1.320 +gboolean SCIF_sendq_enqueue( uint8_t value, gboolean clearFlags )1.321 +{1.322 + uint32_t tmp, length;1.323 + int newpos = SCIF_sendq.tail + 1;1.324 + if( newpos > FIFO_LENGTH )1.325 + newpos = 0;1.326 + if( newpos == SCIF_sendq.head ) {1.327 + /* FIFO full - discard */1.328 + return FALSE;1.329 + }1.330 + SCIF_sendq.data[SCIF_sendq.tail] = value;1.331 + SCIF_sendq.tail = newpos;1.332 +1.333 + /* Update data count register */1.334 + tmp = MMIO_READ( SCIF, SCFDR2 ) & 0x0F;1.335 + length = SCIF_sendq_size();1.336 + MMIO_WRITE( SCIF, SCFDR2, tmp | (length << 8) );1.337 +1.338 + /* Update flags if requested */1.339 + if( clearFlags ) {1.340 + tmp = SCFSR2_TEND;1.341 + if( length > SCIF_sendq.trigger ) {1.342 + tmp |= SCFSR2_TDFE;1.343 + intc_clear_interrupt( INT_SCIF_TXI );1.344 + }1.345 + tmp = MMIO_READ( SCIF, SCFSR2 ) & (~tmp);1.346 + MMIO_WRITE( SCIF, SCFSR2, tmp );1.347 + }1.348 + return TRUE;1.349 +}1.350 +1.351 +void SCIF_sendq_clear( void )1.352 +{1.353 + SCIF_sendq.head = SCIF_sendq.tail = 0;1.354 + MMIO_WRITE( SCIF, SCFDR2, MMIO_READ( SCIF, SCFDR2 ) & 0x0F );1.355 + MMIO_WRITE( SCIF, SCFSR2, MMIO_READ( SCIF, SCFSR2 ) | SCFSR2_TEND | SCFSR2_TDFE );1.356 + if( IS_TRANSMIT_IRQ_ENABLED() ) {1.357 + intc_raise_interrupt( INT_SCIF_TXI );1.358 + }1.359 +}1.360 +1.361 +1.362 +/**1.363 + * Set the break detected flag1.364 + */1.365 +void SCIF_set_break( void )1.366 +{1.367 + MMIO_WRITE( SCIF, SCFSR2, MMIO_READ( SCIF, SCFSR2 ) | SCFSR2_BRK );1.368 + if( IS_RECEIVE_ERROR_IRQ_ENABLED() )1.369 + intc_raise_interrupt( INT_SCIF_BRI );1.370 +}1.371 +1.372 +const static int SCIF_CLOCK_MULTIPLIER[4] = {1, 4, 16, 64};1.373 +1.374 +/**1.375 + * Calculate the current line speed.1.376 + */1.377 +void SCIF_update_line_speed( void )1.378 +{1.379 + /* If CKE1 is set, use the external clock as a base */1.380 + if( MMIO_READ( SCIF, SCSCR2 ) & SCSCR2_CKE ) {1.381 +1.382 +1.383 + } else {1.384 +1.385 + /* Otherwise, SH4 peripheral clock divided by n */1.386 + int mult = SCIF_CLOCK_MULTIPLIER[MMIO_READ( SCIF, SCSMR2 ) & 0x03];1.387 +1.388 + /* Then process the bitrate register */1.389 + int bbr = MMIO_READ( SCIF, SCBRR2 ) & 0xFF;1.390 +1.391 + int baudrate = sh4_peripheral_freq / (32 * mult * (bbr+1) );1.392 +1.393 + if( serial_device != NULL && serial_device->set_line_speed != NULL )1.394 + serial_device->set_line_speed( baudrate );1.395 + INFO( "SCIF baud rate set to %d", baudrate );1.396 + /*1.397 + clock_set_tick_rate( CLOCK_SCIF, baudrate / 10 );1.398 + */1.399 + }1.400 +}1.401 +1.402 +int32_t mmio_region_SCIF_read( uint32_t reg )1.403 +{1.404 + switch( reg ) {1.405 + case SCFRDR2: /* Receive data */1.406 + return SCIF_recvq_dequeue(FALSE);1.407 + default:1.408 + return MMIO_READ( SCIF, reg );1.409 + }1.410 +}1.411 +1.412 +void mmio_region_SCIF_write( uint32_t reg, uint32_t val )1.413 +{1.414 + uint32_t tmp;1.415 + switch( reg ) {1.416 + case SCSMR2: /* Serial mode register */1.417 + /* Bit 6 => 0 = 8-bit, 1 = 7-bit1.418 + * Bit 5 => 0 = Parity disabled, 1 = parity enabled1.419 + * Bit 4 => 0 = Even parity, 1 = Odd parity1.420 + * Bit 3 => 0 = 1 stop bit, 1 = 2 stop bits1.421 + * Bits 0-1 => Clock select 00 = P, 01 = P/4, 10 = P/16, 11 = P/641.422 + */1.423 + val &= 0x007B;1.424 + if( serial_device != NULL ) {1.425 + serial_device->set_line_params( val );1.426 + }1.427 + tmp = MMIO_READ( SCIF, SCSMR2 );1.428 + if( tmp & 0x03 != val & 0x03 ) {1.429 + /* Clock change */1.430 + SCIF_update_line_speed( );1.431 + }1.432 + /* Save for later read-back */1.433 + MMIO_WRITE( SCIF, SCSMR2, val );1.434 + break;1.435 + case SCBRR2: /* Bit rate register */1.436 + MMIO_WRITE( SCIF, SCBRR2, val );1.437 + SCIF_update_line_speed( );1.438 + break;1.439 + case SCSCR2: /* Serial control register */1.440 + /* Bit 7 => Transmit-FIFO-data-empty interrupt enabled1.441 + * Bit 6 => Receive-data-full interrupt enabled1.442 + * Bit 5 => Transmit enable1.443 + * Bit 4 => Receive enable1.444 + * Bit 3 => Receive-error/break interrupt enabled1.445 + * Bit 1 => Clock enable1.446 + */1.447 + val &= 0x00FA;1.448 + /* Clear any interrupts that just became disabled */1.449 + if( val & SCSCR2_TIE == 0 )1.450 + intc_clear_interrupt( INT_SCIF_TXI );1.451 + if( val & SCSCR2_RIE == 0 )1.452 + intc_clear_interrupt( INT_SCIF_RXI );1.453 + if( val & (SCSCR2_RIE|SCSCR2_REIE) == 0 ) {1.454 + intc_clear_interrupt( INT_SCIF_ERI );1.455 + intc_clear_interrupt( INT_SCIF_BRI );1.456 + }1.457 +1.458 + MMIO_WRITE( SCIF, reg, val );1.459 + break;1.460 + case SCFTDR2: /* Transmit FIFO data register */1.461 + SCIF_sendq_enqueue( val, FALSE );1.462 + break;1.463 + case SCFSR2: /* Serial status register */1.464 + /* Bits 12-15 Parity error count1.465 + * Bits 8-11 Framing erro count1.466 + * Bit 7 - Receive error1.467 + * Bit 6 - Transmit end1.468 + * Bit 5 - Transmit FIFO data empty1.469 + * Bit 4 - Break detect1.470 + * Bit 3 - Framing error1.471 + * Bit 2 - Parity error1.472 + * Bit 1 - Receive FIFO data full1.473 + * Bit 0 - Receive data ready1.474 + */1.475 + tmp = MMIO_READ( SCIF, SCFSR2 );1.476 + tmp &= val;1.477 + /* Clear off any flags/interrupts that are being set to 0 */1.478 + MMIO_WRITE( SCIF, reg, tmp );1.479 + break;1.480 + case SCFCR2: /* FIFO control register */1.481 + val &= 0x0F;1.482 + SCIF_recvq.trigger = SCIF_recvq_triggers[val >> 6];1.483 + SCIF_sendq.trigger = SCIF_sendq_triggers[(val >> 4) & 0x03];1.484 + if( val & SCFCR2_TFRST ) {1.485 + SCIF_sendq_clear();1.486 + }1.487 + if( val & SCFCR2_RFRST ) {1.488 + SCIF_recvq_clear();1.489 + }1.490 +1.491 + MMIO_WRITE( SCIF, reg, val );1.492 + break;1.493 + case SCSPTR2: /* Serial Port Register */1.494 + MMIO_WRITE( SCIF, reg, val );1.495 + /* NOT IMPLEMENTED */1.496 + break;1.497 + case SCLSR2:1.498 + val = val & SCLSR2_ORER;1.499 + if( val == 0 ) {1.500 + MMIO_WRITE( SCIF, SCLSR2, val );1.501 + if( MMIO_READ( SCIF, SCFSR2 ) & SCFSR2_ER == 0)1.502 + intc_clear_interrupt( INT_SCIF_ERI );1.503 + }1.504 +1.505 + break;1.506 + }1.507 +}1.508 +1.509 +/**1.510 + * Flag to indicate if data was received (ie added to the receive queue)1.511 + * during the last SCIF clock tick. Used to determine when to set the DR1.512 + * flag.1.513 + */1.514 +gboolean SCIF_rcvd_last_tick = FALSE;1.515 +1.516 +/**1.517 + * Actions for a single tick of the serial clock, defined as the transmission1.518 + * time of a single frame.1.519 + *1.520 + * If transmit queue is non-empty:1.521 + * Transmit one byte and remove from queue1.522 + * If input receive source is non-empty:1.523 + * Transfer one byte to the receive queue (if queue is full, byte is lost)1.524 + * If recvq is non-empty, less than the trigger level, and no data has been1.525 + * received in the last 2 ticks (including this one), set the DR flag and1.526 + * IRQ if appropriate.1.527 + */1.528 +void SCIF_clock_tick( void )1.529 +{1.530 + gboolean rcvd = FALSE;1.531 +1.532 + if( IS_LOOPBACK_ENABLED() ) {1.533 + if( IS_TRANSMIT_ENABLED() ) {1.534 + int val = SCIF_sendq_dequeue();1.535 + if( val != -1 && IS_RECEIVE_ENABLED() ) {1.536 + SCIF_recvq_enqueue( val );1.537 + rcvd = TRUE;1.538 + }1.539 + }1.540 + } else {1.541 + if( IS_TRANSMIT_ENABLED() ) {1.542 + int val = SCIF_sendq_dequeue();1.543 + if( val != -1 && serial_device != NULL &&1.544 + serial_device->receive_data != NULL ) {1.545 + serial_device->receive_data( val );1.546 + }1.547 + }1.548 +1.549 + if( IS_RECEIVE_ENABLED() ) {1.550 + int val = serial_transmit_dequeue();1.551 + if( val != -1 ) {1.552 + SCIF_recvq_enqueue( val );1.553 + rcvd = TRUE;1.554 + }1.555 + }1.556 + }1.557 +1.558 + /* Check if we need to set the DR flag */1.559 + if( !rcvd && !SCIF_rcvd_last_tick &&1.560 + SCIF_recvq.head != SCIF_recvq.tail &&1.561 + SCIF_recvq_size() < SCIF_recvq.trigger ) {1.562 + uint32_t tmp = MMIO_READ( SCIF, SCFSR2 );1.563 + if( tmp & SCFSR2_DR == 0 ) {1.564 + MMIO_WRITE( SCIF, SCFSR2, tmp | SCFSR2_DR );1.565 + if( IS_RECEIVE_IRQ_ENABLED() )1.566 + intc_raise_interrupt( INT_SCIF_RXI );1.567 + }1.568 + }1.569 + SCIF_rcvd_last_tick = rcvd;1.570 +}
.