1*4882a593Smuzhiyun/* SPDX-License-Identifier: GPL-2.0-only */ 2*4882a593Smuzhiyun.psize 0 3*4882a593Smuzhiyun/* 4*4882a593Smuzhiyun wanXL serial card driver for Linux 5*4882a593Smuzhiyun card firmware part 6*4882a593Smuzhiyun 7*4882a593Smuzhiyun Copyright (C) 2003 Krzysztof Halasa <khc@pm.waw.pl> 8*4882a593Smuzhiyun 9*4882a593Smuzhiyun 10*4882a593Smuzhiyun 11*4882a593Smuzhiyun 12*4882a593Smuzhiyun 13*4882a593Smuzhiyun DPRAM BDs: 14*4882a593Smuzhiyun 0x000 - 0x050 TX#0 0x050 - 0x140 RX#0 15*4882a593Smuzhiyun 0x140 - 0x190 TX#1 0x190 - 0x280 RX#1 16*4882a593Smuzhiyun 0x280 - 0x2D0 TX#2 0x2D0 - 0x3C0 RX#2 17*4882a593Smuzhiyun 0x3C0 - 0x410 TX#3 0x410 - 0x500 RX#3 18*4882a593Smuzhiyun 19*4882a593Smuzhiyun 20*4882a593Smuzhiyun 000 5FF 1536 Bytes Dual-Port RAM User Data / BDs 21*4882a593Smuzhiyun 600 6FF 256 Bytes Dual-Port RAM User Data / BDs 22*4882a593Smuzhiyun 700 7FF 256 Bytes Dual-Port RAM User Data / BDs 23*4882a593Smuzhiyun C00 CBF 192 Bytes Dual-Port RAM Parameter RAM Page 1 24*4882a593Smuzhiyun D00 DBF 192 Bytes Dual-Port RAM Parameter RAM Page 2 25*4882a593Smuzhiyun E00 EBF 192 Bytes Dual-Port RAM Parameter RAM Page 3 26*4882a593Smuzhiyun F00 FBF 192 Bytes Dual-Port RAM Parameter RAM Page 4 27*4882a593Smuzhiyun 28*4882a593Smuzhiyun local interrupts level 29*4882a593Smuzhiyun NMI 7 30*4882a593Smuzhiyun PIT timer, CPM (RX/TX complete) 4 31*4882a593Smuzhiyun PCI9060 DMA and PCI doorbells 3 32*4882a593Smuzhiyun Cable - not used 1 33*4882a593Smuzhiyun*/ 34*4882a593Smuzhiyun 35*4882a593Smuzhiyun#include <linux/hdlc.h> 36*4882a593Smuzhiyun#include <linux/hdlc/ioctl.h> 37*4882a593Smuzhiyun#include "wanxl.h" 38*4882a593Smuzhiyun 39*4882a593Smuzhiyun/* memory addresses and offsets */ 40*4882a593Smuzhiyun 41*4882a593SmuzhiyunMAX_RAM_SIZE = 16 * 1024 * 1024 // max RAM supported by hardware 42*4882a593Smuzhiyun 43*4882a593SmuzhiyunPCI9060_VECTOR = 0x0000006C 44*4882a593SmuzhiyunCPM_IRQ_BASE = 0x40 45*4882a593SmuzhiyunERROR_VECTOR = CPM_IRQ_BASE * 4 46*4882a593SmuzhiyunSCC1_VECTOR = (CPM_IRQ_BASE + 0x1E) * 4 47*4882a593SmuzhiyunSCC2_VECTOR = (CPM_IRQ_BASE + 0x1D) * 4 48*4882a593SmuzhiyunSCC3_VECTOR = (CPM_IRQ_BASE + 0x1C) * 4 49*4882a593SmuzhiyunSCC4_VECTOR = (CPM_IRQ_BASE + 0x1B) * 4 50*4882a593SmuzhiyunCPM_IRQ_LEVEL = 4 51*4882a593SmuzhiyunTIMER_IRQ = 128 52*4882a593SmuzhiyunTIMER_IRQ_LEVEL = 4 53*4882a593SmuzhiyunPITR_CONST = 0x100 + 16 // 1 Hz timer 54*4882a593Smuzhiyun 55*4882a593SmuzhiyunMBAR = 0x0003FF00 56*4882a593Smuzhiyun 57*4882a593SmuzhiyunVALUE_WINDOW = 0x40000000 58*4882a593SmuzhiyunORDER_WINDOW = 0xC0000000 59*4882a593Smuzhiyun 60*4882a593SmuzhiyunPLX = 0xFFF90000 61*4882a593Smuzhiyun 62*4882a593SmuzhiyunCSRA = 0xFFFB0000 63*4882a593SmuzhiyunCSRB = 0xFFFB0002 64*4882a593SmuzhiyunCSRC = 0xFFFB0004 65*4882a593SmuzhiyunCSRD = 0xFFFB0006 66*4882a593SmuzhiyunSTATUS_CABLE_LL = 0x2000 67*4882a593SmuzhiyunSTATUS_CABLE_DTR = 0x1000 68*4882a593Smuzhiyun 69*4882a593SmuzhiyunDPRBASE = 0xFFFC0000 70*4882a593Smuzhiyun 71*4882a593SmuzhiyunSCC1_BASE = DPRBASE + 0xC00 72*4882a593SmuzhiyunMISC_BASE = DPRBASE + 0xCB0 73*4882a593SmuzhiyunSCC2_BASE = DPRBASE + 0xD00 74*4882a593SmuzhiyunSCC3_BASE = DPRBASE + 0xE00 75*4882a593SmuzhiyunSCC4_BASE = DPRBASE + 0xF00 76*4882a593Smuzhiyun 77*4882a593Smuzhiyun// offset from SCCx_BASE 78*4882a593Smuzhiyun// SCC_xBASE contain offsets from DPRBASE and must be divisible by 8 79*4882a593SmuzhiyunSCC_RBASE = 0 // 16-bit RxBD base address 80*4882a593SmuzhiyunSCC_TBASE = 2 // 16-bit TxBD base address 81*4882a593SmuzhiyunSCC_RFCR = 4 // 8-bit Rx function code 82*4882a593SmuzhiyunSCC_TFCR = 5 // 8-bit Tx function code 83*4882a593SmuzhiyunSCC_MRBLR = 6 // 16-bit maximum Rx buffer length 84*4882a593SmuzhiyunSCC_C_MASK = 0x34 // 32-bit CRC constant 85*4882a593SmuzhiyunSCC_C_PRES = 0x38 // 32-bit CRC preset 86*4882a593SmuzhiyunSCC_MFLR = 0x46 // 16-bit max Rx frame length (without flags) 87*4882a593Smuzhiyun 88*4882a593SmuzhiyunREGBASE = DPRBASE + 0x1000 89*4882a593SmuzhiyunPICR = REGBASE + 0x026 // 16-bit periodic irq control 90*4882a593SmuzhiyunPITR = REGBASE + 0x02A // 16-bit periodic irq timing 91*4882a593SmuzhiyunOR1 = REGBASE + 0x064 // 32-bit RAM bank #1 options 92*4882a593SmuzhiyunCICR = REGBASE + 0x540 // 32(24)-bit CP interrupt config 93*4882a593SmuzhiyunCIMR = REGBASE + 0x548 // 32-bit CP interrupt mask 94*4882a593SmuzhiyunCISR = REGBASE + 0x54C // 32-bit CP interrupts in-service 95*4882a593SmuzhiyunPADIR = REGBASE + 0x550 // 16-bit PortA data direction bitmap 96*4882a593SmuzhiyunPAPAR = REGBASE + 0x552 // 16-bit PortA pin assignment bitmap 97*4882a593SmuzhiyunPAODR = REGBASE + 0x554 // 16-bit PortA open drain bitmap 98*4882a593SmuzhiyunPADAT = REGBASE + 0x556 // 16-bit PortA data register 99*4882a593Smuzhiyun 100*4882a593SmuzhiyunPCDIR = REGBASE + 0x560 // 16-bit PortC data direction bitmap 101*4882a593SmuzhiyunPCPAR = REGBASE + 0x562 // 16-bit PortC pin assignment bitmap 102*4882a593SmuzhiyunPCSO = REGBASE + 0x564 // 16-bit PortC special options 103*4882a593SmuzhiyunPCDAT = REGBASE + 0x566 // 16-bit PortC data register 104*4882a593SmuzhiyunPCINT = REGBASE + 0x568 // 16-bit PortC interrupt control 105*4882a593SmuzhiyunCR = REGBASE + 0x5C0 // 16-bit Command register 106*4882a593Smuzhiyun 107*4882a593SmuzhiyunSCC1_REGS = REGBASE + 0x600 108*4882a593SmuzhiyunSCC2_REGS = REGBASE + 0x620 109*4882a593SmuzhiyunSCC3_REGS = REGBASE + 0x640 110*4882a593SmuzhiyunSCC4_REGS = REGBASE + 0x660 111*4882a593SmuzhiyunSICR = REGBASE + 0x6EC // 32-bit SI clock route 112*4882a593Smuzhiyun 113*4882a593Smuzhiyun// offset from SCCx_REGS 114*4882a593SmuzhiyunSCC_GSMR_L = 0x00 // 32 bits 115*4882a593SmuzhiyunSCC_GSMR_H = 0x04 // 32 bits 116*4882a593SmuzhiyunSCC_PSMR = 0x08 // 16 bits 117*4882a593SmuzhiyunSCC_TODR = 0x0C // 16 bits 118*4882a593SmuzhiyunSCC_DSR = 0x0E // 16 bits 119*4882a593SmuzhiyunSCC_SCCE = 0x10 // 16 bits 120*4882a593SmuzhiyunSCC_SCCM = 0x14 // 16 bits 121*4882a593SmuzhiyunSCC_SCCS = 0x17 // 8 bits 122*4882a593Smuzhiyun 123*4882a593Smuzhiyun#if QUICC_MEMCPY_USES_PLX 124*4882a593Smuzhiyun .macro memcpy_from_pci src, dest, len // len must be < 8 MB 125*4882a593Smuzhiyun addl #3, \len 126*4882a593Smuzhiyun andl #0xFFFFFFFC, \len // always copy n * 4 bytes 127*4882a593Smuzhiyun movel \src, PLX_DMA_0_PCI 128*4882a593Smuzhiyun movel \dest, PLX_DMA_0_LOCAL 129*4882a593Smuzhiyun movel \len, PLX_DMA_0_LENGTH 130*4882a593Smuzhiyun movel #0x0103, PLX_DMA_CMD_STS // start channel 0 transfer 131*4882a593Smuzhiyun bsr memcpy_from_pci_run 132*4882a593Smuzhiyun .endm 133*4882a593Smuzhiyun 134*4882a593Smuzhiyun .macro memcpy_to_pci src, dest, len 135*4882a593Smuzhiyun addl #3, \len 136*4882a593Smuzhiyun andl #0xFFFFFFFC, \len // always copy n * 4 bytes 137*4882a593Smuzhiyun movel \src, PLX_DMA_1_LOCAL 138*4882a593Smuzhiyun movel \dest, PLX_DMA_1_PCI 139*4882a593Smuzhiyun movel \len, PLX_DMA_1_LENGTH 140*4882a593Smuzhiyun movel #0x0301, PLX_DMA_CMD_STS // start channel 1 transfer 141*4882a593Smuzhiyun bsr memcpy_to_pci_run 142*4882a593Smuzhiyun .endm 143*4882a593Smuzhiyun 144*4882a593Smuzhiyun#else 145*4882a593Smuzhiyun 146*4882a593Smuzhiyun .macro memcpy src, dest, len // len must be < 65536 bytes 147*4882a593Smuzhiyun movel %d7, -(%sp) // src and dest must be < 256 MB 148*4882a593Smuzhiyun movel \len, %d7 // bits 0 and 1 149*4882a593Smuzhiyun lsrl #2, \len 150*4882a593Smuzhiyun andl \len, \len 151*4882a593Smuzhiyun beq 99f // only 0 - 3 bytes 152*4882a593Smuzhiyun subl #1, \len // for dbf 153*4882a593Smuzhiyun98: movel (\src)+, (\dest)+ 154*4882a593Smuzhiyun dbfw \len, 98b 155*4882a593Smuzhiyun99: movel %d7, \len 156*4882a593Smuzhiyun btstl #1, \len 157*4882a593Smuzhiyun beq 99f 158*4882a593Smuzhiyun movew (\src)+, (\dest)+ 159*4882a593Smuzhiyun99: btstl #0, \len 160*4882a593Smuzhiyun beq 99f 161*4882a593Smuzhiyun moveb (\src)+, (\dest)+ 162*4882a593Smuzhiyun99: 163*4882a593Smuzhiyun movel (%sp)+, %d7 164*4882a593Smuzhiyun .endm 165*4882a593Smuzhiyun 166*4882a593Smuzhiyun .macro memcpy_from_pci src, dest, len 167*4882a593Smuzhiyun addl #VALUE_WINDOW, \src 168*4882a593Smuzhiyun memcpy \src, \dest, \len 169*4882a593Smuzhiyun .endm 170*4882a593Smuzhiyun 171*4882a593Smuzhiyun .macro memcpy_to_pci src, dest, len 172*4882a593Smuzhiyun addl #VALUE_WINDOW, \dest 173*4882a593Smuzhiyun memcpy \src, \dest, \len 174*4882a593Smuzhiyun .endm 175*4882a593Smuzhiyun#endif 176*4882a593Smuzhiyun 177*4882a593Smuzhiyun 178*4882a593Smuzhiyun .macro wait_for_command 179*4882a593Smuzhiyun99: btstl #0, CR 180*4882a593Smuzhiyun bne 99b 181*4882a593Smuzhiyun .endm 182*4882a593Smuzhiyun 183*4882a593Smuzhiyun 184*4882a593Smuzhiyun 185*4882a593Smuzhiyun 186*4882a593Smuzhiyun/****************************** card initialization *******************/ 187*4882a593Smuzhiyun .text 188*4882a593Smuzhiyun .global _start 189*4882a593Smuzhiyun_start: bra init 190*4882a593Smuzhiyun 191*4882a593Smuzhiyun .org _start + 4 192*4882a593Smuzhiyunch_status_addr: .long 0, 0, 0, 0 193*4882a593Smuzhiyunrx_descs_addr: .long 0 194*4882a593Smuzhiyun 195*4882a593Smuzhiyuninit: 196*4882a593Smuzhiyun#if DETECT_RAM 197*4882a593Smuzhiyun movel OR1, %d0 198*4882a593Smuzhiyun andl #0xF00007FF, %d0 // mask AMxx bits 199*4882a593Smuzhiyun orl #0xFFFF800 & ~(MAX_RAM_SIZE - 1), %d0 // update RAM bank size 200*4882a593Smuzhiyun movel %d0, OR1 201*4882a593Smuzhiyun#endif 202*4882a593Smuzhiyun 203*4882a593Smuzhiyun addl #VALUE_WINDOW, rx_descs_addr // PCI addresses of shared data 204*4882a593Smuzhiyun clrl %d0 // D0 = 4 * port 205*4882a593Smuzhiyuninit_1: tstl ch_status_addr(%d0) 206*4882a593Smuzhiyun beq init_2 207*4882a593Smuzhiyun addl #VALUE_WINDOW, ch_status_addr(%d0) 208*4882a593Smuzhiyuninit_2: addl #4, %d0 209*4882a593Smuzhiyun cmpl #4 * 4, %d0 210*4882a593Smuzhiyun bne init_1 211*4882a593Smuzhiyun 212*4882a593Smuzhiyun movel #pci9060_interrupt, PCI9060_VECTOR 213*4882a593Smuzhiyun movel #error_interrupt, ERROR_VECTOR 214*4882a593Smuzhiyun movel #port_interrupt_1, SCC1_VECTOR 215*4882a593Smuzhiyun movel #port_interrupt_2, SCC2_VECTOR 216*4882a593Smuzhiyun movel #port_interrupt_3, SCC3_VECTOR 217*4882a593Smuzhiyun movel #port_interrupt_4, SCC4_VECTOR 218*4882a593Smuzhiyun movel #timer_interrupt, TIMER_IRQ * 4 219*4882a593Smuzhiyun 220*4882a593Smuzhiyun movel #0x78000000, CIMR // only SCCx IRQs from CPM 221*4882a593Smuzhiyun movew #(TIMER_IRQ_LEVEL << 8) + TIMER_IRQ, PICR // interrupt from PIT 222*4882a593Smuzhiyun movew #PITR_CONST, PITR 223*4882a593Smuzhiyun 224*4882a593Smuzhiyun // SCC1=SCCa SCC2=SCCb SCC3=SCCc SCC4=SCCd prio=4 HP=-1 IRQ=64-79 225*4882a593Smuzhiyun movel #0xD41F40 + (CPM_IRQ_LEVEL << 13), CICR 226*4882a593Smuzhiyun movel #0x543, PLX_DMA_0_MODE // 32-bit, Ready, Burst, IRQ 227*4882a593Smuzhiyun movel #0x543, PLX_DMA_1_MODE 228*4882a593Smuzhiyun movel #0x0, PLX_DMA_0_DESC // from PCI to local 229*4882a593Smuzhiyun movel #0x8, PLX_DMA_1_DESC // from local to PCI 230*4882a593Smuzhiyun movel #0x101, PLX_DMA_CMD_STS // enable both DMA channels 231*4882a593Smuzhiyun // enable local IRQ, DMA, doorbells and PCI IRQ 232*4882a593Smuzhiyun orl #0x000F0300, PLX_INTERRUPT_CS 233*4882a593Smuzhiyun 234*4882a593Smuzhiyun#if DETECT_RAM 235*4882a593Smuzhiyun bsr ram_test 236*4882a593Smuzhiyun#else 237*4882a593Smuzhiyun movel #1, PLX_MAILBOX_5 // non-zero value = init complete 238*4882a593Smuzhiyun#endif 239*4882a593Smuzhiyun bsr check_csr 240*4882a593Smuzhiyun 241*4882a593Smuzhiyun movew #0xFFFF, PAPAR // all pins are clocks/data 242*4882a593Smuzhiyun clrw PADIR // first function 243*4882a593Smuzhiyun clrw PCSO // CD and CTS always active 244*4882a593Smuzhiyun 245*4882a593Smuzhiyun 246*4882a593Smuzhiyun/****************************** main loop *****************************/ 247*4882a593Smuzhiyun 248*4882a593Smuzhiyunmain: movel channel_stats, %d7 // D7 = doorbell + irq status 249*4882a593Smuzhiyun clrl channel_stats 250*4882a593Smuzhiyun 251*4882a593Smuzhiyun tstl %d7 252*4882a593Smuzhiyun bne main_1 253*4882a593Smuzhiyun // nothing to do - wait for next event 254*4882a593Smuzhiyun stop #0x2200 // supervisor + IRQ level 2 255*4882a593Smuzhiyun movew #0x2700, %sr // disable IRQs again 256*4882a593Smuzhiyun bra main 257*4882a593Smuzhiyun 258*4882a593Smuzhiyunmain_1: clrl %d0 // D0 = 4 * port 259*4882a593Smuzhiyun clrl %d6 // D6 = doorbell to host value 260*4882a593Smuzhiyun 261*4882a593Smuzhiyunmain_l: btstl #DOORBELL_TO_CARD_CLOSE_0, %d7 262*4882a593Smuzhiyun beq main_op 263*4882a593Smuzhiyun bclrl #DOORBELL_TO_CARD_OPEN_0, %d7 // in case both bits are set 264*4882a593Smuzhiyun bsr close_port 265*4882a593Smuzhiyunmain_op: 266*4882a593Smuzhiyun btstl #DOORBELL_TO_CARD_OPEN_0, %d7 267*4882a593Smuzhiyun beq main_cl 268*4882a593Smuzhiyun bsr open_port 269*4882a593Smuzhiyunmain_cl: 270*4882a593Smuzhiyun btstl #DOORBELL_TO_CARD_TX_0, %d7 271*4882a593Smuzhiyun beq main_txend 272*4882a593Smuzhiyun bsr tx 273*4882a593Smuzhiyunmain_txend: 274*4882a593Smuzhiyun btstl #TASK_SCC_0, %d7 275*4882a593Smuzhiyun beq main_next 276*4882a593Smuzhiyun bsr tx_end 277*4882a593Smuzhiyun bsr rx 278*4882a593Smuzhiyun 279*4882a593Smuzhiyunmain_next: 280*4882a593Smuzhiyun lsrl #1, %d7 // port status for next port 281*4882a593Smuzhiyun addl #4, %d0 // D0 = 4 * next port 282*4882a593Smuzhiyun cmpl #4 * 4, %d0 283*4882a593Smuzhiyun bne main_l 284*4882a593Smuzhiyun movel %d6, PLX_DOORBELL_FROM_CARD // signal the host 285*4882a593Smuzhiyun bra main 286*4882a593Smuzhiyun 287*4882a593Smuzhiyun 288*4882a593Smuzhiyun/****************************** open port *****************************/ 289*4882a593Smuzhiyun 290*4882a593Smuzhiyunopen_port: // D0 = 4 * port, D6 = doorbell to host 291*4882a593Smuzhiyun movel ch_status_addr(%d0), %a0 // A0 = port status address 292*4882a593Smuzhiyun tstl STATUS_OPEN(%a0) 293*4882a593Smuzhiyun bne open_port_ret // port already open 294*4882a593Smuzhiyun movel #1, STATUS_OPEN(%a0) // confirm the port is open 295*4882a593Smuzhiyun// setup BDs 296*4882a593Smuzhiyun clrl tx_in(%d0) 297*4882a593Smuzhiyun clrl tx_out(%d0) 298*4882a593Smuzhiyun clrl tx_count(%d0) 299*4882a593Smuzhiyun clrl rx_in(%d0) 300*4882a593Smuzhiyun 301*4882a593Smuzhiyun movel SICR, %d1 // D1 = clock settings in SICR 302*4882a593Smuzhiyun andl clocking_mask(%d0), %d1 303*4882a593Smuzhiyun cmpl #CLOCK_TXFROMRX, STATUS_CLOCKING(%a0) 304*4882a593Smuzhiyun bne open_port_clock_ext 305*4882a593Smuzhiyun orl clocking_txfromrx(%d0), %d1 306*4882a593Smuzhiyun bra open_port_set_clock 307*4882a593Smuzhiyun 308*4882a593Smuzhiyunopen_port_clock_ext: 309*4882a593Smuzhiyun orl clocking_ext(%d0), %d1 310*4882a593Smuzhiyunopen_port_set_clock: 311*4882a593Smuzhiyun movel %d1, SICR // update clock settings in SICR 312*4882a593Smuzhiyun 313*4882a593Smuzhiyun orw #STATUS_CABLE_DTR, csr_output(%d0) // DTR on 314*4882a593Smuzhiyun bsr check_csr // call with disabled timer interrupt 315*4882a593Smuzhiyun 316*4882a593Smuzhiyun// Setup TX descriptors 317*4882a593Smuzhiyun movel first_buffer(%d0), %d1 // D1 = starting buffer address 318*4882a593Smuzhiyun movel tx_first_bd(%d0), %a1 // A1 = starting TX BD address 319*4882a593Smuzhiyun movel #TX_BUFFERS - 2, %d2 // D2 = TX_BUFFERS - 1 counter 320*4882a593Smuzhiyun movel #0x18000000, %d3 // D3 = initial TX BD flags: Int + Last 321*4882a593Smuzhiyun cmpl #PARITY_NONE, STATUS_PARITY(%a0) 322*4882a593Smuzhiyun beq open_port_tx_loop 323*4882a593Smuzhiyun bsetl #26, %d3 // TX BD flag: Transmit CRC 324*4882a593Smuzhiyunopen_port_tx_loop: 325*4882a593Smuzhiyun movel %d3, (%a1)+ // TX flags + length 326*4882a593Smuzhiyun movel %d1, (%a1)+ // buffer address 327*4882a593Smuzhiyun addl #BUFFER_LENGTH, %d1 328*4882a593Smuzhiyun dbfw %d2, open_port_tx_loop 329*4882a593Smuzhiyun 330*4882a593Smuzhiyun bsetl #29, %d3 // TX BD flag: Wrap (last BD) 331*4882a593Smuzhiyun movel %d3, (%a1)+ // Final TX flags + length 332*4882a593Smuzhiyun movel %d1, (%a1)+ // buffer address 333*4882a593Smuzhiyun 334*4882a593Smuzhiyun// Setup RX descriptors // A1 = starting RX BD address 335*4882a593Smuzhiyun movel #RX_BUFFERS - 2, %d2 // D2 = RX_BUFFERS - 1 counter 336*4882a593Smuzhiyunopen_port_rx_loop: 337*4882a593Smuzhiyun movel #0x90000000, (%a1)+ // RX flags + length 338*4882a593Smuzhiyun movel %d1, (%a1)+ // buffer address 339*4882a593Smuzhiyun addl #BUFFER_LENGTH, %d1 340*4882a593Smuzhiyun dbfw %d2, open_port_rx_loop 341*4882a593Smuzhiyun 342*4882a593Smuzhiyun movel #0xB0000000, (%a1)+ // Final RX flags + length 343*4882a593Smuzhiyun movel %d1, (%a1)+ // buffer address 344*4882a593Smuzhiyun 345*4882a593Smuzhiyun// Setup port parameters 346*4882a593Smuzhiyun movel scc_base_addr(%d0), %a1 // A1 = SCC_BASE address 347*4882a593Smuzhiyun movel scc_reg_addr(%d0), %a2 // A2 = SCC_REGS address 348*4882a593Smuzhiyun 349*4882a593Smuzhiyun movel #0xFFFF, SCC_SCCE(%a2) // clear status bits 350*4882a593Smuzhiyun movel #0x0000, SCC_SCCM(%a2) // interrupt mask 351*4882a593Smuzhiyun 352*4882a593Smuzhiyun movel tx_first_bd(%d0), %d1 353*4882a593Smuzhiyun movew %d1, SCC_TBASE(%a1) // D1 = offset of first TxBD 354*4882a593Smuzhiyun addl #TX_BUFFERS * 8, %d1 355*4882a593Smuzhiyun movew %d1, SCC_RBASE(%a1) // D1 = offset of first RxBD 356*4882a593Smuzhiyun moveb #0x8, SCC_RFCR(%a1) // Intel mode, 1000 357*4882a593Smuzhiyun moveb #0x8, SCC_TFCR(%a1) 358*4882a593Smuzhiyun 359*4882a593Smuzhiyun// Parity settings 360*4882a593Smuzhiyun cmpl #PARITY_CRC16_PR1_CCITT, STATUS_PARITY(%a0) 361*4882a593Smuzhiyun bne open_port_parity_1 362*4882a593Smuzhiyun clrw SCC_PSMR(%a2) // CRC16-CCITT 363*4882a593Smuzhiyun movel #0xF0B8, SCC_C_MASK(%a1) 364*4882a593Smuzhiyun movel #0xFFFF, SCC_C_PRES(%a1) 365*4882a593Smuzhiyun movew #HDLC_MAX_MRU + 2, SCC_MFLR(%a1) // 2 bytes for CRC 366*4882a593Smuzhiyun movew #2, parity_bytes(%d0) 367*4882a593Smuzhiyun bra open_port_2 368*4882a593Smuzhiyun 369*4882a593Smuzhiyunopen_port_parity_1: 370*4882a593Smuzhiyun cmpl #PARITY_CRC32_PR1_CCITT, STATUS_PARITY(%a0) 371*4882a593Smuzhiyun bne open_port_parity_2 372*4882a593Smuzhiyun movew #0x0800, SCC_PSMR(%a2) // CRC32-CCITT 373*4882a593Smuzhiyun movel #0xDEBB20E3, SCC_C_MASK(%a1) 374*4882a593Smuzhiyun movel #0xFFFFFFFF, SCC_C_PRES(%a1) 375*4882a593Smuzhiyun movew #HDLC_MAX_MRU + 4, SCC_MFLR(%a1) // 4 bytes for CRC 376*4882a593Smuzhiyun movew #4, parity_bytes(%d0) 377*4882a593Smuzhiyun bra open_port_2 378*4882a593Smuzhiyun 379*4882a593Smuzhiyunopen_port_parity_2: 380*4882a593Smuzhiyun cmpl #PARITY_CRC16_PR0_CCITT, STATUS_PARITY(%a0) 381*4882a593Smuzhiyun bne open_port_parity_3 382*4882a593Smuzhiyun clrw SCC_PSMR(%a2) // CRC16-CCITT preset 0 383*4882a593Smuzhiyun movel #0xF0B8, SCC_C_MASK(%a1) 384*4882a593Smuzhiyun clrl SCC_C_PRES(%a1) 385*4882a593Smuzhiyun movew #HDLC_MAX_MRU + 2, SCC_MFLR(%a1) // 2 bytes for CRC 386*4882a593Smuzhiyun movew #2, parity_bytes(%d0) 387*4882a593Smuzhiyun bra open_port_2 388*4882a593Smuzhiyun 389*4882a593Smuzhiyunopen_port_parity_3: 390*4882a593Smuzhiyun cmpl #PARITY_CRC32_PR0_CCITT, STATUS_PARITY(%a0) 391*4882a593Smuzhiyun bne open_port_parity_4 392*4882a593Smuzhiyun movew #0x0800, SCC_PSMR(%a2) // CRC32-CCITT preset 0 393*4882a593Smuzhiyun movel #0xDEBB20E3, SCC_C_MASK(%a1) 394*4882a593Smuzhiyun clrl SCC_C_PRES(%a1) 395*4882a593Smuzhiyun movew #HDLC_MAX_MRU + 4, SCC_MFLR(%a1) // 4 bytes for CRC 396*4882a593Smuzhiyun movew #4, parity_bytes(%d0) 397*4882a593Smuzhiyun bra open_port_2 398*4882a593Smuzhiyun 399*4882a593Smuzhiyunopen_port_parity_4: 400*4882a593Smuzhiyun clrw SCC_PSMR(%a2) // no parity 401*4882a593Smuzhiyun movel #0xF0B8, SCC_C_MASK(%a1) 402*4882a593Smuzhiyun movel #0xFFFF, SCC_C_PRES(%a1) 403*4882a593Smuzhiyun movew #HDLC_MAX_MRU, SCC_MFLR(%a1) // 0 bytes for CRC 404*4882a593Smuzhiyun clrw parity_bytes(%d0) 405*4882a593Smuzhiyun 406*4882a593Smuzhiyunopen_port_2: 407*4882a593Smuzhiyun movel #0x00000003, SCC_GSMR_H(%a2) // RTSM 408*4882a593Smuzhiyun cmpl #ENCODING_NRZI, STATUS_ENCODING(%a0) 409*4882a593Smuzhiyun bne open_port_nrz 410*4882a593Smuzhiyun movel #0x10040900, SCC_GSMR_L(%a2) // NRZI: TCI Tend RECN+TENC=1 411*4882a593Smuzhiyun bra open_port_3 412*4882a593Smuzhiyun 413*4882a593Smuzhiyunopen_port_nrz: 414*4882a593Smuzhiyun movel #0x10040000, SCC_GSMR_L(%a2) // NRZ: TCI Tend RECN+TENC=0 415*4882a593Smuzhiyunopen_port_3: 416*4882a593Smuzhiyun movew #BUFFER_LENGTH, SCC_MRBLR(%a1) 417*4882a593Smuzhiyun movel %d0, %d1 418*4882a593Smuzhiyun lsll #4, %d1 // D1 bits 7 and 6 = port 419*4882a593Smuzhiyun orl #1, %d1 420*4882a593Smuzhiyun movew %d1, CR // Init SCC RX and TX params 421*4882a593Smuzhiyun wait_for_command 422*4882a593Smuzhiyun 423*4882a593Smuzhiyun // TCI Tend ENR ENT 424*4882a593Smuzhiyun movew #0x001F, SCC_SCCM(%a2) // TXE RXF BSY TXB RXB interrupts 425*4882a593Smuzhiyun orl #0x00000030, SCC_GSMR_L(%a2) // enable SCC 426*4882a593Smuzhiyunopen_port_ret: 427*4882a593Smuzhiyun rts 428*4882a593Smuzhiyun 429*4882a593Smuzhiyun 430*4882a593Smuzhiyun/****************************** close port ****************************/ 431*4882a593Smuzhiyun 432*4882a593Smuzhiyunclose_port: // D0 = 4 * port, D6 = doorbell to host 433*4882a593Smuzhiyun movel scc_reg_addr(%d0), %a0 // A0 = SCC_REGS address 434*4882a593Smuzhiyun clrw SCC_SCCM(%a0) // no SCC interrupts 435*4882a593Smuzhiyun andl #0xFFFFFFCF, SCC_GSMR_L(%a0) // Disable ENT and ENR 436*4882a593Smuzhiyun 437*4882a593Smuzhiyun andw #~STATUS_CABLE_DTR, csr_output(%d0) // DTR off 438*4882a593Smuzhiyun bsr check_csr // call with disabled timer interrupt 439*4882a593Smuzhiyun 440*4882a593Smuzhiyun movel ch_status_addr(%d0), %d1 441*4882a593Smuzhiyun clrl STATUS_OPEN(%d1) // confirm the port is closed 442*4882a593Smuzhiyun rts 443*4882a593Smuzhiyun 444*4882a593Smuzhiyun 445*4882a593Smuzhiyun/****************************** transmit packet ***********************/ 446*4882a593Smuzhiyun// queue packets for transmission 447*4882a593Smuzhiyuntx: // D0 = 4 * port, D6 = doorbell to host 448*4882a593Smuzhiyun cmpl #TX_BUFFERS, tx_count(%d0) 449*4882a593Smuzhiyun beq tx_ret // all DB's = descs in use 450*4882a593Smuzhiyun 451*4882a593Smuzhiyun movel tx_out(%d0), %d1 452*4882a593Smuzhiyun movel %d1, %d2 // D1 = D2 = tx_out BD# = desc# 453*4882a593Smuzhiyun mulul #DESC_LENGTH, %d2 // D2 = TX desc offset 454*4882a593Smuzhiyun addl ch_status_addr(%d0), %d2 455*4882a593Smuzhiyun addl #STATUS_TX_DESCS, %d2 // D2 = TX desc address 456*4882a593Smuzhiyun cmpl #PACKET_FULL, (%d2) // desc status 457*4882a593Smuzhiyun bne tx_ret 458*4882a593Smuzhiyun 459*4882a593Smuzhiyun// queue it 460*4882a593Smuzhiyun movel 4(%d2), %a0 // PCI address 461*4882a593Smuzhiyun lsll #3, %d1 // BD is 8-bytes long 462*4882a593Smuzhiyun addl tx_first_bd(%d0), %d1 // D1 = current tx_out BD addr 463*4882a593Smuzhiyun 464*4882a593Smuzhiyun movel 4(%d1), %a1 // A1 = dest address 465*4882a593Smuzhiyun movel 8(%d2), %d2 // D2 = length 466*4882a593Smuzhiyun movew %d2, 2(%d1) // length into BD 467*4882a593Smuzhiyun memcpy_from_pci %a0, %a1, %d2 468*4882a593Smuzhiyun bsetl #31, (%d1) // CP go ahead 469*4882a593Smuzhiyun 470*4882a593Smuzhiyun// update tx_out and tx_count 471*4882a593Smuzhiyun movel tx_out(%d0), %d1 472*4882a593Smuzhiyun addl #1, %d1 473*4882a593Smuzhiyun cmpl #TX_BUFFERS, %d1 474*4882a593Smuzhiyun bne tx_1 475*4882a593Smuzhiyun clrl %d1 476*4882a593Smuzhiyuntx_1: movel %d1, tx_out(%d0) 477*4882a593Smuzhiyun 478*4882a593Smuzhiyun addl #1, tx_count(%d0) 479*4882a593Smuzhiyun bra tx 480*4882a593Smuzhiyun 481*4882a593Smuzhiyuntx_ret: rts 482*4882a593Smuzhiyun 483*4882a593Smuzhiyun 484*4882a593Smuzhiyun/****************************** packet received ***********************/ 485*4882a593Smuzhiyun 486*4882a593Smuzhiyun// Service receive buffers // D0 = 4 * port, D6 = doorbell to host 487*4882a593Smuzhiyunrx: movel rx_in(%d0), %d1 // D1 = rx_in BD# 488*4882a593Smuzhiyun lsll #3, %d1 // BD is 8-bytes long 489*4882a593Smuzhiyun addl rx_first_bd(%d0), %d1 // D1 = current rx_in BD address 490*4882a593Smuzhiyun movew (%d1), %d2 // D2 = RX BD flags 491*4882a593Smuzhiyun btstl #15, %d2 492*4882a593Smuzhiyun bne rx_ret // BD still empty 493*4882a593Smuzhiyun 494*4882a593Smuzhiyun btstl #1, %d2 495*4882a593Smuzhiyun bne rx_overrun 496*4882a593Smuzhiyun 497*4882a593Smuzhiyun tstw parity_bytes(%d0) 498*4882a593Smuzhiyun bne rx_parity 499*4882a593Smuzhiyun bclrl #2, %d2 // do not test for CRC errors 500*4882a593Smuzhiyunrx_parity: 501*4882a593Smuzhiyun andw #0x0CBC, %d2 // mask status bits 502*4882a593Smuzhiyun cmpw #0x0C00, %d2 // correct frame 503*4882a593Smuzhiyun bne rx_bad_frame 504*4882a593Smuzhiyun clrl %d3 505*4882a593Smuzhiyun movew 2(%d1), %d3 506*4882a593Smuzhiyun subw parity_bytes(%d0), %d3 // D3 = packet length 507*4882a593Smuzhiyun cmpw #HDLC_MAX_MRU, %d3 508*4882a593Smuzhiyun bgt rx_bad_frame 509*4882a593Smuzhiyun 510*4882a593Smuzhiyunrx_good_frame: 511*4882a593Smuzhiyun movel rx_out, %d2 512*4882a593Smuzhiyun mulul #DESC_LENGTH, %d2 513*4882a593Smuzhiyun addl rx_descs_addr, %d2 // D2 = RX desc address 514*4882a593Smuzhiyun cmpl #PACKET_EMPTY, (%d2) // desc stat 515*4882a593Smuzhiyun bne rx_overrun 516*4882a593Smuzhiyun 517*4882a593Smuzhiyun movel %d3, 8(%d2) 518*4882a593Smuzhiyun movel 4(%d1), %a0 // A0 = source address 519*4882a593Smuzhiyun movel 4(%d2), %a1 520*4882a593Smuzhiyun tstl %a1 521*4882a593Smuzhiyun beq rx_ignore_data 522*4882a593Smuzhiyun memcpy_to_pci %a0, %a1, %d3 523*4882a593Smuzhiyunrx_ignore_data: 524*4882a593Smuzhiyun movel packet_full(%d0), (%d2) // update desc stat 525*4882a593Smuzhiyun 526*4882a593Smuzhiyun// update D6 and rx_out 527*4882a593Smuzhiyun bsetl #DOORBELL_FROM_CARD_RX, %d6 // signal host that RX completed 528*4882a593Smuzhiyun movel rx_out, %d2 529*4882a593Smuzhiyun addl #1, %d2 530*4882a593Smuzhiyun cmpl #RX_QUEUE_LENGTH, %d2 531*4882a593Smuzhiyun bne rx_1 532*4882a593Smuzhiyun clrl %d2 533*4882a593Smuzhiyunrx_1: movel %d2, rx_out 534*4882a593Smuzhiyun 535*4882a593Smuzhiyunrx_free_bd: 536*4882a593Smuzhiyun andw #0xF000, (%d1) // clear CM and error bits 537*4882a593Smuzhiyun bsetl #31, (%d1) // free BD 538*4882a593Smuzhiyun// update rx_in 539*4882a593Smuzhiyun movel rx_in(%d0), %d1 540*4882a593Smuzhiyun addl #1, %d1 541*4882a593Smuzhiyun cmpl #RX_BUFFERS, %d1 542*4882a593Smuzhiyun bne rx_2 543*4882a593Smuzhiyun clrl %d1 544*4882a593Smuzhiyunrx_2: movel %d1, rx_in(%d0) 545*4882a593Smuzhiyun bra rx 546*4882a593Smuzhiyun 547*4882a593Smuzhiyunrx_overrun: 548*4882a593Smuzhiyun movel ch_status_addr(%d0), %d2 549*4882a593Smuzhiyun addl #1, STATUS_RX_OVERRUNS(%d2) 550*4882a593Smuzhiyun bra rx_free_bd 551*4882a593Smuzhiyun 552*4882a593Smuzhiyunrx_bad_frame: 553*4882a593Smuzhiyun movel ch_status_addr(%d0), %d2 554*4882a593Smuzhiyun addl #1, STATUS_RX_FRAME_ERRORS(%d2) 555*4882a593Smuzhiyun bra rx_free_bd 556*4882a593Smuzhiyun 557*4882a593Smuzhiyunrx_ret: rts 558*4882a593Smuzhiyun 559*4882a593Smuzhiyun 560*4882a593Smuzhiyun/****************************** packet transmitted ********************/ 561*4882a593Smuzhiyun 562*4882a593Smuzhiyun// Service transmit buffers // D0 = 4 * port, D6 = doorbell to host 563*4882a593Smuzhiyuntx_end: tstl tx_count(%d0) 564*4882a593Smuzhiyun beq tx_end_ret // TX buffers already empty 565*4882a593Smuzhiyun 566*4882a593Smuzhiyun movel tx_in(%d0), %d1 567*4882a593Smuzhiyun movel %d1, %d2 // D1 = D2 = tx_in BD# = desc# 568*4882a593Smuzhiyun lsll #3, %d1 // BD is 8-bytes long 569*4882a593Smuzhiyun addl tx_first_bd(%d0), %d1 // D1 = current tx_in BD address 570*4882a593Smuzhiyun movew (%d1), %d3 // D3 = TX BD flags 571*4882a593Smuzhiyun btstl #15, %d3 572*4882a593Smuzhiyun bne tx_end_ret // BD still being transmitted 573*4882a593Smuzhiyun 574*4882a593Smuzhiyun// update D6, tx_in and tx_count 575*4882a593Smuzhiyun orl bell_tx(%d0), %d6 // signal host that TX desc freed 576*4882a593Smuzhiyun subl #1, tx_count(%d0) 577*4882a593Smuzhiyun movel tx_in(%d0), %d1 578*4882a593Smuzhiyun addl #1, %d1 579*4882a593Smuzhiyun cmpl #TX_BUFFERS, %d1 580*4882a593Smuzhiyun bne tx_end_1 581*4882a593Smuzhiyun clrl %d1 582*4882a593Smuzhiyuntx_end_1: 583*4882a593Smuzhiyun movel %d1, tx_in(%d0) 584*4882a593Smuzhiyun 585*4882a593Smuzhiyun// free host's descriptor 586*4882a593Smuzhiyun mulul #DESC_LENGTH, %d2 // D2 = TX desc offset 587*4882a593Smuzhiyun addl ch_status_addr(%d0), %d2 588*4882a593Smuzhiyun addl #STATUS_TX_DESCS, %d2 // D2 = TX desc address 589*4882a593Smuzhiyun btstl #1, %d3 590*4882a593Smuzhiyun bne tx_end_underrun 591*4882a593Smuzhiyun movel #PACKET_SENT, (%d2) 592*4882a593Smuzhiyun bra tx_end 593*4882a593Smuzhiyun 594*4882a593Smuzhiyuntx_end_underrun: 595*4882a593Smuzhiyun movel #PACKET_UNDERRUN, (%d2) 596*4882a593Smuzhiyun bra tx_end 597*4882a593Smuzhiyun 598*4882a593Smuzhiyuntx_end_ret: rts 599*4882a593Smuzhiyun 600*4882a593Smuzhiyun 601*4882a593Smuzhiyun/****************************** PLX PCI9060 DMA memcpy ****************/ 602*4882a593Smuzhiyun 603*4882a593Smuzhiyun#if QUICC_MEMCPY_USES_PLX 604*4882a593Smuzhiyun// called with interrupts disabled 605*4882a593Smuzhiyunmemcpy_from_pci_run: 606*4882a593Smuzhiyun movel %d0, -(%sp) 607*4882a593Smuzhiyun movew %sr, -(%sp) 608*4882a593Smuzhiyunmemcpy_1: 609*4882a593Smuzhiyun movel PLX_DMA_CMD_STS, %d0 // do not btst PLX register directly 610*4882a593Smuzhiyun btstl #4, %d0 // transfer done? 611*4882a593Smuzhiyun bne memcpy_end 612*4882a593Smuzhiyun stop #0x2200 // enable PCI9060 interrupts 613*4882a593Smuzhiyun movew #0x2700, %sr // disable interrupts again 614*4882a593Smuzhiyun bra memcpy_1 615*4882a593Smuzhiyun 616*4882a593Smuzhiyunmemcpy_to_pci_run: 617*4882a593Smuzhiyun movel %d0, -(%sp) 618*4882a593Smuzhiyun movew %sr, -(%sp) 619*4882a593Smuzhiyunmemcpy_2: 620*4882a593Smuzhiyun movel PLX_DMA_CMD_STS, %d0 // do not btst PLX register directly 621*4882a593Smuzhiyun btstl #12, %d0 // transfer done? 622*4882a593Smuzhiyun bne memcpy_end 623*4882a593Smuzhiyun stop #0x2200 // enable PCI9060 interrupts 624*4882a593Smuzhiyun movew #0x2700, %sr // disable interrupts again 625*4882a593Smuzhiyun bra memcpy_2 626*4882a593Smuzhiyun 627*4882a593Smuzhiyunmemcpy_end: 628*4882a593Smuzhiyun movew (%sp)+, %sr 629*4882a593Smuzhiyun movel (%sp)+, %d0 630*4882a593Smuzhiyun rts 631*4882a593Smuzhiyun#endif 632*4882a593Smuzhiyun 633*4882a593Smuzhiyun 634*4882a593Smuzhiyun 635*4882a593Smuzhiyun 636*4882a593Smuzhiyun 637*4882a593Smuzhiyun 638*4882a593Smuzhiyun/****************************** PLX PCI9060 interrupt *****************/ 639*4882a593Smuzhiyun 640*4882a593Smuzhiyunpci9060_interrupt: 641*4882a593Smuzhiyun movel %d0, -(%sp) 642*4882a593Smuzhiyun 643*4882a593Smuzhiyun movel PLX_DOORBELL_TO_CARD, %d0 644*4882a593Smuzhiyun movel %d0, PLX_DOORBELL_TO_CARD // confirm all requests 645*4882a593Smuzhiyun orl %d0, channel_stats 646*4882a593Smuzhiyun 647*4882a593Smuzhiyun movel #0x0909, PLX_DMA_CMD_STS // clear DMA ch #0 and #1 interrupts 648*4882a593Smuzhiyun 649*4882a593Smuzhiyun movel (%sp)+, %d0 650*4882a593Smuzhiyun rte 651*4882a593Smuzhiyun 652*4882a593Smuzhiyun/****************************** SCC interrupts ************************/ 653*4882a593Smuzhiyun 654*4882a593Smuzhiyunport_interrupt_1: 655*4882a593Smuzhiyun orl #0, SCC1_REGS + SCC_SCCE; // confirm SCC events 656*4882a593Smuzhiyun orl #1 << TASK_SCC_0, channel_stats 657*4882a593Smuzhiyun movel #0x40000000, CISR 658*4882a593Smuzhiyun rte 659*4882a593Smuzhiyun 660*4882a593Smuzhiyunport_interrupt_2: 661*4882a593Smuzhiyun orl #0, SCC2_REGS + SCC_SCCE; // confirm SCC events 662*4882a593Smuzhiyun orl #1 << TASK_SCC_1, channel_stats 663*4882a593Smuzhiyun movel #0x20000000, CISR 664*4882a593Smuzhiyun rte 665*4882a593Smuzhiyun 666*4882a593Smuzhiyunport_interrupt_3: 667*4882a593Smuzhiyun orl #0, SCC3_REGS + SCC_SCCE; // confirm SCC events 668*4882a593Smuzhiyun orl #1 << TASK_SCC_2, channel_stats 669*4882a593Smuzhiyun movel #0x10000000, CISR 670*4882a593Smuzhiyun rte 671*4882a593Smuzhiyun 672*4882a593Smuzhiyunport_interrupt_4: 673*4882a593Smuzhiyun orl #0, SCC4_REGS + SCC_SCCE; // confirm SCC events 674*4882a593Smuzhiyun orl #1 << TASK_SCC_3, channel_stats 675*4882a593Smuzhiyun movel #0x08000000, CISR 676*4882a593Smuzhiyun rte 677*4882a593Smuzhiyun 678*4882a593Smuzhiyunerror_interrupt: 679*4882a593Smuzhiyun rte 680*4882a593Smuzhiyun 681*4882a593Smuzhiyun 682*4882a593Smuzhiyun/****************************** cable and PM routine ******************/ 683*4882a593Smuzhiyun// modified registers: none 684*4882a593Smuzhiyuncheck_csr: 685*4882a593Smuzhiyun movel %d0, -(%sp) 686*4882a593Smuzhiyun movel %d1, -(%sp) 687*4882a593Smuzhiyun movel %d2, -(%sp) 688*4882a593Smuzhiyun movel %a0, -(%sp) 689*4882a593Smuzhiyun movel %a1, -(%sp) 690*4882a593Smuzhiyun 691*4882a593Smuzhiyun clrl %d0 // D0 = 4 * port 692*4882a593Smuzhiyun movel #CSRA, %a0 // A0 = CSR address 693*4882a593Smuzhiyun 694*4882a593Smuzhiyuncheck_csr_loop: 695*4882a593Smuzhiyun movew (%a0), %d1 // D1 = CSR input bits 696*4882a593Smuzhiyun andl #0xE7, %d1 // PM and cable sense bits (no DCE bit) 697*4882a593Smuzhiyun cmpw #STATUS_CABLE_V35 * (1 + 1 << STATUS_CABLE_PM_SHIFT), %d1 698*4882a593Smuzhiyun bne check_csr_1 699*4882a593Smuzhiyun movew #0x0E08, %d1 700*4882a593Smuzhiyun bra check_csr_valid 701*4882a593Smuzhiyun 702*4882a593Smuzhiyuncheck_csr_1: 703*4882a593Smuzhiyun cmpw #STATUS_CABLE_X21 * (1 + 1 << STATUS_CABLE_PM_SHIFT), %d1 704*4882a593Smuzhiyun bne check_csr_2 705*4882a593Smuzhiyun movew #0x0408, %d1 706*4882a593Smuzhiyun bra check_csr_valid 707*4882a593Smuzhiyun 708*4882a593Smuzhiyuncheck_csr_2: 709*4882a593Smuzhiyun cmpw #STATUS_CABLE_V24 * (1 + 1 << STATUS_CABLE_PM_SHIFT), %d1 710*4882a593Smuzhiyun bne check_csr_3 711*4882a593Smuzhiyun movew #0x0208, %d1 712*4882a593Smuzhiyun bra check_csr_valid 713*4882a593Smuzhiyun 714*4882a593Smuzhiyuncheck_csr_3: 715*4882a593Smuzhiyun cmpw #STATUS_CABLE_EIA530 * (1 + 1 << STATUS_CABLE_PM_SHIFT), %d1 716*4882a593Smuzhiyun bne check_csr_disable 717*4882a593Smuzhiyun movew #0x0D08, %d1 718*4882a593Smuzhiyun bra check_csr_valid 719*4882a593Smuzhiyun 720*4882a593Smuzhiyuncheck_csr_disable: 721*4882a593Smuzhiyun movew #0x0008, %d1 // D1 = disable everything 722*4882a593Smuzhiyun movew #0x80E7, %d2 // D2 = input mask: ignore DSR 723*4882a593Smuzhiyun bra check_csr_write 724*4882a593Smuzhiyun 725*4882a593Smuzhiyuncheck_csr_valid: // D1 = mode and IRQ bits 726*4882a593Smuzhiyun movew csr_output(%d0), %d2 727*4882a593Smuzhiyun andw #0x3000, %d2 // D2 = requested LL and DTR bits 728*4882a593Smuzhiyun orw %d2, %d1 // D1 = all requested output bits 729*4882a593Smuzhiyun movew #0x80FF, %d2 // D2 = input mask: include DSR 730*4882a593Smuzhiyun 731*4882a593Smuzhiyuncheck_csr_write: 732*4882a593Smuzhiyun cmpw old_csr_output(%d0), %d1 733*4882a593Smuzhiyun beq check_csr_input 734*4882a593Smuzhiyun movew %d1, old_csr_output(%d0) 735*4882a593Smuzhiyun movew %d1, (%a0) // Write CSR output bits 736*4882a593Smuzhiyun 737*4882a593Smuzhiyuncheck_csr_input: 738*4882a593Smuzhiyun movew (PCDAT), %d1 739*4882a593Smuzhiyun andw dcd_mask(%d0), %d1 740*4882a593Smuzhiyun beq check_csr_dcd_on // DCD and CTS signals are negated 741*4882a593Smuzhiyun movew (%a0), %d1 // D1 = CSR input bits 742*4882a593Smuzhiyun andw #~STATUS_CABLE_DCD, %d1 // DCD off 743*4882a593Smuzhiyun bra check_csr_previous 744*4882a593Smuzhiyun 745*4882a593Smuzhiyuncheck_csr_dcd_on: 746*4882a593Smuzhiyun movew (%a0), %d1 // D1 = CSR input bits 747*4882a593Smuzhiyun orw #STATUS_CABLE_DCD, %d1 // DCD on 748*4882a593Smuzhiyuncheck_csr_previous: 749*4882a593Smuzhiyun andw %d2, %d1 // input mask 750*4882a593Smuzhiyun movel ch_status_addr(%d0), %a1 751*4882a593Smuzhiyun cmpl STATUS_CABLE(%a1), %d1 // check for change 752*4882a593Smuzhiyun beq check_csr_next 753*4882a593Smuzhiyun movel %d1, STATUS_CABLE(%a1) // update status 754*4882a593Smuzhiyun movel bell_cable(%d0), PLX_DOORBELL_FROM_CARD // signal the host 755*4882a593Smuzhiyun 756*4882a593Smuzhiyuncheck_csr_next: 757*4882a593Smuzhiyun addl #2, %a0 // next CSR register 758*4882a593Smuzhiyun addl #4, %d0 // D0 = 4 * next port 759*4882a593Smuzhiyun cmpl #4 * 4, %d0 760*4882a593Smuzhiyun bne check_csr_loop 761*4882a593Smuzhiyun 762*4882a593Smuzhiyun movel (%sp)+, %a1 763*4882a593Smuzhiyun movel (%sp)+, %a0 764*4882a593Smuzhiyun movel (%sp)+, %d2 765*4882a593Smuzhiyun movel (%sp)+, %d1 766*4882a593Smuzhiyun movel (%sp)+, %d0 767*4882a593Smuzhiyun rts 768*4882a593Smuzhiyun 769*4882a593Smuzhiyun 770*4882a593Smuzhiyun/****************************** timer interrupt ***********************/ 771*4882a593Smuzhiyun 772*4882a593Smuzhiyuntimer_interrupt: 773*4882a593Smuzhiyun bsr check_csr 774*4882a593Smuzhiyun rte 775*4882a593Smuzhiyun 776*4882a593Smuzhiyun 777*4882a593Smuzhiyun/****************************** RAM sizing and test *******************/ 778*4882a593Smuzhiyun#if DETECT_RAM 779*4882a593Smuzhiyunram_test: 780*4882a593Smuzhiyun movel #0x12345678, %d1 // D1 = test value 781*4882a593Smuzhiyun movel %d1, (128 * 1024 - 4) 782*4882a593Smuzhiyun movel #128 * 1024, %d0 // D0 = RAM size tested 783*4882a593Smuzhiyunram_test_size: 784*4882a593Smuzhiyun cmpl #MAX_RAM_SIZE, %d0 785*4882a593Smuzhiyun beq ram_test_size_found 786*4882a593Smuzhiyun movel %d0, %a0 787*4882a593Smuzhiyun addl #128 * 1024 - 4, %a0 788*4882a593Smuzhiyun cmpl (%a0), %d1 789*4882a593Smuzhiyun beq ram_test_size_check 790*4882a593Smuzhiyunram_test_next_size: 791*4882a593Smuzhiyun lsll #1, %d0 792*4882a593Smuzhiyun bra ram_test_size 793*4882a593Smuzhiyun 794*4882a593Smuzhiyunram_test_size_check: 795*4882a593Smuzhiyun eorl #0xFFFFFFFF, %d1 796*4882a593Smuzhiyun movel %d1, (128 * 1024 - 4) 797*4882a593Smuzhiyun cmpl (%a0), %d1 798*4882a593Smuzhiyun bne ram_test_next_size 799*4882a593Smuzhiyun 800*4882a593Smuzhiyunram_test_size_found: // D0 = RAM size 801*4882a593Smuzhiyun movel %d0, %a0 // A0 = fill ptr 802*4882a593Smuzhiyun subl #firmware_end + 4, %d0 803*4882a593Smuzhiyun lsrl #2, %d0 804*4882a593Smuzhiyun movel %d0, %d1 // D1 = DBf counter 805*4882a593Smuzhiyunram_test_fill: 806*4882a593Smuzhiyun movel %a0, -(%a0) 807*4882a593Smuzhiyun dbfw %d1, ram_test_fill 808*4882a593Smuzhiyun subl #0x10000, %d1 809*4882a593Smuzhiyun cmpl #0xFFFFFFFF, %d1 810*4882a593Smuzhiyun bne ram_test_fill 811*4882a593Smuzhiyun 812*4882a593Smuzhiyunram_test_loop: // D0 = DBf counter 813*4882a593Smuzhiyun cmpl (%a0)+, %a0 814*4882a593Smuzhiyun dbnew %d0, ram_test_loop 815*4882a593Smuzhiyun bne ram_test_found_bad 816*4882a593Smuzhiyun subl #0x10000, %d0 817*4882a593Smuzhiyun cmpl #0xFFFFFFFF, %d0 818*4882a593Smuzhiyun bne ram_test_loop 819*4882a593Smuzhiyun bra ram_test_all_ok 820*4882a593Smuzhiyun 821*4882a593Smuzhiyunram_test_found_bad: 822*4882a593Smuzhiyun subl #4, %a0 823*4882a593Smuzhiyunram_test_all_ok: 824*4882a593Smuzhiyun movel %a0, PLX_MAILBOX_5 825*4882a593Smuzhiyun rts 826*4882a593Smuzhiyun#endif 827*4882a593Smuzhiyun 828*4882a593Smuzhiyun 829*4882a593Smuzhiyun/****************************** constants *****************************/ 830*4882a593Smuzhiyun 831*4882a593Smuzhiyunscc_reg_addr: 832*4882a593Smuzhiyun .long SCC1_REGS, SCC2_REGS, SCC3_REGS, SCC4_REGS 833*4882a593Smuzhiyunscc_base_addr: 834*4882a593Smuzhiyun .long SCC1_BASE, SCC2_BASE, SCC3_BASE, SCC4_BASE 835*4882a593Smuzhiyun 836*4882a593Smuzhiyuntx_first_bd: 837*4882a593Smuzhiyun .long DPRBASE 838*4882a593Smuzhiyun .long DPRBASE + (TX_BUFFERS + RX_BUFFERS) * 8 839*4882a593Smuzhiyun .long DPRBASE + (TX_BUFFERS + RX_BUFFERS) * 8 * 2 840*4882a593Smuzhiyun .long DPRBASE + (TX_BUFFERS + RX_BUFFERS) * 8 * 3 841*4882a593Smuzhiyun 842*4882a593Smuzhiyunrx_first_bd: 843*4882a593Smuzhiyun .long DPRBASE + TX_BUFFERS * 8 844*4882a593Smuzhiyun .long DPRBASE + TX_BUFFERS * 8 + (TX_BUFFERS + RX_BUFFERS) * 8 845*4882a593Smuzhiyun .long DPRBASE + TX_BUFFERS * 8 + (TX_BUFFERS + RX_BUFFERS) * 8 * 2 846*4882a593Smuzhiyun .long DPRBASE + TX_BUFFERS * 8 + (TX_BUFFERS + RX_BUFFERS) * 8 * 3 847*4882a593Smuzhiyun 848*4882a593Smuzhiyunfirst_buffer: 849*4882a593Smuzhiyun .long BUFFERS_ADDR 850*4882a593Smuzhiyun .long BUFFERS_ADDR + (TX_BUFFERS + RX_BUFFERS) * BUFFER_LENGTH 851*4882a593Smuzhiyun .long BUFFERS_ADDR + (TX_BUFFERS + RX_BUFFERS) * BUFFER_LENGTH * 2 852*4882a593Smuzhiyun .long BUFFERS_ADDR + (TX_BUFFERS + RX_BUFFERS) * BUFFER_LENGTH * 3 853*4882a593Smuzhiyun 854*4882a593Smuzhiyunbell_tx: 855*4882a593Smuzhiyun .long 1 << DOORBELL_FROM_CARD_TX_0, 1 << DOORBELL_FROM_CARD_TX_1 856*4882a593Smuzhiyun .long 1 << DOORBELL_FROM_CARD_TX_2, 1 << DOORBELL_FROM_CARD_TX_3 857*4882a593Smuzhiyun 858*4882a593Smuzhiyunbell_cable: 859*4882a593Smuzhiyun .long 1 << DOORBELL_FROM_CARD_CABLE_0, 1 << DOORBELL_FROM_CARD_CABLE_1 860*4882a593Smuzhiyun .long 1 << DOORBELL_FROM_CARD_CABLE_2, 1 << DOORBELL_FROM_CARD_CABLE_3 861*4882a593Smuzhiyun 862*4882a593Smuzhiyunpacket_full: 863*4882a593Smuzhiyun .long PACKET_FULL, PACKET_FULL + 1, PACKET_FULL + 2, PACKET_FULL + 3 864*4882a593Smuzhiyun 865*4882a593Smuzhiyunclocking_ext: 866*4882a593Smuzhiyun .long 0x0000002C, 0x00003E00, 0x002C0000, 0x3E000000 867*4882a593Smuzhiyunclocking_txfromrx: 868*4882a593Smuzhiyun .long 0x0000002D, 0x00003F00, 0x002D0000, 0x3F000000 869*4882a593Smuzhiyunclocking_mask: 870*4882a593Smuzhiyun .long 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 871*4882a593Smuzhiyundcd_mask: 872*4882a593Smuzhiyun .word 0x020, 0, 0x080, 0, 0x200, 0, 0x800 873*4882a593Smuzhiyun 874*4882a593Smuzhiyun .ascii "wanXL firmware\n" 875*4882a593Smuzhiyun .asciz "Copyright (C) 2003 Krzysztof Halasa <khc@pm.waw.pl>\n" 876*4882a593Smuzhiyun 877*4882a593Smuzhiyun 878*4882a593Smuzhiyun/****************************** variables *****************************/ 879*4882a593Smuzhiyun 880*4882a593Smuzhiyun .align 4 881*4882a593Smuzhiyunchannel_stats: .long 0 882*4882a593Smuzhiyun 883*4882a593Smuzhiyuntx_in: .long 0, 0, 0, 0 // transmitted 884*4882a593Smuzhiyuntx_out: .long 0, 0, 0, 0 // received from host for transmission 885*4882a593Smuzhiyuntx_count: .long 0, 0, 0, 0 // currently in transmit queue 886*4882a593Smuzhiyun 887*4882a593Smuzhiyunrx_in: .long 0, 0, 0, 0 // received from port 888*4882a593Smuzhiyunrx_out: .long 0 // transmitted to host 889*4882a593Smuzhiyunparity_bytes: .word 0, 0, 0, 0, 0, 0, 0 // only 4 words are used 890*4882a593Smuzhiyun 891*4882a593Smuzhiyuncsr_output: .word 0 892*4882a593Smuzhiyunold_csr_output: .word 0, 0, 0, 0, 0, 0, 0 893*4882a593Smuzhiyun .align 4 894*4882a593Smuzhiyunfirmware_end: // must be dword-aligned 895