// // Copyright 2021 Ettus Research, A National Instruments Brand // // SPDX-License-Identifier: LGPL-3.0-or-later // // Module: x4xx_gpio_atr // // Description: // // This module controls the behavior of a GPIO bus of arbitrary width // based on the current ATR state. The radio state is determined by // combining the TX and RX states of each rf channel in the radio in // the following order: {tx_rf1, rx_rf1, tx_rf0, rx_rf0} // // Parameters: // // REG_BASE : Base address to use for registers. // REG_SIZE : Register space size. // WIDTH : Number of GPIO lines controlled by this block. // module x4xx_gpio_atr #( parameter REG_BASE = 0, parameter REG_SIZE = 'h20, parameter WIDTH = 32 ) ( // Slave ctrlport interface input wire ctrlport_clk, input wire ctrlport_rst, input wire s_ctrlport_req_wr, input wire s_ctrlport_req_rd, input wire [19:0] s_ctrlport_req_addr, input wire [31:0] s_ctrlport_req_data, output reg s_ctrlport_resp_ack = 1'b0, output reg [ 1:0] s_ctrlport_resp_status = 2'b00, output reg [31:0] s_ctrlport_resp_data = {32 {1'bX}}, // Run state signals that indicate tx and rx operation input wire [3:0] db_state, // GPIO control signals input wire [WIDTH-1:0] gpio_in, //GPIO input state output reg [WIDTH-1:0] gpio_out = {WIDTH {1'b0}}, //GPIO output state output reg [WIDTH-1:0] gpio_ddr = {WIDTH {1'b0}} //GPIO direction (0=input, 1=output) ); `include "../../lib/rfnoc/core/ctrlport.vh" `include "regmap/gpio_atr_regmap_utils.vh" reg [WIDTH-1:0] in_atr_state [15:0]; initial begin in_atr_state[0] = {WIDTH {1'b0}}; in_atr_state[1] = {WIDTH {1'b0}}; in_atr_state[2] = {WIDTH {1'b0}}; in_atr_state[3] = {WIDTH {1'b0}}; in_atr_state[4] = {WIDTH {1'b0}}; in_atr_state[5] = {WIDTH {1'b0}}; in_atr_state[6] = {WIDTH {1'b0}}; in_atr_state[7] = {WIDTH {1'b0}}; in_atr_state[8] = {WIDTH {1'b0}}; in_atr_state[9] = {WIDTH {1'b0}}; in_atr_state[10] = {WIDTH {1'b0}}; in_atr_state[11] = {WIDTH {1'b0}}; in_atr_state[12] = {WIDTH {1'b0}}; in_atr_state[13] = {WIDTH {1'b0}}; in_atr_state[14] = {WIDTH {1'b0}}; in_atr_state[15] = {WIDTH {1'b0}}; end reg [WIDTH-1:0] ddr_reg, atr_disable, gpio_sw_rb = {WIDTH {1'b0}}; reg [WIDTH-1:0] ogpio, igpio = {WIDTH {1'b0}}; reg [WIDTH-1:0] classic_atr_select = {WIDTH {1'b0}}; // DB state/Classic ATR selector reg atr_mode = 1'b0; genvar state; //--------------------------------------------------------------------------- // Control interface handling //--------------------------------------------------------------------------- // Check that address is within this module's range. wire address_in_range = (s_ctrlport_req_addr >= REG_BASE) && (s_ctrlport_req_addr < REG_BASE + REG_SIZE); // Check that address is targeting an ATR state. wire address_is_atr = (s_ctrlport_req_addr >= REG_BASE + ATR_STATE(0)) && (s_ctrlport_req_addr <= REG_BASE + ATR_STATE(15)); // Decode the ATR state being addressed. wire [3:0]atr_address = s_ctrlport_req_addr[5:2]; always @ (posedge ctrlport_clk) begin if (ctrlport_rst) begin s_ctrlport_resp_ack <= 1'b0; s_ctrlport_resp_data <= {32 {1'bX}}; s_ctrlport_resp_status <= 2'b00; ddr_reg <= {WIDTH {1'b0}}; atr_disable <= {WIDTH {1'b0}}; classic_atr_select <= {WIDTH {1'b0}}; atr_mode <= 1'b0; in_atr_state[0] <= {WIDTH {1'b0}}; in_atr_state[1] <= {WIDTH {1'b0}}; in_atr_state[2] <= {WIDTH {1'b0}}; in_atr_state[3] <= {WIDTH {1'b0}}; in_atr_state[4] <= {WIDTH {1'b0}}; in_atr_state[5] <= {WIDTH {1'b0}}; in_atr_state[6] <= {WIDTH {1'b0}}; in_atr_state[7] <= {WIDTH {1'b0}}; in_atr_state[8] <= {WIDTH {1'b0}}; in_atr_state[9] <= {WIDTH {1'b0}}; in_atr_state[10] <= {WIDTH {1'b0}}; in_atr_state[11] <= {WIDTH {1'b0}}; in_atr_state[12] <= {WIDTH {1'b0}}; in_atr_state[13] <= {WIDTH {1'b0}}; in_atr_state[14] <= {WIDTH {1'b0}}; in_atr_state[15] <= {WIDTH {1'b0}}; end else begin // Write registers if (s_ctrlport_req_wr) begin // Acknowledge by default s_ctrlport_resp_ack <= 1'b1; s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'b0}}; s_ctrlport_resp_status <= CTRL_STS_OKAY; // Address ATR state writes if(address_is_atr) begin in_atr_state[atr_address][GPIO_STATE_A_MSB:GPIO_STATE_A] <= s_ctrlport_req_data[GPIO_STATE_A_MSB:GPIO_STATE_A]; in_atr_state[atr_address][GPIO_STATE_B_MSB:GPIO_STATE_B] <= s_ctrlport_req_data[GPIO_STATE_B_MSB:GPIO_STATE_B]; end else begin // Address writes to the rest of the register space case (s_ctrlport_req_addr) REG_BASE + ATR_OPTION_REGISTRER: begin atr_mode <= s_ctrlport_req_data[ATR_OPTION]; end REG_BASE + CLASSIC_ATR_CONFIG: begin classic_atr_select[RF_SELECT_A_MSB:RF_SELECT_A] <= s_ctrlport_req_data[RF_SELECT_A_MSB:RF_SELECT_A]; classic_atr_select[RF_SELECT_B_MSB:RF_SELECT_B] <= s_ctrlport_req_data[RF_SELECT_B_MSB:RF_SELECT_B]; end REG_BASE + GPIO_DIR: begin ddr_reg[GPIO_DIR_A_MSB:GPIO_DIR_A] <= s_ctrlport_req_data[GPIO_DIR_A_MSB:GPIO_DIR_A]; ddr_reg[GPIO_DIR_B_MSB:GPIO_DIR_B] <= s_ctrlport_req_data[GPIO_DIR_B_MSB:GPIO_DIR_B]; end REG_BASE + GPIO_DISABLED: begin atr_disable[GPIO_DISABLED_A_MSB:GPIO_DISABLED_A] <= s_ctrlport_req_data[GPIO_DISABLED_A_MSB:GPIO_DISABLED_A]; atr_disable[GPIO_DISABLED_B_MSB:GPIO_DISABLED_B] <= s_ctrlport_req_data[GPIO_DISABLED_B_MSB:GPIO_DISABLED_B]; end // No register implementation for provided address default: begin // Acknowledge and provide error status if address is in range if (address_in_range) begin s_ctrlport_resp_status <= CTRL_STS_CMDERR; // No response if out of range end else begin s_ctrlport_resp_ack <= 1'b0; end end endcase end // Read registers end else if (s_ctrlport_req_rd) begin // Acknowledge by default s_ctrlport_resp_ack <= 1'b1; s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'b0}}; s_ctrlport_resp_status <= CTRL_STS_OKAY; // Address ATR state reads if(address_is_atr) begin s_ctrlport_resp_data[GPIO_STATE_A_MSB:GPIO_STATE_A] <= in_atr_state[atr_address][GPIO_STATE_A_MSB:GPIO_STATE_A]; s_ctrlport_resp_data[GPIO_STATE_B_MSB:GPIO_STATE_B] <= in_atr_state[atr_address][GPIO_STATE_B_MSB:GPIO_STATE_B]; end else begin // Address reads to the rest of the register space case (s_ctrlport_req_addr) REG_BASE + ATR_OPTION_REGISTRER: begin s_ctrlport_resp_data[ATR_OPTION] <= atr_mode; end REG_BASE + CLASSIC_ATR_CONFIG: begin s_ctrlport_resp_data[RF_SELECT_A_MSB:RF_SELECT_A] <= classic_atr_select[RF_SELECT_A_MSB:RF_SELECT_A]; s_ctrlport_resp_data[RF_SELECT_B_MSB:RF_SELECT_B] <= classic_atr_select[RF_SELECT_B_MSB:RF_SELECT_B]; end REG_BASE + GPIO_DIR: begin s_ctrlport_resp_data[GPIO_DIR_A_MSB:GPIO_DIR_A] <= ddr_reg[GPIO_DIR_A_MSB:GPIO_DIR_A]; s_ctrlport_resp_data[GPIO_DIR_B_MSB:GPIO_DIR_B] <= ddr_reg[GPIO_DIR_B_MSB:GPIO_DIR_B]; end REG_BASE + GPIO_DISABLED: begin s_ctrlport_resp_data[GPIO_DISABLED_A_MSB:GPIO_DISABLED_A] <= atr_disable[GPIO_DISABLED_A_MSB:GPIO_DISABLED_A]; s_ctrlport_resp_data[GPIO_DISABLED_B_MSB:GPIO_DISABLED_B] <= atr_disable[GPIO_DISABLED_B_MSB:GPIO_DISABLED_B]; end REG_BASE + GPIO_IN: begin s_ctrlport_resp_data[GPIO_IN_A_MSB:GPIO_IN_A] <= gpio_sw_rb[GPIO_IN_A_MSB:GPIO_IN_A]; s_ctrlport_resp_data[GPIO_IN_B_MSB:GPIO_IN_B] <= gpio_sw_rb[GPIO_IN_B_MSB:GPIO_IN_B]; end // No register implementation for provided address default: begin // Acknowledge and provide error status if address is in range if (address_in_range) begin s_ctrlport_resp_status <= CTRL_STS_CMDERR; // No response if out of range end else begin s_ctrlport_resp_ack <= 1'b0; end end endcase end end else begin s_ctrlport_resp_ack <= 1'b0; end end end genvar i; //Pipeline for easier timing closure reg [ 3:0] db_state_d = 4'b0; reg atr_mode_d = 1'b0; reg [WIDTH-1:0] classic_atr_select_d = {WIDTH {1'b0}}; always @(posedge ctrlport_clk) begin db_state_d <= db_state; atr_mode_d <= atr_mode; classic_atr_select_d <= classic_atr_select; end generate for (i=0; i // // // Describes the behavior of GPIO lines when controlled by the ATR state. // // // // Holds a single bit setting for GPIO lines in both ports for a particular ATR sate // // // // // // // Describes GPIO behavior for the different ATR states. When @.ATR_OPTION // is set to use the DB states, TX and RX states for RF0 and RF1 are // combined to create a single vector. This creates 16 different // combinations, each with its own register. When @.ATR_OPTION is set to // classic ATR, offsets 0x00-0x03 in this register group will be driven // in accordance with the state of RF0, and offsets 0x04-0x07 will be // driven in accordance with the state of RF1. // CLASSIC ATR MAPPING: Idle[RF0:0x00; RF1:0x04], RX[RF0:0x01; RF1:0x05], // TX[RF0:0x02; RF1:0x06], FDX[RF0:0x03; RF1:0x07] // // // // // Controls whether GPIO lines use the TX and RX state of an RF channel // (Classic ATR) or the daughterboard state the selector for the // @.ATR_STATE. // // // // Sets the scheme in which RF states in the radio will control GPIO // lines. 0 = DB state is used. RF states are combined and the // GPIO state is driven based on all 16 @.ATR_STATE registers. // 1 = Each RF channel has its separate ATR state(Classic ATR). // Use register @.CLASSIC_ATR_CONFIG to indicate the RF channel // to which each GPIO line responds to. // // // // // // Controls the RF state mapping of each GPIO line when classic // ATR mode is active. // // // // Set which RF channel's state to reflect in the pins for // HDMI connector A when @.ATR_OPTION is set to classic ATR. // Controlled in a per-pin basis. // 0 = RF0 State(GPIO_ATR_STATE 0x00-0x03) // 1 = RF1 State(GPIO_ATR_STATE 0x04-0x07) // // // // // Set which RF channel's state to reflect in the pins of // HDMI connector B when @.ATR_OPTION is set to classic ATR. // Controlled in a per-pin basis. // 0 = RF0 State(GPIO_ATR_STATE 0x00-0x03) // 1 = RF1 State(GPIO_ATR_STATE 0x04-0x07) // // // // // // Controls the direction of each GPIO signal when controlled by the radio state. // 0 = GPIO pin set to input. 1 = GPIO pin set to output // // // // // // // Disable ATR Control. DB state 0 will be reflected regardless of the ATR state. // // // // // // // Reflects the logic state of each GPIO input. // // // // // // //XmlParse xml_off