2 ;; Etrax100 slave network<->parport forwarder
4 ;; Copyright (c) 1999, 2000, 2001, 2002, 2003 Axis Communications AB
6 ;; We got 784 bytes (par loader size) to do DMA forwarding
7 ;; between DMA0/1 (ethernet) and DMA3/4 (par port 0 RX/1 TX)
10 #include <linux/config.h>
12 #define ASSEMBLER_MACROS_ONLY
14 #include <asm/sv_addr_ag.h>
27 #define PAR0ECPCMDBIT 11
31 #include "e100lpslave.h"
34 ;; disable interrupts. we are not going to use them at all.
38 ;; setup DMA connections and port configuration
40 movu.w 0x84, r0 ; DMA2/3/4/5 to par ports
41 move.d r0, [R_GEN_CONFIG]
43 ;; setup port PA dirs and turn on the LED to show were alive
45 movu.w 0x0cfb, r0 ; PA2-PA3 out, PA2 inactive
46 move.d r0, [R_PORT_PA_SET]
48 ;; enable MDIO output pin
49 moveq IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable), r0
50 move.d r0, [R_NETWORK_MGM_CTRL]
52 ;; accept broadcast frames, and enable station address 0
53 moveq IO_STATE(R_NETWORK_REC_CONFIG, broadcast, receive) | \
54 IO_STATE(R_NETWORK_REC_CONFIG, ma0, enable), r0
55 move.d r0, [R_NETWORK_REC_CONFIG]
57 ;; use MII CLK mode, and enable the controller
58 moveq IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) | \
59 IO_STATE(R_NETWORK_GEN_CONFIG, enable, on), r0
60 move.d r0, [R_NETWORK_GEN_CONFIG]
62 move.d IO_STATE(R_PAR0_CONFIG, ioe, noninv) | \
63 IO_STATE(R_PAR0_CONFIG, iseli, noninv) | \
64 IO_STATE(R_PAR0_CONFIG, iautofd, noninv) | \
65 IO_STATE(R_PAR0_CONFIG, istrb, noninv) | \
66 IO_STATE(R_PAR0_CONFIG, iinit, noninv) | \
67 IO_STATE(R_PAR0_CONFIG, iperr, noninv) | \
68 IO_STATE(R_PAR0_CONFIG, iack, noninv) | \
69 IO_STATE(R_PAR0_CONFIG, ibusy, noninv) | \
70 IO_STATE(R_PAR0_CONFIG, ifault, noninv) | \
71 IO_STATE(R_PAR0_CONFIG, isel, noninv) | \
72 IO_STATE(R_PAR0_CONFIG, dma, enable) | \
73 IO_STATE(R_PAR0_CONFIG, rle_in, disable) | \
74 IO_STATE(R_PAR0_CONFIG, rle_out, disable) | \
75 IO_STATE(R_PAR0_CONFIG, enable, on) | \
76 IO_STATE(R_PAR0_CONFIG, force, on) | \
77 IO_STATE(R_PAR0_CONFIG, mode, ecp_rev), r0 ; Reverse ECP - PAR0 is RX
79 move.d r0, [R_PAR0_CONFIG]
81 move.d IO_STATE(R_PAR1_CONFIG, ioe, noninv) | \
82 IO_STATE(R_PAR1_CONFIG, iseli, noninv) | \
83 IO_STATE(R_PAR1_CONFIG, iautofd, noninv) | \
84 IO_STATE(R_PAR1_CONFIG, istrb, noninv) | \
85 IO_STATE(R_PAR1_CONFIG, iinit, noninv) | \
86 IO_STATE(R_PAR1_CONFIG, iperr, inv) | \
87 IO_STATE(R_PAR1_CONFIG, iack, noninv) | \
88 IO_STATE(R_PAR1_CONFIG, ibusy, noninv) | \
89 IO_STATE(R_PAR1_CONFIG, ifault, noninv) | \
90 IO_STATE(R_PAR1_CONFIG, isel, noninv) | \
91 IO_STATE(R_PAR1_CONFIG, dma, enable) | \
92 IO_STATE(R_PAR1_CONFIG, rle_in, disable) | \
93 IO_STATE(R_PAR1_CONFIG, rle_out, disable) | \
94 IO_STATE(R_PAR1_CONFIG, enable, on) | \
95 IO_STATE(R_PAR1_CONFIG, force, on) | \
96 IO_STATE(R_PAR1_CONFIG, mode, ecp_fwd), r0 ; Forward ECP - PAR1 is TX
98 move.d r0, [R_PAR1_CONFIG]
100 moveq IO_FIELD(R_PAR1_DELAY, setup, 0), r0 ; setup time of value * 160 + 20 == 20 ns
101 move.d r0, [R_PAR1_DELAY]
103 ;; we got four descriptors, that can be active at the same time:
109 ;; we got four buffers, each can hold a max packet (we use 1536 bytes)
110 ;; buffers 1 and 2 are used from network to parport, while
111 ;; buffers 3 and 4 are used from parport to network.
113 ;; a double buffering scheme is used, so that new data can be read
114 ;; into a buffer pair while the last data is written out from the
115 ;; last buffer. if the read buffer is done before the write buffer,
116 ;; the reading will halt until the writing is done, at which point
117 ;; writing starts from the newly read and reading can start with
118 ;; the newly written.
121 move.d R_DMA_CH0_FIRST, r1 ; we use this as base for subsequent DMA ops
122 moveq IO_STATE(R_DMA_CH1_CMD, cmd, start), r6
124 move.d R_IRQ_READ0, r9
126 ;; start receiving from network
133 ;; ------------------- MAIN LOOP
135 ;; IRQ bits: parport rcv is par0_ecp_cmd, then dma3_eop
136 ;; network rcv is dma1_eop
137 ;; parport tx is dma4_desc
138 ;; network tx is dma0_eop
142 ;; ------- first handle the parport -> network link
144 ;; check if we got something from the parport
146 move.d [r9], r0 ; r0 <- *R_IRQ_READ0
147 btstq PAR0ECPCMDBIT, r0
151 ;; ack it by reading PAR0_STATUS_DATA
153 move.d [R_PAR0_STATUS_DATA], r0
155 ;; trigger EOP on DMA3 (par0 incoming channel)
157 moveq IO_STATE(R_SET_EOP, ch3_eop, set), r0
158 move.d r0, [R_SET_EOP]
162 ;; if we simultaneously have parport rx EOP and
163 ;; network TX eop, we can swap buffers and start a new RX/TX
165 move.d [r9 + (R_IRQ_READ2 - R_IRQ_READ0)], r0
166 btstq DMA3EOPBIT, r0 ; check parport rx
168 btstq DMA0EOPBIT, r0 ; check network tx
172 ;; prepare to swap buffer ptrs (FN3b <-> TN4b)
174 move.d [r4 = r7 + 56], r0; FP3b
175 move.d [r3 = r7 + 72], r2; TN4b
177 ;; but first check if this was a Host Command Packet
179 move.d [r0], r5 ; r5 <- first 4 bytes in PAR-received packet
180 bne handle_command ; if non-zero, it was a host command
181 addq 4, r0 ; skip command (in delay slot - handle_command requires this)
182 move.d r0, [r3] ; write to To Network descriptor
183 subq 4, r2 ; undo the skipping done last swap
184 move.d r2, [r4] ; write to From Parport descriptor
186 ;; clear the interrupts
188 moveq IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do), r0
189 move.b r0, [r1 + (R_DMA_CH0_CLR_INTR - R_DMA_CH0_FIRST)]
190 move.b r0, [r1 + (R_DMA_CH3_CLR_INTR - R_DMA_CH0_FIRST)]
192 ;; copy received length to outgoing network length
194 move.w [r7 + 60], r0 ; FPhlen
195 subq 4, r0 ; skip command
196 move.w r0, [r7 + 64] ; TN4desc
202 #ifdef CONFIG_ETRAX_ETHERNET_LPSLAVE_HAS_LEDS
203 #if defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK)
204 ;; Turn off the LED signaling an outgoing network packet
206 #elif defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY)
207 ;; Light the LED signaling an outgoing network packet
208 movu.b [LEDAmber], r0
210 #error "Define either CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK or CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY"
212 move.b r0, [R_PORT_PA_DATA]
213 move.d 0x00011000, r0
218 ;; ----- now check the network -> parport link
221 ;; if we simultaneously have network rx EOP and
222 ;; parport TX desc, we can swap buffers and start a new RX/TX
224 move.d [r9 + (R_IRQ_READ2 - R_IRQ_READ0)], r0
225 btstq DMA1EOPBIT, r0 ; check network rx
227 btstq DMA4DESCBIT, r0 ; check parport tx
231 ;; prepare to swap buffer ptrs (FP1b <-> TP2b)
233 move.d [r4 = r7 + 8], r0; FN1b
234 move.d [r3 = r7 + 24], r2; TP2b
235 move.d r0, [r3] ; write to To Parport descriptor
236 move.d r2, [r4] ; write to From Network descriptor
238 ;; clear the interrupts
240 moveq IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do) | \
241 IO_STATE(R_DMA_CH1_CLR_INTR, clr_descr, do), r0
242 move.b r0, [r1 + (R_DMA_CH1_CLR_INTR - R_DMA_CH0_FIRST)]
243 move.b r0, [r1 + (R_DMA_CH4_CLR_INTR - R_DMA_CH0_FIRST)]
245 ;; copy received network length to outgoing parport length
247 move.w [r7 + 12], r0 ; FNhlen
248 move.w r0, [r7 + 16] ; TP2desc
254 #ifdef CONFIG_ETRAX_ETHERNET_LPSLAVE_HAS_LEDS
255 ;; Light the LED signaling an incoming networkpacket
257 move.b r0, [R_PORT_PA_DATA]
258 move.d 0x00010000, r0
264 #ifdef CONFIG_ETRAX_ETHERNET_LPSLAVE_HAS_LEDS
266 ;; Count down LED counter, and turn off the network LED if required
267 move.d [LEDCount], r0
272 move.d r0, [LEDCount]
276 #if defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK)
277 ;; Light the network LED , and start over the main loop
278 movu.b [LEDAmber], r0
279 #elif defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY)
280 ;; Turn off the network LED, and start over the main loop
283 #error "Define either CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK or CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY"
285 move.b r0, [R_PORT_PA_DATA]
291 ;; --- some useful subroutines.
294 ;; handle command. we also need to clear the PAR0 RX EOP IRQ, and
295 ;; restart the PAR0 dma. command is in R5, packet after cmd is in R0
297 moveq IO_STATE(R_DMA_CH3_CLR_INTR, clr_eop, do), r2
298 move.b r2, [r1 + (R_DMA_CH3_CLR_INTR - R_DMA_CH0_FIRST)]
300 cmpq HOST_CMD_SETMAC, r5
304 ;; copy station address (6 bytes) from packet to hardware
307 move.d R_NETWORK_SA_0, r3
317 ;; start DMAs, from parport and to network
321 ;; start transmitting to the network (CH0)
324 move.d r8, [r1] ; TN4desc -> FIRST0
325 move.b r6, [r1 + (R_DMA_CH0_CMD - R_DMA_CH0_FIRST)] ; start -> CMD0
329 ;; start receiving from parport (CH3)
332 move.d r8, [r1 + (R_DMA_CH3_FIRST - R_DMA_CH0_FIRST)] ; FP3desc -> FIRST3
333 move.b r6, [r1 + (R_DMA_CH3_CMD - R_DMA_CH0_FIRST)] ; start -> CMD3
338 ;; start DMAs, from network and to parport
342 ;; start transmitting to the parport (CH4)
345 move.d r8, [r1 + (R_DMA_CH4_FIRST - R_DMA_CH0_FIRST)] ; TP2desc -> FIRST4
346 move.b r6, [r1 + (R_DMA_CH4_CMD - R_DMA_CH0_FIRST)] ; start -> CMD4
348 ;; start receiving from network (CH1) (r7 already contains FN1desc)
350 move.d r7, [r1 + (R_DMA_CH1_FIRST - R_DMA_CH0_FIRST)] ; FN1desc -> FIRST1
351 move.b r6, [r1 + (R_DMA_CH1_CMD - R_DMA_CH0_FIRST)] ; start -> CMD1
356 ;; --- DMA descriptors - each descriptor is 4 longwords (16 bytes)
357 ;; DONT MOVE THESE AROUND. Due to the as/ld "hole-in-the-head",
358 ;; we cant write stuff like (TP2b - TP2desc) but the offsets
359 ;; have to be hardcoded.
365 .word BUFSIZE ; sw_len
366 .word 0x0001 ; ctrl, d_eol is only flag we need
368 FN1b: .dword buffers ; buffer 1 8
374 .word 2 ; sw_len, filled in by code
375 .word 0x0004 ; ctrl, d_wait because ecp cmd in next
376 .dword TP2desc2 ; next
377 TP2b: .dword buffers + BUFSIZE ; buffer 2 24
381 ;; 32 to parport second descriptor, for the ECP command
383 .word 0x0001 ; sw_len, 1 byte (ecp command)
384 .word 0x0019 ; ctrl, d_ecp | d_eol | d_int
386 .dword TP2desc2 ; buffer, dont care
392 .word BUFSIZE ; sw_len
393 .word 0x0001 ; ctrl, d_eol is only flag we need
395 FP3b: .dword buffers + BUFSIZE * 2 ; 56 buffer 3
396 FPhlen: .word 0 ; 60 hw_len
401 .word 2 ; sw_len, filled in by code
402 .word 0x0007 ; ctrl, d_eop | d_eol | d_wait
404 TN4b: .dword buffers + BUFSIZE * 3 + 4 ; 72 buffer 4 (the +4 is to offset the anti-skipping)
408 #ifdef CONFIG_ETRAX_ETHERNET_LPSLAVE_HAS_LEDS
423 ;; after the prog we put the buffers. not in the asm program, we just use
424 ;; the address generated