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>
85da4f4fcSJoel Stanley #include <errno.h>
95da4f4fcSJoel Stanley 
10f6c85685SBrad Bishop #include <openbmc_intf.h>
11f6c85685SBrad Bishop #include <openbmc.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 
1840a360c2SBrad Bishop static GDBusObjectManagerServer *manager = NULL;
1940a360c2SBrad Bishop 
205da4f4fcSJoel Stanley #define PPC_BIT32(bit)          (0x80000000UL >> (bit))
2140a360c2SBrad Bishop 
225da4f4fcSJoel Stanley #define FSI_EXTERNAL_MODE_PATH	"/sys/devices/platform/gpio-fsi/external_mode"
23bed673e2SJoel Stanley #define FSI_SCAN_PATH		"/sys/class/fsi-master/fsi0/rescan"
2440a360c2SBrad Bishop 
255da4f4fcSJoel Stanley /* TODO: Change this over to the cfam path once the cfam chardev patches have landed */
26bed673e2SJoel Stanley #define FSI_RAW_PATH		"/sys/class/fsi-master/fsi0/slave@00:00/raw"
2740a360c2SBrad Bishop 
285da4f4fcSJoel Stanley #define FSI_SCAN_DELAY_US	10000
2940a360c2SBrad Bishop 
305da4f4fcSJoel Stanley /* Attention registers */
315da4f4fcSJoel Stanley #define FSI_A_SI1S		0x081c
325da4f4fcSJoel Stanley #define TRUE_MASK		0x100d
335da4f4fcSJoel Stanley #define INTERRUPT_STATUS_REG	0x100b
3440a360c2SBrad Bishop 
355da4f4fcSJoel Stanley /* SBE boot register and values */
365da4f4fcSJoel Stanley #define SBE_VITAL		0x281c
375da4f4fcSJoel Stanley #define SBE_WARMSTART		PPC_BIT32(0)
385da4f4fcSJoel Stanley #define SBE_HW_TRIGGER		PPC_BIT32(2)
395da4f4fcSJoel Stanley #define SBE_UPDATE_1ST_NIBBLE	PPC_BIT32(3)
405da4f4fcSJoel Stanley #define SBE_IMAGE_SELECT	PPC_BIT32(8)
415da4f4fcSJoel Stanley #define SBE_UPDATE_3RD_NIBBLE	PPC_BIT32(11)
425da4f4fcSJoel Stanley 
435da4f4fcSJoel Stanley /* Once the side is selected and attention bits are set, this starts the SBE */
445da4f4fcSJoel Stanley #define START_SBE		(SBE_WARMSTART | SBE_HW_TRIGGER | SBE_UPDATE_1ST_NIBBLE)
455da4f4fcSJoel Stanley 
465da4f4fcSJoel Stanley /* Primary is first side. Golden is second side */
475da4f4fcSJoel Stanley #define PRIMARY_SIDE		(SBE_HW_TRIGGER | SBE_UPDATE_1ST_NIBBLE)
485da4f4fcSJoel Stanley #define GOLDEN_SIDE		(SBE_HW_TRIGGER | SBE_UPDATE_1ST_NIBBLE | \
495da4f4fcSJoel Stanley 				 SBE_IMAGE_SELECT | SBE_UPDATE_3RD_NIBBLE)
5040a360c2SBrad Bishop 
5140a360c2SBrad Bishop static gboolean
on_init(Control * control,GDBusMethodInvocation * invocation,gpointer user_data)5240a360c2SBrad Bishop on_init(Control *control,
5340a360c2SBrad Bishop 		GDBusMethodInvocation *invocation,
5440a360c2SBrad Bishop 		gpointer user_data)
5540a360c2SBrad Bishop {
5640a360c2SBrad Bishop 	control_complete_init(control,invocation);
5740a360c2SBrad Bishop 	return TRUE;
5840a360c2SBrad Bishop }
5940a360c2SBrad Bishop 
605da4f4fcSJoel Stanley static gint
fsi_putcfam(int fd,uint64_t addr64,uint32_t val_host)615da4f4fcSJoel Stanley fsi_putcfam(int fd, uint64_t addr64, uint32_t val_host)
6240a360c2SBrad Bishop {
635da4f4fcSJoel Stanley 	int rc;
645da4f4fcSJoel Stanley 	uint32_t val = htobe32(val_host);
655da4f4fcSJoel Stanley 	/* Map FSI to FSI_BYTE, as the 'raw' kernel interface expects this */
665da4f4fcSJoel Stanley 	uint32_t addr = (addr64 & 0x7ffc00) | ((addr64 & 0x3ff) << 2);
675da4f4fcSJoel Stanley 
685da4f4fcSJoel Stanley 	rc = lseek(fd, addr, SEEK_SET);
695da4f4fcSJoel Stanley 	if (rc < 0) {
705da4f4fcSJoel Stanley 		g_print("ERROR HostControl: cfam seek failed (0x%08x): %s\n", addr,
715da4f4fcSJoel Stanley 				strerror(errno));
725da4f4fcSJoel Stanley 		return errno;
735da4f4fcSJoel Stanley 	};
745da4f4fcSJoel Stanley 
755da4f4fcSJoel Stanley 	rc = write(fd, &val, sizeof(val));
765da4f4fcSJoel Stanley 	if (rc < 0) {
775da4f4fcSJoel Stanley 		g_print("ERROR HostControl: cfam write failed: %s\n",
785da4f4fcSJoel Stanley 				strerror(errno));
795da4f4fcSJoel Stanley 		return errno;
8040a360c2SBrad Bishop 	}
8140a360c2SBrad Bishop 
825da4f4fcSJoel Stanley 	return 0;
8340a360c2SBrad Bishop }
8440a360c2SBrad Bishop 
fsi_rescan(void)855da4f4fcSJoel Stanley static int fsi_rescan(void)
865da4f4fcSJoel Stanley {
875da4f4fcSJoel Stanley 	char *one = "1";
885da4f4fcSJoel Stanley 	int fd, rc;
895da4f4fcSJoel Stanley 
905da4f4fcSJoel Stanley 	fd = open(FSI_SCAN_PATH, O_WRONLY);
915da4f4fcSJoel Stanley 	if (fd < 0) {
925da4f4fcSJoel Stanley 		g_print("ERROR HostControl: Failed to open path '%s': %s\n",
935da4f4fcSJoel Stanley 				FSI_SCAN_PATH, strerror(errno));
945da4f4fcSJoel Stanley 		return errno;
955da4f4fcSJoel Stanley 	}
96*3fbb4443SAndrew Geissler 	rc = write(fd, one, sizeof(*one));
975da4f4fcSJoel Stanley 	close(fd);
985da4f4fcSJoel Stanley 	if (rc < 0) {
995da4f4fcSJoel Stanley 		g_print("ERROR HostControl: Failed to perform FSI scan: %s\n",
1005da4f4fcSJoel Stanley 				strerror(errno));
1015da4f4fcSJoel Stanley 		return errno;
1025da4f4fcSJoel Stanley 	}
1035da4f4fcSJoel Stanley 	g_print("HostControl: Performing FSI scan (delay %d us)\n",
1045da4f4fcSJoel Stanley 			FSI_SCAN_DELAY_US);
1055da4f4fcSJoel Stanley 	usleep(FSI_SCAN_DELAY_US);
1065da4f4fcSJoel Stanley 
1075da4f4fcSJoel Stanley 	return 0;
1085da4f4fcSJoel Stanley }
10940a360c2SBrad Bishop 
11040a360c2SBrad Bishop static gboolean
on_boot(ControlHost * host,GDBusMethodInvocation * invocation,gpointer user_data)11140a360c2SBrad Bishop on_boot(ControlHost *host,
11240a360c2SBrad Bishop 		GDBusMethodInvocation *invocation,
11340a360c2SBrad Bishop 		gpointer user_data)
11440a360c2SBrad Bishop {
1155da4f4fcSJoel Stanley 	int rc, cfam_fd;
11637846da5SAdriana Kobylak 	GDBusProxy *proxy;
11737846da5SAdriana Kobylak 	GError *error = NULL;
11837846da5SAdriana Kobylak 	GDBusConnection *connection =
11937846da5SAdriana Kobylak 		g_dbus_object_manager_server_get_connection(manager);
12040a360c2SBrad Bishop 
12175a18a23SLei YU 	if(control_host_get_debug_mode(host)==1) {
1225da4f4fcSJoel Stanley 		int fd;
1235da4f4fcSJoel Stanley 		char *one = "1";
12440a360c2SBrad Bishop 		g_print("Enabling debug mode; not booting host\n");
1255da4f4fcSJoel Stanley 		fd = open(FSI_EXTERNAL_MODE_PATH, O_RDWR);
1265da4f4fcSJoel Stanley 		if (fd < 0) {
1275da4f4fcSJoel Stanley 			g_print("ERROR HostControl: Failed to open path '%s'\n",
1285da4f4fcSJoel Stanley 					FSI_EXTERNAL_MODE_PATH);
1295da4f4fcSJoel Stanley 			return TRUE;
13040a360c2SBrad Bishop 		}
131*3fbb4443SAndrew Geissler 		rc = write(fd, one, sizeof(*one));
1325da4f4fcSJoel Stanley 		if (rc < 0) {
1335da4f4fcSJoel Stanley 			g_print("ERROR HostControl: Failed to enable debug mode '%s'\n",
1345da4f4fcSJoel Stanley 					FSI_EXTERNAL_MODE_PATH);
1355da4f4fcSJoel Stanley 		}
1365da4f4fcSJoel Stanley 		close(fd);
13740a360c2SBrad Bishop 		return TRUE;
13840a360c2SBrad Bishop 	}
13940a360c2SBrad Bishop 	g_print("Booting host\n");
1405da4f4fcSJoel Stanley 
1415da4f4fcSJoel Stanley 	rc = fsi_rescan();
1425da4f4fcSJoel Stanley 	if (rc < 0)
1435da4f4fcSJoel Stanley 		return FALSE;
1445da4f4fcSJoel Stanley 
1455da4f4fcSJoel Stanley 	cfam_fd = open(FSI_RAW_PATH, O_RDWR);
1465da4f4fcSJoel Stanley 	if (cfam_fd < 0) {
1475da4f4fcSJoel Stanley 		g_print("ERROR HostControl: Failed to open '%s'\n", FSI_RAW_PATH);
1485da4f4fcSJoel Stanley 		return FALSE;
1495da4f4fcSJoel Stanley 	}
1505da4f4fcSJoel Stanley 
15140a360c2SBrad Bishop 	Control* control = object_get_control((Object*)user_data);
15240a360c2SBrad Bishop 	control_host_complete_boot(host,invocation);
15340a360c2SBrad Bishop 	do {
1545da4f4fcSJoel Stanley 		rc = fsi_putcfam(cfam_fd, FSI_A_SI1S, 0x20000000);
1555da4f4fcSJoel Stanley 		rc |= fsi_putcfam(cfam_fd, TRUE_MASK, 0x40000000);
1565da4f4fcSJoel Stanley 		rc |= fsi_putcfam(cfam_fd, INTERRUPT_STATUS_REG, 0xFFFFFFFF);
1575da4f4fcSJoel Stanley 		if(rc) { break; }
15840a360c2SBrad Bishop 
15940a360c2SBrad Bishop 		const gchar* flash_side = control_host_get_flash_side(host);
16040a360c2SBrad Bishop 		g_print("Using %s side of the bios flash\n",flash_side);
16140a360c2SBrad Bishop 		if(strcmp(flash_side,"primary")==0) {
1625da4f4fcSJoel Stanley 			rc |= fsi_putcfam(cfam_fd, SBE_VITAL, PRIMARY_SIDE);
16340a360c2SBrad Bishop 		} else if(strcmp(flash_side,"golden") == 0) {
1645da4f4fcSJoel Stanley 			rc |= fsi_putcfam(cfam_fd, SBE_VITAL, GOLDEN_SIDE);
16540a360c2SBrad Bishop 		} else {
16640a360c2SBrad Bishop 			g_print("ERROR: Invalid flash side: %s\n",flash_side);
16740a360c2SBrad Bishop 			rc = 0xff;
16840a360c2SBrad Bishop 
16940a360c2SBrad Bishop 		}
1705da4f4fcSJoel Stanley 		if(rc) { break; }
17140a360c2SBrad Bishop 
1725da4f4fcSJoel Stanley 		rc = fsi_putcfam(cfam_fd, SBE_VITAL, START_SBE);
17340a360c2SBrad Bishop 	} while(0);
1745da4f4fcSJoel Stanley 	if(rc)
17540a360c2SBrad Bishop 	{
1765da4f4fcSJoel Stanley 		g_print("ERROR HostControl: SBE sequence failed (rc=%d)\n",rc);
17740a360c2SBrad Bishop 	}
1785da4f4fcSJoel Stanley 	/* Close file descriptor */
1795da4f4fcSJoel Stanley 	close(cfam_fd);
18040a360c2SBrad Bishop 
18140a360c2SBrad Bishop 	control_host_emit_booted(host);
18237846da5SAdriana Kobylak 
18340a360c2SBrad Bishop 	return TRUE;
18440a360c2SBrad Bishop }
18540a360c2SBrad Bishop 
18640a360c2SBrad Bishop static void
on_bus_acquired(GDBusConnection * connection,const gchar * name,gpointer user_data)18740a360c2SBrad Bishop on_bus_acquired(GDBusConnection *connection,
18840a360c2SBrad Bishop 		const gchar *name,
18940a360c2SBrad Bishop 		gpointer user_data)
19040a360c2SBrad Bishop {
19140a360c2SBrad Bishop 	ObjectSkeleton *object;
19240a360c2SBrad Bishop 	//g_print ("Acquired a message bus connection: %s\n",name);
19340a360c2SBrad Bishop 	manager = g_dbus_object_manager_server_new(dbus_object_path);
19440a360c2SBrad Bishop 
19540a360c2SBrad Bishop 	gchar *s;
19640a360c2SBrad Bishop 	s = g_strdup_printf("%s/%s",dbus_object_path,instance_name);
19740a360c2SBrad Bishop 	object = object_skeleton_new(s);
19840a360c2SBrad Bishop 	g_free(s);
19940a360c2SBrad Bishop 
20040a360c2SBrad Bishop 	ControlHost* control_host = control_host_skeleton_new();
20140a360c2SBrad Bishop 	object_skeleton_set_control_host(object, control_host);
20240a360c2SBrad Bishop 	g_object_unref(control_host);
20340a360c2SBrad Bishop 
20440a360c2SBrad Bishop 	Control* control = control_skeleton_new();
20540a360c2SBrad Bishop 	object_skeleton_set_control(object, control);
20640a360c2SBrad Bishop 	g_object_unref(control);
20740a360c2SBrad Bishop 
20840a360c2SBrad Bishop 	//define method callbacks here
20940a360c2SBrad Bishop 	g_signal_connect(control_host,
21040a360c2SBrad Bishop 			"handle-boot",
21140a360c2SBrad Bishop 			G_CALLBACK(on_boot),
21240a360c2SBrad Bishop 			object); /* user_data */
21340a360c2SBrad Bishop 	g_signal_connect(control,
21440a360c2SBrad Bishop 			"handle-init",
21540a360c2SBrad Bishop 			G_CALLBACK(on_init),
21640a360c2SBrad Bishop 			NULL); /* user_data */
21740a360c2SBrad Bishop 
21840a360c2SBrad Bishop 	control_host_set_debug_mode(control_host,0);
21940a360c2SBrad Bishop 	control_host_set_flash_side(control_host,"primary");
22040a360c2SBrad Bishop 
22140a360c2SBrad Bishop 	/* Export the object (@manager takes its own reference to @object) */
22240a360c2SBrad Bishop 	g_dbus_object_manager_server_set_connection(manager, connection);
22340a360c2SBrad Bishop 	g_dbus_object_manager_server_export(manager, G_DBUS_OBJECT_SKELETON(object));
22440a360c2SBrad Bishop 	g_object_unref(object);
22540a360c2SBrad Bishop }
22640a360c2SBrad Bishop 
22740a360c2SBrad Bishop static void
on_name_acquired(GDBusConnection * connection,const gchar * name,gpointer user_data)22840a360c2SBrad Bishop on_name_acquired(GDBusConnection *connection,
22940a360c2SBrad Bishop 		const gchar *name,
23040a360c2SBrad Bishop 		gpointer user_data)
23140a360c2SBrad Bishop {
23240a360c2SBrad Bishop 	// g_print ("Acquired the name %s\n", name);
23340a360c2SBrad Bishop }
23440a360c2SBrad Bishop 
23540a360c2SBrad Bishop static void
on_name_lost(GDBusConnection * connection,const gchar * name,gpointer user_data)23640a360c2SBrad Bishop on_name_lost(GDBusConnection *connection,
23740a360c2SBrad Bishop 		const gchar *name,
23840a360c2SBrad Bishop 		gpointer user_data)
23940a360c2SBrad Bishop {
24040a360c2SBrad Bishop 	// g_print ("Lost the name %s\n", name);
24140a360c2SBrad Bishop }
24240a360c2SBrad Bishop 
24340a360c2SBrad Bishop gint
main(gint argc,gchar * argv[])24440a360c2SBrad Bishop main(gint argc, gchar *argv[])
24540a360c2SBrad Bishop {
24640a360c2SBrad Bishop 	GMainLoop *loop;
24740a360c2SBrad Bishop 	cmdline cmd;
24840a360c2SBrad Bishop 	cmd.argc = argc;
24940a360c2SBrad Bishop 	cmd.argv = argv;
25040a360c2SBrad Bishop 
25140a360c2SBrad Bishop 	guint id;
25240a360c2SBrad Bishop 	loop = g_main_loop_new(NULL, FALSE);
25340a360c2SBrad Bishop 
25440a360c2SBrad Bishop 	id = g_bus_own_name(DBUS_TYPE,
25540a360c2SBrad Bishop 			dbus_name,
25640a360c2SBrad Bishop 			G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
25740a360c2SBrad Bishop 			G_BUS_NAME_OWNER_FLAGS_REPLACE,
25840a360c2SBrad Bishop 			on_bus_acquired,
25940a360c2SBrad Bishop 			on_name_acquired,
26040a360c2SBrad Bishop 			on_name_lost,
26140a360c2SBrad Bishop 			&cmd,
26240a360c2SBrad Bishop 			NULL);
26340a360c2SBrad Bishop 
26440a360c2SBrad Bishop 	g_main_loop_run(loop);
26540a360c2SBrad Bishop 
26640a360c2SBrad Bishop 	g_bus_unown_name(id);
26740a360c2SBrad Bishop 	g_main_loop_unref(loop);
26840a360c2SBrad Bishop 	return 0;
26940a360c2SBrad Bishop }
270