platform: Add Andes AE350 initial support

This commit provides basic support for the AE350 platform.

Signed-off-by: Zong Li <zongbox@gmail.com>
Signed-off-by: Nylon Chen <nylon7@andestech.com>
This commit is contained in:
Nylon Chen 2019-07-18 15:52:25 +08:00 committed by Anup Patel
parent a2a7763ac7
commit 3cbb419def
10 changed files with 650 additions and 0 deletions

View file

@ -0,0 +1,28 @@
Andes AE350 SoC Platform
========================
The AE350 AXI/AHB-based platform N25(F)/NX25(F)/D25F/A25/AX25 CPU with
level-one memories,interrupt controller, debug module, AXI and AHB Bus
Matrix Controller, AXI-to-AHB Bridge and a collection of fundamentalAHB/APB
bus IP components pre-integrated together as a system design.The high-quality
and configurable AHB/APB IPs suites a majority embedded systems,
and the verified platform serves as a starting point to jump start SoC designs.
To build platform specific library and firmwares, provide the *PLATFORM=andes/ae350* parameter to the top level make command.
Platform Options
----------------
The Andes AE350 platform does not have any platform-specific options.
Building Andes AE350 Platform
-----------------------------
To use Linux v5.2 should be used to build Andes AE350 OpenSBI binaries by using the compile time option FW_PAYLOAD_FDT_PATH.
AE350's dts is included in https://github.com/andestech/linux/tree/ast-v3_2_0-release-public
**Linux Kernel Payload**
```
make PLATFORM=andes/ae350 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_PAYLOAD_FDT_PATH=<ae350.dtb path>
```

View file

@ -24,6 +24,8 @@ OpenSBI currently supports the following virtual and hardware platforms:
* **Ariane FPGA SoC**: Platform support for the Ariane FPGA SoC used on * **Ariane FPGA SoC**: Platform support for the Ariane FPGA SoC used on
Genesys 2 board. Genesys 2 board.
* **Andes AE350 SoC**: Platform support for the Andes's SoC (AE350).
The code for these supported platforms can be used as example to implement The code for these supported platforms can be used as example to implement
support for other platforms. The *platform/template* directory also provides support for other platforms. The *platform/template* directory also provides
template files for implementing support for a new platform. The *object.mk*, template files for implementing support for a new platform. The *object.mk*,
@ -34,3 +36,4 @@ facilitate the implementation.
[qemu_sifive_u.md]: qemu_sifive_u.md [qemu_sifive_u.md]: qemu_sifive_u.md
[sifive_fu540.md]: sifive_fu540.md [sifive_fu540.md]: sifive_fu540.md
[ariane-fpga.md]: ariane-fpga.md [ariane-fpga.md]: ariane-fpga.md
[andes_ae350.md]: andes-ae350.md

View file

@ -0,0 +1,36 @@
#
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2019 Andes Technology Corporation
#
# Authors:
# Zong Li <zong@andestech.com>
# Nylon Chen <nylon7@andestech.com>
# Compiler flags
platform-cppflags-y =
platform-cflags-y =
platform-asflags-y =
platform-ldflags-y =
# Blobs to build
FW_TEXT_START=0x00000000
FW_DYNAMIC=y
FW_JUMP=y
ifeq ($(PLATFORM_RISCV_XLEN), 32)
FW_JUMP_ADDR=0x400000
else
FW_JUMP_ADDR=0x200000
endif
FW_JUMP_FDT_ADDR=0x2000000
FW_PAYLOAD=y
ifeq ($(PLATFORM_RISCV_XLEN), 32)
FW_PAYLOAD_OFFSET=0x400000
else
FW_PAYLOAD_OFFSET=0x200000
endif
FW_PAYLOAD_FDT_ADDR=0x2000000

View file

@ -0,0 +1,11 @@
#
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2019 Andes Technology Corporation
#
# Authors:
# Zong Li <zong@andestech.com>
# Nylon Chen <nylon7@andestech.com>
#
platform-objs-y += plicsw.o plmt.o platform.o

View file

@ -0,0 +1,194 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Andes Technology Corporation
*
* Authors:
* Zong Li <zong@andestech.com>
* Nylon Chen <nylon7@andestech.com>
*/
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_const.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_console.h>
#include <sbi_utils/serial/uart8250.h>
#include <sbi_utils/irqchip/plic.h>
#include "platform.h"
#include "plmt.h"
#include "plicsw.h"
/* Platform final initialization. */
static int ae350_final_init(bool cold_boot)
{
void *fdt;
/* enable L1 cache */
uintptr_t mcache_ctl_val = csr_read(CSR_MCACHECTL);
if (!(mcache_ctl_val & V5_MCACHE_CTL_IC_EN))
mcache_ctl_val |= V5_MCACHE_CTL_IC_EN;
if (!(mcache_ctl_val & V5_MCACHE_CTL_DC_EN))
mcache_ctl_val |= V5_MCACHE_CTL_DC_EN;
if (!(mcache_ctl_val & V5_MCACHE_CTL_CCTL_SUEN))
mcache_ctl_val |= V5_MCACHE_CTL_CCTL_SUEN;
csr_write(CSR_MCACHECTL, mcache_ctl_val);
/* enable L2 cache */
uint32_t *l2c_ctl_base = (void *)AE350_L2C_ADDR + V5_L2C_CTL_OFFSET;
uint32_t l2c_ctl_val = *l2c_ctl_base;
if (!(l2c_ctl_val & V5_L2C_CTL_ENABLE_MASK))
l2c_ctl_val |= V5_L2C_CTL_ENABLE_MASK;
*l2c_ctl_base = l2c_ctl_val;
if (!cold_boot)
return 0;
fdt = sbi_scratch_thishart_arg1_ptr();
plic_fdt_fixup(fdt, "riscv,plic0");
return 0;
}
/* Get number of PMP regions for given HART. */
static u32 ae350_pmp_region_count(u32 hartid)
{
return 1;
}
/*
* Get PMP regions details (namely: protection, base address, and size) for
* a given HART.
*/
static int ae350_pmp_region_info(u32 hartid, u32 index, ulong *prot,
ulong *addr, ulong *log2size)
{
int ret = 0;
switch (index) {
case 0:
*prot = PMP_R | PMP_W | PMP_X;
*addr = 0;
*log2size = __riscv_xlen;
break;
default:
ret = -1;
break;
};
return ret;
}
/* Initialize the platform console. */
static int ae350_console_init(void)
{
return uart8250_init(AE350_UART_ADDR,
AE350_UART_FREQUENCY,
AE350_UART_BAUDRATE,
AE350_UART_REG_SHIFT,
AE350_UART_REG_WIDTH);
}
/* Initialize the platform interrupt controller for current HART. */
static int ae350_irqchip_init(bool cold_boot)
{
u32 hartid = sbi_current_hartid();
int ret;
if (cold_boot) {
ret = plic_cold_irqchip_init(AE350_PLIC_ADDR,
AE350_PLIC_NUM_SOURCES,
AE350_HART_COUNT);
if (ret)
return ret;
}
return plic_warm_irqchip_init(hartid, 2 * hartid, 2 * hartid + 1);
}
/* Initialize IPI for current HART. */
static int ae350_ipi_init(bool cold_boot)
{
int ret;
if (cold_boot) {
ret = plicsw_cold_ipi_init(AE350_PLICSW_ADDR,
AE350_HART_COUNT);
if (ret)
return ret;
}
return plicsw_warm_ipi_init();
}
/* Initialize platform timer for current HART. */
static int ae350_timer_init(bool cold_boot)
{
int ret;
if (cold_boot) {
ret = plmt_cold_timer_init(AE350_PLMT_ADDR,
AE350_HART_COUNT);
if (ret)
return ret;
}
return plmt_warm_timer_init();
}
/* Reboot the platform. */
static int ae350_system_reboot(u32 type)
{
/* For now nothing to do. */
sbi_printf("System reboot\n");
return 0;
}
/* Shutdown or poweroff the platform. */
static int ae350_system_shutdown(u32 type)
{
/* For now nothing to do. */
sbi_printf("System shutdown\n");
return 0;
}
/* Platform descriptor. */
const struct sbi_platform_operations platform_ops = {
.final_init = ae350_final_init,
.pmp_region_count = ae350_pmp_region_count,
.pmp_region_info = ae350_pmp_region_info,
.console_init = ae350_console_init,
.console_putc = uart8250_putc,
.console_getc = uart8250_getc,
.irqchip_init = ae350_irqchip_init,
.ipi_init = ae350_ipi_init,
.ipi_send = plicsw_ipi_send,
.ipi_clear = plicsw_ipi_clear,
.timer_init = ae350_timer_init,
.timer_value = plmt_timer_value,
.timer_event_start = plmt_timer_event_start,
.timer_event_stop = plmt_timer_event_stop,
.system_reboot = ae350_system_reboot,
.system_shutdown = ae350_system_shutdown
};
const struct sbi_platform platform = {
.opensbi_version = OPENSBI_VERSION,
.platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
.name = "Andes AE350",
.features = SBI_PLATFORM_DEFAULT_FEATURES,
.hart_count = AE350_HART_COUNT,
.hart_stack_size = AE350_HART_STACK_SIZE,
.disabled_hart_mask = 0,
.platform_ops_addr = (unsigned long)&platform_ops
};

View file

@ -0,0 +1,67 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Andes Technology Corporation
*
* Authors:
* Zong Li <zong@andestech.com>
* Nylon Chen <nylon7@andestech.com>
*/
#ifndef _AE350_PLATFORM_H_
#define _AE350_PLATFORM_H_
#define AE350_HART_COUNT 4
#define AE350_HART_STACK_SIZE 8192
#define AE350_PLIC_ADDR 0xe4000000
#define AE350_PLIC_NUM_SOURCES 71
#define AE350_PLICSW_ADDR 0xe6400000
#define AE350_PLMT_ADDR 0xe6000000
#define AE350_L2C_ADDR 0xe0500000
#define AE350_UART_ADDR_OFFSET 0x20
#define AE350_UART_ADDR (0xf0300000 + AE350_UART_ADDR_OFFSET)
#define AE350_UART_FREQUENCY 19660800
#define AE350_UART_BAUDRATE 38400
#define AE350_UART_REG_SHIFT 2
#define AE350_UART_REG_WIDTH 0
/* nds mcache_ctl register*/
#define CSR_MCACHECTL 0x7ca
#define V5_MCACHE_CTL_IC_EN_OFFSET 0
#define V5_MCACHE_CTL_DC_EN_OFFSET 1
#define V5_MCACHE_CTL_IC_ECCEN_OFFSET 2
#define V5_MCACHE_CTL_DC_ECCEN_OFFSET 4
#define V5_MCACHE_CTL_IC_RWECC_OFFSET 6
#define V5_MCACHE_CTL_DC_RWECC_OFFSET 7
#define V5_MCACHE_CTL_CCTL_SUEN_OFFSET 8
#define V5_MCACHE_CTL_IC_EN (1UL << V5_MCACHE_CTL_IC_EN_OFFSET)
#define V5_MCACHE_CTL_DC_EN (1UL << V5_MCACHE_CTL_DC_EN_OFFSET)
#define V5_MCACHE_CTL_IC_RWECC (1UL << V5_MCACHE_CTL_IC_RWECC_OFFSET)
#define V5_MCACHE_CTL_DC_RWECC (1UL << V5_MCACHE_CTL_DC_RWECC_OFFSET)
#define V5_MCACHE_CTL_CCTL_SUEN (1UL << V5_MCACHE_CTL_CCTL_SUEN_OFFSET)
#define V5_L2C_CTL_OFFSET 0x8
#define V5_L2C_CTL_ENABLE_OFFSET 0
#define V5_L2C_CTL_IPFDPT_OFFSET 3
#define V5_L2C_CTL_DPFDPT_OFFSET 5
#define V5_L2C_CTL_TRAMOCTL_OFFSET 8
#define V5_L2C_CTL_TRAMICTL_OFFSET 10
#define V5_L2C_CTL_DRAMOCTL_OFFSET 11
#define V5_L2C_CTL_DRAMICTL_OFFSET 13
#define V5_L2C_CTL_ENABLE_MASK (1UL << V5_L2C_CTL_ENABLE_OFFSET)
#define V5_L2C_CTL_IPFDPT_MASK (3UL << V5_L2C_CTL_IPFDPT_OFFSET)
#define V5_L2C_CTL_DPFDPT_MASK (3UL << V5_L2C_CTL_DPFDPT_OFFSET)
#define V5_L2C_CTL_TRAMOCTL_MASK (3UL << V5_L2C_CTL_TRAMOCTL_OFFSET)
#define V5_L2C_CTL_TRAMICTL_MASK (1UL << V5_L2C_CTL_TRAMICTL_OFFSET)
#define V5_L2C_CTL_DRAMOCTL_MASK (3UL << V5_L2C_CTL_DRAMOCTL_OFFSET)
#define V5_L2C_CTL_DRAMICTL_MASK (1UL << V5_L2C_CTL_DRAMICTL_OFFSET)
#endif /* _AE350_PLATFORM_H_ */

View file

@ -0,0 +1,145 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Andes Technology Corporation
*
* Authors:
* Zong Li <zong@andestech.com>
* Nylon Chen <nylon7@andestech.com>
*/
#include <sbi/sbi_types.h>
#include <sbi/sbi_hart.h>
#include <sbi/riscv_io.h>
#include "plicsw.h"
#include "platform.h"
static u32 plicsw_ipi_hart_count;
static struct plicsw plicsw_dev[AE350_HART_COUNT];
static inline void plicsw_claim(void)
{
u32 source_hart = sbi_current_hartid();
plicsw_dev[source_hart].source_id =
readl(plicsw_dev[source_hart].plicsw_claim);
}
static inline void plicsw_complete(void)
{
u32 source_hart = sbi_current_hartid();
u32 source = plicsw_dev[source_hart].source_id;
writel(source, plicsw_dev[source_hart].plicsw_claim);
}
static inline u32 plicsw_get_pending(u32 source_hart, u32 target_hart)
{
return readl(plicsw_dev[source_hart].plicsw_pending)
& (PLICSW_HART_MASK >> target_hart);
}
static inline void plic_sw_pending(u32 target_hart)
{
/*
* The pending array registers are w1s type.
* IPI pending array mapping as following:
*
* Pending array start address: base + 0x1000
* -------------------------------------
* | hart 3 | hart 2 | hart 1 | hart 0 |
* -------------------------------------
* Each hart X can send IPI to another hart by setting the
* corresponding bit in hart X own region(see the below).
*
* In each hart region:
* -----------------------------------------------
* | bit 7 | bit 6 | bit 5 | bit 4 | ... | bit 0 |
* -----------------------------------------------
* The bit 7 is used to send IPI to hart 0
* The bit 6 is used to send IPI to hart 1
* The bit 5 is used to send IPI to hart 2
* The bit 4 is used to send IPI to hart 3
*/
u32 source_hart = sbi_current_hartid();
u32 target_offset = (PLICSW_PENDING_PER_HART - 1) - target_hart;
u32 per_hart_offset = PLICSW_PENDING_PER_HART * source_hart;
u32 val = 1 << target_offset << per_hart_offset;
writel(val, plicsw_dev[source_hart].plicsw_pending);
}
void plicsw_ipi_send(u32 target_hart)
{
if (plicsw_ipi_hart_count <= target_hart)
return;
/* Set PLICSW IPI */
plic_sw_pending(target_hart);
}
void plicsw_ipi_clear(u32 target_hart)
{
if (plicsw_ipi_hart_count <= target_hart)
return;
/* Clear CLINT IPI */
plicsw_claim();
plicsw_complete();
}
int plicsw_warm_ipi_init(void)
{
u32 hartid = sbi_current_hartid();
if (!plicsw_dev[hartid].plicsw_pending
&& !plicsw_dev[hartid].plicsw_enable
&& !plicsw_dev[hartid].plicsw_claim)
return -1;
/* Clear PLICSW IPI */
plicsw_ipi_clear(hartid);
return 0;
}
int plicsw_cold_ipi_init(unsigned long base, u32 hart_count)
{
/* Setup source priority */
uint32_t *priority = (void *)base + PLICSW_PRIORITY_BASE;
for (int i = 0; i < AE350_HART_COUNT*PLICSW_PENDING_PER_HART; i++)
writel(1, &priority[i]);
/* Setup target enable.*/
uint32_t enable_mask = PLICSW_HART_MASK;
for (int i = 0; i < AE350_HART_COUNT; i++) {
uint32_t *enable = (void *)base + PLICSW_ENABLE_BASE
+ PLICSW_ENABLE_PER_HART * i;
writel(enable_mask, &enable[0]);
enable_mask >>= 1;
}
/* Figure-out PLICSW IPI register address */
plicsw_ipi_hart_count = hart_count;
for (u32 hartid = 0; hartid < AE350_HART_COUNT; hartid++) {
plicsw_dev[hartid].source_id = 0;
plicsw_dev[hartid].plicsw_pending =
(void *)base
+ PLICSW_PENDING_BASE
+ ((hartid / 4) * 4);
plicsw_dev[hartid].plicsw_enable =
(void *)base
+ PLICSW_ENABLE_BASE
+ PLICSW_ENABLE_PER_HART * hartid;
plicsw_dev[hartid].plicsw_claim =
(void *)base
+ PLICSW_CONTEXT_BASE
+ PLICSW_CONTEXT_CLAIM
+ PLICSW_CONTEXT_PER_HART * hartid;
}
return 0;
}

View file

@ -0,0 +1,46 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Andes Technology Corporation
*
* Authors:
* Zong Li <zong@andestech.com>
* Nylon Chen <nylon7@andestech.com>
*/
#ifndef _AE350_PLICSW_H_
#define _AE350_PLICSW_H_
#define PLICSW_PRIORITY_BASE 0x4
#define PLICSW_PENDING_BASE 0x1000
#define PLICSW_PENDING_PER_HART 0x8
#define PLICSW_ENABLE_BASE 0x2000
#define PLICSW_ENABLE_PER_HART 0x80
#define PLICSW_CONTEXT_BASE 0x200000
#define PLICSW_CONTEXT_PER_HART 0x1000
#define PLICSW_CONTEXT_CLAIM 0x4
#define PLICSW_HART_MASK 0x80808080
struct plicsw {
u32 source_id;
volatile uint32_t *plicsw_pending;
volatile uint32_t *plicsw_enable;
volatile uint32_t *plicsw_claim;
};
void plicsw_ipi_send(u32 target_hart);
void plicsw_ipi_sync(u32 target_hart);
void plicsw_ipi_clear(u32 target_hart);
int plicsw_warm_ipi_init(void);
int plicsw_cold_ipi_init(unsigned long base, u32 hart_count);
#endif /* _AE350_PLICSW_H_ */

View file

@ -0,0 +1,97 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Andes Technology Corporation
*
* Authors:
* Zong Li <zong@andestech.com>
* Nylon Chen <nylon7@andestech.com>
*/
#include <sbi/riscv_io.h>
#include <sbi/sbi_hart.h>
static u32 plmt_time_hart_count;
static volatile void *plmt_time_base;
static volatile u64 *plmt_time_val;
static volatile u64 *plmt_time_cmp;
u64 plmt_timer_value(void)
{
#if __riscv_xlen == 64
return readq_relaxed(plmt_time_val);
#else
u32 lo, hi;
do {
hi = readl_relaxed((void *)plmt_time_val + 0x04);
lo = readl_relaxed(plmt_time_val);
} while (hi != readl_relaxed((void *)plmt_time_val + 0x04));
return ((u64)hi << 32) | (u64)lo;
#endif
}
void plmt_timer_event_stop(void)
{
u32 target_hart = sbi_current_hartid();
if (plmt_time_hart_count <= target_hart)
return;
/* Clear PLMT Time Compare */
#if __riscv_xlen == 64
writeq_relaxed(-1ULL, &plmt_time_cmp[target_hart]);
#else
writel_relaxed(-1UL, &plmt_time_cmp[target_hart]);
writel_relaxed(-1UL, (void *)(&plmt_time_cmp[target_hart]) + 0x04);
#endif
}
void plmt_timer_event_start(u64 next_event)
{
u32 target_hart = sbi_current_hartid();
if (plmt_time_hart_count <= target_hart)
return;
/* Program PLMT Time Compare */
#if __riscv_xlen == 64
writeq_relaxed(next_event, &plmt_time_cmp[target_hart]);
#else
u32 mask = -1UL;
writel_relaxed(next_event & mask, &plmt_time_cmp[target_hart]);
writel_relaxed(next_event >> 32,
(void *)(&plmt_time_cmp[target_hart]) + 0x04);
#endif
}
int plmt_warm_timer_init(void)
{
u32 target_hart = sbi_current_hartid();
if (plmt_time_hart_count <= target_hart || !plmt_time_base)
return -1;
/* Clear PLMT Time Compare */
#if __riscv_xlen == 64
writeq_relaxed(-1ULL, &plmt_time_cmp[target_hart]);
#else
writel_relaxed(-1UL, &plmt_time_cmp[target_hart]);
writel_relaxed(-1UL, (void *)(&plmt_time_cmp[target_hart]) + 0x04);
#endif
return 0;
}
int plmt_cold_timer_init(unsigned long base, u32 hart_count)
{
plmt_time_hart_count = hart_count;
plmt_time_base = (void *)base;
plmt_time_val = (u64 *)(plmt_time_base);
plmt_time_cmp = (u64 *)(plmt_time_base + 0x8);
return 0;
}

View file

@ -0,0 +1,23 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Andes Technology Corporation
*
* Authors:
* Zong Li <zong@andestech.com>
*/
#ifndef _AE350_PLMT_H_
#define _AE350_PLMT_H_
u64 plmt_timer_value(void);
void plmt_timer_event_stop(void);
void plmt_timer_event_start(u64 next_event);
int plmt_warm_timer_init(void);
int plmt_cold_timer_init(unsigned long base, u32 hart_count);
#endif /* _AE350_PLMT_H_ */