Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
adam.huang
Arm Trusted Firmware
Commits
0976b348
Unverified
Commit
0976b348
authored
Mar 13, 2019
by
Soby Mathew
Committed by
GitHub
Mar 13, 2019
Browse files
Merge pull request #1873 from hadi-asyrafi/driver_qspi
intel: Add driver for QSPI
parents
d0759c2c
150f1bc2
Changes
2
Hide whitespace changes
Inline
Side-by-side
plat/intel/soc/stratix10/drivers/qspi/cadence_qspi.c
0 → 100644
View file @
0976b348
/*
* 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
);
}
plat/intel/soc/stratix10/drivers/qspi/cadence_qspi.h
0 → 100644
View file @
0976b348
/*
* 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
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment