David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 1 | ############################################################################### |
| 2 | # |
| 3 | # Virtual DMA driver for MN10300 serial ports |
| 4 | # |
| 5 | # Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. |
| 6 | # Written by David Howells (dhowells@redhat.com) |
| 7 | # |
| 8 | # This program is free software; you can redistribute it and/or |
| 9 | # modify it under the terms of the GNU General Public Licence |
| 10 | # as published by the Free Software Foundation; either version |
| 11 | # 2 of the Licence, or (at your option) any later version. |
| 12 | # |
| 13 | ############################################################################### |
| 14 | #include <linux/sys.h> |
| 15 | #include <linux/linkage.h> |
| 16 | #include <asm/page.h> |
| 17 | #include <asm/smp.h> |
| 18 | #include <asm/cpu-regs.h> |
| 19 | #include <asm/frame.inc> |
| 20 | #include <asm/timer-regs.h> |
David Howells | 2f2a213 | 2009-04-10 14:33:48 +0100 | [diff] [blame] | 21 | #include <proc/cache.h> |
| 22 | #include <unit/timex.h> |
David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 23 | #include "mn10300-serial.h" |
| 24 | |
| 25 | #define SCxCTR 0x00 |
| 26 | #define SCxICR 0x04 |
| 27 | #define SCxTXB 0x08 |
| 28 | #define SCxRXB 0x09 |
| 29 | #define SCxSTR 0x0c |
| 30 | #define SCxTIM 0x0d |
| 31 | |
| 32 | .text |
| 33 | |
| 34 | ############################################################################### |
| 35 | # |
| 36 | # serial port interrupt virtual DMA entry point |
| 37 | # - intended to run at interrupt priority 1 (not affected by local_irq_disable) |
| 38 | # |
| 39 | ############################################################################### |
| 40 | .balign L1_CACHE_BYTES |
| 41 | ENTRY(mn10300_serial_vdma_interrupt) |
Akira Takeuchi | 368dd5a | 2010-10-27 17:28:55 +0100 | [diff] [blame] | 42 | # or EPSW_IE,psw # permit overriding by |
David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 43 | # debugging interrupts |
| 44 | movm [d2,d3,a2,a3,exreg0],(sp) |
| 45 | |
| 46 | movhu (IAGR),a2 # see if which interrupt is |
| 47 | # pending |
| 48 | and IAGR_GN,a2 |
| 49 | add a2,a2 |
| 50 | add mn10300_serial_int_tbl,a2 |
| 51 | |
| 52 | mov (a2+),a3 |
| 53 | mov (__iobase,a3),e2 |
| 54 | mov (a2),a2 |
| 55 | jmp (a2) |
| 56 | |
| 57 | ############################################################################### |
| 58 | # |
| 59 | # serial port receive interrupt virtual DMA entry point |
| 60 | # - intended to run at interrupt priority 1 (not affected by local_irq_disable) |
| 61 | # - stores data/status byte pairs in the ring buffer |
| 62 | # - induces a scheduler tick timer interrupt when done, which we then subvert |
| 63 | # on entry: |
| 64 | # A3 struct mn10300_serial_port * |
| 65 | # E2 I/O port base |
| 66 | # |
| 67 | ############################################################################### |
| 68 | ENTRY(mn10300_serial_vdma_rx_handler) |
| 69 | mov (__rx_icr,a3),e3 |
| 70 | mov GxICR_DETECT,d2 |
| 71 | movbu d2,(e3) # ACK the interrupt |
| 72 | movhu (e3),d2 # flush |
| 73 | |
| 74 | mov (__rx_inp,a3),d3 |
| 75 | mov d3,a2 |
| 76 | add 2,d3 |
| 77 | and MNSC_BUFFER_SIZE-1,d3 |
| 78 | mov (__rx_outp,a3),d2 |
| 79 | cmp d3,d2 |
| 80 | beq mnsc_vdma_rx_overflow |
| 81 | |
| 82 | mov (__rx_buffer,a3),d2 |
| 83 | add d2,a2 |
| 84 | movhu (SCxSTR,e2),d2 |
| 85 | movbu d2,(1,a2) |
| 86 | movbu (SCxRXB,e2),d2 |
| 87 | movbu d2,(a2) |
| 88 | mov d3,(__rx_inp,a3) |
| 89 | bset MNSCx_RX_AVAIL,(__intr_flags,a3) |
| 90 | |
| 91 | mnsc_vdma_rx_done: |
| 92 | mov (__tm_icr,a3),a2 |
| 93 | mov GxICR_LEVEL_6|GxICR_ENABLE|GxICR_REQUEST|GxICR_DETECT,d2 |
| 94 | movhu d2,(a2) # request a slow interrupt |
| 95 | movhu (a2),d2 # flush |
| 96 | |
| 97 | movm (sp),[d2,d3,a2,a3,exreg0] |
| 98 | rti |
| 99 | |
| 100 | mnsc_vdma_rx_overflow: |
| 101 | bset MNSCx_RX_OVERF,(__intr_flags,a3) |
| 102 | bra mnsc_vdma_rx_done |
| 103 | |
| 104 | ############################################################################### |
| 105 | # |
| 106 | # serial port transmit interrupt virtual DMA entry point |
| 107 | # - intended to run at interrupt priority 1 (not affected by local_irq_disable) |
| 108 | # - retrieves data bytes from the ring buffer and passes them to the serial port |
| 109 | # - induces a scheduler tick timer interrupt when done, which we then subvert |
| 110 | # A3 struct mn10300_serial_port * |
| 111 | # E2 I/O port base |
| 112 | # |
| 113 | ############################################################################### |
| 114 | .balign L1_CACHE_BYTES |
| 115 | ENTRY(mn10300_serial_vdma_tx_handler) |
| 116 | mov (__tx_icr,a3),e3 |
| 117 | mov GxICR_DETECT,d2 |
| 118 | movbu d2,(e3) # ACK the interrupt |
| 119 | movhu (e3),d2 # flush |
| 120 | |
| 121 | btst 0x01,(__tx_break,a3) # handle transmit break request |
| 122 | bne mnsc_vdma_tx_break |
| 123 | |
| 124 | movbu (SCxSTR,e2),d2 # don't try and transmit a char if the |
| 125 | # buffer is not empty |
| 126 | btst SC01STR_TBF,d2 # (may have tried to jumpstart) |
| 127 | bne mnsc_vdma_tx_noint |
| 128 | |
| 129 | movbu (__tx_xchar,a3),d2 # handle hi-pri XON/XOFF |
| 130 | or d2,d2 |
| 131 | bne mnsc_vdma_tx_xchar |
| 132 | |
David Howells | 7043078 | 2009-09-23 10:40:24 +0100 | [diff] [blame] | 133 | mov (__uart_state,a3),a2 # see if the TTY Tx queue has anything in it |
David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 134 | mov (__xmit_tail,a2),d3 |
| 135 | mov (__xmit_head,a2),d2 |
| 136 | cmp d3,d2 |
| 137 | beq mnsc_vdma_tx_empty |
| 138 | |
| 139 | mov (__xmit_buffer,a2),d2 # get a char from the buffer and |
| 140 | # transmit it |
| 141 | movbu (d3,d2),d2 |
| 142 | movbu d2,(SCxTXB,e2) # Tx |
| 143 | |
| 144 | inc d3 # advance the buffer pointer |
| 145 | and __UART_XMIT_SIZE-1,d3 |
| 146 | mov (__xmit_head,a2),d2 |
| 147 | mov d3,(__xmit_tail,a2) |
| 148 | |
| 149 | sub d3,d2 # see if we've written everything |
| 150 | beq mnsc_vdma_tx_empty |
| 151 | |
| 152 | and __UART_XMIT_SIZE-1,d2 # see if we just made a hole |
| 153 | cmp __UART_XMIT_SIZE-2,d2 |
| 154 | beq mnsc_vdma_tx_made_hole |
| 155 | |
| 156 | mnsc_vdma_tx_done: |
| 157 | mov (__tm_icr,a3),a2 |
| 158 | mov GxICR_LEVEL_6|GxICR_ENABLE|GxICR_REQUEST|GxICR_DETECT,d2 |
| 159 | movhu d2,(a2) # request a slow interrupt |
| 160 | movhu (a2),d2 # flush |
| 161 | |
| 162 | mnsc_vdma_tx_noint: |
| 163 | movm (sp),[d2,d3,a2,a3,exreg0] |
| 164 | rti |
| 165 | |
| 166 | mnsc_vdma_tx_empty: |
Akira Takeuchi | 368dd5a | 2010-10-27 17:28:55 +0100 | [diff] [blame] | 167 | mov +(NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL)|GxICR_DETECT),d2 |
David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 168 | movhu d2,(e3) # disable the interrupt |
| 169 | movhu (e3),d2 # flush |
| 170 | |
| 171 | bset MNSCx_TX_EMPTY,(__intr_flags,a3) |
| 172 | bra mnsc_vdma_tx_done |
| 173 | |
| 174 | mnsc_vdma_tx_break: |
| 175 | movhu (SCxCTR,e2),d2 # turn on break mode |
| 176 | or SC01CTR_BKE,d2 |
| 177 | movhu d2,(SCxCTR,e2) |
Akira Takeuchi | 368dd5a | 2010-10-27 17:28:55 +0100 | [diff] [blame] | 178 | mov +(NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL)|GxICR_DETECT),d2 |
David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 179 | movhu d2,(e3) # disable transmit interrupts on this |
| 180 | # channel |
| 181 | movhu (e3),d2 # flush |
| 182 | bra mnsc_vdma_tx_noint |
| 183 | |
| 184 | mnsc_vdma_tx_xchar: |
| 185 | bclr 0xff,(__tx_xchar,a3) |
| 186 | movbu d2,(SCxTXB,e2) |
| 187 | bra mnsc_vdma_tx_done |
| 188 | |
| 189 | mnsc_vdma_tx_made_hole: |
| 190 | bset MNSCx_TX_SPACE,(__intr_flags,a3) |
| 191 | bra mnsc_vdma_tx_done |