Search
lxdream.org :: lxdream/src/sh4/scif.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/scif.c
changeset 20:3ffb66aa25c7
next21:fda269b432a7
author nkeynes
date Thu Dec 22 13:28:16 2005 +0000 (14 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
nkeynes@20
     1
/**
nkeynes@20
     2
 * $Id: scif.c,v 1.1 2005-12-22 13:28:16 nkeynes Exp $
nkeynes@20
     3
 * SCIF (Serial Communication Interface with FIFO) implementation - part of the 
nkeynes@20
     4
 * SH4 standard on-chip peripheral set. The SCIF is hooked up to the DCs
nkeynes@20
     5
 * external serial port
nkeynes@20
     6
 *
nkeynes@20
     7
 * Copyright (c) 2005 Nathan Keynes.
nkeynes@20
     8
 *
nkeynes@20
     9
 * This program is free software; you can redistribute it and/or modify
nkeynes@20
    10
 * it under the terms of the GNU General Public License as published by
nkeynes@20
    11
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@20
    12
 * (at your option) any later version.
nkeynes@20
    13
 *
nkeynes@20
    14
 * This program is distributed in the hope that it will be useful,
nkeynes@20
    15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@20
    16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@20
    17
 * GNU General Public License for more details.
nkeynes@20
    18
 */
nkeynes@20
    19
nkeynes@20
    20
#include <glib.h>
nkeynes@20
    21
#include "dream.h"
nkeynes@20
    22
#include "mem.h"
nkeynes@20
    23
#include "sh4core.h"
nkeynes@20
    24
#include "sh4mmio.h"
nkeynes@20
    25
#include "intc.h"
nkeynes@20
    26
#include "clock.h"
nkeynes@20
    27
#include "serial.h"
nkeynes@20
    28
#include "modules.h"
nkeynes@20
    29
nkeynes@20
    30
void SCIF_set_break(void);
nkeynes@20
    31
nkeynes@20
    32
/************************* External serial interface ************************/
nkeynes@20
    33
nkeynes@20
    34
/**
nkeynes@20
    35
 * Note: serial_* operations are called from outside the SH4, and as such are
nkeynes@20
    36
 * named relative to the external serial device. SCIF_* operations are only
nkeynes@20
    37
 * called internally to the SH4 and so are named relative to the CPU.
nkeynes@20
    38
 */
nkeynes@20
    39
nkeynes@20
    40
/**
nkeynes@20
    41
 * Storage space for inbound/outbound data blocks. It's a little more
nkeynes@20
    42
 * convenient for serial consumers to be able to deal with block-sized pieces
nkeynes@20
    43
 * rather than a byte at a time, even if it makes all this look rather
nkeynes@20
    44
 * complicated.
nkeynes@20
    45
 *
nkeynes@20
    46
 * Currently there's no limit on the number of blocks that can be queued up.
nkeynes@20
    47
 */
nkeynes@20
    48
typedef struct serial_data_block {
nkeynes@20
    49
    uint32_t length;
nkeynes@20
    50
    uint32_t offset;
nkeynes@20
    51
    struct serial_data_block *next;
nkeynes@20
    52
    char data[];
nkeynes@20
    53
} *serial_data_block_t;
nkeynes@20
    54
nkeynes@20
    55
serial_data_block_t serial_recvq_head = NULL, serial_recvq_tail = NULL;
nkeynes@20
    56
serial_device_t serial_device = NULL;
nkeynes@20
    57
nkeynes@20
    58
void serial_attach_device( serial_device_t dev ) 
nkeynes@20
    59
{
nkeynes@20
    60
    if( serial_device != NULL )
nkeynes@20
    61
	serial_detach_device();
nkeynes@20
    62
    serial_device = dev;
nkeynes@20
    63
}
nkeynes@20
    64
nkeynes@20
    65
nkeynes@20
    66
void serial_detach_device( void )
nkeynes@20
    67
{
nkeynes@20
    68
    serial_device = NULL;
nkeynes@20
    69
}
nkeynes@20
    70
nkeynes@20
    71
/**
nkeynes@20
    72
 * Add a block of data to the serial receive queue. The data will be received
nkeynes@20
    73
 * by the CPU at the appropriate baud rate.
nkeynes@20
    74
 */
nkeynes@20
    75
void serial_transmit_data( char *data, int length ) {
nkeynes@20
    76
    if( length == 0 )
nkeynes@20
    77
	return;
nkeynes@20
    78
    serial_data_block_t block = 
nkeynes@20
    79
	g_malloc( sizeof( struct serial_data_block ) + length );
nkeynes@20
    80
    block->length = length;
nkeynes@20
    81
    block->offset = 0;
nkeynes@20
    82
    block->next = NULL;
nkeynes@20
    83
    memcpy( block->data, data, length );
nkeynes@20
    84
    
nkeynes@20
    85
    if( serial_recvq_head == NULL ) {
nkeynes@20
    86
	serial_recvq_head = serial_recvq_tail = block;
nkeynes@20
    87
    } else {
nkeynes@20
    88
	serial_recvq_tail->next = block;
nkeynes@20
    89
	serial_recvq_tail = block;
nkeynes@20
    90
    }
nkeynes@20
    91
}
nkeynes@20
    92
nkeynes@20
    93
/**
nkeynes@20
    94
 * Dequeue a byte from the serial input queue
nkeynes@20
    95
 */
nkeynes@20
    96
static int serial_transmit_dequeue( ) {
nkeynes@20
    97
    if( serial_recvq_head != NULL ) {
nkeynes@20
    98
	uint8_t val = serial_recvq_head->data[serial_recvq_head->offset++];
nkeynes@20
    99
	if( serial_recvq_head->offset >= serial_recvq_head->length ) {
nkeynes@20
   100
	    serial_data_block_t next = serial_recvq_head->next;
nkeynes@20
   101
	    g_free( serial_recvq_head );
nkeynes@20
   102
	    serial_recvq_head = next;
nkeynes@20
   103
	    if( next == NULL )
nkeynes@20
   104
		serial_recvq_tail = NULL;
nkeynes@20
   105
	}
nkeynes@20
   106
	return (int)(unsigned int)val;
nkeynes@20
   107
    }
nkeynes@20
   108
    return -1;
nkeynes@20
   109
nkeynes@20
   110
}
nkeynes@20
   111
nkeynes@20
   112
void serial_transmit_break() {
nkeynes@20
   113
    SCIF_set_break();
nkeynes@20
   114
}
nkeynes@20
   115
nkeynes@20
   116
/********************************* SCIF *************************************/
nkeynes@20
   117
nkeynes@20
   118
#define FIFO_LENGTH 16
nkeynes@20
   119
#define FIFO_ARR_LENGTH (FIFO_LENGTH+1)
nkeynes@20
   120
nkeynes@20
   121
/* Serial control register flags */
nkeynes@20
   122
#define SCSCR2_TIE  0x80
nkeynes@20
   123
#define SCSCR2_RIE  0x40
nkeynes@20
   124
#define SCSCR2_TE   0x20
nkeynes@20
   125
#define SCSCR2_RE   0x10
nkeynes@20
   126
#define SCSCR2_REIE 0x08
nkeynes@20
   127
#define SCSCR2_CKE 0x02
nkeynes@20
   128
nkeynes@20
   129
#define IS_TRANSMIT_IRQ_ENABLED() (MMIO_READ(SCIF,SCSCR2) & SCSCR2_TIE)
nkeynes@20
   130
#define IS_RECEIVE_IRQ_ENABLED() (MMIO_READ(SCIF,SCSCR2) & SCSCR2_RIE)
nkeynes@20
   131
#define IS_RECEIVE_ERROR_IRQ_ENABLED() (MMIO_READ(SCIF,SCSCR2) & (SCSCR2_RIE|SCSCR2_REIE))
nkeynes@20
   132
/* Receive is enabled if the RE bit is set in SCSCR2, and the ORER bit is cleared in SCLSR2 */
nkeynes@20
   133
#define IS_RECEIVE_ENABLED() ( (MMIO_READ(SCIF,SCSCR2) & SCSCR2_RE) && (MMIO_READ(SCIF,SCLSR2) & SCLSR2_ORER == 0) )
nkeynes@20
   134
/* Transmit is enabled if the TE bit is set in SCSCR2 */
nkeynes@20
   135
#define IS_TRANSMIT_ENABLED() (MMIO_READ(SCIF,SCSCR2) & SCSCR2_TE)
nkeynes@20
   136
#define IS_LOOPBACK_ENABLED() (MMIO_READ(SCIF,SCFCR2) & SCFCR2_LOOP)
nkeynes@20
   137
nkeynes@20
   138
/* Serial status register flags */
nkeynes@20
   139
#define SCFSR2_ER   0x80
nkeynes@20
   140
#define SCFSR2_TEND 0x40
nkeynes@20
   141
#define SCFSR2_TDFE 0x20
nkeynes@20
   142
#define SCFSR2_BRK  0x10
nkeynes@20
   143
#define SCFSR2_RDF  0x02
nkeynes@20
   144
#define SCFSR2_DR   0x01
nkeynes@20
   145
nkeynes@20
   146
/* FIFO control register flags */
nkeynes@20
   147
#define SCFCR2_MCE   0x08
nkeynes@20
   148
#define SCFCR2_TFRST 0x04
nkeynes@20
   149
#define SCFCR2_RFRST 0x02
nkeynes@20
   150
#define SCFCR2_LOOP  0x01
nkeynes@20
   151
nkeynes@20
   152
/* Line Status Register */
nkeynes@20
   153
#define SCLSR2_ORER 0x01
nkeynes@20
   154
nkeynes@20
   155
struct SCIF_fifo {
nkeynes@20
   156
    int head;
nkeynes@20
   157
    int tail;
nkeynes@20
   158
    int trigger;
nkeynes@20
   159
    uint8_t data[FIFO_ARR_LENGTH];
nkeynes@20
   160
};
nkeynes@20
   161
nkeynes@20
   162
void SCIF_save_state( FILE *f ) 
nkeynes@20
   163
{
nkeynes@20
   164
    
nkeynes@20
   165
nkeynes@20
   166
}
nkeynes@20
   167
nkeynes@20
   168
int SCIF_load_state( FILE *f ) 
nkeynes@20
   169
{
nkeynes@20
   170
    return 0;
nkeynes@20
   171
}
nkeynes@20
   172
nkeynes@20
   173
int SCIF_recvq_triggers[4] = {1, 4, 8, 14};
nkeynes@20
   174
struct SCIF_fifo SCIF_recvq = {0,0,1};
nkeynes@20
   175
nkeynes@20
   176
int SCIF_sendq_triggers[4] = {8, 4, 2, 1};
nkeynes@20
   177
struct SCIF_fifo SCIF_sendq = {0,0,8};
nkeynes@20
   178
nkeynes@20
   179
static inline uint8_t SCIF_recvq_size( ) 
nkeynes@20
   180
{
nkeynes@20
   181
    int val = SCIF_recvq.tail - SCIF_recvq.head;
nkeynes@20
   182
    if( val < 0 ) {
nkeynes@20
   183
	val = FIFO_ARR_LENGTH - SCIF_recvq.head + SCIF_recvq.tail;
nkeynes@20
   184
    }
nkeynes@20
   185
    return val;
nkeynes@20
   186
}
nkeynes@20
   187
nkeynes@20
   188
int SCIF_recvq_dequeue( gboolean clearFlags )
nkeynes@20
   189
{
nkeynes@20
   190
    uint8_t result;
nkeynes@20
   191
    uint32_t tmp, length;
nkeynes@20
   192
    if( SCIF_recvq.head == SCIF_recvq.tail )
nkeynes@20
   193
	return -1; /* No data */
nkeynes@20
   194
    result = SCIF_recvq.data[SCIF_recvq.head++];
nkeynes@20
   195
    if( SCIF_recvq.head > FIFO_LENGTH )
nkeynes@20
   196
	SCIF_recvq.head = 0;
nkeynes@20
   197
nkeynes@20
   198
    /* Update data count register */
nkeynes@20
   199
    tmp = MMIO_READ( SCIF, SCFDR2 ) & 0xF0;
nkeynes@20
   200
    length = SCIF_recvq_size();
nkeynes@20
   201
    MMIO_WRITE( SCIF, SCFDR2, tmp | length );
nkeynes@20
   202
nkeynes@20
   203
    /* Clear flags (if requested ) */
nkeynes@20
   204
    if( clearFlags && length < SCIF_recvq.trigger ) {
nkeynes@20
   205
	tmp = SCFSR2_RDF;
nkeynes@20
   206
	if( length == 0 )
nkeynes@20
   207
	    tmp |= SCFSR2_DR;
nkeynes@20
   208
	tmp = MMIO_READ( SCIF, SCFSR2 ) & (~tmp);
nkeynes@20
   209
	MMIO_WRITE( SCIF, SCFSR2, tmp );
nkeynes@20
   210
	/* If both flags are cleared, clear the interrupt as well */
nkeynes@20
   211
	if( tmp & (SCFSR2_DR|SCFSR2_RDF) == 0 )
nkeynes@20
   212
	    intc_clear_interrupt( INT_SCIF_RXI );
nkeynes@20
   213
    }
nkeynes@20
   214
	    
nkeynes@20
   215
    return (int)(unsigned int)result;
nkeynes@20
   216
}
nkeynes@20
   217
nkeynes@20
   218
gboolean SCIF_recvq_enqueue( uint8_t value )
nkeynes@20
   219
{
nkeynes@20
   220
    uint32_t tmp, length;
nkeynes@20
   221
    int newpos = SCIF_recvq.tail + 1;
nkeynes@20
   222
    if( newpos > FIFO_LENGTH )
nkeynes@20
   223
	newpos = 0;
nkeynes@20
   224
    if( newpos == SCIF_recvq.head ) {
nkeynes@20
   225
	/* FIFO full - set ORER and discard the value */
nkeynes@20
   226
	MMIO_WRITE( SCIF, SCLSR2, SCLSR2_ORER );
nkeynes@20
   227
	if( IS_RECEIVE_ERROR_IRQ_ENABLED() )
nkeynes@20
   228
	    intc_raise_interrupt( INT_SCIF_ERI );
nkeynes@20
   229
	return FALSE;
nkeynes@20
   230
    }
nkeynes@20
   231
    SCIF_recvq.data[SCIF_recvq.tail] = value;
nkeynes@20
   232
nkeynes@20
   233
    /* Update data count register */
nkeynes@20
   234
    tmp = MMIO_READ( SCIF, SCFDR2 ) & 0xF0;
nkeynes@20
   235
    length = SCIF_recvq_size();
nkeynes@20
   236
    MMIO_WRITE( SCIF, SCFDR2, tmp | length );
nkeynes@20
   237
nkeynes@20
   238
    /* Update status register */
nkeynes@20
   239
    tmp = MMIO_READ( SCIF, SCFSR2 );
nkeynes@20
   240
    if( length >= SCIF_recvq.trigger ) {
nkeynes@20
   241
	tmp |= SCFSR2_RDF;
nkeynes@20
   242
	if( IS_RECEIVE_IRQ_ENABLED() ) 
nkeynes@20
   243
	    intc_raise_interrupt( INT_SCIF_RXI );
nkeynes@20
   244
    }
nkeynes@20
   245
    MMIO_WRITE( SCIF, SCFSR2, tmp );
nkeynes@20
   246
    return TRUE;
nkeynes@20
   247
}
nkeynes@20
   248
nkeynes@20
   249
nkeynes@20
   250
/**
nkeynes@20
   251
 * Reset the receive FIFO to its initial state. Manual is unclear as to
nkeynes@20
   252
 * whether this also clears flags/interrupts, but we're assuming here that
nkeynes@20
   253
 * it does until proven otherwise.
nkeynes@20
   254
 */
nkeynes@20
   255
void SCIF_recvq_clear( void ) 
nkeynes@20
   256
{
nkeynes@20
   257
    SCIF_recvq.head = SCIF_recvq.tail = 0;
nkeynes@20
   258
    MMIO_WRITE( SCIF, SCFDR2, MMIO_READ( SCIF, SCFDR2 ) & 0xF0 );
nkeynes@20
   259
    MMIO_WRITE( SCIF, SCFSR2, MMIO_READ( SCIF, SCFSR2 ) & ~(SCFSR2_DR|SCFSR2_RDF) );
nkeynes@20
   260
    intc_clear_interrupt( INT_SCIF_RXI );
nkeynes@20
   261
}
nkeynes@20
   262
nkeynes@20
   263
static inline uint8_t SCIF_sendq_size( ) 
nkeynes@20
   264
{
nkeynes@20
   265
    int val = SCIF_sendq.tail - SCIF_sendq.head;
nkeynes@20
   266
    if( val < 0 ) {
nkeynes@20
   267
	val = FIFO_ARR_LENGTH - SCIF_sendq.head + SCIF_sendq.tail;
nkeynes@20
   268
    }
nkeynes@20
   269
    return val;
nkeynes@20
   270
}
nkeynes@20
   271
nkeynes@20
   272
/**
nkeynes@20
   273
 * Dequeue one byte from the SCIF transmit queue (ie transmit the byte),
nkeynes@20
   274
 * updating all status flags as required.
nkeynes@20
   275
 * @return The byte dequeued, or -1 if the queue is empty.
nkeynes@20
   276
 */
nkeynes@20
   277
int SCIF_sendq_dequeue( )
nkeynes@20
   278
{
nkeynes@20
   279
    uint8_t result;
nkeynes@20
   280
    uint32_t tmp, length;
nkeynes@20
   281
    if( SCIF_sendq.head == SCIF_sendq.tail )
nkeynes@20
   282
	return -1; /* No data */
nkeynes@20
   283
nkeynes@20
   284
    /* Update queue head pointer */
nkeynes@20
   285
    result = SCIF_sendq.data[SCIF_sendq.head++];
nkeynes@20
   286
    if( SCIF_sendq.head > FIFO_LENGTH )
nkeynes@20
   287
	SCIF_sendq.head = 0;
nkeynes@20
   288
nkeynes@20
   289
    /* Update data count register */
nkeynes@20
   290
    tmp = MMIO_READ( SCIF, SCFDR2 ) & 0x0F;
nkeynes@20
   291
    length = SCIF_sendq_size();
nkeynes@20
   292
    MMIO_WRITE( SCIF, SCFDR2, tmp | (length << 8) );
nkeynes@20
   293
    
nkeynes@20
   294
    /* Update status register */
nkeynes@20
   295
    if( length <= SCIF_sendq.trigger ) {
nkeynes@20
   296
	tmp = MMIO_READ( SCIF, SCFSR2 ) | SCFSR2_TDFE;
nkeynes@20
   297
	if( length == 0 )
nkeynes@20
   298
	    tmp |= SCFSR2_TEND; /* Transmission ended - no data waiting */
nkeynes@20
   299
	if( IS_TRANSMIT_IRQ_ENABLED() ) 
nkeynes@20
   300
	    intc_raise_interrupt( INT_SCIF_TXI );
nkeynes@20
   301
	MMIO_WRITE( SCIF, SCFSR2, tmp );
nkeynes@20
   302
    }
nkeynes@20
   303
    return (int)(unsigned int)result;
nkeynes@20
   304
}
nkeynes@20
   305
nkeynes@20
   306
/**
nkeynes@20
   307
 * Enqueue a single byte in the SCIF transmit queue. If the queue is full,
nkeynes@20
   308
 * the value will be discarded.
nkeynes@20
   309
 * @param value to be queued.
nkeynes@20
   310
 * @param clearFlags TRUE if the TEND/TDFE flags should be cleared
nkeynes@20
   311
 *   if the queue exceeds the trigger level. (According to the manual,
nkeynes@20
   312
 *   DMAC writes will clear the flag, whereas regular SH4 writes do NOT
nkeynes@20
   313
 *   automatically clear it. Go figure).
nkeynes@20
   314
 * @return gboolean TRUE if the value was queued, FALSE if the queue was
nkeynes@20
   315
 *   full.
nkeynes@20
   316
 */
nkeynes@20
   317
gboolean SCIF_sendq_enqueue( uint8_t value, gboolean clearFlags )
nkeynes@20
   318
{
nkeynes@20
   319
    uint32_t tmp, length;
nkeynes@20
   320
    int newpos = SCIF_sendq.tail + 1;
nkeynes@20
   321
    if( newpos > FIFO_LENGTH )
nkeynes@20
   322
	newpos = 0;
nkeynes@20
   323
    if( newpos == SCIF_sendq.head ) {
nkeynes@20
   324
	/* FIFO full - discard */
nkeynes@20
   325
	return FALSE;
nkeynes@20
   326
    }
nkeynes@20
   327
    SCIF_sendq.data[SCIF_sendq.tail] = value;
nkeynes@20
   328
    SCIF_sendq.tail = newpos;
nkeynes@20
   329
nkeynes@20
   330
    /* Update data count register */
nkeynes@20
   331
    tmp = MMIO_READ( SCIF, SCFDR2 ) & 0x0F;
nkeynes@20
   332
    length = SCIF_sendq_size();
nkeynes@20
   333
    MMIO_WRITE( SCIF, SCFDR2, tmp | (length << 8) );
nkeynes@20
   334
   
nkeynes@20
   335
    /* Update flags if requested */
nkeynes@20
   336
    if( clearFlags ) {
nkeynes@20
   337
	tmp = SCFSR2_TEND;
nkeynes@20
   338
	if( length > SCIF_sendq.trigger ) {
nkeynes@20
   339
	    tmp |= SCFSR2_TDFE;
nkeynes@20
   340
	    intc_clear_interrupt( INT_SCIF_TXI );
nkeynes@20
   341
	}
nkeynes@20
   342
	tmp = MMIO_READ( SCIF, SCFSR2 ) & (~tmp);
nkeynes@20
   343
	MMIO_WRITE( SCIF, SCFSR2, tmp );
nkeynes@20
   344
    }
nkeynes@20
   345
    return TRUE;
nkeynes@20
   346
}
nkeynes@20
   347
nkeynes@20
   348
void SCIF_sendq_clear( void ) 
nkeynes@20
   349
{
nkeynes@20
   350
    SCIF_sendq.head = SCIF_sendq.tail = 0;
nkeynes@20
   351
    MMIO_WRITE( SCIF, SCFDR2, MMIO_READ( SCIF, SCFDR2 ) & 0x0F );
nkeynes@20
   352
    MMIO_WRITE( SCIF, SCFSR2, MMIO_READ( SCIF, SCFSR2 ) | SCFSR2_TEND | SCFSR2_TDFE );
nkeynes@20
   353
    if( IS_TRANSMIT_IRQ_ENABLED() ) {
nkeynes@20
   354
	intc_raise_interrupt( INT_SCIF_TXI );
nkeynes@20
   355
    }
nkeynes@20
   356
}
nkeynes@20
   357
nkeynes@20
   358
nkeynes@20
   359
/**
nkeynes@20
   360
 * Set the break detected flag
nkeynes@20
   361
 */
nkeynes@20
   362
void SCIF_set_break( void ) 
nkeynes@20
   363
{
nkeynes@20
   364
    MMIO_WRITE( SCIF, SCFSR2, MMIO_READ( SCIF, SCFSR2 ) | SCFSR2_BRK );
nkeynes@20
   365
    if( IS_RECEIVE_ERROR_IRQ_ENABLED() )
nkeynes@20
   366
	intc_raise_interrupt( INT_SCIF_BRI );
nkeynes@20
   367
}
nkeynes@20
   368
nkeynes@20
   369
const static int SCIF_CLOCK_MULTIPLIER[4] = {1, 4, 16, 64};
nkeynes@20
   370
nkeynes@20
   371
/**
nkeynes@20
   372
 * Calculate the current line speed.
nkeynes@20
   373
 */
nkeynes@20
   374
void SCIF_update_line_speed( void )
nkeynes@20
   375
{
nkeynes@20
   376
    /* If CKE1 is set, use the external clock as a base */
nkeynes@20
   377
    if( MMIO_READ( SCIF, SCSCR2 ) & SCSCR2_CKE ) {
nkeynes@20
   378
nkeynes@20
   379
nkeynes@20
   380
    } else {
nkeynes@20
   381
nkeynes@20
   382
	/* Otherwise, SH4 peripheral clock divided by n */
nkeynes@20
   383
	int mult = SCIF_CLOCK_MULTIPLIER[MMIO_READ( SCIF, SCSMR2 ) & 0x03];
nkeynes@20
   384
	
nkeynes@20
   385
	/* Then process the bitrate register */
nkeynes@20
   386
	int bbr = MMIO_READ( SCIF, SCBRR2 ) & 0xFF;
nkeynes@20
   387
nkeynes@20
   388
	int baudrate = sh4_peripheral_freq / (32 * mult * (bbr+1) );
nkeynes@20
   389
	
nkeynes@20
   390
	if( serial_device != NULL && serial_device->set_line_speed != NULL )
nkeynes@20
   391
	    serial_device->set_line_speed( baudrate );
nkeynes@20
   392
	INFO( "SCIF baud rate set to %d", baudrate );
nkeynes@20
   393
	/*
nkeynes@20
   394
	  clock_set_tick_rate( CLOCK_SCIF, baudrate / 10 );
nkeynes@20
   395
	*/
nkeynes@20
   396
    }
nkeynes@20
   397
}
nkeynes@20
   398
nkeynes@20
   399
int32_t mmio_region_SCIF_read( uint32_t reg )
nkeynes@20
   400
{
nkeynes@20
   401
    switch( reg ) {
nkeynes@20
   402
    case SCFRDR2: /* Receive data */
nkeynes@20
   403
	return SCIF_recvq_dequeue(FALSE);
nkeynes@20
   404
    default:
nkeynes@20
   405
	return MMIO_READ( SCIF, reg );
nkeynes@20
   406
    }
nkeynes@20
   407
}
nkeynes@20
   408
nkeynes@20
   409
void mmio_region_SCIF_write( uint32_t reg, uint32_t val ) 
nkeynes@20
   410
{
nkeynes@20
   411
    uint32_t tmp;
nkeynes@20
   412
    switch( reg ) {
nkeynes@20
   413
    case SCSMR2: /* Serial mode register */
nkeynes@20
   414
	/* Bit 6 => 0 = 8-bit, 1 = 7-bit
nkeynes@20
   415
	 * Bit 5 => 0 = Parity disabled, 1 = parity enabled
nkeynes@20
   416
	 * Bit 4 => 0 = Even parity, 1 = Odd parity
nkeynes@20
   417
	 * Bit 3 => 0 = 1 stop bit, 1 = 2 stop bits
nkeynes@20
   418
	 * Bits 0-1 => Clock select 00 = P, 01 = P/4, 10 = P/16, 11 = P/64
nkeynes@20
   419
	 */
nkeynes@20
   420
	val &= 0x007B;
nkeynes@20
   421
	if( serial_device != NULL ) {
nkeynes@20
   422
	    serial_device->set_line_params( val );
nkeynes@20
   423
	}
nkeynes@20
   424
	tmp = MMIO_READ( SCIF, SCSMR2 );
nkeynes@20
   425
	if( tmp & 0x03 != val & 0x03 ) {
nkeynes@20
   426
	    /* Clock change */
nkeynes@20
   427
	    SCIF_update_line_speed( );
nkeynes@20
   428
	}
nkeynes@20
   429
	/* Save for later read-back */
nkeynes@20
   430
	MMIO_WRITE( SCIF, SCSMR2, val );
nkeynes@20
   431
	break;
nkeynes@20
   432
    case SCBRR2: /* Bit rate register */
nkeynes@20
   433
	MMIO_WRITE( SCIF, SCBRR2, val );
nkeynes@20
   434
	SCIF_update_line_speed( );
nkeynes@20
   435
	break;
nkeynes@20
   436
    case SCSCR2: /* Serial control register */
nkeynes@20
   437
	/* Bit 7 => Transmit-FIFO-data-empty interrupt enabled 
nkeynes@20
   438
	 * Bit 6 => Receive-data-full interrupt enabled 
nkeynes@20
   439
	 * Bit 5 => Transmit enable 
nkeynes@20
   440
	 * Bit 4 => Receive enable 
nkeynes@20
   441
	 * Bit 3 => Receive-error/break interrupt enabled
nkeynes@20
   442
	 * Bit 1 => Clock enable
nkeynes@20
   443
	 */
nkeynes@20
   444
	val &= 0x00FA;
nkeynes@20
   445
	/* Clear any interrupts that just became disabled */
nkeynes@20
   446
	if( val & SCSCR2_TIE == 0 )
nkeynes@20
   447
	    intc_clear_interrupt( INT_SCIF_TXI );
nkeynes@20
   448
	if( val & SCSCR2_RIE == 0 )
nkeynes@20
   449
	    intc_clear_interrupt( INT_SCIF_RXI );
nkeynes@20
   450
	if( val & (SCSCR2_RIE|SCSCR2_REIE) == 0 ) {
nkeynes@20
   451
	    intc_clear_interrupt( INT_SCIF_ERI );
nkeynes@20
   452
	    intc_clear_interrupt( INT_SCIF_BRI );
nkeynes@20
   453
	}
nkeynes@20
   454
	    
nkeynes@20
   455
	MMIO_WRITE( SCIF, reg, val );
nkeynes@20
   456
	break;
nkeynes@20
   457
    case SCFTDR2: /* Transmit FIFO data register */
nkeynes@20
   458
	SCIF_sendq_enqueue( val, FALSE );
nkeynes@20
   459
	break;
nkeynes@20
   460
    case SCFSR2: /* Serial status register */
nkeynes@20
   461
	/* Bits 12-15 Parity error count
nkeynes@20
   462
	 * Bits 8-11 Framing erro count 
nkeynes@20
   463
	 * Bit 7 - Receive error
nkeynes@20
   464
	 * Bit 6 - Transmit end
nkeynes@20
   465
	 * Bit 5 - Transmit FIFO data empty
nkeynes@20
   466
	 * Bit 4 - Break detect
nkeynes@20
   467
	 * Bit 3 - Framing error
nkeynes@20
   468
	 * Bit 2 - Parity error
nkeynes@20
   469
	 * Bit 1 - Receive FIFO data full
nkeynes@20
   470
	 * Bit 0 - Receive data ready
nkeynes@20
   471
	 */
nkeynes@20
   472
	tmp = MMIO_READ( SCIF, SCFSR2 );
nkeynes@20
   473
	tmp &= val;
nkeynes@20
   474
	/* Clear off any flags/interrupts that are being set to 0 */
nkeynes@20
   475
	MMIO_WRITE( SCIF, reg, tmp );
nkeynes@20
   476
	break;
nkeynes@20
   477
    case SCFCR2: /* FIFO control register */
nkeynes@20
   478
	val &= 0x0F;
nkeynes@20
   479
	SCIF_recvq.trigger = SCIF_recvq_triggers[val >> 6];
nkeynes@20
   480
	SCIF_sendq.trigger = SCIF_sendq_triggers[(val >> 4) & 0x03];
nkeynes@20
   481
	if( val & SCFCR2_TFRST ) {
nkeynes@20
   482
	    SCIF_sendq_clear();
nkeynes@20
   483
	}
nkeynes@20
   484
	if( val & SCFCR2_RFRST ) {
nkeynes@20
   485
	    SCIF_recvq_clear();
nkeynes@20
   486
	}
nkeynes@20
   487
nkeynes@20
   488
	MMIO_WRITE( SCIF, reg, val );
nkeynes@20
   489
	break;
nkeynes@20
   490
    case SCSPTR2: /* Serial Port Register */
nkeynes@20
   491
	MMIO_WRITE( SCIF, reg, val );
nkeynes@20
   492
	/* NOT IMPLEMENTED */
nkeynes@20
   493
	break;
nkeynes@20
   494
    case SCLSR2:
nkeynes@20
   495
	val = val & SCLSR2_ORER;
nkeynes@20
   496
	if( val == 0 ) {
nkeynes@20
   497
	    MMIO_WRITE( SCIF, SCLSR2, val );
nkeynes@20
   498
	    if( MMIO_READ( SCIF, SCFSR2 ) & SCFSR2_ER == 0) 
nkeynes@20
   499
		intc_clear_interrupt( INT_SCIF_ERI );
nkeynes@20
   500
	}
nkeynes@20
   501
	    
nkeynes@20
   502
	break;
nkeynes@20
   503
    }
nkeynes@20
   504
}
nkeynes@20
   505
nkeynes@20
   506
/**
nkeynes@20
   507
 * Flag to indicate if data was received (ie added to the receive queue)
nkeynes@20
   508
 * during the last SCIF clock tick. Used to determine when to set the DR
nkeynes@20
   509
 * flag.
nkeynes@20
   510
 */
nkeynes@20
   511
gboolean SCIF_rcvd_last_tick = FALSE;
nkeynes@20
   512
nkeynes@20
   513
/**
nkeynes@20
   514
 * Actions for a single tick of the serial clock, defined as the transmission
nkeynes@20
   515
 * time of a single frame.
nkeynes@20
   516
 *
nkeynes@20
   517
 * If transmit queue is non-empty:
nkeynes@20
   518
 *    Transmit one byte and remove from queue
nkeynes@20
   519
 * If input receive source is non-empty:
nkeynes@20
   520
 *    Transfer one byte to the receive queue (if queue is full, byte is lost)
nkeynes@20
   521
 * If recvq is non-empty, less than the trigger level, and no data has been
nkeynes@20
   522
 *    received in the last 2 ticks (including this one), set the DR flag and
nkeynes@20
   523
 *    IRQ if appropriate.
nkeynes@20
   524
 */
nkeynes@20
   525
void SCIF_clock_tick( void ) 
nkeynes@20
   526
{
nkeynes@20
   527
    gboolean rcvd = FALSE;
nkeynes@20
   528
nkeynes@20
   529
    if( IS_LOOPBACK_ENABLED() ) {
nkeynes@20
   530
	if( IS_TRANSMIT_ENABLED() ) {
nkeynes@20
   531
	    int val = SCIF_sendq_dequeue();
nkeynes@20
   532
	    if( val != -1 && IS_RECEIVE_ENABLED() ) {
nkeynes@20
   533
		SCIF_recvq_enqueue( val );
nkeynes@20
   534
		rcvd = TRUE;
nkeynes@20
   535
	    }
nkeynes@20
   536
	}
nkeynes@20
   537
    } else {
nkeynes@20
   538
	if( IS_TRANSMIT_ENABLED() ) {
nkeynes@20
   539
	    int val = SCIF_sendq_dequeue();
nkeynes@20
   540
	    if( val != -1 && serial_device != NULL && 
nkeynes@20
   541
		serial_device->receive_data != NULL ) {
nkeynes@20
   542
		serial_device->receive_data( val );
nkeynes@20
   543
	    }
nkeynes@20
   544
	}
nkeynes@20
   545
	
nkeynes@20
   546
	if( IS_RECEIVE_ENABLED() ) {
nkeynes@20
   547
	    int val = serial_transmit_dequeue();
nkeynes@20
   548
	    if( val != -1 ) {
nkeynes@20
   549
		SCIF_recvq_enqueue( val );
nkeynes@20
   550
		rcvd = TRUE;
nkeynes@20
   551
	    }
nkeynes@20
   552
	}
nkeynes@20
   553
    }
nkeynes@20
   554
nkeynes@20
   555
    /* Check if we need to set the DR flag */
nkeynes@20
   556
    if( !rcvd && !SCIF_rcvd_last_tick &&
nkeynes@20
   557
	SCIF_recvq.head != SCIF_recvq.tail &&
nkeynes@20
   558
	SCIF_recvq_size() < SCIF_recvq.trigger ) {
nkeynes@20
   559
	uint32_t tmp = MMIO_READ( SCIF, SCFSR2 );
nkeynes@20
   560
	if( tmp & SCFSR2_DR == 0 ) {
nkeynes@20
   561
	    MMIO_WRITE( SCIF, SCFSR2, tmp | SCFSR2_DR );
nkeynes@20
   562
	    if( IS_RECEIVE_IRQ_ENABLED() )
nkeynes@20
   563
		intc_raise_interrupt( INT_SCIF_RXI );
nkeynes@20
   564
	}
nkeynes@20
   565
    }
nkeynes@20
   566
    SCIF_rcvd_last_tick = rcvd;
nkeynes@20
   567
}
.