phosphor-buttons: Fix HostSelector mode logic

Task Description:
This task fixes a issue where power button handlers fail to register
in multi-power button systems when a HostSelector D-Bus object exists
for OCP debug card support. The problem occurs because the existing
logic incorrectly assumes that any HostSelector object presence
indicates host selector button mode, preventing proper power button
signal registration in multi-power button configurations.

Motivation:
The current power button handler has two modes:
- Host Selector Button Mode (e.g., Yosemite V2):
Single power button with host selector switch for target host
handling, where hostSelectButtonMode = true
- Multi Power Button Mode (e.g., Yosemite V4):
Each slot/sled has its own power button, where
hostSelectButtonMode = false
However, when HostSelector D-Bus object exists solely for OCP
debug card support (not for power button functionality), the system
incorrectly enters host selector button mode, causing multi-power
button systems to fail registering powerReleased signals.
This results in non-functional power buttons across the platform.

Design:
- Virtual Button Flag: Added virtualButton flag to distinguish
between HostSelector objects used for actual power button control
versus those used for OCP debug card support. The flag is read from
the virtual_button field in the HOST_SELECTOR GPIO configuration.
- Corrected Mode Logic: Modified hostSelectButtonMode calculation
to isHostSelectorExists && !virtualButton, ensuring that
HostSelector objects marked as virtual buttons don't trigger
host selector button mode.
- Unified Signal Registration: Replaced separate single/multi power
button registration logic with a unified approach that dynamically
discovers and registers powerReleased signal handlers for all available
power button interfaces using D-Bus ObjectMapper's GetSubTreePaths.

Test Log(Tested on Yosemite V4):
```
root@bmc:~# cat /etc/default/obmc/gpio/gpio_defs.json | grep -i -E "POWER_BUTTON|HOST_SELECTOR|virtual_button"
            "name": "POWER_BUTTON1",
            "name": "POWER_BUTTON2",
            "name": "POWER_BUTTON3",
            "name": "POWER_BUTTON4",
            "name": "POWER_BUTTON5",
            "name": "POWER_BUTTON6",
            "name": "POWER_BUTTON7",
            "name": "POWER_BUTTON8",
            "name": "HOST_SELECTOR",
            "virtual_button": true,

root@bmc:~# systemctl status phosphor-button-handler.service
● phosphor-button-handler.service - Phosphor Button Handler
     Loaded: loaded (/usr/lib/systemd/system/phosphor-button-handler.service; enabled; preset: enabled)
     Active: active (running) since Wed 2025-11-05 03:09:06 PST; 7s ago
 Invocation: 81fd455a960e4c6cb201712d71219cb2
   Main PID: 9319 (button-handler)
      Tasks: 1 (limit: 1961)
     Memory: 324K (peak: 1M)
        CPU: 65ms
     CGroup: /system.slice/phosphor-button-handler.service
             └─9319 /usr/bin/button-handler

Nov 05 03:09:06 bmc button-handler[9319]: hostSelectButtonMode: False
Nov 05 03:09:06 bmc button-handler[9319]: Starting power button handler
Nov 05 03:09:06 bmc button-handler[9319]: Registering power button handler for: /xyz/openbmc_project/Chassis/Buttons/Power01
Nov 05 03:09:06 bmc button-handler[9319]: Registering power button handler for: /xyz/openbmc_project/Chassis/Buttons/Power02
Nov 05 03:09:06 bmc button-handler[9319]: Registering power button handler for: /xyz/openbmc_project/Chassis/Buttons/Power03
Nov 05 03:09:06 bmc button-handler[9319]: Registering power button handler for: /xyz/openbmc_project/Chassis/Buttons/Power04
Nov 05 03:09:06 bmc button-handler[9319]: Registering power button handler for: /xyz/openbmc_project/Chassis/Buttons/Power05
Nov 05 03:09:06 bmc button-handler[9319]: Registering power button handler for: /xyz/openbmc_project/Chassis/Buttons/Power06
Nov 05 03:09:06 bmc button-handler[9319]: Registering power button handler for: /xyz/openbmc_project/Chassis/Buttons/Power07
Nov 05 03:09:06 bmc button-handler[9319]: Registering power button handler for: /xyz/openbmc_project/Chassis/Buttons/Power08

```
Change-Id: Iaf5a6a4fc93522633ac3caa31d63f86a32eb88f5
Signed-off-by: Liora Guo <liora.guo.wiwynn@gmail.com>
3 files changed
tree: df83f4fa9d6708a444c4de58a71d57fff2be3b4f
  1. inc/
  2. service_files/
  3. src/
  4. subprojects/
  5. .clang-format
  6. .clang-tidy
  7. .gitignore
  8. LICENSE
  9. meson.build
  10. meson.options
  11. meson_config.hpp.in
  12. OWNERS
  13. README.md
README.md

phosphor-buttons

Phosphor-buttons has a collection of IO event handler interfaces for physical inputs which are typically part of some sort of panel.

It defines an individual dbus interface object for each physical button/switch inputs such as power button, reset button etc. Each button interface monitors its associated IO for event changes and emits signals that the button-handler application listens for.

Button Behavior

Power Button

All events occur when the button is released.

If the power is off, power on the host.

If the power is on, it depends on how long the press was and which options are enabled:

  • Short press: Do a host power off
  • Long press, as determined by the 'long-press-time-ms' meson option: Do a chassis (hard) power off.

Custom Power Button Profiles

The 'power-button-profile' meson option can be used to select custom power button profiles that have different behaviors.

Available profiles are:

  • host_then_chassis_poweroff: When power is on, short presses are ignored and a long press issues a host power off first and then a chassis power off if held past a certain time. This class has additional details.

Multi-Host Buttons

See this section below.

Reset Button

When released:

  • If 'reset-button-do-warm-reboot' meson option is set to enabled, does warm reboot the host.
  • Otherwise, reboots the host (default behavior)

ID Button

When released, toggles the 'enclosure_identify' LED group provided by the phosphor-led-manager repository. The group name can be changed using the 'id-led-group' meson option.

Gpio defs config

In order to monitor a button/input interface the respective gpio config details should be mentioned in the gpio defs json file - /etc/default/obmc/gpio/gpio_defs.json

  1. The button interface type name.
  2. An array consists of single or multiple gpio configs associated with the specific button interface.

A gpio can be mapped using the "pin" or "num" keyword. The "pin" key uses alphanumerical references while the "num" key supports the integer pin number.

example gpio def Json config

{
  "gpio_definitions": [
    {
      "name": "POWER_BUTTON",
      "pin": "D0",
      "direction": "both"
    },
    {
      "name": "RESET_BUTTON",
      "pin": "AB0",
      "direction": "both"
    },
    {
      "name": "HOST_SELECTOR",

      "group_gpio_config": [
        {
          "pin": "AA4",
          "direction": "both"
        },
        {
          "pin": "AA5",
          "direction": "both"
        },
        {
          "pin": "AA6",
          "direction": "both"
        },
        {
          "pin": "AA7",
          "direction": "both"
        }
      ]
    }
  ]
}

Single gpio config

This config is original config which can be used for configs with only single gpio such as power button,reset button, OCP debug card host select button.

{
  "name": "POWER_BUTTON",
  "pin": "D0",
  "direction": "both"
}

Note: this config is used by most of the other platforms so this format is kept as it is so that existing gpio configs do not get affected.

Group gpio config

The following configs are related to multi-host bmc systems more info explained in the design: https://github.com/openbmc/docs/blob/master/designs/multihost-phosphor-buttons.md

Host selector gpio config example

The host selector has four gpios associated. So the related gpios are mentioned in a json array named group_gpio_config.

  • name - This is name of the specific gpio line
  • pin - This represents the pin number from linux dts file.
  • polarity - polarity type of the gpio
  • max_position - This represents the max number of hosts in the multi-host bmc system.
  • host_selector_map - This map is oem specific host position map which has how the value read from the host selector gpios is mapped to the respective host number.

Optional: Polling Configuration Some platforms expose the host selector via a CPLD as GPIO inputs without edge-triggered interrupt support (e.g., no edge detection on GPIOs). In such situations, software-based polling mode can be enabled using the following optional fields in the JSON configuration:

  • polling_mode : Set to true to enable polling mode.
  • polling_interval_ms (optional): Polling interval in milliseconds. Defaults to 1000 ms if not specified.

Optional: Virtual Button Configuration Some platforms implement HostSelector objects without actual power button control functionality. To prevent interference with multi-power button mode detection:

  • virtual_button : Set to true when not used as power button, e.g., OCP debug card. Defaults to false if not specified.

Config Example

A.Interrupt example

Example : The value of "7" derived from the 4 host select gpio lines are mapped to host position 1.

{
  "name": "HOST_SELECTOR",

  "group_gpio_config": [
    {
      "name": "host_select_0",
      "pin": "AA4",
      "direction": "both",
      "polarity": "active_high"
    },
    {
      "name": "host_select_1",
      "pin": "AA5",
      "direction": "both",
      "polarity": "active_high"
    },
    {
      "name": "host_select_2",
      "pin": "AA6",
      "direction": "both",
      "polarity": "active_high"
    },
    {
      "name": "host_select_3",
      "pin": "AA7",
      "direction": "both",
      "polarity": "active_high"
    }
  ],
  "max_position": 4,
  "host_selector_map": {
    "6": 0,
    "7": 1,
    "8": 2,
    "9": 3,
    "10": 4,
    "11": 0,
    "12": 1,
    "13": 2,
    "14": 3,
    "15": 4
  }
}

B.Polling example

{
  "name": "HOST_SELECTOR",
  "polling_mode": true,
  "polling_interval_ms": 3000,
  "group_gpio_config": [
    {
      "name": "host_select_sel_0",
      "num": 2340,
      "direction": "in",
      "polarity": "active_low"
    },
    {
      "name": "host_select_sel_1",
      "num": 2341,
      "direction": "in",
      "polarity": "active_low"
    },
    {
      "name": "host_select_sel_2",
      "num": 2342,
      "direction": "in",
      "polarity": "active_low"
    },
    {
      "name": "host_select_sel_3",
      "num": 2343,
      "direction": "in",
      "polarity": "active_low"
    }
  ],
  "max_position": 8,
  "host_selector_map": {
    "0": 0,
    "1": 1,
    "2": 2,
    "3": 3,
    "4": 4,
    "5": 5,
    "6": 6,
    "7": 7,
    "8": 8
  }
}

Host selector cpld config example

There are also some systems that get the host selector selection from the CPLD, the configuration is provided below.

  • name - The button interface type name.
  • i2c_bus - The i2c bus of cpld
  • i2c_address - The i2c address of cpld
  • register_name - The register file name exported by CLD driver for IO event listen
  • max_position - This represents the max number of hosts in the multi-host bmc system.
{
  "cpld_definitions": [
    {
      "name": "HOST_SELECTOR",
      "i2c_bus": 12,
      "i2c_address": 15,
      "register_name": "uart-selection-debug-card",
      "max_position": 4
    }
  ]
}

Serial uart mux config

Similar to host selector there are multiple gpios associated with the serial uart mux. These gpio configs are specified as part of json array "group_gpio_config".

Here the serial uart mux output is accessed via OCP debug card. SO the OCP debug card present gpio is mentioned part of the group_gpio_config. The debug card present gpio is identified by its name "debug_card_present".

The other gpios part of the group gpio config is serial uart MUX gpio select lines and serial_uart_rx line.

  • name - this is name of the specific gpio line
  • pin - this represents the pin number from linux dts file.
  • polarity - polarity type of the gpio
  • serial_uart_mux_map - This is the map for selected host position to the serial uart mux select output value
{
  "name": "SERIAL_UART_MUX",

  "group_gpio_config": [
    {
      "name": "serial_uart_sel_0",
      "pin": "E0",
      "direction": "out",
      "polarity": "active_high"
    },
    {
      "name": "serial_uart_sel_1",
      "pin": "E1",
      "direction": "out",
      "polarity": "active_high"
    },
    {
      "name": "serial_uart_sel_2",
      "pin": "E2",
      "direction": "out",
      "polarity": "active_high"
    },
    {
      "name": "serial_uart_sel_3",
      "pin": "E3",
      "direction": "out",
      "polarity": "active_high"
    },
    {
      "name": "serial_uart_rx",
      "pin": "E4",
      "direction": "out",
      "polarity": "active_high"
    },
    {
      "name": "debug_card_present",
      "pin": "R3",
      "direction": "both",
      "polarity": "active_high"
    }
  ],
  "serial_uart_mux_map": {
    "0": 4,
    "1": 0,
    "2": 1,
    "3": 2,
    "4": 3
  }
}

Multiple power gpio config example

This config is used for configs with multiple power buttons on each slots and whole sled, or for which needs multi-level chassis power control behavior.

name - this is name of the specific gpio line, "POWER_BUTTON" + the index of chassis instance

  • pin - this represents the pin number from linux dts file.
  • multi-action - default no action, set the corresponding behavior with following format:
  • duration - activate when pulling gpio over this value (unit: millisecond)
  • action - chassis power control behavior
{
  "gpio_definitions": [
    {
      "name": "POWER_BUTTON0",
      "pin": "I6",
      "direction": "both",
      "multi-action": [
        {
          "duration": 4000,
          "action": "chassis cycle"
        }
      ]
    },
    {
      "name": "POWER_BUTTON1",
      "pin": "V0",
      "direction": "both",
      "multi-action": [
        {
          "duration": 0,
          "action": "chassis on"
        },
        {
          "duration": 4000,
          "action": "chassis cycle"
        },
        {
          "duration": 8000,
          "action": "chassis off"
        }
      ]
    }
  ]
}