patch-2.1.101 linux/drivers/acorn/block/mfm.S

Next file: linux/drivers/acorn/char/Config.in
Previous file: linux/drivers/acorn/block/ide-rapide.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.100/linux/drivers/acorn/block/mfm.S linux/drivers/acorn/block/mfm.S
@@ -0,0 +1,163 @@
+@ Read/Write DMA code for the ST506/MFM hard drive controllers on the A400
+@   motherboard on ST506 podules.
+@ (c) David Alan Gilbert (gilbertd@cs.man.ac.uk) 1996
+
+#include <asm/assembler.h>
+ 
+_hdc63463_irqdata:
+@ Controller base address
+  .global _hdc63463_baseaddress
+_hdc63463_baseaddress:
+  .word 0
+
+  .global _hdc63463_irqpolladdress
+_hdc63463_irqpolladdress:
+  .word 0
+ 
+  .global _hdc63463_irqpollmask
+_hdc63463_irqpollmask:
+  .word 0
+
+@ where to read/write data  from the kernel data space
+  .global _hdc63463_dataptr
+_hdc63463_dataptr:
+  .word 0
+
+@ Number of bytes left to transfer
+  .global _hdc63463_dataleft
+_hdc63463_dataleft:
+  .word 0
+
+@ -------------------------------------------------------------------------
+@ hdc63463_writedma: DMA from host to controller
+@  internal reg usage: r0=hdc base address, r1=irq poll address, r2=poll mask
+@                      r3=data ptr, r4=data left, r5,r6=temporary
+  .global _hdc63463_writedma
+_hdc63463_writedma:
+  stmfd sp!,{r4-r7}
+  adr r5,_hdc63463_irqdata
+  ldmia r5,{r0,r1,r2,r3,r4}
+
+
+writedma_again:
+
+  @ test number of remaining bytes to transfer
+  cmp r4,#0
+  beq writedma_end
+  bmi writedma_end
+
+  @ Check the hdc is interrupting
+  ldrb r5,[r1,#0]
+  tst r5,r2
+  beq writedma_end
+
+  @ Transfer a block of upto 256 bytes
+  cmp r4,#256
+  movlt r7,r4
+  movge r7,#256
+
+  @ Check the hdc is still busy and command has not ended and no errors
+  ldr r5,[r0,#32]     @ Status reg - 16 bit - its the top few bits which are status
+  @ think we should continue DMA until it drops busy - perhaps this was
+  @ the main problem with corrected errors causing a hang
+  @tst r5,#0x3c00        @ Test for things which should be off
+  @bne writedma_end
+  and r5,r5,#0x8000        @ This is test for things which should be on: Busy
+  cmp r5,#0x8000
+  bne writedma_end 
+
+  @ Bytes remaining at end
+  sub r4,r4,r7
+
+  @ HDC Write register location
+  add r0,r0,#32+8
+
+writedma_loop:
+  @ OK - pretty sure we should be doing this
+
+  ldr r5,[r3],#4          @ Get a word to be written
+  @ get bottom half to be sent first
+  mov r6,r5,lsl#16        @ Separate the first 2 bytes
+  orr r2,r6,r6,lsr #16    @ Duplicate them in the bottom half of the word
+  @ now the top half
+  mov r6,r5,lsr#16        @ Get 2nd 2 bytes
+  orr r6,r6,r6,lsl#16     @ Duplicate
+  @str r6,[r0]       @ to hdc
+  stmia r0,{r2,r6}
+  subs r7,r7,#4           @ Dec. number of bytes left
+  bne writedma_loop
+
+  @ If we were too slow we had better go through again - DAG - took out with new interrupt routine
+  @ sub r0,r0,#32+8
+  @ adr r2,_hdc63463_irqdata
+  @ ldr r2,[r2,#8]
+  @ b writedma_again
+
+writedma_end:
+  adr r5,_hdc63463_irqdata+12
+  stmia r5,{r3,r4}
+  ldmfd sp!,{r4-r7}
+  RETINSTR(mov,pc,lr)
+
+@ -------------------------------------------------------------------------
+@ hdc63463_readdma: DMA from controller to host
+@  internal reg usage: r0=hdc base address, r1=irq poll address, r2=poll mask
+@                      r3=data ptr, r4=data left, r5,r6=temporary
+  .global _hdc63463_readdma
+_hdc63463_readdma:
+  stmfd sp!,{r4-r7}
+  adr r5,_hdc63463_irqdata
+  ldmia r5,{r0,r1,r2,r3,r4}
+
+readdma_again:
+  @ test number of remaining bytes to transfer
+  cmp r4,#0
+  beq readdma_end
+  bmi readdma_end
+
+  @ Check the hdc is interrupting
+  ldrb r5,[r1,#0]
+  tst r5,r2
+  beq readdma_end
+
+  @ Check the hdc is still busy and command has not ended and no errors
+  ldr r5,[r0,#32]     @ Status reg - 16 bit - its the top few bits which are status
+  @ think we should continue DMA until it drops busy - perhaps this was
+  @ the main problem with corrected errors causing a hang
+  @tst r5,#0x3c00      @ Test for things which should be off
+  @bne readdma_end
+  and r5,r5,#0x8000        @ This is test for things which should be on: Busy
+  cmp r5,#0x8000
+  bne readdma_end 
+
+  @ Transfer a block of upto 256 bytes
+  cmp r4,#256
+  movlt r7,r4
+  movge r7,#256
+
+  @ Bytes remaining at end
+  sub r4,r4,r7
+
+  @ Set a pointer to the data register in the HDC
+  add r0,r0,#8
+readdma_loop:
+  @ OK - pretty sure we should be doing this
+  ldmia r0,{r5,r6}
+  mov r5,r5,lsl#16
+  mov r6,r6,lsl#16
+  orr r6,r6,r5,lsr #16
+  str r6,[r3],#4
+  subs r7,r7,#4        @ Decrement bytes to go
+  bne readdma_loop
+
+  @ Try reading multiple blocks - if this was fast enough then I dont think
+  @ this should help - NO taken out DAG - new interrupt handler has
+  @ non-consecutive memory blocks
+  @ sub r0,r0,#8
+  @ b readdma_again
+
+readdma_end:
+  adr r5,_hdc63463_irqdata+12
+  stmia r5,{r3,r4}
+  ldmfd sp!,{r4-r7}
+  RETINSTR(mov,pc,lr)

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov