├── .gitignore ├── Makefile ├── include ├── draw.h ├── font.h ├── hid.h ├── i2c.h ├── pxi.h ├── pxi_cmd.h ├── tmio.h ├── tmio_command.h ├── tmio_hardware.h ├── types.h └── utils.h ├── linker.ld └── source ├── delay.s ├── draw.c ├── i2c.c ├── libc.c ├── main.c ├── pxi.c ├── start.s ├── tiny-printf.c ├── tmio.c └── utils.c /.gitignore: -------------------------------------------------------------------------------- 1 | arm9linuxfw.bin 2 | *.elf 3 | *.o 4 | *.d 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(strip $(DEVKITARM)),) 2 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") 3 | endif 4 | 5 | include $(DEVKITARM)/base_tools 6 | 7 | TARGET = $(notdir $(CURDIR)) 8 | OBJS = source/start.o source/main.o source/tmio.o source/delay.o \ 9 | source/draw.o source/i2c.o source/utils.o source/pxi.o source/tiny-printf.o source/libc.o 10 | ARCH = -mcpu=arm946e-s -march=armv5te -mlittle-endian -mthumb-interwork 11 | ASFLAGS = $(ARCH) -x assembler-with-cpp 12 | CFLAGS = -Wall -O0 -fno-builtin -nostartfiles -nostdlib -fomit-frame-pointer $(ARCH) -Iinclude 13 | DEPS = $(OBJS:.o=.d) 14 | 15 | all: $(TARGET).bin 16 | 17 | debug: CFLAGS += -DDEBUG 18 | debug: ASFLAGS += -DDEBUG 19 | debug: $(TARGET).bin 20 | 21 | $(TARGET).elf: $(OBJS) 22 | $(CC) -T linker.ld $(CFLAGS) $^ -o $@ 23 | 24 | %.bin: %.elf 25 | $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@ 26 | 27 | .s.o: 28 | $(CC) $(ASFLAGS) -MMD -MP -c $< -o $@ 29 | 30 | .c.o: 31 | $(CC) $(CFLAGS) -MMD -MP -c $< -o $@ 32 | 33 | clean: 34 | @rm -f $(TARGET).elf $(TARGET).bin $(OBJS) $(DEPS) 35 | 36 | copy: $(TARGET).bin 37 | cp $(TARGET).bin $(SD3DS)/linux && sync 38 | @echo "Copied!" 39 | 40 | -include $(DEPS) 41 | -------------------------------------------------------------------------------- /include/draw.h: -------------------------------------------------------------------------------- 1 | #ifndef DRAW_H 2 | #define DRAW_H 3 | 4 | #include 5 | #include "types.h" 6 | 7 | #define BYTES_PER_PIXEL 3 8 | #define SCREEN_WIDTH 240 9 | #define SCREEN_HEIGHT 320 10 | 11 | #define SCREEN_SIZE (BYTES_PER_PIXEL * SCREEN_WIDTH * SCREEN_HEIGHT) 12 | 13 | #define RGB(r,g,b) (r<<24|b<<16|g<<8|r) 14 | 15 | #define FB_TOP_SIZE (400 * 240 * 3) 16 | #define FB_BOT_SIZE (320 * 240 * 3) 17 | 18 | #define VRAM_BASE (0x18000000) 19 | #define FB_BASE_PA (VRAM_BASE) 20 | #define FB_TOP_LEFT1 (FB_BASE_PA) 21 | #define FB_TOP_LEFT2 (FB_TOP_LEFT1 + FB_TOP_SIZE) 22 | #define FB_TOP_RIGHT1 (FB_TOP_LEFT2 + FB_TOP_SIZE) 23 | #define FB_TOP_RIGHT2 (FB_TOP_RIGHT1 + FB_TOP_SIZE) 24 | #define FB_BOT_1 (FB_TOP_RIGHT2 + FB_TOP_SIZE) 25 | #define FB_BOT_2 (FB_BOT_1 + FB_BOT_SIZE) 26 | 27 | #define TOP_SCREEN0 (u8*)(FB_TOP_LEFT1) 28 | #define TOP_SCREEN1 (u8*)(FB_TOP_LEFT2) 29 | #define BOT_SCREEN0 (u8*)(FB_BOT_1) 30 | #define BOT_SCREEN1 (u8*)(FB_BOT_2) 31 | extern int current_y; 32 | 33 | void ClearScreen(unsigned char *screen, int color); 34 | void DrawCharacter(unsigned char *screen, int character, int x, int y, int color, int bgcolor); 35 | void DrawHex(unsigned char *screen, unsigned int hex, int x, int y, int color, int bgcolor); 36 | void DrawString(unsigned char *screen, const char *str, int x, int y, int color, int bgcolor); 37 | void DrawStringF(int x, int y, const char *format, ...); 38 | void DrawHexWithName(unsigned char *screen, const char *str, unsigned int hex, int x, int y, int color, int bgcolor); 39 | 40 | void Debug(const char *format, ...); 41 | 42 | void ClearBot(); 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /include/font.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file was autogenerated by raw2c. 3 | Visit http://www.devkitpro.org 4 | */ 5 | 6 | //--------------------------------------------------------------------------------- 7 | #ifndef _font_h_ 8 | #define _font_h_ 9 | //--------------------------------------------------------------------------------- 10 | static const unsigned char font[] = { 11 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e, 12 | 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e, 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 13 | 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x3c, 0x3c, 0x18, 0xff, 0xe7, 0x18, 0x3c, 0x00, 14 | 0x10, 0x38, 0x7c, 0xfe, 0xee, 0x10, 0x38, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 15 | 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 16 | 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78, 17 | 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x08, 0x0c, 0x0a, 0x0a, 0x08, 0x78, 0xf0, 0x00, 18 | 0x18, 0x14, 0x1a, 0x16, 0x72, 0xe2, 0x0e, 0x1c, 0x10, 0x54, 0x38, 0xee, 0x38, 0x54, 0x10, 0x00, 19 | 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00, 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00, 20 | 0x18, 0x3c, 0x5a, 0x18, 0x5a, 0x3c, 0x18, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00, 21 | 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x00, 0x1c, 0x22, 0x38, 0x44, 0x44, 0x38, 0x88, 0x70, 22 | 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00, 0x18, 0x3c, 0x5a, 0x18, 0x5a, 0x3c, 0x18, 0x7e, 23 | 0x18, 0x3c, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x5a, 0x3c, 0x18, 0x00, 24 | 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 25 | 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x24, 0x42, 0xff, 0x42, 0x24, 0x00, 0x00, 26 | 0x00, 0x10, 0x38, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 27 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x00, 28 | 0x6c, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 29 | 0x10, 0x7c, 0xd0, 0x7c, 0x16, 0xfc, 0x10, 0x00, 0x00, 0x66, 0xac, 0xd8, 0x36, 0x6a, 0xcc, 0x00, 30 | 0x38, 0x4c, 0x38, 0x78, 0xce, 0xcc, 0x7a, 0x00, 0x30, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 31 | 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, 32 | 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00, 33 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 34 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x00, 35 | 0x7c, 0xce, 0xde, 0xf6, 0xe6, 0xe6, 0x7c, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x7e, 0x00, 36 | 0x7c, 0xc6, 0x06, 0x1c, 0x70, 0xc6, 0xfe, 0x00, 0x7c, 0xc6, 0x06, 0x3c, 0x06, 0xc6, 0x7c, 0x00, 37 | 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00, 0xfe, 0xc0, 0xfc, 0x06, 0x06, 0xc6, 0x7c, 0x00, 38 | 0x7c, 0xc6, 0xc0, 0xfc, 0xc6, 0xc6, 0x7c, 0x00, 0xfe, 0xc6, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00, 39 | 0x7c, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0x7c, 0x00, 0x7c, 0xc6, 0xc6, 0x7e, 0x06, 0xc6, 0x7c, 0x00, 40 | 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20, 41 | 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 42 | 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00, 43 | 0x7c, 0x82, 0x9e, 0xa6, 0x9e, 0x80, 0x7c, 0x00, 0x7c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 44 | 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 45 | 0xfc, 0x66, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00, 46 | 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00, 0x7c, 0xc6, 0xc6, 0xc0, 0xce, 0xc6, 0x7e, 0x00, 47 | 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 48 | 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00, 49 | 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x82, 0xc6, 0xee, 0xfe, 0xd6, 0xc6, 0xc6, 0x00, 50 | 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 51 | 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x06, 52 | 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xe6, 0x00, 0x7c, 0xc6, 0xc0, 0x7c, 0x06, 0xc6, 0x7c, 0x00, 53 | 0x7e, 0x5a, 0x5a, 0x18, 0x18, 0x18, 0x3c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 54 | 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x82, 0x00, 55 | 0xc6, 0x6c, 0x38, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x00, 56 | 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00, 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00, 57 | 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00, 58 | 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 59 | 0x30, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 60 | 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc6, 0x7c, 0x00, 61 | 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 62 | 0x1c, 0x36, 0x30, 0x78, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x78, 63 | 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, 64 | 0x00, 0x0c, 0x00, 0x1c, 0x0c, 0x0c, 0xcc, 0x78, 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00, 65 | 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0xcc, 0xfe, 0xd6, 0xd6, 0xd6, 0x00, 66 | 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 67 | 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0, 0x00, 0x00, 0x7c, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e, 68 | 0x00, 0x00, 0xde, 0x76, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x7c, 0xc0, 0x7c, 0x06, 0x7c, 0x00, 69 | 0x10, 0x30, 0xfc, 0x30, 0x30, 0x34, 0x18, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 70 | 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00, 0xc6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, 71 | 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, 72 | 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00, 0x0e, 0x18, 0x18, 0x30, 0x18, 0x18, 0x0e, 0x00, 73 | 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, 0xe0, 0x30, 0x30, 0x18, 0x30, 0x30, 0xe0, 0x00, 74 | 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00, 75 | 0x7c, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x18, 0x70, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 76 | 0x0e, 0x10, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 0x7c, 0x82, 0x38, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 77 | 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 0xe0, 0x10, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 78 | 0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x7c, 0xc0, 0xc0, 0x7c, 0x18, 0x70, 79 | 0x7c, 0x82, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 80 | 0xe0, 0x10, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, 81 | 0x7c, 0x82, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, 0xe0, 0x10, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, 82 | 0xc6, 0x00, 0x7c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x38, 0x38, 0x7c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 83 | 0x0e, 0x10, 0xfe, 0x60, 0x78, 0x60, 0xfe, 0x00, 0x00, 0x00, 0x7c, 0x12, 0x7e, 0xd0, 0x7e, 0x00, 84 | 0x7e, 0xc8, 0xc8, 0xfe, 0xc8, 0xc8, 0xce, 0x00, 0x7c, 0x82, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 85 | 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0xe0, 0x10, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 86 | 0x7c, 0x82, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0xe0, 0x10, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 87 | 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 88 | 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x18, 0x7c, 0xd6, 0xd0, 0xd6, 0x7c, 0x18, 0x00, 89 | 0x38, 0x6c, 0x60, 0xf0, 0x60, 0xf2, 0xdc, 0x00, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x7e, 0x18, 0x00, 90 | 0xf8, 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0x06, 0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70, 91 | 0x0e, 0x10, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 0x0e, 0x10, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, 92 | 0x0e, 0x10, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x0e, 0x10, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 93 | 0x66, 0x98, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x98, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0x00, 94 | 0x38, 0x0c, 0x3c, 0x34, 0x00, 0x7e, 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 95 | 0x30, 0x00, 0x30, 0x60, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00, 96 | 0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00, 0xc0, 0xc8, 0xd0, 0xfe, 0x46, 0x8c, 0x1e, 0x00, 97 | 0xc0, 0xc8, 0xd0, 0xec, 0x5c, 0xbe, 0x0c, 0x00, 0x18, 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x18, 0x00, 98 | 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 99 | 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 100 | 0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 101 | 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 102 | 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 103 | 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 104 | 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 105 | 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 106 | 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 107 | 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 108 | 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 109 | 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 110 | 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 111 | 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 112 | 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 113 | 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 114 | 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 115 | 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 116 | 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 117 | 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 118 | 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 119 | 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 120 | 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 121 | 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 122 | 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 123 | 0x00, 0x00, 0x74, 0xcc, 0xc8, 0xdc, 0x76, 0x00, 0x78, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xdc, 0x40, 124 | 0xfe, 0x62, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x02, 0x7e, 0xec, 0x6c, 0x6c, 0x48, 0x00, 125 | 0xfe, 0x62, 0x30, 0x18, 0x30, 0x62, 0xfe, 0x00, 0x00, 0x00, 0x7e, 0xd0, 0xc8, 0xc8, 0x70, 0x00, 126 | 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xf8, 0x80, 0x00, 0x00, 0x7e, 0xd8, 0x18, 0x18, 0x10, 0x00, 127 | 0x38, 0x10, 0x7c, 0xd6, 0xd6, 0x7c, 0x10, 0x38, 0x7c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x7c, 0x00, 128 | 0x7c, 0xc6, 0xc6, 0xc6, 0x6c, 0x28, 0xee, 0x00, 0x3c, 0x22, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00, 129 | 0x00, 0x00, 0x66, 0x99, 0x99, 0x66, 0x00, 0x00, 0x00, 0x06, 0x7c, 0x9e, 0xf2, 0x7c, 0xc0, 0x00, 130 | 0x00, 0x00, 0x7c, 0xc0, 0xf8, 0xc0, 0x7c, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 131 | 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x7e, 0x00, 132 | 0x30, 0x18, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0x00, 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0x7c, 0x00, 133 | 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, 134 | 0x00, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 135 | 0x38, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 136 | 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x00, 137 | 0xd8, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x30, 0xc0, 0xf0, 0x00, 0x00, 0x00, 0x00, 138 | 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 139 | 140 | }; 141 | const int font_size = sizeof(font); 142 | //--------------------------------------------------------------------------------- 143 | #endif //_font_h_ 144 | //--------------------------------------------------------------------------------- 145 | -------------------------------------------------------------------------------- /include/hid.h: -------------------------------------------------------------------------------- 1 | #ifndef HID_H 2 | #define HID_H 3 | 4 | #include "types.h" 5 | 6 | #define HID_PAD (*(vu32 *)0x10146000) 7 | 8 | #define BUTTON_NONE (0xFFF) 9 | #define BUTTON_A (1<<0) 10 | #define BUTTON_B (1<<1) 11 | #define BUTTON_SELECT (1<<2) 12 | #define BUTTON_START (1<<3) 13 | #define BUTTON_RIGHT (1<<4) 14 | #define BUTTON_LEFT (1<<5) 15 | #define BUTTON_UP (1<<6) 16 | #define BUTTON_DOWN (1<<7) 17 | #define BUTTON_R (1<<8) 18 | #define BUTTON_L (1<<9) 19 | #define BUTTON_X (1<<10) 20 | #define BUTTON_Y (1<<11) 21 | 22 | #define BUTTON_HELD(b, m) (~(b) & (m)) 23 | #define BUTTON_PRESSED(b, o, m) ((~(b) & (o)) & (m)) 24 | #define BUTTON_CHANGED(b, o, m) (((b) ^ (o)) & (m)) 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /include/i2c.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | #define I2C1_REG_OFF 0x10161000 6 | #define I2C2_REG_OFF 0x10144000 7 | #define I2C3_REG_OFF 0x10148000 8 | 9 | #define I2C_REG_DATA 0 10 | #define I2C_REG_CNT 1 11 | #define I2C_REG_CNTEX 2 12 | #define I2C_REG_SCL 4 13 | 14 | #define I2C_DEV_MCU 3 15 | #define I2C_DEV_GYRO 10 16 | #define I2C_DEV_IR 13 17 | 18 | u8 i2cGetDeviceBusId(u8 device_id); 19 | u8 i2cGetDeviceRegAddr(u8 device_id); 20 | 21 | vu8* i2cGetDataReg(u8 bus_id); 22 | vu8* i2cGetCntReg(u8 bus_id); 23 | 24 | void i2cWaitBusy(u8 bus_id); 25 | bool i2cGetResult(u8 bus_id); 26 | u8 i2cGetData(u8 bus_id); 27 | void i2cStop(u8 bus_id, u8 arg0); 28 | 29 | bool i2cSelectDevice(u8 bus_id, u8 dev_reg); 30 | bool i2cSelectRegister(u8 bus_id, u8 reg); 31 | 32 | u8 i2cReadRegister(u8 dev_id, u8 reg); 33 | bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data); 34 | 35 | bool i2cReadRegisterBuffer(unsigned int dev_id, int reg, u8* buffer, size_t buf_size); 36 | -------------------------------------------------------------------------------- /include/pxi.h: -------------------------------------------------------------------------------- 1 | #ifndef PXI_H 2 | #define PXI_H 3 | 4 | #include "types.h" 5 | #include "pxi_cmd.h" 6 | 7 | #define REG_PXI_SYNC9 (*(vu32 *)0x10008000) 8 | #define REG_PXI_CNT9 (*(vu32 *)0x10008004) 9 | #define REG_PXI_SEND9 (*(vu32 *)0x10008008) 10 | #define REG_PXI_RECV9 (*(vu32 *)0x1000800C) 11 | 12 | #define PXI_CNT_SEND_FIFO_EMPTY (1 << 0) 13 | #define PXI_CNT_SEND_FIFO_FULL (1 << 1) 14 | #define PXI_CNT_SEND_FIFO_EMPTY_IRQ (1 << 2) 15 | #define PXI_CNT_SEND_FIFO_FLUSH (1 << 3) 16 | #define PXI_CNT_RECV_FIFO_EMPTY (1 << 8) 17 | #define PXI_CNT_RECV_FIFO_FULL (1 << 9) 18 | #define PXI_CNT_RECV_FIFO_NOT_EMPTY_IRQ (1 << 10) 19 | #define PXI_CNT_FIFO_ENABLE (1 << 15) 20 | 21 | #define PXI_SYNC_TRIGGER_PXI_SYNC11 (1 << 29) 22 | #define PXI_SYNC_TRIGGER_PXI_SYNC9 (1 << 30) 23 | #define PXI_SYNC_IRQ_ENABLE (1 << 31) 24 | 25 | void pxi_init(void); 26 | void pxi_deinit(void); 27 | void pxi_recv_cmd_hdr(struct pxi_cmd_hdr *cmd); 28 | void pxi_recv_buffer(void *data, u32 size); 29 | void pxi_send_cmd_response(struct pxi_cmd_hdr *cmd); 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /include/pxi_cmd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * pxi_cmd.h 3 | * 4 | * Copyright (C) 2016 Sergi Granell 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License version 2 as 8 | * published by the Free Software Foundation. 9 | */ 10 | 11 | #ifndef __NINTENDO3DS_PXI_CMD_H 12 | #define __NINTENDO3DS_PXI_CMD_H 13 | 14 | #define PXI_CMD_NONE 0 15 | #define PXI_CMD_PING 1 16 | #define PXI_CMD_SDMMC_READ_SECTOR 2 17 | #define PXI_CMD_SDMMC_WRITE_SECTOR 3 18 | #define PXI_CMD_SDMMC_GET_SIZE 4 19 | 20 | struct pxi_cmd_hdr { 21 | struct { 22 | u16 cmd; 23 | u16 len; 24 | }; 25 | u32 data[0]; 26 | } __attribute__((packed)); 27 | 28 | struct pxi_cmd_sdmmc_read_sector { 29 | struct pxi_cmd_hdr header; 30 | u32 sector; 31 | u32 paddr; 32 | } __attribute__((packed)); 33 | 34 | struct pxi_cmd_sdmmc_write_sector { 35 | struct pxi_cmd_hdr header; 36 | u32 sector; 37 | u32 paddr; 38 | } __attribute__((packed)); 39 | 40 | struct pxi_resp_sdmmc_get_size { 41 | struct pxi_cmd_hdr header; 42 | u32 size; 43 | } __attribute__((packed)); 44 | 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /include/tmio.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, 4 | * You can obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * Copyright (c) 2014-2015, Normmatt, 173210 7 | * 8 | * Alternatively, the contents of this file may be used under the terms 9 | * of the GNU General Public License Version 2, as described below: 10 | * 11 | * This file is free software: you may copy, redistribute and/or modify 12 | * it under the terms of the GNU General Public License as published by the 13 | * Free Software Foundation, either version 2 of the License, or (at your 14 | * option) any later version. 15 | * 16 | * This file is distributed in the hope that it will be useful, but 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 19 | * Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see http://www.gnu.org/licenses/. 23 | */ 24 | 25 | #ifndef TMIO_H 26 | #define TMIO_H 27 | 28 | #include "types.h" 29 | 30 | enum tmio_dev_id { 31 | TMIO_DEV_SDMC = 0, 32 | TMIO_DEV_NAND = 1, 33 | 34 | TMIO_DEV_NUM 35 | }; 36 | 37 | struct tmio_dev { 38 | uint32_t initarg; 39 | uint32_t isSDHC; 40 | uint32_t clk; 41 | uint32_t SDOPT; 42 | uint32_t total_size; //size in sectors of the device 43 | uint32_t res; 44 | }; 45 | 46 | extern struct tmio_dev tmio_dev[TMIO_DEV_NUM]; 47 | 48 | void tmio_init(void); 49 | uint32_t tmio_init_sdmc(void); 50 | uint32_t tmio_init_nand(void); 51 | 52 | uint32_t tmio_readsectors(enum tmio_dev_id target, 53 | uint32_t sector_no, uint32_t numsectors, uint8_t *out); 54 | 55 | uint32_t tmio_writesectors(enum tmio_dev_id target, 56 | uint32_t sector_no, uint32_t numsectors, uint8_t *in); 57 | 58 | #define TMIO_BBS 512 59 | 60 | /* Shared variable with the interrupt handler */ 61 | extern int sdio_1_irq; 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /include/tmio_command.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, 4 | * You can obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * Copyright (c) 2016 173210 7 | * 8 | * Alternatively, the contents of this file may be used under the terms 9 | * of the GNU General Public License Version 2, as described below: 10 | * 11 | * This file is free software: you may copy, redistribute and/or modify 12 | * it under the terms of the GNU General Public License as published by the 13 | * Free Software Foundation, either version 2 of the License, or (at your 14 | * option) any later version. 15 | * 16 | * This file is distributed in the hope that it will be useful, but 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 19 | * Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see http://www.gnu.org/licenses/. 23 | */ 24 | 25 | #ifndef COMMAND_H 26 | #define COMMAND_H 27 | 28 | enum { 29 | // Class 1 30 | MMC_IDLE = 0, 31 | MMC_SEND_OP_COND = 1, 32 | MMC_ALL_SEND_CID = 2, 33 | MMC_SET_RELATIVE_ADDR = 3, 34 | MMC_SWITCH = 6, 35 | MMC_SELECT_CARD = 7, 36 | MMC_SEND_CSD = 9, 37 | MMC_SEND_STATUS = 13, 38 | // Class 2 39 | MMC_SET_BLOCKLEN = 16, 40 | MMC_READ_BLOCK_MULTI = 18, 41 | // Class 4 42 | MMC_WRITE_BLOCK_MULTI = 25, 43 | // Class 8 44 | MMC_APP_CMD = 55 45 | }; 46 | 47 | enum { 48 | // Class 0 49 | SD_SEND_IF_COND = 8, 50 | 51 | // Application command 52 | SD_APP_OP_COND = 41 53 | }; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /include/tmio_hardware.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, 4 | * You can obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * Copyright (c) 2014-2015, Normmatt, 173210 7 | * 8 | * Alternatively, the contents of this file may be used under the terms 9 | * of the GNU General Public License Version 2, as described below: 10 | * 11 | * This file is free software: you may copy, redistribute and/or modify 12 | * it under the terms of the GNU General Public License as published by the 13 | * Free Software Foundation, either version 2 of the License, or (at your 14 | * option) any later version. 15 | * 16 | * This file is distributed in the hope that it will be useful, but 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 19 | * Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see http://www.gnu.org/licenses/. 23 | */ 24 | 25 | #ifndef TMIO_HARDWARE_H 26 | #define TMIO_HARDWARE_H 27 | 28 | #define TMIO_BASE 0x10006000 29 | 30 | enum tmio_regs { 31 | REG_SDCMD = 0x00, 32 | REG_SDPORTSEL = 0x02, 33 | REG_SDCMDARG = 0x04, 34 | REG_SDSTOP = 0x08, 35 | REG_SDBLKCOUNT = 0x0a, 36 | 37 | REG_SDRESP0 = 0x0c, 38 | REG_SDRESP1 = 0x10, 39 | REG_SDRESP2 = 0x14, 40 | REG_SDRESP3 = 0x18, 41 | 42 | REG_SDSTATUS = 0x1c, 43 | 44 | REG_SDIRMASK = 0x20, 45 | REG_SDCLKCTL = 0x24 , 46 | 47 | REG_SDBLKLEN = 0x26, 48 | REG_SDOPT = 0x28, 49 | REG_SDFIFO = 0x30, 50 | 51 | REG_DATACTL = 0xd8, 52 | REG_SDRESET = 0xe0, 53 | REG_SDPROTECTED = 0xf6, //bit 0 determines if sd is protected or not? 54 | 55 | REG_DATACTL32 = 0x100, 56 | REG_SDBLKLEN32 = 0x104, 57 | REG_SDBLKCOUNT32 = 0x108, 58 | REG_SDFIFO32 = 0x10C, 59 | 60 | REG_CLK_AND_WAIT_CTL = 0x138, 61 | REG_RESET_SDIO = 0x1e0 62 | }; 63 | 64 | #define TMIO_STAT_CMDRESPEND 0x00000001 65 | #define TMIO_STAT_DATAEND 0x00000004 66 | #define TMIO_STAT_CARD_REMOVE 0x00000008 67 | #define TMIO_STAT_CARD_INSERT 0x00000010 68 | #define TMIO_STAT_SIGSTATE 0x00000020 69 | #define TMIO_STAT_WRPROTECT 0x00000080 70 | #define TMIO_STAT_CARD_REMOVE_A 0x00000100 71 | #define TMIO_STAT_CARD_INSERT_A 0x00000200 72 | #define TMIO_STAT_SIGSTATE_A 0x00000400 73 | #define TMIO_STAT_CMD_IDX_ERR 0x00010000 74 | #define TMIO_STAT_CRCFAIL 0x00020000 75 | #define TMIO_STAT_STOPBIT_ERR 0x00040000 76 | #define TMIO_STAT_DATATIMEOUT 0x00080000 77 | #define TMIO_STAT_RXOVERFLOW 0x00100000 78 | #define TMIO_STAT_TXUNDERRUN 0x00200000 79 | #define TMIO_STAT_CMDTIMEOUT 0x00400000 80 | #define TMIO_STAT_RXRDY 0x01000000 81 | #define TMIO_STAT_TXRQ 0x02000000 82 | #define TMIO_STAT_ILL_FUNC 0x20000000 83 | #define TMIO_STAT_CMD_BUSY 0x40000000 84 | #define TMIO_STAT_ILL_ACCESS 0x80000000 85 | 86 | #define TMIO_MASK_ALL 0x837f031d 87 | 88 | #define TMIO_MASK_GW (TMIO_STAT_ILL_ACCESS | TMIO_STAT_CMDTIMEOUT | TMIO_STAT_TXUNDERRUN | TMIO_STAT_RXOVERFLOW | \ 89 | TMIO_STAT_DATATIMEOUT | TMIO_STAT_STOPBIT_ERR | TMIO_STAT_CRCFAIL | TMIO_STAT_CMD_IDX_ERR) 90 | 91 | #define TMIO_MASK_READOP (TMIO_STAT_RXRDY | TMIO_STAT_DATAEND) 92 | #define TMIO_MASK_WRITEOP (TMIO_STAT_TXRQ | TMIO_STAT_DATAEND) 93 | 94 | enum { 95 | TMIO32_ENABLE = 0x0002, 96 | TMIO32_STAT_RXRDY = 0x0100, 97 | TMIO32_STAT_BUSY = 0x0200, 98 | TMIO32_IRQ_RXRDY = 0x0800, 99 | TMIO32_IRQ_TXRQ = 0x1000 100 | }; 101 | 102 | enum { 103 | TMIO_CMD_APP = 0x0040, 104 | TMIO_CMD_RESP_R1 = 0x0400, 105 | TMIO_CMD_RESP_R1B = 0x0500, 106 | TMIO_CMD_RESP_R2 = 0x0600, 107 | TMIO_CMD_RESP_R3 = 0x0700, 108 | TMIO_CMD_DATA_PRESENT = 0x0800, 109 | TMIO_CMD_TRANSFER_READ = 0x1000, 110 | TMIO_CMD_TRANSFER_MULTI = 0x2000 111 | }; 112 | 113 | #endif 114 | -------------------------------------------------------------------------------- /include/types.h: -------------------------------------------------------------------------------- 1 | #ifndef TYPES_H 2 | #define TYPES_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | typedef unsigned char u8; 9 | typedef unsigned short u16; 10 | typedef unsigned int u32; 11 | typedef unsigned long long u64; 12 | 13 | /*typedef unsigned char uint8_t; 14 | typedef unsigned short uint16_t; 15 | typedef unsigned int uint32_t; 16 | typedef unsigned long long uint64_t;*/ 17 | 18 | typedef volatile u8 vu8; 19 | typedef volatile u16 vu16; 20 | typedef volatile u32 vu32; 21 | typedef volatile u64 vu64; 22 | 23 | //typedef int bool; 24 | 25 | //#define NULL ((void *)0) 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /include/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H 2 | #define UTILS_H 3 | 4 | #include "types.h" 5 | 6 | #define REG_IRQ_IE (*(vu32 *)0x10001000) 7 | #define REG_IRQ_IF (*(vu32 *)0x10001004) 8 | 9 | #define REG_TIMER_CNT(n) (*(vu32 *)(0x10003002 + 4*(n))) 10 | 11 | #define IRQ_DMAC_1_0 (1 << 0) 12 | #define IRQ_DMAC_1_1 (1 << 1) 13 | #define IRQ_DMAC_1_2 (1 << 2) 14 | #define IRQ_DMAC_1_3 (1 << 3) 15 | #define IRQ_DMAC_1_4 (1 << 4) 16 | #define IRQ_DMAC_1_5 (1 << 5) 17 | #define IRQ_DMAC_1_6 (1 << 6) 18 | #define IRQ_DMAC_1_7 (1 << 7) 19 | #define IRQ_TIMER_0 (1 << 8) 20 | #define IRQ_TIMER_1 (1 << 9) 21 | #define IRQ_TIMER_2 (1 << 10) 22 | #define IRQ_TIMER_3 (1 << 11) 23 | #define IRQ_PXI_SYNC (1 << 12) 24 | #define IRQ_PXI_NOT_FULL (1 << 13) 25 | #define IRQ_PXI_NOT_EMPTY (1 << 14) 26 | #define IRQ_AES (1 << 15) 27 | #define IRQ_SDIO_1 (1 << 16) 28 | #define IRQ_SDIO_1_ASYNC (1 << 17) 29 | #define IRQ_SDIO_3 (1 << 18) 30 | #define IRQ_SDIO_3_ASYNC (1 << 19) 31 | #define IRQ_DEBUG_RECV (1 << 20) 32 | #define IRQ_DEBUG_SEND (1 << 21) 33 | #define IRQ_RSA (1 << 22) 34 | #define IRQ_CTR_CARD_1 (1 << 23) 35 | #define IRQ_CTR_CARD_2 (1 << 24) 36 | #define IRQ_CGC (1 << 25) 37 | #define IRQ_CGC_DET (1 << 26) 38 | #define IRQ_DS_CARD (1 << 27) 39 | #define IRQ_DMAC_2 (1 << 28) 40 | #define IRQ_DMAC_2_ABORT (1 << 29) 41 | 42 | void arm9_enable_irq(void); 43 | void arm9_disable_irq(void); 44 | void arm9_set_regular_exception_vectors(void); 45 | void arm9_wfi(void); 46 | void arm9_disable_timers(void); 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /linker.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") 2 | OUTPUT_ARCH(arm) 3 | 4 | SECTIONS 5 | { 6 | . = 0x08080000; 7 | .text.start : { *(.text.start) } 8 | .text : { *(.text) } 9 | .rodata : { *(.rodata) } 10 | .data : { *(.data) } 11 | .bss : { *(.bss COMMON) } 12 | . = ALIGN(0x1000); 13 | .stack : { 14 | . += 0x1000; 15 | _stack_end = .; 16 | } 17 | . = ALIGN(0x1000); 18 | .irq_stack : { 19 | . += 0x1000; 20 | _irq_stack_end = .; 21 | } 22 | __end__ = ABSOLUTE(.); 23 | } 24 | -------------------------------------------------------------------------------- /source/delay.s: -------------------------------------------------------------------------------- 1 | .arm 2 | .global waitcycles 3 | .type waitcycles STT_FUNC 4 | 5 | @waitcycles ( u32 us ) 6 | waitcycles: 7 | PUSH {R0-R2,LR} 8 | STR R0, [SP,#4] 9 | waitcycles_loop: 10 | LDR R3, [SP,#4] 11 | SUBS R2, R3, #1 12 | STR R2, [SP,#4] 13 | CMP R3, #0 14 | BNE waitcycles_loop 15 | POP {R0-R2,PC} 16 | -------------------------------------------------------------------------------- /source/draw.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "font.h" 7 | #include "draw.h" 8 | 9 | int current_y = 0; 10 | 11 | void ClearScreen(unsigned char *screen, int color) 12 | { 13 | int i; 14 | unsigned char *screenPos = screen; 15 | for (i = 0; i < (SCREEN_HEIGHT * SCREEN_WIDTH); i++) { 16 | *(screenPos++) = color >> 16; // B 17 | *(screenPos++) = color >> 8; // G 18 | *(screenPos++) = color & 0xFF; // R 19 | } 20 | } 21 | 22 | void DrawCharacter(unsigned char *screen, int character, int x, int y, int color, int bgcolor) 23 | { 24 | int yy, xx; 25 | for (yy = 0; yy < 8; yy++) { 26 | int xDisplacement = (x * BYTES_PER_PIXEL * SCREEN_WIDTH); 27 | int yDisplacement = ((SCREEN_WIDTH - (y + yy) - 1) * BYTES_PER_PIXEL); 28 | unsigned char *screenPos = screen + xDisplacement + yDisplacement; 29 | 30 | unsigned char charPos = font[character * 8 + yy]; 31 | for (xx = 7; xx >= 0; xx--) { 32 | if ((charPos >> xx) & 1) { 33 | *(screenPos + 0) = color >> 16; // B 34 | *(screenPos + 1) = color >> 8; // G 35 | *(screenPos + 2) = color & 0xFF; // R 36 | } else { 37 | *(screenPos + 0) = bgcolor >> 16; // B 38 | *(screenPos + 1) = bgcolor >> 8; // G 39 | *(screenPos + 2) = bgcolor & 0xFF; // R 40 | } 41 | screenPos += BYTES_PER_PIXEL * SCREEN_WIDTH; 42 | } 43 | } 44 | } 45 | 46 | void DrawString(unsigned char *screen, const char *str, int x, int y, int color, int bgcolor) 47 | { 48 | int i; 49 | for (i = 0; i < strlen(str); i++) 50 | DrawCharacter(screen, str[i], x + i * 8, y, color, bgcolor); 51 | } 52 | 53 | void DrawStringF(int x, int y, const char *format, ...) 54 | { 55 | char str[256]; 56 | va_list va; 57 | 58 | va_start(va, format); 59 | vsnprintf(str, 256, format, va); 60 | va_end(va); 61 | 62 | DrawString(BOT_SCREEN0, str, x, y, RGB(0, 0, 0), RGB(255, 255, 255)); 63 | DrawString(BOT_SCREEN1, str, x, y, RGB(0, 0, 0), RGB(255, 255, 255)); 64 | } 65 | 66 | void Debug(const char *format, ...) 67 | { 68 | char str[256]; 69 | va_list va; 70 | 71 | va_start(va, format); 72 | vsnprintf(str, 256, format, va); 73 | va_end(va); 74 | 75 | DrawString(BOT_SCREEN0, str, 10, current_y, RGB(0, 0, 0), RGB(255, 255, 255)); 76 | DrawString(BOT_SCREEN1, str, 10, current_y, RGB(0, 0, 0), RGB(255, 255, 255)); 77 | 78 | current_y += 10; 79 | if (current_y > SCREEN_HEIGHT) current_y = 0; 80 | } 81 | 82 | void ClearBot() 83 | { 84 | ClearScreen(BOT_SCREEN0, RGB(255, 255, 255)); 85 | ClearScreen(BOT_SCREEN1, RGB(255, 255, 255)); 86 | current_y = 0; 87 | } 88 | -------------------------------------------------------------------------------- /source/i2c.c: -------------------------------------------------------------------------------- 1 | #include "i2c.h" 2 | 3 | //----------------------------------------------------------------------------- 4 | 5 | static const struct { u8 bus_id, reg_addr; } dev_data[] = { 6 | {0, 0x4A}, {0, 0x7A}, {0, 0x78}, 7 | {1, 0x4A}, {1, 0x78}, {1, 0x2C}, 8 | {1, 0x2E}, {1, 0x40}, {1, 0x44}, 9 | {2, 0xD6}, {2, 0xD0}, {2, 0xD2}, 10 | {2, 0xA4}, {2, 0x9A}, {2, 0xA0}, 11 | }; 12 | 13 | inline u8 i2cGetDeviceBusId(u8 device_id) { 14 | return dev_data[device_id].bus_id; 15 | } 16 | 17 | inline u8 i2cGetDeviceRegAddr(u8 device_id) { 18 | return dev_data[device_id].reg_addr; 19 | } 20 | 21 | //----------------------------------------------------------------------------- 22 | 23 | static vu8* reg_data_addrs[] = { 24 | (vu8*)(I2C1_REG_OFF + I2C_REG_DATA), 25 | (vu8*)(I2C2_REG_OFF + I2C_REG_DATA), 26 | (vu8*)(I2C3_REG_OFF + I2C_REG_DATA), 27 | }; 28 | 29 | inline vu8* i2cGetDataReg(u8 bus_id) { 30 | return reg_data_addrs[bus_id]; 31 | } 32 | 33 | //----------------------------------------------------------------------------- 34 | 35 | static vu8* reg_cnt_addrs[] = { 36 | (vu8*)(I2C1_REG_OFF + I2C_REG_CNT), 37 | (vu8*)(I2C2_REG_OFF + I2C_REG_CNT), 38 | (vu8*)(I2C3_REG_OFF + I2C_REG_CNT), 39 | }; 40 | 41 | inline vu8* i2cGetCntReg(u8 bus_id) { 42 | return reg_cnt_addrs[bus_id]; 43 | } 44 | 45 | //----------------------------------------------------------------------------- 46 | 47 | inline void i2cWaitBusy(u8 bus_id) { 48 | while (*i2cGetCntReg(bus_id) & 0x80); 49 | } 50 | 51 | inline bool i2cGetResult(u8 bus_id) { 52 | i2cWaitBusy(bus_id); 53 | return (*i2cGetCntReg(bus_id) >> 4) & 1; 54 | } 55 | 56 | void i2cStop(u8 bus_id, u8 arg0) { 57 | *i2cGetCntReg(bus_id) = (arg0 << 5) | 0xC0; 58 | i2cWaitBusy(bus_id); 59 | *i2cGetCntReg(bus_id) = 0xC5; 60 | } 61 | 62 | //----------------------------------------------------------------------------- 63 | 64 | bool i2cSelectDevice(u8 bus_id, u8 dev_reg) { 65 | i2cWaitBusy(bus_id); 66 | *i2cGetDataReg(bus_id) = dev_reg; 67 | *i2cGetCntReg(bus_id) = 0xC2; 68 | return i2cGetResult(bus_id); 69 | } 70 | 71 | bool i2cSelectRegister(u8 bus_id, u8 reg) { 72 | i2cWaitBusy(bus_id); 73 | *i2cGetDataReg(bus_id) = reg; 74 | *i2cGetCntReg(bus_id) = 0xC0; 75 | return i2cGetResult(bus_id); 76 | } 77 | 78 | //----------------------------------------------------------------------------- 79 | 80 | u8 i2cReadRegister(u8 dev_id, u8 reg) { 81 | u8 bus_id = i2cGetDeviceBusId(dev_id); 82 | u8 dev_addr = i2cGetDeviceRegAddr(dev_id); 83 | 84 | for (size_t i = 0; i < 8; i++) { 85 | if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg)) { 86 | if (i2cSelectDevice(bus_id, dev_addr | 1)) { 87 | i2cWaitBusy(bus_id); 88 | i2cStop(bus_id, 1); 89 | i2cWaitBusy(bus_id); 90 | return *i2cGetDataReg(bus_id); 91 | } 92 | } 93 | *i2cGetCntReg(bus_id) = 0xC5; 94 | i2cWaitBusy(bus_id); 95 | } 96 | return 0xff; 97 | } 98 | 99 | bool i2cReadRegisterBuffer(unsigned int dev_id, int reg, u8* buffer, size_t buf_size) { 100 | u8 bus_id = i2cGetDeviceBusId(dev_id); 101 | u8 dev_addr = i2cGetDeviceRegAddr(dev_id); 102 | 103 | size_t j = 0; 104 | while (!i2cSelectDevice(bus_id, dev_addr) 105 | || !i2cSelectRegister(bus_id, reg) 106 | || !i2cSelectDevice(bus_id, dev_addr | 1)) 107 | { 108 | i2cWaitBusy(bus_id); 109 | *i2cGetCntReg(bus_id) = 0xC5; 110 | i2cWaitBusy(bus_id); 111 | if (++j >= 8) 112 | return false; 113 | } 114 | 115 | if (buf_size != 1) { 116 | for (size_t i = 0; i < buf_size - 1; i++) { 117 | i2cWaitBusy(bus_id); 118 | *i2cGetCntReg(bus_id) = 0xF0; 119 | i2cWaitBusy(bus_id); 120 | buffer[i] = *i2cGetDataReg(bus_id); 121 | } 122 | } 123 | 124 | i2cWaitBusy(bus_id); 125 | *i2cGetCntReg(bus_id) = 0xE1; 126 | i2cWaitBusy(bus_id); 127 | buffer[buf_size - 1] = *i2cGetDataReg(bus_id); 128 | return true; 129 | } 130 | 131 | bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data) { 132 | u8 bus_id = i2cGetDeviceBusId(dev_id); 133 | u8 dev_addr = i2cGetDeviceRegAddr(dev_id); 134 | 135 | for (int i = 0; i < 8; i++) { 136 | if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg)) { 137 | i2cWaitBusy(bus_id); 138 | *i2cGetDataReg(bus_id) = data; 139 | *i2cGetCntReg(bus_id) = 0xC1; 140 | i2cStop(bus_id, 0); 141 | if (i2cGetResult(bus_id)) 142 | return true; 143 | } 144 | *i2cGetCntReg(bus_id) = 0xC5; 145 | i2cWaitBusy(bus_id); 146 | } 147 | 148 | return false; 149 | } 150 | -------------------------------------------------------------------------------- /source/libc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void *memset(void *s, int c, size_t n) 5 | { 6 | char *p = s; 7 | 8 | while (n) { 9 | *p++ = c; 10 | n--; 11 | } 12 | 13 | return s; 14 | } 15 | 16 | void *memcpy(void *dest, const void *src, size_t n) 17 | { 18 | const char *s = src; 19 | char *d = dest; 20 | 21 | while (n) { 22 | *d++ = *s++; 23 | n--; 24 | } 25 | 26 | return dest; 27 | } 28 | 29 | int memcmp(const void *s1, const void *s2, size_t n) 30 | { 31 | unsigned char u1, u2; 32 | 33 | for (; n--; s1++, s2++) { 34 | u1 = *(unsigned char *)s1; 35 | u2 = *(unsigned char *)s2; 36 | if (u1 != u2) 37 | return u1 - u2; 38 | } 39 | 40 | return 0; 41 | } 42 | 43 | size_t strlen(const char *str) 44 | { 45 | const char *s = str; 46 | 47 | while (*s) 48 | s++; 49 | 50 | return s - str; 51 | } 52 | -------------------------------------------------------------------------------- /source/main.c: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "utils.h" 3 | #include "pxi.h" 4 | #include "draw.h" 5 | #include "hid.h" 6 | #include "i2c.h" 7 | #include "tmio.h" 8 | 9 | #define POWEROFF_MASK (BUTTON_L | BUTTON_R | BUTTON_DOWN | BUTTON_B) 10 | 11 | static void mcu_poweroff() 12 | { 13 | i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 0); 14 | while (1) ; 15 | } 16 | 17 | static void check_poweroff() 18 | { 19 | if ((BUTTON_HELD(HID_PAD, POWEROFF_MASK) & 0x7FF) == POWEROFF_MASK) 20 | mcu_poweroff(); 21 | } 22 | 23 | static union { 24 | struct pxi_cmd_hdr header; 25 | u8 buffer[128]; 26 | } pxi_work; 27 | 28 | static void reset_pxi_pending_work(void) 29 | { 30 | pxi_work.header.cmd = PXI_CMD_NONE; 31 | } 32 | 33 | static void reset_pending_work(void) 34 | { 35 | reset_pxi_pending_work(); 36 | } 37 | 38 | static void do_pxi_cmd_ping_work(void) 39 | { 40 | struct pxi_cmd_hdr *cmd = 41 | (struct pxi_cmd_hdr *)&pxi_work; 42 | struct pxi_cmd_hdr resp; 43 | resp.cmd = cmd->cmd; 44 | resp.len = 0; 45 | 46 | pxi_send_cmd_response(&resp); 47 | reset_pxi_pending_work(); 48 | } 49 | 50 | static void do_pxi_cmd_sdmmc_read_sector_work(void) 51 | { 52 | struct pxi_cmd_sdmmc_read_sector *cmd = 53 | (struct pxi_cmd_sdmmc_read_sector *)&pxi_work; 54 | struct pxi_cmd_hdr resp; 55 | resp.cmd = cmd->header.cmd; 56 | resp.len = 0; 57 | 58 | //Debug("{sector = 0x%08X, paddr = 0x%08X}", cmd->sector, cmd->paddr); 59 | 60 | tmio_readsectors(TMIO_DEV_SDMC, cmd->sector, 1, (void *)cmd->paddr); 61 | 62 | pxi_send_cmd_response(&resp); 63 | reset_pxi_pending_work(); 64 | } 65 | 66 | static void do_pxi_cmd_sdmmc_write_sector_work(void) 67 | { 68 | struct pxi_cmd_sdmmc_write_sector *cmd = 69 | (struct pxi_cmd_sdmmc_write_sector *)&pxi_work; 70 | struct pxi_cmd_hdr resp; 71 | resp.cmd = cmd->header.cmd; 72 | resp.len = 0; 73 | 74 | tmio_writesectors(TMIO_DEV_SDMC, cmd->sector, 1, (void *)cmd->paddr); 75 | 76 | pxi_send_cmd_response(&resp); 77 | reset_pxi_pending_work(); 78 | } 79 | 80 | static void do_pxi_cmd_sdmmc_get_size_work(void) 81 | { 82 | struct pxi_cmd_hdr *cmd = 83 | (struct pxi_cmd_hdr *)&pxi_work; 84 | struct pxi_resp_sdmmc_get_size resp; 85 | resp.header.cmd = cmd->cmd; 86 | resp.header.len = 4; 87 | 88 | resp.size = tmio_dev[TMIO_DEV_SDMC].total_size; 89 | 90 | pxi_send_cmd_response((struct pxi_cmd_hdr*)&resp); 91 | reset_pxi_pending_work(); 92 | } 93 | 94 | static void check_pending_work(void) 95 | { 96 | if (pxi_work.header.cmd != PXI_CMD_NONE) { 97 | switch (pxi_work.header.cmd) { 98 | case PXI_CMD_PING: 99 | do_pxi_cmd_ping_work(); 100 | break; 101 | case PXI_CMD_SDMMC_READ_SECTOR: 102 | do_pxi_cmd_sdmmc_read_sector_work(); 103 | break; 104 | case PXI_CMD_SDMMC_WRITE_SECTOR: 105 | do_pxi_cmd_sdmmc_write_sector_work(); 106 | break; 107 | case PXI_CMD_SDMMC_GET_SIZE: 108 | do_pxi_cmd_sdmmc_get_size_work(); 109 | break; 110 | } 111 | } 112 | } 113 | 114 | void __attribute__((interrupt("IRQ"))) interrupt_vector(void) 115 | { 116 | register u32 irq_if = REG_IRQ_IF; 117 | 118 | /* if (irq_if & (IRQ_PXI_SYNC | IRQ_PXI_NOT_EMPTY | IRQ_PXI_NOT_FULL)) 119 | Debug("IRQ: 0x%08X", irq_if); */ 120 | 121 | if (irq_if & IRQ_SDIO_1) { 122 | /* Acknowledge interrupt */ 123 | REG_IRQ_IF = IRQ_SDIO_1; 124 | irq_if &= ~IRQ_SDIO_1; 125 | 126 | /* Tell the TMIO controller that we have an interrupt */ 127 | sdio_1_irq = 1; 128 | } 129 | 130 | if (irq_if & IRQ_PXI_SYNC) { 131 | REG_IRQ_IF = IRQ_PXI_SYNC; 132 | irq_if &= ~IRQ_PXI_SYNC; 133 | 134 | pxi_recv_cmd_hdr(&pxi_work.header); 135 | pxi_recv_buffer(pxi_work.header.data, pxi_work.header.len); 136 | } 137 | 138 | /*if (irq_if & IRQ_PXI_NOT_EMPTY) { 139 | REG_IRQ_IF = IRQ_PXI_NOT_EMPTY; 140 | irq_if &= ~IRQ_PXI_NOT_EMPTY; 141 | 142 | do { 143 | word = pxi_recv_fifo_pop(); 144 | Debug("wrd: 0x%08X head: %d tail: %d", word, pxi_recv_buf_head, pxi_recv_buf_tail); 145 | *(uint32_t *)&pxi_recv_buf[pxi_recv_buf_head] = word; 146 | pxi_recv_buf_head = (pxi_recv_buf_head + 4) % PXI_BUFFER_SIZE; 147 | pxi_recv_buf_size += 4; 148 | } while (!pxi_recv_fifo_is_empty() && (pxi_recv_buf_size + 4) < PXI_BUFFER_SIZE); 149 | } 150 | 151 | if (irq_if & IRQ_PXI_NOT_FULL) { 152 | REG_IRQ_IF = IRQ_PXI_NOT_FULL; 153 | irq_if &= ~IRQ_PXI_NOT_FULL; 154 | 155 | do { 156 | word = *(uint32_t *)&pxi_send_buf[pxi_send_buf_tail]; 157 | pxi_send_fifo_push(word); 158 | pxi_send_buf_tail = (pxi_send_buf_tail + 4) % PXI_BUFFER_SIZE; 159 | pxi_send_buf_size -= 4; 160 | } while (!pxi_send_fifo_is_full() && pxi_send_buf_size > 4); 161 | }*/ 162 | 163 | /* Acknowledge unhandled interrupts */ 164 | REG_IRQ_IF = irq_if; 165 | } 166 | 167 | int main(void) 168 | { 169 | ClearBot(); 170 | Debug("arm9linuxfw by xerpi"); 171 | 172 | arm9_disable_irq(); 173 | arm9_set_regular_exception_vectors(); 174 | arm9_disable_timers(); 175 | 176 | /* Disable all the interrupts */ 177 | REG_IRQ_IE = 0; 178 | /* Acknowledge all the tnterrupts */ 179 | REG_IRQ_IF = ~0; 180 | /* Enable PXI and SD Interrupts */ 181 | REG_IRQ_IE = IRQ_PXI_SYNC | IRQ_PXI_NOT_FULL | IRQ_PXI_NOT_EMPTY | 182 | IRQ_SDIO_1; 183 | 184 | reset_pending_work(); 185 | arm9_enable_irq(); 186 | 187 | pxi_init(); 188 | tmio_init(); 189 | tmio_init_sdmc(); 190 | 191 | for (;;) { 192 | //arm9_wfi(); 193 | check_pending_work(); 194 | 195 | 196 | /*while (pxi_recv_fifo_is_empty()) 197 | check_poweroff(); 198 | 199 | data = pxi_recv_fifo_pop(); 200 | 201 | tmio_readsectors(TMIO_DEV_SDMC, data, 1, buf); 202 | 203 | for (i = 0; i < TMIO_BBS; i += 4) { 204 | while (pxi_send_fifo_is_full()) 205 | ; 206 | pxi_send_fifo_push(*(uint32_t *)&buf[i]); 207 | }*/ 208 | 209 | check_poweroff(); 210 | } 211 | 212 | 213 | return 0; 214 | } 215 | -------------------------------------------------------------------------------- /source/pxi.c: -------------------------------------------------------------------------------- 1 | #include "pxi.h" 2 | #include "utils.h" 3 | 4 | static inline int pxi_send_fifo_is_empty() 5 | { 6 | return REG_PXI_CNT9 & PXI_CNT_SEND_FIFO_EMPTY; 7 | } 8 | 9 | static inline int pxi_send_fifo_is_full() 10 | { 11 | return REG_PXI_CNT9 & PXI_CNT_SEND_FIFO_FULL; 12 | } 13 | 14 | static inline int pxi_recv_fifo_is_empty() 15 | { 16 | return REG_PXI_CNT9 & PXI_CNT_RECV_FIFO_EMPTY; 17 | } 18 | 19 | static inline int pxi_recv_fifo_is_full() 20 | { 21 | return REG_PXI_CNT9 & PXI_CNT_RECV_FIFO_FULL; 22 | } 23 | 24 | static inline void pxi_send_fifo_push(u32 word) 25 | { 26 | REG_PXI_SEND9 = word; 27 | } 28 | 29 | static inline u32 pxi_recv_fifo_pop(void) 30 | { 31 | return REG_PXI_RECV9; 32 | } 33 | 34 | static inline void pxi_trigger_sync11_irq(void) 35 | { 36 | REG_PXI_SYNC9 |= PXI_SYNC_TRIGGER_PXI_SYNC11; 37 | } 38 | 39 | static void pxi_reset(void) 40 | { 41 | unsigned int i; 42 | 43 | REG_PXI_SYNC9 = 0; 44 | REG_PXI_CNT9 = PXI_CNT_SEND_FIFO_FLUSH; 45 | 46 | for (i = 0; i < 32; i++) { 47 | REG_PXI_RECV9; 48 | } 49 | 50 | REG_PXI_CNT9 = PXI_CNT_SEND_FIFO_EMPTY_IRQ | 51 | PXI_CNT_RECV_FIFO_NOT_EMPTY_IRQ | 52 | PXI_CNT_FIFO_ENABLE; 53 | 54 | REG_PXI_SYNC9 = PXI_SYNC_IRQ_ENABLE; 55 | } 56 | 57 | void pxi_init(void) 58 | { 59 | pxi_reset(); 60 | } 61 | 62 | void pxi_deinit(void) 63 | { 64 | } 65 | 66 | void pxi_recv_cmd_hdr(struct pxi_cmd_hdr *cmd) 67 | { 68 | *(u32 *)cmd = pxi_recv_fifo_pop(); 69 | } 70 | 71 | void pxi_recv_buffer(void *data, u32 size) 72 | { 73 | u32 i; 74 | 75 | for (i = 0; i < size; i+=4) { 76 | while (pxi_recv_fifo_is_empty()) 77 | ; 78 | ((u32 *)data)[i/4] = pxi_recv_fifo_pop(); 79 | } 80 | } 81 | 82 | void pxi_send_cmd_response(struct pxi_cmd_hdr *cmd) 83 | { 84 | unsigned int i; 85 | 86 | while (pxi_send_fifo_is_full()) 87 | ; 88 | 89 | /* 90 | * Send command ID and length. 91 | */ 92 | pxi_send_fifo_push(*(u32 *)cmd); 93 | pxi_trigger_sync11_irq(); 94 | 95 | /* 96 | * Send the command payload (if any). 97 | */ 98 | for (i = 0; i < cmd->len; i+=4) { 99 | pxi_send_fifo_push(cmd->data[i/4]); 100 | } 101 | } 102 | 103 | -------------------------------------------------------------------------------- /source/start.s: -------------------------------------------------------------------------------- 1 | .set ARM_MODE_IRQ, 0x12 2 | .set ARM_MODE_SYS, 0x1F 3 | .set FIQ_DISABLE, 0x40 4 | .set IRQ_DISABLE, 0x80 5 | 6 | .section .text.start 7 | 8 | .global _start 9 | _start: 10 | @ Set IRQ stack 11 | msr cpsr_c, #(ARM_MODE_IRQ|IRQ_DISABLE|FIQ_DISABLE) 12 | ldr sp, =_irq_stack_end 13 | 14 | @ Set SYS mode stack 15 | msr cpsr_c, #(ARM_MODE_SYS|IRQ_DISABLE|FIQ_DISABLE) 16 | ldr sp, =_stack_end 17 | 18 | @ Disable caches / mpu 19 | mrc p15, 0, r4, c1, c0, 0 @ read control register 20 | bic r4, #(1 << 12) @ - instruction cache disable 21 | bic r4, #(1 << 2) @ - data cache disable 22 | bic r4, #(1 << 0) @ - mpu disable 23 | mcr p15, 0, r4, c1, c0, 0 @ write control register 24 | 25 | @ Give read/write access to all the memory regions 26 | ldr r5, =0x33333333 27 | mcr p15, 0, r5, c5, c0, 2 @ write data access 28 | mcr p15, 0, r5, c5, c0, 3 @ write instruction access 29 | 30 | @ Sets MPU permissions and cache settings 31 | ldr r0, =0x0000001D @ ITCM - 00000000 32k 32 | ldr r1, =0x01FF801D @ ITCM - 01ff8000 32k 33 | ldr r2, =0x08000027 @ ARM9 internal mem - 08000000 1M 34 | ldr r3, =0x10000021 @ I/O mem - 10000000 128k 35 | ldr r4, =0x10100025 @ I/O mem - 10100000 512k 36 | ldr r5, =0x20000035 @ FCRAM - 20000000 128M 37 | ldr r6, =0x1FF00027 @ DSP mem - 1FF00000 1M 38 | ldr r7, =0x1800002D @ VRAM - 18000000 8M 39 | mov r8, #0x25 40 | mcr p15, 0, r0, c6, c0, 0 41 | mcr p15, 0, r1, c6, c1, 0 42 | mcr p15, 0, r2, c6, c2, 0 43 | mcr p15, 0, r3, c6, c3, 0 44 | mcr p15, 0, r4, c6, c4, 0 45 | mcr p15, 0, r5, c6, c5, 0 46 | mcr p15, 0, r6, c6, c6, 0 47 | mcr p15, 0, r7, c6, c7, 0 48 | mcr p15, 0, r8, c3, c0, 0 @ Write bufferable 0, 2, 5 49 | mcr p15, 0, r8, c2, c0, 0 @ Data cacheable 0, 2, 5 50 | mcr p15, 0, r8, c2, c0, 1 @ Inst cacheable 0, 2, 5 51 | 52 | @ Enable caches 53 | mrc p15, 0, r4, c1, c0, 0 @ read control register 54 | orr r4, r4, #(1<<18) @ - itcm enable 55 | orr r4, r4, #(1<<12) @ - instruction cache enable 56 | orr r4, r4, #(1<<2) @ - data cache enable 57 | orr r4, r4, #(1<<0) @ - mpu enable 58 | mcr p15, 0, r4, c1, c0, 0 @ write control register 59 | 60 | @ Flush caches 61 | mov r5, #0 62 | mcr p15, 0, r5, c7, c5, 0 @ flush I-cache 63 | mcr p15, 0, r5, c7, c6, 0 @ flush D-cache 64 | mcr p15, 0, r5, c7, c10, 4 @ drain write buffer 65 | 66 | @ Fixes mounting of SDMC 67 | ldr r0, =0x10000020 68 | mov r1, #0x340 69 | str r1, [r0] 70 | 71 | @ Copy interrupt vectors to 0x00000000 (ITCM) 72 | ldr r0, =_interrupt_vectors_table 73 | ldr r1, =0x00000000 74 | ldmia r0!, {r2, r3, r4, r5, r6, r7, r8, r9} 75 | stmia r1!, {r2, r3, r4, r5, r6, r7, r8, r9} 76 | ldmia r0!, {r2, r3, r4, r5, r6, r7, r8, r9} 77 | stmia r1!, {r2, r3, r4, r5, r6, r7, r8, r9} 78 | 79 | blx main 80 | 81 | _stub_interrupt_vector_handler: 82 | subs pc, lr, #4 83 | 84 | _interrupt_vectors_table: 85 | ldr pc, _reset_h 86 | ldr pc, _undefined_instruction_vector_h 87 | ldr pc, _software_interrupt_vector_h 88 | ldr pc, _prefetch_abort_vector_h 89 | ldr pc, _data_abort_vector_h 90 | ldr pc, _reserved_handler_h 91 | ldr pc, _interrupt_vector_h 92 | ldr pc, _fast_interrupt_vector_h 93 | 94 | _reset_h: .word _start 95 | _undefined_instruction_vector_h: .word _stub_interrupt_vector_handler 96 | _software_interrupt_vector_h: .word _stub_interrupt_vector_handler 97 | _prefetch_abort_vector_h: .word _stub_interrupt_vector_handler 98 | _data_abort_vector_h: .word _stub_interrupt_vector_handler 99 | _reserved_handler_h: .word _stub_interrupt_vector_handler 100 | _interrupt_vector_h: .word interrupt_vector 101 | _fast_interrupt_vector_h: .word _stub_interrupt_vector_handler 102 | -------------------------------------------------------------------------------- /source/tiny-printf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Tiny printf version for SPL 3 | * 4 | * Copied from: 5 | * http://www.sparetimelabs.com/printfrevisited/printfrevisited.php 6 | * 7 | * Copyright (C) 2004,2008 Kustaa Nyholm 8 | * 9 | * SPDX-License-Identifier: LGPL-2.1+ 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | static inline int isalpha(int c) 17 | { 18 | return ((unsigned)c | 32) - 'a' < 26; 19 | } 20 | 21 | static inline int isdigit(int c) 22 | { 23 | return (unsigned)c - '0' < 10; 24 | } 25 | 26 | static inline int isalnum(int c) 27 | { 28 | return isalpha(c) || isdigit(c); 29 | } 30 | 31 | struct printf_info { 32 | char *bf; /* Digit buffer */ 33 | char zs; /* non-zero if a digit has been written */ 34 | char *outstr; /* Next output position for sprintf() */ 35 | 36 | /* Output a character */ 37 | void (*putc)(struct printf_info *info, char ch); 38 | }; 39 | 40 | static void putc_normal(struct printf_info *info, char ch) 41 | { 42 | /* putc(ch); */ 43 | } 44 | 45 | static void out(struct printf_info *info, char c) 46 | { 47 | *info->bf++ = c; 48 | } 49 | 50 | static void out_dgt(struct printf_info *info, char dgt) 51 | { 52 | out(info, dgt + (dgt < 10 ? '0' : 'a' - 10)); 53 | info->zs = 1; 54 | } 55 | 56 | static void div_out(struct printf_info *info, unsigned long *num, 57 | unsigned long div) 58 | { 59 | unsigned char dgt = 0; 60 | 61 | while (*num >= div) { 62 | *num -= div; 63 | dgt++; 64 | } 65 | 66 | if (info->zs || dgt > 0) 67 | out_dgt(info, dgt); 68 | } 69 | 70 | #ifdef CONFIG_SPL_NET_SUPPORT 71 | static void string(struct printf_info *info, char *s) 72 | { 73 | char ch; 74 | 75 | while ((ch = *s++)) 76 | out(info, ch); 77 | } 78 | 79 | static const char hex_asc[] = "0123456789abcdef"; 80 | #define hex_asc_lo(x) hex_asc[((x) & 0x0f)] 81 | #define hex_asc_hi(x) hex_asc[((x) & 0xf0) >> 4] 82 | 83 | static inline char *pack_hex_byte(char *buf, u8 byte) 84 | { 85 | *buf++ = hex_asc_hi(byte); 86 | *buf++ = hex_asc_lo(byte); 87 | return buf; 88 | } 89 | 90 | static void mac_address_string(struct printf_info *info, u8 *addr, 91 | bool separator) 92 | { 93 | /* (6 * 2 hex digits), 5 colons and trailing zero */ 94 | char mac_addr[6 * 3]; 95 | char *p = mac_addr; 96 | int i; 97 | 98 | for (i = 0; i < 6; i++) { 99 | p = pack_hex_byte(p, addr[i]); 100 | if (separator && i != 5) 101 | *p++ = ':'; 102 | } 103 | *p = '\0'; 104 | 105 | string(info, mac_addr); 106 | } 107 | 108 | static char *put_dec_trunc(char *buf, unsigned int q) 109 | { 110 | unsigned int d3, d2, d1, d0; 111 | d1 = (q >> 4) & 0xf; 112 | d2 = (q >> 8) & 0xf; 113 | d3 = (q >> 12); 114 | 115 | d0 = 6 * (d3 + d2 + d1) + (q & 0xf); 116 | q = (d0 * 0xcd) >> 11; 117 | d0 = d0 - 10 * q; 118 | *buf++ = d0 + '0'; /* least significant digit */ 119 | d1 = q + 9 * d3 + 5 * d2 + d1; 120 | if (d1 != 0) { 121 | q = (d1 * 0xcd) >> 11; 122 | d1 = d1 - 10 * q; 123 | *buf++ = d1 + '0'; /* next digit */ 124 | 125 | d2 = q + 2 * d2; 126 | if ((d2 != 0) || (d3 != 0)) { 127 | q = (d2 * 0xd) >> 7; 128 | d2 = d2 - 10 * q; 129 | *buf++ = d2 + '0'; /* next digit */ 130 | 131 | d3 = q + 4 * d3; 132 | if (d3 != 0) { 133 | q = (d3 * 0xcd) >> 11; 134 | d3 = d3 - 10 * q; 135 | *buf++ = d3 + '0'; /* next digit */ 136 | if (q != 0) 137 | *buf++ = q + '0'; /* most sign. digit */ 138 | } 139 | } 140 | } 141 | return buf; 142 | } 143 | 144 | static void ip4_addr_string(struct printf_info *info, u8 *addr) 145 | { 146 | /* (4 * 3 decimal digits), 3 dots and trailing zero */ 147 | char ip4_addr[4 * 4]; 148 | char temp[3]; /* hold each IP quad in reverse order */ 149 | char *p = ip4_addr; 150 | int i, digits; 151 | 152 | for (i = 0; i < 4; i++) { 153 | digits = put_dec_trunc(temp, addr[i]) - temp; 154 | /* reverse the digits in the quad */ 155 | while (digits--) 156 | *p++ = temp[digits]; 157 | if (i != 3) 158 | *p++ = '.'; 159 | } 160 | *p = '\0'; 161 | 162 | string(info, ip4_addr); 163 | } 164 | #endif 165 | 166 | /* 167 | * Show a '%p' thing. A kernel extension is that the '%p' is followed 168 | * by an extra set of characters that are extended format 169 | * specifiers. 170 | * 171 | * Right now we handle: 172 | * 173 | * - 'M' For a 6-byte MAC address, it prints the address in the 174 | * usual colon-separated hex notation. 175 | * - 'm' Same as above except there is no colon-separator. 176 | * - 'I4'for IPv4 addresses printed in the usual way (dot-separated 177 | * decimal). 178 | */ 179 | 180 | static void pointer(struct printf_info *info, const char *fmt, void *ptr) 181 | { 182 | #ifdef DEBUG 183 | unsigned long num = (uintptr_t)ptr; 184 | unsigned long div; 185 | #endif 186 | 187 | switch (*fmt) { 188 | #ifdef DEBUG 189 | case 'a': 190 | 191 | switch (fmt[1]) { 192 | case 'p': 193 | default: 194 | num = *(phys_addr_t *)ptr; 195 | break; 196 | } 197 | break; 198 | #endif 199 | #ifdef CONFIG_SPL_NET_SUPPORT 200 | case 'm': 201 | return mac_address_string(info, ptr, false); 202 | case 'M': 203 | return mac_address_string(info, ptr, true); 204 | case 'I': 205 | if (fmt[1] == '4') 206 | return ip4_addr_string(info, ptr); 207 | #endif 208 | default: 209 | break; 210 | } 211 | #ifdef DEBUG 212 | div = 1UL << (sizeof(long) * 8 - 4); 213 | for (; div; div /= 0x10) 214 | div_out(info, &num, div); 215 | #endif 216 | } 217 | 218 | static int _vprintf(struct printf_info *info, const char *fmt, va_list va) 219 | { 220 | char ch; 221 | char *p; 222 | unsigned long num; 223 | char buf[12]; 224 | unsigned long div; 225 | 226 | while ((ch = *(fmt++))) { 227 | if (ch != '%') { 228 | info->putc(info, ch); 229 | } else { 230 | bool lz = false; 231 | int width = 0; 232 | bool islong = false; 233 | 234 | ch = *(fmt++); 235 | if (ch == '-') 236 | ch = *(fmt++); 237 | 238 | if (ch == '0') { 239 | ch = *(fmt++); 240 | lz = 1; 241 | } 242 | 243 | if (ch >= '0' && ch <= '9') { 244 | width = 0; 245 | while (ch >= '0' && ch <= '9') { 246 | width = (width * 10) + ch - '0'; 247 | ch = *fmt++; 248 | } 249 | } 250 | if (ch == 'l') { 251 | ch = *(fmt++); 252 | islong = true; 253 | } 254 | 255 | info->bf = buf; 256 | p = info->bf; 257 | info->zs = 0; 258 | 259 | switch (ch) { 260 | case '\0': 261 | goto abort; 262 | case 'u': 263 | case 'd': 264 | div = 1000000000; 265 | if (islong) { 266 | num = va_arg(va, unsigned long); 267 | if (sizeof(long) > 4) 268 | div *= div * 10; 269 | } else { 270 | num = va_arg(va, unsigned int); 271 | } 272 | 273 | if (ch == 'd') { 274 | if (islong && (long)num < 0) { 275 | num = -(long)num; 276 | out(info, '-'); 277 | } else if (!islong && (int)num < 0) { 278 | num = -(int)num; 279 | out(info, '-'); 280 | } 281 | } 282 | if (!num) { 283 | out_dgt(info, 0); 284 | } else { 285 | for (; div; div /= 10) 286 | div_out(info, &num, div); 287 | } 288 | break; 289 | case 'X': 290 | case 'x': 291 | if (islong) { 292 | num = va_arg(va, unsigned long); 293 | div = 1UL << (sizeof(long) * 8 - 4); 294 | } else { 295 | num = va_arg(va, unsigned int); 296 | div = 0x10000000; 297 | } 298 | if (!num) { 299 | out_dgt(info, 0); 300 | } else { 301 | for (; div; div /= 0x10) 302 | div_out(info, &num, div); 303 | } 304 | break; 305 | case 'c': 306 | out(info, (char)(va_arg(va, int))); 307 | break; 308 | case 's': 309 | p = va_arg(va, char*); 310 | break; 311 | case 'p': 312 | pointer(info, fmt, va_arg(va, void *)); 313 | while (isalnum(fmt[0])) 314 | fmt++; 315 | break; 316 | case '%': 317 | out(info, '%'); 318 | default: 319 | break; 320 | } 321 | 322 | *info->bf = 0; 323 | info->bf = p; 324 | while (*info->bf++ && width > 0) 325 | width--; 326 | while (width-- > 0) 327 | info->putc(info, lz ? '0' : ' '); 328 | if (p) { 329 | while ((ch = *p++)) 330 | info->putc(info, ch); 331 | } 332 | } 333 | } 334 | 335 | abort: 336 | return 0; 337 | } 338 | 339 | int vprintf(const char *fmt, va_list va) 340 | { 341 | struct printf_info info; 342 | 343 | info.putc = putc_normal; 344 | return _vprintf(&info, fmt, va); 345 | } 346 | 347 | int printf(const char *fmt, ...) 348 | { 349 | struct printf_info info; 350 | 351 | va_list va; 352 | int ret; 353 | 354 | info.putc = putc_normal; 355 | va_start(va, fmt); 356 | ret = _vprintf(&info, fmt, va); 357 | va_end(va); 358 | 359 | return ret; 360 | } 361 | 362 | static void putc_outstr(struct printf_info *info, char ch) 363 | { 364 | *info->outstr++ = ch; 365 | } 366 | 367 | /* Note that size is ignored */ 368 | int vsnprintf(char *buf, size_t size, const char *fmt, va_list va) 369 | { 370 | struct printf_info info; 371 | int ret; 372 | 373 | info.outstr = buf; 374 | info.putc = putc_outstr; 375 | ret = _vprintf(&info, fmt, va); 376 | *info.outstr = '\0'; 377 | 378 | return ret; 379 | } 380 | 381 | int sprintf(char *buf, const char *fmt, ...) 382 | { 383 | struct printf_info info; 384 | va_list va; 385 | int ret; 386 | 387 | va_start(va, fmt); 388 | info.outstr = buf; 389 | info.putc = putc_outstr; 390 | ret = _vprintf(&info, fmt, va); 391 | va_end(va); 392 | *info.outstr = '\0'; 393 | 394 | return ret; 395 | } 396 | 397 | /* Note that size is ignored */ 398 | int snprintf(char *buf, size_t size, const char *fmt, ...) 399 | { 400 | va_list va; 401 | int ret; 402 | 403 | va_start(va, fmt); 404 | ret = vsnprintf(buf, size, fmt, va); 405 | va_end(va); 406 | 407 | return ret; 408 | } 409 | -------------------------------------------------------------------------------- /source/tmio.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, 4 | * You can obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * Copyright (c) 2014-2015, Normmatt, 173210 7 | * 8 | * Alternatively, the contents of this file may be used under the terms 9 | * of the GNU General Public License Version 2, as described below: 10 | * 11 | * This file is free software: you may copy, redistribute and/or modify 12 | * it under the terms of the GNU General Public License as published by the 13 | * Free Software Foundation, either version 2 of the License, or (at your 14 | * option) any later version. 15 | * 16 | * This file is distributed in the hope that it will be useful, but 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 19 | * Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see http://www.gnu.org/licenses/. 23 | */ 24 | 25 | #include "types.h" 26 | #include "utils.h" 27 | #include "tmio.h" 28 | #include "tmio_command.h" 29 | #include "tmio_hardware.h" 30 | 31 | int sdio_1_irq; 32 | 33 | #define DATA32_SUPPORT 34 | 35 | void waitcycles(uint32_t val); 36 | 37 | struct tmio_dev tmio_dev[TMIO_DEV_NUM] = { 38 | { .total_size = 0 }, 39 | { .total_size = 0 } 40 | }; 41 | 42 | _Static_assert(TMIO_DEV_NUM == 2, 43 | "TMIO device numer doesn't accord with the driver context."); 44 | 45 | static int waitDataend = 0; 46 | 47 | static uint16_t tmio_read16(enum tmio_regs reg) { 48 | return *(volatile uint16_t*)(TMIO_BASE + reg); 49 | } 50 | 51 | static void tmio_write16(enum tmio_regs reg, uint16_t val) { 52 | *(volatile uint16_t*)(TMIO_BASE + reg) = val; 53 | } 54 | 55 | static uint32_t tmio_read32(enum tmio_regs reg) { 56 | return *(volatile uint32_t*)(TMIO_BASE + reg); 57 | } 58 | 59 | static void tmio_write32(enum tmio_regs reg, uint32_t val) { 60 | *(volatile uint32_t*)(TMIO_BASE + reg) = val; 61 | } 62 | 63 | static void tmio_mask16(enum tmio_regs reg, const uint16_t clear, const uint16_t set) { 64 | uint16_t val = tmio_read16(reg); 65 | val &= ~clear; 66 | val |= set; 67 | tmio_write16(reg, val); 68 | } 69 | 70 | static void setckl(uint32_t data) 71 | { 72 | tmio_mask16(REG_SDCLKCTL,0x100,0); 73 | tmio_mask16(REG_SDCLKCTL,0x2FF,data&0x2FF); 74 | tmio_mask16(REG_SDCLKCTL,0x0,0x100); 75 | } 76 | 77 | static void tmio_wfi() 78 | { 79 | while (!sdio_1_irq) 80 | arm9_wfi(); 81 | 82 | sdio_1_irq = 0; 83 | } 84 | 85 | static void inittarget(enum tmio_dev_id target) 86 | { 87 | uint32_t status; 88 | 89 | if(waitDataend) 90 | { 91 | tmio_write32(REG_SDIRMASK, ~(TMIO_STAT_DATAEND | TMIO_MASK_GW)); 92 | do 93 | { 94 | tmio_wfi(); 95 | tmio_write32(REG_SDSTATUS, ~TMIO_STAT_DATAEND); 96 | 97 | status = tmio_read32(REG_SDSTATUS); 98 | if((status & TMIO_MASK_GW)) 99 | break; 100 | } 101 | while ((status & TMIO_STAT_CMD_BUSY)); 102 | 103 | waitDataend = 0; 104 | } 105 | 106 | tmio_mask16(REG_SDPORTSEL,0x3,target); 107 | setckl(tmio_dev[target].clk); 108 | if(tmio_dev[target].SDOPT == 0) 109 | { 110 | tmio_mask16(REG_SDOPT,0,0x8000); 111 | } 112 | else 113 | { 114 | tmio_mask16(REG_SDOPT,0x8000,0); 115 | } 116 | } 117 | 118 | static uint32_t tmio_wait_respend() 119 | { 120 | uint32_t status, error; 121 | 122 | tmio_write32(REG_SDIRMASK, ~(TMIO_STAT_CMDRESPEND | TMIO_MASK_GW)); 123 | do 124 | { 125 | tmio_wfi(); 126 | status = tmio_read32(REG_SDSTATUS); 127 | error = status & TMIO_MASK_GW; 128 | if(error) 129 | return error; 130 | } 131 | while(!(status & TMIO_STAT_CMDRESPEND)); 132 | 133 | return 0; 134 | } 135 | 136 | static uint32_t tmio_send_command(uint16_t cmd, uint32_t args, int cap_prev_error) 137 | { 138 | uint32_t r; 139 | 140 | if ((tmio_read32(REG_SDSTATUS) & TMIO_STAT_CMD_BUSY)) 141 | { 142 | r = tmio_wait_respend(); 143 | if(r && cap_prev_error) 144 | return r; 145 | } 146 | 147 | tmio_write32(REG_SDSTATUS,0); 148 | tmio_write32(REG_SDCMDARG,args); 149 | tmio_write16(REG_SDCMD,cmd); 150 | 151 | return 0; 152 | } 153 | 154 | uint32_t tmio_readsectors(enum tmio_dev_id target, 155 | uint32_t sector_no, uint32_t numsectors, uint8_t *out) 156 | { 157 | uint32_t error, mask; 158 | 159 | if(tmio_dev[target].isSDHC == 0) sector_no <<= 9; 160 | inittarget(target); 161 | tmio_write16(REG_SDSTOP,0x100); 162 | #ifdef DATA32_SUPPORT 163 | tmio_write16(REG_SDBLKCOUNT32,numsectors); 164 | tmio_write16(REG_SDBLKLEN32,TMIO_BBS); 165 | #endif 166 | tmio_write16(REG_SDBLKCOUNT,numsectors); 167 | 168 | mask = TMIO_MASK_GW; 169 | #ifdef DATA32_SUPPORT 170 | tmio_write16(REG_DATACTL32,TMIO32_ENABLE | TMIO32_IRQ_RXRDY); 171 | #else 172 | mask |= TMIO_STAT_RXRDY; 173 | #endif 174 | 175 | tmio_write32(REG_SDIRMASK,~mask); 176 | tmio_send_command(MMC_READ_BLOCK_MULTI 177 | | TMIO_CMD_RESP_R1 | TMIO_CMD_DATA_PRESENT 178 | | TMIO_CMD_TRANSFER_READ | TMIO_CMD_TRANSFER_MULTI, 179 | sector_no, 0); 180 | 181 | uint16_t *dataPtr = (uint16_t*)out; 182 | uint32_t *dataPtr32 = (uint32_t*)out; 183 | int useBuf32 = 0 == (3 & ((uint32_t)dataPtr)); 184 | 185 | while(numsectors > 0) 186 | { 187 | tmio_wfi(); 188 | 189 | error = tmio_read32(REG_SDSTATUS) & TMIO_MASK_GW; 190 | if(error) 191 | return error; 192 | 193 | #ifdef DATA32_SUPPORT 194 | if(!(tmio_read16(REG_DATACTL32) & TMIO32_STAT_RXRDY)) 195 | continue; 196 | #endif 197 | 198 | #ifdef DATA32_SUPPORT 199 | if(useBuf32) 200 | { 201 | for(int i = 0; i 0) 256 | { 257 | tmio_wfi(); 258 | 259 | error = tmio_read32(REG_SDSTATUS) & TMIO_MASK_GW; 260 | if(error) 261 | return error; 262 | 263 | #ifdef DATA32_SUPPORT 264 | if((tmio_read16(REG_DATACTL32) & TMIO32_STAT_BUSY)) 265 | continue; 266 | #endif 267 | 268 | #ifdef DATA32_SUPPORT 269 | for(int i = 0; i> 6; 290 | switch(type) 291 | { 292 | case 0: 293 | { 294 | uint32_t block_len=csd[9]&0xf; 295 | block_len=1<>7)|((csd[5]&3)<<1); 297 | mult=1<<(mult+2); 298 | result=csd[8]&3; 299 | result=(result<<8)|csd[7]; 300 | result=(result<<2)|(csd[6]>>6); 301 | result=(result+1)*mult*block_len/512; 302 | } 303 | break; 304 | case 1: 305 | result=csd[7]&0x3f; 306 | result=(result<<8)|csd[6]; 307 | result=(result<<8)|csd[5]; 308 | result=(result+1)*1024; 309 | break; 310 | } 311 | return result; 312 | } 313 | 314 | void tmio_init() 315 | { 316 | sdio_1_irq = 0; 317 | 318 | tmio_mask16(REG_DATACTL32, 0x0800, 0x0000); 319 | tmio_mask16(REG_DATACTL32, 0x1000, 0x0000); 320 | tmio_mask16(REG_DATACTL32, 0x0000, 0x0402); 321 | tmio_mask16(REG_DATACTL, 0x2200, 0x0002); 322 | #ifdef DATA32_SUPPORT 323 | tmio_mask16(REG_DATACTL, 0x0020, 0x0000); 324 | tmio_write16(REG_SDBLKLEN32, TMIO_BBS); 325 | #else 326 | tmio_mask16(REG_DATACTL32, 0x0020, 0x0000); 327 | tmio_mask16(REG_DATACTL, 0x0020, 0x0000); 328 | tmio_write16(REG_SDBLKLEN32, 0); 329 | #endif 330 | tmio_write16(REG_SDBLKCOUNT32, 1); 331 | tmio_mask16(REG_SDRESET, 0x0001, 0x0000); 332 | tmio_mask16(REG_SDRESET, 0x0000, 0x0001); 333 | tmio_write32(REG_SDIRMASK, ~TMIO_MASK_ALL); 334 | tmio_mask16(0xFC, 0x0000, 0x00DB); 335 | tmio_mask16(0xFE, 0x0000, 0x00DB); 336 | tmio_mask16(REG_SDPORTSEL, 0x0002, 0x0000); 337 | #ifdef DATA32_SUPPORT 338 | tmio_write16(REG_SDCLKCTL, 0x0020); 339 | tmio_write16(REG_SDOPT, 0x40EE); 340 | #else 341 | tmio_write16(REG_SDCLKCTL, 0x0040); 342 | tmio_write16(REG_SDOPT, 0x40EB); 343 | #endif 344 | tmio_mask16(REG_SDPORTSEL, 0x0002, 0x0000); 345 | tmio_write16(REG_SDBLKLEN, TMIO_BBS); 346 | tmio_write16(REG_SDSTOP, 0); 347 | 348 | inittarget(TMIO_DEV_SDMC); 349 | } 350 | 351 | uint32_t tmio_init_nand() 352 | { 353 | uint32_t r; 354 | 355 | if (tmio_dev[TMIO_DEV_NAND].total_size > 0) 356 | return 0; 357 | 358 | //NAND 359 | tmio_dev[TMIO_DEV_NAND].isSDHC = 0; 360 | tmio_dev[TMIO_DEV_NAND].SDOPT = 0; 361 | tmio_dev[TMIO_DEV_NAND].res = 0; 362 | tmio_dev[TMIO_DEV_NAND].initarg = 1; 363 | tmio_dev[TMIO_DEV_NAND].clk = 0x80; 364 | 365 | inittarget(TMIO_DEV_NAND); 366 | waitcycles(0xF000); 367 | 368 | tmio_send_command(MMC_IDLE,0,0); 369 | 370 | do 371 | { 372 | do 373 | tmio_send_command(MMC_SEND_OP_COND | TMIO_CMD_RESP_R3, 374 | 0x100000,0); 375 | while (tmio_wait_respend()); 376 | } 377 | while((tmio_read32(REG_SDRESP0) & 0x80000000) == 0); 378 | 379 | tmio_send_command(MMC_ALL_SEND_CID | TMIO_CMD_RESP_R2,0x0,0); 380 | r = tmio_send_command(MMC_SET_RELATIVE_ADDR | TMIO_CMD_RESP_R1, 381 | tmio_dev[TMIO_DEV_NAND].initarg << 0x10,1); 382 | if(r) 383 | return r; 384 | 385 | r = tmio_send_command(MMC_SEND_CSD | TMIO_CMD_RESP_R2, 386 | tmio_dev[TMIO_DEV_NAND].initarg << 0x10,1); 387 | if(r) 388 | return r; 389 | 390 | r = tmio_wait_respend(); 391 | if(r) 392 | return r; 393 | 394 | tmio_dev[TMIO_DEV_NAND].total_size = calcSDSize((uint8_t*)TMIO_BASE + REG_SDRESP0,0); 395 | tmio_dev[TMIO_DEV_NAND].clk = 1; 396 | setckl(1); 397 | 398 | tmio_send_command(MMC_SELECT_CARD | TMIO_CMD_RESP_R1, 399 | tmio_dev[TMIO_DEV_NAND].initarg << 0x10,0); 400 | 401 | tmio_dev[TMIO_DEV_NAND].SDOPT = 1; 402 | 403 | r = tmio_send_command(MMC_SWITCH | TMIO_CMD_RESP_R1B,0x3B70100,1); 404 | if(r) 405 | return r; 406 | 407 | r = tmio_send_command(MMC_SWITCH | TMIO_CMD_RESP_R1B,0x3B90100,1); 408 | if(r) 409 | return r; 410 | 411 | r = tmio_send_command(MMC_SEND_STATUS | TMIO_CMD_RESP_R1, 412 | tmio_dev[TMIO_DEV_NAND].initarg << 0x10,1); 413 | if(r) 414 | return r; 415 | 416 | r = tmio_send_command(MMC_SET_BLOCKLEN | TMIO_CMD_RESP_R1,TMIO_BBS,1); 417 | if(r) 418 | return r; 419 | 420 | tmio_dev[TMIO_DEV_NAND].clk |= 0x200; 421 | 422 | inittarget(TMIO_DEV_SDMC); 423 | 424 | return 0; 425 | } 426 | 427 | uint32_t tmio_init_sdmc() 428 | { 429 | uint32_t resp; 430 | uint32_t r; 431 | 432 | if (tmio_dev[TMIO_DEV_SDMC].total_size > 0) 433 | return 0; 434 | 435 | //SD 436 | tmio_dev[TMIO_DEV_SDMC].isSDHC = 0; 437 | tmio_dev[TMIO_DEV_SDMC].SDOPT = 0; 438 | tmio_dev[TMIO_DEV_SDMC].res = 0; 439 | tmio_dev[TMIO_DEV_SDMC].initarg = 0; 440 | tmio_dev[TMIO_DEV_SDMC].clk = 0x80; 441 | 442 | inittarget(TMIO_DEV_SDMC); 443 | waitcycles(0xF000); 444 | tmio_send_command(MMC_IDLE,0,0); 445 | 446 | r = tmio_send_command(SD_SEND_IF_COND | TMIO_CMD_RESP_R1,0x1AA,1); 447 | if(r) 448 | return r; 449 | 450 | uint32_t temp = tmio_wait_respend() ? 0 : 0x1 << 0x1E; 451 | 452 | uint32_t temp2 = 0; 453 | do 454 | { 455 | while(1) 456 | { 457 | tmio_send_command(MMC_APP_CMD | TMIO_CMD_RESP_R1, 458 | tmio_dev[TMIO_DEV_SDMC].initarg << 0x10,0); 459 | temp2 = 1; 460 | if(tmio_send_command(SD_APP_OP_COND 461 | | TMIO_CMD_APP | TMIO_CMD_RESP_R3, 462 | 0x00FF8000 | temp,1)) 463 | continue; 464 | if(!tmio_wait_respend()) 465 | break; 466 | } 467 | 468 | resp = tmio_read32(REG_SDRESP0); 469 | } 470 | while((resp & 0x80000000) == 0); 471 | 472 | if(!((resp >> 30) & 1) || !temp) 473 | temp2 = 0; 474 | 475 | tmio_dev[TMIO_DEV_SDMC].isSDHC = temp2; 476 | 477 | tmio_send_command(MMC_ALL_SEND_CID | TMIO_CMD_RESP_R2,0,0); 478 | 479 | r = tmio_send_command(MMC_SET_RELATIVE_ADDR | TMIO_CMD_RESP_R1,0,1); 480 | if(r) 481 | return r; 482 | 483 | r = tmio_wait_respend(); 484 | if(r) 485 | return r; 486 | 487 | tmio_dev[TMIO_DEV_SDMC].initarg = tmio_read32(REG_SDRESP0) >> 0x10; 488 | tmio_send_command(MMC_SEND_CSD | TMIO_CMD_RESP_R2, 489 | tmio_dev[TMIO_DEV_SDMC].initarg << 0x10,0); 490 | r = tmio_wait_respend(); 491 | if(r) 492 | return r; 493 | 494 | tmio_dev[TMIO_DEV_SDMC].total_size = calcSDSize((uint8_t*)TMIO_BASE + REG_SDRESP0,-1); 495 | tmio_dev[TMIO_DEV_SDMC].clk = 1; 496 | setckl(1); 497 | 498 | tmio_send_command(MMC_SELECT_CARD | TMIO_CMD_RESP_R1B, 499 | tmio_dev[TMIO_DEV_SDMC].initarg << 0x10,0); 500 | r = tmio_send_command(MMC_APP_CMD | TMIO_CMD_RESP_R1, 501 | tmio_dev[TMIO_DEV_SDMC].initarg << 0x10,1); 502 | if(r) 503 | return r; 504 | 505 | tmio_dev[TMIO_DEV_SDMC].SDOPT = 1; 506 | r = tmio_send_command(MMC_SWITCH | TMIO_CMD_APP | TMIO_CMD_RESP_R1, 507 | 0x2,1); 508 | if(r) 509 | return r; 510 | 511 | r = tmio_send_command(MMC_SEND_STATUS | TMIO_CMD_RESP_R1, 512 | tmio_dev[TMIO_DEV_SDMC].initarg << 0x10,1); 513 | if(r) 514 | return r; 515 | 516 | r = tmio_send_command(MMC_SET_BLOCKLEN | TMIO_CMD_RESP_R1,TMIO_BBS,1); 517 | if(r) 518 | return r; 519 | 520 | tmio_dev[TMIO_DEV_SDMC].clk |= 0x200; 521 | 522 | return 0; 523 | } 524 | 525 | uint32_t tmio_wrprotected(enum tmio_dev_id target) 526 | { 527 | inittarget(target); 528 | return tmio_read32(REG_SDSTATUS) & TMIO_STAT_WRPROTECT; 529 | } 530 | -------------------------------------------------------------------------------- /source/utils.c: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | void arm9_enable_irq(void) 4 | { 5 | __asm__ volatile( 6 | "mrs r0, cpsr\n\t" 7 | "bic r0, r0, #0x80\n\t" 8 | "msr cpsr_c, r0\n\t" 9 | : : : "r0"); 10 | } 11 | 12 | void arm9_disable_irq(void) 13 | { 14 | __asm__ volatile( 15 | "mrs r0, cpsr\n\t" 16 | "orr r0, r0, #0x80\n\t" 17 | "msr cpsr_c, r0\n\t" 18 | : : : "r0"); 19 | } 20 | 21 | void arm9_set_regular_exception_vectors(void) 22 | { 23 | __asm__ volatile( 24 | "mrc p15, 0, r0, c1, c0, 0\n\t" 25 | "bic r0, r0, #(1 << 13)\n\t" 26 | "mcr p15, 0, r0, c1, c0, 0\n\t" 27 | : : : "r0"); 28 | } 29 | 30 | void arm9_wfi(void) 31 | { 32 | __asm__ volatile( 33 | "mcr p15, 0, %0, c7, c0, 4\n\t" 34 | : : "r"(0) 35 | ); 36 | } 37 | 38 | void arm9_disable_timers(void) 39 | { 40 | REG_TIMER_CNT(0) = 0; 41 | REG_TIMER_CNT(1) = 0; 42 | REG_TIMER_CNT(2) = 0; 43 | REG_TIMER_CNT(3) = 0; 44 | } 45 | --------------------------------------------------------------------------------