1 /* 2 * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <common/debug.h> 9 #include <lib/mmio.h> 10 #include <string.h> 11 #include <drivers/delay_timer.h> 12 #include <drivers/console.h> 13 14 #include "cadence_qspi.h" 15 #include <platform_def.h> 16 17 #define LESS(a, b) (((a) < (b)) ? (a) : (b)) 18 #define MORE(a, b) (((a) > (b)) ? (a) : (b)) 19 20 21 uint32_t qspi_device_size; 22 int cad_qspi_cs; 23 24 int cad_qspi_idle(void) 25 { 26 return (mmio_read_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG) 27 & CAD_QSPI_CFG_IDLE) >> 31; 28 } 29 30 int cad_qspi_set_baudrate_div(uint32_t div) 31 { 32 if (div > 0xf) 33 return CAD_INVALID; 34 35 mmio_clrsetbits_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG, 36 ~CAD_QSPI_CFG_BAUDDIV_MSK, 37 CAD_QSPI_CFG_BAUDDIV(div)); 38 39 return 0; 40 } 41 42 int cad_qspi_configure_dev_size(uint32_t addr_bytes, 43 uint32_t bytes_per_dev, uint32_t bytes_per_block) 44 { 45 46 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_DEVSZ, 47 CAD_QSPI_DEVSZ_ADDR_BYTES(addr_bytes) | 48 CAD_QSPI_DEVSZ_BYTES_PER_PAGE(bytes_per_dev) | 49 CAD_QSPI_DEVSZ_BYTES_PER_BLOCK(bytes_per_block)); 50 return 0; 51 } 52 53 int cad_qspi_set_read_config(uint32_t opcode, uint32_t instr_type, 54 uint32_t addr_type, uint32_t data_type, 55 uint32_t mode_bit, uint32_t dummy_clk_cycle) 56 { 57 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_DEVRD, 58 CAD_QSPI_DEV_OPCODE(opcode) | 59 CAD_QSPI_DEV_INST_TYPE(instr_type) | 60 CAD_QSPI_DEV_ADDR_TYPE(addr_type) | 61 CAD_QSPI_DEV_DATA_TYPE(data_type) | 62 CAD_QSPI_DEV_MODE_BIT(mode_bit) | 63 CAD_QSPI_DEV_DUMMY_CLK_CYCLE(dummy_clk_cycle)); 64 65 return 0; 66 } 67 68 int cat_qspi_set_write_config(uint32_t addr_type, uint32_t data_type, 69 uint32_t mode_bit, uint32_t dummy_clk_cycle) 70 { 71 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_DEVWR, 72 CAD_QSPI_DEV_ADDR_TYPE(addr_type) | 73 CAD_QSPI_DEV_DATA_TYPE(data_type) | 74 CAD_QSPI_DEV_MODE_BIT(mode_bit) | 75 CAD_QSPI_DEV_DUMMY_CLK_CYCLE(dummy_clk_cycle)); 76 77 return 0; 78 } 79 80 int cad_qspi_timing_config(uint32_t clkphase, uint32_t clkpol, uint32_t csda, 81 uint32_t csdads, uint32_t cseot, uint32_t cssot, 82 uint32_t rddatacap) 83 { 84 uint32_t cfg = mmio_read_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG); 85 86 cfg &= CAD_QSPI_CFG_SELCLKPHASE_CLR_MSK & 87 CAD_QSPI_CFG_SELCLKPOL_CLR_MSK; 88 cfg |= CAD_QSPI_SELCLKPHASE(clkphase) | CAD_QSPI_SELCLKPOL(clkpol); 89 90 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG, cfg); 91 92 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_DELAY, 93 CAD_QSPI_DELAY_CSSOT(cssot) | CAD_QSPI_DELAY_CSEOT(cseot) | 94 CAD_QSPI_DELAY_CSDADS(csdads) | CAD_QSPI_DELAY_CSDA(csda)); 95 96 return 0; 97 } 98 99 int cad_qspi_stig_cmd_helper(int cs, uint32_t cmd) 100 { 101 uint32_t count = 0; 102 103 /* chip select */ 104 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG, 105 (mmio_read_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG) 106 & CAD_QSPI_CFG_CS_MSK) | CAD_QSPI_CFG_CS(cs)); 107 108 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD, cmd); 109 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD, 110 cmd | CAD_QSPI_FLASHCMD_EXECUTE); 111 112 do { 113 uint32_t reg = mmio_read_32(CAD_QSPI_OFFSET + 114 CAD_QSPI_FLASHCMD); 115 if (!(reg & CAD_QSPI_FLASHCMD_EXECUTE_STAT)) 116 break; 117 count++; 118 } while (count < CAD_QSPI_COMMAND_TIMEOUT); 119 120 if (count >= CAD_QSPI_COMMAND_TIMEOUT) { 121 ERROR("Error sending QSPI command %x, timed out\n", 122 cmd); 123 return CAD_QSPI_ERROR; 124 } 125 126 return 0; 127 } 128 129 int cad_qspi_stig_cmd(uint32_t opcode, uint32_t dummy) 130 { 131 if (dummy > ((1 << CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES_MAX) - 1)) { 132 ERROR("Faulty dummy bytes\n"); 133 return -1; 134 } 135 136 return cad_qspi_stig_cmd_helper(cad_qspi_cs, 137 CAD_QSPI_FLASHCMD_OPCODE(opcode) | 138 CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES(dummy)); 139 } 140 141 int cad_qspi_stig_read_cmd(uint32_t opcode, uint32_t dummy, uint32_t num_bytes, 142 uint32_t *output) 143 { 144 if (dummy > ((1 << CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES_MAX) - 1)) { 145 ERROR("Faulty dummy byes\n"); 146 return -1; 147 } 148 149 if ((num_bytes > 8) || (num_bytes == 0)) 150 return -1; 151 152 uint32_t cmd = 153 CAD_QSPI_FLASHCMD_OPCODE(opcode) | 154 CAD_QSPI_FLASHCMD_ENRDDATA(1) | 155 CAD_QSPI_FLASHCMD_NUMRDDATABYTES(num_bytes - 1) | 156 CAD_QSPI_FLASHCMD_ENCMDADDR(0) | 157 CAD_QSPI_FLASHCMD_ENMODEBIT(0) | 158 CAD_QSPI_FLASHCMD_NUMADDRBYTES(0) | 159 CAD_QSPI_FLASHCMD_ENWRDATA(0) | 160 CAD_QSPI_FLASHCMD_NUMWRDATABYTES(0) | 161 CAD_QSPI_FLASHCMD_NUMDUMMYBYTES(dummy); 162 163 if (cad_qspi_stig_cmd_helper(cad_qspi_cs, cmd)) { 164 ERROR("failed to send stig cmd"); 165 return -1; 166 } 167 168 output[0] = mmio_read_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD_RDDATA0); 169 170 if (num_bytes > 4) { 171 output[1] = mmio_read_32(CAD_QSPI_OFFSET + 172 CAD_QSPI_FLASHCMD_RDDATA1); 173 } 174 175 return 0; 176 } 177 178 int cad_qspi_stig_wr_cmd(uint32_t opcode, uint32_t dummy, uint32_t num_bytes, 179 uint32_t *input) 180 { 181 if (dummy > ((1 << CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES_MAX) - 1)) { 182 ERROR("Faulty dummy byes\n"); 183 return -1; 184 } 185 186 if ((num_bytes > 8) || (num_bytes == 0)) 187 return -1; 188 189 uint32_t cmd = CAD_QSPI_FLASHCMD_OPCODE(opcode) | 190 CAD_QSPI_FLASHCMD_ENRDDATA(0) | 191 CAD_QSPI_FLASHCMD_NUMRDDATABYTES(0) | 192 CAD_QSPI_FLASHCMD_ENCMDADDR(0) | 193 CAD_QSPI_FLASHCMD_ENMODEBIT(0) | 194 CAD_QSPI_FLASHCMD_NUMADDRBYTES(0) | 195 CAD_QSPI_FLASHCMD_ENWRDATA(1) | 196 CAD_QSPI_FLASHCMD_NUMWRDATABYTES(num_bytes - 1) | 197 CAD_QSPI_FLASHCMD_NUMDUMMYBYTES(dummy); 198 199 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD_WRDATA0, input[0]); 200 201 if (num_bytes > 4) 202 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD_WRDATA1, 203 input[1]); 204 205 return cad_qspi_stig_cmd_helper(cad_qspi_cs, cmd); 206 } 207 208 int cad_qspi_stig_addr_cmd(uint32_t opcode, uint32_t dummy, uint32_t addr) 209 { 210 uint32_t cmd; 211 212 if (dummy > ((1 << CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES_MAX) - 1)) 213 return -1; 214 215 cmd = CAD_QSPI_FLASHCMD_OPCODE(opcode) | 216 CAD_QSPI_FLASHCMD_NUMDUMMYBYTES(dummy) | 217 CAD_QSPI_FLASHCMD_ENCMDADDR(1) | 218 CAD_QSPI_FLASHCMD_NUMADDRBYTES(2); 219 220 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD_ADDR, addr); 221 222 return cad_qspi_stig_cmd_helper(cad_qspi_cs, cmd); 223 } 224 225 int cad_qspi_device_bank_select(uint32_t bank) 226 { 227 int status = 0; 228 229 status = cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_WREN, 0); 230 if (status != 0) 231 return status; 232 233 status = cad_qspi_stig_wr_cmd(CAD_QSPI_STIG_OPCODE_WREN_EXT_REG, 234 0, 1, &bank); 235 if (status != 0) 236 return status; 237 238 return cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_WRDIS, 0); 239 } 240 241 int cad_qspi_device_status(uint32_t *status) 242 { 243 return cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDSR, 0, 1, status); 244 } 245 246 #if CAD_QSPI_MICRON_N25Q_SUPPORT 247 int cad_qspi_n25q_enable(void) 248 { 249 cad_qspi_set_read_config(QSPI_FAST_READ, CAD_QSPI_INST_SINGLE, 250 CAD_QSPI_ADDR_FASTREAD, CAT_QSPI_ADDR_SINGLE_IO, 1, 251 0); 252 return 0; 253 } 254 255 int cad_qspi_n25q_wait_for_program_and_erase(int program_only) 256 { 257 uint32_t status, flag_sr; 258 int count = 0; 259 260 while (count < CAD_QSPI_COMMAND_TIMEOUT) { 261 status = cad_qspi_device_status(&status); 262 if (status != 0) { 263 ERROR("Error getting device status\n"); 264 return -1; 265 } 266 if (!CAD_QSPI_STIG_SR_BUSY(status)) 267 break; 268 count++; 269 } 270 271 if (count >= CAD_QSPI_COMMAND_TIMEOUT) { 272 ERROR("Timed out waiting for idle\n"); 273 return -1; 274 } 275 276 count = 0; 277 278 while (count < CAD_QSPI_COMMAND_TIMEOUT) { 279 status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDFLGSR, 280 0, 1, &flag_sr); 281 if (status != 0) { 282 ERROR("Error waiting program and erase.\n"); 283 return status; 284 } 285 286 if ((program_only && 287 CAD_QSPI_STIG_FLAGSR_PROGRAMREADY(flag_sr)) || 288 (!program_only && 289 CAD_QSPI_STIG_FLAGSR_ERASEREADY(flag_sr))) 290 break; 291 } 292 293 if (count >= CAD_QSPI_COMMAND_TIMEOUT) 294 ERROR("Timed out waiting for program and erase\n"); 295 296 if ((program_only && CAD_QSPI_STIG_FLAGSR_PROGRAMERROR(flag_sr)) || 297 (!program_only && 298 CAD_QSPI_STIG_FLAGSR_ERASEERROR(flag_sr))) { 299 ERROR("Error programming/erasing flash\n"); 300 cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_CLFSR, 0); 301 return -1; 302 } 303 304 return 0; 305 } 306 #endif 307 308 int cad_qspi_indirect_read_start_bank(uint32_t flash_addr, uint32_t num_bytes) 309 { 310 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDRDSTADDR, flash_addr); 311 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDRDCNT, num_bytes); 312 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDRD, 313 CAD_QSPI_INDRD_START | 314 CAD_QSPI_INDRD_IND_OPS_DONE); 315 316 return 0; 317 } 318 319 320 int cad_qspi_indirect_write_start_bank(uint32_t flash_addr, 321 uint32_t num_bytes) 322 { 323 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDWRSTADDR, flash_addr); 324 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDWRCNT, num_bytes); 325 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDWR, 326 CAD_QSPI_INDWR_START | 327 CAD_QSPI_INDWR_INDDONE); 328 329 return 0; 330 } 331 332 int cad_qspi_indirect_write_finish(void) 333 { 334 #if CAD_QSPI_MICRON_N25Q_SUPPORT 335 return cad_qspi_n25q_wait_for_program_and_erase(1); 336 #else 337 return 0; 338 #endif 339 340 } 341 342 int cad_qspi_enable(void) 343 { 344 int status; 345 346 mmio_setbits_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG, CAD_QSPI_CFG_ENABLE); 347 348 #if CAD_QSPI_MICRON_N25Q_SUPPORT 349 status = cad_qspi_n25q_enable(); 350 if (status != 0) 351 return status; 352 #endif 353 return 0; 354 } 355 356 int cad_qspi_enable_subsector_bank(uint32_t addr) 357 { 358 int status = 0; 359 360 status = cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_WREN, 0); 361 if (status != 0) 362 return status; 363 364 status = cad_qspi_stig_addr_cmd(CAD_QSPI_STIG_OPCODE_SUBSEC_ERASE, 0, 365 addr); 366 if (status != 0) 367 return status; 368 369 #if CAD_QSPI_MICRON_N25Q_SUPPORT 370 status = cad_qspi_n25q_wait_for_program_and_erase(0); 371 #endif 372 return status; 373 } 374 375 int cad_qspi_erase_subsector(uint32_t addr) 376 { 377 int status = 0; 378 379 status = cad_qspi_device_bank_select(addr >> 24); 380 if (status != 0) 381 return status; 382 383 return cad_qspi_enable_subsector_bank(addr); 384 } 385 386 int cad_qspi_erase_sector(uint32_t addr) 387 { 388 int status = 0; 389 390 status = cad_qspi_device_bank_select(addr >> 24); 391 if (status != 0) 392 return status; 393 394 status = cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_WREN, 0); 395 if (status != 0) 396 return status; 397 398 status = cad_qspi_stig_addr_cmd(CAD_QSPI_STIG_OPCODE_SEC_ERASE, 0, 399 addr); 400 if (status != 0) 401 return status; 402 403 #if CAD_QSPI_MICRON_N25Q_SUPPORT 404 status = cad_qspi_n25q_wait_for_program_and_erase(0); 405 #endif 406 return status; 407 } 408 409 void cad_qspi_calibration(uint32_t dev_clk, uint32_t qspi_clk_mhz) 410 { 411 int status; 412 uint32_t dev_sclk_mhz = 27; /*min value to get biggest 0xF div factor*/ 413 uint32_t data_cap_delay; 414 uint32_t sample_rdid; 415 uint32_t rdid; 416 uint32_t div_actual; 417 uint32_t div_bits; 418 int first_pass, last_pass; 419 420 /*1. Set divider to bigger value (slowest SCLK) 421 *2. RDID and save the value 422 */ 423 div_actual = (qspi_clk_mhz + (dev_sclk_mhz - 1)) / dev_sclk_mhz; 424 div_bits = (((div_actual + 1) / 2) - 1); 425 status = cad_qspi_set_baudrate_div(0xf); 426 427 status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDID, 428 0, 3, &sample_rdid); 429 if (status != 0) 430 return; 431 432 /*3. Set divider to the intended frequency 433 *4. Set the read delay = 0 434 *5. RDID and check whether the value is same as item 2 435 *6. Increase read delay and compared the value against item 2 436 *7. Find the range of read delay that have same as 437 * item 2 and divide it to 2 438 */ 439 div_actual = (qspi_clk_mhz + (dev_clk - 1)) / dev_clk; 440 div_bits = (((div_actual + 1) / 2) - 1); 441 status = cad_qspi_set_baudrate_div(div_bits); 442 if (status != 0) 443 return; 444 445 data_cap_delay = 0; 446 first_pass = -1; 447 last_pass = -1; 448 449 do { 450 if (status != 0) 451 break; 452 status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDID, 0, 453 3, &rdid); 454 if (status != 0) 455 break; 456 if (rdid == sample_rdid) { 457 if (first_pass == -1) 458 first_pass = data_cap_delay; 459 else 460 last_pass = data_cap_delay; 461 } 462 463 data_cap_delay++; 464 465 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_RDDATACAP, 466 CAD_QSPI_RDDATACAP_BYP(1) | 467 CAD_QSPI_RDDATACAP_DELAY(data_cap_delay)); 468 469 } while (data_cap_delay < 0x10); 470 471 if (first_pass > 0) { 472 int diff = first_pass - last_pass; 473 474 data_cap_delay = first_pass + diff / 2; 475 } 476 477 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_RDDATACAP, 478 CAD_QSPI_RDDATACAP_BYP(1) | 479 CAD_QSPI_RDDATACAP_DELAY(data_cap_delay)); 480 status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDID, 0, 3, &rdid); 481 482 if (status != 0) 483 return; 484 } 485 486 int cad_qspi_int_disable(uint32_t mask) 487 { 488 if (cad_qspi_idle() == 0) 489 return -1; 490 491 if ((CAD_QSPI_INT_STATUS_ALL & mask) == 0) 492 return -1; 493 494 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_IRQMSK, mask); 495 return 0; 496 } 497 498 void cad_qspi_set_chip_select(int cs) 499 { 500 cad_qspi_cs = cs; 501 } 502 503 int cad_qspi_init(uint32_t desired_clk_freq, uint32_t clk_phase, 504 uint32_t clk_pol, uint32_t csda, uint32_t csdads, 505 uint32_t cseot, uint32_t cssot, uint32_t rddatacap) 506 { 507 int status = 0; 508 uint32_t qspi_desired_clk_freq; 509 uint32_t rdid = 0; 510 uint32_t cap_code; 511 512 INFO("Initializing Qspi\n"); 513 514 if (cad_qspi_idle() == 0) { 515 ERROR("device not idle"); 516 return -1; 517 } 518 519 520 status = cad_qspi_timing_config(clk_phase, clk_pol, csda, csdads, 521 cseot, cssot, rddatacap); 522 523 if (status != 0) { 524 ERROR("config set timing failure\n"); 525 return status; 526 } 527 528 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_REMAPADDR, 529 CAD_QSPI_REMAPADDR_VALUE_SET(0)); 530 531 status = cad_qspi_int_disable(CAD_QSPI_INT_STATUS_ALL); 532 if (status != 0) { 533 ERROR("failed disable\n"); 534 return status; 535 } 536 537 cad_qspi_set_baudrate_div(0xf); 538 status = cad_qspi_enable(); 539 if (status != 0) { 540 ERROR("failed enable\n"); 541 return status; 542 } 543 544 qspi_desired_clk_freq = 100; 545 cad_qspi_calibration(qspi_desired_clk_freq, 50000000); 546 547 status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDID, 0, 3, 548 &rdid); 549 550 if (status != 0) { 551 ERROR("Error reading RDID\n"); 552 return status; 553 } 554 555 /* 556 * NOTE: The Size code seems to be a form of BCD (binary coded decimal). 557 * The first nibble is the 10's digit and the second nibble is the 1's 558 * digit in the number of bytes. 559 * 560 * Capacity ID samples: 561 * 0x15 : 16 Mb => 2 MiB => 1 << 21 ; BCD=15 562 * 0x16 : 32 Mb => 4 MiB => 1 << 22 ; BCD=16 563 * 0x17 : 64 Mb => 8 MiB => 1 << 23 ; BCD=17 564 * 0x18 : 128 Mb => 16 MiB => 1 << 24 ; BCD=18 565 * 0x19 : 256 Mb => 32 MiB => 1 << 25 ; BCD=19 566 * 0x1a 567 * 0x1b 568 * 0x1c 569 * 0x1d 570 * 0x1e 571 * 0x1f 572 * 0x20 : 512 Mb => 64 MiB => 1 << 26 ; BCD=20 573 * 0x21 : 1024 Mb => 128 MiB => 1 << 27 ; BCD=21 574 */ 575 576 cap_code = CAD_QSPI_STIG_RDID_CAPACITYID(rdid); 577 578 if (!(((cap_code >> 4) > 0x9) || ((cap_code & 0xf) > 0x9))) { 579 uint32_t decoded_cap = ((cap_code >> 4) * 10) + 580 (cap_code & 0xf); 581 qspi_device_size = 1 << (decoded_cap + 6); 582 INFO("QSPI Capacity: %x\n\n", qspi_device_size); 583 584 } else { 585 ERROR("Invalid CapacityID encountered: 0x%02x\n", 586 cap_code); 587 return -1; 588 } 589 590 cad_qspi_configure_dev_size(S10_QSPI_ADDR_BYTES, 591 S10_QSPI_BYTES_PER_DEV, S10_BYTES_PER_BLOCK); 592 593 INFO("Flash size: %d Bytes\n", qspi_device_size); 594 595 return status; 596 } 597 598 int cad_qspi_indirect_page_bound_write(uint32_t offset, 599 uint8_t *buffer, uint32_t len) 600 { 601 int status = 0, i; 602 uint32_t write_count, write_capacity, *write_data, space, 603 write_fill_level, sram_partition; 604 605 status = cad_qspi_indirect_write_start_bank(offset, len); 606 if (status != 0) 607 return status; 608 609 write_count = 0; 610 sram_partition = CAD_QSPI_SRAMPART_ADDR(mmio_read_32(CAD_QSPI_OFFSET + 611 CAD_QSPI_SRAMPART)); 612 write_capacity = (uint32_t) CAD_QSPI_SRAM_FIFO_ENTRY_COUNT - 613 sram_partition; 614 615 while (write_count < len) { 616 write_fill_level = CAD_QSPI_SRAMFILL_INDWRPART( 617 mmio_read_32(CAD_QSPI_OFFSET + 618 CAD_QSPI_SRAMFILL)); 619 space = LESS(write_capacity - write_fill_level, 620 (len - write_count) / sizeof(uint32_t)); 621 write_data = (uint32_t *)(buffer + write_count); 622 for (i = 0; i < space; ++i) 623 mmio_write_32(CAD_QSPIDATA_OFST, *write_data++); 624 625 write_count += space * sizeof(uint32_t); 626 } 627 return cad_qspi_indirect_write_finish(); 628 } 629 630 int cad_qspi_read_bank(uint8_t *buffer, uint32_t offset, uint32_t size) 631 { 632 int status; 633 uint32_t read_count = 0, *read_data; 634 int level = 1, count = 0, i; 635 636 status = cad_qspi_indirect_read_start_bank(offset, size); 637 638 if (status != 0) 639 return status; 640 641 while (read_count < size) { 642 do { 643 level = CAD_QSPI_SRAMFILL_INDRDPART( 644 mmio_read_32(CAD_QSPI_OFFSET + 645 CAD_QSPI_SRAMFILL)); 646 read_data = (uint32_t *)(buffer + read_count); 647 for (i = 0; i < level; ++i) 648 *read_data++ = mmio_read_32(CAD_QSPIDATA_OFST); 649 650 read_count += level * sizeof(uint32_t); 651 count++; 652 } while (level > 0); 653 } 654 655 return 0; 656 } 657 658 int cad_qspi_write_bank(uint32_t offset, uint8_t *buffer, uint32_t size) 659 { 660 int status = 0; 661 uint32_t page_offset = offset & (CAD_QSPI_PAGE_SIZE - 1); 662 uint32_t write_size = LESS(size, CAD_QSPI_PAGE_SIZE - page_offset); 663 664 while (size) { 665 status = cad_qspi_indirect_page_bound_write(offset, buffer, 666 write_size); 667 if (status != 0) 668 break; 669 670 offset += write_size; 671 buffer += write_size; 672 size -= write_size; 673 write_size = LESS(size, CAD_QSPI_PAGE_SIZE); 674 } 675 return status; 676 } 677 678 int cad_qspi_read(void *buffer, uint32_t offset, uint32_t size) 679 { 680 uint32_t bank_count, bank_addr, bank_offset, copy_len; 681 uint8_t *read_data; 682 int i, status; 683 684 status = 0; 685 686 if ((offset >= qspi_device_size) || 687 (offset + size - 1 >= qspi_device_size) || 688 (size == 0) || 689 ((long) ((int *)buffer) & 0x3) || 690 (offset & 0x3) || 691 (size & 0x3)) { 692 ERROR("Invalid read parameter"); 693 return -1; 694 } 695 696 if (CAD_QSPI_INDRD_RD_STAT(mmio_read_32(CAD_QSPI_OFFSET + 697 CAD_QSPI_INDRD))) { 698 ERROR("Read in progress"); 699 return -1; 700 } 701 702 /* 703 * bank_count : Number of bank(s) affected, including partial banks. 704 * bank_addr : Aligned address of the first bank, 705 * including partial bank. 706 * bank_ofst : The offset of the bank to read. 707 * Only used when reading the first bank. 708 */ 709 bank_count = CAD_QSPI_BANK_ADDR(offset + size - 1) - 710 CAD_QSPI_BANK_ADDR(offset) + 1; 711 bank_addr = offset & CAD_QSPI_BANK_ADDR_MSK; 712 bank_offset = offset & (CAD_QSPI_BANK_SIZE - 1); 713 714 read_data = (uint8_t *)buffer; 715 716 copy_len = LESS(size, CAD_QSPI_BANK_SIZE - bank_offset); 717 718 for (i = 0; i < bank_count; ++i) { 719 status = cad_qspi_device_bank_select(CAD_QSPI_BANK_ADDR( 720 bank_addr)); 721 if (status != 0) 722 break; 723 status = cad_qspi_read_bank(read_data, bank_offset, copy_len); 724 if (status != 0) 725 break; 726 727 bank_addr += CAD_QSPI_BANK_SIZE; 728 read_data += copy_len; 729 size -= copy_len; 730 bank_offset = 0; 731 copy_len = LESS(size, CAD_QSPI_BANK_SIZE); 732 } 733 734 return status; 735 } 736 737 int cad_qspi_erase(uint32_t offset, uint32_t size) 738 { 739 int status = 0; 740 uint32_t subsector_offset = offset & (CAD_QSPI_SUBSECTOR_SIZE - 1); 741 uint32_t erase_size = LESS(size, 742 CAD_QSPI_SUBSECTOR_SIZE - subsector_offset); 743 744 while (size) { 745 status = cad_qspi_erase_subsector(offset); 746 if (status != 0) 747 break; 748 749 offset += erase_size; 750 size -= erase_size; 751 erase_size = LESS(size, CAD_QSPI_SUBSECTOR_SIZE); 752 } 753 return status; 754 } 755 756 int cad_qspi_write(void *buffer, uint32_t offset, uint32_t size) 757 { 758 int status, i; 759 uint32_t bank_count, bank_addr, bank_offset, copy_len; 760 uint8_t *write_data; 761 762 status = 0; 763 764 if ((offset >= qspi_device_size) || 765 (offset + size - 1 >= qspi_device_size) || 766 (size == 0) || 767 ((long)buffer & 0x3) || 768 (offset & 0x3) || 769 (size & 0x3)) 770 return -2; 771 772 if (CAD_QSPI_INDWR_RDSTAT(mmio_read_32(CAD_QSPI_OFFSET + 773 CAD_QSPI_INDWR))) { 774 ERROR("QSPI Error: Write in progress\n"); 775 return -1; 776 } 777 778 bank_count = CAD_QSPI_BANK_ADDR(offset + size - 1) - 779 CAD_QSPI_BANK_ADDR(offset) + 1; 780 bank_addr = offset & CAD_QSPI_BANK_ADDR_MSK; 781 bank_offset = offset & (CAD_QSPI_BANK_SIZE - 1); 782 783 write_data = buffer; 784 785 copy_len = LESS(size, CAD_QSPI_BANK_SIZE - bank_offset); 786 787 for (i = 0; i < bank_count; ++i) { 788 status = cad_qspi_device_bank_select( 789 CAD_QSPI_BANK_ADDR(bank_addr)); 790 if (status != 0) 791 break; 792 793 status = cad_qspi_write_bank(bank_offset, write_data, 794 copy_len); 795 if (status != 0) 796 break; 797 798 bank_addr += CAD_QSPI_BANK_SIZE; 799 write_data += copy_len; 800 size -= copy_len; 801 bank_offset = 0; 802 803 copy_len = LESS(size, CAD_QSPI_BANK_SIZE); 804 } 805 return status; 806 } 807 808 int cad_qspi_update(void *Buffer, uint32_t offset, uint32_t size) 809 { 810 int status = 0; 811 812 status = cad_qspi_erase(offset, size); 813 if (status != 0) 814 return status; 815 816 return cad_qspi_write(Buffer, offset, size); 817 } 818 819 void cad_qspi_reset(void) 820 { 821 cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_RESET_EN, 0); 822 cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_RESET_MEM, 0); 823 } 824 825