Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0-only */
0002 .psize 0
0003 /*
0004   wanXL serial card driver for Linux
0005   card firmware part
0006 
0007   Copyright (C) 2003 Krzysztof Halasa <khc@pm.waw.pl>
0008 
0009 
0010 
0011 
0012 
0013     DPRAM BDs:
0014     0x000 - 0x050 TX#0  0x050 - 0x140 RX#0
0015     0x140 - 0x190 TX#1  0x190 - 0x280 RX#1
0016     0x280 - 0x2D0 TX#2  0x2D0 - 0x3C0 RX#2
0017     0x3C0 - 0x410 TX#3  0x410 - 0x500 RX#3
0018 
0019 
0020     000 5FF 1536 Bytes Dual-Port RAM User Data / BDs
0021     600 6FF 256 Bytes Dual-Port RAM User Data / BDs
0022     700 7FF 256 Bytes Dual-Port RAM User Data / BDs
0023     C00 CBF 192 Bytes Dual-Port RAM Parameter RAM Page 1
0024     D00 DBF 192 Bytes Dual-Port RAM Parameter RAM Page 2
0025     E00 EBF 192 Bytes Dual-Port RAM Parameter RAM Page 3
0026     F00 FBF 192 Bytes Dual-Port RAM Parameter RAM Page 4
0027 
0028     local interrupts            level
0029     NMI                 7
0030     PIT timer, CPM (RX/TX complete)     4
0031     PCI9060 DMA and PCI doorbells       3
0032     Cable - not used            1
0033 */
0034 
0035 #include <linux/hdlc.h>
0036 #include <linux/hdlc/ioctl.h>
0037 #include "wanxl.h"
0038 
0039 /* memory addresses and offsets */
0040 
0041 MAX_RAM_SIZE    = 16 * 1024 * 1024  // max RAM supported by hardware
0042 
0043 PCI9060_VECTOR  = 0x0000006C
0044 CPM_IRQ_BASE    = 0x40
0045 ERROR_VECTOR    = CPM_IRQ_BASE * 4
0046 SCC1_VECTOR = (CPM_IRQ_BASE + 0x1E) * 4
0047 SCC2_VECTOR = (CPM_IRQ_BASE + 0x1D) * 4
0048 SCC3_VECTOR = (CPM_IRQ_BASE + 0x1C) * 4
0049 SCC4_VECTOR = (CPM_IRQ_BASE + 0x1B) * 4
0050 CPM_IRQ_LEVEL   = 4
0051 TIMER_IRQ   = 128
0052 TIMER_IRQ_LEVEL = 4
0053 PITR_CONST  = 0x100 + 16        // 1 Hz timer
0054 
0055 MBAR        = 0x0003FF00
0056 
0057 VALUE_WINDOW    = 0x40000000
0058 ORDER_WINDOW    = 0xC0000000
0059 
0060 PLX     = 0xFFF90000
0061 
0062 CSRA        = 0xFFFB0000
0063 CSRB        = 0xFFFB0002
0064 CSRC        = 0xFFFB0004
0065 CSRD        = 0xFFFB0006
0066 STATUS_CABLE_LL     = 0x2000
0067 STATUS_CABLE_DTR    = 0x1000
0068 
0069 DPRBASE     = 0xFFFC0000
0070 
0071 SCC1_BASE   = DPRBASE + 0xC00
0072 MISC_BASE   = DPRBASE + 0xCB0
0073 SCC2_BASE   = DPRBASE + 0xD00
0074 SCC3_BASE   = DPRBASE + 0xE00
0075 SCC4_BASE   = DPRBASE + 0xF00
0076 
0077 // offset from SCCx_BASE
0078 // SCC_xBASE contain offsets from DPRBASE and must be divisible by 8
0079 SCC_RBASE   = 0     // 16-bit RxBD base address
0080 SCC_TBASE   = 2     // 16-bit TxBD base address
0081 SCC_RFCR    = 4     // 8-bit Rx function code
0082 SCC_TFCR    = 5     // 8-bit Tx function code
0083 SCC_MRBLR   = 6     // 16-bit maximum Rx buffer length
0084 SCC_C_MASK  = 0x34      // 32-bit CRC constant
0085 SCC_C_PRES  = 0x38      // 32-bit CRC preset
0086 SCC_MFLR    = 0x46      // 16-bit max Rx frame length (without flags)
0087 
0088 REGBASE     = DPRBASE + 0x1000
0089 PICR        = REGBASE + 0x026   // 16-bit periodic irq control
0090 PITR        = REGBASE + 0x02A   // 16-bit periodic irq timing
0091 OR1     = REGBASE + 0x064   // 32-bit RAM bank #1 options
0092 CICR        = REGBASE + 0x540   // 32(24)-bit CP interrupt config
0093 CIMR        = REGBASE + 0x548   // 32-bit CP interrupt mask
0094 CISR        = REGBASE + 0x54C   // 32-bit CP interrupts in-service
0095 PADIR       = REGBASE + 0x550   // 16-bit PortA data direction bitmap
0096 PAPAR       = REGBASE + 0x552   // 16-bit PortA pin assignment bitmap
0097 PAODR       = REGBASE + 0x554   // 16-bit PortA open drain bitmap
0098 PADAT       = REGBASE + 0x556   // 16-bit PortA data register
0099 
0100 PCDIR       = REGBASE + 0x560   // 16-bit PortC data direction bitmap
0101 PCPAR       = REGBASE + 0x562   // 16-bit PortC pin assignment bitmap
0102 PCSO        = REGBASE + 0x564   // 16-bit PortC special options
0103 PCDAT       = REGBASE + 0x566   // 16-bit PortC data register
0104 PCINT       = REGBASE + 0x568   // 16-bit PortC interrupt control
0105 CR      = REGBASE + 0x5C0   // 16-bit Command register
0106 
0107 SCC1_REGS   = REGBASE + 0x600
0108 SCC2_REGS   = REGBASE + 0x620
0109 SCC3_REGS   = REGBASE + 0x640
0110 SCC4_REGS   = REGBASE + 0x660
0111 SICR        = REGBASE + 0x6EC   // 32-bit SI clock route
0112 
0113 // offset from SCCx_REGS
0114 SCC_GSMR_L  = 0x00  // 32 bits
0115 SCC_GSMR_H  = 0x04  // 32 bits
0116 SCC_PSMR    = 0x08  // 16 bits
0117 SCC_TODR    = 0x0C  // 16 bits
0118 SCC_DSR     = 0x0E  // 16 bits
0119 SCC_SCCE    = 0x10  // 16 bits
0120 SCC_SCCM    = 0x14  // 16 bits
0121 SCC_SCCS    = 0x17  // 8 bits
0122 
0123 #if QUICC_MEMCPY_USES_PLX
0124     .macro memcpy_from_pci src, dest, len // len must be < 8 MB
0125     addl #3, \len
0126     andl #0xFFFFFFFC, \len      // always copy n * 4 bytes
0127     movel \src, PLX_DMA_0_PCI
0128     movel \dest, PLX_DMA_0_LOCAL
0129     movel \len, PLX_DMA_0_LENGTH
0130     movel #0x0103, PLX_DMA_CMD_STS  // start channel 0 transfer
0131     bsr memcpy_from_pci_run
0132     .endm
0133 
0134     .macro memcpy_to_pci src, dest, len
0135     addl #3, \len
0136     andl #0xFFFFFFFC, \len      // always copy n * 4 bytes
0137     movel \src, PLX_DMA_1_LOCAL
0138     movel \dest, PLX_DMA_1_PCI
0139     movel \len, PLX_DMA_1_LENGTH
0140     movel #0x0301, PLX_DMA_CMD_STS  // start channel 1 transfer
0141     bsr memcpy_to_pci_run
0142     .endm
0143 
0144 #else
0145 
0146     .macro memcpy src, dest, len    // len must be < 65536 bytes
0147     movel %d7, -(%sp)       // src and dest must be < 256 MB
0148     movel \len, %d7         // bits 0 and 1
0149     lsrl #2, \len
0150     andl \len, \len
0151     beq 99f             // only 0 - 3 bytes
0152     subl #1, \len           // for dbf
0153 98: movel (\src)+, (\dest)+
0154     dbfw \len, 98b
0155 99: movel %d7, \len
0156     btstl #1, \len
0157     beq 99f
0158     movew (\src)+, (\dest)+
0159 99: btstl #0, \len
0160     beq 99f
0161     moveb (\src)+, (\dest)+
0162 99:
0163     movel (%sp)+, %d7
0164     .endm
0165 
0166     .macro memcpy_from_pci src, dest, len
0167     addl #VALUE_WINDOW, \src
0168     memcpy \src, \dest, \len
0169     .endm
0170 
0171     .macro memcpy_to_pci src, dest, len
0172     addl #VALUE_WINDOW, \dest
0173     memcpy \src, \dest, \len
0174     .endm
0175 #endif
0176 
0177 
0178     .macro wait_for_command
0179 99: btstl #0, CR
0180     bne 99b
0181     .endm
0182 
0183 
0184 
0185 
0186 /****************************** card initialization *******************/
0187     .text
0188     .global _start
0189 _start: bra init
0190 
0191     .org _start + 4
0192 ch_status_addr: .long 0, 0, 0, 0
0193 rx_descs_addr:  .long 0
0194 
0195 init:
0196 #if DETECT_RAM
0197     movel OR1, %d0
0198     andl #0xF00007FF, %d0       // mask AMxx bits
0199     orl #0xFFFF800 & ~(MAX_RAM_SIZE - 1), %d0 // update RAM bank size
0200     movel %d0, OR1
0201 #endif
0202 
0203     addl #VALUE_WINDOW, rx_descs_addr // PCI addresses of shared data
0204     clrl %d0            // D0 = 4 * port
0205 init_1: tstl ch_status_addr(%d0)
0206     beq init_2
0207     addl #VALUE_WINDOW, ch_status_addr(%d0)
0208 init_2: addl #4, %d0
0209     cmpl #4 * 4, %d0
0210     bne init_1
0211 
0212     movel #pci9060_interrupt, PCI9060_VECTOR
0213     movel #error_interrupt, ERROR_VECTOR
0214     movel #port_interrupt_1, SCC1_VECTOR
0215     movel #port_interrupt_2, SCC2_VECTOR
0216     movel #port_interrupt_3, SCC3_VECTOR
0217     movel #port_interrupt_4, SCC4_VECTOR
0218     movel #timer_interrupt, TIMER_IRQ * 4
0219 
0220     movel #0x78000000, CIMR     // only SCCx IRQs from CPM
0221     movew #(TIMER_IRQ_LEVEL << 8) + TIMER_IRQ, PICR // interrupt from PIT
0222     movew #PITR_CONST, PITR
0223 
0224     // SCC1=SCCa SCC2=SCCb SCC3=SCCc SCC4=SCCd prio=4 HP=-1 IRQ=64-79
0225     movel #0xD41F40 + (CPM_IRQ_LEVEL << 13), CICR
0226     movel #0x543, PLX_DMA_0_MODE    // 32-bit, Ready, Burst, IRQ
0227     movel #0x543, PLX_DMA_1_MODE
0228     movel #0x0, PLX_DMA_0_DESC  // from PCI to local
0229     movel #0x8, PLX_DMA_1_DESC  // from local to PCI
0230     movel #0x101, PLX_DMA_CMD_STS   // enable both DMA channels
0231     // enable local IRQ, DMA, doorbells and PCI IRQ
0232     orl #0x000F0300, PLX_INTERRUPT_CS
0233 
0234 #if DETECT_RAM
0235     bsr ram_test
0236 #else
0237     movel #1, PLX_MAILBOX_5     // non-zero value = init complete
0238 #endif
0239     bsr check_csr
0240 
0241     movew #0xFFFF, PAPAR        // all pins are clocks/data
0242     clrw PADIR          // first function
0243     clrw PCSO           // CD and CTS always active
0244 
0245 
0246 /****************************** main loop *****************************/
0247 
0248 main:   movel channel_stats, %d7    // D7 = doorbell + irq status
0249     clrl channel_stats
0250 
0251     tstl %d7
0252     bne main_1
0253     // nothing to do - wait for next event
0254     stop #0x2200            // supervisor + IRQ level 2
0255     movew #0x2700, %sr      // disable IRQs again
0256     bra main
0257 
0258 main_1: clrl %d0            // D0 = 4 * port
0259     clrl %d6            // D6 = doorbell to host value
0260 
0261 main_l: btstl #DOORBELL_TO_CARD_CLOSE_0, %d7
0262     beq main_op
0263     bclrl #DOORBELL_TO_CARD_OPEN_0, %d7 // in case both bits are set
0264     bsr close_port
0265 main_op:
0266     btstl #DOORBELL_TO_CARD_OPEN_0, %d7
0267     beq main_cl
0268     bsr open_port
0269 main_cl:
0270     btstl #DOORBELL_TO_CARD_TX_0, %d7
0271     beq main_txend
0272     bsr tx
0273 main_txend:
0274     btstl #TASK_SCC_0, %d7
0275     beq main_next
0276     bsr tx_end
0277     bsr rx
0278 
0279 main_next:
0280     lsrl #1, %d7            // port status for next port
0281     addl #4, %d0            // D0 = 4 * next port
0282     cmpl #4 * 4, %d0
0283     bne main_l
0284     movel %d6, PLX_DOORBELL_FROM_CARD // signal the host
0285     bra main
0286 
0287 
0288 /****************************** open port *****************************/
0289 
0290 open_port:              // D0 = 4 * port, D6 = doorbell to host
0291     movel ch_status_addr(%d0), %a0  // A0 = port status address
0292     tstl STATUS_OPEN(%a0)
0293     bne open_port_ret       // port already open
0294     movel #1, STATUS_OPEN(%a0)  // confirm the port is open
0295 // setup BDs
0296     clrl tx_in(%d0)
0297     clrl tx_out(%d0)
0298     clrl tx_count(%d0)
0299     clrl rx_in(%d0)
0300 
0301     movel SICR, %d1         // D1 = clock settings in SICR
0302     andl clocking_mask(%d0), %d1
0303     cmpl #CLOCK_TXFROMRX, STATUS_CLOCKING(%a0)
0304     bne open_port_clock_ext
0305     orl clocking_txfromrx(%d0), %d1
0306     bra open_port_set_clock
0307 
0308 open_port_clock_ext:
0309     orl clocking_ext(%d0), %d1
0310 open_port_set_clock:
0311     movel %d1, SICR         // update clock settings in SICR
0312 
0313     orw #STATUS_CABLE_DTR, csr_output(%d0)  // DTR on
0314     bsr check_csr           // call with disabled timer interrupt
0315 
0316 // Setup TX descriptors
0317     movel first_buffer(%d0), %d1    // D1 = starting buffer address
0318     movel tx_first_bd(%d0), %a1 // A1 = starting TX BD address
0319     movel #TX_BUFFERS - 2, %d2  // D2 = TX_BUFFERS - 1 counter
0320     movel #0x18000000, %d3      // D3 = initial TX BD flags: Int + Last
0321     cmpl #PARITY_NONE, STATUS_PARITY(%a0)
0322     beq open_port_tx_loop
0323     bsetl #26, %d3          // TX BD flag: Transmit CRC
0324 open_port_tx_loop:
0325     movel %d3, (%a1)+       // TX flags + length
0326     movel %d1, (%a1)+       // buffer address
0327     addl #BUFFER_LENGTH, %d1
0328     dbfw %d2, open_port_tx_loop
0329 
0330     bsetl #29, %d3          // TX BD flag: Wrap (last BD)
0331     movel %d3, (%a1)+       // Final TX flags + length
0332     movel %d1, (%a1)+       // buffer address
0333 
0334 // Setup RX descriptors         // A1 = starting RX BD address
0335     movel #RX_BUFFERS - 2, %d2  // D2 = RX_BUFFERS - 1 counter
0336 open_port_rx_loop:
0337     movel #0x90000000, (%a1)+   // RX flags + length
0338     movel %d1, (%a1)+       // buffer address
0339     addl #BUFFER_LENGTH, %d1
0340     dbfw %d2, open_port_rx_loop
0341 
0342     movel #0xB0000000, (%a1)+   // Final RX flags + length
0343     movel %d1, (%a1)+       // buffer address
0344 
0345 // Setup port parameters
0346     movel scc_base_addr(%d0), %a1   // A1 = SCC_BASE address
0347     movel scc_reg_addr(%d0), %a2    // A2 = SCC_REGS address
0348 
0349     movel #0xFFFF, SCC_SCCE(%a2)    // clear status bits
0350     movel #0x0000, SCC_SCCM(%a2)    // interrupt mask
0351 
0352     movel tx_first_bd(%d0), %d1
0353     movew %d1, SCC_TBASE(%a1)   // D1 = offset of first TxBD
0354     addl #TX_BUFFERS * 8, %d1
0355     movew %d1, SCC_RBASE(%a1)   // D1 = offset of first RxBD
0356     moveb #0x8, SCC_RFCR(%a1)   // Intel mode, 1000
0357     moveb #0x8, SCC_TFCR(%a1)
0358 
0359 // Parity settings
0360     cmpl #PARITY_CRC16_PR1_CCITT, STATUS_PARITY(%a0)
0361     bne open_port_parity_1
0362     clrw SCC_PSMR(%a2)      // CRC16-CCITT
0363     movel #0xF0B8, SCC_C_MASK(%a1)
0364     movel #0xFFFF, SCC_C_PRES(%a1)
0365     movew #HDLC_MAX_MRU + 2, SCC_MFLR(%a1) // 2 bytes for CRC
0366     movew #2, parity_bytes(%d0)
0367     bra open_port_2
0368 
0369 open_port_parity_1:
0370     cmpl #PARITY_CRC32_PR1_CCITT, STATUS_PARITY(%a0)
0371     bne open_port_parity_2
0372     movew #0x0800, SCC_PSMR(%a2)    // CRC32-CCITT
0373     movel #0xDEBB20E3, SCC_C_MASK(%a1)
0374     movel #0xFFFFFFFF, SCC_C_PRES(%a1)
0375     movew #HDLC_MAX_MRU + 4, SCC_MFLR(%a1) // 4 bytes for CRC
0376     movew #4, parity_bytes(%d0)
0377     bra open_port_2
0378 
0379 open_port_parity_2:
0380     cmpl #PARITY_CRC16_PR0_CCITT, STATUS_PARITY(%a0)
0381     bne open_port_parity_3
0382     clrw SCC_PSMR(%a2)      // CRC16-CCITT preset 0
0383     movel #0xF0B8, SCC_C_MASK(%a1)
0384     clrl SCC_C_PRES(%a1)
0385     movew #HDLC_MAX_MRU + 2, SCC_MFLR(%a1) // 2 bytes for CRC
0386     movew #2, parity_bytes(%d0)
0387     bra open_port_2
0388 
0389 open_port_parity_3:
0390     cmpl #PARITY_CRC32_PR0_CCITT, STATUS_PARITY(%a0)
0391     bne open_port_parity_4
0392     movew #0x0800, SCC_PSMR(%a2)    // CRC32-CCITT preset 0
0393     movel #0xDEBB20E3, SCC_C_MASK(%a1)
0394     clrl SCC_C_PRES(%a1)
0395     movew #HDLC_MAX_MRU + 4, SCC_MFLR(%a1) // 4 bytes for CRC
0396     movew #4, parity_bytes(%d0)
0397     bra open_port_2
0398 
0399 open_port_parity_4:
0400     clrw SCC_PSMR(%a2)      // no parity
0401     movel #0xF0B8, SCC_C_MASK(%a1)
0402     movel #0xFFFF, SCC_C_PRES(%a1)
0403     movew #HDLC_MAX_MRU, SCC_MFLR(%a1) // 0 bytes for CRC
0404     clrw parity_bytes(%d0)
0405 
0406 open_port_2:
0407     movel #0x00000003, SCC_GSMR_H(%a2) // RTSM
0408     cmpl #ENCODING_NRZI, STATUS_ENCODING(%a0)
0409     bne open_port_nrz
0410     movel #0x10040900, SCC_GSMR_L(%a2) // NRZI: TCI Tend RECN+TENC=1
0411     bra open_port_3
0412 
0413 open_port_nrz:
0414     movel #0x10040000, SCC_GSMR_L(%a2) // NRZ: TCI Tend RECN+TENC=0
0415 open_port_3:
0416     movew #BUFFER_LENGTH, SCC_MRBLR(%a1)
0417     movel %d0, %d1
0418     lsll #4, %d1            // D1 bits 7 and 6 = port
0419     orl #1, %d1
0420     movew %d1, CR           // Init SCC RX and TX params
0421     wait_for_command
0422 
0423     // TCI Tend ENR ENT
0424     movew #0x001F, SCC_SCCM(%a2)    // TXE RXF BSY TXB RXB interrupts
0425     orl #0x00000030, SCC_GSMR_L(%a2) // enable SCC
0426 open_port_ret:
0427     rts
0428 
0429 
0430 /****************************** close port ****************************/
0431 
0432 close_port:             // D0 = 4 * port, D6 = doorbell to host
0433     movel scc_reg_addr(%d0), %a0    // A0 = SCC_REGS address
0434     clrw SCC_SCCM(%a0)      // no SCC interrupts
0435     andl #0xFFFFFFCF, SCC_GSMR_L(%a0) // Disable ENT and ENR
0436 
0437     andw #~STATUS_CABLE_DTR, csr_output(%d0) // DTR off
0438     bsr check_csr           // call with disabled timer interrupt
0439 
0440     movel ch_status_addr(%d0), %d1
0441     clrl STATUS_OPEN(%d1)       // confirm the port is closed
0442     rts
0443 
0444 
0445 /****************************** transmit packet ***********************/
0446 // queue packets for transmission
0447 tx:                 // D0 = 4 * port, D6 = doorbell to host
0448     cmpl #TX_BUFFERS, tx_count(%d0)
0449     beq tx_ret          // all DB's = descs in use
0450 
0451     movel tx_out(%d0), %d1
0452     movel %d1, %d2          // D1 = D2 = tx_out BD# = desc#
0453     mulul #DESC_LENGTH, %d2     // D2 = TX desc offset
0454     addl ch_status_addr(%d0), %d2
0455     addl #STATUS_TX_DESCS, %d2  // D2 = TX desc address
0456     cmpl #PACKET_FULL, (%d2)    // desc status
0457     bne tx_ret
0458 
0459 // queue it
0460     movel 4(%d2), %a0       // PCI address
0461     lsll #3, %d1            // BD is 8-bytes long
0462     addl tx_first_bd(%d0), %d1  // D1 = current tx_out BD addr
0463 
0464     movel 4(%d1), %a1       // A1 = dest address
0465     movel 8(%d2), %d2       // D2 = length
0466     movew %d2, 2(%d1)       // length into BD
0467     memcpy_from_pci %a0, %a1, %d2
0468     bsetl #31, (%d1)        // CP go ahead
0469 
0470 // update tx_out and tx_count
0471     movel tx_out(%d0), %d1
0472     addl #1, %d1
0473     cmpl #TX_BUFFERS, %d1
0474     bne tx_1
0475     clrl %d1
0476 tx_1:   movel %d1, tx_out(%d0)
0477 
0478     addl #1, tx_count(%d0)
0479     bra tx
0480 
0481 tx_ret: rts
0482 
0483 
0484 /****************************** packet received ***********************/
0485 
0486 // Service receive buffers      // D0 = 4 * port, D6 = doorbell to host
0487 rx: movel rx_in(%d0), %d1       // D1 = rx_in BD#
0488     lsll #3, %d1            // BD is 8-bytes long
0489     addl rx_first_bd(%d0), %d1  // D1 = current rx_in BD address
0490     movew (%d1), %d2        // D2 = RX BD flags
0491     btstl #15, %d2
0492     bne rx_ret          // BD still empty
0493 
0494     btstl #1, %d2
0495     bne rx_overrun
0496 
0497     tstw parity_bytes(%d0)
0498     bne rx_parity
0499     bclrl #2, %d2           // do not test for CRC errors
0500 rx_parity:
0501     andw #0x0CBC, %d2       // mask status bits
0502     cmpw #0x0C00, %d2       // correct frame
0503     bne rx_bad_frame
0504     clrl %d3
0505     movew 2(%d1), %d3
0506     subw parity_bytes(%d0), %d3 // D3 = packet length
0507     cmpw #HDLC_MAX_MRU, %d3
0508     bgt rx_bad_frame
0509 
0510 rx_good_frame:
0511     movel rx_out, %d2
0512     mulul #DESC_LENGTH, %d2
0513     addl rx_descs_addr, %d2     // D2 = RX desc address
0514     cmpl #PACKET_EMPTY, (%d2)   // desc stat
0515     bne rx_overrun
0516 
0517     movel %d3, 8(%d2)
0518     movel 4(%d1), %a0       // A0 = source address
0519     movel 4(%d2), %a1
0520     tstl %a1
0521     beq rx_ignore_data
0522     memcpy_to_pci %a0, %a1, %d3
0523 rx_ignore_data:
0524     movel packet_full(%d0), (%d2)   // update desc stat
0525 
0526 // update D6 and rx_out
0527     bsetl #DOORBELL_FROM_CARD_RX, %d6 // signal host that RX completed
0528     movel rx_out, %d2
0529     addl #1, %d2
0530     cmpl #RX_QUEUE_LENGTH, %d2
0531     bne rx_1
0532     clrl %d2
0533 rx_1:   movel %d2, rx_out
0534 
0535 rx_free_bd:
0536     andw #0xF000, (%d1)     // clear CM and error bits
0537     bsetl #31, (%d1)        // free BD
0538 // update rx_in
0539     movel rx_in(%d0), %d1
0540     addl #1, %d1
0541     cmpl #RX_BUFFERS, %d1
0542     bne rx_2
0543     clrl %d1
0544 rx_2:   movel %d1, rx_in(%d0)
0545     bra rx
0546 
0547 rx_overrun:
0548     movel ch_status_addr(%d0), %d2
0549     addl #1, STATUS_RX_OVERRUNS(%d2)
0550     bra rx_free_bd
0551 
0552 rx_bad_frame:
0553     movel ch_status_addr(%d0), %d2
0554     addl #1, STATUS_RX_FRAME_ERRORS(%d2)
0555     bra rx_free_bd
0556 
0557 rx_ret: rts
0558 
0559 
0560 /****************************** packet transmitted ********************/
0561 
0562 // Service transmit buffers     // D0 = 4 * port, D6 = doorbell to host
0563 tx_end: tstl tx_count(%d0)
0564     beq tx_end_ret          // TX buffers already empty
0565 
0566     movel tx_in(%d0), %d1
0567     movel %d1, %d2          // D1 = D2 = tx_in BD# = desc#
0568     lsll #3, %d1            // BD is 8-bytes long
0569     addl tx_first_bd(%d0), %d1  // D1 = current tx_in BD address
0570     movew (%d1), %d3        // D3 = TX BD flags
0571     btstl #15, %d3
0572     bne tx_end_ret          // BD still being transmitted
0573 
0574 // update D6, tx_in and tx_count
0575     orl bell_tx(%d0), %d6       // signal host that TX desc freed
0576     subl #1, tx_count(%d0)
0577     movel tx_in(%d0), %d1
0578     addl #1, %d1
0579     cmpl #TX_BUFFERS, %d1
0580     bne tx_end_1
0581     clrl %d1
0582 tx_end_1:
0583     movel %d1, tx_in(%d0)
0584 
0585 // free host's descriptor
0586     mulul #DESC_LENGTH, %d2     // D2 = TX desc offset
0587     addl ch_status_addr(%d0), %d2
0588     addl #STATUS_TX_DESCS, %d2  // D2 = TX desc address
0589     btstl #1, %d3
0590     bne tx_end_underrun
0591     movel #PACKET_SENT, (%d2)
0592     bra tx_end
0593 
0594 tx_end_underrun:
0595     movel #PACKET_UNDERRUN, (%d2)
0596     bra tx_end
0597 
0598 tx_end_ret: rts
0599 
0600 
0601 /****************************** PLX PCI9060 DMA memcpy ****************/
0602 
0603 #if QUICC_MEMCPY_USES_PLX
0604 // called with interrupts disabled
0605 memcpy_from_pci_run:
0606     movel %d0, -(%sp)
0607     movew %sr, -(%sp)
0608 memcpy_1:
0609     movel PLX_DMA_CMD_STS, %d0  // do not btst PLX register directly
0610     btstl #4, %d0           // transfer done?
0611     bne memcpy_end
0612     stop #0x2200            // enable PCI9060 interrupts
0613     movew #0x2700, %sr      // disable interrupts again
0614     bra memcpy_1
0615 
0616 memcpy_to_pci_run:
0617     movel %d0, -(%sp)
0618     movew %sr, -(%sp)
0619 memcpy_2:
0620     movel PLX_DMA_CMD_STS, %d0  // do not btst PLX register directly
0621     btstl #12, %d0          // transfer done?
0622     bne memcpy_end
0623     stop #0x2200            // enable PCI9060 interrupts
0624     movew #0x2700, %sr      // disable interrupts again
0625     bra memcpy_2
0626 
0627 memcpy_end:
0628     movew (%sp)+, %sr
0629     movel (%sp)+, %d0
0630     rts
0631 #endif
0632 
0633 
0634 
0635 
0636 
0637 
0638 /****************************** PLX PCI9060 interrupt *****************/
0639 
0640 pci9060_interrupt:
0641     movel %d0, -(%sp)
0642 
0643     movel PLX_DOORBELL_TO_CARD, %d0
0644     movel %d0, PLX_DOORBELL_TO_CARD // confirm all requests
0645     orl %d0, channel_stats
0646 
0647     movel #0x0909, PLX_DMA_CMD_STS  // clear DMA ch #0 and #1 interrupts
0648 
0649     movel (%sp)+, %d0
0650     rte
0651 
0652 /****************************** SCC interrupts ************************/
0653 
0654 port_interrupt_1:
0655     orl #0, SCC1_REGS + SCC_SCCE; // confirm SCC events
0656     orl #1 << TASK_SCC_0, channel_stats
0657     movel #0x40000000, CISR
0658     rte
0659 
0660 port_interrupt_2:
0661     orl #0, SCC2_REGS + SCC_SCCE; // confirm SCC events
0662     orl #1 << TASK_SCC_1, channel_stats
0663     movel #0x20000000, CISR
0664     rte
0665 
0666 port_interrupt_3:
0667     orl #0, SCC3_REGS + SCC_SCCE; // confirm SCC events
0668     orl #1 << TASK_SCC_2, channel_stats
0669     movel #0x10000000, CISR
0670     rte
0671 
0672 port_interrupt_4:
0673     orl #0, SCC4_REGS + SCC_SCCE; // confirm SCC events
0674     orl #1 << TASK_SCC_3, channel_stats
0675     movel #0x08000000, CISR
0676     rte
0677 
0678 error_interrupt:
0679     rte
0680 
0681 
0682 /****************************** cable and PM routine ******************/
0683 // modified registers: none
0684 check_csr:
0685     movel %d0, -(%sp)
0686     movel %d1, -(%sp)
0687     movel %d2, -(%sp)
0688     movel %a0, -(%sp)
0689     movel %a1, -(%sp)
0690 
0691     clrl %d0            // D0 = 4 * port
0692     movel #CSRA, %a0        // A0 = CSR address
0693 
0694 check_csr_loop:
0695     movew (%a0), %d1        // D1 = CSR input bits
0696     andl #0xE7, %d1         // PM and cable sense bits (no DCE bit)
0697     cmpw #STATUS_CABLE_V35 * (1 + 1 << STATUS_CABLE_PM_SHIFT), %d1
0698     bne check_csr_1
0699     movew #0x0E08, %d1
0700     bra check_csr_valid
0701 
0702 check_csr_1:
0703     cmpw #STATUS_CABLE_X21 * (1 + 1 << STATUS_CABLE_PM_SHIFT), %d1
0704     bne check_csr_2
0705     movew #0x0408, %d1
0706     bra check_csr_valid
0707 
0708 check_csr_2:
0709     cmpw #STATUS_CABLE_V24 * (1 + 1 << STATUS_CABLE_PM_SHIFT), %d1
0710     bne check_csr_3
0711     movew #0x0208, %d1
0712     bra check_csr_valid
0713 
0714 check_csr_3:
0715     cmpw #STATUS_CABLE_EIA530 * (1 + 1 << STATUS_CABLE_PM_SHIFT), %d1
0716     bne check_csr_disable
0717     movew #0x0D08, %d1
0718     bra check_csr_valid
0719 
0720 check_csr_disable:
0721     movew #0x0008, %d1      // D1 = disable everything
0722     movew #0x80E7, %d2      // D2 = input mask: ignore DSR
0723     bra check_csr_write
0724 
0725 check_csr_valid:            // D1 = mode and IRQ bits
0726     movew csr_output(%d0), %d2
0727     andw #0x3000, %d2       // D2 = requested LL and DTR bits
0728     orw %d2, %d1            // D1 = all requested output bits
0729     movew #0x80FF, %d2      // D2 = input mask: include DSR
0730 
0731 check_csr_write:
0732     cmpw old_csr_output(%d0), %d1
0733     beq check_csr_input
0734     movew %d1, old_csr_output(%d0)
0735     movew %d1, (%a0)        // Write CSR output bits
0736 
0737 check_csr_input:
0738     movew (PCDAT), %d1
0739     andw dcd_mask(%d0), %d1
0740     beq check_csr_dcd_on        // DCD and CTS signals are negated
0741     movew (%a0), %d1        // D1 = CSR input bits
0742     andw #~STATUS_CABLE_DCD, %d1    // DCD off
0743     bra check_csr_previous
0744 
0745 check_csr_dcd_on:
0746     movew (%a0), %d1        // D1 = CSR input bits
0747     orw #STATUS_CABLE_DCD, %d1  // DCD on
0748 check_csr_previous:
0749     andw %d2, %d1           // input mask
0750     movel ch_status_addr(%d0), %a1
0751     cmpl STATUS_CABLE(%a1), %d1 // check for change
0752     beq check_csr_next
0753     movel %d1, STATUS_CABLE(%a1)    // update status
0754     movel bell_cable(%d0), PLX_DOORBELL_FROM_CARD   // signal the host
0755 
0756 check_csr_next:
0757     addl #2, %a0            // next CSR register
0758     addl #4, %d0            // D0 = 4 * next port
0759     cmpl #4 * 4, %d0
0760     bne check_csr_loop
0761 
0762     movel (%sp)+, %a1
0763     movel (%sp)+, %a0
0764     movel (%sp)+, %d2
0765     movel (%sp)+, %d1
0766     movel (%sp)+, %d0
0767     rts
0768 
0769 
0770 /****************************** timer interrupt ***********************/
0771 
0772 timer_interrupt:
0773     bsr check_csr
0774     rte
0775 
0776 
0777 /****************************** RAM sizing and test *******************/
0778 #if DETECT_RAM
0779 ram_test:
0780     movel #0x12345678, %d1      // D1 = test value
0781     movel %d1, (128 * 1024 - 4)
0782     movel #128 * 1024, %d0      // D0 = RAM size tested
0783 ram_test_size:
0784     cmpl #MAX_RAM_SIZE, %d0
0785     beq ram_test_size_found
0786     movel %d0, %a0
0787     addl #128 * 1024 - 4, %a0
0788     cmpl (%a0), %d1
0789     beq ram_test_size_check
0790 ram_test_next_size:
0791     lsll #1, %d0
0792     bra ram_test_size
0793 
0794 ram_test_size_check:
0795     eorl #0xFFFFFFFF, %d1
0796     movel %d1, (128 * 1024 - 4)
0797     cmpl (%a0), %d1
0798     bne ram_test_next_size
0799 
0800 ram_test_size_found:            // D0 = RAM size
0801     movel %d0, %a0          // A0 = fill ptr
0802     subl #firmware_end + 4, %d0
0803     lsrl #2, %d0
0804     movel %d0, %d1          // D1 = DBf counter
0805 ram_test_fill:
0806     movel %a0, -(%a0)
0807     dbfw %d1, ram_test_fill
0808     subl #0x10000, %d1
0809     cmpl #0xFFFFFFFF, %d1
0810     bne ram_test_fill
0811 
0812 ram_test_loop:              // D0 = DBf counter
0813     cmpl (%a0)+, %a0
0814     dbnew %d0, ram_test_loop
0815     bne ram_test_found_bad
0816     subl #0x10000, %d0
0817     cmpl #0xFFFFFFFF, %d0
0818     bne ram_test_loop
0819     bra ram_test_all_ok
0820 
0821 ram_test_found_bad:
0822     subl #4, %a0
0823 ram_test_all_ok:
0824     movel %a0, PLX_MAILBOX_5
0825     rts
0826 #endif
0827 
0828 
0829 /****************************** constants *****************************/
0830 
0831 scc_reg_addr:
0832     .long SCC1_REGS, SCC2_REGS, SCC3_REGS, SCC4_REGS
0833 scc_base_addr:
0834     .long SCC1_BASE, SCC2_BASE, SCC3_BASE, SCC4_BASE
0835 
0836 tx_first_bd:
0837     .long DPRBASE
0838     .long DPRBASE + (TX_BUFFERS + RX_BUFFERS) * 8
0839     .long DPRBASE + (TX_BUFFERS + RX_BUFFERS) * 8 * 2
0840     .long DPRBASE + (TX_BUFFERS + RX_BUFFERS) * 8 * 3
0841 
0842 rx_first_bd:
0843     .long DPRBASE + TX_BUFFERS * 8
0844     .long DPRBASE + TX_BUFFERS * 8 + (TX_BUFFERS + RX_BUFFERS) * 8
0845     .long DPRBASE + TX_BUFFERS * 8 + (TX_BUFFERS + RX_BUFFERS) * 8 * 2
0846     .long DPRBASE + TX_BUFFERS * 8 + (TX_BUFFERS + RX_BUFFERS) * 8 * 3
0847 
0848 first_buffer:
0849     .long BUFFERS_ADDR
0850     .long BUFFERS_ADDR + (TX_BUFFERS + RX_BUFFERS) * BUFFER_LENGTH
0851     .long BUFFERS_ADDR + (TX_BUFFERS + RX_BUFFERS) * BUFFER_LENGTH * 2
0852     .long BUFFERS_ADDR + (TX_BUFFERS + RX_BUFFERS) * BUFFER_LENGTH * 3
0853 
0854 bell_tx:
0855     .long 1 << DOORBELL_FROM_CARD_TX_0, 1 << DOORBELL_FROM_CARD_TX_1
0856     .long 1 << DOORBELL_FROM_CARD_TX_2, 1 << DOORBELL_FROM_CARD_TX_3
0857 
0858 bell_cable:
0859     .long 1 << DOORBELL_FROM_CARD_CABLE_0, 1 << DOORBELL_FROM_CARD_CABLE_1
0860     .long 1 << DOORBELL_FROM_CARD_CABLE_2, 1 << DOORBELL_FROM_CARD_CABLE_3
0861 
0862 packet_full:
0863     .long PACKET_FULL, PACKET_FULL + 1, PACKET_FULL + 2, PACKET_FULL + 3
0864 
0865 clocking_ext:
0866     .long 0x0000002C, 0x00003E00, 0x002C0000, 0x3E000000
0867 clocking_txfromrx:
0868     .long 0x0000002D, 0x00003F00, 0x002D0000, 0x3F000000
0869 clocking_mask:
0870     .long 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000
0871 dcd_mask:
0872     .word 0x020, 0, 0x080, 0, 0x200, 0, 0x800
0873 
0874     .ascii "wanXL firmware\n"
0875     .asciz "Copyright (C) 2003 Krzysztof Halasa <khc@pm.waw.pl>\n"
0876 
0877 
0878 /****************************** variables *****************************/
0879 
0880         .align 4
0881 channel_stats:  .long 0
0882 
0883 tx_in:      .long 0, 0, 0, 0    // transmitted
0884 tx_out:     .long 0, 0, 0, 0    // received from host for transmission
0885 tx_count:   .long 0, 0, 0, 0    // currently in transmit queue
0886 
0887 rx_in:      .long 0, 0, 0, 0    // received from port
0888 rx_out:     .long 0         // transmitted to host
0889 parity_bytes:   .word 0, 0, 0, 0, 0, 0, 0 // only 4 words are used
0890 
0891 csr_output: .word 0
0892 old_csr_output: .word 0, 0, 0, 0, 0, 0, 0
0893         .align 4
0894 firmware_end:               // must be dword-aligned