> Date: Mon, 17 Aug 2020 12:57:58 +0200 (CEST)
> From: Mark Kettenis <mark.kette...@xs4all.nl>
> 
> > Date: Sun, 16 Aug 2020 19:32:03 +0200 (CEST)
> > From: Mark Kettenis <mark.kette...@xs4all.nl>
> > 
> > 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 -0000      1.57
> +++ dev/sdmmc/sdmmc.c 17 Aug 2020 10:38:11 -0000
> @@ -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 -0000      1.34
> +++ dev/sdmmc/sdmmc_mem.c     17 Aug 2020 10:38:11 -0000
> @@ -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);
> +     }
> +
> +     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 setting.
> +      */
> +     DPRINTF(("%s: switching host to %s\n", SDMMCDEVNAME(sc),
> +         signal_voltage == SDMMC_SIGNAL_VOLTAGE_180 ? "1.8V" : "3.3V"));
> +     error = sdmmc_chip_signal_voltage(sc->sct, sc->sch, signal_voltage);
> +     if (error)
> +             return error;
> +
> +     delay(5000);
> +
> +     /*
> +      * Switch to SDR12 timing
> +      */
> +     error = sdmmc_chip_bus_clock(sc->sct, sc->sch, SDMMC_SDCLK_25MHZ,
> +         SDMMC_TIMING_LEGACY);
> +     if (error)
> +             return error;
> +
> +     delay(1000);
> +
>       return 0;
>  }
>  
> @@ -609,6 +686,30 @@ sdmmc_be512_to_bitfield512(sdmmc_bitfiel
>  }
>  
>  int
> +sdmmc_mem_select_transfer_mode(struct sdmmc_softc *sc, int support_func)
> +{
> +     if (ISSET(sc->sc_flags, SMF_UHS_MODE)) {
> +             if (ISSET(sc->sc_caps, SMC_CAPS_UHS_SDR104) &&
> +                 ISSET(support_func, 1 << SD_ACCESS_MODE_SDR104)) {
> +                     return SD_ACCESS_MODE_SDR104;
> +             }
> +             if (ISSET(sc->sc_caps, SMC_CAPS_UHS_DDR50) &&
> +                 ISSET(support_func, 1 << SD_ACCESS_MODE_DDR50)) {
> +                     return SD_ACCESS_MODE_DDR50;
> +             }
> +             if (ISSET(sc->sc_caps, SMC_CAPS_UHS_SDR50) &&
> +                 ISSET(support_func, 1 << SD_ACCESS_MODE_SDR50)) {
> +                     return SD_ACCESS_MODE_SDR50;
> +             }
> +     }
> +     if (ISSET(sc->sc_caps, SMC_CAPS_SD_HIGHSPEED) &&
> +         ISSET(support_func, 1 << SD_ACCESS_MODE_SDR25)) {
> +             return SD_ACCESS_MODE_SDR25;
> +     }
> +     return SD_ACCESS_MODE_SDR12;
> +}
> +
> +int
>  sdmmc_mem_execute_tuning(struct sdmmc_softc *sc, struct sdmmc_function *sf)
>  {
>       int timing = -1;
> @@ -646,7 +747,7 @@ sdmmc_mem_execute_tuning(struct sdmmc_so
>  int
>  sdmmc_mem_sd_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
>  {
> -     int support_func, best_func, error;
> +     int support_func, best_func, error, i;
>       sdmmc_bitfield512_t status; /* Switch Function Status */
>       uint32_t raw_scr[2];
>  
> @@ -695,8 +796,32 @@ sdmmc_mem_sd_init(struct sdmmc_softc *sc
>  
>               support_func = SFUNC_STATUS_GROUP(&status, 1);
>  
> -             if (support_func & (1 << SD_ACCESS_MODE_SDR25))
> -                     best_func = 1;
> +             if (!ISSET(sc->sc_flags, SMF_UHS_MODE) &&
> +                 (ISSET(support_func, 1 << SD_ACCESS_MODE_SDR50) ||
> +                  ISSET(support_func, 1 << SD_ACCESS_MODE_DDR50) ||
> +                  ISSET(support_func, 1 << SD_ACCESS_MODE_SDR104))) {
> +                     /* XXX UHS-I card started in 1.8V mode, switch now */
> +                     error = sdmmc_mem_signal_voltage(sc,
> +                         SDMMC_SIGNAL_VOLTAGE_180);
> +                     if (error) {
> +                             printf("%s: failed to recover UHS card\n", 
> DEVNAME(sc));
> +                             return error;
> +                     }
> +                     SET(sc->sc_flags, SMF_UHS_MODE);
> +             }
> +
> +             for (i = 0; i < nitems(switch_group0_functions); i++) {
> +                     if (!(support_func & (1 << i)))
> +                             continue;
> +                     DPRINTF(("%s: card supports mode %s\n",
> +                         SDMMCDEVNAME(sc),
> +                         switch_group0_functions[i].name));
> +             }
> +
> +             best_func = sdmmc_mem_select_transfer_mode(sc, support_func);
> +
> +             DPRINTF(("%s: using mode %s\n", SDMMCDEVNAME(sc),
> +                 switch_group0_functions[best_func].name));
>       }
>  
>       if (best_func != 0) {
> @@ -716,13 +841,20 @@ sdmmc_mem_sd_init(struct sdmmc_softc *sc
>               /* Wait 400KHz x 8 clock (2.5us * 8 + slop) */
>               delay(25);
>  
> -             /* High Speed mode, Frequency up to 50MHz. */
> +             /* change bus clock */
>               error = sdmmc_chip_bus_clock(sc->sct, sc->sch,
> -                 SDMMC_SDCLK_50MHZ, SDMMC_TIMING_HIGHSPEED);
> +                 sf->csd.tran_speed, SDMMC_TIMING_HIGHSPEED);
>               if (error) {
>                       printf("%s: can't change bus clock\n", DEVNAME(sc));
>                       return error;
>               }
> +
> +             /* execute tuning (UHS) */
> +             error = sdmmc_mem_execute_tuning(sc, sf);
> +             if (error) {
> +                     printf("%s: can't execute SD tuning\n", DEVNAME(sc));
> +                     return error;
> +             }
>       }
>  
>       return 0;
> @@ -937,7 +1069,7 @@ sdmmc_mem_send_op_cond(struct sdmmc_soft
>                       error = sdmmc_app_command(sc, &cmd);
>               } else {
>                       cmd.c_arg &= ~MMC_OCR_ACCESS_MODE_MASK;
> -                     cmd.c_arg |= MMC_OCR_SECTOR_MODE;
> +                     cmd.c_arg |= MMC_OCR_ACCESS_MODE_SECTOR;
>                       cmd.c_opcode = MMC_SEND_OP_COND;
>                       error = sdmmc_mmc_command(sc, &cmd);
>               }
> Index: dev/sdmmc/sdmmcreg.h
> ===================================================================
> RCS file: /cvs/src/sys/dev/sdmmc/sdmmcreg.h,v
> retrieving revision 1.12
> diff -u -p -r1.12 sdmmcreg.h
> --- dev/sdmmc/sdmmcreg.h      14 Aug 2020 14:49:04 -0000      1.12
> +++ dev/sdmmc/sdmmcreg.h      17 Aug 2020 10:38:11 -0000
> @@ -44,6 +44,7 @@
>  #define SD_SEND_RELATIVE_ADDR                3       /* R6 */
>  #define SD_SEND_SWITCH_FUNC          6       /* R1 */
>  #define SD_SEND_IF_COND                      8       /* R7 */
> +#define SD_VOLTAGE_SWITCH            11      /* R1 */
>  
>  /* SD application commands */                        /* response type */
>  #define SD_APP_SET_BUS_WIDTH         6       /* R1 */
> @@ -52,9 +53,11 @@
>  
>  /* OCR bits */
>  #define MMC_OCR_MEM_READY            (1<<31) /* memory power-up status bit */
> -#define MMC_OCR_ACCESS_MODE_MASK     0x60000000 /* bits 30:29 */
> -#define MMC_OCR_SECTOR_MODE          (1<<30)
> -#define MMC_OCR_BYTE_MODE            (1<<29)
> +#define MMC_OCR_HCS                  (1<<30) /* SD only */
> +#define MMC_OCR_ACCESS_MODE_MASK     (3<<29) /* MMC only */
> +#define MMC_OCR_ACCESS_MODE_BYTE     (0<<29) /* MMC only */
> +#define MMC_OCR_ACCESS_MODE_SECTOR   (2<<29) /* MMC only */
> +#define MMC_OCR_S18A                 (1<<24)
>  #define MMC_OCR_3_5V_3_6V            (1<<23)
>  #define MMC_OCR_3_4V_3_5V            (1<<22)
>  #define MMC_OCR_3_3V_3_4V            (1<<21)
> @@ -73,7 +76,6 @@
>  #define MMC_OCR_2_0V_2_1V            (1<<8)
>  #define MMC_OCR_1_65V_1_95V          (1<<7)
>  
> -#define SD_OCR_SDHC_CAP                      (1<<30)
>  #define SD_OCR_VOL_MASK                      0xFF8000 /* bits 23:15 */
>  
>  /* R1 response type bits */
> Index: dev/ic/rtsxreg.h
> ===================================================================
> RCS file: /cvs/src/sys/dev/ic/rtsxreg.h,v
> retrieving revision 1.4
> diff -u -p -r1.4 rtsxreg.h
> --- dev/ic/rtsxreg.h  6 Sep 2017 13:07:38 -0000       1.4
> +++ dev/ic/rtsxreg.h  17 Aug 2020 10:38:11 -0000
> @@ -387,8 +387,7 @@
>  #define      RTSX_PPBUF_SIZE         256
>  
>  #define      RTSX_SUPPORT_VOLTAGE    (MMC_OCR_3_3V_3_4V|MMC_OCR_3_2V_3_3V|\
> -                             MMC_OCR_3_1V_3_2V|MMC_OCR_3_0V_3_1V|\
> -                             SD_OCR_SDHC_CAP)
> +                             MMC_OCR_3_1V_3_2V|MMC_OCR_3_0V_3_1V)
>  
>  #define      RTSX_CFG_PCI            0x1C
>  #define      RTSX_CFG_ASIC           0x10
> 

Reply via email to