aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acorn/block/mfm.S
blob: c90cbd41ce21e34ada85d39689bd348df0a48c7d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
@ Read/Write DMA code for the ST506/MFM hard drive controllers on the A400 Acorn Archimedes
@   motherboard and on ST506 expansion podules.
@ (c) David Alan Gilbert (linux@treblig.org) 1996-1999

#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 do not 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)