mainboard/lippert: Refactor SEMA watchdog message

It's too critical to ignore when sending the message on
SMBus fails, so allow for a fair amount of retries.
Failure here causes watchdog to do hard reset later.

Move it out of mainboard.c as we need to call this
early in romstage while we are debugging.

Change-Id: I1006b079269d6dd44de630db7a5694124af2f974
Signed-off-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-on: https://review.coreboot.org/21316
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
This commit is contained in:
Kyösti Mälkki 2017-08-30 12:01:08 +03:00
parent 8a8386eeb9
commit 081b66951f
6 changed files with 132 additions and 55 deletions

View File

@ -27,3 +27,7 @@ romstage-y += OemCustomize.c
ramstage-y += buildOpts.c ramstage-y += buildOpts.c
ramstage-y += BiosCallOuts.c ramstage-y += BiosCallOuts.c
ramstage-y += OemCustomize.c ramstage-y += OemCustomize.c
# Minimal SEMA watchdog support
romstage-y += sema.c
ramstage-y += sema.c

View File

@ -27,6 +27,7 @@
#include "SBPLATFORM.h" #include "SBPLATFORM.h"
#include "OEM.h" /* SMBUS0_BASE_ADDRESS */ #include "OEM.h" /* SMBUS0_BASE_ADDRESS */
#include <southbridge/amd/cimx/sb800/gpio_oem.h> #include <southbridge/amd/cimx/sb800/gpio_oem.h>
#include "sema.h"
/* Init SIO GPIOs. */ /* Init SIO GPIOs. */
#define SIO_RUNTIME_BASE 0x0E00 #define SIO_RUNTIME_BASE 0x0E00
@ -59,28 +60,6 @@ static const u16 sio_init_table[] = { // hi = offset, lo = value
0x5780, // GP65: USB power 4/5 = open drain output 0x5780, // GP65: USB power 4/5 = open drain output
}; };
/* Write data block to slave on SMBUS0. */
#define SMB0_STATUS ((SMBUS0_BASE_ADDRESS) + 0)
#define SMB0_CONTROL ((SMBUS0_BASE_ADDRESS) + 2)
#define SMB0_HOSTCMD ((SMBUS0_BASE_ADDRESS) + 3)
#define SMB0_ADDRESS ((SMBUS0_BASE_ADDRESS) + 4)
#define SMB0_DATA0 ((SMBUS0_BASE_ADDRESS) + 5)
#define SMB0_BLOCKDATA ((SMBUS0_BASE_ADDRESS) + 7)
static int smb_write_blk(u8 slave, u8 command, u8 length, const u8 *data)
{
__outbyte(SMB0_STATUS, 0x1E); // clear error status
__outbyte(SMB0_ADDRESS, slave & ~1); // slave addr + direction = out
__outbyte(SMB0_HOSTCMD, command); // or destination offset
__outbyte(SMB0_DATA0, length); // sent before data
__inbyte(SMB0_CONTROL); // reset block data array
while (length--)
__outbyte(SMB0_BLOCKDATA, *(data++));
__outbyte(SMB0_CONTROL, 0x54); // execute block write, no IRQ
while (__inbyte(SMB0_STATUS) == 0x01); // busy, no errors
return __inbyte(SMB0_STATUS) ^ 0x02; // 0x02 = completed, no errors
}
static void init(struct device *dev) static void init(struct device *dev)
{ {
volatile u8 *spi_base; // base addr of Hudson's SPI host controller volatile u8 *spi_base; // base addr of Hudson's SPI host controller
@ -126,11 +105,11 @@ static void init(struct device *dev)
/* Notify the SMC we're alive and kicking, or after a while it will /* Notify the SMC we're alive and kicking, or after a while it will
* effect a power cycle and switch to the alternate BIOS chip. * effect a power cycle and switch to the alternate BIOS chip.
* Should be done as late as possible. */ * Should be done as late as possible.
printk(BIOS_INFO, "Sending BIOS alive message\n"); * Failure here does not matter if watchdog was already disabled,
const u8 i_am_alive[] = { 0x03 }; * by configuration or previous boot, so ignore return value.
if ((i = smb_write_blk(0x50, 0x25, sizeof(i_am_alive), i_am_alive))) */
printk(BIOS_ERR, "smb_write_blk failed: %d\n", i); sema_send_alive();
printk(BIOS_DEBUG, CONFIG_MAINBOARD_PART_NUMBER " EXIT %s\n", __func__); printk(BIOS_DEBUG, CONFIG_MAINBOARD_PART_NUMBER " EXIT %s\n", __func__);
} }

View File

@ -0,0 +1,89 @@
/*
* This file is part of the coreboot project.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <stdlib.h>
#include <arch/io.h>
#include <console/console.h>
#include <device/device.h>
#include <delay.h>
#include "OEM.h" /* SMBUS0_BASE_ADDRESS */
#include "Porting.h"
#include "AGESA.h"
#include <northbridge/amd/agesa/dimmSpd.h>
#include "sema.h"
/* Write data block to slave on SMBUS0. */
#define SMB0_STATUS ((SMBUS0_BASE_ADDRESS) + 0)
#define SMB0_CONTROL ((SMBUS0_BASE_ADDRESS) + 2)
#define SMB0_HOSTCMD ((SMBUS0_BASE_ADDRESS) + 3)
#define SMB0_ADDRESS ((SMBUS0_BASE_ADDRESS) + 4)
#define SMB0_DATA0 ((SMBUS0_BASE_ADDRESS) + 5)
#define SMB0_BLOCKDATA ((SMBUS0_BASE_ADDRESS) + 7)
static int smb_write_blk(u8 slave, u8 command, u8 length, const u8 *data)
{
__outbyte(SMB0_STATUS, 0x1E); // clear error status
__outbyte(SMB0_ADDRESS, slave & ~1); // slave addr + direction = out
__outbyte(SMB0_HOSTCMD, command); // or destination offset
__outbyte(SMB0_DATA0, length); // sent before data
__inbyte(SMB0_CONTROL); // reset block data array
while (length--)
__outbyte(SMB0_BLOCKDATA, *(data++));
__outbyte(SMB0_CONTROL, 0x54); // execute block write, no IRQ
while (__inbyte(SMB0_STATUS) == 0x01); // busy, no errors
return __inbyte(SMB0_STATUS) ^ 0x02; // 0x02 = completed, no errors
}
#define RETRY_COUNT 100
/* Use of mdelay() here would fail in romstage. */
static void early_mdelay(int msecs)
{
while (msecs--) {
int i;
for (i = 0; i < 1000; i++)
inb(0x80);
}
}
int sema_send_alive(void)
{
const u8 i_am_alive[] = { 0x03 };
int i, j = 0;
char one_spd_byte;
/* Fake read just to setup SMBUS controller. */
if (ENV_ROMSTAGE)
smbus_readSpd(0xa0, &one_spd_byte, 1);
/* Notify the SMC we're alive and kicking, or after a while it will
* effect a power cycle and switch to the alternate BIOS chip.
* Should be done as late as possible. */
printk(BIOS_CRIT, "Sending BIOS alive message... ");
do {
i = smb_write_blk(0x50, 0x25, sizeof(i_am_alive), i_am_alive);
early_mdelay(25);
} while ((++j < RETRY_COUNT) && i);
if (j == RETRY_COUNT) {
printk(BIOS_INFO, "failed\n");
return -1;
}
printk(BIOS_CRIT, "took %d tries\n", j);
return 0;
}

View File

@ -0,0 +1,23 @@
/*
* This file is part of the coreboot project.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __LIPPERT_SEMA_H__
#define __LIPPERT_SEMA_H__
/* Signal SEMA watchdog a successful boot.
* Returns < 0 is SMBus message failed after
* several retries.
*/
int sema_send_alive(void);
#endif

View File

@ -27,3 +27,7 @@ romstage-y += OemCustomize.c
ramstage-y += buildOpts.c ramstage-y += buildOpts.c
ramstage-y += BiosCallOuts.c ramstage-y += BiosCallOuts.c
ramstage-y += OemCustomize.c ramstage-y += OemCustomize.c
# Minimal SEMA watchdog support
romstage-y += ../frontrunner-af/sema.c
ramstage-y += ../frontrunner-af/sema.c

View File

@ -27,33 +27,11 @@
#include "SBPLATFORM.h" #include "SBPLATFORM.h"
#include "OEM.h" /* SMBUS0_BASE_ADDRESS */ #include "OEM.h" /* SMBUS0_BASE_ADDRESS */
#include <southbridge/amd/cimx/sb800/gpio_oem.h> #include <southbridge/amd/cimx/sb800/gpio_oem.h>
#include "mainboard/lippert/frontrunner-af/sema.h"
/* Write data block to slave on SMBUS0. */
#define SMB0_STATUS ((SMBUS0_BASE_ADDRESS) + 0)
#define SMB0_CONTROL ((SMBUS0_BASE_ADDRESS) + 2)
#define SMB0_HOSTCMD ((SMBUS0_BASE_ADDRESS) + 3)
#define SMB0_ADDRESS ((SMBUS0_BASE_ADDRESS) + 4)
#define SMB0_DATA0 ((SMBUS0_BASE_ADDRESS) + 5)
#define SMB0_BLOCKDATA ((SMBUS0_BASE_ADDRESS) + 7)
static int smb_write_blk(u8 slave, u8 command, u8 length, const u8 *data)
{
__outbyte(SMB0_STATUS, 0x1E); // clear error status
__outbyte(SMB0_ADDRESS, slave & ~1); // slave addr + direction = out
__outbyte(SMB0_HOSTCMD, command); // or destination offset
__outbyte(SMB0_DATA0, length); // sent before data
__inbyte(SMB0_CONTROL); // reset block data array
while (length--)
__outbyte(SMB0_BLOCKDATA, *(data++));
__outbyte(SMB0_CONTROL, 0x54); // execute block write, no IRQ
while (__inbyte(SMB0_STATUS) == 0x01); // busy, no errors
return __inbyte(SMB0_STATUS) ^ 0x02; // 0x02 = completed, no errors
}
static void init(struct device *dev) static void init(struct device *dev)
{ {
volatile u8 *spi_base; // base addr of Hudson's SPI host controller volatile u8 *spi_base; // base addr of Hudson's SPI host controller
int i;
printk(BIOS_DEBUG, CONFIG_MAINBOARD_PART_NUMBER " ENTER %s\n", __func__); printk(BIOS_DEBUG, CONFIG_MAINBOARD_PART_NUMBER " ENTER %s\n", __func__);
/* Init Hudson GPIOs. */ /* Init Hudson GPIOs. */
@ -93,11 +71,11 @@ static void init(struct device *dev)
/* Notify the SMC we're alive and kicking, or after a while it will /* Notify the SMC we're alive and kicking, or after a while it will
* effect a power cycle and switch to the alternate BIOS chip. * effect a power cycle and switch to the alternate BIOS chip.
* Should be done as late as possible. */ * Should be done as late as possible.
printk(BIOS_INFO, "Sending BIOS alive message\n"); * Failure here does not matter if watchdog was already disabled,
const u8 i_am_alive[] = { 0x03 }; //bit2 = SEL_DP0: 0 = DDI2, 1 = LVDS * by configuration or previous boot, so ignore return value.
if ((i = smb_write_blk(0x50, 0x25, sizeof(i_am_alive), i_am_alive))) */
printk(BIOS_ERR, "smb_write_blk failed: %d\n", i); sema_send_alive();
printk(BIOS_DEBUG, CONFIG_MAINBOARD_PART_NUMBER " EXIT %s\n", __func__); printk(BIOS_DEBUG, CONFIG_MAINBOARD_PART_NUMBER " EXIT %s\n", __func__);
} }