From: Kees Jongenburger Date: Wed, 16 Oct 2013 07:23:00 +0000 (+0200) Subject: arm:mmc driver refactor (use structs) X-Git-Tag: v3.3.0~705 X-Git-Url: http://zhaoyanbai.com/repos/?a=commitdiff_plain;h=7d85156ac0dfc66f8663c83891931a62de4d21df;p=minix.git arm:mmc driver refactor (use structs) Defined register offsets and device configurations in structs to allow more flexibility. This change will allow to support multiple instances of a driver using a different bus. This is needed for the BeagleBone Black. Change-Id: I24e16faeea338c9a847941a846e6d4e49432525e --- diff --git a/drivers/mmc/mmchost.h b/drivers/mmc/mmchost.h index bad9d0911..30144ff9e 100644 --- a/drivers/mmc/mmchost.h +++ b/drivers/mmc/mmchost.h @@ -49,18 +49,22 @@ struct sd_card_regs 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; - -#define RESP_LEN_48_CHK_BUSY (3<<0) -#define RESP_LEN_48 (2<<0) -#define RESP_LEN_136 (1<<0) -#define NO_RESPONSE (0<<0) - + uint32_t data_type; uint32_t resp[4]; unsigned char *data; uint32_t data_len; diff --git a/drivers/mmc/mmchost_mmchs.c b/drivers/mmc/mmchost_mmchs.c index f5c28c321..bc1f5eadd 100644 --- a/drivers/mmc/mmchost_mmchs.c +++ b/drivers/mmc/mmchost_mmchs.c @@ -33,16 +33,35 @@ #ifdef USE_INTR static int hook_id = 1; -#ifdef DM37XX -#define OMAP3_MMC1_IRQ 83 /* MMC/SD module 1 */ -#endif -#ifdef AM335X -#define OMAP3_MMC1_IRQ 64 /* MMC/SD module 1 */ -#endif #endif +#define USE_DMA + #define SANE_TIMEOUT 500000 /* 500 ms */ +struct omap_mmchs *mmchs; /* pointer to the current mmchs */ + +struct omap_mmchs bone_sdcard = { + .io_base = 0, + .io_size = 0x2ff, + .hw_base = 0x48060000, + .irq_nr = 64, /* MMC/SD module 1 */ + .regs = ®s_v1, +}; + +struct omap_mmchs bbxm_sdcard = { + .io_base = 0, + .io_size = 0x2ff, + .hw_base = 0x4809C000, + .irq_nr = 83, /* MMC/SD module 1 */ + .regs = ®s_v0, +}; + +/* Integer divide x by y and ensure that the result z is + * such that x / z is smaller or equal y + */ +#define div_roundup(x, y) (((x)+((y)-1))/(y)) + /* * Define a structure to be used for logging */ @@ -52,7 +71,46 @@ static struct log log = { .log_func = default_log }; -static uint32_t base_address; +#define HSMMCSD_0_IN_FREQ 96000000 /* 96MHz */ +#define HSMMCSD_0_INIT_FREQ 400000 /* 400kHz */ +#define HSMMCSD_0_FREQ_25MHZ 25000000 /* 25MHz */ +#define HSMMCSD_0_FREQ_50MHZ 50000000 /* 50MHz */ + +void +mmc_set32(vir_bytes reg, u32_t mask, u32_t value) +{ + assert(reg >= 0 && reg <= mmchs->io_size); + set32(mmchs->io_base + reg, mask, value); +} + +u32_t +mmc_read32(vir_bytes reg) +{ + assert(reg >= 0 && reg <= mmchs->io_size); + return read32(mmchs->io_base + reg); +} + +void +mmc_write32(vir_bytes reg, u32_t value) +{ + assert(reg >= 0 && reg <= mmchs->io_size); + write32(mmchs->io_base + reg, value); +} + +int +mmchs_set_bus_freq(u32_t freq) +{ + u32_t freq_in = HSMMCSD_0_IN_FREQ; + u32_t freq_out = freq; + + /* Calculate and program the divisor */ + u32_t clkd = div_roundup(freq_in, freq_out); + clkd = (clkd < 2) ? 2 : clkd; + clkd = (clkd > 1023) ? 1023 : clkd; + + log_debug(&log, "Setting divider to %d\n", clkd); + mmc_set32(mmchs->regs->SYSCTL, MMCHS_SD_SYSCTL_CLKD, (clkd << 6)); +} /* * Initialize the MMC controller given a certain @@ -67,35 +125,35 @@ mmchs_init(uint32_t instance) value = 0; struct minix_mem_range mr; spin_t spin; + assert(mmchs); - mr.mr_base = MMCHS1_REG_BASE; - mr.mr_limit = MMCHS1_REG_BASE + 0x400; + mr.mr_base = mmchs->hw_base; + mr.mr_limit = mmchs->hw_base + mmchs->io_size; + /* grant ourself rights to map the register memory */ if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) { panic("Unable to request permission to map memory"); } /* Set the base address to use */ - base_address = - (uint32_t) vm_map_phys(SELF, (void *) MMCHS1_REG_BASE, 0x400); - if (base_address == (uint32_t) MAP_FAILED) - panic("Unable to map MMC memory"); + mmchs->io_base = + (uint32_t) vm_map_phys(SELF, (void *) mmchs->hw_base, + mmchs->io_size); -#ifdef DM37XX - base_address = (unsigned long) base_address - 0x100; -#endif + if (mmchs->io_base == (uint32_t) MAP_FAILED) + panic("Unable to map MMC memory"); /* Soft reset of the controller. This section is documented in the TRM */ /* Write 1 to sysconfig[0] to trigger a reset */ - set32(base_address + MMCHS_SD_SYSCONFIG, MMCHS_SD_SYSCONFIG_SOFTRESET, + mmc_set32(mmchs->regs->SYSCONFIG, MMCHS_SD_SYSCONFIG_SOFTRESET, MMCHS_SD_SYSCONFIG_SOFTRESET); /* Read sysstatus to know when it's done */ spin_init(&spin, SANE_TIMEOUT); - while (!(read32(base_address + MMCHS_SD_SYSSTATUS) + while (!(mmc_read32(mmchs->regs->SYSSTATUS) & MMCHS_SD_SYSSTATUS_RESETDONE)) { if (spin_check(&spin) == FALSE) { log_warn(&log, "mmc init timeout\n"); @@ -104,7 +162,7 @@ mmchs_init(uint32_t instance) } /* Set SD default capabilities */ - set32(base_address + MMCHS_SD_CAPA, MMCHS_SD_CAPA_VS_MASK, + mmc_set32(mmchs->regs->CAPA, MMCHS_SD_CAPA_VS_MASK, MMCHS_SD_CAPA_VS18 | MMCHS_SD_CAPA_VS30); /* TRM mentions MMCHS_SD_CUR_CAPA but does not describe how to limit @@ -129,34 +187,32 @@ mmchs_init(uint32_t instance) /* * wake-up configuration */ - set32(base_address + MMCHS_SD_SYSCONFIG, mask, value); + mmc_set32(mmchs->regs->SYSCONFIG, mask, value); /* Wake-up on sd interrupt for SDIO */ - set32(base_address + MMCHS_SD_HCTL, MMCHS_SD_HCTL_IWE, - MMCHS_SD_HCTL_IWE_EN); + mmc_set32(mmchs->regs->HCTL, MMCHS_SD_HCTL_IWE, MMCHS_SD_HCTL_IWE_EN); /* * MMC host and bus configuration */ - /* Configure data and command transfer (1 bit mode) */ - set32(base_address + MMCHS_SD_CON, MMCHS_SD_CON_DW8, - MMCHS_SD_CON_DW8_1BIT); - set32(base_address + MMCHS_SD_HCTL, MMCHS_SD_HCTL_DTW, + /* Configure data and command transfer (1 bit mode) switching to + * higher bit modes happens after a card is detected */ + mmc_set32(mmchs->regs->CON, MMCHS_SD_CON_DW8, MMCHS_SD_CON_DW8_1BIT); + mmc_set32(mmchs->regs->HCTL, MMCHS_SD_HCTL_DTW, MMCHS_SD_HCTL_DTW_1BIT); /* Configure card voltage to 3.0 volt */ - set32(base_address + MMCHS_SD_HCTL, MMCHS_SD_HCTL_SDVS, + mmc_set32(mmchs->regs->HCTL, MMCHS_SD_HCTL_SDVS, MMCHS_SD_HCTL_SDVS_VS30); /* Power on the host controller and wait for the * MMCHS_SD_HCTL_SDBP_POWER_ON to be set */ - set32(base_address + MMCHS_SD_HCTL, MMCHS_SD_HCTL_SDBP, + mmc_set32(mmchs->regs->HCTL, MMCHS_SD_HCTL_SDBP, MMCHS_SD_HCTL_SDBP_ON); - // /* 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) + while ((mmc_read32(mmchs->regs->HCTL) & MMCHS_SD_HCTL_SDBP) != MMCHS_SD_HCTL_SDBP_ON) { if (spin_check(&spin) == FALSE) { log_warn(&log, "mmc init timeout SDBP not set\n"); @@ -165,21 +221,16 @@ mmchs_init(uint32_t instance) } /* Enable internal clock and clock to the card */ - set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_ICE, + mmc_set32(mmchs->regs->SYSCTL, MMCHS_SD_SYSCTL_ICE, 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, - (0x2 << 6)); + mmchs_set_bus_freq(HSMMCSD_0_INIT_FREQ); - set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_CEN, + mmc_set32(mmchs->regs->SYSCTL, MMCHS_SD_SYSCTL_CEN, MMCHS_SD_SYSCTL_CEN_EN); spin_init(&spin, SANE_TIMEOUT); - while ((read32(base_address + MMCHS_SD_SYSCTL) & MMCHS_SD_SYSCTL_ICS) + while ((mmc_read32(mmchs->regs->SYSCTL) & MMCHS_SD_SYSCTL_ICS) != MMCHS_SD_SYSCTL_ICS_STABLE) { if (spin_check(&spin) == FALSE) { log_warn(&log, "clock not stable\n"); @@ -192,33 +243,30 @@ mmchs_init(uint32_t instance) */ /* Enable command interrupt */ - set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_CC_ENABLE, + mmc_set32(mmchs->regs->IE, MMCHS_SD_IE_CC_ENABLE, MMCHS_SD_IE_CC_ENABLE_ENABLE); /* Enable transfer complete interrupt */ - set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_TC_ENABLE, + mmc_set32(mmchs->regs->IE, MMCHS_SD_IE_TC_ENABLE, MMCHS_SD_IE_TC_ENABLE_ENABLE); /* enable error interrupts */ - set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_ERROR_MASK, 0xffffffffu); + mmc_set32(mmchs->regs->IE, MMCHS_SD_IE_ERROR_MASK, 0xffffffffu); /* clear the error interrupts */ - set32(base_address + MMCHS_SD_STAT, MMCHS_SD_STAT_ERROR_MASK, - 0xffffffffu); + mmc_set32(mmchs->regs->SD_STAT, 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 */ - set32(base_address + MMCHS_SD_CON, MMCHS_SD_CON_INIT, - MMCHS_SD_CON_INIT_INIT); + mmc_set32(mmchs->regs->CON, MMCHS_SD_CON_INIT, MMCHS_SD_CON_INIT_INIT); /* command 0 , type other commands not response etc) */ - write32(base_address + MMCHS_SD_CMD, 0x00); + mmc_write32(mmchs->regs->CMD, 0x00); spin_init(&spin, SANE_TIMEOUT); - while ((read32(base_address + MMCHS_SD_STAT) & MMCHS_SD_STAT_CC) + while ((mmc_read32(mmchs->regs->SD_STAT) & MMCHS_SD_STAT_CC) != MMCHS_SD_STAT_CC_RAISED) { - if (read32(base_address + MMCHS_SD_STAT) & 0x8000) { + if (mmc_read32(mmchs->regs->SD_STAT) & 0x8000) { log_warn(&log, "%s, error stat %x\n", - __FUNCTION__, - read32(base_address + MMCHS_SD_STAT)); + __FUNCTION__, mmc_read32(mmchs->regs->SD_STAT)); return 1; } @@ -229,29 +277,30 @@ mmchs_init(uint32_t instance) } /* clear the cc interrupt status */ - set32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_CC_ENABLE, + mmc_set32(mmchs->regs->SD_STAT, 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 */ - set32(base_address + MMCHS_SD_CON, MMCHS_SD_CON_INIT, + mmc_set32(mmchs->regs->CON, MMCHS_SD_CON_INIT, MMCHS_SD_CON_INIT_NOINIT); /* Set timeout */ - set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_DTO, + mmc_set32(mmchs->regs->SYSCTL, MMCHS_SD_SYSCTL_DTO, MMCHS_SD_SYSCTL_DTO_2POW27); /* Clean the MMCHS_SD_STAT register */ - write32(base_address + MMCHS_SD_STAT, 0xffffffffu); + mmc_write32(mmchs->regs->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); + if (sys_irqsetpolicy(mmchs->irq_nr, 0, &hook_id) != OK) { + log_warn(&log, "mmc: couldn't set IRQ policy %d\n", + mmchs->irq_nr); return 1; } /* enable signaling from MMC controller towards interrupt controller */ - write32(base_address + MMCHS_SD_ISE, 0xffffffffu); + mmc_write32(mmchs->regs->ISE, 0xffffffffu); #endif return 0; @@ -260,13 +309,13 @@ mmchs_init(uint32_t instance) void intr_deassert(int mask) { - if (read32(base_address + MMCHS_SD_STAT) & 0x8000) { + if (mmc_read32(mmchs->regs->SD_STAT) & 0x8000) { 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, + mmc_read32(mmchs->regs->SD_STAT)); + mmc_set32(mmchs->regs->SD_STAT, MMCHS_SD_STAT_ERROR_MASK, 0xffffffffu); } else { - write32(base_address + MMCHS_SD_STAT, mask); + mmc_write32(mmchs->regs->SD_STAT, mask); } } @@ -280,16 +329,15 @@ handle_bwr() /* handle buffer write ready interrupts. These happen in a non * predictable way (eg. we send a request but don't know if we are * first doing to get a request completed before we are allowed to - * send the data to the harware or not */ + * send the data to the hardware or not */ uint32_t value; uint32_t count; - assert(read32(base_address + - MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BWE_EN); + assert(mmc_read32(mmchs->regs->PSTATE) & MMCHS_SD_PSTATE_BWE_EN); assert(io_data != NULL); for (count = 0; count < io_len; count += 4) { - while (!(read32(base_address + - MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BWE_EN)) { + while (!(mmc_read32(mmchs->regs-> + PSTATE) & MMCHS_SD_PSTATE_BWE_EN)) { log_warn(&log, "Error expected Buffer to be write enabled(%d)\n", count); @@ -298,7 +346,7 @@ handle_bwr() *((char *) &value + 1) = io_data[count + 1]; *((char *) &value + 2) = io_data[count + 2]; *((char *) &value + 3) = io_data[count + 3]; - write32(base_address + MMCHS_SD_DATA, value); + mmc_write32(mmchs->regs->DATA, value); } intr_deassert(MMCHS_SD_IE_BWR_ENABLE); /* expect buffer to be write enabled */ @@ -315,13 +363,12 @@ handle_brr() uint32_t count; /* Problem BRE should be true */ - assert(read32(base_address + - MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BRE_EN); + assert(mmc_read32(mmchs->regs->PSTATE) & MMCHS_SD_PSTATE_BRE_EN); assert(io_data != NULL); for (count = 0; count < io_len; count += 4) { - value = read32(base_address + MMCHS_SD_DATA); + value = mmc_read32(mmchs->regs->DATA); io_data[count] = *((char *) &value); io_data[count + 1] = *((char *) &value + 1); io_data[count + 2] = *((char *) &value + 2); @@ -336,7 +383,7 @@ static void mmchs_hw_intr(unsigned int irqs) { log_warn(&log, "Hardware interrupt left over (0x%08lx)\n", - read32(base_address + MMCHS_SD_STAT)); + mmc_read32(mmchs->regs->SD_STAT)); #ifdef USE_INTR if (sys_irqenable(&hook_id) != OK) @@ -377,8 +424,8 @@ intr_wait(int mask) break; case HARDWARE: while ((v = - read32(base_address + - MMCHS_SD_STAT)) != 0) { + mmc_read32(mmchs->regs->SD_STAT)) != + 0) { if (v & MMCHS_SD_IE_BWR_ENABLE) { handle_bwr(); continue; @@ -392,7 +439,7 @@ intr_wait(int mask) /* this is the normal return * path, the mask given * matches the pending - * interrupt. canel the alarm + * interrupt. cancel the alarm * and return */ sys_setalarm(0, 0); return 0; @@ -415,14 +462,14 @@ intr_wait(int mask) break; default: /* - * unhandled message. queue it and + * unhandled notify message. Queue it and * handle it in the blockdriver loop. */ blockdriver_mq_queue(&m, ipc_status); } } else { /* - * unhandled message. queue it and handle it in the + * unhandled message. Queue it and handle it in the * blockdriver loop. */ blockdriver_mq_queue(&m, ipc_status); @@ -437,7 +484,7 @@ intr_wait(int mask) int counter = 0; while (1 == 1) { counter++; - v = read32(base_address + MMCHS_SD_STAT); + v = mmc_read32(mmchs->regs->SD_STAT); if (spin_check(&spin) == FALSE) { log_warn(&log, "Timeout waiting for interrupt (%d) value 0x%08x mask 0x%08x\n", @@ -471,15 +518,15 @@ mmchs_send_cmd(uint32_t command, uint32_t arg) /* Read current interrupt status and fail it an interrupt is already * asserted */ - assert(read32(base_address + MMCHS_SD_STAT) == 0); + assert(mmc_read32(mmchs->regs->SD_STAT) == 0); /* Set arguments */ - write32(base_address + MMCHS_SD_ARG, arg); + mmc_write32(mmchs->regs->ARG, arg); /* Set command */ - set32(base_address + MMCHS_SD_CMD, MMCHS_SD_CMD_MASK, command); + mmc_set32(mmchs->regs->CMD, MMCHS_SD_CMD_MASK, command); if (intr_wait(MMCHS_SD_STAT_CC)) { - uint32_t v = read32(base_address + MMCHS_SD_STAT); + uint32_t v = mmc_read32(mmchs->regs->SD_STAT); intr_deassert(MMCHS_SD_STAT_CC); log_warn(&log, "Failure waiting for interrupt 0x%lx\n", v); return 1; @@ -491,7 +538,7 @@ mmchs_send_cmd(uint32_t command, uint32_t arg) /* * Command with busy response *CAN* also set the TC bit if they exit busy */ - if ((read32(base_address + MMCHS_SD_STAT) + if ((mmc_read32(mmchs->regs->SD_STAT) & MMCHS_SD_IE_TC_ENABLE_ENABLE) == 0) { log_warn(&log, "TC should be raised\n"); } @@ -509,6 +556,8 @@ mmc_send_cmd(struct mmc_command *c) uint32_t cmd, arg; cmd = MMCHS_SD_CMD_INDX_CMD(c->cmd); arg = c->args; + assert(c->data_type == DATA_NONE || c->data_type == DATA_READ + || c->data_type == DATA_WRITE); switch (c->resp_type) { case RESP_LEN_48_CHK_BUSY: @@ -520,7 +569,7 @@ mmc_send_cmd(struct mmc_command *c) case RESP_LEN_136: cmd |= MMCHS_SD_CMD_RSP_TYPE_136B; break; - case NO_RESPONSE: + case RESP_NO_RESPONSE: cmd |= MMCHS_SD_CMD_RSP_TYPE_NO_RESP; break; default: @@ -528,36 +577,35 @@ mmc_send_cmd(struct mmc_command *c) } /* read single block */ - if ((c->cmd == MMC_READ_BLOCK_SINGLE) || (c->cmd == SD_APP_SEND_SCR)) { + if (c->data_type == DATA_READ) { cmd |= MMCHS_SD_CMD_DP_DATA; /* Command with data transfer */ cmd |= MMCHS_SD_CMD_MSBS_SINGLE; /* single block */ cmd |= MMCHS_SD_CMD_DDIR_READ; /* read data from card */ } /* write single block */ - if (c->cmd == MMC_WRITE_BLOCK_SINGLE) { + if (c->data_type == DATA_WRITE) { cmd |= MMCHS_SD_CMD_DP_DATA; /* Command with data transfer */ cmd |= MMCHS_SD_CMD_MSBS_SINGLE; /* single block */ cmd |= MMCHS_SD_CMD_DDIR_WRITE; /* write to the card */ } /* check we are in a sane state */ - if ((read32(base_address + MMCHS_SD_STAT) & 0xffffu)) { + if ((mmc_read32(mmchs->regs->SD_STAT) & 0xffffu)) { 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); + __FUNCTION__, mmc_read32(mmchs->regs->SD_STAT)); + mmc_write32(mmchs->regs->SD_STAT, 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 */ - set32(base_address + MMCHS_SD_IE, + mmc_set32(mmchs->regs->IE, MMCHS_SD_IE_BRR_ENABLE, MMCHS_SD_IE_BRR_ENABLE_ENABLE); } else { - set32(base_address + MMCHS_SD_IE, + mmc_set32(mmchs->regs->IE, MMCHS_SD_IE_BWR_ENABLE, MMCHS_SD_IE_BWR_ENABLE_ENABLE); } @@ -565,7 +613,7 @@ mmc_send_cmd(struct mmc_command *c) io_len = c->data_len; assert(io_len <= 0xFFF); /* only 12 bits */ assert(io_data != NULL); - set32(base_address + MMCHS_SD_BLK, MMCHS_SD_BLK_BLEN, io_len); + mmc_set32(mmchs->regs->BLK, MMCHS_SD_BLK_BLEN, io_len); } ret = mmchs_send_cmd(cmd, arg); @@ -581,11 +629,11 @@ mmc_send_cmd(struct mmc_command *c) return 1; } - write32(base_address + MMCHS_SD_STAT, + mmc_write32(mmchs->regs->SD_STAT, MMCHS_SD_IE_TC_ENABLE_CLEAR); /* disable the bbr interrupt */ - set32(base_address + MMCHS_SD_IE, + mmc_set32(mmchs->regs->IE, MMCHS_SD_IE_BRR_ENABLE, MMCHS_SD_IE_BRR_ENABLE_DISABLE); } else { @@ -598,7 +646,7 @@ mmc_send_cmd(struct mmc_command *c) } intr_deassert(MMCHS_SD_IE_TC_ENABLE_CLEAR); - set32(base_address + MMCHS_SD_IE, + mmc_set32(mmchs->regs->IE, MMCHS_SD_IE_BWR_ENABLE, MMCHS_SD_IE_BWR_ENABLE_DISABLE); @@ -609,15 +657,15 @@ mmc_send_cmd(struct mmc_command *c) switch (c->resp_type) { case RESP_LEN_48_CHK_BUSY: case RESP_LEN_48: - c->resp[0] = read32(base_address + MMCHS_SD_RSP10); + c->resp[0] = mmc_read32(mmchs->regs->RSP10); break; case RESP_LEN_136: - c->resp[0] = read32(base_address + MMCHS_SD_RSP10); - c->resp[1] = read32(base_address + MMCHS_SD_RSP32); - c->resp[2] = read32(base_address + MMCHS_SD_RSP54); - c->resp[3] = read32(base_address + MMCHS_SD_RSP76); + c->resp[0] = mmc_read32(mmchs->regs->RSP10); + c->resp[1] = mmc_read32(mmchs->regs->RSP32); + c->resp[2] = mmc_read32(mmchs->regs->RSP54); + c->resp[3] = mmc_read32(mmchs->regs->RSP76); break; - case NO_RESPONSE: + case RESP_NO_RESPONSE: break; default: return 1; @@ -632,12 +680,11 @@ mmc_send_app_cmd(struct sd_card_regs *card, struct mmc_command *c) struct mmc_command command; command.cmd = MMC_APP_CMD; command.resp_type = RESP_LEN_48; + command.data_type = DATA_NONE; command.args = MMC_ARG_RCA(card->rca); - if (mmc_send_cmd(&command)) { return 1; } - return mmc_send_cmd(c); } @@ -646,7 +693,8 @@ card_goto_idle_state() { struct mmc_command command; command.cmd = MMC_GO_IDLE_STATE; - command.resp_type = NO_RESPONSE; + command.resp_type = RESP_NO_RESPONSE; + command.data_type = DATA_NONE; command.args = 0x00; if (mmc_send_cmd(&command)) { // Failure @@ -659,8 +707,9 @@ int card_identification() { struct mmc_command command; - command.cmd = MMC_SEND_EXT_CSD; + command.cmd = SD_SEND_IF_COND; /* Send CMD8 */ command.resp_type = RESP_LEN_48; + command.data_type = DATA_NONE; command.args = MMCHS_SD_ARG_CMD8_VHS | MMCHS_SD_ARG_CMD8_CHECK_PATTERN; if (mmc_send_cmd(&command)) { @@ -687,6 +736,7 @@ card_query_voltage_and_type(struct sd_card_regs *card) command.cmd = SD_APP_OP_COND; command.resp_type = RESP_LEN_48; + command.data_type = DATA_NONE; /* 0x1 << 30 == send HCS (Host capacity support) and get OCR register */ command.args = @@ -698,7 +748,7 @@ card_query_voltage_and_type(struct sd_card_regs *card) if (mmc_send_app_cmd(card, &command)) { return 1; } - /* @todo wait for max 1 ms */ + spin_init(&spin, SANE_TIMEOUT); while (!(command.resp[0] & MMC_OCR_MEM_READY)) { @@ -707,6 +757,7 @@ card_query_voltage_and_type(struct sd_card_regs *card) * register */ command.cmd = SD_APP_OP_COND; command.resp_type = RESP_LEN_48; + command.data_type = DATA_NONE; /* 0x1 << 30 == send HCS (Host capacity support) */ command.args = MMC_OCR_3_3V_3_4V | MMC_OCR_3_2V_3_3V | MMC_OCR_3_1V_3_2V | MMC_OCR_3_0V_3_1V | MMC_OCR_2_9V_3_0V @@ -737,6 +788,7 @@ card_identify(struct sd_card_regs *card) /* Send cmd 2 (all_send_cid) and expect 136 bits response */ command.cmd = MMC_ALL_SEND_CID; command.resp_type = RESP_LEN_136; + command.data_type = DATA_NONE; command.args = MMC_ARG_RCA(0x0); /* RCA=0000 */ if (mmc_send_cmd(&command)) { @@ -750,6 +802,7 @@ card_identify(struct sd_card_regs *card) command.cmd = MMC_SET_RELATIVE_ADDR; command.resp_type = RESP_LEN_48; + command.data_type = DATA_NONE; command.args = 0x0; /* RCA=0000 */ /* R6 response */ @@ -774,6 +827,7 @@ card_csd(struct sd_card_regs *card) /* send_csd -> r2 response */ command.cmd = MMC_SEND_CSD; command.resp_type = RESP_LEN_136; + command.data_type = DATA_NONE; command.args = MMC_ARG_RCA(card->rca); /* card rca */ if (mmc_send_cmd(&command)) { @@ -785,14 +839,12 @@ 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; } - /* sanity check */ - // log_warn(&log,"size = %llu bytes\n", (long long - // unsigned)SD_CSD_V2_CAPACITY( card->csd) * 512); return 0; } @@ -803,6 +855,7 @@ select_card(struct sd_card_regs *card) command.cmd = MMC_SELECT_CARD; command.resp_type = RESP_LEN_48_CHK_BUSY; + command.data_type = DATA_NONE; command.args = MMC_ARG_RCA(card->rca); /* card rca */ if (mmc_send_cmd(&command)) { @@ -826,6 +879,7 @@ card_scr(struct sd_card_regs *card) /* send_csd -> r2 response */ command.cmd = SD_APP_SEND_SCR; command.resp_type = RESP_LEN_48; + command.data_type = DATA_READ; command.args = 0xaaaaaaaa; command.data = buffer; command.data_len = 8; @@ -836,7 +890,7 @@ card_scr(struct sd_card_regs *card) p = (uint8_t *) card->scr; - /* hussle */ + /* copy the data to card->scr */ for (c = 7; c >= 0; c--) { *p++ = buffer[c]; } @@ -865,6 +919,7 @@ enable_4bit_mode(struct sd_card_regs *card) /* set transfer width */ command.cmd = SD_APP_SET_BUS_WIDTH; command.resp_type = RESP_LEN_48; + command.data_type = DATA_NONE; command.args = 2; /* 4 bits */ if (mmc_send_app_cmd(card, &command)) { @@ -873,9 +928,100 @@ enable_4bit_mode(struct sd_card_regs *card) return 1; } /* now configure the controller to use 4 bit access */ - set32(base_address + MMCHS_SD_HCTL, MMCHS_SD_HCTL_DTW, + mmc_set32(mmchs->regs->HCTL, MMCHS_SD_HCTL_DTW, MMCHS_SD_HCTL_DTW_4BIT); + return 0; + } + return 1; /* expect 4 bits mode to work so having a card + * that doesn't support 4 bits mode */ +} + +void +dump_char(char *out, char in) +{ + int i; + memset(out, 0, 9); + for (i = 0; i < 8; i++) { + out[i] = ((in >> i) & 0x1) ? '1' : '0'; + } + +} + +void +dump(uint8_t * data, int len) +{ + int c; + char digit[4][9]; + char *p = data; + + for (c = 0; c < len;) { + memset(digit, 0, sizeof(digit)); + if (c++ < len) + dump_char(digit[0], *data++); + if (c++ < len) + dump_char(digit[1], *data++); + if (c++ < len) + dump_char(digit[2], *data++); + if (c++ < len) + dump_char(digit[3], *data++); + printf("%x %s %s %s %s\n", c, digit[0], digit[1], digit[2], + digit[3]); } +} + +int +mmc_switch(int function, int value, uint8_t * data) +{ + struct mmc_command command; + + /* function index */ + int findex, fshift; + findex = function - 1; + fshift = findex << 2; /* bits used per function */ + + command.cmd = MMC_SWITCH; + command.resp_type = RESP_LEN_48; + command.data_type = DATA_READ; + command.data = data; + command.data_len = 64; + command.args = (1 << 31) | (0x00ffffff & ~(0xf << fshift)); + command.args |= (value << fshift); + if (mmc_send_cmd(&command)) { + log_warn(&log, "Failed to set device in high speed mode\n"); + return 1; + } + // 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; } @@ -888,6 +1034,7 @@ read_single_block(struct sd_card_regs *card, command.cmd = MMC_READ_BLOCK_SINGLE; command.args = blknr; command.resp_type = RESP_LEN_48; + command.data_type = DATA_READ; command.data = buf; command.data_len = 512; @@ -908,6 +1055,7 @@ write_single_block(struct sd_card_regs *card, command.cmd = MMC_WRITE_BLOCK_SINGLE; command.args = blknr; command.resp_type = RESP_LEN_48; + command.data_type = DATA_WRITE; command.data = buf; command.data_len = 512; @@ -983,6 +1131,7 @@ mmchs_card_initialize(struct sd_slot *slot) log_warn(&log, "Failed to do card_query_voltage_and_type\n"); return NULL; } + if (card_identify(&slot->card.regs)) { log_warn(&log, "Failed to identify card\n"); return NULL; @@ -1009,6 +1158,11 @@ 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; + } + 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 */ @@ -1020,6 +1174,7 @@ mmchs_card_initialize(struct sd_slot *slot) 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; @@ -1067,7 +1222,7 @@ mmchs_card_release(struct sd_card *card) /* TODO:Set card state */ /* now configure the controller to use 4 bit access */ - set32(base_address + MMCHS_SD_HCTL, MMCHS_SD_HCTL_DTW, + mmc_set32(mmchs->regs->HCTL, MMCHS_SD_HCTL_DTW, MMCHS_SD_HCTL_DTW_1BIT); return OK; @@ -1079,6 +1234,12 @@ host_initialize_host_structure_mmchs(struct mmc_host *host) /* Initialize the basic data structures host slots and cards */ int i; +#ifdef AM335X + mmchs = &bone_sdcard; +#endif +#ifdef DM37XX + mmchs = &bbxm_sdcard; +#endif host->host_set_instance = mmchs_host_set_instance; host->host_init = mmchs_host_init; host->set_log_level = mmchs_set_log_level; diff --git a/drivers/mmc/omap_mmc.h b/drivers/mmc/omap_mmc.h index 03ceefbf1..19091e3cd 100644 --- a/drivers/mmc/omap_mmc.h +++ b/drivers/mmc/omap_mmc.h @@ -1,36 +1,105 @@ -///* TODO: Rename to MMCH_0_REG_BASE and add the base address for the other items */ -#ifdef AM335X -#define MMCHS1_REG_BASE 0x48060000 -#endif - -//#ifdef AM_DM37x_Multimedia_Device - -#ifdef DM37XX -#define MMCHS1_REG_BASE 0x4809C000 -#endif -//#define MMCHS2_REG_BASE 0x480B4000 -//#define MMCHS3_REG_BASE 0x480AD000 -//#endif - -#define MMCHS_SD_SYSCONFIG 0x110 /* SD system configuration */ -#define MMCHS_SD_SYSSTATUS 0x114 /* SD system status */ -#define MMCHS_SD_CON 0x12c /* Configuration (functional mode,card initialization etc) */ -#define MMCHS_SD_BLK 0x204 /* Transfer length configuration */ -#define MMCHS_SD_ARG 0x208 /* Command argument bit 38-8 of command format*/ -#define MMCHS_SD_CMD 0x20c /* Command and transfer mode */ -#define MMCHS_SD_RSP10 0x210 /* Command response 0 and 1 */ -#define MMCHS_SD_RSP32 0x214 /* Command response 2 and 3 */ -#define MMCHS_SD_RSP54 0x218 /* Command response 4 and 5 */ -#define MMCHS_SD_RSP76 0x21c /* Command response 6 and 7 */ -#define MMCHS_SD_DATA 0x220 /* Data register */ -#define MMCHS_SD_PSTATE 0x224 /* Present state */ -#define MMCHS_SD_HCTL 0x228 /* Host control(power ,wake-up and transfer) */ -#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 */ +struct omap_mmchs_registers; + +struct omap_mmchs { + vir_bytes io_base; + vir_bytes io_size; + phys_bytes hw_base;/* HW address */ + int irq_nr; + struct omap_mmchs_registers * regs; +}; + +struct omap_mmchs_registers { + /* SD system configuration */ + vir_bytes SYSCONFIG; + /* SD system status */ + vir_bytes SYSSTATUS; + /* Configuration (functional mode,card initialization etc) */ + vir_bytes CON; + /* Transfer length configuration */ + vir_bytes BLK; + /* Command argument bit 38-8 of command format*/ + vir_bytes ARG; + /* Command and transfer mode */ + vir_bytes CMD; + /* SDMA System address */ + vir_bytes SDMASA; + /* Command response 0 and 1 */ + vir_bytes RSP10; + /* Command response 2 and 3 */ + vir_bytes RSP32; + /* Command response 4 and 5 */ + vir_bytes RSP54; + /* Command response 6 and 7 */ + vir_bytes RSP76; + /* Data register */ + vir_bytes DATA; + /* Present state */ + vir_bytes PSTATE; + /* Host control(power ,wake-up and transfer) */ + vir_bytes HCTL; + /* SD System control (reset,clocks and timeout) */ + vir_bytes SYSCTL; + /* SD Interrupt status */ + vir_bytes SD_STAT; + /* SD Interrupt Enable register */ + vir_bytes IE; + /* SD Interrupt Signal Enable register */ + vir_bytes ISE; + /* Capabilities of the host controller */ + vir_bytes CAPA; + /* Current capabilities of the host controller */ + vir_bytes CUR_CAPA; +}; + +/* version used on the AM335x */ +static struct omap_mmchs_registers regs_v1 = { + .SYSCONFIG = 0x110, + .SYSSTATUS = 0x114, + .CON = 0x12c, + .BLK = 0x204, + .ARG = 0x208, + .CMD = 0x20c, + .SDMASA = 0x200, + .RSP10 = 0x210, + .RSP32 = 0x214, + .RSP54 = 0x218, + .RSP76 = 0x21c, + .DATA = 0x220, + .PSTATE = 0x224, + .HCTL = 0x228, + .SYSCTL = 0x22c, + .SD_STAT = 0x230, + .IE = 0x234, + .ISE = 0x238, + .CAPA = 0x240, + .CUR_CAPA = 0x248, +}; + +/* version used on the DM37xx */ +/* DM and AM have the same register but shifted by 0x100. */ +static struct omap_mmchs_registers regs_v0 = { + .SYSCONFIG = 0x010, + .SYSSTATUS = 0x014, + .CON = 0x02c, + .BLK = 0x104, + .ARG = 0x108, + .CMD = 0x10c, + .SDMASA = 0x100, + .RSP10 = 0x110, + .RSP32 = 0x114, + .RSP54 = 0x118, + .RSP76 = 0x11c, + .DATA = 0x120, + .PSTATE = 0x124, + .HCTL = 0x128, + .SYSCTL = 0x12c, + .SD_STAT = 0x130, + .IE = 0x134, + .ISE = 0x138, + .CAPA = 0x140, + .CUR_CAPA = 0x148, +}; + #define MMCHS_SD_SYSCONFIG_AUTOIDLE (0x1 << 0) /* Internal clock gating strategy */ #define MMCHS_SD_SYSCONFIG_AUTOIDLE_DIS (0x0 << 0) /* Clocks are free running */