xref: /openbmc/linux/drivers/net/wan/wanxlfw.S (revision 25763b3c864cf517d686661012d184ee47a49b4c)
1*25763b3cSThomas Gleixner/* SPDX-License-Identifier: GPL-2.0-only */
21da177e4SLinus Torvalds.psize 0
31da177e4SLinus Torvalds/*
41da177e4SLinus Torvalds  wanXL serial card driver for Linux
51da177e4SLinus Torvalds  card firmware part
61da177e4SLinus Torvalds
71da177e4SLinus Torvalds  Copyright (C) 2003 Krzysztof Halasa <khc@pm.waw.pl>
81da177e4SLinus Torvalds
91da177e4SLinus Torvalds
101da177e4SLinus Torvalds
111da177e4SLinus Torvalds
121da177e4SLinus Torvalds
131da177e4SLinus Torvalds	DPRAM BDs:
141da177e4SLinus Torvalds	0x000 - 0x050 TX#0	0x050 - 0x140 RX#0
151da177e4SLinus Torvalds	0x140 - 0x190 TX#1	0x190 - 0x280 RX#1
161da177e4SLinus Torvalds	0x280 - 0x2D0 TX#2	0x2D0 - 0x3C0 RX#2
171da177e4SLinus Torvalds	0x3C0 - 0x410 TX#3	0x410 - 0x500 RX#3
181da177e4SLinus Torvalds
191da177e4SLinus Torvalds
201da177e4SLinus Torvalds	000 5FF 1536 Bytes Dual-Port RAM User Data / BDs
211da177e4SLinus Torvalds	600 6FF 256 Bytes Dual-Port RAM User Data / BDs
221da177e4SLinus Torvalds	700 7FF 256 Bytes Dual-Port RAM User Data / BDs
231da177e4SLinus Torvalds	C00 CBF 192 Bytes Dual-Port RAM Parameter RAM Page 1
241da177e4SLinus Torvalds	D00 DBF 192 Bytes Dual-Port RAM Parameter RAM Page 2
251da177e4SLinus Torvalds	E00 EBF 192 Bytes Dual-Port RAM Parameter RAM Page 3
261da177e4SLinus Torvalds	F00 FBF 192 Bytes Dual-Port RAM Parameter RAM Page 4
271da177e4SLinus Torvalds
281da177e4SLinus Torvalds	local interrupts		    level
291da177e4SLinus Torvalds	NMI					7
301da177e4SLinus Torvalds	PIT timer, CPM (RX/TX complete)		4
311da177e4SLinus Torvalds	PCI9060	DMA and PCI doorbells		3
321da177e4SLinus Torvalds	Cable - not used			1
331da177e4SLinus Torvalds*/
341da177e4SLinus Torvalds
351da177e4SLinus Torvalds#include <linux/hdlc.h>
36c48c8d51SDavid Howells#include <linux/hdlc/ioctl.h>
371da177e4SLinus Torvalds#include "wanxl.h"
381da177e4SLinus Torvalds
391da177e4SLinus Torvalds/* memory addresses and offsets */
401da177e4SLinus Torvalds
411da177e4SLinus TorvaldsMAX_RAM_SIZE	= 16 * 1024 * 1024	// max RAM supported by hardware
421da177e4SLinus Torvalds
431da177e4SLinus TorvaldsPCI9060_VECTOR	= 0x0000006C
441da177e4SLinus TorvaldsCPM_IRQ_BASE	= 0x40
451da177e4SLinus TorvaldsERROR_VECTOR	= CPM_IRQ_BASE * 4
461da177e4SLinus TorvaldsSCC1_VECTOR	= (CPM_IRQ_BASE + 0x1E) * 4
471da177e4SLinus TorvaldsSCC2_VECTOR	= (CPM_IRQ_BASE + 0x1D) * 4
481da177e4SLinus TorvaldsSCC3_VECTOR	= (CPM_IRQ_BASE + 0x1C) * 4
491da177e4SLinus TorvaldsSCC4_VECTOR	= (CPM_IRQ_BASE + 0x1B) * 4
501da177e4SLinus TorvaldsCPM_IRQ_LEVEL	= 4
511da177e4SLinus TorvaldsTIMER_IRQ	= 128
521da177e4SLinus TorvaldsTIMER_IRQ_LEVEL = 4
531da177e4SLinus TorvaldsPITR_CONST	= 0x100 + 16		// 1 Hz timer
541da177e4SLinus Torvalds
551da177e4SLinus TorvaldsMBAR		= 0x0003FF00
561da177e4SLinus Torvalds
571da177e4SLinus TorvaldsVALUE_WINDOW	= 0x40000000
581da177e4SLinus TorvaldsORDER_WINDOW	= 0xC0000000
591da177e4SLinus Torvalds
601da177e4SLinus TorvaldsPLX		= 0xFFF90000
611da177e4SLinus Torvalds
621da177e4SLinus TorvaldsCSRA		= 0xFFFB0000
631da177e4SLinus TorvaldsCSRB		= 0xFFFB0002
641da177e4SLinus TorvaldsCSRC		= 0xFFFB0004
651da177e4SLinus TorvaldsCSRD		= 0xFFFB0006
661da177e4SLinus TorvaldsSTATUS_CABLE_LL		= 0x2000
671da177e4SLinus TorvaldsSTATUS_CABLE_DTR	= 0x1000
681da177e4SLinus Torvalds
691da177e4SLinus TorvaldsDPRBASE		= 0xFFFC0000
701da177e4SLinus Torvalds
711da177e4SLinus TorvaldsSCC1_BASE	= DPRBASE + 0xC00
721da177e4SLinus TorvaldsMISC_BASE	= DPRBASE + 0xCB0
731da177e4SLinus TorvaldsSCC2_BASE	= DPRBASE + 0xD00
741da177e4SLinus TorvaldsSCC3_BASE	= DPRBASE + 0xE00
751da177e4SLinus TorvaldsSCC4_BASE	= DPRBASE + 0xF00
761da177e4SLinus Torvalds
771da177e4SLinus Torvalds// offset from SCCx_BASE
781da177e4SLinus Torvalds// SCC_xBASE contain offsets from DPRBASE and must be divisible by 8
791da177e4SLinus TorvaldsSCC_RBASE	= 0		// 16-bit RxBD base address
801da177e4SLinus TorvaldsSCC_TBASE	= 2		// 16-bit TxBD base address
811da177e4SLinus TorvaldsSCC_RFCR	= 4		// 8-bit Rx function code
821da177e4SLinus TorvaldsSCC_TFCR	= 5		// 8-bit Tx function code
831da177e4SLinus TorvaldsSCC_MRBLR	= 6		// 16-bit maximum Rx buffer length
841da177e4SLinus TorvaldsSCC_C_MASK	= 0x34		// 32-bit CRC constant
851da177e4SLinus TorvaldsSCC_C_PRES	= 0x38		// 32-bit CRC preset
861da177e4SLinus TorvaldsSCC_MFLR	= 0x46		// 16-bit max Rx frame length (without flags)
871da177e4SLinus Torvalds
881da177e4SLinus TorvaldsREGBASE		= DPRBASE + 0x1000
891da177e4SLinus TorvaldsPICR		= REGBASE + 0x026	// 16-bit periodic irq control
901da177e4SLinus TorvaldsPITR		= REGBASE + 0x02A	// 16-bit periodic irq timing
911da177e4SLinus TorvaldsOR1		= REGBASE + 0x064	// 32-bit RAM bank #1 options
921da177e4SLinus TorvaldsCICR		= REGBASE + 0x540	// 32(24)-bit CP interrupt config
931da177e4SLinus TorvaldsCIMR		= REGBASE + 0x548	// 32-bit CP interrupt mask
941da177e4SLinus TorvaldsCISR		= REGBASE + 0x54C	// 32-bit CP interrupts in-service
951da177e4SLinus TorvaldsPADIR		= REGBASE + 0x550	// 16-bit PortA data direction bitmap
961da177e4SLinus TorvaldsPAPAR		= REGBASE + 0x552	// 16-bit PortA pin assignment bitmap
971da177e4SLinus TorvaldsPAODR		= REGBASE + 0x554	// 16-bit PortA open drain bitmap
981da177e4SLinus TorvaldsPADAT		= REGBASE + 0x556	// 16-bit PortA data register
991da177e4SLinus Torvalds
1001da177e4SLinus TorvaldsPCDIR		= REGBASE + 0x560	// 16-bit PortC data direction bitmap
1011da177e4SLinus TorvaldsPCPAR		= REGBASE + 0x562	// 16-bit PortC pin assignment bitmap
1021da177e4SLinus TorvaldsPCSO		= REGBASE + 0x564	// 16-bit PortC special options
1031da177e4SLinus TorvaldsPCDAT		= REGBASE + 0x566	// 16-bit PortC data register
1041da177e4SLinus TorvaldsPCINT		= REGBASE + 0x568	// 16-bit PortC interrupt control
1051da177e4SLinus TorvaldsCR		= REGBASE + 0x5C0	// 16-bit Command register
1061da177e4SLinus Torvalds
1071da177e4SLinus TorvaldsSCC1_REGS	= REGBASE + 0x600
1081da177e4SLinus TorvaldsSCC2_REGS	= REGBASE + 0x620
1091da177e4SLinus TorvaldsSCC3_REGS	= REGBASE + 0x640
1101da177e4SLinus TorvaldsSCC4_REGS	= REGBASE + 0x660
1111da177e4SLinus TorvaldsSICR		= REGBASE + 0x6EC	// 32-bit SI clock route
1121da177e4SLinus Torvalds
1131da177e4SLinus Torvalds// offset from SCCx_REGS
1141da177e4SLinus TorvaldsSCC_GSMR_L	= 0x00	// 32 bits
1151da177e4SLinus TorvaldsSCC_GSMR_H	= 0x04	// 32 bits
1161da177e4SLinus TorvaldsSCC_PSMR	= 0x08	// 16 bits
1171da177e4SLinus TorvaldsSCC_TODR	= 0x0C	// 16 bits
1181da177e4SLinus TorvaldsSCC_DSR		= 0x0E	// 16 bits
1191da177e4SLinus TorvaldsSCC_SCCE	= 0x10	// 16 bits
1201da177e4SLinus TorvaldsSCC_SCCM	= 0x14	// 16 bits
1211da177e4SLinus TorvaldsSCC_SCCS	= 0x17	// 8 bits
1221da177e4SLinus Torvalds
1231da177e4SLinus Torvalds#if QUICC_MEMCPY_USES_PLX
1241da177e4SLinus Torvalds	.macro memcpy_from_pci src, dest, len // len must be < 8 MB
1251da177e4SLinus Torvalds	addl #3, \len
1261da177e4SLinus Torvalds	andl #0xFFFFFFFC, \len		// always copy n * 4 bytes
1271da177e4SLinus Torvalds	movel \src, PLX_DMA_0_PCI
1281da177e4SLinus Torvalds	movel \dest, PLX_DMA_0_LOCAL
1291da177e4SLinus Torvalds	movel \len, PLX_DMA_0_LENGTH
1301da177e4SLinus Torvalds	movel #0x0103, PLX_DMA_CMD_STS	// start channel 0 transfer
1311da177e4SLinus Torvalds	bsr memcpy_from_pci_run
1321da177e4SLinus Torvalds	.endm
1331da177e4SLinus Torvalds
1341da177e4SLinus Torvalds	.macro memcpy_to_pci src, dest, len
1351da177e4SLinus Torvalds	addl #3, \len
1361da177e4SLinus Torvalds	andl #0xFFFFFFFC, \len		// always copy n * 4 bytes
1371da177e4SLinus Torvalds	movel \src, PLX_DMA_1_LOCAL
1381da177e4SLinus Torvalds	movel \dest, PLX_DMA_1_PCI
1391da177e4SLinus Torvalds	movel \len, PLX_DMA_1_LENGTH
1401da177e4SLinus Torvalds	movel #0x0301, PLX_DMA_CMD_STS	// start channel 1 transfer
1411da177e4SLinus Torvalds	bsr memcpy_to_pci_run
1421da177e4SLinus Torvalds	.endm
1431da177e4SLinus Torvalds
1441da177e4SLinus Torvalds#else
1451da177e4SLinus Torvalds
1461da177e4SLinus Torvalds	.macro memcpy src, dest, len	// len must be < 65536 bytes
1471da177e4SLinus Torvalds	movel %d7, -(%sp)		// src and dest must be < 256 MB
1481da177e4SLinus Torvalds	movel \len, %d7			// bits 0 and 1
1491da177e4SLinus Torvalds	lsrl #2, \len
1501da177e4SLinus Torvalds	andl \len, \len
1511da177e4SLinus Torvalds	beq 99f				// only 0 - 3 bytes
1521da177e4SLinus Torvalds	subl #1, \len			// for dbf
1531da177e4SLinus Torvalds98:	movel (\src)+, (\dest)+
1541da177e4SLinus Torvalds	dbfw \len, 98b
1551da177e4SLinus Torvalds99:	movel %d7, \len
1561da177e4SLinus Torvalds	btstl #1, \len
1571da177e4SLinus Torvalds	beq 99f
1581da177e4SLinus Torvalds	movew (\src)+, (\dest)+
1591da177e4SLinus Torvalds99:	btstl #0, \len
1601da177e4SLinus Torvalds	beq 99f
1611da177e4SLinus Torvalds	moveb (\src)+, (\dest)+
1621da177e4SLinus Torvalds99:
1631da177e4SLinus Torvalds	movel (%sp)+, %d7
1641da177e4SLinus Torvalds	.endm
1651da177e4SLinus Torvalds
1661da177e4SLinus Torvalds	.macro memcpy_from_pci src, dest, len
1671da177e4SLinus Torvalds	addl #VALUE_WINDOW, \src
1681da177e4SLinus Torvalds	memcpy \src, \dest, \len
1691da177e4SLinus Torvalds	.endm
1701da177e4SLinus Torvalds
1711da177e4SLinus Torvalds	.macro memcpy_to_pci src, dest, len
1721da177e4SLinus Torvalds	addl #VALUE_WINDOW, \dest
1731da177e4SLinus Torvalds	memcpy \src, \dest, \len
1741da177e4SLinus Torvalds	.endm
1751da177e4SLinus Torvalds#endif
1761da177e4SLinus Torvalds
1771da177e4SLinus Torvalds
1781da177e4SLinus Torvalds	.macro wait_for_command
1791da177e4SLinus Torvalds99:	btstl #0, CR
1801da177e4SLinus Torvalds	bne 99b
1811da177e4SLinus Torvalds	.endm
1821da177e4SLinus Torvalds
1831da177e4SLinus Torvalds
1841da177e4SLinus Torvalds
1851da177e4SLinus Torvalds
1861da177e4SLinus Torvalds/****************************** card initialization *******************/
1871da177e4SLinus Torvalds	.text
1881da177e4SLinus Torvalds	.global _start
1891da177e4SLinus Torvalds_start:	bra init
1901da177e4SLinus Torvalds
1911da177e4SLinus Torvalds	.org _start + 4
1921da177e4SLinus Torvaldsch_status_addr:	.long 0, 0, 0, 0
1931da177e4SLinus Torvaldsrx_descs_addr:	.long 0
1941da177e4SLinus Torvalds
1951da177e4SLinus Torvaldsinit:
1961da177e4SLinus Torvalds#if DETECT_RAM
1971da177e4SLinus Torvalds	movel OR1, %d0
1981da177e4SLinus Torvalds	andl #0xF00007FF, %d0		// mask AMxx bits
1991da177e4SLinus Torvalds	orl #0xFFFF800 & ~(MAX_RAM_SIZE - 1), %d0 // update RAM bank size
2001da177e4SLinus Torvalds	movel %d0, OR1
2011da177e4SLinus Torvalds#endif
2021da177e4SLinus Torvalds
2031da177e4SLinus Torvalds	addl #VALUE_WINDOW, rx_descs_addr // PCI addresses of shared data
2041da177e4SLinus Torvalds	clrl %d0			// D0 = 4 * port
2051da177e4SLinus Torvaldsinit_1:	tstl ch_status_addr(%d0)
2061da177e4SLinus Torvalds	beq init_2
2071da177e4SLinus Torvalds	addl #VALUE_WINDOW, ch_status_addr(%d0)
2081da177e4SLinus Torvaldsinit_2:	addl #4, %d0
2091da177e4SLinus Torvalds	cmpl #4 * 4, %d0
2101da177e4SLinus Torvalds	bne init_1
2111da177e4SLinus Torvalds
2121da177e4SLinus Torvalds	movel #pci9060_interrupt, PCI9060_VECTOR
2131da177e4SLinus Torvalds	movel #error_interrupt, ERROR_VECTOR
2141da177e4SLinus Torvalds	movel #port_interrupt_1, SCC1_VECTOR
2151da177e4SLinus Torvalds	movel #port_interrupt_2, SCC2_VECTOR
2161da177e4SLinus Torvalds	movel #port_interrupt_3, SCC3_VECTOR
2171da177e4SLinus Torvalds	movel #port_interrupt_4, SCC4_VECTOR
2181da177e4SLinus Torvalds	movel #timer_interrupt, TIMER_IRQ * 4
2191da177e4SLinus Torvalds
2201da177e4SLinus Torvalds	movel #0x78000000, CIMR		// only SCCx IRQs from CPM
2211da177e4SLinus Torvalds	movew #(TIMER_IRQ_LEVEL << 8) + TIMER_IRQ, PICR	// interrupt from PIT
2221da177e4SLinus Torvalds	movew #PITR_CONST, PITR
2231da177e4SLinus Torvalds
2241da177e4SLinus Torvalds	// SCC1=SCCa SCC2=SCCb SCC3=SCCc SCC4=SCCd prio=4 HP=-1 IRQ=64-79
2251da177e4SLinus Torvalds	movel #0xD41F40 + (CPM_IRQ_LEVEL << 13), CICR
2261da177e4SLinus Torvalds	movel #0x543, PLX_DMA_0_MODE	// 32-bit, Ready, Burst, IRQ
2271da177e4SLinus Torvalds	movel #0x543, PLX_DMA_1_MODE
2281da177e4SLinus Torvalds	movel #0x0, PLX_DMA_0_DESC	// from PCI to local
2291da177e4SLinus Torvalds	movel #0x8, PLX_DMA_1_DESC	// from local to PCI
2301da177e4SLinus Torvalds	movel #0x101, PLX_DMA_CMD_STS	// enable both DMA channels
2311da177e4SLinus Torvalds	// enable local IRQ, DMA, doorbells and PCI IRQ
2321da177e4SLinus Torvalds	orl #0x000F0300, PLX_INTERRUPT_CS
2331da177e4SLinus Torvalds
2341da177e4SLinus Torvalds#if DETECT_RAM
2351da177e4SLinus Torvalds	bsr ram_test
2361da177e4SLinus Torvalds#else
2371da177e4SLinus Torvalds	movel #1, PLX_MAILBOX_5		// non-zero value = init complete
2381da177e4SLinus Torvalds#endif
2391da177e4SLinus Torvalds	bsr check_csr
2401da177e4SLinus Torvalds
2411da177e4SLinus Torvalds	movew #0xFFFF, PAPAR		// all pins are clocks/data
2421da177e4SLinus Torvalds	clrw PADIR			// first function
2431da177e4SLinus Torvalds	clrw PCSO			// CD and CTS always active
2441da177e4SLinus Torvalds
2451da177e4SLinus Torvalds
2461da177e4SLinus Torvalds/****************************** main loop *****************************/
2471da177e4SLinus Torvalds
2481da177e4SLinus Torvaldsmain:	movel channel_stats, %d7	// D7 = doorbell + irq status
2491da177e4SLinus Torvalds	clrl channel_stats
2501da177e4SLinus Torvalds
2511da177e4SLinus Torvalds	tstl %d7
2521da177e4SLinus Torvalds	bne main_1
2531da177e4SLinus Torvalds	// nothing to do - wait for next event
2541da177e4SLinus Torvalds	stop #0x2200			// supervisor + IRQ level 2
2551da177e4SLinus Torvalds	movew #0x2700, %sr		// disable IRQs again
2561da177e4SLinus Torvalds	bra main
2571da177e4SLinus Torvalds
2581da177e4SLinus Torvaldsmain_1:	clrl %d0			// D0 = 4 * port
2591da177e4SLinus Torvalds	clrl %d6			// D6 = doorbell to host value
2601da177e4SLinus Torvalds
2611da177e4SLinus Torvaldsmain_l: btstl #DOORBELL_TO_CARD_CLOSE_0, %d7
2621da177e4SLinus Torvalds	beq main_op
2631da177e4SLinus Torvalds	bclrl #DOORBELL_TO_CARD_OPEN_0, %d7 // in case both bits are set
2641da177e4SLinus Torvalds	bsr close_port
2651da177e4SLinus Torvaldsmain_op:
2661da177e4SLinus Torvalds	btstl #DOORBELL_TO_CARD_OPEN_0, %d7
2671da177e4SLinus Torvalds	beq main_cl
2681da177e4SLinus Torvalds	bsr open_port
2691da177e4SLinus Torvaldsmain_cl:
2701da177e4SLinus Torvalds	btstl #DOORBELL_TO_CARD_TX_0, %d7
2711da177e4SLinus Torvalds	beq main_txend
2721da177e4SLinus Torvalds	bsr tx
2731da177e4SLinus Torvaldsmain_txend:
2741da177e4SLinus Torvalds	btstl #TASK_SCC_0, %d7
2751da177e4SLinus Torvalds	beq main_next
2761da177e4SLinus Torvalds	bsr tx_end
2771da177e4SLinus Torvalds	bsr rx
2781da177e4SLinus Torvalds
2791da177e4SLinus Torvaldsmain_next:
2801da177e4SLinus Torvalds	lsrl #1, %d7			// port status for next port
2811da177e4SLinus Torvalds	addl #4, %d0			// D0 = 4 * next port
2821da177e4SLinus Torvalds	cmpl #4 * 4, %d0
2831da177e4SLinus Torvalds	bne main_l
2841da177e4SLinus Torvalds	movel %d6, PLX_DOORBELL_FROM_CARD // signal the host
2851da177e4SLinus Torvalds	bra main
2861da177e4SLinus Torvalds
2871da177e4SLinus Torvalds
2881da177e4SLinus Torvalds/****************************** open port *****************************/
2891da177e4SLinus Torvalds
2901da177e4SLinus Torvaldsopen_port:				// D0 = 4 * port, D6 = doorbell to host
2911da177e4SLinus Torvalds	movel ch_status_addr(%d0), %a0	// A0 = port status address
2921da177e4SLinus Torvalds	tstl STATUS_OPEN(%a0)
2931da177e4SLinus Torvalds	bne open_port_ret		// port already open
2941da177e4SLinus Torvalds	movel #1, STATUS_OPEN(%a0)	// confirm the port is open
2951da177e4SLinus Torvalds// setup BDs
2961da177e4SLinus Torvalds	clrl tx_in(%d0)
2971da177e4SLinus Torvalds	clrl tx_out(%d0)
2981da177e4SLinus Torvalds	clrl tx_count(%d0)
2991da177e4SLinus Torvalds	clrl rx_in(%d0)
3001da177e4SLinus Torvalds
3011da177e4SLinus Torvalds	movel SICR, %d1			// D1 = clock settings in SICR
3021da177e4SLinus Torvalds	andl clocking_mask(%d0), %d1
3031da177e4SLinus Torvalds	cmpl #CLOCK_TXFROMRX, STATUS_CLOCKING(%a0)
3041da177e4SLinus Torvalds	bne open_port_clock_ext
3051da177e4SLinus Torvalds	orl clocking_txfromrx(%d0), %d1
3061da177e4SLinus Torvalds	bra open_port_set_clock
3071da177e4SLinus Torvalds
3081da177e4SLinus Torvaldsopen_port_clock_ext:
3091da177e4SLinus Torvalds	orl clocking_ext(%d0), %d1
3101da177e4SLinus Torvaldsopen_port_set_clock:
3111da177e4SLinus Torvalds	movel %d1, SICR			// update clock settings in SICR
3121da177e4SLinus Torvalds
3131da177e4SLinus Torvalds	orw #STATUS_CABLE_DTR, csr_output(%d0)	// DTR on
3141da177e4SLinus Torvalds	bsr check_csr			// call with disabled timer interrupt
3151da177e4SLinus Torvalds
3161da177e4SLinus Torvalds// Setup TX descriptors
3171da177e4SLinus Torvalds	movel first_buffer(%d0), %d1	// D1 = starting buffer address
3181da177e4SLinus Torvalds	movel tx_first_bd(%d0), %a1	// A1 = starting TX BD address
3191da177e4SLinus Torvalds	movel #TX_BUFFERS - 2, %d2	// D2 = TX_BUFFERS - 1 counter
3201da177e4SLinus Torvalds	movel #0x18000000, %d3		// D3 = initial TX BD flags: Int + Last
3211da177e4SLinus Torvalds	cmpl #PARITY_NONE, STATUS_PARITY(%a0)
3221da177e4SLinus Torvalds	beq open_port_tx_loop
3231da177e4SLinus Torvalds	bsetl #26, %d3			// TX BD flag: Transmit CRC
3241da177e4SLinus Torvaldsopen_port_tx_loop:
3251da177e4SLinus Torvalds	movel %d3, (%a1)+		// TX flags + length
3261da177e4SLinus Torvalds	movel %d1, (%a1)+		// buffer address
3271da177e4SLinus Torvalds	addl #BUFFER_LENGTH, %d1
3281da177e4SLinus Torvalds	dbfw %d2, open_port_tx_loop
3291da177e4SLinus Torvalds
3301da177e4SLinus Torvalds	bsetl #29, %d3			// TX BD flag: Wrap (last BD)
3311da177e4SLinus Torvalds	movel %d3, (%a1)+		// Final TX flags + length
3321da177e4SLinus Torvalds	movel %d1, (%a1)+		// buffer address
3331da177e4SLinus Torvalds
3341da177e4SLinus Torvalds// Setup RX descriptors			// A1 = starting RX BD address
3351da177e4SLinus Torvalds	movel #RX_BUFFERS - 2, %d2	// D2 = RX_BUFFERS - 1 counter
3361da177e4SLinus Torvaldsopen_port_rx_loop:
3371da177e4SLinus Torvalds	movel #0x90000000, (%a1)+	// RX flags + length
3381da177e4SLinus Torvalds	movel %d1, (%a1)+		// buffer address
3391da177e4SLinus Torvalds	addl #BUFFER_LENGTH, %d1
3401da177e4SLinus Torvalds	dbfw %d2, open_port_rx_loop
3411da177e4SLinus Torvalds
3421da177e4SLinus Torvalds	movel #0xB0000000, (%a1)+	// Final RX flags + length
3431da177e4SLinus Torvalds	movel %d1, (%a1)+		// buffer address
3441da177e4SLinus Torvalds
3451da177e4SLinus Torvalds// Setup port parameters
3461da177e4SLinus Torvalds	movel scc_base_addr(%d0), %a1	// A1 = SCC_BASE address
3471da177e4SLinus Torvalds	movel scc_reg_addr(%d0), %a2	// A2 = SCC_REGS address
3481da177e4SLinus Torvalds
3491da177e4SLinus Torvalds	movel #0xFFFF, SCC_SCCE(%a2)	// clear status bits
3501da177e4SLinus Torvalds	movel #0x0000, SCC_SCCM(%a2)	// interrupt mask
3511da177e4SLinus Torvalds
3521da177e4SLinus Torvalds	movel tx_first_bd(%d0), %d1
3531da177e4SLinus Torvalds	movew %d1, SCC_TBASE(%a1)	// D1 = offset of first TxBD
3541da177e4SLinus Torvalds	addl #TX_BUFFERS * 8, %d1
3551da177e4SLinus Torvalds	movew %d1, SCC_RBASE(%a1)	// D1 = offset of first RxBD
3561da177e4SLinus Torvalds	moveb #0x8, SCC_RFCR(%a1)	// Intel mode, 1000
3571da177e4SLinus Torvalds	moveb #0x8, SCC_TFCR(%a1)
3581da177e4SLinus Torvalds
3591da177e4SLinus Torvalds// Parity settings
3601da177e4SLinus Torvalds	cmpl #PARITY_CRC16_PR1_CCITT, STATUS_PARITY(%a0)
3611da177e4SLinus Torvalds	bne open_port_parity_1
3621da177e4SLinus Torvalds	clrw SCC_PSMR(%a2)		// CRC16-CCITT
3631da177e4SLinus Torvalds	movel #0xF0B8, SCC_C_MASK(%a1)
3641da177e4SLinus Torvalds	movel #0xFFFF, SCC_C_PRES(%a1)
3651da177e4SLinus Torvalds	movew #HDLC_MAX_MRU + 2, SCC_MFLR(%a1) // 2 bytes for CRC
3661da177e4SLinus Torvalds	movew #2, parity_bytes(%d0)
3671da177e4SLinus Torvalds	bra open_port_2
3681da177e4SLinus Torvalds
3691da177e4SLinus Torvaldsopen_port_parity_1:
3701da177e4SLinus Torvalds	cmpl #PARITY_CRC32_PR1_CCITT, STATUS_PARITY(%a0)
3711da177e4SLinus Torvalds	bne open_port_parity_2
3721da177e4SLinus Torvalds	movew #0x0800, SCC_PSMR(%a2)	// CRC32-CCITT
3731da177e4SLinus Torvalds	movel #0xDEBB20E3, SCC_C_MASK(%a1)
3741da177e4SLinus Torvalds	movel #0xFFFFFFFF, SCC_C_PRES(%a1)
3751da177e4SLinus Torvalds	movew #HDLC_MAX_MRU + 4, SCC_MFLR(%a1) // 4 bytes for CRC
3761da177e4SLinus Torvalds	movew #4, parity_bytes(%d0)
3771da177e4SLinus Torvalds	bra open_port_2
3781da177e4SLinus Torvalds
3791da177e4SLinus Torvaldsopen_port_parity_2:
3801da177e4SLinus Torvalds	cmpl #PARITY_CRC16_PR0_CCITT, STATUS_PARITY(%a0)
3811da177e4SLinus Torvalds	bne open_port_parity_3
3821da177e4SLinus Torvalds	clrw SCC_PSMR(%a2)		// CRC16-CCITT preset 0
3831da177e4SLinus Torvalds	movel #0xF0B8, SCC_C_MASK(%a1)
3841da177e4SLinus Torvalds	clrl SCC_C_PRES(%a1)
3851da177e4SLinus Torvalds	movew #HDLC_MAX_MRU + 2, SCC_MFLR(%a1) // 2 bytes for CRC
3861da177e4SLinus Torvalds	movew #2, parity_bytes(%d0)
3871da177e4SLinus Torvalds	bra open_port_2
3881da177e4SLinus Torvalds
3891da177e4SLinus Torvaldsopen_port_parity_3:
3901da177e4SLinus Torvalds	cmpl #PARITY_CRC32_PR0_CCITT, STATUS_PARITY(%a0)
3911da177e4SLinus Torvalds	bne open_port_parity_4
3921da177e4SLinus Torvalds	movew #0x0800, SCC_PSMR(%a2)	// CRC32-CCITT preset 0
3931da177e4SLinus Torvalds	movel #0xDEBB20E3, SCC_C_MASK(%a1)
3941da177e4SLinus Torvalds	clrl SCC_C_PRES(%a1)
3951da177e4SLinus Torvalds	movew #HDLC_MAX_MRU + 4, SCC_MFLR(%a1) // 4 bytes for CRC
3961da177e4SLinus Torvalds	movew #4, parity_bytes(%d0)
3971da177e4SLinus Torvalds	bra open_port_2
3981da177e4SLinus Torvalds
3991da177e4SLinus Torvaldsopen_port_parity_4:
4001da177e4SLinus Torvalds	clrw SCC_PSMR(%a2)		// no parity
4011da177e4SLinus Torvalds	movel #0xF0B8, SCC_C_MASK(%a1)
4021da177e4SLinus Torvalds	movel #0xFFFF, SCC_C_PRES(%a1)
4031da177e4SLinus Torvalds	movew #HDLC_MAX_MRU, SCC_MFLR(%a1) // 0 bytes for CRC
4041da177e4SLinus Torvalds	clrw parity_bytes(%d0)
4051da177e4SLinus Torvalds
4061da177e4SLinus Torvaldsopen_port_2:
4071da177e4SLinus Torvalds	movel #0x00000003, SCC_GSMR_H(%a2) // RTSM
4081da177e4SLinus Torvalds	cmpl #ENCODING_NRZI, STATUS_ENCODING(%a0)
4091da177e4SLinus Torvalds	bne open_port_nrz
4101da177e4SLinus Torvalds	movel #0x10040900, SCC_GSMR_L(%a2) // NRZI: TCI Tend RECN+TENC=1
4111da177e4SLinus Torvalds	bra open_port_3
4121da177e4SLinus Torvalds
4131da177e4SLinus Torvaldsopen_port_nrz:
4141da177e4SLinus Torvalds	movel #0x10040000, SCC_GSMR_L(%a2) // NRZ: TCI Tend RECN+TENC=0
4151da177e4SLinus Torvaldsopen_port_3:
4161da177e4SLinus Torvalds	movew #BUFFER_LENGTH, SCC_MRBLR(%a1)
4171da177e4SLinus Torvalds	movel %d0, %d1
4181da177e4SLinus Torvalds	lsll #4, %d1			// D1 bits 7 and 6 = port
4191da177e4SLinus Torvalds	orl #1, %d1
4201da177e4SLinus Torvalds	movew %d1, CR			// Init SCC RX and TX params
4211da177e4SLinus Torvalds	wait_for_command
4221da177e4SLinus Torvalds
4231da177e4SLinus Torvalds	// TCI Tend ENR ENT
4241da177e4SLinus Torvalds	movew #0x001F, SCC_SCCM(%a2)	// TXE RXF BSY TXB RXB interrupts
4251da177e4SLinus Torvalds	orl #0x00000030, SCC_GSMR_L(%a2) // enable SCC
4261da177e4SLinus Torvaldsopen_port_ret:
4271da177e4SLinus Torvalds	rts
4281da177e4SLinus Torvalds
4291da177e4SLinus Torvalds
4301da177e4SLinus Torvalds/****************************** close port ****************************/
4311da177e4SLinus Torvalds
4321da177e4SLinus Torvaldsclose_port:				// D0 = 4 * port, D6 = doorbell to host
4331da177e4SLinus Torvalds	movel scc_reg_addr(%d0), %a0	// A0 = SCC_REGS address
4341da177e4SLinus Torvalds	clrw SCC_SCCM(%a0)		// no SCC interrupts
4351da177e4SLinus Torvalds	andl #0xFFFFFFCF, SCC_GSMR_L(%a0) // Disable ENT and ENR
4361da177e4SLinus Torvalds
4371da177e4SLinus Torvalds	andw #~STATUS_CABLE_DTR, csr_output(%d0) // DTR off
4381da177e4SLinus Torvalds	bsr check_csr			// call with disabled timer interrupt
4391da177e4SLinus Torvalds
4401da177e4SLinus Torvalds	movel ch_status_addr(%d0), %d1
4411da177e4SLinus Torvalds	clrl STATUS_OPEN(%d1)		// confirm the port is closed
4421da177e4SLinus Torvalds	rts
4431da177e4SLinus Torvalds
4441da177e4SLinus Torvalds
4451da177e4SLinus Torvalds/****************************** transmit packet ***********************/
4461da177e4SLinus Torvalds// queue packets for transmission
4471da177e4SLinus Torvaldstx:					// D0 = 4 * port, D6 = doorbell to host
4481da177e4SLinus Torvalds	cmpl #TX_BUFFERS, tx_count(%d0)
4491da177e4SLinus Torvalds	beq tx_ret			// all DB's = descs in use
4501da177e4SLinus Torvalds
4511da177e4SLinus Torvalds	movel tx_out(%d0), %d1
4521da177e4SLinus Torvalds	movel %d1, %d2			// D1 = D2 = tx_out BD# = desc#
4531da177e4SLinus Torvalds	mulul #DESC_LENGTH, %d2		// D2 = TX desc offset
4541da177e4SLinus Torvalds	addl ch_status_addr(%d0), %d2
4551da177e4SLinus Torvalds	addl #STATUS_TX_DESCS, %d2	// D2 = TX desc address
4561da177e4SLinus Torvalds	cmpl #PACKET_FULL, (%d2)	// desc status
4571da177e4SLinus Torvalds	bne tx_ret
4581da177e4SLinus Torvalds
4591da177e4SLinus Torvalds// queue it
4601da177e4SLinus Torvalds	movel 4(%d2), %a0		// PCI address
4611da177e4SLinus Torvalds	lsll #3, %d1			// BD is 8-bytes long
4621da177e4SLinus Torvalds	addl tx_first_bd(%d0), %d1	// D1 = current tx_out BD addr
4631da177e4SLinus Torvalds
4641da177e4SLinus Torvalds	movel 4(%d1), %a1		// A1 = dest address
4651da177e4SLinus Torvalds	movel 8(%d2), %d2		// D2 = length
4661da177e4SLinus Torvalds	movew %d2, 2(%d1)		// length into BD
4671da177e4SLinus Torvalds	memcpy_from_pci %a0, %a1, %d2
4681da177e4SLinus Torvalds	bsetl #31, (%d1)		// CP go ahead
4691da177e4SLinus Torvalds
4701da177e4SLinus Torvalds// update tx_out and tx_count
4711da177e4SLinus Torvalds	movel tx_out(%d0), %d1
4721da177e4SLinus Torvalds	addl #1, %d1
4731da177e4SLinus Torvalds	cmpl #TX_BUFFERS, %d1
4741da177e4SLinus Torvalds	bne tx_1
4751da177e4SLinus Torvalds	clrl %d1
4761da177e4SLinus Torvaldstx_1:	movel %d1, tx_out(%d0)
4771da177e4SLinus Torvalds
4781da177e4SLinus Torvalds	addl #1, tx_count(%d0)
4791da177e4SLinus Torvalds	bra tx
4801da177e4SLinus Torvalds
4811da177e4SLinus Torvaldstx_ret: rts
4821da177e4SLinus Torvalds
4831da177e4SLinus Torvalds
4841da177e4SLinus Torvalds/****************************** packet received ***********************/
4851da177e4SLinus Torvalds
4861da177e4SLinus Torvalds// Service receive buffers		// D0 = 4 * port, D6 = doorbell to host
4871da177e4SLinus Torvaldsrx:	movel rx_in(%d0), %d1		// D1 = rx_in BD#
4881da177e4SLinus Torvalds	lsll #3, %d1			// BD is 8-bytes long
4891da177e4SLinus Torvalds	addl rx_first_bd(%d0), %d1	// D1 = current rx_in BD address
4901da177e4SLinus Torvalds	movew (%d1), %d2		// D2 = RX BD flags
4911da177e4SLinus Torvalds	btstl #15, %d2
4921da177e4SLinus Torvalds	bne rx_ret			// BD still empty
4931da177e4SLinus Torvalds
4941da177e4SLinus Torvalds	btstl #1, %d2
4951da177e4SLinus Torvalds	bne rx_overrun
4961da177e4SLinus Torvalds
4971da177e4SLinus Torvalds	tstw parity_bytes(%d0)
4981da177e4SLinus Torvalds	bne rx_parity
4991da177e4SLinus Torvalds	bclrl #2, %d2			// do not test for CRC errors
5001da177e4SLinus Torvaldsrx_parity:
5011da177e4SLinus Torvalds	andw #0x0CBC, %d2		// mask status bits
5021da177e4SLinus Torvalds	cmpw #0x0C00, %d2		// correct frame
5031da177e4SLinus Torvalds	bne rx_bad_frame
5041da177e4SLinus Torvalds	clrl %d3
5051da177e4SLinus Torvalds	movew 2(%d1), %d3
5061da177e4SLinus Torvalds	subw parity_bytes(%d0), %d3	// D3 = packet length
5071da177e4SLinus Torvalds	cmpw #HDLC_MAX_MRU, %d3
5081da177e4SLinus Torvalds	bgt rx_bad_frame
5091da177e4SLinus Torvalds
5101da177e4SLinus Torvaldsrx_good_frame:
5111da177e4SLinus Torvalds	movel rx_out, %d2
5121da177e4SLinus Torvalds	mulul #DESC_LENGTH, %d2
5131da177e4SLinus Torvalds	addl rx_descs_addr, %d2		// D2 = RX desc address
5141da177e4SLinus Torvalds	cmpl #PACKET_EMPTY, (%d2)	// desc stat
5151da177e4SLinus Torvalds	bne rx_overrun
5161da177e4SLinus Torvalds
5171da177e4SLinus Torvalds	movel %d3, 8(%d2)
5181da177e4SLinus Torvalds	movel 4(%d1), %a0		// A0 = source address
5191da177e4SLinus Torvalds	movel 4(%d2), %a1
5201da177e4SLinus Torvalds	tstl %a1
5211da177e4SLinus Torvalds	beq rx_ignore_data
5221da177e4SLinus Torvalds	memcpy_to_pci %a0, %a1, %d3
5231da177e4SLinus Torvaldsrx_ignore_data:
5241da177e4SLinus Torvalds	movel packet_full(%d0), (%d2)	// update desc stat
5251da177e4SLinus Torvalds
5261da177e4SLinus Torvalds// update D6 and rx_out
5271da177e4SLinus Torvalds	bsetl #DOORBELL_FROM_CARD_RX, %d6 // signal host that RX completed
5281da177e4SLinus Torvalds	movel rx_out, %d2
5291da177e4SLinus Torvalds	addl #1, %d2
5301da177e4SLinus Torvalds	cmpl #RX_QUEUE_LENGTH, %d2
5311da177e4SLinus Torvalds	bne rx_1
5321da177e4SLinus Torvalds	clrl %d2
5331da177e4SLinus Torvaldsrx_1:	movel %d2, rx_out
5341da177e4SLinus Torvalds
5351da177e4SLinus Torvaldsrx_free_bd:
5361da177e4SLinus Torvalds	andw #0xF000, (%d1)		// clear CM and error bits
5371da177e4SLinus Torvalds	bsetl #31, (%d1)		// free BD
5381da177e4SLinus Torvalds// update rx_in
5391da177e4SLinus Torvalds	movel rx_in(%d0), %d1
5401da177e4SLinus Torvalds	addl #1, %d1
5411da177e4SLinus Torvalds	cmpl #RX_BUFFERS, %d1
5421da177e4SLinus Torvalds	bne rx_2
5431da177e4SLinus Torvalds	clrl %d1
5441da177e4SLinus Torvaldsrx_2:	movel %d1, rx_in(%d0)
5451da177e4SLinus Torvalds	bra rx
5461da177e4SLinus Torvalds
5471da177e4SLinus Torvaldsrx_overrun:
5481da177e4SLinus Torvalds	movel ch_status_addr(%d0), %d2
5491da177e4SLinus Torvalds	addl #1, STATUS_RX_OVERRUNS(%d2)
5501da177e4SLinus Torvalds	bra rx_free_bd
5511da177e4SLinus Torvalds
5521da177e4SLinus Torvaldsrx_bad_frame:
5531da177e4SLinus Torvalds	movel ch_status_addr(%d0), %d2
5541da177e4SLinus Torvalds	addl #1, STATUS_RX_FRAME_ERRORS(%d2)
5551da177e4SLinus Torvalds	bra rx_free_bd
5561da177e4SLinus Torvalds
5571da177e4SLinus Torvaldsrx_ret: rts
5581da177e4SLinus Torvalds
5591da177e4SLinus Torvalds
5601da177e4SLinus Torvalds/****************************** packet transmitted ********************/
5611da177e4SLinus Torvalds
5621da177e4SLinus Torvalds// Service transmit buffers		// D0 = 4 * port, D6 = doorbell to host
5631da177e4SLinus Torvaldstx_end:	tstl tx_count(%d0)
5641da177e4SLinus Torvalds	beq tx_end_ret			// TX buffers already empty
5651da177e4SLinus Torvalds
5661da177e4SLinus Torvalds	movel tx_in(%d0), %d1
5671da177e4SLinus Torvalds	movel %d1, %d2			// D1 = D2 = tx_in BD# = desc#
5681da177e4SLinus Torvalds	lsll #3, %d1			// BD is 8-bytes long
5691da177e4SLinus Torvalds	addl tx_first_bd(%d0), %d1	// D1 = current tx_in BD address
5701da177e4SLinus Torvalds	movew (%d1), %d3		// D3 = TX BD flags
5711da177e4SLinus Torvalds	btstl #15, %d3
5721da177e4SLinus Torvalds	bne tx_end_ret			// BD still being transmitted
5731da177e4SLinus Torvalds
5741da177e4SLinus Torvalds// update D6, tx_in and tx_count
5751da177e4SLinus Torvalds	orl bell_tx(%d0), %d6		// signal host that TX desc freed
5761da177e4SLinus Torvalds	subl #1, tx_count(%d0)
5771da177e4SLinus Torvalds	movel tx_in(%d0), %d1
5781da177e4SLinus Torvalds	addl #1, %d1
5791da177e4SLinus Torvalds	cmpl #TX_BUFFERS, %d1
5801da177e4SLinus Torvalds	bne tx_end_1
5811da177e4SLinus Torvalds	clrl %d1
5821da177e4SLinus Torvaldstx_end_1:
5831da177e4SLinus Torvalds	movel %d1, tx_in(%d0)
5841da177e4SLinus Torvalds
5851da177e4SLinus Torvalds// free host's descriptor
5861da177e4SLinus Torvalds	mulul #DESC_LENGTH, %d2		// D2 = TX desc offset
5871da177e4SLinus Torvalds	addl ch_status_addr(%d0), %d2
5881da177e4SLinus Torvalds	addl #STATUS_TX_DESCS, %d2	// D2 = TX desc address
5891da177e4SLinus Torvalds	btstl #1, %d3
5901da177e4SLinus Torvalds	bne tx_end_underrun
5911da177e4SLinus Torvalds	movel #PACKET_SENT, (%d2)
5921da177e4SLinus Torvalds	bra tx_end
5931da177e4SLinus Torvalds
5941da177e4SLinus Torvaldstx_end_underrun:
5951da177e4SLinus Torvalds	movel #PACKET_UNDERRUN, (%d2)
5961da177e4SLinus Torvalds	bra tx_end
5971da177e4SLinus Torvalds
5981da177e4SLinus Torvaldstx_end_ret: rts
5991da177e4SLinus Torvalds
6001da177e4SLinus Torvalds
6011da177e4SLinus Torvalds/****************************** PLX PCI9060 DMA memcpy ****************/
6021da177e4SLinus Torvalds
6031da177e4SLinus Torvalds#if QUICC_MEMCPY_USES_PLX
6041da177e4SLinus Torvalds// called with interrupts disabled
6051da177e4SLinus Torvaldsmemcpy_from_pci_run:
6061da177e4SLinus Torvalds	movel %d0, -(%sp)
6071da177e4SLinus Torvalds	movew %sr, -(%sp)
6081da177e4SLinus Torvaldsmemcpy_1:
6091da177e4SLinus Torvalds	movel PLX_DMA_CMD_STS, %d0	// do not btst PLX register directly
6101da177e4SLinus Torvalds	btstl #4, %d0			// transfer done?
6111da177e4SLinus Torvalds	bne memcpy_end
6121da177e4SLinus Torvalds	stop #0x2200			// enable PCI9060 interrupts
6131da177e4SLinus Torvalds	movew #0x2700, %sr		// disable interrupts again
6141da177e4SLinus Torvalds	bra memcpy_1
6151da177e4SLinus Torvalds
6161da177e4SLinus Torvaldsmemcpy_to_pci_run:
6171da177e4SLinus Torvalds	movel %d0, -(%sp)
6181da177e4SLinus Torvalds	movew %sr, -(%sp)
6191da177e4SLinus Torvaldsmemcpy_2:
6201da177e4SLinus Torvalds	movel PLX_DMA_CMD_STS, %d0	// do not btst PLX register directly
6211da177e4SLinus Torvalds	btstl #12, %d0			// transfer done?
6221da177e4SLinus Torvalds	bne memcpy_end
6231da177e4SLinus Torvalds	stop #0x2200			// enable PCI9060 interrupts
6241da177e4SLinus Torvalds	movew #0x2700, %sr		// disable interrupts again
6251da177e4SLinus Torvalds	bra memcpy_2
6261da177e4SLinus Torvalds
6271da177e4SLinus Torvaldsmemcpy_end:
6281da177e4SLinus Torvalds	movew (%sp)+, %sr
6291da177e4SLinus Torvalds	movel (%sp)+, %d0
6301da177e4SLinus Torvalds	rts
6311da177e4SLinus Torvalds#endif
6321da177e4SLinus Torvalds
6331da177e4SLinus Torvalds
6341da177e4SLinus Torvalds
6351da177e4SLinus Torvalds
6361da177e4SLinus Torvalds
6371da177e4SLinus Torvalds
6381da177e4SLinus Torvalds/****************************** PLX PCI9060 interrupt *****************/
6391da177e4SLinus Torvalds
6401da177e4SLinus Torvaldspci9060_interrupt:
6411da177e4SLinus Torvalds	movel %d0, -(%sp)
6421da177e4SLinus Torvalds
6431da177e4SLinus Torvalds	movel PLX_DOORBELL_TO_CARD, %d0
6441da177e4SLinus Torvalds	movel %d0, PLX_DOORBELL_TO_CARD	// confirm all requests
6451da177e4SLinus Torvalds	orl %d0, channel_stats
6461da177e4SLinus Torvalds
6471da177e4SLinus Torvalds	movel #0x0909, PLX_DMA_CMD_STS	// clear DMA ch #0 and #1 interrupts
6481da177e4SLinus Torvalds
6491da177e4SLinus Torvalds	movel (%sp)+, %d0
6501da177e4SLinus Torvalds	rte
6511da177e4SLinus Torvalds
6521da177e4SLinus Torvalds/****************************** SCC interrupts ************************/
6531da177e4SLinus Torvalds
6541da177e4SLinus Torvaldsport_interrupt_1:
6551da177e4SLinus Torvalds	orl #0, SCC1_REGS + SCC_SCCE; // confirm SCC events
6561da177e4SLinus Torvalds	orl #1 << TASK_SCC_0, channel_stats
6571da177e4SLinus Torvalds	movel #0x40000000, CISR
6581da177e4SLinus Torvalds	rte
6591da177e4SLinus Torvalds
6601da177e4SLinus Torvaldsport_interrupt_2:
6611da177e4SLinus Torvalds	orl #0, SCC2_REGS + SCC_SCCE; // confirm SCC events
6621da177e4SLinus Torvalds	orl #1 << TASK_SCC_1, channel_stats
6631da177e4SLinus Torvalds	movel #0x20000000, CISR
6641da177e4SLinus Torvalds	rte
6651da177e4SLinus Torvalds
6661da177e4SLinus Torvaldsport_interrupt_3:
6671da177e4SLinus Torvalds	orl #0, SCC3_REGS + SCC_SCCE; // confirm SCC events
6681da177e4SLinus Torvalds	orl #1 << TASK_SCC_2, channel_stats
6691da177e4SLinus Torvalds	movel #0x10000000, CISR
6701da177e4SLinus Torvalds	rte
6711da177e4SLinus Torvalds
6721da177e4SLinus Torvaldsport_interrupt_4:
6731da177e4SLinus Torvalds	orl #0, SCC4_REGS + SCC_SCCE; // confirm SCC events
6741da177e4SLinus Torvalds	orl #1 << TASK_SCC_3, channel_stats
6751da177e4SLinus Torvalds	movel #0x08000000, CISR
6761da177e4SLinus Torvalds	rte
6771da177e4SLinus Torvalds
6781da177e4SLinus Torvaldserror_interrupt:
6791da177e4SLinus Torvalds	rte
6801da177e4SLinus Torvalds
6811da177e4SLinus Torvalds
6821da177e4SLinus Torvalds/****************************** cable and PM routine ******************/
6831da177e4SLinus Torvalds// modified registers: none
6841da177e4SLinus Torvaldscheck_csr:
6851da177e4SLinus Torvalds	movel %d0, -(%sp)
6861da177e4SLinus Torvalds	movel %d1, -(%sp)
6871da177e4SLinus Torvalds	movel %d2, -(%sp)
6881da177e4SLinus Torvalds	movel %a0, -(%sp)
6891da177e4SLinus Torvalds	movel %a1, -(%sp)
6901da177e4SLinus Torvalds
6911da177e4SLinus Torvalds	clrl %d0			// D0 = 4 * port
6921da177e4SLinus Torvalds	movel #CSRA, %a0		// A0 = CSR address
6931da177e4SLinus Torvalds
6941da177e4SLinus Torvaldscheck_csr_loop:
6951da177e4SLinus Torvalds	movew (%a0), %d1		// D1 = CSR input bits
6961da177e4SLinus Torvalds	andl #0xE7, %d1			// PM and cable sense bits (no DCE bit)
6971da177e4SLinus Torvalds	cmpw #STATUS_CABLE_V35 * (1 + 1 << STATUS_CABLE_PM_SHIFT), %d1
6981da177e4SLinus Torvalds	bne check_csr_1
6991da177e4SLinus Torvalds	movew #0x0E08, %d1
7001da177e4SLinus Torvalds	bra check_csr_valid
7011da177e4SLinus Torvalds
7021da177e4SLinus Torvaldscheck_csr_1:
7031da177e4SLinus Torvalds	cmpw #STATUS_CABLE_X21 * (1 + 1 << STATUS_CABLE_PM_SHIFT), %d1
7041da177e4SLinus Torvalds	bne check_csr_2
7051da177e4SLinus Torvalds	movew #0x0408, %d1
7061da177e4SLinus Torvalds	bra check_csr_valid
7071da177e4SLinus Torvalds
7081da177e4SLinus Torvaldscheck_csr_2:
7091da177e4SLinus Torvalds	cmpw #STATUS_CABLE_V24 * (1 + 1 << STATUS_CABLE_PM_SHIFT), %d1
7101da177e4SLinus Torvalds	bne check_csr_3
7111da177e4SLinus Torvalds	movew #0x0208, %d1
7121da177e4SLinus Torvalds	bra check_csr_valid
7131da177e4SLinus Torvalds
7141da177e4SLinus Torvaldscheck_csr_3:
7151da177e4SLinus Torvalds	cmpw #STATUS_CABLE_EIA530 * (1 + 1 << STATUS_CABLE_PM_SHIFT), %d1
7161da177e4SLinus Torvalds	bne check_csr_disable
7171da177e4SLinus Torvalds	movew #0x0D08, %d1
7181da177e4SLinus Torvalds	bra check_csr_valid
7191da177e4SLinus Torvalds
7201da177e4SLinus Torvaldscheck_csr_disable:
7211da177e4SLinus Torvalds	movew #0x0008, %d1		// D1 = disable everything
7221da177e4SLinus Torvalds	movew #0x80E7, %d2		// D2 = input mask: ignore DSR
7231da177e4SLinus Torvalds	bra check_csr_write
7241da177e4SLinus Torvalds
7251da177e4SLinus Torvaldscheck_csr_valid:			// D1 = mode and IRQ bits
7261da177e4SLinus Torvalds	movew csr_output(%d0), %d2
7271da177e4SLinus Torvalds	andw #0x3000, %d2		// D2 = requested LL and DTR bits
7281da177e4SLinus Torvalds	orw %d2, %d1			// D1 = all requested output bits
7291da177e4SLinus Torvalds	movew #0x80FF, %d2		// D2 = input mask: include DSR
7301da177e4SLinus Torvalds
7311da177e4SLinus Torvaldscheck_csr_write:
7321da177e4SLinus Torvalds	cmpw old_csr_output(%d0), %d1
7331da177e4SLinus Torvalds	beq check_csr_input
7341da177e4SLinus Torvalds	movew %d1, old_csr_output(%d0)
7351da177e4SLinus Torvalds	movew %d1, (%a0)		// Write CSR output bits
7361da177e4SLinus Torvalds
7371da177e4SLinus Torvaldscheck_csr_input:
7381da177e4SLinus Torvalds	movew (PCDAT), %d1
7391da177e4SLinus Torvalds	andw dcd_mask(%d0), %d1
7401da177e4SLinus Torvalds	beq check_csr_dcd_on		// DCD and CTS signals are negated
7411da177e4SLinus Torvalds	movew (%a0), %d1		// D1 = CSR input bits
7421da177e4SLinus Torvalds	andw #~STATUS_CABLE_DCD, %d1	// DCD off
7431da177e4SLinus Torvalds	bra check_csr_previous
7441da177e4SLinus Torvalds
7451da177e4SLinus Torvaldscheck_csr_dcd_on:
7461da177e4SLinus Torvalds	movew (%a0), %d1		// D1 = CSR input bits
7471da177e4SLinus Torvalds	orw #STATUS_CABLE_DCD, %d1	// DCD on
7481da177e4SLinus Torvaldscheck_csr_previous:
7491da177e4SLinus Torvalds	andw %d2, %d1			// input mask
7501da177e4SLinus Torvalds	movel ch_status_addr(%d0), %a1
7511da177e4SLinus Torvalds	cmpl STATUS_CABLE(%a1), %d1	// check for change
7521da177e4SLinus Torvalds	beq check_csr_next
7531da177e4SLinus Torvalds	movel %d1, STATUS_CABLE(%a1)	// update status
7541da177e4SLinus Torvalds	movel bell_cable(%d0), PLX_DOORBELL_FROM_CARD	// signal the host
7551da177e4SLinus Torvalds
7561da177e4SLinus Torvaldscheck_csr_next:
7571da177e4SLinus Torvalds	addl #2, %a0			// next CSR register
7581da177e4SLinus Torvalds	addl #4, %d0			// D0 = 4 * next port
7591da177e4SLinus Torvalds	cmpl #4 * 4, %d0
7601da177e4SLinus Torvalds	bne check_csr_loop
7611da177e4SLinus Torvalds
7621da177e4SLinus Torvalds	movel (%sp)+, %a1
7631da177e4SLinus Torvalds	movel (%sp)+, %a0
7641da177e4SLinus Torvalds	movel (%sp)+, %d2
7651da177e4SLinus Torvalds	movel (%sp)+, %d1
7661da177e4SLinus Torvalds	movel (%sp)+, %d0
7671da177e4SLinus Torvalds	rts
7681da177e4SLinus Torvalds
7691da177e4SLinus Torvalds
7701da177e4SLinus Torvalds/****************************** timer interrupt ***********************/
7711da177e4SLinus Torvalds
7721da177e4SLinus Torvaldstimer_interrupt:
7731da177e4SLinus Torvalds	bsr check_csr
7741da177e4SLinus Torvalds	rte
7751da177e4SLinus Torvalds
7761da177e4SLinus Torvalds
7771da177e4SLinus Torvalds/****************************** RAM sizing and test *******************/
7781da177e4SLinus Torvalds#if DETECT_RAM
7791da177e4SLinus Torvaldsram_test:
7801da177e4SLinus Torvalds	movel #0x12345678, %d1		// D1 = test value
7811da177e4SLinus Torvalds	movel %d1, (128 * 1024 - 4)
7821da177e4SLinus Torvalds	movel #128 * 1024, %d0		// D0 = RAM size tested
7831da177e4SLinus Torvaldsram_test_size:
7841da177e4SLinus Torvalds	cmpl #MAX_RAM_SIZE, %d0
7851da177e4SLinus Torvalds	beq ram_test_size_found
7861da177e4SLinus Torvalds	movel %d0, %a0
7871da177e4SLinus Torvalds	addl #128 * 1024 - 4, %a0
7881da177e4SLinus Torvalds	cmpl (%a0), %d1
7891da177e4SLinus Torvalds	beq ram_test_size_check
7901da177e4SLinus Torvaldsram_test_next_size:
7911da177e4SLinus Torvalds	lsll #1, %d0
7921da177e4SLinus Torvalds	bra ram_test_size
7931da177e4SLinus Torvalds
7941da177e4SLinus Torvaldsram_test_size_check:
7951da177e4SLinus Torvalds	eorl #0xFFFFFFFF, %d1
7961da177e4SLinus Torvalds	movel %d1, (128 * 1024 - 4)
7971da177e4SLinus Torvalds	cmpl (%a0), %d1
7981da177e4SLinus Torvalds	bne ram_test_next_size
7991da177e4SLinus Torvalds
8001da177e4SLinus Torvaldsram_test_size_found:			// D0 = RAM size
8011da177e4SLinus Torvalds	movel %d0, %a0			// A0 = fill ptr
8021da177e4SLinus Torvalds	subl #firmware_end + 4, %d0
8031da177e4SLinus Torvalds	lsrl #2, %d0
8041da177e4SLinus Torvalds	movel %d0, %d1			// D1 = DBf counter
8051da177e4SLinus Torvaldsram_test_fill:
8061da177e4SLinus Torvalds	movel %a0, -(%a0)
8071da177e4SLinus Torvalds	dbfw %d1, ram_test_fill
8081da177e4SLinus Torvalds	subl #0x10000, %d1
8091da177e4SLinus Torvalds	cmpl #0xFFFFFFFF, %d1
8101da177e4SLinus Torvalds	bne ram_test_fill
8111da177e4SLinus Torvalds
8121da177e4SLinus Torvaldsram_test_loop:				// D0 = DBf counter
8131da177e4SLinus Torvalds	cmpl (%a0)+, %a0
8141da177e4SLinus Torvalds	dbnew %d0, ram_test_loop
8151da177e4SLinus Torvalds	bne ram_test_found_bad
8161da177e4SLinus Torvalds	subl #0x10000, %d0
8171da177e4SLinus Torvalds	cmpl #0xFFFFFFFF, %d0
8181da177e4SLinus Torvalds	bne ram_test_loop
8191da177e4SLinus Torvalds	bra ram_test_all_ok
8201da177e4SLinus Torvalds
8211da177e4SLinus Torvaldsram_test_found_bad:
8221da177e4SLinus Torvalds	subl #4, %a0
8231da177e4SLinus Torvaldsram_test_all_ok:
8241da177e4SLinus Torvalds	movel %a0, PLX_MAILBOX_5
8251da177e4SLinus Torvalds	rts
8261da177e4SLinus Torvalds#endif
8271da177e4SLinus Torvalds
8281da177e4SLinus Torvalds
8291da177e4SLinus Torvalds/****************************** constants *****************************/
8301da177e4SLinus Torvalds
8311da177e4SLinus Torvaldsscc_reg_addr:
8321da177e4SLinus Torvalds	.long SCC1_REGS, SCC2_REGS, SCC3_REGS, SCC4_REGS
8331da177e4SLinus Torvaldsscc_base_addr:
8341da177e4SLinus Torvalds	.long SCC1_BASE, SCC2_BASE, SCC3_BASE, SCC4_BASE
8351da177e4SLinus Torvalds
8361da177e4SLinus Torvaldstx_first_bd:
8371da177e4SLinus Torvalds	.long DPRBASE
8381da177e4SLinus Torvalds	.long DPRBASE + (TX_BUFFERS + RX_BUFFERS) * 8
8391da177e4SLinus Torvalds	.long DPRBASE + (TX_BUFFERS + RX_BUFFERS) * 8 * 2
8401da177e4SLinus Torvalds	.long DPRBASE + (TX_BUFFERS + RX_BUFFERS) * 8 * 3
8411da177e4SLinus Torvalds
8421da177e4SLinus Torvaldsrx_first_bd:
8431da177e4SLinus Torvalds	.long DPRBASE + TX_BUFFERS * 8
8441da177e4SLinus Torvalds	.long DPRBASE + TX_BUFFERS * 8 + (TX_BUFFERS + RX_BUFFERS) * 8
8451da177e4SLinus Torvalds	.long DPRBASE + TX_BUFFERS * 8 + (TX_BUFFERS + RX_BUFFERS) * 8 * 2
8461da177e4SLinus Torvalds	.long DPRBASE + TX_BUFFERS * 8 + (TX_BUFFERS + RX_BUFFERS) * 8 * 3
8471da177e4SLinus Torvalds
8481da177e4SLinus Torvaldsfirst_buffer:
8491da177e4SLinus Torvalds	.long BUFFERS_ADDR
8501da177e4SLinus Torvalds	.long BUFFERS_ADDR + (TX_BUFFERS + RX_BUFFERS) * BUFFER_LENGTH
8511da177e4SLinus Torvalds	.long BUFFERS_ADDR + (TX_BUFFERS + RX_BUFFERS) * BUFFER_LENGTH * 2
8521da177e4SLinus Torvalds	.long BUFFERS_ADDR + (TX_BUFFERS + RX_BUFFERS) * BUFFER_LENGTH * 3
8531da177e4SLinus Torvalds
8541da177e4SLinus Torvaldsbell_tx:
8551da177e4SLinus Torvalds	.long 1 << DOORBELL_FROM_CARD_TX_0, 1 << DOORBELL_FROM_CARD_TX_1
8561da177e4SLinus Torvalds	.long 1 << DOORBELL_FROM_CARD_TX_2, 1 << DOORBELL_FROM_CARD_TX_3
8571da177e4SLinus Torvalds
8581da177e4SLinus Torvaldsbell_cable:
8591da177e4SLinus Torvalds	.long 1 << DOORBELL_FROM_CARD_CABLE_0, 1 << DOORBELL_FROM_CARD_CABLE_1
8601da177e4SLinus Torvalds	.long 1 << DOORBELL_FROM_CARD_CABLE_2, 1 << DOORBELL_FROM_CARD_CABLE_3
8611da177e4SLinus Torvalds
8621da177e4SLinus Torvaldspacket_full:
8631da177e4SLinus Torvalds	.long PACKET_FULL, PACKET_FULL + 1, PACKET_FULL + 2, PACKET_FULL + 3
8641da177e4SLinus Torvalds
8651da177e4SLinus Torvaldsclocking_ext:
8661da177e4SLinus Torvalds	.long 0x0000002C, 0x00003E00, 0x002C0000, 0x3E000000
8671da177e4SLinus Torvaldsclocking_txfromrx:
8681da177e4SLinus Torvalds	.long 0x0000002D, 0x00003F00, 0x002D0000, 0x3F000000
8691da177e4SLinus Torvaldsclocking_mask:
8701da177e4SLinus Torvalds	.long 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000
8711da177e4SLinus Torvaldsdcd_mask:
8721da177e4SLinus Torvalds	.word 0x020, 0, 0x080, 0, 0x200, 0, 0x800
8731da177e4SLinus Torvalds
8741da177e4SLinus Torvalds	.ascii "wanXL firmware\n"
8751da177e4SLinus Torvalds	.asciz "Copyright (C) 2003 Krzysztof Halasa <khc@pm.waw.pl>\n"
8761da177e4SLinus Torvalds
8771da177e4SLinus Torvalds
8781da177e4SLinus Torvalds/****************************** variables *****************************/
8791da177e4SLinus Torvalds
8801da177e4SLinus Torvalds		.align 4
8811da177e4SLinus Torvaldschannel_stats:	.long 0
8821da177e4SLinus Torvalds
8831da177e4SLinus Torvaldstx_in:		.long 0, 0, 0, 0	// transmitted
8841da177e4SLinus Torvaldstx_out:		.long 0, 0, 0, 0	// received from host for transmission
8851da177e4SLinus Torvaldstx_count:	.long 0, 0, 0, 0	// currently in transmit queue
8861da177e4SLinus Torvalds
8871da177e4SLinus Torvaldsrx_in:		.long 0, 0, 0, 0	// received from port
8881da177e4SLinus Torvaldsrx_out:		.long 0			// transmitted to host
8891da177e4SLinus Torvaldsparity_bytes:	.word 0, 0, 0, 0, 0, 0, 0 // only 4 words are used
8901da177e4SLinus Torvalds
8911da177e4SLinus Torvaldscsr_output:	.word 0
8921da177e4SLinus Torvaldsold_csr_output:	.word 0, 0, 0, 0, 0, 0, 0
8931da177e4SLinus Torvalds		.align 4
8941da177e4SLinus Torvaldsfirmware_end:				// must be dword-aligned
895