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