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 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 cad_qspi_set_write_config(uint32_t opcode, uint32_t addr_type, 69 uint32_t data_type, uint32_t dummy_clk_cycle) 70 { 71 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_DEVWR, 72 CAD_QSPI_DEV_OPCODE(opcode) | 73 CAD_QSPI_DEV_ADDR_TYPE(addr_type) | 74 CAD_QSPI_DEV_DATA_TYPE(data_type) | 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\n"); 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 cad_qspi_set_write_config(QSPI_WRITE, 0, 0, 0); 253 254 return 0; 255 } 256 257 int cad_qspi_n25q_wait_for_program_and_erase(int program_only) 258 { 259 uint32_t status, flag_sr; 260 int count = 0; 261 262 while (count < CAD_QSPI_COMMAND_TIMEOUT) { 263 status = cad_qspi_device_status(&status); 264 if (status != 0) { 265 ERROR("Error getting device status\n"); 266 return -1; 267 } 268 if (!CAD_QSPI_STIG_SR_BUSY(status)) 269 break; 270 count++; 271 } 272 273 if (count >= CAD_QSPI_COMMAND_TIMEOUT) { 274 ERROR("Timed out waiting for idle\n"); 275 return -1; 276 } 277 278 count = 0; 279 280 while (count < CAD_QSPI_COMMAND_TIMEOUT) { 281 status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDFLGSR, 282 0, 1, &flag_sr); 283 if (status != 0) { 284 ERROR("Error waiting program and erase.\n"); 285 return status; 286 } 287 288 if ((program_only && 289 CAD_QSPI_STIG_FLAGSR_PROGRAMREADY(flag_sr)) || 290 (!program_only && 291 CAD_QSPI_STIG_FLAGSR_ERASEREADY(flag_sr))) 292 break; 293 } 294 295 if (count >= CAD_QSPI_COMMAND_TIMEOUT) 296 ERROR("Timed out waiting for program and erase\n"); 297 298 if ((program_only && CAD_QSPI_STIG_FLAGSR_PROGRAMERROR(flag_sr)) || 299 (!program_only && 300 CAD_QSPI_STIG_FLAGSR_ERASEERROR(flag_sr))) { 301 ERROR("Error programming/erasing flash\n"); 302 cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_CLFSR, 0); 303 return -1; 304 } 305 306 return 0; 307 } 308 #endif 309 310 int cad_qspi_indirect_read_start_bank(uint32_t flash_addr, uint32_t num_bytes) 311 { 312 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDRDSTADDR, flash_addr); 313 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDRDCNT, num_bytes); 314 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDRD, 315 CAD_QSPI_INDRD_START | 316 CAD_QSPI_INDRD_IND_OPS_DONE); 317 318 return 0; 319 } 320 321 322 int cad_qspi_indirect_write_start_bank(uint32_t flash_addr, 323 uint32_t num_bytes) 324 { 325 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDWRSTADDR, flash_addr); 326 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDWRCNT, num_bytes); 327 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDWR, 328 CAD_QSPI_INDWR_START | 329 CAD_QSPI_INDWR_INDDONE); 330 331 return 0; 332 } 333 334 int cad_qspi_indirect_write_finish(void) 335 { 336 #if CAD_QSPI_MICRON_N25Q_SUPPORT 337 return cad_qspi_n25q_wait_for_program_and_erase(1); 338 #else 339 return 0; 340 #endif 341 342 } 343 344 int cad_qspi_enable(void) 345 { 346 int status; 347 348 mmio_setbits_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG, CAD_QSPI_CFG_ENABLE); 349 350 #if CAD_QSPI_MICRON_N25Q_SUPPORT 351 status = cad_qspi_n25q_enable(); 352 if (status != 0) 353 return status; 354 #endif 355 return 0; 356 } 357 358 int cad_qspi_enable_subsector_bank(uint32_t addr) 359 { 360 int status = 0; 361 362 status = cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_WREN, 0); 363 if (status != 0) 364 return status; 365 366 status = cad_qspi_stig_addr_cmd(CAD_QSPI_STIG_OPCODE_SUBSEC_ERASE, 0, 367 addr); 368 if (status != 0) 369 return status; 370 371 #if CAD_QSPI_MICRON_N25Q_SUPPORT 372 status = cad_qspi_n25q_wait_for_program_and_erase(0); 373 #endif 374 return status; 375 } 376 377 int cad_qspi_erase_subsector(uint32_t addr) 378 { 379 int status = 0; 380 381 status = cad_qspi_device_bank_select(addr >> 24); 382 if (status != 0) 383 return status; 384 385 return cad_qspi_enable_subsector_bank(addr); 386 } 387 388 int cad_qspi_erase_sector(uint32_t addr) 389 { 390 int status = 0; 391 392 status = cad_qspi_device_bank_select(addr >> 24); 393 if (status != 0) 394 return status; 395 396 status = cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_WREN, 0); 397 if (status != 0) 398 return status; 399 400 status = cad_qspi_stig_addr_cmd(CAD_QSPI_STIG_OPCODE_SEC_ERASE, 0, 401 addr); 402 if (status != 0) 403 return status; 404 405 #if CAD_QSPI_MICRON_N25Q_SUPPORT 406 status = cad_qspi_n25q_wait_for_program_and_erase(0); 407 #endif 408 return status; 409 } 410 411 void cad_qspi_calibration(uint32_t dev_clk, uint32_t qspi_clk_mhz) 412 { 413 int status; 414 uint32_t dev_sclk_mhz = 27; /*min value to get biggest 0xF div factor*/ 415 uint32_t data_cap_delay; 416 uint32_t sample_rdid; 417 uint32_t rdid; 418 uint32_t div_actual; 419 uint32_t div_bits; 420 int first_pass, last_pass; 421 422 /*1. Set divider to bigger value (slowest SCLK) 423 *2. RDID and save the value 424 */ 425 div_actual = (qspi_clk_mhz + (dev_sclk_mhz - 1)) / dev_sclk_mhz; 426 div_bits = (((div_actual + 1) / 2) - 1); 427 status = cad_qspi_set_baudrate_div(0xf); 428 429 status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDID, 430 0, 3, &sample_rdid); 431 if (status != 0) 432 return; 433 434 /*3. Set divider to the intended frequency 435 *4. Set the read delay = 0 436 *5. RDID and check whether the value is same as item 2 437 *6. Increase read delay and compared the value against item 2 438 *7. Find the range of read delay that have same as 439 * item 2 and divide it to 2 440 */ 441 div_actual = (qspi_clk_mhz + (dev_clk - 1)) / dev_clk; 442 div_bits = (((div_actual + 1) / 2) - 1); 443 status = cad_qspi_set_baudrate_div(div_bits); 444 if (status != 0) 445 return; 446 447 data_cap_delay = 0; 448 first_pass = -1; 449 last_pass = -1; 450 451 do { 452 if (status != 0) 453 break; 454 status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDID, 0, 455 3, &rdid); 456 if (status != 0) 457 break; 458 if (rdid == sample_rdid) { 459 if (first_pass == -1) 460 first_pass = data_cap_delay; 461 else 462 last_pass = data_cap_delay; 463 } 464 465 data_cap_delay++; 466 467 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_RDDATACAP, 468 CAD_QSPI_RDDATACAP_BYP(1) | 469 CAD_QSPI_RDDATACAP_DELAY(data_cap_delay)); 470 471 } while (data_cap_delay < 0x10); 472 473 if (first_pass > 0) { 474 int diff = first_pass - last_pass; 475 476 data_cap_delay = first_pass + diff / 2; 477 } 478 479 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_RDDATACAP, 480 CAD_QSPI_RDDATACAP_BYP(1) | 481 CAD_QSPI_RDDATACAP_DELAY(data_cap_delay)); 482 status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDID, 0, 3, &rdid); 483 484 if (status != 0) 485 return; 486 } 487 488 int cad_qspi_int_disable(uint32_t mask) 489 { 490 if (cad_qspi_idle() == 0) 491 return -1; 492 493 if ((CAD_QSPI_INT_STATUS_ALL & mask) == 0) 494 return -1; 495 496 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_IRQMSK, mask); 497 return 0; 498 } 499 500 void cad_qspi_set_chip_select(int cs) 501 { 502 cad_qspi_cs = cs; 503 } 504 505 int cad_qspi_init(uint32_t desired_clk_freq, uint32_t clk_phase, 506 uint32_t clk_pol, uint32_t csda, uint32_t csdads, 507 uint32_t cseot, uint32_t cssot, uint32_t rddatacap) 508 { 509 int status = 0; 510 uint32_t qspi_desired_clk_freq; 511 uint32_t rdid = 0; 512 uint32_t cap_code; 513 514 INFO("Initializing Qspi\n"); 515 516 if (cad_qspi_idle() == 0) { 517 ERROR("device not idle\n"); 518 return -1; 519 } 520 521 522 status = cad_qspi_timing_config(clk_phase, clk_pol, csda, csdads, 523 cseot, cssot, rddatacap); 524 525 if (status != 0) { 526 ERROR("config set timing failure\n"); 527 return status; 528 } 529 530 mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_REMAPADDR, 531 CAD_QSPI_REMAPADDR_VALUE_SET(0)); 532 533 status = cad_qspi_int_disable(CAD_QSPI_INT_STATUS_ALL); 534 if (status != 0) { 535 ERROR("failed disable\n"); 536 return status; 537 } 538 539 cad_qspi_set_baudrate_div(0xf); 540 status = cad_qspi_enable(); 541 if (status != 0) { 542 ERROR("failed enable\n"); 543 return status; 544 } 545 546 qspi_desired_clk_freq = 100; 547 cad_qspi_calibration(qspi_desired_clk_freq, 50000000); 548 549 status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDID, 0, 3, 550 &rdid); 551 552 if (status != 0) { 553 ERROR("Error reading RDID\n"); 554 return status; 555 } 556 557 /* 558 * NOTE: The Size code seems to be a form of BCD (binary coded decimal). 559 * The first nibble is the 10's digit and the second nibble is the 1's 560 * digit in the number of bytes. 561 * 562 * Capacity ID samples: 563 * 0x15 : 16 Mb => 2 MiB => 1 << 21 ; BCD=15 564 * 0x16 : 32 Mb => 4 MiB => 1 << 22 ; BCD=16 565 * 0x17 : 64 Mb => 8 MiB => 1 << 23 ; BCD=17 566 * 0x18 : 128 Mb => 16 MiB => 1 << 24 ; BCD=18 567 * 0x19 : 256 Mb => 32 MiB => 1 << 25 ; BCD=19 568 * 0x1a 569 * 0x1b 570 * 0x1c 571 * 0x1d 572 * 0x1e 573 * 0x1f 574 * 0x20 : 512 Mb => 64 MiB => 1 << 26 ; BCD=20 575 * 0x21 : 1024 Mb => 128 MiB => 1 << 27 ; BCD=21 576 */ 577 578 cap_code = CAD_QSPI_STIG_RDID_CAPACITYID(rdid); 579 580 if (!(((cap_code >> 4) > 0x9) || ((cap_code & 0xf) > 0x9))) { 581 uint32_t decoded_cap = ((cap_code >> 4) * 10) + 582 (cap_code & 0xf); 583 qspi_device_size = 1 << (decoded_cap + 6); 584 INFO("QSPI Capacity: %x\n\n", qspi_device_size); 585 586 } else { 587 ERROR("Invalid CapacityID encountered: 0x%02x\n", 588 cap_code); 589 return -1; 590 } 591 592 cad_qspi_configure_dev_size(INTEL_QSPI_ADDR_BYTES, 593 INTEL_QSPI_BYTES_PER_DEV, 594 INTEL_BYTES_PER_BLOCK); 595 596 INFO("Flash size: %d Bytes\n", qspi_device_size); 597 598 return status; 599 } 600 601 int cad_qspi_indirect_page_bound_write(uint32_t offset, 602 uint8_t *buffer, uint32_t len) 603 { 604 int status = 0, i; 605 uint32_t write_count, write_capacity, *write_data, space, 606 write_fill_level, sram_partition; 607 608 status = cad_qspi_indirect_write_start_bank(offset, len); 609 if (status != 0) 610 return status; 611 612 write_count = 0; 613 sram_partition = CAD_QSPI_SRAMPART_ADDR(mmio_read_32(CAD_QSPI_OFFSET + 614 CAD_QSPI_SRAMPART)); 615 write_capacity = (uint32_t) CAD_QSPI_SRAM_FIFO_ENTRY_COUNT - 616 sram_partition; 617 618 while (write_count < len) { 619 write_fill_level = CAD_QSPI_SRAMFILL_INDWRPART( 620 mmio_read_32(CAD_QSPI_OFFSET + 621 CAD_QSPI_SRAMFILL)); 622 space = LESS(write_capacity - write_fill_level, 623 (len - write_count) / sizeof(uint32_t)); 624 write_data = (uint32_t *)(buffer + write_count); 625 for (i = 0; i < space; ++i) 626 mmio_write_32(CAD_QSPIDATA_OFST, *write_data++); 627 628 write_count += space * sizeof(uint32_t); 629 } 630 return cad_qspi_indirect_write_finish(); 631 } 632 633 int cad_qspi_read_bank(uint8_t *buffer, uint32_t offset, uint32_t size) 634 { 635 int status; 636 uint32_t read_count = 0, *read_data; 637 int level = 1, count = 0, i; 638 639 status = cad_qspi_indirect_read_start_bank(offset, size); 640 641 if (status != 0) 642 return status; 643 644 while (read_count < size) { 645 do { 646 level = CAD_QSPI_SRAMFILL_INDRDPART( 647 mmio_read_32(CAD_QSPI_OFFSET + 648 CAD_QSPI_SRAMFILL)); 649 read_data = (uint32_t *)(buffer + read_count); 650 for (i = 0; i < level; ++i) 651 *read_data++ = mmio_read_32(CAD_QSPIDATA_OFST); 652 653 read_count += level * sizeof(uint32_t); 654 count++; 655 } while (level > 0); 656 } 657 658 return 0; 659 } 660 661 int cad_qspi_write_bank(uint32_t offset, uint8_t *buffer, uint32_t size) 662 { 663 int status = 0; 664 uint32_t page_offset = offset & (CAD_QSPI_PAGE_SIZE - 1); 665 uint32_t write_size = LESS(size, CAD_QSPI_PAGE_SIZE - page_offset); 666 667 while (size) { 668 status = cad_qspi_indirect_page_bound_write(offset, buffer, 669 write_size); 670 if (status != 0) 671 break; 672 673 offset += write_size; 674 buffer += write_size; 675 size -= write_size; 676 write_size = LESS(size, CAD_QSPI_PAGE_SIZE); 677 } 678 return status; 679 } 680 681 int cad_qspi_read(void *buffer, uint32_t offset, uint32_t size) 682 { 683 uint32_t bank_count, bank_addr, bank_offset, copy_len; 684 uint8_t *read_data; 685 int i, status; 686 687 status = 0; 688 689 if ((offset >= qspi_device_size) || 690 (offset + size - 1 >= qspi_device_size) || 691 (size == 0)) { 692 ERROR("Invalid read parameter\n"); 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\n"); 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 return -2; 768 } 769 770 if (CAD_QSPI_INDWR_RDSTAT(mmio_read_32(CAD_QSPI_OFFSET + 771 CAD_QSPI_INDWR))) { 772 ERROR("QSPI Error: Write in progress\n"); 773 return -1; 774 } 775 776 bank_count = CAD_QSPI_BANK_ADDR(offset + size - 1) - 777 CAD_QSPI_BANK_ADDR(offset) + 1; 778 bank_addr = offset & CAD_QSPI_BANK_ADDR_MSK; 779 bank_offset = offset & (CAD_QSPI_BANK_SIZE - 1); 780 781 write_data = buffer; 782 783 copy_len = LESS(size, CAD_QSPI_BANK_SIZE - bank_offset); 784 785 for (i = 0; i < bank_count; ++i) { 786 status = cad_qspi_device_bank_select( 787 CAD_QSPI_BANK_ADDR(bank_addr)); 788 if (status != 0) 789 break; 790 791 status = cad_qspi_write_bank(bank_offset, write_data, 792 copy_len); 793 if (status != 0) 794 break; 795 796 bank_addr += CAD_QSPI_BANK_SIZE; 797 write_data += copy_len; 798 size -= copy_len; 799 bank_offset = 0; 800 801 copy_len = LESS(size, CAD_QSPI_BANK_SIZE); 802 } 803 return status; 804 } 805 806 int cad_qspi_update(void *Buffer, uint32_t offset, uint32_t size) 807 { 808 int status = 0; 809 810 status = cad_qspi_erase(offset, size); 811 if (status != 0) 812 return status; 813 814 return cad_qspi_write(Buffer, offset, size); 815 } 816 817 void cad_qspi_reset(void) 818 { 819 cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_RESET_EN, 0); 820 cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_RESET_MEM, 0); 821 } 822 823