mirror of
https://gitee.com/anod/open_agb_firm.git
synced 2025-05-07 06:14:12 +08:00
131 lines
3.4 KiB
C
131 lines
3.4 KiB
C
/*
|
|
* This file is part of open_agb_firm
|
|
* Copyright (C) 2021 derrek, profi200
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "types.h"
|
|
#include "arm9/drivers/spicard.h"
|
|
#include "arm9/drivers/cfg9.h"
|
|
#include "arm9/drivers/interrupt.h"
|
|
#include "arm9/drivers/timer.h"
|
|
#include "arm9/drivers/ndma.h"
|
|
|
|
|
|
|
|
static inline void spicWaitBusy(const Spic *const spic)
|
|
{
|
|
while(spic->cnt & SPIC_EN);
|
|
}
|
|
|
|
static inline void spicWaitFifoBusy(const Spic *const spic)
|
|
{
|
|
while(spic->fifo_stat & SPIC_FIFO_BUSY);
|
|
}
|
|
|
|
void SPICARD_init(void)
|
|
{
|
|
static bool inited = false;
|
|
if(inited) return;
|
|
inited = true;
|
|
|
|
// TODO: The whole gamecard init doesn't belong here.
|
|
#define REG_NTRCARDMCNT *((vu16*)0x10164000)
|
|
#define REG_NTRCARDROMCNT *((vu32*)0x10164004)
|
|
|
|
Cfg9 *const cfg9 = getCfg9Regs();
|
|
cfg9->card_insert_delay = 0x1988; // 100 ms.
|
|
cfg9->card_pwroff_delay = 0x264C; // 150 ms.
|
|
// boot9 waits here. Unnecessary?
|
|
|
|
cfg9->card_power = CARD_POWER_OFF_REQ; // Request power off.
|
|
while(cfg9->card_power != CARD_POWER_OFF); // Aotomatically changes to off.
|
|
TIMER_sleepMs(1);
|
|
|
|
cfg9->card_power = CARD_POWER_ON_RESET; // Power on and reset.
|
|
TIMER_sleepMs(10);
|
|
|
|
cfg9->card_power = CARD_POWER_ON; // Power on.
|
|
TIMER_sleepMs(27);
|
|
|
|
// Switch to NTRCARD controller.
|
|
cfg9->cardctl = CARDCTL_NTRCARD;
|
|
REG_NTRCARDMCNT = 0xC000u;
|
|
REG_NTRCARDROMCNT = 0x20000000;
|
|
TIMER_sleepMs(120);
|
|
|
|
cfg9->cardctl = CARDCTL_SPIC_SEL | CARDCTL_NTRCARD;
|
|
|
|
IRQ_registerIsr(IRQ_CTR_CARD_1, NULL);
|
|
Spic *const spic = getSpicRegs();
|
|
spic->int_mask = SPIC_INT_TRAN_END; // Disable interrupt 1.
|
|
spic->int_stat = SPIC_INT_AP_TMOUT | SPIC_INT_AP_MATCH | SPIC_INT_TRAN_END; // Acknowledge.
|
|
}
|
|
|
|
bool SPICARD_autoPollBit(const SpicClk clk, const u32 apParams)
|
|
{
|
|
Spic *const spic = getSpicRegs();
|
|
spic->cnt = clk & 7u;
|
|
spic->autopoll = SPIC_AP_START | apParams;
|
|
|
|
u32 res;
|
|
do
|
|
{
|
|
__wfi();
|
|
res = spic->int_stat;
|
|
} while(!(res & (SPIC_INT_AP_TMOUT | SPIC_INT_AP_MATCH)));
|
|
spic->int_stat = res; // Acknowledge.
|
|
|
|
return (res & SPIC_INT_AP_TMOUT) == 0; // Timeout error.
|
|
}
|
|
|
|
void SPICARD_sendRecv(const SpicClk clk, const u32 *in, u32 *out, const u32 inSize, const u32 outSize)
|
|
{
|
|
const u32 cntParams = SPIC_EN | SPIC_BUS_1BIT | (clk & 7u);
|
|
|
|
Spic *const spic = getSpicRegs();
|
|
if(in)
|
|
{
|
|
spic->blklen = inSize;
|
|
spic->cnt = cntParams | SPIC_DIR_S;
|
|
|
|
u32 counter = 0;
|
|
do
|
|
{
|
|
if((counter & 31) == 0) spicWaitFifoBusy(spic);
|
|
spic->fifo = *in++;
|
|
counter += 4;
|
|
} while(counter < inSize);
|
|
|
|
spicWaitBusy(spic);
|
|
}
|
|
if(out)
|
|
{
|
|
spic->blklen = outSize;
|
|
spic->cnt = cntParams | SPIC_DIR_R;
|
|
|
|
u32 counter = 0;
|
|
do
|
|
{
|
|
if((counter & 31) == 0) spicWaitFifoBusy(spic);
|
|
*out++ = spic->fifo;
|
|
counter += 4;
|
|
} while(counter < outSize);
|
|
|
|
spicWaitBusy(spic);
|
|
}
|
|
|
|
if(clk & SPIC_CLK_CS_HIGH) spic->cs = SPIC_CS_HIGH;
|
|
} |