FS#11417 by Joe Balough: fix audio/tuner on philips hdd6330
[kugel-rb.git] / firmware / target / coldfire / ata-as-coldfire.S
blob0b2cb850f4f6442e0b89727710f4452c8087f04f
1 /***************************************************************************
2  *             __________               __   ___.
3  *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
4  *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
5  *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
6  *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
7  *                     \/            \/     \/    \/            \/
8  * $Id$
9  *
10  * Copyright (C) 2006 by Jens Arnold
11  * Copyright (C) 2010 by Marcin Bukat (byte swaps)
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ****************************************************************************/
23 #include "config.h"
25     .macro SWAP_BYTES dn
26         move.l  %a3, %d7        | d7 = 0x00FF00FF
27         and.l   \dn, %d7        | d7 = .B.D
28         eor.l   %d7, \dn        | dn = A.C.
29         lsl.l   #8, %d7         | d7 = B.D.
30         lsr.l   #8, \dn         | d3 = .A.C
31         or.l    %d7, \dn        | dn = BADC
32     .endm
34     .equ    .ata_port, 0x20000020
35     .equ    .swapmask, 0x00FF00FF
37     .section    .icode,"ax",@progbits
39     .align  2
40     .global copy_read_sectors
41     .type   copy_read_sectors,@function
42     
43 /* Read a number of words from the ATA data port
44  *
45  * Utilises line bursts, assumes there is at least one full line to copy.
46  *
47  * Arguments:
48  *   (4,%sp) - buffer address
49  *   (8,%sp) - word count
50  *
51  * Register usage:
52  *   %a0 - current address
53  *   %a1 - end address
54  *   %a2 - ata port
55  *   %d0 - scratch
56  *   %d1 - shift count
57  *   %d2-%d6 - read buffers
58  *
59  *   #ifdef ATA_SWAP_WORDS
60  *   %d7 - byte swap scrach
61  *   %a3 - byte swap mask
62  *   #endif
63  */
65 copy_read_sectors:
66 #ifdef ATA_SWAP_WORDS
67     lea.l   (-32, %sp), %sp
68     movem.l %d2-%d7/%a2-%a3, (%sp)
69     movem.l (36, %sp), %a0-%a1
70     lea.l   .swapmask, %a3
71 #else
72     lea.l   (-24, %sp), %sp
73     movem.l %d2-%d6/%a2, (%sp)
74     movem.l (28, %sp), %a0-%a1
75 #endif
76     add.l   %a1, %a1
77     add.l   %a0, %a1
78     lea.l   .ata_port, %a2
80     move.l  %a0, %d0
81     btst.l  #0, %d0         /* 16-bit aligned? */
82     jeq     .r_aligned      /* yes, do word copy */
84     /* not 16-bit aligned */
85     subq.l  #1, %a1         /* last byte is done unconditionally */
86     moveq.l #24, %d1        /* preload shift count */
88     move.w  (%a2), %d2      /* load initial word */
89 #ifdef ATA_SWAP_WORDS
90     move.b  %d2, (%a0)+
91     lsr.l   #8, %d2
92 #else
93     move.l  %d2, %d3
94     lsr.l   #8, %d3
95     move.b  %d3, (%a0)+     /* write high byte of it, aligns dest addr */
96 #endif
97     btst.l  #1, %d0         /* longword aligned? (testing old d0 value!) */
98     bne.b   .r_end_u_w1     /* yes, skip leading word handling */
99 #ifdef ATA_SWAP_WORDS
100     move.w  (%a2), %d3
101     lsl.l   #8, %d2
102     move.b  %d3, %d2
103     move.w  %d2, (%a0)+     /* write bytes 2 and 3 as word */
104     move.l  %d3, %d2
105     lsr.l   #8, %d2
106 #else
107     swap    %d2             /* move initial word up */
108     move.w  (%a2), %d2      /* combine with second word */
109     move.l  %d2, %d3
110     lsr.l   #8, %d3
111     move.w  %d3, (%a0)+     /* write bytes 2 and 3 as word */
112 #endif
114 .r_end_u_w1:
115     moveq.l #12, %d0
116     add.l   %a0, %d0
117     and.l   #0xFFFFFFF0,%d0 /* d0 == first line bound */
118     cmp.l   %a0, %d0        /* any leading longwords? */
119     bls.b   .r_end_u_l1     /* no: skip loop */
121 .r_loop_u_l1:
122     move.w  (%a2), %d3      /* load first word */
123     swap    %d3             /* move to upper 16 bit */
124     move.w  (%a2), %d3      /* load second word */
126 #ifdef ATA_SWAP_WORDS
127     SWAP_BYTES %d3
128 #endif
130     move.l  %d3, %d4
131     lsl.l   %d1, %d2
132     lsr.l   #8, %d3
133     or.l    %d3, %d2        /* combine old low byte with new top 3 bytes */
134     move.l  %d2, (%a0)+     /* store as long */
135     move.l  %d4, %d2
136     cmp.l   %a0, %d0        /* run up to first line bound */
137     bhi.b   .r_loop_u_l1
139 .r_end_u_l1:
140     lea.l   (-14, %a1), %a1 /* adjust end addr. to 16 bytes/pass */
142 .r_loop_u_line:
143     move.w  (%a2), %d3      /* load 1st word */
144     swap    %d3             /* move to upper 16 bit */
145     move.w  (%a2), %d3      /* load 2nd word */
147 #ifdef ATA_SWAP_WORDS
148     SWAP_BYTES %d3
149 #endif
151     move.l  %d3, %d0
152     lsl.l   %d1, %d2
153     lsr.l   #8, %d0
154     or.l    %d0, %d2        /* combine old low byte with new top 3 bytes */
155     move.w  (%a2), %d4      /* load 3rd word */
156     swap    %d4             /* move to upper 16 bit */
157     move.w  (%a2), %d4      /* load 4th word */
159 #ifdef ATA_SWAP_WORDS
160     SWAP_BYTES %d4
161 #endif
163     move.l  %d4, %d0
164     lsl.l   %d1, %d3
165     lsr.l   #8, %d0
166     or.l    %d0, %d3        /* combine old low byte with new top 3 bytes */
167     move.w  (%a2), %d5      /* load 5th word */
168     swap    %d5             /* move to upper 16 bit */
169     move.w  (%a2), %d5      /* load 6th word */
171 #ifdef ATA_SWAP_WORDS
172     SWAP_BYTES %d5
173 #endif
175     move.l  %d5, %d0
176     lsl.l   %d1, %d4
177     lsr.l   #8, %d0
178     or.l    %d0, %d4        /* combine old low byte with new top 3 bytes */
179     move.w  (%a2), %d6      /* load 7th word */
180     swap    %d6             /* move to upper 16 bit */
181     move.w  (%a2), %d6      /* load 8th word */
183 #ifdef ATA_SWAP_WORDS
184     SWAP_BYTES %d6
185 #endif
187     move.l  %d6, %d0
188     lsl.l   %d1, %d5
189     lsr.l   #8, %d0
190     or.l    %d0, %d5        /* combine old low byte with new top 3 bytes */
191     movem.l %d2-%d5, (%a0)  /* store line */
192     lea.l   (16, %a0), %a0
193     move.l  %d6, %d2
194     cmp.l   %a0, %a1        /* run up to last line bound */
195     bhi.b   .r_loop_u_line
197     lea.l   (12, %a1), %a1  /* readjust for longword loop */
198     cmp.l   %a0, %a1        /* any trailing longwords? */
199     bls.b   .r_end_u_l2     /* no: skip loop */
201 .r_loop_u_l2:
202     move.w  (%a2), %d3      /* load first word */
203     swap    %d3             /* move to upper 16 bit */
204     move.w  (%a2), %d3      /* load second word */
206 #ifdef ATA_SWAP_WORDS
207     SWAP_BYTES %d3
208 #endif
210     move.l  %d3, %d4
211     lsl.l   %d1, %d2
212     lsr.l   #8, %d3
213     or.l    %d3, %d2        /* combine old low byte with new top 3 bytes */
214     move.l  %d2, (%a0)+     /* store as long */
215     move.l  %d4, %d2
216     cmp.l   %a0, %a1        /* run up to last long bound */
217     bhi.b   .r_loop_u_l2
218         
219 .r_end_u_l2:
220     blo.b   .r_end_u_w2     /* one word left? */
222 #ifdef ATA_SWAP_WORDS
223     move.w  (%a2), %d3
224     lsl.l   #8, %d2
225     move.b  %d3, %d2
226     move.w  %d2, (%a0)+     /* write bytes 2 and 3 as word */
227     move.l  %d3, %d2
228     lsr.l   #8, %d2
229 .r_end_u_w2:
230     move.b  %d2, (%a0)+     /* store final byte */
231     bra.w   .r_exit
232 #else
233     swap    %d2             /* move old word to upper 16 bits */
234     move.w  (%a2), %d2      /* load final word */
235     move.l  %d2, %d3
236     lsr.l   #8, %d3
237     move.w  %d3, (%a0)+     /* write bytes 2 and 3 as word */
238 .r_end_u_w2:
239     move.b  %d2, (%a0)+     /* store final byte */
240     bra.b   .r_exit
241 #endif
243     /* 16-bit aligned */
244 .r_aligned:
245     btst.l  #1, %d0         /* longword aligned? */
246     beq.b   .r_end_a_w1     /* yes, skip leading word handling */
248 #ifdef ATA_SWAP_WORDS
249     move.w  (%a2), %d7      /* copy initial word after byte swap */
250     move.b  %d7, (%a0)+
251     lsr.l   #8, %d7
252     move.b  %d7, (%a0)+
253 #else
254     move.w  (%a2), (%a0)+   /* copy initial word */
255 #endif
256 .r_end_a_w1:
257     moveq.l #12, %d0
258     add.l   %a0, %d0
259     and.l   #0xFFFFFFF0,%d0 /* d0 == first line bound */
260     cmp.l   %a0, %d0        /* any leading longwords? */
261     bls.b   .r_end_a_l1     /* no: skip loop */
263 .r_loop_a_l1:
264     move.w  (%a2), %d1      /* load first word */
265     swap    %d1             /* move it to upper 16 bits */
266     move.w  (%a2), %d1      /* load second word */
268 #ifdef ATA_SWAP_WORDS
269     SWAP_BYTES %d1
270 #endif
272     move.l  %d1, (%a0)+     /* store as long */
273     cmp.l   %a0, %d0        /* run up to first line bound */
274     bhi.b   .r_loop_a_l1
276 .r_end_a_l1:
277     lea.l   (-14, %a1), %a1 /* adjust end addr. to 16 bytes/pass */
279 .r_loop_a_line:
280     move.w  (%a2), %d0      /* load 1st word */
281     swap    %d0             /* move it to upper 16 bits */
282     move.w  (%a2), %d0      /* load 2nd word */
283     move.w  (%a2), %d1      /* load 3rd word */
284     swap    %d1             /* move it to upper 16 bits */
285     move.w  (%a2), %d1      /* load 4th word */
286     move.w  (%a2), %d2      /* load 5th word */
287     swap    %d2             /* move it to upper 16 bits */
288     move.w  (%a2), %d2      /* load 6th word */
289     move.w  (%a2), %d3      /* load 7th word */
290     swap    %d3             /* move it to upper 16 bits */
291     move.w  (%a2), %d3      /* load 8th word */
293 #ifdef ATA_SWAP_WORDS
294     SWAP_BYTES %d0
295     SWAP_BYTES %d1
296     SWAP_BYTES %d2
297     SWAP_BYTES %d3
298 #endif
300     movem.l %d0-%d3, (%a0)  /* store line */
301     lea.l   (16, %a0), %a0
302     cmp.l   %a0, %a1        /* run up to last line bound */
303     bhi.b   .r_loop_a_line
305     lea.l   (12, %a1), %a1  /* readjust for longword loop */
306     cmp.l   %a0, %a1        /* any trailing longwords? */
307     bls.b   .r_end_a_l2     /* no: skip loop */
309 .r_loop_a_l2:
310     move.w  (%a2), %d1      /* read first word */
311     swap    %d1             /* move it to upper 16 bits */
312     move.w  (%a2), %d1      /* read second word */
314 #ifdef ATA_SWAP_WORDS
315     SWAP_BYTES %d1
316 #endif
318     move.l  %d1, (%a0)+     /* store as long */
319     cmp.l   %a0, %a1        /* run up to last long bound */
320     bhi.b   .r_loop_a_l2
321         
322 .r_end_a_l2:
323     blo.b   .r_end_a_w2     /* one word left? */
325 #ifdef ATA_SWAP_WORDS
326     move.w (%a2), %d7      /* copy final word after byte swap */
327     move.b %d7, (%a0)+
328     lsr.l  #8, %d7
329     move.b %d7, (%a0)+
330 #else
331     move.w  (%a2), (%a0)+   /* copy final word */
332 #endif
333 .r_end_a_w2:
335 .r_exit:
336 #ifdef ATA_SWAP_WORDS
337     movem.l (%sp), %d2-%d7/%a2-%a3
338     lea.l   (32, %sp), %sp
339 #else
340     movem.l (%sp), %d2-%d6/%a2
341     lea.l   (24, %sp), %sp
342 #endif
343     rts
345 .r_end:
346     .size   copy_read_sectors,.r_end-copy_read_sectors
348     .align  2
349     .global copy_write_sectors
350     .type   copy_write_sectors,@function
351     
352 /* Write a number of words to the ATA data port
354  * Utilises line bursts, assumes there is at least one full line to copy.
356  * Arguments:
357  *   (4,%sp) - buffer address
358  *   (8,%sp) - word count
360  * Register usage:
361  *   %a0 - current address
362  *   %a1 - end address
363  *   %a2 - ata port
364  *   %d0 - scratch
365  *   %d1 - shift count
366  *   %d2-%d6 - read buffers
368  *   #ifdef ATA_SWAP_WORDS
369  *   %d7 - swap scrach
370  *   %a3 - swap mask
371  *   #endif
372  */
374 copy_write_sectors:
375 #ifdef ATA_SWAP_WORDS
376     lea.l   (-32, %sp), %sp
377     movem.l %d2-%d7/%a2-%a3, (%sp)
378     movem.l (36, %sp), %a0-%a1
379     lea.l   .swapmask, %a3
380 #else
381     lea.l   (-24, %sp), %sp
382     movem.l %d2-%d6/%a2, (%sp)
383     movem.l (28, %sp), %a0-%a1
384 #endif
385     add.l   %a1, %a1
386     add.l   %a0, %a1
387     lea.l   .ata_port, %a2
389     move.l  %a0, %d0
390     btst.l  #0, %d0         /* 16-bit aligned? */
391     jeq     .w_aligned      /* yes, do word copy */
393     /* not 16-bit aligned */
394     subq.l  #1, %a1         /* last byte is done unconditionally */
395     moveq.l #24, %d1        /* preload shift count */
397     move.b  (%a0)+, %d2
399     btst.l  #1, %d0         /* longword aligned? (testing old d0 value!) */
400     bne.b   .w_end_u_w1     /* yes, skip leading word handling */
402     swap    %d2
403     move.w  (%a0)+, %d2
404     move.l  %d2, %d3
405     lsr.l   #8, %d3
407 #ifdef ATA_SWAP_WORDS
408     move.l  %d3, %d7       /* byte swap low word of %d3 */
409     lsr.l   #8, %d7
410     lsl.l   #8, %d3
411     move.b  %d7, %d3
412 #endif
414     move.w  %d3, (%a2)
415         
416 .w_end_u_w1:
417     moveq.l #12, %d0
418     add.l   %a0, %d0
419     and.l   #0xFFFFFFF0,%d0 /* d0 == first line bound */
420     cmp.l   %a0, %d0        /* any leading longwords? */
421     bls.b   .w_end_u_l1     /* no: skip loop */
422         
423 .w_loop_u_l1:
424     move.l  (%a0)+, %d3
425     move.l  %d3, %d4
426     lsl.l   %d1, %d2
427     lsr.l   #8, %d3
428     or.l    %d3, %d2
430 #ifdef ATA_SWAP_WORDS
431     SWAP_BYTES %d2
432 #endif
434     swap    %d2
435     move.w  %d2, (%a2)
436     swap    %d2
437     move.w  %d2, (%a2)
438     move.l  %d4, %d2
439     cmp.l   %a0, %d0        /* run up to first line bound */
440     bhi.b   .w_loop_u_l1
442 .w_end_u_l1:
443     lea.l   (-14, %a1), %a1 /* adjust end addr. to 16 bytes/pass */
445 .w_loop_u_line:
446     movem.l (%a0), %d3-%d6
447     lea.l   (16, %a0), %a0
448     move.l  %d3, %d0
449     lsl.l   %d1, %d2
450     lsr.l   #8, %d0
451     or.l    %d0, %d2
453 #ifdef ATA_SWAP_WORDS
454     SWAP_BYTES %d2
455 #endif
457     swap    %d2
458     move.w  %d2, (%a2)
459     swap    %d2
460     move.w  %d2, (%a2)
461     move.l  %d4, %d0
462     lsl.l   %d1, %d3
463     lsr.l   #8, %d0
464     or.l    %d0, %d3
466 #ifdef ATA_SWAP_WORDS
467     SWAP_BYTES %d3
468 #endif
470     swap    %d3
471     move.w  %d3, (%a2)
472     swap    %d3
473     move.w  %d3, (%a2)
474     move.l  %d5, %d0
475     lsl.l   %d1, %d4
476     lsr.l   #8, %d0
477     or.l    %d0, %d4
479 #ifdef ATA_SWAP_WORDS
480     SWAP_BYTES %d4
481 #endif
483     swap    %d4
484     move.w  %d4, (%a2)
485     swap    %d4
486     move.w  %d4, (%a2)
487     move.l  %d6, %d0
488     lsl.l   %d1, %d5
489     lsr.l   #8, %d0
490     or.l    %d0, %d5
492 #ifdef ATA_SWAP_WORDS
493     SWAP_BYTES %d5
494 #endif
496     swap    %d5
497     move.w  %d5, (%a2)
498     swap    %d5
499     move.w  %d5, (%a2)
500     move.l  %d6, %d2
501     cmp.l   %a0, %a1        /* run up to last line bound */
502     bhi.b   .w_loop_u_line
504     lea.l   (12, %a1), %a1  /* readjust for longword loop */
505     cmp.l   %a0, %a1        /* any trailing longwords? */
506     bls.b   .w_end_u_l2     /* no: skip loop */
508 .w_loop_u_l2:
509     move.l  (%a0)+, %d3
510     move.l  %d3, %d4
511     lsl.l   %d1, %d2
512     lsr.l   #8, %d3
513     or.l    %d3, %d2
515 #ifdef ATA_SWAP_WORDS
516     SWAP_BYTES %d2
517 #endif
519     swap    %d2
520     move.w  %d2, (%a2)
521     swap    %d2
522     move.w  %d2, (%a2)
523     move.l  %d4, %d2
524     cmp.l   %a0, %a1        /* run up to first line bound */
525     bhi.b   .w_loop_u_l2
527 .w_end_u_l2:
528     blo.b   .w_end_u_w2     /* one word left? */
530     swap    %d2
531     move.w  (%a0)+, %d2
532     move.l  %d2, %d3
533     lsr.l   #8, %d3
535 #ifdef ATA_SWAP_WORDS
536     SWAP_BYTES %d3
537 #endif
539     move.w  %d3, (%a2)
541 .w_end_u_w2:
542 #ifdef ATA_SWAP_WORDS
543     move.l  %d2, %d7
544     move.b  (%a0)+, %d2
545     lsl.l   #8, %d2
546     move.b  %d7, %d2
547     move.w  %d2, (%a2)
548     bra.w    .w_exit
549 #else
550     lsl.l   #8, %d2
551     move.b  (%a0)+, %d2
552     move.w  %d2, (%a2)
553     bra.b    .w_exit
554 #endif
556     /* 16-bit aligned */
557 .w_aligned:
558     btst.l  #1, %d0
559     beq.b   .w_end_a_w1
561 #ifdef ATA_SWAP_WORDS
562     move.w  (%a0)+, %d1    /* copy initial word bytes swaped */
563     move.l  %d1, %d7
564     lsl.l   #8, %d1
565     lsr.l   #8, %d7
566     move.b  %d7, %d1
567     move.w  %d1, (%a2)
568 #else
569     move.w  (%a0)+, (%a2)   /* copy initial word */
570 #endif
572 .w_end_a_w1:
573     moveq.l #12, %d0
574     add.l   %a0, %d0
575     and.l   #0xFFFFFFF0,%d0 /* d0 == first line bound */
576     cmp.l   %a0, %d0        /* any leading longwords? */
577     bls.b   .w_end_a_l1     /* no: skip loop */
579 .w_loop_a_l1:
580     move.l  (%a0)+, %d1
582 #ifdef ATA_SWAP_WORDS
583     SWAP_BYTES %d1
584 #endif
586     swap    %d1
587     move.w  %d1, (%a2)
588     swap    %d1
589     move.w  %d1, (%a2)
590     cmp.l   %a0, %d0        /* run up to first line bound */
591     bhi.b   .w_loop_a_l1
593 .w_end_a_l1:
594     lea.l   (-14, %a1), %a1 /* adjust end addr. to 16 bytes/pass */
596 .w_loop_a_line:
597     movem.l (%a0), %d0-%d3
598     lea.l   (16, %a0), %a0
600 #ifdef ATA_SWAP_WORDS
601     SWAP_BYTES %d0
602     SWAP_BYTES %d1
603     SWAP_BYTES %d2
604     SWAP_BYTES %d3
605 #endif
607     swap    %d0
608     move.w  %d0, (%a2)
609     swap    %d0
610     move.w  %d0, (%a2)
611     swap    %d1
612     move.w  %d1, (%a2)
613     swap    %d1
614     move.w  %d1, (%a2)
615     swap    %d2
616     move.w  %d2, (%a2)
617     swap    %d2
618     move.w  %d2, (%a2)
619     swap    %d3
620     move.w  %d3, (%a2)
621     swap    %d3
622     move.w  %d3, (%a2)
623     cmp.l   %a0, %a1        /* run up to last line bound */
624     bhi.b   .w_loop_a_line
625         
626     lea.l   (12, %a1), %a1  /* readjust for longword loop */
627     cmp.l   %a0, %a1        /* any trailing longwords? */
628     bls.b   .w_end_a_l2     /* no: skip loop */
630 .w_loop_a_l2:
631     move.l  (%a0)+, %d1
633 #ifdef ATA_SWAP_WORDS
634     SWAP_BYTES %d1
635 #endif
637     swap    %d1
638     move.w  %d1, (%a2)
639     swap    %d1
640     move.w  %d1, (%a2)
641     cmp.l   %a0, %a1        /* run up to first line bound */
642     bhi.b   .w_loop_a_l2
644 .w_end_a_l2:
645     blo.b   .w_end_a_w2     /* one word left? */
647 #ifdef ATA_SWAP_WORDS
648     move.w  (%a0)+, %d0    /* copy final word after byte swap */
649     move.l  %d0, %d7
650     lsl.l   #8, %d0
651     lsr.l   #8, %d7
652     move.b  %d7, %d0
653     move.w  %d0, (%a2)
654 #else
655     move.w  (%a0)+, (%a2)   /* copy final word */
656 #endif
658 .w_end_a_w2:
660 .w_exit:
661 #ifdef ATA_SWAP_WORDS
662     movem.l (%sp), %d2-%d7/%a2-%a3
663     lea.l   (32, %sp), %sp
664 #else
665     movem.l (%sp), %d2-%d6/%a2
666     lea.l   (24, %sp), %sp
667 #endif
668     rts
670 .w_end:
671     .size   copy_write_sectors,.w_end-copy_write_sectors