Editing Hardware Registers

Jump to navigation Jump to search
Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.

The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.

Latest revision Your text
Line 1: Line 1:
= Introduction =
= Introduction =


With the exception of interrupts, almost all the interaction with the PSP hardware is done through memory mapped IO (MMIO) accesses in the 0xBC000000~0xBFFFFFFF address range. The physical address of this range is actually 0x1C000000~0x1FFFFFFF, but we must OR in the 0x40000000 un-cached flag and the 0x80000000 kernel access flag. Knowing how to communicate with the hardware is vital to understanding the inner workings of the PSP.
On the PSP, except interruptions, almost all the interaction with the hardware is done through memory accesses to "hardware registers" located at the 0xBC000000~0xBFFFFFFF range (actually 0x1C000000~0x1FFFFFFF to which we add the 0x4 uncached flag and the 0x8 kernel flag). Which is the reason why documenting this is vital to understand the PSP hardware.


= 0xA7F00000: L2 cache =
= 0xA7F00000: L2 cache =
Line 451: Line 451:
Bits 6-11 = UART 0-5
Bits 6-11 = UART 0-5


Bits 12-15 = APB (Arm Peripheral Bus) Timer 0-3
Bits 12-15 = APB (?) 0-3


Bits 16-17 = Audio 0-1
Bits 16-17 = Audio 0-1


Bits 18 = LCD Controller
Bits 19-21 = ?


Bits 19 = PWM
Bit 22 = SIRCS (?)
 
Bits 20 = ?
 
Bits 21 = I2C
 
Bit 22 = SIRCS (Sony Serial Infra-Red Control)


Bit 23 = GPIO
Bit 23 = GPIO
Line 498: Line 492:
| 0xBC100064 || 4 || RW || SPI clock select
| 0xBC100064 || 4 || RW || SPI clock select
|-
|-
| 0xBC100068 || 4 || RW || Bits 0-7: PLL frequency
| 0xBC100068 || 4 || RW || 0xF - PLL get/set out select (PLL frequency?)
 
Bits 16-31: unknown, checked against by the iplloader, possibly related to jigkick
|-
|-
| 0xBC100070 || 4 || RW || Set Avc power
| 0xBC100070 || 4 || RW || Set Avc power
Line 506: Line 498:
| 0xBC100074 || 4 || RW || Unknown
| 0xBC100074 || 4 || RW || Unknown
|-
|-
| 0xBC100078 || 4 || RW || I/O enable
| 0xBC100078 || 4 || RW || I/O enable (?) (TODO: verify indices)
 
Bit 1 = EMCSM
 
Bit 2 = USB
 
Bit 3 = ATA
 
Bits 4-5 = MSIF
 
Bit 6 = LCDC


Bits 7-8 = Audio
Bit 0 = NAND


Bit 9 = I2c
Bit 1 = USB


Bit 10 = Sircs
Bit 2 = ATA


Bit 11 = AudioClkout
Bits 3-4 = Memstick Interface


Bit 12 = Key (?)
Bit 5 = LCDC


Bit 13 = PWM
Bit 6-7 = Audio


Bit 14 = ATA HDD
Bit 8 = IIC


Bit 15 = TBD - needs more sysreg reversing
Bit 9 = SIRCS


Bits 16-21 = UART 0-5
Bit 10 = Audio?


Bits 22-23 = TBD - needs more sysreg reversing
Bit 11 = KEY


Bits 24-29 = SPI 0-5
Bit 12 = PWM


Bits 30-31 = TBD - needs more sysreg reversing
Bits 13-18 = UART


Bits 19-24 = SPI
|-
|-
| 0xBC10007C || 4 || RW || Either GPIO pin enable, or GPIO pin direction
| 0xBC10007C || 4 || RW || Either GPIO pin enable, or GPIO pin direction
Line 873: Line 856:
|-
|-
|}
|}
= 0xBC700000: ? =


= 0xBC800000: DMACPlus =
= 0xBC800000: DMACPlus =
Line 1,703: Line 1,688:
| 0xBDE00008 || 4 || RW || Set to 1 on error by the command subroutine
| 0xBDE00008 || 4 || RW || Set to 1 on error by the command subroutine
|-
|-
| 0xBDE0000C || 4 || RW || Set to 1 to start processing, or 2 to start processing phase2
| 0xBDE0000C || 4 || RW || Set to 1 to start processing
|-
|-
| 0xBDE00010 || 4 || RW || KIRK command
| 0xBDE00010 || 4 || RW || KIRK command
Line 1,928: Line 1,913:
|-
|-
| 0xBE0000D0 || 4 || ? || ??
| 0xBE0000D0 || 4 || ? || ??
|-
|}
|}


= 0xBE100000: MagicGate Type-R =
= 0xBE100000: MagicGate hardware for memory stick? =
 
= 0xBE140000: LCDC =


{| class="wikitable"
{| class="wikitable"
Line 1,939: Line 1,927:
! Description
! Description
|-
|-
| 0xBE100000 || ? || ? || Unknown
| 0xBE140000 || 4 || RW || First LCDC controller enable
 
Bits 0-1 = 3 to enable first LCDC controller (tachyon version < 0x800000; otherwise it's set to 0)
|-
|-
| 0xBE100010 || ? || ? || ?Key size (in bits)?. ex: 0x100 (hardcoded)
| 0xBE140004 || 4 || RW || Synchronization difference: (xsync / zoom) - ysync
|-
|-
| 0xBE100020 || ? || ? || Unknown
| 0xBE140008 || 4 || RW || Unknown (fourth argument of sceLcdcCheckMode and sceLcdcSetMode)
|-
|-
| 0xBE100038 || ? || ? || Hardware version 1
| 0xBE140010 || 4 || RW || X back porch
|-
|-
| 0xBE100040 || 0x10 || ? || Key
| 0xBE140014 || 4 || RW || X sync width
|-
|-
| 0xBE100050 || 8 || ? || Unknown
| 0xBE140018 || 4 || RW || X front porch
|-
|-
| 0xBE100060 || 0x10 || ? || IV
| 0xBE14001C || 4 || RW || X resolution
|-
|-
| 0xBE100080 || ? || ? || Control
| 0xBE140020 || 4 || RW || Y back porch
|-
|-
| 0xBE100084 || ? || ? || Status
| 0xBE140024 || 4 || RW || Y sync width
|-
|-
| 0xBE100088 || ? || ? || Algorithm
| 0xBE140028 || 4 || RW || Y front porch
|-
|-
| 0xBE100090 || ? || ? || Unknown. Value at bit 8 is used.
| 0xBE14002C || 4 || RW || Y resolution
|-
|-
| 0xBE100094 || ? || ? || Size
| 0xBE140030 || 4 || R || HPC (?), returned by sceLcdcReadHPC()
|-
|-
| 0xBE100098 || ? || ? || Hardware version 2
| 0xBE140034 || 4 || R || VPC (?), returned by sceLcdcReadVPC()
|-
|-
| 0xBE1000A0 || ?0x800? || ? || Input buffer
| 0xBE140040 || 4 || RW || Y shift (between hardware & software resolution)
|}
|-
| 0xBE140044 || 4 || RW || X shift (between hardware & software resolution)
|-
| 0xBE140048 || 4 || RW || Scaled X resolution
|-
| 0xBE14004C || 4 || RW || Scaled Y resolution (same as the physical Y resolution)
|-
| 0xBE140050 || 4 || RW || Unknown, set to 1, maybe used by sceLcdcReadUnderflow (to be verified)
|-
| 0xBE140070 || 4 || W || Set to 1 when running sceLcdcResume() or sceLcdcInit() on tachyon version >= 0x5000000
|-
|}


= 0xBE140000: LCDC =
The exact same registers are at 0xBE1401.., these ones being used for tachyon version >= 0x8000000 (PSP Go?). <br>
These registers are only set on tachyo version >= 0x8000000:


{| class="wikitable"
{| class="wikitable"
Line 1,977: Line 1,979:
! Description
! Description
|-
|-
| 0xBE140000 || 4 || RW || First LCDC controller enable
| 0xBE140180 || 4 || RW || Always set to 1 when 0xBE140184 - 0xBE140198 are used
 
Bits 0-1 = 3 to enable first LCDC controller (tachyon version < 0x800000; otherwise it's set to 0)
|-
|-
| 0xBE140004 || 4 || RW || Synchronization difference: (xsync / zoom) - ysync
| 0xBE140184 || 4 || RW || Scaled X resolution (read instead of the (real) X resolution above when enabled)
|-
|-
| 0xBE140008 || 4 || RW || Unknown (fourth argument of sceLcdcCheckMode and sceLcdcSetMode)
| 0xBE140188 || 4 || RW || Y resolution (read instead of the (real) Y resolution above when enabled)
|-
|-
| 0xBE140010 || 4 || RW || X back porch
| 0xBE14018C || 4 || RW || Unknown (0x580 - 0x678)
|-
|-
| 0xBE140014 || 4 || RW || X sync width
| 0xBE140190 || 4 || RW || Unknown (0x4C4 - 0x71C)
|-
|-
| 0xBE140018 || 4 || RW || X front porch
| 0xBE140194 || 4 || RW || Unknown (0xAFC - 0xCEC)
|-
|-
| 0xBE14001C || 4 || RW || X resolution
| 0xBE140198 || 4 || RW || Unknown (0x910 - 0xE38)
|-
|-
| 0xBE140020 || 4 || RW || Y back porch
| 0xBE1401A0 || 4 || RW || Display flags?
|-
|-
| 0xBE140024 || 4 || RW || Y sync width
| 0xBE1401B0 || 4 || RW || Display clock?
|-
|-
| 0xBE140028 || 4 || RW || Y front porch
| 0xBE140200 || 4 || W || Set to 1 on initialization
|-
| 0xBE14002C || 4 || RW || Y resolution
|-
| 0xBE140030 || 4 || R || HPC (?), returned by sceLcdcReadHPC()
|-
| 0xBE140034 || 4 || R || VPC (?), returned by sceLcdcReadVPC()
|-
| 0xBE140040 || 4 || RW || Y shift (between hardware & software resolution)
|-
| 0xBE140044 || 4 || RW || X shift (between hardware & software resolution)
|-
| 0xBE140048 || 4 || RW || Scaled X resolution
|-
| 0xBE14004C || 4 || RW || Scaled Y resolution (same as the physical Y resolution)
|-
| 0xBE140050 || 4 || RW || Unknown, set to 1, maybe used by sceLcdcReadUnderflow (to be verified)
|-
| 0xBE140070 || 4 || W || Set to 1 when running sceLcdcResume() or sceLcdcInit() on tachyon version >= 0x5000000
|-
|-
|}
|}


The exact same registers are at 0xBE1401.., these ones being used for tachyon version >= 0x8000000 (PSP Go?). <br>
= 0xBE200000: I2c =
These registers are only set on tachyo version >= 0x8000000:
 


{| class="wikitable"
{| class="wikitable"
Line 2,029: Line 2,011:
! Description
! Description
|-
|-
| 0xBE140180 || 4 || RW || Always set to 1 when 0xBE140184 - 0xBE140198 are used
| 0xBE200000 || 4 || R? || Unknown
|-
|-
| 0xBE140184 || 4 || RW || Scaled X resolution (read instead of the (real) X resolution above when enabled)
| 0xBE200004 || 4 || RW || Command
 
Value 0x85 = unknown (used after writing the transmit data)
 
Value 0x8A = receive data
 
Value 0x87 = unknown (used after writing the transmit data)
 
|-
|-
| 0xBE140188 || 4 || RW || Y resolution (read instead of the (real) Y resolution above when enabled)
| 0xBE200008 || 4 || RW || Data length
|-
|-
| 0xBE14018C || 4 || RW || Unknown (0x580 - 0x678)
| 0xBE20000C || 4 || R? || Read/write data
|-
|-
| 0xBE140190 || 4 || RW || Unknown (0x4C4 - 0x71C)
| 0xBE200010 || 4 || RW || Unknown
|-
|-
| 0xBE140194 || 4 || RW || Unknown (0xAFC - 0xCEC)
| 0xBE200014 || 4 || RW || Unknown
|-
|-
| 0xBE140198 || 4 || RW || Unknown (0x910 - 0xE38)
| 0xBE20001C || 4 || RW || Unknown
|-
|-
| 0xBE1401A0 || 4 || RW || Display flags?
| 0xBE200028 || 4 || R? || Clear/read interrupt
|-
|-
| 0xBE1401B0 || 4 || RW || Display clock?
| 0xBE20002C || 4 || W? || Unknown
|-
| 0xBE140200 || 4 || W || Set to 1 on initialization
|-
|-
|}
|}


= 0xBE200000: I2c =
= 0xBE240000: GPIO =
 


{| class="wikitable"
{| class="wikitable"
Line 2,061: Line 2,047:
! Description
! Description
|-
|-
| 0xBE200000 || 4 || R? || Unknown
| 0xBE240000 || 4 || RW || Is output (?)
|-
| 0xBE240004 || 4 || R || GPIO read pin (1 bit = 1 pin)
|-
|-
| 0xBE200004 || 4 || RW || Command
| 0xBE240008 || 4 || W || GPIO set pin (1 bit = 1 pin)
 
|-
Value 0x85 = unknown (used after writing the transmit data)
| 0xBE24000C || 4 || W|| GPIO clear pin (1 bit = 1 pin)
 
|-
Value 0x8A = receive data
| 0xBE240010 || 4 || RW || Is edge detection (?)
 
|-
Value 0x87 = unknown (used after writing the transmit data)
| 0xBE240014 || 4 || RW || Is falling edge (?)
 
|-
| 0xBE240018 || 4 || RW || Is rising edge (?)
|-
|-
| 0xBE200008 || 4 || RW || Data length
| 0xBE24001C || 4 || RW || Is interrupt enabled
|-
|-
| 0xBE20000C || 4 || R? || Read/write data
| 0xBE240020 || 4 || R? || Is interrupt triggered
|-
|-
| 0xBE200010 || 4 || RW || Unknown
| 0xBE240024 || 4 || W || Acknowledge interrupt
|-
|-
| 0xBE200014 || 4 || RW || Unknown
| 0xBE240030 || 4 || RW || Is capture port (?)
|-
|-
| 0xBE20001C || 4 || RW || Unknown
| 0xBD240034 || 4 || RW || Is timer capture enabled (?)
|-
|-
| 0xBE200028 || 4 || R? || Clear/read interrupt
| 0xBE240040 || 4 || RW || Is input on (?)
|-
|-
| 0xBE20002C || 4 || W? || Unknown
| 0xBE240048 || 4 || W? || Unknown
|-
|-
|}
|}


= 0xBE240000: GPIO =
= 0xBE300000: Power management? =


{| class="wikitable"
Seems to be composed of 3 controllers, each of size 0x20.
|-
 
= 0xBE4C0000 & 0xBE500000: UART =
 
There are two similar UART controllers:
* At 0xBE4C0000: UART4 = ?
* At 0xBE500000: UART3 = Headphone/remote SIO
 
There is also possibly an infrared controller at 0xBE540000.
 
UART port numbers vary depending on documentations.
 
Some documentations seem to argue that there are 8 controllers for 0xBE40 to 0xBE5C, but the syscon interface looks very different so it might not be the case.
 
{| class="wikitable"
|-
! Address
! Address
! Size
! Size
Line 2,097: Line 2,100:
! Description
! Description
|-
|-
| 0xBE240000 || 4 || RW || Is output (?)
| 0xBExx0000 || 4 || RW || Read/write FIFO of the UART port
 
Bits 0-7 = data
 
Writing writes a byte to the Tx buffer and advances the write position.
Reading reads a byte from the Rx buffer and advances the read position.
The FIFO is 32(?) bytes long.
|-
|-
| 0xBE240004 || 4 || R || GPIO read pin (1 bit = 1 pin)
| 0xBExx0004 || 4 || RW || Unknown
|-
|-
| 0xBE240008 || 4 || W || GPIO set pin (1 bit = 1 pin)
| 0xBExx0018 || 4 || RW || Port status
 
Bit 4 = Rx buffer status is empty
 
Bit 5 = Tx buffer status is full
|-
|-
| 0xBE24000C || 4 || W|| GPIO clear pin (1 bit = 1 pin)
| 0xBExx0024 || 4 || W || Upper bits of baudrate divisor, ie (96000000 / baudrate) >> 6
|-
|-
| 0xBE240010 || 4 || RW || Is edge detection (?)
| 0xBExx0028 || 4 || W || Lower bits of baudrate divisor, ie (96000000 / baudrate) & 0x3f
|-
|-
| 0xBE240014 || 4 || RW || Is falling edge (?)
| 0xBExx002C || 4 || RW || Set bits 5-6 to set the baud rate?
|-
|-
| 0xBE240018 || 4 || RW || Is rising edge (?)
| 0xBExx0030 || 4 || RW || Unknown
|-
|-
| 0xBE24001C || 4 || RW || Interrupt enable
| 0xBExx0034 || 4 || RW || Unknown
|-
|-
| 0xBE240020 || 4 || R? || Interrupt Status
| 0xBExx0038 || 4 || RW || Unknown
|-
|-
| 0xBE240024 || 4 || W || Acknowledge interrupt
| 0xBExx0044 || 4 || RW || Clear interrupt?
|-
|-
| 0xBE240030 || 4 || RW || Capture port enable
|}
 
= 0xBE580000: Syscon =
 
{| class="wikitable"
|-
|-
| 0xBD240034 || 4 || RW || Timer capture enable
! Address
! Size
! Read/write
! Description
|-
|-
| 0xBE240040 || 4 || RW || Is input on (?)
| 0xBE580000 || 4 || W? || Unknown (0xCF is written there at initialization time)
|-
|-
| 0xBE240048 || 4 || W? || Unknown
| 0xBE580004 || 4 || RW || Flags
|-
|}


= 0xBE300000: Power management? =
Bit 1 = start syscon command


Seems to be composed of 3 controllers, each of size 0x20.
Bit 2 = reset data index
 
= 0xBE4C0000 & 0xBE500000: UART =
 
[https://developer.arm.com/documentation/ddi0183/f/programmer-s-model/summary-of-registers?lang=en ARM PrimeCell UART PL011]
 
There are two similar UART controllers:
* At 0xBE4C0000: UART4 = ?
* At 0xBE500000: UART3 = Headphone/remote SIO
 
There is also possibly an infrared controller at 0xBE540000.
 
UART port numbers vary depending on documentations.
 
Some documentations seem to argue that there are 8 controllers for 0xBE40 to 0xBE5C, but the syscon interface looks very different so it might not be the case.
 
{| class="wikitable"
|-
! Address
! Size
! Read/write
! Description
|-
| 0xBExx0000 || 4 || RW || Read/write FIFO of the UART port
 
Bits 0-7 = data
 
Writing writes a byte to the Tx buffer and advances the write position.
Reading reads a byte from the Rx buffer and advances the read position.
The FIFO is 32(?) bytes long.
|-
| 0xBExx0004 || 4 || RW || Unknown
|-
| 0xBExx0018 || 4 || RW || Port status
 
Bit 4 = Rx buffer status is empty
 
Bit 5 = Tx buffer status is full
|-
| 0xBExx0024 || 4 || W || Upper bits of baudrate divisor, ie (96000000 / baudrate) >> 6
|-
| 0xBExx0028 || 4 || W || Lower bits of baudrate divisor, ie (96000000 / baudrate) & 0x3f
|-
| 0xBExx002C || 4 || RW || Set bits 5-6 to set the baud rate?
|-
| 0xBExx0030 || 4 || RW || Unknown
|-
| 0xBExx0034 || 4 || RW || Unknown
|-
| 0xBExx0038 || 4 || RW || Unknown
|-
| 0xBExx0044 || 4 || RW || Clear interrupt?
|-
|}
 
= 0xBE580000: Syscon =
[https://developer.arm.com/documentation/ddi0194/h/programmer-s-model/summary-of-primecell-ssp-registers?lang=en ARM PrimeCell Synchronous Serial port PL022]
 
TODO: validate register mappings
 
{| class="wikitable"
|-
! Address
! Size
! Read/write
! Description
|-
| 0xBE580000 || 4 || W? || Unknown (0xCF is written there at initialization time)
|-
| 0xBE580004 || 4 || RW || Flags
 
Bit 1 = start syscon command
 
Bit 2 = reset data index


Bit 3 = in progress?
Bit 3 = in progress?
Line 2,218: Line 2,163:
| 0xBE580014 || 4 || W? || Unknown (0 is written there)
| 0xBE580014 || 4 || W? || Unknown (0 is written there)
|-
|-
| 0xBE580018 || 4 || R? || Unknown
| 0xBE580018 || 4 || R? || Unknown
|-
| 0xBE580020 || 4 || W? || Unknown; clear error status?
|-
| 0xBE580024 || 4 || W? || Unknown (0 is written there)
|-
|}
 
= 0xBE5C0000: LCD controller (Slim) =
 
{| class="wikitable"
|-
! Address
! Size
! Read/write
! Description
|-
| 0xBE5C0000 || 4 || W? || Unknown
|-
| 0xBE5C0004 || 4 || W? || Unknown
|-
| 0xBE5C0008 || 4 || RW? || Unknown
|-
| 0xBE5C000C || 4 || R? || Unknown
|-
| 0xBE5C0010 || 4 || W? || Unknown
|-
| 0xBE5C0014 || 4 || W? || Unknown
|-
| 0xBE5C0024 || 4 || W? || Unknown
|-
|-
|}
| 0xBE580020 || 4 || W? || Unknown; clear error status?
 
= 0xBE740000: Display =
 
{| class="wikitable"
|-
|-
! Address
| 0xBE580024 || 4 || W? || Unknown (0 is written there)
! Size
! Read/write
! Description
|-
| 0xBE740000 || 4 || W? || Unknown
|-
| 0xBE740004 || 4 || RW || Get/set row sync (?)
|-
| 0xBE740008 || 4 || R? || Get sync (?)
|-
| 0xBE74000C || 4 || W? || Unknown
|-
| 0xBE740010 || 4 || W? || Unknown
|-
| 0xBE740014 || 4 || W? || Unknown
|-
| 0xBE740020 || 4 || R? || Unknown
|-
| 0xBE740024 || 4 || W? || Unknown
|-
|-
|}
|}


= 0xBE780000: Display (Slim) =
= 0xBE5C0000: LCD controller (Slim) =
 
{| class="wikitable"
|-
! Address
! Size
! Read/write
! Description
|-
| 0xBE780000 || 4 || ? || Unknown
|-
| 0xBE78001C || 4 || ? || Unknown
|}
 
= 0xBFC00000 & 0xBFD00000 & 0xBFE00000: MIPS Reset Vector and RAM =


Note this is not a hardware register *per se*.
= 0xBE600000: ? =


At boot time, the PSP [[iplloader]] is mapped to read-only 0xBFC00000 then executed. An additional 4096-byte scratchpad-like RAM is accessible at 0xBFD00000 and used as a temporary space to decrypt the IPL blocks.
= 0xBE700000: Display =
Then, once the CPU is reset (0xBC10004C |= 2), the iplloader is unmapped, and the memory which was then at 0xBFD00000 is now mapped at 0xBFC00000 and execution restarts at 0xBFC00000.


On devkit, bloadp is copied to 0xBFE00000 then executed. IPL blocks are usually copied to 0xBFE01000, decrypted in place then executed.
= 0xBFC00000: MIPS Reset Vector =


= 0xBFF00000: NAND DMA buffer =
= 0xBFF00000: NAND DMA buffer =
Line 2,320: Line 2,198:
= References =
= References =


* [http://daifukkat.su/docs/psptek/ PSPTEK]
* [http://daifukkat.su/docs/psptek/ PSPTEK] (done)
* [https://gigawiz.github.io/yapspd/html_chapters_split/chap8.html yapspd]
* [https://gigawiz.github.io/yapspd/html_chapters_split/chap8.html yapspd] (done)
* [https://github.com/uofw/uofw uOFW]
* [https://github.com/uofw/uofw uOFW] (todo: some more info to grab in some modules)
* [https://github.com/jpcsp/jpcsp Jpcsp]
* [https://github.com/jpcsp/jpcsp Jpcsp] (todo: contains a lot of stuff)
Please note that all contributions to PSP Developer wiki are considered to be released under the GNU Free Documentation License 1.2 (see PSP Developer wiki:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!

To protect the wiki against automated edit spam, we kindly ask you to solve the following hCaptcha:

Cancel Editing help (opens in new window)