Hi,
This series introduces initial support for the Ingenic jz4780 SoC & the
MIPS Creator CI20 board which is based upon it.
The jz4780 shares aspects with jz4740. But jz4740 is platform only.
So, the jz4740 & qi_lb60 (Ben NanoNote) are converted to use DT
for some things in order to ease the process of sharing code.
Series is based on 3.19-rc7.
ACKS from various subsystems are welcome so that the series can
go via mips if that is OK with everyone.
Alternative suggestions welcome.
Changes in V2
- Removed FSF addresses.
- Removed 2 patches for binding docs that
were consolidated in the same binding for jz4740.
- Bug fix in error handling in cgu
- Rebase on 3.19-rc7
- Updated defconfig with jz47xx serial and removed initramfs
- Renames in binding from intc to interrupt-controller
- Fix in jz47xx serial for build error on x86 in one config option
- Removed interupt-parent bindings from required bindings
- Fixed imgtec prefix to img
- Added jz47xx config for qi_lb60_defconfig
Regards,
ZubairLK
Paul Burton (34):
dt: Add Ingenic Semiconductor vendor prefix
MIPS: jz4740: require & include DT
MIPS: irq_cpu: declare irqchip table entry
MIPS: jz4740: probe CPU interrupt controller via DT
MIPS: jz4740: use generic plat_irq_dispatch
MIPS: jz4740: move arch_init_irq out of arch/mips/jz4740/irq.c
dt: interrupt-controller: Add ingenic,jz4740-intc binding doc
MIPS: jz4740: allow interrupt controller probe via DT
MIPS: jz4740: probe interrupt controller via DT
MIPS: jz4740: remove non-DT interrupt controller init
MIPS: jz4740: register an irq_domain for the interrupt controller
MIPS: jz4740: call jz4740_clock_init earlier
MIPS: jz4740: replace use of jz4740_clock_bdata
clk: jz47xx-cgu: add driver for Ingenic jz47xx series CGU clocks
dt: clk: Add ingenic,jz4740-cgu binding documentation
MIPS: clk: migrate jz4740 to common clock framework
MIPS: clk: move jz4740_clock_set_wait_mode to jz4740-cgu
MIPS: clk: move jz4740 UDC auto suspend functions to jz4740-cgu
MIPS: clk: move jz4740 clock suspend, resume functions to jz4740-cgu
MIPS: jz4740: remove clock.h
MIPS: jz4740: only detect RAM size if not specified in DT
MIPS: jz4740: support >32 interrupts
MIPS: jz4740: define IRQ numbers based on number of intc IRQs
dt: serial: Add ingenic,jz4740-uart binding
serial: 8250_jz47xx: support for Ingenic jz47xx UARTs
MIPS: allow mach-provided serial.h
MIPS: jz4740: use jz47xx-uart & DT for UART output
dt: clk: Add ingenic,jz4780-cgu binding documentation
clk: add Ingenic jz4780 CGU driver
MIPS: jz4740: add jz4780 interrupt controller support
MIPS: add jz4780 Ingenic vendor ID
MIPS: initial Ingenic jz4780 support
MIPS: initial MIPS Creator CI20 board support
MIPS: allow jz4780 to be selected in Kconfig
.../bindings/clock/ingenic,jz4740-cgu.txt | 52 ++
.../bindings/clock/ingenic,jz4780-cgu.txt | 52 ++
.../interrupt-controller/ingenic,jz4740-intc.txt | 26 +
.../bindings/serial/ingenic,jz4740-uart.txt | 22 +
.../devicetree/bindings/vendor-prefixes.txt | 1 +
arch/mips/Kconfig | 22 +-
arch/mips/boot/dts/Makefile | 2 +
arch/mips/boot/dts/ci20.dts | 21 +
arch/mips/boot/dts/jz4740.dtsi | 68 ++
arch/mips/boot/dts/jz4780.dtsi | 101 +++
arch/mips/boot/dts/qi_lb60.dts | 15 +
arch/mips/configs/ci20_defconfig | 127 +++
arch/mips/configs/qi_lb60_defconfig | 1 +
arch/mips/include/asm/Kbuild | 1 -
arch/mips/include/asm/cpu.h | 1 +
arch/mips/include/asm/mach-generic/serial.h | 21 +
arch/mips/include/asm/mach-jz4740/clock.h | 3 +
arch/mips/include/asm/mach-jz4740/irq.h | 15 +-
arch/mips/include/asm/mach-jz4740/platform.h | 2 -
arch/mips/include/asm/mach-jz4740/serial.h | 27 +
arch/mips/include/asm/serial.h | 21 +
arch/mips/jz4740/Kconfig | 10 +
arch/mips/jz4740/Makefile | 6 +-
arch/mips/jz4740/Platform | 4 +
arch/mips/jz4740/board-qi_lb60.c | 7 -
arch/mips/jz4740/clock-debugfs.c | 108 ---
arch/mips/jz4740/clock.c | 924 ---------------------
arch/mips/jz4740/clock.h | 76 --
arch/mips/jz4740/irq.c | 103 ++-
arch/mips/jz4740/platform.c | 37 +-
arch/mips/jz4740/pm.c | 2 -
arch/mips/jz4740/prom.c | 13 -
arch/mips/jz4740/reset.c | 13 +-
arch/mips/jz4740/serial.c | 33 -
arch/mips/jz4740/serial.h | 23 -
arch/mips/jz4740/setup.c | 33 +-
arch/mips/jz4740/time.c | 19 +-
arch/mips/kernel/cpu-probe.c | 1 +
arch/mips/kernel/irq_cpu.c | 3 +
drivers/clk/Makefile | 2 +
drivers/clk/jz47xx/Makefile | 3 +
drivers/clk/jz47xx/jz4740-cgu.c | 295 +++++++
drivers/clk/jz47xx/jz4780-cgu.c | 742 +++++++++++++++++
drivers/clk/jz47xx/jz47xx-cgu.c | 723 ++++++++++++++++
drivers/clk/jz47xx/jz47xx-cgu.h | 205 +++++
drivers/tty/serial/8250/8250_jz47xx.c | 225 +++++
drivers/tty/serial/8250/Kconfig | 9 +
drivers/tty/serial/8250/Makefile | 1 +
include/dt-bindings/clock/jz4740-cgu.h | 37 +
include/dt-bindings/clock/jz4780-cgu.h | 88 ++
50 files changed, 3070 insertions(+), 1276 deletions(-)
create mode 100644 Documentation/devicetree/bindings/clock/ingenic,jz4740-cgu.txt
create mode 100644 Documentation/devicetree/bindings/clock/ingenic,jz4780-cgu.txt
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/ingenic,jz4740-intc.txt
create mode 100644 Documentation/devicetree/bindings/serial/ingenic,jz4740-uart.txt
create mode 100644 arch/mips/boot/dts/ci20.dts
create mode 100644 arch/mips/boot/dts/jz4740.dtsi
create mode 100644 arch/mips/boot/dts/jz4780.dtsi
create mode 100644 arch/mips/boot/dts/qi_lb60.dts
create mode 100644 arch/mips/configs/ci20_defconfig
create mode 100644 arch/mips/include/asm/mach-generic/serial.h
create mode 100644 arch/mips/include/asm/mach-jz4740/serial.h
create mode 100644 arch/mips/include/asm/serial.h
delete mode 100644 arch/mips/jz4740/clock-debugfs.c
delete mode 100644 arch/mips/jz4740/clock.c
delete mode 100644 arch/mips/jz4740/clock.h
delete mode 100644 arch/mips/jz4740/serial.c
delete mode 100644 arch/mips/jz4740/serial.h
create mode 100644 drivers/clk/jz47xx/Makefile
create mode 100644 drivers/clk/jz47xx/jz4740-cgu.c
create mode 100644 drivers/clk/jz47xx/jz4780-cgu.c
create mode 100644 drivers/clk/jz47xx/jz47xx-cgu.c
create mode 100644 drivers/clk/jz47xx/jz47xx-cgu.h
create mode 100644 drivers/tty/serial/8250/8250_jz47xx.c
create mode 100644 include/dt-bindings/clock/jz4740-cgu.h
create mode 100644 include/dt-bindings/clock/jz4780-cgu.h
--
1.9.1
From: Paul Burton <[email protected]>
Simply use 'ingenic'.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
Cc: [email protected]
---
Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index d443279..d0ea910 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -78,6 +78,7 @@ ibm International Business Machines (IBM)
idt Integrated Device Technologies, Inc.
iom Iomega Corporation
img Imagination Technologies Ltd.
+ingenic Ingenic Semiconductor
innolux Innolux Corporation
intel Intel Corporation
intercontrol Inter Control Group
--
1.9.1
From: Paul Burton <[email protected]>
Require a DT for jz4740 based systems, and add a stub one for the
qi_lb60 (Ben NanoNote) board. Devices will be migrated to being probed
via this DT over time.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
---
arch/mips/Kconfig | 2 ++
arch/mips/boot/dts/Makefile | 1 +
arch/mips/boot/dts/jz4740.dtsi | 5 +++++
arch/mips/boot/dts/qi_lb60.dts | 7 +++++++
arch/mips/jz4740/setup.c | 19 +++++++++++++++++++
5 files changed, 34 insertions(+)
create mode 100644 arch/mips/boot/dts/jz4740.dtsi
create mode 100644 arch/mips/boot/dts/qi_lb60.dts
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 3289969..99d50cd 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -288,6 +288,8 @@ config MACH_JZ4740
select SYS_HAS_EARLY_PRINTK
select HAVE_CLK
select GENERIC_IRQ_CHIP
+ select BUILTIN_DTB
+ select USE_OF
config LANTIQ
bool "Lantiq based platforms"
diff --git a/arch/mips/boot/dts/Makefile b/arch/mips/boot/dts/Makefile
index 4f49fa4..a1127f3 100644
--- a/arch/mips/boot/dts/Makefile
+++ b/arch/mips/boot/dts/Makefile
@@ -9,6 +9,7 @@ dtb-$(CONFIG_DTB_RT2880_EVAL) += rt2880_eval.dtb
dtb-$(CONFIG_DTB_RT305X_EVAL) += rt3052_eval.dtb
dtb-$(CONFIG_DTB_RT3883_EVAL) += rt3883_eval.dtb
dtb-$(CONFIG_DTB_MT7620A_EVAL) += mt7620a_eval.dtb
+dtb-$(CONFIG_JZ4740_QI_LB60) += qi_lb60.dtb
dtb-$(CONFIG_MIPS_SEAD3) += sead3.dtb
obj-y += $(patsubst %.dtb, %.dtb.o, $(dtb-y))
diff --git a/arch/mips/boot/dts/jz4740.dtsi b/arch/mips/boot/dts/jz4740.dtsi
new file mode 100644
index 0000000..c538691f
--- /dev/null
+++ b/arch/mips/boot/dts/jz4740.dtsi
@@ -0,0 +1,5 @@
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "ingenic,jz4740";
+};
diff --git a/arch/mips/boot/dts/qi_lb60.dts b/arch/mips/boot/dts/qi_lb60.dts
new file mode 100644
index 0000000..0c0f639
--- /dev/null
+++ b/arch/mips/boot/dts/qi_lb60.dts
@@ -0,0 +1,7 @@
+/dts-v1/;
+
+#include "jz4740.dtsi"
+
+/ {
+ compatible = "qi,lb60", "ingenic,jz4740";
+};
diff --git a/arch/mips/jz4740/setup.c b/arch/mips/jz4740/setup.c
index ef796f9..d6bb7a3 100644
--- a/arch/mips/jz4740/setup.c
+++ b/arch/mips/jz4740/setup.c
@@ -17,8 +17,11 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
+#include <linux/of_fdt.h>
+#include <linux/of_platform.h>
#include <asm/bootinfo.h>
+#include <asm/prom.h>
#include <asm/mach-jz4740/base.h>
@@ -53,8 +56,24 @@ void __init plat_mem_setup(void)
{
jz4740_reset_init();
jz4740_detect_mem();
+ __dt_setup_arch(__dtb_start);
}
+void __init device_tree_init(void)
+{
+ if (!initial_boot_params)
+ return;
+
+ unflatten_and_copy_device_tree();
+}
+
+static int __init populate_machine(void)
+{
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+ return 0;
+}
+arch_initcall(populate_machine);
+
const char *get_system_type(void)
{
return "JZ4740";
--
1.9.1
From: Paul Burton <[email protected]>
Allow the MIPS CPU interrupt controller to be probed from DT using the
generic __irqchip_of_table for platforms which use irqchip_init. This
will avoid such platforms needing to duplicate the compatible string &
init function pointer.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
---
arch/mips/kernel/irq_cpu.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c
index 590c2c9..981d6a3 100644
--- a/arch/mips/kernel/irq_cpu.c
+++ b/arch/mips/kernel/irq_cpu.c
@@ -38,6 +38,8 @@
#include <asm/mipsmtregs.h>
#include <asm/setup.h>
+#include "../../drivers/irqchip/irqchip.h"
+
static inline void unmask_mips_irq(struct irq_data *d)
{
set_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE));
@@ -163,3 +165,4 @@ int __init mips_cpu_irq_of_init(struct device_node *of_node,
__mips_cpu_irq_init(of_node);
return 0;
}
+IRQCHIP_DECLARE(cpu_intc, "mti,cpu-interrupt-controller", mips_cpu_irq_of_init);
--
1.9.1
From: Paul Burton <[email protected]>
Use the generic irqchip_init function to probe irqchip drivers using DT,
and add the appropriate node to the jz4740 devicetree in place of the
call to mips_cpu_irq_init.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
---
arch/mips/boot/dts/jz4740.dtsi | 7 +++++++
arch/mips/jz4740/irq.c | 4 ++--
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/arch/mips/boot/dts/jz4740.dtsi b/arch/mips/boot/dts/jz4740.dtsi
index c538691f..2d64765c 100644
--- a/arch/mips/boot/dts/jz4740.dtsi
+++ b/arch/mips/boot/dts/jz4740.dtsi
@@ -2,4 +2,11 @@
#address-cells = <1>;
#size-cells = <1>;
compatible = "ingenic,jz4740";
+
+ cpuintc: cpuintc@0 {
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ compatible = "mti,cpu-interrupt-controller";
+ };
};
diff --git a/arch/mips/jz4740/irq.c b/arch/mips/jz4740/irq.c
index 2531da1..9c94f7b 100644
--- a/arch/mips/jz4740/irq.c
+++ b/arch/mips/jz4740/irq.c
@@ -18,6 +18,7 @@
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
+#include <linux/irqchip.h>
#include <linux/timex.h>
#include <linux/slab.h>
#include <linux/delay.h>
@@ -27,7 +28,6 @@
#include <asm/io.h>
#include <asm/mipsregs.h>
-#include <asm/irq_cpu.h>
#include <asm/mach-jz4740/base.h>
@@ -81,7 +81,7 @@ void __init arch_init_irq(void)
struct irq_chip_generic *gc;
struct irq_chip_type *ct;
- mips_cpu_irq_init();
+ irqchip_init();
jz_intc_base = ioremap(JZ4740_INTC_BASE_ADDR, 0x14);
--
1.9.1
From: Paul Burton <[email protected]>
Make use of the generic plat_irq_dispatch function introduced by commit
85f7cdacbb81 "MIPS: Provide a generic plat_irq_dispatch", in order to
reduce unnecessary code duplication.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
---
arch/mips/jz4740/irq.c | 12 ------------
1 file changed, 12 deletions(-)
diff --git a/arch/mips/jz4740/irq.c b/arch/mips/jz4740/irq.c
index 9c94f7b..999d64b 100644
--- a/arch/mips/jz4740/irq.c
+++ b/arch/mips/jz4740/irq.c
@@ -27,7 +27,6 @@
#include <linux/seq_file.h>
#include <asm/io.h>
-#include <asm/mipsregs.h>
#include <asm/mach-jz4740/base.h>
@@ -108,17 +107,6 @@ void __init arch_init_irq(void)
setup_irq(2, &jz4740_cascade_action);
}
-asmlinkage void plat_irq_dispatch(void)
-{
- unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
- if (pending & STATUSF_IP2)
- do_IRQ(2);
- else if (pending & STATUSF_IP3)
- do_IRQ(3);
- else
- spurious_interrupt();
-}
-
#ifdef CONFIG_DEBUG_FS
static inline void intc_seq_reg(struct seq_file *s, const char *name,
--
1.9.1
From: Paul Burton <[email protected]>
In preparation for moving the jz4740 interrupt controller driver to
drivers/irqchip, move arch_init_irq into setup.c such that everything
remaining in irq.c is related to said jz4740 interrupt controller.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
---
arch/mips/include/asm/mach-jz4740/irq.h | 2 ++
arch/mips/jz4740/irq.c | 5 +----
arch/mips/jz4740/setup.c | 8 ++++++++
3 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/arch/mips/include/asm/mach-jz4740/irq.h b/arch/mips/include/asm/mach-jz4740/irq.h
index df50736..5ce4302 100644
--- a/arch/mips/include/asm/mach-jz4740/irq.h
+++ b/arch/mips/include/asm/mach-jz4740/irq.h
@@ -54,4 +54,6 @@
#define NR_IRQS (JZ4740_IRQ_ADC_BASE + 6)
+extern void __init jz4740_intc_init(void);
+
#endif
diff --git a/arch/mips/jz4740/irq.c b/arch/mips/jz4740/irq.c
index 999d64b..1b742c3 100644
--- a/arch/mips/jz4740/irq.c
+++ b/arch/mips/jz4740/irq.c
@@ -18,7 +18,6 @@
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
-#include <linux/irqchip.h>
#include <linux/timex.h>
#include <linux/slab.h>
#include <linux/delay.h>
@@ -75,13 +74,11 @@ static struct irqaction jz4740_cascade_action = {
.name = "JZ4740 cascade interrupt",
};
-void __init arch_init_irq(void)
+void __init jz4740_intc_init(void)
{
struct irq_chip_generic *gc;
struct irq_chip_type *ct;
- irqchip_init();
-
jz_intc_base = ioremap(JZ4740_INTC_BASE_ADDR, 0x14);
/* Mask all irqs */
diff --git a/arch/mips/jz4740/setup.c b/arch/mips/jz4740/setup.c
index d6bb7a3..4808730 100644
--- a/arch/mips/jz4740/setup.c
+++ b/arch/mips/jz4740/setup.c
@@ -16,6 +16,7 @@
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/irqchip.h>
#include <linux/kernel.h>
#include <linux/of_fdt.h>
#include <linux/of_platform.h>
@@ -24,6 +25,7 @@
#include <asm/prom.h>
#include <asm/mach-jz4740/base.h>
+#include <asm/mach-jz4740/irq.h>
#include "reset.h"
@@ -78,3 +80,9 @@ const char *get_system_type(void)
{
return "JZ4740";
}
+
+void __init arch_init_irq(void)
+{
+ irqchip_init();
+ jz4740_intc_init();
+}
--
1.9.1
From: Paul Burton <[email protected]>
Add binding documentation for the Ingenic jz4740 interrupt controller.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
Cc: [email protected]
---
.../interrupt-controller/ingenic,jz4740-intc.txt | 26 ++++++++++++++++++++++
1 file changed, 26 insertions(+)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/ingenic,jz4740-intc.txt
diff --git a/Documentation/devicetree/bindings/interrupt-controller/ingenic,jz4740-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/ingenic,jz4740-intc.txt
new file mode 100644
index 0000000..5e7f4bb
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/ingenic,jz4740-intc.txt
@@ -0,0 +1,26 @@
+Ingenic jz4740 SoC Interrupt Controller
+
+Required properties:
+
+- compatible : should be "ingenic,jz4740-intc" or "ingenic,jz4780-intc"
+- reg : Specifies base physical address and size of the registers.
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+ interrupt source. The value shall be 1.
+- interrupts - Specifies the CPU interrupt the controller is connected to.
+
+Optional properties:
+- interrupt-parent: phandle of the CPU interrupt controller.
+
+Example:
+
+intc: intc@10001000 {
+ compatible = "ingenic,jz4740-intc";
+ reg = <0x10001000 0x14>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpuintc>;
+ interrupts = <2>;
+};
--
1.9.1
From: Paul Burton <[email protected]>
Declare the interrupt controller for probe via the standard irqchip_init
function.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
---
arch/mips/jz4740/irq.c | 26 ++++++++++++++++++++++++--
1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/arch/mips/jz4740/irq.c b/arch/mips/jz4740/irq.c
index 1b742c3..a4f0a82 100644
--- a/arch/mips/jz4740/irq.c
+++ b/arch/mips/jz4740/irq.c
@@ -18,6 +18,7 @@
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
+#include <linux/of_irq.h>
#include <linux/timex.h>
#include <linux/slab.h>
#include <linux/delay.h>
@@ -29,6 +30,8 @@
#include <asm/mach-jz4740/base.h>
+#include "../../drivers/irqchip/irqchip.h"
+
static void __iomem *jz_intc_base;
#define JZ_REG_INTC_STATUS 0x00
@@ -74,7 +77,7 @@ static struct irqaction jz4740_cascade_action = {
.name = "JZ4740 cascade interrupt",
};
-void __init jz4740_intc_init(void)
+static void __init __jz4740_intc_init(int parent_irq)
{
struct irq_chip_generic *gc;
struct irq_chip_type *ct;
@@ -101,8 +104,27 @@ void __init jz4740_intc_init(void)
irq_setup_generic_chip(gc, IRQ_MSK(32), 0, 0, IRQ_NOPROBE | IRQ_LEVEL);
- setup_irq(2, &jz4740_cascade_action);
+ setup_irq(parent_irq, &jz4740_cascade_action);
+}
+
+void __init jz4740_intc_init(void)
+{
+ __jz4740_intc_init(2);
+}
+
+static int __init jz4740_intc_of_init(struct device_node *node,
+ struct device_node *parent)
+{
+ int parent_irq;
+
+ parent_irq = irq_of_parse_and_map(node, 0);
+ if (!parent_irq)
+ return -EINVAL;
+
+ __jz4740_intc_init(parent_irq);
+ return 0;
}
+IRQCHIP_DECLARE(jz4740_intc, "ingenic,jz4740-intc", jz4740_intc_of_init);
#ifdef CONFIG_DEBUG_FS
--
1.9.1
From: Paul Burton <[email protected]>
Add the appropriate DT node to probe the interrupt controller driver
using the devicetree, and remove the call to jz4740_intc_init.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
---
arch/mips/boot/dts/jz4740.dtsi | 11 +++++++++++
arch/mips/jz4740/setup.c | 2 --
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/arch/mips/boot/dts/jz4740.dtsi b/arch/mips/boot/dts/jz4740.dtsi
index 2d64765c..3841024 100644
--- a/arch/mips/boot/dts/jz4740.dtsi
+++ b/arch/mips/boot/dts/jz4740.dtsi
@@ -9,4 +9,15 @@
interrupt-controller;
compatible = "mti,cpu-interrupt-controller";
};
+
+ intc: intc@10001000 {
+ compatible = "ingenic,jz4740-intc";
+ reg = <0x10001000 0x14>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpuintc>;
+ interrupts = <2>;
+ };
};
diff --git a/arch/mips/jz4740/setup.c b/arch/mips/jz4740/setup.c
index 4808730..8c08d7d 100644
--- a/arch/mips/jz4740/setup.c
+++ b/arch/mips/jz4740/setup.c
@@ -25,7 +25,6 @@
#include <asm/prom.h>
#include <asm/mach-jz4740/base.h>
-#include <asm/mach-jz4740/irq.h>
#include "reset.h"
@@ -84,5 +83,4 @@ const char *get_system_type(void)
void __init arch_init_irq(void)
{
irqchip_init();
- jz4740_intc_init();
}
--
1.9.1
From: Paul Burton <[email protected]>
The jz4740 now probes the interrupt controller using DT, so remove the
now dead non-DT init code.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
---
arch/mips/include/asm/mach-jz4740/irq.h | 2 --
arch/mips/jz4740/irq.c | 25 +++++++------------------
2 files changed, 7 insertions(+), 20 deletions(-)
diff --git a/arch/mips/include/asm/mach-jz4740/irq.h b/arch/mips/include/asm/mach-jz4740/irq.h
index 5ce4302..df50736 100644
--- a/arch/mips/include/asm/mach-jz4740/irq.h
+++ b/arch/mips/include/asm/mach-jz4740/irq.h
@@ -54,6 +54,4 @@
#define NR_IRQS (JZ4740_IRQ_ADC_BASE + 6)
-extern void __init jz4740_intc_init(void);
-
#endif
diff --git a/arch/mips/jz4740/irq.c b/arch/mips/jz4740/irq.c
index a4f0a82..9a8bda3 100644
--- a/arch/mips/jz4740/irq.c
+++ b/arch/mips/jz4740/irq.c
@@ -77,10 +77,16 @@ static struct irqaction jz4740_cascade_action = {
.name = "JZ4740 cascade interrupt",
};
-static void __init __jz4740_intc_init(int parent_irq)
+static int __init jz4740_intc_of_init(struct device_node *node,
+ struct device_node *parent)
{
struct irq_chip_generic *gc;
struct irq_chip_type *ct;
+ int parent_irq;
+
+ parent_irq = irq_of_parse_and_map(node, 0);
+ if (!parent_irq)
+ return -EINVAL;
jz_intc_base = ioremap(JZ4740_INTC_BASE_ADDR, 0x14);
@@ -105,23 +111,6 @@ static void __init __jz4740_intc_init(int parent_irq)
irq_setup_generic_chip(gc, IRQ_MSK(32), 0, 0, IRQ_NOPROBE | IRQ_LEVEL);
setup_irq(parent_irq, &jz4740_cascade_action);
-}
-
-void __init jz4740_intc_init(void)
-{
- __jz4740_intc_init(2);
-}
-
-static int __init jz4740_intc_of_init(struct device_node *node,
- struct device_node *parent)
-{
- int parent_irq;
-
- parent_irq = irq_of_parse_and_map(node, 0);
- if (!parent_irq)
- return -EINVAL;
-
- __jz4740_intc_init(parent_irq);
return 0;
}
IRQCHIP_DECLARE(jz4740_intc, "ingenic,jz4740-intc", jz4740_intc_of_init);
--
1.9.1
From: Paul Burton <[email protected]>
When probining the interrupt controller, register an IRQ domain such
that the interrupts can be translated by devicetree code & thus used
from devicetree.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
---
arch/mips/jz4740/irq.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/mips/jz4740/irq.c b/arch/mips/jz4740/irq.c
index 9a8bda3..a620b23 100644
--- a/arch/mips/jz4740/irq.c
+++ b/arch/mips/jz4740/irq.c
@@ -82,6 +82,7 @@ static int __init jz4740_intc_of_init(struct device_node *node,
{
struct irq_chip_generic *gc;
struct irq_chip_type *ct;
+ struct irq_domain *domain;
int parent_irq;
parent_irq = irq_of_parse_and_map(node, 0);
@@ -110,6 +111,11 @@ static int __init jz4740_intc_of_init(struct device_node *node,
irq_setup_generic_chip(gc, IRQ_MSK(32), 0, 0, IRQ_NOPROBE | IRQ_LEVEL);
+ domain = irq_domain_add_legacy(node, num_chips * 32, JZ4740_IRQ_BASE, 0,
+ &irq_domain_simple_ops, NULL);
+ if (!domain)
+ pr_warn("unable to register IRQ domain\n");
+
setup_irq(parent_irq, &jz4740_cascade_action);
return 0;
}
--
1.9.1
From: Paul Burton <[email protected]>
Call jz4740_clock_init before any uses of jz4740_clock_bdata occur. This
is in preparation for replacing uses of that struct with calls to
clk_get_rate, which will allow the clocks to be migrated towards common
clock framework & devicetree.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
---
arch/mips/include/asm/mach-jz4740/clock.h | 2 ++
arch/mips/jz4740/clock.c | 3 +--
arch/mips/jz4740/time.c | 2 ++
3 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/arch/mips/include/asm/mach-jz4740/clock.h b/arch/mips/include/asm/mach-jz4740/clock.h
index 16659cd..01d8468 100644
--- a/arch/mips/include/asm/mach-jz4740/clock.h
+++ b/arch/mips/include/asm/mach-jz4740/clock.h
@@ -20,6 +20,8 @@ enum jz4740_wait_mode {
JZ4740_WAIT_MODE_SLEEP,
};
+int jz4740_clock_init(void);
+
void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode);
void jz4740_clock_udc_enable_auto_suspend(void);
diff --git a/arch/mips/jz4740/clock.c b/arch/mips/jz4740/clock.c
index 1b5f554..c257073 100644
--- a/arch/mips/jz4740/clock.c
+++ b/arch/mips/jz4740/clock.c
@@ -889,7 +889,7 @@ void jz4740_clock_resume(void)
JZ_CLOCK_GATE_TCU | JZ_CLOCK_GATE_DMAC | JZ_CLOCK_GATE_UART0);
}
-static int jz4740_clock_init(void)
+int jz4740_clock_init(void)
{
uint32_t val;
@@ -921,4 +921,3 @@ static int jz4740_clock_init(void)
return 0;
}
-arch_initcall(jz4740_clock_init);
diff --git a/arch/mips/jz4740/time.c b/arch/mips/jz4740/time.c
index 5e430ce..9424344 100644
--- a/arch/mips/jz4740/time.c
+++ b/arch/mips/jz4740/time.c
@@ -19,6 +19,7 @@
#include <linux/clockchips.h>
+#include <asm/mach-jz4740/clock.h>
#include <asm/mach-jz4740/irq.h>
#include <asm/mach-jz4740/timer.h>
#include <asm/time.h>
@@ -109,6 +110,7 @@ void __init plat_time_init(void)
uint32_t clk_rate;
uint16_t ctrl;
+ jz4740_clock_init();
jz4740_timer_init();
clk_rate = jz4740_clock_bdata.ext_rate >> 4;
--
1.9.1
From: Paul Burton <[email protected]>
Replace uses of the jz4740_clock_bdata struct with calls to clk_get_rate
for the appropriate clock. This is in preparation for migrating the
clocks towards common clock framework & devicetree.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
---
arch/mips/jz4740/platform.c | 11 ++++++++++-
arch/mips/jz4740/reset.c | 13 +++++++++++--
arch/mips/jz4740/time.c | 9 ++++++++-
3 files changed, 29 insertions(+), 4 deletions(-)
diff --git a/arch/mips/jz4740/platform.c b/arch/mips/jz4740/platform.c
index 0b12f27..2a5c7c7 100644
--- a/arch/mips/jz4740/platform.c
+++ b/arch/mips/jz4740/platform.c
@@ -13,6 +13,7 @@
*
*/
+#include <linux/clk.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
@@ -308,9 +309,17 @@ static struct platform_device jz4740_uart_device = {
void jz4740_serial_device_register(void)
{
struct plat_serial8250_port *p;
+ struct clk *ext_clk;
+ unsigned long ext_rate;
+
+ ext_clk = clk_get(NULL, "ext");
+ if (IS_ERR(ext_clk))
+ panic("unable to get ext clock");
+ ext_rate = clk_get_rate(ext_clk);
+ clk_put(ext_clk);
for (p = jz4740_uart_data; p->flags != 0; ++p)
- p->uartclk = jz4740_clock_bdata.ext_rate;
+ p->uartclk = ext_rate;
platform_device_register(&jz4740_uart_device);
}
diff --git a/arch/mips/jz4740/reset.c b/arch/mips/jz4740/reset.c
index b6c6343..954e669 100644
--- a/arch/mips/jz4740/reset.c
+++ b/arch/mips/jz4740/reset.c
@@ -12,6 +12,7 @@
*
*/
+#include <linux/clk.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/pm.h>
@@ -79,12 +80,20 @@ static void jz4740_power_off(void)
void __iomem *rtc_base = ioremap(JZ4740_RTC_BASE_ADDR, 0x38);
unsigned long wakeup_filter_ticks;
unsigned long reset_counter_ticks;
+ struct clk *rtc_clk;
+ unsigned long rtc_rate;
+
+ rtc_clk = clk_get(NULL, "rtc");
+ if (IS_ERR(rtc_clk))
+ panic("unable to get RTC clock");
+ rtc_rate = clk_get_rate(rtc_clk);
+ clk_put(rtc_clk);
/*
* Set minimum wakeup pin assertion time: 100 ms.
* Range is 0 to 2 sec if RTC is clocked at 32 kHz.
*/
- wakeup_filter_ticks = (100 * jz4740_clock_bdata.rtc_rate) / 1000;
+ wakeup_filter_ticks = (100 * rtc_rate) / 1000;
if (wakeup_filter_ticks < JZ_RTC_WAKEUP_FILTER_MASK)
wakeup_filter_ticks &= JZ_RTC_WAKEUP_FILTER_MASK;
else
@@ -96,7 +105,7 @@ static void jz4740_power_off(void)
* Set reset pin low-level assertion time after wakeup: 60 ms.
* Range is 0 to 125 ms if RTC is clocked at 32 kHz.
*/
- reset_counter_ticks = (60 * jz4740_clock_bdata.rtc_rate) / 1000;
+ reset_counter_ticks = (60 * rtc_rate) / 1000;
if (reset_counter_ticks < JZ_RTC_RESET_COUNTER_MASK)
reset_counter_ticks &= JZ_RTC_RESET_COUNTER_MASK;
else
diff --git a/arch/mips/jz4740/time.c b/arch/mips/jz4740/time.c
index 9424344..bff2ac9 100644
--- a/arch/mips/jz4740/time.c
+++ b/arch/mips/jz4740/time.c
@@ -13,6 +13,7 @@
*
*/
+#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/time.h>
@@ -109,11 +110,17 @@ void __init plat_time_init(void)
int ret;
uint32_t clk_rate;
uint16_t ctrl;
+ struct clk *ext_clk;
jz4740_clock_init();
jz4740_timer_init();
- clk_rate = jz4740_clock_bdata.ext_rate >> 4;
+ ext_clk = clk_get(NULL, "ext");
+ if (IS_ERR(ext_clk))
+ panic("unable to get ext clock");
+ clk_rate = clk_get_rate(ext_clk) >> 4;
+ clk_put(ext_clk);
+
jz4740_jiffies_per_tick = DIV_ROUND_CLOSEST(clk_rate, HZ);
clockevent_set_clock(&jz4740_clockevent, clk_rate);
--
1.9.1
From: Paul Burton <[email protected]>
This driver supports the CGU clocks for the Ingenic jz47xx series of
SoCs. It is generic enough to be usable across at least the jz4740 to
the jz4780, as will be done in subsequent commits.
Signed-off-by: Paul Burton <[email protected]>
Co-authored-by: Paul Cercueil <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
Cc: Mike Turquette <[email protected]>
---
V2
Removed FSF address
Bug fix in error handling
---
drivers/clk/Makefile | 1 +
drivers/clk/jz47xx/Makefile | 1 +
drivers/clk/jz47xx/jz47xx-cgu.c | 723 ++++++++++++++++++++++++++++++++++++++++
drivers/clk/jz47xx/jz47xx-cgu.h | 205 ++++++++++++
4 files changed, 930 insertions(+)
create mode 100644 drivers/clk/jz47xx/Makefile
create mode 100644 drivers/clk/jz47xx/jz47xx-cgu.c
create mode 100644 drivers/clk/jz47xx/jz47xx-cgu.h
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index d5fba5b..fc434c0 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_ARCH_BERLIN) += berlin/
obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/
obj-$(CONFIG_ARCH_HIP04) += hisilicon/
obj-$(CONFIG_ARCH_HIX5HD2) += hisilicon/
+obj-$(CONFIG_MACH_JZ4740) += jz47xx/
obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/
ifeq ($(CONFIG_COMMON_CLK), y)
obj-$(CONFIG_ARCH_MMP) += mmp/
diff --git a/drivers/clk/jz47xx/Makefile b/drivers/clk/jz47xx/Makefile
new file mode 100644
index 0000000..ac594e5
--- /dev/null
+++ b/drivers/clk/jz47xx/Makefile
@@ -0,0 +1 @@
+obj-y += jz47xx-cgu.o
diff --git a/drivers/clk/jz47xx/jz47xx-cgu.c b/drivers/clk/jz47xx/jz47xx-cgu.c
new file mode 100644
index 0000000..85d0592
--- /dev/null
+++ b/drivers/clk/jz47xx/jz47xx-cgu.c
@@ -0,0 +1,723 @@
+/*
+ * Ingenic jz47xx series CGU driver
+ *
+ * Copyright (c) 2013-2015 Imagination Technologies
+ * Author: Paul Burton <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include "jz47xx-cgu.h"
+
+#define REG_CLKGR 0x20
+#define REG_CLKGR_STRIDE 0x8
+
+#define MHZ (1000 * 1000)
+
+/**
+ * jz47xx_cgu_gate_get - get the value of clock gate register bit
+ * @cgu: reference to the CGU whose registers should be read
+ * @idx: index of the gate bit
+ *
+ * Returns 1 if the gate bit is set, else 0. The index begins with 0 being
+ * bit 0 of CLKGR0, continuing from 32 for bit 0 of CLKGR1 etc. For example,
+ * the index of bit 9 of CLKGR1 would be (32+9) == 41.
+ *
+ * The caller must hold cgu->power_lock.
+ */
+static inline unsigned jz47xx_cgu_gate_get(struct jz47xx_cgu *cgu,
+ unsigned idx)
+{
+ void __iomem *reg;
+ u32 bit, clkgr;
+
+ reg = cgu->base + REG_CLKGR + ((idx / 32) * REG_CLKGR_STRIDE);
+ bit = 1 << (idx % 32);
+ clkgr = readl(reg);
+ return !!(clkgr & bit);
+}
+
+/**
+ * jz47xx_cgu_gate_set - set the value of clock gate register bit
+ * @cgu: reference to the CGU whose registers should be modified
+ * @idx: index of the gate bit
+ * @val: non-zero to gate a clock, otherwise zero
+ *
+ * Sets the given gate bit in order to gate or ungate a clock. See
+ * jz47xx_cgu_gate_get for a description of the idx parameter.
+ *
+ * The caller must hold cgu->power_lock.
+ */
+static inline void jz47xx_cgu_gate_set(struct jz47xx_cgu *cgu,
+ unsigned idx, unsigned val)
+{
+ void __iomem *reg;
+ u32 bit, clkgr;
+
+ reg = cgu->base + REG_CLKGR + ((idx / 32) * REG_CLKGR_STRIDE);
+ bit = 1 << (idx % 32);
+ clkgr = readl(reg);
+
+ if (val)
+ clkgr |= bit;
+ else
+ clkgr &= ~bit;
+
+ writel(clkgr, reg);
+}
+
+/*
+ * PLL operations
+ */
+
+static unsigned long jz47xx_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct jz47xx_clk *jz_clk = to_jz47xx_clk(hw);
+ struct jz47xx_cgu *cgu = jz_clk->cgu;
+ const struct jz47xx_cgu_clk_info *clk_info;
+ const struct jz47xx_cgu_pll_info *pll_info;
+ unsigned m, n, od_enc, od;
+ bool bypass, enable;
+ unsigned long flags;
+ u32 ctl;
+
+ clk_info = &cgu->clock_info[jz_clk->idx];
+ BUG_ON(clk_info->type != CGU_CLK_PLL);
+ pll_info = &clk_info->pll;
+
+ spin_lock_irqsave(&cgu->pll_lock, flags);
+ ctl = readl(cgu->base + pll_info->reg);
+ spin_unlock_irqrestore(&cgu->pll_lock, flags);
+
+ m = ((ctl >> pll_info->m_shift) & GENMASK(pll_info->m_bits - 1, 0));
+ m += pll_info->m_offset;
+ n = ((ctl >> pll_info->n_shift) & GENMASK(pll_info->n_bits - 1, 0));
+ n += pll_info->n_offset;
+ od_enc = ((ctl >> pll_info->od_shift)
+ & GENMASK(pll_info->od_bits - 1, 0));
+ bypass = !!(ctl & BIT(pll_info->bypass_bit));
+ enable = !!(ctl & BIT(pll_info->enable_bit));
+
+ if (bypass)
+ return parent_rate;
+
+ if (!enable)
+ return 0;
+
+ for (od = 0; od < pll_info->od_max; od++) {
+ if (pll_info->od_encoding[od] == od_enc)
+ break;
+ }
+ BUG_ON(od == pll_info->od_max);
+ od++;
+
+ return parent_rate * m / (n * od);
+}
+
+static unsigned long jz47xx_pll_calc(const struct jz47xx_cgu_clk_info *clk_info,
+ unsigned long rate,
+ unsigned long parent_rate,
+ unsigned *pm, unsigned *pn, unsigned *pod)
+{
+ unsigned m, n, od;
+
+ /* deal with MHz */
+ rate -= (rate % MHZ);
+
+ m = rate / MHZ;
+ m = min_t(unsigned, m, 1 << clk_info->pll.m_bits);
+ m = max_t(unsigned, m, 1);
+
+ n = parent_rate / MHZ;
+ n = min_t(unsigned, n, 1 << clk_info->pll.n_bits);
+ n = max_t(unsigned, n, 1);
+
+ od = 1;
+
+ if (pm)
+ *pm = m;
+ if (pn)
+ *pn = n;
+ if (pod)
+ *pod = od;
+
+ return parent_rate * m / (n * od);
+}
+
+static long jz47xx_pll_round_rate(struct clk_hw *hw, unsigned long req_rate,
+ unsigned long *prate)
+{
+ struct jz47xx_clk *jz_clk = to_jz47xx_clk(hw);
+ struct jz47xx_cgu *cgu = jz_clk->cgu;
+ const struct jz47xx_cgu_clk_info *clk_info;
+
+ clk_info = &cgu->clock_info[jz_clk->idx];
+ BUG_ON(clk_info->type != CGU_CLK_PLL);
+
+ return jz47xx_pll_calc(clk_info, req_rate, *prate, NULL, NULL, NULL);
+}
+
+static int jz47xx_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
+ unsigned long parent_rate)
+{
+ const unsigned timeout = 100;
+ struct jz47xx_clk *jz_clk = to_jz47xx_clk(hw);
+ struct jz47xx_cgu *cgu = jz_clk->cgu;
+ const struct jz47xx_cgu_clk_info *clk_info;
+ const struct jz47xx_cgu_pll_info *pll_info;
+ unsigned long rate, flags;
+ unsigned m, n, od, i;
+ u32 ctl;
+
+ clk_info = &cgu->clock_info[jz_clk->idx];
+ BUG_ON(clk_info->type != CGU_CLK_PLL);
+ pll_info = &clk_info->pll;
+
+ rate = jz47xx_pll_calc(clk_info, req_rate, parent_rate,
+ &m, &n, &od);
+ if (rate != req_rate) {
+ pr_info("jz47xx-cgu: request '%s' rate %luHz, actual %luHz\n",
+ clk_info->name, req_rate, rate);
+ }
+
+ spin_lock_irqsave(&cgu->pll_lock, flags);
+ ctl = readl(cgu->base + pll_info->reg);
+
+ ctl &= ~(GENMASK(pll_info->m_bits - 1, 0) << pll_info->m_shift);
+ ctl |= (m - pll_info->m_offset) << pll_info->m_shift;
+
+ ctl &= ~(GENMASK(pll_info->n_bits - 1, 0) << pll_info->n_shift);
+ ctl |= (n - pll_info->n_offset) << pll_info->n_shift;
+
+ ctl &= ~(GENMASK(pll_info->od_bits - 1, 0) << pll_info->od_shift);
+ ctl |= pll_info->od_encoding[od - 1] << pll_info->od_shift;
+
+ ctl &= ~BIT(pll_info->bypass_bit);
+ ctl |= BIT(pll_info->enable_bit);
+
+ writel(ctl, cgu->base + pll_info->reg);
+
+ /* wait for the PLL to stabilise */
+ for (i = 0; i < timeout; i++) {
+ if (readl(cgu->base + pll_info->reg)
+ & BIT(pll_info->stable_bit))
+ break;
+ mdelay(1);
+ }
+
+ spin_unlock_irqrestore(&cgu->pll_lock, flags);
+
+ if (i == timeout)
+ return -EBUSY;
+
+ return 0;
+}
+
+static const struct clk_ops jz47xx_pll_ops = {
+ .recalc_rate = jz47xx_pll_recalc_rate,
+ .round_rate = jz47xx_pll_round_rate,
+ .set_rate = jz47xx_pll_set_rate,
+};
+
+/*
+ * Operations for all non-PLL clocks
+ */
+
+static u8 jz47xx_clk_get_parent(struct clk_hw *hw)
+{
+ struct jz47xx_clk *jz_clk = to_jz47xx_clk(hw);
+ struct jz47xx_cgu *cgu = jz_clk->cgu;
+ const struct jz47xx_cgu_clk_info *clk_info;
+ u32 reg;
+ u8 i, hw_idx, idx = 0;
+
+ clk_info = &cgu->clock_info[jz_clk->idx];
+
+ if (clk_info->type & CGU_CLK_MUX) {
+ reg = readl(cgu->base + clk_info->mux.reg);
+ hw_idx = (reg >> clk_info->mux.shift) &
+ ((1 << clk_info->mux.bits) - 1);
+
+ /*
+ * Convert the hardware index to the parent index by skipping
+ * over any -1's in the parents array.
+ */
+ for (i = 0; i < hw_idx; i++) {
+ if (clk_info->parents[i] != -1)
+ idx++;
+ }
+ }
+
+ return idx;
+}
+
+static int jz47xx_clk_set_parent(struct clk_hw *hw, u8 idx)
+{
+ struct jz47xx_clk *jz_clk = to_jz47xx_clk(hw);
+ struct jz47xx_cgu *cgu = jz_clk->cgu;
+ const struct jz47xx_cgu_clk_info *clk_info;
+ unsigned long flags;
+ u8 curr_idx, hw_idx, num_poss;
+ u32 reg, mask;
+
+ clk_info = &cgu->clock_info[jz_clk->idx];
+
+ if (clk_info->type & CGU_CLK_MUX) {
+ /*
+ * Convert the parent index to the hardware index by adding
+ * 1 for any -1 in the parents array preceeding the given
+ * index. That is, we want the index of idx'th entry in
+ * clk_info->parents which does not equal -1.
+ */
+ hw_idx = curr_idx = 0;
+ num_poss = 1 << clk_info->mux.bits;
+ for (; (hw_idx < num_poss) && (curr_idx != idx); hw_idx++) {
+ if (clk_info->parents[hw_idx] == -1)
+ continue;
+ curr_idx++;
+ }
+
+ /* idx should always be a valid parent */
+ BUG_ON(curr_idx != idx);
+
+ mask = ((1 << clk_info->mux.bits) - 1) << clk_info->mux.shift;
+
+ spin_lock_irqsave(&cgu->divmux_lock, flags);
+
+ /* write the register */
+ reg = readl(cgu->base + clk_info->mux.reg);
+ reg &= ~mask;
+ reg |= hw_idx << clk_info->mux.shift;
+ writel(reg, cgu->base + clk_info->mux.reg);
+
+ spin_unlock_irqrestore(&cgu->divmux_lock, flags);
+ return 0;
+ }
+
+ return idx ? -EINVAL : 0;
+}
+
+static unsigned long jz47xx_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct jz47xx_clk *jz_clk = to_jz47xx_clk(hw);
+ struct jz47xx_cgu *cgu = jz_clk->cgu;
+ const struct jz47xx_cgu_clk_info *clk_info;
+ unsigned long rate = parent_rate;
+ u32 div_reg, div;
+
+ clk_info = &cgu->clock_info[jz_clk->idx];
+
+ if (clk_info->type & CGU_CLK_DIV) {
+ div_reg = readl(cgu->base + clk_info->div.reg);
+ div = (div_reg >> clk_info->div.shift) &
+ ((1 << clk_info->div.bits) - 1);
+ div += 1;
+
+ rate /= div;
+ }
+
+ return rate;
+}
+
+static unsigned jz47xx_clk_calc_div(const struct jz47xx_cgu_clk_info *clk_info,
+ unsigned long parent_rate,
+ unsigned long req_rate)
+{
+ unsigned div;
+
+ /* calculate the divide that gets us closest */
+ div = DIV_ROUND_CLOSEST(parent_rate, req_rate);
+
+ /* and impose hardware constraints */
+ div = min_t(unsigned, div, 1 << clk_info->div.bits);
+ div = max_t(unsigned, div, 1);
+
+ return div;
+}
+
+static long jz47xx_clk_round_rate(struct clk_hw *hw, unsigned long req_rate,
+ unsigned long *parent_rate)
+{
+ struct jz47xx_clk *jz_clk = to_jz47xx_clk(hw);
+ struct jz47xx_cgu *cgu = jz_clk->cgu;
+ const struct jz47xx_cgu_clk_info *clk_info;
+ long rate = req_rate;
+ unsigned div;
+
+ clk_info = &cgu->clock_info[jz_clk->idx];
+
+ if (clk_info->type & CGU_CLK_DIV) {
+ div = jz47xx_clk_calc_div(clk_info, *parent_rate, req_rate);
+ rate = *parent_rate / div;
+ }
+
+ return rate;
+}
+
+static int jz47xx_clk_set_rate(struct clk_hw *hw, unsigned long req_rate,
+ unsigned long parent_rate)
+{
+ struct jz47xx_clk *jz_clk = to_jz47xx_clk(hw);
+ struct jz47xx_cgu *cgu = jz_clk->cgu;
+ const struct jz47xx_cgu_clk_info *clk_info;
+ const unsigned timeout = 100;
+ unsigned long rate, flags;
+ unsigned div, i;
+ u32 reg, mask;
+ int ret = 0;
+
+ clk_info = &cgu->clock_info[jz_clk->idx];
+
+ if (clk_info->type & CGU_CLK_DIV) {
+ div = jz47xx_clk_calc_div(clk_info, parent_rate, req_rate);
+ rate = parent_rate / div;
+
+ if (rate != req_rate)
+ return -EINVAL;
+
+ spin_lock_irqsave(&cgu->divmux_lock, flags);
+ reg = readl(cgu->base + clk_info->div.reg);
+
+ /* update the divide */
+ mask = (1 << clk_info->div.bits) - 1;
+ reg &= ~(mask << clk_info->div.shift);
+ reg |= (div - 1) << clk_info->div.shift;
+
+ /* clear the stop bit */
+ if (clk_info->div.stop_bit != -1)
+ reg &= ~(1 << clk_info->div.stop_bit);
+
+ /* set the change enable bit */
+ if (clk_info->div.ce_bit != -1)
+ reg |= 1 << clk_info->div.ce_bit;
+
+ /* update the hardware */
+ writel(reg, cgu->base + clk_info->div.reg);
+
+ /* wait for the change to take effect */
+ if (clk_info->div.busy_bit != -1) {
+ for (i = 0; i < timeout; i++) {
+ reg = readl(cgu->base + clk_info->div.reg);
+ if (!(reg & (1 << clk_info->div.busy_bit)))
+ break;
+ mdelay(1);
+ }
+ if (i == timeout)
+ ret = -EBUSY;
+ }
+
+ spin_unlock_irqrestore(&cgu->divmux_lock, flags);
+
+ return ret;
+ }
+
+ return -EINVAL;
+}
+
+static int jz47xx_clk_enable(struct clk_hw *hw)
+{
+ struct jz47xx_clk *jz_clk = to_jz47xx_clk(hw);
+ struct jz47xx_cgu *cgu = jz_clk->cgu;
+ const struct jz47xx_cgu_clk_info *clk_info;
+ unsigned long flags;
+
+ clk_info = &cgu->clock_info[jz_clk->idx];
+
+ if (clk_info->type & CGU_CLK_GATE) {
+ /* ungate the clock */
+ spin_lock_irqsave(&cgu->power_lock, flags);
+ jz47xx_cgu_gate_set(cgu, clk_info->gate_bit, 0);
+ spin_unlock_irqrestore(&cgu->power_lock, flags);
+ }
+
+ return 0;
+}
+
+static void jz47xx_clk_disable(struct clk_hw *hw)
+{
+ struct jz47xx_clk *jz_clk = to_jz47xx_clk(hw);
+ struct jz47xx_cgu *cgu = jz_clk->cgu;
+ const struct jz47xx_cgu_clk_info *clk_info;
+ unsigned long flags;
+
+ clk_info = &cgu->clock_info[jz_clk->idx];
+
+ if (clk_info->type & CGU_CLK_GATE) {
+ /* gate the clock */
+ spin_lock_irqsave(&cgu->power_lock, flags);
+ jz47xx_cgu_gate_set(cgu, clk_info->gate_bit, 1);
+ spin_unlock_irqrestore(&cgu->power_lock, flags);
+ }
+}
+
+static int jz47xx_clk_is_enabled(struct clk_hw *hw)
+{
+ struct jz47xx_clk *jz_clk = to_jz47xx_clk(hw);
+ struct jz47xx_cgu *cgu = jz_clk->cgu;
+ const struct jz47xx_cgu_clk_info *clk_info;
+ unsigned long flags;
+ int enabled = 1;
+
+ clk_info = &cgu->clock_info[jz_clk->idx];
+
+ if (clk_info->type & CGU_CLK_GATE) {
+ spin_lock_irqsave(&cgu->power_lock, flags);
+ enabled = !jz47xx_cgu_gate_get(cgu, clk_info->gate_bit);
+ spin_unlock_irqrestore(&cgu->power_lock, flags);
+ }
+
+ return enabled;
+}
+
+static const struct clk_ops jz47xx_clk_ops = {
+ .get_parent = jz47xx_clk_get_parent,
+ .set_parent = jz47xx_clk_set_parent,
+
+ .recalc_rate = jz47xx_clk_recalc_rate,
+ .round_rate = jz47xx_clk_round_rate,
+ .set_rate = jz47xx_clk_set_rate,
+
+ .enable = jz47xx_clk_enable,
+ .disable = jz47xx_clk_disable,
+ .is_enabled = jz47xx_clk_is_enabled,
+};
+
+/*
+ * Setup functions.
+ */
+
+static int register_clock(struct jz47xx_cgu *cgu, unsigned idx)
+{
+ const struct jz47xx_cgu_clk_info *clk_info = &cgu->clock_info[idx];
+ struct clk_init_data clk_init;
+ struct jz47xx_clk *jz_clk = NULL;
+ struct clk *clk, *parent;
+ const char *parent_names[4];
+ unsigned caps, i, num_possible;
+ int err = -EINVAL;
+
+ BUILD_BUG_ON(ARRAY_SIZE(clk_info->parents) > ARRAY_SIZE(parent_names));
+
+ if (clk_info->type == CGU_CLK_EXT) {
+ clk = of_clk_get_by_name(cgu->np, clk_info->name);
+ if (IS_ERR(clk)) {
+ pr_err("%s: no external clock '%s' provided\n",
+ __func__, clk_info->name);
+ err = -ENODEV;
+ goto out;
+ }
+ err = clk_register_clkdev(clk, clk_info->name, NULL);
+ if (err) {
+ clk_put(clk);
+ goto out;
+ }
+ cgu->clocks.clks[idx] = clk;
+ return 0;
+ }
+
+ if (!clk_info->type) {
+ pr_err("%s: no clock type specified for '%s'\n", __func__,
+ clk_info->name);
+ goto out;
+ }
+
+ jz_clk = kzalloc(sizeof(*jz_clk), GFP_KERNEL);
+ if (!jz_clk) {
+ pr_err("%s: failed to allocate struct jz47xx_clk\n", __func__);
+ err = -ENOMEM;
+ goto out;
+ }
+
+ jz_clk->hw.init = &clk_init;
+ jz_clk->cgu = cgu;
+ jz_clk->idx = idx;
+
+ clk_init.name = clk_info->name;
+ clk_init.flags = 0;
+ clk_init.parent_names = parent_names;
+
+ caps = clk_info->type;
+
+ if (caps & (CGU_CLK_MUX | CGU_CLK_CUSTOM)) {
+ clk_init.num_parents = 0;
+
+ if (caps & CGU_CLK_MUX)
+ num_possible = 1 << clk_info->mux.bits;
+ else
+ num_possible = ARRAY_SIZE(clk_info->parents);
+
+ for (i = 0; i < num_possible; i++) {
+ if (clk_info->parents[i] == -1)
+ continue;
+
+ parent = cgu->clocks.clks[clk_info->parents[i]];
+ parent_names[clk_init.num_parents] =
+ __clk_get_name(parent);
+ clk_init.num_parents++;
+ }
+
+ BUG_ON(!clk_init.num_parents);
+ BUG_ON(clk_init.num_parents > ARRAY_SIZE(parent_names));
+ } else {
+ BUG_ON(clk_info->parents[0] == -1);
+ clk_init.num_parents = 1;
+ parent = cgu->clocks.clks[clk_info->parents[0]];
+ parent_names[0] = __clk_get_name(parent);
+ }
+
+ if (caps & CGU_CLK_CUSTOM) {
+ clk_init.ops = clk_info->custom.clk_ops;
+
+ caps &= ~CGU_CLK_CUSTOM;
+
+ if (caps) {
+ pr_err("%s: custom clock may not be combined with type 0x%x\n",
+ __func__, caps);
+ goto out;
+ }
+ } else if (caps & CGU_CLK_PLL) {
+ clk_init.ops = &jz47xx_pll_ops;
+
+ caps &= ~CGU_CLK_PLL;
+
+ if (caps) {
+ pr_err("%s: PLL may not be combined with type 0x%x\n",
+ __func__, caps);
+ goto out;
+ }
+ } else {
+ clk_init.ops = &jz47xx_clk_ops;
+ }
+
+ /* nothing to do for gates */
+ caps &= ~CGU_CLK_GATE;
+
+ if (caps & CGU_CLK_MUX) {
+ if (!(caps & CGU_CLK_MUX_GLITCHFREE))
+ clk_init.flags |= CLK_SET_PARENT_GATE;
+
+ caps &= ~(CGU_CLK_MUX | CGU_CLK_MUX_GLITCHFREE);
+ }
+
+ if (caps & CGU_CLK_DIV) {
+ caps &= ~CGU_CLK_DIV;
+ } else {
+ /* pass rate changes to the parent clock */
+ clk_init.flags |= CLK_SET_RATE_PARENT;
+ }
+
+ if (caps) {
+ pr_err("%s: unknown clock type 0x%x\n", __func__, caps);
+ goto out;
+ }
+
+ clk = clk_register(NULL, &jz_clk->hw);
+ if (IS_ERR(clk)) {
+ pr_err("%s: failed to register clock '%s'\n", __func__,
+ clk_info->name);
+ err = PTR_ERR(clk);
+ goto out;
+ }
+
+ err = clk_register_clkdev(clk, clk_info->name, NULL);
+ if (err)
+ goto out;
+
+ cgu->clocks.clks[idx] = clk;
+out:
+ if (err)
+ kfree(jz_clk);
+ return err;
+}
+
+struct jz47xx_cgu *jz47xx_cgu_new(const struct jz47xx_cgu_clk_info *clock_info,
+ unsigned num_clocks,
+ struct device_node *np)
+{
+ struct jz47xx_cgu *cgu;
+
+ cgu = kzalloc(sizeof(*cgu), GFP_KERNEL);
+ if (!cgu) {
+ pr_err("%s: failed to allocate struct jz47xx_cgu\n", __func__);
+ goto err_out;
+ }
+
+ cgu->base = of_iomap(np, 0);
+ if (!cgu->base) {
+ pr_err("%s: failed to map CGU registers\n", __func__);
+ goto err_out_free;
+ }
+
+ cgu->np = np;
+ cgu->clock_info = clock_info;
+ cgu->clocks.clk_num = num_clocks;
+
+ spin_lock_init(&cgu->divmux_lock);
+ spin_lock_init(&cgu->power_lock);
+ spin_lock_init(&cgu->pll_lock);
+
+ return cgu;
+
+err_out_free:
+ kfree(cgu);
+err_out:
+ return NULL;
+}
+
+int jz47xx_cgu_register_clocks(struct jz47xx_cgu *cgu)
+{
+ unsigned i;
+ int err = -EINVAL;
+
+ cgu->clocks.clks = kzalloc(sizeof(struct clk *) * cgu->clocks.clk_num,
+ GFP_KERNEL);
+ if (!cgu->clocks.clks) {
+ pr_err("%s: failed to alloc clock table\n", __func__);
+ goto err_out;
+ }
+
+ for (i = 0; i < cgu->clocks.clk_num; i++) {
+ err = register_clock(cgu, i);
+ if (err)
+ goto err_out_unregister;
+ }
+
+ err = of_clk_add_provider(cgu->np, of_clk_src_onecell_get,
+ &cgu->clocks);
+ if (err)
+ goto err_out_unregister;
+
+ return 0;
+err_out_unregister:
+ if (cgu) {
+ for (i = 0; i < cgu->clocks.clk_num; i++) {
+ if (!cgu->clocks.clks[i])
+ continue;
+ if (cgu->clock_info[i].type & CGU_CLK_EXT)
+ clk_put(cgu->clocks.clks[i]);
+ else
+ clk_unregister(cgu->clocks.clks[i]);
+ }
+ kfree(cgu->clocks.clks);
+ }
+err_out:
+ return err;
+}
diff --git a/drivers/clk/jz47xx/jz47xx-cgu.h b/drivers/clk/jz47xx/jz47xx-cgu.h
new file mode 100644
index 0000000..ec7fe7d
--- /dev/null
+++ b/drivers/clk/jz47xx/jz47xx-cgu.h
@@ -0,0 +1,205 @@
+/*
+ * Ingenic jz47xx series CGU driver
+ *
+ * Copyright (c) 2013-2015 Imagination Technologies
+ * Author: Paul Burton <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __DRIVERS_CLK_JZ47XX_JZ47XX_CGU_H__
+#define __DRIVERS_CLK_JZ47XX_JZ47XX_CGU_H__
+
+#include <linux/of.h>
+#include <linux/spinlock.h>
+
+/**
+ * struct jz47xx_cgu_pll_info - information about a PLL
+ * @reg: the offset of the PLL's control register within the CGU
+ * @m_shift: the number of bits to shift the multiplier value by (ie. the
+ * index of the lowest bit of the multiplier value in the PLL's
+ * control register)
+ * @m_bits: the size of the multiplier field in bits
+ * @m_offset: the multiplier value which encodes to 0 in the PLL's control
+ * register
+ * @n_shift: the number of bits to shift the divider value by (ie. the
+ * index of the lowest bit of the divider value in the PLL's
+ * control register)
+ * @n_bits: the size of the divider field in bits
+ * @n_offset: the divider value which encodes to 0 in the PLL's control
+ * register
+ * @od_shift: the number of bits to shift the post-VCO divider value by (ie.
+ * the index of the lowest bit of the post-VCO divider value in
+ * the PLL's control register)
+ * @od_bits: the size of the post-VCO divider field in bits
+ * @od_max: the maximum post-VCO divider value
+ * @od_encoding: a pointer to an array mapping post-VCO divider values to
+ * their encoded values in the PLL control register, or -1 for
+ * unsupported values
+ * @bypass_bit: the index of the bypass bit in the PLL control register
+ * @enable_bit: the index of the enable bit in the PLL control register
+ * @stable_bit: the index of the stable bit in the PLL control register
+ */
+struct jz47xx_cgu_pll_info {
+ unsigned reg;
+ unsigned m_shift, m_bits, m_offset;
+ unsigned n_shift, n_bits, n_offset;
+ unsigned od_shift, od_bits, od_max;
+ const s8 *od_encoding;
+ unsigned bypass_bit;
+ unsigned enable_bit;
+ unsigned stable_bit;
+};
+
+/**
+ * struct jz47xx_cgu_mux_info - information about a clock mux
+ * @reg: offset of the mux control register within the CGU
+ * @shift: number of bits to shift the mux value by (ie. the index of
+ * the lowest bit of the mux value within its control register)
+ * @bits: the size of the mux value in bits
+ */
+struct jz47xx_cgu_mux_info {
+ unsigned reg;
+ unsigned shift:5;
+ unsigned bits:5;
+};
+
+/**
+ * struct jz47xx_cgu_div_info - information about a divider
+ * @reg: offset of the divider control register within the CGU
+ * @shift: number of bits to shift the divide value by (ie. the index of
+ * the lowest bit of the divide value within its control register)
+ * @bits: the size of the divide value in bits
+ * @ce_bit: the index of the change enable bit within reg, or -1 is there
+ * isn't one
+ * @busy_bit: the index of the busy bit within reg, or -1 is there isn't one
+ * @stop_bit: the index of the stop bit within reg, or -1 is there isn't one
+ */
+struct jz47xx_cgu_div_info {
+ unsigned reg;
+ unsigned shift:5;
+ unsigned bits:5;
+ int ce_bit:6;
+ int busy_bit:6;
+ int stop_bit:6;
+};
+
+/**
+ * struct jz47xx_cgu_custom_info - information about a custom (SoC) clock
+ */
+struct jz47xx_cgu_custom_info {
+ struct clk_ops *clk_ops;
+};
+
+/**
+ * struct jz47xx_cgu_clk_info - information about a clock
+ * @name: name of the clock
+ * @type: a bitmask formed from CGU_CLK_* values
+ * @parents: an array of the indices of potential parents of this clock
+ * within the clock_info array of the CGU, or -1 in entries
+ * which correspond to no valid parent
+ * @pll: information valid if type includes CGU_CLK_PLL
+ * @gate_bit: the index of the gate bit in the CLKGR* registers, valid if
+ * type includes CGU_CLK_GATE
+ * @mux: information valid if type includes CGU_CLK_MUX
+ * @div: information valid if type includes CGU_CLK_DIV
+ */
+struct jz47xx_cgu_clk_info {
+ const char *name;
+
+ enum {
+ CGU_CLK_NONE = 0,
+ CGU_CLK_EXT = (1 << 0),
+ CGU_CLK_PLL = (1 << 1),
+ CGU_CLK_GATE = (1 << 2),
+ CGU_CLK_MUX = (1 << 3),
+ CGU_CLK_MUX_GLITCHFREE = (1 << 4),
+ CGU_CLK_DIV = (1 << 5),
+ CGU_CLK_CUSTOM = (1 << 6),
+ } type;
+
+ int parents[4];
+
+ union {
+ struct jz47xx_cgu_pll_info pll;
+
+ struct {
+ unsigned gate_bit;
+ struct jz47xx_cgu_mux_info mux;
+ struct jz47xx_cgu_div_info div;
+ };
+
+ struct jz47xx_cgu_custom_info custom;
+ };
+};
+
+/**
+ * struct jz47xx_cgu - data about the CGU
+ * @np: the device tree node that caused the CGU to be probed
+ * @base: the ioremap'ed base address of the CGU registers
+ * @clock_info: an array containing information about implemented clocks
+ * @clocks: used to provide clocks to DT, allows lookup of struct clk*
+ * @gate_lock: lock to be held whilst (un)gating a clock
+ * @divmux_lock: lock to be held whilst re-muxing of rate-changing a clock
+ */
+struct jz47xx_cgu {
+ struct device_node *np;
+ void __iomem *base;
+
+ const struct jz47xx_cgu_clk_info *clock_info;
+ struct clk_onecell_data clocks;
+
+ spinlock_t divmux_lock; /* must be held when changing a divide
+ or re-muxing a clock */
+ spinlock_t power_lock; /* must be held when changing a power
+ manager register */
+ spinlock_t pll_lock; /* must be held when changing a PLL
+ control register */
+};
+
+/**
+ * struct jz47xx_clk - private data for a clock
+ * @hw: see Documentation/clk.txt
+ * @cgu: a pointer to the CGU data
+ * @idx: the index of this clock in cgu->clock_info
+ */
+struct jz47xx_clk {
+ struct clk_hw hw;
+ struct jz47xx_cgu *cgu;
+ unsigned idx;
+};
+
+#define to_jz47xx_clk(_hw) container_of(_hw, struct jz47xx_clk, hw)
+
+/**
+ * jz47xx_cgu_new - create a new CGU instance
+ * @clock_info: an array of clock information structures describing the clocks
+ * which are implemented by the CGU
+ * @num_clocks: the number of entries in clock_info
+ * @np: the device tree node which causes this CGU to be probed
+ *
+ * Returns an opaque pointer to the CGU instance if initialisation & clock
+ * registration is successful, otherwise NULL.
+ */
+struct jz47xx_cgu *jz47xx_cgu_new(const struct jz47xx_cgu_clk_info *clock_info,
+ unsigned num_clocks,
+ struct device_node *np);
+
+/**
+ * jz47xx_cgu_register_clocks - Registers the clocks
+ * @cgu: pointer to cgu data
+ *
+ * Returns 1 on success and -EINVAL if unsuccesful.
+ */
+int jz47xx_cgu_register_clocks(struct jz47xx_cgu *cgu);
+
+#endif /* __DRIVERS_CLK_JZ47XX_JZ47XX_CGU_H__ */
--
1.9.1
From: Paul Burton <[email protected]>
Document the devicetree binding for the Ingenic jz4740 CGU driver.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
Cc: Mike Turquette <[email protected]>
Cc: [email protected]
---
.../bindings/clock/ingenic,jz4740-cgu.txt | 52 ++++++++++++++++++++++
include/dt-bindings/clock/jz4740-cgu.h | 37 +++++++++++++++
2 files changed, 89 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/ingenic,jz4740-cgu.txt
create mode 100644 include/dt-bindings/clock/jz4740-cgu.h
diff --git a/Documentation/devicetree/bindings/clock/ingenic,jz4740-cgu.txt b/Documentation/devicetree/bindings/clock/ingenic,jz4740-cgu.txt
new file mode 100644
index 0000000..b02e168
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/ingenic,jz4740-cgu.txt
@@ -0,0 +1,52 @@
+Ingenic jz4740 SoC CGU binding
+
+The CGU in a jz4740 SoC provides all the clocks generated on-chip. It includes
+PLLs, multiplexers, dividers & gates in order to provide a variety of different
+clock signals derived from only 2 external source clocks.
+
+Required properties:
+- compatible: Should be "ingenic,jz4740-cgu"
+- reg: Should be the address & length of the CGU registers
+- clocks: Should contain the phandle & clock specifier for two clocks external
+ to the TCU. First the external crystal "ext" and second the RTC
+ clock source "rtc".
+- clock-names: Should be set to strings naming the clocks specified in the
+ "clocks" property.
+- #clock-cells: Should be 1.
+ Clock consumers specify this argument to identify a clock. The
+ valid values may be found in <dt-bindings/clock/jz4740-cgu.h>.
+
+Example SoC include file:
+
+/ {
+ cgu: jz4740-cgu {
+ compatible = "ingenic,jz4740-cgu";
+ reg = <0x10000000 0x100>;
+ #clock-cells = <1>;
+ };
+
+ uart0: serial@10030000 {
+ clocks = <&cgu JZ4740_CLK_UART0>;
+ };
+};
+
+Example board file:
+
+/ {
+ ext: clock@0 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <12000000>;
+ };
+
+ rtc: clock@1 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ };
+
+ &cgu {
+ clocks = <&ext> <&rtc>;
+ clock-names: "ext", "rtc";
+ };
+};
diff --git a/include/dt-bindings/clock/jz4740-cgu.h b/include/dt-bindings/clock/jz4740-cgu.h
new file mode 100644
index 0000000..43153d3
--- /dev/null
+++ b/include/dt-bindings/clock/jz4740-cgu.h
@@ -0,0 +1,37 @@
+/*
+ * This header provides clock numbers for the ingenic,jz4740-cgu DT binding.
+ *
+ * They are roughly ordered as:
+ * - external clocks
+ * - PLLs
+ * - muxes/dividers in the order they appear in the jz4740 programmers manual
+ * - gates in order of their bit in the CLKGR* registers
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_JZ4740_CGU_H__
+#define __DT_BINDINGS_CLOCK_JZ4740_CGU_H__
+
+#define JZ4740_CLK_EXT 0
+#define JZ4740_CLK_RTC 1
+#define JZ4740_CLK_PLL 2
+#define JZ4740_CLK_PLL_HALF 3
+#define JZ4740_CLK_CCLK 4
+#define JZ4740_CLK_HCLK 5
+#define JZ4740_CLK_PCLK 6
+#define JZ4740_CLK_MCLK 7
+#define JZ4740_CLK_LCD 8
+#define JZ4740_CLK_LCD_PCLK 9
+#define JZ4740_CLK_I2S 10
+#define JZ4740_CLK_SPI 11
+#define JZ4740_CLK_MMC 12
+#define JZ4740_CLK_UHC 13
+#define JZ4740_CLK_UDC 14
+#define JZ4740_CLK_UART0 15
+#define JZ4740_CLK_UART1 16
+#define JZ4740_CLK_DMA 17
+#define JZ4740_CLK_IPU 18
+#define JZ4740_CLK_ADC 19
+#define JZ4740_CLK_I2C 20
+#define JZ4740_CLK_AIC 21
+
+#endif /* __DT_BINDINGS_CLOCK_JZ4740_CGU_H__ */
--
1.9.1
From: Paul Burton <[email protected]>
Migrate the jz4740 & the qi_lb60 board to use common clock framework
via the new jz74xx-cgu driver.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
Cc: Mike Turquette <[email protected]>
---
V2 Removed FSF address
---
arch/mips/Kconfig | 2 +-
arch/mips/boot/dts/jz4740.dtsi | 23 ++
arch/mips/boot/dts/qi_lb60.dts | 4 +
arch/mips/jz4740/Makefile | 2 -
arch/mips/jz4740/board-qi_lb60.c | 5 -
arch/mips/jz4740/clock-debugfs.c | 108 ------
arch/mips/jz4740/clock.c | 801 +--------------------------------------
arch/mips/jz4740/clock.h | 53 +--
arch/mips/jz4740/time.c | 2 +
drivers/clk/jz47xx/Makefile | 1 +
drivers/clk/jz47xx/jz4740-cgu.c | 219 +++++++++++
11 files changed, 252 insertions(+), 968 deletions(-)
delete mode 100644 arch/mips/jz4740/clock-debugfs.c
create mode 100644 drivers/clk/jz47xx/jz4740-cgu.c
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 99d50cd..8b377a7 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -286,7 +286,7 @@ config MACH_JZ4740
select IRQ_CPU
select ARCH_REQUIRE_GPIOLIB
select SYS_HAS_EARLY_PRINTK
- select HAVE_CLK
+ select COMMON_CLK
select GENERIC_IRQ_CHIP
select BUILTIN_DTB
select USE_OF
diff --git a/arch/mips/boot/dts/jz4740.dtsi b/arch/mips/boot/dts/jz4740.dtsi
index 3841024..ef679b4 100644
--- a/arch/mips/boot/dts/jz4740.dtsi
+++ b/arch/mips/boot/dts/jz4740.dtsi
@@ -1,3 +1,5 @@
+#include <dt-bindings/clock/jz4740-cgu.h>
+
/ {
#address-cells = <1>;
#size-cells = <1>;
@@ -20,4 +22,25 @@
interrupt-parent = <&cpuintc>;
interrupts = <2>;
};
+
+ ext: ext {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ };
+
+ rtc: rtc {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ };
+
+ cgu: jz4740-cgu@10000000 {
+ compatible = "ingenic,jz4740-cgu";
+ reg = <0x10000000 0x100>;
+
+ clocks = <&ext>, <&rtc>;
+ clock-names = "ext", "rtc";
+
+ #clock-cells = <1>;
+ };
};
diff --git a/arch/mips/boot/dts/qi_lb60.dts b/arch/mips/boot/dts/qi_lb60.dts
index 0c0f639..106d13c 100644
--- a/arch/mips/boot/dts/qi_lb60.dts
+++ b/arch/mips/boot/dts/qi_lb60.dts
@@ -5,3 +5,7 @@
/ {
compatible = "qi,lb60", "ingenic,jz4740";
};
+
+&ext {
+ clock-frequency = <12000000>;
+};
diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile
index 28e5535..80e326d 100644
--- a/arch/mips/jz4740/Makefile
+++ b/arch/mips/jz4740/Makefile
@@ -7,8 +7,6 @@
obj-y += prom.o irq.o time.o reset.o setup.o \
gpio.o clock.o platform.o timer.o serial.o
-obj-$(CONFIG_DEBUG_FS) += clock-debugfs.o
-
# board specific support
obj-$(CONFIG_JZ4740_QI_LB60) += board-qi_lb60.o
diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c
index c454525..0fbb2d8 100644
--- a/arch/mips/jz4740/board-qi_lb60.c
+++ b/arch/mips/jz4740/board-qi_lb60.c
@@ -488,11 +488,6 @@ static int __init qi_lb60_init_platform_devices(void)
}
-struct jz4740_clock_board_data jz4740_clock_bdata = {
- .ext_rate = 12000000,
- .rtc_rate = 32768,
-};
-
static __init int board_avt2(char *str)
{
qi_lb60_mmc_pdata.card_detect_active_low = 1;
diff --git a/arch/mips/jz4740/clock-debugfs.c b/arch/mips/jz4740/clock-debugfs.c
deleted file mode 100644
index 325422d0..0000000
--- a/arch/mips/jz4740/clock-debugfs.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2010, Lars-Peter Clausen <[email protected]>
- * JZ4740 SoC clock support debugfs entries
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
-
-#include <asm/mach-jz4740/clock.h>
-#include "clock.h"
-
-static struct dentry *jz4740_clock_debugfs;
-
-static int jz4740_clock_debugfs_show_enabled(void *data, uint64_t *value)
-{
- struct clk *clk = data;
- *value = clk_is_enabled(clk);
-
- return 0;
-}
-
-static int jz4740_clock_debugfs_set_enabled(void *data, uint64_t value)
-{
- struct clk *clk = data;
-
- if (value)
- return clk_enable(clk);
- else
- clk_disable(clk);
-
- return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(jz4740_clock_debugfs_ops_enabled,
- jz4740_clock_debugfs_show_enabled,
- jz4740_clock_debugfs_set_enabled,
- "%llu\n");
-
-static int jz4740_clock_debugfs_show_rate(void *data, uint64_t *value)
-{
- struct clk *clk = data;
- *value = clk_get_rate(clk);
-
- return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(jz4740_clock_debugfs_ops_rate,
- jz4740_clock_debugfs_show_rate,
- NULL,
- "%llu\n");
-
-void jz4740_clock_debugfs_add_clk(struct clk *clk)
-{
- if (!jz4740_clock_debugfs)
- return;
-
- clk->debugfs_entry = debugfs_create_dir(clk->name, jz4740_clock_debugfs);
- debugfs_create_file("rate", S_IWUGO | S_IRUGO, clk->debugfs_entry, clk,
- &jz4740_clock_debugfs_ops_rate);
- debugfs_create_file("enabled", S_IRUGO, clk->debugfs_entry, clk,
- &jz4740_clock_debugfs_ops_enabled);
-
- if (clk->parent) {
- char parent_path[100];
- snprintf(parent_path, 100, "../%s", clk->parent->name);
- clk->debugfs_parent_entry = debugfs_create_symlink("parent",
- clk->debugfs_entry,
- parent_path);
- }
-}
-
-/* TODO: Locking */
-void jz4740_clock_debugfs_update_parent(struct clk *clk)
-{
- debugfs_remove(clk->debugfs_parent_entry);
-
- if (clk->parent) {
- char parent_path[100];
- snprintf(parent_path, 100, "../%s", clk->parent->name);
- clk->debugfs_parent_entry = debugfs_create_symlink("parent",
- clk->debugfs_entry,
- parent_path);
- } else {
- clk->debugfs_parent_entry = NULL;
- }
-}
-
-void jz4740_clock_debugfs_init(void)
-{
- jz4740_clock_debugfs = debugfs_create_dir("jz4740-clock", NULL);
- if (IS_ERR(jz4740_clock_debugfs))
- jz4740_clock_debugfs = NULL;
-}
diff --git a/arch/mips/jz4740/clock.c b/arch/mips/jz4740/clock.c
index c257073..dedee7c 100644
--- a/arch/mips/jz4740/clock.c
+++ b/arch/mips/jz4740/clock.c
@@ -16,6 +16,7 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -27,820 +28,44 @@
#include "clock.h"
-#define JZ_REG_CLOCK_CTRL 0x00
#define JZ_REG_CLOCK_LOW_POWER 0x04
#define JZ_REG_CLOCK_PLL 0x10
#define JZ_REG_CLOCK_GATE 0x20
-#define JZ_REG_CLOCK_SLEEP_CTRL 0x24
-#define JZ_REG_CLOCK_I2S 0x60
-#define JZ_REG_CLOCK_LCD 0x64
-#define JZ_REG_CLOCK_MMC 0x68
-#define JZ_REG_CLOCK_UHC 0x6C
-#define JZ_REG_CLOCK_SPI 0x74
-
-#define JZ_CLOCK_CTRL_I2S_SRC_PLL BIT(31)
-#define JZ_CLOCK_CTRL_KO_ENABLE BIT(30)
-#define JZ_CLOCK_CTRL_UDC_SRC_PLL BIT(29)
-#define JZ_CLOCK_CTRL_UDIV_MASK 0x1f800000
-#define JZ_CLOCK_CTRL_CHANGE_ENABLE BIT(22)
-#define JZ_CLOCK_CTRL_PLL_HALF BIT(21)
-#define JZ_CLOCK_CTRL_LDIV_MASK 0x001f0000
-#define JZ_CLOCK_CTRL_UDIV_OFFSET 23
-#define JZ_CLOCK_CTRL_LDIV_OFFSET 16
-#define JZ_CLOCK_CTRL_MDIV_OFFSET 12
-#define JZ_CLOCK_CTRL_PDIV_OFFSET 8
-#define JZ_CLOCK_CTRL_HDIV_OFFSET 4
-#define JZ_CLOCK_CTRL_CDIV_OFFSET 0
#define JZ_CLOCK_GATE_UART0 BIT(0)
#define JZ_CLOCK_GATE_TCU BIT(1)
-#define JZ_CLOCK_GATE_RTC BIT(2)
-#define JZ_CLOCK_GATE_I2C BIT(3)
-#define JZ_CLOCK_GATE_SPI BIT(4)
-#define JZ_CLOCK_GATE_AIC BIT(5)
-#define JZ_CLOCK_GATE_I2S BIT(6)
-#define JZ_CLOCK_GATE_MMC BIT(7)
-#define JZ_CLOCK_GATE_ADC BIT(8)
-#define JZ_CLOCK_GATE_CIM BIT(9)
-#define JZ_CLOCK_GATE_LCD BIT(10)
#define JZ_CLOCK_GATE_UDC BIT(11)
#define JZ_CLOCK_GATE_DMAC BIT(12)
-#define JZ_CLOCK_GATE_IPU BIT(13)
-#define JZ_CLOCK_GATE_UHC BIT(14)
-#define JZ_CLOCK_GATE_UART1 BIT(15)
-
-#define JZ_CLOCK_I2S_DIV_MASK 0x01ff
-
-#define JZ_CLOCK_LCD_DIV_MASK 0x01ff
-
-#define JZ_CLOCK_MMC_DIV_MASK 0x001f
-#define JZ_CLOCK_UHC_DIV_MASK 0x000f
-
-#define JZ_CLOCK_SPI_SRC_PLL BIT(31)
-#define JZ_CLOCK_SPI_DIV_MASK 0x000f
-
-#define JZ_CLOCK_PLL_M_MASK 0x01ff
-#define JZ_CLOCK_PLL_N_MASK 0x001f
-#define JZ_CLOCK_PLL_OD_MASK 0x0003
#define JZ_CLOCK_PLL_STABLE BIT(10)
-#define JZ_CLOCK_PLL_BYPASS BIT(9)
#define JZ_CLOCK_PLL_ENABLED BIT(8)
-#define JZ_CLOCK_PLL_STABLIZE_MASK 0x000f
-#define JZ_CLOCK_PLL_M_OFFSET 23
-#define JZ_CLOCK_PLL_N_OFFSET 18
-#define JZ_CLOCK_PLL_OD_OFFSET 16
#define JZ_CLOCK_LOW_POWER_MODE_DOZE BIT(2)
#define JZ_CLOCK_LOW_POWER_MODE_SLEEP BIT(0)
-#define JZ_CLOCK_SLEEP_CTRL_SUSPEND_UHC BIT(7)
-#define JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC BIT(6)
-
static void __iomem *jz_clock_base;
-static spinlock_t jz_clock_lock;
-static LIST_HEAD(jz_clocks);
-
-struct main_clk {
- struct clk clk;
- uint32_t div_offset;
-};
-
-struct divided_clk {
- struct clk clk;
- uint32_t reg;
- uint32_t mask;
-};
-
-struct static_clk {
- struct clk clk;
- unsigned long rate;
-};
static uint32_t jz_clk_reg_read(int reg)
{
return readl(jz_clock_base + reg);
}
-static void jz_clk_reg_write_mask(int reg, uint32_t val, uint32_t mask)
-{
- uint32_t val2;
-
- spin_lock(&jz_clock_lock);
- val2 = readl(jz_clock_base + reg);
- val2 &= ~mask;
- val2 |= val;
- writel(val2, jz_clock_base + reg);
- spin_unlock(&jz_clock_lock);
-}
-
static void jz_clk_reg_set_bits(int reg, uint32_t mask)
{
uint32_t val;
- spin_lock(&jz_clock_lock);
val = readl(jz_clock_base + reg);
val |= mask;
writel(val, jz_clock_base + reg);
- spin_unlock(&jz_clock_lock);
}
static void jz_clk_reg_clear_bits(int reg, uint32_t mask)
{
uint32_t val;
- spin_lock(&jz_clock_lock);
val = readl(jz_clock_base + reg);
val &= ~mask;
writel(val, jz_clock_base + reg);
- spin_unlock(&jz_clock_lock);
-}
-
-static int jz_clk_enable_gating(struct clk *clk)
-{
- if (clk->gate_bit == JZ4740_CLK_NOT_GATED)
- return -EINVAL;
-
- jz_clk_reg_clear_bits(JZ_REG_CLOCK_GATE, clk->gate_bit);
- return 0;
-}
-
-static int jz_clk_disable_gating(struct clk *clk)
-{
- if (clk->gate_bit == JZ4740_CLK_NOT_GATED)
- return -EINVAL;
-
- jz_clk_reg_set_bits(JZ_REG_CLOCK_GATE, clk->gate_bit);
- return 0;
-}
-
-static int jz_clk_is_enabled_gating(struct clk *clk)
-{
- if (clk->gate_bit == JZ4740_CLK_NOT_GATED)
- return 1;
-
- return !(jz_clk_reg_read(JZ_REG_CLOCK_GATE) & clk->gate_bit);
-}
-
-static unsigned long jz_clk_static_get_rate(struct clk *clk)
-{
- return ((struct static_clk *)clk)->rate;
-}
-
-static int jz_clk_ko_enable(struct clk *clk)
-{
- jz_clk_reg_set_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_KO_ENABLE);
- return 0;
-}
-
-static int jz_clk_ko_disable(struct clk *clk)
-{
- jz_clk_reg_clear_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_KO_ENABLE);
- return 0;
-}
-
-static int jz_clk_ko_is_enabled(struct clk *clk)
-{
- return !!(jz_clk_reg_read(JZ_REG_CLOCK_CTRL) & JZ_CLOCK_CTRL_KO_ENABLE);
-}
-
-static const int pllno[] = {1, 2, 2, 4};
-
-static unsigned long jz_clk_pll_get_rate(struct clk *clk)
-{
- uint32_t val;
- int m;
- int n;
- int od;
-
- val = jz_clk_reg_read(JZ_REG_CLOCK_PLL);
-
- if (val & JZ_CLOCK_PLL_BYPASS)
- return clk_get_rate(clk->parent);
-
- m = ((val >> 23) & 0x1ff) + 2;
- n = ((val >> 18) & 0x1f) + 2;
- od = (val >> 16) & 0x3;
-
- return ((clk_get_rate(clk->parent) / n) * m) / pllno[od];
-}
-
-static unsigned long jz_clk_pll_half_get_rate(struct clk *clk)
-{
- uint32_t reg;
-
- reg = jz_clk_reg_read(JZ_REG_CLOCK_CTRL);
- if (reg & JZ_CLOCK_CTRL_PLL_HALF)
- return jz_clk_pll_get_rate(clk->parent);
- return jz_clk_pll_get_rate(clk->parent) >> 1;
-}
-
-static const int jz_clk_main_divs[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
-
-static unsigned long jz_clk_main_round_rate(struct clk *clk, unsigned long rate)
-{
- unsigned long parent_rate = jz_clk_pll_get_rate(clk->parent);
- int div;
-
- div = parent_rate / rate;
- if (div > 32)
- return parent_rate / 32;
- else if (div < 1)
- return parent_rate;
-
- div &= (0x3 << (ffs(div) - 1));
-
- return parent_rate / div;
-}
-
-static unsigned long jz_clk_main_get_rate(struct clk *clk)
-{
- struct main_clk *mclk = (struct main_clk *)clk;
- uint32_t div;
-
- div = jz_clk_reg_read(JZ_REG_CLOCK_CTRL);
-
- div >>= mclk->div_offset;
- div &= 0xf;
-
- if (div >= ARRAY_SIZE(jz_clk_main_divs))
- div = ARRAY_SIZE(jz_clk_main_divs) - 1;
-
- return jz_clk_pll_get_rate(clk->parent) / jz_clk_main_divs[div];
-}
-
-static int jz_clk_main_set_rate(struct clk *clk, unsigned long rate)
-{
- struct main_clk *mclk = (struct main_clk *)clk;
- int i;
- int div;
- unsigned long parent_rate = jz_clk_pll_get_rate(clk->parent);
-
- rate = jz_clk_main_round_rate(clk, rate);
-
- div = parent_rate / rate;
-
- i = (ffs(div) - 1) << 1;
- if (i > 0 && !(div & BIT(i-1)))
- i -= 1;
-
- jz_clk_reg_write_mask(JZ_REG_CLOCK_CTRL, i << mclk->div_offset,
- 0xf << mclk->div_offset);
-
- return 0;
-}
-
-static struct clk_ops jz_clk_static_ops = {
- .get_rate = jz_clk_static_get_rate,
- .enable = jz_clk_enable_gating,
- .disable = jz_clk_disable_gating,
- .is_enabled = jz_clk_is_enabled_gating,
-};
-
-static struct static_clk jz_clk_ext = {
- .clk = {
- .name = "ext",
- .gate_bit = JZ4740_CLK_NOT_GATED,
- .ops = &jz_clk_static_ops,
- },
-};
-
-static struct clk_ops jz_clk_pll_ops = {
- .get_rate = jz_clk_pll_get_rate,
-};
-
-static struct clk jz_clk_pll = {
- .name = "pll",
- .parent = &jz_clk_ext.clk,
- .ops = &jz_clk_pll_ops,
-};
-
-static struct clk_ops jz_clk_pll_half_ops = {
- .get_rate = jz_clk_pll_half_get_rate,
-};
-
-static struct clk jz_clk_pll_half = {
- .name = "pll half",
- .parent = &jz_clk_pll,
- .ops = &jz_clk_pll_half_ops,
-};
-
-static const struct clk_ops jz_clk_main_ops = {
- .get_rate = jz_clk_main_get_rate,
- .set_rate = jz_clk_main_set_rate,
- .round_rate = jz_clk_main_round_rate,
-};
-
-static struct main_clk jz_clk_cpu = {
- .clk = {
- .name = "cclk",
- .parent = &jz_clk_pll,
- .ops = &jz_clk_main_ops,
- },
- .div_offset = JZ_CLOCK_CTRL_CDIV_OFFSET,
-};
-
-static struct main_clk jz_clk_memory = {
- .clk = {
- .name = "mclk",
- .parent = &jz_clk_pll,
- .ops = &jz_clk_main_ops,
- },
- .div_offset = JZ_CLOCK_CTRL_MDIV_OFFSET,
-};
-
-static struct main_clk jz_clk_high_speed_peripheral = {
- .clk = {
- .name = "hclk",
- .parent = &jz_clk_pll,
- .ops = &jz_clk_main_ops,
- },
- .div_offset = JZ_CLOCK_CTRL_HDIV_OFFSET,
-};
-
-
-static struct main_clk jz_clk_low_speed_peripheral = {
- .clk = {
- .name = "pclk",
- .parent = &jz_clk_pll,
- .ops = &jz_clk_main_ops,
- },
- .div_offset = JZ_CLOCK_CTRL_PDIV_OFFSET,
-};
-
-static const struct clk_ops jz_clk_ko_ops = {
- .enable = jz_clk_ko_enable,
- .disable = jz_clk_ko_disable,
- .is_enabled = jz_clk_ko_is_enabled,
-};
-
-static struct clk jz_clk_ko = {
- .name = "cko",
- .parent = &jz_clk_memory.clk,
- .ops = &jz_clk_ko_ops,
-};
-
-static int jz_clk_spi_set_parent(struct clk *clk, struct clk *parent)
-{
- if (parent == &jz_clk_pll)
- jz_clk_reg_set_bits(JZ_CLOCK_SPI_SRC_PLL, JZ_REG_CLOCK_SPI);
- else if (parent == &jz_clk_ext.clk)
- jz_clk_reg_clear_bits(JZ_CLOCK_SPI_SRC_PLL, JZ_REG_CLOCK_SPI);
- else
- return -EINVAL;
-
- clk->parent = parent;
-
- return 0;
-}
-
-static int jz_clk_i2s_set_parent(struct clk *clk, struct clk *parent)
-{
- if (parent == &jz_clk_pll_half)
- jz_clk_reg_set_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_I2S_SRC_PLL);
- else if (parent == &jz_clk_ext.clk)
- jz_clk_reg_clear_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_I2S_SRC_PLL);
- else
- return -EINVAL;
-
- clk->parent = parent;
-
- return 0;
-}
-
-static int jz_clk_udc_enable(struct clk *clk)
-{
- jz_clk_reg_set_bits(JZ_REG_CLOCK_SLEEP_CTRL,
- JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC);
-
- return 0;
-}
-
-static int jz_clk_udc_disable(struct clk *clk)
-{
- jz_clk_reg_clear_bits(JZ_REG_CLOCK_SLEEP_CTRL,
- JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC);
-
- return 0;
-}
-
-static int jz_clk_udc_is_enabled(struct clk *clk)
-{
- return !!(jz_clk_reg_read(JZ_REG_CLOCK_SLEEP_CTRL) &
- JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC);
-}
-
-static int jz_clk_udc_set_parent(struct clk *clk, struct clk *parent)
-{
- if (parent == &jz_clk_pll_half)
- jz_clk_reg_set_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_UDC_SRC_PLL);
- else if (parent == &jz_clk_ext.clk)
- jz_clk_reg_clear_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_UDC_SRC_PLL);
- else
- return -EINVAL;
-
- clk->parent = parent;
-
- return 0;
-}
-
-static int jz_clk_udc_set_rate(struct clk *clk, unsigned long rate)
-{
- int div;
-
- if (clk->parent == &jz_clk_ext.clk)
- return -EINVAL;
-
- div = clk_get_rate(clk->parent) / rate - 1;
-
- if (div < 0)
- div = 0;
- else if (div > 63)
- div = 63;
-
- jz_clk_reg_write_mask(JZ_REG_CLOCK_CTRL, div << JZ_CLOCK_CTRL_UDIV_OFFSET,
- JZ_CLOCK_CTRL_UDIV_MASK);
- return 0;
-}
-
-static unsigned long jz_clk_udc_get_rate(struct clk *clk)
-{
- int div;
-
- if (clk->parent == &jz_clk_ext.clk)
- return clk_get_rate(clk->parent);
-
- div = (jz_clk_reg_read(JZ_REG_CLOCK_CTRL) & JZ_CLOCK_CTRL_UDIV_MASK);
- div >>= JZ_CLOCK_CTRL_UDIV_OFFSET;
- div += 1;
-
- return clk_get_rate(clk->parent) / div;
-}
-
-static unsigned long jz_clk_divided_get_rate(struct clk *clk)
-{
- struct divided_clk *dclk = (struct divided_clk *)clk;
- int div;
-
- if (clk->parent == &jz_clk_ext.clk)
- return clk_get_rate(clk->parent);
-
- div = (jz_clk_reg_read(dclk->reg) & dclk->mask) + 1;
-
- return clk_get_rate(clk->parent) / div;
-}
-
-static int jz_clk_divided_set_rate(struct clk *clk, unsigned long rate)
-{
- struct divided_clk *dclk = (struct divided_clk *)clk;
- int div;
-
- if (clk->parent == &jz_clk_ext.clk)
- return -EINVAL;
-
- div = clk_get_rate(clk->parent) / rate - 1;
-
- if (div < 0)
- div = 0;
- else if (div > dclk->mask)
- div = dclk->mask;
-
- jz_clk_reg_write_mask(dclk->reg, div, dclk->mask);
-
- return 0;
-}
-
-static unsigned long jz_clk_ldclk_round_rate(struct clk *clk, unsigned long rate)
-{
- int div;
- unsigned long parent_rate = jz_clk_pll_half_get_rate(clk->parent);
-
- if (rate > 150000000)
- return 150000000;
-
- div = parent_rate / rate;
- if (div < 1)
- div = 1;
- else if (div > 32)
- div = 32;
-
- return parent_rate / div;
-}
-
-static int jz_clk_ldclk_set_rate(struct clk *clk, unsigned long rate)
-{
- int div;
-
- if (rate > 150000000)
- return -EINVAL;
-
- div = jz_clk_pll_half_get_rate(clk->parent) / rate - 1;
- if (div < 0)
- div = 0;
- else if (div > 31)
- div = 31;
-
- jz_clk_reg_write_mask(JZ_REG_CLOCK_CTRL, div << JZ_CLOCK_CTRL_LDIV_OFFSET,
- JZ_CLOCK_CTRL_LDIV_MASK);
-
- return 0;
-}
-
-static unsigned long jz_clk_ldclk_get_rate(struct clk *clk)
-{
- int div;
-
- div = jz_clk_reg_read(JZ_REG_CLOCK_CTRL) & JZ_CLOCK_CTRL_LDIV_MASK;
- div >>= JZ_CLOCK_CTRL_LDIV_OFFSET;
-
- return jz_clk_pll_half_get_rate(clk->parent) / (div + 1);
-}
-
-static const struct clk_ops jz_clk_ops_ld = {
- .set_rate = jz_clk_ldclk_set_rate,
- .get_rate = jz_clk_ldclk_get_rate,
- .round_rate = jz_clk_ldclk_round_rate,
- .enable = jz_clk_enable_gating,
- .disable = jz_clk_disable_gating,
- .is_enabled = jz_clk_is_enabled_gating,
-};
-
-static struct clk jz_clk_ld = {
- .name = "lcd",
- .gate_bit = JZ_CLOCK_GATE_LCD,
- .parent = &jz_clk_pll_half,
- .ops = &jz_clk_ops_ld,
-};
-
-static const struct clk_ops jz_clk_i2s_ops = {
- .set_rate = jz_clk_divided_set_rate,
- .get_rate = jz_clk_divided_get_rate,
- .enable = jz_clk_enable_gating,
- .disable = jz_clk_disable_gating,
- .is_enabled = jz_clk_is_enabled_gating,
- .set_parent = jz_clk_i2s_set_parent,
-};
-
-static const struct clk_ops jz_clk_spi_ops = {
- .set_rate = jz_clk_divided_set_rate,
- .get_rate = jz_clk_divided_get_rate,
- .enable = jz_clk_enable_gating,
- .disable = jz_clk_disable_gating,
- .is_enabled = jz_clk_is_enabled_gating,
- .set_parent = jz_clk_spi_set_parent,
-};
-
-static const struct clk_ops jz_clk_divided_ops = {
- .set_rate = jz_clk_divided_set_rate,
- .get_rate = jz_clk_divided_get_rate,
- .enable = jz_clk_enable_gating,
- .disable = jz_clk_disable_gating,
- .is_enabled = jz_clk_is_enabled_gating,
-};
-
-static struct divided_clk jz4740_clock_divided_clks[] = {
- [0] = {
- .clk = {
- .name = "i2s",
- .parent = &jz_clk_ext.clk,
- .gate_bit = JZ_CLOCK_GATE_I2S,
- .ops = &jz_clk_i2s_ops,
- },
- .reg = JZ_REG_CLOCK_I2S,
- .mask = JZ_CLOCK_I2S_DIV_MASK,
- },
- [1] = {
- .clk = {
- .name = "spi",
- .parent = &jz_clk_ext.clk,
- .gate_bit = JZ_CLOCK_GATE_SPI,
- .ops = &jz_clk_spi_ops,
- },
- .reg = JZ_REG_CLOCK_SPI,
- .mask = JZ_CLOCK_SPI_DIV_MASK,
- },
- [2] = {
- .clk = {
- .name = "lcd_pclk",
- .parent = &jz_clk_pll_half,
- .gate_bit = JZ4740_CLK_NOT_GATED,
- .ops = &jz_clk_divided_ops,
- },
- .reg = JZ_REG_CLOCK_LCD,
- .mask = JZ_CLOCK_LCD_DIV_MASK,
- },
- [3] = {
- .clk = {
- .name = "mmc",
- .parent = &jz_clk_pll_half,
- .gate_bit = JZ_CLOCK_GATE_MMC,
- .ops = &jz_clk_divided_ops,
- },
- .reg = JZ_REG_CLOCK_MMC,
- .mask = JZ_CLOCK_MMC_DIV_MASK,
- },
- [4] = {
- .clk = {
- .name = "uhc",
- .parent = &jz_clk_pll_half,
- .gate_bit = JZ_CLOCK_GATE_UHC,
- .ops = &jz_clk_divided_ops,
- },
- .reg = JZ_REG_CLOCK_UHC,
- .mask = JZ_CLOCK_UHC_DIV_MASK,
- },
-};
-
-static const struct clk_ops jz_clk_udc_ops = {
- .set_parent = jz_clk_udc_set_parent,
- .set_rate = jz_clk_udc_set_rate,
- .get_rate = jz_clk_udc_get_rate,
- .enable = jz_clk_udc_enable,
- .disable = jz_clk_udc_disable,
- .is_enabled = jz_clk_udc_is_enabled,
-};
-
-static const struct clk_ops jz_clk_simple_ops = {
- .enable = jz_clk_enable_gating,
- .disable = jz_clk_disable_gating,
- .is_enabled = jz_clk_is_enabled_gating,
-};
-
-static struct clk jz4740_clock_simple_clks[] = {
- [0] = {
- .name = "udc",
- .parent = &jz_clk_ext.clk,
- .ops = &jz_clk_udc_ops,
- },
- [1] = {
- .name = "uart0",
- .parent = &jz_clk_ext.clk,
- .gate_bit = JZ_CLOCK_GATE_UART0,
- .ops = &jz_clk_simple_ops,
- },
- [2] = {
- .name = "uart1",
- .parent = &jz_clk_ext.clk,
- .gate_bit = JZ_CLOCK_GATE_UART1,
- .ops = &jz_clk_simple_ops,
- },
- [3] = {
- .name = "dma",
- .parent = &jz_clk_high_speed_peripheral.clk,
- .gate_bit = JZ_CLOCK_GATE_DMAC,
- .ops = &jz_clk_simple_ops,
- },
- [4] = {
- .name = "ipu",
- .parent = &jz_clk_high_speed_peripheral.clk,
- .gate_bit = JZ_CLOCK_GATE_IPU,
- .ops = &jz_clk_simple_ops,
- },
- [5] = {
- .name = "adc",
- .parent = &jz_clk_ext.clk,
- .gate_bit = JZ_CLOCK_GATE_ADC,
- .ops = &jz_clk_simple_ops,
- },
- [6] = {
- .name = "i2c",
- .parent = &jz_clk_ext.clk,
- .gate_bit = JZ_CLOCK_GATE_I2C,
- .ops = &jz_clk_simple_ops,
- },
- [7] = {
- .name = "aic",
- .parent = &jz_clk_ext.clk,
- .gate_bit = JZ_CLOCK_GATE_AIC,
- .ops = &jz_clk_simple_ops,
- },
-};
-
-static struct static_clk jz_clk_rtc = {
- .clk = {
- .name = "rtc",
- .gate_bit = JZ_CLOCK_GATE_RTC,
- .ops = &jz_clk_static_ops,
- },
- .rate = 32768,
-};
-
-int clk_enable(struct clk *clk)
-{
- if (!clk->ops->enable)
- return -EINVAL;
-
- return clk->ops->enable(clk);
-}
-EXPORT_SYMBOL_GPL(clk_enable);
-
-void clk_disable(struct clk *clk)
-{
- if (clk->ops->disable)
- clk->ops->disable(clk);
-}
-EXPORT_SYMBOL_GPL(clk_disable);
-
-int clk_is_enabled(struct clk *clk)
-{
- if (clk->ops->is_enabled)
- return clk->ops->is_enabled(clk);
-
- return 1;
-}
-
-unsigned long clk_get_rate(struct clk *clk)
-{
- if (clk->ops->get_rate)
- return clk->ops->get_rate(clk);
- if (clk->parent)
- return clk_get_rate(clk->parent);
-
- return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(clk_get_rate);
-
-int clk_set_rate(struct clk *clk, unsigned long rate)
-{
- if (!clk->ops->set_rate)
- return -EINVAL;
- return clk->ops->set_rate(clk, rate);
-}
-EXPORT_SYMBOL_GPL(clk_set_rate);
-
-long clk_round_rate(struct clk *clk, unsigned long rate)
-{
- if (clk->ops->round_rate)
- return clk->ops->round_rate(clk, rate);
-
- return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(clk_round_rate);
-
-int clk_set_parent(struct clk *clk, struct clk *parent)
-{
- int ret;
- int enabled;
-
- if (!clk->ops->set_parent)
- return -EINVAL;
-
- enabled = clk_is_enabled(clk);
- if (enabled)
- clk_disable(clk);
- ret = clk->ops->set_parent(clk, parent);
- if (enabled)
- clk_enable(clk);
-
- jz4740_clock_debugfs_update_parent(clk);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(clk_set_parent);
-
-struct clk *clk_get(struct device *dev, const char *name)
-{
- struct clk *clk;
-
- list_for_each_entry(clk, &jz_clocks, list) {
- if (strcmp(clk->name, name) == 0)
- return clk;
- }
- return ERR_PTR(-ENXIO);
-}
-EXPORT_SYMBOL_GPL(clk_get);
-
-void clk_put(struct clk *clk)
-{
-}
-EXPORT_SYMBOL_GPL(clk_put);
-
-static inline void clk_add(struct clk *clk)
-{
- list_add_tail(&clk->list, &jz_clocks);
-
- jz4740_clock_debugfs_add_clk(clk);
-}
-
-static void clk_register_clks(void)
-{
- size_t i;
-
- clk_add(&jz_clk_ext.clk);
- clk_add(&jz_clk_pll);
- clk_add(&jz_clk_pll_half);
- clk_add(&jz_clk_cpu.clk);
- clk_add(&jz_clk_high_speed_peripheral.clk);
- clk_add(&jz_clk_low_speed_peripheral.clk);
- clk_add(&jz_clk_ko);
- clk_add(&jz_clk_ld);
- clk_add(&jz_clk_rtc.clk);
-
- for (i = 0; i < ARRAY_SIZE(jz4740_clock_divided_clks); ++i)
- clk_add(&jz4740_clock_divided_clks[i].clk);
-
- for (i = 0; i < ARRAY_SIZE(jz4740_clock_simple_clks); ++i)
- clk_add(&jz4740_clock_simple_clks[i]);
}
void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode)
@@ -891,33 +116,9 @@ void jz4740_clock_resume(void)
int jz4740_clock_init(void)
{
- uint32_t val;
-
jz_clock_base = ioremap(JZ4740_CPM_BASE_ADDR, 0x100);
if (!jz_clock_base)
return -EBUSY;
- spin_lock_init(&jz_clock_lock);
-
- jz_clk_ext.rate = jz4740_clock_bdata.ext_rate;
- jz_clk_rtc.rate = jz4740_clock_bdata.rtc_rate;
-
- val = jz_clk_reg_read(JZ_REG_CLOCK_SPI);
-
- if (val & JZ_CLOCK_SPI_SRC_PLL)
- jz4740_clock_divided_clks[1].clk.parent = &jz_clk_pll_half;
-
- val = jz_clk_reg_read(JZ_REG_CLOCK_CTRL);
-
- if (val & JZ_CLOCK_CTRL_I2S_SRC_PLL)
- jz4740_clock_divided_clks[0].clk.parent = &jz_clk_pll_half;
-
- if (val & JZ_CLOCK_CTRL_UDC_SRC_PLL)
- jz4740_clock_simple_clks[0].parent = &jz_clk_pll_half;
-
- jz4740_clock_debugfs_init();
-
- clk_register_clks();
-
return 0;
}
diff --git a/arch/mips/jz4740/clock.h b/arch/mips/jz4740/clock.h
index 5d07499..86a3e01 100644
--- a/arch/mips/jz4740/clock.h
+++ b/arch/mips/jz4740/clock.h
@@ -16,61 +16,10 @@
#ifndef __MIPS_JZ4740_CLOCK_H__
#define __MIPS_JZ4740_CLOCK_H__
+#include <linux/clk.h>
#include <linux/list.h>
-struct jz4740_clock_board_data {
- unsigned long ext_rate;
- unsigned long rtc_rate;
-};
-
-extern struct jz4740_clock_board_data jz4740_clock_bdata;
-
void jz4740_clock_suspend(void);
void jz4740_clock_resume(void);
-struct clk;
-
-struct clk_ops {
- unsigned long (*get_rate)(struct clk *clk);
- unsigned long (*round_rate)(struct clk *clk, unsigned long rate);
- int (*set_rate)(struct clk *clk, unsigned long rate);
- int (*enable)(struct clk *clk);
- int (*disable)(struct clk *clk);
- int (*is_enabled)(struct clk *clk);
-
- int (*set_parent)(struct clk *clk, struct clk *parent);
-
-};
-
-struct clk {
- const char *name;
- struct clk *parent;
-
- uint32_t gate_bit;
-
- const struct clk_ops *ops;
-
- struct list_head list;
-
-#ifdef CONFIG_DEBUG_FS
- struct dentry *debugfs_entry;
- struct dentry *debugfs_parent_entry;
-#endif
-
-};
-
-#define JZ4740_CLK_NOT_GATED ((uint32_t)-1)
-
-int clk_is_enabled(struct clk *clk);
-
-#ifdef CONFIG_DEBUG_FS
-void jz4740_clock_debugfs_init(void);
-void jz4740_clock_debugfs_add_clk(struct clk *clk);
-void jz4740_clock_debugfs_update_parent(struct clk *clk);
-#else
-static inline void jz4740_clock_debugfs_init(void) {};
-static inline void jz4740_clock_debugfs_add_clk(struct clk *clk) {};
-static inline void jz4740_clock_debugfs_update_parent(struct clk *clk) {};
-#endif
-
#endif
diff --git a/arch/mips/jz4740/time.c b/arch/mips/jz4740/time.c
index bff2ac9..caa796d 100644
--- a/arch/mips/jz4740/time.c
+++ b/arch/mips/jz4740/time.c
@@ -14,6 +14,7 @@
*/
#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/time.h>
@@ -112,6 +113,7 @@ void __init plat_time_init(void)
uint16_t ctrl;
struct clk *ext_clk;
+ of_clk_init(NULL);
jz4740_clock_init();
jz4740_timer_init();
diff --git a/drivers/clk/jz47xx/Makefile b/drivers/clk/jz47xx/Makefile
index ac594e5..21746fc 100644
--- a/drivers/clk/jz47xx/Makefile
+++ b/drivers/clk/jz47xx/Makefile
@@ -1 +1,2 @@
obj-y += jz47xx-cgu.o
+obj-$(CONFIG_MACH_JZ4740) += jz4740-cgu.o
diff --git a/drivers/clk/jz47xx/jz4740-cgu.c b/drivers/clk/jz47xx/jz4740-cgu.c
new file mode 100644
index 0000000..83f1e1f
--- /dev/null
+++ b/drivers/clk/jz47xx/jz4740-cgu.c
@@ -0,0 +1,219 @@
+/*
+ * Ingenic jz4740 SoC CGU driver
+ *
+ * Copyright (c) 2015 Imagination Technologies
+ * Author: Paul Burton <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <dt-bindings/clock/jz4740-cgu.h>
+#include "jz47xx-cgu.h"
+
+/* CGU register offsets */
+#define CGU_REG_CPCCR 0x00
+#define CGU_REG_CPPCR 0x10
+#define CGU_REG_I2SCDR 0x60
+#define CGU_REG_LPCDR 0x64
+#define CGU_REG_MSCCDR 0x68
+#define CGU_REG_UHCCDR 0x6c
+#define CGU_REG_SSICDR 0x74
+
+/* bits within a PLL control register */
+#define PLLCTL_M_SHIFT 23
+#define PLLCTL_M_MASK (0x1ff << PLLCTL_M_SHIFT)
+#define PLLCTL_N_SHIFT 18
+#define PLLCTL_N_MASK (0x1f << PLLCTL_N_SHIFT)
+#define PLLCTL_OD_SHIFT 16
+#define PLLCTL_OD_MASK (0x3 << PLLCTL_OD_SHIFT)
+#define PLLCTL_STABLE (1 << 10)
+#define PLLCTL_BYPASS (1 << 9)
+#define PLLCTL_ENABLE (1 << 8)
+
+static struct jz47xx_cgu *cgu;
+
+static const s8 pll_od_encoding[4] = {
+ 0x0, 0x1, -1, 0x3,
+};
+
+static const struct jz47xx_cgu_clk_info jz4740_cgu_clocks[] = {
+
+ /* External clocks */
+
+ [JZ4740_CLK_EXT] = { "ext", CGU_CLK_EXT },
+ [JZ4740_CLK_RTC] = { "rtc", CGU_CLK_EXT },
+
+ [JZ4740_CLK_PLL] = {
+ "pll", CGU_CLK_PLL,
+ .parents = { JZ4740_CLK_EXT, -1 },
+ .pll = {
+ .reg = CGU_REG_CPPCR,
+ .m_shift = 23,
+ .m_bits = 9,
+ .m_offset = 2,
+ .n_shift = 18,
+ .n_bits = 5,
+ .n_offset = 2,
+ .od_shift = 16,
+ .od_bits = 2,
+ .od_max = 4,
+ .od_encoding = pll_od_encoding,
+ .stable_bit = 10,
+ .bypass_bit = 9,
+ .enable_bit = 8,
+ },
+ },
+
+ /* Muxes & dividers */
+
+ [JZ4740_CLK_PLL_HALF] = {
+ "pll half", CGU_CLK_DIV,
+ .parents = { JZ4740_CLK_PLL, -1 },
+ .div = { CGU_REG_CPCCR, 21, 1, -1, -1, -1 },
+ },
+
+ [JZ4740_CLK_CCLK] = {
+ "cclk", CGU_CLK_DIV,
+ .parents = { JZ4740_CLK_PLL, -1 },
+ .div = { CGU_REG_CPCCR, 0, 4, 22, -1, -1 },
+ },
+
+ [JZ4740_CLK_HCLK] = {
+ "hclk", CGU_CLK_DIV,
+ .parents = { JZ4740_CLK_PLL, -1 },
+ .div = { CGU_REG_CPCCR, 4, 4, 22, -1, -1 },
+ },
+
+ [JZ4740_CLK_PCLK] = {
+ "pclk", CGU_CLK_DIV,
+ .parents = { JZ4740_CLK_PLL, -1 },
+ .div = { CGU_REG_CPCCR, 8, 4, 22, -1, -1 },
+ },
+
+ [JZ4740_CLK_MCLK] = {
+ "mclk", CGU_CLK_DIV,
+ .parents = { JZ4740_CLK_PLL, -1 },
+ .div = { CGU_REG_CPCCR, 12, 4, 22, -1, -1 },
+ },
+
+ [JZ4740_CLK_LCD] = {
+ "lcd", CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4740_CLK_PLL_HALF, -1 },
+ .div = { CGU_REG_CPCCR, 16, 5, 22, -1, -1 },
+ .gate_bit = 10,
+ },
+
+ [JZ4740_CLK_LCD_PCLK] = {
+ "lcd_pclk", CGU_CLK_DIV,
+ .parents = { JZ4740_CLK_PLL_HALF, -1 },
+ .div = { CGU_REG_LPCDR, 0, 11, -1, -1, -1 },
+ },
+
+ [JZ4740_CLK_I2S] = {
+ "i2s", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1 },
+ .mux = { CGU_REG_CPCCR, 31, 1 },
+ .div = { CGU_REG_I2SCDR, 0, 8, -1, -1, -1 },
+ .gate_bit = 6,
+ },
+
+ [JZ4740_CLK_SPI] = {
+ "spi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL, -1 },
+ .mux = { CGU_REG_SSICDR, 31, 1 },
+ .div = { CGU_REG_SSICDR, 0, 4, -1, -1, -1 },
+ .gate_bit = 4,
+ },
+
+ [JZ4740_CLK_MMC] = {
+ "mmc", CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4740_CLK_PLL_HALF, -1 },
+ .div = { CGU_REG_MSCCDR, 0, 5, -1, -1, -1 },
+ .gate_bit = 7,
+ },
+
+ [JZ4740_CLK_UHC] = {
+ "uhc", CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4740_CLK_PLL_HALF, -1 },
+ .div = { CGU_REG_UHCCDR, 0, 4, -1, -1, -1 },
+ .gate_bit = 14,
+ },
+
+ [JZ4740_CLK_UDC] = {
+ "udc", CGU_CLK_MUX | CGU_CLK_DIV,
+ .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1 },
+ .mux = { CGU_REG_CPCCR, 29, 1 },
+ .div = { CGU_REG_CPCCR, 23, 6, -1, -1, -1 },
+ /* TODO: gate via SCR */
+ },
+
+ /* Gate-only clocks */
+
+ [JZ4740_CLK_UART0] = {
+ "uart0", CGU_CLK_GATE,
+ .parents = { JZ4740_CLK_EXT, -1 },
+ .gate_bit = 0,
+ },
+
+ [JZ4740_CLK_UART1] = {
+ "uart1", CGU_CLK_GATE,
+ .parents = { JZ4740_CLK_EXT, -1 },
+ .gate_bit = 15,
+ },
+
+ [JZ4740_CLK_DMA] = {
+ "dma", CGU_CLK_GATE,
+ .parents = { JZ4740_CLK_PCLK, -1 },
+ .gate_bit = 12,
+ },
+
+ [JZ4740_CLK_IPU] = {
+ "ipu", CGU_CLK_GATE,
+ .parents = { JZ4740_CLK_PCLK, -1 },
+ .gate_bit = 13,
+ },
+
+ [JZ4740_CLK_ADC] = {
+ "adc", CGU_CLK_GATE,
+ .parents = { JZ4740_CLK_EXT, -1 },
+ .gate_bit = 8,
+ },
+
+ [JZ4740_CLK_I2C] = {
+ "i2c", CGU_CLK_GATE,
+ .parents = { JZ4740_CLK_EXT, -1 },
+ .gate_bit = 3,
+ },
+
+ [JZ4740_CLK_AIC] = {
+ "aic", CGU_CLK_GATE,
+ .parents = { JZ4740_CLK_EXT, -1 },
+ .gate_bit = 5,
+ },
+};
+
+static void __init jz4740_cgu_init(struct device_node *np)
+{
+ int retval;
+ cgu = jz47xx_cgu_new(jz4740_cgu_clocks, ARRAY_SIZE(jz4740_cgu_clocks),
+ np);
+ if (!cgu)
+ pr_err("%s: failed to initialise CGU\n", __func__);
+
+ retval = jz47xx_cgu_register_clocks(cgu);
+ if (retval)
+ pr_err("%s: failed to register CGU Clocks\n", __func__);
+}
+CLK_OF_DECLARE(jz4740_cgu, "ingenic,jz4740-cgu", jz4740_cgu_init);
--
1.9.1
From: Paul Burton <[email protected]>
The jz4740-cgu driver already has access to the CGU, so it makes sense
to move the few remaining accesses to the CGU from arch/mips/jz4740
there too. Move jz4740_clock_set_wait_mode for such consistency.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
Cc: Mike Turquette <[email protected]>
---
arch/mips/jz4740/clock.c | 16 ----------------
drivers/clk/jz47xx/jz4740-cgu.c | 22 ++++++++++++++++++++++
2 files changed, 22 insertions(+), 16 deletions(-)
diff --git a/arch/mips/jz4740/clock.c b/arch/mips/jz4740/clock.c
index dedee7c..90b44d7 100644
--- a/arch/mips/jz4740/clock.c
+++ b/arch/mips/jz4740/clock.c
@@ -28,7 +28,6 @@
#include "clock.h"
-#define JZ_REG_CLOCK_LOW_POWER 0x04
#define JZ_REG_CLOCK_PLL 0x10
#define JZ_REG_CLOCK_GATE 0x20
@@ -40,9 +39,6 @@
#define JZ_CLOCK_PLL_STABLE BIT(10)
#define JZ_CLOCK_PLL_ENABLED BIT(8)
-#define JZ_CLOCK_LOW_POWER_MODE_DOZE BIT(2)
-#define JZ_CLOCK_LOW_POWER_MODE_SLEEP BIT(0)
-
static void __iomem *jz_clock_base;
static uint32_t jz_clk_reg_read(int reg)
@@ -68,18 +64,6 @@ static void jz_clk_reg_clear_bits(int reg, uint32_t mask)
writel(val, jz_clock_base + reg);
}
-void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode)
-{
- switch (mode) {
- case JZ4740_WAIT_MODE_IDLE:
- jz_clk_reg_clear_bits(JZ_REG_CLOCK_LOW_POWER, JZ_CLOCK_LOW_POWER_MODE_SLEEP);
- break;
- case JZ4740_WAIT_MODE_SLEEP:
- jz_clk_reg_set_bits(JZ_REG_CLOCK_LOW_POWER, JZ_CLOCK_LOW_POWER_MODE_SLEEP);
- break;
- }
-}
-
void jz4740_clock_udc_disable_auto_suspend(void)
{
jz_clk_reg_clear_bits(JZ_REG_CLOCK_GATE, JZ_CLOCK_GATE_UDC);
diff --git a/drivers/clk/jz47xx/jz4740-cgu.c b/drivers/clk/jz47xx/jz4740-cgu.c
index 83f1e1f..ef559e7 100644
--- a/drivers/clk/jz47xx/jz4740-cgu.c
+++ b/drivers/clk/jz47xx/jz4740-cgu.c
@@ -20,10 +20,12 @@
#include <linux/delay.h>
#include <linux/of.h>
#include <dt-bindings/clock/jz4740-cgu.h>
+#include <asm/mach-jz4740/clock.h>
#include "jz47xx-cgu.h"
/* CGU register offsets */
#define CGU_REG_CPCCR 0x00
+#define CGU_REG_LCR 0x04
#define CGU_REG_CPPCR 0x10
#define CGU_REG_I2SCDR 0x60
#define CGU_REG_LPCDR 0x64
@@ -42,6 +44,9 @@
#define PLLCTL_BYPASS (1 << 9)
#define PLLCTL_ENABLE (1 << 8)
+/* bits within the LCR register */
+#define LCR_SLEEP (1 << 0)
+
static struct jz47xx_cgu *cgu;
static const s8 pll_od_encoding[4] = {
@@ -217,3 +222,20 @@ static void __init jz4740_cgu_init(struct device_node *np)
pr_err("%s: failed to register CGU Clocks\n", __func__);
}
CLK_OF_DECLARE(jz4740_cgu, "ingenic,jz4740-cgu", jz4740_cgu_init);
+
+void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode)
+{
+ uint32_t lcr = readl(cgu->base + CGU_REG_LCR);
+
+ switch (mode) {
+ case JZ4740_WAIT_MODE_IDLE:
+ lcr &= ~LCR_SLEEP;
+ break;
+
+ case JZ4740_WAIT_MODE_SLEEP:
+ lcr |= LCR_SLEEP;
+ break;
+ }
+
+ writel(lcr, cgu->base + CGU_REG_LCR);
+}
--
1.9.1
From: Paul Burton <[email protected]>
The jz4740-cgu driver already has access to the CGU, so it makes sense
to move the few remaining accesses to the CGU from arch/mips/jz4740
there too. Move the jz4740_clock_udc_{dis,en}able_auto_suspend functions
there for such consistency.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
Cc: Mike Turquette <[email protected]>
---
arch/mips/jz4740/clock.c | 13 -------------
drivers/clk/jz47xx/jz4740-cgu.c | 20 ++++++++++++++++++++
2 files changed, 20 insertions(+), 13 deletions(-)
diff --git a/arch/mips/jz4740/clock.c b/arch/mips/jz4740/clock.c
index 90b44d7..2a10829 100644
--- a/arch/mips/jz4740/clock.c
+++ b/arch/mips/jz4740/clock.c
@@ -33,7 +33,6 @@
#define JZ_CLOCK_GATE_UART0 BIT(0)
#define JZ_CLOCK_GATE_TCU BIT(1)
-#define JZ_CLOCK_GATE_UDC BIT(11)
#define JZ_CLOCK_GATE_DMAC BIT(12)
#define JZ_CLOCK_PLL_STABLE BIT(10)
@@ -64,18 +63,6 @@ static void jz_clk_reg_clear_bits(int reg, uint32_t mask)
writel(val, jz_clock_base + reg);
}
-void jz4740_clock_udc_disable_auto_suspend(void)
-{
- jz_clk_reg_clear_bits(JZ_REG_CLOCK_GATE, JZ_CLOCK_GATE_UDC);
-}
-EXPORT_SYMBOL_GPL(jz4740_clock_udc_disable_auto_suspend);
-
-void jz4740_clock_udc_enable_auto_suspend(void)
-{
- jz_clk_reg_set_bits(JZ_REG_CLOCK_GATE, JZ_CLOCK_GATE_UDC);
-}
-EXPORT_SYMBOL_GPL(jz4740_clock_udc_enable_auto_suspend);
-
void jz4740_clock_suspend(void)
{
jz_clk_reg_set_bits(JZ_REG_CLOCK_GATE,
diff --git a/drivers/clk/jz47xx/jz4740-cgu.c b/drivers/clk/jz47xx/jz4740-cgu.c
index ef559e7..46b6c1a 100644
--- a/drivers/clk/jz47xx/jz4740-cgu.c
+++ b/drivers/clk/jz47xx/jz4740-cgu.c
@@ -27,6 +27,7 @@
#define CGU_REG_CPCCR 0x00
#define CGU_REG_LCR 0x04
#define CGU_REG_CPPCR 0x10
+#define CGU_REG_CLKGR 0x20
#define CGU_REG_I2SCDR 0x60
#define CGU_REG_LPCDR 0x64
#define CGU_REG_MSCCDR 0x68
@@ -47,6 +48,9 @@
/* bits within the LCR register */
#define LCR_SLEEP (1 << 0)
+/* bits within the CLKGR register */
+#define CLKGR_UDC (1 << 11)
+
static struct jz47xx_cgu *cgu;
static const s8 pll_od_encoding[4] = {
@@ -239,3 +243,19 @@ void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode)
writel(lcr, cgu->base + CGU_REG_LCR);
}
+
+void jz4740_clock_udc_disable_auto_suspend(void)
+{
+ uint32_t clkgr = readl(cgu->base + CGU_REG_CLKGR);
+ clkgr &= ~CLKGR_UDC;
+ writel(clkgr, cgu->base + CGU_REG_CLKGR);
+}
+EXPORT_SYMBOL_GPL(jz4740_clock_udc_disable_auto_suspend);
+
+void jz4740_clock_udc_enable_auto_suspend(void)
+{
+ uint32_t clkgr = readl(cgu->base + CGU_REG_CLKGR);
+ clkgr |= CLKGR_UDC;
+ writel(clkgr, cgu->base + CGU_REG_CLKGR);
+}
+EXPORT_SYMBOL_GPL(jz4740_clock_udc_enable_auto_suspend);
--
1.9.1
From: Paul Burton <[email protected]>
The jz4740-cgu driver already has access to the CGU, so it makes sense
to move the few remaining accesses to the CGU from arch/mips/jz4740
there too. Move the jz4740_clock_{suspend,resume} functions there for
such consistency. The arch/mips/jz4740/clock.c file now contains nothing
more of use & so is removed.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
Cc: Mike Turquette <[email protected]>
---
arch/mips/include/asm/mach-jz4740/clock.h | 2 -
arch/mips/jz4740/Makefile | 2 +-
arch/mips/jz4740/clock.c | 95 -------------------------------
arch/mips/jz4740/time.c | 1 -
drivers/clk/jz47xx/jz4740-cgu.c | 34 +++++++++++
5 files changed, 35 insertions(+), 99 deletions(-)
delete mode 100644 arch/mips/jz4740/clock.c
diff --git a/arch/mips/include/asm/mach-jz4740/clock.h b/arch/mips/include/asm/mach-jz4740/clock.h
index 01d8468..16659cd 100644
--- a/arch/mips/include/asm/mach-jz4740/clock.h
+++ b/arch/mips/include/asm/mach-jz4740/clock.h
@@ -20,8 +20,6 @@ enum jz4740_wait_mode {
JZ4740_WAIT_MODE_SLEEP,
};
-int jz4740_clock_init(void);
-
void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode);
void jz4740_clock_udc_enable_auto_suspend(void);
diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile
index 80e326d..61168a2 100644
--- a/arch/mips/jz4740/Makefile
+++ b/arch/mips/jz4740/Makefile
@@ -5,7 +5,7 @@
# Object file lists.
obj-y += prom.o irq.o time.o reset.o setup.o \
- gpio.o clock.o platform.o timer.o serial.o
+ gpio.o platform.o timer.o serial.o
# board specific support
diff --git a/arch/mips/jz4740/clock.c b/arch/mips/jz4740/clock.c
deleted file mode 100644
index 2a10829..0000000
--- a/arch/mips/jz4740/clock.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2010, Lars-Peter Clausen <[email protected]>
- * JZ4740 SoC clock support
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/clk.h>
-#include <linux/clk-provider.h>
-#include <linux/spinlock.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/list.h>
-#include <linux/err.h>
-
-#include <asm/mach-jz4740/clock.h>
-#include <asm/mach-jz4740/base.h>
-
-#include "clock.h"
-
-#define JZ_REG_CLOCK_PLL 0x10
-#define JZ_REG_CLOCK_GATE 0x20
-
-#define JZ_CLOCK_GATE_UART0 BIT(0)
-#define JZ_CLOCK_GATE_TCU BIT(1)
-#define JZ_CLOCK_GATE_DMAC BIT(12)
-
-#define JZ_CLOCK_PLL_STABLE BIT(10)
-#define JZ_CLOCK_PLL_ENABLED BIT(8)
-
-static void __iomem *jz_clock_base;
-
-static uint32_t jz_clk_reg_read(int reg)
-{
- return readl(jz_clock_base + reg);
-}
-
-static void jz_clk_reg_set_bits(int reg, uint32_t mask)
-{
- uint32_t val;
-
- val = readl(jz_clock_base + reg);
- val |= mask;
- writel(val, jz_clock_base + reg);
-}
-
-static void jz_clk_reg_clear_bits(int reg, uint32_t mask)
-{
- uint32_t val;
-
- val = readl(jz_clock_base + reg);
- val &= ~mask;
- writel(val, jz_clock_base + reg);
-}
-
-void jz4740_clock_suspend(void)
-{
- jz_clk_reg_set_bits(JZ_REG_CLOCK_GATE,
- JZ_CLOCK_GATE_TCU | JZ_CLOCK_GATE_DMAC | JZ_CLOCK_GATE_UART0);
-
- jz_clk_reg_clear_bits(JZ_REG_CLOCK_PLL, JZ_CLOCK_PLL_ENABLED);
-}
-
-void jz4740_clock_resume(void)
-{
- uint32_t pll;
-
- jz_clk_reg_set_bits(JZ_REG_CLOCK_PLL, JZ_CLOCK_PLL_ENABLED);
-
- do {
- pll = jz_clk_reg_read(JZ_REG_CLOCK_PLL);
- } while (!(pll & JZ_CLOCK_PLL_STABLE));
-
- jz_clk_reg_clear_bits(JZ_REG_CLOCK_GATE,
- JZ_CLOCK_GATE_TCU | JZ_CLOCK_GATE_DMAC | JZ_CLOCK_GATE_UART0);
-}
-
-int jz4740_clock_init(void)
-{
- jz_clock_base = ioremap(JZ4740_CPM_BASE_ADDR, 0x100);
- if (!jz_clock_base)
- return -EBUSY;
-
- return 0;
-}
diff --git a/arch/mips/jz4740/time.c b/arch/mips/jz4740/time.c
index caa796d..121ec3a 100644
--- a/arch/mips/jz4740/time.c
+++ b/arch/mips/jz4740/time.c
@@ -114,7 +114,6 @@ void __init plat_time_init(void)
struct clk *ext_clk;
of_clk_init(NULL);
- jz4740_clock_init();
jz4740_timer_init();
ext_clk = clk_get(NULL, "ext");
diff --git a/drivers/clk/jz47xx/jz4740-cgu.c b/drivers/clk/jz47xx/jz4740-cgu.c
index 46b6c1a..3325bd8 100644
--- a/drivers/clk/jz47xx/jz4740-cgu.c
+++ b/drivers/clk/jz47xx/jz4740-cgu.c
@@ -259,3 +259,37 @@ void jz4740_clock_udc_enable_auto_suspend(void)
writel(clkgr, cgu->base + CGU_REG_CLKGR);
}
EXPORT_SYMBOL_GPL(jz4740_clock_udc_enable_auto_suspend);
+
+#define JZ_CLOCK_GATE_UART0 BIT(0)
+#define JZ_CLOCK_GATE_TCU BIT(1)
+#define JZ_CLOCK_GATE_DMAC BIT(12)
+
+void jz4740_clock_suspend(void)
+{
+ uint32_t clkgr, cppcr;
+
+ clkgr = readl(cgu->base + CGU_REG_CLKGR);
+ clkgr |= JZ_CLOCK_GATE_TCU | JZ_CLOCK_GATE_DMAC | JZ_CLOCK_GATE_UART0;
+ writel(clkgr, cgu->base + CGU_REG_CLKGR);
+
+ cppcr = readl(cgu->base + CGU_REG_CPPCR);
+ cppcr &= ~BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.enable_bit);
+ writel(cppcr, cgu->base + CGU_REG_CPPCR);
+}
+
+void jz4740_clock_resume(void)
+{
+ uint32_t clkgr, cppcr;
+
+ cppcr = readl(cgu->base + CGU_REG_CPPCR);
+ cppcr |= BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.enable_bit);
+ writel(cppcr, cgu->base + CGU_REG_CPPCR);
+
+ do {
+ cppcr = readl(cgu->base + CGU_REG_CPPCR);
+ } while (!(cppcr & BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.stable_bit)));
+
+ clkgr = readl(cgu->base + CGU_REG_CLKGR);
+ clkgr &= ~(JZ_CLOCK_GATE_TCU | JZ_CLOCK_GATE_DMAC | JZ_CLOCK_GATE_UART0);
+ writel(clkgr, cgu->base + CGU_REG_CLKGR);
+}
--
1.9.1
From: Paul Burton <[email protected]>
The only thing remaining in arch/mips/jz4740/clock.h is declarations of
the jz4780_clock_{suspend,resume} functions. Move these to
arch/mips/include/asm/mach-jz4740/clock.h for consistency with similar
functions, and remove the redundant arch/mips/jz4740/clock.h header.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
---
arch/mips/include/asm/mach-jz4740/clock.h | 3 +++
arch/mips/jz4740/clock.h | 25 -------------------------
arch/mips/jz4740/pm.c | 2 --
3 files changed, 3 insertions(+), 27 deletions(-)
delete mode 100644 arch/mips/jz4740/clock.h
diff --git a/arch/mips/include/asm/mach-jz4740/clock.h b/arch/mips/include/asm/mach-jz4740/clock.h
index 16659cd..104d2df 100644
--- a/arch/mips/include/asm/mach-jz4740/clock.h
+++ b/arch/mips/include/asm/mach-jz4740/clock.h
@@ -22,6 +22,9 @@ enum jz4740_wait_mode {
void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode);
+void jz4740_clock_suspend(void);
+void jz4740_clock_resume(void);
+
void jz4740_clock_udc_enable_auto_suspend(void);
void jz4740_clock_udc_disable_auto_suspend(void);
diff --git a/arch/mips/jz4740/clock.h b/arch/mips/jz4740/clock.h
deleted file mode 100644
index 86a3e01..0000000
--- a/arch/mips/jz4740/clock.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2010, Lars-Peter Clausen <[email protected]>
- * JZ4740 SoC clock support
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef __MIPS_JZ4740_CLOCK_H__
-#define __MIPS_JZ4740_CLOCK_H__
-
-#include <linux/clk.h>
-#include <linux/list.h>
-
-void jz4740_clock_suspend(void);
-void jz4740_clock_resume(void);
-
-#endif
diff --git a/arch/mips/jz4740/pm.c b/arch/mips/jz4740/pm.c
index d8e2130..2d8653f 100644
--- a/arch/mips/jz4740/pm.c
+++ b/arch/mips/jz4740/pm.c
@@ -20,8 +20,6 @@
#include <asm/mach-jz4740/clock.h>
-#include "clock.h"
-
static int jz4740_pm_enter(suspend_state_t state)
{
jz4740_clock_suspend();
--
1.9.1
From: Paul Burton <[email protected]>
Allow a devicetree to specify the memory present in the system rather
than probing it from the memory controller. This both saves the probing
for systems where the amount of memory is fixed, and will simplify the
bringup of later jz47xx series SoCs where the memory controller register
layout differs.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
---
arch/mips/Kconfig | 1 +
arch/mips/jz4740/Makefile | 2 ++
arch/mips/jz4740/setup.c | 8 +++++++-
3 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 8b377a7..ef82cd3 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -290,6 +290,7 @@ config MACH_JZ4740
select GENERIC_IRQ_CHIP
select BUILTIN_DTB
select USE_OF
+ select LIBFDT
config LANTIQ
bool "Lantiq based platforms"
diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile
index 61168a2..340dc16 100644
--- a/arch/mips/jz4740/Makefile
+++ b/arch/mips/jz4740/Makefile
@@ -7,6 +7,8 @@
obj-y += prom.o irq.o time.o reset.o setup.o \
gpio.o platform.o timer.o serial.o
+CFLAGS_setup.o = -I$(src)/../../../scripts/dtc/libfdt
+
# board specific support
obj-$(CONFIG_JZ4740_QI_LB60) += board-qi_lb60.o
diff --git a/arch/mips/jz4740/setup.c b/arch/mips/jz4740/setup.c
index 8c08d7d..1bed3cb 100644
--- a/arch/mips/jz4740/setup.c
+++ b/arch/mips/jz4740/setup.c
@@ -18,6 +18,7 @@
#include <linux/io.h>
#include <linux/irqchip.h>
#include <linux/kernel.h>
+#include <linux/libfdt.h>
#include <linux/of_fdt.h>
#include <linux/of_platform.h>
@@ -55,9 +56,14 @@ static void __init jz4740_detect_mem(void)
void __init plat_mem_setup(void)
{
+ int offset;
+
jz4740_reset_init();
- jz4740_detect_mem();
__dt_setup_arch(__dtb_start);
+
+ offset = fdt_path_offset(__dtb_start, "/memory");
+ if (offset < 0)
+ jz4740_detect_mem();
}
void __init device_tree_init(void)
--
1.9.1
From: Paul Burton <[email protected]>
On later jz47xx series SoCs the interrupt controller supports more than
32 interrupts, which it does by duplicating the registers at intervals
of 0x20 bytes within its address space. Add support for an arbitrary
number of interrupts using multiple generic chips, and provide the
number of chips to register from the SoC-specific probe function.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
---
arch/mips/jz4740/irq.c | 58 ++++++++++++++++++++++++++++++++------------------
1 file changed, 37 insertions(+), 21 deletions(-)
diff --git a/arch/mips/jz4740/irq.c b/arch/mips/jz4740/irq.c
index a620b23..3e53a32 100644
--- a/arch/mips/jz4740/irq.c
+++ b/arch/mips/jz4740/irq.c
@@ -33,21 +33,27 @@
#include "../../drivers/irqchip/irqchip.h"
static void __iomem *jz_intc_base;
+static unsigned jz_num_chips;
#define JZ_REG_INTC_STATUS 0x00
#define JZ_REG_INTC_MASK 0x04
#define JZ_REG_INTC_SET_MASK 0x08
#define JZ_REG_INTC_CLEAR_MASK 0x0c
#define JZ_REG_INTC_PENDING 0x10
+#define CHIP_SIZE 0x20
static irqreturn_t jz4740_cascade(int irq, void *data)
{
uint32_t irq_reg;
+ unsigned i;
- irq_reg = readl(jz_intc_base + JZ_REG_INTC_PENDING);
+ for (i = 0; i < jz_num_chips; i++) {
+ irq_reg = readl(jz_intc_base + (i * CHIP_SIZE) + JZ_REG_INTC_PENDING);
+ if (!irq_reg)
+ continue;
- if (irq_reg)
- generic_handle_irq(__fls(irq_reg) + JZ4740_IRQ_BASE);
+ generic_handle_irq(__fls(irq_reg) + (i * 32) + JZ4740_IRQ_BASE);
+ }
return IRQ_HANDLED;
}
@@ -77,39 +83,43 @@ static struct irqaction jz4740_cascade_action = {
.name = "JZ4740 cascade interrupt",
};
-static int __init jz4740_intc_of_init(struct device_node *node,
- struct device_node *parent)
+static int __init jz47xx_intc_of_init(struct device_node *node, unsigned num_chips)
{
struct irq_chip_generic *gc;
struct irq_chip_type *ct;
struct irq_domain *domain;
int parent_irq;
+ unsigned i;
parent_irq = irq_of_parse_and_map(node, 0);
if (!parent_irq)
return -EINVAL;
- jz_intc_base = ioremap(JZ4740_INTC_BASE_ADDR, 0x14);
+ jz_num_chips = num_chips;
+ jz_intc_base = ioremap(JZ4740_INTC_BASE_ADDR,
+ ((num_chips - 1) * CHIP_SIZE) + 0x14);
- /* Mask all irqs */
- writel(0xffffffff, jz_intc_base + JZ_REG_INTC_SET_MASK);
+ for (i = 0; i < num_chips; i++) {
+ /* Mask all irqs */
+ writel(0xffffffff, jz_intc_base + (i * CHIP_SIZE) + JZ_REG_INTC_SET_MASK);
- gc = irq_alloc_generic_chip("INTC", 1, JZ4740_IRQ_BASE, jz_intc_base,
- handle_level_irq);
+ gc = irq_alloc_generic_chip("INTC", 1, JZ4740_IRQ_BASE + (i * 32),
+ jz_intc_base + (i * CHIP_SIZE), handle_level_irq);
- gc->wake_enabled = IRQ_MSK(32);
+ gc->wake_enabled = IRQ_MSK(32);
- ct = gc->chip_types;
- ct->regs.enable = JZ_REG_INTC_CLEAR_MASK;
- ct->regs.disable = JZ_REG_INTC_SET_MASK;
- ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
- ct->chip.irq_mask = irq_gc_mask_disable_reg;
- ct->chip.irq_mask_ack = irq_gc_mask_disable_reg;
- ct->chip.irq_set_wake = irq_gc_set_wake;
- ct->chip.irq_suspend = jz4740_irq_suspend;
- ct->chip.irq_resume = jz4740_irq_resume;
+ ct = gc->chip_types;
+ ct->regs.enable = JZ_REG_INTC_CLEAR_MASK;
+ ct->regs.disable = JZ_REG_INTC_SET_MASK;
+ ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
+ ct->chip.irq_mask = irq_gc_mask_disable_reg;
+ ct->chip.irq_mask_ack = irq_gc_mask_disable_reg;
+ ct->chip.irq_set_wake = irq_gc_set_wake;
+ ct->chip.irq_suspend = jz4740_irq_suspend;
+ ct->chip.irq_resume = jz4740_irq_resume;
- irq_setup_generic_chip(gc, IRQ_MSK(32), 0, 0, IRQ_NOPROBE | IRQ_LEVEL);
+ irq_setup_generic_chip(gc, IRQ_MSK(32), 0, 0, IRQ_NOPROBE | IRQ_LEVEL);
+ }
domain = irq_domain_add_legacy(node, num_chips * 32, JZ4740_IRQ_BASE, 0,
&irq_domain_simple_ops, NULL);
@@ -119,6 +129,12 @@ static int __init jz4740_intc_of_init(struct device_node *node,
setup_irq(parent_irq, &jz4740_cascade_action);
return 0;
}
+
+static int __init jz4740_intc_of_init(struct device_node *node,
+ struct device_node *parent)
+{
+ return jz47xx_intc_of_init(node, 1);
+}
IRQCHIP_DECLARE(jz4740_intc, "ingenic,jz4740-intc", jz4740_intc_of_init);
#ifdef CONFIG_DEBUG_FS
--
1.9.1
From: Paul Burton <[email protected]>
For interrupts numbered after those of the interrupt controller, define
their numbers based upon the number of interrupts provided by the SoC
interrupt controller. This is in preparation for supporting later jz47xx
series SoCs which provide more interrupts.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
---
arch/mips/include/asm/mach-jz4740/irq.h | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/arch/mips/include/asm/mach-jz4740/irq.h b/arch/mips/include/asm/mach-jz4740/irq.h
index df50736..b218f76 100644
--- a/arch/mips/include/asm/mach-jz4740/irq.h
+++ b/arch/mips/include/asm/mach-jz4740/irq.h
@@ -19,6 +19,10 @@
#define MIPS_CPU_IRQ_BASE 0
#define JZ4740_IRQ_BASE 8
+#ifdef CONFIG_MACH_JZ4740
+# define NR_INTC_IRQS 32
+#endif
+
/* 1st-level interrupts */
#define JZ4740_IRQ(x) (JZ4740_IRQ_BASE + (x))
#define JZ4740_IRQ_I2C JZ4740_IRQ(1)
@@ -45,12 +49,12 @@
#define JZ4740_IRQ_LCD JZ4740_IRQ(30)
/* 2nd-level interrupts */
-#define JZ4740_IRQ_DMA(x) (JZ4740_IRQ(32) + (x))
+#define JZ4740_IRQ_DMA(x) (JZ4740_IRQ(NR_INTC_IRQS) + (x))
#define JZ4740_IRQ_INTC_GPIO(x) (JZ4740_IRQ_GPIO0 - (x))
-#define JZ4740_IRQ_GPIO(x) (JZ4740_IRQ(48) + (x))
+#define JZ4740_IRQ_GPIO(x) (JZ4740_IRQ(NR_INTC_IRQS + 16) + (x))
-#define JZ4740_IRQ_ADC_BASE JZ4740_IRQ(176)
+#define JZ4740_IRQ_ADC_BASE JZ4740_IRQ(NR_INTC_IRQS + 144)
#define NR_IRQS (JZ4740_IRQ_ADC_BASE + 6)
--
1.9.1
From: Paul Burton <[email protected]>
Add binding documentation for Ingenic jz4740 UARTs.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
Cc: [email protected]
---
.../bindings/serial/ingenic,jz4740-uart.txt | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
create mode 100644 Documentation/devicetree/bindings/serial/ingenic,jz4740-uart.txt
diff --git a/Documentation/devicetree/bindings/serial/ingenic,jz4740-uart.txt b/Documentation/devicetree/bindings/serial/ingenic,jz4740-uart.txt
new file mode 100644
index 0000000..9e12de6
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/ingenic,jz4740-uart.txt
@@ -0,0 +1,22 @@
+* Ingenic jz4740 UART
+
+Required properties:
+- compatible : "ingenic,jz4740-uart" or "ingenic,jz4780-uart"
+- reg : offset and length of the register set for the device.
+- interrupts : should contain uart interrupt.
+- clocks : phandles to the module & baud clocks.
+- clock-names: tuple listing input clock names.
+ Required elements: "baud", "module"
+
+Example:
+
+uart0: serial@10030000 {
+ compatible = "ingenic,jz4740-uart";
+ reg = <0x10030000 0x100>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <9>;
+
+ clocks = <&ext>, <&cgu JZ4740_CLK_UART0>;
+ clock-names = "baud", "module";
+};
--
1.9.1
From: Paul Burton <[email protected]>
Introduce a driver suitable for use with the UARTs present in
Ingenic jz47xx series SoCs. These are described as being ns16550
compatible but aren't quite - they require the setting of an extra bit
in the FCR register to enable the UART module. The serial_out
implementation is the same as that in arch/mips/jz4740/serial.c - which
will shortly be removed.
Signed-off-by: Paul Burton <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
Cc: [email protected]
---
V2 changes
Removed FSF address
Added select SERIAL_CORE_CONSOLE to fix a build error
---
drivers/tty/serial/8250/8250_jz47xx.c | 225 ++++++++++++++++++++++++++++++++++
drivers/tty/serial/8250/Kconfig | 9 ++
drivers/tty/serial/8250/Makefile | 1 +
3 files changed, 235 insertions(+)
create mode 100644 drivers/tty/serial/8250/8250_jz47xx.c
diff --git a/drivers/tty/serial/8250/8250_jz47xx.c b/drivers/tty/serial/8250/8250_jz47xx.c
new file mode 100644
index 0000000..49a63ce
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_jz47xx.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2010 Lars-Peter Clausen <[email protected]>
+ * Copyright (C) 2015 Imagination Technologies
+ *
+ * Ingenic jz47xx series UART support
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+
+struct jz47xx_uart_data {
+ struct clk *clk_module;
+ struct clk *clk_baud;
+ int line;
+};
+
+#define UART_FCR_UME BIT(4)
+
+static struct earlycon_device *early_device;
+
+static uint8_t __init early_in(struct uart_port *port, int offset)
+{
+ return readl(port->membase + (offset << 2));
+}
+
+static void __init early_out(struct uart_port *port, int offset, uint8_t value)
+{
+ writel(value, port->membase + (offset << 2));
+}
+
+static void __init jz47xx_early_console_putc(struct uart_port *port, int c)
+{
+ uint8_t lsr;
+
+ do {
+ lsr = early_in(port, UART_LSR);
+ } while ((lsr & UART_LSR_TEMT) == 0);
+
+ early_out(port, UART_TX, c);
+}
+
+static void __init jz47xx_early_console_write(struct console *console,
+ const char *s, unsigned int count)
+{
+ uart_console_write(&early_device->port, s, count, jz47xx_early_console_putc);
+}
+
+static int __init jz47xx_early_console_setup(struct earlycon_device *dev,
+ const char *opt)
+{
+ struct uart_port *port = &dev->port;
+ unsigned int baud, divisor;
+
+ if (!dev->port.membase)
+ return -ENODEV;
+
+ baud = dev->baud ?: 115200;
+ divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud);
+
+ early_out(port, UART_IER, 0);
+ early_out(port, UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN8);
+ early_out(port, UART_DLL, 0);
+ early_out(port, UART_DLM, 0);
+ early_out(port, UART_LCR, UART_LCR_WLEN8);
+ early_out(port, UART_FCR, UART_FCR_UME | UART_FCR_CLEAR_XMIT |
+ UART_FCR_CLEAR_RCVR | UART_FCR_ENABLE_FIFO);
+ early_out(port, UART_MCR, UART_MCR_RTS | UART_MCR_DTR);
+
+ early_out(port, UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN8);
+ early_out(port, UART_DLL, divisor & 0xff);
+ early_out(port, UART_DLM, (divisor >> 8) & 0xff);
+ early_out(port, UART_LCR, UART_LCR_WLEN8);
+
+ early_device = dev;
+ dev->con->write = jz47xx_early_console_write;
+
+ return 0;
+}
+EARLYCON_DECLARE(jz4740_uart, jz47xx_early_console_setup);
+OF_EARLYCON_DECLARE(jz4740_uart, "ingenic,jz4740-uart", jz47xx_early_console_setup);
+EARLYCON_DECLARE(jz4780_uart, jz47xx_early_console_setup);
+OF_EARLYCON_DECLARE(jz4780_uart, "ingenic,jz4780-uart", jz47xx_early_console_setup);
+
+static void jz47xx_serial_out(struct uart_port *p, int offset, int value)
+{
+ switch (offset) {
+ case UART_FCR:
+ /* UART module enable */
+ value |= UART_FCR_UME;
+ break;
+
+ case UART_IER:
+ value |= (value & 0x4) << 2;
+ break;
+
+ default:
+ break;
+ }
+
+ writeb(value, p->membase + (offset << p->regshift));
+}
+
+static int jz47xx_probe(struct platform_device *pdev)
+{
+ struct uart_8250_port uart = {};
+ struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ struct jz47xx_uart_data *data;
+ int err;
+
+ if (!regs || !irq) {
+ dev_err(&pdev->dev, "no registers/irq defined\n");
+ return -EINVAL;
+ }
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ spin_lock_init(&uart.port.lock);
+ uart.port.type = PORT_16550;
+ uart.port.flags = UPF_SKIP_TEST | UPF_IOREMAP | UPF_FIXED_TYPE;
+ uart.port.iotype = UPIO_MEM;
+ uart.port.mapbase = regs->start;
+ uart.port.regshift = 2;
+ uart.port.serial_out = jz47xx_serial_out;
+ uart.port.irq = irq->start;
+ uart.port.dev = &pdev->dev;
+
+ uart.port.membase = devm_ioremap(&pdev->dev, regs->start,
+ resource_size(regs));
+ if (!uart.port.membase)
+ return -ENOMEM;
+
+ data->clk_module = devm_clk_get(&pdev->dev, "module");
+ if (IS_ERR(data->clk_module)) {
+ err = PTR_ERR(data->clk_module);
+ if (err != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "unable to get module clock: %d\n", err);
+ return err;
+ }
+
+ data->clk_baud = devm_clk_get(&pdev->dev, "baud");
+ if (IS_ERR(data->clk_baud)) {
+ err = PTR_ERR(data->clk_baud);
+ if (err != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "unable to get baud clock: %d\n", err);
+ return err;
+ }
+
+ err = clk_prepare_enable(data->clk_module);
+ if (err) {
+ dev_err(&pdev->dev, "could not enable module clock: %d\n", err);
+ goto out;
+ }
+
+ err = clk_prepare_enable(data->clk_baud);
+ if (err) {
+ dev_err(&pdev->dev, "could not enable baud clock: %d\n", err);
+ goto out_disable_moduleclk;
+ }
+ uart.port.uartclk = clk_get_rate(data->clk_baud);
+
+ data->line = serial8250_register_8250_port(&uart);
+ if (data->line < 0) {
+ err = data->line;
+ goto out_disable_baudclk;
+ }
+
+ platform_set_drvdata(pdev, data);
+ return 0;
+
+out_disable_baudclk:
+ clk_disable_unprepare(data->clk_baud);
+out_disable_moduleclk:
+ clk_disable_unprepare(data->clk_module);
+out:
+ return err;
+}
+
+static int jz47xx_remove(struct platform_device *pdev)
+{
+ struct jz47xx_uart_data *data = platform_get_drvdata(pdev);
+
+ serial8250_unregister_port(data->line);
+ clk_disable_unprepare(data->clk_module);
+ clk_disable_unprepare(data->clk_baud);
+ return 0;
+}
+
+static const struct of_device_id jz47xx_of_match[] = {
+ { .compatible = "ingenic,jz4740-uart" },
+ { .compatible = "ingenic,jz4780-uart" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, jz47xx_of_match);
+
+static struct platform_driver jz47xx_platform_driver = {
+ .driver = {
+ .name = "jz47xx-uart",
+ .owner = THIS_MODULE,
+ .of_match_table = jz47xx_of_match,
+ },
+ .probe = jz47xx_probe,
+ .remove = jz47xx_remove,
+};
+
+module_platform_driver(jz47xx_platform_driver);
+
+MODULE_AUTHOR("Paul Burton");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Ingenic jz47xx SoC series UART driver");
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 0fcbcd2..ebb298e 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -322,3 +322,12 @@ config SERIAL_8250_MT6577
help
If you have a Mediatek based board and want to use the
serial port, say Y to this option. If unsure, say N.
+
+config SERIAL_8250_JZ47XX
+ tristate "Support for Ingenic jz47xx series serial ports"
+ depends on SERIAL_8250
+ select SERIAL_EARLYCON
+ select SERIAL_CORE_CONSOLE
+ help
+ If you have a system using an Ingenic jz47xx series SoC and wish to
+ make use of its UARTs, say Y to this option. If unsure, say N.
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 31e7cdc..ddbcb7a 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -23,3 +23,4 @@ obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o
obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o
obj-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o
obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o
+obj-$(CONFIG_SERIAL_8250_JZ47XX) += 8250_jz47xx.o
--
1.9.1
From: Paul Burton <[email protected]>
Allow platforms to set BAUD_BASE, which is used by earlycon to calculate
the baud clock.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
---
V2 Removed FSF address
---
arch/mips/include/asm/Kbuild | 1 -
arch/mips/include/asm/mach-generic/serial.h | 21 +++++++++++++++++++++
arch/mips/include/asm/serial.h | 21 +++++++++++++++++++++
3 files changed, 42 insertions(+), 1 deletion(-)
create mode 100644 arch/mips/include/asm/mach-generic/serial.h
create mode 100644 arch/mips/include/asm/serial.h
diff --git a/arch/mips/include/asm/Kbuild b/arch/mips/include/asm/Kbuild
index 200efea..3cd9114 100644
--- a/arch/mips/include/asm/Kbuild
+++ b/arch/mips/include/asm/Kbuild
@@ -13,7 +13,6 @@ generic-y += preempt.h
generic-y += scatterlist.h
generic-y += sections.h
generic-y += segment.h
-generic-y += serial.h
generic-y += trace_clock.h
generic-y += ucontext.h
generic-y += user.h
diff --git a/arch/mips/include/asm/mach-generic/serial.h b/arch/mips/include/asm/mach-generic/serial.h
new file mode 100644
index 0000000..25932bb
--- /dev/null
+++ b/arch/mips/include/asm/mach-generic/serial.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2015 Imagination Technologies
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MACH_GENERIC_SERIAL_H__
+#define __MACH_GENERIC_SERIAL_H__
+
+#include <asm-generic/serial.h>
+
+#endif /* __MACH_GENERIC_SERIAL_H__ */
diff --git a/arch/mips/include/asm/serial.h b/arch/mips/include/asm/serial.h
new file mode 100644
index 0000000..a50e7b0
--- /dev/null
+++ b/arch/mips/include/asm/serial.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2015 Imagination Technologies
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ASM_SERIAL_H__
+#define __ASM_SERIAL_H__
+
+#include_next <serial.h>
+
+#endif /* __ASM_SERIAL_H__ */
--
1.9.1
From: Paul Burton <[email protected]>
Remove the serial support from arch/mips/jz4740 & make use of the new
jz47xx-uart driver. This is done for both regular & early console
output.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
---
V2 Removed FSF header
---
arch/mips/Kconfig | 1 -
arch/mips/boot/dts/jz4740.dtsi | 22 ++++++++++++++
arch/mips/boot/dts/qi_lb60.dts | 4 +++
arch/mips/configs/qi_lb60_defconfig | 1 +
arch/mips/include/asm/mach-jz4740/platform.h | 2 --
arch/mips/include/asm/mach-jz4740/serial.h | 21 +++++++++++++
arch/mips/jz4740/Makefile | 2 +-
arch/mips/jz4740/board-qi_lb60.c | 2 --
arch/mips/jz4740/platform.c | 44 ----------------------------
arch/mips/jz4740/prom.c | 13 --------
arch/mips/jz4740/serial.c | 33 ---------------------
arch/mips/jz4740/serial.h | 23 ---------------
12 files changed, 49 insertions(+), 119 deletions(-)
create mode 100644 arch/mips/include/asm/mach-jz4740/serial.h
delete mode 100644 arch/mips/jz4740/serial.c
delete mode 100644 arch/mips/jz4740/serial.h
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index ef82cd3..622d0aa 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -285,7 +285,6 @@ config MACH_JZ4740
select DMA_NONCOHERENT
select IRQ_CPU
select ARCH_REQUIRE_GPIOLIB
- select SYS_HAS_EARLY_PRINTK
select COMMON_CLK
select GENERIC_IRQ_CHIP
select BUILTIN_DTB
diff --git a/arch/mips/boot/dts/jz4740.dtsi b/arch/mips/boot/dts/jz4740.dtsi
index ef679b4..c52d92d 100644
--- a/arch/mips/boot/dts/jz4740.dtsi
+++ b/arch/mips/boot/dts/jz4740.dtsi
@@ -43,4 +43,26 @@
#clock-cells = <1>;
};
+
+ uart0: serial@10030000 {
+ compatible = "ingenic,jz4740-uart";
+ reg = <0x10030000 0x100>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <9>;
+
+ clocks = <&ext>, <&cgu JZ4740_CLK_UART0>;
+ clock-names = "baud", "module";
+ };
+
+ uart1: serial@10031000 {
+ compatible = "ingenic,jz4740-uart";
+ reg = <0x10031000 0x100>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <8>;
+
+ clocks = <&ext>, <&cgu JZ4740_CLK_UART1>;
+ clock-names = "baud", "module";
+ };
};
diff --git a/arch/mips/boot/dts/qi_lb60.dts b/arch/mips/boot/dts/qi_lb60.dts
index 106d13c..2414d63 100644
--- a/arch/mips/boot/dts/qi_lb60.dts
+++ b/arch/mips/boot/dts/qi_lb60.dts
@@ -4,6 +4,10 @@
/ {
compatible = "qi,lb60", "ingenic,jz4740";
+
+ chosen {
+ stdout-path = &uart0;
+ };
};
&ext {
diff --git a/arch/mips/configs/qi_lb60_defconfig b/arch/mips/configs/qi_lb60_defconfig
index 2b96547..04371ab 100644
--- a/arch/mips/configs/qi_lb60_defconfig
+++ b/arch/mips/configs/qi_lb60_defconfig
@@ -66,6 +66,7 @@ CONFIG_SERIAL_8250_CONSOLE=y
# CONFIG_SERIAL_8250_DMA is not set
CONFIG_SERIAL_8250_NR_UARTS=2
CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+CONFIG_SERIAL_8250_JZ47XX=y
# CONFIG_HW_RANDOM is not set
CONFIG_SPI=y
CONFIG_SPI_GPIO=y
diff --git a/arch/mips/include/asm/mach-jz4740/platform.h b/arch/mips/include/asm/mach-jz4740/platform.h
index 069b43a..32cfbe6 100644
--- a/arch/mips/include/asm/mach-jz4740/platform.h
+++ b/arch/mips/include/asm/mach-jz4740/platform.h
@@ -35,6 +35,4 @@ extern struct platform_device jz4740_wdt_device;
extern struct platform_device jz4740_pwm_device;
extern struct platform_device jz4740_dma_device;
-void jz4740_serial_device_register(void);
-
#endif
diff --git a/arch/mips/include/asm/mach-jz4740/serial.h b/arch/mips/include/asm/mach-jz4740/serial.h
new file mode 100644
index 0000000..9f93563
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4740/serial.h
@@ -0,0 +1,21 @@
+/*
+* Copyright (c) 2015 Imagination Technologies
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License as
+* published by the Free Software Foundation; either version 2 of
+* the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+*/
+
+#ifndef __JZ4740_SERIAL_H__
+#define __JZ4740_SERIAL_H__
+
+#define BASE_BAUD (12000000 / 16)
+
+#endif /* __JZ4740_SERIAL_H__ */
diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile
index 340dc16..ae72346 100644
--- a/arch/mips/jz4740/Makefile
+++ b/arch/mips/jz4740/Makefile
@@ -5,7 +5,7 @@
# Object file lists.
obj-y += prom.o irq.o time.o reset.o setup.o \
- gpio.o platform.o timer.o serial.o
+ gpio.o platform.o timer.o
CFLAGS_setup.o = -I$(src)/../../../scripts/dtc/libfdt
diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c
index 0fbb2d8..f84526d 100644
--- a/arch/mips/jz4740/board-qi_lb60.c
+++ b/arch/mips/jz4740/board-qi_lb60.c
@@ -473,8 +473,6 @@ static int __init qi_lb60_init_platform_devices(void)
gpiod_add_lookup_table(&qi_lb60_audio_gpio_table);
- jz4740_serial_device_register();
-
spi_register_board_info(qi_lb60_spi_board_info,
ARRAY_SIZE(qi_lb60_spi_board_info));
diff --git a/arch/mips/jz4740/platform.c b/arch/mips/jz4740/platform.c
index 2a5c7c7..8226a36 100644
--- a/arch/mips/jz4740/platform.c
+++ b/arch/mips/jz4740/platform.c
@@ -280,50 +280,6 @@ struct platform_device jz4740_adc_device = {
.resource = jz4740_adc_resources,
};
-/* Serial */
-#define JZ4740_UART_DATA(_id) \
- { \
- .flags = UPF_SKIP_TEST | UPF_IOREMAP | UPF_FIXED_TYPE, \
- .iotype = UPIO_MEM, \
- .regshift = 2, \
- .serial_out = jz4740_serial_out, \
- .type = PORT_16550, \
- .mapbase = JZ4740_UART ## _id ## _BASE_ADDR, \
- .irq = JZ4740_IRQ_UART ## _id, \
- }
-
-static struct plat_serial8250_port jz4740_uart_data[] = {
- JZ4740_UART_DATA(0),
- JZ4740_UART_DATA(1),
- {},
-};
-
-static struct platform_device jz4740_uart_device = {
- .name = "serial8250",
- .id = 0,
- .dev = {
- .platform_data = jz4740_uart_data,
- },
-};
-
-void jz4740_serial_device_register(void)
-{
- struct plat_serial8250_port *p;
- struct clk *ext_clk;
- unsigned long ext_rate;
-
- ext_clk = clk_get(NULL, "ext");
- if (IS_ERR(ext_clk))
- panic("unable to get ext clock");
- ext_rate = clk_get_rate(ext_clk);
- clk_put(ext_clk);
-
- for (p = jz4740_uart_data; p->flags != 0; ++p)
- p->uartclk = ext_rate;
-
- platform_device_register(&jz4740_uart_device);
-}
-
/* Watchdog */
static struct resource jz4740_wdt_resources[] = {
{
diff --git a/arch/mips/jz4740/prom.c b/arch/mips/jz4740/prom.c
index 5a93f38..6984683 100644
--- a/arch/mips/jz4740/prom.c
+++ b/arch/mips/jz4740/prom.c
@@ -53,16 +53,3 @@ void __init prom_init(void)
void __init prom_free_prom_memory(void)
{
}
-
-#define UART_REG(_reg) ((void __iomem *)CKSEG1ADDR(JZ4740_UART0_BASE_ADDR + (_reg << 2)))
-
-void prom_putchar(char c)
-{
- uint8_t lsr;
-
- do {
- lsr = readb(UART_REG(UART_LSR));
- } while ((lsr & UART_LSR_TEMT) == 0);
-
- writeb(c, UART_REG(UART_TX));
-}
diff --git a/arch/mips/jz4740/serial.c b/arch/mips/jz4740/serial.c
deleted file mode 100644
index d23de45..0000000
--- a/arch/mips/jz4740/serial.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2010, Lars-Peter Clausen <[email protected]>
- * JZ4740 serial support
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/io.h>
-#include <linux/serial_core.h>
-#include <linux/serial_reg.h>
-
-void jz4740_serial_out(struct uart_port *p, int offset, int value)
-{
- switch (offset) {
- case UART_FCR:
- value |= 0x10; /* Enable uart module */
- break;
- case UART_IER:
- value |= (value & 0x4) << 2;
- break;
- default:
- break;
- }
- writeb(value, p->membase + (offset << p->regshift));
-}
diff --git a/arch/mips/jz4740/serial.h b/arch/mips/jz4740/serial.h
deleted file mode 100644
index 8eb715b..0000000
--- a/arch/mips/jz4740/serial.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2010, Lars-Peter Clausen <[email protected]>
- * JZ4740 serial support
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef __MIPS_JZ4740_SERIAL_H__
-#define __MIPS_JZ4740_SERIAL_H__
-
-struct uart_port;
-
-void jz4740_serial_out(struct uart_port *p, int offset, int value);
-
-#endif
--
1.9.1
From: Paul Burton <[email protected]>
Document the devictree binding for the Ingenic jz4780 CGU driver.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
Cc: Mike Turquette <[email protected]>
Cc: [email protected]
---
.../bindings/clock/ingenic,jz4780-cgu.txt | 52 +++++++++++++
include/dt-bindings/clock/jz4780-cgu.h | 88 ++++++++++++++++++++++
2 files changed, 140 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/ingenic,jz4780-cgu.txt
create mode 100644 include/dt-bindings/clock/jz4780-cgu.h
diff --git a/Documentation/devicetree/bindings/clock/ingenic,jz4780-cgu.txt b/Documentation/devicetree/bindings/clock/ingenic,jz4780-cgu.txt
new file mode 100644
index 0000000..2432a49
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/ingenic,jz4780-cgu.txt
@@ -0,0 +1,52 @@
+Ingenic jz4780 SoC CGU binding
+
+The CGU in a jz4780 SoC provides all the clocks generated on-chip. It includes
+PLLs, multiplexers, dividers & gates in order to provide a variety of different
+clock signals derived from only 2 external source clocks.
+
+Required properties:
+- compatible: Should be "ingenic,jz4780-cgu"
+- reg: Should be the address & length of the CGU registers
+- clocks: Should contain the phandle & clock specifier for two clocks external
+ to the TCU. First the external crystal "ext" and second the RTC
+ clock source "rtc".
+- clock-names: Should be set to strings naming the clocks specified in the
+ "clocks" property.
+- #clock-cells: Should be 1.
+ Clock consumers specify this argument to identify a clock. The
+ valid values may be found in <dt-bindings/clock/jz4780-cgu.h>.
+
+Example SoC include file:
+
+/ {
+ cgu: jz4780-cgu {
+ compatible = "ingenic,jz4780-cgu";
+ reg = <0x10000000 0x100>;
+ #clock-cells = <1>;
+ };
+
+ uart0: serial@10030000 {
+ clocks = <&cgu JZ4780_CLK_UART0>;
+ };
+};
+
+Example board file:
+
+/ {
+ ext: clock@0 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <48000000>;
+ };
+
+ rtc: clock@1 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ };
+
+ &cgu {
+ clocks = <&ext> <&rtc>;
+ clock-names: "ext", "rtc";
+ };
+};
diff --git a/include/dt-bindings/clock/jz4780-cgu.h b/include/dt-bindings/clock/jz4780-cgu.h
new file mode 100644
index 0000000..467165e
--- /dev/null
+++ b/include/dt-bindings/clock/jz4780-cgu.h
@@ -0,0 +1,88 @@
+/*
+ * This header provides clock numbers for the ingenic,jz4780-cgu DT binding.
+ *
+ * They are roughly ordered as:
+ * - external clocks
+ * - PLLs
+ * - muxes/dividers in the order they appear in the jz4780 programmers manual
+ * - gates in order of their bit in the CLKGR* registers
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_JZ4780_CGU_H__
+#define __DT_BINDINGS_CLOCK_JZ4780_CGU_H__
+
+#define JZ4780_CLK_EXCLK 0
+#define JZ4780_CLK_RTCLK 1
+#define JZ4780_CLK_APLL 2
+#define JZ4780_CLK_MPLL 3
+#define JZ4780_CLK_EPLL 4
+#define JZ4780_CLK_VPLL 5
+#define JZ4780_CLK_OTGPHY 6
+#define JZ4780_CLK_SCLKA 7
+#define JZ4780_CLK_CPUMUX 8
+#define JZ4780_CLK_CPU 9
+#define JZ4780_CLK_L2CACHE 10
+#define JZ4780_CLK_AHB0 11
+#define JZ4780_CLK_AHB2PMUX 12
+#define JZ4780_CLK_AHB2 13
+#define JZ4780_CLK_PCLK 14
+#define JZ4780_CLK_DDR 15
+#define JZ4780_CLK_VPU 16
+#define JZ4780_CLK_I2SPLL 17
+#define JZ4780_CLK_I2S 18
+#define JZ4780_CLK_LCD0PIXCLK 19
+#define JZ4780_CLK_LCD1PIXCLK 20
+#define JZ4780_CLK_MSCMUX 21
+#define JZ4780_CLK_MSC0 22
+#define JZ4780_CLK_MSC1 23
+#define JZ4780_CLK_MSC2 24
+#define JZ4780_CLK_UHC 25
+#define JZ4780_CLK_SSIPLL 26
+#define JZ4780_CLK_SSI 27
+#define JZ4780_CLK_CIMMCLK 28
+#define JZ4780_CLK_PCMPLL 29
+#define JZ4780_CLK_PCM 30
+#define JZ4780_CLK_GPU 31
+#define JZ4780_CLK_HDMI 32
+#define JZ4780_CLK_BCH 33
+#define JZ4780_CLK_NEMC 34
+#define JZ4780_CLK_OTG0 35
+#define JZ4780_CLK_SSI0 36
+#define JZ4780_CLK_SMB0 37
+#define JZ4780_CLK_SMB1 38
+#define JZ4780_CLK_SCC 39
+#define JZ4780_CLK_AIC 40
+#define JZ4780_CLK_TSSI0 41
+#define JZ4780_CLK_OWI 42
+#define JZ4780_CLK_KBC 43
+#define JZ4780_CLK_SADC 44
+#define JZ4780_CLK_UART0 45
+#define JZ4780_CLK_UART1 46
+#define JZ4780_CLK_UART2 47
+#define JZ4780_CLK_UART3 48
+#define JZ4780_CLK_SSI1 49
+#define JZ4780_CLK_SSI2 50
+#define JZ4780_CLK_PDMA 51
+#define JZ4780_CLK_GPS 52
+#define JZ4780_CLK_MAC 53
+#define JZ4780_CLK_SMB2 54
+#define JZ4780_CLK_CIM 55
+#define JZ4780_CLK_LCD 56
+#define JZ4780_CLK_TVE 57
+#define JZ4780_CLK_IPU 58
+#define JZ4780_CLK_DDR0 59
+#define JZ4780_CLK_DDR1 60
+#define JZ4780_CLK_SMB3 61
+#define JZ4780_CLK_TSSI1 62
+#define JZ4780_CLK_COMPRESS 63
+#define JZ4780_CLK_AIC1 64
+#define JZ4780_CLK_GPVLC 65
+#define JZ4780_CLK_OTG1 66
+#define JZ4780_CLK_UART4 67
+#define JZ4780_CLK_AHBMON 68
+#define JZ4780_CLK_SMB4 69
+#define JZ4780_CLK_DES 70
+#define JZ4780_CLK_X2D 71
+#define JZ4780_CLK_CORE1 72
+
+#endif /* __DT_BINDINGS_CLOCK_JZ4780_CGU_H__ */
--
1.9.1
From: Paul Burton <[email protected]>
Add support for the clocks provided by the CGU in the Ingenic jz4780
SoC, making use of the jz47xx-cgu code to do the heavy lifting.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
Cc: Mike Turquette <[email protected]>
---
V2 Removed FSF header
---
drivers/clk/Makefile | 1 +
drivers/clk/jz47xx/Makefile | 1 +
drivers/clk/jz47xx/jz4780-cgu.c | 742 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 744 insertions(+)
create mode 100644 drivers/clk/jz47xx/jz4780-cgu.c
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index fc434c0..3eac9e2 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/
obj-$(CONFIG_ARCH_HIP04) += hisilicon/
obj-$(CONFIG_ARCH_HIX5HD2) += hisilicon/
obj-$(CONFIG_MACH_JZ4740) += jz47xx/
+obj-$(CONFIG_MACH_JZ4780) += jz47xx/
obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/
ifeq ($(CONFIG_COMMON_CLK), y)
obj-$(CONFIG_ARCH_MMP) += mmp/
diff --git a/drivers/clk/jz47xx/Makefile b/drivers/clk/jz47xx/Makefile
index 21746fc..5e0b845 100644
--- a/drivers/clk/jz47xx/Makefile
+++ b/drivers/clk/jz47xx/Makefile
@@ -1,2 +1,3 @@
obj-y += jz47xx-cgu.o
obj-$(CONFIG_MACH_JZ4740) += jz4740-cgu.o
+obj-$(CONFIG_MACH_JZ4780) += jz4780-cgu.o
diff --git a/drivers/clk/jz47xx/jz4780-cgu.c b/drivers/clk/jz47xx/jz4780-cgu.c
new file mode 100644
index 0000000..054db6e
--- /dev/null
+++ b/drivers/clk/jz47xx/jz4780-cgu.c
@@ -0,0 +1,742 @@
+/*
+ * Ingenic jz4780 SoC CGU driver
+ *
+ * Copyright (c) 2013-2015 Imagination Technologies
+ * Author: Paul Burton <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <dt-bindings/clock/jz4780-cgu.h>
+#include "jz47xx-cgu.h"
+
+/* CGU register offsets */
+#define CGU_REG_CLOCKCONTROL 0x00
+#define CGU_REG_PLLCONTROL 0x0c
+#define CGU_REG_APLL 0x10
+#define CGU_REG_MPLL 0x14
+#define CGU_REG_EPLL 0x18
+#define CGU_REG_VPLL 0x1c
+#define CGU_REG_OPCR 0x24
+#define CGU_REG_DDRCDR 0x2c
+#define CGU_REG_VPUCDR 0x30
+#define CGU_REG_USBPCR 0x3c
+#define CGU_REG_USBRDT 0x40
+#define CGU_REG_USBVBFIL 0x44
+#define CGU_REG_USBPCR1 0x48
+#define CGU_REG_LP0CDR 0x54
+#define CGU_REG_I2SCDR 0x60
+#define CGU_REG_LP1CDR 0x64
+#define CGU_REG_MSC0CDR 0x68
+#define CGU_REG_UHCCDR 0x6c
+#define CGU_REG_SSICDR 0x74
+#define CGU_REG_CIMCDR 0x7c
+#define CGU_REG_PCMCDR 0x84
+#define CGU_REG_GPUCDR 0x88
+#define CGU_REG_HDMICDR 0x8c
+#define CGU_REG_MSC1CDR 0xa4
+#define CGU_REG_MSC2CDR 0xa8
+#define CGU_REG_BCHCDR 0xac
+#define CGU_REG_CLOCKSTATUS 0xd4
+
+/* bits within a PLL control register */
+#define PLLCTL_M_SHIFT 19
+#define PLLCTL_M_MASK (0x1fff << PLLCTL_M_SHIFT)
+#define PLLCTL_N_SHIFT 13
+#define PLLCTL_N_MASK (0x3f << PLLCTL_N_SHIFT)
+#define PLLCTL_OD_SHIFT 9
+#define PLLCTL_OD_MASK (0xf << PLLCTL_OD_SHIFT)
+#define PLLCTL_ON (1 << 4)
+#define PLLCTL_BYPASS (1 << 1)
+#define PLLCTL_ENABLE (1 << 0)
+
+/* bits within the OPCR register */
+#define OPCR_SPENDN0 (1 << 7)
+#define OPCR_SPENDN1 (1 << 6)
+
+/* bits within the USBPCR register */
+#define USBPCR_USB_MODE BIT(31)
+#define USBPCR_IDPULLUP_MASK (0x3 << 28)
+#define USBPCR_COMMONONN BIT(25)
+#define USBPCR_VBUSVLDEXT BIT(24)
+#define USBPCR_VBUSVLDEXTSEL BIT(23)
+#define USBPCR_POR BIT(22)
+#define USBPCR_OTG_DISABLE BIT(20)
+#define USBPCR_COMPDISTUNE_MASK (0x7 << 17)
+#define USBPCR_OTGTUNE_MASK (0x7 << 14)
+#define USBPCR_SQRXTUNE_MASK (0x7 << 11)
+#define USBPCR_TXFSLSTUNE_MASK (0xf << 7)
+#define USBPCR_TXPREEMPHTUNE BIT(6)
+#define USBPCR_TXHSXVTUNE_MASK (0x3 << 4)
+#define USBPCR_TXVREFTUNE_MASK 0xf
+
+/* bits within the USBPCR1 register */
+#define USBPCR1_REFCLKSEL_SHIFT 26
+#define USBPCR1_REFCLKSEL_MASK (0x3 << USBPCR1_REFCLKSEL_SHIFT)
+#define USBPCR1_REFCLKSEL_CORE (0x2 << USBPCR1_REFCLKSEL_SHIFT)
+#define USBPCR1_REFCLKDIV_SHIFT 24
+#define USBPCR1_REFCLKDIV_MASK (0x3 << USBPCR1_REFCLKDIV_SHIFT)
+#define USBPCR1_REFCLKDIV_19_2 (0x3 << USBPCR1_REFCLKDIV_SHIFT)
+#define USBPCR1_REFCLKDIV_48 (0x2 << USBPCR1_REFCLKDIV_SHIFT)
+#define USBPCR1_REFCLKDIV_24 (0x1 << USBPCR1_REFCLKDIV_SHIFT)
+#define USBPCR1_REFCLKDIV_12 (0x0 << USBPCR1_REFCLKDIV_SHIFT)
+#define USBPCR1_USB_SEL BIT(28)
+#define USBPCR1_WORD_IF0 BIT(19)
+#define USBPCR1_WORD_IF1 BIT(18)
+
+/* bits within the USBRDT register */
+#define USBRDT_VBFIL_LD_EN BIT(25)
+#define USBRDT_USBRDT_MASK 0x7fffff
+
+/* bits within the USBVBFIL register */
+#define USBVBFIL_IDDIGFIL_SHIFT 16
+#define USBVBFIL_IDDIGFIL_MASK (0xffff << USBVBFIL_IDDIGFIL_SHIFT)
+#define USBVBFIL_USBVBFIL_MASK (0xffff)
+
+static struct jz47xx_cgu *cgu;
+
+static u8 jz4780_otg_phy_get_parent(struct clk_hw *hw)
+{
+ /* we only use CLKCORE, revisit if that ever changes */
+ return 0;
+}
+
+static int jz4780_otg_phy_set_parent(struct clk_hw *hw, u8 idx)
+{
+ unsigned long flags;
+ u32 usbpcr1;
+
+ if (idx > 0)
+ return -EINVAL;
+
+ spin_lock_irqsave(&cgu->power_lock, flags);
+
+ usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1);
+ usbpcr1 &= ~USBPCR1_REFCLKSEL_MASK;
+ /* we only use CLKCORE */
+ usbpcr1 |= USBPCR1_REFCLKSEL_CORE;
+ writel(usbpcr1, cgu->base + CGU_REG_USBPCR1);
+
+ spin_unlock_irqrestore(&cgu->power_lock, flags);
+ return 0;
+}
+
+static unsigned long jz4780_otg_phy_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ u32 usbpcr1;
+ unsigned refclk_div;
+
+ usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1);
+ refclk_div = usbpcr1 & USBPCR1_REFCLKDIV_MASK;
+
+ switch (refclk_div) {
+ case USBPCR1_REFCLKDIV_12:
+ return 12000000;
+
+ case USBPCR1_REFCLKDIV_24:
+ return 24000000;
+
+ case USBPCR1_REFCLKDIV_48:
+ return 48000000;
+
+ case USBPCR1_REFCLKDIV_19_2:
+ return 19200000;
+ }
+
+ BUG();
+ return parent_rate;
+}
+
+static long jz4780_otg_phy_round_rate(struct clk_hw *hw, unsigned long req_rate,
+ unsigned long *parent_rate)
+{
+ if (req_rate < 15600000)
+ return 12000000;
+
+ if (req_rate < 21600000)
+ return 19200000;
+
+ if (req_rate < 36000000)
+ return 24000000;
+
+ return 48000000;
+}
+
+static int jz4780_otg_phy_set_rate(struct clk_hw *hw, unsigned long req_rate,
+ unsigned long parent_rate)
+{
+ unsigned long flags;
+ u32 usbpcr1, div_bits;
+
+ switch (req_rate) {
+ case 12000000:
+ div_bits = USBPCR1_REFCLKDIV_12;
+ break;
+
+ case 19200000:
+ div_bits = USBPCR1_REFCLKDIV_19_2;
+ break;
+
+ case 24000000:
+ div_bits = USBPCR1_REFCLKDIV_24;
+ break;
+
+ case 48000000:
+ div_bits = USBPCR1_REFCLKDIV_48;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&cgu->power_lock, flags);
+
+ usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1);
+ usbpcr1 &= ~USBPCR1_REFCLKDIV_MASK;
+ usbpcr1 |= div_bits;
+ writel(usbpcr1, cgu->base + CGU_REG_USBPCR1);
+
+ spin_unlock_irqrestore(&cgu->power_lock, flags);
+ return 0;
+}
+
+struct clk_ops jz4780_otg_phy_ops = {
+ .get_parent = jz4780_otg_phy_get_parent,
+ .set_parent = jz4780_otg_phy_set_parent,
+
+ .recalc_rate = jz4780_otg_phy_recalc_rate,
+ .round_rate = jz4780_otg_phy_round_rate,
+ .set_rate = jz4780_otg_phy_set_rate,
+};
+
+static const s8 pll_od_encoding[16] = {
+ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+ 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
+};
+
+static const struct jz47xx_cgu_clk_info jz4780_cgu_clocks[] = {
+
+ /* External clocks */
+
+ [JZ4780_CLK_EXCLK] = { "ext", CGU_CLK_EXT },
+ [JZ4780_CLK_RTCLK] = { "rtc", CGU_CLK_EXT },
+
+ /* PLLs */
+
+#define DEF_PLL(name) { \
+ .reg = CGU_REG_ ## name, \
+ .m_shift = 19, \
+ .m_bits = 13, \
+ .m_offset = 1, \
+ .n_shift = 13, \
+ .n_bits = 6, \
+ .n_offset = 1, \
+ .od_shift = 9, \
+ .od_bits = 4, \
+ .od_max = 16, \
+ .od_encoding = pll_od_encoding, \
+ .stable_bit = 6, \
+ .bypass_bit = 1, \
+ .enable_bit = 0, \
+}
+
+ [JZ4780_CLK_APLL] = {
+ "apll", CGU_CLK_PLL,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .pll = DEF_PLL(APLL),
+ },
+
+ [JZ4780_CLK_MPLL] = {
+ "mpll", CGU_CLK_PLL,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .pll = DEF_PLL(MPLL),
+ },
+
+ [JZ4780_CLK_EPLL] = {
+ "epll", CGU_CLK_PLL,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .pll = DEF_PLL(EPLL),
+ },
+
+ [JZ4780_CLK_VPLL] = {
+ "vpll", CGU_CLK_PLL,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .pll = DEF_PLL(VPLL),
+ },
+
+#undef DEF_PLL
+
+ /* Custom (SoC-specific) OTG PHY */
+
+ [JZ4780_CLK_OTGPHY] = {
+ "otg_phy", CGU_CLK_CUSTOM,
+ .parents = { -1, -1, JZ4780_CLK_EXCLK, -1 },
+ .custom = { &jz4780_otg_phy_ops },
+ },
+
+ /* Muxes & dividers */
+
+ [JZ4780_CLK_SCLKA] = {
+ "sclk_a", CGU_CLK_MUX,
+ .parents = { -1, JZ4780_CLK_APLL, JZ4780_CLK_EXCLK,
+ JZ4780_CLK_RTCLK },
+ .mux = { CGU_REG_CLOCKCONTROL, 30, 2 },
+ },
+
+ [JZ4780_CLK_CPUMUX] = {
+ "cpumux", CGU_CLK_MUX,
+ .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
+ JZ4780_CLK_EPLL },
+ .mux = { CGU_REG_CLOCKCONTROL, 28, 2 },
+ },
+
+ [JZ4780_CLK_CPU] = {
+ "cpu", CGU_CLK_DIV,
+ .parents = { JZ4780_CLK_CPUMUX, -1 },
+ .div = { CGU_REG_CLOCKCONTROL, 0, 4, 22, -1, -1 },
+ },
+
+ [JZ4780_CLK_L2CACHE] = {
+ "l2cache", CGU_CLK_DIV,
+ .parents = { JZ4780_CLK_CPUMUX, -1 },
+ .div = { CGU_REG_CLOCKCONTROL, 4, 4, -1, -1, -1 },
+ },
+
+ [JZ4780_CLK_AHB0] = {
+ "ahb0", CGU_CLK_MUX | CGU_CLK_DIV,
+ .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
+ JZ4780_CLK_EPLL },
+ .mux = { CGU_REG_CLOCKCONTROL, 26, 2 },
+ .div = { CGU_REG_CLOCKCONTROL, 8, 4, 21, -1, -1 },
+ },
+
+ [JZ4780_CLK_AHB2PMUX] = {
+ "ahb2_apb_mux", CGU_CLK_MUX,
+ .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
+ JZ4780_CLK_RTCLK },
+ .mux = { CGU_REG_CLOCKCONTROL, 24, 2 },
+ },
+
+ [JZ4780_CLK_AHB2] = {
+ "ahb2", CGU_CLK_DIV,
+ .parents = { JZ4780_CLK_AHB2PMUX, -1 },
+ .div = { CGU_REG_CLOCKCONTROL, 12, 4, 20, -1, -1 },
+ },
+
+ [JZ4780_CLK_PCLK] = {
+ "pclk", CGU_CLK_DIV,
+ .parents = { JZ4780_CLK_AHB2PMUX, -1 },
+ .div = { CGU_REG_CLOCKCONTROL, 16, 4, 20, -1, -1 },
+ },
+
+ [JZ4780_CLK_DDR] = {
+ "ddr", CGU_CLK_MUX | CGU_CLK_DIV,
+ .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, -1 },
+ .mux = { CGU_REG_DDRCDR, 30, 2 },
+ .div = { CGU_REG_DDRCDR, 0, 4, 29, 28, 27 },
+ },
+
+ [JZ4780_CLK_VPU] = {
+ "vpu", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
+ JZ4780_CLK_EPLL, -1 },
+ .mux = { CGU_REG_VPUCDR, 30, 2 },
+ .div = { CGU_REG_VPUCDR, 0, 4, 29, 28, 27 },
+ .gate_bit = 32 + 2,
+ },
+
+ [JZ4780_CLK_I2SPLL] = {
+ "i2s_pll", CGU_CLK_MUX | CGU_CLK_DIV,
+ .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_EPLL, -1 },
+ .mux = { CGU_REG_I2SCDR, 30, 1 },
+ .div = { CGU_REG_I2SCDR, 0, 8, 29, 28, 27 },
+ },
+
+ [JZ4780_CLK_I2S] = {
+ "i2s", CGU_CLK_MUX,
+ .parents = { JZ4780_CLK_EXCLK, JZ4780_CLK_I2SPLL, -1 },
+ .mux = { CGU_REG_I2SCDR, 31, 1 },
+ },
+
+ [JZ4780_CLK_LCD0PIXCLK] = {
+ "lcd0pixclk", CGU_CLK_MUX | CGU_CLK_DIV,
+ .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
+ JZ4780_CLK_VPLL, -1 },
+ .mux = { CGU_REG_LP0CDR, 30, 2 },
+ .div = { CGU_REG_LP0CDR, 0, 8, 28, 27, 26 },
+ },
+
+ [JZ4780_CLK_LCD1PIXCLK] = {
+ "lcd1pixclk", CGU_CLK_MUX | CGU_CLK_DIV,
+ .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
+ JZ4780_CLK_VPLL, -1 },
+ .mux = { CGU_REG_LP1CDR, 30, 2 },
+ .div = { CGU_REG_LP1CDR, 0, 8, 28, 27, 26 },
+ },
+
+ [JZ4780_CLK_MSCMUX] = {
+ "msc_mux", CGU_CLK_MUX,
+ .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, -1 },
+ .mux = { CGU_REG_MSC0CDR, 30, 2 },
+ },
+
+ [JZ4780_CLK_MSC0] = {
+ "msc0", CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_MSCMUX, -1 },
+ .div = { CGU_REG_MSC0CDR, 0, 8, 29, 28, 27 },
+ .gate_bit = 3,
+ },
+
+ [JZ4780_CLK_MSC1] = {
+ "msc1", CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_MSCMUX, -1 },
+ .div = { CGU_REG_MSC1CDR, 0, 8, 29, 28, 27 },
+ .gate_bit = 11,
+ },
+
+ [JZ4780_CLK_MSC2] = {
+ "msc2", CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_MSCMUX, -1 },
+ .div = { CGU_REG_MSC2CDR, 0, 8, 29, 28, 27 },
+ .gate_bit = 12,
+ },
+
+ [JZ4780_CLK_UHC] = {
+ "uhc", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
+ JZ4780_CLK_EPLL, JZ4780_CLK_OTGPHY },
+ .mux = { CGU_REG_UHCCDR, 30, 2 },
+ .div = { CGU_REG_UHCCDR, 0, 8, 29, 28, 27 },
+ .gate_bit = 24,
+ },
+
+ [JZ4780_CLK_SSIPLL] = {
+ "ssi_pll", CGU_CLK_MUX | CGU_CLK_DIV,
+ .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, -1 },
+ .mux = { CGU_REG_SSICDR, 30, 1 },
+ .div = { CGU_REG_SSICDR, 0, 8, 29, 28, 27 },
+ },
+
+ [JZ4780_CLK_SSI] = {
+ "ssi", CGU_CLK_MUX,
+ .parents = { JZ4780_CLK_EXCLK, JZ4780_CLK_SSIPLL, -1 },
+ .mux = { CGU_REG_SSICDR, 31, 1 },
+ },
+
+ [JZ4780_CLK_CIMMCLK] = {
+ "cim_mclk", CGU_CLK_MUX | CGU_CLK_DIV,
+ .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, -1 },
+ .mux = { CGU_REG_CIMCDR, 31, 1 },
+ .div = { CGU_REG_CIMCDR, 0, 8, 30, 29, 28 },
+ },
+
+ [JZ4780_CLK_PCMPLL] = {
+ "pcm_pll", CGU_CLK_MUX | CGU_CLK_DIV,
+ .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
+ JZ4780_CLK_EPLL, JZ4780_CLK_VPLL },
+ .mux = { CGU_REG_PCMCDR, 29, 2 },
+ .div = { CGU_REG_PCMCDR, 0, 8, 28, 27, 26 },
+ },
+
+ [JZ4780_CLK_PCM] = {
+ "pcm", CGU_CLK_MUX | CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, JZ4780_CLK_PCMPLL, -1 },
+ .mux = { CGU_REG_PCMCDR, 31, 1 },
+ .gate_bit = 32 + 3,
+ },
+
+ [JZ4780_CLK_GPU] = {
+ "gpu", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
+ JZ4780_CLK_EPLL },
+ .mux = { CGU_REG_GPUCDR, 30, 2 },
+ .div = { CGU_REG_GPUCDR, 0, 4, 29, 28, 27 },
+ .gate_bit = 32 + 4,
+ },
+
+ [JZ4780_CLK_HDMI] = {
+ "hdmi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
+ JZ4780_CLK_VPLL, -1 },
+ .mux = { CGU_REG_HDMICDR, 30, 2 },
+ .div = { CGU_REG_HDMICDR, 0, 8, 29, 28, 26 },
+ .gate_bit = 32 + 9,
+ },
+
+ [JZ4780_CLK_BCH] = {
+ "bch", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
+ JZ4780_CLK_EPLL },
+ .mux = { CGU_REG_BCHCDR, 30, 2 },
+ .div = { CGU_REG_BCHCDR, 0, 4, 29, 28, 27 },
+ .gate_bit = 1,
+ },
+
+ /* Gate-only clocks */
+
+ [JZ4780_CLK_NEMC] = {
+ "nemc", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_AHB2, -1 },
+ .gate_bit = 0,
+ },
+
+ [JZ4780_CLK_OTG0] = {
+ "otg0", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .gate_bit = 2,
+ },
+
+ [JZ4780_CLK_SSI0] = {
+ "ssi0", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_SSI, -1 },
+ .gate_bit = 4,
+ },
+
+ [JZ4780_CLK_SMB0] = {
+ "smb0", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_PCLK, -1 },
+ .gate_bit = 5,
+ },
+
+ [JZ4780_CLK_SMB1] = {
+ "smb1", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_PCLK, -1 },
+ .gate_bit = 6,
+ },
+
+ [JZ4780_CLK_SCC] = {
+ "scc", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .gate_bit = 7,
+ },
+
+ [JZ4780_CLK_AIC] = {
+ "aic", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .gate_bit = 8,
+ },
+
+ [JZ4780_CLK_TSSI0] = {
+ "tssi0", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .gate_bit = 9,
+ },
+
+ [JZ4780_CLK_OWI] = {
+ "owi", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .gate_bit = 10,
+ },
+
+ [JZ4780_CLK_KBC] = {
+ "kbc", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .gate_bit = 13,
+ },
+
+ [JZ4780_CLK_SADC] = {
+ "sadc", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .gate_bit = 14,
+ },
+
+ [JZ4780_CLK_UART0] = {
+ "uart0", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .gate_bit = 15,
+ },
+
+ [JZ4780_CLK_UART1] = {
+ "uart1", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .gate_bit = 16,
+ },
+
+ [JZ4780_CLK_UART2] = {
+ "uart2", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .gate_bit = 17,
+ },
+
+ [JZ4780_CLK_UART3] = {
+ "uart3", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .gate_bit = 18,
+ },
+
+ [JZ4780_CLK_SSI1] = {
+ "ssi1", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_SSI, -1 },
+ .gate_bit = 19,
+ },
+
+ [JZ4780_CLK_SSI2] = {
+ "ssi2", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_SSI, -1 },
+ .gate_bit = 20,
+ },
+
+ [JZ4780_CLK_PDMA] = {
+ "pdma", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .gate_bit = 21,
+ },
+
+ [JZ4780_CLK_GPS] = {
+ "gps", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .gate_bit = 22,
+ },
+
+ [JZ4780_CLK_MAC] = {
+ "mac", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .gate_bit = 23,
+ },
+
+ [JZ4780_CLK_SMB2] = {
+ "smb2", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_PCLK, -1 },
+ .gate_bit = 25,
+ },
+
+ [JZ4780_CLK_CIM] = {
+ "cim", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .gate_bit = 26,
+ },
+
+ [JZ4780_CLK_LCD] = {
+ "lcd", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .gate_bit = 28,
+ },
+
+ [JZ4780_CLK_TVE] = {
+ "tve", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_LCD, -1 },
+ .gate_bit = 27,
+ },
+
+ [JZ4780_CLK_IPU] = {
+ "ipu", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .gate_bit = 29,
+ },
+
+ [JZ4780_CLK_DDR0] = {
+ "ddr0", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_DDR, -1 },
+ .gate_bit = 30,
+ },
+
+ [JZ4780_CLK_DDR1] = {
+ "ddr1", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_DDR, -1 },
+ .gate_bit = 31,
+ },
+
+ [JZ4780_CLK_SMB3] = {
+ "smb3", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_PCLK, -1 },
+ .gate_bit = 32 + 0,
+ },
+
+ [JZ4780_CLK_TSSI1] = {
+ "tssi1", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .gate_bit = 32 + 1,
+ },
+
+ [JZ4780_CLK_COMPRESS] = {
+ "compress", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .gate_bit = 32 + 5,
+ },
+
+ [JZ4780_CLK_AIC1] = {
+ "aic1", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .gate_bit = 32 + 6,
+ },
+
+ [JZ4780_CLK_GPVLC] = {
+ "gpvlc", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .gate_bit = 32 + 7,
+ },
+
+ [JZ4780_CLK_OTG1] = {
+ "otg1", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .gate_bit = 32 + 8,
+ },
+
+ [JZ4780_CLK_UART4] = {
+ "uart4", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .gate_bit = 32 + 10,
+ },
+
+ [JZ4780_CLK_AHBMON] = {
+ "ahb_mon", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .gate_bit = 32 + 11,
+ },
+
+ [JZ4780_CLK_SMB4] = {
+ "smb4", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_PCLK, -1 },
+ .gate_bit = 32 + 12,
+ },
+
+ [JZ4780_CLK_DES] = {
+ "des", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .gate_bit = 32 + 13,
+ },
+
+ [JZ4780_CLK_X2D] = {
+ "x2d", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1 },
+ .gate_bit = 32 + 14,
+ },
+
+ [JZ4780_CLK_CORE1] = {
+ "core1", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_CPU, -1 },
+ .gate_bit = 32 + 15,
+ },
+
+};
+
+static void __init jz4780_cgu_init(struct device_node *np)
+{
+ int retval;
+
+ cgu = jz47xx_cgu_new(jz4780_cgu_clocks, ARRAY_SIZE(jz4780_cgu_clocks),
+ np);
+ if (!cgu)
+ pr_err("%s: failed to initialise CGU\n", __func__);
+
+ retval = jz47xx_cgu_register_clocks(cgu);
+ if (retval)
+ pr_err("%s: failed to register CGU Clocks\n", __func__);
+
+ clk_set_parent(cgu->clocks.clks[JZ4780_CLK_UHC],
+ cgu->clocks.clks[JZ4780_CLK_MPLL]);
+}
+CLK_OF_DECLARE(jz4780_cgu, "ingenic,jz4780-cgu", jz4780_cgu_init);
--
1.9.1
From: Paul Burton <[email protected]>
Allow the jz4780 interrupt controller to be probed from devicetree,
supporting the 64 interrupts it provides.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
---
arch/mips/jz4740/irq.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/arch/mips/jz4740/irq.c b/arch/mips/jz4740/irq.c
index 3e53a32..de1c03e 100644
--- a/arch/mips/jz4740/irq.c
+++ b/arch/mips/jz4740/irq.c
@@ -137,6 +137,13 @@ static int __init jz4740_intc_of_init(struct device_node *node,
}
IRQCHIP_DECLARE(jz4740_intc, "ingenic,jz4740-intc", jz4740_intc_of_init);
+static int __init jz4780_intc_of_init(struct device_node *node,
+ struct device_node *parent)
+{
+ return jz47xx_intc_of_init(node, 2);
+}
+IRQCHIP_DECLARE(jz4780_intc, "ingenic,jz4780-intc", jz4780_intc_of_init);
+
#ifdef CONFIG_DEBUG_FS
static inline void intc_seq_reg(struct seq_file *s, const char *name,
--
1.9.1
From: Paul Burton <[email protected]>
With the jz4780, Ingenic switched to use a different vendor ID in the
coprocessor 0 PRID register (whilst keeping the product ID & revision
the same as the jz4740 & jz4770...). Add a definition for the new
vendor ID & handle it in the same way as the older one.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
---
arch/mips/include/asm/cpu.h | 1 +
arch/mips/kernel/cpu-probe.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h
index 33866fc..ab00d3b 100644
--- a/arch/mips/include/asm/cpu.h
+++ b/arch/mips/include/asm/cpu.h
@@ -43,6 +43,7 @@
#define PRID_COMP_NETLOGIC 0x0c0000
#define PRID_COMP_CAVIUM 0x0d0000
#define PRID_COMP_INGENIC 0xd00000
+#define PRID_COMP_INGENIC_4780 0xe10000
/*
* Assigned Processor ID (implementation) values for bits 15:8 of the PRId
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 5342674..ca98c4a 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -1313,6 +1313,7 @@ void cpu_probe(void)
cpu_probe_cavium(c, cpu);
break;
case PRID_COMP_INGENIC:
+ case PRID_COMP_INGENIC_4780:
cpu_probe_ingenic(c, cpu);
break;
case PRID_COMP_NETLOGIC:
--
1.9.1
From: Paul Burton <[email protected]>
Support the Ingenic jz4780 SoC using the code under arch/mips/jz4740 now
that it has been generalised sufficiently. This is left unselectable in
Kconfig until a jz4780 based board is added in a later commit.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
---
arch/mips/Kconfig | 16 +++++
arch/mips/boot/dts/jz4780.dtsi | 101 +++++++++++++++++++++++++++++
arch/mips/include/asm/mach-jz4740/irq.h | 5 ++
arch/mips/include/asm/mach-jz4740/serial.h | 8 ++-
arch/mips/jz4740/Makefile | 4 +-
arch/mips/jz4740/Platform | 4 ++
arch/mips/jz4740/time.c | 7 +-
7 files changed, 142 insertions(+), 3 deletions(-)
create mode 100644 arch/mips/boot/dts/jz4780.dtsi
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 622d0aa..296bafb 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -291,6 +291,22 @@ config MACH_JZ4740
select USE_OF
select LIBFDT
+config MACH_JZ4780
+ bool
+ select SYS_HAS_CPU_MIPS32_R2
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+ select SYS_SUPPORTS_ZBOOT_UART16550
+ select DMA_NONCOHERENT
+ select IRQ_CPU
+ select ARCH_REQUIRE_GPIOLIB
+ select COMMON_CLK
+ select GENERIC_IRQ_CHIP
+ select BUILTIN_DTB
+ select USE_OF
+ select LIBFDT
+ select MIPS_CPU_SCACHE
+
config LANTIQ
bool "Lantiq based platforms"
select DMA_NONCOHERENT
diff --git a/arch/mips/boot/dts/jz4780.dtsi b/arch/mips/boot/dts/jz4780.dtsi
new file mode 100644
index 0000000..d9b696f
--- /dev/null
+++ b/arch/mips/boot/dts/jz4780.dtsi
@@ -0,0 +1,101 @@
+#include <dt-bindings/clock/jz4780-cgu.h>
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "ingenic,jz4780";
+
+ cpuintc: cpuintc@0 {
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ compatible = "mti,cpu-interrupt-controller";
+ };
+
+ intc: intc@10001000 {
+ compatible = "ingenic,jz4780-intc";
+ reg = <0x10001000 0x50>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpuintc>;
+ interrupts = <2>;
+ };
+
+ ext: ext {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ };
+
+ rtc: rtc {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ };
+
+ cgu: jz4780-cgu@10000000 {
+ compatible = "ingenic,jz4780-cgu";
+ reg = <0x10000000 0x100>;
+
+ clocks = <&ext>, <&rtc>;
+ clock-names = "ext", "rtc";
+
+ #clock-cells = <1>;
+ };
+
+ uart0: serial@10030000 {
+ compatible = "ingenic,jz4780-uart";
+ reg = <0x10030000 0x100>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <51>;
+
+ clocks = <&ext>, <&cgu JZ4780_CLK_UART0>;
+ clock-names = "baud", "module";
+ };
+
+ uart1: serial@10031000 {
+ compatible = "ingenic,jz4780-uart";
+ reg = <0x10031000 0x100>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <50>;
+
+ clocks = <&ext>, <&cgu JZ4780_CLK_UART1>;
+ clock-names = "baud", "module";
+ };
+
+ uart2: serial@10032000 {
+ compatible = "ingenic,jz4780-uart";
+ reg = <0x10032000 0x100>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <49>;
+
+ clocks = <&ext>, <&cgu JZ4780_CLK_UART2>;
+ clock-names = "baud", "module";
+ };
+
+ uart3: serial@10033000 {
+ compatible = "ingenic,jz4780-uart";
+ reg = <0x10033000 0x100>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <48>;
+
+ clocks = <&ext>, <&cgu JZ4780_CLK_UART3>;
+ clock-names = "baud", "module";
+ };
+
+ uart4: serial@10034000 {
+ compatible = "ingenic,jz4780-uart";
+ reg = <0x10034000 0x100>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <34>;
+
+ clocks = <&ext>, <&cgu JZ4780_CLK_UART4>;
+ clock-names = "baud", "module";
+ };
+};
diff --git a/arch/mips/include/asm/mach-jz4740/irq.h b/arch/mips/include/asm/mach-jz4740/irq.h
index b218f76..7e4ec21 100644
--- a/arch/mips/include/asm/mach-jz4740/irq.h
+++ b/arch/mips/include/asm/mach-jz4740/irq.h
@@ -22,6 +22,9 @@
#ifdef CONFIG_MACH_JZ4740
# define NR_INTC_IRQS 32
#endif
+#ifdef CONFIG_MACH_JZ4780
+# define NR_INTC_IRQS 64
+#endif
/* 1st-level interrupts */
#define JZ4740_IRQ(x) (JZ4740_IRQ_BASE + (x))
@@ -48,6 +51,8 @@
#define JZ4740_IRQ_IPU JZ4740_IRQ(29)
#define JZ4740_IRQ_LCD JZ4740_IRQ(30)
+#define JZ4780_IRQ_TCU2 JZ4740_IRQ(25)
+
/* 2nd-level interrupts */
#define JZ4740_IRQ_DMA(x) (JZ4740_IRQ(NR_INTC_IRQS) + (x))
diff --git a/arch/mips/include/asm/mach-jz4740/serial.h b/arch/mips/include/asm/mach-jz4740/serial.h
index 9f93563..5001d34 100644
--- a/arch/mips/include/asm/mach-jz4740/serial.h
+++ b/arch/mips/include/asm/mach-jz4740/serial.h
@@ -16,6 +16,12 @@
#ifndef __JZ4740_SERIAL_H__
#define __JZ4740_SERIAL_H__
-#define BASE_BAUD (12000000 / 16)
+#ifdef CONFIG_MACH_JZ4740
+# define BASE_BAUD (12000000 / 16)
+#endif
+
+#ifdef CONFIG_MACH_JZ4780
+# define BASE_BAUD (48000000 / 16)
+#endif
#endif /* __JZ4740_SERIAL_H__ */
diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile
index ae72346..03e9f0a 100644
--- a/arch/mips/jz4740/Makefile
+++ b/arch/mips/jz4740/Makefile
@@ -5,7 +5,9 @@
# Object file lists.
obj-y += prom.o irq.o time.o reset.o setup.o \
- gpio.o platform.o timer.o
+ platform.o timer.o
+
+obj-$(CONFIG_MACH_JZ4740) += gpio.o
CFLAGS_setup.o = -I$(src)/../../../scripts/dtc/libfdt
diff --git a/arch/mips/jz4740/Platform b/arch/mips/jz4740/Platform
index ba91be9..ad1b443 100644
--- a/arch/mips/jz4740/Platform
+++ b/arch/mips/jz4740/Platform
@@ -1,3 +1,7 @@
platform-$(CONFIG_MACH_JZ4740) += jz4740/
cflags-$(CONFIG_MACH_JZ4740) += -I$(srctree)/arch/mips/include/asm/mach-jz4740
load-$(CONFIG_MACH_JZ4740) += 0xffffffff80010000
+
+platform-$(CONFIG_MACH_JZ4780) += jz4740/
+cflags-$(CONFIG_MACH_JZ4780) += -I$(srctree)/arch/mips/include/asm/mach-jz4740
+load-$(CONFIG_MACH_JZ4780) += 0xffffffff80010000
diff --git a/arch/mips/jz4740/time.c b/arch/mips/jz4740/time.c
index 121ec3a..e4e440d 100644
--- a/arch/mips/jz4740/time.c
+++ b/arch/mips/jz4740/time.c
@@ -96,7 +96,12 @@ static struct clock_event_device jz4740_clockevent = {
.set_next_event = jz4740_clockevent_set_next,
.set_mode = jz4740_clockevent_set_mode,
.rating = 200,
+#ifdef CONFIG_MACH_JZ4740
.irq = JZ4740_IRQ_TCU0,
+#endif
+#ifdef CONFIG_MACH_JZ4780
+ .irq = JZ4780_IRQ_TCU2,
+#endif
};
static struct irqaction timer_irqaction = {
@@ -136,7 +141,7 @@ void __init plat_time_init(void)
if (ret)
printk(KERN_ERR "Failed to register clocksource: %d\n", ret);
- setup_irq(JZ4740_IRQ_TCU0, &timer_irqaction);
+ setup_irq(jz4740_clockevent.irq, &timer_irqaction);
ctrl = JZ_TIMER_CTRL_PRESCALE_16 | JZ_TIMER_CTRL_SRC_EXT;
--
1.9.1
From: Paul Burton <[email protected]>
Add a device tree for the Ingenic jz4780 based MIPS Creator CI20 board.
Note that this is unselectable via Kconfig until the jz4780 SoC is made
selectable in a later commit.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
---
arch/mips/boot/dts/Makefile | 1 +
arch/mips/boot/dts/ci20.dts | 21 +++++++
arch/mips/configs/ci20_defconfig | 127 +++++++++++++++++++++++++++++++++++++++
arch/mips/jz4740/Kconfig | 10 +++
4 files changed, 159 insertions(+)
create mode 100644 arch/mips/boot/dts/ci20.dts
create mode 100644 arch/mips/configs/ci20_defconfig
diff --git a/arch/mips/boot/dts/Makefile b/arch/mips/boot/dts/Makefile
index a1127f3..28e6a21 100644
--- a/arch/mips/boot/dts/Makefile
+++ b/arch/mips/boot/dts/Makefile
@@ -10,6 +10,7 @@ dtb-$(CONFIG_DTB_RT305X_EVAL) += rt3052_eval.dtb
dtb-$(CONFIG_DTB_RT3883_EVAL) += rt3883_eval.dtb
dtb-$(CONFIG_DTB_MT7620A_EVAL) += mt7620a_eval.dtb
dtb-$(CONFIG_JZ4740_QI_LB60) += qi_lb60.dtb
+dtb-$(CONFIG_JZ4780_CI20) += ci20.dtb
dtb-$(CONFIG_MIPS_SEAD3) += sead3.dtb
obj-y += $(patsubst %.dtb, %.dtb.o, $(dtb-y))
diff --git a/arch/mips/boot/dts/ci20.dts b/arch/mips/boot/dts/ci20.dts
new file mode 100644
index 0000000..4f882ef
--- /dev/null
+++ b/arch/mips/boot/dts/ci20.dts
@@ -0,0 +1,21 @@
+/dts-v1/;
+
+#include "jz4780.dtsi"
+
+/ {
+ compatible = "img,ci20", "ingenic,jz4780";
+
+ chosen {
+ stdout-path = &uart4;
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x0 0x10000000
+ 0x30000000 0x30000000>;
+ };
+};
+
+&ext {
+ clock-frequency = <48000000>;
+};
diff --git a/arch/mips/configs/ci20_defconfig b/arch/mips/configs/ci20_defconfig
new file mode 100644
index 0000000..6562d28
--- /dev/null
+++ b/arch/mips/configs/ci20_defconfig
@@ -0,0 +1,127 @@
+CONFIG_MACH_JZ4780=y
+# CONFIG_COMPACTION is not set
+CONFIG_HZ_100=y
+CONFIG_PREEMPT=y
+# CONFIG_SECCOMP is not set
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_KERNEL_XZ=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_FHANDLE=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_MEMCG=y
+CONFIG_MEMCG_KMEM=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
+# CONFIG_RD_GZIP is not set
+CONFIG_RD_XZ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLAB=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_ALLOW_DEV_COREDUMP is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_LEGACY_PTY_COUNT=2
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=5
+CONFIG_SERIAL_8250_RUNTIME_UARTS=5
+CONFIG_SERIAL_8250_JZ47XX=y
+CONFIG_SERIAL_OF_PLATFORM=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_HID is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_IOMMU_SUPPORT is not set
+# CONFIG_DNOTIFY is not set
+CONFIG_PROC_KCORE=y
+# CONFIG_PROC_PAGE_MONITOR is not set
+CONFIG_TMPFS=y
+CONFIG_CONFIGFS_FS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_NLS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=y
+CONFIG_NLS_CODEPAGE_775=y
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_CODEPAGE_852=y
+CONFIG_NLS_CODEPAGE_855=y
+CONFIG_NLS_CODEPAGE_857=y
+CONFIG_NLS_CODEPAGE_860=y
+CONFIG_NLS_CODEPAGE_861=y
+CONFIG_NLS_CODEPAGE_862=y
+CONFIG_NLS_CODEPAGE_863=y
+CONFIG_NLS_CODEPAGE_864=y
+CONFIG_NLS_CODEPAGE_865=y
+CONFIG_NLS_CODEPAGE_866=y
+CONFIG_NLS_CODEPAGE_869=y
+CONFIG_NLS_CODEPAGE_936=y
+CONFIG_NLS_CODEPAGE_950=y
+CONFIG_NLS_CODEPAGE_932=y
+CONFIG_NLS_CODEPAGE_949=y
+CONFIG_NLS_CODEPAGE_874=y
+CONFIG_NLS_ISO8859_8=y
+CONFIG_NLS_CODEPAGE_1250=y
+CONFIG_NLS_CODEPAGE_1251=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=y
+CONFIG_NLS_ISO8859_3=y
+CONFIG_NLS_ISO8859_4=y
+CONFIG_NLS_ISO8859_5=y
+CONFIG_NLS_ISO8859_6=y
+CONFIG_NLS_ISO8859_7=y
+CONFIG_NLS_ISO8859_9=y
+CONFIG_NLS_ISO8859_13=y
+CONFIG_NLS_ISO8859_14=y
+CONFIG_NLS_ISO8859_15=y
+CONFIG_NLS_KOI8_R=y
+CONFIG_NLS_KOI8_U=y
+CONFIG_NLS_UTF8=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_PANIC_ON_OOPS=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_STACKTRACE=y
+# CONFIG_FTRACE is not set
+# CONFIG_EARLY_PRINTK is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS4,115200 clk_ignore_unused"
diff --git a/arch/mips/jz4740/Kconfig b/arch/mips/jz4740/Kconfig
index 4689030..72ac174 100644
--- a/arch/mips/jz4740/Kconfig
+++ b/arch/mips/jz4740/Kconfig
@@ -7,3 +7,13 @@ config JZ4740_QI_LB60
bool "Qi Hardware Ben NanoNote"
endchoice
+
+choice
+ prompt "Machine type"
+ depends on MACH_JZ4780
+ default JZ4780_CI20
+
+config JZ4780_CI20
+ bool "MIPS Creator CI20"
+
+endchoice
--
1.9.1
From: Paul Burton <[email protected]>
Now that a jz4780 based board (the MIPS Creator CI20) is present, allow
the jz4780 SoC to be selected as the machine type via Kconfig.
Signed-off-by: Paul Burton <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>
---
arch/mips/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 296bafb..6bd77f1 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -292,7 +292,7 @@ config MACH_JZ4740
select LIBFDT
config MACH_JZ4780
- bool
+ bool "Ingenic JZ4780 based machines"
select SYS_HAS_CPU_MIPS32_R2
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_LITTLE_ENDIAN
--
1.9.1
On Wednesday 04 February 2015 15:21:40 Zubair Lutfullah Kakakhel wrote:
> + domain = irq_domain_add_legacy(node, num_chips * 32, JZ4740_IRQ_BASE, 0,
> + &irq_domain_simple_ops, NULL);
> + if (!domain)
> + pr_warn("unable to register IRQ domain\n");
> +
> setup_irq(parent_irq, &jz4740_cascade_action);
Can you use the linear domain instead, or do you still require devices
that are hardcoded in the platform code rather than DT?
Arnd
On Wednesday 04 February 2015 15:21:44 Zubair Lutfullah Kakakhel wrote:
>
> +/ {
> + ext: clock@0 {
> + compatible = "fixed-clock";
> + #clock-cells = <0>;
> + clock-frequency = <12000000>;
> + };
> +
> + rtc: clock@1 {
> + compatible = "fixed-clock";
> + #clock-cells = <0>;
> + clock-frequency = <32768>;
> + };
> +
> + &cgu {
> + clocks = <&ext> <&rtc>;
> + clock-names: "ext", "rtc";
> + };
> +};
> diff --git a/include/dt-bindings/clock/jz4740-cgu.h b/include/dt-bindings/clock/jz4740-cgu.h
> new file mode 100644
> index 0000000..43153d3
> --- /dev/null
> +++ b/include/dt-bindings/clock/jz4740-cgu.h
> @@ -0,0 +1,37 @@
> +/*
> + * This header provides clock numbers for the ingenic,jz4740-cgu DT binding.
> + *
> + * They are roughly ordered as:
> + * - external clocks
> + * - PLLs
> + * - muxes/dividers in the order they appear in the jz4740 programmers manual
> + * - gates in order of their bit in the CLKGR* registers
> + */
> +
> +#ifndef __DT_BINDINGS_CLOCK_JZ4740_CGU_H__
> +#define __DT_BINDINGS_CLOCK_JZ4740_CGU_H__
> +
> +#define JZ4740_CLK_EXT 0
> +#define JZ4740_CLK_RTC 1
> +#define JZ4740_CLK_PLL 2
> +#define JZ4740_CLK_PLL_HALF 3
So there are fixed clocks for ext and rtc that are used as inputs
to the cgu, but also outputs with the same name. How do these relate?
Arnd
On Wednesday 04 February 2015 15:21:56 Zubair Lutfullah Kakakhel wrote:
> +#ifndef __JZ4740_SERIAL_H__
> +#define __JZ4740_SERIAL_H__
> +
> +#define BASE_BAUD (12000000 / 16)
> +
> +#endif /* __JZ4740_SERIAL_H__ */
>
This looks wrong: You should not need to hardcode this number when
you can get it from DT.
Arnd
On Wed, Feb 04, 2015 at 03:21:29PM +0000, Zubair Lutfullah Kakakhel wrote:
> Hi,
>
> This series introduces initial support for the Ingenic jz4780 SoC & the
> MIPS Creator CI20 board which is based upon it.
>
> The jz4780 shares aspects with jz4740. But jz4740 is platform only.
>
> So, the jz4740 & qi_lb60 (Ben NanoNote) are converted to use DT
> for some things in order to ease the process of sharing code.
>
> Series is based on 3.19-rc7.
>
> ACKS from various subsystems are welcome so that the series can
> go via mips if that is OK with everyone.
>
> Alternative suggestions welcome.
>
> Changes in V2
> - Removed FSF addresses.
> - Removed 2 patches for binding docs that
> were consolidated in the same binding for jz4740.
> - Bug fix in error handling in cgu
> - Rebase on 3.19-rc7
> - Updated defconfig with jz47xx serial and removed initramfs
> - Renames in binding from intc to interrupt-controller
> - Fix in jz47xx serial for build error on x86 in one config option
> - Removed interupt-parent bindings from required bindings
> - Fixed imgtec prefix to img
> - Added jz47xx config for qi_lb60_defconfig
>
> Regards,
> ZubairLK
Hi Zubair,
So first of all, thanks. I've been rather busy & haven't had time to
revise this patchset myself yet so I appreciate your effort.
Having said that, I do find it at best rather rude to take someone elses
patches, modify them & submit them without first:
- Asking the author if that's ok.
- Allowing the author to look over the changes you've made to their
patches.
- Making it clear in the commit message for each patch which
modifications you have made.
As is I now have to go and retroactively check each patch against mine
to find out what's different, since you didn't indicate that in each
patch, and then hope I agree with the changes that you made but which
the patches indicate I authored.
So please, if you should see fit to modify any of my patches in the
future, do the above things first.
Thanks,
Paul
> Paul Burton (34):
> dt: Add Ingenic Semiconductor vendor prefix
> MIPS: jz4740: require & include DT
> MIPS: irq_cpu: declare irqchip table entry
> MIPS: jz4740: probe CPU interrupt controller via DT
> MIPS: jz4740: use generic plat_irq_dispatch
> MIPS: jz4740: move arch_init_irq out of arch/mips/jz4740/irq.c
> dt: interrupt-controller: Add ingenic,jz4740-intc binding doc
> MIPS: jz4740: allow interrupt controller probe via DT
> MIPS: jz4740: probe interrupt controller via DT
> MIPS: jz4740: remove non-DT interrupt controller init
> MIPS: jz4740: register an irq_domain for the interrupt controller
> MIPS: jz4740: call jz4740_clock_init earlier
> MIPS: jz4740: replace use of jz4740_clock_bdata
> clk: jz47xx-cgu: add driver for Ingenic jz47xx series CGU clocks
> dt: clk: Add ingenic,jz4740-cgu binding documentation
> MIPS: clk: migrate jz4740 to common clock framework
> MIPS: clk: move jz4740_clock_set_wait_mode to jz4740-cgu
> MIPS: clk: move jz4740 UDC auto suspend functions to jz4740-cgu
> MIPS: clk: move jz4740 clock suspend, resume functions to jz4740-cgu
> MIPS: jz4740: remove clock.h
> MIPS: jz4740: only detect RAM size if not specified in DT
> MIPS: jz4740: support >32 interrupts
> MIPS: jz4740: define IRQ numbers based on number of intc IRQs
> dt: serial: Add ingenic,jz4740-uart binding
> serial: 8250_jz47xx: support for Ingenic jz47xx UARTs
> MIPS: allow mach-provided serial.h
> MIPS: jz4740: use jz47xx-uart & DT for UART output
> dt: clk: Add ingenic,jz4780-cgu binding documentation
> clk: add Ingenic jz4780 CGU driver
> MIPS: jz4740: add jz4780 interrupt controller support
> MIPS: add jz4780 Ingenic vendor ID
> MIPS: initial Ingenic jz4780 support
> MIPS: initial MIPS Creator CI20 board support
> MIPS: allow jz4780 to be selected in Kconfig
>
> .../bindings/clock/ingenic,jz4740-cgu.txt | 52 ++
> .../bindings/clock/ingenic,jz4780-cgu.txt | 52 ++
> .../interrupt-controller/ingenic,jz4740-intc.txt | 26 +
> .../bindings/serial/ingenic,jz4740-uart.txt | 22 +
> .../devicetree/bindings/vendor-prefixes.txt | 1 +
> arch/mips/Kconfig | 22 +-
> arch/mips/boot/dts/Makefile | 2 +
> arch/mips/boot/dts/ci20.dts | 21 +
> arch/mips/boot/dts/jz4740.dtsi | 68 ++
> arch/mips/boot/dts/jz4780.dtsi | 101 +++
> arch/mips/boot/dts/qi_lb60.dts | 15 +
> arch/mips/configs/ci20_defconfig | 127 +++
> arch/mips/configs/qi_lb60_defconfig | 1 +
> arch/mips/include/asm/Kbuild | 1 -
> arch/mips/include/asm/cpu.h | 1 +
> arch/mips/include/asm/mach-generic/serial.h | 21 +
> arch/mips/include/asm/mach-jz4740/clock.h | 3 +
> arch/mips/include/asm/mach-jz4740/irq.h | 15 +-
> arch/mips/include/asm/mach-jz4740/platform.h | 2 -
> arch/mips/include/asm/mach-jz4740/serial.h | 27 +
> arch/mips/include/asm/serial.h | 21 +
> arch/mips/jz4740/Kconfig | 10 +
> arch/mips/jz4740/Makefile | 6 +-
> arch/mips/jz4740/Platform | 4 +
> arch/mips/jz4740/board-qi_lb60.c | 7 -
> arch/mips/jz4740/clock-debugfs.c | 108 ---
> arch/mips/jz4740/clock.c | 924 ---------------------
> arch/mips/jz4740/clock.h | 76 --
> arch/mips/jz4740/irq.c | 103 ++-
> arch/mips/jz4740/platform.c | 37 +-
> arch/mips/jz4740/pm.c | 2 -
> arch/mips/jz4740/prom.c | 13 -
> arch/mips/jz4740/reset.c | 13 +-
> arch/mips/jz4740/serial.c | 33 -
> arch/mips/jz4740/serial.h | 23 -
> arch/mips/jz4740/setup.c | 33 +-
> arch/mips/jz4740/time.c | 19 +-
> arch/mips/kernel/cpu-probe.c | 1 +
> arch/mips/kernel/irq_cpu.c | 3 +
> drivers/clk/Makefile | 2 +
> drivers/clk/jz47xx/Makefile | 3 +
> drivers/clk/jz47xx/jz4740-cgu.c | 295 +++++++
> drivers/clk/jz47xx/jz4780-cgu.c | 742 +++++++++++++++++
> drivers/clk/jz47xx/jz47xx-cgu.c | 723 ++++++++++++++++
> drivers/clk/jz47xx/jz47xx-cgu.h | 205 +++++
> drivers/tty/serial/8250/8250_jz47xx.c | 225 +++++
> drivers/tty/serial/8250/Kconfig | 9 +
> drivers/tty/serial/8250/Makefile | 1 +
> include/dt-bindings/clock/jz4740-cgu.h | 37 +
> include/dt-bindings/clock/jz4780-cgu.h | 88 ++
> 50 files changed, 3070 insertions(+), 1276 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/clock/ingenic,jz4740-cgu.txt
> create mode 100644 Documentation/devicetree/bindings/clock/ingenic,jz4780-cgu.txt
> create mode 100644 Documentation/devicetree/bindings/interrupt-controller/ingenic,jz4740-intc.txt
> create mode 100644 Documentation/devicetree/bindings/serial/ingenic,jz4740-uart.txt
> create mode 100644 arch/mips/boot/dts/ci20.dts
> create mode 100644 arch/mips/boot/dts/jz4740.dtsi
> create mode 100644 arch/mips/boot/dts/jz4780.dtsi
> create mode 100644 arch/mips/boot/dts/qi_lb60.dts
> create mode 100644 arch/mips/configs/ci20_defconfig
> create mode 100644 arch/mips/include/asm/mach-generic/serial.h
> create mode 100644 arch/mips/include/asm/mach-jz4740/serial.h
> create mode 100644 arch/mips/include/asm/serial.h
> delete mode 100644 arch/mips/jz4740/clock-debugfs.c
> delete mode 100644 arch/mips/jz4740/clock.c
> delete mode 100644 arch/mips/jz4740/clock.h
> delete mode 100644 arch/mips/jz4740/serial.c
> delete mode 100644 arch/mips/jz4740/serial.h
> create mode 100644 drivers/clk/jz47xx/Makefile
> create mode 100644 drivers/clk/jz47xx/jz4740-cgu.c
> create mode 100644 drivers/clk/jz47xx/jz4780-cgu.c
> create mode 100644 drivers/clk/jz47xx/jz47xx-cgu.c
> create mode 100644 drivers/clk/jz47xx/jz47xx-cgu.h
> create mode 100644 drivers/tty/serial/8250/8250_jz47xx.c
> create mode 100644 include/dt-bindings/clock/jz4740-cgu.h
> create mode 100644 include/dt-bindings/clock/jz4780-cgu.h
>
> --
> 1.9.1
>
Hello.
On 02/04/2015 06:21 PM, Zubair Lutfullah Kakakhel wrote:
> From: Paul Burton <[email protected]>
> Use the generic irqchip_init function to probe irqchip drivers using DT,
> and add the appropriate node to the jz4740 devicetree in place of the
> call to mips_cpu_irq_init.
> Signed-off-by: Paul Burton <[email protected]>
> Cc: Lars-Peter Clausen <[email protected]>
> ---
> arch/mips/boot/dts/jz4740.dtsi | 7 +++++++
> arch/mips/jz4740/irq.c | 4 ++--
> 2 files changed, 9 insertions(+), 2 deletions(-)
> diff --git a/arch/mips/boot/dts/jz4740.dtsi b/arch/mips/boot/dts/jz4740.dtsi
> index c538691f..2d64765c 100644
> --- a/arch/mips/boot/dts/jz4740.dtsi
> +++ b/arch/mips/boot/dts/jz4740.dtsi
> @@ -2,4 +2,11 @@
> #address-cells = <1>;
> #size-cells = <1>;
> compatible = "ingenic,jz4740";
> +
> + cpuintc: cpuintc@0 {
Please name it "interrupt-controller". And why there's <unit-address> if
there's no "reg" prop?
> + #address-cells = <0>;
> + #interrupt-cells = <1>;
> + interrupt-controller;
> + compatible = "mti,cpu-interrupt-controller";
> + };
> };
[...]
WBR, Sergei
Hello.
On 02/04/2015 06:21 PM, Zubair Lutfullah Kakakhel wrote:
> From: Paul Burton <[email protected]>
> Add binding documentation for the Ingenic jz4740 interrupt controller.
> Signed-off-by: Paul Burton <[email protected]>
> Cc: Lars-Peter Clausen <[email protected]>
> Cc: [email protected]
> ---
> .../interrupt-controller/ingenic,jz4740-intc.txt | 26 ++++++++++++++++++++++
> 1 file changed, 26 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/interrupt-controller/ingenic,jz4740-intc.txt
> diff --git a/Documentation/devicetree/bindings/interrupt-controller/ingenic,jz4740-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/ingenic,jz4740-intc.txt
> new file mode 100644
> index 0000000..5e7f4bb
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/interrupt-controller/ingenic,jz4740-intc.txt
> @@ -0,0 +1,26 @@
> +Ingenic jz4740 SoC Interrupt Controller
JZ4740?
> +
> +Required properties:
> +
> +- compatible : should be "ingenic,jz4740-intc" or "ingenic,jz4780-intc"
> +- reg : Specifies base physical address and size of the registers.
> +- interrupt-controller : Identifies the node as an interrupt controller
> +- #interrupt-cells : Specifies the number of cells needed to encode an
> + interrupt source. The value shall be 1.
> +- interrupts - Specifies the CPU interrupt the controller is connected to.
> +
> +Optional properties:
> +- interrupt-parent: phandle of the CPU interrupt controller.
> +
> +Example:
> +
> +intc: intc@10001000 {
Name it "interrupt-controller@10001000", please.
> + compatible = "ingenic,jz4740-intc";
> + reg = <0x10001000 0x14>;
> +
> + interrupt-controller;
> + #interrupt-cells = <1>;
> +
> + interrupt-parent = <&cpuintc>;
> + interrupts = <2>;
> +};
WBR, Sergei
On 02/04/2015 06:21 PM, Zubair Lutfullah Kakakhel wrote:
> From: Paul Burton <[email protected]>
> Add the appropriate DT node to probe the interrupt controller driver
> using the devicetree, and remove the call to jz4740_intc_init.
> Signed-off-by: Paul Burton <[email protected]>
> Cc: Lars-Peter Clausen <[email protected]>
> ---
> arch/mips/boot/dts/jz4740.dtsi | 11 +++++++++++
> arch/mips/jz4740/setup.c | 2 --
> 2 files changed, 11 insertions(+), 2 deletions(-)
> diff --git a/arch/mips/boot/dts/jz4740.dtsi b/arch/mips/boot/dts/jz4740.dtsi
> index 2d64765c..3841024 100644
> --- a/arch/mips/boot/dts/jz4740.dtsi
> +++ b/arch/mips/boot/dts/jz4740.dtsi
> @@ -9,4 +9,15 @@
> interrupt-controller;
> compatible = "mti,cpu-interrupt-controller";
> };
> +
> + intc: intc@10001000 {
Name it "interrupt-controller@10001000", please. I have faint memories of
already telling you to do this...
> + compatible = "ingenic,jz4740-intc";
> + reg = <0x10001000 0x14>;
> +
> + interrupt-controller;
> + #interrupt-cells = <1>;
> +
> + interrupt-parent = <&cpuintc>;
> + interrupts = <2>;
> + };
> };
[...]
WBR, Sergei
On Wed, 2015-02-04 at 15:22 +0000, Zubair Lutfullah Kakakhel wrote:
> From: Paul Burton <[email protected]>
>
> Add a device tree for the Ingenic jz4780 based MIPS Creator CI20 board.
> Note that this is unselectable via Kconfig until the jz4780 SoC is made
> selectable in a later commit.
>
> Signed-off-by: Paul Burton <[email protected]>
> Cc: Lars-Peter Clausen <[email protected]>
> ---
> arch/mips/boot/dts/Makefile | 1 +
> arch/mips/boot/dts/ci20.dts | 21 +++++++
> arch/mips/configs/ci20_defconfig | 127 +++++++++++++++++++++++++++++++++++++++
> arch/mips/jz4740/Kconfig | 10 +++
> 4 files changed, 159 insertions(+)
> create mode 100644 arch/mips/boot/dts/ci20.dts
> create mode 100644 arch/mips/configs/ci20_defconfig
>[...]
> diff --git a/arch/mips/jz4740/Kconfig b/arch/mips/jz4740/Kconfig
> index 4689030..72ac174 100644
> --- a/arch/mips/jz4740/Kconfig
> +++ b/arch/mips/jz4740/Kconfig
> @@ -7,3 +7,13 @@ config JZ4740_QI_LB60
> bool "Qi Hardware Ben NanoNote"
>
> endchoice
> +
> +choice
> + prompt "Machine type"
> + depends on MACH_JZ4780
> + default JZ4780_CI20
> +
> +config JZ4780_CI20
> + bool "MIPS Creator CI20"
> +
> +endchoice
This adds a choice with a single entry. What's the point?
Paul Bolle
On Wed, 2015-02-04 at 15:21 +0000, Zubair Lutfullah Kakakhel wrote:
> From: Paul Burton <[email protected]>
>
> Introduce a driver suitable for use with the UARTs present in
> Ingenic jz47xx series SoCs. These are described as being ns16550
> compatible but aren't quite - they require the setting of an extra bit
> in the FCR register to enable the UART module. The serial_out
> implementation is the same as that in arch/mips/jz4740/serial.c - which
> will shortly be removed.
>
> Signed-off-by: Paul Burton <[email protected]>
> Cc: Greg Kroah-Hartman <[email protected]>
> Cc: Lars-Peter Clausen <[email protected]>
> Cc: [email protected]
>
> ---
> V2 changes
> Removed FSF address
> Added select SERIAL_CORE_CONSOLE to fix a build error
> ---
> drivers/tty/serial/8250/8250_jz47xx.c | 225 ++++++++++++++++++++++++++++++++++
> drivers/tty/serial/8250/Kconfig | 9 ++
> drivers/tty/serial/8250/Makefile | 1 +
> 3 files changed, 235 insertions(+)
> create mode 100644 drivers/tty/serial/8250/8250_jz47xx.c
>
>[...]
> diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
> index 0fcbcd2..ebb298e 100644
> --- a/drivers/tty/serial/8250/Kconfig
> +++ b/drivers/tty/serial/8250/Kconfig
> @@ -322,3 +322,12 @@ config SERIAL_8250_MT6577
> help
> If you have a Mediatek based board and want to use the
> serial port, say Y to this option. If unsure, say N.
> +
> +config SERIAL_8250_JZ47XX
> + tristate "Support for Ingenic jz47xx series serial ports"
> + depends on SERIAL_8250
> + select SERIAL_EARLYCON
> + select SERIAL_CORE_CONSOLE
> + help
> + If you have a system using an Ingenic jz47xx series SoC and wish to
> + make use of its UARTs, say Y to this option. If unsure, say N.
Nit: should people never say M?
Paul Bolle