Skip to content

Commit

Permalink
ast-io: Rework setup/tear-down of communication with the BMC
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
amboar authored and stewartsmith committed Jul 17, 2018
1 parent 8972e44 commit ebc8524
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 30 deletions.
63 changes: 61 additions & 2 deletions hw/ast-bmc/ast-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down
19 changes: 15 additions & 4 deletions include/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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
Expand All @@ -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);
Expand Down
1 change: 1 addition & 0 deletions platforms/astbmc/astbmc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
112 changes: 92 additions & 20 deletions platforms/astbmc/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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();
Expand All @@ -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),
Expand Down
2 changes: 1 addition & 1 deletion platforms/astbmc/romulus.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
3 changes: 2 additions & 1 deletion platforms/astbmc/witherspoon.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions platforms/qemu/qemu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down

0 comments on commit ebc8524

Please sign in to comment.