Merge pull request #1873 from hadi-asyrafi/driver_qspi
intel: Add driver for QSPI
This commit is contained in:
commit
0976b3487b
|
@ -0,0 +1,824 @@
|
|||
/*
|
||||
* Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <common/debug.h>
|
||||
#include <lib/mmio.h>
|
||||
#include <string.h>
|
||||
#include <drivers/delay_timer.h>
|
||||
#include <drivers/console.h>
|
||||
|
||||
#include "cadence_qspi.h"
|
||||
#include <platform_def.h>
|
||||
|
||||
#define LESS(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#define MORE(a, b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
|
||||
uint32_t qspi_device_size;
|
||||
int cad_qspi_cs;
|
||||
|
||||
int cad_qspi_idle(void)
|
||||
{
|
||||
return (mmio_read_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG)
|
||||
& CAD_QSPI_CFG_IDLE) >> 31;
|
||||
}
|
||||
|
||||
int cad_qspi_set_baudrate_div(uint32_t div)
|
||||
{
|
||||
if (div > 0xf)
|
||||
return CAD_INVALID;
|
||||
|
||||
mmio_clrsetbits_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG,
|
||||
~CAD_QSPI_CFG_BAUDDIV_MSK,
|
||||
CAD_QSPI_CFG_BAUDDIV(div));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cad_qspi_configure_dev_size(uint32_t addr_bytes,
|
||||
uint32_t bytes_per_dev, uint32_t bytes_per_block)
|
||||
{
|
||||
|
||||
mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_DEVSZ,
|
||||
CAD_QSPI_DEVSZ_ADDR_BYTES(addr_bytes) |
|
||||
CAD_QSPI_DEVSZ_BYTES_PER_PAGE(bytes_per_dev) |
|
||||
CAD_QSPI_DEVSZ_BYTES_PER_BLOCK(bytes_per_block));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cad_qspi_set_read_config(uint32_t opcode, uint32_t instr_type,
|
||||
uint32_t addr_type, uint32_t data_type,
|
||||
uint32_t mode_bit, uint32_t dummy_clk_cycle)
|
||||
{
|
||||
mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_DEVRD,
|
||||
CAD_QSPI_DEV_OPCODE(opcode) |
|
||||
CAD_QSPI_DEV_INST_TYPE(instr_type) |
|
||||
CAD_QSPI_DEV_ADDR_TYPE(addr_type) |
|
||||
CAD_QSPI_DEV_DATA_TYPE(data_type) |
|
||||
CAD_QSPI_DEV_MODE_BIT(mode_bit) |
|
||||
CAD_QSPI_DEV_DUMMY_CLK_CYCLE(dummy_clk_cycle));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cat_qspi_set_write_config(uint32_t addr_type, uint32_t data_type,
|
||||
uint32_t mode_bit, uint32_t dummy_clk_cycle)
|
||||
{
|
||||
mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_DEVWR,
|
||||
CAD_QSPI_DEV_ADDR_TYPE(addr_type) |
|
||||
CAD_QSPI_DEV_DATA_TYPE(data_type) |
|
||||
CAD_QSPI_DEV_MODE_BIT(mode_bit) |
|
||||
CAD_QSPI_DEV_DUMMY_CLK_CYCLE(dummy_clk_cycle));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cad_qspi_timing_config(uint32_t clkphase, uint32_t clkpol, uint32_t csda,
|
||||
uint32_t csdads, uint32_t cseot, uint32_t cssot,
|
||||
uint32_t rddatacap)
|
||||
{
|
||||
uint32_t cfg = mmio_read_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG);
|
||||
|
||||
cfg &= CAD_QSPI_CFG_SELCLKPHASE_CLR_MSK &
|
||||
CAD_QSPI_CFG_SELCLKPOL_CLR_MSK;
|
||||
cfg |= CAD_QSPI_SELCLKPHASE(clkphase) | CAD_QSPI_SELCLKPOL(clkpol);
|
||||
|
||||
mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG, cfg);
|
||||
|
||||
mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_DELAY,
|
||||
CAD_QSPI_DELAY_CSSOT(cssot) | CAD_QSPI_DELAY_CSEOT(cseot) |
|
||||
CAD_QSPI_DELAY_CSDADS(csdads) | CAD_QSPI_DELAY_CSDA(csda));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cad_qspi_stig_cmd_helper(int cs, uint32_t cmd)
|
||||
{
|
||||
uint32_t count = 0;
|
||||
|
||||
/* chip select */
|
||||
mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG,
|
||||
(mmio_read_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG)
|
||||
& CAD_QSPI_CFG_CS_MSK) | CAD_QSPI_CFG_CS(cs));
|
||||
|
||||
mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD, cmd);
|
||||
mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD,
|
||||
cmd | CAD_QSPI_FLASHCMD_EXECUTE);
|
||||
|
||||
do {
|
||||
uint32_t reg = mmio_read_32(CAD_QSPI_OFFSET +
|
||||
CAD_QSPI_FLASHCMD);
|
||||
if (!(reg & CAD_QSPI_FLASHCMD_EXECUTE_STAT))
|
||||
break;
|
||||
count++;
|
||||
} while (count < CAD_QSPI_COMMAND_TIMEOUT);
|
||||
|
||||
if (count >= CAD_QSPI_COMMAND_TIMEOUT) {
|
||||
ERROR("Error sending QSPI command %x, timed out\n",
|
||||
cmd);
|
||||
return CAD_QSPI_ERROR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cad_qspi_stig_cmd(uint32_t opcode, uint32_t dummy)
|
||||
{
|
||||
if (dummy > ((1 << CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES_MAX) - 1)) {
|
||||
ERROR("Faulty dummy bytes\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return cad_qspi_stig_cmd_helper(cad_qspi_cs,
|
||||
CAD_QSPI_FLASHCMD_OPCODE(opcode) |
|
||||
CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES(dummy));
|
||||
}
|
||||
|
||||
int cad_qspi_stig_read_cmd(uint32_t opcode, uint32_t dummy, uint32_t num_bytes,
|
||||
uint32_t *output)
|
||||
{
|
||||
if (dummy > ((1 << CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES_MAX) - 1)) {
|
||||
ERROR("Faulty dummy byes\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((num_bytes > 8) || (num_bytes == 0))
|
||||
return -1;
|
||||
|
||||
uint32_t cmd =
|
||||
CAD_QSPI_FLASHCMD_OPCODE(opcode) |
|
||||
CAD_QSPI_FLASHCMD_ENRDDATA(1) |
|
||||
CAD_QSPI_FLASHCMD_NUMRDDATABYTES(num_bytes - 1) |
|
||||
CAD_QSPI_FLASHCMD_ENCMDADDR(0) |
|
||||
CAD_QSPI_FLASHCMD_ENMODEBIT(0) |
|
||||
CAD_QSPI_FLASHCMD_NUMADDRBYTES(0) |
|
||||
CAD_QSPI_FLASHCMD_ENWRDATA(0) |
|
||||
CAD_QSPI_FLASHCMD_NUMWRDATABYTES(0) |
|
||||
CAD_QSPI_FLASHCMD_NUMDUMMYBYTES(dummy);
|
||||
|
||||
if (cad_qspi_stig_cmd_helper(cad_qspi_cs, cmd)) {
|
||||
ERROR("failed to send stig cmd");
|
||||
return -1;
|
||||
}
|
||||
|
||||
output[0] = mmio_read_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD_RDDATA0);
|
||||
|
||||
if (num_bytes > 4) {
|
||||
output[1] = mmio_read_32(CAD_QSPI_OFFSET +
|
||||
CAD_QSPI_FLASHCMD_RDDATA1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cad_qspi_stig_wr_cmd(uint32_t opcode, uint32_t dummy, uint32_t num_bytes,
|
||||
uint32_t *input)
|
||||
{
|
||||
if (dummy > ((1 << CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES_MAX) - 1)) {
|
||||
ERROR("Faulty dummy byes\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((num_bytes > 8) || (num_bytes == 0))
|
||||
return -1;
|
||||
|
||||
uint32_t cmd = CAD_QSPI_FLASHCMD_OPCODE(opcode) |
|
||||
CAD_QSPI_FLASHCMD_ENRDDATA(0) |
|
||||
CAD_QSPI_FLASHCMD_NUMRDDATABYTES(0) |
|
||||
CAD_QSPI_FLASHCMD_ENCMDADDR(0) |
|
||||
CAD_QSPI_FLASHCMD_ENMODEBIT(0) |
|
||||
CAD_QSPI_FLASHCMD_NUMADDRBYTES(0) |
|
||||
CAD_QSPI_FLASHCMD_ENWRDATA(1) |
|
||||
CAD_QSPI_FLASHCMD_NUMWRDATABYTES(num_bytes - 1) |
|
||||
CAD_QSPI_FLASHCMD_NUMDUMMYBYTES(dummy);
|
||||
|
||||
mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD_WRDATA0, input[0]);
|
||||
|
||||
if (num_bytes > 4)
|
||||
mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD_WRDATA1,
|
||||
input[1]);
|
||||
|
||||
return cad_qspi_stig_cmd_helper(cad_qspi_cs, cmd);
|
||||
}
|
||||
|
||||
int cad_qspi_stig_addr_cmd(uint32_t opcode, uint32_t dummy, uint32_t addr)
|
||||
{
|
||||
uint32_t cmd;
|
||||
|
||||
if (dummy > ((1 << CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES_MAX) - 1))
|
||||
return -1;
|
||||
|
||||
cmd = CAD_QSPI_FLASHCMD_OPCODE(opcode) |
|
||||
CAD_QSPI_FLASHCMD_NUMDUMMYBYTES(dummy) |
|
||||
CAD_QSPI_FLASHCMD_ENCMDADDR(1) |
|
||||
CAD_QSPI_FLASHCMD_NUMADDRBYTES(2);
|
||||
|
||||
mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD_ADDR, addr);
|
||||
|
||||
return cad_qspi_stig_cmd_helper(cad_qspi_cs, cmd);
|
||||
}
|
||||
|
||||
int cad_qspi_device_bank_select(uint32_t bank)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
status = cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_WREN, 0);
|
||||
if (status != 0)
|
||||
return status;
|
||||
|
||||
status = cad_qspi_stig_wr_cmd(CAD_QSPI_STIG_OPCODE_WREN_EXT_REG,
|
||||
0, 1, &bank);
|
||||
if (status != 0)
|
||||
return status;
|
||||
|
||||
return cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_WRDIS, 0);
|
||||
}
|
||||
|
||||
int cad_qspi_device_status(uint32_t *status)
|
||||
{
|
||||
return cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDSR, 0, 1, status);
|
||||
}
|
||||
|
||||
#if CAD_QSPI_MICRON_N25Q_SUPPORT
|
||||
int cad_qspi_n25q_enable(void)
|
||||
{
|
||||
cad_qspi_set_read_config(QSPI_FAST_READ, CAD_QSPI_INST_SINGLE,
|
||||
CAD_QSPI_ADDR_FASTREAD, CAT_QSPI_ADDR_SINGLE_IO, 1,
|
||||
0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cad_qspi_n25q_wait_for_program_and_erase(int program_only)
|
||||
{
|
||||
uint32_t status, flag_sr;
|
||||
int count = 0;
|
||||
|
||||
while (count < CAD_QSPI_COMMAND_TIMEOUT) {
|
||||
status = cad_qspi_device_status(&status);
|
||||
if (status != 0) {
|
||||
ERROR("Error getting device status\n");
|
||||
return -1;
|
||||
}
|
||||
if (!CAD_QSPI_STIG_SR_BUSY(status))
|
||||
break;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count >= CAD_QSPI_COMMAND_TIMEOUT) {
|
||||
ERROR("Timed out waiting for idle\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
|
||||
while (count < CAD_QSPI_COMMAND_TIMEOUT) {
|
||||
status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDFLGSR,
|
||||
0, 1, &flag_sr);
|
||||
if (status != 0) {
|
||||
ERROR("Error waiting program and erase.\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
if ((program_only &&
|
||||
CAD_QSPI_STIG_FLAGSR_PROGRAMREADY(flag_sr)) ||
|
||||
(!program_only &&
|
||||
CAD_QSPI_STIG_FLAGSR_ERASEREADY(flag_sr)))
|
||||
break;
|
||||
}
|
||||
|
||||
if (count >= CAD_QSPI_COMMAND_TIMEOUT)
|
||||
ERROR("Timed out waiting for program and erase\n");
|
||||
|
||||
if ((program_only && CAD_QSPI_STIG_FLAGSR_PROGRAMERROR(flag_sr)) ||
|
||||
(!program_only &&
|
||||
CAD_QSPI_STIG_FLAGSR_ERASEERROR(flag_sr))) {
|
||||
ERROR("Error programming/erasing flash\n");
|
||||
cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_CLFSR, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int cad_qspi_indirect_read_start_bank(uint32_t flash_addr, uint32_t num_bytes)
|
||||
{
|
||||
mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDRDSTADDR, flash_addr);
|
||||
mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDRDCNT, num_bytes);
|
||||
mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDRD,
|
||||
CAD_QSPI_INDRD_START |
|
||||
CAD_QSPI_INDRD_IND_OPS_DONE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int cad_qspi_indirect_write_start_bank(uint32_t flash_addr,
|
||||
uint32_t num_bytes)
|
||||
{
|
||||
mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDWRSTADDR, flash_addr);
|
||||
mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDWRCNT, num_bytes);
|
||||
mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDWR,
|
||||
CAD_QSPI_INDWR_START |
|
||||
CAD_QSPI_INDWR_INDDONE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cad_qspi_indirect_write_finish(void)
|
||||
{
|
||||
#if CAD_QSPI_MICRON_N25Q_SUPPORT
|
||||
return cad_qspi_n25q_wait_for_program_and_erase(1);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
int cad_qspi_enable(void)
|
||||
{
|
||||
int status;
|
||||
|
||||
mmio_setbits_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG, CAD_QSPI_CFG_ENABLE);
|
||||
|
||||
#if CAD_QSPI_MICRON_N25Q_SUPPORT
|
||||
status = cad_qspi_n25q_enable();
|
||||
if (status != 0)
|
||||
return status;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cad_qspi_enable_subsector_bank(uint32_t addr)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
status = cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_WREN, 0);
|
||||
if (status != 0)
|
||||
return status;
|
||||
|
||||
status = cad_qspi_stig_addr_cmd(CAD_QSPI_STIG_OPCODE_SUBSEC_ERASE, 0,
|
||||
addr);
|
||||
if (status != 0)
|
||||
return status;
|
||||
|
||||
#if CAD_QSPI_MICRON_N25Q_SUPPORT
|
||||
status = cad_qspi_n25q_wait_for_program_and_erase(0);
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
int cad_qspi_erase_subsector(uint32_t addr)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
status = cad_qspi_device_bank_select(addr >> 24);
|
||||
if (status != 0)
|
||||
return status;
|
||||
|
||||
return cad_qspi_enable_subsector_bank(addr);
|
||||
}
|
||||
|
||||
int cad_qspi_erase_sector(uint32_t addr)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
status = cad_qspi_device_bank_select(addr >> 24);
|
||||
if (status != 0)
|
||||
return status;
|
||||
|
||||
status = cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_WREN, 0);
|
||||
if (status != 0)
|
||||
return status;
|
||||
|
||||
status = cad_qspi_stig_addr_cmd(CAD_QSPI_STIG_OPCODE_SEC_ERASE, 0,
|
||||
addr);
|
||||
if (status != 0)
|
||||
return status;
|
||||
|
||||
#if CAD_QSPI_MICRON_N25Q_SUPPORT
|
||||
status = cad_qspi_n25q_wait_for_program_and_erase(0);
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
void cad_qspi_calibration(uint32_t dev_clk, uint32_t qspi_clk_mhz)
|
||||
{
|
||||
int status;
|
||||
uint32_t dev_sclk_mhz = 27; /*min value to get biggest 0xF div factor*/
|
||||
uint32_t data_cap_delay;
|
||||
uint32_t sample_rdid;
|
||||
uint32_t rdid;
|
||||
uint32_t div_actual;
|
||||
uint32_t div_bits;
|
||||
int first_pass, last_pass;
|
||||
|
||||
/*1. Set divider to bigger value (slowest SCLK)
|
||||
*2. RDID and save the value
|
||||
*/
|
||||
div_actual = (qspi_clk_mhz + (dev_sclk_mhz - 1)) / dev_sclk_mhz;
|
||||
div_bits = (((div_actual + 1) / 2) - 1);
|
||||
status = cad_qspi_set_baudrate_div(0xf);
|
||||
|
||||
status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDID,
|
||||
0, 3, &sample_rdid);
|
||||
if (status != 0)
|
||||
return;
|
||||
|
||||
/*3. Set divider to the intended frequency
|
||||
*4. Set the read delay = 0
|
||||
*5. RDID and check whether the value is same as item 2
|
||||
*6. Increase read delay and compared the value against item 2
|
||||
*7. Find the range of read delay that have same as
|
||||
* item 2 and divide it to 2
|
||||
*/
|
||||
div_actual = (qspi_clk_mhz + (dev_clk - 1)) / dev_clk;
|
||||
div_bits = (((div_actual + 1) / 2) - 1);
|
||||
status = cad_qspi_set_baudrate_div(div_bits);
|
||||
if (status != 0)
|
||||
return;
|
||||
|
||||
data_cap_delay = 0;
|
||||
first_pass = -1;
|
||||
last_pass = -1;
|
||||
|
||||
do {
|
||||
if (status != 0)
|
||||
break;
|
||||
status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDID, 0,
|
||||
3, &rdid);
|
||||
if (status != 0)
|
||||
break;
|
||||
if (rdid == sample_rdid) {
|
||||
if (first_pass == -1)
|
||||
first_pass = data_cap_delay;
|
||||
else
|
||||
last_pass = data_cap_delay;
|
||||
}
|
||||
|
||||
data_cap_delay++;
|
||||
|
||||
mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_RDDATACAP,
|
||||
CAD_QSPI_RDDATACAP_BYP(1) |
|
||||
CAD_QSPI_RDDATACAP_DELAY(data_cap_delay));
|
||||
|
||||
} while (data_cap_delay < 0x10);
|
||||
|
||||
if (first_pass > 0) {
|
||||
int diff = first_pass - last_pass;
|
||||
|
||||
data_cap_delay = first_pass + diff / 2;
|
||||
}
|
||||
|
||||
mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_RDDATACAP,
|
||||
CAD_QSPI_RDDATACAP_BYP(1) |
|
||||
CAD_QSPI_RDDATACAP_DELAY(data_cap_delay));
|
||||
status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDID, 0, 3, &rdid);
|
||||
|
||||
if (status != 0)
|
||||
return;
|
||||
}
|
||||
|
||||
int cad_qspi_int_disable(uint32_t mask)
|
||||
{
|
||||
if (cad_qspi_idle() == 0)
|
||||
return -1;
|
||||
|
||||
if ((CAD_QSPI_INT_STATUS_ALL & mask) == 0)
|
||||
return -1;
|
||||
|
||||
mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_IRQMSK, mask);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cad_qspi_set_chip_select(int cs)
|
||||
{
|
||||
cad_qspi_cs = cs;
|
||||
}
|
||||
|
||||
int cad_qspi_init(uint32_t desired_clk_freq, uint32_t clk_phase,
|
||||
uint32_t clk_pol, uint32_t csda, uint32_t csdads,
|
||||
uint32_t cseot, uint32_t cssot, uint32_t rddatacap)
|
||||
{
|
||||
int status = 0;
|
||||
uint32_t qspi_desired_clk_freq;
|
||||
uint32_t rdid = 0;
|
||||
uint32_t cap_code;
|
||||
|
||||
INFO("Initializing Qspi\n");
|
||||
|
||||
if (cad_qspi_idle() == 0) {
|
||||
ERROR("device not idle");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
status = cad_qspi_timing_config(clk_phase, clk_pol, csda, csdads,
|
||||
cseot, cssot, rddatacap);
|
||||
|
||||
if (status != 0) {
|
||||
ERROR("config set timing failure\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_REMAPADDR,
|
||||
CAD_QSPI_REMAPADDR_VALUE_SET(0));
|
||||
|
||||
status = cad_qspi_int_disable(CAD_QSPI_INT_STATUS_ALL);
|
||||
if (status != 0) {
|
||||
ERROR("failed disable\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
cad_qspi_set_baudrate_div(0xf);
|
||||
status = cad_qspi_enable();
|
||||
if (status != 0) {
|
||||
ERROR("failed enable\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
qspi_desired_clk_freq = 100;
|
||||
cad_qspi_calibration(qspi_desired_clk_freq, 50000000);
|
||||
|
||||
status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDID, 0, 3,
|
||||
&rdid);
|
||||
|
||||
if (status != 0) {
|
||||
ERROR("Error reading RDID\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: The Size code seems to be a form of BCD (binary coded decimal).
|
||||
* The first nibble is the 10's digit and the second nibble is the 1's
|
||||
* digit in the number of bytes.
|
||||
*
|
||||
* Capacity ID samples:
|
||||
* 0x15 : 16 Mb => 2 MiB => 1 << 21 ; BCD=15
|
||||
* 0x16 : 32 Mb => 4 MiB => 1 << 22 ; BCD=16
|
||||
* 0x17 : 64 Mb => 8 MiB => 1 << 23 ; BCD=17
|
||||
* 0x18 : 128 Mb => 16 MiB => 1 << 24 ; BCD=18
|
||||
* 0x19 : 256 Mb => 32 MiB => 1 << 25 ; BCD=19
|
||||
* 0x1a
|
||||
* 0x1b
|
||||
* 0x1c
|
||||
* 0x1d
|
||||
* 0x1e
|
||||
* 0x1f
|
||||
* 0x20 : 512 Mb => 64 MiB => 1 << 26 ; BCD=20
|
||||
* 0x21 : 1024 Mb => 128 MiB => 1 << 27 ; BCD=21
|
||||
*/
|
||||
|
||||
cap_code = CAD_QSPI_STIG_RDID_CAPACITYID(rdid);
|
||||
|
||||
if (!(((cap_code >> 4) > 0x9) || ((cap_code & 0xf) > 0x9))) {
|
||||
uint32_t decoded_cap = ((cap_code >> 4) * 10) +
|
||||
(cap_code & 0xf);
|
||||
qspi_device_size = 1 << (decoded_cap + 6);
|
||||
INFO("QSPI Capacity: %x\n\n", qspi_device_size);
|
||||
|
||||
} else {
|
||||
ERROR("Invalid CapacityID encountered: 0x%02x\n",
|
||||
cap_code);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cad_qspi_configure_dev_size(S10_QSPI_ADDR_BYTES,
|
||||
S10_QSPI_BYTES_PER_DEV, S10_BYTES_PER_BLOCK);
|
||||
|
||||
INFO("Flash size: %d Bytes\n", qspi_device_size);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int cad_qspi_indirect_page_bound_write(uint32_t offset,
|
||||
uint8_t *buffer, uint32_t len)
|
||||
{
|
||||
int status = 0, i;
|
||||
uint32_t write_count, write_capacity, *write_data, space,
|
||||
write_fill_level, sram_partition;
|
||||
|
||||
status = cad_qspi_indirect_write_start_bank(offset, len);
|
||||
if (status != 0)
|
||||
return status;
|
||||
|
||||
write_count = 0;
|
||||
sram_partition = CAD_QSPI_SRAMPART_ADDR(mmio_read_32(CAD_QSPI_OFFSET +
|
||||
CAD_QSPI_SRAMPART));
|
||||
write_capacity = (uint32_t) CAD_QSPI_SRAM_FIFO_ENTRY_COUNT -
|
||||
sram_partition;
|
||||
|
||||
while (write_count < len) {
|
||||
write_fill_level = CAD_QSPI_SRAMFILL_INDWRPART(
|
||||
mmio_read_32(CAD_QSPI_OFFSET +
|
||||
CAD_QSPI_SRAMFILL));
|
||||
space = LESS(write_capacity - write_fill_level,
|
||||
(len - write_count) / sizeof(uint32_t));
|
||||
write_data = (uint32_t *)(buffer + write_count);
|
||||
for (i = 0; i < space; ++i)
|
||||
mmio_write_32(CAD_QSPIDATA_OFST, *write_data++);
|
||||
|
||||
write_count += space * sizeof(uint32_t);
|
||||
}
|
||||
return cad_qspi_indirect_write_finish();
|
||||
}
|
||||
|
||||
int cad_qspi_read_bank(uint8_t *buffer, uint32_t offset, uint32_t size)
|
||||
{
|
||||
int status;
|
||||
uint32_t read_count = 0, *read_data;
|
||||
int level = 1, count = 0, i;
|
||||
|
||||
status = cad_qspi_indirect_read_start_bank(offset, size);
|
||||
|
||||
if (status != 0)
|
||||
return status;
|
||||
|
||||
while (read_count < size) {
|
||||
do {
|
||||
level = CAD_QSPI_SRAMFILL_INDRDPART(
|
||||
mmio_read_32(CAD_QSPI_OFFSET +
|
||||
CAD_QSPI_SRAMFILL));
|
||||
read_data = (uint32_t *)(buffer + read_count);
|
||||
for (i = 0; i < level; ++i)
|
||||
*read_data++ = mmio_read_32(CAD_QSPIDATA_OFST);
|
||||
|
||||
read_count += level * sizeof(uint32_t);
|
||||
count++;
|
||||
} while (level > 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cad_qspi_write_bank(uint32_t offset, uint8_t *buffer, uint32_t size)
|
||||
{
|
||||
int status = 0;
|
||||
uint32_t page_offset = offset & (CAD_QSPI_PAGE_SIZE - 1);
|
||||
uint32_t write_size = LESS(size, CAD_QSPI_PAGE_SIZE - page_offset);
|
||||
|
||||
while (size) {
|
||||
status = cad_qspi_indirect_page_bound_write(offset, buffer,
|
||||
write_size);
|
||||
if (status != 0)
|
||||
break;
|
||||
|
||||
offset += write_size;
|
||||
buffer += write_size;
|
||||
size -= write_size;
|
||||
write_size = LESS(size, CAD_QSPI_PAGE_SIZE);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int cad_qspi_read(void *buffer, uint32_t offset, uint32_t size)
|
||||
{
|
||||
uint32_t bank_count, bank_addr, bank_offset, copy_len;
|
||||
uint8_t *read_data;
|
||||
int i, status;
|
||||
|
||||
status = 0;
|
||||
|
||||
if ((offset >= qspi_device_size) ||
|
||||
(offset + size - 1 >= qspi_device_size) ||
|
||||
(size == 0) ||
|
||||
((long) ((int *)buffer) & 0x3) ||
|
||||
(offset & 0x3) ||
|
||||
(size & 0x3)) {
|
||||
ERROR("Invalid read parameter");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (CAD_QSPI_INDRD_RD_STAT(mmio_read_32(CAD_QSPI_OFFSET +
|
||||
CAD_QSPI_INDRD))) {
|
||||
ERROR("Read in progress");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* bank_count : Number of bank(s) affected, including partial banks.
|
||||
* bank_addr : Aligned address of the first bank,
|
||||
* including partial bank.
|
||||
* bank_ofst : The offset of the bank to read.
|
||||
* Only used when reading the first bank.
|
||||
*/
|
||||
bank_count = CAD_QSPI_BANK_ADDR(offset + size - 1) -
|
||||
CAD_QSPI_BANK_ADDR(offset) + 1;
|
||||
bank_addr = offset & CAD_QSPI_BANK_ADDR_MSK;
|
||||
bank_offset = offset & (CAD_QSPI_BANK_SIZE - 1);
|
||||
|
||||
read_data = (uint8_t *)buffer;
|
||||
|
||||
copy_len = LESS(size, CAD_QSPI_BANK_SIZE - bank_offset);
|
||||
|
||||
for (i = 0; i < bank_count; ++i) {
|
||||
status = cad_qspi_device_bank_select(CAD_QSPI_BANK_ADDR(
|
||||
bank_addr));
|
||||
if (status != 0)
|
||||
break;
|
||||
status = cad_qspi_read_bank(read_data, bank_offset, copy_len);
|
||||
if (status != 0)
|
||||
break;
|
||||
|
||||
bank_addr += CAD_QSPI_BANK_SIZE;
|
||||
read_data += copy_len;
|
||||
size -= copy_len;
|
||||
bank_offset = 0;
|
||||
copy_len = LESS(size, CAD_QSPI_BANK_SIZE);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int cad_qspi_erase(uint32_t offset, uint32_t size)
|
||||
{
|
||||
int status = 0;
|
||||
uint32_t subsector_offset = offset & (CAD_QSPI_SUBSECTOR_SIZE - 1);
|
||||
uint32_t erase_size = LESS(size,
|
||||
CAD_QSPI_SUBSECTOR_SIZE - subsector_offset);
|
||||
|
||||
while (size) {
|
||||
status = cad_qspi_erase_subsector(offset);
|
||||
if (status != 0)
|
||||
break;
|
||||
|
||||
offset += erase_size;
|
||||
size -= erase_size;
|
||||
erase_size = LESS(size, CAD_QSPI_SUBSECTOR_SIZE);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int cad_qspi_write(void *buffer, uint32_t offset, uint32_t size)
|
||||
{
|
||||
int status, i;
|
||||
uint32_t bank_count, bank_addr, bank_offset, copy_len;
|
||||
uint8_t *write_data;
|
||||
|
||||
status = 0;
|
||||
|
||||
if ((offset >= qspi_device_size) ||
|
||||
(offset + size - 1 >= qspi_device_size) ||
|
||||
(size == 0) ||
|
||||
((long)buffer & 0x3) ||
|
||||
(offset & 0x3) ||
|
||||
(size & 0x3))
|
||||
return -2;
|
||||
|
||||
if (CAD_QSPI_INDWR_RDSTAT(mmio_read_32(CAD_QSPI_OFFSET +
|
||||
CAD_QSPI_INDWR))) {
|
||||
ERROR("QSPI Error: Write in progress\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bank_count = CAD_QSPI_BANK_ADDR(offset + size - 1) -
|
||||
CAD_QSPI_BANK_ADDR(offset) + 1;
|
||||
bank_addr = offset & CAD_QSPI_BANK_ADDR_MSK;
|
||||
bank_offset = offset & (CAD_QSPI_BANK_SIZE - 1);
|
||||
|
||||
write_data = buffer;
|
||||
|
||||
copy_len = LESS(size, CAD_QSPI_BANK_SIZE - bank_offset);
|
||||
|
||||
for (i = 0; i < bank_count; ++i) {
|
||||
status = cad_qspi_device_bank_select(
|
||||
CAD_QSPI_BANK_ADDR(bank_addr));
|
||||
if (status != 0)
|
||||
break;
|
||||
|
||||
status = cad_qspi_write_bank(bank_offset, write_data,
|
||||
copy_len);
|
||||
if (status != 0)
|
||||
break;
|
||||
|
||||
bank_addr += CAD_QSPI_BANK_SIZE;
|
||||
write_data += copy_len;
|
||||
size -= copy_len;
|
||||
bank_offset = 0;
|
||||
|
||||
copy_len = LESS(size, CAD_QSPI_BANK_SIZE);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int cad_qspi_update(void *Buffer, uint32_t offset, uint32_t size)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
status = cad_qspi_erase(offset, size);
|
||||
if (status != 0)
|
||||
return status;
|
||||
|
||||
return cad_qspi_write(Buffer, offset, size);
|
||||
}
|
||||
|
||||
void cad_qspi_reset(void)
|
||||
{
|
||||
cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_RESET_EN, 0);
|
||||
cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_RESET_MEM, 0);
|
||||
}
|
||||
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef __CAD_QSPI_H__
|
||||
#define __CAD_QSPI_H__
|
||||
|
||||
#define CAD_QSPI_MICRON_N25Q_SUPPORT 1
|
||||
|
||||
#define CAD_QSPI_OFFSET 0xff8d2000
|
||||
|
||||
#define CAD_INVALID -1
|
||||
#define CAD_QSPI_ERROR -2
|
||||
|
||||
#define CAD_QSPI_ADDR_FASTREAD 0
|
||||
#define CAD_QSPI_ADDR_FASTREAD_DUAL_IO 1
|
||||
#define CAD_QSPI_ADDR_FASTREAD_QUAD_IO 2
|
||||
#define CAT_QSPI_ADDR_SINGLE_IO 0
|
||||
#define CAT_QSPI_ADDR_DUAL_IO 1
|
||||
#define CAT_QSPI_ADDR_QUAD_IO 2
|
||||
|
||||
#define CAD_QSPI_BANK_ADDR(x) ((x) >> 24)
|
||||
#define CAD_QSPI_BANK_ADDR_MSK 0xff000000
|
||||
|
||||
#define CAD_QSPI_COMMAND_TIMEOUT 0x10000000
|
||||
|
||||
#define CAD_QSPI_CFG 0x0
|
||||
#define CAD_QSPI_CFG_BAUDDIV_MSK 0xff87ffff
|
||||
#define CAD_QSPI_CFG_BAUDDIV(x) (((x) << 19) & 0x780000)
|
||||
#define CAD_QSPI_CFG_CS_MSK ~0x3c00
|
||||
#define CAD_QSPI_CFG_CS(x) (((x) << 11))
|
||||
#define CAD_QSPI_CFG_ENABLE (1 << 0)
|
||||
#define CAD_QSPI_CFG_ENDMA_CLR_MSK 0xffff7fff
|
||||
#define CAD_QSPI_CFG_IDLE (1 << 31)
|
||||
#define CAD_QSPI_CFG_SELCLKPHASE_CLR_MSK 0xfffffffb
|
||||
#define CAD_QSPI_CFG_SELCLKPOL_CLR_MSK 0xfffffffd
|
||||
|
||||
#define CAD_QSPIDATA_OFST 0xff900000
|
||||
|
||||
#define CAD_QSPI_DELAY 0xc
|
||||
#define CAD_QSPI_DELAY_CSSOT(x) (((x) & 0xff) << 0)
|
||||
#define CAD_QSPI_DELAY_CSEOT(x) (((x) & 0xff) << 8)
|
||||
#define CAD_QSPI_DELAY_CSDADS(x) (((x) & 0xff) << 16)
|
||||
#define CAD_QSPI_DELAY_CSDA(x) (((x) & 0xff) << 24)
|
||||
|
||||
#define CAD_QSPI_DEVSZ 0x14
|
||||
#define CAD_QSPI_DEVSZ_ADDR_BYTES(x) ((x) << 0)
|
||||
#define CAD_QSPI_DEVSZ_BYTES_PER_PAGE(x) ((x) << 4)
|
||||
#define CAD_QSPI_DEVSZ_BYTES_PER_BLOCK(x) ((x) << 16)
|
||||
|
||||
#define CAD_QSPI_DEVWR 0x8
|
||||
#define CAD_QSPI_DEVRD 0x4
|
||||
#define CAD_QSPI_DEV_OPCODE(x) (((x) & 0xff) << 0)
|
||||
#define CAD_QSPI_DEV_INST_TYPE(x) (((x) & 0x03) << 8)
|
||||
#define CAD_QSPI_DEV_ADDR_TYPE(x) (((x) & 0x03) << 12)
|
||||
#define CAD_QSPI_DEV_DATA_TYPE(x) (((x) & 0x03) << 16)
|
||||
#define CAD_QSPI_DEV_MODE_BIT(x) (((x) & 0x01) << 20)
|
||||
#define CAD_QSPI_DEV_DUMMY_CLK_CYCLE(x) (((x) & 0x0f) << 24)
|
||||
|
||||
#define CAD_QSPI_FLASHCMD 0x90
|
||||
#define CAD_QSPI_FLASHCMD_ADDR 0x94
|
||||
#define CAD_QSPI_FLASHCMD_EXECUTE 0x1
|
||||
#define CAD_QSPI_FLASHCMD_EXECUTE_STAT 0x2
|
||||
#define CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES_MAX 5
|
||||
#define CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES(x) (((x) << 7) & 0x000f80)
|
||||
#define CAD_QSPI_FLASHCMD_OPCODE(x) (((x) & 0xff) << 24)
|
||||
#define CAD_QSPI_FLASHCMD_ENRDDATA(x) (((x) & 1) << 23)
|
||||
#define CAD_QSPI_FLASHCMD_NUMRDDATABYTES(x) (((x) & 0xf) << 20)
|
||||
#define CAD_QSPI_FLASHCMD_ENCMDADDR(x) (((x) & 1) << 19)
|
||||
#define CAD_QSPI_FLASHCMD_ENMODEBIT(x) (((x) & 1) << 18)
|
||||
#define CAD_QSPI_FLASHCMD_NUMADDRBYTES(x) (((x) & 0x3) << 16)
|
||||
#define CAD_QSPI_FLASHCMD_ENWRDATA(x) (((x) & 1) << 15)
|
||||
#define CAD_QSPI_FLASHCMD_NUMWRDATABYTES(x) (((x) & 0x7) << 12)
|
||||
#define CAD_QSPI_FLASHCMD_NUMDUMMYBYTES(x) (((x) & 0x1f) << 7)
|
||||
#define CAD_QSPI_FLASHCMD_RDDATA0 0xa0
|
||||
#define CAD_QSPI_FLASHCMD_RDDATA1 0xa4
|
||||
#define CAD_QSPI_FLASHCMD_WRDATA0 0xa8
|
||||
#define CAD_QSPI_FLASHCMD_WRDATA1 0xac
|
||||
|
||||
#define CAD_QSPI_RDDATACAP 0x10
|
||||
#define CAD_QSPI_RDDATACAP_BYP(x) (((x) & 1) << 0)
|
||||
#define CAD_QSPI_RDDATACAP_DELAY(x) (((x) & 0xf) << 1)
|
||||
|
||||
#define CAD_QSPI_REMAPADDR 0x24
|
||||
#define CAD_QSPI_REMAPADDR_VALUE_SET(x) (((x) & 0xffffffff) << 0)
|
||||
|
||||
#define CAD_QSPI_SRAMPART 0x18
|
||||
#define CAD_QSPI_SRAMFILL 0x2c
|
||||
#define CAD_QSPI_SRAMPART_ADDR(x) (((x) >> 0) & 0x3ff)
|
||||
#define CAD_QSPI_SRAM_FIFO_ENTRY_COUNT (512 / sizeof(uint32_t))
|
||||
#define CAD_QSPI_SRAMFILL_INDWRPART(x) (((x) >> 16) & 0x00ffff)
|
||||
#define CAD_QSPI_SRAMFILL_INDRDPART(x) (((x) >> 0) & 0x00ffff)
|
||||
|
||||
#define CAD_QSPI_SELCLKPHASE(x) (((x) & 1) << 2)
|
||||
#define CAD_QSPI_SELCLKPOL(x) (((x) & 1) << 1)
|
||||
|
||||
#define CAD_QSPI_STIG_FLAGSR_PROGRAMREADY(x) (((x) >> 7) & 1)
|
||||
#define CAD_QSPI_STIG_FLAGSR_ERASEREADY(x) (((x) >> 7) & 1)
|
||||
#define CAD_QSPI_STIG_FLAGSR_ERASEERROR(x) (((x) >> 5) & 1)
|
||||
#define CAD_QSPI_STIG_FLAGSR_PROGRAMERROR(x) (((x) >> 4) & 1)
|
||||
#define CAD_QSPI_STIG_OPCODE_CLFSR 0x50
|
||||
#define CAD_QSPI_STIG_OPCODE_RDID 0x9f
|
||||
#define CAD_QSPI_STIG_OPCODE_WRDIS 0x4
|
||||
#define CAD_QSPI_STIG_OPCODE_WREN 0x6
|
||||
#define CAD_QSPI_STIG_OPCODE_SUBSEC_ERASE 0x20
|
||||
#define CAD_QSPI_STIG_OPCODE_SEC_ERASE 0xd8
|
||||
#define CAD_QSPI_STIG_OPCODE_WREN_EXT_REG 0xc5
|
||||
#define CAD_QSPI_STIG_OPCODE_DIE_ERASE 0xc4
|
||||
#define CAD_QSPI_STIG_OPCODE_BULK_ERASE 0xc7
|
||||
#define CAD_QSPI_STIG_OPCODE_RDSR 0x5
|
||||
#define CAD_QSPI_STIG_OPCODE_RDFLGSR 0x70
|
||||
#define CAD_QSPI_STIG_OPCODE_RESET_EN 0x66
|
||||
#define CAD_QSPI_STIG_OPCODE_RESET_MEM 0x99
|
||||
#define CAD_QSPI_STIG_RDID_CAPACITYID(x) (((x) >> 16) & 0xff)
|
||||
#define CAD_QSPI_STIG_SR_BUSY(x) (((x) >> 0) & 1)
|
||||
|
||||
|
||||
#define CAD_QSPI_INST_SINGLE 0
|
||||
#define CAD_QSPI_INST_DUAL 1
|
||||
#define CAD_QSPI_INST_QUAD 2
|
||||
|
||||
#define CAD_QSPI_INDRDSTADDR 0x68
|
||||
#define CAD_QSPI_INDRDCNT 0x6c
|
||||
#define CAD_QSPI_INDRD 0x60
|
||||
#define CAD_QSPI_INDRD_RD_STAT(x) (((x) >> 2) & 1)
|
||||
#define CAD_QSPI_INDRD_START 1
|
||||
#define CAD_QSPI_INDRD_IND_OPS_DONE 0x20
|
||||
|
||||
#define CAD_QSPI_INDWR 0x70
|
||||
#define CAD_QSPI_INDWR_RDSTAT(x) (((x) >> 2) & 1)
|
||||
#define CAD_QSPI_INDWRSTADDR 0x78
|
||||
#define CAD_QSPI_INDWRCNT 0x7c
|
||||
#define CAD_QSPI_INDWR 0x70
|
||||
#define CAD_QSPI_INDWR_START 0x1
|
||||
#define CAD_QSPI_INDWR_INDDONE 0x20
|
||||
|
||||
#define CAD_QSPI_INT_STATUS_ALL 0x0000ffff
|
||||
|
||||
#define CAD_QSPI_N25Q_DIE_SIZE 0x02000000
|
||||
#define CAD_QSPI_BANK_SIZE 0x01000000
|
||||
#define CAD_QSPI_PAGE_SIZE 0x00000100
|
||||
|
||||
#define CAD_QSPI_IRQMSK 0x44
|
||||
|
||||
#define CAD_QSPI_SUBSECTOR_SIZE 0x1000
|
||||
|
||||
#define S10_QSPI_ADDR_BYTES 2
|
||||
#define S10_QSPI_BYTES_PER_DEV 256
|
||||
#define S10_BYTES_PER_BLOCK 16
|
||||
|
||||
#define QSPI_FAST_READ 0xb
|
||||
|
||||
// QSPI CONFIGURATIONS
|
||||
|
||||
#define QSPI_CONFIG_CPOL 1
|
||||
#define QSPI_CONFIG_CPHA 1
|
||||
|
||||
#define QSPI_CONFIG_CSSOT 0x14
|
||||
#define QSPI_CONFIG_CSEOT 0x14
|
||||
#define QSPI_CONFIG_CSDADS 0xff
|
||||
#define QSPI_CONFIG_CSDA 0xc8
|
||||
|
||||
int cad_qspi_init(uint32_t desired_clk_freq, uint32_t clk_phase,
|
||||
uint32_t clk_pol, uint32_t csda, uint32_t csdads,
|
||||
uint32_t cseot, uint32_t cssot, uint32_t rddatacap);
|
||||
void cad_qspi_set_chip_select(int cs);
|
||||
int cad_qspi_erase(uint32_t offset, uint32_t size);
|
||||
int cad_qspi_write(void *buffer, uint32_t offset, uint32_t size);
|
||||
int cad_qspi_read(void *buffer, uint32_t offset, uint32_t size);
|
||||
int cad_qspi_update(void *buffer, uint32_t offset, uint32_t size);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue