Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/sdmmc Implement SDHC sampling clock tuning procedure.



details:   https://anonhg.NetBSD.org/src/rev/1311b6a0bf0e
branches:  trunk
changeset: 809859:1311b6a0bf0e
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Wed Aug 05 10:30:25 2015 +0000

description:
Implement SDHC sampling clock tuning procedure.

diffstat:

 sys/dev/sdmmc/sdhc.c    |  108 ++++++++++++++++++++++++++++++++++++++++++++---
 sys/dev/sdmmc/sdhcreg.h |    4 +-
 2 files changed, 104 insertions(+), 8 deletions(-)

diffs (191 lines):

diff -r 55a62ca67cbf -r 1311b6a0bf0e sys/dev/sdmmc/sdhc.c
--- a/sys/dev/sdmmc/sdhc.c      Wed Aug 05 10:29:37 2015 +0000
+++ b/sys/dev/sdmmc/sdhc.c      Wed Aug 05 10:30:25 2015 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: sdhc.c,v 1.78 2015/08/05 07:31:52 mlelstv Exp $        */
+/*     $NetBSD: sdhc.c,v 1.79 2015/08/05 10:30:25 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.78 2015/08/05 07:31:52 mlelstv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.79 2015/08/05 10:30:25 jmcneill Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_sdmmc.h"
@@ -55,6 +55,7 @@
 #define SDHC_BUFFER_TIMEOUT    hz
 #define SDHC_TRANSFER_TIMEOUT  hz
 #define SDHC_DMA_TIMEOUT       (hz*3)
+#define SDHC_TUNING_TIMEOUT    hz
 
 struct sdhc_host {
        struct sdhc_softc *sc;          /* host controller device */
@@ -182,6 +183,7 @@
 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_execute_tuning(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);
@@ -224,6 +226,7 @@
        /* UHS functions */
        .signal_voltage = sdhc_signal_voltage,
        .bus_clock_ddr = sdhc_bus_clock_ddr,
+       .execute_tuning = sdhc_execute_tuning,
 };
 
 static int
@@ -318,11 +321,11 @@
                caps = sc->sc_caps;
                caps2 = sc->sc_caps2;
        } else {
-               caps = HREAD4(hp, SDHC_CAPABILITIES);
+               caps = sc->sc_caps = HREAD4(hp, SDHC_CAPABILITIES);
                if (hp->specver >= SDHC_SPEC_VERS_300) {
-                       caps2 = HREAD4(hp, SDHC_CAPABILITIES2);
+                       caps2 = sc->sc_caps2 = HREAD4(hp, SDHC_CAPABILITIES2);
                } else {
-                       caps2 = 0;
+                       caps2 = sc->sc_caps2 = 0;
                }
        }
 
@@ -1227,6 +1230,97 @@
        return 0;
 }
 
+/*
+ * Sampling clock tuning procedure (UHS)
+ */
+static int
+sdhc_execute_tuning(sdmmc_chipset_handle_t sch, int timing)
+{
+       struct sdhc_host *hp = (struct sdhc_host *)sch;
+       struct sdmmc_command cmd;
+       uint8_t hostctl;
+       int opcode, error, retry = 40;
+
+       switch (timing) {
+       case SDMMC_TIMING_MMC_HS200:
+               opcode = MMC_SEND_TUNING_BLOCK_HS200;
+               break;
+       case SDMMC_TIMING_UHS_SDR50:
+               if (!ISSET(hp->sc->sc_caps2, SDHC_TUNING_SDR50))
+                       return 0;
+               /* FALLTHROUGH */
+       case SDMMC_TIMING_UHS_SDR104:
+               opcode = MMC_SEND_TUNING_BLOCK;
+               break;
+       default:
+               return EINVAL;
+       }
+
+       hostctl = HREAD1(hp, SDHC_HOST_CTL);
+
+       /* enable buffer read ready interrupt */
+       HSET2(hp, SDHC_NINTR_SIGNAL_EN, SDHC_BUFFER_READ_READY);
+       HSET2(hp, SDHC_NINTR_STATUS_EN, SDHC_BUFFER_READ_READY);
+
+       /* disable DMA */
+       HCLR1(hp, SDHC_HOST_CTL, SDHC_DMA_SELECT);
+
+       /* reset tuning circuit */
+       HCLR2(hp, SDHC_HOST_CTL2, SDHC_SAMPLING_CLOCK_SEL);
+
+       /* start of tuning */
+       HWRITE2(hp, SDHC_HOST_CTL2, SDHC_EXECUTE_TUNING);
+
+       mutex_enter(&hp->intr_lock);
+       do {
+               memset(&cmd, 0, sizeof(cmd));
+               cmd.c_opcode = opcode;
+               cmd.c_arg = 0;
+               cmd.c_flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1;
+               if (ISSET(hostctl, SDHC_8BIT_MODE)) {
+                       cmd.c_blklen = cmd.c_datalen = 128;
+               } else {
+                       cmd.c_blklen = cmd.c_datalen = 64;
+               }
+
+               error = sdhc_start_command(hp, &cmd);
+               if (error)
+                       break;
+
+               if (!sdhc_wait_intr(hp, SDHC_BUFFER_READ_READY,
+                   SDHC_TUNING_TIMEOUT)) {
+                       break;
+               }
+
+               delay(1000);
+       } while (HREAD2(hp, SDHC_HOST_CTL2) & SDHC_EXECUTE_TUNING && --retry);
+       mutex_exit(&hp->intr_lock);
+
+       /* disable buffer read ready interrupt */
+       HCLR2(hp, SDHC_NINTR_SIGNAL_EN, SDHC_BUFFER_READ_READY);
+       HCLR2(hp, SDHC_NINTR_STATUS_EN, SDHC_BUFFER_READ_READY);
+
+       if (HREAD2(hp, SDHC_HOST_CTL2) & SDHC_EXECUTE_TUNING) {
+               HCLR2(hp, SDHC_HOST_CTL2,
+                   SDHC_SAMPLING_CLOCK_SEL|SDHC_EXECUTE_TUNING);
+               sdhc_soft_reset(hp, SDHC_RESET_DAT|SDHC_RESET_CMD);
+               aprint_error_dev(hp->sc->sc_dev,
+                   "tuning did not complete, using fixed sampling clock\n");
+               return EIO;             /* tuning did not complete */
+       }
+
+       if ((HREAD2(hp, SDHC_HOST_CTL2) & SDHC_SAMPLING_CLOCK_SEL) == 0) {
+               HCLR2(hp, SDHC_HOST_CTL2,
+                   SDHC_SAMPLING_CLOCK_SEL|SDHC_EXECUTE_TUNING);
+               sdhc_soft_reset(hp, SDHC_RESET_DAT|SDHC_RESET_CMD);
+               aprint_error_dev(hp->sc->sc_dev,
+                   "tuning failed, using fixed sampling clock\n");
+               return EIO;             /* tuning failed */
+       }
+
+       return 0;               /* tuning completed */
+}
+
 static int
 sdhc_wait_state(struct sdhc_host *hp, uint32_t mask, uint32_t value)
 {
@@ -1405,7 +1499,7 @@
                command |= SDHC_CRC_CHECK_ENABLE;
        if (ISSET(cmd->c_flags, SCF_RSP_IDX))
                command |= SDHC_INDEX_CHECK_ENABLE;
-       if (cmd->c_data != NULL)
+       if (cmd->c_datalen > 0)
                command |= SDHC_DATA_PRESENT_SELECT;
 
        if (!ISSET(cmd->c_flags, SCF_RSP_PRESENT))
@@ -1438,7 +1532,7 @@
        }
 
        /* Set DMA start address. */
-       if (ISSET(hp->flags, SHF_USE_ADMA2_MASK) && cmd->c_datalen > 0) {
+       if (ISSET(hp->flags, SHF_USE_ADMA2_MASK) && cmd->c_data != NULL) {
                for (int seg = 0; seg < cmd->c_dmamap->dm_nsegs; seg++) {
                        bus_addr_t paddr =
                            cmd->c_dmamap->dm_segs[seg].ds_addr;
diff -r 55a62ca67cbf -r 1311b6a0bf0e sys/dev/sdmmc/sdhcreg.h
--- a/sys/dev/sdmmc/sdhcreg.h   Wed Aug 05 10:29:37 2015 +0000
+++ b/sys/dev/sdmmc/sdhcreg.h   Wed Aug 05 10:30:25 2015 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: sdhcreg.h,v 1.15 2015/08/02 21:45:12 jmcneill Exp $    */
+/*     $NetBSD: sdhcreg.h,v 1.16 2015/08/05 10:30:25 jmcneill Exp $    */
 /*     $OpenBSD: sdhcreg.h,v 1.4 2006/07/30 17:20:40 fgsch Exp $       */
 
 /*
@@ -143,6 +143,8 @@
 #define  SDHC_EINTR_SIGNAL_MASK                0x03ff  /* excluding vendor signals */
 #define SDHC_CMD12_ERROR_STATUS                0x3c
 #define SDHC_HOST_CTL2                 0x3e
+#define  SDHC_SAMPLING_CLOCK_SEL       (1<<7)
+#define  SDHC_EXECUTE_TUNING           (1<<6)
 #define  SDHC_1_8V_SIGNAL_EN           (1<<3)
 #define  SDHC_UHS_MODE_SELECT_SHIFT    0
 #define  SDHC_UHS_MODE_SELECT_MASK     0x7



Home | Main Index | Thread Index | Old Index