1@ 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)
163