Re: sdmmc(4): add UHS-I support
On Sat, 22 Aug 2020 14:09:53 +0200 (CEST) Mark Kettenis wrote: > > Date: Mon, 17 Aug 2020 12:57:58 +0200 (CEST) > > From: Mark Kettenis > > > > > Date: Sun, 16 Aug 2020 19:32:03 +0200 (CEST) > > > From: Mark Kettenis > > > > > > The diff below adds support for higher speeds as supported by > > > UHS-I SD cards to the generic sdmmc(4) layer. The diff in itself > > > does not enable the use of those modes. That needs separate > > > changes to the SD/MMC controller drivers. I have such a diff for > > > amlmmc(4) that allows me to use SDR50 mode. > > > > > > However, to make sure this diff doesn't break existing lower speed > > > modes I'd appreciate tests on a variety of hardware. So if > > > sdmmc(4) shows up in your dmesg, please test this by exercising > > > your (u)SD or (e)MMC cards. > > > > > > Thanks, > > > > > > Mark > > > > Previous diff didn't build properly on amd64. Here is a new diff. > > I did not receive a lot of test reports, but the diff has been in > snaps for about a week. > > ok? No issues found using it on my boot device: sdmmc0 at sximmc0: 4-bit, sd high-speed, mmc high-speed, dma scsibus0 at sdmmc0: 2 targets, initiator 0 ok mglocker@ > > > Index: dev/sdmmc/sdmmc.c > > === > > RCS file: /cvs/src/sys/dev/sdmmc/sdmmc.c,v > > retrieving revision 1.57 > > diff -u -p -r1.57 sdmmc.c > > --- dev/sdmmc/sdmmc.c 15 Aug 2020 13:21:02 - 1.57 > > +++ dev/sdmmc/sdmmc.c 17 Aug 2020 10:38:11 - > > @@ -111,6 +111,10 @@ sdmmc_attach(struct device *parent, stru > > printf(": 1-bit"); > > if (ISSET(saa->caps, SMC_CAPS_SD_HIGHSPEED)) > > printf(", sd high-speed"); > > + if (ISSET(saa->caps, SMC_CAPS_UHS_SDR50)) > > + printf(", sdr50"); > > + if (ISSET(saa->caps, SMC_CAPS_UHS_SDR104)) > > + printf(", sdr104"); > > if (ISSET(saa->caps, SMC_CAPS_MMC_HIGHSPEED)) > > printf(", mmc high-speed"); > > if (ISSET(saa->caps, SMC_CAPS_MMC_DDR52)) > > Index: dev/sdmmc/sdmmc_mem.c > > === > > RCS file: /cvs/src/sys/dev/sdmmc/sdmmc_mem.c,v > > retrieving revision 1.34 > > diff -u -p -r1.34 sdmmc_mem.c > > --- dev/sdmmc/sdmmc_mem.c 14 Aug 2020 14:49:04 - > > 1.34 +++ dev/sdmmc/sdmmc_mem.c 17 Aug 2020 10:38:11 - > > @@ -52,6 +52,7 @@ int sdmmc_mem_decode_scr(struct sdmmc_so > > intsdmmc_mem_send_cxd_data(struct sdmmc_softc *, int, void > > *, size_t); int sdmmc_mem_set_bus_width(struct > > sdmmc_function *, int); int sdmmc_mem_mmc_switch(struct > > sdmmc_function *, uint8_t, uint8_t, uint8_t); +int > > sdmmc_mem_signal_voltage(struct sdmmc_softc *, int); > > intsdmmc_mem_sd_init(struct sdmmc_softc *, struct > > sdmmc_function *); int sdmmc_mem_mmc_init(struct sdmmc_softc > > *, struct sdmmc_function *); @@ -104,12 +105,16 @@ const int > > sdmmc_mmc_timings[] = { int > > sdmmc_mem_enable(struct sdmmc_softc *sc) > > { > > - u_int32_t host_ocr; > > - u_int32_t card_ocr; > > + uint32_t host_ocr; > > + uint32_t card_ocr; > > + uint32_t new_ocr; > > + uint32_t ocr = 0; > > + int error; > > > > rw_assert_wrlock(&sc->sc_lock); > > > > /* Set host mode to SD "combo" card or SD memory-only. */ > > + CLR(sc->sc_flags, SMF_UHS_MODE); > > SET(sc->sc_flags, SMF_SD_MODE|SMF_MEM_MODE); > > > > /* Reset memory (*must* do that before CMD55 or CMD1). */ > > @@ -153,14 +158,86 @@ sdmmc_mem_enable(struct sdmmc_softc *sc) > > > > host_ocr &= card_ocr; /* only allow the common voltages */ > > > > - if (sdmmc_send_if_cond(sc, card_ocr) == 0) > > - host_ocr |= SD_OCR_SDHC_CAP; > > + if (ISSET(sc->sc_flags, SMF_SD_MODE)) { > > + if (sdmmc_send_if_cond(sc, card_ocr) == 0) > > + SET(ocr, MMC_OCR_HCS); > > + > > + if (sdmmc_chip_host_ocr(sc->sct, sc->sch) & > > MMC_OCR_S18A) > > + SET(ocr, MMC_OCR_S18A); > > + } > > + host_ocr |= ocr; > > > > /* Send the new OCR value until all cards are ready. */ > > - if (sdmmc_mem_send_op_cond(sc, host_ocr, NULL) != 0) { > > + if (sdmmc_mem_send_op_cond(sc, host_ocr, &new_ocr) != 0) { > > DPRINTF(("%s: can't send memory OCR\n", > > DEVNAME(sc))); return 1; > > } > > + > > + if (ISSET(sc->sc_flags, SMF_SD_MODE) && ISSET(new_ocr, > > MMC_OCR_S18A)) { > > + /* > > +* Card and host support low voltage mode, begin > > switch > > +* sequence. > > +*/ > > + struct sdmmc_command cmd; > > + > > + memset(&cmd, 0, sizeof(cmd)); > > + cmd.c_arg = 0; > > + cmd.c_flags = SCF_CMD_AC | SCF_RSP_R1; > > + cmd.c_opcode = SD_VOLTAGE_SWITCH; > > + DPRINTF(("%s: switching card to 1.8V\n", > > DEVNAME(sc))); > > + error = sdmmc_mmc_command(sc, &cmd); > > + if (error) { >
Re: sdmmc(4): add UHS-I support
> Date: Mon, 17 Aug 2020 12:57:58 +0200 (CEST) > From: Mark Kettenis > > > Date: Sun, 16 Aug 2020 19:32:03 +0200 (CEST) > > From: Mark Kettenis > > > > The diff below adds support for higher speeds as supported by UHS-I SD > > cards to the generic sdmmc(4) layer. The diff in itself does not > > enable the use of those modes. That needs separate changes to the > > SD/MMC controller drivers. I have such a diff for amlmmc(4) that > > allows me to use SDR50 mode. > > > > However, to make sure this diff doesn't break existing lower speed > > modes I'd appreciate tests on a variety of hardware. So if sdmmc(4) > > shows up in your dmesg, please test this by exercising your (u)SD or > > (e)MMC cards. > > > > Thanks, > > > > Mark > > Previous diff didn't build properly on amd64. Here is a new diff. I did not receive a lot of test reports, but the diff has been in snaps for about a week. ok? > Index: dev/sdmmc/sdmmc.c > === > RCS file: /cvs/src/sys/dev/sdmmc/sdmmc.c,v > retrieving revision 1.57 > diff -u -p -r1.57 sdmmc.c > --- dev/sdmmc/sdmmc.c 15 Aug 2020 13:21:02 - 1.57 > +++ dev/sdmmc/sdmmc.c 17 Aug 2020 10:38:11 - > @@ -111,6 +111,10 @@ sdmmc_attach(struct device *parent, stru > printf(": 1-bit"); > if (ISSET(saa->caps, SMC_CAPS_SD_HIGHSPEED)) > printf(", sd high-speed"); > + if (ISSET(saa->caps, SMC_CAPS_UHS_SDR50)) > + printf(", sdr50"); > + if (ISSET(saa->caps, SMC_CAPS_UHS_SDR104)) > + printf(", sdr104"); > if (ISSET(saa->caps, SMC_CAPS_MMC_HIGHSPEED)) > printf(", mmc high-speed"); > if (ISSET(saa->caps, SMC_CAPS_MMC_DDR52)) > Index: dev/sdmmc/sdmmc_mem.c > === > RCS file: /cvs/src/sys/dev/sdmmc/sdmmc_mem.c,v > retrieving revision 1.34 > diff -u -p -r1.34 sdmmc_mem.c > --- dev/sdmmc/sdmmc_mem.c 14 Aug 2020 14:49:04 - 1.34 > +++ dev/sdmmc/sdmmc_mem.c 17 Aug 2020 10:38:11 - > @@ -52,6 +52,7 @@ int sdmmc_mem_decode_scr(struct sdmmc_so > int sdmmc_mem_send_cxd_data(struct sdmmc_softc *, int, void *, size_t); > int sdmmc_mem_set_bus_width(struct sdmmc_function *, int); > int sdmmc_mem_mmc_switch(struct sdmmc_function *, uint8_t, uint8_t, > uint8_t); > +int sdmmc_mem_signal_voltage(struct sdmmc_softc *, int); > > int sdmmc_mem_sd_init(struct sdmmc_softc *, struct sdmmc_function *); > int sdmmc_mem_mmc_init(struct sdmmc_softc *, struct sdmmc_function *); > @@ -104,12 +105,16 @@ const int sdmmc_mmc_timings[] = { > int > sdmmc_mem_enable(struct sdmmc_softc *sc) > { > - u_int32_t host_ocr; > - u_int32_t card_ocr; > + uint32_t host_ocr; > + uint32_t card_ocr; > + uint32_t new_ocr; > + uint32_t ocr = 0; > + int error; > > rw_assert_wrlock(&sc->sc_lock); > > /* Set host mode to SD "combo" card or SD memory-only. */ > + CLR(sc->sc_flags, SMF_UHS_MODE); > SET(sc->sc_flags, SMF_SD_MODE|SMF_MEM_MODE); > > /* Reset memory (*must* do that before CMD55 or CMD1). */ > @@ -153,14 +158,86 @@ sdmmc_mem_enable(struct sdmmc_softc *sc) > > host_ocr &= card_ocr; /* only allow the common voltages */ > > - if (sdmmc_send_if_cond(sc, card_ocr) == 0) > - host_ocr |= SD_OCR_SDHC_CAP; > + if (ISSET(sc->sc_flags, SMF_SD_MODE)) { > + if (sdmmc_send_if_cond(sc, card_ocr) == 0) > + SET(ocr, MMC_OCR_HCS); > + > + if (sdmmc_chip_host_ocr(sc->sct, sc->sch) & MMC_OCR_S18A) > + SET(ocr, MMC_OCR_S18A); > + } > + host_ocr |= ocr; > > /* Send the new OCR value until all cards are ready. */ > - if (sdmmc_mem_send_op_cond(sc, host_ocr, NULL) != 0) { > + if (sdmmc_mem_send_op_cond(sc, host_ocr, &new_ocr) != 0) { > DPRINTF(("%s: can't send memory OCR\n", DEVNAME(sc))); > return 1; > } > + > + if (ISSET(sc->sc_flags, SMF_SD_MODE) && ISSET(new_ocr, MMC_OCR_S18A)) { > + /* > + * Card and host support low voltage mode, begin switch > + * sequence. > + */ > + struct sdmmc_command cmd; > + > + memset(&cmd, 0, sizeof(cmd)); > + cmd.c_arg = 0; > + cmd.c_flags = SCF_CMD_AC | SCF_RSP_R1; > + cmd.c_opcode = SD_VOLTAGE_SWITCH; > + DPRINTF(("%s: switching card to 1.8V\n", DEVNAME(sc))); > + error = sdmmc_mmc_command(sc, &cmd); > + if (error) { > + DPRINTF(("%s: voltage switch command failed\n", > + SDMMCDEVNAME(sc))); > + return error; > + } > + > + error = sdmmc_mem_signal_voltage(sc, SDMMC_SIGNAL_VOLTAGE_180); > + if (error) > + return error; > + > + SET(sc->sc_flags, SMF_UHS_MODE); > + } > +
Re: sdmmc(4): add UHS-I support
On Mon, Aug 17, 2020 at 12:57:58PM +0200, Mark Kettenis wrote: > > > Date: Sun, 16 Aug 2020 19:32:03 +0200 (CEST) > > From: Mark Kettenis > > > > The diff below adds support for higher speeds as supported by UHS-I SD > > cards to the generic sdmmc(4) layer. The diff in itself does not > > enable the use of those modes. That needs separate changes to the > > SD/MMC controller drivers. I have such a diff for amlmmc(4) that > > allows me to use SDR50 mode. > > > > However, to make sure this diff doesn't break existing lower speed > > modes I'd appreciate tests on a variety of hardware. So if sdmmc(4) > > shows up in your dmesg, please test this by exercising your (u)SD or > > (e)MMC cards. > > > > Thanks, > > > > Mark > > Previous diff didn't build properly on amd64. Here is a new diff. Tested on the GPD Pocket, no problems seen. OpenBSD 6.7-current (GENERIC.MP) #0: Tue Aug 18 16:08:43 CST 2020 ke...@gpdpocket.kevlo.org:/usr/src/sys/arch/amd64/compile/GENERIC.MP real mem = 8477282304 (8084MB) avail mem = 8213426176 (7832MB) random: good seed from bootblocks mpath0 at root scsibus0 at mpath0: 256 targets mainbus0 at root bios0 at mainbus0: SMBIOS rev. 3.0 @ 0x7b8de000 (51 entries) bios0: vendor American Megatrends Inc. version "5.11" date 08/07/2017 bios0: Default string Default string acpi0 at bios0: ACPI 5.0 acpi0: sleep states S0 S4 S5 acpi0: tables DSDT FACP APIC FPDT FIDT MCFG SSDT SSDT SSDT UEFI SSDT HPET SSDT SSDT SSDT LPIT BCFG PRAM BGRT TPM2 CSRT WDAT SSDT SSDT SSDT acpi0: wakeup devices acpitimer0 at acpi0: 3579545 Hz, 24 bits acpimadt0 at acpi0 addr 0xfee0: PC-AT compat cpu0 at mainbus0: apid 0 (boot processor) cpu0: Intel(R) Atom(TM) x7-Z8750 CPU @ 1.60GHz, 1600.40 MHz, 06-4c-04 cpu0: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,DS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE,SSE3,PCLMUL,DTES64,MWAIT,DS-CPL,VMX,EST,TM2,SSSE3,CX16,xTPR,PDCM,SSE4.1,SSE4.2,MOVBE,POPCNT,DEADLINE,AES,RDRAND,NXE,RDTSCP,LONG,LAHF,3DNOWP,PERF,ITSC,TSC_ADJUST,SMEP,ERMS,MD_CLEAR,IBRS,IBPB,STIBP,SENSOR,ARAT,MELTDOWN cpu0: 1MB 64b/line 16-way L2 cache cpu0: smt 0, core 0, package 0 mtrr: Pentium Pro MTRR support, 8 var ranges, 88 fixed ranges cpu0: apic clock running at 79MHz cpu0: mwait min=64, max=64, C-substates=0.2.0.0.0.0.3.3, IBE cpu1 at mainbus0: apid 2 (application processor) cpu1: Intel(R) Atom(TM) x7-Z8750 CPU @ 1.60GHz, 1599.94 MHz, 06-4c-04 cpu1: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,DS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE,SSE3,PCLMUL,DTES64,MWAIT,DS-CPL,VMX,EST,TM2,SSSE3,CX16,xTPR,PDCM,SSE4.1,SSE4.2,MOVBE,POPCNT,DEADLINE,AES,RDRAND,NXE,RDTSCP,LONG,LAHF,3DNOWP,PERF,ITSC,TSC_ADJUST,SMEP,ERMS,MD_CLEAR,IBRS,IBPB,STIBP,SENSOR,ARAT,MELTDOWN cpu1: 1MB 64b/line 16-way L2 cache cpu1: smt 0, core 1, package 0 cpu2 at mainbus0: apid 4 (application processor) cpu2: Intel(R) Atom(TM) x7-Z8750 CPU @ 1.60GHz, 1599.96 MHz, 06-4c-04 cpu2: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,DS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE,SSE3,PCLMUL,DTES64,MWAIT,DS-CPL,VMX,EST,TM2,SSSE3,CX16,xTPR,PDCM,SSE4.1,SSE4.2,MOVBE,POPCNT,DEADLINE,AES,RDRAND,NXE,RDTSCP,LONG,LAHF,3DNOWP,PERF,ITSC,TSC_ADJUST,SMEP,ERMS,MD_CLEAR,IBRS,IBPB,STIBP,SENSOR,ARAT,MELTDOWN cpu2: 1MB 64b/line 16-way L2 cache cpu2: smt 0, core 2, package 0 cpu3 at mainbus0: apid 6 (application processor) cpu3: Intel(R) Atom(TM) x7-Z8750 CPU @ 1.60GHz, 1599.95 MHz, 06-4c-04 cpu3: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,DS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE,SSE3,PCLMUL,DTES64,MWAIT,DS-CPL,VMX,EST,TM2,SSSE3,CX16,xTPR,PDCM,SSE4.1,SSE4.2,MOVBE,POPCNT,DEADLINE,AES,RDRAND,NXE,RDTSCP,LONG,LAHF,3DNOWP,PERF,ITSC,TSC_ADJUST,SMEP,ERMS,MD_CLEAR,IBRS,IBPB,STIBP,SENSOR,ARAT,MELTDOWN cpu3: 1MB 64b/line 16-way L2 cache cpu3: smt 0, core 3, package 0 ioapic0 at mainbus0: apid 1 pa 0xfec0, version 20, 115 pins acpimcfg0 at acpi0 acpimcfg0: addr 0xe000, bus 0-255 acpihpet0 at acpi0: 14318179 Hz acpiprt0 at acpi0: bus 0 (PCI0) acpiprt1 at acpi0: bus 1 (RP01) acpiprt2 at acpi0: bus -1 (RP02) acpiprt3 at acpi0: bus -1 (RP03) acpiprt4 at acpi0: bus -1 (RP04) acpicpu0 at acpi0: C3(10@1000 mwait.1@0x64), C2(10@500 mwait.1@0x58), C1(1000@1 mwait.1), PSS acpicpu1 at acpi0: C3(10@1000 mwait.1@0x64), C2(10@500 mwait.1@0x58), C1(1000@1 mwait.1), PSS acpicpu2 at acpi0: C3(10@1000 mwait.1@0x64), C2(10@500 mwait.1@0x58), C1(1000@1 mwait.1), PSS acpicpu3 at acpi0: C3(10@1000 mwait.1@0x64), C2(10@500 mwait.1@0x58), C1(1000@1 mwait.1), PSS acpipwrres0 at acpi0: ID3C, resource for ISP3 acpipwrres1 at acpi0: WWPR, resource for HS03, MDM1 acpipwrres2 at acpi0: WWPR, resource for HS13, MDM1 acpipwrres3 at acpi0: WWPR, resource for SSC1, MDM3 acpipwrres4 at acpi0: WWPR, resource for SSCW, MDM3 acpipwrres5 at acpi0: WWPR, resource for HSC1, MDM2 acpipwrres6 at acpi0: WWPR, resource for HSC3, MDM4 acpipwrres7 at acpi0: CLK3, resource for RTK1, RTKA acpi
Re: sdmmc(4): add UHS-I support
Mark Kettenis writes: >> However, to make sure this diff doesn't break existing lower speed >> modes I'd appreciate tests on a variety of hardware. So if sdmmc(4) >> shows up in your dmesg, please test this by exercising your (u)SD or >> (e)MMC cards. No problems encountered reading/writing the SD card with this diff on RPi4: sdhc0: SDHC 3.0, 250 MHz base clock sdmmc0 at sdhc0: 4-bit, sd high-speed, mmc high-speed ... sdhc1 at simplebus4 sdhc1: SDHC 3.0, 100 MHz base clock sdmmc1 at sdhc1: 8-bit, sd high-speed, mmc high-speed, ddr52, dma ... scsibus0 at sdmmc1: 2 targets, initiator 0 sd0 at scsibus0 targ 1 lun 0: removable sd0: 15193MB, 512 bytes/sector, 31116288 sectors ... bwfm0 at sdmmc0 function 1 manufacturer 0x02d0, product 0xa9a6 at sdmmc0 function 2 not configured manufacturer 0x02d0, product 0xa9a6 at sdmmc0 function 3 not configured
Re: sdmmc(4): add UHS-I support
> Date: Sun, 16 Aug 2020 19:32:03 +0200 (CEST) > From: Mark Kettenis > > The diff below adds support for higher speeds as supported by UHS-I SD > cards to the generic sdmmc(4) layer. The diff in itself does not > enable the use of those modes. That needs separate changes to the > SD/MMC controller drivers. I have such a diff for amlmmc(4) that > allows me to use SDR50 mode. > > However, to make sure this diff doesn't break existing lower speed > modes I'd appreciate tests on a variety of hardware. So if sdmmc(4) > shows up in your dmesg, please test this by exercising your (u)SD or > (e)MMC cards. > > Thanks, > > Mark Previous diff didn't build properly on amd64. Here is a new diff. Index: dev/sdmmc/sdmmc.c === RCS file: /cvs/src/sys/dev/sdmmc/sdmmc.c,v retrieving revision 1.57 diff -u -p -r1.57 sdmmc.c --- dev/sdmmc/sdmmc.c 15 Aug 2020 13:21:02 - 1.57 +++ dev/sdmmc/sdmmc.c 17 Aug 2020 10:38:11 - @@ -111,6 +111,10 @@ sdmmc_attach(struct device *parent, stru printf(": 1-bit"); if (ISSET(saa->caps, SMC_CAPS_SD_HIGHSPEED)) printf(", sd high-speed"); + if (ISSET(saa->caps, SMC_CAPS_UHS_SDR50)) + printf(", sdr50"); + if (ISSET(saa->caps, SMC_CAPS_UHS_SDR104)) + printf(", sdr104"); if (ISSET(saa->caps, SMC_CAPS_MMC_HIGHSPEED)) printf(", mmc high-speed"); if (ISSET(saa->caps, SMC_CAPS_MMC_DDR52)) Index: dev/sdmmc/sdmmc_mem.c === RCS file: /cvs/src/sys/dev/sdmmc/sdmmc_mem.c,v retrieving revision 1.34 diff -u -p -r1.34 sdmmc_mem.c --- dev/sdmmc/sdmmc_mem.c 14 Aug 2020 14:49:04 - 1.34 +++ dev/sdmmc/sdmmc_mem.c 17 Aug 2020 10:38:11 - @@ -52,6 +52,7 @@ int sdmmc_mem_decode_scr(struct sdmmc_so intsdmmc_mem_send_cxd_data(struct sdmmc_softc *, int, void *, size_t); intsdmmc_mem_set_bus_width(struct sdmmc_function *, int); intsdmmc_mem_mmc_switch(struct sdmmc_function *, uint8_t, uint8_t, uint8_t); +intsdmmc_mem_signal_voltage(struct sdmmc_softc *, int); intsdmmc_mem_sd_init(struct sdmmc_softc *, struct sdmmc_function *); intsdmmc_mem_mmc_init(struct sdmmc_softc *, struct sdmmc_function *); @@ -104,12 +105,16 @@ const int sdmmc_mmc_timings[] = { int sdmmc_mem_enable(struct sdmmc_softc *sc) { - u_int32_t host_ocr; - u_int32_t card_ocr; + uint32_t host_ocr; + uint32_t card_ocr; + uint32_t new_ocr; + uint32_t ocr = 0; + int error; rw_assert_wrlock(&sc->sc_lock); /* Set host mode to SD "combo" card or SD memory-only. */ + CLR(sc->sc_flags, SMF_UHS_MODE); SET(sc->sc_flags, SMF_SD_MODE|SMF_MEM_MODE); /* Reset memory (*must* do that before CMD55 or CMD1). */ @@ -153,14 +158,86 @@ sdmmc_mem_enable(struct sdmmc_softc *sc) host_ocr &= card_ocr; /* only allow the common voltages */ - if (sdmmc_send_if_cond(sc, card_ocr) == 0) - host_ocr |= SD_OCR_SDHC_CAP; + if (ISSET(sc->sc_flags, SMF_SD_MODE)) { + if (sdmmc_send_if_cond(sc, card_ocr) == 0) + SET(ocr, MMC_OCR_HCS); + + if (sdmmc_chip_host_ocr(sc->sct, sc->sch) & MMC_OCR_S18A) + SET(ocr, MMC_OCR_S18A); + } + host_ocr |= ocr; /* Send the new OCR value until all cards are ready. */ - if (sdmmc_mem_send_op_cond(sc, host_ocr, NULL) != 0) { + if (sdmmc_mem_send_op_cond(sc, host_ocr, &new_ocr) != 0) { DPRINTF(("%s: can't send memory OCR\n", DEVNAME(sc))); return 1; } + + if (ISSET(sc->sc_flags, SMF_SD_MODE) && ISSET(new_ocr, MMC_OCR_S18A)) { + /* +* Card and host support low voltage mode, begin switch +* sequence. +*/ + struct sdmmc_command cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.c_arg = 0; + cmd.c_flags = SCF_CMD_AC | SCF_RSP_R1; + cmd.c_opcode = SD_VOLTAGE_SWITCH; + DPRINTF(("%s: switching card to 1.8V\n", DEVNAME(sc))); + error = sdmmc_mmc_command(sc, &cmd); + if (error) { + DPRINTF(("%s: voltage switch command failed\n", + SDMMCDEVNAME(sc))); + return error; + } + + error = sdmmc_mem_signal_voltage(sc, SDMMC_SIGNAL_VOLTAGE_180); + if (error) + return error; + + SET(sc->sc_flags, SMF_UHS_MODE); + } + + return 0; +} + +int +sdmmc_mem_signal_voltage(struct sdmmc_softc *sc, int signal_voltage) +{ + int error; + + /* +* Stop the clock +*/ + error = sdmmc_chip_bus_clock(sc->sct, sc->sch, 0, SDMMC_TIMING_LEGACY); + if (error
sdmmc(4): add UHS-I support
The diff below adds support for higher speeds as supported by UHS-I SD cards to the generic sdmmc(4) layer. The diff in itself does not enable the use of those modes. That needs separate changes to the SD/MMC controller drivers. I have such a diff for amlmmc(4) that allows me to use SDR50 mode. However, to make sure this diff doesn't break existing lower speed modes I'd appreciate tests on a variety of hardware. So if sdmmc(4) shows up in your dmesg, please test this by exercising your (u)SD or (e)MMC cards. Thanks, Mark Index: dev/sdmmc/sdmmc.c === RCS file: /cvs/src/sys/dev/sdmmc/sdmmc.c,v retrieving revision 1.57 diff -u -p -r1.57 sdmmc.c --- dev/sdmmc/sdmmc.c 15 Aug 2020 13:21:02 - 1.57 +++ dev/sdmmc/sdmmc.c 16 Aug 2020 17:15:55 - @@ -111,6 +111,10 @@ sdmmc_attach(struct device *parent, stru printf(": 1-bit"); if (ISSET(saa->caps, SMC_CAPS_SD_HIGHSPEED)) printf(", sd high-speed"); + if (ISSET(saa->caps, SMC_CAPS_UHS_SDR50)) + printf(", sdr50"); + if (ISSET(saa->caps, SMC_CAPS_UHS_SDR104)) + printf(", sdr104"); if (ISSET(saa->caps, SMC_CAPS_MMC_HIGHSPEED)) printf(", mmc high-speed"); if (ISSET(saa->caps, SMC_CAPS_MMC_DDR52)) Index: dev/sdmmc/sdmmc_mem.c === RCS file: /cvs/src/sys/dev/sdmmc/sdmmc_mem.c,v retrieving revision 1.34 diff -u -p -r1.34 sdmmc_mem.c --- dev/sdmmc/sdmmc_mem.c 14 Aug 2020 14:49:04 - 1.34 +++ dev/sdmmc/sdmmc_mem.c 16 Aug 2020 17:15:55 - @@ -52,6 +52,7 @@ int sdmmc_mem_decode_scr(struct sdmmc_so intsdmmc_mem_send_cxd_data(struct sdmmc_softc *, int, void *, size_t); intsdmmc_mem_set_bus_width(struct sdmmc_function *, int); intsdmmc_mem_mmc_switch(struct sdmmc_function *, uint8_t, uint8_t, uint8_t); +intsdmmc_mem_signal_voltage(struct sdmmc_softc *, int); intsdmmc_mem_sd_init(struct sdmmc_softc *, struct sdmmc_function *); intsdmmc_mem_mmc_init(struct sdmmc_softc *, struct sdmmc_function *); @@ -104,12 +105,16 @@ const int sdmmc_mmc_timings[] = { int sdmmc_mem_enable(struct sdmmc_softc *sc) { - u_int32_t host_ocr; - u_int32_t card_ocr; + uint32_t host_ocr; + uint32_t card_ocr; + uint32_t new_ocr; + uint32_t ocr = 0; + int error; rw_assert_wrlock(&sc->sc_lock); /* Set host mode to SD "combo" card or SD memory-only. */ + CLR(sc->sc_flags, SMF_UHS_MODE); SET(sc->sc_flags, SMF_SD_MODE|SMF_MEM_MODE); /* Reset memory (*must* do that before CMD55 or CMD1). */ @@ -153,14 +158,86 @@ sdmmc_mem_enable(struct sdmmc_softc *sc) host_ocr &= card_ocr; /* only allow the common voltages */ - if (sdmmc_send_if_cond(sc, card_ocr) == 0) - host_ocr |= SD_OCR_SDHC_CAP; + if (ISSET(sc->sc_flags, SMF_SD_MODE)) { + if (sdmmc_send_if_cond(sc, card_ocr) == 0) + SET(ocr, MMC_OCR_HCS); + + if (sdmmc_chip_host_ocr(sc->sct, sc->sch) & MMC_OCR_S18A) + SET(ocr, MMC_OCR_S18A); + } + host_ocr |= ocr; /* Send the new OCR value until all cards are ready. */ - if (sdmmc_mem_send_op_cond(sc, host_ocr, NULL) != 0) { + if (sdmmc_mem_send_op_cond(sc, host_ocr, &new_ocr) != 0) { DPRINTF(("%s: can't send memory OCR\n", DEVNAME(sc))); return 1; } + + if (ISSET(sc->sc_flags, SMF_SD_MODE) && ISSET(new_ocr, MMC_OCR_S18A)) { + /* +* Card and host support low voltage mode, begin switch +* sequence. +*/ + struct sdmmc_command cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.c_arg = 0; + cmd.c_flags = SCF_CMD_AC | SCF_RSP_R1; + cmd.c_opcode = SD_VOLTAGE_SWITCH; + DPRINTF(("%s: switching card to 1.8V\n", DEVNAME(sc))); + error = sdmmc_mmc_command(sc, &cmd); + if (error) { + DPRINTF(("%s: voltage switch command failed\n", + SDMMCDEVNAME(sc))); + return error; + } + + error = sdmmc_mem_signal_voltage(sc, SDMMC_SIGNAL_VOLTAGE_180); + if (error) + return error; + + SET(sc->sc_flags, SMF_UHS_MODE); + } + + return 0; +} + +int +sdmmc_mem_signal_voltage(struct sdmmc_softc *sc, int signal_voltage) +{ + int error; + + /* +* Stop the clock +*/ + error = sdmmc_chip_bus_clock(sc->sct, sc->sch, 0, SDMMC_TIMING_LEGACY); + if (error) + return error; + + delay(1000); + + /* +* Card switch command was successful, update host controller +* signal voltage sett