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