1# Add a New System to OpenBMC
2
3**Document Purpose:** How to add a new system to the OpenBMC distribution
4
5**Audience:** Programmer familiar with OpenBMC
6
7**Prerequisites:** Completed Development Environment Setup [Document][32]
8
9## Overview
10
11This document will describe the following:
12
13* Review background about Yocto and BitBake
14* Creating a new system layer
15* Populating this new layer
16* Building the new system and testing in QEMU
17* Adding configs for sensors, LEDs, inventories, etc.
18
19## Background
20
21The OpenBMC distribution is based on [Yocto](https://www.yoctoproject.org/).
22Yocto is a project that allows developers to create custom Linux distributions.
23OpenBMC uses Yocto to create their embedded Linux distribution to run on
24a variety of devices.
25
26Yocto has a concept of hierarchical layers. When you build a Yocto-based
27distribution, you define a set of layers for that distribution. OpenBMC uses
28many common layers from Yocto as well as some of its own layers. The layers
29defined within OpenBMC can be found with the meta-* directories in OpenBMC
30[GitHub](https://github.com/openbmc/openbmc).
31
32Yocto layers are a combination of different files that define packages to
33incorporate in that layer. One of the key file types used in these layers is
34[BitBake](https://github.com/openembedded/bitbake/blob/master/README) recipes.
35
36BitBake is a fully functional language in itself. For this lesson, we will
37focus on only the aspects of BitBake required to understand the process of
38adding a new system.
39
40## Start the Initial BitBake
41
42For this work, you will need to have allocated at least 100GB of space to your
43development environment and as much memory and CPU as possible. The initial
44build of an OpenBMC distribution can take hours. Once that first build is done
45though, future builds will use cached data from the first build, speeding the
46process up by orders of magnitude.
47
48So before we do anything else, let's get that first build going.
49
50Follow the direction on the OpenBMC GitHub [page](https://github.com/openbmc/openbmc/blob/master/README.md#2-download-the-source)
51for the Romulus system (steps 2-4).
52
53## Create a New System
54
55While the BitBake operation is going above, let's start creating our new system.
56Similar to previous lessons, we'll be using Romulus as our reference. Our new
57system will be called romulus-prime.
58
59From your openbmc repository you cloned above, the Romulus layer is defined
60within `meta-ibm/meta-romulus/`.  The Romulus layer is defined within the
61`conf` subdirectory. Under `conf` you will see a layout like this:
62
63```
64meta-ibm/meta-romulus/conf/
65├── bblayers.conf.sample
66├── conf-notes.txt
67├── layer.conf
68├── local.conf.sample
69└── machine
70    └── romulus.conf
71```
72
73To create our new romulus-prime system we are going to start out by copying
74our romulus layer.
75```
76cp -R meta-ibm/meta-romulus meta-ibm/meta-romulus-prime
77```
78
79Let's review and modify each file needed in our new layer
80
811. meta-ibm/meta-romulus-prime/conf/bblayers.conf.sample
82
83   This file defines the layers to pull into the meta-romulus-prime
84   distribution. You can see in it a variety of Yocto layers (meta, meta-poky,
85   meta-openembedded/meta-oe, ...). It also has OpenBMC layers like
86   meta-phosphor, meta-openpower, meta-ibm, and meta-ibm/meta-romulus.
87
88   The only change you need in this file is to change the two instances of
89   meta-romulus to meta-romulus-prime. This will ensure your new layer is used
90   when building your new system.
91
922. meta-ibm/meta-romulus-prime/conf/conf-notes.txt
93
94   This file simply states the default target the user will build when working
95   with your new layer. This remains the same as it is common for all OpenBMC
96   systems.
97
983. meta-ibm/meta-romulus-prime/conf/layer.conf
99
100   The main purpose of this file is to tell BitBake where to look for recipes
101   (\*.bb files). Recipe files end with a `.bb` extension and are what contain
102   all of the packaging logic for the different layers. `.bbappend` files are
103   also recipe files but provide a way to append onto `.bb` files.
104   `.bbappend` files are commonly used to add or remove something from a
105   corresponding `.bb` file in a different layer.
106
107   The only change you need in here is to find/replace the "romulus-layer" to
108   "romulus-prime-layer"
109
1104. meta-ibm/meta-romulus-prime/conf/local.conf.sample
111
112   This file is where all local configuration settings go for your layer. The
113   documentation in it is well done and it's worth a read.
114
115   The only change required in here is to change the `MACHINE` to
116   `romulus-prime`.
117
1185. meta-ibm/meta-romulus-prime/conf/machine/romulus.conf
119
120   This file describes the specifics for your machine. You define the kernel
121   device tree to use, any overrides to specific features you will be pulling
122   in, and other system specific pointers. This file is a good reference for
123   the different things you need to change when creating a new system (kernel
124   device tree, MRW, LED settings, inventory access, ...)
125
126   The first thing you need to do is rename the file to `romulus-prime.conf`.
127
128   **Note** If our new system really was just a variant of Romulus,
129   with the same hardware configuration, then we could have just created a
130   new machine in the Romulus layer. Any customizations for that system
131   could be included in the corresponding .conf file for that new machine. For
132   the purposes of this exercise we are assuming our romulus-prime system has
133   at least a few hardware changes requiring us to create this new layer.
134
135## Build New System
136
137This will not initially compile but it's good to verify a few things from the
138initial setup are done correctly.
139
140Do not start this step until the build we started at the beginning of this
141lesson has completed.
142
1431. Modify the conf for your current build
144
145   Within the shell you did the initial "bitbake" operation you need to reset
146   the conf file for your build. You can manually copy in the new files or just
147   remove it and let BitBake do it for you:
148   ```
149   cd ..
150   rm -r ./build/conf
151   export TEMPLATECONF=meta-ibm/meta-romulus-prime/conf
152   . openbmc-env
153   ```
154
155   Run your "bitbake" command.
156
1572. Nothing RPROVIDES 'romulus-prime-config'
158
159   This will be your first error after running "bitbake obmc-phosphor-image"
160   against your new system.
161
162   The openbmc/skeleton repository was used for initial prototyping of OpenBMC.
163   Within this repository is a [configs](https://github.com/openbmc/skeleton/tree/master/configs) directory.
164
165   The majority of this config data is no longer used but until it is all
166   completely removed, you need to provide it.
167
168   Since this repository and file are on there way out, we'll simply do a quick
169   workaround for this issue.
170
171   Create a config files as follows:
172   ```
173   cp meta-ibm/meta-romulus-prime/recipes-phosphor/workbook/romulus-config.bb meta-ibm/meta-romulus-prime/recipes-phosphor/workbook/romulus-prime-config.bb
174
175   vi meta-ibm/meta-romulus-prime/recipes-phosphor/workbook/romulus-prime-config.bb
176
177   SUMMARY = "Romulus board wiring"
178   DESCRIPTION = "Board wiring information for the Romulus OpenPOWER system."
179   PR = "r1"
180
181   inherit config-in-skeleton
182
183   #Use Romulus config
184   do_make_setup() {
185           cp ${S}/Romulus.py \
186                   ${S}/obmc_system_config.py
187           cat <<EOF > ${S}/setup.py
188   from distutils.core import setup
189
190   setup(name='${BPN}',
191       version='${PR}',
192       py_modules=['obmc_system_config'],
193       )
194   EOF
195   }
196
197   ```
198
199   Re-run your "bitbake" command.
200
2013. Fetcher failure for URL: file://romulus.cfg
202
203   This is the config file required by the kernel. It's where you can put some
204   additional kernel config parameters. For our purposes here, just modify
205   romulus-prime to use the romulus.cfg file. We just need to add the `-prime`
206   to the prepend path.
207   ```
208   vi ./meta-ibm/meta-romulus-prime/recipes-kernel/linux/linux-aspeed_%.bbappend
209
210   FILESEXTRAPATHS_prepend_romulus-prime := "${THISDIR}/${PN}:"
211   SRC_URI += "file://romulus.cfg"
212   ```
213
214   Re-run your "bitbake" command.
215
2164. No rule to make target arch/arm/boot/dts/aspeed-bmc-opp-romulus-prime.dtb
217
218   The .dtb file is a device tree blob file. It is generated during the Linux
219   kernel build based on its corresponding .dts file. When you introduce a
220   new OpenBMC system, you need to send these kernel updates upstream. The
221   linked email [thread](https://lists.ozlabs.org/pipermail/openbmc/2018-September/013260.html)
222   is an example of this process. Upstreaming to the kernel is a lesson in
223   itself. For this lesson, we will simply use the Romulus kernel config files.
224   ```
225   vi ./meta-ibm/meta-romulus-prime/conf/machine/romulus-prime.conf
226   # Replace the ${MACHINE} variable in the KERNEL_DEVICETREE
227
228   # Use romulus device tree
229   KERNEL_DEVICETREE = "${KMACHINE}-bmc-opp-romulus.dtb"
230   ```
231
232   Re-run your "bitbake" command.
233
234## Boot New System
235
236And you've finally built your new system's image! There are more
237customizations to be done but let's first verify what you have boots.
238
239Your new image will be in the following location from where you ran your
240"bitbake" command:
241```
242./tmp/deploy/images/romulus-prime/obmc-phosphor-image-romulus-prime.static.mtd
243```
244Copy this image to where you've set up your QEMU session and re-run the
245command to start QEMU (`qemu-system-arm` command from
246[dev-environment.md][32]), giving your new file as input.
247
248Once booted, you should see the following for the login:
249```
250romulus-prime login:
251```
252
253There you go! You've done the basics of creating, booting, and building a new
254system. This is by no means a complete system but you now have the base for
255the customizations you'll need to do for your new system.
256
257## Further Customizations
258
259There are a lot of other areas to customize when creating a new system.
260
261### Kernel changes
262
263This section describes how you can make changes to the kernel to port OpenBMC
264to a new machine.
265The device tree is in https://github.com/openbmc/linux/tree/dev-4.13/arch/arm/boot/dts.
266For examples, see [aspeed-bmc-opp-romulus.dts][1] or a similar machine.
267Complete the following steps to make kernel changes:
268
2691. Add the new machine device tree:
270   * Describe the GPIOs, e.g. LED, FSI, gpio-keys, etc. You should get such
271     info from schematic.
272   * Describe the i2c buses and devices, which usually include various hwmon
273     sensors.
274   * Describe the other devices, e.g. uarts, mac.
275   * Usually the flash layout does not need to change. Just include
276     `openbmc-flash-layout.dtsi`.
2772. Modify Makefile to build the device tree.
2783. Reference to [openbmc kernel doc][31] on submitting patches to mailing list.
279
280Note:
281* In `dev-4.10`, there is common and machine-specific initialization code in
282  `arch/arm/mach-aspeed/aspeed.c` which is used to do common initializations
283  and perform specific settings in each machine.
284  Starting in branch `dev-4.13`, there is no such initialization code. Most of
285  the inits are done with the upstream clock and reset driver.
286* If the machine needs specific settings (e.g. uart routing), please
287  send mail to [the mailing list][2] for discussion.
288
289
290### Workbook
291
292In legacy OpenBMC, there is a "workbook" to describe the machine's services,
293sensors, FRUs, etc.
294This workbook is a python configuration file and it is used by other services
295in [skeleton][3].
296In the latest OpenBMC, the skeleton services are mostly replaced by
297phosphor-xxx services and thus skeleton is deprecated.
298But the workbook is still needed for now to make the build.
299
300[meta-quanta][4] is an example that defines its own config in OpenBMC tree, so
301that it does not rely on skeleton repo, although it is kind of dummy.
302
303Before [e0e69be][26], or before v2.4 tag, OpenPOWER machines use several
304configurations related to GPIO. For example, in [Romulus.py][5], the
305configuration details are as follows:
306
307```python
308GPIO_CONFIG['BMC_POWER_UP'] = \
309        {'gpio_pin': 'D1', 'direction': 'out'}
310GPIO_CONFIG['SYS_PWROK_BUFF'] = \
311        {'gpio_pin': 'D2', 'direction': 'in'}
312
313GPIO_CONFIGS = {
314    'power_config' : {
315        'power_good_in' : 'SYS_PWROK_BUFF',
316        'power_up_outs' : [
317            ('BMC_POWER_UP', True),
318        ],
319        'reset_outs' : [
320        ],
321    },
322}
323```
324The PowerUp and PowerOK GPIOs are needed for the build to power on the chassis
325and check the power state.
326
327After that, the GPIO related configs are removed from the workbook, and
328replaced by `gpio_defs.json`, e.g. [2a80da2][27] introduces the GPIO json
329config for Romulus.
330
331```json
332{
333    "gpio_configs": {
334         "power_config": {
335            "power_good_in": "SYS_PWROK_BUFF",
336            "power_up_outs": [
337                { "name": "SOFTWARE_PGOOD", "polarity": true},
338                { "name": "BMC_POWER_UP", "polarity": true}
339            ],
340            "reset_outs": [
341            ]
342        }
343    },
344
345     "gpio_definitions": [
346        {
347            "name": "SOFTWARE_PGOOD",
348            "pin": "R1",
349            "direction": "out"
350        },
351        {
352            "name": "BMC_POWER_UP",
353            "pin": "D1",
354            "direction": "out"
355        },
356    ...
357}
358```
359
360Each machine shall define the similar json config to describe the GPIO
361configurations.
362
363
364### Hwmon Sensors
365
366Hwmon sensors include sensors on board (e.g. temperature sensors, fans) and
367OCC sensors.
368The config files path and name shall match the devices in device tree.
369
370There is detailed document in openbmc [doc/sensor-architecture][6].
371
372Here let's take Romulus as an example.
373The config files are in [meta-romulus/recipes-phosphor/sensors][7] which
374includes sensors on board and sensors of OCC, where on board sensors are via
375i2c and occ sensors are via FSI.
376
377* [w83773g@4c.conf][8] defines the `w83773` temperature sensor containing 3
378temperatures:
379   ```
380   LABEL_temp1 = "outlet"
381   ...
382   LABEL_temp2 = "inlet_cpu"
383   ...
384   LABEL_temp3 = "inlet_io"
385   ```
386   This device is defined in its device tree as [w83773g@4c][9].
387   When BMC starts, the udev rule will start `phosphor-hwmon` and it will create
388   temperature sensors on below DBus objects based on its sysfs attributes.
389   ```
390   /xyz/openbmc_project/sensors/temperature/outlet
391   /xyz/openbmc_project/sensors/temperature/inlet_cpu
392   /xyz/openbmc_project/sensors/temperature/inlet_io
393   ```
394* [pwm-tacho-controller@1e786000.conf][10] defines the fans and the config is
395   similar as above, the difference is that it creates `fan_tach` sensors.
396* [occ-hwmon.1.conf][11] defines the occ hwmon sensor for master CPU.
397   This config is a bit different, that it shall tell `phosphor-hwmon` to read
398   the label instead of directly getting the index of the sensor, because CPU
399   cores and DIMMs could be dynamic, e.g. CPU cores could be disabled, DIMMs
400   could be pulled out.
401   ```
402   MODE_temp1 = "label"
403   MODE_temp2 = "label"
404   ...
405   MODE_temp31 = "label"
406   MODE_temp32 = "label"
407   LABEL_temp91 = "p0_core0_temp"
408   LABEL_temp92 = "p0_core1_temp"
409   ...
410   LABEL_temp33 = "dimm6_temp"
411   LABEL_temp34 = "dimm7_temp"
412   LABEL_power2 = "p0_power"
413   ...
414   ```
415   * The `MODE_temp* = "label"` tells that if it sees `tempX`, it shall read
416      the label which is the sensor id.
417   * And `LABEL_temp* = "xxx"` tells the sensor name for the corresponding
418      sensor id.
419   * For example, if `temp1_input` is 37000 and `temp1_label` is 91 in sysfs,
420      `phosphor-hwmon` knows `temp1_input` is for sensor id 91, which is
421      `p0_core0_temp`, so it creates
422      `/xyz/openbmc_project/sensors/temperature/p0_core0_temp` with sensor
423      value 37000.
424   * For Romulus, the power sensors do not need to read label since all powers
425      are available on a system.
426   * For Witherspoon, the power sensors are similar to temperature sensors,
427      that it shall tell hwmon to read the `function_id` instead of directly
428      getting the index of the sensor.
429
430
431### LEDs
432
433Several parts are involved for LED.
434
4351. In kernel dts, LEDs shall be described, e.g. [romulus dts][12] describes
436   3 LEDs, `fault`, `identify` and `power`.
437   ```
438     leds {
439       compatible = "gpio-leds";
440
441       fault {
442         gpios = <&gpio ASPEED_GPIO(N, 2) GPIO_ACTIVE_LOW>;
443       };
444
445       identify {
446         gpios = <&gpio ASPEED_GPIO(N, 4) GPIO_ACTIVE_HIGH>;
447       };
448
449       power {
450         gpios = <&gpio ASPEED_GPIO(R, 5) GPIO_ACTIVE_LOW>;
451       };
452     };
453   ```
4542. In machine layer, LEDs shall be configured via yaml to describe how it
455   functions, e.g. [Romulus led yaml][28]:
456   ```
457   bmc_booted:
458       power:
459           Action: 'Blink'
460           DutyOn: 50
461           Period: 1000
462           Priority: 'On'
463   power_on:
464       power:
465           Action: 'On'
466           DutyOn: 50
467           Period: 0
468           Priority: 'On'
469   ...
470   ```
471   It tells the LED manager to set the `power` LED to blink when BMC is ready
472   and booted, and set it on when host is powered on.
4733. At runtime, LED manager automatically set LEDs on/off/blink based on the
474   above yaml config.
4754. LED can be accessed manually via /xyz/openbmc_project/led/, e.g.
476   * Get identify LED state:
477      ```
478      curl -b cjar -k https://$bmc/xyz/openbmc_project/led/physical/identify
479      ```
480   * Set identify LED to blink:
481      ```
482      curl -b cjar -k -X PUT -H "Content-Type: application/json" -d '{"data": "xyz.openbmc_project.Led.Physical.Action.Blink" }' https://$bmc/xyz/openbmc_project/led/physical/identify/attr/State
483      ```
4845. When an error related to a FRU occurs, an event log is created in logging
485   with a CALLOUT path. [phosphor-fru-fault-monitor][29] monitors the logs:
486   * Assert the related fault LED group when a log with the CALLOUT path is
487      generated;
488   * De-assert the related fault LED group when the log is marked as
489      "Resolved" or deleted.
490
491**Note**: This yaml config can be automatically generated by
492[phosphor-mrw-tools][13] from its MRW, see [Witherspoon example][14].
493
494
495### Inventories and other sensors
496
497Inventories, other sensors (e.g. CPU/DIMM temperature), and FRUs are defined
498in ipmi's yaml config files.
499
500E.g. [meta-romulus/recipes-phosphor/ipmi][15]
501* `romulus-ipmi-inventory-map` defines regular inventories, e.g. CPU, memory,
502   motherboard.
503* `phosphor-ipmi-fru-properties` defines extra properties of the inventories.
504* `phosphor-ipmi-sensor-inventory` defines the sensors from IPMI.
505* `romulus-ipmi-inventory-sel` defines inventories used for IPMI SEL.
506
507For inventory map and fru-properties, they are similar between different
508systems, you can refer to this example and make one for your system.
509
510For ipmi-sensor-inventory, the sensors from IPMI are different between
511systems, so you need to define your own sensors, e.g.
512```
5130x08:
514  sensorType: 0x07
515  path: /org/open_power/control/occ0
516  ...
5170x1e:
518  sensorType: 0x0C
519  path: /system/chassis/motherboard/dimm0
520  ...
5210x22:
522  sensorType: 0x07
523  path: /system/chassis/motherboard/cpu0/core0
524```
525The first value `0x08`, `0x1e` and `0x22` are the sensor id of IPMI, which is
526defined in MRW.
527You should follow the system's MRW to define the above config.
528
529**Note**: The yaml configs can be automatically generated by
530[phosphor-mrw-tools][13] from its MRW, see [Witherspoon example][14].
531
532
533### Fans
534[phosphor-fan-presence][16] manages all the services about fan:
535* `phosphor-fan-presence` checks if a fan is present, creates the fan DBus
536   objects in inventory and update the `Present` property.
537* `phosphor-fan-monitor` checks if a fan is functional, and update the
538   `Functional` property of the fan Dbus object.
539* `phosphor-fan-control` controls the fan speed by setting the fan speed target
540   based on conditions, e.g. temperatures.
541* `phosphor-cooling-type` checks and sets if the system is air-cooled or
542   water-cooled by setting properties of
543   `/xyz/openbmc_project/inventory/system/chassis` object.
544
545All the above services are configurable, e.g. by yaml config.
546So the machine specific configs shall be written when porting OpenBMC to a new
547machine.
548
549Taking Romulus as an example, it is air-cooled and has 3 fans without GPIO
550presence detection.
551
552#### Fan presence
553Romulus has no GPIO detection for fans, so it checks fan tach sensor:
554```
555- name: fan0
556  path: /system/chassis/motherboard/fan0
557  methods:
558    - type: tach
559      sensors:
560        - fan0
561```
562The yaml config tells that
563* It shall create `/system/chassis/motherboard/fan0` object in inventory.
564* It shall check fan0 tach sensor (`/sensors/fan_tach/fan0`) to set `Present`
565   property on the fan0 object.
566
567#### Fan monitor
568Romulus fans use pwm to control the fan speed, where pwm ranges from 0 to 255,
569and the fan speed ranges from 0 to about 7000.
570So it needs a factor and offset to mapping the pwm to fan speed:
571```
572  - inventory: /system/chassis/motherboard/fan0
573    allowed_out_of_range_time: 30
574    deviation: 15
575    num_sensors_nonfunc_for_fan_nonfunc: 1
576    sensors:
577      - name: fan0
578        has_target: true
579        target_interface: xyz.openbmc_project.Control.FanPwm
580        factor: 21
581        offset: 1600
582```
583The yaml config tells that:
5841. It shall use `FanPwm` as target interface of the tach sensor.
5852. It shall calculate the expected fan speed as `target * 21 + 1600`.
5863. The deviation is `15%`, so if the fan speed is out of the expected range
587   for more than 30 seconds, fan0 shall be set as non-functional.
588
589#### Fan control
590The fan control service requires 4 yaml configuration files:
591* `zone-condition` defines the cooling zone conditions. Romulus is always
592   air-cooled, so this config is as simple as defining an `air_cooled_chassis`
593   condition based on the cooling type property.
594   ```
595  - name: air_cooled_chassis
596    type: getProperty
597    properties:
598      - property: WaterCooled
599        interface: xyz.openbmc_project.Inventory.Decorator.CoolingType
600        path: /xyz/openbmc_project/inventory/system/chassis
601        type: bool
602        value: false
603   ```
604* `zone-config` defines the cooling zones. Romulus has only one zone:
605   ```
606  zones:
607    - zone: 0
608      full_speed: 255
609      default_floor: 195
610      increase_delay: 5
611      decrease_interval: 30
612   ```
613   It defines that the zone full speed and default floor speed for the fans,
614   so the fan pwm will be set to 255 if it is in full speed, and set to 195 if
615   fans are in default floor speed.
616* `fan-config` defines which fans are controlled in which zone and which target
617   interface shall be used, e.g. below yaml config defines fan0 shall be
618   controlled in zone0 and it shall use `FanPwm` interface.
619   ```
620  - inventory: /system/chassis/motherboard/fan0
621    cooling_zone: 0
622    sensors:
623      - fan0
624    target_interface: xyz.openbmc_project.Control.FanPwm
625    ...
626   ```
627* `events-config` defines the various events and its handlers, e.g. which fan
628   targets shall be set in which temperature.
629   This config is a bit complicated, the [exmaple event yaml][17] provides
630   documents and examples.
631   Romulus example:
632   ```
633    - name: set_air_cooled_speed_boundaries_based_on_ambient
634      groups:
635          - name: zone0_ambient
636            interface: xyz.openbmc_project.Sensor.Value
637            property:
638                name: Value
639                type: int64_t
640      matches:
641          - name: propertiesChanged
642      actions:
643          - name: set_floor_from_average_sensor_value
644            map:
645                value:
646                    - 27000: 85
647                    - 32000: 112
648                    - 37000: 126
649                    - 40000: 141
650                type: std::map<int64_t, uint64_t>
651          - name: set_ceiling_from_average_sensor_value
652            map:
653                value:
654                    - 25000: 175
655                    - 27000: 255
656                type: std::map<int64_t, uint64_t>
657   ```
658   The above yaml config defines the fan floor and ceiling speed in
659   `zone0_ambient`'s different temperatures. E.g.
660   1. When the temperature is lower than 27 degreesC, the floor speed (pwm)
661      shall be set to 85.
662   2. When the temperature is between 27 and 32 degrees C, the floor speed
663      (pwm) shall be set to 112, etc.
664
665With above configs, phosphor-fan will run the fan presence/monitor/control
666logic as configured specifically for the machine.
667
668**Note**: Romulus fans are simple. For a more complicated example, refer to
669[Witherspoon fan configurations][18]. The following are the additional
670functions of Witherspoon fan configuration:
671
672* It checks GPIO for fan presence.
673* It checks GPIO to determine if the system is air or water cooled.
674* It has more sensors and more events in fan control.
675
676
677### GPIOs
678This section mainly focuses on the GPIOs in device tree that shall be
679monitored.
680E.g.:
681* A GPIO may represent a signal of host checkstop.
682* A GPIO may represent a button press.
683* A GPIO may represent if a device is attached or not.
684
685They are categorized as `phosphor-gpio-presence` for checking presences of a
686device, and `phosphor-gpio-monitor` for monitoring a GPIO.
687
688#### GPIOs in device tree
689All the GPIOs to be monitored shall be described in the device tree.
690E.g.
691```
692  gpio-keys {
693    compatible = "gpio-keys";
694    checkstop {
695      label = "checkstop";
696      gpios = <&gpio ASPEED_GPIO(J, 2) GPIO_ACTIVE_LOW>;
697      linux,code = <ASPEED_GPIO(J, 2)>;
698    };
699    id-button {
700      label = "id-button";
701      gpios = <&gpio ASPEED_GPIO(Q, 7) GPIO_ACTIVE_LOW>;
702      linux,code = <ASPEED_GPIO(Q, 7)>;
703    };
704  };
705```
706The following code describes two GPIO keys, one for `checkstop` and the other
707for `id-button`, where the key code is calculated from [aspeed-gpio.h][24]:
708```
709#define ASPEED_GPIO_PORT_A 0
710#define ASPEED_GPIO_PORT_B 1
711...
712#define ASPEED_GPIO_PORT_Y 24
713#define ASPEED_GPIO_PORT_Z 25
714#define ASPEED_GPIO_PORT_AA 26
715...
716
717#define ASPEED_GPIO(port, offset) \
718  ((ASPEED_GPIO_PORT_##port * 8) + offset)
719```
720
721#### GPIO Presence
722Witherspoon and Zaius have examples for gpio presence.
723
724* [Witherspoon][19]:
725   ```
726   INVENTORY=/system/chassis/motherboard/powersupply0
727   DEVPATH=/dev/input/by-path/platform-gpio-keys-event
728   KEY=104
729   NAME=powersupply0
730   DRIVERS=/sys/bus/i2c/drivers/ibm-cffps,3-0069
731   ```
732   It checks GPIO key 104 for `powersupply0`'s presence, creates the inventory
733   object and bind or unbind the driver.
734* [Zaius][20]:
735   ```
736   INVENTORY=/system/chassis/pcie_card_e2b
737   DEVPATH=/dev/input/by-path/platform-gpio-keys-event
738   KEY=39
739   NAME=pcie_card_e2b
740   ```
741   It checks GPIO key 39 for `pcie_card_e2b`'s presence, and creates the
742   inventory object.
743
744#### GPIO monitor
745Typical usage of GPIO monitor is to monitor the checkstop event from the host,
746or button presses.
747
748* [checkstop monitor][21] is a common service for OpenPOWER machines.
749   ```
750   DEVPATH=/dev/input/by-path/platform-gpio-keys-event
751   KEY=74
752   POLARITY=1
753   TARGET=obmc-host-crash@0.target
754   ```
755   By default it monitors GPIO key 74, and if it is triggered, it tells
756   systemd to start `obmc-host-crash@0.target`.
757   For systems using a different GPIO pin for checkstop, it simply overrides
758   the default one by specifying its own config file in meta-machine layer.
759   E.g. [Zaius's checkstop config][22].
760   **Note**: when the key is pressed, `phosphor-gpio-monitor` starts the target
761   unit and exits.
762* [id-button monitor][23] is an example service on Romulus to monitor ID
763   button press.
764   ```
765   DEVPATH=/dev/input/by-path/platform-gpio-keys-event
766   KEY=135
767   POLARITY=1
768   TARGET=id-button-pressed.service
769   EXTRA_ARGS=--continue
770   ```
771   It monitors GPIO key 135 for the button press and starts
772   `id-button-pressed.service`, that handles the event by setting the identify
773   LED group's `Assert` property.
774   **Note**: It has an extra argument, `--continue`, that tells
775   `phosphor-gpio-monitor` to not exit and continue running when the key is
776   pressed.
777
778[1]: https://github.com/openbmc/linux/blob/dev-4.13/arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts
779[2]: https://lists.ozlabs.org/listinfo/openbmc
780[3]: https://github.com/openbmc/skeleton
781[4]: https://github.com/openbmc/openbmc/tree/master/meta-quanta/meta-q71l/recipes-phosphor/workbook
782[5]: https://github.com/openbmc/skeleton/blob/master/configs/Romulus.py
783[6]: https://github.com/openbmc/docs/blob/master/sensor-architecture.md
784[7]: https://github.com/openbmc/openbmc/tree/master/meta-ibm/meta-romulus/recipes-phosphor/sensors
785[8]: https://github.com/openbmc/openbmc/blob/298c4328fd20fcd7645da1565c143b1b668ef541/meta-ibm/meta-romulus/recipes-phosphor/sensors/phosphor-hwmon/obmc/hwmon/ahb/apb/i2c%401e78a000/i2c-bus%40440/w83773g%404c.conf
786[9]: https://github.com/openbmc/linux/blob/aca92be80c008bceeb6fb62fd1d450b5be5d0a4f/arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts#L208
787[10]: https://github.com/openbmc/openbmc/blob/298c4328fd20fcd7645da1565c143b1b668ef541/meta-ibm/meta-romulus/recipes-phosphor/sensors/phosphor-hwmon/obmc/hwmon/ahb/apb/pwm-tacho-controller%401e786000.conf
788[11]: https://github.com/openbmc/openbmc/blob/298c4328fd20fcd7645da1565c143b1b668ef541/meta-ibm/meta-romulus/recipes-phosphor/sensors/phosphor-hwmon/obmc/hwmon/devices/platform/gpio-fsi/fsi0/slave%4000--00/00--00--00--06/sbefifo1-dev0/occ-hwmon.1.conf
789[12]: https://github.com/openbmc/linux/blob/aca92be80c008bceeb6fb62fd1d450b5be5d0a4f/arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts#L42
790[13]: https://github.com/openbmc/phosphor-mrw-tools
791[14]: https://github.com/openbmc/openbmc/blob/764b88f4056cc98082e233216704e94613499e64/meta-ibm/meta-witherspoon/conf/distro/openbmc-witherspoon.conf#L4
792[15]: https://github.com/openbmc/openbmc/tree/master/meta-ibm/meta-romulus/recipes-phosphor/ipmi
793[16]: https://github.com/openbmc/phosphor-fan-presence
794[17]: https://github.com/openbmc/phosphor-fan-presence/blob/master/control/example/events.yaml
795[18]: https://github.com/openbmc/openbmc/tree/master/meta-ibm/meta-witherspoon/recipes-phosphor/fans
796[19]: https://github.com/openbmc/openbmc/blob/master/meta-ibm/meta-witherspoon/recipes-phosphor/gpio/phosphor-gpio-monitor/obmc/gpio/phosphor-power-supply-0.conf
797[20]: https://github.com/openbmc/openbmc/blob/master/meta-ingrasys/meta-zaius/recipes-phosphor/gpio/phosphor-gpio-monitor/obmc/gpio/phosphor-pcie-card-e2b.conf
798[21]: https://github.com/openbmc/openbmc/blob/master/meta-openpower/recipes-phosphor/host/checkstop-monitor.bb
799[22]: https://github.com/openbmc/openbmc/blob/master/meta-ingrasys/meta-zaius/recipes-phosphor/host/checkstop-monitor/obmc/gpio/checkstop
800[23]: https://github.com/openbmc/openbmc/tree/master/meta-ibm/meta-romulus/recipes-phosphor/gpio
801[24]: https://github.com/openbmc/linux/blob/dev-4.13/include/dt-bindings/gpio/aspeed-gpio.h
802[25]: https://github.com/openbmc/docs/blob/master/development/add-new-system.md
803[26]: https://github.com/openbmc/openbmc/commit/e0e69beab7c268e4ad98972016c78b0d7d5769ac
804[27]: https://github.com/openbmc/openbmc/commit/2a80da2262bf13aa1ddb589cf3f2b672d26b0975
805[28]: https://github.com/openbmc/openbmc/blob/3cce45a96f0416b4c3d8f2b698cb830662a29227/meta-ibm/meta-romulus/recipes-phosphor/leds/romulus-led-manager-config/led.yaml
806[29]: https://github.com/openbmc/phosphor-led-manager/tree/master/fault-monitor
807[30]: https://github.com/openbmc/docs/blob/master/development/dev-environment.md
808[31]: https://github.com/openbmc/docs/blob/master/kernel-development.md
809[32]: https://github.com/openbmc/docs/blob/master/development/dev-environment.md
810