aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Jeffery <andrew@aj.id.au>2018-07-17 11:32:53 +0930
committerStewart Smith <stewart@linux.ibm.com>2018-07-17 01:13:16 -0500
commitebc8524a3a457f73083d984296bfd797940a711c (patch)
treeb478552a2b810ceff3e98bbefe67aa07706dbf48
parent8972e44f97883e5aabf4b9c6737dcf3b22fd24b8 (diff)
downloadskiboot-ebc8524a3a457f73083d984296bfd797940a711c.zip
skiboot-ebc8524a3a457f73083d984296bfd797940a711c.tar.gz
skiboot-ebc8524a3a457f73083d984296bfd797940a711c.tar.bz2
ast-io: Rework setup/tear-down of communication with the BMC
It's possible for the platform to configure the BMC with SuperIO access disabled. Rework the interfaces to report failures if SuperIO is not enabled, and clean up once we're finished. Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Signed-off-by: Stewart Smith <stewart@linux.ibm.com>
-rw-r--r--hw/ast-bmc/ast-io.c63
-rw-r--r--include/ast.h19
-rw-r--r--platforms/astbmc/astbmc.h1
-rw-r--r--platforms/astbmc/common.c112
-rw-r--r--platforms/astbmc/romulus.c2
-rw-r--r--platforms/astbmc/witherspoon.c3
-rw-r--r--platforms/qemu/qemu.c4
7 files changed, 174 insertions, 30 deletions
diff --git a/hw/ast-bmc/ast-io.c b/hw/ast-bmc/ast-io.c
index a552871..eb80181 100644
--- a/hw/ast-bmc/ast-io.c
+++ b/hw/ast-bmc/ast-io.c
@@ -119,6 +119,17 @@
#define BMC_SIO_SCR29_MBOX 0x08
#define BMC_SIO_SCR29_MEMBOOT 0x10
+/*
+ * SIO Register 0x2d: Platform Flags (normal bit ordering)
+ *
+ * [ 7 ] Hostboot configures SUART
+ * [ 6 ] Hostboot configures VUART
+ * [5:1] Reserved
+ * [ 0 ] Isolate Service Processor
+ */
+#define BMC_SIO_PLAT_FLAGS 0x2d
+#define BMC_SIO_PLAT_ISOLATE_SP 0x01
+
enum {
BMC_SIO_DEV_NONE = -1,
BMC_SIO_DEV_UART1 = 2,
@@ -310,10 +321,58 @@ static void ast_setup_sio_irq_polarity(void)
bmc_sio_put(true);
}
-void ast_io_init(void)
+static bool ast_sio_is_enabled(void)
+{
+ bool enabled;
+
+ lpc_outb(0xa5, 0x2e);
+ lpc_outb(0xa5, 0x2e);
+
+ /* Heuristic attempt to confirm SIO is enabled.
+ *
+ * Do two tests of 1 byte, giving a false positive probability of
+ * 1/65536. Read tests on disabled SIO tended to return 0x60.
+ */
+ bmc_sio_outb(0x2, 0x07);
+ enabled = bmc_sio_inb(0x07) == 2;
+ if (enabled) {
+ bmc_sio_outb(0xd, 0x07);
+ enabled = bmc_sio_inb(0x07) == 0xd;
+ }
+
+ if (enabled)
+ lpc_outb(0xaa, 0x2e);
+
+ return enabled;
+}
+
+bool ast_sio_init(void)
{
+ bool enabled = ast_sio_is_enabled();
+
+ prlog(PR_NOTICE, "PLAT: SuperIO is %s\n",
+ enabled ? "available" : "unavailable!");
+
/* Configure all AIO interrupts to level low */
- ast_setup_sio_irq_polarity();
+ if (enabled)
+ ast_setup_sio_irq_polarity();
+
+ return enabled;
+}
+
+bool ast_can_isolate_sp(void)
+{
+ return bmc_sio_inb(BMC_SIO_PLAT_FLAGS) & BMC_SIO_PLAT_ISOLATE_SP;
+}
+
+bool ast_io_is_rw(void)
+{
+ return !(ast_ahb_readl(LPC_HICRB) & LPC_HICRB_ILPC_DISABLE);
+}
+
+bool ast_io_init(void)
+{
+ return ast_io_is_rw();
}
bool ast_lpc_fw_is_mbox(void)
diff --git a/include/ast.h b/include/ast.h
index 3525c82..1b5e001 100644
--- a/include/ast.h
+++ b/include/ast.h
@@ -39,6 +39,8 @@
#define LPC_HICR6 (LPC_BASE + 0x80)
#define LPC_HICR7 (LPC_BASE + 0x88)
#define LPC_HICR8 (LPC_BASE + 0x8c)
+#define LPC_HICRB (LPC_BASE + 0x100)
+#define LPC_HICRB_ILPC_DISABLE (1 << 6)
#define LPC_iBTCR0 (LPC_BASE + 0x140)
/* VUART1 */
@@ -49,9 +51,15 @@
#define VUART1_ADDRH (VUART1_BASE + 0x2c)
/* SCU registers */
-#define SCU_BASE 0x1e6e2000
-#define SCU_HW_STRAPPING (SCU_BASE + 0x70)
-#define SCU_REVISION_ID (SCU_BASE + 0x7C)
+#define SCU_BASE 0x1e6e2000
+#define SCU_HW_STRAPPING (SCU_BASE + 0x70)
+#define SCU_STRAP_SIO_DECODE_DISABLE (1 << 20)
+#define SCU_REVISION_ID (SCU_BASE + 0x7C)
+#define SCU_REVISION_SOC_FAMILY(x) (((x) >> 24) & 0xff)
+#define SCU_REVISION_SOC_FAMILY_2400 0x02
+#define SCU_REVISION_SOC_FAMILY_2500 0x04
+#define SCU_REVISION_HW_REVISION_ID(x) (((x) >> 16) & 0xff)
+#define SCU_REVISION_CHIP_BONDING(x) (((x) >> 8) & 0x3)
/* MCR registers */
#define MCR_BASE 0x1e6e0000
@@ -73,7 +81,10 @@
void ast_ahb_writel(uint32_t val, uint32_t reg);
uint32_t ast_ahb_readl(uint32_t reg);
-void ast_io_init(void);
+bool ast_sio_init(void);
+bool ast_can_isolate_sp(void);
+bool ast_io_init(void);
+bool ast_io_is_rw(void);
bool ast_lpc_fw_is_flash(void);
bool ast_lpc_fw_is_mbox(void);
bool ast_scratch_reg_is_mbox(void);
diff --git a/platforms/astbmc/astbmc.h b/platforms/astbmc/astbmc.h
index fb6c68a..fc53d1a 100644
--- a/platforms/astbmc/astbmc.h
+++ b/platforms/astbmc/astbmc.h
@@ -89,6 +89,7 @@ extern void astbmc_init(void);
extern void astbmc_ext_irq_serirq_cpld(unsigned int chip_id);
extern int pnor_init(void);
extern void check_all_slot_table(void);
+extern void astbmc_exit(void);
extern void slot_table_init(const struct slot_table_entry *top_table);
extern void slot_table_get_slot_info(struct phb *phb, struct pci_device * pd);
diff --git a/platforms/astbmc/common.c b/platforms/astbmc/common.c
index 6c90b7d..4b5d9a6 100644
--- a/platforms/astbmc/common.c
+++ b/platforms/astbmc/common.c
@@ -372,25 +372,13 @@ static void astbmc_fixup_psi_bar(void)
xscom_write(chip->id, 0x201090A, psibar);
}
-void astbmc_early_init(void)
+static void astbmc_fixup_uart(void)
{
- /* Hostboot's device-tree isn't quite right yet */
- astbmc_fixup_dt();
-
- /* Hostboot forgets to populate the PSI BAR */
- astbmc_fixup_psi_bar();
-
- /* Send external interrupts to me */
- psi_set_external_irq_policy(EXTERNAL_IRQ_POLICY_SKIBOOT);
-
- /* Initialize AHB accesses via AST2400 */
- ast_io_init();
-
/*
- * Depending on which image we are running, it may be configuring
- * the virtual UART or not. Check if VUART is enabled and use
- * SIO if not. We also correct the configuration of VUART as some
- * BMC images don't setup the interrupt properly
+ * Depending on which image we are running, it may be configuring the
+ * virtual UART or not. Check if VUART is enabled and use SIO if not.
+ * We also correct the configuration of VUART as some BMC images don't
+ * setup the interrupt properly
*/
if (ast_is_vuart1_enabled()) {
printf("PLAT: Using virtual UART\n");
@@ -400,11 +388,37 @@ void astbmc_early_init(void)
printf("PLAT: Using SuperIO UART\n");
ast_setup_sio_uart1(UART_IO_BASE, UART_LPC_IRQ);
}
+}
+
+void astbmc_early_init(void)
+{
+ /* Hostboot's device-tree isn't quite right yet */
+ astbmc_fixup_dt();
- /* Similarly, some BMCs don't configure the BT interrupt properly */
- ast_setup_ibt(BT_IO_BASE, BT_LPC_IRQ);
+ /* Hostboot forgets to populate the PSI BAR */
+ astbmc_fixup_psi_bar();
+
+ /* Send external interrupts to me */
+ psi_set_external_irq_policy(EXTERNAL_IRQ_POLICY_SKIBOOT);
- ast_setup_sio_mbox(MBOX_IO_BASE, MBOX_LPC_IRQ);
+ if (ast_sio_init()) {
+ if (!ast_can_isolate_sp()) {
+ /*
+ * BMCs claiming support for isolation must have
+ * correctly configured the UART and BT for host
+ * firmware. If not, let's apply some fixups for broken
+ * BMC firmwares.
+ */
+ if (ast_io_init()) {
+ astbmc_fixup_uart();
+ ast_setup_ibt(BT_IO_BASE, BT_LPC_IRQ);
+ } else
+ prerror("PLAT: AST IO initialisation failed!\n");
+ }
+
+ ast_setup_sio_mbox(MBOX_IO_BASE, MBOX_LPC_IRQ);
+ } else
+ prerror("PLAT: AST SIO initialisation failed!\n");
/* Setup UART and use it as console */
uart_init();
@@ -414,6 +428,64 @@ void astbmc_early_init(void)
prd_init();
}
+static bool astbmc_isolate_via_io(void)
+{
+ uint32_t hw_strapping;
+ uint32_t silicon_rev;
+ uint8_t family;
+
+ silicon_rev = ast_ahb_readl(SCU_REVISION_ID);
+ family = SCU_REVISION_SOC_FAMILY(silicon_rev);
+
+ if (family == SCU_REVISION_SOC_FAMILY_2400) {
+ /* Strapping is read-modify-write on SCU70 */
+ hw_strapping = SCU_STRAP_SIO_DECODE_DISABLE;
+ hw_strapping |= ast_ahb_readl(SCU_HW_STRAPPING);
+ } else if (family == SCU_REVISION_SOC_FAMILY_2500) {
+ /*
+ * Strapping is W1S on SCU70, W1C on SCU7C. We're setting a bit
+ * so read-modify-write *should* work, but in reality it breaks
+ * the AXI/AHB divider, so don't do that.
+ */
+ hw_strapping = SCU_STRAP_SIO_DECODE_DISABLE;
+ } else {
+ prerror("PLAT: Unrecognised BMC silicon revision 0x%x, isolation failed\n",
+ silicon_rev);
+ return false;
+ }
+
+ ast_ahb_writel(hw_strapping, SCU_HW_STRAPPING);
+
+ return true;
+}
+
+static bool astbmc_isolate_via_ipmi(void)
+{
+ return false;
+}
+
+static void astbmc_isolate(void)
+{
+ bool isolated;
+
+ isolated = ast_io_is_rw() ? astbmc_isolate_via_io()
+ : astbmc_isolate_via_ipmi();
+
+ if (!isolated) {
+ prlog(PR_EMERG, "PLAT: BMC isolation failed\n");
+ abort();
+ }
+
+ prlog(PR_INFO, "PLAT: Isolated BMC\n");
+}
+
+void astbmc_exit(void)
+{
+ if (ast_can_isolate_sp())
+ astbmc_isolate();
+ ipmi_wdt_final_reset();
+}
+
const struct bmc_platform astbmc_ami = {
.name = "AMI",
.ipmi_oem_partial_add_esel = IPMI_CODE(0x3a, 0xf0),
diff --git a/platforms/astbmc/romulus.c b/platforms/astbmc/romulus.c
index 8d3d104..67c5946 100644
--- a/platforms/astbmc/romulus.c
+++ b/platforms/astbmc/romulus.c
@@ -80,6 +80,6 @@ DECLARE_PLATFORM(romulus) = {
.cec_power_down = astbmc_ipmi_power_down,
.cec_reboot = astbmc_ipmi_reboot,
.elog_commit = ipmi_elog_commit,
- .exit = ipmi_wdt_final_reset,
+ .exit = astbmc_exit,
.terminate = ipmi_terminate,
};
diff --git a/platforms/astbmc/witherspoon.c b/platforms/astbmc/witherspoon.c
index cb09eef..d663709 100644
--- a/platforms/astbmc/witherspoon.c
+++ b/platforms/astbmc/witherspoon.c
@@ -29,6 +29,7 @@
#include <phb4.h>
#include "astbmc.h"
+#include "ast.h"
/*
* HACK: Hostboot doesn't export the correct data for the system VPD EEPROM
@@ -165,7 +166,7 @@ DECLARE_PLATFORM(witherspoon) = {
.cec_power_down = astbmc_ipmi_power_down,
.cec_reboot = astbmc_ipmi_reboot,
.elog_commit = ipmi_elog_commit,
- .exit = ipmi_wdt_final_reset,
+ .exit = astbmc_exit,
.terminate = ipmi_terminate,
.pci_get_slot_info = dt_slot_get_slot_info,
diff --git a/platforms/qemu/qemu.c b/platforms/qemu/qemu.c
index dee61cc..a9b4f57 100644
--- a/platforms/qemu/qemu.c
+++ b/platforms/qemu/qemu.c
@@ -246,8 +246,8 @@ static bool qemu_probe(void)
psi_set_external_irq_policy(EXTERNAL_IRQ_POLICY_SKIBOOT);
- /* Initialize AHB accesses via AST2400 */
- ast_io_init();
+ if (!ast_sio_init())
+ prerror("PLAT: AST SIO initialisation failed!\n");
/* Setup UART and use it as console */
uart_init();