svn commit: r186786 - stable/7/sys/dev/mmc
Alexander Motin
mav at FreeBSD.org
Mon Jan 5 11:40:11 PST 2009
Author: mav
Date: Mon Jan 5 19:40:09 2009
New Revision: 186786
URL: http://svn.freebsd.org/changeset/base/186786
Log:
Sync MMC/SD subsystem with HEAD.
Add support for MMC and SDHC cards, high speed timing, wide bus, multiblock
transfers and many other features.
Modified:
stable/7/sys/dev/mmc/bridge.h
stable/7/sys/dev/mmc/mmc.c
stable/7/sys/dev/mmc/mmcbrvar.h
stable/7/sys/dev/mmc/mmcreg.h
stable/7/sys/dev/mmc/mmcsd.c
stable/7/sys/dev/mmc/mmcvar.h
Modified: stable/7/sys/dev/mmc/bridge.h
==============================================================================
--- stable/7/sys/dev/mmc/bridge.h Mon Jan 5 17:38:03 2009 (r186785)
+++ stable/7/sys/dev/mmc/bridge.h Mon Jan 5 19:40:09 2009 (r186786)
@@ -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 */
};
Modified: stable/7/sys/dev/mmc/mmc.c
==============================================================================
--- stable/7/sys/dev/mmc/mmc.c Mon Jan 5 17:38:03 2009 (r186785)
+++ stable/7/sys/dev/mmc/mmc.c Mon Jan 5 19:40:09 2009 (r186786)
@@ -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,10 +83,23 @@ 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 */
+ 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 */
+ u_char high_cap; /* High Capacity card (block addressed) */
+ 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
@@ -94,21 +108,32 @@ struct mmc_ivars {
static int mmc_probe(device_t dev);
static int mmc_attach(device_t dev);
static int mmc_detach(device_t dev);
+static int mmc_suspend(device_t dev);
+static int mmc_resume(device_t dev);
#define MMC_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
#define MMC_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
-#define MMC_LOCK_INIT(_sc) \
- mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \
+#define MMC_LOCK_INIT(_sc) \
+ mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \
"mmc", MTX_DEF)
#define MMC_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
#define MMC_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED);
#define MMC_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
+static int mmc_calculate_clock(struct mmc_softc *sc);
static void mmc_delayed_attach(void *);
+static void mmc_power_down(struct mmc_softc *sc);
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_card_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_scan(struct mmc_softc *sc);
+static int mmc_delete_cards(struct mmc_softc *sc);
static void
mmc_ms_delay(int ms)
@@ -120,7 +145,7 @@ static int
mmc_probe(device_t dev)
{
- device_set_desc(dev, "mmc/sd bus");
+ device_set_desc(dev, "MMC/SD bus");
return (0);
}
@@ -145,35 +170,47 @@ static int
mmc_detach(device_t dev)
{
struct mmc_softc *sc = device_get_softc(dev);
- device_t *kids;
- int i, nkid;
-
- /* kill children [ph33r]. -sorbo */
- if (device_get_children(sc->dev, &kids, &nkid) != 0)
- return 0;
- for (i = 0; i < nkid; i++) {
- device_t kid = kids[i];
- void *ivar = device_get_ivars(kid);
-
- device_detach(kid);
- device_delete_child(sc->dev, kid);
- free(ivar, M_DEVBUF);
- }
- free(kids, M_TEMP);
+ int err;
+ if ((err = mmc_delete_cards(sc)) != 0)
+ return (err);
+ mmc_power_down(sc);
MMC_LOCK_DESTROY(sc);
- return 0;
+ return (0);
+}
+
+static int
+mmc_suspend(device_t dev)
+{
+ struct mmc_softc *sc = device_get_softc(dev);
+ int err;
+
+ err = bus_generic_suspend(dev);
+ if (err)
+ return (err);
+ mmc_power_down(sc);
+ return (0);
+}
+
+static int
+mmc_resume(device_t dev)
+{
+ struct mmc_softc *sc = device_get_softc(dev);
+
+ mmc_scan(sc);
+ return (bus_generic_resume(dev));
}
static int
mmc_acquire_bus(device_t busdev, device_t dev)
{
struct mmc_softc *sc;
+ struct mmc_ivars *ivar;
int err;
int rca;
- err = MMCBR_ACQUIRE_HOST(device_get_parent(busdev), dev);
+ err = MMCBR_ACQUIRE_HOST(device_get_parent(busdev), busdev);
if (err)
return (err);
sc = device_get_softc(busdev);
@@ -184,24 +221,36 @@ mmc_acquire_bus(device_t busdev, device_
MMC_UNLOCK(sc);
if (busdev != dev) {
- // Keep track of the last rca that we've selected. If
- // we're asked to do it again, don't. We never unselect
- // unless the bus code itself wants the mmc bus.
+ /*
+ * Keep track of the last rca that we've selected. If
+ * we're asked to do it again, don't. We never
+ * unselect unless the bus code itself wants the mmc
+ * bus, and constantly reselecting causes problems.
+ */
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);
+ if (bootverbose) {
+ 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_card_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 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);
@@ -221,7 +270,7 @@ mmc_release_bus(device_t busdev, device_
if (sc->owner != dev)
panic("mmc: you don't own the bus. game over.");
MMC_UNLOCK(sc);
- err = MMCBR_RELEASE_HOST(device_get_parent(busdev), dev);
+ err = MMCBR_RELEASE_HOST(device_get_parent(busdev), busdev);
if (err)
return (err);
MMC_LOCK(sc);
@@ -230,17 +279,11 @@ mmc_release_bus(device_t busdev, device_
return (0);
}
-static void
-mmc_rescan_cards(struct mmc_softc *sc)
-{
- /* XXX: Look at the children and see if they respond to status */
-}
-
static uint32_t
mmc_select_vdd(struct mmc_softc *sc, uint32_t ocr)
{
- // XXX
- return ocr;
+
+ return (ocr & MMC_OCR_VOLTAGE);
}
static int
@@ -250,7 +293,7 @@ mmc_highest_voltage(uint32_t ocr)
for (i = 30; i >= 0; i--)
if (ocr & (1 << i))
- return i;
+ return (i);
return (-1);
}
@@ -259,31 +302,25 @@ mmc_wakeup(struct mmc_request *req)
{
struct mmc_softc *sc;
-// printf("Wakeup for req %p done_data %p\n", req, req->done_data);
sc = (struct mmc_softc *)req->done_data;
MMC_LOCK(sc);
req->flags |= MMC_REQ_DONE;
- wakeup(req);
MMC_UNLOCK(sc);
+ wakeup(req);
}
static int
mmc_wait_for_req(struct mmc_softc *sc, struct mmc_request *req)
{
- int err;
req->done = mmc_wakeup;
req->done_data = sc;
-// printf("Submitting request %p sc %p\n", req, sc);
MMCBR_REQUEST(device_get_parent(sc->dev), sc->dev, req);
MMC_LOCK(sc);
- do {
- err = msleep(req, &sc->sc_mtx, PZERO | PCATCH, "mmcreq",
- hz / 10);
- } while (!(req->flags & MMC_REQ_DONE) && err == EAGAIN);
-// printf("Request %p done with error %d\n", req, err);
+ while ((req->flags & MMC_REQ_DONE) == 0)
+ msleep(req, &sc->sc_mtx, 0, "mmcreq", 0);
MMC_UNLOCK(sc);
- return (err);
+ return (0);
}
static int
@@ -291,7 +328,7 @@ mmc_wait_for_request(device_t brdev, dev
{
struct mmc_softc *sc = device_get_softc(brdev);
- return mmc_wait_for_req(sc, req);
+ return (mmc_wait_for_req(sc, req));
}
static int
@@ -302,9 +339,8 @@ mmc_wait_for_cmd(struct mmc_softc *sc, s
memset(&mreq, 0, sizeof(mreq));
memset(cmd->resp, 0, sizeof(cmd->resp));
cmd->retries = retries;
- cmd->data = NULL;
mreq.cmd = cmd;
-// printf("CMD: %x ARG %x\n", cmd->opcode, cmd->arg);
+/* printf("CMD: %x ARG %x\n", cmd->opcode, cmd->arg); */
mmc_wait_for_req(sc, &mreq);
return (cmd->error);
}
@@ -320,6 +356,7 @@ mmc_wait_for_app_cmd(struct mmc_softc *s
appcmd.opcode = MMC_APP_CMD;
appcmd.arg = rca << 16;
appcmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ appcmd.data = NULL;
mmc_wait_for_cmd(sc, &appcmd, 0);
err = appcmd.error;
if (err != MMC_ERR_NONE)
@@ -345,6 +382,7 @@ mmc_wait_for_command(struct mmc_softc *s
cmd.opcode = opcode;
cmd.arg = arg;
cmd.flags = flags;
+ cmd.data = NULL;
err = mmc_wait_for_cmd(sc, &cmd, retries);
if (err)
return (err);
@@ -374,6 +412,7 @@ mmc_idle_cards(struct mmc_softc *sc)
cmd.opcode = MMC_GO_IDLE_STATE;
cmd.arg = 0;
cmd.flags = MMC_RSP_NONE | MMC_CMD_BC;
+ cmd.data = NULL;
mmc_wait_for_cmd(sc, &cmd, 0);
mmc_ms_delay(1);
@@ -392,19 +431,21 @@ mmc_send_app_op_cond(struct mmc_softc *s
cmd.opcode = ACMD_SD_SEND_OP_COND;
cmd.arg = ocr;
cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
+ cmd.data = NULL;
for (i = 0; i < 100; i++) {
err = mmc_wait_for_app_cmd(sc, 0, &cmd, CMD_RETRIES);
if (err != MMC_ERR_NONE)
break;
- if ((cmd.resp[0] & MMC_OCR_CARD_BUSY) || ocr == 0)
+ if ((cmd.resp[0] & MMC_OCR_CARD_BUSY) ||
+ (ocr & MMC_OCR_VOLTAGE) == 0)
break;
err = MMC_ERR_TIMEOUT;
mmc_ms_delay(10);
}
if (rocr && err == MMC_ERR_NONE)
*rocr = cmd.resp[0];
- return err;
+ return (err);
}
static int
@@ -417,19 +458,37 @@ mmc_send_op_cond(struct mmc_softc *sc, u
cmd.opcode = MMC_SEND_OP_COND;
cmd.arg = ocr;
cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
+ cmd.data = NULL;
for (i = 0; i < 100; i++) {
err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES);
if (err != MMC_ERR_NONE)
break;
- if ((cmd.resp[0] & MMC_OCR_CARD_BUSY) || ocr == 0)
+ if ((cmd.resp[0] & MMC_OCR_CARD_BUSY) ||
+ (ocr & MMC_OCR_VOLTAGE) == 0)
break;
err = MMC_ERR_TIMEOUT;
mmc_ms_delay(10);
}
if (rocr && err == MMC_ERR_NONE)
*rocr = cmd.resp[0];
- return err;
+ 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
@@ -448,43 +507,269 @@ 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);
}
-// I wonder if the following is endian safe.
+static void
+mmc_power_down(struct mmc_softc *sc)
+{
+ device_t dev = sc->dev;
+
+ mmcbr_set_bus_mode(dev, opendrain);
+ mmcbr_set_chip_select(dev, cs_dontcare);
+ 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)
+{
+ int flags;
+
+ flags = (rca ? MMC_RSP_R1B : MMC_RSP_NONE) | MMC_CMD_AC;
+ return (mmc_wait_for_command(sc, MMC_SELECT_CARD, (uint32_t)rca << 16,
+ flags, 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 * 4));
+ cmd.arg |= value << (grp * 4);
+ 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_card_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)
+mmc_get_bits(uint32_t *bits, int bit_len, int start, int size)
{
- const int i = 3 - (start / 32);
+ const int i = (bit_len / 32) - (start / 32) - 1;
const int shift = start & 31;
uint32_t retval = bits[i] >> shift;
if (size + shift > 32)
retval |= bits[i - 1] << (32 - shift);
- return retval & ((1 << size) - 1);
+ return (retval & ((1 << size) - 1));
}
static void
-mmc_decode_cid(int is_sd, uint32_t *raw_cid, struct mmc_cid *cid)
+mmc_decode_cid_sd(uint32_t *raw_cid, struct mmc_cid *cid)
{
int i;
+ /* There's no version info, so we take it on faith */
memset(cid, 0, sizeof(*cid));
- if (is_sd) {
- /* There's no version info, so we take it on faith */
- cid->mid = mmc_get_bits(raw_cid, 120, 8);
- cid->oid = mmc_get_bits(raw_cid, 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);
- } else {
- // XXX write me
- panic("write mmc cid decoder");
- }
+ 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, 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
+mmc_decode_cid_mmc(uint32_t *raw_cid, struct mmc_cid *cid)
+{
+ int i;
+
+ /* There's no version info, so we take it on faith */
+ memset(cid, 0, sizeof(*cid));
+ 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, 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] = {
@@ -501,50 +786,142 @@ static const int cur_max[8] = {
};
static void
-mmc_decode_csd(int is_sd, uint32_t *raw_csd, struct mmc_csd *csd)
+mmc_decode_csd_sd(uint32_t *raw_csd, struct mmc_csd *csd)
{
int v;
int m;
int e;
memset(csd, 0, sizeof(*csd));
- if (is_sd) {
- csd->csd_structure = v = mmc_get_bits(raw_csd, 126, 2);
- if (v == 0) {
- 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, 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 if (v == 1) {
- panic("Write SDHC CSD parser");
- } else
- panic("unknown SD CSD version");
- } else {
- panic("Write a MMC CSD parser");
+ csd->csd_structure = v = mmc_get_bits(raw_csd, 128, 126, 2);
+ if (v == 0) {
+ 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, 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, 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, 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, 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, 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, 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, 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");
+}
+
+static void
+mmc_decode_csd_mmc(uint32_t *raw_csd, struct mmc_csd *csd)
+{
+ int m;
+ int e;
+
+ memset(csd, 0, sizeof(*csd));
+ 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, 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, 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 = 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;
+
+ memset(scr, 0, sizeof(*scr));
+
+ 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(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
@@ -556,6 +933,7 @@ mmc_all_send_cid(struct mmc_softc *sc, u
cmd.opcode = MMC_ALL_SEND_CID;
cmd.arg = 0;
cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
+ cmd.data = NULL;
err = mmc_wait_for_cmd(sc, &cmd, 0);
memcpy(rawcid, cmd.resp, 4 * sizeof(uint32_t));
return (err);
@@ -570,12 +948,103 @@ mmc_send_csd(struct mmc_softc *sc, uint1
cmd.opcode = MMC_SEND_CSD;
cmd.arg = rca << 16;
cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
+ cmd.data = NULL;
err = mmc_wait_for_cmd(sc, &cmd, 0);
memcpy(rawcid, cmd.resp, 4 * sizeof(uint32_t));
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_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;
+ 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)
{
struct mmc_command cmd;
@@ -584,6 +1053,7 @@ mmc_send_relative_addr(struct mmc_softc
cmd.opcode = SD_SEND_RELATIVE_ADDR;
cmd.arg = 0;
cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
+ cmd.data = NULL;
err = mmc_wait_for_cmd(sc, &cmd, 0);
*resp = cmd.resp[0];
return (err);
@@ -592,39 +1062,182 @@ mmc_send_relative_addr(struct mmc_softc
static void
mmc_discover_cards(struct mmc_softc *sc)
{
- struct mmc_ivars *ivar;
- int err;
- uint32_t resp;
+ struct mmc_ivars *ivar = NULL;
+ device_t *devlist;
+ int err, i, devcount, newcard;
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-all
mailing list