diff --git a/constraints/ecpix-5.lpf b/constraints/ecpix-5.lpf index 6517b0f..1748601 100644 --- a/constraints/ecpix-5.lpf +++ b/constraints/ecpix-5.lpf @@ -43,3 +43,17 @@ LOCATE COMP "led8_b_n" SITE "P22"; IOBUF PORT "led8_r_n" IO_TYPE=LVCMOS33; IOBUF PORT "led8_g_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; diff --git a/fpga/top-ecpix5.vhdl b/fpga/top-ecpix5.vhdl index 077b801..ee855dc 100644 --- a/fpga/top-ecpix5.vhdl +++ b/fpga/top-ecpix5.vhdl @@ -17,6 +17,9 @@ entity toplevel is USE_LITEDRAM : boolean := false; NO_BRAM : 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; UART_IS_16550 : boolean := true; HAS_UART1 : boolean := false; @@ -45,7 +48,14 @@ entity toplevel is led7_b_n : out std_ulogic; led8_r_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; @@ -60,6 +70,14 @@ architecture behaviour of toplevel is signal system_clk : 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 function get_bram_size return natural is begin @@ -82,6 +100,15 @@ architecture behaviour of toplevel is constant BRAM_SIZE : natural := get_bram_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 -- Main SoC @@ -96,7 +123,11 @@ begin HAS_DRAM => USE_LITEDRAM, DRAM_SIZE => 512 * 1024 * 1024, 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, UART0_IS_16550 => UART_IS_16550, HAS_UART1 => HAS_UART1, @@ -111,9 +142,34 @@ begin -- UART signals 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 signal div2 : std_ulogic := '0'; begin diff --git a/litedram/gen-src/sdram_init/main.c b/litedram/gen-src/sdram_init/main.c index 2d99410..9bf98d4 100644 --- a/litedram/gen-src/sdram_init/main.c +++ b/litedram/gen-src/sdram_init/main.c @@ -41,6 +41,7 @@ void flush_cpu_icache(void) #define SPI_CMD_READ 0x03 #define SPI_CMD_DUAL_FREAD 0x3b #define SPI_CMD_QUAD_FREAD 0x6b +#define SPI_CMD_QUAD_FREAD_4BA 0x6c #define SPI_CMD_RDCR 0x35 #define SPI_CMD_WREN 0x06 #define SPI_CMD_PP 0x02 @@ -106,10 +107,44 @@ static void check_spansion_quad_mode(void) 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) { bool quad = false; 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(); writeb(SPI_CMD_RDID, SPI_FCTRL_BASE + SPI_REG_DATA); @@ -134,6 +169,13 @@ static bool check_flash(void) printf(" Micron"); 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) { uint32_t cfg; printf(" [quad IO mode]"); @@ -141,12 +183,8 @@ static bool check_flash(void) /* Preserve the default clock div for the board */ cfg = readl(SPI_FCTRL_BASE + SPI_REG_AUTO_CFG); 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); } printf("\n");