[MINOR] SD card init success

It's almost stable version. DO NOT USE IT!
This commit is contained in:
Korobov Nikita
2017-07-05 05:53:50 +03:00
parent 03eaf9dac8
commit 65def63cad
10 changed files with 1709 additions and 291 deletions

View File

@@ -227,14 +227,14 @@ service mib
service init
{
uid 0;
ipc # ipc targets allowed:
ipc # ipc targets allowed:
pm vfs rs vm
;
system NONE; # No kernel calls allowed
system NONE; # No kernel calls allowed
vm BASIC; # Only basic VM calls allowed
io NONE; # No I/O range allowed
irq NONE; # No IRQs allowed
sigmgr pm; # Signal manager is PM
sigmgr pm; # Signal manager is PM
};
#
@@ -327,9 +327,9 @@ service virtio_blk
service at_wini
{
io 1f0:8 # Controller 0
3f6 # Also controller 0
3f6 # Also controller 0
170:8 # Controller 1
376 # Also controller 1
376 # Also controller 1
;
irq
14 # Controller 0
@@ -434,13 +434,13 @@ service omap_mmc
{
system
PRIVCTL # 4
IRQCTL # 19
IRQCTL # 19
;
# Interrupts allowed
irq
64
83
; # IRQs allowed
; # IRQs allowed
priority 4; # priority queue 4
};
@@ -448,12 +448,12 @@ service rpi_mmc
{
system
PRIVCTL # 4
IRQCTL # 19
IRQCTL # 19
;
# Interrupts allowed
irq
24
; # IRQs allowed
126
; # IRQs allowed
priority 4; # priority queue 4
};
@@ -461,7 +461,7 @@ service fb
{
system
UMAP # 14
DEVIO # 21
DEVIO # 21
PRIVCTL # 4
;
ipc
@@ -520,7 +520,7 @@ service uds
service pty
{
system
KILL # 06
KILL # 06
;
ipc
SYSTEM vfs rs vm
@@ -547,7 +547,7 @@ service rpi_emmc
PADCONF
;
irq
28 # MMCSD1INT
52 # MMCSD1INT
;
};

View File

@@ -0,0 +1,4 @@
HERE=${.CURDIR}/..
.PATH: ${HERE}
MMC_SRCS= mmcblk.c mmchost_dummy.c sdhcreg.h sdmmcreg.h

View File

@@ -0,0 +1,663 @@
/*
* Block driver for Multi Media Cards (MMC).
*/
/* kernel headers */
#include <minix/syslib.h>
#include <minix/driver.h>
#include <minix/blockdriver.h>
#include <minix/drvlib.h>
#include <minix/log.h>
#include <minix/minlib.h>
/* system headers */
#include <sys/ioc_disk.h> /* disk IOCTL's */
/* usr headers */
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <signal.h>
/* 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;
}

View File

@@ -0,0 +1,156 @@
#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);

View File

@@ -0,0 +1,170 @@
/* kernel headers */
#include <minix/blockdriver.h>
#include <minix/minlib.h>
#include <minix/log.h>
/* usr headers */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>
#include <unistd.h>
/* 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]);
}

View File

@@ -59,8 +59,8 @@
/* 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
/* BCM2835 MMC1 interrupt number. */
#define BCM2835_MMCSD1INT 52
static uint32_t bus_width;
@@ -239,19 +239,22 @@ send_cmd(uint32_t arg, uint32_t cmd)
write32(reg->arg1, arg);
write32(reg->cmdtm, cmd);
/* Wait for the command completion. */
if (irq_wait() < 0)
if (irq_wait() < 0) {
log_warn (&log, "can't wait irq\n");
return -1;
stat = read32(reg->irpt_mask);
}
stat = read32(reg->irpt);
/*
* 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
write32(reg->irpt, 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) {
log_warn(&log, "timeout error\n");
reset_mmchs_fsm(MMCHS_SD_SYSCTL_SRC);
return -1;
}
@@ -277,7 +280,7 @@ send_cmd_check_r1(uint32_t arg, uint32_t cmd)
static int
go_idle_state(void)
{
return send_cmd(0, MMCHS_SD_CMD_INDX_CMD(GO_IDLE_STATE));
return send_cmd(0, MMCHS_SD_CMD_INDX_CMD(MMC_GO_IDLE_STATE));
}
/* Send CMD1 (SEND_OP_COND) command to the card. */
@@ -298,7 +301,7 @@ all_send_cid(void)
{
uint32_t cmd;
cmd = MMCHS_SD_CMD_INDX_CMD(ALL_SEND_CID)
cmd = MMCHS_SD_CMD_INDX_CMD(MMC_ALL_SEND_CID)
| MMCHS_SD_CMD_CCCE_ENABLE
| MMCHS_SD_CMD_RSP_TYPE_136B;
return send_cmd(0, cmd);
@@ -310,7 +313,7 @@ set_relative_addr(void)
{
uint32_t cmd;
cmd = MMCHS_SD_CMD_INDX_CMD(SEND_RELATIVE_ADDR)
cmd = MMCHS_SD_CMD_INDX_CMD(MMC_SET_RELATIVE_ADDR)
| MMCHS_SD_CMD_CICE_ENABLE
| MMCHS_SD_CMD_CCCE_ENABLE
| MMCHS_SD_CMD_RSP_TYPE_48B;
@@ -325,7 +328,7 @@ mmc_switch(uint32_t access, uint32_t index, uint32_t value)
/* 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)
cmd = MMCHS_SD_CMD_INDX_CMD(MMC_SWITCH)
| MMCHS_SD_CMD_CICE_ENABLE
| MMCHS_SD_CMD_CCCE_ENABLE
| MMCHS_SD_CMD_RSP_TYPE_48B_BUSY;
@@ -338,7 +341,7 @@ select_card(void)
{
uint32_t cmd;
cmd = MMCHS_SD_CMD_INDX_CMD(SELECT_CARD)
cmd = MMCHS_SD_CMD_INDX_CMD(MMC_SELECT_CARD)
| MMCHS_SD_CMD_CICE_ENABLE
| MMCHS_SD_CMD_CCCE_ENABLE
| MMCHS_SD_CMD_RSP_TYPE_48B;
@@ -351,7 +354,7 @@ send_csd(void)
{
uint32_t cmd;
cmd = MMCHS_SD_CMD_INDX_CMD(SEND_CSD)
cmd = MMCHS_SD_CMD_INDX_CMD(MMC_SEND_CSD)
| MMCHS_SD_CMD_CCCE_ENABLE
| MMCHS_SD_CMD_RSP_TYPE_136B;
return send_cmd(MMC_ARG_RCA(RCA), cmd);
@@ -363,7 +366,7 @@ send_status(void)
{
uint32_t cmd;
cmd = MMCHS_SD_CMD_INDX_CMD(SEND_STATUS)
cmd = MMCHS_SD_CMD_INDX_CMD(MMC_SEND_STATUS)
| MMCHS_SD_CMD_CICE_ENABLE
| MMCHS_SD_CMD_CCCE_ENABLE
| MMCHS_SD_CMD_RSP_TYPE_48B;
@@ -377,7 +380,7 @@ set_blocklen(void)
uint32_t cmd;
/* Set block length to sector size (512B). */
cmd = MMCHS_SD_CMD_INDX_CMD(SET_BLOCKLEN)
cmd = MMCHS_SD_CMD_INDX_CMD(MMC_SET_BLOCKLEN)
| MMCHS_SD_CMD_CICE_ENABLE
| MMCHS_SD_CMD_CCCE_ENABLE
| MMCHS_SD_CMD_RSP_TYPE_48B;
@@ -390,7 +393,7 @@ read_single_block(uint32_t addr)
{
uint32_t cmd;
cmd = MMCHS_SD_CMD_INDX_CMD(READ_SINGLE_BLOCK)
cmd = MMCHS_SD_CMD_INDX_CMD(MMC_READ_BLOCK_SINGLE)
| MMCHS_SD_CMD_DP_DATA
| MMCHS_SD_CMD_CICE_ENABLE
| MMCHS_SD_CMD_CCCE_ENABLE
@@ -405,7 +408,7 @@ write_block(uint32_t addr)
{
uint32_t cmd;
cmd = MMCHS_SD_CMD_INDX_CMD(WRITE_SINGLE_BLOCK)
cmd = MMCHS_SD_CMD_INDX_CMD(MMC_WRITE_BLOCK_SINGLE)
| MMCHS_SD_CMD_DP_DATA
| MMCHS_SD_CMD_CICE_ENABLE
| MMCHS_SD_CMD_CCCE_ENABLE
@@ -453,8 +456,8 @@ read_busy(void)
*/
if (irq_wait() < 0)
return -1;
stat = read32(reg->irpt_mask);
write32(reg->irpt_mask, MMCHS_SD_STAT_DCRC
stat = read32(reg->irpt);
write32(reg->irpt, MMCHS_SD_STAT_DCRC
| MMCHS_SD_STAT_DTO
| MMCHS_SD_STAT_TC);
if (stat & MMCHS_SD_STAT_ERRI) {
@@ -477,8 +480,8 @@ read_data(uint32_t *data)
/* 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);
if (read32(reg->irpt) & MMCHS_SD_STAT_BRR) {
write32(reg->irpt, MMCHS_SD_STAT_BRR);
for (i=SD_DATA_WLEN; i>0; i--)
*data++ = read32(reg->data);
}
@@ -486,8 +489,8 @@ read_data(uint32_t *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
stat = read32(reg->irpt);
write32(reg->irpt, MMCHS_SD_STAT_DEB
| MMCHS_SD_STAT_DCRC
| MMCHS_SD_STAT_DTO
| MMCHS_SD_STAT_TC);
@@ -512,7 +515,7 @@ write_data(uint32_t *data)
if (irq_wait() < 0)
return -1;
if (read32(reg->status) & MMCHS_SD_STAT_BWR) {
write32(reg->irpt_mask, MMCHS_SD_STAT_BWR);
write32(reg->irpt, MMCHS_SD_STAT_BWR);
for (i = SD_DATA_WLEN; i > 0; i--)
write32(reg->data, *data++);
}
@@ -520,8 +523,8 @@ write_data(uint32_t *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
stat = read32(reg->irpt);
write32(reg->irpt, MMCHS_SD_STAT_DEB
| MMCHS_SD_STAT_DCRC
| MMCHS_SD_STAT_DTO
| MMCHS_SD_STAT_TC);
@@ -585,10 +588,6 @@ 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)
@@ -620,8 +619,10 @@ minix_init(void)
reg->slotisr_var += v_base;
/* Register the MMC1 interrupt number. */
if (sys_irqsetpolicy(BCM2835_MMCSD1INT, 0, &hook_id) != OK)
if (sys_irqsetpolicy(BCM2835_MMCSD1INT, 0, &hook_id) != OK) {
log_warn(&log, "can't set irq\n");
return -1;
}
return 0;
}
@@ -654,7 +655,7 @@ 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.
@@ -664,30 +665,10 @@ emmc_host_init(struct mmc_host *host)
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;
*/
set32(reg->control1, MMCHS_SD_SYSCTL_SRA,
MMCHS_SD_SYSCTL_SRA);
/* Set the bus clock frequency to FOD (400kHz). */
set32(reg->control1, MMCHS_SD_SYSCTL_CLKD,
MMCHS_SD_SYSCTL_CLKD_400KHZ << 6);
@@ -698,27 +679,19 @@ emmc_host_init(struct mmc_host *host)
/* 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;
== MMCHS_SD_SYSCTL_ICS_UNSTABLE) {
log_warn(&log, "clock is unstable\n");
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
write32(reg->irpt_mask, MMCHS_SD_IE_ERROR_MASK
| MMCHS_SD_IE_BRR_ENABLE_ENABLE
| MMCHS_SD_IE_BWR_ENABLE_ENABLE
| MMCHS_SD_IE_TC_ENABLE_ENABLE
@@ -777,17 +750,10 @@ emmc_card_initialize(struct sd_slot *slot)
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)
if (repeat_send_op_cond() < 0)
return NULL;
*/
/* CMD2. The driver has no use for the CID. */
if (all_send_cid() < 0)
return NULL;
@@ -796,13 +762,6 @@ emmc_card_initialize(struct sd_slot *slot)
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;
@@ -825,9 +784,9 @@ emmc_card_initialize(struct sd_slot *slot)
return NULL;
/* Receive the Extended CSD register. */
/* if (read_data((uint32_t *)card_ext_csd) < 0)
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;
@@ -863,13 +822,10 @@ emmc_card_initialize(struct sd_slot *slot)
/* 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
set32(reg->control0, MMCHS_SD_HCTL_DTW,
MMCHS_SD_HCTL_DTW_1BIT);
/* CMD16. Set block length to sector size (512B). */
if (set_blocklen() < 0)
return NULL;
@@ -910,7 +866,7 @@ emmc_card_release(struct sd_card *card)
static void
emmc_hw_intr(unsigned int irqs)
{
log_warn(&log, "register SD_STAT == 0x%08x\n", reg->irpt_mask);
log_warn(&log, "register SD_STAT == 0x%08x\n", reg->irpt);
}
/*

View File

@@ -36,8 +36,6 @@
static int hook_id = 1;
#endif
#define USE_DMA
#define SANE_TIMEOUT 500000 /* 500 ms */
struct rpi_mmchs *mmchs; /* pointer to the current mmchs */
@@ -46,7 +44,7 @@ struct rpi_mmchs rpi_sdcard = {
.io_base = 0,
.io_size = 0x100,
.hw_base = 0x3f300000,
.irq_nr = 24,
.irq_nr = 126,
.regs = &regs_v0
};
@@ -64,10 +62,10 @@ static struct log log = {
.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 */
#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)
@@ -139,6 +137,8 @@ mmchs_init(uint32_t instance)
/* Soft reset of the controller. This section is documented in the TRM
*/
mmc_write32(mmchs->regs->control0, 0);
mmc_write32(mmchs->regs->control2, 0);
/* Write 1 to sysconfig[0] to trigger a reset */
mmc_set32(mmchs->regs->control1, MMCHS_SD_SYSCTL_SRA,
MMCHS_SD_SYSCTL_SRA);
@@ -154,10 +154,6 @@ mmchs_init(uint32_t instance)
}
}
/* 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
*/
@@ -188,7 +184,6 @@ mmchs_init(uint32_t instance)
*/
/* 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 */
@@ -201,37 +196,6 @@ mmchs_init(uint32_t instance)
/* 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);
@@ -255,13 +219,13 @@ mmchs_init(uint32_t instance)
void
intr_deassert(int mask)
{
if (mmc_read32(mmchs->regs->irpt_mask) & 0x8000) {
if (mmc_read32(mmchs->regs->irpt) & 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,
mmc_read32(mmchs->regs->irpt));
mmc_set32(mmchs->regs->irpt, MMCHS_SD_STAT_ERROR_MASK,
0xffffffffu);
} else {
mmc_write32(mmchs->regs->irpt_mask, mask);
mmc_write32(mmchs->regs->irpt, mask);
}
}
@@ -329,7 +293,7 @@ static void
mmchs_hw_intr(unsigned int irqs)
{
log_warn(&log, "Hardware interrupt left over (0x%08lx)\n",
mmc_read32(mmchs->regs->irpt_mask));
mmc_read32(mmchs->regs->irpt));
#ifdef USE_INTR
if (sys_irqenable(&hook_id) != OK)
@@ -352,6 +316,7 @@ intr_wait(int mask)
message m;
int ipc_status;
int ticks = SANE_TIMEOUT * sys_hz() / 1000000;
log_info(&log, "wait irpt with 0x%x\n", mmc_read32(mmchs->regs->irpt));
if (ticks <= 0)
ticks = 1;
@@ -370,7 +335,7 @@ intr_wait(int mask)
break;
case HARDWARE:
while ((v =
mmc_read32(mmchs->regs->irpt_mask)) !=
mmc_read32(mmchs->regs->irpt)) !=
0) {
if (v & MMCHS_SD_IE_BWR_ENABLE) {
handle_bwr();
@@ -430,7 +395,7 @@ intr_wait(int mask)
int counter = 0;
while (1 == 1) {
counter++;
v = mmc_read32(mmchs->regs->irpt_mask);
v = mmc_read32(mmchs->regs->irpt);
if (spin_check(&spin) == FALSE) {
log_warn(&log,
"Timeout waiting for interrupt (%d) value 0x%08x mask 0x%08x\n",
@@ -462,9 +427,10 @@ int
mmchs_send_cmd(uint32_t command, uint32_t arg)
{
spin_t spin;
/* Read current interrupt status and fail it an interrupt is already
* asserted */
assert(mmc_read32(mmchs->regs->irpt_mask) == 0);
assert(mmc_read32(mmchs->regs->irpt) == 0);
/* Set arguments */
mmc_write32(mmchs->regs->arg1, arg);
@@ -472,24 +438,31 @@ mmchs_send_cmd(uint32_t command, uint32_t arg)
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);
uint32_t v = mmc_read32(mmchs->regs->irpt);
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);
intr_deassert(MMCHS_SD_STAT_DONE);
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)
if ((mmc_read32(mmchs->regs->irpt)
& MMCHS_SD_IE_TC_ENABLE_ENABLE) == 0) {
log_warn(&log, "TC should be raised\n");
}
intr_deassert(MMCHS_SD_STAT_TC);
}
spin_init(&spin, SANE_TIMEOUT);
while(1) {
if(spin_check(&spin) == FALSE)
break;
}
return 0;
}
@@ -537,21 +510,21 @@ mmc_send_cmd(struct mmc_command *c)
}
/* check we are in a sane state */
if ((mmc_read32(mmchs->regs->irpt_mask) & 0xffffu)) {
if ((mmc_read32(mmchs->regs->irpt) & 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);
__FUNCTION__, mmc_read32(mmchs->regs->irpt));
mmc_write32(mmchs->regs->irpt, 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,
mmc_set32(mmchs->regs->irpt_mask,
MMCHS_SD_IE_BRR_ENABLE,
MMCHS_SD_IE_BRR_ENABLE_ENABLE);
} else {
mmc_set32(mmchs->regs->irpt,
mmc_set32(mmchs->regs->irpt_mask,
MMCHS_SD_IE_BWR_ENABLE,
MMCHS_SD_IE_BWR_ENABLE_ENABLE);
}
@@ -561,7 +534,6 @@ mmc_send_cmd(struct mmc_command *c)
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) {
@@ -575,11 +547,11 @@ mmc_send_cmd(struct mmc_command *c)
return 1;
}
mmc_write32(mmchs->regs->irpt_mask,
mmc_write32(mmchs->regs->irpt,
MMCHS_SD_IE_TC_ENABLE_CLEAR);
/* disable the bbr interrupt */
mmc_set32(mmchs->regs->irpt,
mmc_set32(mmchs->regs->irpt_mask,
MMCHS_SD_IE_BRR_ENABLE,
MMCHS_SD_IE_BRR_ENABLE_DISABLE);
} else {
@@ -592,13 +564,12 @@ mmc_send_cmd(struct mmc_command *c)
}
intr_deassert(MMCHS_SD_IE_TC_ENABLE_CLEAR);
mmc_set32(mmchs->regs->irpt,
mmc_set32(mmchs->regs->irpt_mask,
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:
@@ -654,23 +625,14 @@ card_identification()
{
struct mmc_command command;
command.cmd = SD_SEND_IF_COND; /* Send CMD8 */
command.resp_type = RESP_LEN_48;
command.resp_type = RESP_NO_RESPONSE;
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;
}
@@ -698,7 +660,7 @@ card_query_voltage_and_type(struct sd_card_regs *card)
spin_init(&spin, SANE_TIMEOUT);
while (!(command.resp[0] & MMC_OCR_MEM_READY)) {
/* Send ADMD41 */
/* Send ACMD41 */
/* 0x1 << 30 == send HCS (Host capacity support) and get OCR
* register */
command.cmd = SD_APP_OP_COND;
@@ -723,7 +685,7 @@ card_query_voltage_and_type(struct sd_card_regs *card)
}
}
card->ocr = command.resp[3];
card->ocr = (command.resp[0] >> 8) & 0xffff;
return 0;
}
@@ -785,12 +747,6 @@ card_csd(struct sd_card_regs *card)
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;
}
@@ -826,7 +782,7 @@ card_scr(struct sd_card_regs *card)
command.cmd = SD_APP_SEND_SCR;
command.resp_type = RESP_LEN_48;
command.data_type = DATA_READ;
command.args = 0xaaaaaaaa;
command.args = 0;
command.data = buffer;
command.data_len = 8;
@@ -939,38 +895,6 @@ mmc_switch(int function, int value, uint8_t * data)
// 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)
@@ -1042,7 +966,7 @@ mmchs_host_set_instance(struct mmc_host *host, int instance)
int
mmchs_host_reset(struct mmc_host *host)
{
// mmchs_init(1);
mmchs_init(1);
return 0;
}
@@ -1056,7 +980,7 @@ mmchs_card_detect(struct sd_slot *slot)
struct sd_card *
mmchs_card_initialize(struct sd_slot *slot)
{
// mmchs_init(1);
mmchs_init(1);
struct sd_card *card;
card = &slot->card;
@@ -1104,28 +1028,49 @@ mmchs_card_initialize(struct sd_slot *slot)
return NULL;
}
if (enable_high_speed_mode(&slot->card.regs)) {
log_warn(&log, "failed to configure high speed mode mode\n");
return NULL;
int blksize;
switch (SD_CSD_READ_BL_LEN(slot->card.regs.csd)) {
case 0x09:
blksize = 512;
break;
case 0x0a:
blksize = 1024;
break;
case 0x0b:
blksize = 2048;
break;
default:
log_warn(&log, "Unknown block size\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 = blksize;
int version;
switch (SD_CSD_CSDVER(slot->card.regs.csd)) {
case 0:
version = 1;
break;
case 1:
version = 2;
break;
}
slot->card.blk_size = 512; /* HARDCODED value */
slot->card.blk_count = SD_CSD_V2_CAPACITY(slot->card.regs.csd);
if (version == 1)
slot->card.blk_count = SD_CSD_CAPACITY(slot->card.regs.csd);
else
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;
if (version == 1)
slot->card.part[0].dv_size =
(unsigned long long) SD_CSD_CAPACITY(slot->card.regs.csd) * blksize;
else
slot->card.part[0].dv_size =
(unsigned long long) SD_CSD_V2_CAPACITY(slot->card.regs.csd) * blksize;
log_info(&log, "dv_size: %d, blksize: %d\n", slot->card.part[0].dv_size, slot->card.blk_size);
return &slot->card;
}
@@ -1137,6 +1082,7 @@ mmchs_host_read(struct sd_card *card,
uint32_t i;
i = count;
for (i = 0; i < count; i++) {
log_info(&log, "read %d block\n", i);
read_single_block(&card->regs, blknr + i,
buf + (i * card->blk_size));
}
@@ -1152,6 +1098,7 @@ mmchs_host_write(struct sd_card *card,
i = count;
for (i = 0; i < count; i++) {
log_info(&log, "write %d block\n", i);
write_single_block(&card->regs, blknr + i,
buf + (i * card->blk_size));
}

View File

@@ -178,26 +178,27 @@ struct rpi_mmchs {
#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_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_DONE (0xffff0001u) /* send command done */
#define MMCHS_SD_STAT_ERRI (0x01 << 15) /* Error interrupt */
#define MMCHS_SD_STAT_ERROR_MASK (0xfe << 15 | 0x1 << 24)
#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_ERROR_MASK (0xfe << 15 | 0x1 << 24)
#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 */
@@ -222,42 +223,6 @@ struct rpi_mmchs {
#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)

View File

@@ -0,0 +1,202 @@
/* $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 <uwe@openbsd.org>
*
* 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_ */

View File

@@ -0,0 +1,355 @@
/* $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 <uwe@openbsd.org>
*
* 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_ */