diff options
Diffstat (limited to 'docs/zephyr')
-rw-r--r-- | docs/zephyr/project_config.md | 174 | ||||
-rw-r--r-- | docs/zephyr/zephyr_build.md | 172 | ||||
-rw-r--r-- | docs/zephyr/zephyr_i2c.md | 370 | ||||
-rw-r--r-- | docs/zephyr/zephyr_init.md | 53 | ||||
-rw-r--r-- | docs/zephyr/zephyr_new_board_checklist.md | 65 | ||||
-rw-r--r-- | docs/zephyr/zephyr_poc_device_bringup.md | 52 | ||||
-rw-r--r-- | docs/zephyr/zephyr_shim.md | 381 | ||||
-rw-r--r-- | docs/zephyr/zephyr_template.md | 56 | ||||
-rw-r--r-- | docs/zephyr/ztest.md | 200 |
9 files changed, 1523 insertions, 0 deletions
diff --git a/docs/zephyr/project_config.md b/docs/zephyr/project_config.md new file mode 100644 index 0000000000..285e90dbdd --- /dev/null +++ b/docs/zephyr/project_config.md @@ -0,0 +1,174 @@ +Project Configuration +===================== + +[TOC] + +## Setting up a new program ("reference board" or "baseboard") + +Unlike the legacy EC codebase, Zephyr projects all live together in +one big happy directory. The intent of this design is to encourage +code-sharing between projects, and reduce the amount of copy/paste +that is required to bring up a new project. This directory can, but +does not have to, correlate to the unified build Chrome OS board, +however firmware authors can always choose a different structure if it +makes sense for the specific scenario. As a hypothetical example, +similar Chromeboxes and Chromebooks may wish to share the Zephyr EC +project directory instead of use separate directories, even if they +are using a different unified build board. + +To set up a new EC program, create a new directory under +[`zephyr/projects`](../../zephyr/projects) with the following files: + +- `BUILD.py` - specifies which builds can be made from this directory, + and what the device-tree overlays and Kconfig files are for each + build. +- `CMakeLists.txt` - Baseboard-specific C files can be listed here. +- `prj.conf` (optional) - Default Kconfig settings for all projects. +- `Kconfig` (optional) - Set options for your reference design here, + which variants can use to install optional C sources. + +An in-depth example of each file is given below: + +### BUILD.py + +`BUILD.py` is a Python-based config file for setting up your reference +board and the associated variants. The name `BUILD.py` is important +and case-sensitive: `zmake` searches for files by this +name. + +When `BUILD.py` is sourced, the following two globals are defined: + +- `here`: A `pathlib.Path` object containing the path to the directory + `BUILD.py` is located in. +- `register_project`: A function which informs `zmake` of a new + project to be built. Your `BUILD.py` file needs to call this + function one or more times. + +`register_project` takes the following keyword arguments: + +- `project_name` (required): The name of the project (typically the + Google codename). This name must be unique amongst all projects + known to `zmake`, and `zmake` will error if you choose a conflicting + name. +- `zephyr_board` (required): The name of the Zephyr board to use for + the project. The Zephyr build system expects a Zephyr board + directory under `boards/${ARCH}/${ZEPHYR_BOARD_NAME}`. **Note:** + the concept of a Zephyr board does not align with the Chrome OS + concept of a board: for most projects this will typically be the + name of the EC chip used, not the name of the model or overlay. +- `supported_toolchains` (required): A list of the toolchain names + supported by the build. Valid values are `coreboot-sdk`, `host`, + `llvm`, and `zephyr`. Note that only `coreboot-sdk` and `llvm` are + supported in the chroot, and all projects must be able to build in + the chroot, so your project must at least list one of `coreboot-sdk` + or `llvm`. +- `output_packer` (required): An output packer type which defines + which builds get generated, and how they get assembled together into + a binary. +- `modules` (optional): A list of module names required by the + project. The default, if left unspecified, is to use all modules + known by `zmake`. Generally speaking, there is no harm to including + unnecessary modules as modules are typically guarded by Kconfig + options, so the only reason to set this is if your project needs to + build in a limited environment where not all modules are available. +- `is_test` (optional): `True` if the code should be executed as a + test after compilation, `False` otherwise. Defaults to `False`. +- `dts_overlays` (optional): A list of files which should be + concatenated together and applied as a Zephyr device-tree overlay. + Defaults to no overlays (empty list). +- `project_dir` (optional): The path to where `CMakeLists.txt` and + `Kconfig` can be found for the project, defaulting to `here`. + +Note that most projects will not want to call `register_project` +directly, but instead one of the helper functions, which sets even +more defaults for you: + +- `register_host_project`: Define a project which runs in the chroot + (not on hardware). +- `register_host_test`: Just like `register_host_project`, but + `is_test` gets set to `True`. +- `register_raw_project`: Register a project which builds a single + `.bin` file, no RO+RW packing, no FMAP. +- `register_binman_project`: Register a project which builds RO and RW + sections, packed together, and including FMAP. +- `register_npcx_project`: Just like `register_binman_project`, but + expects a file generated named `zephyr.npcx.bin` for the RO section + with Nuvoton's header. + +You can find the implementation of these functions in +[`zephyr/zmake/zmake/configlib.py`](../../zephyr/zmake/zmake/configlib.py). + +`BUILD.py` files are auto-formatted with `black`. After editing a +`BUILD.py` file, please run `black BUILD.py` on it. + +### CMakeLists.txt + +This file, should at minimum contain the following: + +``` cmake +cmake_minimum_required(VERSION 3.20.1) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(ec) +``` + +You may additionally want to specify any C files or include +directories your project needs using `zephyr_library_sources` or +`zephyr_library_include_directories`. + +### prj.conf and prj_${project_name}.conf + +`prj.conf` has default Kconfig settings for all projects, and +`prj_${project_name}.conf` can contain overrides for certain projects. +The format is `KEY=VALUE`, as typical for Kconfig. + +### Kconfig + +If certain projects need project-specific C files or ifdefs, the only +way to do so is to create a `Kconfig` file with the options schema you +want, and use it to toggle the inclusion of certain files. + +The file must end with a single line that reads +`source "Kconfig.zephyr"`. Note that this file is optional, so it's +recommended to only include it if you really need it. + +## Setting up a new variant of an EC program + +**Unlike our legacy EC, there are no files or directories to copy and +paste to setup a new variant in Zephyr code.** + +Simply add a `register_project`-based call to the existing `BUILD.py` +for your reference board. + +Below is an example of how programs may wish to structure this in +`BUILD.py`: + +``` python +# Copyright 2021 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +def register_variant(project_name, chip="it8xx2", extra_dts_overlays=()): + register_binman_project( + project_name=project_name, + zephyr_board=chip, + dts_overlays=[ + here / "base_power_sequence.dts", + here / "i2c.dts", + **extra_dts_overlays, + ], + ) + + +# Reference board +register_variant( + project_name="asurada", + extra_dts_overlays=[here / "reference_gpios.dts"], +) + +# Variants +register_variant( + project_name="hayato", + extra_dts_overlays=[here / "hayato_gpios.dts"], +) +``` diff --git a/docs/zephyr/zephyr_build.md b/docs/zephyr/zephyr_build.md new file mode 100644 index 0000000000..60a9e1d97e --- /dev/null +++ b/docs/zephyr/zephyr_build.md @@ -0,0 +1,172 @@ +# Building Zephyr OS + +[TOC] + +Chromium OS EC uses the `zmake` tool to build Zephyr. + +This section describes how to build and use zmake. + +## Syncing the source + +N.B. The Zephyr build relies on multiple repos and tools which get installed as +packages into the chroot. This means that partial syncs are not supported +(i.e. just doing `repo sync .` in platform/ec). You must run +`~/trunk/src/scripts/update_chroot` frequently, ideally each time you do a full +repo sync. This will update zmake and the repos in src/third_party/zephyr + + +## Working inside the chroot + +### Install zmake + +The `zephyr-build-tools` ebuild builds and installed zmake. This should happen +automatically, with the caveat above. + +To do this manually and run tests: + +```bash +FEATURE=test sudo -E emerge zephyr-build-tools +``` + + +### Building + +You can build zephyr with: + +```bash +emerge-volteer chromeos-zephyr +``` + +For local development you can run zmake directly; see instruction below. + +## Working outside the chroot + +Running outside the Chromium OS chroot is useful for upstream work and for +those using the EC outside the Chromium OS. + + +### Remove west, if installed [b/184654974](http://b/184654974) + +Zephyr's Cmake system will try to attach itself to the west tool if it finds it +installed, conflicting with manual cmake invocations. If you installed west, +you'll need to remove it: + +```bash +python3 -m pip uninstall west +``` + + +### Install zmake + +You can install zmake with pip: + +```bash +cd ~/chromiumos/src/platform/ec +python3 -m pip install -e zephyr/zmake --user +``` + +Ensure that ~/.local/bin in on your PATH + +You may also need to install these items: + +```bash +sudo apt-get install cmake ninja-build python3-pyelftools gcc-multilib \ + python3-pykwalify python3-colorama python3-testfixtures +``` + +You must reinstall zmake after any `repo sync` since new features may have been +added that are needed by the build. + + +### Install binman + +First build pylibfdt: + +```bash +cd somewhere +sudo apt-get install flex bison swig +git clone git://git.kernel.org/pub/scm/utils/dtc/dtc.git +cd dtc +make +make install PREFIX=~/.local # You can install this where it suits +``` + +If you have a Chromium OS checkout then you should do: + +```bash +cd ~/.local/bin +ln -s ~/chromiumos/src/third_party/u-boot/files/tools/binman/binman +``` + +otherwise: + +```bash +cd somewhere +git clone https://source.denx.de/u-boot/u-boot.git +cd ~/.local/bin +ln -s somewhere/u-boot/tools/binman/binman +``` + +As above, ensure that `~/.local/bin` in on your PATH + + +### Install Zephyr toolchain + +If using the Zephyr toolchain (`-t zephyr`), follow the [upstream +documentation] to install the Zephyr build tools. + +[upstream documentation]: https://docs.zephyrproject.org/getting_started/index.html#install-a-toolchain + + +### Building + +You can use `zmake help` to obtain help on how to use zmake. The following is +a rough guide. + +First configure the build with the project you want: + +```bash +# Use -t zephyr when running outside chroot + +zmake configure -B /tmp/z/vol zephyr/projects/volteer/volteer/ -t zephyr +``` + +If you are building for posix-ec, change the default toolchain to host to make +it use the system toolchain instead of llvm. Make sure to start with a clean +build directory if zmake returns any build error: + +```bash +zmake configure -B /tmp/posix zephyr/projects/posix-ec -t host +``` + +Then build with just the target directory: + +``` +zmake build /tmp/z/vol +``` + +The output is in that directory: + +* `output/zephyr.bin` - output binary (read-only and read-write packed + together) +* `output/zephyr.ro.elf` - read-only ELF for debugging +* `output/zephyr.rw.elf` - read-write ELF for debugging + +You might also find these files useful (using read-only as an example): + +* `build-ro/zephyr/.config` - Kconfig options selected +* `build-ro/zephyr/include/generated/devicetree_unfixed.h` - the (large) + header file that zephyr uses to provide devicetree information to the C code +* `build-ro/zephyr/zephyr.dts` - devicetree that is used +* `build-ro/zephyr/zephyr.dts` - map of image + + +### Looking at the Kconfig + +It should be possible to do this with: + +```bash +ninja -C /tmp/z/vol/build-ro menuconfig +``` + +However at present this does not work [b/184662866](http://b/184662866). diff --git a/docs/zephyr/zephyr_i2c.md b/docs/zephyr/zephyr_i2c.md new file mode 100644 index 0000000000..625efa98a5 --- /dev/null +++ b/docs/zephyr/zephyr_i2c.md @@ -0,0 +1,370 @@ +# Zephyr I2C Bus Configuration + +[TOC] + +## Overview + +The [I2C] buses provide access and control to on-board peripherals, including +USB-C chips, battery, charging IC, and sensors. + +## Kconfig Options + +Kconfig Option | Default state | Documentation +:--------------------------------- | :-----------: | :------------ +`CONFIG_PLATFORM_EC_I2C` | y | [EC I2C] + +The following options are available only when `CONFIG_PLATFORM_EC_I2C=y`. + +Kconfig sub-option | Default | Documentation +:-------------------------------------------- | :-----: | :------------ +`CONFIG_I2C_SHELL` | y | [CONFIG_I2C_SHELL] +`CONFIG_PLATFORM_EC_I2C_DEBUG` | n | [I2C Debug] +`CONFIG_PLATFORM_EC_I2C_DEBUG_PASSTHRU` | n | [I2C Debug Passthru] +`CONFIG_PLATFORM_EC_CONSOLE_CMD_I2C_PORTMAP` | n | [I2C Portmap] +`CONFIG_PLATFORM_EC_CONSOLE_CMD_I2C_SPEED` | n | [I2C Speed] +`CONFIG_PLATFORM_EC_HOSTCMD_I2C_CONTROL` | n | [I2C Control] +`CONFIG_PLATFORM_EC_I2C_PASSTHRU_RESTRICTED` | n | [I2C Passthru Restricted] + +## Devicetree Nodes + +The EC chip disables all I2C buses by default. Enable the I2C buses used on +your design by changing the chip-specific I2C bus `status` property to `"okay"`. + +I2C bus properties: + +Property | Description | Settings +:------- | :---------- | :------- +`status` | Enables or disables the I2C controller | `"okay"` <br> `"disabled"` +`label` | Override the EC chip specific label. We recommend changing the label to match the net name of the I2C bus. The label must begin with `"I2C_"`. |`"I2C_<net_name>"` +`clock-frequency` | Sets the initial I2C bus frequency in Hz. | `I2C_BITRATE_STANDARD` - 100 KHz <br> `I2C_BITRATE_FAST` - 400 KHz <br> `I2C_BITRATE_FAST_PLUS` - 1 MHz + +Example enabling I2C0 and I2C3 at 100 KHz and 1 MHz, respectively. +``` +&i2c0 { + status = "okay"; + label = "I2C_BATTERY"; + clock-frequency = <I2C_BITRATE_STANDARD>; +}; +&i2c3 { + status = "okay"; + label = "I2C_USB_C0_PD"; + clock-frequency = <I2C_BITRATE_FAST_PLUS>; +}; +``` + +### Nuvoton NPCX ECs + +Nuvoton ECs use two devicetree nodes to describe the I2C buses used, an I2C +controller and an I2C port. + +Nuvoton I2C node labels use the following pattern: +- I2C controller: `&i2c_ctrl<controller>` +- I2C port: `&i2c<controller>_<port>` + +Where `<controller>` specifies the I2C controller number (0-7), and `<port>` +specifies the port number (0-1). You can only enable one I2C port per +controller, and not all I2C controllers support both ports. + +The Nuvoton I2C port contains the standard Zephyr I2C bus properties. The +Nuvoton I2C controller contains only the `status` property. + +To enable a Nuvoton I2C bus, set both the I2C controller and I2C port `status` +property to `"okay"`.Set the `clock-frequency` and `label` properties in the I2C +port as shown below: + +``` +&i2c_ctrl4 { + status = "okay"; +}; +&i2c4_1 { + status = "okay"; + label = "I2C_EEPROM"; + clock-frequency = <I2C_BITRATE_FAST>; +}; +``` + +### ITE IT8xxx2 ECs + +ITE ECs use a single devicetree node, `&i2c<channel>` to enable an I2C bus. +`<channel>` specifies the I2C/SMBus channel number (0-5). + +``` +&i2c3 { + status = "okay"; + label = "I2C_USB_C0_PD"; + clock-frequency = <I2C_BITRATE_STANDARD>; +}; +``` + +### Mapping legacy I2C port numbers to Zephyr devicetree nodes + +The legacy I2C API for the Chromium EC application uses an enumeration (e.g. +`I2C_PORT_ACCEL`, `I2C_PORT_EEPROM`) to specify the I2C bus during transfer +operations. + +The `named-i2c-ports` node creates the mapping between the legacy I2C bus +enumeration and the Zephyr I2C bus device instance. + +``` +named-i2c-ports { + compatible = "named-i2c-ports"; + battery { + i2c-port = <&i2c0_0>; + remote-port = <0>; + enum-name = "I2C_PORT_BATTERY"; + } +}; +``` + +You can map multiple enumeration values to the same Zephyr I2C bus device +instance. + +``` +named-i2c-ports { + compatible = "named-i2c-ports"; + battery { + i2c-port = <&i2c0_0>; + remote-port = <0>; + enum-name = "I2C_PORT_BATTERY"; + } + charger { + i2c-port = <&i2c0_0>; + remote-port = <0>; + enum-name = "I2C_PORT_CHARGER"; + }; +}; +``` + +Refer to the [cros-ec-i2c-port-base.yaml] child-binding file for details about +each property. + +## Board Specific Code + +None required. + +## Threads + +I2C support does not enable any threads. + +## Testing and Debugging + +### Shell Command: i2c +The EC application enables the the Zephyr shell command, `i2c`, when +`CONFIG_I2C_SHELL=y`. The `i2c` command includes the following [subcommands]: + +Subcommand | Description | Usage +:--------- | :---------- | :---- +`scan` | Scan I2C devices | `i2c scan <i2c_bus_label>` +`recover` | Recover I2C bus | `i2c recover <i2c_bus_label>` +`read` | Read bytes from an I2C device | `i2c read <i2c_bus_label> <dev_addr> <reg_addr> [<num_bytes>]` +`read_byte` | Read a byte from an I2C device | `i2c read_byte <i2c_bus_label> <dev_addr> <reg_addr>` +`write` | Write bytes to an I2C device | `i2c write <i2c_bus_label> <dev_addr> <reg_addr> <out_byte0> .. <out_byteN>` +`write_byte` | Write a byte to an I2C device | `i2c write_byte <i2c_bus_label> <dev_addr> <reg_addr> <out_byte>` + +I2C parameter summary: + +Parameter | Description +:-------- | :---------- +`<i2c_bus_label>` | The I2C bus label property. By default this is specified by the EC vendor in the respective devicetree include file unless you override the label in your devicetree. +`<dev_addr>` | The I2C device address, specified using 7-bit notation. Valid device addresses are 0 - 0x7F. +`<reg_addr>` | The register address with the I2C device to read or write. +`<num_bytes>` | For the `read` subcommand, specifies the number of bytes to read from the I2C device. Default is 16 bytes if not specified. +`<out_byte>` | For the `write_byte` subcommand, specifies the single data byte to write to the I2C device. +`<out_byte0>..<out_byteN>` | For the `write` subcommand, specifies the data bytes to write to the I2C device. + +### Shell Command: i2c_portmap +The shell command `i2c_portmap` displays the mapping of I2C bus enumeration to +the physical bus and to the remote port index. + +Example `i2c_portmap` output from a Volteer board: +``` +uart:~$ i2c_portmap +Zephyr physical I2C ports (9): + 0 : 0 + 1 : 0 + 2 : 1 + 3 : 2 + 4 : 3 + 5 : 4 + 6 : 4 + 7 : 5 + 8 : 5 +Zephyr remote I2C ports (9): + 0 : -1 + 1 : -1 + 2 : -1 + 3 : -1 + 4 : -1 + 5 : -1 + 6 : -1 + 7 : 7 + 8 : -1 +``` + +### I2C Tracing + +For runtime troubleshooting of an I2C device, enable the [I2C +tracing](../i2c-debugging.md) module to log all I2C transactions initiated by +the EC code. + +## Example + +The image below shows the I2C bus assignment for the Volteer reference board. + +![I2C Example] + +The Volteer reference design uses the Nuvoton NPCX EC, and needs the following +I2C buses enabled: + +Net Name | NPCX I2C Designator | Bus speed +:----------------- | :------------------ | :-------- +EC_I2C7_EEPROM_PWR | I2C7_PORT0 | 400 kHz +EC_I2C5_BATTERY | I2C5_PORT0 | 100 kHz +EC_I2C0_SENSOR | I2C0_PORT0 | 400 kHz +EC_I2C1_USB_C0 | I2C1_PORT0 | 1000 kHz +EC_I2C2_USB_C1 | I2C2_PORT0 | 1000 kHz +EC_I2C3_USB_1_MIX | I2C3_PORT0 | 100 kHz + + +### Enable Nuvoton I2C buses +The Volteer project enables the Nuvoton I2C buses in [volteer.dts]. + +```c +&i2c0_0 { + status = "okay"; + clock-frequency = <I2C_BITRATE_FAST>; + label = "I2C_SENSOR"; +}; +&i2c_ctrl0 { + status = "okay"; +}; + +&i2c1_0 { + status = "okay"; + clock-frequency = <I2C_BITRATE_FAST_PLUS>; + label = "I2C_USB_C0"; +}; +&i2c_ctrl1 { + status = "okay"; +}; + +&i2c2_0 { + status = "okay"; + clock-frequency = <I2C_BITRATE_FAST_PLUS>; + label = "I2C_USB_C1"; +}; +&i2c_ctrl2 { + status = "okay"; +}; + +&i2c3_0 { + status = "okay"; + clock-frequency = <I2C_BITRATE_STANDARD>; + label = "I2C_USB_1_MIX"; +}; +&i2c_ctrl3 { + status = "okay"; +}; + +&i2c5_0 { + status = "okay"; + clock-frequency = <I2C_BITRATE_STANDARD>; + label = "I2C_BATTERY"; +}; +&i2c_ctrl5 { + status = "okay"; +}; + +&i2c7_0 { + status = "okay"; + clock-frequency = <I2C_BITRATE_FAST>; + label = "I2C_EEPROM_PWR"; + + isl9241: isl9241@9 { + compatible = "intersil,isl9241"; + reg = <0x09>; + label = "ISL9241_CHARGER"; + switching-frequency = <SWITCHING_FREQ_724KHZ>; + }; +}; +&i2c_ctrl7 { + status = "okay"; +}; +``` + +### Map I2C Enumerations +The legacy cros-ec drivers require the board to define the following enumeration +values: + +I2C Enumeration Name | Volteer I2C Bus Mapping +:------------------- | :---------------------- +`I2C_PORT_SENSOR` | EC_I2C0_SENSOR +`I2C_PORT_ACCEL` | EC_I2C0_SENSOR +`I2C_PORT_USB_C0` | EC_I2C1_USB_C0 +`I2C_PORT_USB_C1` | EC_I2C2_USB_C1 +`I2C_PORT_USB_1_MIX` | EC_I2C3_USB_1_MIX +`I2C_PORT_POWER` | EC_I2C5_BATTERY +`I2C_PORT_BATTERY` | EC_I2C5_BATTERY +`I2C_PORT_EEPROM` | EC_I2C7_EEPROM_PWR +`I2C_PORT_CHARGER` | EC_I2C7_EEPROM_PWR + +The Volteer project establishes this map using the `named-i2c-ports` as shown +below: + +```c + named-i2c-ports { + compatible = "named-i2c-ports"; + + i2c_sensor: sensor { + i2c-port = <&i2c0_0>; + enum-name = "I2C_PORT_SENSOR"; + }; + i2c-accel { + i2c-port = <&i2c0_0>; + enum-name = "I2C_PORT_ACCEL"; + }; + i2c_usb_c0: usb-c0 { + i2c-port = <&i2c1_0>; + enum-name = "I2C_PORT_USB_C0"; + }; + i2c_usb_c1: usb-c1 { + i2c-port = <&i2c2_0>; + enum-name = "I2C_PORT_USB_C1"; + }; + usb1-mix { + i2c-port = <&i2c3_0>; + enum-name = "I2C_PORT_USB_1_MIX"; + }; + power { + i2c-port = <&i2c5_0>; + enum-name = "I2C_PORT_POWER"; + }; + battery { + i2c-port = <&i2c5_0>; + enum-name = "I2C_PORT_BATTERY"; + }; + eeprom { + i2c-port = <&i2c7_0>; + remote-port = <7>; + enum-name = "I2C_PORT_EEPROM"; + }; + charger { + i2c-port = <&i2c7_0>; + enum-name = "I2C_PORT_CHARGER"; + }; + }; +``` + +[I2C]: ../ec_terms.md#i2c +[subcommands]: https://github.com/zephyrproject-rtos/zephyr/blob/f4a0ea7b43eee4d2ee735ab6beccc68c9d40a7d0/drivers/i2c/i2c_shell.c#L245 +[I2C Example]: ../images/i2c_example.png +[EC I2C]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/ec/zephyr/Kconfig;?q="config%20PLATFORM_EC_I2C"&ss=chromiumos +[CONFIG_I2C_SHELL]: https://docs.zephyrproject.org/latest/reference/kconfig/CONFIG_I2C_SHELL.html +[I2C Debug]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/ec/zephyr/Kconfig;?q=PLATFORM_EC_I2C_DEBUG&sq=&ss=chromiumos +[I2C Debug Passthru]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/ec/zephyr/Kconfig;?q=PLATFORM_EC_I2C_DEBUG_PASSTHRU&ss=chromiumos +[I2C Portmap]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/ec/zephyr/Kconfig?q=PLATFORM_EC_CONSOLE_CMD_I2C_PORTMAP&ss=chromiumos%2Fchromiumos%2Fcodesearch +[I2C Speed]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/ec/zephyr/Kconfig?q=PLATFORM_EC_CONSOLE_CMD_I2C_SPEED&ss=chromiumos +[I2C Control]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/ec/zephyr/Kconfig?q=PLATFORM_EC_HOSTCMD_I2C_CONTROL&ss=chromiumos +[I2C Passthru Restricted]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/ec/zephyr/Kconfig?q=PLATFORM_EC_I2C_PASSTHRU_RESTRICTED&ss=chromiumos +[cros-ec-i2c-port-base.yaml]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/ec/zephyr/dts/bindings/i2c/cros-ec-i2c-port-base.yaml +[volteer.dts]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/ec/zephyr/boards/arm/volteer/volteer.dts; diff --git a/docs/zephyr/zephyr_init.md b/docs/zephyr/zephyr_init.md new file mode 100644 index 0000000000..8822736efb --- /dev/null +++ b/docs/zephyr/zephyr_init.md @@ -0,0 +1,53 @@ +# Zephyr OS-based EC Initialization Order + +Zephyr provides Z_INIT_ENTRY_DEFINE() & the extend macro to install the initial +function. The initialize flow for different levels would be like the following +(not very detailed): +* architecture-specific initialization +* `PRE_KERNEL_1` level +* `PRE_KERNEL_2` level +* `POST_KERNEL` level +* `APPLICATION` level +* main() + +The kernel and driver initial functions separate into specific initialize +levels. It couldn't put all initial functions in main() for the Zephyr OS-based +EC. It is also hard to maintain those initial priority which separates into +different files. + +This file defines some Zephyr OS-based EC initial priorities which have critical +sequence requirement for initializing: + +## PRE_KERNEL_1 +* Priority (0-9) - Reserved for system testability: + + The highest priority could be used in zephyr. Don't use it when system + development. Buffer it for the following system development & testing. + +* Priority (10-19) - Chip level system pre-initialization: + + These priorities in this range are used for critical chip initialization, + including determining the reset cause and initializing the battery-backed + RAM driver. Most chip drivers should only be initialized after + `PLATFORM_EC_SYSTEM_PRE_INIT`. + +* Priority (20) - PLATFORM_EC_SYSTEM_PRE_INIT: + + At this initialization priority, the CROS system checks the reset cause and + initializing the system reset flags. Any chip level drivers related to + determining the reset type must be at a higher priority. + +* TODO + +## PRE_KERNEL_2 +* TODO + +## POST_KERNEL +* TODO + +## APPLICATION +* TODO + +## main() +* TODO +* Start the tasks. diff --git a/docs/zephyr/zephyr_new_board_checklist.md b/docs/zephyr/zephyr_new_board_checklist.md new file mode 100644 index 0000000000..c90bd4e2f2 --- /dev/null +++ b/docs/zephyr/zephyr_new_board_checklist.md @@ -0,0 +1,65 @@ +# Creating a New Zephyr EC Project + +[TOC] + +## Overview + +This document describes the high-level steps needed to create a new Zephyr EC +project for a Chromebook design. + +## Intended Audience + +This document is for use by software engineers working in the EC codebase. This +document and the linked documents provide a guide for creating new Zephyr EC +projects and for modifying/maintaining existing Zephyr EC projects. + +## How to use this document + +The following sections detail a single feature set that needs modification for +your board design. Each feature set can be implemented with a reasonably sized +change list, and can be worked on independently. + +Each feature includes the following sub-tasks: + +- **Kconfig Options** - This section details the `Kconfig` options relevant to + the feature. `Kconfig` options are enabled in one of the [project + configuration files]. +- **Devicetree Nodes** - This section details the devicetree nodes and + properties required by the feature. +- **Board Specific Code** - When present, this section details any C code that + your project must implement. +- **Threads** - This section details the threads created by the feature and + provides an overview of each thread. +- **Testing and Debugging** - This section details strategies for testing the EC + feature set and for debugging issues. This section also documents EC console + commands related to the feature set. +- **Example** - This section walks through a complete example for configuring an + EC feature based on existing board implementation. + +## Adding a new board to zmake + +Refer the [zmake](TODO) documentation to add a new board project to zmake. + +## Configure EC Features + +The checklist below provides an overview of EC features that you must configure +for correct operation of a Chromebook. The “Needed for Power On” column +indicates the critical features needed during board bringup. Use the +documentation link for details about the code changes required to implement each +feature. + +EC Feature | Needed for Power On +:-------------------------------------------------------------------------- | :-----------------: +[Configure EC Chipset (TODO)](./zephyr_template.md) | yes +[Configure AP to EC Communication (TOD0)](./zephyr_template.md) | yes +[Configure AP Power Sequencing (TODO)](./zephyr_template.md) | yes +[Configure USB-C (TODO)](./zephyr_template.md) | yes +[Configure Charger (TODO)](./zephyr_template.md) | yes +[Configure I2C Buses (TODO)](./zephyr_template.md) | yes +[Configure Batteries (TODO)](./zephyr_template.md) | no +[Configure CrOS Board Information (CBI) (TODO)](./zephyr_template.md) | no +[Configure Keyboard (TODO)](./zephyr_template.md) | no +[Configure LEDs (TODO)](./zephyr_template.md) | no +[Configure Motion Sensors (TODO)](./zephyr_template.md) | no +[Configure BC1.2 Charger Detector (TODO)](./zephyr_template.md) | no +[Configure Battery (TODO)](./zephyr_template.md) | no diff --git a/docs/zephyr/zephyr_poc_device_bringup.md b/docs/zephyr/zephyr_poc_device_bringup.md new file mode 100644 index 0000000000..394aa4a05b --- /dev/null +++ b/docs/zephyr/zephyr_poc_device_bringup.md @@ -0,0 +1,52 @@ +# Zephyr Proof-of-Concept-Device Bringup + +It may be useful to build a Zephyr OS-based EC for a device which +already has a CrOS EC device build, for the purposes of demonstrating +the feasibility of Zephyr OS. + +This document is a work-in-progress list of tricks & tools that may be +useful to you. + +## Initial Bringup + +Initially, you'll want to get a basic UART functioning with nothing +but a shell and some basic console commands. + +An example CL to do this for Lazor can be found +[here](https://crrev.com/c/2749765). + +## Bringing up GPIOs + +After you have UART functioning, GPIOs can be an easy target to start +unblocking further features. + +We have a very ugly program to auto-generate the GPIO DTS based on +gpio.inc for the existing board. You can find it at +`util/gpios_to_zephyr_dts.c`, and instructions are in the file on how +to compile and use it. You may have to hand-modify the output. + +The resultant CL for Lazor can be found [here](https://crrev.com/c/2749768). + +## Bring up Host Commands + +Set `CONFIG_PLATFORM_EC_HOSTCMD=y` and enable the appropriate +host-command interface for your platform (e.g., eSPI). + +An example CL for Lazor can be found [here](https://crrev.com/c/2749428). + +As long as you get this compiling that should be enough to move to the +next step. Further testing of the host command layer will require +power sequencing up and going. + +## Enabling some simple GPIO-based buttons and switches + +Next, you can: + +* [Add the lid switch](https://crrev.com/c/2749768) +* [Add the power button](https://crrev.com/c/2749426) +* [Add AC presence detection](https://crrev.com/c/2749428) + +## Power Sequencing + +TODO(jrosenth): add steps on enabling power sequencing and expand this +document. diff --git a/docs/zephyr/zephyr_shim.md b/docs/zephyr/zephyr_shim.md new file mode 100644 index 0000000000..fac0383aff --- /dev/null +++ b/docs/zephyr/zephyr_shim.md @@ -0,0 +1,381 @@ +[TOC] + +# Zephyr Shimming How-To + +## Objective + +Allow a subset of the platform/ec code to be built as part of the Zephyr-based +EC without needing to land code into upstream zephyr, or our zephyr-chrome +repository. + +## Background + +Now that Google has joined [Zephyr OS](https://www.zephyrproject.org/), the EC +team is moving toward it instead of platform/ec code on embedded controllers for +future Chrome OS devices. See the +[originally proposed idea](https://goto.google.com/cros-ec-rtos) and a more +specific [Zephyr process doc](https://goto.google.com/zephyr-structure) of what +future development on Zephyr will look like. + +Simply put, we want to move to Zephyr OS to use an open-source embedded OS that +has a vibrant community. The embedded OS scene for the industry is very +fragmented, with various parties using their own custom solution. We see the +strong open-source community at Zephyr as potentially helping to consolidate +efforts in the embedded controller space. It will also benefit our partners +(both chip vendors and OEMs) since they should only have to support one embedded +OS (i.e., Zephyr) for both their Chrome OS and Windows based devices. + +Migrating to use Zephyr fully is going to take a few years. We do not want to +diverge from the active development happening on platform/ec code. We +potentially want to ship a product using Zephyr before the migration is +complete. + +## Design ideas + +In order to reuse `platform/ec` development , we shim "active" `platform/ec` +code as a +[Zephyr Module](https://docs.zephyrproject.org/latest/guides/modules.html). This +requires us to add some Zephyr specific code in a `zephyr` directory in the +`platform/ec` codebase. Once we release a Zephyr-based EC, then we can turn down +platform/ec for future development and work on migrating the platform/ec-module +code out of the module directory and into a first-class Zephyr code format -- in +the local +[Chrome Zephyr repo](https://chromium.googlesource.com/chromiumos/platform/zephyr-chrome/+/HEAD) +and ultimately [upstream](https://github.com/zephyrproject-rtos/zephyr). + +For platform/ec code that is stable and not under active development, the Zephyr +team may port that code to Zephyr, thus skipping the shimming process. + +### Subsystems of interest + +#### With Shim + +We shim the following subsystems (non-exhaustive). + +* USB-C: TCPC, PPC, MUX, TCPMv2 +* Charge Manager +* SoC Power Sequencing +* Sensors, if Intel’s HID-based solution is delayed in getting to Zephyr + upstream + +#### Little-to-No Shim + +We adopt upstream Zephyr or skip the shimming process (non-exhaustive). + +* CBI and dependent EEPROM code + * The format is stable. We pull in the list of CBI tags from platform/ec + though +* EFS2, Vboot, RO/RW split + * Adjusting flash layout would be difficult to shim, and the concept is + very stable. + * We may shim some core EFS2 logic +* Host command framework +* Sensors, if Intel’s HID-based solution getts to Zephyr upstream and passes + CTS +* Keyboard and keycode scanning support + * We may shim the newer Vivaldi feature. +* Console support + * We allow individual console commands via DECLARE\_CONSOLE\_COMMAND to be + shimmed to Zephyr. These convert commands to work with Zephyr's shell + subsystem. +* I2C + +### New content in platform/ec + +Add the `src/platform/ec/zephyr` folder with: + +* [Module integration files](https://docs.zephyrproject.org/latest/guides/modules.html#build-system-integration), + e.g., module.yml, CMakeLists.txt, and KConfig. + * **module.yml** is the required entry point (must be located at + _zephyr/module.yml_ in the repository) for Zephyr modules, and declares + the location of Kconfig and CMakeLists.txt files used by the Zephyr + build system. + * **CMakeLists.txt** replicates build logic for the files being shimmed, + outside of the platform/ec Makefile. + * **Kconfig** will declare any CONFIG\_\* options which are important to + expose from platform/ec code to the Zephyr build. +* Shim code to translate platform/ec code into Zephyr code + * For example, redefine platform/ec’s + [`DECLARE_HOST_COMMAND`](https://source.chromium.org/chromiumos/chromiumos/codesearch/+/HEAD:src/platform/ec/include/host_command.h;l=256;drc=514923bc59f5a3435dbb7cbf348735ed41889ffe) + to map to Zephyr's upstream + [`EC_HOST_CMD_HANDLER`](https://github.com/zephyrproject-rtos/zephyr/blob/d7468bf836b75c29980441f294a61eae6bf4bc75/include/ec_host_cmd.h#L73) + macro. This allows us to compile select platform/ec files in the Zephyr + build. + +### Namespace Collisions + +One significant issue of mixing Zephyr headers with our existing EC code is that +we currently have many names colliding with the Zephyr code. For example, +Zephyr's atomic functions also are named `atomic_add`, `atomic_or`, ..., +however, have a different API from our EC's atomic functions. This is critical, +since atomic operations are often used in `static inline` functions placed in +header files. + +In some cases, we are able to hack around these collisions by creating macros +and functions which are compatible with both Zephyr and our EC's usages. For +example, we can create a modified `IS_ENABLED` which accepts both defined to +nothing usages (CrOS EC `config.h` style), and defined to `1` usages (Zephyr +Kconfig style). + +However, long term, we may find this to be a continual cause of issues, and +creating hacks for every colliding macro or function may be unsustainable. We +propose _gradually_ introducing a namespace prefix to the `platform/ec` +codebase, for example `crec_`. We can begin at the critical areas of namespace +collision (e.g., atomics) and continue to improve the naming convention with +time. + +### New CQ check + +As long as code from platform/ec is part of the zephyr +[ebuild](http://cs/chromeos_public/src/third_party/chromiumos-overlay/chromeos-base/chromeos-zephyr-2_3/chromeos-zephyr-2_3-9999.ebuild), +then we need to run the Zephyr CQ checks on any platform/ec CLs in addition to +the normal platform/ec CQ checks. This ensures that platform/ec changes aren’t +breaking the Zephyr builds and requiring the Zephyr team to debug recent +changes. + +For local builds, we can run `emerge-betty chromeos-zephyr-2_3` or `zmake` +utility to check that an EC CL has not broken anything on the Zephyr side. + +We will work with the CI team to enable this. + +## How to shim features + +Before you get started shimming a feature, it's important to +understand the general philosophies behind Zephyr OS and shimming: + +* Our current EC's OS isn't going away any time soon. Even after we + ship our first device with a Zephyr-based EC, we may still be working on + other projects using the old OS. It's important to consider how + your feature will apply to both the Zephyr world and CrOS EC OS + world. + +* We won't be converting old devices to use Zephyr-based firmware. + This means that our existing OS and its code will need maintained + for bug and security fixes for years to come. **Do not allow the + code you write for the CrOS EC OS to lack in quality or be "throw + away code" as it will need to be maintained for a long time.** + +* Shimming, by the very nature of the design, will lead to some ugly + hacks. We try and avoid this when we can, but some of them may be + completely unavoidable. This means we need to actively work against + nature to keep the code clean. If we do things right, there's even + a possibility that we leave things cleaner than we found them. + +* Shimming occasionally digs up landmines. Be prepared to step on + them. 💣 + +### What code can be shimmed? + +Code in the `common/` directory (and other common code directories, +like `power/`) is the ideal target for shimming, with the exception of +core OS features which have Zephyr OS equivalents. + +Code in the following directories should **never be shimmed**: + +- `core/`: this directory contains architecture-specific code which + should have a Zephyr OS equivalent feature. + +- `chip/`: this directory contains chip-specific code, and similarly + should have a Zephyr OS equivalent feature. + +In both cases, you should instead determine (or, in rare cases, +implement upstream) the equivalent Zephyr OS feature, and *implement +an architecture and chip agnostic* "shim layer" in the `zephyr/shim/` +directory which translates the APIs as necessary. + +As of the time of this document, the shim layer is nearing 100% +complete, and it should be rare that you encounter an API which needs +translation. + +Finally, code in the following directories should **avoid being +shimmed, if possible**: + +- `board/`: this directory contains variant-specific code. + +- `baseboard/`: this directory contains baseboard-specific code. + +In both cases, the only value in shimming in code from one of those +directories would be to enable a Zephyr OS build for a device which +already has CrOS EC OS support, as *Zephyr-only projects will not have +these directories*. You should be thinking about how this would be +implemented for a Zephyr-only project, and filing bugs to create the +appropriate device-tree and Kconfig equivalents before shimming this +code. + +See [Zephyr PoC device bringup](zephyr_poc_device_bringup.md) for more +information about bringing up proof-of-concept devices. + +### Configuration + +CrOS EC OS uses a special header `config.h`, which sets configuration +defaults, and includes board and chip specific configurations by +expecting the headers `board.h` and `config_chip.h` to be present. +Most of these configuration options start with `CONFIG_`, however the +rules were loosely defined over the years. + +Zephyr OS, on the other hand, uses two different configuration +systems: + +* Kconfig, the configuration system from the Linux Kernel, which + fits well within the domain of preprocessor definitions in C. The + schema for our Kconfig files can be found under `zephyr/Kconfig`, + and project-specific configurations are made in `prj.conf` files. + + Kconfig is generally used to select which EC software features are + enabled, and should be avoided for hardware configurations, such as + chip configuration registers and their default settings. + +* Open Firmware Device Tree, which you may also be familiar with from + the Linux kernel. This configuration can be found in `*.dts` files. + + Device-tree is generally used for hardware configurations, and + should be avoided for EC software feature configuration. + +For code which is shimmed, we need to play nicely with both the CrOS +EC OS configuration system, and Zephyr's configuration systems. Thus, +we follow the following pattern: + +* EC software features are configured using `Kconfig` and + `zephyr/shim/include/config_chip.h` translates them into the + appropriate CrOS EC OS configurations using patterns such as below: + + ```c + #undef CONFIG_CMD_GETTIME + #ifdef CONFIG_PLATFORM_EC_TIMER_CMD_GETTIME + #define CONFIG_CMD_GETTIME + #endif + ``` + + The preprocessor code should follow that template exactly, and not + use any nesting (Kconfig handles dependencies, there is no reason to + do it again in the preprocessor code). + +* **The domain of Kconfig options and CrOS EC configuration names + should be completely distinct.** This is because the Kconfig options + are included automatically, and including `config.h` may undefine + them. To mitigate this, we follow a convention of using + `CONFIG_PLATFORM_EC_` as the prefix for EC software features in + Kconfig. + +One special configuration option exists, `CONFIG_ZEPHYR`, which you +can use to detect whether the OS is Zephyr OS. This is the +conventional way to add Zephyr-specific (or excluded) code in CrOS EC +code. + +The typical EC macros for reducing `#ifdef` messes (e.g., +`IS_ENABLED`, `STATIC_IF`, etc.) work with both CrOS EC OS and Kconfig +options, and should be used when possible. + +### Header Files + +Besides the include paths provided by Zephyr OS, the following paths +are additionally added for shimmed code: + +* `include/` +* `zephyr/include/` +* `zephyr/shim/include/` + +The names of headers in these directories should be completely +distinct. C compilers have no mechanism for "include ordering", and +there is no way to "override a header". + +If you feel the need to "override" a header, say `foo.h` in +`include/`, the best way to do this is to give it a different name +under `zephyr/shim/include` (e.g., `zephyr_foo_shim.h`), and include +that in the `foo.h` header with a `#ifdef CONFIG_ZEPHYR` guard. + +The typical styling convention for includes (following existing +conventions in `platform/ec` and other C codebases we have) is: + +* Zephyr OS headers in pointy brackets, in alphabetical order. + +* One blank line + +* CrOS EC OS headers (either from `include/`, `zephyr/shim/include/`, + or the current directory), in quotes (not pointy brackets). + +### Adding files to Cmake + +Zephyr's build system (including shimmed code) uses CMake instead of +`Makefiles`, and your code will not be compiled for Zephyr unless you +list the files in `zephyr/CMakeLists.txt`. + +### Step-by-step guide to adding a Kconfig + +Follow these steps: + +1. Make sure you have read the above Configuration section + +2. Add your config to one of zephyr/Kconfig* files. Note the PLATFORM_EC_ prefix + and try to put it near related things: + + ```kconfig + config PLATFORM_EC_CHARGER_BQ25720 + bool "TI BQ25720 charger" + help + The TI BQ25720 is a blah blah (describe summary from datasheet, + at least 3 lines so take 10 minutes to write something truly useful) + ``` + + Consider a `depends on PLATFORM_EC_...` line if it depends on an existing + feature. + +3. Add to zephyr/shim/include/config_chip.h (put it at the bottom): + + ```kconfig + #undef CONFIG_CHARGER_BQ25720 + #ifdef CONFIG_PLATFORM_EC_CHARGER_BQ25720 + #define CONFIG_CHARGER_BQ25720 + #endif + ``` + +4. Add the source file to zephyr/CMakeLists.txt if it is not already there. For + ordering check the comments in that file: + + `zephyr_sources_ifdef(CONFIG_PLATFORM_EC_CHARGER_BQ25720 + "${PLATFORM_EC}/driver/charger/bq25720.c")` + +5. Run a build on a board that enables the new CONFIG (in config.h) to make sure + there are no problems. + +6. If it doesn't work, please email zephyr-task-force@ or file a bug and assign + it to sjg@, cc zephyr-task-force@ (please include CL link and the error + output). + +### Unit Tests + +Unit tests, implemented using the Ztest framework, can be found in +`zephyr/test`. + +To run all unit tests, you use `zmake testall`. + +## Alternatives Considered + +### Translate code and mirror into the zephyr-chrome repository + +We could potentially write a script which, via a series of find/replace +operations, translates a platform/ec module to use Zephyr functions, macros, and +paradigms. On a frequent basis, we would translate all modules of interest in +the platform/ec repository and land an "uprev" change in the zephyr-chrome +repository. + +The main disadvantage of this technique is that we can't get any CQ coverage +when platform/ec CLs land that the modules will continue to work in Zephyr. +Additionally, the translator script would be delicate and probably require +frequent maintenance. + +However, this technique does have some benefits. With modules directly +translated to code in the Zephyr paradigm, the process of upstreaming a shimmed +module to ZephyrOS would be significantly easier. Additionally, it would require +no shim code in platform/ec. + +### Don't do any code sharing + +One option is to avoid shimming in any platform/ec code and allow the Zephyr +team to re-implement features in upstream zephyr, or our local zephyr-chrome +repository. + +Disregarding the infeasible amount of work required to complete this option, the +platform/ec repository has a far faster development pace as there are many more +contributors, and the Zephyr features would quickly lose parity during the time +frame that we are launching both Zephyr-based and platform/ec-based devices. diff --git a/docs/zephyr/zephyr_template.md b/docs/zephyr/zephyr_template.md new file mode 100644 index 0000000000..f75883eec9 --- /dev/null +++ b/docs/zephyr/zephyr_template.md @@ -0,0 +1,56 @@ +# Zephyr EC Feature Configuration Template + +[TOC] + +## Overview + +*Description of the Zephyr EC feature and the capabilities provided* + +## Kconfig Options + +*List the Kconfig options that enable the feature and list any sub-configuration +options that control the behavior of the feature.* + +Kconfig Option | Default | Documentation +:------------------------------------- | :-----: | :------------ +`CONFIG_PLATFORM_EC_<option>` | y/n | [zephyr/Kconfig](../zephyr/Kconfig) + +Kconfig sub-option | Default | Documentation +:------------------------------------- | :-----: | :------------ +`CONFIG_PLATFORM_EC_<option>` | y/n | [zephyr/Kconfig](../zephyr/Kconfig) + + +*Note - Avoid documenting `CONFIG_` options in the markdown as the relevant +`Kconfig*` contains the authoritative definition. Link directly to the Kconfig +option in source like this: [I2C Passthru Restricted].* + +## Devicetree Nodes + +*Detail the devicetree nodes that configure the feature.* + +*Note - avoid documenting node properties here. Point to the relevant `.yaml` +file instead, which contains the authoritative definition.* + +## Board Specific Code + +*Document any board specific routines that a user must create to successfully +compile and run. For many features, this can section can be empty.* + +## Threads + +*Document any threads enabled by this feature.* + +## Testing and Debugging + +*Provide any tips for testing and debugging the EC feature.* + +## Example + +*Provide code snippets from a working board to walk the user through +all code that must be created to enable this feature.* + +<!-- +The following demonstrates linking to a code search result for a Kconfig option. +Reference this link in your text by matching the text in brackets exactly. +--> +[I2C Passthru Restricted]:https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/ec/zephyr/Kconfig?q=%22config%20PLATFORM_EC_I2C_PASSTHRU_RESTRICTED%22&ss=chromiumos diff --git a/docs/zephyr/ztest.md b/docs/zephyr/ztest.md new file mode 100644 index 0000000000..021b3391bd --- /dev/null +++ b/docs/zephyr/ztest.md @@ -0,0 +1,200 @@ +# Porting EC unit tests to Ztest + +[TOC] + +This HOWTO shows the process for porting the EC's `base32` unit test to Zephyr's +Ztest framework. All of the work is done in `src/platform/ec`. + +See +[Test Framework - Zephyr Project Documentation](https://docs.zephyrproject.org/1.12.0/subsystems/test/ztest.html#quick-start-unit-testing) +for details about Zephyr's Ztest framework. + +For examples of porting an EC unit test to the Ztest API, see: * +[base32](https://crrev.com/c/2492527) and +[improvements](https://crrev.com/c/2634401) * +[accel_cal](https://crrev.com/c/2645198) + +## Porting Considerations + +Not every EC unit test can be ported to Ztest. This section describes cases that +are not supported and cases where caveats apply. + +### EC Mocks Are Not Supported + +If a test has a `$TEST.mocklist` file associated with the unit test, it is using +the EC mocking framework, which is unsupported in the Ztest framework. Ztest has +its own mocking framework which the EC does not support. + +### Multiple Task Caveats + +The EC unit test framework starts a single task to call `run_test`, and this +task will then call the functions for the various test cases. Some unit tests +have multiple threads of execution, which is enabled by a `$TEST.tasklist` file +associated with the unit test. The test runner task has a task ID of +`TASK_ID_TEST_RUNNER`, which can be used as an argument to any of the task +functions. See for example the +[`charge_ramp` unit test](https://chromium.googlesource.com/chromiumos/platform/ec/+/HEAD/test/charge_ramp.c#81) +and the +[`host_command` unit test](https://chromium.googlesource.com/chromiumos/platform/ec/+/HEAD/test/host_command.c#32) + +When a unit test is ported to Ztest, `test_main` doesn't have a thread ID, so +`TASK_ID_TEST_RUNNER` is undefined. `charge_ramp` and `host_command` cannot be +ported at this time. `test_main` also cannot call any of the task functions that +must be called from a task, such as `task_wake`; these functions can pend the +calling task, but since `test_main` doesn't have a thread ID, the pend will +fail. See the +[`mutex` unit test](https://chromium.googlesource.com/chromiumos/platform/ec/+/HEAD/test/mutex.c#116) +for an example. + +## Determine source files being tested + +Determine which C files the unit test requires by finding the test in +`test/test_config.h`: + +``` +#ifdef TEST_BASE32 +#define CONFIG_BASE32 +#endif +``` + +Locate the `CONFIG` item(s) in `common/build.mk`: + +``` +common-$(CONFIG_BASE32)+=base32.o +``` + +So for the `base32` test, we only need to shim `common/base32.c`. + +Add the C files to `zephyr/shim/CMakeLists.txt`, in the "Shimmed modules" +section: + +``` +# Shimmed modules +zephyr_sources_ifdef(CONFIG_PLATFORM_EC "${PLATFORM_EC}/common/base32.c") +``` + +Refer to [zephyr: shim in base32.c](https://crrev.com/c/2468631). + +## Create test directory + +Create a new directory for the unit test in `zephyr/test/base32`. + +Create `zephyr/test/base32/prj.conf` with these contents: + +``` +CONFIG_ZTEST=y +CONFIG_PLATFORM_EC=y +``` + +Create `zephyr/test/base32/CMakeLists.txt` with these contents: + +``` +target_sources(app PRIVATE ${PLATFORM_EC}/test/base32.c) +``` + +## Modify test source code + +### Test cases + +In the unit test, replace `run_test` with `TEST_MAIN()`. This will allow both +platform/ec tests and Ztests to share the same entry point. + +Change `RUN_TEST` to `ztest_unit_test` and add the `ztest_test_suite` wrapper +plus the call to `ztest_run_test_suite`. + +```c +/* + * Define the test cases to run. We need to do this twice, once in the format + * that Ztest uses, and again in the format the the EC test framework uses. + * If you add a test to one of them, make sure to add it to the other. + */ +TEST_MAIN() +{ + ztest_test_suite(test_base32_lib, + ztest_unit_test(test_crc5), + ztest_unit_test(test_encode), + ztest_unit_test(test_decode)); + ztest_run_test_suite(test_base32_lib); +} +``` + +Each function that is called by `ztest_unit_test` needs to be declared using +`DECLARE_EC_TEST`. Keep the `return EC_SUCCESS;` at the end of the test +function. Note that for the EC build, `TEST_MAIN` will call `test_reset` before +running the test cases, and `test_print_result` after. + +### Assert macros + +Change the `TEST_ASSERT` macros to `zassert` macros. There are plans to automate +this process, but for now, it's a manual process involving some intelligent +find-and-replace. + +* `TEST_ASSERT(n)` to `zassert_true(n, NULL)` +* `TEST_EQ(a, b, fmt)` to `zassert_equal(a, b, fmt ## ", " ## fmt, a, b)` + * e.g. `TEST_EQ(a, b, "%d")` becomes `zassert_equal(a, b, "%d, %d", a, b)` +* `TEST_NE(a, b, fmt)` to `zassert_not_equal(a, b, fmt ## ", " ## fmt, a, b)` +* `TEST_LT(a, b, fmt)` to `zassert_true(a < b, fmt ## ", " ## fmt, a, b)` +* `TEST_LE(a, b, fmt)` to `zassert_true(a <= b, fmt ## ", " ## fmt, a, b)` +* `TEST_GT(a, b, fmt)` to `zassert_true(a > b, fmt ## ", " ## fmt, a, b)` +* `TEST_GE(a, b, fmt)` tp `zassert_true(a >= b, fmt ## ", " ## fmt, a, b)` +* `TEST_BITS_SET(a, bits)` to `zassert_true(a & (int)bits == (int)bits, "%u, + %u", a & (int)bits, (int)bits)` +* `TEST_BITS_CLEARED(a, bits)` to `zassert_true(a & (int)bits == 0, "%u, 0", a + & (int)bits)` +* `TEST_ASSERT_ARRAY_EQ(s, d, n)` to `zassert_mem_equal(s, d, b, NULL)` +* `TEST_CHECK(n)` to `zassert_true(n, NULL)` +* `TEST_NEAR(a, b, epsilon, fmt)` to `zassert_within(a, b, epsilon, fmt, a)` + * Currently, every usage of `TEST_NEAR` involves floating point values +* `TEST_ASSERT_ABS_LESS(n, t)` to `zassert_true(abs(n) < t, "%d, %d", n, t)` + * Currently, every usage of `TEST_ASSERT_ANS_LESS` involves signed + integers. + +There isn't a good replacement for `TEST_ASSERT_MEMSET(d, c, n)`, but it is only +used in two tests, `printf.c` and `utils.c`. If you need this test, you'll need +to code up a loop over the `n` bytes starting at `d`, and `zassert_equal` that +each byte is equal to `c`. + +Also note that some tests use constructs like `TEST_ASSERT(var == const)`, which +would have been better write as `TEST_EQ(var, const)`. These should be rewritten +to use `zassert_equal`. + +Refer to +[test: Allow EC unit test to use Ztest API](https://crrev.com/c/2492527) for the +changes to the base32.c source code. + +### Tasklist + +For any test that has a corresponding `${TESTNAME}.tasklist`, add the file +`shimmed_test_tasks.h` in the zephyr test directory, and in that file, +`#include` the tasklist file. See [accel_cal](https://crrev.com/c/2645198) for +an example. + +Add `CONFIG_HAS_TEST_TASKS=y` to the `prj.conf` file, as well as the appropriate +`CONFIG_PLATFORM_EC` defines to include or exclude code that the unit under test +uses. + +## Build and run + +Use `zmake` to build and run the test: + +``` +(cr) $ zmake -l DEBUG configure --test -B build/ztest/base32 zephyr/test/base32 +... +UART_0 connected to pseudotty: /dev/pts/1 +*** Booting Zephyr OS build zephyr-v2.4.0-1-g63b2330a85cd *** +Running test suite test_base32_lib +=================================================================== +START - test_crc5 + PASS - test_crc5 +=================================================================== +START - test_encode + PASS - test_encode +=================================================================== +START - test_decode + PASS - test_decode +=================================================================== +Test suite test_base32_lib succeeded +=================================================================== +PROJECT EXECUTION SUCCESSFUL +(cr) $ +``` |