------------------------------------------------------------------ -- _____ ______ _____ - -- |_ _| | ____|/ ____| Institute of Embedded Systems - -- | | _ __ | |__ | (___ Zuercher Hochschule fuer - -- | | | '_ \| __| \___ \ angewandte Wissenschaften - -- _| |_| | | | |____ ____) | (University of Applied Sciences) - -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland - ------------------------------------------------------------------ -- -- Project : SInet -- Module : -- Description : MDIO Interface and Link status check -- -- $LastChangedDate: 2010-03-02 12:22:00 +0100 (Tue, 02 Mar 2010) $ -- $Rev: 3094 $ -- $Author: beut $ ----------------------------------------------------------------- -- -- Change History -- Date |Name |Modification ------------|----------|----------------------------------------- -- 2.05.07 | GLC | file created ----------------------------------------------------------------- -- 02.11.07 | ffar | adaptation for SInet ----------------------------------------------------------------- -- 01.03.10 | ffar | add state write Mode (RMII/MII selectabel) ----------------------------------------------------------------- library ieee; use ieee.numeric_std.all; use ieee.std_logic_1164.all; library ines_ethernet; use ines_ethernet.mii_management_transmit_pkg.all; library ines_misc; use ines_misc.ines_vhdl_lib_base_pkg.all; use ines_misc.reduce_pack.all; package mdio_interface_pkg is component mdio_interface generic( C_SET_TO_MII : boolean := false; CLK_DIVIDER : natural := 10; -- divider for MDC CHK_INTERVAL : natural := 50e6; -- link check interval in clk_i cycles NO_OF_PORTS : natural := 1; -- number of ports to poll => max 4 ADDR_PORT_1 : natural := 1; ADDR_PORT_2 : natural := 2; ADDR_PORT_3 : natural := 3; ADDR_PORT_4 : natural := 4 ); port( clk_i : in std_logic; reset_n_i : in std_logic; -- manual access phy_addr_i : in std_logic_vector(4 downto 0); phy_reg_i : in std_logic_vector(4 downto 0); phy_data_i : in std_logic_vector(15 downto 0); phy_data_o : out std_logic_vector(15 downto 0); send_i : in std_logic; read_i : in std_logic; busy_n_o : out std_logic; -- Status out link_o : out std_logic_vector(3 downto 0); -- 1= link OK reset_phy_i : in std_logic_vector(3 downto 0); -- 1= reset phy -- MDIO mdio_i : in std_logic; mdio_o : out std_logic; mdio_oe_o : out std_logic; mdc_o : out std_logic ); end component; end package mdio_interface_pkg; library ieee; use ieee.numeric_std.all; use ieee.std_logic_1164.all; library ines_ethernet; use ines_ethernet.mii_management_transmit_pkg.all; library ines_misc; use ines_misc.ines_vhdl_lib_base_pkg.all; use ines_misc.reduce_pack.all; entity mdio_interface is generic( C_SET_TO_MII : boolean := false;-- set to mii mode (otherwise mii mode, otherwise rmii is enabled) CLK_DIVIDER : natural := 10; -- divider for MDC CHK_INTERVAL : natural := 50e6; -- link check interval in clk_i cycles NO_OF_PORTS : natural := 1; -- number of ports to poll => max 4 ADDR_PORT_1 : natural := 1; ADDR_PORT_2 : natural := 2; ADDR_PORT_3 : natural := 3; ADDR_PORT_4 : natural := 4 ); port( clk_i : in std_logic; reset_n_i : in std_logic; -- manual access phy_addr_i : in std_logic_vector(4 downto 0); phy_reg_i : in std_logic_vector(4 downto 0); phy_data_i : in std_logic_vector(15 downto 0); phy_data_o : out std_logic_vector(15 downto 0); send_i : in std_logic; read_i : in std_logic; busy_n_o : out std_logic; -- Status out link_o : out std_logic_vector(3 downto 0); -- 1= link OK reset_phy_i : in std_logic_vector(3 downto 0); -- 1= reset phy -- MDIO mdio_i : in std_logic; mdio_o : out std_logic; mdio_oe_o : out std_logic; mdc_o : out std_logic ); end mdio_interface; architecture rtl of mdio_interface is type states is (S_IDLE, S_WAIT, S_RESET, S_RESTART, S_GETLINK, S_WAIT_GETLINK, S_RMII_READ, S_RMII_READ_WAIT, S_RMII_WRITE, S_RMII_WRITE_WAIT, S_READ, S_WRITE); signal current_state : states; signal interval_cnt : integer range 0 to CHK_INTERVAL; signal chk_link : std_logic; signal write_mode : std_logic; signal curr_phy_no : integer range 1 to NO_OF_PORTS; signal phy_addr : std_logic_vector(4 downto 0); signal phy_reg : std_logic_vector(4 downto 0); signal phy_dat_i : std_logic_vector(15 downto 0); signal phy_dat_o : std_logic_vector(15 downto 0); signal rmii_reg_dat : std_logic_vector(15 downto 0); signal phy_write : std_logic; signal phy_read : std_logic; signal phy_done : std_logic; signal done_f : std_logic; constant CONTROL_REG : std_logic_vector(4 downto 0) := "00000"; -- 0x00 constant STATUS_REG : std_logic_vector(4 downto 0) := "10000"; -- 0x10 constant RMII_REG : std_logic_vector(4 downto 0) := "10111"; -- 0x17 constant C_RMII_MII_BITMASK : std_logic_vector(15 downto 0) := "0000000000010000"; -- 0x10 constant MII_ADDR : std_logic_array_5(1 to 4) := (std_logic_vector(to_unsigned(ADDR_PORT_1,5)), std_logic_vector(to_unsigned(ADDR_PORT_2,5)), std_logic_vector(to_unsigned(ADDR_PORT_3,5)), std_logic_vector(to_unsigned(ADDR_PORT_4,5))); begin phy_data_o <= phy_dat_o; busy_n_o <= phy_done; sm_proc : process (clk_i, reset_n_i, current_state, chk_link, reset_phy_i, send_i, read_i, phy_done, curr_phy_no) begin if reset_n_i = '0' then phy_addr <= (others => '0'); phy_reg <= (others => '0'); phy_dat_o <= (others => '0'); phy_write <= '0'; phy_read <= '0'; current_state <= S_IDLE; link_o <= (others => '0'); curr_phy_no <= 1; done_f <= '0'; elsif clk_i'event and clk_i = '1' then phy_write <= '0'; phy_read <= '0'; case current_state is when S_IDLE => if chk_link = '1' then current_state <= S_GETLINK; elsif write_mode = '1' then current_state <= S_RMII_READ; elsif or_reduce(reset_phy_i) = '1' then -- /= "0000" then current_state <= S_RESET; elsif send_i = '1' then current_state <= S_WRITE; elsif read_i = '1' then current_state <= S_READ; end if; when S_GETLINK => phy_addr <= MII_ADDR(curr_phy_no); phy_reg <= STATUS_REG; phy_read <= '1'; current_state <= S_WAIT_GETLINK; when S_WAIT_GETLINK => if phy_done = '1' and done_f = '0' and curr_phy_no < NO_OF_PORTS then link_o(curr_phy_no-1) <= phy_dat_i(0); curr_phy_no <= curr_phy_no + 1; current_state <= S_GETLINK; elsif phy_done = '1' and done_f = '0' then link_o(curr_phy_no-1) <= phy_dat_i(0); curr_phy_no <= 1; current_state <= S_IDLE; end if; when S_RMII_READ => phy_addr <= MII_ADDR(curr_phy_no); phy_reg <= RMII_REG; phy_read <= '1'; current_state <= S_RMII_READ_WAIT; when S_RMII_READ_WAIT => if phy_done = '1' and done_f = '0' then rmii_reg_dat <= phy_dat_i; current_state <= S_RMII_WRITE; end if; when S_RMII_WRITE => phy_addr <= MII_ADDR(curr_phy_no); phy_reg <= RMII_REG; if C_SET_TO_MII = true then -- Clear Bit Nr 5 and set PHY in MII MODE phy_dat_o <= rmii_reg_dat and (not C_RMII_MII_BITMASK); else -- Set Bit Nr 5 and set PHY in RMII MODE phy_dat_o <= rmii_reg_dat or C_RMII_MII_BITMASK; end if; phy_write <= '1'; current_state <= S_RMII_WRITE_WAIT; when S_RMII_WRITE_WAIT => if phy_done = '1' and done_f = '0' and curr_phy_no < NO_OF_PORTS then curr_phy_no <= curr_phy_no + 1; -- Start Read and Write for other PHY's current_state <= S_RMII_READ; elsif phy_done = '1' and done_f = '0' then curr_phy_no <= 1; current_state <= S_IDLE; end if; when S_READ => phy_addr <= phy_addr_i; phy_reg <= phy_reg_i; phy_read <= '1'; current_state <= S_WAIT; when S_WRITE => phy_addr <= phy_addr_i; phy_reg <= phy_reg_i; phy_dat_o <= phy_data_i; phy_write <= '1'; current_state <= S_WAIT; when S_RESET => if reset_phy_i(0) = '1' then phy_addr <= MII_ADDR(1); elsif reset_phy_i(1) = '1' then phy_addr <= MII_ADDR(2); elsif reset_phy_i(2) = '1' then phy_addr <= MII_ADDR(3); elsif reset_phy_i(3) = '1' then phy_addr <= MII_ADDR(4); end if; phy_reg <= CONTROL_REG; phy_dat_o <= X"8000"; phy_write <= '1'; current_state <= S_WAIT; when S_RESTART => current_state <= S_IDLE; when S_WAIT => if phy_done = '1' and done_f = '0' then current_state <= S_IDLE; end if; end case; done_f <= phy_done; end if; end process; interval_proc : process (clk_i, reset_n_i) begin if reset_n_i = '0' then interval_cnt <= 0; chk_link <= '0'; write_mode <= '0'; elsif clk_i'event and clk_i = '1' then chk_link <= '0'; write_mode <= '0'; if interval_cnt < CHK_INTERVAL then interval_cnt <= interval_cnt + 1; else interval_cnt <= 0; chk_link <= '1'; end if; if interval_cnt = CHK_INTERVAL - 10000 then write_mode <= '1'; end if; end if; end process; mdio_transceiver : mii_management_transmit generic map( G_CLK_DIVIDER => CLK_DIVIDER ) port map( clk => clk_i, reset_n => reset_n_i, phy_addr_i => phy_addr, phy_reg_i => phy_reg, phy_data_i => phy_dat_o, phy_data_o => phy_dat_i, send_i => phy_write, read_i => phy_read, done_o => phy_done, mdc_pad_o => mdc_o, md_pad_i => mdio_i, md_pad_o => mdio_o, md_padoe_o => mdio_oe_o ); end rtl;