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 }