github.com/f-secure-foundry/tamago@v0.0.0-20220307101044-d73fcdd7f11b/soc/imx6/usdhc/usdhc.go (about)

     1  // NXP Ultra Secured Digital Host Controller (uSDHC) driver
     2  // https://github.com/f-secure-foundry/tamago
     3  //
     4  // IP: https://www.mobiveil.com/esdhc/
     5  //
     6  // Copyright (c) F-Secure Corporation
     7  // https://foundry.f-secure.com
     8  //
     9  // Use of this source code is governed by the license
    10  // that can be found in the LICENSE file.
    11  
    12  // Package usdhc implements a driver for Freescale Enhanced Secure Digital
    13  // Host Controller (eSDHC) interface, also known as NXP Ultra Secured Digital
    14  // Host Controller (uSDHC).
    15  //
    16  // It currently supports interfacing with SD/MMC cards up to High Speed mode
    17  // and Dual Data Rate.
    18  //
    19  // Higher speed modes for eMMC cards are HS200 (controller supported and driver
    20  // supported) and HS400 mode (unsupported at controller level) [p35, Table 4,
    21  // JESD84-B51].
    22  //
    23  // Higher speed modes for SD cards are SDR50/SDR104 (controller and driver
    24  // supported), DDR50 (controller supported, unimplemented in this driver) and
    25  // UHS-II modes (unsupported at controller level) [p37-38, Figure 3-14 and
    26  // 3-15, SD-PL-7.10].
    27  //
    28  // The highest speed supported by the driver, card and controller is
    29  // automatically selected by Detect().
    30  //
    31  // For eMMC cards, speed mode HS200 requires the target board to have eMMC I/O
    32  // signaling to 1.8V, this must be advertised by the board package by defining
    33  // LowVoltage() on the relevant USDHC instance.
    34  //
    35  // For SD cards, speed modes SDR50/SDR104 require the target board to switch SD
    36  // I/O signaling to 1.8V, the switching procedure must be implemented by the
    37  // board package by defining LowVoltage() on the relevant USDHC instance.
    38  //
    39  // Note that due to NXP errata ERR010450 the following maximum theoretical
    40  // limits apply:
    41  //  * eMMC  HS200: 150MB/s - 150MHz (instead of 200MB/s - 200MHz), supported
    42  //  * eMMC  DDR52:  90MB/s -  45MHz (instead of 104MB/s -  52MHz), supported
    43  //  *   SD SDR104:  75MB/s - 150MHz (instead of 104MB/s - 208MHz), supported
    44  //  *   SD  DDR50:  45MB/s -  45MHz (instead of  50MB/s -  50MHz), unsupported
    45  //
    46  // This package is only meant to be used with `GOOS=tamago GOARCH=arm` as
    47  // supported by the TamaGo framework for bare metal Go on ARM SoCs, see
    48  // https://github.com/f-secure-foundry/tamago.
    49  package usdhc
    50  
    51  import (
    52  	"errors"
    53  	"fmt"
    54  	"sync"
    55  	"time"
    56  
    57  	"github.com/f-secure-foundry/tamago/bits"
    58  	"github.com/f-secure-foundry/tamago/dma"
    59  	"github.com/f-secure-foundry/tamago/internal/reg"
    60  	"github.com/f-secure-foundry/tamago/soc/imx6"
    61  )
    62  
    63  // USDHC registers (p4012, 58.8 uSDHC Memory Map/Register Definition, IMX6ULLRM).
    64  const (
    65  	USDHC1_BASE = 0x02190000
    66  	USDHC2_BASE = 0x02194000
    67  
    68  	USDHCx_BLK_ATT  = 0x04
    69  	BLK_ATT_BLKCNT  = 16
    70  	BLK_ATT_BLKSIZE = 0
    71  
    72  	USDHCx_CMD_ARG = 0x08
    73  
    74  	USDHCx_CMD_XFR_TYP = 0x0c
    75  	CMD_XFR_TYP_CMDINX = 24
    76  	CMD_XFR_TYP_CMDTYP = 22
    77  	CMD_XFR_TYP_DPSEL  = 21
    78  	CMD_XFR_TYP_CICEN  = 20
    79  	CMD_XFR_TYP_CCCEN  = 19
    80  	CMD_XFR_TYP_RSPTYP = 16
    81  
    82  	USDHCx_CMD_RSP0 = 0x10
    83  	USDHCx_CMD_RSP1 = 0x14
    84  	USDHCx_CMD_RSP2 = 0x18
    85  	USDHCx_CMD_RSP3 = 0x1c
    86  
    87  	USDHCx_PRES_STATE = 0x24
    88  	PRES_STATE_DLSL   = 24
    89  	PRES_STATE_WPSPL  = 19
    90  	PRES_STATE_BREN   = 11
    91  	PRES_STATE_SDSTB  = 3
    92  	PRES_STATE_CDIHB  = 1
    93  	PRES_STATE_CIHB   = 0
    94  
    95  	USDHCx_PROT_CTRL = 0x28
    96  	PROT_CTRL_DMASEL = 8
    97  	PROT_CTRL_EMODE  = 4
    98  	PROT_CTRL_DTW    = 1
    99  
   100  	USDHCx_SYS_CTRL  = 0x2c
   101  	SYS_CTRL_INITA   = 27
   102  	SYS_CTRL_RSTD    = 26
   103  	SYS_CTRL_RSTC    = 25
   104  	SYS_CTRL_RSTA    = 24
   105  	SYS_CTRL_DTOCV   = 16
   106  	SYS_CTRL_SDCLKFS = 8
   107  	SYS_CTRL_DVS     = 4
   108  
   109  	USDHCx_INT_STATUS = 0x30
   110  	INT_STATUS_DMAE   = 28
   111  	INT_STATUS_TNE    = 26
   112  	INT_STATUS_AC12E  = 24
   113  	INT_STATUS_CIE    = 19
   114  	INT_STATUS_CEBE   = 18
   115  	INT_STATUS_CCE    = 17
   116  	INT_STATUS_CTOE   = 16
   117  	INT_STATUS_CRM    = 7
   118  	INT_STATUS_BRR    = 5
   119  	INT_STATUS_TC     = 1
   120  	INT_STATUS_CC     = 0
   121  
   122  	USDHCx_INT_STATUS_EN  = 0x34
   123  	INT_STATUS_EN_DTOESEN = 20
   124  	INT_STATUS_EN_BWRSEN  = 4
   125  
   126  	USDHCx_INT_SIGNAL_EN = 0x38
   127  	INT_SIGNAL_EN_BWRIEN = 4
   128  
   129  	USDHCx_AUTOCMD12_ERR_STATUS      = 0x3c
   130  	AUTOCMD12_ERR_STATUS_SMP_CLK_SEL = 23
   131  	AUTOCMD12_ERR_STATUS_EXE_TUNE    = 22
   132  
   133  	USDHCx_WTMK_LVL = 0x44
   134  	WTMK_LVL_WR_WML = 16
   135  	WTMK_LVL_RD_WML = 0
   136  
   137  	USDHCx_MIX_CTRL       = 0x48
   138  	MIX_CTRL_FBCLK_SEL    = 25
   139  	MIX_CTRL_AUTO_TUNE_EN = 24
   140  	MIX_CTRL_SMP_CLK_SEL  = 23
   141  	MIX_CTRL_EXE_TUNE     = 22
   142  	MIX_CTRL_MSBSEL       = 5
   143  	MIX_CTRL_DTDSEL       = 4
   144  	MIX_CTRL_DDR_EN       = 3
   145  	MIX_CTRL_AC12EN       = 2
   146  	MIX_CTRL_BCEN         = 1
   147  	MIX_CTRL_DMAEN        = 0
   148  
   149  	USDHCx_ADMA_ERR_STATUS = 0x54
   150  	USDHCx_ADMA_SYS_ADDR   = 0x58
   151  
   152  	USDHCx_VEND_SPEC       = 0xc0
   153  	VEND_SPEC_FRC_SDCLK_ON = 8
   154  	VEND_SPEC_VSELECT      = 1
   155  
   156  	USDHCx_VEND_SPEC2         = 0xc8
   157  	VEND_SPEC2_TUNING_1bit_EN = 5
   158  	VEND_SPEC2_TUNING_8bit_EN = 4
   159  
   160  	USDHCx_TUNING_CTRL           = 0xcc
   161  	TUNING_CTRL_STD_TUNING_EN    = 24
   162  	TUNING_CTRL_TUNING_STEP      = 16
   163  	TUNING_CTRL_TUNING_START_TAP = 0
   164  )
   165  
   166  // Configuration constants (p348, 35.4.2 Frequency divider configuration,
   167  // IMX6FG) to support the following frequencies:
   168  //   * Identification frequency ≤ 400 KHz
   169  //   * Operating frequency ≤ 25 MHz
   170  //   * High frequency ≤ 50 MHz
   171  const (
   172  	// p346, 35.2 Clocks, IMX6FG.
   173  	//
   174  	// The root clock is derived by default from PLL2 PFD2 (396MHz) with divide
   175  	// by 2, therefore 198MHz.
   176  
   177  	// Data Timeout Counter Value: SDCLK x 2** 29
   178  	DTOCV = 0xf
   179  
   180  	// Divide-by-8
   181  	DVS_ID = 7
   182  	// Root clock divided by 64
   183  	SDCLKFS_ID = 0x20
   184  	// Identification frequency: 198 / (8 * 64) == ~400 KHz
   185  
   186  	// Divide-by-2
   187  	DVS_OP = 1
   188  	// Root clock divided by 4
   189  	SDCLKFS_OP = 0x02
   190  	// Operating frequency: 198 / (2 * 4) == 24.75 MHz
   191  
   192  	// PLL2 PFD2 clock divided by 2
   193  	ROOTCLK_HS_SDR = 1
   194  	// Root clock frequency: 396 MHz / (1 + 1) = 198 MHz
   195  
   196  	// Divide-by-1
   197  	DVS_HS = 0
   198  	// Root clock divided by 4 (Single Data Rate mode)
   199  	SDCLKFS_HS_SDR = 0x02
   200  	// Root clock divided by 4 (Dual Data Rate mode)
   201  	SDCLKFS_HS_DDR = 0x01
   202  	// High Speed frequency: 198 / (1 * 4) == 49.5 MHz
   203  )
   204  
   205  // CardInfo holds detected card information.
   206  type CardInfo struct {
   207  	// eMMC card
   208  	MMC bool
   209  	// SD card
   210  	SD bool
   211  	// High Capacity
   212  	HC bool
   213  	// High Speed
   214  	HS bool
   215  	// Dual Data Rate
   216  	DDR bool
   217  	// Maximum throughput (on this controller)
   218  	Rate int
   219  
   220  	// Block Size
   221  	BlockSize int
   222  	// Capacity
   223  	Blocks int
   224  
   225  	// device identification number
   226  	CID [16]byte
   227  }
   228  
   229  // USDHC represents a controller instance.
   230  type USDHC struct {
   231  	sync.Mutex
   232  
   233  	// LowVoltage is the board specific function responsible for voltage
   234  	// switching (SD) or low voltage indication (eMMC).
   235  	//
   236  	// The return value reflects whether the voltage switch (SD) or
   237  	// low voltage indication (MMC) is successful.
   238  	LowVoltage func(enable bool) bool
   239  
   240  	// controller index
   241  	n int
   242  	// bus width
   243  	width int
   244  	// clock gate
   245  	cg int
   246  	// Relative Card Address
   247  	rca uint32
   248  
   249  	// control registers
   250  	blk_att         uint32
   251  	wtmk_lvl        uint32
   252  	cmd_arg         uint32
   253  	cmd_xfr         uint32
   254  	cmd_rsp         uint32
   255  	prot_ctrl       uint32
   256  	sys_ctrl        uint32
   257  	mix_ctrl        uint32
   258  	pres_state      uint32
   259  	int_status      uint32
   260  	int_status_en   uint32
   261  	int_signal_en   uint32
   262  	adma_sys_addr   uint32
   263  	adma_err_status uint32
   264  	ac12_err_status uint32
   265  	vend_spec       uint32
   266  	vend_spec2      uint32
   267  	tuning_ctrl     uint32
   268  
   269  	// detected card properties
   270  	card CardInfo
   271  
   272  	// eMMC Replay Protected Memory Block (RPMB) operation
   273  	rpmb bool
   274  
   275  	readTimeout  time.Duration
   276  	writeTimeout time.Duration
   277  }
   278  
   279  // USDHC1 instance
   280  var USDHC1 = &USDHC{n: 1}
   281  
   282  // USDHC2 instance
   283  var USDHC2 = &USDHC{n: 2}
   284  
   285  // getRootClock returns the USDHCx_CLK_ROOT clock by reading CSCMR1[USDHCx_CLK_SEL]
   286  // and CSCDR1[USDHCx_PODF]
   287  // (p629, Figure 18-2. Clock Tree - Part 1, IMX6ULLRM)
   288  func (hw *USDHC) getRootClock() (podf uint32, sel uint32, clock uint32) {
   289  	var podf_pos int
   290  	var clksel_pos int
   291  	var freq uint32
   292  
   293  	switch hw.n {
   294  	case 1:
   295  		podf_pos = imx6.CSCDR1_USDHC1_CLK_PODF
   296  		clksel_pos = imx6.CSCMR1_USDHC1_CLK_SEL
   297  	case 2:
   298  		podf_pos = imx6.CSCDR1_USDHC2_CLK_PODF
   299  		clksel_pos = imx6.CSCMR1_USDHC2_CLK_SEL
   300  	default:
   301  		return
   302  	}
   303  
   304  	podf = reg.Get(imx6.CCM_CSCDR1, podf_pos, 0b111)
   305  	sel = reg.Get(imx6.CCM_CSCMR1, clksel_pos, 1)
   306  
   307  	if sel == 1 {
   308  		_, freq = imx6.GetPFD(2, 0)
   309  	} else {
   310  		_, freq = imx6.GetPFD(2, 2)
   311  	}
   312  
   313  	clock = freq / (podf + 1)
   314  
   315  	return
   316  }
   317  
   318  // setRootClock controls the USDHCx_CLK_ROOT clock by setting CSCMR1[USDHCx_CLK_SEL]
   319  // and CSCDR1[USDHCx_PODF]
   320  // (p629, Figure 18-2. Clock Tree - Part 1, IMX6ULLRM).
   321  func (hw *USDHC) setRootClock(podf uint32, sel uint32) (err error) {
   322  	var podf_pos int
   323  	var clksel_pos int
   324  
   325  	if podf < 0 || podf > 7 {
   326  		return errors.New("podf value out of range")
   327  	}
   328  
   329  	if sel < 0 || sel > 1 {
   330  		return errors.New("selector value out of range")
   331  	}
   332  
   333  	switch hw.n {
   334  	case 1:
   335  		podf_pos = imx6.CSCDR1_USDHC1_CLK_PODF
   336  		clksel_pos = imx6.CSCMR1_USDHC1_CLK_SEL
   337  	case 2:
   338  		podf_pos = imx6.CSCDR1_USDHC2_CLK_PODF
   339  		clksel_pos = imx6.CSCMR1_USDHC2_CLK_SEL
   340  	default:
   341  		return errors.New("invalid interface index")
   342  	}
   343  
   344  	reg.SetN(imx6.CCM_CSCDR1, podf_pos, 0b111, podf)
   345  	reg.SetN(imx6.CCM_CSCMR1, clksel_pos, 1, sel)
   346  
   347  	return
   348  }
   349  
   350  // setClock controls the clock of USDHCx_CLK line by setting
   351  // the SDCLKFS and DVS fields of USDHCx_SYS_CTRL register
   352  // p4035, 58.8.12 System Control (uSDHCx_SYS_CTRL), IMX6ULLRM.
   353  func (hw *USDHC) setClock(dvs int, sdclkfs int) {
   354  	// Prevent possible glitch on the card clock as noted in
   355  	// p4011, 58.7.7 Change Clock Frequency, IMX6ULLRM.
   356  	reg.Clear(hw.vend_spec, VEND_SPEC_FRC_SDCLK_ON)
   357  
   358  	if dvs < 0 && sdclkfs < 0 {
   359  		return
   360  	}
   361  
   362  	// Wait for stable clock as noted in
   363  	// p4038, DVS[3:0], IMX6ULLRM.
   364  	reg.Wait(hw.pres_state, PRES_STATE_SDSTB, 1, 1)
   365  
   366  	sys := reg.Read(hw.sys_ctrl)
   367  
   368  	// p348, 35.4.2 Frequency divider configuration, IMX6FG
   369  	bits.SetN(&sys, SYS_CTRL_DVS, 0xf, uint32(dvs))
   370  	bits.SetN(&sys, SYS_CTRL_SDCLKFS, 0xff, uint32(sdclkfs))
   371  
   372  	reg.Write(hw.sys_ctrl, sys)
   373  	reg.Wait(hw.pres_state, PRES_STATE_SDSTB, 1, 1)
   374  
   375  	if hw.card.SD {
   376  		reg.Set(hw.vend_spec, VEND_SPEC_FRC_SDCLK_ON)
   377  	}
   378  }
   379  
   380  // executeTuning performs the bus tuning, `cmd` should be set to the relevant
   381  // send tuning block command index, `blocks` represents the number of tuning
   382  // blocks.
   383  func (hw *USDHC) executeTuning(index uint32, blocks uint32) error {
   384  	reg.SetN(hw.tuning_ctrl, TUNING_CTRL_TUNING_STEP, 0b111, TUNING_STEP)
   385  	reg.SetN(hw.tuning_ctrl, TUNING_CTRL_TUNING_START_TAP, 0xff, TUNING_START_TAP)
   386  	reg.Set(hw.tuning_ctrl, TUNING_CTRL_STD_TUNING_EN)
   387  
   388  	reg.Clear(hw.ac12_err_status, AUTOCMD12_ERR_STATUS_SMP_CLK_SEL)
   389  	reg.Set(hw.ac12_err_status, AUTOCMD12_ERR_STATUS_EXE_TUNE)
   390  
   391  	reg.Set(hw.mix_ctrl, MIX_CTRL_FBCLK_SEL)
   392  	reg.Set(hw.mix_ctrl, MIX_CTRL_AUTO_TUNE_EN)
   393  
   394  	// temporarily disable all interrupts other than Buffer Read Ready
   395  	defer reg.Write(hw.int_signal_en, reg.Read(hw.int_signal_en))
   396  	defer reg.Write(hw.int_status_en, reg.Read(hw.int_status_en))
   397  	reg.Write(hw.int_signal_en, INT_SIGNAL_EN_BWRIEN)
   398  	reg.Write(hw.int_status_en, INT_STATUS_EN_BWRSEN)
   399  
   400  	// temporarily lower read timeout for faster tuning
   401  	defer func(d time.Duration) {
   402  		hw.readTimeout = d
   403  	}(hw.readTimeout)
   404  	hw.readTimeout = 1 * time.Millisecond
   405  
   406  	tuning_block := make([]byte, blocks)
   407  
   408  	for i := 0; i < TUNING_MAX_LOOP_COUNT; i++ {
   409  		// send tuning block command, ignore responses
   410  		hw.transfer(index, READ, 0, 1, blocks, tuning_block)
   411  
   412  		ac12_err_status := reg.Read(hw.ac12_err_status)
   413  
   414  		if bits.Get(&ac12_err_status, AUTOCMD12_ERR_STATUS_EXE_TUNE, 1) == 0 &&
   415  			bits.Get(&ac12_err_status, AUTOCMD12_ERR_STATUS_SMP_CLK_SEL, 1) == 1 {
   416  			return nil
   417  		}
   418  	}
   419  
   420  	return errors.New("tuning failed")
   421  }
   422  
   423  // Info returns detected card information.
   424  func (hw *USDHC) Info() CardInfo {
   425  	return hw.card
   426  }
   427  
   428  // Init initializes the uSDHC controller instance.
   429  func (hw *USDHC) Init(width int) {
   430  	var base uint32
   431  
   432  	hw.Lock()
   433  
   434  	switch hw.n {
   435  	case 1:
   436  		base = USDHC1_BASE
   437  		hw.cg = imx6.CCGRx_CG1
   438  	case 2:
   439  		base = USDHC2_BASE
   440  		hw.cg = imx6.CCGRx_CG2
   441  	default:
   442  		panic("invalid uSDHC controller instance")
   443  	}
   444  
   445  	hw.width = width
   446  	hw.blk_att = base + USDHCx_BLK_ATT
   447  	hw.wtmk_lvl = base + USDHCx_WTMK_LVL
   448  	hw.cmd_arg = base + USDHCx_CMD_ARG
   449  	hw.cmd_xfr = base + USDHCx_CMD_XFR_TYP
   450  	hw.cmd_rsp = base + USDHCx_CMD_RSP0
   451  	hw.prot_ctrl = base + USDHCx_PROT_CTRL
   452  	hw.sys_ctrl = base + USDHCx_SYS_CTRL
   453  	hw.mix_ctrl = base + USDHCx_MIX_CTRL
   454  	hw.pres_state = base + USDHCx_PRES_STATE
   455  	hw.int_status = base + USDHCx_INT_STATUS
   456  	hw.int_status_en = base + USDHCx_INT_STATUS_EN
   457  	hw.int_signal_en = base + USDHCx_INT_SIGNAL_EN
   458  	hw.adma_sys_addr = base + USDHCx_ADMA_SYS_ADDR
   459  	hw.adma_err_status = base + USDHCx_ADMA_ERR_STATUS
   460  	hw.ac12_err_status = base + USDHCx_AUTOCMD12_ERR_STATUS
   461  	hw.vend_spec = base + USDHCx_VEND_SPEC
   462  	hw.vend_spec2 = base + USDHCx_VEND_SPEC2
   463  	hw.tuning_ctrl = base + USDHCx_TUNING_CTRL
   464  
   465  	// Generic SD specs read/write timeout rules (applied also to MMC by
   466  	// this driver).
   467  	//
   468  	// p106, 4.6.2.1 Read, SD-PL-7.10
   469  	hw.readTimeout = 100 * time.Millisecond
   470  	// p106, 4.6.2.2 Write, SD-PL-7.10
   471  	hw.writeTimeout = 500 * time.Millisecond
   472  
   473  	// enable clock
   474  	reg.SetN(imx6.CCM_CCGR6, hw.cg, 0b11, 0b11)
   475  
   476  	hw.Unlock()
   477  }
   478  
   479  // Detect initializes an SD/MMC card. The highest speed supported by the
   480  // driver, card and controller is automatically selected. Speed modes that
   481  // require voltage switching require definition of function VoltageSelect on
   482  // the USDHC instance, which is up to board packages.
   483  func (hw *USDHC) Detect() (err error) {
   484  	hw.Lock()
   485  	defer hw.Unlock()
   486  
   487  	if hw.cg == 0 {
   488  		return errors.New("controller is not initialized")
   489  	}
   490  
   491  	// check if a card has already been detected and not removed since
   492  	if reg.Get(hw.int_status, INT_STATUS_CRM, 1) == 0 && (hw.card.MMC || hw.card.SD) {
   493  		return
   494  	}
   495  
   496  	// clear card information
   497  	hw.card = CardInfo{}
   498  
   499  	// soft reset uSDHC
   500  	reg.Set(hw.sys_ctrl, SYS_CTRL_RSTA)
   501  	reg.Wait(hw.sys_ctrl, SYS_CTRL_RSTA, 1, 0)
   502  
   503  	// A soft reset fails to clear MIX_CTRL register, clear it all except
   504  	// tuning bits.
   505  	mix := reg.Read(hw.mix_ctrl)
   506  	bits.Clear(&mix, MIX_CTRL_FBCLK_SEL)
   507  	bits.Clear(&mix, MIX_CTRL_AUTO_TUNE_EN)
   508  	bits.Clear(&mix, MIX_CTRL_SMP_CLK_SEL)
   509  	bits.Clear(&mix, MIX_CTRL_EXE_TUNE)
   510  	reg.Write(hw.mix_ctrl, mix)
   511  
   512  	// data transfer width, default to 1-bit mode
   513  	dtw := 0b00
   514  
   515  	switch hw.width {
   516  	case 1:
   517  		dtw = 0b00
   518  	case 4:
   519  		dtw = 0b01
   520  	case 8:
   521  		dtw = 0b10
   522  	default:
   523  		return errors.New("unsupported controller data transfer width")
   524  	}
   525  
   526  	// set data transfer width
   527  	reg.SetN(hw.prot_ctrl, PROT_CTRL_DTW, 0b11, uint32(dtw))
   528  	// set little endian mode
   529  	reg.SetN(hw.prot_ctrl, PROT_CTRL_EMODE, 0b11, 0b10)
   530  
   531  	// clear clock
   532  	hw.setClock(-1, -1)
   533  	// set identification frequency
   534  	hw.setClock(DVS_ID, SDCLKFS_ID)
   535  
   536  	// set data timeout counter to SDCLK x 2^28
   537  	reg.Clear(hw.int_status_en, INT_STATUS_EN_DTOESEN)
   538  	reg.SetN(hw.sys_ctrl, SYS_CTRL_DTOCV, 0xf, DTOCV)
   539  	reg.Set(hw.int_status_en, INT_STATUS_EN_DTOESEN)
   540  
   541  	// initialize
   542  	reg.Set(hw.sys_ctrl, SYS_CTRL_INITA)
   543  	reg.Wait(hw.sys_ctrl, SYS_CTRL_INITA, 1, 0)
   544  
   545  	// CMD0 - GO_IDLE_STATE - reset card
   546  	if err = hw.cmd(0, GO_IDLE_STATE, 0, 0); err != nil {
   547  		return
   548  	}
   549  
   550  	if hw.voltageValidationSD() {
   551  		err = hw.initSD()
   552  	} else if hw.voltageValidationMMC() {
   553  		err = hw.initMMC()
   554  	} else {
   555  		return fmt.Errorf("no card detected on uSDHC%d", hw.n)
   556  	}
   557  
   558  	if err != nil {
   559  		return
   560  	}
   561  
   562  	if !hw.card.DDR {
   563  		// CMD16 - SET_BLOCKLEN - define the block length,
   564  		// only legal In single data rate mode.
   565  		err = hw.cmd(16, uint32(hw.card.BlockSize), 0, 0)
   566  	}
   567  
   568  	return
   569  }
   570  
   571  // transfer data from/to the card as specified in:
   572  //   p347, 35.5.1 Reading data from the card, IMX6FG,
   573  //   p354, 35.5.2 Writing data to the card, IMX6FG.
   574  func (hw *USDHC) transfer(index uint32, dtd uint32, arg uint64, blocks uint32, blockSize uint32, buf []byte) (err error) {
   575  	var timeout time.Duration
   576  
   577  	if hw.cg == 0 {
   578  		return errors.New("controller is not initialized")
   579  	}
   580  
   581  	if blocks == 0 || blockSize == 0 {
   582  		return
   583  	}
   584  
   585  	if (blocks & 0xffff) > 0xffff {
   586  		return errors.New("transfer size cannot exceed 65535 blocks")
   587  	}
   588  
   589  	// State polling cannot be issued while tuning (CMD19 and CMD21).
   590  	if !(index == 19 || index == 21) {
   591  		if err = hw.waitState(CURRENT_STATE_TRAN, 1*time.Millisecond); err != nil {
   592  			return
   593  		}
   594  	}
   595  
   596  	// set block size
   597  	reg.SetN(hw.blk_att, BLK_ATT_BLKSIZE, 0x1fff, blockSize)
   598  	// set block count
   599  	reg.SetN(hw.blk_att, BLK_ATT_BLKCNT, 0xffff, blocks)
   600  
   601  	bufAddress := dma.Alloc(buf, 32)
   602  	defer dma.Free(bufAddress)
   603  
   604  	// ADMA2 descriptor
   605  	bd := &ADMABufferDescriptor{}
   606  	bd.Init(bufAddress, len(buf))
   607  
   608  	bdAddress := dma.Alloc(bd.Bytes(), 4)
   609  	defer dma.Free(bdAddress)
   610  
   611  	reg.Write(hw.adma_sys_addr, bdAddress)
   612  
   613  	if hw.card.HC && (index == 18 || index == 25) {
   614  		// p102, 4.3.14 Command Functional Difference in Card Capacity Types, SD-PL-7.10
   615  		arg = arg / uint64(blockSize)
   616  	}
   617  
   618  	if hw.rpmb {
   619  		err = hw.partitionAccessMMC(PARTITION_ACCESS_RPMB)
   620  
   621  		if err != nil {
   622  			return
   623  		}
   624  
   625  		// CMD23 - SET_BLOCK_COUNT - define read/write block count
   626  		if err = hw.cmd(23, blocks, 0, 0); err != nil {
   627  			return
   628  		}
   629  
   630  		defer hw.partitionAccessMMC(PARTITION_ACCESS_NONE)
   631  	}
   632  
   633  	switch dtd {
   634  	case WRITE:
   635  		timeout = hw.writeTimeout * time.Duration(blocks)
   636  		// set write watermark level
   637  		reg.SetN(hw.wtmk_lvl, WTMK_LVL_WR_WML, 0xff, blockSize/4)
   638  	case READ:
   639  		timeout = hw.readTimeout * time.Duration(blocks)
   640  		// set read watermark level
   641  		reg.SetN(hw.wtmk_lvl, WTMK_LVL_RD_WML, 0xff, blockSize/4)
   642  	}
   643  
   644  	err = hw.cmd(index, uint32(arg), blocks, timeout)
   645  	adma_err := reg.Read(hw.adma_err_status)
   646  
   647  	if err != nil {
   648  		return fmt.Errorf("len:%d arg:%#x timeout:%v ADMA:%#x, %v", len(buf), arg, timeout, adma_err, err)
   649  	}
   650  
   651  	if adma_err > 0 {
   652  		return fmt.Errorf("len:%d arg:%#x timeout:%v ADMA:%#x", len(buf), arg, timeout, adma_err)
   653  	}
   654  
   655  	if dtd == READ {
   656  		dma.Read(bufAddress, 0, buf)
   657  	}
   658  
   659  	return
   660  }
   661  
   662  func (hw *USDHC) transferBlocks(index uint32, dtd uint32, lba int, buf []byte) (err error) {
   663  	blockSize := hw.card.BlockSize
   664  	offset := uint64(lba) * uint64(blockSize)
   665  	size := len(buf)
   666  
   667  	if size == 0 || blockSize == 0 {
   668  		return
   669  	}
   670  
   671  	if size%blockSize != 0 {
   672  		return fmt.Errorf("write size must be %d bytes aligned", blockSize)
   673  	}
   674  
   675  	blocks := size / blockSize
   676  
   677  	hw.Lock()
   678  	defer hw.Unlock()
   679  
   680  	return hw.transfer(index, dtd, offset, uint32(blocks), uint32(blockSize), buf)
   681  }
   682  
   683  // WriteBlocks transfers full blocks of data to the card.
   684  func (hw *USDHC) WriteBlocks(lba int, buf []byte) (err error) {
   685  	// CMD25 - WRITE_MULTIPLE_BLOCK - write consecutive blocks
   686  	return hw.transferBlocks(25, WRITE, lba, buf)
   687  }
   688  
   689  // ReadBlocks transfers full blocks of data from the card.
   690  func (hw *USDHC) ReadBlocks(lba int, buf []byte) (err error) {
   691  	// CMD18 - READ_MULTIPLE_BLOCK - read consecutive blocks
   692  	return hw.transferBlocks(18, READ, lba, buf)
   693  }
   694  
   695  // Read transfers data from the card.
   696  func (hw *USDHC) Read(offset int64, size int64) (buf []byte, err error) {
   697  	blockSize := int64(hw.card.BlockSize)
   698  
   699  	if size == 0 || blockSize == 0 {
   700  		return
   701  	}
   702  
   703  	blockOffset := offset % blockSize
   704  	blocks := (blockOffset + size) / blockSize
   705  
   706  	if blocks == 0 {
   707  		blocks = 1
   708  	} else if (offset+size)%blockSize != 0 {
   709  		blocks += 1
   710  	}
   711  
   712  	bufSize := int(blocks * blockSize)
   713  
   714  	// data buffer
   715  	buf = make([]byte, bufSize)
   716  
   717  	hw.Lock()
   718  	defer hw.Unlock()
   719  
   720  	// CMD18 - READ_MULTIPLE_BLOCK - read consecutive blocks
   721  	err = hw.transfer(18, READ, uint64(offset), uint32(blocks), uint32(blockSize), buf)
   722  
   723  	if err != nil {
   724  		return
   725  	}
   726  
   727  	trim := size % blockSize
   728  
   729  	if hw.card.HC {
   730  		if blockOffset != 0 || trim > 0 {
   731  			buf = buf[blockOffset : blockOffset+size]
   732  		}
   733  	} else if trim > 0 {
   734  		buf = buf[:offset+size]
   735  	}
   736  
   737  	return
   738  }