mirror of
https://github.com/fail0verflow/mini.git
synced 2025-02-21 13:57:11 +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
|
#define HW_REG_BASE 0xd800000
|
||||||
|
|
||||||
// The PPC can only see the first three IPC registers
|
// 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_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)
|
#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_TIMER (HW_REG_BASE + 0x010)
|
||||||
#define HW_ALARM (HW_REG_BASE + 0x014)
|
#define HW_ALARM (HW_REG_BASE + 0x014)
|
||||||
|
|
||||||
// maybe?
|
#define HW_PPCIRQFLAG (HW_REG_BASE + 0x030)
|
||||||
#define HW_FIQFLAG (HW_REG_BASE + 0x030)
|
#define HW_PPCIRQMASK (HW_REG_BASE + 0x034)
|
||||||
#define HW_FIQENABLE (HW_REG_BASE + 0x034)
|
|
||||||
|
|
||||||
#define HW_IRQFLAG (HW_REG_BASE + 0x038)
|
#define HW_ARMIRQFLAG (HW_REG_BASE + 0x038)
|
||||||
#define HW_IRQENABLE (HW_REG_BASE + 0x03c)
|
#define HW_ARMIRQMASK (HW_REG_BASE + 0x03c)
|
||||||
|
|
||||||
#define HW_MEMMIRR (HW_REG_BASE + 0x060)
|
#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[];
|
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 = {
|
const ipc_infohdr __ipc_info ALIGNED(32) MEM2_RODATA = {
|
||||||
.magic = "IPC",
|
.magic = "IPC",
|
||||||
.version = 1,
|
.version = 1,
|
||||||
@ -74,7 +93,7 @@ void ipc_post(u32 code, u32 tag, u32 num_args, ...)
|
|||||||
dc_flushrange((void*)&out_queue[out_tail], 32);
|
dc_flushrange((void*)&out_queue[out_tail], 32);
|
||||||
out_tail = (out_tail+1)&(IPC_OUT_SIZE-1);
|
out_tail = (out_tail+1)&(IPC_OUT_SIZE-1);
|
||||||
poke_outtail(out_tail);
|
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);
|
irq_restore(cookie);
|
||||||
}
|
}
|
||||||
@ -204,8 +223,8 @@ static void process_in(void)
|
|||||||
void ipc_irq(void)
|
void ipc_irq(void)
|
||||||
{
|
{
|
||||||
int donebell = 0;
|
int donebell = 0;
|
||||||
while(read32(HW_IPC_ARMCTRL) & IPC_CTRL_RECV) {
|
while(read32(HW_IPC_ARMCTRL) & IPC_CTRL_IN) {
|
||||||
write32(HW_IPC_ARMCTRL, IPC_CTRL_INT_RECV | IPC_CTRL_RECV);
|
write32(HW_IPC_ARMCTRL, IPC_CTRL_IRQ_IN | IPC_CTRL_IN);
|
||||||
while(peek_intail() != in_head) {
|
while(peek_intail() != in_head) {
|
||||||
process_in();
|
process_in();
|
||||||
in_head = (in_head+1)&(IPC_IN_SIZE-1);
|
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_ARMMSG, 0);
|
||||||
write32(HW_IPC_PPCMSG, 0);
|
write32(HW_IPC_PPCMSG, 0);
|
||||||
write32(HW_IPC_PPCCTRL, IPC_CTRL_SENT|IPC_CTRL_RECV);
|
write32(HW_IPC_PPCCTRL, IPC_CTRL_RESET);
|
||||||
write32(HW_IPC_ARMCTRL, IPC_CTRL_SENT|IPC_CTRL_RECV);
|
write32(HW_IPC_ARMCTRL, IPC_CTRL_RESET);
|
||||||
slow_queue_head = 0;
|
slow_queue_head = 0;
|
||||||
slow_queue_tail = 0;
|
slow_queue_tail = 0;
|
||||||
in_head = 0;
|
in_head = 0;
|
||||||
out_tail = 0;
|
out_tail = 0;
|
||||||
irq_enable(IRQ_IPC);
|
irq_enable(IRQ_IPC);
|
||||||
write32(HW_IPC_ARMCTRL, IPC_CTRL_INT_RECV);
|
write32(HW_IPC_ARMCTRL, IPC_CTRL_IRQ_IN);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ipc_shutdown(void)
|
void ipc_shutdown(void)
|
||||||
{
|
{
|
||||||
write32(HW_IPC_ARMMSG, 0);
|
write32(HW_IPC_ARMMSG, 0);
|
||||||
write32(HW_IPC_PPCMSG, 0);
|
write32(HW_IPC_PPCMSG, 0);
|
||||||
write32(HW_IPC_PPCCTRL, IPC_CTRL_SENT|IPC_CTRL_RECV);
|
write32(HW_IPC_PPCCTRL, IPC_CTRL_RESET);
|
||||||
write32(HW_IPC_ARMCTRL, IPC_CTRL_SENT|IPC_CTRL_RECV);
|
write32(HW_IPC_ARMCTRL, IPC_CTRL_RESET);
|
||||||
irq_disable(IRQ_IPC);
|
irq_disable(IRQ_IPC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
36
irq.c
36
irq.c
@ -11,26 +11,26 @@ void irq_setup_stack(void);
|
|||||||
void irq_initialize(void)
|
void irq_initialize(void)
|
||||||
{
|
{
|
||||||
irq_setup_stack();
|
irq_setup_stack();
|
||||||
write32(HW_IRQENABLE, 0);
|
write32(HW_ARMIRQMASK, 0);
|
||||||
write32(HW_IRQFLAG, 0xffffffff);
|
write32(HW_ARMIRQFLAG, 0xffffffff);
|
||||||
irq_restore(CPSR_FIQDIS);
|
irq_restore(CPSR_FIQDIS);
|
||||||
|
|
||||||
//???
|
//???
|
||||||
write32(HW_IRQENABLE+0x04, 0);
|
write32(HW_ARMIRQMASK+0x04, 0);
|
||||||
write32(HW_IRQENABLE+0x20, 0);
|
write32(HW_ARMIRQMASK+0x20, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void irq_shutdown(void)
|
void irq_shutdown(void)
|
||||||
{
|
{
|
||||||
write32(HW_IRQENABLE, 0);
|
write32(HW_ARMIRQMASK, 0);
|
||||||
write32(HW_IRQFLAG, 0xffffffff);
|
write32(HW_ARMIRQFLAG, 0xffffffff);
|
||||||
irq_kill();
|
irq_kill();
|
||||||
}
|
}
|
||||||
|
|
||||||
void irq_handler(void)
|
void irq_handler(void)
|
||||||
{
|
{
|
||||||
u32 enabled = read32(HW_IRQENABLE);
|
u32 enabled = read32(HW_ARMIRQMASK);
|
||||||
u32 flags = read32(HW_IRQFLAG);
|
u32 flags = read32(HW_ARMIRQFLAG);
|
||||||
|
|
||||||
//gecko_printf("In IRQ handler: 0x%08x 0x%08x 0x%08x\n", enabled, flags, flags & enabled);
|
//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("Timer: %08x\n", read32(HW_TIMER));
|
||||||
gecko_printf("Alarm: %08x\n", read32(HW_ALARM));
|
gecko_printf("Alarm: %08x\n", read32(HW_ALARM));
|
||||||
write32(HW_ALARM, 0); // shut it up
|
write32(HW_ALARM, 0); // shut it up
|
||||||
write32(HW_IRQFLAG, IRQF_TIMER);
|
write32(HW_ARMIRQFLAG, IRQF_TIMER);
|
||||||
}
|
}
|
||||||
if(flags & IRQF_NAND) {
|
if(flags & IRQF_NAND) {
|
||||||
// gecko_printf("IRQ: NAND\n");
|
// gecko_printf("IRQ: NAND\n");
|
||||||
write32(NAND_CMD, 0x7fffffff); // shut it up
|
write32(NAND_CMD, 0x7fffffff); // shut it up
|
||||||
write32(HW_IRQFLAG, IRQF_NAND);
|
write32(HW_ARMIRQFLAG, IRQF_NAND);
|
||||||
nand_irq();
|
nand_irq();
|
||||||
}
|
}
|
||||||
if(flags & IRQF_GPIO1B) {
|
if(flags & IRQF_GPIO1B) {
|
||||||
gecko_printf("IRQ: GPIO1B\n");
|
gecko_printf("IRQ: GPIO1B\n");
|
||||||
write32(HW_GPIO1BINTFLAG, 0xFFFFFF); // shut it up
|
write32(HW_GPIO1BINTFLAG, 0xFFFFFF); // shut it up
|
||||||
write32(HW_IRQFLAG, IRQF_GPIO1B);
|
write32(HW_ARMIRQFLAG, IRQF_GPIO1B);
|
||||||
}
|
}
|
||||||
if(flags & IRQF_GPIO1) {
|
if(flags & IRQF_GPIO1) {
|
||||||
gecko_printf("IRQ: GPIO1\n");
|
gecko_printf("IRQ: GPIO1\n");
|
||||||
write32(HW_GPIO1INTFLAG, 0xFFFFFF); // shut it up
|
write32(HW_GPIO1INTFLAG, 0xFFFFFF); // shut it up
|
||||||
write32(HW_IRQFLAG, IRQF_GPIO1);
|
write32(HW_ARMIRQFLAG, IRQF_GPIO1);
|
||||||
}
|
}
|
||||||
if(flags & IRQF_RESET) {
|
if(flags & IRQF_RESET) {
|
||||||
gecko_printf("IRQ: RESET\n");
|
gecko_printf("IRQ: RESET\n");
|
||||||
write32(HW_IRQFLAG, IRQF_RESET);
|
write32(HW_ARMIRQFLAG, IRQF_RESET);
|
||||||
}
|
}
|
||||||
if(flags & IRQF_IPC) {
|
if(flags & IRQF_IPC) {
|
||||||
//gecko_printf("IRQ: IPC\n");
|
//gecko_printf("IRQ: IPC\n");
|
||||||
ipc_irq();
|
ipc_irq();
|
||||||
write32(HW_IRQFLAG, IRQF_IPC);
|
write32(HW_ARMIRQFLAG, IRQF_IPC);
|
||||||
}
|
}
|
||||||
if(flags & IRQF_AES) {
|
if(flags & IRQF_AES) {
|
||||||
gecko_printf("IRQ: AES\n");
|
gecko_printf("IRQ: AES\n");
|
||||||
write32(HW_IRQFLAG, IRQF_AES);
|
write32(HW_ARMIRQFLAG, IRQF_AES);
|
||||||
}
|
}
|
||||||
flags &= ~IRQF_ALL;
|
flags &= ~IRQF_ALL;
|
||||||
if(flags) {
|
if(flags) {
|
||||||
gecko_printf("IRQ: unknown 0x%08x\n", flags);
|
gecko_printf("IRQ: unknown 0x%08x\n", flags);
|
||||||
write32(HW_IRQFLAG, flags);
|
write32(HW_ARMIRQFLAG, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void irq_enable(u32 irq)
|
void irq_enable(u32 irq)
|
||||||
{
|
{
|
||||||
set32(HW_IRQENABLE, 1<<irq);
|
set32(HW_ARMIRQMASK, 1<<irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
void irq_disable(u32 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