| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 1 | #include <stdint.h> | 
|  | 2 | #include <stdio.h> | 
|  | 3 | #include <stdlib.h> | 
|  | 4 | #include <string.h> | 
|  | 5 | #include <fcntl.h> | 
|  | 6 | #include <unistd.h> | 
|  | 7 | #include <sys/stat.h> | 
|  | 8 | #include <sys/mman.h> | 
|  | 9 | #include <syslog.h> | 
| Brad Bishop | f6c8568 | 2016-06-27 11:56:39 -0400 | [diff] [blame] | 10 | #include <openbmc_intf.h> | 
|  | 11 | #include <openbmc.h> | 
|  | 12 | #include <gpio.h> | 
| Lei YU | 45cb4fc | 2016-11-29 01:48:26 +0800 | [diff] [blame] | 13 | #include <gpio_configs.h> | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 14 |  | 
|  | 15 | /* ------------------------------------------------------------------------- */ | 
|  | 16 | static const gchar* dbus_object_path = "/org/openbmc/control"; | 
|  | 17 | static const gchar* instance_name = "power0"; | 
|  | 18 | static const gchar* dbus_name = "org.openbmc.control.Power"; | 
|  | 19 |  | 
| Yi Li | 0475f65 | 2016-10-25 13:19:59 +0800 | [diff] [blame] | 20 | static int g_pci_reset_held = 1; | 
|  | 21 |  | 
| Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 22 | static GpioConfigs g_gpio_configs; | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 23 |  | 
|  | 24 | static GDBusObjectManagerServer *manager = NULL; | 
|  | 25 |  | 
|  | 26 | time_t pgood_timeout_start = 0; | 
|  | 27 |  | 
|  | 28 | // TODO:  Change to interrupt driven instead of polling | 
|  | 29 | static gboolean | 
|  | 30 | poll_pgood(gpointer user_data) | 
|  | 31 | { | 
|  | 32 | ControlPower *control_power = object_get_control_power((Object*)user_data); | 
|  | 33 | Control* control = object_get_control((Object*)user_data); | 
|  | 34 |  | 
|  | 35 | //send the heartbeat | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 36 | guint poll_int = control_get_poll_interval(control); | 
|  | 37 | if(poll_int == 0) | 
|  | 38 | { | 
| Xo Wang | 20a1941 | 2016-09-22 11:26:14 -0700 | [diff] [blame] | 39 | g_print("ERROR PowerControl: Poll interval cannot be 0\n"); | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 40 | return FALSE; | 
|  | 41 | } | 
|  | 42 | //handle timeout | 
|  | 43 | time_t current_time = time(NULL); | 
|  | 44 | if(difftime(current_time,pgood_timeout_start) > control_power_get_pgood_timeout(control_power) | 
|  | 45 | && pgood_timeout_start != 0) | 
|  | 46 | { | 
| Xo Wang | 20a1941 | 2016-09-22 11:26:14 -0700 | [diff] [blame] | 47 | g_print("ERROR PowerControl: Pgood poll timeout\n"); | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 48 | // set timeout to 0 so timeout doesn't happen again | 
|  | 49 | control_power_set_pgood_timeout(control_power,0); | 
|  | 50 | pgood_timeout_start = 0; | 
| Patrick Williams | 27eaf90 | 2017-03-21 15:46:40 -0500 | [diff] [blame] | 51 | return TRUE; | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 52 | } | 
| Xo Wang | 20a1941 | 2016-09-22 11:26:14 -0700 | [diff] [blame] | 53 | uint8_t pgood_state; | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 54 |  | 
| Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 55 | int rc = gpio_open(&g_gpio_configs.power_gpio.power_good_in); | 
| Xo Wang | 20a1941 | 2016-09-22 11:26:14 -0700 | [diff] [blame] | 56 | if(rc != GPIO_OK) { | 
|  | 57 | g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n", | 
| Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 58 | g_gpio_configs.power_gpio.power_good_in.name, rc); | 
| Xo Wang | 20a1941 | 2016-09-22 11:26:14 -0700 | [diff] [blame] | 59 | return FALSE; | 
|  | 60 | } | 
| Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 61 | rc = gpio_read(&g_gpio_configs.power_gpio.power_good_in, &pgood_state); | 
|  | 62 | gpio_close(&g_gpio_configs.power_gpio.power_good_in); | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 63 | if(rc == GPIO_OK) | 
|  | 64 | { | 
|  | 65 | //if changed, set property and emit signal | 
| Xo Wang | 20a1941 | 2016-09-22 11:26:14 -0700 | [diff] [blame] | 66 | if(pgood_state != control_power_get_pgood(control_power)) | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 67 | { | 
| Xo Wang | 20a1941 | 2016-09-22 11:26:14 -0700 | [diff] [blame] | 68 | int i; | 
|  | 69 | uint8_t reset_state; | 
|  | 70 | control_power_set_pgood(control_power, pgood_state); | 
|  | 71 | if(pgood_state == 0) | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 72 | { | 
|  | 73 | control_power_emit_power_lost(control_power); | 
|  | 74 | control_emit_goto_system_state(control,"HOST_POWERED_OFF"); | 
| Yi Li | 0475f65 | 2016-10-25 13:19:59 +0800 | [diff] [blame] | 75 | g_pci_reset_held = 1; | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 76 | } | 
|  | 77 | else | 
|  | 78 | { | 
|  | 79 | control_power_emit_power_good(control_power); | 
|  | 80 | control_emit_goto_system_state(control,"HOST_POWERED_ON"); | 
| Xo Wang | 20a1941 | 2016-09-22 11:26:14 -0700 | [diff] [blame] | 81 | } | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 82 |  | 
| Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 83 | for(i = 0; i < g_gpio_configs.power_gpio.num_reset_outs; i++) | 
| Xo Wang | 20a1941 | 2016-09-22 11:26:14 -0700 | [diff] [blame] | 84 | { | 
| Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 85 | GPIO *reset_out = &g_gpio_configs.power_gpio.reset_outs[i]; | 
| Xo Wang | 20a1941 | 2016-09-22 11:26:14 -0700 | [diff] [blame] | 86 | rc = gpio_open(reset_out); | 
|  | 87 | if(rc != GPIO_OK) | 
|  | 88 | { | 
|  | 89 | g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n", | 
|  | 90 | reset_out->name, rc); | 
|  | 91 | continue; | 
|  | 92 | } | 
|  | 93 |  | 
| Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 94 | reset_state = pgood_state ^ g_gpio_configs.power_gpio.reset_pols[i]; | 
| Yi Li | 39df403 | 2016-12-16 16:06:50 +0800 | [diff] [blame] | 95 | g_print("PowerControl: pgood: %d, setting reset %s to %d\n", | 
| Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 96 | (int)pgood_state, reset_out->name, (int)reset_state); | 
| Xo Wang | 20a1941 | 2016-09-22 11:26:14 -0700 | [diff] [blame] | 97 | gpio_write(reset_out, reset_state); | 
|  | 98 | gpio_close(reset_out); | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 99 | } | 
| Yi Li | 0475f65 | 2016-10-25 13:19:59 +0800 | [diff] [blame] | 100 |  | 
| Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 101 | for(i = 0; i < g_gpio_configs.power_gpio.num_pci_reset_outs; i++) | 
| Yi Li | 0475f65 | 2016-10-25 13:19:59 +0800 | [diff] [blame] | 102 | { | 
| Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 103 | GPIO *pci_reset_out = &g_gpio_configs.power_gpio.pci_reset_outs[i]; | 
| Yi Li | 0475f65 | 2016-10-25 13:19:59 +0800 | [diff] [blame] | 104 | if(pgood_state == 1) | 
|  | 105 | { | 
|  | 106 | /* | 
|  | 107 | * When powering on, hold PCI reset until | 
|  | 108 | * the processor can forward clocks and control reset. | 
|  | 109 | */ | 
| Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 110 | if(g_gpio_configs.power_gpio.pci_reset_holds[i]) | 
| Yi Li | 0475f65 | 2016-10-25 13:19:59 +0800 | [diff] [blame] | 111 | { | 
|  | 112 | g_print("Holding pci reset: %s\n", pci_reset_out->name); | 
|  | 113 | continue; | 
|  | 114 | } | 
|  | 115 | } | 
|  | 116 | rc = gpio_open(pci_reset_out); | 
|  | 117 | if(rc != GPIO_OK) | 
|  | 118 | { | 
|  | 119 | g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n", | 
|  | 120 | pci_reset_out->name, rc); | 
|  | 121 | continue; | 
|  | 122 | } | 
|  | 123 |  | 
| Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 124 | reset_state = pgood_state ^ g_gpio_configs.power_gpio.pci_reset_pols[i]; | 
| Yi Li | 39df403 | 2016-12-16 16:06:50 +0800 | [diff] [blame] | 125 | g_print("PowerControl: pgood: %d, setting pci reset %s to %d\n", | 
| Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 126 | (int)pgood_state, pci_reset_out->name, (int)reset_state); | 
| Yi Li | 0475f65 | 2016-10-25 13:19:59 +0800 | [diff] [blame] | 127 | gpio_write(pci_reset_out, reset_state); | 
|  | 128 | gpio_close(pci_reset_out); | 
|  | 129 | } | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 130 | } | 
|  | 131 | } else { | 
| Xo Wang | 20a1941 | 2016-09-22 11:26:14 -0700 | [diff] [blame] | 132 | g_print("ERROR PowerControl: GPIO read error (gpio=%s,rc=%d)\n", | 
| Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 133 | g_gpio_configs.power_gpio.power_good_in.name, rc); | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 134 | //return false so poll won't get called anymore | 
|  | 135 | return FALSE; | 
|  | 136 | } | 
|  | 137 | //pgood is not at desired state yet | 
| Xo Wang | 20a1941 | 2016-09-22 11:26:14 -0700 | [diff] [blame] | 138 | if(pgood_state != control_power_get_state(control_power) && | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 139 | control_power_get_pgood_timeout(control_power) > 0) | 
|  | 140 | { | 
|  | 141 | if(pgood_timeout_start == 0 ) { | 
|  | 142 | pgood_timeout_start = current_time; | 
|  | 143 | } | 
|  | 144 | } | 
|  | 145 | else | 
|  | 146 | { | 
|  | 147 | pgood_timeout_start = 0; | 
|  | 148 | } | 
|  | 149 | return TRUE; | 
|  | 150 | } | 
|  | 151 |  | 
| Yi Li | 0475f65 | 2016-10-25 13:19:59 +0800 | [diff] [blame] | 152 | /* Handler for BootProgress signal from BootProgress sensor */ | 
|  | 153 | static void | 
|  | 154 | on_boot_progress(GDBusConnection *connection, | 
|  | 155 | const gchar *sender_name, | 
|  | 156 | const gchar *object_path, | 
|  | 157 | const gchar *interface_name, | 
|  | 158 | const gchar *signal_name, | 
|  | 159 | GVariant *parameters, | 
|  | 160 | gpointer user_data) | 
|  | 161 | { | 
| Lei YU | 93b84e4 | 2017-10-11 15:06:20 +0800 | [diff] [blame] | 162 | gchar *interface; | 
|  | 163 | GVariantIter *properties; | 
|  | 164 | GVariantIter *dummy; | 
|  | 165 | gchar *boot_progress = NULL; | 
|  | 166 | gchar *property; | 
|  | 167 | GVariant *value; | 
| Yi Li | 0475f65 | 2016-10-25 13:19:59 +0800 | [diff] [blame] | 168 | uint8_t pgood_state; | 
|  | 169 | uint8_t reset_state; | 
|  | 170 | int rc; | 
|  | 171 | int i; | 
| Lei YU | 93b84e4 | 2017-10-11 15:06:20 +0800 | [diff] [blame] | 172 | int ignore; | 
| Yi Li | 0475f65 | 2016-10-25 13:19:59 +0800 | [diff] [blame] | 173 |  | 
|  | 174 | if(!parameters) | 
|  | 175 | return; | 
|  | 176 |  | 
|  | 177 | /* prevent release again */ | 
|  | 178 | if(!g_pci_reset_held) | 
|  | 179 | return; | 
|  | 180 |  | 
| Lei YU | 93b84e4 | 2017-10-11 15:06:20 +0800 | [diff] [blame] | 181 | g_variant_get(parameters, "(&sa{sv}as)", &interface, &properties, &dummy); | 
|  | 182 | for(i = 0; g_variant_iter_next(properties, "{&sv}", &property, &value); i++) | 
|  | 183 | { | 
|  | 184 | if (strcmp(property, "BootProgress") == 0) | 
|  | 185 | { | 
|  | 186 | gchar* tmp; | 
|  | 187 | g_variant_get(value, "&s", &tmp); | 
|  | 188 | boot_progress = g_strdup(tmp); | 
|  | 189 | g_print("BootProgress: %s\n", boot_progress); | 
|  | 190 | g_variant_unref(value); | 
|  | 191 | } | 
|  | 192 | } | 
|  | 193 |  | 
|  | 194 | g_variant_iter_free(properties); | 
|  | 195 | g_variant_iter_free(dummy); | 
|  | 196 | if (boot_progress == NULL) | 
|  | 197 | return; | 
|  | 198 |  | 
| Yi Li | 0475f65 | 2016-10-25 13:19:59 +0800 | [diff] [blame] | 199 | /* Release PCI reset when FW boot progress goes beyond 'Baseboard Init' */ | 
| Lei YU | 93b84e4 | 2017-10-11 15:06:20 +0800 | [diff] [blame] | 200 | ignore = strcmp(boot_progress, | 
|  | 201 | "xyz.openbmc_project.State.Boot.Progress.ProgressStages.MotherboardInit") == 0; | 
|  | 202 | g_free(boot_progress); | 
|  | 203 |  | 
|  | 204 | if (ignore) | 
| Yi Li | 0475f65 | 2016-10-25 13:19:59 +0800 | [diff] [blame] | 205 | return; | 
|  | 206 |  | 
| Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 207 | rc = gpio_open(&g_gpio_configs.power_gpio.power_good_in); | 
| Yi Li | 0475f65 | 2016-10-25 13:19:59 +0800 | [diff] [blame] | 208 | if(rc != GPIO_OK) | 
|  | 209 | { | 
|  | 210 | g_print("ERROR PowerControl: on_boot_progress(): GPIO open error (gpio=%s,rc=%d)\n", | 
| Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 211 | g_gpio_configs.power_gpio.power_good_in.name, rc); | 
| Yi Li | 0475f65 | 2016-10-25 13:19:59 +0800 | [diff] [blame] | 212 | return; | 
|  | 213 | } | 
| Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 214 | rc = gpio_read(&g_gpio_configs.power_gpio.power_good_in, &pgood_state); | 
|  | 215 | gpio_close(&g_gpio_configs.power_gpio.power_good_in); | 
| Yi Li | 0475f65 | 2016-10-25 13:19:59 +0800 | [diff] [blame] | 216 | if(rc != GPIO_OK || pgood_state != 1) | 
|  | 217 | return; | 
|  | 218 |  | 
| Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 219 | for(i = 0; i < g_gpio_configs.power_gpio.num_pci_reset_outs; i++) | 
| Yi Li | 0475f65 | 2016-10-25 13:19:59 +0800 | [diff] [blame] | 220 | { | 
| Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 221 | GPIO *pci_reset_out = &g_gpio_configs.power_gpio.pci_reset_outs[i]; | 
| Yi Li | 0475f65 | 2016-10-25 13:19:59 +0800 | [diff] [blame] | 222 |  | 
| Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 223 | if(!g_gpio_configs.power_gpio.pci_reset_holds[i]) | 
| Yi Li | 0475f65 | 2016-10-25 13:19:59 +0800 | [diff] [blame] | 224 | continue; | 
|  | 225 | rc = gpio_open(pci_reset_out); | 
|  | 226 | if(rc != GPIO_OK) | 
|  | 227 | { | 
|  | 228 | g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n", | 
|  | 229 | pci_reset_out->name, rc); | 
|  | 230 | continue; | 
|  | 231 | } | 
|  | 232 |  | 
| Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 233 | reset_state = pgood_state ^ g_gpio_configs.power_gpio.pci_reset_pols[i]; | 
| Yi Li | 39df403 | 2016-12-16 16:06:50 +0800 | [diff] [blame] | 234 | g_print("PowerControl: pgood: %d, setting pci reset %s to %d\n", | 
| Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 235 | (int)pgood_state, pci_reset_out->name, (int)reset_state); | 
| Yi Li | 0475f65 | 2016-10-25 13:19:59 +0800 | [diff] [blame] | 236 | gpio_write(pci_reset_out, reset_state); | 
|  | 237 | gpio_close(pci_reset_out); | 
| Lei YU | 93b84e4 | 2017-10-11 15:06:20 +0800 | [diff] [blame] | 238 | g_print("Released pci reset: %s\n", pci_reset_out->name); | 
| Yi Li | 0475f65 | 2016-10-25 13:19:59 +0800 | [diff] [blame] | 239 | } | 
|  | 240 | g_pci_reset_held = 0; | 
|  | 241 | } | 
|  | 242 |  | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 243 | static gboolean | 
|  | 244 | on_set_power_state(ControlPower *pwr, | 
|  | 245 | GDBusMethodInvocation *invocation, | 
|  | 246 | guint state, | 
|  | 247 | gpointer user_data) | 
|  | 248 | { | 
|  | 249 | Control* control = object_get_control((Object*)user_data); | 
| Xo Wang | aa6c76f | 2017-03-03 14:25:01 -0800 | [diff] [blame] | 250 | PowerGpio *power_gpio = &g_gpio_configs.power_gpio; | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 251 | if(state > 1) | 
|  | 252 | { | 
|  | 253 | g_dbus_method_invocation_return_dbus_error(invocation, | 
|  | 254 | "org.openbmc.ControlPower.Error.Failed", | 
|  | 255 | "Invalid power state"); | 
|  | 256 | return TRUE; | 
|  | 257 | } | 
|  | 258 | // return from method call | 
|  | 259 | control_power_complete_set_power_state(pwr,invocation); | 
|  | 260 | if(state == control_power_get_state(pwr)) | 
|  | 261 | { | 
|  | 262 | g_print("Power already at requested state: %d\n",state); | 
|  | 263 | } | 
|  | 264 | else | 
|  | 265 | { | 
|  | 266 | int error = 0; | 
|  | 267 | do { | 
| Xo Wang | 20a1941 | 2016-09-22 11:26:14 -0700 | [diff] [blame] | 268 | int i; | 
|  | 269 | uint8_t power_up_out; | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 270 | if(state == 1) { | 
|  | 271 | control_emit_goto_system_state(control,"HOST_POWERING_ON"); | 
|  | 272 | } else { | 
|  | 273 | control_emit_goto_system_state(control,"HOST_POWERING_OFF"); | 
|  | 274 | } | 
| Xo Wang | aa6c76f | 2017-03-03 14:25:01 -0800 | [diff] [blame] | 275 | for (i = 0; i < power_gpio->num_power_up_outs; i++) { | 
|  | 276 | GPIO *power_pin = &power_gpio->power_up_outs[i]; | 
| Xo Wang | 20a1941 | 2016-09-22 11:26:14 -0700 | [diff] [blame] | 277 | error = gpio_open(power_pin); | 
|  | 278 | if(error != GPIO_OK) { | 
|  | 279 | g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n", | 
| Xo Wang | aa6c76f | 2017-03-03 14:25:01 -0800 | [diff] [blame] | 280 | power_gpio->power_up_outs[i].name, error); | 
| Xo Wang | 20a1941 | 2016-09-22 11:26:14 -0700 | [diff] [blame] | 281 | continue; | 
|  | 282 | } | 
| Xo Wang | aa6c76f | 2017-03-03 14:25:01 -0800 | [diff] [blame] | 283 | power_up_out = state ^ !power_gpio->power_up_pols[i]; | 
| Xo Wang | 20a1941 | 2016-09-22 11:26:14 -0700 | [diff] [blame] | 284 | g_print("PowerControl: setting power up %s to %d\n", | 
| Xo Wang | aa6c76f | 2017-03-03 14:25:01 -0800 | [diff] [blame] | 285 | power_gpio->power_up_outs[i].name, (int)power_up_out); | 
| Xo Wang | 20a1941 | 2016-09-22 11:26:14 -0700 | [diff] [blame] | 286 | error = gpio_write(power_pin, power_up_out); | 
|  | 287 | if(error != GPIO_OK) { | 
|  | 288 | continue; | 
|  | 289 | } | 
|  | 290 | gpio_close(power_pin); | 
|  | 291 | } | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 292 | if(error != GPIO_OK) { break;	} | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 293 | control_power_set_state(pwr,state); | 
|  | 294 | } while(0); | 
|  | 295 | if(error != GPIO_OK) | 
|  | 296 | { | 
| Xo Wang | 20a1941 | 2016-09-22 11:26:14 -0700 | [diff] [blame] | 297 | g_print("ERROR PowerControl: GPIO set power state (rc=%d)\n",error); | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 298 | } | 
| Xo Wang | aa6c76f | 2017-03-03 14:25:01 -0800 | [diff] [blame] | 299 |  | 
|  | 300 | /* If there's a latch, it should be enabled following changes to the | 
|  | 301 | * power pins' states. This commits the changes to the latch states. */ | 
|  | 302 | if (power_gpio->latch_out.name != NULL) { | 
|  | 303 | int rc; | 
|  | 304 | uint8_t latch_value = 0; | 
|  | 305 | rc = gpio_open(&power_gpio->latch_out); | 
|  | 306 | if (rc != GPIO_OK) { | 
|  | 307 | /* Failures are non-fatal. */ | 
|  | 308 | g_print("PowerControl ERROR failed to open latch %s rc=%d\n", | 
|  | 309 | power_gpio->latch_out.name, rc); | 
|  | 310 | return TRUE; | 
|  | 311 | } | 
|  | 312 | /* Make the latch transparent for as brief of a time as possible. */ | 
|  | 313 | rc = gpio_write(&power_gpio->latch_out, 1); | 
|  | 314 | if (rc != GPIO_OK) { | 
|  | 315 | g_print("PowerControl ERROR failed to assert latch %s rc=%d\n", | 
|  | 316 | power_gpio->latch_out.name, rc); | 
|  | 317 | } else { | 
|  | 318 | g_print("PowerControl asserted latch %s\n", | 
|  | 319 | power_gpio->latch_out.name); | 
|  | 320 | } | 
|  | 321 | rc = gpio_write(&power_gpio->latch_out, 0); | 
|  | 322 | if (rc != GPIO_OK) { | 
|  | 323 | g_print("PowerControl ERROR failed to clear latch %s rc=%d\n", | 
|  | 324 | power_gpio->latch_out.name, rc); | 
|  | 325 | } | 
|  | 326 | gpio_close(&power_gpio->latch_out); | 
|  | 327 | } | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 328 | } | 
| Xo Wang | aa6c76f | 2017-03-03 14:25:01 -0800 | [diff] [blame] | 329 |  | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 330 | return TRUE; | 
|  | 331 | } | 
|  | 332 |  | 
|  | 333 | static gboolean | 
|  | 334 | on_init(Control *control, | 
|  | 335 | GDBusMethodInvocation *invocation, | 
|  | 336 | gpointer user_data) | 
|  | 337 | { | 
|  | 338 | pgood_timeout_start = 0; | 
|  | 339 | //guint poll_interval = control_get_poll_interval(control); | 
|  | 340 | //g_timeout_add(poll_interval, poll_pgood, user_data); | 
|  | 341 | control_complete_init(control,invocation); | 
|  | 342 | return TRUE; | 
|  | 343 | } | 
|  | 344 |  | 
|  | 345 | static gboolean | 
|  | 346 | on_get_power_state(ControlPower *pwr, | 
|  | 347 | GDBusMethodInvocation *invocation, | 
|  | 348 | gpointer user_data) | 
|  | 349 | { | 
|  | 350 | guint pgood = control_power_get_pgood(pwr); | 
|  | 351 | control_power_complete_get_power_state(pwr,invocation,pgood); | 
|  | 352 | return TRUE; | 
|  | 353 | } | 
|  | 354 |  | 
| Xo Wang | 20a1941 | 2016-09-22 11:26:14 -0700 | [diff] [blame] | 355 | static int | 
|  | 356 | set_up_gpio(GDBusConnection *connection, | 
|  | 357 | PowerGpio *power_gpio, | 
|  | 358 | ControlPower* control_power) | 
|  | 359 | { | 
|  | 360 | int error = GPIO_OK; | 
|  | 361 | int rc; | 
|  | 362 | int i; | 
|  | 363 | uint8_t pgood_state; | 
|  | 364 |  | 
|  | 365 | // get gpio device paths | 
| Xo Wang | c1ce68b | 2016-09-22 16:34:37 -0700 | [diff] [blame] | 366 | if(power_gpio->latch_out.name != NULL) {  /* latch is optional */ | 
|  | 367 | rc = gpio_init(connection, &power_gpio->latch_out); | 
|  | 368 | if(rc != GPIO_OK) { | 
|  | 369 | error = rc; | 
|  | 370 | } | 
|  | 371 | } | 
| Xo Wang | 20a1941 | 2016-09-22 11:26:14 -0700 | [diff] [blame] | 372 | rc = gpio_init(connection, &power_gpio->power_good_in); | 
|  | 373 | if(rc != GPIO_OK) { | 
|  | 374 | error = rc; | 
|  | 375 | } | 
|  | 376 | for(int i = 0; i < power_gpio->num_power_up_outs; i++) { | 
|  | 377 | rc = gpio_init(connection, &power_gpio->power_up_outs[i]); | 
|  | 378 | if(rc != GPIO_OK) { | 
|  | 379 | error = rc; | 
|  | 380 | } | 
|  | 381 | } | 
|  | 382 | for(int i = 0; i < power_gpio->num_reset_outs; i++) { | 
|  | 383 | rc = gpio_init(connection, &power_gpio->reset_outs[i]); | 
|  | 384 | if(rc != GPIO_OK) { | 
|  | 385 | error = rc; | 
|  | 386 | } | 
|  | 387 | } | 
| Yi Li | 0475f65 | 2016-10-25 13:19:59 +0800 | [diff] [blame] | 388 | for(int i = 0; i < power_gpio->num_pci_reset_outs; i++) { | 
|  | 389 | rc = gpio_init(connection, &power_gpio->pci_reset_outs[i]); | 
|  | 390 | if(rc != GPIO_OK) { | 
|  | 391 | error = rc; | 
|  | 392 | } | 
|  | 393 | } | 
| Xo Wang | 20a1941 | 2016-09-22 11:26:14 -0700 | [diff] [blame] | 394 |  | 
|  | 395 | rc = gpio_open(&power_gpio->power_good_in); | 
|  | 396 | if(rc != GPIO_OK) { | 
|  | 397 | return rc; | 
|  | 398 | } | 
|  | 399 | rc = gpio_read(&power_gpio->power_good_in, &pgood_state); | 
|  | 400 | if(rc != GPIO_OK) { | 
|  | 401 | return rc; | 
|  | 402 | } | 
|  | 403 | gpio_close(&power_gpio->power_good_in); | 
|  | 404 | control_power_set_pgood(control_power, pgood_state); | 
|  | 405 | control_power_set_state(control_power, pgood_state); | 
|  | 406 | g_print("Pgood state: %d\n", pgood_state); | 
|  | 407 |  | 
|  | 408 | return error; | 
|  | 409 | } | 
|  | 410 |  | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 411 | static void | 
|  | 412 | on_bus_acquired(GDBusConnection *connection, | 
|  | 413 | const gchar *name, | 
|  | 414 | gpointer user_data) | 
|  | 415 | { | 
|  | 416 | ObjectSkeleton *object; | 
|  | 417 | cmdline *cmd = user_data; | 
|  | 418 | if(cmd->argc < 3) | 
|  | 419 | { | 
|  | 420 | g_print("Usage: power_control.exe [poll interval] [timeout]\n"); | 
|  | 421 | return; | 
|  | 422 | } | 
|  | 423 | manager = g_dbus_object_manager_server_new(dbus_object_path); | 
|  | 424 | gchar *s; | 
|  | 425 | s = g_strdup_printf("%s/%s",dbus_object_path,instance_name); | 
|  | 426 | object = object_skeleton_new(s); | 
|  | 427 | g_free(s); | 
|  | 428 |  | 
|  | 429 | ControlPower* control_power = control_power_skeleton_new(); | 
|  | 430 | object_skeleton_set_control_power(object, control_power); | 
|  | 431 | g_object_unref(control_power); | 
|  | 432 |  | 
|  | 433 | Control* control = control_skeleton_new(); | 
|  | 434 | object_skeleton_set_control(object, control); | 
|  | 435 | g_object_unref(control); | 
|  | 436 |  | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 437 | //define method callbacks here | 
|  | 438 | g_signal_connect(control_power, | 
|  | 439 | "handle-set-power-state", | 
|  | 440 | G_CALLBACK(on_set_power_state), | 
|  | 441 | object); /* user_data */ | 
|  | 442 |  | 
|  | 443 | g_signal_connect(control_power, | 
|  | 444 | "handle-get-power-state", | 
|  | 445 | G_CALLBACK(on_get_power_state), | 
|  | 446 | NULL); /* user_data */ | 
|  | 447 |  | 
|  | 448 | g_signal_connect(control, | 
|  | 449 | "handle-init", | 
|  | 450 | G_CALLBACK(on_init), | 
|  | 451 | object); /* user_data */ | 
|  | 452 |  | 
| Yi Li | 0475f65 | 2016-10-25 13:19:59 +0800 | [diff] [blame] | 453 | /* Listen for BootProgress signal from BootProgress sensor */ | 
|  | 454 | g_dbus_connection_signal_subscribe(connection, | 
|  | 455 | NULL, /* service */ | 
| Lei YU | 93b84e4 | 2017-10-11 15:06:20 +0800 | [diff] [blame] | 456 | "org.freedesktop.DBus.Properties", /* interface_name */ | 
|  | 457 | "PropertiesChanged", /* member: name of the signal */ | 
|  | 458 | "/xyz/openbmc_project/state/host0", /* obj path */ | 
| Yi Li | 0475f65 | 2016-10-25 13:19:59 +0800 | [diff] [blame] | 459 | NULL, /* arg0 */ | 
|  | 460 | G_DBUS_SIGNAL_FLAGS_NONE, | 
|  | 461 | (GDBusSignalCallback) on_boot_progress, | 
|  | 462 | object, /* user data */ | 
|  | 463 | NULL ); | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 464 |  | 
|  | 465 | /* Export the object (@manager takes its own reference to @object) */ | 
| Brad Bishop | 58e694d | 2016-04-13 16:04:32 -0400 | [diff] [blame] | 466 | g_dbus_object_manager_server_set_connection(manager, connection); | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 467 | g_dbus_object_manager_server_export(manager, G_DBUS_OBJECT_SKELETON(object)); | 
|  | 468 | g_object_unref(object); | 
|  | 469 |  | 
| Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 470 | if(read_gpios(connection, &g_gpio_configs) != TRUE) { | 
| Xo Wang | 20a1941 | 2016-09-22 11:26:14 -0700 | [diff] [blame] | 471 | g_print("ERROR PowerControl: could not read power GPIO configuration\n"); | 
|  | 472 | } | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 473 |  | 
| Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 474 | int rc = set_up_gpio(connection, &g_gpio_configs.power_gpio, control_power); | 
| Xo Wang | 20a1941 | 2016-09-22 11:26:14 -0700 | [diff] [blame] | 475 | if(rc != GPIO_OK) { | 
|  | 476 | g_print("ERROR PowerControl: GPIO setup (rc=%d)\n",rc); | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 477 | } | 
|  | 478 | //start poll | 
|  | 479 | pgood_timeout_start = 0; | 
|  | 480 | int poll_interval = atoi(cmd->argv[1]); | 
|  | 481 | int pgood_timeout = atoi(cmd->argv[2]); | 
|  | 482 | if(poll_interval < 1000 || pgood_timeout <5) { | 
| Xo Wang | 20a1941 | 2016-09-22 11:26:14 -0700 | [diff] [blame] | 483 | g_print("ERROR PowerControl: poll_interval < 1000 or pgood_timeout < 5\n"); | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 484 | } else { | 
|  | 485 | control_set_poll_interval(control,poll_interval); | 
|  | 486 | control_power_set_pgood_timeout(control_power,pgood_timeout); | 
|  | 487 | g_timeout_add(poll_interval, poll_pgood, object); | 
|  | 488 | } | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 489 | } | 
|  | 490 |  | 
|  | 491 | static void | 
|  | 492 | on_name_acquired(GDBusConnection *connection, | 
|  | 493 | const gchar *name, | 
|  | 494 | gpointer user_data) | 
|  | 495 | { | 
|  | 496 | } | 
|  | 497 |  | 
|  | 498 | static void | 
|  | 499 | on_name_lost(GDBusConnection *connection, | 
|  | 500 | const gchar *name, | 
|  | 501 | gpointer user_data) | 
|  | 502 | { | 
| Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 503 | free_gpios(&g_gpio_configs); | 
| Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 504 | } | 
|  | 505 |  | 
|  | 506 | /*----------------------------------------------------------------*/ | 
|  | 507 | /* Main Event Loop                                                */ | 
|  | 508 |  | 
|  | 509 | gint | 
|  | 510 | main(gint argc, gchar *argv[]) | 
|  | 511 | { | 
|  | 512 | GMainLoop *loop; | 
|  | 513 | cmdline cmd; | 
|  | 514 | cmd.argc = argc; | 
|  | 515 | cmd.argv = argv; | 
|  | 516 |  | 
|  | 517 | guint id; | 
|  | 518 | loop = g_main_loop_new(NULL, FALSE); | 
|  | 519 |  | 
|  | 520 | id = g_bus_own_name(DBUS_TYPE, | 
|  | 521 | dbus_name, | 
|  | 522 | G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | | 
|  | 523 | G_BUS_NAME_OWNER_FLAGS_REPLACE, | 
|  | 524 | on_bus_acquired, | 
|  | 525 | on_name_acquired, | 
|  | 526 | on_name_lost, | 
|  | 527 | &cmd, | 
|  | 528 | NULL); | 
|  | 529 |  | 
|  | 530 | g_main_loop_run(loop); | 
|  | 531 |  | 
|  | 532 | g_bus_unown_name(id); | 
|  | 533 | g_main_loop_unref(loop); | 
|  | 534 | return 0; | 
|  | 535 | } |