From 643d40c1c4d154e0ac922402663349521c372e3a Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 2 Aug 2010 11:00:08 +0200 Subject: Add packages needed for TSE MAC --- lib/ethernet/components/mdio_interface.vhd | 349 +++++++++++++++++++++++++++++ 1 file changed, 349 insertions(+) create mode 100644 lib/ethernet/components/mdio_interface.vhd (limited to 'lib/ethernet/components/mdio_interface.vhd') diff --git a/lib/ethernet/components/mdio_interface.vhd b/lib/ethernet/components/mdio_interface.vhd new file mode 100644 index 0000000..483dcf1 --- /dev/null +++ b/lib/ethernet/components/mdio_interface.vhd @@ -0,0 +1,349 @@ +------------------------------------------------------------------ +-- _____ ______ _____ - +-- |_ _| | ____|/ ____| 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; + -- cgit v1.2.3-54-g00ecf