diff --git a/Cargo.lock b/Cargo.lock index 07f2f65178..7e30179734 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4385,6 +4385,20 @@ dependencies = [ "autocfg", ] +[[package]] +name = "metro" +version = "0.1.0" +dependencies = [ + "build-util", + "cfg-if", + "cortex-m", + "cortex-m-rt", + "drv-stm32h7-startup", + "kern", + "ringbuf", + "stm32h7", +] + [[package]] name = "microcbor" version = "0.1.0" diff --git a/app/metro/Cargo.toml b/app/metro/Cargo.toml new file mode 100644 index 0000000000..7a2e30ce71 --- /dev/null +++ b/app/metro/Cargo.toml @@ -0,0 +1,32 @@ +[package] +edition = "2024" +readme = "README.md" +name = "metro" +version = "0.1.0" + +[features] +traptrace = ["ringbuf"] +dump = ["kern/dump"] +measurement-handoff = ["drv-stm32h7-startup/measurement-handoff"] + +[dependencies] +cortex-m = { workspace = true } +cortex-m-rt ={ workspace = true } +cfg-if = { workspace = true } +stm32h7 = { workspace = true, features = ["rt", "stm32h753"] } +ringbuf = { path = "../../lib/ringbuf", optional = true } + +drv-stm32h7-startup = { path = "../../drv/stm32h7-startup", features = ["h753"] } +kern = { path = "../../sys/kern" } + +[build-dependencies] +build-util = {path = "../../build/util"} + +# this lets you use `cargo fix`! +[[bin]] +name = "metro" +test = false +bench = false + +[lints] +workspace = true diff --git a/app/metro/README.md b/app/metro/README.md new file mode 100644 index 0000000000..9a1916af77 --- /dev/null +++ b/app/metro/README.md @@ -0,0 +1,8 @@ +# Metro Service Processor (SP) firmware + +The Metro is the (TBA) compute sled in the Oxide rack. + +This folder contains the firmware that runs on its service processor (SP). + +The Root of Trust firmware is common across multiple boards and can be found +in the [`oxide-rot-1` subfolder](../oxide-rot-1). diff --git a/app/metro/base.toml b/app/metro/base.toml new file mode 100644 index 0000000000..1c9c54b51a --- /dev/null +++ b/app/metro/base.toml @@ -0,0 +1,1577 @@ +target = "thumbv7em-none-eabihf" +chip = "../../chips/stm32h7" +default-ram = "axi_sram" +stacksize = 896 + +[kernel] +name = "metro" +requires = {flash = 32768, ram = 8192} +features = [ + # "dump", + # "measurement-handoff", +] +extern-regions = [{ region = "dtcm", shared = true }] + +# AJM 2026-09-07: All of these sections are compiled out! We need to review +# and port them for the new hardware. + +# [mmio] +# peripheral-region = "fmc_nor_psram_bank_1" +# register-map = "../../drv/spartan7-loader/metro-seq/metro_seq_top.json" + +# [caboose] +# tasks = ["control_plane_agent", "packrat"] +# region = "flash" +# size = 256 + +[tasks.jefe] +name = "task-jefe" +priority = 0 +max-sizes = {flash = 16384, ram = 4096} +start = true +features = [ + # "dump", + # "fault-notification", +] +stacksize = 2424 +notifications = ["fault", "timer"] +extern-regions = ["sram1", "sram2", "sram3", "sram4"] + +# [tasks.jefe.config.on-state-change] +# net = "jefe-state-change" +# host_sp_comms = "jefe-state-change" +# spd = "jefe-state-change" + +# [tasks.jefe.config.on-task-fault] +# packrat = "task-faulted" + +# [tasks.jefe.config.allowed-callers] +# set_state = ["metro_seq"] +# set_reset_reason = ["sys"] +# request_reset = ["hiffy", "control_plane_agent"] + +# [tasks.net] +# name = "task-net" +# stacksize = 8000 +# priority = 5 +# features = ["mgmt", "h753", "metro", "vlan", "vpd-mac"] +# max-sizes = {flash = 131072, ram = 131072, sram1_mac = 16384} +# default-ram = "dtcm" +# sections = {eth_bulk = "sram1_mac"} +# uses = ["eth", "tim16"] +# start = true +# interrupts = {"eth.irq" = "eth-irq", "tim16.irq" = "mdio-timer-irq"} +# task-slots = ["sys", "packrat", { spi_driver = "spi2_driver" }, "jefe"] +# notifications = ["eth-irq", "mdio-timer-irq", "wake-timer", "jefe-state-change"] + +# [tasks.sys] +# name = "drv-stm32xx-sys" +# features = ["h753", "exti", "no-panic"] +# priority = 1 +# uses = ["rcc", "gpios", "system_flash", "syscfg", "exti"] +# start = true +# task-slots = ["jefe"] +# notifications = ["exti-wildcard-irq"] + +# [tasks.sys.interrupts] +# "exti.exti0" = "exti-wildcard-irq" +# "exti.exti1" = "exti-wildcard-irq" +# "exti.exti2" = "exti-wildcard-irq" +# "exti.exti3" = "exti-wildcard-irq" +# "exti.exti4" = "exti-wildcard-irq" +# "exti.exti9_5" = "exti-wildcard-irq" +# "exti.exti15_10" = "exti-wildcard-irq" + +# [tasks.sys.config.gpio-irqs.rot_irq] +# port = "F" +# pin = 2 +# owner = {name = "sprot", notification = "rot_irq"} + +# [tasks.sys.config.gpio-irqs.seq_irq] +# # FPGA1_TO_SP_IRQ1_L +# port = "F" +# pin = 5 +# owner = {name = "metro_seq", notification = "seq_irq"} + +# [tasks.spi2_driver] +# name = "drv-stm32h7-spi-server" +# priority = 3 +# max-sizes = {flash = 16384, ram = 4096} +# features = ["spi2", "h753"] +# uses = ["spi2"] +# start = true +# interrupts = {"spi2.irq" = "spi-irq"} +# stacksize = 872 +# task-slots = ["sys"] +# notifications = ["spi-irq"] + +# # XXX this is only used by metro_seq; could we merge it? +# [tasks.spi3_driver] +# name = "drv-stm32h7-spi-server" +# priority = 3 +# max-sizes = {flash = 16384, ram = 4096} +# features = ["spi3", "h753"] +# uses = ["spi3"] +# start = true +# interrupts = {"spi3.irq" = "spi-irq"} +# stacksize = 872 +# task-slots = ["sys"] +# notifications = ["spi-irq"] + +# [tasks.i2c_driver] +# name = "drv-stm32xx-i2c-server" +# stacksize = 1048 +# features = ["h753"] +# priority = 3 +# uses = ["i2c1", "i2c2", "i2c3", "i2c4"] +# start = true +# task-slots = ["sys"] +# notifications = ["i2c1-irq", "i2c2-irq", "i2c3-irq", "i2c4-irq"] + +# [tasks.i2c_driver.interrupts] +# "i2c1.event" = "i2c1-irq" +# "i2c1.error" = "i2c1-irq" +# "i2c2.event" = "i2c2-irq" +# "i2c2.error" = "i2c2-irq" +# "i2c3.event" = "i2c3-irq" +# "i2c3.error" = "i2c3-irq" +# "i2c4.event" = "i2c4-irq" +# "i2c4.error" = "i2c4-irq" + +# [tasks.packrat] +# name = "task-packrat" +# priority = 1 +# stacksize = 1712 +# start = true +# task-slots = ["jefe"] +# features = ["metro", "ereport"] +# notifications = ["task-faulted"] + +# [tasks.rng_driver] +# features = ["h753", "packrat"] +# name = "drv-stm32h7-rng" +# priority = 6 +# uses = ["rng"] +# start = true +# stacksize = 512 +# task-slots = ["sys", "packrat"] + +# [tasks.thermal] +# name = "task-thermal" +# features = ["metro"] +# priority = 8 +# max-sizes = {flash = 32768, ram = 8192 } +# stacksize = 3000 +# start = true +# task-slots = ["i2c_driver", "sensor", "metro_seq", "jefe"] +# notifications = ["timer"] + +# [tasks.power] +# name = "task-power" +# features = ["metro"] +# priority = 8 +# max-sizes = {flash = 65536, ram = 16384 } +# stacksize = 3800 +# start = true +# task-slots = ["i2c_driver", "sensor", "metro_seq"] +# notifications = ["timer"] + +# [tasks.hiffy] +# name = "task-hiffy" +# features = ["h753", "stm32h7", "i2c", "gpio", "spi", "qspi", "hash", "sprot", "turbo"] +# priority = 7 +# max-sizes = {flash = 32768, ram = 65536 } +# stacksize = 1328 +# start = true +# task-slots = ["sys", "hf", "i2c_driver", "hash_driver", "update_server", "sprot", "net"] +# notifications = ["timer"] + +# [tasks.metro_seq] +# name = "drv-metro-seq-server" +# features = ["h753"] +# priority = 7 +# max-sizes = {flash = 131072, ram = 32768 } +# stacksize = 3200 +# start = true +# task-slots = ["sys", "i2c_driver", {spi_front = "spi3_driver"}, "jefe", "packrat", "auxflash", "spartan7_loader", "hf"] +# uses = ["mmio_sequencer", "mmio_info", "mmio_espi", "mmio_debug_ctrl"] +# notifications = ["timer", "vcore", "seq-irq"] + +# [tasks.ignition_flash] +# name = "drv-ignition-flash" +# priority = 7 +# stacksize = 1200 +# start = true +# task-slots = ["sys", {spi_front = "spi3_driver"}, "spartan7_loader"] +# uses = ["mmio_sequencer"] # TODO make the mux a separate peripheral + +# [tasks.spartan7_loader] +# name = "drv-spartan7-loader" +# features = ["h753"] +# priority = 4 +# max-sizes = {flash = 131072, ram = 16384 } +# stacksize = 2600 +# start = true +# task-slots = ["sys", {spi = "spi2_driver"}, "auxflash"] +# copy-to-archive = ["register_defs"] + +# [tasks.spartan7_loader.config] +# program_l = "sys_api::Port::B.pin(1)" +# init_l = "sys_api::Port::B.pin(6)" +# config_done = "sys_api::Port::B.pin(4)" +# user_reset_l = "sys_api::Port::A.pin(6)" +# register_defs = "metro-seq/*.json" + +# [tasks.hash_driver] +# name = "drv-stm32h7-hash-server" +# features = ["h753"] +# priority = 2 +# max-sizes = {flash = 16384, ram=4096 } +# stacksize = 2048 +# start = true +# uses = ["hash"] +# interrupts = {"hash.irq" = "hash-irq"} +# task-slots = ["sys"] +# notifications = ["hash-irq"] + +# [tasks.hf] +# name = "drv-metro-hf" +# priority = 6 +# start = true +# uses = ["mmio_spi_nor"] +# task-slots = ["hash_driver", "spartan7_loader"] +# stacksize = 4000 +# notifications = ["timer"] + +# [tasks.update_server] +# name = "stm32h7-update-server" +# priority = 3 +# max-sizes = {flash = 16384, ram = 4096} +# stacksize = 2048 +# start = true +# uses = ["flash_controller"] +# extern-regions = ["bank2"] +# interrupts = {"flash_controller.irq" = "flash-irq"} +# notifications = ["flash-irq"] + +# [tasks.sensor] +# name = "task-sensor" +# priority = 4 +# max-sizes = {flash = 16384, ram = 16384 } +# stacksize = 1024 +# start = true + +# [tasks.host_sp_comms] +# name = "task-host-sp-comms" +# features = ["stm32h753", "usart6", "baud_rate_3M", "hardware_flow_control", "vlan", "metro"] +# uses = ["usart6", "dbgmcu"] +# interrupts = {"usart6.irq" = "usart-irq"} +# priority = 9 +# max-sizes = {flash = 78000, ram = 65536} +# stacksize = 7664 +# start = true +# task-slots = ["sys", { cpu_seq = "metro_seq" }, "hf", "control_plane_agent", "net", "packrat", "i2c_driver", { spi_driver = "spi2_driver" }, "sprot", "auxflash"] +# notifications = ["jefe-state-change", "usart-irq", "multitimer", "control-plane-agent"] + +# [tasks.udpecho] +# name = "task-udpecho" +# priority = 6 +# max-sizes = {flash = 16384, ram = 8192} +# stacksize = 4096 +# start = true +# task-slots = ["net"] +# features = ["vlan"] +# notifications = ["socket"] + +# [tasks.udpbroadcast] +# name = "task-udpbroadcast" +# priority = 6 +# max-sizes = {flash = 16384, ram = 8192} +# stacksize = 2048 +# start = true +# task-slots = ["net", "packrat"] +# features = ["vlan"] +# notifications = ["socket"] + +# [tasks.control_plane_agent] +# name = "task-control-plane-agent" +# priority = 8 +# stacksize = 7000 +# start = true +# uses = ["usart1"] +# task-slots = [ +# "auxflash", +# "jefe", +# "dump_agent", +# "net", +# "update_server", +# "sys", +# "hf", +# { cpu_seq = "metro_seq" }, +# "validate", +# "sensor", +# "sprot", +# "i2c_driver", +# "packrat", +# "user_leds", +# "vpd", +# ] +# features = [ +# "metro", +# "usart1", +# "vlan", +# "baud_rate_3M", +# "vpd", +# "auxflash", +# ] +# notifications = ["usart-irq", "socket", "timer"] +# interrupts = {"usart1.irq" = "usart-irq"} + +# [tasks.sprot] +# name = "drv-stm32h7-sprot-server" +# priority = 4 +# max-sizes = {flash = 65536, ram = 32768} +# stacksize = 16384 +# start = true +# task-slots = ["sys"] +# features = ["sink_test", "use-spi-core", "h753", "spi5"] +# uses = ["spi5"] +# notifications = ["spi-irq", "rot-irq", "timer"] +# interrupts = {"spi5.irq" = "spi-irq"} + +# [tasks.validate] +# name = "task-validate" +# priority = 5 +# max-sizes = {flash = 16384, ram = 4096 } +# stacksize = 1000 +# start = true +# task-slots = ["i2c_driver"] + +# [tasks.vpd] +# name = "task-vpd" +# priority = 4 +# max-sizes = {flash = 8192, ram = 1024} +# start = true +# task-slots = ["sys", "i2c_driver"] +# stacksize = 800 + +# [tasks.user_leds] +# name = "drv-user-leds" +# features = ["stm32h7"] +# priority = 2 +# max-sizes = {flash = 2048, ram = 1024} +# start = true +# task-slots = ["sys"] +# notifications = ["timer"] + +# [tasks.dump_agent] +# name = "task-dump-agent" +# priority = 6 +# max-sizes = {flash = 32768, ram = 16384 } +# start = true +# task-slots = ["sprot", "jefe", "net"] +# stacksize = 2400 +# extern-regions = ["sram1", "sram2", "sram3", "sram4"] +# notifications = ["socket"] +# features = ["net", "vlan"] + +# [tasks.snitch] +# name = "task-snitch" +# # The snitch should have a priority immediately below that of the net task, +# # to minimize the number of components that can starve it from resources. +# priority = 6 +# stacksize = 1200 +# start = true +# task-slots = ["net", "packrat"] +# features = ["vlan"] +# notifications = ["socket"] + +# [tasks.spd] +# name = "task-metro-spd" +# priority = 7 +# max-sizes = {flash = 8192, ram = 4096 } +# start = true +# notifications = ["jefe-state-change", "timer"] +# task-slots = ["jefe", "spartan7_loader", "packrat", "sensor"] +# uses = ["mmio_dimms"] +# stacksize = 976 + +# [tasks.auxflash] +# name = "drv-auxflash-server" +# priority = 3 +# max-sizes = {flash = 32768, ram = 4096} +# features = ["h753", "fast-qspi"] +# uses = ["quadspi"] +# start = true +# notifications = ["qspi-irq"] +# interrupts = {"quadspi.irq" = "qspi-irq"} +# stacksize = 3504 +# task-slots = ["sys"] + +[tasks.idle] +name = "task-idle" +priority = 15 +max-sizes = {flash = 128, ram = 256} +stacksize = 256 +start = true + +# [config] + +# # +# # From Cosmo Rev-B +# # + +# # +# # I2C1: Front FPGA I2C mux +# # +# [[config.i2c.controllers]] +# controller = 1 + +# # +# # SMBUS_SP_TO_FPGA2_SMCLK +# # SMBUS_SP_TO_FPGA2_SMDAT +# # +# [config.i2c.controllers.ports.B] +# name = "front" +# description = "Front FPGA mux" +# scl.pin = 8 +# sda.pin = 9 +# af = 4 + +# # The front FPGA has one sixteen-channel virtual mux +# [[config.i2c.controllers.ports.B.muxes]] +# driver = "oximux16" +# address = 0x70 +# # The reset line is SP_TO_FPGA2_I2C_MUX_RESET on rev2+ boards +# nreset = { port = "B", pin = 10 } + + +# # +# # I2C2: Main FPGA I2C mux +# # +# [[config.i2c.controllers]] +# controller = 2 + + +# # +# # I2C_SP_TO_FPGA1_SCL +# # I2C_SP_TO_FPGA1_SDA +# # +# [config.i2c.controllers.ports.F] +# name = "main" +# description = "Main FPGA mux" +# scl.pin = 1 +# sda.pin = 0 +# af = 4 + +# # The main FPGA has one sixteen-channel virtual mux +# [[config.i2c.controllers.ports.F.muxes]] +# driver = "oximux16" +# address = 0x70 +# # The reset line is FPGA1_TO_SP_MISC_A on rev A and SP_TO_FPGA1_I2C_MUX_RESET on +# # subsequent revisions (but has the same physical pin) +# nreset = { port = "H", pin = 9 } + +# # +# # I2C3: Mid bus +# # +# [[config.i2c.controllers]] +# controller = 3 + +# # +# # SMBUS_SP_TO_MID_SMCLK_A2 +# # SMBUS_SP_TO_MID_SMDAT_A2 +# # +# [config.i2c.controllers.ports.H] +# name = "mid" +# description = "Mid bus" +# scl.pin = 7 +# sda.pin = 8 +# af = 4 + +# # +# # I2C4: Rear bus +# # +# [[config.i2c.controllers]] +# controller = 4 + +# # +# # SMBUS_SP_TO_REAR_SMCLK_A2 +# # SMBUS_SP_TO_REAR_SMDAT_A2 +# # +# [config.i2c.controllers.ports.F] +# name = "rear" +# description = "Rear bus" +# scl.pin = 14 +# sda.pin = 15 +# af = 4 + +# ################################################################################ + +# # The `front` bus is managed by FPGA2, which impersonates a set of muxes +# # The connection between SP and FPGA is SMBUS_SP_TO_FPGA2 +# [[config.i2c.devices]] +# bus = "front" +# address = 0x70 +# device = "oximux16" +# description = "Front FPGA virtual mux" +# refdes = ["U31"] +# # TODO Audit i2c devices using validate-with-raw-read. +# # https://github.com/oxidecomputer/hubris/issues/2629 +# validate-with-raw-read = true + +# # Welcome to the sharkfin zone +# # SMBUS_FPGA2_TO_CEMA +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 1 +# address = 0b1010_000 +# device = "at24csw080" +# description = "U.2 Sharkfin A VPD" +# name = "sharkfin_a_vpd" +# refdes = ["J200", "U2"] +# removable = true + +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 1 +# address = 0b0111_000 +# device = "max5970" +# description = "U.2 Sharkfin A hot swap controller" +# power = { rails = [ "V12_U2A_A0", "V3P3_U2A_A0" ], pmbus = false } +# sensors = { voltage = 2, current = 2 } +# name = "sharkfin_a_hsc" +# refdes = ["J200", "U1"] +# removable = true + +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 1 +# address = 0b110_1010 +# device = "nvme_bmc" +# description = "U.2 A NVMe Basic Management Command" +# sensors = { temperature = 1 } +# name = "U2_N0" +# refdes = ["J200", "J2"] +# removable = true + +# # SMBUS_FPGA2_TO_CEMB +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 2 +# address = 0b1010_000 +# device = "at24csw080" +# description = "U.2 Sharkfin B VPD" +# name = "sharkfin_b_vpd" +# refdes = ["J201", "U2"] +# removable = true + +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 2 +# address = 0b0111_000 +# device = "max5970" +# description = "U.2 Sharkfin B hot swap controller" +# power = { rails = [ "V12_U2B_A0", "V3P3_U2B_A0" ], pmbus = false } +# sensors = { voltage = 2, current = 2 } +# name = "sharkfin_b_hsc" +# refdes = ["J201", "U1"] +# removable = true + +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 2 +# address = 0b110_1010 +# device = "nvme_bmc" +# description = "U.2 B NVMe Basic Management Control" +# sensors = { temperature = 1 } +# name = "U2_N1" +# refdes = ["J201", "J2"] +# removable = true + +# # SMBUS_FPGA2_TO_CEMC +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 3 +# address = 0b1010_000 +# device = "at24csw080" +# description = "U.2 Sharkfin C VPD" +# name = "sharkfin_c_vpd" +# refdes = ["J202", "U2"] +# removable = true + +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 3 +# address = 0b0111_000 +# device = "max5970" +# description = "U.2 Sharkfin C hot swap controller" +# power = { rails = [ "V12_U2C_A0", "V3P3_U2C_A0" ], pmbus = false } +# sensors = { voltage = 2, current = 2 } +# name = "sharkfin_c_hsc" +# refdes = ["J202", "U1"] +# removable = true + +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 3 +# address = 0b110_1010 +# device = "nvme_bmc" +# description = "U.2 C NVMe Basic Management Control" +# sensors = { temperature = 1 } +# name = "U2_N2" +# refdes = ["J202", "J2"] +# removable = true + +# # SMBUS_FPGA2_TO_CEMD +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 4 +# address = 0b1010_000 +# device = "at24csw080" +# description = "U.2 Sharkfin D VPD" +# name = "sharkfin_d_vpd" +# refdes = ["J203", "U2"] +# removable = true + +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 4 +# address = 0b0111_000 +# device = "max5970" +# description = "U.2 Sharkfin D hot swap controller" +# power = { rails = [ "V12_U2D_A0", "V3P3_U2D_A0" ], pmbus = false } +# sensors = { voltage = 2, current = 2 } +# name = "sharkfin_d_hsc" +# refdes = ["J203", "U1"] +# removable = true + +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 4 +# address = 0b110_1010 +# device = "nvme_bmc" +# description = "U.2 D NVMe Basic Management Control" +# sensors = { temperature = 1 } +# name = "U2_N3" +# refdes = ["J203", "J2"] +# removable = true + +# # SMBUS_FPGA2_TO_CEME +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 5 +# address = 0b1010_000 +# device = "at24csw080" +# description = "U.2 Sharkfin E VPD" +# name = "sharkfin_e_vpd" +# refdes = ["J204", "U2"] +# removable = true + +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 5 +# address = 0b0111_000 +# device = "max5970" +# description = "U.2 Sharkfin E hot swap controller" +# power = { rails = [ "V12_U2E_A0", "V3P3_U2E_A0" ], pmbus = false } +# sensors = { voltage = 2, current = 2 } +# name = "sharkfin_e_hsc" +# refdes = ["J204", "U1"] +# removable = true + +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 5 +# address = 0b110_1010 +# device = "nvme_bmc" +# description = "U.2 E NVMe Basic Management Control" +# sensors = { temperature = 1 } +# name = "U2_N4" +# refdes = ["J204", "J2"] +# removable = true + +# # SMBUS_FPGA2_TO_CEMF +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 6 +# address = 0b1010_000 +# device = "at24csw080" +# description = "U.2 Sharkfin F VPD" +# name = "sharkfin_f_vpd" +# refdes = ["J205", "U2"] +# removable = true + +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 6 +# address = 0b0111_000 +# device = "max5970" +# description = "U.2 Sharkfin F hot swap controller" +# power = { rails = [ "V12_U2F_A0", "V3P3_U2F_A0" ], pmbus = false } +# sensors = { voltage = 2, current = 2 } +# name = "sharkfin_f_hsc" +# refdes = ["J205", "U1"] +# removable = true + +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 6 +# address = 0b110_1010 +# device = "nvme_bmc" +# description = "U.2 F NVMe Basic Management Control" +# sensors = { temperature = 1 } +# name = "U2_N5" +# refdes = ["J205", "J2"] +# removable = true + +# # Note that we skip segments 7 and 8, which are +# # I2C_FPGA2_TO_MCIO1 and I2C_FPGA2_TO_MCIO2 + +# # SMBUS_FPGA2_TO_CEMG +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 9 +# address = 0b1010_000 +# device = "at24csw080" +# description = "U.2 Sharkfin G VPD" +# name = "sharkfin_g_vpd" +# refdes = ["J206", "U2"] +# removable = true + +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 9 +# address = 0b0111_000 +# device = "max5970" +# description = "U.2 Sharkfin G hot swap controller" +# power = { rails = [ "V12_U2G_A0", "V3P3_U2G_A0" ], pmbus = false } +# sensors = { voltage = 2, current = 2 } +# name = "sharkfin_g_hsc" +# refdes = ["J206", "U1"] +# removable = true + +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 9 +# address = 0b110_1010 +# device = "nvme_bmc" +# description = "U.2 G NVMe Basic Management Control" +# sensors = { temperature = 1 } +# name = "U2_N6" +# refdes = ["J206", "J2"] +# removable = true + + + +# # SMBUS_FPGA2_TO_CEMH +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 10 +# address = 0b1010_000 +# device = "at24csw080" +# description = "U.2 Sharkfin H VPD" +# name = "sharkfin_h_vpd" +# refdes = ["J207", "U2"] +# removable = true + +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 10 +# address = 0b0111_000 +# device = "max5970" +# description = "U.2 Sharkfin H hot swap controller" +# power = { rails = [ "V12_U2H_A0", "V3P3_U2H_A0" ], pmbus = false } +# sensors = { voltage = 2, current = 2 } +# name = "sharkfin_h_hsc" +# refdes = ["J207", "U1"] +# removable = true + +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 10 +# address = 0b110_1010 +# device = "nvme_bmc" +# description = "U.2 H NVMe Basic Management Control" +# sensors = { temperature = 1 } +# name = "U2_N7" +# refdes = ["J207", "J2"] +# removable = true + +# # SMBUS_FPGA2_TO_CEMI +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 11 +# address = 0b1010_000 +# device = "at24csw080" +# description = "U.2 Sharkfin I VPD" +# name = "sharkfin_i_vpd" +# refdes = ["J208", "U2"] +# removable = true + +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 11 +# address = 0b0111_000 +# device = "max5970" +# description = "U.2 Sharkfin I hot swap controller" +# power = { rails = [ "V12_U2I_A0", "V3P3_U2I_A0" ], pmbus = false } +# sensors = { voltage = 2, current = 2 } +# name = "sharkfin_i_hsc" +# refdes = ["J208", "U1"] +# removable = true + +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 11 +# address = 0b110_1010 +# device = "nvme_bmc" +# description = "U.2 I NVMe Basic Management Control" +# sensors = { temperature = 1 } +# name = "U2_N8" +# refdes = ["J208", "J2"] +# removable = true + +# # SMBUS_FPGA2_TO_CEMJ +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 12 +# address = 0b1010_000 +# device = "at24csw080" +# description = "U.2 Sharkfin J VPD" +# name = "sharkfin_j_vpd" +# refdes = ["J209", "U2"] +# removable = true + +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 12 +# address = 0b0111_000 +# device = "max5970" +# description = "U.2 Sharkfin J hot swap controller" +# power = { rails = [ "V12_U2J_A0", "V3P3_U2J_A0" ], pmbus = false } +# sensors = { voltage = 2, current = 2 } +# name = "sharkfin_j_hsc" +# refdes = ["J209", "U1"] +# removable = true + +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 12 +# address = 0b110_1010 +# device = "nvme_bmc" +# description = "U.2 J NVMe Basic Management Control" +# sensors = { temperature = 1 } +# name = "U2_N9" +# refdes = ["J209", "J2"] +# removable = true +# # you are now leaving the sharkfin zone + +# # SMBUS_FPGA2_TO_FRONT +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 13 +# address = 0x48 +# device = "tmp117" +# name = "Southwest" +# description = "Southwest temperature sensor" +# sensors = { temperature = 1 } +# removable = true +# refdes = ["J44", "U1"] + +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 13 +# address = 0x49 +# device = "tmp117" +# name = "South" +# description = "South temperature sensor" +# sensors = { temperature = 1 } +# removable = true +# refdes = ["J45", "U1"] + +# [[config.i2c.devices]] +# bus = "front" +# mux = 1 +# segment = 13 +# address = 0x4a +# device = "tmp117" +# name = "Southeast" +# description = "Southeast temperature sensor" +# sensors = { temperature = 1 } +# removable = true +# refdes = ["J46", "U1"] + +# ################################################################################ + +# # The `main` bus is managed by FPGA1, which impersonates a set of muxes +# # The connection between SP and FPGA is I2C_SP_TO_FPGA1 +# [[config.i2c.devices]] +# bus = "main" +# address = 0x70 +# device = "oximux16" +# description = "Main FPGA virtual mux" +# refdes = ["U27", "MUX"] +# # TODO Audit i2c devices using validate-with-raw-read. +# # https://github.com/oxidecomputer/hubris/issues/2629 +# validate-with-raw-read = true + +# # SMBUS_FPGA1_TO_M2A +# [[config.i2c.devices]] +# bus = "main" +# mux = 1 +# segment = 1 +# address = 0b110_1010 +# device = "nvme_bmc" +# description = "M.2 A NVMe Basic Management Command" +# name = "M2_A" +# sensors = { temperature = 1 } +# removable = true +# refdes = "J210" + +# # SMBUS_FPGA1_TO_M2B +# [[config.i2c.devices]] +# bus = "main" +# mux = 1 +# segment = 2 +# address = 0b110_1010 +# device = "nvme_bmc" +# description = "M.2 B NVMe Basic Management Command" +# name = "M2_B" +# sensors = { temperature = 1 } +# removable = true +# refdes = "J211" + +# # Segment 3 is unused + +# [[config.i2c.devices]] +# bus = "main" +# mux = 1 +# segment = 4 +# address = 0x3c +# device = "sbrmi" +# name = "RMI" +# description = "CPU via SB-RMI" +# refdes = ["U1", "SBRMI"] + +# [[config.i2c.devices]] +# bus = "main" +# mux = 1 +# segment = 4 +# address = 0x4c +# device = "sbtsi" +# name = "CPU" +# description = "CPU temperature sensor" +# sensors = { temperature = 1 } +# refdes = ["U1", "SBTSI"] + +# # Segment 5 is SEC_SP5_TO_FPGA1 +# # Segment 6 is unused + +# # I2C_FPGA1_TO_FAN_VPD +# [[config.i2c.devices]] +# bus = "main" +# mux = 1 +# segment = 7 +# address = 0b1010_000 +# device = "at24csw080" +# eeprom-vpd = "sled-fan-tray" +# description = "Fan VPD" +# refdes = ["J34", "U1"] +# name = "fan_vpd" +# removable = true + +# # SMBUS_FPGA1_TO_NIC_THERM +# [[config.i2c.devices]] +# bus = "main" +# mux = 1 +# segment = 8 +# address = 0x4c +# device = "tmp451" +# name = "t6" +# sensors = { temperature = 1 } +# description = "T6 temperature sensor" +# refdes = "U53" + +# # XXX DIMM temperature sensors are on this bus, proxied by the FPGA + +# ################################################################################ +# # mid bus, on SMBUS_SP_TO_MID_SMCLK_A2 and SMBUS_SP_TO_MID_SMDAT_A2 +# [[config.i2c.devices]] +# bus = "mid" +# address = 0x24 +# device = "tps546b24a" +# description = "A2 3.3V rail" +# power = { rails = [ "V3P3_SP_A2" ] } +# sensors = { temperature = 1, voltage = 1, current = 1 } +# refdes = "U82" +# name = "v3p3_sp_a2" + +# [[config.i2c.devices]] +# bus = "mid" +# address = 0x27 +# device = "tps546b24a" +# description = "A2 5V rail" +# power = { rails = [ "V5_SYS_A2" ] } +# sensors = { temperature = 1, voltage = 1, current = 1 } +# refdes = "U83" +# name = "v5p0_sys_a2" + +# [[config.i2c.devices]] +# bus = "mid" +# address = 0x29 +# device = "tps546b24a" +# description = "A2 1.8V rail" +# power = { rails = [ "V1P8_SYS_A2" ] } +# sensors = { temperature = 1, voltage = 1, current = 1 } +# refdes = "U81" +# name = "v1p8_sys_a2" + +# [[config.i2c.devices]] +# bus = "mid" +# address = 0x3a +# device = "max5970" +# name = "m2" +# description = "M.2 hot plug controller" +# power = { rails = [ "V3P3_M2A_A0HP", "V3P3_M2B_A0HP" ], pmbus = false } +# sensors = { voltage = 2, current = 2 } +# refdes = "U15" + +# [[config.i2c.devices]] +# bus = "mid" +# address = 0x54 +# device = "ltc4282" +# name = "mcio" +# description = "12V MCIO hot plug controller" +# power = { rails = ["V12_MCIO_A0HP"], pmbus = false } +# sensors = { voltage = 1, current = 1 } +# refdes = "U16" + +# [[config.i2c.devices]] +# bus = "mid" +# address = 0x56 +# device = "ltc4282" +# name = "dimm_hsc_ghijkl" +# description = "DIMM GHIJKL hot plug controller" +# power = { rails = ["V12_DDR5_GHIJKL_A0"], pmbus = false } +# sensors = { voltage = 1, current = 1 } +# refdes = "U42" + +# [[config.i2c.devices]] +# bus = "mid" +# address = 0x55 +# device = "ltc4282" +# name = "dimm_hsc_abcdef" +# description = "DIMM ABCDEF hot plug controller" +# power = { rails = ["V12_DDR5_ABCDEF_A0"], pmbus = false } +# sensors = { voltage = 1, current = 1 } +# refdes = "U127" + +# [[config.i2c.devices]] +# bus = "mid" +# address = 0x75 +# device = "raa229620a" +# description = "South power controller (Core 0, SOC)" +# power.rails = [ "VDDCR_CPU0_A0", "VDDCR_SOC_A0" ] +# power.phases = [ [ 0, 1, 2, 3, 4, 5, 6, 7 ], [ 8, 9, 10, 11 ] ] +# sensors = { temperature = 2, power = 2, voltage = 2, current = 2 } +# refdes = "U90" + +# [[config.i2c.devices]] +# bus = "mid" +# address = 0x76 +# device = "raa229620a" +# description = "North power controller (Core 1, VDDIO)" +# power.rails = [ "VDDCR_CPU1_A0", "VDDIO_SP5_A0" ] +# power.phases = [ [ 0, 1, 2, 3, 4, 5, 6, 7 ], [ 8, 9, 10, 11 ] ] +# sensors = { temperature = 2, power = 2, voltage = 2, current = 2 } +# refdes = "U103" + +# [[config.i2c.devices]] +# bus = "mid" +# address = 0x5c +# device = "isl68224" +# description = "SP5 power controller (V1P1, V1P8, V3P3)" +# power.rails = [ "V1P1_SP5_A0", "V1P8_SP5_A1", "V3P3_SP5_A1" ] +# power.phases = [ [ 0, 1, 2 ], [ 3 ], [ 4 ] ] +# sensors = { voltage = 3, current = 3 } # XXX add temperature sensors? +# refdes = "U116" + +# ################################################################################ + +# [[config.i2c.devices]] +# bus = "rear" +# address = 0x39 +# device = "max5970" +# description = "NIC hot swap" +# power = { rails = [ "V12P0_NIC_A0HP", "V5P0_NIC_A0HP" ], pmbus = false } +# sensors = { voltage = 2, current = 2 } +# refdes = "U54" + +# [[config.i2c.devices]] +# bus = "rear" +# address = 0x25 +# device = "tps546b24a" +# description = "T6 power controller" +# power = { rails = [ "V0P96_NIC_VDD_A0HP" ] } +# sensors = { temperature = 1, voltage = 1, current = 1 } +# refdes = "U123" +# name = "v0p96_nic" + +# [[config.i2c.devices]] +# bus = "rear" +# address = 0x48 +# device = "tmp117" +# name = "Northwest" +# description = "Northwest temperature sensor" +# sensors = { temperature = 1 } +# removable = true +# refdes = ["J47", "U1"] + +# [[config.i2c.devices]] +# bus = "rear" +# address = 0x49 +# device = "tmp117" +# name = "North" +# description = "North temperature sensor" +# sensors = { temperature = 1 } +# removable = true +# refdes = ["J48", "U1"] + +# [[config.i2c.devices]] +# bus = "rear" +# address = 0x4a +# device = "tmp117" +# name = "Northeast" +# description = "Northeast temperature sensor" +# sensors = { temperature = 1 } +# removable = true +# refdes = ["J49", "U1"] + +# [[config.i2c.devices]] +# bus = "rear" +# address = 0x20 +# device = "max31790" +# description = "Fan controller" +# sensors = { speed = 6, names = [ +# "Southeast", "Northeast", "South", "North", "Southwest", "Northwest" +# ] } +# refdes = "U58" + +# [[config.i2c.devices]] +# bus = "rear" +# address = 0x67 +# device = "bmr491" +# name = "IBC" +# description = "Intermediate bus converter" +# power = { rails = [ "V12_SYS_A2" ] } +# sensors = { temperature = 1, voltage = 1, current = 1 } +# refdes = "U80" + +# [[config.i2c.devices]] +# bus = "rear" +# address = 0b1010_000 +# device = "at24csw080" +# name = "local_vpd" +# description = "Metro VPD" +# refdes = "U32" + +# # The `rear` bus also spans the isolation barrier to the 54V zone. On the other +# # side of the isolation barrier, data is split between a shared SDAI line +# # (SMBUS_SP_TO_REAR_SMDAT_ISO) and per-HSC SDAO lines. + +# # SMBUS_SP_TO_REAR_SMDAT_ISO +# # SMBUS_FAN_EAST_HSC_TO_SP_SMDAT_ISO +# [[config.i2c.devices]] +# bus = "rear" +# address = 0x11 +# device = "lm5066i" +# description = "Fan hot swap controller (east)" +# power = { rails = [ "V54P5_FAN_EAST" ] } +# sensors = { temperature = 1, voltage = 1, current = 1 } +# refdes = "U71" + +# # SMBUS_SP_TO_REAR_SMDAT_ISO +# # SMBUS_FAN_CENTRAL_HSC_TO_SP_SMDAT_ISO +# [[config.i2c.devices]] +# bus = "rear" +# address = 0x12 +# device = "lm5066i" +# description = "Fan hot swap controller (central)" +# power = { rails = [ "V54P5_FAN_CENTRAL" ] } +# sensors = { temperature = 1, voltage = 1, current = 1 } +# refdes = "U72" + +# # SMBUS_SP_TO_REAR_SMDAT_ISO +# # SMBUS_FAN_WEST_HSC_TO_SP_SMDAT_ISO +# [[config.i2c.devices]] +# bus = "rear" +# address = 0x13 +# device = "lm5066i" +# description = "Fan hot swap controller (west)" +# power = { rails = [ "V54P5_FAN_WEST" ] } +# sensors = { temperature = 1, voltage = 1, current = 1 } +# refdes = "U73" + +# # SMBUS_SP_TO_REAR_SMDAT_ISO +# # SMBUS_MAIN_HSC_TO_SP_SMDAT_ISO +# [[config.i2c.devices]] +# bus = "rear" +# address = 0x14 +# device = "adm127x" +# description = "Sled hot swap controller" +# power = { rails = [ "V54P5_IBC_A3" ] } +# sensors = { temperature = 1, voltage = 1, current = 1 } +# refdes = "U79" + +# [[config.sensor.devices]] +# name = "A_TS0" +# device = "dimm" +# description = "DIMM A, sensor 0" +# sensors.temperature = 1 +# refdes = "J101" + +# [[config.sensor.devices]] +# name = "A_TS1" +# device = "dimm" +# description = "DIMM A, sensor 1" +# sensors.temperature = 1 +# refdes = "J101" + +# [[config.sensor.devices]] +# name = "B_TS0" +# device = "dimm" +# description = "DIMM B, sensor 0" +# sensors.temperature = 1 +# refdes = "J102" + +# [[config.sensor.devices]] +# name = "B_TS1" +# device = "dimm" +# description = "DIMM B, sensor 1" +# sensors.temperature = 1 +# refdes = "J102" + +# [[config.sensor.devices]] +# name = "C_TS0" +# device = "dimm" +# description = "DIMM C, sensor 0" +# sensors.temperature = 1 +# refdes = "J103" + +# [[config.sensor.devices]] +# name = "C_TS1" +# device = "dimm" +# description = "DIMM C, sensor 1" +# sensors.temperature = 1 +# refdes = "J103" + +# [[config.sensor.devices]] +# name = "D_TS0" +# device = "dimm" +# description = "DIMM D, sensor 0" +# sensors.temperature = 1 +# refdes = "J104" + +# [[config.sensor.devices]] +# name = "D_TS1" +# device = "dimm" +# description = "DIMM D, sensor 1" +# sensors.temperature = 1 +# refdes = "J104" + +# [[config.sensor.devices]] +# name = "E_TS0" +# device = "dimm" +# description = "DIMM E, sensor 0" +# sensors.temperature = 1 +# refdes = "J105" + +# [[config.sensor.devices]] +# name = "E_TS1" +# device = "dimm" +# description = "DIMM E, sensor 1" +# sensors.temperature = 1 +# refdes = "J105" + +# [[config.sensor.devices]] +# name = "F_TS0" +# device = "dimm" +# description = "DIMM F, sensor 0" +# sensors.temperature = 1 +# refdes = "J106" + +# [[config.sensor.devices]] +# name = "F_TS1" +# device = "dimm" +# description = "DIMM F, sensor 1" +# sensors.temperature = 1 +# refdes = "J106" + +# [[config.sensor.devices]] +# name = "G_TS0" +# device = "dimm" +# description = "DIMM G, sensor 0" +# sensors.temperature = 1 +# refdes = "J107" + +# [[config.sensor.devices]] +# name = "G_TS1" +# device = "dimm" +# description = "DIMM G, sensor 1" +# sensors.temperature = 1 +# refdes = "J107" + +# [[config.sensor.devices]] +# name = "H_TS0" +# device = "dimm" +# description = "DIMM H, sensor 0" +# sensors.temperature = 1 +# refdes = "J108" + +# [[config.sensor.devices]] +# name = "H_TS1" +# device = "dimm" +# description = "DIMM H, sensor 1" +# sensors.temperature = 1 +# refdes = "J108" + +# [[config.sensor.devices]] +# name = "I_TS0" +# device = "dimm" +# description = "DIMM I, sensor 0" +# sensors.temperature = 1 +# refdes = "J109" + +# [[config.sensor.devices]] +# name = "I_TS1" +# device = "dimm" +# description = "DIMM I, sensor 1" +# sensors.temperature = 1 +# refdes = "J109" + +# [[config.sensor.devices]] +# name = "J_TS0" +# device = "dimm" +# description = "DIMM J, sensor 0" +# sensors.temperature = 1 +# refdes = "J110" + +# [[config.sensor.devices]] +# name = "J_TS1" +# device = "dimm" +# description = "DIMM J, sensor 1" +# sensors.temperature = 1 +# refdes = "J110" + +# [[config.sensor.devices]] +# name = "K_TS0" +# device = "dimm" +# description = "DIMM K, sensor 0" +# sensors.temperature = 1 +# refdes = "J111" + +# [[config.sensor.devices]] +# name = "K_TS1" +# device = "dimm" +# description = "DIMM K, sensor 1" +# sensors.temperature = 1 +# refdes = "J111" + +# [[config.sensor.devices]] +# name = "L_TS0" +# device = "dimm" +# description = "DIMM L, sensor 0" +# sensors.temperature = 1 +# refdes = "J112" + +# [[config.sensor.devices]] +# name = "L_TS1" +# device = "dimm" +# description = "DIMM L, sensor 1" +# sensors.temperature = 1 +# refdes = "J112" + +# [[config.sensor.devices]] +# name = "fan_ctrl" +# device = "thermal_loop" +# description = "Thermal loop" +# sensors.pwm = 1 +# # XXX(eliza) arguably, we could also use the refdes of the actual fan controller +# # IC here, but we're treating the PWM percentage more as a synthetic property +# # determined by Hubris...and on some boards (such as Sidecar) there are multiple +# # fan controller ICs that all get the same PWM. So, use a generic component name +# # here. +# refdes = "fan_ctrl" + +# ################################################################################ +# [config.spi.spi2] +# controller = 2 + +# # SP_TO_FPGA1_CFG +# # SP_TO_FPGA1_DAT +# [config.spi.spi2.mux_options.port_b] +# outputs = [ +# {port = "B", pins = [13, 15], af = 5}, +# ] +# input = {port = "B", pin = 14, af = 5} + +# [config.spi.spi2.devices.spartan7_fpga] +# mux = "port_b" +# cs = [] +# clock_divider = "DIV8" # 12.5 MHz +# # no CS pin; we're using the SPI peripheral to send synchronized CLK + DATA + +# # SPI_SP_TO_KSZ8463_SCK +# # SPI_SP_TO_KSZ8463_DAT +# # SPI_KSZ8463_TO_SP_DAT +# [config.spi.spi2.mux_options.port_i] +# outputs = [ +# {port = "I", pins = [1, 3], af = 5}, +# ] +# input = {port = "I", pin = 2, af = 5} + +# [config.spi.spi2.devices.ksz8463] +# mux = "port_i" +# cs = [{port = "I", pin = 0}] # SPI_SP_TO_KSZ8463_CS_L + +# ################################################################################ +# # SPI3 goes through a mux controlled by the main FPGA (FPGA1), and can talk to +# # either the front FPGA (FPGA2) or the Ignition flash chip +# [config.spi.spi3] +# controller = 3 + +# # SPI_SP_TO_SP_MUX_SCK (PC10) +# # SPI_SP_TO_SP_MUX_DAT (PB5) +# # SPI_SP_MUX_TO_SP_DAT (PC11) +# [config.spi.spi3.mux_options.port_c] +# outputs = [ +# { port = "C", pins = [10], af = 6}, +# { port = "B", pins = [5], af = 7}, +# ] +# input = {port = "C", pin = 11, af = 6} + +# [config.spi.spi3.devices.mux] +# mux = "port_c" +# cs = [{port = "A", pin = 15}] # SPI_SP_TO_SP_MUX_CS_L + +# ################################################################################ + +# [config.spi.spi5] +# controller = 5 + +# # SPI_SP_TO_ROT_DAT (PJ10) +# # SPI_ROT_TO_SP_DAT (PJ11) +# # SPI_SP_TO_ROT_SCK (PK0) +# [config.spi.spi5.mux_options.port_j] +# outputs = [ +# {port = "J", pins = [10], af = 5}, +# {port = "K", pins = [0], af = 5}, +# ] +# input = {port = "J", pin = 11, af = 5} + +# # SPI_SP_TO_ROT_CL_L (PK1) +# [config.spi.spi5.devices.rot] +# mux = "port_j" +# cs = [{port = "K", pin = 1}] +# clock_divider = "DIV256" + +# ################################################################################ + +# # VLAN configuration +# [config.net.vlans.sidecar1] +# vid = 0x301 +# trusted = true +# port = 1 + +# [config.net.vlans.sidecar2] +# vid = 0x302 +# trusted = true +# port = 2 + +# # UDP ports in sockets below are assigned in oxidecomputer/oana + +# [config.net.sockets.echo] +# kind = "udp" +# owner = {name = "udpecho", notification = "socket"} +# port = 7 +# tx = { packets = 3, bytes = 1024 } +# rx = { packets = 3, bytes = 1024 } + +# [config.net.sockets.broadcast] +# kind = "udp" +# owner = {name = "udpbroadcast", notification = "socket"} +# port = 997 +# tx = { packets = 3, bytes = 1024 } +# rx = { packets = 3, bytes = 1024 } + +# [config.net.sockets.control_plane_agent] +# kind = "udp" +# owner = {name = "control_plane_agent", notification = "socket"} +# port = 11111 +# tx = { packets = 3, bytes = 2048 } +# rx = { packets = 3, bytes = 2048 } + +# [config.net.sockets.dump_agent] +# kind = "udp" +# owner = {name = "dump_agent", notification = "socket"} +# port = 11113 +# tx = { packets = 3, bytes = 1024 } +# rx = { packets = 3, bytes = 1024 } + +# [config.net.sockets.ereport] +# kind = "udp" +# owner = {name = "snitch", notification = "socket"} +# port = 57005 +# tx = { packets = 3, bytes = 1024 } +# # v0 ereport requests are always 35B, so just make the buffer exactly +# # that size... +# rx = { packets = 3, bytes = 35 } + +# [config.auxflash] +# memory-size = 33_554_432 # 256 Mib / 32 MiB +# slot-count = 16 # 2 MiB slots + +# [[auxflash.blobs]] +# file = "drv/spartan7-loader/metro-seq/metro_seq.bz2" +# unzip = "bz2" +# compress = true +# tag = "SPA7" + +# [[auxflash.blobs]] +# file = "drv/metro-seq-server/metro-hp/metro_hp.bz2" +# unzip = "bz2" +# compress = true +# tag = "ICE4" diff --git a/app/metro/build.rs b/app/metro/build.rs new file mode 100644 index 0000000000..7e465bc6b9 --- /dev/null +++ b/app/metro/build.rs @@ -0,0 +1,8 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +fn main() { + build_util::expose_target_board(); + build_util::expose_m_profile().unwrap(); +} diff --git a/app/metro/dev.toml b/app/metro/dev.toml new file mode 100644 index 0000000000..bf89d1e89b --- /dev/null +++ b/app/metro/dev.toml @@ -0,0 +1,48 @@ +# Configuration fragment for -dev images + +# [tasks.jefe.config.allowed-callers] +# request_reset = ["udprpc"] + +# [tasks.udprpc] +# name = "task-udprpc" +# priority = 6 +# max-sizes = {flash = 32768, ram = 8192} +# stacksize = 4096 +# start = true +# task-slots = ["net"] +# features = ["vlan"] +# notifications = ["socket"] + +# [tasks.fmc_demo] +# name = "drv-stm32h7-fmc-demo-server" +# features = ["h753"] +# priority = 6 +# start = true +# task-slots = ["sys", "net"] +# uses = ["fmc_nor_psram_bank_1"] # yolo +# notifications = ["socket"] + +# [config.net.sockets.rpc] +# kind = "udp" +# owner = {name = "udprpc", notification = "socket"} +# port = 998 +# tx = { packets = 3, bytes = 1024 } +# rx = { packets = 3, bytes = 1024 } + +# [tasks.hiffy] +# features = ["net", "vlan"] +# notifications = ["socket"] + +# [config.net.sockets.fmc_test] +# kind = "udp" +# owner = {name = "fmc_demo", notification = "socket"} +# port = 11114 +# tx = { packets = 3, bytes = 4096 } +# rx = { packets = 3, bytes = 4096 } + +# [config.net.sockets.hiffy] +# kind = "udp" +# owner = {name = "hiffy", notification = "socket"} +# port = 11115 +# tx = { packets = 3, bytes = 32 } +# rx = { packets = 1, bytes = 4096 } diff --git a/app/metro/lab.toml b/app/metro/lab.toml new file mode 100644 index 0000000000..a5d3ec2605 --- /dev/null +++ b/app/metro/lab.toml @@ -0,0 +1,3 @@ +# # Configuration fragment for -lab images +# tasks.metro_seq.features = ["stay-in-a2", "enable-backplane-pcie-clk"] +# tasks.packrat.features = ["boot-kmdb"] diff --git a/app/metro/rev-a-dev.toml b/app/metro/rev-a-dev.toml new file mode 100644 index 0000000000..caa96f1078 --- /dev/null +++ b/app/metro/rev-a-dev.toml @@ -0,0 +1,2 @@ +name = "metro-a-dev" +inherit = ["rev-a.toml", "dev.toml"] diff --git a/app/metro/rev-a-lab.toml b/app/metro/rev-a-lab.toml new file mode 100644 index 0000000000..d241a2707c --- /dev/null +++ b/app/metro/rev-a-lab.toml @@ -0,0 +1,2 @@ +name = "metro-a-lab" +inherit = ["rev-a-dev.toml", "lab.toml"] diff --git a/app/metro/rev-a.toml b/app/metro/rev-a.toml new file mode 100644 index 0000000000..32b814a748 --- /dev/null +++ b/app/metro/rev-a.toml @@ -0,0 +1,4 @@ +# This is the production image. We expect `name` to match `board` +name = "metro-a" +board = "metro-a" +inherit = "base.toml" diff --git a/app/metro/src/main.rs b/app/metro/src/main.rs new file mode 100644 index 0000000000..70a81e26d0 --- /dev/null +++ b/app/metro/src/main.rs @@ -0,0 +1,429 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#![no_std] +#![no_main] + +// We have to do this if we don't otherwise use it to ensure its vector table +// gets linked in. +extern crate stm32h7; + +use stm32h7::stm32h753 as device; + +use drv_stm32h7_startup::ClockConfig; + +use cortex_m_rt::entry; + +#[cfg(feature = "traptrace")] +mod tracing; + +#[entry] +fn main() -> ! { + system_init(); + + const CYCLES_PER_MS: u32 = 400_000; + + #[cfg(feature = "traptrace")] + kern::profiling::configure_events_table(tracing::table()); + + unsafe { kern::startup::start_kernel(CYCLES_PER_MS) } +} + +fn system_init() { + let cp = cortex_m::Peripherals::take().unwrap(); + let p = device::Peripherals::take().unwrap(); + + // Check the package we've been flashed on (Metro boards use BGA240) + // + // We need to turn the SYSCFG block on to do this. + p.RCC.apb4enr.modify(|_, w| w.syscfgen().enabled()); + cortex_m::asm::dsb(); + // Now, we can read the appropriately-named package register to find out + // what package we're on. + match p.SYSCFG.pkgr.read().pkg().bits() { + 0b1000 => { + // TFBGA240, yay + } + _ => { + // uh + panic!(); + } + } + + // Metro has resistors strapping three pins to indicate the board revision. + // + // We read the board version very early in boot to try and detect the + // firmware being flashed on the wrong board. In particular, we read the + // version _before_ setting up the clock tree below, just in case we change + // the crystal configuration in a subsequent rev. + // + // Note that the firmware _does not_ adapt to different board revs. We still + // require different firmware per revision; this check serves to detect if + // you've flashed the wrong one, only. + // + // The revision is on pins PG[2:0], with PG2 as the MSB. + + // Un-gate the clock to GPIO bank G. + p.RCC.ahb4enr.modify(|_, w| w.gpiogen().set_bit()); + cortex_m::asm::dsb(); + + // PG2:0 are configured as AF by default, so switch them to inputs. We're + // able to read the pins right away, because they have strong (1K) + // pull-up/down resistors populated on the board. + p.GPIOG.moder.modify(|_, w| { + w.moder0().input(); + w.moder1().input(); + w.moder2().input() + }); + + // Okay! What does the fox^Wpins say? + let rev = p.GPIOG.idr.read().bits() & 0b111; + + cfg_if::cfg_if! { + if #[cfg(target_board = "metro-a")] { + let expected_rev = 0b000; + } + else { + compile_error!("not a recognized metro board") + } + } + + assert_eq!(rev, expected_rev); + + // Do most of the setup with the common implementation. + let p = drv_stm32h7_startup::system_init_custom( + cp, + p, + ClockConfig { + source: drv_stm32h7_startup::ClockSource::ExternalCrystal, + // 8MHz HSE freq is within VCO input range of 2-16, so, DIVM=1 to bypass + // the prescaler. + divm: 1, + // VCO must tolerate an 8MHz input range: + vcosel: device::rcc::pllcfgr::PLL1VCOSEL_A::WIDEVCO, + pllrange: device::rcc::pllcfgr::PLL1RGE_A::RANGE8, + // DIVN governs the multiplication of the VCO input frequency to produce + // the intermediate frequency. We want an IF of 800MHz, or a + // multiplication of 100x. + // + // We subtract 1 to get the DIVN value because the PLL effectively adds + // one to what we write. + divn: 100 - 1, + // P is the divisor from the VCO IF to the system frequency. We want + // 400MHz, so: + divp: device::rcc::pll1divr::DIVP1_A::DIV2, + // Q produces kernel clocks; we set it to 200MHz: + divq: 4 - 1, + // R is mostly used by the trace unit and we leave it fast: + divr: 2 - 1, + + // We run the CPU at the full core rate of 400MHz: + cpu_div: device::rcc::d1cfgr::D1CPRE_A::DIV1, + // We down-shift the AHB by a factor of 2, to 200MHz, to meet its + // constraints: + ahb_div: device::rcc::d1cfgr::HPRE_A::DIV2, + // We configure all APB for 100MHz. These are relative to the AHB + // frequency. + apb1_div: device::rcc::d2cfgr::D2PPRE1_A::DIV2, + apb2_div: device::rcc::d2cfgr::D2PPRE2_A::DIV2, + apb3_div: device::rcc::d1cfgr::D1PPRE_A::DIV2, + apb4_div: device::rcc::d3cfgr::D3PPRE_A::DIV2, + + // Flash runs at 200MHz: 2WS, 2 programming cycles. See reference manual + // Table 13. + flash_latency: 2, + flash_write_delay: 2, + }, + ); + + // Now that our clock tree is configured appropriately, we need to set up + // the external bus to the FPGA. This ensures that we're not relying on any + // particular task to do it, so we can direct-map its peripherals into other + // tasks. If those tasks try to use the peripheral before the FPGA is + // initialized, the peripherals won't work, but the result should not be + // _fatal._ + + // Pin mapping: + // PB7 ADV_L (this is PB2 on the schematic, manually jumpered) + // + // PD0 DA2 + // PD1 DA3 + // PD2 - + // PD3 CLK + // PD4 OE_L + // PD5 WE_L + // PD6 WAIT_L <-- pulled up in hardware + // PD7 CS1_L + // PD8 DA13 + // PD9 DA14 + // PD10 DA15 + // PD11 A16 + // PD12 A17 + // PD13 A18 + // PD14 DA0 + // PD15 DA1 + // + // PE0 BL0_L + // PE1 BL1_L + // PE2 A23 <-- new + // PE3 A19 + // PE4 A20 <-- new + // PE5 A21 <-- new + // PE6 A22 <-- new + // PE7 DA4 + // PE8 DA5 + // PE9 DA6 + // PE10 DA7 + // PE11 DA8 + // PE12 DA9 + // PE13 DA10 + // PE14 DA11 + // PE15 DA12 + // + // Our goal is to put all of these into the appropriate AF setting (which, + // conveniently, is AF12 across all ports) and prepare the memory controller. + + // Ensure clock is enabled to both the GPIO ports we touch, and the FMC + // itself. + p.RCC.ahb3enr.modify(|_, w| w.fmcen().set_bit()); + p.RCC.ahb4enr.modify(|_, w| { + w.gpioben().set_bit(); + w.gpioden().set_bit(); + w.gpioeen().set_bit(); + w + }); + cortex_m::asm::dsb(); + + // Expose all the pins _first._ This seems to work best. + + // GPIOB + p.GPIOB.afrl.modify(|_, w| { + w.afr7().af12(); + w + }); + p.GPIOB.ospeedr.modify(|_, w| { + w.ospeedr7().very_high_speed(); + w + }); + p.GPIOB.moder.modify(|_, w| { + w.moder7().alternate(); + w + }); + + // GPIOD + p.GPIOD.afrl.modify(|_, w| { + w.afr0().af12(); + w.afr1().af12(); + // pin 2 used for something else + w.afr3().af12(); + w.afr4().af12(); + w.afr5().af12(); + w.afr6().af12(); + w.afr7().af12(); + w + }); + p.GPIOD.afrh.modify(|_, w| { + w.afr8().af12(); + w.afr9().af12(); + w.afr10().af12(); + w.afr11().af12(); + w.afr12().af12(); + w.afr13().af12(); + w.afr14().af12(); + w.afr15().af12(); + w + }); + p.GPIOD.ospeedr.modify(|_, w| { + w.ospeedr0().very_high_speed(); + w.ospeedr1().very_high_speed(); + // pin 2 used elsewhere + w.ospeedr3().very_high_speed(); + w.ospeedr4().very_high_speed(); + w.ospeedr5().very_high_speed(); + w.ospeedr6().very_high_speed(); + w.ospeedr7().very_high_speed(); + + w.ospeedr8().very_high_speed(); + w.ospeedr9().very_high_speed(); + w.ospeedr10().very_high_speed(); + w.ospeedr11().very_high_speed(); + w.ospeedr12().very_high_speed(); + w.ospeedr13().very_high_speed(); + w.ospeedr14().very_high_speed(); + w.ospeedr15().very_high_speed(); + w + }); + p.GPIOD.moder.modify(|_, w| { + w.moder0().alternate(); + w.moder1().alternate(); + // pin 2 used elsewhere + w.moder3().alternate(); + w.moder4().alternate(); + w.moder5().alternate(); + w.moder6().alternate(); + w.moder7().alternate(); + + w.moder8().alternate(); + w.moder9().alternate(); + w.moder10().alternate(); + w.moder11().alternate(); + w.moder12().alternate(); + w.moder13().alternate(); + w.moder14().alternate(); + w.moder15().alternate(); + w + }); + + // GPIOE + // NOTE: this implementation only brings up a 20-bit address on the FMC bus, + // because that's what worked on Grapefruit. The hardware supports a 24-bit + // address! + p.GPIOE.afrl.modify(|_, w| { + w.afr0().af12(); + w.afr1().af12(); + w.afr3().af12(); + w.afr7().af12(); + w + }); + p.GPIOE.afrh.modify(|_, w| { + w.afr8().af12(); + w.afr9().af12(); + w.afr10().af12(); + w.afr11().af12(); + w.afr12().af12(); + w.afr13().af12(); + w.afr14().af12(); + w.afr15().af12(); + w + }); + p.GPIOE.ospeedr.modify(|_, w| { + w.ospeedr0().very_high_speed(); + w.ospeedr1().very_high_speed(); + w.ospeedr3().very_high_speed(); + w.ospeedr7().very_high_speed(); + + w.ospeedr8().very_high_speed(); + w.ospeedr9().very_high_speed(); + w.ospeedr10().very_high_speed(); + w.ospeedr11().very_high_speed(); + w.ospeedr12().very_high_speed(); + w.ospeedr13().very_high_speed(); + w.ospeedr14().very_high_speed(); + w.ospeedr15().very_high_speed(); + w + }); + p.GPIOE.moder.modify(|_, w| { + w.moder0().alternate(); + w.moder1().alternate(); + w.moder3().alternate(); + w.moder7().alternate(); + + w.moder8().alternate(); + w.moder9().alternate(); + w.moder10().alternate(); + w.moder11().alternate(); + w.moder12().alternate(); + w.moder13().alternate(); + w.moder14().alternate(); + w.moder15().alternate(); + w + }); + + // Basic memory controller setup: + p.FMC.bcr1.write(|w| { + // Emit clock signal continuously, the FPGA likes that. + w.cclken().set_bit(); + + // Use synchronous bursts for both writes and reads. + w.bursten().set_bit(); + w.cburstrw().set_bit(); + + // Enable wait states. + w.waiten().set_bit(); + // Expect the wait state to be active _during_ a wait, not one cycle + // early. + w.waitcfg().set_bit(); + + // Enable writes through the controller. + w.wren().set_bit(); + + // Disable NOR flash memory access (may not be necessary?) + w.faccen().clear_bit(); + + // Configure the memory as "PSRAM" since that's the closest to the + // behavior we want. + // + // Safety: this enum value is not modeled in the PAC, but is defined in + // the reference manual, so this has no implications for safety. + unsafe { + w.mtyp().bits(0b01); + } + + // Turn on the bank (note that we have not turned on the _controller_ + // still). + w.mbken().set_bit(); + + unsafe { + // Swap the device map so that the default memory map uses device + // memory to avoid speculation + w.bmap().bits(0b01); + } + // The following fields are being deliberately left in their reset + // states: + // - FMCEN is being left off + // - Write FIFO is being left on (TODO is this correct?) + // - CPSIZE is being left with no special behavior on page-crossing + // - ASYNCWAIT is being left off since we're synchronous + // - EXTMOD is being left off, since it seems to only affect async + // - WAITPOL is treating NWAIT as active low (could change if desired) + // - MWID is being left at a 16 bit data bus. + // - MUXEN is being left with a multiplexed A/D bus. + + w + }); + + // Now for the timings. + // + // Synchronous access write/read latency, minus 2. That is, 0 means 2 cycle + // latency. Max value: 15 (for 17 cycles). NWAIT is not sampled until this + // period has elapsed, so if you're handshaking with a device using NWAIT, + // you almost certainly want this to be 0. + const DATLAT: u8 = 0; + // FMC_CLK division ratio relative to input (AHB3) clock, minus 1. Range: + // 1..=15. + // + // Note from the clock config earlier in this function that AHB3 is running + // at 200 MHz. + const CLKDIV: u8 = 3; // /4, for 50 MHz -- field is divisor minus 1 + + // Bus turnaround time in FMC_CLK cycles, 0..=15 + const BUSTURN: u8 = 0; + + p.FMC.btr1.write(|w| { + unsafe { + w.datlat().bits(DATLAT); + } + unsafe { + w.clkdiv().bits(CLKDIV); + } + unsafe { + w.busturn().bits(BUSTURN); + } + + // Deliberately left in reset state and/or ignored: + // - ACCMOD: only applies when EXTMOD is set in BCR above; also probably + // async only + // - DATAST: async only + // - ADDHLD: async only + // - ADDSET: async only + // + w + }); + + // BWTR1 register is irrelevant if we're not using EXTMOD, which we're not, + // currently. + + // Turn on the controller. + p.FMC.bcr1.modify(|_, w| w.fmcen().set_bit()); +} diff --git a/app/metro/src/tracing.rs b/app/metro/src/tracing.rs new file mode 100644 index 0000000000..a61b92de4c --- /dev/null +++ b/app/metro/src/tracing.rs @@ -0,0 +1,90 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +// +// If you are cutting-and-pasting this code into another kernel (and that +// kernel is armv6m), it is hoped that you will cut-and-paste this compile +// error along with it and take heed of its admonition! +// +#[cfg(not(any(armv7m, armv8m)))] +compile_error!("ringbuf is unsound in the kernel on armv6m"); + +use ringbuf::*; + +#[derive(Copy, Clone, PartialEq)] +enum Event { + SyscallEnter(u32), + SyscallExit, + SecondarySyscallEnter, + SecondarySyscallExit, + IsrEnter, + IsrExit, + TimerIsrEnter, + TimerIsrExit, + ContextSwitch(usize), +} + +#[derive(Copy, Clone, PartialEq)] +enum Trace { + None, + Event(Event), +} + +ringbuf!(Trace, 128, Trace::None); + +fn trace(event: Event) { + ringbuf_entry!(Trace::Event(event)); +} + +fn syscall_enter(nr: u32) { + trace(Event::SyscallEnter(nr)); +} + +fn syscall_exit() { + trace(Event::SyscallExit); +} + +fn secondary_syscall_enter() { + trace(Event::SecondarySyscallEnter); +} + +fn secondary_syscall_exit() { + trace(Event::SecondarySyscallExit); +} + +fn isr_enter() { + trace(Event::IsrEnter); +} + +fn isr_exit() { + trace(Event::IsrExit); +} + +fn timer_isr_enter() { + trace(Event::TimerIsrEnter); +} + +fn timer_isr_exit() { + trace(Event::TimerIsrExit); +} + +fn context_switch(addr: usize) { + trace(Event::ContextSwitch(addr)); +} + +static TRACING: kern::profiling::EventsTable = kern::profiling::EventsTable { + syscall_enter, + syscall_exit, + secondary_syscall_enter, + secondary_syscall_exit, + isr_enter, + isr_exit, + timer_isr_enter, + timer_isr_exit, + context_switch, +}; + +pub fn table() -> &'static kern::profiling::EventsTable { + &TRACING +} diff --git a/boards/metro-a.toml b/boards/metro-a.toml new file mode 100644 index 0000000000..eb91eeac9c --- /dev/null +++ b/boards/metro-a.toml @@ -0,0 +1,2 @@ +[probe-rs] +chip-name = "STM32H753ZITx"