summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/SOURCES9
-rw-r--r--firmware/target/arm/ata-as-arm.S344
-rw-r--r--firmware/target/arm/ata-target.h16
3 files changed, 366 insertions, 3 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES
index 3fdbdbb..227eab1 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -410,6 +410,7 @@ target/coldfire/iriver/h100/usb-h100.c
#ifdef IRIVER_H10
#ifndef SIMULATOR
+target/arm/ata-as-arm.S
target/arm/ata-pp5020.c
target/arm/wmcodec-pp.c
target/arm/i2s-pp.c
@@ -424,6 +425,7 @@ target/arm/usb-pp.c
#ifdef IRIVER_H10_5GB
#ifndef SIMULATOR
+target/arm/ata-as-arm.S
target/arm/ata-pp5020.c
target/arm/wmcodec-pp.c
target/arm/i2s-pp.c
@@ -460,6 +462,7 @@ target/arm/gigabeat/meg-fx/pcm-meg-fx.c
#ifdef ELIO_TPJ1022
#ifndef SIMULATOR
+target/arm/ata-as-arm.S
target/arm/ata-pp5020.c
target/arm/wmcodec-pp.c
target/arm/i2s-pp.c
@@ -478,6 +481,7 @@ drivers/lcd-ipod.c
drivers/pcf50605.c
target/arm/wmcodec-pp.c
target/arm/i2s-pp.c
+target/arm/ata-as-arm.S
target/arm/ata-pp5020.c
target/arm/ipod/adc-ipod.c
target/arm/ipod/backlight-4g_color.c
@@ -491,6 +495,7 @@ target/arm/usb-pp.c
#ifndef SIMULATOR
drivers/lcd-ipod.c
drivers/pcf50605.c
+target/arm/ata-as-arm.S
target/arm/ata-pp5020.c
target/arm/wmcodec-pp.c
target/arm/i2s-pp.c
@@ -506,6 +511,7 @@ target/arm/usb-pp.c
#ifndef SIMULATOR
drivers/lcd-ipod.c
drivers/pcf50605.c
+target/arm/ata-as-arm.S
target/arm/ata-pp5020.c
target/arm/wmcodec-pp.c
target/arm/i2s-pp.c
@@ -521,6 +527,7 @@ target/arm/usb-pp.c
#ifndef SIMULATOR
drivers/lcd-ipodvideo.c
drivers/pcf50605.c
+target/arm/ata-as-arm.S
target/arm/ata-pp5020.c
target/arm/wmcodec-pp.c
target/arm/i2s-pp.c
@@ -551,6 +558,7 @@ target/arm/usb-pp.c
#ifndef SIMULATOR
drivers/lcd-ipod.c
drivers/pcf50605.c
+target/arm/ata-as-arm.S
target/arm/ata-pp5020.c
target/arm/wmcodec-pp.c
target/arm/i2s-pp.c
@@ -566,6 +574,7 @@ target/arm/usb-pp.c
#ifndef SIMULATOR
drivers/lcd-ipod.c
drivers/pcf50605.c
+target/arm/ata-as-arm.S
target/arm/ata-pp5020.c
target/arm/wmcodec-pp.c
target/arm/i2s-pp.c
diff --git a/firmware/target/arm/ata-as-arm.S b/firmware/target/arm/ata-as-arm.S
new file mode 100644
index 0000000..32fc28c
--- /dev/null
+++ b/firmware/target/arm/ata-as-arm.S
@@ -0,0 +1,344 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2007 by Jens Arnold
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "config.h"
+
+
+#if CONFIG_CPU == PP5002
+ /* Causes ATA retries on iPod G3 probably related to improper controller
+ * setup. Needs investigation. */
+ .section .icode,"ax",%progbits
+ .equ .ata_port, 0xc00031e0
+#elif CONFIG_CPU == PP5020
+ /* Verified working on (PP5020, PP5021, PP5022) targets */
+ .section .icode,"ax",%progbits
+ .equ .ata_port, 0xc30001e0
+#elif CONFIG_CPU == S3C2440
+ /* Untested */
+ .text
+ .equ .ata_port, 0x18000000
+#endif
+
+ .align 2
+ .global copy_read_sectors
+ .type copy_read_sectors,%function
+
+/* Read a number of words from the ATA data port
+ *
+ * Optimised for speed; assumes wordcount >= 10
+ *
+ * Arguments:
+ * r0 - buffer address
+ * r1 - word count
+ *
+ * Register usage:
+ * r0 - current address
+ * r1 - word count
+ * r2 - ata port
+ * r3..r6, lr - read buffers
+ */
+
+copy_read_sectors:
+ stmfd sp!, {r4, r5, r6, lr}
+ ldr r2, =.ata_port
+ tst r0, #1 /* 16 bit aligned? */
+ beq .r_aligned
+
+ /* not 16-bit aligned */
+ sub r1, r1, #1 /* one halfword is handled unconditionally */
+ ldrh r3, [r2] /* read first halfword */
+ strb r3, [r0], #1 /* store low byte */
+ mov r3, r3, lsr #8
+
+ tst r0, #2 /* 32 bit aligned? */
+ beq .r_noword_u
+ ldrh r4, [r2] /* read second halfword */
+ orr r3, r3, r4, lsl #8 /* combine with old byte */
+ strh r3, [r0], #2 /* store */
+ mov r3, r4, lsr #8
+ sub r1, r1, #1 /* another halfword taken */
+.r_noword_u:
+
+ sub r1, r1, #8 /* adjust for zero-check and doing 8 halfwords/loop */
+.r_loop_u:
+ ldrh r4, [r2] /* Read 8 halfwords and combine them into */
+ orr r3, r3, r4, lsl #8 /* 4 words so that they're properly aligned */
+ ldrh r4, [r2] /* in memory. Bottom byte of first word is */
+ orr r3, r3, r4, lsl #24 /* the top byte from the last round. Write */
+ mov r4, r4, lsr #8 /* all 4 words at once. */
+ ldrh r5, [r2]
+ orr r4, r4, r5, lsl #8
+ ldrh r5, [r2]
+ orr r4, r4, r5, lsl #24
+ mov r5, r5, lsr #8
+ ldrh r6, [r2]
+ orr r5, r5, r6, lsl #8
+ ldrh r6, [r2]
+ orr r5, r5, r6, lsl #24
+ mov r6, r6, lsr #8
+ ldrh lr, [r2]
+ orr r6, r6, lr, lsl #8
+ ldrh lr, [r2]
+ orr r6, r6, lr, lsl #24
+ stmia r0!, {r3, r4, r5, r6}
+ mov r3, lr, lsr #8
+ subs r1, r1, #8 /* 8 or more halfwords left? */
+ bge .r_loop_u
+
+ /* No need to adjust the count, only checking bits from now on. */
+ tst r1, #4 /* 4 or more halfwords left? */
+ beq .r_end4_u
+ ldrh r4, [r2]
+ orr r3, r3, r4, lsl #8
+ ldrh r4, [r2]
+ orr r3, r3, r4, lsl #24
+ mov r4, r4, lsr #8
+ ldrh r5, [r2]
+ orr r4, r4, r5, lsl #8
+ ldrh r5, [r2]
+ orr r4, r4, r5, lsl #24
+ stmia r0!, {r3, r4}
+ mov r3, r5, lsr #8
+.r_end4_u:
+
+ tst r1, #2 /* 2 or more halfwords left? */
+ beq .r_end2_u
+ ldrh r4, [r2]
+ orr r3, r3, r4, lsl #8
+ ldrh r4, [r2]
+ orr r3, r3, r4, lsl #24
+ str r3, [r0], #4
+ mov r3, r4, lsr #8
+.r_end2_u:
+
+ tst r1, #1 /* one halfword left? */
+ ldrneh r4, [r2]
+ orrne r3, r3, r4, lsl #8
+ strneh r3, [r0], #2
+ movne r3, r4, lsr #8
+
+ strb r3, [r0], #1 /* store final byte */
+
+ ldmfd sp!, {r4, r5, r6, pc}
+
+ /* 16-bit aligned */
+.r_aligned:
+ tst r0, #2 /* 32 bit aligned? */
+ ldrneh r3, [r2] /* no: read first halfword */
+ strneh r3, [r0], #2 /* store */
+ subne r1, r1, #1 /* one halfword taken */
+
+ sub r1, r1, #8 /* adjust for zero-check and doing 8 halfwords/loop */
+.r_loop_a:
+ ldrh r3, [r2] /* Read 8 halfwords and combine each pair */
+ ldrh r4, [r2] /* into a word, then store all at once. */
+ orr r3, r3, r4, lsl #16
+ ldrh r4, [r2]
+ ldrh r5, [r2]
+ orr r4, r4, r5, lsl #16
+ ldrh r5, [r2]
+ ldrh r6, [r2]
+ orr r5, r5, r6, lsl #16
+ ldrh r6, [r2]
+ ldrh lr, [r2]
+ orr r6, r6, lr, lsl #16
+ stmia r0!, {r3, r4, r5, r6}
+ subs r1, r1, #8 /* 8 or more halfwords left? */
+ bge .r_loop_a
+
+ /* No need to adjust the count, only checking bits from now on. */
+ tst r1, #4 /* 4 or more halfwords left? */
+ beq .r_end4_a
+ ldrh r3, [r2]
+ ldrh r4, [r2]
+ orr r3, r3, r4, lsl #16
+ ldrh r4, [r2]
+ ldrh r5, [r2]
+ orr r4, r4, r5, lsl #16
+ stmia r0!, {r3, r4}
+.r_end4_a:
+
+ tst r1, #2 /* 2 or more halfwords left? */
+ ldrneh r3, [r2]
+ ldrneh r4, [r2]
+ orrne r3, r3, r4, lsl #16
+ strne r3, [r0], #4
+
+ tst r1, #1 /* one halfword left? */
+ ldrneh r3, [r2]
+ strneh r3, [r0], #2
+
+ ldmfd sp!, {r4, r5, r6, pc}
+
+.r_end:
+ .size copy_read_sectors,.r_end-copy_read_sectors
+
+ .align 2
+ .global copy_write_sectors
+ .type copy_write_sectors,%function
+
+/* Write a number of words to the ATA data port
+ *
+ * Optimised for speed; assumes wordcount >= 10
+ *
+ * Arguments:
+ * r0 - buffer address
+ * r1 - word count
+ *
+ * Register usage:
+ * r0 - current address
+ * r1 - word count
+ * r2 - ata port
+ * r3..r6, lr - read buffers
+ */
+
+copy_write_sectors:
+ stmfd sp!, {r4, r5, r6, lr}
+ ldr r2, =.ata_port
+ tst r0, #1 /* 16 bit aligned? */
+ beq .w_aligned
+
+ /* not 16-bit aligned */
+ sub r1, r1, #1 /* one halfword is done unconditionally */
+ ldrb r3, [r0], #1 /* load 1st byte, now halfword aligned. */
+
+ tst r0, #2 /* 32 bit aligned? */
+ beq .w_noword_u
+ ldrh r4, [r0], #2 /* load a halfword */
+ orr r3, r3, r4, lsl #8 /* combine with old byte */
+ strh r3, [r2] /* write halfword */
+ mov r3, r4, lsr #8
+ sub r1, r1, #1 /* another halfword taken */
+.w_noword_u:
+
+ sub r1, r1, #8 /* adjust for zero-check and doing 8 halfwords/loop */
+.w_loop_u:
+ ldmia r0!, {r4, r5, r6, lr}
+ orr r3, r3, r4, lsl #8 /* Load 4 words at once and decompose them */
+ strh r3, [r2] /* into 8 halfwords in a way that the words */
+ mov r3, r3, lsr #16 /* are shifted by 8 bits, putting the high */
+ strh r3, [r2] /* byte of one word into the low byte of */
+ mov r4, r4, lsr #24 /* the next. High byte of last word becomes */
+ orr r4, r4, r5, lsl #8 /* low byte of next round. */
+ strh r4, [r2]
+ mov r4, r4, lsr #16
+ strh r4, [r2]
+ mov r5, r5, lsr #24
+ orr r5, r5, r6, lsl #8
+ strh r5, [r2]
+ mov r5, r5, lsr #16
+ strh r5, [r2]
+ mov r6, r6, lsr #24
+ orr r6, r6, lr, lsl #8
+ strh r6, [r2]
+ mov r6, r6, lsr #16
+ strh r6, [r2]
+ mov r3, lr, lsr #24
+ subs r1, r1, #8 /* 8 or more halfwords left? */
+ bge .w_loop_u
+
+ /* No need to adjust the count, only checking bits from now on. */
+ tst r1, #4 /* 4 or more halfwords left? */
+ beq .w_end4_u
+ ldmia r0!, {r4, r5}
+ orr r3, r3, r4, lsl #8
+ strh r3, [r2]
+ mov r3, r3, lsr #16
+ strh r3, [r2]
+ mov r4, r4, lsr #24
+ orr r4, r4, r5, lsl #8
+ strh r4, [r2]
+ mov r4, r4, lsr #16
+ strh r4, [r2]
+ mov r3, r5, lsr #24
+.w_end4_u:
+
+ tst r1, #2 /* 2 or more halfwords left? */
+ beq .w_end2_u
+ ldr r4, [r0], #4
+ orr r3, r3, r4, lsl #8
+ strh r3, [r2]
+ mov r3, r3, lsr #16
+ strh r3, [r2]
+ mov r3, r4, lsr #24
+.w_end2_u:
+
+ tst r1, #1 /* one halfword left? */
+ ldrneh r4, [r0], #2
+ orrne r3, r3, r4, lsl #8
+ strneh r3, [r2]
+ movne r3, r3, lsr #16
+
+ ldrb r4, [r0], #1 /* load final byte */
+ orr r3, r3, r4, lsl #8
+ strh r3, [r2] /* write final halfword */
+
+ ldmfd sp!, {r4, r5, r6, pc}
+
+ /* 16-bit aligned */
+.w_aligned:
+ tst r0, #2 /* 32 bit aligned? */
+ ldrneh r3, [r0], #2 /* no: load first halfword */
+ strneh r3, [r2] /* write */
+ subne r1, r1, #1 /* one halfword taken */
+
+ sub r1, r1, #8 /* adjust for zero-check and doing 8 halfwords/loop */
+.w_loop_a:
+ ldmia r0!, {r3, r4, r5, r6}
+ strh r3, [r2] /* Load 4 words and decompose them into */
+ mov r3, r3, lsr #16 /* 2 halfwords each, and write those. */
+ strh r3, [r2]
+ strh r4, [r2]
+ mov r4, r4, lsr #16
+ strh r4, [r2]
+ strh r5, [r2]
+ mov r5, r5, lsr #16
+ strh r5, [r2]
+ strh r6, [r2]
+ mov r6, r6, lsr #16
+ strh r6, [r2]
+ subs r1, r1, #8 /* 8 or more halfwords left? */
+ bge .w_loop_a
+
+ /* No need to adjust the count, only checking bits from now on. */
+ tst r1, #4 /* 4 or more halfwords left? */
+ beq .w_end4_a
+ ldmia r0!, {r3, r4}
+ strh r3, [r2]
+ mov r3, r3, lsr #16
+ strh r3, [r2]
+ strh r4, [r2]
+ mov r4, r4, lsr #16
+ strh r4, [r2]
+.w_end4_a:
+
+ tst r1, #2 /* 2 or more halfwords left? */
+ ldrne r3, [r0], #4
+ strneh r3, [r2]
+ movne r3, r3, lsr #16
+ strneh r3, [r2]
+
+ tst r1, #1 /* one halfword left? */
+ ldrneh r3, [r0], #2
+ strneh r3, [r2]
+
+ ldmfd sp!, {r4, r5, r6, pc}
+
+.w_end:
+ .size copy_write_sectors,.w_end-copy_write_sectors
diff --git a/firmware/target/arm/ata-target.h b/firmware/target/arm/ata-target.h
index 0f25f89..d6c5f51 100644
--- a/firmware/target/arm/ata-target.h
+++ b/firmware/target/arm/ata-target.h
@@ -19,15 +19,25 @@
#if (CONFIG_CPU == PP5002) || (CONFIG_CPU == PP5020)
-/* Plain C read & write loops */
-
#if (CONFIG_CPU == PP5002)
+
+/* Plain C reading and writing. See comment in ata-as-arm.S */
+
#define ATA_IOBASE 0xc00031e0
#define ATA_CONTROL (*((volatile unsigned char*)(0xc00033f8)))
+
#elif (CONFIG_CPU == PP5020)
+
+/* asm optimized reading and writing */
+#define ATA_OPTIMIZED_READING
+#define ATA_OPTIMIZED_WRITING
+void copy_read_sectors(unsigned char* buf, int wordcount);
+void copy_write_sectors(const unsigned char* buf, int wordcount);
+
#define ATA_IOBASE 0xc30001e0
#define ATA_CONTROL (*((volatile unsigned char*)(0xc30003f8)))
-#endif
+
+#endif /* CONFIG_CPU */
#define ATA_DATA (*((volatile unsigned short*)(ATA_IOBASE)))
#define ATA_ERROR (*((volatile unsigned char*)(ATA_IOBASE + 0x04)))