140a360c2SBrad Bishop #include <stdio.h>
240a360c2SBrad Bishop #include <stdlib.h>
340a360c2SBrad Bishop #include <string.h>
440a360c2SBrad Bishop #include <fcntl.h>
540a360c2SBrad Bishop #include <unistd.h>
640a360c2SBrad Bishop #include <sys/stat.h>
740a360c2SBrad Bishop #include <sys/mman.h>
8f6c85685SBrad Bishop #include <openbmc_intf.h>
9f6c85685SBrad Bishop #include <openbmc.h>
10f6c85685SBrad Bishop #include <gpio.h>
11*75a18a23SLei YU #include <power_gpio.h>
1240a360c2SBrad Bishop 
1340a360c2SBrad Bishop /* ------------------------------------------------------------------------- */
1440a360c2SBrad Bishop static const gchar* dbus_object_path = "/org/openbmc/control";
1540a360c2SBrad Bishop static const gchar* instance_name = "host0";
1640a360c2SBrad Bishop static const gchar* dbus_name = "org.openbmc.control.Host";
1740a360c2SBrad Bishop 
18*75a18a23SLei YU static GpioConfigs g_gpio_configs;
19*75a18a23SLei YU 
2040a360c2SBrad Bishop static GDBusObjectManagerServer *manager = NULL;
2140a360c2SBrad Bishop 
22*75a18a23SLei YU static GPIO* fsi_data;
23*75a18a23SLei YU static GPIO* fsi_clk;
24*75a18a23SLei YU static GPIO* fsi_enable;
25*75a18a23SLei YU static GPIO* cronus_sel;
26*75a18a23SLei YU static size_t num_optionals;
27*75a18a23SLei YU static GPIO* optionals;
28*75a18a23SLei YU static gboolean* optional_pols;
2940a360c2SBrad Bishop 
3040a360c2SBrad Bishop /* Bit bang patterns */
3140a360c2SBrad Bishop 
3240a360c2SBrad Bishop //putcfam pu 281c 30000000 -p0 (Primary Side Select)
3340a360c2SBrad Bishop static const char* primary = "000011111111110101111000111001100111111111111111111111111111101111111111";
3440a360c2SBrad Bishop //putcfam pu 281c B0000000 -p0
3540a360c2SBrad Bishop static const char* go = "000011111111110101111000111000100111111111111111111111111111101101111111";
3640a360c2SBrad Bishop //putcfam pu 0x281c 30900000 (Golden Side Select)
3740a360c2SBrad Bishop static const char* golden = "000011111111110101111000111001100111101101111111111111111111101001111111";
3840a360c2SBrad Bishop 
3940a360c2SBrad Bishop /* Setup attentions */
4040a360c2SBrad Bishop //putcfam pu 0x081C 20000000
4140a360c2SBrad Bishop static const char* attnA = "000011111111111101111110001001101111111111111111111111111111110001111111";
4240a360c2SBrad Bishop //putcfam pu 0x100D 40000000
4340a360c2SBrad Bishop static const char* attnB = "000011111111111011111100101001011111111111111111111111111111110001111111";
4440a360c2SBrad Bishop //putcfam pu 0x100B FFFFFFFF
4540a360c2SBrad Bishop static const char* attnC = "000011111111111011111101001000000000000000000000000000000000001011111111";
4640a360c2SBrad Bishop 
4740a360c2SBrad Bishop 
4840a360c2SBrad Bishop 
4940a360c2SBrad Bishop static gboolean
5040a360c2SBrad Bishop on_init(Control *control,
5140a360c2SBrad Bishop 		GDBusMethodInvocation *invocation,
5240a360c2SBrad Bishop 		gpointer user_data)
5340a360c2SBrad Bishop {
5440a360c2SBrad Bishop 	control_complete_init(control,invocation);
5540a360c2SBrad Bishop 	return TRUE;
5640a360c2SBrad Bishop }
5740a360c2SBrad Bishop 
5840a360c2SBrad Bishop int
5940a360c2SBrad Bishop fsi_bitbang(const char* pattern)
6040a360c2SBrad Bishop {
6140a360c2SBrad Bishop 	int rc=GPIO_OK;
6240a360c2SBrad Bishop 	int i;
6340a360c2SBrad Bishop 	for(i=0;i<strlen(pattern);i++) {
64*75a18a23SLei YU 		rc = gpio_writec(fsi_data,pattern[i]);
6540a360c2SBrad Bishop 		if(rc!=GPIO_OK) { break; }
66*75a18a23SLei YU 		rc = gpio_clock_cycle(fsi_clk,1);
6740a360c2SBrad Bishop 		if(rc!=GPIO_OK) { break; }
6840a360c2SBrad Bishop 	}
6940a360c2SBrad Bishop 	return rc;
7040a360c2SBrad Bishop }
7140a360c2SBrad Bishop 
7240a360c2SBrad Bishop int
7340a360c2SBrad Bishop fsi_standby()
7440a360c2SBrad Bishop {
7540a360c2SBrad Bishop 	int rc=GPIO_OK;
76*75a18a23SLei YU 	rc = gpio_write(fsi_data,1);
7740a360c2SBrad Bishop 	if(rc!=GPIO_OK) { return rc; }
78*75a18a23SLei YU 	rc = gpio_clock_cycle(fsi_clk,5000);
7940a360c2SBrad Bishop 	if(rc!=GPIO_OK) { return rc; }
8040a360c2SBrad Bishop 	return rc;
8140a360c2SBrad Bishop }
8240a360c2SBrad Bishop 
8340a360c2SBrad Bishop 
8440a360c2SBrad Bishop static gboolean
8540a360c2SBrad Bishop on_boot(ControlHost *host,
8640a360c2SBrad Bishop 		GDBusMethodInvocation *invocation,
8740a360c2SBrad Bishop 		gpointer user_data)
8840a360c2SBrad Bishop {
8940a360c2SBrad Bishop 	int rc = GPIO_OK;
9037846da5SAdriana Kobylak 	GDBusProxy *proxy;
9137846da5SAdriana Kobylak 	GError *error = NULL;
9237846da5SAdriana Kobylak 	GVariant *result = NULL;
9337846da5SAdriana Kobylak 	GDBusConnection *connection =
9437846da5SAdriana Kobylak 		g_dbus_object_manager_server_get_connection(manager);
9540a360c2SBrad Bishop 
96*75a18a23SLei YU 	if (!(fsi_data && fsi_clk && fsi_enable && cronus_sel)) {
97*75a18a23SLei YU 		g_print("ERROR invalid GPIO configuration, will not boot\n");
98*75a18a23SLei YU 		return FALSE;
99*75a18a23SLei YU 	}
100*75a18a23SLei YU 	if(control_host_get_debug_mode(host)==1) {
10140a360c2SBrad Bishop 		g_print("Enabling debug mode; not booting host\n");
102*75a18a23SLei YU 		rc |= gpio_open(fsi_enable);
103*75a18a23SLei YU 		rc |= gpio_open(cronus_sel);
104*75a18a23SLei YU 		rc |= gpio_write(fsi_enable,1);
105*75a18a23SLei YU 		rc |= gpio_write(cronus_sel,0);
10640a360c2SBrad Bishop 		if(rc!=GPIO_OK) {
10740a360c2SBrad Bishop 			g_print("ERROR enabling debug mode: %d\n",rc);
10840a360c2SBrad Bishop 		}
10940a360c2SBrad Bishop 		return TRUE;
11040a360c2SBrad Bishop 	}
11140a360c2SBrad Bishop 	g_print("Booting host\n");
11240a360c2SBrad Bishop 	Control* control = object_get_control((Object*)user_data);
11340a360c2SBrad Bishop 	control_host_complete_boot(host,invocation);
11440a360c2SBrad Bishop 	do {
115*75a18a23SLei YU 		rc = gpio_open(fsi_clk);
116*75a18a23SLei YU 		rc |= gpio_open(fsi_data);
117*75a18a23SLei YU 		rc |= gpio_open(fsi_enable);
118*75a18a23SLei YU 		rc |= gpio_open(cronus_sel);
119*75a18a23SLei YU 		for (size_t i = 0; i < num_optionals; ++i) {
120*75a18a23SLei YU 			rc |= gpio_open(&optionals[i]);
121*75a18a23SLei YU 		}
12240a360c2SBrad Bishop 		if(rc!=GPIO_OK) { break; }
12340a360c2SBrad Bishop 
12440a360c2SBrad Bishop 		//setup dc pins
125*75a18a23SLei YU 		rc = gpio_write(cronus_sel,1);
126*75a18a23SLei YU 		rc |= gpio_write(fsi_enable,1);
127*75a18a23SLei YU 		rc |= gpio_write(fsi_clk,1);
128*75a18a23SLei YU 		for (size_t i = 0; i < num_optionals; ++i) {
129*75a18a23SLei YU 			rc |= gpio_write(&optionals[i], optional_pols[i]);
130*75a18a23SLei YU 		}
13140a360c2SBrad Bishop 		if(rc!=GPIO_OK) { break; }
13240a360c2SBrad Bishop 
13340a360c2SBrad Bishop 		//data standy state
13440a360c2SBrad Bishop 		rc = fsi_standby();
13540a360c2SBrad Bishop 
13640a360c2SBrad Bishop 		//clear out pipes
137*75a18a23SLei YU 		rc |= gpio_write(fsi_data,0);
138*75a18a23SLei YU 		rc |= gpio_clock_cycle(fsi_clk,256);
139*75a18a23SLei YU 		rc |= gpio_write(fsi_data,1);
140*75a18a23SLei YU 		rc |= gpio_clock_cycle(fsi_clk,50);
14140a360c2SBrad Bishop 		if(rc!=GPIO_OK) { break; }
14240a360c2SBrad Bishop 
14340a360c2SBrad Bishop 		rc = fsi_bitbang(attnA);
14440a360c2SBrad Bishop 		rc |= fsi_standby();
14540a360c2SBrad Bishop 
14640a360c2SBrad Bishop 		rc |= fsi_bitbang(attnB);
14740a360c2SBrad Bishop 		rc |= fsi_standby();
14840a360c2SBrad Bishop 
14940a360c2SBrad Bishop 		rc |= fsi_bitbang(attnC);
15040a360c2SBrad Bishop 		rc |= fsi_standby();
15140a360c2SBrad Bishop 		if(rc!=GPIO_OK) { break; }
15240a360c2SBrad Bishop 
15340a360c2SBrad Bishop 		const gchar* flash_side = control_host_get_flash_side(host);
15440a360c2SBrad Bishop 		g_print("Using %s side of the bios flash\n",flash_side);
15540a360c2SBrad Bishop 		if(strcmp(flash_side,"primary")==0) {
15640a360c2SBrad Bishop 			rc |= fsi_bitbang(primary);
15740a360c2SBrad Bishop 		} else if(strcmp(flash_side,"golden") == 0) {
15840a360c2SBrad Bishop 			rc |= fsi_bitbang(golden);
15940a360c2SBrad Bishop 		} else {
16040a360c2SBrad Bishop 			g_print("ERROR: Invalid flash side: %s\n",flash_side);
16140a360c2SBrad Bishop 			rc = 0xff;
16240a360c2SBrad Bishop 
16340a360c2SBrad Bishop 		}
16440a360c2SBrad Bishop 		rc |= fsi_standby();
16540a360c2SBrad Bishop 		if(rc!=GPIO_OK) { break; }
16640a360c2SBrad Bishop 
16740a360c2SBrad Bishop 		rc = fsi_bitbang(go);
16840a360c2SBrad Bishop 
169*75a18a23SLei YU 		rc |= gpio_write(fsi_data,1); /* Data standby state */
170*75a18a23SLei YU 		rc |= gpio_clock_cycle(fsi_clk,2);
17140a360c2SBrad Bishop 
172*75a18a23SLei YU 		rc |= gpio_write(fsi_clk,0); /* hold clk low for clock mux */
173*75a18a23SLei YU 		rc |= gpio_write(fsi_enable,0);
174*75a18a23SLei YU 		rc |= gpio_clock_cycle(fsi_clk,16);
175*75a18a23SLei YU 		rc |= gpio_write(fsi_clk,0); /* Data standby state */
17640a360c2SBrad Bishop 
17740a360c2SBrad Bishop 	} while(0);
17840a360c2SBrad Bishop 	if(rc != GPIO_OK)
17940a360c2SBrad Bishop 	{
18040a360c2SBrad Bishop 		g_print("ERROR HostControl: GPIO sequence failed (rc=%d)\n",rc);
18140a360c2SBrad Bishop 	} else {
18240a360c2SBrad Bishop 		control_emit_goto_system_state(control,"HOST_BOOTING");
18340a360c2SBrad Bishop 	}
184*75a18a23SLei YU 	gpio_close(fsi_clk);
185*75a18a23SLei YU 	gpio_close(fsi_data);
186*75a18a23SLei YU 	gpio_close(fsi_enable);
187*75a18a23SLei YU 	gpio_close(cronus_sel);
188*75a18a23SLei YU 	for (size_t i = 0; i < num_optionals; ++i) {
189*75a18a23SLei YU 		gpio_close(&optionals[i]);
190*75a18a23SLei YU 	}
19140a360c2SBrad Bishop 
19237846da5SAdriana Kobylak 	// Start watchdog with 30s timeout per the OpenPower Host IPMI Spec.
19337846da5SAdriana Kobylak 	// Once the host starts booting, it'll reset and refresh the timer.
19437846da5SAdriana Kobylak 	error = NULL;
19537846da5SAdriana Kobylak 	// TODO Use the object mapper to lookup the bus name when this is
19637846da5SAdriana Kobylak 	// refactored to use sdbus.
19737846da5SAdriana Kobylak 	proxy = g_dbus_proxy_new_sync(connection,
19837846da5SAdriana Kobylak 		G_DBUS_PROXY_FLAGS_NONE,
19937846da5SAdriana Kobylak 		NULL, /* GDBusInterfaceInfo* */
20037846da5SAdriana Kobylak 		"org.openbmc.watchdog.Host", /* name */
20137846da5SAdriana Kobylak 		"/org/openbmc/watchdog/host0", /* object path */
20237846da5SAdriana Kobylak 		"org.openbmc.Watchdog", /* interface name */
20337846da5SAdriana Kobylak 		NULL, /* GCancellable */
20437846da5SAdriana Kobylak 		&error);
20537846da5SAdriana Kobylak 	g_assert_no_error(error);
20637846da5SAdriana Kobylak 	if(error)
20737846da5SAdriana Kobylak 		goto exit;
20837846da5SAdriana Kobylak 
20937846da5SAdriana Kobylak 	// Set watchdog timer to 30s
21037846da5SAdriana Kobylak 	error = NULL;
21137846da5SAdriana Kobylak 	result = g_dbus_proxy_call_sync(proxy,
21237846da5SAdriana Kobylak 		"set",
21337846da5SAdriana Kobylak 		g_variant_new("(i)", 30000),
21437846da5SAdriana Kobylak 		G_DBUS_CALL_FLAGS_NONE,
21537846da5SAdriana Kobylak 		-1,
21637846da5SAdriana Kobylak 		NULL,
21737846da5SAdriana Kobylak 		&error);
21837846da5SAdriana Kobylak 	g_assert_no_error(error);
21937846da5SAdriana Kobylak 	if (error)
22037846da5SAdriana Kobylak 		goto exit;
22137846da5SAdriana Kobylak 	if (result)
22237846da5SAdriana Kobylak 		g_variant_unref(result);
22337846da5SAdriana Kobylak 
22437846da5SAdriana Kobylak 	// Start watchdog timer
22537846da5SAdriana Kobylak 	error = NULL;
22637846da5SAdriana Kobylak 	result = g_dbus_proxy_call_sync(proxy,
22737846da5SAdriana Kobylak 		"start",
22837846da5SAdriana Kobylak 		NULL,
22937846da5SAdriana Kobylak 		G_DBUS_CALL_FLAGS_NONE,
23037846da5SAdriana Kobylak 		-1,
23137846da5SAdriana Kobylak 		NULL,
23237846da5SAdriana Kobylak 		&error);
23337846da5SAdriana Kobylak 	g_assert_no_error(error);
23437846da5SAdriana Kobylak 	if (error)
23537846da5SAdriana Kobylak 		goto exit;
23637846da5SAdriana Kobylak 
23740a360c2SBrad Bishop 	control_host_emit_booted(host);
23837846da5SAdriana Kobylak 
23937846da5SAdriana Kobylak exit:
24037846da5SAdriana Kobylak 	if (result)
24137846da5SAdriana Kobylak 		g_variant_unref(result);
24237846da5SAdriana Kobylak 
24340a360c2SBrad Bishop 	return TRUE;
24440a360c2SBrad Bishop }
24540a360c2SBrad Bishop 
24640a360c2SBrad Bishop static void
24740a360c2SBrad Bishop on_bus_acquired(GDBusConnection *connection,
24840a360c2SBrad Bishop 		const gchar *name,
24940a360c2SBrad Bishop 		gpointer user_data)
25040a360c2SBrad Bishop {
25140a360c2SBrad Bishop 	ObjectSkeleton *object;
25240a360c2SBrad Bishop 	//g_print ("Acquired a message bus connection: %s\n",name);
25340a360c2SBrad Bishop 	manager = g_dbus_object_manager_server_new(dbus_object_path);
25440a360c2SBrad Bishop 
25540a360c2SBrad Bishop 	gchar *s;
25640a360c2SBrad Bishop 	s = g_strdup_printf("%s/%s",dbus_object_path,instance_name);
25740a360c2SBrad Bishop 	object = object_skeleton_new(s);
25840a360c2SBrad Bishop 	g_free(s);
25940a360c2SBrad Bishop 
26040a360c2SBrad Bishop 	ControlHost* control_host = control_host_skeleton_new();
26140a360c2SBrad Bishop 	object_skeleton_set_control_host(object, control_host);
26240a360c2SBrad Bishop 	g_object_unref(control_host);
26340a360c2SBrad Bishop 
26440a360c2SBrad Bishop 	Control* control = control_skeleton_new();
26540a360c2SBrad Bishop 	object_skeleton_set_control(object, control);
26640a360c2SBrad Bishop 	g_object_unref(control);
26740a360c2SBrad Bishop 
26840a360c2SBrad Bishop 	//define method callbacks here
26940a360c2SBrad Bishop 	g_signal_connect(control_host,
27040a360c2SBrad Bishop 			"handle-boot",
27140a360c2SBrad Bishop 			G_CALLBACK(on_boot),
27240a360c2SBrad Bishop 			object); /* user_data */
27340a360c2SBrad Bishop 	g_signal_connect(control,
27440a360c2SBrad Bishop 			"handle-init",
27540a360c2SBrad Bishop 			G_CALLBACK(on_init),
27640a360c2SBrad Bishop 			NULL); /* user_data */
27740a360c2SBrad Bishop 
27840a360c2SBrad Bishop 	control_host_set_debug_mode(control_host,0);
27940a360c2SBrad Bishop 	control_host_set_flash_side(control_host,"primary");
28040a360c2SBrad Bishop 
28140a360c2SBrad Bishop 	/* Export the object (@manager takes its own reference to @object) */
28240a360c2SBrad Bishop 	g_dbus_object_manager_server_set_connection(manager, connection);
28340a360c2SBrad Bishop 	g_dbus_object_manager_server_export(manager, G_DBUS_OBJECT_SKELETON(object));
28440a360c2SBrad Bishop 	g_object_unref(object);
28540a360c2SBrad Bishop 
286*75a18a23SLei YU 	if(read_gpios(connection, &g_gpio_configs) != TRUE) {
287*75a18a23SLei YU 		g_print("ERROR Hostctl: could not read GPIO configuration\n");
288*75a18a23SLei YU 		return;
289*75a18a23SLei YU 	}
290*75a18a23SLei YU 
291*75a18a23SLei YU 	fsi_data = &g_gpio_configs.hostctl_gpio.fsi_data;
292*75a18a23SLei YU 	fsi_clk = &g_gpio_configs.hostctl_gpio.fsi_clk;
293*75a18a23SLei YU 	fsi_enable = &g_gpio_configs.hostctl_gpio.fsi_enable;
294*75a18a23SLei YU 	cronus_sel = &g_gpio_configs.hostctl_gpio.cronus_sel;
295*75a18a23SLei YU 	num_optionals = g_gpio_configs.hostctl_gpio.num_optionals;
296*75a18a23SLei YU 	optionals = g_gpio_configs.hostctl_gpio.optionals;
297*75a18a23SLei YU 	optional_pols = g_gpio_configs.hostctl_gpio.optional_pols;
298*75a18a23SLei YU 
299*75a18a23SLei YU 	gpio_init(connection, fsi_data);
300*75a18a23SLei YU 	gpio_init(connection, fsi_clk);
301*75a18a23SLei YU 	gpio_init(connection, fsi_enable);
302*75a18a23SLei YU 	gpio_init(connection, cronus_sel);
303*75a18a23SLei YU 	for (int i = 0; i < num_optionals; ++i) {
304*75a18a23SLei YU 		gpio_init(connection, &optionals[i]);
305*75a18a23SLei YU 	}
30640a360c2SBrad Bishop }
30740a360c2SBrad Bishop 
30840a360c2SBrad Bishop static void
30940a360c2SBrad Bishop on_name_acquired(GDBusConnection *connection,
31040a360c2SBrad Bishop 		const gchar *name,
31140a360c2SBrad Bishop 		gpointer user_data)
31240a360c2SBrad Bishop {
31340a360c2SBrad Bishop 	// g_print ("Acquired the name %s\n", name);
31440a360c2SBrad Bishop }
31540a360c2SBrad Bishop 
31640a360c2SBrad Bishop static void
31740a360c2SBrad Bishop on_name_lost(GDBusConnection *connection,
31840a360c2SBrad Bishop 		const gchar *name,
31940a360c2SBrad Bishop 		gpointer user_data)
32040a360c2SBrad Bishop {
32140a360c2SBrad Bishop 	// g_print ("Lost the name %s\n", name);
322*75a18a23SLei YU 	free_gpios(&g_gpio_configs);
32340a360c2SBrad Bishop }
32440a360c2SBrad Bishop 
32540a360c2SBrad Bishop gint
32640a360c2SBrad Bishop main(gint argc, gchar *argv[])
32740a360c2SBrad Bishop {
32840a360c2SBrad Bishop 	GMainLoop *loop;
32940a360c2SBrad Bishop 	cmdline cmd;
33040a360c2SBrad Bishop 	cmd.argc = argc;
33140a360c2SBrad Bishop 	cmd.argv = argv;
33240a360c2SBrad Bishop 
33340a360c2SBrad Bishop 	guint id;
33440a360c2SBrad Bishop 	loop = g_main_loop_new(NULL, FALSE);
33540a360c2SBrad Bishop 
33640a360c2SBrad Bishop 	id = g_bus_own_name(DBUS_TYPE,
33740a360c2SBrad Bishop 			dbus_name,
33840a360c2SBrad Bishop 			G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
33940a360c2SBrad Bishop 			G_BUS_NAME_OWNER_FLAGS_REPLACE,
34040a360c2SBrad Bishop 			on_bus_acquired,
34140a360c2SBrad Bishop 			on_name_acquired,
34240a360c2SBrad Bishop 			on_name_lost,
34340a360c2SBrad Bishop 			&cmd,
34440a360c2SBrad Bishop 			NULL);
34540a360c2SBrad Bishop 
34640a360c2SBrad Bishop 	g_main_loop_run(loop);
34740a360c2SBrad Bishop 
34840a360c2SBrad Bishop 	g_bus_unown_name(id);
34940a360c2SBrad Bishop 	g_main_loop_unref(loop);
35040a360c2SBrad Bishop 	return 0;
35140a360c2SBrad Bishop }
352