Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/sdmmc add support for UHS-I modes on capable 3.0+ co...



details:   https://anonhg.NetBSD.org/src/rev/fa773d23ffb0
branches:  trunk
changeset: 809815:fa773d23ffb0
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Sun Aug 02 21:45:12 2015 +0000

description:
add support for UHS-I modes on capable 3.0+ controllers

diffstat:

 sys/dev/sdmmc/sdhc.c    |  70 ++++++++++++++++++++++++++++++++++++++++++------
 sys/dev/sdmmc/sdhcreg.h |  25 ++++++++++++++++-
 2 files changed, 85 insertions(+), 10 deletions(-)

diffs (187 lines):

diff -r f92b8aa38fa1 -r fa773d23ffb0 sys/dev/sdmmc/sdhc.c
--- a/sys/dev/sdmmc/sdhc.c      Sun Aug 02 21:44:36 2015 +0000
+++ b/sys/dev/sdmmc/sdhc.c      Sun Aug 02 21:45:12 2015 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: sdhc.c,v 1.70 2015/08/02 11:28:01 jmcneill Exp $       */
+/*     $NetBSD: sdhc.c,v 1.71 2015/08/02 21:45:12 jmcneill Exp $       */
 /*     $OpenBSD: sdhc.c,v 1.25 2009/01/13 19:44:20 grange Exp $        */
 
 /*
@@ -23,7 +23,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.70 2015/08/02 11:28:01 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.71 2015/08/02 21:45:12 jmcneill Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_sdmmc.h"
@@ -181,6 +181,7 @@
 static void    sdhc_card_intr_ack(sdmmc_chipset_handle_t);
 static void    sdhc_exec_command(sdmmc_chipset_handle_t,
                    struct sdmmc_command *);
+static int     sdhc_signal_voltage(sdmmc_chipset_handle_t, int);
 static int     sdhc_start_command(struct sdhc_host *, struct sdmmc_command *);
 static int     sdhc_wait_state(struct sdhc_host *, uint32_t, uint32_t);
 static int     sdhc_soft_reset(struct sdhc_host *, int);
@@ -218,7 +219,10 @@
 
        /* card interrupt */
        .card_enable_intr = sdhc_card_enable_intr,
-       .card_intr_ack = sdhc_card_intr_ack
+       .card_intr_ack = sdhc_card_intr_ack,
+
+       /* UHS functions */
+       .signal_voltage = sdhc_signal_voltage,
 };
 
 static int
@@ -249,7 +253,7 @@
 {
        struct sdmmcbus_attach_args saa;
        struct sdhc_host *hp;
-       uint32_t caps;
+       uint32_t caps, caps2;
        uint16_t sdhcver;
        int error;
 
@@ -314,6 +318,11 @@
        } else {
                caps = HREAD4(hp, SDHC_CAPABILITIES);
        }
+       if (hp->specver >= SDHC_SPEC_VERS_300) {
+               caps2 = HREAD4(hp, SDHC_CAPABILITIES2);
+       } else {
+               caps2 = 0;
+       }
 
        /*
         * Use DMA if the host system and the controller support it.
@@ -402,11 +411,21 @@
        aprint_normal(",");
        if (ISSET(caps, SDHC_HIGH_SPEED_SUPP)) {
                SET(hp->ocr, MMC_OCR_HCS);
-               aprint_normal(" High-Speed");
+               aprint_normal(" HS");
+       }
+       if (ISSET(caps2, SDHC_SDR50_SUPP)) {
+               SET(hp->ocr, MMC_OCR_S18A);
+               aprint_normal(" SDR50");
        }
-       if (ISSET(caps, SDHC_VOLTAGE_SUPP_1_8V) &&
-           (hp->specver < SDHC_SPEC_VERS_300 ||
-            ISSET(caps, SDHC_EMBEDDED_SLOT))) {
+       if (ISSET(caps2, SDHC_SDR104_SUPP)) {
+               SET(hp->ocr, MMC_OCR_S18A);
+               aprint_normal(" SDR104");
+       }
+       if (ISSET(caps2, SDHC_DDR50_SUPP)) {
+               SET(hp->ocr, MMC_OCR_S18A);
+               aprint_normal(" DDR50");
+       }
+       if (ISSET(caps, SDHC_VOLTAGE_SUPP_1_8V)) {
                SET(hp->ocr, MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V);
                aprint_normal(" 1.8V");
        }
@@ -812,7 +831,7 @@
         * Select the lowest voltage according to capabilities.
         */
        ocr &= hp->ocr;
-       if (ISSET(ocr, MMC_OCR_1_7V_1_8V|MMC_OCR_1_8V_1_9V)) {
+       if (ISSET(ocr, MMC_OCR_1_7V_1_8V|MMC_OCR_1_8V_1_9V|MMC_OCR_S18A)) {
                vdd = SDHC_VOLTAGE_1_8V;
        } else if (ISSET(ocr, MMC_OCR_2_9V_3_0V|MMC_OCR_3_0V_3_1V)) {
                vdd = SDHC_VOLTAGE_3_0V;
@@ -986,6 +1005,20 @@
                        goto out;
        }
 
+       if (hp->specver >= SDHC_SPEC_VERS_300) {
+               /* XXX DDR */
+               HCLR2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_MASK);
+               if (freq > 100000) {
+                       HSET2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_SDR104);
+               } else if (freq > 50000) {
+                       HSET2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_SDR50);
+               } else if (freq > 25000) {
+                       HSET2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_SDR25);
+               } else {
+                       HSET2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_SDR12);
+               }
+       }
+
        /*
         * Set the minimum base clock frequency divisor.
         */
@@ -1155,6 +1188,25 @@
 }
 
 static int
+sdhc_signal_voltage(sdmmc_chipset_handle_t sch, int signal_voltage)
+{
+       struct sdhc_host *hp = (struct sdhc_host *)sch;
+
+       switch (signal_voltage) {
+       case SDMMC_SIGNAL_VOLTAGE_180:
+               HSET2(hp, SDHC_HOST_CTL2, SDHC_1_8V_SIGNAL_EN);
+               break;
+       case SDMMC_SIGNAL_VOLTAGE_330:
+               HCLR2(hp, SDHC_HOST_CTL2, SDHC_1_8V_SIGNAL_EN);
+               break;
+       default:
+               return EINVAL;
+       }
+
+       return 0;
+}
+
+static int
 sdhc_wait_state(struct sdhc_host *hp, uint32_t mask, uint32_t value)
 {
        uint32_t state;
diff -r f92b8aa38fa1 -r fa773d23ffb0 sys/dev/sdmmc/sdhcreg.h
--- a/sys/dev/sdmmc/sdhcreg.h   Sun Aug 02 21:44:36 2015 +0000
+++ b/sys/dev/sdmmc/sdhcreg.h   Sun Aug 02 21:45:12 2015 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: sdhcreg.h,v 1.14 2015/07/29 12:11:14 jmcneill Exp $    */
+/*     $NetBSD: sdhcreg.h,v 1.15 2015/08/02 21:45:12 jmcneill Exp $    */
 /*     $OpenBSD: sdhcreg.h,v 1.4 2006/07/30 17:20:40 fgsch Exp $       */
 
 /*
@@ -142,6 +142,15 @@
 #define SDHC_EINTR_SIGNAL_EN           0x3a
 #define  SDHC_EINTR_SIGNAL_MASK                0x03ff  /* excluding vendor signals */
 #define SDHC_CMD12_ERROR_STATUS                0x3c
+#define SDHC_HOST_CTL2                 0x3e
+#define  SDHC_1_8V_SIGNAL_EN           (1<<3)
+#define  SDHC_UHS_MODE_SELECT_SHIFT    0
+#define  SDHC_UHS_MODE_SELECT_MASK     0x7
+#define  SDHC_UHS_MODE_SELECT_SDR12    0
+#define  SDHC_UHS_MODE_SELECT_SDR25    1
+#define  SDHC_UHS_MODE_SELECT_SDR50    2
+#define  SDHC_UHS_MODE_SELECT_SDR104   3
+#define  SDHC_UHS_MODE_SELECT_DDR50    4
 #define SDHC_CAPABILITIES              0x40
 #define  SDHC_SHARED_BUS_SLOT          (1<<31)
 #define  SDHC_EMBEDDED_SLOT            (1<<30)
@@ -167,6 +176,20 @@
 #define  SDHC_TIMEOUT_FREQ_UNIT                (1<<7)  /* 0=KHz, 1=MHz */
 #define  SDHC_TIMEOUT_FREQ_SHIFT       0
 #define  SDHC_TIMEOUT_FREQ_MASK                0x1f
+#define SDHC_CAPABILITIES2             0x44
+#define  SDHC_SDR50_SUPP               (1<<0)
+#define  SDHC_SDR104_SUPP              (1<<1)
+#define  SDHC_DDR50_SUPP               (1<<2)
+#define  SDHC_DRIVER_TYPE_A            (1<<4)
+#define  SDHC_DRIVER_TYPE_C            (1<<5)
+#define  SDHC_DRIVER_TYPE_D            (1<<6)
+#define  SDHC_TIMER_COUNT_SHIFT                8
+#define  SDHC_TIMER_COUNT_MASK         0xf
+#define  SDHC_TUNING_SDR50             (1<<13)
+#define  SDHC_RETUNING_MODES_SHIFT     14
+#define  SDHC_RETUNING_MODES_MASK      0x3
+#define  SDHC_CLOCK_MULTIPLIER_SHIFT   16
+#define  SDHC_CLOCK_MULTIPLIER_MASK    0xff
 #define SDHC_ADMA_ERROR_STATUS         0x54
 #define  SDHC_ADMA_LENGTH_MISMATCH     (1<<2)
 #define  SDHC_ADMA_ERROR_STATE         (3<<0)



Home | Main Index | Thread Index | Old Index