diff --git a/distrib/sets/lists/minix-base/md.evbarm b/distrib/sets/lists/minix-base/md.evbarm index ddb43e324..41499b2af 100644 --- a/distrib/sets/lists/minix-base/md.evbarm +++ b/distrib/sets/lists/minix-base/md.evbarm @@ -16,12 +16,14 @@ ./etc/system.conf.d/usbd minix-base ./service/bmp085 minix-base ./service/cat24c256 minix-base -./service/emmc minix-base +./service/omap_emmc minix-base +./service/rpi_emmc minix-base ./service/fb minix-base ./service/gpio minix-base ./service/i2c minix-base ./service/lan8710a minix-base -./service/mmc minix-base +./service/omap_mmc minix-base +./service/rpi_mmc minix-base ./service/random minix-base ./service/sht21 minix-base ./service/tda19988 minix-base diff --git a/etc/system.conf b/etc/system.conf index a2d6bc006..9c81549c0 100644 --- a/etc/system.conf +++ b/etc/system.conf @@ -430,7 +430,7 @@ service devman ; }; -service mmc +service omap_mmc { system PRIVCTL # 4 @@ -444,6 +444,19 @@ service mmc priority 4; # priority queue 4 }; +service rpi_mmc +{ + system + PRIVCTL # 4 + IRQCTL # 19 + ; + # Interrupts allowed + irq + 24 + ; # IRQs allowed + priority 4; # priority queue 4 +}; + service fb { system @@ -526,7 +539,19 @@ service edfictl ipc ALL; }; -service emmc +service rpi_emmc +{ + system + PRIVCTL + IRQCTL + PADCONF + ; + irq + 28 # MMCSD1INT + ; +}; + +service omap_emmc { system PRIVCTL diff --git a/minix/drivers/storage/mmc/Makefile b/minix/drivers/storage/mmc/Makefile index 630994824..827131216 100644 --- a/minix/drivers/storage/mmc/Makefile +++ b/minix/drivers/storage/mmc/Makefile @@ -1,18 +1,4 @@ -# Makefile for the mmc driver. -PROGS= mmc emmc -MAN.mmc= -MAN.emmc= +.include +SUBDIR+= rpi omap -SRCS.mmc= mmcblk.c mmchost_dummy.c sdhcreg.h sdmmcreg.h -SRCS.mmc += mmchost_mmchs.c -SRCS.emmc= emmc.c mmcblk.c - -DPADD+= ${LIBBLOCKDRIVER} ${LIBSYS} -LDADD+= -lblockdriver -lsys -CLEANFILES+=.depend mmcblk.d - -# -# This is a system driver. -CPPFLAGS+= -D_SYSTEM=1 - -.include +.include diff --git a/minix/drivers/storage/mmc/mmcblk.c b/minix/drivers/storage/mmc/mmcblk.c deleted file mode 100644 index 7e5446f29..000000000 --- a/minix/drivers/storage/mmc/mmcblk.c +++ /dev/null @@ -1,663 +0,0 @@ -/* - * Block driver for Multi Media Cards (MMC). - */ -/* kernel headers */ -#include -#include -#include -#include -#include -#include - -/* system headers */ -#include /* disk IOCTL's */ - -/* usr headers */ -#include -#include -#include -#include -#include - -/* local headers */ -#include "mmchost.h" - -/* used for logging */ -static struct log log = { - .name = "mmc_block", - .log_level = LEVEL_INFO, - .log_func = default_log -}; - -/* holding the current host controller */ -static struct mmc_host host; - -#define NR_SUBDEVS (MAX_DRIVES * SUB_PER_DRIVE) - -/* When passing data over a grant one needs to pass - * a buffer to sys_safecopy copybuff is used for that*/ -#define COPYBUFF_SIZE 0x1000 /* 4k buff */ -static unsigned char copybuff[COPYBUFF_SIZE]; - -static struct sd_slot *get_slot(devminor_t minor); - -/* Prototypes for the block device */ -static int block_open(devminor_t minor, int access); -static int block_close(devminor_t minor); -static int block_transfer(devminor_t minor, - int do_write, - u64_t position, - endpoint_t endpt, iovec_t * iov, unsigned int nr_req, int flags); - -static int block_ioctl(devminor_t minor, unsigned long request, - endpoint_t endpt, cp_grant_id_t grant, endpoint_t user_endpt); -static struct device *block_part(devminor_t minor); - -/* System even handling */ -static void sef_local_startup(); -static int block_system_event_cb(int type, sef_init_info_t * info); -static void block_signal_handler_cb(int signo); - -void -bdr_alarm(clock_t stamp) -{ - log_debug(&log, "alarm %d\n", stamp); -} - -static int apply_env(); -static void hw_intr(unsigned int irqs); - -/* set the global logging level */ -static void set_log_level(int level); - -/* Entry points for the BLOCK driver. */ -static struct blockdriver mmc_driver = { - .bdr_type = BLOCKDRIVER_TYPE_DISK,/* handle partition requests */ - .bdr_open = block_open, /* device open */ - .bdr_close = block_close, /* on a close */ - .bdr_transfer = block_transfer, /* does the I/O */ - .bdr_ioctl = block_ioctl, /* ioctls */ - .bdr_part = block_part, /* get partition information */ - .bdr_intr = hw_intr, /* left over interrupts */ - .bdr_alarm = bdr_alarm /* no alarm processing */ -}; - -static void -hw_intr(unsigned int irqs) -{ - log_debug(&log, "Hardware inter left over\n"); - host.hw_intr(irqs); -} - -static int -apply_env() -{ - long v; - /* apply the env setting passed to this driver parameters accepted - * log_level=[0-4] (NONE,WARN,INFO,DEBUG,TRACE) instance=[0-3] - * instance/bus number to use for this driver Passing these arguments - * is done when starting the driver using the service command in the - * following way service up /service/mmc -args "log_level=2 instance=1 - * driver=dummy" -dev /dev/c2d0 */ - char driver[16]; - memset(driver, '\0', 16); - (void) env_get_param("driver", driver, 16); - if (strlen(driver) == 0 - || strncmp(driver, "mmchs", strlen("mmchs") + 1) == 0) { - /* early init of host mmc host controller. This code should - * depend on knowing the hardware that is running bellow. */ -#ifdef __arm__ - host_initialize_host_structure_mmchs(&host); -#endif - } else if (strncmp(driver, "dummy", strlen("dummy") + 1) == 0) { - host_initialize_host_structure_dummy(&host); - } else { - log_warn(&log, "Unknown driver %s\n", driver); - } - /* Initialize the verbosity level. */ - v = 0; - if (env_parse("log_level", "d", 0, &v, LEVEL_NONE, - LEVEL_TRACE) == EP_SET) { - set_log_level(v); - } - - /* Find out which driver instance we are. */ - v = 0; - env_parse("instance", "d", 0, &v, 0, 3); - if (host.host_set_instance(&host, v)) { - log_warn(&log, "Failed to set mmc instance to %d\n", v); - return -1; /* NOT OK */ - } - return OK; -} - -; - -/*===========================================================================* - * block_open * - *===========================================================================*/ -static int -block_open(devminor_t minor, int access) -{ - struct sd_slot *slot; - slot = get_slot(minor); - int i, j; - int part_count, sub_part_count; - - i = j = part_count = sub_part_count = 0; - - if (!slot) { - log_debug(&log, "Not handling open on non existing slot\n"); - return EIO; - } - - assert(slot->host != NULL); - - if (!slot->host->card_detect(slot)) { - log_debug(&log, "No card inserted in the SD slot\n"); - return EIO; - } - - /* If we are already open just increase the open count and return */ - if (slot->card.state == SD_MODE_DATA_TRANSFER_MODE) { - assert(slot->card.open_ct >= 0); - slot->card.open_ct++; - log_trace(&log, "increased open count to %d\n", - slot->card.open_ct); - return OK; - } - - /* We did not have an sd-card inserted so we are going to probe for it - */ - log_debug(&log, "First open on (%d)\n", minor); - if (!host.card_initialize(slot)) { - // * TODO: set card state to INVALID until removed? */ - return EIO; - } - - partition(&mmc_driver, 0 /* first card on bus */ , P_PRIMARY, - 0 /* atapi device?? */ ); - - log_trace(&log, "descr \toffset(bytes) size(bytes)\n", minor); - - log_trace(&log, "disk %d\t0x%016llx 0x%016llx\n", i, - slot->card.part[0].dv_base, slot->card.part[0].dv_size); - for (i = 1; i < 5; i++) { - if (slot->card.part[i].dv_size == 0) - continue; - part_count++; - log_trace(&log, "part %d\t0x%016llx 0x%016llx\n", i, - slot->card.part[i].dv_base, slot->card.part[i].dv_size); - for (j = 0; j < 4; j++) { - if (slot->card.subpart[(i - 1) * 4 + j].dv_size == 0) - continue; - sub_part_count++; - log_trace(&log, - " sub %d/%d\t0x%016llx 0x%016llx\n", i, j, - slot->card.subpart[(i - 1) * 4 + j].dv_base, - slot->card.subpart[(i - 1) * 4 + j].dv_size); - } - } - log_debug(&log, "Found %d partitions and %d sub partitions\n", - part_count, sub_part_count); - slot->card.open_ct++; - assert(slot->card.open_ct == 1); - return OK; -} - -/*===========================================================================* - * block_close * - *===========================================================================*/ -static int -block_close(devminor_t minor) -{ - struct sd_slot *slot; - - slot = get_slot(minor); - if (!slot) { - log_debug(&log, "Not handling open on non existing slot\n"); - return EIO; - } - - /* if we arrived here we expect a card to be present, we will need do - * deal with removal later */ - assert(slot->host != NULL); - assert(slot->card.open_ct >= 1); - - /* If this is not the last open count simply decrease the counter and - * return */ - if (slot->card.open_ct > 1) { - slot->card.open_ct--; - log_trace(&log, "decreased open count to %d\n", - slot->card.open_ct); - return OK; - } - - assert(slot->card.open_ct == 1); - log_debug(&log, "freeing the block device as it is no longer used\n"); - - /* release the card as check the open_ct should be 0 */ - slot->host->card_release(&slot->card); - assert(slot->card.open_ct == 0); - return OK; -} - -static int -copyto(endpoint_t dst_e, - cp_grant_id_t gr_id, vir_bytes offset, vir_bytes address, size_t bytes) -{ - /* Helper function that used memcpy to copy data when the endpoint == - * SELF */ - if (dst_e == SELF) { - memcpy((char *) gr_id + offset, (char *) address, bytes); - return OK; - } else { - /* Read io_size bytes from our data at the correct * offset - * and write it to the output buffer at 0 */ - return sys_safecopyto(dst_e, gr_id, offset, address, bytes); - } -} - -static int -copyfrom(endpoint_t src_e, - cp_grant_id_t gr_id, vir_bytes offset, vir_bytes address, size_t bytes) -{ - /* Helper function that used memcpy to copy data when the endpoint == - * SELF */ - if (src_e == SELF) { - memcpy((char *) address, (char *) gr_id + offset, bytes); - return OK; - } else { - return sys_safecopyfrom(src_e, gr_id, offset, address, bytes); - } -} - -/*===========================================================================* - * block_transfer * - *===========================================================================*/ -static int -block_transfer( - devminor_t minor, /* minor device number */ - int do_write, /* read or write? */ - u64_t position, /* offset on device to read or write */ - endpoint_t endpt, /* process doing the request */ - iovec_t * iov, /* pointer to read or write request vector */ - unsigned int nr_req, /* length of request vector */ - int flags /* transfer flags */ - ) -{ - unsigned long counter; - iovec_t *ciov; /* Current IO Vector */ - struct device *dev; /* The device used */ - struct sd_slot *slot; /* The sd slot the requests is pointed to */ - vir_bytes io_size; /* Size to read/write to/from the iov */ - vir_bytes io_offset; /* Size to read/write to/from the iov */ - vir_bytes bytes_written; - - int r, blk_size, i; - - /* Get the current "device" geometry */ - dev = block_part(minor); - if (dev == NULL) { - log_warn(&log, - "Transfer requested on unknown device minor(%d)\n", minor); - /* Unknown device */ - return ENXIO; - } - log_trace(&log, "I/O on minor(%d) %s at 0x%016llx\n", minor, - (do_write) ? "Write" : "Read", position); - - slot = get_slot(minor); - assert(slot); - - if (slot->card.blk_size == 0) { - log_warn(&log, "Request on a card with block size of 0\n"); - return EINVAL; - } - if (slot->card.blk_size > COPYBUFF_SIZE) { - log_warn(&log, - "Card block size (%d) exceeds internal buffer size %d\n", - slot->card.blk_size, COPYBUFF_SIZE); - return EINVAL; - } - - /* It is fully up to the driver to decide on restrictions for the - * parameters of transfers, in those cases we return EINVAL */ - if (position % slot->card.blk_size != 0) { - /* Starting at a block boundary */ - log_warn(&log, - "Requests must start at a block boundary" - "(start,block size)=(%016llx,%08x)\n", position, - slot->card.blk_size); - return EINVAL; - } - - blk_size = slot->card.blk_size; - - bytes_written = 0; - - /* Are we trying to start reading past the end */ - if (position >= dev->dv_size) { - log_warn(&log, "start reading past drive size\n"); - return 0; - }; - - ciov = iov; - /* do some more validation */ - for (counter = 0; counter < nr_req; counter++) { - assert(ciov != NULL); - if (ciov->iov_size % blk_size != 0) { - /* transfer a multiple of blk_size */ - log_warn(&log, - "Requests must start at a block boundary " - "(start,block size)=(%016llx,%08x)\n", position, - slot->card.blk_size); - return EINVAL; - } - - if (ciov->iov_size <= 0) { - log_warn(&log, - "Invalid iov size for iov %d of %d size\n", - counter, nr_req, ciov->iov_size); - return EINVAL; - } - ciov++; - } - - ciov = iov; - for (counter = 0; counter < nr_req; counter++) { - /* Assume we are to transfer the amount of data given in the - * input/output vector but ensure we are not doing i/o past - * our own boundaries */ - io_size = ciov->iov_size; - io_offset = position + bytes_written; - - /* Check we are not reading/writing past the end */ - if (position + bytes_written + io_size > dev->dv_size) { - io_size = dev->dv_size - (position + bytes_written); - }; - - log_trace(&log, - "I/O %s request(%d/%d) iov(grant,size,iosize," - "offset)=(%d,%d,%d,%d)\n", - (do_write) ? "write" : "read", counter + 1, nr_req, - ciov->iov_addr, ciov->iov_size, io_size, io_offset); - /* transfer max one block at the time */ - for (i = 0; i < io_size / blk_size; i++) { - if (do_write) { - /* Read io_size bytes from i/o vector starting - * at 0 and write it to out buffer at the - * correct offset */ - r = copyfrom(endpt, ciov->iov_addr, - i * blk_size, (vir_bytes) copybuff, - blk_size); - if (r != OK) { - log_warn(&log, - "I/O write error: %s iov(base,size)=(%d,%d)" - " at offset=%d\n", - strerror(_SIGN r), ciov->iov_addr, - ciov->iov_size, io_offset); - return EINVAL; - } - - /* write a single block */ - slot->host->write(&slot->card, - (dev->dv_base / blk_size) + - (io_offset / blk_size) + i, 1, copybuff); - bytes_written += blk_size; - } else { - /* read a single block info copybuff */ - slot->host->read(&slot->card, - (dev->dv_base / blk_size) + - (io_offset / blk_size) + i, 1, copybuff); - /* Read io_size bytes from our data at the - * correct offset and write it to the output - * buffer at 0 */ - r = copyto(endpt, ciov->iov_addr, i * blk_size, - (vir_bytes) copybuff, blk_size); - if (r != OK) { - log_warn(&log, - "I/O read error: %s iov(base,size)=(%d,%d)" - " at offset=%d\n", - strerror(_SIGN r), ciov->iov_addr, - ciov->iov_size, io_offset); - return EINVAL; - } - bytes_written += blk_size; - } - } - ciov++; - } - return bytes_written; -} - -/*===========================================================================* - * block_ioctl * - *===========================================================================*/ -static int -block_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt, - cp_grant_id_t grant, endpoint_t UNUSED(user_endpt)) -{ - /* IOCTL handling */ - struct sd_slot *slot; - log_trace(&log, - "enter (minor,request,endpoint,grant)=(%d,%lu,%d)\n", minor, - request, endpt, grant); - - slot = get_slot(minor); - if (!slot) { - log_warn(&log, - "Doing ioctl on non existing block device(%d)\n", minor); - return EINVAL; - } - - switch (request) { - case DIOCOPENCT: - // TODO: add a check for card validity */ - log_trace(&log, "returning open count %d\n", - slot->card.open_ct); - /* return the current open count */ - return sys_safecopyto(endpt, grant, 0, - (vir_bytes) & slot->card.open_ct, - sizeof(slot->card.open_ct)); - case DIOCFLUSH: - /* No need to flush but some devices like movinands require - * 500 ms inactivity */ - return OK; - } - - return ENOTTY; -} - -/*===========================================================================* - * block_part * - *===========================================================================*/ -static struct device * -block_part(devminor_t minor) -{ - /* - * Reuse the existing MINIX major/minor partitioning scheme. - * - 8 drives - * - 5 devices per drive allowing direct access to the disk and up to 4 - * partitions (IBM style partitioning without extended partitions) - * - 4 Minix style sub partitions per partitions - */ - struct device *dev; - struct sd_slot *slot; - - dev = NULL; - slot = get_slot(minor); - if (!slot) { - log_warn(&log, - "Device information requested for non existing partition " - "minor(%d)\n", minor); - return NULL; - } - - if (!slot->host->card_detect(slot)) { - log_warn(&log, - "Device information requested from empty slot(%d)\n", - minor); - return NULL; - } - - if (minor < 5) { - /* we are talking about the first disk */ - dev = &slot->card.part[minor]; - log_trace(&log, - "returning partition(%d) (base,size)=(0x%016llx,0x%016llx)\n", - minor, dev->dv_base, dev->dv_size); - } else if (minor >= 128 && minor < 128 + 16) { - /* sub partitions of the first disk we don't care about the - * rest */ - dev = &slot->card.subpart[minor - 128]; - log_trace(&log, - "returning sub partition(%d) (base,size)=(0x%016llx,0x%016llx)\n", - minor - 128, dev->dv_base, dev->dv_size); - - } else { - log_warn(&log, - "Device information requested for non existing " - "partition minor(%d)\n", minor); - } - return dev; -} - -/*===========================================================================* - * sef_local_startup * - *===========================================================================*/ -static void -sef_local_startup() -{ - log_info(&log, "Initializing the MMC block device\n"); - if (apply_env()) { - log_warn(&log, "Failed while applying environment settings\n"); - exit(EXIT_FAILURE); - } - - if (host.host_init(&host)) { - log_warn(&log, "Failed to initialize the host controller\n"); - exit(EXIT_FAILURE); - } - /* - * Register callbacks for fresh start, live update and restart. - * Use the same function for all event types - */ - sef_setcb_init_fresh(block_system_event_cb); - - /* Register a signal handler */ - sef_setcb_signal_handler(block_signal_handler_cb); - - /* SEF startup */ - sef_startup(); -} - -/*===========================================================================* - * block_system_event_cb * - *===========================================================================*/ -static int -block_system_event_cb(int type, sef_init_info_t * info) -{ - /* - * Callbacks for the System event framework as registered in - * sef_local_startup */ - switch (type) { - case SEF_INIT_FRESH: - log_info(&log, "System event framework fresh start\n"); - break; - - case SEF_INIT_LU: - /* Restore the state. post update */ - log_info(&log, "System event framework live update\n"); - break; - - case SEF_INIT_RESTART: - log_info(&log, "System event framework post restart\n"); - break; - } - blockdriver_announce(type); - return OK; -} - -/*===========================================================================* - * block_signal_handler_cb * - *===========================================================================*/ -static void -block_signal_handler_cb(int signo) -{ - struct sd_slot *slot; - - log_debug(&log, "System event framework signal handler sig(%d)\n", - signo); - /* Only check for termination signal, ignore anything else. */ - if (signo != SIGTERM) - return; - - /* we only have a single slot and need an open count idealy we should - * iterate over the card to determine the open count */ - slot = get_slot(0); - assert(slot); - if (slot->card.open_ct > 0) { - log_debug(&log, "Not responding to SIGTERM (open count=%d)\n", - slot->card.open_ct); - return; - } - - log_info(&log, "MMC driver exit"); - exit(0); -} - -#define IS_MINIX_SUB_PARTITION_MINOR(minor) (minor >= MINOR_d0p0s0 ) - -static struct sd_slot * -get_slot(devminor_t minor) -{ - /* - * Get an sd_slot based on the minor number. - * - * This driver only supports a single card at at time. Also as - * we are following the major/minor scheme of other driver we - * must return a slot for all minors on disk 0 these are 0-5 - * for the disk and 4 main partitions and - * number 128 till 144 for sub partitions. - */ - /* If this is a minor for the first disk (e.g. minor 0 till 5) */ - if (minor >= 0 && minor / DEV_PER_DRIVE == 0) { - /* we are talking about the first disk and that is all we - * support */ - return &host.slot[0]; - } else if (IS_MINIX_SUB_PARTITION_MINOR(minor) - && (((minor - MINOR_d0p0s0) / SUB_PER_DRIVE) == 0)) { - /* a minor from the first disk */ - return &host.slot[0]; - } else { - log_trace(&log, - "Device information requested for non existing partition " - "minor(%d)\n", minor); - return NULL; - } -} - -static void -set_log_level(int level) -{ - if (level < 0 || level >= 4) { - return; - } - log_info(&log, "Setting verbosity level to %d\n", level); - log.log_level = level; - if (host.set_log_level) { - host.set_log_level(level); - } -} - -int -main(int argc, char **argv) -{ - - /* Set and apply the environment */ - env_setargs(argc, argv); - sef_local_startup(); - blockdriver_task(&mmc_driver); - return EXIT_SUCCESS; -} diff --git a/minix/drivers/storage/mmc/mmchost.h b/minix/drivers/storage/mmc/mmchost.h deleted file mode 100644 index 30144ff9e..000000000 --- a/minix/drivers/storage/mmc/mmchost.h +++ /dev/null @@ -1,156 +0,0 @@ - -#define SUBPARTITION_PER_PARTITION 4 /* 4 sub partitions per partition */ -#define PARTITONS_PER_DISK 4 /* 4 partitions per disk */ -#define MINOR_PER_DISK 1 /* one additional minor to point to */ - -/** - * We can have multiple MMC host controller present on the hardware. The MINIX - * approach to handle this is to run a driver for each instance. Every driver - * will therefore be stated with an "instance" id and the rest of the code here - * will assume a single host controller to be present. - * - * The SD specification allows multiple cards to be attached to a single host - * controller using the same lines. I recommend reading SD Specifications Part 1 - * Physical layer Simplified Specification chapter 3 about SD Memory Card system - * concepts if you want to get a better understanding of this. - * - * In practice an MMC host will usually have a single slot attached to it and that - * Slot may or may not contain a card. On sudden card removal we might want to - * keep track of the last inserted card and we might therefore at later stage - * add an additional "last_card" attribute to the card. - * - * The following diagram shows the structure that will be used to modulate the - * hardware written in umlwiki syntax. - * - * [/host/ - * +instance:int] 1 --- 0..4 [ /slot/ - * +card_detect:func ] 1 --- 0..1 [ /card/ ] - * ` - */ - -#define MAX_SD_SLOTS 4 - -struct mmc_host; - -//TODO Add more modes like INACTIVE STATE and such -#define SD_MODE_UNINITIALIZED 0 -#define SD_MODE_CARD_IDENTIFICATION 1 -#define SD_MODE_DATA_TRANSFER_MODE 2 - -struct sd_card_regs -{ - uint32_t cid[4]; /* Card Identification */ - uint32_t rca; /* Relative card address */ - uint32_t dsr; /* Driver stage register */ - uint32_t csd[4]; /* Card specific data */ - uint32_t scr[2]; /* SD configuration */ - uint32_t ocr; /* Operation conditions */ - uint32_t ssr[5]; /* SD Status */ - uint32_t csr; /* Card status */ -}; - -#define RESP_LEN_48_CHK_BUSY (3<<0) -#define RESP_LEN_48 (2<<0) -#define RESP_LEN_136 (1<<0) -#define RESP_NO_RESPONSE (0<<0) - -#define DATA_NONE (0) -#define DATA_READ (1) -#define DATA_WRITE (2) - -/* struct representing an mmc command */ -struct mmc_command -{ - uint32_t cmd; - uint32_t args; - uint32_t resp_type; - uint32_t data_type; - uint32_t resp[4]; - unsigned char *data; - uint32_t data_len; -}; - -/* structure representing an SD card */ -struct sd_card -{ - /* pointer back to the SD slot for convenience */ - struct sd_slot *slot; - - struct sd_card_regs regs; - - /* some helpers (data comming from the csd) */ - uint32_t blk_size; - uint32_t blk_count; - - /* drive state: deaf, initialized, dead */ - unsigned state; - - /* MINIX/block driver related things */ - int open_ct; /* in-use count */ - - /* 1 disks + 4 partitions and 16 possible sub partitions */ - struct device part[MINOR_PER_DISK + PARTITONS_PER_DISK]; - struct device subpart[PARTITONS_PER_DISK * SUBPARTITION_PER_PARTITION]; -}; - -/* structure representing an SD slot */ -struct sd_slot -{ - /* pointer back to the host for convenience */ - struct mmc_host *host; - - unsigned state; - struct sd_card card; -}; - -/* structure for the host controller */ -struct mmc_host -{ - /* MMC host configuration */ - int (*host_set_instance) (struct mmc_host * host, int instance); - /* MMC host configuration */ - int (*host_init) (struct mmc_host * host); - /* Set log level */ - void (*set_log_level) (int level); - /* Host controller reset */ - int (*host_reset) (struct mmc_host * host); - /* Card detection (binary yes/no) */ - int (*card_detect) (struct sd_slot * slot); - /* Perform card detection e.g. card type */ - struct sd_card *(*card_initialize) (struct sd_slot * slot); - /* Release the card */ - int (*card_release) (struct sd_card * card); - - /* Additional hardware interrupts */ - void (*hw_intr) (unsigned int irqs); - - /* read count blocks into existing buf */ - int (*read) (struct sd_card * card, - uint32_t blknr, uint32_t count, unsigned char *buf); - - /* write count blocks */ - int (*write) (struct sd_card * card, - uint32_t blknr, uint32_t count, unsigned char *buf); - - /* up to 4 slots with 4 SD cards */ - struct sd_slot slot[MAX_SD_SLOTS]; -}; - -#if 0 -/* Command execution */ -int (*send_cmd) (struct sd_card * card, struct mmc_command *); - -/* struct representing an mmc command */ -struct mmc_command -{ - uint32_t cmd; - uint32_t args; - uint32_t resp[4]; - unsigned char *data; - uint32_t data_len; -}; -#endif - -/* Hack done for driver registration */ -void host_initialize_host_structure_mmchs(struct mmc_host *host); -void host_initialize_host_structure_dummy(struct mmc_host *host); diff --git a/minix/drivers/storage/mmc/mmchost_dummy.c b/minix/drivers/storage/mmc/mmchost_dummy.c deleted file mode 100644 index db26a6af3..000000000 --- a/minix/drivers/storage/mmc/mmchost_dummy.c +++ /dev/null @@ -1,170 +0,0 @@ -/* kernel headers */ -#include -#include -#include - -/* usr headers */ -#include -#include -#include -#include -#include - -/* local headers */ -#include "mmchost.h" -#include "sdmmcreg.h" - -/* - * Define a structure to be used for logging - */ -static struct log log = { - .name = "mmc_host_memory", - .log_level = LEVEL_INFO, - .log_func = default_log -}; - -/* This is currently a dummy driver using an in-memory structure */ -#define DUMMY_SIZE_IN_BLOCKS 0xFFFFFu -#define DUMMY_BLOCK_SIZE 512 -static char *dummy_data = NULL; - -static struct sd_card * -init_dummy_sdcard(struct sd_slot *slot) -{ - int i; - struct sd_card *card; - - assert(slot != NULL); - - log_info(&log, "Using a dummy card \n"); - if (dummy_data == NULL) { - dummy_data = malloc(DUMMY_BLOCK_SIZE * DUMMY_SIZE_IN_BLOCKS); - if (dummy_data == NULL) { - panic - ("Failed to allocate data for dummy mmc driver\n"); - } - } - - card = &slot->card; - memset(card, 0, sizeof(struct sd_card)); - card->slot = slot; - - for (i = 0; i < MINOR_PER_DISK + PARTITONS_PER_DISK; i++) { - card->part[i].dv_base = 0; - card->part[i].dv_size = 0; - } - - for (i = 0; i < PARTITONS_PER_DISK * SUBPARTITION_PER_PARTITION; i++) { - card->subpart[i].dv_base = 0; - card->subpart[i].dv_size = 0; - } - - card->part[0].dv_base = 0; - card->part[0].dv_size = DUMMY_BLOCK_SIZE * DUMMY_SIZE_IN_BLOCKS; - return card; -} - -int -dummy_host_init(struct mmc_host *host) -{ - return 0; -} - -void -dummy_set_log_level(int level) -{ - if (level >= 0 && level <= 4) { - log.log_level = level; - } -} - -int -dummy_host_set_instance(struct mmc_host *host, int instance) -{ - log_info(&log, "Using instance number %d\n", instance); - if (instance != 0) { - return EIO; - } - return OK; -} - -int -dummy_host_reset(struct mmc_host *host) -{ - return 0; -} - -int -dummy_card_detect(struct sd_slot *slot) -{ - return 1; -} - -struct sd_card * -dummy_card_initialize(struct sd_slot *slot) -{ - slot->card.blk_size = DUMMY_BLOCK_SIZE; - slot->card.blk_count = DUMMY_SIZE_IN_BLOCKS; - slot->card.state = SD_MODE_DATA_TRANSFER_MODE; - - memset(slot->card.part, 0, sizeof(slot->card.part)); - memset(slot->card.subpart, 0, sizeof(slot->card.subpart)); - slot->card.part[0].dv_base = 0; - slot->card.part[0].dv_size = DUMMY_BLOCK_SIZE * DUMMY_SIZE_IN_BLOCKS; - return &slot->card; -} - -int -dummy_card_release(struct sd_card *card) -{ - assert(card->open_ct == 1); - card->open_ct--; - card->state = SD_MODE_UNINITIALIZED; - /* TODO:Set card state */ - return OK; -} - -/* read count blocks into existing buf */ -int -dummy_host_read(struct sd_card *card, - uint32_t blknr, uint32_t count, unsigned char *buf) -{ - memcpy(buf, &dummy_data[blknr * DUMMY_BLOCK_SIZE], - count * DUMMY_BLOCK_SIZE); - return OK; -} - -/* write count blocks */ -int -dummy_host_write(struct sd_card *card, - uint32_t blknr, uint32_t count, unsigned char *buf) -{ - memcpy(&dummy_data[blknr * DUMMY_BLOCK_SIZE], buf, - count * DUMMY_BLOCK_SIZE); - return OK; -} - -void -host_initialize_host_structure_dummy(struct mmc_host *host) -{ - /* Initialize the basic data structures host slots and cards */ - int i; - - host->host_set_instance = dummy_host_set_instance; - host->host_init = dummy_host_init; - host->set_log_level = dummy_set_log_level; - host->host_reset = dummy_host_reset; - host->card_detect = dummy_card_detect; - host->card_initialize = dummy_card_initialize; - host->card_release = dummy_card_release; - host->read = dummy_host_read; - host->write = dummy_host_write; - - /* initialize data structures */ - for (i = 0; i < sizeof(host->slot) / sizeof(host->slot[0]); i++) { - // @TODO set initial card and slot state - host->slot[i].host = host; - host->slot[i].card.slot = &host->slot[i]; - } - init_dummy_sdcard(&host->slot[0]); -} diff --git a/minix/drivers/storage/mmc/omap/Makefile b/minix/drivers/storage/mmc/omap/Makefile new file mode 100644 index 000000000..db932f41a --- /dev/null +++ b/minix/drivers/storage/mmc/omap/Makefile @@ -0,0 +1,23 @@ +.include + +PROGS= omap_mmc omap_emmc +MAN.omap_emmc= +MAN.omap_mmc= +BINDIR= /service/ + +SRCS.omap_emmc+= emmc.c mmcblk.c + +.include "../Makefile.inc" + +SRCS.omap_mmc= ${MMC_SRCS} +SRCS.omap_mmc += mmchost_mmchs.c + +DPADD+= ${LIBBLOCKDRIVER} ${LIBSYS} +LDADD+= -lblockdriver -lsys +CLEANFILES+=.depend mmcblk.d + +# +# This is a system driver. +CPPFLAGS+= -D_SYSTEM=1 + +.include diff --git a/minix/drivers/storage/mmc/emmc.c b/minix/drivers/storage/mmc/omap/emmc.c similarity index 99% rename from minix/drivers/storage/mmc/emmc.c rename to minix/drivers/storage/mmc/omap/emmc.c index f52715f55..59daa8f81 100644 --- a/minix/drivers/storage/mmc/emmc.c +++ b/minix/drivers/storage/mmc/omap/emmc.c @@ -8,8 +8,8 @@ #include #include "omap_mmc.h" -#include "mmchost.h" -#include "sdmmcreg.h" +#include "../mmchost.h" +#include "../sdmmcreg.h" /* MINIX IRQ timeout. Twice the host controller data/busy timeout @ 48MHz. */ #define IRQ_TIMEOUT 5600000 /* 5,600,000 us */ diff --git a/minix/drivers/storage/mmc/mmchost_mmchs.c b/minix/drivers/storage/mmc/omap/mmchost_mmchs.c similarity index 99% rename from minix/drivers/storage/mmc/mmchost_mmchs.c rename to minix/drivers/storage/mmc/omap/mmchost_mmchs.c index 1a098f1da..919b0745e 100644 --- a/minix/drivers/storage/mmc/mmchost_mmchs.c +++ b/minix/drivers/storage/mmc/omap/mmchost_mmchs.c @@ -21,12 +21,11 @@ #include /* local headers */ -#include "mmchost.h" +#include "../mmchost.h" /* header imported from netbsd */ -#include "sdmmcreg.h" -#include "sdmmcreg.h" -#include "sdhcreg.h" +#include "../sdmmcreg.h" +#include "../sdhcreg.h" /* omap /hardware related */ #include "omap_mmc.h" diff --git a/minix/drivers/storage/mmc/omap_mmc.h b/minix/drivers/storage/mmc/omap/omap_mmc.h similarity index 100% rename from minix/drivers/storage/mmc/omap_mmc.h rename to minix/drivers/storage/mmc/omap/omap_mmc.h diff --git a/minix/drivers/storage/mmc/rpi/Makefile b/minix/drivers/storage/mmc/rpi/Makefile new file mode 100644 index 000000000..446752adc --- /dev/null +++ b/minix/drivers/storage/mmc/rpi/Makefile @@ -0,0 +1,23 @@ +.include + +PROGS= rpi_mmc rpi_emmc +MAN.rpi_emmc= +MAN.rpi_mmc= +BINDIR= /service/ + +SRCS.rpi_emmc+= emmc.c mmcblk.c + +.include "../Makefile.inc" + +SRCS.rpi_mmc= ${MMC_SRCS} +SRCS.rpi_mmc += mmchost_mmchs.c + +DPADD+= ${LIBBLOCKDRIVER} ${LIBSYS} +LDADD+= -lblockdriver -lsys +CLEANFILES+=.depend mmcblk.d + +# +# This is a system driver. +CPPFLAGS+= -D_SYSTEM=1 + +.include diff --git a/minix/drivers/storage/mmc/rpi/emmc.c b/minix/drivers/storage/mmc/rpi/emmc.c new file mode 100644 index 000000000..7ea597ec7 --- /dev/null +++ b/minix/drivers/storage/mmc/rpi/emmc.c @@ -0,0 +1,1008 @@ +#include +#include +#include +#include +#include +#include + +#include +//#include "rpi_mmc.h" +#include "../mmchost.h" +#include "../sdmmcreg.h" +#include "rpi_mmc.h" + +/* MINIX IRQ timeout. Twice the host controller data/busy timeout @ 48MHz. */ +#define IRQ_TIMEOUT 5600000 /* 5,600,000 us */ + +#define MMCHS_TIMEOUT 500000 /* 500,000 us */ + +/* Reference clock frequency divisors: */ +#define MMCHS_SD_SYSCTL_CLKD_400KHZ 240 /* 96MHz/400kHz */ +#define MMCHS_SD_SYSCTL_CLKD_26MHZ 4 /* ceiling 96MHz/26MHz */ +#define MMCHS_SD_SYSCTL_CLKD_52MHZ 2 /* ceiling 96MHz/52MHz */ + +/* The host SD_DATA register is 128 words (512B). */ +#define SD_DATA_WLEN 128 + +/* + * Card initialization timeout, twice the standard: + * "The device must complete its initialization within 1 second of the first + * CMD1 issued with a valid OCR range." (MMCA, 4.41) + */ +#define CARD_INI_TIMEOUT 2000000 /* 2,000,000 us */ + +/* Card EXT_CSD register fields. */ +#define MMC_EXT_CSD_SEC_COUNT (*(uint32_t *)&card_ext_csd[212]) +#define MMC_EXT_CSD_CARD_TYPE (card_ext_csd[196]) +#define MMC_EXT_CSD_CARD_TYPE_HS_MMC_52MHZ (0x1 << 1) + +/* Card intended operating voltage range: 2.7V to 3.6V */ +#define MMC_OCR_VDD_RANGE 0x00FF8000 + +/* Error bits in the card status (R1) response. */ +#define R1_ERROR_MASK 0xFDFFA080 + +/* Relative Card Address. Must be greater than 1. */ +#define RCA 0x2 + +/* The card sector size is 512B. */ +#define SEC_SIZE 512 + +/* + * AM335x Control Module registers CONF_GPMC_ADn. + * Configuration do multiplex CONF_GPMC_ADn to signals MMC1_DATn (Mode 1). + */ +#define CONF_GPMC_AD(N) (0x800 + 4*(N)) +#define CONF_GPMC_AD_MASK 0x7F +#define CONF_GPMC_AD_VAL 0x31 + +/* AM335x MMC1 memory map (physical start address and size). */ +#define BCM2835_MMC0_BASE_ADDR 0x3F300000 +#define BCM2835_MMC0_SIZE (4 << 6) +/* AM335x MMC1 interrupt number. */ +#define BCM2835_MMCSD1INT 28 + +static uint32_t bus_width; + +/* AM335x MMCHS registers virtual addresses: virtual base + offset. */ +static rpi_mmchs_registers *reg; + +/* Card registers. */ +static uint32_t card_csd[4]; +static uint8_t card_ext_csd[512]; + +static uint32_t card_write_protect; +static uint64_t card_size; + +/* IRQ_HOOK_ID for SYS_IRQCTL kernel call. */ +static int hook_id = 1; + +/* Initialize the log system. */ +static struct log log = { + .name = "emmc", + .log_level = LEVEL_INFO, + .log_func = default_log, +}; + + +/* + * Spin until a register flag is set, or the time runs out. + * Return the flag value. + */ +static uint32_t +spin_until_set(uint32_t address, uint32_t flag) +{ + spin_t s; + int spin; + uint32_t v; + + spin_init(&s, MMCHS_TIMEOUT); + do { + spin = spin_check(&s); + v = (read32(address) & flag); + } while ((v == 0) && (spin == TRUE)); + + return v; +} + +/* + * Spin until the time runs out. + */ +static void +spin_time() +{ + spin_t s; + int spin; + + spin_init(&s, MMCHS_TIMEOUT); + do { + spin = spin_check(&s); + } while (spin == TRUE); +} +/* + * Spin until a register flag is clear, or the time runs out. + * Return the flag value. + */ +static uint32_t +spin_until_clear(uint32_t address, uint32_t flag) +{ + spin_t s; + int spin; + uint32_t v; + + spin_init(&s, MMCHS_TIMEOUT); + do { + spin = spin_check(&s); + v = (read32(address) & flag); + } while ((v != 0) && (spin == TRUE)); + + return v; +} + +/* + * Change the bus clock frequency (divisor). + * Return 0 on success, a negative integer on error. + */ +static int +set_bus_clkd(uint32_t clkd) +{ + uint32_t control1; + /* + * Disable the bus clock, set the clock divider, wait until the + * internal clock is stable, enable the bus clock. + */ + set32(reg->control1, MMCHS_SD_SYSCTL_CEN, MMCHS_SD_SYSCTL_CEN_DIS); + set32(reg->control1, MMCHS_SD_SYSCTL_CLKD, clkd << 6); + if (spin_until_set(reg->control1, MMCHS_SD_SYSCTL_ICS) + == MMCHS_SD_SYSCTL_ICS_UNSTABLE) + return -1; + set32(reg->control1, MMCHS_SD_SYSCTL_CEN, MMCHS_SD_SYSCTL_CEN_EN); + + return 0; +} + +/* + * Receive an interrupt request. + * Return 0 on success, a negative integer on error. + */ +static int +irq_receive(void) +{ + message m; + int ipc_status; + + while (1) { + if (driver_receive(ANY, &m, &ipc_status) != OK) + return -1; + if (is_ipc_notify(ipc_status) + && (_ENDPOINT_P(m.m_source) == CLOCK)) + return -1; + if (is_ipc_notify(ipc_status) + && (_ENDPOINT_P(m.m_source) == HARDWARE)) + return 0; + /* + * m will be discarded if the driver is out of memory. + */ + blockdriver_mq_queue(&m, ipc_status); + } +} + +/* + * Wait for an interrupt request. + * Return 0 on interrupt, a negative integer on error. + */ +static int +irq_wait(void) +{ + int r; + + if (sys_irqenable(&hook_id) != OK) + return -1; + sys_setalarm(micros_to_ticks(IRQ_TIMEOUT), 0); + r = irq_receive(); + sys_setalarm(0, 0); + if (r < 0) + sys_irqdisable(&hook_id); + + return r; +} + +/* + * Software reset for mmc_cmd or mmc_dat line. + */ +static void +reset_mmchs_fsm(uint32_t line) +{ + /* + * "The proper procedure is: (a) Set to 1 to start reset, + * (b) Poll for 1 to identify start of reset, and + * (c) Poll for 0 to identify reset is complete." (AM335x TRM) + */ + set32(reg->control1, line, line); + spin_until_set(reg->control1, line); + spin_until_clear(reg->control1, line); +} + +/* + * Send a command to the card. + * Return 0 on success, a negative integer on error. + */ +static int +send_cmd(uint32_t arg, uint32_t cmd) +{ + uint32_t stat; + + if (read32(reg->status) + & (MMCHS_SD_PSTATE_DATI | MMCHS_SD_PSTATE_CMDI)) + return -1; /* Issuing of commands is not allowed. */ + + write32(reg->arg1, arg); + write32(reg->cmdtm, cmd); + /* Wait for the command completion. */ + if (irq_wait() < 0) + return -1; + stat = read32(reg->irpt_mask); + /* + * Clear only the command status/error bits. The transfer status/error + * bits (including ERRI) must be preserved. + */ + write32(reg->irpt_mask, MMCHS_SD_STAT_CIE + | MMCHS_SD_STAT_CEB + | MMCHS_SD_STAT_CCRC + | MMCHS_SD_STAT_CTO + | MMCHS_SD_STAT_CC); + if (stat & MMCHS_SD_STAT_CTO) { + reset_mmchs_fsm(MMCHS_SD_SYSCTL_SRC); + return -1; + } + return 0; +} + +/* + * Send a command to the card, and check for errors in the response (R1). + * Return 0 on success, a negative integer on error. + */ +static int +send_cmd_check_r1(uint32_t arg, uint32_t cmd) +{ + if (send_cmd(arg, cmd) < 0) + return -1; + /* Check for card errors in the card response (R1). */ + if (read32(reg->resp0) & R1_ERROR_MASK) + return -1; + return 0; +} + +/* Send CMD0 (GO_IDLE_STATE) command to the card. */ +static int +go_idle_state(void) +{ + return send_cmd(0, MMCHS_SD_CMD_INDX_CMD(GO_IDLE_STATE)); +} + +/* Send CMD1 (SEND_OP_COND) command to the card. */ +static int +send_op_cond(void) +{ + uint32_t cmd; + + /* The driver is capable of handling sector type of addressing. */ + cmd = MMCHS_SD_CMD_INDX_CMD(SD_SEND_OP_COND) + | MMCHS_SD_CMD_RSP_TYPE_48B; + return send_cmd((MMC_OCR_HCS | MMC_OCR_VDD_RANGE), cmd); +} + +/* Send CMD2 (ALL_SEND_CID) command to the card. */ +static int +all_send_cid(void) +{ + uint32_t cmd; + + cmd = MMCHS_SD_CMD_INDX_CMD(ALL_SEND_CID) + | MMCHS_SD_CMD_CCCE_ENABLE + | MMCHS_SD_CMD_RSP_TYPE_136B; + return send_cmd(0, cmd); +} + +/* Send CMD3 (SET_RELATIVE_ADDR) command to the card. */ +static int +set_relative_addr(void) +{ + uint32_t cmd; + + cmd = MMCHS_SD_CMD_INDX_CMD(SEND_RELATIVE_ADDR) + | MMCHS_SD_CMD_CICE_ENABLE + | MMCHS_SD_CMD_CCCE_ENABLE + | MMCHS_SD_CMD_RSP_TYPE_48B; + return send_cmd_check_r1(MMC_ARG_RCA(RCA), cmd); +} + +/* Send CMD6 (SWITCH) command to the card. */ +static int +mmc_switch(uint32_t access, uint32_t index, uint32_t value) +{ + uint32_t arg, cmd; + + /* SWITCH argument: [25:24] Access, [23:16] Index, [15:8] Value. */ + arg = (access << 24) | (index << 16) | (value << 8); + cmd = MMCHS_SD_CMD_INDX_CMD(SWITCH_FUNC) + | MMCHS_SD_CMD_CICE_ENABLE + | MMCHS_SD_CMD_CCCE_ENABLE + | MMCHS_SD_CMD_RSP_TYPE_48B_BUSY; + return send_cmd_check_r1(arg, cmd); +} + +/* Send CMD7 (SELECT_CARD) command to the card. */ +static int +select_card(void) +{ + uint32_t cmd; + + cmd = MMCHS_SD_CMD_INDX_CMD(SELECT_CARD) + | MMCHS_SD_CMD_CICE_ENABLE + | MMCHS_SD_CMD_CCCE_ENABLE + | MMCHS_SD_CMD_RSP_TYPE_48B; + return send_cmd_check_r1(MMC_ARG_RCA(RCA), cmd); +} + +/* Send CMD9 (SEND_CSD) command to the card. */ +static int +send_csd(void) +{ + uint32_t cmd; + + cmd = MMCHS_SD_CMD_INDX_CMD(SEND_CSD) + | MMCHS_SD_CMD_CCCE_ENABLE + | MMCHS_SD_CMD_RSP_TYPE_136B; + return send_cmd(MMC_ARG_RCA(RCA), cmd); +} + +/* Send CMD13 (SEND_STATUS) command to the card. */ +static int +send_status(void) +{ + uint32_t cmd; + + cmd = MMCHS_SD_CMD_INDX_CMD(SEND_STATUS) + | MMCHS_SD_CMD_CICE_ENABLE + | MMCHS_SD_CMD_CCCE_ENABLE + | MMCHS_SD_CMD_RSP_TYPE_48B; + return send_cmd_check_r1(MMC_ARG_RCA(RCA), cmd); +} + +/* Send CMD16 (SET_BLOCKLEN) command to the card. */ +static int +set_blocklen(void) +{ + uint32_t cmd; + + /* Set block length to sector size (512B). */ + cmd = MMCHS_SD_CMD_INDX_CMD(SET_BLOCKLEN) + | MMCHS_SD_CMD_CICE_ENABLE + | MMCHS_SD_CMD_CCCE_ENABLE + | MMCHS_SD_CMD_RSP_TYPE_48B; + return send_cmd_check_r1(SEC_SIZE, cmd); +} + +/* Send CMD17 (READ_SINGLE_BLOCK) to the card. */ +static int +read_single_block(uint32_t addr) +{ + uint32_t cmd; + + cmd = MMCHS_SD_CMD_INDX_CMD(READ_SINGLE_BLOCK) + | MMCHS_SD_CMD_DP_DATA + | MMCHS_SD_CMD_CICE_ENABLE + | MMCHS_SD_CMD_CCCE_ENABLE + | MMCHS_SD_CMD_RSP_TYPE_48B + | MMCHS_SD_CMD_DDIR_READ; + return send_cmd_check_r1(addr, cmd); +} + +/* Send CMD24 (WRITE_BLOCK) to the card. */ +static int +write_block(uint32_t addr) +{ + uint32_t cmd; + + cmd = MMCHS_SD_CMD_INDX_CMD(WRITE_SINGLE_BLOCK) + | MMCHS_SD_CMD_DP_DATA + | MMCHS_SD_CMD_CICE_ENABLE + | MMCHS_SD_CMD_CCCE_ENABLE + | MMCHS_SD_CMD_RSP_TYPE_48B + | MMCHS_SD_CMD_DDIR_WRITE; + return send_cmd_check_r1(addr, cmd); +} + +/* + * Repeat CMD1 until the card is ready, or the time runs out. + * Return 0 on ready, a negative integer on error. + */ +static int +repeat_send_op_cond(void) +{ + spin_t s; + int spin; + uint32_t card_ocr; + + spin_init(&s, CARD_INI_TIMEOUT); + do { + spin = spin_check(&s); + if (send_op_cond() < 0) + return -1; + card_ocr = read32(reg->resp0); + } while (((card_ocr & MMC_OCR_MEM_READY) == 0) && (spin == TRUE)); + + if ((card_ocr & MMC_OCR_MEM_READY) == 0) + return -1; /* Card is still busy. */ + + return 0; +} + +/* + * Read (receive) the busy signal from the card. + * Return 0 on success, a negative integer on error. + */ +static int +read_busy(void) +{ + uint32_t stat; + /* + * The busy signal is optional, but the host controller will assert + * SD_STAT[1] TC even if the card does not send it. + */ + if (irq_wait() < 0) + return -1; + stat = read32(reg->irpt_mask); + write32(reg->irpt_mask, MMCHS_SD_STAT_DCRC + | MMCHS_SD_STAT_DTO + | MMCHS_SD_STAT_TC); + if (stat & MMCHS_SD_STAT_ERRI) { + reset_mmchs_fsm(MMCHS_SD_SYSCTL_SRD); + return -1; + } + + return 0; +} + +/* + * Read (receive) data from the card. + * Return 0 on success, a negative integer on error. + */ +static int +read_data(uint32_t *data) +{ + uint32_t stat, i; + + /* Wait for BRR interrupt. */ + if (irq_wait() < 0) + return -1; + if (read32(reg->irpt_mask) & MMCHS_SD_STAT_BRR) { + write32(reg->irpt_mask, MMCHS_SD_STAT_BRR); + for (i=SD_DATA_WLEN; i>0; i--) + *data++ = read32(reg->data); + } + + /* Wait for TC or ERRI interrupt. */ + if (irq_wait() < 0) + return -1; + stat = read32(reg->irpt_mask); + write32(reg->irpt_mask, MMCHS_SD_STAT_DEB + | MMCHS_SD_STAT_DCRC + | MMCHS_SD_STAT_DTO + | MMCHS_SD_STAT_TC); + if (stat & MMCHS_SD_STAT_ERRI) { + reset_mmchs_fsm(MMCHS_SD_SYSCTL_SRD); + return -1; + } + + return 0; +} + +/* + * Write (send) data to the card. + * Return 0 on success, a negative integer on error. + */ +static int +write_data(uint32_t *data) +{ + uint32_t stat, i; + + /* Wait for BWR interrupt. */ + if (irq_wait() < 0) + return -1; + if (read32(reg->status) & MMCHS_SD_STAT_BWR) { + write32(reg->irpt_mask, MMCHS_SD_STAT_BWR); + for (i = SD_DATA_WLEN; i > 0; i--) + write32(reg->data, *data++); + } + + /* Wait for TC or ERRI interrupt. */ + if (irq_wait() < 0) + return -1; + stat = read32(reg->irpt_mask); + write32(reg->irpt_mask, MMCHS_SD_STAT_DEB + | MMCHS_SD_STAT_DCRC + | MMCHS_SD_STAT_DTO + | MMCHS_SD_STAT_TC); + if (stat & MMCHS_SD_STAT_ERRI) { + reset_mmchs_fsm(MMCHS_SD_SYSCTL_SRD); + return -1; + } + return 0; +} + +/* + * Read a block from the card. + * Return 0 on success, a negative integer on error. + */ +static int +cim_read_block(uint32_t addr, uint32_t *data) +{ + /* Send CMD17. */ + if (read_single_block(addr) < 0) + return -1; + /* Read from the host buffer. */ + return read_data(data); +} + +/* + * Write a block to the card. + * Return 0 on success, a negative integer on error. + */ +static int +cim_write_block(uint32_t addr, uint32_t *data) +{ + /* Send CMD24. */ + if (write_block(addr) < 0) + return -1; + /* Write into the host buffer. */ + if (write_data(data) < 0) + return -1; + /* CMD13. Check the result of the write operation. */ + return send_status(); +} + + +/* + * Interface to the MINIX block device driver. + */ +static int +emmc_host_set_instance(struct mmc_host *host, int instance) +{ + if (instance != 0) + return EIO; + return 0; +} + +/* + * Initialize the driver and kernel structures. + * Return 0 on success, a negative integer on error. + */ +static int +minix_init(void) +{ + struct minix_mem_range mr; + uint32_t v_base; + + /* + * On the BeagleBone Black, the eMMC device is connected to MMC1. + * Add the MMC1 memory address range to the process' resources. + */ + mr.mr_base = BCM2835_MMC0_BASE_ADDR; + mr.mr_limit = BCM2835_MMC0_BASE_ADDR + BCM2835_MMC0_SIZE - 1; + if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != OK) + return -1; + + /* Map the MMC1 physical base address to a virtual address. */ + v_base = (uint32_t)vm_map_phys(SELF, (void *)mr.mr_base, + BCM2835_MMC0_SIZE); + if (v_base == (uint32_t)MAP_FAILED) + return -1; + + /* Set the registers virtual addresses. */ + reg = ®s_v0; + reg->blkscnt += v_base; + reg->arg1 += v_base; + reg->cmdtm += v_base; + reg->resp0 += v_base; + reg->resp1 += v_base; + reg->resp2 += v_base; + reg->resp3 += v_base; + reg->data += v_base; + reg->status += v_base; + reg->control0 += v_base; + reg->control1 += v_base; + reg->irpt += v_base; + reg->irpt_mask += v_base; + reg->irpt_en += v_base; + reg->control2 += v_base; + reg->slotisr_var += v_base; + + /* Register the MMC1 interrupt number. */ + if (sys_irqsetpolicy(BCM2835_MMCSD1INT, 0, &hook_id) != OK) + return -1; + return 0; +} + +/* + * Configure the Control Module registers CONF_GPMC_AD4-7. + * Multiplex pins GPMC_AD4-7 to signals MMC1_DAT4-7 (Mode 1). + * Return 0 on success, a negative integer on error. + */ +static int +conf_gpmc_ad(void) +{ + uint32_t i; + + for (i=4; i<8; i++) { + if (sys_padconf(CONF_GPMC_AD(i), CONF_GPMC_AD_MASK, + CONF_GPMC_AD_VAL) != OK) + return -1; + } + return 0; +} + +/* + * Interface to the MINIX block device driver. + * Host controller initialization. + * Return 0 on success, a negative integer on error. + */ +static int +emmc_host_init(struct mmc_host *host) +{ + /* Initialize the driver and kernel structures. */ + if (minix_init() < 0) + return -1; +#if 0 + /* + * Multiplex pins GPMC_AD4-7 to signals MMC1_DAT4-7 (Mode 1), in order + * to allow the use of 8-bit mode. + * U-Boot multiplexes only pins GPMC_AD0-3 to signals MMC1_DAT0-3. + */ + if (conf_gpmc_ad() < 0) + bus_width = EXT_CSD_BUS_WIDTH_4; + else + bus_width = EXT_CSD_BUS_WIDTH_8; +#endif + /* Reset the host controller. */ +/* set32(reg->SYSCONFIG, MMCHS_SD_SYSCONFIG_SOFTRESET, + MMCHS_SD_SYSCONFIG_SOFTRESET); + if (spin_until_set(reg->SYSSTATUS, MMCHS_SD_SYSSTATUS_RESETDONE) + != MMCHS_SD_SYSSTATUS_RESETDONE) + return -1; +*/ + /* + * SD_CAPA: "The host driver shall not modify this register after the + * initialization." (AM335x TRM) + */ + + /* + * Set the bus voltage to 3V, and turn the bus power on. + * On the BeagleBone Black, the bus voltage is pulled up to 3.3V, but + * the MMCHS supports only 1.8V or 3V. + */ +/* set32(reg->HCTL, MMCHS_SD_HCTL_SDVS, MMCHS_SD_HCTL_SDVS_VS30); + set32(reg->HCTL, MMCHS_SD_HCTL_SDBP, MMCHS_SD_HCTL_SDBP_ON); + if (spin_until_set(reg->HCTL, MMCHS_SD_HCTL_SDBP) + == MMCHS_SD_HCTL_SDBP_OFF) + return -1; +*/ + /* Set the bus clock frequency to FOD (400kHz). */ + set32(reg->control1, MMCHS_SD_SYSCTL_CLKD, + MMCHS_SD_SYSCTL_CLKD_400KHZ << 6); + + /* Set data and busy time-out: ~2,6s @ 400kHz.*/ + set32(reg->control1, MMCHS_SD_SYSCTL_DTO, MMCHS_SD_SYSCTL_DTO_2POW20); + + /* Enable the internal clock. */ + set32(reg->control1, MMCHS_SD_SYSCTL_ICE, MMCHS_SD_SYSCTL_ICE_EN); + if (spin_until_set(reg->control1, MMCHS_SD_SYSCTL_ICS) + == MMCHS_SD_SYSCTL_ICS_UNSTABLE) + return -1; + + /* Enable the bus clock. */ + set32(reg->control1, MMCHS_SD_SYSCTL_CEN, MMCHS_SD_SYSCTL_CEN_EN); + + /* + * Set the internal clock gating strategy to automatic, and enable + * Smart Idle mode. The host controller does not implement wake-up + * request (SWAKEUP pin is not connected). + */ + /*set32(reg->SYSCONFIG, MMCHS_SD_SYSCONFIG_AUTOIDLE, + MMCHS_SD_SYSCONFIG_AUTOIDLE_EN); + set32(reg->SYSCONFIG, MMCHS_SD_SYSCONFIG_SIDLEMODE, + MMCHS_SD_SYSCONFIG_SIDLEMODE_IDLE);*/ + + /* The driver reads and writes single 512B blocks. */ + set32(reg->blkscnt, MMCHS_SD_BLK_BLEN, SEC_SIZE); + + /* Enable interrupt status and requests. */ + write32(reg->irpt, MMCHS_SD_IE_ERROR_MASK + | MMCHS_SD_IE_BRR_ENABLE_ENABLE + | MMCHS_SD_IE_BWR_ENABLE_ENABLE + | MMCHS_SD_IE_TC_ENABLE_ENABLE + | MMCHS_SD_IE_CC_ENABLE_ENABLE); + write32(reg->irpt_en, MMCHS_SD_IE_ERROR_MASK + | MMCHS_SD_IE_BRR_ENABLE_ENABLE + | MMCHS_SD_IE_BWR_ENABLE_ENABLE + | MMCHS_SD_IE_TC_ENABLE_ENABLE + | MMCHS_SD_IE_CC_ENABLE_ENABLE); + return 0; +} + +/* + * Interface to the MINIX block device driver. + * Set the log level. + */ +static void +emmc_set_log_level(int level) +{ + log.log_level = level; +} + + +/* + * Interface to the MINIX block device driver. + * Unused, but declared in mmchost.h. + */ +static int +emmc_host_reset(struct mmc_host *host) +{ + return 0; +} + +/* + * Interface to the MINIX block device driver. + * Card detection. + */ +static int +emmc_card_detect(struct sd_slot *slot) +{ + /* The card is detected during card initialization. */ + return 1; +} + +/* + * Interface to the MINIX block device driver. + * Card initialization. Also, finish the MMCHS initialization. + * Return NULL on error. + */ +static struct sd_card * +emmc_card_initialize(struct sd_slot *slot) +{ + uint32_t clkd; + + /* CMD0 */ + if (go_idle_state() < 0) + return NULL; + + /* + * Set the MMC_CMD line to open drain. + * "The host starts the card identification process in open-drain mode + * with the identification clock rate FOD." (MMCA, 4.41) + */ + //set32(reg->CON, MMCHS_SD_CON_OD, MMCHS_SD_CON_OD_OD); + + /* CMD1 */ + /*if (repeat_send_op_cond() < 0) + return NULL; +*/ + /* CMD2. The driver has no use for the CID. */ + if (all_send_cid() < 0) + return NULL; + + /* CMD3 */ + if (set_relative_addr() < 0) + return NULL; + + /* + * Set the MMC_CMD line to push-pull. + * "When the card is in Stand-by State, communication over the CMD and + * DAT lines will be performed in push-pull mode." (MMCA, 4.41) + */ + //set32(reg->CON, MMCHS_SD_CON_OD, MMCHS_SD_CON_OD_PP); + + /* CMD9 */ + if (send_csd() < 0) + return NULL; + card_csd[0] = read32(reg->resp0); + card_csd[1] = read32(reg->resp1); + card_csd[2] = read32(reg->resp2); + card_csd[3] = read32(reg->resp3); + + /* Card capacity for cards up to 2GB of density. */ + card_size = (uint64_t)MMC_CSD_CAPACITY(card_csd) + << MMC_CSD_READ_BL_LEN(card_csd); + + card_write_protect = (SD_CSD_PERM_WRITE_PROTECT(card_csd) + | SD_CSD_TMP_WRITE_PROTECT(card_csd)); + if (card_write_protect) + log_info(&log, "the eMMC is write protected\n"); + + /* CMD7 */ + if (select_card() < 0) + return NULL; + + /* Receive the Extended CSD register. */ +/* if (read_data((uint32_t *)card_ext_csd) < 0) + return NULL; +*/ + /* Card capacity for densities greater than 2GB. */ + if (MMC_EXT_CSD_SEC_COUNT > 0) + card_size = (uint64_t)MMC_EXT_CSD_SEC_COUNT * SEC_SIZE; + + /* CMD6. Switch to high-speed mode: EXT_CSD[185] HS_TIMING = 1. */ + if (mmc_switch(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, 1) < 0) + return NULL; + /* Wait for the (optional) busy signal. */ + if (read_busy() < 0) + return NULL; + /* CMD13. Check the result of the SWITCH operation. */ + if (send_status() < 0) + return NULL; + + /* Change the bus clock frequency. */ + if (MMC_EXT_CSD_CARD_TYPE & MMC_EXT_CSD_CARD_TYPE_HS_MMC_52MHZ) + clkd = MMCHS_SD_SYSCTL_CLKD_52MHZ; /* 48 MHz */ + else + clkd = MMCHS_SD_SYSCTL_CLKD_26MHZ; /* 24 MHz */ + if (set_bus_clkd(clkd) < 0) + return NULL; + + /* Set data and busy time-out: ~ 2,8s @ 48MHz.*/ + set32(reg->control1, MMCHS_SD_SYSCTL_DTO, MMCHS_SD_SYSCTL_DTO_2POW27); + + /* CMD6. Set data bus width. */ + if (mmc_switch(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_BUS_WIDTH, + bus_width) < 0) + return NULL; + /* Wait for the (optional) busy signal. */ + if (read_busy() < 0) + return NULL; + /* CMD13. Check the result of the SWITCH operation. */ + if (send_status() < 0) + return NULL; +#if 0 + /* Host controller: set data bus width. */ + if (bus_width == EXT_CSD_BUS_WIDTH_4) + set32(reg->HCTL, MMCHS_SD_HCTL_DTW, MMCHS_SD_HCTL_DTW_4BIT); + else + set32(reg->CON, MMCHS_SD_CON_DW8, MMCHS_SD_CON_DW8_8BITS); +#endif + /* CMD16. Set block length to sector size (512B). */ + if (set_blocklen() < 0) + return NULL; + + /* Initialize the block device driver structures. */ + slot->card.blk_size = SEC_SIZE; + slot->card.blk_count = card_size / SEC_SIZE; + slot->card.state = SD_MODE_DATA_TRANSFER_MODE; + slot->card.open_ct = 0; + memset(slot->card.part, 0, sizeof(slot->card.part)); + memset(slot->card.subpart, 0, sizeof(slot->card.subpart)); + slot->card.part[0].dv_size = card_size; + + return &(slot->card); +} + +/* + * Interface to the MINIX block device driver. + * Card release. + */ +static int +emmc_card_release(struct sd_card *card) +{ + /* Decrements the "in-use count." */ + card->open_ct--; + + /* + * The block special file is closed, but the driver does not need to + * "release" the eMMC, even if the driver is unloaded. + */ + return 0; +} + +/* + * Interface to the MINIX block device driver. + * Handle unexpected interrupts. + */ +static void +emmc_hw_intr(unsigned int irqs) +{ + log_warn(&log, "register SD_STAT == 0x%08x\n", reg->irpt_mask); +} + +/* + * Interface to the MINIX block device driver. + * Read/write blocks. + * Return the number of blocks read/written, or a negative integer on error. + */ +static int +emmc_read_write(int (*cim_read_write)(uint32_t, uint32_t *), + uint32_t blknr, uint32_t count, unsigned char *buf) +{ + int blocks, r; + uint32_t addr; + + blocks = 0; /* count of blocks read/written. */ + r = 0; + while ((count > 0) && (r == 0)) { + /* + * Data address for media =< 2GB is byte address, and data + * address for media > 2GB is sector address. + */ + if (card_size <= (2U << 30)) + addr = blknr * SEC_SIZE; + else + addr = blknr; + + r = (*cim_read_write)(addr, (uint32_t *)buf); + if (r == 0) { + blknr++; + count--; + buf += SEC_SIZE; + blocks++; + } + else if (blocks == 0) + blocks = r; + } + + return blocks; +} + +/* + * Interface to the MINIX block device driver. + * Read blocks. + */ +static int +emmc_read(struct sd_card *card, + uint32_t blknr, uint32_t count, unsigned char *buf) +{ + return emmc_read_write(&cim_read_block, blknr, count, buf); +} + +/* + * Interface to the MINIX block device driver. + * Write blocks. + */ +static int +emmc_write(struct sd_card *card, + uint32_t blknr, uint32_t count, unsigned char *buf) +{ + if (card_write_protect) + return -1; /* The card is write protected. */ + return emmc_read_write(&cim_write_block, blknr, count, buf); +} + +void +host_initialize_host_structure_mmchs(struct mmc_host *host) +{ + uint32_t i; + + /* Register the driver interface at the block device driver. */ + host->host_set_instance = &emmc_host_set_instance; + host->host_init = &emmc_host_init; + host->set_log_level = &emmc_set_log_level; + host->host_reset = NULL; + host->card_detect = &emmc_card_detect; + host->card_initialize = &emmc_card_initialize; + host->card_release = &emmc_card_release; + host->hw_intr = &emmc_hw_intr; + host->read = &emmc_read; + host->write = &emmc_write; + for (i=0; islot[i].host = host; + host->slot[i].card.state = SD_MODE_UNINITIALIZED; + host->slot[i].card.slot = &host->slot[i]; + } +} + +/* + * Interface to the MINIX block device driver. + * Unused, but declared in mmchost.h. + */ +void +host_initialize_host_structure_dummy(struct mmc_host *host) +{ +} \ No newline at end of file diff --git a/minix/drivers/storage/mmc/rpi/mmchost_mmchs.c b/minix/drivers/storage/mmc/rpi/mmchost_mmchs.c new file mode 100644 index 000000000..34fe46a86 --- /dev/null +++ b/minix/drivers/storage/mmc/rpi/mmchost_mmchs.c @@ -0,0 +1,1207 @@ +/* kernel headers */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* usr headers */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* local headers */ +#include "../mmchost.h" + +/* header imported from netbsd */ +#include "../sdmmcreg.h" +#include "../sdhcreg.h" + +/* rpi hardware related */ +#include "rpi_mmc.h" + +#define USE_INTR + +#ifdef USE_INTR +static int hook_id = 1; +#endif + +#define USE_DMA + +#define SANE_TIMEOUT 500000 /* 500 ms */ + +struct rpi_mmchs *mmchs; /* pointer to the current mmchs */ + +struct rpi_mmchs rpi_sdcard = { + .io_base = 0, + .io_size = 0x100, + .hw_base = 0x3f300000, + .irq_nr = 24, + .regs = ®s_v0 +}; + +/* Integer divide x by y and ensure that the result z is + * such that x / z is smaller or equal y + */ +#define div_roundup(x, y) (((x)+((y)-1))/(y)) + +/* + * Define a structure to be used for logging + */ +static struct log log = { + .name = "mmc_host_mmchs", + .log_level = LEVEL_INFO, + .log_func = default_log +}; + +#define HSMMCSD_0_IN_FREQ 96000000 /* 96MHz */ +#define HSMMCSD_0_INIT_FREQ 400000 /* 400kHz */ +#define HSMMCSD_0_FREQ_25MHZ 25000000 /* 25MHz */ +#define HSMMCSD_0_FREQ_50MHZ 50000000 /* 50MHz */ + +void +mmc_set32(vir_bytes reg, u32_t mask, u32_t value) +{ + assert(reg >= 0 && reg <= mmchs->io_size); + set32(mmchs->io_base + reg, mask, value); +} + +u32_t +mmc_read32(vir_bytes reg) +{ + assert(reg >= 0 && reg <= mmchs->io_size); + return read32(mmchs->io_base + reg); +} + +void +mmc_write32(vir_bytes reg, u32_t value) +{ + assert(reg >= 0 && reg <= mmchs->io_size); + write32(mmchs->io_base + reg, value); +} + +void +mmchs_set_bus_freq(u32_t freq) +{ + u32_t freq_in = HSMMCSD_0_IN_FREQ; + u32_t freq_out = freq; + + /* Calculate and program the divisor */ + u32_t clkd = div_roundup(freq_in, freq_out); + clkd = (clkd < 2) ? 2 : clkd; + clkd = (clkd > 1023) ? 1023 : clkd; + + log_debug(&log, "Setting divider to %d\n", clkd); + mmc_set32(mmchs->regs->control1, MMCHS_SD_SYSCTL_CLKD, (clkd << 6)); +} + +/* + * Initialize the MMC controller given a certain + * instance. this driver only handles a single + * mmchs controller at a given time. + */ +int +mmchs_init(uint32_t instance) +{ + + uint32_t value; + value = 0; + struct minix_mem_range mr; + spin_t spin; + assert(mmchs); + + mr.mr_base = mmchs->hw_base; + mr.mr_limit = mmchs->hw_base + mmchs->io_size; + + /* grant ourself rights to map the register memory */ + if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) { + panic("Unable to request permission to map memory"); + } + + /* Set the base address to use */ + mmchs->io_base = + (uint32_t) vm_map_phys(SELF, (void *) mmchs->hw_base, + mmchs->io_size); + + if (mmchs->io_base == (uint32_t) MAP_FAILED) + panic("Unable to map MMC memory"); + + /* Soft reset of the controller. This section is documented in the TRM + */ + + /* Write 1 to sysconfig[0] to trigger a reset */ + mmc_set32(mmchs->regs->control1, MMCHS_SD_SYSCTL_SRA, + MMCHS_SD_SYSCTL_SRA); + + /* Read sysstatus to know when it's done */ + + spin_init(&spin, SANE_TIMEOUT); + while (mmc_read32(mmchs->regs->control1) + & MMCHS_SD_SYSCTL_SRA) { + if (spin_check(&spin) == FALSE) { + log_warn(&log, "mmc init timeout\n"); + return 1; + } + } + + /* Set SD default capabilities */ + mmc_set32(mmchs->regs->slotisr_var, MMCHS_SD_CAPA_VS_MASK, + MMCHS_SD_CAPA_VS18 | MMCHS_SD_CAPA_VS30); + + /* + * MMC host and bus configuration + */ + + mmc_set32(mmchs->regs->control0, MMCHS_SD_HCTL_DTW, + MMCHS_SD_HCTL_DTW_1BIT); + + /* Enable internal clock and clock to the card */ + mmc_set32(mmchs->regs->control1, MMCHS_SD_SYSCTL_ICE, + MMCHS_SD_SYSCTL_ICE_EN); + + mmchs_set_bus_freq(HSMMCSD_0_INIT_FREQ); + + mmc_set32(mmchs->regs->control1, MMCHS_SD_SYSCTL_CEN, + MMCHS_SD_SYSCTL_CEN_EN); + + spin_init(&spin, SANE_TIMEOUT); + while ((mmc_read32(mmchs->regs->control1) & MMCHS_SD_SYSCTL_ICS) + != MMCHS_SD_SYSCTL_ICS_STABLE) { + if (spin_check(&spin) == FALSE) { + log_warn(&log, "clock not stable\n"); + return 1; + } + } + + /* + * See spruh73e page 3576 Card Detection, Identification, and Selection + */ + + /* Enable command interrupt */ + mmc_write32(mmchs->regs->irpt_en, 0); + mmc_set32(mmchs->regs->irpt_mask, MMCHS_SD_IE_CC_ENABLE, + MMCHS_SD_IE_CC_ENABLE_ENABLE); + /* Enable transfer complete interrupt */ + mmc_set32(mmchs->regs->irpt_mask, MMCHS_SD_IE_TC_ENABLE, + MMCHS_SD_IE_TC_ENABLE_ENABLE); + + /* enable error interrupts */ + mmc_set32(mmchs->regs->irpt_mask, MMCHS_SD_IE_ERROR_MASK, 0xffffffffu); + + /* clear the error interrupts */ + mmc_set32(mmchs->regs->irpt, MMCHS_SD_STAT_ERROR_MASK, 0xffffffffu); + + /* send a init signal to the host controller. This does not actually + * send a command to a card manner */ + //mmc_set32(mmchs->regs->CON, MMCHS_SD_CON_INIT, MMCHS_SD_CON_INIT_INIT); + /* command 0 , type other commands not response etc) */ + mmc_write32(mmchs->regs->cmdtm, 0x00); + + spin_init(&spin, SANE_TIMEOUT); + while ((mmc_read32(mmchs->regs->irpt) & MMCHS_SD_STAT_CC) + != MMCHS_SD_STAT_CC_RAISED) { + if (mmc_read32(mmchs->regs->irpt) & 0x8000) { + log_warn(&log, "%s, error stat %x\n", + __FUNCTION__, mmc_read32(mmchs->regs->irpt_mask)); + return 1; + } + + if (spin_check(&spin) == FALSE) { + log_warn(&log, "Interrupt not raised during init\n"); + return 1; + } + } + + /* clear the cc interrupt status */ + mmc_set32(mmchs->regs->irpt_mask, MMCHS_SD_IE_CC_ENABLE, + MMCHS_SD_IE_CC_ENABLE_ENABLE); + + /* + * Set Set SD_CON[1] INIT bit to 0x0 to end the initialization sequence + */ + /*mmc_set32(mmchs->regs->CON, MMCHS_SD_CON_INIT, + MMCHS_SD_CON_INIT_NOINIT); + + /* Set timeout */ + mmc_set32(mmchs->regs->control1, MMCHS_SD_SYSCTL_DTO, + MMCHS_SD_SYSCTL_DTO_2POW27); + + /* Clean the MMCHS_SD_STAT register */ + mmc_write32(mmchs->regs->irpt, 0xffffffffu); +#ifdef USE_INTR + hook_id = 1; + if (sys_irqsetpolicy(mmchs->irq_nr, 0, &hook_id) != OK) { + log_warn(&log, "mmc: couldn't set IRQ policy %d\n", + mmchs->irq_nr); + return 1; + } + /* enable signaling from MMC controller towards interrupt controller */ + mmc_write32(mmchs->regs->irpt_en, 0xffffffffu); +#endif + + return 0; +} + +void +intr_deassert(int mask) +{ + if (mmc_read32(mmchs->regs->irpt_mask) & 0x8000) { + log_warn(&log, "%s, error stat %08x\n", __FUNCTION__, + mmc_read32(mmchs->regs->irpt_mask)); + mmc_set32(mmchs->regs->irpt_mask, MMCHS_SD_STAT_ERROR_MASK, + 0xffffffffu); + } else { + mmc_write32(mmchs->regs->irpt_mask, mask); + } +} + +/* pointer to the data to transfer used in bwr and brr */ +unsigned char *io_data; +int io_len; + +void +handle_bwr() +{ + /* handle buffer write ready interrupts. These happen in a non + * predictable way (eg. we send a request but don't know if we are + * first doing to get a request completed before we are allowed to + * send the data to the hardware or not */ + uint32_t value; + uint32_t count; + assert(mmc_read32(mmchs->regs->status) & MMCHS_SD_PSTATE_BWE_EN); + assert(io_data != NULL); + + for (count = 0; count < io_len; count += 4) { + while (!(mmc_read32(mmchs->regs-> + status) & MMCHS_SD_PSTATE_BWE_EN)) { + log_warn(&log, + "Error expected Buffer to be write enabled(%d)\n", + count); + } + *((char *) &value) = io_data[count]; + *((char *) &value + 1) = io_data[count + 1]; + *((char *) &value + 2) = io_data[count + 2]; + *((char *) &value + 3) = io_data[count + 3]; + mmc_write32(mmchs->regs->data, value); + } + intr_deassert(MMCHS_SD_IE_BWR_ENABLE); + /* expect buffer to be write enabled */ + io_data = NULL; +} + +void +handle_brr() +{ + /* handle buffer read ready interrupts. genrally these happen afther + * the data is read from the sd card. */ + + uint32_t value; + uint32_t count; + + /* Problem BRE should be true */ + assert(mmc_read32(mmchs->regs->status) & MMCHS_SD_PSTATE_BRE_EN); + + assert(io_data != NULL); + + for (count = 0; count < io_len; count += 4) { + value = mmc_read32(mmchs->regs->data); + io_data[count] = *((char *) &value); + io_data[count + 1] = *((char *) &value + 1); + io_data[count + 2] = *((char *) &value + 2); + io_data[count + 3] = *((char *) &value + 3); + } + /* clear bbr interrupt */ + intr_deassert(MMCHS_SD_IE_BRR_ENABLE_ENABLE); + io_data = NULL; +} + +static void +mmchs_hw_intr(unsigned int irqs) +{ + log_warn(&log, "Hardware interrupt left over (0x%08lx)\n", + mmc_read32(mmchs->regs->irpt_mask)); + +#ifdef USE_INTR + if (sys_irqenable(&hook_id) != OK) + printf("couldn't re-enable interrupt \n"); +#endif + /* Leftover interrupt(s) received; ack it/them. */ +} + +/*===========================================================================* + * w_intr_wait * + *===========================================================================*/ +static int +intr_wait(int mask) +{ + long v; +#ifdef USE_INTR + if (sys_irqenable(&hook_id) != OK) + printf("Failed to enable irqenable irq\n"); + /* Wait for a task completion interrupt. */ + message m; + int ipc_status; + int ticks = SANE_TIMEOUT * sys_hz() / 1000000; + + if (ticks <= 0) + ticks = 1; + while (1) { + int rr; + sys_setalarm(ticks, 0); + if ((rr = driver_receive(ANY, &m, &ipc_status)) != OK) { + panic("driver_receive failed: %d", rr); + }; + if (is_ipc_notify(ipc_status)) { + switch (_ENDPOINT_P(m.m_source)) { + case CLOCK: + /* Timeout. */ + log_warn(&log, "TIMEOUT\n"); + return 1; + break; + case HARDWARE: + while ((v = + mmc_read32(mmchs->regs->irpt_mask)) != + 0) { + if (v & MMCHS_SD_IE_BWR_ENABLE) { + handle_bwr(); + continue; + } + if (v & MMCHS_SD_IE_BRR_ENABLE) { + handle_brr(); + continue; + } + + if (v & mask) { + /* this is the normal return + * path, the mask given + * matches the pending + * interrupt. cancel the alarm + * and return */ + sys_setalarm(0, 0); + return 0; + } else if (v & (1 << 15)) { + return 1; /* error */ + } + + log_warn(&log, + "unexpected HW interrupt 0x%08x mask 0X%08x\n", + v, mask); + if (sys_irqenable(&hook_id) != OK) + printf + ("Failed to re-enable irqenable irq\n"); + } + /* if we end up here re-enable interrupts for + * the next round */ + if (sys_irqenable(&hook_id) != OK) + printf + ("Failed to re-enable irqenable irq\n"); + break; + default: + /* + * unhandled notify message. Queue it and + * handle it in the blockdriver loop. + */ + blockdriver_mq_queue(&m, ipc_status); + } + } else { + /* + * unhandled message. Queue it and handle it in the + * blockdriver loop. + */ + blockdriver_mq_queue(&m, ipc_status); + } + } + sys_setalarm(0, 0); /* cancel the alarm */ + +#else + spin_t spin; + spin_init(&spin, SANE_TIMEOUT); + /* Wait for completion */ + int counter = 0; + while (1 == 1) { + counter++; + v = mmc_read32(mmchs->regs->irpt_mask); + if (spin_check(&spin) == FALSE) { + log_warn(&log, + "Timeout waiting for interrupt (%d) value 0x%08x mask 0x%08x\n", + counter, v, mask); + return 1; + } + if (v & MMCHS_SD_IE_BWR_ENABLE) { + handle_bwr(); + continue; + } + if (v & MMCHS_SD_IE_BRR_ENABLE) { + handle_brr(); + continue; + } + if (v & mask) { + return 0; + } else if (v & 0xFF00) { + log_debug(&log, + "unexpected HW interrupt (%d) 0x%08x mask 0x%08x\n", + v, mask); + return 1; + } + } + return 1; /* unreached */ +#endif /* USE_INTR */ +} + +int +mmchs_send_cmd(uint32_t command, uint32_t arg) +{ + + /* Read current interrupt status and fail it an interrupt is already + * asserted */ + assert(mmc_read32(mmchs->regs->irpt_mask) == 0); + + /* Set arguments */ + mmc_write32(mmchs->regs->arg1, arg); + /* Set command */ + mmc_set32(mmchs->regs->cmdtm, MMCHS_SD_CMD_MASK, command); + + if (intr_wait(MMCHS_SD_STAT_CC)) { + uint32_t v = mmc_read32(mmchs->regs->irpt_mask); + intr_deassert(MMCHS_SD_STAT_CC); + log_warn(&log, "Failure waiting for interrupt 0x%lx\n", v); + return 1; + } + intr_deassert(MMCHS_SD_STAT_CC); + + if ((command & MMCHS_SD_CMD_RSP_TYPE) == + MMCHS_SD_CMD_RSP_TYPE_48B_BUSY) { + /* + * Command with busy response *CAN* also set the TC bit if they exit busy + */ + if ((mmc_read32(mmchs->regs->irpt_mask) + & MMCHS_SD_IE_TC_ENABLE_ENABLE) == 0) { + log_warn(&log, "TC should be raised\n"); + } + intr_deassert(MMCHS_SD_STAT_TC); + } + return 0; +} + +int +mmc_send_cmd(struct mmc_command *c) +{ + + /* convert the command to a hsmmc command */ + int ret; + uint32_t cmd, arg; + cmd = MMCHS_SD_CMD_INDX_CMD(c->cmd); + arg = c->args; + assert(c->data_type == DATA_NONE || c->data_type == DATA_READ + || c->data_type == DATA_WRITE); + + switch (c->resp_type) { + case RESP_LEN_48_CHK_BUSY: + cmd |= MMCHS_SD_CMD_RSP_TYPE_48B_BUSY; + break; + case RESP_LEN_48: + cmd |= MMCHS_SD_CMD_RSP_TYPE_48B; + break; + case RESP_LEN_136: + cmd |= MMCHS_SD_CMD_RSP_TYPE_136B; + break; + case RESP_NO_RESPONSE: + cmd |= MMCHS_SD_CMD_RSP_TYPE_NO_RESP; + break; + default: + return 1; + } + + /* read single block */ + if (c->data_type == DATA_READ) { + cmd |= MMCHS_SD_CMD_DP_DATA; /* Command with data transfer */ + cmd |= MMCHS_SD_CMD_MSBS_SINGLE; /* single block */ + cmd |= MMCHS_SD_CMD_DDIR_READ; /* read data from card */ + } + + /* write single block */ + if (c->data_type == DATA_WRITE) { + cmd |= MMCHS_SD_CMD_DP_DATA; /* Command with data transfer */ + cmd |= MMCHS_SD_CMD_MSBS_SINGLE; /* single block */ + cmd |= MMCHS_SD_CMD_DDIR_WRITE; /* write to the card */ + } + + /* check we are in a sane state */ + if ((mmc_read32(mmchs->regs->irpt_mask) & 0xffffu)) { + log_warn(&log, "%s, interrupt already raised stat %08x\n", + __FUNCTION__, mmc_read32(mmchs->regs->irpt_mask)); + mmc_write32(mmchs->regs->irpt_mask, MMCHS_SD_IE_CC_ENABLE_CLEAR); + } + + if (cmd & MMCHS_SD_CMD_DP_DATA) { + if (cmd & MMCHS_SD_CMD_DDIR_READ) { + /* if we are going to read enable the buffer ready + * interrupt */ + mmc_set32(mmchs->regs->irpt, + MMCHS_SD_IE_BRR_ENABLE, + MMCHS_SD_IE_BRR_ENABLE_ENABLE); + } else { + mmc_set32(mmchs->regs->irpt, + MMCHS_SD_IE_BWR_ENABLE, + MMCHS_SD_IE_BWR_ENABLE_ENABLE); + } + io_data = c->data; + io_len = c->data_len; + assert(io_len <= 0xFFF); /* only 12 bits */ + assert(io_data != NULL); + mmc_set32(mmchs->regs->blkscnt, MMCHS_SD_BLK_BLEN, io_len); + } + + ret = mmchs_send_cmd(cmd, arg); + + if (cmd & MMCHS_SD_CMD_DP_DATA) { + assert(c->data_len); + if (cmd & MMCHS_SD_CMD_DDIR_READ) { + /* Wait for TC */ + if (intr_wait(MMCHS_SD_IE_TC_ENABLE_ENABLE)) { + intr_deassert(MMCHS_SD_IE_TC_ENABLE_ENABLE); + log_warn(&log, + "(Read) Timeout waiting for interrupt\n"); + return 1; + } + + mmc_write32(mmchs->regs->irpt_mask, + MMCHS_SD_IE_TC_ENABLE_CLEAR); + + /* disable the bbr interrupt */ + mmc_set32(mmchs->regs->irpt, + MMCHS_SD_IE_BRR_ENABLE, + MMCHS_SD_IE_BRR_ENABLE_DISABLE); + } else { + /* Wait for TC */ + if (intr_wait(MMCHS_SD_IE_TC_ENABLE_ENABLE)) { + intr_deassert(MMCHS_SD_IE_TC_ENABLE_CLEAR); + log_warn(&log, + "(Write) Timeout waiting for transfer complete\n"); + return 1; + } + intr_deassert(MMCHS_SD_IE_TC_ENABLE_CLEAR); + + mmc_set32(mmchs->regs->irpt, + MMCHS_SD_IE_BWR_ENABLE, + MMCHS_SD_IE_BWR_ENABLE_DISABLE); + + } + } + + /* copy response into cmd->resp */ + switch (c->resp_type) { + case RESP_LEN_48_CHK_BUSY: + case RESP_LEN_48: + c->resp[0] = mmc_read32(mmchs->regs->resp0); + break; + case RESP_LEN_136: + c->resp[0] = mmc_read32(mmchs->regs->resp0); + c->resp[1] = mmc_read32(mmchs->regs->resp1); + c->resp[2] = mmc_read32(mmchs->regs->resp2); + c->resp[3] = mmc_read32(mmchs->regs->resp3); + break; + case RESP_NO_RESPONSE: + break; + default: + return 1; + } + + return ret; +} + +int +mmc_send_app_cmd(struct sd_card_regs *card, struct mmc_command *c) +{ + struct mmc_command command; + command.cmd = MMC_APP_CMD; + command.resp_type = RESP_LEN_48; + command.data_type = DATA_NONE; + command.args = MMC_ARG_RCA(card->rca); + if (mmc_send_cmd(&command)) { + return 1; + } + return mmc_send_cmd(c); +} + +int +card_goto_idle_state() +{ + struct mmc_command command; + command.cmd = MMC_GO_IDLE_STATE; + command.resp_type = RESP_NO_RESPONSE; + command.data_type = DATA_NONE; + command.args = 0x00; + if (mmc_send_cmd(&command)) { + // Failure + return 1; + } + return 0; +} + +int +card_identification() +{ + struct mmc_command command; + command.cmd = SD_SEND_IF_COND; /* Send CMD8 */ + command.resp_type = RESP_LEN_48; + command.data_type = DATA_NONE; + command.args = MMCHS_SD_ARG_CMD8_VHS | MMCHS_SD_ARG_CMD8_CHECK_PATTERN; + + if (mmc_send_cmd(&command)) { + /* We currently only support 2.0, and 1.0 won't respond to + * this request */ + log_warn(&log, "%s, non SDHC card inserted\n", __FUNCTION__); + return 1; + } + + if (!(command.resp[0] + == (MMCHS_SD_ARG_CMD8_VHS | MMCHS_SD_ARG_CMD8_CHECK_PATTERN))) { + log_warn(&log, "%s, check pattern check failed %08x\n", + __FUNCTION__, command.resp[0]); + return 1; + } + return 0; +} + +int +card_query_voltage_and_type(struct sd_card_regs *card) +{ + struct mmc_command command; + spin_t spin; + + command.cmd = SD_APP_OP_COND; + command.resp_type = RESP_LEN_48; + command.data_type = DATA_NONE; + + /* 0x1 << 30 == send HCS (Host capacity support) and get OCR register */ + command.args = + MMC_OCR_3_3V_3_4V | MMC_OCR_3_2V_3_3V | MMC_OCR_3_1V_3_2V | + MMC_OCR_3_0V_3_1V | MMC_OCR_2_9V_3_0V | MMC_OCR_2_8V_2_9V | + MMC_OCR_2_7V_2_8V; + command.args |= MMC_OCR_HCS; /* RCA=0000 */ + + if (mmc_send_app_cmd(card, &command)) { + return 1; + } + + spin_init(&spin, SANE_TIMEOUT); + while (!(command.resp[0] & MMC_OCR_MEM_READY)) { + + /* Send ADMD41 */ + /* 0x1 << 30 == send HCS (Host capacity support) and get OCR + * register */ + command.cmd = SD_APP_OP_COND; + command.resp_type = RESP_LEN_48; + command.data_type = DATA_NONE; + /* 0x1 << 30 == send HCS (Host capacity support) */ + command.args = MMC_OCR_3_3V_3_4V | MMC_OCR_3_2V_3_3V + | MMC_OCR_3_1V_3_2V | MMC_OCR_3_0V_3_1V | MMC_OCR_2_9V_3_0V + | MMC_OCR_2_8V_2_9V | MMC_OCR_2_7V_2_8V; + command.args |= MMC_OCR_HCS; /* RCA=0000 */ + + if (mmc_send_app_cmd(card, &command)) { + return 1; + } + + /* if bit 31 is set the response is valid */ + if ((command.resp[0] & MMC_OCR_MEM_READY)) { + break; + } + if (spin_check(&spin) == FALSE) { + log_warn(&log, "TIMEOUT waiting for the SD card\n"); + } + + } + card->ocr = command.resp[3]; + return 0; +} + +int +card_identify(struct sd_card_regs *card) +{ + struct mmc_command command; + /* Send cmd 2 (all_send_cid) and expect 136 bits response */ + command.cmd = MMC_ALL_SEND_CID; + command.resp_type = RESP_LEN_136; + command.data_type = DATA_NONE; + command.args = MMC_ARG_RCA(0x0); /* RCA=0000 */ + + if (mmc_send_cmd(&command)) { + return 1; + } + + card->cid[0] = command.resp[0]; + card->cid[1] = command.resp[1]; + card->cid[2] = command.resp[2]; + card->cid[3] = command.resp[3]; + + command.cmd = MMC_SET_RELATIVE_ADDR; + command.resp_type = RESP_LEN_48; + command.data_type = DATA_NONE; + command.args = 0x0; /* RCA=0000 */ + + /* R6 response */ + if (mmc_send_cmd(&command)) { + return 1; + } + + card->rca = SD_R6_RCA(command.resp); + /* MMHCS only supports a single card so sending MMCHS_SD_CMD_CMD2 is + * useless Still we should make it possible in the API to support + * multiple cards */ + + return 0; +} + +int +card_csd(struct sd_card_regs *card) +{ + /* Read the Card Specific Data register */ + struct mmc_command command; + + /* send_csd -> r2 response */ + command.cmd = MMC_SEND_CSD; + command.resp_type = RESP_LEN_136; + command.data_type = DATA_NONE; + command.args = MMC_ARG_RCA(card->rca); /* card rca */ + + if (mmc_send_cmd(&command)) { + return 1; + } + + card->csd[0] = command.resp[0]; + card->csd[1] = command.resp[1]; + card->csd[2] = command.resp[2]; + card->csd[3] = command.resp[3]; + + log_trace(&log, "CSD version %d\n", SD_CSD_CSDVER(card->csd)); + if (SD_CSD_CSDVER(card->csd) != SD_CSD_CSDVER_2_0) { + log_warn(&log, "Version 2.0 of CSD register expected\n"); + return 1; + } + + return 0; +} + +int +select_card(struct sd_card_regs *card) +{ + struct mmc_command command; + + command.cmd = MMC_SELECT_CARD; + command.resp_type = RESP_LEN_48_CHK_BUSY; + command.data_type = DATA_NONE; + command.args = MMC_ARG_RCA(card->rca); /* card rca */ + + if (mmc_send_cmd(&command)) { + return 1; + } + return 0; +} + +int +card_scr(struct sd_card_regs *card) +{ + uint8_t buffer[8]; /* 64 bits */ + uint8_t *p; + int c; + /* the SD CARD configuration register. This is an additional register + * next to the Card Specific register containing additional data we + * need */ + struct mmc_command command; + + log_trace(&log, "Read card scr\n"); + /* send_csd -> r2 response */ + command.cmd = SD_APP_SEND_SCR; + command.resp_type = RESP_LEN_48; + command.data_type = DATA_READ; + command.args = 0xaaaaaaaa; + command.data = buffer; + command.data_len = 8; + + if (mmc_send_app_cmd(card, &command)) { + return 1; + } + + p = (uint8_t *) card->scr; + + /* copy the data to card->scr */ + for (c = 7; c >= 0; c--) { + *p++ = buffer[c]; + } + + if (!SCR_SD_BUS_WIDTHS(card->scr) & SCR_SD_BUS_WIDTHS_4BIT) { + /* it would be very weird not to support 4 bits access */ + log_warn(&log, "4 bit access not supported\n"); + } + + log_trace(&log, "1 bit bus width %ssupported\n", + (SCR_SD_BUS_WIDTHS(card->scr) & SCR_SD_BUS_WIDTHS_1BIT) ? "" : + "un"); + log_trace(&log, "4 bit bus width %ssupported\n", + (SCR_SD_BUS_WIDTHS(card->scr) & SCR_SD_BUS_WIDTHS_4BIT) ? "" : + "un"); + + return 0; +} + +int +enable_4bit_mode(struct sd_card_regs *card) +{ + struct mmc_command command; + + if (SCR_SD_BUS_WIDTHS(card->scr) & SCR_SD_BUS_WIDTHS_4BIT) { + /* set transfer width */ + command.cmd = SD_APP_SET_BUS_WIDTH; + command.resp_type = RESP_LEN_48; + command.data_type = DATA_NONE; + command.args = 2; /* 4 bits */ + + if (mmc_send_app_cmd(card, &command)) { + log_warn(&log, + "SD-card does not support 4 bit transfer\n"); + return 1; + } + /* now configure the controller to use 4 bit access */ + mmc_set32(mmchs->regs->control0, MMCHS_SD_HCTL_DTW, + MMCHS_SD_HCTL_DTW_4BIT); + return 0; + } + return 1; /* expect 4 bits mode to work so having a card + * that doesn't support 4 bits mode */ +} + +void +dump_char(char *out, char in) +{ + int i; + memset(out, 0, 9); + for (i = 0; i < 8; i++) { + out[i] = ((in >> i) & 0x1) ? '1' : '0'; + } + +} + +void +dump(uint8_t * data, int len) +{ + int c; + char digit[4][9]; + char *p = data; + + for (c = 0; c < len;) { + memset(digit, 0, sizeof(digit)); + if (c++ < len) + dump_char(digit[0], *data++); + if (c++ < len) + dump_char(digit[1], *data++); + if (c++ < len) + dump_char(digit[2], *data++); + if (c++ < len) + dump_char(digit[3], *data++); + printf("%x %s %s %s %s\n", c, digit[0], digit[1], digit[2], + digit[3]); + } +} + +void +mmc_switch(int function, int value, uint8_t * data) +{ + struct mmc_command command; + + /* function index */ + int findex, fshift; + findex = function - 1; + fshift = findex << 2; /* bits used per function */ + + command.cmd = MMC_SWITCH; + command.resp_type = RESP_LEN_48; + command.data_type = DATA_READ; + command.data = data; + command.data_len = 64; + command.args = (1 << 31) | (0x00ffffff & ~(0xf << fshift)); + command.args |= (value << fshift); + if (mmc_send_cmd(&command)) { + log_warn(&log, "Failed to set device in high speed mode\n"); + return; + } + // dump(data,64); +} + +int +enable_high_speed_mode(struct sd_card_regs *card) +{ + /* MMC cards using version 4.0 or higher of the specs can work at + * higher bus rates. After setting the bus width one can send the + * HS_TIMING command to set the card in high speed mode after witch + * one can higher up the frequency */ + + uint8_t buffer[64]; /* 512 bits */ + log_info(&log, "Enabling high speed mode\n"); +#if 0 + Doesnt currently work + if (SCR_SD_SPEC(&card->scr[0]) >= SCR_SD_SPEC_VER_1_10) + { + mmc_switch(1, 1, buffer); + } +#endif + + if (SD_CSD_SPEED(card->csd) == SD_CSD_SPEED_25_MHZ) { + log_trace(&log, "Using 25MHz clock\n"); + mmchs_set_bus_freq(HSMMCSD_0_FREQ_25MHZ); + } else if (SD_CSD_SPEED(card->csd) == SD_CSD_SPEED_50_MHZ) { + log_trace(&log, "Using 50MHz clock\n"); + mmchs_set_bus_freq(HSMMCSD_0_FREQ_50MHZ); + } else { + log_warn(&log, "Unknown speed 0x%x in CSD register\n", + SD_CSD_SPEED(card->csd)); + } + + return 0; +} + +int +read_single_block(struct sd_card_regs *card, + uint32_t blknr, unsigned char *buf) +{ + struct mmc_command command; + + command.cmd = MMC_READ_BLOCK_SINGLE; + command.args = blknr; + command.resp_type = RESP_LEN_48; + command.data_type = DATA_READ; + command.data = buf; + command.data_len = 512; + + if (mmc_send_cmd(&command)) { + log_warn(&log, "Error sending command\n"); + return 1; + } + + return 0; +} + +int +write_single_block(struct sd_card_regs *card, + uint32_t blknr, unsigned char *buf) +{ + struct mmc_command command; + + command.cmd = MMC_WRITE_BLOCK_SINGLE; + command.args = blknr; + command.resp_type = RESP_LEN_48; + command.data_type = DATA_WRITE; + command.data = buf; + command.data_len = 512; + + /* write single block */ + if (mmc_send_cmd(&command)) { + log_warn(&log, "Write single block command failed\n"); + return 1; + } + + return 0; +} + +int +mmchs_host_init(struct mmc_host *host) +{ + mmchs_init(1); + return 0; +} + +void +mmchs_set_log_level(int level) +{ + if (level >= 0 && level <= 4) { + log.log_level = level; + } +} + +int +mmchs_host_set_instance(struct mmc_host *host, int instance) +{ + log_info(&log, "Using instance number %d\n", instance); + if (instance != 0) { + return EIO; + } + return OK; +} + +int +mmchs_host_reset(struct mmc_host *host) +{ + // mmchs_init(1); + return 0; +} + +int +mmchs_card_detect(struct sd_slot *slot) +{ + /* @TODO implement proper card detect */ + return 1; +} + +struct sd_card * +mmchs_card_initialize(struct sd_slot *slot) +{ + // mmchs_init(1); + + struct sd_card *card; + card = &slot->card; + memset(card, 0, sizeof(struct sd_card)); + card->slot = slot; + + if (card_goto_idle_state()) { + log_warn(&log, "Failed to go idle state\n"); + return NULL; + } + + if (card_identification()) { + log_warn(&log, "Failed to do card_identification\n"); + return NULL; + } + + if (card_query_voltage_and_type(&slot->card.regs)) { + log_warn(&log, "Failed to do card_query_voltage_and_type\n"); + return NULL; + } + + if (card_identify(&slot->card.regs)) { + log_warn(&log, "Failed to identify card\n"); + return NULL; + } + /* We have now initialized the hardware identified the card */ + if (card_csd(&slot->card.regs)) { + log_warn(&log, "failed to read csd (card specific data)\n"); + return NULL; + } + + if (select_card(&slot->card.regs)) { + log_warn(&log, "Failed to select card\n"); + return NULL; + } + + if (card_scr(&slot->card.regs)) { + log_warn(&log, + "failed to read scr (card additional specific data)\n"); + return NULL; + } + + if (enable_4bit_mode(&slot->card.regs)) { + log_warn(&log, "failed to configure 4 bit access mode\n"); + return NULL; + } + + if (enable_high_speed_mode(&slot->card.regs)) { + log_warn(&log, "failed to configure high speed mode mode\n"); + return NULL; + } + + if (SD_CSD_READ_BL_LEN(slot->card.regs.csd) != 0x09) { + /* for CSD version 2.0 the value is fixed to 0x09 and means a + * block size of 512 */ + log_warn(&log, "Block size expect to be 512\n"); + return NULL; + } + + slot->card.blk_size = 512; /* HARDCODED value */ + slot->card.blk_count = SD_CSD_V2_CAPACITY(slot->card.regs.csd); + slot->card.state = SD_MODE_DATA_TRANSFER_MODE; + + /* MINIX related stuff to keep track of partitions */ + memset(slot->card.part, 0, sizeof(slot->card.part)); + memset(slot->card.subpart, 0, sizeof(slot->card.subpart)); + slot->card.part[0].dv_base = 0; + slot->card.part[0].dv_size = + (unsigned long long) SD_CSD_V2_CAPACITY(slot->card.regs.csd) * 512; + return &slot->card; +} + +/* read count blocks into existing buf */ +static int +mmchs_host_read(struct sd_card *card, + uint32_t blknr, uint32_t count, unsigned char *buf) +{ + uint32_t i; + i = count; + for (i = 0; i < count; i++) { + read_single_block(&card->regs, blknr + i, + buf + (i * card->blk_size)); + } + return OK; +} + +/* write count blocks */ +static int +mmchs_host_write(struct sd_card *card, + uint32_t blknr, uint32_t count, unsigned char *buf) +{ + uint32_t i; + + i = count; + for (i = 0; i < count; i++) { + write_single_block(&card->regs, blknr + i, + buf + (i * card->blk_size)); + } + + return OK; +} + +int +mmchs_card_release(struct sd_card *card) +{ + assert(card->open_ct == 1); + card->open_ct--; + card->state = SD_MODE_UNINITIALIZED; + /* TODO:Set card state */ + + /* now configure the controller to use 4 bit access */ + mmc_set32(mmchs->regs->control0, MMCHS_SD_HCTL_DTW, + MMCHS_SD_HCTL_DTW_1BIT); + + return OK; +} + +void +host_initialize_host_structure_mmchs(struct mmc_host *host) +{ + /* Initialize the basic data structures host slots and cards */ + int i; + mmchs = NULL; + + struct machine machine ; + sys_getmachine(&machine); + + mmchs = &rpi_sdcard; + + assert(mmchs); + host->host_set_instance = mmchs_host_set_instance; + host->host_init = mmchs_host_init; + host->set_log_level = mmchs_set_log_level; + host->host_reset = mmchs_host_reset; + host->card_detect = mmchs_card_detect; + host->card_initialize = mmchs_card_initialize; + host->card_release = mmchs_card_release; + host->hw_intr = mmchs_hw_intr; + host->read = mmchs_host_read; + host->write = mmchs_host_write; + + /* initialize data structures */ + for (i = 0; i < sizeof(host->slot) / sizeof(host->slot[0]); i++) { + // @TODO set initial card and slot state + host->slot[i].host = host; + host->slot[i].card.slot = &host->slot[i]; + } +} diff --git a/minix/drivers/storage/mmc/rpi/rpi_mmc.h b/minix/drivers/storage/mmc/rpi/rpi_mmc.h new file mode 100644 index 000000000..36c215638 --- /dev/null +++ b/minix/drivers/storage/mmc/rpi/rpi_mmc.h @@ -0,0 +1,282 @@ +#ifndef __SD_H__ +#define __SD_H__ + +#define RW +#define R + +typedef struct { + RW vir_bytes blkscnt; + RW vir_bytes arg1; + RW vir_bytes cmdtm; + R vir_bytes resp0; + R vir_bytes resp1; + R vir_bytes resp2; + R vir_bytes resp3; + RW vir_bytes data; + R vir_bytes status; + RW vir_bytes control0; + RW vir_bytes control1; + RW vir_bytes irpt; + RW vir_bytes irpt_mask; + RW vir_bytes irpt_en; + RW vir_bytes control2; + RW vir_bytes slotisr_var; +} rpi_mmchs_registers; + +rpi_mmchs_registers regs_v0 = { + .blkscnt = 0x4, + .arg1 = 0x8, + .cmdtm = 0xc, + .resp0 = 0x10, + .resp1 = 0x14, + .resp2 = 0x18, + .resp3 = 0x1c, + .data = 0x20, + .status = 0x24, + .control0 = 0x28, + .control1 = 0x2c, + .irpt = 0x30, + .irpt_mask = 0x34, + .irpt_en = 0x38, + .control2 = 0x3c, + .slotisr_var = 0xfc +}; + +struct rpi_mmchs { + vir_bytes io_base; + vir_bytes io_size; + phys_bytes hw_base;/* HW address */ + int irq_nr; + rpi_mmchs_registers * regs; +}; + +#define MMCHS_SD_SYSCONFIG_AUTOIDLE (0x1 << 0) /* Internal clock gating strategy */ +#define MMCHS_SD_SYSCONFIG_AUTOIDLE_DIS (0x0 << 0) /* Clocks are free running */ +#define MMCHS_SD_SYSCONFIG_AUTOIDLE_EN (0x1 << 0) /* Automatic clock gating strategy */ +#define MMCHS_SD_SYSCONFIG_SOFTRESET (0x1 << 1) /* Software reset bit writing */ +#define MMCHS_SD_SYSCONFIG_ENAWAKEUP (0x1 << 2) /* Wake-up feature control */ +#define MMCHS_SD_SYSCONFIG_ENAWAKEUP_DIS (0x0 << 2) /* Disable wake-up capability */ +#define MMCHS_SD_SYSCONFIG_ENAWAKEUP_EN (0x1 << 2) /* Enable wake-up capability */ +#define MMCHS_SD_SYSCONFIG_SIDLEMODE (0x3 << 3) /* Power management */ +#define MMCHS_SD_SYSCONFIG_SIDLEMODE_UNCONDITIONAL (0x0 << 3) /* Go into idle mode unconditionally upon request */ +#define MMCHS_SD_SYSCONFIG_SIDLEMODE_IGNORE (0x1 << 3) /* Ignore ILDE requests */ +#define MMCHS_SD_SYSCONFIG_SIDLEMODE_IDLE (0x2 << 3) /* Acknowledge IDLE request switch to wake-up mode */ +#define MMCHS_SD_SYSCONFIG_SIDLEMODE_SMART_IDLE (0x3 << 3) /* Smart-idle */ +#define MMCHS_SD_SYSCONFIG_CLOCKACTIVITY (0x3 << 8) /* Clock activity during wake-up */ +#define MMCHS_SD_SYSCONFIG_CLOCKACTIVITY_OFF (0x0 << 8) /* Interface and functional clock can be switched off */ +#define MMCHS_SD_SYSCONFIG_CLOCKACTIVITY_IF (0x1 << 8) /* Only Interface clock (functional can be switched off*/ +#define MMCHS_SD_SYSCONFIG_CLOCKACTIVITY_FUNC (0x2 << 8) /* Only Functional clock (interface clock can be switched off) */ +#define MMCHS_SD_SYSCONFIG_CLOCKACTIVITY_BOOTH (0x3 << 8) /* Booth the interface and functional clock are maintained */ +#define MMCHS_SD_SYSCONFIG_STANDBYMODE (0x3 << 12) /* Configuration for standby */ +#define MMCHS_SD_SYSCONFIG_STANDBYMODE_FORCE_STANDBY (0x0 << 12) /* Force standby mode upon idle request*/ +#define MMCHS_SD_SYSCONFIG_STANDBYMODE_NO_STANDBY (0x1 << 12) /* Never go into standby mode */ +#define MMCHS_SD_SYSCONFIG_STANDBYMODE_WAKEUP_INTERNAL (0x2 << 12) /* Go into wake-up mode based on internal knowledge */ +#define MMCHS_SD_SYSCONFIG_STANDBYMODE_WAKEUP_SMART (0x3 << 12) /* Go info wake-up mode when possible */ + +#define MMCHS_SD_SYSSTATUS_RESETDONE 0x01 + +#define MMCHS_SD_CON_DW8 (0x1 << 5) /* 8-bit mode MMC select , For SD clear this bit */ +#define MMCHS_SD_CON_DW8_1BIT (0x0 << 5) /* 1 or 4 bits data width configuration(also set SD_HCTL) */ +#define MMCHS_SD_CON_DW8_8BITS (0x1 << 5) /* 8 bits data width configuration */ +#define MMCHS_SD_CON_INIT (0x1 << 1) /* Send initialization stream (all cards) */ +#define MMCHS_SD_CON_INIT_NOINIT (0x0 << 1) /* Do nothing */ +#define MMCHS_SD_CON_INIT_INIT (0x1 << 1) /* Send initialization stream */ +#define MMCHS_SD_CON_OD (0x1 << 0) /* Card open drain mode (MMC cards only) */ +#define MMCHS_SD_CON_OD_PP (0x0 << 0) /* No open drain (push-pull). */ +#define MMCHS_SD_CON_OD_OD (0x1 << 0) /* Open drain */ + +#define MMCHS_SD_BLK_NBLK (0xffffu << 16) /* Block count for the current transfer */ +#define MMCHS_SD_BLK_BLEN (0xfff << 0) /* Transfer block size */ +#define MMCHS_SD_BLK_BLEN_NOTRANSFER (0x0 << 0) /* No transfer */ + +#define MMCHS_SD_CMD_INDX (0x3f << 24) /* Command index */ +#define MMCHS_SD_CMD_INDX_CMD(x) (x << 24) /* MMC command index binary encoded values from 0 to 63 */ + +#define MMCHS_SD_ARG_MASK (0xffffffffu) /* Mask everything */ +#define MMCHS_SD_ARG_CMD8_VHS (0x1 << (16 - 8)) /* Voltage between 2.7 and 3.6 v*/ +#define MMCHS_SD_ARG_CMD8_CHECK_PATTERN (0xaa <<(8 - 8)) /* 10101010b pattern */ + +#define MMCHS_SD_CMD_TYPE (0x3 << 22) /* Command type. */ +#define MMCHS_SD_CMD_TYPE_OTHER (0x0 << 22) /* Other type of commands (like go idle) */ +#define MMCHS_SD_CMD_TYPE_BUS_SUSPEND (0x1 << 22) /* Upon CMD52 "Bus Suspend" operation */ +#define MMCHS_SD_CMD_TYPE_FUNCTION_SELECT (0x2 << 22) /* Upon CMD52 "Function Select" operation */ +#define MMCHS_SD_CMD_TYPE_IOABORT (0x3 << 22) /* Upon CMD12 and CMD21 "I/O Abort */ +#define MMCHS_SD_CMD_DP (0x1 << 21) /* Data present select */ +#define MMCHS_SD_CMD_DP_DATA (0x1 << 21) /* Additional data is present on the data lines */ +#define MMCHS_SD_CMD_DP_NODATA (0x0 << 21) /* No additional data is present on the data lines */ +#define MMCHS_SD_CMD_CICE (0x1 << 20) /* Command index response check enable */ +#define MMCHS_SD_CMD_CICE_ENABLE (0x1 << 20) /* Enable index check response */ +#define MMCHS_SD_CMD_CICE_DISABLE (0x0 << 20) /* Disable index check response */ +#define MMCHS_SD_CMD_CCCE (0x1 << 19) /* Command CRC7 Check enable on responses*/ +#define MMCHS_SD_CMD_CCCE_ENABLE (0x1 << 19) /* Enable CRC7 Check on response */ +#define MMCHS_SD_CMD_CCCE_DISABLE (0x0 << 19) /* Disable CRC7 Check on response */ +#define MMCHS_SD_CMD_RSP_TYPE (0x3 << 16) /* Response type */ +#define MMCHS_SD_CMD_RSP_TYPE_NO_RESP (0x0 << 16) /* No response */ +#define MMCHS_SD_CMD_RSP_TYPE_136B (0x1 << 16) /* Response length 136 bits */ +#define MMCHS_SD_CMD_RSP_TYPE_48B (0x2 << 16) /* Response length 48 bits */ +#define MMCHS_SD_CMD_RSP_TYPE_48B_BUSY (0x3 << 16) /* Response length 48 bits with busy after response */ +#define MMCHS_SD_CMD_MSBS (0x1 << 5) /* Multi/Single block select */ +#define MMCHS_SD_CMD_MSBS_SINGLE (0x0 << 5) /* Single block mode */ +#define MMCHS_SD_CMD_MSBS_MULTI (0x0 << 5) /* Multi block mode */ +#define MMCHS_SD_CMD_DDIR (0x1 << 4) /* Data transfer direction */ +#define MMCHS_SD_CMD_DDIR_READ (0x1 << 4) /* Data read (card to host) */ +#define MMCHS_SD_CMD_DDIR_WRITE (0x0 << 4) /* Data write (host to card) */ +#define MMCHS_SD_CMD_ACEN (0x1 << 2) /* Auto CMD12 Enable */ +#define MMCHS_SD_CMD_ACEN_DIS (0x0 << 2) /* Auto CMD12 Disable */ +#define MMCHS_SD_CMD_ACEN_EN (0x1 << 2) /* Auto CMD12 Enable */ +#define MMCHS_SD_CMD_BCE (0x1 << 1) /* Block Count Enable(for multi block transfer) */ +#define MMCHS_SD_CMD_BCE_DIS (0x0 << 1) /* Disabled block count for infinite transfer*/ +#define MMCHS_SD_CMD_BCE_EN (0x1 << 1) /* Enabled for multi block transfer with know amount of blocks */ +#define MMCHS_SD_CMD_DE (0x1 << 0) /* DMA enable */ +#define MMCHS_SD_CMD_DE_DIS (0x0 << 0) /* Disable DMA */ +#define MMCHS_SD_CMD_DE_EN (0x1 << 0) /* Enable DMA */ +#define MMCHS_SD_CMD_MASK ~(0x1 << 30 | 0x1 << 31 | 0x1 << 18 | 0x1 <<3) /* bits 30 , 31 and 18 are reserved */ + +#define MMCHS_SD_PSTATE_CI (0x1 << 16) /* Card Inserted */ +#define MMCHS_SD_PSTATE_CI_INSERTED (0x1 << 16) /* Card Inserted is inserted*/ +#define MMCHS_SD_PSTATE_BRE (0x1 << 11) /* Buffer read enable */ +#define MMCHS_SD_PSTATE_BRE_DIS (0x0 << 11) /* Read BLEN bytes disabled*/ +#define MMCHS_SD_PSTATE_BRE_EN (0x1 << 11) /* Read BLEN bytes enabled*/ +#define MMCHS_SD_PSTATE_BWE (0x1 << 10) /* Buffer Write enable */ +#define MMCHS_SD_PSTATE_BWE_DIS (0x0 << 10) /* There is no room left in the buffer to write BLEN bytes of data */ +#define MMCHS_SD_PSTATE_BWE_EN (0x1 << 10) /* There is enough space in the buffer to write BLEN bytes of data*/ +#define MMCHS_SD_PSTATE_DATI (0x1 << 1) /* Command inhibit (mmc_dat) */ +#define MMCHS_SD_PSTATE_CMDI (0x1 << 0) /* Command inhibit (mmc_cmd) */ + +#define MMCHS_SD_HCTL_DTW (0x1 << 1) /*Data transfer width.(must be set after a successful ACMD6) */ +#define MMCHS_SD_HCTL_DTW_1BIT (0x0 << 1) /*1 bit transfer with */ +#define MMCHS_SD_HCTL_DTW_4BIT (0x1 << 1) /*4 bit transfer with */ +#define MMCHS_SD_HCTL_SDBP (0x1 << 8) /*SD bus power */ +#define MMCHS_SD_HCTL_SDBP_OFF (0x0 << 8) /*SD Power off (start card detect?) */ +#define MMCHS_SD_HCTL_SDBP_ON (0x1 << 8) /*SD Power on (start card detect?) */ +#define MMCHS_SD_HCTL_SDVS (0x7 << 9) /*SD bus voltage select */ +#define MMCHS_SD_HCTL_SDVS_VS18 (0x5 << 9) /*1.8 V */ +#define MMCHS_SD_HCTL_SDVS_VS30 (0x6 << 9) /*3.0 V */ +#define MMCHS_SD_HCTL_SDVS_VS33 (0x7 << 9) /*3.3 V */ +#define MMCHS_SD_HCTL_IWE (0x1 << 24)/* wake-up event on SD interrupt */ +#define MMCHS_SD_HCTL_IWE_DIS (0x0 << 24)/* Disable wake-up on SD interrupt */ +#define MMCHS_SD_HCTL_IWE_EN (0x1 << 24)/* Enable wake-up on SD interrupt */ + +#define MMCHS_SD_SYSCTL_CLKD (0x3ff << 6) /* 10 bits clock frequency select */ +#define MMCHS_SD_SYSCTL_SRD (0x1 << 26) /* Soft reset for mmc_dat line */ +#define MMCHS_SD_SYSCTL_SRC (0x1 << 25) /* Soft reset for mmc_cmd line */ +#define MMCHS_SD_SYSCTL_SRA (0x1 << 24) /* Soft reset all (host controller) */ + +#define MMCHS_SD_SYSCTL_ICE (0x1 << 0) /* Internal clock enable register */ +#define MMCHS_SD_SYSCTL_ICE_DIS (0x0 << 0) /* Disable internal clock */ +#define MMCHS_SD_SYSCTL_ICE_EN (0x1 << 0) /* Enable internal clock */ +#define MMCHS_SD_SYSCTL_ICS (0x1 << 1) /* Internal clock stable register */ +#define MMCHS_SD_SYSCTL_ICS_UNSTABLE (0x0 << 1) /* Internal clock is unstable */ +#define MMCHS_SD_SYSCTL_ICS_STABLE (0x1 << 1) /* Internal clock is stable */ +#define MMCHS_SD_SYSCTL_CEN (0x1 << 2) /* Card lock enable provide clock to the card */ +#define MMCHS_SD_SYSCTL_CEN_DIS (0x0 << 2) /* Internal clock is unstable */ +#define MMCHS_SD_SYSCTL_CEN_EN (0x1 << 2) /* Internal clock is stable */ + +#define MMCHS_SD_SYSCTL_DTO (0xf << 16) /* Data timeout counter */ +#define MMCHS_SD_SYSCTL_DTO_2POW13 (0x0 << 16) /* TCF x 2^13 */ +#define MMCHS_SD_SYSCTL_DTO_2POW14 (0x1 << 16) /* TCF x 2^14 */ +#define MMCHS_SD_SYSCTL_DTO_2POW20 (0x7 << 16) /* TCF x 2^20 */ +#define MMCHS_SD_SYSCTL_DTO_2POW27 (0xe << 16) /* TCF x 2^27 */ + +#define MMCHS_SD_STAT_CERR (0x1 << 28) /* card error */ +#define MMCHS_SD_STAT_DEB (0x1 << 22) /* data end bit error */ +#define MMCHS_SD_STAT_DCRC (0x1 << 21) /* data CRC error */ +#define MMCHS_SD_STAT_DTO (0x1 << 20) /* data timeout error */ +#define MMCHS_SD_STAT_CIE (0x1 << 19) /* command index error */ +#define MMCHS_SD_STAT_CEB (0x1 << 18) /* command end bit error */ +#define MMCHS_SD_STAT_CCRC (0x1 << 17) /* command CRC error */ +#define MMCHS_SD_STAT_CTO (0x1 << 16) /* command timeout error */ +#define MMCHS_SD_STAT_ERRI (0x01 << 15) /* Error interrupt */ +#define MMCHS_SD_STAT_ERROR_MASK (0xff << 15 | 0x3 << 24 | 0x03 << 28) +#define MMCHS_SD_STAT_BRR (0x1 << 5) /* Buffer Read ready */ +#define MMCHS_SD_STAT_BWR (0x1 << 4) /* Buffer Write ready */ +#define MMCHS_SD_STAT_CC (0x1 << 0) /* Command complete status */ +#define MMCHS_SD_STAT_CC_UNRAISED (0x0 << 0) /* Command not completed */ +#define MMCHS_SD_STAT_CC_RAISED (0x1 << 0) /* Command completed */ +#define MMCHS_SD_STAT_TC (0x1 << 1) /* Transfer complete status */ +#define MMCHS_SD_STAT_TC_UNRAISED (0x0 << 1) /* Transfer not completed */ +#define MMCHS_SD_STAT_TC_RAISED (0x1 << 1) /* Transfer completed */ + +#define MMCHS_SD_IE_ERROR_MASK (0xff << 15 | 0x3 << 24 | 0x03 << 28) + +#define MMCHS_SD_IE_CC_ENABLE (0x1 << 0) /* Command complete interrupt enable */ +#define MMCHS_SD_IE_CC_ENABLE_ENABLE (0x1 << 0) /* Command complete Interrupts are enabled */ +#define MMCHS_SD_IE_CC_ENABLE_CLEAR (0x1 << 0) /* Clearing is done by writing a 0x1 */ + +#define MMCHS_SD_IE_TC_ENABLE (0x1 << 1) /* Transfer complete interrupt enable */ +#define MMCHS_SD_IE_TC_ENABLE_ENABLE (0x1 << 1) /* Transfer complete Interrupts are enabled */ +#define MMCHS_SD_IE_TC_ENABLE_CLEAR (0x1 << 1) /* Clearing TC is done by writing a 0x1 */ + +#define MMCHS_SD_IE_BRR_ENABLE (0x1 << 5) /* Buffer read ready interrupt */ +#define MMCHS_SD_IE_BRR_ENABLE_DISABLE (0x0 << 5) /* Buffer read ready interrupt disable */ +#define MMCHS_SD_IE_BRR_ENABLE_ENABLE (0x1 << 5) /* Buffer read ready interrupt enable */ +#define MMCHS_SD_IE_BRR_ENABLE_CLEAR (0x1 << 5) /* Buffer read ready interrupt clear */ + +#define MMCHS_SD_IE_BWR_ENABLE (0x1 << 4) /* Buffer write ready interrupt */ +#define MMCHS_SD_IE_BWR_ENABLE_DISABLE (0x0 << 4) /* Buffer write ready interrupt disable */ +#define MMCHS_SD_IE_BWR_ENABLE_ENABLE (0x1 << 4) /* Buffer write ready interrupt enable */ +#define MMCHS_SD_IE_BWR_ENABLE_CLEAR (0x1 << 4) /* Buffer write ready interrupt clear */ + +#define MMCHS_SD_CAPA_VS_MASK (0x7 << 24 ) /* voltage mask */ +#define MMCHS_SD_CAPA_VS18 (0x01 << 26 ) /* 1.8 volt */ +#define MMCHS_SD_CAPA_VS30 (0x01 << 25 ) /* 3.0 volt */ +#define MMCHS_SD_CAPA_VS33 (0x01 << 24 ) /* 3.3 volt */ + +// The actual command indices +#define GO_IDLE_STATE 0 +#define ALL_SEND_CID 2 +#define SEND_RELATIVE_ADDR 3 +#define SET_DSR 4 +#define IO_SET_OP_COND 5 +#define SWITCH_FUNC 6 +#define SELECT_CARD 7 +#define DESELECT_CARD 7 +#define SELECT_DESELECT_CARD 7 +#define SEND_IF_COND 8 +#define SEND_CSD 9 +#define SEND_CID 10 +#define VOLTAGE_SWITCH 11 +#define STOP_TRANSMISSION 12 +#define SEND_STATUS 13 +#define GO_INACTIVE_STATE 15 +#define SET_BLOCKLEN 16 +#define READ_SINGLE_BLOCK 17 +#define READ_MULTIPLE_BLOCK 18 +#define SEND_TUNING_BLOCK 19 +#define SPEED_CLASS_CONTROL 20 +#define SET_BLOCK_COUNT 23 +#define WRITE_SINGLE_BLOCK 24 +#define WRITE_MULTIPLE_BLOCK 25 +#define PROGRAM_CSD 27 +#define SET_WRITE_PROT 28 +#define CLR_WRITE_PROT 29 +#define SEND_WRITE_PROT 30 +#define ERASE_WR_BLK_START 32 +#define ERASE_WR_BLK_END 33 +#define ERASE 38 +#define LOCK_UNLOCK 42 +#define APP_CMD 55 +#define GEN_CMD 56 + +#define IS_APP_CMD 0x80000000 +#define ACMD(a) (a | IS_APP_CMD) +#define SET_BUS_WIDTH (6 | IS_APP_CMD) +#define SD_STATUS (13 | IS_APP_CMD) +#define SEND_NUM_WR_BLOCKS (22 | IS_APP_CMD) +#define SET_WR_BLK_ERASE_COUNT (23 | IS_APP_CMD) +#define SD_SEND_OP_COND (41 | IS_APP_CMD) +#define SET_CLR_CARD_DETECT (42 | IS_APP_CMD) +#define SEND_SCR (51 | IS_APP_CMD) + +#define SD_GET_CLOCK_DIVIDER_FAIL 0xffffffff + +#define MIN_FREQ 400000 +#define BCM2835_EMMC_WRITE_DELAY (((2 * 1000000) / MIN_FREQ) + 1) + +// Enable 4-bit support +#define SD_4BIT_DATA + +// Enable SDXC maximum performance mode +#define SDXC_MAXIMUM_PERFORMANCE + +#endif \ No newline at end of file diff --git a/minix/drivers/storage/mmc/sdhcreg.h b/minix/drivers/storage/mmc/sdhcreg.h deleted file mode 100644 index df6f33125..000000000 --- a/minix/drivers/storage/mmc/sdhcreg.h +++ /dev/null @@ -1,202 +0,0 @@ -/* $NetBSD: sdhcreg.h,v 1.6 2012/03/02 18:20:34 nonaka Exp $ */ -/* $OpenBSD: sdhcreg.h,v 1.4 2006/07/30 17:20:40 fgsch Exp $ */ - -/* - * Copyright (c) 2006 Uwe Stuehler - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _SDHCREG_H_ -#define _SDHCREG_H_ - -/* Host standard register set */ -#define SDHC_DMA_ADDR 0x00 -#define SDHC_BLOCK_SIZE 0x04 -#define SDHC_BLOCK_COUNT 0x06 -#define SDHC_BLOCK_COUNT_MAX 512 -#define SDHC_ARGUMENT 0x08 -#define SDHC_TRANSFER_MODE 0x0c -#define SDHC_MULTI_BLOCK_MODE (1<<5) -#define SDHC_READ_MODE (1<<4) -#define SDHC_AUTO_CMD12_ENABLE (1<<2) -#define SDHC_BLOCK_COUNT_ENABLE (1<<1) -#define SDHC_DMA_ENABLE (1<<0) -#define SDHC_COMMAND 0x0e -/* 14-15 reserved */ -#define SDHC_COMMAND_INDEX_SHIFT 8 -#define SDHC_COMMAND_INDEX_MASK 0x3f -#define SDHC_COMMAND_TYPE_ABORT (3<<6) -#define SDHC_COMMAND_TYPE_RESUME (2<<6) -#define SDHC_COMMAND_TYPE_SUSPEND (1<<6) -#define SDHC_COMMAND_TYPE_NORMAL (0<<6) -#define SDHC_DATA_PRESENT_SELECT (1<<5) -#define SDHC_INDEX_CHECK_ENABLE (1<<4) -#define SDHC_CRC_CHECK_ENABLE (1<<3) -/* 2 reserved */ -#define SDHC_RESP_LEN_48_CHK_BUSY (3<<0) -#define SDHC_RESP_LEN_48 (2<<0) -#define SDHC_RESP_LEN_136 (1<<0) -#define SDHC_NO_RESPONSE (0<<0) -#define SDHC_RESPONSE 0x10 /* - 0x1f */ -#define SDHC_DATA 0x20 -#define SDHC_PRESENT_STATE 0x24 -/* 25-31 reserved */ -#define SDHC_CMD_LINE_SIGNAL_LEVEL (1<<24) -#define SDHC_DAT3_LINE_LEVEL (1<<23) -#define SDHC_DAT2_LINE_LEVEL (1<<22) -#define SDHC_DAT1_LINE_LEVEL (1<<21) -#define SDHC_DAT0_LINE_LEVEL (1<<20) -#define SDHC_WRITE_PROTECT_SWITCH (1<<19) -#define SDHC_CARD_DETECT_PIN_LEVEL (1<<18) -#define SDHC_CARD_STATE_STABLE (1<<17) -#define SDHC_CARD_INSERTED (1<<16) -/* 12-15 reserved */ -#define SDHC_BUFFER_READ_ENABLE (1<<11) -#define SDHC_BUFFER_WRITE_ENABLE (1<<10) -#define SDHC_READ_TRANSFER_ACTIVE (1<<9) -#define SDHC_WRITE_TRANSFER_ACTIVE (1<<8) -/* 3-7 reserved */ -#define SDHC_DAT_ACTIVE (1<<2) -#define SDHC_CMD_INHIBIT_DAT (1<<1) -#define SDHC_CMD_INHIBIT_CMD (1<<0) -#define SDHC_CMD_INHIBIT_MASK 0x0003 -#define SDHC_HOST_CTL 0x28 -#define SDHC_HIGH_SPEED (1<<2) -#define SDHC_ESDHC_8BIT_MODE (1<<2) /* eSDHC */ -#define SDHC_4BIT_MODE (1<<1) -#define SDHC_LED_ON (1<<0) -#define SDHC_POWER_CTL 0x29 -#define SDHC_VOLTAGE_SHIFT 1 -#define SDHC_VOLTAGE_MASK 0x07 -#define SDHC_VOLTAGE_3_3V 0x07 -#define SDHC_VOLTAGE_3_0V 0x06 -#define SDHC_VOLTAGE_1_8V 0x05 -#define SDHC_BUS_POWER (1<<0) -#define SDHC_BLOCK_GAP_CTL 0x2a -#define SDHC_WAKEUP_CTL 0x2b -#define SDHC_CLOCK_CTL 0x2c -#define SDHC_SDCLK_DIV_SHIFT 8 -#define SDHC_SDCLK_DIV_MASK 0xff -#define SDHC_SDCLK_XDIV_SHIFT 6 -#define SDHC_SDCLK_XDIV_MASK 0x3 -#define SDHC_SDCLK_CGM (1<<5) -#define SDHC_SDCLK_DVS_SHIFT 4 -#define SDHC_SDCLK_DVS_MASK 0xf -#define SDHC_SDCLK_ENABLE (1<<2) -#define SDHC_INTCLK_STABLE (1<<1) -#define SDHC_INTCLK_ENABLE (1<<0) -#define SDHC_TIMEOUT_CTL 0x2e -#define SDHC_TIMEOUT_MAX 0x0e -#define SDHC_SOFTWARE_RESET 0x2f -#define SDHC_INIT_ACTIVE (1<<3) -#define SDHC_RESET_MASK 0x5 -#define SDHC_RESET_DAT (1<<2) -#define SDHC_RESET_CMD (1<<1) -#define SDHC_RESET_ALL (1<<0) -#define SDHC_NINTR_STATUS 0x30 -#define SDHC_ERROR_INTERRUPT (1<<15) -#define SDHC_CARD_INTERRUPT (1<<8) -#define SDHC_CARD_REMOVAL (1<<7) -#define SDHC_CARD_INSERTION (1<<6) -#define SDHC_BUFFER_READ_READY (1<<5) -#define SDHC_BUFFER_WRITE_READY (1<<4) -#define SDHC_DMA_INTERRUPT (1<<3) -#define SDHC_BLOCK_GAP_EVENT (1<<2) -#define SDHC_TRANSFER_COMPLETE (1<<1) -#define SDHC_COMMAND_COMPLETE (1<<0) -#define SDHC_NINTR_STATUS_MASK 0x81ff -#define SDHC_EINTR_STATUS 0x32 -#define SDHC_DMA_ERROR (1<<12) -#define SDHC_AUTO_CMD12_ERROR (1<<8) -#define SDHC_CURRENT_LIMIT_ERROR (1<<7) -#define SDHC_DATA_END_BIT_ERROR (1<<6) -#define SDHC_DATA_CRC_ERROR (1<<5) -#define SDHC_DATA_TIMEOUT_ERROR (1<<4) -#define SDHC_CMD_INDEX_ERROR (1<<3) -#define SDHC_CMD_END_BIT_ERROR (1<<2) -#define SDHC_CMD_CRC_ERROR (1<<1) -#define SDHC_CMD_TIMEOUT_ERROR (1<<0) -#define SDHC_EINTR_STATUS_MASK 0x01ff /* excluding vendor signals */ -#define SDHC_NINTR_STATUS_EN 0x34 -#define SDHC_EINTR_STATUS_EN 0x36 -#define SDHC_NINTR_SIGNAL_EN 0x38 -#define SDHC_NINTR_SIGNAL_MASK 0x01ff -#define SDHC_EINTR_SIGNAL_EN 0x3a -#define SDHC_EINTR_SIGNAL_MASK 0x01ff /* excluding vendor signals */ -#define SDHC_CMD12_ERROR_STATUS 0x3c -#define SDHC_CAPABILITIES 0x40 -#define SDHC_VOLTAGE_SUPP_1_8V (1<<26) -#define SDHC_VOLTAGE_SUPP_3_0V (1<<25) -#define SDHC_VOLTAGE_SUPP_3_3V (1<<24) -#define SDHC_DMA_SUPPORT (1<<22) -#define SDHC_HIGH_SPEED_SUPP (1<<21) -#define SDHC_MAX_BLK_LEN_512 0 -#define SDHC_MAX_BLK_LEN_1024 1 -#define SDHC_MAX_BLK_LEN_2048 2 -#define SDHC_MAX_BLK_LEN_4096 3 -#define SDHC_MAX_BLK_LEN_SHIFT 16 -#define SDHC_MAX_BLK_LEN_MASK 0x3 -#define SDHC_BASE_FREQ_SHIFT 8 -#define SDHC_BASE_FREQ_MASK 0x3f -#define SDHC_TIMEOUT_FREQ_UNIT (1<<7) /* 0=KHz, 1=MHz */ -#define SDHC_TIMEOUT_FREQ_SHIFT 0 -#define SDHC_TIMEOUT_FREQ_MASK 0x1f -#define SDHC_MAX_CAPABILITIES 0x48 -#define SDHC_HOST_VER 0xFC -#define SDHC_VVN_MASK 0x0f -#define SDHC_VVN_SHIFT 0x04 -#define SDHC_SVN_MASK 0x0f -#define SDHC_SVN_SHIFT 0x00 -#define SDHC_SLOT_INTR_STATUS 0xfc -#define SDHC_HOST_CTL_VERSION 0xfe -#define SDHC_SPEC_VERS_SHIFT 0 -#define SDHC_SPEC_VERS_MASK 0xff -#define SDHC_VENDOR_VERS_SHIFT 8 -#define SDHC_VENDOR_VERS_MASK 0xff -#define SDHC_DMA_CTL 0x40c /* eSDHC */ -#define SDHC_DMA_SNOOP 0x40 - -/* SDHC_SPEC_VERS */ -#define SDHC_SPEC_VERS_100 0x00 -#define SDHC_SPEC_VERS_200 0x01 -#define SDHC_SPEC_VERS_300 0x02 - -/* SDHC_CAPABILITIES decoding */ -#define SDHC_BASE_FREQ_KHZ(cap) \ - ((((cap) >> SDHC_BASE_FREQ_SHIFT) & SDHC_BASE_FREQ_MASK) * 1000) -#define SDHC_TIMEOUT_FREQ(cap) \ - (((cap) >> SDHC_TIMEOUT_FREQ_SHIFT) & SDHC_TIMEOUT_FREQ_MASK) -#define SDHC_TIMEOUT_FREQ_KHZ(cap) \ - (((cap) & SDHC_TIMEOUT_FREQ_UNIT) ? \ - SDHC_TIMEOUT_FREQ(cap) * 1000: \ - SDHC_TIMEOUT_FREQ(cap)) - -/* SDHC_HOST_CTL_VERSION decoding */ -#define SDHC_SPEC_VERSION(hcv) \ - (((hcv) >> SDHC_SPEC_VERS_SHIFT) & SDHC_SPEC_VERS_MASK) -#define SDHC_VENDOR_VERSION(hcv) \ - (((hcv) >> SDHC_VENDOR_VERS_SHIFT) & SDHC_VENDOR_VERS_MASK) - -#define SDHC_PRESENT_STATE_BITS \ - "\20\31CL\30D3L\27D2L\26D1L\25D0L\24WPS\23CD\22CSS\21CI" \ - "\14BRE\13BWE\12RTA\11WTA\3DLA\2CID\1CIC" -#define SDHC_NINTR_STATUS_BITS \ - "\20\20ERROR\11CARD\10REMOVAL\7INSERTION\6READ\5WRITE" \ - "\4DMA\3GAP\2XFER\1CMD" -#define SDHC_EINTR_STATUS_BITS \ - "\20\11ACMD12\10CL\7DEB\6DCRC\5DT\4CI\3CEB\2CCRC\1CT" -#define SDHC_CAPABILITIES_BITS \ - "\20\33Vdd1.8V\32Vdd3.0V\31Vdd3.3V\30SUSPEND\27DMA\26HIGHSPEED" - -#endif /* _SDHCREG_H_ */ diff --git a/minix/drivers/storage/mmc/sdmmcreg.h b/minix/drivers/storage/mmc/sdmmcreg.h deleted file mode 100644 index d9f3e1c91..000000000 --- a/minix/drivers/storage/mmc/sdmmcreg.h +++ /dev/null @@ -1,355 +0,0 @@ -/* $NetBSD: sdmmcreg.h,v 1.8 2012/01/27 03:07:21 matt Exp $ */ -/* $OpenBSD: sdmmcreg.h,v 1.4 2009/01/09 10:55:22 jsg Exp $ */ - -/* - * Copyright (c) 2006 Uwe Stuehler - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _SDMMCREG_H_ -#define _SDMMCREG_H_ - -/* MMC commands */ /* response type */ -#define MMC_GO_IDLE_STATE 0 /* R0 */ -#define MMC_SEND_OP_COND 1 /* R3 */ -#define MMC_ALL_SEND_CID 2 /* R2 */ -#define MMC_SET_RELATIVE_ADDR 3 /* R1 */ -#define MMC_SWITCH 6 /* R1b */ -#define MMC_SELECT_CARD 7 /* R1 */ -#define MMC_SEND_EXT_CSD 8 /* R1 */ -#define MMC_SEND_CSD 9 /* R2 */ -#define MMC_SEND_CID 10 /* R2 */ -#define MMC_STOP_TRANSMISSION 12 /* R1b */ -#define MMC_SEND_STATUS 13 /* R1 */ -#define MMC_INACTIVE_STATE 15 /* R0 */ -#define MMC_SET_BLOCKLEN 16 /* R1 */ -#define MMC_READ_BLOCK_SINGLE 17 /* R1 */ -#define MMC_READ_BLOCK_MULTIPLE 18 /* R1 */ -#define MMC_SET_BLOCK_COUNT 23 /* R1 */ -#define MMC_WRITE_BLOCK_SINGLE 24 /* R1 */ -#define MMC_WRITE_BLOCK_MULTIPLE 25 /* R1 */ -#define MMC_PROGRAM_CSD 27 /* R1 */ -#define MMC_SET_WRITE_PROT 28 /* R1b */ -#define MMC_SET_CLR_WRITE_PROT 29 /* R1b */ -#define MMC_SET_SEND_WRITE_PROT 30 /* R1 */ -#define MMC_TAG_SECTOR_START 32 /* R1 */ -#define MMC_TAG_SECTOR_END 33 /* R1 */ -#define MMC_UNTAG_SECTOR 34 /* R1 */ -#define MMC_TAG_ERASE_GROUP_START 35 /* R1 */ -#define MMC_TAG_ERASE_GROUP_END 36 /* R1 */ -#define MMC_UNTAG_ERASE_GROUP 37 /* R1 */ -#define MMC_ERASE 38 /* R1b */ -#define MMC_LOCK_UNLOCK 42 /* R1b */ -#define MMC_APP_CMD 55 /* R1 */ -#define MMC_READ_OCR 58 /* R3 */ - -/* SD commands */ /* response type */ -#define SD_SEND_RELATIVE_ADDR 3 /* R6 */ -#define SD_SEND_SWITCH_FUNC 6 /* R1 */ -#define SD_SEND_IF_COND 8 /* R7 */ - -/* SD application commands */ /* response type */ -#define SD_APP_SET_BUS_WIDTH 6 /* R1 */ -#define SD_APP_OP_COND 41 /* R3 */ -#define SD_APP_SEND_SCR 51 /* R1 */ - -/* OCR bits */ -#define MMC_OCR_MEM_READY (1U<<31)/* memory power-up status bit */ -#define MMC_OCR_HCS (1<<30) -#define MMC_OCR_3_5V_3_6V (1<<23) -#define MMC_OCR_3_4V_3_5V (1<<22) -#define MMC_OCR_3_3V_3_4V (1<<21) -#define MMC_OCR_3_2V_3_3V (1<<20) -#define MMC_OCR_3_1V_3_2V (1<<19) -#define MMC_OCR_3_0V_3_1V (1<<18) -#define MMC_OCR_2_9V_3_0V (1<<17) -#define MMC_OCR_2_8V_2_9V (1<<16) -#define MMC_OCR_2_7V_2_8V (1<<15) -#define MMC_OCR_2_6V_2_7V (1<<14) -#define MMC_OCR_2_5V_2_6V (1<<13) -#define MMC_OCR_2_4V_2_5V (1<<12) -#define MMC_OCR_2_3V_2_4V (1<<11) -#define MMC_OCR_2_2V_2_3V (1<<10) -#define MMC_OCR_2_1V_2_2V (1<<9) -#define MMC_OCR_2_0V_2_1V (1<<8) -#define MMC_OCR_1_9V_2_0V (1<<7) -#define MMC_OCR_1_8V_1_9V (1<<6) -#define MMC_OCR_1_7V_1_8V (1<<5) -#define MMC_OCR_1_6V_1_7V (1<<4) - -/* R1 response type bits */ -#define MMC_R1_READY_FOR_DATA (1<<8) /* ready for next transfer */ -#define MMC_R1_APP_CMD (1<<5) /* app. commands supported */ - -/* 48-bit response decoding (32 bits w/o CRC) */ -#define MMC_R1(resp) ((resp)[0]) -#define MMC_R3(resp) ((resp)[0]) -#define SD_R6(resp) ((resp)[0]) -#define MMC_R7(resp) ((resp)[0]) -#define MMC_SPI_R1(resp) ((resp)[0]) -#define MMC_SPI_R7(resp) ((resp)[1]) - -/* RCA argument and response */ -#define MMC_ARG_RCA(rca) ((rca) << 16) -#define SD_R6_RCA(resp) (SD_R6((resp)) >> 16) - -/* bus width argument */ -#define SD_ARG_BUS_WIDTH_1 0 -#define SD_ARG_BUS_WIDTH_4 2 - -/* EXT_CSD fields */ -#define EXT_CSD_BUS_WIDTH 183 /* WO */ -#define EXT_CSD_HS_TIMING 185 /* R/W */ -#define EXT_CSD_REV 192 /* RO */ -#define EXT_CSD_STRUCTURE 194 /* RO */ -#define EXT_CSD_CARD_TYPE 196 /* RO */ - -/* EXT_CSD field definitions */ -#define EXT_CSD_CMD_SET_NORMAL (1U << 0) -#define EXT_CSD_CMD_SET_SECURE (1U << 1) -#define EXT_CSD_CMD_SET_CPSECURE (1U << 2) - -/* EXT_CSD_BUS_WIDTH */ -#define EXT_CSD_BUS_WIDTH_1 0 /* 1 bit mode */ -#define EXT_CSD_BUS_WIDTH_4 1 /* 4 bit mode */ -#define EXT_CSD_BUS_WIDTH_8 2 /* 8 bit mode */ - -/* EXT_CSD_STRUCTURE */ -#define EXT_CSD_STRUCTURE_VER_1_0 0 /* CSD Version No.1.0 */ -#define EXT_CSD_STRUCTURE_VER_1_1 1 /* CSD Version No.1.1 */ -#define EXT_CSD_STRUCTURE_VER_1_2 2 /* Version 4.1-4.2-4.3 */ - -/* EXT_CSD_CARD_TYPE */ -#define EXT_CSD_CARD_TYPE_26M (1 << 0) -#define EXT_CSD_CARD_TYPE_52M (1 << 1) - -/* MMC_SWITCH access mode */ -#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */ -#define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits in value */ -#define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits in value */ -#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ - -/* SPI mode reports R1/R2(SEND_STATUS) status. */ -#define R1_SPI_IDLE (1 << 0) -#define R1_SPI_ERASE_RESET (1 << 1) -#define R1_SPI_ILLEGAL_COMMAND (1 << 2) -#define R1_SPI_COM_CRC (1 << 3) -#define R1_SPI_ERASE_SEQ (1 << 4) -#define R1_SPI_ADDRESS (1 << 5) -#define R1_SPI_PARAMETER (1 << 6) -/* R1 bit 7 is always zero */ -#define R2_SPI_CARD_LOCKED (1 << 8) -#define R2_SPI_WP_ERASE_SKIP (1 << 9) /* or lock/unlock fail */ -#define R2_SPI_LOCK_UNLOCK_FAIL R2_SPI_WP_ERASE_SKIP -#define R2_SPI_ERROR (1 << 10) -#define R2_SPI_CC_ERROR (1 << 11) -#define R2_SPI_CARD_ECC_ERROR (1 << 12) -#define R2_SPI_WP_VIOLATION (1 << 13) -#define R2_SPI_ERASE_PARAM (1 << 14) -#define R2_SPI_OUT_OF_RANGE (1 << 15) /* or CSD overwrite */ -#define R2_SPI_CSD_OVERWRITE R2_SPI_OUT_OF_RANGE - -/* MMC R2 response (CSD) */ -#define MMC_CSD_CSDVER(resp) MMC_RSP_BITS((resp), 126, 2) -#define MMC_CSD_CSDVER_1_0 0 -#define MMC_CSD_CSDVER_1_1 1 -#define MMC_CSD_CSDVER_1_2 2 /* MMC 4.1 - 4.2 - 4.3 */ -#define MMC_CSD_CSDVER_EXT_CSD 3 /* Version is coded in CSD_STRUCTURE in EXT_CSD */ -#define MMC_CSD_MMCVER(resp) MMC_RSP_BITS((resp), 122, 4) -#define MMC_CSD_MMCVER_1_0 0 /* MMC 1.0 - 1.2 */ -#define MMC_CSD_MMCVER_1_4 1 /* MMC 1.4 */ -#define MMC_CSD_MMCVER_2_0 2 /* MMC 2.0 - 2.2 */ -#define MMC_CSD_MMCVER_3_1 3 /* MMC 3.1 - 3.3 */ -#define MMC_CSD_MMCVER_4_0 4 /* MMC 4.1 - 4.2 - 4.3 */ -#define MMC_CSD_TAAC(resp) MMC_RSP_BITS((resp), 112, 8) -#define MMC_CSD_TAAC_MANT(resp) MMC_RSP_BITS((resp), 115, 4) -#define MMC_CSD_TAAC_EXP(resp) MMC_RSP_BITS((resp), 112, 3) -#define MMC_CSD_NSAC(resp) MMC_RSP_BITS((resp), 104, 8) -#define MMC_CSD_TRAN_SPEED(resp) MMC_RSP_BITS((resp), 96, 8) -#define MMC_CSD_TRAN_SPEED_MANT(resp) MMC_RSP_BITS((resp), 99, 4) -#define MMC_CSD_TRAN_SPEED_EXP(resp) MMC_RSP_BITS((resp), 96, 3) -#define MMC_CSD_READ_BL_LEN(resp) MMC_RSP_BITS((resp), 80, 4) -#define MMC_CSD_C_SIZE(resp) MMC_RSP_BITS((resp), 62, 12) -#define MMC_CSD_CAPACITY(resp) ((MMC_CSD_C_SIZE((resp))+1) << \ - (MMC_CSD_C_SIZE_MULT((resp))+2)) -#define MMC_CSD_C_SIZE_MULT(resp) MMC_RSP_BITS((resp), 47, 3) -#define MMC_CSD_R2W_FACTOR(resp) MMC_RSP_BITS((resp), 26, 3) -#define MMC_CSD_WRITE_BL_LEN(resp) MMC_RSP_BITS((resp), 22, 4) - -/* MMC v1 R2 response (CID) */ -#define MMC_CID_MID_V1(resp) MMC_RSP_BITS((resp), 104, 24) -#define MMC_CID_PNM_V1_CPY(resp, pnm) \ - do { \ - (pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \ - (pnm)[1] = MMC_RSP_BITS((resp), 88, 8); \ - (pnm)[2] = MMC_RSP_BITS((resp), 80, 8); \ - (pnm)[3] = MMC_RSP_BITS((resp), 72, 8); \ - (pnm)[4] = MMC_RSP_BITS((resp), 64, 8); \ - (pnm)[5] = MMC_RSP_BITS((resp), 56, 8); \ - (pnm)[6] = MMC_RSP_BITS((resp), 48, 8); \ - (pnm)[7] = '\0'; \ - } while (/*CONSTCOND*/0) -#define MMC_CID_REV_V1(resp) MMC_RSP_BITS((resp), 40, 8) -#define MMC_CID_PSN_V1(resp) MMC_RSP_BITS((resp), 16, 24) -#define MMC_CID_MDT_V1(resp) MMC_RSP_BITS((resp), 8, 8) - -/* MMC v2 R2 response (CID) */ -#define MMC_CID_MID_V2(resp) MMC_RSP_BITS((resp), 120, 8) -#define MMC_CID_OID_V2(resp) MMC_RSP_BITS((resp), 104, 16) -#define MMC_CID_PNM_V2_CPY(resp, pnm) \ - do { \ - (pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \ - (pnm)[1] = MMC_RSP_BITS((resp), 88, 8); \ - (pnm)[2] = MMC_RSP_BITS((resp), 80, 8); \ - (pnm)[3] = MMC_RSP_BITS((resp), 72, 8); \ - (pnm)[4] = MMC_RSP_BITS((resp), 64, 8); \ - (pnm)[5] = MMC_RSP_BITS((resp), 56, 8); \ - (pnm)[6] = '\0'; \ - } while (/*CONSTCOND*/0) -#define MMC_CID_PSN_V2(resp) MMC_RSP_BITS((resp), 16, 32) - -/* SD R2 response (CSD) */ -#define SD_CSD_CSDVER(resp) MMC_RSP_BITS((resp), 126, 2) -#define SD_CSD_CSDVER_1_0 0 -#define SD_CSD_CSDVER_2_0 1 -#define SD_CSD_MMCVER(resp) MMC_RSP_BITS((resp), 122, 4) -#define SD_CSD_TAAC(resp) MMC_RSP_BITS((resp), 112, 8) -#define SD_CSD_TAAC_EXP(resp) MMC_RSP_BITS((resp), 115, 4) -#define SD_CSD_TAAC_MANT(resp) MMC_RSP_BITS((resp), 112, 3) -#define SD_CSD_TAAC_1_5_MSEC 0x26 -#define SD_CSD_NSAC(resp) MMC_RSP_BITS((resp), 104, 8) -#define SD_CSD_SPEED(resp) MMC_RSP_BITS((resp), 96, 8) -#define SD_CSD_SPEED_MANT(resp) MMC_RSP_BITS((resp), 99, 4) -#define SD_CSD_SPEED_EXP(resp) MMC_RSP_BITS((resp), 96, 3) -#define SD_CSD_SPEED_25_MHZ 0x32 -#define SD_CSD_SPEED_50_MHZ 0x5a -#define SD_CSD_CCC(resp) MMC_RSP_BITS((resp), 84, 12) -#define SD_CSD_CCC_BASIC (1 << 0) /* basic */ -#define SD_CSD_CCC_BR (1 << 2) /* block read */ -#define SD_CSD_CCC_BW (1 << 4) /* block write */ -#define SD_CSD_CCC_ERACE (1 << 5) /* erase */ -#define SD_CSD_CCC_WP (1 << 6) /* write protection */ -#define SD_CSD_CCC_LC (1 << 7) /* lock card */ -#define SD_CSD_CCC_AS (1 << 8) /*application specific*/ -#define SD_CSD_CCC_IOM (1 << 9) /* I/O mode */ -#define SD_CSD_CCC_SWITCH (1 << 10) /* switch */ -#define SD_CSD_READ_BL_LEN(resp) MMC_RSP_BITS((resp), 80, 4) -#define SD_CSD_READ_BL_PARTIAL(resp) MMC_RSP_BITS((resp), 79, 1) -#define SD_CSD_WRITE_BLK_MISALIGN(resp) MMC_RSP_BITS((resp), 78, 1) -#define SD_CSD_READ_BLK_MISALIGN(resp) MMC_RSP_BITS((resp), 77, 1) -#define SD_CSD_DSR_IMP(resp) MMC_RSP_BITS((resp), 76, 1) -#define SD_CSD_C_SIZE(resp) MMC_RSP_BITS((resp), 62, 12) -#define SD_CSD_CAPACITY(resp) ((SD_CSD_C_SIZE((resp))+1) << \ - (SD_CSD_C_SIZE_MULT((resp))+2)) -#define SD_CSD_VDD_R_CURR_MIN(resp) MMC_RSP_BITS((resp), 59, 3) -#define SD_CSD_VDD_R_CURR_MAX(resp) MMC_RSP_BITS((resp), 56, 3) -#define SD_CSD_VDD_W_CURR_MIN(resp) MMC_RSP_BITS((resp), 53, 3) -#define SD_CSD_VDD_W_CURR_MAX(resp) MMC_RSP_BITS((resp), 50, 3) -#define SD_CSD_VDD_RW_CURR_100mA 0x7 -#define SD_CSD_VDD_RW_CURR_80mA 0x6 -#define SD_CSD_V2_C_SIZE(resp) MMC_RSP_BITS((resp), 48, 22) -#define SD_CSD_V2_CAPACITY(resp) ((SD_CSD_V2_C_SIZE((resp))+1) << 10) -#define SD_CSD_V2_BL_LEN 0x9 /* 512 */ -#define SD_CSD_C_SIZE_MULT(resp) MMC_RSP_BITS((resp), 47, 3) -#define SD_CSD_ERASE_BLK_EN(resp) MMC_RSP_BITS((resp), 46, 1) -#define SD_CSD_SECTOR_SIZE(resp) MMC_RSP_BITS((resp), 39, 7) /* +1 */ -#define SD_CSD_WP_GRP_SIZE(resp) MMC_RSP_BITS((resp), 32, 7) /* +1 */ -#define SD_CSD_WP_GRP_ENABLE(resp) MMC_RSP_BITS((resp), 31, 1) -#define SD_CSD_R2W_FACTOR(resp) MMC_RSP_BITS((resp), 26, 3) -#define SD_CSD_WRITE_BL_LEN(resp) MMC_RSP_BITS((resp), 22, 4) -#define SD_CSD_RW_BL_LEN_2G 0xa -#define SD_CSD_RW_BL_LEN_1G 0x9 -#define SD_CSD_WRITE_BL_PARTIAL(resp) MMC_RSP_BITS((resp), 21, 1) -#define SD_CSD_FILE_FORMAT_GRP(resp) MMC_RSP_BITS((resp), 15, 1) -#define SD_CSD_COPY(resp) MMC_RSP_BITS((resp), 14, 1) -#define SD_CSD_PERM_WRITE_PROTECT(resp) MMC_RSP_BITS((resp), 13, 1) -#define SD_CSD_TMP_WRITE_PROTECT(resp) MMC_RSP_BITS((resp), 12, 1) -#define SD_CSD_FILE_FORMAT(resp) MMC_RSP_BITS((resp), 10, 2) - -/* SD R2 response (CID) */ -#define SD_CID_MID(resp) MMC_RSP_BITS((resp), 120, 8) -#define SD_CID_OID(resp) MMC_RSP_BITS((resp), 104, 16) -#define SD_CID_PNM_CPY(resp, pnm) \ - do { \ - (pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \ - (pnm)[1] = MMC_RSP_BITS((resp), 88, 8); \ - (pnm)[2] = MMC_RSP_BITS((resp), 80, 8); \ - (pnm)[3] = MMC_RSP_BITS((resp), 72, 8); \ - (pnm)[4] = MMC_RSP_BITS((resp), 64, 8); \ - (pnm)[5] = '\0'; \ - } while (/*CONSTCOND*/0) -#define SD_CID_REV(resp) MMC_RSP_BITS((resp), 56, 8) -#define SD_CID_PSN(resp) MMC_RSP_BITS((resp), 24, 32) -#define SD_CID_MDT(resp) MMC_RSP_BITS((resp), 8, 12) - -/* SCR (SD Configuration Register) */ -#define SCR_STRUCTURE(scr) MMC_RSP_BITS((scr), 60, 4) -#define SCR_STRUCTURE_VER_1_0 0 /* Version 1.0 */ -#define SCR_SD_SPEC(scr) MMC_RSP_BITS((scr), 56, 4) -#define SCR_SD_SPEC_VER_1_0 0 /* Version 1.0 and 1.01 */ -#define SCR_SD_SPEC_VER_1_10 1 /* Version 1.10 */ -#define SCR_SD_SPEC_VER_2 2 /* Version 2.00 or Version 3.0X */ -#define SCR_DATA_STAT_AFTER_ERASE(scr) MMC_RSP_BITS((scr), 55, 1) -#define SCR_SD_SECURITY(scr) MMC_RSP_BITS((scr), 52, 3) -#define SCR_SD_SECURITY_NONE 0 /* no security */ -#define SCR_SD_SECURITY_1_0 1 /* security protocol 1.0 */ -#define SCR_SD_SECURITY_1_0_2 2 /* security protocol 1.0 */ -#define SCR_SD_BUS_WIDTHS(scr) MMC_RSP_BITS((scr), 48, 4) -#define SCR_SD_BUS_WIDTHS_1BIT (1 << 0) /* 1bit (DAT0) */ -#define SCR_SD_BUS_WIDTHS_4BIT (1 << 2) /* 4bit (DAT0-3) */ -#define SCR_RESERVED(scr) MMC_RSP_BITS((scr), 32, 16) -#define SCR_RESERVED2(scr) MMC_RSP_BITS((scr), 0, 32) - -/* Status of Switch Function */ -#define SFUNC_STATUS_GROUP(status, group) \ - be16toh(__bitfield((uint32_t *)(status), (7 - (group)) << 4, 16)) - -/* Might be slow, but it should work on big and little endian systems. */ - - -/* The macro used to do a (start)-8 to work around a bug in hardware see sdhc.c - * of the openbsd mmc code driver. - */ -#define MMC_RSP_BITS(resp, start, len) __bitfield((resp), (start), (len)) -static inline int -__bitfield(uint32_t *src, int start, int len) -{ - uint8_t *sp; - uint32_t dst, mask; - int shift, bs, bc; - - if (start < 0 || len < 0 || len > 32) - return 0; - - dst = 0; - mask = len % 32 ? UINT_MAX >> (32 - (len % 32)) : UINT_MAX; - shift = 0; - - while (len > 0) { - sp = (uint8_t *)src + start / 8; - bs = start % 8; - bc = 8 - bs; - if (bc > len) - bc = len; - dst |= (*sp >> bs) << shift; - shift += bc; - start += bc; - len -= bc; - } - - dst &= mask; - return (int)dst; -} - -#endif /* _SDMMCREG_H_ */ diff --git a/minix/drivers/storage/ramdisk/Makefile b/minix/drivers/storage/ramdisk/Makefile index a51e6298a..03dc26d24 100644 --- a/minix/drivers/storage/ramdisk/Makefile +++ b/minix/drivers/storage/ramdisk/Makefile @@ -28,27 +28,29 @@ PROTO= proto # Common to all architectures ETC= system.conf group EXTRA= rc -PROTO_FILES= proto.common.etc -PROTO_FILES+= proto.common.dynamic +PROTO_FILES= proto.common.etc +PROTO_FILES+= proto.common.dynamic PROGRAMS= # defined PROGRAMS+= fsck_mfs dir.fsck_mfs:= minix/commands/fsck.mfs PROGRAMS+= grep -dir.grep:= minix/usr.bin/grep +dir.grep:= minix/usr.bin/grep +PROGRAMS+= dd +dir.dd:= bin/dd PROGRAMS+= input -dir.input:= minix/servers/input +dir.input:= minix/servers/input PROGRAMS+= loadramdisk dir.loadramdisk:= minix/commands/loadramdisk PROGRAMS+= mfs -dir.mfs:= minix/fs/mfs +dir.mfs:= minix/fs/mfs PROGRAMS+= mount -dir.mount:= minix/commands/mount +dir.mount:= minix/commands/mount PROGRAMS+= procfs dir.procfs:= minix/fs/procfs PROGRAMS+= service dir.service:= minix/commands/service PROGRAMS+= sh -dir.sh:= bin/sh +dir.sh:= bin/sh PROGRAMS+= sysenv dir.sysenv:= minix/commands/sysenv PROGRAMS+= umount @@ -65,9 +67,9 @@ dir.at_wini:= minix/drivers/storage/at_wini PROGRAMS+= floppy dir.floppy:= minix/drivers/storage/floppy PROGRAMS+= pci -dir.pci:= minix/drivers/bus/pci +dir.pci:= minix/drivers/bus/pci PROGRAMS+= pckbd -dir.pckbd:= minix/drivers/hid/pckbd +dir.pckbd:= minix/drivers/hid/pckbd PROGRAMS+= cdprobe dir.cdprobe:= minix/commands/cdprobe PROGRAMS+= pwd_mkdb @@ -77,23 +79,25 @@ dir.isofs:= minix/fs/isofs .if ${MKSMALL} != "yes" PROGRAMS+= ahci -dir.ahci:= minix/drivers/storage/ahci +dir.ahci:= minix/drivers/storage/ahci PROGRAMS+= virtio_blk dir.virtio_blk:= minix/drivers/storage/virtio_blk PROGRAMS+= ext2 -dir.ext2:= minix/fs/ext2 +dir.ext2:= minix/fs/ext2 .endif .if ${MKACPI} != "no" RAMDISK_INC_ACPI= 1 PROGRAMS+= acpi -dir.acpi:= minix/drivers/power/acpi +dir.acpi:= minix/drivers/power/acpi .endif .endif # ${MACHINE_ARCH} == "i386" .if ${MACHINE_ARCH} == "earm" -PROGRAMS+= mmc -dir.mmc:= minix/drivers/storage/mmc +PROGRAMS+= rpi_mmc +dir.rpi_mmc:= minix/drivers/storage/mmc/rpi +PROGRAMS+= omap_mmc +dir.omap_mmc:= minix/drivers/storage/mmc/omap .endif # ${MACHINE_ARCH} == "earm" .if ${LDSTATIC} == "-dynamic" diff --git a/minix/drivers/storage/ramdisk/proto b/minix/drivers/storage/ramdisk/proto index 84e946d36..5a6ef92e9 100644 --- a/minix/drivers/storage/ramdisk/proto +++ b/minix/drivers/storage/ramdisk/proto @@ -12,6 +12,7 @@ d--755 0 0 mount ---755 0 0 mount umount ---755 0 0 umount grep ---755 0 0 grep + dd ---755 0 0 dd sh ---755 0 0 sh service ---755 0 0 service $ @@ -28,7 +29,8 @@ d--755 0 0 isofs ---755 0 0 isofs #endif #ifdef __arm__ - mmc ---755 0 0 mmc + rpi_mmc ---755 0 0 rpi_mmc + omap_mmc ---755 0 0 omap_mmc #endif mfs ---755 0 0 mfs procfs ---755 0 0 procfs diff --git a/minix/drivers/storage/ramdisk/rc b/minix/drivers/storage/ramdisk/rc index 47bd3ea1f..a4c28e91e 100644 --- a/minix/drivers/storage/ramdisk/rc +++ b/minix/drivers/storage/ramdisk/rc @@ -53,7 +53,7 @@ fi if [ X`/bin/sysenv arch` = Xearm ] then echo Starting the mmc driver - /bin/service -c up /service/mmc -dev /dev/c0d0 + /bin/service -c up /service/rpi_mmc -dev /dev/c0d0 fi /bin/service up /service/procfs || echo "WARNING: couldn't start procfs"