2023-12-05 10:13:12

by Yoshinori Sato

[permalink] [raw]
Subject: [DO NOT MERGE v5 00/37] Device Tree support for SH7751 based board

This is an updated version of something I wrote about 7 years ago.
Minimum support for R2D-plus and LANDISK.
I think R2D-1 will work if you add AX88796 to dts.
And board-specific functions and SCI's SPI functions are not supported.

You can get it working with qemu found here.
https://gitlab.com/yoshinori.sato/qemu/-/tree/landisk


v5 changes.
- pci-sh7751: revert header changes. and some fix in previuous driver.
- sh/kernel/iomap.c: Use SH io functions.
- sm501 and sm501fb: re-write DT support.

v4 changes.
- cpg-sh7750: use clk-divider and clk-gate.
- pci-sh7751: unified header files to old PCI driver.
- irq-renesas-sh7751: IPR registers direct mapping.
- irq-renesas-sh7751irl: useful register bit mapping.
- sm501 and sm501fb: re-write dt parser.
- j2_minus: fix build error.
- dt-binding schema: fix some errors.
- *.dts: cleanup.

v3 changes.
- Rewrite clk drivers.
- Added sh_tmu to OF support.
- Cleanup PCI stuff.
- Update sm501 and sm501fb OF support.
- Update devicetree and documents.

v2 changes.
- Rebasing v6,6-rc1
- re-write irqchip driver.
- Add binding documents.
- Cleanup review comment.

Yoshinori Sato (37):
sh: passing FDT address to kernel startup.
sh: Kconfig unified OF supported targets.
sh: Enable OF support for build and configuration.
dt-bindings: interrupt-controller: Add header for Renesas SH3/4 INTC.
sh: GENERIC_IRQ_CHIP support for CONFIG_OF=y
sh: kernel/setup Update DT support.
sh: Fix COMMON_CLK support in CONFIG_OF=y.
clocksource: sh_tmu: CLOCKSOURCE support.
dt-bindings: timer: renesas,tmu: add renesas,tmu-sh7750
sh: Common PCI Framework driver support.
pci: pci-sh7751: Add SH7751 PCI driver
dt-bindings: pci: pci-sh7751: Add SH7751 PCI
dt-bindings: clock: sh7750-cpg: Add renesas,sh7750-cpg header.
clk: Compatible with narrow registers
clk: renesas: Add SH7750/7751 CPG Driver
irqchip: Add SH7751 INTC driver
dt-bindings: interrupt-controller: renesas,sh7751-intc: Add
json-schema
irqchip: SH7751 IRL external encoder with enable gate.
dt-bindings: interrupt-controller: renesas,sh7751-irl-ext: Add
json-schema
serial: sh-sci: fix SH4 OF support.
dt-bindings: serial: renesas,scif: Add scif-sh7751.
dt-bindings: display: smi,sm501: SMI SM501 binding json-schema
mfd: sm501: Convert platform_data to OF property
dt-binding: sh: cpus: Add SH CPUs json-schema
dt-bindings: vendor-prefixes: Add iodata
dt-bindings: vendor-prefixes: Add smi
dt-bindings: ata: ata-generic: Add new targets
dt-bindings: soc: renesas: sh: Add SH7751 based target
sh: SH7751R SoC Internal peripheral definition dtsi.
sh: add RTS7751R2D Plus DTS
sh: Add IO DATA LANDISK dts
sh: Add IO DATA USL-5P dts
sh: j2_mimas_v2.dts update
sh: Add dtbs target support.
sh: RTS7751R2D Plus OF defconfig
sh: LANDISK OF defconfig
sh: j2_defconfig: update

.../devicetree/bindings/ata/ata-generic.yaml | 2 +
.../bindings/clock/renesas,sh7750-cpg.yaml | 103 ++++
.../bindings/display/smi,sm501.yaml | 134 +++++
.../renesas,sh7751-intc.yaml | 105 ++++
.../renesas,sh7751-irl-ext.yaml | 83 +++
.../bindings/pci/renesas,sh7751-pci.yaml | 128 +++++
.../bindings/serial/renesas,scif.yaml | 1 +
.../devicetree/bindings/sh/cpus.yaml | 73 +++
.../devicetree/bindings/soc/renesas/sh.yaml | 32 ++
.../bindings/timer/renesas,tmu.yaml | 11 +-
.../devicetree/bindings/vendor-prefixes.yaml | 4 +
arch/sh/Kconfig | 11 +-
arch/sh/boards/Kconfig | 24 +-
arch/sh/boards/of-generic.c | 28 +-
arch/sh/boot/compressed/head_32.S | 5 +-
arch/sh/boot/dts/Makefile | 5 +
arch/sh/boot/dts/j2_mimas_v2.dts | 2 +-
arch/sh/boot/dts/landisk.dts | 74 +++
arch/sh/boot/dts/rts7751r2dplus.dts | 157 ++++++
arch/sh/boot/dts/sh7751r.dtsi | 150 ++++++
arch/sh/boot/dts/usl-5p.dts | 84 +++
arch/sh/configs/j2_defconfig | 11 +-
arch/sh/configs/landisk-of_defconfig | 111 ++++
arch/sh/configs/rts7751r2dplus-of_defconfig | 93 ++++
arch/sh/drivers/Makefile | 2 +
arch/sh/drivers/pci/pci.c | 6 -
arch/sh/include/asm/io.h | 6 +
arch/sh/include/asm/irq.h | 10 +-
arch/sh/include/asm/pci.h | 4 +
arch/sh/kernel/cpu/Makefile | 6 +-
arch/sh/kernel/cpu/irq/imask.c | 17 +
arch/sh/kernel/cpu/sh4/Makefile | 3 +
arch/sh/kernel/iomap.c | 24 +
arch/sh/kernel/setup.c | 51 +-
arch/sh/kernel/time.c | 12 +
drivers/clk/clk-divider.c | 56 +-
drivers/clk/clk-gate.c | 56 +-
drivers/clk/renesas/Kconfig | 16 +-
drivers/clk/renesas/Makefile | 1 +
drivers/clk/renesas/clk-sh7750.c | 498 ++++++++++++++++++
drivers/clocksource/sh_tmu.c | 161 ++++--
drivers/irqchip/Kconfig | 15 +
drivers/irqchip/Makefile | 3 +
drivers/irqchip/irq-renesas-sh7751.c | 290 ++++++++++
drivers/irqchip/irq-renesas-sh7751irl.c | 227 ++++++++
drivers/mfd/sm501.c | 99 ++++
drivers/pci/controller/Kconfig | 9 +
drivers/pci/controller/Makefile | 1 +
drivers/pci/controller/pci-sh7751.c | 302 +++++++++++
drivers/pci/controller/pci-sh7751.h | 76 +++
drivers/tty/serial/Kconfig | 2 +-
drivers/tty/serial/sh-sci.c | 6 +-
drivers/video/fbdev/sm501fb.c | 82 +++
include/dt-bindings/clock/sh7750-cpg.h | 26 +
include/dt-bindings/display/sm501.h | 25 +
.../interrupt-controller/sh7751-intc.h | 21 +
include/linux/clk-provider.h | 22 +-
include/linux/sh_intc.h | 7 +-
58 files changed, 3396 insertions(+), 177 deletions(-)
create mode 100644 Documentation/devicetree/bindings/clock/renesas,sh7750-cpg.yaml
create mode 100644 Documentation/devicetree/bindings/display/smi,sm501.yaml
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/renesas,sh7751-intc.yaml
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/renesas,sh7751-irl-ext.yaml
create mode 100644 Documentation/devicetree/bindings/pci/renesas,sh7751-pci.yaml
create mode 100644 Documentation/devicetree/bindings/sh/cpus.yaml
create mode 100644 Documentation/devicetree/bindings/soc/renesas/sh.yaml
create mode 100644 arch/sh/boot/dts/landisk.dts
create mode 100644 arch/sh/boot/dts/rts7751r2dplus.dts
create mode 100644 arch/sh/boot/dts/sh7751r.dtsi
create mode 100644 arch/sh/boot/dts/usl-5p.dts
create mode 100644 arch/sh/configs/landisk-of_defconfig
create mode 100644 arch/sh/configs/rts7751r2dplus-of_defconfig
create mode 100644 drivers/clk/renesas/clk-sh7750.c
create mode 100644 drivers/irqchip/irq-renesas-sh7751.c
create mode 100644 drivers/irqchip/irq-renesas-sh7751irl.c
create mode 100644 drivers/pci/controller/pci-sh7751.c
create mode 100644 drivers/pci/controller/pci-sh7751.h
create mode 100644 include/dt-bindings/clock/sh7750-cpg.h
create mode 100644 include/dt-bindings/display/sm501.h
create mode 100644 include/dt-bindings/interrupt-controller/sh7751-intc.h

--
2.39.2


2023-12-05 10:13:29

by Yoshinori Sato

[permalink] [raw]
Subject: [DO NOT MERGE v5 27/37] dt-bindings: ata: ata-generic: Add new targets

Added new ata-generic target.
- iodata,usl-5p-ata
- renesas,rts7751r2d-ata

Each boards have simple IDE Interface. Use ATA generic driver.

Signed-off-by: Yoshinori Sato <[email protected]>
---
Documentation/devicetree/bindings/ata/ata-generic.yaml | 2 ++
1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/ata/ata-generic.yaml b/Documentation/devicetree/bindings/ata/ata-generic.yaml
index 0697927f3d7e..1025b3b351d0 100644
--- a/Documentation/devicetree/bindings/ata/ata-generic.yaml
+++ b/Documentation/devicetree/bindings/ata/ata-generic.yaml
@@ -18,6 +18,8 @@ properties:
- enum:
- arm,vexpress-cf
- fsl,mpc8349emitx-pata
+ - iodata,usl-5p-ata
+ - renesas,rts7751r2d-ata
- const: ata-generic

reg:
--
2.39.2

2023-12-05 10:13:29

by Yoshinori Sato

[permalink] [raw]
Subject: [DO NOT MERGE v5 01/37] sh: passing FDT address to kernel startup.

R4 is caller saved in SH ABI.
Save it so it doesn't get corrupted until it's needed for initialization.

Signed-off-by: Yoshinori Sato <[email protected]>
---
arch/sh/boot/compressed/head_32.S | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/sh/boot/compressed/head_32.S b/arch/sh/boot/compressed/head_32.S
index 7bb168133dbb..6be59851122e 100644
--- a/arch/sh/boot/compressed/head_32.S
+++ b/arch/sh/boot/compressed/head_32.S
@@ -15,7 +15,8 @@ startup:
/* Load initial status register */
mov.l init_sr, r1
ldc r1, sr
-
+ /* Save FDT address */
+ mov r4, r13
/* Move myself to proper location if necessary */
mova 1f, r0
mov.l 1f, r2
@@ -84,7 +85,7 @@ l1:
/* Jump to the start of the decompressed kernel */
mov.l kernel_start_addr, r0
jmp @r0
- nop
+ mov r13, r4

.align 2
bss_start_addr:
--
2.39.2

2023-12-05 10:13:34

by Yoshinori Sato

[permalink] [raw]
Subject: [DO NOT MERGE v5 03/37] sh: Enable OF support for build and configuration.

IRQ, CLK and PCI will be migrated to a common driver framework.
So if OF, disable the SH specific drivers.

Signed-off-by: Yoshinori Sato <[email protected]>
---
arch/sh/Kconfig | 11 ++++++-----
arch/sh/drivers/Makefile | 2 ++
arch/sh/kernel/cpu/Makefile | 9 +++++++--
arch/sh/kernel/cpu/sh4/Makefile | 3 +++
4 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 7500521b2b98..63961d273af7 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -65,10 +65,10 @@ config SUPERH
select MODULES_USE_ELF_RELA
select NEED_SG_DMA_LENGTH
select NO_DMA if !MMU && !DMA_COHERENT
- select NO_GENERIC_PCI_IOPORT_MAP if PCI
+ select NO_GENERIC_PCI_IOPORT_MAP if !SH_DEVICE_TREE
select OLD_SIGACTION
select OLD_SIGSUSPEND
- select PCI_DOMAINS if PCI
+ select PCI_DOMAINS if PCI && !SH_DEVICE_TREE
select PERF_EVENTS
select PERF_USE_VMALLOC
select RTC_LIB
@@ -152,7 +152,7 @@ menu "System type"
#
config CPU_SH2
bool
- select SH_INTC
+ select SH_INTC if !SH_DEVICE_TREE

config CPU_SH2A
bool
@@ -178,7 +178,7 @@ config CPU_SH4
select CPU_HAS_INTEVT
select CPU_HAS_SR_RB
select CPU_HAS_FPU if !CPU_SH4AL_DSP
- select SH_INTC
+ select SH_INTC if !SH_DEVICE_TREE
select SYS_SUPPORTS_SH_TMU

config CPU_SH4A
@@ -521,6 +521,7 @@ config SH_PCLK_FREQ

config SH_CLK_CPG
def_bool y
+ depends on !COMMON_CLK

config SH_CLK_CPG_LEGACY
depends on SH_CLK_CPG
@@ -665,7 +666,7 @@ config BUILTIN_DTB_SOURCE
kernel.

config ZERO_PAGE_OFFSET
- hex
+ hex "Zero page offset"
default "0x00010000" if PAGE_SIZE_64KB || SH_RTS7751R2D || \
SH_7751_SOLUTION_ENGINE
default "0x00004000" if PAGE_SIZE_16KB || SH_SH03
diff --git a/arch/sh/drivers/Makefile b/arch/sh/drivers/Makefile
index 8bd10b904bf9..83f609ca1eb4 100644
--- a/arch/sh/drivers/Makefile
+++ b/arch/sh/drivers/Makefile
@@ -5,6 +5,8 @@

obj-y += dma/ platform_early.o

+ifndef CONFIG_SH_DEVICE_TREE
obj-$(CONFIG_PCI) += pci/
+endif
obj-$(CONFIG_PUSH_SWITCH) += push-switch.o
obj-$(CONFIG_HEARTBEAT) += heartbeat.o
diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile
index 46118236bf04..e00ebf134985 100644
--- a/arch/sh/kernel/cpu/Makefile
+++ b/arch/sh/kernel/cpu/Makefile
@@ -16,6 +16,11 @@ obj-$(CONFIG_ARCH_SHMOBILE) += shmobile/
# Common interfaces.

obj-$(CONFIG_SH_ADC) += adc.o
+ifndef CONFIG_COMMON_CLK
+obj-y += clock.o
obj-$(CONFIG_SH_CLK_CPG_LEGACY) += clock-cpg.o
-
-obj-y += irq/ init.o clock.o fpu.o pfc.o proc.o
+endif
+ifndef CONFIG_GENERIC_IRQ_CHIP
+obj-y += irq/
+endif
+obj-y += init.o fpu.o pfc.o proc.o
diff --git a/arch/sh/kernel/cpu/sh4/Makefile b/arch/sh/kernel/cpu/sh4/Makefile
index 02e3ee16e15c..33da4c86feff 100644
--- a/arch/sh/kernel/cpu/sh4/Makefile
+++ b/arch/sh/kernel/cpu/sh4/Makefile
@@ -15,6 +15,7 @@ perf-$(CONFIG_CPU_SUBTYPE_SH7750) := perf_event.o
perf-$(CONFIG_CPU_SUBTYPE_SH7750S) := perf_event.o
perf-$(CONFIG_CPU_SUBTYPE_SH7091) := perf_event.o

+ifndef CONFIG_SH_DEVICE_TREE
# CPU subtype setup
obj-$(CONFIG_CPU_SUBTYPE_SH7750) += setup-sh7750.o
obj-$(CONFIG_CPU_SUBTYPE_SH7750R) += setup-sh7750.o
@@ -29,5 +30,7 @@ ifndef CONFIG_CPU_SH4A
clock-$(CONFIG_CPU_SH4) := clock-sh4.o
endif

+endif # CONFIG_SH_DEVICE_TREE
+
obj-y += $(clock-y)
obj-$(CONFIG_PERF_EVENTS) += $(perf-y)
--
2.39.2

2023-12-05 10:13:41

by Yoshinori Sato

[permalink] [raw]
Subject: [DO NOT MERGE v5 02/37] sh: Kconfig unified OF supported targets.

Targets that support OF should be treated as one board.

Signed-off-by: Yoshinori Sato <[email protected]>
---
arch/sh/boards/Kconfig | 24 ++++++++++++++----------
1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig
index 109bec4dad94..e7e52779ef62 100644
--- a/arch/sh/boards/Kconfig
+++ b/arch/sh/boards/Kconfig
@@ -19,16 +19,9 @@ config SH_DEVICE_TREE
select TIMER_OF
select COMMON_CLK
select GENERIC_CALIBRATE_DELAY
-
-config SH_JCORE_SOC
- bool "J-Core SoC"
- select SH_DEVICE_TREE
- select CLKSRC_JCORE_PIT
- select JCORE_AIC
- depends on CPU_J2
- help
- Select this option to include drivers core components of the
- J-Core SoC, including interrupt controllers and timers.
+ select GENERIC_IRQ_CHIP
+ select SYS_SUPPORTS_PCI
+ select GENERIC_PCI_IOMAP if PCI

config SH_SOLUTION_ENGINE
bool "SolutionEngine"
@@ -293,6 +286,7 @@ config SH_LANDISK
bool "LANDISK"
depends on CPU_SUBTYPE_SH7751R
select HAVE_PCI
+ select SYS_SUPPORTS_PCI
help
I-O DATA DEVICE, INC. "LANDISK Series" support.

@@ -369,6 +363,16 @@ config SH_APSH4AD0A
help
Select AP-SH4AD-0A if configuring for an ALPHAPROJECT AP-SH4AD-0A.

+config SH_OF_BOARD
+ bool "General Open Firmware boards"
+ select SH_DEVICE_TREE
+ select CLKSRC_JCORE_PIT if CPU_J2
+ select JCORE_AIC if CPU_J2
+ select HAVE_PCI if CPU_SUBTYPE_SH7751R
+ help
+ This board means general OF supported targets.
+
+
source "arch/sh/boards/mach-r2d/Kconfig"
source "arch/sh/boards/mach-highlander/Kconfig"
source "arch/sh/boards/mach-sdk7780/Kconfig"
--
2.39.2

2023-12-05 10:13:44

by Yoshinori Sato

[permalink] [raw]
Subject: [DO NOT MERGE v5 18/37] irqchip: SH7751 IRL external encoder with enable gate.

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 <[email protected]>
---
drivers/irqchip/Kconfig | 7 +
drivers/irqchip/Makefile | 2 +
drivers/irqchip/irq-renesas-sh7751irl.c | 227 ++++++++++++++++++++++++
3 files changed, 236 insertions(+)
create mode 100644 drivers/irqchip/irq-renesas-sh7751irl.c

diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 658523f65b1d..2a061c01f381 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -687,4 +687,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 26c91d075e25..91df16726b1f 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -121,3 +121,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..99ee5bf9fb1e
--- /dev/null
+++ b/drivers/irqchip/irq-renesas-sh7751irl.c
@@ -0,0 +1,227 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SH7751 based board IRL 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_irq_bit(struct device_node *node, struct sh7751irl_intc_priv *priv)
+{
+ struct property *enable_map;
+ const __be32 *p;
+ u32 nr_bits;
+ u32 irl;
+ int ret;
+
+ /* Fill in unused */
+ memset(priv->enable_bit, ~0, sizeof(priv->enable_bit));
+
+ enable_map = of_find_property(node, "renesas,enable-bit", &nr_bits);
+ if (IS_ERR(enable_map))
+ return PTR_ERR(enable_map);
+
+ nr_bits /= sizeof(u32);
+ /* 2words per entry. */
+ if (nr_bits % 2)
+ return -EINVAL;
+ nr_bits /= 2;
+ if (nr_bits > NR_IRL)
+ return -EINVAL;
+
+ ret = nr_bits;
+ p = NULL;
+ for (; nr_bits > 0; nr_bits--) {
+ /* 1st word - IRL */
+ p = of_prop_next_u32(enable_map, p, &irl);
+ if (!p || irl > NR_IRL)
+ return -EINVAL;
+ /* 2nd word - enable bit index */
+ p = of_prop_next_u32(enable_map, p, &priv->enable_bit[irl]);
+ if (priv->enable_bit[irl] >= priv->width)
+ return -EINVAL;
+ }
+ return ret;
+}
+
+static int __init sh7751irl_init(struct device_node *node, struct device_node *parent)
+{
+ struct sh7751irl_intc_priv *priv;
+ struct irq_domain *d;
+ void __iomem *base;
+ int ret = 0;
+
+ base = of_iomap(node, 0);
+ if (!base)
+ ret = -EINVAL;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base = base;
+ of_property_read_u32(node, "renesas,width", &priv->width);
+ if (priv->width != 8 && priv->width != 16 && priv->width != 32) {
+ pr_err("%pOFP: Invalid register width.\n", node);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ priv->invert = of_property_read_bool(node, "renesas,set-to-disable");
+
+ ret = load_irq_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

2023-12-05 10:13:47

by Yoshinori Sato

[permalink] [raw]
Subject: [DO NOT MERGE v5 22/37] dt-bindings: display: smi,sm501: SMI SM501 binding json-schema

Define SM501 functions and modes.

Signed-off-by: Yoshinori Sato <[email protected]>
---
.../bindings/display/smi,sm501.yaml | 134 ++++++++++++++++++
include/dt-bindings/display/sm501.h | 25 ++++
2 files changed, 159 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/smi,sm501.yaml
create mode 100644 include/dt-bindings/display/sm501.h

diff --git a/Documentation/devicetree/bindings/display/smi,sm501.yaml b/Documentation/devicetree/bindings/display/smi,sm501.yaml
new file mode 100644
index 000000000000..df46600b8d4a
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/smi,sm501.yaml
@@ -0,0 +1,134 @@
+# 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 <[email protected]>
+
+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.
+
+ interrupt-name: true
+
+ 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:
+ description: CRT output control
+
+ panel:
+ description: Panel output control
+
+ bpp:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: Color depth
+
+ smi,flags:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: Display control flags.
+
+ smi,devices:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: SM501 device function select.
+
+ smi,mclk:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: mclk frequency.
+
+ smi,m1xclk:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: m1xclk frequency.
+
+ smi,misc-timing:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: Miscellaneous Timing reg value.
+
+ smi,misc-control:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: Miscellaneous Control reg value.
+
+ smi,gpio-low:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: GPIO0 to 31 Control reg value.
+
+ smi,gpio-high:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: GPIO32 to 63 Control reg value.
+
+ smi,gpio-i2c:
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ minItems: 5
+ description: |
+ GPIO I2C bus number
+ 1st field - I2C bus number
+ 2nd Field - GPIO SDA
+ 3rd Field - GPIO SCL
+ 4th Field - Timeout
+ 5th Field - udelay
+
+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];
+ };
diff --git a/include/dt-bindings/display/sm501.h b/include/dt-bindings/display/sm501.h
new file mode 100644
index 000000000000..1be8490d7635
--- /dev/null
+++ b/include/dt-bindings/display/sm501.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
+
+/* Platform data definitions */
+
+#define SM501FB_FLAG_USE_INIT_MODE (1<<0)
+#define SM501FB_FLAG_DISABLE_AT_EXIT (1<<1)
+#define SM501FB_FLAG_USE_HWCURSOR (1<<2)
+#define SM501FB_FLAG_USE_HWACCEL (1<<3)
+#define SM501FB_FLAG_PANEL_NO_FPEN (1<<4)
+#define SM501FB_FLAG_PANEL_NO_VBIASEN (1<<5)
+#define SM501FB_FLAG_PANEL_INV_FPEN (1<<6)
+#define SM501FB_FLAG_PANEL_INV_VBIASEN (1<<7)
+
+#define SM501_USE_USB_HOST (1<<0)
+#define SM501_USE_USB_SLAVE (1<<1)
+#define SM501_USE_SSP0 (1<<2)
+#define SM501_USE_SSP1 (1<<3)
+#define SM501_USE_UART0 (1<<4)
+#define SM501_USE_UART1 (1<<5)
+#define SM501_USE_FBACCEL (1<<6)
+#define SM501_USE_AC97 (1<<7)
+#define SM501_USE_I2S (1<<8)
+#define SM501_USE_GPIO (1<<9)
+
+#define SM501_USE_ALL (0xffffffff)
--
2.39.2

2023-12-05 10:13:48

by Yoshinori Sato

[permalink] [raw]
Subject: [DO NOT MERGE v5 09/37] dt-bindings: timer: renesas,tmu: add renesas,tmu-sh7750

Add SH7750 TMU entry.

Signed-off-by: Yoshinori Sato <[email protected]>
---
.../devicetree/bindings/timer/renesas,tmu.yaml | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/timer/renesas,tmu.yaml b/Documentation/devicetree/bindings/timer/renesas,tmu.yaml
index a67e427a9e7e..925c2a691b25 100644
--- a/Documentation/devicetree/bindings/timer/renesas,tmu.yaml
+++ b/Documentation/devicetree/bindings/timer/renesas,tmu.yaml
@@ -21,6 +21,7 @@ properties:
compatible:
items:
- enum:
+ - renesas,tmu-sh7750 # SH7750
- renesas,tmu-r8a7740 # R-Mobile A1
- renesas,tmu-r8a774a1 # RZ/G2M
- renesas,tmu-r8a774b1 # RZ/G2N
@@ -46,7 +47,14 @@ properties:

interrupts:
minItems: 2
- maxItems: 3
+ maxItems: 4
+
+ interrupt-names:
+ items:
+ - const: tuni0
+ - const: tuni1
+ - const: tuni2
+ - const: ticpi2

clocks:
maxItems: 1
@@ -84,6 +92,7 @@ if:
- renesas,tmu-r8a7740
- renesas,tmu-r8a7778
- renesas,tmu-r8a7779
+ - renesas,tmu-sh7750
then:
required:
- resets
--
2.39.2

2023-12-05 10:13:54

by Yoshinori Sato

[permalink] [raw]
Subject: [DO NOT MERGE v5 10/37] sh: Common PCI Framework driver support.

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 <[email protected]>
---
arch/sh/drivers/pci/pci.c | 6 ------
arch/sh/include/asm/io.h | 6 ++++++
arch/sh/include/asm/pci.h | 4 ++++
arch/sh/kernel/iomap.c | 24 ++++++++++++++++++++++++
4 files changed, 34 insertions(+), 6 deletions(-)

diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index a3903304f33f..61a19c2c9014 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -286,12 +286,6 @@ void __iomem *__pci_ioport_map(struct pci_dev *dev,
return (void __iomem *)(chan->io_map_base + port);
}

-void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
-{
- iounmap(addr);
-}
-EXPORT_SYMBOL(pci_iounmap);
-
#endif /* CONFIG_GENERIC_IOMAP */

EXPORT_SYMBOL(PCIBIOS_MIN_IO);
diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h
index ac521f287fa5..efea1bd0a681 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>
@@ -317,4 +318,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..ec68ce4e4a17 100644
--- a/arch/sh/kernel/iomap.c
+++ b/arch/sh/kernel/iomap.c
@@ -160,3 +160,27 @@ void iowrite32_rep(void __iomem *addr, const void *src, unsigned long count)
mmio_outsl(addr, src, count);
}
EXPORT_SYMBOL(iowrite32_rep);
+
+#if defined(CONFIG_PCI) && !defined(CONFIG_GENERIC_IOMAP)
+void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
+{
+ iounmap(addr);
+}
+EXPORT_SYMBOL(pci_iounmap);
+
+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 ioremap_page_range(vaddr, vaddr + resource_size(res), phys_addr,
+ pgprot_device(PAGE_KERNEL));
+}
+EXPORT_SYMBOL(pci_remap_iospace);
+#endif
--
2.39.2

2023-12-05 10:13:57

by Yoshinori Sato

[permalink] [raw]
Subject: [DO NOT MERGE v5 16/37] irqchip: Add SH7751 INTC driver

Renesas SH7751 Internal interrupt controller driver.

Signed-off-by: Yoshinori Sato <[email protected]>
---
drivers/irqchip/Kconfig | 8 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-renesas-sh7751.c | 290 +++++++++++++++++++++++++++
3 files changed, 299 insertions(+)
create mode 100644 drivers/irqchip/irq-renesas-sh7751.c

diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index f7149d0f3d45..658523f65b1d 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -679,4 +679,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 ffd945fe71aa..26c91d075e25 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -120,3 +120,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..2a5cb2444d99
--- /dev/null
+++ b/drivers/irqchip/irq-renesas-sh7751.c
@@ -0,0 +1,290 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas SH7751 interrupt controller driver
+ *
+ * Copyright 2023 Yoshinori Sato <[email protected]>
+ */
+
+#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/sh7751-intc.h>
+
+struct ipr {
+ unsigned int off;
+ unsigned int idx;
+};
+
+struct sh7751_intc_priv {
+ void __iomem *base;
+ void __iomem *intpri00;
+ struct ipr *iprmap[2];
+ 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
+
+/*
+ * IPR registers have 4bit priority x 4 entry (16bits)
+ * Interrupts can be masked by setting pri to 0.
+ */
+static void update_ipr(struct sh7751_intc_priv *priv, unsigned int irq, u16 pri)
+{
+ struct ipr *ipr = NULL;
+ void __iomem *ipr_base;
+ unsigned int offset;
+ u16 mask;
+
+ if (irq < GRP1_IRQ_START) {
+ /* Group0 */
+ ipr = priv->iprmap[0];
+ ipr += irq - IRQ_START;
+ ipr_base = priv->base + R_IPR;
+ offset = ipr->off;
+ } else {
+ /* Group1 */
+ ipr = priv->iprmap[1];
+ ipr += irq - GRP1_IRQ_START;
+ ipr_base = priv->intpri00;
+ offset = ipr->off - INTPRI00;
+ }
+ if (ipr->off != ~0) {
+ 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);
+ } else {
+ pr_warn_once("%s: undefined IPR in irq %u\n", __FILE__, irq);
+ }
+}
+
+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;
+}
+
+static void endisable_irq(struct irq_data *data, int 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 */
+ /* disable for SR.IMASK */
+ update_sr_imask(irq - IRQ_START, enable);
+ else
+ /* Internal peripheral interrupt */
+ /* mask for IPR priority 0 */
+ update_ipr(priv, irq, enable);
+}
+
+static void sh7751_mask_irq(struct irq_data *data)
+{
+ endisable_irq(data, 0);
+}
+
+static void sh7751_unmask_irq(struct irq_data *data)
+{
+ endisable_irq(data, 1);
+}
+
+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 const struct irq_domain_ops irq_ops = {
+ .map = irq_sh7751_map,
+ .xlate = irq_domain_xlate_onecell,
+};
+
+static int __init load_ipr_map(struct device_node *intc,
+ struct sh7751_intc_priv *priv)
+{
+ struct property *ipr_map;
+ unsigned int num_ipr, i;
+ struct ipr *ipr;
+ const __be32 *p;
+ u32 irq;
+
+ ipr_map = of_find_property(intc, "renesas,ipr-map", &num_ipr);
+ if (IS_ERR(ipr_map))
+ return PTR_ERR(ipr_map);
+ num_ipr /= sizeof(u32);
+ /* 3words per entry. */
+ if (num_ipr % 3)
+ goto error1;
+ num_ipr /= 3;
+ if (num_ipr >= NR_IPRMAP0 + NR_IPRMAP1)
+ goto error1;
+
+ /* Allocate map array and fill in unassigned */
+ priv->iprmap[0] = kmalloc_array(NR_IPRMAP0, sizeof(struct ipr), GFP_KERNEL);
+ if (priv->iprmap[0] == NULL)
+ return -ENOMEM;
+ memset(priv->iprmap[0], ~0, NR_IPRMAP0 * sizeof(struct ipr));
+ priv->iprmap[1] = kmalloc_array(NR_IPRMAP1, sizeof(struct ipr), GFP_KERNEL);
+ if (priv->iprmap[1] == NULL) {
+ kfree(priv->iprmap[0]);
+ return -ENOMEM;
+ }
+ memset(priv->iprmap[1], ~0, NR_IPRMAP1 * sizeof(struct ipr));
+
+ p = NULL;
+ for (; num_ipr > 0; num_ipr--) {
+ /* 1st word - INTEVT code */
+ p = of_prop_next_u32(ipr_map, p, &irq);
+ if (!p)
+ goto error;
+ irq = evt2irq(irq);
+ if (!is_valid_irq(irq))
+ goto error;
+ if (irq < GRP1_IRQ_START) {
+ ipr = priv->iprmap[0];
+ irq -= IRQ_START;
+ } else {
+ ipr = priv->iprmap[1];
+ irq -= GRP1_IRQ_START;
+ }
+ ipr += irq;
+ /* 2nd word - IPR register offset */
+ p = of_prop_next_u32(ipr_map, p, &ipr->off);
+ /* 3rd word - IPR register bit indx */
+ p = of_prop_next_u32(ipr_map, p, &ipr->idx);
+
+ if ((ipr->off != INTPRI00 && ipr->off > IPRD) ||
+ ipr->idx > IPR_B12)
+ goto error;
+ }
+
+ for (ipr = priv->iprmap[0], i = 0; i < NR_IPRMAP0; ipr++, i++) {
+ if (ipr->off != ~0) {
+ pr_debug("INTEVT=%04x (%u) reg=IPR%c idx=%u\n",
+ irq2evt(i + IRQ_START), i + IRQ_START,
+ 'A' + ipr->off / 4, ipr->idx);
+ }
+ }
+ for (ipr = priv->iprmap[1], i = 0; i < NR_IPRMAP1; ipr++, i++) {
+ if (ipr->off != ~0) {
+ pr_debug("INTEVT=%04x (%u) reg=INTPRI00 idx=%u\n",
+ irq2evt(i + GRP1_IRQ_START), i + GRP1_IRQ_START,
+ ipr->idx);
+ }
+ }
+ return 0;
+error:
+ kfree(priv->iprmap[0]);
+ kfree(priv->iprmap[1]);
+error1:
+ pr_err("%pOFP: Failed to load renesas,ipr-map\n", intc);
+ return -EINVAL;
+}
+
+static int __init sh7751_intc_of_init(struct device_node *intc,
+ struct device_node *parent)
+{
+ struct sh7751_intc_priv *priv;
+ void __iomem *base, *base2;
+ struct irq_domain *domain;
+ u16 icr;
+ int ret;
+
+ base = of_iomap(intc, 0);
+ base2 = of_iomap(intc, 1);
+ if (!base || !base2) {
+ pr_err("%pOFP: Invalid register definition\n", intc);
+ return -EINVAL;
+ }
+
+ priv = kzalloc(sizeof(struct sh7751_intc_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
+
+ ret = load_ipr_map(intc, priv);
+ if (ret < 0) {
+ kfree(priv);
+ return ret;
+ }
+
+ priv->base = base;
+ priv->intpri00 = base2;
+
+ 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);
+ kfree(priv);
+ return -ENOMEM;
+ }
+
+ irq_set_default_host(domain);
+ pr_info("%pOFP: SH7751 Interrupt controller (%s external IRQ)",
+ intc, priv->irlm ? "4 lines" : "15 level");
+ return 0;
+}
+
+IRQCHIP_DECLARE(sh_7751_intc,
+ "renesas,sh7751-intc", sh7751_intc_of_init);
--
2.39.2

2023-12-05 10:14:09

by Yoshinori Sato

[permalink] [raw]
Subject: [DO NOT MERGE v5 15/37] clk: renesas: Add SH7750/7751 CPG Driver

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

Signed-off-by: Yoshinori Sato <[email protected]>
---
drivers/clk/renesas/Kconfig | 16 +-
drivers/clk/renesas/Makefile | 1 +
drivers/clk/renesas/clk-sh7750.c | 498 +++++++++++++++++++++++++++++++
3 files changed, 513 insertions(+), 2 deletions(-)
create mode 100644 drivers/clk/renesas/clk-sh7750.c

diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig
index 69396e197959..b1350cda7ade 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
@@ -40,6 +40,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

@@ -193,6 +196,10 @@ config CLK_SH73A0
select CLK_RENESAS_CPG_MSTP
select CLK_RENESAS_DIV6

+config CLK_SH7750
+ bool "SH7750/7751 family clock support" if COMPILE_TEST
+ help
+ This is a driver for SH7750 / SH7751 CPG.

# Family
config CLK_RCAR_CPG_LIB
@@ -223,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 879a07d445f9..233e029fcd54 100644
--- a/drivers/clk/renesas/Makefile
+++ b/drivers/clk/renesas/Makefile
@@ -37,6 +37,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..bd971e9a8869
--- /dev/null
+++ b/drivers/clk/renesas/clk-sh7750.c
@@ -0,0 +1,498 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas SH7750/51 CPG driver
+ *
+ * Copyright 2023 Yoshinori Sato <[email protected]>
+ */
+
+#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("%s: failed to register %s pll clock (%d)\n",
+ __func__, clk_name, ret);
+ return ret;
+ }
+ if (ret < 0)
+ pr_err("%s: failed to add provider %s (%d)\n",
+ __func__, 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);
+}
+
+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 */
+ };
+
+ unsigned int i;
+ int ret;
+ struct clk_hw_onecell_data *data;
+ struct clk_hw *reg_hw;
+ int num_clk = ARRAY_SIZE(divout) + ARRAY_SIZE(stbcrout) + ARRAY_SIZE(clkstpout);
+
+ 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;
+ }
+ for (i = 0; i < ARRAY_SIZE(stbcrout); i++) {
+ u32 off = (i < 5) ? STBCR : STBCR2;
+
+ if (i >= 5 && !(cpg->feat & MSTP_CR2))
+ break;
+ reg_hw = __clk_hw_register_gate(NULL, node, stbcrout[i],
+ divout[0], NULL, NULL,
+ 0, cpg->frqcr + off, i % 5,
+ 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) {
+ for (i = 0; i < ARRAY_SIZE(clkstpout); i++) {
+ if (i == 2 && !(cpg->feat & MSTP_CSTP2))
+ continue;
+ 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;
+}
+
+static struct cpg_priv *sh7750_cpg_setup(struct device_node *node, u32 feat)
+{
+ unsigned int num_parents;
+ u32 mode;
+ struct cpg_priv *cpg;
+ int ret = 0;
+
+ num_parents = of_clk_get_parent_count(node);
+ if (num_parents < 1) {
+ pr_err("%s: no parent found", node->name);
+ return ERR_PTR(-ENODEV);
+ }
+
+ of_property_read_u32_index(node, "renesas,mode", 0, &mode);
+ if (mode >= 7) {
+ pr_err("%s: Invalid clock mode setting (%u)\n",
+ node->name, mode);
+ return ERR_PTR(-EINVAL);
+ }
+
+ cpg = kzalloc(sizeof(struct cpg_priv), GFP_KERNEL);
+ if (!cpg)
+ return ERR_PTR(-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;
+
+ return cpg;
+
+unmap_clkstp00:
+ iounmap(cpg->clkstp00);
+unmap_frqcr:
+ iounmap(cpg->frqcr);
+cpg_free:
+ kfree(cpg);
+ return ERR_PTR(ret);
+}
+
+static void __init sh7750_cpg_init(struct device_node *node)
+{
+ cpg_data = sh7750_cpg_setup(node, cpg_feature[CPG_SH7750]);
+ if (IS_ERR(cpg_data))
+ cpg_data = NULL;
+}
+
+static void __init sh7750s_cpg_init(struct device_node *node)
+{
+ cpg_data = sh7750_cpg_setup(node, cpg_feature[CPG_SH7750S]);
+ if (IS_ERR(cpg_data))
+ cpg_data = NULL;
+}
+
+static void __init sh7750r_cpg_init(struct device_node *node)
+{
+ cpg_data = sh7750_cpg_setup(node, cpg_feature[CPG_SH7750R]);
+ if (IS_ERR(cpg_data))
+ cpg_data = NULL;
+}
+
+static void __init sh7751_cpg_init(struct device_node *node)
+{
+ cpg_data = sh7750_cpg_setup(node, cpg_feature[CPG_SH7751]);
+ if (IS_ERR(cpg_data))
+ cpg_data = NULL;
+}
+
+static void __init sh7751r_cpg_init(struct device_node *node)
+{
+ cpg_data = sh7750_cpg_setup(node, cpg_feature[CPG_SH7751R]);
+ if (IS_ERR(cpg_data))
+ cpg_data = NULL;
+}
+
+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);
+ cpg_data = sh7750_cpg_setup(pdev->dev.of_node, feature);
+ if (IS_ERR(cpg_data))
+ return PTR_ERR(cpg_data);
+ return 0;
+}
+
+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

2023-12-05 10:14:18

by Yoshinori Sato

[permalink] [raw]
Subject: [DO NOT MERGE v5 19/37] dt-bindings: interrupt-controller: renesas,sh7751-irl-ext: Add json-schema

Renesas SH7751 external interrupt encoder json-schema.

Signed-off-by: Yoshinori Sato <[email protected]>
---
.../renesas,sh7751-irl-ext.yaml | 83 +++++++++++++++++++
1 file changed, 83 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..ba4fe2e4d749
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,sh7751-irl-ext.yaml
@@ -0,0 +1,83 @@
+# 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 IRL external encoder with enable regs.
+
+maintainers:
+ - Yoshinori Sato <[email protected]>
+
+description: |
+ This is the generally used external interrupt encoder on SH7751 based boards.
+
+properties:
+ compatible:
+ items:
+ - const: renesas,sh7751-irl-ext
+
+ reg:
+ minItems: 1
+
+ interrupt-controller: true
+
+ '#interrupt-cells':
+ const: 1
+
+ '#address-cells':
+ const: 0
+
+ '#size-cells':
+ const: 0
+
+ renesas,width:
+ description: Enable register width
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [8, 16, 32]
+
+ renesas,set-to-disable:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description: Setting this flag to 1 disables it.
+
+ renesas,enable-bit:
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ description: |
+ IRL enable register bit mapping
+ 1st word IRL
+ 2nd word bit index of enable register
+
+required:
+ - compatible
+ - reg
+ - interrupt-controller
+ - '#interrupt-cells'
+ - renesas,width
+ - renesas,enable-bit
+
+additionalProperties: false
+
+examples:
+ - |
+ r2dintc: sh7751irl_encoder@a4000000 {
+ compatible = "renesas,sh7751-irl-ext";
+ reg = <0xa4000000 0x02>;
+ interrupt-controller;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+ renesas,width = <16>;
+ renesas,enable-bit = <0 11>, /* PCI INTD */
+ <1 9>, /* CF IDE */
+ <2 8>, /* CF CD */
+ <3 12>, /* PCI INTC */
+ <4 10>, /* SM501 */
+ <5 6>, /* KEY */
+ <6 5>, /* RTC ALARM */
+ <7 4>, /* RTC T */
+ <8 7>, /* SDCARD */
+ <9 14>, /* PCI INTA */
+ <10 13>, /* PCI INTB */
+ <11 0>, /* EXT */
+ <12 15>; /* TP */
+ };
--
2.39.2

2023-12-05 13:36:53

by Rob Herring

[permalink] [raw]
Subject: Re: [DO NOT MERGE v5 22/37] dt-bindings: display: smi,sm501: SMI SM501 binding json-schema


On Tue, 05 Dec 2023 18:45:41 +0900, Yoshinori Sato wrote:
> Define SM501 functions and modes.
>
> Signed-off-by: Yoshinori Sato <[email protected]>
> ---
> .../bindings/display/smi,sm501.yaml | 134 ++++++++++++++++++
> include/dt-bindings/display/sm501.h | 25 ++++
> 2 files changed, 159 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/display/smi,sm501.yaml
> create mode 100644 include/dt-bindings/display/sm501.h
>

My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):

yamllint warnings/errors:

dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/smi,sm501.yaml: interrupt-name: missing type definition
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/smi,sm501.yaml: edid: missing type definition
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/smi,sm501.yaml: crt: missing type definition

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/f671beae8a8ebfd361f4c903bccce713135a169f.1701768028.git.ysato@users.sourceforge.jp

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.

2023-12-05 15:29:43

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: [DO NOT MERGE v5 09/37] dt-bindings: timer: renesas,tmu: add renesas,tmu-sh7750

Hi Sato-san,

On Tue, Dec 5, 2023 at 10:46 AM Yoshinori Sato
<[email protected]> wrote:
> Add SH7750 TMU entry.
>
> Signed-off-by: Yoshinori Sato <[email protected]>

Thanks for your patch!

> --- a/Documentation/devicetree/bindings/timer/renesas,tmu.yaml
> +++ b/Documentation/devicetree/bindings/timer/renesas,tmu.yaml
> @@ -21,6 +21,7 @@ properties:
> compatible:
> items:
> - enum:
> + - renesas,tmu-sh7750 # SH7750

Please preserve alphabetical sort order.

> - renesas,tmu-r8a7740 # R-Mobile A1
> - renesas,tmu-r8a774a1 # RZ/G2M
> - renesas,tmu-r8a774b1 # RZ/G2N

The rest LGTM.

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

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

2023-12-05 15:57:09

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [DO NOT MERGE v5 22/37] dt-bindings: display: smi,sm501: SMI SM501 binding json-schema

On 05/12/2023 14:36, Arnd Bergmann wrote:
> On Tue, Dec 5, 2023, at 10:45, Yoshinori Sato wrote:
>> Define SM501 functions and modes.
>>
>> Signed-off-by: Yoshinori Sato <[email protected]>
>> ---
>> .../bindings/display/smi,sm501.yaml | 134 ++++++++++++++++++
>> include/dt-bindings/display/sm501.h | 25 ++++
>
> It looks like we already have a binding at
> Documentation/devicetree/bindings/display/sm501fb.txt

Which I asked to do three months ago. Several comments were simply
ignored and never responded to.

Best regards,
Krzysztof

2023-12-05 16:07:45

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [DO NOT MERGE v5 09/37] dt-bindings: timer: renesas,tmu: add renesas,tmu-sh7750

On 05/12/2023 10:45, Yoshinori Sato wrote:
> diff --git a/Documentation/devicetree/bindings/timer/renesas,tmu.yaml b/Documentation/devicetree/bindings/timer/renesas,tmu.yaml
> index a67e427a9e7e..925c2a691b25 100644
> --- a/Documentation/devicetree/bindings/timer/renesas,tmu.yaml
> +++ b/Documentation/devicetree/bindings/timer/renesas,tmu.yaml
> @@ -21,6 +21,7 @@ properties:
> compatible:
> items:
> - enum:
> + - renesas,tmu-sh7750 # SH7750

Please keep alphabetical order.

> - renesas,tmu-r8a7740 # R-Mobile A1
> - renesas,tmu-r8a774a1 # RZ/G2M
> - renesas,tmu-r8a774b1 # RZ/G2N
> @@ -46,7 +47,14 @@ properties:
>
> interrupts:
> minItems: 2
> - maxItems: 3
> + maxItems: 4

You need to constrain in allOf:if:then: existing and new variants. Old
did not have 4 interrupts.

Best regards,
Krzysztof

2023-12-05 21:02:25

by Rob Herring

[permalink] [raw]
Subject: Re: [DO NOT MERGE v5 19/37] dt-bindings: interrupt-controller: renesas,sh7751-irl-ext: Add json-schema

On Tue, Dec 05, 2023 at 06:45:38PM +0900, Yoshinori Sato wrote:
> Renesas SH7751 external interrupt encoder json-schema.
>
> Signed-off-by: Yoshinori Sato <[email protected]>
> ---
> .../renesas,sh7751-irl-ext.yaml | 83 +++++++++++++++++++
> 1 file changed, 83 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..ba4fe2e4d749
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,sh7751-irl-ext.yaml
> @@ -0,0 +1,83 @@
> +# 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 IRL external encoder with enable regs.

IRL? In Real Life?

> +
> +maintainers:
> + - Yoshinori Sato <[email protected]>
> +
> +description: |

Don't need '|' if no formatting to preserve.

> + This is the generally used external interrupt encoder on SH7751 based boards.
> +
> +properties:
> + compatible:
> + items:
> + - const: renesas,sh7751-irl-ext
> +
> + reg:
> + minItems: 1

maxItems: 1

> +
> + interrupt-controller: true
> +
> + '#interrupt-cells':
> + const: 1
> +
> + '#address-cells':
> + const: 0
> +
> + '#size-cells':
> + const: 0

Don't need #size-cells.

> +
> + renesas,width:
> + description: Enable register width
> + $ref: /schemas/types.yaml#/definitions/uint32
> + enum: [8, 16, 32]

reg-io-width is the standard property for this purpose.

> +
> + renesas,set-to-disable:
> + $ref: /schemas/types.yaml#/definitions/flag
> + description: Setting this flag to 1 disables it.

You can't set a boolean to 1. What is 'it' here?

> +
> + renesas,enable-bit:
> + $ref: /schemas/types.yaml#/definitions/uint32-array

You've described a 2 entry matrix, not an array.

> + description: |
> + IRL enable register bit mapping
> + 1st word IRL
> + 2nd word bit index of enable register

Needs a better description of what this is for. If it is per SoC then it
should be implied from the compatible string.


> +
> +required:
> + - compatible
> + - reg
> + - interrupt-controller
> + - '#interrupt-cells'
> + - renesas,width
> + - renesas,enable-bit
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + r2dintc: sh7751irl_encoder@a4000000 {

interrupt-controller@...

Drop unused labels.

> + compatible = "renesas,sh7751-irl-ext";
> + reg = <0xa4000000 0x02>;
> + interrupt-controller;
> + #address-cells = <0>;
> + #size-cells = <0>;
> + #interrupt-cells = <1>;
> + renesas,width = <16>;
> + renesas,enable-bit = <0 11>, /* PCI INTD */
> + <1 9>, /* CF IDE */
> + <2 8>, /* CF CD */
> + <3 12>, /* PCI INTC */
> + <4 10>, /* SM501 */
> + <5 6>, /* KEY */
> + <6 5>, /* RTC ALARM */
> + <7 4>, /* RTC T */
> + <8 7>, /* SDCARD */
> + <9 14>, /* PCI INTA */
> + <10 13>, /* PCI INTB */
> + <11 0>, /* EXT */
> + <12 15>; /* TP */

Looks like the first value is just the index of the entry, so drop it
and use the index.

But better yet, these are all per interrupt values. Put them into the
interrupt cell values instead. For example the RTC would have something
like:

interrupts = <6 5>, <7 4>;

Though I do wonder if you really need the first value, or that was just
interrupt numbers you made up and then created this mapping?

Rob

2023-12-06 05:01:00

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [DO NOT MERGE v5 10/37] sh: Common PCI Framework driver support.

On Tue, Dec 5, 2023, at 10:45, Yoshinori Sato wrote:
> +
> +#if defined(CONFIG_PCI) && !defined(CONFIG_GENERIC_IOMAP)
> +void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
> +{
> + iounmap(addr);
> +}
> +EXPORT_SYMBOL(pci_iounmap);

This definition does not work for addresses that are
returned by ioport_map(), include pci_iomap() on
IORESOURCE_IO. However, the definition in lib/pci_iomap.c
should work fine, you just need to #define ARCH_WANTS_GENERIC_PCI_IOUNMAP
to get that.

Arnd

2023-12-06 08:56:06

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [DO NOT MERGE v5 22/37] dt-bindings: display: smi,sm501: SMI SM501 binding json-schema

On Tue, Dec 5, 2023, at 10:45, Yoshinori Sato wrote:
> Define SM501 functions and modes.
>
> Signed-off-by: Yoshinori Sato <[email protected]>
> ---
> .../bindings/display/smi,sm501.yaml | 134 ++++++++++++++++++
> include/dt-bindings/display/sm501.h | 25 ++++

It looks like we already have a binding at
Documentation/devicetree/bindings/display/sm501fb.txt

> + 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.

Why do you need both the "swap" and the specific little/big
properties?

> + crt:
> + description: CRT output control
> +
> + panel:
> + description: Panel output control

What type are these?

> + smi,misc-timing:
> + $ref: /schemas/types.yaml#/definitions/uint32
> + description: Miscellaneous Timing reg value.
> +
> + smi,misc-control:
> + $ref: /schemas/types.yaml#/definitions/uint32
> + description: Miscellaneous Control reg value.
> +
> + smi,gpio-low:
> + $ref: /schemas/types.yaml#/definitions/uint32
> + description: GPIO0 to 31 Control reg value.
> +
> + smi,gpio-high:
> + $ref: /schemas/types.yaml#/definitions/uint32
> + description: GPIO32 to 63 Control reg value.

Register values should generally not go into DT


> +
> + smi,gpio-i2c:
> + $ref: /schemas/types.yaml#/definitions/uint32-array
> + minItems: 5
> + description: |
> + GPIO I2C bus number
> + 1st field - I2C bus number
> + 2nd Field - GPIO SDA
> + 3rd Field - GPIO SCL
> + 4th Field - Timeout
> + 5th Field - udelay

Instead of a bus number and other fields, I think
this should reference an i2c device.

Arnd

2023-12-08 15:49:37

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [DO NOT MERGE v5 16/37] irqchip: Add SH7751 INTC driver

On Tue, Dec 05 2023 at 18:45, Yoshinori Sato wrote:
> +static void endisable_irq(struct irq_data *data, int enable)

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 */
> + /* disable for SR.IMASK */
> + update_sr_imask(irq - IRQ_START, enable);
> + else
> + /* Internal peripheral interrupt */
> + /* mask for IPR priority 0 */
> + update_ipr(priv, irq, enable);

Lacks curly brackets on the if/else

> +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 const struct irq_domain_ops irq_ops = {

Newline before 'static ...'

> + .map = irq_sh7751_map,
> + .xlate = irq_domain_xlate_onecell,
> +};
> +
> +static int __init load_ipr_map(struct device_node *intc,
> + struct sh7751_intc_priv *priv)
> +{
> + struct property *ipr_map;
> + unsigned int num_ipr, i;
> + struct ipr *ipr;
> + const __be32 *p;
> + u32 irq;
> +
> + ipr_map = of_find_property(intc, "renesas,ipr-map", &num_ipr);
> + if (IS_ERR(ipr_map))
> + return PTR_ERR(ipr_map);
> + num_ipr /= sizeof(u32);
> + /* 3words per entry. */
> + if (num_ipr % 3)

Three words per ... But you can spare the comment by doing:

if (num_ipr % WORDS_PER_ENTRY)

> + goto error1;
> + num_ipr /= 3;
> +static int __init sh7751_intc_of_init(struct device_node *intc,
> + struct device_node *parent)
> +{
> + struct sh7751_intc_priv *priv;
> + void __iomem *base, *base2;
> + struct irq_domain *domain;
> + u16 icr;
> + int ret;
> +
> + base = of_iomap(intc, 0);
> + base2 = of_iomap(intc, 1);
> + if (!base || !base2) {
> + pr_err("%pOFP: Invalid register definition\n", intc);

What unmaps 'base' if 'base' is valid and base2 == NULL?

> + return -EINVAL;
> + }
> +
> + priv = kzalloc(sizeof(struct sh7751_intc_priv), GFP_KERNEL);
> + if (priv == NULL)
> + return -ENOMEM;

Leaks base[2] maps, no?

> + ret = load_ipr_map(intc, priv);
> + if (ret < 0) {
> + kfree(priv);
> + return ret;
> + }
> +
> + priv->base = base;
> + priv->intpri00 = base2;
> +
> + 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);
> + kfree(priv);
> + return -ENOMEM;
> + }
> +
> + irq_set_default_host(domain);
> + pr_info("%pOFP: SH7751 Interrupt controller (%s external IRQ)",
> + intc, priv->irlm ? "4 lines" : "15 level");
> + return 0;
> +}
> +
> +IRQCHIP_DECLARE(sh_7751_intc,
> + "renesas,sh7751-intc", sh7751_intc_of_init);

One line please.

Thanks,

tglx