UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
Visitor cheebi7
Visitor
890 Views
Registered: ‎03-05-2018

VCU118 - SGMII AxiEthernet - Axi Initialization

Dear Community,

 

I know there are several other questions regarding this topic. But none of them worked for me nor did they presumably have the same issue.

 

I am trying to use Axi-Ethernet-IP-Code on a Virtex UltraScale+ on the VCU118 Eval Board.

 

Before posting IP-configuration and startup code, I want to state my observations and questions:

 

* The Phy does complete autonegotiation with 1000MBps as requested.

* However, the TEMAC-status register (PPST 0x30) doesn't show rudi_c (bit2), link sync (bit1) nor link status (bit0). The state is 0x800.

* The Phy and the board are working, as I can use the MB-Design with lwip-example project.

 

Regarding the following answers concerning configuring the TI phy with SGMII on VCU118:

 

[1] How to bring up the SGMII PHY

 

[2] SGMII Ethernet of VCU118

 

[3] VCU118 SGMII Ethernet

 

Documentation:

[5] pg051-tri-mode-eth-mac

 

[6] pg138-axi-ethernet

 

I designed the IP core and wrote a startup FSM which configures the IP core through axi.

 

In order to make sure, the phy and the board are working I used the lwip-example project. The example-project works fine. I then studied the microblaze C code in order to make sure to have the correct configuration FSM states. The microblaze code goes through all the configurations I would expect from the documentation [5,6] and the above links [1-3]. Although I do the same configuration steps in my configuration FSM as in the microblaze code, I don't find the TEMAC status register (addr 0x30) go into "link up" state (i.e. bits 2-0 are expected to be 0x7 but they remain 0x0).

 

Am I doing the configuration steps also stated in [2] and in [1] in the correct order?

Can you please relate to what I am missing?

 

Here are my configuration steps:

 

I customized the IP core with the following settings:

 

ip_1.PNG

 

ip_2.PNG

 

 

ip_3.PNG

 

 

ip_4.PNG

 

ip_6.PNG

 

ip_7.PNG

 

 

Configuration-FSM:

 

I want to use this core without Microblaze. Therefore, I modified a initialization FSM from a previous Xilinx-Example-Project. This FSM goes through various stages to start the externel TI phy for use with 6-wire SGMII.

 

The code is the following:

 

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.all;

library work;

entity ethernet_config_axi_lite is
Generic(
  REJECT_BROADCAST_FRAME  : BOOLEAN := TRUE;
  REJECT_MULTICAST_FRAME  : BOOLEAN := FALSE;
  ACCEPT_BAD_FRAMES       : BOOLEAN := FALSE;
  PROMISCUOUS_MODE        : BOOLEAN := FALSE;
  MAC_UNICAST_ADD         : STD_LOGIC_VECTOR(47 downto 0) := x"010203040506"
);
port (
        s_axi_aclk         : in  STD_LOGIC;
        s_axi_resetn	   : in  STD_LOGIC;

	probe_axi_state    : out STD_LOGIC_VECTOR(7 downto 0);
	probe_axi_stack    : out STD_LOGIC_VECTOR(7 downto 0);
	probe_axi_rd_data  :out STD_LOGIC_VECTOR(31 downto 0);
	probe_int_stat     : out STD_LOGIC_VECTOR(7 downto 0);
	probe_phy_stat     : out STD_LOGIC_VECTOR(31 downto 0);
	probe_temac_stat   : out STD_LOGIC_VECTOR(31 downto 0);
        probe_phy_model    : out STD_LOGIC_VECTOR(15 downto 0);
        probe_sgmii_reg    : out STD_LOGIC_VECTOR(31 downto 0);

	s_axi_awaddr	   : out STD_LOGIC_VECTOR(17 downto 0);
	s_axi_awvalid	   : out STD_LOGIC;
	s_axi_awready	   : in STD_LOGIC;
	
	s_axi_wdata        : out STD_LOGIC_VECTOR(31 downto 0);
	s_axi_wvalid	   : out STD_LOGIC;
	s_axi_wready	   : in STD_LOGIC;
	
	s_axi_bresp        : in STD_LOGIC_VECTOR(1 downto 0);
	s_axi_bvalid	   : in STD_LOGIC;
	s_axi_bready	   : out STD_LOGIC;
	
	s_axi_araddr	   : out STD_LOGIC_VECTOR(17 downto 0);
	s_axi_arvalid	   : out STD_LOGIC;
	s_axi_arready	   : in STD_LOGIC;
	
	s_axi_rdata        : in STD_LOGIC_VECTOR(31 downto 0);
	s_axi_rresp        : in STD_LOGIC_VECTOR(1 downto 0);
	s_axi_rvalid	   : in STD_LOGIC;
	s_axi_rready	   : out STD_LOGIC
);
end ethernet_config_axi_lite;



architecture rtl of ethernet_config_axi_lite is

   -- main state machine

   -- Encoded main state machine states.
   type state_typ is         (INIT,                   -- 0
                              WAIT_FOR_RESET_RESP,    -- 1
                              MDIO_SETUP,             -- 2
                              CNFG_RAF,               -- 3
                              
                              CNFG_TX,                -- 4
                              CNFG_RX,                -- 5
                              CNFG_FLOW,              -- 6
                              CNFG_FILTER,            -- 7
                              CNFG_MAC_LO_ADDR,       -- 8
                              CNFG_MAC_HI_ADDR,       -- 9
                              CNFG_GAP1,              -- 10
                              READ_PHY_MODEL,         -- 11
                              EN_SGMIICLK_WAIT_RDY,   -- 12 
                              EN_SGMIICLK_1,          -- 13
                              EN_SGMIICLK_2,          -- 14
                              EN_SGMIICLK_3,          -- 15
                              EN_SGMIICLK_4,          -- 16
                              CNFG_GAP2,              -- 17
                              POLL_SGMII_CLK_UP,      -- 18
                              CHECK_SGMII_CLK_UP,     -- 19
                              WRITE_PHY_CTRL_REG,     -- 20
                              WRITE_PHY_CFGR2_REG,    -- 21
                              DIS_RGMII_1,            -- 22
                              DIS_RGMII_2,            -- 23
                              DIS_RGMII_3,            -- 24
                              DIS_RGMII_4,            -- 25
                              EN_SGMII,               -- 26
                              POLL_AUTONEG_CMPLT_1,   -- 27
                              CHECK_AUTONEG_CMPLT_1,  -- 28
                              WORK_AROUND_1,          -- 29 
                              WORK_AROUND_2,          -- 30
                              WORK_AROUND_3,          -- 31
                              WORK_AROUND_4,          -- 32
                              CNFG_GAP3,              -- 33
                              MDIO_STATS_POLL_CHECK,  -- 34
                              START_AUTONEG_2,        -- 35
                              POLL_AUTONEG_CMPLT_2,   -- 36
                              CHECK_AUTONEG_CMPLT_2,  -- 37 
                              POLL_LINK_UP,           -- 38
                              CHECK_LINK_UP,          -- 39
                              CNFG_SPEED_2,           -- 40
                              EN_INTERRUPTS,          -- 41
                              
                              RD_STAT1,               -- 42
                              RD_STAT2,               -- 43
                              WAIT_FOR_DELAY,         -- 44
                              WAIT_FOR_MDIO_RDY,      -- 45
                              WAIT_FOR_MDIO_POLL1,    -- 46
                              VERIF_SGMIICLK_1,       -- 47
                              VERIF_SGMIICLK_2,       -- 48
                              VERIF_SGMIICLK_3,       -- 49
                              VERIF_SGMIICLK_4,       -- 50
                              VERIF_SGMIICLK_5,       -- 51
                              VERIF_SGMIICLK_6,       -- 52
                              WAIT_FOR_MDIO_RDY2,     -- 53
                              WAIT_FOR_MDIO_POLL2,    -- 54
                              CNFG_SPEED_1            -- 55
                              );

   
   -- MDIO State machine
   type mdio_state_typ is    (IDLE,
                              SET_DATA,
                              INIT,
                              POLL);

   -- AXI State Machine
   type axi_state_typ is     (IDLE_A,
                              READ,
                              WRITE,
                              DONE);


   -- Reset addr filter reg address
   constant RESET_ADDFILTER_ADD    : std_logic_vector(16 downto 0) := "00000" & x"000";
   
   -- Interrupt status reg address                  (0x00C)
   constant INT_STATUS_ADD         : std_logic_vector(16 downto 0) := "00000" & x"00C";
   
   -- Interrupt enable reg address
   constant INT_ENABLE_ADD         : std_logic_vector(16 downto 0) := "00000" & x"014";
   
   -- TEMAC status reg address
   constant TEMAC_STAT_ADD         : std_logic_vector(16 downto 0) := "00000" & x"030";
   
   -- Management configuration register address     (0x500)
   constant CONFIG_MANAGEMENT_ADD  : std_logic_vector(16 downto 0) := "00000" & X"500";
   
   -- Flow control configuration register address   (0x40C)
   constant FLOW_CTRL_ADD          : std_logic_vector(16 downto 0) := "00000" & X"40C";

   -- Receiver configuration register address       (0x404)
   constant RECEIVER_ADD           : std_logic_vector(16 downto 0) := "00000" & X"404";

   -- Transmitter configuration register address    (0x408)
   constant TRANSMITTER_ADD        : std_logic_vector(16 downto 0) := "00000" & X"408";

   -- Speed configuration register address    (0x410)
   constant SPEED_CONFIG_ADD       : std_logic_vector(16 downto 0) := "00000" & X"410";

   -- Unicast Word 0 configuration register address (0x700)
   constant CONFIG_UNI0_CTRL_ADD   : std_logic_vector(16 downto 0) := "00000" & X"700";

   -- Unicast Word 1 configuration register address (0x704)
   constant CONFIG_UNI1_CTRL_ADD   : std_logic_vector(16 downto 0) := "00000" & X"704";

   -- Address Filter configuration register address (0x708)
   constant FILTER_CTRL_ADD        : std_logic_vector(16 downto 0) := "00000" & X"708";
   
 
   -- Frame filter bytes (3 to 0)  register address (0x710)
   constant CONFIG_FRAME_FILTER_1     : std_logic_vector(16 downto 0) := "00000" & X"710";

   -- Frame filter bytes (7 to 4)  register address (0x714)
   constant CONFIG_FRAME_FILTER_2     : std_logic_vector(16 downto 0) := "00000" & X"714";

   -- Frame filter bytes (11 to 8) register address (0x718)
   constant CONFIG_FRAME_FILTER_3     : std_logic_vector(16 downto 0) := "00000" & X"718";

   -- Frame filter mask bytes (3 to 0) register address (0x750)
   constant CONFIG_FRAME_FILTER_MASK_1 : std_logic_vector(16 downto 0) := "00000" & X"750";

   -- Frame filter mask bytes (7 to 4) register address (0x754)
   constant CONFIG_FRAME_FILTER_MASK_2 : std_logic_vector(16 downto 0) := "00000" & X"754";

   -- Frame filter mask bytes (11 to 8) register address (0x758)
   constant CONFIG_FRAME_FILTER_MASK_3 : std_logic_vector(16 downto 0) := "00000" & X"758";

   
   -- MDIO registers
   constant MDIO_CONTROL           : std_logic_vector(16 downto 0) := "00000" & X"504";
   constant MDIO_TX_DATA           : std_logic_vector(16 downto 0) := "00000" & X"508";
   constant MDIO_RX_DATA           : std_logic_vector(16 downto 0) := "00000" & X"50C";
   constant MDIO_OP_RD             : std_logic_vector(1 downto 0)  := "10";
   constant MDIO_OP_WR             : std_logic_vector(1 downto 0)  := "01";

   
   -- PHY Registers
   -- phy address is actually a 6 bit field but other bits are reserved so simpler to specify as 8 bit
   signal phy_addr                 : std_logic_vector(7 downto 0) := X"03";
   
   constant PHY_CONTROL_REG        : std_logic_vector(7 downto 0)    := X"00";
   constant PHY_STATUS_REG         : std_logic_vector(7 downto 0)    := X"01";
   constant PHY_ID_REG             : std_logic_vector(7 downto 0)    := X"02"; -- should be read as 0x2000
   constant PHY_MODEL_REG          : std_logic_vector(7 downto 0)    := X"03"; -- should be read as 0xA231
   constant PHY_ADVERTISE_REG      : std_logic_vector(7 downto 0)    := X"04";
   constant PHY_ABILITY_1_REG      : std_logic_vector(7 downto 0)    := X"05";
   constant PHY_1000BASET_CONTROL_REG : std_logic_vector(7 downto 0) := X"09";
   
   -- for VCU118 workaround
   -- TI DP83867 PHY special registers
   constant TI_PHY_REGCR           : std_logic_vector(7 downto 0) := X"0D";
   constant TI_PHY_ADDDR           : std_logic_vector(7 downto 0) := X"0E";
   constant TI_PHY_PHYCTRL         : std_logic_vector(7 downto 0) := X"10";
   constant TI_PHY_CFGR2           : std_logic_vector(7 downto 0) := X"14";
   -- TI DP83867 PHY bit definitions
   constant TI_PHY_REGCR_DEVAD_EN  : std_logic_vector(31 downto 0) := X"0000001F";
   constant TI_PHY_REGCR_DATA      : std_logic_vector(31 downto 0) := X"0000401F";
   constant TI_PHY_SGMIITYPE       : std_logic_vector(31 downto 0) := X"000000D3"; -- ext reg address
   constant TI_PHY_SGMII_CLK_EN    : std_logic_vector(31 downto 0) := X"00004000";
   constant TI_PHY_CR_SGMII_EN     : std_logic_vector(31 downto 0) := X"00000800";
   constant TI_PHY_CFGR4           : std_logic_vector(31 downto 0) := X"00000031"; -- ext reg address
   constant DP83867_R32_RGMIICTL1  : std_logic_vector(31 downto 0) := X"00000032"; -- ext reg address

   ---------------------------------------------------
   -- Signal declarations
   signal s_rjct_bcf : std_logic; -- reject broadcast frame
   signal s_rjct_mcf : std_logic; -- reject multicast frame
   signal s_acpt_bf  : std_logic; -- accept bad frames
   
   signal axi_status               : std_logic_vector(4 downto 0);   -- used to keep track of axi transactions
   
   signal mdio_ready               : std_logic;                      -- captured to acknowledge the end of mdio transactions
   
   signal axi_rd_data              : std_logic_vector(31 downto 0);
   signal axi_wr_data              : std_logic_vector(31 downto 0);
   
   signal mdio_wr_data             : std_logic_vector(31 downto 0);
   

   signal axi_state                : state_typ;                      -- main state machine to configure example design
   signal axi_state_stack          : state_typ;                      -- return to this state after pushing state and jumping to intermediate
   signal axi_state_2nd_stack      : state_typ;                      -- return value of jumps into wait for mdio ready
   
   signal mdio_access_sm           : mdio_state_typ;                 -- mdio state machine to handle mdio register config
   signal axi_access_sm            : axi_state_typ;                  -- axi state machine - handles the 5 channels

   signal start_access             : std_logic;                      -- used to kick the axi acees state machine
   
   signal start_mdio               : std_logic;                      -- used to kick the mdio state machine
   signal drive_mdio               : std_logic;                      -- selects between mdio fields and direct sm control
   signal mdio_op                  : std_logic_vector(1 downto 0);
   signal mdio_reg_addr            : std_logic_vector(7 downto 0);
   
   signal temp_reg                 : std_logic_vector(31 downto 0);
   
   signal writenread               : std_logic;
   signal addr                     : std_logic_vector(16 downto 0);

   signal delay_counter            : unsigned(28 downto 0) := (others => '1');

   -- to avoid logic being stripped a serial input is included which enables an address/data and
   -- control to be setup for a user config access..
   signal serial_command_shift     : std_logic_vector(36 downto 0);
   signal load_data                : std_logic;
   signal capture_data             : std_logic;
   signal write_access             : std_logic;
   signal read_access              : std_logic;

   signal s_axi_reset              : std_logic;

   signal s_axi_awvalid_int        : std_logic;
   signal s_axi_wvalid_int         : std_logic;
   signal s_axi_bready_int         : std_logic;
   signal s_axi_arvalid_int        : std_logic;
   signal s_axi_rready_int         : std_logic;

   signal design_on_board         : std_logic_vector(3 downto 0) := X"0";

   

begin

   s_rjct_bcf  <= '1' when REJECT_BROADCAST_FRAME  else '0';
   s_rjct_mcf  <= '1' when REJECT_MULTICAST_FRAME  else '0';
   s_acpt_bf   <= '1' when ACCEPT_BAD_FRAMES       else '0';
   

   ---- debug
   probe_axi_state <= STD_LOGIC_VECTOR(TO_UNSIGNED(state_typ'POS(axi_state), probe_axi_state'LENGTH));
   probe_axi_stack <= STD_LOGIC_VECTOR(TO_UNSIGNED(state_typ'POS(axi_state_stack), probe_axi_state'LENGTH));
   probe_axi_rd_data <= axi_rd_data;

   s_axi_awvalid <= s_axi_awvalid_int;
   s_axi_wvalid  <= s_axi_wvalid_int;
   s_axi_bready  <= s_axi_bready_int;
   s_axi_arvalid <= s_axi_arvalid_int;
   s_axi_rready  <= s_axi_rready_int;

   s_axi_reset <= not s_axi_resetn;

   -----------------------------------------------------------------------------
   -- Management process. This process sets up the configuration by
   -- turning off flow control, then checks gathered statistics at the
   -- end of transmission
   -----------------------------------------------------------------------------
   gen_state : process (s_axi_aclk)
   begin
      if s_axi_aclk'event and s_axi_aclk = '1' then
         if s_axi_reset = '1' then
            delay_counter   <= (others => '1');
            axi_state       <= WAIT_FOR_DELAY;
            axi_state_stack <= INIT;
            
            start_access    <= '0';
            start_mdio      <= '0';
            drive_mdio      <= '0';
            mdio_op         <= (others => '0');
            mdio_reg_addr   <= (others => '0');
            
            writenread      <= '0';
            addr            <= (others => '0');
            axi_wr_data     <= (others => '0');
            phy_addr        <= X"03";
            
         -- main state machine is kicking off multi cycle accesses in each state so has to
         -- stall while they take place
   
         elsif axi_access_sm = IDLE_A and mdio_access_sm = IDLE and start_access = '0' and start_mdio = '0' then
         
            case axi_state is
            
               when INIT =>
                  drive_mdio    <= '0';
                  start_mdio    <= '0';
                  start_access  <= '1';
                  writenread    <= '0';
                  addr          <= INT_STATUS_ADD;
                  axi_state     <= WAIT_FOR_RESET_RESP;
                  
               when WAIT_FOR_RESET_RESP =>
                  if (axi_rd_data(8) = '1' and axi_rd_data(7) = '1') then
                      -- bit8: PhyRstCmplt: 0 - PHY not ready,   1 - PHY ready
                      -- bit7: MgtRdy:      0 - TEMAC not ready, 1 - TEMAC ready  
                      axi_state    <= MDIO_SETUP;
                  else
                      axi_state    <= INIT;
                  end if;
                  
               when MDIO_SETUP =>
                  start_access     <= '1';
                  writenread       <= '1';
                  addr             <= CONFIG_MANAGEMENT_ADD;
                  axi_wr_data      <= X"0000005F";
                  delay_counter    <= (others => '1');
                  axi_state        <= WAIT_FOR_DELAY;
                  axi_state_stack  <= CNFG_RAF;
                  
               when CNFG_RAF =>
                  drive_mdio       <= '0';
                  start_access     <= '1';
                  writenread       <= '1';
                  addr             <= RESET_ADDFILTER_ADD;
                  axi_wr_data      <= x"0000" & '0' & s_acpt_bf & "00" & x"00" & '0' & s_rjct_mcf & s_rjct_bcf & '0';
                  axi_state        <= CNFG_TX;
                  
               when CNFG_TX =>
                  start_access     <= '1';
                  writenread       <= '1';
                  addr             <= TRANSMITTER_ADD;
                  axi_wr_data      <= x"10000000";
                  axi_state        <= CNFG_RX;
                  
               when CNFG_RX =>
                  start_access     <= '1';
                  writenread       <= '1';
                  addr             <= RECEIVER_ADD;
                  axi_wr_data      <= x"1000FFFF";
                  axi_state        <= CNFG_FLOW;
                  
               when CNFG_FLOW =>
                  start_access     <= '1';
                  writenread       <= '1';
                  addr             <= FLOW_CTRL_ADD;
                  axi_wr_data      <= x"1000FFFF";
                  axi_state        <= CNFG_FILTER;
                  
               when CNFG_FILTER =>
                  start_access     <= '1';
                  writenread       <= '1';
                  addr             <= FILTER_CTRL_ADD;
                  axi_wr_data      <= x"1000FFFF";
                  axi_state        <= CNFG_MAC_LO_ADDR;
                  
               when CNFG_MAC_LO_ADDR =>
                  start_access     <= '1';
                  writenread       <= '1';
                  addr             <= CONFIG_UNI0_CTRL_ADD;
                  axi_wr_data      <= MAC_UNICAST_ADD(23 downto 16) & MAC_UNICAST_ADD(31 downto 24) & MAC_UNICAST_ADD(39 downto 32) & MAC_UNICAST_ADD(47 downto 40);
                  axi_state        <= CNFG_MAC_HI_ADDR;
      
               when CNFG_MAC_HI_ADDR =>
                  start_access     <= '1';
                  writenread       <= '1';
                  addr             <= CONFIG_UNI1_CTRL_ADD;
                  axi_wr_data      <= x"0000" & MAC_UNICAST_ADD(7 downto 0) & MAC_UNICAST_ADD(15 downto 8);
                  delay_counter    <= (others => '1');
                  axi_state        <= WAIT_FOR_DELAY;
                  axi_state_stack  <= CNFG_SPEED_1;
                  
               when CNFG_SPEED_1 =>                 
                  start_access     <= '1';
                  writenread       <= '1';
                  addr             <= SPEED_CONFIG_ADD; -- 0x410
                  axi_wr_data      <= X"80000000";
                  delay_counter    <= (others => '1');
                  axi_state        <= WAIT_FOR_DELAY;
                  axi_state_stack  <= CNFG_GAP1;
                  
               --- TEMAC configured ---
               
               when CNFG_GAP1 =>
                  axi_state        <= WAIT_FOR_MDIO_RDY;
                  axi_state_stack  <= READ_PHY_MODEL;
               
               when READ_PHY_MODEL =>
                  drive_mdio       <= '1';
                  start_mdio       <= '1';
                  mdio_op          <= MDIO_OP_RD;
                  mdio_reg_addr    <= PHY_MODEL_REG; -- 0x3
                  axi_state        <= EN_SGMIICLK_WAIT_RDY;
               
               --- Enable SGMII clock ---
                  
               when EN_SGMIICLK_WAIT_RDY =>
                  probe_phy_model  <= axi_rd_data(15 downto 0);
                  axi_state        <= WAIT_FOR_MDIO_RDY;
                  axi_state_stack  <= EN_SGMIICLK_1;
               
               when EN_SGMIICLK_1 =>
                  drive_mdio       <= '1';
                  start_mdio       <= '1';
                  mdio_op          <= MDIO_OP_WR;
                  mdio_reg_addr    <= TI_PHY_REGCR; -- 0xD
                  axi_wr_data      <= X"0000001F"; -- TI_PHY_REGCR_DEVAD_EN
                  axi_state        <= WAIT_FOR_MDIO_RDY;
                  axi_state_stack  <= EN_SGMIICLK_2;
               
               when EN_SGMIICLK_2 =>
                  drive_mdio       <= '1';
                  start_mdio       <= '1';
                  mdio_op          <= MDIO_OP_WR;
                  mdio_reg_addr    <= TI_PHY_ADDDR; -- 0xE
                  axi_wr_data      <= X"000000D3"; -- TI_PHY_SGMIITYPE
                  axi_state        <= WAIT_FOR_MDIO_RDY;
                  axi_state_stack  <= EN_SGMIICLK_3;
                  
               when EN_SGMIICLK_3 =>
                  drive_mdio       <= '1';
                  start_mdio       <= '1';
                  mdio_op          <= MDIO_OP_WR;
                  mdio_reg_addr    <= TI_PHY_REGCR; --0xD
                  axi_wr_data      <= X"0000401F"; -- TI_PHY_REGCR_DATA
                  axi_state        <= WAIT_FOR_MDIO_RDY;
                  axi_state_stack  <= EN_SGMIICLK_4;
                  
               when EN_SGMIICLK_4  =>
                  drive_mdio       <= '1';
                  start_mdio       <= '1';
                  mdio_op          <= MDIO_OP_WR;
                  mdio_reg_addr    <= TI_PHY_ADDDR; -- 0xE
                  axi_wr_data      <= X"00004000"; -- TI_PHY_SGMII_CLK_EN
                  axi_state        <= WAIT_FOR_MDIO_RDY;
                  axi_state_stack  <= VERIF_SGMIICLK_1;
                  
                  
                --- Verify register content
-- (not necessary, but I wanted to check the MDIO and Phy registers are working
-- as expected.) when VERIF_SGMIICLK_1 => axi_state <= WAIT_FOR_MDIO_RDY; axi_state_stack <= VERIF_SGMIICLK_2; when VERIF_SGMIICLK_2 => drive_mdio <= '1'; start_mdio <= '1'; mdio_op <= MDIO_OP_WR; mdio_reg_addr <= TI_PHY_REGCR; -- 0xD axi_wr_data <= X"0000001F"; -- TI_PHY_REGCR_DEVAD_EN axi_state <= WAIT_FOR_MDIO_RDY; axi_state_stack <= VERIF_SGMIICLK_3; when VERIF_SGMIICLK_3 => drive_mdio <= '1'; start_mdio <= '1'; mdio_op <= MDIO_OP_WR; mdio_reg_addr <= TI_PHY_ADDDR; -- 0xE axi_wr_data <= X"000000D3"; -- TI_PHY_SGMIITYPE axi_state <= WAIT_FOR_MDIO_RDY; axi_state_stack <= VERIF_SGMIICLK_4; when VERIF_SGMIICLK_4 => drive_mdio <= '1'; start_mdio <= '1'; mdio_op <= MDIO_OP_WR; mdio_reg_addr <= TI_PHY_REGCR; --0xD axi_wr_data <= X"0000401F"; -- TI_PHY_REGCR_DATA axi_state <= WAIT_FOR_MDIO_RDY; axi_state_stack <= VERIF_SGMIICLK_5; when VERIF_SGMIICLK_5 => drive_mdio <= '1'; start_mdio <= '1'; mdio_op <= MDIO_OP_RD; mdio_reg_addr <= TI_PHY_ADDDR; -- 0xE axi_state <= VERIF_SGMIICLK_6; when VERIF_SGMIICLK_6 => probe_sgmii_reg <= axi_rd_data; -- this works (checked with ILA) axi_state <= CNFG_GAP2; --- SGMII clock enabled --- when CNFG_GAP2 => drive_mdio <= '0'; delay_counter <= (others => '1'); axi_state <= WAIT_FOR_DELAY; axi_state_stack <= POLL_SGMII_CLK_UP; when POLL_SGMII_CLK_UP => start_access <= '1'; writenread <= '0'; addr <= TEMAC_STAT_ADD; axi_state <= CHECK_SGMII_CLK_UP; when CHECK_SGMII_CLK_UP => probe_temac_stat <= axi_rd_data; --if (axi_rd_data(2 downto 0) /= "000" ) then

-- unfortunately this state never changes. However, it changes in MB example.
if True then axi_state <= WAIT_FOR_MDIO_RDY; axi_state_stack <= WRITE_PHY_CTRL_REG; else axi_state <= POLL_SGMII_CLK_UP; end if; -- SGMII clock is on when WRITE_PHY_CTRL_REG => drive_mdio <= '1'; start_mdio <= '1'; mdio_op <= MDIO_OP_WR; mdio_reg_addr <= PHY_CONTROL_REG; -- 0x0 axi_wr_data <= X"00001140"; -- axi_state <= WAIT_FOR_MDIO_RDY; axi_state_stack <= WRITE_PHY_CFGR2_REG; when WRITE_PHY_CFGR2_REG => drive_mdio <= '1'; start_mdio <= '1'; mdio_op <= MDIO_OP_WR; mdio_reg_addr <= TI_PHY_CFGR2; -- 0x14 axi_wr_data <= X"000029C7"; -- axi_state <= WAIT_FOR_MDIO_RDY; axi_state_stack <= DIS_RGMII_1; --- PHY configured when DIS_RGMII_1 => drive_mdio <= '1'; start_mdio <= '1'; mdio_op <= MDIO_OP_WR; mdio_reg_addr <= TI_PHY_REGCR; -- 0xD axi_wr_data <= X"0000001F"; -- TI_PHY_REGCR_DEVAD_EN axi_state <= WAIT_FOR_MDIO_RDY; axi_state_stack <= DIS_RGMII_2; when DIS_RGMII_2 => drive_mdio <= '1'; start_mdio <= '1'; mdio_op <= MDIO_OP_WR; mdio_reg_addr <= TI_PHY_ADDDR; -- 0xE axi_wr_data <= X"00000032"; -- DP83867_R32_RGMIICTL1 axi_state <= WAIT_FOR_MDIO_RDY; axi_state_stack <= DIS_RGMII_3; when DIS_RGMII_3 => drive_mdio <= '1'; start_mdio <= '1'; mdio_op <= MDIO_OP_WR; mdio_reg_addr <= TI_PHY_REGCR; -- 0xD axi_wr_data <= X"0000401F"; -- TI_PHY_REGCR_DATA axi_state <= WAIT_FOR_MDIO_RDY; axi_state_stack <= DIS_RGMII_4; when DIS_RGMII_4 => drive_mdio <= '1'; start_mdio <= '1'; mdio_op <= MDIO_OP_WR; mdio_reg_addr <= TI_PHY_ADDDR; -- 0xE axi_wr_data <= X"00000000"; axi_state <= WAIT_FOR_MDIO_RDY; axi_state_stack <= EN_SGMII; --- RGMII disabled when EN_SGMII => drive_mdio <= '1'; start_mdio <= '1'; mdio_op <= MDIO_OP_WR; mdio_reg_addr <= TI_PHY_PHYCTRL; -- 0x10 axi_wr_data <= X"00000800"; -- TI_PHY_CR_SGMII_EN axi_state <= WAIT_FOR_MDIO_RDY; axi_state_stack <= POLL_AUTONEG_CMPLT_1; -- SGMII enabled -> Wait for autonegotiation when POLL_AUTONEG_CMPLT_1 => drive_mdio <= '1'; start_mdio <= '1'; mdio_op <= MDIO_OP_RD; mdio_reg_addr <= PHY_ABILITY_1_REG; -- 0x5 axi_state <= CHECK_AUTONEG_CMPLT_1; when CHECK_AUTONEG_CMPLT_1 => if (axi_rd_data(14) = '0') then axi_state <= POLL_AUTONEG_CMPLT_1; else axi_state <= WORK_AROUND_1; end if; --- Autonegotiation passed when WORK_AROUND_1 => drive_mdio <= '1'; start_mdio <= '1'; mdio_op <= MDIO_OP_WR; mdio_reg_addr <= TI_PHY_REGCR; -- 0xD axi_wr_data <= X"0000001F"; -- TI_PHY_REGCR_DEVAD_EN axi_state <= WAIT_FOR_MDIO_RDY; axi_state_stack <= WORK_AROUND_2; when WORK_AROUND_2 => drive_mdio <= '1'; start_mdio <= '1'; mdio_op <= MDIO_OP_WR; mdio_reg_addr <= TI_PHY_ADDDR; -- 0xE axi_wr_data <= X"00000031"; -- TI_PHY_CFGR4 axi_state <= WAIT_FOR_MDIO_RDY; axi_state_stack <= WORK_AROUND_3; when WORK_AROUND_3 => drive_mdio <= '1'; start_mdio <= '1'; mdio_op <= MDIO_OP_WR; mdio_reg_addr <= TI_PHY_REGCR; -- 0xD axi_wr_data <= X"0000401F"; -- TI_PHY_REGCR_DATA axi_state <= WAIT_FOR_MDIO_RDY; axi_state_stack <= WORK_AROUND_4; when WORK_AROUND_4 => drive_mdio <= '1'; start_mdio <= '1'; mdio_op <= MDIO_OP_WR; mdio_reg_addr <= TI_PHY_ADDDR; -- 0xE axi_wr_data <= X"00001170"; axi_state <= WAIT_FOR_MDIO_RDY; axi_state_stack <= CNFG_GAP3; --- Work around completed --- Change PHY_ADDR when CNFG_GAP3 => -- Change PHY_ADDR
-- this is something I found in the MB code to be crucial
-- however, my problem is already in a previous state, that TEMAC state doesn't go to "link up" phy_addr <= X"01"; delay_counter <= (others => '1'); axi_state <= WAIT_FOR_DELAY; axi_state_stack <= START_AUTONEG_2; when START_AUTONEG_2 => drive_mdio <= '1'; start_mdio <= '1'; mdio_op <= MDIO_OP_WR; mdio_reg_addr <= PHY_CONTROL_REG; axi_wr_data <= X"00001340"; axi_state <= WAIT_FOR_MDIO_RDY; axi_state_stack <= POLL_AUTONEG_CMPLT_2; when POLL_AUTONEG_CMPLT_2 => drive_mdio <= '1'; start_mdio <= '1'; mdio_op <= MDIO_OP_RD; mdio_reg_addr <= PHY_STATUS_REG; -- 0x1 axi_state <= CHECK_AUTONEG_CMPLT_2; when CHECK_AUTONEG_CMPLT_2 => if (axi_rd_data(5) = '0') then axi_state <= POLL_AUTONEG_CMPLT_2; else axi_state <= POLL_LINK_UP; end if; when POLL_LINK_UP => drive_mdio <= '1'; start_mdio <= '1'; mdio_op <= MDIO_OP_RD; mdio_reg_addr <= PHY_ABILITY_1_REG; -- 0x5 axi_state <= CHECK_LINK_UP; when CHECK_LINK_UP => if (axi_rd_data(14) = '0') then axi_state <= POLL_LINK_UP; else axi_state <= CNFG_SPEED_2; end if; --- Link is up --- Change PHY_ADDR when CNFG_SPEED_2 => phy_addr <= X"03"; drive_mdio <= '0'; start_access <= '1'; writenread <= '1'; addr <= SPEED_CONFIG_ADD; -- 0x410 axi_wr_data <= X"80000000"; delay_counter <= (others => '1'); axi_state <= WAIT_FOR_DELAY; axi_state_stack <= EN_INTERRUPTS; when EN_INTERRUPTS => start_access <= '1'; writenread <= '1'; addr <= INT_ENABLE_ADD; -- 0x14 axi_wr_data <= X"00000034"; -- TxCmplt & RxMemOvr & RxCpmlt axi_state <= RD_STAT1; -- Let's really hope our ethernet now comes up. when RD_STAT1 => probe_phy_stat <= axi_rd_data; drive_mdio <= '0'; start_access <= '1'; writenread <= '0'; addr <= TEMAC_STAT_ADD; axi_state <= RD_STAT2; when RD_STAT2 => probe_temac_stat <= axi_rd_data; drive_mdio <= '1'; start_mdio <= '1'; mdio_reg_addr <= PHY_STATUS_REG; mdio_op <= MDIO_OP_RD; axi_state <= RD_STAT1; when WAIT_FOR_DELAY => if (delay_counter /= 0) then delay_counter <= delay_counter - 1; else axi_state <= axi_state_stack; end if; when WAIT_FOR_MDIO_RDY => drive_mdio <= '0'; -- make sure mdio is disabled start_access <= '1'; writenread <= '0'; addr <= MDIO_RX_DATA; axi_state <= WAIT_FOR_MDIO_POLL1; when WAIT_FOR_MDIO_POLL1 => if axi_rd_data(16) = '1' then delay_counter <= to_unsigned(500, 29); axi_state <= WAIT_FOR_DELAY; axi_state_2nd_stack <= axi_state_stack; -- return value of 2nd jump axi_state_stack <= WAIT_FOR_MDIO_RDY2; else axi_state <= WAIT_FOR_MDIO_RDY; end if; when WAIT_FOR_MDIO_RDY2 => start_access <= '1'; writenread <= '0'; addr <= MDIO_CONTROL; axi_state <= WAIT_FOR_MDIO_POLL2; when WAIT_FOR_MDIO_POLL2 => if axi_rd_data(7) = '1' then drive_mdio <= '1'; -- reactivate mdio axi_state <= axi_state_2nd_stack; else axi_state <= WAIT_FOR_MDIO_RDY2; end if; when others => axi_state <= INIT; end case; else start_access <= '0'; start_mdio <= '0'; end if; end if; end process gen_state; -------------------------------------------------- -- MDIO setup - split from main state machine to make more manageable gen_mdio_state : process (s_axi_aclk) begin if s_axi_aclk'event and s_axi_aclk = '1' then if s_axi_reset = '1' then mdio_access_sm <= IDLE; elsif axi_access_sm = IDLE_A or axi_access_sm = DONE then case mdio_access_sm is when IDLE => if start_mdio = '1' then if mdio_op = MDIO_OP_WR then mdio_access_sm <= SET_DATA; mdio_wr_data <= axi_wr_data; else mdio_access_sm <= INIT; mdio_wr_data <= PHY_ADDR & mdio_reg_addr & mdio_op & "001" & "00000000000"; end if; end if; when SET_DATA => mdio_access_sm <= INIT; mdio_wr_data <= PHY_ADDR & mdio_reg_addr & mdio_op & "001" & "00000000000"; when INIT => mdio_access_sm <= POLL; when POLL => if mdio_ready = '1' then mdio_access_sm <= IDLE; end if; end case; elsif mdio_access_sm = POLL and mdio_ready = '1' then mdio_access_sm <= IDLE; end if; end if; end process gen_mdio_state; --------------------------------------------------------------------------------------------- -- processes to generate the axi transactions - only simple reads and write can be generated gen_axi_state : process (s_axi_aclk) begin if s_axi_aclk'event and s_axi_aclk = '1' then if s_axi_reset = '1' then axi_access_sm <= IDLE_A; else case axi_access_sm is when IDLE_A => if start_access = '1' or start_mdio = '1' or mdio_access_sm /= IDLE then if mdio_access_sm = POLL then axi_access_sm <= READ; elsif (start_access = '1' and writenread = '1') or (start_mdio = '1' or mdio_access_sm = SET_DATA or mdio_access_sm = INIT) then axi_access_sm <= WRITE; else axi_access_sm <= READ; end if; end if; when WRITE => -- wait in this state until axi_status signals the write is complete if axi_status(4 downto 2) = "111" then axi_access_sm <= DONE; end if; when READ => -- wait in this state until axi_status signals the read is complete if axi_status(1 downto 0) = "11" then axi_access_sm <= DONE; end if; when DONE => axi_access_sm <= IDLE_A; end case; end if; end if; end process gen_axi_state; -- need a process per axi interface (i.e 5) -- in each case the interface is driven accordingly and once acknowledged a sticky -- status bit is set and the process waits until the access_sm moves on -- READ ADDR read_addr_p : process (s_axi_aclk) begin if s_axi_aclk'event and s_axi_aclk = '1' then if axi_access_sm = READ then if axi_status(0) = '0' then if drive_mdio = '1' then s_axi_araddr <= "000000" & MDIO_RX_DATA(11 downto 0); else s_axi_araddr <= "000000" & addr(11 downto 0); end if; s_axi_arvalid_int <= '1'; if s_axi_arready = '1' and s_axi_arvalid_int = '1' then axi_status(0) <= '1'; s_axi_araddr <= (others => '0'); s_axi_arvalid_int <= '0'; end if; end if; else axi_status(0) <= '0'; s_axi_araddr <= (others => '0'); s_axi_arvalid_int <= '0'; end if; end if; end process read_addr_p; -- READ DATA/RESP read_data_p : process (s_axi_aclk) begin if s_axi_aclk'event and s_axi_aclk = '1' then if axi_access_sm = READ then if axi_status(1) = '0' then s_axi_rready_int <= '1'; if s_axi_rvalid = '1' and s_axi_rready_int = '1' then axi_status(1) <= '1'; s_axi_rready_int <= '0'; axi_rd_data <= s_axi_rdata; if drive_mdio = '1' and s_axi_rdata(16) = '1' then mdio_ready <= '1'; end if; end if; end if; else s_axi_rready_int <= '0'; axi_status(1) <= '0'; if axi_access_sm = IDLE_A and (start_access = '1' or start_mdio = '1') then mdio_ready <= '0'; axi_rd_data <= (others => '0'); end if; end if; end if; end process read_data_p; -- WRITE ADDR write_addr_p : process (s_axi_aclk) begin if s_axi_aclk'event and s_axi_aclk = '1' then if axi_access_sm = WRITE then if axi_status(2) = '0' then if drive_mdio = '1' then if mdio_access_sm = SET_DATA then s_axi_awaddr <= "000000" & MDIO_TX_DATA(11 downto 0); else s_axi_awaddr <= "000000" & MDIO_CONTROL(11 downto 0); end if; else s_axi_awaddr <= "000000" & addr(11 downto 0); end if; s_axi_awvalid_int <= '1'; if s_axi_awready = '1' and s_axi_awvalid_int = '1' then axi_status(2) <= '1'; s_axi_awaddr <= (others => '0'); s_axi_awvalid_int <= '0'; end if; end if; else s_axi_awaddr <= (others => '0'); s_axi_awvalid_int <= '0'; axi_status(2) <= '0'; end if; end if; end process write_addr_p; -- WRITE DATA write_data_p : process (s_axi_aclk) begin if s_axi_aclk'event and s_axi_aclk = '1' then if axi_access_sm = WRITE then if axi_status(3) = '0' then if drive_mdio = '1' then s_axi_wdata <= mdio_wr_data; else s_axi_wdata <= axi_wr_data; end if; s_axi_wvalid_int <= '1'; if s_axi_wready = '1' and s_axi_wvalid_int = '1' then axi_status(3) <= '1'; s_axi_wvalid_int <= '0'; end if; end if; else s_axi_wdata <= (others => '0'); s_axi_wvalid_int <= '0'; axi_status(3) <= '0'; end if; end if; end process write_data_p; -- WRITE RESP write_resp_p : process (s_axi_aclk) begin if s_axi_aclk'event and s_axi_aclk = '1' then if axi_access_sm = WRITE then if axi_status(4) = '0' then s_axi_bready_int <= '1'; if s_axi_bvalid = '1' and s_axi_bready_int = '1' then axi_status(4) <= '1'; s_axi_bready_int <= '0'; end if; end if; else s_axi_bready_int <= '0'; axi_status(4) <= '0'; end if; end if; end process write_resp_p; end rtl;

 

 

The temac state remains after all configuration states in status 0x800. I expect 0x807, from what I have seen in the behavior of the lwip-example.

 

ILA-output:

 

phy_trace.PNG

 

Output of the lwip-example code with register states before configurationa and after configuration. As can be seen, some time after Enable SGMII Clock has been issued, the TEMAC goes into status 0x807:

 

-----lwIP TCP echo server ------

TCP packets sent to port 6001 will be echoed back

Skip Reset first time.

Phy divisor set (reg 0x500).

Initial settings

old reg => new regs (before MAC addr set and Phy_setup())
0x000: 0x00000000 => 0x00000004
0x030: 0x00000800 => 0x00000800
0x404: 0x1000FFFF => 0x1000FFFF
0x408: 0x10000000 => 0x10000000
0x40C: 0x60000000 => 0x60000000
0x410: 0x80000000 => 0x80000000
0x500: 0x0000005D => 0x0000005D
0x700: 0xFFFFFFFF => 0xFFFFFFFF
0x704: 0x0000FFFF => 0x0000FFFF
0x708: 0x80000000 => 0x00000000
set MAC addr.
XAxiEthernet_SetMacAddress: setting mac address to: 01:02:03:04:05:06
0x700: 0xFFFFFFFF => 0x04030201
0x704: 0x0000FFFF => 0x00000605

phy registers (phy_addr=3):
0x0: 0x1140
0x1: 0x7949
0x4: 0x1E1
0x5: 0x0
0x9: 0x300
0xA: 0x0
0x10: 0x5848
0x11: 0x2
0x13: 0x40
0x14: 0x29C7
0x31: 0x10B0
0x32: 0xD3
0x37: 0x0
0x38: 0x0
0xD3: 0x0
0xDC: 0x3800
Enable SGMII Clock
short after sgmii clk en - 0x030: 0x800
long  after sgmii clk en - 0x030: 0x807
reg(0x0) = 0x1140
reg(0x14) = 0x29C7
Disable RGMII
Enable SGMII
reg(0x10)=0x800
Waiting for Link to be up 
reg(0x5)_b14=1...
Auto negotiation completed for TI PHY on phy_addr=3

Work around complete.
0x000: 0x4
0x030: 0x807
0x404: 0x1000FFFF
0x408: 0x10000000
0x40C: 0x60000000
0x708: 0x0

redefine phy_addr from phy_addr=3to phy_addr=1

Start PHY autonegotiation, phy_addr: 1
control_reg (reg 0x0, phy_addr 1) write : 0x1340
phy status reg(0x1): 0x1C8
Waiting for PHY to  complete autonegotiation... completed (phy status reg (0x1): 0x1F8)
Waiting for Link to be up... completed (bit 15 set in reg 0x5: 0xD801)
phy registers (phy_addr=3):
0x0: 0x1140
0x1: 0x796D
0x4: 0x1E1
0x5: 0xCDE1
0x9: 0x300
0xA: 0x3C00
0x10: 0x800
0x11: 0xBC02
0x13: 0x1C42
0x14: 0x29C7
0x31: 0x1170
0x32: 0x0
0x37: 0x3
0x38: 0x1
0xD3: 0x4000
0xDC: 0x3800
auto-negotiated link speed: 1000
speed set 0x410: 0x80000000 => 0x80000000
Starting AxiEthernet Transmitter...
Starting AxiEthernet Receiver...
interrupt enable reg = 0x0 (before enabling)
interrupt enable reg = 0x18 (after enabling)

DHCP Timeout
Configuring default IP of 192.168.1.10
Board IP: 192.168.1.10

Netmask : 255.255.255.0

Gateway : 192.168.1.1

TCP echo server started @ port 7

I read the TEMAC status register (addr 0x30) directly after enabling the SGMII clock. Then I go into a long for-loop in order to wait a moment and read the register (addr 0x30) again. It is 0x807. This corresponds to the first states of my FSM. I do not understand, why the TEMAC in my design remains in status 0x800...

 

Do you think this is related to the IP customization?

 

What else should I check?

 

Thank you so much for your help in advance.

 

Best regards,

Cheebi

 

 

0 Kudos