1 /* SPDX-License-Identifier: GPL-2.0-only */
4 wanXL serial card driver for Linux
7 Copyright (C) 2003 Krzysztof Halasa <khc@pm.waw.pl>
14 0x000 - 0x050 TX#0 0x050 - 0x140 RX#0
15 0x140 - 0x190 TX#1 0x190 - 0x280 RX#1
16 0x280 - 0x2D0 TX#2 0x2D0 - 0x3C0 RX#2
17 0x3C0 - 0x410 TX#3 0x410 - 0x500 RX#3
20 000 5FF 1536 Bytes Dual-Port RAM User Data / BDs
21 600 6FF 256 Bytes Dual-Port RAM User Data / BDs
22 700 7FF 256 Bytes Dual-Port RAM User Data / BDs
23 C00 CBF 192 Bytes Dual-Port RAM Parameter RAM Page 1
24 D00 DBF 192 Bytes Dual-Port RAM Parameter RAM Page 2
25 E00 EBF 192 Bytes Dual-Port RAM Parameter RAM Page 3
26 F00 FBF 192 Bytes Dual-Port RAM Parameter RAM Page 4
28 local interrupts level
30 PIT timer, CPM (RX/TX complete) 4
31 PCI9060 DMA and PCI doorbells 3
35 #include <linux/hdlc.h>
36 #include <linux/hdlc/ioctl.h>
39 /* memory addresses and offsets */
41 MAX_RAM_SIZE = 16 * 1024 * 1024 // max RAM supported by hardware
43 PCI9060_VECTOR = 0x0000006C
45 ERROR_VECTOR = CPM_IRQ_BASE * 4
46 SCC1_VECTOR = (CPM_IRQ_BASE + 0x1E) * 4
47 SCC2_VECTOR = (CPM_IRQ_BASE + 0x1D) * 4
48 SCC3_VECTOR = (CPM_IRQ_BASE + 0x1C) * 4
49 SCC4_VECTOR = (CPM_IRQ_BASE + 0x1B) * 4
53 PITR_CONST = 0x100 + 16 // 1 Hz timer
57 VALUE_WINDOW = 0x40000000
58 ORDER_WINDOW = 0xC0000000
66 STATUS_CABLE_LL = 0x2000
67 STATUS_CABLE_DTR = 0x1000
71 SCC1_BASE = DPRBASE + 0xC00
72 MISC_BASE = DPRBASE + 0xCB0
73 SCC2_BASE = DPRBASE + 0xD00
74 SCC3_BASE = DPRBASE + 0xE00
75 SCC4_BASE = DPRBASE + 0xF00
77 // offset from SCCx_BASE
78 // SCC_xBASE contain offsets from DPRBASE and must be divisible by 8
79 SCC_RBASE = 0 // 16-bit RxBD base address
80 SCC_TBASE = 2 // 16-bit TxBD base address
81 SCC_RFCR = 4 // 8-bit Rx function code
82 SCC_TFCR = 5 // 8-bit Tx function code
83 SCC_MRBLR = 6 // 16-bit maximum Rx buffer length
84 SCC_C_MASK = 0x34 // 32-bit CRC constant
85 SCC_C_PRES = 0x38 // 32-bit CRC preset
86 SCC_MFLR = 0x46 // 16-bit max Rx frame length (without flags)
88 REGBASE = DPRBASE + 0x1000
89 PICR = REGBASE + 0x026 // 16-bit periodic irq control
90 PITR = REGBASE + 0x02A // 16-bit periodic irq timing
91 OR1 = REGBASE + 0x064 // 32-bit RAM bank #1 options
92 CICR = REGBASE + 0x540 // 32(24)-bit CP interrupt config
93 CIMR = REGBASE + 0x548 // 32-bit CP interrupt mask
94 CISR = REGBASE + 0x54C // 32-bit CP interrupts in-service
95 PADIR = REGBASE + 0x550 // 16-bit PortA data direction bitmap
96 PAPAR = REGBASE + 0x552 // 16-bit PortA pin assignment bitmap
97 PAODR = REGBASE + 0x554 // 16-bit PortA open drain bitmap
98 PADAT = REGBASE + 0x556 // 16-bit PortA data register
100 PCDIR = REGBASE + 0x560 // 16-bit PortC data direction bitmap
101 PCPAR = REGBASE + 0x562 // 16-bit PortC pin assignment bitmap
102 PCSO = REGBASE + 0x564 // 16-bit PortC special options
103 PCDAT = REGBASE + 0x566 // 16-bit PortC data register
104 PCINT = REGBASE + 0x568 // 16-bit PortC interrupt control
105 CR = REGBASE + 0x5C0 // 16-bit Command register
107 SCC1_REGS = REGBASE + 0x600
108 SCC2_REGS = REGBASE + 0x620
109 SCC3_REGS = REGBASE + 0x640
110 SCC4_REGS = REGBASE + 0x660
111 SICR = REGBASE + 0x6EC // 32-bit SI clock route
113 // offset from SCCx_REGS
114 SCC_GSMR_L = 0x00 // 32 bits
115 SCC_GSMR_H = 0x04 // 32 bits
116 SCC_PSMR = 0x08 // 16 bits
117 SCC_TODR = 0x0C // 16 bits
118 SCC_DSR = 0x0E // 16 bits
119 SCC_SCCE = 0x10 // 16 bits
120 SCC_SCCM = 0x14 // 16 bits
121 SCC_SCCS = 0x17 // 8 bits
123 #if QUICC_MEMCPY_USES_PLX
124 .macro memcpy_from_pci src, dest, len // len must be < 8 MB
126 andl #0xFFFFFFFC, \len // always copy n * 4 bytes
127 movel \src, PLX_DMA_0_PCI
128 movel \dest, PLX_DMA_0_LOCAL
129 movel \len, PLX_DMA_0_LENGTH
130 movel #0x0103, PLX_DMA_CMD_STS // start channel 0 transfer
131 bsr memcpy_from_pci_run
134 .macro memcpy_to_pci src, dest, len
136 andl #0xFFFFFFFC, \len // always copy n * 4 bytes
137 movel \src, PLX_DMA_1_LOCAL
138 movel \dest, PLX_DMA_1_PCI
139 movel \len, PLX_DMA_1_LENGTH
140 movel #0x0301, PLX_DMA_CMD_STS // start channel 1 transfer
141 bsr memcpy_to_pci_run
146 .macro memcpy src, dest, len // len must be < 65536 bytes
147 movel %d7, -(%sp) // src and dest must be < 256 MB
148 movel \len, %d7 // bits 0 and 1
151 beq 99f // only 0 - 3 bytes
152 subl #1, \len // for dbf
153 98: movel (\src)+, (\dest)+
158 movew (\src)+, (\dest)+
161 moveb (\src)+, (\dest)+
166 .macro memcpy_from_pci src, dest, len
167 addl #VALUE_WINDOW, \src
168 memcpy \src, \dest, \len
171 .macro memcpy_to_pci src, dest, len
172 addl #VALUE_WINDOW, \dest
173 memcpy \src, \dest, \len
178 .macro wait_for_command
186 /****************************** card initialization *******************/
192 ch_status_addr: .long 0, 0, 0, 0
193 rx_descs_addr: .long 0
198 andl #0xF00007FF, %d0 // mask AMxx bits
199 orl #0xFFFF800 & ~(MAX_RAM_SIZE - 1), %d0 // update RAM bank size
203 addl #VALUE_WINDOW, rx_descs_addr // PCI addresses of shared data
204 clrl %d0 // D0 = 4 * port
205 init_1: tstl ch_status_addr(%d0)
207 addl #VALUE_WINDOW, ch_status_addr(%d0)
212 movel #pci9060_interrupt, PCI9060_VECTOR
213 movel #error_interrupt, ERROR_VECTOR
214 movel #port_interrupt_1, SCC1_VECTOR
215 movel #port_interrupt_2, SCC2_VECTOR
216 movel #port_interrupt_3, SCC3_VECTOR
217 movel #port_interrupt_4, SCC4_VECTOR
218 movel #timer_interrupt, TIMER_IRQ * 4
220 movel #0x78000000, CIMR // only SCCx IRQs from CPM
221 movew #(TIMER_IRQ_LEVEL << 8) + TIMER_IRQ, PICR // interrupt from PIT
222 movew #PITR_CONST, PITR
224 // SCC1=SCCa SCC2=SCCb SCC3=SCCc SCC4=SCCd prio=4 HP=-1 IRQ=64-79
225 movel #0xD41F40 + (CPM_IRQ_LEVEL << 13), CICR
226 movel #0x543, PLX_DMA_0_MODE // 32-bit, Ready, Burst, IRQ
227 movel #0x543, PLX_DMA_1_MODE
228 movel #0x0, PLX_DMA_0_DESC // from PCI to local
229 movel #0x8, PLX_DMA_1_DESC // from local to PCI
230 movel #0x101, PLX_DMA_CMD_STS // enable both DMA channels
231 // enable local IRQ, DMA, doorbells and PCI IRQ
232 orl #0x000F0300, PLX_INTERRUPT_CS
237 movel #1, PLX_MAILBOX_5 // non-zero value = init complete
241 movew #0xFFFF, PAPAR // all pins are clocks/data
242 clrw PADIR // first function
243 clrw PCSO // CD and CTS always active
246 /****************************** main loop *****************************/
248 main: movel channel_stats, %d7 // D7 = doorbell + irq status
253 // nothing to do - wait for next event
254 stop #0x2200 // supervisor + IRQ level 2
255 movew #0x2700, %sr // disable IRQs again
258 main_1: clrl %d0 // D0 = 4 * port
259 clrl %d6 // D6 = doorbell to host value
261 main_l: btstl #DOORBELL_TO_CARD_CLOSE_0, %d7
263 bclrl #DOORBELL_TO_CARD_OPEN_0, %d7 // in case both bits are set
266 btstl #DOORBELL_TO_CARD_OPEN_0, %d7
270 btstl #DOORBELL_TO_CARD_TX_0, %d7
274 btstl #TASK_SCC_0, %d7
280 lsrl #1, %d7 // port status for next port
281 addl #4, %d0 // D0 = 4 * next port
284 movel %d6, PLX_DOORBELL_FROM_CARD // signal the host
288 /****************************** open port *****************************/
290 open_port: // D0 = 4 * port, D6 = doorbell to host
291 movel ch_status_addr(%d0), %a0 // A0 = port status address
292 tstl STATUS_OPEN(%a0)
293 bne open_port_ret // port already open
294 movel #1, STATUS_OPEN(%a0) // confirm the port is open
301 movel SICR, %d1 // D1 = clock settings in SICR
302 andl clocking_mask(%d0), %d1
303 cmpl #CLOCK_TXFROMRX, STATUS_CLOCKING(%a0)
304 bne open_port_clock_ext
305 orl clocking_txfromrx(%d0), %d1
306 bra open_port_set_clock
309 orl clocking_ext(%d0), %d1
311 movel %d1, SICR // update clock settings in SICR
313 orw #STATUS_CABLE_DTR, csr_output(%d0) // DTR on
314 bsr check_csr // call with disabled timer interrupt
316 // Setup TX descriptors
317 movel first_buffer(%d0), %d1 // D1 = starting buffer address
318 movel tx_first_bd(%d0), %a1 // A1 = starting TX BD address
319 movel #TX_BUFFERS - 2, %d2 // D2 = TX_BUFFERS - 1 counter
320 movel #0x18000000, %d3 // D3 = initial TX BD flags: Int + Last
321 cmpl #PARITY_NONE, STATUS_PARITY(%a0)
322 beq open_port_tx_loop
323 bsetl #26, %d3 // TX BD flag: Transmit CRC
325 movel %d3, (%a1)+ // TX flags + length
326 movel %d1, (%a1)+ // buffer address
327 addl #BUFFER_LENGTH, %d1
328 dbfw %d2, open_port_tx_loop
330 bsetl #29, %d3 // TX BD flag: Wrap (last BD)
331 movel %d3, (%a1)+ // Final TX flags + length
332 movel %d1, (%a1)+ // buffer address
334 // Setup RX descriptors // A1 = starting RX BD address
335 movel #RX_BUFFERS - 2, %d2 // D2 = RX_BUFFERS - 1 counter
337 movel #0x90000000, (%a1)+ // RX flags + length
338 movel %d1, (%a1)+ // buffer address
339 addl #BUFFER_LENGTH, %d1
340 dbfw %d2, open_port_rx_loop
342 movel #0xB0000000, (%a1)+ // Final RX flags + length
343 movel %d1, (%a1)+ // buffer address
345 // Setup port parameters
346 movel scc_base_addr(%d0), %a1 // A1 = SCC_BASE address
347 movel scc_reg_addr(%d0), %a2 // A2 = SCC_REGS address
349 movel #0xFFFF, SCC_SCCE(%a2) // clear status bits
350 movel #0x0000, SCC_SCCM(%a2) // interrupt mask
352 movel tx_first_bd(%d0), %d1
353 movew %d1, SCC_TBASE(%a1) // D1 = offset of first TxBD
354 addl #TX_BUFFERS * 8, %d1
355 movew %d1, SCC_RBASE(%a1) // D1 = offset of first RxBD
356 moveb #0x8, SCC_RFCR(%a1) // Intel mode, 1000
357 moveb #0x8, SCC_TFCR(%a1)
360 cmpl #PARITY_CRC16_PR1_CCITT, STATUS_PARITY(%a0)
361 bne open_port_parity_1
362 clrw SCC_PSMR(%a2) // CRC16-CCITT
363 movel #0xF0B8, SCC_C_MASK(%a1)
364 movel #0xFFFF, SCC_C_PRES(%a1)
365 movew #HDLC_MAX_MRU + 2, SCC_MFLR(%a1) // 2 bytes for CRC
366 movew #2, parity_bytes(%d0)
370 cmpl #PARITY_CRC32_PR1_CCITT, STATUS_PARITY(%a0)
371 bne open_port_parity_2
372 movew #0x0800, SCC_PSMR(%a2) // CRC32-CCITT
373 movel #0xDEBB20E3, SCC_C_MASK(%a1)
374 movel #0xFFFFFFFF, SCC_C_PRES(%a1)
375 movew #HDLC_MAX_MRU + 4, SCC_MFLR(%a1) // 4 bytes for CRC
376 movew #4, parity_bytes(%d0)
380 cmpl #PARITY_CRC16_PR0_CCITT, STATUS_PARITY(%a0)
381 bne open_port_parity_3
382 clrw SCC_PSMR(%a2) // CRC16-CCITT preset 0
383 movel #0xF0B8, SCC_C_MASK(%a1)
385 movew #HDLC_MAX_MRU + 2, SCC_MFLR(%a1) // 2 bytes for CRC
386 movew #2, parity_bytes(%d0)
390 cmpl #PARITY_CRC32_PR0_CCITT, STATUS_PARITY(%a0)
391 bne open_port_parity_4
392 movew #0x0800, SCC_PSMR(%a2) // CRC32-CCITT preset 0
393 movel #0xDEBB20E3, SCC_C_MASK(%a1)
395 movew #HDLC_MAX_MRU + 4, SCC_MFLR(%a1) // 4 bytes for CRC
396 movew #4, parity_bytes(%d0)
400 clrw SCC_PSMR(%a2) // no parity
401 movel #0xF0B8, SCC_C_MASK(%a1)
402 movel #0xFFFF, SCC_C_PRES(%a1)
403 movew #HDLC_MAX_MRU, SCC_MFLR(%a1) // 0 bytes for CRC
404 clrw parity_bytes(%d0)
407 movel #0x00000003, SCC_GSMR_H(%a2) // RTSM
408 cmpl #ENCODING_NRZI, STATUS_ENCODING(%a0)
410 movel #0x10040900, SCC_GSMR_L(%a2) // NRZI: TCI Tend RECN+TENC=1
414 movel #0x10040000, SCC_GSMR_L(%a2) // NRZ: TCI Tend RECN+TENC=0
416 movew #BUFFER_LENGTH, SCC_MRBLR(%a1)
418 lsll #4, %d1 // D1 bits 7 and 6 = port
420 movew %d1, CR // Init SCC RX and TX params
424 movew #0x001F, SCC_SCCM(%a2) // TXE RXF BSY TXB RXB interrupts
425 orl #0x00000030, SCC_GSMR_L(%a2) // enable SCC
430 /****************************** close port ****************************/
432 close_port: // D0 = 4 * port, D6 = doorbell to host
433 movel scc_reg_addr(%d0), %a0 // A0 = SCC_REGS address
434 clrw SCC_SCCM(%a0) // no SCC interrupts
435 andl #0xFFFFFFCF, SCC_GSMR_L(%a0) // Disable ENT and ENR
437 andw #~STATUS_CABLE_DTR, csr_output(%d0) // DTR off
438 bsr check_csr // call with disabled timer interrupt
440 movel ch_status_addr(%d0), %d1
441 clrl STATUS_OPEN(%d1) // confirm the port is closed
445 /****************************** transmit packet ***********************/
446 // queue packets for transmission
447 tx: // D0 = 4 * port, D6 = doorbell to host
448 cmpl #TX_BUFFERS, tx_count(%d0)
449 beq tx_ret // all DB's = descs in use
451 movel tx_out(%d0), %d1
452 movel %d1, %d2 // D1 = D2 = tx_out BD# = desc#
453 mulul #DESC_LENGTH, %d2 // D2 = TX desc offset
454 addl ch_status_addr(%d0), %d2
455 addl #STATUS_TX_DESCS, %d2 // D2 = TX desc address
456 cmpl #PACKET_FULL, (%d2) // desc status
460 movel 4(%d2), %a0 // PCI address
461 lsll #3, %d1 // BD is 8-bytes long
462 addl tx_first_bd(%d0), %d1 // D1 = current tx_out BD addr
464 movel 4(%d1), %a1 // A1 = dest address
465 movel 8(%d2), %d2 // D2 = length
466 movew %d2, 2(%d1) // length into BD
467 memcpy_from_pci %a0, %a1, %d2
468 bsetl #31, (%d1) // CP go ahead
470 // update tx_out and tx_count
471 movel tx_out(%d0), %d1
473 cmpl #TX_BUFFERS, %d1
476 tx_1: movel %d1, tx_out(%d0)
478 addl #1, tx_count(%d0)
484 /****************************** packet received ***********************/
486 // Service receive buffers // D0 = 4 * port, D6 = doorbell to host
487 rx: movel rx_in(%d0), %d1 // D1 = rx_in BD#
488 lsll #3, %d1 // BD is 8-bytes long
489 addl rx_first_bd(%d0), %d1 // D1 = current rx_in BD address
490 movew (%d1), %d2 // D2 = RX BD flags
492 bne rx_ret // BD still empty
497 tstw parity_bytes(%d0)
499 bclrl #2, %d2 // do not test for CRC errors
501 andw #0x0CBC, %d2 // mask status bits
502 cmpw #0x0C00, %d2 // correct frame
506 subw parity_bytes(%d0), %d3 // D3 = packet length
507 cmpw #HDLC_MAX_MRU, %d3
512 mulul #DESC_LENGTH, %d2
513 addl rx_descs_addr, %d2 // D2 = RX desc address
514 cmpl #PACKET_EMPTY, (%d2) // desc stat
518 movel 4(%d1), %a0 // A0 = source address
522 memcpy_to_pci %a0, %a1, %d3
524 movel packet_full(%d0), (%d2) // update desc stat
526 // update D6 and rx_out
527 bsetl #DOORBELL_FROM_CARD_RX, %d6 // signal host that RX completed
530 cmpl #RX_QUEUE_LENGTH, %d2
533 rx_1: movel %d2, rx_out
536 andw #0xF000, (%d1) // clear CM and error bits
537 bsetl #31, (%d1) // free BD
539 movel rx_in(%d0), %d1
541 cmpl #RX_BUFFERS, %d1
544 rx_2: movel %d1, rx_in(%d0)
548 movel ch_status_addr(%d0), %d2
549 addl #1, STATUS_RX_OVERRUNS(%d2)
553 movel ch_status_addr(%d0), %d2
554 addl #1, STATUS_RX_FRAME_ERRORS(%d2)
560 /****************************** packet transmitted ********************/
562 // Service transmit buffers // D0 = 4 * port, D6 = doorbell to host
563 tx_end: tstl tx_count(%d0)
564 beq tx_end_ret // TX buffers already empty
566 movel tx_in(%d0), %d1
567 movel %d1, %d2 // D1 = D2 = tx_in BD# = desc#
568 lsll #3, %d1 // BD is 8-bytes long
569 addl tx_first_bd(%d0), %d1 // D1 = current tx_in BD address
570 movew (%d1), %d3 // D3 = TX BD flags
572 bne tx_end_ret // BD still being transmitted
574 // update D6, tx_in and tx_count
575 orl bell_tx(%d0), %d6 // signal host that TX desc freed
576 subl #1, tx_count(%d0)
577 movel tx_in(%d0), %d1
579 cmpl #TX_BUFFERS, %d1
583 movel %d1, tx_in(%d0)
585 // free host's descriptor
586 mulul #DESC_LENGTH, %d2 // D2 = TX desc offset
587 addl ch_status_addr(%d0), %d2
588 addl #STATUS_TX_DESCS, %d2 // D2 = TX desc address
591 movel #PACKET_SENT, (%d2)
595 movel #PACKET_UNDERRUN, (%d2)
601 /****************************** PLX PCI9060 DMA memcpy ****************/
603 #if QUICC_MEMCPY_USES_PLX
604 // called with interrupts disabled
609 movel PLX_DMA_CMD_STS, %d0 // do not btst PLX register directly
610 btstl #4, %d0 // transfer done?
612 stop #0x2200 // enable PCI9060 interrupts
613 movew #0x2700, %sr // disable interrupts again
620 movel PLX_DMA_CMD_STS, %d0 // do not btst PLX register directly
621 btstl #12, %d0 // transfer done?
623 stop #0x2200 // enable PCI9060 interrupts
624 movew #0x2700, %sr // disable interrupts again
638 /****************************** PLX PCI9060 interrupt *****************/
643 movel PLX_DOORBELL_TO_CARD, %d0
644 movel %d0, PLX_DOORBELL_TO_CARD // confirm all requests
645 orl %d0, channel_stats
647 movel #0x0909, PLX_DMA_CMD_STS // clear DMA ch #0 and #1 interrupts
652 /****************************** SCC interrupts ************************/
655 orl #0, SCC1_REGS + SCC_SCCE; // confirm SCC events
656 orl #1 << TASK_SCC_0, channel_stats
657 movel #0x40000000, CISR
661 orl #0, SCC2_REGS + SCC_SCCE; // confirm SCC events
662 orl #1 << TASK_SCC_1, channel_stats
663 movel #0x20000000, CISR
667 orl #0, SCC3_REGS + SCC_SCCE; // confirm SCC events
668 orl #1 << TASK_SCC_2, channel_stats
669 movel #0x10000000, CISR
673 orl #0, SCC4_REGS + SCC_SCCE; // confirm SCC events
674 orl #1 << TASK_SCC_3, channel_stats
675 movel #0x08000000, CISR
682 /****************************** cable and PM routine ******************/
683 // modified registers: none
691 clrl %d0 // D0 = 4 * port
692 movel #CSRA, %a0 // A0 = CSR address
695 movew (%a0), %d1 // D1 = CSR input bits
696 andl #0xE7, %d1 // PM and cable sense bits (no DCE bit)
697 cmpw #STATUS_CABLE_V35 * (1 + 1 << STATUS_CABLE_PM_SHIFT), %d1
703 cmpw #STATUS_CABLE_X21 * (1 + 1 << STATUS_CABLE_PM_SHIFT), %d1
709 cmpw #STATUS_CABLE_V24 * (1 + 1 << STATUS_CABLE_PM_SHIFT), %d1
715 cmpw #STATUS_CABLE_EIA530 * (1 + 1 << STATUS_CABLE_PM_SHIFT), %d1
716 bne check_csr_disable
721 movew #0x0008, %d1 // D1 = disable everything
722 movew #0x80E7, %d2 // D2 = input mask: ignore DSR
725 check_csr_valid: // D1 = mode and IRQ bits
726 movew csr_output(%d0), %d2
727 andw #0x3000, %d2 // D2 = requested LL and DTR bits
728 orw %d2, %d1 // D1 = all requested output bits
729 movew #0x80FF, %d2 // D2 = input mask: include DSR
732 cmpw old_csr_output(%d0), %d1
734 movew %d1, old_csr_output(%d0)
735 movew %d1, (%a0) // Write CSR output bits
739 andw dcd_mask(%d0), %d1
740 beq check_csr_dcd_on // DCD and CTS signals are negated
741 movew (%a0), %d1 // D1 = CSR input bits
742 andw #~STATUS_CABLE_DCD, %d1 // DCD off
743 bra check_csr_previous
746 movew (%a0), %d1 // D1 = CSR input bits
747 orw #STATUS_CABLE_DCD, %d1 // DCD on
749 andw %d2, %d1 // input mask
750 movel ch_status_addr(%d0), %a1
751 cmpl STATUS_CABLE(%a1), %d1 // check for change
753 movel %d1, STATUS_CABLE(%a1) // update status
754 movel bell_cable(%d0), PLX_DOORBELL_FROM_CARD // signal the host
757 addl #2, %a0 // next CSR register
758 addl #4, %d0 // D0 = 4 * next port
770 /****************************** timer interrupt ***********************/
777 /****************************** RAM sizing and test *******************/
780 movel #0x12345678, %d1 // D1 = test value
781 movel %d1, (128 * 1024 - 4)
782 movel #128 * 1024, %d0 // D0 = RAM size tested
784 cmpl #MAX_RAM_SIZE, %d0
785 beq ram_test_size_found
787 addl #128 * 1024 - 4, %a0
789 beq ram_test_size_check
795 eorl #0xFFFFFFFF, %d1
796 movel %d1, (128 * 1024 - 4)
798 bne ram_test_next_size
800 ram_test_size_found: // D0 = RAM size
801 movel %d0, %a0 // A0 = fill ptr
802 subl #firmware_end + 4, %d0
804 movel %d0, %d1 // D1 = DBf counter
807 dbfw %d1, ram_test_fill
809 cmpl #0xFFFFFFFF, %d1
812 ram_test_loop: // D0 = DBf counter
814 dbnew %d0, ram_test_loop
815 bne ram_test_found_bad
817 cmpl #0xFFFFFFFF, %d0
824 movel %a0, PLX_MAILBOX_5
829 /****************************** constants *****************************/
832 .long SCC1_REGS, SCC2_REGS, SCC3_REGS, SCC4_REGS
834 .long SCC1_BASE, SCC2_BASE, SCC3_BASE, SCC4_BASE
838 .long DPRBASE + (TX_BUFFERS + RX_BUFFERS) * 8
839 .long DPRBASE + (TX_BUFFERS + RX_BUFFERS) * 8 * 2
840 .long DPRBASE + (TX_BUFFERS + RX_BUFFERS) * 8 * 3
843 .long DPRBASE + TX_BUFFERS * 8
844 .long DPRBASE + TX_BUFFERS * 8 + (TX_BUFFERS + RX_BUFFERS) * 8
845 .long DPRBASE + TX_BUFFERS * 8 + (TX_BUFFERS + RX_BUFFERS) * 8 * 2
846 .long DPRBASE + TX_BUFFERS * 8 + (TX_BUFFERS + RX_BUFFERS) * 8 * 3
850 .long BUFFERS_ADDR + (TX_BUFFERS + RX_BUFFERS) * BUFFER_LENGTH
851 .long BUFFERS_ADDR + (TX_BUFFERS + RX_BUFFERS) * BUFFER_LENGTH * 2
852 .long BUFFERS_ADDR + (TX_BUFFERS + RX_BUFFERS) * BUFFER_LENGTH * 3
855 .long 1 << DOORBELL_FROM_CARD_TX_0, 1 << DOORBELL_FROM_CARD_TX_1
856 .long 1 << DOORBELL_FROM_CARD_TX_2, 1 << DOORBELL_FROM_CARD_TX_3
859 .long 1 << DOORBELL_FROM_CARD_CABLE_0, 1 << DOORBELL_FROM_CARD_CABLE_1
860 .long 1 << DOORBELL_FROM_CARD_CABLE_2, 1 << DOORBELL_FROM_CARD_CABLE_3
863 .long PACKET_FULL, PACKET_FULL + 1, PACKET_FULL + 2, PACKET_FULL + 3
866 .long 0x0000002C, 0x00003E00, 0x002C0000, 0x3E000000
868 .long 0x0000002D, 0x00003F00, 0x002D0000, 0x3F000000
870 .long 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000
872 .word 0x020, 0, 0x080, 0, 0x200, 0, 0x800
874 .ascii "wanXL firmware\n"
875 .asciz "Copyright (C) 2003 Krzysztof Halasa <khc@pm.waw.pl>\n"
878 /****************************** variables *****************************/
881 channel_stats: .long 0
883 tx_in: .long 0, 0, 0, 0 // transmitted
884 tx_out: .long 0, 0, 0, 0 // received from host for transmission
885 tx_count: .long 0, 0, 0, 0 // currently in transmit queue
887 rx_in: .long 0, 0, 0, 0 // received from port
888 rx_out: .long 0 // transmitted to host
889 parity_bytes: .word 0, 0, 0, 0, 0, 0, 0 // only 4 words are used
892 old_csr_output: .word 0, 0, 0, 0, 0, 0, 0
894 firmware_end: // must be dword-aligned