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