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