Initial port of bare metal firmware to Zephyr

Tested to properly IPL and allow console interaction
with the host over the Zephyr UART shell.
parent a2b9c12f
# SPDX-License-Identifier: GPL-3.0-only
SET(FPGA_BUILD_DIR "${CMAKE_CURRENT_SOURCE_DIR}/bootrom/fpga/release"
CACHE PATH
"Path to the FPGA build folder from the litex-boards repo: <litex-boards-repo>/litex_boards/targets/build/versa_ecp5")
cmake_minimum_required(VERSION 3.13.1)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
# # Default include for all subprojects
include_directories(${FPGA_BUILD_DIR}/software/include)
include_directories(include)
project(kestrel_module)
target_sources(app PRIVATE
src/zephyr.c
src/shell.c
src/opencores_i2c.c
src/fsi.c
src/kestrel.c
src/direct_uart.c
)
# Config options for Kestrel main application
# Copyright (c) 2021 Raptor Engineering, LLC <sales@raptorengineering.com>
# SPDX-License-Identifier: GPL-3.0-only
source "Kconfig.zephyr"
Selected files from the bootrom repository
The bootrom repository cannot be directly included due to a conflict between the Zephyr irq.h and the bootrom irq.h files
#ifndef __HW_COMMON_H
#define __HW_COMMON_H
#include <stdint.h>
#include <system.h>
/* To overwrite CSR subregister accessors, define extern, non-inlined versions
* of csr_[read|write]_simple(), and define CSR_ACCESSORS_DEFINED.
*/
#ifndef CSR_ACCESSORS_DEFINED
#define CSR_ACCESSORS_DEFINED
#ifdef __ASSEMBLER__
#define MMPTR(x) x
#else /* ! __ASSEMBLER__ */
/* CSRs are stored in subregister slices of CONFIG_CSR_DATA_WIDTH (native
* endianness), with the least significant slice at the lowest aligned
* (base) address. */
#include <generated/soc.h>
#if !defined(CONFIG_CSR_DATA_WIDTH)
#error CSR_DATA_WIDTH MUST be set before including this file!
#endif
/* CSR subregisters (a.k.a. "simple CSRs") are embedded inside uint32_t
* aligned locations: */
#define MMPTR(a) (*((volatile uint32_t *)(a)))
static inline void csr_write_simple(unsigned long v, unsigned long a)
{
MMPTR(a) = v;
}
static inline unsigned long csr_read_simple(unsigned long a)
{
return MMPTR(a);
}
#endif /* ! __ASSEMBLER__ */
#endif /* ! CSR_ACCESSORS_DEFINED */
/* CSR data width (subreg. width) in bytes, for direct comparson to sizeof() */
#define CSR_DW_BYTES (CONFIG_CSR_DATA_WIDTH/8)
#define CSR_OFFSET_BYTES 4
#ifndef __ASSEMBLER__
/* Number of subregs required for various total byte sizes, by subreg width:
* NOTE: 1, 2, 4, and 8 bytes represent uint[8|16|32|64]_t C types; However,
* CSRs of intermediate byte sizes (24, 40, 48, and 56) are NOT padded
* (with extra unallocated subregisters) to the next valid C type!
* +-----+-----------------+
* | csr | bytes |
* | _dw | 1 2 3 4 5 6 7 8 |
* | |-----=---=-=-=---|
* | 1 | 1 2 3 4 5 6 7 8 |
* | 2 | 1 1 2 2 3 3 4 4 |
* | 4 | 1 1 1 1 2 2 2 2 |
* | 8 | 1 1 1 1 1 1 1 1 |
* +-----+-----------------+ */
static inline int num_subregs(int csr_bytes)
{
return (csr_bytes - 1) / CSR_DW_BYTES + 1;
}
/* Read a CSR of size 'csr_bytes' located at address 'a'. */
static inline uint64_t _csr_rd(unsigned long a, int csr_bytes)
{
uint64_t r = csr_read_simple(a);
for (int i = 1; i < num_subregs(csr_bytes); i++) {
r <<= CONFIG_CSR_DATA_WIDTH;
a += CSR_OFFSET_BYTES;
r |= csr_read_simple(a);
}
return r;
}
/* Write value 'v' to a CSR of size 'csr_bytes' located at address 'a'. */
static inline void _csr_wr(unsigned long a, uint64_t v, int csr_bytes)
{
int ns = num_subregs(csr_bytes);
for (int i = 0; i < ns; i++) {
csr_write_simple(v >> (CONFIG_CSR_DATA_WIDTH * (ns - 1 - i)), a);
a += CSR_OFFSET_BYTES;
}
}
// FIXME: - should we provide 24, 40, 48, and 56 bit csr_[rd|wr] methods?
static inline uint8_t csr_rd_uint8(unsigned long a)
{
return _csr_rd(a, sizeof(uint8_t));
}
static inline void csr_wr_uint8(uint8_t v, unsigned long a)
{
_csr_wr(a, v, sizeof(uint8_t));
}
static inline uint16_t csr_rd_uint16(unsigned long a)
{
return _csr_rd(a, sizeof(uint16_t));
}
static inline void csr_wr_uint16(uint16_t v, unsigned long a)
{
_csr_wr(a, v, sizeof(uint16_t));
}
static inline uint32_t csr_rd_uint32(unsigned long a)
{
return _csr_rd(a, sizeof(uint32_t));
}
static inline void csr_wr_uint32(uint32_t v, unsigned long a)
{
_csr_wr(a, v, sizeof(uint32_t));
}
static inline uint64_t csr_rd_uint64(unsigned long a)
{
return _csr_rd(a, sizeof(uint64_t));
}
static inline void csr_wr_uint64(uint64_t v, unsigned long a)
{
_csr_wr(a, v, sizeof(uint64_t));
}
/* Read a CSR located at address 'a' into an array 'buf' of 'cnt' elements.
*
* NOTE: Since CSR_DW_BYTES is a constant here, we might be tempted to further
* optimize things by leaving out one or the other of the if() branches below,
* depending on each unsigned type width;
* However, this code is also meant to serve as a reference for how CSRs are
* to be manipulated by other programs (e.g., an OS kernel), which may benefit
* from dynamically handling multiple possible CSR subregister data widths
* (e.g., by passing a value in through the Device Tree).
* Ultimately, if CSR_DW_BYTES is indeed a constant, the compiler should be
* able to determine on its own whether it can automatically optimize away one
* of the if() branches! */
#define _csr_rd_buf(a, buf, cnt) \
{ \
int i, j, nsubs, n_sub_elem; \
uint64_t r; \
if (sizeof(buf[0]) >= CSR_DW_BYTES) { \
/* one or more subregisters per element */ \
for (i = 0; i < cnt; i++) { \
buf[i] = _csr_rd(a, sizeof(buf[0])); \
a += CSR_OFFSET_BYTES * num_subregs(sizeof(buf[0])); \
} \
} else { \
/* multiple elements per subregister (2, 4, or 8) */ \
nsubs = num_subregs(sizeof(buf[0]) * cnt); \
n_sub_elem = CSR_DW_BYTES / sizeof(buf[0]); \
for (i = 0; i < nsubs; i++) { \
r = csr_read_simple(a); \
for (j = n_sub_elem - 1; j >= 0; j--) { \
if (i * n_sub_elem + j < cnt) \
buf[i * n_sub_elem + j] = r; \
r >>= sizeof(buf[0]) * 8; \
} \
a += CSR_OFFSET_BYTES; \
} \
} \
}
/* Write an array 'buf' of 'cnt' elements to a CSR located at address 'a'.
*
* NOTE: The same optimization considerations apply here as with _csr_rd_buf()
* above.
*/
#define _csr_wr_buf(a, buf, cnt) \
{ \
int i, j, nsubs, n_sub_elem; \
uint64_t v; \
if (sizeof(buf[0]) >= CSR_DW_BYTES) { \
/* one or more subregisters per element */ \
for (i = 0; i < cnt; i++) { \
_csr_wr(a, buf[i], sizeof(buf[0])); \
a += CSR_OFFSET_BYTES * num_subregs(sizeof(buf[0])); \
} \
} else { \
/* multiple elements per subregister (2, 4, or 8) */ \
nsubs = num_subregs(sizeof(buf[0]) * cnt); \
n_sub_elem = CSR_DW_BYTES / sizeof(buf[0]); \
for (i = 0; i < nsubs; i++) { \
v = buf[i * n_sub_elem + 0]; \
for (j = 1; j < n_sub_elem; j++) { \
if (i * n_sub_elem + j == cnt) \
break; \
v <<= sizeof(buf[0]) * 8; \
v |= buf[i * n_sub_elem + j]; \
} \
csr_write_simple(v, a); \
a += CSR_OFFSET_BYTES; \
} \
} \
}
static inline void csr_rd_buf_uint8(unsigned long a, uint8_t *buf, int cnt)
{
_csr_rd_buf(a, buf, cnt);
}
static inline void csr_wr_buf_uint8(unsigned long a,
const uint8_t *buf, int cnt)
{
_csr_wr_buf(a, buf, cnt);
}
static inline void csr_rd_buf_uint16(unsigned long a, uint16_t *buf, int cnt)
{
_csr_rd_buf(a, buf, cnt);
}
static inline void csr_wr_buf_uint16(unsigned long a,
const uint16_t *buf, int cnt)
{
_csr_wr_buf(a, buf, cnt);
}
static inline void csr_rd_buf_uint32(unsigned long a, uint32_t *buf, int cnt)
{
_csr_rd_buf(a, buf, cnt);
}
static inline void csr_wr_buf_uint32(unsigned long a,
const uint32_t *buf, int cnt)
{
_csr_wr_buf(a, buf, cnt);
}
/* NOTE: the macros' "else" branch is unreachable, no need to be warned
* about a >= 64bit left shift! */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshift-count-overflow"
static inline void csr_rd_buf_uint64(unsigned long a, uint64_t *buf, int cnt)
{
_csr_rd_buf(a, buf, cnt);
}
static inline void csr_wr_buf_uint64(unsigned long a,
const uint64_t *buf, int cnt)
{
_csr_wr_buf(a, buf, cnt);
}
#pragma GCC diagnostic pop
#endif /* ! __ASSEMBLER__ */
#endif /* __HW_COMMON_H */
#ifndef __SYSTEM_H
#define __SYSTEM_H
#ifdef __cplusplus
extern "C" {
#endif
static inline void flush_cpu_icache(void)
{
__asm__ volatile ("icbi 0,0; isync" : : : "memory");
}
static inline void flush_cpu_dcache(void)
{
/* FIXME: do something useful here! */
}; //lint !e19
void flush_l2_cache(void);
void busy_wait(unsigned int ms);
#ifdef __cplusplus
}
#endif
#endif /* __SYSTEM_H */
kestrel:
name: Kestrel main application
common:
integration_platforms:
- native_posix
# Gemeral configuration
CONFIG_PRINTK=y
CONFIG_SHELL=y
CONFIG_LOG=y
CONFIG_NET_LOG=y
CONFIG_INIT_STACKS=y
CONFIG_THREAD_STACK_INFO=y
CONFIG_KERNEL_SHELL=y
CONFIG_THREAD_MONITOR=y
CONFIG_THREAD_NAME=y
CONFIG_DEVICE_SHELL=y
CONFIG_POSIX_CLOCK=y
CONFIG_DATE_SHELL=y
CONFIG_NET_SHELL=y
CONFIG_SHELL_CMDS_SELECT=y
CONFIG_SHELL_BACKEND_SERIAL=y
CONFIG_SHELL_BACKEND_TELNET=y
CONFIG_THREAD_RUNTIME_STATS=y
CONFIG_THREAD_RUNTIME_STATS_USE_TIMING_FUNCTIONS=y
# Kestrel specific configuration
CONFIG_NET_TC_THREAD_PREEMPTIVE=n
# Kernel options
CONFIG_TEST_RANDOM_GENERATOR=y
CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE=100663296
# Logging settings
CONFIG_LOG_MODE_IMMEDIATE=y
CONFIG_LOG_RUNTIME_FILTERING=y
CONFIG_LOG_BUFFER_SIZE=1024
CONFIG_LOG_PRINTK=y
CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD=0
# POSIX options
CONFIG_POSIX_MAX_FDS=20
# Networking config
CONFIG_NETWORKING=y
CONFIG_NET_IPV4=y
CONFIG_NET_IPV6=y
CONFIG_NET_TCP=y
CONFIG_NET_UDP=y
CONFIG_NET_SOCKETS=y
CONFIG_NET_SOCKETS_POSIX_NAMES=y
CONFIG_NET_MAX_CONN=20
CONFIG_NET_MAX_CONTEXTS=20
CONFIG_NET_STATISTICS=y
CONFIG_NET_CONNECTION_MANAGER=y
CONFIG_NET_MGMT=y
CONFIG_NET_MGMT_EVENT=y
# Network buffers
CONFIG_NET_PKT_RX_COUNT=96
CONFIG_NET_PKT_TX_COUNT=96
CONFIG_NET_BUF_RX_COUNT=128
CONFIG_NET_BUF_TX_COUNT=128
CONFIG_NET_CONTEXT_NET_PKT_POOL=y
CONFIG_NET_BUF_POOL_USAGE=y
# IP address options
CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3
CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4
# Network address config
CONFIG_NET_CONFIG_SETTINGS=y
CONFIG_NET_CONFIG_NEED_IPV4=y
CONFIG_NET_CONFIG_NEED_IPV6=y
CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1"
CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8::2"
CONFIG_NET_DHCPV4=y
# This is needed so that the sample app can respond to queries
# as fast as possible.
CONFIG_NET_TCP_TIME_WAIT_DELAY=0
......@@ -107,8 +107,9 @@
#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_STATUS_CYCLE_TYPE_IO 0
#define AQUILA_LPC_STATUS_CYCLE_TYPE_TPM 1
#define AQUILA_LPC_STATUS_CYCLE_TYPE_FW 2
#define AQUILA_LPC_VUART1_FIFO_EMPTY 0x00000100
#define AQUILA_LPC_VUART2_FIFO_EMPTY 0x01000000
......@@ -123,10 +124,14 @@
#define AQUILA_LPC_VUART1_FIFO_READ_MASK 0xff
#define AQUILA_LPC_VUART1_FIFO_READ_SHIFT 0
#define AQUILA_LPC_VUART2_FIFO_READ_MASK 0xff
#define AQUILA_LPC_VUART2_FIFO_READ_SHIFT 16
#define AQUILA_LPC_VUART_BLOCK_OFFSET 0xe00000
#define AQUILA_LPC_VUART1_STATUS_REG 0x4
#define AQUILA_LPC_VUART1_CONTROL_REG 0x8
#define AQUILA_LPC_VUART2_STATUS_REG 0xc
#define AQUILA_LPC_VUART2_CONTROL_REG 0x10
#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
......
/*
* Copyright (c) 2019 Michael Neuling <mikey@neuling.org>
* Copyright (c) 2019 Anton Blanchard <anton@linux.ibm.com>
* Copyright (c) 2021 Raptor Engineering, LLC <sales@raptorengineering.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* This file contains a very minimal direct-mode driver for the LiteX UART
* present on Kestrel systems. It is primarily useful for debugging.
*/
#include <stddef.h>
#include <stdint.h>
/*
* Core UART functions to implement for a port
*/
#define UART_BASE 0xc0002000
#define POTATO_CONSOLE_RXTX 0x00
#define POTATO_CONSOLE_STATUS_TX_FULL 0x04
#define POTATO_CONSOLE_STATUS_RX_EMPTY 0x08
#define POTATO_CONSOLE_EV_PENDING 0x10
#define POTATO_CONSOLE_EV_RX (1 << 1)
static uint8_t potato_uart_reg_read(int offset)
{
uint64_t addr;
uint8_t val;
addr = UART_BASE + offset;
val = *(volatile uint8_t *)addr;
return val;
}
static void potato_uart_reg_write(int offset, uint8_t val)
{
uint64_t addr;
addr = UART_BASE + offset;
*(volatile uint8_t *)addr = val;
}
static int potato_uart_rx_empty(void)
{
uint8_t val;
val = potato_uart_reg_read(POTATO_CONSOLE_STATUS_RX_EMPTY);
if (val)
return 1;
return 0;
}
static int potato_uart_tx_full(void)
{
uint8_t val;
val = potato_uart_reg_read(POTATO_CONSOLE_STATUS_TX_FULL);
if (val)
return 1;
return 0;
}
static char potato_uart_read(void)
{
uint8_t val;
val = potato_uart_reg_read(POTATO_CONSOLE_RXTX);
potato_uart_reg_write(POTATO_CONSOLE_EV_PENDING, POTATO_CONSOLE_EV_RX);
return (char)val;
}
static void potato_uart_write(char c)
{
uint8_t val;
val = c;
potato_uart_reg_write(POTATO_CONSOLE_RXTX, val);
}
int direct_serial_getchar(void)
{
if (potato_uart_rx_empty())
return -1;
return potato_uart_read();
}
void direct_serial_putchar(unsigned char c)
{
while (potato_uart_tx_full())
/* Do Nothing */;
potato_uart_write(c);
}
\ No newline at end of file
......@@ -3,6 +3,9 @@
// Released under the terms of the GPL v3
// See the LICENSE file for full details
#include <logging/log.h>
LOG_MODULE_REGISTER(kestrel_fsi, LOG_LEVEL_DBG);
#include "fsi.h"
#include <generated/mem.h>
......@@ -36,6 +39,8 @@
// Platform data
#define IBM_POWER9_SLAVE_ID 0
#define KESTREL_LOG(...) LOG_INF(__VA_ARGS__)
static int check_device_id(void)
{
uint32_t devid_high = read_openfsi_register(OPENFSIMASTER_BASE, FSI_MASTER_REG_DEVICE_ID_HIGH);
......@@ -46,7 +51,7 @@ static int check_device_id(void)
return 0;
}
printf("Raptor OpenFSI master not found!\n");
KESTREL_LOG("Raptor OpenFSI master not found!");
return -1;
}
......@@ -104,14 +109,14 @@ static int access_fsi_mem(uint8_t slave_id, uint32_t address, fsi_data_length_t
}
#ifdef DEBUG
printf("%s(): address 0x%06x, data: 0x%08x sta: 0x%08x\n", __FUNCTION__, address, *data, word);
KESTREL_LOG("%s(): address 0x%06x, data: 0x%08x sta: 0x%08x", __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",
KESTREL_LOG("[WARNING] FSI master returned error code %d on access to FSI "
"address 0x%06x",
status_code, address);
#endif
if (!ret)
......@@ -167,7 +172,7 @@ static int initialize_fsi_master(void)
write_openfsi_register(OPENFSIMASTER_BASE, FSI_MASTER_REG_CONTROL, word);
#ifdef DEBUG
printf("%s(): after setup: ctl 0x%08x, sta 0x%08x\n", __FUNCTION__, read_openfsi_register(OPENFSIMASTER_BASE, FSI_MASTER_REG_CONTROL),
KESTREL_LOG("%s(): after setup: ctl 0x%08x, sta 0x%08x", __FUNCTION__, read_openfsi_register(OPENFSIMASTER_BASE, FSI_MASTER_REG_CONTROL),
read_openfsi_register(OPENFSIMASTER_BASE, FSI_MASTER_REG_STATUS));
#endif
......@@ -256,11 +261,11 @@ int start_ipl(int side)
if ((side < 0) || (side > 1))
{
printf("Invalid side %d specified\n", side);
KESTREL_LOG("Invalid side %d specified", side);
return -2;
}
printf("Starting IPL on side %d\n", side);
KESTREL_LOG("Starting IPL on side %d", side);
if (run_pre_ipl_fixups())
{
......@@ -348,7 +353,7 @@ int start_ipl(int side)
return 0;
fail:
printf("IPL failed!\n");
KESTREL_LOG("IPL failed!");
return -1;
}
......@@ -362,7 +367,7 @@ int get_sbe_status(void)
goto fail;
}
printf("CFAM 0x%06x: 0x%08x\n", IBM_POWER9_SBE_MSG_REGISTER, word);
KESTREL_LOG("CFAM 0x%06x: 0x%08x", 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))
......@@ -370,11 +375,11 @@ int get_sbe_status(void)
goto fail;
}
printf("CFAM 0x%06x: 0x%08x\n", IBM_POWER9_HB_MBX5_REG, word);
KESTREL_LOG("CFAM 0x%06x: 0x%08x", IBM_POWER9_HB_MBX5_REG, word);
return 0;
fail:
printf("Processor not responding!\n");
KESTREL_LOG("Processor not responding!");
return -1;
}
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -3,6 +3,9 @@
// Released under the terms of the GPL v3
// See the LICENSE file for full details
#include <logging/log.h>
LOG_MODULE_REGISTER(kestrel_i2c, LOG_LEVEL_DBG);
#include "opencores_i2c.h"
#include "utility.h"
......@@ -13,9 +16,11 @@
#include <stdio.h>
#include <stdlib.h>
#define KESTREL_LOG(...) LOG_INF(__VA_ARGS__)
int initialize_i2c_master(uint8_t *base_address, int i2c_bus_frequency)
{
printf("Configuring I2C master at address %p...\n", base_address);
KESTREL_LOG("Configuring I2C master at address %p...", 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))
......@@ -23,22 +28,22 @@ int initialize_i2c_master(uint8_t *base_address, int i2c_bus_frequency)
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",
KESTREL_LOG("OpenCores I2C master found, device version %0d.%0d.%d",
(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",
KESTREL_LOG("Desired prescale register: 0x%04x (system clock %dMHz, bus frequency "
"%dkHz)",
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);
KESTREL_LOG("Enabling I2C core", 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);
......@@ -66,7 +71,7 @@ int write_i2c_data(uint8_t *base_address, uint8_t slave_address, uint8_t *data,
{
if (i2c_op_timeout_counter > I2C_MASTER_OPERATION_TIMEOUT_VALUE)
{
printf("[WARNING] I2C operation timed out in device select!\n");
KESTREL_LOG("[WARNING] I2C operation timed out in device select!");
i2c_op_failed = 1;
break;
}
......@@ -79,7 +84,7 @@ int write_i2c_data(uint8_t *base_address, uint8_t slave_address, uint8_t *data,
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");
KESTREL_LOG("[WARNING] I2C operation failed in device select!");
i2c_op_failed = 1;
}
}
......@@ -105,7 +110,7 @@ int write_i2c_data(uint8_t *base_address, uint8_t slave_address, uint8_t *data,
{
if (i2c_op_timeout_counter > I2C_MASTER_OPERATION_TIMEOUT_VALUE)
{
printf("[WARNING] I2C operation timed out in register write!\n");
KESTREL_LOG("[WARNING] I2C operation timed out in register write!");
i2c_op_failed = 1;
break;
}
......@@ -119,7 +124,7 @@ int write_i2c_data(uint8_t *base_address, uint8_t slave_address, uint8_t *data,
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");
KESTREL_LOG("[WARNING] I2C operation failed in register write!");
i2c_op_failed = 1;
}
}
......@@ -151,7 +156,7 @@ int read_i2c_data(uint8_t *base_address, uint8_t slave_address, uint8_t *data, i
{
if (i2c_op_timeout_counter > I2C_MASTER_OPERATION_TIMEOUT_VALUE)
{
printf("[WARNING] I2C operation timed out in device select!\n");
KESTREL_LOG("[WARNING] I2C operation timed out in device select!");
i2c_op_failed = 1;
break;
}
......@@ -164,7 +169,7 @@ int read_i2c_data(uint8_t *base_address, uint8_t slave_address, uint8_t *data, i
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");
KESTREL_LOG("[WARNING] I2C operation failed in device select!");
i2c_op_failed = 1;
}
}
......@@ -200,7 +205,7 @@ int read_i2c_data(uint8_t *base_address, uint8_t slave_address, uint8_t *data, i
{
if (i2c_op_timeout_counter > I2C_MASTER_OPERATION_TIMEOUT_VALUE)
{
printf("[WARNING] I2C operation timed out in register read!\n");
KESTREL_LOG("[WARNING] I2C operation timed out in register read!");
i2c_op_failed = 1;
break;
}
......
// © 2020 - 2021 Raptor Engineering, LLC
//
// Released under the terms of the GPL v3