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; }
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); } }
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); }
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); } }
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); }
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); }
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; }
// 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); }
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; }
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); }
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"); } }
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); } }
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); }
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; }
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; }
// 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); } } }