# VisionFive/JH7100 ideas ## Pseudocode conventions (Who knows, might need them) - Memory ranges: `start_addr + size`, e.g. `0x2000_0000 + 256MiB` - Bit ranges: `[end:start]`, both inclusive. - Data addresses: `type[addr]`, e.g. `uint32_t[0x1185_81a0]` ## Boot process Generally in this order: - Boot ROM (Mask ROM `0x18400000`, no source code) - [secondBoot] (SPI flash offset `0x00_0000` to intRAM0 `0x1800_0000`) - [ddrinit] (SPI flash offset `0x01_0000` to intRAM1 `0x1808_0000`) - OpenSBI + [u-boot] (SPI flash offset `0x04_0000` to DDR `0x8000_0000`) - payload, mostly [Linux](https://github.com/starfive-tech/linux) (Usually on storage such as SD card or USB drive, or network) [secondBoot]: https://github.com/starfive-tech/JH7100_secondBoot [ddrinit]: https://github.com/starfive-tech/JH7100_ddrinit [u-boot]: https://github.com/starfive-tech/u-boot There are various 'secret' register definitions in the vendor source code. I've collected some of them in [this gist][undoc-regs]. [undoc-regs]: https://gist.github.com/dramforever/5679d55c3e94e75bdabb804f9efb0a63 ### Boot ROM You can just dump the code and put it into Ghidra or something. Based on [ddrinit], or at least very similar. Unused code in ddrinit can be found in the Boot ROM. On the VisionFive board. - `SCFG_boot_mode = 0` - `PAD_GPIO[61:60] = 0` (Set with resistors) - `PAD_GPIO[62] = 'BOOT MODE' button` (Held is `1`) - `PAD_GPIO[63] = 1` (Set with resistors) Boot always goes to ROM, which is `0x1184_0000 + 32KiB` #### Not hart 0 - `wfi` (Expecting MSI from CLINT) - Reads `uint32_t[0x1801_fffc]` - Jumps to that address #### Hart 0 - `gpio_init()` (Commented out code in ddrinit) - `uart_init(3)` (9600 baud at 'DEBUG' port) - If button held: `boot_from_uart()` - Otherwise: `boot_from_spi(1)`, loads secondBoot ### secondBoot - Sets up clocks - Sets [`io_padshare_sel = 6`](#IO-pad-configuration) - Resets a few things ### ddrinit #### DRAM Controller The controller is an [OpenEdges OMC (ORBIT Memory Controller)](https://www.openedges.com/memorycontroller). The following information is copied from the website. ##### DRAM Support - JEDEC compliant LPDDR5x/5/4x/4/3, DDR4/3, GDDR6, HBM3 support - Up to 4 ranks/channel (configurable) ##### High Performance - Proprietary out-of-order scheduling algorithm​ - Dual-PHY control for 2x DRAM channel bandwidth with a single OMC instance ##### Low Power Consumption - Ultra-low power consumption with HW controlled dynamic DRAM frequency scaling - Automatically handles training activities required for frequency change - Automated DRAM power management ![OpenEdges ORBIT](https://static.wixstatic.com/media/fcd3ed_50908b98864a4cc587734f0d55fd4839~mv2.png/v1/fill/w_985,h_464,al_c,q_90,usm_0.66_1.00_0.01,enc_auto/OMC_block%20diagram.png) ### OpenSBI + U-Boot Booting and create a combined FIT uImage: https://www.thegoodpenguin.co.uk/blog/u-boot-fit-image-overview/ #### Booting from SD card ##### Flat image ```shell # load files from FAT fs from SD card to memory fatload mmc 0 80200000 Image fatload mmc 0 82200000 jh7100-starfive-visionfive-v1.dtb # set a kernel cmdline, aka bootargs in U-Boot setenv bootargs "console=ttyS0,115200 earlycon=sbi" # boot a raw Image; note: the "-" means that we have no initrd booti 80200000 - 82200000 ``` ##### FIT image ```shell fatload mmc 0 80200000 mImage setenv bootargs "console=ttyS0,115200 earlycon=sbi" bootm 80200000 ``` #### Network boot We can use [`centre` from Harvey OS](https://github.com/Harvey-OS/go/tree/main/cmd/centre) to serve TFTP and DHCP. ```shell setenv serverip 192.168.22.1 setenv bootargs "console=ttyS0,115200 earlycon=sbi" dhcp;tftpboot 80200000 mImage;bootm 80200000 ``` ### Linux - https://github.com/starfive-tech/linux A bunch of very interesting stuff in the device tree files: - https://github.com/starfive-tech/linux/tree/visionfive/arch/riscv/boot/dts/starfive ## Peripherals and other ports ### (Q)SPI flash - Clocks: `qspi_refclk`, `qspi_ahb`, `qspi_apb` - Resets: `qspi_core`, `qspi_ahb`, `qspi_apb` `cdns,qspi-nor` - [Advanced High-performance Bus (AHB)](https://en.wikipedia.org/wiki/Advanced_Microcontroller_Bus_Architecture#Advanced_High-performance_Bus_(AHB)): `0x2000_0000 + 256MiB` (memory mapped area) - [Advanced Peripheral Bus (APB)](https://en.wikipedia.org/wiki/Advanced_Microcontroller_Bus_Architecture#Advanced_Peripheral_Bus_(APB)): `0x1186_0000 + 64KiB` (control registers) The flash chip on-board supports QSPI but actually only single-wire SPI is ever used. Resets to reading with `EBh` command so AHB doesn't work at power-on. - Reading AHB requires: - `uint32_t[0x11800000] = 0x01000000` (secondBoot, early) - `_SWITCH_CLOCK_clk_cpundbus_root_SOURCE_clk_pll0_out_` - `uint32_t[0x11800010] = 0x01000000` (secondBoot, early) - `_SWITCH_CLOCK_clk_perh0_root_SOURCE_clk_pll0_out_` - `uint32_t[0x11860004] = 0x00000003` (secondBoot, when reading flash) ### GPIO The JH7100 has a kinda confusing GPIO multiplexer, though it's not *that* bad if you're just a user and never go that low level... https://elixir.bootlin.com/linux/v5.19-rc5/source/Documentation/devicetree/bindings/pinctrl/starfive,jh7100-pinctrl.yaml#L9 ### UART `GPIO13`/`GPIO14` on the 40-pin header and the 'DEBUG' header are *both* UART3 because of the GPIO mux thing. ### IO pad configuration The IO pad is used to configure on which GPIO pins the peripherals appear. secondBoot moves the UART to be seen on the 40 pin header instead of the extra debug header. The further vendor firmware components (DDR init, U-Boot, OpenSBI) assume that the UART is running on 115200 baud, whereas the initial mask ROM sets it to 9600 for xmodem transfer. The UART movment happens here in `secondBoot`, `_SET_SYSCON_REG_register104_SCFG_io_padshare_sel(6);`: https://github.com/starfive-tech/JH7100_secondBoot/blob/e17302063c9a4b74475b18ff24dd149c27257354/boot/bootmain.c#L178-L183 We can retain this switch so that we can use the boot mode / xmodem transfer to start running from SRAM for development, but still use the full baud rate on the other header. I.e., we need to hook up two USB serial adapters. ### JTAG - Howto: https://forum.rvspace.org/t/connecting-to-visionfive-s-jtag-port-a-short-guide/514 - Device tree modifications for JTAG after booting Linux: https://gist.github.com/dramforever/e37d05f33a111cf6a8278114c2664629 - Blog post: https://dram.page/p/visionfive-jtag-1 ### Clocks https://github.com/starfive-tech/linux/blob/visionfive/drivers/clk/starfive/clk-starfive-jh7100.c ### E24 core - Clocks: `e24_apb`, `e24rtc` - Resets: `e24` (`mtime` ticks according to the `e24rtc`) - JTAG on a different TAP on the same scan chain as U74 - E24 reset vector `uint32_t[0x1185_00bc]` (`register47_e24_reset_vector`). - Memory map: E24 System Bus `0x8000_0000 + 2GiB` is the same as U74 `0x1000_0000 + 2GiB`. - Has access to first 256MiB of DDR RAM (`0x8000_0000 + 256MiB`) - *Not* cache coherent! #### CLIC Info on the Core-Local Interrupt Controller: - https://www.sifive.com/blog/interrupts-on-the-sifive-e2-series - https://github.com/riscv/riscv-fast-interrupt/blob/master/clic.adoc The 'local interrupt' lines: - ~~I have no idea what the CLIC is connected to.~~ - The E24 CLIC is connected to the same interrupts as the U74 PLIC - E24 Local interrupt `n` is U74 PLIC interrupt source `n + 1` (CLIC has `lint0`, but PLIC doesn't have source 0) Is this the first silicon available to the general public with a SiFive CLIC? ### Ethernet The transceiver is a [Motorcomm YT8521SH]( https://datasheet.lcsc.com/szlcsc/2106070236_Motorcomm-YT8521SH-CA_C2685354.pdf). ### 'ChipLink' MSI device - Clocks: `msi_apb` - Resets: `msi_apb` Ever want to control 10 different interrupts from MMIO? I don't know why you'd want that, but... - ChipLink/MSI Slave: `0x1247_0000 + 32KiB` Every single 4-byte word is aliased to the same 32-bit register. It seems that this device doesn't do address decoding. Format: - `bits[31:10]` Hard-wired to zero - `bits[9:0]` Controls PLIC interrupts `[42:33]` and CLIC interrupts `[41:32]` ### Vivante GC300 GPU (?) - Clocks: `gc300_2x`, `gc300_ahb`, `gc300_axi`, `jpcgc300_axibus`, `jpcgc300_mainclk` - Resets: `gc300_2x`, `gc300_ahb`, `gc300_axi`, `jpcgc300_main` - Interrupts (unknown) (What's 'JPC'?) This isn't even mentioned in the vendor datasheet. Secret GPU? Completely broken? Needs more info. - `GPU2D_CSR` `0x1010_0000 + 256KiB` Mainline `etnaviv` initializes fine, but DMA doesn't seem to work. ``` [ 28.069600] etnaviv etnaviv: bound 10100000.gpu (ops gpu_ops [etnaviv]) [ 28.073585] etnaviv-gpu 10100000.gpu: model: GC300, revision: 4635 [ 28.212694] [drm] Initialized etnaviv 1.3.0 20151214 for etnaviv on minor 0 ``` ### Xtensa Vision P6 If you mux out the JTAG ports, OpenOCD can recognize Xtensa from `IDCODE`. Need a core configuration file to do anything meaningful, so probably never going to get it...