Set of mmc layer improvements:
- add MMC support. - add SDHC support. - add 4 and 8 bit bus width support. - add High Speed bus timing support.
This commit is contained in:
parent
8389b646b1
commit
c18f1e2627
@ -104,6 +104,10 @@ enum mmc_bus_width {
|
||||
bus_width_1 = 0, bus_width_4 = 2, bus_width_8 = 3
|
||||
};
|
||||
|
||||
enum mmc_bus_timing {
|
||||
bus_timing_normal = 0, bus_timing_hs
|
||||
};
|
||||
|
||||
struct mmc_ios {
|
||||
uint32_t clock; /* Speed of the clock in Hz to move data */
|
||||
enum mmc_vdd vdd; /* Voltage to apply to the power pins/ */
|
||||
@ -111,6 +115,7 @@ struct mmc_ios {
|
||||
enum mmc_chip_select chip_select;
|
||||
enum mmc_bus_width bus_width;
|
||||
enum mmc_power_mode power_mode;
|
||||
enum mmc_bus_timing timing;
|
||||
};
|
||||
|
||||
enum mmc_card_mode {
|
||||
@ -125,6 +130,7 @@ struct mmc_host {
|
||||
uint32_t caps;
|
||||
#define MMC_CAP_4_BIT_DATA (1 << 0) /* Can do 4-bit data transfers */
|
||||
#define MMC_CAP_8_BIT_DATA (1 << 1) /* Can do 8-bit data transfers */
|
||||
#define MMC_CAP_HSPEED (1 << 2) /* Can do High Speed transfers */
|
||||
enum mmc_card_mode mode;
|
||||
struct mmc_ios ios; /* Current state of the host */
|
||||
};
|
||||
|
@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/module.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/endian.h>
|
||||
|
||||
#include <dev/mmc/mmcreg.h>
|
||||
#include <dev/mmc/mmcbrvar.h>
|
||||
@ -82,11 +83,19 @@ struct mmc_softc {
|
||||
struct mmc_ivars {
|
||||
uint32_t raw_cid[4]; /* Raw bits of the CID */
|
||||
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 */
|
||||
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 */
|
||||
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 */
|
||||
u_char high_cap; /* High Capacity card */
|
||||
uint32_t tran_speed; /* Max speed in normal mode */
|
||||
uint32_t hs_tran_speed; /* Max speed in high speed mode */
|
||||
};
|
||||
|
||||
#define CMD_RETRIES 3
|
||||
@ -111,6 +120,11 @@ static int mmc_wait_for_cmd(struct mmc_softc *sc, struct mmc_command *cmd,
|
||||
int retries);
|
||||
static int mmc_wait_for_command(struct mmc_softc *sc, uint32_t opcode,
|
||||
uint32_t arg, uint32_t flags, uint32_t *resp, int retries);
|
||||
static int mmc_select_card(struct mmc_softc *sc, uint16_t rca);
|
||||
static int mmc_set_bus_width(struct mmc_softc *sc, uint16_t rca, int width);
|
||||
static int mmc_app_send_scr(struct mmc_softc *sc, uint16_t rca, uint32_t *rawscr);
|
||||
static void mmc_app_decode_scr(uint32_t *raw_scr, struct mmc_scr *scr);
|
||||
static int mmc_send_ext_csd(struct mmc_softc *sc, uint8_t *rawextcsd);
|
||||
|
||||
static void
|
||||
mmc_ms_delay(int ms)
|
||||
@ -173,6 +187,7 @@ static int
|
||||
mmc_acquire_bus(device_t busdev, device_t dev)
|
||||
{
|
||||
struct mmc_softc *sc;
|
||||
struct mmc_ivars *ivar;
|
||||
int err;
|
||||
int rca;
|
||||
|
||||
@ -195,21 +210,26 @@ mmc_acquire_bus(device_t busdev, device_t dev)
|
||||
*/
|
||||
rca = mmc_get_rca(dev);
|
||||
if (sc->last_rca != rca) {
|
||||
mmc_wait_for_command(sc, MMC_SELECT_CARD, rca << 16,
|
||||
MMC_RSP_R1 | MMC_CMD_AC, NULL, CMD_RETRIES);
|
||||
mmc_select_card(sc, rca);
|
||||
sc->last_rca = rca;
|
||||
/* Prepare bus width for the new card. */
|
||||
ivar = device_get_ivars(dev);
|
||||
device_printf(busdev,
|
||||
"setting bus width to %d bits\n",
|
||||
(ivar->bus_width == bus_width_4)?4:
|
||||
(ivar->bus_width == bus_width_8)?8:1);
|
||||
mmc_set_bus_width(sc, rca, ivar->bus_width);
|
||||
mmcbr_set_bus_width(busdev, ivar->bus_width);
|
||||
mmcbr_update_ios(busdev);
|
||||
}
|
||||
/* XXX should set bus width here? */
|
||||
} else {
|
||||
/*
|
||||
* If there's a card selected, stand down.
|
||||
*/
|
||||
if (sc->last_rca != 0) {
|
||||
mmc_wait_for_command(sc, MMC_SELECT_CARD, 0,
|
||||
MMC_RSP_R1 | MMC_CMD_AC, NULL, CMD_RETRIES);
|
||||
mmc_select_card(sc, 0);
|
||||
sc->last_rca = 0;
|
||||
}
|
||||
/* XXX should set bus width here? */
|
||||
}
|
||||
|
||||
return (0);
|
||||
@ -444,6 +464,22 @@ mmc_send_op_cond(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr)
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
mmc_send_if_cond(struct mmc_softc *sc, uint8_t vhs)
|
||||
{
|
||||
struct mmc_command cmd;
|
||||
int err;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.opcode = SD_SEND_IF_COND;
|
||||
cmd.arg = (vhs << 8) + 0xAA;
|
||||
cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
|
||||
cmd.data = NULL;
|
||||
|
||||
err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES);
|
||||
return (err);
|
||||
}
|
||||
|
||||
static void
|
||||
mmc_power_up(struct mmc_softc *sc)
|
||||
{
|
||||
@ -460,6 +496,7 @@ mmc_power_up(struct mmc_softc *sc)
|
||||
mmc_ms_delay(1);
|
||||
|
||||
mmcbr_set_clock(dev, mmcbr_get_f_min(sc->dev));
|
||||
mmcbr_set_timing(dev, bus_timing_normal);
|
||||
mmcbr_set_power_mode(dev, power_on);
|
||||
mmcbr_update_ios(dev);
|
||||
mmc_ms_delay(2);
|
||||
@ -475,9 +512,207 @@ mmc_power_down(struct mmc_softc *sc)
|
||||
mmcbr_set_bus_width(dev, bus_width_1);
|
||||
mmcbr_set_power_mode(dev, power_off);
|
||||
mmcbr_set_clock(dev, 0);
|
||||
mmcbr_set_timing(dev, bus_timing_normal);
|
||||
mmcbr_update_ios(dev);
|
||||
}
|
||||
|
||||
static int
|
||||
mmc_select_card(struct mmc_softc *sc, uint16_t rca)
|
||||
{
|
||||
return (mmc_wait_for_command(sc, MMC_SELECT_CARD, ((uint32_t)rca) << 16,
|
||||
MMC_RSP_R1B | MMC_CMD_AC, NULL, CMD_RETRIES));
|
||||
}
|
||||
|
||||
static int
|
||||
mmc_switch(struct mmc_softc *sc, uint8_t set, uint8_t index, uint8_t value)
|
||||
{
|
||||
struct mmc_command cmd;
|
||||
int err;
|
||||
|
||||
cmd.opcode = MMC_SWITCH_FUNC;
|
||||
cmd.arg = (MMC_SWITCH_FUNC_WR << 24) |
|
||||
(index << 16) |
|
||||
(value << 8) |
|
||||
set;
|
||||
cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
|
||||
cmd.data = NULL;
|
||||
err = mmc_wait_for_cmd(sc, &cmd, 0);
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
mmc_sd_switch(struct mmc_softc *sc, uint8_t mode, uint8_t grp, uint8_t value, uint8_t *res)
|
||||
{
|
||||
int err;
|
||||
struct mmc_command cmd;
|
||||
struct mmc_data data;
|
||||
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
memset(&data, 0, sizeof(struct mmc_data));
|
||||
|
||||
memset(res, 0, 64);
|
||||
cmd.opcode = SD_SWITCH_FUNC;
|
||||
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
|
||||
cmd.arg = mode << 31;
|
||||
cmd.arg |= 0x00FFFFFF;
|
||||
cmd.arg &= ~(0xF << grp);
|
||||
cmd.arg |= value << grp;
|
||||
cmd.data = &data;
|
||||
|
||||
data.data = res;
|
||||
data.len = 64;
|
||||
data.flags = MMC_DATA_READ;
|
||||
|
||||
err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES);
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
mmc_set_bus_width(struct mmc_softc *sc, uint16_t rca, int width)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (mmcbr_get_mode(sc->dev) == mode_sd) {
|
||||
struct mmc_command cmd;
|
||||
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
cmd.opcode = ACMD_SET_BUS_WIDTH;
|
||||
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
|
||||
switch (width) {
|
||||
case bus_width_1:
|
||||
cmd.arg = SD_BUS_WIDTH_1;
|
||||
break;
|
||||
case bus_width_4:
|
||||
cmd.arg = SD_BUS_WIDTH_4;
|
||||
break;
|
||||
default:
|
||||
return (MMC_ERR_INVALID);
|
||||
}
|
||||
err = mmc_wait_for_app_cmd(sc, rca, &cmd, CMD_RETRIES);
|
||||
} else {
|
||||
uint8_t value;
|
||||
|
||||
switch (width) {
|
||||
case bus_width_1:
|
||||
value = EXT_CSD_BUS_WIDTH_1;
|
||||
break;
|
||||
case bus_width_4:
|
||||
value = EXT_CSD_BUS_WIDTH_4;
|
||||
break;
|
||||
case bus_width_8:
|
||||
value = EXT_CSD_BUS_WIDTH_8;
|
||||
break;
|
||||
default:
|
||||
return (MMC_ERR_INVALID);
|
||||
}
|
||||
err = mmc_switch(sc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, value);
|
||||
}
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
mmc_set_timing(struct mmc_softc *sc, int timing)
|
||||
{
|
||||
int err;
|
||||
uint8_t value;
|
||||
|
||||
switch (timing) {
|
||||
case bus_timing_normal:
|
||||
value = 0;
|
||||
break;
|
||||
case bus_timing_hs:
|
||||
value = 1;
|
||||
break;
|
||||
default:
|
||||
return (MMC_ERR_INVALID);
|
||||
}
|
||||
if (mmcbr_get_mode(sc->dev) == mode_sd) {
|
||||
u_char switch_res[64];
|
||||
|
||||
err = mmc_sd_switch(sc, 1, 0, value, switch_res);
|
||||
} else {
|
||||
err = mmc_switch(sc, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_HS_TIMING, value);
|
||||
}
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
mmc_test_bus_width(struct mmc_softc *sc)
|
||||
{
|
||||
struct mmc_command cmd;
|
||||
struct mmc_data data;
|
||||
int err;
|
||||
uint8_t buf[8];
|
||||
uint8_t p8[8] = { 0x55, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
uint8_t p8ok[8] = { 0xAA, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
uint8_t p4[4] = { 0x5A, 0x00, 0x00, 0x00, };
|
||||
uint8_t p4ok[4] = { 0xA5, 0x00, 0x00, 0x00, };
|
||||
|
||||
if (mmcbr_get_caps(sc->dev) & MMC_CAP_8_BIT_DATA) {
|
||||
mmcbr_set_bus_width(sc->dev, bus_width_8);
|
||||
mmcbr_update_ios(sc->dev);
|
||||
|
||||
cmd.opcode = MMC_BUSTEST_W;
|
||||
cmd.arg = 0;
|
||||
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
|
||||
cmd.data = &data;
|
||||
|
||||
data.data = p8;
|
||||
data.len = 8;
|
||||
data.flags = MMC_DATA_WRITE;
|
||||
mmc_wait_for_cmd(sc, &cmd, 0);
|
||||
|
||||
cmd.opcode = MMC_BUSTEST_R;
|
||||
cmd.arg = 0;
|
||||
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
|
||||
cmd.data = &data;
|
||||
|
||||
data.data = buf;
|
||||
data.len = 8;
|
||||
data.flags = MMC_DATA_READ;
|
||||
err = mmc_wait_for_cmd(sc, &cmd, 0);
|
||||
|
||||
mmcbr_set_bus_width(sc->dev, bus_width_1);
|
||||
mmcbr_update_ios(sc->dev);
|
||||
|
||||
if (err == MMC_ERR_NONE && memcmp(buf, p8ok, 8) == 0)
|
||||
return (bus_width_8);
|
||||
}
|
||||
|
||||
if (mmcbr_get_caps(sc->dev) & MMC_CAP_4_BIT_DATA) {
|
||||
mmcbr_set_bus_width(sc->dev, bus_width_4);
|
||||
mmcbr_update_ios(sc->dev);
|
||||
|
||||
cmd.opcode = MMC_BUSTEST_W;
|
||||
cmd.arg = 0;
|
||||
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
|
||||
cmd.data = &data;
|
||||
|
||||
data.data = p4;
|
||||
data.len = 4;
|
||||
data.flags = MMC_DATA_WRITE;
|
||||
mmc_wait_for_cmd(sc, &cmd, 0);
|
||||
|
||||
cmd.opcode = MMC_BUSTEST_R;
|
||||
cmd.arg = 0;
|
||||
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
|
||||
cmd.data = &data;
|
||||
|
||||
data.data = buf;
|
||||
data.len = 4;
|
||||
data.flags = MMC_DATA_READ;
|
||||
err = mmc_wait_for_cmd(sc, &cmd, 0);
|
||||
|
||||
mmcbr_set_bus_width(sc->dev, bus_width_1);
|
||||
mmcbr_update_ios(sc->dev);
|
||||
|
||||
if (err == MMC_ERR_NONE && memcmp(buf, p4ok, 4) == 0)
|
||||
return (bus_width_4);
|
||||
}
|
||||
return (bus_width_1);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
mmc_get_bits(uint32_t *bits, int start, int size)
|
||||
{
|
||||
@ -506,8 +741,14 @@ mmc_decode_cid(int is_sd, uint32_t *raw_cid, struct mmc_cid *cid)
|
||||
cid->mdt_year = mmc_get_bits(raw_cid, 12, 8) + 2001;
|
||||
cid->mdt_month = mmc_get_bits(raw_cid, 8, 4);
|
||||
} else {
|
||||
/* XXX write me */
|
||||
panic("write mmc cid decoder");
|
||||
cid->mid = mmc_get_bits(raw_cid, 120, 8);
|
||||
cid->oid = mmc_get_bits(raw_cid, 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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -563,14 +804,84 @@ mmc_decode_csd(int is_sd, uint32_t *raw_csd, struct mmc_csd *csd)
|
||||
csd->write_bl_len = 1 << mmc_get_bits(raw_csd, 22, 4);
|
||||
csd->write_bl_partial = mmc_get_bits(raw_csd, 21, 1);
|
||||
} else if (v == 1) {
|
||||
panic("Write SDHC CSD parser");
|
||||
m = mmc_get_bits(raw_csd, 115, 4);
|
||||
e = mmc_get_bits(raw_csd, 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->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) *
|
||||
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);
|
||||
} else
|
||||
panic("unknown SD CSD version");
|
||||
} else {
|
||||
panic("Write a MMC CSD parser");
|
||||
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->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->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->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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
static int
|
||||
mmc_all_send_cid(struct mmc_softc *sc, uint32_t *rawcid)
|
||||
{
|
||||
@ -601,6 +912,70 @@ mmc_send_csd(struct mmc_softc *sc, uint16_t rca, uint32_t *rawcid)
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
mmc_app_send_scr(struct mmc_softc *sc, uint16_t rca, uint32_t *rawscr)
|
||||
{
|
||||
int err;
|
||||
struct mmc_command cmd;
|
||||
struct mmc_data data;
|
||||
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
memset(&data, 0, sizeof(struct mmc_data));
|
||||
|
||||
memset(rawscr, 0, 8);
|
||||
cmd.opcode = ACMD_SEND_SCR;
|
||||
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
|
||||
cmd.arg = 0;
|
||||
cmd.data = &data;
|
||||
|
||||
data.data = rawscr;
|
||||
data.len = 8;
|
||||
data.flags = MMC_DATA_READ;
|
||||
|
||||
err = mmc_wait_for_app_cmd(sc, rca, &cmd, CMD_RETRIES);
|
||||
rawscr[0] = be32toh(rawscr[0]);
|
||||
rawscr[1] = be32toh(rawscr[1]);
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
mmc_send_ext_csd(struct mmc_softc *sc, uint8_t *rawextcsd)
|
||||
{
|
||||
int err;
|
||||
struct mmc_command cmd;
|
||||
struct mmc_data data;
|
||||
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
memset(&data, 0, sizeof(struct mmc_data));
|
||||
|
||||
memset(rawextcsd, 0, 512);
|
||||
cmd.opcode = MMC_SEND_EXT_CSD;
|
||||
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
|
||||
cmd.arg = 0;
|
||||
cmd.data = &data;
|
||||
|
||||
data.data = rawextcsd;
|
||||
data.len = 512;
|
||||
data.flags = MMC_DATA_READ;
|
||||
|
||||
err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES);
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
mmc_set_relative_addr(struct mmc_softc *sc, uint16_t resp)
|
||||
{
|
||||
struct mmc_command cmd;
|
||||
int err;
|
||||
|
||||
cmd.opcode = MMC_SET_RELATIVE_ADDR;
|
||||
cmd.arg = resp << 16;
|
||||
cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
|
||||
cmd.data = NULL;
|
||||
err = mmc_wait_for_cmd(sc, &cmd, 0);
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
mmc_send_relative_addr(struct mmc_softc *sc, uint32_t *resp)
|
||||
{
|
||||
@ -623,6 +998,8 @@ mmc_discover_cards(struct mmc_softc *sc)
|
||||
int err;
|
||||
uint32_t resp;
|
||||
device_t child;
|
||||
uint16_t rca = 2;
|
||||
u_char switch_res[64];
|
||||
|
||||
while (1) {
|
||||
ivar = malloc(sizeof(struct mmc_ivars), M_DEVBUF,
|
||||
@ -636,22 +1013,75 @@ mmc_discover_cards(struct mmc_softc *sc)
|
||||
device_printf(sc->dev, "Error reading CID %d\n", err);
|
||||
break;
|
||||
}
|
||||
if (mmcbr_get_mode(sc->dev) == mode_sd) {
|
||||
ivar->mode = mode_sd;
|
||||
if (mmcbr_get_ro(sc->dev))
|
||||
ivar->read_only = 1;
|
||||
ivar->bus_width = bus_width_1;
|
||||
ivar->mode = mmcbr_get_mode(sc->dev);
|
||||
if (ivar->mode == mode_sd) {
|
||||
mmc_decode_cid(1, ivar->raw_cid, &ivar->cid);
|
||||
mmc_send_relative_addr(sc, &resp);
|
||||
ivar->rca = resp >> 16;
|
||||
if (mmcbr_get_ro(sc->dev))
|
||||
ivar->read_only = 1;
|
||||
/* Get card CSD. */
|
||||
mmc_send_csd(sc, ivar->rca, ivar->raw_csd);
|
||||
mmc_decode_csd(1, ivar->raw_csd, &ivar->csd);
|
||||
printf("SD CARD: %lld bytes\n", (long long)
|
||||
ivar->csd.capacity);
|
||||
if (ivar->csd.csd_structure > 0)
|
||||
ivar->high_cap = 1;
|
||||
ivar->tran_speed = ivar->csd.tran_speed;
|
||||
/* 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);
|
||||
mmc_app_decode_scr(ivar->raw_scr, &ivar->scr);
|
||||
/* Get card switch capabilities. */
|
||||
if ((ivar->scr.sda_vsn >= 1) &&
|
||||
(ivar->csd.ccc & (1<<10))) {
|
||||
mmc_sd_switch(sc, 0, 0, 0xF, switch_res);
|
||||
if (switch_res[13] & 2) {
|
||||
ivar->timing = bus_timing_hs;
|
||||
ivar->hs_tran_speed = 50000000;
|
||||
}
|
||||
}
|
||||
mmc_select_card(sc, 0);
|
||||
/* Find max supported bus width. */
|
||||
if ((mmcbr_get_caps(sc->dev) & MMC_CAP_4_BIT_DATA) &&
|
||||
(ivar->scr.bus_widths & SD_SCR_BUS_WIDTH_4))
|
||||
ivar->bus_width = bus_width_4;
|
||||
/* Add device. */
|
||||
child = device_add_child(sc->dev, NULL, -1);
|
||||
device_set_ivars(child, ivar);
|
||||
return;
|
||||
}
|
||||
panic("Write MMC card code here");
|
||||
mmc_decode_cid(0, ivar->raw_cid, &ivar->cid);
|
||||
ivar->rca = rca++;
|
||||
mmc_set_relative_addr(sc, ivar->rca);
|
||||
/* Get card CSD. */
|
||||
mmc_send_csd(sc, ivar->rca, ivar->raw_csd);
|
||||
mmc_decode_csd(0, ivar->raw_csd, &ivar->csd);
|
||||
ivar->tran_speed = ivar->csd.tran_speed;
|
||||
/* Only MMC >= 4.x cards support EXT_CSD. */
|
||||
if (ivar->csd.spec_vers >= 4) {
|
||||
/* Card must be selected to fetch EXT_CSD. */
|
||||
mmc_select_card(sc, ivar->rca);
|
||||
mmc_send_ext_csd(sc, ivar->raw_ext_csd);
|
||||
/* Get card speed in high speed mode. */
|
||||
ivar->timing = bus_timing_hs;
|
||||
if (((uint8_t *)(ivar->raw_ext_csd))[EXT_CSD_CARD_TYPE]
|
||||
& EXT_CSD_CARD_TYPE_52)
|
||||
ivar->hs_tran_speed = 52000000;
|
||||
else if (((uint8_t *)(ivar->raw_ext_csd))[EXT_CSD_CARD_TYPE]
|
||||
& EXT_CSD_CARD_TYPE_26)
|
||||
ivar->hs_tran_speed = 26000000;
|
||||
else
|
||||
ivar->hs_tran_speed = ivar->tran_speed;
|
||||
/* Find max supported bus width. */
|
||||
ivar->bus_width = mmc_test_bus_width(sc);
|
||||
mmc_select_card(sc, 0);
|
||||
} else {
|
||||
ivar->bus_width = bus_width_1;
|
||||
ivar->timing = bus_timing_normal;
|
||||
}
|
||||
/* Add device. */
|
||||
child = device_add_child(sc->dev, NULL, -1);
|
||||
device_set_ivars(child, ivar);
|
||||
}
|
||||
free(ivar, M_DEVBUF);
|
||||
}
|
||||
@ -661,6 +1091,7 @@ mmc_go_discovery(struct mmc_softc *sc)
|
||||
{
|
||||
uint32_t ocr;
|
||||
device_t dev;
|
||||
int err;
|
||||
|
||||
dev = sc->dev;
|
||||
if (mmcbr_get_power_mode(dev) != power_on) {
|
||||
@ -671,7 +1102,9 @@ mmc_go_discovery(struct mmc_softc *sc)
|
||||
mmc_power_up(sc);
|
||||
mmcbr_set_bus_mode(dev, pushpull);
|
||||
mmc_idle_cards(sc);
|
||||
if (mmc_send_app_op_cond(sc, 0, &ocr) != MMC_ERR_NONE) {
|
||||
err = mmc_send_if_cond(sc, 1);
|
||||
if (mmc_send_app_op_cond(sc, err?0:MMC_OCR_CCS, &ocr) !=
|
||||
MMC_ERR_NONE) {
|
||||
/*
|
||||
* Failed, try MMC
|
||||
*/
|
||||
@ -697,9 +1130,11 @@ mmc_go_discovery(struct mmc_softc *sc)
|
||||
/*
|
||||
* Reselect the cards after we've idled them above.
|
||||
*/
|
||||
if (mmcbr_get_mode(dev) == mode_sd)
|
||||
mmc_send_app_op_cond(sc, mmcbr_get_ocr(dev), NULL);
|
||||
else
|
||||
if (mmcbr_get_mode(dev) == mode_sd) {
|
||||
err = mmc_send_if_cond(sc, 1);
|
||||
mmc_send_app_op_cond(sc,
|
||||
(err?0:MMC_OCR_CCS)|mmcbr_get_ocr(dev), NULL);
|
||||
} else
|
||||
mmc_send_op_cond(sc, mmcbr_get_ocr(dev), NULL);
|
||||
mmc_discover_cards(sc);
|
||||
|
||||
@ -712,22 +1147,47 @@ mmc_go_discovery(struct mmc_softc *sc)
|
||||
static int
|
||||
mmc_calculate_clock(struct mmc_softc *sc)
|
||||
{
|
||||
int max_dtr = 0;
|
||||
int max_dtr, max_hs_dtr, max_timing;
|
||||
int nkid, i, f_min, f_max;
|
||||
device_t *kids;
|
||||
struct mmc_ivars *ivar;
|
||||
|
||||
f_min = mmcbr_get_f_min(sc->dev);
|
||||
f_max = mmcbr_get_f_max(sc->dev);
|
||||
max_dtr = f_max;
|
||||
max_dtr = max_hs_dtr = f_max;
|
||||
if ((mmcbr_get_caps(sc->dev) & MMC_CAP_HSPEED))
|
||||
max_timing = bus_timing_hs;
|
||||
else
|
||||
max_timing = bus_timing_normal;
|
||||
if (device_get_children(sc->dev, &kids, &nkid) != 0)
|
||||
panic("can't get children");
|
||||
for (i = 0; i < nkid; i++)
|
||||
if (mmc_get_tran_speed(kids[i]) < max_dtr)
|
||||
max_dtr = mmc_get_tran_speed(kids[i]);
|
||||
for (i = 0; i < nkid; i++) {
|
||||
ivar = device_get_ivars(kids[i]);
|
||||
if (ivar->timing < max_timing)
|
||||
max_timing = ivar->timing;
|
||||
if (ivar->tran_speed < max_dtr)
|
||||
max_dtr = ivar->tran_speed;
|
||||
if (ivar->hs_tran_speed < max_dtr)
|
||||
max_hs_dtr = ivar->hs_tran_speed;
|
||||
}
|
||||
for (i = 0; i < nkid; i++) {
|
||||
ivar = device_get_ivars(kids[i]);
|
||||
if (ivar->timing == bus_timing_normal)
|
||||
continue;
|
||||
mmc_select_card(sc, ivar->rca);
|
||||
mmc_set_timing(sc, max_timing);
|
||||
}
|
||||
mmc_select_card(sc, 0);
|
||||
free(kids, M_TEMP);
|
||||
device_printf(sc->dev, "setting transfer rate to %d.%03dMHz\n",
|
||||
max_dtr / 1000000, (max_dtr / 1000) % 1000);
|
||||
return (max_dtr);
|
||||
if (max_timing == bus_timing_hs)
|
||||
max_dtr = max_hs_dtr;
|
||||
device_printf(sc->dev, "setting transfer rate to %d.%03dMHz%s\n",
|
||||
max_dtr / 1000000, (max_dtr / 1000) % 1000,
|
||||
(max_timing == bus_timing_hs)?" with high speed timing":"");
|
||||
mmcbr_set_timing(sc->dev, max_timing);
|
||||
mmcbr_set_clock(sc->dev, max_dtr);
|
||||
mmcbr_update_ios(sc->dev);
|
||||
return max_dtr;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -741,8 +1201,7 @@ mmc_scan(struct mmc_softc *sc)
|
||||
if (mmcbr_get_power_mode(dev) == power_on)
|
||||
mmc_rescan_cards(sc);
|
||||
mmc_go_discovery(sc);
|
||||
mmcbr_set_clock(dev, mmc_calculate_clock(sc));
|
||||
mmcbr_update_ios(dev);
|
||||
mmc_calculate_clock(sc);
|
||||
|
||||
mmc_release_bus(dev, dev);
|
||||
/* XXX probe/attach/detach children? */
|
||||
@ -774,6 +1233,9 @@ mmc_read_ivar(device_t bus, device_t child, int which, u_char *result)
|
||||
case MMC_IVAR_READ_ONLY:
|
||||
*(int *)result = ivar->read_only;
|
||||
break;
|
||||
case MMC_IVAR_HIGH_CAP:
|
||||
*(int *)result = ivar->high_cap;
|
||||
break;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
@ -71,6 +71,7 @@ enum mmcbr_device_ivars {
|
||||
MMCBR_IVAR_POWER_MODE,
|
||||
MMCBR_IVAR_VDD,
|
||||
MMCBR_IVAR_CAPS,
|
||||
MMCBR_IVAR_TIMING,
|
||||
// MMCBR_IVAR_,
|
||||
};
|
||||
|
||||
@ -92,6 +93,7 @@ MMCBR_ACCESSOR(ocr, OCR, int)
|
||||
MMCBR_ACCESSOR(power_mode, POWER_MODE, int)
|
||||
MMCBR_ACCESSOR(vdd, VDD, int)
|
||||
MMCBR_ACCESSOR(caps, CAPS, int)
|
||||
MMCBR_ACCESSOR(timing, TIMING, int)
|
||||
|
||||
static int __inline
|
||||
mmcbr_update_ios(device_t dev)
|
||||
|
@ -86,7 +86,7 @@ struct mmc_command {
|
||||
#define MMC_RSP_R2 (MMC_RSP_PRESENT | MMC_RSP_136 | MMC_RSP_CRC)
|
||||
#define MMC_RSP_R3 (MMC_RSP_PRESENT)
|
||||
#define MMC_RSP_R6 (MMC_RSP_PRESENT | MMC_RSP_CRC)
|
||||
/* R7 -- new in sd 2.0 */
|
||||
#define MMC_RSP_R7 (MMC_RSP_PRESENT | MMC_RSP_CRC)
|
||||
#define MMC_RSP(x) ((x) & MMC_RSP_MASK)
|
||||
uint32_t retries;
|
||||
uint32_t error;
|
||||
@ -181,16 +181,23 @@ struct mmc_request {
|
||||
#define SD_SEND_RELATIVE_ADDR 3
|
||||
#define MMC_SET_DSR 4
|
||||
/* reserved: 5 */
|
||||
#define MMC_SWITCH_FUNC 6
|
||||
#define MMC_SWITCH_FUNC_CMDS 0
|
||||
#define MMC_SWITCH_FUNC_SET 1
|
||||
#define MMC_SWITCH_FUNC_CLR 2
|
||||
#define MMC_SWITCH_FUNC_WR 3
|
||||
#define MMC_SELECT_CARD 7
|
||||
#define MMC_DESELECT_CARD 7
|
||||
#define MMC_SEND_IF_COND 8
|
||||
#define MMC_SEND_EXT_CSD 8
|
||||
#define SD_SEND_IF_COND 8
|
||||
#define MMC_SEND_CSD 9
|
||||
#define MMC_SEND_CID 10
|
||||
#define MMC_READ_DAT_UNTIL_STOP 11
|
||||
#define MMC_STOP_TRANSMISSION 12
|
||||
#define MMC_SEND_STATUS 13
|
||||
/* reserved: 14 */
|
||||
#define MMC_BUSTEST_R 14
|
||||
#define MMC_GO_INACTIVE_STATE 15
|
||||
#define MMC_BUSTEST_W 19
|
||||
|
||||
/* Class 2: Block oriented read commands */
|
||||
#define MMC_SET_BLOCKLEN 16
|
||||
@ -277,6 +284,37 @@ struct mmc_request {
|
||||
#define ACMD_SET_CLR_CARD_DETECT 42
|
||||
#define ACMD_SEND_SCR 51
|
||||
|
||||
/*
|
||||
* EXT_CSD fields
|
||||
*/
|
||||
|
||||
#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 */
|
||||
|
||||
/*
|
||||
* EXT_CSD field definitions
|
||||
*/
|
||||
|
||||
#define EXT_CSD_CMD_SET_NORMAL 1
|
||||
#define EXT_CSD_CMD_SET_SECURE 2
|
||||
#define EXT_CSD_CMD_SET_CPSECURE 4
|
||||
|
||||
#define EXT_CSD_CARD_TYPE_26 1
|
||||
#define EXT_CSD_CARD_TYPE_52 2
|
||||
|
||||
#define EXT_CSD_BUS_WIDTH_1 0
|
||||
#define EXT_CSD_BUS_WIDTH_4 1
|
||||
#define EXT_CSD_BUS_WIDTH_8 2
|
||||
|
||||
/*
|
||||
* SD bus widths
|
||||
*/
|
||||
#define SD_BUS_WIDTH_1 0
|
||||
#define SD_BUS_WIDTH_4 2
|
||||
|
||||
/* OCR bits */
|
||||
|
||||
/*
|
||||
@ -328,6 +366,7 @@ struct mmc_cid {
|
||||
struct mmc_csd
|
||||
{
|
||||
uint8_t csd_structure;
|
||||
uint8_t spec_vers;
|
||||
uint16_t ccc;
|
||||
uint16_t tacc;
|
||||
uint32_t nsac;
|
||||
@ -351,6 +390,14 @@ struct mmc_csd
|
||||
wp_grp_enable:1;
|
||||
};
|
||||
|
||||
struct mmc_scr
|
||||
{
|
||||
unsigned char sda_vsn;
|
||||
unsigned char bus_widths;
|
||||
#define SD_SCR_BUS_WIDTH_1 (1<<0)
|
||||
#define SD_SCR_BUS_WIDTH_4 (1<<2)
|
||||
};
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
@ -106,6 +106,7 @@ static int
|
||||
mmcsd_probe(device_t dev)
|
||||
{
|
||||
|
||||
device_quiet(dev);
|
||||
device_set_desc(dev, "MMC/SD Memory Card");
|
||||
return (0);
|
||||
}
|
||||
@ -256,7 +257,9 @@ mmcsd_task(void *arg)
|
||||
else
|
||||
cmd.opcode = MMC_WRITE_BLOCK;
|
||||
}
|
||||
cmd.arg = block << 9;
|
||||
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;
|
||||
|
@ -62,6 +62,7 @@ enum mmc_device_ivars {
|
||||
MMC_IVAR_SECTOR_SIZE,
|
||||
MMC_IVAR_TRAN_SPEED,
|
||||
MMC_IVAR_READ_ONLY,
|
||||
MMC_IVAR_HIGH_CAP,
|
||||
// MMC_IVAR_,
|
||||
};
|
||||
|
||||
@ -77,5 +78,6 @@ MMC_ACCESSOR(rca, RCA, int)
|
||||
MMC_ACCESSOR(sector_size, SECTOR_SIZE, int)
|
||||
MMC_ACCESSOR(tran_speed, TRAN_SPEED, int)
|
||||
MMC_ACCESSOR(read_only, READ_ONLY, int)
|
||||
MMC_ACCESSOR(high_cap, HIGH_CAP, int)
|
||||
|
||||
#endif /* DEV_MMC_MMCVAR_H */
|
||||
|
Loading…
x
Reference in New Issue
Block a user