Module Name:    src
Committed By:   martin
Date:           Sat Oct 26 15:26:43 UTC 2024

Modified Files:
        src/sys/dev/sdmmc [netbsd-10]: ld_sdmmc.c sdmmc_mem.c sdmmcreg.h
            sdmmcvar.h

Log Message:
Pull up following revision(s) (requested by jmcneill in ticket #985):

        sys/dev/sdmmc/sdmmcvar.h: revision 1.37
        sys/dev/sdmmc/sdmmcreg.h: revision 1.35
        sys/dev/sdmmc/ld_sdmmc.c: revision 1.44
        sys/dev/sdmmc/sdmmc_mem.c: revision 1.76

sdmmc: Add support for SD card caches.

SD physical 6.0 specification introduced Application Performance Class 2
(A2), which adds support for drive caches and command queueing.

Add support for enabling and flushing the cache when this feature is
present.


To generate a diff of this commit:
cvs rdiff -u -r1.42.4.1 -r1.42.4.2 src/sys/dev/sdmmc/ld_sdmmc.c
cvs rdiff -u -r1.74.8.1 -r1.74.8.2 src/sys/dev/sdmmc/sdmmc_mem.c
cvs rdiff -u -r1.34 -r1.34.34.1 src/sys/dev/sdmmc/sdmmcreg.h
cvs rdiff -u -r1.36 -r1.36.18.1 src/sys/dev/sdmmc/sdmmcvar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/sdmmc/ld_sdmmc.c
diff -u src/sys/dev/sdmmc/ld_sdmmc.c:1.42.4.1 src/sys/dev/sdmmc/ld_sdmmc.c:1.42.4.2
--- src/sys/dev/sdmmc/ld_sdmmc.c:1.42.4.1	Sat Feb  3 12:39:17 2024
+++ src/sys/dev/sdmmc/ld_sdmmc.c	Sat Oct 26 15:26:43 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: ld_sdmmc.c,v 1.42.4.1 2024/02/03 12:39:17 martin Exp $	*/
+/*	$NetBSD: ld_sdmmc.c,v 1.42.4.2 2024/10/26 15:26:43 martin Exp $	*/
 
 /*
  * Copyright (c) 2008 KIYOHARA Takashi
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ld_sdmmc.c,v 1.42.4.1 2024/02/03 12:39:17 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ld_sdmmc.c,v 1.42.4.2 2024/10/26 15:26:43 martin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_sdmmc.h"
@@ -322,18 +322,23 @@ ld_sdmmc_doattach(void *arg)
 	struct ld_sdmmc_softc *sc = (struct ld_sdmmc_softc *)arg;
 	struct ld_softc *ld = &sc->sc_ld;
 	struct sdmmc_softc *ssc = device_private(device_parent(ld->sc_dv));
-	const u_int cache_size = sc->sc_sf->ext_csd.cache_size;
+	const u_int emmc_cache_size = sc->sc_sf->ext_csd.cache_size;
+	const bool sd_cache = sc->sc_sf->ssr.cache;
 	char buf[sizeof("9999 KB")];
 
 	ldattach(ld, BUFQ_DISK_DEFAULT_STRAT);
 	aprint_normal_dev(ld->sc_dv, "%d-bit width,", sc->sc_sf->width);
 	if (ssc->sc_transfer_mode != NULL)
 		aprint_normal(" %s,", ssc->sc_transfer_mode);
-	if (cache_size > 0) {
-		format_bytes(buf, sizeof(buf), cache_size);
+	if (emmc_cache_size > 0) {
+		format_bytes(buf, sizeof(buf), emmc_cache_size);
 		aprint_normal(" %s cache%s,", buf,
 		    ISSET(sc->sc_sf->flags, SFF_CACHE_ENABLED) ? "" :
 		    " (disabled)");
+	} else if (sd_cache) {
+		aprint_normal(" Cache%s,",
+		    ISSET(sc->sc_sf->flags, SFF_CACHE_ENABLED) ? "" :
+		    " (disabled)");
 	}
 	if ((ssc->sc_busclk / 1000) != 0)
 		aprint_normal(" %u.%03u MHz\n",

Index: src/sys/dev/sdmmc/sdmmc_mem.c
diff -u src/sys/dev/sdmmc/sdmmc_mem.c:1.74.8.1 src/sys/dev/sdmmc/sdmmc_mem.c:1.74.8.2
--- src/sys/dev/sdmmc/sdmmc_mem.c:1.74.8.1	Sun Apr 30 10:58:07 2023
+++ src/sys/dev/sdmmc/sdmmc_mem.c	Sat Oct 26 15:26:43 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdmmc_mem.c,v 1.74.8.1 2023/04/30 10:58:07 martin Exp $	*/
+/*	$NetBSD: sdmmc_mem.c,v 1.74.8.2 2024/10/26 15:26:43 martin 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.74.8.1 2023/04/30 10:58:07 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.74.8.2 2024/10/26 15:26:43 martin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_sdmmc.h"
@@ -83,7 +83,15 @@ static int sdmmc_mem_send_ssr(struct sdm
     sdmmc_bitfield512_t *);
 static int sdmmc_mem_decode_ssr(struct sdmmc_softc *, struct sdmmc_function *,
     sdmmc_bitfield512_t *);
+static int sdmmc_mem_decode_general_info(struct sdmmc_softc *,
+    struct sdmmc_function * ,const uint8_t *);
+static int sdmmc_mem_pef_enable_cache(struct sdmmc_softc *,
+    struct sdmmc_function *);
 static int sdmmc_mem_send_cxd_data(struct sdmmc_softc *, int, void *, size_t);
+static int sdmmc_mem_read_extr_single(struct sdmmc_softc *, struct sdmmc_function *,
+    uint8_t, uint8_t, uint32_t, uint16_t, void *);
+static int sdmmc_mem_write_extr_single(struct sdmmc_softc *, struct sdmmc_function *,
+    uint8_t, uint8_t, uint32_t, uint8_t, bool);
 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 *);
 static int sdmmc_mem_mmc_switch(struct sdmmc_function *, uint8_t, uint8_t,
@@ -926,6 +934,27 @@ skipswitchfuncs:
 		return error;
 	}
 
+	/* detect extended functions */
+	if (!ISSET(sc->sc_caps, SMC_CAPS_SPI_MODE) && sf->scr.support_cmd48) {
+		uint8_t ginfo[512];
+		error = sdmmc_mem_read_extr_single(sc, sf, SD_EXTR_MIO_MEM, 0, 0,
+		    sizeof(ginfo), ginfo);
+		if (error == 0) {
+			sdmmc_mem_decode_general_info(sc, sf, ginfo);
+		}
+	}
+
+	/* enable card cache if supported */
+	if (sf->ssr.cache && sf->ext_sd.pef.valid) {
+		error = sdmmc_mem_pef_enable_cache(sc, sf);
+		if (error != 0) {
+			aprint_error_dev(sc->sc_dev,
+			    "can't enable cache: %d", error);
+		} else {
+			SET(sf->flags, SFF_CACHE_ENABLED);
+		}
+	}
+
 	return 0;
 }
 
@@ -1308,11 +1337,20 @@ sdmmc_mem_decode_scr(struct sdmmc_softc 
 
 	ver = SCR_STRUCTURE(resp);
 	sf->scr.sd_spec = SCR_SD_SPEC(resp);
+	if (sf->scr.sd_spec == 2) {
+		sf->scr.sd_spec3 = SCR_SD_SPEC3(resp);
+		if (sf->scr.sd_spec3) {
+			sf->scr.sd_spec4 = SCR_SD_SPEC4(resp);
+		}
+	}
 	sf->scr.bus_width = SCR_SD_BUS_WIDTHS(resp);
+	if (sf->scr.sd_spec4) {
+		sf->scr.support_cmd48 = SCR_CMD_SUPPORT_CMD48(resp);
+	}
 
-	DPRINTF(("%s: sdmmc_mem_decode_scr: %08x%08x ver=%d, spec=%d, bus width=%d\n",
+	DPRINTF(("%s: sdmmc_mem_decode_scr: %08x%08x ver=%d, spec=%d,%d,%d, bus width=%d\n",
 	    SDMMCDEVNAME(sc), resp[1], resp[0],
-	    ver, sf->scr.sd_spec, sf->scr.bus_width));
+	    ver, sf->scr.sd_spec, sf->scr.sd_spec3, sf->scr.sd_spec4, sf->scr.bus_width));
 
 	if (ver != 0 && ver != 1) {
 		DPRINTF(("%s: unknown structure version: %d\n",
@@ -1413,6 +1451,7 @@ sdmmc_mem_decode_ssr(struct sdmmc_softc 
 	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 uint64_t perf_enhance = SSR_PERFORMANCE_ENHANCE(ssr);
 
 	switch (speed_class) {
 	case SSR_SPEED_CLASS_0:	speed_class_val = 0; break;
@@ -1429,6 +1468,10 @@ sdmmc_mem_decode_ssr(struct sdmmc_softc 
 	default: bus_width_val = -1;
 	}
 
+	if (ISSET(perf_enhance, SSR_PERFORMANCE_ENHANCE_CACHE)) {
+		sf->ssr.cache = true;
+	}
+
 	/*
 	 * Log card status
 	 */
@@ -1445,12 +1488,104 @@ sdmmc_mem_decode_ssr(struct sdmmc_softc 
 		printf(", V%d", video_speed_class);
 	if (app_perf_class)
 		printf(", A%d", app_perf_class);
+	if (ISSET(perf_enhance, SSR_PERFORMANCE_ENHANCE_CACHE))
+		printf(", Cache");
+	if (ISSET(perf_enhance, SSR_PERFORMANCE_ENHANCE_HOST_MAINT|
+				SSR_PERFORMANCE_ENHANCE_CARD_MAINT)) {
+		printf(", %s self-maintenance",
+		       perf_enhance == SSR_PERFORMANCE_ENHANCE_HOST_MAINT ? "Host" :
+		       perf_enhance == SSR_PERFORMANCE_ENHANCE_CARD_MAINT ? "Card" :
+		       "Host/Card");
+	}
 	printf("\n");
 
 	return 0;
 }
 
 static int
+sdmmc_mem_decode_general_info(struct sdmmc_softc *sc, struct sdmmc_function *sf,
+    const uint8_t *ginfo)
+{
+	uint16_t len = SD_GENERAL_INFO_HDR_LENGTH(ginfo);
+	unsigned num_ext = SD_GENERAL_INFO_HDR_NUM_EXT(ginfo);
+	unsigned index = SD_GENERAL_INFO_EXT_FIRST;
+	unsigned ext;
+
+	DPRINTF(("%s: sdmmc_mem_decode_general_info: rev=%u, len=%u, num_ext=%u\n",
+		SDMMCDEVNAME(sc), SD_GENERAL_INFO_HDR_REVISION(ginfo),
+		len, num_ext));
+
+	/*
+	 * General Information Length can span more than one page, but for
+	 * now just parse the first one.
+	 */
+	len = uimin(SDMMC_SECTOR_SIZE, len);
+
+	for (ext = 0; ext < num_ext && index < len && index != 0; ext++) {
+		uint16_t sfc = SD_EXTENSION_INFO_SFC(ginfo, index);
+		unsigned num_reg = SD_EXTENSION_INFO_NUM_REG(ginfo, index);
+		uint32_t reg;
+
+		if (num_reg == 0) {
+			goto next_ext;
+		}
+		reg = SD_EXTENSION_INFO_REG(ginfo, index, 0);
+
+		DPRINTF(("%s: sdmmc_mem_decode_general_info: sfc=0x%04x, reg=0x%08x\n",
+			SDMMCDEVNAME(sc), sfc, reg));
+
+		switch (sfc) {
+		case SD_SFC_PEF:
+			sf->ext_sd.pef.valid = true;
+			sf->ext_sd.pef.fno =
+			    SD_EXTENSION_INFO_REG_FNO(reg);
+			sf->ext_sd.pef.start_addr = 
+			    SD_EXTENSION_INFO_REG_START_ADDR(reg);
+			break;
+		}
+
+next_ext:
+		index = SD_EXTENSION_INFO_NEXT(ginfo, index);
+	}
+
+	return 0;
+}
+
+static int
+sdmmc_mem_pef_enable_cache(struct sdmmc_softc *sc,
+    struct sdmmc_function *sf)
+{
+	uint8_t data[512];
+	int error;
+
+	error = sdmmc_mem_read_extr_single(sc, sf, SD_EXTR_MIO_MEM,
+	    sf->ext_sd.pef.fno, sf->ext_sd.pef.start_addr,
+	    sizeof(data), data);
+	if (error != 0) {
+		return error;
+	}
+
+	if (SD_PEF_CACHE_ENABLE(data)) {
+		/* Cache is already enabled. */
+		return 0;
+	}
+
+	error = sdmmc_mem_write_extr_single(sc, sf, SD_EXTR_MIO_MEM,
+	    sf->ext_sd.pef.fno,
+	    sf->ext_sd.pef.start_addr + SD_PEF_CACHE_ENABLE_OFFSET, 1,
+	    false);
+	if (error != 0) {
+		device_printf(sc->sc_dev,
+		    "setting cache enable failed: %d\n", error);
+		return error;
+	}
+
+	device_printf(sc->sc_dev, "cache enabled\n");
+
+	return 0;
+}
+
+static int
 sdmmc_mem_send_cxd_data(struct sdmmc_softc *sc, int opcode, void *data,
     size_t datalen)
 {
@@ -1524,6 +1659,168 @@ dmamem_free:
 }
 
 static int
+sdmmc_mem_read_extr_single(struct sdmmc_softc *sc, struct sdmmc_function *sf,
+    uint8_t mio, uint8_t fno, uint32_t addr, uint16_t datalen, void *data)
+{
+	struct sdmmc_command cmd;
+	bus_dma_segment_t ds[1];
+	void *ptr = NULL;
+	int rseg;
+	int error = 0;
+
+	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 = data;
+	}
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.c_data = ptr;
+	cmd.c_datalen = datalen;
+	cmd.c_blklen = SDMMC_SECTOR_SIZE;
+	cmd.c_opcode = SD_READ_EXTR_SINGLE;
+	cmd.c_arg = __SHIFTIN((uint32_t)mio, SD_EXTR_MIO) |
+		    __SHIFTIN((uint32_t)fno, SD_EXTR_FNO) |
+		    __SHIFTIN(addr, SD_EXTR_ADDR) |
+		    __SHIFTIN(datalen - 1, SD_EXTR_LEN);
+	cmd.c_flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1;
+	if (ISSET(sc->sc_caps, SMC_CAPS_DMA))
+		cmd.c_dmamap = sc->sc_dmap;
+
+	error = sdmmc_mmc_command(sc, &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(data, ptr, datalen);
+		}
+#ifdef SDMMC_DEBUG
+		sdmmc_dump_data("EXT", data, datalen);
+#endif
+	}
+
+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);
+		}
+	}
+	return error;
+}
+
+static int
+sdmmc_mem_write_extr_single(struct sdmmc_softc *sc, struct sdmmc_function *sf,
+    uint8_t mio, uint8_t fno, uint32_t addr, uint8_t value, bool poll)
+{
+	struct sdmmc_command cmd;
+	bus_dma_segment_t ds[1];
+	uint8_t buf[512];
+	uint16_t buflen = sizeof(buf);
+	void *ptr = NULL;
+	int rseg;
+	int error = 0;
+
+	if (ISSET(sc->sc_caps, SMC_CAPS_DMA)) {
+		error = bus_dmamem_alloc(sc->sc_dmat, buflen, PAGE_SIZE, 0, ds,
+		    1, &rseg, BUS_DMA_NOWAIT);
+		if (error)
+			goto out;
+		error = bus_dmamem_map(sc->sc_dmat, ds, 1, buflen, &ptr,
+		    BUS_DMA_NOWAIT);
+		if (error)
+			goto dmamem_free;
+		error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmap, ptr, buflen,
+		    NULL, BUS_DMA_NOWAIT|BUS_DMA_STREAMING|BUS_DMA_WRITE);
+		if (error)
+			goto dmamem_unmap;
+
+		memset(ptr, 0, buflen);
+		*(uint8_t *)ptr = value;
+
+		bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, buflen,
+		    BUS_DMASYNC_PREWRITE);
+	} else {
+		buf[0] = value;
+		ptr = buf;
+	}
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.c_data = ptr;
+	cmd.c_datalen = buflen;
+	cmd.c_blklen = SDMMC_SECTOR_SIZE;
+	cmd.c_opcode = SD_WRITE_EXTR_SINGLE;
+	cmd.c_arg = __SHIFTIN((uint32_t)mio, SD_EXTR_MIO) |
+		    __SHIFTIN((uint32_t)fno, SD_EXTR_FNO) |
+		    __SHIFTIN(addr, SD_EXTR_ADDR) |
+		    __SHIFTIN(0, SD_EXTR_LEN);
+	cmd.c_flags = SCF_CMD_ADTC | SCF_RSP_R1;
+	if (ISSET(sc->sc_caps, SMC_CAPS_DMA))
+		cmd.c_dmamap = sc->sc_dmap;
+
+	error = sdmmc_mmc_command(sc, &cmd);
+	if (error == 0) {
+		if (ISSET(sc->sc_caps, SMC_CAPS_DMA)) {
+			bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, buflen,
+			    BUS_DMASYNC_POSTWRITE);
+		}
+	}
+
+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, buflen);
+dmamem_free:
+			bus_dmamem_free(sc->sc_dmat, ds, rseg);
+		}
+	}
+
+	if (!error) {
+		do {
+			memset(&cmd, 0, sizeof(cmd));
+			cmd.c_opcode = MMC_SEND_STATUS;
+			cmd.c_arg = MMC_ARG_RCA(sf->rca);
+			cmd.c_flags = SCF_CMD_AC | SCF_RSP_R1 | SCF_RSP_SPI_R2 |
+				      SCF_TOUT_OK;
+			if (poll) {
+				cmd.c_flags |= SCF_POLL;
+			}
+			error = sdmmc_mmc_command(sc, &cmd);
+			if (error)
+				break;
+			/* XXX time out */
+		} while (!ISSET(MMC_R1(cmd.c_resp), MMC_R1_READY_FOR_DATA));
+
+		if (error) {
+			aprint_error_dev(sc->sc_dev,
+			    "error waiting for data ready after ext write : %d\n",
+			    error);
+		}
+	}
+
+	return error;
+}
+
+static int
 sdmmc_set_bus_width(struct sdmmc_function *sf, int width)
 {
 	struct sdmmc_softc *sc = sf->sc;
@@ -2259,15 +2556,33 @@ sdmmc_mem_flush_cache(struct sdmmc_funct
 	SDMMC_LOCK(sc);
 	mutex_enter(&sc->sc_mtx);
 
-	error = sdmmc_mem_mmc_switch(sf,
-	    EXT_CSD_CMD_SET_NORMAL, EXT_CSD_FLUSH_CACHE,
-	    EXT_CSD_FLUSH_CACHE_FLUSH, poll);
+	if (ISSET(sc->sc_flags, SMF_SD_MODE)) {
+		KASSERT(sf->ext_sd.pef.valid);
+		error = sdmmc_mem_write_extr_single(sc, sf, SD_EXTR_MIO_MEM,
+		    sf->ext_sd.pef.fno,
+		    sf->ext_sd.pef.start_addr + SD_PEF_CACHE_FLUSH_OFFSET, 1,
+		    poll);
+		if (error == 0) {
+			uint8_t data[512];
+
+			error = sdmmc_mem_read_extr_single(sc, sf, SD_EXTR_MIO_MEM,
+			    sf->ext_sd.pef.fno, sf->ext_sd.pef.start_addr,
+			    sizeof(data), data);
+			if (error == 0 && SD_PEF_CACHE_FLUSH(data) != 0) {
+				device_printf(sc->sc_dev, "cache flush failed\n");
+			}
+		}
+	} else {
+		error = sdmmc_mem_mmc_switch(sf,
+		    EXT_CSD_CMD_SET_NORMAL, EXT_CSD_FLUSH_CACHE,
+		    EXT_CSD_FLUSH_CACHE_FLUSH, poll);
+	}
 
 	mutex_exit(&sc->sc_mtx);
 	SDMMC_UNLOCK(sc);
 
 #ifdef SDMMC_DEBUG
-	device_printf(sc->sc_dev, "mmc flush cache error %d\n", error);
+	device_printf(sc->sc_dev, "flush cache error %d\n", error);
 #endif
 
 	return error;

Index: src/sys/dev/sdmmc/sdmmcreg.h
diff -u src/sys/dev/sdmmc/sdmmcreg.h:1.34 src/sys/dev/sdmmc/sdmmcreg.h:1.34.34.1
--- src/sys/dev/sdmmc/sdmmcreg.h:1.34	Thu Apr 19 21:50:09 2018
+++ src/sys/dev/sdmmc/sdmmcreg.h	Sat Oct 26 15:26:43 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdmmcreg.h,v 1.34 2018/04/19 21:50:09 christos Exp $	*/
+/*	$NetBSD: sdmmcreg.h,v 1.34.34.1 2024/10/26 15:26:43 martin Exp $	*/
 /*	$OpenBSD: sdmmcreg.h,v 1.4 2009/01/09 10:55:22 jsg Exp $	*/
 
 /*
@@ -63,6 +63,8 @@
 #define SD_VOLTAGE_SWITCH		11	/* R1 */
 #define SD_ERASE_WR_BLK_START		32	/* R1 */
 #define SD_ERASE_WR_BLK_END		33	/* R1 */
+#define SD_READ_EXTR_SINGLE		48	/* R1 */
+#define SD_WRITE_EXTR_SINGLE		49	/* R1 */
 
 /* SD application commands */			/* response type */
 #define SD_APP_SET_BUS_WIDTH		6	/* R1 */
@@ -71,6 +73,15 @@
 #define SD_APP_OP_COND			41	/* R3 */
 #define SD_APP_SEND_SCR			51	/* R1 */
 
+/* SD extended register argument fields */
+#define SD_EXTR_MIO			(0x1U << 31)
+#define SD_EXTR_MIO_MEM			0
+#define SD_EXTR_MIO_IO			1
+#define SD_EXTR_FNO			(0xfU << 27)
+#define SD_EXTR_MW			(1U << 26)	/* write only */
+#define SD_EXTR_ADDR			(0x1ffff << 9)
+#define SD_EXTR_LEN			0x1ff
+
 /* SD erase arguments */
 #define SD_ERASE_DISCARD		0x00000001
 #define SD_ERASE_FULE			0x00000002
@@ -355,7 +366,9 @@
 #define  SCR_SD_BUS_WIDTHS_4BIT		(1 << 2) /* 4bit (DAT0-3) */
 #define SCR_SD_SPEC3(scr)		MMC_RSP_BITS((scr), 47, 1)
 #define SCR_EX_SECURITY(scr)		MMC_RSP_BITS((scr), 43, 4)
+#define SCR_SD_SPEC4(scr)		MMC_RSP_BITS((scr), 42, 1)
 #define SCR_RESERVED(scr)		MMC_RSP_BITS((scr), 34, 9)
+#define SCR_CMD_SUPPORT_CMD48(scr)	MMC_RSP_BITS((scr), 34, 1)
 #define SCR_CMD_SUPPORT_CMD23(scr)	MMC_RSP_BITS((scr), 33, 1)
 #define SCR_CMD_SUPPORT_CMD20(scr)	MMC_RSP_BITS((scr), 32, 1)
 #define SCR_RESERVED2(scr)		MMC_RSP_BITS((scr), 0, 32)
@@ -393,6 +406,10 @@
 #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_PERFORMANCE_ENHANCE_CACHE		__BIT(0)
+#define  SSR_PERFORMANCE_ENHANCE_HOST_MAINT	__BIT(1)
+#define  SSR_PERFORMANCE_ENHANCE_CARD_MAINT	__BIT(2)
+#define  SSR_PERFORMANCE_ENHANCE_COMMAND_QUEUE	__BITS(7,3)
 #define SSR_DISCARD_SUPPORT(resp)	__bitfield((resp), 313, 1)
 #define SSR_FULE_SUPPORT(resp)		__bitfield((resp), 312, 1)
 
@@ -406,6 +423,29 @@
 #define SD_ACCESS_MODE_SDR104	3
 #define SD_ACCESS_MODE_DDR50	4
 
+/* SD extension data */
+#define SD_GENERAL_INFO_HDR_REVISION(data)	le16dec(&(data)[0])
+#define SD_GENERAL_INFO_HDR_LENGTH(data)	le16dec(&(data)[2])
+#define SD_GENERAL_INFO_HDR_NUM_EXT(data)	((data)[4])
+#define SD_GENERAL_INFO_EXT_FIRST		16
+#define SD_EXTENSION_INFO_SFC(data, index)	le16dec(&(data)[(index) + 0])
+#define SD_EXTENSION_INFO_NEXT(data, index)	le16dec(&(data)[(index) + 40])
+#define	SD_EXTENSION_INFO_NUM_REG(data, index)	((data)[(index) + 42])
+#define SD_EXTENSION_INFO_REG(data, index, num)	le32dec(&(data)[(index) + 44 + (num) * 4])
+
+#define SD_EXTENSION_INFO_REG_FNO(addr)		(((addr) >> 18) & 0xf)
+#define SD_EXTENSION_INFO_REG_START_ADDR(addr)	((addr) & 0x1ffff)
+
+/* SD extension standard function codes */
+#define SD_SFC_PEF	0x0002
+
+/* Performance Enhancement Function */
+#define SD_PEF_CACHE_SUPPORT(data)		((data)[4] & 0x01)
+#define SD_PEF_CACHE_ENABLE(data)		((data)[260] & 0x01)
+#define SD_PEF_CACHE_FLUSH(data)		((data)[261] & 0x01)
+#define SD_PEF_CACHE_ENABLE_OFFSET		260
+#define SD_PEF_CACHE_FLUSH_OFFSET		261
+
 /* This assumes the response fields are in host byte order in 32-bit units.  */
 #define MMC_RSP_BITS(resp, start, len)	__bitfield((resp), (start)-8, (len))
 static __inline uint32_t

Index: src/sys/dev/sdmmc/sdmmcvar.h
diff -u src/sys/dev/sdmmc/sdmmcvar.h:1.36 src/sys/dev/sdmmc/sdmmcvar.h:1.36.18.1
--- src/sys/dev/sdmmc/sdmmcvar.h:1.36	Sat Mar 13 23:22:44 2021
+++ src/sys/dev/sdmmc/sdmmcvar.h	Sat Oct 26 15:26:43 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdmmcvar.h,v 1.36 2021/03/13 23:22:44 mlelstv Exp $	*/
+/*	$NetBSD: sdmmcvar.h,v 1.36.18.1 2024/10/26 15:26:43 martin Exp $	*/
 /*	$OpenBSD: sdmmcvar.h,v 1.13 2009/01/09 10:55:22 jsg Exp $	*/
 
 /*
@@ -66,9 +66,27 @@ struct sdmmc_cid {
 
 struct sdmmc_scr {
 	int	sd_spec;
+	int	sd_spec3;
+	int	sd_spec4;
 	int	bus_width;
+	bool	support_cmd48;
 };
 
+struct sdmmc_ssr {
+	bool	cache;		/* cache supported */
+};
+
+struct sdmmc_ext_regset {
+	bool		valid;
+	uint8_t		fno;
+	uint32_t	start_addr;
+};
+
+struct sdmmc_ext_sd {
+	struct sdmmc_ext_regset	pef;	/* Performance Enhancement */
+};
+
+
 typedef uint32_t sdmmc_response[4];
 
 struct sdmmc_softc;
@@ -201,6 +219,8 @@ struct sdmmc_function {
 	sdmmc_response raw_cid;		/* temp. storage for decoding */
 	uint32_t raw_scr[2];
 	struct sdmmc_scr scr;		/* decoded SCR value */
+	struct sdmmc_ssr ssr;		/* decoded SSR value */
+	struct sdmmc_ext_sd ext_sd;	/* decoded SD extension value */
 
 	void *bbuf;			/* bounce buffer */
 	bus_dmamap_t bbuf_dmap;		/* DMA map for bounce buffer */

Reply via email to