aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-10-08 13:19:21 +1100
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-10-08 13:19:21 +1100
commit10fb2e543b666ec92f57068daf2c2d9b151c6ba2 (patch)
tree808c5ff7b6f174f69914abfc97bffb9013e84506
parent37d2ac7a132fb73cd83cd9c978e0e3e30325a6e0 (diff)
downloadskiboot-10fb2e543b666ec92f57068daf2c2d9b151c6ba2.zip
skiboot-10fb2e543b666ec92f57068daf2c2d9b151c6ba2.tar.gz
skiboot-10fb2e543b666ec92f57068daf2c2d9b151c6ba2.tar.bz2
ast/io: Fix a number of issues with SuperIO access
The code to access AST registers via the iLPC->AHB bridge was very fragile and relied on the SIO to be kept unlocked with the right device selected. This got broken when adding the new UART configuration among other things. Rework this to create a pair of get/put() helpers to use to access a given SIO device, which take care of doing the appropriate device selection when needed and also take/release the SIO spinlock. This fixes Flash/NVRAM setup which got broken along the way and also makes the fixup for the VUART interrupts actually work. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--hw/ast-bmc/ast-io.c130
1 files changed, 74 insertions, 56 deletions
diff --git a/hw/ast-bmc/ast-io.c b/hw/ast-bmc/ast-io.c
index e8bad14..2553104 100644
--- a/hw/ast-bmc/ast-io.c
+++ b/hw/ast-bmc/ast-io.c
@@ -91,7 +91,21 @@
#include "ast.h"
+enum {
+ BMC_SIO_DEV_NONE = -1,
+ BMC_SIO_DEV_UART1 = 2,
+ BMC_SIO_DEV_UART2 = 3,
+ BMC_SIO_DEV_SWC = 4,
+ BMC_SIO_DEV_KBC = 5,
+ BMC_SIO_DEV_P80 = 7,
+ BMC_SIO_DEV_UART3 = 0xb,
+ BMC_SIO_DEV_UART4 = 0xc,
+ BMC_SIO_DEV_LPC2AHB = 0xd,
+ BMC_SIO_DEV_MBOX = 0xe,
+};
+
static struct lock bmc_sio_lock = LOCK_UNLOCKED;
+static int bmc_sio_cur_dev = BMC_SIO_DEV_NONE;
/*
* SuperIO indirect accesses
@@ -108,12 +122,45 @@ static uint8_t bmc_sio_inb(uint8_t reg)
return lpc_inb(0x2f);
}
+static void bmc_sio_get(int dev)
+{
+ lock(&bmc_sio_lock);
+
+ if (bmc_sio_cur_dev == dev || dev < 0)
+ return;
+
+ if (bmc_sio_cur_dev == BMC_SIO_DEV_NONE) {
+ /* Send SuperIO password */
+ lpc_outb(0xa5, 0x2e);
+ lpc_outb(0xa5, 0x2e);
+ }
+
+ /* Select logical dev */
+ bmc_sio_outb(dev, 0x07);
+
+ bmc_sio_cur_dev = dev;
+}
+
+static void bmc_sio_put(bool lock_sio)
+{
+ if (lock_sio) {
+ /* Re-lock SuperIO */
+ lpc_outb(0xaa, 0x2e);
+
+ bmc_sio_cur_dev = BMC_SIO_DEV_NONE;
+ }
+ unlock(&bmc_sio_lock);
+}
+
/*
* AHB accesses via iLPC->AHB in SuperIO. Works on byteswapped
* values (ie. Little Endian registers)
*/
static void bmc_sio_ahb_prep(uint32_t reg, uint8_t type)
{
+ /* Enable iLPC->AHB */
+ bmc_sio_outb(0x01, 0x30);
+
/* Address */
bmc_sio_outb((reg >> 24) & 0xff, 0xf0);
bmc_sio_outb((reg >> 16) & 0xff, 0xf1);
@@ -126,7 +173,7 @@ static void bmc_sio_ahb_prep(uint32_t reg, uint8_t type)
static void bmc_sio_ahb_writel(uint32_t val, uint32_t reg)
{
- lock(&bmc_sio_lock);
+ bmc_sio_get(BMC_SIO_DEV_LPC2AHB);
bmc_sio_ahb_prep(reg, 2);
@@ -139,14 +186,14 @@ static void bmc_sio_ahb_writel(uint32_t val, uint32_t reg)
/* Trigger */
bmc_sio_outb(0xcf, 0xfe);
- unlock(&bmc_sio_lock);
+ bmc_sio_put(false);
}
static uint32_t bmc_sio_ahb_readl(uint32_t reg)
{
uint32_t val = 0;
- lock(&bmc_sio_lock);
+ bmc_sio_get(BMC_SIO_DEV_LPC2AHB);
bmc_sio_ahb_prep(reg, 2);
@@ -159,28 +206,11 @@ static uint32_t bmc_sio_ahb_readl(uint32_t reg)
val = (val << 8) | bmc_sio_inb(0xf6);
val = (val << 8) | bmc_sio_inb(0xf7);
- unlock(&bmc_sio_lock);
+ bmc_sio_put(false);
return val;
}
-static void bmc_sio_ahb_init(void)
-{
- /* Send SuperIO password */
- lpc_outb(0xa5, 0x2e);
- lpc_outb(0xa5, 0x2e);
-
- /* Select logical dev d */
- bmc_sio_outb(0x0d, 0x07);
-
- /* Enable iLPC->AHB */
- bmc_sio_outb(0x01, 0x30);
-
- /* We leave the SuperIO enabled and unlocked for
- * subsequent accesses.
- */
-}
-
/*
* External API
*
@@ -288,56 +318,55 @@ int ast_copy_from_ahb(void *dst, uint32_t reg, uint32_t len)
static void ast_setup_sio_irq_polarity(void)
{
- /* Send SuperIO password */
- lpc_outb(0xa5, 0x2e);
- lpc_outb(0xa5, 0x2e);
-
/* Select logical dev 2 */
- bmc_sio_outb(0x02, 0x07);
+ bmc_sio_get(BMC_SIO_DEV_UART1);
bmc_sio_outb(0x01, 0x71); /* level low */
+ bmc_sio_put(false);
/* Select logical dev 3 */
- bmc_sio_outb(0x03, 0x07);
+ bmc_sio_get(BMC_SIO_DEV_UART2);
bmc_sio_outb(0x01, 0x71); /* irq level low */
+ bmc_sio_put(false);
/* Select logical dev 4 */
- bmc_sio_outb(0x04, 0x07);
+ bmc_sio_get(BMC_SIO_DEV_SWC);
bmc_sio_outb(0x01, 0x71); /* irq level low */
+ bmc_sio_put(false);
/* Select logical dev 5 */
- bmc_sio_outb(0x05, 0x07);
+ bmc_sio_get(BMC_SIO_DEV_KBC);
bmc_sio_outb(0x01, 0x71); /* irq level low */
bmc_sio_outb(0x01, 0x73); /* irq level low */
+ bmc_sio_put(false);
/* Select logical dev 7 */
- bmc_sio_outb(0x07, 0x07);
+ bmc_sio_get(BMC_SIO_DEV_P80);
bmc_sio_outb(0x01, 0x71); /* irq level low */
+ bmc_sio_put(false);
/* Select logical dev d */
- bmc_sio_outb(0x0b, 0x07);
+ bmc_sio_get(BMC_SIO_DEV_UART3);
bmc_sio_outb(0x01, 0x71); /* irq level low */
+ bmc_sio_put(false);
/* Select logical dev c */
- bmc_sio_outb(0x0c, 0x07);
+ bmc_sio_get(BMC_SIO_DEV_UART4);
bmc_sio_outb(0x01, 0x71); /* irq level low */
+ bmc_sio_put(false);
/* Select logical dev d */
- bmc_sio_outb(0x0d, 0x07);
+ bmc_sio_get(BMC_SIO_DEV_LPC2AHB);
bmc_sio_outb(0x01, 0x71); /* irq level low */
+ bmc_sio_put(false);
/* Select logical dev e */
- bmc_sio_outb(0x0e, 0x07);
+ bmc_sio_get(BMC_SIO_DEV_MBOX);
bmc_sio_outb(0x01, 0x71); /* irq level low */
-
- /* Re-lock SuperIO */
- lpc_outb(0xaa, 0x2e);
+ bmc_sio_put(true);
}
void ast_io_init(void)
{
- /* Initialize iLPC->AHB bridge */
- bmc_sio_ahb_init();
-
/* Configure the LPC->AHB bridge for PNOR access (just in case) */
bmc_sio_ahb_writel(0x30000e00, LPC_HICR7);
bmc_sio_ahb_writel(0xfe0001ff, LPC_HICR8);
@@ -374,6 +403,7 @@ void ast_setup_vuart1(uint16_t io_base, uint8_t irq)
v = bmc_sio_ahb_readl(VUART1_GCTRLA);
v = v & ~2u;
bmc_sio_ahb_writel(v, VUART1_GCTRLA);
+ v = bmc_sio_ahb_readl(VUART1_GCTRLA);
/* IRQ number */
v = bmc_sio_ahb_readl(VUART1_GCTRLB);
@@ -388,12 +418,7 @@ void ast_setup_vuart1(uint16_t io_base, uint8_t irq)
/* Setup SuperIO UART 1 */
void ast_setup_sio_uart1(uint16_t io_base, uint8_t irq)
{
- /* Send SuperIO password */
- lpc_outb(0xa5, 0x2e);
- lpc_outb(0xa5, 0x2e);
-
- /* Select logical dev 2 */
- bmc_sio_outb(0x02, 0x07);
+ bmc_sio_get(BMC_SIO_DEV_UART1);
/* Disable UART1 for configuration */
bmc_sio_outb(0x00, 0x30);
@@ -407,22 +432,15 @@ void ast_setup_sio_uart1(uint16_t io_base, uint8_t irq)
/* Enable UART1 */
bmc_sio_outb(0x01, 0x30);
- /* Re-lock SuperIO */
- lpc_outb(0xaa, 0x2e);
+ bmc_sio_put(true);
}
void ast_disable_sio_uart1(void)
{
- /* Send SuperIO password */
- lpc_outb(0xa5, 0x2e);
- lpc_outb(0xa5, 0x2e);
-
- /* Select logical dev 2 */
- bmc_sio_outb(0x02, 0x07);
+ bmc_sio_get(BMC_SIO_DEV_UART1);
/* Disable UART1 */
bmc_sio_outb(0x00, 0x30);
- /* Re-lock SuperIO */
- lpc_outb(0xaa, 0x2e);
+ bmc_sio_put(true);
}