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 */