WiiU gamepad documentation
Table of contents
Credits
* libdrc docs, helped me get started
* STM8 documentations, too
SVC
SVC are specific to the firmware and not tied to hardware.
0: enable IRQ
1: disable IRQ
11: assert fail, debug crap?? triggers error screen on retail units
IRQ
used by bootloader: 0, 1, 6, 7, 8, 9
0x00: timer 0 (UIC related?)
0x01: timer 1
0x02: SDIO
0x03: ???
0x04: ???
0x05: UART
0x06: SPI related
0x07: SPI related
0x08: DMA0
0x09: DMA1 (and others? DMA2?)
0x0A: ???
0x0B: ???
0x0C: ???
0x0D: DMA3??
0x0E: DMA4??
0x0F: I2C
0x10: vcapt/camera
0x11: vcapt/camera
0x12: vout
0x13: ???
0x14: vcapt/camera
0x15: VBlank end
0x16: VBlank start
0x17: aout/audio
0x18: acapt/microphone
0x19: ???
0x1A: ???
0x1B: ???
0x1C: ???
0x1D: vcapt/camera
0x1E: acapt/microphone
0x1F: ???
0x20: ????
0x21: ????
0x22: ????
0x23: ????
0x24: ????
0x25: ????
0x26: ????
0x27: ????
F0001208+(n*4): IRQ enable for IRQ n -- bit6 = disable?? bit0-3: set to 0xE except for 20-27??
F0001420+(n*4): 5 or 1, related to the way the IRQ triggers
F00013F0 (16): index of IRQ that was triggered
F00013F8 (16): IRQ related, read then written into F00013FC
F00013FC (16): IRQ related, ack??
F00019D8: general IRQ disable??
F00019DC: set to 0
Memory map
F0001xxx: IRQ controller
F00040xx: DMA
F00044xx: SPI
F00058xx: I2C
Registers
F0000000 (32): hardware type
if value is 0x41:
* GPIO flags 0x8000 and 0x4000 are swapped
* I2C controller is Samsung and not Renesas
* video decoder/output hardware also seems different
F0000408: another timer??
F0004000 (32): DMA control reg? init: 0x8001 set, 0xFC cleared
F0004400: SPI
F0004C80: UART
F0005800: I2C
F0009400 (32): 0x003B0417
F0009404 (32): 0x01B201FE
F0009408 (32): 0x00000020
F000940C (32): 0x00000008
F0009410 (32): 0x00000060
F0009414 (32): 0x00000008
F0009418 (32): 0x000003B6
F000941C (32): 0x000001E8
F0009420 (32): 0x00000060
F0009424 (32): 0x00000356
F0009428 (32): 0x00000008
F0009460 (32): framebuffer X offset (96)
F0009464 (32): framebuffer width (854)
F0009468 (32): framebuffer Y offset (8)
F000946C (32): framebuffer height (480)
F0009470 (32): framebuffer stride in bytes
F0009474 (32): framebuffer address, firmware uses 0x00388400
F0009480 (32): display control reg of sorts. bits 1 and 4 must be set for display to work. bit 0 breaks display. bit 4 adds some weird offset (YUV mode?).
F00094B0 (32): bit0-1: pixel format
0: 8bit paletted
1: 4bit paletted
2: 16bit direct color -- RGB555 (xRRRRRGGGGGBBBBB)
3: 16bit direct color -- RGB565 (RRRRRGGGGGGBBBBB)
F00094B4 (32): ??? bit0-15 cleared when setting up framebuffer
F0009500: palette write position
F0009504: write here to set a palette entry. palette write position automatically advanced.
F0009508: ?? 8 + something
F000950C: ?? 0xB2 + something
F0009510: ?? 0x15C + something
F0009514: ?? 0x7FF + something
Timers
F0000410: timer 0
F0000420: timer 1
base+00 (32): timer control register
bit0: enable?
bit1: enable but different?
bit4-6: prescaler?
base+04 (32): timer value?
base+08 (32): timer reload value? set to desired interval minus one
LCD
Initialization:
1. Configure GPIO0 as an output. Register value: 0xC200
2. Set GPIO0 to 0
3. Set GPIO0 to 1
4. Send data to the LCD I2C device: bus 3, device 0x39
4.1. write B0 02
4.2. write BF
4.3. read 5 bytes, first 4 are the device identifier
4.4. write B0 03
LCD device identifiers: 0x00000002=Panasonic, 0x08922201=JDI
Initialization for Panasonic LCD:
4.5. write 05 00 00 01 7A
Initialization for JDI LCD:
4.5. write B0 02
4.6. write BB 08 7A 01 00
4.7. write B0 03
Color format: 8bpp paletted. Palette is placed just before the framebuffer and is 1024 bytes (256 colors, 32bit ABGR).
(firmware places the palette before the framebuffer, but it's supposed to be written by using F0009500/F0009504)
Maybe other color formats are possible. The firmware has code for conditionally doubling coordinates and sizes when doing DMA.
Audio
F0005400: audio output
F0005480: audio capture
F00054C0: audio capture
F0005400: ?? status??
F0005404: ?? status??
F0005408: buffer address. must be aligned to a 16-byte boundary.
F000540C: buffer end address
F0005410: ?? current playback address?
F0005414: ????
F0005418: ????
F000541C: ??
F0005420: ?? bit0=something. bit2=something.
F0005424: ?? something >> 3
F0005428: ??
F000542C: ?? set to 0 during init. bit3=something. bit2=something.
F0005430: ??
F0005434: ??
DMA
DMA0: F0004040
DMA1: N/A
DMA2: F0004100
DMA3: F0004140
DMA4: F0004180
DMA0 is... different.
DMA0:
SPI DMA:
F0004040 (32): set bit0 then write 2 to start???
F0004044 (32): control reg?? bit0: direction, probably 1=write. direction. bit1-3: ???
F0004048 (32): ?? set to 0
F000404C (32): ?? set to 0
F0004050 (32): remaining byte count minus one (write total size to copy minus one)
F0004054 (32): source/destination address
IR DMA:
F0004060 to F0004074. same as for SPI DMA.
DMA2/3/4:
base+00 (32): set bit0 then write 2 to start???
base+04 (32): set to 0x430 or 0x470
base+08 (32): chunk size
base+0C (32): stride between each chunk start in the source buffer
base+10 (32): stride between each chunk start in the destination buffer
base+14 (32): remaining byte count minus one (write total size to copy minus one)
base+18 (32): source address
base+1C (32): destination address
base+20 (32): ??? between 0 and 0xFF
base+24 (32): ??? same
GPIO
mostly copypasta from the libdrc docs, thanks there
F0005100: GPIO0, LCD related (LCD enable?)
F0005108: GPIO1, unused
F000510C: GPIO2, NFC related
F0005110: GPIP3, NFC related
F0005114: GPIO4, rumble
F0005118: GPIO5, "sensor bar power", whatever that is
F000511C: GPIO6, camera related
F0005098: GPIO7, unused
note: there are gaps between the addresses there, check if there are more GPIOs hiding there, namely:
* F000509C to F00050FC
* F0005104
GPIO register format:
bit0: ???
bit8: output value
bit9: 1=output
bit10: input value
bit11: 1=input
bit12: ???
bit13: ???
bit14: ???
bit15: ???
note: bit14 and bit15 are swapped on the Samsung controller (see register F0000000).
todo: what happens if bit9 and bit11 are set/cleared together?
todo: check if that shit can be set to trigger IRQs
SPI
F0004400:
SPI control reg of sorts?
F0004404:
bit1: transfer direction; 0=write, 1=read
bit6: ??? set to 1-then-0 before reading from the UIC
bit8: device; 0=UIC, 1=Flash
bit9: chipselect; 0=selected, 1=released
bit10: ??? gets set when write FIFO goes empty?
F0004408:
IRQ flags -- writing a 1 acknowledges the IRQ flag
bit6: read IRQ (read operation finished)
bit7: write IRQ (write operation finished)
F000440C:
bit0-4: maybe free space in write FIFO? 0x10 after a write has completed
bit8-12: number of bytes in read FIFO
F0004410:
bit0-7: data input/output
F0004418:
bit6: enable read IRQ
bit7: enable write IRQ
F0004420:
number of bytes to read
F0004424:
??
Noting that SPI can also be accessed by DMA (TODO: work out how, exactly).
documentation for the SPI Flash memory
I2C
03/39: LCD
03/21: CMOS camera
03/18: audio amp
F0005800 (32): works the same as F0005804??
F0005804 (32): transfer start register. set bit1 to transfer unit 1, bit2 to transfer unit 2, etc...
RENESAS I2C
Registers: F0005C00 (1), F0006000 (2), F0006400 (3), F0006800 (4)
base+004 (32): device address << 1. data is also written here or read from here.
base+008 (32): OR'd with 0x18. also OR'd with 2 when waiting...? or 1?
base+020 (32): bit6 = something (error?) bit7 = error? too
base+104 (32): ??? set to 4 when writing. bit0-1 set when reading.
base+108 (32): ??? set to 4 when writing. set to 3 when reading.
base+138 (32): ????????? buf[0] + 0x100
base+13C (32): ????????? buf[1] + 0x100 (if len>=2)
Procedure to read data:
1. base+008 |= 0x18
2. F0005804 |= 1 << unit
3. if bit6 in base+020 is cleared: base+008 |= 0x2
4. if bit6 or bit7 in base+020 is set:
4.1. (sync primitives)
4.2. if bit6 in base+020 is set: error
4.3. base+008 |= 0x2
4.4. if bit7 in base+020 is set: error
5. base+004 = (device << 1) | 1
6. (sync primitive)
7. (sync primitive)
8. base+008 &= ~0x8; base+008 |= 0x4;
9. base+008 |= 0x20
10. wait till bit5 in base+008 is cleared
11. (sync primitive)
12. (sync primitive)
13. read byte from base+004, store it
14. if transfer not finished, go to 9
15. base+008 &= ~0x4
16. base+008 &= ~0x4; base+008 |= 0x28;
17. wait till bit5 in base+008 is cleared
18. (sync primitive)
19. (sync primitive)
20. F0005804 |= 1 << unit if not already set
21. base+008 |= 0x1
22. (sync primitive)
23. (sync primitive)
24. F0005804 = what it was before
25. F0005804 &= ~(1 << unit)
Procedure to write data:
1. base+008 |= 0x18
2. F0005804 |= 1 << unit
3. if bit6 in base+020 is cleared: base+008 |= 0x2
4. if bit6 or bit7 in base+020 is set:
4.1. (sync primitives)
4.2. if bit6 in base+020 is set: error
4.3. base+008 |= 0x2
4.4. if bit7 in base+020 is set: error
5. base+004 = (device << 1)
6. (sync primitive)
7. (sync primitive)
8. write byte into base+004
9. if transfer not finished, go to 7
10. (sync primitive)
11. (sync primitive)
12. if base+018 has bit2 set -> error??
(this part not done if a read is going to follow the write??)
13. F0005804 |= 1 << unit if not already set
14. base+008 |= 0x1
15. (sync primitive)
16. (sync primitive)
17. F0005804 = what it was before
18. F0005804 &= ~(1 << unit)
SAMSUNG I2C
Registers: F0005C00 (1), F0006000 (2), F0006400 (3), F0006800 (4)
base+000 (32): bit4 cleared and bit8 set when starting a transfer
base+004 (32): set to 0x10 or 0x30, then 0x33 or 0x32 after writing device addr. bit0 = transfer/busy?
base+00C (32): device address << 1. data read/written here.
base+010 (32): set to 4 during a transfer, 1 at the end
Procedure to read data:
1. F0005804 |= 1 << unit
2. base+004 = 0x10
3. base+00C = device << 1
4. base+004 = 0x32 (or 0x33?)
5. base+000 &= ~0x10; base+000 |= 0x100;
6. (sync primitive)
7. if (this is the last byte) base+010 = 0x4
8. base+000 &= ~0x10; base+000 |= 0x100;
9. (sync primitive)
10. (sync primitive)
11. read byte from base+00C, store it
12. if transfer not finished, go to 7
13.
14. SamsungDelay(0xDE8) (reading F0005804 each iteration, num iterations = (n+0x59)/0x5A)
15. base+010 = 0x1
16. base+000 &= ~0x10; base+000 |= 0x100;
17. SamsungDelay(0x6D6)
18. base+004 = 0x32 (or 0x33?)
19. SamsungDelay(0x514)
20. F0005804 &= ~(1 << unit)
Procedure to write data:
1. F0005804 |= 1 << unit
2. base+004 = 0x10
3. base+00C = device << 1
4. base+004 = 0x32 (or 0x33?)
5. base+000 &= ~0x10; base+000 |= 0x100;
6.
7. (sync primitive)
8. if base+004 has bit0 set: error
9. (sync primitive)
10. write byte into base+00C
11. SamsungDelay(0x7D0)
12. base+000 &= ~0x10; base+000 |= 0x100;
13. if transfer not finished, go to 7
14. (sync primitive)
15. (sync primitive)
16. if base+004 has bit0 set: R6=0xC (more transfers can follow??)
(this part not done if a read is going to follow the write??)
17. SamsungDelay(0xDE8) (reading F0005804 each iteration, num iterations = (n+0x59)/0x5A)
18. base+010 = 0x1
19. base+000 &= ~0x10; base+000 |= 0x100;
20. SamsungDelay(0x6D6)
21. base+004 = 0x32 (or 0x33?)
22. SamsungDelay(0x514)
23. F0005804 &= ~(1 << unit)
UIC
UIC initialization by firmware
UIC code (UMI_ blob) is loaded at 0x9000 in UIC memory space.
Code upload process:
1. F0004400 = 0x83F8
2. Write 00 FF to the UIC (via SPI)
3. Keep reading one byte from the UIC, until the byte isn't 0. A value of 0x79 is 'good'.
4. Read 7 bytes from the UIC
5. F0004400 = 0x83F8
6. Write 31 CE, wait for reply (not 00). Response must be 0x79.
7. Write AA BB CC DD EE:
AA = address bit 24-31
BB = address bit 16-23
CC = address bit 8-15
DD = address bit 0-7
EE = AA ^ BB ^ CC ^ DD
(address is UIC-side address)
then wait for response 0x79 as usual
8. Write AA, where AA = size of transfer (max 0x80). Wait for response.
9. Write the data, followed by one byte AA, where AA = size of transfer XORed to each byte of the data. Wait for response.
(if response isn't 0x79, it just retries instead of outright failing)
10. if transfer not finished, go to 5
11. Write 21 DE, wait for reply!=0x79. Reply must be 0x51.
12. F0004400 = 0x8018
UIC commands
Commands sent via SPI.
0x02: write UIC memory
Parameters: 3 bytes AA BB CC. AA=address bit8-15, BB=address bit0-7, CC=length. Address must be within range 0x1100..0x17FF.
Then bytes to be written to memory.
Response: none
0x03: read UIC memory
Parameters: 3 bytes AA BB CC. AA=address bit8-15, BB=address bit0-7, CC=length. Address must be within range 0x1100..0x17FF.
Response: 0x80 bytes
0x05: queries device on expansion port
Parameters: none
Response: 1 byte. 07=debugger
0x07: queries input data
Parameters: none
Response: 0x80 bytes. see libdrc docs for data format.
0x0A: ??
Parameters: none
Response: 6 bytes
0x0B: ??
Parameters: none
Response: 4 bytes
0x0F: ??
Parameters: none
Response: 2 bytes
0x10: ??
Parameters: none
Response: 1 byte
0x12: toggles backlight
Parameters: 1 byte. 0=off 1=on
Response: none
0x13: ??
Parameters: none
Response: 1 byte
0x15: reboot
Parameters: none
Response: none
0x18: ??
Parameters: none
Response: 1 byte
0x1A: ??
Parameters: none
Response: 0xFF bytes
0x1C: ??
Parameters: none
Response: 4 bytes
0x7F: queries UIC firmware version or smth
Parameters: none
Response: 1 byte, 0x3C or 0x2C?
UIC internals
I may add some details about the UIC internals, but there are very good STM8 docs that cover the UIC well:
* STM8 programmer manual, covers the processor (instruction set, registers, etc...)
* STM8 register map, addresses of I/O registers, memory map...
* STM8 hardware reference, covers the extra hardware (I2C, SPI, etc...)