blob: c90cbd41ce21e34ada85d39689bd348df0a48c7d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001@ Read/Write DMA code for the ST506/MFM hard drive controllers on the A400 Acorn Archimedes
2@ motherboard and on ST506 expansion podules.
3@ (c) David Alan Gilbert (linux@treblig.org) 1996-1999
4
5#include <asm/assembler.h>
6
7hdc63463_irqdata:
8@ Controller base address
9 .global hdc63463_baseaddress
10hdc63463_baseaddress:
11 .word 0
12
13 .global hdc63463_irqpolladdress
14hdc63463_irqpolladdress:
15 .word 0
16
17 .global hdc63463_irqpollmask
18hdc63463_irqpollmask:
19 .word 0
20
21@ where to read/write data from the kernel data space
22 .global hdc63463_dataptr
23hdc63463_dataptr:
24 .word 0
25
26@ Number of bytes left to transfer
27 .global hdc63463_dataleft
28hdc63463_dataleft:
29 .word 0
30
31@ -------------------------------------------------------------------------
32@ hdc63463_writedma: DMA from host to controller
33@ internal reg usage: r0=hdc base address, r1=irq poll address, r2=poll mask
34@ r3=data ptr, r4=data left, r5,r6=temporary
35 .global hdc63463_writedma
36hdc63463_writedma:
37 stmfd sp!,{r4-r7}
38 adr r5,hdc63463_irqdata
39 ldmia r5,{r0,r1,r2,r3,r4}
40
41writedma_again:
42
43 @ test number of remaining bytes to transfer
44 cmp r4,#0
45 beq writedma_end
46 bmi writedma_end
47
48 @ Check the hdc is interrupting
49 ldrb r5,[r1,#0]
50 tst r5,r2
51 beq writedma_end
52
53 @ Transfer a block of upto 256 bytes
54 cmp r4,#256
55 movlt r7,r4
56 movge r7,#256
57
58 @ Check the hdc is still busy and command has not ended and no errors
59 ldr r5,[r0,#32] @ Status reg - 16 bit - its the top few bits which are status
60 @ think we should continue DMA until it drops busy - perhaps this was
61 @ the main problem with corrected errors causing a hang
62 @tst r5,#0x3c00 @ Test for things which should be off
63 @bne writedma_end
64 and r5,r5,#0x8000 @ This is test for things which should be on: Busy
65 cmp r5,#0x8000
66 bne writedma_end
67
68 @ Bytes remaining at end
69 sub r4,r4,r7
70
71 @ HDC Write register location
72 add r0,r0,#32+8
73
74writedma_loop:
75 @ OK - pretty sure we should be doing this
76
77 ldr r5,[r3],#4 @ Get a word to be written
78 @ get bottom half to be sent first
79 mov r6,r5,lsl#16 @ Separate the first 2 bytes
80 orr r2,r6,r6,lsr #16 @ Duplicate them in the bottom half of the word
81 @ now the top half
82 mov r6,r5,lsr#16 @ Get 2nd 2 bytes
83 orr r6,r6,r6,lsl#16 @ Duplicate
84 @str r6,[r0] @ to hdc
85 stmia r0,{r2,r6}
86 subs r7,r7,#4 @ Dec. number of bytes left
87 bne writedma_loop
88
89 @ If we were too slow we had better go through again - DAG - took out with new interrupt routine
90 @ sub r0,r0,#32+8
91 @ adr r2,hdc63463_irqdata
92 @ ldr r2,[r2,#8]
93 @ b writedma_again
94
95writedma_end:
96 adr r5,hdc63463_irqdata+12
97 stmia r5,{r3,r4}
98 ldmfd sp!,{r4-r7}
99 RETINSTR(mov,pc,lr)
100
101@ -------------------------------------------------------------------------
102@ hdc63463_readdma: DMA from controller to host
103@ internal reg usage: r0=hdc base address, r1=irq poll address, r2=poll mask
104@ r3=data ptr, r4=data left, r5,r6=temporary
105 .global hdc63463_readdma
106hdc63463_readdma:
107 stmfd sp!,{r4-r7}
108 adr r5,hdc63463_irqdata
109 ldmia r5,{r0,r1,r2,r3,r4}
110
111readdma_again:
112 @ test number of remaining bytes to transfer
113 cmp r4,#0
114 beq readdma_end
115 bmi readdma_end
116
117 @ Check the hdc is interrupting
118 ldrb r5,[r1,#0]
119 tst r5,r2
120 beq readdma_end
121
122 @ Check the hdc is still busy and command has not ended and no errors
123 ldr r5,[r0,#32] @ Status reg - 16 bit - its the top few bits which are status
124 @ think we should continue DMA until it drops busy - perhaps this was
125 @ the main problem with corrected errors causing a hang
126 @tst r5,#0x3c00 @ Test for things which should be off
127 @bne readdma_end
128 and r5,r5,#0x8000 @ This is test for things which should be on: Busy
129 cmp r5,#0x8000
130 bne readdma_end
131
132 @ Transfer a block of upto 256 bytes
133 cmp r4,#256
134 movlt r7,r4
135 movge r7,#256
136
137 @ Bytes remaining at end
138 sub r4,r4,r7
139
140 @ Set a pointer to the data register in the HDC
141 add r0,r0,#8
142readdma_loop:
143 @ OK - pretty sure we should be doing this
144 ldmia r0,{r5,r6}
145 mov r5,r5,lsl#16
146 mov r6,r6,lsl#16
147 orr r6,r6,r5,lsr #16
148 str r6,[r3],#4
149 subs r7,r7,#4 @ Decrement bytes to go
150 bne readdma_loop
151
152 @ Try reading multiple blocks - if this was fast enough then I do not think
153 @ this should help - NO taken out DAG - new interrupt handler has
154 @ non-consecutive memory blocks
155 @ sub r0,r0,#8
156 @ b readdma_again
157
158readdma_end:
159 adr r5,hdc63463_irqdata+12
160 stmia r5,{r3,r4}
161 ldmfd sp!,{r4-r7}
162 RETINSTR(mov,pc,lr)