From f093346b5752ed8b76feabdfb7bc0a04d9376cbe Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sun, 19 Aug 2018 15:19:26 +0100 Subject: [PATCH] sam: more work on the ATA disk interface We can now detect Atom and Atom Lite, as well as select the right 8 or 16bit handling for them. The 16bit handlers are hairy because we can be doing an I/O that crosses a page boundary. This needs a bit of thought to keep it efficient. Atom Lite on the other hand appears to be trivial. --- Kernel/platform-sam/atom.s | 104 ++++++++++++++++++----------- Kernel/platform-sam/devatom.c | 25 +++++++ Kernel/platform-sam/discard.c | 4 +- Kernel/platform-sam/platform_ide.h | 5 ++ 4 files changed, 98 insertions(+), 40 deletions(-) diff --git a/Kernel/platform-sam/atom.s b/Kernel/platform-sam/atom.s index dff0897a..e343ac57 100644 --- a/Kernel/platform-sam/atom.s +++ b/Kernel/platform-sam/atom.s @@ -38,6 +38,9 @@ BLKPARAM_SWAP_PAGE .equ 3 IDE_DATA_R .equ 0x00F6 IDE_DATA_W .equ 0x00F7 +; +; TODO: Use atom_ methods once written and we have them workable +; _devide_read_data: ld a, (_blk_op + BLKPARAM_IS_USER_OFFSET) ld hl, (_blk_op + BLKPARAM_ADDR_OFFSET) @@ -91,48 +94,66 @@ ide_w2: call atomlite_writer pop ix jp map_kernel_low + ; -; This needs optimizing to use as we know C = 0 - but think about -; the hard case with atom and split transfers. Probably need to -; unroll the loop into two halves, check termination on each and also -; somehow indicate partial transfers. We do know the transfer will be -; a total of 512 bytes so the rule I think is -; if bit 0,c on 1st transfer - it's split word +; Routines for the Atom IDE 16bit interface +; +; Not yet finished ; -atomlite_reader: - ld a,#0x30 - out (0xF5),a ; Select data port - ld d,b - ld e,c - ld bc,#0xF6 -ide_r_loop: - ini - dec de - ld a,d - or e - jr nz,ide_r_loop - ret ; ; The non split case 512 bytes as fast as we can given the interface ; design ; -atomlite_reader_fast: +atom_reader_fast: ; Select data port ld a,#0x30 out (0xF5),a - ld bc,#0xF7 - xor a ; 256 words -atomlite_rf_loop: - dec c + ld bc,#0xF7 ; 256 words, port F7 +atom_rf_loop: + ld a,(0xF6) ini ; Read from F6 for the data high - inc c - inc b ; so it's one loop of 256 counts - ini - jr nz, atomlite_rf_loop + ld (hl),a + inc hl + jr nz,atom_rf_loop + ret +; +; The non split case 512 bytes as fast as we can given the interface +; design. For Atomlite we could just inir +; +atom_writer_fast: + ld a,#0x30 + out (0xF5),a ; Select data port + ld bc,#0xF7 ; 256 words port F7 +atomlite_wf_loop: + ld a,(hl) + inc hl + outi + out (0xF6),a + jr nz, atomlite_wf_loop ret + +; +; The Atomlite is simpler +; + ; -; This needs optimizing to use as we know C = 0 +; The Atomlite reader is simple ; +atomlite_reader_fast: + ld a,#0x30 + out (0xF5),a + ld bc,#0xF7 + inir + inir + ret +atomlite_writer_fast: + ld a,#0x30 + out (0xF5),a + ld bc,#0xF7 ; 256 bytes port F7 + otir + otir + ret + atomlite_writer: ld a,#0x30 out (0xF5),a ; Select data port @@ -147,18 +168,23 @@ ide_w_loop: jr nz,ide_w_loop ret ; -; The non split case 512 bytes as fast as we can given the interface -; design. For Atomlite we could just inir +; This needs optimizing to use as we know C = 0 - but think about +; the hard case with atom and split transfers. Probably need to +; unroll the loop into two halves, check termination on each and also +; somehow indicate partial transfers. We do know the transfer will be +; a total of 512 bytes so the rule I think is +; if bit 0,c on 1st transfer - it's split word ; -atomlite_writer_fast: +atomlite_reader: ld a,#0x30 out (0xF5),a ; Select data port + ld d,b + ld e,c ld bc,#0xF6 -atomlite_wf_loop: - inc c - outi ; Write F6 - dec c - inc b ; So it's 256 times count - outi ; Then F7 - jr nz, atomlite_wf_loop +ide_r_loop: + ini + dec de + ld a,d + or e + jr nz,ide_r_loop ret diff --git a/Kernel/platform-sam/devatom.c b/Kernel/platform-sam/devatom.c index ce45111d..ccb4c841 100644 --- a/Kernel/platform-sam/devatom.c +++ b/Kernel/platform-sam/devatom.c @@ -1,11 +1,14 @@ #include #include #include +#include __sfr __at 0xF5 ide_addr; __sfr __at 0xF6 ide_high; __sfr __at 0xF7 ide_low; +uint8_t atom_type; + uint8_t devide_readb(uint8_t reg) { volatile uint8_t dummy; @@ -20,3 +23,25 @@ void devide_writeb(uint8_t reg, uint8_t value) ide_high = 0; ide_low = value; } + +uint8_t atom_probe(void) +{ + ide_addr = ide_reg_lba_0; + ide_high = 0xAA; + ide_low = 0x55; + /* This triggers the read back. On an AtomLite it reads the lba register + and returns it. On the Atom it reads the lba register and latches it + and returns the high 8bits - ie 0 */ + if (ide_high == 0x55) { + kputs("AtomLite IDE detected.\n"); + atom_type = ATOM_LITE; + return 1; + } + /* Did we latch 0x55. If so we have a real Atom IDE */ + if (ide_low == 0x55) { + kputs("Atom IDE detected.\n"); + atom_type = ATOM_16BIT; + return 1; + } + return 0; +} diff --git a/Kernel/platform-sam/discard.c b/Kernel/platform-sam/discard.c index b65e6749..6254053b 100644 --- a/Kernel/platform-sam/discard.c +++ b/Kernel/platform-sam/discard.c @@ -4,6 +4,7 @@ #include #include #include +#include void map_init(void) { @@ -30,5 +31,6 @@ void device_init(void) /* Time of day clock */ inittod(); #endif - devide_init(); + if (atom_probe()) + devide_init(); } diff --git a/Kernel/platform-sam/platform_ide.h b/Kernel/platform-sam/platform_ide.h index dc55ee37..fcf35bf9 100644 --- a/Kernel/platform-sam/platform_ide.h +++ b/Kernel/platform-sam/platform_ide.h @@ -45,3 +45,8 @@ #define ide_reg_altstatus (IDE_CS3 | 6) #define ide_reg_control (IDE_CS3 | 7) + +#include + +#define IDE_8BIT_ONLY /* For the Atomlite */ +#define IDE_IS_8BIT(drive) (atom_type != ATOM_16BIT) -- 2.34.1