mmc:development

* let busy loops timeout.
* Start using interrupt handlers.
* Allocate the ramdisk only when used.

Change-Id: Ie08d66eefef3c8cd3ee16c04f74a9a50cc12b021
This commit is contained in:
Kees Jongenburger 2012-10-19 15:44:10 +02:00 committed by Kees Jongenburger
parent c31c70743a
commit 3de9b14567
6 changed files with 286 additions and 109 deletions

View file

@ -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;

View file

@ -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);

View file

@ -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));

View file

@ -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;

View file

@ -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)

View file

@ -549,6 +549,9 @@ service mmc
{
system
PRIVCTL # 4
IRQCTL # 19
;
irq 83; # IRQ 83 allowed
;
};