xref: /openbmc/docs/development/add-new-system.md (revision 309abc9187735439077138246f0e657aad902789)
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```bash
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```bash
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   ```bash
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   ```bash
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   ```bash
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   ```bash
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```bash
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```text
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
281<https://github.com/openbmc/linux/tree/dev-4.13/arch/arm/boot/dts>. For
282examples, see [aspeed-bmc-opp-romulus.dts][1] or a similar machine. Complete the
283following steps 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```bash
392  LABEL_temp1 = "outlet"
393  ...
394  LABEL_temp2 = "inlet_cpu"
395  ...
396  LABEL_temp3 = "inlet_io"
397```
398
399This device is defined in its device tree as [w83773g@4c][9]. When BMC starts,
400the udev rule will start `phosphor-hwmon` and it will create temperature sensors
401on below DBus objects based on its sysfs attributes.
402
403```bash
404  /xyz/openbmc_project/sensors/temperature/outlet
405  /xyz/openbmc_project/sensors/temperature/inlet_cpu
406  /xyz/openbmc_project/sensors/temperature/inlet_io
407```
408
409- [pwm-tacho-controller@1e786000.conf][10] defines the fans and the config is
410  similar as above, the difference is that it creates `fan_tach` sensors.
411- [occ-hwmon.1.conf][11] defines the occ hwmon sensor for master CPU. This
412  config is a bit different, that it shall tell `phosphor-hwmon` to read the
413  label instead of directly getting the index of the sensor, because CPU cores
414  and DIMMs could be dynamic, e.g. CPU cores could be disabled, DIMMs could be
415  pulled out.
416
417```bash
418  MODE_temp1 = "label"
419  MODE_temp2 = "label"
420  ...
421  MODE_temp31 = "label"
422  MODE_temp32 = "label"
423  LABEL_temp91 = "p0_core0_temp"
424  LABEL_temp92 = "p0_core1_temp"
425  ...
426  LABEL_temp33 = "dimm6_temp"
427  LABEL_temp34 = "dimm7_temp"
428  LABEL_power2 = "p0_power"
429  ...
430```
431
432- The `MODE_temp* = "label"` tells that if it sees `tempX`, it shall read the
433  label which is the sensor id.
434- And `LABEL_temp* = "xxx"` tells the sensor name for the corresponding sensor
435  id.
436- For example, if `temp1_input` is 37000 and `temp1_label` is 91 in sysfs,
437  `phosphor-hwmon` knows `temp1_input` is for sensor id 91, which is
438  `p0_core0_temp`, so it creates
439  `/xyz/openbmc_project/sensors/temperature/p0_core0_temp` with sensor
440  value 37000.
441- For Romulus, the power sensors do not need to read label since all powers are
442  available on a system.
443- For Witherspoon, the power sensors are similar to temperature sensors, that it
444  shall tell hwmon to read the `function_id` instead of directly getting the
445  index of the sensor.
446
447### LEDs
448
449Several parts are involved for LED.
450
4511. In kernel dts, LEDs shall be described, e.g. [romulus dts][12] describes 3
452   LEDs, `fault`, `identify` and `power`.
453
454   ```dts
455    leds {
456      compatible = "gpio-leds";
457
458      fault {
459        gpios = <&gpio ASPEED_GPIO(N, 2) GPIO_ACTIVE_LOW>;
460      };
461
462      identify {
463        gpios = <&gpio ASPEED_GPIO(N, 4) GPIO_ACTIVE_HIGH>;
464      };
465
466      power {
467        gpios = <&gpio ASPEED_GPIO(R, 5) GPIO_ACTIVE_LOW>;
468      };
469    };
470   ```
471
4722. In machine layer, LEDs shall be configured via yaml to describe how it
473   functions, e.g. [Romulus led yaml][28]:
474
475   ```yaml
476   bmc_booted:
477     power:
478       Action: "Blink"
479       DutyOn: 50
480       Period: 1000
481       Priority: "On"
482   power_on:
483     power:
484       Action: "On"
485       DutyOn: 50
486       Period: 0
487       Priority: "On"
488   ```
489
490   It tells the LED manager to set the `power` LED to blink when BMC is ready
491   and booted, and set it on when host is powered on. 3. At runtime, LED manager
492   automatically set LEDs on/off/blink based on the above yaml config. 4. LED
493   can be accessed manually via /xyz/openbmc_project/led/, e.g.
494
4953. Get identify LED state:
496
497   ```bash
498    curl -b cjar -k https://$bmc/xyz/openbmc_project/led/physical/identify
499   ```
500
5014. Set identify LED to blink:
502
503   ```bash
504    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
505   ```
506
5075. When an error related to a FRU occurs, an event log is created in logging
508   with a CALLOUT path. [phosphor-fru-fault-monitor][29] monitors the logs:
509   - Assert the related fault LED group when a log with the CALLOUT path is
510     generated;
511   - De-assert the related fault LED group when the log is marked as "Resolved"
512     or deleted.
513
514**Note**: This yaml config can be automatically generated by
515[phosphor-mrw-tools][13] from its MRW, see [Witherspoon example][14].
516
517### Inventories and other sensors
518
519Inventories, other sensors (e.g. CPU/DIMM temperature), and FRUs are defined in
520ipmi's yaml config files.
521
522E.g. [meta-romulus/recipes-phosphor/ipmi][15]
523
524- `romulus-ipmi-inventory-map` defines regular inventories, e.g. CPU, memory,
525  motherboard.
526- `phosphor-ipmi-fru-properties` defines extra properties of the inventories.
527- `phosphor-ipmi-sensor-inventory` defines the sensors from IPMI.
528- `romulus-ipmi-inventory-sel` defines inventories used for IPMI SEL.
529
530For inventory map and fru-properties, they are similar between different
531systems, you can refer to this example and make one for your system.
532
533For ipmi-sensor-inventory, the sensors from IPMI are different between systems,
534so you need to define your own sensors, e.g.
535
536```yaml
5370x08:
538  sensorType: 0x07
539  path: /org/open_power/control/occ0
540  ...
5410x1e:
542  sensorType: 0x0C
543  path: /system/chassis/motherboard/dimm0
544  ...
5450x22:
546  sensorType: 0x07
547  path: /system/chassis/motherboard/cpu0/core0
548```
549
550The first value `0x08`, `0x1e` and `0x22` are the sensor id of IPMI, which is
551defined in MRW. You should follow the system's MRW to define the above config.
552
553**Note**: The yaml configs can be automatically generated by
554[phosphor-mrw-tools][13] from its MRW, see [Witherspoon example][14].
555
556### Fans
557
558[phosphor-fan-presence][16] manages all the services about fan:
559
560- `phosphor-fan-presence` checks if a fan is present, creates the fan DBus
561  objects in inventory and update the `Present` property.
562- `phosphor-fan-monitor` checks if a fan is functional, and update the
563  `Functional` property of the fan Dbus object.
564- `phosphor-fan-control` controls the fan speed by setting the fan speed target
565  based on conditions, e.g. temperatures.
566- `phosphor-cooling-type` checks and sets if the system is air-cooled or
567  water-cooled by setting properties of
568  `/xyz/openbmc_project/inventory/system/chassis` object.
569
570All the above services are configurable, e.g. by yaml config. So the machine
571specific configs shall be written when porting OpenBMC to a new machine.
572
573Taking Romulus as an example, it is air-cooled and has 3 fans without GPIO
574presence detection.
575
576#### Fan presence
577
578Romulus has no GPIO detection for fans, so it checks fan tach sensor:
579
580```yaml
581- name: fan0
582  path: /system/chassis/motherboard/fan0
583  methods:
584    - type: tach
585      sensors:
586        - fan0
587```
588
589The yaml config tells that
590
591- It shall create `/system/chassis/motherboard/fan0` object in inventory.
592- It shall check fan0 tach sensor (`/sensors/fan_tach/fan0`) to set `Present`
593  property on the fan0 object.
594
595#### Fan monitor
596
597Romulus fans use pwm to control the fan speed, where pwm ranges from 0 to 255,
598and the fan speed ranges from 0 to about 7000. So it needs a factor and offset
599to mapping the pwm to fan speed:
600
601```yaml
602- inventory: /system/chassis/motherboard/fan0
603  allowed_out_of_range_time: 30
604  deviation: 15
605  num_sensors_nonfunc_for_fan_nonfunc: 1
606  sensors:
607    - name: fan0
608      has_target: true
609      target_interface: xyz.openbmc_project.Control.FanPwm
610      factor: 21
611      offset: 1600
612```
613
614The yaml config tells that:
615
6161. It shall use `FanPwm` as target interface of the tach sensor.
6172. It shall calculate the expected fan speed as `target * 21 + 1600`.
6183. The deviation is `15%`, so if the fan speed is out of the expected range for
619   more than 30 seconds, fan0 shall be set as non-functional.
620
621#### Fan control
622
623The fan control service requires 4 yaml configuration files:
624
625- `zone-condition` defines the cooling zone conditions. Romulus is always
626  air-cooled, so this config is as simple as defining an `air_cooled_chassis`
627  condition based on the cooling type property.
628
629```yaml
630  - name: air_cooled_chassis
631   type: getProperty
632   properties:
633     - property: WaterCooled
634       interface: xyz.openbmc_project.Inventory.Decorator.CoolingType
635       path: /xyz/openbmc_project/inventory/system/chassis
636       type: bool
637       value: false
638```
639
640- `zone-config` defines the cooling zones. Romulus has only one zone:
641
642```yaml
643zones:
644  - zone: 0
645    full_speed: 255
646    default_floor: 195
647    increase_delay: 5
648    decrease_interval: 30
649```
650
651It defines that the zone full speed and default floor speed for the fans, so the
652fan pwm will be set to 255 if it is in full speed, and set to 195 if fans are in
653default floor speed.
654
655- `fan-config` defines which fans are controlled in which zone and which target
656  interface shall be used, e.g. below yaml config defines fan0 shall be
657  controlled in zone0 and it shall use `FanPwm` interface.
658
659```yaml
660  - inventory: /system/chassis/motherboard/fan0
661   cooling_zone: 0
662   sensors:
663     - fan0
664   target_interface: xyz.openbmc_project.Control.FanPwm
665   ...
666```
667
668- `events-config` defines the various events and its handlers, e.g. which fan
669  targets shall be set in which temperature. This config is a bit complicated,
670  the [example event yaml][17] provides documents and examples. Romulus example:
671
672```yaml
673- name: set_air_cooled_speed_boundaries_based_on_ambient
674  groups:
675    - name: zone0_ambient
676      interface: xyz.openbmc_project.Sensor.Value
677      property:
678        name: Value
679        type: int64_t
680  matches:
681    - name: propertiesChanged
682  actions:
683    - name: set_floor_from_average_sensor_value
684      map:
685        value:
686          - 27000: 85
687          - 32000: 112
688          - 37000: 126
689          - 40000: 141
690        type: std::map<int64_t, uint64_t>
691    - name: set_ceiling_from_average_sensor_value
692      map:
693        value:
694          - 25000: 175
695          - 27000: 255
696        type: std::map<int64_t, uint64_t>
697```
698
699The above yaml config defines the fan floor and ceiling speed in
700`zone0_ambient`'s different temperatures. E.g.
701
7021. When the temperature is lower than 27 degreesC, the floor speed (pwm) shall
703   be set to 85.
7042. When the temperature is between 27 and 32 degrees C, the floor speed (pwm)
705   shall be set to 112, etc.
706
707With above configs, phosphor-fan will run the fan presence/monitor/control logic
708as configured specifically for the machine.
709
710**Note**: Romulus fans are simple. For a more complicated example, refer to
711[Witherspoon fan configurations][18]. The following are the additional functions
712of Witherspoon fan configuration:
713
714- It checks GPIO for fan presence.
715- It checks GPIO to determine if the system is air or water cooled.
716- It has more sensors and more events in fan control.
717
718### GPIOs
719
720This section mainly focuses on the GPIOs in device tree that shall be monitored.
721E.g.:
722
723- A GPIO may represent a signal of host checkstop.
724- A GPIO may represent a button press.
725- A GPIO may represent if a device is attached or not.
726
727They are categorized as `phosphor-gpio-presence` for checking presences of a
728device, and `phosphor-gpio-monitor` for monitoring a GPIO.
729
730#### GPIOs in device tree
731
732All the GPIOs to be monitored shall be described in the device tree. E.g.
733
734```dts
735  gpio-keys {
736    compatible = "gpio-keys";
737
738    checkstop {
739      label = "checkstop";
740      gpios = <&gpio ASPEED_GPIO(J, 2) GPIO_ACTIVE_LOW>;
741      linux,code = <ASPEED_GPIO(J, 2)>;
742    };
743    id-button {
744      label = "id-button";
745      gpios = <&gpio ASPEED_GPIO(Q, 7) GPIO_ACTIVE_LOW>;
746      linux,code = <ASPEED_GPIO(Q, 7)>;
747    };
748  };
749```
750
751The following code describes two GPIO keys, one for `checkstop` and the other
752for `id-button`, where the key code is calculated from [aspeed-gpio.h][24]:
753
754```bash
755#define ASPEED_GPIO_PORT_A 0
756#define ASPEED_GPIO_PORT_B 1
757...
758#define ASPEED_GPIO_PORT_Y 24
759#define ASPEED_GPIO_PORT_Z 25
760#define ASPEED_GPIO_PORT_AA 26
761...
762
763#define ASPEED_GPIO(port, offset) \
764  ((ASPEED_GPIO_PORT_##port * 8) + offset)
765```
766
767#### GPIO Presence
768
769Witherspoon and Zaius have examples for gpio presence.
770
771- [Witherspoon][19]:
772
773```bash
774INVENTORY=/system/chassis/motherboard/powersupply0
775DEVPATH=/dev/input/by-path/platform-gpio-keys-event
776KEY=104
777NAME=powersupply0
778DRIVERS=/sys/bus/i2c/drivers/ibm-cffps,3-0069
779```
780
781It checks GPIO key 104 for `powersupply0`'s presence, creates the inventory
782object and bind or unbind the driver.
783
784- [Zaius][20]:
785
786```bash
787INVENTORY=/system/chassis/pcie_card_e2b
788DEVPATH=/dev/input/by-path/platform-gpio-keys-event
789KEY=39
790NAME=pcie_card_e2b
791```
792
793It checks GPIO key 39 for `pcie_card_e2b`'s presence, and creates the inventory
794object.
795
796#### GPIO monitor
797
798Typical usage of GPIO monitor is to monitor the checkstop event from the host,
799or button presses.
800
801- [checkstop monitor][21] is a common service for OpenPOWER machines.
802
803```bash
804DEVPATH=/dev/input/by-path/platform-gpio-keys-event
805KEY=74
806POLARITY=1
807TARGET=obmc-host-crash@0.target
808```
809
810By default it monitors GPIO key 74, and if it is triggered, it tells systemd to
811start `obmc-host-crash@0.target`. For systems using a different GPIO pin for
812checkstop, it simply overrides the default one by specifying its own config file
813in meta-machine layer. E.g. [Zaius's checkstop config][22]. **Note**: when the
814key is pressed, `phosphor-gpio-monitor` starts the target unit and exits.
815
816- [id-button monitor][23] is an example service on Romulus to monitor ID button
817  press.
818
819```bash
820DEVPATH=/dev/input/by-path/platform-gpio-keys-event
821KEY=135
822POLARITY=1
823TARGET=id-button-pressed.service
824EXTRA_ARGS=--continue
825```
826
827It monitors GPIO key 135 for the button press and starts
828`id-button-pressed.service`, that handles the event by setting the identify LED
829group's `Assert` property. **Note**: It has an extra argument, `--continue`,
830that tells `phosphor-gpio-monitor` to not exit and continue running when the key
831is pressed.
832
833[1]:
834  https://github.com/openbmc/linux/blob/dev-4.13/arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts
835[2]: https://lists.ozlabs.org/listinfo/openbmc
836[3]: https://github.com/openbmc/skeleton
837[4]:
838  https://github.com/openbmc/openbmc/tree/master/meta-quanta/meta-q71l/recipes-phosphor/workbook
839[5]: https://github.com/openbmc/skeleton/blob/master/configs/Romulus.py
840[6]:
841  https://github.com/openbmc/docs/blob/master/architecture/sensor-architecture.md
842[7]:
843  https://github.com/openbmc/openbmc/tree/master/meta-ibm/meta-romulus/recipes-phosphor/sensors
844[8]:
845  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
846[9]:
847  https://github.com/openbmc/linux/blob/aca92be80c008bceeb6fb62fd1d450b5be5d0a4f/arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts#L208
848[10]:
849  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
850[11]:
851  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
852[12]:
853  https://github.com/openbmc/linux/blob/aca92be80c008bceeb6fb62fd1d450b5be5d0a4f/arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts#L42
854[13]: https://github.com/openbmc/phosphor-mrw-tools
855[14]:
856  https://github.com/openbmc/openbmc/blob/764b88f4056cc98082e233216704e94613499e64/meta-ibm/meta-witherspoon/conf/distro/openbmc-witherspoon.conf#L4
857[15]:
858  https://github.com/openbmc/openbmc/tree/master/meta-ibm/meta-romulus/recipes-phosphor/ipmi
859[16]: https://github.com/openbmc/phosphor-fan-presence
860[17]:
861  https://github.com/openbmc/phosphor-fan-presence/blob/master/control/example/events.yaml
862[18]:
863  https://github.com/openbmc/openbmc/tree/master/meta-ibm/meta-witherspoon/recipes-phosphor/fans
864[19]:
865  https://github.com/openbmc/openbmc/blob/master/meta-ibm/meta-witherspoon/recipes-phosphor/gpio/phosphor-gpio-monitor/obmc/gpio/phosphor-power-supply-0.conf
866[20]:
867  https://github.com/openbmc/openbmc/blob/master/meta-ingrasys/meta-zaius/recipes-phosphor/gpio/phosphor-gpio-monitor/obmc/gpio/phosphor-pcie-card-e2b.conf
868[21]:
869  https://github.com/openbmc/openbmc/blob/master/meta-openpower/recipes-phosphor/host/checkstop-monitor.bb
870[22]:
871  https://github.com/openbmc/openbmc/blob/master/meta-ingrasys/meta-zaius/recipes-phosphor/host/checkstop-monitor/obmc/gpio/checkstop
872[23]:
873  https://github.com/openbmc/openbmc/tree/master/meta-ibm/meta-romulus/recipes-phosphor/gpio
874[24]:
875  https://github.com/openbmc/linux/blob/dev-4.13/include/dt-bindings/gpio/aspeed-gpio.h
876[26]:
877  https://github.com/openbmc/openbmc/commit/e0e69beab7c268e4ad98972016c78b0d7d5769ac
878[27]:
879  https://github.com/openbmc/openbmc/commit/2a80da2262bf13aa1ddb589cf3f2b672d26b0975
880[28]:
881  https://github.com/openbmc/openbmc/blob/3cce45a96f0416b4c3d8f2b698cb830662a29227/meta-ibm/meta-romulus/recipes-phosphor/leds/romulus-led-manager-config/led.yaml
882[29]: https://github.com/openbmc/phosphor-led-manager/tree/master/fault-monitor
883[31]: https://github.com/openbmc/docs/blob/master/kernel-development.md
884[32]: https://github.com/openbmc/docs/blob/master/development/dev-environment.md
885