mmc:development
* let busy loops timeout. * Start using interrupt handlers. * Allocate the ramdisk only when used. Change-Id: Ie08d66eefef3c8cd3ee16c04f74a9a50cc12b021
This commit is contained in:
parent
c31c70743a
commit
3de9b14567
|
@ -6,6 +6,8 @@
|
|||
#include <minix/driver.h>
|
||||
#include <minix/blockdriver.h>
|
||||
#include <minix/drvlib.h>
|
||||
#include <minix/minlib.h>
|
||||
|
||||
|
||||
/* system headers */
|
||||
#include <sys/ioc_disk.h> /* disk IOCTL's */
|
||||
|
@ -24,25 +26,13 @@
|
|||
/* used for logging */
|
||||
static struct mmclog log = {
|
||||
.name = "mmc_block",
|
||||
.log_level = LEVEL_DEBUG,
|
||||
.log_level = LEVEL_INFO,
|
||||
.log_func = default_log
|
||||
};
|
||||
|
||||
/* holding the current host controller */
|
||||
static struct mmc_host host;
|
||||
|
||||
/*@TODO REMOVE THIS */
|
||||
void
|
||||
read_tsc_64(u64_t * t)
|
||||
{
|
||||
}
|
||||
|
||||
u32_t
|
||||
tsc_64_to_micros(u64_t tsc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define SUB_PER_DRIVE (NR_PARTITIONS * NR_PARTITIONS)
|
||||
#define NR_SUBDEVS (MAX_DRIVES * SUB_PER_DRIVE)
|
||||
|
||||
|
@ -70,12 +60,18 @@ 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);
|
||||
|
||||
static int apply_env();
|
||||
void
|
||||
bdr_alarm(clock_t stamp)
|
||||
{
|
||||
mmc_log_debug(&log, "alarm %d\n", stamp);
|
||||
|
||||
}
|
||||
|
||||
static int apply_env();
|
||||
static void hw_intr(unsigned int irqs);
|
||||
|
||||
#if 0
|
||||
/* set the global logging level */
|
||||
static void set_log_level(int level);
|
||||
#endif
|
||||
|
||||
/* Entry points for the BLOCK driver. */
|
||||
static struct blockdriver mmc_driver = {
|
||||
|
@ -87,20 +83,28 @@ static struct blockdriver mmc_driver = {
|
|||
NULL, /* no need to clean up (yet) */
|
||||
block_part, /* return partition information */
|
||||
NULL, /* no geometry */
|
||||
NULL, /* no interrupt processing */
|
||||
NULL, /* no alarm processing */
|
||||
hw_intr, /* left over interrupts */
|
||||
bdr_alarm, /* no alarm processing */
|
||||
NULL, /* no processing of other messages */
|
||||
NULL /* no threading support */
|
||||
};
|
||||
|
||||
static void
|
||||
hw_intr(unsigned int irqs)
|
||||
{
|
||||
mmc_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,WARNING,INFO,DEBUG,TRACE) instance=[0-3]
|
||||
* 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 /sbin/mmc -args "log_level=2 instance=1
|
||||
* following way service up /sbin/mmc -args "log_level=2 instance=1
|
||||
* driver=dummy" -dev /dev/c2d0 */
|
||||
char driver[16];
|
||||
memset(driver, '\0', 16);
|
||||
|
@ -115,10 +119,6 @@ apply_env()
|
|||
} else {
|
||||
mmc_log_warn(&log, "Unknown driver %s\n", driver);
|
||||
}
|
||||
#if 0
|
||||
long v;
|
||||
/* The following code(env_parse) uses strtol.c and needs __aeabi_idiv */
|
||||
/* @TODO: re-enable this function when __aeabi_idiv will be present */
|
||||
/* Initialize the verbosity level. */
|
||||
v = 0;
|
||||
if (env_parse("log_level", "d", 0, &v, LEVEL_NONE,
|
||||
|
@ -133,7 +133,6 @@ apply_env()
|
|||
mmc_log_warn(&log, "Failed to set mmc instance to %d\n", v);
|
||||
return -1; /* NOT OK */
|
||||
}
|
||||
#endif
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -185,27 +184,27 @@ block_open(dev_t minor, int access)
|
|||
partition(&mmc_driver, 0 /* first card on bus */ , P_PRIMARY,
|
||||
0 /* atapi device?? */ );
|
||||
|
||||
mmc_log_debug(&log, "descr \toffset(bytes) size(bytes)\n", minor);
|
||||
mmc_log_trace(&log, "descr \toffset(bytes) size(bytes)\n", minor);
|
||||
|
||||
mmc_log_debug(&log, "disk %d\t0x%016llx 0x%016llx\n", i,
|
||||
mmc_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++;
|
||||
mmc_log_debug(&log, "part %d\t0x%016llx 0x%016llx\n", i,
|
||||
mmc_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++;
|
||||
mmc_log_debug(&log,
|
||||
mmc_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);
|
||||
}
|
||||
}
|
||||
mmc_log_info(&log, "Found %d partitions and %d sub partitions\n",
|
||||
mmc_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);
|
||||
|
@ -312,7 +311,7 @@ block_transfer(dev_t minor, /* minor device number */
|
|||
/* Unknown device */
|
||||
return ENXIO;
|
||||
}
|
||||
mmc_log_trace(&log, "I/O %d %s 0x%llx\n", minor,
|
||||
mmc_log_trace(&log, "I/O on minor(%d) %s at 0x%016llx\n", minor,
|
||||
(do_write) ? "Write" : "Read", position);
|
||||
|
||||
slot = get_slot(minor);
|
||||
|
@ -636,20 +635,18 @@ get_slot(dev_t minor)
|
|||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
set_log_level(int level)
|
||||
{
|
||||
if (level < 0 || level >= 4) {
|
||||
return;
|
||||
}
|
||||
mmc_log_debug(&log, "Setting verbosity level to %d\n", level);
|
||||
mmc_log_info(&log, "Setting verbosity level to %d\n", level);
|
||||
log.log_level = level;
|
||||
if (host.set_log_level) {
|
||||
host.set_log_level(level);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
|
@ -657,7 +654,6 @@ main(int argc, char **argv)
|
|||
|
||||
/* Set and apply the environment */
|
||||
env_setargs(argc, argv);
|
||||
|
||||
sef_local_startup();
|
||||
blockdriver_task(&mmc_driver);
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
@ -117,6 +117,9 @@ struct mmc_host
|
|||
/* 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);
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
/* kernel headers */
|
||||
#include <minix/blockdriver.h>
|
||||
#include <minix/minlib.h>
|
||||
|
||||
/* usr headers */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* local headers */
|
||||
#include "mmclog.h"
|
||||
|
@ -17,14 +19,14 @@
|
|||
*/
|
||||
static struct mmclog log = {
|
||||
.name = "mmc_host_memory",
|
||||
.log_level = LEVEL_TRACE,
|
||||
.log_level = LEVEL_INFO,
|
||||
.log_func = default_log
|
||||
};
|
||||
|
||||
/* This is currently a dummy driver using an in-memory structure */
|
||||
#define DUMMY_SIZE_IN_BLOCKS 0xFFFu
|
||||
#define DUMMY_SIZE_IN_BLOCKS 0xFFFFFu
|
||||
#define DUMMY_BLOCK_SIZE 512
|
||||
static char dummy_data[DUMMY_BLOCK_SIZE * DUMMY_SIZE_IN_BLOCKS];
|
||||
static char *dummy_data = NULL;
|
||||
|
||||
static struct sd_card *
|
||||
init_dummy_sdcard(struct sd_slot *slot)
|
||||
|
@ -35,6 +37,13 @@ init_dummy_sdcard(struct sd_slot *slot)
|
|||
assert(slot != NULL);
|
||||
|
||||
mmc_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));
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
#include <minix/blockdriver.h>
|
||||
#include <minix/com.h>
|
||||
#include <minix/vm.h>
|
||||
#include <minix/spin.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
/* usr headers */
|
||||
#include <assert.h>
|
||||
|
@ -12,6 +14,7 @@
|
|||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* local headers */
|
||||
#include "mmclog.h"
|
||||
|
@ -25,6 +28,14 @@
|
|||
/* omap /hardware related */
|
||||
#include "omap_mmc.h"
|
||||
|
||||
#define USE_INTR
|
||||
|
||||
#ifdef USE_INTR
|
||||
static int hook_id = 1;
|
||||
#define OMAP3_MMC1_IRQ 83 /* MMC/SD module 1 */
|
||||
#endif
|
||||
|
||||
#define SANE_TIMEOUT 500000 /* 500 MS */
|
||||
/*
|
||||
* Define a structure to be used for logging
|
||||
*/
|
||||
|
@ -38,14 +49,14 @@ static struct mmclog log = {
|
|||
#define BIT(x)(0x1 << x)
|
||||
|
||||
/* Write a uint32_t value to a memory address. */
|
||||
inline void
|
||||
static inline void
|
||||
write32(uint32_t address, uint32_t value)
|
||||
{
|
||||
REG(address) = value;
|
||||
}
|
||||
|
||||
/* Read an uint32_t from a memory address */
|
||||
inline uint32_t
|
||||
static inline uint32_t
|
||||
read32(uint32_t address)
|
||||
{
|
||||
|
||||
|
@ -53,7 +64,7 @@ read32(uint32_t address)
|
|||
}
|
||||
|
||||
/* Set a 32 bits value depending on a mask */
|
||||
inline void
|
||||
static inline void
|
||||
set32(uint32_t address, uint32_t mask, uint32_t value)
|
||||
{
|
||||
uint32_t val;
|
||||
|
@ -75,13 +86,11 @@ static uint32_t base_address;
|
|||
int
|
||||
mmchs_init(uint32_t instance)
|
||||
{
|
||||
int counter;
|
||||
|
||||
uint32_t value;
|
||||
|
||||
counter = 0;
|
||||
value = 0;
|
||||
|
||||
struct minix_mem_range mr;
|
||||
spin_t spin;
|
||||
|
||||
mr.mr_base = MMCHS1_REG_BASE;
|
||||
mr.mr_limit = MMCHS1_REG_BASE + 0x400;
|
||||
|
@ -106,11 +115,14 @@ mmchs_init(uint32_t instance)
|
|||
MMCHS_SD_SYSCONFIG_SOFTRESET);
|
||||
|
||||
/* Read sysstatus to know when it's done */
|
||||
|
||||
spin_init(&spin, SANE_TIMEOUT);
|
||||
while (!(read32(base_address + MMCHS_SD_SYSSTATUS)
|
||||
& MMCHS_SD_SYSSTATUS_RESETDONE)) {
|
||||
/* TODO:Add proper delay and escape route */
|
||||
|
||||
counter++;
|
||||
if (spin_check(&spin) == FALSE) {
|
||||
mmc_log_warn(&log, "mmc init timeout\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set SD default capabilities */
|
||||
|
@ -164,12 +176,14 @@ mmchs_init(uint32_t instance)
|
|||
set32(base_address + MMCHS_SD_HCTL, MMCHS_SD_HCTL_SDBP,
|
||||
MMCHS_SD_HCTL_SDBP_ON);
|
||||
|
||||
/* TODO: Add padconf stuff here as documented in the TRM */
|
||||
|
||||
// /* TODO: Add padconf/pinmux stuff here as documented in the TRM */
|
||||
spin_init(&spin, SANE_TIMEOUT);
|
||||
while ((read32(base_address + MMCHS_SD_HCTL) & MMCHS_SD_HCTL_SDBP)
|
||||
!= MMCHS_SD_HCTL_SDBP_ON) {
|
||||
/* TODO:Add proper delay and escape route */
|
||||
counter++;
|
||||
if (spin_check(&spin) == FALSE) {
|
||||
mmc_log_warn(&log, "mmc init timeout SDBP not set\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable internal clock and clock to the card */
|
||||
|
@ -177,16 +191,23 @@ mmchs_init(uint32_t instance)
|
|||
MMCHS_SD_SYSCTL_ICE_EN);
|
||||
|
||||
// @TODO Fix external clock enable , this one is very slow
|
||||
// but we first need faster context switching
|
||||
//set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_CLKD,
|
||||
// (0x20 << 6));
|
||||
set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_CLKD,
|
||||
(0x3ff << 6));
|
||||
(0x5 << 6));
|
||||
|
||||
set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_CEN,
|
||||
MMCHS_SD_SYSCTL_CEN_EN);
|
||||
counter = 0;
|
||||
|
||||
spin_init(&spin, SANE_TIMEOUT);
|
||||
while ((read32(base_address + MMCHS_SD_SYSCTL) & MMCHS_SD_SYSCTL_ICS)
|
||||
!= MMCHS_SD_SYSCTL_ICS_STABLE) {
|
||||
/* TODO:Add proper delay and escape route */
|
||||
counter++;
|
||||
|
||||
if (spin_check(&spin) == FALSE) {
|
||||
mmc_log_warn(&log, "clock not stable\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -216,7 +237,7 @@ mmchs_init(uint32_t instance)
|
|||
/* command 0 , type other commands not response etc) */
|
||||
write32(base_address + MMCHS_SD_CMD, 0x00);
|
||||
|
||||
counter = 0;
|
||||
spin_init(&spin, SANE_TIMEOUT);
|
||||
while ((read32(base_address + MMCHS_SD_STAT) & MMCHS_SD_STAT_CC)
|
||||
!= MMCHS_SD_STAT_CC_RAISED) {
|
||||
if (read32(base_address + MMCHS_SD_STAT) & 0x8000) {
|
||||
|
@ -225,7 +246,12 @@ mmchs_init(uint32_t instance)
|
|||
read32(base_address + MMCHS_SD_STAT));
|
||||
return 1;
|
||||
}
|
||||
counter++;
|
||||
|
||||
if (spin_check(&spin) == FALSE) {
|
||||
mmc_log_warn(&log,
|
||||
"Interrupt not raised during init\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* clear the cc interrupt status */
|
||||
|
@ -238,41 +264,151 @@ mmchs_init(uint32_t instance)
|
|||
set32(base_address + MMCHS_SD_CON, MMCHS_SD_CON_INIT,
|
||||
MMCHS_SD_CON_INIT_NOINIT);
|
||||
|
||||
/* Set timeout */
|
||||
set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_DTO,
|
||||
MMCHS_SD_SYSCTL_DTO_2POW27);
|
||||
|
||||
/* Clean the MMCHS_SD_STAT register */
|
||||
write32(base_address + MMCHS_SD_STAT, 0xffffffffu);
|
||||
#ifdef USE_INTR
|
||||
hook_id = 1;
|
||||
if (sys_irqsetpolicy(OMAP3_MMC1_IRQ, 0, &hook_id) != OK) {
|
||||
printf("mmc: couldn't set IRQ policy %d\n", OMAP3_MMC1_IRQ);
|
||||
return 1;
|
||||
}
|
||||
/* enable signaling from MMC controller towards interrupt controller */
|
||||
write32(base_address + MMCHS_SD_ISE, 0xffffffffu);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mmchs_hw_intr(unsigned int irqs)
|
||||
{
|
||||
mmc_log_warn(&log, "Hardware interrupt left over\n");
|
||||
|
||||
#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. */
|
||||
// w_timeout(); /* a.o. set w_status */
|
||||
mmc_log_warn(&log, "TIMEOUT\n");
|
||||
return 1;
|
||||
break;
|
||||
case HARDWARE:
|
||||
v = read32(base_address + MMCHS_SD_STAT);
|
||||
if (v & mask) {
|
||||
sys_setalarm(0, 0);
|
||||
return 0;
|
||||
} else if (v & (1 << 15)){
|
||||
return 1; /* error */
|
||||
} else {
|
||||
mmc_log_debug(&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");
|
||||
continue;
|
||||
// return 1;
|
||||
}
|
||||
default:
|
||||
/*
|
||||
* unhandled message. queue it and
|
||||
* handle it in the blockdriver loop.
|
||||
*/
|
||||
blockdriver_mq_queue(&m, ipc_status);
|
||||
}
|
||||
} else {
|
||||
mmc_log_debug(&log, "Other\n");
|
||||
/*
|
||||
* 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 = read32(base_address + MMCHS_SD_STAT);
|
||||
if (spin_check(&spin) == FALSE) {
|
||||
mmc_log_warn(&log, "Timeout waiting for interrupt (%d) value 0x%08x mask 0x%08x\n",counter, v,mask);
|
||||
return 1;
|
||||
}
|
||||
if (v & mask) {
|
||||
return 0;
|
||||
} else if (v & 0xFF00) {
|
||||
mmc_log_debug(&log, "unexpected HW interrupt (%d) 0x%08x mask 0x%08x\n", v, mask);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 1; /* unreached */
|
||||
#endif /* USE_INTR */
|
||||
}
|
||||
|
||||
void
|
||||
intr_assert(int mask)
|
||||
{
|
||||
if (read32(base_address + MMCHS_SD_STAT) & 0x8000) {
|
||||
mmc_log_debug(&log, "%s, error stat %08x\n", __FUNCTION__,
|
||||
read32(base_address + MMCHS_SD_STAT));
|
||||
set32(base_address + MMCHS_SD_STAT, MMCHS_SD_STAT_ERROR_MASK,
|
||||
0xffffffffu);
|
||||
} else {
|
||||
write32(base_address + MMCHS_SD_STAT, mask);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
mmchs_send_cmd(uint32_t command, uint32_t arg)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
/* Read current interrupt status and fail it an interrupt is already
|
||||
* asserted */
|
||||
if ((read32(base_address + MMCHS_SD_STAT) & 0xffffu)) {
|
||||
mmc_log_warn(&log, "%s, interrupt already raised stat %08x\n",
|
||||
__FUNCTION__, read32(base_address + MMCHS_SD_STAT));
|
||||
write32(base_address + MMCHS_SD_STAT,
|
||||
MMCHS_SD_IE_CC_ENABLE_CLEAR);
|
||||
// return 1;
|
||||
}
|
||||
|
||||
/* Set arguments */
|
||||
write32(base_address + MMCHS_SD_ARG, arg);
|
||||
/* Set command */
|
||||
set32(base_address + MMCHS_SD_CMD, MMCHS_SD_CMD_MASK, command);
|
||||
|
||||
/* Wait for completion */
|
||||
while ((read32(base_address + MMCHS_SD_STAT) & 0xffffu) == 0x0) {
|
||||
count++;
|
||||
}
|
||||
|
||||
if (read32(base_address + MMCHS_SD_STAT) & 0x8000) {
|
||||
mmc_log_warn(&log, "%s, error stat %08x\n", __FUNCTION__,
|
||||
read32(base_address + MMCHS_SD_STAT));
|
||||
set32(base_address + MMCHS_SD_STAT, MMCHS_SD_STAT_ERROR_MASK,
|
||||
0xffffffffu);
|
||||
if (intr_wait(MMCHS_SD_STAT_CC | MMCHS_SD_IE_TC_ENABLE_CLEAR)) {
|
||||
intr_assert(MMCHS_SD_STAT_CC);
|
||||
mmc_log_warn(&log, "Failure waiting for interrupt\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -281,16 +417,20 @@ mmchs_send_cmd(uint32_t command, uint32_t arg)
|
|||
/*
|
||||
* Command with busy response *CAN* also set the TC bit if they exit busy
|
||||
*/
|
||||
while ((read32(base_address + MMCHS_SD_STAT)
|
||||
if ((read32(base_address + MMCHS_SD_STAT)
|
||||
& MMCHS_SD_IE_TC_ENABLE_ENABLE) == 0) {
|
||||
count++;
|
||||
mmc_log_warn(&log, "TC should be raised\n");
|
||||
}
|
||||
write32(base_address + MMCHS_SD_STAT,
|
||||
MMCHS_SD_IE_TC_ENABLE_CLEAR);
|
||||
}
|
||||
|
||||
/* clear the cc status */
|
||||
write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_CC_ENABLE_CLEAR);
|
||||
if (intr_wait(MMCHS_SD_STAT_CC | MMCHS_SD_IE_TC_ENABLE_CLEAR)) {
|
||||
intr_assert(MMCHS_SD_STAT_CC);
|
||||
mmc_log_warn(&log, "Failure waiting for clear\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
intr_assert(MMCHS_SD_STAT_CC);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -383,10 +523,11 @@ card_identification()
|
|||
int
|
||||
card_query_voltage_and_type(struct sd_card_regs *card)
|
||||
{
|
||||
|
||||
spin_t spin;
|
||||
command.cmd = MMC_APP_CMD;
|
||||
command.resp_type = RESP_LEN_48;
|
||||
command.args = MMC_ARG_RCA(0x0); /* RCA=0000 */
|
||||
|
||||
if (mmc_send_cmd(&command)) {
|
||||
return 1;
|
||||
}
|
||||
|
@ -405,6 +546,7 @@ card_query_voltage_and_type(struct sd_card_regs *card)
|
|||
return 1;
|
||||
}
|
||||
/* @todo wait for max 1 ms */
|
||||
spin_init(&spin, SANE_TIMEOUT);
|
||||
while (!(command.resp[0] & MMC_OCR_MEM_READY)) {
|
||||
command.cmd = MMC_APP_CMD;
|
||||
command.resp_type = RESP_LEN_48;
|
||||
|
@ -432,6 +574,10 @@ card_query_voltage_and_type(struct sd_card_regs *card)
|
|||
if ((command.resp[0] & MMC_OCR_MEM_READY)) {
|
||||
break;
|
||||
}
|
||||
if (spin_check(&spin) == FALSE) {
|
||||
mmc_log_warn(&log,
|
||||
"TIMEOUT waiting for the SD card\n");
|
||||
}
|
||||
|
||||
}
|
||||
card->ocr = command.resp[3];
|
||||
|
@ -536,15 +682,18 @@ read_single_block(struct sd_card_regs *card,
|
|||
| MMCHS_SD_CMD_MSBS_SINGLE /* single block */
|
||||
| MMCHS_SD_CMD_DDIR_READ /* read data from card */
|
||||
, blknr)) {
|
||||
mmc_log_warn(&log, "Error sending command\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
while ((read32(base_address + MMCHS_SD_STAT)
|
||||
& MMCHS_SD_IE_BRR_ENABLE_ENABLE) == 0) {
|
||||
count++;
|
||||
if (intr_wait(MMCHS_SD_IE_BRR_ENABLE_ENABLE)) {
|
||||
intr_assert(MMCHS_SD_IE_BRR_ENABLE_ENABLE);
|
||||
mmc_log_warn(&log, "Timeout waiting for interrupt\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(read32(base_address + MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BRE_EN)) {
|
||||
mmc_log_warn(&log, "Problem BRE should be true\n");
|
||||
return 1; /* We are not allowed to read data from the
|
||||
* data buffer */
|
||||
}
|
||||
|
@ -558,11 +707,12 @@ read_single_block(struct sd_card_regs *card,
|
|||
}
|
||||
|
||||
/* Wait for TC */
|
||||
while ((read32(base_address +
|
||||
MMCHS_SD_STAT) & MMCHS_SD_IE_TC_ENABLE_ENABLE)
|
||||
== 0) {
|
||||
count++;
|
||||
if (intr_wait(MMCHS_SD_IE_TC_ENABLE_ENABLE)) {
|
||||
intr_assert(MMCHS_SD_IE_TC_ENABLE_ENABLE);
|
||||
mmc_log_warn(&log, "Timeout waiting for interrupt\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_TC_ENABLE_CLEAR);
|
||||
|
||||
/* clear and disable the bbr interrupt */
|
||||
|
@ -579,17 +729,21 @@ write_single_block(struct sd_card_regs *card,
|
|||
uint32_t count;
|
||||
uint32_t value;
|
||||
|
||||
count = 0;
|
||||
if ((read32(base_address + MMCHS_SD_STAT) & 0xffffu)) {
|
||||
mmc_log_warn(&log, "%s, interrupt already raised stat %08x\n",
|
||||
__FUNCTION__, read32(base_address + MMCHS_SD_STAT));
|
||||
write32(base_address + MMCHS_SD_STAT,
|
||||
MMCHS_SD_IE_CC_ENABLE_CLEAR);
|
||||
// return 1;
|
||||
}
|
||||
|
||||
set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_BWR_ENABLE,
|
||||
MMCHS_SD_IE_BWR_ENABLE_ENABLE);
|
||||
count = 0;
|
||||
|
||||
// set32(base_address + MMCHS_SD_IE, 0xfff , 0xfff);
|
||||
set32(base_address + MMCHS_SD_BLK, MMCHS_SD_BLK_BLEN, 512);
|
||||
|
||||
/* Set timeout */
|
||||
set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_DTO,
|
||||
MMCHS_SD_SYSCTL_DTO_2POW27);
|
||||
|
||||
/* write single block */
|
||||
if (mmchs_send_cmd(MMCHS_SD_CMD_INDX_CMD(MMC_WRITE_BLOCK_SINGLE)
|
||||
| MMCHS_SD_CMD_DP_DATA /* Command with data transfer */
|
||||
|
@ -597,19 +751,32 @@ write_single_block(struct sd_card_regs *card,
|
|||
| MMCHS_SD_CMD_MSBS_SINGLE /* single block */
|
||||
| MMCHS_SD_CMD_DDIR_WRITE /* write to the card */
|
||||
, blknr)) {
|
||||
mmc_log_warn(&log, "Write single block command failed\n");
|
||||
mmc_log_trace(&log, "STAT=(0x%08x)\n",
|
||||
read32(base_address + MMCHS_SD_STAT));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Wait for the MMCHS_SD_IE_BWR_ENABLE interrupt */
|
||||
while ((read32(base_address +
|
||||
MMCHS_SD_STAT) & MMCHS_SD_IE_BWR_ENABLE) == 0) {
|
||||
count++;
|
||||
if (intr_wait(MMCHS_SD_IE_BWR_ENABLE)) {
|
||||
intr_assert(MMCHS_SD_IE_BWR_ENABLE);
|
||||
mmc_log_warn(&log, "WFI failed\n");
|
||||
return 1;
|
||||
}
|
||||
/* clear the interrupt directly */
|
||||
intr_assert(MMCHS_SD_IE_BWR_ENABLE);
|
||||
|
||||
if (!(read32(base_address + MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BWE_EN)) {
|
||||
mmc_log_warn(&log,
|
||||
"Error expected Buffer to be write enabled\n");
|
||||
return 1; /* not ready to write data */
|
||||
}
|
||||
|
||||
|
||||
for (count = 0; count < 512; count += 4) {
|
||||
while (!(read32(base_address + MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BWE_EN)){
|
||||
mmc_log_trace(&log, "Error expected Buffer to be write enabled(%d)\n", count);
|
||||
}
|
||||
*((char *) &value) = buf[count];
|
||||
*((char *) &value + 1) = buf[count + 1];
|
||||
*((char *) &value + 2) = buf[count + 2];
|
||||
|
@ -617,17 +784,14 @@ write_single_block(struct sd_card_regs *card,
|
|||
write32(base_address + MMCHS_SD_DATA, value);
|
||||
}
|
||||
|
||||
|
||||
/* Wait for TC */
|
||||
while ((read32(base_address +
|
||||
MMCHS_SD_STAT) & MMCHS_SD_IE_TC_ENABLE_ENABLE)
|
||||
== 0) {
|
||||
count++;
|
||||
if (intr_wait(MMCHS_SD_IE_TC_ENABLE_CLEAR)) {
|
||||
intr_assert(MMCHS_SD_IE_TC_ENABLE_CLEAR);
|
||||
mmc_log_warn(&log, "(Write) Timeout waiting for transfer complete\n");
|
||||
return 1;
|
||||
}
|
||||
write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_TC_ENABLE_CLEAR);
|
||||
write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_CC_ENABLE_CLEAR); /* finished.
|
||||
*/
|
||||
/* clear the bwr interrupt FIXME is this right when writing? */
|
||||
write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_BWR_ENABLE_CLEAR);
|
||||
intr_assert(MMCHS_SD_IE_TC_ENABLE_CLEAR);
|
||||
set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_BWR_ENABLE,
|
||||
MMCHS_SD_IE_BWR_ENABLE_DISABLE);
|
||||
return 0;
|
||||
|
@ -661,7 +825,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;
|
||||
}
|
||||
|
||||
|
@ -675,7 +839,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;
|
||||
|
@ -785,6 +949,7 @@ host_initialize_host_structure_mmchs(struct mmc_host *host)
|
|||
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;
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#define MMCHS_SD_SYSCTL 0x22c /* SD System control (reset,clocks and timeout) */
|
||||
#define MMCHS_SD_STAT 0x230 /* SD Interrupt status */
|
||||
#define MMCHS_SD_IE 0x234 /* SD Interrupt Enable register */
|
||||
#define MMCHS_SD_ISE 0x238 /* SD Interrupt Signal Enable register */
|
||||
#define MMCHS_SD_CAPA 0x240 /* Capabilities of the host controller */
|
||||
#define MMCHS_SD_CUR_CAPA 0x248 /* Current capabilities of the host controller */
|
||||
|
||||
|
@ -146,7 +147,7 @@
|
|||
#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_2POW27 (0x3 << 16) /* TCF x 2^27 */
|
||||
#define MMCHS_SD_SYSCTL_DTO_2POW27 (0xe << 16) /* TCF x 2^27 */
|
||||
|
||||
#define MMCHS_SD_STAT_ERRI (0x01 << 15) /* Error interrupt */
|
||||
#define MMCHS_SD_STAT_ERROR_MASK (0xff << 15 | 0x3 << 24 | 0x03 << 28)
|
||||
|
|
|
@ -549,6 +549,9 @@ service mmc
|
|||
{
|
||||
system
|
||||
PRIVCTL # 4
|
||||
IRQCTL # 19
|
||||
;
|
||||
irq 83; # IRQ 83 allowed
|
||||
;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue