github.com/usbarmory/tamago@v0.0.0-20240508072735-8612bbe1e454/soc/nxp/usdhc/usdhc.go (about)

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