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