Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/sdmmc Read SD status register and print card status ...
details: https://anonhg.NetBSD.org/src/rev/f657c923d1f8
branches: trunk
changeset: 354669:f657c923d1f8
user: jmcneill <jmcneill%NetBSD.org@localhost>
date: Sat Jun 24 23:07:35 2017 +0000
description:
Read SD status register and print card status when a new SD card is found:
sdmmc0: SD card status: 4-bit, C10, U1, V10
If the SD status register reports discard support, set the DISCARD arg to
the ERASE operation to let the card know that the host doesn't care if the
erase is performed.
diffstat:
sys/dev/sdmmc/sdmmc_mem.c | 158 +++++++++++++++++++++++++++++++++++++++++++++-
sys/dev/sdmmc/sdmmcreg.h | 42 +++++++++++-
sys/dev/sdmmc/sdmmcvar.h | 3 +-
3 files changed, 198 insertions(+), 5 deletions(-)
diffs (287 lines):
diff -r 75eb3785998b -r f657c923d1f8 sys/dev/sdmmc/sdmmc_mem.c
--- a/sys/dev/sdmmc/sdmmc_mem.c Sat Jun 24 13:43:36 2017 +0000
+++ b/sys/dev/sdmmc/sdmmc_mem.c Sat Jun 24 23:07:35 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: sdmmc_mem.c,v 1.58 2017/06/24 11:27:33 jmcneill Exp $ */
+/* $NetBSD: sdmmc_mem.c,v 1.59 2017/06/24 23:07:35 jmcneill Exp $ */
/* $OpenBSD: sdmmc_mem.c,v 1.10 2009/01/09 10:55:22 jsg Exp $ */
/*
@@ -45,7 +45,7 @@
/* Routines for SD/MMC memory cards. */
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.58 2017/06/24 11:27:33 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.59 2017/06/24 23:07:35 jmcneill Exp $");
#ifdef _KERNEL_OPT
#include "opt_sdmmc.h"
@@ -79,6 +79,10 @@
static int sdmmc_mem_send_scr(struct sdmmc_softc *, struct sdmmc_function *,
uint32_t *scr);
static int sdmmc_mem_decode_scr(struct sdmmc_softc *, struct sdmmc_function *);
+static int sdmmc_mem_send_ssr(struct sdmmc_softc *, struct sdmmc_function *,
+ sdmmc_bitfield512_t *);
+static int sdmmc_mem_decode_ssr(struct sdmmc_softc *, struct sdmmc_function *,
+ sdmmc_bitfield512_t *);
static int sdmmc_mem_send_cxd_data(struct sdmmc_softc *, int, void *, size_t);
static int sdmmc_set_bus_width(struct sdmmc_function *, int);
static int sdmmc_mem_sd_switch(struct sdmmc_function *, int, int, int, sdmmc_bitfield512_t *);
@@ -778,7 +782,7 @@
sdmmc_mem_sd_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
{
int support_func, best_func, bus_clock, error, i;
- sdmmc_bitfield512_t status; /* Switch Function Status */
+ sdmmc_bitfield512_t status;
bool ddr = false;
/* change bus clock */
@@ -888,6 +892,15 @@
sc->sc_transfer_mode = switch_group0_functions[best_func].name;
sc->sc_busddr = ddr;
+ /* get card status */
+ error = sdmmc_mem_send_ssr(sc, sf, &status);
+ if (error) {
+ aprint_error_dev(sc->sc_dev, "can't get SD status: %d\n",
+ error);
+ return error;
+ }
+ sdmmc_mem_decode_ssr(sc, sf, &status);
+
/* execute tuning (UHS) */
error = sdmmc_mem_execute_tuning(sc, sf);
if (error) {
@@ -1270,6 +1283,143 @@
}
static int
+sdmmc_mem_send_ssr(struct sdmmc_softc *sc, struct sdmmc_function *sf,
+ sdmmc_bitfield512_t *ssr)
+{
+ struct sdmmc_command cmd;
+ bus_dma_segment_t ds[1];
+ void *ptr = NULL;
+ int datalen = 64;
+ int rseg;
+ int error = 0;
+
+ /* Don't lock */
+
+ if (ISSET(sc->sc_caps, SMC_CAPS_DMA)) {
+ error = bus_dmamem_alloc(sc->sc_dmat, datalen, PAGE_SIZE, 0,
+ ds, 1, &rseg, BUS_DMA_NOWAIT);
+ if (error)
+ goto out;
+ error = bus_dmamem_map(sc->sc_dmat, ds, 1, datalen, &ptr,
+ BUS_DMA_NOWAIT);
+ if (error)
+ goto dmamem_free;
+ error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmap, ptr, datalen,
+ NULL, BUS_DMA_NOWAIT|BUS_DMA_STREAMING|BUS_DMA_READ);
+ if (error)
+ goto dmamem_unmap;
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, datalen,
+ BUS_DMASYNC_PREREAD);
+ } else {
+ ptr = malloc(datalen, M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (ptr == NULL)
+ goto out;
+ }
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.c_data = ptr;
+ cmd.c_datalen = datalen;
+ cmd.c_blklen = datalen;
+ cmd.c_arg = 0;
+ cmd.c_flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1 | SCF_RSP_SPI_R1;
+ cmd.c_opcode = SD_APP_SD_STATUS;
+ if (ISSET(sc->sc_caps, SMC_CAPS_DMA))
+ cmd.c_dmamap = sc->sc_dmap;
+
+ error = sdmmc_app_command(sc, sf, &cmd);
+ if (error == 0) {
+ if (ISSET(sc->sc_caps, SMC_CAPS_DMA)) {
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, datalen,
+ BUS_DMASYNC_POSTREAD);
+ }
+ memcpy(ssr, ptr, datalen);
+ }
+
+out:
+ if (ptr != NULL) {
+ if (ISSET(sc->sc_caps, SMC_CAPS_DMA)) {
+ bus_dmamap_unload(sc->sc_dmat, sc->sc_dmap);
+dmamem_unmap:
+ bus_dmamem_unmap(sc->sc_dmat, ptr, datalen);
+dmamem_free:
+ bus_dmamem_free(sc->sc_dmat, ds, rseg);
+ } else {
+ free(ptr, M_DEVBUF);
+ }
+ }
+ DPRINTF(("%s: sdmem_mem_send_ssr: error = %d\n", SDMMCDEVNAME(sc),
+ error));
+
+ if (error == 0)
+ sdmmc_be512_to_bitfield512(ssr);
+
+#ifdef SDMMC_DEBUG
+ if (error == 0)
+ sdmmc_dump_data("SSR", ssr, datalen);
+#endif
+ return error;
+}
+
+static int
+sdmmc_mem_decode_ssr(struct sdmmc_softc *sc, struct sdmmc_function *sf,
+ sdmmc_bitfield512_t *ssr_bitfield)
+{
+ uint32_t *ssr = (uint32_t *)ssr_bitfield;
+ int speed_class_val, bus_width_val;
+
+ const int bus_width = SSR_DAT_BUS_WIDTH(ssr);
+ const int speed_class = SSR_SPEED_CLASS(ssr);
+ const int uhs_speed_grade = SSR_UHS_SPEED_GRADE(ssr);
+ const int video_speed_class = SSR_VIDEO_SPEED_CLASS(ssr);
+ const int app_perf_class = SSR_APP_PERF_CLASS(ssr);
+ const int discard_support = SSR_DISCARD_SUPPORT(ssr);
+
+ switch (speed_class) {
+ case SSR_SPEED_CLASS_0: speed_class_val = 0; break;
+ case SSR_SPEED_CLASS_2: speed_class_val = 2; break;
+ case SSR_SPEED_CLASS_4: speed_class_val = 4; break;
+ case SSR_SPEED_CLASS_6: speed_class_val = 6; break;
+ case SSR_SPEED_CLASS_10: speed_class_val = 10; break;
+ default: speed_class_val = -1; break;
+ }
+
+ switch (bus_width) {
+ case SSR_DAT_BUS_WIDTH_1: bus_width_val = 1; break;
+ case SSR_DAT_BUS_WIDTH_4: bus_width_val = 4; break;
+ default: bus_width_val = -1;
+ }
+
+ /*
+ * Log card status
+ */
+ device_printf(sc->sc_dev, "SD card status:");
+ if (bus_width_val != -1)
+ printf(" %d-bit", bus_width_val);
+ else
+ printf(" unknown bus width");
+ if (speed_class_val != -1)
+ printf(", C%d", speed_class_val);
+ if (uhs_speed_grade)
+ printf(", U%d", uhs_speed_grade);
+ if (video_speed_class)
+ printf(", V%d", video_speed_class);
+ if (app_perf_class)
+ printf(", A%d", app_perf_class);
+ if (discard_support)
+ printf(", DISCARD");
+ printf("\n");
+
+ /*
+ * Set function flags
+ */
+ if (discard_support)
+ SET(sf->flags, SFF_DISCARD);
+
+ return 0;
+}
+
+static int
sdmmc_mem_send_cxd_data(struct sdmmc_softc *sc, int opcode, void *data,
size_t datalen)
{
@@ -2036,6 +2186,8 @@
/* Start the erase operation */
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = MMC_ERASE;
+ if (ISSET(sf->flags, SFF_DISCARD))
+ cmd.c_arg = SD_ERASE_DISCARD;
cmd.c_flags = SCF_CMD_AC | SCF_RSP_R1B;
error = sdmmc_mmc_command(sc, &cmd);
if (error)
diff -r 75eb3785998b -r f657c923d1f8 sys/dev/sdmmc/sdmmcreg.h
--- a/sys/dev/sdmmc/sdmmcreg.h Sat Jun 24 13:43:36 2017 +0000
+++ b/sys/dev/sdmmc/sdmmcreg.h Sat Jun 24 23:07:35 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: sdmmcreg.h,v 1.30 2017/06/24 11:27:33 jmcneill Exp $ */
+/* $NetBSD: sdmmcreg.h,v 1.31 2017/06/24 23:07:35 jmcneill Exp $ */
/* $OpenBSD: sdmmcreg.h,v 1.4 2009/01/09 10:55:22 jsg Exp $ */
/*
@@ -70,6 +70,10 @@
#define SD_APP_OP_COND 41 /* R3 */
#define SD_APP_SEND_SCR 51 /* R1 */
+/* SD erase arguments */
+#define SD_ERASE_DISCARD 0x00000001
+#define SD_ERASE_FULE 0x00000002
+
/* OCR bits */
#define MMC_OCR_MEM_READY (1U<<31)/* memory power-up status bit */
#define MMC_OCR_HCS (1<<30) /* SD only */
@@ -345,6 +349,42 @@
#define SCR_CMD_SUPPORT_CMD20(scr) MMC_RSP_BITS((scr), 32, 1)
#define SCR_RESERVED2(scr) MMC_RSP_BITS((scr), 0, 32)
+/* SSR (SD Status Register) */
+#define SSR_DAT_BUS_WIDTH(resp) __bitfield((resp), 510, 2)
+#define SSR_DAT_BUS_WIDTH_1 0
+#define SSR_DAT_BUS_WIDTH_4 2
+#define SSR_SECURED_MODE(resp) __bitfield((resp), 509, 1)
+#define SSR_SD_CARD_TYPE(resp) __bitfield((resp), 480, 16)
+#define SSR_SD_CARD_TYPE_RDWR 0
+#define SSR_SD_CARD_TYPE_ROM 1
+#define SSR_SD_CARD_TYPE_OTP 2
+#define SSR_SIZE_OF_PROTECTED_AREA(resp) __bitfield((resp), 448, 32)
+#define SSR_SPEED_CLASS(resp) __bitfield((resp), 440, 8)
+#define SSR_SPEED_CLASS_0 0
+#define SSR_SPEED_CLASS_2 1
+#define SSR_SPEED_CLASS_4 2
+#define SSR_SPEED_CLASS_6 3
+#define SSR_SPEED_CLASS_10 4
+#define SSR_PERFORMANCE_MOVE(resp) __bitfield((resp), 432, 8)
+#define SSR_AU_SIZE(resp) __bitfield((resp), 428, 4)
+#define SSR_ERASE_SIZE(resp) __bitfield((resp), 408, 16)
+#define SSR_ERASE_TIMEOUT(resp) __bitfield((resp), 402, 6)
+#define SSR_ERASE_OFFSET(resp) __bitfield((resp), 400, 2)
+#define SSR_UHS_SPEED_GRADE(resp) __bitfield((resp), 396, 4)
+#define SSR_UHS_SPEED_GRADE_10MB 1
+#define SSR_UHS_SPEED_GRADE_30MB 3
+#define SSR_UHS_AU_SIZE(resp) __bitfield((resp), 392, 4)
+#define SSR_VIDEO_SPEED_CLASS(resp) __bitfield((resp), 384, 8)
+#define SSR_VSC_AU_SIZE(resp) __bitfield((resp), 368, 10)
+#define SSR_SUS_ADDR(resp) __bitfield((resp), 346, 22)
+#define SSR_APP_PERF_CLASS(resp) __bitfield((resp), 336, 4)
+#define SSR_APP_PERF_CLASS_UNSUPPORTED 0
+#define SSR_APP_PERF_CLASS_A1 1
+#define SSR_APP_PERF_CLASS_A2 2
+#define SSR_PERFORMANCE_ENHANCE(resp) __bitfield((resp), 328, 8)
+#define SSR_DISCARD_SUPPORT(resp) __bitfield((resp), 313, 1)
+#define SSR_FULE_SUPPORT(resp) __bitfield((resp), 312, 1)
+
/* Status of Switch Function */
#define SFUNC_STATUS_GROUP(status, group) \
(__bitfield((uint32_t *)(status), 400 + (group - 1) * 16, 16))
diff -r 75eb3785998b -r f657c923d1f8 sys/dev/sdmmc/sdmmcvar.h
--- a/sys/dev/sdmmc/sdmmcvar.h Sat Jun 24 13:43:36 2017 +0000
+++ b/sys/dev/sdmmc/sdmmcvar.h Sat Jun 24 23:07:35 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: sdmmcvar.h,v 1.25 2017/06/24 11:27:33 jmcneill Exp $ */
+/* $NetBSD: sdmmcvar.h,v 1.26 2017/06/24 23:07:35 jmcneill Exp $ */
/* $OpenBSD: sdmmcvar.h,v 1.13 2009/01/09 10:55:22 jsg Exp $ */
/*
@@ -185,6 +185,7 @@
int flags;
#define SFF_ERROR 0x0001 /* function is poo; ignore it */
#define SFF_SDHC 0x0002 /* SD High Capacity card */
+#define SFF_DISCARD 0x0004 /* SD card supports discard erase */
SIMPLEQ_ENTRY(sdmmc_function) sf_list;
/* SD card I/O function members */
int number; /* I/O function number or -1 */
Home |
Main Index |
Thread Index |
Old Index