forked from Mirrors/opensbi
lib: utils/ipi: Add Andes fdt ipi driver support
Move Andes PLICSW ipi device to fdt ipi framework, this patch is based on Leo's modified IPI scheme on PLICSW. Current IPI scheme uses bit 0 of pending reigster on PLICSW to send IPI from hart 0 to hart 7, but bit 0 needs to be hardwired to 0 according to spec. After some investigation, self-IPI seems to be seldom or never used, so we re-order the IPI scheme to support 8 core platforms. dts example (Quad-core AX45MP): plicsw: interrupt-controller@e6400000 { compatible = "andestech,plicsw"; reg = <0x00000000 0xe6400000 0x00000000 0x00400000>; interrupts-extended = <&CPU0_intc 3 &CPU1_intc 3 &CPU2_intc 3 &CPU3_intc 3>; interrupt-controller; #address-cells = <2>; #interrupt-cells = <2>; }; Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com> Reviewed-by: Anup Patel <anup@brainfault.org>
This commit is contained in:

committed by
Anup Patel

parent
6f3258e671
commit
ce7c490719
@@ -11,6 +11,8 @@ config PLATFORM_ANDES_AE350
|
||||
select FDT_RESET_ATCWDT200
|
||||
select FDT_IRQCHIP
|
||||
select FDT_IRQCHIP_PLIC
|
||||
select FDT_IPI
|
||||
select FDT_IPI_PLICSW
|
||||
default y
|
||||
|
||||
if PLATFORM_ANDES_AE350
|
||||
|
@@ -15,7 +15,7 @@ platform-asflags-y =
|
||||
platform-ldflags-y =
|
||||
|
||||
# Objects to build
|
||||
platform-objs-y += cache.o platform.o plicsw.o
|
||||
platform-objs-y += cache.o platform.o
|
||||
|
||||
# Blobs to build
|
||||
FW_TEXT_START=0x00000000
|
||||
|
@@ -25,8 +25,8 @@
|
||||
#include <sbi_utils/reset/fdt_reset.h>
|
||||
#include <sbi_utils/serial/fdt_serial.h>
|
||||
#include <sbi_utils/timer/fdt_timer.h>
|
||||
#include <sbi_utils/ipi/fdt_ipi.h>
|
||||
#include "platform.h"
|
||||
#include "plicsw.h"
|
||||
#include "cache.h"
|
||||
|
||||
struct sbi_platform platform;
|
||||
@@ -88,29 +88,6 @@ static int ae350_final_init(bool cold_boot)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct sbi_ipi_device plicsw_ipi = {
|
||||
.name = "ae350_plicsw",
|
||||
.ipi_send = plicsw_ipi_send,
|
||||
.ipi_clear = plicsw_ipi_clear
|
||||
};
|
||||
|
||||
/* 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;
|
||||
|
||||
sbi_ipi_set_device(&plicsw_ipi);
|
||||
}
|
||||
|
||||
return plicsw_warm_ipi_init();
|
||||
}
|
||||
|
||||
/* Vendor-Specific SBI handler */
|
||||
static int ae350_vendor_ext_provider(long extid, long funcid,
|
||||
const struct sbi_trap_regs *regs, unsigned long *out_value,
|
||||
@@ -163,7 +140,7 @@ const struct sbi_platform_operations platform_ops = {
|
||||
|
||||
.irqchip_init = fdt_irqchip_init,
|
||||
|
||||
.ipi_init = ae350_ipi_init,
|
||||
.ipi_init = fdt_ipi_init,
|
||||
|
||||
.timer_init = fdt_timer_init,
|
||||
|
||||
|
@@ -11,8 +11,6 @@
|
||||
#ifndef _AE350_PLATFORM_H_
|
||||
#define _AE350_PLATFORM_H_
|
||||
|
||||
#define AE350_PLICSW_ADDR 0xe6400000
|
||||
|
||||
#define AE350_L2C_ADDR 0xe0500000
|
||||
|
||||
/*Memory and Miscellaneous Registers*/
|
||||
|
@@ -1,139 +0,0 @@
|
||||
/*
|
||||
* 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_asm.h>
|
||||
#include <sbi/riscv_io.h>
|
||||
#include <sbi/sbi_types.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 = current_hartid();
|
||||
|
||||
plicsw_dev[source_hart].source_id =
|
||||
readl(plicsw_dev[source_hart].plicsw_claim);
|
||||
}
|
||||
|
||||
static inline void plicsw_complete(void)
|
||||
{
|
||||
u32 source_hart = current_hartid();
|
||||
u32 source = plicsw_dev[source_hart].source_id;
|
||||
|
||||
writel(source, plicsw_dev[source_hart].plicsw_claim);
|
||||
}
|
||||
|
||||
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 = 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 PLICSW IPI */
|
||||
plicsw_claim();
|
||||
plicsw_complete();
|
||||
}
|
||||
|
||||
int plicsw_warm_ipi_init(void)
|
||||
{
|
||||
u32 hartid = 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;
|
||||
}
|
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* 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_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_ */
|
Reference in New Issue
Block a user