Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion sw/device/lib/hal/mocha.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ timer_t mocha_system_timer(void)
plic_t mocha_system_plic(void)
{
#if defined(__riscv_zcherihybrid)
return (plic_t)create_mmio_capability(plic_base, 0x4004004u);
return (plic_t)create_mmio_capability(plic_base, sizeof(struct plic_memory_layout));
#else /* !defined(__riscv_zcherihybrid) */
return (plic_t)plic_base;
#endif /* defined(__riscv_zcherihybrid) */
Expand Down
12 changes: 11 additions & 1 deletion sw/device/lib/hal/mocha.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,17 @@

static const uintptr_t dram_base = 0x80000000ul;

// In order of memory map.
/* device IRQs at the PLIC */
enum mocha_system_irq : uint32_t {
mocha_system_irq_i2c = (1u << 6),
mocha_system_irq_spi_device = (1u << 7),
mocha_system_irq_uart = (1u << 8),
mocha_system_irq_gpio = (1u << 9),
mocha_system_irq_pwrmgr = (1u << 10),
mocha_system_irq_mailbox = (1u << 11),
};

/* In order of memory map. */
mailbox_t mocha_system_mailbox(void);
gpio_t mocha_system_gpio(void);
clkmgr_t mocha_system_clkmgr(void);
Expand Down
126 changes: 79 additions & 47 deletions sw/device/lib/hal/plic.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,115 +5,147 @@
#include "hal/plic.h"
#include "hal/mmio.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

uint8_t plic_interrupt_priority_get(plic_t plic, uint8_t intr_id)
void plic_init(plic_t plic)
{
if (intr_id >= PLIC_NUM_SRC) {
return 0;
}
return (DEV_READ(plic + PLIC_PRIO_REG + 4 * intr_id) & PLIC_PRIO_MASK);
plic_machine_interrupt_enable_write(plic, 0u);
plic_supervisor_interrupt_enable_write(plic, 0u);
}

void plic_interrupt_priority_set(plic_t plic, uint8_t intr_id, uint8_t prio)
uint8_t plic_interrupt_priority_read(plic_t plic, uint32_t intr)
{
if (intr_id < PLIC_NUM_SRC) {
DEV_WRITE(plic + PLIC_PRIO_REG + 4 * intr_id, prio & PLIC_PRIO_MASK);
if (intr == 0u) {
return 0u;
}

size_t id = __builtin_ctz(intr);
plic_prio prio = VOLATILE_READ(plic->prio[id]);
return prio.prio;
}

bool plic_interrupt_is_pending(plic_t plic, uint8_t intr_id)
void plic_interrupt_priority_write(plic_t plic, uint32_t intrs, uint8_t priority)
{
return ((DEV_READ(plic + PLIC_IP_REG) & (1 << intr_id)) != 0);
if (intrs == 0u) {
return;
}

uint32_t remain = intrs;
do {
size_t id = __builtin_ctz(remain);
remain &= ~(1u << id);
plic_prio prio = { .prio = priority };
VOLATILE_WRITE(plic->prio[id], prio);
} while (remain != 0u);
}

bool plic_machine_interrupt_enable_get(plic_t plic, uint8_t intr_id)
uint32_t plic_machine_interrupt_enable_read(plic_t plic)
{
return ((DEV_READ(plic + PLIC_IE0_REG) & (1 << intr_id)) != 0);
return VOLATILE_READ(plic->ie0);
}

bool plic_supervisor_interrupt_enable_get(plic_t plic, uint8_t intr_id)
uint32_t plic_supervisor_interrupt_enable_read(plic_t plic)
{
return ((DEV_READ(plic + PLIC_IE1_REG) & (1 << intr_id)) != 0);
return VOLATILE_READ(plic->ie1);
}

void plic_machine_interrupt_enable(plic_t plic, uint8_t intr_id)
void plic_machine_interrupt_enable_write(plic_t plic, uint32_t intrs)
{
DEV_WRITE(plic + PLIC_IE0_REG, DEV_READ(plic + PLIC_IE0_REG) | (1 << intr_id));
VOLATILE_WRITE(plic->ie0, intrs);
}

void plic_supervisor_interrupt_enable(plic_t plic, uint8_t intr_id)
void plic_supervisor_interrupt_enable_write(plic_t plic, uint32_t intrs)
{
DEV_WRITE(plic + PLIC_IE1_REG, DEV_READ(plic + PLIC_IE1_REG) | (1 << intr_id));
VOLATILE_WRITE(plic->ie1, intrs);
}

void plic_machine_interrupt_disable(plic_t plic, uint8_t intr_id)
void plic_machine_interrupt_enable_set(plic_t plic, uint32_t intrs)
{
DEV_WRITE(plic + PLIC_IE0_REG, DEV_READ(plic + PLIC_IE0_REG) & ~(1 << intr_id));
uint32_t ie0 = VOLATILE_READ(plic->ie0);
VOLATILE_WRITE(plic->ie0, ie0 |= intrs);
}

void plic_supervisor_interrupt_disable(plic_t plic, uint8_t intr_id)
void plic_supervisor_interrupt_enable_set(plic_t plic, uint32_t intrs)
{
DEV_WRITE(plic + PLIC_IE1_REG, DEV_READ(plic + PLIC_IE1_REG) & ~(1 << intr_id));
uint32_t ie1 = VOLATILE_READ(plic->ie1);
VOLATILE_WRITE(plic->ie1, ie1 |= intrs);
}

void plic_machine_interrupt_disable_all(plic_t plic)
void plic_machine_interrupt_enable_clear(plic_t plic, uint32_t intrs)
{
DEV_WRITE(plic + PLIC_IE0_REG, 0);
uint32_t ie0 = VOLATILE_READ(plic->ie0);
VOLATILE_WRITE(plic->ie0, ie0 & ~intrs);
}

void plic_supervisor_interrupt_disable_all(plic_t plic)
void plic_supervisor_interrupt_enable_clear(plic_t plic, uint32_t intrs)
{
DEV_WRITE(plic + PLIC_IE1_REG, 0);
uint32_t ie1 = VOLATILE_READ(plic->ie1);
VOLATILE_WRITE(plic->ie1, ie1 & ~intrs);
}

uint8_t plic_machine_priority_threshold_get(plic_t plic)
bool plic_interrupt_all_pending(plic_t plic, uint32_t intrs)
{
return (DEV_READ(plic + PLIC_THRESHOLD0_REG) & PLIC_PRIO_MASK);
return (VOLATILE_READ(plic->ip) & intrs) == intrs;
}

uint8_t plic_supervisor_priority_threshold_get(plic_t plic)
bool plic_interrupt_any_pending(plic_t plic, uint32_t intrs)
{
return (DEV_READ(plic + PLIC_THRESHOLD1_REG) & PLIC_PRIO_MASK);
return (VOLATILE_READ(plic->ip) & intrs) != 0u;
}

void plic_machine_priority_threshold_set(plic_t plic, uint8_t prio)
uint8_t plic_machine_priority_threshold_read(plic_t plic)
{
DEV_WRITE(plic + PLIC_THRESHOLD0_REG, prio & PLIC_PRIO_MASK);
plic_threshold0 threshold = VOLATILE_READ(plic->threshold0);
return threshold.threshold0;
}

void plic_supervisor_priority_threshold_set(plic_t plic, uint8_t prio)
uint8_t plic_supervisor_priority_threshold_read(plic_t plic)
{
DEV_WRITE(plic + PLIC_THRESHOLD1_REG, prio & PLIC_PRIO_MASK);
plic_threshold1 threshold = VOLATILE_READ(plic->threshold1);
return threshold.threshold1;
}

uint8_t plic_machine_interrupt_claim(plic_t plic)
void plic_machine_priority_threshold_write(plic_t plic, uint8_t prio)
{
return (uint8_t)DEV_READ(plic + PLIC_CC0_REG);
plic_threshold0 threshold = { .threshold0 = prio };
VOLATILE_WRITE(plic->threshold0, threshold);
}

uint8_t plic_supervisor_interrupt_claim(plic_t plic)
void plic_supervisor_priority_threshold_write(plic_t plic, uint8_t prio)
{
return (uint8_t)DEV_READ(plic + PLIC_CC1_REG);
plic_threshold1 threshold = { .threshold1 = prio };
VOLATILE_WRITE(plic->threshold1, threshold);
}

void plic_machine_interrupt_complete(plic_t plic, uint8_t intr_id)
uint32_t plic_machine_interrupt_claim(plic_t plic)
{
DEV_WRITE(plic + PLIC_CC0_REG, (uint32_t)intr_id);
plic_cc0 claim = VOLATILE_READ(plic->cc0);
return (1u << claim.cc0);
}

void plic_supervisor_interrupt_complete(plic_t plic, uint8_t intr_id)
uint32_t plic_supervisor_interrupt_claim(plic_t plic)
{
DEV_WRITE(plic + PLIC_CC1_REG, (uint32_t)intr_id);
plic_cc1 claim = VOLATILE_READ(plic->cc1);
return (1u << claim.cc1);
}

void plic_alert_trigger(plic_t plic)
void plic_machine_interrupt_complete(plic_t plic, uint32_t intr)
{
DEV_WRITE(plic + PLIC_ALERT_TEST_REG, 1);
if (intr == 0u) {
return;
}
size_t id = __builtin_ctz(intr);
plic_cc0 complete = { .cc0 = id };
VOLATILE_WRITE(plic->cc0, complete);
}

void plic_init(plic_t plic)
void plic_supervisor_interrupt_complete(plic_t plic, uint32_t intr)
{
plic_machine_interrupt_disable_all(plic);
plic_supervisor_interrupt_disable_all(plic);
if (intr == 0u) {
return;
}
size_t id = __builtin_ctz(intr);
plic_cc1 complete = { .cc1 = id };
VOLATILE_WRITE(plic->cc1, complete);
}
62 changes: 23 additions & 39 deletions sw/device/lib/hal/plic.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,30 @@

#pragma once

#include "autogen/plic.h"
#include <stdbool.h>
#include <stdint.h>

#define PLIC_PRIO_REG (0x0)
#define PLIC_PRIO_MASK (0x3)

#define PLIC_IP_REG (0x1000)
#define PLIC_IE0_REG (0x2000)
#define PLIC_IE1_REG (0x2100)
#define PLIC_THRESHOLD0_REG (0x200000)
#define PLIC_THRESHOLD1_REG (0x201000)
#define PLIC_CC0_REG (0x200004)
#define PLIC_CC1_REG (0x201004)
#define PLIC_MSIP0_REG (0x4000000)
#define PLIC_MSIP1_REG (0x4000004)
#define PLIC_ALERT_TEST_REG (0x4004000)

#define PLIC_NUM_SRC (32)

typedef void *plic_t;

uint8_t plic_interrupt_priority_get(plic_t plic, uint8_t intr_id);
void plic_interrupt_priority_set(plic_t plic, uint8_t intr_id, uint8_t prio);
bool plic_interrupt_is_pending(plic_t plic, uint8_t intr_id);
bool plic_machine_interrupt_enable_get(plic_t plic, uint8_t intr_id);
bool plic_supervisor_interrupt_enable_get(plic_t plic, uint8_t intr_id);
void plic_machine_interrupt_enable(plic_t plic, uint8_t intr_id);
void plic_supervisor_interrupt_enable(plic_t plic, uint8_t intr_id);
void plic_machine_interrupt_disable(plic_t plic, uint8_t intr_id);
void plic_supervisor_interrupt_disable(plic_t plic, uint8_t intr_id);
void plic_machine_interrupt_disable_all(plic_t plic);
void plic_supervisor_interrupt_disable_all(plic_t plic);
uint8_t plic_machine_priority_threshold_get(plic_t plic);
uint8_t plic_supervisor_priority_threshold_get(plic_t plic);
void plic_machine_priority_threshold_set(plic_t plic, uint8_t prio);
void plic_supervisor_priority_threshold_set(plic_t plic, uint8_t prio);
uint8_t plic_machine_interrupt_claim(plic_t plic);
uint8_t plic_supervisor_interrupt_claim(plic_t plic);
void plic_machine_interrupt_complete(plic_t plic, uint8_t intr_id);
void plic_supervisor_interrupt_complete(plic_t plic, uint8_t intr_id);
void plic_alert_trigger(plic_t plic);

/* initialistation */
void plic_init(plic_t plic);

uint8_t plic_interrupt_priority_read(plic_t plic, uint32_t intr);
void plic_interrupt_priority_write(plic_t plic, uint32_t intrs, uint8_t prio);
uint32_t plic_machine_interrupt_enable_read(plic_t plic);
uint32_t plic_supervisor_interrupt_enable_read(plic_t plic);
void plic_machine_interrupt_enable_write(plic_t plic, uint32_t intrs);
void plic_supervisor_interrupt_enable_write(plic_t plic, uint32_t intrs);
void plic_machine_interrupt_enable_set(plic_t plic, uint32_t intrs);
void plic_supervisor_interrupt_enable_set(plic_t plic, uint32_t intrs);
void plic_machine_interrupt_enable_clear(plic_t plic, uint32_t intrs);
void plic_supervisor_interrupt_enable_clear(plic_t plic, uint32_t intrs);
bool plic_interrupt_all_pending(plic_t plic, uint32_t intrs);
bool plic_interrupt_any_pending(plic_t plic, uint32_t intrs);
uint8_t plic_machine_priority_threshold_read(plic_t plic);
uint8_t plic_supervisor_priority_threshold_read(plic_t plic);
void plic_machine_priority_threshold_write(plic_t plic, uint8_t prio);
void plic_supervisor_priority_threshold_write(plic_t plic, uint8_t prio);
uint32_t plic_machine_interrupt_claim(plic_t plic);
uint32_t plic_supervisor_interrupt_claim(plic_t plic);
void plic_machine_interrupt_complete(plic_t plic, uint32_t intr);
void plic_supervisor_interrupt_complete(plic_t plic, uint32_t intr);
40 changes: 18 additions & 22 deletions sw/device/tests/plic/smoketest.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,28 @@ bool reg_test(plic_t plic)
{
plic_init(plic);

plic_interrupt_priority_set(plic, 4, 2);
if ((plic_interrupt_priority_get(plic, 4) & PLIC_PRIO_MASK) != 2) {
plic_interrupt_priority_write(plic, 4, 2);
if ((plic_interrupt_priority_read(plic, 4) != 2)) {
return false;
}

plic_machine_interrupt_enable(plic, 22);
if (!plic_machine_interrupt_enable_get(plic, 22)) {
plic_machine_interrupt_enable_set(plic, 1 << 22);
if (!(plic_machine_interrupt_enable_read(plic) & (1 << 22))) {
return false;
}

plic_machine_interrupt_disable(plic, 22);
if (plic_machine_interrupt_enable_get(plic, 22)) {
plic_machine_interrupt_enable_clear(plic, 1 << 22);
if (plic_machine_interrupt_enable_read(plic) & (1 << 22)) {
return false;
}

plic_supervisor_interrupt_enable(plic, 13);
if (!plic_supervisor_interrupt_enable_get(plic, 13)) {
plic_supervisor_interrupt_enable_set(plic, 1 << 13);
if (!(plic_supervisor_interrupt_enable_read(plic) & (1 << 13))) {
return false;
}

plic_supervisor_interrupt_disable(plic, 13);
if (plic_supervisor_interrupt_enable_get(plic, 13)) {
plic_supervisor_interrupt_enable_clear(plic, 1 << 13);
if (plic_supervisor_interrupt_enable_read(plic) & (1 << 13)) {
return false;
}

Expand All @@ -47,17 +47,15 @@ bool reg_test(plic_t plic)

bool uart_machine_irq_test(plic_t plic, uart_t uart)
{
uint8_t intr_id;

const int UART_INTR_ID = 8;
uint32_t intr_id;

plic_init(plic);
plic_interrupt_priority_set(plic, UART_INTR_ID, 3);
plic_machine_priority_threshold_set(plic, 0);
plic_interrupt_priority_write(plic, mocha_system_irq_uart, 3);
plic_machine_priority_threshold_write(plic, 0);

uart_interrupt_enable_write(uart, uart_intr_rx_frame_err);

plic_machine_interrupt_enable(plic, UART_INTR_ID);
plic_machine_interrupt_enable_set(plic, mocha_system_irq_uart);

// Check that mip MEIP is clear
if (hart_interrupt_any_pending(interrupt_machine_external)) {
Expand Down Expand Up @@ -91,17 +89,15 @@ bool uart_machine_irq_test(plic_t plic, uart_t uart)

bool uart_supervisor_irq_test(plic_t plic, uart_t uart)
{
uint8_t intr_id;

const int UART_INTR_ID = 8;
uint32_t intr_id;

plic_init(plic);
plic_interrupt_priority_set(plic, UART_INTR_ID, 3);
plic_supervisor_priority_threshold_set(plic, 0);
plic_interrupt_priority_write(plic, mocha_system_irq_uart, 3);
plic_supervisor_priority_threshold_write(plic, 0);

uart_interrupt_enable_write(uart, uart_intr_rx_timeout);

plic_supervisor_interrupt_enable(plic, UART_INTR_ID);
plic_supervisor_interrupt_enable_set(plic, mocha_system_irq_uart);

// Check that mip SEIP is clear
if (hart_interrupt_any_pending(interrupt_software_external)) {
Expand Down
Loading