From d50341a8f49372c9c93f3df69d536bceeb2f47b0 Mon Sep 17 00:00:00 2001 From: Michael Brandt Date: Thu, 3 Feb 2011 13:08:35 +0100 Subject: db8500: Fix PRCMU mailbox acknowledge With newer PRCMU FW (2.0.6), clearing of the Ack mailbox interrupt is enforced. This patch clears the Ack mailbox interrupt. ST-Ericsson ID: ER 322248 Change-Id: I38c7af5a375230c22b61db6cc46283c01ff39727 Signed-off-by: Michael Brandt Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/14201 Reviewed-by: Par-Olof HAKANSSON Reviewed-by: QATOOLS Reviewed-by: Ulf MORLAND Reviewed-by: Mattias NILSSON Tested-by: Jonas SKARSTAM --- cpu/arm_cortexa9/db8500/prcmu.c | 93 ++++++++++++++++++++++++++++------------- 1 file changed, 64 insertions(+), 29 deletions(-) diff --git a/cpu/arm_cortexa9/db8500/prcmu.c b/cpu/arm_cortexa9/db8500/prcmu.c index a82379f94..efc3fabf3 100644 --- a/cpu/arm_cortexa9/db8500/prcmu.c +++ b/cpu/arm_cortexa9/db8500/prcmu.c @@ -36,6 +36,9 @@ #define PRCM_MBOX_CPU_VAL (PRCMU_BASE + 0x0fc) #define PRCM_MBOX_CPU_SET (PRCMU_BASE + 0x100) +/* register for Ack mailbox interrupts */ +#define PRCM_ARM_IT1_CLEAR (PRCMU_BASE + 0x48C) +#define PRCM_ARM_IT1_VAL (PRCMU_BASE + 0x494) #define PRCM_XP70_CUR_PWR_STATE (tcdm_base + 0xFFC) @@ -59,12 +62,7 @@ #define PRCMU_I2C_READ(slave) \ (((slave) << 1) | I2CREAD | (cpu_is_u8500v2() ? (1 << 6) : 0)) -enum mailbox_t { - REQ_MB0 = 0, /* Uses XP70_IT_EVENT_10 */ - REQ_MB1 = 1, /* Uses XP70_IT_EVENT_11 */ - REQ_MB2 = 2, /* Uses XP70_IT_EVENT_12 */ - REQ_MB5 = 5, /* Uses XP70_IT_EVENT_17 */ -}; +#define I2C_MBOX_BIT (1 << 5) static void *tcdm_base; @@ -90,26 +88,39 @@ static int prcmu_is_ready(void) return ready; } -static int _wait_for_req_complete(enum mailbox_t num) +static int wait_for_i2c_mbx_rdy(void) { - int timeout = 1000; + int timeout = 10000; - /* checking any already on-going transaction */ - while ((readl(PRCM_MBOX_CPU_VAL) & (1 << num)) && timeout--) + if (readl(PRCM_ARM_IT1_VAL) & I2C_MBOX_BIT) { + printf("prcmu: warning i2c mailbox was not acked\n"); + /* clear mailbox 5 ack irq */ + writel(I2C_MBOX_BIT, PRCM_ARM_IT1_CLEAR); + } + + /* check any already on-going transaction */ + while ((readl(PRCM_MBOX_CPU_VAL) & I2C_MBOX_BIT) && timeout--) ; - timeout = 1000; + if (timeout == 0) + return -1; + + return 0; +} + +static int wait_for_i2c_req_done(void) +{ + int timeout = 10000; /* Set an interrupt to XP70 */ - writel(1 << num, PRCM_MBOX_CPU_SET); + writel(I2C_MBOX_BIT, PRCM_MBOX_CPU_SET); - while ((readl(PRCM_MBOX_CPU_VAL) & (1 << num)) && timeout--) + /* wait for mailbox 5 (i2c) ack */ + while (!(readl(PRCM_ARM_IT1_VAL) & I2C_MBOX_BIT) && timeout--) ; - if (!timeout) { - printf("PRCMU operation timed out\n"); + if (timeout == 0) return -1; - } return 0; } @@ -124,6 +135,7 @@ int prcmu_i2c_read(u8 reg, u16 slave) { uint8_t i2c_status; uint8_t i2c_val; + int ret; if (!prcmu_is_ready()) return -1; @@ -131,13 +143,23 @@ int prcmu_i2c_read(u8 reg, u16 slave) dbg_printk("\nprcmu_4500_i2c_read:bank=%x;reg=%x;\n", reg, slave); + ret = wait_for_i2c_mbx_rdy(); + if (ret) { + printf("prcmu_i2c_read: mailbox became not ready\n"); + return ret; + } + /* prepare the data for mailbox 5 */ writeb(PRCMU_I2C_READ(reg), PRCM_REQ_MB5_I2COPTYPE_REG); writeb((1 << 3) | 0x0, PRCM_REQ_MB5_BIT_FIELDS); writeb(slave, PRCM_REQ_MB5_I2CSLAVE); writeb(0, PRCM_REQ_MB5_I2CVAL); - _wait_for_req_complete(REQ_MB5); + ret = wait_for_i2c_req_done(); + if (ret) { + printf("prcmu_i2c_read: mailbox request timed out\n"); + return ret; + } /* retrieve values */ dbg_printk("ack-mb5:transfer status = %x\n", @@ -149,16 +171,14 @@ int prcmu_i2c_read(u8 reg, u16 slave) i2c_status = readb(PRCM_ACK_MB5_STATUS); i2c_val = readb(PRCM_ACK_MB5_VAL); + /* clear mailbox 5 ack irq */ + writel(I2C_MBOX_BIT, PRCM_ARM_IT1_CLEAR); if (i2c_status == I2C_RD_OK) return i2c_val; - else { - - printf("prcmu_i2c_read:read return status= %d\n", - i2c_status); - return -1; - } + printf("prcmu_i2c_read:read return status= %d\n", i2c_status); + return -1; } /** @@ -171,6 +191,7 @@ int prcmu_i2c_read(u8 reg, u16 slave) int prcmu_i2c_write(u8 reg, u16 slave, u8 reg_data) { uint8_t i2c_status; + int ret; if (!prcmu_is_ready()) return -1; @@ -178,14 +199,23 @@ int prcmu_i2c_write(u8 reg, u16 slave, u8 reg_data) dbg_printk("\nprcmu_4500_i2c_write:bank=%x;reg=%x;\n", reg, slave); + ret = wait_for_i2c_mbx_rdy(); + if (ret) { + printf("prcmu_i2c_write: mailbox became not ready\n"); + return ret; + } + /* prepare the data for mailbox 5 */ writeb(PRCMU_I2C_WRITE(reg), PRCM_REQ_MB5_I2COPTYPE_REG); writeb((1 << 3) | 0x0, PRCM_REQ_MB5_BIT_FIELDS); writeb(slave, PRCM_REQ_MB5_I2CSLAVE); writeb(reg_data, PRCM_REQ_MB5_I2CVAL); - dbg_printk("\ncpu_is_u8500v11\n"); - _wait_for_req_complete(REQ_MB5); + ret = wait_for_i2c_req_done(); + if (ret) { + printf("prcmu_i2c_write: mailbox request timed out\n"); + return ret; + } /* retrieve values */ dbg_printk("ack-mb5:transfer status = %x\n", @@ -197,12 +227,14 @@ int prcmu_i2c_write(u8 reg, u16 slave, u8 reg_data) i2c_status = readb(PRCM_ACK_MB5_STATUS); dbg_printk("\ni2c_status = %x\n", i2c_status); + /* clear mailbox 5 ack irq */ + writel(I2C_MBOX_BIT, PRCM_ARM_IT1_CLEAR); + if (i2c_status == I2C_WR_OK) return 0; - else { - printf("ape-i2c: i2c_status : 0x%x\n", i2c_status); - return -1; - } + + printf("prcmu_i2c_write: i2c_status : 0x%x\n", i2c_status); + return -1; } static void prcmu_enable(u32 *reg) @@ -228,4 +260,7 @@ void db8500_prcmu_init(void) prcmu_enable((u32 *)PRCM_I2CCLK_MGT_REG); prcmu_enable((u32 *)PRCM_SDMMCCLK_MGT_REG); + + /* Clean up the mailbox interrupts after pre-u-boot code. */ + writel(I2C_MBOX_BIT, PRCM_ARM_IT1_CLEAR); } -- cgit v1.2.3