spi: Send dummy clocks at boot

When using an FPGA which routes the SPI clock via STARTUPE2 as is
done on the Nexys Video (or optionally on Arty), the HW needs at
least 3 beats of that clock to complete the switch from the internal
config clock to the one we provide.

This works around it by having the SPI controller send 8 dummy
clocks at boot time with CS held high.

Without this, flash identification will fail those boards

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
jtag-port
Benjamin Herrenschmidt 4 years ago
parent bf36ea365b
commit 3c2739e10a

@ -11,6 +11,9 @@ entity spi_flash_ctrl is
DEF_CLK_DIV : natural := 2; -- Clock divider SCK = CLK/((CLK_DIV+1)*2) DEF_CLK_DIV : natural := 2; -- Clock divider SCK = CLK/((CLK_DIV+1)*2)
DEF_QUAD_READ : boolean := false; -- Use quad read with 8 clk dummy DEF_QUAD_READ : boolean := false; -- Use quad read with 8 clk dummy


-- Dummy clocks after boot
BOOT_CLOCKS : boolean := true; -- Send 8 dummy clocks after boot

-- Number of data lines (1=MISO/MOSI, otherwise 2 or 4) -- Number of data lines (1=MISO/MOSI, otherwise 2 or 4)
DATA_LINES : positive := 1 DATA_LINES : positive := 1
); );
@ -103,7 +106,7 @@ architecture rtl of spi_flash_ctrl is
constant DEFAULT_CS_TIMEOUT : integer := 32; constant DEFAULT_CS_TIMEOUT : integer := 32;


-- Automatic mode state -- Automatic mode state
type auto_state_t is (AUTO_IDLE, AUTO_CS_ON, AUTO_CMD, type auto_state_t is (AUTO_BOOT, AUTO_IDLE, AUTO_CS_ON, AUTO_CMD,
AUTO_ADR0, AUTO_ADR1, AUTO_ADR2, AUTO_ADR3, AUTO_ADR0, AUTO_ADR1, AUTO_ADR2, AUTO_ADR3,
AUTO_DUMMY, AUTO_DUMMY,
AUTO_DAT0, AUTO_DAT1, AUTO_DAT2, AUTO_DAT3, AUTO_DAT0, AUTO_DAT1, AUTO_DAT2, AUTO_DAT3,
@ -125,7 +128,7 @@ architecture rtl of spi_flash_ctrl is
-- Automatic mode latches -- Automatic mode latches
signal auto_data : std_ulogic_vector(wb_out.dat'left downto 0) := (others => '0'); signal auto_data : std_ulogic_vector(wb_out.dat'left downto 0) := (others => '0');
signal auto_cnt : integer range 0 to 63 := 0; signal auto_cnt : integer range 0 to 63 := 0;
signal auto_state : auto_state_t := AUTO_IDLE; signal auto_state : auto_state_t := AUTO_BOOT;
signal auto_last_addr : std_ulogic_vector(31 downto 0); signal auto_last_addr : std_ulogic_vector(31 downto 0);


begin begin
@ -176,7 +179,7 @@ begin
-- in practice. -- in practice.
-- --
if cmd_valid = '1' and cmd_ready = '1' then if cmd_valid = '1' and cmd_ready = '1' then
pending_read <= '1'; pending_read <= not wb_req.we;
elsif bus_idle = '1' then elsif bus_idle = '1' then
pending_read <= '0'; pending_read <= '0';
end if; end if;
@ -396,21 +399,29 @@ begin
if rst = '1' or ctrl_reset = '1' then if rst = '1' or ctrl_reset = '1' then
auto_cs <= '0'; auto_cs <= '0';
auto_cnt_next <= 0; auto_cnt_next <= 0;
auto_next <= AUTO_IDLE; auto_next <= AUTO_BOOT;
else else
-- Run counter -- Run counter
if auto_cnt /= 0 then if auto_cnt /= 0 then
auto_cnt_next <= auto_cnt - 1; auto_cnt_next <= auto_cnt - 1;
end if; end if;


-- Automatic CS is set whenever state isn't IDLE or RECOVERY -- Automatic CS is set whenever state isn't IDLE or RECOVERY or BOOT
if auto_state /= AUTO_IDLE and if auto_state /= AUTO_IDLE and
auto_state /= AUTO_RECOVERY then auto_state /= AUTO_RECOVERY and
auto_state /= AUTO_BOOT then
auto_cs <= '1'; auto_cs <= '1';
end if; end if;


-- State machine -- State machine
case auto_state is case auto_state is
when AUTO_BOOT =>
if BOOT_CLOCKS then
auto_cmd_valid <= '1';
if cmd_ready = '1' then
auto_next <= AUTO_IDLE;
end if;
end if;
when AUTO_IDLE => when AUTO_IDLE =>
-- Access to the memory map only when manual CS isn't set -- Access to the memory map only when manual CS isn't set
if wb_map_valid = '1' and ctrl_cs = '0' then if wb_map_valid = '1' and ctrl_cs = '0' then
@ -599,3 +610,4 @@ begin
end process; end process;


end architecture; end architecture;


Loading…
Cancel
Save