107cbc27cSLeonardo Fogel #include <minix/blockdriver.h>
207cbc27cSLeonardo Fogel #include <minix/board.h>
307cbc27cSLeonardo Fogel #include <minix/log.h>
407cbc27cSLeonardo Fogel #include <minix/mmio.h>
507cbc27cSLeonardo Fogel #include <minix/spin.h>
607cbc27cSLeonardo Fogel #include <minix/syslib.h>
707cbc27cSLeonardo Fogel
807cbc27cSLeonardo Fogel #include <sys/mman.h>
907cbc27cSLeonardo Fogel
1007cbc27cSLeonardo Fogel #include "omap_mmc.h"
1107cbc27cSLeonardo Fogel #include "mmchost.h"
1207cbc27cSLeonardo Fogel #include "sdmmcreg.h"
1307cbc27cSLeonardo Fogel
1407cbc27cSLeonardo Fogel /* MINIX IRQ timeout. Twice the host controller data/busy timeout @ 48MHz. */
1507cbc27cSLeonardo Fogel #define IRQ_TIMEOUT 5600000 /* 5,600,000 us */
1607cbc27cSLeonardo Fogel
1707cbc27cSLeonardo Fogel #define MMCHS_TIMEOUT 500000 /* 500,000 us */
1807cbc27cSLeonardo Fogel
1907cbc27cSLeonardo Fogel /* Reference clock frequency divisors: */
2007cbc27cSLeonardo Fogel #define MMCHS_SD_SYSCTL_CLKD_400KHZ 240 /* 96MHz/400kHz */
2107cbc27cSLeonardo Fogel #define MMCHS_SD_SYSCTL_CLKD_26MHZ 4 /* ceiling 96MHz/26MHz */
2207cbc27cSLeonardo Fogel #define MMCHS_SD_SYSCTL_CLKD_52MHZ 2 /* ceiling 96MHz/52MHz */
2307cbc27cSLeonardo Fogel
2407cbc27cSLeonardo Fogel /* The host SD_DATA register is 128 words (512B). */
2507cbc27cSLeonardo Fogel #define SD_DATA_WLEN 128
2607cbc27cSLeonardo Fogel
2707cbc27cSLeonardo Fogel /*
2807cbc27cSLeonardo Fogel * Card initialization timeout, twice the standard:
2907cbc27cSLeonardo Fogel * "The device must complete its initialization within 1 second of the first
3007cbc27cSLeonardo Fogel * CMD1 issued with a valid OCR range." (MMCA, 4.41)
3107cbc27cSLeonardo Fogel */
3207cbc27cSLeonardo Fogel #define CARD_INI_TIMEOUT 2000000 /* 2,000,000 us */
3307cbc27cSLeonardo Fogel
3407cbc27cSLeonardo Fogel /* Card EXT_CSD register fields. */
3507cbc27cSLeonardo Fogel #define MMC_EXT_CSD_SEC_COUNT (*(uint32_t *)&card_ext_csd[212])
3607cbc27cSLeonardo Fogel #define MMC_EXT_CSD_CARD_TYPE (card_ext_csd[196])
3707cbc27cSLeonardo Fogel #define MMC_EXT_CSD_CARD_TYPE_HS_MMC_52MHZ (0x1 << 1)
3807cbc27cSLeonardo Fogel
3907cbc27cSLeonardo Fogel /* Card intended operating voltage range: 2.7V to 3.6V */
4007cbc27cSLeonardo Fogel #define MMC_OCR_VDD_RANGE 0x00FF8000
4107cbc27cSLeonardo Fogel
4207cbc27cSLeonardo Fogel /* Error bits in the card status (R1) response. */
4307cbc27cSLeonardo Fogel #define R1_ERROR_MASK 0xFDFFA080
4407cbc27cSLeonardo Fogel
4507cbc27cSLeonardo Fogel /* Relative Card Address. Must be greater than 1. */
4607cbc27cSLeonardo Fogel #define RCA 0x2
4707cbc27cSLeonardo Fogel
4807cbc27cSLeonardo Fogel /* The card sector size is 512B. */
4907cbc27cSLeonardo Fogel #define SEC_SIZE 512
5007cbc27cSLeonardo Fogel
51*47962876SLeonardo Fogel /*
52*47962876SLeonardo Fogel * AM335x Control Module registers CONF_GPMC_ADn.
53*47962876SLeonardo Fogel * Configuration do multiplex CONF_GPMC_ADn to signals MMC1_DATn (Mode 1).
54*47962876SLeonardo Fogel */
55*47962876SLeonardo Fogel #define CONF_GPMC_AD(N) (0x800 + 4*(N))
56*47962876SLeonardo Fogel #define CONF_GPMC_AD_MASK 0x7F
57*47962876SLeonardo Fogel #define CONF_GPMC_AD_VAL 0x31
58*47962876SLeonardo Fogel
5907cbc27cSLeonardo Fogel /* AM335x MMC1 memory map (physical start address and size). */
6007cbc27cSLeonardo Fogel #define AM335X_MMC1_BASE_ADDR 0x481D8000
6107cbc27cSLeonardo Fogel #define AM335X_MMC1_SIZE (4 << 10)
6207cbc27cSLeonardo Fogel /* AM335x MMC1 interrupt number. */
6307cbc27cSLeonardo Fogel #define AM335X_MMCSD1INT 28
6407cbc27cSLeonardo Fogel
65*47962876SLeonardo Fogel static uint32_t bus_width;
66*47962876SLeonardo Fogel
6707cbc27cSLeonardo Fogel /* AM335x MMCHS registers virtual addresses: virtual base + offset. */
6807cbc27cSLeonardo Fogel static struct omap_mmchs_registers *reg;
6907cbc27cSLeonardo Fogel
7007cbc27cSLeonardo Fogel /* Card registers. */
7107cbc27cSLeonardo Fogel static uint32_t card_csd[4];
7207cbc27cSLeonardo Fogel static uint8_t card_ext_csd[512];
7307cbc27cSLeonardo Fogel
7407cbc27cSLeonardo Fogel static uint32_t card_write_protect;
7507cbc27cSLeonardo Fogel static uint64_t card_size;
7607cbc27cSLeonardo Fogel
7707cbc27cSLeonardo Fogel /* IRQ_HOOK_ID for SYS_IRQCTL kernel call. */
7807cbc27cSLeonardo Fogel static int hook_id = 1;
7907cbc27cSLeonardo Fogel
8007cbc27cSLeonardo Fogel /* Initialize the log system. */
8107cbc27cSLeonardo Fogel static struct log log = {
8207cbc27cSLeonardo Fogel .name = "emmc",
8307cbc27cSLeonardo Fogel .log_level = LEVEL_INFO,
8407cbc27cSLeonardo Fogel .log_func = default_log,
8507cbc27cSLeonardo Fogel };
8607cbc27cSLeonardo Fogel
8707cbc27cSLeonardo Fogel
8807cbc27cSLeonardo Fogel /*
8907cbc27cSLeonardo Fogel * Spin until a register flag is set, or the time runs out.
9007cbc27cSLeonardo Fogel * Return the flag value.
9107cbc27cSLeonardo Fogel */
9207cbc27cSLeonardo Fogel static uint32_t
spin_until_set(uint32_t address,uint32_t flag)9307cbc27cSLeonardo Fogel spin_until_set(uint32_t address, uint32_t flag)
9407cbc27cSLeonardo Fogel {
9507cbc27cSLeonardo Fogel spin_t s;
9607cbc27cSLeonardo Fogel int spin;
9707cbc27cSLeonardo Fogel uint32_t v;
9807cbc27cSLeonardo Fogel
9907cbc27cSLeonardo Fogel spin_init(&s, MMCHS_TIMEOUT);
10007cbc27cSLeonardo Fogel do {
10107cbc27cSLeonardo Fogel spin = spin_check(&s);
10207cbc27cSLeonardo Fogel v = (read32(address) & flag);
10307cbc27cSLeonardo Fogel } while ((v == 0) && (spin == TRUE));
10407cbc27cSLeonardo Fogel
10507cbc27cSLeonardo Fogel return v;
10607cbc27cSLeonardo Fogel }
10707cbc27cSLeonardo Fogel
10807cbc27cSLeonardo Fogel /*
10907cbc27cSLeonardo Fogel * Spin until a register flag is clear, or the time runs out.
11007cbc27cSLeonardo Fogel * Return the flag value.
11107cbc27cSLeonardo Fogel */
11207cbc27cSLeonardo Fogel static uint32_t
spin_until_clear(uint32_t address,uint32_t flag)11307cbc27cSLeonardo Fogel spin_until_clear(uint32_t address, uint32_t flag)
11407cbc27cSLeonardo Fogel {
11507cbc27cSLeonardo Fogel spin_t s;
11607cbc27cSLeonardo Fogel int spin;
11707cbc27cSLeonardo Fogel uint32_t v;
11807cbc27cSLeonardo Fogel
11907cbc27cSLeonardo Fogel spin_init(&s, MMCHS_TIMEOUT);
12007cbc27cSLeonardo Fogel do {
12107cbc27cSLeonardo Fogel spin = spin_check(&s);
12207cbc27cSLeonardo Fogel v = (read32(address) & flag);
12307cbc27cSLeonardo Fogel } while ((v != 0) && (spin == TRUE));
12407cbc27cSLeonardo Fogel
12507cbc27cSLeonardo Fogel return v;
12607cbc27cSLeonardo Fogel }
12707cbc27cSLeonardo Fogel
12807cbc27cSLeonardo Fogel /*
12907cbc27cSLeonardo Fogel * Change the bus clock frequency (divisor).
13007cbc27cSLeonardo Fogel * Return 0 on success, a negative integer on error.
13107cbc27cSLeonardo Fogel */
13207cbc27cSLeonardo Fogel static int
set_bus_clkd(uint32_t clkd)13307cbc27cSLeonardo Fogel set_bus_clkd(uint32_t clkd)
13407cbc27cSLeonardo Fogel {
13507cbc27cSLeonardo Fogel /*
13607cbc27cSLeonardo Fogel * Disable the bus clock, set the clock divider, wait until the
13707cbc27cSLeonardo Fogel * internal clock is stable, enable the bus clock.
13807cbc27cSLeonardo Fogel */
13907cbc27cSLeonardo Fogel set32(reg->SYSCTL, MMCHS_SD_SYSCTL_CEN, MMCHS_SD_SYSCTL_CEN_DIS);
14007cbc27cSLeonardo Fogel set32(reg->SYSCTL, MMCHS_SD_SYSCTL_CLKD, clkd << 6);
14107cbc27cSLeonardo Fogel if (spin_until_set(reg->SYSCTL, MMCHS_SD_SYSCTL_ICS)
14207cbc27cSLeonardo Fogel == MMCHS_SD_SYSCTL_ICS_UNSTABLE)
14307cbc27cSLeonardo Fogel return -1;
14407cbc27cSLeonardo Fogel set32(reg->SYSCTL, MMCHS_SD_SYSCTL_CEN, MMCHS_SD_SYSCTL_CEN_EN);
14507cbc27cSLeonardo Fogel
14607cbc27cSLeonardo Fogel return 0;
14707cbc27cSLeonardo Fogel }
14807cbc27cSLeonardo Fogel
14907cbc27cSLeonardo Fogel /*
15007cbc27cSLeonardo Fogel * Receive an interrupt request.
15107cbc27cSLeonardo Fogel * Return 0 on success, a negative integer on error.
15207cbc27cSLeonardo Fogel */
15307cbc27cSLeonardo Fogel static int
irq_receive(void)15407cbc27cSLeonardo Fogel irq_receive(void)
15507cbc27cSLeonardo Fogel {
15607cbc27cSLeonardo Fogel message m;
15707cbc27cSLeonardo Fogel int ipc_status;
15807cbc27cSLeonardo Fogel
15907cbc27cSLeonardo Fogel while (1) {
16007cbc27cSLeonardo Fogel if (driver_receive(ANY, &m, &ipc_status) != OK)
16107cbc27cSLeonardo Fogel return -1;
16207cbc27cSLeonardo Fogel if (is_ipc_notify(ipc_status)
16307cbc27cSLeonardo Fogel && (_ENDPOINT_P(m.m_source) == CLOCK))
16407cbc27cSLeonardo Fogel return -1;
16507cbc27cSLeonardo Fogel if (is_ipc_notify(ipc_status)
16607cbc27cSLeonardo Fogel && (_ENDPOINT_P(m.m_source) == HARDWARE))
16707cbc27cSLeonardo Fogel return 0;
16807cbc27cSLeonardo Fogel /*
16907cbc27cSLeonardo Fogel * m will be discarded if the driver is out of memory.
17007cbc27cSLeonardo Fogel */
17107cbc27cSLeonardo Fogel blockdriver_mq_queue(&m, ipc_status);
17207cbc27cSLeonardo Fogel }
17307cbc27cSLeonardo Fogel }
17407cbc27cSLeonardo Fogel
17507cbc27cSLeonardo Fogel /*
17607cbc27cSLeonardo Fogel * Wait for an interrupt request.
17707cbc27cSLeonardo Fogel * Return 0 on interrupt, a negative integer on error.
17807cbc27cSLeonardo Fogel */
17907cbc27cSLeonardo Fogel static int
irq_wait(void)18007cbc27cSLeonardo Fogel irq_wait(void)
18107cbc27cSLeonardo Fogel {
18207cbc27cSLeonardo Fogel int r;
18307cbc27cSLeonardo Fogel
18407cbc27cSLeonardo Fogel if (sys_irqenable(&hook_id) != OK)
18507cbc27cSLeonardo Fogel return -1;
18607cbc27cSLeonardo Fogel sys_setalarm(micros_to_ticks(IRQ_TIMEOUT), 0);
18707cbc27cSLeonardo Fogel r = irq_receive();
18807cbc27cSLeonardo Fogel sys_setalarm(0, 0);
18907cbc27cSLeonardo Fogel if (r < 0)
19007cbc27cSLeonardo Fogel sys_irqdisable(&hook_id);
19107cbc27cSLeonardo Fogel
19207cbc27cSLeonardo Fogel return r;
19307cbc27cSLeonardo Fogel }
19407cbc27cSLeonardo Fogel
19507cbc27cSLeonardo Fogel /*
19607cbc27cSLeonardo Fogel * Software reset for mmc_cmd or mmc_dat line.
19707cbc27cSLeonardo Fogel */
19807cbc27cSLeonardo Fogel static void
reset_mmchs_fsm(uint32_t line)19907cbc27cSLeonardo Fogel reset_mmchs_fsm(uint32_t line)
20007cbc27cSLeonardo Fogel {
20107cbc27cSLeonardo Fogel /*
20207cbc27cSLeonardo Fogel * "The proper procedure is: (a) Set to 1 to start reset,
20307cbc27cSLeonardo Fogel * (b) Poll for 1 to identify start of reset, and
20407cbc27cSLeonardo Fogel * (c) Poll for 0 to identify reset is complete." (AM335x TRM)
20507cbc27cSLeonardo Fogel */
20607cbc27cSLeonardo Fogel set32(reg->SYSCTL, line, line);
20707cbc27cSLeonardo Fogel spin_until_set(reg->SYSCTL, line);
20807cbc27cSLeonardo Fogel spin_until_clear(reg->SYSCTL, line);
20907cbc27cSLeonardo Fogel }
21007cbc27cSLeonardo Fogel
21107cbc27cSLeonardo Fogel /*
21207cbc27cSLeonardo Fogel * Send a command to the card.
21307cbc27cSLeonardo Fogel * Return 0 on success, a negative integer on error.
21407cbc27cSLeonardo Fogel */
21507cbc27cSLeonardo Fogel static int
send_cmd(uint32_t arg,uint32_t cmd)21607cbc27cSLeonardo Fogel send_cmd(uint32_t arg, uint32_t cmd)
21707cbc27cSLeonardo Fogel {
21807cbc27cSLeonardo Fogel uint32_t stat;
21907cbc27cSLeonardo Fogel
22007cbc27cSLeonardo Fogel if (read32(reg->PSTATE)
22107cbc27cSLeonardo Fogel & (MMCHS_SD_PSTATE_DATI | MMCHS_SD_PSTATE_CMDI))
22207cbc27cSLeonardo Fogel return -1; /* Issuing of commands is not allowed. */
22307cbc27cSLeonardo Fogel write32(reg->ARG, arg);
22407cbc27cSLeonardo Fogel write32(reg->CMD, cmd);
22507cbc27cSLeonardo Fogel /* Wait for the command completion. */
22607cbc27cSLeonardo Fogel if (irq_wait() < 0)
22707cbc27cSLeonardo Fogel return -1;
22807cbc27cSLeonardo Fogel stat = read32(reg->SD_STAT);
22907cbc27cSLeonardo Fogel /*
23007cbc27cSLeonardo Fogel * Clear only the command status/error bits. The transfer status/error
23107cbc27cSLeonardo Fogel * bits (including ERRI) must be preserved.
23207cbc27cSLeonardo Fogel */
23307cbc27cSLeonardo Fogel write32(reg->SD_STAT, MMCHS_SD_STAT_CIE
23407cbc27cSLeonardo Fogel | MMCHS_SD_STAT_CEB
23507cbc27cSLeonardo Fogel | MMCHS_SD_STAT_CCRC
23607cbc27cSLeonardo Fogel | MMCHS_SD_STAT_CTO
23707cbc27cSLeonardo Fogel | MMCHS_SD_STAT_CC);
23807cbc27cSLeonardo Fogel if (stat & MMCHS_SD_STAT_CTO) {
23907cbc27cSLeonardo Fogel reset_mmchs_fsm(MMCHS_SD_SYSCTL_SRC);
24007cbc27cSLeonardo Fogel return -1;
24107cbc27cSLeonardo Fogel }
24207cbc27cSLeonardo Fogel
24307cbc27cSLeonardo Fogel return 0;
24407cbc27cSLeonardo Fogel }
24507cbc27cSLeonardo Fogel
24607cbc27cSLeonardo Fogel /*
24707cbc27cSLeonardo Fogel * Send a command to the card, and check for errors in the response (R1).
24807cbc27cSLeonardo Fogel * Return 0 on success, a negative integer on error.
24907cbc27cSLeonardo Fogel */
25007cbc27cSLeonardo Fogel static int
send_cmd_check_r1(uint32_t arg,uint32_t cmd)25107cbc27cSLeonardo Fogel send_cmd_check_r1(uint32_t arg, uint32_t cmd)
25207cbc27cSLeonardo Fogel {
25307cbc27cSLeonardo Fogel if (send_cmd(arg, cmd) < 0)
25407cbc27cSLeonardo Fogel return -1;
25507cbc27cSLeonardo Fogel /* Check for card errors in the card response (R1). */
25607cbc27cSLeonardo Fogel if (read32(reg->RSP10) & R1_ERROR_MASK)
25707cbc27cSLeonardo Fogel return -1;
25807cbc27cSLeonardo Fogel
25907cbc27cSLeonardo Fogel return 0;
26007cbc27cSLeonardo Fogel }
26107cbc27cSLeonardo Fogel
26207cbc27cSLeonardo Fogel /* Send CMD0 (GO_IDLE_STATE) command to the card. */
26307cbc27cSLeonardo Fogel static int
go_idle_state(void)26407cbc27cSLeonardo Fogel go_idle_state(void)
26507cbc27cSLeonardo Fogel {
26607cbc27cSLeonardo Fogel return send_cmd(MMC_GO_IDLE_STATE, MMC_GO_IDLE_STATE);
26707cbc27cSLeonardo Fogel }
26807cbc27cSLeonardo Fogel
26907cbc27cSLeonardo Fogel /* Send CMD1 (SEND_OP_COND) command to the card. */
27007cbc27cSLeonardo Fogel static int
send_op_cond(void)27107cbc27cSLeonardo Fogel send_op_cond(void)
27207cbc27cSLeonardo Fogel {
27307cbc27cSLeonardo Fogel uint32_t cmd;
27407cbc27cSLeonardo Fogel
27507cbc27cSLeonardo Fogel /* The driver is capable of handling sector type of addressing. */
27607cbc27cSLeonardo Fogel cmd = MMCHS_SD_CMD_INDX_CMD(MMC_SEND_OP_COND)
27707cbc27cSLeonardo Fogel | MMCHS_SD_CMD_RSP_TYPE_48B;
27807cbc27cSLeonardo Fogel return send_cmd((MMC_OCR_HCS | MMC_OCR_VDD_RANGE), cmd);
27907cbc27cSLeonardo Fogel }
28007cbc27cSLeonardo Fogel
28107cbc27cSLeonardo Fogel /* Send CMD2 (ALL_SEND_CID) command to the card. */
28207cbc27cSLeonardo Fogel static int
all_send_cid(void)28307cbc27cSLeonardo Fogel all_send_cid(void)
28407cbc27cSLeonardo Fogel {
28507cbc27cSLeonardo Fogel uint32_t cmd;
28607cbc27cSLeonardo Fogel
28707cbc27cSLeonardo Fogel cmd = MMCHS_SD_CMD_INDX_CMD(MMC_ALL_SEND_CID)
28807cbc27cSLeonardo Fogel | MMCHS_SD_CMD_CCCE_ENABLE
28907cbc27cSLeonardo Fogel | MMCHS_SD_CMD_RSP_TYPE_136B;
29007cbc27cSLeonardo Fogel return send_cmd(0, cmd);
29107cbc27cSLeonardo Fogel }
29207cbc27cSLeonardo Fogel
29307cbc27cSLeonardo Fogel /* Send CMD3 (SET_RELATIVE_ADDR) command to the card. */
29407cbc27cSLeonardo Fogel static int
set_relative_addr(void)29507cbc27cSLeonardo Fogel set_relative_addr(void)
29607cbc27cSLeonardo Fogel {
29707cbc27cSLeonardo Fogel uint32_t cmd;
29807cbc27cSLeonardo Fogel
29907cbc27cSLeonardo Fogel cmd = MMCHS_SD_CMD_INDX_CMD(MMC_SET_RELATIVE_ADDR)
30007cbc27cSLeonardo Fogel | MMCHS_SD_CMD_CICE_ENABLE
30107cbc27cSLeonardo Fogel | MMCHS_SD_CMD_CCCE_ENABLE
30207cbc27cSLeonardo Fogel | MMCHS_SD_CMD_RSP_TYPE_48B;
30307cbc27cSLeonardo Fogel return send_cmd_check_r1(MMC_ARG_RCA(RCA), cmd);
30407cbc27cSLeonardo Fogel }
30507cbc27cSLeonardo Fogel
30607cbc27cSLeonardo Fogel /* Send CMD6 (SWITCH) command to the card. */
30707cbc27cSLeonardo Fogel static int
mmc_switch(uint32_t access,uint32_t index,uint32_t value)30807cbc27cSLeonardo Fogel mmc_switch(uint32_t access, uint32_t index, uint32_t value)
30907cbc27cSLeonardo Fogel {
31007cbc27cSLeonardo Fogel uint32_t arg, cmd;
31107cbc27cSLeonardo Fogel
31207cbc27cSLeonardo Fogel /* SWITCH argument: [25:24] Access, [23:16] Index, [15:8] Value. */
31307cbc27cSLeonardo Fogel arg = (access << 24) | (index << 16) | (value << 8);
31407cbc27cSLeonardo Fogel cmd = MMCHS_SD_CMD_INDX_CMD(MMC_SWITCH)
31507cbc27cSLeonardo Fogel | MMCHS_SD_CMD_CICE_ENABLE
31607cbc27cSLeonardo Fogel | MMCHS_SD_CMD_CCCE_ENABLE
31707cbc27cSLeonardo Fogel | MMCHS_SD_CMD_RSP_TYPE_48B_BUSY;
31807cbc27cSLeonardo Fogel return send_cmd_check_r1(arg, cmd);
31907cbc27cSLeonardo Fogel }
32007cbc27cSLeonardo Fogel
32107cbc27cSLeonardo Fogel /* Send CMD7 (SELECT_CARD) command to the card. */
32207cbc27cSLeonardo Fogel static int
select_card(void)32307cbc27cSLeonardo Fogel select_card(void)
32407cbc27cSLeonardo Fogel {
32507cbc27cSLeonardo Fogel uint32_t cmd;
32607cbc27cSLeonardo Fogel
32707cbc27cSLeonardo Fogel cmd = MMCHS_SD_CMD_INDX_CMD(MMC_SELECT_CARD)
32807cbc27cSLeonardo Fogel | MMCHS_SD_CMD_CICE_ENABLE
32907cbc27cSLeonardo Fogel | MMCHS_SD_CMD_CCCE_ENABLE
33007cbc27cSLeonardo Fogel | MMCHS_SD_CMD_RSP_TYPE_48B;
33107cbc27cSLeonardo Fogel return send_cmd_check_r1(MMC_ARG_RCA(RCA), cmd);
33207cbc27cSLeonardo Fogel }
33307cbc27cSLeonardo Fogel
33407cbc27cSLeonardo Fogel /* Send CMD8 (SEND_EXT_CSD) command to the card. */
33507cbc27cSLeonardo Fogel static int
send_ext_csd(void)33607cbc27cSLeonardo Fogel send_ext_csd(void)
33707cbc27cSLeonardo Fogel {
33807cbc27cSLeonardo Fogel uint32_t cmd;
33907cbc27cSLeonardo Fogel
34007cbc27cSLeonardo Fogel cmd = MMCHS_SD_CMD_INDX_CMD(MMC_SEND_EXT_CSD)
34107cbc27cSLeonardo Fogel | MMCHS_SD_CMD_DP_DATA
34207cbc27cSLeonardo Fogel | MMCHS_SD_CMD_CICE_ENABLE
34307cbc27cSLeonardo Fogel | MMCHS_SD_CMD_CCCE_ENABLE
34407cbc27cSLeonardo Fogel | MMCHS_SD_CMD_RSP_TYPE_48B
34507cbc27cSLeonardo Fogel | MMCHS_SD_CMD_DDIR_READ;
34607cbc27cSLeonardo Fogel return send_cmd_check_r1(0, cmd);
34707cbc27cSLeonardo Fogel }
34807cbc27cSLeonardo Fogel
34907cbc27cSLeonardo Fogel /* Send CMD9 (SEND_CSD) command to the card. */
35007cbc27cSLeonardo Fogel static int
send_csd(void)35107cbc27cSLeonardo Fogel send_csd(void)
35207cbc27cSLeonardo Fogel {
35307cbc27cSLeonardo Fogel uint32_t cmd;
35407cbc27cSLeonardo Fogel
35507cbc27cSLeonardo Fogel cmd = MMCHS_SD_CMD_INDX_CMD(MMC_SEND_CSD)
35607cbc27cSLeonardo Fogel | MMCHS_SD_CMD_CCCE_ENABLE
35707cbc27cSLeonardo Fogel | MMCHS_SD_CMD_RSP_TYPE_136B;
35807cbc27cSLeonardo Fogel return send_cmd(MMC_ARG_RCA(RCA), cmd);
35907cbc27cSLeonardo Fogel }
36007cbc27cSLeonardo Fogel
36107cbc27cSLeonardo Fogel /* Send CMD13 (SEND_STATUS) command to the card. */
36207cbc27cSLeonardo Fogel static int
send_status(void)36307cbc27cSLeonardo Fogel send_status(void)
36407cbc27cSLeonardo Fogel {
36507cbc27cSLeonardo Fogel uint32_t cmd;
36607cbc27cSLeonardo Fogel
36707cbc27cSLeonardo Fogel cmd = MMCHS_SD_CMD_INDX_CMD(MMC_SEND_STATUS)
36807cbc27cSLeonardo Fogel | MMCHS_SD_CMD_CICE_ENABLE
36907cbc27cSLeonardo Fogel | MMCHS_SD_CMD_CCCE_ENABLE
37007cbc27cSLeonardo Fogel | MMCHS_SD_CMD_RSP_TYPE_48B;
37107cbc27cSLeonardo Fogel return send_cmd_check_r1(MMC_ARG_RCA(RCA), cmd);
37207cbc27cSLeonardo Fogel }
37307cbc27cSLeonardo Fogel
37407cbc27cSLeonardo Fogel /* Send CMD16 (SET_BLOCKLEN) command to the card. */
37507cbc27cSLeonardo Fogel static int
set_blocklen(void)37607cbc27cSLeonardo Fogel set_blocklen(void)
37707cbc27cSLeonardo Fogel {
37807cbc27cSLeonardo Fogel uint32_t cmd;
37907cbc27cSLeonardo Fogel
38007cbc27cSLeonardo Fogel /* Set block length to sector size (512B). */
38107cbc27cSLeonardo Fogel cmd = MMCHS_SD_CMD_INDX_CMD(MMC_SET_BLOCKLEN)
38207cbc27cSLeonardo Fogel | MMCHS_SD_CMD_CICE_ENABLE
38307cbc27cSLeonardo Fogel | MMCHS_SD_CMD_CCCE_ENABLE
38407cbc27cSLeonardo Fogel | MMCHS_SD_CMD_RSP_TYPE_48B;
38507cbc27cSLeonardo Fogel return send_cmd_check_r1(SEC_SIZE, cmd);
38607cbc27cSLeonardo Fogel }
38707cbc27cSLeonardo Fogel
38807cbc27cSLeonardo Fogel /* Send CMD17 (READ_SINGLE_BLOCK) to the card. */
38907cbc27cSLeonardo Fogel static int
read_single_block(uint32_t addr)39007cbc27cSLeonardo Fogel read_single_block(uint32_t addr)
39107cbc27cSLeonardo Fogel {
39207cbc27cSLeonardo Fogel uint32_t cmd;
39307cbc27cSLeonardo Fogel
39407cbc27cSLeonardo Fogel cmd = MMCHS_SD_CMD_INDX_CMD(MMC_READ_BLOCK_SINGLE)
39507cbc27cSLeonardo Fogel | MMCHS_SD_CMD_DP_DATA
39607cbc27cSLeonardo Fogel | MMCHS_SD_CMD_CICE_ENABLE
39707cbc27cSLeonardo Fogel | MMCHS_SD_CMD_CCCE_ENABLE
39807cbc27cSLeonardo Fogel | MMCHS_SD_CMD_RSP_TYPE_48B
39907cbc27cSLeonardo Fogel | MMCHS_SD_CMD_DDIR_READ;
40007cbc27cSLeonardo Fogel return send_cmd_check_r1(addr, cmd);
40107cbc27cSLeonardo Fogel }
40207cbc27cSLeonardo Fogel
40307cbc27cSLeonardo Fogel /* Send CMD24 (WRITE_BLOCK) to the card. */
40407cbc27cSLeonardo Fogel static int
write_block(uint32_t addr)40507cbc27cSLeonardo Fogel write_block(uint32_t addr)
40607cbc27cSLeonardo Fogel {
40707cbc27cSLeonardo Fogel uint32_t cmd;
40807cbc27cSLeonardo Fogel
40907cbc27cSLeonardo Fogel cmd = MMCHS_SD_CMD_INDX_CMD(MMC_WRITE_BLOCK_SINGLE)
41007cbc27cSLeonardo Fogel | MMCHS_SD_CMD_DP_DATA
41107cbc27cSLeonardo Fogel | MMCHS_SD_CMD_CICE_ENABLE
41207cbc27cSLeonardo Fogel | MMCHS_SD_CMD_CCCE_ENABLE
41307cbc27cSLeonardo Fogel | MMCHS_SD_CMD_RSP_TYPE_48B
41407cbc27cSLeonardo Fogel | MMCHS_SD_CMD_DDIR_WRITE;
41507cbc27cSLeonardo Fogel return send_cmd_check_r1(addr, cmd);
41607cbc27cSLeonardo Fogel }
41707cbc27cSLeonardo Fogel
41807cbc27cSLeonardo Fogel /*
41907cbc27cSLeonardo Fogel * Repeat CMD1 until the card is ready, or the time runs out.
42007cbc27cSLeonardo Fogel * Return 0 on ready, a negative integer on error.
42107cbc27cSLeonardo Fogel */
42207cbc27cSLeonardo Fogel static int
repeat_send_op_cond(void)42307cbc27cSLeonardo Fogel repeat_send_op_cond(void)
42407cbc27cSLeonardo Fogel {
42507cbc27cSLeonardo Fogel spin_t s;
42607cbc27cSLeonardo Fogel int spin;
42707cbc27cSLeonardo Fogel uint32_t card_ocr;
42807cbc27cSLeonardo Fogel
42907cbc27cSLeonardo Fogel spin_init(&s, CARD_INI_TIMEOUT);
43007cbc27cSLeonardo Fogel do {
43107cbc27cSLeonardo Fogel spin = spin_check(&s);
43207cbc27cSLeonardo Fogel if (send_op_cond() < 0)
43307cbc27cSLeonardo Fogel return -1;
43407cbc27cSLeonardo Fogel card_ocr = read32(reg->RSP10);
43507cbc27cSLeonardo Fogel } while (((card_ocr & MMC_OCR_MEM_READY) == 0) && (spin == TRUE));
43607cbc27cSLeonardo Fogel
43707cbc27cSLeonardo Fogel if ((card_ocr & MMC_OCR_MEM_READY) == 0)
43807cbc27cSLeonardo Fogel return -1; /* Card is still busy. */
43907cbc27cSLeonardo Fogel
44007cbc27cSLeonardo Fogel return 0;
44107cbc27cSLeonardo Fogel }
44207cbc27cSLeonardo Fogel
44307cbc27cSLeonardo Fogel /*
44407cbc27cSLeonardo Fogel * Read (receive) the busy signal from the card.
44507cbc27cSLeonardo Fogel * Return 0 on success, a negative integer on error.
44607cbc27cSLeonardo Fogel */
44707cbc27cSLeonardo Fogel static int
read_busy(void)44807cbc27cSLeonardo Fogel read_busy(void)
44907cbc27cSLeonardo Fogel {
45007cbc27cSLeonardo Fogel uint32_t stat;
45107cbc27cSLeonardo Fogel /*
45207cbc27cSLeonardo Fogel * The busy signal is optional, but the host controller will assert
45307cbc27cSLeonardo Fogel * SD_STAT[1] TC even if the card does not send it.
45407cbc27cSLeonardo Fogel */
45507cbc27cSLeonardo Fogel if (irq_wait() < 0)
45607cbc27cSLeonardo Fogel return -1;
45707cbc27cSLeonardo Fogel stat = read32(reg->SD_STAT);
45807cbc27cSLeonardo Fogel write32(reg->SD_STAT, MMCHS_SD_STAT_DCRC
45907cbc27cSLeonardo Fogel | MMCHS_SD_STAT_DTO
46007cbc27cSLeonardo Fogel | MMCHS_SD_STAT_TC);
46107cbc27cSLeonardo Fogel if (stat & MMCHS_SD_STAT_ERRI) {
46207cbc27cSLeonardo Fogel reset_mmchs_fsm(MMCHS_SD_SYSCTL_SRD);
46307cbc27cSLeonardo Fogel return -1;
46407cbc27cSLeonardo Fogel }
46507cbc27cSLeonardo Fogel
46607cbc27cSLeonardo Fogel return 0;
46707cbc27cSLeonardo Fogel }
46807cbc27cSLeonardo Fogel
46907cbc27cSLeonardo Fogel /*
47007cbc27cSLeonardo Fogel * Read (receive) data from the card.
47107cbc27cSLeonardo Fogel * Return 0 on success, a negative integer on error.
47207cbc27cSLeonardo Fogel */
47307cbc27cSLeonardo Fogel static int
read_data(uint32_t * data)47407cbc27cSLeonardo Fogel read_data(uint32_t *data)
47507cbc27cSLeonardo Fogel {
47607cbc27cSLeonardo Fogel uint32_t stat, i;
47707cbc27cSLeonardo Fogel
47807cbc27cSLeonardo Fogel /* Wait for BRR interrupt. */
47907cbc27cSLeonardo Fogel if (irq_wait() < 0)
48007cbc27cSLeonardo Fogel return -1;
48107cbc27cSLeonardo Fogel if (read32(reg->SD_STAT) & MMCHS_SD_STAT_BRR) {
48207cbc27cSLeonardo Fogel write32(reg->SD_STAT, MMCHS_SD_STAT_BRR);
48307cbc27cSLeonardo Fogel for (i=SD_DATA_WLEN; i>0; i--)
48407cbc27cSLeonardo Fogel *data++ = read32(reg->DATA);
48507cbc27cSLeonardo Fogel }
48607cbc27cSLeonardo Fogel
48707cbc27cSLeonardo Fogel /* Wait for TC or ERRI interrupt. */
48807cbc27cSLeonardo Fogel if (irq_wait() < 0)
48907cbc27cSLeonardo Fogel return -1;
49007cbc27cSLeonardo Fogel stat = read32(reg->SD_STAT);
49107cbc27cSLeonardo Fogel write32(reg->SD_STAT, MMCHS_SD_STAT_DEB
49207cbc27cSLeonardo Fogel | MMCHS_SD_STAT_DCRC
49307cbc27cSLeonardo Fogel | MMCHS_SD_STAT_DTO
49407cbc27cSLeonardo Fogel | MMCHS_SD_STAT_TC);
49507cbc27cSLeonardo Fogel if (stat & MMCHS_SD_STAT_ERRI) {
49607cbc27cSLeonardo Fogel reset_mmchs_fsm(MMCHS_SD_SYSCTL_SRD);
49707cbc27cSLeonardo Fogel return -1;
49807cbc27cSLeonardo Fogel }
49907cbc27cSLeonardo Fogel
50007cbc27cSLeonardo Fogel return 0;
50107cbc27cSLeonardo Fogel }
50207cbc27cSLeonardo Fogel
50307cbc27cSLeonardo Fogel /*
50407cbc27cSLeonardo Fogel * Write (send) data to the card.
50507cbc27cSLeonardo Fogel * Return 0 on success, a negative integer on error.
50607cbc27cSLeonardo Fogel */
50707cbc27cSLeonardo Fogel static int
write_data(uint32_t * data)50807cbc27cSLeonardo Fogel write_data(uint32_t *data)
50907cbc27cSLeonardo Fogel {
51007cbc27cSLeonardo Fogel uint32_t stat, i;
51107cbc27cSLeonardo Fogel
51207cbc27cSLeonardo Fogel /* Wait for BWR interrupt. */
51307cbc27cSLeonardo Fogel if (irq_wait() < 0)
51407cbc27cSLeonardo Fogel return -1;
51507cbc27cSLeonardo Fogel if (read32(reg->SD_STAT) & MMCHS_SD_STAT_BWR) {
51607cbc27cSLeonardo Fogel write32(reg->SD_STAT, MMCHS_SD_STAT_BWR);
51707cbc27cSLeonardo Fogel for (i=SD_DATA_WLEN; i>0; i--)
51807cbc27cSLeonardo Fogel write32(reg->DATA, *data++);
51907cbc27cSLeonardo Fogel }
52007cbc27cSLeonardo Fogel
52107cbc27cSLeonardo Fogel /* Wait for TC or ERRI interrupt. */
52207cbc27cSLeonardo Fogel if (irq_wait() < 0)
52307cbc27cSLeonardo Fogel return -1;
52407cbc27cSLeonardo Fogel stat = read32(reg->SD_STAT);
52507cbc27cSLeonardo Fogel write32(reg->SD_STAT, MMCHS_SD_STAT_DEB
52607cbc27cSLeonardo Fogel | MMCHS_SD_STAT_DCRC
52707cbc27cSLeonardo Fogel | MMCHS_SD_STAT_DTO
52807cbc27cSLeonardo Fogel | MMCHS_SD_STAT_TC);
52907cbc27cSLeonardo Fogel if (stat & MMCHS_SD_STAT_ERRI) {
53007cbc27cSLeonardo Fogel reset_mmchs_fsm(MMCHS_SD_SYSCTL_SRD);
53107cbc27cSLeonardo Fogel return -1;
53207cbc27cSLeonardo Fogel }
53307cbc27cSLeonardo Fogel
53407cbc27cSLeonardo Fogel return 0;
53507cbc27cSLeonardo Fogel }
53607cbc27cSLeonardo Fogel
53707cbc27cSLeonardo Fogel /*
53807cbc27cSLeonardo Fogel * Read a block from the card.
53907cbc27cSLeonardo Fogel * Return 0 on success, a negative integer on error.
54007cbc27cSLeonardo Fogel */
54107cbc27cSLeonardo Fogel static int
cim_read_block(uint32_t addr,uint32_t * data)54207cbc27cSLeonardo Fogel cim_read_block(uint32_t addr, uint32_t *data)
54307cbc27cSLeonardo Fogel {
54407cbc27cSLeonardo Fogel /* Send CMD17. */
54507cbc27cSLeonardo Fogel if (read_single_block(addr) < 0)
54607cbc27cSLeonardo Fogel return -1;
54707cbc27cSLeonardo Fogel /* Read from the host buffer. */
54807cbc27cSLeonardo Fogel return read_data(data);
54907cbc27cSLeonardo Fogel }
55007cbc27cSLeonardo Fogel
55107cbc27cSLeonardo Fogel /*
55207cbc27cSLeonardo Fogel * Write a block to the card.
55307cbc27cSLeonardo Fogel * Return 0 on success, a negative integer on error.
55407cbc27cSLeonardo Fogel */
55507cbc27cSLeonardo Fogel static int
cim_write_block(uint32_t addr,uint32_t * data)55607cbc27cSLeonardo Fogel cim_write_block(uint32_t addr, uint32_t *data)
55707cbc27cSLeonardo Fogel {
55807cbc27cSLeonardo Fogel /* Send CMD24. */
55907cbc27cSLeonardo Fogel if (write_block(addr) < 0)
56007cbc27cSLeonardo Fogel return -1;
56107cbc27cSLeonardo Fogel /* Write into the host buffer. */
56207cbc27cSLeonardo Fogel if (write_data(data) < 0)
56307cbc27cSLeonardo Fogel return -1;
56407cbc27cSLeonardo Fogel /* CMD13. Check the result of the write operation. */
56507cbc27cSLeonardo Fogel return send_status();
56607cbc27cSLeonardo Fogel }
56707cbc27cSLeonardo Fogel
56807cbc27cSLeonardo Fogel
56907cbc27cSLeonardo Fogel /*
57007cbc27cSLeonardo Fogel * Interface to the MINIX block device driver.
57107cbc27cSLeonardo Fogel */
57207cbc27cSLeonardo Fogel static int
emmc_host_set_instance(struct mmc_host * host,int instance)57307cbc27cSLeonardo Fogel emmc_host_set_instance(struct mmc_host *host, int instance)
57407cbc27cSLeonardo Fogel {
57507cbc27cSLeonardo Fogel if (instance != 0)
57607cbc27cSLeonardo Fogel return EIO;
57707cbc27cSLeonardo Fogel return 0;
57807cbc27cSLeonardo Fogel }
57907cbc27cSLeonardo Fogel
58007cbc27cSLeonardo Fogel /*
58107cbc27cSLeonardo Fogel * Initialize the driver and kernel structures.
58207cbc27cSLeonardo Fogel * Return 0 on success, a negative integer on error.
58307cbc27cSLeonardo Fogel */
58407cbc27cSLeonardo Fogel static int
minix_init(void)58507cbc27cSLeonardo Fogel minix_init(void)
58607cbc27cSLeonardo Fogel {
58707cbc27cSLeonardo Fogel struct minix_mem_range mr;
58807cbc27cSLeonardo Fogel uint32_t v_base;
58907cbc27cSLeonardo Fogel
59007cbc27cSLeonardo Fogel /*
59107cbc27cSLeonardo Fogel * On the BeagleBone Black, the eMMC device is connected to MMC1.
59207cbc27cSLeonardo Fogel * Add the MMC1 memory address range to the process' resources.
59307cbc27cSLeonardo Fogel */
59407cbc27cSLeonardo Fogel mr.mr_base = AM335X_MMC1_BASE_ADDR;
59507cbc27cSLeonardo Fogel mr.mr_limit = AM335X_MMC1_BASE_ADDR + AM335X_MMC1_SIZE - 1;
59607cbc27cSLeonardo Fogel if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != OK)
59707cbc27cSLeonardo Fogel return -1;
59807cbc27cSLeonardo Fogel
59907cbc27cSLeonardo Fogel /* Map the MMC1 physical base address to a virtual address. */
60007cbc27cSLeonardo Fogel v_base = (uint32_t)vm_map_phys(SELF, (void *)mr.mr_base,
60107cbc27cSLeonardo Fogel AM335X_MMC1_SIZE);
60207cbc27cSLeonardo Fogel if (v_base == (uint32_t)MAP_FAILED)
60307cbc27cSLeonardo Fogel return -1;
60407cbc27cSLeonardo Fogel
60507cbc27cSLeonardo Fogel /* Set the registers virtual addresses. */
60607cbc27cSLeonardo Fogel reg = ®s_v1;
60707cbc27cSLeonardo Fogel reg->SYSCONFIG += v_base;
60807cbc27cSLeonardo Fogel reg->SYSSTATUS += v_base;
60907cbc27cSLeonardo Fogel reg->CON += v_base;
61007cbc27cSLeonardo Fogel reg->BLK += v_base;
61107cbc27cSLeonardo Fogel reg->ARG += v_base;
61207cbc27cSLeonardo Fogel reg->CMD += v_base;
61307cbc27cSLeonardo Fogel reg->RSP10 += v_base;
61407cbc27cSLeonardo Fogel reg->RSP32 += v_base;
61507cbc27cSLeonardo Fogel reg->RSP54 += v_base;
61607cbc27cSLeonardo Fogel reg->RSP76 += v_base;
61707cbc27cSLeonardo Fogel reg->DATA += v_base;
61807cbc27cSLeonardo Fogel reg->PSTATE += v_base;
61907cbc27cSLeonardo Fogel reg->HCTL += v_base;
62007cbc27cSLeonardo Fogel reg->SYSCTL += v_base;
62107cbc27cSLeonardo Fogel reg->SD_STAT += v_base;
62207cbc27cSLeonardo Fogel reg->IE += v_base;
62307cbc27cSLeonardo Fogel reg->ISE += v_base;
62407cbc27cSLeonardo Fogel
62507cbc27cSLeonardo Fogel /* Register the MMC1 interrupt number. */
62607cbc27cSLeonardo Fogel if (sys_irqsetpolicy(AM335X_MMCSD1INT, 0, &hook_id) != OK)
62707cbc27cSLeonardo Fogel return -1;
62807cbc27cSLeonardo Fogel
62907cbc27cSLeonardo Fogel return 0;
63007cbc27cSLeonardo Fogel }
63107cbc27cSLeonardo Fogel
63207cbc27cSLeonardo Fogel /*
633*47962876SLeonardo Fogel * Configure the Control Module registers CONF_GPMC_AD4-7.
634*47962876SLeonardo Fogel * Multiplex pins GPMC_AD4-7 to signals MMC1_DAT4-7 (Mode 1).
635*47962876SLeonardo Fogel * Return 0 on success, a negative integer on error.
636*47962876SLeonardo Fogel */
637*47962876SLeonardo Fogel static int
conf_gpmc_ad(void)638*47962876SLeonardo Fogel conf_gpmc_ad(void)
639*47962876SLeonardo Fogel {
640*47962876SLeonardo Fogel uint32_t i;
641*47962876SLeonardo Fogel
642*47962876SLeonardo Fogel for (i=4; i<8; i++) {
643*47962876SLeonardo Fogel if (sys_padconf(CONF_GPMC_AD(i), CONF_GPMC_AD_MASK,
644*47962876SLeonardo Fogel CONF_GPMC_AD_VAL) != OK)
645*47962876SLeonardo Fogel return -1;
646*47962876SLeonardo Fogel }
647*47962876SLeonardo Fogel return 0;
648*47962876SLeonardo Fogel }
649*47962876SLeonardo Fogel
650*47962876SLeonardo Fogel /*
65107cbc27cSLeonardo Fogel * Interface to the MINIX block device driver.
65207cbc27cSLeonardo Fogel * Host controller initialization.
65307cbc27cSLeonardo Fogel * Return 0 on success, a negative integer on error.
65407cbc27cSLeonardo Fogel */
65507cbc27cSLeonardo Fogel static int
emmc_host_init(struct mmc_host * host)65607cbc27cSLeonardo Fogel emmc_host_init(struct mmc_host *host)
65707cbc27cSLeonardo Fogel {
65807cbc27cSLeonardo Fogel struct machine machine;
65907cbc27cSLeonardo Fogel
66007cbc27cSLeonardo Fogel /* The eMMC is present on the BBB only. */
66107cbc27cSLeonardo Fogel sys_getmachine(&machine);
66207cbc27cSLeonardo Fogel if (!BOARD_IS_BBB(machine.board_id))
66307cbc27cSLeonardo Fogel return -1;
66407cbc27cSLeonardo Fogel
66507cbc27cSLeonardo Fogel /* Initialize the driver and kernel structures. */
66607cbc27cSLeonardo Fogel if (minix_init() < 0)
66707cbc27cSLeonardo Fogel return -1;
66807cbc27cSLeonardo Fogel
669*47962876SLeonardo Fogel /*
670*47962876SLeonardo Fogel * Multiplex pins GPMC_AD4-7 to signals MMC1_DAT4-7 (Mode 1), in order
671*47962876SLeonardo Fogel * to allow the use of 8-bit mode.
672*47962876SLeonardo Fogel * U-Boot multiplexes only pins GPMC_AD0-3 to signals MMC1_DAT0-3.
673*47962876SLeonardo Fogel */
674*47962876SLeonardo Fogel if (conf_gpmc_ad() < 0)
675*47962876SLeonardo Fogel bus_width = EXT_CSD_BUS_WIDTH_4;
676*47962876SLeonardo Fogel else
677*47962876SLeonardo Fogel bus_width = EXT_CSD_BUS_WIDTH_8;
678*47962876SLeonardo Fogel
67907cbc27cSLeonardo Fogel /* Reset the host controller. */
68007cbc27cSLeonardo Fogel set32(reg->SYSCONFIG, MMCHS_SD_SYSCONFIG_SOFTRESET,
68107cbc27cSLeonardo Fogel MMCHS_SD_SYSCONFIG_SOFTRESET);
68207cbc27cSLeonardo Fogel if (spin_until_set(reg->SYSSTATUS, MMCHS_SD_SYSSTATUS_RESETDONE)
68307cbc27cSLeonardo Fogel != MMCHS_SD_SYSSTATUS_RESETDONE)
68407cbc27cSLeonardo Fogel return -1;
68507cbc27cSLeonardo Fogel
68607cbc27cSLeonardo Fogel /*
68707cbc27cSLeonardo Fogel * SD_CAPA: "The host driver shall not modify this register after the
68807cbc27cSLeonardo Fogel * initialization." (AM335x TRM)
68907cbc27cSLeonardo Fogel */
69007cbc27cSLeonardo Fogel
69107cbc27cSLeonardo Fogel /*
69207cbc27cSLeonardo Fogel * Set the bus voltage to 3V, and turn the bus power on.
69307cbc27cSLeonardo Fogel * On the BeagleBone Black, the bus voltage is pulled up to 3.3V, but
69407cbc27cSLeonardo Fogel * the MMCHS supports only 1.8V or 3V.
69507cbc27cSLeonardo Fogel */
69607cbc27cSLeonardo Fogel set32(reg->HCTL, MMCHS_SD_HCTL_SDVS, MMCHS_SD_HCTL_SDVS_VS30);
69707cbc27cSLeonardo Fogel set32(reg->HCTL, MMCHS_SD_HCTL_SDBP, MMCHS_SD_HCTL_SDBP_ON);
69807cbc27cSLeonardo Fogel if (spin_until_set(reg->HCTL, MMCHS_SD_HCTL_SDBP)
69907cbc27cSLeonardo Fogel == MMCHS_SD_HCTL_SDBP_OFF)
70007cbc27cSLeonardo Fogel return -1;
70107cbc27cSLeonardo Fogel
70207cbc27cSLeonardo Fogel /* Set the bus clock frequency to FOD (400kHz). */
70307cbc27cSLeonardo Fogel set32(reg->SYSCTL, MMCHS_SD_SYSCTL_CLKD,
70407cbc27cSLeonardo Fogel MMCHS_SD_SYSCTL_CLKD_400KHZ << 6);
70507cbc27cSLeonardo Fogel
70607cbc27cSLeonardo Fogel /* Set data and busy time-out: ~2,6s @ 400kHz.*/
70707cbc27cSLeonardo Fogel set32(reg->SYSCTL, MMCHS_SD_SYSCTL_DTO, MMCHS_SD_SYSCTL_DTO_2POW20);
70807cbc27cSLeonardo Fogel
70907cbc27cSLeonardo Fogel /* Enable the internal clock. */
71007cbc27cSLeonardo Fogel set32(reg->SYSCTL, MMCHS_SD_SYSCTL_ICE, MMCHS_SD_SYSCTL_ICE_EN);
71107cbc27cSLeonardo Fogel if (spin_until_set(reg->SYSCTL, MMCHS_SD_SYSCTL_ICS)
71207cbc27cSLeonardo Fogel == MMCHS_SD_SYSCTL_ICS_UNSTABLE)
71307cbc27cSLeonardo Fogel return -1;
71407cbc27cSLeonardo Fogel
71507cbc27cSLeonardo Fogel /* Enable the bus clock. */
71607cbc27cSLeonardo Fogel set32(reg->SYSCTL, MMCHS_SD_SYSCTL_CEN, MMCHS_SD_SYSCTL_CEN_EN);
71707cbc27cSLeonardo Fogel
71807cbc27cSLeonardo Fogel /*
71907cbc27cSLeonardo Fogel * Set the internal clock gating strategy to automatic, and enable
72007cbc27cSLeonardo Fogel * Smart Idle mode. The host controller does not implement wake-up
72107cbc27cSLeonardo Fogel * request (SWAKEUP pin is not connected).
72207cbc27cSLeonardo Fogel */
72307cbc27cSLeonardo Fogel set32(reg->SYSCONFIG, MMCHS_SD_SYSCONFIG_AUTOIDLE,
72407cbc27cSLeonardo Fogel MMCHS_SD_SYSCONFIG_AUTOIDLE_EN);
72507cbc27cSLeonardo Fogel set32(reg->SYSCONFIG, MMCHS_SD_SYSCONFIG_SIDLEMODE,
72607cbc27cSLeonardo Fogel MMCHS_SD_SYSCONFIG_SIDLEMODE_IDLE);
72707cbc27cSLeonardo Fogel
72807cbc27cSLeonardo Fogel /* The driver reads and writes single 512B blocks. */
72907cbc27cSLeonardo Fogel set32(reg->BLK, MMCHS_SD_BLK_BLEN, SEC_SIZE);
73007cbc27cSLeonardo Fogel
73107cbc27cSLeonardo Fogel /* Enable interrupt status and requests. */
73207cbc27cSLeonardo Fogel write32(reg->IE, MMCHS_SD_IE_ERROR_MASK
73307cbc27cSLeonardo Fogel | MMCHS_SD_IE_BRR_ENABLE_ENABLE
73407cbc27cSLeonardo Fogel | MMCHS_SD_IE_BWR_ENABLE_ENABLE
73507cbc27cSLeonardo Fogel | MMCHS_SD_IE_TC_ENABLE_ENABLE
73607cbc27cSLeonardo Fogel | MMCHS_SD_IE_CC_ENABLE_ENABLE);
73707cbc27cSLeonardo Fogel write32(reg->ISE, MMCHS_SD_IE_ERROR_MASK
73807cbc27cSLeonardo Fogel | MMCHS_SD_IE_BRR_ENABLE_ENABLE
73907cbc27cSLeonardo Fogel | MMCHS_SD_IE_BWR_ENABLE_ENABLE
74007cbc27cSLeonardo Fogel | MMCHS_SD_IE_TC_ENABLE_ENABLE
74107cbc27cSLeonardo Fogel | MMCHS_SD_IE_CC_ENABLE_ENABLE);
74207cbc27cSLeonardo Fogel
74307cbc27cSLeonardo Fogel return 0;
74407cbc27cSLeonardo Fogel }
74507cbc27cSLeonardo Fogel
74607cbc27cSLeonardo Fogel /*
74707cbc27cSLeonardo Fogel * Interface to the MINIX block device driver.
74807cbc27cSLeonardo Fogel * Set the log level.
74907cbc27cSLeonardo Fogel */
75007cbc27cSLeonardo Fogel static void
emmc_set_log_level(int level)75107cbc27cSLeonardo Fogel emmc_set_log_level(int level)
75207cbc27cSLeonardo Fogel {
75307cbc27cSLeonardo Fogel log.log_level = level;
75407cbc27cSLeonardo Fogel }
75507cbc27cSLeonardo Fogel
75607cbc27cSLeonardo Fogel
75707cbc27cSLeonardo Fogel /*
75807cbc27cSLeonardo Fogel * Interface to the MINIX block device driver.
75907cbc27cSLeonardo Fogel * Unused, but declared in mmchost.h.
76007cbc27cSLeonardo Fogel */
76107cbc27cSLeonardo Fogel #if 0
76207cbc27cSLeonardo Fogel static int
76307cbc27cSLeonardo Fogel emmc_host_reset(struct mmc_host *host)
76407cbc27cSLeonardo Fogel {
76507cbc27cSLeonardo Fogel return 0;
76607cbc27cSLeonardo Fogel }
76707cbc27cSLeonardo Fogel #endif
76807cbc27cSLeonardo Fogel
76907cbc27cSLeonardo Fogel /*
77007cbc27cSLeonardo Fogel * Interface to the MINIX block device driver.
77107cbc27cSLeonardo Fogel * Card detection.
77207cbc27cSLeonardo Fogel */
77307cbc27cSLeonardo Fogel static int
emmc_card_detect(struct sd_slot * slot)77407cbc27cSLeonardo Fogel emmc_card_detect(struct sd_slot *slot)
77507cbc27cSLeonardo Fogel {
77607cbc27cSLeonardo Fogel /* The card is detected during card initialization. */
77707cbc27cSLeonardo Fogel return 1;
77807cbc27cSLeonardo Fogel }
77907cbc27cSLeonardo Fogel
78007cbc27cSLeonardo Fogel /*
78107cbc27cSLeonardo Fogel * Interface to the MINIX block device driver.
78207cbc27cSLeonardo Fogel * Card initialization. Also, finish the MMCHS initialization.
78307cbc27cSLeonardo Fogel * Return NULL on error.
78407cbc27cSLeonardo Fogel */
78507cbc27cSLeonardo Fogel static struct sd_card *
emmc_card_initialize(struct sd_slot * slot)78607cbc27cSLeonardo Fogel emmc_card_initialize(struct sd_slot *slot)
78707cbc27cSLeonardo Fogel {
78807cbc27cSLeonardo Fogel uint32_t clkd;
78907cbc27cSLeonardo Fogel
79007cbc27cSLeonardo Fogel /* CMD0 */
79107cbc27cSLeonardo Fogel if (go_idle_state() < 0)
79207cbc27cSLeonardo Fogel return NULL;
79307cbc27cSLeonardo Fogel
79407cbc27cSLeonardo Fogel /*
79507cbc27cSLeonardo Fogel * Set the MMC_CMD line to open drain.
79607cbc27cSLeonardo Fogel * "The host starts the card identification process in open-drain mode
79707cbc27cSLeonardo Fogel * with the identification clock rate FOD." (MMCA, 4.41)
79807cbc27cSLeonardo Fogel */
79907cbc27cSLeonardo Fogel set32(reg->CON, MMCHS_SD_CON_OD, MMCHS_SD_CON_OD_OD);
80007cbc27cSLeonardo Fogel
80107cbc27cSLeonardo Fogel /* CMD1 */
80207cbc27cSLeonardo Fogel if (repeat_send_op_cond() < 0)
80307cbc27cSLeonardo Fogel return NULL;
80407cbc27cSLeonardo Fogel
80507cbc27cSLeonardo Fogel /* CMD2. The driver has no use for the CID. */
80607cbc27cSLeonardo Fogel if (all_send_cid() < 0)
80707cbc27cSLeonardo Fogel return NULL;
80807cbc27cSLeonardo Fogel
80907cbc27cSLeonardo Fogel /* CMD3 */
81007cbc27cSLeonardo Fogel if (set_relative_addr() < 0)
81107cbc27cSLeonardo Fogel return NULL;
81207cbc27cSLeonardo Fogel
81307cbc27cSLeonardo Fogel /*
81407cbc27cSLeonardo Fogel * Set the MMC_CMD line to push-pull.
81507cbc27cSLeonardo Fogel * "When the card is in Stand-by State, communication over the CMD and
81607cbc27cSLeonardo Fogel * DAT lines will be performed in push-pull mode." (MMCA, 4.41)
81707cbc27cSLeonardo Fogel */
81807cbc27cSLeonardo Fogel set32(reg->CON, MMCHS_SD_CON_OD, MMCHS_SD_CON_OD_PP);
81907cbc27cSLeonardo Fogel
82007cbc27cSLeonardo Fogel /* CMD9 */
82107cbc27cSLeonardo Fogel if (send_csd() < 0)
82207cbc27cSLeonardo Fogel return NULL;
82307cbc27cSLeonardo Fogel card_csd[0] = read32(reg->RSP10);
82407cbc27cSLeonardo Fogel card_csd[1] = read32(reg->RSP32);
82507cbc27cSLeonardo Fogel card_csd[2] = read32(reg->RSP54);
82607cbc27cSLeonardo Fogel card_csd[3] = read32(reg->RSP76);
82707cbc27cSLeonardo Fogel
82807cbc27cSLeonardo Fogel /* Card capacity for cards up to 2GB of density. */
82907cbc27cSLeonardo Fogel card_size = (uint64_t)MMC_CSD_CAPACITY(card_csd)
83007cbc27cSLeonardo Fogel << MMC_CSD_READ_BL_LEN(card_csd);
83107cbc27cSLeonardo Fogel
83207cbc27cSLeonardo Fogel card_write_protect = (SD_CSD_PERM_WRITE_PROTECT(card_csd)
83307cbc27cSLeonardo Fogel | SD_CSD_TMP_WRITE_PROTECT(card_csd));
83407cbc27cSLeonardo Fogel if (card_write_protect)
83507cbc27cSLeonardo Fogel log_info(&log, "the eMMC is write protected\n");
83607cbc27cSLeonardo Fogel
83707cbc27cSLeonardo Fogel /* CMD7 */
83807cbc27cSLeonardo Fogel if (select_card() < 0)
83907cbc27cSLeonardo Fogel return NULL;
84007cbc27cSLeonardo Fogel
84107cbc27cSLeonardo Fogel /* CMD8 */
84207cbc27cSLeonardo Fogel if (send_ext_csd() < 0)
84307cbc27cSLeonardo Fogel return NULL;
84407cbc27cSLeonardo Fogel /* Receive the Extended CSD register. */
84507cbc27cSLeonardo Fogel if (read_data((uint32_t *)card_ext_csd) < 0)
84607cbc27cSLeonardo Fogel return NULL;
84707cbc27cSLeonardo Fogel
84807cbc27cSLeonardo Fogel /* Card capacity for densities greater than 2GB. */
84907cbc27cSLeonardo Fogel if (MMC_EXT_CSD_SEC_COUNT > 0)
85007cbc27cSLeonardo Fogel card_size = (uint64_t)MMC_EXT_CSD_SEC_COUNT * SEC_SIZE;
85107cbc27cSLeonardo Fogel
85207cbc27cSLeonardo Fogel /* CMD6. Switch to high-speed mode: EXT_CSD[185] HS_TIMING = 1. */
85307cbc27cSLeonardo Fogel if (mmc_switch(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, 1) < 0)
85407cbc27cSLeonardo Fogel return NULL;
85507cbc27cSLeonardo Fogel /* Wait for the (optional) busy signal. */
85607cbc27cSLeonardo Fogel if (read_busy() < 0)
85707cbc27cSLeonardo Fogel return NULL;
85807cbc27cSLeonardo Fogel /* CMD13. Check the result of the SWITCH operation. */
85907cbc27cSLeonardo Fogel if (send_status() < 0)
86007cbc27cSLeonardo Fogel return NULL;
86107cbc27cSLeonardo Fogel
86207cbc27cSLeonardo Fogel /* Change the bus clock frequency. */
86307cbc27cSLeonardo Fogel if (MMC_EXT_CSD_CARD_TYPE & MMC_EXT_CSD_CARD_TYPE_HS_MMC_52MHZ)
86407cbc27cSLeonardo Fogel clkd = MMCHS_SD_SYSCTL_CLKD_52MHZ; /* 48 MHz */
86507cbc27cSLeonardo Fogel else
86607cbc27cSLeonardo Fogel clkd = MMCHS_SD_SYSCTL_CLKD_26MHZ; /* 24 MHz */
86707cbc27cSLeonardo Fogel if (set_bus_clkd(clkd) < 0)
86807cbc27cSLeonardo Fogel return NULL;
86907cbc27cSLeonardo Fogel
87007cbc27cSLeonardo Fogel /* Set data and busy time-out: ~ 2,8s @ 48MHz.*/
87107cbc27cSLeonardo Fogel set32(reg->SYSCTL, MMCHS_SD_SYSCTL_DTO, MMCHS_SD_SYSCTL_DTO_2POW27);
87207cbc27cSLeonardo Fogel
873*47962876SLeonardo Fogel /* CMD6. Set data bus width. */
87407cbc27cSLeonardo Fogel if (mmc_switch(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_BUS_WIDTH,
875*47962876SLeonardo Fogel bus_width) < 0)
87607cbc27cSLeonardo Fogel return NULL;
87707cbc27cSLeonardo Fogel /* Wait for the (optional) busy signal. */
87807cbc27cSLeonardo Fogel if (read_busy() < 0)
87907cbc27cSLeonardo Fogel return NULL;
88007cbc27cSLeonardo Fogel /* CMD13. Check the result of the SWITCH operation. */
88107cbc27cSLeonardo Fogel if (send_status() < 0)
88207cbc27cSLeonardo Fogel return NULL;
88307cbc27cSLeonardo Fogel
884*47962876SLeonardo Fogel /* Host controller: set data bus width. */
885*47962876SLeonardo Fogel if (bus_width == EXT_CSD_BUS_WIDTH_4)
88607cbc27cSLeonardo Fogel set32(reg->HCTL, MMCHS_SD_HCTL_DTW, MMCHS_SD_HCTL_DTW_4BIT);
887*47962876SLeonardo Fogel else
888*47962876SLeonardo Fogel set32(reg->CON, MMCHS_SD_CON_DW8, MMCHS_SD_CON_DW8_8BITS);
88907cbc27cSLeonardo Fogel
89007cbc27cSLeonardo Fogel /* CMD16. Set block length to sector size (512B). */
89107cbc27cSLeonardo Fogel if (set_blocklen() < 0)
89207cbc27cSLeonardo Fogel return NULL;
89307cbc27cSLeonardo Fogel
89407cbc27cSLeonardo Fogel /* Initialize the block device driver structures. */
89507cbc27cSLeonardo Fogel slot->card.blk_size = SEC_SIZE;
89607cbc27cSLeonardo Fogel slot->card.blk_count = card_size / SEC_SIZE;
89707cbc27cSLeonardo Fogel slot->card.state = SD_MODE_DATA_TRANSFER_MODE;
89807cbc27cSLeonardo Fogel slot->card.open_ct = 0;
89907cbc27cSLeonardo Fogel memset(slot->card.part, 0, sizeof(slot->card.part));
90007cbc27cSLeonardo Fogel memset(slot->card.subpart, 0, sizeof(slot->card.subpart));
90107cbc27cSLeonardo Fogel slot->card.part[0].dv_size = card_size;
90207cbc27cSLeonardo Fogel
90307cbc27cSLeonardo Fogel return &(slot->card);
90407cbc27cSLeonardo Fogel }
90507cbc27cSLeonardo Fogel
90607cbc27cSLeonardo Fogel /*
90707cbc27cSLeonardo Fogel * Interface to the MINIX block device driver.
90807cbc27cSLeonardo Fogel * Card release.
90907cbc27cSLeonardo Fogel */
91007cbc27cSLeonardo Fogel static int
emmc_card_release(struct sd_card * card)91107cbc27cSLeonardo Fogel emmc_card_release(struct sd_card *card)
91207cbc27cSLeonardo Fogel {
91307cbc27cSLeonardo Fogel /* Decrements the "in-use count." */
91407cbc27cSLeonardo Fogel card->open_ct--;
91507cbc27cSLeonardo Fogel
91607cbc27cSLeonardo Fogel /*
91707cbc27cSLeonardo Fogel * The block special file is closed, but the driver does not need to
91807cbc27cSLeonardo Fogel * "release" the eMMC, even if the driver is unloaded.
91907cbc27cSLeonardo Fogel */
92007cbc27cSLeonardo Fogel
92107cbc27cSLeonardo Fogel return 0;
92207cbc27cSLeonardo Fogel }
92307cbc27cSLeonardo Fogel
92407cbc27cSLeonardo Fogel /*
92507cbc27cSLeonardo Fogel * Interface to the MINIX block device driver.
92607cbc27cSLeonardo Fogel * Handle unexpected interrupts.
92707cbc27cSLeonardo Fogel */
92807cbc27cSLeonardo Fogel static void
emmc_hw_intr(unsigned int irqs)92907cbc27cSLeonardo Fogel emmc_hw_intr(unsigned int irqs)
93007cbc27cSLeonardo Fogel {
93107cbc27cSLeonardo Fogel log_warn(&log, "register SD_STAT == 0x%08x\n", reg->SD_STAT);
93207cbc27cSLeonardo Fogel }
93307cbc27cSLeonardo Fogel
93407cbc27cSLeonardo Fogel /*
93507cbc27cSLeonardo Fogel * Interface to the MINIX block device driver.
93607cbc27cSLeonardo Fogel * Read/write blocks.
93707cbc27cSLeonardo Fogel * Return the number of blocks read/written, or a negative integer on error.
93807cbc27cSLeonardo Fogel */
93907cbc27cSLeonardo Fogel static int
emmc_read_write(int (* cim_read_write)(uint32_t,uint32_t *),uint32_t blknr,uint32_t count,unsigned char * buf)94007cbc27cSLeonardo Fogel emmc_read_write(int (*cim_read_write)(uint32_t, uint32_t *),
94107cbc27cSLeonardo Fogel uint32_t blknr, uint32_t count, unsigned char *buf)
94207cbc27cSLeonardo Fogel {
94307cbc27cSLeonardo Fogel int blocks, r;
94407cbc27cSLeonardo Fogel uint32_t addr;
94507cbc27cSLeonardo Fogel
94607cbc27cSLeonardo Fogel blocks = 0; /* count of blocks read/written. */
94707cbc27cSLeonardo Fogel r = 0;
94807cbc27cSLeonardo Fogel while ((count > 0) && (r == 0)) {
94907cbc27cSLeonardo Fogel /*
95007cbc27cSLeonardo Fogel * Data address for media =< 2GB is byte address, and data
95107cbc27cSLeonardo Fogel * address for media > 2GB is sector address.
95207cbc27cSLeonardo Fogel */
95307cbc27cSLeonardo Fogel if (card_size <= (2U << 30))
95407cbc27cSLeonardo Fogel addr = blknr * SEC_SIZE;
95507cbc27cSLeonardo Fogel else
95607cbc27cSLeonardo Fogel addr = blknr;
95707cbc27cSLeonardo Fogel
95807cbc27cSLeonardo Fogel r = (*cim_read_write)(addr, (uint32_t *)buf);
95907cbc27cSLeonardo Fogel if (r == 0) {
96007cbc27cSLeonardo Fogel blknr++;
96107cbc27cSLeonardo Fogel count--;
96207cbc27cSLeonardo Fogel buf += SEC_SIZE;
96307cbc27cSLeonardo Fogel blocks++;
96407cbc27cSLeonardo Fogel }
96507cbc27cSLeonardo Fogel else if (blocks == 0)
96607cbc27cSLeonardo Fogel blocks = r;
96707cbc27cSLeonardo Fogel }
96807cbc27cSLeonardo Fogel
96907cbc27cSLeonardo Fogel return blocks;
97007cbc27cSLeonardo Fogel }
97107cbc27cSLeonardo Fogel
97207cbc27cSLeonardo Fogel /*
97307cbc27cSLeonardo Fogel * Interface to the MINIX block device driver.
97407cbc27cSLeonardo Fogel * Read blocks.
97507cbc27cSLeonardo Fogel */
97607cbc27cSLeonardo Fogel static int
emmc_read(struct sd_card * card,uint32_t blknr,uint32_t count,unsigned char * buf)97707cbc27cSLeonardo Fogel emmc_read(struct sd_card *card,
97807cbc27cSLeonardo Fogel uint32_t blknr, uint32_t count, unsigned char *buf)
97907cbc27cSLeonardo Fogel {
98007cbc27cSLeonardo Fogel return emmc_read_write(&cim_read_block, blknr, count, buf);
98107cbc27cSLeonardo Fogel }
98207cbc27cSLeonardo Fogel
98307cbc27cSLeonardo Fogel /*
98407cbc27cSLeonardo Fogel * Interface to the MINIX block device driver.
98507cbc27cSLeonardo Fogel * Write blocks.
98607cbc27cSLeonardo Fogel */
98707cbc27cSLeonardo Fogel static int
emmc_write(struct sd_card * card,uint32_t blknr,uint32_t count,unsigned char * buf)98807cbc27cSLeonardo Fogel emmc_write(struct sd_card *card,
98907cbc27cSLeonardo Fogel uint32_t blknr, uint32_t count, unsigned char *buf)
99007cbc27cSLeonardo Fogel {
99107cbc27cSLeonardo Fogel if (card_write_protect)
99207cbc27cSLeonardo Fogel return -1; /* The card is write protected. */
99307cbc27cSLeonardo Fogel return emmc_read_write(&cim_write_block, blknr, count, buf);
99407cbc27cSLeonardo Fogel }
99507cbc27cSLeonardo Fogel
99607cbc27cSLeonardo Fogel /*
99707cbc27cSLeonardo Fogel * Interface to the MINIX block device driver.
99807cbc27cSLeonardo Fogel * Driver interface registration.
99907cbc27cSLeonardo Fogel */
100007cbc27cSLeonardo Fogel void
host_initialize_host_structure_mmchs(struct mmc_host * host)100107cbc27cSLeonardo Fogel host_initialize_host_structure_mmchs(struct mmc_host *host)
100207cbc27cSLeonardo Fogel {
100307cbc27cSLeonardo Fogel uint32_t i;
100407cbc27cSLeonardo Fogel
100507cbc27cSLeonardo Fogel /* Register the driver interface at the block device driver. */
100607cbc27cSLeonardo Fogel host->host_set_instance = &emmc_host_set_instance;
100707cbc27cSLeonardo Fogel host->host_init = &emmc_host_init;
100807cbc27cSLeonardo Fogel host->set_log_level = &emmc_set_log_level;
100907cbc27cSLeonardo Fogel host->host_reset = NULL;
101007cbc27cSLeonardo Fogel host->card_detect = &emmc_card_detect;
101107cbc27cSLeonardo Fogel host->card_initialize = &emmc_card_initialize;
101207cbc27cSLeonardo Fogel host->card_release = &emmc_card_release;
101307cbc27cSLeonardo Fogel host->hw_intr = &emmc_hw_intr;
101407cbc27cSLeonardo Fogel host->read = &emmc_read;
101507cbc27cSLeonardo Fogel host->write = &emmc_write;
101607cbc27cSLeonardo Fogel for (i=0; i<MAX_SD_SLOTS; i++) {
101707cbc27cSLeonardo Fogel host->slot[i].host = host;
101807cbc27cSLeonardo Fogel host->slot[i].card.state = SD_MODE_UNINITIALIZED;
101907cbc27cSLeonardo Fogel host->slot[i].card.slot = &host->slot[i];
102007cbc27cSLeonardo Fogel }
102107cbc27cSLeonardo Fogel }
102207cbc27cSLeonardo Fogel
102307cbc27cSLeonardo Fogel /*
102407cbc27cSLeonardo Fogel * Interface to the MINIX block device driver.
102507cbc27cSLeonardo Fogel * Unused, but declared in mmchost.h.
102607cbc27cSLeonardo Fogel */
102707cbc27cSLeonardo Fogel void
host_initialize_host_structure_dummy(struct mmc_host * host)102807cbc27cSLeonardo Fogel host_initialize_host_structure_dummy(struct mmc_host *host)
102907cbc27cSLeonardo Fogel {
103007cbc27cSLeonardo Fogel }
1031