nvidia-riscv/ubootVF2vsK1X.md

38 KiB

VisionFive 2

3x C files

Sourced from https://github.com/starfive-tech/u-boot/tree/JH7110_VF2_6.6_v5.13.2 , the VisionFive 2 port of the U-Boot bootloader.

Documentation to come, prioritising K1, which does not have a EDK2 port at time of writing.

Files

spl.c Functions

spl_board_init_f

wrapper for spl_soc_init

spl_parse_board_header

Set spl_image_size = 0x01000000 set entrypoint = 0x40000000 set load_addr = 0x40000000 set os = IH_OS_U_BOOT (17; firmware)

spl_boot_device

read from the MODE_SELECT_REG (0x1702002c), and check the first 2 bits.

Boot mode boot device
0 SPI
1 MMC2
2 MMC1
3 UART

default to log and return BOOT_DEVICE_NONE (16)

spl_get_load_buffer

return STARFIVE_SPL_BOOT_LOAD_ADDR (0x60000000)

board_init_f

call starfive_jh7110_pll_set_rate for PLL0 to 1000MHz; set PLL0 to 1GHz call starfive_jh7110_pll_set_rate for PLL2 to 1188MHz; set PLL2 to 1.188GHz

DDR control depends on clk init

This section seems to simply index these addresses, and write nothing to it.

clkrsetbits_le32 takes in 3 args; address, bits to clear, and bits to set. This then reads the address, clear and set bits, then write back to the address.

call clrsetbits_le32 with args

  • SYS_CRG_BASE (0x13020000)
  • CLK_CPU_ROOT_SW_MASK (0x1000000)
  • BIT(CLK_BUS_ROOT_SW_SHIFT) & CLK_BUS_ROOT_SW_MASK (0x1000000)

call clrsetbits_le32 with args

  • SYS_CRG_BASE + CLK_BUS_ROOT_OFFSET (0x13020000 + 0x1000000 = 0x14020000)
  • CLK_CPU_ROOT_SW_MASK (0x1000000)
  • BIT(CLK_BUS_ROOT_SW_SHIFT) & CLK_BUS_ROOT_SW_MASK (0x1000000)

set clk_perh_root clk default mux sel to pll2

This section seems to simply index these addresses, and write nothing to it. call clrsetbits_le32 with args

  • SYS_CRG_BASE + CLK_PERH_ROOT_OFFSET (0x13020000 + 0x10 = 0x13020010)
  • CLK_PERH_ROOT_MASK (0x1000000)
  • BIT(CLK_PERH_ROOT_SHIFT) & CLK_PERH_ROOT_MASK (0x1000000)

lots of bitmanip, not worth interpreting

Improved GMAC0 TX I/O PAD compatibility

lots of bitmanip, not worth interpreting

Improved GMAC1 TX I/O PAD compatibility

lots of bitmanip, not worth interpreting

Set GPIO to 3.3v

set SYS_SYSCON_BASE + 0xc (0x13030000 + 0xc = 0x1303000c) to 0x0 (doesn't immediately seem to do anything?)

setup uart0

setup jtag

reset emmc

reset sdio

init i2c5

call spl_early_init, panic if fail

call arch_cpu_init_dm

call preloader_console_init

call spl_board_init_f, log if fail

return

board_fit_config-name_match

No implementation, always use first config

spl_enable_uart2

set bit 31 at address SYS_CRG_BASE + CLK_UART2_APB_OFFSET (0x13020000 + 0x254 = 0x13020254) set bit 31 at address SYS_CRG_BASE + CLK_UART2_CORE_OFFSET (0x13020000 + 0x258 = 0x13020258) clear bits 23 and 24 at address SYS_CRG_BASE + CLK_RSTN_3_OFFSET (0x13020000 + 0x300 = 0x13020300)

declare GPIO 43 as digital input set GPIO 43 digital output (???) to 0x4f set drive strength for GPIO 43 to 3 (12mA)

set GPIO 42 as digital input set GPIO 42 digital input (???) to 62

spl_perform_fixups

get the rtos base address and the offset, and if they both eist, call spl_enable_uart2. set rtos_image_address to CONFIG_SPL_OPENSBI_LOAD_ADDR (0x40000000) + the loaded offset, then copy the rtos from the image to the base address

starfive_visionfive2.c Functions

sys_reset_clear

clear the passed reset bit at the address SYS_CRG_BASE (0x13020000) + the passed assert

wait for the status register to change

jh7110_timer_init

lots of bitmanip, not worth interpreting

Enable APB, Timer0-Timer3 clocks

reset all timers

jh7110_gmac_init_1000M

init the given ethernet port at the given speed. lots of bitmanip, not worth interpreting

jh7110_gmac_init_100M

init the given ethernet port at the given speed. lots of bitmanip, not worth interpreting

jh7110_gmac_sel_tx_to_rgmii

init the ethernet port for common sub-gigabit comms (RGMII is best documented by Intel in their Cyclone V and Arria V SoC design guidelines)

set_uboot_fdt_addr_env

set envvar uboot_fdt_addr from the devicetree blob

get_chip_type

call get_data_from_eeprom to get the chip revision, then set the chip_vision envvar accordingly (a->A, b->B, other -> unknown). Also return type

get_board_type

call get_pcb_revision_from_eeprfom to get the board revision. Check the masked information for one of the 3 board versions

jh7110_gmac_init

If the passed chip type is A, do nothing. otherwise, set up the ethernet for RGMII for both ports

If the board type is BOARD_1000M_100M, init ethernet for 1000M on port 0 and 100M on port 1. Otherwise, use 1000M for both.

jh7110_usb_init

USB init; more bit manip

get_cpu_voltage_type

read the binning offset of the chip, and adjust envvar cpu_max_vol to 1000000, 1060000, 1020000; map to 0x08f0, 0x0ff0, and 0x0ef0 respectively

jh7110_jtag_init

JTAG init; bit manip

jh7110_i2c_init

If passed id is 5, set stuff up. Otherwise, don't do anything

get_boot_mode

check bits 1 and 2 against the value in AON_IOMUX_BASE + AON_GPIO_DIN_REG (0x17020000 + 0x2c = 0x1702002c)

Boot version encoding bootmode envvar devnum envvar
FLASH 0 flash 1
SD 1 sd 1
EMMC 2 emmc 0
default default uart 1

jh7110_gpio_init

pin 57 set to output enable, GPO of 0 (???), DIN (???) of 9. Drive strength set to 3, and pullup resistors

pin 58 set to output enable, GPO of 0 (???), DIN (???) of 10. Drive strength set to 3, and pullup resistors

board_init

enable cache

jtag init

timer init

usb init, primarily USB2

i2c init

gpio init

board_late_init

Get boot mode, and init gmac based on chip and board type

update memory_addr and memory_size envvars accordingly

Get the UCLASS_VIDEO device, and return early if fail

Display the logo provided to the screen, return quietly but early if fail

get the opmsg_shmem object from the devicetree. If this is successful, get the base from the devicetree. and if this exists, set the eth0addr and eth1addr envvars according to read mac addresses

misc_init_r

hardcoded mac addresses of 6c:cf:39:6c:de:ad and 6c:cf:39:7c:ae:5d

If the build config includes OTP (one-time programmable memory), try to read the mac address from the OTP first, and overwrite the hardcoded mac addresses

set the eth0addr and eth1addr based on mac address

get the chip name

set the envvar for uboot fdt address

if OTP, get cpu voltage type as well

check_eeprom_dram_info

Only exists if CONFIG_ID_EEPROM is set

only allow valid values of 1, 2, 4, 8, and 16

resize_ddr_from_eeprom

Only has behaviour if CONFIG_ID_EEPROM is set

Get the i2c device, return early if it doesn't init properly

get the memory size info from the eeprom, and check then return the RAM size

board_ddr_size

wrapper for resize_ddr_from_eeprom

visionfive2-i2c-eeprom.c Functions

is_match_magic

stringcompare passed hats to hats signature

calculate_crc16

well commented and documented

update_crc

update CRC of passed eeprom atom

dump_raw_eeprom

display raw hex from eeprom

hats_atom_crc_check

check atom crc

hats_get_atom

iterate over atoms listed in header, check them. return the atom we're looking for

show_eeprom

print formatted eeprom contents

parse_eeprom_info

if correct: has_been_read set to 1, then display info else: has_been_read set to -1, dump hex data to output

Get the atom HATS_ATOM_VENDOR, and if it exists, save the serialnumber

get the atom HATS_ATOM_CUSTOM, and if it exists, save PCB rev, BOM rev, MAC0, and MAC1 addresses

read_eeprom

check has_been_read, return immediately if it's set already; comms over i2c using dm_i2c_read

prog_eeprom

write eeprom from memory; comm over i2c.

check match magit from the given buffer. If it matches magic properly, write to board using dm_i2c_write

set_mac_address

check the mac address and save to the RAM-saved EEPROM copy, including update crc

set_pcb_revision

edit in-RAM EEPROM copy; update crc

set_bom_revision

set uppercase BOM revision to the in-RAM EEPROM copy; update crc

set_product_id

set product ID as string to the in-RAM EEPROM copy; update crc

init_local_copy

init in-memory EEPROM with magic number. Must be done to init blank eeprom or overwrite corrupted magic number

print_usage

print statement; does what it says on the tin

do_mac

???

mac_read_from_eeprom

dump eeprom to buffer

setup ethaddr envvars

setup serial# from eeprom ptsr

get_pcb_revision_from_eeprom

read the eeprom, and print the pcb revision

get_data_from_eeprom

direct memcpy for some data


K1-X

6x C files, multiple json, config files, 1x its file, 1x C header

Sourced from https://git.blizzard.systems/bianbu-mirror-repos/milkv-jupiter-uboot-2022.10 , which is a proxy of the BianbuOS U-Boot source repository.

No open documentation for the X60 core IP, so building everything in edk2 need to be based off publicly available information.

For any instance in this section, the following C-type define block is useful:

#define BIT(nr) (1UL <<(nr))

Correlated Files from VF2

spl.c Functions

timer_init

Defines register GEN_CNT (0xd5001000), of size 0x20, read from the address, write back to the register after modifying

__get_boot_storage

Store STORAGE_API_P_ADDR (0xc0838498), also get the address stored there. If the address is the same as SDCARD_API_ENTRY (0xffe0a548), return BOOT_MODE_SD, otherwise, return the output of get_boot_pin_select, defined in k1x.c

fix_boot_mode

If the value stored in the BOOT_DEV_FLAG_REG(0xd4282d10) is zero, call set_boot_mode(__get_boot_storage()). set_boot_mode is defined in k1x.c, and __get_boot_storage is defined above.

board_pinctrl_setup

SDCard Pin control setup. MFPR_MMC1_BASE(0xd401e1b8) is the base address of the SD interface. Sets all pins to MUX_MODE0, no edge detection, all pins but CLK to PULL_UP (CLK is PULL_DOWN), and set PAD_3V_DS4 (Meaning unclear at time of writing)

Pin offset pin name Mux mode edge-detect pull-up/-down/float PAD voltage and driver strength
0x00 MMC1_DATA3 0 None Pull-up PAD_3V_DS41
0x04 MMC1_DATA2 0 None Pull-up PAD_3V_DS41
0x08 MMC1_DATA1 0 None Pull-up PAD_3V_DS41
0x0c MMC1_DATA0 0 None Pull-up PAD_3V_DS41
0x10 MMC1_CMD 0 None Pull-up PAD_3V_DS41
0x14 MMC1_CLK 0 None Pull-down PAD_3V_DS41

adjust_cpu_freq

Parameter 1: cluster (unknown meaning) Parameter 2: freq (Actrive frequency)

Read the value from ( K1X_APMU_BASE(0xd4282800) + a custom offset (0x38c) + cluster * 4) into the variable val This following bits are then cleared in val: 0x0107 (Bits 1, 2, 3, and 13) Switch statement based on frequency:

  • 1600000Hz: set bits 1, 2, and 3 in val
  • 1228000Hz: set bit 3 in val
  • 819000Hz: set bit 1 in val
  • 614000Hz (default): set no values in val, set freq to 614000Hz

Write this value back to the originally read address. Read the bit back, set bit 12, write back, and wait until it is cleared on the other side (while loop, checking bit 12) return the frequency that was set

raise_cpu_frequency

Write 0x2dffff to 0xd4051024 (This does....???)

Enable CLK_1228M

Read from K1X_MPMU_BASE(0xd4050000) + 0x1024, set bits 13,14,15,16, write back

Enable PLL3(3200MHz)

Read from K1X_APB_SPARE_BASE (0xd4090000) + 0x012c, set bit 31, write back.

Enable PLL3_DIV2

Read from K1X_APB_SPARE_BASE (0xd4090000) + 0x0128, set bit 1, write back.

Call cpu_get_current_dev, save to cpu. (Gets the current CPU; external driver/cpu/cpu-uclass.c definition)

Read the frequency (uint32) from the DeviceTree for cluster 0 (Not sure where this comes from). so if this fails, log it and assign the CPU frequency to 1228000Hz. Otherwise, set the CPU frequency to whatever the DT says

Read the frequency (uint32) from the DeviceTree for cluster 1 (not sure where this comes from). so if this fails, log it and assign the CPU frequency to 614000Hz (log says 1228000 though). Otherwise, set the CPU frequency to whatever the DT says

load_board_config_from_efuse

This is enabled by the SPACEMIT_K1X_EFUSE config variable.

Load the efuse driver, then read from the efuse into the array fuses (2 bytes long).

If this read properly, and the first byte isn't zero:

  • set eeprom_i2c_index to bits 0-3 of the first byte
  • set eeprom_pin_group to bits 4-5 of the first byte
  • set pmic_type to bits 0-3 of the second byte

load_chipid_from_efuse

This is enabled by the SPACEMIT_K1X_EFUSE config variable.

Load the efuse driver, then read from the efuse into the array fuses (32 bytes long).

Bits 191 to 251 is the chip ID, but that's larger than 1 byte, so we do the following:

  1. get bit 192-251 (fuses[24], all bits)
  2. left shift 1 bit, OR with bit 191 (fuses[23], high bit)

load_default_board_config

Set eeprom_i2c_index to the enviornment variable of the same name, or default back to K1_DEFAULT_EEPROM_I2C_INDEX (2).

Set eeprom_pin_group to the enviornment variable of the same name, or default back to K1_DEFAULT_EEPROM_PIN_GROUP (0).

Set pmic_type to the environment variable of the same name, or default to K1_DEFALT_PMIC_TYPE [sic] (0).

load_board_config

Load defaults first, then load from efuse if available, then print to debuglog

read_boot_storage_emmc

Get the block device mmc:1, dump the first partition into a buffer, and return it

read_boot_storage_sdcard

Get the block device mmc:0, dump the first partition into a buffer, and return it

read_boot_storage_spinor

probe all MTD devices, get the "private", dump the device into a buffer, and return it

read_training_info

Get the current boot storage (using get_boot_storage from k1x.c), get the training info, and save it to a buffer.

(iterate over possible boot storage modes, and use the appropriate read_boot_storage_* function defined above, using address 0x10000 for EMMC or SD and 0x0 for NOR)

restore_ddr_training_info

load map system-memory address 0xC0800000, and save it to an object. This object contains a trait "magic", along with a crc32, chipid, mac_addr, version, cs_num, 2 reserved arrays, and a parameter array

If booting from USB, or if the training info is the wrong size, or any of the information loaded was bad, force retraining by clearing all info and returning false, indicating failure.

flush and invalidate cache

update_ddr_training_info

load map system-memory address 0xC0800000, and save it to an object. This object contains a trait "magic", along with a crc32, chipid, mac_addr, version, cs_num, 2 reserved arrays, and a parameter array

If the DDR still contains the magic training value, and the CRC is the same as we had before, we don't need to save it. Clear the magic bit and move on.

Otherwise, set all the values appropriately

update_ddr_config_info

Force update all values

spl_board_init_f

If SYS_I2C_LEGACY is set in config, call i2c_init_board, defined below

void i2c_init_board(void)
{
	int i = 0;

	mmio_write_32(0xd4051024, (*(unsigned int *)0xd4051024) | (1 << 6));
	mmio_write_32(0xd4090104, (*(unsigned int *)0xd4090104) | (1 << 4));

	mmio_write_32(0xd401e228, (*(unsigned int *)0xd401e228) | (1 << 1));
        mmio_write_32(0xd401e22c, (*(unsigned int *)0xd401e22c) | (1 << 1));
	/* init the clk & reset or pinctrl */
	for (i = 0; i < sizeof(apbc_clk_reg) / sizeof(apbc_clk_reg[0]); ++i) {
		mmio_write_32(apbc_clk_reg[i], (I2C_FUNCLK_33MHz << 4) | 0x4);
		mmio_write_32(apbc_clk_reg[i], (I2C_FUNCLK_33MHz << 4) | 0x7);
		mmio_write_32(apbc_clk_reg[i], (I2C_FUNCLK_33MHz << 4) | 0x3);
	}
}

If SPACEMIT_POWER is set in config, call board_pmic_init; unclear how this is implemented at time of writing

call raise_cpu_frequency

call update_ddr_info

Get the UCLASS_RAM device, and if it fails, log it. This means DRAM initialisation failed

call update_ddr_config_info

call timer_init

board_init_f

Call fix_boot_mode, then board_pinctrl_setup, then spl_early_init. If the last fails, panic.

Call riscv_cpu_setup, then preloader_console_init, then spl_board_init_f. If the last fails, panic.

board_fit_config_name_match

Enabled if CONFIG_SPL_LOAD_FIT config variable is enabled

Set the buildin_name to the previously-acquired product_name, defaulting to k1-x_deb1

As long as the name is the same as the passed-in name, log "Boot from fit configuration", and return safely. Otherwise, fail

_spl_env_driver_lookup

Iterate over linked driver entries to find the location we're looking for. Lots of pointer shenanigans and API calls, not super important.

spl_load_env

Call get_boot_mode. Return immediately if the boot mode is USB.

Set the environment location depending on the boot mode and the config values.

call spl_env_driver_lookup, and if it doesn't fail, load it. If it can't load, fail back to default

get_mac_address

Call k1x_eeprom_init. If this is successful, and the pointer passed in is real, and the TLV_CODE_MAC_BASE2 loaded from EEPROM is successful, log the mac address and return safe, otherwise return fail.

get_product_name

Allocate memory space for the device name.

Call k1x_eeprom_init. If this is successful, and the name was allocated properly, and the TLV_CODE_PRODUCT_NAME loaded from EEPROM is successful, log the product name and return it. Otherwise, free the allocated memory and log that we're using the default product name.

update_ddr_info

Call k1x_eeprom_init. Allocate and clear a chunk of memory for the DDR type from the EEPROM. Read TLV_CODE_DDR_TYPE from the EEPROM, and save the ddr type.

Read TLV_CODE_DDR_CSNUMfrom EEPROM, and if read successfully, save it.

Read TLV_CODE_DDR_DATARATE from EEPROM, and if read successfully, save it.

spl_board_init

Call spl_load_env, then get and save the product name using get_product_name

spl_get_load_buffer

Return a correctly cast pointer to the FIT address, according to the build-time config variable CONFIG_SPL_LOAD_FIT_ADDRESS

board_boot_order

Call get_boot_mode, and set the value in spl_boot_lilst[0]

spl_boot_list[1] is set as booting device from ram; that is, loading and running u-boot from RAM. No other values are assigned

k1x.c Functions

set_boot_mode

write the boot mode enum to the BOOT_DEV_FLAG_REG (0xd4282d10)

get_boot_pin_select

Read from BOOT_PIN_SELECT (0xd4282c20), and check bits 9 and 10.

Bitmask Boot mode
b00 BOOT_MODE_EMMC
b10 BOOT_MODE_NOR
b01 BOOT_MODE_NAND
b11 BOOT_MODE_SD

get_boot_mode

Get the boot mode value from BOOT_DEV_FLAG_REG (0xd4282d10)

Check against boot mode enum:

Hex value boot mode
0x055a USB
0x055b EMMC
0x055c NAND
0x055d NOR
0x055e SD
0x055f SHELL

set_serialnumber_based_on_boot_mode

Get the serial number from the boot environment variable (serial#)

Get the bootmode

If the bootmode isn't USB, and the environment variable is set, set the USB gadget download serial number

get_boot_storage

Call get_boot_mode

If the boot medium isn't SD card, call get_boot_pin_select

mmc_get_env_dev

Call get_boot_mode

If the boot mode is EMMC, return MMC_DEV_EMMC (2), otherwise return MMC_DEV_SD (0)

write_boot_storage_emmc

Get the EMMC block device

select the first partition, and dump the given buffer into the selected partition

write_boot_storage_sdcard

Get the SD block device

select the first partition, and dump the given buffer into the selected partition

write_boot_storage_spinor

Get the MTD private devic, and dump the given buffer to the device

write_training_info

call get_boot_storage

Use the appropriate storage callback to write to the current boot storage

(Done using an array of struct with enum, address, and function callback pointer; iterate over array)

save_ddr_training_info

Get the info from the DDR_TRAINING_INFO_BUFF (0xc0800000), and if it is valid (magic bits = 0x54524444, crc matches) pass the information to write_training_info

get_ddr_config_info

Get the info from the DDR_TRAINING_INFO_BUFF (0xc0800000), and if it is valid (magic bits = 0x54524444, crc matches), set the value of ddr_cs_num; if it isn't, set ddr_cs_num to the default of 1

According to the comments and documentation, this seems to be DDR channel number

get_reboot_config

If the reboot_config value is set, immediately return it.

Direct copy of commment:

K1 has non-reset register(BOOT_CIU_DEBUG_REG0) to save boot config before system reboot, but it will be clear when K1 power is down, then boot config will be save in P1.

Read from the aforementioned register (0xd4282f90) into flag

If flag is either BOOT_MODE_SHELL (0x055f) or BOOT_MODE_USB (0x055a), clear the BOOT_CIU_DEBUG_REG0 register, and set reboot_config to flag and return reboot_config

Otherwise, set reboot_config to BOOT_MODE_BOOTSTRAP (0x0560).

Load the power management driver for the spacemit_pm8xx, and if that fails log the error and return 0.

Read from the PMIC's non-reset register (address 0xab), and log it. If bit 0 of the config is set, set reboot_config to BOOT_MODE_USB, and clear the register. If bit 1 of the config is set, set reboot_config to BOOT_MODE_SHELL, and clear the register. Then return reboot_config

button_get_state_by_label

For each child of the passed in udev device, get the class platform data, and if the platform data label exists and is what we're looking for, read the boolean invert-state as well as calling button_get_state. If invert-state is true, invert the state. Return the state of the button

If we can't find the button, return -ENOENT (-2; Error: No entity)

get_fastboot_key_config

Get the /gpio_keys object. If it's invalid, return -ENODEV (-19; Error: no device)

Read the fastboot-key-combo string, set the passed config's key_names value. If the read call fails, return the fail value now.

Set the config's key_count to the length of the read string.

Read fastboot-key-press-time, set the config's press_time value. If the read fails, return the read fail value, otherwise return 0

check_fastboot_keys

Call get_fastboot_key_config; if it fails, log the failure and return false

log the config

Get the GPIO device. If this fails, log the failure and return false

Allocate memory for the key_states

call get_timer(0), and save the output.

While the updated timer is still less than the configured press time:

  • iterate over the keys, get the button state. If the stateis in error or the button is not set to on, break out of this iteration loop now, and clear all_pressed
  • If all_pressed is cleared, free the value key_states, and return false now
  • delay for 10ms

If we get here, the button has been pressed and held for the requisite amount of time Free the key_states value, log that fastboot was detected, and return true

run_fastboot_command

Call get_boot_mode

If the boot mode is USB, if the reboot config from get_reboot_config is USB, or (if it is enabled) check_fastboot_keys returns true:

  • set stdout environment variable to the value found in stdout_flash
  • Run the command fastboot 0
  • call refresh_config_info

run_uboot_shell

call get_boot_mode

If the boot or reboot mode is SHELL, return 0, else return 1

_load_env_from_blk

Iterate over partitions 1 thru 16. If getting the partition info errors, then skip it. If the name is the same as the BOOTFS_NAME, (bootfs), log that we've matched and stop iterating.

If the final value of the iterator is larger than 16, return now. We couldn't find the bootfs.

Set the environment variable bootfs_part to a string of the partition number found earlier

Set the environment variable bootfs_devname to the device name passed in

Call the U-Boot load command to load the environment text file, from the given device name, the found device number, and the partition number, into CONFIG_SPL_LOAD_FIT_ADDRESS(0x11000000). The file name is defined as env_%s.txt, where %s is set to CONFIG_SYS_CONFIG_NAME, which defaults to k1-x.

If the command doesn't run successfully, return now.

Clear the command buffer, then set the next command buffer to be env import -t 0x%x, where %x is CONFIG_SPL_LOAD_FIT_ADDRESS mentioned previously.

If the command runs successfully, log such.

parse_mtdparts_and_find_bootfs

Get the value from the mtdparts environment variable. If this value isn't set, log and return NULL

Find the start of the last partition (search for the last instance of the ( character), and if it exists, find the end of the partition (search for the first instance of the ) character.

If the end exists, and the size of the partition is the right size, copy the partition into the character buffer

Run ubi part found_partition, and if it runs successfully, run ubi check bootfs. If this is successful, return the found partition.

If we get here, we couldn't find a partition, return NULL.

import_env_from_bootfs

Call get_boot_mode

If built to support ENV_IS_IN_NFS, if the boot mode isn't USB, and the bootfs doesn't exist:

  • if built to support networking, initialise the ethernet controller via eth_initialise
  • call load_env_from_nfs, and if successful, return now

Large switch block based on acquired boot mode; build-time config variable ENV_IS_IN_X toggles blocks

BOOT_MODE_NAND and ENV_IS_IN_MTD

Set the bootfs_name to be bootfs. If this setting fails, log and return.

call parse_mtdparts_and_find_bootfs. If this fails, log and return.

Run the U-Boot command ubifsmount ubi0:bootfs. If this command fails, log and return.

Allocate space for the environment text file, then run ubifsload CONFIG_SPL_LOAD_FIT_ADDRSSS env_k1-x.txt

Clear the command buffer, then run env import -t CONFIG_SPL_LOAD_FIT_ADDRESS

BOOT_MODE_NOR

call get_available_boot_blk_dev; if this fails log and return

call blk_get_dev, and save this value. If it is valid, call _load_env_from_blk

(BOOT_MODE_EMMC or BOOT_MODE_SD) and CONFIG_MMC

call mmc_get_env_dev, and pass this output into find_mmc_device. If this fails, log and return. Otherwise, call mmc_init. If this fails, return.

Call _load_env_from_blk to load from the mmc

run_cardfirmware_flash_command

Only actually does anything if CONFIG_MMC is enabled

call find_mmc_device. If this is fails, return now Call mmc_init. If this fails, return now

Iterate over partitions, get the info from the partition. If it fails, keep searching. If it's a match, exit iteration.

If we couldn't find it at all, return.

Run the uboot command fatsize mmc MMC_DEV_SD:partition_number FLASH_CONFIG_FILE_NAME (FLASH_CONFIG_FILE_NAME defaults to partition_universal.json) If this is successful, run flash_image mmc

setenv_boot_mode

If ENV_IS_IN_NFS is set: get the environment variable boot_override, and if it exists, set the boot_device envvar to the value from boot_override, and clear the envvar boot_override. Return now.

call get_boot_mode.

In NAND boot mode

set the envvar boot_device to nand

In NOR boot mode

call get_available_boot_blk_dev, and if this fails, return now. Set envvar boot_device to nor, and boot_devnum to a string of the found block device index

In EMMC boot mode

set envvar boot_device to mmc, and boot_devnum to a string of MMC_DEV_EMMC (2)

In SD boot mode

set envvar boot_device to mmc, and boot_devnum to a string of MMC_DEV_SD (0)

In USB boot mode

set envvar bootcmd to CONFIG_BOOTCOMMAND (bootm 0x11000000)

Fallback

clear envvar boot_device

read_from_eeprom

call read_tlvinfo_tlv_eeprom; if this fails, log and return

Guess-and-check offset until all the things line up (essentially)

find_tlv_in_buffer

Similar guess-and-check methodology from read_from_eeprom

mac_read_from_buffer

Call find_tlv_in_buffer, looking for TLV_CODE_MAC_SIZE (0x2a). If we found it, extract from output using..... this:

maccount = (mac_size_tlv->value[0] << 8) | mac_size_tlv->value[1];

Call find_tlv_in_buffer, looking for TLV_CODE_MAC_BASE (0x24). If we found it, copy the found value into the array mac_base. Otherwise, clear the array.

iterate over all mac options. if it passes is_valid_ethaddr, format the string properly, format the enetvar envvar depending on which mac address we're using, and if that envvar has not been set, set it to our valid ethaddr

Increment MAC to the next value for the next port, as long as it's valid

set_env_ethaddr

If we're given existing eeprom data, parse that, and if that fails, log and return. Otherwise, try to parse from EEPROM, and if that fails, log and return.

call eth_env_get_enetaddr on both ethaddr and eth1addr, and if they're both valid, log the first mac address and return.

If we get here, we couldn't load a MAC, so let's generate one instead. Call net_random_ethaddr, and set mac_addr[0:2] to 0xfe. Then, copy this value to the second mac address, and increment by 1

Write our found/generated mac addresses to the envvars

run tlv_eeprom

save the mac address to eeprom, using tlv_eeprom set 0x24 mac_address run command tlv_eeprom set 0x2a 2 run command tlv_eeprom write

set_dev_serial_no

If we're given eeprom data, search the buffer for TLV_CODE_SERIAL_NUMBER (0x23) Otherwise, search eeprom

If the value exists, and has a reasonable length, set the envvar serial#, and free temp var

refresh_config_info

For each line in this chart: Follow the same behaviour defined for set_dev_serial_number

Code Encoding Name datatype
TLV_CODE_PRODUCT_NAME 0x21 product_name string
TLV_CODE_PART_NUMBER 0x22 part# string
TLV_CODE_SERIAL_NUMBER 0x23 serial# string
TLV_CODE_MANUF_DATE 0x25 manufacture_date string
TLV_CODE_MANUF_NAME 0x2b manufacturer string
TLV_CODE_WIFI_MAC_ADDR 0x60 wifi_addr string
TLV_CODE_BLUETOOTH_ADDR 0x61 bt_addr string
TLV_CODE_DEVICE_VERSION 0x26 device_version numeric
TLV_CODE_SDK_VERSION 0x40 sdk_version numeric

board_init

If build config CONFIG_DM_REGULATOR_SPM8XX, call regulators_enable_boot_on, and if this fails, log If build config CONFIG_SPACEMIT_SHUTDOWN_CHARGE, if the boot mode is usb, call uclass_get_device_by_driver, using the shutdown_charge driver.

board_late_init

If the envvar product_name isn't set, set it to DEFAULT_PRODUCT_NAME (k1-x_deb1)

allocate 2048 bytes, aligned to 32 bytes. If this fails, log and return -ENOMEM (-12, Error: No Memory)

Call read_tlvinfo_tlv_eeprom, and if it fails, log

If the generated tlv_hdr is not null, first_entry isn't null, and the header passes is_valid_tlvinfo_header, call each of the following with the buffered eeprom data:

  • set_env_ethaddr
  • set_dev_serial_no
  • refresh_config_info Otherwise, call each of the above functions with an input buffer of NULL

call set_serialnumber_based_on_boot_mode

If CONFIG_VIDEO_SPACEMIT, call uclass_probe_all for UCLASS_VIDEO (118), and for UCLASS_DISPLAY (34), and if either fails, log

If CONFIG_BUTTON, call uclass_probe_all for UCLASS_BUTTON (29), and log pass/fail

call run_fastboot_command

call run_cardfirmware_flash_command

call run_uboot_shell, and if this fails, log reboot into uboot shell and return 0

call import_env_from_bootfs, then if no video is connected, set envvar stdout to serial.

call setenv_boot_mode

set the envvar ram_size correctly (mem=%dMB)

get the node of the chosen boot path (/chosen). If this fails, log and return 0.

read kernel start address from the device tree; if fail, log and return 0

set the envvar kernel_start based on the read kernel start address, then return 0.

board_fdt_blob_setup

If the config is set correctly, check the FDT header before returning the firmware address. Otherwise, return (ulong *)&_end (unclear what that means)

env_get_location

If priority is higher than 1, return ENVL_UNKNOWN (0)

Get the current boot mode, and return the correct ENVL_X, depending on CONFIG_ENV_IS_IN_X. Default state is ENVL_UNKNOWN, unless CONFIG_ENV_IS_NOWHERE in which case default is ENVL_NOWHERE.

misc_init_r

required function, no behaviour

dram_init

call get_ddr_config_info call ddr_get_density, multiply by SZ_1MB (0x00100000), save as dram_size set ram_base to CONFIG_SYS_SDRAM_BASE (0x0) set ram_size to dram_size

dram_init_banksize

call ddr_get_density, multiply by SZ_1MB (0x00100000), save as dram_size

set bi_dram[0].start = CONFIG_SYS_SDRAM_BASE (0x0)

If dram_size > 2 gigs (encoded as 0x80000000), set bi_dram[0].size to 2 gigs, if CONFIG_NR_DRAM_BANKS is more than 1, set bi_dram[1].start to 0x100000000, and bi_dram[1].size to dram_size - 2g

if dram_size <= 2 gigs, directly assign bi_dram[0].size as dram_size

return 0

board_get_usable_ram_top

call ddr_get_density, multiply by SZ_1MB (0x00100000), save as dram_size

If dram_size is more than 2 gigs, return 0x80000000 due to 32-bit DMA limit. otherwise, just return dram_size

board_fit_config_name_match

only exists if CONFIG_SPL_BUILD is undefined

get the envvar product_name, convert it to consistent formatting (k1-x_deb1)

If the product name exists, and it fitts the passed name, log and return 0, else return 1

get_dro_from_efuse

Get the device that is compatible with the spacemit_k1x_efuse, and if it fails, return SVT_DRO_DEFAULT_VALUE (120)

Read from efuse, the info we want is in bank7, bits 173-181, and if that value isn't zero, return it. If it is zero, return the default (120)

get_chipinfo_from_efuse

Get the device that is compatible with the spacemit_k1x_efuse, and if it fails, return ENODEV (19; Error: No Device)

Read from efuse, the product ID is in bank 7, bits 182-190

Read from efuse, the waver ID is in bank 7, bits 139-154

ft_board_cpu_fixup

call fdt_path_offset to get the root node of the devicetree. If this fails, log and return -EINVAL (22; Error Invalid argument)

call get_chipinfo_from_efuse, and convert the product ID and wafer ID to big-endian

call fdt_setprop to set the product and wafer ids in the devicetree

get the cpu node from the devicetree

get the dro(?) value from efuse, convert to big-endian, and save to the devicetree; if fail, return failcode

return 0

ft_board_info_fixup

get the devicetree root node; if fail log and return -EINVAL (22; Error invalid argument)

get the envvar part#, and save it to the devicetree

ft_board_mac_addr_fixup

get the devicetree soc node.

get the envvar for both macs, and save to devicetree

ft_board_setup

If FDT_FIXUP_PARTITIONS is enabled, and the boot mode is NOR, call fdt_fixup_mtdparts

If FDT_SIMPLEFB is enabled, call fdtdec_add_reserved_memory to reserve the framebuffer memory

call each function in order

  • ft_board_cpu_fixup
  • ft_board_info_fixup
  • ft_board_mac_addr_fixup

return 0

has_bootarg

If all input parameters don't exist, return false.

Iterate through all parameters, skipping spaces, and check if the parameter is valid. If it is, return true.

If we never returned, then we have no valid bootargs, return false

board_fdt_chosen_bootargs

get the envvar fdt_addr, and if it doesn't exist, return with the value in envvar bootargs

check the header of fdt, and if it fails, log and return with the value in envvar bootargs

get the /chosen object from the devicetree, get the property bootargs, and save to dts_args

Log both env and dts bootargs.

If the dts bootargs don't exist, immediately return with bootargs

string manip to merge both bootargs envvar and dts_args, then return the merged string

k1x-i2c-eeprom.c

Functions:

init_tlv_data

Read from i2c

check if the header is correct, and the rest of the size is still valid.

Read the rest of the info into the buffer

spacemit_eeprom_read

mostly move data around after data checking; not clear but it's late

i2c_set_pinctrl

wrapper for pointer shenanigans; sets value

i2c_get_pinctrl

wrapper for pointer shenanigans; sets value

k1x_eeprom_init

struct eeprom_config {
	uint8_t bus;
	uint16_t addr;
	uint8_t pin_function;
	uint32_t scl_pin_reg;
	uint32_t sda_pin_reg;
};

const struct eeprom_config eeprom_info[] = {
	// eeprom @deb1 & deb2: I2C2, pin group(GPIO_84, GPIO_85)
	{2, 0x50, MUX_MODE4, 0xd401e154, 0xd401e158},
	// eeprom @evb: I2C6, pin group(GPIO_118, GPIO_119)
	{6, 0x50, MUX_MODE2, 0xd401e228, 0xd401e22c},
};

Try both eeprom options for the following: Set the pin functions for SCL and SDA. If it fails, unset and try next iteration. Call init_tlv_data, return saddr

_read_from_i2c

Read from i2c. I don't fully get it, but it's a C implementation of i2c interaction

_write_to_i2c

write from i2c, see comments above

clear_eeprom

create memory block of given size, write to i2c



  1. Voltage 3V, Driver Strength 4. This is also written in the relevant #define block as bit[12:10] 001 ↩︎

  2. TLV = Type-Length-Value ↩︎