Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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) |