Clean up hollywood, IRQ, IPC, match Wiibrew

This commit is contained in:
marcan 2009-03-18 18:05:23 +01:00 committed by bushing
parent 75017b64a4
commit 5bfe8f17d9
3 changed files with 51 additions and 87 deletions

View File

@ -7,74 +7,19 @@
#define HW_REG_BASE 0xd800000
// The PPC can only see the first three IPC registers
#define HW_IPC_PPCMSG (HW_REG_BASE + 0x000) //PPC to ARM
#define HW_IPC_PPCMSG (HW_REG_BASE + 0x000)
#define HW_IPC_PPCCTRL (HW_REG_BASE + 0x004)
#define HW_IPC_ARMMSG (HW_REG_BASE + 0x008) //ARM to PPC
#define HW_IPC_ARMMSG (HW_REG_BASE + 0x008)
#define HW_IPC_ARMCTRL (HW_REG_BASE + 0x00c)
// Write one to send a message. Cleared when peer writes one to IPC_CTRL_RECV.
#define IPC_CTRL_SEND 0x01
// Set by peer to acknowledge a message. Write one to clear.
#define IPC_CTRL_SENT 0x02
// Set by peer to send a message. Write one to clear.
#define IPC_CTRL_RECV 0x04
// Write one acknowledge a message. Cleared when peer writes one to IPC_CTRL_SENT.
#define IPC_CTRL_RECVD 0x08
// Enable interrupt when a message is received
#define IPC_CTRL_INT_RECV 0x10
// Enable interrupt when a sent message is acknowledged
#define IPC_CTRL_INT_SENT 0x20
/*
The IPC registers are connected to each other.
Both registers are identical and this works for
both peers. Flag bits are cleared by writing a one
to them.
When Peer A sets this Peer B sees this set
IPC_CTRL_SEND IPC_CTRL_RECV
IPC_CTRL_RECVD IPC_CTRL_SENT
In fact, bit _SEND on Peer A and bit _RECV on peer B are the same bit,
and the same goes for _RECVD and _SENT, except writing one from A _sets_
the bit, and writing one from B _clears_ the bit. The same, of course,
is true for the other pair of bits in the other direction.
The flow, therefore, goes as follows, for a message
from A to B. Steps with the same number can be taken
in any order.
1. Peer A writes the message address to the register
2. Peer A sets IPC_CTRL_SEND
3. Peer B sees IPC_CTRL_RECV
4. Peer B writes one to IPC_CTRL_RECV to clear it (A's IPC_CTRL_SEND is cleared at this point)
4. Peer B reads its message address register
5. Peer B sets IPC_CTRL_RECVD
6. Peer A sees IPC_CTRL_SENT
7. Peer A writes one to IPC_CTRL_SENT to clear it (B's IPC_CTRL_RECVD is cleared at this point)
7. Peer A may now write to the message address register again
The same is true for a message from Peer B to Peer A.
In the particular case of IOS IPC, the PPC is always the "master"
(it sends requests as messages) and the ARM is always the "slave"
(it replies to PPC's requests). IOS can handle up to 16(15?)
simultaneously pending transactions (the PPC can send up to 16(15?)
messages without getting any replies - for example, due to
asynchronous requests or multithreaded execution of blocking
requests)
*/
#define HW_TIMER (HW_REG_BASE + 0x010)
#define HW_ALARM (HW_REG_BASE + 0x014)
// maybe?
#define HW_FIQFLAG (HW_REG_BASE + 0x030)
#define HW_FIQENABLE (HW_REG_BASE + 0x034)
#define HW_PPCIRQFLAG (HW_REG_BASE + 0x030)
#define HW_PPCIRQMASK (HW_REG_BASE + 0x034)
#define HW_IRQFLAG (HW_REG_BASE + 0x038)
#define HW_IRQENABLE (HW_REG_BASE + 0x03c)
#define HW_ARMIRQFLAG (HW_REG_BASE + 0x038)
#define HW_ARMIRQMASK (HW_REG_BASE + 0x03c)
#define HW_MEMMIRR (HW_REG_BASE + 0x060)

35
ipc.c
View File

@ -18,6 +18,25 @@ static volatile ipc_request slow_queue[IPC_SLOW_SIZE];
extern char __mem2_area_start[];
// These defines are for the ARMCTRL regs
// See http://wiibrew.org/wiki/Hardware/IPC
#define IPC_CTRL_Y1 0x01
#define IPC_CTRL_X2 0x02
#define IPC_CTRL_X1 0x04
#define IPC_CTRL_Y2 0x08
#define IPC_CTRL_IX1 0x10
#define IPC_CTRL_IX2 0x20
// Our definitions for this IPC interface
#define IPC_CTRL_OUT IPC_CTRL_Y1
#define IPC_CTRL_IN IPC_CTRL_X1
#define IPC_CTRL_IRQ_IN IPC_CTRL_IX1
// reset both flags (X* for ARM and Y* for PPC)
#define IPC_CTRL_RESET 0x06
const ipc_infohdr __ipc_info ALIGNED(32) MEM2_RODATA = {
.magic = "IPC",
.version = 1,
@ -74,7 +93,7 @@ void ipc_post(u32 code, u32 tag, u32 num_args, ...)
dc_flushrange((void*)&out_queue[out_tail], 32);
out_tail = (out_tail+1)&(IPC_OUT_SIZE-1);
poke_outtail(out_tail);
write32(HW_IPC_ARMCTRL, IPC_CTRL_INT_RECV | IPC_CTRL_SEND);
write32(HW_IPC_ARMCTRL, IPC_CTRL_IRQ_IN | IPC_CTRL_OUT);
irq_restore(cookie);
}
@ -204,8 +223,8 @@ static void process_in(void)
void ipc_irq(void)
{
int donebell = 0;
while(read32(HW_IPC_ARMCTRL) & IPC_CTRL_RECV) {
write32(HW_IPC_ARMCTRL, IPC_CTRL_INT_RECV | IPC_CTRL_RECV);
while(read32(HW_IPC_ARMCTRL) & IPC_CTRL_IN) {
write32(HW_IPC_ARMCTRL, IPC_CTRL_IRQ_IN | IPC_CTRL_IN);
while(peek_intail() != in_head) {
process_in();
in_head = (in_head+1)&(IPC_IN_SIZE-1);
@ -221,22 +240,22 @@ void ipc_initialize(void)
{
write32(HW_IPC_ARMMSG, 0);
write32(HW_IPC_PPCMSG, 0);
write32(HW_IPC_PPCCTRL, IPC_CTRL_SENT|IPC_CTRL_RECV);
write32(HW_IPC_ARMCTRL, IPC_CTRL_SENT|IPC_CTRL_RECV);
write32(HW_IPC_PPCCTRL, IPC_CTRL_RESET);
write32(HW_IPC_ARMCTRL, IPC_CTRL_RESET);
slow_queue_head = 0;
slow_queue_tail = 0;
in_head = 0;
out_tail = 0;
irq_enable(IRQ_IPC);
write32(HW_IPC_ARMCTRL, IPC_CTRL_INT_RECV);
write32(HW_IPC_ARMCTRL, IPC_CTRL_IRQ_IN);
}
void ipc_shutdown(void)
{
write32(HW_IPC_ARMMSG, 0);
write32(HW_IPC_PPCMSG, 0);
write32(HW_IPC_PPCCTRL, IPC_CTRL_SENT|IPC_CTRL_RECV);
write32(HW_IPC_ARMCTRL, IPC_CTRL_SENT|IPC_CTRL_RECV);
write32(HW_IPC_PPCCTRL, IPC_CTRL_RESET);
write32(HW_IPC_ARMCTRL, IPC_CTRL_RESET);
irq_disable(IRQ_IPC);
}

36
irq.c
View File

@ -11,26 +11,26 @@ void irq_setup_stack(void);
void irq_initialize(void)
{
irq_setup_stack();
write32(HW_IRQENABLE, 0);
write32(HW_IRQFLAG, 0xffffffff);
write32(HW_ARMIRQMASK, 0);
write32(HW_ARMIRQFLAG, 0xffffffff);
irq_restore(CPSR_FIQDIS);
//???
write32(HW_IRQENABLE+0x04, 0);
write32(HW_IRQENABLE+0x20, 0);
write32(HW_ARMIRQMASK+0x04, 0);
write32(HW_ARMIRQMASK+0x20, 0);
}
void irq_shutdown(void)
{
write32(HW_IRQENABLE, 0);
write32(HW_IRQFLAG, 0xffffffff);
write32(HW_ARMIRQMASK, 0);
write32(HW_ARMIRQFLAG, 0xffffffff);
irq_kill();
}
void irq_handler(void)
{
u32 enabled = read32(HW_IRQENABLE);
u32 flags = read32(HW_IRQFLAG);
u32 enabled = read32(HW_ARMIRQMASK);
u32 flags = read32(HW_ARMIRQFLAG);
//gecko_printf("In IRQ handler: 0x%08x 0x%08x 0x%08x\n", enabled, flags, flags & enabled);
@ -41,50 +41,50 @@ void irq_handler(void)
gecko_printf("Timer: %08x\n", read32(HW_TIMER));
gecko_printf("Alarm: %08x\n", read32(HW_ALARM));
write32(HW_ALARM, 0); // shut it up
write32(HW_IRQFLAG, IRQF_TIMER);
write32(HW_ARMIRQFLAG, IRQF_TIMER);
}
if(flags & IRQF_NAND) {
// gecko_printf("IRQ: NAND\n");
write32(NAND_CMD, 0x7fffffff); // shut it up
write32(HW_IRQFLAG, IRQF_NAND);
write32(HW_ARMIRQFLAG, IRQF_NAND);
nand_irq();
}
if(flags & IRQF_GPIO1B) {
gecko_printf("IRQ: GPIO1B\n");
write32(HW_GPIO1BINTFLAG, 0xFFFFFF); // shut it up
write32(HW_IRQFLAG, IRQF_GPIO1B);
write32(HW_ARMIRQFLAG, IRQF_GPIO1B);
}
if(flags & IRQF_GPIO1) {
gecko_printf("IRQ: GPIO1\n");
write32(HW_GPIO1INTFLAG, 0xFFFFFF); // shut it up
write32(HW_IRQFLAG, IRQF_GPIO1);
write32(HW_ARMIRQFLAG, IRQF_GPIO1);
}
if(flags & IRQF_RESET) {
gecko_printf("IRQ: RESET\n");
write32(HW_IRQFLAG, IRQF_RESET);
write32(HW_ARMIRQFLAG, IRQF_RESET);
}
if(flags & IRQF_IPC) {
//gecko_printf("IRQ: IPC\n");
ipc_irq();
write32(HW_IRQFLAG, IRQF_IPC);
write32(HW_ARMIRQFLAG, IRQF_IPC);
}
if(flags & IRQF_AES) {
gecko_printf("IRQ: AES\n");
write32(HW_IRQFLAG, IRQF_AES);
write32(HW_ARMIRQFLAG, IRQF_AES);
}
flags &= ~IRQF_ALL;
if(flags) {
gecko_printf("IRQ: unknown 0x%08x\n", flags);
write32(HW_IRQFLAG, flags);
write32(HW_ARMIRQFLAG, flags);
}
}
void irq_enable(u32 irq)
{
set32(HW_IRQENABLE, 1<<irq);
set32(HW_ARMIRQMASK, 1<<irq);
}
void irq_disable(u32 irq)
{
clear32(HW_IRQENABLE, 1<<irq);
clear32(HW_ARMIRQMASK, 1<<irq);
}