From: Will Sowerbutts Date: Mon, 29 Dec 2014 00:47:58 +0000 (+0000) Subject: Kernel: Add a generic SD/MMC storage card driver, using SPI bus X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=0216dee9ab704f71a2a5c09848502ef6691c3f9c;p=FUZIX.git Kernel: Add a generic SD/MMC storage card driver, using SPI bus functions provided by the platform. Also includes a driver for the SD card SPI bus on the n8vem-mark4 platform. --- diff --git a/Kernel/cpu-z180/z180.h b/Kernel/cpu-z180/z180.h index 591b896e..61b4d44f 100644 --- a/Kernel/cpu-z180/z180.h +++ b/Kernel/cpu-z180/z180.h @@ -46,6 +46,9 @@ __sfr __at (Z180_IO_BASE + 0x1B) ASCI_ASTC0H; /* ASCI time constant register c __sfr __at (Z180_IO_BASE + 0x1C) ASCI_ASTC1L; /* ASCI time constant register channel 1 low */ __sfr __at (Z180_IO_BASE + 0x1D) ASCI_ASTC1H; /* ASCI time constant register channel 1 high */ +__sfr __at (Z180_IO_BASE + 0x0A) CSIO_CNTR; /* CSI/O control/status register */ +__sfr __at (Z180_IO_BASE + 0x0B) CSIO_TRDR; /* CSI/O transmit/receive data register */ + __sfr __at (0xE0) ESCC_CTRL_A; /* ESCC Channel A control register */ __sfr __at (0xE1) ESCC_DATA_A; /* ESCC Channel A data register */ __sfr __at (0xE2) ESCC_CTRL_B; /* ESCC Channel B control register */ diff --git a/Kernel/dev/devsd.c b/Kernel/dev/devsd.c new file mode 100644 index 00000000..d5ecb433 --- /dev/null +++ b/Kernel/dev/devsd.c @@ -0,0 +1,373 @@ +/*-----------------------------------------------------------------------*/ +/* Fuzix SD card driver */ +/* 2014-12-28 Will Sowerbutts */ +/* */ +/* Based on UZI-socz80 SD card driver, which was itself based on: */ +/* MMCv3/SDv1/SDv2 (in SPI mode) control module (C)ChaN, 2007 */ +/* (from http://www.cl.cam.ac.uk/teaching/1011/P31/lib/diskio.c) */ +/* and http://elm-chan.org/docs/mmc/mmc_e.html */ +/*-----------------------------------------------------------------------*/ + +/* Minor numbers: See comments in devide.c, exactly the same scheme is used here. */ + +#include +#include +#include +#include +#include +#include +#include +#include "config.h" + +#define MAX_SLICES 63 + +/* keep track of current card type, UZI partition offset */ +static uint8_t sd_drive_present; /* bitmap */ +static uint8_t sd_card_type[SD_DRIVE_COUNT]; +static uint32_t sd_partition_start[SD_DRIVE_COUNT]; +static uint8_t sd_slice_count[SD_DRIVE_COUNT]; + +/* internal functions */ +static void sd_init_drive(uint8_t drive); +static int sd_readwrite(uint8_t minor, uint8_t rawflag, bool do_write); +static int sd_spi_init(uint8_t drive); +static void sd_spi_release(uint8_t drive); +static int sd_spi_wait_ready(uint8_t drive); +static bool sd_spi_transmit_block(uint8_t drive, void *ptr, unsigned int length); +static bool sd_spi_receive_block(uint8_t drive, void *ptr, unsigned int length); +static int sd_send_command(uint8_t drive, unsigned char cmd, uint32_t arg); +static uint32_t sd_get_size_sectors(uint8_t drive); +static bool sd_read_sector(uint8_t drive, void *ptr, uint32_t lba); +static bool sd_write_sector(uint8_t drive, void *ptr, uint32_t lba); + +int devsd_open(uint8_t minor, uint16_t flags) +{ + uint8_t drive; + flags; /* not used */ + + drive = minor >> 6; + minor = minor & 0x3F; + + if(sd_drive_present & (1 << drive) && (minor == 0 || minor < sd_slice_count[drive])) + return 0; + + udata.u_error = ENODEV; + return -1; +} + +int devsd_read(uint8_t minor, uint8_t rawflag, uint8_t flag) +{ + flag; /* not used */ + return sd_readwrite(minor, rawflag, false); +} + +int devsd_write(uint8_t minor, uint8_t rawflag, uint8_t flag) +{ + flag; /* not used */ + return sd_readwrite(minor, rawflag, true); +} + +void devsd_init(void) +{ + uint8_t d; + + sd_drive_present = 0; + for(d=0; d> 6; + minor = minor & 0x3F; + + if(rawflag == 0){ + target = udata.u_buf->bf_data; + + for(attempt=0; attempt<5; attempt++){ + lba = udata.u_buf->bf_blk; + + /* minor 0 is the whole drive, without translation */ + if(minor > 0){ + lba += sd_partition_start[drive]; + lba += ((unsigned long)(minor-1) << SLICE_SIZE_LOG2_SECTORS); + } + if(do_write){ + if(sd_write_sector(drive, udata.u_buf->bf_data, lba)) + return 1; + }else{ + if(sd_read_sector(drive, udata.u_buf->bf_data, lba)) + return 1; + } + kputs("sd: failed, retrying.\n"); + } + } + + udata.u_error = EIO; + return -1; +} + +static void sd_init_drive(uint8_t drive) +{ + uint32_t sector_count; + unsigned char *sector; + + sd_partition_start[drive] = 0; + sd_slice_count[drive] = 0; + + kprintf("sd%c: ", 'a'+drive); + sd_card_type[drive] = sd_spi_init(drive); + + if(!(sd_card_type[drive] & (~CT_BLOCK))){ + kprintf("no card found\n"); + return; + } + + /* read and compute card size */ + sector_count = sd_get_size_sectors(drive); + if(!sector_count){ + kputs("weird card\n"); + return; + } + + /* read partition table, locate the UZI partition */ + sector = (unsigned char*)tmpbuf(); + + if(!sd_read_sector(drive, sector, 0)){ + kprintf("failed to read partition table\n"); + goto failout; + } + + /* if we get this far the drive is probably ok */ + sd_drive_present |= (1 << drive); + + /* look for our partition */ + parse_partition_table(sector, &sd_partition_start[drive], &sd_slice_count[drive], MAX_SLICES); + +failout: + brelse((bufptr)sector); +} + +static int sd_spi_init(uint8_t drive) +{ + unsigned char n, cmd, card_type, ocr[4]; + timer_t timer; + + sd_spi_raise_cs(drive); + + sd_spi_clock(drive, false); + for (n = 20; n; n--) + sd_spi_receive_byte(drive); /* 160 dummy clocks */ + + card_type = 0; + /* Enter Idle state */ + if (sd_send_command(drive, CMD0, 0) == 1) { + /* initialisation timeout 1 second */ + timer = set_timer_sec(1); + if (sd_send_command(drive, CMD8, (uint32_t)0x1AA) == 1) { /* SDHC */ + /* Get trailing return value of R7 resp */ + for (n = 0; n < 4; n++) ocr[n] = sd_spi_receive_byte(drive); + /* The card can work at vdd range of 2.7-3.6V */ + if (ocr[2] == 0x01 && ocr[3] == 0xAA) { + /* Wait for leaving idle state (ACMD41 with HCS bit) */ + while(!timer_expired(timer) && sd_send_command(drive, ACMD41, (uint32_t)1 << 30)); + /* Check CCS bit in the OCR */ + if (!timer_expired(timer) && sd_send_command(drive, CMD58, 0) == 0) { + for (n = 0; n < 4; n++) ocr[n] = sd_spi_receive_byte(drive); + card_type = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* SDv2 */ + } + } + } else { /* SDSC or MMC */ + if (sd_send_command(drive, ACMD41, 0) <= 1) { + /* SDv1 */ + card_type = CT_SD1; + cmd = ACMD41; + } else { + /* MMCv3 */ + card_type = CT_MMC; + cmd = CMD1; + } + /* Wait for leaving idle state */ + while(!timer_expired(timer) && sd_send_command(drive, cmd, 0)); + /* Set R/W block length to 512 */ + if(timer_expired || sd_send_command(drive, CMD16, 512) != 0) + card_type = 0; + } + } + sd_spi_release(drive); + + if (card_type) { + sd_spi_clock(drive, true); /* up to 20MHz should be OK */ + return card_type; + } + + return 0; /* failed */ +} + +static void sd_spi_release(uint8_t drive) +{ + sd_spi_raise_cs(drive); + sd_spi_receive_byte(drive); +} + +static int sd_spi_wait_ready(uint8_t drive) +{ + unsigned char res; + timer_t timer; + + timer = set_timer_ms(100); + sd_spi_receive_byte(drive); + do{ + res = sd_spi_receive_byte(drive); + if(timer_expired(timer)){ + kputs("sd_spi_wait_ready: timeout\n"); + break; + } + }while ((res != 0xFF)); + + return res; +} + +static bool sd_spi_transmit_block(uint8_t drive, void *ptr, unsigned int length) +{ + unsigned char reply; + + if(sd_spi_wait_ready(drive) != 0xFF) + return false; /* failed */ + + sd_spi_transmit_byte(drive, 0xFE); + sd_spi_transmit_from_memory(drive, ptr, length); + sd_spi_transmit_byte(drive, 0xFF); /* dummy CRC */ + sd_spi_transmit_byte(drive, 0xFF); + reply = sd_spi_receive_byte(drive); + if((reply & 0x1f) != 0x05) + return false; /* failed */ + return true; /* hooray! */ +} + +static bool sd_spi_receive_block(uint8_t drive, void *ptr, unsigned int length) +{ + unsigned int timer; + unsigned char b; + + timer = set_timer_ms(250); + + do{ + b = sd_spi_receive_byte(drive); + if(timer_expired(timer)){ + kputs("sd_spi_receive_block: timeout\n"); + return false; + } + }while(b == 0xFF); + + if(b != 0xFE) + return false; /* failed */ + + return sd_spi_receive_to_memory(drive, ptr, length); /* returns true on success */ +} + +static int sd_send_command(uint8_t drive, unsigned char cmd, uint32_t arg) +{ + unsigned char n, res, *p; + + if (cmd & 0x80) { /* ACMD is the command sequense of CMD55-CMD */ + cmd &= 0x7F; + res = sd_send_command(drive, CMD55, 0); + if (res > 1) + return res; + } + + /* Select the card and wait for ready */ + sd_spi_raise_cs(drive); + sd_spi_lower_cs(drive); + if (sd_spi_wait_ready(drive) != 0xFF) + return 0xFF; + + /* Send command packet */ + sd_spi_transmit_byte(drive, cmd); /* Start + Command index */ +#if 0 + sd_spi_transmit_byte(drive, (unsigned char)(arg >> 24)); /* Argument[31..24] */ + sd_spi_transmit_byte(drive, (unsigned char)(arg >> 16)); /* Argument[23..16] */ + sd_spi_transmit_byte(drive, (unsigned char)(arg >> 8)); /* Argument[15..8] */ + sd_spi_transmit_byte(drive, (unsigned char)arg); /* Argument[7..0] */ +#else + /* sdcc sadly unable to figure this out for itself yet */ + p = (unsigned char *)&arg; + sd_spi_transmit_byte(drive, p[3]); /* Argument[31..24] */ + sd_spi_transmit_byte(drive, p[2]); /* Argument[23..16] */ + sd_spi_transmit_byte(drive, p[1]); /* Argument[15..8] */ + sd_spi_transmit_byte(drive, p[0]); /* Argument[7..0] */ +#endif + /* there's only a few commands (in native mode) that need correct CRCs */ + n = 0x01; /* Dummy CRC + Stop */ + if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) */ + if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) */ + sd_spi_transmit_byte(drive, n); + + /* Receive command response */ + if (cmd == CMD12) + sd_spi_receive_byte(drive); /* Skip a stuff byte when stop reading */ + n = 10; /* Wait for a valid response in timeout of 10 attempts */ + do{ + res = sd_spi_receive_byte(drive); + }while ((res & 0x80) && --n); + + return res; /* Return with the response value */ +} + +static uint32_t sd_get_size_sectors(uint8_t drive) +{ + unsigned char csd[16], n; + uint32_t sectors = 0; + + if(sd_send_command(drive, CMD9, 0) == 0 && sd_spi_receive_block(drive, csd, 16)){ + if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */ + sectors = ((uint32_t)csd[9] + (uint32_t)((unsigned int)csd[8] << 8) + 1) << 10; + } else { /* SDC ver 1.XX or MMC*/ + n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2; + sectors = (csd[8] >> 6) + ((unsigned int)csd[7] << 2) + ((unsigned int)(csd[6] & 3) << 10) + 1; + sectors = sectors << (n - 9); + } + } + sd_spi_release(drive); + return sectors; +} + +static bool sd_read_sector(uint8_t drive, void *ptr, uint32_t lba) +{ + bool r = false; + + if(sd_card_type[drive] != CT_NONE){ + if(!(sd_card_type[drive] & CT_BLOCK)) + lba = lba << 9; /* multiply by 512 to get byte address */ + + if(sd_send_command(drive, CMD17, lba) == 0) + r = sd_spi_receive_block(drive, ptr, 512); + + sd_spi_release(drive); + } + + return r; +} + +static bool sd_write_sector(uint8_t drive, void *ptr, uint32_t lba) +{ + bool r = false; + + if(sd_card_type[drive] != CT_NONE){ + if(!(sd_card_type[drive] & CT_BLOCK)) + lba = lba << 9; /* multiply by 512 to get byte address */ + + if(sd_send_command(drive, CMD24, lba) == 0) + r = sd_spi_transmit_block(drive, ptr, 512); + + sd_spi_release(drive); + } + + return r; +} diff --git a/Kernel/dev/devsd.h b/Kernel/dev/devsd.h new file mode 100644 index 00000000..62a98a40 --- /dev/null +++ b/Kernel/dev/devsd.h @@ -0,0 +1,58 @@ +#ifndef __DEVSD_DOT_H__ +#define __DEVSD_DOT_H__ + +/* SD Configuration (in config.h) + + Define DEVICE_SD if SD hardware is present on your platform. + + Define SD_DRIVE_COUNT to the number of SD cards your hardware + supports (range 1--4). + + Provide the platform-specific SPI functions listed below to + drive the SPI bus on your hardware, for an example of how to + do this see platform-n8vem-mark4/devsdspi.c +*/ + + +/* public interface */ +int devsd_open(uint8_t minor, uint16_t flags); +int devsd_read(uint8_t minor, uint8_t rawflag, uint8_t flag); +int devsd_write(uint8_t minor, uint8_t rawflag, uint8_t flag); +void devsd_init(void); + +/* platform-specific SPI functions */ +void sd_spi_clock(uint8_t drive, bool go_fast); +void sd_spi_raise_cs(uint8_t drive); +void sd_spi_lower_cs(uint8_t drive); +void sd_spi_transmit_byte(uint8_t drive, uint8_t byte); +uint8_t sd_spi_receive_byte(uint8_t drive); +bool sd_spi_receive_to_memory(uint8_t drive, uint8_t *ptr, unsigned int length); +bool sd_spi_transmit_from_memory(uint8_t drive, uint8_t *ptr, unsigned int length); + +/* Definitions for MMC/SDC command */ +#define CMD0 (0x40+0) /* GO_IDLE_STATE */ +#define CMD1 (0x40+1) /* SEND_OP_COND (MMC) */ +#define ACMD41 (0xC0+41) /* SEND_OP_COND (SDC) */ +#define CMD8 (0x40+8) /* SEND_IF_COND */ +#define CMD9 (0x40+9) /* SEND_CSD */ +#define CMD10 (0x40+10) /* SEND_CID */ +#define CMD12 (0x40+12) /* STOP_TRANSMISSION */ +#define ACMD13 (0xC0+13) /* SD_STATUS (SDC) */ +#define CMD16 (0x40+16) /* SET_BLOCKLEN */ +#define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */ +#define CMD18 (0x40+18) /* READ_MULTIPLE_BLOCK */ +#define CMD23 (0x40+23) /* SET_BLOCK_COUNT (MMC) */ +#define ACMD23 (0xC0+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */ +#define CMD24 (0x40+24) /* WRITE_BLOCK */ +#define CMD25 (0x40+25) /* WRITE_MULTIPLE_BLOCK */ +#define CMD55 (0x40+55) /* APP_CMD */ +#define CMD58 (0x40+58) /* READ_OCR */ + +#define CT_NONE 0x00 +#define CT_MMC 0x01 +#define CT_SD1 0x02 +#define CT_SD2 0x04 +#define CT_SDC (CT_SD1|CT_SD2) +#define CT_BLOCK 0x08 + +#endif /* __DEVSD_DOT_H__ */ diff --git a/Kernel/platform-n8vem-mark4/Makefile b/Kernel/platform-n8vem-mark4/Makefile index e6680a0c..decc6332 100644 --- a/Kernel/platform-n8vem-mark4/Makefile +++ b/Kernel/platform-n8vem-mark4/Makefile @@ -1,5 +1,5 @@ -CSRCS += devices.c main.c devtty.c -DSRCS = ../dev/devide.c ../dev/mbr.c +CSRCS += devices.c main.c devtty.c devsdspi.c +DSRCS = ../dev/devide.c ../dev/devsd.c ../dev/mbr.c ASRCS = crt0.s z180.s mark4.s commonmem.s diff --git a/Kernel/platform-n8vem-mark4/README b/Kernel/platform-n8vem-mark4/README index 50248e13..f2a11026 100644 --- a/Kernel/platform-n8vem-mark4/README +++ b/Kernel/platform-n8vem-mark4/README @@ -3,7 +3,7 @@ By Will Sowerbutts Assumes an N8VEM Mark IV SBC fitted with 512KB RAM, with the RS232 port as tty1, and the RS422 port as tty2. Does not yet support any ECB peripheral -boards. +boards. On-board IDE and SD mass storage interfaces are both supported. To build, edit ../Makefile to read: diff --git a/Kernel/platform-n8vem-mark4/config.h b/Kernel/platform-n8vem-mark4/config.h index 2b6ce54c..22377c40 100644 --- a/Kernel/platform-n8vem-mark4/config.h +++ b/Kernel/platform-n8vem-mark4/config.h @@ -54,3 +54,6 @@ #define IDE_REG_BASE MARK4_IO_BASE #define IDE_8BIT_ONLY #define IDE_REG_CS1_FIRST + +#define DEVICE_SD +#define SD_DRIVE_COUNT 1 diff --git a/Kernel/platform-n8vem-mark4/devices.c b/Kernel/platform-n8vem-mark4/devices.c index 2e861aa2..ad3c585d 100644 --- a/Kernel/platform-n8vem-mark4/devices.c +++ b/Kernel/platform-n8vem-mark4/devices.c @@ -5,6 +5,7 @@ #include #include #include +#include struct devsw dev_tab[] = /* The device driver switch table */ { @@ -13,9 +14,9 @@ struct devsw dev_tab[] = /* The device driver switch table */ /* 0: /dev/hd IDE-8 interface */ { devide_open, no_close, devide_read, devide_write, no_ioctl }, /* 1: /dev/sd SD interface */ - { no_open, no_close, no_rdwr, no_rdwr, no_ioctl }, + { devsd_open, no_close, devsd_read, devsd_write, no_ioctl }, /* 2: /dev/tty serial ports */ - { tty_open, tty_close, tty_read, tty_write, tty_ioctl }, + { tty_open, tty_close, tty_read, tty_write, tty_ioctl }, /* 3: /dev/lpr Unused slot (pad to keep system devices at index 4) */ { no_open, no_close, no_rdwr, no_rdwr, no_ioctl }, /* 4: /dev/mem etc System devices (one offs) */ @@ -28,7 +29,7 @@ bool validdev(uint16_t dev) /* This is a bit uglier than needed but the right hand side is a constant this way */ if(dev > ((sizeof(dev_tab)/sizeof(struct devsw)) << 8) + 255) - return false; + return false; else return true; } @@ -36,4 +37,5 @@ bool validdev(uint16_t dev) void device_init(void) { devide_init(); + devsd_init(); } diff --git a/Kernel/platform-n8vem-mark4/devsdspi.c b/Kernel/platform-n8vem-mark4/devsdspi.c new file mode 100644 index 00000000..ec0d0740 --- /dev/null +++ b/Kernel/platform-n8vem-mark4/devsdspi.c @@ -0,0 +1,164 @@ +/*-----------------------------------------------------------------------*/ +/* N8VEM Mark IV Z180 CSI/O SPI SD driver */ +/* 2014-12-27 Will Sowerbutts */ +/*-----------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include "config.h" +#include + +#define CSIO_CNTR_TE (1<<4) /* transmit enable */ +#define CSIO_CNTR_RE (1<<5) /* receive enable */ +#define CSIO_CNTR_END_FLAG (1<<7) /* operation completed flag */ + +#define MARK4_SD_CS (1<<2) /* chip select */ +#define MARK4_SD_WRITE_PROTECT (1<<4) /* write protect */ +#define MARK4_SD_CARD_DETECT (1<<5) /* card detect */ +#define MARK4_SD_INT_ENABLE (1<<6) /* interrupt enable */ +#define MARK4_SD_INT_PENDING (1<<7) /* interrupt enable */ + +__sfr __at (MARK4_IO_BASE + 0x09) MARK4_SD; + +/* the CSI/O and SD card send bits in opposite orders, so we need to flip them over */ +static uint8_t reverse_byte[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff +}; + + +void sd_spi_clock(uint8_t drive, bool go_fast) +{ + unsigned char c; + drive; /* not used */ + + c = CSIO_CNTR & 0xf8; /* clear low three bits, gives fastest rate (clk/20) */ + if(!go_fast) + c = c | 0x03; /* set low two bits, clk/160 (can go down to clk/1280, see data sheet) */ + CSIO_CNTR = c; +} + +void sd_spi_raise_cs(uint8_t drive) +{ + drive; /* not used */ + /* wait for idle */ + while(CSIO_CNTR & (CSIO_CNTR_TE | CSIO_CNTR_RE)); + MARK4_SD = MARK4_SD & (~MARK4_SD_CS); +} + +void sd_spi_lower_cs(uint8_t drive) +{ + drive; /* not used */ + /* wait for idle */ + while(CSIO_CNTR & (CSIO_CNTR_TE | CSIO_CNTR_RE)); + MARK4_SD = MARK4_SD | MARK4_SD_CS; +} + +void sd_spi_transmit_byte(uint8_t drive, unsigned char byte) +{ + unsigned char c; + drive; /* not used */ + + /* reverse the bits before we busywait */ + byte = reverse_byte[byte]; + + /* wait for any current transmit operation to complete */ + do{ + c = CSIO_CNTR; + }while(c & CSIO_CNTR_TE); + + /* write the byte and enable transmitter */ + CSIO_TRDR = byte; + CSIO_CNTR = c | CSIO_CNTR_TE; +} + +uint8_t sd_spi_receive_byte(uint8_t drive) +{ + unsigned char c; + drive; /* not used */ + + /* wait for any current transmit or receive operation to complete */ + do{ + c = CSIO_CNTR; + }while(c & (CSIO_CNTR_TE | CSIO_CNTR_RE)); + + /* enable receive operation */ + CSIO_CNTR = c | CSIO_CNTR_RE; + + /* wait for receive to complete */ + while(CSIO_CNTR & CSIO_CNTR_RE); + + /* read byte */ + return reverse_byte[CSIO_TRDR]; +} + +bool sd_spi_receive_to_memory(uint8_t drive, uint8_t *ptr, unsigned int length) +{ + unsigned char c; + drive; /* not used */ + + /* wait for any current transmit or receive operation to complete */ + do{ + c = CSIO_CNTR; + }while(c & (CSIO_CNTR_TE | CSIO_CNTR_RE)); + + while(length){ + /* enable receive operation */ + CSIO_CNTR = c | CSIO_CNTR_RE; + + /* wait for receive to complete */ + do{ + c = CSIO_CNTR; + }while(c & CSIO_CNTR_RE); + + /* read byte */ + *ptr = reverse_byte[CSIO_TRDR]; + + /* next byte */ + ptr++; + length--; + } + + return true; +} + +bool sd_spi_transmit_from_memory(uint8_t drive, uint8_t *ptr, int length) +{ + unsigned char c, b; + drive; /* not used */ + + while(length){ + b = reverse_byte[*ptr]; + + /* wait for transmit to complete */ + do{ + c = CSIO_CNTR; + }while(c & CSIO_CNTR_TE); + + /* write the byte and enable transmitter */ + CSIO_TRDR = b; + CSIO_CNTR = c | CSIO_CNTR_TE; + + /* next byte */ + ptr++; + length--; + } + return true; +} diff --git a/Kernel/platform-n8vem-mark4/uzi.lnk b/Kernel/platform-n8vem-mark4/uzi.lnk index 6d10b67a..31c4371b 100644 --- a/Kernel/platform-n8vem-mark4/uzi.lnk +++ b/Kernel/platform-n8vem-mark4/uzi.lnk @@ -33,5 +33,7 @@ swap.rel devsys.rel platform-n8vem-mark4/devtty.rel platform-n8vem-mark4/devide.rel +platform-n8vem-mark4/devsd.rel +platform-n8vem-mark4/devsdspi.rel platform-n8vem-mark4/mbr.rel -e