]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
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) |