initial commit. loads from 4th partition
This commit is contained in:
parent
0774bc3658
commit
95e15ef4fd
8 changed files with 833 additions and 0 deletions
11
Makefile
Normal file
11
Makefile
Normal file
|
@ -0,0 +1,11 @@
|
|||
CC=~/opt/bin/arm-none-eabi-gcc
|
||||
LD=~/opt/bin/arm-none-eabi-ld
|
||||
all: arm9loaderhax.bin
|
||||
arm9loaderhax.bin: arm9loaderhax.elf
|
||||
objcopy -O binary $^ $@
|
||||
arm9loaderhax.elf: sdmmc.o loader.o delay.o
|
||||
$(LD) -T loader.ld -o $@ $^
|
||||
%.o: %.c
|
||||
$(CC) -c $^ -mcpu=arm946e-s -march=armv5te -mlittle-endian
|
||||
%.o: %.s
|
||||
$(CC) -c $^ -mcpu=arm946e-s -march=armv5te -mlittle-endian
|
21
common.h
Normal file
21
common.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#define u8 unsigned char
|
||||
#define u16 unsigned short
|
||||
#define u32 unsigned int
|
||||
#define u64 unsigned long long
|
||||
#define bool int
|
||||
#define true 1
|
||||
#define false 0
|
||||
#define NULL 0
|
||||
#define vu8 volatile u8
|
||||
#define vu16 volatile u16
|
||||
#define vu32 volatile u32
|
||||
#define vu64 volatile u64
|
||||
|
||||
#define max(a,b) \
|
||||
({ __typeof__ (a) _a = (a); \
|
||||
__typeof__ (b) _b = (b); \
|
||||
_a > _b ? _a : _b; })
|
||||
#define min(a,b) \
|
||||
({ __typeof__ (a) _a = (a); \
|
||||
__typeof__ (b) _b = (b); \
|
||||
_a < _b ? _a : _b; })
|
9
delay.h
Normal file
9
delay.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
// Copyright 2014 Normmatt
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
void ioDelay(u32 us);
|
80
delay.s
Normal file
80
delay.s
Normal file
|
@ -0,0 +1,80 @@
|
|||
.section .text.start
|
||||
.align 4
|
||||
b _start
|
||||
.word 0, 0
|
||||
.global _start
|
||||
.extern main
|
||||
_start:
|
||||
mov sp, #0x27000000
|
||||
//Disable caches/mpu
|
||||
mrc p15, 0, r0, c1, c0, 0
|
||||
bic r0, #0x1000 //Disable instruction cache
|
||||
bic r0, #0x4 //Disable data cache
|
||||
bic r0, #0x1 //Disable MPU
|
||||
mcr p15, 0, r0, c1, c0, 0
|
||||
ldr r0, =0x33333333
|
||||
mcr p15, 0, r0, c5, c0, 2 //Write data access
|
||||
mcr p15, 0, r0, c5, c0, 3 //Write instruction access
|
||||
// Sets MPU permissions and cache settings
|
||||
ldr r0, =0xFFFF001D // ffff0000 32k | bootrom (unprotected part)
|
||||
ldr r1, =0x3000801B // fff00000 16k | dtcm
|
||||
ldr r2, =0x01FF801D // 01ff8000 32k | itcm
|
||||
ldr r3, =0x08000029 // 08000000 2M | arm9 mem (O3DS / N3DS)
|
||||
ldr r4, =0x10000029 // 10000000 2M | io mem (ARM9 / first 2MB)
|
||||
ldr r5, =0x20000037 // 20000000 256M | fcram (O3DS / N3DS)
|
||||
ldr r6, =0x1FF00027 // 1FF00000 1M | dsp / axi wram
|
||||
ldr r7, =0x1800002D // 18000000 8M | vram (+ 2MB)
|
||||
mov r8, #0x29
|
||||
mcr p15, 0, r0, c6, c0, 0
|
||||
mcr p15, 0, r1, c6, c1, 0
|
||||
mcr p15, 0, r2, c6, c2, 0
|
||||
mcr p15, 0, r3, c6, c3, 0
|
||||
mcr p15, 0, r4, c6, c4, 0
|
||||
mcr p15, 0, r5, c6, c5, 0
|
||||
mcr p15, 0, r6, c6, c6, 0
|
||||
mcr p15, 0, r7, c6, c7, 0
|
||||
mcr p15, 0, r8, c3, c0, 0 // Write bufferable 0, 3, 5
|
||||
mcr p15, 0, r8, c2, c0, 0 // Data cacheable 0, 3, 5
|
||||
mcr p15, 0, r8, c2, c0, 1 // Inst cacheable 0, 3, 5
|
||||
// Enable dctm
|
||||
ldr r0, =0x3000800A // set dtcm
|
||||
mcr p15, 0, r0, c9, c1, 0 // set the dtcm Region Register
|
||||
|
||||
// Enable caches
|
||||
mrc p15, 0, r0, c1, c0, 0 // read control register
|
||||
orr r0, r0, #(1<<18) // - itcm enable
|
||||
orr r0, r0, #(1<<16) // - dtcm enable
|
||||
//orr r0, r0, #(1<<12) // - instruction cache enable
|
||||
//orr r0, r0, #(1<<2) // - data cache enable
|
||||
orr r0, r0, #(1<<0) // - mpu enable
|
||||
mcr p15, 0, r0, c1, c0, 0 // write control register
|
||||
|
||||
// Flush caches
|
||||
mov r0, #0
|
||||
mcr p15, 0, r0, c7, c5, 0 // flush I-cache
|
||||
mcr p15, 0, r0, c7, c6, 0 // flush D-cache
|
||||
mcr p15, 0, r0, c7, c10, 4 // drain write buffer
|
||||
|
||||
// Fixes mounting of SDMC
|
||||
ldr r0, =0x10000020
|
||||
mov r1, #0x340
|
||||
str r1, [r0]
|
||||
|
||||
b init
|
||||
// Copyright 2014 Normmatt
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
.arm
|
||||
.global ioDelay
|
||||
.type ioDelay STT_FUNC
|
||||
|
||||
@ioDelay ( u32 us )
|
||||
ioDelay:
|
||||
ldr r1, =0x18000000 @ VRAM
|
||||
1:
|
||||
@ Loop doing uncached reads from VRAM to make loop timing more reliable
|
||||
ldr r2, [r1]
|
||||
subs r0, #1
|
||||
bgt 1b
|
||||
bx lr
|
60
loader.c
Normal file
60
loader.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
#include "common.h"
|
||||
#include "sdmmc.h"
|
||||
struct FIRM_sect {
|
||||
u32 offset;
|
||||
u32 physical;
|
||||
u32 size;
|
||||
u32 arm11;
|
||||
u8 SHA256[0x20]; //Implement later.
|
||||
}__attribute__((packed));
|
||||
struct FIRM_header {
|
||||
char magic[4];
|
||||
int reserved1;
|
||||
u32 arm11Entry;
|
||||
u32 arm9Entry;
|
||||
u8 reserved2[0x30];
|
||||
struct FIRM_sect sections[4];
|
||||
u8 RSA2048[0x100]; //I'd need to find out big N's private key to do that!
|
||||
}__attribute__((packed));
|
||||
struct chs {
|
||||
u8 head;
|
||||
u8 sector;
|
||||
u8 cylinder;
|
||||
}__attribute__((packed));
|
||||
struct partition {
|
||||
u8 status;
|
||||
struct chs start_chs;
|
||||
u8 parttype;
|
||||
struct chs end_chs;
|
||||
u32 start;
|
||||
u32 length;
|
||||
}__attribute__((packed));
|
||||
struct MBR {
|
||||
u8 bootstrap[0x1BE];
|
||||
struct partition partition[4];
|
||||
u16 signature;
|
||||
}__attribute__((packed));
|
||||
void main() {
|
||||
// start up SD-Card controller
|
||||
sdmmc_sdcard_init();
|
||||
|
||||
struct MBR drive;
|
||||
sdmmc_sdcard_readsectors(0,1, (u8*)&drive);
|
||||
if(drive.partition[3].status==0) {
|
||||
//Found the partition
|
||||
struct FIRM_header firm;
|
||||
sdmmc_sdcard_readsectors(drive.partition[3].start,1, (u8*)&firm);
|
||||
char* magic="FIRM";
|
||||
for(int i=0;i<4;i++)
|
||||
if(magic[i]!=firm.magic[i])
|
||||
return; //Check magic
|
||||
for(;;); //Deadlock if checksum's right. for debugging
|
||||
}
|
||||
}
|
||||
void init() {
|
||||
main();
|
||||
u8 *lfb=(u8*)0x18300000;
|
||||
for(int i=0;i<500;i++)
|
||||
lfb[i]=0xFF; //Output simple error
|
||||
for(;;);
|
||||
}
|
11
loader.ld
Normal file
11
loader.ld
Normal file
|
@ -0,0 +1,11 @@
|
|||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x23F00000;
|
||||
.text.start : { *(.text.start)}
|
||||
.text : {*(.text)}
|
||||
.data : {*(.data)}
|
||||
.bss : {*(.bss COMMON)}
|
||||
.rodata : {*(.rodata)}
|
||||
. = ALIGN(4);
|
||||
}
|
500
sdmmc.c
Normal file
500
sdmmc.c
Normal file
|
@ -0,0 +1,500 @@
|
|||
// Copyright 2014 Normmatt
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "sdmmc.h"
|
||||
#include "delay.h"
|
||||
|
||||
//Uncomment to enable 32bit fifo support?
|
||||
//not currently working
|
||||
//#define DATA32_SUPPORT
|
||||
|
||||
static struct mmcdevice handleNAND;
|
||||
static struct mmcdevice handleSD;
|
||||
|
||||
static inline u16 sdmmc_read16(u16 reg) {
|
||||
return *(vu16*)(SDMMC_BASE + reg);
|
||||
}
|
||||
|
||||
static inline void sdmmc_write16(u16 reg, u16 val) {
|
||||
*(vu16*)(SDMMC_BASE + reg) = val;
|
||||
}
|
||||
|
||||
static inline u32 sdmmc_read32(u16 reg) {
|
||||
return *(vu32*)(SDMMC_BASE + reg);
|
||||
}
|
||||
|
||||
static inline void sdmmc_write32(u16 reg, u32 val) {
|
||||
*(vu32*)(SDMMC_BASE + reg) = val;
|
||||
}
|
||||
|
||||
static inline void sdmmc_mask16(u16 reg, const u16 clear, const u16 set) {
|
||||
u16 val = sdmmc_read16(reg);
|
||||
val &= ~clear;
|
||||
val |= set;
|
||||
sdmmc_write16(reg, val);
|
||||
}
|
||||
|
||||
static inline void setckl(u32 data)
|
||||
{
|
||||
sdmmc_mask16(REG_SDCLKCTL, 0x100, 0);
|
||||
sdmmc_mask16(REG_SDCLKCTL, 0x2FF, data & 0x2FF);
|
||||
sdmmc_mask16(REG_SDCLKCTL, 0x0, 0x100);
|
||||
}
|
||||
|
||||
|
||||
mmcdevice *getMMCDevice(int drive)
|
||||
{
|
||||
if(drive==0) return &handleNAND;
|
||||
return &handleSD;
|
||||
}
|
||||
|
||||
int __attribute__((noinline)) geterror(struct mmcdevice *ctx)
|
||||
{
|
||||
//if(ctx->error == 0x4) return -1;
|
||||
//else return 0;
|
||||
return (ctx->error << 29) >> 31;
|
||||
}
|
||||
|
||||
|
||||
void __attribute__((noinline)) inittarget(struct mmcdevice *ctx)
|
||||
{
|
||||
sdmmc_mask16(REG_SDPORTSEL,0x3,(u16)ctx->devicenumber);
|
||||
setckl(ctx->clk);
|
||||
if (ctx->SDOPT == 0) {
|
||||
sdmmc_mask16(REG_SDOPT, 0, 0x8000);
|
||||
} else {
|
||||
sdmmc_mask16(REG_SDOPT, 0x8000, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void __attribute__((noinline)) sdmmc_send_command(struct mmcdevice *ctx, u32 cmd, u32 args)
|
||||
{
|
||||
bool getSDRESP = (cmd << 15) >> 31;
|
||||
u16 flags = (cmd << 15) >> 31;
|
||||
const bool readdata = cmd & 0x20000;
|
||||
const bool writedata = cmd & 0x40000;
|
||||
|
||||
if (readdata || writedata)
|
||||
flags |= TMIO_STAT0_DATAEND;
|
||||
|
||||
ctx->error = 0;
|
||||
while (sdmmc_read16(REG_SDSTATUS1) & TMIO_STAT1_CMD_BUSY); //mmc working?
|
||||
sdmmc_write16(REG_SDIRMASK0,0);
|
||||
sdmmc_write16(REG_SDIRMASK1,0);
|
||||
sdmmc_write16(REG_SDSTATUS0,0);
|
||||
sdmmc_write16(REG_SDSTATUS1,0);
|
||||
|
||||
#ifdef DATA32_SUPPORT
|
||||
if (readdata)
|
||||
sdmmc_mask16(REG_SDDATACTL32, 0x1000, 0x800);
|
||||
if (writedata)
|
||||
sdmmc_mask16(REG_SDDATACTL32, 0x800, 0x1000);
|
||||
#else
|
||||
sdmmc_mask16(REG_SDDATACTL32,0x1800,0);
|
||||
#endif
|
||||
|
||||
sdmmc_write16(REG_SDCMDARG0,args &0xFFFF);
|
||||
sdmmc_write16(REG_SDCMDARG1,args >> 16);
|
||||
sdmmc_write16(REG_SDCMD,cmd &0xFFFF);
|
||||
|
||||
u32 size = ctx->size;
|
||||
u16 *dataPtr = (u16*)ctx->data;
|
||||
#ifdef DATA32_SUPPORT
|
||||
u32 *dataPtr32 = (u32*)ctx->data;
|
||||
#endif
|
||||
|
||||
bool useBuf = ( NULL != dataPtr );
|
||||
#ifdef DATA32_SUPPORT
|
||||
bool useBuf32 = (useBuf && (0 == (3 & ((u32)dataPtr))));
|
||||
#endif
|
||||
|
||||
u16 status0 = 0;
|
||||
while(true) {
|
||||
u16 status1 = sdmmc_read16(REG_SDSTATUS1);
|
||||
if (status1 & TMIO_STAT1_RXRDY) {
|
||||
if (readdata && useBuf) {
|
||||
sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_RXRDY, 0);
|
||||
//sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_RXRDY);
|
||||
if (size > 0x1FF) {
|
||||
#ifdef DATA32_SUPPORT
|
||||
if (useBuf32) {
|
||||
for(int i = 0; i<0x200; i+=4)
|
||||
*dataPtr32++ = sdmmc_read32(REG_SDFIFO32);
|
||||
} else {
|
||||
#endif
|
||||
for(int i = 0; i<0x200; i+=2)
|
||||
*dataPtr++ = sdmmc_read16(REG_SDFIFO);
|
||||
#ifdef DATA32_SUPPORT
|
||||
}
|
||||
#endif
|
||||
size -= 0x200;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (status1 & TMIO_STAT1_TXRQ) {
|
||||
if (writedata && useBuf) {
|
||||
sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_TXRQ, 0);
|
||||
//sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_TXRQ);
|
||||
if (size > 0x1FF) {
|
||||
#ifdef DATA32_SUPPORT
|
||||
for (int i = 0; i<0x200; i+=4)
|
||||
sdmmc_write32(REG_SDFIFO32,*dataPtr32++);
|
||||
#else
|
||||
for (int i = 0; i<0x200; i+=2)
|
||||
sdmmc_write16(REG_SDFIFO,*dataPtr++);
|
||||
#endif
|
||||
size -= 0x200;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (status1 & TMIO_MASK_GW) {
|
||||
ctx->error |= 4;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(status1 & TMIO_STAT1_CMD_BUSY)) {
|
||||
status0 = sdmmc_read16(REG_SDSTATUS0);
|
||||
if (sdmmc_read16(REG_SDSTATUS0) & TMIO_STAT0_CMDRESPEND)
|
||||
ctx->error |= 0x1;
|
||||
if (status0 & TMIO_STAT0_DATAEND)
|
||||
ctx->error |= 0x2;
|
||||
|
||||
if ((status0 & flags) == flags)
|
||||
break;
|
||||
}
|
||||
}
|
||||
ctx->stat0 = sdmmc_read16(REG_SDSTATUS0);
|
||||
ctx->stat1 = sdmmc_read16(REG_SDSTATUS1);
|
||||
sdmmc_write16(REG_SDSTATUS0,0);
|
||||
sdmmc_write16(REG_SDSTATUS1,0);
|
||||
|
||||
if (getSDRESP != 0) {
|
||||
ctx->ret[0] = sdmmc_read16(REG_SDRESP0) | (sdmmc_read16(REG_SDRESP1) << 16);
|
||||
ctx->ret[1] = sdmmc_read16(REG_SDRESP2) | (sdmmc_read16(REG_SDRESP3) << 16);
|
||||
ctx->ret[2] = sdmmc_read16(REG_SDRESP4) | (sdmmc_read16(REG_SDRESP5) << 16);
|
||||
ctx->ret[3] = sdmmc_read16(REG_SDRESP6) | (sdmmc_read16(REG_SDRESP7) << 16);
|
||||
}
|
||||
}
|
||||
|
||||
int __attribute__((noinline)) sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, u8 *in)
|
||||
{
|
||||
if (handleSD.isSDHC == 0)
|
||||
sector_no <<= 9;
|
||||
inittarget(&handleSD);
|
||||
sdmmc_write16(REG_SDSTOP,0x100);
|
||||
|
||||
#ifdef DATA32_SUPPORT
|
||||
sdmmc_write16(REG_SDBLKCOUNT32,numsectors);
|
||||
#endif
|
||||
|
||||
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
|
||||
handleSD.data = in;
|
||||
handleSD.size = numsectors << 9;
|
||||
sdmmc_send_command(&handleSD,0x52C19,sector_no);
|
||||
return geterror(&handleSD);
|
||||
}
|
||||
|
||||
int __attribute__((noinline)) sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, u8 *out)
|
||||
{
|
||||
if (handleSD.isSDHC == 0)
|
||||
sector_no <<= 9;
|
||||
inittarget(&handleSD);
|
||||
sdmmc_write16(REG_SDSTOP,0x100);
|
||||
|
||||
#ifdef DATA32_SUPPORT
|
||||
sdmmc_write16(REG_SDBLKCOUNT32,numsectors);
|
||||
sdmmc_write16(REG_SDBLKLEN32,0x200);
|
||||
#endif
|
||||
|
||||
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
|
||||
handleSD.data = out;
|
||||
handleSD.size = numsectors << 9;
|
||||
sdmmc_send_command(&handleSD,0x33C12,sector_no);
|
||||
return geterror(&handleSD);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int __attribute__((noinline)) sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, u8 *out)
|
||||
{
|
||||
if (handleNAND.isSDHC == 0)
|
||||
sector_no <<= 9;
|
||||
inittarget(&handleNAND);
|
||||
sdmmc_write16(REG_SDSTOP,0x100);
|
||||
|
||||
#ifdef DATA32_SUPPORT
|
||||
sdmmc_write32(REG_SDBLKCOUNT32,numsectors);
|
||||
#else
|
||||
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
|
||||
#endif
|
||||
|
||||
handleNAND.data = out;
|
||||
handleNAND.size = numsectors << 9;
|
||||
sdmmc_send_command(&handleNAND,0x33C12,sector_no);
|
||||
inittarget(&handleSD);
|
||||
return geterror(&handleNAND);
|
||||
}
|
||||
|
||||
int __attribute__((noinline)) sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, u8 *in) //experimental
|
||||
{
|
||||
if (handleNAND.isSDHC == 0)
|
||||
sector_no <<= 9;
|
||||
inittarget(&handleNAND);
|
||||
sdmmc_write16(REG_SDSTOP,0x100);
|
||||
|
||||
#ifdef DATA32_SUPPORT
|
||||
sdmmc_write32(REG_SDBLKCOUNT32,numsectors);
|
||||
#else
|
||||
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
|
||||
#endif
|
||||
|
||||
handleNAND.data = in;
|
||||
handleNAND.size = numsectors << 9;
|
||||
sdmmc_send_command(&handleNAND,0x52C19,sector_no);
|
||||
inittarget(&handleSD);
|
||||
return geterror(&handleNAND);
|
||||
}
|
||||
|
||||
static u32 calcSDSize(u8* csd, int type)
|
||||
{
|
||||
u32 result = 0;
|
||||
if (type == -1) type = csd[14] >> 6;
|
||||
switch (type) {
|
||||
case 0:
|
||||
{
|
||||
u32 block_len = csd[9] & 0xf;
|
||||
block_len = 1 << block_len;
|
||||
u32 mult = (csd[4] >> 7) | ((csd[5] & 3) << 1);
|
||||
mult = 1 << (mult + 2);
|
||||
result = csd[8] & 3;
|
||||
result = (result << 8) | csd[7];
|
||||
result = (result << 2) | (csd[6] >> 6);
|
||||
result = (result + 1) * mult * block_len / 512;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
result = csd[7] & 0x3f;
|
||||
result = (result << 8) | csd[6];
|
||||
result = (result << 8) | csd[5];
|
||||
result = (result + 1) * 1024;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void InitSD()
|
||||
{
|
||||
//NAND
|
||||
handleNAND.isSDHC = 0;
|
||||
handleNAND.SDOPT = 0;
|
||||
handleNAND.res = 0;
|
||||
handleNAND.initarg = 1;
|
||||
handleNAND.clk = 0x80;
|
||||
handleNAND.devicenumber = 1;
|
||||
|
||||
//SD
|
||||
handleSD.isSDHC = 0;
|
||||
handleSD.SDOPT = 0;
|
||||
handleSD.res = 0;
|
||||
handleSD.initarg = 0;
|
||||
handleSD.clk = 0x80;
|
||||
handleSD.devicenumber = 0;
|
||||
|
||||
//sdmmc_mask16(0x100,0x800,0);
|
||||
//sdmmc_mask16(0x100,0x1000,0);
|
||||
//sdmmc_mask16(0x100,0x0,0x402);
|
||||
//sdmmc_mask16(0xD8,0x22,0x2);
|
||||
//sdmmc_mask16(0x100,0x2,0);
|
||||
//sdmmc_mask16(0xD8,0x22,0);
|
||||
//sdmmc_write16(0x104,0);
|
||||
//sdmmc_write16(0x108,1);
|
||||
//sdmmc_mask16(REG_SDRESET,1,0); //not in new Version -- nintendo's code does this
|
||||
//sdmmc_mask16(REG_SDRESET,0,1); //not in new Version -- nintendo's code does this
|
||||
//sdmmc_mask16(0x20,0,0x31D);
|
||||
//sdmmc_mask16(0x22,0,0x837F);
|
||||
//sdmmc_mask16(0xFC,0,0xDB);
|
||||
//sdmmc_mask16(0xFE,0,0xDB);
|
||||
////sdmmc_write16(REG_SDCLKCTL,0x20);
|
||||
////sdmmc_write16(REG_SDOPT,0x40EE);
|
||||
////sdmmc_mask16(0x02,0x3,0);
|
||||
//sdmmc_write16(REG_SDCLKCTL,0x40);
|
||||
//sdmmc_write16(REG_SDOPT,0x40EB);
|
||||
//sdmmc_mask16(0x02,0x3,0);
|
||||
//sdmmc_write16(REG_SDBLKLEN,0x200);
|
||||
//sdmmc_write16(REG_SDSTOP,0);
|
||||
|
||||
*(vu16*)0x10006100 &= 0xF7FFu; //SDDATACTL32
|
||||
*(vu16*)0x10006100 &= 0xEFFFu; //SDDATACTL32
|
||||
#ifdef DATA32_SUPPORT
|
||||
*(vu16*)0x10006100 |= 0x402u; //SDDATACTL32
|
||||
#else
|
||||
*(vu16*)0x10006100 |= 0x402u; //SDDATACTL32
|
||||
#endif
|
||||
*(vu16*)0x100060D8 = (*(vu16*)0x100060D8 & 0xFFDD) | 2;
|
||||
#ifdef DATA32_SUPPORT
|
||||
*(vu16*)0x10006100 &= 0xFFFFu; //SDDATACTL32
|
||||
*(vu16*)0x100060D8 &= 0xFFDFu; //SDDATACTL
|
||||
*(vu16*)0x10006104 = 512; //SDBLKLEN32
|
||||
#else
|
||||
*(vu16*)0x10006100 &= 0xFFFDu; //SDDATACTL32
|
||||
*(vu16*)0x100060D8 &= 0xFFDDu; //SDDATACTL
|
||||
*(vu16*)0x10006104 = 0; //SDBLKLEN32
|
||||
#endif
|
||||
*(vu16*)0x10006108 = 1; //SDBLKCOUNT32
|
||||
*(vu16*)0x100060E0 &= 0xFFFEu; //SDRESET
|
||||
*(vu16*)0x100060E0 |= 1u; //SDRESET
|
||||
*(vu16*)0x10006020 |= TMIO_MASK_ALL; //SDIR_MASK0
|
||||
*(vu16*)0x10006022 |= TMIO_MASK_ALL>>16; //SDIR_MASK1
|
||||
*(vu16*)0x100060FC |= 0xDBu; //SDCTL_RESERVED7
|
||||
*(vu16*)0x100060FE |= 0xDBu; //SDCTL_RESERVED8
|
||||
*(vu16*)0x10006002 &= 0xFFFCu; //SDPORTSEL
|
||||
#ifdef DATA32_SUPPORT
|
||||
*(vu16*)0x10006024 = 0x20;
|
||||
*(vu16*)0x10006028 = 0x40EE;
|
||||
#else
|
||||
*(vu16*)0x10006024 = 0x40; //Nintendo sets this to 0x20
|
||||
*(vu16*)0x10006028 = 0x40EB; //Nintendo sets this to 0x40EE
|
||||
#endif
|
||||
*(vu16*)0x10006002 &= 0xFFFCu; ////SDPORTSEL
|
||||
*(vu16*)0x10006026 = 512; //SDBLKLEN
|
||||
*(vu16*)0x10006008 = 0; //SDSTOP
|
||||
|
||||
inittarget(&handleSD);
|
||||
}
|
||||
|
||||
int Nand_Init()
|
||||
{
|
||||
inittarget(&handleNAND);
|
||||
ioDelay(0xF000);
|
||||
|
||||
sdmmc_send_command(&handleNAND,0,0);
|
||||
|
||||
do {
|
||||
do {
|
||||
sdmmc_send_command(&handleNAND,0x10701,0x100000);
|
||||
} while ( !(handleNAND.error & 1) );
|
||||
} while((handleNAND.ret[0] & 0x80000000) == 0);
|
||||
|
||||
sdmmc_send_command(&handleNAND,0x10602,0x0);
|
||||
if (handleNAND.error & 0x4) return -1;
|
||||
|
||||
sdmmc_send_command(&handleNAND,0x10403,handleNAND.initarg << 0x10);
|
||||
if (handleNAND.error & 0x4) return -1;
|
||||
|
||||
sdmmc_send_command(&handleNAND,0x10609,handleNAND.initarg << 0x10);
|
||||
if (handleNAND.error & 0x4) return -1;
|
||||
|
||||
handleNAND.total_size = calcSDSize((u8*)&handleNAND.ret[0],0);
|
||||
handleNAND.clk = 1;
|
||||
setckl(1);
|
||||
|
||||
sdmmc_send_command(&handleNAND,0x10407,handleNAND.initarg << 0x10);
|
||||
if (handleNAND.error & 0x4) return -1;
|
||||
|
||||
handleNAND.SDOPT = 1;
|
||||
|
||||
sdmmc_send_command(&handleNAND,0x10506,0x3B70100);
|
||||
if (handleNAND.error & 0x4) return -1;
|
||||
|
||||
sdmmc_send_command(&handleNAND,0x10506,0x3B90100);
|
||||
if (handleNAND.error & 0x4) return -1;
|
||||
|
||||
sdmmc_send_command(&handleNAND,0x1040D,handleNAND.initarg << 0x10);
|
||||
if (handleNAND.error & 0x4) return -1;
|
||||
|
||||
sdmmc_send_command(&handleNAND,0x10410,0x200);
|
||||
if (handleNAND.error & 0x4) return -1;
|
||||
|
||||
handleNAND.clk |= 0x200;
|
||||
|
||||
inittarget(&handleSD);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SD_Init()
|
||||
{
|
||||
inittarget(&handleSD);
|
||||
|
||||
//ioDelay(0x3E8);
|
||||
//ioDelay(0xF000);
|
||||
ioDelay(1u << 18);
|
||||
|
||||
//If not inserted
|
||||
if (!(*((vu16*)0x1000601c) & TMIO_STAT0_SIGSTATE)) return -1;
|
||||
|
||||
sdmmc_send_command(&handleSD,0,0);
|
||||
sdmmc_send_command(&handleSD,0x10408,0x1AA);
|
||||
//u32 temp = (handleSD.ret[0] == 0x1AA) << 0x1E;
|
||||
u32 temp = (handleSD.error & 0x1) << 0x1E;
|
||||
|
||||
//int count = 0;
|
||||
u32 temp2 = 0;
|
||||
do {
|
||||
do {
|
||||
sdmmc_send_command(&handleSD,0x10437,handleSD.initarg << 0x10);
|
||||
sdmmc_send_command(&handleSD,0x10769,0x00FF8000 | temp);
|
||||
temp2 = 1;
|
||||
} while ( !(handleSD.error & 1) );
|
||||
|
||||
} while((handleSD.ret[0] & 0x80000000) == 0);
|
||||
//do
|
||||
//{
|
||||
// sdmmc_send_command(&handleSD,0x10437,handleSD.initarg << 0x10);
|
||||
// sdmmc_send_command(&handleSD,0x10769,0x00FF8000 | temp);
|
||||
//
|
||||
//}
|
||||
//while(!(handleSD.ret[0] & 0x80000000));
|
||||
|
||||
if(!((handleSD.ret[0] >> 30) & 1) || !temp)
|
||||
temp2 = 0;
|
||||
|
||||
handleSD.isSDHC = temp2;
|
||||
//handleSD.isSDHC = (handleSD.ret[0] & 0x40000000);
|
||||
|
||||
sdmmc_send_command(&handleSD,0x10602,0);
|
||||
if (handleSD.error & 0x4) return -1;
|
||||
|
||||
sdmmc_send_command(&handleSD,0x10403,0);
|
||||
if (handleSD.error & 0x4) return -1;
|
||||
handleSD.initarg = handleSD.ret[0] >> 0x10;
|
||||
|
||||
sdmmc_send_command(&handleSD,0x10609,handleSD.initarg << 0x10);
|
||||
if (handleSD.error & 0x4) return -1;
|
||||
|
||||
handleSD.total_size = calcSDSize((u8*)&handleSD.ret[0],-1);
|
||||
handleSD.clk = 1;
|
||||
setckl(1);
|
||||
|
||||
sdmmc_send_command(&handleSD,0x10507,handleSD.initarg << 0x10);
|
||||
if (handleSD.error & 0x4) return -1;
|
||||
|
||||
sdmmc_send_command(&handleSD,0x10437,handleSD.initarg << 0x10);
|
||||
if (handleSD.error & 0x4) return -1;
|
||||
|
||||
handleSD.SDOPT = 1;
|
||||
sdmmc_send_command(&handleSD,0x10446,0x2);
|
||||
if (handleSD.error & 0x4) return -1;
|
||||
|
||||
sdmmc_send_command(&handleSD,0x1040D,handleSD.initarg << 0x10);
|
||||
if (handleSD.error & 0x4) return -1;
|
||||
|
||||
sdmmc_send_command(&handleSD,0x10410,0x200);
|
||||
if (handleSD.error & 0x4) return -1;
|
||||
handleSD.clk |= 0x200;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sdmmc_sdcard_init()
|
||||
{
|
||||
InitSD();
|
||||
Nand_Init();
|
||||
return SD_Init();
|
||||
}
|
141
sdmmc.h
Normal file
141
sdmmc.h
Normal file
|
@ -0,0 +1,141 @@
|
|||
// Copyright 2014 Normmatt
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define SDMMC_BASE 0x10006000u
|
||||
|
||||
#define REG_SDCMD 0x00
|
||||
#define REG_SDPORTSEL 0x02
|
||||
#define REG_SDCMDARG 0x04
|
||||
#define REG_SDCMDARG0 0x04
|
||||
#define REG_SDCMDARG1 0x06
|
||||
#define REG_SDSTOP 0x08
|
||||
#define REG_SDBLKCOUNT 0x0a
|
||||
|
||||
#define REG_SDRESP0 0x0c
|
||||
#define REG_SDRESP1 0x0e
|
||||
#define REG_SDRESP2 0x10
|
||||
#define REG_SDRESP3 0x12
|
||||
#define REG_SDRESP4 0x14
|
||||
#define REG_SDRESP5 0x16
|
||||
#define REG_SDRESP6 0x18
|
||||
#define REG_SDRESP7 0x1a
|
||||
|
||||
#define REG_SDSTATUS0 0x1c
|
||||
#define REG_SDSTATUS1 0x1e
|
||||
|
||||
#define REG_SDIRMASK0 0x20
|
||||
#define REG_SDIRMASK1 0x22
|
||||
#define REG_SDCLKCTL 0x24
|
||||
|
||||
#define REG_SDBLKLEN 0x26
|
||||
#define REG_SDOPT 0x28
|
||||
#define REG_SDFIFO 0x30
|
||||
|
||||
#define REG_SDDATACTL 0xd8
|
||||
#define REG_SDRESET 0xe0
|
||||
#define REG_SDPROTECTED 0xf6 //bit 0 determines if sd is protected or not?
|
||||
|
||||
#define REG_SDDATACTL32 0x100
|
||||
#define REG_SDBLKLEN32 0x104
|
||||
#define REG_SDBLKCOUNT32 0x108
|
||||
#define REG_SDFIFO32 0x10C
|
||||
|
||||
#define REG_CLK_AND_WAIT_CTL 0x138
|
||||
#define REG_RESET_SDIO 0x1e0
|
||||
|
||||
#define TMIO_STAT0_CMDRESPEND 0x0001
|
||||
#define TMIO_STAT0_DATAEND 0x0004
|
||||
#define TMIO_STAT0_CARD_REMOVE 0x0008
|
||||
#define TMIO_STAT0_CARD_INSERT 0x0010
|
||||
#define TMIO_STAT0_SIGSTATE 0x0020
|
||||
#define TMIO_STAT0_WRPROTECT 0x0080
|
||||
#define TMIO_STAT0_CARD_REMOVE_A 0x0100
|
||||
#define TMIO_STAT0_CARD_INSERT_A 0x0200
|
||||
#define TMIO_STAT0_SIGSTATE_A 0x0400
|
||||
#define TMIO_STAT1_CMD_IDX_ERR 0x0001
|
||||
#define TMIO_STAT1_CRCFAIL 0x0002
|
||||
#define TMIO_STAT1_STOPBIT_ERR 0x0004
|
||||
#define TMIO_STAT1_DATATIMEOUT 0x0008
|
||||
#define TMIO_STAT1_RXOVERFLOW 0x0010
|
||||
#define TMIO_STAT1_TXUNDERRUN 0x0020
|
||||
#define TMIO_STAT1_CMDTIMEOUT 0x0040
|
||||
#define TMIO_STAT1_RXRDY 0x0100
|
||||
#define TMIO_STAT1_TXRQ 0x0200
|
||||
#define TMIO_STAT1_ILL_FUNC 0x2000
|
||||
#define TMIO_STAT1_CMD_BUSY 0x4000
|
||||
#define TMIO_STAT1_ILL_ACCESS 0x8000
|
||||
|
||||
//Comes from TWLSDK mongoose.tef DWARF info
|
||||
#define SDMC_NORMAL 0x00000000
|
||||
#define SDMC_ERR_COMMAND 0x00000001
|
||||
#define SDMC_ERR_CRC 0x00000002
|
||||
#define SDMC_ERR_END 0x00000004
|
||||
#define SDMC_ERR_TIMEOUT 0x00000008
|
||||
#define SDMC_ERR_FIFO_OVF 0x00000010
|
||||
#define SDMC_ERR_FIFO_UDF 0x00000020
|
||||
#define SDMC_ERR_WP 0x00000040
|
||||
#define SDMC_ERR_ABORT 0x00000080
|
||||
#define SDMC_ERR_FPGA_TIMEOUT 0x00000100
|
||||
#define SDMC_ERR_PARAM 0x00000200
|
||||
#define SDMC_ERR_R1_STATUS 0x00000800
|
||||
#define SDMC_ERR_NUM_WR_SECTORS 0x00001000
|
||||
#define SDMC_ERR_RESET 0x00002000
|
||||
#define SDMC_ERR_ILA 0x00004000
|
||||
#define SDMC_ERR_INFO_DETECT 0x00008000
|
||||
|
||||
#define SDMC_STAT_ERR_UNKNOWN 0x00080000
|
||||
#define SDMC_STAT_ERR_CC 0x00100000
|
||||
#define SDMC_STAT_ERR_ECC_FAILED 0x00200000
|
||||
#define SDMC_STAT_ERR_CRC 0x00800000
|
||||
#define SDMC_STAT_ERR_OTHER 0xf9c70008
|
||||
|
||||
#define TMIO_MASK_ALL 0x837f031d
|
||||
|
||||
#define TMIO_MASK_GW (TMIO_STAT1_ILL_ACCESS | TMIO_STAT1_CMDTIMEOUT | TMIO_STAT1_TXUNDERRUN | TMIO_STAT1_RXOVERFLOW | \
|
||||
TMIO_STAT1_DATATIMEOUT | TMIO_STAT1_STOPBIT_ERR | TMIO_STAT1_CRCFAIL | TMIO_STAT1_CMD_IDX_ERR)
|
||||
|
||||
#define TMIO_MASK_READOP (TMIO_STAT1_RXRDY | TMIO_STAT1_DATAEND)
|
||||
#define TMIO_MASK_WRITEOP (TMIO_STAT1_TXRQ | TMIO_STAT1_DATAEND)
|
||||
|
||||
typedef struct mmcdevice {
|
||||
u8* data;
|
||||
u32 size;
|
||||
u32 error;
|
||||
u16 stat0;
|
||||
u16 stat1;
|
||||
u32 ret[4];
|
||||
u32 initarg;
|
||||
u32 isSDHC;
|
||||
u32 clk;
|
||||
u32 SDOPT;
|
||||
u32 devicenumber;
|
||||
u32 total_size; //size in sectors of the device
|
||||
u32 res;
|
||||
} mmcdevice;
|
||||
|
||||
/*int sdmmc_sdcard_init();
|
||||
void sdmmc_sdcard_readsector(uint32_t sector_no, void *out);
|
||||
void sdmmc_sdcard_readsectors(uint32_t sector_no, uint32_t numsectors, void *out);
|
||||
void sdmmc_sdcard_writesector(uint32_t sector_no, void *in);
|
||||
void sdmmc_sdcard_writesectors(uint32_t sector_no, uint32_t numsectors, void *in);
|
||||
void sdmmc_blktransferinit();*/
|
||||
|
||||
int sdmmc_sdcard_init();
|
||||
int sdmmc_sdcard_readsector(u32 sector_no, u8 *out);
|
||||
int sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, u8 *out);
|
||||
int sdmmc_sdcard_writesector(u32 sector_no, u8 *in);
|
||||
int sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, u8 *in);
|
||||
|
||||
int sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, u8 *out);
|
||||
int sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, u8 *in);
|
||||
|
||||
mmcdevice *getMMCDevice(int drive);
|
||||
|
||||
void InitSDMMC();
|
||||
int Nand_Init();
|
||||
int SD_Init();
|
Loading…
Reference in a new issue