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 }