symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/mcf_uart.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * ColdFire UART emulation.
       
     3  *
       
     4  * Copyright (c) 2007 CodeSourcery.
       
     5  *
       
     6  * This code is licenced under the GPL
       
     7  */
       
     8 #include "hw.h"
       
     9 #include "mcf.h"
       
    10 #include "qemu-char.h"
       
    11 
       
    12 typedef struct {
       
    13     uint8_t mr[2];
       
    14     uint8_t sr;
       
    15     uint8_t isr;
       
    16     uint8_t imr;
       
    17     uint8_t bg1;
       
    18     uint8_t bg2;
       
    19     uint8_t fifo[4];
       
    20     uint8_t tb;
       
    21     int current_mr;
       
    22     int fifo_len;
       
    23     int tx_enabled;
       
    24     int rx_enabled;
       
    25     qemu_irq irq;
       
    26     CharDriverState *chr;
       
    27 } mcf_uart_state;
       
    28 
       
    29 /* UART Status Register bits.  */
       
    30 #define MCF_UART_RxRDY  0x01
       
    31 #define MCF_UART_FFULL  0x02
       
    32 #define MCF_UART_TxRDY  0x04
       
    33 #define MCF_UART_TxEMP  0x08
       
    34 #define MCF_UART_OE     0x10
       
    35 #define MCF_UART_PE     0x20
       
    36 #define MCF_UART_FE     0x40
       
    37 #define MCF_UART_RB     0x80
       
    38 
       
    39 /* Interrupt flags.  */
       
    40 #define MCF_UART_TxINT  0x01
       
    41 #define MCF_UART_RxINT  0x02
       
    42 #define MCF_UART_DBINT  0x04
       
    43 #define MCF_UART_COSINT 0x80
       
    44 
       
    45 /* UMR1 flags.  */
       
    46 #define MCF_UART_BC0    0x01
       
    47 #define MCF_UART_BC1    0x02
       
    48 #define MCF_UART_PT     0x04
       
    49 #define MCF_UART_PM0    0x08
       
    50 #define MCF_UART_PM1    0x10
       
    51 #define MCF_UART_ERR    0x20
       
    52 #define MCF_UART_RxIRQ  0x40
       
    53 #define MCF_UART_RxRTS  0x80
       
    54 
       
    55 static void mcf_uart_update(mcf_uart_state *s)
       
    56 {
       
    57     s->isr &= ~(MCF_UART_TxINT | MCF_UART_RxINT);
       
    58     if (s->sr & MCF_UART_TxRDY)
       
    59         s->isr |= MCF_UART_TxINT;
       
    60     if ((s->sr & ((s->mr[0] & MCF_UART_RxIRQ)
       
    61                   ? MCF_UART_FFULL : MCF_UART_RxRDY)) != 0)
       
    62         s->isr |= MCF_UART_RxINT;
       
    63 
       
    64     qemu_set_irq(s->irq, (s->isr & s->imr) != 0);
       
    65 }
       
    66 
       
    67 uint32_t mcf_uart_read(void *opaque, target_phys_addr_t addr)
       
    68 {
       
    69     mcf_uart_state *s = (mcf_uart_state *)opaque;
       
    70     switch (addr & 0x3f) {
       
    71     case 0x00:
       
    72         return s->mr[s->current_mr];
       
    73     case 0x04:
       
    74         return s->sr;
       
    75     case 0x0c:
       
    76         {
       
    77             uint8_t val;
       
    78             int i;
       
    79 
       
    80             if (s->fifo_len == 0)
       
    81                 return 0;
       
    82 
       
    83             val = s->fifo[0];
       
    84             s->fifo_len--;
       
    85             for (i = 0; i < s->fifo_len; i++)
       
    86                 s->fifo[i] = s->fifo[i + 1];
       
    87             s->sr &= ~MCF_UART_FFULL;
       
    88             if (s->fifo_len == 0)
       
    89                 s->sr &= ~MCF_UART_RxRDY;
       
    90             mcf_uart_update(s);
       
    91             qemu_chr_accept_input(s->chr);
       
    92             return val;
       
    93         }
       
    94     case 0x10:
       
    95         /* TODO: Implement IPCR.  */
       
    96         return 0;
       
    97     case 0x14:
       
    98         return s->isr;
       
    99     case 0x18:
       
   100         return s->bg1;
       
   101     case 0x1c:
       
   102         return s->bg2;
       
   103     default:
       
   104         return 0;
       
   105     }
       
   106 }
       
   107 
       
   108 /* Update TxRDY flag and set data if present and enabled.  */
       
   109 static void mcf_uart_do_tx(mcf_uart_state *s)
       
   110 {
       
   111     if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) {
       
   112         if (s->chr)
       
   113             qemu_chr_write(s->chr, (unsigned char *)&s->tb, 1);
       
   114         s->sr |= MCF_UART_TxEMP;
       
   115     }
       
   116     if (s->tx_enabled) {
       
   117         s->sr |= MCF_UART_TxRDY;
       
   118     } else {
       
   119         s->sr &= ~MCF_UART_TxRDY;
       
   120     }
       
   121 }
       
   122 
       
   123 static void mcf_do_command(mcf_uart_state *s, uint8_t cmd)
       
   124 {
       
   125     /* Misc command.  */
       
   126     switch ((cmd >> 4) & 3) {
       
   127     case 0: /* No-op.  */
       
   128         break;
       
   129     case 1: /* Reset mode register pointer.  */
       
   130         s->current_mr = 0;
       
   131         break;
       
   132     case 2: /* Reset receiver.  */
       
   133         s->rx_enabled = 0;
       
   134         s->fifo_len = 0;
       
   135         s->sr &= ~(MCF_UART_RxRDY | MCF_UART_FFULL);
       
   136         break;
       
   137     case 3: /* Reset transmitter.  */
       
   138         s->tx_enabled = 0;
       
   139         s->sr |= MCF_UART_TxEMP;
       
   140         s->sr &= ~MCF_UART_TxRDY;
       
   141         break;
       
   142     case 4: /* Reset error status.  */
       
   143         break;
       
   144     case 5: /* Reset break-change interrupt.  */
       
   145         s->isr &= ~MCF_UART_DBINT;
       
   146         break;
       
   147     case 6: /* Start break.  */
       
   148     case 7: /* Stop break.  */
       
   149         break;
       
   150     }
       
   151 
       
   152     /* Transmitter command.  */
       
   153     switch ((cmd >> 2) & 3) {
       
   154     case 0: /* No-op.  */
       
   155         break;
       
   156     case 1: /* Enable.  */
       
   157         s->tx_enabled = 1;
       
   158         mcf_uart_do_tx(s);
       
   159         break;
       
   160     case 2: /* Disable.  */
       
   161         s->tx_enabled = 0;
       
   162         mcf_uart_do_tx(s);
       
   163         break;
       
   164     case 3: /* Reserved.  */
       
   165         fprintf(stderr, "mcf_uart: Bad TX command\n");
       
   166         break;
       
   167     }
       
   168 
       
   169     /* Receiver command.  */
       
   170     switch (cmd & 3) {
       
   171     case 0: /* No-op.  */
       
   172         break;
       
   173     case 1: /* Enable.  */
       
   174         s->rx_enabled = 1;
       
   175         break;
       
   176     case 2:
       
   177         s->rx_enabled = 0;
       
   178         break;
       
   179     case 3: /* Reserved.  */
       
   180         fprintf(stderr, "mcf_uart: Bad RX command\n");
       
   181         break;
       
   182     }
       
   183 }
       
   184 
       
   185 void mcf_uart_write(void *opaque, target_phys_addr_t addr, uint32_t val)
       
   186 {
       
   187     mcf_uart_state *s = (mcf_uart_state *)opaque;
       
   188     switch (addr & 0x3f) {
       
   189     case 0x00:
       
   190         s->mr[s->current_mr] = val;
       
   191         s->current_mr = 1;
       
   192         break;
       
   193     case 0x04:
       
   194         /* CSR is ignored.  */
       
   195         break;
       
   196     case 0x08: /* Command Register.  */
       
   197         mcf_do_command(s, val);
       
   198         break;
       
   199     case 0x0c: /* Transmit Buffer.  */
       
   200         s->sr &= ~MCF_UART_TxEMP;
       
   201         s->tb = val;
       
   202         mcf_uart_do_tx(s);
       
   203         break;
       
   204     case 0x10:
       
   205         /* ACR is ignored.  */
       
   206         break;
       
   207     case 0x14:
       
   208         s->imr = val;
       
   209         break;
       
   210     default:
       
   211         break;
       
   212     }
       
   213     mcf_uart_update(s);
       
   214 }
       
   215 
       
   216 static void mcf_uart_reset(mcf_uart_state *s)
       
   217 {
       
   218     s->fifo_len = 0;
       
   219     s->mr[0] = 0;
       
   220     s->mr[1] = 0;
       
   221     s->sr = MCF_UART_TxEMP;
       
   222     s->tx_enabled = 0;
       
   223     s->rx_enabled = 0;
       
   224     s->isr = 0;
       
   225     s->imr = 0;
       
   226 }
       
   227 
       
   228 static void mcf_uart_push_byte(mcf_uart_state *s, uint8_t data)
       
   229 {
       
   230     /* Break events overwrite the last byte if the fifo is full.  */
       
   231     if (s->fifo_len == 4)
       
   232         s->fifo_len--;
       
   233 
       
   234     s->fifo[s->fifo_len] = data;
       
   235     s->fifo_len++;
       
   236     s->sr |= MCF_UART_RxRDY;
       
   237     if (s->fifo_len == 4)
       
   238         s->sr |= MCF_UART_FFULL;
       
   239 
       
   240     mcf_uart_update(s);
       
   241 }
       
   242 
       
   243 static void mcf_uart_event(void *opaque, int event)
       
   244 {
       
   245     mcf_uart_state *s = (mcf_uart_state *)opaque;
       
   246 
       
   247     switch (event) {
       
   248     case CHR_EVENT_BREAK:
       
   249         s->isr |= MCF_UART_DBINT;
       
   250         mcf_uart_push_byte(s, 0);
       
   251         break;
       
   252     default:
       
   253         break;
       
   254     }
       
   255 }
       
   256 
       
   257 static int mcf_uart_can_receive(void *opaque)
       
   258 {
       
   259     mcf_uart_state *s = (mcf_uart_state *)opaque;
       
   260 
       
   261     return s->rx_enabled && (s->sr & MCF_UART_FFULL) == 0;
       
   262 }
       
   263 
       
   264 static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size)
       
   265 {
       
   266     mcf_uart_state *s = (mcf_uart_state *)opaque;
       
   267 
       
   268     mcf_uart_push_byte(s, buf[0]);
       
   269 }
       
   270 
       
   271 void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
       
   272 {
       
   273     mcf_uart_state *s;
       
   274 
       
   275     s = qemu_mallocz(sizeof(mcf_uart_state));
       
   276     s->chr = chr;
       
   277     s->irq = irq;
       
   278     if (chr) {
       
   279         qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive,
       
   280                               mcf_uart_event, s);
       
   281     }
       
   282     mcf_uart_reset(s);
       
   283     return s;
       
   284 }
       
   285 
       
   286 
       
   287 static CPUReadMemoryFunc *mcf_uart_readfn[] = {
       
   288    mcf_uart_read,
       
   289    mcf_uart_read,
       
   290    mcf_uart_read
       
   291 };
       
   292 
       
   293 static CPUWriteMemoryFunc *mcf_uart_writefn[] = {
       
   294    mcf_uart_write,
       
   295    mcf_uart_write,
       
   296    mcf_uart_write
       
   297 };
       
   298 
       
   299 void mcf_uart_mm_init(target_phys_addr_t base, qemu_irq irq,
       
   300                       CharDriverState *chr)
       
   301 {
       
   302     mcf_uart_state *s;
       
   303     int iomemtype;
       
   304 
       
   305     s = mcf_uart_init(irq, chr);
       
   306     iomemtype = cpu_register_io_memory(0, mcf_uart_readfn,
       
   307                                        mcf_uart_writefn, s);
       
   308     cpu_register_physical_memory(base, 0x40, iomemtype);
       
   309 }