mirror of
https://github.com/fail0verflow/mini.git
synced 2025-02-17 12:06:20 +01:00
Clean up hollywood, IRQ, IPC, match Wiibrew
This commit is contained in:
parent
75017b64a4
commit
5bfe8f17d9
67
hollywood.h
67
hollywood.h
@ -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
35
ipc.c
@ -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
36
irq.c
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user