diff options
author | Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com> | 2012-11-30 18:45:48 +0000 |
---|---|---|
committer | Jon Medhurst <tixy@linaro.org> | 2013-04-29 09:43:14 +0100 |
commit | 115a0591a2dbc54ed825ca93bc57c490477eac77 (patch) | |
tree | 34153ef9b2363c7d7b150a64e06ab27e2809d314 /drivers | |
parent | 3eb9d1401200e998fb9af53d4afe4f3959a2b19b (diff) |
misc: vexpress/spc: update error handling code based on firmware response
The latest firmware has the following protocol for PWC_STATUS update
to communicate status/faults:
CA15 DVFS request: 0x0001 complete, 0x0002 error
CA7 DVFS request: 0x0010 complete, 0x0020 error
SPC_SYS_CFG request: 0x0100 complete, 0x0200 error
This patch updates the driver to handle the error conditions based on
the above protocol.
Signed-off-by: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/misc/vexpress/arm-spc.c | 67 |
1 files changed, 50 insertions, 17 deletions
diff --git a/drivers/misc/vexpress/arm-spc.c b/drivers/misc/vexpress/arm-spc.c index 073a3fc465f..85583d58674 100644 --- a/drivers/misc/vexpress/arm-spc.c +++ b/drivers/misc/vexpress/arm-spc.c @@ -101,6 +101,14 @@ struct vexpress_spc_drvdata { void __iomem *baseaddr; uint32_t a15_clusid; int irq; + uint32_t cur_rsp_mask; + uint32_t cur_rsp_stat; +#define A15_OPP 0 +#define A7_OPP 1 +#define COMMS_OPP 2 +#define STAT_COMPLETE(type) ((1 << 0) << (type << 2)) +#define STAT_ERR(type) ((1 << 1) << (type << 2)) +#define RESPONSE_MASK(type) (STAT_COMPLETE(type) | STAT_ERR(type)) struct semaphore lock; struct completion done; uint32_t freqs[MAX_CLUSTERS][MAX_OPPS]; @@ -271,17 +279,36 @@ static int vexpress_spc_find_perf_index(int cluster, u32 freq) return idx; } +static int vexpress_spc_waitforcompletion(int req_type) +{ + int ret; + + if (!wait_for_completion_interruptible_timeout(&info->done, + usecs_to_jiffies(TIME_OUT_US))) + ret = -ETIMEDOUT; + else + ret = info->cur_rsp_stat & STAT_COMPLETE(req_type) ? 0 : -EIO; + return ret; +} + int vexpress_spc_set_performance(int cluster, u32 freq) { - u32 perf_cfg_reg = 0; - u32 perf_stat_reg = 0; - int ret = 0, perf; + u32 perf_cfg_reg, perf_stat_reg; + int ret, perf, req_type; if (IS_ERR_OR_NULL(info)) return -ENXIO; - perf_cfg_reg = cluster != info->a15_clusid ? PERF_LVL_A7 : PERF_LVL_A15; - perf_stat_reg = cluster != info->a15_clusid ? PERF_REQ_A7 : PERF_REQ_A15; + if (cluster != info->a15_clusid) { + req_type = A7_OPP; + perf_cfg_reg = PERF_LVL_A7; + perf_stat_reg = PERF_REQ_A7; + } else { + req_type = A15_OPP; + perf_cfg_reg = PERF_LVL_A15; + perf_stat_reg = PERF_REQ_A15; + } + perf = vexpress_spc_find_perf_index(cluster, freq); if (perf >= MAX_OPPS) @@ -292,16 +319,17 @@ int vexpress_spc_set_performance(int cluster, u32 freq) init_completion(&info->done); + info->cur_rsp_mask = RESPONSE_MASK(req_type); + writel(perf, info->baseaddr + perf_cfg_reg); - if (!wait_for_completion_interruptible_timeout(&info->done, - usecs_to_jiffies(TIME_OUT_US))) { - ret = -ETIMEDOUT; - } + ret = vexpress_spc_waitforcompletion(req_type); + + info->cur_rsp_mask = 0; up(&info->lock); - return ret; + return ret; } EXPORT_SYMBOL_GPL(vexpress_spc_set_performance); @@ -516,10 +544,12 @@ EXPORT_SYMBOL_GPL(vexpress_spc_check_loaded); irqreturn_t vexpress_spc_irq_handler(int irq, void *data) { struct vexpress_spc_drvdata *drv_data = data; + uint32_t status = readl_relaxed(drv_data->baseaddr + PWC_STATUS); - readl_relaxed(drv_data->baseaddr + PWC_STATUS); - - complete(&drv_data->done); + if (info->cur_rsp_mask & status) { + info->cur_rsp_stat = status; + complete(&drv_data->done); + } return IRQ_HANDLED; } @@ -533,15 +563,18 @@ static int read_sys_cfg(int func, int offset, uint32_t *data) init_completion(&info->done); + info->cur_rsp_mask = RESPONSE_MASK(COMMS_OPP); + /* Set the control value */ writel(SYS_CFG_START | func | offset >> 2, info->baseaddr + COMMS); - if (!wait_for_completion_interruptible_timeout(&info->done, - usecs_to_jiffies(TIME_OUT_US))) - ret = -ETIMEDOUT; - else + ret = vexpress_spc_waitforcompletion(COMMS_OPP); + + if (!ret) *data = readl(info->baseaddr + SYS_CFG_RDATA); + info->cur_rsp_mask = 0; + up(&info->lock); return ret; |