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