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

Sync from internal development repository GIT hash dfb40c41

Major update
Verified to fully IPL attached Blackbird host to Petitboot shell using Versa ECP5
parent 785c6503
......@@ -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 fsi.o
OBJECTS=utility.o isr.o main.o fsi.o opencores_i2c.o
all: firmware.bin
......@@ -18,7 +18,7 @@ firmware.elf: $(OBJECTS)
$(LD) $(LDFLAGS) \
-T linker.ld \
-N -o $@ \
$(BUILD_DIR)/software/libbase/crt0-ctr.o \
$(BUILD_DIR)/software/libbase/crt0.o \
$(OBJECTS) \
-L$(BUILD_DIR)/software/libbase \
-L$(BUILD_DIR)/software/libcompiler_rt \
......
// © 2020 Raptor Engineering, LLC
//
// Released under the terms of the AGPL v3
// See the LICENSE file for full details
#ifndef _AQUILA_H
#define _AQUILA_H
#define AQUILA_LPC_CTL_BLOCK_OFFSET 0xf00000
#define AQUILA_LPC_STATUS_CYC_WNR_MASK 0x1
#define AQUILA_LPC_STATUS_CYC_WNR_SHIFT 1
#define AQUILA_LPC_STATUS_ATTN_REQ_MASK 0x1
#define AQUILA_LPC_STATUS_ATTN_REQ_SHIFT 0
#define AQUILA_LPC_STATUS_CYCLE_TYPE_MASK 0x3
#define AQUILA_LPC_STATUS_CYCLE_TYPE_SHIFT 2
#define AQUILA_LPC_STATUS_FW_CYCLE_MSIZE_MASK 0xf
#define AQUILA_LPC_STATUS_FW_CYCLE_MSIZE_SHIFT 16
#define AQUILA_LPC_STATUS_FW_CYCLE_IDSEL_MASK 0xf
#define AQUILA_LPC_STATUS_FW_CYCLE_IDSEL_SHIFT 20
#define AQUILA_LPC_STATUS_ACT_ADDR_MASK 0xfffffff
#define AQUILA_LPC_STATUS_ACT_ADDR_SHIFT 0
#define AQUILA_LPC_STATUS_ACT_WDATA_MASK 0xff
#define AQUILA_LPC_STATUS_ACT_WDATA_SHIFT 0
#define AQUILA_LPC_CTL_ACT_RDATA_MASK 0xff
#define AQUILA_LPC_CTL_ACT_RDATA_SHIFT 8
#define AQUILA_LPC_CTL_EN_IO_CYCLES_MASK 0x1
#define AQUILA_LPC_CTL_EN_IO_CYCLES_SHIFT 3
#define AQUILA_LPC_CTL_EN_FW_CYCLES_MASK 0x1
#define AQUILA_LPC_CTL_EN_FW_CYCLES_SHIFT 1
#define AQUILA_LPC_CTL_EN_VUART1_MASK 0x1
#define AQUILA_LPC_CTL_EN_VUART1_SHIFT 4
#define AQUILA_LPC_CTL_EN_VUART2_MASK 0x1
#define AQUILA_LPC_CTL_EN_VUART2_SHIFT 5
#define AQUILA_LPC_CTL_EN_IPMI_BT_MASK 0x1
#define AQUILA_LPC_CTL_EN_IPMI_BT_SHIFT 6
#define AQUILA_LPC_CTL_EN_IPMI_BT_IRQ_MASK 0x1
#define AQUILA_LPC_CTL_EN_IPMI_BT_IRQ_SHIFT 16
#define AQUILA_LPC_CTL_IPMI_BT_ADDR_MASK 0xff
#define AQUILA_LPC_CTL_IPMI_BT_ADDR_SHIFT 8
#define AQUILA_LPC_CTL_EN_FW_CYCLE_IRQ_MASK 0x1
#define AQUILA_LPC_CTL_EN_FW_CYCLE_IRQ_SHIFT 17
#define AQUILA_LPC_CTL_EN_TPM_CYCLE_IRQ_MASK 0x1
#define AQUILA_LPC_CTL_EN_TPM_CYCLE_IRQ_SHIFT 18
#define AQUILA_LPC_CTL_EN_IO_CYCLE_IRQ_MASK 0x1
#define AQUILA_LPC_CTL_EN_IO_CYCLE_IRQ_SHIFT 19
#define AQUILA_LPC_CTL_XFER_ERR_MASK 0x1
#define AQUILA_LPC_CTL_XFER_ERR_SHIFT 1
#define AQUILA_LPC_CTL_XFER_CONT_MASK 0x1
#define AQUILA_LPC_CTL_XFER_CONT_SHIFT 0
#define AQUILA_LPC_RANGE_ENABLE_MASK 0x1
#define AQUILA_LPC_RANGE_ENABLE_SHIFT 31
#define AQUILA_LPC_RANGE_ALLOW_IO_MASK 0x1
#define AQUILA_LPC_RANGE_ALLOW_IO_SHIFT 30
#define AQUILA_LPC_RANGE_ALLOW_TPM_MASK 0x1
#define AQUILA_LPC_RANGE_ALLOW_TPM_SHIFT 29
#define AQUILA_LPC_RANGE_START_ADDR_MASK 0xfffffff
#define AQUILA_LPC_RANGE_START_ADDR_SHIFT 0
#define AQUILA_LPC_RANGE_END_ADDR_MASK 0xfffffff
#define AQUILA_LPC_RANGE_END_ADDR_SHIFT 0
#define AQUILA_LPC_CTL_EN_FW_DMA_R_MASK 0x1
#define AQUILA_LPC_CTL_EN_FW_DMA_R_SHIFT 0
#define AQUILA_LPC_CTL_EN_FW_DMA_W_MASK 0x1
#define AQUILA_LPC_CTL_EN_FW_DMA_W_SHIFT 1
#define AQUILA_LPC_REG_DEVICE_ID_HIGH 0x0
#define AQUILA_LPC_REG_DEVICE_ID_LOW 0x4
#define AQUILA_LPC_REG_DEVICE_VERSION 0x8
#define AQUILA_LPC_REG_CONTROL1 0xc
#define AQUILA_LPC_REG_CONTROL2 0x10
#define AQUILA_LPC_REG_RANGE1_CONFIG 0x14
#define AQUILA_LPC_REG_RANGE1_END 0x18
#define AQUILA_LPC_REG_RANGE2_CONFIG 0x1c
#define AQUILA_LPC_REG_RANGE2_END 0x20
#define AQUILA_LPC_REG_RANGE3_CONFIG 0x24
#define AQUILA_LPC_REG_RANGE3_END 0x28
#define AQUILA_LPC_REG_RANGE4_CONFIG 0x2c
#define AQUILA_LPC_REG_RANGE4_END 0x30
#define AQUILA_LPC_REG_RANGE5_CONFIG 0x34
#define AQUILA_LPC_REG_RANGE5_END 0x38
#define AQUILA_LPC_REG_RANGE6_CONFIG 0x3c
#define AQUILA_LPC_REG_RANGE6_END 0x40
#define AQUILA_LPC_REG_DMA_CONFIG1 0x44
#define AQUILA_LPC_REG_DMA_CONFIG2 0x48
#define AQUILA_LPC_REG_DMA_CONFIG3 0x4c
#define AQUILA_LPC_REG_DMA_CONFIG4 0x50
#define AQUILA_LPC_REG_DMA_CONFIG5 0x54
#define AQUILA_LPC_REG_DMA_CONFIG6 0x58
#define AQUILA_LPC_REG_STATUS1 0x5c
#define AQUILA_LPC_REG_STATUS2 0x60
#define AQUILA_LPC_REG_STATUS3 0x64
#define AQUILA_LPC_REG_STATUS4 0x68
#define AQUILA_LPC_REG_IPMI_BT_STATUS 0x6c
#define AQUILA_LPC_DEVICE_ID_HIGH 0x7c525054
#define AQUILA_LPC_DEVICE_ID_LOW 0x4c504353
#define AQUILA_LPC_VERSION_MAJOR_MASK 0xffff
#define AQUILA_LPC_VERSION_MAJOR_SHIFT 16
#define AQUILA_LPC_VERSION_MINOR_MASK 0xff
#define AQUILA_LPC_VERSION_MINOR_SHIFT 8
#define AQUILA_LPC_VERSION_PATCH_MASK 0xff
#define AQUILA_LPC_VERSION_PATCH_SHIFT 0
#define AQUILA_LPC_FW_DATA_BLOCK_OFFSET 0xc00000
#define AQUILA_LPC_IPMI_BT_DATA_BLOCK_OFFSET 0xd00000
#define AQUILA_LPC_STATUS_CYCLE_TYPE_IO 0
#define AQUILA_LPC_STATUS_CYCLE_TYPE_FW 2
#define AQUILA_LPC_VUART1_FIFO_EMPTY 0x00000100
#define AQUILA_LPC_VUART2_FIFO_EMPTY 0x01000000
#define AQUILA_LPC_IRQ_ASSERTED 0x00000001
#define AQUILA_LPC_VUART1_IRQ_ASSERTED 0x00000002
#define AQUILA_LPC_VUART2_IRQ_ASSERTED 0x00000004
#define AQUILA_LPC_IPMI_BT_IRQ_ASSERTED 0x00000008
#define AQUILA_LPC_FW_CYCLE_IRQ_ASSERTED 0x00000010
#define AQUILA_LPC_TPM_CYCLE_IRQ_ASSERTED 0x00000020
#define AQUILA_LPC_IO_CYCLE_IRQ_ASSERTED 0x00000040
#define AQUILA_LPC_VUART1_FIFO_READ_MASK 0xff
#define AQUILA_LPC_VUART1_FIFO_READ_SHIFT 0
#define AQUILA_LPC_VUART_BLOCK_OFFSET 0xe00000
#define AQUILA_LPC_VUART1_STATUS_REG 0x4
#define AQUILA_LPC_VUART1_CONTROL_REG 0x8
#define AQUILA_LPC_VUART_FIFO_TRIG_LVL_MASK 0xff
#define AQUILA_LPC_VUART_FIFO_TRIG_LVL_SHIFT 8
#define AQUILA_LPC_VUART_FIFO_IRQ_EN_MASK 0x1
#define AQUILA_LPC_VUART_FIFO_IRQ_EN_SHIFT 30
#define AQUILA_LPC_VUART_IRQ_EN_MASK 0x1
#define AQUILA_LPC_VUART_IRQ_EN_SHIFT 31
#define AQUILA_LPC_VUART_WFIFO_FULL_MASK 0x1
#define AQUILA_LPC_VUART_WFIFO_FULL_SHIFT 24
#define AQUILA_EV_MASTER_IRQ 0x1
static inline uint32_t read_aquila_register(unsigned long base_address, uint8_t reg) {
return *((volatile uint32_t*)(base_address + AQUILA_LPC_CTL_BLOCK_OFFSET + reg));
}
static inline void write_aquila_register(unsigned long base_address, uint8_t reg, uint32_t data) {
*((volatile uint32_t*)(base_address + AQUILA_LPC_CTL_BLOCK_OFFSET + reg)) = data;
}
static inline uint8_t lpc_fw_msize_to_bytes(uint8_t msize) {
switch (msize) {
case 0: return 1;
case 1: return 2;
case 2: return 4;
case 4: return 16;
case 7: return 128;
default: return 0;
}
}
void lpc_slave_isr(void);
#endif // _AQUILA_H
\ No newline at end of file
......@@ -7,7 +7,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <generated/csr.h>
#include <generated/mem.h>
#include "fsi.h"
......@@ -38,8 +38,8 @@
#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();
uint32_t devid_high = read_openfsi_register(OPENFSIMASTER_BASE, FSI_MASTER_REG_DEVICE_ID_HIGH);
uint32_t devid_low = read_openfsi_register(OPENFSIMASTER_BASE, FSI_MASTER_REG_DEVICE_ID_LOW);
if ((devid_high == 0x7c525054) && (devid_low == 0x4653494d)) {
return 0;
......@@ -58,36 +58,36 @@ static int access_fsi_mem(uint8_t slave_id, uint32_t address, fsi_data_length_t
return -1;
// Set up request
word = openfsi_master_interface_sid_adr_read();
word = read_openfsi_register(OPENFSIMASTER_BASE, FSI_MASTER_REG_SID_ADR);
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);
write_openfsi_register(OPENFSIMASTER_BASE, FSI_MASTER_REG_SID_ADR, word);
if (write) {
openfsi_master_interface_tx_data_write(*data);
write_openfsi_register(OPENFSIMASTER_BASE, FSI_MASTER_REG_TX_DATA, *data);
}
// Set direction and start operation
word = openfsi_master_interface_control_reg_read();
word = read_openfsi_register(OPENFSIMASTER_BASE, FSI_MASTER_REG_CONTROL);
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);
write_openfsi_register(OPENFSIMASTER_BASE, FSI_MASTER_REG_CONTROL, 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)));
while (!(read_openfsi_register(OPENFSIMASTER_BASE, FSI_MASTER_REG_STATUS) & (FSI_MASTER_CTL_CYCLE_START_MASK << FSI_MASTER_CTL_CYCLE_START_SHIFT)));
// Read status register
word = openfsi_master_interface_status_reg_read();
word = read_openfsi_register(OPENFSIMASTER_BASE, FSI_MASTER_REG_STATUS);
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();
*data = read_openfsi_register(OPENFSIMASTER_BASE, FSI_MASTER_REG_RX_DATA);
#ifdef DEBUG
printf("%s(): address 0x%06x, data: 0x%08x sta: 0x%08x\n", __FUNCTION__, address, *data, word);
......@@ -102,10 +102,10 @@ static int access_fsi_mem(uint8_t slave_id, uint32_t address, fsi_data_length_t
}
// Clear any operation request flag
word = openfsi_master_interface_control_reg_read();
word = read_openfsi_register(OPENFSIMASTER_BASE, FSI_MASTER_REG_CONTROL);
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);
write_openfsi_register(OPENFSIMASTER_BASE, FSI_MASTER_REG_CONTROL, word);
return ret;
}
......@@ -124,24 +124,24 @@ static int initialize_fsi_master(void) {
return -1;
// Clear any pending operation requests
word = openfsi_master_interface_control_reg_read();
word = read_openfsi_register(OPENFSIMASTER_BASE, FSI_MASTER_REG_CONTROL);
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);
write_openfsi_register(OPENFSIMASTER_BASE, FSI_MASTER_REG_CONTROL, 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));
while (read_openfsi_register(OPENFSIMASTER_BASE, FSI_MASTER_REG_STATUS) & (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 = read_openfsi_register(OPENFSIMASTER_BASE, FSI_MASTER_REG_CONTROL);
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);
write_openfsi_register(OPENFSIMASTER_BASE, FSI_MASTER_REG_CONTROL, 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());
printf("%s(): after setup: ctl 0x%08x, sta 0x%08x\n", __FUNCTION__, read_openfsi_register(OPENFSIMASTER_BASE, FSI_MASTER_REG_CONTROL), read_openfsi_register(OPENFSIMASTER_BASE, FSI_MASTER_REG_STATUS));
#endif
return 0;
......
......@@ -12,31 +12,50 @@ typedef enum {
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
// Peripheral registers
#define FSI_MASTER_REG_DEVICE_ID_HIGH 0x0
#define FSI_MASTER_REG_DEVICE_ID_LOW 0x4
#define FSI_MASTER_REG_DEVICE_VERSION 0x8
#define FSI_MASTER_REG_SID_ADR 0xc
#define FSI_MASTER_REG_CONTROL 0x10
#define FSI_MASTER_REG_STATUS 0x14
#define FSI_MASTER_REG_TX_DATA 0x18
#define FSI_MASTER_REG_RX_DATA 0x1c
#define FSI_MASTER_REG_DMA_IRQ 0x20
#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
static inline uint32_t read_openfsi_register(unsigned long base_address, uint8_t reg) {
return *((volatile uint32_t*)(base_address + reg));
}
static inline void write_openfsi_register(unsigned long base_address, uint8_t reg, uint32_t data) {
*((volatile uint32_t*)(base_address + reg)) = data;
}
int run_pre_ipl_fixups(void);
int start_ipl(int side);
......
// © 2020 Raptor Engineering, LLC
//
// Released under the terms of the AGPL v3
// See the LICENSE file for full details
#ifndef _IPMI_BT_H
#define _IPMI_BT_H
// Bitfield flag shifts
#define IPMI_BT_CTL_CLEAR_WR_PTR_SHIFT 0
#define IPMI_BT_CTL_CLEAR_RD_PTR_SHIFT 1
#define IPMI_BT_CTL_H2B_ATN_SHIFT 2
#define IPMI_BT_CTL_B2H_ATN_SHIFT 3
#define IPMI_BT_CTL_SMS_ATN_SHIFT 4
#define IPMI_BT_CTL_OEM0_SHIFT 5
#define IPMI_BT_CTL_H_BUSY_SHIFT 6
#define IPMI_BT_CTL_B_BUSY_SHIFT 7
// Sensor mappings
// NOTE: These may change from platform to platform!
// The values below are valid for Raptor Computing Systems Talos II / Blackbird
#define IPMI_SENSOR_FW_BOOT 0x02 // XML ID /sys-0/fw_boot_sensor [W]
#define IPMI_SENSOR_CPU0_OCC_ACTIVE 0x03 // XML ID /sys-0/node-0/motherboard-0/proc_socket-0/module-0/p9_proc_s/occ/occ_active_sensor [W]
#define IPMI_SENSOR_CPU1_OCC_ACTIVE 0x04 // XML ID /sys-0/node-0/motherboard-0/proc_socket-1/module-0/p9_proc_s/occ/occ_active_sensor [W]
#define IPMI_SENSOR_CPU0_FUNC 0x08 // XML ID /sys-0/node-0/motherboard-0/proc_socket-0/module-0/p9_proc_s/cpu_func_sensor [W]
#define IPMI_SENSOR_CPU1_FUNC 0x09 // XML ID /sys-0/node-0/motherboard-0/proc_socket-1/module-0/p9_proc_s/cpu_func_sensor [W]
#define IPMI_SENSOR_BOOT_COUNT 0x8b // XML ID /sys-0/boot_count_sensor [RW]
#define IPMI_SENSOR_PLANAR_FAULT 0x8c // XML ID /sys-0/node-0/motherboard_fault_sensor [W]
#define IPMI_SENSOR_REF_CLK_FAULT 0x8d // XML ID /sys-0/node-0/ref_clk_sensor [W]
#define IPMI_SENSOR_PCIE_CLK_FAULT 0x8e // XML ID /sys-0/node-0/pci_clk_sensor [W]
#define IPMI_SENSOR_TOD_CLK_FAULT 0x8f // XML ID /sys-0/node-0/tod_clk_sensor [W]
#define IPMI_SENSOR_APSS_FAULT 0x93 // XML ID /sys-0/node-0/apss_fault_sensor [W]
#define IPMI_SENSOR_DERATING_FACTOR 0x96 // XML ID /sys-0/ps_derating_sensor [R]
// Inventory bitfield sensor ranges
#define IPMI_SENSOR_INV_DIMM_FUNC_BEG 0x0b // XML ID /sys-0/node-0/motherboard-0/dimmconn-<X>/dimm-0/dimm_func_sensor [W]
#define IPMI_SENSOR_INV_DIMM_FUNC_END 0x1a
#define IPMI_SENSOR_INV_CPU0_FUNC_BEG 0x2b // XML ID /sys-0/node-0/motherboard-0/proc_socket-0/module-0/p9_proc_s/eq<X>/ex<Y>/core<Z>/cpucore_func_sensor [W]
#define IPMI_SENSOR_INV_CPU0_FUNC_END 0x42
#define IPMI_SENSOR_INV_CPU1_FUNC_BEG 0x43 // XML ID /sys-0/node-0/motherboard-0/proc_socket-1/module-0/p9_proc_s/eq<X>/ex<Y>/core<Z>/cpucore_func_sensor [W]
#define IPMI_SENSOR_INV_CPU1_FUNC_END 0x5a
// Event Data Byte bitfield mappings
// These are believed constant across hostboot versions, and are defined in hostboot src/include/usr/ipmi/ipmisensor.H
#define IPMI_OP_EVT_SHIFT_DIMM_DSBL 4
#define IPMI_OP_EVT_SHIFT_DIMM_PRST 6
#define IPMI_OP_EVT_SHIFT_PROC_PRST 7
#define IPMI_OP_EVT_SHIFT_PROC_DSBL 8
// IPMI network function codes
#define IPMI_NETFN_SENS_ET_REQ 0x04
#define IPMI_NETFN_APP_REQUEST 0x06
#define IPMI_NETFN_STORAGE_REQ 0x0a
#define IPMI_NETFN_DCMI_GP_REQ 0x2c
#define IPMI_NETFN_OEM_IBM_REQ 0x3a
// Sensor / Event commands
#define IPMI_CMD_GET_SNS_READNG 0x2d
#define IPMI_CMD_SET_SN_RD_EV_S 0x30
// Application commands
#define IPMI_CMD_GET_DEVICE_ID 0x01
#define IPMI_CMD_GET_BT_INT_CAP 0x36
// Storage commands
#define IPMI_CMD_GET_SEL_TIME 0x48
#define IPMI_CMD_SET_SEL_TIME 0x49
// IBM commands
#define IPMI_CMD_IBM_HIOMAP_REQ 0x5a
#define IPMI_CC_NO_ERROR 0x00
#define IPMI_CC_SNS_NOT_PRSNT 0xcb
#define IPMI_CC_INVALID_COMMAND 0xc1
#define BASE_IPMI_REQUEST_LENGTH 3
#define BASE_IPMI_RESPONSE_LENGTH 4
#define BASE_DCMI_RESPONSE_LENGTH (BASE_IPMI_RESPONSE_LENGTH + 1)
#define BASE_HIOMAP_RESPONSE_LENGTH (BASE_IPMI_RESPONSE_LENGTH + 2)
// DCMI commands
#define DCMI_CMD_GET_CAPABILITIES 0x01
#define DCMI_CMD_GET_POWER_CAP 0x03
// DCMI response codes
#define DCMI_CC_NO_ERROR 0x00
#define DCMI_CC_INVALID_COMMAND 0xc1
// DCMI parameters
#define DCMI_ENFORCE_POWER_LIMIT 0
#define DCMI_POWER_LIMIT_W 190
#define DCMI_CORR_LIMIT_TIME_MS 500
#define DCMI_PWR_SAMPLE_PERIOD_S 1
// HIOMAP commands
#define HIOMAP_CMD_RESET 0x01
#define HIOMAP_CMD_GET_INFO 0x02
#define HIOMAP_CMD_GET_FLASH_INFO 0x03
#define HIOMAP_CMD_CREATE_RD_WIN 0x04
#define HIOMAP_CMD_CLOSE_WINDOW 0x05
#define HIOMAP_CMD_CREATE_WR_WIN 0x06
#define HIOMAP_CMD_MARK_DIRTY 0x07
#define HIOMAP_CMD_FLUSH 0x08
#define HIOMAP_CMD_ACK 0x09
#define HIOMAP_CMD_ERASE 0x0a
#define HIOMAP_CMD_GET_FLASH_NAME 0x0b
#define HIOMAP_CMD_LOCK 0x0c
#define HIOMAP_WINDOW_TYPE_READ 0x0
#define HIOMAP_WINDOW_TYPE_WRITE 0x1
#define HIOMAP_WINDOW_INACTIVE 0x2
// HIOMAP parameters
#define HIOMAP_SUGGESTED_TIMEOUT_S 15
#define HIOMAP_PNOR_DEVICE_COUNT 1
// 4k block size
// Requires subsector erase capability
#define FLASH_BLOCK_SIZE_SHIFT 12
// 64MB Flash
#define FLASH_SIZE_BYTES 67108864
// 256 byte pages
#define FLASH_PAGE_SIZE_BYTES 256
// Minimum erase size is one block
#define FLASH_ERASE_GRAN_BLOCKS 1
// Maximum cacheable / writeable chunk size
// Constrained by available BRAM in the FPGA
#define FLASH_MAX_WR_WINDOW_BYTES 4096
// Calculated and specification locked HIOMAP parameters
#define LPC_ADDRESS_BITS 28
#define FLASH_SIZE_BLOCKS (FLASH_SIZE_BYTES >> FLASH_BLOCK_SIZE_SHIFT)
#define FLASH_ERASE_GRAN_BYTES (FLASH_ERASE_GRAN_BLOCKS << FLASH_BLOCK_SIZE_SHIFT)
// OpenPOWER system constants
#define OPENPOWER_BOOT_COUNT_SENSOR_DEFAULT 2
typedef struct hiomap_pnor_dirty_range {
uint32_t start_address;
uint32_t bytes;
uint8_t erased;
} hiomap_pnor_dirty_range_t;
typedef struct hiomap_configuration_data {
uint8_t protocol_version;
uint32_t window_start_address;
uint32_t window_length_bytes;
uint8_t active_device_id;
uint8_t window_type;
uint8_t dirty_range_count;
hiomap_pnor_dirty_range_t dirty_ranges[128];
} hiomap_configuration_data_t;
typedef struct __attribute__((packed)) ipmi_request_message {
uint8_t length;
uint8_t netfn_lun;
uint8_t sequence;
uint8_t command;
uint8_t data[256 - BASE_IPMI_REQUEST_LENGTH];
} ipmi_request_message_t;
typedef struct __attribute__((packed)) ipmi_response_message {
uint8_t length;
uint8_t netfn_lun;
uint8_t sequence;
uint8_t command;
uint8_t completion_code;
uint8_t data[256 - BASE_IPMI_REQUEST_LENGTH];
} ipmi_response_message_t;
#endif // _IPMI_BT_H
......@@ -3,24 +3,81 @@
#include <irq.h>
#include <uart.h>
void isr(void);
#include "aquila.h"
uint32_t irq_unhandled_vector = 0;
uint32_t irq_unhandled_source = 0;
uint8_t irq_unhandled_vector_valid = 0;
uint8_t irq_unhandled_source_valid = 0;
void isr(uint64_t vec);
void isr_dec(void);
#ifdef CONFIG_CPU_HAS_INTERRUPT
void isr(void)
void isr(uint64_t vec)
{
__attribute__((unused)) unsigned int irqs;
if (vec == 0x900)
{
// DEC interrupt
isr_dec();
return;
}
if (vec == 0x500)
{
// Read interrupt source
uint32_t xirr = xics_icp_readw(PPC_XICS_XIRR);
uint32_t irq_source = xirr & 0x00ffffff;
irqs = irq_pending() & irq_getmask();
__attribute__((unused)) unsigned int irqs;
// Handle IPI interrupts separately
if (irq_source == 2) {
// IPI interrupt
xics_icp_writeb(PPC_XICS_MFRR, 0xff);
}
else if (irq_source == 0) {
// Unknown source, slently ignore...
}
else {
// External interrupt
irqs = irq_pending() & irq_getmask();
#ifndef UART_POLLING
if(irqs & (1 << UART_INTERRUPT))
uart_isr();
if (irqs & (1 << UART_INTERRUPT))
uart_isr();
#endif
if (irqs & (1 << HOSTLPCSLAVE_INTERRUPT))
lpc_slave_isr();
if (!irqs) {
irq_unhandled_source = irq_source;
irq_unhandled_source_valid = 1;
}
}
// Clear interrupt
xics_icp_writew(PPC_XICS_XIRR, xirr);
return;
}
irq_unhandled_vector = vec;
irq_unhandled_vector_valid = 1;
while (1);
}
void isr_dec(void)
{
// For now, just set DEC back to a large enough value to slow the flood of DEC-initiated timer interrupts
mtdec(0x000000000ffffff);
}
#else
void isr(void){};
void isr_dec(void){};
#endif
INCLUDE generated/output_format.ld
ENTRY(_start)
__DYNAMIC = 0;
INCLUDE generated/regions.ld
SECTIONS
......@@ -10,33 +8,47 @@ SECTIONS
.text :
{
_ftext = .;
*(.text .stub .text.* .gnu.linkonce.t.*)
_etext = .;
} > main_ram
.rodata :
{
. = ALIGN(4);
. = ALIGN(8);
_frodata = .;
*(.rodata .rodata.* .gnu.linkonce.r.*)
*(.rodata1)
*(.got .got.*)
*(.toc .toc.*)
/* Make sure the file is aligned on disk as well
as in memory; CRC calculation requires that. */
FILL(0);
. = ALIGN(8);
_erodata = .;
} > main_ram
.data :
{
. = ALIGN(4);
. = ALIGN(8);
_fdata = .;
*(.data .data.* .gnu.linkonce.d.*)
*(.data1)
_gp = ALIGN(16);
*(.sdata .sdata.* .gnu.linkonce.s.*)
/* Make sure the file is aligned on disk as well
as in memory; CRC calculation requires that. */
FILL(0);
. = ALIGN(8);
_edata = .;
} > main_ram
.bss :
{
. = ALIGN(4);
. = ALIGN(8);
__rom_isr_address = .;
. = . + 8;
_fbss = .;
*(.dynsbss)
*(.sbss .sbss.* .gnu.linkonce.sb.*)
......@@ -44,10 +56,19 @@ SECTIONS
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
. = ALIGN(8);
_ebss = .;
_end = .;
} > sram
/DISCARD/ :
{
*(.eh_frame)
*(.comment)
}
}
PROVIDE(_fstack = ORIGIN(sram) + LENGTH(sram) - 4);
PROVIDE(_fstack = ORIGIN(sram) + LENGTH(sram) - 8);
PROVIDE(_fdata_rom = LOADADDR(.data));
PROVIDE(_edata_rom = LOADADDR(.data) + SIZEOF(.data));
This diff is collapsed.
// © 2020 Raptor Engineering, LLC
//
// Released under the terms of the AGPL v3
// See the LICENSE file for full details
uint32_t micron_n25q_spi_device_ids[] = {
0x20ba2010
};
const char* micron_n25q_spi_device_names[] = {
"Micron N25Q 512MB"
};
#define MICRON_N25Q_SPI_FAST_READ_DUMMY_CLOCK_CYCLES 10
#define MICRON_N25Q_SPI_3BA_SPI_READ_CMD 0x03
#define MICRON_N25Q_SPI_4BA_SPI_READ_CMD 0x13
// NOTE: QSPI mode unavailable for single read, use Write Disable command as plaecholder
#define MICRON_N25Q_SPI_3BA_QSPI_READ_CMD 0x04
#define MICRON_N25Q_SPI_4BA_QSPI_READ_CMD 0x04
#define MICRON_N25Q_SPI_3BA_SPI_FAST_READ_CMD 0x0b
#define MICRON_N25Q_SPI_4BA_SPI_FAST_READ_CMD 0x0c
#define MICRON_N25Q_SPI_3BA_QSPI_FAST_READ_CMD 0xeb
#define MICRON_N25Q_SPI_4BA_QSPI_FAST_READ_CMD 0xec
// NOTE: The same command code is used for both QSPI 3BA and QSPI 4BA extended quad input writes, thus the device must be placed in either 3BA or 4BA mode prior to issuing PAGE PROGRAM
#define MICRON_N25Q_SPI_3BA_SPI_PAGE_PROGRAM_CMD 0x02
#define MICRON_N25Q_SPI_4BA_SPI_PAGE_PROGRAM_CMD 0x12
#define MICRON_N25Q_SPI_3BA_QSPI_PAGE_PROGRAM_CMD 0x38
#define MICRON_N25Q_SPI_4BA_QSPI_PAGE_PROGRAM_CMD 0x38
\ No newline at end of file
// © 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 <generated/soc.h>
#include "utility.h"
#include "opencores_i2c.h"
int initialize_i2c_master(uint8_t* base_address, int i2c_bus_frequency) {
printf("Configuring I2C master at address %p...\n", base_address);
if ((*((volatile uint32_t*)(base_address + OPENCORES_I2C_MASTER_DEVICE_ID_HIGH)) != OPENCORES_I2C_DEVICE_ID_HIGH)
|| (*((volatile uint32_t*)(base_address + OPENCORES_I2C_MASTER_DEVICE_ID_LOW)) != OPENCORES_I2C_DEVICE_ID_LOW)) {
return -1;
}
uint32_t opencores_spi_version = *((volatile uint32_t*)(base_address + OPENCORES_I2C_MASTER_DEVICE_VERSION));
printf("OpenCores I2C master found, device version %0d.%0d.%d\n", (opencores_spi_version >> OPENCORES_I2C_VERSION_MAJOR_SHIFT) & OPENCORES_I2C_VERSION_MAJOR_MASK, (opencores_spi_version >> OPENCORES_I2C_VERSION_MINOR_SHIFT) & OPENCORES_I2C_VERSION_MINOR_MASK, (opencores_spi_version >> OPENCORES_I2C_VERSION_PATCH_SHIFT) & OPENCORES_I2C_VERSION_PATCH_MASK);
// Compute prescale value from system clock and desired I2C frequency in HZ
uint16_t i2c_prescale = (CONFIG_CLOCK_FREQUENCY / (5LL * i2c_bus_frequency)) - 1;
printf("Desired prescale register: 0x%04x (system clock %dMHz, bus frequency %dkHz)\n", i2c_prescale, CONFIG_CLOCK_FREQUENCY / 1000000LL, i2c_bus_frequency / 1000LL);
*((volatile uint8_t*)(base_address + OPENCORES_I2C_MASTER_PRESCALE_LOW)) = i2c_prescale & 0xff;
*((volatile uint8_t*)(base_address + OPENCORES_I2C_MASTER_PRESCALE_HIGH)) = (i2c_prescale >> 8) & 0xff;
if ((*((volatile uint8_t*)(base_address + OPENCORES_I2C_MASTER_PRESCALE_LOW)) == (i2c_prescale & 0xff))
&& (*((volatile uint8_t*)(base_address + OPENCORES_I2C_MASTER_PRESCALE_HIGH)) == ((i2c_prescale >> 8) & 0xff))) {
printf("Enabling I2C core\n", i2c_prescale);
*((volatile uint8_t*)(base_address + OPENCORES_I2C_MASTER_PRESCALE_CTL)) = (OPENCORES_I2C_MASTER_CTL_CORE_EN_MASK << OPENCORES_I2C_MASTER_CTL_CORE_EN_SHIFT);
return 0;
}
return 1;
}
int write_i2c_data(uint8_t* base_address, uint8_t slave_address, uint8_t* data, int data_length, uint8_t send_stop_signal) {
uint32_t i2c_op_timeout_counter;
uint8_t i2c_op_failed;
int active_byte;
uint8_t byte;
i2c_op_failed = 0;
*((volatile uint8_t*)(base_address + OPENCORES_I2C_MASTER_TX_RX)) = (slave_address << 1) | (OPENCORES_I2C_MASTER_TX_RX_WRITE_MASK << OPENCORES_I2C_MASTER_TX_RX_WRITE_SHIFT);
*((volatile uint8_t*)(base_address + OPENCORES_I2C_MASTER_CMD_STATUS)) = (OPENCORES_I2C_MASTER_CMD_STA_MASK << OPENCORES_I2C_MASTER_CMD_STA_SHIFT) | (OPENCORES_I2C_MASTER_CMD_WR_MASK << OPENCORES_I2C_MASTER_CMD_WR_SHIFT);
i2c_op_timeout_counter = 0;
while ((*((volatile uint8_t*)(base_address + OPENCORES_I2C_MASTER_CMD_STATUS)) >> OPENCORES_I2C_MASTER_STATUS_TIP_SHIFT) & OPENCORES_I2C_MASTER_STATUS_TIP_MASK) {
if (i2c_op_timeout_counter > I2C_MASTER_OPERATION_TIMEOUT_VALUE) {
printf("[WARNING] I2C operation timed out in device select!\n");
i2c_op_failed = 1;
break;
}
usleep(100);
i2c_op_timeout_counter++;
}
if (!i2c_op_failed) {
if ((*((volatile uint8_t*)(base_address + OPENCORES_I2C_MASTER_CMD_STATUS)) >> OPENCORES_I2C_MASTER_STATUS_RXACK_SHIFT) & OPENCORES_I2C_MASTER_STATUS_RXACK_MASK) {
printf("[WARNING] I2C operation failed in device select!\n");
i2c_op_failed = 1;
}
}
for (active_byte = 0; active_byte < data_length; active_byte++) {
if (!i2c_op_failed) {
*((volatile uint8_t*)(base_address + OPENCORES_I2C_MASTER_TX_RX)) = *(data + active_byte);
byte = OPENCORES_I2C_MASTER_CMD_WR_MASK << OPENCORES_I2C_MASTER_CMD_WR_SHIFT;
if ((active_byte + 1) == data_length) {
// Final byte
if (send_stop_signal) {
byte |= OPENCORES_I2C_MASTER_CMD_STO_MASK << OPENCORES_I2C_MASTER_CMD_STO_SHIFT;
}
}
*((volatile uint8_t*)(base_address + OPENCORES_I2C_MASTER_CMD_STATUS)) = byte;
i2c_op_timeout_counter = 0;
while ((*((volatile uint8_t*)(base_address + OPENCORES_I2C_MASTER_CMD_STATUS)) >> OPENCORES_I2C_MASTER_STATUS_TIP_SHIFT) & OPENCORES_I2C_MASTER_STATUS_TIP_MASK) {
if (i2c_op_timeout_counter > I2C_MASTER_OPERATION_TIMEOUT_VALUE) {
printf("[WARNING] I2C operation timed out in register write!\n");
i2c_op_failed = 1;
break;
}
usleep(100);
i2c_op_timeout_counter++;
}
}
if (!i2c_op_failed) {
if ((*((volatile uint8_t*)(base_address + OPENCORES_I2C_MASTER_CMD_STATUS)) >> OPENCORES_I2C_MASTER_STATUS_RXACK_SHIFT) & OPENCORES_I2C_MASTER_STATUS_RXACK_MASK) {
printf("[WARNING] I2C operation failed in register write!\n");
i2c_op_failed = 1;
}
}
if (i2c_op_failed) {
break;
}
}
return i2c_op_failed;
}
int read_i2c_data(uint8_t* base_address, uint8_t slave_address, uint8_t* data, int* data_length, int max_data_length, uint8_t send_stop_signal) {
uint32_t i2c_op_timeout_counter;
uint8_t i2c_op_failed;
int active_byte;
uint8_t byte;
i2c_op_failed = 0;
*((volatile uint8_t*)(base_address + OPENCORES_I2C_MASTER_TX_RX)) = (slave_address << 1) | (OPENCORES_I2C_MASTER_TX_RX_READ_MASK << OPENCORES_I2C_MASTER_TX_RX_READ_SHIFT);
*((volatile uint8_t*)(base_address + OPENCORES_I2C_MASTER_CMD_STATUS)) = (OPENCORES_I2C_MASTER_CMD_STA_MASK << OPENCORES_I2C_MASTER_CMD_STA_SHIFT) | (OPENCORES_I2C_MASTER_CMD_WR_MASK << OPENCORES_I2C_MASTER_CMD_WR_SHIFT);
i2c_op_timeout_counter = 0;
while ((*((volatile uint8_t*)(base_address + OPENCORES_I2C_MASTER_CMD_STATUS)) >> OPENCORES_I2C_MASTER_STATUS_TIP_SHIFT) & OPENCORES_I2C_MASTER_STATUS_TIP_MASK) {
if (i2c_op_timeout_counter > I2C_MASTER_OPERATION_TIMEOUT_VALUE) {
printf("[WARNING] I2C operation timed out in device select!\n");
i2c_op_failed = 1;
break;
}
usleep(100);
i2c_op_timeout_counter++;
}
if (!i2c_op_failed) {
if ((*((volatile uint8_t*)(base_address + OPENCORES_I2C_MASTER_CMD_STATUS)) >> OPENCORES_I2C_MASTER_STATUS_RXACK_SHIFT) & OPENCORES_I2C_MASTER_STATUS_RXACK_MASK) {
printf("[WARNING] I2C operation failed in device select!\n");
i2c_op_failed = 1;
}
}
if (data_length) {
*data_length = 0;
}
for (active_byte = 0; active_byte < max_data_length; active_byte++) {
if (!i2c_op_failed) {
if ((active_byte + 1) == max_data_length) {
// Final byte, send NACK
byte = (OPENCORES_I2C_MASTER_CMD_RD_MASK << OPENCORES_I2C_MASTER_CMD_RD_SHIFT) | (OPENCORES_I2C_MASTER_CMD_NACK_MASK << OPENCORES_I2C_MASTER_CMD_NACK_SHIFT);
if (send_stop_signal) {
byte |= OPENCORES_I2C_MASTER_CMD_STO_MASK << OPENCORES_I2C_MASTER_CMD_STO_SHIFT;
}
*((volatile uint8_t*)(base_address + OPENCORES_I2C_MASTER_CMD_STATUS)) = byte;
}
else {
// More bytes expected, send ACK
*((volatile uint8_t*)(base_address + OPENCORES_I2C_MASTER_CMD_STATUS)) = (OPENCORES_I2C_MASTER_CMD_RD_MASK << OPENCORES_I2C_MASTER_CMD_RD_SHIFT) | (OPENCORES_I2C_MASTER_CMD_ACK_MASK << OPENCORES_I2C_MASTER_CMD_ACK_SHIFT);
}
while ((*((volatile uint8_t*)(base_address + OPENCORES_I2C_MASTER_CMD_STATUS)) >> OPENCORES_I2C_MASTER_STATUS_TIP_SHIFT) & OPENCORES_I2C_MASTER_STATUS_TIP_MASK) {
if (i2c_op_timeout_counter > I2C_MASTER_OPERATION_TIMEOUT_VALUE) {
printf("[WARNING] I2C operation timed out in register read!\n");
i2c_op_failed = 1;
break;
}
usleep(100);
i2c_op_timeout_counter++;
}
if (!i2c_op_failed) {
*(data + active_byte) = *((volatile uint8_t*)(base_address + OPENCORES_I2C_MASTER_TX_RX));
if (data_length) {
*data_length = *data_length + 1;
}
}
}
if (i2c_op_failed) {
break;
}
}
return i2c_op_failed;
}
uint8_t i2c_read_register_byte(uint8_t* base_address, uint8_t slave_address, uint8_t slave_register, int* error) {
uint8_t retval = 0xff;
uint8_t byte;
if (error) {
*error = -1;
}
if (!write_i2c_data(base_address, slave_address, &slave_register, 1, 0)) {
if (!read_i2c_data(base_address, slave_address, &byte, NULL, 1, 1)) {
retval = byte;
if (error) {
*error = 0;
}
}
}
return retval;
}
int i2c_write_register_byte(uint8_t* base_address, uint8_t slave_address, uint8_t slave_register, uint8_t data) {
uint8_t tx_data[2];
// Assemble TX data structure
tx_data[0] = slave_register;
tx_data[1] = data;
if (!write_i2c_data(base_address, slave_address, tx_data, 2, 1)) {
return 0;
}
return 1;
}
\ No newline at end of file
// © 2020 Raptor Engineering, LLC
//
// Released under the terms of the AGPL v3
// See the LICENSE file for full details
#ifndef _OPENCORES_I2C_H
#define _OPENCORES_I2C_H
#define OPENCORES_I2C_MASTER_DEVICE_ID_LOW 0x0
#define OPENCORES_I2C_MASTER_DEVICE_ID_HIGH 0x4
#define OPENCORES_I2C_MASTER_DEVICE_VERSION 0x8
#define OPENCORES_I2C_MASTER_PRESCALE_LOW 0x10
#define OPENCORES_I2C_MASTER_PRESCALE_HIGH 0x11
#define OPENCORES_I2C_MASTER_PRESCALE_CTL 0x12
#define OPENCORES_I2C_MASTER_TX_RX 0x13
#define OPENCORES_I2C_MASTER_CMD_STATUS 0x14
#define OPENCORES_I2C_DEVICE_ID_HIGH 0x4932434d
#define OPENCORES_I2C_DEVICE_ID_LOW 0x4f504e43
#define OPENCORES_I2C_VERSION_MAJOR_MASK 0xffff
#define OPENCORES_I2C_VERSION_MAJOR_SHIFT 16
#define OPENCORES_I2C_VERSION_MINOR_MASK 0xff
#define OPENCORES_I2C_VERSION_MINOR_SHIFT 8
#define OPENCORES_I2C_VERSION_PATCH_MASK 0xff
#define OPENCORES_I2C_VERSION_PATCH_SHIFT 0
#define OPENCORES_I2C_MASTER_CTL_CORE_EN_MASK 0x1
#define OPENCORES_I2C_MASTER_CTL_CORE_EN_SHIFT 7
#define OPENCORES_I2C_MASTER_CTL_IRQ_EN_MASK 0x1
#define OPENCORES_I2C_MASTER_CTL_IRQ_EN_SHIFT 6
#define OPENCORES_I2C_MASTER_CMD_STA_MASK 0x1
#define OPENCORES_I2C_MASTER_CMD_STA_SHIFT 7
#define OPENCORES_I2C_MASTER_CMD_STO_MASK 0x1
#define OPENCORES_I2C_MASTER_CMD_STO_SHIFT 6
#define OPENCORES_I2C_MASTER_CMD_RD_MASK 0x1
#define OPENCORES_I2C_MASTER_CMD_RD_SHIFT 5
#define OPENCORES_I2C_MASTER_CMD_WR_MASK 0x1
#define OPENCORES_I2C_MASTER_CMD_WR_SHIFT 4
#define OPENCORES_I2C_MASTER_CMD_ACK_MASK 0x0
#define OPENCORES_I2C_MASTER_CMD_ACK_SHIFT 3
#define OPENCORES_I2C_MASTER_CMD_NACK_MASK 0x1
#define OPENCORES_I2C_MASTER_CMD_NACK_SHIFT 3
#define OPENCORES_I2C_MASTER_CMD_IACK_MASK 0x1
#define OPENCORES_I2C_MASTER_CMD_IACK_SHIFT 0
#define OPENCORES_I2C_MASTER_STATUS_RXACK_MASK 0x1
#define OPENCORES_I2C_MASTER_STATUS_RXACK_SHIFT 7
#define OPENCORES_I2C_MASTER_STATUS_BUSY_MASK 0x1
#define OPENCORES_I2C_MASTER_STATUS_BUSY_SHIFT 6
#define OPENCORES_I2C_MASTER_STATUS_ARBL_MASK 0x1
#define OPENCORES_I2C_MASTER_STATUS_ARBL_SHIFT 5
#define OPENCORES_I2C_MASTER_STATUS_TIP_MASK 0x1
#define OPENCORES_I2C_MASTER_STATUS_TIP_SHIFT 1
#define OPENCORES_I2C_MASTER_STATUS_IRQP_MASK 0x1
#define OPENCORES_I2C_MASTER_STATUS_IRQP_SHIFT 0
#define OPENCORES_I2C_MASTER_TX_RX_WRITE_MASK 0x0
#define OPENCORES_I2C_MASTER_TX_RX_WRITE_SHIFT 0
#define OPENCORES_I2C_MASTER_TX_RX_READ_MASK 0x1
#define OPENCORES_I2C_MASTER_TX_RX_READ_SHIFT 0
#define I2C_MASTER_4_ADDR 0xc0010000L
#define I2C_MASTER_OPERATION_TIMEOUT_VALUE 10000
int initialize_i2c_master(uint8_t* base_address, int i2c_bus_frequency);
int write_i2c_data(uint8_t* base_address, uint8_t slave_address, uint8_t* data, int data_length, uint8_t send_stop_signal);
int read_i2c_data(uint8_t* base_address, uint8_t slave_address, uint8_t* data, int* data_length, int max_data_length, uint8_t send_stop_signal);
uint8_t i2c_read_register_byte(uint8_t* base_address, uint8_t slave_address, uint8_t slave_register, int* error);
int i2c_write_register_byte(uint8_t* base_address, uint8_t slave_address, uint8_t slave_register, uint8_t data);
#endif // _OPENCORES_I2C_H
\ No newline at end of file
......@@ -3,6 +3,29 @@
// Released under the terms of the AGPL v3
// See the LICENSE file for full details
#define TERCEL_SPI_REG_DEVICE_ID_HIGH 0x0
#define TERCEL_SPI_REG_DEVICE_ID_LOW 0x4
#define TERCEL_SPI_REG_DEVICE_VERSION 0x8
#define TERCEL_SPI_REG_SYS_CLK_FREQ 0xc
#define TERCEL_SPI_REG_SYS_PHY_CFG1 0x10
#define TERCEL_SPI_REG_SYS_FLASH_CFG1 0x14
#define TERCEL_SPI_REG_SYS_FLASH_CFG2 0x18
#define TERCEL_SPI_REG_SYS_FLASH_CFG3 0x1c
#define TERCEL_SPI_REG_SYS_FLASH_CFG4 0x20
#define TERCEL_SPI_REG_SYS_FLASH_CFG5 0x24
#define TERCEL_SPI_REG_SYS_CORE_CTL1 0x28
#define TERCEL_SPI_REG_SYS_CORE_DATA1 0x2c
#define TERCEL_SPI_DEVICE_ID_HIGH 0x7c525054
#define TERCEL_SPI_DEVICE_ID_LOW 0x5350494d
#define TERCEL_SPI_VERSION_MAJOR_MASK 0xffff
#define TERCEL_SPI_VERSION_MAJOR_SHIFT 16
#define TERCEL_SPI_VERSION_MINOR_MASK 0xff
#define TERCEL_SPI_VERSION_MINOR_SHIFT 8
#define TERCEL_SPI_VERSION_PATCH_MASK 0xff
#define TERCEL_SPI_VERSION_PATCH_SHIFT 0
#define TERCEL_SPI_ENABLE_USER_MODE_MASK 0x1
#define TERCEL_SPI_ENABLE_USER_MODE_SHIFT 0x0
#define TERCEL_SPI_PHY_DUMMY_CYCLES_MASK 0xff
......@@ -15,6 +38,10 @@
#define TERCEL_SPI_PHY_4BA_ENABLE_SHIFT 18
#define TERCEL_SPI_PHY_FAST_READ_ENABLE_MASK 0x1
#define TERCEL_SPI_PHY_FAST_READ_ENABLE_SHIFT 19
#define TERCEL_SPI_PHY_QSPI_EXT_READ_EN_MASK 0x1
#define TERCEL_SPI_PHY_QSPI_EXT_READ_EN_SHIFT 20
#define TERCEL_SPI_PHY_QSPI_EXT_WRITE_EN_MASK 0x1
#define TERCEL_SPI_PHY_QSPI_EXT_WRITE_EN_SHIFT 21
#define TERCEL_SPI_PHY_CS_EXTRA_IDLE_CYC_MASK 0xff
#define TERCEL_SPI_PHY_CS_EXTRA_IDLE_CYC_SHIFT 24
#define TERCEL_SPI_FLASH_EN_MULTCYC_WRITE_MASK 0x1
......@@ -24,8 +51,25 @@
#define TERCEL_SPI_FLASH_CS_EN_LIMIT_CYC_MASK 0xffffffff
#define TERCEL_SPI_FLASH_CS_EN_LIMIT_CYC_SHIFT 0
#define TERCEL_SPI_3BA_SPI_CMD_MASK 0xff
#define TERCEL_SPI_3BA_SPI_CMD_SHIFT 0
#define TERCEL_SPI_4BA_SPI_CMD_MASK 0xff
#define TERCEL_SPI_4BA_SPI_CMD_SHIFT 8
#define TERCEL_SPI_3BA_QSPI_CMD_MASK 0xff
#define TERCEL_SPI_3BA_QSPI_CMD_SHIFT 16
#define TERCEL_SPI_4BA_QSPI_CMD_MASK 0xff
#define TERCEL_SPI_4BA_QSPI_CMD_SHIFT 24
#define TERCEL_SPI_PHY_IO_TYPE_SINGLE 0x0
#define TERCEL_SPI_PHY_IO_TYPE_QUAD 0x2
#define TERCEL_SPI_PHY_3BA_MODE 0x0
#define TERCEL_SPI_PHY_4BA_MODE 0x1
static inline uint32_t read_tercel_register(unsigned long base_address, uint8_t reg) {
return *((volatile uint32_t*)(base_address + reg));
}
static inline void write_tercel_register(unsigned long base_address, uint8_t reg, uint32_t data) {
*((volatile uint32_t*)(base_address + reg)) = data;
}
\ No newline at end of file
// © 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 <limits.h>
#include <generated/soc.h>
#define TICKS_PER_US (CONFIG_CLOCK_FREQUENCY / 1000000LL)
#include "utility.h"
static __inline__ unsigned long long rdtsc(void)
{
unsigned long long int tsc;
unsigned long int high;
unsigned long int low;
unsigned long int scratch;
__asm__ volatile(
"0: \n"
"\tmftbu %0 \n"
"\tmftb %1 \n"
"\tmftbu %2 \n"
"\tcmpw %2,%0 \n"
"\tbne 0b \n"
: "=r"(high), "=r"(low), "=r"(scratch)
);
tsc = high << 32;
tsc |= low;
return tsc;
}
void usleep(int usecs) {
unsigned long long start_tsc;
unsigned long long current_tsc;
unsigned long long offset;
offset = 0;
start_tsc = rdtsc();
while (1) {
current_tsc = rdtsc();
if (current_tsc < start_tsc) {
offset = ULONG_MAX - start_tsc;
start_tsc = 0;
}
if (((current_tsc - start_tsc) + offset) >= (TICKS_PER_US * usecs)) {
break;
}
}
}
\ No newline at end of file
// © 2020 Raptor Engineering, LLC
//
// Released under the terms of the AGPL v3
// See the LICENSE file for full details
#ifndef _UTILITY_H
#define _UTILITY_H
void usleep(int usecs);
#endif // _UTILITY_H
\ No newline at end of file
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