[U-Boot,v3,097/108] x86: apollolake: Add ITSS driver
diff mbox series

Message ID 20191021033913.220758-92-sjg@chromium.org
State New
Delegated to: Bin Meng
Headers show
Series
  • x86: Add initial support for apollolake
Related show

Commit Message

Simon Glass Oct. 21, 2019, 3:39 a.m. UTC
This driver models some sort of interrupt thingy but there are so many
abreviations that I cannot find out what it stands for. Possibly something
to do with interrupts.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3:
- Add snapshot/restore for IRQs
- Use the IRQ uclass instead of ITSS

Changes in v2: None

 arch/x86/cpu/apollolake/Makefile            |   1 +
 arch/x86/cpu/apollolake/itss.c              | 214 ++++++++++++++++++++
 arch/x86/include/asm/arch-apollolake/itss.h |  43 ++++
 3 files changed, 258 insertions(+)
 create mode 100644 arch/x86/cpu/apollolake/itss.c
 create mode 100644 arch/x86/include/asm/arch-apollolake/itss.h

Comments

Andy Shevchenko Oct. 21, 2019, 8:41 a.m. UTC | #1
On Mon, Oct 21, 2019 at 6:58 AM Simon Glass <sjg@chromium.org> wrote:
>
> This driver models some sort of interrupt thingy but there are so many
> abreviations that I cannot find out what it stands for. Possibly something
> to do with interrupts.

From documentation.
Interrupt Timer Subsystem

The below code is only small part of what it can do / does.

>  arch/x86/cpu/apollolake/itss.c              | 214 ++++++++++++++++++++

P.S. Heard first time today about it.
Andy Shevchenko Oct. 21, 2019, 8:43 a.m. UTC | #2
On Mon, Oct 21, 2019 at 11:41 AM Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
>
> On Mon, Oct 21, 2019 at 6:58 AM Simon Glass <sjg@chromium.org> wrote:
> >
> > This driver models some sort of interrupt thingy but there are so many
> > abreviations that I cannot find out what it stands for. Possibly something
> > to do with interrupts.
>
> From documentation.
> Interrupt Timer Subsystem
>
> The below code is only small part of what it can do / does.
>
> >  arch/x86/cpu/apollolake/itss.c              | 214 ++++++++++++++++++++
>
> P.S. Heard first time today about it.

Okay, nailed it. It's a re-make of iLB. So, basically this has to be a
part of iLB driver(s).

In BXT it contains legacy (8254, 8259) and standard (HPET, IOAPIC) devices.
Simon Glass Oct. 21, 2019, 10:53 p.m. UTC | #3
Hi Andy,

On Mon, 21 Oct 2019 at 02:44, Andy Shevchenko <andy.shevchenko@gmail.com> wrote:
>
> On Mon, Oct 21, 2019 at 11:41 AM Andy Shevchenko
> <andy.shevchenko@gmail.com> wrote:
> >
> > On Mon, Oct 21, 2019 at 6:58 AM Simon Glass <sjg@chromium.org> wrote:
> > >
> > > This driver models some sort of interrupt thingy but there are so many
> > > abreviations that I cannot find out what it stands for. Possibly something
> > > to do with interrupts.
> >
> > From documentation.
> > Interrupt Timer Subsystem
> >
> > The below code is only small part of what it can do / does.
> >
> > >  arch/x86/cpu/apollolake/itss.c              | 214 ++++++++++++++++++++
> >
> > P.S. Heard first time today about it.
>
> Okay, nailed it. It's a re-make of iLB. So, basically this has to be a
> part of iLB driver(s).
>
> In BXT it contains legacy (8254, 8259) and standard (HPET, IOAPIC) devices.

OK. Where is the iLB driver? So are any changes needed for this patch?

Regards,
Simon
Andy Shevchenko Oct. 22, 2019, 8:22 a.m. UTC | #4
On Tue, Oct 22, 2019 at 1:54 AM Simon Glass <sjg@chromium.org> wrote:
> On Mon, 21 Oct 2019 at 02:44, Andy Shevchenko <andy.shevchenko@gmail.com> wrote:

> OK. Where is the iLB driver? So are any changes needed for this patch?

I guess in U-Boot we call it LPC... (What a mess with all this abbreviations!)
Simon Glass Oct. 22, 2019, 1:50 p.m. UTC | #5
Hi Andy,

On Tue, 22 Oct 2019 at 02:23, Andy Shevchenko <andy.shevchenko@gmail.com> wrote:
>
> On Tue, Oct 22, 2019 at 1:54 AM Simon Glass <sjg@chromium.org> wrote:
> > On Mon, 21 Oct 2019 at 02:44, Andy Shevchenko <andy.shevchenko@gmail.com> wrote:
>
> > OK. Where is the iLB driver? So are any changes needed for this patch?
>
> I guess in U-Boot we call it LPC... (What a mess with all this abbreviations!)

OK. So is this right?

LPC - Low-Pin-Count bus
iLB - Intel Legacy Block

Regards,
Simon
Andy Shevchenko Oct. 22, 2019, 6:56 p.m. UTC | #6
On Tue, Oct 22, 2019 at 4:51 PM Simon Glass <sjg@chromium.org> wrote:
> On Tue, 22 Oct 2019 at 02:23, Andy Shevchenko <andy.shevchenko@gmail.com> wrote:
> > On Tue, Oct 22, 2019 at 1:54 AM Simon Glass <sjg@chromium.org> wrote:
> > > On Mon, 21 Oct 2019 at 02:44, Andy Shevchenko <andy.shevchenko@gmail.com> wrote:
> >
> > > OK. Where is the iLB driver? So are any changes needed for this patch?
> >
> > I guess in U-Boot we call it LPC... (What a mess with all this abbreviations!)
>
> OK. So is this right?
>
> LPC - Low-Pin-Count bus
> iLB - Intel Legacy Block

Yes.

Patch
diff mbox series

diff --git a/arch/x86/cpu/apollolake/Makefile b/arch/x86/cpu/apollolake/Makefile
index 0615bb120d3..edd7e49154b 100644
--- a/arch/x86/cpu/apollolake/Makefile
+++ b/arch/x86/cpu/apollolake/Makefile
@@ -6,6 +6,7 @@  obj-$(CONFIG_SPL_BUILD) += systemagent.o
 
 obj-y += gpio.o
 obj-y += hostbridge.o
+obj-y += itss.o
 obj-y += lpss.o
 obj-y += pmc.o
 obj-y += uart.o
diff --git a/arch/x86/cpu/apollolake/itss.c b/arch/x86/cpu/apollolake/itss.c
new file mode 100644
index 00000000000..8789f8e6bb9
--- /dev/null
+++ b/arch/x86/cpu/apollolake/itss.c
@@ -0,0 +1,214 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Something to do with Interrupts, but I don't know what ITSS stands for
+ *
+ * Copyright (C) 2017 Intel Corporation.
+ * Copyright (C) 2017 Siemens AG
+ * Copyright 2019 Google LLC
+ *
+ * Taken from coreboot itss.c
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dt-structs.h>
+#include <irq.h>
+#include <p2sb.h>
+#include <spl.h>
+#include <asm/arch/itss.h>
+
+struct apl_itss_platdata {
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	/* Put this first since driver model will copy the data here */
+	struct dtd_intel_apl_itss dtplat;
+#endif
+};
+
+/* struct pmc_route - Routing for PMC to GPIO */
+struct pmc_route {
+	u32 pmc;
+	u32 gpio;
+};
+
+struct apl_itss_priv {
+	struct pmc_route *route;
+	uint route_count;
+	u32 irq_snapshot[NUM_IPC_REGS];
+};
+
+static int apl_set_polarity(struct udevice *dev, uint irq, bool active_low)
+{
+	u32 mask;
+	uint reg;
+
+	if (irq > ITSS_MAX_IRQ)
+		return -EINVAL;
+
+	reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * (irq / IRQS_PER_IPC);
+	mask = 1 << (irq % IRQS_PER_IPC);
+
+	pcr_clrsetbits32(dev, reg, mask, active_low ? mask : 0);
+
+	return 0;
+}
+
+#ifndef CONFIG_TPL_BUILD
+static int apl_snapshot_polarities(struct udevice *dev)
+{
+	struct apl_itss_priv *priv = dev_get_priv(dev);
+	const int start = GPIO_IRQ_START;
+	const int end = GPIO_IRQ_END;
+	int reg_start;
+	int reg_end;
+	int i;
+
+	reg_start = start / IRQS_PER_IPC;
+	reg_end = (end + IRQS_PER_IPC - 1) / IRQS_PER_IPC;
+
+	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);
+	}
+
+	return 0;
+}
+
+static void show_polarities(struct udevice *dev, const char *msg)
+{
+	int i;
+
+	log_info("ITSS IRQ Polarities %s:\n", msg);
+	for (i = 0; i < NUM_IPC_REGS; i++) {
+		uint reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * i;
+
+		log_info("IPC%d: 0x%08x\n", i, pcr_read32(dev, reg));
+	}
+}
+
+static int apl_restore_polarities(struct udevice *dev)
+{
+	struct apl_itss_priv *priv = dev_get_priv(dev);
+	const int start = GPIO_IRQ_START;
+	const int end = GPIO_IRQ_END;
+	int reg_start;
+	int reg_end;
+	int i;
+
+	show_polarities(dev, "Before");
+
+	reg_start = start / IRQS_PER_IPC;
+	reg_end = (end + IRQS_PER_IPC - 1) / IRQS_PER_IPC;
+
+	for (i = reg_start; i < reg_end; i++) {
+		u32 mask;
+		u16 reg;
+		int irq_start;
+		int irq_end;
+
+		irq_start = i * IRQS_PER_IPC;
+		irq_end = min(irq_start + IRQS_PER_IPC - 1, ITSS_MAX_IRQ);
+
+		if (start > irq_end)
+			continue;
+		if (end < irq_start)
+			break;
+
+		/* Track bits within the bounds of of the register */
+		irq_start = max(start, irq_start) % IRQS_PER_IPC;
+		irq_end = min(end, irq_end) % IRQS_PER_IPC;
+
+		/* Create bitmask of the inclusive range of start and end */
+		mask = (((1U << irq_end) - 1) | (1U << irq_end));
+		mask &= ~((1U << irq_start) - 1);
+
+		reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * i;
+		pcr_clrsetbits32(dev, reg, mask, mask & priv->irq_snapshot[i]);
+	}
+
+	show_polarities(dev, "After");
+
+	return 0;
+}
+#endif
+
+static int apl_route_pmc_gpio_gpe(struct udevice *dev, uint pmc_gpe_num)
+{
+	struct apl_itss_priv *priv = dev_get_priv(dev);
+	struct pmc_route *route;
+	int i;
+
+	for (i = 0, route = priv->route; i < priv->route_count; i++, route++) {
+		if (pmc_gpe_num == route->pmc)
+			return route->gpio;
+	}
+
+	return -ENOENT;
+}
+
+static int apl_itss_ofdata_to_platdata(struct udevice *dev)
+{
+	struct apl_itss_priv *priv = dev_get_priv(dev);
+	int ret;
+
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct apl_itss_platdata *plat = dev_get_platdata(dev);
+	struct dtd_intel_apl_itss *dtplat = &plat->dtplat;
+
+	/*
+	 * It would be nice to do this in the bind() method, but with
+	 * of-platdata binding happens in the order that DM finds things in the
+	 * linker list (i.e. alphabetical order by driver name). So the GPIO
+	 * device may well be bound before its parent (p2sb), and this call
+	 * will fail if p2sb is not bound yet.
+	 *
+	 * TODO(sjg@chromium.org): Add a parent pointer to child devices in dtoc
+	 */
+	ret = p2sb_set_port_id(dev, dtplat->intel_p2sb_port_id);
+	if (ret)
+		return log_msg_ret("Could not set port id", ret);
+	priv->route = (struct pmc_route *)dtplat->intel_pmc_routes;
+	priv->route_count = ARRAY_SIZE(dtplat->intel_pmc_routes) /
+		 sizeof(struct pmc_route);
+#else
+	int size;
+
+	size = dev_read_size(dev, "intel,pmc-routes");
+	if (size < 0)
+		return size;
+	priv->route = malloc(size);
+	if (!priv->route)
+		return -ENOMEM;
+	ret = dev_read_u32_array(dev, "intel,pmc-routes", (u32 *)priv->route,
+				 size / sizeof(fdt32_t));
+	if (ret)
+		return log_msg_ret("Cannot read pmc-routes", ret);
+	priv->route_count = size / sizeof(struct pmc_route);
+#endif
+
+	return 0;
+}
+
+static const struct irq_ops apl_itss_ops = {
+	.route_pmc_gpio_gpe	= apl_route_pmc_gpio_gpe,
+	.set_polarity	= apl_set_polarity,
+#ifndef CONFIG_TPL_BUILD
+	.snapshot_polarities = apl_snapshot_polarities,
+	.restore_polarities = apl_restore_polarities,
+#endif
+};
+
+static const struct udevice_id apl_itss_ids[] = {
+	{ .compatible = "intel,apl-itss"},
+	{ }
+};
+
+U_BOOT_DRIVER(apl_itss_drv) = {
+	.name		= "intel_apl_itss",
+	.id		= UCLASS_IRQ,
+	.of_match	= apl_itss_ids,
+	.ops		= &apl_itss_ops,
+	.ofdata_to_platdata = apl_itss_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct apl_itss_platdata),
+	.priv_auto_alloc_size = sizeof(struct apl_itss_priv),
+};
diff --git a/arch/x86/include/asm/arch-apollolake/itss.h b/arch/x86/include/asm/arch-apollolake/itss.h
new file mode 100644
index 00000000000..c8fbb7b19c3
--- /dev/null
+++ b/arch/x86/include/asm/arch-apollolake/itss.h
@@ -0,0 +1,43 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2017 Intel Corporation.
+ * Copyright 2019 Google LLC
+ *
+ * Modified from coreboot itss.h
+ */
+
+#ifndef ASM_ARCH_ITSS_H
+#define ASM_ARCH_ITSS_H
+
+#define GPIO_IRQ_START	50
+#define GPIO_IRQ_END	ITSS_MAX_IRQ
+
+#define ITSS_MAX_IRQ	119
+#define IRQS_PER_IPC	32
+#define NUM_IPC_REGS	((ITSS_MAX_IRQ + IRQS_PER_IPC - 1) / IRQS_PER_IPC)
+
+/* Max PXRC registers in ITSS */
+#define MAX_PXRC_CONFIG	(PCR_ITSS_PIRQH_ROUT - PCR_ITSS_PIRQA_ROUT + 1)
+
+/* PIRQA Routing Control Register */
+#define PCR_ITSS_PIRQA_ROUT	0x3100
+/* PIRQB Routing Control Register */
+#define PCR_ITSS_PIRQB_ROUT	0x3101
+/* PIRQC Routing Control Register */
+#define PCR_ITSS_PIRQC_ROUT	0x3102
+/* PIRQD Routing Control Register */
+#define PCR_ITSS_PIRQD_ROUT	0x3103
+/* PIRQE Routing Control Register */
+#define PCR_ITSS_PIRQE_ROUT	0x3104
+/* PIRQF Routing Control Register */
+#define PCR_ITSS_PIRQF_ROUT	0x3105
+/* PIRQG Routing Control Register */
+#define PCR_ITSS_PIRQG_ROUT	0x3106
+/* PIRQH Routing Control Register */
+#define PCR_ITSS_PIRQH_ROUT	0x3107
+/* ITSS Interrupt polarity control */
+#define PCR_ITSS_IPC0_CONF	0x3200
+/* ITSS Power reduction control */
+#define PCR_ITSS_ITSSPRC	0x3300
+
+#endif /* ASM_ARCH_ITSS_H */