From 8ce3150cd6f526f48f9fed3abb549f578ce67694 Mon Sep 17 00:00:00 2001 From: Kees Jongenburger Date: Wed, 16 Oct 2013 09:23:00 +0200 Subject: [PATCH] arm:mmc driver small cleanup. --- drivers/mmc/mmchost.h | 27 +++++----- drivers/mmc/mmchost_mmchs.c | 103 +++++++++++++++++++++++++++++------- drivers/mmc/omap_mmc.h | 3 ++ drivers/mmc/sdmmcreg.h | 1 + 4 files changed, 100 insertions(+), 34 deletions(-) diff --git a/drivers/mmc/mmchost.h b/drivers/mmc/mmchost.h index bad9d0911..0b2a4f276 100644 --- a/drivers/mmc/mmchost.h +++ b/drivers/mmc/mmchost.h @@ -39,28 +39,27 @@ struct mmc_host; struct sd_card_regs { - uint32_t cid[4]; /* Card Identification */ - uint32_t rca; /* Relative card address */ - uint32_t dsr; /* Driver stage register */ - uint32_t csd[4]; /* Card specific data */ - uint32_t scr[2]; /* SD configuration */ - uint32_t ocr; /* Operation conditions */ - uint32_t ssr[5]; /* SD Status */ - uint32_t csr; /* Card status */ + uint32_t cid[4]; /* Card Identification */ + uint32_t rca; /* Relative card address */ + uint32_t dsr; /* Driver stage register */ + uint32_t csd[4]; /* Card specific data */ + uint32_t scr[2]; /* SD configuration */ + uint32_t ocr; /* Operation conditions */ + uint32_t ssr[5]; /* SD Status */ + uint32_t csr; /* Card status */ }; +#define RESP_LEN_48_CHK_BUSY (3<<0) +#define RESP_LEN_48 (2<<0) +#define RESP_LEN_136 (1<<0) +#define NO_RESPONSE (0<<0) + /* 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 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..f9a76ced8 100644 --- a/drivers/mmc/mmchost_mmchs.c +++ b/drivers/mmc/mmchost_mmchs.c @@ -43,6 +43,11 @@ static int hook_id = 1; #define SANE_TIMEOUT 500000 /* 500 ms */ +/* 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,8 +57,33 @@ static struct log log = { .log_func = default_log }; +/** + * MMC use memory mapped IO and base_address is the + * base address for the controller in use. + */ 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 */ + +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); + set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_CLKD, + (clkd << 6)); +} + /* * Initialize the MMC controller given a certain * instance. this driver only handles a single @@ -69,19 +99,24 @@ mmchs_init(uint32_t instance) spin_t spin; mr.mr_base = MMCHS1_REG_BASE; - mr.mr_limit = MMCHS1_REG_BASE + 0x400; + mr.mr_limit = MMCHS1_REG_BASE + MMCHS1_REG_BASE_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); + (uint32_t) vm_map_phys(SELF, (void *) MMCHS1_REG_BASE, MMCHS1_REG_BASE_SIZE); + if (base_address == (uint32_t) MAP_FAILED) panic("Unable to map MMC memory"); #ifdef DM37XX + /* DM and AM have the same register but shifted by 0x100. instead of redefining the registers + * we simply move the start offset + */ base_address = (unsigned long) base_address - 0x100; #endif @@ -139,7 +174,8 @@ mmchs_init(uint32_t instance) * MMC host and bus configuration */ - /* Configure data and command transfer (1 bit mode) */ + /* Configure data and command transfer (1 bit mode) switching + * to higher bit modes happens after a card is detected */ 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, @@ -154,7 +190,6 @@ mmchs_init(uint32_t instance) set32(base_address + MMCHS_SD_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) != MMCHS_SD_HCTL_SDBP_ON) { @@ -168,12 +203,8 @@ mmchs_init(uint32_t instance) set32(base_address + MMCHS_SD_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, MMCHS_SD_SYSCTL_CEN_EN); @@ -247,7 +278,7 @@ mmchs_init(uint32_t instance) #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); + log_warn(&log,"mmc: couldn't set IRQ policy %d\n", OMAP3_MMC1_IRQ); return 1; } /* enable signaling from MMC controller towards interrupt controller */ @@ -280,7 +311,7 @@ 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 + @@ -392,7 +423,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 +446,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); @@ -698,7 +729,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)) { @@ -790,9 +821,6 @@ card_csd(struct sd_card_regs *card) return 1; } - /* sanity check */ - // log_warn(&log,"size = %llu bytes\n", (long long - // unsigned)SD_CSD_V2_CAPACITY( card->csd) * 512); return 0; } @@ -836,7 +864,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]; } @@ -875,7 +903,35 @@ enable_4bit_mode(struct sd_card_regs *card) /* now configure the controller to use 4 bit access */ set32(base_address + MMCHS_SD_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 */ +} + +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 + */ + log_info(&log, + "Enabling high speed mode\n"); + + 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; } @@ -983,6 +1039,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 +1066,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 +1082,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; diff --git a/drivers/mmc/omap_mmc.h b/drivers/mmc/omap_mmc.h index 03ceefbf1..2f3161455 100644 --- a/drivers/mmc/omap_mmc.h +++ b/drivers/mmc/omap_mmc.h @@ -8,6 +8,9 @@ #ifdef DM37XX #define MMCHS1_REG_BASE 0x4809C000 #endif + +/* The size of the memory mapped register */ +#define MMCHS1_REG_BASE_SIZE 0x2ff //#define MMCHS2_REG_BASE 0x480B4000 //#define MMCHS3_REG_BASE 0x480AD000 //#endif diff --git a/drivers/mmc/sdmmcreg.h b/drivers/mmc/sdmmcreg.h index d9f3e1c91..a5577b9b5 100644 --- a/drivers/mmc/sdmmcreg.h +++ b/drivers/mmc/sdmmcreg.h @@ -308,6 +308,7 @@ #define SCR_SD_BUS_WIDTHS(scr) MMC_RSP_BITS((scr), 48, 4) #define SCR_SD_BUS_WIDTHS_1BIT (1 << 0) /* 1bit (DAT0) */ #define SCR_SD_BUS_WIDTHS_4BIT (1 << 2) /* 4bit (DAT0-3) */ +#define SCR_SD_SPEC3(scr) MMC_RSP_BITS((scr), 47, 1) #define SCR_RESERVED(scr) MMC_RSP_BITS((scr), 32, 16) #define SCR_RESERVED2(scr) MMC_RSP_BITS((scr), 0, 32)