# Devicetree Language Devicetrees use what's called a Domain Specific Language, so you need to follow the rules of the language when you're writing a devicetree. Fortunately, it's a relatively simple language, and because its use is so limited, it can frequently be learned just by following existing examples. ## Comments Comments in the devicetree are all single line style. They use the '#' character to start the comment, and go to the end of the line. ### Comment Style * Put a space between the pound sign and the comment. * \# Good * \#Bad * Sentence fragments are fine, but don't end them with a period. ### When to use comments There are standard locations where comments are typically used and expected. #### Starting a group of settings Similar to commenting a function with the intent of the function, it can be useful to describe at the top of a block of settings with what's being configured. Below is a good example. ```text # VR Settings Configuration for 4 Domains # +----------------+-----------+-----------+-------------+----------+ # | Domain/Setting | SA | IA | GT Unsliced | GT | # +----------------+-----------+-----------+-------------+----------+ # | Psi1Threshold | 20A | 20A | 20A | 20A | # | Psi2Threshold | 4A | 5A | 5A | 5A | # | Psi3Threshold | 1A | 1A | 1A | 1A | # | Psi3Enable | 1 | 1 | 1 | 1 | # | Psi4Enable | 1 | 1 | 1 | 1 | # | ImonSlope | 0 | 0 | 0 | 0 | # | ImonOffset | 0 | 0 | 0 | 0 | # | IccMax | 7A | 34A | 35A | 35A | # | VrVoltageLimit | 1.52V | 1.52V | 1.52V | 1.52V | # | AC LoadLine | 15 mOhm | 5.7 mOhm | 5.2 mOhm | 5.2 mOhm | # | DC LoadLine | 14.3 mOhm | 4.83 mOhm | 4.2 mOhm | 4.2 mOhm | # +----------------+-----------+-----------+-------------+----------+ ``` #### End of keyword blocks If there are multiple end statements in a row, and it's not instantly obvious which end statement closes which keyword block, It's useful to add a comment to say what's being ended. Below, we have three end statements in a row and the start of these blocks are probably close to the top of the file. Identifying what the 'end' statement is closing can be determined by the spacing, but it's still useful to note it with a comment. ```text end # agesa northbridge end # domain end # northbridge/amd/agesa/family14/root_complex ``` #### Identifying the reason for a setting Registers which don't have a name that makes it obvious what is being set, or don't have a macro that identifies what it's being set to should be commented. The register setting and macro below both describe what the setting is, but don't describe what they're being used for. Adding the comment of "Camera", gives the reader the extra information to know what's on that USB port, and understand that you (generally) don't need overcurrent protection for an internal camera. ```text register "usb2_ports[7]" = "USB2_PORT_MID(OC_SKIP)" # Camera ``` This below register is well named and tells you that there's going to be a delay of 12ms, but without the comment, you don't know why. ```text register "stop_delay_ms" = "12" # NIC needs time to quiesce ``` #### Devices without aliases It's been common in the past to comment device identifiers with what the device is, but this may be less needed now with aliases, which allow devices to be named in a meaningful way. For older platforms which don't have aliases set in the chipset.cb file, or for non chipset devices, it's still useful to add a comment after the device is set. ### When not to use comments #### Magic numbers This overlaps somewhat with the next section, but if you find yourself having to put in a comment to explain what's being set, evaluate whether it can be expressed as a macro instead. ``` register "PmConfigSlpS3MinAssert" = "2" # 50ms ``` Instead of using the magic number 2, use a macro, just as you'd be expected to do in your code. It's not obvious without the comment what 2 means, so use a macro instead. If there's some reason that a macro cannot be used, then sure, add a comment, but this should be very unusual. #### Redundant comments With good naming, comments may not be needed. Example of redundant comments: ```text register "ipc1" = "0x00000000" # IPC1 ``` ```text register "link_freq[0]" = "360 * MHz" # 360 MHz ``` #### Devices with aliases For older chipset or SoC devices, or for non chipset devices that don't have a chipset.cb file, it's still desirable to use comments on the 'device' line, but if the device has an alias, it should be used. ## Registers ### Register Names Any registers which encode a value that has any sort of unit should include the unit in the name instead of in a comment. The name "tFAW" in the register below is taken directly from the name in the spec, but adding the units makes it a lot easier to understand. ```text register "tFAW" = "40000" # picoseconds ``` ### Use Macros for encoded values If the value associated with the register encodes the unit, instead of entering the value directly, add a macro for the value. ```text register "PchPmSlpS3MinAssert" = "3" # 50ms ``` This would be easier to understand if it had a macro, not just a magic number, as seen below. ```text register "PchPmSlpS3MinAssert" = "ASSERT_50_MILLISEC" ``` ## Devicetree Keywords alias, as, chip, cpu, cpu_cluster, device, domain, drq, end, field, fw_config, generic, gpio, hidden, i2c, inherit, io, ioapic, ioapic_irq, lapic, mandatory, mmio, off, on, option, pci, pnp, probe, ref, register, smbios_dev_info, smbios_slot_desc, spi, subsystemid, usb, use ## Keyword Types The keywords are divided into a number of different categories. A few keywords fall into more than one of these categories. ### Alias Types The alias type keywords are used to give human readable names to devices, then later update that name for a specific usage. * alias, as, use ### Containers These keywords act to group information into logical units of different sorts. * chip, device, domain, field, fw_config, end ### Device/Bus Types These keywords are used to identify the type of device being configured and select the appropriate structure for configuration. * cpu, cpu_cluster, domain, generic, gpio, i2c, ioapic, lapic, mmio, pci, pnp, ref, spi, usb ### Enumeration Status Modifiers The status modifiers determine how a device should be treated during enumeration. * on, off, hidden, mandatory ### Firmware configuration * field, fw_config, option, probe, ref ### Resource allocation * drq, io, irq ### SMBIOS * smbios_dev_info, smbios_slot_desc ### Subsystem * inherit, subsystemid ### Register * register ### MPTABLE * ioapic_irq ## Keyword Definitions ### alias * Keyword type: Alias * Introduced in June of 2020, coreboot version 4.12 * Usage: `device **alias** ... end` Sometimes, the driver of one device needs to know about another device that can be anywhere in the device hierarchy. Current applications boil down to EEPROMs that store information that is consumed by some code (e.g. MAC address). The idea is to give device nodes in the `devicetree.cb` an alias that can later be used to link it to a device driver's `config` structure. The driver has to declare a field of type `struct device *`, e.g. Override devices can add an alias if it does not exist, but cannot change the alias for a device that already exists. Alias names are checked for conflicts both in the base tree and in the override tree. References are resolved after the tree is parsed so aliases and references do not need to be in a specific order in the tree. Example: ```text device i2c 0x50 alias my_eeprom on end ``` static.c: ```C struct some_chip_driver_config { DEVTREE_CONST struct device *needed_eeprom; }; ``` ### as * Keyword type: Alias * Introduced in June of 2020, coreboot version 4.12 * Usage: `use as ` This keyword is used along with the 'use' keyword to give a more specific name to a generic alias. The author of the devicetree is free to choose any alias name that is unique in the devicetree. Later, when configuring the driver the alias can be used to link the device with the field of a driver's config as in the following example. Example: ```text chip some/chip/driver use my_eeprom as needed_eeprom end ``` ### chip * Keyword type: Component type * Introduced in initial sconfig implementation, pre coreboot 4.0 * Usage: `**chip** ... end` The chip keyword defines a section for a device inside a hierarchy of devices. Following the chip keyword is a path to an optional chip.h file. If this file exists, it should contain a structure of all register settings available for this device. The section started with "chip" is closed with the "end" keyword. Note that register commands are chip based, not device based. Example: ```text chip some/chip/driver # comment as desired # A chip section must have at least one device inside it ... end # some/chip/driver ``` ### cpu * Keyword type: Device type * Introduced in October of 2014, coreboot version 4.0 * Usage: `device **cpu** [alias ] ... end` The cpu device type was introduced In order to enumerate CPU devices that are non-x86 (read: no lapic). This device type is not used very much, as most non-x86 platforms just handle all the CPU configuration at the cpu_cluster level. Example: ```text device cpu 0 on end ``` ### cpu_cluster * Keyword type: Device type * Introduced in initial sconfig implementation, pre coreboot 4.0 as apic_cluster * Updated in May of 2010 - renamed from apic_cluster to lapic_cluster * Updated in February of 2013 - Renamed from from lapic_cluster to cpu_cluster * Usage: `device cpu_cluster [alias ] …. end` The CPU Cluster is typically one of the two top-level devices in a devicetree, with the other being the PCI Domain. Like the domain keyword, the cpu_cluster acts as a bridge device to contain any CPU and lapic devices. On x86 type devices, the CPU Cluster contains CPU chip entries for each socket which then contain any lapics on the system. On ARM or other non-x86 devices, the CPU Cluster can either contain multiple CPUs or it can just be marked 'on', leaving all CPU configuration to be handled at the CPU Cluster level. Example: ```text device cpu_cluster 0 on device lapic 0 on end end ``` ### device * Keyword type: Component type * Introduced in: Initial sconfig implementation, pre coreboot 4.0 * Usage: `device [alias ] …. end` A chip defines a collection of one or more devices, and as such, the device is the fundamental building block of devicetree. The device block tells coreboot that a device is present on the mainboard, gives some information on how to find, access, and work with the device based on the device type. Examples: ```text device cpu_cluster 0 on device lapic 0 on end end ``` ### domain * Keyword type: Device type * Introduced in: Initial sconfig implementation, pre coreboot 4.0 * Updated in: February of 2013: Renamed pci_domain to domain * Usage: `device domain [alias ] ... end` The domain type device acts as a container for one or more chips, defining a logical bus segment. As of 2022-04-29, the domain keyword is still used exclusively to define PCI bus segments. Example: ```text device domain 0 on device generic 0 alias dptf_policy on end device pci 1f.0 on # 8086 229c - LPC bridge device pnp 2e.209 off end # GPIO 4 end end ``` ### drq * Keyword type: Resource type * Introduced in: Initial sconfig implementation, pre coreboot 4.0 * Usage: `drq 0x = ` Drq is used to configure a legacy DMA Request line register for a device on a legacy bus - ISA/LPC. The drq configuration is only allowed inside a pnp block. Example: ```text device pnp 2e.1 on # Parallel port io 0x60 = 0x378 irq 0x70 = 7 drq 0x74 = 3 end ``` ### end * Keyword type: Component type * Introduced in: Initial sconfig implementation, pre coreboot 4.0 * Usage: ` ... end` End is used to close a chip, device, field, or fw_config block. Example: ```text chip northbridge/intel/x4x device domain 0 on chip southbridge/intel/i82801gx device pci 1f.0 on # ISA bridge chip superio/winbond/w83627dhg device pnp 2e.1 on # LPT io 0x60 = 0x378 irq 0x70 = 7 drq 0x74 = 3 end # LPT end # superio/winbond/w83627dhg end # ISA Bridge end # Southbridge end # domain 0 end # Northbridge ``` ### field * Keyword type: Firmware config * Introduced in: May of 2020, coreboot version 4.12 * Usage: `field [ | …] ... end` Fields define the bits used in the Firmware config runtime options. Note that the bits in a field can be discontiguous. All field definitions must be inside a fw_config block. Example: ```text field AUDIO 8 10 | 29 29 option NONE 0 option MAX98357_ALC5682I_I2S 1 option MAX98373_ALC5682I_I2S 2 option MAX98373_ALC5682_SNDW 3 option MAX98373_ALC5682I_I2S_UP4 4 option MAX98360_ALC5682I_I2S 5 option RT1011_ALC5682I_I2S 6 option AUDIO_FOO 7 option AUDIO_BAR 8 option AUDIO_QUUX 9 option AUDIO_BLAH1 10 option AUDIO_BLAH2 15 end ``` static_fw_config.h: ```C FW_CONFIG_FIELD_AUDIO_MASK 0x20000700 FW_CONFIG_FIELD_AUDIO_OPTION_NONE_VALUE 0x0 FW_CONFIG_FIELD_AUDIO_OPTION_MAX98357_ALC5682I_I2S_VALUE 0x100 FW_CONFIG_FIELD_AUDIO_OPTION_MAX98373_ALC5682I_I2S_VALUE 0x200 FW_CONFIG_FIELD_AUDIO_OPTION_MAX98373_ALC5682_SNDW_VALUE 0x300 FW_CONFIG_FIELD_AUDIO_OPTION_MAX98373_ALC5682I_I2S_UP4_VALUE 0x400 FW_CONFIG_FIELD_AUDIO_OPTION_MAX98360_ALC5682I_I2S_VALUE 0x500 FW_CONFIG_FIELD_AUDIO_OPTION_RT1011_ALC5682I_I2S_VALUE 0x600 FW_CONFIG_FIELD_AUDIO_OPTION_AUDIO_FOO_VALUE 0x700 FW_CONFIG_FIELD_AUDIO_OPTION_AUDIO_BAR_VALUE 0x20000000 FW_CONFIG_FIELD_AUDIO_OPTION_AUDIO_QUUX_VALUE 0x20000100 FW_CONFIG_FIELD_AUDIO_OPTION_AUDIO_BLAH1_VALUE 0x20000200 FW_CONFIG_FIELD_AUDIO_OPTION_AUDIO_BLAH2_VALUE 0x20000700 ``` ### fw_config * Keyword type: Firmware config * Introduced in: May of 2020, coreboot version 4.12 * Usage: fw_config Fw_config is the top level token for defining firmware config fields. All field and option definitions must be inside the fw_config block. Note that the table can be defined before any chips are configured. Example: ```text fw_config field USB_DB 0 1 option USB_DB_A1_PS8811_C1_PS8818 0 option USB_DB_A1_ANX7491_C1_ANX7451 1 end field FORM_FACTOR 2 option FORM_FACTOR_CLAMSHELL 0 option FORM_FACTOR_CONVERTIBLE 1 end end ``` ### generic * Keyword type: Device type * Introduced in: May of 2016, coreboot version 4.4 * Usage: `device generic [alias ] ... end` This allows the devicetree to describe a device that does not have a specific bus, but may need to be described in tables for the operating system. For instance some chips may have various GPIO connections that need to be described but do not fall under any other device. Example: ```text device pci 0c.0 on # CNVi chip drivers/wifi/generic register "wake" = "GPE0A_CNVI_PME_STS" device generic 0 on end end end ``` ### gpio * Keyword type: Device type * Introduced in: December 2020, coreboot version 4.13 * Usage: `device **gpio** [alias ] ... end` The general idea behind this is that every chip can have gpios that shall be accessible in a very generic way by any driver through the devicetree. The chip that implements the chip-specific gpio operations has to assign them to the generic device operations struct, which then gets assigned to the gpio device during device probing. See CB:48583 for how this gets done for the SoCs using intel/blocks/gpio. The gpio device then can be added to the devicetree with an alias name like in the following example: ```text chip soc/whateverlake device gpio 0 alias soc_gpio on end ... end ``` Any driver that requires access to this gpio device needs to have a device pointer (or multiple) and an option for specifying the gpio to be used in its chip config like this: ```C struct drivers_ipmi_config { ... DEVTREE_CONST struct device *gpio_dev; u16 post_complete_gpio; ... }; ``` The device `soc_gpio` can then be linked to the chip driver's `gpio_dev` above by using the syntax `use ... as ...`, which was introduced in commit 8e1ea52: ```text chip drivers/ipmi use soc_gpio as gpio_dev register "bmc_jumper_gpio" = "GPP_D22" ... end ``` The IPMI driver can then use the generic gpio operations without any knowlege of the chip's specifics: ```C unsigned int gpio_val; const struct gpio_operations *gpio_ops; gpio_ops = dev_get_gpio_ops(conf->gpio_dev); gpio_val = gpio_ops->get(conf->bmc_jumper_gpio); ``` For a full example have a look at CB:48096 and CB:48095. ### hidden * Keyword type: Enumeration Status Modifier * Introduced in: September 2018, coreboot version 4.8 * Updated in: February of 2020, coreboot version 4.11 * Usage: `device [alias ] hidden ... end` The "Hidden" keyword was added to support devices sharing the same driver to update their ACPI status with different values. If a device is marked as Hidden, it omits the "SHOW_IN_UI" field, which prevents the device from showing up in the OSPM user interface. This was added to prevent ChromeOS specific devices from showing up in Windows, for example. It does not look like this keyword was ever actually used in this capacity, but the code for this is still present. In 2020, the "Hidden" keyword's use was expanded to fix the problem of PCI devices which have been hidden by disabling access to the config space. Because the Device/Vendor IDs read back as 0xffffffff from the hidden device, it appears that there is no PCI device located at that Bus/Device/Function. This causes coreboot to remove the device at the end of PCI enumeration. To fix this, if a device uses 'hidden' instead of 'on', then it will be assumed during PCI enumeration that the device indeed does exist, and it will not be removed. This allows coreboot to manually assign resources to the device even though it doesn't appear to exist. Example: ```text device pci 1f.2 alias pmc hidden end ``` static.c: ```C .enabled = 1, .hidden = 1, .mandatory = 0, ``` ### i2c * Keyword type: Device type * Introduced in: Initial sconfig implementation, pre coreboot 4.0 * Usage: `device I2c [alias ] ... end` The identifier is the device's address encoded as hexadecimal number. Example: ```text device i2c 2c on end chip drivers/i2c/generic register "hid" = ""ELAN0000"" register "desc" = ""ELAN Touchpad"" register "irq_gpio" = "ACPI_GPIO_IRQ_LEVEL_LOW(GPIO_9)" register "wake" = "GEVENT_22" register "probed" = "1" device i2c 15 on end end ``` ### inherit * Keyword type: subsystem * Introduced in: March of 2011, coreboot version 4.0 * Usage: `subsystemid beee c001 inherit` Used to modify the subsystemid keyword, inherit makes the ID apply to all subdevices and functions. Example: ```text device pci 00.0 on subsystemid 0xdead 0xbeef inherit end ``` ### io * Keyword type: Resource * Introduced in: Initial sconfig implementation, pre coreboot 4.0 * Usage: `io 0x
= 0x` The io command is used to set an legacy device's io register to a value. Example: ```text device pnp 4e.06 on # Keyboard io 0x60 = 0x0060 io 0x62 = 0x0064 irq 0x70 = 1 end ``` ### ioapic * Keyword type: Device type * Usage: `device ioapic [alias ] ... end` ### ioapic_irq * Keyword type: Mpinit type * Introduced in: June of 2012, coreboot version 4.0 * Usage: `ioapic_irq ` This keyword is used to support autogeneration of the MPTABLE from devicetree.cb. This is done by a write_smp_table() declared weak in mpspec.c. If the mainboard doesn't provide its own function, this generic implementation is called. The ioapic_irq directive can be used in pci and pci_domain devices. If there's no directive, the autogen code traverses the tree back to the pci_domain and stops at the first device which sets such a directive, and uses that information to generate the entry according to PCI IRQ routing rules. ```text ``` ### irq * Keyword type: Resource type * Introduced in initial sconfig implementation, pre coreboot 4.0 * Usage: `irq 0x
= 0x` Irq is used to configure a legacy interrupt Request line register for a device on a legacy bus - ISA/LPC/eSPI. The irq configuration is only allowed inside a pnp block. Example: ```text irq 0xc5 = 0x1f ``` ```text chip superio/fintek/f71808a device pnp 4e.4 on # Hardware monitor io 0x60 = 0x295 irq 0x70 = 0 end end ``` ### lapic * Keyword type: Device type * Introduced in initial sconfig implementation, pre coreboot 4.0 * Updated in May of 2010 - Renamed apic to lapic * Usage: `device lapic [alias ] ... end` Defines an lapic device on an x86 mainboard. Example: ```text device cpu_cluster 0 on # (L)APIC cluster chip cpu/intel/slot_1 # CPU socket 0 device lapic 0 on end # Local APIC of CPU 0 end chip cpu/intel/slot_1 # CPU socket 1 device lapic 1 on end # Local APIC of CPU 1 end end ``` ### mandatory * Keyword type: Enumeration Status Modifier * Introduced in: February of 2020, coreboot version 4.11 * Usage: `device [alias ] mandatory ... end` The Mandatory keyword allows for minimal PCI scanning which speeds up the boot process. Only devices marked "mandatory" get enabled and scanned during PCI enumeration when the MINIMAL_PCI_SCANNING Kconfig option is enabled. If MINIMAL_PCI_SCANNING is not enabled, this means the same as 'on'. static.c: ```C .enabled = 1, .hidden = 0, .mandatory = 1, ``` example: ```text device pci 1f.0 mandatory # LPC chip drivers/pc80/tpm device pnp 0c31.0 on end end # tpm end # LPC ``` ### mmio * Keyword type: Device type * Introduced in January of 2018, coreboot version 4.7 * Usage: `device mmio 0x
[alias ] ... end` The mmio keyword allows fixed memory-mapped IO addressed devices to be assigned to given values. AMD platforms perform a significant amount of configuration through these MMIO addresses, including I2C bus configuration. example: ```text device mmio 0xfedc9000 alias uart_0 off end device mmio 0xfedca000 alias uart_1 off end device mmio 0xfedc2000 on # I2C 0 chip drivers/generic/adau7002 device generic 0.0 on end end chip drivers/i2c/da7219 register "irq_gpio" = "ACPI_GPIO_IRQ_EDGE_LOW(GPIO_14)" end chip drivers/generic/max98357a register "hid" = ""MX98357A"" register "sdmode_delay" = "5" device generic 0.1 on end end end # I2C 0 ``` ### off * Keyword type: Enumeration Status Modifier * Introduced in: Initial sconfig implementation, pre coreboot 4.0 * Usage: `device [alias ] off ... end` Indicates that the device should be disabled if possible and should not be enumerated or configured. To disable a device, the code to disable it must be present in the chipset/SoC code, though it isn't always possible to actually disable the device. Note that If a device (especially PCI devices) is marked as 'off', but does not get disabled, the OS or a driver may discover the device during its enumeration sequence and assign it resources anyway. static.c: ```C .enabled = 0 .hidden = 0, .mandatory = 0, ``` example: ```text device usb 2.6 off end device pnp 2e.0 off end # FDC device pci 15.2 off end ``` ### on * Keyword type: Enumeration Status Modifier * Introduced in: Initial sconfig implementation, pre coreboot 4.0 * Usage: `device [alias ] on ... end` Marks a device as present and enabled. This indicates that the device should be enumerated and configured. static.c: ```C .enabled = 1 .hidden = 0, .mandatory = 0, ``` Example: ```text device lapic 0 on end device pci 00.0 on end # Host Bridge device pnp 0c31.0 on end ``` ### option * Keyword type: Firmware config * Usage: `option ` Options define the values which may be used in a firmware config field. The option keyword may only be used inside a field, which may only be used inside an fw_config block. Example: ```text fw_config field OLED_SCREEN 28 option OLED_NOT_PRESENT 0 option OLED_PRESENT 1 end end ``` ### pci * Keyword type: Device type * Introduced in: Initial sconfig implementation, pre coreboot 4.0 * Usage: `device pci [alias ] …. end` The pci device type defines a PCI or PCIe device on the PCI logical bus. Resources for all PCI devices are assigned automatically, or must be assigned in code if they're non-standard. Only a single segment group is supported per domain, but there can be multiple domains to support the case of multiple segment groups, each with a bus 0. Because the bus is not specified, It's assumed that all pci devices that are not behind a pci bridge device are on bus 0. If there are additional pci busses in a chip, they can be added behind their bridge device. Examples: ```text device pci 1a.0 on end # USB2 EHCI #2 device pci 1b.0 on # High Definition Audio subsystemid 0x1a86 0x4352 end ``` Example - ISA bus under PCI to ISA bridge: ```text device pci 4.0 on # ISA bridge chip superio/winbond/w83977tf # Super I/O device pnp 3f0.2 on # COM1 io 0x60 = 0x3f8 irq 0x70 = 4 end end end ``` Example - PCI Bus under a PCI to PCI bridge: ```text device pci 08.0 on end # Dummy Host Bridge, do not disable device pci 08.1 alias gpp_bridge_a off # Internal GPP Bridge 0 to Bus A device pci 0.0 alias gfx off end # Internal GPU (GFX) device pci 0.1 alias gfx_hda off end # Display HDA (GFXAZ) end ``` ### pnp * Keyword type: Device type * Introduced in: Initial sconfig implementation, pre coreboot 4.0 * Usage: `device pnp [alias ] …. end` pnp is used to define an IO addressed device within a chip on a legacy bus - ISA, LPC, or eSPI. The identifier is the IO address used to access the chip, followed by the identifier for the device within the chip. The io, irq, and drq resource identifiers are allowed only inside a pnp device. Example: ```text chip superio/ite/it8783ef device pnp 2e.0 off end # Floppy device pnp 2e.1 on # COM 1 io 0x60 = 0x3f8 irq 0x70 = 4 end end ``` ### probe * Keyword type: Firmware config * Introduced in May of 2020, coreboot version 4.12 * Usage: `probe