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