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: UIC
0x01: timer? used for delays
0x02: SDIO
0x03: ???
0x04: ???
0x05: UART
0x06: ??? bootloader listens to it
0x07: ??? bootloader listens to it
0x08: ??? bootloader listens to it
0x09: DMA
0x0A: ???
0x0B: ???
0x0C: ???
0x0D: ???
0x0E: ???
0x0F: I2C
0x10: vcapt/camera
0x11: vcapt/camera
0x12: vout
0x13: ???
0x14: vcapt/camera
0x15: vout
0x16: vout
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): set to 5 when enabling IRQ, 1 when disabling

F00019D8: general IRQ disable??
F00019DC: set to 0


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??

F0000410 (32): bit1 = enable timer
F0000414 (32): timer of sorts (TODO: work out frequency)
F0000418 (32): ??? set to FFFFFFFF

F00013F0 (16): index of IRQ that was triggered
F00013F8 (16): IRQ related, read then written into F00013FC
F00013FC (16): IRQ related, ack??

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?? set to 0x003B0417
F0009464 (32): framebuffer width (854)
F0009468 (32): framebuffer Y offset?? set to 0x01B201FE
F000946C (32): framebuffer height (480)
F0009470 (32): framebuffer stride in pixels (bytes/2 when pixel format is 1)
F0009474 (32): framebuffer address, firmware uses 0x00388400

F0009480 (32): ??? 0x14 cleared, 0x2 set

F00094B0 (32): ??? bit0-2: pixel format: 0=8bit paletted, 1=16bit something, 2=8bit something else?
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


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: mode for F0004410. 0=write, 1=read
bit6: in manual mode, set to 1-then-0 before reading
bit8: ??? 1=Flash???
bit9: set after having read incoming data (and after having cleared bit6 in F0004418)
bit10: ???
?? probably has chipselect bits and other shit

F000440C:
bit0: presumably 1=busy
bit0-4: presumably status. 0x10 after a byte has been transferred.

F0004410: 
bit0-7: data input/output

F0004418:
bit6: set before reading bytes in FIFO mode, cleared afterwards
bit7: set before writing last byte in FIFO mode, cleared after transfer is done

F0004420:
number of bytes to read

F0004424:
??

Noting that SPI can also be accessed by DMA (TODO: work out how, exactly).

SPECULATION
* SPI has an immediate mode (writing a byte transfers it) and a FIFO mode (packing up bytes until told to transfer)...?

todo: work out how to do transfers 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.

0x03: ??
Parameters: 3 bytes AA BB CC. AA=something bit8-15, BB=something bit0-7, CC=0x80. something=0x1100+smth
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

0x13: ??
Parameters: none
Response: 1 byte

0x18: ??
Parameters: none
Response: 1 byte

0x1A: ??
Parameters: none
Response: 0xFF bytes

0x1C: ??
Parameters: none
Response: 4 bytes

0x7F: queries... something
Parameters: none
Response: 1 byte

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...)