1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
2 | .psize 0 |
3 | /* |
4 | wanXL serial card driver for Linux |
5 | card firmware part |
6 | |
7 | Copyright (C) 2003 Krzysztof Halasa <khc@pm.waw.pl> |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | DPRAM BDs: |
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 |
18 | |
19 | |
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 |
27 | |
28 | local interrupts level |
29 | NMI 7 |
30 | PIT timer, CPM (RX/TX complete) 4 |
31 | PCI9060 DMA and PCI doorbells 3 |
32 | Cable - not used 1 |
33 | */ |
34 | |
35 | #include <linux/hdlc.h> |
36 | #include <linux/hdlc/ioctl.h> |
37 | #include "wanxl.h" |
38 | |
39 | /* memory addresses and offsets */ |
40 | |
41 | MAX_RAM_SIZE = 16 * 1024 * 1024 // max RAM supported by hardware |
42 | |
43 | PCI9060_VECTOR = 0x0000006C |
44 | CPM_IRQ_BASE = 0x40 |
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 |
50 | CPM_IRQ_LEVEL = 4 |
51 | TIMER_IRQ = 128 |
52 | TIMER_IRQ_LEVEL = 4 |
53 | PITR_CONST = 0x100 + 16 // 1 Hz timer |
54 | |
55 | MBAR = 0x0003FF00 |
56 | |
57 | VALUE_WINDOW = 0x40000000 |
58 | ORDER_WINDOW = 0xC0000000 |
59 | |
60 | PLX = 0xFFF90000 |
61 | |
62 | CSRA = 0xFFFB0000 |
63 | CSRB = 0xFFFB0002 |
64 | CSRC = 0xFFFB0004 |
65 | CSRD = 0xFFFB0006 |
66 | STATUS_CABLE_LL = 0x2000 |
67 | STATUS_CABLE_DTR = 0x1000 |
68 | |
69 | DPRBASE = 0xFFFC0000 |
70 | |
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 |
76 | |
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) |
87 | |
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 |
99 | |
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 |
106 | |
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 |
112 | |
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 |
122 | |
123 | #if QUICC_MEMCPY_USES_PLX |
124 | .macro memcpy_from_pci src, dest, len // len must be < 8 MB |
125 | addl #3, \len |
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 |
132 | .endm |
133 | |
134 | .macro memcpy_to_pci src, dest, len |
135 | addl #3, \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 |
142 | .endm |
143 | |
144 | #else |
145 | |
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 |
149 | lsrl #2, \len |
150 | andl \len, \len |
151 | beq 99f // only 0 - 3 bytes |
152 | subl #1, \len // for dbf |
153 | 98: movel (\src)+, (\dest)+ |
154 | dbfw \len, 98b |
155 | 99: movel %d7, \len |
156 | btstl #1, \len |
157 | beq 99f |
158 | movew (\src)+, (\dest)+ |
159 | 99: btstl #0, \len |
160 | beq 99f |
161 | moveb (\src)+, (\dest)+ |
162 | 99: |
163 | movel (%sp)+, %d7 |
164 | .endm |
165 | |
166 | .macro memcpy_from_pci src, dest, len |
167 | addl #VALUE_WINDOW, \src |
168 | memcpy \src, \dest, \len |
169 | .endm |
170 | |
171 | .macro memcpy_to_pci src, dest, len |
172 | addl #VALUE_WINDOW, \dest |
173 | memcpy \src, \dest, \len |
174 | .endm |
175 | #endif |
176 | |
177 | |
178 | .macro wait_for_command |
179 | 99: btstl #0, CR |
180 | bne 99b |
181 | .endm |
182 | |
183 | |
184 | |
185 | |
186 | /****************************** card initialization *******************/ |
187 | .text |
188 | .global _start |
189 | _start: bra init |
190 | |
191 | .org _start + 4 |
192 | ch_status_addr: .long 0, 0, 0, 0 |
193 | rx_descs_addr: .long 0 |
194 | |
195 | init: |
196 | #if DETECT_RAM |
197 | movel OR1, %d0 |
198 | andl #0xF00007FF, %d0 // mask AMxx bits |
199 | orl #0xFFFF800 & ~(MAX_RAM_SIZE - 1), %d0 // update RAM bank size |
200 | movel %d0, OR1 |
201 | #endif |
202 | |
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) |
206 | beq init_2 |
207 | addl #VALUE_WINDOW, ch_status_addr(%d0) |
208 | init_2: addl #4, %d0 |
209 | cmpl #4 * 4, %d0 |
210 | bne init_1 |
211 | |
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 |
219 | |
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 |
223 | |
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 |
233 | |
234 | #if DETECT_RAM |
235 | bsr ram_test |
236 | #else |
237 | movel #1, PLX_MAILBOX_5 // non-zero value = init complete |
238 | #endif |
239 | bsr check_csr |
240 | |
241 | movew #0xFFFF, PAPAR // all pins are clocks/data |
242 | clrw PADIR // first function |
243 | clrw PCSO // CD and CTS always active |
244 | |
245 | |
246 | /****************************** main loop *****************************/ |
247 | |
248 | main: movel channel_stats, %d7 // D7 = doorbell + irq status |
249 | clrl channel_stats |
250 | |
251 | tstl %d7 |
252 | bne main_1 |
253 | // nothing to do - wait for next event |
254 | stop #0x2200 // supervisor + IRQ level 2 |
255 | movew #0x2700, %sr // disable IRQs again |
256 | bra main |
257 | |
258 | main_1: clrl %d0 // D0 = 4 * port |
259 | clrl %d6 // D6 = doorbell to host value |
260 | |
261 | main_l: btstl #DOORBELL_TO_CARD_CLOSE_0, %d7 |
262 | beq main_op |
263 | bclrl #DOORBELL_TO_CARD_OPEN_0, %d7 // in case both bits are set |
264 | bsr close_port |
265 | main_op: |
266 | btstl #DOORBELL_TO_CARD_OPEN_0, %d7 |
267 | beq main_cl |
268 | bsr open_port |
269 | main_cl: |
270 | btstl #DOORBELL_TO_CARD_TX_0, %d7 |
271 | beq main_txend |
272 | bsr tx |
273 | main_txend: |
274 | btstl #TASK_SCC_0, %d7 |
275 | beq main_next |
276 | bsr tx_end |
277 | bsr rx |
278 | |
279 | main_next: |
280 | lsrl #1, %d7 // port status for next port |
281 | addl #4, %d0 // D0 = 4 * next port |
282 | cmpl #4 * 4, %d0 |
283 | bne main_l |
284 | movel %d6, PLX_DOORBELL_FROM_CARD // signal the host |
285 | bra main |
286 | |
287 | |
288 | /****************************** open port *****************************/ |
289 | |
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 |
295 | // setup BDs |
296 | clrl tx_in(%d0) |
297 | clrl tx_out(%d0) |
298 | clrl tx_count(%d0) |
299 | clrl rx_in(%d0) |
300 | |
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 |
307 | |
308 | open_port_clock_ext: |
309 | orl clocking_ext(%d0), %d1 |
310 | open_port_set_clock: |
311 | movel %d1, SICR // update clock settings in SICR |
312 | |
313 | orw #STATUS_CABLE_DTR, csr_output(%d0) // DTR on |
314 | bsr check_csr // call with disabled timer interrupt |
315 | |
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 |
324 | open_port_tx_loop: |
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 |
329 | |
330 | bsetl #29, %d3 // TX BD flag: Wrap (last BD) |
331 | movel %d3, (%a1)+ // Final TX flags + length |
332 | movel %d1, (%a1)+ // buffer address |
333 | |
334 | // Setup RX descriptors // A1 = starting RX BD address |
335 | movel #RX_BUFFERS - 2, %d2 // D2 = RX_BUFFERS - 1 counter |
336 | open_port_rx_loop: |
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 |
341 | |
342 | movel #0xB0000000, (%a1)+ // Final RX flags + length |
343 | movel %d1, (%a1)+ // buffer address |
344 | |
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 |
348 | |
349 | movel #0xFFFF, SCC_SCCE(%a2) // clear status bits |
350 | movel #0x0000, SCC_SCCM(%a2) // interrupt mask |
351 | |
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) |
358 | |
359 | // Parity settings |
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) |
367 | bra open_port_2 |
368 | |
369 | open_port_parity_1: |
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) |
377 | bra open_port_2 |
378 | |
379 | open_port_parity_2: |
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) |
384 | clrl SCC_C_PRES(%a1) |
385 | movew #HDLC_MAX_MRU + 2, SCC_MFLR(%a1) // 2 bytes for CRC |
386 | movew #2, parity_bytes(%d0) |
387 | bra open_port_2 |
388 | |
389 | open_port_parity_3: |
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) |
394 | clrl SCC_C_PRES(%a1) |
395 | movew #HDLC_MAX_MRU + 4, SCC_MFLR(%a1) // 4 bytes for CRC |
396 | movew #4, parity_bytes(%d0) |
397 | bra open_port_2 |
398 | |
399 | open_port_parity_4: |
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) |
405 | |
406 | open_port_2: |
407 | movel #0x00000003, SCC_GSMR_H(%a2) // RTSM |
408 | cmpl #ENCODING_NRZI, STATUS_ENCODING(%a0) |
409 | bne open_port_nrz |
410 | movel #0x10040900, SCC_GSMR_L(%a2) // NRZI: TCI Tend RECN+TENC=1 |
411 | bra open_port_3 |
412 | |
413 | open_port_nrz: |
414 | movel #0x10040000, SCC_GSMR_L(%a2) // NRZ: TCI Tend RECN+TENC=0 |
415 | open_port_3: |
416 | movew #BUFFER_LENGTH, SCC_MRBLR(%a1) |
417 | movel %d0, %d1 |
418 | lsll #4, %d1 // D1 bits 7 and 6 = port |
419 | orl #1, %d1 |
420 | movew %d1, CR // Init SCC RX and TX params |
421 | wait_for_command |
422 | |
423 | // TCI Tend ENR ENT |
424 | movew #0x001F, SCC_SCCM(%a2) // TXE RXF BSY TXB RXB interrupts |
425 | orl #0x00000030, SCC_GSMR_L(%a2) // enable SCC |
426 | open_port_ret: |
427 | rts |
428 | |
429 | |
430 | /****************************** close port ****************************/ |
431 | |
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 |
436 | |
437 | andw #~STATUS_CABLE_DTR, csr_output(%d0) // DTR off |
438 | bsr check_csr // call with disabled timer interrupt |
439 | |
440 | movel ch_status_addr(%d0), %d1 |
441 | clrl STATUS_OPEN(%d1) // confirm the port is closed |
442 | rts |
443 | |
444 | |
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 |
450 | |
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 |
457 | bne tx_ret |
458 | |
459 | // queue it |
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 |
463 | |
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 |
469 | |
470 | // update tx_out and tx_count |
471 | movel tx_out(%d0), %d1 |
472 | addl #1, %d1 |
473 | cmpl #TX_BUFFERS, %d1 |
474 | bne tx_1 |
475 | clrl %d1 |
476 | tx_1: movel %d1, tx_out(%d0) |
477 | |
478 | addl #1, tx_count(%d0) |
479 | bra tx |
480 | |
481 | tx_ret: rts |
482 | |
483 | |
484 | /****************************** packet received ***********************/ |
485 | |
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 |
491 | btstl #15, %d2 |
492 | bne rx_ret // BD still empty |
493 | |
494 | btstl #1, %d2 |
495 | bne rx_overrun |
496 | |
497 | tstw parity_bytes(%d0) |
498 | bne rx_parity |
499 | bclrl #2, %d2 // do not test for CRC errors |
500 | rx_parity: |
501 | andw #0x0CBC, %d2 // mask status bits |
502 | cmpw #0x0C00, %d2 // correct frame |
503 | bne rx_bad_frame |
504 | clrl %d3 |
505 | movew 2(%d1), %d3 |
506 | subw parity_bytes(%d0), %d3 // D3 = packet length |
507 | cmpw #HDLC_MAX_MRU, %d3 |
508 | bgt rx_bad_frame |
509 | |
510 | rx_good_frame: |
511 | movel rx_out, %d2 |
512 | mulul #DESC_LENGTH, %d2 |
513 | addl rx_descs_addr, %d2 // D2 = RX desc address |
514 | cmpl #PACKET_EMPTY, (%d2) // desc stat |
515 | bne rx_overrun |
516 | |
517 | movel %d3, 8(%d2) |
518 | movel 4(%d1), %a0 // A0 = source address |
519 | movel 4(%d2), %a1 |
520 | tstl %a1 |
521 | beq rx_ignore_data |
522 | memcpy_to_pci %a0, %a1, %d3 |
523 | rx_ignore_data: |
524 | movel packet_full(%d0), (%d2) // update desc stat |
525 | |
526 | // update D6 and rx_out |
527 | bsetl #DOORBELL_FROM_CARD_RX, %d6 // signal host that RX completed |
528 | movel rx_out, %d2 |
529 | addl #1, %d2 |
530 | cmpl #RX_QUEUE_LENGTH, %d2 |
531 | bne rx_1 |
532 | clrl %d2 |
533 | rx_1: movel %d2, rx_out |
534 | |
535 | rx_free_bd: |
536 | andw #0xF000, (%d1) // clear CM and error bits |
537 | bsetl #31, (%d1) // free BD |
538 | // update rx_in |
539 | movel rx_in(%d0), %d1 |
540 | addl #1, %d1 |
541 | cmpl #RX_BUFFERS, %d1 |
542 | bne rx_2 |
543 | clrl %d1 |
544 | rx_2: movel %d1, rx_in(%d0) |
545 | bra rx |
546 | |
547 | rx_overrun: |
548 | movel ch_status_addr(%d0), %d2 |
549 | addl #1, STATUS_RX_OVERRUNS(%d2) |
550 | bra rx_free_bd |
551 | |
552 | rx_bad_frame: |
553 | movel ch_status_addr(%d0), %d2 |
554 | addl #1, STATUS_RX_FRAME_ERRORS(%d2) |
555 | bra rx_free_bd |
556 | |
557 | rx_ret: rts |
558 | |
559 | |
560 | /****************************** packet transmitted ********************/ |
561 | |
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 |
565 | |
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 |
571 | btstl #15, %d3 |
572 | bne tx_end_ret // BD still being transmitted |
573 | |
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 |
578 | addl #1, %d1 |
579 | cmpl #TX_BUFFERS, %d1 |
580 | bne tx_end_1 |
581 | clrl %d1 |
582 | tx_end_1: |
583 | movel %d1, tx_in(%d0) |
584 | |
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 |
589 | btstl #1, %d3 |
590 | bne tx_end_underrun |
591 | movel #PACKET_SENT, (%d2) |
592 | bra tx_end |
593 | |
594 | tx_end_underrun: |
595 | movel #PACKET_UNDERRUN, (%d2) |
596 | bra tx_end |
597 | |
598 | tx_end_ret: rts |
599 | |
600 | |
601 | /****************************** PLX PCI9060 DMA memcpy ****************/ |
602 | |
603 | #if QUICC_MEMCPY_USES_PLX |
604 | // called with interrupts disabled |
605 | memcpy_from_pci_run: |
606 | movel %d0, -(%sp) |
607 | movew %sr, -(%sp) |
608 | memcpy_1: |
609 | movel PLX_DMA_CMD_STS, %d0 // do not btst PLX register directly |
610 | btstl #4, %d0 // transfer done? |
611 | bne memcpy_end |
612 | stop #0x2200 // enable PCI9060 interrupts |
613 | movew #0x2700, %sr // disable interrupts again |
614 | bra memcpy_1 |
615 | |
616 | memcpy_to_pci_run: |
617 | movel %d0, -(%sp) |
618 | movew %sr, -(%sp) |
619 | memcpy_2: |
620 | movel PLX_DMA_CMD_STS, %d0 // do not btst PLX register directly |
621 | btstl #12, %d0 // transfer done? |
622 | bne memcpy_end |
623 | stop #0x2200 // enable PCI9060 interrupts |
624 | movew #0x2700, %sr // disable interrupts again |
625 | bra memcpy_2 |
626 | |
627 | memcpy_end: |
628 | movew (%sp)+, %sr |
629 | movel (%sp)+, %d0 |
630 | rts |
631 | #endif |
632 | |
633 | |
634 | |
635 | |
636 | |
637 | |
638 | /****************************** PLX PCI9060 interrupt *****************/ |
639 | |
640 | pci9060_interrupt: |
641 | movel %d0, -(%sp) |
642 | |
643 | movel PLX_DOORBELL_TO_CARD, %d0 |
644 | movel %d0, PLX_DOORBELL_TO_CARD // confirm all requests |
645 | orl %d0, channel_stats |
646 | |
647 | movel #0x0909, PLX_DMA_CMD_STS // clear DMA ch #0 and #1 interrupts |
648 | |
649 | movel (%sp)+, %d0 |
650 | rte |
651 | |
652 | /****************************** SCC interrupts ************************/ |
653 | |
654 | port_interrupt_1: |
655 | orl #0, SCC1_REGS + SCC_SCCE; // confirm SCC events |
656 | orl #1 << TASK_SCC_0, channel_stats |
657 | movel #0x40000000, CISR |
658 | rte |
659 | |
660 | port_interrupt_2: |
661 | orl #0, SCC2_REGS + SCC_SCCE; // confirm SCC events |
662 | orl #1 << TASK_SCC_1, channel_stats |
663 | movel #0x20000000, CISR |
664 | rte |
665 | |
666 | port_interrupt_3: |
667 | orl #0, SCC3_REGS + SCC_SCCE; // confirm SCC events |
668 | orl #1 << TASK_SCC_2, channel_stats |
669 | movel #0x10000000, CISR |
670 | rte |
671 | |
672 | port_interrupt_4: |
673 | orl #0, SCC4_REGS + SCC_SCCE; // confirm SCC events |
674 | orl #1 << TASK_SCC_3, channel_stats |
675 | movel #0x08000000, CISR |
676 | rte |
677 | |
678 | error_interrupt: |
679 | rte |
680 | |
681 | |
682 | /****************************** cable and PM routine ******************/ |
683 | // modified registers: none |
684 | check_csr: |
685 | movel %d0, -(%sp) |
686 | movel %d1, -(%sp) |
687 | movel %d2, -(%sp) |
688 | movel %a0, -(%sp) |
689 | movel %a1, -(%sp) |
690 | |
691 | clrl %d0 // D0 = 4 * port |
692 | movel #CSRA, %a0 // A0 = CSR address |
693 | |
694 | check_csr_loop: |
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 |
698 | bne check_csr_1 |
699 | movew #0x0E08, %d1 |
700 | bra check_csr_valid |
701 | |
702 | check_csr_1: |
703 | cmpw #STATUS_CABLE_X21 * (1 + 1 << STATUS_CABLE_PM_SHIFT), %d1 |
704 | bne check_csr_2 |
705 | movew #0x0408, %d1 |
706 | bra check_csr_valid |
707 | |
708 | check_csr_2: |
709 | cmpw #STATUS_CABLE_V24 * (1 + 1 << STATUS_CABLE_PM_SHIFT), %d1 |
710 | bne check_csr_3 |
711 | movew #0x0208, %d1 |
712 | bra check_csr_valid |
713 | |
714 | check_csr_3: |
715 | cmpw #STATUS_CABLE_EIA530 * (1 + 1 << STATUS_CABLE_PM_SHIFT), %d1 |
716 | bne check_csr_disable |
717 | movew #0x0D08, %d1 |
718 | bra check_csr_valid |
719 | |
720 | check_csr_disable: |
721 | movew #0x0008, %d1 // D1 = disable everything |
722 | movew #0x80E7, %d2 // D2 = input mask: ignore DSR |
723 | bra check_csr_write |
724 | |
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 |
730 | |
731 | check_csr_write: |
732 | cmpw old_csr_output(%d0), %d1 |
733 | beq check_csr_input |
734 | movew %d1, old_csr_output(%d0) |
735 | movew %d1, (%a0) // Write CSR output bits |
736 | |
737 | check_csr_input: |
738 | movew (PCDAT), %d1 |
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 |
744 | |
745 | check_csr_dcd_on: |
746 | movew (%a0), %d1 // D1 = CSR input bits |
747 | orw #STATUS_CABLE_DCD, %d1 // DCD on |
748 | check_csr_previous: |
749 | andw %d2, %d1 // input mask |
750 | movel ch_status_addr(%d0), %a1 |
751 | cmpl STATUS_CABLE(%a1), %d1 // check for change |
752 | beq check_csr_next |
753 | movel %d1, STATUS_CABLE(%a1) // update status |
754 | movel bell_cable(%d0), PLX_DOORBELL_FROM_CARD // signal the host |
755 | |
756 | check_csr_next: |
757 | addl #2, %a0 // next CSR register |
758 | addl #4, %d0 // D0 = 4 * next port |
759 | cmpl #4 * 4, %d0 |
760 | bne check_csr_loop |
761 | |
762 | movel (%sp)+, %a1 |
763 | movel (%sp)+, %a0 |
764 | movel (%sp)+, %d2 |
765 | movel (%sp)+, %d1 |
766 | movel (%sp)+, %d0 |
767 | rts |
768 | |
769 | |
770 | /****************************** timer interrupt ***********************/ |
771 | |
772 | timer_interrupt: |
773 | bsr check_csr |
774 | rte |
775 | |
776 | |
777 | /****************************** RAM sizing and test *******************/ |
778 | #if DETECT_RAM |
779 | ram_test: |
780 | movel #0x12345678, %d1 // D1 = test value |
781 | movel %d1, (128 * 1024 - 4) |
782 | movel #128 * 1024, %d0 // D0 = RAM size tested |
783 | ram_test_size: |
784 | cmpl #MAX_RAM_SIZE, %d0 |
785 | beq ram_test_size_found |
786 | movel %d0, %a0 |
787 | addl #128 * 1024 - 4, %a0 |
788 | cmpl (%a0), %d1 |
789 | beq ram_test_size_check |
790 | ram_test_next_size: |
791 | lsll #1, %d0 |
792 | bra ram_test_size |
793 | |
794 | ram_test_size_check: |
795 | eorl #0xFFFFFFFF, %d1 |
796 | movel %d1, (128 * 1024 - 4) |
797 | cmpl (%a0), %d1 |
798 | bne ram_test_next_size |
799 | |
800 | ram_test_size_found: // D0 = RAM size |
801 | movel %d0, %a0 // A0 = fill ptr |
802 | subl #firmware_end + 4, %d0 |
803 | lsrl #2, %d0 |
804 | movel %d0, %d1 // D1 = DBf counter |
805 | ram_test_fill: |
806 | movel %a0, -(%a0) |
807 | dbfw %d1, ram_test_fill |
808 | subl #0x10000, %d1 |
809 | cmpl #0xFFFFFFFF, %d1 |
810 | bne ram_test_fill |
811 | |
812 | ram_test_loop: // D0 = DBf counter |
813 | cmpl (%a0)+, %a0 |
814 | dbnew %d0, ram_test_loop |
815 | bne ram_test_found_bad |
816 | subl #0x10000, %d0 |
817 | cmpl #0xFFFFFFFF, %d0 |
818 | bne ram_test_loop |
819 | bra ram_test_all_ok |
820 | |
821 | ram_test_found_bad: |
822 | subl #4, %a0 |
823 | ram_test_all_ok: |
824 | movel %a0, PLX_MAILBOX_5 |
825 | rts |
826 | #endif |
827 | |
828 | |
829 | /****************************** constants *****************************/ |
830 | |
831 | scc_reg_addr: |
832 | .long SCC1_REGS, SCC2_REGS, SCC3_REGS, SCC4_REGS |
833 | scc_base_addr: |
834 | .long SCC1_BASE, SCC2_BASE, SCC3_BASE, SCC4_BASE |
835 | |
836 | tx_first_bd: |
837 | .long DPRBASE |
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 |
841 | |
842 | rx_first_bd: |
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 |
847 | |
848 | first_buffer: |
849 | .long BUFFERS_ADDR |
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 |
853 | |
854 | bell_tx: |
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 |
857 | |
858 | bell_cable: |
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 |
861 | |
862 | packet_full: |
863 | .long PACKET_FULL, PACKET_FULL + 1, PACKET_FULL + 2, PACKET_FULL + 3 |
864 | |
865 | clocking_ext: |
866 | .long 0x0000002C, 0x00003E00, 0x002C0000, 0x3E000000 |
867 | clocking_txfromrx: |
868 | .long 0x0000002D, 0x00003F00, 0x002D0000, 0x3F000000 |
869 | clocking_mask: |
870 | .long 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 |
871 | dcd_mask: |
872 | .word 0x020, 0, 0x080, 0, 0x200, 0, 0x800 |
873 | |
874 | .ascii "wanXL firmware\n" |
875 | .asciz "Copyright (C) 2003 Krzysztof Halasa <khc@pm.waw.pl>\n" |
876 | |
877 | |
878 | /****************************** variables *****************************/ |
879 | |
880 | .align 4 |
881 | channel_stats: .long 0 |
882 | |
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 |
886 | |
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 |
890 | |
891 | csr_output: .word 0 |
892 | old_csr_output: .word 0, 0, 0, 0, 0, 0, 0 |
893 | .align 4 |
894 | firmware_end: // must be dword-aligned |
895 | |