├── .gitignore ├── LICENCE ├── Makefile ├── README ├── boot.s ├── ccu.h ├── demo.c ├── demo_data.h ├── display.c ├── display.h ├── interrupts.c ├── interrupts.h ├── linker.ld ├── mmu.c ├── mmu.h ├── ports.c ├── ports.h ├── spritelayers.c ├── spritelayers.h ├── startup.c ├── system.c ├── system.h ├── uart.c ├── uart.h ├── usb.c └── usb.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | os.* 3 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | Copyright 2018 Charlie Smurthwaite 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | 9 | 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC=arm-none-eabi-gcc 2 | OBJCOPY=arm-none-eabi-objcopy 3 | CFLAGS=-T linker.ld -mfpu=neon -mfloat-abi=hard -mcpu=cortex-a7 -fpic -ffreestanding -O3 -nostdlib -Wextra 4 | 5 | os.bin: os.elf 6 | $(OBJCOPY) -O binary --remove-section .uncached os.elf os.bin 7 | os.elf: boot.o startup.o uart.o ports.o mmu.o system.o display.o interrupts.o spritelayers.o usb.o demo.o 8 | $(CC) $(CFLAGS) -o os.elf boot.o startup.o uart.o ports.o mmu.o system.o display.o interrupts.o spritelayers.o usb.o demo.o 9 | 10 | boot.o: boot.s 11 | $(CC) $(CFLAGS) -c boot.s 12 | startup.o: startup.c 13 | $(CC) $(CFLAGS) -c startup.c 14 | uart.o: uart.c 15 | $(CC) $(CFLAGS) -c uart.c 16 | ports.o: ports.c 17 | $(CC) $(CFLAGS) -c ports.c 18 | mmu.o: mmu.c 19 | $(CC) $(CFLAGS) -c mmu.c 20 | system.o: system.c 21 | $(CC) $(CFLAGS) -c system.c 22 | display.o: display.c 23 | $(CC) $(CFLAGS) -c display.c 24 | interrupts.o: interrupts.c 25 | $(CC) $(CFLAGS) -c interrupts.c 26 | spritelayers.o: spritelayers.c 27 | $(CC) $(CFLAGS) -c spritelayers.c 28 | usb.o: usb.c 29 | $(CC) $(CFLAGS) -c usb.c 30 | demo.o: demo.c 31 | $(CC) $(CFLAGS) -c demo.c 32 | 33 | clean: 34 | rm -f *.o os.* 35 | 36 | install: os.bin 37 | sunxi-fel spl ../u-boot/spl/sunxi-spl.bin write 0x4e000000 os.bin exe 0x4e000000 38 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This repository represents an attempt to run bare metal code on an Allwinner SoC. 2 | 3 | Current target is the H3. This code will implement drivers for all hardware used 4 | with the exception of DRAM which is initialized by u-boot SPL. 5 | -------------------------------------------------------------------------------- /boot.s: -------------------------------------------------------------------------------- 1 | _reset: 2 | cpsid if 3 | 4 | MRC p15,0,r0,c1,c0,2 // Read CP Access register 5 | ORR r0,r0,#0x00f00000 // Enable full access to NEON/VFP (Coprocessors 10 and 11) 6 | MCR p15,0,r0,c1,c0,2 // Write CP Access register 7 | ISB 8 | MOV r0,#0x40000000 // Switch on the VFP and NEON hardware 9 | VMSR FPEXC,r0 // Set EN bit in FPEXC 10 | 11 | mov sp, #0x4000 12 | b startup 13 | 14 | .globl _ivt 15 | _ivt: 16 | ldr pc, _reset_h 17 | ldr pc, _undefined_instruction_vector_h 18 | ldr pc, _software_interrupt_vector_h 19 | ldr pc, _prefetch_abort_vector_h 20 | ldr pc, _data_abort_vector_h 21 | ldr pc, _unused_handler_h 22 | ldr pc, _interrupt_vector_h 23 | ldr pc, _fast_interrupt_vector_h 24 | _reset_h: .word _reset 25 | _undefined_instruction_vector_h: .word _reset 26 | _software_interrupt_vector_h: .word _reset 27 | _prefetch_abort_vector_h: .word _reset 28 | _data_abort_vector_h: .word _reset 29 | _unused_handler_h: .word _reset 30 | _interrupt_vector_h: .word interrupt 31 | _fast_interrupt_vector_h: .word _reset 32 | -------------------------------------------------------------------------------- /ccu.h: -------------------------------------------------------------------------------- 1 | // The CCU registers base address. 2 | #define CCU_BASE 0x01C20000 3 | 4 | // Structure of CCU registers. 5 | #define PLL_CPUX_CTRL *(volatile uint32_t *)(CCU_BASE + 0X000) 6 | #define PLL_AUDIO_CTRL *(volatile uint32_t *)(CCU_BASE + 0X008) 7 | #define PLL_VIDEO_CTRL *(volatile uint32_t *)(CCU_BASE + 0X010) 8 | #define PLL_VE_CTRL *(volatile uint32_t *)(CCU_BASE + 0X018) 9 | #define PLL_DDR_CTRL *(volatile uint32_t *)(CCU_BASE + 0X020) 10 | #define PLL_PERIPH0_CTRL *(volatile uint32_t *)(CCU_BASE + 0X028) 11 | #define PLL_GPU_CTRL *(volatile uint32_t *)(CCU_BASE + 0X038) 12 | #define PLL_PERIPH1_CTRL *(volatile uint32_t *)(CCU_BASE + 0X044) 13 | #define PLL_DE_CTRL *(volatile uint32_t *)(CCU_BASE + 0X048) 14 | #define CPUX_AXI_CFG *(volatile uint32_t *)(CCU_BASE + 0X050) 15 | #define AHB1_APB1_CFG *(volatile uint32_t *)(CCU_BASE + 0X054) 16 | #define APB2_CFG *(volatile uint32_t *)(CCU_BASE + 0X058) 17 | #define AHB2_CFG *(volatile uint32_t *)(CCU_BASE + 0X05C) 18 | #define BUS_CLK_GATING0 *(volatile uint32_t *)(CCU_BASE + 0X060) 19 | #define BUS_CLK_GATING1 *(volatile uint32_t *)(CCU_BASE + 0X064) 20 | #define BUS_CLK_GATING2 *(volatile uint32_t *)(CCU_BASE + 0X068) 21 | #define BUS_CLK_GATING3 *(volatile uint32_t *)(CCU_BASE + 0X06C) 22 | #define BUS_CLK_GATING4 *(volatile uint32_t *)(CCU_BASE + 0X070) 23 | #define THS_CLK *(volatile uint32_t *)(CCU_BASE + 0X074) 24 | #define NAND_CLK *(volatile uint32_t *)(CCU_BASE + 0X080) 25 | #define SDMMC0_CLK *(volatile uint32_t *)(CCU_BASE + 0X088) 26 | #define SDMMC1_CLK *(volatile uint32_t *)(CCU_BASE + 0X08C) 27 | #define SDMMC2_CLK *(volatile uint32_t *)(CCU_BASE + 0X090) 28 | #define CE_CLK *(volatile uint32_t *)(CCU_BASE + 0X09C) 29 | #define SPI0_CLK *(volatile uint32_t *)(CCU_BASE + 0X0A0) 30 | #define SPI1_CLK *(volatile uint32_t *)(CCU_BASE + 0X0A4) 31 | #define I2S_PCM0_CLK *(volatile uint32_t *)(CCU_BASE + 0X0B0) 32 | #define I2S_PCM1_CLK *(volatile uint32_t *)(CCU_BASE + 0X0B4) 33 | #define I2S_PCM2_CLK *(volatile uint32_t *)(CCU_BASE + 0X0B8) 34 | #define OWA_CLK *(volatile uint32_t *)(CCU_BASE + 0X0C0) 35 | #define USBPHY_CFG *(volatile uint32_t *)(CCU_BASE + 0X0CC) 36 | #define DRAM_CFG *(volatile uint32_t *)(CCU_BASE + 0X0F4) 37 | #define MBUS_RST *(volatile uint32_t *)(CCU_BASE + 0X0FC) 38 | #define DRAM_CLK_GATING *(volatile uint32_t *)(CCU_BASE + 0X100) 39 | #define DE_CLK *(volatile uint32_t *)(CCU_BASE + 0X104) 40 | #define TCON0_CLK *(volatile uint32_t *)(CCU_BASE + 0X118) 41 | #define TVE_CLK *(volatile uint32_t *)(CCU_BASE + 0X120) 42 | #define DEINTERLACE_CLK *(volatile uint32_t *)(CCU_BASE + 0X124) 43 | #define CSI_MISC_CLK *(volatile uint32_t *)(CCU_BASE + 0X130) 44 | #define CSI_CLK *(volatile uint32_t *)(CCU_BASE + 0X134) 45 | #define VE_CLK *(volatile uint32_t *)(CCU_BASE + 0X13C) 46 | #define AC_DIG_CLK *(volatile uint32_t *)(CCU_BASE + 0X140) 47 | #define AVS_CLK *(volatile uint32_t *)(CCU_BASE + 0X144) 48 | #define HDMI_CLK *(volatile uint32_t *)(CCU_BASE + 0X150) 49 | #define HDMI_SLOW_CLK *(volatile uint32_t *)(CCU_BASE + 0X154) 50 | #define MBUS_CLK *(volatile uint32_t *)(CCU_BASE + 0X15C) 51 | #define GPU_CLK *(volatile uint32_t *)(CCU_BASE + 0X1A0) 52 | #define PLL_STABLE_TIME0 *(volatile uint32_t *)(CCU_BASE + 0X200) 53 | #define PLL_STABLE_TIME1 *(volatile uint32_t *)(CCU_BASE + 0X204) 54 | #define PLL_CPUX_BIAS *(volatile uint32_t *)(CCU_BASE + 0X220) 55 | #define PLL_AUDIO_BIAS *(volatile uint32_t *)(CCU_BASE + 0X224) 56 | #define PLL_VIDEO_BIAS *(volatile uint32_t *)(CCU_BASE + 0X228) 57 | #define PLL_VE_BIAS *(volatile uint32_t *)(CCU_BASE + 0X22C) 58 | #define PLL_DDR_BIAS *(volatile uint32_t *)(CCU_BASE + 0X230) 59 | #define PLL_PERIPH0_BIAS *(volatile uint32_t *)(CCU_BASE + 0X234) 60 | #define PLL_GPU_BIAS *(volatile uint32_t *)(CCU_BASE + 0X23C) 61 | #define PLL_PERIPH1_BIAS *(volatile uint32_t *)(CCU_BASE + 0X244) 62 | #define PLL_DE_BIAS *(volatile uint32_t *)(CCU_BASE + 0X248) 63 | #define PLL_CPUX_TUN *(volatile uint32_t *)(CCU_BASE + 0X250) 64 | #define PLL_DDR_TUN *(volatile uint32_t *)(CCU_BASE + 0X260) 65 | #define PLL_CPUX_PAT_CTRL *(volatile uint32_t *)(CCU_BASE + 0X280) 66 | #define PLL_AUDIO_PAT_CTRL0 *(volatile uint32_t *)(CCU_BASE + 0X284) 67 | #define PLL_VIDEO_PAT_CTRL0 *(volatile uint32_t *)(CCU_BASE + 0X288) 68 | #define PLL_VE_PAT_CTRL *(volatile uint32_t *)(CCU_BASE + 0X28C) 69 | #define PLL_DDR_PAT_CTRL0 *(volatile uint32_t *)(CCU_BASE + 0X290) 70 | #define PLL_GPU_PAT_CTRL *(volatile uint32_t *)(CCU_BASE + 0X29C) 71 | #define PLL_PERIPH1_PAT_CTRL1 *(volatile uint32_t *)(CCU_BASE + 0X2A4) 72 | #define PLL_DE_PAT_CTRL *(volatile uint32_t *)(CCU_BASE + 0X2A8) 73 | #define BUS_SOFT_RST0 *(volatile uint32_t *)(CCU_BASE + 0X2C0) 74 | #define BUS_SOFT_RST1 *(volatile uint32_t *)(CCU_BASE + 0X2C4) 75 | #define BUS_SOFT_RST2 *(volatile uint32_t *)(CCU_BASE + 0X2C8) 76 | #define BUS_SOFT_RST3 *(volatile uint32_t *)(CCU_BASE + 0X2D0) 77 | #define BUS_SOFT_RST4 *(volatile uint32_t *)(CCU_BASE + 0X2D8) 78 | #define CCU_SEC_SWITCH *(volatile uint32_t *)(CCU_BASE + 0X2F0) 79 | #define PS_CTRL *(volatile uint32_t *)(CCU_BASE + 0X300) 80 | #define PS_CNT *(volatile uint32_t *)(CCU_BASE + 0X304) 81 | 82 | #define R_PRCM_BASE 0x01F01400 83 | #define APB0_CLK_GATING *(volatile uint32_t *)(R_PRCM_BASE + 0x28) -------------------------------------------------------------------------------- /demo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "spritelayers.h" 3 | #include "display.h" 4 | #include "demo_data.h" 5 | #include "uart.h" 6 | 7 | // Define the scrolling background pattern 8 | uint32_t* pattern[100*100]; 9 | struct sprite_layer background; 10 | 11 | void game_start() { 12 | // Populate the pattern 13 | for(int n=0;n<100*100;n++) 14 | pattern[n] = demo_sprite; 15 | 16 | // Configure the background to use the pattern 17 | background.pattern = pattern; 18 | background.x_size = 100; 19 | background.y_size = 100; 20 | background.x_offset = 0; 21 | background.y_offset = 0; 22 | } 23 | 24 | void game_tick(uint32_t tick_counter) { 25 | // Scroll the background 26 | background.x_offset = -(tick_counter%16); 27 | // ...and render it 20 times for fun 28 | // This approximately represents the performance limit, 10,000 sprites 29 | for(int n=0;n<20;n++) 30 | render_layer(&background); 31 | } 32 | -------------------------------------------------------------------------------- /demo_data.h: -------------------------------------------------------------------------------- 1 | // Sprite 2 | uint8_t demo_sprite_data[] = "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 3 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 4 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 5 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 6 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 7 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 8 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 9 | "\000\000\000\000\000\000\000\000\252\000\000\002\375\000\000p\376\000\000\322\376\000\000\370\376\000\000\362\376" 10 | "\000\000\320\373\000\000>\000\000\000\000\000\000\374@\000\000\376\311\000\000\376\365\000\000\376\367\000" 11 | "\000\376\342\000\000\375u\000\000\000\000\000\000\000\000\376\000\000\241\377\000\000\377\376\000\000\252\367" 12 | "\000\000\035\365\000\000\030\375\000\000h\374\000\000R\000\000\346\011\000\000\376\360\000\000\376\331\000" 13 | "\000\366\032\000\000\364\025\000\000\375b\000\000\375~\000\000\000\000\372\000\000\060\377\000\000\377\376" 14 | "\000\000\356\352\000\000\013\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\371)\000\000\377\377" 15 | "\000\000\376\327\000\000\355\015\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\375\000\000i\377\000\000" 16 | "\377\376\000\000\277\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\343\010\000\000\376" 17 | "\346\000\000\377\377\000\000\376\367\000\000\376\303\000\000\375}\000\000\361\021\000\000\000\000\375" 18 | "\000\000i\377\000\000\377\376\000\000\277\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 19 | "\000\000\000\000\370\"\000\000\376\233\000\000\376\343\000\000\377\377\000\000\377\377\000\000\376\322" 20 | "\000\000\000\000\372\000\000\060\377\000\000\377\376\000\000\356\352\000\000\013\000\000\000\000\000\000\000\000\000" 21 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\373\067\000\000\376\374\000\000" 22 | "\377\377\000\000\360\020\000\000\000\000\376\000\000\241\377\000\000\377\376\000\000\251\367\000\000\035" 23 | "\364\000\000\026\375\000\000e\374\000\000Q\000\000\370\"\000\000\376\254\000\000\373=\000\000\355\015\000" 24 | "\000\372,\000\000\376\366\000\000\376\342\000\000\000\000\000\000\000\000\300\000\000\003\375\000\000q\376\000" 25 | "\000\323\376\000\000\371\376\000\000\365\376\000\000\323\374\000\000?\000\000\364\026\000\000\376\274" 26 | "\000\000\376\347\000\000\376\371\000\000\376\360\000\000\376\277\000\000\373\063\000\000\000\000\000\000\000" 27 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 28 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000\377\000\377\000\377" 29 | "\000\377\000\377\000\377\000\377\000\377\000\377\000\377\000\377\000\377\000\377\000\377\000\377" 30 | "\000\377\000\377\000\377\000\377\000\377\000\377\000\377\000\377\000\377\000\377\000\377\000\377" 31 | "\000\377\000\377\000\377\000\377\000\377\000\377\000\377\000\377\000\377\000\377\000\377\000\377" 32 | "\000\377\000\377\000\377\000\377\000\377\000\377\000\377\000\377\000\377\000\377\000\377\000\377" 33 | "\000\377\000\377\000\377\000\377\000\377\000\377\000\377\000\377\000\377\000\377\000\377\000\377" 34 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" 35 | "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"; 36 | uint32_t* demo_sprite = (uint32_t*) demo_sprite_data; 37 | -------------------------------------------------------------------------------- /display.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "ccu.h" 3 | #include "system.h" 4 | #include "display.h" 5 | #include "uart.h" 6 | 7 | volatile uint32_t framebuffer1[512*512] __attribute__ ((section ("UNCACHED"))); 8 | volatile uint32_t framebuffer2[512*512] __attribute__ ((section ("UNCACHED"))); 9 | volatile uint32_t framebuffer3[512*512] __attribute__ ((section ("UNCACHED"))); 10 | 11 | void display_clocks_init() { 12 | // Set up shared and dedicated clocks for HDMI, LCD/TCON and DE2 13 | PLL_DE_CTRL = (1<<31) | (1<<24) | (17<<8) | (0<<0); // 432MHz 14 | PLL_VIDEO_CTRL = (1<<31) | (1<<25) | (1<<24) | (98<<8) | (7<<0); // 297MHz 15 | BUS_CLK_GATING1 |= (1<<12) | (1<<11) | (1<<3); // Enable DE, HDMI, TCON0 16 | BUS_SOFT_RST1 |= (1<<12) | (3<<10) | (1<<3); // De-assert reset of DE, HDMI0/1, TCON0 17 | DE_CLK = (1<<31) | (1<<24); // Enable DE clock, set source to PLL_DE 18 | HDMI_CLK = (1<<31); // Enable HDMI clk (use PLL3) 19 | HDMI_SLOW_CLK = (1<<31); // Enable HDMI slow clk 20 | TCON0_CLK = (1<<31) | 3; // Enable TCON0 clk, divide by 4 21 | } 22 | 23 | void hdmi_init() { 24 | // HDMI PHY init, the following black magic is based on the procedure documented at: 25 | // http://linux-sunxi.org/images/3/38/AW_HDMI_TX_PHY_S40_Spec_V0.1.pdf 26 | HDMI_PHY_CFG1 = 0; 27 | HDMI_PHY_CFG1 = 1; 28 | udelay(5); 29 | HDMI_PHY_CFG1 |= (1<<16); 30 | HDMI_PHY_CFG1 |= (1<<1); 31 | udelay(10); 32 | HDMI_PHY_CFG1 |= (1<<2); 33 | udelay(5); 34 | HDMI_PHY_CFG1 |= (1<<3); 35 | udelay(40); 36 | HDMI_PHY_CFG1 |= (1<<19); 37 | udelay(100); 38 | HDMI_PHY_CFG1 |= (1<<18); 39 | HDMI_PHY_CFG1 |= (7<<4); 40 | while((HDMI_PHY_STS & 0x80) == 0); 41 | HDMI_PHY_CFG1 |= (0xf<<4); 42 | HDMI_PHY_CFG1 |= (0xf<<8); 43 | HDMI_PHY_CFG3 |= (1<<0) | (1<<2); 44 | 45 | HDMI_PHY_PLL1 &= ~(1<<26); 46 | HDMI_PHY_CEC = 0; 47 | 48 | HDMI_PHY_PLL1 = 0x39dc5040; 49 | HDMI_PHY_PLL2 = 0x80084381; 50 | udelay(10000); 51 | HDMI_PHY_PLL3 = 1; 52 | HDMI_PHY_PLL1 |= (1<<25); 53 | udelay(10000); 54 | uint32_t tmp = (HDMI_PHY_STS & 0x1f800) >> 11; 55 | HDMI_PHY_PLL1 |= (1<<31) | (1<<30) | tmp; 56 | 57 | HDMI_PHY_CFG1 = 0x01FFFF7F; 58 | HDMI_PHY_CFG2 = 0x8063A800; 59 | HDMI_PHY_CFG3 = 0x0F81C485; 60 | 61 | /* enable read access to HDMI controller */ 62 | HDMI_PHY_READ_EN = 0x54524545; 63 | /* descramble register offsets */ 64 | HDMI_PHY_UNSCRAMBLE = 0x42494E47; 65 | 66 | // HDMI Config, based on the documentation at: 67 | // https://people.freebsd.org/~gonzo/arm/iMX6-HDMI.pdf 68 | HDMI_FC_INVIDCONF = (1<<6) | (1<<5) | (1<<4) | (1<<3); // Polarity etc 69 | HDMI_FC_INHACTIV0 = (1920 & 0xff); // Horizontal pixels 70 | HDMI_FC_INHACTIV1 = (1920 >> 8); // Horizontal pixels 71 | HDMI_FC_INHBLANK0 = (280 & 0xff); // Horizontal blanking 72 | HDMI_FC_INHBLANK1 = (280 >> 8); // Horizontal blanking 73 | 74 | HDMI_FC_INVACTIV0 = (1080 & 0xff); // Vertical pixels 75 | HDMI_FC_INVACTIV1 = (1080 >> 8); // Vertical pixels 76 | HDMI_FC_INVBLANK = 45; // Vertical blanking 77 | 78 | HDMI_FC_HSYNCINDELAY0 = (88 & 0xff); // Horizontal Front porch 79 | HDMI_FC_HSYNCINDELAY1 = (88 >> 8); // Horizontal Front porch 80 | HDMI_FC_VSYNCINDELAY = 4; // Vertical front porch 81 | HDMI_FC_HSYNCINWIDTH0 = (44 & 0xff); // Horizontal sync pulse 82 | HDMI_FC_HSYNCINWIDTH1 = (44 >> 8); // Horizontal sync pulse 83 | HDMI_FC_VSYNCINWIDTH = 5; // Vertical sync pulse 84 | 85 | HDMI_FC_CTRLDUR = 12; // Frame Composer Control Period Duration 86 | HDMI_FC_EXCTRLDUR = 32; // Frame Composer Extended Control Period Duration 87 | HDMI_FC_EXCTRLSPAC = 1; // Frame Composer Extended Control Period Maximum Spacing 88 | HDMI_FC_CH0PREAM = 0x0b; // Frame Composer Channel 0 Non-Preamble Data 89 | HDMI_FC_CH1PREAM = 0x16; // Frame Composer Channel 1 Non-Preamble Data 90 | HDMI_FC_CH2PREAM = 0x21; // Frame Composer Channel 2 Non-Preamble Data 91 | HDMI_MC_FLOWCTRL = 0; // Main Controller Feed Through Control 92 | HDMI_MC_CLKDIS = 0x74; // Main Controller Synchronous Clock Domain Disable 93 | } 94 | 95 | void lcd_init() { 96 | // LCD0 feeds mixer0 to HDMI 97 | LCD0_GCTL = (1<<31); 98 | LCD0_GINT0 = 0; 99 | LCD0_TCON1_CTL = (1<<31) | (30<<4); 100 | LCD0_TCON1_BASIC0 = (1919<<16) | 1079; 101 | LCD0_TCON1_BASIC1 = (1919<<16) | 1079; 102 | LCD0_TCON1_BASIC2 = (1919<<16) | 1079; 103 | LCD0_TCON1_BASIC3 = (2199<<16) | 191; 104 | LCD0_TCON1_BASIC4 = (2250<<16) | 40; 105 | LCD0_TCON1_BASIC5 = (43<<16) | 4; 106 | 107 | LCD0_GINT1 = 1; 108 | LCD0_GINT0 = (1<<28); 109 | } 110 | 111 | // This function configured DE2 as follows: 112 | // MIXER0 -> WB -> MIXER1 -> HDMI 113 | void de2_init() { 114 | DE_AHB_RESET |= (1<<0); 115 | DE_SCLK_GATE |= (1<<0); 116 | DE_HCLK_GATE |= (1<<0); 117 | DE_DE2TCON_MUX &= ~(1<<0); 118 | 119 | // Erase the whole of MIXER0. This contains uninitialized data. 120 | for(uint32_t addr = DE_MIXER0 + 0x0000; addr < DE_MIXER0 + 0xC000; addr += 4) 121 | *(volatile uint32_t*)(addr) = 0; 122 | 123 | DE_MIXER0_GLB_CTL = 1; 124 | DE_MIXER0_GLB_SIZE = (1079<<16) | 1919; 125 | 126 | DE_MIXER0_BLD_FILL_COLOR_CTL = 0x100; 127 | DE_MIXER0_BLD_CH_RTCTL = 0; 128 | DE_MIXER0_BLD_SIZE = (1079<<16) | 1919; 129 | DE_MIXER0_BLD_CH_ISIZE(0) = (1079<<16) | 1919; 130 | 131 | // The output takes a 480x270 area from a total 512x302 132 | // buffer leaving a 16px overscan on all 4 sides. 133 | DE_MIXER0_OVL_V_ATTCTL(0) = (1<<15) | (1<<0); 134 | DE_MIXER0_OVL_V_MBSIZE(0) = (269<<16) | 479; 135 | DE_MIXER0_OVL_V_COOR(0) = 0; 136 | DE_MIXER0_OVL_V_PITCH0(0) = 512*4; // Scan line in bytes including overscan 137 | DE_MIXER0_OVL_V_TOP_LADD0(0) = (uint32_t)&framebuffer1[512*16+16]; // Start at y=16 138 | 139 | DE_MIXER0_OVL_V_SIZE = (269<<16) | 479; 140 | 141 | DE_MIXER0_VS_CTRL = 1; 142 | DE_MIXER0_VS_OUT_SIZE = (1079<<16) | 1919; 143 | DE_MIXER0_VS_Y_SIZE = (269<<16) | 479; 144 | DE_MIXER0_VS_Y_HSTEP = 0x40000; 145 | DE_MIXER0_VS_Y_VSTEP = 0x40000; 146 | DE_MIXER0_VS_C_SIZE = (269<<16) | 479; 147 | DE_MIXER0_VS_C_HSTEP = 0x40000; 148 | DE_MIXER0_VS_C_VSTEP = 0x40000; 149 | for(int n=0;n<32;n++) { 150 | DE_MIXER0_VS_Y_HCOEF0(n) = 0x40000000; 151 | DE_MIXER0_VS_Y_HCOEF1(n) = 0; 152 | DE_MIXER0_VS_Y_VCOEF(n) = 0x00004000; 153 | DE_MIXER0_VS_C_HCOEF0(n) = 0x40000000; 154 | DE_MIXER0_VS_C_HCOEF1(n) = 0; 155 | DE_MIXER0_VS_C_VCOEF(n) = 0x00004000; 156 | } 157 | DE_MIXER0_VS_CTRL = 1 | (1<<4); 158 | DE_MIXER0_GLB_DBUFFER = 1; 159 | } 160 | 161 | // This function initializes the HDMI port and TCON. 162 | // Almost everything here is resolution specific and 163 | // currently hardcoded to 1920x1080@60Hz. 164 | void display_init() { 165 | active_buffer = framebuffer1; 166 | display_clocks_init(); 167 | hdmi_init(); 168 | lcd_init(); 169 | de2_init(); 170 | } 171 | 172 | void buffer_swap() { 173 | DE_MIXER0_OVL_V_TOP_LADD0(0) = (uint32_t)(active_buffer + 512*16+16); 174 | if(active_buffer == framebuffer1) { 175 | active_buffer = framebuffer2; 176 | } else if(active_buffer == framebuffer2) { 177 | active_buffer = framebuffer3; 178 | } else { 179 | active_buffer = framebuffer1; 180 | } 181 | // Blank visible area 182 | for(int n=512*16; n<512*(270+16); n++) 183 | active_buffer[n] = 0; 184 | DE_MIXER0_GLB_DBUFFER = 1; 185 | } -------------------------------------------------------------------------------- /display.h: -------------------------------------------------------------------------------- 1 | #define VIDEO_RAM_BYTES 0x180000 2 | 3 | // The HDMI registers base address. 4 | #define HDMI_BASE 0x01EE0000 5 | #define HDMI_PHY_BASE (HDMI_BASE + 0x10000) 6 | 7 | // HDMI register helpers. 8 | #define HDMI_PHY_POL *(volatile uint32_t*)(HDMI_BASE + 0x10000) 9 | #define HDMI_PHY_READ_EN *(volatile uint32_t*)(HDMI_BASE + 0x10010) 10 | #define HDMI_PHY_UNSCRAMBLE *(volatile uint32_t*)(HDMI_BASE + 0x10014) 11 | #define HDMI_PHY_CFG1 *(volatile uint32_t*)(HDMI_BASE + 0x10020) 12 | #define HDMI_PHY_CFG2 *(volatile uint32_t*)(HDMI_BASE + 0x10024) 13 | #define HDMI_PHY_CFG3 *(volatile uint32_t*)(HDMI_BASE + 0x10028) 14 | #define HDMI_PHY_PLL1 *(volatile uint32_t*)(HDMI_BASE + 0x1002C) 15 | #define HDMI_PHY_PLL2 *(volatile uint32_t*)(HDMI_BASE + 0x10030) 16 | #define HDMI_PHY_PLL3 *(volatile uint32_t*)(HDMI_BASE + 0x10034) 17 | #define HDMI_PHY_STS *(volatile uint32_t*)(HDMI_BASE + 0x10038) 18 | #define HDMI_PHY_CEC *(volatile uint32_t*)(HDMI_BASE + 0x1003C) 19 | 20 | #define HDMI_FC_INVIDCONF *(volatile uint8_t*)(HDMI_BASE + 0x1000) 21 | 22 | #define HDMI_FC_INHACTIV0 *(volatile uint8_t*)(HDMI_BASE + 0x1001) 23 | #define HDMI_FC_INHACTIV1 *(volatile uint8_t*)(HDMI_BASE + 0x1002) 24 | #define HDMI_FC_INHBLANK0 *(volatile uint8_t*)(HDMI_BASE + 0x1003) 25 | #define HDMI_FC_INHBLANK1 *(volatile uint8_t*)(HDMI_BASE + 0x1004) 26 | 27 | #define HDMI_FC_INVACTIV0 *(volatile uint8_t*)(HDMI_BASE + 0x1005) 28 | #define HDMI_FC_INVACTIV1 *(volatile uint8_t*)(HDMI_BASE + 0x1006) 29 | #define HDMI_FC_INVBLANK *(volatile uint8_t*)(HDMI_BASE + 0x1007) 30 | 31 | #define HDMI_FC_HSYNCINDELAY0 *(volatile uint8_t*)(HDMI_BASE + 0x1008) 32 | #define HDMI_FC_HSYNCINDELAY1 *(volatile uint8_t*)(HDMI_BASE + 0x1009) 33 | #define HDMI_FC_HSYNCINWIDTH0 *(volatile uint8_t*)(HDMI_BASE + 0x100A) 34 | #define HDMI_FC_HSYNCINWIDTH1 *(volatile uint8_t*)(HDMI_BASE + 0x100B) 35 | #define HDMI_FC_VSYNCINDELAY *(volatile uint8_t*)(HDMI_BASE + 0x100C) 36 | #define HDMI_FC_VSYNCINWIDTH *(volatile uint8_t*)(HDMI_BASE + 0x100D) 37 | 38 | #define HDMI_FC_CTRLDUR *(volatile uint8_t*)(HDMI_BASE + 0x1011) 39 | #define HDMI_FC_EXCTRLDUR *(volatile uint8_t*)(HDMI_BASE + 0x1012) 40 | #define HDMI_FC_EXCTRLSPAC *(volatile uint8_t*)(HDMI_BASE + 0x1013) 41 | #define HDMI_FC_CH0PREAM *(volatile uint8_t*)(HDMI_BASE + 0x1014) 42 | #define HDMI_FC_CH1PREAM *(volatile uint8_t*)(HDMI_BASE + 0x1015) 43 | #define HDMI_FC_CH2PREAM *(volatile uint8_t*)(HDMI_BASE + 0x1016) 44 | #define HDMI_MC_FLOWCTRL *(volatile uint8_t*)(HDMI_BASE + 0x4004) 45 | #define HDMI_MC_CLKDIS *(volatile uint8_t*)(HDMI_BASE + 0x4001) 46 | 47 | #define HDMI_VP_STUFF *(volatile uint8_t*)(HDMI_BASE + 0x0802) 48 | #define HDMI_VP_CONF *(volatile uint8_t*)(HDMI_BASE + 0x0804) 49 | 50 | #define HDMI_TX_INVID0 *(volatile uint8_t*)(HDMI_BASE + 0x0200) 51 | #define HDMI_TX_INSTUFFING *(volatile uint8_t*)(HDMI_BASE + 0x0201) 52 | 53 | // LCD/TCON 54 | #define LCD0_BASE 0x01C0C000 55 | #define LCD0_GCTL *(volatile uint32_t*)(LCD0_BASE + 0x000) 56 | #define LCD0_GINT0 *(volatile uint32_t*)(LCD0_BASE + 0x004) 57 | #define LCD0_GINT1 *(volatile uint32_t*)(LCD0_BASE + 0x008) 58 | #define LCD0_TCON1_CTL *(volatile uint32_t*)(LCD0_BASE + 0x090) 59 | #define LCD0_TCON1_BASIC0 *(volatile uint32_t*)(LCD0_BASE + 0x094) 60 | #define LCD0_TCON1_BASIC1 *(volatile uint32_t*)(LCD0_BASE + 0x098) 61 | #define LCD0_TCON1_BASIC2 *(volatile uint32_t*)(LCD0_BASE + 0x09C) 62 | #define LCD0_TCON1_BASIC3 *(volatile uint32_t*)(LCD0_BASE + 0x0A0) 63 | #define LCD0_TCON1_BASIC4 *(volatile uint32_t*)(LCD0_BASE + 0x0A4) 64 | #define LCD0_TCON1_BASIC5 *(volatile uint32_t*)(LCD0_BASE + 0x0A8) 65 | 66 | #define LCD1_BASE 0x01C0D000 67 | #define LCD1_GCTL *(volatile uint32_t*)(LCD1_BASE + 0x000) 68 | #define LCD1_GINT0 *(volatile uint32_t*)(LCD1_BASE + 0x004) 69 | #define LCD1_GINT1 *(volatile uint32_t*)(LCD1_BASE + 0x008) 70 | #define LCD1_TCON1_CTL *(volatile uint32_t*)(LCD1_BASE + 0x090) 71 | #define LCD1_TCON1_BASIC0 *(volatile uint32_t*)(LCD1_BASE + 0x094) 72 | #define LCD1_TCON1_BASIC1 *(volatile uint32_t*)(LCD1_BASE + 0x098) 73 | #define LCD1_TCON1_BASIC2 *(volatile uint32_t*)(LCD1_BASE + 0x09C) 74 | #define LCD1_TCON1_BASIC3 *(volatile uint32_t*)(LCD1_BASE + 0x0A0) 75 | #define LCD1_TCON1_BASIC4 *(volatile uint32_t*)(LCD1_BASE + 0x0A4) 76 | #define LCD1_TCON1_BASIC5 *(volatile uint32_t*)(LCD1_BASE + 0x0A8) 77 | 78 | // DE2 79 | #define DE_BASE 0x01000000 80 | #define DE_SCLK_GATE *(volatile uint32_t*)(DE_BASE + 0x000) 81 | #define DE_HCLK_GATE *(volatile uint32_t*)(DE_BASE + 0x004) 82 | #define DE_AHB_RESET *(volatile uint32_t*)(DE_BASE + 0x008) 83 | #define DE_SCLK_DIV *(volatile uint32_t*)(DE_BASE + 0x00C) 84 | #define DE_DE2TCON_MUX *(volatile uint32_t*)(DE_BASE + 0x010) 85 | 86 | // Mixer 0 87 | #define DE_MIXER0 (DE_BASE + 0x100000) 88 | #define DE_MIXER0_GLB (DE_MIXER0 + 0x0) 89 | #define DE_MIXER0_GLB_CTL *(volatile uint32_t*)(DE_MIXER0_GLB + 0x000) 90 | #define DE_MIXER0_GLB_STS *(volatile uint32_t*)(DE_MIXER0_GLB + 0x004) 91 | #define DE_MIXER0_GLB_DBUFFER *(volatile uint32_t*)(DE_MIXER0_GLB + 0x008) 92 | #define DE_MIXER0_GLB_SIZE *(volatile uint32_t*)(DE_MIXER0_GLB + 0x00C) 93 | 94 | #define DE_MIXER0_BLD (DE_MIXER0 + 0x1000) 95 | #define DE_MIXER0_BLD_FILL_COLOR_CTL *(volatile uint32_t*)(DE_MIXER0_BLD + 0x000) 96 | #define DE_MIXER0_BLD_FILL_COLOR(x) *(volatile uint32_t*)(DE_MIXER0_BLD + 0x004 + x * 0x10) 97 | #define DE_MIXER0_BLD_CH_ISIZE(x) *(volatile uint32_t*)(DE_MIXER0_BLD + 0x008 + x * 0x10) 98 | #define DE_MIXER0_BLD_CH_OFFSET(x) *(volatile uint32_t*)(DE_MIXER0_BLD + 0x00C + x * 0x10) 99 | #define DE_MIXER0_BLD_CH_RTCTL *(volatile uint32_t*)(DE_MIXER0_BLD + 0x080) 100 | #define DE_MIXER0_BLD_PREMUL_CTL *(volatile uint32_t*)(DE_MIXER0_BLD + 0x084) 101 | #define DE_MIXER0_BLD_BK_COLOR *(volatile uint32_t*)(DE_MIXER0_BLD + 0x088) 102 | #define DE_MIXER0_BLD_SIZE *(volatile uint32_t*)(DE_MIXER0_BLD + 0x08C) 103 | #define DE_MIXER0_BLD_CTL(x) *(volatile uint32_t*)(DE_MIXER0_BLD + 0x090 + x * 0x4) 104 | #define DE_MIXER0_BLD_KEY_CTL *(volatile uint32_t*)(DE_MIXER0_BLD + 0x0B0) 105 | #define DE_MIXER0_BLD_KEY_CON *(volatile uint32_t*)(DE_MIXER0_BLD + 0x0B4) 106 | #define DE_MIXER0_BLD_KEY_MAX(x) *(volatile uint32_t*)(DE_MIXER0_BLD + 0x0C0 + x * 0x4) 107 | #define DE_MIXER0_BLD_KEY_MIN(x) *(volatile uint32_t*)(DE_MIXER0_BLD + 0x0E0 + x * 0x4) 108 | #define DE_MIXER0_BLD_OUT_COLOR *(volatile uint32_t*)(DE_MIXER0_BLD + 0x0FC) 109 | 110 | #define DE_MIXER0_OVL_V (DE_MIXER0 + 0x2000) 111 | #define DE_MIXER0_OVL_V_ATTCTL(x) *(volatile uint32_t*)(DE_MIXER0_OVL_V + 0x00 + x * 0x30) 112 | #define DE_MIXER0_OVL_V_MBSIZE(x) *(volatile uint32_t*)(DE_MIXER0_OVL_V + 0x04 + x * 0x30) 113 | #define DE_MIXER0_OVL_V_COOR(x) *(volatile uint32_t*)(DE_MIXER0_OVL_V + 0x08 + x * 0x30) 114 | #define DE_MIXER0_OVL_V_PITCH0(x) *(volatile uint32_t*)(DE_MIXER0_OVL_V + 0x0C + x * 0x30) 115 | #define DE_MIXER0_OVL_V_PITCH1(x) *(volatile uint32_t*)(DE_MIXER0_OVL_V + 0x10 + x * 0x30) 116 | #define DE_MIXER0_OVL_V_PITCH2(x) *(volatile uint32_t*)(DE_MIXER0_OVL_V + 0x14 + x * 0x30) 117 | #define DE_MIXER0_OVL_V_TOP_LADD0(x) *(volatile uint32_t*)(DE_MIXER0_OVL_V + 0x18 + x * 0x30) 118 | #define DE_MIXER0_OVL_V_TOP_LADD1(x) *(volatile uint32_t*)(DE_MIXER0_OVL_V + 0x1C + x * 0x30) 119 | #define DE_MIXER0_OVL_V_TOP_LADD2(x) *(volatile uint32_t*)(DE_MIXER0_OVL_V + 0x20 + x * 0x30) 120 | #define DE_MIXER0_OVL_V_BOT_LADD0(x) *(volatile uint32_t*)(DE_MIXER0_OVL_V + 0x24 + x * 0x30) 121 | #define DE_MIXER0_OVL_V_BOT_LADD1(x) *(volatile uint32_t*)(DE_MIXER0_OVL_V + 0x28 + x * 0x30) 122 | #define DE_MIXER0_OVL_V_BOT_LADD2(x) *(volatile uint32_t*)(DE_MIXER0_OVL_V + 0x2C + x * 0x30) 123 | #define DE_MIXER0_OVL_V_FILL_COLOR(x) *(volatile uint32_t*)(DE_MIXER0_OVL_V + 0xC0 + x * 0x4) 124 | #define DE_MIXER0_OVL_V_TOP_HADD0 *(volatile uint32_t*)(DE_MIXER0_OVL_V + 0xD0) 125 | #define DE_MIXER0_OVL_V_TOP_HADD1 *(volatile uint32_t*)(DE_MIXER0_OVL_V + 0xD4) 126 | #define DE_MIXER0_OVL_V_TOP_HADD2 *(volatile uint32_t*)(DE_MIXER0_OVL_V + 0xD8) 127 | #define DE_MIXER0_OVL_V_BOT_HADD0 *(volatile uint32_t*)(DE_MIXER0_OVL_V + 0xDC) 128 | #define DE_MIXER0_OVL_V_BOT_HADD1 *(volatile uint32_t*)(DE_MIXER0_OVL_V + 0xE0) 129 | #define DE_MIXER0_OVL_V_BOT_HADD2 *(volatile uint32_t*)(DE_MIXER0_OVL_V + 0xE4) 130 | #define DE_MIXER0_OVL_V_SIZE *(volatile uint32_t*)(DE_MIXER0_OVL_V + 0xE8) 131 | 132 | #define DE_MIXER0_VS_BASE (DE_MIXER0 + 0x20000) 133 | #define DE_MIXER0_VS_CTRL *(volatile uint32_t*)(DE_MIXER0_VS_BASE + 0x00) 134 | #define DE_MIXER0_VS_STATUS *(volatile uint32_t*)(DE_MIXER0_VS_BASE + 0x08) 135 | #define DE_MIXER0_VS_FIELD_CTRL *(volatile uint32_t*)(DE_MIXER0_VS_BASE + 0x0C) 136 | #define DE_MIXER0_VS_OUT_SIZE *(volatile uint32_t*)(DE_MIXER0_VS_BASE + 0x40) 137 | #define DE_MIXER0_VS_Y_SIZE *(volatile uint32_t*)(DE_MIXER0_VS_BASE + 0x80) 138 | #define DE_MIXER0_VS_Y_HSTEP *(volatile uint32_t*)(DE_MIXER0_VS_BASE + 0x88) 139 | #define DE_MIXER0_VS_Y_VSTEP *(volatile uint32_t*)(DE_MIXER0_VS_BASE + 0x8C) 140 | #define DE_MIXER0_VS_Y_HPHASE *(volatile uint32_t*)(DE_MIXER0_VS_BASE + 0x90) 141 | #define DE_MIXER0_VS_Y_VPHASE0 *(volatile uint32_t*)(DE_MIXER0_VS_BASE + 0x98) 142 | #define DE_MIXER0_VS_Y_VPHASE1 *(volatile uint32_t*)(DE_MIXER0_VS_BASE + 0x9C) 143 | #define DE_MIXER0_VS_C_SIZE *(volatile uint32_t*)(DE_MIXER0_VS_BASE + 0xC0) 144 | #define DE_MIXER0_VS_C_HSTEP *(volatile uint32_t*)(DE_MIXER0_VS_BASE + 0xC8) 145 | #define DE_MIXER0_VS_C_VSTEP *(volatile uint32_t*)(DE_MIXER0_VS_BASE + 0xCC) 146 | #define DE_MIXER0_VS_C_HPHASE *(volatile uint32_t*)(DE_MIXER0_VS_BASE + 0xD0) 147 | #define DE_MIXER0_VS_C_VPHASE0 *(volatile uint32_t*)(DE_MIXER0_VS_BASE + 0xD8) 148 | #define DE_MIXER0_VS_C_VPHASE1 *(volatile uint32_t*)(DE_MIXER0_VS_BASE + 0xDC) 149 | #define DE_MIXER0_VS_Y_HCOEF0(x) *(volatile uint32_t*)(DE_MIXER0_VS_BASE + 0x200 + x * 4) 150 | #define DE_MIXER0_VS_Y_HCOEF1(x) *(volatile uint32_t*)(DE_MIXER0_VS_BASE + 0x300 + x * 4) 151 | #define DE_MIXER0_VS_Y_VCOEF(x) *(volatile uint32_t*)(DE_MIXER0_VS_BASE + 0x400 + x * 4) 152 | #define DE_MIXER0_VS_C_HCOEF0(x) *(volatile uint32_t*)(DE_MIXER0_VS_BASE + 0x600 + x * 4) 153 | #define DE_MIXER0_VS_C_HCOEF1(x) *(volatile uint32_t*)(DE_MIXER0_VS_BASE + 0x700 + x * 4) 154 | #define DE_MIXER0_VS_C_VCOEF(x) *(volatile uint32_t*)(DE_MIXER0_VS_BASE + 0x800 + x * 4) 155 | 156 | void display_init(); 157 | void buffer_swap(); 158 | 159 | volatile uint32_t* active_buffer; 160 | -------------------------------------------------------------------------------- /interrupts.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "uart.h" 3 | #include "interrupts.h" 4 | #include "display.h" 5 | 6 | extern uint32_t _ivt; 7 | void game_tick_next(); 8 | 9 | // Called when an interrupt is triggered 10 | // Currently this is always triggered by at new frame at 60Hz 11 | void __attribute__((interrupt("FIQ"))) interrupt(void) { 12 | game_tick_next(); 13 | LCD0_GINT0 &= ~(1<<12); 14 | } 15 | 16 | // Copy the interrupt table from _ivt to 0x0 17 | void install_ivt() { 18 | uint32_t* source = &_ivt; 19 | uint32_t* destination = (uint32_t*)(0); 20 | for(int n=0; n<2*8; n++) 21 | destination[n] = source[n]; 22 | 23 | struct gicd_reg* gicd = (struct gicd_reg*) GICD_BASE; 24 | gicd->ctlr = 1; 25 | gicd->isenabler[118/32] = 1<<(118%32); 26 | gicd->itargetsr[118] = 1; 27 | gicd->ipriorityr[118] = 1; 28 | struct gicc_reg* gicc = (struct gicc_reg*) GICC_BASE; 29 | gicc->ctlr = 1; 30 | gicc->pmr = 10; 31 | asm("cpsie if;"); // Enable interrupts 32 | } 33 | -------------------------------------------------------------------------------- /interrupts.h: -------------------------------------------------------------------------------- 1 | #define GICD_BASE 0x01C81000 2 | 3 | 4 | #define GICD_BASE 0x01C81000 5 | struct gicd_reg { 6 | uint32_t ctlr; /* 0x000 */ 7 | uint32_t typer; /* 0x004 */ 8 | uint32_t iidr; /* 0x008 */ 9 | uint32_t rfu0[29]; /* 0x00C - 0x07C */ 10 | uint32_t igroupr[32]; /* 0x080 - 0x0FC */ 11 | uint32_t isenabler[32]; 12 | uint32_t icenabler[32]; 13 | uint32_t ispender[32]; 14 | uint32_t icpender[32]; 15 | uint32_t isactiver[32]; 16 | uint32_t icactiver[32]; 17 | uint8_t ipriorityr[1024]; 18 | uint8_t itargetsr[1024]; 19 | uint32_t icfgr[64]; 20 | uint32_t rfu1[64]; 21 | uint32_t nsacr[64]; 22 | uint32_t sgir; 23 | uint32_t rfu2[3]; 24 | uint32_t cpendsgir[4]; 25 | uint32_t spendsgir[4]; 26 | uint32_t rfu3[52]; 27 | }; 28 | 29 | #define GICC_BASE 0x01C82000 30 | struct gicc_reg { 31 | uint32_t ctlr; /* 0x000 */ 32 | uint32_t pmr; /* 0x004 */ 33 | uint32_t bpr; /* 0x008 */ 34 | uint32_t iar; /* 0x00C */ 35 | uint32_t eoir; 36 | uint32_t rpr; 37 | uint32_t hppir; 38 | uint32_t abpr; 39 | uint32_t aiar; 40 | uint32_t aeoir; 41 | uint32_t ahppir; 42 | uint32_t rfu0[41]; 43 | uint32_t apr[4]; 44 | uint32_t nsapr[4]; 45 | uint32_t rfu1[3]; 46 | uint32_t iidr; 47 | uint32_t rfu2[960]; 48 | uint32_t dir; 49 | }; 50 | 51 | void install_ivt(); -------------------------------------------------------------------------------- /linker.ld: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x4e000000; 4 | .text : { 5 | boot.o(.text) 6 | *(.text) 7 | } 8 | .bss : { 9 | _bstart1 = . ; 10 | *(.bss); *(COMMON); 11 | _bend1 = . ; 12 | } 13 | .data : { 14 | *(.data) 15 | } 16 | .uncached 0x50000000 : { 17 | _bstart2 = . ; 18 | *(UNCACHED); 19 | _bend2 = . ; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /mmu.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void mmu_init() { 4 | 5 | // Disable MMU 6 | asm("ldr r8, =0x0; mcr p15, 0, r8, c1, c0, 0;" : : : "r8"); 7 | 8 | // Populate the pagetable 9 | volatile uint32_t* pagetable = (volatile uint32_t *)0x4000; 10 | for(int n=0;n<0x1000;n++) { 11 | if(n==0) { 12 | // SRAM. Write back. 13 | pagetable[n] = (n<<20) | (1<<12) | (3<<10) | (3<<2) | 2; 14 | } else if(n>=0x400 && n<0x500) { 15 | // First half of DRAM. Write back. 16 | pagetable[n] = (n<<20) | (1<<12) | (3<<10) | (3<<2) | 2; 17 | } else if(n>=0x500 && n<0x600) { 18 | // Video DRAM. Normal uncached. 19 | pagetable[n] = (n<<20) | (1<<12) | (3<<10) | (0<<2) | 2; 20 | } else { 21 | // Other stuff. Strictly ordered for safety. 22 | pagetable[n] = (n<<20) | (0<<12) | (3<<10) | (0<<2) | 2; 23 | } 24 | } 25 | 26 | // Set up the pagetable 27 | asm("ldr r8, =0x4000; mcr p15, 0, r8, c2, c0, 0" : : : "r8"); 28 | asm("ldr r8, =0x0; mcr p15, 0, r8, c2, c0, 2" : : : "r8"); 29 | asm("ldr r8, =0x3; mcr p15, 0, r8, c3, c0, 0" : : : "r8"); 30 | 31 | // Enable MMU 32 | asm( 33 | "ldr r8, =0x0;" 34 | "MCR p15, 0, r8, c8, C3, 0;" 35 | "MCR p15, 0, r8, c8, C5, 0;" 36 | "MCR p15, 0, r8, c8, C6, 0;" 37 | "MCR p15, 0, r8, c8, C7, 0;" 38 | "mcr p15, 0, r8, c12, c0, 0;" 39 | 40 | "ldr r8, =0x1005;" 41 | "mcr p15, 0, r8, c1, c0, 0;" 42 | : : : "r8"); 43 | 44 | } 45 | -------------------------------------------------------------------------------- /mmu.h: -------------------------------------------------------------------------------- 1 | void mmu_init(); -------------------------------------------------------------------------------- /ports.c: -------------------------------------------------------------------------------- 1 | #include "ports.h" 2 | #include "ccu.h" 3 | 4 | void gpio_init() { 5 | BUS_CLK_GATING2 |= (1<<5); 6 | APB0_CLK_GATING |= (1<<0); 7 | } 8 | 9 | void set_pin_mode(uint32_t port_addr, uint32_t pin, uint32_t mode) { 10 | struct port_registers * port = (struct port_registers *)port_addr; 11 | if(pin < 8) { 12 | port->cfg0 &= ~(7 << ((pin - 0) * 4)); 13 | port->cfg0 |= (mode << ((pin - 0) * 4)); 14 | } else if(pin < 16) { 15 | port->cfg1 &= ~(7 << ((pin - 8) * 4)); 16 | port->cfg1 |= (mode << ((pin - 8) * 4)); 17 | } else if(pin < 24) { 18 | port->cfg2 &= ~(7 << ((pin - 16) * 4)); 19 | port->cfg2 |= (mode << ((pin - 16) * 4)); 20 | } else { 21 | port->cfg3 &= ~(7 << ((pin - 24) * 4)); 22 | port->cfg3 |= (mode << ((pin - 24) * 4)); 23 | } 24 | } 25 | 26 | void set_pin_data(uint32_t port_addr, uint32_t pin, uint32_t data) { 27 | struct port_registers * port = (struct port_registers *)port_addr; 28 | if(data) { 29 | port->data |= (1 << pin); 30 | } else { 31 | port->data &= ~(1 << pin); 32 | } 33 | } -------------------------------------------------------------------------------- /ports.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // Port access struct 4 | struct port_registers { 5 | uint32_t cfg0; 6 | uint32_t cfg1; 7 | uint32_t cfg2; 8 | uint32_t cfg3; 9 | uint32_t data; 10 | }; 11 | 12 | // The PORT registers base address. 13 | #define PIO_BASE 0x01C20800 14 | #define PORTA PIO_BASE + 0 * 0x24 15 | #define PORTC PIO_BASE + 2 * 0x24 16 | #define PORTD PIO_BASE + 3 * 0x24 17 | #define PORTE PIO_BASE + 4 * 0x24 18 | #define PORTF PIO_BASE + 5 * 0x24 19 | #define PORTG PIO_BASE + 6 * 0x24 20 | #define PORTL 0x01F02C00 21 | 22 | void set_pin_mode(uint32_t port, uint32_t pin, uint32_t mode); 23 | void set_pin_data(uint32_t port, uint32_t pin, uint32_t data); 24 | void gpio_init(); -------------------------------------------------------------------------------- /spritelayers.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "spritelayers.h" 3 | #include "display.h" 4 | 5 | inline void render_raw(uint32_t* pattern, volatile uint32_t* destination); 6 | 7 | void render_layer(struct sprite_layer* layer) { 8 | uint32_t** pattern = layer->pattern; 9 | // Iterate over sprites 10 | int32_t y_position = layer->y_offset; 11 | for(uint32_t y=0; y < layer->y_size; y++) { 12 | y_position += 16; 13 | int32_t x_position = layer->x_offset; 14 | for(uint32_t x=0; x < layer->x_size; x++) { 15 | x_position += 16; 16 | // Don't render anything outside the buffer area 17 | if(*pattern && 18 | x_position > 0 && x_position < 496 && 19 | y_position > 0 && y_position < 286) 20 | render_raw(*pattern, active_buffer + y_position * 512 + x_position); 21 | // } 22 | pattern++; 23 | } 24 | } 25 | } 26 | 27 | void render_sprite(uint32_t* pattern, int32_t x_offset, int32_t y_offset){ 28 | // Add 16 to the offset such that 0,0 is the upper-left of the visible display 29 | volatile uint32_t* destination = active_buffer + (y_offset + 16) * 512 + (x_offset + 16); 30 | render_raw(pattern, destination); 31 | } 32 | 33 | 34 | inline void render_raw(uint32_t* pattern, volatile uint32_t* destination) { 35 | for(int y=0; y<16; y++) { 36 | for(int x=0; x<16; x++) { 37 | if(*pattern) { 38 | *destination = *pattern; 39 | } 40 | pattern++; 41 | destination++; 42 | } 43 | destination += 512-16; 44 | } 45 | } 46 | 47 | // TODO: An additionl function to render individual sprites with full 8-bit opacity 48 | -------------------------------------------------------------------------------- /spritelayers.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct sprite_layer { 4 | uint32_t** pattern; 5 | uint32_t x_size; 6 | uint32_t y_size; 7 | int32_t x_offset; 8 | int32_t y_offset; 9 | }; 10 | 11 | void render_layer(struct sprite_layer* layer); 12 | void render_sprite(uint32_t* pattern, int32_t x, int32_t y); 13 | -------------------------------------------------------------------------------- /startup.c: -------------------------------------------------------------------------------- 1 | #include "ports.h" 2 | #include "uart.h" 3 | #include "mmu.h" 4 | #include "system.h" 5 | #include "display.h" 6 | #include "interrupts.h" 7 | #include "ccu.h" 8 | #include "usb.h" 9 | 10 | uint32_t tick_counter; 11 | 12 | void game_tick(uint32_t tick_counter); 13 | void game_start(); 14 | 15 | void startup() { 16 | init_bss(); 17 | 18 | // Reboot in n seconds using watchdog 19 | reboot(2); // 0x8 == 10 second reset timer 20 | 21 | // Enble all GPIO 22 | gpio_init(); 23 | 24 | // Configure the UART for debugging 25 | uart_init(); 26 | uart_print("Booting!\r\n"); 27 | 28 | // Set up MMU and paging configuration 29 | mmu_init(); 30 | 31 | // Illuminate the power LED 32 | set_pin_mode(PORTL, 10, 1); // PORT L10 output 33 | set_pin_data(PORTL, 10, 1); // PORT L10 high 34 | 35 | // Configure display 36 | display_init((volatile uint32_t*)(0x60000000-VIDEO_RAM_BYTES)); 37 | 38 | // USB 39 | usb_init(); 40 | 41 | uart_print("Ready!\r\n"); 42 | game_start(); 43 | 44 | install_ivt(); 45 | 46 | // Go back to sleep 47 | while(1) asm("wfi"); 48 | } 49 | 50 | void game_tick_next() { 51 | buffer_swap(); 52 | game_tick(tick_counter); 53 | tick_counter++; 54 | } 55 | -------------------------------------------------------------------------------- /system.c: -------------------------------------------------------------------------------- 1 | #include "system.h" 2 | 3 | void init_bss() { 4 | for (char* dst = &_bstart1; dst < &_bend1; dst++) 5 | *dst = 0; 6 | for (char* dst = &_bstart2; dst < &_bend2; dst++) 7 | *dst = 0; 8 | } 9 | 10 | void udelay(uint32_t d) { 11 | for(uint32_t n=0;n 2 | 3 | #define TIMER_BASE 0x01C20C00 4 | #define WDOG0_MODE *(volatile uint32_t *)(TIMER_BASE + 0xB8) 5 | void udelay(uint32_t d); 6 | void reboot(uint32_t seconds); 7 | 8 | void init_bss(); 9 | extern char _bstart1; 10 | extern char _bend1; 11 | extern char _bstart2; 12 | extern char _bend2; 13 | -------------------------------------------------------------------------------- /uart.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "uart.h" 4 | #include "ports.h" 5 | #include "ccu.h" 6 | 7 | // Set up the UART (serial port) 8 | void uart_init() 9 | { 10 | // Configure port 11 | set_pin_mode(PORTA, 4, 2); 12 | 13 | // Enable clock 14 | BUS_CLK_GATING3 |= (1<<16); 15 | BUS_SOFT_RST4 |= (1<<16); 16 | 17 | // Configure baud rate 18 | UART0_LCR = (1<<7) | 3; 19 | UART0_DLL = 13; 20 | UART0_LCR = 3; 21 | 22 | // Enable FIFO 23 | UART0_FCR = 0x00000001; 24 | } 25 | 26 | // UART is ready to receive data to transmit? 27 | unsigned char uart_tx_ready() 28 | { 29 | return (UART0_USR & 2); 30 | } 31 | 32 | // UART has received data? 33 | unsigned char uart_rx_ready() 34 | { 35 | return (UART0_LSR & 1); 36 | } 37 | 38 | // Push one byte to the UART port (blocking until ready to transmit) 39 | void uart_putc(unsigned char byte) 40 | { 41 | // Wait for UART transmit FIFO to be not full. 42 | while ( ! uart_tx_ready() ); 43 | UART0_THR = byte; 44 | } 45 | 46 | // Write a zero terminated string to the UART 47 | void uart_print(const char* str) 48 | { 49 | while(*str) { 50 | uart_putc(*str); 51 | str++; 52 | } 53 | } 54 | 55 | // Print a char to the UART as ASCII HEX 56 | void uart_print_uint8(unsigned char number) 57 | { 58 | unsigned char chars[] = "0123456789ABCDEF"; 59 | uart_putc(chars[(number >> 4) & 0xF]); 60 | uart_putc(chars[(number >> 0) & 0xF]); 61 | } 62 | 63 | // Print a uint32 to the UART as ASCII HEX 64 | void uart_print_uint32(uint32_t number) 65 | { 66 | unsigned char chars[] = "0123456789ABCDEF"; 67 | uart_putc(chars[(number >> 28) & 0xF]); 68 | uart_putc(chars[(number >> 24) & 0xF]); 69 | uart_putc(chars[(number >> 20) & 0xF]); 70 | uart_putc(chars[(number >> 16) & 0xF]); 71 | uart_putc(chars[(number >> 12) & 0xF]); 72 | uart_putc(chars[(number >> 8) & 0xF]); 73 | uart_putc(chars[(number >> 4) & 0xF]); 74 | uart_putc(chars[(number >> 0) & 0xF]); 75 | } -------------------------------------------------------------------------------- /uart.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // The UART registers base address. 4 | #define UART0_BASE 0x01C28000 5 | // Macros to access UART registers. 6 | #define UART0_RBR *(volatile uint32_t *)(UART0_BASE + 0x00) 7 | #define UART0_THR *(volatile uint32_t *)(UART0_BASE + 0x00) 8 | #define UART0_DLL *(volatile uint32_t *)(UART0_BASE + 0x00) 9 | #define UART0_IER *(volatile uint32_t *)(UART0_BASE + 0x04) 10 | #define UART0_FCR *(volatile uint32_t *)(UART0_BASE + 0x08) 11 | #define UART0_LCR *(volatile uint32_t *)(UART0_BASE + 0x0C) 12 | #define UART0_LSR *(volatile uint32_t *)(UART0_BASE + 0x14) 13 | #define UART0_USR *(volatile uint32_t *)(UART0_BASE + 0x7C) 14 | 15 | void uart_init(); 16 | void uart_print(const char* str); 17 | void uart_print_uint8(unsigned char number); 18 | void uart_print_uint32(uint32_t number); -------------------------------------------------------------------------------- /usb.c: -------------------------------------------------------------------------------- 1 | #include "usb.h" 2 | #include "uart.h" 3 | #include "ccu.h" 4 | #include "ports.h" 5 | #include "system.h" 6 | 7 | // Allocate memory for a setup request and a setup response in DRAM 8 | char setup_request[8] __attribute__ ((section ("UNCACHED"))) __attribute__ ((aligned (16))); 9 | char setup_response[8] __attribute__ ((section ("UNCACHED"))) __attribute__ ((aligned (16))); 10 | 11 | // Allocate memory for hcca, ED and 3 x TD 12 | struct hcca hcca __attribute__ ((section ("UNCACHED"))); 13 | struct ed controlED __attribute__ ((section ("UNCACHED"))); 14 | struct td setup_td[3] __attribute__ ((section ("UNCACHED"))); 15 | 16 | void usb_init() { 17 | // Enable clocks 18 | BUS_CLK_GATING0 |= (1<<29)|(1<<25); 19 | BUS_SOFT_RST0 |= (1<<29)|(1<<25); 20 | USBPHY_CFG |= (1<<17) | (1<<9) | (1<<1); 21 | // Enabe INCR16, INCR8, INCR4 22 | USB1_HCI_ICR = 0x00000701; 23 | USB1_HCI_UNK1 = 0; 24 | 25 | // Reset OHCI 26 | USB1_O_HCCOMMANDSTATUS |= 1; 27 | while(USB1_O_HCCOMMANDSTATUS & 1); 28 | 29 | // Basic OHCI setup 30 | USB1_O_HCFMINTERVAL = 0xA7782EDF; // Magic constant, sorry 31 | USB1_O_HCPERIODDICSTART = 0x2A2F; // Magic constant, sorry 32 | USB1_O_HCHCCA = (uint32_t)&hcca; 33 | USB1_O_HCCONTROLHEADED = (uint32_t)&controlED; 34 | USB1_O_HCCONTROLCURRENTED = 0; 35 | 36 | setup_request[0] = 0x80; 37 | setup_request[1] = 0x06; 38 | setup_request[2] = 0x00; 39 | setup_request[3] = 0x01; 40 | setup_request[4] = 0x00; 41 | setup_request[5] = 0x00; 42 | setup_request[6] = 0x08; 43 | setup_request[7] = 0x00; 44 | 45 | // Build the 3 transport descriptors for the setup process 46 | setup_td[0].info = 0xE2E00000; 47 | setup_td[0].cbp = (uint32_t)setup_request; 48 | setup_td[0].nexttd = (uint32_t)&setup_td[1]; 49 | setup_td[0].bufferend = ((uint32_t)setup_request)+7; 50 | 51 | setup_td[1].info = 0xE3F00000; 52 | setup_td[1].cbp = (uint32_t)setup_response; 53 | setup_td[1].nexttd = (uint32_t)&setup_td[2]; 54 | setup_td[1].bufferend = ((uint32_t)setup_response)+7; 55 | 56 | setup_td[2].info = 0xE3080000; 57 | setup_td[2].cbp = 0; 58 | setup_td[2].nexttd = (uint32_t)&setup_td[3]; 59 | setup_td[2].bufferend = 0; 60 | 61 | // Build the endpoint descriptor for the setup process 62 | controlED.info = 0x00082000; 63 | controlED.headp = &setup_td[0]; 64 | controlED.tailp = &setup_td[3]; 65 | controlED.nexted = 0; 66 | 67 | // Reset the root hub port 68 | USB1_O_HCRHPORTSTATUS = (1<<4); 69 | //udelay(10000); 70 | USB1_O_HCRHPORTSTATUS = (1<<1); 71 | 72 | // Enable control packets 73 | USB1_O_HCCONTROL = 0x90; 74 | //udelay(100000); 75 | // Inform controller of new control data 76 | USB1_O_HCCOMMANDSTATUS |= 2; 77 | 78 | udelay(10000); 79 | 80 | // Everything that follows is to check the results. 81 | 82 | uart_print("Control ED: "); 83 | uart_print_uint32(controlED.info); 84 | uart_print(" "); 85 | uart_print_uint32((uint32_t)controlED.headp); 86 | uart_print(" "); 87 | uart_print_uint32((uint32_t)controlED.tailp); 88 | uart_print(" "); 89 | uart_print_uint32((uint32_t)controlED.nexted); 90 | uart_print(" "); 91 | uart_print("\r\n"); 92 | 93 | for(uint32_t n=0; n<3; n++) { 94 | uart_print("Setup TD["); 95 | uart_print_uint8(n); 96 | uart_print("]: "); 97 | uart_print_uint32(setup_td[n].info); 98 | uart_print(" "); 99 | uart_print_uint32(setup_td[n].cbp); 100 | uart_print(" "); 101 | uart_print_uint32(setup_td[n].nexttd); 102 | uart_print(" "); 103 | uart_print_uint32(setup_td[n].bufferend); 104 | uart_print(" "); 105 | uart_print("\r\n"); 106 | } 107 | 108 | uart_print("Setup Request: "); 109 | for(int n=0; n<8; n++) { 110 | uart_print_uint8(setup_request[n]); 111 | uart_print(" "); 112 | } 113 | uart_print("\r\n"); 114 | 115 | uart_print("Setup Response: "); 116 | for(int n=0; n<8; n++) { 117 | uart_print_uint8(setup_response[n]); 118 | uart_print(" "); 119 | } 120 | uart_print("\r\n"); 121 | 122 | } 123 | -------------------------------------------------------------------------------- /usb.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define USB1_BASE 0x01C1B000 4 | 5 | #define USB1_E_CAPLENGTH *(volatile uint8_t *)(USB1_BASE + 0x000) 6 | #define USB1_E_HCIVERSION *(volatile uint16_t *)(USB1_BASE + 0x002) 7 | #define USB1_E_HCSPARAMS *(volatile uint32_t *)(USB1_BASE + 0x004) 8 | #define USB1_E_HCCPARAMS *(volatile uint32_t *)(USB1_BASE + 0x008) 9 | #define USB1_E_HCSPPORTROUTE *(volatile uint32_t *)(USB1_BASE + 0x00C) 10 | 11 | #define USB1_E_USBCMD *(volatile uint32_t *)(USB1_BASE + 0x010) 12 | #define USB1_E_USBSTS *(volatile uint32_t *)(USB1_BASE + 0x014) 13 | #define USB1_E_USBINTR *(volatile uint32_t *)(USB1_BASE + 0x018) 14 | #define USB1_E_FRINDEX *(volatile uint32_t *)(USB1_BASE + 0x01C) 15 | #define USB1_E_CTRLDSSEGMENT *(volatile uint32_t *)(USB1_BASE + 0x020) 16 | #define USB1_E_PERIODICLISTBASE *(volatile uint32_t *)(USB1_BASE + 0x024) 17 | #define USB1_E_ASYNCLISTADDR *(volatile uint32_t *)(USB1_BASE + 0x028) 18 | #define USB1_E_CONFIGFLAG *(volatile uint32_t *)(USB1_BASE + 0x050) 19 | #define USB1_E_PORTSC *(volatile uint32_t *)(USB1_BASE + 0x054) 20 | 21 | #define USB1_O_HCREVISION *(volatile uint32_t *)(USB1_BASE + 0x400) 22 | #define USB1_O_HCCONTROL *(volatile uint32_t *)(USB1_BASE + 0x404) 23 | #define USB1_O_HCCOMMANDSTATUS *(volatile uint32_t *)(USB1_BASE + 0x408) 24 | #define USB1_O_HCINTERRUPTSTATUS *(volatile uint32_t *)(USB1_BASE + 0x40C) 25 | #define USB1_O_HCINTERRUPTENABLE *(volatile uint32_t *)(USB1_BASE + 0x410) 26 | #define USB1_O_HCINTERRUPTDISABLE *(volatile uint32_t *)(USB1_BASE + 0x414) 27 | 28 | #define USB1_O_HCHCCA *(volatile uint32_t *)(USB1_BASE + 0x418) 29 | #define USB1_O_HCPERIODCURRENTED *(volatile uint32_t *)(USB1_BASE + 0x41C) 30 | #define USB1_O_HCCONTROLHEADED *(volatile uint32_t *)(USB1_BASE + 0x420) 31 | #define USB1_O_HCCONTROLCURRENTED *(volatile uint32_t *)(USB1_BASE + 0x424) 32 | #define USB1_O_HCBULKHEADED *(volatile uint32_t *)(USB1_BASE + 0x428) 33 | #define USB1_O_HCBULKCURRENTED *(volatile uint32_t *)(USB1_BASE + 0x42C) 34 | #define USB1_O_HCDONEHEAD *(volatile uint32_t *)(USB1_BASE + 0x430) 35 | 36 | #define USB1_O_HCFMINTERVAL *(volatile uint32_t *)(USB1_BASE + 0x434) 37 | #define USB1_O_HCFMREMAINING *(volatile uint32_t *)(USB1_BASE + 0x438) 38 | #define USB1_O_HCFMNUMBER *(volatile uint32_t *)(USB1_BASE + 0x43C) 39 | #define USB1_O_HCPERIODDICSTART *(volatile uint32_t *)(USB1_BASE + 0x440) 40 | #define USB1_O_HCLSTHRESHOLD *(volatile uint32_t *)(USB1_BASE + 0x444) 41 | 42 | #define USB1_O_HCRHDESCRIPTORA *(volatile uint32_t *)(USB1_BASE + 0x448) 43 | #define USB1_O_HCRHDESCRIPTORB *(volatile uint32_t *)(USB1_BASE + 0x44C) 44 | #define USB1_O_HCRHSTATUS *(volatile uint32_t *)(USB1_BASE + 0x450) 45 | #define USB1_O_HCRHPORTSTATUS *(volatile uint32_t *)(USB1_BASE + 0x454) 46 | 47 | #define USB1_HCI_ICR *(volatile uint32_t *)(USB1_BASE + 0x800) 48 | #define USB1_HSIC_STATUS *(volatile uint32_t *)(USB1_BASE + 0x804) 49 | #define USB1_HCI_UNK1 *(volatile uint32_t *)(USB1_BASE + 0x810) 50 | 51 | #define USB_PHY_CFG *(volatile uint32_t *)0x01c19410 52 | 53 | struct td { 54 | uint32_t info; 55 | uint32_t cbp; 56 | uint32_t nexttd; 57 | uint32_t bufferend; 58 | } __attribute__ ((aligned (16))); 59 | 60 | struct ed { 61 | uint32_t info; 62 | struct td* tailp; 63 | struct td* headp; 64 | struct ed* nexted; 65 | } __attribute__ ((aligned (16))); 66 | 67 | struct hcca { 68 | uint32_t HccaInterrruptTable[32]; 69 | uint16_t HccaFrameNumber; 70 | uint16_t HccaPad1; 71 | uint32_t HccaDoneHead; 72 | uint8_t reserved[120]; 73 | } __attribute__ ((aligned (256))); 74 | 75 | void usb_init(); 76 | --------------------------------------------------------------------------------