Merge from Linus' tree.
[linux-2.6] / drivers / acorn / block / mfm.S
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  
7 hdc63463_irqdata:
8 @ Controller base address
9   .global hdc63463_baseaddress
10 hdc63463_baseaddress:
11   .word 0
12
13   .global hdc63463_irqpolladdress
14 hdc63463_irqpolladdress:
15   .word 0
16  
17   .global hdc63463_irqpollmask
18 hdc63463_irqpollmask:
19   .word 0
20
21 @ where to read/write data  from the kernel data space
22   .global hdc63463_dataptr
23 hdc63463_dataptr:
24   .word 0
25
26 @ Number of bytes left to transfer
27   .global hdc63463_dataleft
28 hdc63463_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
36 hdc63463_writedma:
37   stmfd sp!,{r4-r7}
38   adr r5,hdc63463_irqdata
39   ldmia r5,{r0,r1,r2,r3,r4}
40
41 writedma_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
74 writedma_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
95 writedma_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
106 hdc63463_readdma:
107   stmfd sp!,{r4-r7}
108   adr r5,hdc63463_irqdata
109   ldmia r5,{r0,r1,r2,r3,r4}
110
111 readdma_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
142 readdma_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
158 readdma_end:
159   adr r5,hdc63463_irqdata+12
160   stmia r5,{r3,r4}
161   ldmfd sp!,{r4-r7}
162   RETINSTR(mov,pc,lr)