This is a respin of a previous series to extend the sdcard boot menu description. Instead of showing the product name and card version, this series shows the product name and card capacity. The card capacity is more likely to mean something to an end-user than a manufacturer's card version.
Kevin O'Connor (6): sdcard: Move sdcard_set_frequency()/sdcard_set_power() in sdcard.c sdcard: Move frequency setting into sdcard_card_setup() sdcard: Move drive registration to sdcard_card_setup() sdcard: Turn card_type into a bitmap and store if card is MMC type sdcard: Display sdcard product name in boot menu sdcard: Obtain card capacity and report it on the boot menu
src/hw/sdcard.c | 219 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 133 insertions(+), 86 deletions(-)
Just code movement; no code changes.
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/hw/sdcard.c | 116 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 58 insertions(+), 58 deletions(-)
diff --git a/src/hw/sdcard.c b/src/hw/sdcard.c index 8e7e954..bf35277 100644 --- a/src/hw/sdcard.c +++ b/src/hw/sdcard.c @@ -293,6 +293,64 @@ sdcard_process_op(struct disk_op_s *op) * Setup ****************************************************************/
+static int +sdcard_set_power(struct sdhci_s *regs) +{ + u32 cap = readl(®s->cap_lo); + u32 volt, vbits; + if (cap & SD_CAPLO_V33) { + volt = 1<<20; + vbits = SPC_V33; + } else if (cap & SD_CAPLO_V30) { + volt = 1<<18; + vbits = SPC_V30; + } else if (cap & SD_CAPLO_V18) { + volt = 1<<7; + vbits = SPC_V18; + } else { + dprintf(1, "SD controller unsupported volt range (%x)\n", cap); + return -1; + } + writeb(®s->power_control, 0); + msleep(SDHCI_POWER_OFF_TIME); + writeb(®s->power_control, vbits | SPC_POWER_ON); + msleep(SDHCI_POWER_ON_TIME); + return volt; +} + +static int +sdcard_set_frequency(struct sdhci_s *regs, u32 khz) +{ + u16 ver = readw(®s->controller_version); + u32 cap = readl(®s->cap_lo); + u32 base_freq = (cap >> SD_CAPLO_BASECLOCK_SHIFT) & SD_CAPLO_BASECLOCK_MASK; + if (!base_freq) { + dprintf(1, "Unknown base frequency for SD controller\n"); + return -1; + } + // Set new frequency + u32 divisor = DIV_ROUND_UP(base_freq * 1000, khz); + u16 creg; + if ((ver & 0xff) <= 0x01) { + divisor = divisor > 1 ? 1 << __fls(divisor-1) : 0; + creg = (divisor & SCC_SDCLK_MASK) << SCC_SDCLK_SHIFT; + } else { + divisor = DIV_ROUND_UP(divisor, 2); + creg = (divisor & SCC_SDCLK_MASK) << SCC_SDCLK_SHIFT; + creg |= (divisor & SCC_SDCLK_HI_MASK) >> SCC_SDCLK_HI_RSHIFT; + } + dprintf(3, "sdcard_set_frequency %d %d %x\n", base_freq, khz, creg); + writew(®s->clock_control, 0); + writew(®s->clock_control, creg | SCC_INTERNAL_ENABLE); + // Wait for frequency to become active + int ret = sdcard_waitw(®s->clock_control, SCC_STABLE); + if (ret < 0) + return ret; + // Enable SD clock + writew(®s->clock_control, creg | SCC_INTERNAL_ENABLE | SCC_CLOCK_ENABLE); + return 0; +} + // Initialize an SD card static int sdcard_card_setup(struct sdhci_s *regs, int volt) @@ -357,64 +415,6 @@ sdcard_card_setup(struct sdhci_s *regs, int volt) return card_type; }
-static int -sdcard_set_power(struct sdhci_s *regs) -{ - u32 cap = readl(®s->cap_lo); - u32 volt, vbits; - if (cap & SD_CAPLO_V33) { - volt = 1<<20; - vbits = SPC_V33; - } else if (cap & SD_CAPLO_V30) { - volt = 1<<18; - vbits = SPC_V30; - } else if (cap & SD_CAPLO_V18) { - volt = 1<<7; - vbits = SPC_V18; - } else { - dprintf(1, "SD controller unsupported volt range (%x)\n", cap); - return -1; - } - writeb(®s->power_control, 0); - msleep(SDHCI_POWER_OFF_TIME); - writeb(®s->power_control, vbits | SPC_POWER_ON); - msleep(SDHCI_POWER_ON_TIME); - return volt; -} - -static int -sdcard_set_frequency(struct sdhci_s *regs, u32 khz) -{ - u16 ver = readw(®s->controller_version); - u32 cap = readl(®s->cap_lo); - u32 base_freq = (cap >> SD_CAPLO_BASECLOCK_SHIFT) & SD_CAPLO_BASECLOCK_MASK; - if (!base_freq) { - dprintf(1, "Unknown base frequency for SD controller\n"); - return -1; - } - // Set new frequency - u32 divisor = DIV_ROUND_UP(base_freq * 1000, khz); - u16 creg; - if ((ver & 0xff) <= 0x01) { - divisor = divisor > 1 ? 1 << __fls(divisor-1) : 0; - creg = (divisor & SCC_SDCLK_MASK) << SCC_SDCLK_SHIFT; - } else { - divisor = DIV_ROUND_UP(divisor, 2); - creg = (divisor & SCC_SDCLK_MASK) << SCC_SDCLK_SHIFT; - creg |= (divisor & SCC_SDCLK_HI_MASK) >> SCC_SDCLK_HI_RSHIFT; - } - dprintf(3, "sdcard_set_frequency %d %d %x\n", base_freq, khz, creg); - writew(®s->clock_control, 0); - writew(®s->clock_control, creg | SCC_INTERNAL_ENABLE); - // Wait for frequency to become active - int ret = sdcard_waitw(®s->clock_control, SCC_STABLE); - if (ret < 0) - return ret; - // Enable SD clock - writew(®s->clock_control, creg | SCC_INTERNAL_ENABLE | SCC_CLOCK_ENABLE); - return 0; -} - // Setup and configure an SD card controller static void sdcard_controller_setup(struct sdhci_s *regs, int prio)
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/hw/sdcard.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/src/hw/sdcard.c b/src/hw/sdcard.c index bf35277..a60fa92 100644 --- a/src/hw/sdcard.c +++ b/src/hw/sdcard.c @@ -355,9 +355,14 @@ sdcard_set_frequency(struct sdhci_s *regs, u32 khz) static int sdcard_card_setup(struct sdhci_s *regs, int volt) { + // Set controller to initialization clock rate + int ret = sdcard_set_frequency(regs, 400); + if (ret) + return ret; + msleep(SDHCI_CLOCK_ON_TIME); // Reset card u32 param[4] = { }; - int ret = sdcard_pio(regs, SC_GO_IDLE_STATE, param); + ret = sdcard_pio(regs, SC_GO_IDLE_STATE, param); if (ret) return ret; // Let card know SDHC/SDXC is supported and confirm voltage @@ -412,6 +417,10 @@ sdcard_card_setup(struct sdhci_s *regs, int volt) ret = sdcard_pio(regs, SC_SELECT_DESELECT_CARD, param); if (ret) return ret; + // Set controller to data transfer clock rate + ret = sdcard_set_frequency(regs, 25000); + if (ret) + return ret; return card_type; }
@@ -438,18 +447,11 @@ sdcard_controller_setup(struct sdhci_s *regs, int prio) int volt = sdcard_set_power(regs); if (volt < 0) return; - int ret = sdcard_set_frequency(regs, 400); - if (ret) - goto fail; - msleep(SDHCI_CLOCK_ON_TIME);
// Initialize card int card_type = sdcard_card_setup(regs, volt); if (card_type < 0) goto fail; - ret = sdcard_set_frequency(regs, 25000); - if (ret) - goto fail;
// Register drive struct sddrive_s *drive = malloc_fseg(sizeof(*drive));
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/hw/sdcard.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/src/hw/sdcard.c b/src/hw/sdcard.c index a60fa92..5b3ffb1 100644 --- a/src/hw/sdcard.c +++ b/src/hw/sdcard.c @@ -353,8 +353,9 @@ sdcard_set_frequency(struct sdhci_s *regs, u32 khz)
// Initialize an SD card static int -sdcard_card_setup(struct sdhci_s *regs, int volt) +sdcard_card_setup(struct sddrive_s *drive, int volt, int prio) { + struct sdhci_s *regs = drive->regs; // Set controller to initialization clock rate int ret = sdcard_set_frequency(regs, 400); if (ret) @@ -402,7 +403,7 @@ sdcard_card_setup(struct sdhci_s *regs, int volt) } msleep(5); // Avoid flooding log when debugging } - int card_type = (param[0] & SR_OCR_CCS) ? SF_HC : SF_SC; + drive->card_type = (param[0] & SR_OCR_CCS) ? SF_HC : SF_SC; // Select card param[0] = 0x00; ret = sdcard_pio(regs, SC_ALL_SEND_CID, param); @@ -421,7 +422,13 @@ sdcard_card_setup(struct sdhci_s *regs, int volt) ret = sdcard_set_frequency(regs, 25000); if (ret) return ret; - return card_type; + // Register drive + drive->drive.blksize = DISK_SECTOR_SIZE; + drive->drive.sectors = (u64)-1; // XXX + dprintf(1, "Found SD Card at %p\n", regs); + char *desc = znprintf(MAXDESCSIZE, "SD Card"); // XXX + boot_add_hd(&drive->drive, desc, prio); + return 0; }
// Setup and configure an SD card controller @@ -449,11 +456,6 @@ sdcard_controller_setup(struct sdhci_s *regs, int prio) return;
// Initialize card - int card_type = sdcard_card_setup(regs, volt); - if (card_type < 0) - goto fail; - - // Register drive struct sddrive_s *drive = malloc_fseg(sizeof(*drive)); if (!drive) { warn_noalloc(); @@ -461,14 +463,12 @@ sdcard_controller_setup(struct sdhci_s *regs, int prio) } memset(drive, 0, sizeof(*drive)); drive->drive.type = DTYPE_SDCARD; - drive->drive.blksize = DISK_SECTOR_SIZE; - drive->drive.sectors = (u64)-1; // XXX drive->regs = regs; - drive->card_type = card_type; - - dprintf(1, "Found SD Card at %p\n", regs); - char *desc = znprintf(MAXDESCSIZE, "SD Card"); // XXX - boot_add_hd(&drive->drive, desc, prio); + int ret = sdcard_card_setup(drive, volt, prio); + if (ret) { + free(drive); + goto fail; + } return; fail: writeb(®s->power_control, 0);
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/hw/sdcard.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/src/hw/sdcard.c b/src/hw/sdcard.c index 5b3ffb1..336314e 100644 --- a/src/hw/sdcard.c +++ b/src/hw/sdcard.c @@ -139,8 +139,8 @@ struct sddrive_s { };
// SD card types -#define SF_SC 1 -#define SF_HC 2 +#define SF_MMC (1<<0) +#define SF_HIGHCAPACITY (1<<1)
// Repeatedly read a u16 register until any bit in a given mask is set static int @@ -228,7 +228,7 @@ sdcard_pio_transfer(struct sddrive_s *drive, int cmd, u32 addr u16 tmode = ((count > 1 ? ST_MULTIPLE|ST_AUTO_CMD12|ST_BLOCKCOUNT : 0) | (isread ? ST_READ : 0)); writew(&drive->regs->transfer_mode, tmode); - if (drive->card_type < SF_HC) + if (!(drive->card_type & SF_HIGHCAPACITY)) addr *= DISK_SECTOR_SIZE; u32 param[4] = { addr }; int ret = sdcard_pio(drive->regs, cmd, param); @@ -367,8 +367,7 @@ sdcard_card_setup(struct sddrive_s *drive, int volt, int prio) if (ret) return ret; // Let card know SDHC/SDXC is supported and confirm voltage - u32 isMMC = 0, hcs = 0; - u32 vrange = (volt >= (1<<15) ? 0x100 : 0x200) | 0xaa; + u32 hcs = 0, vrange = (volt >= (1<<15) ? 0x100 : 0x200) | 0xaa; param[0] = vrange; ret = sdcard_pio(regs, SC_SEND_IF_COND, param); if (!ret && param[0] == vrange) @@ -382,14 +381,14 @@ sdcard_card_setup(struct sddrive_s *drive, int volt, int prio) ret = sdcard_pio(regs, SC_SEND_OP_COND, param); if (ret) return ret; - isMMC = 1; + drive->card_type |= SF_MMC; hcs = (1<<30); } // Init card u32 end = timer_calc(SDHCI_POWERUP_TIMEOUT); for (;;) { param[0] = hcs | volt; // high-capacity support and voltage level - if (isMMC) + if (drive->card_type & SF_MMC) ret = sdcard_pio(regs, SC_SEND_OP_COND, param); else ret = sdcard_pio_app(regs, SC_APP_SEND_OP_COND, param); @@ -403,17 +402,17 @@ sdcard_card_setup(struct sddrive_s *drive, int volt, int prio) } msleep(5); // Avoid flooding log when debugging } - drive->card_type = (param[0] & SR_OCR_CCS) ? SF_HC : SF_SC; + drive->card_type |= (param[0] & SR_OCR_CCS) ? SF_HIGHCAPACITY : 0; // Select card param[0] = 0x00; ret = sdcard_pio(regs, SC_ALL_SEND_CID, param); if (ret) return ret; - param[0] = isMMC ? 0x0001 << 16 : 0x00; + param[0] = drive->card_type & SF_MMC ? 0x0001 << 16 : 0x00; ret = sdcard_pio(regs, SC_SEND_RELATIVE_ADDR, param); if (ret) return ret; - u16 rca = isMMC ? 0x0001 : param[0] >> 16; + u16 rca = drive->card_type & SF_MMC ? 0x0001 : param[0] >> 16; param[0] = rca << 16; ret = sdcard_pio(regs, SC_SELECT_DESELECT_CARD, param); if (ret)
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/hw/sdcard.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/src/hw/sdcard.c b/src/hw/sdcard.c index 336314e..d5ea40c 100644 --- a/src/hw/sdcard.c +++ b/src/hw/sdcard.c @@ -408,6 +408,8 @@ sdcard_card_setup(struct sddrive_s *drive, int volt, int prio) ret = sdcard_pio(regs, SC_ALL_SEND_CID, param); if (ret) return ret; + u8 cid[16]; + memcpy(cid, param, sizeof(cid)); param[0] = drive->card_type & SF_MMC ? 0x0001 << 16 : 0x00; ret = sdcard_pio(regs, SC_SEND_RELATIVE_ADDR, param); if (ret) @@ -424,8 +426,14 @@ sdcard_card_setup(struct sddrive_s *drive, int volt, int prio) // Register drive drive->drive.blksize = DISK_SECTOR_SIZE; drive->drive.sectors = (u64)-1; // XXX - dprintf(1, "Found SD Card at %p\n", regs); - char *desc = znprintf(MAXDESCSIZE, "SD Card"); // XXX + char pnm[7] = {}; + int i; + for (i=0; i < (drive->card_type & SF_MMC ? 6 : 5); i++) + pnm[i] = cid[11-i]; + char *desc = znprintf(MAXDESCSIZE, "%s %s" + , drive->card_type & SF_MMC ? "MMC drive" : "SD card" + , pnm); + dprintf(1, "Found sdcard at %p: %s\n", regs, desc); boot_add_hd(&drive->drive, desc, prio); return 0; }
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/hw/sdcard.c | 48 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-)
diff --git a/src/hw/sdcard.c b/src/hw/sdcard.c index d5ea40c..d80b473 100644 --- a/src/hw/sdcard.c +++ b/src/hw/sdcard.c @@ -68,6 +68,8 @@ struct sdhci_s { #define SC_SEND_RELATIVE_ADDR ((3<<8) | SCB_R48) #define SC_SELECT_DESELECT_CARD ((7<<8) | SCB_R48b) #define SC_SEND_IF_COND ((8<<8) | SCB_R48) +#define SC_SEND_EXT_CSD ((8<<8) | SCB_R48d) +#define SC_SEND_CSD ((9<<8) | SCB_R136) #define SC_READ_SINGLE ((17<<8) | SCB_R48d) #define SC_READ_MULTIPLE ((18<<8) | SCB_R48d) #define SC_WRITE_SINGLE ((24<<8) | SCB_R48d) @@ -351,6 +353,35 @@ sdcard_set_frequency(struct sdhci_s *regs, u32 khz) return 0; }
+// Obtain the disk size of an SD card +static int +sdcard_get_capacity(struct sddrive_s *drive, u8 *csd) +{ + // Original MMC/SD card capacity formula + u16 C_SIZE = (csd[6] >> 6) | (csd[7] << 2) | ((csd[8] & 0x03) << 10); + u8 C_SIZE_MULT = (csd[4] >> 7) | ((csd[5] & 0x03) << 1); + u8 READ_BL_LEN = csd[9] & 0x0f; + u32 count = (C_SIZE+1) << (C_SIZE_MULT + 2 + READ_BL_LEN - 9); + // Check for newer encoding formats. + u8 CSD_STRUCTURE = csd[14] >> 6; + if ((drive->card_type & SF_MMC) && CSD_STRUCTURE >= 2) { + // Get capacity from EXT_CSD register + u8 ext_csd[512]; + int ret = sdcard_pio_transfer(drive, SC_SEND_EXT_CSD, 0, ext_csd, 1); + if (ret) + return ret; + count = *(u32*)&ext_csd[212]; + } else if (!(drive->card_type & SF_MMC) && CSD_STRUCTURE >= 1) { + // High capacity SD card + u32 C_SIZE2 = csd[5] | (csd[6] << 8) | ((csd[7] & 0x3f) << 16); + count = (C_SIZE2+1) << (19-9); + } + // Fill drive struct and return + drive->drive.blksize = DISK_SECTOR_SIZE; + drive->drive.sectors = count; + return 0; +} + // Initialize an SD card static int sdcard_card_setup(struct sddrive_s *drive, int volt, int prio) @@ -403,7 +434,7 @@ sdcard_card_setup(struct sddrive_s *drive, int volt, int prio) msleep(5); // Avoid flooding log when debugging } drive->card_type |= (param[0] & SR_OCR_CCS) ? SF_HIGHCAPACITY : 0; - // Select card + // Select card (get cid, set rca, get csd, select card) param[0] = 0x00; ret = sdcard_pio(regs, SC_ALL_SEND_CID, param); if (ret) @@ -416,6 +447,12 @@ sdcard_card_setup(struct sddrive_s *drive, int volt, int prio) return ret; u16 rca = drive->card_type & SF_MMC ? 0x0001 : param[0] >> 16; param[0] = rca << 16; + ret = sdcard_pio(regs, SC_SEND_CSD, param); + if (ret) + return ret; + u8 csd[16]; + memcpy(csd, param, sizeof(csd)); + param[0] = rca << 16; ret = sdcard_pio(regs, SC_SELECT_DESELECT_CARD, param); if (ret) return ret; @@ -424,15 +461,16 @@ sdcard_card_setup(struct sddrive_s *drive, int volt, int prio) if (ret) return ret; // Register drive - drive->drive.blksize = DISK_SECTOR_SIZE; - drive->drive.sectors = (u64)-1; // XXX + ret = sdcard_get_capacity(drive, csd); + if (ret) + return ret; char pnm[7] = {}; int i; for (i=0; i < (drive->card_type & SF_MMC ? 6 : 5); i++) pnm[i] = cid[11-i]; - char *desc = znprintf(MAXDESCSIZE, "%s %s" + char *desc = znprintf(MAXDESCSIZE, "%s %s %dMiB" , drive->card_type & SF_MMC ? "MMC drive" : "SD card" - , pnm); + , pnm, (u32)(drive->drive.sectors >> 11)); dprintf(1, "Found sdcard at %p: %s\n", regs, desc); boot_add_hd(&drive->drive, desc, prio); return 0;
On Mon, Aug 31, 2015 at 05:51:15PM -0400, Kevin O'Connor wrote:
This is a respin of a previous series to extend the sdcard boot menu description. Instead of showing the product name and card version, this series shows the product name and card capacity. The card capacity is more likely to mean something to an end-user than a manufacturer's card version.
FYI - I committed this series.
-Kevin