Commit 6b12e787 authored by Raptor Engineering Development Team's avatar Raptor Engineering Development Team
Browse files

Add initial integration of FSI core and FSI IPL firmware for Raptor Computing...

Add initial integration of FSI core and FSI IPL firmware for Raptor Computing Systems POWER9 systems

Verified to properly start the IPL sequence on a Raptor Computing Systems Blackbird
with external LPC / IPMI bridge interface attached.
parent eeec6ece
......@@ -3,7 +3,7 @@ BUILD_DIR=../build/versa_ecp5
include $(BUILD_DIR)/software/include/generated/variables.mak
include $(SOC_DIRECTORY)/software/common.mak
OBJECTS=isr.o main.o
OBJECTS=isr.o main.o fsi.o
all: firmware.bin
......
// © 2020 Raptor Engineering, LLC
//
// Released under the terms of the AGPL v3
// See the LICENSE file for full details
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <generated/csr.h>
#include "fsi.h"
#define DEBUG
// General FSI register definitions for IBM CFAM slaves
#define IBM_CFAM_FSI_SMODE 0x0800
#define IBM_CFAM_FSI_SISC 0x0802
#define IBM_CFAM_FSI_SSTAT 0x0805
// Boot-related CFAM register definitions for IBM POWER9 processors
#define IBM_POWER9_FSI_A_SI1S 0x081c
#define IBM_POWER9_LL_MODE_REG 0x0840
#define IBM_POWER9_FSI2PIB_CHIPID 0x100a
#define IBM_POWER9_FSI2PIB_INTERRUPT 0x100b
#define IBM_POWER9_FSI2PIB_TRUE_MASK 0x100d
#define IBM_POWER9_CBS_CS 0x2801
#define IBM_POWER9_SBE_CTRL_STATUS 0x2808
#define IBM_POWER9_SBE_MSG_REGISTER 0x2809
#define IBM_POWER9_ROOT_CTRL0 0x2810
#define IBM_POWER9_PERV_CTRL0 0x281a
#define IBM_POWER9_HB_MBX5_REG 0x283c
#define IBM_POWER9_SCRATCH_REGISTER_8 0x283f
#define IBM_POWER9_ROOT_CTRL8 0x2918
#define IBM_POWER9_ROOT_CTRL1_CLEAR 0x2931
// Platform data
#define IBM_POWER9_SLAVE_ID 0
static int check_device_id(void) {
uint32_t devid_high = openfsi_master_interface_device_id_high_read();
uint32_t devid_low = openfsi_master_interface_device_id_low_read();
if ((devid_high == 0x7c525054) && (devid_low == 0x4653494d)) {
return 0;
}
printf("Raptor OpenFSI master not found!\n");
return -1;
}
static int access_fsi_mem(uint8_t slave_id, uint32_t address, fsi_data_length_t data_length, uint8_t write, uint32_t* data) {
int ret = 0;
uint32_t word;
uint8_t status_code;
if (!data)
return -1;
// Set up request
word = openfsi_master_interface_sid_adr_read();
word &= ~(FSI_MASTER_SID_SLAVE_ID_MASK << FSI_MASTER_SID_SLAVE_ID_SHIFT);
word |= ((slave_id & FSI_MASTER_SID_SLAVE_ID_MASK) << FSI_MASTER_SID_SLAVE_ID_SHIFT);
word &= ~(FSI_MASTER_SID_ADDRESS_MASK << FSI_MASTER_SID_ADDRESS_SHIFT);
word |= ((address & FSI_MASTER_SID_ADDRESS_MASK) << FSI_MASTER_SID_ADDRESS_SHIFT);
word &= ~(FSI_MASTER_SID_DATA_LENGTH_MASK << FSI_MASTER_SID_DATA_LENGTH_SHIFT);
word |= ((data_length & FSI_MASTER_SID_DATA_LENGTH_MASK) << FSI_MASTER_SID_DATA_LENGTH_SHIFT);
openfsi_master_interface_sid_adr_write(word);
if (write) {
openfsi_master_interface_tx_data_write(*data);
}
// Set direction and start operation
word = openfsi_master_interface_control_reg_read();
word &= ~(FSI_MASTER_CTL_DATA_DIRECTION_MASK << FSI_MASTER_CTL_DATA_DIRECTION_SHIFT);
word |= ((write & FSI_MASTER_CTL_DATA_DIRECTION_MASK) << FSI_MASTER_CTL_DATA_DIRECTION_SHIFT);
word &= ~(FSI_MASTER_CTL_CYCLE_START_MASK << FSI_MASTER_CTL_CYCLE_START_SHIFT);
word |= ((1 & FSI_MASTER_CTL_CYCLE_START_MASK) << FSI_MASTER_CTL_CYCLE_START_SHIFT);
openfsi_master_interface_control_reg_write(word);
// Wait for operation to complete
while (!(openfsi_master_interface_status_reg_read() & (FSI_MASTER_CTL_CYCLE_START_MASK << FSI_MASTER_CTL_CYCLE_START_SHIFT)));
// Read status register
word = openfsi_master_interface_status_reg_read();
status_code = (word >> FSI_MASTER_STAT_CYCLE_ERROR_SHIFT) & FSI_MASTER_STAT_CYCLE_ERROR_MASK;
// Read data
if (!write)
*data = openfsi_master_interface_rx_data_read();
#ifdef DEBUG
printf("%s(): address 0x%06x, data: 0x%08x sta: 0x%08x\n", __FUNCTION__, address, *data, word);
#endif
if (status_code) {
#ifdef DEBUG
printf("[WARNING] FSI master returned error code %d on access to FSI address 0x%06x\n", status_code, address);
#endif
if (!ret)
ret = -1;
}
// Clear any operation request flag
word = openfsi_master_interface_control_reg_read();
word &= ~(FSI_MASTER_CTL_CYCLE_START_MASK << FSI_MASTER_CTL_CYCLE_START_SHIFT);
word |= ((0 & FSI_MASTER_CTL_CYCLE_START_MASK) << FSI_MASTER_CTL_CYCLE_START_SHIFT);
openfsi_master_interface_control_reg_write(word);
return ret;
}
static int access_cfam(uint8_t slave_id, uint32_t cfam_address, fsi_data_length_t data_length, uint8_t write, uint32_t* data) {
// CFAM to FSI address mangling
uint32_t fsi_address = (cfam_address & 0xfc00) | ((cfam_address & 0x3ff) << 2);
return access_fsi_mem(slave_id, fsi_address, data_length, write, data);
}
static int initialize_fsi_master(void) {
uint32_t word;
if (check_device_id())
return -1;
// Clear any pending operation requests
word = openfsi_master_interface_control_reg_read();
word &= ~(FSI_MASTER_CTL_CYCLE_START_MASK << FSI_MASTER_CTL_CYCLE_START_SHIFT);
word |= ((0 & FSI_MASTER_CTL_CYCLE_START_MASK) << FSI_MASTER_CTL_CYCLE_START_SHIFT);
openfsi_master_interface_control_reg_write(word);
// Wait for any running operation(s) to complete
while (openfsi_master_interface_status_reg_read() & (FSI_MASTER_CTL_CYCLE_START_MASK << FSI_MASTER_CTL_CYCLE_START_SHIFT));
// Set up ACK to CMD turnaround delay and enable CRC protection / enhanced error recovery
word = openfsi_master_interface_control_reg_read();
word &= ~(FSI_MASTER_CTL_CMD_ISSUE_DELAY_MASK << FSI_MASTER_CTL_CMD_ISSUE_DELAY_SHIFT);
word |= ((20 & FSI_MASTER_CTL_CMD_ISSUE_DELAY_MASK) << FSI_MASTER_CTL_CMD_ISSUE_DELAY_SHIFT);
word |= 1 << FSI_MASTER_CTL_ENABLE_CRC_SHIFT;
word |= 1 << FSI_MASTER_CTL_ENABLE_EER_SHIFT;
openfsi_master_interface_control_reg_write(word);
#ifdef DEBUG
printf("%s(): after setup: ctl 0x%08x, sta 0x%08x\n", __FUNCTION__, openfsi_master_interface_control_reg_read(), openfsi_master_interface_status_reg_read());
#endif
return 0;
}
int run_pre_ipl_fixups(void) {
uint32_t word;
uint32_t fsi_cfam_error_register;
// Set up FSI slave...
// [31]=1: Warm start done
// [29]=1: HW CRC check enabled
// [26:24]: FSI slave ID (0)
// [23:20]: Echo delay (7)
// [19:16]: Send delay (7)
// [11:8]: Clock ratio (8)
word = 0xa0ff0800;
if (access_cfam(IBM_POWER9_SLAVE_ID, IBM_CFAM_FSI_SMODE, FSI_DATA_LENGTH_WORD, FSI_DIRECTION_WRITE, &word))
goto fail;
// Ensure asynchronous clock mode is set
word = 0x0000001;
if (access_cfam(IBM_POWER9_SLAVE_ID, IBM_POWER9_LL_MODE_REG, FSI_DATA_LENGTH_WORD, FSI_DIRECTION_WRITE, &word))
goto fail;
// Configure SBE to pre-IPL state
if (access_cfam(IBM_POWER9_SLAVE_ID, IBM_POWER9_LL_MODE_REG, FSI_DATA_LENGTH_WORD, FSI_DIRECTION_READ, &word))
goto fail;
word &= ~(0x1 << 31); // Clear SBE IPL start flag
word &= ~(0x1 << 29); // Run SCAN0 and CLOCKSTART during IPL
word &= ~(0x1 << 28); // Clear SBE start prevention flag
if (access_cfam(IBM_POWER9_SLAVE_ID, IBM_POWER9_LL_MODE_REG, FSI_DATA_LENGTH_WORD, FSI_DIRECTION_WRITE, &word))
goto fail;
// Clear SBE status mailbox
word = 0x00000000;
if (access_cfam(IBM_POWER9_SLAVE_ID, IBM_POWER9_SBE_MSG_REGISTER, FSI_DATA_LENGTH_WORD, FSI_DIRECTION_WRITE, &word))
goto fail;
// Read CFAM error IRQ register
if (access_cfam(IBM_POWER9_SLAVE_ID, IBM_CFAM_FSI_SISC, FSI_DATA_LENGTH_WORD, FSI_DIRECTION_READ, &word))
goto fail;
fsi_cfam_error_register = word;
// Read CFAM status register
if (access_cfam(IBM_POWER9_SLAVE_ID, IBM_CFAM_FSI_SSTAT, FSI_DATA_LENGTH_WORD, FSI_DIRECTION_READ, &word))
goto fail;
// Clear CFAM error IRQ register
if (access_cfam(IBM_POWER9_SLAVE_ID, IBM_CFAM_FSI_SISC, FSI_DATA_LENGTH_WORD, FSI_DIRECTION_WRITE, &fsi_cfam_error_register))
goto fail;
return 0;
fail:
return -1;
}
int start_ipl(int side) {
uint32_t word;
if (initialize_fsi_master())
goto fail;
if ((side < 0) || (side > 1)) {
printf("Invalid side %d specified\n", side);
return -2;
}
printf("Starting IPL on side %d\n", side);
if (run_pre_ipl_fixups())
goto fail;
// Ensure asynchronous clock mode is set
word = 0x0000001;
if (access_cfam(IBM_POWER9_SLAVE_ID, IBM_POWER9_LL_MODE_REG, FSI_DATA_LENGTH_WORD, FSI_DIRECTION_WRITE, &word))
goto fail;
// Clock mux select override
if (access_cfam(IBM_POWER9_SLAVE_ID, IBM_POWER9_ROOT_CTRL8, FSI_DATA_LENGTH_WORD, FSI_DIRECTION_READ, &word))
goto fail;
word |= 0xc;
if (access_cfam(IBM_POWER9_SLAVE_ID, IBM_POWER9_ROOT_CTRL8, FSI_DATA_LENGTH_WORD, FSI_DIRECTION_WRITE, &word))
goto fail;
// Setup FSI2PIB to report checkstop
word = 0x20000000;
if (access_cfam(IBM_POWER9_SLAVE_ID, IBM_POWER9_FSI_A_SI1S, FSI_DATA_LENGTH_WORD, FSI_DIRECTION_WRITE, &word))
goto fail;
// Enable XSTOP/ATTN interrupt
word = 0x60000000;
if (access_cfam(IBM_POWER9_SLAVE_ID, IBM_POWER9_FSI2PIB_TRUE_MASK, FSI_DATA_LENGTH_WORD, FSI_DIRECTION_WRITE, &word))
goto fail;
// Arm XSTOP/ATTN interrupt
word = 0xffffffff;
if (access_cfam(IBM_POWER9_SLAVE_ID, IBM_POWER9_FSI2PIB_INTERRUPT, FSI_DATA_LENGTH_WORD, FSI_DIRECTION_WRITE, &word))
goto fail;
// SBE boot side configuration
if (access_cfam(IBM_POWER9_SLAVE_ID, IBM_POWER9_SBE_CTRL_STATUS, FSI_DATA_LENGTH_WORD, FSI_DIRECTION_READ, &word))
goto fail;
if (side == 0)
word &= ~(0x1 << 14);
else
word |= 0x1 << 14;
if (access_cfam(IBM_POWER9_SLAVE_ID, IBM_POWER9_SBE_CTRL_STATUS, FSI_DATA_LENGTH_WORD, FSI_DIRECTION_WRITE, &word))
goto fail;
// Ensure edge-triggered SBE start bit is deasserted prior to ignition...
if (access_cfam(IBM_POWER9_SLAVE_ID, IBM_POWER9_CBS_CS, FSI_DATA_LENGTH_WORD, FSI_DIRECTION_READ, &word))
goto fail;
word &= ~(0x1 << 31);
if (access_cfam(IBM_POWER9_SLAVE_ID, IBM_POWER9_CBS_CS, FSI_DATA_LENGTH_WORD, FSI_DIRECTION_WRITE, &word))
goto fail;
// ...and light the fuse!
word |= 0x1 << 31;
if (access_cfam(IBM_POWER9_SLAVE_ID, IBM_POWER9_CBS_CS, FSI_DATA_LENGTH_WORD, FSI_DIRECTION_WRITE, &word))
goto fail;
return 0;
fail:
printf("IPL failed!\n");
return -1;
}
int get_sbe_status(void) {
uint32_t word;
// SBE
if (access_cfam(IBM_POWER9_SLAVE_ID, IBM_POWER9_SBE_MSG_REGISTER, FSI_DATA_LENGTH_WORD, FSI_DIRECTION_READ, &word))
goto fail;
printf("CFAM 0x%06x: 0x%08x\n", IBM_POWER9_SBE_MSG_REGISTER, word);
// Hostboot
if (access_cfam(IBM_POWER9_SLAVE_ID, IBM_POWER9_HB_MBX5_REG, FSI_DATA_LENGTH_WORD, FSI_DIRECTION_READ, &word))
goto fail;
printf("CFAM 0x%06x: 0x%08x\n", IBM_POWER9_HB_MBX5_REG, word);
return 0;
fail:
printf("Processor not responding!\n");
return -1;
}
// © 2020 Raptor Engineering, LLC
//
// Released under the terms of the AGPL v3
// See the LICENSE file for full details
#ifndef _FSI_H
#define _FSI_H
typedef enum {
FSI_DATA_LENGTH_BYTE = 0,
FSI_DATA_LENGTH_HALFWORD = 1,
FSI_DATA_LENGTH_WORD = 2
} fsi_data_length_t;
#define FSI_MASTER_SID_SLAVE_ID_MASK 0x3
#define FSI_MASTER_SID_SLAVE_ID_SHIFT 29
#define FSI_MASTER_SID_ADDRESS_MASK 0x1fffff
#define FSI_MASTER_SID_ADDRESS_SHIFT 8
#define FSI_MASTER_SID_DATA_LENGTH_MASK 0x3
#define FSI_MASTER_SID_DATA_LENGTH_SHIFT 0
#define FSI_MASTER_CTL_CMD_ISSUE_DELAY_MASK 0xff
#define FSI_MASTER_CTL_CMD_ISSUE_DELAY_SHIFT 8
#define FSI_MASTER_CTL_DATA_DIRECTION_MASK 0x1
#define FSI_MASTER_CTL_DATA_DIRECTION_SHIFT 1
#define FSI_MASTER_CTL_ENABLE_CRC_MASK 0x1
#define FSI_MASTER_CTL_ENABLE_CRC_SHIFT 17
#define FSI_MASTER_CTL_ENABLE_EER_MASK 0x1
#define FSI_MASTER_CTL_ENABLE_EER_SHIFT 16
#define FSI_MASTER_CTL_CYCLE_START_MASK 0x1
#define FSI_MASTER_CTL_CYCLE_START_SHIFT 0
#define FSI_MASTER_STAT_CYCLE_ERROR_MASK 0x7
#define FSI_MASTER_STAT_CYCLE_ERROR_SHIFT 8
#define FSI_MASTER_STAT_CYCLE_COMPLETE_MASK 0x1
#define FSI_MASTER_STAT_CYCLE_COMPLETE_SHIFT 0
#define FSI_DIRECTION_READ 0
#define FSI_DIRECTION_WRITE 1
int run_pre_ipl_fixups(void);
int start_ipl(int side);
int get_sbe_status(void);
#endif // _FSI_H
......@@ -7,6 +7,8 @@
#include <console.h>
#include <generated/csr.h>
#include "fsi.h"
static char *readstr(void)
{
char c[2];
......@@ -63,7 +65,7 @@ static char *get_token(char **str)
static void prompt(void)
{
printf("RUNTIME>");
printf("FSP0>");
}
static void help(void)
......@@ -71,6 +73,8 @@ static void help(void)
puts("Available commands:");
puts("help - this command");
puts("reboot - reboot CPU");
puts("ipl - Start IPL sequence");
puts("sbe_status - Get SBE status register");
}
static void reboot(void)
......@@ -90,6 +94,10 @@ static void console_service(void)
help();
else if(strcmp(token, "reboot") == 0)
reboot();
else if(strcmp(token, "ipl") == 0)
start_ipl(0);
else if(strcmp(token, "sbe_status") == 0)
get_sbe_status();
prompt();
}
......@@ -101,7 +109,7 @@ int main(void)
#endif
uart_init();
puts("\nLab004 - CPU testing software built "__DATE__" "__TIME__"\n");
puts("\nRaptor Open FSP\nBuilt "__DATE__" "__TIME__"\n");
help();
prompt();
......
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