blob: ad71af827243e02892fb6b7438e70e85c0ca579b [file] [log] [blame]
// SPDX-License-Identifier: BSD-2-Clause
/*
* Copyright 2019 Broadcom.
*/
#include <drivers/bcm/bnxt.h>
#include <initcall.h>
#include <io.h>
#include <kernel/delay.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#define BNXT_REG_CTRL_BASE 0x3040000
#define BNXT_REG_ECO_RESERVED 0x3042400
#define BNXT_FLASH_ACCESS_DONE_BIT 2
#define NIC400_BNXT_IDM_IO_CONTROL_DIRECT 0x60e00408
#define BNXT_INDIRECT_BASE 0x60800000
#define BNXT_INDIRECT_ADDR_MASK 0x3fffffu
#define BNXT_INDIRECT_BASE_MASK (~BNXT_INDIRECT_ADDR_MASK)
#define BNXT_INDIRECT_WINDOW_SIZE (BNXT_INDIRECT_ADDR_MASK + 1)
#define BNXT_REG_CTRL_BPE_MODE_REG 0x0
#define BNXT_REG_CTRL_BPE_MODE_FASTBOOT_MODE_BIT 2
#define BNXT_REG_CTRL_BPE_MODE_CM3_RST_BIT 1
#define BNXT_REG_CTRL_BPE_STAT_REG 0x4
#define BNXT_REG_CTRL_FSTBOOT_PTR_REG 0x8
#define BNXT_ERROR_MASK 0xf0000000
#define BNXT_CTRL_ADDR(x) (BNXT_REG_CTRL_BASE + (x))
#define BNXT_HANDSHAKE_TIMEOUT_MS 1000
#define KONG_REG_CTRL_MODE_REG 0x03900000
#define KONG_REG_CTRL_MODE_CPUHALT_N_BIT 0
#define BNXT_STICKY_BYTE_POR 0x04030088
#define BNXT_STICKY_BYTE_POR_MHB_BIT 4
#define BNXT_HEALTH_CHECK_REG 0x03100008
enum bnxt_handshake_sts {
BNXT_HANDSHAKE_SUCCESS = 0,
BNXT_HANDSHAKE_WAIT_ERROR,
BNXT_HANDSHAKE_WAIT_TIMEOUT
};
static vaddr_t bnxt_access_window_virt_addr;
static vaddr_t bnxt_indirect_dest_addr;
static void bnxt_prepare_access_window(uint32_t addr)
{
addr &= BNXT_INDIRECT_BASE_MASK;
io_write32(bnxt_access_window_virt_addr, addr);
}
static vaddr_t bnxt_indirect_tgt_addr(uint32_t addr)
{
addr &= BNXT_INDIRECT_ADDR_MASK;
return (vaddr_t)(bnxt_indirect_dest_addr + addr);
}
uint32_t bnxt_write32_multiple(uintptr_t dst,
uintptr_t src,
uint32_t num_entries,
int src_4byte_increment)
{
uint32_t i = 0;
vaddr_t target = 0;
if (num_entries == 0)
return 0;
/* Only write up to the next window boundary */
if ((dst & BNXT_INDIRECT_BASE_MASK) !=
((dst + num_entries * sizeof(uint32_t)) & BNXT_INDIRECT_BASE_MASK))
num_entries = (((dst + BNXT_INDIRECT_WINDOW_SIZE) &
BNXT_INDIRECT_BASE_MASK) -
dst) /
sizeof(uint32_t);
bnxt_prepare_access_window(dst);
target = bnxt_indirect_tgt_addr(dst);
for (i = 0; i < num_entries; i++) {
io_write32(target, *(uint32_t *)src);
target += sizeof(uint32_t);
if (src_4byte_increment)
src += sizeof(uint32_t);
}
return num_entries;
}
static uint32_t bnxt_read(uint32_t addr)
{
bnxt_prepare_access_window(addr);
return io_read32(bnxt_indirect_tgt_addr(addr));
}
static uint32_t bnxt_read_ctrl(uint32_t offset)
{
return bnxt_read(BNXT_CTRL_ADDR(offset));
}
static void bnxt_write(uint32_t addr, uint32_t value)
{
bnxt_prepare_access_window(addr);
io_write32(bnxt_indirect_tgt_addr(addr), value);
}
static void bnxt_write_ctrl(uint32_t offset, uint32_t value)
{
bnxt_write(BNXT_CTRL_ADDR(offset), value);
}
void bnxt_handshake_clear(void)
{
uint32_t value = bnxt_read(BNXT_REG_ECO_RESERVED);
value = value & ~BIT(BNXT_FLASH_ACCESS_DONE_BIT);
bnxt_write(BNXT_REG_ECO_RESERVED, value);
}
static int bnxt_handshake_done(void)
{
uint32_t value = 0;
value = bnxt_read(BNXT_REG_ECO_RESERVED);
value &= BIT(BNXT_FLASH_ACCESS_DONE_BIT);
return value != 0;
}
uint32_t bnxt_wait_handshake(uint32_t max_timeout)
{
int ret = 0;
uint32_t status = 0;
uint32_t timeout = 0;
/* If no timeout given we go with max timeout */
if (max_timeout == 0)
max_timeout = BNXT_HANDSHAKE_TIMEOUT_MS;
timeout = max_timeout;
DMSG("Waiting for ChiMP handshake...");
do {
if (bnxt_handshake_done()) {
ret = BNXT_HANDSHAKE_SUCCESS;
break;
}
/* No need to wait if ChiMP reported an error */
status = bnxt_read_ctrl(BNXT_REG_CTRL_BPE_STAT_REG);
if (status & BNXT_ERROR_MASK) {
EMSG("ChiMP error 0x%x. Wait aborted", status);
ret = BNXT_HANDSHAKE_WAIT_ERROR;
break;
}
mdelay(1);
} while (--timeout);
if (!bnxt_handshake_done()) {
if (timeout == 0) {
ret = BNXT_HANDSHAKE_WAIT_TIMEOUT;
EMSG("Timeout waiting for ChiMP handshake");
}
} else {
ret = BNXT_HANDSHAKE_SUCCESS;
DMSG("ChiMP handshake successful");
}
return ret;
}
void bnxt_chimp_halt(void)
{
uint32_t value = 0;
value = bnxt_read_ctrl(BNXT_REG_CTRL_BPE_MODE_REG);
value |= BIT(BNXT_REG_CTRL_BPE_MODE_CM3_RST_BIT);
bnxt_write_ctrl(BNXT_REG_CTRL_BPE_MODE_REG, value);
}
void bnxt_kong_halt(void)
{
uint32_t value = 0;
value = bnxt_read(KONG_REG_CTRL_MODE_REG);
value &= ~BIT(KONG_REG_CTRL_MODE_CPUHALT_N_BIT);
bnxt_write(KONG_REG_CTRL_MODE_REG, value);
}
int bnxt_fastboot(uintptr_t addr)
{
uint32_t value = 0;
value = bnxt_read(BNXT_STICKY_BYTE_POR);
value |= BIT(BNXT_STICKY_BYTE_POR_MHB_BIT);
bnxt_write(BNXT_STICKY_BYTE_POR, value);
/* Set the fastboot address and type */
bnxt_write_ctrl(BNXT_REG_CTRL_FSTBOOT_PTR_REG, addr);
/* Set fastboot mode & take BNXT CPU1 out of reset */
value = bnxt_read_ctrl(BNXT_REG_CTRL_BPE_MODE_REG);
value |= BIT(BNXT_REG_CTRL_BPE_MODE_FASTBOOT_MODE_BIT);
value &= ~BIT(BNXT_REG_CTRL_BPE_MODE_CM3_RST_BIT);
bnxt_write_ctrl(BNXT_REG_CTRL_BPE_MODE_REG, value);
return 0;
}
uint32_t bnxt_health_status(void)
{
return bnxt_read(BNXT_HEALTH_CHECK_REG);
}
static TEE_Result bnxt_init(void)
{
bnxt_access_window_virt_addr =
(vaddr_t)phys_to_virt(NIC400_BNXT_IDM_IO_CONTROL_DIRECT,
MEM_AREA_IO_SEC);
bnxt_indirect_dest_addr =
(vaddr_t)phys_to_virt(BNXT_INDIRECT_BASE,
MEM_AREA_IO_SEC);
return TEE_SUCCESS;
}
driver_init(bnxt_init);