summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/mmc/mmc.c251
-rw-r--r--sys/dev/mmc/mmcreg.h19
-rw-r--r--sys/dev/mmc/mmcsd.c210
-rw-r--r--sys/dev/mmc/mmcvar.h2
4 files changed, 333 insertions, 149 deletions
diff --git a/sys/dev/mmc/mmc.c b/sys/dev/mmc/mmc.c
index bfa58a4..c6bce35 100644
--- a/sys/dev/mmc/mmc.c
+++ b/sys/dev/mmc/mmc.c
@@ -85,11 +85,13 @@ struct mmc_ivars {
uint32_t raw_csd[4]; /* Raw bits of the CSD */
uint32_t raw_scr[2]; /* Raw bits of the SCR */
uint8_t raw_ext_csd[512]; /* Raw bits of the EXT_CSD */
+ uint32_t raw_sd_status[16]; /* Raw bits of the SD_STATUS */
uint16_t rca;
enum mmc_card_mode mode;
struct mmc_cid cid; /* cid decoded */
struct mmc_csd csd; /* csd decoded */
struct mmc_scr scr; /* scr decoded */
+ struct mmc_sd_status sd_status; /* SD_STATUS decoded */
u_char read_only; /* True when the device is read-only */
u_char bus_width; /* Bus width to use */
u_char timing; /* Bus timing support */
@@ -97,6 +99,7 @@ struct mmc_ivars {
uint32_t sec_count; /* Card capacity in 512byte blocks */
uint32_t tran_speed; /* Max speed in normal mode */
uint32_t hs_tran_speed; /* Max speed in high speed mode */
+ uint32_t erase_sector; /* Card native erase sector size */
};
#define CMD_RETRIES 3
@@ -723,9 +726,8 @@ mmc_test_bus_width(struct mmc_softc *sc)
}
static uint32_t
-mmc_get_bits(uint32_t *bits, int start, int size)
+mmc_get_bits(uint32_t *bits, int bit_len, int start, int size)
{
- const int bit_len = 128;
const int i = (bit_len / 32) - (start / 32) - 1;
const int shift = start & 31;
uint32_t retval = bits[i] >> shift;
@@ -741,14 +743,14 @@ mmc_decode_cid_sd(uint32_t *raw_cid, struct mmc_cid *cid)
/* There's no version info, so we take it on faith */
memset(cid, 0, sizeof(*cid));
- cid->mid = mmc_get_bits(raw_cid, 120, 8);
- cid->oid = mmc_get_bits(raw_cid, 104, 16);
+ cid->mid = mmc_get_bits(raw_cid, 128, 120, 8);
+ cid->oid = mmc_get_bits(raw_cid, 128, 104, 16);
for (i = 0; i < 5; i++)
- cid->pnm[i] = mmc_get_bits(raw_cid, 96 - i * 8, 8);
- cid->prv = mmc_get_bits(raw_cid, 56, 8);
- cid->psn = mmc_get_bits(raw_cid, 24, 32);
- cid->mdt_year = mmc_get_bits(raw_cid, 12, 8) + 2001;
- cid->mdt_month = mmc_get_bits(raw_cid, 8, 4);
+ cid->pnm[i] = mmc_get_bits(raw_cid, 128, 96 - i * 8, 8);
+ cid->prv = mmc_get_bits(raw_cid, 128, 56, 8);
+ cid->psn = mmc_get_bits(raw_cid, 128, 24, 32);
+ cid->mdt_year = mmc_get_bits(raw_cid, 128, 12, 8) + 2001;
+ cid->mdt_month = mmc_get_bits(raw_cid, 128, 8, 4);
}
static void
@@ -758,14 +760,14 @@ mmc_decode_cid_mmc(uint32_t *raw_cid, struct mmc_cid *cid)
/* There's no version info, so we take it on faith */
memset(cid, 0, sizeof(*cid));
- cid->mid = mmc_get_bits(raw_cid, 120, 8);
- cid->oid = mmc_get_bits(raw_cid, 104, 8);
+ cid->mid = mmc_get_bits(raw_cid, 128, 120, 8);
+ cid->oid = mmc_get_bits(raw_cid, 128, 104, 8);
for (i = 0; i < 6; i++)
- cid->pnm[i] = mmc_get_bits(raw_cid, 96 - i * 8, 8);
- cid->prv = mmc_get_bits(raw_cid, 48, 8);
- cid->psn = mmc_get_bits(raw_cid, 16, 32);
- cid->mdt_month = mmc_get_bits(raw_cid, 12, 4);
- cid->mdt_year = mmc_get_bits(raw_cid, 8, 4) + 1997;
+ cid->pnm[i] = mmc_get_bits(raw_cid, 128, 96 - i * 8, 8);
+ cid->prv = mmc_get_bits(raw_cid, 128, 48, 8);
+ cid->psn = mmc_get_bits(raw_cid, 128, 16, 32);
+ cid->mdt_month = mmc_get_bits(raw_cid, 128, 12, 4);
+ cid->mdt_year = mmc_get_bits(raw_cid, 128, 8, 4) + 1997;
}
static const int exp[8] = {
@@ -789,58 +791,58 @@ mmc_decode_csd_sd(uint32_t *raw_csd, struct mmc_csd *csd)
int e;
memset(csd, 0, sizeof(*csd));
- csd->csd_structure = v = mmc_get_bits(raw_csd, 126, 2);
+ csd->csd_structure = v = mmc_get_bits(raw_csd, 128, 126, 2);
if (v == 0) {
- m = mmc_get_bits(raw_csd, 115, 4);
- e = mmc_get_bits(raw_csd, 112, 3);
+ m = mmc_get_bits(raw_csd, 128, 115, 4);
+ e = mmc_get_bits(raw_csd, 128, 112, 3);
csd->tacc = exp[e] * mant[m] + 9 / 10;
- csd->nsac = mmc_get_bits(raw_csd, 104, 8) * 100;
- m = mmc_get_bits(raw_csd, 99, 4);
- e = mmc_get_bits(raw_csd, 96, 3);
+ csd->nsac = mmc_get_bits(raw_csd, 128, 104, 8) * 100;
+ m = mmc_get_bits(raw_csd, 128, 99, 4);
+ e = mmc_get_bits(raw_csd, 128, 96, 3);
csd->tran_speed = exp[e] * 10000 * mant[m];
- csd->ccc = mmc_get_bits(raw_csd, 84, 12);
- csd->read_bl_len = 1 << mmc_get_bits(raw_csd, 80, 4);
- csd->read_bl_partial = mmc_get_bits(raw_csd, 79, 1);
- csd->write_blk_misalign = mmc_get_bits(raw_csd, 78, 1);
- csd->read_blk_misalign = mmc_get_bits(raw_csd, 77, 1);
- csd->dsr_imp = mmc_get_bits(raw_csd, 76, 1);
- csd->vdd_r_curr_min = cur_min[mmc_get_bits(raw_csd, 59, 3)];
- csd->vdd_r_curr_max = cur_max[mmc_get_bits(raw_csd, 56, 3)];
- csd->vdd_w_curr_min = cur_min[mmc_get_bits(raw_csd, 53, 3)];
- csd->vdd_w_curr_max = cur_max[mmc_get_bits(raw_csd, 50, 3)];
- m = mmc_get_bits(raw_csd, 62, 12);
- e = mmc_get_bits(raw_csd, 47, 3);
+ csd->ccc = mmc_get_bits(raw_csd, 128, 84, 12);
+ csd->read_bl_len = 1 << mmc_get_bits(raw_csd, 128, 80, 4);
+ csd->read_bl_partial = mmc_get_bits(raw_csd, 128, 79, 1);
+ csd->write_blk_misalign = mmc_get_bits(raw_csd, 128, 78, 1);
+ csd->read_blk_misalign = mmc_get_bits(raw_csd, 128, 77, 1);
+ csd->dsr_imp = mmc_get_bits(raw_csd, 128, 76, 1);
+ csd->vdd_r_curr_min = cur_min[mmc_get_bits(raw_csd, 128, 59, 3)];
+ csd->vdd_r_curr_max = cur_max[mmc_get_bits(raw_csd, 128, 56, 3)];
+ csd->vdd_w_curr_min = cur_min[mmc_get_bits(raw_csd, 128, 53, 3)];
+ csd->vdd_w_curr_max = cur_max[mmc_get_bits(raw_csd, 128, 50, 3)];
+ m = mmc_get_bits(raw_csd, 128, 62, 12);
+ e = mmc_get_bits(raw_csd, 128, 47, 3);
csd->capacity = ((1 + m) << (e + 2)) * csd->read_bl_len;
- csd->erase_blk_en = mmc_get_bits(raw_csd, 46, 1);
- csd->sector_size = mmc_get_bits(raw_csd, 39, 7);
- csd->wp_grp_size = mmc_get_bits(raw_csd, 32, 7);
- csd->wp_grp_enable = mmc_get_bits(raw_csd, 31, 1);
- csd->r2w_factor = 1 << mmc_get_bits(raw_csd, 26, 3);
- csd->write_bl_len = 1 << mmc_get_bits(raw_csd, 22, 4);
- csd->write_bl_partial = mmc_get_bits(raw_csd, 21, 1);
+ csd->erase_blk_en = mmc_get_bits(raw_csd, 128, 46, 1);
+ csd->erase_sector = mmc_get_bits(raw_csd, 128, 39, 7) + 1;
+ csd->wp_grp_size = mmc_get_bits(raw_csd, 128, 32, 7);
+ csd->wp_grp_enable = mmc_get_bits(raw_csd, 128, 31, 1);
+ csd->r2w_factor = 1 << mmc_get_bits(raw_csd, 128, 26, 3);
+ csd->write_bl_len = 1 << mmc_get_bits(raw_csd, 128, 22, 4);
+ csd->write_bl_partial = mmc_get_bits(raw_csd, 128, 21, 1);
} else if (v == 1) {
- m = mmc_get_bits(raw_csd, 115, 4);
- e = mmc_get_bits(raw_csd, 112, 3);
+ m = mmc_get_bits(raw_csd, 128, 115, 4);
+ e = mmc_get_bits(raw_csd, 128, 112, 3);
csd->tacc = exp[e] * mant[m] + 9 / 10;
- csd->nsac = mmc_get_bits(raw_csd, 104, 8) * 100;
- m = mmc_get_bits(raw_csd, 99, 4);
- e = mmc_get_bits(raw_csd, 96, 3);
+ csd->nsac = mmc_get_bits(raw_csd, 128, 104, 8) * 100;
+ m = mmc_get_bits(raw_csd, 128, 99, 4);
+ e = mmc_get_bits(raw_csd, 128, 96, 3);
csd->tran_speed = exp[e] * 10000 * mant[m];
- csd->ccc = mmc_get_bits(raw_csd, 84, 12);
- csd->read_bl_len = 1 << mmc_get_bits(raw_csd, 80, 4);
- csd->read_bl_partial = mmc_get_bits(raw_csd, 79, 1);
- csd->write_blk_misalign = mmc_get_bits(raw_csd, 78, 1);
- csd->read_blk_misalign = mmc_get_bits(raw_csd, 77, 1);
- csd->dsr_imp = mmc_get_bits(raw_csd, 76, 1);
- csd->capacity = ((uint64_t)mmc_get_bits(raw_csd, 48, 22) + 1) *
+ csd->ccc = mmc_get_bits(raw_csd, 128, 84, 12);
+ csd->read_bl_len = 1 << mmc_get_bits(raw_csd, 128, 80, 4);
+ csd->read_bl_partial = mmc_get_bits(raw_csd, 128, 79, 1);
+ csd->write_blk_misalign = mmc_get_bits(raw_csd, 128, 78, 1);
+ csd->read_blk_misalign = mmc_get_bits(raw_csd, 128, 77, 1);
+ csd->dsr_imp = mmc_get_bits(raw_csd, 128, 76, 1);
+ csd->capacity = ((uint64_t)mmc_get_bits(raw_csd, 128, 48, 22) + 1) *
512 * 1024;
- csd->erase_blk_en = mmc_get_bits(raw_csd, 46, 1);
- csd->sector_size = mmc_get_bits(raw_csd, 39, 7);
- csd->wp_grp_size = mmc_get_bits(raw_csd, 32, 7);
- csd->wp_grp_enable = mmc_get_bits(raw_csd, 31, 1);
- csd->r2w_factor = 1 << mmc_get_bits(raw_csd, 26, 3);
- csd->write_bl_len = 1 << mmc_get_bits(raw_csd, 22, 4);
- csd->write_bl_partial = mmc_get_bits(raw_csd, 21, 1);
+ csd->erase_blk_en = mmc_get_bits(raw_csd, 128, 46, 1);
+ csd->erase_sector = mmc_get_bits(raw_csd, 128, 39, 7) + 1;
+ csd->wp_grp_size = mmc_get_bits(raw_csd, 128, 32, 7);
+ csd->wp_grp_enable = mmc_get_bits(raw_csd, 128, 31, 1);
+ csd->r2w_factor = 1 << mmc_get_bits(raw_csd, 128, 26, 3);
+ csd->write_bl_len = 1 << mmc_get_bits(raw_csd, 128, 22, 4);
+ csd->write_bl_partial = mmc_get_bits(raw_csd, 128, 21, 1);
} else
panic("unknown SD CSD version");
}
@@ -852,56 +854,72 @@ mmc_decode_csd_mmc(uint32_t *raw_csd, struct mmc_csd *csd)
int e;
memset(csd, 0, sizeof(*csd));
- csd->csd_structure = mmc_get_bits(raw_csd, 126, 2);
- csd->spec_vers = mmc_get_bits(raw_csd, 122, 4);
- m = mmc_get_bits(raw_csd, 115, 4);
- e = mmc_get_bits(raw_csd, 112, 3);
+ csd->csd_structure = mmc_get_bits(raw_csd, 128, 126, 2);
+ csd->spec_vers = mmc_get_bits(raw_csd, 128, 122, 4);
+ m = mmc_get_bits(raw_csd, 128, 115, 4);
+ e = mmc_get_bits(raw_csd, 128, 112, 3);
csd->tacc = exp[e] * mant[m] + 9 / 10;
- csd->nsac = mmc_get_bits(raw_csd, 104, 8) * 100;
- m = mmc_get_bits(raw_csd, 99, 4);
- e = mmc_get_bits(raw_csd, 96, 3);
+ csd->nsac = mmc_get_bits(raw_csd, 128, 104, 8) * 100;
+ m = mmc_get_bits(raw_csd, 128, 99, 4);
+ e = mmc_get_bits(raw_csd, 128, 96, 3);
csd->tran_speed = exp[e] * 10000 * mant[m];
- csd->ccc = mmc_get_bits(raw_csd, 84, 12);
- csd->read_bl_len = 1 << mmc_get_bits(raw_csd, 80, 4);
- csd->read_bl_partial = mmc_get_bits(raw_csd, 79, 1);
- csd->write_blk_misalign = mmc_get_bits(raw_csd, 78, 1);
- csd->read_blk_misalign = mmc_get_bits(raw_csd, 77, 1);
- csd->dsr_imp = mmc_get_bits(raw_csd, 76, 1);
- csd->vdd_r_curr_min = cur_min[mmc_get_bits(raw_csd, 59, 3)];
- csd->vdd_r_curr_max = cur_max[mmc_get_bits(raw_csd, 56, 3)];
- csd->vdd_w_curr_min = cur_min[mmc_get_bits(raw_csd, 53, 3)];
- csd->vdd_w_curr_max = cur_max[mmc_get_bits(raw_csd, 50, 3)];
- m = mmc_get_bits(raw_csd, 62, 12);
- e = mmc_get_bits(raw_csd, 47, 3);
+ csd->ccc = mmc_get_bits(raw_csd, 128, 84, 12);
+ csd->read_bl_len = 1 << mmc_get_bits(raw_csd, 128, 80, 4);
+ csd->read_bl_partial = mmc_get_bits(raw_csd, 128, 79, 1);
+ csd->write_blk_misalign = mmc_get_bits(raw_csd, 128, 78, 1);
+ csd->read_blk_misalign = mmc_get_bits(raw_csd, 128, 77, 1);
+ csd->dsr_imp = mmc_get_bits(raw_csd, 128, 76, 1);
+ csd->vdd_r_curr_min = cur_min[mmc_get_bits(raw_csd, 128, 59, 3)];
+ csd->vdd_r_curr_max = cur_max[mmc_get_bits(raw_csd, 128, 56, 3)];
+ csd->vdd_w_curr_min = cur_min[mmc_get_bits(raw_csd, 128, 53, 3)];
+ csd->vdd_w_curr_max = cur_max[mmc_get_bits(raw_csd, 128, 50, 3)];
+ m = mmc_get_bits(raw_csd, 128, 62, 12);
+ e = mmc_get_bits(raw_csd, 128, 47, 3);
csd->capacity = ((1 + m) << (e + 2)) * csd->read_bl_len;
-// csd->erase_blk_en = mmc_get_bits(raw_csd, 46, 1);
-// csd->sector_size = mmc_get_bits(raw_csd, 39, 7);
- csd->wp_grp_size = mmc_get_bits(raw_csd, 32, 5);
- csd->wp_grp_enable = mmc_get_bits(raw_csd, 31, 1);
- csd->r2w_factor = 1 << mmc_get_bits(raw_csd, 26, 3);
- csd->write_bl_len = 1 << mmc_get_bits(raw_csd, 22, 4);
- csd->write_bl_partial = mmc_get_bits(raw_csd, 21, 1);
+ csd->erase_blk_en = 0;
+ csd->erase_sector = (mmc_get_bits(raw_csd, 128, 42, 5) + 1) *
+ (mmc_get_bits(raw_csd, 128, 37, 5) + 1);
+ csd->wp_grp_size = mmc_get_bits(raw_csd, 128, 32, 5);
+ csd->wp_grp_enable = mmc_get_bits(raw_csd, 128, 31, 1);
+ csd->r2w_factor = 1 << mmc_get_bits(raw_csd, 128, 26, 3);
+ csd->write_bl_len = 1 << mmc_get_bits(raw_csd, 128, 22, 4);
+ csd->write_bl_partial = mmc_get_bits(raw_csd, 128, 21, 1);
}
static void
mmc_app_decode_scr(uint32_t *raw_scr, struct mmc_scr *scr)
{
unsigned int scr_struct;
- uint32_t tmp[4];
-
- tmp[3] = raw_scr[1];
- tmp[2] = raw_scr[0];
memset(scr, 0, sizeof(*scr));
- scr_struct = mmc_get_bits(tmp, 60, 4);
+ scr_struct = mmc_get_bits(raw_scr, 64, 60, 4);
if (scr_struct != 0) {
printf("Unrecognised SCR structure version %d\n",
scr_struct);
return;
}
- scr->sda_vsn = mmc_get_bits(tmp, 56, 4);
- scr->bus_widths = mmc_get_bits(tmp, 48, 4);
+ scr->sda_vsn = mmc_get_bits(raw_scr, 64, 56, 4);
+ scr->bus_widths = mmc_get_bits(raw_scr, 64, 48, 4);
+}
+
+static void
+mmc_app_decode_sd_status(uint32_t *raw_sd_status,
+ struct mmc_sd_status *sd_status)
+{
+
+ memset(sd_status, 0, sizeof(*sd_status));
+
+ sd_status->bus_width = mmc_get_bits(raw_sd_status, 512, 510, 2);
+ sd_status->secured_mode = mmc_get_bits(raw_sd_status, 512, 509, 1);
+ sd_status->card_type = mmc_get_bits(raw_sd_status, 512, 480, 16);
+ sd_status->prot_area = mmc_get_bits(raw_sd_status, 512, 448, 12);
+ sd_status->speed_class = mmc_get_bits(raw_sd_status, 512, 440, 8);
+ sd_status->perf_move = mmc_get_bits(raw_sd_status, 512, 432, 8);
+ sd_status->au_size = mmc_get_bits(raw_sd_status, 512, 428, 4);
+ sd_status->erase_size = mmc_get_bits(raw_sd_status, 512, 408, 16);
+ sd_status->erase_timeout = mmc_get_bits(raw_sd_status, 512, 402, 6);
+ sd_status->erase_offset = mmc_get_bits(raw_sd_status, 512, 400, 2);
}
static int
@@ -985,6 +1003,32 @@ mmc_send_ext_csd(struct mmc_softc *sc, uint8_t *rawextcsd)
}
static int
+mmc_app_sd_status(struct mmc_softc *sc, uint16_t rca, uint32_t *rawsdstatus)
+{
+ int err, i;
+ struct mmc_command cmd;
+ struct mmc_data data;
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+ memset(&data, 0, sizeof(struct mmc_data));
+
+ memset(rawsdstatus, 0, 64);
+ cmd.opcode = ACMD_SD_STATUS;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+ cmd.arg = 0;
+ cmd.data = &data;
+
+ data.data = rawsdstatus;
+ data.len = 64;
+ data.flags = MMC_DATA_READ;
+
+ err = mmc_wait_for_app_cmd(sc, rca, &cmd, CMD_RETRIES);
+ for (i = 0; i < 16; i++)
+ rawsdstatus[i] = be32toh(rawsdstatus[i]);
+ return (err);
+}
+
+static int
mmc_set_relative_addr(struct mmc_softc *sc, uint16_t resp)
{
struct mmc_command cmd;
@@ -1050,6 +1094,8 @@ mmc_discover_cards(struct mmc_softc *sc)
if (ivar->csd.csd_structure > 0)
ivar->high_cap = 1;
ivar->tran_speed = ivar->csd.tran_speed;
+ ivar->erase_sector = ivar->csd.erase_sector *
+ ivar->csd.write_bl_len / MMC_SECTOR_SIZE;
/* Get card SCR. Card must be selected to fetch it. */
mmc_select_card(sc, ivar->rca);
mmc_app_send_scr(sc, ivar->rca, ivar->raw_scr);
@@ -1063,6 +1109,13 @@ mmc_discover_cards(struct mmc_softc *sc)
ivar->hs_tran_speed = 50000000;
}
}
+ mmc_app_sd_status(sc, ivar->rca, ivar->raw_sd_status);
+ mmc_app_decode_sd_status(ivar->raw_sd_status,
+ &ivar->sd_status);
+ if (ivar->sd_status.au_size != 0) {
+ ivar->erase_sector =
+ 16 << ivar->sd_status.au_size;
+ }
mmc_select_card(sc, 0);
/* Find max supported bus width. */
if ((mmcbr_get_caps(sc->dev) & MMC_CAP_4_BIT_DATA) &&
@@ -1081,6 +1134,8 @@ mmc_discover_cards(struct mmc_softc *sc)
mmc_decode_csd_mmc(ivar->raw_csd, &ivar->csd);
ivar->sec_count = ivar->csd.capacity / MMC_SECTOR_SIZE;
ivar->tran_speed = ivar->csd.tran_speed;
+ ivar->erase_sector = ivar->csd.erase_sector *
+ ivar->csd.write_bl_len / MMC_SECTOR_SIZE;
/* Only MMC >= 4.x cards support EXT_CSD. */
if (ivar->csd.spec_vers >= 4) {
/* Card must be selected to fetch EXT_CSD. */
@@ -1108,6 +1163,13 @@ mmc_discover_cards(struct mmc_softc *sc)
/* Find max supported bus width. */
ivar->bus_width = mmc_test_bus_width(sc);
mmc_select_card(sc, 0);
+ /* Handle HC erase sector size. */
+ if (ivar->raw_ext_csd[EXT_CSD_ERASE_GRP_SIZE] != 0) {
+ ivar->erase_sector = 1024 *
+ ivar->raw_ext_csd[EXT_CSD_ERASE_GRP_SIZE];
+ mmc_switch(sc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_ERASE_GRP_DEF, 1);
+ }
} else {
ivar->bus_width = bus_width_1;
ivar->timing = bus_timing_normal;
@@ -1278,6 +1340,9 @@ mmc_read_ivar(device_t bus, device_t child, int which, u_char *result)
case MMC_IVAR_BUS_WIDTH:
*(int *)result = ivar->bus_width;
break;
+ case MMC_IVAR_ERASE_SECTOR:
+ *(int *)result = ivar->erase_sector;
+ break;
}
return (0);
}
diff --git a/sys/dev/mmc/mmcreg.h b/sys/dev/mmc/mmcreg.h
index ce109ff..aef2a3d 100644
--- a/sys/dev/mmc/mmcreg.h
+++ b/sys/dev/mmc/mmcreg.h
@@ -288,11 +288,14 @@ struct mmc_request {
* EXT_CSD fields
*/
+#define EXT_CSD_ERASE_GRP_DEF 175 /* R/W */
#define EXT_CSD_BUS_WIDTH 183 /* R/W */
#define EXT_CSD_HS_TIMING 185 /* R/W */
#define EXT_CSD_CARD_TYPE 196 /* RO */
#define EXT_CSD_REV 192 /* RO */
#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */
+#define EXT_CSD_ERASE_TO_MULT 223 /* RO */
+#define EXT_CSD_ERASE_GRP_SIZE 224 /* RO */
/*
* EXT_CSD field definitions
@@ -379,7 +382,7 @@ struct mmc_csd
uint32_t vdd_w_curr_min;
uint32_t vdd_w_curr_max;
uint32_t wp_grp_size;
- uint32_t sector_size; /* Erase sector size! */
+ uint32_t erase_sector;
uint64_t capacity;
unsigned int read_bl_partial:1,
read_blk_misalign:1,
@@ -398,6 +401,20 @@ struct mmc_scr
#define SD_SCR_BUS_WIDTH_4 (1<<2)
};
+struct mmc_sd_status
+{
+ uint8_t bus_width;
+ uint8_t secured_mode;
+ uint16_t card_type;
+ uint16_t prot_area;
+ uint8_t speed_class;
+ uint8_t perf_move;
+ uint8_t au_size;
+ uint16_t erase_size;
+ uint8_t erase_timeout;
+ uint8_t erase_offset;
+};
+
/*
* Older versions of the MMC standard had a variable sector size. However,
* I've been able to find no old MMC or SD cards that have a non 512
diff --git a/sys/dev/mmc/mmcsd.c b/sys/dev/mmc/mmcsd.c
index d0ea6a8..44ba5d2 100644
--- a/sys/dev/mmc/mmcsd.c
+++ b/sys/dev/mmc/mmcsd.c
@@ -133,10 +133,11 @@ mmcsd_attach(device_t dev)
// d->d_dump = mmcsd_dump; Need polling mmc layer
d->d_name = "mmcsd";
d->d_drv1 = sc;
- d->d_maxsize = MAXPHYS; /* Maybe ask bridge? */
+ d->d_maxsize = 4*1024*1024; /* Maximum defined SD card AU size. */
d->d_sectorsize = mmc_get_sector_size(dev);
d->d_mediasize = mmc_get_media_size(dev) * d->d_sectorsize;
d->d_unit = device_get_unit(dev);
+ d->d_flags = DISKFLAG_CANDELETE;
/*
* Display in most natural units. There's no cards < 1MB.
* The SD standard goes to 2GiB, but the data format supports
@@ -216,6 +217,151 @@ mmcsd_strategy(struct bio *bp)
MMCSD_UNLOCK(sc);
}
+static daddr_t
+mmcsd_rw(struct mmcsd_softc *sc, struct bio *bp)
+{
+ daddr_t block, end;
+ struct mmc_command cmd;
+ struct mmc_command stop;
+ struct mmc_request req;
+ struct mmc_data data;
+ device_t dev = sc->dev;
+ int sz = sc->disk->d_sectorsize;
+
+ block = bp->bio_pblkno;
+ end = bp->bio_pblkno + (bp->bio_bcount / sz);
+ while (block < end) {
+ char *vaddr = bp->bio_data +
+ (block - bp->bio_pblkno) * sz;
+ int numblocks;
+#ifdef MULTI_BLOCK
+ numblocks = end - block;
+#else
+ numblocks = 1;
+#endif
+ memset(&req, 0, sizeof(req));
+ memset(&cmd, 0, sizeof(cmd));
+ memset(&stop, 0, sizeof(stop));
+ req.cmd = &cmd;
+ cmd.data = &data;
+ if (bp->bio_cmd == BIO_READ) {
+ if (numblocks > 1)
+ cmd.opcode = MMC_READ_MULTIPLE_BLOCK;
+ else
+ cmd.opcode = MMC_READ_SINGLE_BLOCK;
+ } else {
+ if (numblocks > 1)
+ cmd.opcode = MMC_WRITE_MULTIPLE_BLOCK;
+ else
+ cmd.opcode = MMC_WRITE_BLOCK;
+ }
+ cmd.arg = block;
+ if (!mmc_get_high_cap(dev))
+ cmd.arg <<= 9;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+ data.data = vaddr;
+ data.mrq = &req;
+ if (bp->bio_cmd == BIO_READ)
+ data.flags = MMC_DATA_READ;
+ else
+ data.flags = MMC_DATA_WRITE;
+ data.len = numblocks * sz;
+ if (numblocks > 1) {
+ data.flags |= MMC_DATA_MULTI;
+ stop.opcode = MMC_STOP_TRANSMISSION;
+ stop.arg = 0;
+ stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
+ req.stop = &stop;
+ }
+// printf("Len %d %lld-%lld flags %#x sz %d\n",
+// (int)data.len, (long long)block, (long long)end, data.flags, sz);
+ MMCBUS_WAIT_FOR_REQUEST(device_get_parent(dev), dev,
+ &req);
+ if (req.cmd->error != MMC_ERR_NONE)
+ break;
+ block += numblocks;
+ }
+ return (block);
+}
+
+static daddr_t
+mmcsd_delete(struct mmcsd_softc *sc, struct bio *bp)
+{
+ daddr_t block, end, start, stop;
+ struct mmc_command cmd;
+ struct mmc_request req;
+ device_t dev = sc->dev;
+ int sz = sc->disk->d_sectorsize;
+ int erase_sector;
+
+ block = bp->bio_pblkno;
+ end = bp->bio_pblkno + (bp->bio_bcount / sz);
+
+ /* Safe round to the erase sector boundaries. */
+ erase_sector = mmc_get_erase_sector(dev);
+ start = block + erase_sector - 1; /* Round up. */
+ start -= start % erase_sector;
+ stop = end; /* Round down. */
+ stop -= end % erase_sector;
+
+ /* We can't erase areas smaller then sector. */
+ if (start >= stop)
+ return (end);
+
+ /* Set erase start position. */
+ memset(&req, 0, sizeof(req));
+ memset(&cmd, 0, sizeof(cmd));
+ req.cmd = &cmd;
+ if (mmc_get_card_type(dev) == mode_sd)
+ cmd.opcode = SD_ERASE_WR_BLK_START;
+ else
+ cmd.opcode = MMC_ERASE_GROUP_START;
+ cmd.arg = start;
+ if (!mmc_get_high_cap(dev))
+ cmd.arg <<= 9;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ MMCBUS_WAIT_FOR_REQUEST(device_get_parent(dev), dev,
+ &req);
+ if (req.cmd->error != MMC_ERR_NONE) {
+ printf("erase err1: %d\n", req.cmd->error);
+ return (block);
+ }
+ /* Set erase stop position. */
+ memset(&req, 0, sizeof(req));
+ memset(&cmd, 0, sizeof(cmd));
+ req.cmd = &cmd;
+ if (mmc_get_card_type(dev) == mode_sd)
+ cmd.opcode = SD_ERASE_WR_BLK_END;
+ else
+ cmd.opcode = MMC_ERASE_GROUP_END;
+ cmd.arg = stop;
+ if (!mmc_get_high_cap(dev))
+ cmd.arg <<= 9;
+ cmd.arg--;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ MMCBUS_WAIT_FOR_REQUEST(device_get_parent(dev), dev,
+ &req);
+ if (req.cmd->error != MMC_ERR_NONE) {
+ printf("erase err2: %d\n", req.cmd->error);
+ return (block);
+ }
+ /* Erase range. */
+ memset(&req, 0, sizeof(req));
+ memset(&cmd, 0, sizeof(cmd));
+ req.cmd = &cmd;
+ cmd.opcode = MMC_ERASE;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+ MMCBUS_WAIT_FOR_REQUEST(device_get_parent(dev), dev,
+ &req);
+ if (req.cmd->error != MMC_ERR_NONE) {
+ printf("erase err3 %d\n", req.cmd->error);
+ return (block);
+ }
+
+ return (end);
+}
+
static void
mmcsd_task(void *arg)
{
@@ -223,10 +369,6 @@ mmcsd_task(void *arg)
struct bio *bp;
int sz;
daddr_t block, end;
- struct mmc_command cmd;
- struct mmc_command stop;
- struct mmc_request req;
- struct mmc_data data;
device_t dev;
dev = sc->dev;
@@ -242,7 +384,6 @@ mmcsd_task(void *arg)
MMCSD_UNLOCK(sc);
if (!sc->running)
break;
-// printf("mmc_task: request %p for block %ju\n", bp, bp->bio_pblkno);
if (bp->bio_cmd != BIO_READ && mmc_get_read_only(dev)) {
bp->bio_error = EROFS;
bp->bio_resid = bp->bio_bcount;
@@ -252,56 +393,15 @@ mmcsd_task(void *arg)
}
MMCBUS_ACQUIRE_BUS(device_get_parent(dev), dev);
sz = sc->disk->d_sectorsize;
+ block = bp->bio_pblkno;
end = bp->bio_pblkno + (bp->bio_bcount / sz);
- for (block = bp->bio_pblkno; block < end;) {
- char *vaddr = bp->bio_data + (block - bp->bio_pblkno) * sz;
- int numblocks;
-#ifdef MULTI_BLOCK
- numblocks = end - block;
-#else
- numblocks = 1;
-#endif
- memset(&req, 0, sizeof(req));
- memset(&cmd, 0, sizeof(cmd));
- memset(&stop, 0, sizeof(stop));
- req.cmd = &cmd;
- cmd.data = &data;
- if (bp->bio_cmd == BIO_READ) {
- if (numblocks > 1)
- cmd.opcode = MMC_READ_MULTIPLE_BLOCK;
- else
- cmd.opcode = MMC_READ_SINGLE_BLOCK;
- } else {
- if (numblocks > 1)
- cmd.opcode = MMC_WRITE_MULTIPLE_BLOCK;
- else
- cmd.opcode = MMC_WRITE_BLOCK;
- }
- cmd.arg = block;
- if (!mmc_get_high_cap(dev))
- cmd.arg <<= 9;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
- data.data = vaddr;
- data.mrq = &req;
- if (bp->bio_cmd == BIO_READ)
- data.flags = MMC_DATA_READ;
- else
- data.flags = MMC_DATA_WRITE;
- data.len = numblocks * sz;
- if (numblocks > 1) {
- data.flags |= MMC_DATA_MULTI;
- stop.opcode = MMC_STOP_TRANSMISSION;
- stop.arg = 0;
- stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
- req.stop = &stop;
- }
-// printf("Len %d %lld-%lld flags %#x sz %d\n",
-// (int)data.len, (long long)block, (long long)end, data.flags, sz);
- MMCBUS_WAIT_FOR_REQUEST(device_get_parent(dev), dev,
- &req);
- if (req.cmd->error != MMC_ERR_NONE)
- break;
- block += numblocks;
+ if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) {
+ block = mmcsd_rw(sc, bp);
+ } else if (bp->bio_cmd == BIO_DELETE) {
+ block = mmcsd_delete(sc, bp);
+ } else {
+ /* UNSUPPORTED COMMAND */
+ block = bp->bio_pblkno;
}
MMCBUS_RELEASE_BUS(device_get_parent(dev), dev);
if (block < end) {
diff --git a/sys/dev/mmc/mmcvar.h b/sys/dev/mmc/mmcvar.h
index 8821f67..5a0e437 100644
--- a/sys/dev/mmc/mmcvar.h
+++ b/sys/dev/mmc/mmcvar.h
@@ -67,6 +67,7 @@ enum mmc_device_ivars {
MMC_IVAR_HIGH_CAP,
MMC_IVAR_CARD_TYPE,
MMC_IVAR_BUS_WIDTH,
+ MMC_IVAR_ERASE_SECTOR,
// MMC_IVAR_,
};
@@ -85,5 +86,6 @@ MMC_ACCESSOR(read_only, READ_ONLY, int)
MMC_ACCESSOR(high_cap, HIGH_CAP, int)
MMC_ACCESSOR(card_type, CARD_TYPE, int)
MMC_ACCESSOR(bus_width, BUS_WIDTH, int)
+MMC_ACCESSOR(erase_sector, ERASE_SECTOR, int)
#endif /* DEV_MMC_MMCVAR_H */
OpenPOWER on IntegriCloud