github.com/f-secure-foundry/tamago@v0.0.0-20220307101044-d73fcdd7f11b/soc/imx6/usdhc/sd.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
    13  
    14  import (
    15  	"encoding/binary"
    16  	"errors"
    17  	"fmt"
    18  	"time"
    19  
    20  	"github.com/f-secure-foundry/tamago/bits"
    21  	"github.com/f-secure-foundry/tamago/internal/reg"
    22  )
    23  
    24  // SD registers
    25  const (
    26  	// p101, 4.3.13 Send Interface Condition Command (CMD8), SD-PL-7.10
    27  	CMD8_ARG_VHS           = 8
    28  	CMD8_ARG_CHECK_PATTERN = 0
    29  
    30  	VHS_HIGH      = 0b0001
    31  	VHS_LOW       = 0b0010
    32  	CHECK_PATTERN = 0b10101010
    33  
    34  	// p59, 4.2.3.1 Initialization Command (ACMD41), SD-PL-7.10
    35  	// p198, 5.1 OCR register, SD-PL-7.10
    36  	SD_OCR_BUSY       = 31
    37  	SD_OCR_HCS        = 30
    38  	SD_OCR_UHSII      = 29
    39  	SD_OCR_XPC        = 28
    40  	SD_OCR_S18R       = 24
    41  	SD_OCR_VDD_HV_MAX = 23
    42  	SD_OCR_VDD_HV_MIN = 15
    43  	SD_OCR_VDD_LV     = 7
    44  
    45  	// p120, Table 4-32 : Switch Function Commands (class 10), SD-PL-7.10
    46  	SD_SWITCH_MODE = 31
    47  	// p92, Table 4-11 : Available Functions of CMD6, SD-PL-7.10
    48  	SD_SWITCH_POWER_LIMIT_GROUP = 4
    49  	SD_SWITCH_ACCESS_MODE_GROUP = 1
    50  	// p95, 4.3.10.4 Switch Function Status, SD-PL-7.10
    51  	SD_SWITCH_STATUS_LENGTH = 64
    52  
    53  	// p89, 4.3.10 Switch Function Command, SD-PL-7.10
    54  	MODE_CHECK         = 0
    55  	MODE_SWITCH        = 1
    56  	ACCESS_MODE_HS     = 0x1
    57  	ACCESS_MODE_SDR50  = 0x2
    58  	ACCESS_MODE_SDR104 = 0x3
    59  	POWER_LIMIT_288W   = 0x3
    60  
    61  	// p201 5.3.1 CSD_STRUCTURE, SD-PL-7.10
    62  	SD_CSD_STRUCTURE = 126 + CSD_RSP_OFF
    63  
    64  	// p202 5.3.2 CSD Register (CSD Version 1.0), SD-PL-7.10
    65  	SD_CSD_C_SIZE_MULT_1 = 47 + CSD_RSP_OFF
    66  	SD_CSD_C_SIZE_1      = 62 + CSD_RSP_OFF
    67  	SD_CSD_READ_BL_LEN_1 = 80 + CSD_RSP_OFF
    68  
    69  	// p209 5.3.3 CSD Register (CSD Version 2.0), SD-PL-7.10
    70  	SD_CSD_C_SIZE_2      = 48 + CSD_RSP_OFF
    71  	SD_CSD_READ_BL_LEN_2 = 80 + CSD_RSP_OFF
    72  
    73  	// p212 5.3.4 CSD Register (CSD Version 3.0), SD-PL-7.10
    74  	SD_CSD_C_SIZE_3      = 48 + CSD_RSP_OFF
    75  	SD_CSD_READ_BL_LEN_3 = 80 + CSD_RSP_OFF
    76  
    77  	// p23, 2. System Features, SD-PL-7.10
    78  	HS_MBPS     = 25
    79  	SDR50_MBPS  = 50
    80  	SDR104_MBPS = 75 // instead of 104 due to NXP ERR010450
    81  
    82  	// PLL2 PFD2 clock divided by 2
    83  	ROOTCLK_UHS_SDR50 = 1
    84  	// Root clock frequency: 396 MHz / (1 + 1) = 198 MHz
    85  
    86  	// PLL2 PFD2 clock divided by 3
    87  	ROOTCLK_UHS_SDR104 = 2 // instead of 1 due to NXP ERR010450
    88  	// Root clock frequency: 396 MHz / (1 + 2) = 132 MHz
    89  
    90  	// Root clock divided by 2 (Single Data Rate mode)
    91  	SDCLKFS_UHS_SDR50 = 0x01
    92  	// SDR50 frequency: 198 / (1 * 2) == 99 MHz
    93  
    94  	// Root clock divided by 1 (Single Data Rate mode)
    95  	SDCLKFS_UHS_SDR104 = 0
    96  	// SDR104 frequency: 132 / (1 * 1) == 132 MHz
    97  )
    98  
    99  // SD constants
   100  const (
   101  	SD_DETECT_TIMEOUT     = 1 * time.Second
   102  	SD_DEFAULT_BLOCK_SIZE = 512
   103  
   104  	// Tuning should complete in max 40 cycles
   105  	// p42, 4.2.4.5 Tuning Command, SD-PL-7.10
   106  	TUNING_MAX_LOOP_COUNT = 40
   107  
   108  	// The following values are set to make the standard tuning logic
   109  	// complete in less then 40 cycles.
   110  	TUNING_STEP      = 2
   111  	TUNING_START_TAP = 20
   112  )
   113  
   114  func (hw *USDHC) switchSD(mode uint32, group int, val uint32) (status []byte, err error) {
   115  	var arg uint32
   116  
   117  	// set `no influence` (0xf) for all function groups
   118  	arg = 0x00ffffff
   119  	// set mode check
   120  	bits.SetN(&arg, SD_SWITCH_MODE, 1, mode)
   121  	// set function group
   122  	bits.SetN(&arg, (group-1)*4, 0xf, val)
   123  
   124  	status = make([]byte, SD_SWITCH_STATUS_LENGTH)
   125  
   126  	// CMD6 - SWITCH - switch mode of operation
   127  	if err = hw.transfer(6, READ, uint64(arg), 1, SD_SWITCH_STATUS_LENGTH, status); err != nil {
   128  		return
   129  	}
   130  
   131  	err = hw.waitState(CURRENT_STATE_TRAN, 500*time.Millisecond)
   132  
   133  	if err != nil {
   134  		return
   135  	}
   136  
   137  	if (hw.rsp(0)>>STATUS_SWITCH_ERROR)&1 != 0 {
   138  		err = errors.New("switch error")
   139  	}
   140  
   141  	return
   142  }
   143  
   144  func (hw *USDHC) executeTuningSD() error {
   145  	return hw.executeTuning(19, 64)
   146  }
   147  
   148  // p350, 35.4.4 SD voltage validation flow chart, IMX6FG
   149  func (hw *USDHC) voltageValidationSD() bool {
   150  	var arg uint32
   151  	var hv bool
   152  
   153  	// ensure 3.3V signaling
   154  	if hw.LowVoltage != nil {
   155  		hw.LowVoltage(false)
   156  	}
   157  
   158  	// CMD8 - SEND_IF_COND - read device data
   159  	// p101, 4.3.13 Send Interface Condition Command (CMD8), SD-PL-7.10
   160  
   161  	bits.SetN(&arg, CMD8_ARG_VHS, 0b1111, VHS_HIGH)
   162  	bits.SetN(&arg, CMD8_ARG_CHECK_PATTERN, 0xff, CHECK_PATTERN)
   163  
   164  	if hw.cmd(8, arg, 0, 0) == nil && hw.rsp(0) == arg {
   165  		// HC/LC HV SD 2.x
   166  		hw.card.HC = true
   167  		hv = true
   168  	} else {
   169  		arg = VHS_LOW<<CMD8_ARG_VHS | CHECK_PATTERN
   170  
   171  		if hw.cmd(8, arg, 0, 0) == nil && hw.rsp(0) == arg {
   172  			// LC SD 1.x
   173  			hw.card.HC = true
   174  		} else {
   175  			// LC SD 2.x
   176  			hv = true
   177  		}
   178  	}
   179  
   180  	// ACMD41 - SD_SEND_OP_COND - read capacity information
   181  	// p59, 4.2.3.1 Initialization Command (ACMD41), SD-PL-7.10
   182  	//
   183  	// The ACMD41 full argument is the OCR, despite the standard
   184  	// confusingly naming OCR only bits 23-08 of it (which instead
   185  	// represents part of OCR register voltage window).
   186  	arg = 0
   187  
   188  	if hw.card.HC {
   189  		// SDHC or SDXC supported
   190  		bits.Set(&arg, SD_OCR_HCS)
   191  		// Maximum Performance
   192  		bits.Set(&arg, SD_OCR_XPC)
   193  		// Switch to 1.8V (only check acceptance for speed detection)
   194  		bits.Set(&arg, SD_OCR_S18R)
   195  	}
   196  
   197  	if hv {
   198  		// set HV range
   199  		bits.SetN(&arg, SD_OCR_VDD_HV_MIN, 0x1ff, 0x1ff)
   200  	} else {
   201  		bits.Set(&arg, SD_OCR_VDD_LV)
   202  	}
   203  
   204  	start := time.Now()
   205  
   206  	for time.Since(start) <= SD_DETECT_TIMEOUT {
   207  		// CMD55 - APP_CMD - next command is application specific
   208  		if hw.cmd(55, 0, 0, 0) != nil {
   209  			break
   210  		}
   211  
   212  		// ACMD41 - SD_SEND_OP_COND - send operating conditions
   213  		if err := hw.cmd(41, arg, 0, 0); err != nil {
   214  			break
   215  		}
   216  
   217  		rsp := hw.rsp(0)
   218  
   219  		if bits.Get(&rsp, SD_OCR_BUSY, 1) == 0 {
   220  			continue
   221  		}
   222  
   223  		if bits.Get(&rsp, SD_OCR_HCS, 1) == 1 {
   224  			hw.card.HC = true
   225  		}
   226  
   227  		// Select the fastest mandatory speed mode, supported by this
   228  		// driver, according to the card type.
   229  
   230  		if bits.Get(&rsp, SD_OCR_S18R, 1) == 1 {
   231  			// UHS-I
   232  			hw.card.Rate = SDR50_MBPS
   233  		} else if bits.Get(&rsp, SD_OCR_UHSII, 1) == 1 {
   234  			// UHS-II
   235  			hw.card.Rate = SDR50_MBPS
   236  		} else {
   237  			// Non UHS-I
   238  			hw.card.Rate = HS_MBPS
   239  		}
   240  
   241  		hw.card.SD = true
   242  
   243  		break
   244  	}
   245  
   246  	return hw.card.SD
   247  }
   248  
   249  func (hw *USDHC) detectCapabilitiesSD() (err error) {
   250  	// CMD9 - SEND_CSD - read device data
   251  	if err = hw.cmd(9, hw.rca, 0, 0); err != nil {
   252  		return
   253  	}
   254  
   255  	ver := hw.rspVal(SD_CSD_STRUCTURE, 0b11)
   256  
   257  	switch ver {
   258  	case 0:
   259  		// CSD Version 1.0
   260  		c_size_mult := hw.rspVal(SD_CSD_C_SIZE_MULT_1, 0b111)
   261  		c_size := hw.rspVal(SD_CSD_C_SIZE_1, 0xfff)
   262  		read_bl_len := hw.rspVal(SD_CSD_READ_BL_LEN_1, 0xf)
   263  
   264  		// p205, C_SIZE, SD-PL-7.10
   265  		hw.card.BlockSize = 2 << (read_bl_len - 1)
   266  		hw.card.Blocks = int((c_size + 1) * (2 << (c_size_mult + 2)))
   267  	case 1:
   268  		// CSD Version 2.0
   269  		c_size := hw.rspVal(SD_CSD_C_SIZE_2, 0x3fffff)
   270  		read_bl_len := hw.rspVal(SD_CSD_READ_BL_LEN_2, 0xf)
   271  
   272  		// p210, C_SIZE, SD-PL-7.10
   273  		hw.card.BlockSize = 2 << (read_bl_len - 1)
   274  		hw.card.Blocks = int(c_size+1) * 1024
   275  	case 2:
   276  		// CSD Version 3.0
   277  		c_size := hw.rspVal(SD_CSD_C_SIZE_2, 0xfffffff)
   278  		read_bl_len := hw.rspVal(SD_CSD_READ_BL_LEN_2, 0xf)
   279  
   280  		// p213, C_SIZE, SD-PL-7.10
   281  		hw.card.BlockSize = 2 << (read_bl_len - 1)
   282  		hw.card.Blocks = int(c_size+1) * 1024
   283  	default:
   284  		return fmt.Errorf("unsupported CSD version %d", ver)
   285  	}
   286  
   287  	return
   288  }
   289  
   290  // p60, 4.2.4 Bus Signal Voltage Switch Sequence, SD-PL-7.10
   291  func (hw *USDHC) voltageSwitchSD() (err error) {
   292  	// CMD11 - VOLTAGE_SWITCH - switch to 1.8V signaling
   293  	if err = hw.cmd(11, 0, 0, 0); err != nil {
   294  		return
   295  	}
   296  
   297  	if !reg.WaitFor(1*time.Millisecond, hw.pres_state, PRES_STATE_DLSL, 1, 0) {
   298  		return fmt.Errorf("voltage switch failed, invalid data line")
   299  	}
   300  
   301  	hw.setClock(-1, -1)
   302  
   303  	// SoC uSDHC IO power voltage selection signal (might be unused)
   304  	reg.Set(hw.vend_spec, VEND_SPEC_VSELECT)
   305  
   306  	// board specific low voltage selection/indication function
   307  	if hw.LowVoltage != nil && !hw.LowVoltage(true) {
   308  		return errors.New("voltage switch failed, not at LV")
   309  	}
   310  
   311  	time.Sleep(10 * time.Millisecond)
   312  
   313  	hw.setClock(DVS_OP, SDCLKFS_OP)
   314  
   315  	if !reg.WaitFor(1*time.Millisecond, hw.pres_state, PRES_STATE_DLSL, 1, 1) {
   316  		return fmt.Errorf("voltage switch failed, invalid data line")
   317  	}
   318  
   319  	return
   320  }
   321  
   322  // p351, 35.4.5 SD card initialization flow chart, IMX6FG
   323  // p57, 4.2.3 Card Initialization and Identification Process, SD-PL-7.10
   324  func (hw *USDHC) initSD() (err error) {
   325  	var arg uint32
   326  	var bus_width uint32
   327  	var mode uint32
   328  	var root_clk uint32
   329  	var clk int
   330  	var tune bool
   331  
   332  	if hw.LowVoltage == nil {
   333  		hw.card.Rate = HS_MBPS
   334  	} else if hw.card.Rate >= SDR50_MBPS {
   335  		if err = hw.voltageSwitchSD(); err != nil {
   336  			hw.card.Rate = HS_MBPS
   337  		}
   338  	}
   339  
   340  	// CMD2 - ALL_SEND_CID - get unique card identification
   341  	if err = hw.cmd(2, arg, 0, 0); err != nil {
   342  		return
   343  	}
   344  
   345  	for i := 0; i < len(hw.card.CID); i += 4 {
   346  		binary.LittleEndian.PutUint32(hw.card.CID[i:], hw.rsp(i/4))
   347  	}
   348  
   349  	// CMD3 - SEND_RELATIVE_ADDR - get relative card address (RCA)
   350  	if err = hw.cmd(3, arg, 0, 0); err != nil {
   351  		return
   352  	}
   353  
   354  	if state := (hw.rsp(0) >> STATUS_CURRENT_STATE) & 0b1111; state != CURRENT_STATE_IDENT {
   355  		return fmt.Errorf("card not in ident state (%d)", state)
   356  	}
   357  
   358  	if hw.card.Rate == HS_MBPS {
   359  		hw.setClock(-1, -1)
   360  		hw.setClock(DVS_OP, SDCLKFS_OP)
   361  	}
   362  
   363  	// set relative card address
   364  	hw.rca = hw.rsp(0) & (0xffff << RCA_ADDR)
   365  
   366  	if err = hw.detectCapabilitiesSD(); err != nil {
   367  		return
   368  	}
   369  
   370  	// CMD7 - SELECT/DESELECT CARD - enter transfer state
   371  	if err = hw.cmd(7, hw.rca, 0, 0); err != nil {
   372  		return
   373  	}
   374  
   375  	if err = hw.waitState(CURRENT_STATE_TRAN, 1*time.Millisecond); err != nil {
   376  		return
   377  	}
   378  
   379  	// CMD55 - APP_CMD - next command is application specific
   380  	if err = hw.cmd(55, hw.rca, 0, 0); err != nil {
   381  		return
   382  	}
   383  
   384  	if ((hw.rsp(0) >> STATUS_APP_CMD) & 1) != 1 {
   385  		return fmt.Errorf("card not expecting application command")
   386  	}
   387  
   388  	// p118, Table 4-31, SD-PL-7.10
   389  	switch hw.width {
   390  	case 1:
   391  		bus_width = 0b00
   392  	case 4:
   393  		bus_width = 0b10
   394  	default:
   395  		return errors.New("unsupported SD bus width")
   396  	}
   397  
   398  	// ACMD6 - SET_BUS_WIDTH - define the card data bus width
   399  	if err = hw.cmd(6, uint32(bus_width), 0, 0); err != nil {
   400  		return
   401  	}
   402  
   403  	if hw.card.Rate >= SDR50_MBPS {
   404  		// Check support bits 415:400 for SDR104 mode,
   405  		// p96, 4.3.10.4 Switch Function Status, SD-PL-7.10.
   406  		if status, _ := hw.switchSD(MODE_CHECK, SD_SWITCH_ACCESS_MODE_GROUP, 0xf); status[13]&ACCESS_MODE_SDR104 != 0 {
   407  			hw.card.Rate = SDR104_MBPS
   408  		}
   409  	}
   410  
   411  	switch hw.card.Rate {
   412  	case HS_MBPS:
   413  		mode = ACCESS_MODE_HS
   414  		root_clk = ROOTCLK_HS_SDR
   415  		clk = SDCLKFS_HS_SDR
   416  	case SDR50_MBPS:
   417  		mode = ACCESS_MODE_SDR50
   418  		root_clk = ROOTCLK_UHS_SDR50
   419  		clk = SDCLKFS_UHS_SDR50
   420  		tune = true
   421  	case SDR104_MBPS:
   422  		mode = ACCESS_MODE_SDR104
   423  		root_clk = ROOTCLK_UHS_SDR104
   424  		clk = SDCLKFS_UHS_SDR104
   425  		tune = true
   426  	default:
   427  		return
   428  	}
   429  
   430  	if _, err = hw.switchSD(MODE_SWITCH, SD_SWITCH_POWER_LIMIT_GROUP, POWER_LIMIT_288W); err != nil {
   431  		return
   432  	}
   433  
   434  	if _, err = hw.switchSD(MODE_SWITCH, SD_SWITCH_ACCESS_MODE_GROUP, mode); err != nil {
   435  		return
   436  	}
   437  
   438  	hw.setClock(-1, -1)
   439  	hw.setRootClock(root_clk, 0)
   440  	hw.setClock(DVS_HS, clk)
   441  
   442  	if tune {
   443  		err = hw.executeTuningSD()
   444  	}
   445  
   446  	hw.card.HS = true
   447  
   448  	return
   449  }