[BACK]Return to sdhc.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / sdmmc

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/sys/dev/sdmmc/sdhc.c between version 1.9.2.1 and 1.9.2.2

version 1.9.2.1, 2012/04/17 00:08:03 version 1.9.2.2, 2012/10/30 17:22:01
Line 88  struct sdhc_host {
Line 88  struct sdhc_host {
 };  };
   
 #define HDEVNAME(hp)    (device_xname((hp)->sc->sc_dev))  #define HDEVNAME(hp)    (device_xname((hp)->sc->sc_dev))
   #define HDEVINST(hp)    ((int)(((hp)-(hp)->sc->sc_host[0])/sizeof(*(hp))))
   
 static uint8_t  static uint8_t
 hread1(struct sdhc_host *hp, bus_size_t reg)  hread1(struct sdhc_host *hp, bus_size_t reg)
Line 216  static struct sdmmc_chip_functions sdhc_
Line 217  static struct sdmmc_chip_functions sdhc_
         sdhc_card_intr_ack          sdhc_card_intr_ack
 };  };
   
   static int
   sdhc_cfprint(void *aux, const char *pnp)
   {
           const struct sdmmcbus_attach_args * const saa = aux;
           const struct sdhc_host * const hp = saa->saa_sch;
   
           if (pnp) {
                   aprint_normal("sdmmc at %s", pnp);
           }
           aprint_normal(" slot %d", HDEVINST(hp));
   
           return UNCONF;
   }
   
 /*  /*
  * Called by attachment driver.  For each SD card slot there is one SD   * Called by attachment driver.  For each SD card slot there is one SD
  * host controller standard register set. (1.3)   * host controller standard register set. (1.3)
Line 277  sdhc_host_found(struct sdhc_softc *sc, b
Line 292  sdhc_host_found(struct sdhc_softc *sc, b
         (void)sdhc_host_reset(hp);          (void)sdhc_host_reset(hp);
   
         /* Determine host capabilities. */          /* Determine host capabilities. */
         mutex_enter(&hp->host_mtx);          if (ISSET(sc->sc_flags, SDHC_FLAG_HOSTCAPS)) {
         caps = HREAD4(hp, SDHC_CAPABILITIES);                  caps = sc->sc_caps;
         mutex_exit(&hp->host_mtx);          } else {
                   mutex_enter(&hp->host_mtx);
                   caps = HREAD4(hp, SDHC_CAPABILITIES);
                   mutex_exit(&hp->host_mtx);
           }
   
 #if notyet  
         /* Use DMA if the host system and the controller support it. */          /* Use DMA if the host system and the controller support it. */
         if (ISSET(sc->sc_flags, SDHC_FLAG_FORCE_DMA)          if (ISSET(sc->sc_flags, SDHC_FLAG_FORCE_DMA) ||
          || ((ISSET(sc->sc_flags, SDHC_FLAG_USE_DMA)              (ISSET(sc->sc_flags, SDHC_FLAG_USE_DMA &&
            && ISSET(caps, SDHC_DMA_SUPPORT)))) {               ISSET(caps, SDHC_DMA_SUPPORT)))) {
                 SET(hp->flags, SHF_USE_DMA);                  SET(hp->flags, SHF_USE_DMA);
                 aprint_normal_dev(sc->sc_dev, "using DMA transfer\n");                  aprint_normal_dev(sc->sc_dev, "using DMA transfer\n");
         }          }
 #endif  
   
         /*          /*
          * Determine the base clock frequency. (2.2.24)           * Determine the base clock frequency. (2.2.24)
          */           */
         hp->clkbase = SDHC_BASE_FREQ_KHZ(caps);          if (hp->specver == SDHC_SPEC_VERS_300) {
                   hp->clkbase = SDHC_BASE_V3_FREQ_KHZ(caps);
           } else {
                   hp->clkbase = SDHC_BASE_FREQ_KHZ(caps);
           }
         if (hp->clkbase == 0) {          if (hp->clkbase == 0) {
                 if (sc->sc_clkbase == 0) {                  if (sc->sc_clkbase == 0) {
                         /* The attachment driver must tell us. */                          /* The attachment driver must tell us. */
Line 319  sdhc_host_found(struct sdhc_softc *sc, b
Line 340  sdhc_host_found(struct sdhc_softc *sc, b
          * capabilities. (2.2.15)           * capabilities. (2.2.15)
          */           */
         HWRITE1(hp, SDHC_TIMEOUT_CTL, SDHC_TIMEOUT_MAX);          HWRITE1(hp, SDHC_TIMEOUT_CTL, SDHC_TIMEOUT_MAX);
 #if 0  #if 1
         if (ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED))          if (ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED))
                 HWRITE4(hp, SDHC_NINTR_STATUS, SDHC_CMD_TIMEOUT_ERROR << 16);                  HWRITE4(hp, SDHC_NINTR_STATUS, SDHC_CMD_TIMEOUT_ERROR << 16);
 #endif  #endif
Line 386  sdhc_host_found(struct sdhc_softc *sc, b
Line 407  sdhc_host_found(struct sdhc_softc *sc, b
                 saa.saa_caps |= SMC_CAPS_8BIT_MODE;                  saa.saa_caps |= SMC_CAPS_8BIT_MODE;
         if (ISSET(caps, SDHC_HIGH_SPEED_SUPP))          if (ISSET(caps, SDHC_HIGH_SPEED_SUPP))
                 saa.saa_caps |= SMC_CAPS_SD_HIGHSPEED;                  saa.saa_caps |= SMC_CAPS_SD_HIGHSPEED;
 #if notyet          if (ISSET(hp->flags, SHF_USE_DMA)) {
         if (ISSET(hp->flags, SHF_USE_DMA))  
                 saa.saa_caps |= SMC_CAPS_DMA;                  saa.saa_caps |= SMC_CAPS_DMA;
 #endif                  if (hp->specver == SDHC_SPEC_VERS_100) {
         hp->sdmmc = config_found(sc->sc_dev, &saa, NULL);                          saa.saa_caps |= SMC_CAPS_MULTI_SEG_DMA;
                   }
           }
           if (ISSET(sc->sc_flags, SDHC_FLAG_SINGLE_ONLY))
                   saa.saa_caps |= SMC_CAPS_SINGLE_ONLY;
           hp->sdmmc = config_found(sc->sc_dev, &saa, sdhc_cfprint);
   
         return 0;          return 0;
   
Line 533  sdhc_host_reset1(sdmmc_chipset_handle_t 
Line 558  sdhc_host_reset1(sdmmc_chipset_handle_t 
   
         /* Set data timeout counter value to max for now. */          /* Set data timeout counter value to max for now. */
         HWRITE1(hp, SDHC_TIMEOUT_CTL, SDHC_TIMEOUT_MAX);          HWRITE1(hp, SDHC_TIMEOUT_CTL, SDHC_TIMEOUT_MAX);
 #if 0  #if 1
         if (ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED))          if (ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED))
                 HWRITE4(hp, SDHC_NINTR_STATUS, SDHC_CMD_TIMEOUT_ERROR << 16);                  HWRITE4(hp, SDHC_NINTR_STATUS, SDHC_CMD_TIMEOUT_ERROR << 16);
 #endif  #endif
   
         /* Enable interrupts. */          /* Enable interrupts. */
           mutex_enter(&hp->intr_mtx);
         sdhcimask = SDHC_CARD_REMOVAL | SDHC_CARD_INSERTION |          sdhcimask = SDHC_CARD_REMOVAL | SDHC_CARD_INSERTION |
             SDHC_BUFFER_READ_READY | SDHC_BUFFER_WRITE_READY |              SDHC_BUFFER_READ_READY | SDHC_BUFFER_WRITE_READY |
             SDHC_DMA_INTERRUPT | SDHC_BLOCK_GAP_EVENT |              SDHC_DMA_INTERRUPT | SDHC_BLOCK_GAP_EVENT |
Line 557  sdhc_host_reset1(sdmmc_chipset_handle_t 
Line 583  sdhc_host_reset1(sdmmc_chipset_handle_t 
                 HWRITE2(hp, SDHC_NINTR_SIGNAL_EN, sdhcimask);                  HWRITE2(hp, SDHC_NINTR_SIGNAL_EN, sdhcimask);
                 HWRITE2(hp, SDHC_EINTR_SIGNAL_EN, SDHC_EINTR_SIGNAL_MASK);                  HWRITE2(hp, SDHC_EINTR_SIGNAL_EN, SDHC_EINTR_SIGNAL_MASK);
         }          }
           mutex_exit(&hp->intr_mtx);
   
 out:  out:
         return error;          return error;
Line 600  sdhc_card_detect(sdmmc_chipset_handle_t 
Line 627  sdhc_card_detect(sdmmc_chipset_handle_t 
         struct sdhc_host *hp = (struct sdhc_host *)sch;          struct sdhc_host *hp = (struct sdhc_host *)sch;
         int r;          int r;
   
           if (hp->sc->sc_vendor_card_detect)
                   return (*hp->sc->sc_vendor_card_detect)(hp->sc);
   
         mutex_enter(&hp->host_mtx);          mutex_enter(&hp->host_mtx);
         r = ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_CARD_INSERTED);          r = ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_CARD_INSERTED);
         mutex_exit(&hp->host_mtx);          mutex_exit(&hp->host_mtx);
Line 616  sdhc_write_protect(sdmmc_chipset_handle_
Line 646  sdhc_write_protect(sdmmc_chipset_handle_
         struct sdhc_host *hp = (struct sdhc_host *)sch;          struct sdhc_host *hp = (struct sdhc_host *)sch;
         int r;          int r;
   
           if (hp->sc->sc_vendor_write_protect)
                   return (*hp->sc->sc_vendor_write_protect)(hp->sc);
   
         mutex_enter(&hp->host_mtx);          mutex_enter(&hp->host_mtx);
         r = ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_WRITE_PROTECT_SWITCH);          r = ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_WRITE_PROTECT_SWITCH);
         mutex_exit(&hp->host_mtx);          mutex_exit(&hp->host_mtx);
Line 633  sdhc_bus_power(sdmmc_chipset_handle_t sc
Line 666  sdhc_bus_power(sdmmc_chipset_handle_t sc
         struct sdhc_host *hp = (struct sdhc_host *)sch;          struct sdhc_host *hp = (struct sdhc_host *)sch;
         uint8_t vdd;          uint8_t vdd;
         int error = 0;          int error = 0;
           const uint32_t pcmask =
               ~(SDHC_BUS_POWER | (SDHC_VOLTAGE_MASK << SDHC_VOLTAGE_SHIFT));
   
         mutex_enter(&hp->host_mtx);          mutex_enter(&hp->host_mtx);
   
Line 671  sdhc_bus_power(sdmmc_chipset_handle_t sc
Line 706  sdhc_bus_power(sdmmc_chipset_handle_t sc
                  * voltage ramp until power rises.                   * voltage ramp until power rises.
                  */                   */
                 HWRITE1(hp, SDHC_POWER_CTL,                  HWRITE1(hp, SDHC_POWER_CTL,
                     (vdd << SDHC_VOLTAGE_SHIFT) | SDHC_BUS_POWER);                      HREAD1(hp, SDHC_POWER_CTL) & pcmask);
                   sdmmc_delay(1);
                   HWRITE1(hp, SDHC_POWER_CTL, (vdd << SDHC_VOLTAGE_SHIFT));
                   sdmmc_delay(1);
                   HSET1(hp, SDHC_POWER_CTL, SDHC_BUS_POWER);
                 sdmmc_delay(10000);                  sdmmc_delay(10000);
   
                 /*                  /*
Line 706  sdhc_clock_divisor(struct sdhc_host *hp,
Line 745  sdhc_clock_divisor(struct sdhc_host *hp,
                                 *divp = SDHC_SDCLK_CGM                                  *divp = SDHC_SDCLK_CGM
                                     | ((div & 0x300) << SDHC_SDCLK_XDIV_SHIFT)                                      | ((div & 0x300) << SDHC_SDCLK_XDIV_SHIFT)
                                     | ((div & 0x0ff) << SDHC_SDCLK_DIV_SHIFT);                                      | ((div & 0x0ff) << SDHC_SDCLK_DIV_SHIFT);
                                   //freq = hp->clkbase / div;
                                 return true;                                  return true;
                         }                          }
                 }                  }
Line 723  sdhc_clock_divisor(struct sdhc_host *hp,
Line 763  sdhc_clock_divisor(struct sdhc_host *hp,
                                 DPRINTF(2,                                  DPRINTF(2,
                                     ("%s: divisor for freq %u is %u * %u\n",                                      ("%s: divisor for freq %u is %u * %u\n",
                                     HDEVNAME(hp), freq, div * 2, dvs + 1));                                      HDEVNAME(hp), freq, div * 2, dvs + 1));
                                   //freq = hp->clkbase / (div * 2) * (dvs + 1);
                                 return true;                                  return true;
                         }                          }
                         /*                          /*
Line 730  sdhc_clock_divisor(struct sdhc_host *hp,
Line 771  sdhc_clock_divisor(struct sdhc_host *hp,
                          */                           */
                         roundup |= dvs & 1;                          roundup |= dvs & 1;
                 }                  }
                 panic("%s: can't find divisor for freq %u", HDEVNAME(hp), freq);                  /* No divisor found. */
                   return false;
         } else {          } else {
                 for (div = 1; div <= 256; div *= 2) {                  if (hp->sc->sc_clkmsk != 0)
                         if ((hp->clkbase / div) <= freq) {                          *divp = (hp->clkbase / freq) <<
                                 *divp = (div / 2) << SDHC_SDCLK_DIV_SHIFT;                              (ffs(hp->sc->sc_clkmsk) - 1);
                                 return true;                  else
                         }                          *divp = (hp->clkbase / freq) << SDHC_SDCLK_DIV_SHIFT;
                 }                  return true;
         }          }
         /* No divisor found. */          /* No divisor found. */
         return false;          return false;
Line 753  sdhc_bus_clock(sdmmc_chipset_handle_t sc
Line 795  sdhc_bus_clock(sdmmc_chipset_handle_t sc
         struct sdhc_host *hp = (struct sdhc_host *)sch;          struct sdhc_host *hp = (struct sdhc_host *)sch;
         u_int div;          u_int div;
         u_int timo;          u_int timo;
           int16_t reg;
         int error = 0;          int error = 0;
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
         bool present;          bool present;
Line 763  sdhc_bus_clock(sdmmc_chipset_handle_t sc
Line 806  sdhc_bus_clock(sdmmc_chipset_handle_t sc
   
         /* Must not stop the clock if commands are in progress. */          /* Must not stop the clock if commands are in progress. */
         if (present && sdhc_card_detect(hp)) {          if (present && sdhc_card_detect(hp)) {
                 printf("%s: sdhc_sdclk_frequency_select: command in progress\n",                  aprint_normal_dev(hp->sc->sc_dev,
                     device_xname(hp->sc->sc_dev));                      "%s: command in progress\n", __func__);
         }          }
 #endif  #endif
   
Line 780  sdhc_bus_clock(sdmmc_chipset_handle_t sc
Line 823  sdhc_bus_clock(sdmmc_chipset_handle_t sc
                         goto out;                          goto out;
                 }                  }
         } else {          } else {
                 HWRITE2(hp, SDHC_CLOCK_CTL, 0);                  HCLR2(hp, SDHC_CLOCK_CTL, SDHC_SDCLK_ENABLE);
                 if (freq == SDMMC_SDCLK_OFF)                  if (freq == SDMMC_SDCLK_OFF)
                         goto out;                          goto out;
         }          }
Line 797  sdhc_bus_clock(sdmmc_chipset_handle_t sc
Line 840  sdhc_bus_clock(sdmmc_chipset_handle_t sc
                 HWRITE4(hp, SDHC_CLOCK_CTL,                  HWRITE4(hp, SDHC_CLOCK_CTL,
                     div | (SDHC_TIMEOUT_MAX << 16));                      div | (SDHC_TIMEOUT_MAX << 16));
         } else {          } else {
                 HWRITE2(hp, SDHC_CLOCK_CTL, div);                  reg = HREAD2(hp, SDHC_CLOCK_CTL);
                   reg &= (SDHC_INTCLK_STABLE | SDHC_INTCLK_ENABLE);
                   HWRITE2(hp, SDHC_CLOCK_CTL, reg | div);
         }          }
   
         /*          /*
Line 902  sdhc_bus_width(sdmmc_chipset_handle_t sc
Line 947  sdhc_bus_width(sdmmc_chipset_handle_t sc
 static int  static int
 sdhc_bus_rod(sdmmc_chipset_handle_t sch, int on)  sdhc_bus_rod(sdmmc_chipset_handle_t sch, int on)
 {  {
           struct sdhc_host *hp = (struct sdhc_host *)sch;
   
           if (hp->sc->sc_vendor_rod)
                   return (*hp->sc->sc_vendor_rod)(hp->sc, on);
   
         /* Nothing ?? */  
         return 0;          return 0;
 }  }
   
Line 913  sdhc_card_enable_intr(sdmmc_chipset_hand
Line 961  sdhc_card_enable_intr(sdmmc_chipset_hand
         struct sdhc_host *hp = (struct sdhc_host *)sch;          struct sdhc_host *hp = (struct sdhc_host *)sch;
   
         if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) {          if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) {
                 mutex_enter(&hp->host_mtx);                  mutex_enter(&hp->intr_mtx);
                 if (enable) {                  if (enable) {
                         HSET2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);                          HSET2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
                         HSET2(hp, SDHC_NINTR_SIGNAL_EN, SDHC_CARD_INTERRUPT);                          HSET2(hp, SDHC_NINTR_SIGNAL_EN, SDHC_CARD_INTERRUPT);
Line 921  sdhc_card_enable_intr(sdmmc_chipset_hand
Line 969  sdhc_card_enable_intr(sdmmc_chipset_hand
                         HCLR2(hp, SDHC_NINTR_SIGNAL_EN, SDHC_CARD_INTERRUPT);                          HCLR2(hp, SDHC_NINTR_SIGNAL_EN, SDHC_CARD_INTERRUPT);
                         HCLR2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);                          HCLR2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
                 }                  }
                 mutex_exit(&hp->host_mtx);                  mutex_exit(&hp->intr_mtx);
         }          }
 }  }
   
Line 931  sdhc_card_intr_ack(sdmmc_chipset_handle_
Line 979  sdhc_card_intr_ack(sdmmc_chipset_handle_
         struct sdhc_host *hp = (struct sdhc_host *)sch;          struct sdhc_host *hp = (struct sdhc_host *)sch;
   
         if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) {          if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) {
                 mutex_enter(&hp->host_mtx);                  mutex_enter(&hp->intr_mtx);
                 HSET2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);                  HSET2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
                 mutex_exit(&hp->host_mtx);                  mutex_exit(&hp->intr_mtx);
         }          }
 }  }
   
Line 959  sdhc_exec_command(sdmmc_chipset_handle_t
Line 1007  sdhc_exec_command(sdmmc_chipset_handle_t
         struct sdhc_host *hp = (struct sdhc_host *)sch;          struct sdhc_host *hp = (struct sdhc_host *)sch;
         int error;          int error;
   
 #if 0          if (cmd->c_data && ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) {
         if (cmd->c_data) {  
                 const uint16_t ready = SDHC_BUFFER_READ_READY | SDHC_BUFFER_WRITE_READY;                  const uint16_t ready = SDHC_BUFFER_READ_READY | SDHC_BUFFER_WRITE_READY;
                   mutex_enter(&hp->intr_mtx);
                 if (ISSET(hp->flags, SHF_USE_DMA)) {                  if (ISSET(hp->flags, SHF_USE_DMA)) {
                         HCLR2(hp, SDHC_NINTR_SIGNAL_EN, ready);                          HCLR2(hp, SDHC_NINTR_SIGNAL_EN, ready);
                         HCLR2(hp, SDHC_NINTR_STATUS_EN, ready);                          HCLR2(hp, SDHC_NINTR_STATUS_EN, ready);
Line 969  sdhc_exec_command(sdmmc_chipset_handle_t
Line 1017  sdhc_exec_command(sdmmc_chipset_handle_t
                         HSET2(hp, SDHC_NINTR_SIGNAL_EN, ready);                          HSET2(hp, SDHC_NINTR_SIGNAL_EN, ready);
                         HSET2(hp, SDHC_NINTR_STATUS_EN, ready);                          HSET2(hp, SDHC_NINTR_STATUS_EN, ready);
                 }                  }
                   mutex_exit(&hp->intr_mtx);
         }          }
 #endif  
   
         /*          /*
          * Start the MMC command, or mark `cmd' as failed and return.           * Start the MMC command, or mark `cmd' as failed and return.
Line 997  sdhc_exec_command(sdmmc_chipset_handle_t
Line 1045  sdhc_exec_command(sdmmc_chipset_handle_t
          */           */
         mutex_enter(&hp->host_mtx);          mutex_enter(&hp->host_mtx);
         if (cmd->c_error == 0 && ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {          if (cmd->c_error == 0 && ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
                   cmd->c_resp[0] = HREAD4(hp, SDHC_RESPONSE + 0);
                 if (ISSET(cmd->c_flags, SCF_RSP_136)) {                  if (ISSET(cmd->c_flags, SCF_RSP_136)) {
                         uint8_t *p = (uint8_t *)cmd->c_resp;                          cmd->c_resp[1] = HREAD4(hp, SDHC_RESPONSE + 4);
                         int i;                          cmd->c_resp[2] = HREAD4(hp, SDHC_RESPONSE + 8);
                           cmd->c_resp[3] = HREAD4(hp, SDHC_RESPONSE + 12);
                         for (i = 0; i < 15; i++)                          if (ISSET(hp->sc->sc_flags, SDHC_FLAG_RSP136_CRC)) {
                                 *p++ = HREAD1(hp, SDHC_RESPONSE + i);                                  cmd->c_resp[0] = (cmd->c_resp[0] >> 8) |
                 } else {                                      (cmd->c_resp[1] << 24);
                         cmd->c_resp[0] = HREAD4(hp, SDHC_RESPONSE);                                  cmd->c_resp[1] = (cmd->c_resp[1] >> 8) |
                                       (cmd->c_resp[2] << 24);
                                   cmd->c_resp[2] = (cmd->c_resp[2] >> 8) |
                                       (cmd->c_resp[3] << 24);
                                   cmd->c_resp[3] = (cmd->c_resp[3] >> 8);
                           }
                 }                  }
         }          }
         mutex_exit(&hp->host_mtx);          mutex_exit(&hp->host_mtx);
Line 1018  sdhc_exec_command(sdmmc_chipset_handle_t
Line 1072  sdhc_exec_command(sdmmc_chipset_handle_t
                 sdhc_transfer_data(hp, cmd);                  sdhc_transfer_data(hp, cmd);
   
 out:  out:
 #if 0          if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)
         if (cmd->c_dmamap != NULL && cmd->c_error == 0              && !ISSET(hp->sc->sc_flags, SDHC_FLAG_NO_LED_ON)) {
             && ISSET(hp->flags, SHF_USE_DMA)  
             && ISSET(cmd->c_flags, SCF_CMD_READ) {  
                 if (((uintptr_t)cmd->c_data & PAGE_MASK) + cmd->c_datalen > PAGE_SIZE) {  
                         memcpy(cmd->c_data,  
                             (void *)hp->sc->dma_map->dm_segs[0].ds_addr,  
                             cmd->c_datalen);  
                 }  
                 bus_dmamap_unload(hp->sc->dt, hp->sc->dma_map);  
         }  
 #endif  
   
         if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) {  
                 mutex_enter(&hp->host_mtx);                  mutex_enter(&hp->host_mtx);
                 /* Turn off the LED. */                  /* Turn off the LED. */
                 HCLR1(hp, SDHC_HOST_CTL, SDHC_LED_ON);                  HCLR1(hp, SDHC_HOST_CTL, SDHC_LED_ON);
Line 1082  sdhc_start_command(struct sdhc_host *hp,
Line 1124  sdhc_start_command(struct sdhc_host *hp,
         }          }
   
         /* Prepare transfer mode register value. (2.2.5) */          /* Prepare transfer mode register value. (2.2.5) */
         mode = 0;          mode = SDHC_BLOCK_COUNT_ENABLE;
         if (ISSET(cmd->c_flags, SCF_CMD_READ))          if (ISSET(cmd->c_flags, SCF_CMD_READ))
                 mode |= SDHC_READ_MODE;                  mode |= SDHC_READ_MODE;
         if (blkcount > 0) {          if (blkcount > 1) {
                 mode |= SDHC_BLOCK_COUNT_ENABLE;                  mode |= SDHC_MULTI_BLOCK_MODE;
                 if (blkcount > 1) {                  /* XXX only for memory commands? */
                         mode |= SDHC_MULTI_BLOCK_MODE;                  mode |= SDHC_AUTO_CMD12_ENABLE;
                         /* XXX only for memory commands? */  
                         mode |= SDHC_AUTO_CMD12_ENABLE;  
                 }  
         }          }
         if (cmd->c_dmamap != NULL && cmd->c_datalen > 0) {          if (cmd->c_dmamap != NULL && cmd->c_datalen > 0) {
                 if (cmd->c_dmamap->dm_nsegs == 1) {                  mode |= SDHC_DMA_ENABLE;
                         mode |= SDHC_DMA_ENABLE;  
                 } else {  
                         cmd->c_dmamap = NULL;  
                 }  
         }          }
   
         /*          /*
Line 1130  sdhc_start_command(struct sdhc_host *hp,
Line 1165  sdhc_start_command(struct sdhc_host *hp,
         DPRINTF(1,("%s: writing cmd: blksize=%d blkcnt=%d mode=%04x cmd=%04x\n",          DPRINTF(1,("%s: writing cmd: blksize=%d blkcnt=%d mode=%04x cmd=%04x\n",
             HDEVNAME(hp), blksize, blkcount, mode, command));              HDEVNAME(hp), blksize, blkcount, mode, command));
   
           blksize |= (MAX(0, PAGE_SHIFT - 12) & SDHC_DMA_BOUNDARY_MASK) <<
               SDHC_DMA_BOUNDARY_SHIFT;    /* PAGE_SIZE DMA boundary */
   
         mutex_enter(&hp->host_mtx);          mutex_enter(&hp->host_mtx);
   
         if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) {          if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) {
Line 1150  sdhc_start_command(struct sdhc_host *hp,
Line 1188  sdhc_start_command(struct sdhc_host *hp,
                 HWRITE4(hp, SDHC_ARGUMENT, cmd->c_arg);                  HWRITE4(hp, SDHC_ARGUMENT, cmd->c_arg);
                 HWRITE4(hp, SDHC_TRANSFER_MODE, mode | (command << 16));                  HWRITE4(hp, SDHC_TRANSFER_MODE, mode | (command << 16));
         } else {          } else {
                 HWRITE2(hp, SDHC_TRANSFER_MODE, mode);  
                 HWRITE2(hp, SDHC_BLOCK_SIZE, blksize);                  HWRITE2(hp, SDHC_BLOCK_SIZE, blksize);
                 if (blkcount > 1)                  HWRITE2(hp, SDHC_BLOCK_COUNT, blkcount);
                         HWRITE2(hp, SDHC_BLOCK_COUNT, blkcount);  
                 HWRITE4(hp, SDHC_ARGUMENT, cmd->c_arg);                  HWRITE4(hp, SDHC_ARGUMENT, cmd->c_arg);
                   HWRITE2(hp, SDHC_TRANSFER_MODE, mode);
                 HWRITE2(hp, SDHC_COMMAND, command);                  HWRITE2(hp, SDHC_COMMAND, command);
         }          }
   
Line 1196  sdhc_transfer_data(struct sdhc_host *hp,
Line 1233  sdhc_transfer_data(struct sdhc_host *hp,
 static int  static int
 sdhc_transfer_data_dma(struct sdhc_host *hp, struct sdmmc_command *cmd)  sdhc_transfer_data_dma(struct sdhc_host *hp, struct sdmmc_command *cmd)
 {  {
         bus_dmamap_t dmap = cmd->c_dmamap;          bus_dma_segment_t *dm_segs = cmd->c_dmamap->dm_segs;
         uint16_t blklen = cmd->c_blklen;          bus_addr_t posaddr;
         uint16_t blkcnt = cmd->c_datalen / blklen;          bus_addr_t segaddr;
         uint16_t remain;          bus_size_t seglen;
           u_int seg = 0;
         int error = 0;          int error = 0;
           int status;
   
         KASSERT(HREAD2(hp, SDHC_NINTR_STATUS_EN) & SDHC_DMA_INTERRUPT);          KASSERT(HREAD2(hp, SDHC_NINTR_STATUS_EN) & SDHC_DMA_INTERRUPT);
         KASSERT(HREAD2(hp, SDHC_NINTR_SIGNAL_EN) & SDHC_DMA_INTERRUPT);          KASSERT(HREAD2(hp, SDHC_NINTR_SIGNAL_EN) & SDHC_DMA_INTERRUPT);
Line 1208  sdhc_transfer_data_dma(struct sdhc_host 
Line 1247  sdhc_transfer_data_dma(struct sdhc_host 
         KASSERT(HREAD2(hp, SDHC_NINTR_SIGNAL_EN) & SDHC_TRANSFER_COMPLETE);          KASSERT(HREAD2(hp, SDHC_NINTR_SIGNAL_EN) & SDHC_TRANSFER_COMPLETE);
   
         for (;;) {          for (;;) {
                 if (!sdhc_wait_intr(hp,                  status = sdhc_wait_intr(hp,
                     SDHC_DMA_INTERRUPT|SDHC_TRANSFER_COMPLETE,                      SDHC_DMA_INTERRUPT|SDHC_TRANSFER_COMPLETE,
                     SDHC_DMA_TIMEOUT)) {                      SDHC_DMA_TIMEOUT);
   
                   if (status & SDHC_TRANSFER_COMPLETE) {
                           break;
                   }
                   if (!status) {
                         error = ETIMEDOUT;                          error = ETIMEDOUT;
                         break;                          break;
                 }                  }
                   if ((status & SDHC_DMA_INTERRUPT) == 0) {
                           continue;
                   }
   
                 /* single block mode */                  /* DMA Interrupt (boundary crossing) */
                 if (blkcnt == 1)  
                         break;  
   
                 /* multi block mode */                  segaddr = dm_segs[seg].ds_addr;
                 remain = HREAD2(hp, SDHC_BLOCK_COUNT);                  seglen = dm_segs[seg].ds_len;
                 if (remain == 0)                  mutex_enter(&hp->host_mtx);
                         break;                  posaddr = HREAD4(hp, SDHC_DMA_ADDR);
                   mutex_exit(&hp->host_mtx);
   
                 HWRITE4(hp, SDHC_DMA_ADDR,                  if ((seg == (cmd->c_dmamap->dm_nsegs-1)) && (posaddr == (segaddr + seglen))) {
                     dmap->dm_segs[0].ds_addr + (blkcnt - remain) * blklen);                          break;
                   }
                   mutex_enter(&hp->host_mtx);
                   if ((posaddr >= segaddr) && (posaddr < (segaddr + seglen)))
                           HWRITE4(hp, SDHC_DMA_ADDR, posaddr);
                   else if ((posaddr >= segaddr) && (posaddr == (segaddr + seglen)) && (seg + 1) < cmd->c_dmamap->dm_nsegs)
                           HWRITE4(hp, SDHC_DMA_ADDR, dm_segs[++seg].ds_addr);
                   mutex_exit(&hp->host_mtx);
                   KASSERT(seg < cmd->c_dmamap->dm_nsegs);
         }          }
   
 #if 0  
         if (error == 0 && !sdhc_wait_intr(hp, SDHC_TRANSFER_COMPLETE,  
             SDHC_TRANSFER_TIMEOUT))  
                 error = ETIMEDOUT;  
 #endif  
   
         return error;          return error;
 }  }
   
Line 1272  sdhc_transfer_data_pio(struct sdhc_host 
Line 1320  sdhc_transfer_data_pio(struct sdhc_host 
   
         while (datalen > 0) {          while (datalen > 0) {
                 if (!ISSET(HREAD4(hp, SDHC_PRESENT_STATE), imask)) {                  if (!ISSET(HREAD4(hp, SDHC_PRESENT_STATE), imask)) {
                           mutex_enter(&hp->intr_mtx);
                         if (ISSET(hp->sc->sc_flags, SDHC_FLAG_32BIT_ACCESS)) {                          if (ISSET(hp->sc->sc_flags, SDHC_FLAG_32BIT_ACCESS)) {
                                 HSET4(hp, SDHC_NINTR_SIGNAL_EN, imask);                                  HSET4(hp, SDHC_NINTR_SIGNAL_EN, imask);
                         } else {                          } else {
                                 HSET2(hp, SDHC_NINTR_SIGNAL_EN, imask);                                  HSET2(hp, SDHC_NINTR_SIGNAL_EN, imask);
                         }                          }
                           mutex_exit(&hp->intr_mtx);
                         if (!sdhc_wait_intr(hp, imask, SDHC_BUFFER_TIMEOUT)) {                          if (!sdhc_wait_intr(hp, imask, SDHC_BUFFER_TIMEOUT)) {
                                 error = ETIMEDOUT;                                  error = ETIMEDOUT;
                                 break;                                  break;
Line 1309  sdhc_read_data_pio(struct sdhc_host *hp,
Line 1359  sdhc_read_data_pio(struct sdhc_host *hp,
   
         if (((__uintptr_t)data & 3) == 0) {          if (((__uintptr_t)data & 3) == 0) {
                 while (datalen > 3) {                  while (datalen > 3) {
                         *(uint32_t *)data = HREAD4(hp, SDHC_DATA);                          *(uint32_t *)data = le32toh(HREAD4(hp, SDHC_DATA));
                         data += 4;                          data += 4;
                         datalen -= 4;                          datalen -= 4;
                 }                  }
                 if (datalen > 1) {                  if (datalen > 1) {
                         *(uint16_t *)data = HREAD2(hp, SDHC_DATA);                          *(uint16_t *)data = le16toh(HREAD2(hp, SDHC_DATA));
                         data += 2;                          data += 2;
                         datalen -= 2;                          datalen -= 2;
                 }                  }
Line 1325  sdhc_read_data_pio(struct sdhc_host *hp,
Line 1375  sdhc_read_data_pio(struct sdhc_host *hp,
                 }                  }
         } else if (((__uintptr_t)data & 1) == 0) {          } else if (((__uintptr_t)data & 1) == 0) {
                 while (datalen > 1) {                  while (datalen > 1) {
                         *(uint16_t *)data = HREAD2(hp, SDHC_DATA);                          *(uint16_t *)data = le16toh(HREAD2(hp, SDHC_DATA));
                         data += 2;                          data += 2;
                         datalen -= 2;                          datalen -= 2;
                 }                  }
Line 1349  sdhc_write_data_pio(struct sdhc_host *hp
Line 1399  sdhc_write_data_pio(struct sdhc_host *hp
   
         if (((__uintptr_t)data & 3) == 0) {          if (((__uintptr_t)data & 3) == 0) {
                 while (datalen > 3) {                  while (datalen > 3) {
                         HWRITE4(hp, SDHC_DATA, *(uint32_t *)data);                          HWRITE4(hp, SDHC_DATA, htole32(*(uint32_t *)data));
                         data += 4;                          data += 4;
                         datalen -= 4;                          datalen -= 4;
                 }                  }
                 if (datalen > 1) {                  if (datalen > 1) {
                         HWRITE2(hp, SDHC_DATA, *(uint16_t *)data);                          HWRITE2(hp, SDHC_DATA, htole16(*(uint16_t *)data));
                         data += 2;                          data += 2;
                         datalen -= 2;                          datalen -= 2;
                 }                  }
Line 1365  sdhc_write_data_pio(struct sdhc_host *hp
Line 1415  sdhc_write_data_pio(struct sdhc_host *hp
                 }                  }
         } else if (((__uintptr_t)data & 1) == 0) {          } else if (((__uintptr_t)data & 1) == 0) {
                 while (datalen > 1) {                  while (datalen > 1) {
                         HWRITE2(hp, SDHC_DATA, *(uint16_t *)data);                          HWRITE2(hp, SDHC_DATA, htole16(*(uint16_t *)data));
                         data += 2;                          data += 2;
                         datalen -= 2;                          datalen -= 2;
                 }                  }
Line 1389  esdhc_read_data_pio(struct sdhc_host *hp
Line 1439  esdhc_read_data_pio(struct sdhc_host *hp
         uint16_t status = HREAD2(hp, SDHC_NINTR_STATUS);          uint16_t status = HREAD2(hp, SDHC_NINTR_STATUS);
         uint32_t v;          uint32_t v;
   
           const size_t watermark = (HREAD4(hp, SDHC_WATERMARK_LEVEL) >> SDHC_WATERMARK_READ_SHIFT) & SDHC_WATERMARK_READ_MASK;
           size_t count = 0;
   
         while (datalen > 3 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) {          while (datalen > 3 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) {
                   if (count == 0) {
                           /*
                            * If we've drained "watermark" words, we need to wait
                            * a little bit so the read FIFO can refill.
                            */
                           sdmmc_delay(10);
                           count = watermark;
                   }
                 v = HREAD4(hp, SDHC_DATA);                  v = HREAD4(hp, SDHC_DATA);
                 v = le32toh(v);                  v = le32toh(v);
                 *(uint32_t *)data = v;                  *(uint32_t *)data = v;
                 data += 4;                  data += 4;
                 datalen -= 4;                  datalen -= 4;
                 status = HREAD2(hp, SDHC_NINTR_STATUS);                  status = HREAD2(hp, SDHC_NINTR_STATUS);
                   count--;
         }          }
         if (datalen > 0 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) {          if (datalen > 0 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) {
                   if (count == 0) {
                           sdmmc_delay(10);
                   }
                 v = HREAD4(hp, SDHC_DATA);                  v = HREAD4(hp, SDHC_DATA);
                 v = le32toh(v);                  v = le32toh(v);
                 do {                  do {
Line 1413  esdhc_write_data_pio(struct sdhc_host *h
Line 1478  esdhc_write_data_pio(struct sdhc_host *h
         uint16_t status = HREAD2(hp, SDHC_NINTR_STATUS);          uint16_t status = HREAD2(hp, SDHC_NINTR_STATUS);
         uint32_t v;          uint32_t v;
   
           const size_t watermark = (HREAD4(hp, SDHC_WATERMARK_LEVEL) >> SDHC_WATERMARK_WRITE_SHIFT) & SDHC_WATERMARK_WRITE_MASK;
           size_t count = watermark;
   
         while (datalen > 3 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) {          while (datalen > 3 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) {
                   if (count == 0) {
                           sdmmc_delay(10);
                           count = watermark;
                   }
                 v = *(uint32_t *)data;                  v = *(uint32_t *)data;
                 v = htole32(v);                  v = htole32(v);
                 HWRITE4(hp, SDHC_DATA, v);                  HWRITE4(hp, SDHC_DATA, v);
                 data += 4;                  data += 4;
                 datalen -= 4;                  datalen -= 4;
                 status = HREAD2(hp, SDHC_NINTR_STATUS);                  status = HREAD2(hp, SDHC_NINTR_STATUS);
                   count--;
         }          }
         if (datalen > 0 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) {          if (datalen > 0 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) {
                   if (count == 0) {
                           sdmmc_delay(10);
                   }
                 v = *(uint32_t *)data;                  v = *(uint32_t *)data;
                 v = htole32(v);                  v = htole32(v);
                 HWRITE4(hp, SDHC_DATA, v);                  HWRITE4(hp, SDHC_DATA, v);
Line 1516  sdhc_intr(void *arg)
Line 1592  sdhc_intr(void *arg)
                         uint32_t xstatus = HREAD4(hp, SDHC_NINTR_STATUS);                          uint32_t xstatus = HREAD4(hp, SDHC_NINTR_STATUS);
                         status = xstatus;                          status = xstatus;
                         error = xstatus >> 16;                          error = xstatus >> 16;
                         status |= (error ? SDHC_ERROR_INTERRUPT : 0);                          if (error)
                         if (!ISSET(status, SDHC_NINTR_STATUS_MASK))                                  xstatus |= SDHC_ERROR_INTERRUPT;
                           else if (!ISSET(status, SDHC_NINTR_STATUS_MASK))
                                 continue; /* no interrupt for us */                                  continue; /* no interrupt for us */
                         /* Acknowledge the interrupts we are about to handle. */                          /* Acknowledge the interrupts we are about to handle. */
                         HWRITE4(hp, SDHC_NINTR_STATUS, xstatus);                          HWRITE4(hp, SDHC_NINTR_STATUS, xstatus);
Line 1539  sdhc_intr(void *arg)
Line 1616  sdhc_intr(void *arg)
                 DPRINTF(2,("%s: interrupt status=%x error=%x\n", HDEVNAME(hp),                  DPRINTF(2,("%s: interrupt status=%x error=%x\n", HDEVNAME(hp),
                     status, error));                      status, error));
   
                   mutex_enter(&hp->intr_mtx);
   
                 /* Claim this interrupt. */                  /* Claim this interrupt. */
                 done = 1;                  done = 1;
   
Line 1589  sdhc_intr(void *arg)
Line 1668  sdhc_intr(void *arg)
                         HCLR2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);                          HCLR2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
                         sdmmc_card_intr(hp->sdmmc);                          sdmmc_card_intr(hp->sdmmc);
                 }                  }
                   mutex_exit(&hp->intr_mtx);
         }          }
   
         return done;          return done;

Legend:
Removed from v.1.9.2.1  
changed lines
  Added in v.1.9.2.2

CVSweb <webmaster@jp.NetBSD.org>