spmi-pmic-arb: ignore faulty interrupt bits
Due to some faulty HW/SW interaction during boot loader time, the first accumulator bit may be incorectly set. When the peripheral represented by this bit is not owned by the application processor, it stays set forever, confusing the interrupt controller to think that it get interrupted by that peripheral when it isn't. To amend this problem, we read the accumulator value at boot time and compare that value to the accumulator when new interrupt is handled. If a bit reperesenting a peripheral was set at probe time, then it is ignored. Change-Id: Iab3d70d6c63520ac7be1e77aba113cf5f46ec003 Signed-off-by: Gilad Avidov <gavidov@codeaurora.org>
This commit is contained in:
parent
c1a5a21e73
commit
e3aa950ec4
|
@ -190,6 +190,10 @@ struct spmi_pmic_arb_ver {
|
|||
* @fmt_cmd formats a command to be set into PMIC_ARBq_CHNLn_CMD
|
||||
* @chnl_ofst calculates offset of the base of a channel reg space
|
||||
* @ee execution environment id
|
||||
* @irq_acc0_init_val initial value of the interrupt accumulator at probe time.
|
||||
* Use for an HW workaround. On handling interrupts, the first accumulator
|
||||
* register will be compared against this value, and bits which are set at
|
||||
* boot will be ignored.
|
||||
*/
|
||||
struct spmi_pmic_arb_dev {
|
||||
struct spmi_controller controller;
|
||||
|
@ -213,6 +217,7 @@ struct spmi_pmic_arb_dev {
|
|||
const struct spmi_pmic_arb_ver *ver;
|
||||
u8 *ppid_2_chnl_tbl;
|
||||
u32 prev_prtcl_irq_stat;
|
||||
u32 irq_acc0_init_val;
|
||||
};
|
||||
|
||||
static struct spmi_pmic_arb_dev *the_pmic_arb;
|
||||
|
@ -886,6 +891,12 @@ __pmic_arb_periph_irq(int irq, void *dev_id, bool show)
|
|||
status = readl_relaxed(pmic_arb->intr +
|
||||
pmic_arb->ver->owner_acc_status(ee, i));
|
||||
|
||||
if ((i == 0) && (status & pmic_arb->irq_acc0_init_val)) {
|
||||
dev_dbg(pmic_arb->dev, "Ignoring IRQ acc[0] mask:0x%x\n",
|
||||
status & pmic_arb->irq_acc0_init_val);
|
||||
status &= ~pmic_arb->irq_acc0_init_val;
|
||||
}
|
||||
|
||||
for (j = 0; status && j < 32; ++j, status >>= 1) {
|
||||
if (status & 0x1) {
|
||||
u8 id = (i * 32) + j;
|
||||
|
@ -1131,13 +1142,6 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, pmic_arb->pic_irq,
|
||||
pmic_arb_periph_irq, IRQF_TRIGGER_HIGH, pdev->name, pmic_arb);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "request IRQ failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Get properties from the device tree */
|
||||
ret = spmi_pmic_arb_get_property(pdev, "cell-index", &cell_index);
|
||||
if (ret)
|
||||
|
@ -1175,11 +1179,24 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
|
|||
pmic_arb->controller.dev.parent = pdev->dev.parent;
|
||||
pmic_arb->controller.dev.of_node = of_node_get(pdev->dev.of_node);
|
||||
|
||||
pmic_arb->irq_acc0_init_val = readl_relaxed(pmic_arb->intr +
|
||||
pmic_arb->ver->owner_acc_status(pmic_arb->ee, 0));
|
||||
if (pmic_arb->irq_acc0_init_val)
|
||||
dev_err(&pdev->dev, "non-zero irq-accumulator[0]:0x%x\n",
|
||||
pmic_arb->irq_acc0_init_val);
|
||||
|
||||
/* Callbacks */
|
||||
pmic_arb->controller.cmd = pmic_arb_cmd;
|
||||
pmic_arb->controller.read_cmd = pmic_arb_read_cmd;
|
||||
pmic_arb->controller.write_cmd = pmic_arb_write_cmd;
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, pmic_arb->pic_irq,
|
||||
pmic_arb_periph_irq, IRQF_TRIGGER_HIGH, pdev->name, pmic_arb);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "request IRQ failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = spmi_add_controller(&pmic_arb->controller);
|
||||
if (ret)
|
||||
goto err_add_controller;
|
||||
|
|
Loading…
Reference in New Issue