Commit 1fdd01db authored by Dimitris Lampridis's avatar Dimitris Lampridis

introduce sfp i2c adapter module

parent e4f3f8c8
......@@ -32,4 +32,5 @@ files = [
"gc_dyn_extend_pulse.vhd",
"gc_ds182x_interface.vhd",
"gc_ds182x_readout.vhd",
"gc_sfp_i2c_adapter.vhd",
];
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- General Cores Library
-- https://www.ohwr.org/projects/general-cores
--------------------------------------------------------------------------------
--
-- unit name: gc_sfp_i2c_adapter
--
-- description: A simple I2C adapter that emulates the SFP DDM and provides
-- access to the vendor id. Useful for when the SFP is not directly accessible
-- over I2C.
--
--------------------------------------------------------------------------------
-- Copyright CERN 2016-2019
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.gencores_pkg.all;
entity gc_sfp_i2c_adapter is
port (
-- Clock, reset ports
clk_i : in std_logic;
rst_n_i : in std_logic;
-- I2C lines
scl_i : in std_logic;
sda_i : in std_logic;
sda_en_o : out std_logic;
-- HIGH if both of the following are true:
-- 1. SFP is detected (plugged in)
-- 2. The part number has been successfully read after the SFP detection
sfp_det_valid_i : in std_logic;
-- 16 byte vendor Part Number (PN)
-- (ASCII encoded, first character byte in bits 127 downto 120)
sfp_data_i : in std_logic_vector (127 downto 0)
);
end entity gc_sfp_i2c_adapter;
architecture rtl of gc_sfp_i2c_adapter is
-----------------------------------------------------------------------------
-- Types
-----------------------------------------------------------------------------
-- 64-byte array representing the DDM serial ID area of the SFP management
type t_sfp_ddm_serial_id is array (0 to 63) of std_logic_vector(7 downto 0);
-----------------------------------------------------------------------------
-- Signals
-----------------------------------------------------------------------------
signal sfp_i2c_tx_byte : std_logic_vector(7 downto 0);
signal sfp_i2c_rx_byte : std_logic_vector(7 downto 0);
signal sfp_i2c_r_done : std_logic;
signal sfp_i2c_w_done : std_logic;
signal sfp_ddm_din : t_sfp_ddm_serial_id := (others => (others => '0'));
signal sfp_ddm_reg : t_sfp_ddm_serial_id := (others => (others => '0'));
signal sfp_ddm_addr : unsigned(5 downto 0);
signal sfp_ddm_sum : unsigned(7 downto 0);
begin -- architecture rtl
cmp_gc_i2c_slave : gc_i2c_slave
generic map (
g_auto_addr_ack => TRUE)
port map (
clk_i => clk_i,
rst_n_i => rst_n_i,
scl_i => scl_i,
-- clock streching not implemented by module
scl_o => open,
scl_en_o => open,
sda_i => sda_i,
-- sda_o is not necessary, sda_en has all the info that we need
sda_o => open,
sda_en_o => sda_en_o,
-- standard SFP management I2C address
i2c_addr_i => "1010000",
-- no need to ACK, we use auto address ACK
-- and only use one byte writes
ack_i => '0',
tx_byte_i => sfp_i2c_tx_byte,
rx_byte_o => sfp_i2c_rx_byte,
-- we only care about r_done (new address)
-- and w_done (load next byte from serial_id)
i2c_sta_p_o => open,
i2c_sto_p_o => open,
addr_good_p_o => open,
r_done_p_o => sfp_i2c_r_done,
w_done_p_o => sfp_i2c_w_done,
op_o => open);
-- Populate the sfp_ddm Vendor PN using the sfp_data_i input
gen_sfp_ddm_data : for i in 0 to 15 generate
sfp_ddm_din(40+i) <= sfp_data_i(127-i*8 downto 120-i*8);
end generate gen_sfp_ddm_data;
-- Calculate CC_BASE for the last byte of the sfp_ddm.
-- We only sum the 16 bytes, all other bytes are zero anyway.
sfp_ddm_sum <=
(((unsigned(sfp_data_i(127 downto 120)) + unsigned(sfp_data_i(119 downto 112))) +
(unsigned(sfp_data_i(111 downto 104)) + unsigned(sfp_data_i(103 downto 96)))) +
((unsigned(sfp_data_i(95 downto 88)) + unsigned(sfp_data_i(87 downto 80))) +
(unsigned(sfp_data_i(79 downto 72)) + unsigned(sfp_data_i(71 downto 64))))) +
(((unsigned(sfp_data_i(63 downto 56)) + unsigned(sfp_data_i(55 downto 48))) +
(unsigned(sfp_data_i(47 downto 40)) + unsigned(sfp_data_i(39 downto 32)))) +
((unsigned(sfp_data_i(31 downto 24)) + unsigned(sfp_data_i(23 downto 16))) +
(unsigned(sfp_data_i(15 downto 8)) + unsigned(sfp_data_i(7 downto 0)))));
sfp_ddm_din(63) <= std_logic_vector(sfp_ddm_sum);
-- always offer to send the next byte pointed to by the address counter
sfp_i2c_tx_byte <= sfp_ddm_reg(to_integer(sfp_ddm_addr));
-- Drive the SFP DDM based on the r_done/w_done pulses
p_sfp_ddm_addr_counter : process (clk_i) is
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
sfp_ddm_addr <= (others => '0');
sfp_ddm_reg <= (others => (others => '0'));
else
-- check valid flag to load DDM register
if sfp_det_valid_i = '1' then
sfp_ddm_reg <= sfp_ddm_din;
else
sfp_ddm_reg <= (others => (others => '0'));
end if;
if sfp_i2c_r_done = '1' then
-- update address pointer with new value
sfp_ddm_addr <= unsigned(sfp_i2c_rx_byte(5 downto 0));
elsif sfp_i2c_w_done = '1' then
-- increase address pointer
sfp_ddm_addr <= sfp_ddm_addr + 1;
end if;
end if;
end if;
end process p_sfp_ddm_addr_counter;
end architecture rtl;
......@@ -608,6 +608,21 @@ package gencores_pkg is
id_ok_o : out std_logic);
end component gc_ds182x_readout;
------------------------------------------------------------------------------
-- SFP I2C Adapter
------------------------------------------------------------------------------
component gc_sfp_i2c_adapter is
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
scl_i : in std_logic;
sda_i : in std_logic;
sda_en_o : out std_logic;
sfp_det_valid_i : in std_logic;
sfp_data_i : in std_logic_vector (127 downto 0));
end component gc_sfp_i2c_adapter;
--============================================================================
-- Procedures and functions
--============================================================================
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment