// © 2020 Raptor Engineering, LLC // // Released under the terms of the AGPL v3 // See the LICENSE file for full details // Need RTC for SEL `include "simple_rtc.v" module ipmi_bt_slave_interface( input wire [8:0] input_xfer_write_addr, input wire [7:0] input_xfer_write_data, input wire input_xfer_write_clk, input wire input_xfer_write_wren, input wire [8:0] output_xfer_read_addr, output wire [7:0] output_xfer_read_data, input wire output_xfer_read_clk, output wire bmc_to_host_ctl_sms_req, output wire bmc_to_host_ctl_attn_req, input wire bmc_to_host_ctl_sms_ack, input wire bmc_to_host_ctl_attn_ack, input wire host_to_bmc_ctl_attn_req, input wire irq_ack, input wire irq_bmc_reset, output wire bmc_to_host_ctl_sms_ack_cont, output wire bmc_to_host_ctl_attn_ack_cont, output wire host_to_bmc_ctl_attn_req_cont, output wire irq_ack_cont, output wire irq_bmc_reset_cont, input wire h_busy, output wire b_busy, input wire irq_enable, output wire irq_req, output wire hiomap_new_window_req, input wire hiomap_new_window_ack, output reg [27:0] hiomap_active_window_start_address, output reg [27:0] hiomap_active_window_size_bytes, output wire hiomap_window_type_write, output wire hiomap_flush_req, input wire hiomap_flush_ack, output wire [27:0] hiomap_flush_sector_count, output wire hiomap_flush_type_erase, output wire [27:0] hiomap_erase_address_offset, output wire [27:0] hiomap_erase_sector_count, output wire [27:0] hiomap_erase_address_step, output wire [27:0] hiomap_program_address_step, output wire [27:0] hiomap_def_win_size_bytes, input wire reset, input wire logic_clk, input wire rtc_base_clock, output wire [7:0] debug_port ); reg [8:0] input_xfer_read_addr; wire [7:0] input_xfer_read_data; reg [8:0] output_xfer_write_addr; reg [7:0] output_xfer_write_data; reg output_xfer_write_wren = 0; reg b_busy_reg = 1; reg h_busy_reg = 0; reg bmc_to_host_ctl_sms_req_reg = 0; reg bmc_to_host_ctl_attn_req_reg = 0; reg host_to_bmc_ctl_attn_req_cont_reg = 0; reg bmc_to_host_ctl_attn_ack_cont_reg = 0; reg irq_ack_cont_reg = 0; reg irq_bmc_reset_cont_reg = 0; reg irq_req_reg = 0; reg hiomap_new_window_req_reg = 0; reg hiomap_window_type_write_reg = 0; reg hiomap_flush_req_reg = 0; reg [27:0] hiomap_flush_sector_count_reg = 0; reg hiomap_flush_type_erase_reg = 0; reg [27:0] hiomap_erase_address_offset_reg = 0; reg [27:0] hiomap_erase_sector_count_reg = 0; assign b_busy = b_busy_reg; assign bmc_to_host_ctl_sms_req = bmc_to_host_ctl_sms_req_reg; assign bmc_to_host_ctl_attn_req = bmc_to_host_ctl_attn_req_reg; assign host_to_bmc_ctl_attn_req_cont = host_to_bmc_ctl_attn_req_cont_reg; assign bmc_to_host_ctl_attn_ack_cont = bmc_to_host_ctl_attn_ack_cont_reg; assign irq_ack_cont = irq_ack_cont_reg; assign irq_bmc_reset_cont = irq_bmc_reset_cont_reg; assign irq_req = irq_req_reg; assign hiomap_new_window_req = hiomap_new_window_req_reg; assign hiomap_window_type_write = hiomap_window_type_write_reg; assign hiomap_flush_req = hiomap_flush_req_reg; assign hiomap_flush_sector_count = hiomap_flush_sector_count_reg; assign hiomap_flush_type_erase = hiomap_flush_type_erase_reg; assign hiomap_erase_address_offset = hiomap_erase_address_offset_reg; assign hiomap_erase_sector_count = hiomap_erase_sector_count_reg; parameter INTERFACE_INITIALIZE_STATE_01 = 0; parameter INTERFACE_INITIALIZE_STATE_02 = 1; parameter INTERFACE_TRANSFER_STATE_IDLE = 2; parameter INTERFACE_TRANSFER_STATE_WT01 = 4; parameter INTERFACE_TRANSFER_STATE_CP01 = 8; parameter INTERFACE_TRANSFER_STATE_CP02 = 9; parameter INTERFACE_TRANSFER_STATE_CP03 = 10; parameter INTERFACE_TRANSFER_STATE_CP04 = 11; parameter INTERFACE_TRANSFER_STATE_CP05 = 12; parameter INTERFACE_TRANSFER_STATE_CP06 = 13; parameter INTERFACE_TRANSFER_STATE_CP07 = 14; parameter INTERFACE_TRANSFER_STATE_CP08 = 15; parameter INTERFACE_TRANSFER_STATE_CP09 = 16; parameter INTERFACE_TRANSFER_STATE_RL01 = 32; parameter INTERFACE_TRANSFER_STATE_RL02 = 33; parameter INTERFACE_TRANSFER_STATE_RL03 = 34; parameter INTERFACE_TRANSFER_STATE_RL04 = 35; parameter INTERFACE_TRANSFER_STATE_RL05 = 36; parameter INTERFACE_TRANSFER_STATE_RL06 = 37; parameter INTERFACE_TRANSFER_STATE_RT01 = 64; parameter INTERFACE_TRANSFER_STATE_RT02 = 65; parameter INTERFACE_TRANSFER_STATE_RT03 = 66; parameter INTERFACE_TRANSFER_STATE_RT04 = 67; parameter INTERFACE_TRANSFER_STATE_RT05 = 68; parameter INTERFACE_TRANSFER_STATE_RT06 = 69; parameter INTERFACE_TRANSFER_STATE_SM01 = 96; parameter INTERFACE_TRANSFER_STATE_SM02 = 97; parameter INTERFACE_TRANSFER_STATE_SM03 = 98; parameter INTERFACE_TRANSFER_STATE_SM04 = 99; parameter INTERFACE_TRANSFER_STATE_SM05 = 100; parameter INTERFACE_TRANSFER_STATE_HM01 = 128; parameter INTERFACE_TRANSFER_STATE_HM02 = 129; parameter INTERFACE_TRANSFER_STATE_HM03 = 130; parameter INTERFACE_TRANSFER_STATE_HM04 = 131; parameter INTERFACE_TRANSFER_STATE_HM05 = 132; parameter INTERFACE_TRANSFER_STATE_HM06 = 133; parameter INTERFACE_TRANSFER_STATE_HM07 = 134; parameter INTERFACE_TRANSFER_STATE_HM08 = 135; parameter INTERFACE_TRANSFER_STATE_HM09 = 136; parameter INTERFACE_TRANSFER_STATE_HM10 = 137; parameter INTERFACE_TRANSFER_STATE_HM11 = 138; parameter INTERFACE_TRANSFER_STATE_DM01 = 160; parameter INTERFACE_TRANSFER_STATE_DM02 = 161; parameter INTERFACE_TRANSFER_STATE_DM03 = 162; parameter INTERFACE_TRANSFER_STATE_DM04 = 163; parameter INTERFACE_TRANSFER_STATE_DM05 = 164; parameter INTERFACE_TRANSFER_STATE_DM06 = 165; parameter INTERFACE_TRANSFER_STATE_DM07 = 166; parameter INTERFACE_TRANSFER_STATE_DM08 = 167; parameter INTERFACE_TRANSFER_STATE_ST01 = 196; parameter INTERFACE_TRANSFER_STATE_ST02 = 197; parameter INTERFACE_TRANSFER_STATE_ST03 = 198; parameter INTERFACE_TRANSFER_STATE_ST04 = 199; parameter INTERFACE_TRANSFER_STATE_ST05 = 200; parameter COMMAND_PROCESS_STATE_RG01 = 13; // Sensor mappings // NOTE: These may change from platform to platform! // The values below are valid for Raptor Computing Systems Talos II / Blackbird parameter IPMI_SENSOR_FW_BOOT = 8'h02; // XML ID /sys-0/fw_boot_sensor [W] parameter IPMI_SENSOR_CPU0_OCC_ACTIVE = 8'h03; // XML ID /sys-0/node-0/motherboard-0/proc_socket-0/module-0/p9_proc_s/occ/occ_active_sensor [W] parameter IPMI_SENSOR_CPU1_OCC_ACTIVE = 8'h04; // XML ID /sys-0/node-0/motherboard-0/proc_socket-1/module-0/p9_proc_s/occ/occ_active_sensor [W] parameter IPMI_SENSOR_CPU0_FUNC = 8'h08; // XML ID /sys-0/node-0/motherboard-0/proc_socket-0/module-0/p9_proc_s/cpu_func_sensor [W] parameter IPMI_SENSOR_CPU1_FUNC = 8'h09; // XML ID /sys-0/node-0/motherboard-0/proc_socket-1/module-0/p9_proc_s/cpu_func_sensor [W] parameter IPMI_SENSOR_BOOT_COUNT = 8'h8b; // XML ID /sys-0/boot_count_sensor [RW] parameter IPMI_SENSOR_PLANAR_FAULT = 8'h8c; // XML ID /sys-0/node-0/motherboard_fault_sensor [W] parameter IPMI_SENSOR_REF_CLK_FAULT = 8'h8d; // XML ID /sys-0/node-0/ref_clk_sensor [W] parameter IPMI_SENSOR_PCIE_CLK_FAULT = 8'h8e; // XML ID /sys-0/node-0/pci_clk_sensor [W] parameter IPMI_SENSOR_TOD_CLK_FAULT = 8'h8f; // XML ID /sys-0/node-0/tod_clk_sensor [W] parameter IPMI_SENSOR_APSS_FAULT = 8'h93; // XML ID /sys-0/node-0/apss_fault_sensor [W] parameter IPMI_SENSOR_DERATING_FACTOR = 8'h96; // XML ID /sys-0/ps_derating_sensor [R] // Inventory bitfield sensor ranges parameter IPMI_SENSOR_INV_DIMM_FUNC_BEG = 8'h0b; // XML ID /sys-0/node-0/motherboard-0/dimmconn-/dimm-0/dimm_func_sensor [W] parameter IPMI_SENSOR_INV_DIMM_FUNC_END = 8'h1a; parameter IPMI_SENSOR_INV_CPU0_FUNC_BEG = 8'h2b; // XML ID /sys-0/node-0/motherboard-0/proc_socket-0/module-0/p9_proc_s/eq/ex/core/cpucore_func_sensor [W] parameter IPMI_SENSOR_INV_CPU0_FUNC_END = 8'h42; parameter IPMI_SENSOR_INV_CPU1_FUNC_BEG = 8'h43; // XML ID /sys-0/node-0/motherboard-0/proc_socket-1/module-0/p9_proc_s/eq/ex/core/cpucore_func_sensor [W] parameter IPMI_SENSOR_INV_CPU1_FUNC_END = 8'h5a; // Event Data Byte bitfield mappings // These are believed constant across hostboot versions, and are defined in hostboot src/include/usr/ipmi/ipmisensor.H parameter IPMI_OP_EVT_SHIFT_DIMM_DSBL = 4; parameter IPMI_OP_EVT_SHIFT_DIMM_PRST = 6; parameter IPMI_OP_EVT_SHIFT_PROC_PRST = 7; parameter IPMI_OP_EVT_SHIFT_PROC_DSBL = 8; // IPMI network function codes parameter IPMI_NETFN_SENS_ET_REQ = 8'h04; parameter IPMI_NETFN_APP_REQUEST = 8'h06; parameter IPMI_NETFN_STORAGE_REQ = 8'h0a; parameter IPMI_NETFN_DCMI_GP_REQ = 8'h2c; parameter IPMI_NETFN_OEM_IBM_REQ = 8'h3a; // Sensor / Event commands parameter IPMI_CMD_GET_SNS_READNG = 8'h2d; parameter IPMI_CMD_SET_SN_RD_EV_S = 8'h30; // Application commands parameter IPMI_CMD_GET_DEVICE_ID = 8'h01; parameter IPMI_CMD_GET_BT_INT_CAP = 8'h36; // Storage commands parameter IPMI_CMD_GET_SEL_TIME = 8'h48; parameter IPMI_CMD_SET_SEL_TIME = 8'h49; // IBM commands parameter IPMI_CMD_IBM_HIOMAP_REQ = 8'h5a; parameter IPMI_CC_NO_ERROR = 8'h00; parameter IPMI_CC_SNS_NOT_PRSNT = 8'hcb; parameter IPMI_CC_INVALID_COMMAND = 8'hc1; parameter BASE_IPMI_RESPONSE_LENGTH = 4; parameter BASE_DCMI_RESPONSE_LENGTH = BASE_IPMI_RESPONSE_LENGTH + 1; parameter BASE_HIOMAP_RESPONSE_LENGTH = BASE_IPMI_RESPONSE_LENGTH + 2; // DCMI commands parameter DCMI_CMD_GET_CAPABILITIES = 8'h01; parameter DCMI_CMD_GET_POWER_CAP = 8'h03; // DCMI response codes parameter DCMI_CC_NO_ERROR = 8'h00; parameter DCMI_CC_INVALID_COMMAND = 8'hc1; // DCMI parameters parameter DCMI_ENFORCE_POWER_LIMIT = 0; parameter DCMI_POWER_LIMIT_W = 190; parameter DCMI_CORR_LIMIT_TIME_MS = 500; parameter DCMI_PWR_SAMPLE_PERIOD_S = 1; // HIOMAP commands parameter HIOMAP_CMD_RESET = 8'h01; parameter HIOMAP_CMD_GET_INFO = 8'h02; parameter HIOMAP_CMD_GET_FLASH_INFO = 8'h03; parameter HIOMAP_CMD_CREATE_RD_WIN = 8'h04; parameter HIOMAP_CMD_CLOSE_WINDOW = 8'h05; parameter HIOMAP_CMD_CREATE_WR_WIN = 8'h06; parameter HIOMAP_CMD_MARK_DIRTY = 8'h07; parameter HIOMAP_CMD_FLUSH = 8'h08; parameter HIOMAP_CMD_ACK = 8'h09; parameter HIOMAP_CMD_ERASE = 8'h0a; parameter HIOMAP_CMD_GET_FLASH_NAME = 8'h0b; parameter HIOMAP_CMD_LOCK = 8'h0c; parameter HIOMAP_WINDOW_TYPE_READ = 2'h0; parameter HIOMAP_WINDOW_TYPE_WRITE = 2'h1; parameter HIOMAP_WINDOW_INACTIVE = 2'h2; // HIOMAP parameters parameter HIOMAP_SUGGESTED_TIMEOUT_S = 15; parameter HIOMAP_PNOR_DEVICE_COUNT = 1; // 4k block size // Requires subsector erase capability parameter FLASH_BLOCK_SIZE_SHIFT = 12; // 64MB Flash parameter FLASH_SIZE_BYTES = 67108864; // 256 byte pages parameter FLASH_PAGE_SIZE_BYTES = 256; // Minimum erase size is one block parameter FLASH_ERASE_GRAN_BLOCKS = 1; // Maximum cacheable / writeable chunk size // Constrained by available BRAM in the FPGA parameter FLASH_MAX_WR_WINDOW_BYTES = 4096; // Calculated and specification locked HIOMAP parameters parameter LPC_ADDRESS_BITS = 28; parameter FLASH_SIZE_BLOCKS = FLASH_SIZE_BYTES >> FLASH_BLOCK_SIZE_SHIFT; parameter FLASH_ERASE_GRAN_BYTES = FLASH_ERASE_GRAN_BLOCKS << FLASH_BLOCK_SIZE_SHIFT; // Flash device constants assign hiomap_erase_address_step = 1 << FLASH_BLOCK_SIZE_SHIFT; assign hiomap_program_address_step = FLASH_PAGE_SIZE_BYTES; assign hiomap_def_win_size_bytes = FLASH_SIZE_BYTES; // OpenPOWER system constants parameter OPENPOWER_BOOT_COUNT_SENSOR_DEFAULT = 2; // Main sequencer reg [7:0] ipmi_transfer_state = 0; reg [7:0] ipmi_req_data_byte = 0; reg [7:0] ipmi_resp_data_byte = 0; reg [7:0] ipmi_req_length; reg [7:0] ipmi_resp_length; reg [5:0] ipmi_netfn; reg [1:0] ipmi_lun; reg [7:0] ipmi_command; reg [7:0] ipmi_seq; reg [7:0] ipmi_completion_code; reg [7:0] ipmi_group_extension_id; reg [7:0] ipmi_sensor_number; reg [7:0] ipmi_sensor_value; reg [14:0] ipmi_event_assertion_req_value; reg [14:0] ipmi_event_deassertion_req_value; reg ipmi_sensor_edb_write_requested; reg ipmi_sensor_write_requested; reg [7:0] openpower_boot_count_sensor; reg [15:0] openpower_dimm_functional_bitfield; reg [23:0] openpower_cpu0_functional_bitfield; reg [23:0] openpower_cpu1_functional_bitfield; reg [7:0] dcmi_parameter_selector; reg [7:0] dcmi_response_length_add; reg [7:0] hiomap_cmd; reg [7:0] hiomap_seq; reg [7:0] hiomap_active_device_id = 0; reg [7:0] hiomap_protocol_version = 0; reg [(LPC_ADDRESS_BITS-1):0] hiomap_window_start_address = 0; reg [(LPC_ADDRESS_BITS-1):0] hiomap_window_length_bytes = FLASH_SIZE_BYTES; reg [(LPC_ADDRESS_BITS-1):0] hiomap_erase_offset_bytes = 0; reg [(LPC_ADDRESS_BITS-1):0] hiomap_erase_length_bytes = 0; reg [1:0] hiomap_window_type = HIOMAP_WINDOW_TYPE_READ; reg host_to_bmc_ctl_attn_req_prev = 0; reg bmc_to_host_ctl_attn_req_prev = 0; assign debug_port = ipmi_transfer_state; // Instantiate simple RTC to back timestamp-reliant calls reg [31:0] rtc_clock_set; wire [31:0] rtc_current_time; reg rtc_set_strobe = 0; simple_rtc simple_rtc( .base_clock(rtc_base_clock), .clock_set(rtc_clock_set), .current_time(rtc_current_time), .set_strobe(rtc_set_strobe) ); always @(posedge logic_clk) begin if (reset) begin ipmi_transfer_state <= INTERFACE_INITIALIZE_STATE_01; hiomap_window_start_address <= 0; hiomap_window_length_bytes <= FLASH_SIZE_BYTES; hiomap_window_type <= HIOMAP_WINDOW_TYPE_READ; hiomap_window_type_write_reg = 0; hiomap_flush_type_erase_reg = 0; b_busy_reg <= 1; output_xfer_write_wren <= 0; bmc_to_host_ctl_attn_req_reg <= 0; host_to_bmc_ctl_attn_req_prev <= 0; openpower_boot_count_sensor <= OPENPOWER_BOOT_COUNT_SENSOR_DEFAULT; openpower_dimm_functional_bitfield <= 0; openpower_cpu0_functional_bitfield <= 0; openpower_cpu1_functional_bitfield <= 0; end else begin case (ipmi_transfer_state) INTERFACE_INITIALIZE_STATE_01: begin // Reset all control signals hiomap_window_type_write_reg = 0; hiomap_flush_type_erase_reg = 0; b_busy_reg <= 1; output_xfer_write_wren <= 0; bmc_to_host_ctl_attn_req_reg <= 0; host_to_bmc_ctl_attn_req_prev <= 0; ipmi_transfer_state <= INTERFACE_INITIALIZE_STATE_02; end INTERFACE_INITIALIZE_STATE_02: begin // Clear any active interlocked control signals if (host_to_bmc_ctl_attn_req) begin host_to_bmc_ctl_attn_req_cont_reg <= 1; end if (bmc_to_host_ctl_attn_ack) begin bmc_to_host_ctl_attn_ack_cont_reg <= 1; end if (!host_to_bmc_ctl_attn_req && !bmc_to_host_ctl_attn_ack) begin host_to_bmc_ctl_attn_req_cont_reg <= 0; bmc_to_host_ctl_attn_ack_cont_reg <= 0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_IDLE; end end INTERFACE_TRANSFER_STATE_IDLE: begin if (!host_to_bmc_ctl_attn_req_prev && host_to_bmc_ctl_attn_req) begin // Write transfer from host to BMC ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_WT01; end else begin if (host_to_bmc_ctl_attn_req) begin // Interlock failed! // Try to recover... host_to_bmc_ctl_attn_req_cont_reg <= 1; end else begin host_to_bmc_ctl_attn_req_cont_reg <= 0; end end b_busy_reg <= 0; end INTERFACE_TRANSFER_STATE_WT01: begin // Set busy and wait for ATN bit clear by external logic b_busy_reg <= 1; if (host_to_bmc_ctl_attn_req) begin host_to_bmc_ctl_attn_req_cont_reg <= 1; end else begin host_to_bmc_ctl_attn_req_cont_reg <= 0; input_xfer_read_addr <= 0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_CP01; end end INTERFACE_TRANSFER_STATE_CP01: begin // Wait for RAM to respond with read data ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_CP02; end INTERFACE_TRANSFER_STATE_CP02: begin // Parse incoming command and generate response ipmi_req_length <= input_xfer_read_data; input_xfer_read_addr <= input_xfer_read_addr + 1; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_CP03; end INTERFACE_TRANSFER_STATE_CP03: begin // Wait for RAM to respond with read data ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_CP04; end INTERFACE_TRANSFER_STATE_CP04: begin ipmi_netfn <= input_xfer_read_data[7:2]; ipmi_lun <= input_xfer_read_data[1:0]; input_xfer_read_addr <= input_xfer_read_addr + 1; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_CP05; end INTERFACE_TRANSFER_STATE_CP05: begin // Wait for RAM to respond with read data ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_CP06; end INTERFACE_TRANSFER_STATE_CP06: begin ipmi_seq <= input_xfer_read_data; input_xfer_read_addr <= input_xfer_read_addr + 1; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_CP07; end INTERFACE_TRANSFER_STATE_CP07: begin // Wait for RAM to respond with read data ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_CP08; end INTERFACE_TRANSFER_STATE_CP08: begin ipmi_command <= input_xfer_read_data; input_xfer_read_addr <= input_xfer_read_addr + 1; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_CP09; end INTERFACE_TRANSFER_STATE_CP09: begin // Determine response length case (ipmi_netfn) IPMI_NETFN_SENS_ET_REQ: begin case (ipmi_command) IPMI_CMD_GET_SNS_READNG, IPMI_CMD_SET_SN_RD_EV_S: begin // The final response length is not set here. // Response length will be set by the HIOMAP // protocol handler prior to return to // the standard transfer flow. ipmi_resp_length <= BASE_IPMI_RESPONSE_LENGTH; ipmi_completion_code <= IPMI_CC_NO_ERROR; end default: begin ipmi_resp_length <= BASE_IPMI_RESPONSE_LENGTH; ipmi_completion_code <= IPMI_CC_INVALID_COMMAND; end endcase end IPMI_NETFN_APP_REQUEST: begin case (ipmi_command) IPMI_CMD_GET_DEVICE_ID: begin ipmi_resp_length <= BASE_IPMI_RESPONSE_LENGTH + 15; ipmi_completion_code <= IPMI_CC_NO_ERROR; end IPMI_CMD_GET_BT_INT_CAP: begin ipmi_resp_length <= BASE_IPMI_RESPONSE_LENGTH + 5; ipmi_completion_code <= IPMI_CC_NO_ERROR; end default: begin ipmi_resp_length <= BASE_IPMI_RESPONSE_LENGTH; ipmi_completion_code <= IPMI_CC_INVALID_COMMAND; end endcase end IPMI_NETFN_STORAGE_REQ: begin case (ipmi_command) IPMI_CMD_GET_SEL_TIME, IPMI_CMD_SET_SEL_TIME: begin // The final response length is not set here. // Response length will be set by the HIOMAP // protocol handler prior to return to // the standard transfer flow. ipmi_resp_length <= BASE_IPMI_RESPONSE_LENGTH; ipmi_completion_code <= IPMI_CC_NO_ERROR; end default: begin ipmi_resp_length <= BASE_IPMI_RESPONSE_LENGTH; ipmi_completion_code <= IPMI_CC_INVALID_COMMAND; end endcase end IPMI_NETFN_DCMI_GP_REQ: begin case (ipmi_command) DCMI_CMD_GET_CAPABILITIES, DCMI_CMD_GET_POWER_CAP: begin // The final response length is not set here. // Response length will be set by the HIOMAP // protocol handler prior to return to // the standard transfer flow. ipmi_resp_length <= BASE_DCMI_RESPONSE_LENGTH; ipmi_completion_code <= DCMI_CC_NO_ERROR; end default: begin ipmi_resp_length <= BASE_IPMI_RESPONSE_LENGTH; ipmi_completion_code <= DCMI_CC_INVALID_COMMAND; end endcase end IPMI_NETFN_OEM_IBM_REQ: begin case (ipmi_command) IPMI_CMD_IBM_HIOMAP_REQ: begin // The final response length is not set here. // Response length will be set by the HIOMAP // protocol handler prior to return to // the standard transfer flow. ipmi_resp_length <= BASE_IPMI_RESPONSE_LENGTH; ipmi_completion_code <= IPMI_CC_NO_ERROR; end default: begin ipmi_resp_length <= BASE_IPMI_RESPONSE_LENGTH; ipmi_completion_code <= IPMI_CC_INVALID_COMMAND; end endcase end default: begin ipmi_resp_length <= BASE_IPMI_RESPONSE_LENGTH; ipmi_completion_code <= IPMI_CC_INVALID_COMMAND; end endcase if (!h_busy_reg) begin if (ipmi_netfn == IPMI_NETFN_SENS_ET_REQ) begin // Escape into sensor / event handler flow input_xfer_read_addr <= 4; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_SM01; end else if (ipmi_netfn == IPMI_NETFN_STORAGE_REQ) begin // Escape into storage handler flow input_xfer_read_addr <= 4; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_ST01; end else if ((ipmi_netfn == IPMI_NETFN_OEM_IBM_REQ) && (ipmi_command == IPMI_CMD_IBM_HIOMAP_REQ)) begin // Escape into HIOMAP handler flow input_xfer_read_addr <= 4; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM01; end else if (ipmi_netfn == IPMI_NETFN_DCMI_GP_REQ) begin // Escape into DCMI handler flow input_xfer_read_addr <= 4; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_DM01; end else begin ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RL01; end end end INTERFACE_TRANSFER_STATE_RL01: begin // Load response header into buffer output_xfer_write_addr <= 0; output_xfer_write_data <= ipmi_resp_length; output_xfer_write_wren <= 1'b1; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RL02; end INTERFACE_TRANSFER_STATE_RL02: begin output_xfer_write_addr <= output_xfer_write_addr + 1; output_xfer_write_data[7:2] <= ipmi_netfn + 1; output_xfer_write_data[1:0] <= ipmi_lun; output_xfer_write_wren <= 1'b1; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RL03; end INTERFACE_TRANSFER_STATE_RL03: begin output_xfer_write_addr <= output_xfer_write_addr + 1; output_xfer_write_data <= ipmi_seq; output_xfer_write_wren <= 1'b1; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RL04; end INTERFACE_TRANSFER_STATE_RL04: begin output_xfer_write_addr <= output_xfer_write_addr + 1; output_xfer_write_data <= ipmi_command; output_xfer_write_wren <= 1'b1; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RL05; end INTERFACE_TRANSFER_STATE_RL05: begin output_xfer_write_addr <= output_xfer_write_addr + 1; output_xfer_write_data <= ipmi_completion_code; output_xfer_write_wren <= 1'b1; ipmi_resp_data_byte <= 0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RL06; end INTERFACE_TRANSFER_STATE_RL06: begin // Write response data if required case (ipmi_netfn) IPMI_NETFN_SENS_ET_REQ: begin // Already written by sensor / event handler flow output_xfer_write_wren <= 1'b0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RT01; end IPMI_NETFN_APP_REQUEST: begin case (ipmi_command) IPMI_CMD_GET_DEVICE_ID: begin case (ipmi_resp_data_byte) 0: output_xfer_write_data <= 8'h00; 1: output_xfer_write_data <= 8'h00; 2: output_xfer_write_data <= 8'h00; 3: output_xfer_write_data <= 8'h00; 4: output_xfer_write_data <= 8'h02; 5: output_xfer_write_data <= 8'h00; 6: output_xfer_write_data <= 8'h05; 7: output_xfer_write_data <= 8'hcb; 8: output_xfer_write_data <= 8'h00; 9: output_xfer_write_data <= 8'h01; 10: output_xfer_write_data <= 8'h00; 11: output_xfer_write_data <= 8'h00; 12: output_xfer_write_data <= 8'h00; 13: output_xfer_write_data <= 8'h00; 14: output_xfer_write_data <= 8'h00; endcase if (ipmi_resp_data_byte < 15) begin output_xfer_write_addr <= output_xfer_write_addr + 1; output_xfer_write_wren <= 1'b1; ipmi_resp_data_byte <= ipmi_resp_data_byte + 1; end else begin output_xfer_write_wren <= 1'b0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RT01; end end IPMI_CMD_GET_BT_INT_CAP: begin case (ipmi_resp_data_byte) 0: output_xfer_write_data <= 8'h01; 1: output_xfer_write_data <= 8'h3f; 2: output_xfer_write_data <= 8'h3f; 3: output_xfer_write_data <= 8'h01; 4: output_xfer_write_data <= 8'h01; endcase if (ipmi_resp_data_byte < 5) begin output_xfer_write_addr <= output_xfer_write_addr + 1; output_xfer_write_wren <= 1'b1; ipmi_resp_data_byte <= ipmi_resp_data_byte + 1; end else begin output_xfer_write_wren <= 1'b0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RT01; end end default: begin output_xfer_write_wren <= 1'b0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RT01; end endcase end IPMI_NETFN_STORAGE_REQ: begin // Already written by the storage handler flow output_xfer_write_wren <= 1'b0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RT01; end IPMI_NETFN_DCMI_GP_REQ: begin // Already written by DCMI handler flow output_xfer_write_wren <= 1'b0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RT01; end IPMI_NETFN_OEM_IBM_REQ: begin case (ipmi_command) IPMI_CMD_IBM_HIOMAP_REQ: begin // Already written by HIOMAP handler flow output_xfer_write_wren <= 1'b0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RT01; end default: begin output_xfer_write_wren <= 1'b0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RT01; end endcase end default: begin output_xfer_write_wren <= 1'b0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RT01; end endcase end INTERFACE_TRANSFER_STATE_RT01: begin // Check for active external sequencer commands if (hiomap_new_window_req_reg || hiomap_flush_req_reg) begin if (hiomap_new_window_ack) begin hiomap_new_window_req_reg <= 0; end if (hiomap_flush_ack) begin hiomap_flush_req_reg <= 0; end end else begin ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RT02; end // BMC has read and acted on incoming buffer contents // Clear busy flag (a.k.a. H2B buffer lock) b_busy_reg <= 0; end INTERFACE_TRANSFER_STATE_RT02: begin // Wait for active external sequencer commands to fully complete, // and for host to return to ready status if (!h_busy_reg && !hiomap_new_window_ack && !hiomap_flush_ack) begin ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RT03; end end INTERFACE_TRANSFER_STATE_RT03: begin // Signal data ready bmc_to_host_ctl_attn_req_reg <= 1; if (h_busy_reg) begin // Host has entered read cycle, so it is now safe to // process the ATN bit clear ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RT04; end end INTERFACE_TRANSFER_STATE_RT04: begin if (bmc_to_host_ctl_attn_ack) begin bmc_to_host_ctl_attn_req_reg <= 0; bmc_to_host_ctl_attn_ack_cont_reg <= 1; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RT05; end end INTERFACE_TRANSFER_STATE_RT05: begin if (!bmc_to_host_ctl_attn_ack) begin bmc_to_host_ctl_attn_ack_cont_reg <= 0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RT06; end end INTERFACE_TRANSFER_STATE_RT06: begin if (!h_busy_reg) begin ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_IDLE; end end INTERFACE_TRANSFER_STATE_SM01: begin ipmi_req_data_byte <= 0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_SM02; end INTERFACE_TRANSFER_STATE_SM02: begin // Decode parameters as required case (ipmi_command) IPMI_CMD_GET_SNS_READNG: begin ipmi_sensor_number <= input_xfer_read_data; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_SM04; end IPMI_CMD_SET_SN_RD_EV_S: begin case (ipmi_req_data_byte) 0: begin ipmi_sensor_number <= input_xfer_read_data; end 1: begin if (input_xfer_read_data[7:6] == 2'b00) begin ipmi_sensor_edb_write_requested = 0; end else begin ipmi_sensor_edb_write_requested = 1; end if (input_xfer_read_data[1:0] == 2'b01) begin ipmi_sensor_write_requested = 1; end else begin ipmi_sensor_write_requested = 0; end end 2: begin ipmi_sensor_value <= input_xfer_read_data; end 3: begin ipmi_event_assertion_req_value[7:0] <= input_xfer_read_data; end 4: begin ipmi_event_assertion_req_value[14:8] <= input_xfer_read_data[6:0]; end 5: begin ipmi_event_deassertion_req_value[7:0] <= input_xfer_read_data; end 6: begin ipmi_event_deassertion_req_value[14:8] <= input_xfer_read_data[6:0]; end // Bytes 7-9 ignored for now as they are not relevant to the OpenPOWER sensor control scheme endcase if (ipmi_req_data_byte < 9) begin ipmi_req_data_byte <= ipmi_req_data_byte + 1; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_SM03; end else begin ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_SM04; end end default: begin ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_SM04; end endcase input_xfer_read_addr <= input_xfer_read_addr + 1; ipmi_resp_data_byte <= 0; output_xfer_write_addr <= BASE_IPMI_RESPONSE_LENGTH; end INTERFACE_TRANSFER_STATE_SM03: begin // Wait for RAM to respond with read data ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_SM02; end INTERFACE_TRANSFER_STATE_SM04: begin // Sanitize parameters // NOTE: For future implementation if required ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_SM05; end INTERFACE_TRANSFER_STATE_SM05: begin case (ipmi_command) IPMI_CMD_GET_SNS_READNG: begin case (ipmi_sensor_number) IPMI_SENSOR_BOOT_COUNT: begin case (ipmi_resp_data_byte) 0: output_xfer_write_data <= openpower_boot_count_sensor; 1: output_xfer_write_data <= 8'h00; // No events from this sensor 2: output_xfer_write_data <= 8'h00; // No event flags set (byte 1) 3: output_xfer_write_data <= 8'h80; // No event flags set (byte 2) default: output_xfer_write_data <= 8'h00; endcase end IPMI_SENSOR_DERATING_FACTOR: begin case (ipmi_resp_data_byte) 0: output_xfer_write_data <= 8'h64; // Raw sensor value. 100% (no derate) 1: output_xfer_write_data <= 8'h00; // No events from this sensor 2: output_xfer_write_data <= 8'h64; // 100% (no derate). Yes, this is passed in the event status field (!?) 3: output_xfer_write_data <= 8'h80; // This is an abuse of the event status field, but it's in hostboot, so...not much choice. default: output_xfer_write_data <= 8'h00; endcase end default: begin output_xfer_write_data <= 8'h00; // Signal error via standard IPMI error mechanism ipmi_resp_length <= BASE_IPMI_RESPONSE_LENGTH; ipmi_completion_code <= IPMI_CC_SNS_NOT_PRSNT; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RL01; end endcase if (ipmi_resp_data_byte < 4) begin output_xfer_write_addr <= output_xfer_write_addr + 1; output_xfer_write_wren <= 1'b1; ipmi_resp_data_byte <= ipmi_resp_data_byte + 1; end else begin output_xfer_write_wren <= 1'b0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RL01; end ipmi_resp_length <= BASE_IPMI_RESPONSE_LENGTH + 4; end IPMI_CMD_SET_SN_RD_EV_S: begin case (ipmi_sensor_number) IPMI_SENSOR_FW_BOOT: begin // NOTE: For future implementation if required if (ipmi_sensor_write_requested) begin // Sensor value write not supported for this sensor ipmi_completion_code <= 8'h80; end if (ipmi_sensor_edb_write_requested) begin // Event Data Byte write not supported for this sensor ipmi_completion_code <= 8'h81; end end IPMI_SENSOR_CPU0_OCC_ACTIVE: begin // NOTE: For future implementation if required if (ipmi_sensor_write_requested) begin // Sensor value write not supported for this sensor ipmi_completion_code <= 8'h80; end if (ipmi_sensor_edb_write_requested) begin // Event Data Byte write not supported for this sensor ipmi_completion_code <= 8'h81; end end IPMI_SENSOR_CPU1_OCC_ACTIVE: begin // NOTE: For future implementation if required if (ipmi_sensor_write_requested) begin // Sensor value write not supported for this sensor ipmi_completion_code <= 8'h80; end if (ipmi_sensor_edb_write_requested) begin // Event Data Byte write not supported for this sensor ipmi_completion_code <= 8'h81; end end IPMI_SENSOR_CPU0_FUNC: begin // NOTE: For future implementation if required if (ipmi_sensor_write_requested) begin // Sensor value write not supported for this sensor ipmi_completion_code <= 8'h80; end if (ipmi_sensor_edb_write_requested) begin // Event Data Byte write not supported for this sensor ipmi_completion_code <= 8'h81; end end IPMI_SENSOR_CPU1_FUNC: begin // NOTE: For future implementation if required if (ipmi_sensor_write_requested) begin // Sensor value write not supported for this sensor ipmi_completion_code <= 8'h80; end if (ipmi_sensor_edb_write_requested) begin // Event Data Byte write not supported for this sensor ipmi_completion_code <= 8'h81; end end IPMI_SENSOR_BOOT_COUNT: begin if (ipmi_sensor_write_requested) begin openpower_boot_count_sensor <= ipmi_sensor_value; end if (ipmi_sensor_edb_write_requested) begin // Event Data Byte write not supported for this sensor ipmi_completion_code <= 8'h81; end end IPMI_SENSOR_PLANAR_FAULT: begin // NOTE: For future implementation if required if (ipmi_sensor_write_requested) begin // Sensor value write not supported for this sensor ipmi_completion_code <= 8'h80; end if (ipmi_sensor_edb_write_requested) begin // Event Data Byte write not supported for this sensor ipmi_completion_code <= 8'h81; end end IPMI_SENSOR_REF_CLK_FAULT: begin // NOTE: For future implementation if required if (ipmi_sensor_write_requested) begin // Sensor value write not supported for this sensor ipmi_completion_code <= 8'h80; end if (ipmi_sensor_edb_write_requested) begin // Event Data Byte write not supported for this sensor ipmi_completion_code <= 8'h81; end end IPMI_SENSOR_PCIE_CLK_FAULT: begin // NOTE: For future implementation if required if (ipmi_sensor_write_requested) begin // Sensor value write not supported for this sensor ipmi_completion_code <= 8'h80; end if (ipmi_sensor_edb_write_requested) begin // Event Data Byte write not supported for this sensor ipmi_completion_code <= 8'h81; end end IPMI_SENSOR_TOD_CLK_FAULT: begin // NOTE: For future implementation if required if (ipmi_sensor_write_requested) begin // Sensor value write not supported for this sensor ipmi_completion_code <= 8'h80; end if (ipmi_sensor_edb_write_requested) begin // Event Data Byte write not supported for this sensor ipmi_completion_code <= 8'h81; end end IPMI_SENSOR_APSS_FAULT: begin // NOTE: For future implementation if required if (ipmi_sensor_write_requested) begin // Sensor value write not supported for this sensor ipmi_completion_code <= 8'h80; end if (ipmi_sensor_edb_write_requested) begin // Event Data Byte write not supported for this sensor ipmi_completion_code <= 8'h81; end end default: begin if ((ipmi_sensor_number >= IPMI_SENSOR_INV_DIMM_FUNC_BEG) && (ipmi_sensor_number <= IPMI_SENSOR_INV_DIMM_FUNC_END)) begin if (ipmi_event_assertion_req_value[IPMI_OP_EVT_SHIFT_DIMM_DSBL]) begin // Non-functional openpower_dimm_functional_bitfield <= openpower_dimm_functional_bitfield & ~(1 << (ipmi_sensor_number - IPMI_SENSOR_INV_DIMM_FUNC_BEG)); end else begin // Functional openpower_dimm_functional_bitfield <= openpower_dimm_functional_bitfield | (1 << (ipmi_sensor_number - IPMI_SENSOR_INV_DIMM_FUNC_BEG)); end if (ipmi_sensor_write_requested) begin // Sensor value write not supported for this sensor ipmi_completion_code <= 8'h80; end end else if ((ipmi_sensor_number >= IPMI_SENSOR_INV_CPU0_FUNC_BEG) && (ipmi_sensor_number <= IPMI_SENSOR_INV_CPU0_FUNC_END)) begin if (ipmi_event_assertion_req_value[IPMI_OP_EVT_SHIFT_PROC_DSBL]) begin // Non-functional openpower_cpu0_functional_bitfield <= openpower_cpu0_functional_bitfield & ~(1 << (ipmi_sensor_number - IPMI_SENSOR_INV_CPU0_FUNC_BEG)); end else begin // Functional openpower_cpu0_functional_bitfield <= openpower_cpu0_functional_bitfield | (1 << (ipmi_sensor_number - IPMI_SENSOR_INV_CPU0_FUNC_BEG)); end if (ipmi_sensor_write_requested) begin // Sensor value write not supported for this sensor ipmi_completion_code <= 8'h80; end end else if ((ipmi_sensor_number >= IPMI_SENSOR_INV_CPU1_FUNC_BEG) && (ipmi_sensor_number <= IPMI_SENSOR_INV_CPU1_FUNC_END)) begin if (ipmi_event_assertion_req_value[IPMI_OP_EVT_SHIFT_PROC_DSBL]) begin // Non-functional openpower_cpu1_functional_bitfield <= openpower_cpu1_functional_bitfield & ~(1 << (ipmi_sensor_number - IPMI_SENSOR_INV_CPU1_FUNC_BEG)); end else begin // Functional openpower_cpu1_functional_bitfield <= openpower_cpu1_functional_bitfield | (1 << (ipmi_sensor_number - IPMI_SENSOR_INV_CPU1_FUNC_BEG)); end if (ipmi_sensor_write_requested) begin // Sensor value write not supported for this sensor ipmi_completion_code <= 8'h80; end end else begin output_xfer_write_data <= 8'h00; // Signal error via standard IPMI error mechanism ipmi_resp_length <= BASE_IPMI_RESPONSE_LENGTH; ipmi_completion_code <= IPMI_CC_SNS_NOT_PRSNT; end end endcase ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RL01; end default: begin // Signal error via standard IPMI error mechanism ipmi_resp_length <= BASE_IPMI_RESPONSE_LENGTH; ipmi_completion_code <= IPMI_CC_INVALID_COMMAND; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RL01; end endcase end INTERFACE_TRANSFER_STATE_HM01: begin // Wait for RAM to respond with read data ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM02; end INTERFACE_TRANSFER_STATE_HM02: begin hiomap_cmd <= input_xfer_read_data; input_xfer_read_addr <= input_xfer_read_addr + 1; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM03; end INTERFACE_TRANSFER_STATE_HM03: begin // Wait for RAM to respond with read data ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM04; end INTERFACE_TRANSFER_STATE_HM04: begin hiomap_seq <= input_xfer_read_data; ipmi_req_data_byte <= 0; input_xfer_read_addr <= input_xfer_read_addr + 1; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM05; end INTERFACE_TRANSFER_STATE_HM05: begin // Wait for RAM to respond with read data ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM06; end INTERFACE_TRANSFER_STATE_HM06: begin // Decode parameters as required case (hiomap_cmd) HIOMAP_CMD_GET_INFO: begin if (input_xfer_read_data > 3) begin // We only support up to the HIOMAP v3 protocol hiomap_protocol_version <= 3; end else begin hiomap_protocol_version <= input_xfer_read_data; end ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM08; end HIOMAP_CMD_CREATE_RD_WIN, HIOMAP_CMD_CREATE_WR_WIN: begin case (hiomap_protocol_version) // All three known versions use the same parameter ordering, starting with the offset parameter // that requires block to address translation. We can easily handle this by changing the exit // test for each version instead of duplicating the translation logic three times. // Additionally, both the read and write commands use the same parameter ordering, down to the // same differences between HIOMAP versions. Instead of duplicating three times, also use the // same logic to decode the write commands and only switch queued window type based on the exact // command provided. 1, 2, 3: begin case (ipmi_req_data_byte) 0: begin hiomap_window_start_address[(FLASH_BLOCK_SIZE_SHIFT+7):(FLASH_BLOCK_SIZE_SHIFT)] <= input_xfer_read_data; if ((LPC_ADDRESS_BITS - 1) >= (FLASH_BLOCK_SIZE_SHIFT + 16)) begin hiomap_window_start_address[(LPC_ADDRESS_BITS-1):(FLASH_BLOCK_SIZE_SHIFT+16)] = 0; end end 1: begin if ((FLASH_BLOCK_SIZE_SHIFT + 8) < (LPC_ADDRESS_BITS - 1)) begin if ((FLASH_BLOCK_SIZE_SHIFT + 15) < (LPC_ADDRESS_BITS - 1)) begin hiomap_window_start_address[(FLASH_BLOCK_SIZE_SHIFT+15):(FLASH_BLOCK_SIZE_SHIFT+8)] <= input_xfer_read_data; end else begin hiomap_window_start_address[(LPC_ADDRESS_BITS-1):(FLASH_BLOCK_SIZE_SHIFT+8)] <= input_xfer_read_data; end end end 2: begin hiomap_window_length_bytes[(FLASH_BLOCK_SIZE_SHIFT+7):(FLASH_BLOCK_SIZE_SHIFT)] <= input_xfer_read_data; if ((LPC_ADDRESS_BITS - 1) >= (FLASH_BLOCK_SIZE_SHIFT + 16)) begin hiomap_window_length_bytes[(LPC_ADDRESS_BITS-1):(FLASH_BLOCK_SIZE_SHIFT+16)] = 0; end end 3: begin if ((FLASH_BLOCK_SIZE_SHIFT + 8) < (LPC_ADDRESS_BITS - 1)) begin if ((FLASH_BLOCK_SIZE_SHIFT + 15) < (LPC_ADDRESS_BITS - 1)) begin hiomap_window_length_bytes[(FLASH_BLOCK_SIZE_SHIFT+15):(FLASH_BLOCK_SIZE_SHIFT+8)] <= input_xfer_read_data; end else begin hiomap_window_length_bytes[(LPC_ADDRESS_BITS-1):(FLASH_BLOCK_SIZE_SHIFT+8)] <= input_xfer_read_data; end end end 4: begin hiomap_active_device_id <= input_xfer_read_data; end endcase case (hiomap_protocol_version) 1: begin if (ipmi_req_data_byte < 1) begin ipmi_req_data_byte <= ipmi_req_data_byte + 1; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM07; end else begin ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM08; end end 2: begin if (ipmi_req_data_byte < 3) begin ipmi_req_data_byte <= ipmi_req_data_byte + 1; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM07; end else begin ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM08; end end 3: begin if (ipmi_req_data_byte < 4) begin ipmi_req_data_byte <= ipmi_req_data_byte + 1; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM07; end else begin ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM08; end end endcase case (hiomap_cmd) HIOMAP_CMD_CREATE_RD_WIN: hiomap_window_type <= HIOMAP_WINDOW_TYPE_READ; HIOMAP_CMD_CREATE_WR_WIN: hiomap_window_type <= HIOMAP_WINDOW_TYPE_WRITE; endcase end endcase end HIOMAP_CMD_ERASE: begin case (hiomap_protocol_version) // Both known protocol versions use the same parameter type, size and ordering for this command 2, 3: begin case (ipmi_req_data_byte) 0: begin hiomap_erase_offset_bytes[(FLASH_BLOCK_SIZE_SHIFT+7):(FLASH_BLOCK_SIZE_SHIFT)] <= input_xfer_read_data; if ((LPC_ADDRESS_BITS - 1) >= (FLASH_BLOCK_SIZE_SHIFT + 16)) begin hiomap_erase_offset_bytes[(LPC_ADDRESS_BITS-1):(FLASH_BLOCK_SIZE_SHIFT+16)] = 0; end end 1: begin if ((FLASH_BLOCK_SIZE_SHIFT + 8) < (LPC_ADDRESS_BITS - 1)) begin if ((FLASH_BLOCK_SIZE_SHIFT + 15) < (LPC_ADDRESS_BITS - 1)) begin hiomap_erase_offset_bytes[(FLASH_BLOCK_SIZE_SHIFT+15):(FLASH_BLOCK_SIZE_SHIFT+8)] <= input_xfer_read_data; end else begin hiomap_erase_offset_bytes[(LPC_ADDRESS_BITS-1):(FLASH_BLOCK_SIZE_SHIFT+8)] <= input_xfer_read_data; end end end 2: begin hiomap_erase_length_bytes[(FLASH_BLOCK_SIZE_SHIFT+7):(FLASH_BLOCK_SIZE_SHIFT)] <= input_xfer_read_data; if ((LPC_ADDRESS_BITS - 1) >= (FLASH_BLOCK_SIZE_SHIFT + 16)) begin hiomap_erase_length_bytes[(LPC_ADDRESS_BITS-1):(FLASH_BLOCK_SIZE_SHIFT+16)] = 0; end end 3: begin if ((FLASH_BLOCK_SIZE_SHIFT + 8) < (LPC_ADDRESS_BITS - 1)) begin if ((FLASH_BLOCK_SIZE_SHIFT + 15) < (LPC_ADDRESS_BITS - 1)) begin hiomap_erase_length_bytes[(FLASH_BLOCK_SIZE_SHIFT+15):(FLASH_BLOCK_SIZE_SHIFT+8)] <= input_xfer_read_data; end else begin hiomap_erase_length_bytes[(LPC_ADDRESS_BITS-1):(FLASH_BLOCK_SIZE_SHIFT+8)] <= input_xfer_read_data; end end end endcase case (hiomap_protocol_version) 2, 3: begin if (ipmi_req_data_byte < 3) begin ipmi_req_data_byte <= ipmi_req_data_byte + 1; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM07; end else begin ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM08; end end endcase case (hiomap_cmd) HIOMAP_CMD_CREATE_RD_WIN: hiomap_window_type <= HIOMAP_WINDOW_TYPE_READ; HIOMAP_CMD_CREATE_WR_WIN: hiomap_window_type <= HIOMAP_WINDOW_TYPE_WRITE; endcase end endcase end default: begin ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM08; end endcase input_xfer_read_addr <= input_xfer_read_addr + 1; ipmi_resp_data_byte <= 0; output_xfer_write_addr <= BASE_HIOMAP_RESPONSE_LENGTH; end INTERFACE_TRANSFER_STATE_HM07: begin // Wait for RAM to respond with read data ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM06; end INTERFACE_TRANSFER_STATE_HM08: begin // Sanitize parameters case (hiomap_cmd) HIOMAP_CMD_CREATE_RD_WIN, HIOMAP_CMD_CREATE_WR_WIN: begin case (hiomap_protocol_version) 1: begin if (hiomap_cmd == HIOMAP_CMD_CREATE_RD_WIN) begin // Size unspecified, use one block as the size hiomap_window_length_bytes <= 1 << FLASH_BLOCK_SIZE_SHIFT; end if (hiomap_cmd == HIOMAP_CMD_CREATE_WR_WIN) begin // Size unspecified, use one block or the maximum write // cache size as the returned size, whichever is smaller... if (FLASH_MAX_WR_WINDOW_BYTES < (1 << FLASH_BLOCK_SIZE_SHIFT)) begin hiomap_window_length_bytes <= FLASH_MAX_WR_WINDOW_BYTES; end else begin hiomap_window_length_bytes <= 1 << FLASH_BLOCK_SIZE_SHIFT; end end end 2: begin if (hiomap_cmd == HIOMAP_CMD_CREATE_RD_WIN) begin // Zero sized window indicates undefined size, but must be at least one block // Just use one block as the size in this corner case... if (hiomap_window_length_bytes == 0) begin hiomap_window_length_bytes <= 1 << FLASH_BLOCK_SIZE_SHIFT; end end if (hiomap_cmd == HIOMAP_CMD_CREATE_WR_WIN) begin // Zero sized window indicates undefined size, but must be at least one block // Just use one block as the size in this corner case... if (hiomap_window_length_bytes == 0) begin hiomap_window_length_bytes <= 1 << FLASH_BLOCK_SIZE_SHIFT; end else begin // The host can only request a window size, not demand one // If the request is larger than our write cache size, limit // the returned window to the write cache size... if (hiomap_window_length_bytes > FLASH_MAX_WR_WINDOW_BYTES) begin hiomap_window_length_bytes <= FLASH_MAX_WR_WINDOW_BYTES; end end end end 3: begin if (hiomap_cmd == HIOMAP_CMD_CREATE_RD_WIN) begin // Zero sized window indicates undefined size, but must be at least one block // Just use one block as the size in this corner case... if (hiomap_window_length_bytes == 0) begin hiomap_window_length_bytes <= 1 << FLASH_BLOCK_SIZE_SHIFT; end end if (hiomap_cmd == HIOMAP_CMD_CREATE_WR_WIN) begin // Zero sized window indicates undefined size, but must be at least one block // Just use one block as the size in this corner case... if (hiomap_window_length_bytes == 0) begin hiomap_window_length_bytes <= 1 << FLASH_BLOCK_SIZE_SHIFT; end else begin // The host can only request a window size, not demand one // If the request is larger than our write cache size, limit // the returned window to the write cache size... if (hiomap_window_length_bytes > FLASH_MAX_WR_WINDOW_BYTES) begin hiomap_window_length_bytes <= FLASH_MAX_WR_WINDOW_BYTES; end end end end endcase end endcase ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM09; end INTERFACE_TRANSFER_STATE_HM09: begin case (hiomap_cmd) HIOMAP_CMD_RESET: begin hiomap_window_start_address <= 0; hiomap_window_length_bytes <= FLASH_SIZE_BYTES; hiomap_window_type <= HIOMAP_WINDOW_TYPE_READ; ipmi_resp_length <= BASE_HIOMAP_RESPONSE_LENGTH; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM10; end HIOMAP_CMD_GET_INFO: begin case (hiomap_protocol_version) 1: begin case (ipmi_resp_data_byte) 0: output_xfer_write_data <= hiomap_protocol_version; // FIXME // This assumes the read/write window is the entire Flash device! 1: output_xfer_write_data <= FLASH_SIZE_BLOCKS[7:0]; 2: output_xfer_write_data <= FLASH_SIZE_BLOCKS[15:8]; 3: output_xfer_write_data <= FLASH_SIZE_BLOCKS[7:0]; 4: output_xfer_write_data <= FLASH_SIZE_BLOCKS[15:8]; endcase if (ipmi_resp_data_byte < 5) begin output_xfer_write_addr <= output_xfer_write_addr + 1; output_xfer_write_wren <= 1'b1; ipmi_resp_data_byte <= ipmi_resp_data_byte + 1; end else begin output_xfer_write_wren <= 1'b0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM10; end ipmi_resp_length <= BASE_HIOMAP_RESPONSE_LENGTH + 5; end 2: begin case (ipmi_resp_data_byte) 0: output_xfer_write_data <= hiomap_protocol_version; 1: output_xfer_write_data <= FLASH_BLOCK_SIZE_SHIFT; 2: output_xfer_write_data <= HIOMAP_SUGGESTED_TIMEOUT_S[7:0]; 3: output_xfer_write_data <= HIOMAP_SUGGESTED_TIMEOUT_S[15:8]; endcase if (ipmi_resp_data_byte < 4) begin output_xfer_write_addr <= output_xfer_write_addr + 1; output_xfer_write_wren <= 1'b1; ipmi_resp_data_byte <= ipmi_resp_data_byte + 1; end else begin output_xfer_write_wren <= 1'b0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM10; end ipmi_resp_length <= BASE_HIOMAP_RESPONSE_LENGTH + 4; end 3: begin case (ipmi_resp_data_byte) 0: output_xfer_write_data <= hiomap_protocol_version; 1: output_xfer_write_data <= FLASH_BLOCK_SIZE_SHIFT; 2: output_xfer_write_data <= HIOMAP_SUGGESTED_TIMEOUT_S[7:0]; 3: output_xfer_write_data <= HIOMAP_SUGGESTED_TIMEOUT_S[15:8]; 4: output_xfer_write_data <= HIOMAP_PNOR_DEVICE_COUNT; endcase if (ipmi_resp_data_byte < 5) begin output_xfer_write_addr <= output_xfer_write_addr + 1; output_xfer_write_wren <= 1'b1; ipmi_resp_data_byte <= ipmi_resp_data_byte + 1; end else begin output_xfer_write_wren <= 1'b0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM10; end ipmi_resp_length <= BASE_HIOMAP_RESPONSE_LENGTH + 5; end default: begin // Signal error via standard IPMI error mechanism ipmi_resp_length <= BASE_IPMI_RESPONSE_LENGTH; ipmi_completion_code <= IPMI_CC_INVALID_COMMAND; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM10; end endcase end HIOMAP_CMD_GET_FLASH_INFO: begin case (hiomap_protocol_version) 1: begin case (ipmi_resp_data_byte) 0: output_xfer_write_data <= FLASH_SIZE_BYTES[7:0]; 1: output_xfer_write_data <= FLASH_SIZE_BYTES[15:8]; 2: output_xfer_write_data <= FLASH_SIZE_BYTES[23:16]; 3: output_xfer_write_data <= FLASH_SIZE_BYTES[31:24]; 4: output_xfer_write_data <= FLASH_ERASE_GRAN_BYTES[7:0]; 5: output_xfer_write_data <= FLASH_ERASE_GRAN_BYTES[15:8]; 6: output_xfer_write_data <= FLASH_ERASE_GRAN_BYTES[23:16]; 7: output_xfer_write_data <= FLASH_ERASE_GRAN_BYTES[31:24]; endcase if (ipmi_resp_data_byte < 8) begin output_xfer_write_addr <= output_xfer_write_addr + 1; output_xfer_write_wren <= 1'b1; ipmi_resp_data_byte <= ipmi_resp_data_byte + 1; end else begin output_xfer_write_wren <= 1'b0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM10; end ipmi_resp_length <= BASE_HIOMAP_RESPONSE_LENGTH + 8; end 2, 3: begin case (ipmi_resp_data_byte) 0: output_xfer_write_data <= FLASH_SIZE_BLOCKS[7:0]; 1: output_xfer_write_data <= FLASH_SIZE_BLOCKS[15:8]; 2: output_xfer_write_data <= FLASH_ERASE_GRAN_BLOCKS[7:0]; 3: output_xfer_write_data <= FLASH_ERASE_GRAN_BLOCKS[15:8]; endcase if (ipmi_resp_data_byte < 4) begin output_xfer_write_addr <= output_xfer_write_addr + 1; output_xfer_write_wren <= 1'b1; ipmi_resp_data_byte <= ipmi_resp_data_byte + 1; end else begin output_xfer_write_wren <= 1'b0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM10; end ipmi_resp_length <= BASE_HIOMAP_RESPONSE_LENGTH + 4; end default: begin // Signal error via standard IPMI error mechanism ipmi_resp_length <= BASE_IPMI_RESPONSE_LENGTH; ipmi_completion_code <= IPMI_CC_INVALID_COMMAND; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM10; end endcase end HIOMAP_CMD_CREATE_RD_WIN: begin // Use 1:1 mapping between LPC offset and Flash offset for this simple bridge case (hiomap_protocol_version) 1: begin case (ipmi_resp_data_byte) 0: output_xfer_write_data <= (hiomap_window_start_address >> FLASH_BLOCK_SIZE_SHIFT) & 8'hff; 1: output_xfer_write_data <= (hiomap_window_start_address >> (FLASH_BLOCK_SIZE_SHIFT + 8)) & 8'hff; endcase if (ipmi_resp_data_byte < 2) begin output_xfer_write_addr <= output_xfer_write_addr + 1; output_xfer_write_wren <= 1'b1; ipmi_resp_data_byte <= ipmi_resp_data_byte + 1; end else begin output_xfer_write_wren <= 1'b0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM10; end ipmi_resp_length <= BASE_HIOMAP_RESPONSE_LENGTH + 2; end 2, 3: begin case (ipmi_resp_data_byte) 0: output_xfer_write_data <= (hiomap_window_start_address >> FLASH_BLOCK_SIZE_SHIFT) & 8'hff; 1: output_xfer_write_data <= (hiomap_window_start_address >> (FLASH_BLOCK_SIZE_SHIFT + 8)) & 8'hff; 2: output_xfer_write_data <= (hiomap_window_length_bytes >> FLASH_BLOCK_SIZE_SHIFT) & 8'hff; 3: output_xfer_write_data <= (hiomap_window_length_bytes >> (FLASH_BLOCK_SIZE_SHIFT + 8)) & 8'hff; 4: output_xfer_write_data <= (hiomap_window_start_address >> FLASH_BLOCK_SIZE_SHIFT) & 8'hff; 5: output_xfer_write_data <= (hiomap_window_start_address >> (FLASH_BLOCK_SIZE_SHIFT + 8)) & 8'hff; endcase if (ipmi_resp_data_byte < 6) begin output_xfer_write_addr <= output_xfer_write_addr + 1; output_xfer_write_wren <= 1'b1; ipmi_resp_data_byte <= ipmi_resp_data_byte + 1; end else begin output_xfer_write_wren <= 1'b0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM10; end ipmi_resp_length <= BASE_HIOMAP_RESPONSE_LENGTH + 6; end endcase end HIOMAP_CMD_CLOSE_WINDOW: begin hiomap_window_type <= HIOMAP_WINDOW_INACTIVE; ipmi_resp_length <= BASE_HIOMAP_RESPONSE_LENGTH; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM10; end HIOMAP_CMD_CREATE_WR_WIN: begin // Use 1:1 mapping between LPC offset and Flash offset for this simple bridge case (hiomap_protocol_version) 1: begin case (ipmi_resp_data_byte) 0: output_xfer_write_data <= (hiomap_window_start_address >> FLASH_BLOCK_SIZE_SHIFT) & 8'hff; 1: output_xfer_write_data <= (hiomap_window_start_address >> (FLASH_BLOCK_SIZE_SHIFT + 8)) & 8'hff; endcase if (ipmi_resp_data_byte < 2) begin output_xfer_write_addr <= output_xfer_write_addr + 1; output_xfer_write_wren <= 1'b1; ipmi_resp_data_byte <= ipmi_resp_data_byte + 1; end else begin output_xfer_write_wren <= 1'b0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM10; end ipmi_resp_length <= BASE_HIOMAP_RESPONSE_LENGTH + 2; end 2, 3: begin case (ipmi_resp_data_byte) 0: output_xfer_write_data <= (hiomap_window_start_address >> FLASH_BLOCK_SIZE_SHIFT) & 8'hff; 1: output_xfer_write_data <= (hiomap_window_start_address >> (FLASH_BLOCK_SIZE_SHIFT + 8)) & 8'hff; 2: output_xfer_write_data <= (hiomap_window_length_bytes >> FLASH_BLOCK_SIZE_SHIFT) & 8'hff; 3: output_xfer_write_data <= (hiomap_window_length_bytes >> (FLASH_BLOCK_SIZE_SHIFT + 8)) & 8'hff; 4: output_xfer_write_data <= (hiomap_window_start_address >> FLASH_BLOCK_SIZE_SHIFT) & 8'hff; 5: output_xfer_write_data <= (hiomap_window_start_address >> (FLASH_BLOCK_SIZE_SHIFT + 8)) & 8'hff; endcase if (ipmi_resp_data_byte < 6) begin output_xfer_write_addr <= output_xfer_write_addr + 1; output_xfer_write_wren <= 1'b1; ipmi_resp_data_byte <= ipmi_resp_data_byte + 1; end else begin output_xfer_write_wren <= 1'b0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM10; end ipmi_resp_length <= BASE_HIOMAP_RESPONSE_LENGTH + 6; end endcase end HIOMAP_CMD_MARK_DIRTY: begin // The exact region to mark dirty is passed // in several parameters. // For now, since the iCE40 can't handle more // than a couple of subsectors at a time, just // ignore and claim sucess. The FLUSH routine // will erase and write the entire cache to // Flash when invoked. // // WARNING: HOSTBOOT WORKAROUND FOLLOWS // In src/usr/pnor/pnor_ipmidd.C, PnorIpmiDD::_writeFlash(), // Hostboot runs a small loop to write each block in an oversize // (i.e. greater than the current write window) buffer to backing // storage (Flash). Unfortunately this loop only calls the mark // dirty command before adjusting the window, and as a result // all writes to sectors other than the last sector would be lost // if the HIOMAP specification were followed here. // // Instead of the specified behavior where FLUSH is the only // command to initiate writes, we also add an implicit FLUSH // to the MARK_DIRTY command as a workaround. ipmi_resp_length <= BASE_HIOMAP_RESPONSE_LENGTH; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM10; end HIOMAP_CMD_FLUSH: begin // The exact region to flush is passed in // several parameters. // For now, since the iCE40 can't handle more // than a couple of subsectors at a time, just // erase and write the entire cache to Flash // when invoked. ipmi_resp_length <= BASE_HIOMAP_RESPONSE_LENGTH; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM10; end HIOMAP_CMD_ACK: begin // Mask is in input_xfer_read_data // For now just ignore and claim sucess ipmi_resp_length <= BASE_HIOMAP_RESPONSE_LENGTH; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM10; end HIOMAP_CMD_ERASE: begin case (hiomap_protocol_version) 2, 3: begin ipmi_resp_length <= BASE_HIOMAP_RESPONSE_LENGTH; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM10; end default: begin // Signal error via standard IPMI error mechanism ipmi_resp_length <= BASE_IPMI_RESPONSE_LENGTH; ipmi_completion_code <= IPMI_CC_INVALID_COMMAND; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM10; end endcase end HIOMAP_CMD_GET_FLASH_NAME: begin case (hiomap_protocol_version) 3: begin case (ipmi_resp_data_byte) 0: output_xfer_write_data <= 8'h04; // 4 bytes 1: output_xfer_write_data <= 8'h50; // 'P' 2: output_xfer_write_data <= 8'h4e; // 'N' 3: output_xfer_write_data <= 8'h4f; // 'O' 4: output_xfer_write_data <= 8'h52; // 'R' default: output_xfer_write_data <= 0; endcase if (ipmi_resp_data_byte < 11) begin output_xfer_write_addr <= output_xfer_write_addr + 1; output_xfer_write_wren <= 1'b1; ipmi_resp_data_byte <= ipmi_resp_data_byte + 1; end else begin output_xfer_write_wren <= 1'b0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM10; end ipmi_resp_length <= BASE_HIOMAP_RESPONSE_LENGTH + 11; end default: begin // Signal error via standard IPMI error mechanism ipmi_resp_length <= BASE_IPMI_RESPONSE_LENGTH; ipmi_completion_code <= IPMI_CC_INVALID_COMMAND; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM10; end endcase end HIOMAP_CMD_LOCK: begin case (hiomap_protocol_version) 3: begin // NOTE: Since we can only process one sector at a time for write, // the logic for LOCK is greatly simplified. For this implementation, // LOCK always fails on a write window, and always succeeds on a read // window. If larger caches are added, this needs to be revisited. if (hiomap_window_type == HIOMAP_WINDOW_TYPE_WRITE) begin // Signal error via standard IPMI error mechanism ipmi_resp_length <= BASE_IPMI_RESPONSE_LENGTH; ipmi_completion_code <= IPMI_CC_INVALID_COMMAND; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM10; end else begin // No response parameters are specified for this command ipmi_resp_length <= BASE_HIOMAP_RESPONSE_LENGTH; end end default: begin // Signal error via standard IPMI error mechanism ipmi_resp_length <= BASE_IPMI_RESPONSE_LENGTH; ipmi_completion_code <= IPMI_CC_INVALID_COMMAND; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM10; end endcase end default: begin // Signal error via standard IPMI error mechanism ipmi_resp_length <= BASE_IPMI_RESPONSE_LENGTH; ipmi_completion_code <= IPMI_CC_INVALID_COMMAND; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM10; end endcase end INTERFACE_TRANSFER_STATE_HM10: begin case (hiomap_cmd) HIOMAP_CMD_CREATE_RD_WIN, HIOMAP_CMD_CREATE_WR_WIN: begin // Set up external HIOMAP cache request hiomap_active_window_start_address <= hiomap_window_start_address; hiomap_active_window_size_bytes <= hiomap_window_length_bytes; if (hiomap_window_type == HIOMAP_WINDOW_TYPE_WRITE) begin hiomap_window_type_write_reg <= 1; end else begin hiomap_window_type_write_reg <= 0; end end HIOMAP_CMD_MARK_DIRTY: begin // WARNING: See workaround text above for HIOMAP_CMD_MARK_DIRTY // Set up implicit flush hiomap_flush_sector_count_reg <= hiomap_active_window_size_bytes >> FLASH_BLOCK_SIZE_SHIFT; hiomap_flush_type_erase_reg <= 0; end HIOMAP_CMD_FLUSH: begin // Set up external HIOMAP flush request hiomap_flush_sector_count_reg <= hiomap_active_window_size_bytes >> FLASH_BLOCK_SIZE_SHIFT; hiomap_flush_type_erase_reg <= 0; end HIOMAP_CMD_ERASE: begin case (hiomap_protocol_version) 2, 3: begin // Set up external HIOMAP erase request hiomap_erase_address_offset_reg <= hiomap_erase_offset_bytes; hiomap_erase_sector_count_reg <= hiomap_erase_length_bytes >> FLASH_BLOCK_SIZE_SHIFT; hiomap_flush_type_erase_reg <= 1; end endcase end endcase // Load HIOMAP portion of response header into buffer, phase 1 output_xfer_write_addr <= BASE_IPMI_RESPONSE_LENGTH + 1; output_xfer_write_data <= hiomap_cmd; output_xfer_write_wren <= 1'b1; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_HM11; end INTERFACE_TRANSFER_STATE_HM11: begin case (hiomap_cmd) HIOMAP_CMD_CREATE_RD_WIN, HIOMAP_CMD_CREATE_WR_WIN: begin // Fire external HIOMAP cache request hiomap_new_window_req_reg <= 1; end HIOMAP_CMD_MARK_DIRTY: begin // WARNING: See workaround text above for HIOMAP_CMD_MARK_DIRTY // Fire implicit flush hiomap_flush_req_reg <= 1; end HIOMAP_CMD_FLUSH: begin // Fire external HIOMAP flush request hiomap_flush_req_reg <= 1; end HIOMAP_CMD_ERASE: begin case (hiomap_protocol_version) 2, 3: begin // Fire external HIOMAP erase request hiomap_flush_req_reg <= 1; end endcase end endcase // Load HIOMAP portion of response header into buffer, phase 2 output_xfer_write_addr <= output_xfer_write_addr + 1; output_xfer_write_data <= hiomap_seq; output_xfer_write_wren <= 1'b1; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RL01; end INTERFACE_TRANSFER_STATE_DM01: begin // Wait for RAM to respond with read data ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_DM02; end INTERFACE_TRANSFER_STATE_DM02: begin ipmi_group_extension_id <= input_xfer_read_data; ipmi_req_data_byte <= 0; input_xfer_read_addr <= input_xfer_read_addr + 1; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_DM03; end INTERFACE_TRANSFER_STATE_DM03: begin // Wait for RAM to respond with read data ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_DM04; end INTERFACE_TRANSFER_STATE_DM04: begin // Decode parameters as required case (ipmi_command) DCMI_CMD_GET_CAPABILITIES: begin dcmi_parameter_selector <= input_xfer_read_data; case (input_xfer_read_data) 1: dcmi_response_length_add <= 7; 2: dcmi_response_length_add <= 9; 3: dcmi_response_length_add <= 6; 4: dcmi_response_length_add <= 7; 5: dcmi_response_length_add <= 5; default: dcmi_response_length_add <= 9; // Invalid parameter page, use maximum of values above endcase ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_DM06; end default: begin ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_DM06; end endcase input_xfer_read_addr <= input_xfer_read_addr + 1; ipmi_resp_data_byte <= 0; output_xfer_write_addr <= BASE_DCMI_RESPONSE_LENGTH; end INTERFACE_TRANSFER_STATE_DM05: begin // Wait for RAM to respond with read data ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_DM04; end INTERFACE_TRANSFER_STATE_DM06: begin // Sanitize parameters // NOTE: For future implementation if required ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_DM07; end INTERFACE_TRANSFER_STATE_DM07: begin case (ipmi_command) DCMI_CMD_GET_CAPABILITIES: begin case (ipmi_resp_data_byte) 0: output_xfer_write_data <= 8'hdc; // Extension ID 1: output_xfer_write_data <= 8'h01; // Spec conformance -- major revision 2: output_xfer_write_data <= 8'h05; // Spec conformance -- minor revision 3: output_xfer_write_data <= 8'h02; // Parameter revision default: begin case (dcmi_parameter_selector) // Supported DCMI capabilities 1: begin case (ipmi_resp_data_byte) 4: output_xfer_write_data <= 8'h00; // Reserved 5: output_xfer_write_data <= 8'h01; // Power management capabilities available 6: output_xfer_write_data <= 8'h01; // In-band system interface capability available endcase end // Mandatory platform attributes 2: begin case (ipmi_resp_data_byte) 4: output_xfer_write_data <= 8'h00; // No SEL of any kind (this is out of compliance with the DCMI spec 5: output_xfer_write_data <= 8'h00; // but we simply don't have a SEL buffer to expose to the host!) 6: output_xfer_write_data <= 8'h00; // Reserved 7: output_xfer_write_data <= 8'h00; // Reserved 8: output_xfer_write_data <= 8'h01; // Sampling frequency for temperature monitoring in seconds endcase end // Optional platform attributes 3: begin case (ipmi_resp_data_byte) 4: output_xfer_write_data <= 8'h00; // Power management device IPMB slave address 5: output_xfer_write_data <= 8'h00; // Power management Controller Channel Number and device revision endcase end // Manageability access attributes 4: begin case (ipmi_resp_data_byte) 4: output_xfer_write_data <= 8'hff; // Primary LAN OOB support (not supported) 5: output_xfer_write_data <= 8'hff; // Secondary LAN OOB support (not supported) 6: output_xfer_write_data <= 8'hff; // Serial OOB TMODE capability (not supported) endcase end // Enhanced system power statistics attributes 5: begin case (ipmi_resp_data_byte) 4: output_xfer_write_data <= 8'h00; // Number of supported rolling average time periods endcase end default: begin // Host has requested an invalid parameter page // Write zeroes... output_xfer_write_data <= 8'h00; end endcase end endcase if (ipmi_resp_data_byte < dcmi_response_length_add) begin output_xfer_write_addr <= output_xfer_write_addr + 1; output_xfer_write_wren <= 1'b1; ipmi_resp_data_byte <= ipmi_resp_data_byte + 1; end else begin output_xfer_write_wren <= 1'b0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_DM08; end ipmi_resp_length <= BASE_DCMI_RESPONSE_LENGTH + dcmi_response_length_add; ipmi_completion_code <= DCMI_CC_NO_ERROR; end DCMI_CMD_GET_POWER_CAP: begin case (ipmi_resp_data_byte) 0: output_xfer_write_data <= 8'h00; // Reserved 1: output_xfer_write_data <= 8'h00; // Reserved 2: output_xfer_write_data <= 8'h00; // No action taken on power limit violation 3: output_xfer_write_data <= DCMI_POWER_LIMIT_W[7:0]; // Power limit in watts 4: output_xfer_write_data <= DCMI_POWER_LIMIT_W[15:8]; 5: output_xfer_write_data <= DCMI_CORR_LIMIT_TIME_MS[7:0]; // Correction time in milliseconds 6: output_xfer_write_data <= DCMI_CORR_LIMIT_TIME_MS[15:8]; 7: output_xfer_write_data <= DCMI_CORR_LIMIT_TIME_MS[23:16]; 8: output_xfer_write_data <= DCMI_CORR_LIMIT_TIME_MS[31:24]; 9: output_xfer_write_data <= 8'h00; // Reserved 10: output_xfer_write_data <= 8'h00; // Reserved 11: output_xfer_write_data <= DCMI_PWR_SAMPLE_PERIOD_S[7:0]; // Sampling period in seconds 12: output_xfer_write_data <= DCMI_PWR_SAMPLE_PERIOD_S[15:8]; endcase if (ipmi_resp_data_byte < 13) begin output_xfer_write_addr <= output_xfer_write_addr + 1; output_xfer_write_wren <= 1'b1; ipmi_resp_data_byte <= ipmi_resp_data_byte + 1; end else begin output_xfer_write_wren <= 1'b0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_DM08; end ipmi_resp_length <= BASE_DCMI_RESPONSE_LENGTH + 13; if (DCMI_ENFORCE_POWER_LIMIT) begin ipmi_completion_code <= 8'h00; // Power limit active end else begin ipmi_completion_code <= 8'h80; // No active set power limit end end default: begin // Signal error via standard IPMI error mechanism ipmi_resp_length <= BASE_IPMI_RESPONSE_LENGTH; ipmi_completion_code <= DCMI_CC_INVALID_COMMAND; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_DM08; end endcase end INTERFACE_TRANSFER_STATE_DM08: begin // Load DCMI portion of response header into buffer output_xfer_write_addr <= BASE_IPMI_RESPONSE_LENGTH + 1; output_xfer_write_data <= ipmi_group_extension_id; output_xfer_write_wren <= 1'b1; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RL01; end INTERFACE_TRANSFER_STATE_ST01: begin // Wait for RAM to respond with read data ipmi_req_data_byte <= 0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_ST02; end INTERFACE_TRANSFER_STATE_ST02: begin // Decode parameters as required case (ipmi_command) IPMI_CMD_SET_SEL_TIME: begin case (ipmi_req_data_byte) 0: rtc_clock_set[7:0] <= input_xfer_read_data; 1: rtc_clock_set[15:8] <= input_xfer_read_data; 2: rtc_clock_set[23:16] <= input_xfer_read_data; 3: rtc_clock_set[31:24] <= input_xfer_read_data; endcase if (ipmi_req_data_byte < 4) begin ipmi_req_data_byte <= ipmi_req_data_byte + 1; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_ST03; end else begin rtc_set_strobe <= 1; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_ST04; end end default: begin ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_ST04; end endcase input_xfer_read_addr <= input_xfer_read_addr + 1; ipmi_resp_data_byte <= 0; output_xfer_write_addr <= BASE_IPMI_RESPONSE_LENGTH; end INTERFACE_TRANSFER_STATE_ST03: begin // Wait for RAM to respond with read data ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_ST04; end INTERFACE_TRANSFER_STATE_ST04: begin // Sanitize parameters / handle strobes case (ipmi_command) IPMI_CMD_SET_SEL_TIME: begin rtc_set_strobe <= 0; end endcase ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_ST05; end INTERFACE_TRANSFER_STATE_ST05: begin case (ipmi_command) IPMI_CMD_GET_SEL_TIME: begin case (ipmi_resp_data_byte) 0: output_xfer_write_data <= rtc_current_time[7:0]; 1: output_xfer_write_data <= rtc_current_time[15:8]; 2: output_xfer_write_data <= rtc_current_time[23:16]; 3: output_xfer_write_data <= rtc_current_time[31:24]; endcase if (ipmi_resp_data_byte < 4) begin output_xfer_write_addr <= output_xfer_write_addr + 1; output_xfer_write_wren <= 1'b1; ipmi_resp_data_byte <= ipmi_resp_data_byte + 1; end else begin output_xfer_write_wren <= 1'b0; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RL01; end ipmi_resp_length <= BASE_IPMI_RESPONSE_LENGTH + 4; end default: begin // Signal error via standard IPMI error mechanism ipmi_resp_length <= BASE_IPMI_RESPONSE_LENGTH; ipmi_completion_code <= IPMI_CC_INVALID_COMMAND; ipmi_transfer_state <= INTERFACE_TRANSFER_STATE_RL01; end endcase end default: begin ipmi_transfer_state <= INTERFACE_INITIALIZE_STATE_01; end endcase // IRQ handler if (irq_ack) begin irq_req_reg <= 0; irq_ack_cont_reg <= 1; end else begin if (!irq_ack_cont_reg) begin if (!irq_ack_cont_reg && !bmc_to_host_ctl_attn_req_prev && bmc_to_host_ctl_attn_req) begin irq_req_reg <= 1; end end else begin irq_ack_cont_reg <= 0; end end if (!irq_ack_cont_reg) begin // Wait for prior IRQ line handshake to complete before sampling the B2H_ATN line // This ensures that the IRQ is still fired if the continue signal is asserted while // B2H_ATN transitions from inactive to active. bmc_to_host_ctl_attn_req_prev <= bmc_to_host_ctl_attn_req; end host_to_bmc_ctl_attn_req_prev <= host_to_bmc_ctl_attn_req; end h_busy_reg <= h_busy; end wire [7:0] input_xfer_bram_junk_data; SB_RAM40_4K #( .INIT_0(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_1(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_2(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_3(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_4(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_5(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_6(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_7(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_8(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_9(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_A(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_B(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_C(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_D(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_E(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_F(256'h0000000000000000000000000000000000000000000000000000000000000000), // 512 elements deep, 8 bits wide .READ_MODE(1), .WRITE_MODE(1) ) ipmi_bt_cycle_input_xfer_bram( .RDATA({input_xfer_bram_junk_data[7], input_xfer_read_data[7], input_xfer_bram_junk_data[6], input_xfer_read_data[6], input_xfer_bram_junk_data[5], input_xfer_read_data[5], input_xfer_bram_junk_data[4], input_xfer_read_data[4], input_xfer_bram_junk_data[3], input_xfer_read_data[3], input_xfer_bram_junk_data[2], input_xfer_read_data[2], input_xfer_bram_junk_data[1], input_xfer_read_data[1], input_xfer_bram_junk_data[0], input_xfer_read_data[0]}), .RADDR({2'b00, input_xfer_read_addr}), .WADDR({2'b00, input_xfer_write_addr}), .MASK(16'hxxxx), .WDATA({1'bx, input_xfer_write_data[7], 1'bx, input_xfer_write_data[6], 1'bx, input_xfer_write_data[5], 1'bx, input_xfer_write_data[4], 1'bx, input_xfer_write_data[3], 1'bx, input_xfer_write_data[2], 1'bx, input_xfer_write_data[1], 1'bx, input_xfer_write_data[0]}), .RCLKE(1'b1), .RCLK(logic_clk), .RE(1'b1), .WCLKE(input_xfer_write_wren), .WCLK(input_xfer_write_clk), .WE(1'b1) ); wire [7:0] output_xfer_bram_junk_data; SB_RAM40_4K #( .INIT_0(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_1(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_2(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_3(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_4(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_5(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_6(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_7(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_8(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_9(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_A(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_B(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_C(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_D(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_E(256'h0000000000000000000000000000000000000000000000000000000000000000), .INIT_F(256'h0000000000000000000000000000000000000000000000000000000000000000), // 512 elements deep, 8 bits wide .READ_MODE(1), .WRITE_MODE(1) ) ipmi_bt_cycle_output_xfer_bram( .RDATA({output_xfer_bram_junk_data[7], output_xfer_read_data[7], output_xfer_bram_junk_data[6], output_xfer_read_data[6], output_xfer_bram_junk_data[5], output_xfer_read_data[5], output_xfer_bram_junk_data[4], output_xfer_read_data[4], output_xfer_bram_junk_data[3], output_xfer_read_data[3], output_xfer_bram_junk_data[2], output_xfer_read_data[2], output_xfer_bram_junk_data[1], output_xfer_read_data[1], output_xfer_bram_junk_data[0], output_xfer_read_data[0]}), .RADDR({2'b00, output_xfer_read_addr}), .WADDR({2'b00, output_xfer_write_addr}), .MASK(16'hxxxx), .WDATA({1'bx, output_xfer_write_data[7], 1'bx, output_xfer_write_data[6], 1'bx, output_xfer_write_data[5], 1'bx, output_xfer_write_data[4], 1'bx, output_xfer_write_data[3], 1'bx, output_xfer_write_data[2], 1'bx, output_xfer_write_data[1], 1'bx, output_xfer_write_data[0]}), .RCLKE(1'b1), .RCLK(output_xfer_read_clk), .RE(1'b1), .WCLKE(output_xfer_write_wren), .WCLK(logic_clk), .WE(1'b1) ); endmodule