ECPIX-5: Wire up SPI flash

The flash chip on my board is an ISSI IS26LP256P chip.  The ISSI chip
requires slightly different setup for quad mode from the other brands,
but works fine with the existing SPI flash interface logic here.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
pull/428/head
Paul Mackerras 8 months ago
parent 166e3f4ab2
commit 82dacf2c1c

@ -43,3 +43,17 @@ LOCATE COMP "led8_b_n" SITE "P22";
IOBUF PORT "led8_r_n" IO_TYPE=LVCMOS33; IOBUF PORT "led8_r_n" IO_TYPE=LVCMOS33;
IOBUF PORT "led8_g_n" IO_TYPE=LVCMOS33; IOBUF PORT "led8_g_n" IO_TYPE=LVCMOS33;
IOBUF PORT "led8_b_n" IO_TYPE=LVCMOS33; IOBUF PORT "led8_b_n" IO_TYPE=LVCMOS33;

// We use USRMCLK instead for clk
// LOCATE COMP "spi_flash_clk" SITE "U16";
// IOBUF PORT "spi_flash_clk" IO_TYPE=LVCMOS33;
LOCATE COMP "spi_flash_cs_n" SITE "AA2";
IOBUF PORT "spi_flash_cs_n" IO_TYPE=LVCMOS33;
LOCATE COMP "spi_flash_mosi" SITE "AE2";
IOBUF PORT "spi_flash_mosi" IO_TYPE=LVCMOS33;
LOCATE COMP "spi_flash_miso" SITE "AD2";
IOBUF PORT "spi_flash_miso" IO_TYPE=LVCMOS33;
LOCATE COMP "spi_flash_wp_n" SITE "AF2";
IOBUF PORT "spi_flash_wp_n" IO_TYPE=LVCMOS33;
LOCATE COMP "spi_flash_hold_n" SITE "AE1";
IOBUF PORT "spi_flash_hold_n" IO_TYPE=LVCMOS33;

@ -17,6 +17,9 @@ entity toplevel is
USE_LITEDRAM : boolean := false; USE_LITEDRAM : boolean := false;
NO_BRAM : boolean := false; NO_BRAM : boolean := false;
SCLK_STARTUPE2 : boolean := false; SCLK_STARTUPE2 : boolean := false;
SPI_FLASH_OFFSET : integer := 4194304;
SPI_FLASH_DEF_CKDV : natural := 0;
SPI_FLASH_DEF_QUAD : boolean := true;
LOG_LENGTH : natural := 0; LOG_LENGTH : natural := 0;
UART_IS_16550 : boolean := true; UART_IS_16550 : boolean := true;
HAS_UART1 : boolean := false; HAS_UART1 : boolean := false;
@ -45,7 +48,14 @@ entity toplevel is
led7_b_n : out std_ulogic; led7_b_n : out std_ulogic;
led8_r_n : out std_ulogic; led8_r_n : out std_ulogic;
led8_g_n : out std_ulogic; led8_g_n : out std_ulogic;
led8_b_n : out std_ulogic led8_b_n : out std_ulogic;

-- SPI
spi_flash_cs_n : out std_ulogic;
spi_flash_mosi : inout std_ulogic;
spi_flash_miso : inout std_ulogic;
spi_flash_wp_n : inout std_ulogic;
spi_flash_hold_n : inout std_ulogic


); );
end entity toplevel; end entity toplevel;
@ -60,6 +70,14 @@ architecture behaviour of toplevel is
signal system_clk : std_ulogic; signal system_clk : std_ulogic;
signal system_clk_locked : std_ulogic; signal system_clk_locked : std_ulogic;


-- SPI flash
signal spi_sck : std_ulogic;
signal spi_sck_ts : std_ulogic;
signal spi_cs_n : std_ulogic;
signal spi_sdat_o : std_ulogic_vector(3 downto 0);
signal spi_sdat_oe : std_ulogic_vector(3 downto 0);
signal spi_sdat_i : std_ulogic_vector(3 downto 0);

-- Fixup various memory sizes based on generics -- Fixup various memory sizes based on generics
function get_bram_size return natural is function get_bram_size return natural is
begin begin
@ -82,6 +100,15 @@ architecture behaviour of toplevel is
constant BRAM_SIZE : natural := get_bram_size; constant BRAM_SIZE : natural := get_bram_size;
constant PAYLOAD_SIZE : natural := get_payload_size; constant PAYLOAD_SIZE : natural := get_payload_size;


COMPONENT USRMCLK
PORT(
USRMCLKI : IN STD_ULOGIC;
USRMCLKTS : IN STD_ULOGIC
);
END COMPONENT;
attribute syn_noprune: boolean ;
attribute syn_noprune of USRMCLK: component is true;

begin begin


-- Main SoC -- Main SoC
@ -96,7 +123,11 @@ begin
HAS_DRAM => USE_LITEDRAM, HAS_DRAM => USE_LITEDRAM,
DRAM_SIZE => 512 * 1024 * 1024, DRAM_SIZE => 512 * 1024 * 1024,
DRAM_INIT_SIZE => PAYLOAD_SIZE, DRAM_INIT_SIZE => PAYLOAD_SIZE,
HAS_SPI_FLASH => false, HAS_SPI_FLASH => true,
SPI_FLASH_DLINES => 4,
SPI_FLASH_OFFSET => SPI_FLASH_OFFSET,
SPI_FLASH_DEF_CKDV => SPI_FLASH_DEF_CKDV,
SPI_FLASH_DEF_QUAD => SPI_FLASH_DEF_QUAD,
LOG_LENGTH => LOG_LENGTH, LOG_LENGTH => LOG_LENGTH,
UART0_IS_16550 => UART_IS_16550, UART0_IS_16550 => UART_IS_16550,
HAS_UART1 => HAS_UART1, HAS_UART1 => HAS_UART1,
@ -111,7 +142,32 @@ begin


-- UART signals -- UART signals
uart0_txd => uart0_txd, uart0_txd => uart0_txd,
uart0_rxd => uart0_rxd uart0_rxd => uart0_rxd,

-- SPI signals
spi_flash_sck => spi_sck,
spi_flash_cs_n => spi_cs_n,
spi_flash_sdat_o => spi_sdat_o,
spi_flash_sdat_oe => spi_sdat_oe,
spi_flash_sdat_i => spi_sdat_i
);

-- SPI Flash
--
spi_flash_cs_n <= spi_cs_n;
spi_flash_mosi <= spi_sdat_o(0) when spi_sdat_oe(0) = '1' else 'Z';
spi_flash_miso <= spi_sdat_o(1) when spi_sdat_oe(1) = '1' else 'Z';
spi_flash_wp_n <= spi_sdat_o(2) when spi_sdat_oe(2) = '1' else 'Z';
spi_flash_hold_n <= spi_sdat_o(3) when spi_sdat_oe(3) = '1' else 'Z';
spi_sdat_i(0) <= spi_flash_mosi;
spi_sdat_i(1) <= spi_flash_miso;
spi_sdat_i(2) <= spi_flash_wp_n;
spi_sdat_i(3) <= spi_flash_hold_n;
spi_sck_ts <= '0';

uclk: USRMCLK port map (
USRMCLKI => spi_sck,
USRMCLKTS => spi_sck_ts
); );


nodram: if not USE_LITEDRAM generate nodram: if not USE_LITEDRAM generate

@ -41,6 +41,7 @@ void flush_cpu_icache(void)
#define SPI_CMD_READ 0x03 #define SPI_CMD_READ 0x03
#define SPI_CMD_DUAL_FREAD 0x3b #define SPI_CMD_DUAL_FREAD 0x3b
#define SPI_CMD_QUAD_FREAD 0x6b #define SPI_CMD_QUAD_FREAD 0x6b
#define SPI_CMD_QUAD_FREAD_4BA 0x6c
#define SPI_CMD_RDCR 0x35 #define SPI_CMD_RDCR 0x35
#define SPI_CMD_WREN 0x06 #define SPI_CMD_WREN 0x06
#define SPI_CMD_PP 0x02 #define SPI_CMD_PP 0x02
@ -106,10 +107,44 @@ static void check_spansion_quad_mode(void)
wait_wip(); wait_wip();
} }


static uint32_t check_enable_issi_quad(void)
{
uint8_t sr;

/* Read status register to see if quad mode is already enabled */
fl_cs_on();
writeb(SPI_CMD_RDSR, SPI_FCTRL_BASE + SPI_REG_DATA);
sr = readb(SPI_FCTRL_BASE + SPI_REG_DATA);
fl_cs_off();
if ((sr & 0x40) == 0) {
printf(" [enabling quad]");
send_wren();
fl_cs_on();
writeb(SPI_CMD_WWR, SPI_FCTRL_BASE + SPI_REG_DATA);
writeb(sr | 0x40, SPI_FCTRL_BASE + SPI_REG_DATA);
fl_cs_off();
wait_wip();
}

/* Enable quad mode and 4B addresses, 8 dummy cycles */
return SPI_CMD_QUAD_FREAD_4BA |
(0x07 << SPI_REG_AUTO_CFG_DUMMIES_SHIFT) |
SPI_REG_AUT_CFG_MODE_QUAD | SPI_REG_AUTO_CFG_ADDR4 |
(0x20 << SPI_REG_AUTO_CFG_CSTOUT_SHIFT);
}

static bool check_flash(void) static bool check_flash(void)
{ {
bool quad = false; bool quad = false;
uint8_t id[3]; uint8_t id[3];
uint32_t autocfg;

/* default auto mode configuration for quad reads: */
/* Enable quad mode, 8 dummy clocks, 32 cycles CS timeout */
autocfg = SPI_CMD_QUAD_FREAD |
(0x07 << SPI_REG_AUTO_CFG_DUMMIES_SHIFT) |
SPI_REG_AUT_CFG_MODE_QUAD |
(0x20 << SPI_REG_AUTO_CFG_CSTOUT_SHIFT);


fl_cs_on(); fl_cs_on();
writeb(SPI_CMD_RDID, SPI_FCTRL_BASE + SPI_REG_DATA); writeb(SPI_CMD_RDID, SPI_FCTRL_BASE + SPI_REG_DATA);
@ -134,6 +169,13 @@ static bool check_flash(void)
printf(" Micron"); printf(" Micron");
quad = true; quad = true;
} }
if (id[0] == 0x9d && (id[1] & ~0x10) == 0x60 &&
id[2] == 0x19) {
/* ISSI IS25LP256D or IS25WP256D */
printf(" ISSI");
autocfg = check_enable_issi_quad();
quad = true;
}
if (quad) { if (quad) {
uint32_t cfg; uint32_t cfg;
printf(" [quad IO mode]"); printf(" [quad IO mode]");
@ -141,12 +183,8 @@ static bool check_flash(void)
/* Preserve the default clock div for the board */ /* Preserve the default clock div for the board */
cfg = readl(SPI_FCTRL_BASE + SPI_REG_AUTO_CFG); cfg = readl(SPI_FCTRL_BASE + SPI_REG_AUTO_CFG);
cfg &= SPI_REG_AUTO_CFG_CKDIV_MASK; cfg &= SPI_REG_AUTO_CFG_CKDIV_MASK;
cfg |= autocfg;


/* Enable quad mode, 8 dummy clocks, 32 cycles CS timeout */
cfg |= SPI_CMD_QUAD_FREAD |
(0x07 << SPI_REG_AUTO_CFG_DUMMIES_SHIFT) |
SPI_REG_AUT_CFG_MODE_QUAD |
(0x20 << SPI_REG_AUTO_CFG_CSTOUT_SHIFT);
writel(cfg, SPI_FCTRL_BASE + SPI_REG_AUTO_CFG); writel(cfg, SPI_FCTRL_BASE + SPI_REG_AUTO_CFG);
} }
printf("\n"); printf("\n");

Loading…
Cancel
Save