* Re: [PATCH 0/3] ARM: dts: aspeed: Deprecate g[45]-style compatibles
From: Andrew Jeffery @ 2019-08-01 5:45 UTC (permalink / raw)
To: Linus Walleij
Cc: linux-aspeed, Lee Jones, Rob Herring, Mark Rutland, Joel Stanley,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Linux ARM, linux-kernel@vger.kernel.org, open list:GPIO SUBSYSTEM
In-Reply-To: <9d0f2b20-e6f6-419c-a866-c4a0dd92aa63@www.fastmail.com>
On Tue, 30 Jul 2019, at 10:27, Andrew Jeffery wrote:
>
>
> On Tue, 30 Jul 2019, at 07:23, Linus Walleij wrote:
> > On Wed, Jul 24, 2019 at 10:13 AM Andrew Jeffery <andrew@aj.id.au> wrote:
> >
> > > It's probably best if we push the three patches all through one tree rather
> > > than fragmenting. Is everyone happy if Joel applies them to the aspeed tree?
> >
> > If you are sure it will not collide with parallell work in the
> > pinctrl tree, yes.
> > Acked-by: Linus Walleij <linus.walleij@linaro.org>
> >
> > (If it does collide I'd prefer to take the pinctrl patches and fix the
> > conflicts in my tree.)
>
> Fair enough, I don't know the answer so I'll poke around. I don't
> really mind
> where the series goes in, I just want to avoid landing only part of it
> if I split it up.
Okay, it currently conflicts with my cleanup-devicetree-warnings series.
Joel, do you mind if Linus takes this series through the pinctrl tree, given
the fix to the devicetrees is patch 1/3?
Andrew
^ permalink raw reply
* Re: [PATCH v7 11/20] cpufreq: tegra124: Add suspend and resume support
From: Viresh Kumar @ 2019-08-01 5:40 UTC (permalink / raw)
To: Sowjanya Komatineni
Cc: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
linus.walleij, stefan, mark.rutland, pdeschrijver, pgaikwad,
sboyd, linux-clk, linux-gpio, jckuo, josephl, talho, linux-tegra,
linux-kernel, mperttunen, spatra, robh+dt, digetx, devicetree,
rjw, linux-pm
In-Reply-To: <1564607463-28802-12-git-send-email-skomatineni@nvidia.com>
On 31-07-19, 14:10, Sowjanya Komatineni wrote:
> This patch adds suspend and resume pm ops for cpufreq driver.
>
> PLLP is the safe clock source for CPU during system suspend and
> resume as PLLP rate is below the CPU Fmax at Vmin.
>
> CPUFreq driver suspend switches the CPU clock source to PLLP and
> disables the DFLL clock.
>
> During system resume, warmboot code powers up the CPU with PLLP
> clock source. So CPUFreq driver resume enabled DFLL clock and
> switches CPU back to DFLL clock source.
>
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
> drivers/cpufreq/tegra124-cpufreq.c | 60 ++++++++++++++++++++++++++++++++++++++
> 1 file changed, 60 insertions(+)
Is there any hard dependency of this patch on the rest of the patches?
Can I apply it alone to cpufreq tree ?
--
viresh
^ permalink raw reply
* Re: [PATCH net-next v2 4/4] net: ftgmac100: Select ASPEED MDIO driver for the AST2600
From: Andrew Lunn @ 2019-08-01 3:56 UTC (permalink / raw)
To: Andrew Jeffery
Cc: netdev, davem, robh+dt, mark.rutland, joel, f.fainelli,
hkallweit1, devicetree, linux-arm-kernel, linux-aspeed,
linux-kernel
In-Reply-To: <20190731053959.16293-5-andrew@aj.id.au>
On Wed, Jul 31, 2019 at 03:09:59PM +0930, Andrew Jeffery wrote:
> Ensures we can talk to a PHY via MDIO on the AST2600, as the MDIO
> controller is now separate from the MAC.
>
> Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply
* Re: [PATCH net-next v2 3/4] net: ftgmac100: Add support for DT phy-handle property
From: Andrew Lunn @ 2019-08-01 3:55 UTC (permalink / raw)
To: Andrew Jeffery
Cc: netdev, davem, robh+dt, mark.rutland, joel, f.fainelli,
hkallweit1, devicetree, linux-arm-kernel, linux-aspeed,
linux-kernel
In-Reply-To: <20190731053959.16293-4-andrew@aj.id.au>
On Wed, Jul 31, 2019 at 03:09:58PM +0930, Andrew Jeffery wrote:
> phy-handle is necessary for the AST2600 which separates the MDIO
> controllers from the MAC.
>
> I've tried to minimise the intrusion of supporting the AST2600 to the
> FTGMAC100 by leaving in place the existing MDIO support for the embedded
> MDIO interface. The AST2400 and AST2500 continue to be supported this
> way, as it avoids breaking/reworking existing devicetrees.
>
> The AST2600 support by contrast requires the presence of the phy-handle
> property in the MAC devicetree node to specify the appropriate PHY to
> associate with the MAC. In the event that someone wants to specify the
> MDIO bus topology under the MAC node on an AST2400 or AST2500, the
> current auto-probe approach is done conditional on the absence of an
> "mdio" child node of the MAC.
>
> Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply
* [PATCH v6 2/2] dt-bindings: mtd: Document Macronix raw NAND controller bindings
From: Mason Yang @ 2019-08-01 3:55 UTC (permalink / raw)
To: miquel.raynal, marek.vasut, bbrezillon, dwmw2, computersforpeace,
vigneshr, richard, robh+dt, stefan, mark.rutland
Cc: linux-kernel, linux-mtd, juliensu, paul.burton, liang.yang,
lee.jones, masonccyang, anders.roxell, christophe.kerello, paul,
devicetree
In-Reply-To: <1564631710-30276-1-git-send-email-masonccyang@mxic.com.tw>
Document the bindings used by the Macronix raw NAND controller.
Signed-off-by: Mason Yang <masonccyang@mxic.com.tw>
---
Documentation/devicetree/bindings/mtd/mxic-nand.txt | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mtd/mxic-nand.txt
diff --git a/Documentation/devicetree/bindings/mtd/mxic-nand.txt b/Documentation/devicetree/bindings/mtd/mxic-nand.txt
new file mode 100644
index 0000000..de37d60
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/mxic-nand.txt
@@ -0,0 +1,19 @@
+Macronix Raw NAND Controller Device Tree Bindings
+-------------------------------------------------
+
+Required properties:
+- compatible: should be "mxicy,multi-itfc-v009-nand-morph"
+- reg: should contain 1 entry for the registers
+- interrupts: interrupt line connected to this raw NAND controller
+- clock-names: should contain "ps", "send" and "send_dly"
+- clocks: should contain 3 phandles for the "ps", "send" and
+ "send_dly" clocks
+
+Example:
+
+ nand: nand-controller@43c30000 {
+ compatible = "mxicy,multi-itfc-v009-nand-morph";
+ reg = <0x43c30000 0x10000>;
+ clocks = <&clkwizard 0>, <&clkwizard 1>, <&clkc 15>;
+ clock-names = "send", "send_dly", "ps";
+ };
--
1.9.1
^ permalink raw reply related
* [PATCH v6 1/2] mtd: rawnand: Add Macronix raw NAND controller driver
From: Mason Yang @ 2019-08-01 3:55 UTC (permalink / raw)
To: miquel.raynal, marek.vasut, bbrezillon, dwmw2, computersforpeace,
vigneshr, richard, robh+dt, stefan, mark.rutland
Cc: linux-kernel, linux-mtd, juliensu, paul.burton, liang.yang,
lee.jones, masonccyang, anders.roxell, christophe.kerello, paul,
devicetree
In-Reply-To: <1564631710-30276-1-git-send-email-masonccyang@mxic.com.tw>
Add a driver for Macronix raw NAND controller.
Signed-off-by: Mason Yang <masonccyang@mxic.com.tw>
---
drivers/mtd/nand/raw/Kconfig | 6 +
drivers/mtd/nand/raw/Makefile | 1 +
drivers/mtd/nand/raw/mxic_nand.c | 554 +++++++++++++++++++++++++++++++++++++++
3 files changed, 561 insertions(+)
create mode 100644 drivers/mtd/nand/raw/mxic_nand.c
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index 5a711d8..9cff36a 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -407,6 +407,12 @@ config MTD_NAND_MTK
Enables support for NAND controller on MTK SoCs.
This controller is found on mt27xx, mt81xx, mt65xx SoCs.
+config MTD_NAND_MXIC
+ tristate "Macronix raw NAND controller"
+ depends on HAS_IOMEM || COMPILE_TEST
+ help
+ This selects the Macronix raw NAND controller driver.
+
config MTD_NAND_TEGRA
tristate "NVIDIA Tegra NAND controller"
depends on ARCH_TEGRA || COMPILE_TEST
diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile
index efaf5cd..9b43fbf 100644
--- a/drivers/mtd/nand/raw/Makefile
+++ b/drivers/mtd/nand/raw/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o
obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/
obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o
obj-$(CONFIG_MTD_NAND_MTK) += mtk_ecc.o mtk_nand.o
+obj-$(CONFIG_MTD_NAND_MXIC) += mxic_nand.o
obj-$(CONFIG_MTD_NAND_TEGRA) += tegra_nand.o
obj-$(CONFIG_MTD_NAND_STM32_FMC2) += stm32_fmc2_nand.o
obj-$(CONFIG_MTD_NAND_MESON) += meson_nand.o
diff --git a/drivers/mtd/nand/raw/mxic_nand.c b/drivers/mtd/nand/raw/mxic_nand.c
new file mode 100644
index 0000000..56e816d
--- /dev/null
+++ b/drivers/mtd/nand/raw/mxic_nand.c
@@ -0,0 +1,554 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Macronix International Co., Ltd.
+ *
+ * Author:
+ * Mason Yang <masonccyang@mxic.com.tw>
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/platform_device.h>
+
+#include "internals.h"
+
+#define HC_CFG 0x0
+#define HC_CFG_IF_CFG(x) ((x) << 27)
+#define HC_CFG_DUAL_SLAVE BIT(31)
+#define HC_CFG_INDIVIDUAL BIT(30)
+#define HC_CFG_NIO(x) (((x) / 4) << 27)
+#define HC_CFG_TYPE(s, t) ((t) << (23 + ((s) * 2)))
+#define HC_CFG_TYPE_SPI_NOR 0
+#define HC_CFG_TYPE_SPI_NAND 1
+#define HC_CFG_TYPE_SPI_RAM 2
+#define HC_CFG_TYPE_RAW_NAND 3
+#define HC_CFG_SLV_ACT(x) ((x) << 21)
+#define HC_CFG_CLK_PH_EN BIT(20)
+#define HC_CFG_CLK_POL_INV BIT(19)
+#define HC_CFG_BIG_ENDIAN BIT(18)
+#define HC_CFG_DATA_PASS BIT(17)
+#define HC_CFG_IDLE_SIO_LVL(x) ((x) << 16)
+#define HC_CFG_MAN_START_EN BIT(3)
+#define HC_CFG_MAN_START BIT(2)
+#define HC_CFG_MAN_CS_EN BIT(1)
+#define HC_CFG_MAN_CS_ASSERT BIT(0)
+
+#define INT_STS 0x4
+#define INT_STS_EN 0x8
+#define INT_SIG_EN 0xc
+#define INT_STS_ALL GENMASK(31, 0)
+#define INT_RDY_PIN BIT(26)
+#define INT_RDY_SR BIT(25)
+#define INT_LNR_SUSP BIT(24)
+#define INT_ECC_ERR BIT(17)
+#define INT_CRC_ERR BIT(16)
+#define INT_LWR_DIS BIT(12)
+#define INT_LRD_DIS BIT(11)
+#define INT_SDMA_INT BIT(10)
+#define INT_DMA_FINISH BIT(9)
+#define INT_RX_NOT_FULL BIT(3)
+#define INT_RX_NOT_EMPTY BIT(2)
+#define INT_TX_NOT_FULL BIT(1)
+#define INT_TX_EMPTY BIT(0)
+
+#define HC_EN 0x10
+#define HC_EN_BIT BIT(0)
+
+#define TXD(x) (0x14 + ((x) * 4))
+#define RXD 0x24
+
+#define SS_CTRL(s) (0x30 + ((s) * 4))
+#define LRD_CFG 0x44
+#define LWR_CFG 0x80
+#define RWW_CFG 0x70
+#define OP_READ BIT(23)
+#define OP_DUMMY_CYC(x) ((x) << 17)
+#define OP_ADDR_BYTES(x) ((x) << 14)
+#define OP_CMD_BYTES(x) (((x) - 1) << 13)
+#define OP_OCTA_CRC_EN BIT(12)
+#define OP_DQS_EN BIT(11)
+#define OP_ENHC_EN BIT(10)
+#define OP_PREAMBLE_EN BIT(9)
+#define OP_DATA_DDR BIT(8)
+#define OP_DATA_BUSW(x) ((x) << 6)
+#define OP_ADDR_DDR BIT(5)
+#define OP_ADDR_BUSW(x) ((x) << 3)
+#define OP_CMD_DDR BIT(2)
+#define OP_CMD_BUSW(x) (x)
+#define OP_BUSW_1 0
+#define OP_BUSW_2 1
+#define OP_BUSW_4 2
+#define OP_BUSW_8 3
+
+#define OCTA_CRC 0x38
+#define OCTA_CRC_IN_EN(s) BIT(3 + ((s) * 16))
+#define OCTA_CRC_CHUNK(s, x) ((fls((x) / 32)) << (1 + ((s) * 16)))
+#define OCTA_CRC_OUT_EN(s) BIT(0 + ((s) * 16))
+
+#define ONFI_DIN_CNT(s) (0x3c + (s))
+
+#define LRD_CTRL 0x48
+#define RWW_CTRL 0x74
+#define LWR_CTRL 0x84
+#define LMODE_EN BIT(31)
+#define LMODE_SLV_ACT(x) ((x) << 21)
+#define LMODE_CMD1(x) ((x) << 8)
+#define LMODE_CMD0(x) (x)
+
+#define LRD_ADDR 0x4c
+#define LWR_ADDR 0x88
+#define LRD_RANGE 0x50
+#define LWR_RANGE 0x8c
+
+#define AXI_SLV_ADDR 0x54
+
+#define DMAC_RD_CFG 0x58
+#define DMAC_WR_CFG 0x94
+#define DMAC_CFG_PERIPH_EN BIT(31)
+#define DMAC_CFG_ALLFLUSH_EN BIT(30)
+#define DMAC_CFG_LASTFLUSH_EN BIT(29)
+#define DMAC_CFG_QE(x) (((x) + 1) << 16)
+#define DMAC_CFG_BURST_LEN(x) (((x) + 1) << 12)
+#define DMAC_CFG_BURST_SZ(x) ((x) << 8)
+#define DMAC_CFG_DIR_READ BIT(1)
+#define DMAC_CFG_START BIT(0)
+
+#define DMAC_RD_CNT 0x5c
+#define DMAC_WR_CNT 0x98
+
+#define SDMA_ADDR 0x60
+
+#define DMAM_CFG 0x64
+#define DMAM_CFG_START BIT(31)
+#define DMAM_CFG_CONT BIT(30)
+#define DMAM_CFG_SDMA_GAP(x) (fls((x) / 8192) << 2)
+#define DMAM_CFG_DIR_READ BIT(1)
+#define DMAM_CFG_EN BIT(0)
+
+#define DMAM_CNT 0x68
+
+#define LNR_TIMER_TH 0x6c
+
+#define RDM_CFG0 0x78
+#define RDM_CFG0_POLY(x) (x)
+
+#define RDM_CFG1 0x7c
+#define RDM_CFG1_RDM_EN BIT(31)
+#define RDM_CFG1_SEED(x) (x)
+
+#define LWR_SUSP_CTRL 0x90
+#define LWR_SUSP_CTRL_EN BIT(31)
+
+#define DMAS_CTRL 0x9c
+#define DMAS_CTRL_EN BIT(31)
+#define DMAS_CTRL_DIR_READ BIT(30)
+
+#define DATA_STROB 0xa0
+#define DATA_STROB_EDO_EN BIT(2)
+#define DATA_STROB_INV_POL BIT(1)
+#define DATA_STROB_DELAY_2CYC BIT(0)
+
+#define IDLY_CODE(x) (0xa4 + ((x) * 4))
+#define IDLY_CODE_VAL(x, v) ((v) << (((x) % 4) * 8))
+
+#define GPIO 0xc4
+#define GPIO_PT(x) BIT(3 + ((x) * 16))
+#define GPIO_RESET(x) BIT(2 + ((x) * 16))
+#define GPIO_HOLDB(x) BIT(1 + ((x) * 16))
+#define GPIO_WPB(x) BIT((x) * 16)
+
+#define HC_VER 0xd0
+
+#define HW_TEST(x) (0xe0 + ((x) * 4))
+
+#define MXIC_NFC_MAX_CLK_HZ 50000000
+
+struct mxic_nand_ctlr {
+ struct clk *ps_clk;
+ struct clk *send_clk;
+ struct clk *send_dly_clk;
+ void __iomem *regs;
+ struct nand_controller controller;
+ struct device *dev;
+ void *priv;
+};
+
+struct mxic_nand_chip {
+ struct nand_chip chip;
+};
+
+static int mxic_nfc_clk_enable(struct mxic_nand_ctlr *nfc)
+{
+ int ret;
+
+ ret = clk_prepare_enable(nfc->ps_clk);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(nfc->send_clk);
+ if (ret)
+ goto err_ps_clk;
+
+ ret = clk_prepare_enable(nfc->send_dly_clk);
+ if (ret)
+ goto err_send_dly_clk;
+
+ return ret;
+
+err_send_dly_clk:
+ clk_disable_unprepare(nfc->send_clk);
+err_ps_clk:
+ clk_disable_unprepare(nfc->ps_clk);
+
+ return ret;
+}
+
+static void mxic_nfc_clk_disable(struct mxic_nand_ctlr *nfc)
+{
+ clk_disable_unprepare(nfc->send_clk);
+ clk_disable_unprepare(nfc->send_dly_clk);
+ clk_disable_unprepare(nfc->ps_clk);
+}
+
+static void mxic_nfc_set_input_delay(struct mxic_nand_ctlr *nfc, u8 idly_code)
+{
+ writel(IDLY_CODE_VAL(0, idly_code) |
+ IDLY_CODE_VAL(1, idly_code) |
+ IDLY_CODE_VAL(2, idly_code) |
+ IDLY_CODE_VAL(3, idly_code),
+ nfc->regs + IDLY_CODE(0));
+ writel(IDLY_CODE_VAL(4, idly_code) |
+ IDLY_CODE_VAL(5, idly_code) |
+ IDLY_CODE_VAL(6, idly_code) |
+ IDLY_CODE_VAL(7, idly_code),
+ nfc->regs + IDLY_CODE(1));
+}
+
+static int mxic_nfc_clk_setup(struct mxic_nand_ctlr *nfc, unsigned long freq)
+{
+ int ret;
+
+ ret = clk_set_rate(nfc->send_clk, freq);
+ if (ret)
+ return ret;
+
+ ret = clk_set_rate(nfc->send_dly_clk, freq);
+ if (ret)
+ return ret;
+
+ /*
+ * A constant delay range from 0x0 ~ 0x1F for input delay,
+ * the unit is 78 ps, the max input delay is 2.418 ns.
+ */
+ mxic_nfc_set_input_delay(nfc, 0xf);
+
+ /*
+ * Phase degree = 360 * freq * output-delay
+ * where output-delay is a constant value 1 ns in FPGA.
+ *
+ * Get Phase degree = 360 * freq * 1 ns
+ * = 360 * freq * 1 sec / 1000000000
+ * = 9 * freq / 25000000
+ */
+ ret = clk_set_phase(nfc->send_dly_clk, 9 * freq / 25000000);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int mxic_nfc_set_freq(struct mxic_nand_ctlr *nfc, unsigned long freq)
+{
+ int ret;
+
+ if (freq > MXIC_NFC_MAX_CLK_HZ)
+ freq = MXIC_NFC_MAX_CLK_HZ;
+
+ mxic_nfc_clk_disable(nfc);
+ ret = mxic_nfc_clk_setup(nfc, freq);
+ if (ret)
+ return ret;
+
+ ret = mxic_nfc_clk_enable(nfc);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void mxic_nfc_hw_init(struct mxic_nand_ctlr *nfc)
+{
+ writel(DATA_STROB_EDO_EN, nfc->regs + DATA_STROB);
+ writel(HC_CFG_NIO(8) | HC_CFG_TYPE(1, HC_CFG_TYPE_RAW_NAND) |
+ HC_CFG_SLV_ACT(0) | HC_CFG_MAN_CS_EN |
+ HC_CFG_IDLE_SIO_LVL(1), nfc->regs + HC_CFG);
+ writel(INT_STS_ALL, nfc->regs + INT_STS_EN);
+ writel(0x0, nfc->regs + ONFI_DIN_CNT(0));
+ writel(0, nfc->regs + LRD_CFG);
+ writel(0, nfc->regs + LRD_CTRL);
+ writel(0x0, nfc->regs + HC_EN);
+
+ /* Default 10 MHz to setup tRC_min/tWC_min:100 ns */
+ mxic_nfc_set_freq(nfc, 10000000);
+}
+
+static void mxic_nfc_cs_enable(struct mxic_nand_ctlr *nfc)
+{
+ writel(readl(nfc->regs + HC_CFG) | HC_CFG_MAN_CS_EN,
+ nfc->regs + HC_CFG);
+ writel(HC_CFG_MAN_CS_ASSERT | readl(nfc->regs + HC_CFG),
+ nfc->regs + HC_CFG);
+}
+
+static void mxic_nfc_cs_disable(struct mxic_nand_ctlr *nfc)
+{
+ writel(~HC_CFG_MAN_CS_ASSERT & readl(nfc->regs + HC_CFG),
+ nfc->regs + HC_CFG);
+}
+
+static int mxic_nfc_wait_ready(struct nand_chip *chip)
+{
+ struct mxic_nand_ctlr *nfc = nand_get_controller_data(chip);
+ u32 sts;
+
+ return readl_poll_timeout(nfc->regs + INT_STS, sts,
+ sts & INT_RDY_PIN, 0, USEC_PER_SEC);
+}
+
+static int mxic_nfc_data_xfer(struct mxic_nand_ctlr *nfc, const void *txbuf,
+ void *rxbuf, unsigned int len)
+{
+ unsigned int pos = 0;
+
+ while (pos < len) {
+ unsigned int nbytes = len - pos;
+ u32 data = 0xffffffff;
+ u32 sts;
+ int ret;
+
+ if (nbytes > 4)
+ nbytes = 4;
+
+ if (txbuf)
+ memcpy(&data, txbuf + pos, nbytes);
+
+ ret = readl_poll_timeout(nfc->regs + INT_STS, sts,
+ sts & INT_TX_EMPTY, 0, USEC_PER_SEC);
+ if (ret)
+ return ret;
+
+ writel(data, nfc->regs + TXD(nbytes % 4));
+
+ ret = readl_poll_timeout(nfc->regs + INT_STS, sts,
+ sts & INT_TX_EMPTY, 0,
+ USEC_PER_SEC);
+ if (ret)
+ return ret;
+
+ ret = readl_poll_timeout(nfc->regs + INT_STS, sts,
+ sts & INT_RX_NOT_EMPTY, 0,
+ USEC_PER_SEC);
+ if (ret)
+ return ret;
+
+ data = readl(nfc->regs + RXD);
+ if (rxbuf) {
+ data >>= (8 * (4 - nbytes));
+ memcpy(rxbuf + pos, &data, nbytes);
+ }
+ if (readl(nfc->regs + INT_STS) & INT_RX_NOT_EMPTY)
+ dev_warn(nfc->dev, "RX FIFO not empty\n")
+
+ pos += nbytes;
+ }
+
+ return 0;
+}
+
+static int mxic_nfc_exec_op(struct nand_chip *chip,
+ const struct nand_operation *op, bool check_only)
+{
+ struct mxic_nand_ctlr *nfc = nand_get_controller_data(chip);
+ const struct nand_op_instr *instr = NULL;
+ int ret = 0;
+ unsigned int op_id;
+
+ mxic_nfc_cs_enable(nfc);
+ for (op_id = 0; op_id < op->ninstrs; op_id++) {
+ instr = &op->instrs[op_id];
+
+ switch (instr->type) {
+ case NAND_OP_CMD_INSTR:
+ writel(0, nfc->regs + HC_EN);
+ writel(HC_EN_BIT, nfc->regs + HC_EN);
+ writel(OP_CMD_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) |
+ OP_CMD_BYTES(0), nfc->regs + SS_CTRL(0));
+
+ ret = mxic_nfc_data_xfer(nfc,
+ &instr->ctx.cmd.opcode,
+ NULL, 1);
+ break;
+
+ case NAND_OP_ADDR_INSTR:
+ writel(OP_ADDR_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) |
+ OP_ADDR_BYTES(instr->ctx.addr.naddrs),
+ nfc->regs + SS_CTRL(0));
+ ret = mxic_nfc_data_xfer(nfc,
+ instr->ctx.addr.addrs, NULL,
+ instr->ctx.addr.naddrs);
+ break;
+
+ case NAND_OP_DATA_IN_INSTR:
+ writel(0x0, nfc->regs + ONFI_DIN_CNT(0));
+ writel(OP_DATA_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) |
+ OP_READ, nfc->regs + SS_CTRL(0));
+ ret = mxic_nfc_data_xfer(nfc, NULL,
+ instr->ctx.data.buf.in,
+ instr->ctx.data.len);
+ break;
+
+ case NAND_OP_DATA_OUT_INSTR:
+ writel(instr->ctx.data.len,
+ nfc->regs + ONFI_DIN_CNT(0));
+ writel(OP_DATA_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F),
+ nfc->regs + SS_CTRL(0));
+ ret = mxic_nfc_data_xfer(nfc,
+ instr->ctx.data.buf.out, NULL,
+ instr->ctx.data.len);
+ break;
+
+ case NAND_OP_WAITRDY_INSTR:
+ ret = mxic_nfc_wait_ready(chip);
+ break;
+ }
+ }
+ mxic_nfc_cs_disable(nfc);
+
+ return ret;
+}
+
+static int mxic_nfc_setup_data_interface(struct nand_chip *chip, int chipnr,
+ const struct nand_data_interface *conf)
+{
+ struct mxic_nand_ctlr *nfc = nand_get_controller_data(chip);
+ const struct nand_sdr_timings *sdr;
+ unsigned long freq;
+
+ sdr = nand_get_sdr_timings(conf);
+ if (IS_ERR(sdr))
+ return PTR_ERR(sdr);
+
+ if (chipnr < 0)
+ return 0;
+
+ if (sdr->tRC_min)
+ freq = 1000000000 / (sdr->tRC_min / 1000);
+
+ return mxic_nfc_set_freq(nfc, freq);
+}
+
+static const struct nand_controller_ops mxic_nand_controller_ops = {
+ .exec_op = mxic_nfc_exec_op,
+ .setup_data_interface = mxic_nfc_setup_data_interface,
+};
+
+static int mxic_nfc_probe(struct platform_device *pdev)
+{
+ struct mtd_info *mtd;
+ struct mxic_nand_ctlr *nfc;
+ struct mxic_nand_chip *mxic_nand;
+ struct nand_chip *nand_chip;
+ struct resource *res;
+ int err;
+
+ nfc = devm_kzalloc(&pdev->dev, sizeof(struct mxic_nand_ctlr),
+ GFP_KERNEL);
+ if (!nfc)
+ return -ENOMEM;
+
+ mxic_nand = devm_kzalloc(&pdev->dev, sizeof(struct mxic_nand_chip),
+ GFP_KERNEL);
+ if (!mxic_nand)
+ return -ENOMEM;
+
+ nfc->ps_clk = devm_clk_get(&pdev->dev, "ps");
+ if (IS_ERR(nfc->ps_clk))
+ return PTR_ERR(nfc->ps_clk);
+
+ nfc->send_clk = devm_clk_get(&pdev->dev, "send");
+ if (IS_ERR(nfc->send_clk))
+ return PTR_ERR(nfc->send_clk);
+
+ nfc->send_dly_clk = devm_clk_get(&pdev->dev, "send_dly");
+ if (IS_ERR(nfc->send_dly_clk))
+ return PTR_ERR(nfc->send_dly_clk);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ nfc->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(nfc->regs))
+ return PTR_ERR(nfc->regs);
+
+ nand_chip = &mxic_nand->chip;
+ mtd = nand_to_mtd(nand_chip);
+ mtd->dev.parent = &pdev->dev;
+ nand_chip->ecc.priv = NULL;
+ nand_set_flash_node(nand_chip, pdev->dev.of_node);
+ nand_chip->priv = nfc;
+ nfc->dev = &pdev->dev;
+ nfc->priv = nand_chip;
+
+ nfc->controller.ops = &mxic_nand_controller_ops;
+ nand_controller_init(&nfc->controller);
+ nand_chip->controller = &nfc->controller;
+
+ mxic_nfc_hw_init(nfc);
+
+ err = nand_scan(nand_chip, 1);
+ if (err)
+ goto fail;
+
+ err = mtd_device_register(mtd, NULL, 0);
+ if (err)
+ goto fail;
+
+ platform_set_drvdata(pdev, nfc);
+ return 0;
+
+fail:
+ mxic_nfc_clk_disable(nfc);
+ return err;
+}
+
+static int mxic_nfc_remove(struct platform_device *pdev)
+{
+ struct mxic_nand_ctlr *nfc = platform_get_drvdata(pdev);
+
+ nand_release(nfc->priv);
+ mxic_nfc_clk_disable(nfc);
+ return 0;
+}
+
+static const struct of_device_id mxic_nfc_of_ids[] = {
+ { .compatible = "mxicy,multi-itfc-v009-nand-morph", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mxic_nfc_of_ids);
+
+static struct platform_driver mxic_nfc_driver = {
+ .probe = mxic_nfc_probe,
+ .remove = mxic_nfc_remove,
+ .driver = {
+ .name = "mxic-nfc",
+ .of_match_table = mxic_nfc_of_ids,
+ },
+};
+module_platform_driver(mxic_nfc_driver);
+
+MODULE_AUTHOR("Mason Yang <masonccyang@mxic.com.tw>");
+MODULE_DESCRIPTION("Macronix raw NAND controller driver");
+MODULE_LICENSE("GPL v2");
--
1.9.1
^ permalink raw reply related
* [PATCH v6 0/2] Add Macronix raw NAND controller driver
From: Mason Yang @ 2019-08-01 3:55 UTC (permalink / raw)
To: miquel.raynal, marek.vasut, bbrezillon, dwmw2, computersforpeace,
vigneshr, richard, robh+dt, stefan, mark.rutland
Cc: linux-kernel, linux-mtd, juliensu, paul.burton, liang.yang,
lee.jones, masonccyang, anders.roxell, christophe.kerello, paul,
devicetree
Hi,
v6 patch including:
1. compatible rename to "mxicy,multi-itfc-v009-nand-morph"
2. remove xxx_clk to xxx in DTS and driver.
3. patch mxic_nfc_data_xfer()
v5 patch including:
1. compatible rename to "macronix,nand-controller"
2. handle three clock in one
3. other minor patches
v4 patch back to only raw NAND controller driver instead of MFD,
raw NAND and SPI driver. This is based on MFD maintainer, Lee Jones
comments:
MFD is for registering child devices of chips which offer genuine
cross-subsystem functionality.
It is not designed for mode selecting, or as a place to shove shared code
just because a better location doesn't appear to exist.
v3 patch is to rename the title of SPI controller driver.
"Patch Macronix SPI controller driver according to MX25F0A MFD driver"
v2s patches is to support Macronix MX25F0A MFD driver
for raw nand and spi controller which is separated
form previous patchset:
https://patchwork.kernel.org/patch/10874679/
thanks for your review.
best regards,
Mason
Mason Yang (2):
mtd: rawnand: Add Macronix raw NAND controller driver
dt-bindings: mtd: Document Macronix raw NAND controller bindings
.../devicetree/bindings/mtd/mxic-nand.txt | 19 +
drivers/mtd/nand/raw/Kconfig | 6 +
drivers/mtd/nand/raw/Makefile | 1 +
drivers/mtd/nand/raw/mxic_nand.c | 554 +++++++++++++++++++++
4 files changed, 580 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mtd/mxic-nand.txt
create mode 100644 drivers/mtd/nand/raw/mxic_nand.c
--
1.9.1
^ permalink raw reply
* Re: [PATCH net-next v2 2/4] net: phy: Add mdio-aspeed
From: Andrew Lunn @ 2019-08-01 3:53 UTC (permalink / raw)
To: Andrew Jeffery
Cc: netdev, davem, robh+dt, mark.rutland, joel, f.fainelli,
hkallweit1, devicetree, linux-arm-kernel, linux-aspeed,
linux-kernel
In-Reply-To: <20190731053959.16293-3-andrew@aj.id.au>
On Wed, Jul 31, 2019 at 03:09:57PM +0930, Andrew Jeffery wrote:
> The AST2600 design separates the MDIO controllers from the MAC, which is
> where they were placed in the AST2400 and AST2500. Further, the register
> interface is reworked again, so now we have three possible different
> interface implementations, however this driver only supports the
> interface provided by the AST2600. The AST2400 and AST2500 will continue
> to be supported by the MDIO support embedded in the FTGMAC100 driver.
>
> The hardware supports both C22 and C45 mode, but for the moment only C22
> support is implemented.
>
> Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply
* Re: [PATCH v2 2/2] ARM: dts: aspeed: Add Mihawk BMC platform
From: Andrew Jeffery @ 2019-08-01 3:10 UTC (permalink / raw)
To: Ben Pai, Rob Herring, mark.rutland, Joel Stanley, devicetree,
linux-arm-kernel, linux-aspeed, linux-kernel
Cc: wangat
In-Reply-To: <20190731074742.23456-1-Ben_Pai@wistron.com>
Hi Ben,
Comments inline below. Also apologies for the IBM/IPS mixup in the previous
review, I've been corrected :)
On Wed, 31 Jul 2019, at 17:17, Ben Pai wrote:
> The Mihawk BMC is an ASPEED ast2500 based BMC that is part of an
> OpenPower Power9 server.
>
> Signed-off-by: Ben Pai <Ben_Pai@wistron.com>
> ---
> arch/arm/boot/dts/Makefile | 1 +
> arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts | 907 ++++++++++++++++++++
> 2 files changed, 908 insertions(+)
> create mode 100755 arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts
>
> diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
> index eb6de52c1936..262345544359 100644
> --- a/arch/arm/boot/dts/Makefile
> +++ b/arch/arm/boot/dts/Makefile
> @@ -1281,5 +1281,6 @@ dtb-$(CONFIG_ARCH_ASPEED) += \
> aspeed-bmc-opp-vesnin.dtb \
> aspeed-bmc-opp-witherspoon.dtb \
> aspeed-bmc-opp-zaius.dtb \
> + aspeed-bmc-opp-mihawk.dtb \
This is a sorted list, please put it in the right spot.
> aspeed-bmc-portwell-neptune.dtb \
> aspeed-bmc-quanta-q71l.dtb
> diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts
> b/arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts
> new file mode 100755
> index 000000000000..913c94326f3f
> --- /dev/null
> +++ b/arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts
> @@ -0,0 +1,907 @@
> +/dts-v1/;
> +
> +#include "aspeed-g5.dtsi"
> +#include <dt-bindings/gpio/aspeed-gpio.h>
> +#include <dt-bindings/leds/leds-pca955x.h>
> +
> +/ {
> + model = "Mihawk BMC";
> + compatible = "ibm,mihawk-bmc", "aspeed,ast2500";
> +
> +
> + chosen {
> + stdout-path = &uart5;
> + bootargs = "console=ttyS4,115200 earlyprintk";
> + };
> +
> + memory@80000000 {
> + reg = <0x80000000 0x20000000>; /* address and size of RAM(512MB) */
> + };
> +
> + reserved-memory {
> + #address-cells = <1>;
> + #size-cells = <1>;
> + ranges;
> +
> + flash_memory: region@98000000 {
> + no-map;
> + reg = <0x98000000 0x04000000>; /* 64M */
> + };
> +
> + gfx_memory: framebuffer {
> + size = <0x01000000>;
> + alignment = <0x01000000>;
> + compatible = "shared-dma-pool";
> + reusable;
> + };
> +
> + video_engine_memory: jpegbuffer {
> + size = <0x02000000>; /* 32MM */
> + alignment = <0x01000000>;
> + compatible = "shared-dma-pool";
> + reusable;
> + };
> + };
> +
> + gpio-keys {
> + compatible = "gpio-keys";
> +
> + air-water {
> + label = "air-water";
> + gpios = <&gpio ASPEED_GPIO(F, 6) GPIO_ACTIVE_LOW>;
> + linux,code = <ASPEED_GPIO(F, 6)>;
> + };
> +
> + checkstop {
> + label = "checkstop";
> + gpios = <&gpio ASPEED_GPIO(J, 2) GPIO_ACTIVE_LOW>;
> + linux,code = <ASPEED_GPIO(J, 2)>;
> + };
> +
> + ps0-presence {
> + label = "ps0-presence";
> + gpios = <&gpio ASPEED_GPIO(Z, 2) GPIO_ACTIVE_LOW>;
> + linux,code = <ASPEED_GPIO(Z, 2)>;
> + };
> +
> + ps1-presence {
> + label = "ps1-presence";
> + gpios = <&gpio ASPEED_GPIO(Z, 0) GPIO_ACTIVE_LOW>;
> + linux,code = <ASPEED_GPIO(Z, 0)>;
> + };
> + id-button {
> + label = "id-button";
> + gpios = <&gpio ASPEED_GPIO(F, 1) GPIO_ACTIVE_LOW>;
> + linux,code = <ASPEED_GPIO(F, 1)>;
> + };
> + };
> +
> + gpio-keys-polled {
> + compatible = "gpio-keys-polled";
> + #address-cells = <1>;
Delete the #address-cells property (both it and the #size-cells properties
are not needed for the gpio-keys-polled node).
> + poll-interval = <1000>;
> +
> + fan0-presence {
> + label = "fan0-presence";
> + gpios = <&pca9552 9 GPIO_ACTIVE_LOW>;
> + linux,code = <9>;
> + };
> +
> + fan1-presence {
> + label = "fan1-presence";
> + gpios = <&pca9552 10 GPIO_ACTIVE_LOW>;
> + linux,code = <10>;
> + };
> +
> + fan2-presence {
> + label = "fan2-presence";
> + gpios = <&pca9552 11 GPIO_ACTIVE_LOW>;
> + linux,code = <11>;
> + };
> +
> + fan3-presence {
> + label = "fan3-presence";
> + gpios = <&pca9552 12 GPIO_ACTIVE_LOW>;
> + linux,code = <12>;
> + };
> +
> + fan4-presence {
> + label = "fan4-presence";
> + gpios = <&pca9552 13 GPIO_ACTIVE_LOW>;
> + linux,code = <13>;
> + };
> +
> + fan5-presence {
> + label = "fan5-presence";
> + gpios = <&pca9552 14 GPIO_ACTIVE_LOW>;
> + linux,code = <14>;
> + };
> + };
> +
> + leds {
> + compatible = "gpio-leds";
> +
> + fault {
> + retain-state-shutdown;
> + default-state = "keep";
> + gpios = <&gpio ASPEED_GPIO(AA, 0) GPIO_ACTIVE_LOW>;
> + };
> +
> + power {
> + retain-state-shutdown;
> + default-state = "keep";
> + gpios = <&gpio ASPEED_GPIO(AA, 1) GPIO_ACTIVE_LOW>;
> + };
> +
> + rear-id {
> + retain-state-shutdown;
> + default-state = "keep";
> + gpios = <&gpio ASPEED_GPIO(AA, 2) GPIO_ACTIVE_LOW>;
> + };
> +
> + rear-g {
> + retain-state-shutdown;
> + default-state = "keep";
> + gpios = <&gpio ASPEED_GPIO(AA, 4) GPIO_ACTIVE_LOW>;
> + };
> +
> + rear-ok {
> + retain-state-shutdown;
> + default-state = "keep";
> + gpios = <&gpio ASPEED_GPIO(Y, 0) GPIO_ACTIVE_LOW>;
> + };
> +
> + fan0 {
> + retain-state-shutdown;
> + default-state = "keep";
> + gpios = <&pca9552 0 GPIO_ACTIVE_LOW>;
> + };
> +
> + fan1 {
> + retain-state-shutdown;
> + default-state = "keep";
> + gpios = <&pca9552 1 GPIO_ACTIVE_LOW>;
> + };
> +
> + fan2 {
> + retain-state-shutdown;
> + default-state = "keep";
> + gpios = <&pca9552 2 GPIO_ACTIVE_LOW>;
> + };
> +
> + fan3 {
> + retain-state-shutdown;
> + default-state = "keep";
> + gpios = <&pca9552 3 GPIO_ACTIVE_LOW>;
> + };
> +
> + fan4 {
> + retain-state-shutdown;
> + default-state = "keep";
> + gpios = <&pca9552 4 GPIO_ACTIVE_LOW>;
> + };
> +
> + fan5 {
> + retain-state-shutdown;
> + default-state = "keep";
> + gpios = <&pca9552 5 GPIO_ACTIVE_LOW>;
> + };
> + };
> +
> + fsi: gpio-fsi {
> + compatible = "fsi-master-gpio", "fsi-master";
> + #address-cells = <2>;
> + #size-cells = <0>;
> + no-gpio-delays;
> +
> + clock-gpios = <&gpio ASPEED_GPIO(E, 6) GPIO_ACTIVE_HIGH>;
> + data-gpios = <&gpio ASPEED_GPIO(E, 7) GPIO_ACTIVE_HIGH>;
> + mux-gpios = <&gpio ASPEED_GPIO(E, 5) GPIO_ACTIVE_HIGH>;
> + enable-gpios = <&gpio ASPEED_GPIO(D, 0) GPIO_ACTIVE_HIGH>;
> + trans-gpios = <&gpio ASPEED_GPIO(R, 2) GPIO_ACTIVE_HIGH>;
> + };
> + iio-hwmon-12v {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 0>;
> + };
> +
> + iio-hwmon-5v {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 1>;
> + };
> +
> + iio-hwmon-3v {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 2>;
> + };
> +
> + iio-hwmon-vdd0 {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 3>;
> + };
> +
> + iio-hwmon-vdd1 {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 4>;
> + };
> +
> + iio-hwmon-vcs0 {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 5>;
> + };
> +
> + iio-hwmon-vcs1 {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 6>;
> + };
> +
> + iio-hwmon-vdn0 {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 7>;
> + };
> +
> + iio-hwmon-vdn1 {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 8>;
> + };
> +
> + iio-hwmon-vio0 {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 9>;
> + };
> +
> + iio-hwmon-vio1 {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 10>;
> + };
> +
> + iio-hwmon-vddra {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 11>;
> + };
> +
> + iio-hwmon-vddrb {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 13>;
> + };
> +
> + iio-hwmon-vddrc {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 14>;
> + };
> +
> + iio-hwmon-vddrd {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 15>;
> + };
> +
> + iio-hwmon-battery {
> + compatible = "iio-hwmon";
> + io-channels = <&adc 12>;
> + };
> +};
> +
> +&pwm_tacho {
> + status = "okay";
> + /*compatible = "aspeed,ast2500-pwm-tacho";
> + #address-cells = <1>;
> + #size-cells = <1>;
> + reg = <0x1e786000 0x1000>;
> + clocks = <&pwm_tacho_fixed_clk>;*/
I missed this commented block last time? Please remove it.
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_pwm1_default
> + &pinctrl_pwm2_default &pinctrl_pwm3_default
> + &pinctrl_pwm4_default &pinctrl_pwm5_default>;
> +
> + fan@0 {
> + reg = <0x00>;
> + aspeed,fan-tach-ch = /bits/ 8 <0x00>;
> + };
> +
> + fan@1 {
> + reg = <0x01>;
> + aspeed,fan-tach-ch = /bits/ 8 <0x01>;
> + };
> +
> + fan@2 {
> + reg = <0x02>;
> + aspeed,fan-tach-ch = /bits/ 8 <0x02>;
> + };
> +
> + fan@3 {
> + reg = <0x03>;
> + aspeed,fan-tach-ch = /bits/ 8 <0x03>;
> + };
> +
> + fan@4 {
> + reg = <0x04>;
> + aspeed,fan-tach-ch = /bits/ 8 <0x04>;
> + };
> +
> + fan@5 {
> + reg = <0x05>;
> + aspeed,fan-tach-ch = /bits/ 8 <0x05>;
> + };
> +
> + fan@6 {
> + reg = <0x00>;
> + aspeed,fan-tach-ch = /bits/ 8 <0x06>;
> + };
> +
> + fan@7 {
> + reg = <0x01>;
> + aspeed,fan-tach-ch = /bits/ 8 <0x07>;
> + };
> +
> + fan@8 {
> + reg = <0x02>;
> + aspeed,fan-tach-ch = /bits/ 8 <0x08>;
> + };
> +
> + fan@9 {
> + reg = <0x03>;
> + aspeed,fan-tach-ch = /bits/ 8 <0x09>;
> + };
> +
> + fan@10 {
> + reg = <0x04>;
> + aspeed,fan-tach-ch = /bits/ 8 <0x0a>;
> + };
> +
> + fan@11 {
> + reg = <0x05>;
> + aspeed,fan-tach-ch = /bits/ 8 <0x0b>;
> + };
> +};
> +
> +&fmc {
> + status = "okay";
> + flash@0 {
> + status = "okay";
> + label = "bmc";
> + m25p,fast-read;
> + spi-max-frequency = <50000000>;
> + partitions {
> + #address-cells = < 1 >;
> + #size-cells = < 1 >;
> + compatible = "fixed-partitions";
> + u-boot@0 {
> + reg = < 0 0x60000 >;
> + label = "u-boot";
> + };
> + u-boot-env@60000 {
> + reg = < 0x60000 0x20000 >;
> + label = "u-boot-env";
> + };
> + obmc-ubi@80000 {
> + reg = < 0x80000 0x1F80000 >;
> + label = "obmc-ubi";
> + };
> + };
> + };
> + flash@1 {
> + status = "okay";
> + label = "alt-bmc";
> + m25p,fast-read;
> + spi-max-frequency = <50000000>;
> + partitions {
> + #address-cells = < 1 >;
> + #size-cells = < 1 >;
> + compatible = "fixed-partitions";
> + u-boot@0 {
> + reg = < 0 0x60000 >;
> + label = "alt-u-boot";
> + };
> + u-boot-env@60000 {
> + reg = < 0x60000 0x20000 >;
> + label = "alt-u-boot-env";
> + };
> + obmc-ubi@80000 {
> + reg = < 0x80000 0x1F80000 >;
> + label = "alt-obmc-ubi";
> + };
> + };
> + };
> +};
> +
> +&spi1 {
> + status = "okay";
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_spi1_default>;
> +
> + flash@0 {
> + status = "okay";
> + label = "pnor";
> + m25p,fast-read;
> + spi-max-frequency = <100000000>;
> + };
> +};
> +
> +&lpc_ctrl {
> + status = "okay";
> + memory-region = <&flash_memory>;
> + flash = <&spi1>;
> +};
> +
> +&uart1 {
> + /* Rear RS-232 connector */
> + status = "okay";
> +
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_txd1_default
> + &pinctrl_rxd1_default
> + &pinctrl_nrts1_default
> + &pinctrl_ndtr1_default
> + &pinctrl_ndsr1_default
> + &pinctrl_ncts1_default
> + &pinctrl_ndcd1_default
> + &pinctrl_nri1_default>;
> +};
> +
> +&uart2 {
> + /* APSS */
> + status = "okay";
> +
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_txd2_default &pinctrl_rxd2_default>;
> +};
> +
> +&uart5 {
> + status = "okay";
> +};
> +
> +&mac0 {
> + status = "okay";
> +
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_rmii1_default>;
> + use-ncsi;
> +};
> +
> +&mac1 {
> + status = "okay";
> +
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>;
> +};
> +
> +&i2c0 {
> + status = "disabled";
> +};
> +
> +&i2c1 {
> + status = "disabled";
> +};
> +
> +&i2c2 {
> + status = "okay";
> +
> + /* SAMTEC P0 */
> + /* SAMTEC P1 */
> +
> +};
> +
> +&i2c3 {
> + status = "okay";
> +
> + /* APSS */
> + /* CPLD */
> +
> + /* PCA9516 (repeater) ->
> + * CLK Buffer 9FGS9092
> + * CLK Buffer 9DBL0651BKILFT
> + * CLK Buffer 9DBL0651BKILFT
> + * Power Supply 0
> + * Power Supply 1
> + * PCA 9552 LED
> + */
> +
> + power-supply@58 {
> + compatible = "ibm,cffps1";
> + reg = <0x58>;
> + };
> +
> + power-supply@5b {
> + compatible = "ibm,cffps1";
> + reg = <0x5b>;
> + };
> +
> + pca9552: pca9552@60 {
> + compatible = "nxp,pca9552";
> + reg = <0x60>;
> + #address-cells = <1>;
> + #size-cells = <0>;
> + gpio-controller;
> + #gpio-cells = <2>;
> +
> + gpio@0 {
> + reg = <0>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio@1 {
> + reg = <1>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio@2 {
> + reg = <2>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio@3 {
> + reg = <3>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio@4 {
> + reg = <4>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio@5 {
> + reg = <5>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio@6 {
> + reg = <6>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio@7 {
> + reg = <7>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio@8 {
> + reg = <8>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio@9 {
> + reg = <9>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio@10 {
> + reg = <10>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio@11 {
> + reg = <11>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio@12 {
> + reg = <12>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio@13 {
> + reg = <13>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio@14 {
> + reg = <14>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> + gpio@15 {
> + reg = <15>;
> + type = <PCA955X_TYPE_GPIO>;
> + };
> +
> + };
> +
> +};
> +
> +&i2c4 {
> + status = "okay";
> +
> + /* CP0 VDD & VCS : IR35221 */
> + /* CP0 VDN : IR35221 */
> + /* CP0 VIO : IR38064 */
> + /* CP0 VDDR : PXM1330 */
> +
> + ir35221@70 {
> + compatible = "infineon,ir35221";
> + reg = <0x70>;
> + };
> +
> + ir35221@72 {
> + compatible = "infineon,ir35221";
> + reg = <0x72>;
> + };
> +
> +};
> +
> +&i2c5 {
> + status = "okay";
> +
> + /* CP0 VDD & VCS : IR35221 */
> + /* CP0 VDN : IR35221 */
> + /* CP0 VIO : IR38064 */
> + /* CP0 VDDR : PXM1330 */
> +
> + ir35221@70 {
> + compatible = "infineon,ir35221";
> + reg = <0x70>;
> + };
> +
> + ir35221@72 {
> + compatible = "infineon,ir35221";
> + reg = <0x72>;
> + };
> +
> +};
> +
> +&i2c6 {
> + status = "okay";
> +
> + /* pca9548 -> NVMe1 to 8 */
> +
> + pca9548@70 {
> + compatible = "nxp,pca9548";
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <0x70>;
> + };
> +
> +};
> +
> +&i2c7 {
> + status = "okay";
> +
> + /* pca9548 -> NVMe9 to 16 */
> +
> + pca9548@70 {
> + compatible = "nxp,pca9548";
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <0x70>;
> + };
> +
> +};
> +
> +&i2c8 {
> + status = "okay";
> +
> + eeprom@50 {
> + compatible = "atmel,24c64";
> + reg = <0x50>;
> + };
> +};
> +
> +&i2c9 {
> + status = "okay";
> +
> + /* pca9545 Riser ->
> + * PCIe x8 Slot3
> + * PCIe x16 slot4
> + * PCIe x8 slot5
> + * I2C BMC RISER PCA9554
> + * BMC SCL/SDA PCA9554
> + * PCA9554
> + */
> +
> + /* pca9545 ->
> + * PCIe x16 Slot1
> + * PCIe x8 slot2
> + * PEX8748
> + */
> +
> + pca9545riser@70 {
> + compatible = "nxp,pca9545";
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <0x70>;
> +
> + i2c-mux-idle-disconnect;
> + interrupt-controller;
> + #interrupt-cells = <2>;
> + };
> +
> + pca9545@71 {
> + compatible = "nxp,pca9545";
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <0x71>;
> +
> + i2c-mux-idle-disconnect;
> + interrupt-controller;
> + #interrupt-cells = <2>;
> + };
> +};
> +
> +&i2c10 {
> + status = "okay";
> +
> + /* pca9545 Riser ->
> + * PCIe x8 Slot8
> + * PCIe x16 slot9
> + * PCIe x8 slot10
> + * I2C BMC RISER PCA9554
> + * BMC SCL/SDA PCA9554
> + * PCA9554
> + */
> +
> + /* pca9545 ->
> + * PCIe x16 Slot1
> + * PCIe x8 slot2
> + * PEX8748
> + */
> +
> + pca9545riser@70 {
> + compatible = "nxp,pca9545";
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <0x70>;
> +
> + i2c-mux-idle-disconnect;
> + interrupt-controller;
> + #interrupt-cells = <2>;
> + };
> +
> + pca9545@71 {
> + compatible = "nxp,pca9545";
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <0x71>;
> +
> + i2c-mux-idle-disconnect;
> + interrupt-controller;
> + #interrupt-cells = <2>;
> + };
> +};
> +
> +&i2c11 {
> + status = "okay";
> +
> + /* TPM */
> + /* RTC RX8900CE */
> + /* FPGA for power sequence */
> + /* TMP275A */
> + /* TMP275A */
> + /* EMC1462 */
> +
> + tpm@57 {
> + compatible = "infineon,slb9645tt";
> + reg = <0x57>;
> + };
> +
> + rtc@32 {
> + compatible = "epson,rx8900";
> + reg = <0x32>;
> + };
> +
> + tmp275@48 {
> + compatible = "ti,tmp275";
> + reg = <0x48>;
> + };
> +
> + tmp275@49 {
> + compatible = "ti,tmp275";
> + reg = <0x49>;
> + };
> +
> + /* chip emc1462 use emc1403 driver */
> + emc1403@4c {
> + compatible = "smsc,emc1403";
> + reg = <0x4c>;
> + };
> +
> +};
> +
> +&i2c12 {
> + status = "okay";
> +
> + /* pca9545 ->
> + * SAS BP1
> + * SAS BP2
> + * NVMe BP
> + * M.2 riser
> + */
> +
> + pca9545@70 {
> + compatible = "nxp,pca9545";
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <0x70>;
> +
> + interrupt-controller;
> + #interrupt-cells = <2>;
> +
> + i2c@0 {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <0>;
> +
> + eeprom@50 {
> + compatible = "atmel,24c64";
> + reg = <0x50>;
> + };
> + };
> +
> + i2c@1 {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <1>;
> +
> + eeprom@50 {
> + compatible = "atmel,24c64";
> + reg = <0x50>;
> + };
> + };
> +
> + i2c@2 {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <2>;
> +
> + eeprom@50 {
> + compatible = "atmel,24c64";
> + reg = <0x50>;
> + };
> + };
> +
> + i2c@3 {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <3>;
> +
> + tmp275@48 {
> + compatible = "ti,tmp275";
> + reg = <0x48>;
> + };
> + };
> +
> + };
> +
> +};
> +
> +&i2c13 {
> + status = "okay";
> +
> + /* pca9548 ->
> + * NVMe BP
> + * NVMe HDD17 to 24
> + */
> +
> + pca9548@70 {
> + compatible = "nxp,pca9548";
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <0x70>;
> + };
> +};
> +
> +&vuart {
> + status = "okay";
> +};
> +
> +&gfx {
> + status = "okay";
> + memory-region = <&gfx_memory>;
> +};
> +
> +&adc {
> + status = "okay";
You're still missing the pinmux properties for the ADC lines being used.
Please add them.
Cheers,
Andrew
> +};
> +
> +&wdt1 {
> + aspeed,reset-type = "none";
> + aspeed,external-signal;
> + aspeed,ext-push-pull;
> + aspeed,ext-active-high;
> +
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_wdtrst1_default>;
> +};
> +
> +&wdt2 {
> + aspeed,alt-boot;
> +};
> +
> +&ibt {
> + status = "okay";
> +};
> +
> +&vhub {
> + status = "okay";
> +};
> +
> +&video {
> + status = "okay";
> + memory-region = <&video_engine_memory>;
> +};
> +
> +#include "ibm-power9-dual.dtsi"
> +
> --
> 2.17.1
>
>
> ---------------------------------------------------------------------------------------------------------------------------------------------------------------
> This email contains confidential or legally privileged information and
> is for the sole use of its intended recipient.
> Any unauthorized review, use, copying or distribution of this email or
> the content of this email is strictly prohibited.
> If you are not the intended recipient, you may reply to the sender and
> should delete this e-mail immediately.
> ---------------------------------------------------------------------------------------------------------------------------------------------------------------
>
^ permalink raw reply
* Re: [PATCH] libfdt: reduce the number of headers included from libfdt_env.h
From: Masahiro Yamada @ 2019-08-01 2:30 UTC (permalink / raw)
To: Rob Herring, Frank Rowand, DTML; +Cc: Linux Kernel Mailing List, Rob Herring
In-Reply-To: <20190617162123.24920-1-yamada.masahiro@socionext.com>
On Tue, Jun 18, 2019 at 1:21 AM Masahiro Yamada
<yamada.masahiro@socionext.com> wrote:
>
> Currently, libfdt_env.h includes <linux/kernel.h> just for INT_MAX.
>
> <linux/kernel.h> pulls in a lots of broat.
>
> Thanks to commit 54d50897d544 ("linux/kernel.h: split *_MAX and *_MIN
> macros into <linux/limits.h>"), <linux/kernel.h> can be replaced with
> <linux/limits.h>.
>
> This saves including dozens of headers.
>
> Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
> ---
ping?
> include/linux/libfdt_env.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/include/linux/libfdt_env.h b/include/linux/libfdt_env.h
> index edb0f0c30904..2231eb855e8f 100644
> --- a/include/linux/libfdt_env.h
> +++ b/include/linux/libfdt_env.h
> @@ -2,7 +2,7 @@
> #ifndef LIBFDT_ENV_H
> #define LIBFDT_ENV_H
>
> -#include <linux/kernel.h> /* For INT_MAX */
> +#include <linux/limits.h> /* For INT_MAX */
> #include <linux/string.h>
>
> #include <asm/byteorder.h>
> --
> 2.17.1
>
--
Best Regards
Masahiro Yamada
^ permalink raw reply
* [PATCH v3 5/5] dt-bindings: Update the riscv,isa string description
From: Atish Patra @ 2019-08-01 0:58 UTC (permalink / raw)
To: linux-kernel
Cc: Mark Rutland, devicetree, Albert Ou, Daniel Lezcano, Yangtao Li,
Greg Kroah-Hartman, Anup Patel, Johan Hovold, Atish Patra,
Rob Herring, Palmer Dabbelt, Gary Guo, Paul Walmsley, linux-riscv,
Enrico Weigelt, Thomas Gleixner, Allison Randal
In-Reply-To: <20190801005843.10343-1-atish.patra@wdc.com>
Since the RISC-V specification states that ISA description strings are
case-insensitive, there's no functional difference between mixed-case,
upper-case, and lower-case ISA strings. Thus, to simplify parsing,
specify that the letters present in "riscv,isa" must be all lowercase.
Suggested-by: Paul Walmsley <paul.walmsley@sifive.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
---
Documentation/devicetree/bindings/riscv/cpus.yaml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/riscv/cpus.yaml b/Documentation/devicetree/bindings/riscv/cpus.yaml
index c899111aa5e3..4f0acb00185a 100644
--- a/Documentation/devicetree/bindings/riscv/cpus.yaml
+++ b/Documentation/devicetree/bindings/riscv/cpus.yaml
@@ -46,10 +46,12 @@ properties:
- rv64imafdc
description:
Identifies the specific RISC-V instruction set architecture
- supported by the hart. These are documented in the RISC-V
+ supported by the hart. These are documented in the RISC-V
User-Level ISA document, available from
https://riscv.org/specifications/
+ Letters in the riscv,isa string must be all lowercase.
+
timebase-frequency:
type: integer
minimum: 1
--
2.21.0
^ permalink raw reply related
* [PATCH v3 4/5] RISC-V: Export few kernel symbols
From: Atish Patra @ 2019-08-01 0:58 UTC (permalink / raw)
To: linux-kernel
Cc: Mark Rutland, devicetree, Albert Ou, Daniel Lezcano, Yangtao Li,
Greg Kroah-Hartman, Anup Patel, Johan Hovold, Atish Patra,
Rob Herring, Palmer Dabbelt, Gary Guo, Paul Walmsley, linux-riscv,
Enrico Weigelt, Thomas Gleixner, Allison Randal
In-Reply-To: <20190801005843.10343-1-atish.patra@wdc.com>
Export few symbols used by kvm module. Without this, kvm can not
be compiled as a module.
Signed-off-by: Atish Patra <atish.patra@wdc.com>
---
arch/riscv/kernel/smp.c | 2 +-
arch/riscv/kernel/time.c | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/riscv/kernel/smp.c b/arch/riscv/kernel/smp.c
index 5a9834503a2f..402979f575de 100644
--- a/arch/riscv/kernel/smp.c
+++ b/arch/riscv/kernel/smp.c
@@ -193,4 +193,4 @@ void smp_send_reschedule(int cpu)
{
send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE);
}
-
+EXPORT_SYMBOL_GPL(smp_send_reschedule);
diff --git a/arch/riscv/kernel/time.c b/arch/riscv/kernel/time.c
index 541a2b885814..9dd1f2e64db1 100644
--- a/arch/riscv/kernel/time.c
+++ b/arch/riscv/kernel/time.c
@@ -9,6 +9,7 @@
#include <asm/sbi.h>
unsigned long riscv_timebase;
+EXPORT_SYMBOL_GPL(riscv_timebase);
void __init time_init(void)
{
--
2.21.0
^ permalink raw reply related
* [PATCH v3 3/5] RISC-V: Fix unsupported isa string info.
From: Atish Patra @ 2019-08-01 0:58 UTC (permalink / raw)
To: linux-kernel
Cc: Atish Patra, Albert Ou, Allison Randal, Anup Patel,
Daniel Lezcano, devicetree, Enrico Weigelt, Gary Guo,
Greg Kroah-Hartman, Johan Hovold, linux-riscv, Mark Rutland,
Palmer Dabbelt, Paul Walmsley, Rob Herring, Thomas Gleixner,
Yangtao Li
In-Reply-To: <20190801005843.10343-1-atish.patra@wdc.com>
Currently, kernel prints a info warning if any of the extensions
from "mafdcsu" is missing in device tree. This is not entirely
correct as Linux can boot with "f or d" extensions if kernel is
configured accordingly. Moreover, it will continue to print the
info string for future extensions such as hypervisor as well which
is misleading. /proc/cpuinfo also doesn't print any other extensions
except "mafdcsu".
Make sure that info log is only printed only if kernel is configured
to have any mandatory extensions but device tree doesn't describe it.
All the extensions present in device tree and follow the order
described in the RISC-V specification (except 'S') are printed via
/proc/cpuinfo always.
Signed-off-by: Atish Patra <atish.patra@wdc.com>
---
arch/riscv/kernel/cpu.c | 47 ++++++++++++++++++++++++++++++++---------
1 file changed, 37 insertions(+), 10 deletions(-)
diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c
index 7da3c6a93abd..9b1d4550fbe6 100644
--- a/arch/riscv/kernel/cpu.c
+++ b/arch/riscv/kernel/cpu.c
@@ -7,6 +7,7 @@
#include <linux/seq_file.h>
#include <linux/of.h>
#include <asm/smp.h>
+#include <asm/hwcap.h>
/*
* Returns the hart ID of the given device tree node, or -ENODEV if the node
@@ -46,11 +47,14 @@ int riscv_of_processor_hartid(struct device_node *node)
#ifdef CONFIG_PROC_FS
-static void print_isa(struct seq_file *f, const char *orig_isa)
+static void print_isa(struct seq_file *f, const char *orig_isa,
+ unsigned long cpuid)
{
- static const char *ext = "mafdcsu";
+ static const char *mandatory_ext = "mafdcsu";
const char *isa = orig_isa;
const char *e;
+ char unsupported_isa[26] = {0};
+ int index = 0;
/*
* Linux doesn't support rv32e or rv128i, and we only support booting
@@ -70,27 +74,50 @@ static void print_isa(struct seq_file *f, const char *orig_isa)
isa += 5;
/*
- * Check the rest of the ISA string for valid extensions, printing those
- * we find. RISC-V ISA strings define an order, so we only print the
+ * RISC-V ISA strings define an order, so we only print all the
* extension bits when they're in order. Hide the supervisor (S)
* extension from userspace as it's not accessible from there.
+ * Throw a warning only if any mandatory extensions are not available
+ * and kernel is configured to have that mandatory extensions.
*/
- for (e = ext; *e != '\0'; ++e) {
- if (isa[0] == e[0]) {
+ for (e = mandatory_ext; *e != '\0'; ++e) {
+ if (isa[0] != e[0]) {
+#if defined(CONFIG_ISA_RISCV_C)
+ if (isa[0] == 'c')
+ continue;
+#endif
+#if defined(CONFIG_FP)
+ if ((isa[0] == 'f') || (isa[0] == 'd'))
+ continue;
+#endif
+ unsupported_isa[index] = e[0];
+ index++;
+ }
+ /* Only write if part of isa string */
+ if (isa[0] != '\0') {
if (isa[0] != 's')
seq_write(f, isa, 1);
-
isa++;
}
}
+ if (isa[0] != '\0') {
+ /* Add remainging isa strings */
+ for (e = isa; *e != '\0'; ++e) {
+#if !defined(CONFIG_VIRTUALIZATION)
+ if (e[0] != 'h')
+#endif
+ seq_write(f, e, 1);
+ }
+ }
seq_puts(f, "\n");
/*
* If we were given an unsupported ISA in the device tree then print
* a bit of info describing what went wrong.
*/
- if (isa[0] != '\0')
- pr_info("unsupported ISA \"%s\" in device tree\n", orig_isa);
+ if (unsupported_isa[0])
+ pr_info("unsupported ISA extensions \"%s\" in device tree for cpu [%ld]\n",
+ unsupported_isa, cpuid);
}
static void print_mmu(struct seq_file *f, const char *mmu_type)
@@ -134,7 +161,7 @@ static int c_show(struct seq_file *m, void *v)
seq_printf(m, "processor\t: %lu\n", cpu_id);
seq_printf(m, "hart\t\t: %lu\n", cpuid_to_hartid_map(cpu_id));
if (!of_property_read_string(node, "riscv,isa", &isa))
- print_isa(m, isa);
+ print_isa(m, isa, cpu_id);
if (!of_property_read_string(node, "mmu-type", &mmu))
print_mmu(m, mmu);
if (!of_property_read_string(node, "compatible", &compat)
--
2.21.0
^ permalink raw reply related
* [PATCH v3 2/5] RISC-V: Add riscv_isa reprensenting ISA features common across CPUs
From: Atish Patra @ 2019-08-01 0:58 UTC (permalink / raw)
To: linux-kernel
Cc: Anup Patel, Atish Patra, Albert Ou, Allison Randal,
Daniel Lezcano, devicetree, Enrico Weigelt, Gary Guo,
Greg Kroah-Hartman, Johan Hovold, linux-riscv, Mark Rutland,
Palmer Dabbelt, Paul Walmsley, Rob Herring, Thomas Gleixner,
Yangtao Li
In-Reply-To: <20190801005843.10343-1-atish.patra@wdc.com>
From: Anup Patel <anup.patel@wdc.com>
This patch adds riscv_isa integer to represent ISA features common
across all CPUs. The riscv_isa is not same as elf_hwcap because
elf_hwcap will only have ISA features relevant for user-space apps
whereas riscv_isa will have ISA features relevant to both kernel
and user-space apps.
One of the use case is KVM hypervisor where riscv_isa will be used
to do following operations:
1. Check whether hypervisor extension is available
2. Find ISA features that need to be virtualized (e.g. floating
point support, vector extension, etc.)
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
---
arch/riscv/include/asm/hwcap.h | 16 ++++++++++++++
arch/riscv/kernel/cpufeature.c | 39 +++++++++++++++++++++++++++++++---
2 files changed, 52 insertions(+), 3 deletions(-)
diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
index 7ecb7c6a57b1..717306780add 100644
--- a/arch/riscv/include/asm/hwcap.h
+++ b/arch/riscv/include/asm/hwcap.h
@@ -22,5 +22,21 @@ enum {
};
extern unsigned long elf_hwcap;
+
+#define RISCV_ISA_EXT_a (1UL << ('a' - 'a'))
+#define RISCV_ISA_EXT_c (1UL << ('c' - 'a'))
+#define RISCV_ISA_EXT_d (1UL << ('d' - 'a'))
+#define RISCV_ISA_EXT_f (1UL << ('f' - 'a'))
+#define RISCV_ISA_EXT_h (1UL << ('h' - 'a'))
+#define RISCV_ISA_EXT_i (1UL << ('i' - 'a'))
+#define RISCV_ISA_EXT_m (1UL << ('m' - 'a'))
+#define RISCV_ISA_EXT_s (1UL << ('s' - 'a'))
+#define RISCV_ISA_EXT_u (1UL << ('u' - 'a'))
+
+extern unsigned long riscv_isa;
+
+#define riscv_isa_extension_available(ext_char) \
+ (riscv_isa & RISCV_ISA_EXT_##ext_char)
+
#endif
#endif
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index b1ade9a49347..becc99272341 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -12,6 +12,9 @@
#include <asm/smp.h>
unsigned long elf_hwcap __read_mostly;
+unsigned long riscv_isa __read_mostly;
+EXPORT_SYMBOL_GPL(riscv_isa);
+
#ifdef CONFIG_FPU
bool has_fpu __read_mostly;
#endif
@@ -20,7 +23,8 @@ void riscv_fill_hwcap(void)
{
struct device_node *node;
const char *isa;
- size_t i;
+ char print_str[BITS_PER_LONG+1];
+ size_t i, j, isa_len;
static unsigned long isa2hwcap[256] = {0};
isa2hwcap['i'] = isa2hwcap['I'] = COMPAT_HWCAP_ISA_I;
@@ -31,9 +35,11 @@ void riscv_fill_hwcap(void)
isa2hwcap['c'] = isa2hwcap['C'] = COMPAT_HWCAP_ISA_C;
elf_hwcap = 0;
+ riscv_isa = 0;
for_each_of_cpu_node(node) {
unsigned long this_hwcap = 0;
+ unsigned long this_isa = 0;
if (riscv_of_processor_hartid(node) < 0)
continue;
@@ -43,8 +49,20 @@ void riscv_fill_hwcap(void)
continue;
}
- for (i = 0; i < strlen(isa); ++i)
+ i = 0;
+ isa_len = strlen(isa);
+#if defined(CONFIG_32BIT)
+ if (!strncmp(isa, "rv32", 4))
+ i += 4;
+#elif defined(CONFIG_64BIT)
+ if (!strncmp(isa, "rv64", 4))
+ i += 4;
+#endif
+ for (; i < isa_len; ++i) {
this_hwcap |= isa2hwcap[(unsigned char)(isa[i])];
+ if ('a' <= isa[i] && isa[i] <= 'z')
+ this_isa |= (1UL << (isa[i] - 'a'));
+ }
/*
* All "okay" hart should have same isa. Set HWCAP based on
@@ -55,6 +73,11 @@ void riscv_fill_hwcap(void)
elf_hwcap &= this_hwcap;
else
elf_hwcap = this_hwcap;
+
+ if (riscv_isa)
+ riscv_isa &= this_isa;
+ else
+ riscv_isa = this_isa;
}
/* We don't support systems with F but without D, so mask those out
@@ -64,7 +87,17 @@ void riscv_fill_hwcap(void)
elf_hwcap &= ~COMPAT_HWCAP_ISA_F;
}
- pr_info("elf_hwcap is 0x%lx\n", elf_hwcap);
+ memset(print_str, 0, sizeof(print_str));
+ for (i = 0, j = 0; i < BITS_PER_LONG; i++)
+ if (riscv_isa & (1UL << i))
+ print_str[j++] = (char)('a' + i);
+ pr_info("riscv: ISA extensions %s\n", print_str);
+
+ memset(print_str, 0, sizeof(print_str));
+ for (i = 0, j = 0; i < BITS_PER_LONG; i++)
+ if (elf_hwcap & (1UL << i))
+ print_str[j++] = (char)('a' + i);
+ pr_info("riscv: ELF capabilities %s\n", print_str);
#ifdef CONFIG_FPU
if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D))
--
2.21.0
^ permalink raw reply related
* [PATCH v3 1/5] RISC-V: Remove per cpu clocksource
From: Atish Patra @ 2019-08-01 0:58 UTC (permalink / raw)
To: linux-kernel
Cc: Atish Patra, Albert Ou, Allison Randal, Anup Patel,
Daniel Lezcano, devicetree, Enrico Weigelt, Gary Guo,
Greg Kroah-Hartman, Johan Hovold, linux-riscv, Mark Rutland,
Palmer Dabbelt, Paul Walmsley, Rob Herring, Thomas Gleixner,
Yangtao Li
In-Reply-To: <20190801005843.10343-1-atish.patra@wdc.com>
There is only one clocksource in RISC-V. The boot cpu initializes
that clocksource. No need to keep a percpu data structure.
Signed-off-by: Atish Patra <atish.patra@wdc.com>
---
drivers/clocksource/timer-riscv.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/clocksource/timer-riscv.c b/drivers/clocksource/timer-riscv.c
index 5e6038fbf115..09e031176bc6 100644
--- a/drivers/clocksource/timer-riscv.c
+++ b/drivers/clocksource/timer-riscv.c
@@ -55,7 +55,7 @@ static u64 riscv_sched_clock(void)
return get_cycles64();
}
-static DEFINE_PER_CPU(struct clocksource, riscv_clocksource) = {
+static struct clocksource riscv_clocksource = {
.name = "riscv_clocksource",
.rating = 300,
.mask = CLOCKSOURCE_MASK(64),
@@ -92,7 +92,6 @@ void riscv_timer_interrupt(void)
static int __init riscv_timer_init_dt(struct device_node *n)
{
int cpuid, hartid, error;
- struct clocksource *cs;
hartid = riscv_of_processor_hartid(n);
if (hartid < 0) {
@@ -112,8 +111,7 @@ static int __init riscv_timer_init_dt(struct device_node *n)
pr_info("%s: Registering clocksource cpuid [%d] hartid [%d]\n",
__func__, cpuid, hartid);
- cs = per_cpu_ptr(&riscv_clocksource, cpuid);
- error = clocksource_register_hz(cs, riscv_timebase);
+ error = clocksource_register_hz(&riscv_clocksource, riscv_timebase);
if (error) {
pr_err("RISCV timer register failed [%d] for cpu = [%d]\n",
error, cpuid);
--
2.21.0
^ permalink raw reply related
* [PATCH v3 0/5] Miscellaneous fixes
From: Atish Patra @ 2019-08-01 0:58 UTC (permalink / raw)
To: linux-kernel
Cc: Mark Rutland, devicetree, Albert Ou, Daniel Lezcano, Yangtao Li,
Greg Kroah-Hartman, Anup Patel, Johan Hovold, Atish Patra,
Rob Herring, Palmer Dabbelt, Gary Guo, Paul Walmsley, linux-riscv,
Enrico Weigelt, Thomas Gleixner, Allison Randal
This patch series have some unrelated fixes related
to clocksource, dt-bindings and isa strings.
I combined them into series as most of them are
prerequisite for kvm patch series.
Changes from v2->v3:
1. Updated commit text of dt binding patch.
2. Removed couple of remaining uppercase usage.
Changes from v1->v2:
1. Dropped the case-insensitive support patch and added a dt-bindings
update patch.
2. Added a export symbol patch.
Anup Patel (1):
RISC-V: Add riscv_isa reprensenting ISA features common across CPUs
Atish Patra (4):
RISC-V: Remove per cpu clocksource
RISC-V: Fix unsupported isa string info.
RISC-V: Export few kernel symbols
dt-bindings: Update the riscv,isa string description
.../devicetree/bindings/riscv/cpus.yaml | 4 +-
arch/riscv/include/asm/hwcap.h | 16 +++++++
arch/riscv/kernel/cpu.c | 47 +++++++++++++++----
arch/riscv/kernel/cpufeature.c | 39 +++++++++++++--
arch/riscv/kernel/smp.c | 2 +-
arch/riscv/kernel/time.c | 1 +
drivers/clocksource/timer-riscv.c | 6 +--
7 files changed, 96 insertions(+), 19 deletions(-)
--
2.21.0
^ permalink raw reply
* RE: [EXT] Re: [Patch v3 2/2] dt-bindings: spi: spi-fsl-qspi: Add bindings of ls1088a and ls1012a
From: Leo Li @ 2019-07-31 23:28 UTC (permalink / raw)
To: Ashish Kumar, Rob Herring, Han Xu
Cc: devicetree@vger.kernel.org, bbrezillon@kernel.org, Kuldeep Singh,
broonie@kernel.org, linux-mtd@lists.infradead.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <VI1PR04MB4015206CD4AAA1E54C5978DA95DD0@VI1PR04MB4015.eurprd04.prod.outlook.com>
> -----Original Message-----
> From: Ashish Kumar
> Sent: Monday, July 29, 2019 4:09 AM
> To: Rob Herring <robh@kernel.org>; Leo Li <leoyang.li@nxp.com>
> Cc: devicetree@vger.kernel.org; bbrezillon@kernel.org; broonie@kernel.org;
> linux-arm-kernel@lists.infradead.org; linux-mtd@lists.infradead.org;
> Kuldeep Singh <kuldeep.singh@nxp.com>
> Subject: RE: [EXT] Re: [Patch v3 2/2] dt-bindings: spi: spi-fsl-qspi: Add
> bindings of ls1088a and ls1012a
>
>
>
> > -----Original Message-----
> > From: Rob Herring <robh@kernel.org>
> > Sent: Wednesday, July 10, 2019 1:39 AM
> > To: Ashish Kumar <ashish.kumar@nxp.com>
> > Cc: devicetree@vger.kernel.org; bbrezillon@kernel.org;
> > broonie@kernel.org; linux-arm-kernel@lists.infradead.org;
> > linux-mtd@lists.infradead.org; Ashish Kumar <ashish.kumar@nxp.com>;
> > Kuldeep Singh <kuldeep.singh@nxp.com>; Ashish Kumar
> > <ashish.kumar@nxp.com>
> > Subject: [EXT] Re: [Patch v3 2/2] dt-bindings: spi: spi-fsl-qspi: Add
> > bindings of ls1088a and ls1012a
> >
> > Caution: EXT Email
> >
> > On Wed, 19 Jun 2019 16:41:54 +0530, Ashish Kumar wrote:
> > > Signed-off-by: Kuldeep Singh <kuldeep.singh@nxp.com>
> > > Signed-off-by: Ashish Kumar <ashish.kumar@nxp.com>
> > > ---
> > > v3:
> > > Rebase to top
> > > v2:
> > > Convert to patch series and rebasing done on top of tree
> > >
> > > Documentation/devicetree/bindings/spi/spi-fsl-qspi.txt | 2 ++
> > > 1 file changed, 2 insertions(+)
> > >
> >
> > Reviewed-by: Rob Herring <robh@kernel.org>
>
> Hi Leo,
>
> I think Rob, is waiting for you ack.
Binding patches usually go through subsystem tree. So I think this actually need ack from qspi maintainer Han Xu and be picked up by SPI maintainer.
Regards,
Leo
^ permalink raw reply
* RE: [EXT] Re: [Patch v3 1/2] dt-bindings: spi: spi-fsl-qspi: Add ls2080a compatibility string to bindings
From: Leo Li @ 2019-07-31 23:26 UTC (permalink / raw)
To: Ashish Kumar, Rob Herring, Han Xu
Cc: devicetree@vger.kernel.org, bbrezillon@kernel.org, Kuldeep Singh,
broonie@kernel.org, linux-mtd@lists.infradead.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <VI1PR04MB4015B154965BA4BEF402890B95DD0@VI1PR04MB4015.eurprd04.prod.outlook.com>
> -----Original Message-----
> From: Ashish Kumar
> Sent: Monday, July 29, 2019 4:11 AM
> To: Rob Herring <robh@kernel.org>; Leo Li <leoyang.li@nxp.com>
> Cc: devicetree@vger.kernel.org; bbrezillon@kernel.org; broonie@kernel.org;
> linux-arm-kernel@lists.infradead.org; linux-mtd@lists.infradead.org;
> Kuldeep Singh <kuldeep.singh@nxp.com>
> Subject: RE: [EXT] Re: [Patch v3 1/2] dt-bindings: spi: spi-fsl-qspi: Add ls2080a
> compatibility string to bindings
>
>
>
> > -----Original Message-----
> > From: Rob Herring <robh@kernel.org>
> > Sent: Wednesday, July 10, 2019 1:39 AM
> > To: Ashish Kumar <ashish.kumar@nxp.com>
> > Cc: devicetree@vger.kernel.org; bbrezillon@kernel.org;
> > broonie@kernel.org; linux-arm-kernel@lists.infradead.org;
> > linux-mtd@lists.infradead.org; Ashish Kumar <ashish.kumar@nxp.com>;
> > Kuldeep Singh <kuldeep.singh@nxp.com>; Ashish Kumar
> > <ashish.kumar@nxp.com>
> > Subject: [EXT] Re: [Patch v3 1/2] dt-bindings: spi: spi-fsl-qspi: Add
> > ls2080a compatibility string to bindings
> >
> > Caution: EXT Email
> >
> > On Wed, 19 Jun 2019 16:41:53 +0530, Ashish Kumar wrote:
> > > There are 2 version of QSPI-IP, according to which controller
> > > registers sets can be big endian or little endian.There are some
> > > other minor changes like RX fifo depth etc.
> > >
> > > The big endian version uses driver compatible "fsl,ls1021a-qspi" and
> > > little endian version uses driver compatible "fsl,ls2080a-qspi"
> > >
> > > Signed-off-by: Kuldeep Singh <kuldeep.singh@nxp.com>
> > > Signed-off-by: Ashish Kumar <ashish.kumar@nxp.com>
> > > ---
> > > v3:
> > > Rebase to top
> > > v2:
> > > Convert to patch series and rebasing done on top of tree
> > >
> > > Documentation/devicetree/bindings/spi/spi-fsl-qspi.txt | 3 +--
> > > 1 file changed, 1 insertion(+), 2 deletions(-)
> > >
> >
> > Reviewed-by: Rob Herring <robh@kernel.org>
>
> Hi Leo,
>
> I think Rob, is waiting for you ack.
Binding patches usually go through subsystem tree. So I think this actually need ack from qspi maintainer Han Xu and be picked up by SPI maintainer.
Regards,
Leo
^ permalink raw reply
* Re: [PATCH 3/3] arm64: dts: ls1088a: Revise gpio registers to little-endian
From: Li Yang @ 2019-07-31 23:19 UTC (permalink / raw)
To: Chuanhua Han
Cc: Shawn Guo, Rob Herring, Mark Rutland, Linus Walleij,
Bartosz Golaszewski,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, lkml,
linux-gpio
In-Reply-To: <20190529083254.39581-3-chuanhua.han@nxp.com>
On Wed, May 29, 2019 at 3:32 AM Chuanhua Han <chuanhua.han@nxp.com> wrote:
>
> Since fsl-ls1088a Soc GPIO registers are used as little endian,
> the patch adds the little-endian attribute to each gpio node.
>
> Signed-off-by: Chuanhua Han <chuanhua.han@nxp.com>
Acked-by: Li Yang <leoyang.li@nxp.com>
> ---
> arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
> index 661137ffa319..3e6d20d065bd 100644
> --- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
> +++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
> @@ -272,6 +272,7 @@
> compatible = "fsl,qoriq-gpio";
> reg = <0x0 0x2300000 0x0 0x10000>;
> interrupts = <0 36 IRQ_TYPE_LEVEL_HIGH>;
> + little-endian;
> gpio-controller;
> #gpio-cells = <2>;
> interrupt-controller;
> @@ -282,6 +283,7 @@
> compatible = "fsl,qoriq-gpio";
> reg = <0x0 0x2310000 0x0 0x10000>;
> interrupts = <0 36 IRQ_TYPE_LEVEL_HIGH>;
> + little-endian;
> gpio-controller;
> #gpio-cells = <2>;
> interrupt-controller;
> @@ -292,6 +294,7 @@
> compatible = "fsl,qoriq-gpio";
> reg = <0x0 0x2320000 0x0 0x10000>;
> interrupts = <0 37 IRQ_TYPE_LEVEL_HIGH>;
> + little-endian;
> gpio-controller;
> #gpio-cells = <2>;
> interrupt-controller;
> @@ -302,6 +305,7 @@
> compatible = "fsl,qoriq-gpio";
> reg = <0x0 0x2330000 0x0 0x10000>;
> interrupts = <0 37 IRQ_TYPE_LEVEL_HIGH>;
> + little-endian;
> gpio-controller;
> #gpio-cells = <2>;
> interrupt-controller;
> --
> 2.17.1
>
^ permalink raw reply
* Re: [PATCH 1/2] arm64: dts: ls1028a: Fix GPIO work fail.
From: Li Yang @ 2019-07-31 23:17 UTC (permalink / raw)
To: Hui Song
Cc: Shawn Guo, Rob Herring, Mark Rutland, Linus Walleij,
Bartosz Golaszewski,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, lkml,
linux-gpio
In-Reply-To: <20190718094902.15562-1-hui.song_1@nxp.com>
On Thu, Jul 18, 2019 at 4:59 AM Hui Song <hui.song_1@nxp.com> wrote:
>
Change the title to be something like:
arm64: dts: ls1028a: fix gpio nodes
> From: Song Hui <hui.song_1@nxp.com>
>
> Add ls1028a device specify compatible.
Please submit a separate patch to update the device tree binding too.
> Make gpio as little-endian deal.
"Update the nodes to include little-endian property to be consistent
with the hardware."
>
> Signed-off-by: Song Hui <hui.song_1@nxp.com>
> ---
> arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 9 ++++++---
> 1 file changed, 6 insertions(+), 3 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
> index 7975519..488602b 100644
> --- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
> +++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
> @@ -277,33 +277,36 @@
> };
>
> gpio1: gpio@2300000 {
> - compatible = "fsl,qoriq-gpio";
> + compatible = "fsl,ls1028a-gpio","fsl,qoriq-gpio";
> reg = <0x0 0x2300000 0x0 0x10000>;
> interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
> gpio-controller;
> #gpio-cells = <2>;
> interrupt-controller;
> #interrupt-cells = <2>;
> + little-endian;
> };
>
> gpio2: gpio@2310000 {
> - compatible = "fsl,qoriq-gpio";
> + compatible = "fsl,ls1028a-gpio","fsl,qoriq-gpio";
> reg = <0x0 0x2310000 0x0 0x10000>;
> interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
> gpio-controller;
> #gpio-cells = <2>;
> interrupt-controller;
> #interrupt-cells = <2>;
> + little-endian;
> };
>
> gpio3: gpio@2320000 {
> - compatible = "fsl,qoriq-gpio";
> + compatible = "fsl,ls1028a-gpio","fsl,qoriq-gpio";
> reg = <0x0 0x2320000 0x0 0x10000>;
> interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
> gpio-controller;
> #gpio-cells = <2>;
> interrupt-controller;
> #interrupt-cells = <2>;
> + little-endian;
> };
>
> usb0: usb@3100000 {
> --
> 2.9.5
>
^ permalink raw reply
* Re: [PATCH v7 07/20] clk: tegra: clk-periph: Add save and restore support
From: Sowjanya Komatineni @ 2019-07-31 23:09 UTC (permalink / raw)
To: Dmitry Osipenko, thierry.reding, jonathanh, tglx, jason,
marc.zyngier, linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, linux-tegra, linux-kernel, mperttunen, spatra,
robh+dt, devicetree
In-Reply-To: <e796e26e-830c-b1be-e368-c7ff177a61dd@gmail.com>
On 7/31/19 3:44 AM, Dmitry Osipenko wrote:
> 31.07.2019 12:50, Dmitry Osipenko пишет:
>> 31.07.2019 3:20, Sowjanya Komatineni пишет:
>>> This patch implements save and restore context for peripheral fixed
>>> clock ops, peripheral gate clock ops, sdmmc mux clock ops, and
>>> peripheral clock ops.
>>>
>>> During system suspend, core power goes off and looses the settings
>>> of the Tegra CAR controller registers.
>>>
>>> So during suspend entry clock and reset state of peripherals is saved
>>> and on resume they are restored to have clocks back to same rate and
>>> state as before suspend.
>>>
>>> Acked-by: Thierry Reding <treding@nvidia.com>
>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>> ---
>>> drivers/clk/tegra/clk-periph-fixed.c | 33 ++++++++++++++++++++++++++++++++
>>> drivers/clk/tegra/clk-periph-gate.c | 34 +++++++++++++++++++++++++++++++++
>>> drivers/clk/tegra/clk-periph.c | 37 ++++++++++++++++++++++++++++++++++++
>>> drivers/clk/tegra/clk-sdmmc-mux.c | 28 +++++++++++++++++++++++++++
>>> drivers/clk/tegra/clk.h | 6 ++++++
>>> 5 files changed, 138 insertions(+)
>>>
>>> diff --git a/drivers/clk/tegra/clk-periph-fixed.c b/drivers/clk/tegra/clk-periph-fixed.c
>>> index c088e7a280df..21b24530fa00 100644
>>> --- a/drivers/clk/tegra/clk-periph-fixed.c
>>> +++ b/drivers/clk/tegra/clk-periph-fixed.c
>>> @@ -60,11 +60,44 @@ tegra_clk_periph_fixed_recalc_rate(struct clk_hw *hw,
>>> return (unsigned long)rate;
>>> }
>>>
>>> +static int tegra_clk_periph_fixed_save_context(struct clk_hw *hw)
>>> +{
>>> + struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw);
>>> + u32 mask = 1 << (fixed->num % 32);
>>> +
>>> + fixed->enb_ctx = readl_relaxed(fixed->base + fixed->regs->enb_reg) &
>>> + mask;
>>> + fixed->rst_ctx = readl_relaxed(fixed->base + fixed->regs->rst_reg) &
>>> + mask;
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static void tegra_clk_periph_fixed_restore_context(struct clk_hw *hw)
>>> +{
>>> + struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw);
>>> + u32 mask = 1 << (fixed->num % 32);
>>> +
>>> + if (fixed->enb_ctx)
>>> + writel_relaxed(mask, fixed->base + fixed->regs->enb_set_reg);
>>> + else
>>> + writel_relaxed(mask, fixed->base + fixed->regs->enb_clr_reg);
>>> +
>>> + udelay(2);
>>> +
>>> + if (!fixed->rst_ctx) {
>>> + udelay(5); /* reset propogation delay */
>>> + writel_relaxed(mask, fixed->base + fixed->regs->rst_reg);
>>> + }
>>> +}
>>> +
>>> static const struct clk_ops tegra_clk_periph_fixed_ops = {
>>> .is_enabled = tegra_clk_periph_fixed_is_enabled,
>>> .enable = tegra_clk_periph_fixed_enable,
>>> .disable = tegra_clk_periph_fixed_disable,
>>> .recalc_rate = tegra_clk_periph_fixed_recalc_rate,
>>> + .save_context = tegra_clk_periph_fixed_save_context,
>>> + .restore_context = tegra_clk_periph_fixed_restore_context,
>>> };
>>>
>>> struct clk *tegra_clk_register_periph_fixed(const char *name,
>>> diff --git a/drivers/clk/tegra/clk-periph-gate.c b/drivers/clk/tegra/clk-periph-gate.c
>>> index 4b31beefc9fc..6ba5b08e0787 100644
>>> --- a/drivers/clk/tegra/clk-periph-gate.c
>>> +++ b/drivers/clk/tegra/clk-periph-gate.c
>>> @@ -25,6 +25,8 @@ static DEFINE_SPINLOCK(periph_ref_lock);
>>>
>>> #define read_rst(gate) \
>>> readl_relaxed(gate->clk_base + (gate->regs->rst_reg))
>>> +#define write_rst_set(val, gate) \
>>> + writel_relaxed(val, gate->clk_base + (gate->regs->rst_set_reg))
>>> #define write_rst_clr(val, gate) \
>>> writel_relaxed(val, gate->clk_base + (gate->regs->rst_clr_reg))
>>>
>>> @@ -110,10 +112,42 @@ static void clk_periph_disable(struct clk_hw *hw)
>>> spin_unlock_irqrestore(&periph_ref_lock, flags);
>>> }
>>>
>>> +static int clk_periph_gate_save_context(struct clk_hw *hw)
>>> +{
>>> + struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
>>> +
>>> + gate->clk_state_ctx = read_enb(gate) & periph_clk_to_bit(gate);
>>> + gate->rst_state_ctx = read_rst(gate) & periph_clk_to_bit(gate);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static void clk_periph_gate_restore_context(struct clk_hw *hw)
>>> +{
>>> + struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
>>> +
>>> + if (gate->clk_state_ctx)
>>> + write_enb_set(periph_clk_to_bit(gate), gate);
>>> + else
>>> + write_enb_clr(periph_clk_to_bit(gate), gate);
>>> +
>>> + udelay(5);
>>> +
>>> + if (!(gate->flags & TEGRA_PERIPH_NO_RESET) &&
>>> + !(gate->flags & TEGRA_PERIPH_MANUAL_RESET)) {
>>> + if (gate->rst_state_ctx)
>>> + write_rst_set(periph_clk_to_bit(gate), gate);
>>> + else
>>> + write_rst_clr(periph_clk_to_bit(gate), gate);
>>> + }
>>> +}
>>> +
>>> const struct clk_ops tegra_clk_periph_gate_ops = {
>>> .is_enabled = clk_periph_is_enabled,
>>> .enable = clk_periph_enable,
>>> .disable = clk_periph_disable,
>>> + .save_context = clk_periph_gate_save_context,
>>> + .restore_context = clk_periph_gate_restore_context,
>>> };
>>>
>>> struct clk *tegra_clk_register_periph_gate(const char *name,
>>> diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c
>>> index 58437da25156..06fb62955768 100644
>>> --- a/drivers/clk/tegra/clk-periph.c
>>> +++ b/drivers/clk/tegra/clk-periph.c
>>> @@ -99,6 +99,37 @@ static void clk_periph_disable(struct clk_hw *hw)
>>> gate_ops->disable(gate_hw);
>>> }
>>>
>>> +static int clk_periph_save_context(struct clk_hw *hw)
>>> +{
>>> + struct tegra_clk_periph *periph = to_clk_periph(hw);
>>> + const struct clk_ops *gate_ops = periph->gate_ops;
>>> + struct clk_hw *gate_hw = &periph->gate.hw;
>>> +
>>> + if (!(periph->gate.flags & TEGRA_PERIPH_NO_GATE))
>>> + gate_ops->save_context(gate_hw);
>>> +
>>> + periph->parent_ctx = clk_periph_get_parent(hw);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static void clk_periph_restore_context(struct clk_hw *hw)
>>> +{
>>> + struct tegra_clk_periph *periph = to_clk_periph(hw);
>>> + const struct clk_ops *gate_ops = periph->gate_ops;
>>> + struct clk_hw *gate_hw = &periph->gate.hw;
>>> + const struct clk_ops *div_ops = periph->div_ops;
>>> + struct clk_hw *div_hw = &periph->divider.hw;
>>> +
>>> + clk_periph_set_parent(hw, periph->parent_ctx);
>>> +
>>> + if (!(periph->gate.flags & TEGRA_PERIPH_NO_DIV))
>>> + div_ops->restore_context(div_hw);
>> Could you please point to where the divider's save_context() happens?
>> Because I can't see it.
> Ah, I now see that there is no need to save the dividers context because
> clk itself has enough info that is needed for the context's restoring
> (like I pointed in the review to v6).
>
> Looks like you could also implement a new clk_hw_get_parent_index()
> generic helper to get the index instead of storing it manually.
clk_periph_get_parent basically invokes existing clk_mux_ops
get_parent() which is then saved in tegra_clk_periph.
All existing drivers are using directly get_parent() from clk_mux which
actually gets index from the register read.
To have this more generic w.r.t save/restore context point of view,
probably instead of implementing new get_parent_index helper, I think
its better to implement save_context and restore_context to clk_mux_ops
along with creating parent_index field into clk_mux to cache index
during set_parent.
So we just need to invoke mux_ops save_context and restore_context.
^ permalink raw reply
* [PATCH v2 6/6] irqchip/irq-pruss-intc: Add support for ICSSG INTC on K3 SoCs
From: Suman Anna @ 2019-07-31 22:41 UTC (permalink / raw)
To: Marc Zyngier, Thomas Gleixner, Jason Cooper
Cc: Rob Herring, David Lechner, Tony Lindgren, Andrew F. Davis,
Roger Quadros, Lokesh Vutla, Grygorii Strashko, Sekhar Nori,
Murali Karicheri, devicetree, linux-omap, linux-arm-kernel,
linux-kernel, Suman Anna
In-Reply-To: <20190731224149.11153-1-s-anna@ti.com>
The K3 AM65x and J721E SoCs have the next generation of the PRU-ICSS IP,
commonly called ICSSG. The PRUSS INTC present within the ICSSG supports
more System Events (160 vs 64), more Interrupt Channels and Host Interrupts
(20 vs 10) compared to the previous generation PRUSS INTC instances. The
first 2 and the last 10 of these host interrupt lines are used by the
PRU and other auxiliary cores and sub-modules within the ICSSG, with 8
host interrupts connected to MPU. The host interrupts 5, 6, 7 are also
connected to the other ICSSG instances within the SoC and can be
partitioned as per system integration through the board dts files.
Enhance the PRUSS INTC driver to add support for this ICSSG INTC
instance. This support is added using specific compatible and match
data and updating the code to use this data instead of the current
hard-coded macros. The INTC config structure is updated to use the
higher events and channels on all SoCs, while limiting the actual
processing to only the relevant number of events/channels/interrupts.
Signed-off-by: Suman Anna <s-anna@ti.com>
---
v2:
- Rebased patch with indexed macros like ESRx, ECRx where x = 0,1 dropped
v1: https://patchwork.kernel.org/patch/11034543/
drivers/irqchip/Kconfig | 2 +-
drivers/irqchip/irq-pruss-intc.c | 181 +++++++++++++++++--------
include/linux/irqchip/irq-pruss-intc.h | 4 +-
3 files changed, 126 insertions(+), 61 deletions(-)
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index dc6b5aa77a5d..a98bfec6b364 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -473,7 +473,7 @@ config TI_SCI_INTA_IRQCHIP
config TI_PRUSS_INTC
tristate "TI PRU-ICSS Interrupt Controller"
- depends on ARCH_DAVINCI || SOC_AM33XX || SOC_AM437X || SOC_DRA7XX || ARCH_KEYSTONE
+ depends on ARCH_DAVINCI || SOC_AM33XX || SOC_AM437X || SOC_DRA7XX || ARCH_KEYSTONE || ARCH_K3
select IRQ_DOMAIN
help
This enables support for the PRU-ICSS Local Interrupt Controller
diff --git a/drivers/irqchip/irq-pruss-intc.c b/drivers/irqchip/irq-pruss-intc.c
index 59e26dfbb179..891a14b6c399 100644
--- a/drivers/irqchip/irq-pruss-intc.c
+++ b/drivers/irqchip/irq-pruss-intc.c
@@ -7,6 +7,7 @@
* Suman Anna <s-anna@ti.com>
*/
+#include <linux/bitmap.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqchip/chained_irq.h>
@@ -26,9 +27,6 @@
/* minimum starting host interrupt number for MPU */
#define MIN_PRU_HOST_INT 2
-/* maximum number of host interrupts */
-#define MAX_PRU_HOST_INT 10
-
/* PRU_ICSS_INTC registers */
#define PRU_INTC_REVID 0x0000
#define PRU_INTC_CR 0x0004
@@ -42,19 +40,14 @@
#define PRU_INTC_HIDISR 0x0038
#define PRU_INTC_GPIR 0x0080
#define PRU_INTC_SRSR(x) (0x0200 + (x) * 4)
-#define PRU_INTC_SECR0 0x0280
-#define PRU_INTC_SECR1 0x0284
-#define PRU_INTC_ESR0 0x0300
-#define PRU_INTC_ESR1 0x0304
-#define PRU_INTC_ECR0 0x0380
-#define PRU_INTC_ECR1 0x0384
+#define PRU_INTC_SECR(x) (0x0280 + (x) * 4)
+#define PRU_INTC_ESR(x) (0x0300 + (x) * 4)
+#define PRU_INTC_ECR(x) (0x0380 + (x) * 4)
#define PRU_INTC_CMR(x) (0x0400 + (x) * 4)
#define PRU_INTC_HMR(x) (0x0800 + (x) * 4)
#define PRU_INTC_HIPIR(x) (0x0900 + (x) * 4)
-#define PRU_INTC_SIPR0 0x0d00
-#define PRU_INTC_SIPR1 0x0d04
-#define PRU_INTC_SITR0 0x0d80
-#define PRU_INTC_SITR1 0x0d84
+#define PRU_INTC_SIPR(x) (0x0d00 + (x) * 4)
+#define PRU_INTC_SITR(x) (0x0d80 + (x) * 4)
#define PRU_INTC_HINLR(x) (0x1100 + (x) * 4)
#define PRU_INTC_HIER 0x1500
@@ -71,12 +64,23 @@
/* HIPIR register bit-fields */
#define INTC_HIPIR_NONE_HINT 0x80000000
+/**
+ * struct pruss_intc_match_data - match data to handle SoC variations
+ * @num_system_events: number of input system events handled by the PRUSS INTC
+ * @num_host_intrs: number of host interrupts supported by the PRUSS INTC
+ */
+struct pruss_intc_match_data {
+ u8 num_system_events;
+ u8 num_host_intrs;
+};
+
/**
* struct pruss_intc - PRUSS interrupt controller structure
* @irqs: kernel irq numbers corresponding to PRUSS host interrupts
* @base: base virtual address of INTC register space
* @irqchip: irq chip for this interrupt controller
* @domain: irq domain for this interrupt controller
+ * @data: cached PRUSS INTC IP configuration data
* @config_map: stored INTC configuration mapping data
* @lock: mutex to serialize access to INTC
* @host_mask: indicate which HOST IRQs are enabled
@@ -88,6 +92,7 @@ struct pruss_intc {
void __iomem *base;
struct irq_chip *irqchip;
struct irq_domain *domain;
+ const struct pruss_intc_match_data *data;
struct pruss_intc_config config_map;
struct mutex lock; /* PRUSS INTC lock */
u32 host_mask;
@@ -112,7 +117,7 @@ static int pruss_intc_check_write(struct pruss_intc *intc, unsigned int reg,
if (!intc)
return -EINVAL;
- if (sysevent >= MAX_PRU_SYS_EVENTS)
+ if (sysevent >= intc->data->num_system_events)
return -EINVAL;
pruss_intc_write_reg(intc, reg, sysevent);
@@ -191,16 +196,28 @@ int pruss_intc_configure(struct device *dev,
struct pruss_intc_config *intc_config)
{
struct pruss_intc *intc;
- int i, idx, ret;
+ int i, idx;
s8 ch, host;
- u64 sysevt_mask = 0;
+ u32 num_events, num_intrs, num_regs;
+ unsigned long *sysevt_bitmap;
+ u32 *sysevts;
u32 ch_mask = 0;
u32 host_mask = 0;
+ int ret = 0;
intc = to_pruss_intc(dev);
if (IS_ERR(intc))
return PTR_ERR(intc);
+ num_events = intc->data->num_system_events;
+ num_intrs = intc->data->num_host_intrs;
+ num_regs = DIV_ROUND_UP(num_events, 32);
+
+ sysevt_bitmap = bitmap_zalloc(num_events, GFP_KERNEL);
+ if (!sysevt_bitmap)
+ return -ENOMEM;
+ sysevts = (u32 *)sysevt_bitmap;
+
mutex_lock(&intc->lock);
/*
@@ -208,7 +225,7 @@ int pruss_intc_configure(struct device *dev,
* for 4 events, with each event occupying the lower nibble in
* a register byte address in little-endian fashion
*/
- for (i = 0; i < ARRAY_SIZE(intc_config->sysev_to_ch); i++) {
+ for (i = 0; i < num_events; i++) {
ch = intc_config->sysev_to_ch[i];
if (ch < 0)
continue;
@@ -223,7 +240,7 @@ int pruss_intc_configure(struct device *dev,
intc->config_map.sysev_to_ch[i] = ch;
pruss_intc_update_cmr(intc, i, ch);
- sysevt_mask |= BIT_ULL(i);
+ bitmap_set(sysevt_bitmap, i, 1);
ch_mask |= BIT(ch);
idx = i / CMR_EVT_PER_REG;
@@ -236,7 +253,7 @@ int pruss_intc_configure(struct device *dev,
* 4 channels, with each channel occupying the lower nibble in
* a register byte address in little-endian fashion
*/
- for (i = 0; i < ARRAY_SIZE(intc_config->ch_to_host); i++) {
+ for (i = 0; i < num_intrs; i++) {
host = intc_config->ch_to_host[i];
if (host < 0)
continue;
@@ -267,17 +284,19 @@ int pruss_intc_configure(struct device *dev,
pruss_intc_read_reg(intc, PRU_INTC_HMR(idx)));
}
- dev_info(dev, "configured system_events = 0x%016llx intr_channels = 0x%08x host_intr = 0x%08x\n",
- sysevt_mask, ch_mask, host_mask);
+ dev_info(dev, "configured system_events[%d-0] = %*pb\n",
+ num_events - 1, num_events, sysevt_bitmap);
+ dev_info(dev, "configured intr_channels = 0x%08x host_intr = 0x%08x\n",
+ ch_mask, host_mask);
/* enable system events, writing 0 has no-effect */
- pruss_intc_write_reg(intc, PRU_INTC_ESR0, lower_32_bits(sysevt_mask));
- pruss_intc_write_reg(intc, PRU_INTC_SECR0, lower_32_bits(sysevt_mask));
- pruss_intc_write_reg(intc, PRU_INTC_ESR1, upper_32_bits(sysevt_mask));
- pruss_intc_write_reg(intc, PRU_INTC_SECR1, upper_32_bits(sysevt_mask));
+ for (i = 0; i < num_regs; i++) {
+ pruss_intc_write_reg(intc, PRU_INTC_ESR(i), sysevts[i]);
+ pruss_intc_write_reg(intc, PRU_INTC_SECR(i), sysevts[i]);
+ }
/* enable host interrupts */
- for (i = 0; i < MAX_PRU_HOST_INT; i++) {
+ for (i = 0; i < num_intrs; i++) {
if (host_mask & BIT(i))
pruss_intc_write_reg(intc, PRU_INTC_HIEISR, i);
}
@@ -286,9 +305,7 @@ int pruss_intc_configure(struct device *dev,
pruss_intc_write_reg(intc, PRU_INTC_GER, 1);
intc->host_mask |= host_mask;
-
- mutex_unlock(&intc->lock);
- return 0;
+ goto out;
fail_ch:
while (--i >= 0) {
@@ -297,7 +314,7 @@ int pruss_intc_configure(struct device *dev,
pruss_intc_update_hmr(intc, i, 0);
}
}
- i = ARRAY_SIZE(intc_config->sysev_to_ch);
+ i = num_events;
fail_evt:
while (--i >= 0) {
if (intc_config->sysev_to_ch[i] >= 0) {
@@ -305,7 +322,9 @@ int pruss_intc_configure(struct device *dev,
pruss_intc_update_cmr(intc, i, 0);
}
}
+out:
mutex_unlock(&intc->lock);
+ bitmap_free(sysevt_bitmap);
return ret;
}
EXPORT_SYMBOL_GPL(pruss_intc_configure);
@@ -325,28 +344,39 @@ int pruss_intc_unconfigure(struct device *dev,
struct pruss_intc *intc;
int i;
s8 ch, host;
- u64 sysevt_mask = 0;
+ u32 num_events, num_intrs, num_regs;
+ unsigned long *sysevt_bitmap;
+ u32 *sysevts;
u32 host_mask = 0;
intc = to_pruss_intc(dev);
if (IS_ERR(intc))
return PTR_ERR(intc);
+ num_events = intc->data->num_system_events;
+ num_intrs = intc->data->num_host_intrs;
+ num_regs = DIV_ROUND_UP(num_events, 32);
+
+ sysevt_bitmap = bitmap_zalloc(num_events, GFP_KERNEL);
+ if (!sysevt_bitmap)
+ return -ENOMEM;
+ sysevts = (u32 *)sysevt_bitmap;
+
mutex_lock(&intc->lock);
- for (i = 0; i < ARRAY_SIZE(intc_config->sysev_to_ch); i++) {
+ for (i = 0; i < num_events; i++) {
ch = intc_config->sysev_to_ch[i];
if (ch < 0)
continue;
/* mark sysevent free in global map */
intc->config_map.sysev_to_ch[i] = PRU_INTC_FREE;
- sysevt_mask |= BIT_ULL(i);
+ bitmap_set(sysevt_bitmap, i, 1);
/* clear the map using reset value 0 */
pruss_intc_update_cmr(intc, i, 0);
}
- for (i = 0; i < ARRAY_SIZE(intc_config->ch_to_host); i++) {
+ for (i = 0; i < num_intrs; i++) {
host = intc_config->ch_to_host[i];
if (host < 0)
continue;
@@ -358,24 +388,26 @@ int pruss_intc_unconfigure(struct device *dev,
pruss_intc_update_hmr(intc, i, 0);
}
- dev_info(dev, "unconfigured system_events = 0x%016llx host_intr = 0x%08x\n",
- sysevt_mask, host_mask);
+ dev_info(dev, "unconfigured system_events[%d-0] = %*pb\n",
+ num_events - 1, num_events, sysevt_bitmap);
+ dev_info(dev, "unconfigured host_intr = 0x%08x\n", host_mask);
- /* disable system events, writing 0 has no-effect */
- pruss_intc_write_reg(intc, PRU_INTC_ECR0, lower_32_bits(sysevt_mask));
- pruss_intc_write_reg(intc, PRU_INTC_ECR1, upper_32_bits(sysevt_mask));
- /* clear any pending status */
- pruss_intc_write_reg(intc, PRU_INTC_SECR0, lower_32_bits(sysevt_mask));
- pruss_intc_write_reg(intc, PRU_INTC_SECR1, upper_32_bits(sysevt_mask));
+ for (i = 0; i < num_regs; i++) {
+ /* disable system events, writing 0 has no-effect */
+ pruss_intc_write_reg(intc, PRU_INTC_ECR(i), sysevts[i]);
+ /* clear any pending status */
+ pruss_intc_write_reg(intc, PRU_INTC_SECR(i), sysevts[i]);
+ }
/* disable host interrupts */
- for (i = 0; i < MAX_PRU_HOST_INT; i++) {
+ for (i = 0; i < num_intrs; i++) {
if (host_mask & BIT(i))
pruss_intc_write_reg(intc, PRU_INTC_HIDISR, i);
}
intc->host_mask &= ~host_mask;
mutex_unlock(&intc->lock);
+ bitmap_free(sysevt_bitmap);
return 0;
}
@@ -384,21 +416,28 @@ EXPORT_SYMBOL_GPL(pruss_intc_unconfigure);
static void pruss_intc_init(struct pruss_intc *intc)
{
int i;
+ int num_chnl_map_regs = DIV_ROUND_UP(intc->data->num_system_events,
+ CMR_EVT_PER_REG);
+ int num_host_intr_regs = DIV_ROUND_UP(intc->data->num_host_intrs,
+ HMR_CH_PER_REG);
+ int num_event_type_regs =
+ DIV_ROUND_UP(intc->data->num_system_events, 32);
- /* configure polarity to active high for all system interrupts */
- pruss_intc_write_reg(intc, PRU_INTC_SIPR0, 0xffffffff);
- pruss_intc_write_reg(intc, PRU_INTC_SIPR1, 0xffffffff);
-
- /* configure type to pulse interrupt for all system interrupts */
- pruss_intc_write_reg(intc, PRU_INTC_SITR0, 0);
- pruss_intc_write_reg(intc, PRU_INTC_SITR1, 0);
+ /*
+ * configure polarity (SIPR register) to active high and
+ * type (SITR register) to pulse interrupt for all system events
+ */
+ for (i = 0; i < num_event_type_regs; i++) {
+ pruss_intc_write_reg(intc, PRU_INTC_SIPR(i), 0xffffffff);
+ pruss_intc_write_reg(intc, PRU_INTC_SITR(i), 0);
+ }
- /* clear all 16 interrupt channel map registers */
- for (i = 0; i < 16; i++)
+ /* clear all interrupt channel map registers, 4 events per register */
+ for (i = 0; i < num_chnl_map_regs; i++)
pruss_intc_write_reg(intc, PRU_INTC_CMR(i), 0);
- /* clear all 3 host interrupt map registers */
- for (i = 0; i < 3; i++)
+ /* clear all host interrupt map registers, 4 channels per register */
+ for (i = 0; i < num_host_intr_regs; i++)
pruss_intc_write_reg(intc, PRU_INTC_HMR(i), 0);
}
@@ -549,11 +588,20 @@ static int pruss_intc_probe(struct platform_device *pdev)
struct resource *res;
struct irq_chip *irqchip;
int i, irq, count;
+ const struct pruss_intc_match_data *data;
u8 temp_intr[MAX_NUM_HOST_IRQS] = { 0 };
+ u8 max_system_events;
+
+ data = of_device_get_match_data(dev);
+ if (!data)
+ return -ENODEV;
+
+ max_system_events = data->num_system_events;
intc = devm_kzalloc(dev, sizeof(*intc), GFP_KERNEL);
if (!intc)
return -ENOMEM;
+ intc->data = data;
platform_set_drvdata(pdev, intc);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -623,8 +671,7 @@ static int pruss_intc_probe(struct platform_device *pdev)
irqchip->name = dev_name(dev);
intc->irqchip = irqchip;
- /* always 64 events */
- intc->domain = irq_domain_add_linear(dev->of_node, MAX_PRU_SYS_EVENTS,
+ intc->domain = irq_domain_add_linear(dev->of_node, max_system_events,
&pruss_intc_irq_domain_ops, intc);
if (!intc->domain)
return -ENOMEM;
@@ -661,6 +708,7 @@ static int pruss_intc_probe(struct platform_device *pdev)
static int pruss_intc_remove(struct platform_device *pdev)
{
struct pruss_intc *intc = platform_get_drvdata(pdev);
+ u8 max_system_events = intc->data->num_system_events;
unsigned int hwirq;
int i;
@@ -670,15 +718,32 @@ static int pruss_intc_remove(struct platform_device *pdev)
NULL);
}
- for (hwirq = 0; hwirq < MAX_PRU_SYS_EVENTS; hwirq++)
+ for (hwirq = 0; hwirq < max_system_events; hwirq++)
irq_dispose_mapping(irq_find_mapping(intc->domain, hwirq));
irq_domain_remove(intc->domain);
return 0;
}
+static const struct pruss_intc_match_data pruss_intc_data = {
+ .num_system_events = 64,
+ .num_host_intrs = 10,
+};
+
+static const struct pruss_intc_match_data icssg_intc_data = {
+ .num_system_events = 160,
+ .num_host_intrs = 20,
+};
+
static const struct of_device_id pruss_intc_of_match[] = {
- { .compatible = "ti,pruss-intc", },
+ {
+ .compatible = "ti,pruss-intc",
+ .data = &pruss_intc_data,
+ },
+ {
+ .compatible = "ti,icssg-intc",
+ .data = &icssg_intc_data,
+ },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, pruss_intc_of_match);
diff --git a/include/linux/irqchip/irq-pruss-intc.h b/include/linux/irqchip/irq-pruss-intc.h
index daffc048b303..cc6f9190b04f 100644
--- a/include/linux/irqchip/irq-pruss-intc.h
+++ b/include/linux/irqchip/irq-pruss-intc.h
@@ -10,10 +10,10 @@
#define __LINUX_IRQ_PRUSS_INTC_H
/* maximum number of system events */
-#define MAX_PRU_SYS_EVENTS 64
+#define MAX_PRU_SYS_EVENTS 160
/* maximum number of interrupt channels */
-#define MAX_PRU_CHANNELS 10
+#define MAX_PRU_CHANNELS 20
/* use -1 to mark unassigned events and channels */
#define PRU_INTC_FREE -1
--
2.22.0
^ permalink raw reply related
* [PATCH v2 5/6] irqchip/irq-pruss-intc: Implement irq_{get,set}_irqchip_state ops
From: Suman Anna @ 2019-07-31 22:41 UTC (permalink / raw)
To: Marc Zyngier, Thomas Gleixner, Jason Cooper
Cc: Rob Herring, David Lechner, Tony Lindgren, Andrew F. Davis,
Roger Quadros, Lokesh Vutla, Grygorii Strashko, Sekhar Nori,
Murali Karicheri, devicetree, linux-omap, linux-arm-kernel,
linux-kernel, Suman Anna
In-Reply-To: <20190731224149.11153-1-s-anna@ti.com>
From: David Lechner <david@lechnology.com>
This implements the irq_get_irqchip_state and irq_set_irqchip_state
callbacks for the TI PRUSS INTC driver. The set callback can be used
by drivers to "kick" a PRU by enabling a PRU system event.
Example:
irq_set_irqchip_state(irq, IRQCHIP_STATE_PENDING, true);
Signed-off-by: David Lechner <david@lechnology.com>
Signed-off-by: Suman Anna <s-anna@ti.com>
---
v2: New patch from David replacing an exported API from v1,
https://patchwork.kernel.org/patch/11034565/
drivers/irqchip/irq-pruss-intc.c | 41 ++++++++++++++++++++++++++++++--
1 file changed, 39 insertions(+), 2 deletions(-)
diff --git a/drivers/irqchip/irq-pruss-intc.c b/drivers/irqchip/irq-pruss-intc.c
index 63cfc665be1e..59e26dfbb179 100644
--- a/drivers/irqchip/irq-pruss-intc.c
+++ b/drivers/irqchip/irq-pruss-intc.c
@@ -7,6 +7,7 @@
* Suman Anna <s-anna@ti.com>
*/
+#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/irqchip/irq-pruss-intc.h>
@@ -40,8 +41,7 @@
#define PRU_INTC_HIEISR 0x0034
#define PRU_INTC_HIDISR 0x0038
#define PRU_INTC_GPIR 0x0080
-#define PRU_INTC_SRSR0 0x0200
-#define PRU_INTC_SRSR1 0x0204
+#define PRU_INTC_SRSR(x) (0x0200 + (x) * 4)
#define PRU_INTC_SECR0 0x0280
#define PRU_INTC_SECR1 0x0284
#define PRU_INTC_ESR0 0x0300
@@ -439,6 +439,41 @@ static void pruss_intc_irq_relres(struct irq_data *data)
module_put(THIS_MODULE);
}
+static int pruss_intc_irq_get_irqchip_state(struct irq_data *data,
+ enum irqchip_irq_state which,
+ bool *state)
+{
+ struct pruss_intc *intc = irq_data_get_irq_chip_data(data);
+ u32 reg, mask, srsr;
+
+ if (which != IRQCHIP_STATE_PENDING)
+ return -EINVAL;
+
+ reg = PRU_INTC_SRSR(data->hwirq / 32);
+ mask = BIT(data->hwirq % 32);
+
+ srsr = pruss_intc_read_reg(intc, reg);
+
+ *state = !!(srsr & mask);
+
+ return 0;
+}
+
+static int pruss_intc_irq_set_irqchip_state(struct irq_data *data,
+ enum irqchip_irq_state which,
+ bool state)
+{
+ struct pruss_intc *intc = irq_data_get_irq_chip_data(data);
+
+ if (which != IRQCHIP_STATE_PENDING)
+ return -EINVAL;
+
+ if (state)
+ return pruss_intc_check_write(intc, PRU_INTC_SISR, data->hwirq);
+
+ return pruss_intc_check_write(intc, PRU_INTC_SICR, data->hwirq);
+}
+
static int pruss_intc_irq_domain_map(struct irq_domain *d, unsigned int virq,
irq_hw_number_t hw)
{
@@ -583,6 +618,8 @@ static int pruss_intc_probe(struct platform_device *pdev)
irqchip->irq_unmask = pruss_intc_irq_unmask;
irqchip->irq_request_resources = pruss_intc_irq_reqres;
irqchip->irq_release_resources = pruss_intc_irq_relres;
+ irqchip->irq_get_irqchip_state = pruss_intc_irq_get_irqchip_state;
+ irqchip->irq_set_irqchip_state = pruss_intc_irq_set_irqchip_state;
irqchip->name = dev_name(dev);
intc->irqchip = irqchip;
--
2.22.0
^ permalink raw reply related
* [PATCH v2 4/6] irqchip/irq-pruss-intc: Add helper functions to configure internal mapping
From: Suman Anna @ 2019-07-31 22:41 UTC (permalink / raw)
To: Marc Zyngier, Thomas Gleixner, Jason Cooper
Cc: Rob Herring, David Lechner, Tony Lindgren, Andrew F. Davis,
Roger Quadros, Lokesh Vutla, Grygorii Strashko, Sekhar Nori,
Murali Karicheri, devicetree, linux-omap, linux-arm-kernel,
linux-kernel, Suman Anna
In-Reply-To: <20190731224149.11153-1-s-anna@ti.com>
The PRUSS INTC receives a number of system input interrupt source events
and supports individual control configuration and hardware prioritization.
These input events can be mapped to some output interrupt lines through 2
levels of many-to-one mapping i.e. events to channel mapping and channels
to output interrupts.
This mapping information is provided through the PRU firmware that is
loaded onto a PRU core/s or through the device tree node of the PRU
application. The mapping is configured by the PRU remoteproc driver, and
is setup before the PRU core is started and cleaned up after the PRU core
is stopped. This event mapping configuration logic programs the Channel
Map Registers (CMRx) and Host-Interrupt Map Registers (HMRx) only when a
new program is being loaded/started and the same events and interrupt
channels are reset to zero when stopping a PRU.
Add two helper functions: pruss_intc_configure() & pruss_intc_unconfigure()
that the PRU remoteproc driver can use to configure the PRUSS INTC.
Signed-off-by: Suman Anna <s-anna@ti.com>
Signed-off-by: Andrew F. Davis <afd@ti.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
v2:
- Added new internal helper functions pruss_intc_update_cmr/hmr for
programming CMR and HMR registers
- Added unroll logic on failures in pruss_intc_configure() using the
refactored functions
- Updated unconfigure logic to reset the map registers and updated
patch description accordingly
- Renamed the FREE macro to PRU_INTC_FREE and moved it to header file
v1: https://patchwork.kernel.org/patch/11034563/
drivers/irqchip/irq-pruss-intc.c | 286 ++++++++++++++++++++++++-
include/linux/irqchip/irq-pruss-intc.h | 36 ++++
2 files changed, 320 insertions(+), 2 deletions(-)
create mode 100644 include/linux/irqchip/irq-pruss-intc.h
diff --git a/drivers/irqchip/irq-pruss-intc.c b/drivers/irqchip/irq-pruss-intc.c
index 3a1b8a93cfad..63cfc665be1e 100644
--- a/drivers/irqchip/irq-pruss-intc.c
+++ b/drivers/irqchip/irq-pruss-intc.c
@@ -9,6 +9,7 @@
#include <linux/irq.h>
#include <linux/irqchip/chained_irq.h>
+#include <linux/irqchip/irq-pruss-intc.h>
#include <linux/irqdomain.h>
#include <linux/module.h>
#include <linux/of_device.h>
@@ -24,8 +25,8 @@
/* minimum starting host interrupt number for MPU */
#define MIN_PRU_HOST_INT 2
-/* maximum number of system events */
-#define MAX_PRU_SYS_EVENTS 64
+/* maximum number of host interrupts */
+#define MAX_PRU_HOST_INT 10
/* PRU_ICSS_INTC registers */
#define PRU_INTC_REVID 0x0000
@@ -57,6 +58,16 @@
#define PRU_INTC_HINLR(x) (0x1100 + (x) * 4)
#define PRU_INTC_HIER 0x1500
+/* CMR register bit-field macros */
+#define CMR_EVT_MAP_MASK 0xf
+#define CMR_EVT_MAP_BITS 8
+#define CMR_EVT_PER_REG 4
+
+/* HMR register bit-field macros */
+#define HMR_CH_MAP_MASK 0xf
+#define HMR_CH_MAP_BITS 8
+#define HMR_CH_PER_REG 4
+
/* HIPIR register bit-fields */
#define INTC_HIPIR_NONE_HINT 0x80000000
@@ -66,7 +77,9 @@
* @base: base virtual address of INTC register space
* @irqchip: irq chip for this interrupt controller
* @domain: irq domain for this interrupt controller
+ * @config_map: stored INTC configuration mapping data
* @lock: mutex to serialize access to INTC
+ * @host_mask: indicate which HOST IRQs are enabled
* @shared_intr: bit-map denoting if the MPU host interrupt is shared
* @invalid_intr: bit-map denoting if host interrupt is not connected to MPU
*/
@@ -75,7 +88,9 @@ struct pruss_intc {
void __iomem *base;
struct irq_chip *irqchip;
struct irq_domain *domain;
+ struct pruss_intc_config config_map;
struct mutex lock; /* PRUSS INTC lock */
+ u32 host_mask;
u16 shared_intr;
u16 invalid_intr;
};
@@ -105,6 +120,267 @@ static int pruss_intc_check_write(struct pruss_intc *intc, unsigned int reg,
return 0;
}
+static void pruss_intc_update_cmr(struct pruss_intc *intc, int evt, s8 ch)
+{
+ u32 idx, val;
+
+ idx = evt / CMR_EVT_PER_REG;
+ val = pruss_intc_read_reg(intc, PRU_INTC_CMR(idx));
+ val &= ~(CMR_EVT_MAP_MASK <<
+ ((evt % CMR_EVT_PER_REG) * CMR_EVT_MAP_BITS));
+ val |= ch << ((evt % CMR_EVT_PER_REG) * CMR_EVT_MAP_BITS);
+ pruss_intc_write_reg(intc, PRU_INTC_CMR(idx), val);
+}
+
+static void pruss_intc_update_hmr(struct pruss_intc *intc, int ch, s8 host)
+{
+ u32 idx, val;
+
+ idx = ch / HMR_CH_PER_REG;
+ val = pruss_intc_read_reg(intc, PRU_INTC_HMR(idx));
+ val &= ~(HMR_CH_MAP_MASK <<
+ ((ch % HMR_CH_PER_REG) * HMR_CH_MAP_BITS));
+ val |= host << ((ch % HMR_CH_PER_REG) * HMR_CH_MAP_BITS);
+ pruss_intc_write_reg(intc, PRU_INTC_HMR(idx), val);
+}
+
+static struct pruss_intc *to_pruss_intc(struct device *pru_dev)
+{
+ struct device_node *np;
+ struct platform_device *pdev;
+ struct device *pruss_dev = pru_dev->parent;
+ struct pruss_intc *intc = ERR_PTR(-ENODEV);
+
+ np = of_get_child_by_name(pruss_dev->of_node, "interrupt-controller");
+ if (!np) {
+ dev_err(pruss_dev, "pruss does not have an interrupt-controller node\n");
+ return intc;
+ }
+
+ pdev = of_find_device_by_node(np);
+ if (!pdev) {
+ dev_err(pruss_dev, "no associated platform device\n");
+ goto out;
+ }
+
+ intc = platform_get_drvdata(pdev);
+ if (!intc) {
+ dev_err(pruss_dev, "pruss intc device probe failed?\n");
+ intc = ERR_PTR(-EINVAL);
+ }
+
+out:
+ of_node_put(np);
+ return intc;
+}
+
+/**
+ * pruss_intc_configure() - configure the PRUSS INTC
+ * @dev: pru device pointer
+ * @intc_config: PRU core-specific INTC configuration
+ *
+ * Configures the PRUSS INTC with the provided configuration from
+ * a PRU core. Any existing event to channel mappings or channel to
+ * host interrupt mappings are checked to make sure there are no
+ * conflicting configuration between both the PRU cores. The function
+ * is intended to be used only by the PRU remoteproc driver.
+ *
+ * Returns 0 on success, or a suitable error code otherwise
+ */
+int pruss_intc_configure(struct device *dev,
+ struct pruss_intc_config *intc_config)
+{
+ struct pruss_intc *intc;
+ int i, idx, ret;
+ s8 ch, host;
+ u64 sysevt_mask = 0;
+ u32 ch_mask = 0;
+ u32 host_mask = 0;
+
+ intc = to_pruss_intc(dev);
+ if (IS_ERR(intc))
+ return PTR_ERR(intc);
+
+ mutex_lock(&intc->lock);
+
+ /*
+ * configure channel map registers - each register holds map info
+ * for 4 events, with each event occupying the lower nibble in
+ * a register byte address in little-endian fashion
+ */
+ for (i = 0; i < ARRAY_SIZE(intc_config->sysev_to_ch); i++) {
+ ch = intc_config->sysev_to_ch[i];
+ if (ch < 0)
+ continue;
+
+ /* check if sysevent already assigned */
+ if (intc->config_map.sysev_to_ch[i] != PRU_INTC_FREE) {
+ dev_err(dev, "event %d (req. channel %d) already assigned to channel %d\n",
+ i, ch, intc->config_map.sysev_to_ch[i]);
+ ret = -EEXIST;
+ goto fail_evt;
+ }
+
+ intc->config_map.sysev_to_ch[i] = ch;
+ pruss_intc_update_cmr(intc, i, ch);
+ sysevt_mask |= BIT_ULL(i);
+ ch_mask |= BIT(ch);
+ idx = i / CMR_EVT_PER_REG;
+
+ dev_dbg(dev, "SYSEVT%d -> CH%d (CMR%d 0x%08x)\n", i, ch, idx,
+ pruss_intc_read_reg(intc, PRU_INTC_CMR(idx)));
+ }
+
+ /*
+ * set host map registers - each register holds map info for
+ * 4 channels, with each channel occupying the lower nibble in
+ * a register byte address in little-endian fashion
+ */
+ for (i = 0; i < ARRAY_SIZE(intc_config->ch_to_host); i++) {
+ host = intc_config->ch_to_host[i];
+ if (host < 0)
+ continue;
+
+ /* check if channel already assigned */
+ if (intc->config_map.ch_to_host[i] != PRU_INTC_FREE) {
+ dev_err(dev, "channel %d (req. intr_no %d) already assigned to intr_no %d\n",
+ i, host, intc->config_map.ch_to_host[i]);
+ ret = -EEXIST;
+ goto fail_ch;
+ }
+
+ /* check if host intr is already in use by other PRU */
+ if (intc->host_mask & (1U << host)) {
+ dev_err(dev, "%s: host intr %d already in use\n",
+ __func__, host);
+ ret = -EEXIST;
+ goto fail_ch;
+ }
+
+ intc->config_map.ch_to_host[i] = host;
+ pruss_intc_update_hmr(intc, i, host);
+ ch_mask |= BIT(i);
+ host_mask |= BIT(host);
+ idx = i / HMR_CH_PER_REG;
+
+ dev_dbg(dev, "CH%d -> HOST%d (HMR%d 0x%08x)\n", i, host, idx,
+ pruss_intc_read_reg(intc, PRU_INTC_HMR(idx)));
+ }
+
+ dev_info(dev, "configured system_events = 0x%016llx intr_channels = 0x%08x host_intr = 0x%08x\n",
+ sysevt_mask, ch_mask, host_mask);
+
+ /* enable system events, writing 0 has no-effect */
+ pruss_intc_write_reg(intc, PRU_INTC_ESR0, lower_32_bits(sysevt_mask));
+ pruss_intc_write_reg(intc, PRU_INTC_SECR0, lower_32_bits(sysevt_mask));
+ pruss_intc_write_reg(intc, PRU_INTC_ESR1, upper_32_bits(sysevt_mask));
+ pruss_intc_write_reg(intc, PRU_INTC_SECR1, upper_32_bits(sysevt_mask));
+
+ /* enable host interrupts */
+ for (i = 0; i < MAX_PRU_HOST_INT; i++) {
+ if (host_mask & BIT(i))
+ pruss_intc_write_reg(intc, PRU_INTC_HIEISR, i);
+ }
+
+ /* global interrupt enable */
+ pruss_intc_write_reg(intc, PRU_INTC_GER, 1);
+
+ intc->host_mask |= host_mask;
+
+ mutex_unlock(&intc->lock);
+ return 0;
+
+fail_ch:
+ while (--i >= 0) {
+ if (intc_config->ch_to_host[i] >= 0) {
+ intc->config_map.ch_to_host[i] = PRU_INTC_FREE;
+ pruss_intc_update_hmr(intc, i, 0);
+ }
+ }
+ i = ARRAY_SIZE(intc_config->sysev_to_ch);
+fail_evt:
+ while (--i >= 0) {
+ if (intc_config->sysev_to_ch[i] >= 0) {
+ intc->config_map.sysev_to_ch[i] = PRU_INTC_FREE;
+ pruss_intc_update_cmr(intc, i, 0);
+ }
+ }
+ mutex_unlock(&intc->lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pruss_intc_configure);
+
+/**
+ * pruss_intc_unconfigure() - unconfigure the PRUSS INTC
+ * @dev: pru device pointer
+ * @intc_config: PRU core specific INTC configuration
+ *
+ * Undo whatever was done in pruss_intc_configure() for a PRU core.
+ * It should be sufficient to just mark the resources free in the
+ * global map and disable the host interrupts and sysevents.
+ */
+int pruss_intc_unconfigure(struct device *dev,
+ struct pruss_intc_config *intc_config)
+{
+ struct pruss_intc *intc;
+ int i;
+ s8 ch, host;
+ u64 sysevt_mask = 0;
+ u32 host_mask = 0;
+
+ intc = to_pruss_intc(dev);
+ if (IS_ERR(intc))
+ return PTR_ERR(intc);
+
+ mutex_lock(&intc->lock);
+
+ for (i = 0; i < ARRAY_SIZE(intc_config->sysev_to_ch); i++) {
+ ch = intc_config->sysev_to_ch[i];
+ if (ch < 0)
+ continue;
+
+ /* mark sysevent free in global map */
+ intc->config_map.sysev_to_ch[i] = PRU_INTC_FREE;
+ sysevt_mask |= BIT_ULL(i);
+ /* clear the map using reset value 0 */
+ pruss_intc_update_cmr(intc, i, 0);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(intc_config->ch_to_host); i++) {
+ host = intc_config->ch_to_host[i];
+ if (host < 0)
+ continue;
+
+ /* mark channel free in global map */
+ intc->config_map.ch_to_host[i] = PRU_INTC_FREE;
+ host_mask |= BIT(host);
+ /* clear the map using reset value 0 */
+ pruss_intc_update_hmr(intc, i, 0);
+ }
+
+ dev_info(dev, "unconfigured system_events = 0x%016llx host_intr = 0x%08x\n",
+ sysevt_mask, host_mask);
+
+ /* disable system events, writing 0 has no-effect */
+ pruss_intc_write_reg(intc, PRU_INTC_ECR0, lower_32_bits(sysevt_mask));
+ pruss_intc_write_reg(intc, PRU_INTC_ECR1, upper_32_bits(sysevt_mask));
+ /* clear any pending status */
+ pruss_intc_write_reg(intc, PRU_INTC_SECR0, lower_32_bits(sysevt_mask));
+ pruss_intc_write_reg(intc, PRU_INTC_SECR1, upper_32_bits(sysevt_mask));
+
+ /* disable host interrupts */
+ for (i = 0; i < MAX_PRU_HOST_INT; i++) {
+ if (host_mask & BIT(i))
+ pruss_intc_write_reg(intc, PRU_INTC_HIDISR, i);
+ }
+
+ intc->host_mask &= ~host_mask;
+ mutex_unlock(&intc->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_intc_unconfigure);
+
static void pruss_intc_init(struct pruss_intc *intc)
{
int i;
@@ -290,6 +566,12 @@ static int pruss_intc_probe(struct platform_device *pdev)
mutex_init(&intc->lock);
+ for (i = 0; i < ARRAY_SIZE(intc->config_map.sysev_to_ch); i++)
+ intc->config_map.sysev_to_ch[i] = PRU_INTC_FREE;
+
+ for (i = 0; i < ARRAY_SIZE(intc->config_map.ch_to_host); i++)
+ intc->config_map.ch_to_host[i] = PRU_INTC_FREE;
+
pruss_intc_init(intc);
irqchip = devm_kzalloc(dev, sizeof(*irqchip), GFP_KERNEL);
diff --git a/include/linux/irqchip/irq-pruss-intc.h b/include/linux/irqchip/irq-pruss-intc.h
new file mode 100644
index 000000000000..daffc048b303
--- /dev/null
+++ b/include/linux/irqchip/irq-pruss-intc.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * PRU-ICSS sub-system private interfaces
+ *
+ * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+ * Suman Anna <s-anna@ti.com>
+ */
+
+#ifndef __LINUX_IRQ_PRUSS_INTC_H
+#define __LINUX_IRQ_PRUSS_INTC_H
+
+/* maximum number of system events */
+#define MAX_PRU_SYS_EVENTS 64
+
+/* maximum number of interrupt channels */
+#define MAX_PRU_CHANNELS 10
+
+/* use -1 to mark unassigned events and channels */
+#define PRU_INTC_FREE -1
+
+/**
+ * struct pruss_intc_config - INTC configuration info
+ * @sysev_to_ch: system events to channel mapping information
+ * @ch_to_host: interrupt channel to host interrupt information
+ */
+struct pruss_intc_config {
+ s8 sysev_to_ch[MAX_PRU_SYS_EVENTS];
+ s8 ch_to_host[MAX_PRU_CHANNELS];
+};
+
+int pruss_intc_configure(struct device *dev,
+ struct pruss_intc_config *intc_config);
+int pruss_intc_unconfigure(struct device *dev,
+ struct pruss_intc_config *intc_config);
+
+#endif /* __LINUX_IRQ_PRUSS_INTC_H */
--
2.22.0
^ permalink raw reply related
* [PATCH v2 3/6] irqchip/irq-pruss-intc: Add support for shared and invalid interrupts
From: Suman Anna @ 2019-07-31 22:41 UTC (permalink / raw)
To: Marc Zyngier, Thomas Gleixner, Jason Cooper
Cc: Rob Herring, David Lechner, Tony Lindgren, Andrew F. Davis,
Roger Quadros, Lokesh Vutla, Grygorii Strashko, Sekhar Nori,
Murali Karicheri, devicetree, linux-omap, linux-arm-kernel,
linux-kernel, Suman Anna
In-Reply-To: <20190731224149.11153-1-s-anna@ti.com>
The PRUSS INTC has a fixed number of output interrupt lines that are
connected to a number of processors or other PRUSS instances or other
devices (like DMA) on the SoC. The output interrupt lines 2 through 9
are usually connected to the main Arm host processor and are referred
to as host interrupts 0 through 7 from ARM/MPU perspective.
All of these 8 host interrupts are not always exclusively connected
to the Arm interrupt controller. Some SoCs have some interrupt lines
not connected to the Arm interrupt controller at all, while a few others
have the interrupt lines connected to multiple processors in which they
need to be partitioned as per SoC integration needs. For example, AM437x
and 66AK2G SoCs have 2 PRUSS instances each and have the host interrupt 5
connected to the other PRUSS, while AM335x has host interrupt 0 shared
between MPU and TSC_ADC and host interrupts 6 & 7 shared between MPU and
a DMA controller.
Add support to the PRUSS INTC driver to allow both these shared and
invalid interrupts by not returning a failure if any of these interrupts
are skipped from the corresponding INTC DT node.
Signed-off-by: Suman Anna <s-anna@ti.com>
---
v2:
- Fixed a typo in error message trace for ti,irqs-shared
- Updated patch description to use generic "interrupt controller" instead
of GIC
- Revised the kerneldoc comment for invalid_intr
v1: https://patchwork.kernel.org/patch/11034559/
drivers/irqchip/irq-pruss-intc.c | 44 +++++++++++++++++++++++++++++++-
1 file changed, 43 insertions(+), 1 deletion(-)
diff --git a/drivers/irqchip/irq-pruss-intc.c b/drivers/irqchip/irq-pruss-intc.c
index 4a9456544fd0..3a1b8a93cfad 100644
--- a/drivers/irqchip/irq-pruss-intc.c
+++ b/drivers/irqchip/irq-pruss-intc.c
@@ -67,6 +67,8 @@
* @irqchip: irq chip for this interrupt controller
* @domain: irq domain for this interrupt controller
* @lock: mutex to serialize access to INTC
+ * @shared_intr: bit-map denoting if the MPU host interrupt is shared
+ * @invalid_intr: bit-map denoting if host interrupt is not connected to MPU
*/
struct pruss_intc {
unsigned int irqs[MAX_NUM_HOST_IRQS];
@@ -74,6 +76,8 @@ struct pruss_intc {
struct irq_chip *irqchip;
struct irq_domain *domain;
struct mutex lock; /* PRUSS INTC lock */
+ u16 shared_intr;
+ u16 invalid_intr;
};
static inline u32 pruss_intc_read_reg(struct pruss_intc *intc, unsigned int reg)
@@ -233,7 +237,8 @@ static int pruss_intc_probe(struct platform_device *pdev)
struct pruss_intc *intc;
struct resource *res;
struct irq_chip *irqchip;
- int i, irq;
+ int i, irq, count;
+ u8 temp_intr[MAX_NUM_HOST_IRQS] = { 0 };
intc = devm_kzalloc(dev, sizeof(*intc), GFP_KERNEL);
if (!intc)
@@ -250,6 +255,39 @@ static int pruss_intc_probe(struct platform_device *pdev)
dev_dbg(dev, "intc memory: pa %pa size 0x%zx va %pK\n", &res->start,
(size_t)resource_size(res), intc->base);
+ count = of_property_read_variable_u8_array(dev->of_node,
+ "ti,irqs-reserved",
+ temp_intr, 0,
+ MAX_NUM_HOST_IRQS);
+ if (count < 0 && count != -EINVAL)
+ return count;
+ count = (count == -EINVAL ? 0 : count);
+ for (i = 0; i < count; i++) {
+ if (temp_intr[i] < MAX_NUM_HOST_IRQS) {
+ intc->invalid_intr |= BIT(temp_intr[i]);
+ } else {
+ dev_warn(dev, "ignoring invalid reserved irq %d\n",
+ temp_intr[i]);
+ }
+ temp_intr[i] = 0;
+ }
+
+ count = of_property_read_variable_u8_array(dev->of_node,
+ "ti,irqs-shared",
+ temp_intr, 0,
+ MAX_NUM_HOST_IRQS);
+ if (count < 0 && count != -EINVAL)
+ return count;
+ count = (count == -EINVAL ? 0 : count);
+ for (i = 0; i < count; i++) {
+ if (temp_intr[i] < MAX_NUM_HOST_IRQS) {
+ intc->shared_intr |= BIT(temp_intr[i]);
+ } else {
+ dev_warn(dev, "ignoring invalid shared irq %d\n",
+ temp_intr[i]);
+ }
+ }
+
mutex_init(&intc->lock);
pruss_intc_init(intc);
@@ -275,6 +313,10 @@ static int pruss_intc_probe(struct platform_device *pdev)
for (i = 0; i < MAX_NUM_HOST_IRQS; i++) {
irq = platform_get_irq_byname(pdev, irq_names[i]);
if (irq < 0) {
+ if (intc->shared_intr & BIT(i) ||
+ intc->invalid_intr & BIT(i))
+ continue;
+
dev_err(dev, "platform_get_irq_byname failed for %s : %d\n",
irq_names[i], irq);
goto fail_irq;
--
2.22.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox