summaryrefslogtreecommitdiff
path: root/lib/ethernet/components/mdio_interface.vhd
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ethernet/components/mdio_interface.vhd')
-rw-r--r--lib/ethernet/components/mdio_interface.vhd349
1 files changed, 349 insertions, 0 deletions
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;
+