xref: /openbmc/skeleton/op-pwrctl/power_control_obj.c (revision 600ff3300c45a41ed2f3bc45372980fd1a660f7d)
140a360c2SBrad Bishop #include <stdint.h>
240a360c2SBrad Bishop #include <stdio.h>
340a360c2SBrad Bishop #include <stdlib.h>
440a360c2SBrad Bishop #include <string.h>
540a360c2SBrad Bishop #include <fcntl.h>
640a360c2SBrad Bishop #include <unistd.h>
740a360c2SBrad Bishop #include <sys/stat.h>
840a360c2SBrad Bishop #include <sys/mman.h>
940a360c2SBrad Bishop #include <syslog.h>
10f6c85685SBrad Bishop #include <openbmc_intf.h>
11f6c85685SBrad Bishop #include <openbmc.h>
12f6c85685SBrad Bishop #include <gpio.h>
1345cb4fccSLei YU #include <gpio_configs.h>
1440a360c2SBrad Bishop 
1540a360c2SBrad Bishop /* ------------------------------------------------------------------------- */
1640a360c2SBrad Bishop static const gchar* dbus_object_path = "/org/openbmc/control";
1740a360c2SBrad Bishop static const gchar* instance_name = "power0";
1840a360c2SBrad Bishop static const gchar* dbus_name = "org.openbmc.control.Power";
1940a360c2SBrad Bishop 
200475f65fSYi Li static int g_pci_reset_held = 1;
210475f65fSYi Li 
2275a18a23SLei YU static GpioConfigs g_gpio_configs;
2340a360c2SBrad Bishop 
2440a360c2SBrad Bishop static GDBusObjectManagerServer *manager = NULL;
2540a360c2SBrad Bishop 
2640a360c2SBrad Bishop time_t pgood_timeout_start = 0;
2740a360c2SBrad Bishop 
2840a360c2SBrad Bishop // TODO:  Change to interrupt driven instead of polling
2940a360c2SBrad Bishop static gboolean
poll_pgood(gpointer user_data)3040a360c2SBrad Bishop poll_pgood(gpointer user_data)
3140a360c2SBrad Bishop {
3240a360c2SBrad Bishop 	ControlPower *control_power = object_get_control_power((Object*)user_data);
3340a360c2SBrad Bishop 	Control* control = object_get_control((Object*)user_data);
3440a360c2SBrad Bishop 
3540a360c2SBrad Bishop 	//send the heartbeat
3640a360c2SBrad Bishop 	guint poll_int = control_get_poll_interval(control);
3740a360c2SBrad Bishop 	if(poll_int == 0)
3840a360c2SBrad Bishop 	{
3920a19416SXo Wang 		g_print("ERROR PowerControl: Poll interval cannot be 0\n");
4040a360c2SBrad Bishop 		return FALSE;
4140a360c2SBrad Bishop 	}
4240a360c2SBrad Bishop 	//handle timeout
4340a360c2SBrad Bishop 	time_t current_time = time(NULL);
4440a360c2SBrad Bishop 	if(difftime(current_time,pgood_timeout_start) > control_power_get_pgood_timeout(control_power)
4540a360c2SBrad Bishop 			&& pgood_timeout_start != 0)
4640a360c2SBrad Bishop 	{
4720a19416SXo Wang 		g_print("ERROR PowerControl: Pgood poll timeout\n");
4840a360c2SBrad Bishop 		// set timeout to 0 so timeout doesn't happen again
4940a360c2SBrad Bishop 		control_power_set_pgood_timeout(control_power,0);
5040a360c2SBrad Bishop 		pgood_timeout_start = 0;
5127eaf901SPatrick Williams 		return TRUE;
5240a360c2SBrad Bishop 	}
5320a19416SXo Wang 	uint8_t pgood_state;
5440a360c2SBrad Bishop 
55c0c74e7cSAnthony Wilson 	int rc = gpio_open(&g_gpio_configs.power_gpio.power_good_in, 0);
5620a19416SXo Wang 	if(rc != GPIO_OK) {
57c0c74e7cSAnthony Wilson 		gpio_close(&g_gpio_configs.power_gpio.power_good_in);
5820a19416SXo Wang 		g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n",
5975a18a23SLei YU 				g_gpio_configs.power_gpio.power_good_in.name, rc);
6020a19416SXo Wang 		return FALSE;
6120a19416SXo Wang 	}
6275a18a23SLei YU 	rc = gpio_read(&g_gpio_configs.power_gpio.power_good_in, &pgood_state);
6375a18a23SLei YU 	gpio_close(&g_gpio_configs.power_gpio.power_good_in);
6440a360c2SBrad Bishop 	if(rc == GPIO_OK)
6540a360c2SBrad Bishop 	{
6640a360c2SBrad Bishop 		//if changed, set property and emit signal
6720a19416SXo Wang 		if(pgood_state != control_power_get_pgood(control_power))
6840a360c2SBrad Bishop 		{
69*600ff330SPatrick Williams 			size_t i;
7020a19416SXo Wang 			uint8_t reset_state;
7120a19416SXo Wang 			control_power_set_pgood(control_power, pgood_state);
7220a19416SXo Wang 			if(pgood_state == 0)
7340a360c2SBrad Bishop 			{
7440a360c2SBrad Bishop 				control_power_emit_power_lost(control_power);
750475f65fSYi Li 				g_pci_reset_held = 1;
7640a360c2SBrad Bishop 			}
7740a360c2SBrad Bishop 			else
7840a360c2SBrad Bishop 			{
7940a360c2SBrad Bishop 				control_power_emit_power_good(control_power);
8020a19416SXo Wang 			}
8140a360c2SBrad Bishop 
8275a18a23SLei YU 			for(i = 0; i < g_gpio_configs.power_gpio.num_reset_outs; i++)
8320a19416SXo Wang 			{
8475a18a23SLei YU 				GPIO *reset_out = &g_gpio_configs.power_gpio.reset_outs[i];
85c0c74e7cSAnthony Wilson 				reset_state = pgood_state ^ g_gpio_configs.power_gpio.reset_pols[i];
86c0c74e7cSAnthony Wilson 				rc = gpio_open(reset_out, reset_state);
8720a19416SXo Wang 				if(rc != GPIO_OK)
8820a19416SXo Wang 				{
89c0c74e7cSAnthony Wilson 					gpio_close(reset_out);
9020a19416SXo Wang 					g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n",
9120a19416SXo Wang 							reset_out->name, rc);
9220a19416SXo Wang 					continue;
9320a19416SXo Wang 				}
9420a19416SXo Wang 
9539df4035SYi Li 				g_print("PowerControl: pgood: %d, setting reset %s to %d\n",
9639df4035SYi Li 						(int)pgood_state, reset_out->name, (int)reset_state);
9720a19416SXo Wang 				gpio_write(reset_out, reset_state);
9820a19416SXo Wang 				gpio_close(reset_out);
9940a360c2SBrad Bishop 			}
1000475f65fSYi Li 
10175a18a23SLei YU 			for(i = 0; i < g_gpio_configs.power_gpio.num_pci_reset_outs; i++)
1020475f65fSYi Li 			{
10375a18a23SLei YU 				GPIO *pci_reset_out = &g_gpio_configs.power_gpio.pci_reset_outs[i];
1040475f65fSYi Li 				if(pgood_state == 1)
1050475f65fSYi Li 				{
1060475f65fSYi Li 					/*
1070475f65fSYi Li 					 * When powering on, hold PCI reset until
1080475f65fSYi Li 					 * the processor can forward clocks and control reset.
1090475f65fSYi Li 					 */
11075a18a23SLei YU 					if(g_gpio_configs.power_gpio.pci_reset_holds[i])
1110475f65fSYi Li 					{
1120475f65fSYi Li 						g_print("Holding pci reset: %s\n", pci_reset_out->name);
1130475f65fSYi Li 						continue;
1140475f65fSYi Li 					}
1150475f65fSYi Li 				}
116c0c74e7cSAnthony Wilson 				reset_state = pgood_state ^ g_gpio_configs.power_gpio.pci_reset_pols[i];
117c0c74e7cSAnthony Wilson 				rc = gpio_open(pci_reset_out, reset_state);
1180475f65fSYi Li 				if(rc != GPIO_OK)
1190475f65fSYi Li 				{
120c0c74e7cSAnthony Wilson 					gpio_close(pci_reset_out);
1210475f65fSYi Li 					g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n",
1220475f65fSYi Li 							pci_reset_out->name, rc);
1230475f65fSYi Li 					continue;
1240475f65fSYi Li 				}
1250475f65fSYi Li 
12639df4035SYi Li 				g_print("PowerControl: pgood: %d, setting pci reset %s to %d\n",
12739df4035SYi Li 						(int)pgood_state, pci_reset_out->name, (int)reset_state);
1280475f65fSYi Li 				gpio_write(pci_reset_out, reset_state);
1290475f65fSYi Li 				gpio_close(pci_reset_out);
1300475f65fSYi Li 			}
13140a360c2SBrad Bishop 		}
13240a360c2SBrad Bishop 	} else {
13320a19416SXo Wang 		g_print("ERROR PowerControl: GPIO read error (gpio=%s,rc=%d)\n",
13475a18a23SLei YU 				g_gpio_configs.power_gpio.power_good_in.name, rc);
13540a360c2SBrad Bishop 		//return false so poll won't get called anymore
13640a360c2SBrad Bishop 		return FALSE;
13740a360c2SBrad Bishop 	}
13840a360c2SBrad Bishop 	//pgood is not at desired state yet
13920a19416SXo Wang 	if(pgood_state != control_power_get_state(control_power) &&
14040a360c2SBrad Bishop 			control_power_get_pgood_timeout(control_power) > 0)
14140a360c2SBrad Bishop 	{
14240a360c2SBrad Bishop 		if(pgood_timeout_start == 0 ) {
14340a360c2SBrad Bishop 			pgood_timeout_start = current_time;
14440a360c2SBrad Bishop 		}
14540a360c2SBrad Bishop 	}
14640a360c2SBrad Bishop 	else
14740a360c2SBrad Bishop 	{
14840a360c2SBrad Bishop 		pgood_timeout_start = 0;
14940a360c2SBrad Bishop 	}
15040a360c2SBrad Bishop 	return TRUE;
15140a360c2SBrad Bishop }
15240a360c2SBrad Bishop 
1530475f65fSYi Li /* Handler for BootProgress signal from BootProgress sensor */
1540475f65fSYi Li static void
on_boot_progress(GDBusConnection * connection,const gchar * sender_name,const gchar * object_path,const gchar * interface_name,const gchar * signal_name,GVariant * parameters,gpointer user_data)1550475f65fSYi Li on_boot_progress(GDBusConnection *connection,
1560475f65fSYi Li 		const gchar *sender_name,
1570475f65fSYi Li 		const gchar *object_path,
1580475f65fSYi Li 		const gchar *interface_name,
1590475f65fSYi Li 		const gchar *signal_name,
1600475f65fSYi Li 		GVariant *parameters,
1610475f65fSYi Li 		gpointer user_data)
1620475f65fSYi Li {
163*600ff330SPatrick Williams 	(void) connection;
164*600ff330SPatrick Williams 	(void) sender_name;
165*600ff330SPatrick Williams 	(void) object_path;
166*600ff330SPatrick Williams 	(void) interface_name;
167*600ff330SPatrick Williams 	(void) signal_name;
168*600ff330SPatrick Williams 	(void) user_data;
169*600ff330SPatrick Williams 
17093b84e42SLei YU 	gchar *interface;
17193b84e42SLei YU 	GVariantIter *properties;
17293b84e42SLei YU 	GVariantIter *dummy;
17393b84e42SLei YU 	gchar *boot_progress = NULL;
17493b84e42SLei YU 	gchar *property;
17593b84e42SLei YU 	GVariant *value;
1760475f65fSYi Li 	uint8_t pgood_state;
1770475f65fSYi Li 	uint8_t reset_state;
1780475f65fSYi Li 	int rc;
179*600ff330SPatrick Williams 	size_t i;
18093b84e42SLei YU 	int ignore;
1810475f65fSYi Li 
1820475f65fSYi Li 	if(!parameters)
1830475f65fSYi Li 		return;
1840475f65fSYi Li 
1850475f65fSYi Li 	/* prevent release again */
1860475f65fSYi Li 	if(!g_pci_reset_held)
1870475f65fSYi Li 		return;
1880475f65fSYi Li 
18993b84e42SLei YU 	g_variant_get(parameters, "(&sa{sv}as)", &interface, &properties, &dummy);
19093b84e42SLei YU 	for(i = 0; g_variant_iter_next(properties, "{&sv}", &property, &value); i++)
19193b84e42SLei YU 	{
19293b84e42SLei YU 		if (strcmp(property, "BootProgress") == 0)
19393b84e42SLei YU 		{
19493b84e42SLei YU 			gchar* tmp;
19593b84e42SLei YU 			g_variant_get(value, "&s", &tmp);
19693b84e42SLei YU 			boot_progress = g_strdup(tmp);
19793b84e42SLei YU 			g_print("BootProgress: %s\n", boot_progress);
19893b84e42SLei YU 			g_variant_unref(value);
19993b84e42SLei YU 		}
20093b84e42SLei YU 	}
20193b84e42SLei YU 
20293b84e42SLei YU 	g_variant_iter_free(properties);
20393b84e42SLei YU 	g_variant_iter_free(dummy);
20493b84e42SLei YU 	if (boot_progress == NULL)
20593b84e42SLei YU 		return;
20693b84e42SLei YU 
2070475f65fSYi Li 	/* Release PCI reset when FW boot progress goes beyond 'Baseboard Init' */
20893b84e42SLei YU 	ignore = strcmp(boot_progress,
20993b84e42SLei YU 		"xyz.openbmc_project.State.Boot.Progress.ProgressStages.MotherboardInit") == 0;
21093b84e42SLei YU 	g_free(boot_progress);
21193b84e42SLei YU 
21293b84e42SLei YU 	if (ignore)
2130475f65fSYi Li 		return;
2140475f65fSYi Li 
215c0c74e7cSAnthony Wilson 	rc = gpio_open(&g_gpio_configs.power_gpio.power_good_in, 0);
2160475f65fSYi Li 	if(rc != GPIO_OK)
2170475f65fSYi Li 	{
218c0c74e7cSAnthony Wilson 		gpio_close(&g_gpio_configs.power_gpio.power_good_in);
2190475f65fSYi Li 		g_print("ERROR PowerControl: on_boot_progress(): GPIO open error (gpio=%s,rc=%d)\n",
22075a18a23SLei YU 			g_gpio_configs.power_gpio.power_good_in.name, rc);
2210475f65fSYi Li 		return;
2220475f65fSYi Li 	}
22375a18a23SLei YU 	rc = gpio_read(&g_gpio_configs.power_gpio.power_good_in, &pgood_state);
22475a18a23SLei YU 	gpio_close(&g_gpio_configs.power_gpio.power_good_in);
2250475f65fSYi Li 	if(rc != GPIO_OK || pgood_state != 1)
2260475f65fSYi Li 		return;
2270475f65fSYi Li 
22875a18a23SLei YU 	for(i = 0; i < g_gpio_configs.power_gpio.num_pci_reset_outs; i++)
2290475f65fSYi Li 	{
23075a18a23SLei YU 		GPIO *pci_reset_out = &g_gpio_configs.power_gpio.pci_reset_outs[i];
2310475f65fSYi Li 
23275a18a23SLei YU 		if(!g_gpio_configs.power_gpio.pci_reset_holds[i])
2330475f65fSYi Li 			continue;
234c0c74e7cSAnthony Wilson 		reset_state = pgood_state ^ g_gpio_configs.power_gpio.pci_reset_pols[i];
235c0c74e7cSAnthony Wilson 		rc = gpio_open(pci_reset_out, reset_state);
2360475f65fSYi Li 		if(rc != GPIO_OK)
2370475f65fSYi Li 		{
238c0c74e7cSAnthony Wilson 			gpio_close(pci_reset_out);
2390475f65fSYi Li 			g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n",
2400475f65fSYi Li 					pci_reset_out->name, rc);
2410475f65fSYi Li 			continue;
2420475f65fSYi Li 		}
2430475f65fSYi Li 
24439df4035SYi Li 		g_print("PowerControl: pgood: %d, setting pci reset %s to %d\n",
24539df4035SYi Li 				(int)pgood_state, pci_reset_out->name, (int)reset_state);
2460475f65fSYi Li 		gpio_write(pci_reset_out, reset_state);
2470475f65fSYi Li 		gpio_close(pci_reset_out);
24893b84e42SLei YU 		g_print("Released pci reset: %s\n", pci_reset_out->name);
2490475f65fSYi Li 	}
2500475f65fSYi Li 	g_pci_reset_held = 0;
2510475f65fSYi Li }
2520475f65fSYi Li 
25340a360c2SBrad Bishop static gboolean
on_set_power_state(ControlPower * pwr,GDBusMethodInvocation * invocation,guint state,gpointer user_data)25440a360c2SBrad Bishop on_set_power_state(ControlPower *pwr,
25540a360c2SBrad Bishop 		GDBusMethodInvocation *invocation,
25640a360c2SBrad Bishop 		guint state,
25740a360c2SBrad Bishop 		gpointer user_data)
25840a360c2SBrad Bishop {
259*600ff330SPatrick Williams 	(void) user_data;
260aa6c76fcSXo Wang 	PowerGpio *power_gpio = &g_gpio_configs.power_gpio;
26140a360c2SBrad Bishop 	if(state > 1)
26240a360c2SBrad Bishop 	{
26340a360c2SBrad Bishop 		g_dbus_method_invocation_return_dbus_error(invocation,
26440a360c2SBrad Bishop 				"org.openbmc.ControlPower.Error.Failed",
26540a360c2SBrad Bishop 				"Invalid power state");
26640a360c2SBrad Bishop 		return TRUE;
26740a360c2SBrad Bishop 	}
26840a360c2SBrad Bishop 	// return from method call
26940a360c2SBrad Bishop 	control_power_complete_set_power_state(pwr,invocation);
270*600ff330SPatrick Williams 	if(state == (guint) control_power_get_state(pwr))
27140a360c2SBrad Bishop 	{
27240a360c2SBrad Bishop 		g_print("Power already at requested state: %d\n",state);
27340a360c2SBrad Bishop 	}
27440a360c2SBrad Bishop 	else
27540a360c2SBrad Bishop 	{
27640a360c2SBrad Bishop 		int error = 0;
27740a360c2SBrad Bishop 		do {
278*600ff330SPatrick Williams 			size_t i;
27920a19416SXo Wang 			uint8_t power_up_out;
280aa6c76fcSXo Wang 			for (i = 0; i < power_gpio->num_power_up_outs; i++) {
281aa6c76fcSXo Wang 				GPIO *power_pin = &power_gpio->power_up_outs[i];
282c0c74e7cSAnthony Wilson 				power_up_out = state ^ !power_gpio->power_up_pols[i];
283c0c74e7cSAnthony Wilson 				error = gpio_open(power_pin, power_up_out);
28420a19416SXo Wang 				if(error != GPIO_OK) {
285c0c74e7cSAnthony Wilson 					gpio_close(power_pin);
28620a19416SXo Wang 					g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n",
287aa6c76fcSXo Wang 							power_gpio->power_up_outs[i].name, error);
28820a19416SXo Wang 					continue;
28920a19416SXo Wang 				}
29020a19416SXo Wang 				g_print("PowerControl: setting power up %s to %d\n",
291aa6c76fcSXo Wang 						power_gpio->power_up_outs[i].name, (int)power_up_out);
29220a19416SXo Wang 				error = gpio_write(power_pin, power_up_out);
29320a19416SXo Wang 				if(error != GPIO_OK) {
294c0c74e7cSAnthony Wilson 					gpio_close(power_pin);
29520a19416SXo Wang 					continue;
29620a19416SXo Wang 				}
29720a19416SXo Wang 				gpio_close(power_pin);
29820a19416SXo Wang 			}
29940a360c2SBrad Bishop 			if(error != GPIO_OK) { break;	}
30040a360c2SBrad Bishop 			control_power_set_state(pwr,state);
30140a360c2SBrad Bishop 		} while(0);
30240a360c2SBrad Bishop 		if(error != GPIO_OK)
30340a360c2SBrad Bishop 		{
30420a19416SXo Wang 			g_print("ERROR PowerControl: GPIO set power state (rc=%d)\n",error);
30540a360c2SBrad Bishop 		}
306aa6c76fcSXo Wang 
307aa6c76fcSXo Wang 		/* If there's a latch, it should be enabled following changes to the
308aa6c76fcSXo Wang 		 * power pins' states. This commits the changes to the latch states. */
309aa6c76fcSXo Wang 		if (power_gpio->latch_out.name != NULL) {
310aa6c76fcSXo Wang 			int rc;
311c0c74e7cSAnthony Wilson 			uint8_t latch_value = 1;
312c0c74e7cSAnthony Wilson 			rc = gpio_open(&power_gpio->latch_out, latch_value);
313aa6c76fcSXo Wang 			if (rc != GPIO_OK) {
314aa6c76fcSXo Wang 				/* Failures are non-fatal. */
315c0c74e7cSAnthony Wilson 				gpio_close(&power_gpio->latch_out);
316aa6c76fcSXo Wang 				g_print("PowerControl ERROR failed to open latch %s rc=%d\n",
317aa6c76fcSXo Wang 						power_gpio->latch_out.name, rc);
318aa6c76fcSXo Wang 				return TRUE;
31940a360c2SBrad Bishop 			}
320aa6c76fcSXo Wang 			/* Make the latch transparent for as brief of a time as possible. */
321c0c74e7cSAnthony Wilson 			rc = gpio_write(&power_gpio->latch_out, latch_value--);
322aa6c76fcSXo Wang 			if (rc != GPIO_OK) {
323aa6c76fcSXo Wang 				g_print("PowerControl ERROR failed to assert latch %s rc=%d\n",
324aa6c76fcSXo Wang 						power_gpio->latch_out.name, rc);
325aa6c76fcSXo Wang 			} else {
326aa6c76fcSXo Wang 				g_print("PowerControl asserted latch %s\n",
327aa6c76fcSXo Wang 						power_gpio->latch_out.name);
328aa6c76fcSXo Wang 			}
329c0c74e7cSAnthony Wilson 			rc = gpio_write(&power_gpio->latch_out, latch_value);
330aa6c76fcSXo Wang 			if (rc != GPIO_OK) {
331aa6c76fcSXo Wang 				g_print("PowerControl ERROR failed to clear latch %s rc=%d\n",
332aa6c76fcSXo Wang 						power_gpio->latch_out.name, rc);
333aa6c76fcSXo Wang 			}
334aa6c76fcSXo Wang 			gpio_close(&power_gpio->latch_out);
335aa6c76fcSXo Wang 		}
336aa6c76fcSXo Wang 	}
337aa6c76fcSXo Wang 
33840a360c2SBrad Bishop 	return TRUE;
33940a360c2SBrad Bishop }
34040a360c2SBrad Bishop 
34140a360c2SBrad Bishop static gboolean
on_init(Control * control,GDBusMethodInvocation * invocation,gpointer user_data)34240a360c2SBrad Bishop on_init(Control *control,
34340a360c2SBrad Bishop 		GDBusMethodInvocation *invocation,
34440a360c2SBrad Bishop 		gpointer user_data)
34540a360c2SBrad Bishop {
346*600ff330SPatrick Williams 	(void) user_data;
34740a360c2SBrad Bishop 	pgood_timeout_start = 0;
34840a360c2SBrad Bishop 	//guint poll_interval = control_get_poll_interval(control);
34940a360c2SBrad Bishop 	//g_timeout_add(poll_interval, poll_pgood, user_data);
35040a360c2SBrad Bishop 	control_complete_init(control,invocation);
35140a360c2SBrad Bishop 	return TRUE;
35240a360c2SBrad Bishop }
35340a360c2SBrad Bishop 
35440a360c2SBrad Bishop static gboolean
on_get_power_state(ControlPower * pwr,GDBusMethodInvocation * invocation,gpointer user_data)35540a360c2SBrad Bishop on_get_power_state(ControlPower *pwr,
35640a360c2SBrad Bishop 		GDBusMethodInvocation *invocation,
35740a360c2SBrad Bishop 		gpointer user_data)
35840a360c2SBrad Bishop {
359*600ff330SPatrick Williams 	(void) user_data;
36040a360c2SBrad Bishop 	guint pgood = control_power_get_pgood(pwr);
36140a360c2SBrad Bishop 	control_power_complete_get_power_state(pwr,invocation,pgood);
36240a360c2SBrad Bishop 	return TRUE;
36340a360c2SBrad Bishop }
36440a360c2SBrad Bishop 
36520a19416SXo Wang static int
set_up_gpio(PowerGpio * power_gpio,ControlPower * control_power)3660f3fd5aaSMatt Spinler set_up_gpio(PowerGpio *power_gpio, ControlPower* control_power)
36720a19416SXo Wang {
36820a19416SXo Wang 	int error = GPIO_OK;
36920a19416SXo Wang 	int rc;
370*600ff330SPatrick Williams 	size_t i;
37120a19416SXo Wang 	uint8_t pgood_state;
37220a19416SXo Wang 
37320a19416SXo Wang 	// get gpio device paths
374c1ce68b3SXo Wang 	if(power_gpio->latch_out.name != NULL) {  /* latch is optional */
375c0c74e7cSAnthony Wilson 		rc = gpio_get_params(&power_gpio->latch_out);
376c1ce68b3SXo Wang 		if(rc != GPIO_OK) {
377c1ce68b3SXo Wang 			error = rc;
378c1ce68b3SXo Wang 		}
379c1ce68b3SXo Wang 	}
380c0c74e7cSAnthony Wilson 	rc = gpio_get_params(&power_gpio->power_good_in);
38120a19416SXo Wang 	if(rc != GPIO_OK) {
38220a19416SXo Wang 		error = rc;
38320a19416SXo Wang 	}
384*600ff330SPatrick Williams 	for(i = 0; i < power_gpio->num_power_up_outs; i++) {
385c0c74e7cSAnthony Wilson 		rc = gpio_get_params(&power_gpio->power_up_outs[i]);
38620a19416SXo Wang 		if(rc != GPIO_OK) {
38720a19416SXo Wang 			error = rc;
38820a19416SXo Wang 		}
38920a19416SXo Wang 	}
390*600ff330SPatrick Williams 	for(i = 0; i < power_gpio->num_reset_outs; i++) {
391c0c74e7cSAnthony Wilson 		rc = gpio_get_params(&power_gpio->reset_outs[i]);
39220a19416SXo Wang 		if(rc != GPIO_OK) {
39320a19416SXo Wang 			error = rc;
39420a19416SXo Wang 		}
39520a19416SXo Wang 	}
396*600ff330SPatrick Williams 	for(i = 0; i < power_gpio->num_pci_reset_outs; i++) {
397c0c74e7cSAnthony Wilson 		rc = gpio_get_params(&power_gpio->pci_reset_outs[i]);
3980475f65fSYi Li 		if(rc != GPIO_OK) {
3990475f65fSYi Li 			error = rc;
4000475f65fSYi Li 		}
4010475f65fSYi Li 	}
40220a19416SXo Wang 
4030f0946beSMatt Spinler 	gpio_inits_done();
4040f0946beSMatt Spinler 
405c0c74e7cSAnthony Wilson 	rc = gpio_open(&power_gpio->power_good_in, 0);
40620a19416SXo Wang 	if(rc != GPIO_OK) {
407c0c74e7cSAnthony Wilson 		gpio_close(&power_gpio->power_good_in);
40820a19416SXo Wang 		return rc;
40920a19416SXo Wang 	}
41020a19416SXo Wang 	rc = gpio_read(&power_gpio->power_good_in, &pgood_state);
41120a19416SXo Wang 	if(rc != GPIO_OK) {
412c0c74e7cSAnthony Wilson 		gpio_close(&power_gpio->power_good_in);
41320a19416SXo Wang 		return rc;
41420a19416SXo Wang 	}
41520a19416SXo Wang 	gpio_close(&power_gpio->power_good_in);
41620a19416SXo Wang 	control_power_set_pgood(control_power, pgood_state);
41720a19416SXo Wang 	control_power_set_state(control_power, pgood_state);
41820a19416SXo Wang 	g_print("Pgood state: %d\n", pgood_state);
41920a19416SXo Wang 
42020a19416SXo Wang 	return error;
42120a19416SXo Wang }
42220a19416SXo Wang 
42340a360c2SBrad Bishop static void
on_bus_acquired(GDBusConnection * connection,const gchar * name,gpointer user_data)42440a360c2SBrad Bishop on_bus_acquired(GDBusConnection *connection,
42540a360c2SBrad Bishop 		const gchar *name,
42640a360c2SBrad Bishop 		gpointer user_data)
42740a360c2SBrad Bishop {
428*600ff330SPatrick Williams 	(void) name;
42940a360c2SBrad Bishop 	ObjectSkeleton *object;
43040a360c2SBrad Bishop 	cmdline *cmd = user_data;
43140a360c2SBrad Bishop 	if(cmd->argc < 3)
43240a360c2SBrad Bishop 	{
43340a360c2SBrad Bishop 		g_print("Usage: power_control.exe [poll interval] [timeout]\n");
43440a360c2SBrad Bishop 		return;
43540a360c2SBrad Bishop 	}
43640a360c2SBrad Bishop 	manager = g_dbus_object_manager_server_new(dbus_object_path);
43740a360c2SBrad Bishop 	gchar *s;
43840a360c2SBrad Bishop 	s = g_strdup_printf("%s/%s",dbus_object_path,instance_name);
43940a360c2SBrad Bishop 	object = object_skeleton_new(s);
44040a360c2SBrad Bishop 	g_free(s);
44140a360c2SBrad Bishop 
44240a360c2SBrad Bishop 	ControlPower* control_power = control_power_skeleton_new();
44340a360c2SBrad Bishop 	object_skeleton_set_control_power(object, control_power);
44440a360c2SBrad Bishop 	g_object_unref(control_power);
44540a360c2SBrad Bishop 
44640a360c2SBrad Bishop 	Control* control = control_skeleton_new();
44740a360c2SBrad Bishop 	object_skeleton_set_control(object, control);
44840a360c2SBrad Bishop 	g_object_unref(control);
44940a360c2SBrad Bishop 
45040a360c2SBrad Bishop 	//define method callbacks here
45140a360c2SBrad Bishop 	g_signal_connect(control_power,
45240a360c2SBrad Bishop 			"handle-set-power-state",
45340a360c2SBrad Bishop 			G_CALLBACK(on_set_power_state),
45440a360c2SBrad Bishop 			object); /* user_data */
45540a360c2SBrad Bishop 
45640a360c2SBrad Bishop 	g_signal_connect(control_power,
45740a360c2SBrad Bishop 			"handle-get-power-state",
45840a360c2SBrad Bishop 			G_CALLBACK(on_get_power_state),
45940a360c2SBrad Bishop 			NULL); /* user_data */
46040a360c2SBrad Bishop 
46140a360c2SBrad Bishop 	g_signal_connect(control,
46240a360c2SBrad Bishop 			"handle-init",
46340a360c2SBrad Bishop 			G_CALLBACK(on_init),
46440a360c2SBrad Bishop 			object); /* user_data */
46540a360c2SBrad Bishop 
4660475f65fSYi Li 	/* Listen for BootProgress signal from BootProgress sensor */
4670475f65fSYi Li 	g_dbus_connection_signal_subscribe(connection,
4680475f65fSYi Li 			NULL, /* service */
46993b84e42SLei YU 			"org.freedesktop.DBus.Properties", /* interface_name */
47093b84e42SLei YU 			"PropertiesChanged", /* member: name of the signal */
47193b84e42SLei YU 			"/xyz/openbmc_project/state/host0", /* obj path */
4720475f65fSYi Li 			NULL, /* arg0 */
4730475f65fSYi Li 			G_DBUS_SIGNAL_FLAGS_NONE,
4740475f65fSYi Li 			(GDBusSignalCallback) on_boot_progress,
4750475f65fSYi Li 			object, /* user data */
4760475f65fSYi Li 			NULL );
47740a360c2SBrad Bishop 
47840a360c2SBrad Bishop 	/* Export the object (@manager takes its own reference to @object) */
47940a360c2SBrad Bishop 	g_dbus_object_manager_server_set_connection(manager, connection);
48040a360c2SBrad Bishop 	g_dbus_object_manager_server_export(manager, G_DBUS_OBJECT_SKELETON(object));
48140a360c2SBrad Bishop 	g_object_unref(object);
48240a360c2SBrad Bishop 
4830f3fd5aaSMatt Spinler 	if(read_gpios(&g_gpio_configs) != TRUE) {
48420a19416SXo Wang 		g_print("ERROR PowerControl: could not read power GPIO configuration\n");
4851acfd753SYong Li 		exit(-1);
48620a19416SXo Wang 	}
48740a360c2SBrad Bishop 
4880f3fd5aaSMatt Spinler 	int rc = set_up_gpio(&g_gpio_configs.power_gpio, control_power);
48920a19416SXo Wang 	if(rc != GPIO_OK) {
49020a19416SXo Wang 		g_print("ERROR PowerControl: GPIO setup (rc=%d)\n",rc);
4911acfd753SYong Li 		exit(-1);
49240a360c2SBrad Bishop 	}
49340a360c2SBrad Bishop 	//start poll
49440a360c2SBrad Bishop 	pgood_timeout_start = 0;
49540a360c2SBrad Bishop 	int poll_interval = atoi(cmd->argv[1]);
49640a360c2SBrad Bishop 	int pgood_timeout = atoi(cmd->argv[2]);
49789e6c918SMatt Spinler 	if(poll_interval < 500 || pgood_timeout <5) {
49889e6c918SMatt Spinler 		g_print("ERROR PowerControl: poll_interval < 500 or pgood_timeout < 5\n");
4991acfd753SYong Li 		exit(-1);
50040a360c2SBrad Bishop 	} else {
50140a360c2SBrad Bishop 		control_set_poll_interval(control,poll_interval);
50240a360c2SBrad Bishop 		control_power_set_pgood_timeout(control_power,pgood_timeout);
50340a360c2SBrad Bishop 		g_timeout_add(poll_interval, poll_pgood, object);
50440a360c2SBrad Bishop 	}
50540a360c2SBrad Bishop }
50640a360c2SBrad Bishop 
50740a360c2SBrad Bishop static void
on_name_acquired(GDBusConnection * connection,const gchar * name,gpointer user_data)50840a360c2SBrad Bishop on_name_acquired(GDBusConnection *connection,
50940a360c2SBrad Bishop 		const gchar *name,
51040a360c2SBrad Bishop 		gpointer user_data)
51140a360c2SBrad Bishop {
512*600ff330SPatrick Williams 	(void) connection;
513*600ff330SPatrick Williams 	(void) name;
514*600ff330SPatrick Williams 	(void) user_data;
51540a360c2SBrad Bishop }
51640a360c2SBrad Bishop 
51740a360c2SBrad Bishop static void
on_name_lost(GDBusConnection * connection,const gchar * name,gpointer user_data)51840a360c2SBrad Bishop on_name_lost(GDBusConnection *connection,
51940a360c2SBrad Bishop 		const gchar *name,
52040a360c2SBrad Bishop 		gpointer user_data)
52140a360c2SBrad Bishop {
522*600ff330SPatrick Williams 	(void) connection;
523*600ff330SPatrick Williams 	(void) name;
524*600ff330SPatrick Williams 	(void) user_data;
52575a18a23SLei YU 	free_gpios(&g_gpio_configs);
52640a360c2SBrad Bishop }
52740a360c2SBrad Bishop 
52840a360c2SBrad Bishop /*----------------------------------------------------------------*/
52940a360c2SBrad Bishop /* Main Event Loop                                                */
53040a360c2SBrad Bishop 
53140a360c2SBrad Bishop gint
main(gint argc,gchar * argv[])53240a360c2SBrad Bishop main(gint argc, gchar *argv[])
53340a360c2SBrad Bishop {
53440a360c2SBrad Bishop 	GMainLoop *loop;
53540a360c2SBrad Bishop 	cmdline cmd;
53640a360c2SBrad Bishop 	cmd.argc = argc;
53740a360c2SBrad Bishop 	cmd.argv = argv;
53840a360c2SBrad Bishop 
53940a360c2SBrad Bishop 	guint id;
54040a360c2SBrad Bishop 	loop = g_main_loop_new(NULL, FALSE);
54140a360c2SBrad Bishop 
54240a360c2SBrad Bishop 	id = g_bus_own_name(DBUS_TYPE,
54340a360c2SBrad Bishop 			dbus_name,
54440a360c2SBrad Bishop 			G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
54540a360c2SBrad Bishop 			G_BUS_NAME_OWNER_FLAGS_REPLACE,
54640a360c2SBrad Bishop 			on_bus_acquired,
54740a360c2SBrad Bishop 			on_name_acquired,
54840a360c2SBrad Bishop 			on_name_lost,
54940a360c2SBrad Bishop 			&cmd,
55040a360c2SBrad Bishop 			NULL);
55140a360c2SBrad Bishop 
55240a360c2SBrad Bishop 	g_main_loop_run(loop);
55340a360c2SBrad Bishop 
55440a360c2SBrad Bishop 	g_bus_unown_name(id);
55540a360c2SBrad Bishop 	g_main_loop_unref(loop);
55640a360c2SBrad Bishop 	return 0;
55740a360c2SBrad Bishop }
558