linux-sh.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [DO NOT MERGE v7 09/36] sh: Common PCI Framework driver support.
       [not found] <cover.1712041249.git.ysato@users.sourceforge.jp>
@ 2024-04-04  4:59 ` Yoshinori Sato
  2024-04-04  4:59 ` [DO NOT MERGE v7 10/36] pci: pci-sh7751: Add SH7751 PCI driver Yoshinori Sato
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Yoshinori Sato @ 2024-04-04  4:59 UTC (permalink / raw)
  To: linux-sh; +Cc: Yoshinori Sato

Add New OF based PCI Host driver.
This driver conflicts some point in legacy PCI driver.
To resolve the conflict, I made some changes to the legacy driver.

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 arch/sh/include/asm/io.h  |  6 ++++++
 arch/sh/include/asm/pci.h |  4 ++++
 arch/sh/kernel/iomap.c    | 18 ++++++++++++++++++
 3 files changed, 28 insertions(+)

diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h
index 5c544cf5201b..29b5f996cde3 100644
--- a/arch/sh/include/asm/io.h
+++ b/arch/sh/include/asm/io.h
@@ -20,6 +20,7 @@
 #include <asm/page.h>
 #include <linux/pgtable.h>
 #include <asm-generic/iomap.h>
+#include <linux/ioport.h>
 
 #define __IO_PREFIX     generic
 #include <asm/io_generic.h>
@@ -310,4 +311,9 @@ unsigned long long poke_real_address_q(unsigned long long addr,
 int valid_phys_addr_range(phys_addr_t addr, size_t size);
 int valid_mmap_phys_addr_range(unsigned long pfn, size_t size);
 
+#if defined(CONFIG_PCI) && !defined(CONFIG_GENERIC_IOMAP)
+#define pci_remap_iospace pci_remap_iospace
+int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr);
+#endif
+
 #endif /* __ASM_SH_IO_H */
diff --git a/arch/sh/include/asm/pci.h b/arch/sh/include/asm/pci.h
index 54c30126ea17..92b3bd604319 100644
--- a/arch/sh/include/asm/pci.h
+++ b/arch/sh/include/asm/pci.h
@@ -2,6 +2,7 @@
 #ifndef __ASM_SH_PCI_H
 #define __ASM_SH_PCI_H
 
+#ifndef CONFIG_SH_DEVICE_TREE
 /* Can be used to override the logic in pci_scan_bus for skipping
    already-configured bus numbers - to be used for buggy BIOSes
    or architectures with incomplete PCI setup by the loader */
@@ -88,4 +89,7 @@ static inline int pci_proc_domain(struct pci_bus *bus)
 	return hose->need_domain_info;
 }
 
+#else /* CONFIG_SH_DEVICE_TREE */
+#include <asm-generic/pci.h>
+#endif
 #endif /* __ASM_SH_PCI_H */
diff --git a/arch/sh/kernel/iomap.c b/arch/sh/kernel/iomap.c
index 0a0dff4e66de..d1b8e496ca23 100644
--- a/arch/sh/kernel/iomap.c
+++ b/arch/sh/kernel/iomap.c
@@ -160,3 +160,21 @@ void iowrite32_rep(void __iomem *addr, const void *src, unsigned long count)
 	mmio_outsl(addr, src, count);
 }
 EXPORT_SYMBOL(iowrite32_rep);
+
+#if defined(pci_remap_iospace)
+int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr)
+{
+	unsigned long vaddr = res->start;
+
+	if (!(res->flags & IORESOURCE_IO))
+		return -EINVAL;
+
+	if (res->end > IO_SPACE_LIMIT)
+		return -EINVAL;
+
+	__set_io_port_base(phys_addr);
+	return vmap_page_range(vaddr, vaddr + resource_size(res), phys_addr,
+			       pgprot_device(PAGE_KERNEL));
+}
+EXPORT_SYMBOL(pci_remap_iospace);
+#endif
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [DO NOT MERGE v7 10/36] pci: pci-sh7751: Add SH7751 PCI driver
       [not found] <cover.1712041249.git.ysato@users.sourceforge.jp>
  2024-04-04  4:59 ` [DO NOT MERGE v7 09/36] sh: Common PCI Framework driver support Yoshinori Sato
@ 2024-04-04  4:59 ` Yoshinori Sato
  2024-04-04  4:59 ` [DO NOT MERGE v7 11/36] dt-bindings: pci: pci-sh7751: Add SH7751 PCI Yoshinori Sato
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Yoshinori Sato @ 2024-04-04  4:59 UTC (permalink / raw)
  To: linux-sh; +Cc: Yoshinori Sato

Renesas SH7751 CPU Internal PCI Controller driver.

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 drivers/pci/controller/Kconfig      |   9 +
 drivers/pci/controller/Makefile     |   1 +
 drivers/pci/controller/pci-sh7751.c | 342 ++++++++++++++++++++++++++++
 3 files changed, 352 insertions(+)
 create mode 100644 drivers/pci/controller/pci-sh7751.c

diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index e534c02ee34f..a2fd917a2e03 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -353,6 +353,15 @@ config PCIE_XILINX_CPM
 	  Say 'Y' here if you want kernel support for the
 	  Xilinx Versal CPM host bridge.
 
+config PCI_SH7751
+	bool "Renesas SH7751 PCI controller"
+	depends on OF
+	depends on CPU_SUBTYPE_SH7751 || CPU_SUBTYPE_SH7751R || COMPILE_TEST
+	select PCI_HOST_COMMON
+	help
+	  Say 'Y' here if you want kernel to support the Renesas SH7751 PCI
+	  Host Bridge driver.
+
 source "drivers/pci/controller/cadence/Kconfig"
 source "drivers/pci/controller/dwc/Kconfig"
 source "drivers/pci/controller/mobiveil/Kconfig"
diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile
index f2b19e6174af..aa97e5d74e58 100644
--- a/drivers/pci/controller/Makefile
+++ b/drivers/pci/controller/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_PCI_LOONGSON) += pci-loongson.o
 obj-$(CONFIG_PCIE_HISI_ERR) += pcie-hisi-error.o
 obj-$(CONFIG_PCIE_APPLE) += pcie-apple.o
 obj-$(CONFIG_PCIE_MT7621) += pcie-mt7621.o
+obj-$(CONFIG_PCI_SH7751) += pci-sh7751.o
 
 # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
 obj-y				+= dwc/
diff --git a/drivers/pci/controller/pci-sh7751.c b/drivers/pci/controller/pci-sh7751.c
new file mode 100644
index 000000000000..a5340689f737
--- /dev/null
+++ b/drivers/pci/controller/pci-sh7751.c
@@ -0,0 +1,342 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SH7751 PCI driver
+ * Copyright (C) 2023 Yoshinori Sato
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_pci.h>
+#include <linux/of_platform.h>
+#include <linux/pci-ecam.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/pci.h>
+#include <linux/dma-direct.h>
+#include <asm/addrspace.h>
+
+/* PCICR and PCICLKCR write enable magic key */
+#define PCIC_WE_KEY		(0xa5 << 24)
+
+/* PCIC registers */
+/* 0x0000 - 0x00ff mapped to PCI device configuration space */
+#define PCIC_PCICR		0x100	/* PCI Control Register */
+#define PCIC_PCICR_TRSB		BIT(9)	/* Target Read Single */
+#define PCIC_PCICR_BSWP		BIT(8)	/* Target Byte Swap */
+#define PCIC_PCICR_PLUP		BIT(7)	/* Enable PCI Pullup */
+#define PCIC_PCICR_ARBM		BIT(6)	/* PCI Arbitration Mode */
+#define PCIC_PCICR_MD10		BIT(5)	/* MD10 status */
+#define PCIC_PCICR_MD9		BIT(4)	/* MD9 status */
+#define PCIC_PCICR_SERR		BIT(3)	/* SERR output assert */
+#define PCIC_PCICR_INTA		BIT(2)	/* INTA output assert */
+#define PCIC_PCICR_PRST		BIT(1)	/* PCI Reset Assert */
+#define PCIC_PCICR_CFIN		BIT(0)	/* Central Fun. Init Done */
+
+#define PCIC_PCILSR0		0x104	/* PCI Local Space Register0 */
+#define PCIC_PCILSR1		0x108	/* PCI Local Space Register1 */
+#define PCIC_PCILAR0		0x10c	/* PCI Local Addr Register1 */
+#define PCIC_PCILAR1		0x110	/* PCI Local Addr Register1 */
+#define PCIC_PCIINT		0x114	/* PCI Interrupt Register */
+#define PCIC_PCIINTM		0x118	/* PCI Interrupt Mask */
+#define PCIC_PCIALR		0x11c	/* Error Address Register */
+#define PCIC_PCICLR		0x120	/* Error Command/Data */
+#define PCIC_PCIAINT		0x130	/* Arbiter Interrupt Register */
+#define PCIC_PCIAINTM		0x134	/* Arbiter Int. Mask Register */
+#define PCIC_PCIBMLR		0x138	/* Error Bus Master Register */
+#define PCIC_PCIDMABT		0x140	/* DMA Transfer Arb. Register */
+#define PCIC_PCIPAR		0x1c0	/* PIO Address Register */
+#define PCIC_PCIMBR		0x1c4	/* Memory Base Address */
+#define PCIC_PCIIOBR		0x1c8	/* I/O Base Address Register */
+
+#define PCIC_PCIPINT		0x1cc	/* Power Mgmnt Int. Register */
+#define PCIC_PCIPINT_D3		BIT(1)	/* D3 Pwr Mgmt. Interrupt */
+#define PCIC_PCIPINT_D0		BIT(0)	/* D0 Pwr Mgmt. Interrupt */
+
+#define PCIC_PCIPINTM		0x1d0	/* Power Mgmnt Mask Register */
+#define PCIC_PCICLKR		0x1d4	/* Clock Ctrl. Register */
+#define PCIC_PCIBCR1		0x1e0	/* Memory BCR1 Register */
+#define PCIC_PCIBCR2		0x1e4	/* Memory BCR2 Register */
+#define PCIC_PCIWCR1		0x1e8	/* Wait Control 1 Register */
+#define PCIC_PCIWCR2		0x1ec	/* Wait Control 2 Register */
+#define PCIC_PCIWCR3		0x1f0	/* Wait Control 3 Register */
+#define PCIC_PCIMCR		0x1f4	/* Memory Control Register */
+#define PCIC_PCIBCR3		0x1f8	/* Memory BCR3 Register */
+#define PCIC_PCIPDR		0x220	/* Port IO Data Register */
+
+/* PCI IDs */
+/* Hitachi is the company that led to Renesas. */
+/* The SH7751 was designed by Hitachi, so it has a Hitachi ID. */
+#define PCI_VENDOR_ID_HITACHI	0x1054
+#define PCI_DEVICE_ID_SH7751	0x3505
+#define PCI_DEVICE_ID_SH7751R	0x350e
+
+/* BSC registers */
+/* Copy BSC setting to PCI BSC */
+#define BSC_BCR1		0x0000
+#define BSC_BCR1_SLAVE		BIT(30)
+#define BSC_BCR1_BRQEN		BIT(19)
+#define BSC_BCR2		0x0004
+#define BSC_BCR3		0x0050
+#define BSC_WCR1		0x0008
+#define BSC_WCR2		0x000c
+#define BSC_WCR3		0x0010
+#define BSC_MCR			0x0014
+#define BSC_MCR_MRSET		BIT(30)
+#define BSC_MCR_RFSH		BIT(2)
+
+/* PCIC access wrapper */
+#define pcic_writel(val, base, reg)	writel(val, base + (reg))
+#define pcic_readl(base, reg)		readl(base + (reg))
+
+/*
+ * We need to avoid collisions with `mirrored' VGA ports
+ * and other strange ISA hardware, so we always want the
+ * addresses to be allocated in the 0x000-0x0ff region
+ * modulo 0x400.
+ */
+#define IO_REGION_BASE 0x1000
+resource_size_t pcibios_align_resource(void *data, const struct resource *res,
+				resource_size_t size, resource_size_t align)
+{
+	resource_size_t start = res->start;
+
+	if (res->flags & IORESOURCE_IO) {
+		if (start < PCIBIOS_MIN_IO + IO_REGION_BASE)
+			start = PCIBIOS_MIN_IO + IO_REGION_BASE;
+
+		/*
+		 * Put everything into 0x00-0xff region modulo 0x400.
+		 */
+		if (start & 0x300)
+			start = (start + 0x3ff) & ~0x3ff;
+	}
+
+	return start;
+}
+
+static int setup_pci_bsc(struct device *dev, void __iomem *pcic,
+			 void __iomem *bsc, unsigned int area, bool bcr3)
+{
+	u32 word;
+
+	word = __raw_readl(bsc + BSC_BCR1);
+	/* check BCR for SDRAM in area */
+	if (((word >> area) & 1) == 0) {
+		dev_err(dev, "Area %u is not configured for SDRAM. BCR1=0x%x\n",
+			area, word);
+		return -EINVAL;
+	}
+	word |= BSC_BCR1_SLAVE;		/* PCIC BSC is slave only */
+	pcic_writel(word, pcic, PCIC_PCIBCR1);
+
+	word = __raw_readw(bsc + BSC_BCR2);
+	/* check BCR2 for 32bit SDRAM interface*/
+	if (((word >> (area << 1)) & 0x3) != 0x3) {
+		dev_err(dev, "Area %u is not 32 bit SDRAM. BCR2=0x%x\n",
+			area, word);
+		return -EINVAL;
+	}
+	pcic_writel(word, pcic, PCIC_PCIBCR2);
+
+	if (bcr3) {
+		/* BCR3 have only SH7751R */
+		word = __raw_readw(bsc + BSC_BCR3);
+		pcic_writel(word, pcic, PCIC_PCIBCR3);
+	}
+
+	/* configure the wait control registers */
+	word = __raw_readl(bsc + BSC_WCR1);
+	pcic_writel(word, pcic, PCIC_PCIWCR1);
+	word = __raw_readl(bsc + BSC_WCR2);
+	pcic_writel(word, pcic, PCIC_PCIWCR2);
+	word = __raw_readl(bsc + BSC_WCR3);
+	pcic_writel(word, pcic, PCIC_PCIWCR3);
+	word = __raw_readl(bsc + BSC_MCR);
+	/* Clear MRSET and RFSH bit */
+	word &= ~(BSC_MCR_MRSET | BSC_MCR_RFSH);
+	pcic_writel(word, pcic, PCIC_PCIMCR);
+
+	return 0;
+}
+
+#define NUM_AREA 7
+static int set_pci_ranges(struct device *dev,
+			  void __iomem *pcic, void __iomem *bsc, bool bcr3)
+{
+	struct resource_entry *dma, *tmp;
+	struct pci_host_bridge *bridge;
+	u32 bsc_done[NUM_AREA];
+	unsigned int la;
+
+	bridge = dev_get_drvdata(dev);
+	pcic_writel(0, pcic, PCIC_PCILAR0);
+	pcic_writel(0, pcic, PCIC_PCILAR1);
+	la = 0;
+	memset(&bsc_done, 0, sizeof(bsc_done));
+	resource_list_for_each_entry_safe(dma, tmp, &bridge->dma_ranges) {
+		struct resource *res = dma->res;
+		unsigned int area;
+		u32 word;
+
+		switch (resource_type(res)) {
+		case IORESOURCE_IO:
+			/* BAR0 is I/O space */
+			word = res->start | 1;
+			pcic_writel(word, pcic, PCI_BASE_ADDRESS_0);
+			word = pcic_readl(pcic, PCI_COMMAND);
+			word |= PCI_COMMAND_IO;
+			pcic_writel(word, pcic, PCI_COMMAND);
+			break;
+		case IORESOURCE_MEM:
+			if (la > 4) {
+				dev_err(dev, "Invalid range definition.\n");
+				return -EINVAL;
+			}
+			area = (res->start >> 26) & 0x07;
+			word = res->end - res->start;
+			if (area >= NUM_AREA) {
+				/* Area 7 is reserved. */
+				dev_info(dev, "Invalid local address 0x%08x. Ignore it.\n",
+					 res->start);
+				break;
+			}
+			pcic_writel(res->start, pcic, PCI_BASE_ADDRESS_1 + la);
+			/* if dummy entry, skip BSC setup */
+			if (word < 4)
+				break;
+			/* BAR1 is local area 0, BAR2 is local area 1 */
+			pcic_writel(word, pcic, PCIC_PCILSR0 + la);
+			word = P2SEGADDR(res->start);
+			pcic_writel(word, pcic, PCIC_PCILAR0 + la);
+			la += 4;
+			if (!bsc_done[area]) {
+				/* check BCR for SDRAM in specified area. And setup PCI BSC. */
+				if (setup_pci_bsc(dev, pcic, bsc, area, bcr3))
+					return -EINVAL;
+				bsc_done[area] = 1;
+			}
+			break;
+		}
+	}
+	return 0;
+}
+
+static int sh7751_pci_probe(struct platform_device *pdev)
+{
+	struct resource *res, *bscres;
+	void __iomem *pcic;
+	void __iomem *bsc;
+	u16 vid, did;
+	u32 word;
+	int ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (IS_ERR(res))
+		return PTR_ERR(res);
+	pcic = ioremap(res->start, res->end - res->start + 1);
+
+	bscres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	bsc = devm_ioremap_resource(&pdev->dev, bscres);
+	if (IS_ERR(bsc))
+		return PTR_ERR(bsc);
+
+	/* check for SH7751/SH7751R hardware */
+	word = pcic_readl(pcic, PCI_VENDOR_ID);
+	vid = word & 0xffff;
+	did = word >> 16;
+	if ((vid != PCI_VENDOR_ID_HITACHI) ||
+	    ((did != PCI_DEVICE_ID_SH7751) &&
+	     (did != PCI_DEVICE_ID_SH7751R))) {
+		dev_err(&pdev->dev, "This is not an SH7751(R)\n");
+		return -ENODEV;
+	}
+	dev_info(&pdev->dev, "PCI core found at %pR\n", res);
+
+	/* Set the BCR's to enable PCI access */
+	word = __raw_readl(bsc + BSC_BCR1);
+	word |= BSC_BCR1_BRQEN;
+	__raw_writel(word, bsc + BSC_BCR1);
+
+	/* Turn the clocks back on (not done in reset)*/
+	pcic_writel(PCIC_WE_KEY | 0, pcic, PCIC_PCICLKR);
+	/* Clear Powerdown IRQ's (not done in reset) */
+	word = PCIC_PCIPINT_D3 | PCIC_PCIPINT_D0;
+	pcic_writel(word, pcic, PCIC_PCIPINT);
+
+	/* set the command/status */
+	word = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+		PCI_COMMAND_PARITY | PCI_COMMAND_WAIT;
+	pcic_writel(word, pcic, PCI_COMMAND);
+
+	/* define this host as the host bridge */
+	word = PCI_BASE_CLASS_BRIDGE << 24;
+	pcic_writel(word, pcic, PCI_CLASS_REVISION);
+
+	ret = pci_host_common_probe(pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "Initialize failed (%d)\n", ret);
+		return ret;
+	}
+
+	/* Set IO and Mem windows to local address */
+	if (set_pci_ranges(&pdev->dev, pcic, bsc,
+			   did == PCI_DEVICE_ID_SH7751R))
+		return -EINVAL;
+	pcic_writel(0, pcic, PCIC_PCIIOBR);
+
+	if (of_property_read_bool(pdev->dev.of_node, "renesas,bus-arbit-round-robin"))
+		word |= BIT(0);
+	else
+		word = 0;
+	pcic_writel(word, pcic, PCIC_PCIDMABT);
+
+	/* SH7751 init done, set central function init complete */
+	/* use round robin mode to stop a device starving/overrunning */
+	word = PCIC_PCICR_CFIN | PCIC_PCICR_ARBM;
+	pcic_writel(PCIC_WE_KEY | word, pcic, PCIC_PCICR);
+
+	return 0;
+}
+
+/*
+ * Direct access to PCI hardware...
+ */
+#define CONFIG_CMD(bus, devfn, where) \
+	(0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3))
+
+static void __iomem *sh4_pci_map_bus(struct pci_bus *bus,
+				     unsigned int devfn, int where)
+{
+	struct pci_config_window *cfg = bus->sysdata;
+	void __iomem *pcic = (void __iomem *)cfg->res.start;
+
+	pcic_writel(CONFIG_CMD(bus, devfn, where), pcic, PCIC_PCIPAR);
+	return pcic + PCIC_PCIPDR;
+}
+
+static const struct pci_ecam_ops pci_sh7751_bus_ops = {
+	.pci_ops	= {
+		.map_bus = sh4_pci_map_bus,
+		.read    = pci_generic_config_read32,
+		.write   = pci_generic_config_write32,
+	}
+};
+
+static const struct of_device_id sh7751_pci_of_match[] = {
+	{ .compatible = "renesas,sh7751-pci",
+	  .data = &pci_sh7751_bus_ops },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, sh7751_pci_of_match);
+
+static struct platform_driver sh7751_pci_driver = {
+	.driver = {
+		.name = "sh7751-pci",
+		.of_match_table = sh7751_pci_of_match,
+	},
+	.probe = sh7751_pci_probe,
+};
+module_platform_driver(sh7751_pci_driver);
+
+MODULE_DESCRIPTION("SH7751 PCI driver");
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [DO NOT MERGE v7 11/36] dt-bindings: pci: pci-sh7751: Add SH7751 PCI
       [not found] <cover.1712041249.git.ysato@users.sourceforge.jp>
  2024-04-04  4:59 ` [DO NOT MERGE v7 09/36] sh: Common PCI Framework driver support Yoshinori Sato
  2024-04-04  4:59 ` [DO NOT MERGE v7 10/36] pci: pci-sh7751: Add SH7751 PCI driver Yoshinori Sato
@ 2024-04-04  4:59 ` Yoshinori Sato
  2024-04-04  4:59 ` [DO NOT MERGE v7 12/36] dt-bindings: clock: sh7750-cpg: Add renesas,sh7750-cpg header Yoshinori Sato
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Yoshinori Sato @ 2024-04-04  4:59 UTC (permalink / raw)
  To: linux-sh; +Cc: Yoshinori Sato

Renesas SH7751 PCI Controller json-schema.

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 .../bindings/pci/renesas,sh7751-pci.yaml      | 89 +++++++++++++++++++
 1 file changed, 89 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/renesas,sh7751-pci.yaml

diff --git a/Documentation/devicetree/bindings/pci/renesas,sh7751-pci.yaml b/Documentation/devicetree/bindings/pci/renesas,sh7751-pci.yaml
new file mode 100644
index 000000000000..115c2bb67339
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/renesas,sh7751-pci.yaml
@@ -0,0 +1,89 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pci/renesas,sh7751-pci.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas SH7751 PCI Host controller
+
+maintainers:
+  - Yoshinori Sato <ysato@users.sourceforge.jp>
+
+allOf:
+  - $ref: /schemas/pci/pci-bus.yaml#
+
+properties:
+  compatible:
+    const: renesas,sh7751-pci
+
+  reg:
+    minItems: 2
+    maxItems: 2
+
+  reg-names:
+    items:
+      - const: PCI Controller
+      - const: Bus State Controller
+
+  "#interrupt-cells":
+    const: 1
+
+  "#address-cells":
+    const: 3
+
+  "#size-cells":
+    const: 2
+
+  ranges: true
+
+  dma-ranges: true
+
+  interrupt-controller: true
+
+  renesas,bus-arbit-round-robin:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description: |
+      Set DMA bus arbitration to round robin.
+
+required:
+  - compatible
+  - reg
+  - "#interrupt-cells"
+  - "#address-cells"
+  - "#size-cells"
+  - ranges
+  - interrupt-map
+  - interrupt-map-mask
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    pci@fe200000 {
+            compatible = "renesas,sh7751-pci";
+            #address-cells = <3>;
+            #size-cells = <2>;
+            #interrupt-cells = <1>;
+            interrupt-controller;
+            device_type = "pci";
+            bus-range = <0 0>;
+            ranges = <0x02000000 0 0xfd000000 0xfd000000 0 0x01000000>,
+                     <0x01000000 0 0x00000000 0xfe240000 0 0x00040000>;
+            dma-ranges = <0x02000000 0 0xc000000 0x0c000000 0 0x04000000>;
+            reg = <0xfe200000 0x0400>,
+                  <0xff800000 0x0100>;
+            interrupt-map = <0x0000 0 0 1 &julianintc 5 IRQ_TYPE_LEVEL_LOW>,
+                            <0x0000 0 0 2 &julianintc 6 IRQ_TYPE_LEVEL_LOW>,
+                            <0x0000 0 0 3 &julianintc 7 IRQ_TYPE_LEVEL_LOW>,
+                            <0x0000 0 0 4 &julianintc 8 IRQ_TYPE_LEVEL_LOW>,
+                            <0x0800 0 0 1 &julianintc 6 IRQ_TYPE_LEVEL_LOW>,
+                            <0x0800 0 0 2 &julianintc 7 IRQ_TYPE_LEVEL_LOW>,
+                            <0x0800 0 0 3 &julianintc 8 IRQ_TYPE_LEVEL_LOW>,
+                            <0x0800 0 0 4 &julianintc 5 IRQ_TYPE_LEVEL_LOW>,
+                            <0x1000 0 0 1 &julianintc 7 IRQ_TYPE_LEVEL_LOW>,
+                            <0x1000 0 0 2 &julianintc 8 IRQ_TYPE_LEVEL_LOW>,
+                            <0x1000 0 0 3 &julianintc 5 IRQ_TYPE_LEVEL_LOW>,
+                            <0x1000 0 0 4 &julianintc 6 IRQ_TYPE_LEVEL_LOW>;
+            interrupt-map-mask = <0x1800 0 0 7>;
+    };
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [DO NOT MERGE v7 12/36] dt-bindings: clock: sh7750-cpg: Add renesas,sh7750-cpg header.
       [not found] <cover.1712041249.git.ysato@users.sourceforge.jp>
                   ` (2 preceding siblings ...)
  2024-04-04  4:59 ` [DO NOT MERGE v7 11/36] dt-bindings: pci: pci-sh7751: Add SH7751 PCI Yoshinori Sato
@ 2024-04-04  4:59 ` Yoshinori Sato
  2024-04-04  4:59 ` [DO NOT MERGE v7 13/36] clk: Compatible with narrow registers Yoshinori Sato
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Yoshinori Sato @ 2024-04-04  4:59 UTC (permalink / raw)
  To: linux-sh; +Cc: Yoshinori Sato

SH7750 CPG Clock output define.

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 .../bindings/clock/renesas,sh7750-cpg.yaml    | 105 ++++++++++++++++++
 include/dt-bindings/clock/sh7750-cpg.h        |  26 +++++
 2 files changed, 131 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/renesas,sh7750-cpg.yaml
 create mode 100644 include/dt-bindings/clock/sh7750-cpg.h

diff --git a/Documentation/devicetree/bindings/clock/renesas,sh7750-cpg.yaml b/Documentation/devicetree/bindings/clock/renesas,sh7750-cpg.yaml
new file mode 100644
index 000000000000..04c10b0834ee
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/renesas,sh7750-cpg.yaml
@@ -0,0 +1,105 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/renesas,sh7750-cpg.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas SH7750/7751 Clock Pulse Generator (CPG)
+
+maintainers:
+  - Yoshinori Sato <ysato@users.sourceforge.jp>
+
+description:
+  The Clock Pulse Generator (CPG) generates core clocks for the SoC.  It
+  includes PLLs, and variable ratio dividers.
+
+  The CPG may also provide a Clock Domain for SoC devices, in combination with
+  the CPG Module Stop (MSTP) Clocks.
+
+properties:
+  compatible:
+    enum:
+      - renesas,sh7750-cpg             # SH7750
+      - renesas,sh7750s-cpg            # SH775S
+      - renesas,sh7750r-cpg            # SH7750R
+      - renesas,sh7751-cpg             # SH7751
+      - renesas,sh7751r-cpg            # SH7751R
+
+  reg: true
+
+  reg-names: true
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    const: extal
+
+  '#clock-cells':
+    const: 1
+
+  renesas,mode:
+    description: Board-specific settings of the MD[0-2] pins on SoC
+    $ref: /schemas/types.yaml#/definitions/uint32
+    minimum: 0
+    maximum: 6
+
+  '#power-domain-cells':
+    const: 0
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - clocks
+  - clock-names
+  - '#clock-cells'
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - renesas,sh7750-cpg
+              - renesas,sh7750s-cpg
+    then:
+      properties:
+        reg:
+          maxItems: 1
+        reg-names:
+          items:
+            - const: FRQCR
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - renesas,sh7750r-cpg
+              - renesas,sh7751-cpg
+              - renesas,sh7751r-cpg
+    then:
+      properties:
+        reg:
+          maxItems: 2
+        reg-names:
+          items:
+            - const: FRQCR
+            - const: CLKSTP00
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/sh7750-cpg.h>
+    cpg: clock-controller@ffc00000 {
+        #clock-cells = <1>;
+        #power-domain-cells = <0>;
+        compatible = "renesas,sh7751r-cpg";
+        clocks = <&extal>;
+        clock-names = "extal";
+        reg = <0xffc00000 20>, <0xfe0a0000 16>;
+        reg-names = "FRQCR", "CLKSTP00";
+        renesas,mode = <0>;
+    };
diff --git a/include/dt-bindings/clock/sh7750-cpg.h b/include/dt-bindings/clock/sh7750-cpg.h
new file mode 100644
index 000000000000..ec267be91adf
--- /dev/null
+++ b/include/dt-bindings/clock/sh7750-cpg.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+ *
+ * Copyright 2023 Yoshinori Sato
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_SH7750_H__
+#define __DT_BINDINGS_CLOCK_SH7750_H__
+
+#define SH7750_CPG_PLLOUT	0
+
+#define SH7750_CPG_PCK		1
+#define SH7750_CPG_BCK		2
+#define SH7750_CPG_ICK		3
+
+#define SH7750_MSTP_SCI		4
+#define SH7750_MSTP_RTC		5
+#define SH7750_MSTP_TMU012	6
+#define SH7750_MSTP_SCIF	7
+#define SH7750_MSTP_DMAC	8
+#define SH7750_MSTP_UBC		9
+#define SH7750_MSTP_SQ		10
+#define SH7750_CSTP_INTC	11
+#define SH7750_CSTP_TMU34	12
+#define SH7750_CSTP_PCIC	13
+
+#endif
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [DO NOT MERGE v7 13/36] clk: Compatible with narrow registers
       [not found] <cover.1712041249.git.ysato@users.sourceforge.jp>
                   ` (3 preceding siblings ...)
  2024-04-04  4:59 ` [DO NOT MERGE v7 12/36] dt-bindings: clock: sh7750-cpg: Add renesas,sh7750-cpg header Yoshinori Sato
@ 2024-04-04  4:59 ` Yoshinori Sato
  2024-04-04  4:59 ` [DO NOT MERGE v7 14/36] clk: renesas: Add SH7750/7751 CPG Driver Yoshinori Sato
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Yoshinori Sato @ 2024-04-04  4:59 UTC (permalink / raw)
  To: linux-sh; +Cc: Yoshinori Sato

divider and gate only support 32-bit registers.
Older hardware uses narrower registers, so I want to be able to handle
8-bit and 16-bit wide registers.

Seven clk_divider flags are used, and if I add flags for 8bit access and
16bit access, 8bit will not be enough, so I expanded it to u16.

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 drivers/clk/clk-divider.c    | 56 +++++++++++++++++++++-----------
 drivers/clk/clk-gate.c       | 62 ++++++++++++++++++++++++++++--------
 include/linux/clk-provider.h | 22 ++++++++++---
 3 files changed, 103 insertions(+), 37 deletions(-)

diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index a2c2b5203b0a..a1b5187cd63d 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -26,20 +26,38 @@
  * parent - fixed parent.  No clk_set_parent support
  */
 
-static inline u32 clk_div_readl(struct clk_divider *divider)
-{
-	if (divider->flags & CLK_DIVIDER_BIG_ENDIAN)
-		return ioread32be(divider->reg);
-
-	return readl(divider->reg);
+static inline u32 clk_div_read(struct clk_divider *divider)
+{
+	if (divider->flags & CLK_DIVIDER_REG_8BIT)
+		return readb(divider->reg);
+	else if (divider->flags & CLK_DIVIDER_REG_16BIT) {
+		if (divider->flags & CLK_DIVIDER_BIG_ENDIAN)
+			return ioread16be(divider->reg);
+		else
+			return readw(divider->reg);
+	} else {
+		if (divider->flags & CLK_DIVIDER_BIG_ENDIAN)
+			return ioread32be(divider->reg);
+		else
+			return readl(divider->reg);
+	}
 }
 
-static inline void clk_div_writel(struct clk_divider *divider, u32 val)
+static inline void clk_div_write(struct clk_divider *divider, u32 val)
 {
-	if (divider->flags & CLK_DIVIDER_BIG_ENDIAN)
-		iowrite32be(val, divider->reg);
-	else
-		writel(val, divider->reg);
+	if (divider->flags & CLK_DIVIDER_REG_8BIT)
+		writeb(val, divider->reg);
+	else if (divider->flags & CLK_DIVIDER_REG_16BIT) {
+		if (divider->flags & CLK_DIVIDER_BIG_ENDIAN)
+			iowrite16be(val, divider->reg);
+		else
+			writew(val, divider->reg);
+	} else {
+		if (divider->flags & CLK_DIVIDER_BIG_ENDIAN)
+			iowrite32be(val, divider->reg);
+		else
+			writel(val, divider->reg);
+	}
 }
 
 static unsigned int _get_table_maxdiv(const struct clk_div_table *table,
@@ -152,7 +170,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
 	struct clk_divider *divider = to_clk_divider(hw);
 	unsigned int val;
 
-	val = clk_div_readl(divider) >> divider->shift;
+	val = clk_div_read(divider) >> divider->shift;
 	val &= clk_div_mask(divider->width);
 
 	return divider_recalc_rate(hw, parent_rate, val, divider->table,
@@ -434,7 +452,7 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
 	if (divider->flags & CLK_DIVIDER_READ_ONLY) {
 		u32 val;
 
-		val = clk_div_readl(divider) >> divider->shift;
+		val = clk_div_read(divider) >> divider->shift;
 		val &= clk_div_mask(divider->width);
 
 		return divider_ro_round_rate(hw, rate, prate, divider->table,
@@ -455,7 +473,7 @@ static int clk_divider_determine_rate(struct clk_hw *hw,
 	if (divider->flags & CLK_DIVIDER_READ_ONLY) {
 		u32 val;
 
-		val = clk_div_readl(divider) >> divider->shift;
+		val = clk_div_read(divider) >> divider->shift;
 		val &= clk_div_mask(divider->width);
 
 		return divider_ro_determine_rate(hw, req, divider->table,
@@ -505,11 +523,11 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
 	if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
 		val = clk_div_mask(divider->width) << (divider->shift + 16);
 	} else {
-		val = clk_div_readl(divider);
+		val = clk_div_read(divider);
 		val &= ~(clk_div_mask(divider->width) << divider->shift);
 	}
 	val |= (u32)value << divider->shift;
-	clk_div_writel(divider, val);
+	clk_div_write(divider, val);
 
 	if (divider->lock)
 		spin_unlock_irqrestore(divider->lock, flags);
@@ -538,7 +556,7 @@ struct clk_hw *__clk_hw_register_divider(struct device *dev,
 		struct device_node *np, const char *name,
 		const char *parent_name, const struct clk_hw *parent_hw,
 		const struct clk_parent_data *parent_data, unsigned long flags,
-		void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
+		void __iomem *reg, u8 shift, u8 width, u32 clk_divider_flags,
 		const struct clk_div_table *table, spinlock_t *lock)
 {
 	struct clk_divider *div;
@@ -610,7 +628,7 @@ EXPORT_SYMBOL_GPL(__clk_hw_register_divider);
 struct clk *clk_register_divider_table(struct device *dev, const char *name,
 		const char *parent_name, unsigned long flags,
 		void __iomem *reg, u8 shift, u8 width,
-		u8 clk_divider_flags, const struct clk_div_table *table,
+		u32 clk_divider_flags, const struct clk_div_table *table,
 		spinlock_t *lock)
 {
 	struct clk_hw *hw;
@@ -664,7 +682,7 @@ struct clk_hw *__devm_clk_hw_register_divider(struct device *dev,
 		struct device_node *np, const char *name,
 		const char *parent_name, const struct clk_hw *parent_hw,
 		const struct clk_parent_data *parent_data, unsigned long flags,
-		void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
+		void __iomem *reg, u8 shift, u8 width, u32 clk_divider_flags,
 		const struct clk_div_table *table, spinlock_t *lock)
 {
 	struct clk_hw **ptr, *hw;
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
index 68e585a02fd9..65191f9684ff 100644
--- a/drivers/clk/clk-gate.c
+++ b/drivers/clk/clk-gate.c
@@ -24,20 +24,38 @@
  * parent - fixed parent.  No clk_set_parent support
  */
 
-static inline u32 clk_gate_readl(struct clk_gate *gate)
+static inline u32 clk_gate_read(struct clk_gate *gate)
 {
-	if (gate->flags & CLK_GATE_BIG_ENDIAN)
-		return ioread32be(gate->reg);
-
-	return readl(gate->reg);
+	if (gate->flags & CLK_GATE_REG_8BIT)
+		return readb(gate->reg);
+	else if (gate->flags & CLK_GATE_REG_16BIT) {
+		if (gate->flags & CLK_GATE_BIG_ENDIAN)
+			return ioread16be(gate->reg);
+		else
+			return readw(gate->reg);
+	} else {
+		if (gate->flags & CLK_GATE_BIG_ENDIAN)
+			return ioread32be(gate->reg);
+		else
+			return readl(gate->reg);
+	}
 }
 
-static inline void clk_gate_writel(struct clk_gate *gate, u32 val)
+static inline void clk_gate_write(struct clk_gate *gate, u32 val)
 {
-	if (gate->flags & CLK_GATE_BIG_ENDIAN)
-		iowrite32be(val, gate->reg);
-	else
-		writel(val, gate->reg);
+	if (gate->flags & CLK_GATE_REG_8BIT)
+		writeb(val, gate->reg);
+	else if (gate->flags & CLK_GATE_REG_16BIT) {
+		if (gate->flags & CLK_GATE_BIG_ENDIAN)
+			iowrite16be(val, gate->reg);
+		else
+			writew(val, gate->reg);
+	} else {
+		if (gate->flags & CLK_GATE_BIG_ENDIAN)
+			iowrite32be(val, gate->reg);
+		else
+			writel(val, gate->reg);
+	}
 }
 
 /*
@@ -72,7 +90,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
 		if (set)
 			reg |= BIT(gate->bit_idx);
 	} else {
-		reg = clk_gate_readl(gate);
+		reg = clk_gate_read(gate);
 
 		if (set)
 			reg |= BIT(gate->bit_idx);
@@ -80,7 +98,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
 			reg &= ~BIT(gate->bit_idx);
 	}
 
-	clk_gate_writel(gate, reg);
+	clk_gate_write(gate, reg);
 
 	if (gate->lock)
 		spin_unlock_irqrestore(gate->lock, flags);
@@ -105,7 +123,7 @@ int clk_gate_is_enabled(struct clk_hw *hw)
 	u32 reg;
 	struct clk_gate *gate = to_clk_gate(hw);
 
-	reg = clk_gate_readl(gate);
+	reg = clk_gate_read(gate);
 
 	/* if a set bit disables this clk, flip it before masking */
 	if (gate->flags & CLK_GATE_SET_TO_DISABLE)
@@ -137,12 +155,30 @@ struct clk_hw *__clk_hw_register_gate(struct device *dev,
 	struct clk_init_data init = {};
 	int ret = -EINVAL;
 
+	/* validate register size option and bit_idx */
 	if (clk_gate_flags & CLK_GATE_HIWORD_MASK) {
 		if (bit_idx > 15) {
 			pr_err("gate bit exceeds LOWORD field\n");
 			return ERR_PTR(-EINVAL);
 		}
 	}
+	if (clk_gate_flags & CLK_GATE_REG_16BIT) {
+		if (bit_idx > 15) {
+			pr_err("gate bit exceeds 16 bits\n");
+			return ERR_PTR(-EINVAL);
+		}
+	}
+	if (clk_gate_flags & CLK_GATE_REG_8BIT) {
+		if (bit_idx > 7) {
+			pr_err("gate bit exceeds 8 bits\n");
+			return ERR_PTR(-EINVAL);
+		}
+	}
+	if ((clk_gate_flags & CLK_GATE_HIWORD_MASK) &&
+	    clk_gate_flags & (CLK_GATE_REG_8BIT | CLK_GATE_REG_16BIT)) {
+		pr_err("HIWORD_MASK required 32-bit register\n");
+		return ERR_PTR(-EINVAL);
+	}
 
 	/* allocate the gate */
 	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 4a537260f655..eaa6ff1d0b2e 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -508,12 +508,16 @@ void of_fixed_clk_setup(struct device_node *np);
  * CLK_GATE_BIG_ENDIAN - by default little endian register accesses are used for
  *	the gate register.  Setting this flag makes the register accesses big
  *	endian.
+ * CLK_GATE_REG_8BIT - by default 32bit register accesses are used for
+ *	the gate register.  Setting this flag makes the register accesses 8bit.
+ * CLK_GATE_REG_16BIT - by default 32bit register accesses are used for
+ *	the gate register.  Setting this flag makes the register accesses 16bit.
  */
 struct clk_gate {
 	struct clk_hw hw;
 	void __iomem	*reg;
 	u8		bit_idx;
-	u8		flags;
+	u32		flags;
 	spinlock_t	*lock;
 };
 
@@ -522,6 +526,8 @@ struct clk_gate {
 #define CLK_GATE_SET_TO_DISABLE		BIT(0)
 #define CLK_GATE_HIWORD_MASK		BIT(1)
 #define CLK_GATE_BIG_ENDIAN		BIT(2)
+#define CLK_GATE_REG_8BIT		BIT(3)
+#define CLK_GATE_REG_16BIT		BIT(4)
 
 extern const struct clk_ops clk_gate_ops;
 struct clk_hw *__clk_hw_register_gate(struct device *dev,
@@ -675,13 +681,17 @@ struct clk_div_table {
  * CLK_DIVIDER_BIG_ENDIAN - By default little endian register accesses are used
  *	for the divider register.  Setting this flag makes the register accesses
  *	big endian.
+ * CLK_DIVIDER_REG_8BIT - by default 32bit register accesses are used for
+ *	the gate register.  Setting this flag makes the register accesses 8bit.
+ * CLK_DIVIDER_REG_16BIT - by default 32bit register accesses are used for
+ *	the gate register.  Setting this flag makes the register accesses 16bit.
  */
 struct clk_divider {
 	struct clk_hw	hw;
 	void __iomem	*reg;
 	u8		shift;
 	u8		width;
-	u8		flags;
+	u16		flags;
 	const struct clk_div_table	*table;
 	spinlock_t	*lock;
 };
@@ -697,6 +707,8 @@ struct clk_divider {
 #define CLK_DIVIDER_READ_ONLY		BIT(5)
 #define CLK_DIVIDER_MAX_AT_ZERO		BIT(6)
 #define CLK_DIVIDER_BIG_ENDIAN		BIT(7)
+#define CLK_DIVIDER_REG_8BIT		BIT(8)
+#define CLK_DIVIDER_REG_16BIT		BIT(9)
 
 extern const struct clk_ops clk_divider_ops;
 extern const struct clk_ops clk_divider_ro_ops;
@@ -726,18 +738,18 @@ struct clk_hw *__clk_hw_register_divider(struct device *dev,
 		struct device_node *np, const char *name,
 		const char *parent_name, const struct clk_hw *parent_hw,
 		const struct clk_parent_data *parent_data, unsigned long flags,
-		void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
+		void __iomem *reg, u8 shift, u8 width, u32 clk_divider_flags,
 		const struct clk_div_table *table, spinlock_t *lock);
 struct clk_hw *__devm_clk_hw_register_divider(struct device *dev,
 		struct device_node *np, const char *name,
 		const char *parent_name, const struct clk_hw *parent_hw,
 		const struct clk_parent_data *parent_data, unsigned long flags,
-		void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
+		void __iomem *reg, u8 shift, u8 width, u32 clk_divider_flags,
 		const struct clk_div_table *table, spinlock_t *lock);
 struct clk *clk_register_divider_table(struct device *dev, const char *name,
 		const char *parent_name, unsigned long flags,
 		void __iomem *reg, u8 shift, u8 width,
-		u8 clk_divider_flags, const struct clk_div_table *table,
+		u32 clk_divider_flags, const struct clk_div_table *table,
 		spinlock_t *lock);
 /**
  * clk_register_divider - register a divider clock with the clock framework
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [DO NOT MERGE v7 14/36] clk: renesas: Add SH7750/7751 CPG Driver
       [not found] <cover.1712041249.git.ysato@users.sourceforge.jp>
                   ` (4 preceding siblings ...)
  2024-04-04  4:59 ` [DO NOT MERGE v7 13/36] clk: Compatible with narrow registers Yoshinori Sato
@ 2024-04-04  4:59 ` Yoshinori Sato
  2024-04-04  4:59 ` [DO NOT MERGE v7 15/36] irqchip: Add SH7751 INTC driver Yoshinori Sato
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Yoshinori Sato @ 2024-04-04  4:59 UTC (permalink / raw)
  To: linux-sh; +Cc: Yoshinori Sato

Renesas SH7750 and SH7751 series CPG driver.
This driver supported frequency control and clock gating.

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 drivers/clk/renesas/Kconfig      |  13 +-
 drivers/clk/renesas/Makefile     |   1 +
 drivers/clk/renesas/clk-sh7750.c | 480 +++++++++++++++++++++++++++++++
 3 files changed, 491 insertions(+), 3 deletions(-)
 create mode 100644 drivers/clk/renesas/clk-sh7750.c

diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig
index d252150402e8..482efcb6e76e 100644
--- a/drivers/clk/renesas/Kconfig
+++ b/drivers/clk/renesas/Kconfig
@@ -1,8 +1,8 @@
 # SPDX-License-Identifier: GPL-2.0
 
 config CLK_RENESAS
-	bool "Renesas SoC clock support" if COMPILE_TEST && !ARCH_RENESAS
-	default y if ARCH_RENESAS
+	bool "Renesas SoC clock support" if COMPILE_TEST && !ARCH_RENESAS && !SUPERH
+	default y if ARCH_RENESAS || SUPERH
 	select CLK_EMEV2 if ARCH_EMEV2
 	select CLK_RZA1 if ARCH_R7S72100
 	select CLK_R7S9210 if ARCH_R7S9210
@@ -41,6 +41,9 @@ config CLK_RENESAS
 	select CLK_R9A08G045 if ARCH_R9A08G045
 	select CLK_R9A09G011 if ARCH_R9A09G011
 	select CLK_SH73A0 if ARCH_SH73A0
+	select CLK_SH7750 if CPU_SUBTYPE_SH7750 || CPU_SUBTYPE_SH7750S || \
+	                     CPU_SUBTYPE_SH7750R || CPU_SUBTYPE_SH7751 || \
+			     CPU_SUBTYPE_SH7751R
 
 if CLK_RENESAS
 
@@ -198,7 +201,6 @@ config CLK_SH73A0
 	select CLK_RENESAS_CPG_MSTP
 	select CLK_RENESAS_DIV6
 
-
 # Family
 config CLK_RCAR_CPG_LIB
 	bool "CPG/MSSR library functions" if COMPILE_TEST
@@ -228,6 +230,11 @@ config CLK_RZG2L
 	bool "Renesas RZ/{G2L,G2UL,G3S,V2L} family clock support" if COMPILE_TEST
 	select RESET_CONTROLLER
 
+config CLK_SH7750
+	bool "Renesas SH7750/7751 family clock support" if COMPILE_TEST
+	help
+	  This is a driver for SH7750 / SH7751 CPG.
+
 # Generic
 config CLK_RENESAS_CPG_MSSR
 	bool "CPG/MSSR clock support" if COMPILE_TEST
diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile
index f7e18679c3b8..ea0ffa8d59c4 100644
--- a/drivers/clk/renesas/Makefile
+++ b/drivers/clk/renesas/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_CLK_R9A07G054)		+= r9a07g044-cpg.o
 obj-$(CONFIG_CLK_R9A08G045)		+= r9a08g045-cpg.o
 obj-$(CONFIG_CLK_R9A09G011)		+= r9a09g011-cpg.o
 obj-$(CONFIG_CLK_SH73A0)		+= clk-sh73a0.o
+obj-$(CONFIG_CLK_SH7750)		+= clk-sh7750.o
 
 # Family
 obj-$(CONFIG_CLK_RCAR_CPG_LIB)		+= rcar-cpg-lib.o
diff --git a/drivers/clk/renesas/clk-sh7750.c b/drivers/clk/renesas/clk-sh7750.c
new file mode 100644
index 000000000000..043269d31200
--- /dev/null
+++ b/drivers/clk/renesas/clk-sh7750.c
@@ -0,0 +1,480 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas SH7750/51 CPG driver
+ *
+ * Copyright 2023 Yoshinori Sato <ysato@users.sourceforge.jp>
+ */
+
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+/* PCLK divide rate selector */
+static const struct clk_div_table pdiv_table[] = {
+	{ .val = 0, .div = 2, },
+	{ .val = 1, .div = 3, },
+	{ .val = 2, .div = 4, },
+	{ .val = 3, .div = 6, },
+	{ .val = 4, .div = 8, },
+	{ }
+};
+
+/* ICLK and BCLK divide rate selector */
+static const struct clk_div_table div_table[] = {
+	{ .val = 0, .div = 1, },
+	{ .val = 1, .div = 2, },
+	{ .val = 2, .div = 3, },
+	{ .val = 3, .div = 4, },
+	{ .val = 4, .div = 6, },
+	{ .val = 5, .div = 8, },
+	{ }
+};
+
+struct cpg_priv {
+	struct clk_hw hw;
+	spinlock_t clklock;
+	void __iomem *frqcr;
+	void __iomem *clkstp00;
+	u32 mode;
+	u32 feat;
+};
+
+/* CPG feature flag */
+#define CPG_DIV1	BIT(0)	/* 7750, 7750S, 7751 */
+#define MSTP_CR2	BIT(1)	/* 7750S, 7750R, 7751, 7751R */
+#define MSTP_CLKSTP	BIT(2)	/* 7750R, 7751, 7751R */
+#define MSTP_CSTP2	BIT(3)	/* 7751, 7751R */
+
+enum {
+	CPG_SH7750,
+	CPG_SH7750S,
+	CPG_SH7750R,
+	CPG_SH7751,
+	CPG_SH7751R,
+};
+
+static const u32 cpg_feature[] = {
+	[CPG_SH7750]  = CPG_DIV1,
+	[CPG_SH7750S] = CPG_DIV1 | MSTP_CR2,
+	[CPG_SH7750R] = MSTP_CR2 | MSTP_CLKSTP,
+	[CPG_SH7751]  = CPG_DIV1 | MSTP_CR2 | MSTP_CLKSTP | MSTP_CSTP2,
+	[CPG_SH7751R] = MSTP_CR2 | MSTP_CLKSTP | MSTP_CSTP2,
+};
+
+enum clk_type {CLK_DIV, CLK_STBCR, CLK_STBCR2, CLK_CLKSTP00};
+
+enum {
+	FRQCR = 0,
+	STBCR = 4,
+	WTCNT = 8,
+	WTCSR = 12,
+	STBCR2 = 16,
+	CLKSTP00 = 0,
+	CLKSTPCLR00 = 8,
+};
+
+static struct cpg_priv *cpg_data;
+
+#define to_priv(_hw) container_of(_hw, struct cpg_priv, hw)
+
+#define FRQCR_PLL1EN BIT(10)
+static const unsigned int pll1mult[] = { 12, 12, 6, 12, 6, 12, 1};
+
+static unsigned long pll_recalc_rate(struct clk_hw *hw,
+				      unsigned long parent_rate)
+{
+	struct cpg_priv *cpg = to_priv(hw);
+	unsigned long rate = parent_rate;
+	u16 frqcr;
+
+	frqcr = ioread16(cpg->frqcr);
+	if (frqcr & FRQCR_PLL1EN) {
+		rate *= pll1mult[cpg->mode];
+		if (cpg->mode < 6 && (cpg->feat & CPG_DIV1))
+			rate /= 2;
+	}
+	return rate;
+}
+
+static void get_round_rate(struct cpg_priv *cpg,
+			   unsigned long *out, bool *pllen,
+			   unsigned long rate, unsigned long prate)
+{
+	long pllout, res;
+	bool pll;
+
+	if (cpg->mode < 6 && (cpg->feat & CPG_DIV1))
+		prate /= 2;
+
+	pllout = prate * pll1mult[cpg->mode];
+	if (abs(pllout - rate) > abs(prate - rate)) {
+		res = prate;
+		pll = false;
+	} else {
+		res = pllout;
+		pll = true;
+	}
+	if (out)
+		*out = res;
+	if (pllen)
+		*pllen = pll;
+}
+
+static int pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
+{
+	struct cpg_priv *cpg = to_priv(hw);
+
+	get_round_rate(cpg, &req->rate, NULL, req->rate, req->best_parent_rate);
+	return 0;
+}
+
+static int pll_set_rate(struct clk_hw *hw,
+			unsigned long rate, unsigned long prate)
+{
+	struct cpg_priv *cpg = to_priv(hw);
+	bool oldpll, newpll;
+	u16 frqcr;
+
+	frqcr = ioread16(cpg->frqcr);
+	get_round_rate(cpg, NULL, &newpll, rate, prate);
+	oldpll = frqcr & FRQCR_PLL1EN;
+	frqcr &= ~FRQCR_PLL1EN;
+
+	if (newpll) {
+		frqcr |= FRQCR_PLL1EN;
+		if (!oldpll) {
+			/* set PLL wakeup delay time */
+			iowrite16(0xa500, cpg->frqcr + WTCNT);
+			iowrite16(0xa507, cpg->frqcr + WTCNT);
+			iowrite16(0x5a00, cpg->frqcr + WTCSR);
+		}
+	}
+	iowrite16(frqcr, cpg->frqcr);
+
+	/* Test for new PLL state */
+	frqcr = ioread16(cpg->frqcr);
+	oldpll = frqcr & FRQCR_PLL1EN;
+	return !(oldpll == newpll);
+}
+
+static const struct clk_ops pll_ops = {
+	.recalc_rate = pll_recalc_rate,
+	.determine_rate = pll_determine_rate,
+	.set_rate = pll_set_rate,
+};
+
+#define PLLOUT "pllout"
+
+static int register_pll(struct device_node *node, struct cpg_priv *cpg)
+{
+	const char *clk_name = node->name;
+	const char *parent_name;
+	struct clk_init_data init = {
+		.name = PLLOUT,
+		.ops = &pll_ops,
+		.flags = 0,
+		.num_parents = 1,
+	};
+	int ret;
+
+	parent_name = of_clk_get_parent_name(node, 0);
+	init.parent_names = &parent_name;
+	cpg->hw.init = &init;
+
+	ret = of_clk_hw_register(node, &cpg->hw);
+	if (ret < 0)
+		pr_err("%pOF: failed to add provider %s (%d)\n",
+		       node, clk_name, ret);
+	return ret;
+}
+
+static void clkstp00_sw(struct clk_hw *hw, bool on)
+{
+	u32 val;
+	struct clk_gate *gate = to_clk_gate(hw);
+
+	val = BIT(gate->bit_idx);
+	if (on)
+		writel(val, gate->reg + CLKSTPCLR00);
+	else
+		writel(val, gate->reg);
+}
+
+static int clkstp00_enable(struct clk_hw *hw)
+{
+	clkstp00_sw(hw, true);
+	return 0;
+}
+
+static void clkstp00_disable(struct clk_hw *hw)
+{
+	clkstp00_sw(hw, false);
+}
+
+static int clkstp00_is_enabled(struct clk_hw *hw)
+{
+	u8 val;
+	struct clk_gate *gate = to_clk_gate(hw);
+
+	val = readb(gate->reg);
+	val &= 1 << gate->bit_idx;
+	return val == 0;
+}
+
+static const struct clk_ops gate_clkstp00_ops = {
+	.enable = clkstp00_enable,
+	.disable = clkstp00_disable,
+	.is_enabled = clkstp00_is_enabled,
+};
+
+static struct clk_hw *clk_hw_register_clkstp(struct device_node *node,
+					     const char *name,
+					     const char *parent,
+					     void __iomem *reg, int bit,
+					     spinlock_t *lock)
+{
+	struct clk_gate *gate;
+	struct clk_init_data init = {
+		.name = name,
+		.ops = &gate_clkstp00_ops,
+		.flags = 0,
+		.parent_names = &parent,
+		.num_parents = 1,
+	};
+	struct clk_hw *hw;
+	int ret;
+
+	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+	if (gate == NULL)
+		goto error;
+	gate->reg = reg;
+	gate->bit_idx = bit;
+	gate->flags = 0;
+	gate->lock = lock;
+	gate->hw.init = &init;
+	hw = &gate->hw;
+	ret = of_clk_hw_register(node, hw);
+	if (ret < 0)
+		goto error;
+	return hw;
+error:
+	kfree(gate);
+	return ERR_PTR(ret);
+}
+
+#define STBCR_BASE 5
+#define CLKSTP_BASE 2
+static int register_div(struct device_node *node, struct cpg_priv *cpg)
+{
+	static const char * const divout[] = {
+		"fck", "bck", "ick",
+	};
+	static const char * const stbcrout[] = {
+		"sci_clk", "rtc_clk", "tmu012_clk",	/* STBCR */
+		"scif_clk", "dmac_clk",			/* STBCR */
+		"ubc_clk", "sq_clk",			/* STBCR2 */
+	};
+	static const char * const clkstpout[] = {
+		"intc_clk", "tmu34_clk", "pcic_clk",	/* CLKSTP00 */
+	};
+
+	int num_clk = ARRAY_SIZE(divout) + ARRAY_SIZE(stbcrout) + ARRAY_SIZE(clkstpout);
+	struct clk_hw_onecell_data *data;
+	struct clk_hw *reg_hw;
+	unsigned int i, n;
+	int ret;
+
+	data = kzalloc(struct_size(data, hws, num_clk + 1), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	num_clk = 0;
+	for (i = 0; i < ARRAY_SIZE(divout); i++) {
+		reg_hw = __clk_hw_register_divider(NULL, node, divout[i],
+						   PLLOUT, NULL, NULL,
+						   0, cpg->frqcr, i * 3, 3,
+						   CLK_DIVIDER_REG_16BIT,
+						   (i == 0) ? pdiv_table : div_table,
+						   &cpg->clklock);
+		if (IS_ERR(reg_hw)) {
+			ret = PTR_ERR(reg_hw);
+			goto error;
+		}
+		data->hws[num_clk++] = reg_hw;
+	}
+
+	n = (cpg->feat & MSTP_CR2) ? ARRAY_SIZE(stbcrout) : STBCR_BASE;
+	for (i = 0; i < n; i++) {
+		u32 off =  (i < (ARRAY_SIZE(stbcrout) - 2)) ? STBCR : STBCR2;
+
+		reg_hw = __clk_hw_register_gate(NULL, node, stbcrout[i],
+						divout[0], NULL, NULL,
+						0, cpg->frqcr + off, i % STBCR_BASE,
+						CLK_GATE_REG_8BIT | CLK_GATE_SET_TO_DISABLE,
+						&cpg->clklock);
+		if (IS_ERR(reg_hw)) {
+			ret = PTR_ERR(reg_hw);
+			goto error;
+		}
+		data->hws[num_clk++] = reg_hw;
+	}
+
+	if (cpg->feat & MSTP_CLKSTP) {
+		n = (cpg->feat & MSTP_CSTP2) ? ARRAY_SIZE(clkstpout) : CLKSTP_BASE;
+		for (i = 0; i < n; i++) {
+			reg_hw = clk_hw_register_clkstp(node, clkstpout[i],
+							divout[0], cpg->clkstp00,
+							i, &cpg->clklock);
+			if (IS_ERR(reg_hw)) {
+				ret = PTR_ERR(reg_hw);
+				goto error;
+			}
+			data->hws[num_clk++] = reg_hw;
+		}
+	}
+
+	data->num = num_clk;
+	ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, data);
+	if (ret < 0)
+		goto error;
+	return 0;
+
+error:
+	pr_err("%pOF: failed to register clock (%d)\n",
+		       node, ret);
+	for (num_clk--; num_clk >= 0; num_clk--)
+		kfree(data->hws[num_clk]);
+	kfree(data);
+	return ret;
+}
+
+#define NR_CLKMODE 7
+static int sh7750_cpg_setup(struct device_node *node, u32 feat)
+{
+	struct cpg_priv *cpg;
+	u32 mode = NR_CLKMODE;
+	int ret = 0;
+
+	cpg_data = NULL;
+
+	of_property_read_u32_index(node, "renesas,mode", 0, &mode);
+	if (mode >= NR_CLKMODE) {
+		pr_err("%s: Invalid clock mode setting (%u)\n",
+		       node->name, mode);
+		return -EINVAL;
+	}
+
+	cpg = kzalloc(sizeof(struct cpg_priv), GFP_KERNEL);
+	if (!cpg)
+		return -ENOMEM;
+
+	cpg->frqcr = of_iomap(node, 0);
+	if (cpg->frqcr == NULL) {
+		pr_err("%pOF: failed to map divide register", node);
+		ret = -ENODEV;
+		goto cpg_free;
+	}
+
+	if (feat & MSTP_CLKSTP) {
+		cpg->clkstp00 = of_iomap(node, 1);
+		if (cpg->clkstp00 == NULL) {
+			pr_err("%pOF: failed to map clkstp00 register", node);
+			ret = -ENODEV;
+			goto unmap_frqcr;
+		}
+	}
+	cpg->feat = feat;
+	cpg->mode = mode;
+
+	ret = register_pll(node, cpg);
+	if (ret < 0)
+		goto unmap_clkstp00;
+
+	ret = register_div(node, cpg);
+	if (ret < 0)
+		goto unmap_clkstp00;
+
+	cpg_data = cpg;
+	return 0;
+
+unmap_clkstp00:
+	iounmap(cpg->clkstp00);
+unmap_frqcr:
+	iounmap(cpg->frqcr);
+cpg_free:
+	kfree(cpg);
+	return ret;
+}
+
+static void __init sh7750_cpg_init(struct device_node *node)
+{
+	sh7750_cpg_setup(node, cpg_feature[CPG_SH7750]);
+}
+
+static void __init sh7750s_cpg_init(struct device_node *node)
+{
+	sh7750_cpg_setup(node, cpg_feature[CPG_SH7750S]);
+}
+
+static void __init sh7750r_cpg_init(struct device_node *node)
+{
+	sh7750_cpg_setup(node, cpg_feature[CPG_SH7750R]);
+}
+
+static void __init sh7751_cpg_init(struct device_node *node)
+{
+	sh7750_cpg_setup(node, cpg_feature[CPG_SH7751]);
+}
+
+static void __init sh7751r_cpg_init(struct device_node *node)
+{
+	sh7750_cpg_setup(node, cpg_feature[CPG_SH7751R]);
+}
+
+CLK_OF_DECLARE_DRIVER(sh7750_cpg, "renesas,sh7750-cpg",
+		      sh7750_cpg_init);
+CLK_OF_DECLARE_DRIVER(sh7750s_cpg, "renesas,sh7750s-cpg",
+		      sh7750s_cpg_init);
+CLK_OF_DECLARE_DRIVER(sh7750r_cpg, "renesas,sh7750r-cpg",
+		      sh7750r_cpg_init);
+CLK_OF_DECLARE_DRIVER(sh7751_cpg, "renesas,sh7751-cpg",
+		      sh7751_cpg_init);
+CLK_OF_DECLARE_DRIVER(sh7751r_cpg, "renesas,sh7751r-cpg",
+		      sh7751r_cpg_init);
+
+static int sh7750_cpg_probe(struct platform_device *pdev)
+{
+	u32 feature;
+
+	if (cpg_data)
+		return 0;
+	feature = *(u32 *)of_device_get_match_data(&pdev->dev);
+	return sh7750_cpg_setup(pdev->dev.of_node, feature);
+}
+
+static const struct of_device_id sh7750_cpg_of_match[] = {
+	{ .compatible = "renesas,sh7750-cpg",
+	  .data = &cpg_feature[CPG_SH7750] },
+	{ .compatible = "renesas,sh7750s-cpg",
+	  .data = &cpg_feature[CPG_SH7750S] },
+	{ .compatible = "renesas,sh7750r-cpg",
+	  .data = &cpg_feature[CPG_SH7750R] },
+	{ .compatible = "renesas,sh7751-cpg",
+	  .data = &cpg_feature[CPG_SH7751] },
+	{ .compatible = "renesas,sh7751r-cpg",
+	  .data = &cpg_feature[CPG_SH7751R] },
+	{ }
+};
+
+static struct platform_driver sh7750_cpg_driver = {
+	.probe  = sh7750_cpg_probe,
+	.driver = {
+		.name = "sh7750-cpg",
+		.of_match_table = sh7750_cpg_of_match,
+	},
+};
+builtin_platform_driver(sh7750_cpg_driver);
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [DO NOT MERGE v7 15/36] irqchip: Add SH7751 INTC driver
       [not found] <cover.1712041249.git.ysato@users.sourceforge.jp>
                   ` (5 preceding siblings ...)
  2024-04-04  4:59 ` [DO NOT MERGE v7 14/36] clk: renesas: Add SH7750/7751 CPG Driver Yoshinori Sato
@ 2024-04-04  4:59 ` Yoshinori Sato
  2024-04-04  4:59 ` [DO NOT MERGE v7 16/36] dt-bindings: interrupt-controller: renesas,sh7751-intc: Add json-schema Yoshinori Sato
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Yoshinori Sato @ 2024-04-04  4:59 UTC (permalink / raw)
  To: linux-sh; +Cc: Yoshinori Sato

Renesas SH7751 Internal interrupt controller driver.

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 drivers/irqchip/Kconfig              |   8 +
 drivers/irqchip/Makefile             |   1 +
 drivers/irqchip/irq-renesas-sh7751.c | 282 +++++++++++++++++++++++++++
 3 files changed, 291 insertions(+)
 create mode 100644 drivers/irqchip/irq-renesas-sh7751.c

diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 72c07a12f5e1..33badb5b4f00 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -690,4 +690,12 @@ config SUNPLUS_SP7021_INTC
 	  chained controller, routing all interrupt source in P-Chip to
 	  the primary controller on C-Chip.
 
+config RENESAS_SH7751_INTC
+	bool "Renesas SH7751 Interrupt Controller"
+	depends on SH_DEVICE_TREE || COMPILE_TEST
+	select IRQ_DOMAIN_HIERARCHY
+	help
+	  Support for the Renesas SH7751 On-chip interrupt controller.
+	  And external interrupt encoder for some targets.
+
 endmenu
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index ec4a18380998..51855034a895 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -121,3 +121,4 @@ obj-$(CONFIG_IRQ_IDT3243X)		+= irq-idt3243x.o
 obj-$(CONFIG_APPLE_AIC)			+= irq-apple-aic.o
 obj-$(CONFIG_MCHP_EIC)			+= irq-mchp-eic.o
 obj-$(CONFIG_SUNPLUS_SP7021_INTC)	+= irq-sp7021-intc.o
+obj-$(CONFIG_RENESAS_SH7751_INTC)	+= irq-renesas-sh7751.o
diff --git a/drivers/irqchip/irq-renesas-sh7751.c b/drivers/irqchip/irq-renesas-sh7751.c
new file mode 100644
index 000000000000..91d6dc3ed04c
--- /dev/null
+++ b/drivers/irqchip/irq-renesas-sh7751.c
@@ -0,0 +1,282 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas SH7751 interrupt controller driver
+ *
+ * Copyright 2023 Yoshinori Sato <ysato@users.sourceforge.jp>
+ */
+
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <dt-bindings/interrupt-controller/renesas,sh7751-intc.h>
+
+struct ipr {
+	u16 off;
+	u16 idx;
+};
+
+struct sh7751_intc_priv {
+	const struct ipr *iprmap;
+	void __iomem *base;
+	void __iomem *intpri00;
+	bool	     irlm;
+};
+
+enum {
+	R_ICR         = 0x00,
+	R_IPR         = 0x04,
+	R_INTPRI00    = 0x00,
+	R_INTREQ00    = 0x20,
+	R_INTMSK00    = 0x40,
+	R_INTMSKCLR00 = 0x60,
+};
+
+#define ICR_IRLM BIT(7)
+
+/*
+ * SH7751 IRQ mapping
+ *  IRQ16 - 63: Group0 - IPRA to IPRD
+ *   IRQ16 - 31: external IRL input (ICR.IRLM is 0)
+ *  IRQ80 - 92: Group1 - INTPRI00
+ */
+#define IRQ_START	16
+#define MAX_IRL		(IRQ_START + NR_IRL)
+#define GRP0_IRQ_END	63
+#define GRP1_IRQ_START	80
+#define IRQ_END		92
+
+#define NR_IPRMAP0	(GRP0_IRQ_END - IRQ_START + 1)
+#define NR_IPRMAP1	(IRQ_END - GRP1_IRQ_START)
+#define IPR_PRI_MASK	0x000f
+
+#define IPRA			0
+#define IPRB			4
+#define IPRC			8
+#define IPRD			12
+#define INTPRI00		256
+#define IPR_B12			12
+#define IPR_B8			8
+#define IPR_B4			4
+#define IPR_B0			0
+
+/* SH7751 EVT to IPR mapping table */
+static const struct ipr sh7751_iprmap[] = {
+	[evt2irq(0x240)] = {IPRD, IPR_B12},	/* IRL0 (ICR.IRLM=1) */
+	[evt2irq(0x2a0)] = {IPRD, IPR_B8},	/* IRL1 (ICR.IRLM=1) */
+	[evt2irq(0x300)] = {IPRD, IPR_B4},	/* IRL2 (ICR.IRLM=1) */
+	[evt2irq(0x360)] = {IPRD, IPR_B0},	/* IRL3 (ICR.IRLM=1) */
+	[evt2irq(0x400)] = {IPRA, IPR_B12},	/* TMU0 */
+	[evt2irq(0x420)] = {IPRA, IPR_B8},	/* TMU1 */
+	[evt2irq(0x440)] = {IPRA, IPR_B4},	/* TMU2 TNUI */
+	[evt2irq(0x460)] = {IPRA, IPR_B4},	/* TMU2 TICPI */
+	[evt2irq(0x480)] = {IPRA, IPR_B0},	/* RTC ATI */
+	[evt2irq(0x4a0)] = {IPRA, IPR_B0},	/* RTC PRI */
+	[evt2irq(0x4c0)] = {IPRA, IPR_B0},	/* RTC CUI */
+	[evt2irq(0x4e0)] = {IPRB, IPR_B4},	/* SCI ERI */
+	[evt2irq(0x500)] = {IPRB, IPR_B4},	/* SCI RXI */
+	[evt2irq(0x520)] = {IPRB, IPR_B4},	/* SCI TXI */
+	[evt2irq(0x540)] = {IPRB, IPR_B4},	/* SCI TEI */
+	[evt2irq(0x560)] = {IPRB, IPR_B12},	/* WDT */
+	[evt2irq(0x580)] = {IPRB, IPR_B8},	/* REF RCMI */
+	[evt2irq(0x5a0)] = {IPRB, IPR_B4},	/* REF ROVI */
+	[evt2irq(0x600)] = {IPRC, IPR_B0},	/* H-UDI */
+	[evt2irq(0x620)] = {IPRC, IPR_B12},	/* GPIO */
+	[evt2irq(0x640)] = {IPRC, IPR_B8},	/* DMAC DMTE0 */
+	[evt2irq(0x660)] = {IPRC, IPR_B8},	/* DMAC DMTE1 */
+	[evt2irq(0x680)] = {IPRC, IPR_B8},	/* DMAC DMTE2 */
+	[evt2irq(0x6a0)] = {IPRC, IPR_B8},	/* DMAC DMTE3 */
+	[evt2irq(0x6c0)] = {IPRC, IPR_B8},	/* DMAC DMAE */
+	[evt2irq(0x700)] = {IPRC, IPR_B4},	/* SCIF ERI */
+	[evt2irq(0x720)] = {IPRC, IPR_B4},	/* SCIF RXI */
+	[evt2irq(0x740)] = {IPRC, IPR_B4},	/* SCIF BRI */
+	[evt2irq(0x760)] = {IPRC, IPR_B4},	/* SCIF TXI */
+	[evt2irq(0x780)] = {IPRC, IPR_B8},	/* DMAC DMTE4 */
+	[evt2irq(0x7a0)] = {IPRC, IPR_B8},	/* DMAC DMTE5 */
+	[evt2irq(0x7c0)] = {IPRC, IPR_B8},	/* DMAC DMTE6 */
+	[evt2irq(0x7e0)] = {IPRC, IPR_B8},	/* DMAC DMTE7 */
+	[evt2irq(0xa00)] = {INTPRI00, IPR_B0},	/* PCIC PCISERR */
+	[evt2irq(0xa20)] = {INTPRI00, IPR_B4},	/* PCIC PCIDMA3 */
+	[evt2irq(0xa40)] = {INTPRI00, IPR_B4},	/* PCIC PCIDMA2 */
+	[evt2irq(0xa60)] = {INTPRI00, IPR_B4},	/* PCIC PCIDMA1 */
+	[evt2irq(0xa80)] = {INTPRI00, IPR_B4},	/* PCIC PCIDMA0 */
+	[evt2irq(0xaa0)] = {INTPRI00, IPR_B4},	/* PCIC PCIPWON */
+	[evt2irq(0xac0)] = {INTPRI00, IPR_B4},	/* PCIC PCIPWDWN */
+	[evt2irq(0xae0)] = {INTPRI00, IPR_B4},	/* PCIC PCIERR */
+	[evt2irq(0xb00)] = {INTPRI00, IPR_B8},	/* TMU3 */
+	[evt2irq(0xb80)] = {INTPRI00, IPR_B12},	/* TMU4 */
+};
+
+/*
+ * IPR registers have 4bit priority x 4 entry (16bits)
+ */
+static void update_ipr(struct sh7751_intc_priv *priv, unsigned int irq, u16 pri)
+{
+	const struct ipr *ipr = NULL;
+	void __iomem *ipr_base;
+	unsigned int offset;
+	u16 mask;
+
+	ipr = priv->iprmap + irq;
+	if (irq < GRP1_IRQ_START) {
+		/* Group0 */
+		ipr_base = priv->base + R_IPR;
+		offset = ipr->off;
+	} else {
+		/* Group1 */
+		ipr_base = priv->intpri00;
+		offset = ipr->off - INTPRI00;
+	}
+	mask = ~(IPR_PRI_MASK << ipr->idx);
+	pri = (pri & IPR_PRI_MASK) << ipr->idx;
+	mask &= __raw_readw(ipr_base + offset);
+	__raw_writew(mask | pri, ipr_base + offset);
+}
+
+static inline bool is_valid_irq(unsigned int irq)
+{
+	/* IRQ16 - 63 */
+	if (irq >= IRQ_START && irq < IRQ_START + NR_IPRMAP0)
+		return true;
+	/* IRQ80 - 92 */
+	if (irq >= GRP1_IRQ_START && irq <= IRQ_END)
+		return true;
+	return false;
+}
+
+static inline struct sh7751_intc_priv *irq_data_to_priv(struct irq_data *data)
+{
+	return data->domain->host_data;
+}
+
+/* Interrupt unmask priority is 1, mask priority is 0 */
+#define PRI_ENABLE  1
+#define PRI_DISABLE 0
+static void endisable_irq(struct irq_data *data, bool enable)
+{
+	struct sh7751_intc_priv *priv;
+	unsigned int irq;
+
+	priv = irq_data_to_priv(data);
+
+	irq = irqd_to_hwirq(data);
+	if (!is_valid_irq(irq)) {
+		/* IRQ out of range */
+		pr_warn_once("%s: IRQ %u is out of range\n", __FILE__, irq);
+		return;
+	}
+
+	if (irq <= MAX_IRL && !priv->irlm) {
+		/* IRL encoded external interrupt */
+		/* enable and disable from SR.IMASK */
+		update_sr_imask(irq - IRQ_START, enable);
+	} else {
+		/* Internal peripheral interrupt */
+		/* enable and disable from interrupt priority */
+		update_ipr(priv, irq, enable ? PRI_ENABLE : PRI_DISABLE);
+	}
+}
+
+static void sh7751_mask_irq(struct irq_data *data)
+{
+	endisable_irq(data, false);
+}
+
+static void sh7751_unmask_irq(struct irq_data *data)
+{
+	endisable_irq(data, true);
+}
+
+static const struct irq_chip sh7751_irq_chip = {
+	.name		= "SH7751-INTC",
+	.irq_unmask	= sh7751_unmask_irq,
+	.irq_mask	= sh7751_mask_irq,
+};
+
+static int irq_sh7751_map(struct irq_domain *h, unsigned int virq,
+			  irq_hw_number_t hw_irq_num)
+{
+	irq_set_chip_and_handler(virq, &sh7751_irq_chip, handle_level_irq);
+	irq_get_irq_data(virq)->chip_data = h->host_data;
+	irq_modify_status(virq, IRQ_NOREQUEST, IRQ_NOPROBE);
+	return 0;
+}
+
+static int irq_sh7751_xlate(struct irq_domain *d, struct device_node *ctrlr,
+			     const u32 *intspec, unsigned int intsize,
+			     unsigned long *out_hwirq, unsigned int *out_type)
+{
+	if (WARN_ON(intsize < 1))
+		return -EINVAL;
+	*out_hwirq = evt2irq(intspec[0]);
+	*out_type = IRQ_TYPE_NONE;
+	return 0;
+}
+
+static const struct irq_domain_ops irq_ops = {
+	.map    = irq_sh7751_map,
+	.xlate  = irq_sh7751_xlate,
+};
+
+static int __init shintc_of_init(struct device_node *intc, struct device_node *parent,
+				 const struct ipr *iprmap)
+{
+	struct sh7751_intc_priv *priv;
+	void __iomem *base, *base2;
+	struct irq_domain *domain;
+	u16 icr;
+	int ret;
+
+	priv = kzalloc(sizeof(struct sh7751_intc_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return -ENOMEM;
+
+	base = of_iomap(intc, 0);
+	base2 = of_iomap(intc, 1);
+	if (!base || !base2) {
+		pr_err("%pOFP: Invalid register definition\n", intc);
+		ret = -EINVAL;
+		goto error;
+	}
+
+	priv->base = base;
+	priv->intpri00 = base2;
+	priv->iprmap = iprmap;
+
+	if (of_property_read_bool(intc, "renesas,irlm")) {
+		priv->irlm = true;
+		icr = __raw_readw(priv->base + R_ICR);
+		icr |= ICR_IRLM;
+		__raw_writew(icr, priv->base + R_ICR);
+	}
+
+	domain = irq_domain_add_linear(intc, NR_IRQS, &irq_ops, priv);
+	if (domain == NULL) {
+		pr_err("%pOFP: cannot initialize irq domain\n", intc);
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	irq_set_default_host(domain);
+	pr_info("%pOFP: SH7751 Interrupt controller (%s external IRQ)",
+		intc, priv->irlm ? "4 lines" : "15 level");
+	return 0;
+
+error:
+	if (base)
+		iounmap(base);
+	if (base2)
+		iounmap(base);
+	kfree(priv);
+	return ret;
+}
+
+static int __init sh7751_intc_of_init(struct device_node *intc,
+				      struct device_node *parent)
+{
+	return shintc_of_init(intc, parent, sh7751_iprmap);
+}
+
+IRQCHIP_DECLARE(sh_7751_intc, "renesas,sh7751-intc", sh7751_intc_of_init);
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [DO NOT MERGE v7 16/36] dt-bindings: interrupt-controller: renesas,sh7751-intc: Add json-schema
       [not found] <cover.1712041249.git.ysato@users.sourceforge.jp>
                   ` (6 preceding siblings ...)
  2024-04-04  4:59 ` [DO NOT MERGE v7 15/36] irqchip: Add SH7751 INTC driver Yoshinori Sato
@ 2024-04-04  4:59 ` Yoshinori Sato
  2024-04-04  4:59 ` [DO NOT MERGE v7 17/36] irqchip: SH7751 external interrupt encoder with enable gate Yoshinori Sato
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Yoshinori Sato @ 2024-04-04  4:59 UTC (permalink / raw)
  To: linux-sh; +Cc: Yoshinori Sato

Renesas SH7751 INTC json-schema.

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 .../renesas,sh7751-intc.yaml                  | 53 +++++++++++++++++++
 1 file changed, 53 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/renesas,sh7751-intc.yaml

diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,sh7751-intc.yaml b/Documentation/devicetree/bindings/interrupt-controller/renesas,sh7751-intc.yaml
new file mode 100644
index 000000000000..fb924eff465d
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,sh7751-intc.yaml
@@ -0,0 +1,53 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interrupt-controller/renesas,sh7751-intc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas SH7751 Interrupt Controller
+
+maintainers:
+  - Yoshinori Sato <ysato@users.sourceforge.jp>
+
+properties:
+  compatible:
+    items:
+      - const: renesas,sh7751-intc
+
+  '#interrupt-cells':
+    const: 1
+
+  interrupt-controller: true
+
+  reg:
+    maxItems: 2
+
+  reg-names:
+    items:
+      - const: ICR
+      - const: INTPRI00
+
+  renesas,icr-irlm:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description: If true four independent interrupt requests mode (ICR.IRLM is 1).
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - '#interrupt-cells'
+  - interrupt-controller
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/renesas,sh7751-intc.h>
+    shintc: interrupt-controller@ffd00000 {
+            compatible = "renesas,sh7751-intc";
+            reg = <0xffd00000 14>, <0xfe080000 128>;
+            reg-names = "ICR", "INTPRI00";
+            #interrupt-cells = <1>;
+            interrupt-controller;
+    };
+...
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [DO NOT MERGE v7 17/36] irqchip: SH7751 external interrupt encoder with enable gate.
       [not found] <cover.1712041249.git.ysato@users.sourceforge.jp>
                   ` (7 preceding siblings ...)
  2024-04-04  4:59 ` [DO NOT MERGE v7 16/36] dt-bindings: interrupt-controller: renesas,sh7751-intc: Add json-schema Yoshinori Sato
@ 2024-04-04  4:59 ` Yoshinori Sato
  2024-04-04  4:59 ` [DO NOT MERGE v7 18/36] dt-bindings: interrupt-controller: renesas,sh7751-irl-ext: Add json-schema Yoshinori Sato
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Yoshinori Sato @ 2024-04-04  4:59 UTC (permalink / raw)
  To: linux-sh; +Cc: Yoshinori Sato

SH7751 have 15 level external interrupt.
It is typically connected to the CPU through a priority encoder
that can suppress requests.
This driver provides a way to control those hardware with irqchip.

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 drivers/irqchip/Kconfig                 |   7 +
 drivers/irqchip/Makefile                |   2 +
 drivers/irqchip/irq-renesas-sh7751irl.c | 221 ++++++++++++++++++++++++
 3 files changed, 230 insertions(+)
 create mode 100644 drivers/irqchip/irq-renesas-sh7751irl.c

diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 33badb5b4f00..7670fcd6757d 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -698,4 +698,11 @@ config RENESAS_SH7751_INTC
 	  Support for the Renesas SH7751 On-chip interrupt controller.
 	  And external interrupt encoder for some targets.
 
+config RENESAS_SH7751IRL_INTC
+	bool "Renesas SH7751 based target IRL encoder support."
+	depends on RENESAS_SH7751_INTC
+	help
+	  Support for External Interrupt encoder
+	  on the some Renesas SH7751 based target.
+
 endmenu
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 51855034a895..bc21d65441f2 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -122,3 +122,5 @@ obj-$(CONFIG_APPLE_AIC)			+= irq-apple-aic.o
 obj-$(CONFIG_MCHP_EIC)			+= irq-mchp-eic.o
 obj-$(CONFIG_SUNPLUS_SP7021_INTC)	+= irq-sp7021-intc.o
 obj-$(CONFIG_RENESAS_SH7751_INTC)	+= irq-renesas-sh7751.o
+obj-$(CONFIG_RENESAS_SH7751IRL_INTC)	+= irq-renesas-sh7751irl.o
+
diff --git a/drivers/irqchip/irq-renesas-sh7751irl.c b/drivers/irqchip/irq-renesas-sh7751irl.c
new file mode 100644
index 000000000000..5990f2cd9a3d
--- /dev/null
+++ b/drivers/irqchip/irq-renesas-sh7751irl.c
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SH7751 based board external interrupt level encoder driver
+ * (Renesas RTS7751R2D / IO DATA DEVICE LANDISK, USL-5P)
+ *
+ * Copyright (C) 2023 Yoshinori Sato
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+
+struct sh7751irl_intc_priv {
+	struct irq_domain *irq_domain;
+	void __iomem	  *base;
+	unsigned int	  width;
+	bool		  invert;
+	u32		  enable_bit[NR_IRL];
+};
+
+static inline unsigned long get_reg(void __iomem *addr, unsigned int w)
+{
+	switch (w) {
+	case 8:
+		return __raw_readb(addr);
+	case 16:
+		return __raw_readw(addr);
+	case 32:
+		return __raw_readl(addr);
+	default:
+		/* The size is checked when reading the properties. */
+		pr_err("%s: Invalid width %d", __FILE__, w);
+		return 0;
+	}
+}
+
+static inline void set_reg(void __iomem *addr, unsigned int w, unsigned long val)
+{
+	switch (w) {
+	case 8:
+		__raw_writeb(val, addr);
+		break;
+	case 16:
+		__raw_writew(val, addr);
+		break;
+	case 32:
+		__raw_writel(val, addr);
+		break;
+	default:
+		pr_err("%s: Invalid width %d", __FILE__, w);
+	}
+}
+
+static inline struct sh7751irl_intc_priv *irq_data_to_priv(struct irq_data *data)
+{
+	return data->domain->host_data;
+}
+
+static void irl_endisable(struct irq_data *data, unsigned int enable)
+{
+	struct sh7751irl_intc_priv *priv;
+	unsigned long val;
+	unsigned int irl;
+
+	priv = irq_data_to_priv(data);
+	irl = irqd_to_hwirq(data) - IRL_BASE_IRQ;
+
+	if (irl < NR_IRL && priv->enable_bit[irl] < priv->width) {
+		if (priv->invert)
+			enable = !enable;
+
+		val = get_reg(priv->base, priv->width);
+		if (enable)
+			set_bit(priv->enable_bit[irl], &val);
+		else
+			clear_bit(priv->enable_bit[irl], &val);
+		set_reg(priv->base, priv->width, val);
+	} else {
+		pr_err("%s: Invalid register define in IRL %u", __FILE__, irl);
+	}
+}
+
+static void sh7751irl_intc_disable_irq(struct irq_data *data)
+{
+	irl_endisable(data, 0);
+}
+
+static void sh7751irl_intc_enable_irq(struct irq_data *data)
+{
+	irl_endisable(data, 1);
+}
+
+static struct irq_chip sh7751irl_intc_chip = {
+	.name		= "SH7751IRL-INTC",
+	.irq_enable	= sh7751irl_intc_enable_irq,
+	.irq_disable	= sh7751irl_intc_disable_irq,
+};
+
+static int sh7751irl_intc_map(struct irq_domain *h, unsigned int virq,
+			       irq_hw_number_t hw_irq_num)
+{
+	irq_set_chip_and_handler(virq, &sh7751irl_intc_chip, handle_level_irq);
+	irq_get_irq_data(virq)->chip_data = h->host_data;
+	irq_modify_status(virq, IRQ_NOREQUEST, IRQ_NOPROBE);
+	return 0;
+}
+
+static int sh7751irl_intc_translate(struct irq_domain *domain,
+			       struct irq_fwspec *fwspec, unsigned long *hwirq,
+			       unsigned int *type)
+{
+	if (fwspec->param[0] > NR_IRL)
+		return -EINVAL;
+
+	switch (fwspec->param_count) {
+	case 2:
+		*type = fwspec->param[1];
+		fallthrough;
+	case 1:
+		*hwirq = fwspec->param[0] + IRL_BASE_IRQ;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static const struct irq_domain_ops sh7751irl_intc_domain_ops = {
+	.map = sh7751irl_intc_map,
+	.translate = sh7751irl_intc_translate,
+};
+
+static int __init load_irl_bit(struct device_node *node, struct sh7751irl_intc_priv *priv)
+{
+	struct property *enable_map;
+	const __be32 *p;
+	u32 nr_bits, bit;
+	u32 irl;
+	int ret;
+
+	/* Fill in unused */
+	memset(priv->enable_bit, ~0, sizeof(priv->enable_bit));
+
+	enable_map = of_find_property(node, "renesas,enable-reg", &nr_bits);
+	if (IS_ERR(enable_map))
+		return PTR_ERR(enable_map);
+
+	nr_bits /= sizeof(u32);
+	if (nr_bits > priv->width)
+		return -EINVAL;
+
+	ret = nr_bits;
+	p = NULL;
+	for (bit = nr_bits; bit > 0; bit--) {
+		p = of_prop_next_u32(enable_map, p, &irl);
+		if (p == NULL || irl > NR_IRL)
+			return -EINVAL;
+		if (irl == NR_IRL)
+			/* IRL15 is unassined bit */
+			continue;
+		priv->enable_bit[irl] = bit - 1;
+	}
+	return ret;
+}
+
+static int __init sh7751irl_init(struct device_node *node, struct device_node *parent)
+{
+	struct sh7751irl_intc_priv *priv;
+	struct resource res;
+	struct irq_domain *d;
+	void __iomem *base;
+	int ret = 0;
+
+	if (of_address_to_resource(node, 0, &res))
+		return -EINVAL;
+	if (resource_size(&res) > 4)
+		return -EINVAL;
+
+	base = ioremap(res.start, resource_size(&res));
+	if (!base)
+		return -EINVAL;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->base = base;
+	priv->width = 8 << resource_size(&res);
+
+	ret = load_irl_bit(node, priv);
+	if (ret < 0) {
+		pr_err("%pOFP: Invalid register define.\n", node);
+		goto error;
+	}
+
+	d = irq_domain_add_tree(node, &sh7751irl_intc_domain_ops, priv);
+	if (d == NULL) {
+		pr_err("%pOFP: cannot initialize irq domain\n", node);
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	priv->irq_domain = d;
+	irq_domain_update_bus_token(d, DOMAIN_BUS_WIRED);
+	pr_info("%pOFP: SH7751 External Interrupt encoder (input=%d)", node, ret);
+	return 0;
+error:
+	kfree(priv);
+	return ret;
+}
+
+IRQCHIP_DECLARE(renesas_sh7751_irl, "renesas,sh7751-irl-ext", sh7751irl_init);
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [DO NOT MERGE v7 18/36] dt-bindings: interrupt-controller: renesas,sh7751-irl-ext: Add json-schema
       [not found] <cover.1712041249.git.ysato@users.sourceforge.jp>
                   ` (8 preceding siblings ...)
  2024-04-04  4:59 ` [DO NOT MERGE v7 17/36] irqchip: SH7751 external interrupt encoder with enable gate Yoshinori Sato
@ 2024-04-04  4:59 ` Yoshinori Sato
  2024-04-04  4:59 ` [DO NOT MERGE v7 19/36] serial: sh-sci: fix SH4 OF support Yoshinori Sato
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Yoshinori Sato @ 2024-04-04  4:59 UTC (permalink / raw)
  To: linux-sh; +Cc: Yoshinori Sato

Renesas SH7751 external interrupt encoder json-schema.

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 .../renesas,sh7751-irl-ext.yaml               | 57 +++++++++++++++++++
 1 file changed, 57 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/renesas,sh7751-irl-ext.yaml

diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,sh7751-irl-ext.yaml b/Documentation/devicetree/bindings/interrupt-controller/renesas,sh7751-irl-ext.yaml
new file mode 100644
index 000000000000..fc174c0467e7
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,sh7751-irl-ext.yaml
@@ -0,0 +1,57 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interrupt-controller/renesas,sh7751-irl-ext.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas SH7751 external interrupt encoder with enable regs.
+
+maintainers:
+  - Yoshinori Sato <ysato@users.sourceforge.jp>
+
+description:
+  This is the generally used external interrupt encoder on SH7751 based boards.
+
+properties:
+  compatible:
+    items:
+      - const: renesas,sh7751-irl-ext
+
+  reg: true
+
+  interrupt-controller: true
+
+  '#interrupt-cells':
+    const: 2
+
+  '#address-cells':
+    const: 0
+
+  renesas,set-to-disable:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description: Invert enable registers. Setting the bit to 0 enables interrupts.
+
+  renesas,enable-reg:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    description: |
+      IRQ enable register bit mapping
+
+required:
+  - compatible
+  - reg
+  - interrupt-controller
+  - '#interrupt-cells'
+  - renesas,enable-reg
+
+additionalProperties: false
+
+examples:
+  - |
+    r2dintc: interrupt-controller@a4000000 {
+        compatible = "renesas,sh7751-irl-ext";
+        reg = <0xa4000000 0x02>;
+        interrupt-controller;
+        #address-cells = <0>;
+        #interrupt-cells = <1>;
+        renesas,enable-reg = <12 9 10 3 0 4 1 2 8 5 6 7 15 15 15 11>;
+    };
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [DO NOT MERGE v7 19/36] serial: sh-sci: fix SH4 OF support.
       [not found] <cover.1712041249.git.ysato@users.sourceforge.jp>
                   ` (9 preceding siblings ...)
  2024-04-04  4:59 ` [DO NOT MERGE v7 18/36] dt-bindings: interrupt-controller: renesas,sh7751-irl-ext: Add json-schema Yoshinori Sato
@ 2024-04-04  4:59 ` Yoshinori Sato
  2024-04-05 13:54   ` Geert Uytterhoeven
  2024-04-04  4:59 ` [DO NOT MERGE v7 20/36] dt-bindings: serial: renesas,scif: Add scif-sh7751 Yoshinori Sato
                   ` (4 subsequent siblings)
  15 siblings, 1 reply; 17+ messages in thread
From: Yoshinori Sato @ 2024-04-04  4:59 UTC (permalink / raw)
  To: linux-sh; +Cc: Yoshinori Sato, Geert Uytterhoeven

- fix earlycon name.
- fix earlyprintk hung (NULL pointer reference).
- fix SERIAL_SH_SCI_EARLYCON enablement

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 drivers/tty/serial/Kconfig  | 2 +-
 drivers/tty/serial/sh-sci.c | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index ffcf4882b25f..dfe5fd436816 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -661,7 +661,7 @@ config SERIAL_SH_SCI_EARLYCON
 	depends on SERIAL_SH_SCI=y
 	select SERIAL_CORE_CONSOLE
 	select SERIAL_EARLYCON
-	default ARCH_RENESAS
+	default ARCH_RENESAS || SUPERH
 
 config SERIAL_SH_SCI_DMA
 	bool "DMA support" if EXPERT
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index e512eaa57ed5..46466fb5a637 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -2717,7 +2717,7 @@ static int sci_remap_port(struct uart_port *port)
 	if (port->membase)
 		return 0;
 
-	if (port->dev->of_node || (port->flags & UPF_IOREMAP)) {
+	if ((port->dev && port->dev->of_node) || (port->flags & UPF_IOREMAP)) {
 		port->membase = ioremap(port->mapbase, sport->reg_size);
 		if (unlikely(!port->membase)) {
 			dev_err(port->dev, "can't remap port#%d\n", port->line);
@@ -3545,8 +3545,8 @@ static int __init hscif_early_console_setup(struct earlycon_device *device,
 
 OF_EARLYCON_DECLARE(sci, "renesas,sci", sci_early_console_setup);
 OF_EARLYCON_DECLARE(scif, "renesas,scif", scif_early_console_setup);
-OF_EARLYCON_DECLARE(scif, "renesas,scif-r7s9210", rzscifa_early_console_setup);
-OF_EARLYCON_DECLARE(scif, "renesas,scif-r9a07g044", rzscifa_early_console_setup);
+OF_EARLYCON_DECLARE(rzscifa, "renesas,scif-r7s9210", rzscifa_early_console_setup);
+OF_EARLYCON_DECLARE(rzscifa, "renesas,scif-r9a07g044", rzscifa_early_console_setup);
 OF_EARLYCON_DECLARE(scifa, "renesas,scifa", scifa_early_console_setup);
 OF_EARLYCON_DECLARE(scifb, "renesas,scifb", scifb_early_console_setup);
 OF_EARLYCON_DECLARE(hscif, "renesas,hscif", hscif_early_console_setup);
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [DO NOT MERGE v7 20/36] dt-bindings: serial: renesas,scif: Add scif-sh7751.
       [not found] <cover.1712041249.git.ysato@users.sourceforge.jp>
                   ` (10 preceding siblings ...)
  2024-04-04  4:59 ` [DO NOT MERGE v7 19/36] serial: sh-sci: fix SH4 OF support Yoshinori Sato
@ 2024-04-04  4:59 ` Yoshinori Sato
  2024-04-04  4:59 ` [DO NOT MERGE v7 21/36] dt-bindings: display: smi,sm501: SMI SM501 binding json-schema Yoshinori Sato
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Yoshinori Sato @ 2024-04-04  4:59 UTC (permalink / raw)
  To: linux-sh; +Cc: Yoshinori Sato, Geert Uytterhoeven

Add Renesas SH7751 SCIF.

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 Documentation/devicetree/bindings/serial/renesas,scif.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/serial/renesas,scif.yaml b/Documentation/devicetree/bindings/serial/renesas,scif.yaml
index 4610a5bd580c..590f88e2ced9 100644
--- a/Documentation/devicetree/bindings/serial/renesas,scif.yaml
+++ b/Documentation/devicetree/bindings/serial/renesas,scif.yaml
@@ -18,6 +18,7 @@ properties:
       - items:
           - enum:
               - renesas,scif-r7s72100     # RZ/A1H
+              - renesas,scif-sh7751       # SH7751
           - const: renesas,scif           # generic SCIF compatible UART
 
       - items:
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [DO NOT MERGE v7 21/36] dt-bindings: display: smi,sm501: SMI SM501 binding json-schema
       [not found] <cover.1712041249.git.ysato@users.sourceforge.jp>
                   ` (11 preceding siblings ...)
  2024-04-04  4:59 ` [DO NOT MERGE v7 20/36] dt-bindings: serial: renesas,scif: Add scif-sh7751 Yoshinori Sato
@ 2024-04-04  4:59 ` Yoshinori Sato
  2024-04-04  5:00 ` [DO NOT MERGE v7 22/36] dt-bindings: display: sm501 register definition helper Yoshinori Sato
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Yoshinori Sato @ 2024-04-04  4:59 UTC (permalink / raw)
  To: linux-sh; +Cc: Yoshinori Sato

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 .../bindings/display/smi,sm501.yaml           | 398 ++++++++++++++++++
 1 file changed, 398 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/smi,sm501.yaml

diff --git a/Documentation/devicetree/bindings/display/smi,sm501.yaml b/Documentation/devicetree/bindings/display/smi,sm501.yaml
new file mode 100644
index 000000000000..06c6af4fa4a9
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/smi,sm501.yaml
@@ -0,0 +1,398 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/smi,sm501.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Silicon Motion SM501 Mobile Multimedia Companion Chip
+
+maintainers:
+  - Yoshinori Sato <ysato@user.sourceforge.jp>
+
+description: |
+  These DT bindings describe the SM501.
+
+properties:
+  compatible:
+    const:
+      smi,sm501
+
+  reg:
+    maxItems: 2
+    description: |
+     First entry: System Configuration register
+     Second entry: IO space (Display Controller register)
+
+  interrupts:
+    description: SM501 interrupt to the cpu should be described here.
+
+  mode:
+    $ref: /schemas/types.yaml#/definitions/string
+    description: select a video mode
+
+  edid:
+    description: |
+      verbatim EDID data block describing attached display.
+      Data from the detailed timing descriptor will be used to
+      program the display controller.
+
+  little-endian:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description: available on big endian systems, to set different foreign endian.
+  big-endian:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description: available on little endian systems, to set different foreign endian.
+
+  swap-fb-endian:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description: swap framebuffer byteorder.
+
+  route-crt-panel:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description: Panel output merge to CRT.
+
+  crt:
+    type: object
+    description: CRT output control
+    properties:
+      edid:
+        $ref: /schemas/types.yaml#/definitions/uint8-array
+        description: |
+          verbatim EDID data block describing attached display.
+          Data from the detailed timing descriptor will be used to
+          program the display controller.
+
+      smi,flags:
+        $ref: /schemas/types.yaml#/definitions/string-array
+        description: Display control flags.
+        items:
+          anyOf:
+            - const: use-init-done
+            - const: disable-at-exit
+            - const: use-hwcursor
+            - const: use-hwaccel
+            - const: panel-no-fpen
+            - const: panel-no-vbiasen
+            - const: panel-inv-fpen
+            - const: panel-inv-vbiasen
+        maxItems: 8
+
+      bpp:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        description: Color depth
+
+  panel:
+    type: object
+    description: Panel output control
+    properties:
+      edid:
+        $ref: /schemas/types.yaml#/definitions/uint8-array
+        description: |
+          verbatim EDID data block describing attached display.
+          Data from the detailed timing descriptor will be used to
+          program the display controller.
+
+      smi,flags:
+        $ref: /schemas/types.yaml#/definitions/string-array
+        description: Display control flags.
+        items:
+          anyOf:
+            - const: use-init-done
+            - const: disable-at-exit
+            - const: use-hwcursor
+            - const: use-hwaccel
+            - const: panel-no-fpen
+            - const: panel-no-vbiasen
+            - const: panel-inv-fpen
+            - const: panel-inv-vbiasen
+        maxItems: 8
+
+      bpp:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        description: Color depth
+
+  smi,devices:
+    $ref: /schemas/types.yaml#/definitions/string-array
+    description: Select SM501 device functions.
+    items:
+      anyOf:
+        - const: usb-host
+        - const: usb-slave
+        - const: ssp0
+        - const: ssp1
+        - const: uart0
+        - const: uart1
+        - const: fbaccel
+        - const: ac97
+        - const: i2s
+        - const: gpio
+    minItems: 1
+    maxItems: 10
+
+  smi,mclk:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: mclk frequency.
+
+  smi,m1xclk:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: m1xclk frequency.
+
+  misc-timing:
+    type: object
+    description: Miscellaneous Timing register values.
+    properties:
+      ex:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        description: Extend bus holding time.
+
+      xc:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        description: Xscale clock input select.
+
+      usb-over-current-detect-disable:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: USB host current detection disable (Us=0).
+
+      usb-over-current-detect-enable:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: USB host current detection disable (Us=1).
+
+      sdram-clock-mode1-288mhz:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: SSM1 bit is clear.
+
+      sdram-clock-mode1-div:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: SSM1 bit is set.
+
+      sm1:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: SDRAM clock divider for PW mode 1.
+
+      sdram-clock-mode0-288mhz:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: SSM0 bit is clear.
+
+      sdram-clock-mode0-div:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: SSM0 bit is set.
+
+      sm0:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        description: SDRAM clock divider for PW mode 0.
+
+      pll-debug-input:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: 96MHz PLL debug input reference frequency (Deb=0).
+
+      pll-debug-output:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: 96MHz PLL debug output frequency (Deb=1).
+
+      no-acpi-control:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: No ACPI control (A=0).
+
+      acpi-control:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: No ACPI control (A=1).
+
+      divider:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        description: Second PLL output frequency.
+
+      usb-host-normal:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: USB Host normal mode.
+
+      usb-host-simulation:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: USB Host simulation mode.
+
+      delay:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        description: Delay time to latch read data. Set the value to 10x.
+
+  misc-control:
+    type: object
+    description: Miscellaneous Control register values.
+    properties:
+      pad:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        description: PCI Pad drive strength.
+
+      usbclk:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        description: USB Clcok Select.
+
+      uart1:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: UART1 (SSP=0)
+
+      ssp1:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: SSP1 (SSP=1)
+
+      latch-address-disable:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: 8051 Latch disable (Lat=0).
+
+      latch-address-enable:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: 8051 Latch enable (Lat=1).
+
+      panel-data-18bit:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: Flat Panel data 18bit (FP=0).
+
+      panel-data-24bit:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: Flat Panel data 24bit (FP=1).
+
+      xtal-freq-24mhz:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: Crystal frequency 24MHz (Freq=0).
+
+      xtal-freq-12mhz:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: Crystal frequency 12MHz (Freq=1).
+
+      refresh:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        description: Internal memory refresh timing.
+
+      hold:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        description: BUS Hold time.
+
+      sh-ready-low:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: SuperH ready polarity active low (SH=0).
+
+      sh-ready-high:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: SuperH ready polarity active high (SH=1).
+
+      interrupt-normal:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: Interrupt normal (II=0).
+
+      interrupt-inverted:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: Interrupt Inverting (II=1).
+
+      pll-clock-count-disable:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: PLL clock count disable.
+
+      pll-clock-count-enaable:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: PLL clock count enable.
+
+      dac-power-enable:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: DAC Power enable (DAC=0).
+
+      dac-power-disable:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: DAC Power disable (DAC=1).
+
+      usb-slave-cpu:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: USB slave controller cpu (MC=0).
+
+      usb-slave-8051:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: USB slave controller 8051MCU (MC=1).
+
+      burst-length-8:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: CPU Master burst length 8 (BL=0).
+
+      burst-length-1:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: CPU Master burst length 1 (BL=1).
+
+      usb-port-master:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: USB port master.
+
+      usb-port-slave:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: USB port slave.
+
+      vr-mmio-30mb:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: NEC VR Memory map MMIO locatedat 30MB (VR=0)
+
+      vr-mmio-62mb:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: NEC VR Memory map MMIO locatedat 62MB (VR=1)
+
+  gpio-pin-control:
+    type: object
+    description: GPIO control configuration.
+    properties:
+      pin:
+        type: object
+        properties:
+          gpio:
+            $ref: /schemas/types.yaml#/definitions/flag
+            description: pin in/out use GPIO.
+          function:
+            $ref: /schemas/types.yaml#/definitions/flag
+            description: pin in/out use function.
+
+  gpio-i2c:
+    type: object
+    description: GPIO I2C definition.
+    properties:
+      i2c:
+        type: object
+        properties:
+          bus:
+            $ref: /schemas/types.yaml#/definitions/uint32
+            description: I2C bus number.
+
+          sda:
+            $ref: /schemas/types.yaml#/definitions/uint32
+            description: I2C SDA pin port number.
+
+          scl:
+            $ref: /schemas/types.yaml#/definitions/uint32
+            description: I2C SCL pin port number.
+
+          delay:
+            $ref: /schemas/types.yaml#/definitions/uint32
+            description: bit transmission delay.
+
+          timeout:
+            $ref: /schemas/types.yaml#/definitions/uint32
+            description: transmission timeout.
+
+additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+
+examples:
+  # MPC5200
+  - |
+    display@1,0 {
+        compatible = "smi,sm501";
+        reg = <0x00000000 0x00800000
+               0x03e00000 0x00200000>;
+        interrupts = <1 1 3>;
+        mode = "640x480-32@60";
+        edid = [00 ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00
+                00 00 01 04 00 00 00 00 00 00 00 00 00 00 00 00
+                00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+                00 00 00 00 00 00 f0 0a 80 fb 20 e0 25 10 32 60
+                02 00 00 00 00 00 00 06 00 00 00 00 00 00 00 00
+                00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+                00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+                00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 bd];
+    };
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [DO NOT MERGE v7 22/36] dt-bindings: display: sm501 register definition helper
       [not found] <cover.1712041249.git.ysato@users.sourceforge.jp>
                   ` (12 preceding siblings ...)
  2024-04-04  4:59 ` [DO NOT MERGE v7 21/36] dt-bindings: display: smi,sm501: SMI SM501 binding json-schema Yoshinori Sato
@ 2024-04-04  5:00 ` Yoshinori Sato
  2024-04-04  5:00 ` [DO NOT MERGE v7 23/36] mfd: sm501: Convert platform_data to OF property Yoshinori Sato
  2024-04-04  5:00 ` [DO NOT MERGE v7 24/36] dt-binding: sh: cpus: Add SH CPUs json-schema Yoshinori Sato
  15 siblings, 0 replies; 17+ messages in thread
From: Yoshinori Sato @ 2024-04-04  5:00 UTC (permalink / raw)
  To: linux-sh; +Cc: Yoshinori Sato

Miscellaneous Timing and Miscellaneous Control registers definition.

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 include/dt-bindings/display/sm501.h | 76 +++++++++++++++++++++++++++++
 1 file changed, 76 insertions(+)
 create mode 100644 include/dt-bindings/display/sm501.h

diff --git a/include/dt-bindings/display/sm501.h b/include/dt-bindings/display/sm501.h
new file mode 100644
index 000000000000..a6c6943642e4
--- /dev/null
+++ b/include/dt-bindings/display/sm501.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
+#ifndef __DT_BINDING_DISPALY_SM501__
+#define __DT_BINDING_DISPALY_SM501__
+
+/* Miscellaneous Conntrol */
+#define SM501_MISC_CONTROL_PAD_24	0
+#define SM501_MISC_CONTROL_PAD_12	1
+#define SM501_MISC_CONTROL_PAD_8	2
+
+#define SM501_MISC_CONTROL_USBCLK_XTAL	0
+#define SM501_MISC_CONTROL_USBCLK_96MHZ	1
+#define SM501_MISC_CONTROL_USBCLK_48MHZ	2
+
+#define SM501_MISC_CONTROL_RFSH_8US	0
+#define SM501_MISC_CONTROL_RFSH_16US	1
+#define SM501_MISC_CONTROL_RFSH_32US	2
+#define SM501_MISC_CONTROL_RFSH_64US	3
+
+#define SM501_MISC_CONTROL_HOLD_EMPTY	0
+#define SM501_MISC_CONTROL_HOLD_8TR	1
+#define SM501_MISC_CONTROL_HOLD_16TR	2
+#define SM501_MISC_CONTROL_HOLD_24TR	3
+#define SM501_MISC_CONTROL_HOLD_32TR	4
+
+/* Miscellaneous timing */
+#define SM501_MISC_TIMING_EX_HOLD_0	0
+#define SM501_MISC_TIMING_EX_HOLD_16	1
+#define SM501_MISC_TIMING_EX_HOLD_32	2
+#define SM501_MISC_TIMING_EX_HOLD_48	3
+#define SM501_MISC_TIMING_EX_HOLD_64	4
+#define SM501_MISC_TIMING_EX_HOLD_80	5
+#define SM501_MISC_TIMING_EX_HOLD_96	6
+#define SM501_MISC_TIMING_EX_HOLD_112	7
+#define SM501_MISC_TIMING_EX_HOLD_128	8
+#define SM501_MISC_TIMING_EX_HOLD_144	9
+#define SM501_MISC_TIMING_EX_HOLD_160	10
+#define SM501_MISC_TIMING_EX_HOLD_176	11
+#define SM501_MISC_TIMING_EX_HOLD_192	12
+#define SM501_MISC_TIMING_EX_HOLD_208	13
+#define SM501_MISC_TIMING_EX_HOLD_224	14
+#define SM501_MISC_TIMING_EX_HOLD_240	15
+
+#define SM501_MISC_TIMING_XC_INTERNAL	0
+#define SM501_MISC_TIMING_XC_HCLK	1
+#define SM501_MISC_TIMING_XC_GPIO	2
+
+#define SM501_MISC_TIMING_SM_DIV1	0
+#define SM501_MISC_TIMING_SM_DIV2	1
+#define SM501_MISC_TIMING_SM_DIV4	2
+#define SM501_MISC_TIMING_SM_DIV8	3
+#define SM501_MISC_TIMING_SM_DIV16	4
+#define SM501_MISC_TIMING_SM_DIV32	5
+#define SM501_MISC_TIMING_SM_DIV64	6
+#define SM501_MISC_TIMING_SM_DIV128	7
+#define SM501_MISC_TIMING_SM_DIV3	8
+#define SM501_MISC_TIMING_SM_DIV6	9
+#define SM501_MISC_TIMING_SM_DIV12	10
+#define SM501_MISC_TIMING_SM_DIV24	11
+#define SM501_MISC_TIMING_SM_DIV48	12
+#define SM501_MISC_TIMING_SM_DIV96	13
+#define SM501_MISC_TIMING_SM_DIV192	14
+#define SM501_MISC_TIMING_SM_DIV384	15
+
+#define SM501_MISC_TIMING_DIV336MHZ	0
+#define SM501_MISC_TIMING_DIV288MHZ	1
+#define SM501_MISC_TIMING_DIV240MHZ	2
+#define SM501_MISC_TIMING_DIV192MHZ	3
+
+#define SM501_MISC_TIMING_DELAY_NONE	0
+#define SM501_MISC_TIMING_DELAY_0_5	1
+#define SM501_MISC_TIMING_DELAY_1_0	2
+#define SM501_MISC_TIMING_DELAY_1_5	3
+#define SM501_MISC_TIMING_DELAY_2_0	4
+#define SM501_MISC_TIMING_DELAY_2_5	5
+
+#endif
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [DO NOT MERGE v7 23/36] mfd: sm501: Convert platform_data to OF property
       [not found] <cover.1712041249.git.ysato@users.sourceforge.jp>
                   ` (13 preceding siblings ...)
  2024-04-04  5:00 ` [DO NOT MERGE v7 22/36] dt-bindings: display: sm501 register definition helper Yoshinori Sato
@ 2024-04-04  5:00 ` Yoshinori Sato
  2024-04-04  5:00 ` [DO NOT MERGE v7 24/36] dt-binding: sh: cpus: Add SH CPUs json-schema Yoshinori Sato
  15 siblings, 0 replies; 17+ messages in thread
From: Yoshinori Sato @ 2024-04-04  5:00 UTC (permalink / raw)
  To: linux-sh; +Cc: Yoshinori Sato

Various parameters of SM501 can be set using platform_data,
so parameters cannot be passed in the DeviceTree target.
Expands the parameters set in platform_data so that they can be
specified using DeviceTree properties.

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 drivers/mfd/sm501.c           | 315 ++++++++++++++++++++++++++++++++++
 drivers/video/fbdev/sm501fb.c | 106 ++++++++++++
 2 files changed, 421 insertions(+)

diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
index b3592982a83b..98a69e254f5f 100644
--- a/drivers/mfd/sm501.c
+++ b/drivers/mfd/sm501.c
@@ -82,6 +82,16 @@ struct sm501_devdata {
 	unsigned int			 rev;
 };
 
+struct sm501_config_props_uint {
+	char *name;
+	u32 shift;
+};
+
+struct sm501_config_props_flag {
+	char *clr_name;
+	char *set_name;
+	u32 bit;
+};
 
 #define MHZ (1000 * 1000)
 
@@ -1370,6 +1380,305 @@ static int sm501_init_dev(struct sm501_devdata *sm)
 	return 0;
 }
 
+static const struct sm501_config_props_uint misc_timing[] = {
+	{"delay",    0},
+	{"-",        3},
+	{"divider",  4},
+	{"-",        6},
+	{"sm0",      8},
+	{"-",       12},
+	{"sm1",     16},
+	{"-",       20},
+	{"xc",      24},
+	{"-",       26},
+	{"ex",      28},
+	{NULL,      32},
+};
+
+static const struct sm501_config_props_flag misc_timing_flag[] = {
+	{"usb-host-normal",          "usb-host-simulation",    3},
+	{"no-acpi-control",          "acpi-control",           6},
+	{"pll-debug-input",          "pll-debug-output",       7},
+	{"sdram-clock-mode0-288mhz", "sdram-clock-mode0-div", 12},
+	{"sdram-clock-mode1-288mhz", "sdram-clock-mode1-div", 20},
+	{"usb-over-current-detect-disable",
+	 "usb-over-current-detect-enable",  23},
+	{},
+};
+
+static const struct sm501_config_props_uint misc_control[] = {
+	{"hold",     18},
+	{"refresh",  21},
+	{"-",        23},
+	{"usbclk",   28},
+	{"pad",      30},
+	{NULL,       32},
+};
+
+static const struct sm501_config_props_flag misc_control_flag[] = {
+	{"vr-mmio-30mb",            "vr-mmio-62mb",             4},
+	{"usb-port-master",         "usb-port-slave",           9},
+	{"burst-length-8",          "burst-length-1",          10},
+	{"usb-slave-cpu",           "usb-slave-8051",          11},
+	{"dac-power-enable",        "dac-power-disable",       12},
+	{"pll-clock-count-disable", "pll-clock-count-enable",  15},
+	{"interrupt-normal",        "interrupt-invarted",      16},
+	{"sh-ready-low",            "sh-ready-high",           17},
+	{"xtal-freq-24mhz",         "xtal-freq-12mhz",         24},
+	{"panel-data-18bit",        "panel-dtat-24bit",        25},
+	{"latch-address-disable",   "latch-address-enable",    26},
+	{"uart1",                   "ssp1",                    27},
+	{},
+};
+
+/* Read configuration values */
+static void sm501_of_read_config(struct device *dev, struct device_node *np,
+				 const char *prefix,
+				 const struct sm501_config_props_uint *props,
+				 const struct sm501_config_props_flag *props_flag,
+				 struct sm501_reg_init *ret)
+{
+	struct device_node *child;
+	char *name;
+	u32 shift;
+	u32 width;
+	u32 mask;
+	u32 val;
+
+	ret->mask = ~0;
+	ret->set = 0;
+
+	child = of_get_child_by_name(np, prefix);
+	if (!child)
+		return;
+
+	while (props->name) {
+		name = props->name;
+		shift = props->shift;
+		props++;
+
+		if (name[0] == '-' ||
+		    of_property_read_u32(child, name, &val))
+			continue;
+
+		width = props->shift - shift;
+		mask = (1 << width) - 1;
+		if (mask < val) {
+			dev_warn(dev, "%s invalid value %d", name, val);
+			continue;
+		}
+		mask = ~(mask << shift);
+		ret->mask &= mask;
+		ret->set |= val << shift;
+	}
+	while (props_flag->clr_name) {
+		val = ~0;
+		if (of_property_read_bool(child, props_flag->clr_name))
+			val = 0;
+		else if (of_property_read_bool(child, props_flag->set_name))
+			val = 1;
+		if (val != ~0) {
+			val <<= (props_flag->bit & 31);
+			mask = 1 << (props_flag->bit & 31);
+			ret->mask &= ~mask;
+			ret->set |= val;
+		}
+		props_flag++;
+	}
+}
+
+/* Read GPIO control */
+/*
+ * DT example.
+ * gpio-pin-control {
+ *   pin@0 {
+ *	 gpio-port;
+ *   };
+ *   pin@1 {
+ *	 function;
+ *   };
+ * };
+ */
+static void sm501_of_read_gpio(struct device *dev, struct device_node *np,
+			       struct sm501_reg_init *hi, struct sm501_reg_init *low)
+{
+	struct device_node *gpio_group, *pin;
+	const char *prop_mode;
+	unsigned int pin_no;
+	int mode;
+	u64 mask;
+	u64 set;
+
+	mask = ~0;
+	set = 0;
+	gpio_group = of_get_child_by_name(np, "gpio-pin-control");
+	if (gpio_group) {
+		for_each_child_of_node(gpio_group, pin) {
+			mode = -1;
+			if (sscanf(pin->full_name, "pin@%u", &pin_no) == 1) {
+				if (of_property_read_bool(pin, "gpio-port"))
+					mode = 0;
+				else if (of_property_read_bool(pin, "function"))
+					mode = 1;
+			}
+			/* GPIO0 - 47 and 55 -63 */
+			if (mode < 0 ||
+			    (pin_no >= 64 || (pin_no >= 48 && pin_no <= 54))) {
+				dev_warn(dev,
+					 "%s mode %s is invalid.", pin->name, prop_mode);
+			} else {
+				mask &= ~(1 << pin_no);
+				set |= mode << pin_no;
+			}
+		}
+	}
+	hi->set = set >> 32;
+	low->set = set & 0xffffffff;
+	hi->mask = mask >> 32;
+	low->mask = mask & 0xffffffff;
+}
+
+static inline int read_i2c_prop(struct device *dev, struct device_node *child,
+				const char *name, u32 *val)
+{
+	if (of_property_read_u32(child, name, val)) {
+		dev_warn(dev, "%s/%s not found. skip it.", of_node_full_name(child), name);
+		return -ENOENT;
+	}
+	return 0;
+}
+
+/* Read GPIO I2C configuration */
+/*
+ * DT example.
+ * gpio-i2c {
+ *    i2c@0 {
+ *	sda = <gpio-pin>;
+ *	scl = <gpio-pin>;
+ *	delay = <delay>;
+ *	timeout = <timeout>;
+ *    };
+ *    i2c@1 {
+ *      :
+ *    };
+ *    :
+ * };
+ */
+static int sm501_parse_dt_gpio_i2c(struct device *dev, struct sm501_platdata *plat,
+				   struct device_node *np)
+{
+	struct device_node *i2c_group, *child;
+	unsigned int i;
+	u32 i2c_nr;
+	int err;
+
+	i2c_group = of_get_child_by_name(np, "gpio-i2c");
+	if (!i2c_group)
+		return 0;
+
+	i2c_nr = of_get_child_count(i2c_group);
+	plat->gpio_i2c = devm_kzalloc(dev, sizeof(*plat->gpio_i2c) * i2c_nr,
+				      GFP_KERNEL);
+	if (!plat->gpio_i2c)
+		return -ENOMEM;
+
+	plat->gpio_i2c_nr = i2c_nr;
+	i = 0;
+	for_each_child_of_node(i2c_group, child) {
+		u32 bus;
+
+		if (sscanf(child->full_name, "i2c@%u", &bus) != 1) {
+			dev_warn(dev, "Unknown address %s\n", child->name);
+			continue;
+		}
+
+		err = 0;
+		plat->gpio_i2c[i].bus_num = bus;
+		err += read_i2c_prop(dev, child, "sda", &plat->gpio_i2c[i].pin_sda);
+		err += read_i2c_prop(dev, child, "scl", &plat->gpio_i2c[i].pin_scl);
+		err += read_i2c_prop(dev, child, "delay", &plat->gpio_i2c[i].udelay);
+		err += read_i2c_prop(dev, child, "timeout", &plat->gpio_i2c[i].timeout);
+		if (err == 0)
+			i++;
+	}
+
+	return 0;
+}
+
+/* Read device functions */
+static u32 sm501_read_devices(struct device *dev, struct device_node *np)
+{
+	static const char * const funcname[] = {
+		"usb-host", "usb-slave", "ssp0", "ssp1",
+		"uart0", "uart1", "fbaccel", "ac97",
+		"i2s", "gpio",
+	};
+	struct property *prop;
+	unsigned int i;
+	const char *s;
+	u32 ret = 0;
+
+	of_property_for_each_string(np, "smi,devices", prop, s) {
+		for (i = 0; i < ARRAY_SIZE(funcname); i++) {
+			if (strcmp(s, funcname[i]) == 0) {
+				ret |= 1 << i;
+				goto next;
+			}
+		}
+		dev_warn(dev, "Unknown device function '%s'", s);
+next:
+	}
+	if (!ret)
+		dev_warn(dev, "devices not defined. disable all functions.");
+	return ret;
+}
+
+/* Build platform_data from OF property */
+struct plat_dt {
+	struct sm501_platdata plat;
+	struct sm501_initdata init;
+};
+
+static int sm501_parse_dt(struct sm501_devdata *sm, struct device_node *np)
+{
+	struct sm501_platdata *plat;
+	struct plat_dt *dt_p;
+	u32 word;
+	int ret;
+
+	dt_p = devm_kzalloc(sm->dev, sizeof(*dt_p), GFP_KERNEL);
+	if (!dt_p)
+		return -ENOMEM;
+
+	plat = &dt_p->plat;
+	plat->init = &dt_p->init;
+
+	plat->init->devices = sm501_read_devices(sm->dev, np);
+	/* mclk and m1xclk are not u32, so convert between them using intermediate variables. */
+	of_property_read_u32(np, "smi,mclk", &word);
+	plat->init->mclk = word;
+	of_property_read_u32(np, "smi,m1xclk", &word);
+	plat->init->m1xclk = word;
+
+	sm501_of_read_config(sm->dev, np, "misc-timing",
+			     misc_timing, misc_timing_flag,
+			     &plat->init->misc_timing);
+	sm501_of_read_config(sm->dev, np, "misc-control",
+			     misc_control, misc_control_flag,
+			     &plat->init->misc_control);
+	sm501_of_read_gpio(sm->dev, np,
+			   &plat->init->gpio_high, &plat->init->gpio_low);
+
+	if (IS_ENABLED(CONFIG_MFD_SM501_GPIO) &&
+	    (plat->init->devices & SM501_USE_GPIO)) {
+		ret = sm501_parse_dt_gpio_i2c(sm->dev, plat, np);
+		if (ret)
+			return ret;
+	}
+	sm->platdata = plat;
+	return 0;
+}
+
 static int sm501_plat_probe(struct platform_device *dev)
 {
 	struct sm501_devdata *sm;
@@ -1406,6 +1715,12 @@ static int sm501_plat_probe(struct platform_device *dev)
 		goto err_res;
 	}
 
+	if (IS_ENABLED(CONFIG_OF) && dev->dev.of_node) {
+		ret = sm501_parse_dt(sm, dev->dev.of_node);
+		if (ret)
+			goto err_res;
+	}
+
 	platform_set_drvdata(dev, sm);
 
 	sm->regs = ioremap(sm->io_res->start, resource_size(sm->io_res));
diff --git a/drivers/video/fbdev/sm501fb.c b/drivers/video/fbdev/sm501fb.c
index d6fdc1737cd2..5de00f2570aa 100644
--- a/drivers/video/fbdev/sm501fb.c
+++ b/drivers/video/fbdev/sm501fb.c
@@ -1932,6 +1932,106 @@ static int sm501fb_start_one(struct sm501fb_info *info,
 	return 0;
 }
 
+#if defined(CONFIG_OF)
+static u32 read_display_flags(struct device_node *np)
+{
+	static const char * const name[] = {
+		"use-init-done", "disable-at-exit", "use-hwcursor", "use-hwaccel",
+		"panel-no-fpen", "panel-no-vbiasen", "panel-inv-fpen", "panel-inv-vbiasen",
+	};
+
+	struct property *prop;
+	unsigned int i;
+	const char *s;
+	u32 ret = 0;
+
+	of_property_for_each_string(np, "smi,flags", prop, s) {
+		for (i = 0; i < ARRAY_SIZE(name); i++) {
+			if (strcmp(s, name[i]) == 0) {
+				ret |= 1 << i;
+				break;
+			}
+		}
+	}
+	return ret;
+}
+
+/* parse CRT / panel configuration */
+static struct sm501_platdata_fbsub *dt_fbsub(struct device *dev,
+					     struct device_node *np,
+					     const char *name)
+{
+	struct sm501_platdata_fbsub *fbsub = NULL;
+	struct fb_videomode *def_mode = NULL;
+	struct device_node *child;
+	const void *p_edid;
+	u32 flags = 0;
+	u32 bpp = 0;
+	int len;
+
+	child = of_get_child_by_name(np, name);
+	if (child == NULL)
+		return NULL;
+
+	p_edid = of_get_property(child, "edid", &len);
+	if (p_edid && len == EDID_LENGTH) {
+		struct fb_monspecs *specs;
+		u8 *edid;
+
+		edid = kmemdup(p_edid, EDID_LENGTH, GFP_KERNEL);
+		if (edid) {
+			specs = kzalloc(sizeof(*specs), GFP_KERNEL);
+			if (specs) {
+				fb_edid_to_monspecs(edid, specs);
+				def_mode = specs->modedb;
+			}
+		}
+		kfree(edid);
+	}
+
+	of_property_read_u32(child, "bpp", &bpp);
+
+	/* If flags property is obtained, fbsub is returned. */
+	flags = read_display_flags(child);
+	if (flags) {
+		fbsub = devm_kzalloc(dev, sizeof(*fbsub), GFP_KERNEL);
+		if (fbsub) {
+			fbsub->def_mode = def_mode;
+			fbsub->def_bpp = bpp;
+			fbsub->flags = flags;
+		}
+	}
+	return fbsub;
+}
+
+/* Build platform_data from OF property */
+static struct sm501_platdata_fb *pdata_from_dt(struct device *dev, struct device_node *np)
+{
+	enum sm501_fb_routing fb_route = SM501_FB_OWN;
+	struct sm501_platdata_fb *pdata = NULL;
+	struct sm501_platdata_fbsub *fb_crt;
+	struct sm501_platdata_fbsub *fb_pnl;
+	unsigned int flags = 0;
+
+	if (of_property_read_bool(np, "route-crt-panel"))
+		fb_route = SM501_FB_CRT_PANEL;
+	if (of_property_read_bool(np, "swap-fb-endian"))
+		flags = SM501_FBPD_SWAP_FB_ENDIAN;
+	fb_crt = dt_fbsub(dev, np, "crt");
+	fb_pnl = dt_fbsub(dev, np, "panel");
+	if (fb_crt || fb_pnl) {
+		pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+		if (pdata) {
+			pdata->fb_route = fb_route;
+			pdata->flags = flags;
+			pdata->fb_crt = fb_crt;
+			pdata->fb_pnl = fb_pnl;
+		}
+	}
+	return pdata;
+}
+#endif
+
 static int sm501fb_probe(struct platform_device *pdev)
 {
 	struct sm501fb_info *info;
@@ -1974,6 +2074,12 @@ static int sm501fb_probe(struct platform_device *pdev)
 				if (info->edid_data)
 					found = 1;
 			}
+			/* Get platform data compatible configuration */
+			if (!found) {
+				info->pdata = pdata_from_dt(dev, np);
+				if (info->pdata)
+					found = 1;
+			}
 		}
 #endif
 		if (!found) {
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [DO NOT MERGE v7 24/36] dt-binding: sh: cpus: Add SH CPUs json-schema
       [not found] <cover.1712041249.git.ysato@users.sourceforge.jp>
                   ` (14 preceding siblings ...)
  2024-04-04  5:00 ` [DO NOT MERGE v7 23/36] mfd: sm501: Convert platform_data to OF property Yoshinori Sato
@ 2024-04-04  5:00 ` Yoshinori Sato
  15 siblings, 0 replies; 17+ messages in thread
From: Yoshinori Sato @ 2024-04-04  5:00 UTC (permalink / raw)
  To: linux-sh; +Cc: Yoshinori Sato

Renesas SH series and compatible ISA CPUs.

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 .../devicetree/bindings/sh/cpus.yaml          | 61 +++++++++++++++++++
 1 file changed, 61 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sh/cpus.yaml

diff --git a/Documentation/devicetree/bindings/sh/cpus.yaml b/Documentation/devicetree/bindings/sh/cpus.yaml
new file mode 100644
index 000000000000..43e079b8753d
--- /dev/null
+++ b/Documentation/devicetree/bindings/sh/cpus.yaml
@@ -0,0 +1,61 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sh/cpus.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas SuperH CPUs
+
+maintainers:
+  - Yoshinori Sato <ysato@users.sourceforge.jp>
+
+description: |+
+  Definition of CPU core with Renesas SuperH and compatible instruction set.
+
+properties:
+  compatible:
+    anyOf:
+      - items:
+          - enum:
+              - renesas,sh2a
+              - renesas,sh3
+              - renesas,sh4
+              - renesas,sh4a
+              - jcore,j2
+          - const: renesas,sh2
+      - const: renesas,sh2
+
+  clocks:
+    maxItems: 1
+
+  reg:
+    maxItems: 1
+
+  device_type: true
+
+required:
+  - compatible
+  - reg
+  - device_type
+
+
+examples:
+  - |
+    #include <dt-bindings/clock/sh7750-cpg.h>
+    cpus {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        cpu: cpu@0 {
+            compatible = "renesas,sh4", "renesas,sh2";
+            device_type = "cpu";
+            reg = <0>;
+            clocks = <&cpg SH7750_CPG_ICK>;
+            clock-names = "ick";
+            icache-size = <16384>;
+            icache-line-size = <32>;
+            dcache-size = <32768>;
+            dcache-line-size = <32>;
+        };
+    };
+...
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [DO NOT MERGE v7 19/36] serial: sh-sci: fix SH4 OF support.
  2024-04-04  4:59 ` [DO NOT MERGE v7 19/36] serial: sh-sci: fix SH4 OF support Yoshinori Sato
@ 2024-04-05 13:54   ` Geert Uytterhoeven
  0 siblings, 0 replies; 17+ messages in thread
From: Geert Uytterhoeven @ 2024-04-05 13:54 UTC (permalink / raw)
  To: Yoshinori Sato; +Cc: linux-sh, Geert Uytterhoeven

Hi Sato-san,

Thanks for the update!

On Thu, Apr 4, 2024 at 7:01 AM Yoshinori Sato
<ysato@users.sourceforge.jp> wrote:
> - fix earlycon name.

Might be wise to explain what was wrong with it...

    (because else "scif" will invoke rzscifa_early_console_setup()
     on non-DT platforms)

> - fix earlyprintk hung (NULL pointer reference).
> - fix SERIAL_SH_SCI_EARLYCON enablement
>
> Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>

> --- a/drivers/tty/serial/sh-sci.c
> +++ b/drivers/tty/serial/sh-sci.c
> @@ -2717,7 +2717,7 @@ static int sci_remap_port(struct uart_port *port)
>         if (port->membase)
>                 return 0;
>
> -       if (port->dev->of_node || (port->flags & UPF_IOREMAP)) {
> +       if ((port->dev && port->dev->of_node) || (port->flags & UPF_IOREMAP)) {

Looks like the dev_of_node() wrapper exists to handle this.

>                 port->membase = ioremap(port->mapbase, sport->reg_size);
>                 if (unlikely(!port->membase)) {
>                         dev_err(port->dev, "can't remap port#%d\n", port->line);
> @@ -3545,8 +3545,8 @@ static int __init hscif_early_console_setup(struct earlycon_device *device,
>
>  OF_EARLYCON_DECLARE(sci, "renesas,sci", sci_early_console_setup);
>  OF_EARLYCON_DECLARE(scif, "renesas,scif", scif_early_console_setup);
> -OF_EARLYCON_DECLARE(scif, "renesas,scif-r7s9210", rzscifa_early_console_setup);
> -OF_EARLYCON_DECLARE(scif, "renesas,scif-r9a07g044", rzscifa_early_console_setup);
> +OF_EARLYCON_DECLARE(rzscifa, "renesas,scif-r7s9210", rzscifa_early_console_setup);
> +OF_EARLYCON_DECLARE(rzscifa, "renesas,scif-r9a07g044", rzscifa_early_console_setup);
>  OF_EARLYCON_DECLARE(scifa, "renesas,scifa", scifa_early_console_setup);
>  OF_EARLYCON_DECLARE(scifb, "renesas,scifb", scifb_early_console_setup);
>  OF_EARLYCON_DECLARE(hscif, "renesas,hscif", hscif_early_console_setup);

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2024-04-05 13:54 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <cover.1712041249.git.ysato@users.sourceforge.jp>
2024-04-04  4:59 ` [DO NOT MERGE v7 09/36] sh: Common PCI Framework driver support Yoshinori Sato
2024-04-04  4:59 ` [DO NOT MERGE v7 10/36] pci: pci-sh7751: Add SH7751 PCI driver Yoshinori Sato
2024-04-04  4:59 ` [DO NOT MERGE v7 11/36] dt-bindings: pci: pci-sh7751: Add SH7751 PCI Yoshinori Sato
2024-04-04  4:59 ` [DO NOT MERGE v7 12/36] dt-bindings: clock: sh7750-cpg: Add renesas,sh7750-cpg header Yoshinori Sato
2024-04-04  4:59 ` [DO NOT MERGE v7 13/36] clk: Compatible with narrow registers Yoshinori Sato
2024-04-04  4:59 ` [DO NOT MERGE v7 14/36] clk: renesas: Add SH7750/7751 CPG Driver Yoshinori Sato
2024-04-04  4:59 ` [DO NOT MERGE v7 15/36] irqchip: Add SH7751 INTC driver Yoshinori Sato
2024-04-04  4:59 ` [DO NOT MERGE v7 16/36] dt-bindings: interrupt-controller: renesas,sh7751-intc: Add json-schema Yoshinori Sato
2024-04-04  4:59 ` [DO NOT MERGE v7 17/36] irqchip: SH7751 external interrupt encoder with enable gate Yoshinori Sato
2024-04-04  4:59 ` [DO NOT MERGE v7 18/36] dt-bindings: interrupt-controller: renesas,sh7751-irl-ext: Add json-schema Yoshinori Sato
2024-04-04  4:59 ` [DO NOT MERGE v7 19/36] serial: sh-sci: fix SH4 OF support Yoshinori Sato
2024-04-05 13:54   ` Geert Uytterhoeven
2024-04-04  4:59 ` [DO NOT MERGE v7 20/36] dt-bindings: serial: renesas,scif: Add scif-sh7751 Yoshinori Sato
2024-04-04  4:59 ` [DO NOT MERGE v7 21/36] dt-bindings: display: smi,sm501: SMI SM501 binding json-schema Yoshinori Sato
2024-04-04  5:00 ` [DO NOT MERGE v7 22/36] dt-bindings: display: sm501 register definition helper Yoshinori Sato
2024-04-04  5:00 ` [DO NOT MERGE v7 23/36] mfd: sm501: Convert platform_data to OF property Yoshinori Sato
2024-04-04  5:00 ` [DO NOT MERGE v7 24/36] dt-binding: sh: cpus: Add SH CPUs json-schema Yoshinori Sato

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).