github.com/usbarmory/tamago@v0.0.0-20240508072735-8612bbe1e454/soc/nxp/usdhc/mmc.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
    13  
    14  import (
    15  	"encoding/binary"
    16  	"errors"
    17  	"fmt"
    18  	"time"
    19  
    20  	"github.com/usbarmory/tamago/bits"
    21  	"github.com/usbarmory/tamago/internal/reg"
    22  )
    23  
    24  // MMC registers
    25  const (
    26  	// p181, 7.1 OCR register, JESD84-B51
    27  	MMC_OCR_BUSY        = 31
    28  	MMC_OCR_ACCESS_MODE = 29
    29  	MMC_OCR_VDD_HV_MAX  = 23
    30  	MMC_OCR_VDD_HV_MIN  = 15
    31  	MMC_OCR_VDD_LV      = 7
    32  
    33  	ACCESS_MODE_BYTE   = 0b00
    34  	ACCESS_MODE_SECTOR = 0b10
    35  
    36  	// p62, 6.6.1 Command sets and extended settings, JESD84-B51
    37  	MMC_SWITCH_ACCESS  = 24
    38  	MMC_SWITCH_INDEX   = 16
    39  	MMC_SWITCH_VALUE   = 8
    40  	MMC_SWITCH_CMD_SET = 0
    41  
    42  	ACCESS_WRITE_BYTE = 0b11
    43  
    44  	// p184 7.3 CSD register, JESD84-B51
    45  	MMC_CSD_SPEC_VERS   = 122 + CSD_RSP_OFF
    46  	MMC_CSD_TRAN_SPEED  = 96 + CSD_RSP_OFF
    47  	MMC_CSD_READ_BL_LEN = 80 + CSD_RSP_OFF
    48  	MMC_CSD_C_SIZE      = 62 + CSD_RSP_OFF
    49  	MMC_CSD_C_SIZE_MULT = 47 + CSD_RSP_OFF
    50  
    51  	// p186 TRAN_SPEED [103:96], JESD84-B51
    52  	TRAN_SPEED_26MHZ = 0x32
    53  
    54  	// p193, 7.4 Extended CSD register, JESD84-B51
    55  	EXT_CSD_SEC_COUNT        = 212
    56  	EXT_CSD_DEVICE_TYPE      = 196
    57  	EXT_CSD_HS_TIMING        = 185
    58  	EXT_CSD_BUS_WIDTH        = 183
    59  	EXT_CSD_PARTITION_CONFIG = 179
    60  
    61  	// p224, PARTITION_CONFIG, JESD84-B51
    62  	PARTITION_ACCESS_NONE = 0x0
    63  	PARTITION_ACCESS_RPMB = 0x3
    64  
    65  	// p222, 7.4.65 HS_TIMING [185], JESD84-B51
    66  	HS_TIMING_HS    = 0x1
    67  	HS_TIMING_HS200 = 0x2
    68  
    69  	// p35, 5.3.2 Bus Speed Modes, JESD84-B51
    70  	HSSDR_MBPS = 52
    71  	HSDDR_MBPS = 104
    72  	HS200_MBPS = 150 // instead of 200 due to NXP ERR010450
    73  
    74  	// PLL2 PFD2 clock divided by 2
    75  	ROOTCLK_HS_DDR = 1
    76  	// Root clock frequency: 396 MHz / (1 + 1) = 198 MHz
    77  
    78  	// PLL2 PFD2 clock divided by 3
    79  	ROOTCLK_HS200 = 2 // instead of 1 due to NXP ERR010450
    80  	// Root clock frequency: 396 MHz / (1 + 2) = 132 MHz
    81  
    82  	// Root clock divided by 1 (Single Data Rate mode)
    83  	SDCLKFS_HS200 = 0
    84  	// HS200 frequency: 132 / (1 * 1) == 132 MHz
    85  
    86  )
    87  
    88  // MMC constants
    89  const (
    90  	MMC_DETECT_TIMEOUT     = 1 * time.Second
    91  	MMC_DEFAULT_BLOCK_SIZE = 512
    92  )
    93  
    94  // p352, 35.4.6 MMC voltage validation flow chart, IMX6FG
    95  func (hw *USDHC) voltageValidationMMC() bool {
    96  	var arg uint32
    97  
    98  	// CMD1 - SEND_OP_COND
    99  	// p57, 6.4.2 Access mode validation, JESD84-B51
   100  
   101  	// sector mode supported
   102  	bits.SetN(&arg, MMC_OCR_ACCESS_MODE, 0b11, ACCESS_MODE_SECTOR)
   103  	// set HV range
   104  	bits.SetN(&arg, MMC_OCR_VDD_HV_MIN, 0x1ff, 0x1ff)
   105  
   106  	// p46, 6.3.1 Device reset to Pre-idle state, JESD84-B51
   107  	time.Sleep(1 * time.Millisecond)
   108  
   109  	start := time.Now()
   110  
   111  	for time.Since(start) <= MMC_DETECT_TIMEOUT {
   112  		// CMD1 - SEND_OP_COND - send operating conditions
   113  		if err := hw.cmd(1, arg, 0, 0); err != nil {
   114  			break
   115  		}
   116  
   117  		rsp := hw.rsp(0)
   118  
   119  		if bits.Get(&rsp, MMC_OCR_BUSY, 1) == 0 {
   120  			continue
   121  		}
   122  
   123  		if bits.Get(&rsp, MMC_OCR_ACCESS_MODE, 0b11) == ACCESS_MODE_SECTOR {
   124  			hw.card.HC = true
   125  		}
   126  
   127  		hw.card.MMC = true
   128  
   129  		break
   130  	}
   131  
   132  	return hw.card.MMC
   133  }
   134  
   135  func (hw *USDHC) writeCardRegisterMMC(reg uint32, val uint32) (err error) {
   136  	var arg uint32
   137  
   138  	// write MMC_SWITCH_VALUE in register pointed in MMC_SWITCH_INDEX
   139  	bits.SetN(&arg, MMC_SWITCH_ACCESS, 0b11, ACCESS_WRITE_BYTE)
   140  	// set MMC_SWITCH_INDEX to desired register
   141  	bits.SetN(&arg, MMC_SWITCH_INDEX, 0xff, reg)
   142  	// set register value
   143  	bits.SetN(&arg, MMC_SWITCH_VALUE, 0xff, val)
   144  
   145  	// CMD6 - SWITCH - switch mode of operation
   146  	err = hw.cmd(6, arg, 0, 0)
   147  
   148  	if err != nil {
   149  		return
   150  	}
   151  
   152  	// We could use EXT_CSD[GENERIC_CMD6_TIME] for a better tran state
   153  	// timeout, we rather choose to apply a generic timeout for now (as
   154  	// most drivers do).
   155  	err = hw.waitState(CURRENT_STATE_TRAN, 500*time.Millisecond)
   156  
   157  	if err != nil {
   158  		return
   159  	}
   160  
   161  	if (hw.rsp(0)>>STATUS_SWITCH_ERROR)&1 != 0 {
   162  		err = errors.New("switch error")
   163  	}
   164  
   165  	return
   166  }
   167  
   168  func (hw *USDHC) detectCapabilitiesMMC(c_size_mult uint32, c_size uint32, read_bl_len uint32) (err error) {
   169  	extCSD := make([]byte, MMC_DEFAULT_BLOCK_SIZE)
   170  
   171  	// CMD8 - SEND_EXT_CSD - read extended device data
   172  	if err = hw.transfer(8, READ, 0, 1, MMC_DEFAULT_BLOCK_SIZE, extCSD); err != nil {
   173  		return
   174  	}
   175  
   176  	// p128, Table 39 — e•MMC internal sizes and related Units / Granularities, JESD84-B51
   177  
   178  	// density greater than 2GB (emulation mode is always assumed)
   179  	if c_size > 0xff {
   180  		hw.card.BlockSize = MMC_DEFAULT_BLOCK_SIZE
   181  		hw.card.Blocks = int(binary.LittleEndian.Uint32(extCSD[EXT_CSD_SEC_COUNT:]))
   182  	} else {
   183  		// p188, 7.3.12 C_SIZE [73:62], JESD84-B51
   184  		hw.card.BlockSize = 2 << (read_bl_len - 1)
   185  		hw.card.Blocks = int((c_size + 1) * (2 << (c_size_mult + 2)))
   186  	}
   187  
   188  	// p220, Table 137 — Device types, JESD84-B51
   189  	deviceType := extCSD[EXT_CSD_DEVICE_TYPE]
   190  
   191  	if (deviceType>>4)&0b11 > 0 && hw.LowVoltage != nil && hw.LowVoltage(false) {
   192  		hw.card.Rate = HS200_MBPS
   193  	} else if (deviceType>>2)&0b11 > 0 {
   194  		hw.card.Rate = HSDDR_MBPS
   195  	} else if deviceType&0b11 > 0 {
   196  		hw.card.Rate = HSSDR_MBPS
   197  	}
   198  
   199  	return
   200  }
   201  
   202  func (hw *USDHC) executeTuningMMC() error {
   203  	reg.SetN(hw.vend_spec2, VEND_SPEC2_TUNING_8bit_EN, 1, 1)
   204  	return hw.executeTuning(21, 128)
   205  }
   206  
   207  // p352, 35.4.7 MMC card initialization flow chart, IMX6FG
   208  // p58, 6.4.4 Device identification process, JESD84-B51
   209  func (hw *USDHC) initMMC() (err error) {
   210  	var arg uint32
   211  	var bus_width uint32
   212  	var timing uint32
   213  	var root_clk uint32
   214  	var clk int
   215  	var ddr bool
   216  	var tune bool
   217  
   218  	// CMD2 - ALL_SEND_CID - get unique card identification
   219  	if err = hw.cmd(2, arg, 0, 0); err != nil {
   220  		return
   221  	}
   222  
   223  	for i := 0; i < len(hw.card.CID); i += 4 {
   224  		binary.LittleEndian.PutUint32(hw.card.CID[i:], hw.rsp(i/4))
   225  	}
   226  
   227  	// Send CMD3 with a chosen RCA, with value greater than 1,
   228  	// p301, A.6.1 Bus initialization , JESD84-B51.
   229  	hw.rca = (uint32(hw.Index) + 1) << RCA_ADDR
   230  
   231  	// CMD3 - SET_RELATIVE_ADDR - set relative card address (RCA),
   232  	if err = hw.cmd(3, hw.rca, 0, 0); err != nil {
   233  		return
   234  	}
   235  
   236  	if state := (hw.rsp(0) >> STATUS_CURRENT_STATE) & 0b1111; state != CURRENT_STATE_IDENT {
   237  		return fmt.Errorf("card not in ident state (%d)", state)
   238  	}
   239  
   240  	// CMD9 - SEND_CSD - read device data
   241  	if err = hw.cmd(9, hw.rca, 0, 0); err != nil {
   242  		return
   243  	}
   244  
   245  	// block count multiplier
   246  	c_size_mult := hw.rspVal(MMC_CSD_C_SIZE_MULT, 0b111)
   247  	// block count
   248  	c_size := hw.rspVal(MMC_CSD_C_SIZE, 0xfff)
   249  	// block size
   250  	read_bl_len := hw.rspVal(MMC_CSD_READ_BL_LEN, 0xf)
   251  	// operating frequency
   252  	mhz := hw.rspVal(MMC_CSD_TRAN_SPEED, 0xff)
   253  	// e•MMC specification version
   254  	ver := hw.rspVal(MMC_CSD_SPEC_VERS, 0xf)
   255  
   256  	if mhz == TRAN_SPEED_26MHZ {
   257  		// clear clock
   258  		hw.setFreq(-1, -1)
   259  		// set operating frequency
   260  		hw.setFreq(DVS_OP, SDCLKFS_OP)
   261  	} else {
   262  		return fmt.Errorf("unexpected TRAN_SPEED %#x", mhz)
   263  	}
   264  
   265  	// CMD7 - SELECT/DESELECT CARD - enter transfer state
   266  	if err = hw.cmd(7, hw.rca, 0, 0); err != nil {
   267  		return
   268  	}
   269  
   270  	err = hw.waitState(CURRENT_STATE_TRAN, 1*time.Millisecond)
   271  
   272  	if err != nil {
   273  		return
   274  	}
   275  
   276  	// p223, 7.4.67 BUS_WIDTH [183], JESD84-B51
   277  	switch hw.width {
   278  	case 4:
   279  		bus_width = 1
   280  	case 8:
   281  		bus_width = 2
   282  	default:
   283  		return errors.New("unsupported MMC bus width")
   284  	}
   285  
   286  	err = hw.writeCardRegisterMMC(EXT_CSD_BUS_WIDTH, bus_width)
   287  
   288  	if err != nil {
   289  		return
   290  	}
   291  
   292  	err = hw.detectCapabilitiesMMC(c_size_mult, c_size, read_bl_len)
   293  
   294  	if err != nil {
   295  		return
   296  	}
   297  
   298  	// Enable High Speed DDR mode only on Version 4.1 or above eMMC cards
   299  	// with supported rate.
   300  	if ver < 4 || hw.card.Rate <= HSSDR_MBPS {
   301  		return
   302  	}
   303  
   304  	switch hw.card.Rate {
   305  	case HSDDR_MBPS:
   306  		timing = HS_TIMING_HS
   307  		root_clk = ROOTCLK_HS_DDR
   308  		clk = SDCLKFS_HS_DDR
   309  		ddr = true
   310  
   311  		// p223, 7.4.67 BUS_WIDTH [183], JESD84-B51
   312  		switch hw.width {
   313  		case 4:
   314  			bus_width = 5
   315  		case 8:
   316  			bus_width = 6
   317  		}
   318  	case HS200_MBPS:
   319  		timing = HS_TIMING_HS200
   320  		root_clk = ROOTCLK_HS200
   321  		clk = SDCLKFS_HS200
   322  		tune = true
   323  	default:
   324  		return
   325  	}
   326  
   327  	// p112, Dual Data Rate mode operation, JESD84-B51
   328  	err = hw.writeCardRegisterMMC(EXT_CSD_HS_TIMING, timing)
   329  
   330  	if err != nil {
   331  		return
   332  	}
   333  
   334  	err = hw.writeCardRegisterMMC(EXT_CSD_BUS_WIDTH, bus_width)
   335  
   336  	if err != nil {
   337  		return
   338  	}
   339  
   340  	hw.setFreq(-1, -1)
   341  	hw.SetClock(hw.Index, root_clk, 0)
   342  	hw.setFreq(DVS_HS, clk)
   343  
   344  	if tune {
   345  		// FIXME: Use fixed sampling clock as eMMC tuning fails for unknown reasons.
   346  		// err = hw.executeTuningMMC()
   347  	}
   348  
   349  	hw.card.DDR = ddr
   350  	hw.card.HS = true
   351  
   352  	return
   353  }
   354  
   355  // p224, 7.4.69 PARTITION_CONFIG [179], JESD84-B51
   356  func (hw *USDHC) partitionAccessMMC(access uint32) (err error) {
   357  	return hw.writeCardRegisterMMC(EXT_CSD_PARTITION_CONFIG, access)
   358  }
   359  
   360  // p106, 6.6.22.4.3 Authenticated Data Write, JESD84-B51
   361  // p108, 6.6.22.4.4 Authenticated Data Read,  JESD84-B51
   362  func (hw *USDHC) transferRPMB(dtd int, buf []byte, rel bool) (err error) {
   363  	if !hw.card.MMC {
   364  		return fmt.Errorf("no MMC card detected on uSDHC%d", hw.Index)
   365  	}
   366  
   367  	if len(buf) != 512 {
   368  		return errors.New("transfer size must be 512")
   369  	}
   370  
   371  	blocks := uint32(1)
   372  
   373  	hw.Lock()
   374  	hw.rpmb = true
   375  
   376  	defer func() {
   377  		hw.rpmb = false
   378  		hw.Unlock()
   379  	}()
   380  
   381  	if dtd == WRITE {
   382  		if rel {
   383  			// reliable write request
   384  			bits.Set(&blocks, 31)
   385  		}
   386  
   387  		// CMD25 - WRITE_MULTIPLE_BLOCK - write consecutive blocks
   388  		err = hw.transfer(25, WRITE, 0, blocks, 512, buf)
   389  	} else {
   390  		// CMD18 - READ_MULTIPLE_BLOCK - read consecutive blocks
   391  		err = hw.transfer(18, READ, 0, blocks, 512, buf)
   392  	}
   393  
   394  	return
   395  }
   396  
   397  // WriteRPMB transfers a single Replay Protected Memory Block (RPMB) data frame
   398  // to the card. The `rel` boolean indicates whether a reliable write should be
   399  // requested (required for some RPMB transfer).
   400  func (hw *USDHC) WriteRPMB(buf []byte, rel bool) (err error) {
   401  	return hw.transferRPMB(WRITE, buf, rel)
   402  }
   403  
   404  // ReadRPMB transfers a single Replay Protected Memory Block (RPMB) data
   405  // frame from the card.
   406  func (hw *USDHC) ReadRPMB(buf []byte) (err error) {
   407  	return hw.transferRPMB(READ, buf, false)
   408  }