Beispiel #1
0
int sdmmc_get_sectors(void)
{
	if (card.inserted == 0) {
		gecko_printf("sdmmc: READ: no card inserted.\n");
		return -1;
	}

	if (card.new_card == 1) {
		gecko_printf("sdmmc: new card inserted but not acknowledged yet.\n");
		return -1;
	}

//	sdhc_error(sdhci->reg_base, "num sectors = %u", sdhci->num_sectors);
	
	return card.num_sectors;
}
Beispiel #2
0
void powerpc_ipc(volatile ipc_request *req)
{
	switch (req->req) {
	case IPC_PPC_BOOT:
		if (req->args[0]) {
			// Enqueued from ARM side, do not invalidate mem nor ipc_post
			powerpc_boot_mem((u8 *) req->args[1], req->args[2]);
		} else {
			dc_invalidaterange((void *) req->args[1], req->args[2]);
			int res = powerpc_boot_mem((u8 *) req->args[1], req->args[2]);
			if (res)
				ipc_post(req->code, req->tag, 1, res);
		}

		break;

	case IPC_PPC_BOOT_FILE:
		if (req->args[0]) {
			// Enqueued from ARM side, do not invalidate mem nor ipc_post
			powerpc_boot_file((char *) req->args[1]);
		} else {
			dc_invalidaterange((void *) req->args[1],
								strnlen((char *) req->args[1], 256));
			int res = powerpc_boot_file((char *) req->args[1]);
			if (res)
				ipc_post(req->code, req->tag, 1, res);
		}

		break;

	default:
		gecko_printf("IPC: unknown SLOW PPC request %04X\n", req->req);
	}
}
Beispiel #3
0
void powerpc_upload_stub(u32 entry)
{
	u32 i;

	set32(HW_EXICTRL, EXICTRL_ENABLE_EXI);

	// lis r3, entry@h
	write32(EXI_BOOT_BASE + 4 * 0, 0x3c600000 | entry >> 16);
	// ori r3, r3, entry@l
	write32(EXI_BOOT_BASE + 4 * 1, 0x60630000 | (entry & 0xffff));
	// mtsrr0 r3
	write32(EXI_BOOT_BASE + 4 * 2, 0x7c7a03a6);
	// li r3, 0
	write32(EXI_BOOT_BASE + 4 * 3, 0x38600000);
	// mtsrr1 r3
	write32(EXI_BOOT_BASE + 4 * 4, 0x7c7b03a6);
	// rfi
	write32(EXI_BOOT_BASE + 4 * 5, 0x4c000064);

	for (i = 6; i < 0x10; ++i)
		write32(EXI_BOOT_BASE + 4 * i, 0);

	set32(HW_DIFLAGS, DIFLAGS_BOOT_CODE);
	set32(HW_AHBPROT, 0xFFFFFFFF);

	gecko_printf("disabling EXI now...\n");
	clear32(HW_EXICTRL, EXICTRL_ENABLE_EXI);
}
Beispiel #4
0
void irq_handler(void)
{
	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);

	flags = flags & enabled;

	if(flags & IRQF_TIMER) {
		if (_alarm_frequency) {
			// currently we use the alarm timer only for lame usbgecko polling
			gecko_timer();
			write32(HW_ALARM, read32(HW_TIMER) + _alarm_frequency);
		}
		write32(HW_ARMIRQFLAG, IRQF_TIMER);
	}
	if(flags & IRQF_NAND) {
//		gecko_printf("IRQ: NAND\n");
		write32(NAND_CMD, 0x7fffffff); // shut it up
		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_ARMIRQFLAG, IRQF_GPIO1B);
	}
	if(flags & IRQF_GPIO1) {
//		gecko_printf("IRQ: GPIO1\n");
		write32(HW_GPIO1INTFLAG, 0xFFFFFF); // shut it up
		write32(HW_ARMIRQFLAG, IRQF_GPIO1);
	}
	if(flags & IRQF_RESET) {
//		gecko_printf("IRQ: RESET\n");
		write32(HW_ARMIRQFLAG, IRQF_RESET);
	}
	if(flags & IRQF_IPC) {
		//gecko_printf("IRQ: IPC\n");
		ipc_irq();
		write32(HW_ARMIRQFLAG, IRQF_IPC);
	}
	if(flags & IRQF_AES) {
//		gecko_printf("IRQ: AES\n");
		write32(HW_ARMIRQFLAG, IRQF_AES);
	}
	if (flags & IRQF_SDHC) {
//		gecko_printf("IRQ: SDHC\n");
		write32(HW_ARMIRQFLAG, IRQF_SDHC);
		sdhc_irq();
	}
	
	flags &= ~IRQF_ALL;
	if(flags) {
		gecko_printf("IRQ: unknown 0x%08x\n", flags);
		write32(HW_ARMIRQFLAG, flags);
	}
}
Beispiel #5
0
void powerpc_hang(void)
{
	gecko_printf("Hanging PPC. End debug output.\n\n");
	gecko_enable(0);
	clear32(HW_RESETS, 0x30);
	udelay(100);
	set32(HW_RESETS, 0x20);
	udelay(100);
}
Beispiel #6
0
void sdmmc_abort(void) {
	struct sdmmc_command cmd;
	gecko_printf("abortion kthx\n");
	
	memset(&cmd, 0, sizeof(cmd));
	cmd.c_opcode = MMC_STOP_TRANSMISSION;
	cmd.c_arg = 0;
	cmd.c_flags = SCF_RSP_R1B;
	sdhc_exec_command(card.handle, &cmd);
}
Beispiel #7
0
int sdmmc_read(u32 blk_start, u32 blk_count, void *data)
{
	struct sdmmc_command cmd;

	gecko_printf("%s(%u, %u, %p)\n", __FUNCTION__, blk_start, blk_count, data);
	if (card.inserted == 0) {
		gecko_printf("sdmmc: READ: no card inserted.\n");
		return -1;
	}

	if (card.selected == 0) {
		if (sdmmc_select() < 0) {
			gecko_printf("sdmmc: READ: cannot select card.\n");
			return -1;
		}
	}

	if (card.new_card == 1) {
		gecko_printf("sdmmc: new card inserted but not acknowledged yet.\n");
		return -1;
	}

	DPRINTF(2, ("sdmmc: MMC_READ_BLOCK_MULTIPLE\n"));
	memset(&cmd, 0, sizeof(cmd));
	cmd.c_opcode = MMC_READ_BLOCK_MULTIPLE;
	if (card.sdhc_blockmode)
		cmd.c_arg = blk_start;
	else
		cmd.c_arg = blk_start * SDMMC_DEFAULT_BLOCKLEN;
	cmd.c_data = data;
	cmd.c_datalen = blk_count * SDMMC_DEFAULT_BLOCKLEN;
	cmd.c_blklen = SDMMC_DEFAULT_BLOCKLEN;
	cmd.c_flags = SCF_RSP_R1 | SCF_CMD_READ;
	sdhc_exec_command(card.handle, &cmd);

	if (cmd.c_error) {
		gecko_printf("sdmmc: MMC_READ_BLOCK_MULTIPLE failed with %d\n", cmd.c_error);
		return -1;
	}
	DPRINTF(2, ("sdmmc: MMC_READ_BLOCK_MULTIPLE done\n"));

	return 0;
}
Beispiel #8
0
// flush device and also invalidate memory
void ahb_flush_from(enum AHBDEV dev)
{
	u32 cookie = irq_kill();
	u16 req = 0;
	u16 ack;
	int i;

	switch(dev)
	{
		case AHB_STARLET:
		case AHB_1:
			req = 1;
			break;
		case AHB_AES:
		case AHB_SHA1:
			req = 2;
			break;
		case AHB_NAND:
		case AHB_SDHC:
			req = 8;
			break;
		default:
			gecko_printf("ahb_flush(%d): Invalid device\n", dev);
			goto done;
	}

	write16(MEM_FLUSHREQ, req);

	for(i=0;i<1000000;i++) {
		ack = read16(MEM_FLUSHACK);
		_ahb_flush_to(AHB_STARLET);
		if(ack == req)
			break;
	}
	write16(MEM_FLUSHREQ, 0);
	if(i>=1000000) {
		gecko_printf("ahb_flush(%d): Flush (0x%x) did not ack!\n", dev, req);
	}
done:
	irq_restore(cookie);
}
Beispiel #9
0
int sdmmc_select(void)
{
	struct sdmmc_command cmd;

	DPRINTF(2, ("sdmmc: MMC_SELECT_CARD\n"));
	memset(&cmd, 0, sizeof(cmd));
	cmd.c_opcode = MMC_SELECT_CARD;
	cmd.c_arg = ((u32)card.rca)<<16;
	cmd.c_flags = SCF_RSP_R1B;
	sdhc_exec_command(card.handle, &cmd);
	gecko_printf("%s: resp=%x\n", __FUNCTION__, MMC_R1(cmd.c_resp));
	sdhc_dump_regs(card.handle);
	
//	gecko_printf("present state = %x\n", HREAD4(hp, SDHC_PRESENT_STATE));
	if (cmd.c_error) {
		gecko_printf("sdmmc: MMC_SELECT card failed with %d.\n", cmd.c_error);
		return -1;
	}

	card.selected = 1;
	return 0;
}
Beispiel #10
0
void powerpc_reset(void)
{
  gecko_printf("Resetting PPC. End debug output.\n\n");
	gecko_enable(0);
 	// enable the broadway IPC interrupt
	write32(HW_PPCIRQMASK, (1<<30));
	clear32(HW_RESETS, 0x30);
	udelay(100);
	set32(HW_RESETS, 0x20);
	udelay(100);
	set32(HW_RESETS, 0x10);
	udelay(100000);
	set32(HW_EXICTRL, EXICTRL_ENABLE_EXI);
}
Beispiel #11
0
void hexdump(void *d, int len) {
  u8 *data;
  int i, off;
  data = (u8*)d;
  for (off=0; off<len; off += 16) {
    gecko_printf("%08x  ",off);
    for(i=0; i<16; i++)
      if((i+off)>=len) gecko_printf("   ");
      else gecko_printf("%02x ",data[off+i]);

    gecko_printf(" ");
    for(i=0; i<16; i++)
      if((i+off)>=len) gecko_printf(" ");
      else gecko_printf("%c",ascii(data[off+i]));
    gecko_printf("\n");
  }
}
Beispiel #12
0
void InitDebug()
{
	if (CFG.debug_gecko & (1|4))
	{
		if (usb_isgeckoalive(EXI_CHANNEL_1)) {
			usb_flush(EXI_CHANNEL_1);
			if (!gecko_enabled) {
				gecko_enabled = 1;
				gecko_prints("\n\n====================\n\n");
			}
		}
	}
	if (CFG.debug_gecko & 2) {
		CON_EnableGecko(EXI_CHANNEL_1, 0);
	}
	debug_inited = 1;
	if (strlen(dbg_log_buf)) {
		gecko_printf(">>>\n%s\n<<<\n", dbg_log_buf);
	}
}
Beispiel #13
0
void mem_initialize(void)
{
	u32 cr;
	u32 cookie = irq_kill();

	gecko_printf("MEM: cleaning up\n");

	_ic_inval();
	_dc_inval();
	_tlb_inval();

	gecko_printf("MEM: unprotecting memory\n");

	mem_protect(0,NULL,NULL);

	gecko_printf("MEM: mapping sections\n");

	memset32(__page_table, 0, 16384);

	map_section(0x000, 0x000, 0x018, WRITEBACK_CACHE | DOMAIN(0) | AP_RWUSER);
	map_section(0x100, 0x100, 0x040, WRITEBACK_CACHE | DOMAIN(0) | AP_RWUSER);
	map_section(0x0d0, 0x0d0, 0x001, NONBUFFERABLE | DOMAIN(0) | AP_RWUSER);
	map_section(0x0d8, 0x0d8, 0x001, NONBUFFERABLE | DOMAIN(0) | AP_RWUSER);
	map_section(0xfff, 0xfff, 0x001, WRITEBACK_CACHE | DOMAIN(0) | AP_RWUSER);

	set_dacr(0xFFFFFFFF); //manager access for all domains, ignore AP
	set_ttbr((u32)__page_table); //configure translation table

	_drain_write_buffer();

	cr = get_cr();

#ifndef NO_CACHES
	gecko_printf("MEM: enabling caches\n");

	cr |= CR_DCACHE | CR_ICACHE;
	set_cr(cr);

	gecko_printf("MEM: enabling MMU\n");

	cr |= CR_MMU;
	set_cr(cr);
#endif

	gecko_printf("MEM: init done\n");

	irq_restore(cookie);
}
Beispiel #14
0
void sdmmc_needs_discover(void)
{
	struct sdmmc_command cmd;
	u32 ocr;

	DPRINTF(0, ("sdmmc: card needs discovery.\n"));
	sdhc_host_reset(card.handle);
	card.new_card = 1;

	if (!sdhc_card_detect(card.handle)) {
		DPRINTF(1, ("sdmmc: card (no longer?) inserted.\n"));
		card.inserted = 0;
		return;
	}
	
	DPRINTF(1, ("sdmmc: enabling power\n"));
	if (sdhc_bus_power(card.handle, 1) != 0) {
		gecko_printf("sdmmc: powerup failed for card\n");
		goto out;
	}

	DPRINTF(1, ("sdmmc: enabling clock\n"));
	if (sdhc_bus_clock(card.handle, SDMMC_DEFAULT_CLOCK) != 0) {
		gecko_printf("sdmmc: could not enable clock for card\n");
		goto out_power;
	}

	DPRINTF(1, ("sdmmc: sending GO_IDLE_STATE\n"));

	memset(&cmd, 0, sizeof(cmd));
	cmd.c_opcode = MMC_GO_IDLE_STATE;
	cmd.c_flags = SCF_RSP_R0;
	sdhc_exec_command(card.handle, &cmd);

	if (cmd.c_error) {
		gecko_printf("sdmmc: GO_IDLE_STATE failed with %d\n", cmd.c_error);
		goto out_clock;
	}
	DPRINTF(2, ("sdmmc: GO_IDLE_STATE response: %x\n", MMC_R1(cmd.c_resp)));

	DPRINTF(1, ("sdmmc: sending SEND_IF_COND\n"));

	memset(&cmd, 0, sizeof(cmd));
	cmd.c_opcode = SD_SEND_IF_COND;
	cmd.c_arg = 0x1aa;
	cmd.c_flags = SCF_RSP_R7;
	cmd.c_timeout = 100;
	sdhc_exec_command(card.handle, &cmd);

	ocr = card.handle->ocr;
	if (cmd.c_error || (cmd.c_resp[0] & 0xff) != 0xaa)
		ocr &= ~SD_OCR_SDHC_CAP;
	else
		ocr |= SD_OCR_SDHC_CAP;
	DPRINTF(2, ("sdmmc: SEND_IF_COND ocr: %x\n", ocr));

	int tries;
	for (tries = 100; tries > 0; tries--) {
		udelay(100000);
	
		memset(&cmd, 0, sizeof(cmd));
		cmd.c_opcode = MMC_APP_CMD;
		cmd.c_arg = 0;
		cmd.c_flags = SCF_RSP_R1;
		sdhc_exec_command(card.handle, &cmd);

		if (cmd.c_error)
			continue;
	
		memset(&cmd, 0, sizeof(cmd));
		cmd.c_opcode = SD_APP_OP_COND;
		cmd.c_arg = ocr;
		cmd.c_flags = SCF_RSP_R3;
		sdhc_exec_command(card.handle, &cmd);
		if (cmd.c_error)
			continue;

		DPRINTF(3, ("sdmmc: response for SEND_IF_COND: %08x\n",
					MMC_R1(cmd.c_resp)));
		if (ISSET(MMC_R1(cmd.c_resp), MMC_OCR_MEM_READY))
			break;
	}
	if (!ISSET(cmd.c_resp[0], MMC_OCR_MEM_READY)) {
		gecko_printf("sdmmc: card failed to powerup.\n");
		goto out_power;
	}

	if (ISSET(MMC_R1(cmd.c_resp), SD_OCR_SDHC_CAP))
		card.sdhc_blockmode = 1;
	else
		card.sdhc_blockmode = 0;
	DPRINTF(2, ("sdmmc: SDHC: %d\n", card.sdhc_blockmode));
	
	u8 *resp;
	DPRINTF(2, ("sdmmc: MMC_ALL_SEND_CID\n"));
	memset(&cmd, 0, sizeof(cmd));
	cmd.c_opcode = MMC_ALL_SEND_CID;
	cmd.c_arg = 0;
	cmd.c_flags = SCF_RSP_R2;
	sdhc_exec_command(card.handle, &cmd);
	if (cmd.c_error) {
		gecko_printf("sdmmc: MMC_ALL_SEND_CID failed with %d\n", cmd.c_error);
		goto out_clock;
	}

	card.cid = MMC_R1(cmd.c_resp);
	resp = (u8 *)cmd.c_resp;
	gecko_printf("CID: mid=%02x name='%c%c%c%c%c%c%c' prv=%d.%d psn=%02x%02x%02x%02x mdt=%d/%d\n", resp[14], 
		resp[13],resp[12],resp[11],resp[10],resp[9],resp[8],resp[7], resp[6], resp[5] >> 4, resp[5] & 0xf, 
		resp[4], resp[3], resp[2], resp[0] & 0xf, 2000 + (resp[0] >> 4));
		
	DPRINTF(2, ("sdmmc: SD_SEND_RELATIVE_ADDRESS\n"));
	memset(&cmd, 0, sizeof(cmd));
	cmd.c_opcode = SD_SEND_RELATIVE_ADDR;
	cmd.c_arg = 0;
	cmd.c_flags = SCF_RSP_R6;
	sdhc_exec_command(card.handle, &cmd);
	if (cmd.c_error) {
		gecko_printf("sdmmc: SD_SEND_RCA failed with %d\n", cmd.c_error);
		goto out_clock;
	}

	card.rca = MMC_R1(cmd.c_resp)>>16;
	DPRINTF(2, ("sdmmc: rca: %08x\n", card.rca));

	card.selected = 0;
	card.inserted = 1;

	memset(&cmd, 0, sizeof(cmd));
	cmd.c_opcode = MMC_SEND_CSD;
	cmd.c_arg = ((u32)card.rca)<<16;
	cmd.c_flags = SCF_RSP_R2;
	sdhc_exec_command(card.handle, &cmd);
	if (cmd.c_error) {
		gecko_printf("sdmmc: MMC_SEND_CSD failed with %d\n", cmd.c_error);
		goto out_power;
	}

	resp = (u8 *)cmd.c_resp;

	int i;
	gecko_printf("csd: ");
	for(i=15; i>=0; i--) gecko_printf("%02x ", (u32) resp[i]);
	gecko_printf("\n");

	if (resp[13] == 0xe) { // sdhc
		unsigned int c_size = resp[7] << 16 | resp[6] << 8 | resp[5];
		gecko_printf("sdmmc: sdhc mode, c_size=%u, card size = %uk\n", c_size, (c_size + 1)* 512);
		card.timeout = 250 * 1000000; // spec says read timeout is 100ms and write/erase timeout is 250ms
		card.num_sectors = (c_size + 1) * 1024; // number of 512-byte sectors
	}
	else {
		unsigned int taac, nsac, read_bl_len, c_size, c_size_mult;
		taac = resp[13];
		nsac = resp[12];
		read_bl_len = resp[9] & 0xF;
		
		c_size = (resp[8] & 3) << 10;
		c_size |= (resp[7] << 2);
		c_size |= (resp[6] >> 6);
		c_size_mult = (resp[5] & 3) << 1;
		c_size_mult |= resp[4] >> 7;
		gecko_printf("taac=%u nsac=%u read_bl_len=%u c_size=%u c_size_mult=%u card size=%u bytes\n",
			taac, nsac, read_bl_len, c_size, c_size_mult, (c_size + 1) * (4 << c_size_mult) * (1 << read_bl_len));
		static const unsigned int time_unit[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000};
		static const unsigned int time_value[] = {1, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80}; // must div by 10
		card.timeout = time_unit[taac & 7] * time_value[(taac >> 3) & 0xf] / 10;
		gecko_printf("calculated timeout =  %uns\n", card.timeout);
		card.num_sectors = (c_size + 1) * (4 << c_size_mult) * (1 << read_bl_len) / 512;
	}

	sdmmc_select();
	DPRINTF(2, ("sdmmc: MMC_SET_BLOCKLEN\n"));
	memset(&cmd, 0, sizeof(cmd));
	cmd.c_opcode = MMC_SET_BLOCKLEN;
	cmd.c_arg = SDMMC_DEFAULT_BLOCKLEN;
	cmd.c_flags = SCF_RSP_R1;
	sdhc_exec_command(card.handle, &cmd);
	if (cmd.c_error) {
		gecko_printf("sdmmc: MMC_SET_BLOCKLEN failed with %d\n", cmd.c_error);
		card.inserted = card.selected = 0;
		goto out_clock;
	}
	return;

out_clock:
	sdhc_bus_clock(card.handle, SDMMC_SDCLK_OFF);

out_power:
	sdhc_bus_power(card.handle, 0);
out:
	return;
}
Beispiel #15
0
u32 _main(void *base)
{
	FRESULT fres;
	int res;
	u32 vector;
	(void)base;

	gecko_init();
	gecko_printf("mini %s loading\n", git_version);

	gecko_printf("Initializing exceptions...\n");
	exception_initialize();
	gecko_printf("Configuring caches and MMU...\n");
	mem_initialize();

	gecko_printf("IOSflags: %08x %08x %08x\n",
		read32(0xffffff00), read32(0xffffff04), read32(0xffffff08));
	gecko_printf("          %08x %08x %08x\n",
		read32(0xffffff0c), read32(0xffffff10), read32(0xffffff14));

	irq_initialize();
	irq_enable(IRQ_TIMER);
//	irq_enable(IRQ_GPIO1B);
	irq_enable(IRQ_GPIO1);
	irq_enable(IRQ_RESET);
	gecko_timer_initialize();
	gecko_printf("Interrupts initialized\n");

	crypto_initialize();
	gecko_printf("crypto support initialized\n");

	nand_initialize();
	gecko_printf("NAND initialized.\n");

	boot2_init();

	gecko_printf("Initializing IPC...\n");
	ipc_initialize();

	gecko_printf("Initializing SDHC...\n");
	sdhc_init();

	gecko_printf("Mounting SD...\n");
	fres = f_mount(0, &fatfs);

	//if (read32(0x0d800190) & 2)
	//{
	//	gecko_printf("GameCube compatibility mode detected...\n");
		vector = boot2_run(1, 2);
	//	goto shutdown;
	//}

	//if(fres != FR_OK)
	//{
	//	gecko_printf("Error %d while trying to mount SD\n", fres);
	//	panic2(0, PANIC_MOUNT);
	//}

	//gecko_printf("Trying to boot:" PPC_BOOT_FILE "\n");

	//res = powerpc_boot_file(PPC_BOOT_FILE);
	//if(res < 0) {
	//	gecko_printf("Failed to boot PPC: %d\n", res);
	//	gecko_printf("Continuing anyway\n");
	//}

	//gecko_printf("Going into IPC mainloop...\n");
	//vector = ipc_process_slow();
	//gecko_printf("IPC mainloop done!\n");
	gecko_printf("Shutting down IPC...\n");
	ipc_shutdown();

shutdown:
	gecko_printf("Shutting down interrupts...\n");
	irq_shutdown();
	gecko_printf("Shutting down caches and MMU...\n");
	mem_shutdown();

	gecko_printf("Vectoring to 0x%08x...\n", vector);
	return vector;
}
Beispiel #16
0
// this is ripped from IOS, because no one can figure out just WTF this thing is doing
void _ahb_flush_to(enum AHBDEV dev) {
	u32 mask = 10;
	switch(dev) {
		case AHB_STARLET: mask = 0x8000; break;
		case AHB_1: mask = 0x4000; break;
		//case 2: mask = 0x0001; break;
		case AHB_NAND: mask = 0x0002; break;
		case AHB_AES: mask = 0x0004; break;
		case AHB_SHA1: mask = 0x0008; break;
		//case 6: mask = 0x0010; break;
		//case 7: mask = 0x0020; break;
		//case 8: mask = 0x0040; break;
		case AHB_SDHC: mask = 0x0080; break;
		//case 10: mask = 0x0100; break;
		//case 11: mask = 0x1000; break;
		//case 12: mask = 0x0000; break;
		default:
			gecko_printf("ahb_invalidate(%d): Invalid device\n", dev);
			return;
	}
	//NOTE: 0xd8b000x, not 0xd8b400x!
	u32 val = _mc_read32(0xd8b0008);
	if(!(val & mask)) {
		switch(dev) {
			// 2 to 10 in IOS, add more
			case AHB_NAND:
			case AHB_AES:
			case AHB_SHA1:
			case AHB_SDHC:
				while((read32(HW_18C) & 0xF) == 9)
					set32(HW_188, 0x10000);
				clear32(HW_188, 0x10000);
				set32(HW_188, 0x2000000);
				mask32(HW_124, 0x7c0, 0x280);
				set32(HW_134, 0x400);
				while((read32(HW_18C) & 0xF) != 9);
				set32(HW_100, 0x400);
				set32(HW_104, 0x400);
				set32(HW_108, 0x400);
				set32(HW_10c, 0x400);
				set32(HW_110, 0x400);
				set32(HW_114, 0x400);
				set32(HW_118, 0x400);
				set32(HW_11c, 0x400);
				set32(HW_120, 0x400);
				write32(0xd8b0008, _mc_read32(0xd8b0008) & (~mask));
				write32(0xd8b0008, _mc_read32(0xd8b0008) | mask);
				clear32(HW_134, 0x400);
				clear32(HW_100, 0x400);
				clear32(HW_104, 0x400);
				clear32(HW_108, 0x400);
				clear32(HW_10c, 0x400);
				clear32(HW_110, 0x400);
				clear32(HW_114, 0x400);
				clear32(HW_118, 0x400);
				clear32(HW_11c, 0x400);
				clear32(HW_120, 0x400);
				clear32(HW_188, 0x2000000);
				mask32(HW_124, 0x7c0, 0xc0);
			//0, 1, 11 in IOS, add more
			case AHB_STARLET:
			case AHB_1:
				write32(0xd8b0008, val & (~mask));
				// wtfux
				write32(0xd8b0008, val | mask);
				write32(0xd8b0008, val | mask);
				write32(0xd8b0008, val | mask);
		}
	}
}