summaryrefslogtreecommitdiff
path: root/grlib.c
diff options
context:
space:
mode:
authorJiri Gaisler <jiri@gaisler.se>2021-04-11 20:20:15 +0200
committerJiri Gaisler <jiri@gaisler.se>2021-06-10 22:04:11 +0200
commit88914409e05680b1bf0731f6a2abb6716fb2020f (patch)
tree5e258c8978535f7a0ef63142848ddcb2e487b2e0 /grlib.c
parent73267b6a278293b795502193869efda25b2f2a42 (diff)
Added simple RISC-V PLIC functionality for NS16550 interrupt
* RTEMS spconsole01 test now passes
Diffstat (limited to 'grlib.c')
-rw-r--r--grlib.c263
1 files changed, 197 insertions, 66 deletions
diff --git a/grlib.c b/grlib.c
index fc99df9..7982059 100644
--- a/grlib.c
+++ b/grlib.c
@@ -244,7 +244,7 @@ greth_add (int irq, uint32 addr, uint32 mask)
GRLIB_PP_APBADDR (addr, mask));
greth_irq = irq;
if (sis_verbose)
- printf(" GRETH 10/100 Mbit Ethernet core 0x%08x %d\n", addr, irq);
+ printf (" GRETH 10/100 Mbit Ethernet core 0x%08x %d\n", addr, irq);
}
const struct grlib_ipcore greth = {
@@ -259,7 +259,7 @@ leon3_add ()
{
grlib_ahbmpp_add (GRLIB_PP_ID (VENDOR_GAISLER, GAISLER_LEON3, 0, 0));
if (sis_verbose)
- printf(" LEON3 SPARC V8 processor \n");
+ printf (" LEON3 SPARC V8 processor \n");
}
const struct grlib_ipcore leon3s = {
@@ -334,7 +334,7 @@ apbmst_add (int irq, uint32 addr, uint32 mask)
grlib_ahbspp_add (GRLIB_PP_ID (VENDOR_GAISLER, GAISLER_APBMST, 0, 0),
GRLIB_PP_AHBADDR (addr, mask, 0, 0, 2), 0, 0, 0);
if (sis_verbose)
- printf(" AHB/APB Bridge 0x%08x\n", addr);
+ printf (" AHB/APB Bridge 0x%08x\n", addr);
}
const struct grlib_ipcore apbmst = {
@@ -598,7 +598,7 @@ irqmp_add (int irq, uint32 addr, uint32 mask)
grlib_apbpp_add (GRLIB_PP_ID (VENDOR_GAISLER, GAISLER_IRQMP, 2, 0),
GRLIB_PP_APBADDR (addr, mask));
if (sis_verbose)
- printf(" IRQMP Interrupt controller 0x%08x\n", addr);
+ printf (" IRQMP Interrupt controller 0x%08x\n", addr);
}
const struct grlib_ipcore irqmp = {
@@ -671,7 +671,7 @@ gpt_add (int irq, uint32 addr, uint32 mask)
GRLIB_PP_APBADDR (addr, mask));
gpt_irq = irq;
if (sis_verbose)
- printf(" GPTIMER timer unit 0x%08x %d\n", addr, irq);
+ printf (" GPTIMER timer unit 0x%08x %d\n", addr, irq);
}
static void
@@ -1223,7 +1223,7 @@ apbuart_add (int irq, uint32 addr, uint32 mask)
grlib_apbpp_add (GRLIB_PP_ID (VENDOR_GAISLER, GAISLER_APBUART, 1, irq),
GRLIB_PP_APBADDR (addr, mask));
if (sis_verbose)
- printf(" APBUART serial port 0x%08x %d\n", addr, irq);
+ printf (" APBUART serial port 0x%08x %d\n", addr, irq);
}
const struct grlib_ipcore apbuart = {
@@ -1280,7 +1280,7 @@ sdctrl_add (int irq, uint32 addr, uint32 mask)
grlib_ahbspp_add (GRLIB_PP_ID (VENDOR_GAISLER, GAISLER_SDCTRL, 0, 0),
GRLIB_PP_AHBADDR (addr, mask, 1, 1, 2), 0, 0, 0);
if (sis_verbose)
- printf(" SDRAM controller %d M 0x%08x\n",
+ printf (" SDRAM controller %d M 0x%08x\n",
(~(mask << 20) + 1) >> 20, addr);
}
@@ -1311,7 +1311,7 @@ srctrl_add (int irq, uint32 addr, uint32 mask)
grlib_ahbspp_add (GRLIB_PP_ID (VENDOR_GAISLER, GAISLER_SRCTRL, 0, 0),
GRLIB_PP_AHBADDR (addr, mask, 1, 1, 2), 0, 0, 0);
if (sis_verbose)
- printf(" PROM controller %d M 0x%08x\n",
+ printf (" PROM controller %d M 0x%08x\n",
(~(mask << 20) + 1) >> 20, addr);
}
@@ -1334,48 +1334,69 @@ grlib_boot_init (void)
}
/* ------------------- ns16550 -----------------------*/
-
-static int32 uart_lcr;
+static void plic_irq (int irq);
+static int32 uart_lcr, uart_ie, uart_mcr, ns16550_irq, uart_txctrl;
static void
ns16550_add (int irq, uint32 addr, uint32 mask)
{
grlib_ahbspp_add (GRLIB_PP_ID (VENDOR_CONTRIB, CONTRIB_NS16550, 0, 0),
GRLIB_PP_AHBADDR (addr, mask, 0, 0, 2), 0, 0, 0);
+ ns16550_irq = irq;
if (sis_verbose)
- printf(" NS16550 UART 0x%08x %d\n", addr, irq);
+ printf (" NS16550 UART 0x%08x %d\n", addr, irq);
}
static int
ns16550_write (uint32 addr, uint32 * data, uint32 sz)
{
- switch (addr & 0xff)
+ switch (addr & 0xff)
+ {
+ case 0:
+ if (!uart_lcr)
{
- case 0:
- if (!uart_lcr)
- putchar (*data & 0xff);
- break;
- case 0x0c:
- uart_lcr = *data & 0x80;
- break;
+ putchar (*data & 0xff);
}
+ break;
+ case 4:
+ if (!uart_lcr)
+ uart_ie = *data & 0xff;
+ break;
+ case 0x08:
+ uart_txctrl = *data & 0xff;
+ break;
+ case 0x0c:
+ uart_lcr = *data & 0x80;
+ break;
+ case 0x10:
+ uart_mcr = *data & 0xff;
+ break;
+ }
+ if ((uart_ie & 0x2) && (uart_mcr & 0x8))
+ plic_irq (ns16550_irq);
return 1;
}
static int
ns16550_read (uint32 addr, uint32 * data)
{
- *data = 0;
- switch (addr & 0xff)
- {
- case 0x10:
- *data = 0x03;
- break;
- case 0x14:
- *data = 0x60;
- break;
- }
+ *data = 0;
+ switch (addr & 0xff)
+ {
+ case 0x04:
+ *data = uart_ie;
+ break;
+ case 0x08:
+ *data = uart_txctrl;
+ break;
+ case 0x10:
+ *data = uart_mcr; //0x03;
+ break;
+ case 0x14:
+ *data = 0x60;
+ break;
+ }
return 4;
}
@@ -1383,6 +1404,8 @@ static void
ns16550_reset (void)
{
uart_lcr = 0;
+ uart_ie = 0;
+ uart_mcr = 0;
}
const struct grlib_ipcore ns16550 = {
@@ -1397,7 +1420,7 @@ clint_add (int irq, uint32 addr, uint32 mask)
grlib_ahbspp_add (GRLIB_PP_ID (VENDOR_CONTRIB, CONTRIB_CLINT, 0, 0),
GRLIB_PP_AHBADDR (addr, mask, 0, 0, 2), 0, 0, 0);
if (sis_verbose)
- printf(" CLINT Interrupt controller 0x%08x %d\n", addr, irq);
+ printf (" CLINT Interrupt controller 0x%08x %d\n", addr, irq);
}
#define CLINTSTART 0x00000
@@ -1410,29 +1433,29 @@ clint_read (uint32 addr, uint32 * data)
uint64 tmp;
int reg, cpuid;
- reg = (addr >> 2) & 1;
- cpuid = ((addr >> 3) % NCPU);
- if ((addr >= CLINT_TIMEBASE) && (addr < CLINTEND))
- {
- tmp = ebase.simtime >> 32;
- if (reg)
- *data = tmp & 0xffffffff;
- else
- *data = ebase.simtime & 0xffffffff;
- }
- else if ((addr >= CLINT_TIMECMP) && (addr < CLINT_TIMEBASE))
- {
- tmp = sregs[cpuid].mtimecmp >> 32;
- if (reg)
- *data = tmp & 0xffffffff;
- else
- *data = sregs[cpuid].mtimecmp & 0xffffffff;
- }
- else if ((addr >= 0) && (addr < CLINT_TIMECMP))
- {
- cpuid = ((addr >> 2) % NCPU);
- *data = ((sregs[cpuid].mip & MIP_MSIP) >> 4) & 1;
- }
+ reg = (addr >> 2) & 1;
+ cpuid = ((addr >> 3) % NCPU);
+ if ((addr >= CLINT_TIMEBASE) && (addr < CLINTEND))
+ {
+ tmp = ebase.simtime >> 32;
+ if (reg)
+ *data = tmp & 0xffffffff;
+ else
+ *data = ebase.simtime & 0xffffffff;
+ }
+ else if ((addr >= CLINT_TIMECMP) && (addr < CLINT_TIMEBASE))
+ {
+ tmp = sregs[cpuid].mtimecmp >> 32;
+ if (reg)
+ *data = tmp & 0xffffffff;
+ else
+ *data = sregs[cpuid].mtimecmp & 0xffffffff;
+ }
+ else if ((addr >= 0) && (addr < CLINT_TIMECMP))
+ {
+ cpuid = ((addr >> 2) % NCPU);
+ *data = ((sregs[cpuid].mip & MIP_MSIP) >> 4) & 1;
+ }
return 4;
}
@@ -1495,7 +1518,115 @@ const struct grlib_ipcore clint = {
};
/* ------------------- plic --------------------------*/
-/* no functionality supported for now */
+/* simplified functionality supported for now */
+
+#define PLIC_PRIO 0
+#define PLIC_IPEND 0x1000
+#define PLIC_IENA 0x2000
+#define PLIC_THRES 0x200000
+#define PLIC_CLAIM 0x200004
+#define PLIC_MASK1 0xFC
+
+static unsigned char plic_prio[64];
+static uint32 plic_ie[NCPU][2];
+static uint32 plic_ip[2];
+static uint32 plic_thres[NCPU];
+static uint32 plic_claim[NCPU];
+
+static void
+plic_check_irq (uint32 hart)
+{
+ int i, irq;
+ if (irq = (plic_ie[hart][0] & plic_ip[0]))
+ {
+ for (i = 1; i < 32; i++)
+ {
+ if ((irq >> i) & 1)
+ plic_claim[hart] = i;
+ }
+ sregs[hart].mip |= MIP_MEIP;
+ }
+}
+
+static void
+plic_irq (int irq)
+{
+ int i;
+ plic_ip[0] |= (1 << irq);
+ for (i = 0; i < NCPU; i++)
+ {
+ plic_check_irq (i);
+ rv32_check_lirq (i);
+ }
+}
+
+static int
+plic_read (uint32 addr, uint32 * data)
+{
+ int hart;
+ if (addr >= PLIC_THRES)
+ {
+ hart = ((addr >> 12) & 0x0F) % NCPU;
+ if ((addr & PLIC_MASK1) == 0)
+ *data = plic_thres[hart]; // irq threshold, not used for now
+ else
+ {
+ *data = plic_claim[hart];
+ plic_claim[hart] = 0;
+ plic_ip[0] &= ~(1 << *data);
+ }
+ }
+ else if (addr >= PLIC_IENA)
+ {
+ hart = ((addr >> 7) & 0x0F) % NCPU;
+ if (addr & 4)
+ *data = plic_ie[hart][1]; // irq enable
+ else
+ *data = plic_ie[hart][0];
+ }
+ else if (addr >= PLIC_IPEND)
+ {
+ hart = ((addr >> 7) & 0x0F) % NCPU;
+ if (addr & 4)
+ *data = plic_ip[1]; // irq pending
+ else
+ *data = plic_ip[0];
+ }
+ else if (addr < PLIC_IPEND)
+ {
+ *data = plic_prio[(addr & 0x0ff) >> 2]; // irq priority, not used for now
+ }
+ if (sis_verbose)
+ printf (" PLIC read 0x%08x %d\n", addr, *data);
+ return 4;
+}
+
+static int
+plic_write (uint32 addr, uint32 * data, uint32 sz)
+{
+ int hart;
+ if (addr >= PLIC_THRES)
+ {
+ hart = ((addr >> 12) & 0x0F) % NCPU;
+ if ((addr & PLIC_MASK1) == 0)
+ plic_thres[hart] = *data; // irq threshold, not used for now
+ else
+ plic_check_irq (hart); // irq completion
+ }
+ else if (addr >= PLIC_IENA)
+ {
+ hart = ((addr >> 7) & 0x0F) % NCPU;
+ if (addr & 4)
+ plic_ie[hart][1] = *data; // irq enable
+ else
+ plic_ie[hart][0] = *data;
+ }
+ else if (addr < PLIC_IPEND)
+ {
+ plic_prio[(addr & 0x0ff) >> 2] = *data; // irq priority, not used for now
+ }
+ return 1;
+}
static void
plic_add (int irq, uint32 addr, uint32 mask)
@@ -1503,11 +1634,11 @@ plic_add (int irq, uint32 addr, uint32 mask)
grlib_ahbspp_add (GRLIB_PP_ID (VENDOR_CONTRIB, CONTRIB_PLIC, 0, 0),
GRLIB_PP_AHBADDR (addr, mask, 0, 0, 2), 0, 0, 0);
if (sis_verbose)
- printf(" PLIC Interrupt controller 0x%08x %d\n", addr, irq);
+ printf (" PLIC Interrupt controller 0x%08x %d\n", addr, irq);
}
const struct grlib_ipcore plic = {
- NULL, NULL, NULL, NULL, plic_add
+ NULL, NULL, plic_read, plic_write, plic_add
};
/* ------------------- sifive test module --------------*/
@@ -1518,17 +1649,17 @@ s5test_write (uint32 addr, uint32 * data, uint32 sz)
{
int i;
- switch (addr & 0xff)
+ switch (addr & 0xff)
+ {
+ case 0:
+ if (*data == 0x5555)
{
- case 0:
- if (*data == 0x5555)
- {
- printf ("Power-off issued, exiting ...\n");
- for (i=0; i< ncpu; i++)
- sregs[i].trap = ERROR_TRAP;
- }
- break;
+ printf ("Power-off issued, exiting ...\n");
+ for (i = 0; i < ncpu; i++)
+ sregs[i].trap = ERROR_TRAP;
}
+ break;
+ }
return 1;
}
@@ -1539,7 +1670,7 @@ s5test_add (int irq, uint32 addr, uint32 mask)
grlib_ahbspp_add (GRLIB_PP_ID (VENDOR_CONTRIB, CONTRIB_S5TEST, 0, 0),
GRLIB_PP_AHBADDR (addr, mask, 0, 0, 2), 0, 0, 0);
if (sis_verbose)
- printf(" S5 Test module 0x%08x %d\n", addr, irq);
+ printf (" S5 Test module 0x%08x %d\n", addr, irq);
}
const struct grlib_ipcore s5test = {