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