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