Unverified Commit 695e081c authored by Michael Neuling's avatar Michael Neuling Committed by GitHub

Merge pull request #210 from ozbenh/xics

xics: Cleanups and add a simple ICS for use by Linux
parents b90a0a21 bb54af59
......@@ -78,6 +78,16 @@ package common is
type irq_state_t is (WRITE_SRR0, WRITE_SRR1);
-- For now, fixed 16 sources, make this either a parametric
-- package of some sort or an unconstrainted array.
type ics_to_icp_t is record
-- Level interrupts only, ICS just keeps prsenting the
-- highest priority interrupt. Once handling edge, something
-- smarter involving handshake & reject support will be needed
src : std_ulogic_vector(3 downto 0);
pri : std_ulogic_vector(7 downto 0);
end record;
-- This needs to die...
type ctrl_t is record
tb: std_ulogic_vector(63 downto 0);
......
......@@ -11,7 +11,8 @@
#define SYSCON_BASE 0xc0000000 /* System control regs */
#define UART_BASE 0xc0002000 /* UART */
#define XICS_BASE 0xc0004000 /* Interrupt controller */
#define XICS_ICP_BASE 0xc0004000 /* Interrupt controller */
#define XICS_ICS_BASE 0xc0005000 /* Interrupt controller */
#define SPI_FCTRL_BASE 0xc0006000 /* SPI flash controller registers */
#define DRAM_CTRL_BASE 0xc8000000 /* LiteDRAM control registers */
#define SPI_FLASH_BASE 0xf0000000 /* SPI Flash memory map */
......
......@@ -21,6 +21,7 @@ use work.wishbone_types.all;
-- 0xc0000000: SYSCON
-- 0xc0002000: UART0
-- 0xc0004000: XICS ICP
-- 0xc0005000: XICS ICS
-- 0xc0006000: SPI Flash controller
-- 0xc8nnnnnn: External IO bus
-- 0xf0000000: Flash "ROM" mapping
......@@ -130,12 +131,14 @@ architecture behaviour of soc is
signal wb_spiflash_is_reg : std_ulogic;
signal wb_spiflash_is_map : std_ulogic;
-- XICS0 signals:
signal wb_xics0_in : wb_io_master_out;
signal wb_xics0_out : wb_io_slave_out;
signal int_level_in : std_ulogic_vector(15 downto 0);
signal core_ext_irq : std_ulogic;
-- XICS signals:
signal wb_xics_icp_in : wb_io_master_out;
signal wb_xics_icp_out : wb_io_slave_out;
signal wb_xics_ics_in : wb_io_master_out;
signal wb_xics_ics_out : wb_io_slave_out;
signal int_level_in : std_ulogic_vector(15 downto 0);
signal ics_to_icp : ics_to_icp_t;
signal core_ext_irq : std_ulogic;
-- Main memory signals:
signal wb_bram_in : wishbone_master_out;
......@@ -171,7 +174,8 @@ architecture behaviour of soc is
-- IO branch split:
type slave_io_type is (SLAVE_IO_SYSCON,
SLAVE_IO_UART,
SLAVE_IO_ICP_0,
SLAVE_IO_ICP,
SLAVE_IO_ICS,
SLAVE_IO_SPI_FLASH_REG,
SLAVE_IO_SPI_FLASH_MAP,
SLAVE_IO_EXTERNAL,
......@@ -441,7 +445,8 @@ begin
-- IO wishbone slave intercon.
--
slave_io_intercon: process(wb_sio_out, wb_syscon_out, wb_uart0_out,
wb_ext_io_out, wb_xics0_out, wb_spiflash_out)
wb_ext_io_out, wb_xics_icp_out, wb_xics_ics_out,
wb_spiflash_out)
variable slave_io : slave_io_type;
variable match : std_ulogic_vector(31 downto 12);
......@@ -462,7 +467,9 @@ begin
elsif std_match(match, x"C8---") then
slave_io := SLAVE_IO_EXTERNAL;
elsif std_match(match, x"C0004") then
slave_io := SLAVE_IO_ICP_0;
slave_io := SLAVE_IO_ICP;
elsif std_match(match, x"C0005") then
slave_io := SLAVE_IO_ICS;
elsif std_match(match, x"C0006") then
slave_io := SLAVE_IO_SPI_FLASH_REG;
end if;
......@@ -474,11 +481,15 @@ begin
wb_spiflash_is_reg <= '0';
wb_spiflash_is_map <= '0';
-- Only give xics 8 bits of wb addr
wb_xics0_in <= wb_sio_out;
wb_xics0_in.adr <= (others => '0');
wb_xics0_in.adr(7 downto 0) <= wb_sio_out.adr(7 downto 0);
wb_xics0_in.cyc <= '0';
-- Only give xics 8 bits of wb addr (for now...)
wb_xics_icp_in <= wb_sio_out;
wb_xics_icp_in.adr <= (others => '0');
wb_xics_icp_in.adr(7 downto 0) <= wb_sio_out.adr(7 downto 0);
wb_xics_icp_in.cyc <= '0';
wb_xics_ics_in <= wb_sio_out;
wb_xics_ics_in.adr <= (others => '0');
wb_xics_ics_in.adr(11 downto 0) <= wb_sio_out.adr(11 downto 0);
wb_xics_ics_in.cyc <= '0';
wb_ext_io_in <= wb_sio_out;
wb_ext_io_in.cyc <= '0';
......@@ -521,9 +532,12 @@ begin
when SLAVE_IO_UART =>
wb_uart0_in.cyc <= wb_sio_out.cyc;
wb_sio_in <= wb_uart0_out;
when SLAVE_IO_ICP_0 =>
wb_xics0_in.cyc <= wb_sio_out.cyc;
wb_sio_in <= wb_xics0_out;
when SLAVE_IO_ICP =>
wb_xics_icp_in.cyc <= wb_sio_out.cyc;
wb_sio_in <= wb_xics_icp_out;
when SLAVE_IO_ICS =>
wb_xics_ics_in.cyc <= wb_sio_out.cyc;
wb_sio_in <= wb_xics_ics_out;
when SLAVE_IO_SPI_FLASH_MAP =>
-- Clear top bits so they don't make their way to the
-- fash chip.
......@@ -614,17 +628,28 @@ begin
wb_spiflash_out.stall <= wb_spiflash_in.cyc and not wb_spiflash_out.ack;
end generate;
xics0: entity work.xics
xics_icp: entity work.xics_icp
port map(
clk => system_clk,
rst => rst_xics,
wb_in => wb_xics_icp_in,
wb_out => wb_xics_icp_out,
ics_in => ics_to_icp,
core_irq_out => core_ext_irq
);
xics_ics: entity work.xics_ics
generic map(
LEVEL_NUM => 16
SRC_NUM => 16,
PRIO_BITS => 3
)
port map(
clk => system_clk,
rst => rst_xics,
wb_in => wb_xics0_in,
wb_out => wb_xics0_out,
wb_in => wb_xics_ics_in,
wb_out => wb_xics_ics_out,
int_level_in => int_level_in,
core_irq_out => core_ext_irq
icp_out => ics_to_icp
);
-- Assign external interrupts
......
......@@ -9,7 +9,7 @@ CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
OBJCOPY = $(CROSS_COMPILE)objcopy
CFLAGS = -Os -g -Wall -std=c99 -msoft-float -mno-string -mno-multiple -mno-vsx -mno-altivec -mlittle-endian -fno-stack-protector -mstrict-align -ffreestanding -fdata-sections -ffunction-sections -I ../../include
CFLAGS = -Os -g -Wall -std=c99 -nostdinc -msoft-float -mno-string -mno-multiple -mno-vsx -mno-altivec -mlittle-endian -fno-stack-protector -mstrict-align -ffreestanding -fdata-sections -ffunction-sections -I ../../include -isystem $(shell $(CC) -print-file-name=include)
ASFLAGS = $(CFLAGS)
LDFLAGS = -T powerpc.lds
......
No preview for this file type
Test 0:PASS
Test 1:PASS
Test 2:PASS
Test 3:PASS
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <limits.h>
#include "console.h"
#include "xics.h"
......@@ -13,8 +12,8 @@ void delay(void)
{
static volatile int i;
for (i = 0; i < 10; ++i)
;
for (i = 0; i < 16; ++i)
__asm__ volatile("" : : : "memory");
}
void print_number(unsigned int i) // only for i = 0-999
......@@ -75,6 +74,8 @@ void ipi_isr(void) {
debug_puts(IPI);
isrs_run |= ISR_IPI;
icp_write8(XICS_MFRR, 0xff);
}
......@@ -110,6 +111,8 @@ struct isr_op isr_table[] = {
bool ipi_running;
#define ISR "ISR XISR="
#define PRIO " PRIO="
#define CPPR " CPPR="
void isr(void)
{
struct isr_op *op;
......@@ -118,11 +121,15 @@ void isr(void)
assert(!ipi_running); // check we aren't reentrant
ipi_running = true;
xirr = xics_read32(XICS_XIRR); // read hardware irq source
xirr = icp_read32(XICS_XIRR); // read hardware irq source
#ifdef DEBUG
puts(ISR);
print_number(xirr & 0xff);
puts(PRIO);
print_number(xirr >> 24);
puts(CPPR);
print_number(icp_read8(XICS_XIRR_POLL));
puts("\n");
#endif
......@@ -136,7 +143,7 @@ void isr(void)
op++;
}
xics_write32(XICS_XIRR, xirr); // EOI
icp_write32(XICS_XIRR, xirr); // EOI
ipi_running = false;
}
......@@ -144,45 +151,91 @@ void isr(void)
/*****************************************/
int xics_test_0(void)
{
uint32_t v0, v1;
v0 = ics_read_xive(0);
v1 = ics_read_xive(1);
#ifdef DEBUG
puts("\n");
puts("xive(0) bfr: ");
print_number(v0);
puts("\n");
puts("xive(1) bfr: ");
print_number(v1);
puts("\n");
#endif
assert(v0 = 0xff);
assert(v1 = 0xff);
ics_write_xive(0xa, 0);
ics_write_xive(0x5, 1);
v0 = ics_read_xive(0);
v1 = ics_read_xive(1);
#ifdef DEBUG
puts("\n");
puts("xive(0) aft: ");
print_number(v0);
puts("\n");
puts("xive(1) aft: ");
print_number(v1);
puts("\n");
#endif
assert(v0 = 0xa);
assert(v1 = 0x5);
ics_write_xive(0xff, 0);
ics_write_xive(0xff, 1);
v0 = ics_read_xive(0);
v1 = ics_read_xive(1);
assert(v0 = 0xff);
assert(v1 = 0xff);
return 0;
}
int xics_test_1(void)
{
// setup
xics_write8(XICS_XIRR, 0x00); // mask all interrupts
icp_write8(XICS_XIRR, 0x00); // mask all interrupts
isrs_run = 0;
xics_write8(XICS_XIRR, 0x00); // mask all interrupts
icp_write8(XICS_XIRR, 0x00); // mask all interrupts
// trigger two interrupts
potato_uart_irq_en(); // cause 0x500 interrupt
xics_write8(XICS_MFRR, 0x05); // cause 0x500 interrupt
potato_uart_irq_en(); // cause serial interrupt
ics_write_xive(0x6, 0); // set source to prio 6
icp_write8(XICS_MFRR, 0x04); // cause ipi interrupt at prio 5
// still masked, so shouldn't happen yet
delay();
assert(isrs_run == 0);
// unmask IPI only
xics_write8(XICS_XIRR, 0x40);
icp_write8(XICS_XIRR, 0x6);
delay();
assert(isrs_run == ISR_IPI);
// unmask UART
xics_write8(XICS_XIRR, 0xc0);
icp_write8(XICS_XIRR, 0x7);
delay();
assert(isrs_run == (ISR_IPI | ISR_UART));
// cleanup
xics_write8(XICS_XIRR, 0x00); // mask all interrupts
icp_write8(XICS_XIRR, 0x00); // mask all interrupts
potato_uart_irq_dis();
ics_write_xive(0, 0xff);
isrs_run = 0;
return 0;
}
int xics_test_1(void)
int xics_test_2(void)
{
// setup
xics_write8(XICS_XIRR, 0x00); // mask all interrupts
icp_write8(XICS_XIRR, 0x00); // mask all interrupts
isrs_run = 0;
xics_write8(XICS_XIRR, 0xff); // allow all interrupts
icp_write8(XICS_XIRR, 0xff); // allow all interrupts
// should be none pending
delay();
......@@ -190,13 +243,14 @@ int xics_test_1(void)
// trigger both
potato_uart_irq_en(); // cause 0x500 interrupt
xics_write8(XICS_MFRR, 0x05); // cause 0x500 interrupt
icp_write8(XICS_MFRR, 0x05); // cause 0x500 interrupt
delay();
assert(isrs_run == (ISR_IPI | ISR_UART));
// cleanup
xics_write8(XICS_XIRR, 0x00); // mask all interrupts
icp_write8(XICS_XIRR, 0x00); // mask all interrupts
potato_uart_irq_dis();
isrs_run = 0;
return 0;
......@@ -207,19 +261,19 @@ void mtmsrd(uint64_t val)
__asm__ volatile("mtmsrd %0" : : "r" (val));
}
int xics_test_2(void)
int xics_test_3(void)
{
// setup
xics_write8(XICS_XIRR, 0x00); // mask all interrupts
icp_write8(XICS_XIRR, 0x00); // mask all interrupts
isrs_run = 0;
// trigger interrupts with MSR[EE]=0 and show they are not run
mtmsrd(0x9000000000000003); // EE off
xics_write8(XICS_XIRR, 0xff); // allow all interrupts
icp_write8(XICS_XIRR, 0xff); // allow all interrupts
// trigger an IPI
xics_write8(XICS_MFRR, 0x05); // cause 0x500 interrupt
icp_write8(XICS_MFRR, 0x05); // cause 0x500 interrupt
delay();
assert(isrs_run == 0);
......@@ -229,7 +283,7 @@ int xics_test_2(void)
assert(isrs_run == ISR_IPI);
// cleanup
xics_write8(XICS_XIRR, 0x00); // mask all interrupts
icp_write8(XICS_XIRR, 0x00); // mask all interrupts
isrs_run = 0;
return 0;
......@@ -243,6 +297,7 @@ int (*tests[])(void) = {
xics_test_0,
xics_test_1,
xics_test_2,
xics_test_3,
NULL
};
......
#include <stdint.h>
#include "microwatt_soc.h"
#include "io.h"
......@@ -8,22 +7,35 @@
#define XICS_RESV 0x8
#define XICS_MFRR 0xC
uint8_t xics_read8(int offset)
#define bswap32(x) (uint32_t)__builtin_bswap32((uint32_t)(x))
uint8_t icp_read8(int offset)
{
return readb(XICS_ICP_BASE + offset);
}
void icp_write8(int offset, uint8_t val)
{
return readb(XICS_BASE + offset);
writeb(val, XICS_ICP_BASE + offset);
}
void xics_write8(int offset, uint8_t val)
uint32_t icp_read32(int offset)
{
writeb(val, XICS_BASE + offset);
return bswap32(readl(XICS_ICP_BASE + offset));
}
uint32_t xics_read32(int offset)
static inline void icp_write32(int offset, uint32_t val)
{
return readl(XICS_BASE + offset);
writel(bswap32(val), XICS_ICP_BASE + offset);
}
void xics_write32(int offset, uint32_t val)
uint32_t ics_read_xive(int irq)
{
writel(val, XICS_BASE + offset);
return bswap32(readl(XICS_ICS_BASE + 0x800 + (irq << 2)));
}
void ics_write_xive(uint32_t val, int irq)
{
writel(bswap32(val), XICS_ICS_BASE + 0x800 + (irq << 2));
}
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment