On Sat, 22 Aug 2020 14:09:53 +0200 (CEST)
Mark Kettenis <mark.kette...@xs4all.nl> wrote:

> > 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?

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