x86: apl: Fix save/restore of ITSS priorities
The FSP-S changes the ITSS priorities. The code that tries to save it
before running FSP-S and restore it afterwards does not work as U-Boot
relocates in between the save and restore. This means that the driver
data saved before relocation is lost and the new driver just sees zeroes.
Fix this by allocating space in the relocated memory for the ITSS data.
Save it there and access it from the driver after relocation.
This fixes interrupt handling on coral.
Also drop the log_msg_ret() in irq_first_device_type() since this function
can be called speculatively in places where we are not sure if there is
an interrupt controller of that type. The resulting log errors are
confusing when there is no error.
Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>
diff --git a/arch/x86/cpu/apollolake/fsp_s.c b/arch/x86/cpu/apollolake/fsp_s.c
index 3a54297..e54b0ac 100644
--- a/arch/x86/cpu/apollolake/fsp_s.c
+++ b/arch/x86/cpu/apollolake/fsp_s.c
@@ -160,11 +160,6 @@
ret = irq_first_device_type(X86_IRQT_ITSS, &itss);
if (ret)
return log_msg_ret("no itss", ret);
- /*
- * Snapshot the current GPIO IRQ polarities. FSP is setting a default
- * policy that doesn't honour boards' requirements
- */
- irq_snapshot_polarities(itss);
/*
* Clear the GPI interrupt status and enable registers. These
@@ -203,7 +198,11 @@
ret = irq_first_device_type(X86_IRQT_ITSS, &itss);
if (ret)
return log_msg_ret("no itss", ret);
- /* Restore GPIO IRQ polarities back to previous settings */
+
+ /*
+ * Restore GPIO IRQ polarities back to previous settings. This was
+ * stored in reserve_arch() - see X86_IRQT_ITSS
+ */
irq_restore_polarities(itss);
/* soc_init() */
diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c
index 23a4d63..9ef797b 100644
--- a/arch/x86/cpu/cpu.c
+++ b/arch/x86/cpu/cpu.c
@@ -25,6 +25,7 @@
#include <dm.h>
#include <errno.h>
#include <init.h>
+#include <irq.h>
#include <log.h>
#include <malloc.h>
#include <syscon.h>
@@ -269,9 +270,11 @@
#ifndef CONFIG_EFI_STUB
int reserve_arch(void)
{
-#ifdef CONFIG_ENABLE_MRC_CACHE
- mrccache_reserve();
-#endif
+ struct udevice *itss;
+ int ret;
+
+ if (IS_ENABLED(CONFIG_ENABLE_MRC_CACHE))
+ mrccache_reserve();
#ifdef CONFIG_SEABIOS
high_table_reserve();
@@ -288,6 +291,15 @@
fsp_save_s3_stack();
}
}
+ ret = irq_first_device_type(X86_IRQT_ITSS, &itss);
+ if (!ret) {
+ /*
+ * Snapshot the current GPIO IRQ polarities. FSP-S is about to
+ * run and will set a default policy that doesn't honour boards'
+ * requirements
+ */
+ irq_snapshot_polarities(itss);
+ }
return 0;
}
diff --git a/arch/x86/cpu/intel_common/itss.c b/arch/x86/cpu/intel_common/itss.c
index 963afa8..fe84ebe 100644
--- a/arch/x86/cpu/intel_common/itss.c
+++ b/arch/x86/cpu/intel_common/itss.c
@@ -65,14 +65,23 @@
int i;
reg_start = start / IRQS_PER_IPC;
- reg_end = (end + IRQS_PER_IPC - 1) / IRQS_PER_IPC;
+ reg_end = DIV_ROUND_UP(end, IRQS_PER_IPC);
+ log_info("ITSS IRQ Polarities snapshot %p\n", priv->irq_snapshot);
for (i = reg_start; i < reg_end; i++) {
uint reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * i;
priv->irq_snapshot[i] = pcr_read32(dev, reg);
+ log_debug(" - %d, reg %x: irq_snapshot[i] %x\n", i, reg,
+ priv->irq_snapshot[i]);
}
+ /* Save the snapshot for use after relocation */
+ gd->start_addr_sp -= sizeof(*priv);
+ gd->start_addr_sp &= ~0xf;
+ gd->arch.itss_priv = (void *)gd->start_addr_sp;
+ memcpy(gd->arch.itss_priv, priv, sizeof(*priv));
+
return 0;
}
@@ -91,16 +100,26 @@
static int restore_polarities(struct udevice *dev)
{
struct itss_priv *priv = dev_get_priv(dev);
+ struct itss_priv *old_priv;
const int start = GPIO_IRQ_START;
const int end = GPIO_IRQ_END;
int reg_start;
int reg_end;
int i;
+ /* Get the snapshot which was stored by the pre-reloc device */
+ old_priv = gd->arch.itss_priv;
+ if (!old_priv)
+ return log_msg_ret("priv", -EFAULT);
+ memcpy(priv->irq_snapshot, old_priv->irq_snapshot,
+ sizeof(priv->irq_snapshot));
+
show_polarities(dev, "Before");
+ log_info("priv->irq_snapshot %p\n", priv->irq_snapshot);
reg_start = start / IRQS_PER_IPC;
- reg_end = (end + IRQS_PER_IPC - 1) / IRQS_PER_IPC;
+ reg_end = DIV_ROUND_UP(end, IRQS_PER_IPC);
+
for (i = reg_start; i < reg_end; i++) {
u32 mask;
@@ -125,6 +144,8 @@
mask &= ~((1U << irq_start) - 1);
reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * i;
+ log_debug(" - %d, reg %x: mask %x, irq_snapshot[i] %x\n",
+ i, reg, mask, priv->irq_snapshot[i]);
pcr_clrsetbits32(dev, reg, mask, mask & priv->irq_snapshot[i]);
}