Board Configuration

The board configuration is the most important part of the board-tailoring, and it works as a data structure containing all the tailoring data which can be supplied by the customers of Microchip (here customer is the one designing a board - not the end user).

The board configuration itself is guarded by a YANG schema file which describes all the fields which can be configured and encoded as CBOR as defined by RFC9254.

The board.yang is different from all the other YANG modules in the system as it is not exposed over CORECONF, and completely invisible to the end-user. The board-yang data belong to the firmware image and are signed along with that image, and therefore being considered as part of the firmware.

CBOR is a compact and machine-friendly encoding, but not very human-friendly, and for this reason, the actual board configurations are written in YAML format, and then converted to CBOR. The build system takes care of doing that.

When reading this material, one should have the board.tree and board.yang files open, and reference them.

The high-level structure of the board.tree looks like this:

module: board
  +--rw drivers                   <container>
  |  ...
  +--rw capabilities              <container>
  |  ...
  +--rw factory_default_config?   <anydata>
  |  ...
  +--rw extmod                    <container>
  |  ...

A basic and empty board configuration YAML template can look like this:

board:drivers:
board:capabilities:
board:factory_default_config:

The following section will go into detail with each of the major sections

1. Drivers

1.1. SGPIO Banks

SGPIOs (Serial GPIOs) are used for communication with devices on the board such as SFP modules and LEDs. Up to 32 SGPIO ports can be enabled, with each port consisting of 1-4 bits. This configuration results in a serial data stream comprising 'ports * bits' number of GPIOs. The definition looks like this:

module: board
  +--rw drivers
     +--rw sgpio_banks
        +--rw sgpio_bank* [sgpio_bank]
           +--rw sgpio_bank    dev_sgpio_bank
           +--rw bit_count     uint32
           +--rw port_mask     uint32
           +--rw clock_div?    uint32
           +--rw pin_ctrl
              +--rw pins*           uint32
              +--rw pin_function    pin_function
  • sgpio_bank is used to select which physical instance in hardware to configure; typically, 1-3 instances are available.

  • bit_count is the number of GPIOs (or bits) that are enabled per SGPIO port, with 1-4 bits available.

  • port_mask defines the SGPIO ports that get enabled. Some signals (e.g., SFP LOS) are mapped directly to the chip device with the same number as the SGPIO port in this mask.

  • clock_div maps directly into the hardware where the SGPIO frequency is set. The resulting frequency is the system clock divided by this value.

  • pin_ctrl is used to assign physical pins on the SoC to this function. Check the datasheet for an overview of which pins can be used.

Example with SGPIO ports 0,1,24,25,26,27 enabled, with 4 bits per port:

  sgpio_banks:
    sgpio_bank:
      - sgpio_bank: DEV_SGPIO_BANK_0
        bit_count: 4
        port_mask: 0x0F000003
        clock_div: 65
        pin_ctrl:
          pins: [5, 6, 7, 8]
          pin_function: alt1

1.2. FlexCom

FlexCOM is a SoC HW component capable of providing a UART, I2C, or SPI interface. The definition of the FlexCOM in the board.tree looks like this:

  +--rw drivers
     +--rw flexcoms
        +--rw flexcom* [hw_instance]
           +--rw hw_instance    uint32
           +--rw uart?          dev_uart
           +--rw i2c?           dev_i2c
           +--rw spi?           dev_spi
           +--rw pin_ctrl
              +--rw pins*           uint32
              +--rw pin_function    pin_function

Here:

  • hw_instance is used to select which physical instance in HW to configure. Typically a SoC supports 2-5 instances, and each instance can only be configured to work with a fixed pool of pins. It is therefore important to configure the correct instance (according to the schematic).

  • uart, i2c, and spi are used to select the personality of the FlexCOM instance. Any given flexcom entry must include one and only one of them. The DEV_xxx value assigned to either uart, i2c, or spi is an internal handle, used further down in the file to reference the FlexCOM instance.

  • pin_ctrl is used to assign physical pins on the SoC to this function. Check the datasheet for an overview of what pins can be used.

Following is an example where FlexCom-0 is configured as UART, and FlexCOM-3 is configured as an I2C controller:

board:drivers:
  flexcoms:
    flexcom:
      - hw_instance: 0
        uart: DEV_UART_0
        pin_ctrl:
          pins: [3, 4]
          pin_function: alt1
      - hw_instance: 3
        i2c: DEV_I2C_0
        pin_ctrl:
          pins: [55, 56]
          pin_function: alt2

See also: MUP1 and I2C Mux.

1.3. UART

UART peripheral within a SoC. The definition of the uart in the board.tree looks like this:

  +--rw drivers
     +--rw uarts
        +--rw uart* [hw_instance]
           +--rw hw_instance    uint32
           +--rw logical_id?    dev_uart

Here:

  • hw_instance is used to select which physical instance in HW to configure. On PIC64-HPSC/HX, instance 0 is the SysC UART and instance 1-4 are for AppC UART 0-3.

  • logical_id is the logical handle (DEV_UART_x value) for this UART. This is used when referencing the UART in other places, such as in the "mup1" section.

1.4. I2C

I2C bus controller within a SoC. The definition of the i2c in the board.tree looks like this:

  +--rw drivers
     +--rw i2cs
        +--rw i2c* [hw_instance]
           +--rw hw_instance    uint32
           +--rw logical_id?    dev_i2c

Here:

  • hw_instance is used to select which physical instance in HW to configure. On PIC64-HPSC/HX, instance 0 is the SysC I2C and instance 1-4 are for AppC I2C 0-3.

  • logical_id is the logical handle (DEV_I2C_x value) for this I2C. This is used when referencing the I2C bus in other places, such as when specifying the parent bus of an I2C multiplexer.

1.5. Pin Group

Pin group is used to configure and manage the multiplexing of pins to allow multiple devices to share the same physical pins. The pins can be either GPIOs or SGPIOs. The typical usage is to control a mux to I2C devices. The definition looks like this:

module: board
  +--rw drivers
     +--rw pin_groups
        +--rw pin_group* [pin_group]
           +--rw pin_group    dev_pin_group
           +--rw sleep        uint32
           +--ro mux_pins* []
              +--ro (ref)
              |  +--:(sgpio)
              |  |  +--ro sgpio
              |  |     +--ro ref_sgpio_bank    dev_sgpio_bank
              |  |     +--ro port              uint8
              |  |     +--ro bit               uint8
              |  +--:(gpio)
              |     +--ro gpio?     uint32
              +--ro direction       gpio_direction
              +--ro active_state?   active
  • pin_group is the internal handle for others to reference when choosing a pin group.

  • sleep is the time it takes to change the mux, i.e., the driver waits this number of ms before returning and the mux is formed.

  • sgpio defines a reference to an SGPIO bank and which port/bit are used to form the group.

  • gpio has the same purpose as sgpio, just for GPIOs.

Example of a pin group formed by 3 SGPIO pins, wich can contol mux with up to 8 outputs:

  pin_groups:
    pin_group:
      - pin_group: DEV_PIN_GROUP_0
        sleep: 10
        mux_pins:
          - sgpio:
              ref_sgpio_bank: DEV_SGPIO_BANK_0
              port: 0
              bit: 1
            direction: GPIO_DIR_OUT
          - sgpio:
              ref_sgpio_bank: DEV_SGPIO_BANK_0
              port: 0
              bit: 2
            direction: GPIO_DIR_OUT
          - sgpio:
              ref_sgpio_bank: DEV_SGPIO_BANK_0
              port: 0
              bit: 3
            direction: GPIO_DIR_OUT

1.6. I2C Mux

I2C Mux is used to control a number of I2C devices (which share the same I2C bus) by enabling only one of them at a time and keeping the others disabled. Users will reference the MUX based on how it should be configured with 'DEV_MUX_x'.

Two types of I2C muxes are supported. The first type uses GPIOs to select between different I2C channels. The second type are PCA954x type devices which accepts writes to one I2C address to switch between the different I2C channels.

I2C muxes must mux an I2C root bus. An I2C root bus is a bus controller declared in FlexCom or I2C. It is not allowed to place a mux on the output of a mux.

Only one type of mux must be used on a given I2C root bus. i.e., it is not allowed to mix GPIOs type muxes with PCA954x type muxes on a given I2C root bus.

The definition looks like this:

module: board
  +--rw drivers
     +--rw i2c_muxs
        +--rw i2c_mux* [i2c_mux]
           +--rw i2c_mux          dev_i2c_mux
           +--rw ref_parent       dev_i2c
           +--rw ref_pin_group    dev_pin_group
           +--rw gpio_mask        uint32
     +--rw i2c_mux_pca954x
        +--rw i2c_mux* [i2c_mux]
           +--rw i2c_mux        dev_i2c_mux
           +--rw ref_parent     dev_i2c
           +--rw i2c_address    uint8
           +--rw i2c_val        uint8
  • i2c_mux is the internal handle for others to reference when choosing an I2C mux with a specific mux configuration.

  • ref_parent is a reference to an already defined HW I2C instance.

  • ref_pin_group is a reference to an already defined pin group for GPIO controlled I2C mux.

  • gpio_mask defines the pin mask for GPIO controlled I2C mux.

  • i2c_address defines the I2C address to write to for PCA954x I2C mux.

  • i2c_val defines the I2C value written to i2c_address for PCA954x I2C mux.

Example of a GPIO controlled I2C MUX with a reference for channel 0 to 3.

  i2c_muxs:
    i2c_mux:
      - i2c_mux: DEV_MUX_0
        ref_parent: DEV_I2C_0
        ref_pin_group: DEV_PIN_GROUP_0
        gpio_mask: 0
      - i2c_mux: DEV_MUX_1
        ref_parent: DEV_I2C_0
        ref_pin_group: DEV_PIN_GROUP_0
        gpio_mask: 1
      - i2c_mux: DEV_MUX_2
        ref_parent: DEV_I2C_0
        ref_pin_group: DEV_PIN_GROUP_0
        gpio_mask: 2
      - i2c_mux: DEV_MUX_3
        ref_parent: DEV_I2C_0
        ref_pin_group: DEV_PIN_GROUP_0
        gpio_mask: 3

Example of a PCA954x I2C MUX at address 0x70 with a reference for channel 0 and 1:

    i2c_mux_pca954x:
        i2c_mux:
            - i2c_mux: DEV_MUX_0
              ref_parent: DEV_I2C_0
              i2c_address: 0x70
              i2c_val: 0x01
            - i2c_mux: DEV_MUX_1
              ref_parent: DEV_I2C_0
              i2c_address: 0x70
              i2c_val: 0x02

1.7. MCP230xx I2C GPIO expander

module: board
  +--rw gpio_mcp230xx
     +--rw mcp230xx* [handle]
        +--rw handle         dev_sgpio_bank
        +--rw (i2c_parent)
           +--:(i2c_bus)
           |  +--rw i2c_bus?   dev_i2c
           +--:(i2c_mux)
              +--rw i2c_mux?   dev_i2c_mux
        +--rw i2c_address    uint8
        +--rw gpio_count     uint32
  • handle is the internal handle for others to reference this mcp230xx instance.

  • i2c_bus is the I2C bus of this mcp230xx instance if it is placed on a root I2C bus. See FlexCom or I2C.

  • i2c_mux is the I2C bus of this mcp230xx instance if it is placed on an I2C multiplexer. See I2C Mux.

  • i2c_address is the I2C address of this mcp230xx instance.

  • gpio_count is the total number of gpio of this mcp230xx instance. Must be 8 or 16.

Example of three MCP230xx at address 0x21, 0x22 and 0x23 on I2C bus DEV_MUX_0, each providing 16 GPIOs:

    gpio_mcp230xx:
        mcp230xx:
            - handle: DEV_SGPIO_BANK_0
              i2c_mux: DEV_MUX_0
              i2c_address: 0x21
              gpio_count: 16
            - handle: DEV_SGPIO_BANK_1
              i2c_mux: DEV_MUX_0
              i2c_address: 0x22
              gpio_count: 16
            - handle: DEV_SGPIO_BANK_2
              i2c_mux: DEV_MUX_0
              i2c_address: 0x23
              gpio_count: 16

1.8. SFP

The SFP signals that are defined consist of the following: LOS (input), TX_FAULT (input), PRESENT (input), and TX_ENABLE (output). When inserted, 'PRESENT' goes high and the ROM is read via I2C to determine the type and thereby how to configure the switch port to match its capabilities. The definition looks like this:

module: board
  +--rw drivers
     +--rw sfps
        +--rw sfp* [portno]
           +--rw los
           |  +--rw (ref)
           |  |  +--:(sgpio)
           |  |  |  +--rw sgpio
           |  |  |     +--rw ref_sgpio_bank    dev_sgpio_bank
           |  |  |     +--rw port              uint8
           |  |  |     +--rw bit               uint8
           |  |  +--:(gpio)
           |  |     +--rw gpio?     uint32
           |  +--rw direction       gpio_direction
           |  +--rw active_state?   active
           +--rw tx_fault
           |  +--rw (ref)
           |  |  +--:(sgpio)
           |  |  |  +--rw sgpio
           |  |  |     +--rw ref_sgpio_bank    dev_sgpio_bank
           |  |  |     +--rw port              uint8
           |  |  |     +--rw bit               uint8
           |  |  +--:(gpio)
           |  |     +--rw gpio?     uint32
           |  +--rw direction       gpio_direction
           |  +--rw active_state?   active
           +--rw present
           |  +--rw (ref)
           |  |  +--:(sgpio)
           |  |  |  +--rw sgpio
           |  |  |     +--rw ref_sgpio_bank    dev_sgpio_bank
           |  |  |     +--rw port              uint8
           |  |  |     +--rw bit               uint8
           |  |  +--:(gpio)
           |  |     +--rw gpio?     uint32
           |  +--rw direction       gpio_direction
           |  +--rw active_state?   active
           +--rw tx_enable
           |  +--rw (ref)
           |  |  +--:(sgpio)
           |  |  |  +--rw sgpio
           |  |  |     +--rw ref_sgpio_bank    dev_sgpio_bank
           |  |  |     +--rw port              uint8
           |  |  |     +--rw bit               uint8
           |  |  +--:(gpio)
           |  |     +--rw gpio?     uint32
           |  +--rw direction       gpio_direction
           |  +--rw active_state?   active
           +--rw portno         uint32
           +--rw ref_i2c_mux?   dev_i2c_mux
  • portno defines to which switch front port (zero-based) this SFP belongs.

  • los indicates a loss of the received optical signal.

  • present indicates that a module is present.

  • tx_enable signal is used to enable the transmitter output.

  • tx_fault indicates faults in the Tx direction.

  • direction can be either input or output (output for tx_enable, input for others).

  • active_state defines the signal’s active state. This is usually documented in schematics.

  • sgpio/gpio section defines how the signals are mapped to either SGPIO port/bit or GPIO ID.

  • ref_i2c_mux is a reference to an already defined I2C mux, which enables this SFP I2C.

Example of a single SFP implementation:

  sfps:
    sfp:
      - portno: 24
        ref_i2c_mux: DEV_MUX_0
        los:
          sgpio:
            ref_sgpio_bank: DEV_SGPIO_BANK_0
            port: 24
            bit: 0
          direction: GPIO_DIR_IN
          active_state: high
        tx_fault:
          sgpio:
            ref_sgpio_bank: DEV_SGPIO_BANK_0
            port: 24
            bit: 2
          direction: GPIO_DIR_IN
          active_state: high
        present:
          sgpio:
            ref_sgpio_bank: DEV_SGPIO_BANK_0
            port: 24
            bit: 1
          direction: GPIO_DIR_IN
          active_state: low
        tx_enable:
          sgpio:
            ref_sgpio_bank: DEV_SGPIO_BANK_0
            port: 24
            bit: 2
          direction: GPIO_DIR_OUT
          active_state: low

1.9. MDIO

The MDIO (Management Data Input/Output) is a serial bus protocol used for PHY access. There are usually 1-3 buses available on the SoC, and each PHY will reference which bus they belong to.

module: board
  +--rw drivers
     +--rw mdios
        +--rw mdio* [miim_bus]
           +--rw miim_bus     miim_bus
           +--rw pin_ctrl
           |  +--rw pins*           uint32
           |  +--rw pin_function    pin_function
           +--rw frequency?   uint32
  • miim_bus is the bus ID, used for reference.

  • pin_ctrl is used to assign physical pins on the SoC to this function. Check the datasheet for an overview of what pins can be used.

  • frequency is the MIIM bus frequency in Hz. Leave out for default SoC frequency.

Example of an MDIO:

  mdios:
    mdio:
      - miim_bus: MIIM_BUS_0
        frequency: 2500000
        pin_ctrl:
          pins: [9, 10]
          pin_function: alt1

1.10. MUP1

MUP1 is a UART protocol facilitating configuring and inspecting the status of the Switch using the UART.

MUP1 is a SW function, but it needs to know which UART device it shall use. This is done by setting a handle, which ties it to the HW instance of the same handle (typically a FlexCom).

The definition of the MUP1 in the board.tree looks like this:

module: board
  +--rw drivers
     +--rw mup1
        +--rw ref_uart?   dev_uart

Following is an example connecting the MUP1 function to the HW instance using DEV_UART_0.

board:drivers:
  mup1:
    ref_uart: DEV_UART_0

See also: FlexCom

1.11. Flash

The SPI-NOR (QSPI) flash holds the bootloader, the firmware images and the file system. How fast and how wide it can be driven depends on the board — trace lengths, layout and the flash part fitted — so it is a board setting rather than a property of the software.

LAN969x and LAN966x based designs require a flash part that can erase down to 4 KiB pages. The driver issues the 4 KiB sector-erase opcode (0x20) and nothing else, so a part whose smallest erasable unit is larger — a 64 KiB block-erase-only device, for instance — cannot be used, regardless of the mode and speed selected here.

The definition in the board.tree looks like this:

module: board
  +--rw drivers
     +--rw flash_static
        +--rw mode?    enumeration
        +--rw speed?   uint32

The container is called flash_static because every value is stated by the board, rather than discovered from the flash part itself.

mode names the read protocol by its command-address-data bus widths:

Value Meaning

single_1_1_1

One line throughout, using the low-frequency read opcode (0x03). The default, and what the driver has always used. Most flash parts only rate this opcode to around 50 MHz.

quad_1_4_4

Quad I/O (0xEB): command on one line, then address and data on four, with a six-cycle dummy phase. The driver sets the flash part’s quad-enable bit as required for the part fitted.

speed is an upper bound in MHz, not an exact frequency. The achievable frequencies are the SoC clock divided by an integer, so the driver picks the highest one that does not exceed the bound — usually landing below it. A bound below the slowest the divider can express is clamped to that slowest rate.

The value is taken as given: it is not checked against what the platform or the flash part can sustain. Consult the datasheet for the platform and the part fitted before raising it — what is safe varies by board layout, trace length and the part itself.

Both settings are applied when the flash is brought up and are fixed for the lifetime of the device; there is no runtime reconfiguration and no management node reporting them.

Omitting the container gives single_1_1_1 / 25 MHz, which is what the driver used before these settings existed, so a board that says nothing behaves exactly as it did. Raising either value is opt-in per board. Note the bootloader runs the same flash at 100 MHz quad, so a part sustaining more than the default is the normal case rather than the exception — but it wants measuring on the board before it is declared here.

board:drivers:
  flash_static:
    mode: single_1_1_1
    speed: 25

This configures the application’s flash access only. The bootloader reads its own device tree and has its own clock and bus width, so a board that cannot sustain the defaults needs both lowered — changing one leaves the other running as before. See the bootloader tailoring section in SW Tailoring.

Raise these values only after measuring on the board in question. A setting the board cannot sustain shows up as corrupted reads, which can look like almost any other fault. The safe order when bringing up a new board is to start at single_1_1_1 / 25 MHz, confirm the device is stable, and widen or speed up one step at a time.

1.12. GPIO-Restart

The GPIO for Board restart is defined here. A board restart can e.g. be performed from management. The definition looks like this:

module: board
  +--rw drivers
     +--rw gpio_restart
        +--rw (ref)
        |  +--:(sgpio)
        |  |  +--rw sgpio
        |  |     +--rw ref_sgpio_bank    dev_sgpio_bank
        |  |     +--rw port              uint8
        |  |     +--rw bit               uint8
        |  +--:(gpio)
        |     +--rw gpio?     uint32
        +--rw direction       gpio_direction
        +--rw active_state?   active
  • sgpio/gpio section defines how the signals are mapped to either SGPIO port/bit or GPIO ID.

  • direction is output.

  • active_state defines the signal’s active state. This is usually documented in schematics.

Example:

  gpio_restart:
    gpio: 60
    direction: GPIO_DIR_OUT
    active_state: low

1.13. GPIO-Reset

This reset is an input signal (activated by pressing a button) that indicates a reset-to-default should be performed. The SoC will immediately reset and read this signal during startup (state of the reset button). If active, the configuration is restored to default. The definition looks like this:

module: board
  +--rw drivers
     +--rw gpio_reset
        +--rw (ref)
        |  +--:(sgpio)
        |  |  +--rw sgpio
        |  |     +--rw ref_sgpio_bank    dev_sgpio_bank
        |  |     +--rw port              uint8
        |  |     +--rw bit               uint8
        |  +--:(gpio)
        |     +--rw gpio?     uint32
        +--rw direction       gpio_direction
        +--rw active_state?   active
  • sgpio/gpio section defines how the signals are mapped to either SGPIO port/bit or GPIO ID.

  • direction is input.

  • active_state defines the signal’s active state. This is usually documented in schematics.

Example:

  gpio_reset:
    gpio: 2
    direction: GPIO_DIR_IN

1.14. Status Leds

A board can define up to four status GPIOs. Each one has a drive state for the boot phase and another for normal operation, so the same mechanism covers both a blinking LED that shows the system is alive and a steady signal an external host can sample to detect that the system has restarted.

Defining more than four is a board configuration error and is reported at startup.

module: board
  +--rw drivers
     +--rw status_leds
        +--rw status_led* [instance_id]
           +--rw instance_id                    uint8
           +--rw (ref)
           |  +--:(sgpio)
           |  |  +--rw sgpio
           |  |     +--rw ref_sgpio_bank    dev_sgpio_bank
           |  |     +--rw port              uint8
           |  |     +--rw bit               uint8
           |  +--:(gpio)
           |     +--rw gpio?                    uint32
           +--rw direction                      gpio_direction
           +--rw active_state?                  active
           +--rw gpio_state_at_init?            status_led_state_init
           +--rw gpio_state_at_boot_complete?   status_led_state
  • instance_id identifies the instance and must be unique. A duplicate is reported at startup.

  • direction must be GPIO_DIR_OUT.

  • sgpio/gpio section defines how the signals are mapped to either SGPIO port/bit or GPIO ID.

  • direction is output.

  • active_state defines the signal’s active state. This is usually documented in schematics. It defaults to high.

  • gpio_state_at_init is the state held while the system boots. It defaults to tri_state.

  • gpio_state_at_boot_complete is the state taken once boot has completed. It defaults to blink.

The two state leaves take these values:

Value Meaning

tri_state

The pin is released and left high impedance, so an external pull resistor determines its level. Not available for a pin behind an SGPIO or an I2C expander, which is always driven.

active

The pin is driven to the level given by active_state.

inactive

The pin is driven to the opposite of active_state.

blink

The pin alternates between the active and the inactive level once per second. Only valid for gpio_state_at_boot_complete.

Note that active and inactive describe the signal, not the voltage: the pin level follows from active_state. To drive a pin high once boot has completed, set active_state: high and gpio_state_at_boot_complete: active.

Example of a blinking status LED, wired active low:

  status_leds:
    status_led:
      - instance_id: 0
        gpio: 61
        direction: GPIO_DIR_OUT
        active_state: low
        gpio_state_at_init: inactive
        gpio_state_at_boot_complete: blink

Example of a signal for detecting that the system has restarted. The pin is pulled low on the board, so it is left released while booting and driven high afterwards. A host sampling the pin sees it go low for as long as the system is booting:

  status_leds:
    status_led:
      - instance_id: 1
        gpio: 14
        direction: GPIO_DIR_OUT
        active_state: high
        gpio_state_at_init: tri_state
        gpio_state_at_boot_complete: active

status_leds supersedes the earlier status_led container, which held a single LED. That container is deprecated but still honoured: it configures one status LED, driven inactive while booting and blinking once boot has completed — the behaviour it had before the drive states became configurable.

The two are mutually exclusive. A board configuration defining both is rejected at startup, so a migration has to be completed rather than left half done.

1.15. PHY Reset

The PHY’s reset state is controlled through the pin defined here.

module: board
  +--rw drivers
    +--rw phy_reset
       +--rw (ref)
       |  +--:(sgpio)
       |  |  +--rw sgpio
       |  |     +--rw ref_sgpio_bank    dev_sgpio_bank
       |  |     +--rw port              uint8
       |  |     +--rw bit               uint8
       |  +--:(gpio)
       |     +--rw gpio?     uint32
       +--rw direction       gpio_direction
       +--rw active_state?   active
  • sgpio/gpio section defines how the signals are mapped to either SGPIO port/bit or GPIO ID.

  • direction is output.

  • active_state defines the signal’s active state. This is usually documented in schematics.

Example:

  phy_reset:
    gpio: 62
    direction: GPIO_DIR_OUT
    active_state: low

1.16. WatchDog

The watchdog is a hardware timer and helps to ensure the system can recover from unforeseen failures. It reboots the system if its timer has not been updated by the CPU within a period that is set here. If left out, then the watchdog is disabled.

module: board
  +--rw drivers
     +--rw watchdog
        +--rw timeout?   enumeration

Example, when timeout is set to 2 seconds:

  watchdog:
    timeout: timeout_2000ms

1.17. FS (File System)

This section defines the file types that are needed to be stored in the flash. The types must be defined in lm_os.h. If the type is not defined here a storage is not possible. Minimum file/block size is 4096B.

module: board
  +--rw fs
     +--rw files* [type]
        +--rw type        fs_type
        +--rw offset?     uint32
        +--rw max_size?   uint32

Example, when the startup-cfg is enabled at offset 0 and max size is set to 48KB:

  fs:
    files:
      - type: FS_TYPE_STARTUP
        offset: 0
        max_size: 49152 # 48KB

1.18. TimeStamp properties

This container contains timestamping proterties. Currently it has a list of time-stamp calibration profiles, which a given port can link to.

Index 0 in the calibrations list is reserved for interfaces which does not use/require any calibration.
module: board
  +--rw drivers
     +--rw timestamp
        +--rw calibrations* [idx]
           +--rw idx            uint32
           +--rw calibration* [type]
              +--rw type    ts_type
              +--rw rx?     int32
              +--rw tx?     int32
timestamp:
    calibrations:
      - idx: 1
        calibration:
          - type: SPEED_10MBIT
            rx: 37000
            tx: 10000
          - type: SPEED_100MBIT
            rx: 350
            tx: 350
          - type: SPEED_1000MBIT
            rx: 0
            tx: 0
      - idx: 2
        calibration:
          - type: SPEED_100MBIT
            rx: 950
            tx: 950
          - type: SPEED_1000MBIT
            rx: 0
            tx: 0
          - type: SPEED_10000MBIT
            rx: 0
            tx: 0
The profile will only be used by ports which points to it in the drivers/bridge/eth_ports/eth_port/ts_calibration leaf. See Bridge.

1.19. Port Leds

This section defines how the front port LEDs should be accessed, typically SFP-based LEDs. Each switch port typically has two LEDs: green for 'high' speed and a second one (red/yellow/orange, etc.) for 'low' speed. Note that the PHYs usually control the LEDs directly through their own GPIOs and do not require any board configuration setup.

module: board
  +--rw drivers
     +--rw port_leds
        +--rw port_led* [portno]
           +--rw portno        uint32
           +--rw led_green
           |  +--rw (ref)
           |  |  +--:(sgpio)
           |  |  |  +--rw sgpio
           |  |  |     +--rw ref_sgpio_bank    dev_sgpio_bank
           |  |  |     +--rw port              uint8
           |  |  |     +--rw bit               uint8
           |  |  +--:(gpio)
           |  |     +--rw gpio?     uint32
           |  +--rw direction       gpio_direction
           |  +--rw active_state?   active
           +--rw led_second
              +--rw (ref)
              |  +--:(sgpio)
              |  |  +--rw sgpio
              |  |     +--rw ref_sgpio_bank    dev_sgpio_bank
              |  |     +--rw port              uint8
              |  |     +--rw bit               uint8
              |  +--:(gpio)
              |     +--rw gpio?     uint32
              +--rw direction       gpio_direction
              +--rw active_state?   active
  • portno defines to which switch front port (zero-based) these LEDs belong.

  • led_green defines how the green LED is accessed through SGPIOs or GPIOs.

  • led_second defines how the second LED is accessed through SGPIOs or GPIOs.

  • sgpio/gpio section defines how the signals are mapped to either SGPIO port/bit or GPIO ID. Example:

  port_leds:
    port_led:
      - portno: 24
        led_green:
          sgpio:
            ref_sgpio_bank: DEV_SGPIO_BANK_0
            port: 24
            bit: 0
          direction: GPIO_DIR_OUT
          active_state: low
        led_second:
          sgpio:
            ref_sgpio_bank: DEV_SGPIO_BANK_0
            port: 24
            bit: 1
          direction: GPIO_DIR_OUT
          active_state: low

1.20. Bridge

The Ethernet bridge interconnects multiple ports to form a LAN. This section defines the switch chip and the properties of each of the attached ports and phys.

module: board
  +--rw drivers
     +--rw bridge
        +--rw mux_mode?      port_mux_mode
        +--rw target_chip    target_chip_type
        +--rw eth_ports
           +--rw eth_port* [port_dev]
              +--rw port_dev          uint32
              +--rw phy_mode          phy_mode
              +--rw phy_chip?         int32
              +--rw in_band_aneg?     boolean
              +--rw bandwidth?        uint32
              +--rw ts_calibration?   uint32
              +--rw phy
                 +--rw ref_miim_bus       miim_bus
                 +--rw miim_addr          uint32
                 +--rw dummy?             boolean
                 +--rw base_port?         uint32
                 +--rw extmod?            boolean
                 +--rw media_interface?   media_interface
                 +--rw phy_driver_id?  uint32
                 +--rw phy_readback* [addr]
                 |  +--rw addr     uint32
                 |  +--rw value?   uint16
                 |  +--rw mask?    uint16
                 +--rw fixed_link
                 |  +--rw speed?   uint32
                 |  +--rw role?    phy_role
                 +--rw led* [id]
                 |  +--rw id      phy_led_id
                 |  +--rw mode    phy_led_mode
                 +--rw tunables* [link_id]
                    +--rw link_id    link_id_enum
                    +--rw tunable* [type]
                       +--rw type     tunable
                       +--rw value?   uint32
  • mux_mode defines which devices and serdeses are used. Used on some SoCs.

  • phy_mode defines the PHY to MAC interface. Valid values:

    • rgmii — RGMII (10/100/1G), 12-pin interface using a synchronous 125 MHz clock

    • rgmii_txid — RGMII with 2 ns internal TX delay

    • rgmii_rxid — RGMII with 2 ns internal RX delay

    • rgmii_id — RGMII with 2 ns internal RX and TX delay

    • rmii — RMII (10/100)

    • sgmii — SGMII (10/100/1G), 8B/10B PCS encoding, supports in-band Cisco SGMII aneg

    • qsgmii — QSGMII, equivalent to 4xSGMII over a single serdes

    • 1000base-x — 1000BASE-X (1G, 8B/10B PCS, Clause-37 in-band aneg)

    • 2500base-x — 2500BASE-X (2.5G, 8B/10B PCS, no autoneg)

    • 10gbase-r — 10GBASE-R (10G), 64B/66B PCS encoding at 10.3125 Gbaud

  • target_chip The physical chip sometimes supports different skews. target_chip defines which one.

  • port_dev defines the chip port device to be used.

  • phy_chip defines the physical PHY chip this port is associated with, for hardware monitoring.

  • bandwidth defines the internal switch core bandwidth this port requires.

  • ts_calibration (optionally) points to time-stamping calibration profile defined in TimeStamp properties

  • in_band_aneg means that the PHY status is fetched via the device PCS as opposed to via MDIO access. Supported for some interfaces.

  • ref_miim_bus defines the PHY MIIM bus ID.

  • miim_addr defines the PHY address on the bus.

  • dummy means that this is a software PHY and PHY access is disabled. Typically used where PHY access is not possible. A fixed_link with the desired speed must also be configured so the dummy PHY knows what link speed to report. ref_miim_bus and miim_addr must be present (to satisfy the YANG model) but are ignored at runtime.

  • base_port is used for quad PHYs for determining which port ID should be used for access of shared resources.

  • extmod (optionally) declare that this PHY shall be implemented by the EXTMOD instead of the build-in driver library. See this for additional details.

  • media_interface configures which media interface the PHY is using. If the leaf is missing then the default is cu. Valid values:

    • cu — copper interface

    • 1000base-x — use 1000BASE-X (1G, 8B/10B PCS, Clause-37 in band aneg)

    • sgmii — SGMII (10/100/1G), 8B/10B PCS encoding supports in-band Cisco SGMII aneg

  • phy_driver_id (optionally) means that the PHY driver with this ID will be used for the device instead of what is in registers 2 and 3 of the device. This is used when you want to force loading a specific driver for a PHY device. In this way it is possible that the same binary file can support future PHY devices.

  • phy_readback (optionally) means that the SW will read the registers of the PHYs and compare them with the expected value. This is used to check that the expected PHY is on the board. This list can contain 0 or up to 4 entries.

  • addr the PHY register address. The address is encoded as a single u32, where the most significant 16 bits are the page, and the least significant 16 bits are the address.

  • value the expected value to be found at the PHY register address

  • mask both the expected value and the value read from the register will be anded with this mask before being compared.

  • fixed_link means that the speed is forced as opposed to 'aneg', and is left out when aneg is enabled.

  • speed defines the speed of the fixed_link.

  • role defines the role (master/slave) of the PHY, and is left out when aneg is enabled.

  • led defines the LED settings for the PHY. Supported for some PHYs.

  • tunables configures the tunables on the interface.

    • link_id decides which points on the interface to configure. It is possible to configure the following points

      • switch which is the switch side

      • phy_host which is on the PHY towards the switch

      • phy_line which is on the PHY towards the line side

    • tunable contains a list of tunable that are configured on the interface

      • type describes the tunable type. Currently only tx_ampl is supported

      • value the value to be set in the register

The following example is a bridge with one PHY-based port, one SFP-based port, and one dummy PHY port:

    target_chip: lan9696tsn
    eth_ports:
      eth_port:
        - port_dev: 0
          phy_mode: qsgmii
          phy_chip: 1
          bandwidth: 1000
          phy:
            ref_miim_bus: MIIM_BUS_0
            miim_addr: 4
            base_port: 0
            led:
              - id: led0
                mode: link1000_activity
              - id: led1
                mode: link10_100_activity
        - port_dev: 24
          phy_mode: 10gbase-r
          bandwidth: 10000
          ts_calibration: 2
        - port_dev: 29
          phy_mode: sgmii
          bandwidth: 1000
          phy:
            ref_miim_bus: MIIM_BUS_0
            miim_addr: 0
            dummy: true
            fixed_link:
              speed: 1000

1.21. PTP

Pin configuration of PTP functions. This section defines the GPIO to PTP mapping.

module: board
  +--rw drivers
     +--rw ptp
        +--ro pins* []
           +--ro pin_ctrl
              +--ro pins*           uint32
              +--ro pin_function    pin_function
  • pin_ctrl is used to assign physical pins on the SoC to this function. Check the datasheet for an overview of what pins can be used.

  • pins defines the GPIO(s) ID.

  • pin_function defines the mode to configure the pin(s).

The following example maps 3 GPIOs to the 1PPS PTP function ALT4:

  ptp:
    pins:
      - pin_ctrl:
          pins: [57, 58, 59]
          pin_function: alt4

1.22. EXTMOD (Driver)

A EXTMOD Driver used to claim HW resources and expose the relevant HW to the EXTMOD module. The EXTMOD module will have to decide what to do with it.

Currently, only GPIOs can be assigned to EXTMOD.

module: board
  +--rw drivers
     +--rw extmod
        +--ro gpios* []
           +--ro (ref)
           |  +--:(sgpio)
           |  |  +--ro sgpio
           |  |     +--ro ref_sgpio_bank    dev_sgpio_bank
           |  |     +--ro port              uint8
           |  |     +--ro bit               uint8
           |  +--:(gpio)
           |     +--ro gpio?     uint32
           +--ro direction       gpio_direction
           +--ro active_state?   active

Following is an example on how to assign GPIO 25 and 26 to the GPIO module.

When using the GPIO, the lmeo_gpio_read/write functions operate on index in this array meaning that to access GPIO 25, one will have to use index 0.
  extmod:
    gpios:
    - gpio: 25
      direction: GPIO_DIR_IN
    - gpio: 26
      direction: GPIO_DIR_OUT
      active_state: low

2. Allocating of resources (capabilities)

The capabilities section is used to provide selected configurations for the application. All capability configurations are parsed at boot-time, and if this configuration requires memory to be allocated, then this allocation is done before the MUP1 announce packet is emitted.

If too many resources are assigned, it will result in a fatal boot error, and the board-tailor needs to lower the counts.

Here is what the capability section looks like in the board.tree:

module: board
  +--rw capabilities
     +--rw manufacturer          string
     +--rw model                 string
     +--rw platform_id?          uint16
     +--rw l3_count?             uint32
     +--rw ltc_count?            uint32
     +--rw ltc_pin_count?        uint8
     +--rw phy_timestamping?     boolean
     +--rw stream_count?         uint32
     +--rw coap_session_count?   uint32
     +--rw arp_count?            uint32
     +--rw ipv4_route_count?     uint32

Where:

  • manufacturer: is a string returned by the IETF-HW YANG manufacturer leaf.

  • model: is the model returned in the IETF-System YANG.

  • platform_id?: Firmware-image compatibility identifier for this board (see Firmware image compatibility (platform_id) below). Omit it (or set 0) to disable the firmware-image platform check.

  • l3_count?: Is the number of L3 interfaces. This shall be set to 1 on SW variants without routing support, and can be up to 32 on SW variants with routing support.

  • ltc_count?: Is the number of PTP instances (each instance is tied to a PTP domain). Set this to 3, as this is the number of domains supported in HW.

  • ltc_pin_count?: Number of PTP Pins which can be used for 1PPS in/out.

  • phy_timestamping?: Select if PHY time-stamping shall be used (requires PHYs with time-stamping support).

  • stream_count?: Number of PSFP Streams.

  • coap_session_count?: Number of CoAP sessions to support.

  • arp_count?: Number of ARP entries to support.

  • ipv4_route_count?: Number of IPv4 static routes. This shall be set to zero on SW variants without routing, and above 1 on systems with SW routing.

  • mld_instance_count?: Number of MLD snooping instances.

  • mld_group_count?: Number of MLD multicast groups (across all instances).

  • mld_source_count?: Number of MLD source entries (across all groups).

Here is an example of the capabilities:

board:capabilities:
  manufacturer: "Microchip Technology Inc."
  model: "LAN9698RED - EV89P81A (UNG8422)"
  platform_id: 0x0003
  l3_count: 1
  ltc_count: 3
  ltc_pin_count: 8
  phy_timestamping: false
  stream_count: 64
  coap_session_count: 4
  arp_count: 64
  ipv4_route_count: 0
  mld_instance_count: 8
  mld_group_count: 128
  mld_source_count: 512

2.1. Firmware image compatibility (platform_id)

Every firmware image is stamped with the platform_id of the board it was built for, and the firmware-update service rejects an image whose id is not compatible with the running board before writing flash — this stops an image for a different platform from bricking the device.

Assign ids per compatibility group: boards that should accept each other’s images get the same value, so set it in the base board configuration and the auto / no-security / DTLS variants inherit it. The Microchip lan969x boards use one id per SoC:

SoC (target_chip) platform_id

lan9692vao (EV09P11A, EV22N59A)

0x0001

lan9696red (EV23X71A)

0x0002

lan9698red (EV89P81A)

0x0003

Rules:

  • Assignable values are 0x0001–0x7ffe. Bit 15 is reserved: the build sets it on the bootloader image so an application image cannot be written to the bootloader (and vice versa).

  • 0x0000 (the default when omitted) disables the check on that board.

  • The build reads platform_id from the board configuration and stamps it into the image automatically; no per-image build flag is needed.

3. Factory defaults

The factory defaults can contain the full CORECONF data-store, and is applied at boot time if no user-configuration is stored in flash.

An example of a factory defaults which includes port 1 and port 2 in VLAN 1 is shown below:

board:factory_default_config:
  ieee802-dot1q-bridge:bridges:
    bridge:
      - name: b0
        component:
          - name: c0
            filtering-database:
              vlan-registration-entry:
                - database-id: 0
                  vids: '1'
                  entry-type: static
                  port-map:
                    - port-ref: 1
                      static-vlan-registration-entries:
                        vlan-transmitted: untagged
                    - port-ref: 2
                      static-vlan-registration-entries:
                        vlan-transmitted: untagged