2017-06-07 20:04:48

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH 00/15] Ingenic JZ4770 and GCW Zero patchset

Hi,

This set of 15 commits brings basic support of the JZ4770 SoC from
Ingenic.

The support is currently minimal, but enough to boot to a initramfs
userspace from the serial console.

The last patch introduces support for one JZ4770 based device, the
open-source game console GCW Zero, successfully kickstarted in 2012.

Regards,
-Paul


2017-06-07 20:04:52

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH 02/15] clk: ingenic: support PLLs with no bypass bit

The second PLL of the JZ4770 does not have a bypass bit.
This commit makes it possible to support it with the current common CGU
code.

Signed-off-by: Paul Cercueil <[email protected]>
---
drivers/clk/ingenic/cgu.c | 3 ++-
drivers/clk/ingenic/cgu.h | 2 ++
2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
index eb9002ccf3fc..75b083ba294c 100644
--- a/drivers/clk/ingenic/cgu.c
+++ b/drivers/clk/ingenic/cgu.c
@@ -100,7 +100,8 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
n += pll_info->n_offset;
od_enc = ctl >> pll_info->od_shift;
od_enc &= GENMASK(pll_info->od_bits - 1, 0);
- bypass = !!(ctl & BIT(pll_info->bypass_bit));
+ bypass = !pll_info->no_bypass_bit &&
+ !!(ctl & BIT(pll_info->bypass_bit));
enable = !!(ctl & BIT(pll_info->enable_bit));

if (bypass)
diff --git a/drivers/clk/ingenic/cgu.h b/drivers/clk/ingenic/cgu.h
index 09700b2c555d..2e3d258c3ed2 100644
--- a/drivers/clk/ingenic/cgu.h
+++ b/drivers/clk/ingenic/cgu.h
@@ -48,6 +48,7 @@
* @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
+ * @no_bypass_bit: if set, the PLL has no bypass functionality
*/
struct ingenic_cgu_pll_info {
unsigned reg;
@@ -58,6 +59,7 @@ struct ingenic_cgu_pll_info {
u8 bypass_bit;
u8 enable_bit;
u8 stable_bit;
+ bool no_bypass_bit;
};

/**
--
2.11.0

2017-06-07 20:05:04

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH 12/15] MIPS: JZ4770: Work around config2 misreporting associativity

From: Maarten ter Huurne <[email protected]>

According to config2, the associativity would be 5-ways, but the
documentation states 4-ways, which also matches the documented
L2 cache size of 256 kB.

Signed-off-by: Maarten ter Huurne <[email protected]>
---
arch/mips/mm/sc-mips.c | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c
index c909c3342729..67a3b4d88580 100644
--- a/arch/mips/mm/sc-mips.c
+++ b/arch/mips/mm/sc-mips.c
@@ -15,6 +15,7 @@
#include <asm/mmu_context.h>
#include <asm/r4kcache.h>
#include <asm/mips-cm.h>
+#include <asm/bootinfo.h>

/*
* MIPS32/MIPS64 L2 cache handling
@@ -228,6 +229,14 @@ static inline int __init mips_sc_probe(void)
else
return 0;

+ /*
+ * According to config2 it would be 5-ways, but that is contradicted
+ * by all documentation.
+ */
+ if (current_cpu_type() == CPU_JZRISC &&
+ mips_machtype == MACH_INGENIC_JZ4770)
+ c->scache.ways = 4;
+
c->scache.waysize = c->scache.sets * c->scache.linesz;
c->scache.waybit = __ffs(c->scache.waysize);

--
2.11.0

2017-06-07 20:05:10

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH 14/15] devicetree/bindings: Add GCW vendor prefix

Games Consoles Worldwide, mostly known under the acronym GCW, is the
creator of the GCW Zero open-source video game system.

Signed-off-by: Paul Cercueil <[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 c03d20140366..abe0b72b05b6 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -114,6 +114,7 @@ focaltech FocalTech Systems Co.,Ltd
friendlyarm Guangzhou FriendlyARM Computer Tech Co., Ltd
fsl Freescale Semiconductor
fujitsu Fujitsu Ltd.
+gcw Games Consoles Worldwide
ge General Electric Company
geekbuying GeekBuying
gef GE Fanuc Intelligent Platforms Embedded Systems, Inc.
--
2.11.0

2017-06-07 20:05:09

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH 06/15] serial: 8250_ingenic: Parse earlycon options

In the devicetree, it is possible to specify the baudrate, parity,
bits, flow of the early console, by passing a configuration string like
this:

aliases {
serial0 = &uart0;
};

chosen {
stdout-path = "serial0:57600n8";
};

This, for instance, will configure the early console for a baudrate of
57600 bps, no parity, and 8 bits per baud.

This patches implements parsing of this configuration string in the
8250_ingenic driver, which previously just ignored it.

Signed-off-by: Paul Cercueil <[email protected]>
---
drivers/tty/serial/8250/8250_ingenic.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c
index b31b2ca552d1..59f3e632df49 100644
--- a/drivers/tty/serial/8250/8250_ingenic.c
+++ b/drivers/tty/serial/8250/8250_ingenic.c
@@ -99,14 +99,24 @@ static int __init ingenic_early_console_setup(struct earlycon_device *dev,
const char *opt)
{
struct uart_port *port = &dev->port;
- unsigned int baud, divisor;
+ unsigned int divisor;
+ int baud = 115200;

if (!dev->port.membase)
return -ENODEV;

+ if (opt) {
+ char options[256];
+ unsigned int parity, bits, flow; /* unused for now */
+
+ strlcpy(options, opt, sizeof(options));
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ }
+
ingenic_early_console_setup_clock(dev);

- baud = dev->baud ?: 115200;
+ if (dev->baud)
+ baud = dev->baud;
divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud);

early_out(port, UART_IER, 0);
--
2.11.0

2017-06-07 20:05:27

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH 08/15] MIPS: ingenic: Use common cmdline handling code

From: Paul Burton <[email protected]>

jz4740_init_cmdline appends all arguments from argv (in fw_arg1) to
arcs_cmdline, up to argc (in fw_arg0). The common code in
fw_init_cmdline will do the exact same thing when run on a system where
fw_arg0 isn't a pointer to kseg0 (it'll also set _fw_envp but we don't
use it). Remove the custom implementation & use the generic code.

Signed-off-by: Paul Burton <[email protected]>
---
arch/mips/jz4740/prom.c | 24 ++----------------------
1 file changed, 2 insertions(+), 22 deletions(-)

diff --git a/arch/mips/jz4740/prom.c b/arch/mips/jz4740/prom.c
index 47e857194ce6..a62dd8e6ecf9 100644
--- a/arch/mips/jz4740/prom.c
+++ b/arch/mips/jz4740/prom.c
@@ -20,33 +20,13 @@
#include <linux/serial_reg.h>

#include <asm/bootinfo.h>
+#include <asm/fw/fw.h>
#include <asm/mach-jz4740/base.h>

-static __init void jz4740_init_cmdline(int argc, char *argv[])
-{
- unsigned int count = COMMAND_LINE_SIZE - 1;
- int i;
- char *dst = &(arcs_cmdline[0]);
- char *src;
-
- for (i = 1; i < argc && count; ++i) {
- src = argv[i];
- while (*src && count) {
- *dst++ = *src++;
- --count;
- }
- *dst++ = ' ';
- }
- if (i > 1)
- --dst;
-
- *dst = 0;
-}
-
void __init prom_init(void)
{
- jz4740_init_cmdline((int)fw_arg0, (char **)fw_arg1);
mips_machtype = MACH_INGENIC_JZ4740;
+ fw_init_cmdline();
}

void __init prom_free_prom_memory(void)
--
2.11.0

2017-06-07 20:05:45

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH 15/15] MIPS: ingenic: Initial GCW Zero support

The GCW Zero (http://www.gcw-zero.com) is a retro-gaming focused
handheld game console, successfully kickstarted in ~2012, running Linux.

Signed-off-by: Paul Cercueil <[email protected]>
---
arch/mips/boot/dts/ingenic/Makefile | 1 +
arch/mips/boot/dts/ingenic/gcw0.dts | 60 +++++++++++++++++++++++++++++++++++++
arch/mips/configs/gcw0_defconfig | 28 +++++++++++++++++
arch/mips/jz4740/Kconfig | 4 +++
arch/mips/jz4740/boards.c | 1 +
5 files changed, 94 insertions(+)
create mode 100644 arch/mips/boot/dts/ingenic/gcw0.dts
create mode 100644 arch/mips/configs/gcw0_defconfig

diff --git a/arch/mips/boot/dts/ingenic/Makefile b/arch/mips/boot/dts/ingenic/Makefile
index f2b864f07850..f64ad1c27a28 100644
--- a/arch/mips/boot/dts/ingenic/Makefile
+++ b/arch/mips/boot/dts/ingenic/Makefile
@@ -1,4 +1,5 @@
dtb-$(CONFIG_JZ4740_QI_LB60) += qi_lb60.dtb
+dtb-$(CONFIG_JZ4770_GCW0) += gcw0.dtb
dtb-$(CONFIG_JZ4780_CI20) += ci20.dtb

obj-y += $(patsubst %.dtb, %.dtb.o, $(dtb-y))
diff --git a/arch/mips/boot/dts/ingenic/gcw0.dts b/arch/mips/boot/dts/ingenic/gcw0.dts
new file mode 100644
index 000000000000..9c9a0137ccdf
--- /dev/null
+++ b/arch/mips/boot/dts/ingenic/gcw0.dts
@@ -0,0 +1,60 @@
+/dts-v1/;
+
+#include "jz4770.dtsi"
+
+/ {
+ compatible = "gcw,zero", "ingenic,jz4770";
+
+ aliases {
+ serial0 = &uart0;
+ serial1 = &uart1;
+ serial2 = &uart2;
+ serial3 = &uart3;
+ };
+
+ chosen {
+ stdout-path = "serial2:57600n8";
+ };
+
+ board {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges = <>;
+
+ otg_phy: otg-phy {
+ compatible = "usb-nop-xceiv";
+ clocks = <&cgu JZ4770_CLK_OTG_PHY>;
+ clock-names = "main_clk";
+ };
+ };
+};
+
+&ext {
+ clock-frequency = <12000000>;
+};
+
+&uart2 {
+ status = "okay";
+};
+
+&cgu {
+ /* Put high-speed peripherals under PLL1, such that we can change the
+ * PLL0 frequency on demand without having to suspend peripherals.
+ * We use a rate of 432 MHz, which is the least common multiple of
+ * 27 MHz (required by TV encoder) and 48 MHz (required by USB host).
+ */
+ assigned-clocks =
+ <&cgu JZ4770_CLK_PLL1>,
+ <&cgu JZ4770_CLK_UHC>;
+ assigned-clock-parents =
+ <0>,
+ <&cgu JZ4770_CLK_PLL1>;
+ assigned-clock-rates =
+ <432000000>;
+};
+
+&uhc {
+ /* The WiFi module is connected to the UHC. */
+ status = "okay";
+};
diff --git a/arch/mips/configs/gcw0_defconfig b/arch/mips/configs/gcw0_defconfig
new file mode 100644
index 000000000000..471497033855
--- /dev/null
+++ b/arch/mips/configs/gcw0_defconfig
@@ -0,0 +1,28 @@
+CONFIG_MACH_INGENIC=y
+CONFIG_JZ4770_GCW0=y
+CONFIG_HIGHMEM=y
+# CONFIG_BOUNCE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_SECCOMP is not set
+CONFIG_CROSS_COMPILE="mipsel-gcw0-linux-uclibc-"
+CONFIG_NO_HZ_IDLE=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_EMBEDDED=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_NETDEVICES=y
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_INGENIC=y
+CONFIG_USB=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_TMPFS=y
diff --git a/arch/mips/jz4740/Kconfig b/arch/mips/jz4740/Kconfig
index 922850503271..db270653fe8c 100644
--- a/arch/mips/jz4740/Kconfig
+++ b/arch/mips/jz4740/Kconfig
@@ -7,6 +7,10 @@ config JZ4740_QI_LB60
bool "Qi Hardware Ben NanoNote"
select MACH_JZ4740

+config JZ4770_GCW0
+ bool "Game Consoles Worldwide GCW Zero"
+ select MACH_JZ4770
+
config JZ4780_CI20
bool "MIPS Creator CI20"
select MACH_JZ4780
diff --git a/arch/mips/jz4740/boards.c b/arch/mips/jz4740/boards.c
index a3cf64cf004a..98a4d8e68cf0 100644
--- a/arch/mips/jz4740/boards.c
+++ b/arch/mips/jz4740/boards.c
@@ -12,5 +12,6 @@
#include <asm/mips_machine.h>

MIPS_MACHINE(MACH_INGENIC_JZ4740, "qi,lb60", "Qi Hardware Ben Nanonote", NULL);
+MIPS_MACHINE(MACH_INGENIC_JZ4770, "gcw,zero", "GCW Zero", NULL);
MIPS_MACHINE(MACH_INGENIC_JZ4780, "img,ci20",
"Imagination Technologies CI20", NULL);
--
2.11.0

2017-06-07 20:06:16

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH 11/15] MIPS: ingenic: Initial JZ4770 support

Provide just enough bits (clocks, clocksource, uart) to allow a kernel
to boot on the JZ4770 SoC to a initramfs userspace.

Signed-off-by: Paul Cercueil <[email protected]>
---
arch/mips/boot/dts/ingenic/jz4770.dtsi | 210 +++++++++++++++++++++++++++++++++
arch/mips/jz4740/Kconfig | 6 +
arch/mips/jz4740/time.c | 2 +-
3 files changed, 217 insertions(+), 1 deletion(-)
create mode 100644 arch/mips/boot/dts/ingenic/jz4770.dtsi

diff --git a/arch/mips/boot/dts/ingenic/jz4770.dtsi b/arch/mips/boot/dts/ingenic/jz4770.dtsi
new file mode 100644
index 000000000000..d8d0a741ff5d
--- /dev/null
+++ b/arch/mips/boot/dts/ingenic/jz4770.dtsi
@@ -0,0 +1,210 @@
+#include <dt-bindings/clock/jz4770-cgu.h>
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "ingenic,jz4770";
+
+ cpuintc: interrupt-controller {
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ compatible = "mti,cpu-interrupt-controller";
+ };
+
+ intc: interrupt-controller@10001000 {
+ compatible = "ingenic,jz4770-intc";
+ reg = <0x10001000 0x40>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpuintc>;
+ interrupts = <2>;
+ };
+
+ ext: ext {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ };
+
+ osc32k: osc32k {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ };
+
+ cgu: jz4770-cgu@10000000 {
+ compatible = "ingenic,jz4770-cgu";
+ reg = <0x10000000 0x100>;
+
+ clocks = <&ext>, <&osc32k>;
+ clock-names = "ext", "osc32k";
+
+ #clock-cells = <1>;
+ };
+
+ pinctrl: pin-controller@10010000 {
+ compatible = "ingenic,jz4770-pinctrl";
+ reg = <0x10010000 0x600>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ gpa: gpio@0 {
+ compatible = "ingenic,jz4770-gpio";
+ reg = <0>;
+
+ gpio-controller;
+ gpio-ranges = <&pinctrl 0 0 32>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <17>;
+ };
+
+ gpb: gpio@1 {
+ compatible = "ingenic,jz4770-gpio";
+ reg = <1>;
+
+ gpio-controller;
+ gpio-ranges = <&pinctrl 0 32 32>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <16>;
+ };
+
+ gpc: gpio@2 {
+ compatible = "ingenic,jz4770-gpio";
+ reg = <2>;
+
+ gpio-controller;
+ gpio-ranges = <&pinctrl 0 64 32>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <15>;
+ };
+
+ gpd: gpio@3 {
+ compatible = "ingenic,jz4770-gpio";
+ reg = <3>;
+
+ gpio-controller;
+ gpio-ranges = <&pinctrl 0 96 32>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <14>;
+ };
+
+ gpe: gpio@4 {
+ compatible = "ingenic,jz4770-gpio";
+ reg = <4>;
+
+ gpio-controller;
+ gpio-ranges = <&pinctrl 0 128 32>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <13>;
+ };
+
+ gpf: gpio@5 {
+ compatible = "ingenic,jz4770-gpio";
+ reg = <5>;
+
+ gpio-controller;
+ gpio-ranges = <&pinctrl 0 160 32>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <12>;
+ };
+ };
+
+ uart0: serial@10030000 {
+ compatible = "ingenic,jz4770-uart";
+ reg = <0x10030000 0x100>;
+
+ clocks = <&ext>, <&cgu JZ4770_CLK_UART0>;
+ clock-names = "baud", "module";
+
+ interrupt-parent = <&intc>;
+ interrupts = <5>;
+
+ status = "disabled";
+ };
+
+ uart1: serial@10031000 {
+ compatible = "ingenic,jz4770-uart";
+ reg = <0x10031000 0x100>;
+
+ clocks = <&ext>, <&cgu JZ4770_CLK_UART1>;
+ clock-names = "baud", "module";
+
+ interrupt-parent = <&intc>;
+ interrupts = <4>;
+
+ status = "disabled";
+ };
+
+ uart2: serial@10032000 {
+ compatible = "ingenic,jz4770-uart";
+ reg = <0x10032000 0x100>;
+
+ clocks = <&ext>, <&cgu JZ4770_CLK_UART2>;
+ clock-names = "baud", "module";
+
+ interrupt-parent = <&intc>;
+ interrupts = <3>;
+
+ status = "disabled";
+ };
+
+ uart3: serial@10033000 {
+ compatible = "ingenic,jz4770-uart";
+ reg = <0x10033000 0x100>;
+
+ clocks = <&ext>, <&cgu JZ4770_CLK_UART3>;
+ clock-names = "baud", "module";
+
+ interrupt-parent = <&intc>;
+ interrupts = <2>;
+
+ status = "disabled";
+ };
+
+ uhc: uhc@13430000 {
+ compatible = "generic-ohci";
+ reg = <0x13430000 0x1000>;
+
+ clocks = <&cgu JZ4770_CLK_UHC>, <&cgu JZ4770_CLK_UHC_PHY>;
+ assigned-clocks = <&cgu JZ4770_CLK_UHC>;
+ assigned-clock-rates = <48000000>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <20>;
+
+ status = "disabled";
+ };
+};
diff --git a/arch/mips/jz4740/Kconfig b/arch/mips/jz4740/Kconfig
index 36f82017695d..922850503271 100644
--- a/arch/mips/jz4740/Kconfig
+++ b/arch/mips/jz4740/Kconfig
@@ -17,6 +17,12 @@ config MACH_JZ4740
bool
select SYS_HAS_CPU_MIPS32_R1

+config MACH_JZ4770
+ bool
+ select MIPS_CPU_SCACHE
+ select SYS_HAS_CPU_MIPS32_R2
+ select SYS_SUPPORTS_HIGHMEM
+
config MACH_JZ4780
bool
select MIPS_CPU_SCACHE
diff --git a/arch/mips/jz4740/time.c b/arch/mips/jz4740/time.c
index bb1ad5119da4..2ca9160f642a 100644
--- a/arch/mips/jz4740/time.c
+++ b/arch/mips/jz4740/time.c
@@ -113,7 +113,7 @@ static struct clock_event_device jz4740_clockevent = {
#ifdef CONFIG_MACH_JZ4740
.irq = JZ4740_IRQ_TCU0,
#endif
-#ifdef CONFIG_MACH_JZ4780
+#if defined(CONFIG_MACH_JZ4770) || defined(CONFIG_MACH_JZ4780)
.irq = JZ4780_IRQ_TCU2,
#endif
};
--
2.11.0

2017-06-07 20:06:34

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH 13/15] MIPS: JZ4770: Workaround for corrupted DMA transfers

From: Maarten ter Huurne <[email protected]>

We have seen MMC DMA transfers read corrupted data from SDRAM when
a burst interval ends at physical address 0x10000000. To avoid this
problem, we remove the final page of low memory from the memory map.

Signed-off-by: Maarten ter Huurne <[email protected]>
---
arch/mips/jz4740/setup.c | 24 ++++++++++++++++++++++++
arch/mips/kernel/setup.c | 8 ++++++++
2 files changed, 32 insertions(+)

diff --git a/arch/mips/jz4740/setup.c b/arch/mips/jz4740/setup.c
index afd84ee966e8..6948b133a15d 100644
--- a/arch/mips/jz4740/setup.c
+++ b/arch/mips/jz4740/setup.c
@@ -23,6 +23,7 @@

#include <asm/bootinfo.h>
#include <asm/mips_machine.h>
+#include <asm/page.h>
#include <asm/prom.h>

#include <asm/mach-jz4740/base.h>
@@ -102,6 +103,29 @@ void __init arch_init_irq(void)
irqchip_init();
}

+/*
+ * We have seen MMC DMA transfers read corrupted data from SDRAM when a burst
+ * interval ends at physical address 0x10000000. To avoid this problem, we
+ * remove the final page of low memory from the memory map.
+ */
+void __init jz4770_reserve_unsafe_for_dma(void)
+{
+ int i;
+
+ for (i = 0; i < boot_mem_map.nr_map; i++) {
+ struct boot_mem_map_entry *entry = boot_mem_map.map + i;
+
+ if (entry->type != BOOT_MEM_RAM)
+ continue;
+
+ if (entry->addr + entry->size != 0x10000000)
+ continue;
+
+ entry->size -= PAGE_SIZE;
+ break;
+ }
+}
+
static int __init jz4740_machine_setup(void)
{
mips_machine_setup();
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 89785600fde4..cccfd7ba89fe 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -838,6 +838,14 @@ static void __init arch_mem_init(char **cmdline_p)

parse_early_param();

+#ifdef CONFIG_MACH_JZ4770
+ if (current_cpu_type() == CPU_JZRISC &&
+ mips_machtype == MACH_INGENIC_JZ4770) {
+ extern void __init jz4770_reserve_unsafe_for_dma(void);
+ jz4770_reserve_unsafe_for_dma();
+ }
+#endif
+
if (usermem) {
pr_info("User-defined physical RAM map:\n");
print_memory_map();
--
2.11.0

2017-06-07 20:05:02

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH 09/15] MIPS: platform: add machtype IDs for more Ingenic SoCs

Add a machtype ID for the JZ4780 SoC, which was missing, and one for the
newly supported JZ4770 SoC.

Signed-off-by: Paul Cercueil <[email protected]>
---
arch/mips/include/asm/bootinfo.h | 2 ++
1 file changed, 2 insertions(+)

diff --git a/arch/mips/include/asm/bootinfo.h b/arch/mips/include/asm/bootinfo.h
index e26a093bb17a..a301a8f4bc66 100644
--- a/arch/mips/include/asm/bootinfo.h
+++ b/arch/mips/include/asm/bootinfo.h
@@ -79,6 +79,8 @@ enum loongson_machine_type {
*/
#define MACH_INGENIC_JZ4730 0 /* JZ4730 SOC */
#define MACH_INGENIC_JZ4740 1 /* JZ4740 SOC */
+#define MACH_INGENIC_JZ4770 2 /* JZ4770 SOC */
+#define MACH_INGENIC_JZ4780 3 /* JZ4780 SOC */

extern char *system_type;
const char *get_system_type(void);
--
2.11.0

2017-06-07 20:05:01

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH 03/15] clk: ingenic: Add code to enable/disable PLLs

This commit permits the PLLs to be dynamically enabled and disabled when
their children clocks are enabled and disabled.

Signed-off-by: Paul Cercueil <[email protected]>
---
drivers/clk/ingenic/cgu.c | 89 +++++++++++++++++++++++++++++++++++++++--------
1 file changed, 74 insertions(+), 15 deletions(-)

diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
index 75b083ba294c..08613b803b14 100644
--- a/drivers/clk/ingenic/cgu.c
+++ b/drivers/clk/ingenic/cgu.c
@@ -107,9 +107,6 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
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;
@@ -153,17 +150,25 @@ ingenic_pll_calc(const struct ingenic_cgu_clk_info *clk_info,
return div_u64((u64)parent_rate * m, n * od);
}

-static long
-ingenic_pll_round_rate(struct clk_hw *hw, unsigned long req_rate,
- unsigned long *prate)
+static inline const struct ingenic_cgu_clk_info *to_clk_info(
+ struct ingenic_clk *ingenic_clk)
{
- struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
struct ingenic_cgu *cgu = ingenic_clk->cgu;
const struct ingenic_cgu_clk_info *clk_info;

clk_info = &cgu->clock_info[ingenic_clk->idx];
BUG_ON(clk_info->type != CGU_CLK_PLL);

+ return clk_info;
+}
+
+static long
+ingenic_pll_round_rate(struct clk_hw *hw, unsigned long req_rate,
+ unsigned long *prate)
+{
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
+ const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
+
return ingenic_pll_calc(clk_info, req_rate, *prate, NULL, NULL, NULL);
}

@@ -171,19 +176,14 @@ static int
ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
unsigned long parent_rate)
{
- const unsigned timeout = 100;
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
struct ingenic_cgu *cgu = ingenic_clk->cgu;
- const struct ingenic_cgu_clk_info *clk_info;
- const struct ingenic_cgu_pll_info *pll_info;
+ const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
+ const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
unsigned long rate, flags;
- unsigned m, n, od, i;
+ unsigned int m, n, od;
u32 ctl;

- clk_info = &cgu->clock_info[ingenic_clk->idx];
- BUG_ON(clk_info->type != CGU_CLK_PLL);
- pll_info = &clk_info->pll;
-
rate = ingenic_pll_calc(clk_info, req_rate, parent_rate,
&m, &n, &od);
if (rate != req_rate)
@@ -202,6 +202,26 @@ ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
ctl &= ~(GENMASK(pll_info->od_bits - 1, 0) << pll_info->od_shift);
ctl |= pll_info->od_encoding[od - 1] << pll_info->od_shift;

+ writel(ctl, cgu->base + pll_info->reg);
+ spin_unlock_irqrestore(&cgu->lock, flags);
+
+ return 0;
+}
+
+static int ingenic_pll_enable(struct clk_hw *hw)
+{
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
+ struct ingenic_cgu *cgu = ingenic_clk->cgu;
+ const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
+ const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
+ const unsigned int timeout = 100;
+ unsigned long flags;
+ unsigned int i;
+ u32 ctl;
+
+ spin_lock_irqsave(&cgu->lock, flags);
+ ctl = readl(cgu->base + pll_info->reg);
+
ctl &= ~BIT(pll_info->bypass_bit);
ctl |= BIT(pll_info->enable_bit);

@@ -223,10 +243,48 @@ ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
return 0;
}

+static void ingenic_pll_disable(struct clk_hw *hw)
+{
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
+ struct ingenic_cgu *cgu = ingenic_clk->cgu;
+ const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
+ const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
+ unsigned long flags;
+ u32 ctl;
+
+ spin_lock_irqsave(&cgu->lock, flags);
+ ctl = readl(cgu->base + pll_info->reg);
+
+ ctl &= ~BIT(pll_info->enable_bit);
+
+ writel(ctl, cgu->base + pll_info->reg);
+ spin_unlock_irqrestore(&cgu->lock, flags);
+}
+
+static int ingenic_pll_is_enabled(struct clk_hw *hw)
+{
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
+ struct ingenic_cgu *cgu = ingenic_clk->cgu;
+ const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
+ const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
+ unsigned long flags;
+ u32 ctl;
+
+ spin_lock_irqsave(&cgu->lock, flags);
+ ctl = readl(cgu->base + pll_info->reg);
+ spin_unlock_irqrestore(&cgu->lock, flags);
+
+ return !!(ctl & BIT(pll_info->enable_bit));
+}
+
static const struct clk_ops ingenic_pll_ops = {
.recalc_rate = ingenic_pll_recalc_rate,
.round_rate = ingenic_pll_round_rate,
.set_rate = ingenic_pll_set_rate,
+
+ .enable = ingenic_pll_enable,
+ .disable = ingenic_pll_disable,
+ .is_enabled = ingenic_pll_is_enabled,
};

/*
@@ -601,6 +659,7 @@ static int ingenic_register_clock(struct ingenic_cgu *cgu, unsigned idx)
}
} else if (caps & CGU_CLK_PLL) {
clk_init.ops = &ingenic_pll_ops;
+ clk_init.flags |= CLK_SET_RATE_GATE;

caps &= ~CGU_CLK_PLL;

--
2.11.0

2017-06-07 20:07:31

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH 10/15] MIPS: ingenic: Add machine info for supported boards

This makes sure that 'mips_machtype' will be initialized to the SoC
version used on the board.

Signed-off-by: Paul Cercueil <[email protected]>
---
arch/mips/Kconfig | 1 +
arch/mips/jz4740/Makefile | 2 +-
arch/mips/jz4740/boards.c | 16 ++++++++++++++++
arch/mips/jz4740/setup.c | 34 +++++++++++++++++++++++++++++-----
4 files changed, 47 insertions(+), 6 deletions(-)
create mode 100644 arch/mips/jz4740/boards.c

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 2828ecde133d..f36ffb93efd9 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -370,6 +370,7 @@ config MACH_INGENIC
select BUILTIN_DTB
select USE_OF
select LIBFDT
+ select MIPS_MACHINE

config LANTIQ
bool "Lantiq based platforms"
diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile
index 39d70bde8cfe..87feb246fafe 100644
--- a/arch/mips/jz4740/Makefile
+++ b/arch/mips/jz4740/Makefile
@@ -5,7 +5,7 @@
# Object file lists.

obj-y += prom.o time.o reset.o setup.o \
- platform.o timer.o
+ platform.o timer.o boards.o

obj-$(CONFIG_MACH_JZ4740) += gpio.o

diff --git a/arch/mips/jz4740/boards.c b/arch/mips/jz4740/boards.c
new file mode 100644
index 000000000000..a3cf64cf004a
--- /dev/null
+++ b/arch/mips/jz4740/boards.c
@@ -0,0 +1,16 @@
+/*
+ * Ingenic boards support
+ *
+ * Copyright 2017, Paul Cercueil <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or later
+ * as published by the Free Software Foundation.
+ */
+
+#include <asm/bootinfo.h>
+#include <asm/mips_machine.h>
+
+MIPS_MACHINE(MACH_INGENIC_JZ4740, "qi,lb60", "Qi Hardware Ben Nanonote", NULL);
+MIPS_MACHINE(MACH_INGENIC_JZ4780, "img,ci20",
+ "Imagination Technologies CI20", NULL);
diff --git a/arch/mips/jz4740/setup.c b/arch/mips/jz4740/setup.c
index 6d0152321819..afd84ee966e8 100644
--- a/arch/mips/jz4740/setup.c
+++ b/arch/mips/jz4740/setup.c
@@ -22,6 +22,7 @@
#include <linux/of_fdt.h>

#include <asm/bootinfo.h>
+#include <asm/mips_machine.h>
#include <asm/prom.h>

#include <asm/mach-jz4740/base.h>
@@ -53,16 +54,34 @@ static void __init jz4740_detect_mem(void)
add_memory_region(0, size, BOOT_MEM_RAM);
}

+static unsigned long __init get_board_mach_type(const void *fdt)
+{
+ const struct mips_machine *mach;
+
+ for (mach = (struct mips_machine *)&__mips_machines_start;
+ mach < (struct mips_machine *)&__mips_machines_end;
+ mach++) {
+ if (!fdt_node_check_compatible(fdt, 0, mach->mach_id))
+ return mach->mach_type;
+ }
+
+ return MACH_INGENIC_JZ4740;
+}
+
void __init plat_mem_setup(void)
{
int offset;

+ if (!early_init_dt_scan(__dtb_start))
+ return;
+
jz4740_reset_init();
- __dt_setup_arch(__dtb_start);

offset = fdt_path_offset(__dtb_start, "/memory");
if (offset < 0)
jz4740_detect_mem();
+
+ mips_machtype = get_board_mach_type(__dtb_start);
}

void __init device_tree_init(void)
@@ -75,13 +94,18 @@ void __init device_tree_init(void)

const char *get_system_type(void)
{
- if (IS_ENABLED(CONFIG_MACH_JZ4780))
- return "JZ4780";
-
- return "JZ4740";
+ return mips_get_machine_name();
}

void __init arch_init_irq(void)
{
irqchip_init();
}
+
+static int __init jz4740_machine_setup(void)
+{
+ mips_machine_setup();
+
+ return 0;
+}
+arch_initcall(jz4740_machine_setup);
--
2.11.0

2017-06-07 20:04:59

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH 07/15] MIPS: Setup boot_command_line before plat_mem_setup

From: Paul Burton <[email protected]>

Platforms using DT will typically call __dt_setup_arch from
plat_mem_setup. This in turn calls early_init_dt_scan. When
CONFIG_CMDLINE is set, this leads to its value being copied into
boot_command_line by early_init_dt_scan_chosen. If this happens before
the code setting up boot_command_line in arch_mem_init runs, that code
will go on to append CONFIG_CMDLINE (via builtin_cmdline) to
boot_command_line again, duplicating it. For some command line
parameters (eg. earlycon) this can be a problem. Set up
boot_command_line before early_init_dt_scan_chosen gets called such that
it will not write CONFIG_CMDLINE in this scenario & the arguments aren't
duplicated.

Signed-off-by: Paul Burton <[email protected]>
---
arch/mips/kernel/setup.c | 39 ++++++++++++++++++++-------------------
1 file changed, 20 insertions(+), 19 deletions(-)

diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 01d1dbde5fbf..89785600fde4 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -785,25 +785,6 @@ static void __init arch_mem_init(char **cmdline_p)
struct memblock_region *reg;
extern void plat_mem_setup(void);

- /* call board setup routine */
- plat_mem_setup();
-
- /*
- * Make sure all kernel memory is in the maps. The "UP" and
- * "DOWN" are opposite for initdata since if it crosses over
- * into another memory section you don't want that to be
- * freed when the initdata is freed.
- */
- arch_mem_addpart(PFN_DOWN(__pa_symbol(&_text)) << PAGE_SHIFT,
- PFN_UP(__pa_symbol(&_edata)) << PAGE_SHIFT,
- BOOT_MEM_RAM);
- arch_mem_addpart(PFN_UP(__pa_symbol(&__init_begin)) << PAGE_SHIFT,
- PFN_DOWN(__pa_symbol(&__init_end)) << PAGE_SHIFT,
- BOOT_MEM_INIT_RAM);
-
- pr_info("Determined physical RAM map:\n");
- print_memory_map();
-
#if defined(CONFIG_CMDLINE_BOOL) && defined(CONFIG_CMDLINE_OVERRIDE)
strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
#else
@@ -831,6 +812,26 @@ static void __init arch_mem_init(char **cmdline_p)
}
#endif
#endif
+
+ /* call board setup routine */
+ plat_mem_setup();
+
+ /*
+ * Make sure all kernel memory is in the maps. The "UP" and
+ * "DOWN" are opposite for initdata since if it crosses over
+ * into another memory section you don't want that to be
+ * freed when the initdata is freed.
+ */
+ arch_mem_addpart(PFN_DOWN(__pa_symbol(&_text)) << PAGE_SHIFT,
+ PFN_UP(__pa_symbol(&_edata)) << PAGE_SHIFT,
+ BOOT_MEM_RAM);
+ arch_mem_addpart(PFN_UP(__pa_symbol(&__init_begin)) << PAGE_SHIFT,
+ PFN_DOWN(__pa_symbol(&__init_end)) << PAGE_SHIFT,
+ BOOT_MEM_INIT_RAM);
+
+ pr_info("Determined physical RAM map:\n");
+ print_memory_map();
+
strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);

*cmdline_p = command_line;
--
2.11.0

2017-06-07 20:08:02

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH 04/15] clk: Add Ingenic jz4770 CGU driver

Add support for the clocks provided by the CGU in the Ingenic JZ4770
SoC.

Signed-off-by: Paul Cercueil <[email protected]>
Signed-off-by: Maarten ter Huurne <[email protected]>
---
drivers/clk/ingenic/Makefile | 1 +
drivers/clk/ingenic/jz4770-cgu.c | 485 +++++++++++++++++++++++++++++++++
include/dt-bindings/clock/jz4770-cgu.h | 57 ++++
3 files changed, 543 insertions(+)
create mode 100644 drivers/clk/ingenic/jz4770-cgu.c
create mode 100644 include/dt-bindings/clock/jz4770-cgu.h

diff --git a/drivers/clk/ingenic/Makefile b/drivers/clk/ingenic/Makefile
index cd47b0664c2b..1456e4cdb562 100644
--- a/drivers/clk/ingenic/Makefile
+++ b/drivers/clk/ingenic/Makefile
@@ -1,3 +1,4 @@
obj-y += cgu.o
obj-$(CONFIG_MACH_JZ4740) += jz4740-cgu.o
+obj-$(CONFIG_MACH_JZ4770) += jz4770-cgu.o
obj-$(CONFIG_MACH_JZ4780) += jz4780-cgu.o
diff --git a/drivers/clk/ingenic/jz4770-cgu.c b/drivers/clk/ingenic/jz4770-cgu.c
new file mode 100644
index 000000000000..993db42df5fc
--- /dev/null
+++ b/drivers/clk/ingenic/jz4770-cgu.c
@@ -0,0 +1,485 @@
+/*
+ * JZ4770 SoC CGU driver
+ *
+ * Copyright 2017, Paul Cercueil <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or later
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/syscore_ops.h>
+#include <dt-bindings/clock/jz4770-cgu.h>
+#include "cgu.h"
+
+/*
+ * CPM registers offset address definition
+ */
+#define CGU_REG_CPCCR 0x00
+#define CGU_REG_LCR 0x04
+#define CGU_REG_CPPCR0 0x10
+#define CGU_REG_CLKGR0 0x20
+#define CGU_REG_OPCR 0x24
+#define CGU_REG_CLKGR1 0x28
+#define CGU_REG_CPPCR1 0x30
+#define CGU_REG_USBPCR1 0x48
+#define CGU_REG_USBCDR 0x50
+#define CGU_REG_I2SCDR 0x60
+#define CGU_REG_LPCDR 0x64
+#define CGU_REG_MSC0CDR 0x68
+#define CGU_REG_UHCCDR 0x6c
+#define CGU_REG_SSICDR 0x74
+#define CGU_REG_CIMCDR 0x7c
+#define CGU_REG_GPSCDR 0x80
+#define CGU_REG_PCMCDR 0x84
+#define CGU_REG_GPUCDR 0x88
+#define CGU_REG_MSC1CDR 0xA4
+#define CGU_REG_MSC2CDR 0xA8
+#define CGU_REG_BCHCDR 0xAC
+
+/* bits within the LCR register */
+#define LCR_LPM BIT(0) /* Low Power Mode */
+
+/* bits within the OPCR register */
+#define OPCR_SPENDH BIT(5) /* UHC PHY suspend */
+#define OPCR_SPENDN BIT(7) /* OTG PHY suspend */
+
+/* bits within the USBPCR1 register */
+#define USBPCR1_UHC_POWER BIT(5) /* UHC PHY power down */
+
+static struct ingenic_cgu *cgu;
+
+static int jz4770_uhc_phy_enable(struct clk_hw *hw)
+{
+ void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
+ void __iomem *reg_usbpcr1 = cgu->base + CGU_REG_USBPCR1;
+
+ writel(readl(reg_opcr) & ~OPCR_SPENDH, reg_opcr);
+ writel(readl(reg_usbpcr1) | USBPCR1_UHC_POWER, reg_usbpcr1);
+ return 0;
+}
+
+static void jz4770_uhc_phy_disable(struct clk_hw *hw)
+{
+ void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
+ void __iomem *reg_usbpcr1 = cgu->base + CGU_REG_USBPCR1;
+
+ writel(readl(reg_usbpcr1) & ~USBPCR1_UHC_POWER, reg_usbpcr1);
+ writel(readl(reg_opcr) | OPCR_SPENDH, reg_opcr);
+}
+
+static int jz4770_uhc_phy_is_enabled(struct clk_hw *hw)
+{
+ void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
+ void __iomem *reg_usbpcr1 = cgu->base + CGU_REG_USBPCR1;
+
+ return !(readl(reg_opcr) & OPCR_SPENDH) &&
+ (readl(reg_usbpcr1) & USBPCR1_UHC_POWER);
+}
+
+struct clk_ops jz4770_uhc_phy_ops = {
+ .enable = jz4770_uhc_phy_enable,
+ .disable = jz4770_uhc_phy_disable,
+ .is_enabled = jz4770_uhc_phy_is_enabled,
+};
+
+static int jz4770_otg_phy_enable(struct clk_hw *hw)
+{
+ void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
+
+ writel(readl(reg_opcr) | OPCR_SPENDN, reg_opcr);
+
+ /* Wait for the clock to be stable */
+ udelay(50);
+ return 0;
+}
+
+static void jz4770_otg_phy_disable(struct clk_hw *hw)
+{
+ void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
+
+ writel(readl(reg_opcr) & ~OPCR_SPENDN, reg_opcr);
+}
+
+static int jz4770_otg_phy_is_enabled(struct clk_hw *hw)
+{
+ void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
+
+ return !!(readl(reg_opcr) & OPCR_SPENDN);
+}
+
+struct clk_ops jz4770_otg_phy_ops = {
+ .enable = jz4770_otg_phy_enable,
+ .disable = jz4770_otg_phy_disable,
+ .is_enabled = jz4770_otg_phy_is_enabled,
+};
+
+static const s8 pll_od_encoding[8] = {
+ 0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
+};
+
+static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
+
+ /* External clocks */
+
+ [JZ4770_CLK_EXT] = { "ext", CGU_CLK_EXT },
+ [JZ4770_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },
+
+ /* PLLs */
+
+ [JZ4770_CLK_PLL0] = {
+ "pll0", CGU_CLK_PLL,
+ .parents = { JZ4770_CLK_EXT },
+ .pll = {
+ .reg = CGU_REG_CPPCR0,
+ .m_shift = 24,
+ .m_bits = 7,
+ .m_offset = 1,
+ .n_shift = 18,
+ .n_bits = 5,
+ .n_offset = 1,
+ .od_shift = 16,
+ .od_bits = 2,
+ .od_max = 8,
+ .od_encoding = pll_od_encoding,
+ .bypass_bit = 9,
+ .enable_bit = 8,
+ .stable_bit = 10,
+ },
+ },
+
+ [JZ4770_CLK_PLL1] = {
+ /* TODO: PLL1 can depend on PLL0 */
+ "pll1", CGU_CLK_PLL,
+ .parents = { JZ4770_CLK_EXT },
+ .pll = {
+ .reg = CGU_REG_CPPCR1,
+ .m_shift = 24,
+ .m_bits = 7,
+ .m_offset = 1,
+ .n_shift = 18,
+ .n_bits = 5,
+ .n_offset = 1,
+ .od_shift = 16,
+ .od_bits = 2,
+ .od_max = 8,
+ .od_encoding = pll_od_encoding,
+ .enable_bit = 7,
+ .stable_bit = 6,
+ .no_bypass_bit = true,
+ },
+ },
+
+ /* Main clocks */
+
+ [JZ4770_CLK_CCLK] = {
+ "cclk", CGU_CLK_DIV,
+ .parents = { JZ4770_CLK_PLL0, },
+ .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 },
+ },
+ [JZ4770_CLK_H0CLK] = {
+ "h0clk", CGU_CLK_DIV,
+ .parents = { JZ4770_CLK_PLL0, },
+ .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 },
+ },
+ [JZ4770_CLK_H1CLK] = {
+ "h1clk", CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_PLL0, },
+ .div = { CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1 },
+ .gate = { CGU_REG_LCR, 30 },
+ },
+ [JZ4770_CLK_H2CLK] = {
+ "h2clk", CGU_CLK_DIV,
+ .parents = { JZ4770_CLK_PLL0, },
+ .div = { CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1 },
+ },
+ [JZ4770_CLK_C1CLK] = {
+ "c1clk", CGU_CLK_DIV,
+ .parents = { JZ4770_CLK_PLL0, },
+ .div = { CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1 },
+ },
+ [JZ4770_CLK_PCLK] = {
+ "pclk", CGU_CLK_DIV,
+ .parents = { JZ4770_CLK_PLL0, },
+ .div = { CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1 },
+ },
+
+ /* Those divided clocks can connect to PLL0 or PLL1 */
+
+ [JZ4770_CLK_MMC0_MUX] = {
+ "mmc0_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_MSC0CDR, 30, 1 },
+ .div = { CGU_REG_MSC0CDR, 0, 1, 7, -1, -1, 31 },
+ .gate = { CGU_REG_MSC0CDR, 31 },
+ },
+ [JZ4770_CLK_MMC1_MUX] = {
+ "mmc1_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_MSC1CDR, 30, 1 },
+ .div = { CGU_REG_MSC1CDR, 0, 1, 7, -1, -1, 31 },
+ .gate = { CGU_REG_MSC1CDR, 31 },
+ },
+ [JZ4770_CLK_MMC2_MUX] = {
+ "mmc2_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_MSC2CDR, 30, 1 },
+ .div = { CGU_REG_MSC2CDR, 0, 1, 7, -1, -1, 31 },
+ .gate = { CGU_REG_MSC2CDR, 31 },
+ },
+ [JZ4770_CLK_CIM] = {
+ "cim", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_CIMCDR, 31, 1 },
+ .div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 26 },
+ },
+ [JZ4770_CLK_UHC] = {
+ "uhc", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_UHCCDR, 29, 1 },
+ .div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 24 },
+ },
+ [JZ4770_CLK_GPU] = {
+ "gpu", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, -1 },
+ .mux = { CGU_REG_GPUCDR, 31, 1 },
+ .div = { CGU_REG_GPUCDR, 0, 1, 3, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR1, 9 },
+ },
+ [JZ4770_CLK_BCH] = {
+ "bch", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_BCHCDR, 31, 1 },
+ .div = { CGU_REG_BCHCDR, 0, 1, 3, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 1 },
+ },
+ [JZ4770_CLK_LPCLK_MUX] = {
+ "lpclk", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_LPCDR, 29, 1 },
+ .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 28 },
+ },
+ [JZ4770_CLK_GPS] = {
+ "gps", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_GPSCDR, 31, 1 },
+ .div = { CGU_REG_GPSCDR, 0, 1, 4, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 22 },
+ },
+
+ /* Those divided clocks can connect to EXT, PLL0 or PLL1 */
+
+ [JZ4770_CLK_SSI_MUX] = {
+ "ssi_mux", CGU_CLK_DIV | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_EXT, -1,
+ JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
+ .mux = { CGU_REG_SSICDR, 30, 2 },
+ .div = { CGU_REG_SSICDR, 0, 1, 6, -1, -1, -1 },
+ },
+ [JZ4770_CLK_PCM_MUX] = {
+ "pcm_mux", CGU_CLK_DIV | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_EXT, -1,
+ JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
+ .mux = { CGU_REG_PCMCDR, 30, 2 },
+ .div = { CGU_REG_PCMCDR, 0, 1, 9, -1, -1, -1 },
+ },
+ [JZ4770_CLK_I2S] = {
+ "i2s", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_EXT, -1,
+ JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
+ .mux = { CGU_REG_I2SCDR, 30, 2 },
+ .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR1, 13 },
+ },
+ [JZ4770_CLK_OTG] = {
+ "usb", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_EXT, -1,
+ JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
+ .mux = { CGU_REG_USBCDR, 30, 2 },
+ .div = { CGU_REG_USBCDR, 0, 1, 8, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 2 },
+ },
+
+ /* Gate-only clocks */
+
+ [JZ4770_CLK_SSI0] = {
+ "ssi0", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_SSI_MUX, },
+ .gate = { CGU_REG_CLKGR0, 4 },
+ },
+ [JZ4770_CLK_SSI1] = {
+ "ssi1", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_SSI_MUX, },
+ .gate = { CGU_REG_CLKGR0, 19 },
+ },
+ [JZ4770_CLK_SSI2] = {
+ "ssi2", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_SSI_MUX, },
+ .gate = { CGU_REG_CLKGR0, 20 },
+ },
+ [JZ4770_CLK_PCM0] = {
+ "pcm0", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_PCM_MUX, },
+ .gate = { CGU_REG_CLKGR1, 8 },
+ },
+ [JZ4770_CLK_PCM1] = {
+ "pcm1", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_PCM_MUX, },
+ .gate = { CGU_REG_CLKGR1, 10 },
+ },
+ [JZ4770_CLK_DMA] = {
+ "dma", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_H2CLK, },
+ .gate = { CGU_REG_CLKGR0, 21 },
+ },
+ [JZ4770_CLK_I2C0] = {
+ "i2c0", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 5 },
+ },
+ [JZ4770_CLK_I2C1] = {
+ "i2c1", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 6 },
+ },
+ [JZ4770_CLK_I2C2] = {
+ "i2c2", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR1, 15 },
+ },
+ [JZ4770_CLK_UART0] = {
+ "uart0", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 15 },
+ },
+ [JZ4770_CLK_UART1] = {
+ "uart1", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 16 },
+ },
+ [JZ4770_CLK_UART2] = {
+ "uart2", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 17 },
+ },
+ [JZ4770_CLK_UART3] = {
+ "uart3", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 18 },
+ },
+ [JZ4770_CLK_IPU] = {
+ "ipu", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_H0CLK, },
+ .gate = { CGU_REG_CLKGR0, 29 },
+ },
+ [JZ4770_CLK_ADC] = {
+ "adc", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 14 },
+ },
+ [JZ4770_CLK_AIC] = {
+ "aic", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 8 },
+ },
+ [JZ4770_CLK_AUX] = {
+ "aux", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_C1CLK, },
+ .gate = { CGU_REG_CLKGR1, 14 },
+ },
+ [JZ4770_CLK_VPU] = {
+ "vpu", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_H1CLK, },
+ .gate = { CGU_REG_CLKGR1, 7 },
+ },
+ [JZ4770_CLK_MMC0] = {
+ "mmc0", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_MMC0_MUX, },
+ .gate = { CGU_REG_CLKGR0, 3 },
+ },
+ [JZ4770_CLK_MMC1] = {
+ "mmc1", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_MMC1_MUX, },
+ .gate = { CGU_REG_CLKGR0, 11 },
+ },
+ [JZ4770_CLK_MMC2] = {
+ "mmc2", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_MMC2_MUX, },
+ .gate = { CGU_REG_CLKGR0, 12 },
+ },
+
+ /* Custom clocks */
+
+ [JZ4770_CLK_UHC_PHY] = {
+ "uhc_phy", CGU_CLK_CUSTOM,
+ .parents = { JZ4770_CLK_UHC, -1, -1, -1 },
+ .custom = { &jz4770_uhc_phy_ops },
+ },
+ [JZ4770_CLK_OTG_PHY] = {
+ "usb_phy", CGU_CLK_CUSTOM,
+ .parents = { JZ4770_CLK_OTG, -1, -1, -1 },
+ .custom = { &jz4770_otg_phy_ops },
+ },
+
+ [JZ4770_CLK_EXT512] = {
+ "ext/512", CGU_CLK_FIXDIV,
+ .parents = { JZ4770_CLK_EXT },
+ .fixdiv = { 512 },
+ },
+
+ [JZ4770_CLK_RTC] = {
+ "rtc", CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_EXT512, JZ4770_CLK_OSC32K, },
+ .mux = { CGU_REG_OPCR, 2, 1},
+ },
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int jz4770_cgu_pm_suspend(void)
+{
+ u32 val;
+
+ val = readl(cgu->base + CGU_REG_LCR);
+ writel(val | LCR_LPM, cgu->base + CGU_REG_LCR);
+ return 0;
+}
+
+static void jz4770_cgu_pm_resume(void)
+{
+ u32 val;
+
+ val = readl(cgu->base + CGU_REG_LCR);
+ writel(val & ~LCR_LPM, cgu->base + CGU_REG_LCR);
+}
+
+static struct syscore_ops jz4770_cgu_pm_ops = {
+ .suspend = jz4770_cgu_pm_suspend,
+ .resume = jz4770_cgu_pm_resume,
+};
+#endif /* CONFIG_PM_SLEEP */
+
+static void __init jz4770_cgu_init(struct device_node *np)
+{
+ int retval;
+
+ cgu = ingenic_cgu_new(jz4770_cgu_clocks,
+ ARRAY_SIZE(jz4770_cgu_clocks), np);
+ if (!cgu)
+ pr_err("%s: failed to initialise CGU\n", __func__);
+
+ retval = ingenic_cgu_register_clocks(cgu);
+ if (retval)
+ pr_err("%s: failed to register CGU Clocks\n", __func__);
+
+#ifdef CONFIG_PM_SLEEP
+ register_syscore_ops(&jz4770_cgu_pm_ops);
+#endif
+}
+CLK_OF_DECLARE(jz4770_cgu, "ingenic,jz4770-cgu", jz4770_cgu_init);
diff --git a/include/dt-bindings/clock/jz4770-cgu.h b/include/dt-bindings/clock/jz4770-cgu.h
new file mode 100644
index 000000000000..54b8b2ae4a73
--- /dev/null
+++ b/include/dt-bindings/clock/jz4770-cgu.h
@@ -0,0 +1,57 @@
+/*
+ * This header provides clock numbers for the ingenic,jz4770-cgu DT binding.
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_JZ4770_CGU_H__
+#define __DT_BINDINGS_CLOCK_JZ4770_CGU_H__
+
+#define JZ4770_CLK_EXT 0
+#define JZ4770_CLK_OSC32K 1
+#define JZ4770_CLK_PLL0 2
+#define JZ4770_CLK_PLL1 3
+#define JZ4770_CLK_CCLK 4
+#define JZ4770_CLK_H0CLK 5
+#define JZ4770_CLK_H1CLK 6
+#define JZ4770_CLK_H2CLK 7
+#define JZ4770_CLK_C1CLK 8
+#define JZ4770_CLK_PCLK 9
+#define JZ4770_CLK_MMC0_MUX 10
+#define JZ4770_CLK_MMC0 11
+#define JZ4770_CLK_MMC1_MUX 12
+#define JZ4770_CLK_MMC1 13
+#define JZ4770_CLK_MMC2_MUX 14
+#define JZ4770_CLK_MMC2 15
+#define JZ4770_CLK_CIM 16
+#define JZ4770_CLK_UHC 17
+#define JZ4770_CLK_GPU 18
+#define JZ4770_CLK_BCH 19
+#define JZ4770_CLK_LPCLK_MUX 20
+#define JZ4770_CLK_GPS 21
+#define JZ4770_CLK_SSI_MUX 22
+#define JZ4770_CLK_PCM_MUX 23
+#define JZ4770_CLK_I2S 24
+#define JZ4770_CLK_OTG 25
+#define JZ4770_CLK_SSI0 26
+#define JZ4770_CLK_SSI1 27
+#define JZ4770_CLK_SSI2 28
+#define JZ4770_CLK_PCM0 29
+#define JZ4770_CLK_PCM1 30
+#define JZ4770_CLK_DMA 31
+#define JZ4770_CLK_I2C0 32
+#define JZ4770_CLK_I2C1 33
+#define JZ4770_CLK_I2C2 34
+#define JZ4770_CLK_UART0 35
+#define JZ4770_CLK_UART1 36
+#define JZ4770_CLK_UART2 37
+#define JZ4770_CLK_UART3 38
+#define JZ4770_CLK_IPU 39
+#define JZ4770_CLK_ADC 40
+#define JZ4770_CLK_AIC 41
+#define JZ4770_CLK_AUX 42
+#define JZ4770_CLK_VPU 43
+#define JZ4770_CLK_UHC_PHY 44
+#define JZ4770_CLK_OTG_PHY 45
+#define JZ4770_CLK_EXT512 46
+#define JZ4770_CLK_RTC 47
+
+#endif /* __DT_BINDINGS_CLOCK_JZ4770_CGU_H__ */
--
2.11.0

2017-06-07 20:04:56

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH 05/15] serial: 8250_ingenic: Add support for the JZ4770 SoC

The JZ4770 SoC's UART is no different from the other JZ SoCs, so this
commit simply adds the ingenic,jz4770-uart compatible string.

Signed-off-by: Paul Cercueil <[email protected]>
---
Documentation/devicetree/bindings/serial/ingenic,uart.txt | 3 ++-
drivers/tty/serial/8250/8250_ingenic.c | 5 +++++
2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/serial/ingenic,uart.txt b/Documentation/devicetree/bindings/serial/ingenic,uart.txt
index 02cb7fe59cb7..75fd8b314af9 100644
--- a/Documentation/devicetree/bindings/serial/ingenic,uart.txt
+++ b/Documentation/devicetree/bindings/serial/ingenic,uart.txt
@@ -2,7 +2,8 @@

Required properties:
- compatible : "ingenic,jz4740-uart", "ingenic,jz4760-uart",
- "ingenic,jz4775-uart" or "ingenic,jz4780-uart"
+ "ingenic,jz4770-uart", "ingenic,jz4775-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.
diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c
index 4d9dc10e265c..b31b2ca552d1 100644
--- a/drivers/tty/serial/8250/8250_ingenic.c
+++ b/drivers/tty/serial/8250/8250_ingenic.c
@@ -133,6 +133,10 @@ EARLYCON_DECLARE(jz4740_uart, ingenic_early_console_setup);
OF_EARLYCON_DECLARE(jz4740_uart, "ingenic,jz4740-uart",
ingenic_early_console_setup);

+EARLYCON_DECLARE(jz4770_uart, ingenic_early_console_setup);
+OF_EARLYCON_DECLARE(jz4770_uart, "ingenic,jz4770-uart",
+ ingenic_early_console_setup);
+
EARLYCON_DECLARE(jz4775_uart, ingenic_early_console_setup);
OF_EARLYCON_DECLARE(jz4775_uart, "ingenic,jz4775-uart",
ingenic_early_console_setup);
@@ -327,6 +331,7 @@ static const struct ingenic_uart_config jz4780_uart_config = {
static const struct of_device_id of_match[] = {
{ .compatible = "ingenic,jz4740-uart", .data = &jz4740_uart_config },
{ .compatible = "ingenic,jz4760-uart", .data = &jz4760_uart_config },
+ { .compatible = "ingenic,jz4770-uart", .data = &jz4760_uart_config },
{ .compatible = "ingenic,jz4775-uart", .data = &jz4760_uart_config },
{ .compatible = "ingenic,jz4780-uart", .data = &jz4780_uart_config },
{ /* sentinel */ }
--
2.11.0

2017-06-07 20:04:50

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH 01/15] clk: ingenic: Fix recalc_rate for clocks with fixed divider

Previously, the clocks with a fixed divider would report their rate
as being the same as the one of their parent, independently of the
divider in use. This commit fixes this behaviour.

This went unnoticed as neither the jz4740 nor the jz4780 CGU code
have clocks with fixed dividers yet.

Signed-off-by: Paul Cercueil <[email protected]>
---
drivers/clk/ingenic/cgu.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
index e8248f9185f7..eb9002ccf3fc 100644
--- a/drivers/clk/ingenic/cgu.c
+++ b/drivers/clk/ingenic/cgu.c
@@ -328,6 +328,8 @@ ingenic_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
div *= clk_info->div.div;

rate /= div;
+ } else if (clk_info->type & CGU_CLK_FIXDIV) {
+ rate /= clk_info->fixdiv.div;
}

return rate;
--
2.11.0

2017-06-07 20:59:47

by Stephen Boyd

[permalink] [raw]
Subject: Re: [PATCH 04/15] clk: Add Ingenic jz4770 CGU driver

On 06/07, Paul Cercueil wrote:
> Add support for the clocks provided by the CGU in the Ingenic JZ4770
> SoC.
>
> Signed-off-by: Paul Cercueil <[email protected]>
> Signed-off-by: Maarten ter Huurne <[email protected]>

Signed-off chain looks odd. Sender should be last in the chain
and first is typically author.

WARNING: struct clk_ops should normally be const
#118: FILE: drivers/clk/ingenic/jz4770-cgu.c:84:
+struct clk_ops jz4770_uhc_phy_ops = {

WARNING: struct clk_ops should normally be const
#149: FILE: drivers/clk/ingenic/jz4770-cgu.c:115:
+struct clk_ops jz4770_otg_phy_ops = {

drivers/clk/ingenic/jz4770-cgu.c:84:16:
warning: symbol 'jz4770_uhc_phy_ops' was not declared. Should it
be static?
drivers/clk/ingenic/jz4770-cgu.c:115:16:
warning: symbol 'jz4770_otg_phy_ops' was not declared. Should it
be static?

> diff --git a/drivers/clk/ingenic/jz4770-cgu.c b/drivers/clk/ingenic/jz4770-cgu.c
> new file mode 100644
> index 000000000000..993db42df5fc
> --- /dev/null
> +++ b/drivers/clk/ingenic/jz4770-cgu.c
> @@ -0,0 +1,485 @@
> +/*
> + * JZ4770 SoC CGU driver
> + *
> + * Copyright 2017, Paul Cercueil <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 or later
> + * as published by the Free Software Foundation.
> + */
> +
> +#include <linux/bitops.h>
> +#include <linux/clk-provider.h>
> +#include <linux/delay.h>
> +#include <linux/of.h>
> +#include <linux/syscore_ops.h>
> +#include <dt-bindings/clock/jz4770-cgu.h>
> +#include "cgu.h"
> +
[..]
> +
> +static struct syscore_ops jz4770_cgu_pm_ops = {
> + .suspend = jz4770_cgu_pm_suspend,
> + .resume = jz4770_cgu_pm_resume,
> +};
> +#endif /* CONFIG_PM_SLEEP */
> +
> +static void __init jz4770_cgu_init(struct device_node *np)
> +{
> + int retval;
> +
> + cgu = ingenic_cgu_new(jz4770_cgu_clocks,
> + ARRAY_SIZE(jz4770_cgu_clocks), np);
> + if (!cgu)
> + pr_err("%s: failed to initialise CGU\n", __func__);
> +
> + retval = ingenic_cgu_register_clocks(cgu);
> + if (retval)
> + pr_err("%s: failed to register CGU Clocks\n", __func__);
> +
> +#ifdef CONFIG_PM_SLEEP

if (IS_ENABLED(CONFIG_PM_SLEEP) instead?

> + register_syscore_ops(&jz4770_cgu_pm_ops);
> +#endif
> +}
> +CLK_OF_DECLARE(jz4770_cgu, "ingenic,jz4770-cgu", jz4770_cgu_init);

Any reason this can't be a platform driver? Please add a comment
above CLK_OF_DECLARE describing what is preventing that.

> diff --git a/include/dt-bindings/clock/jz4770-cgu.h b/include/dt-bindings/clock/jz4770-cgu.h
> new file mode 100644
> index 000000000000..54b8b2ae4a73
> --- /dev/null
> +++ b/include/dt-bindings/clock/jz4770-cgu.h

Can you split this file off into a different patch? That way clk
tree can apply clk patches on top of a stable branch where this
file lives by itself.

--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

2017-06-08 07:31:18

by Marcin Nowakowski

[permalink] [raw]
Subject: Re: [PATCH 06/15] serial: 8250_ingenic: Parse earlycon options

Hi Paul,

On 07.06.2017 22:04, Paul Cercueil wrote:
> In the devicetree, it is possible to specify the baudrate, parity,
> bits, flow of the early console, by passing a configuration string like
> this:
>
> aliases {
> serial0 = &uart0;
> };
>
> chosen {
> stdout-path = "serial0:57600n8";
> };
>
> This, for instance, will configure the early console for a baudrate of
> 57600 bps, no parity, and 8 bits per baud.
>
> This patches implements parsing of this configuration string in the
> 8250_ingenic driver, which previously just ignored it.
>
> Signed-off-by: Paul Cercueil <[email protected]>
> ---
> drivers/tty/serial/8250/8250_ingenic.c | 14 ++++++++++++--
> 1 file changed, 12 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c
> index b31b2ca552d1..59f3e632df49 100644
> --- a/drivers/tty/serial/8250/8250_ingenic.c
> +++ b/drivers/tty/serial/8250/8250_ingenic.c
> @@ -99,14 +99,24 @@ static int __init ingenic_early_console_setup(struct earlycon_device *dev,
> const char *opt)
> {
> struct uart_port *port = &dev->port;
> - unsigned int baud, divisor;
> + unsigned int divisor;
> + int baud = 115200;
>
> if (!dev->port.membase)
> return -ENODEV;
>
> + if (opt) {
> + char options[256];
> + unsigned int parity, bits, flow; /* unused for now */
> +
> + strlcpy(options, opt, sizeof(options));

Rather than adding this extra local copy maybe you could instead:

-void uart_parse_options(char *options, int *baud, int *parity, int *bits,
+void uart_parse_options(const char *options, int *baud, int *parity,
int *bits,

I cannot see any reason why uart_parse_options shouldn't take 'const
char *options' as an argument.

> + uart_parse_options(options, &baud, &parity, &bits, &flow);
> + }
> +
> ingenic_early_console_setup_clock(dev);
>
> - baud = dev->baud ?: 115200;
> + if (dev->baud)
> + baud = dev->baud;
> divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud);
>
> early_out(port, UART_IER, 0);
>


Marcin

2017-06-08 08:50:24

by Maarten ter Huurne

[permalink] [raw]
Subject: Re: [PATCH 04/15] clk: Add Ingenic jz4770 CGU driver

On Wednesday 07 June 2017 13:59:43 Stephen Boyd wrote:
> On 06/07, Paul Cercueil wrote:
> > Add support for the clocks provided by the CGU in the Ingenic JZ4770
> > SoC.
> >
> > Signed-off-by: Paul Cercueil <[email protected]>
> > Signed-off-by: Maarten ter Huurne <[email protected]>
>
> Signed-off chain looks odd. Sender should be last in the chain
> and first is typically author.

Paul is the main author, but one or more commits I made were squashed
into the patch during its development.

Bye,
Maarten

2017-06-08 21:10:12

by Paul Cercueil

[permalink] [raw]
Subject: Re: [PATCH 04/15] clk: Add Ingenic jz4770 CGU driver

Hi,

>> + register_syscore_ops(&jz4770_cgu_pm_ops);
>> +#endif
>> +}
>> +CLK_OF_DECLARE(jz4770_cgu, "ingenic,jz4770-cgu", jz4770_cgu_init);
>
> Any reason this can't be a platform driver? Please add a comment
> above CLK_OF_DECLARE describing what is preventing that.

It would probably be possible, if we cared about having a platform
driver.
But we will only ever probe it from devicetree, just like with the
already existing jz4740-cgu and jz4780-cgu drivers.

>> diff --git a/include/dt-bindings/clock/jz4770-cgu.h
>> b/include/dt-bindings/clock/jz4770-cgu.h
>> new file mode 100644
>> index 000000000000..54b8b2ae4a73
>> --- /dev/null
>> +++ b/include/dt-bindings/clock/jz4770-cgu.h
>
> Can you split this file off into a different patch? That way clk
> tree can apply clk patches on top of a stable branch where this
> file lives by itself.

Sure.

Thanks,
- Paul

2017-06-08 21:12:16

by Paul Cercueil

[permalink] [raw]
Subject: Re: [PATCH 06/15] serial: 8250_ingenic: Parse earlycon options

Hi,

[...]
>> diff --git a/drivers/tty/serial/8250/8250_ingenic.c
>> b/drivers/tty/serial/8250/8250_ingenic.c
>> index b31b2ca552d1..59f3e632df49 100644
>> --- a/drivers/tty/serial/8250/8250_ingenic.c
>> +++ b/drivers/tty/serial/8250/8250_ingenic.c
>> @@ -99,14 +99,24 @@ static int __init
>> ingenic_early_console_setup(struct earlycon_device *dev,
>> const char *opt)
>> {
>> struct uart_port *port = &dev->port;
>> - unsigned int baud, divisor;
>> + unsigned int divisor;
>> + int baud = 115200;
>> if (!dev->port.membase)
>> return -ENODEV;
>> + if (opt) {
>> + char options[256];
>> + unsigned int parity, bits, flow; /* unused for now */
>> +
>> + strlcpy(options, opt, sizeof(options));
>
> Rather than adding this extra local copy maybe you could instead:
>
> -void uart_parse_options(char *options, int *baud, int *parity, int
> *bits,
> +void uart_parse_options(const char *options, int *baud, int *parity,
> int *bits,
>
> I cannot see any reason why uart_parse_options shouldn't take 'const
> char *options' as an argument.

Sure, good remark. I'll send a patch to change the prototype.

Thanks,
- Paul

2017-06-09 14:22:48

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH 05/15] serial: 8250_ingenic: Add support for the JZ4770 SoC

On Wed, Jun 07, 2017 at 10:04:29PM +0200, Paul Cercueil wrote:
> The JZ4770 SoC's UART is no different from the other JZ SoCs, so this
> commit simply adds the ingenic,jz4770-uart compatible string.
>
> Signed-off-by: Paul Cercueil <[email protected]>
> ---
> Documentation/devicetree/bindings/serial/ingenic,uart.txt | 3 ++-
> drivers/tty/serial/8250/8250_ingenic.c | 5 +++++
> 2 files changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/devicetree/bindings/serial/ingenic,uart.txt b/Documentation/devicetree/bindings/serial/ingenic,uart.txt
> index 02cb7fe59cb7..75fd8b314af9 100644
> --- a/Documentation/devicetree/bindings/serial/ingenic,uart.txt
> +++ b/Documentation/devicetree/bindings/serial/ingenic,uart.txt
> @@ -2,7 +2,8 @@
>
> Required properties:
> - compatible : "ingenic,jz4740-uart", "ingenic,jz4760-uart",
> - "ingenic,jz4775-uart" or "ingenic,jz4780-uart"
> + "ingenic,jz4770-uart", "ingenic,jz4775-uart" or
> + "ingenic,jz4780-uart"

If you respin, please reformat to 1 per line.

Acked-by: Rob Herring <[email protected]>

2017-06-09 14:24:09

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH 14/15] devicetree/bindings: Add GCW vendor prefix

On Wed, Jun 07, 2017 at 10:04:38PM +0200, Paul Cercueil wrote:
> Games Consoles Worldwide, mostly known under the acronym GCW, is the
> creator of the GCW Zero open-source video game system.
>
> Signed-off-by: Paul Cercueil <[email protected]>
> ---
> Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
> 1 file changed, 1 insertion(+)

Acked-by: Rob Herring <[email protected]>

2017-06-20 15:19:12

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v2 02/17] clk: ingenic: Fix recalc_rate for clocks with fixed divider

Previously, the clocks with a fixed divider would report their rate
as being the same as the one of their parent, independently of the
divider in use. This commit fixes this behaviour.

This went unnoticed as neither the jz4740 nor the jz4780 CGU code
have clocks with fixed dividers yet.

Signed-off-by: Paul Cercueil <[email protected]>
---
drivers/clk/ingenic/cgu.c | 2 ++
1 file changed, 2 insertions(+)

v2: No changes

diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
index e8248f9185f7..eb9002ccf3fc 100644
--- a/drivers/clk/ingenic/cgu.c
+++ b/drivers/clk/ingenic/cgu.c
@@ -328,6 +328,8 @@ ingenic_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
div *= clk_info->div.div;

rate /= div;
+ } else if (clk_info->type & CGU_CLK_FIXDIV) {
+ rate /= clk_info->fixdiv.div;
}

return rate;
--
2.11.0

2017-06-20 15:19:18

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v2 09/17] MIPS: Setup boot_command_line before plat_mem_setup

From: Paul Burton <[email protected]>

Platforms using DT will typically call __dt_setup_arch from
plat_mem_setup. This in turn calls early_init_dt_scan. When
CONFIG_CMDLINE is set, this leads to its value being copied into
boot_command_line by early_init_dt_scan_chosen. If this happens before
the code setting up boot_command_line in arch_mem_init runs, that code
will go on to append CONFIG_CMDLINE (via builtin_cmdline) to
boot_command_line again, duplicating it. For some command line
parameters (eg. earlycon) this can be a problem. Set up
boot_command_line before early_init_dt_scan_chosen gets called such that
it will not write CONFIG_CMDLINE in this scenario & the arguments aren't
duplicated.

Signed-off-by: Paul Burton <[email protected]>
---
arch/mips/kernel/setup.c | 39 ++++++++++++++++++++-------------------
1 file changed, 20 insertions(+), 19 deletions(-)

v2: No change

diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 01d1dbde5fbf..89785600fde4 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -785,25 +785,6 @@ static void __init arch_mem_init(char **cmdline_p)
struct memblock_region *reg;
extern void plat_mem_setup(void);

- /* call board setup routine */
- plat_mem_setup();
-
- /*
- * Make sure all kernel memory is in the maps. The "UP" and
- * "DOWN" are opposite for initdata since if it crosses over
- * into another memory section you don't want that to be
- * freed when the initdata is freed.
- */
- arch_mem_addpart(PFN_DOWN(__pa_symbol(&_text)) << PAGE_SHIFT,
- PFN_UP(__pa_symbol(&_edata)) << PAGE_SHIFT,
- BOOT_MEM_RAM);
- arch_mem_addpart(PFN_UP(__pa_symbol(&__init_begin)) << PAGE_SHIFT,
- PFN_DOWN(__pa_symbol(&__init_end)) << PAGE_SHIFT,
- BOOT_MEM_INIT_RAM);
-
- pr_info("Determined physical RAM map:\n");
- print_memory_map();
-
#if defined(CONFIG_CMDLINE_BOOL) && defined(CONFIG_CMDLINE_OVERRIDE)
strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
#else
@@ -831,6 +812,26 @@ static void __init arch_mem_init(char **cmdline_p)
}
#endif
#endif
+
+ /* call board setup routine */
+ plat_mem_setup();
+
+ /*
+ * Make sure all kernel memory is in the maps. The "UP" and
+ * "DOWN" are opposite for initdata since if it crosses over
+ * into another memory section you don't want that to be
+ * freed when the initdata is freed.
+ */
+ arch_mem_addpart(PFN_DOWN(__pa_symbol(&_text)) << PAGE_SHIFT,
+ PFN_UP(__pa_symbol(&_edata)) << PAGE_SHIFT,
+ BOOT_MEM_RAM);
+ arch_mem_addpart(PFN_UP(__pa_symbol(&__init_begin)) << PAGE_SHIFT,
+ PFN_DOWN(__pa_symbol(&__init_end)) << PAGE_SHIFT,
+ BOOT_MEM_INIT_RAM);
+
+ pr_info("Determined physical RAM map:\n");
+ print_memory_map();
+
strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);

*cmdline_p = command_line;
--
2.11.0

2017-06-20 15:19:25

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v2 11/17] MIPS: platform: add machtype IDs for more Ingenic SoCs

Add a machtype ID for the JZ4780 SoC, which was missing, and one for the
newly supported JZ4770 SoC.

Signed-off-by: Paul Cercueil <[email protected]>
---
arch/mips/include/asm/bootinfo.h | 2 ++
1 file changed, 2 insertions(+)

v2: No change

diff --git a/arch/mips/include/asm/bootinfo.h b/arch/mips/include/asm/bootinfo.h
index e26a093bb17a..a301a8f4bc66 100644
--- a/arch/mips/include/asm/bootinfo.h
+++ b/arch/mips/include/asm/bootinfo.h
@@ -79,6 +79,8 @@ enum loongson_machine_type {
*/
#define MACH_INGENIC_JZ4730 0 /* JZ4730 SOC */
#define MACH_INGENIC_JZ4740 1 /* JZ4740 SOC */
+#define MACH_INGENIC_JZ4770 2 /* JZ4770 SOC */
+#define MACH_INGENIC_JZ4780 3 /* JZ4780 SOC */

extern char *system_type;
const char *get_system_type(void);
--
2.11.0

2017-06-20 15:19:22

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v2 12/17] MIPS: ingenic: Add machine info for supported boards

This makes sure that 'mips_machtype' will be initialized to the SoC
version used on the board.

Signed-off-by: Paul Cercueil <[email protected]>
---
arch/mips/Kconfig | 1 +
arch/mips/jz4740/Makefile | 2 +-
arch/mips/jz4740/boards.c | 16 ++++++++++++++++
arch/mips/jz4740/setup.c | 34 +++++++++++++++++++++++++++++-----
4 files changed, 47 insertions(+), 6 deletions(-)
create mode 100644 arch/mips/jz4740/boards.c

v2: No change

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 2828ecde133d..f36ffb93efd9 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -370,6 +370,7 @@ config MACH_INGENIC
select BUILTIN_DTB
select USE_OF
select LIBFDT
+ select MIPS_MACHINE

config LANTIQ
bool "Lantiq based platforms"
diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile
index 39d70bde8cfe..87feb246fafe 100644
--- a/arch/mips/jz4740/Makefile
+++ b/arch/mips/jz4740/Makefile
@@ -5,7 +5,7 @@
# Object file lists.

obj-y += prom.o time.o reset.o setup.o \
- platform.o timer.o
+ platform.o timer.o boards.o

obj-$(CONFIG_MACH_JZ4740) += gpio.o

diff --git a/arch/mips/jz4740/boards.c b/arch/mips/jz4740/boards.c
new file mode 100644
index 000000000000..a3cf64cf004a
--- /dev/null
+++ b/arch/mips/jz4740/boards.c
@@ -0,0 +1,16 @@
+/*
+ * Ingenic boards support
+ *
+ * Copyright 2017, Paul Cercueil <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or later
+ * as published by the Free Software Foundation.
+ */
+
+#include <asm/bootinfo.h>
+#include <asm/mips_machine.h>
+
+MIPS_MACHINE(MACH_INGENIC_JZ4740, "qi,lb60", "Qi Hardware Ben Nanonote", NULL);
+MIPS_MACHINE(MACH_INGENIC_JZ4780, "img,ci20",
+ "Imagination Technologies CI20", NULL);
diff --git a/arch/mips/jz4740/setup.c b/arch/mips/jz4740/setup.c
index 6d0152321819..afd84ee966e8 100644
--- a/arch/mips/jz4740/setup.c
+++ b/arch/mips/jz4740/setup.c
@@ -22,6 +22,7 @@
#include <linux/of_fdt.h>

#include <asm/bootinfo.h>
+#include <asm/mips_machine.h>
#include <asm/prom.h>

#include <asm/mach-jz4740/base.h>
@@ -53,16 +54,34 @@ static void __init jz4740_detect_mem(void)
add_memory_region(0, size, BOOT_MEM_RAM);
}

+static unsigned long __init get_board_mach_type(const void *fdt)
+{
+ const struct mips_machine *mach;
+
+ for (mach = (struct mips_machine *)&__mips_machines_start;
+ mach < (struct mips_machine *)&__mips_machines_end;
+ mach++) {
+ if (!fdt_node_check_compatible(fdt, 0, mach->mach_id))
+ return mach->mach_type;
+ }
+
+ return MACH_INGENIC_JZ4740;
+}
+
void __init plat_mem_setup(void)
{
int offset;

+ if (!early_init_dt_scan(__dtb_start))
+ return;
+
jz4740_reset_init();
- __dt_setup_arch(__dtb_start);

offset = fdt_path_offset(__dtb_start, "/memory");
if (offset < 0)
jz4740_detect_mem();
+
+ mips_machtype = get_board_mach_type(__dtb_start);
}

void __init device_tree_init(void)
@@ -75,13 +94,18 @@ void __init device_tree_init(void)

const char *get_system_type(void)
{
- if (IS_ENABLED(CONFIG_MACH_JZ4780))
- return "JZ4780";
-
- return "JZ4740";
+ return mips_get_machine_name();
}

void __init arch_init_irq(void)
{
irqchip_init();
}
+
+static int __init jz4740_machine_setup(void)
+{
+ mips_machine_setup();
+
+ return 0;
+}
+arch_initcall(jz4740_machine_setup);
--
2.11.0

2017-06-20 15:19:28

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v2 13/17] MIPS: ingenic: Initial JZ4770 support

Provide just enough bits (clocks, clocksource, uart) to allow a kernel
to boot on the JZ4770 SoC to a initramfs userspace.

Signed-off-by: Paul Cercueil <[email protected]>
---
arch/mips/boot/dts/ingenic/jz4770.dtsi | 210 +++++++++++++++++++++++++++++++++
arch/mips/jz4740/Kconfig | 6 +
arch/mips/jz4740/time.c | 2 +-
3 files changed, 217 insertions(+), 1 deletion(-)
create mode 100644 arch/mips/boot/dts/ingenic/jz4770.dtsi

v2: No change

diff --git a/arch/mips/boot/dts/ingenic/jz4770.dtsi b/arch/mips/boot/dts/ingenic/jz4770.dtsi
new file mode 100644
index 000000000000..d8d0a741ff5d
--- /dev/null
+++ b/arch/mips/boot/dts/ingenic/jz4770.dtsi
@@ -0,0 +1,210 @@
+#include <dt-bindings/clock/jz4770-cgu.h>
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "ingenic,jz4770";
+
+ cpuintc: interrupt-controller {
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ compatible = "mti,cpu-interrupt-controller";
+ };
+
+ intc: interrupt-controller@10001000 {
+ compatible = "ingenic,jz4770-intc";
+ reg = <0x10001000 0x40>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpuintc>;
+ interrupts = <2>;
+ };
+
+ ext: ext {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ };
+
+ osc32k: osc32k {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ };
+
+ cgu: jz4770-cgu@10000000 {
+ compatible = "ingenic,jz4770-cgu";
+ reg = <0x10000000 0x100>;
+
+ clocks = <&ext>, <&osc32k>;
+ clock-names = "ext", "osc32k";
+
+ #clock-cells = <1>;
+ };
+
+ pinctrl: pin-controller@10010000 {
+ compatible = "ingenic,jz4770-pinctrl";
+ reg = <0x10010000 0x600>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ gpa: gpio@0 {
+ compatible = "ingenic,jz4770-gpio";
+ reg = <0>;
+
+ gpio-controller;
+ gpio-ranges = <&pinctrl 0 0 32>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <17>;
+ };
+
+ gpb: gpio@1 {
+ compatible = "ingenic,jz4770-gpio";
+ reg = <1>;
+
+ gpio-controller;
+ gpio-ranges = <&pinctrl 0 32 32>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <16>;
+ };
+
+ gpc: gpio@2 {
+ compatible = "ingenic,jz4770-gpio";
+ reg = <2>;
+
+ gpio-controller;
+ gpio-ranges = <&pinctrl 0 64 32>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <15>;
+ };
+
+ gpd: gpio@3 {
+ compatible = "ingenic,jz4770-gpio";
+ reg = <3>;
+
+ gpio-controller;
+ gpio-ranges = <&pinctrl 0 96 32>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <14>;
+ };
+
+ gpe: gpio@4 {
+ compatible = "ingenic,jz4770-gpio";
+ reg = <4>;
+
+ gpio-controller;
+ gpio-ranges = <&pinctrl 0 128 32>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <13>;
+ };
+
+ gpf: gpio@5 {
+ compatible = "ingenic,jz4770-gpio";
+ reg = <5>;
+
+ gpio-controller;
+ gpio-ranges = <&pinctrl 0 160 32>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <12>;
+ };
+ };
+
+ uart0: serial@10030000 {
+ compatible = "ingenic,jz4770-uart";
+ reg = <0x10030000 0x100>;
+
+ clocks = <&ext>, <&cgu JZ4770_CLK_UART0>;
+ clock-names = "baud", "module";
+
+ interrupt-parent = <&intc>;
+ interrupts = <5>;
+
+ status = "disabled";
+ };
+
+ uart1: serial@10031000 {
+ compatible = "ingenic,jz4770-uart";
+ reg = <0x10031000 0x100>;
+
+ clocks = <&ext>, <&cgu JZ4770_CLK_UART1>;
+ clock-names = "baud", "module";
+
+ interrupt-parent = <&intc>;
+ interrupts = <4>;
+
+ status = "disabled";
+ };
+
+ uart2: serial@10032000 {
+ compatible = "ingenic,jz4770-uart";
+ reg = <0x10032000 0x100>;
+
+ clocks = <&ext>, <&cgu JZ4770_CLK_UART2>;
+ clock-names = "baud", "module";
+
+ interrupt-parent = <&intc>;
+ interrupts = <3>;
+
+ status = "disabled";
+ };
+
+ uart3: serial@10033000 {
+ compatible = "ingenic,jz4770-uart";
+ reg = <0x10033000 0x100>;
+
+ clocks = <&ext>, <&cgu JZ4770_CLK_UART3>;
+ clock-names = "baud", "module";
+
+ interrupt-parent = <&intc>;
+ interrupts = <2>;
+
+ status = "disabled";
+ };
+
+ uhc: uhc@13430000 {
+ compatible = "generic-ohci";
+ reg = <0x13430000 0x1000>;
+
+ clocks = <&cgu JZ4770_CLK_UHC>, <&cgu JZ4770_CLK_UHC_PHY>;
+ assigned-clocks = <&cgu JZ4770_CLK_UHC>;
+ assigned-clock-rates = <48000000>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <20>;
+
+ status = "disabled";
+ };
+};
diff --git a/arch/mips/jz4740/Kconfig b/arch/mips/jz4740/Kconfig
index 36f82017695d..922850503271 100644
--- a/arch/mips/jz4740/Kconfig
+++ b/arch/mips/jz4740/Kconfig
@@ -17,6 +17,12 @@ config MACH_JZ4740
bool
select SYS_HAS_CPU_MIPS32_R1

+config MACH_JZ4770
+ bool
+ select MIPS_CPU_SCACHE
+ select SYS_HAS_CPU_MIPS32_R2
+ select SYS_SUPPORTS_HIGHMEM
+
config MACH_JZ4780
bool
select MIPS_CPU_SCACHE
diff --git a/arch/mips/jz4740/time.c b/arch/mips/jz4740/time.c
index bb1ad5119da4..2ca9160f642a 100644
--- a/arch/mips/jz4740/time.c
+++ b/arch/mips/jz4740/time.c
@@ -113,7 +113,7 @@ static struct clock_event_device jz4740_clockevent = {
#ifdef CONFIG_MACH_JZ4740
.irq = JZ4740_IRQ_TCU0,
#endif
-#ifdef CONFIG_MACH_JZ4780
+#if defined(CONFIG_MACH_JZ4770) || defined(CONFIG_MACH_JZ4780)
.irq = JZ4780_IRQ_TCU2,
#endif
};
--
2.11.0

2017-06-20 15:19:53

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v2 17/17] MIPS: ingenic: Initial GCW Zero support

The GCW Zero (http://www.gcw-zero.com) is a retro-gaming focused
handheld game console, successfully kickstarted in ~2012, running Linux.

Signed-off-by: Paul Cercueil <[email protected]>
---
arch/mips/boot/dts/ingenic/Makefile | 1 +
arch/mips/boot/dts/ingenic/gcw0.dts | 60 +++++++++++++++++++++++++++++++++++++
arch/mips/configs/gcw0_defconfig | 28 +++++++++++++++++
arch/mips/jz4740/Kconfig | 4 +++
arch/mips/jz4740/boards.c | 1 +
5 files changed, 94 insertions(+)
create mode 100644 arch/mips/boot/dts/ingenic/gcw0.dts
create mode 100644 arch/mips/configs/gcw0_defconfig

v2: No change

diff --git a/arch/mips/boot/dts/ingenic/Makefile b/arch/mips/boot/dts/ingenic/Makefile
index f2b864f07850..f64ad1c27a28 100644
--- a/arch/mips/boot/dts/ingenic/Makefile
+++ b/arch/mips/boot/dts/ingenic/Makefile
@@ -1,4 +1,5 @@
dtb-$(CONFIG_JZ4740_QI_LB60) += qi_lb60.dtb
+dtb-$(CONFIG_JZ4770_GCW0) += gcw0.dtb
dtb-$(CONFIG_JZ4780_CI20) += ci20.dtb

obj-y += $(patsubst %.dtb, %.dtb.o, $(dtb-y))
diff --git a/arch/mips/boot/dts/ingenic/gcw0.dts b/arch/mips/boot/dts/ingenic/gcw0.dts
new file mode 100644
index 000000000000..9c9a0137ccdf
--- /dev/null
+++ b/arch/mips/boot/dts/ingenic/gcw0.dts
@@ -0,0 +1,60 @@
+/dts-v1/;
+
+#include "jz4770.dtsi"
+
+/ {
+ compatible = "gcw,zero", "ingenic,jz4770";
+
+ aliases {
+ serial0 = &uart0;
+ serial1 = &uart1;
+ serial2 = &uart2;
+ serial3 = &uart3;
+ };
+
+ chosen {
+ stdout-path = "serial2:57600n8";
+ };
+
+ board {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges = <>;
+
+ otg_phy: otg-phy {
+ compatible = "usb-nop-xceiv";
+ clocks = <&cgu JZ4770_CLK_OTG_PHY>;
+ clock-names = "main_clk";
+ };
+ };
+};
+
+&ext {
+ clock-frequency = <12000000>;
+};
+
+&uart2 {
+ status = "okay";
+};
+
+&cgu {
+ /* Put high-speed peripherals under PLL1, such that we can change the
+ * PLL0 frequency on demand without having to suspend peripherals.
+ * We use a rate of 432 MHz, which is the least common multiple of
+ * 27 MHz (required by TV encoder) and 48 MHz (required by USB host).
+ */
+ assigned-clocks =
+ <&cgu JZ4770_CLK_PLL1>,
+ <&cgu JZ4770_CLK_UHC>;
+ assigned-clock-parents =
+ <0>,
+ <&cgu JZ4770_CLK_PLL1>;
+ assigned-clock-rates =
+ <432000000>;
+};
+
+&uhc {
+ /* The WiFi module is connected to the UHC. */
+ status = "okay";
+};
diff --git a/arch/mips/configs/gcw0_defconfig b/arch/mips/configs/gcw0_defconfig
new file mode 100644
index 000000000000..471497033855
--- /dev/null
+++ b/arch/mips/configs/gcw0_defconfig
@@ -0,0 +1,28 @@
+CONFIG_MACH_INGENIC=y
+CONFIG_JZ4770_GCW0=y
+CONFIG_HIGHMEM=y
+# CONFIG_BOUNCE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_SECCOMP is not set
+CONFIG_CROSS_COMPILE="mipsel-gcw0-linux-uclibc-"
+CONFIG_NO_HZ_IDLE=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_EMBEDDED=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_NETDEVICES=y
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_INGENIC=y
+CONFIG_USB=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_TMPFS=y
diff --git a/arch/mips/jz4740/Kconfig b/arch/mips/jz4740/Kconfig
index 922850503271..db270653fe8c 100644
--- a/arch/mips/jz4740/Kconfig
+++ b/arch/mips/jz4740/Kconfig
@@ -7,6 +7,10 @@ config JZ4740_QI_LB60
bool "Qi Hardware Ben NanoNote"
select MACH_JZ4740

+config JZ4770_GCW0
+ bool "Game Consoles Worldwide GCW Zero"
+ select MACH_JZ4770
+
config JZ4780_CI20
bool "MIPS Creator CI20"
select MACH_JZ4780
diff --git a/arch/mips/jz4740/boards.c b/arch/mips/jz4740/boards.c
index a3cf64cf004a..98a4d8e68cf0 100644
--- a/arch/mips/jz4740/boards.c
+++ b/arch/mips/jz4740/boards.c
@@ -12,5 +12,6 @@
#include <asm/mips_machine.h>

MIPS_MACHINE(MACH_INGENIC_JZ4740, "qi,lb60", "Qi Hardware Ben Nanonote", NULL);
+MIPS_MACHINE(MACH_INGENIC_JZ4770, "gcw,zero", "GCW Zero", NULL);
MIPS_MACHINE(MACH_INGENIC_JZ4780, "img,ci20",
"Imagination Technologies CI20", NULL);
--
2.11.0

2017-06-20 15:20:06

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v2 16/17] devicetree/bindings: Add GCW vendor prefix

Game Consoles Worldwide, mostly known under the acronym GCW, is the
creator of the GCW Zero open-source video game system.

Signed-off-by: Paul Cercueil <[email protected]>
Acked-by: Rob Herring <[email protected]>
---
Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
1 file changed, 1 insertion(+)

v2: It's 'Game Consoles Worldwide', not 'Games Consoles Worldwide'

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index c03d20140366..5921aa1248fb 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -114,6 +114,7 @@ focaltech FocalTech Systems Co.,Ltd
friendlyarm Guangzhou FriendlyARM Computer Tech Co., Ltd
fsl Freescale Semiconductor
fujitsu Fujitsu Ltd.
+gcw Game Consoles Worldwide
ge General Electric Company
geekbuying GeekBuying
gef GE Fanuc Intelligent Platforms Embedded Systems, Inc.
--
2.11.0

2017-06-20 15:20:22

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v2 15/17] MIPS: JZ4770: Workaround for corrupted DMA transfers

From: Maarten ter Huurne <[email protected]>

We have seen MMC DMA transfers read corrupted data from SDRAM when
a burst interval ends at physical address 0x10000000. To avoid this
problem, we remove the final page of low memory from the memory map.

Signed-off-by: Maarten ter Huurne <[email protected]>
---
arch/mips/jz4740/setup.c | 24 ++++++++++++++++++++++++
arch/mips/kernel/setup.c | 8 ++++++++
2 files changed, 32 insertions(+)

v2: No change

diff --git a/arch/mips/jz4740/setup.c b/arch/mips/jz4740/setup.c
index afd84ee966e8..6948b133a15d 100644
--- a/arch/mips/jz4740/setup.c
+++ b/arch/mips/jz4740/setup.c
@@ -23,6 +23,7 @@

#include <asm/bootinfo.h>
#include <asm/mips_machine.h>
+#include <asm/page.h>
#include <asm/prom.h>

#include <asm/mach-jz4740/base.h>
@@ -102,6 +103,29 @@ void __init arch_init_irq(void)
irqchip_init();
}

+/*
+ * We have seen MMC DMA transfers read corrupted data from SDRAM when a burst
+ * interval ends at physical address 0x10000000. To avoid this problem, we
+ * remove the final page of low memory from the memory map.
+ */
+void __init jz4770_reserve_unsafe_for_dma(void)
+{
+ int i;
+
+ for (i = 0; i < boot_mem_map.nr_map; i++) {
+ struct boot_mem_map_entry *entry = boot_mem_map.map + i;
+
+ if (entry->type != BOOT_MEM_RAM)
+ continue;
+
+ if (entry->addr + entry->size != 0x10000000)
+ continue;
+
+ entry->size -= PAGE_SIZE;
+ break;
+ }
+}
+
static int __init jz4740_machine_setup(void)
{
mips_machine_setup();
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 89785600fde4..cccfd7ba89fe 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -838,6 +838,14 @@ static void __init arch_mem_init(char **cmdline_p)

parse_early_param();

+#ifdef CONFIG_MACH_JZ4770
+ if (current_cpu_type() == CPU_JZRISC &&
+ mips_machtype == MACH_INGENIC_JZ4770) {
+ extern void __init jz4770_reserve_unsafe_for_dma(void);
+ jz4770_reserve_unsafe_for_dma();
+ }
+#endif
+
if (usermem) {
pr_info("User-defined physical RAM map:\n");
print_memory_map();
--
2.11.0

2017-06-20 15:20:39

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v2 14/17] MIPS: JZ4770: Work around config2 misreporting associativity

From: Maarten ter Huurne <[email protected]>

According to config2, the associativity would be 5-ways, but the
documentation states 4-ways, which also matches the documented
L2 cache size of 256 kB.

Signed-off-by: Maarten ter Huurne <[email protected]>
---
arch/mips/mm/sc-mips.c | 9 +++++++++
1 file changed, 9 insertions(+)

v2: No change

diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c
index c909c3342729..67a3b4d88580 100644
--- a/arch/mips/mm/sc-mips.c
+++ b/arch/mips/mm/sc-mips.c
@@ -15,6 +15,7 @@
#include <asm/mmu_context.h>
#include <asm/r4kcache.h>
#include <asm/mips-cm.h>
+#include <asm/bootinfo.h>

/*
* MIPS32/MIPS64 L2 cache handling
@@ -228,6 +229,14 @@ static inline int __init mips_sc_probe(void)
else
return 0;

+ /*
+ * According to config2 it would be 5-ways, but that is contradicted
+ * by all documentation.
+ */
+ if (current_cpu_type() == CPU_JZRISC &&
+ mips_machtype == MACH_INGENIC_JZ4770)
+ c->scache.ways = 4;
+
c->scache.waysize = c->scache.sets * c->scache.linesz;
c->scache.waybit = __ffs(c->scache.waysize);

--
2.11.0

2017-06-20 15:19:15

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v2 05/17] clk: Add Ingenic jz4770 CGU driver

Add support for the clocks provided by the CGU in the Ingenic JZ4770
SoC.

Signed-off-by: Paul Cercueil <[email protected]>
Signed-off-by: Maarten ter Huurne <[email protected]>
---
drivers/clk/ingenic/Makefile | 1 +
drivers/clk/ingenic/jz4770-cgu.c | 487 +++++++++++++++++++++++++++++++++
include/dt-bindings/clock/jz4770-cgu.h | 57 ++++
3 files changed, 545 insertions(+)
create mode 100644 drivers/clk/ingenic/jz4770-cgu.c
create mode 100644 include/dt-bindings/clock/jz4770-cgu.h

v2: Make structures static const

diff --git a/drivers/clk/ingenic/Makefile b/drivers/clk/ingenic/Makefile
index cd47b0664c2b..1456e4cdb562 100644
--- a/drivers/clk/ingenic/Makefile
+++ b/drivers/clk/ingenic/Makefile
@@ -1,3 +1,4 @@
obj-y += cgu.o
obj-$(CONFIG_MACH_JZ4740) += jz4740-cgu.o
+obj-$(CONFIG_MACH_JZ4770) += jz4770-cgu.o
obj-$(CONFIG_MACH_JZ4780) += jz4780-cgu.o
diff --git a/drivers/clk/ingenic/jz4770-cgu.c b/drivers/clk/ingenic/jz4770-cgu.c
new file mode 100644
index 000000000000..4b2411d8a491
--- /dev/null
+++ b/drivers/clk/ingenic/jz4770-cgu.c
@@ -0,0 +1,487 @@
+/*
+ * JZ4770 SoC CGU driver
+ *
+ * Copyright 2017, Paul Cercueil <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or later
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/syscore_ops.h>
+#include <dt-bindings/clock/jz4770-cgu.h>
+#include "cgu.h"
+
+/*
+ * CPM registers offset address definition
+ */
+#define CGU_REG_CPCCR 0x00
+#define CGU_REG_LCR 0x04
+#define CGU_REG_CPPCR0 0x10
+#define CGU_REG_CLKGR0 0x20
+#define CGU_REG_OPCR 0x24
+#define CGU_REG_CLKGR1 0x28
+#define CGU_REG_CPPCR1 0x30
+#define CGU_REG_USBPCR1 0x48
+#define CGU_REG_USBCDR 0x50
+#define CGU_REG_I2SCDR 0x60
+#define CGU_REG_LPCDR 0x64
+#define CGU_REG_MSC0CDR 0x68
+#define CGU_REG_UHCCDR 0x6c
+#define CGU_REG_SSICDR 0x74
+#define CGU_REG_CIMCDR 0x7c
+#define CGU_REG_GPSCDR 0x80
+#define CGU_REG_PCMCDR 0x84
+#define CGU_REG_GPUCDR 0x88
+#define CGU_REG_MSC1CDR 0xA4
+#define CGU_REG_MSC2CDR 0xA8
+#define CGU_REG_BCHCDR 0xAC
+
+/* bits within the LCR register */
+#define LCR_LPM BIT(0) /* Low Power Mode */
+
+/* bits within the OPCR register */
+#define OPCR_SPENDH BIT(5) /* UHC PHY suspend */
+#define OPCR_SPENDN BIT(7) /* OTG PHY suspend */
+
+/* bits within the USBPCR1 register */
+#define USBPCR1_UHC_POWER BIT(5) /* UHC PHY power down */
+
+static struct ingenic_cgu *cgu;
+
+static int jz4770_uhc_phy_enable(struct clk_hw *hw)
+{
+ void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
+ void __iomem *reg_usbpcr1 = cgu->base + CGU_REG_USBPCR1;
+
+ writel(readl(reg_opcr) & ~OPCR_SPENDH, reg_opcr);
+ writel(readl(reg_usbpcr1) | USBPCR1_UHC_POWER, reg_usbpcr1);
+ return 0;
+}
+
+static void jz4770_uhc_phy_disable(struct clk_hw *hw)
+{
+ void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
+ void __iomem *reg_usbpcr1 = cgu->base + CGU_REG_USBPCR1;
+
+ writel(readl(reg_usbpcr1) & ~USBPCR1_UHC_POWER, reg_usbpcr1);
+ writel(readl(reg_opcr) | OPCR_SPENDH, reg_opcr);
+}
+
+static int jz4770_uhc_phy_is_enabled(struct clk_hw *hw)
+{
+ void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
+ void __iomem *reg_usbpcr1 = cgu->base + CGU_REG_USBPCR1;
+
+ return !(readl(reg_opcr) & OPCR_SPENDH) &&
+ (readl(reg_usbpcr1) & USBPCR1_UHC_POWER);
+}
+
+static const struct clk_ops jz4770_uhc_phy_ops = {
+ .enable = jz4770_uhc_phy_enable,
+ .disable = jz4770_uhc_phy_disable,
+ .is_enabled = jz4770_uhc_phy_is_enabled,
+};
+
+static int jz4770_otg_phy_enable(struct clk_hw *hw)
+{
+ void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
+
+ writel(readl(reg_opcr) | OPCR_SPENDN, reg_opcr);
+
+ /* Wait for the clock to be stable */
+ udelay(50);
+ return 0;
+}
+
+static void jz4770_otg_phy_disable(struct clk_hw *hw)
+{
+ void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
+
+ writel(readl(reg_opcr) & ~OPCR_SPENDN, reg_opcr);
+}
+
+static int jz4770_otg_phy_is_enabled(struct clk_hw *hw)
+{
+ void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
+
+ return !!(readl(reg_opcr) & OPCR_SPENDN);
+}
+
+static const struct clk_ops jz4770_otg_phy_ops = {
+ .enable = jz4770_otg_phy_enable,
+ .disable = jz4770_otg_phy_disable,
+ .is_enabled = jz4770_otg_phy_is_enabled,
+};
+
+static const s8 pll_od_encoding[8] = {
+ 0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
+};
+
+static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
+
+ /* External clocks */
+
+ [JZ4770_CLK_EXT] = { "ext", CGU_CLK_EXT },
+ [JZ4770_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },
+
+ /* PLLs */
+
+ [JZ4770_CLK_PLL0] = {
+ "pll0", CGU_CLK_PLL,
+ .parents = { JZ4770_CLK_EXT },
+ .pll = {
+ .reg = CGU_REG_CPPCR0,
+ .m_shift = 24,
+ .m_bits = 7,
+ .m_offset = 1,
+ .n_shift = 18,
+ .n_bits = 5,
+ .n_offset = 1,
+ .od_shift = 16,
+ .od_bits = 2,
+ .od_max = 8,
+ .od_encoding = pll_od_encoding,
+ .bypass_bit = 9,
+ .enable_bit = 8,
+ .stable_bit = 10,
+ },
+ },
+
+ [JZ4770_CLK_PLL1] = {
+ /* TODO: PLL1 can depend on PLL0 */
+ "pll1", CGU_CLK_PLL,
+ .parents = { JZ4770_CLK_EXT },
+ .pll = {
+ .reg = CGU_REG_CPPCR1,
+ .m_shift = 24,
+ .m_bits = 7,
+ .m_offset = 1,
+ .n_shift = 18,
+ .n_bits = 5,
+ .n_offset = 1,
+ .od_shift = 16,
+ .od_bits = 2,
+ .od_max = 8,
+ .od_encoding = pll_od_encoding,
+ .enable_bit = 7,
+ .stable_bit = 6,
+ .no_bypass_bit = true,
+ },
+ },
+
+ /* Main clocks */
+
+ [JZ4770_CLK_CCLK] = {
+ "cclk", CGU_CLK_DIV,
+ .parents = { JZ4770_CLK_PLL0, },
+ .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 },
+ },
+ [JZ4770_CLK_H0CLK] = {
+ "h0clk", CGU_CLK_DIV,
+ .parents = { JZ4770_CLK_PLL0, },
+ .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 },
+ },
+ [JZ4770_CLK_H1CLK] = {
+ "h1clk", CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_PLL0, },
+ .div = { CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1 },
+ .gate = { CGU_REG_LCR, 30 },
+ },
+ [JZ4770_CLK_H2CLK] = {
+ "h2clk", CGU_CLK_DIV,
+ .parents = { JZ4770_CLK_PLL0, },
+ .div = { CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1 },
+ },
+ [JZ4770_CLK_C1CLK] = {
+ "c1clk", CGU_CLK_DIV,
+ .parents = { JZ4770_CLK_PLL0, },
+ .div = { CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1 },
+ },
+ [JZ4770_CLK_PCLK] = {
+ "pclk", CGU_CLK_DIV,
+ .parents = { JZ4770_CLK_PLL0, },
+ .div = { CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1 },
+ },
+
+ /* Those divided clocks can connect to PLL0 or PLL1 */
+
+ [JZ4770_CLK_MMC0_MUX] = {
+ "mmc0_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_MSC0CDR, 30, 1 },
+ .div = { CGU_REG_MSC0CDR, 0, 1, 7, -1, -1, 31 },
+ .gate = { CGU_REG_MSC0CDR, 31 },
+ },
+ [JZ4770_CLK_MMC1_MUX] = {
+ "mmc1_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_MSC1CDR, 30, 1 },
+ .div = { CGU_REG_MSC1CDR, 0, 1, 7, -1, -1, 31 },
+ .gate = { CGU_REG_MSC1CDR, 31 },
+ },
+ [JZ4770_CLK_MMC2_MUX] = {
+ "mmc2_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_MSC2CDR, 30, 1 },
+ .div = { CGU_REG_MSC2CDR, 0, 1, 7, -1, -1, 31 },
+ .gate = { CGU_REG_MSC2CDR, 31 },
+ },
+ [JZ4770_CLK_CIM] = {
+ "cim", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_CIMCDR, 31, 1 },
+ .div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 26 },
+ },
+ [JZ4770_CLK_UHC] = {
+ "uhc", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_UHCCDR, 29, 1 },
+ .div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 24 },
+ },
+ [JZ4770_CLK_GPU] = {
+ "gpu", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, -1 },
+ .mux = { CGU_REG_GPUCDR, 31, 1 },
+ .div = { CGU_REG_GPUCDR, 0, 1, 3, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR1, 9 },
+ },
+ [JZ4770_CLK_BCH] = {
+ "bch", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_BCHCDR, 31, 1 },
+ .div = { CGU_REG_BCHCDR, 0, 1, 3, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 1 },
+ },
+ [JZ4770_CLK_LPCLK_MUX] = {
+ "lpclk", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_LPCDR, 29, 1 },
+ .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 28 },
+ },
+ [JZ4770_CLK_GPS] = {
+ "gps", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_GPSCDR, 31, 1 },
+ .div = { CGU_REG_GPSCDR, 0, 1, 4, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 22 },
+ },
+
+ /* Those divided clocks can connect to EXT, PLL0 or PLL1 */
+
+ [JZ4770_CLK_SSI_MUX] = {
+ "ssi_mux", CGU_CLK_DIV | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_EXT, -1,
+ JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
+ .mux = { CGU_REG_SSICDR, 30, 2 },
+ .div = { CGU_REG_SSICDR, 0, 1, 6, -1, -1, -1 },
+ },
+ [JZ4770_CLK_PCM_MUX] = {
+ "pcm_mux", CGU_CLK_DIV | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_EXT, -1,
+ JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
+ .mux = { CGU_REG_PCMCDR, 30, 2 },
+ .div = { CGU_REG_PCMCDR, 0, 1, 9, -1, -1, -1 },
+ },
+ [JZ4770_CLK_I2S] = {
+ "i2s", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_EXT, -1,
+ JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
+ .mux = { CGU_REG_I2SCDR, 30, 2 },
+ .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR1, 13 },
+ },
+ [JZ4770_CLK_OTG] = {
+ "usb", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_EXT, -1,
+ JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
+ .mux = { CGU_REG_USBCDR, 30, 2 },
+ .div = { CGU_REG_USBCDR, 0, 1, 8, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 2 },
+ },
+
+ /* Gate-only clocks */
+
+ [JZ4770_CLK_SSI0] = {
+ "ssi0", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_SSI_MUX, },
+ .gate = { CGU_REG_CLKGR0, 4 },
+ },
+ [JZ4770_CLK_SSI1] = {
+ "ssi1", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_SSI_MUX, },
+ .gate = { CGU_REG_CLKGR0, 19 },
+ },
+ [JZ4770_CLK_SSI2] = {
+ "ssi2", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_SSI_MUX, },
+ .gate = { CGU_REG_CLKGR0, 20 },
+ },
+ [JZ4770_CLK_PCM0] = {
+ "pcm0", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_PCM_MUX, },
+ .gate = { CGU_REG_CLKGR1, 8 },
+ },
+ [JZ4770_CLK_PCM1] = {
+ "pcm1", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_PCM_MUX, },
+ .gate = { CGU_REG_CLKGR1, 10 },
+ },
+ [JZ4770_CLK_DMA] = {
+ "dma", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_H2CLK, },
+ .gate = { CGU_REG_CLKGR0, 21 },
+ },
+ [JZ4770_CLK_I2C0] = {
+ "i2c0", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 5 },
+ },
+ [JZ4770_CLK_I2C1] = {
+ "i2c1", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 6 },
+ },
+ [JZ4770_CLK_I2C2] = {
+ "i2c2", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR1, 15 },
+ },
+ [JZ4770_CLK_UART0] = {
+ "uart0", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 15 },
+ },
+ [JZ4770_CLK_UART1] = {
+ "uart1", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 16 },
+ },
+ [JZ4770_CLK_UART2] = {
+ "uart2", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 17 },
+ },
+ [JZ4770_CLK_UART3] = {
+ "uart3", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 18 },
+ },
+ [JZ4770_CLK_IPU] = {
+ "ipu", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_H0CLK, },
+ .gate = { CGU_REG_CLKGR0, 29 },
+ },
+ [JZ4770_CLK_ADC] = {
+ "adc", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 14 },
+ },
+ [JZ4770_CLK_AIC] = {
+ "aic", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 8 },
+ },
+ [JZ4770_CLK_AUX] = {
+ "aux", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_C1CLK, },
+ .gate = { CGU_REG_CLKGR1, 14 },
+ },
+ [JZ4770_CLK_VPU] = {
+ "vpu", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_H1CLK, },
+ .gate = { CGU_REG_CLKGR1, 7 },
+ },
+ [JZ4770_CLK_MMC0] = {
+ "mmc0", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_MMC0_MUX, },
+ .gate = { CGU_REG_CLKGR0, 3 },
+ },
+ [JZ4770_CLK_MMC1] = {
+ "mmc1", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_MMC1_MUX, },
+ .gate = { CGU_REG_CLKGR0, 11 },
+ },
+ [JZ4770_CLK_MMC2] = {
+ "mmc2", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_MMC2_MUX, },
+ .gate = { CGU_REG_CLKGR0, 12 },
+ },
+
+ /* Custom clocks */
+
+ [JZ4770_CLK_UHC_PHY] = {
+ "uhc_phy", CGU_CLK_CUSTOM,
+ .parents = { JZ4770_CLK_UHC, -1, -1, -1 },
+ .custom = { &jz4770_uhc_phy_ops },
+ },
+ [JZ4770_CLK_OTG_PHY] = {
+ "usb_phy", CGU_CLK_CUSTOM,
+ .parents = { JZ4770_CLK_OTG, -1, -1, -1 },
+ .custom = { &jz4770_otg_phy_ops },
+ },
+
+ [JZ4770_CLK_EXT512] = {
+ "ext/512", CGU_CLK_FIXDIV,
+ .parents = { JZ4770_CLK_EXT },
+ .fixdiv = { 512 },
+ },
+
+ [JZ4770_CLK_RTC] = {
+ "rtc", CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_EXT512, JZ4770_CLK_OSC32K, },
+ .mux = { CGU_REG_OPCR, 2, 1},
+ },
+};
+
+#if IS_ENABLED(CONFIG_PM_SLEEP)
+static int jz4770_cgu_pm_suspend(void)
+{
+ u32 val;
+
+ val = readl(cgu->base + CGU_REG_LCR);
+ writel(val | LCR_LPM, cgu->base + CGU_REG_LCR);
+ return 0;
+}
+
+static void jz4770_cgu_pm_resume(void)
+{
+ u32 val;
+
+ val = readl(cgu->base + CGU_REG_LCR);
+ writel(val & ~LCR_LPM, cgu->base + CGU_REG_LCR);
+}
+
+static struct syscore_ops jz4770_cgu_pm_ops = {
+ .suspend = jz4770_cgu_pm_suspend,
+ .resume = jz4770_cgu_pm_resume,
+};
+#endif /* CONFIG_PM_SLEEP */
+
+static void __init jz4770_cgu_init(struct device_node *np)
+{
+ int retval;
+
+ cgu = ingenic_cgu_new(jz4770_cgu_clocks,
+ ARRAY_SIZE(jz4770_cgu_clocks), np);
+ if (!cgu)
+ pr_err("%s: failed to initialise CGU\n", __func__);
+
+ retval = ingenic_cgu_register_clocks(cgu);
+ if (retval)
+ pr_err("%s: failed to register CGU Clocks\n", __func__);
+
+#if IS_ENABLED(CONFIG_PM_SLEEP)
+ register_syscore_ops(&jz4770_cgu_pm_ops);
+#endif
+}
+
+/* We only probe via devicetree, no need for a platform driver */
+CLK_OF_DECLARE(jz4770_cgu, "ingenic,jz4770-cgu", jz4770_cgu_init);
diff --git a/include/dt-bindings/clock/jz4770-cgu.h b/include/dt-bindings/clock/jz4770-cgu.h
new file mode 100644
index 000000000000..54b8b2ae4a73
--- /dev/null
+++ b/include/dt-bindings/clock/jz4770-cgu.h
@@ -0,0 +1,57 @@
+/*
+ * This header provides clock numbers for the ingenic,jz4770-cgu DT binding.
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_JZ4770_CGU_H__
+#define __DT_BINDINGS_CLOCK_JZ4770_CGU_H__
+
+#define JZ4770_CLK_EXT 0
+#define JZ4770_CLK_OSC32K 1
+#define JZ4770_CLK_PLL0 2
+#define JZ4770_CLK_PLL1 3
+#define JZ4770_CLK_CCLK 4
+#define JZ4770_CLK_H0CLK 5
+#define JZ4770_CLK_H1CLK 6
+#define JZ4770_CLK_H2CLK 7
+#define JZ4770_CLK_C1CLK 8
+#define JZ4770_CLK_PCLK 9
+#define JZ4770_CLK_MMC0_MUX 10
+#define JZ4770_CLK_MMC0 11
+#define JZ4770_CLK_MMC1_MUX 12
+#define JZ4770_CLK_MMC1 13
+#define JZ4770_CLK_MMC2_MUX 14
+#define JZ4770_CLK_MMC2 15
+#define JZ4770_CLK_CIM 16
+#define JZ4770_CLK_UHC 17
+#define JZ4770_CLK_GPU 18
+#define JZ4770_CLK_BCH 19
+#define JZ4770_CLK_LPCLK_MUX 20
+#define JZ4770_CLK_GPS 21
+#define JZ4770_CLK_SSI_MUX 22
+#define JZ4770_CLK_PCM_MUX 23
+#define JZ4770_CLK_I2S 24
+#define JZ4770_CLK_OTG 25
+#define JZ4770_CLK_SSI0 26
+#define JZ4770_CLK_SSI1 27
+#define JZ4770_CLK_SSI2 28
+#define JZ4770_CLK_PCM0 29
+#define JZ4770_CLK_PCM1 30
+#define JZ4770_CLK_DMA 31
+#define JZ4770_CLK_I2C0 32
+#define JZ4770_CLK_I2C1 33
+#define JZ4770_CLK_I2C2 34
+#define JZ4770_CLK_UART0 35
+#define JZ4770_CLK_UART1 36
+#define JZ4770_CLK_UART2 37
+#define JZ4770_CLK_UART3 38
+#define JZ4770_CLK_IPU 39
+#define JZ4770_CLK_ADC 40
+#define JZ4770_CLK_AIC 41
+#define JZ4770_CLK_AUX 42
+#define JZ4770_CLK_VPU 43
+#define JZ4770_CLK_UHC_PHY 44
+#define JZ4770_CLK_OTG_PHY 45
+#define JZ4770_CLK_EXT512 46
+#define JZ4770_CLK_RTC 47
+
+#endif /* __DT_BINDINGS_CLOCK_JZ4770_CGU_H__ */
--
2.11.0

2017-06-20 15:21:13

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v2 10/17] MIPS: ingenic: Use common cmdline handling code

From: Paul Burton <[email protected]>

jz4740_init_cmdline appends all arguments from argv (in fw_arg1) to
arcs_cmdline, up to argc (in fw_arg0). The common code in
fw_init_cmdline will do the exact same thing when run on a system where
fw_arg0 isn't a pointer to kseg0 (it'll also set _fw_envp but we don't
use it). Remove the custom implementation & use the generic code.

Signed-off-by: Paul Burton <[email protected]>
---
arch/mips/jz4740/prom.c | 24 ++----------------------
1 file changed, 2 insertions(+), 22 deletions(-)

v2: No change

diff --git a/arch/mips/jz4740/prom.c b/arch/mips/jz4740/prom.c
index 47e857194ce6..a62dd8e6ecf9 100644
--- a/arch/mips/jz4740/prom.c
+++ b/arch/mips/jz4740/prom.c
@@ -20,33 +20,13 @@
#include <linux/serial_reg.h>

#include <asm/bootinfo.h>
+#include <asm/fw/fw.h>
#include <asm/mach-jz4740/base.h>

-static __init void jz4740_init_cmdline(int argc, char *argv[])
-{
- unsigned int count = COMMAND_LINE_SIZE - 1;
- int i;
- char *dst = &(arcs_cmdline[0]);
- char *src;
-
- for (i = 1; i < argc && count; ++i) {
- src = argv[i];
- while (*src && count) {
- *dst++ = *src++;
- --count;
- }
- *dst++ = ' ';
- }
- if (i > 1)
- --dst;
-
- *dst = 0;
-}
-
void __init prom_init(void)
{
- jz4740_init_cmdline((int)fw_arg0, (char **)fw_arg1);
mips_machtype = MACH_INGENIC_JZ4740;
+ fw_init_cmdline();
}

void __init prom_free_prom_memory(void)
--
2.11.0

2017-06-20 15:21:30

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v2 08/17] serial: 8250_ingenic: Parse earlycon options

In the devicetree, it is possible to specify the baudrate, parity,
bits, flow of the early console, by passing a configuration string like
this:

aliases {
serial0 = &uart0;
};

chosen {
stdout-path = "serial0:57600n8";
};

This, for instance, will configure the early console for a baudrate of
57600 bps, no parity, and 8 bits per baud.

This patches implements parsing of this configuration string in the
8250_ingenic driver, which previously just ignored it.

Signed-off-by: Paul Cercueil <[email protected]>
---
drivers/tty/serial/8250/8250_ingenic.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)

v2: Don't create temp. buffer, now that uart_parse_options takes a const char*

diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c
index b31b2ca552d1..be4a07a24342 100644
--- a/drivers/tty/serial/8250/8250_ingenic.c
+++ b/drivers/tty/serial/8250/8250_ingenic.c
@@ -99,14 +99,22 @@ static int __init ingenic_early_console_setup(struct earlycon_device *dev,
const char *opt)
{
struct uart_port *port = &dev->port;
- unsigned int baud, divisor;
+ unsigned int divisor;
+ int baud = 115200;

if (!dev->port.membase)
return -ENODEV;

+ if (opt) {
+ unsigned int parity, bits, flow; /* unused for now */
+
+ uart_parse_options(opt, &baud, &parity, &bits, &flow);
+ }
+
ingenic_early_console_setup_clock(dev);

- baud = dev->baud ?: 115200;
+ if (dev->baud)
+ baud = dev->baud;
divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud);

early_out(port, UART_IER, 0);
--
2.11.0

2017-06-20 15:21:50

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v2 07/17] serial: 8250_ingenic: Add support for the JZ4770 SoC

The JZ4770 SoC's UART is no different from the other JZ SoCs, so this
commit simply adds the ingenic,jz4770-uart compatible string.

Signed-off-by: Paul Cercueil <[email protected]>
Acked-by: Rob Herring <[email protected]>
---
Documentation/devicetree/bindings/serial/ingenic,uart.txt | 8 ++++++--
drivers/tty/serial/8250/8250_ingenic.c | 5 +++++
2 files changed, 11 insertions(+), 2 deletions(-)

v2: List one compatible entry per line

diff --git a/Documentation/devicetree/bindings/serial/ingenic,uart.txt b/Documentation/devicetree/bindings/serial/ingenic,uart.txt
index 02cb7fe59cb7..c3c6406d5cfe 100644
--- a/Documentation/devicetree/bindings/serial/ingenic,uart.txt
+++ b/Documentation/devicetree/bindings/serial/ingenic,uart.txt
@@ -1,8 +1,12 @@
* Ingenic SoC UART

Required properties:
-- compatible : "ingenic,jz4740-uart", "ingenic,jz4760-uart",
- "ingenic,jz4775-uart" or "ingenic,jz4780-uart"
+- compatible : One of:
+ - "ingenic,jz4740-uart",
+ - "ingenic,jz4760-uart",
+ - "ingenic,jz4770-uart",
+ - "ingenic,jz4775-uart",
+ - "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.
diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c
index 4d9dc10e265c..b31b2ca552d1 100644
--- a/drivers/tty/serial/8250/8250_ingenic.c
+++ b/drivers/tty/serial/8250/8250_ingenic.c
@@ -133,6 +133,10 @@ EARLYCON_DECLARE(jz4740_uart, ingenic_early_console_setup);
OF_EARLYCON_DECLARE(jz4740_uart, "ingenic,jz4740-uart",
ingenic_early_console_setup);

+EARLYCON_DECLARE(jz4770_uart, ingenic_early_console_setup);
+OF_EARLYCON_DECLARE(jz4770_uart, "ingenic,jz4770-uart",
+ ingenic_early_console_setup);
+
EARLYCON_DECLARE(jz4775_uart, ingenic_early_console_setup);
OF_EARLYCON_DECLARE(jz4775_uart, "ingenic,jz4775-uart",
ingenic_early_console_setup);
@@ -327,6 +331,7 @@ static const struct ingenic_uart_config jz4780_uart_config = {
static const struct of_device_id of_match[] = {
{ .compatible = "ingenic,jz4740-uart", .data = &jz4740_uart_config },
{ .compatible = "ingenic,jz4760-uart", .data = &jz4760_uart_config },
+ { .compatible = "ingenic,jz4770-uart", .data = &jz4760_uart_config },
{ .compatible = "ingenic,jz4775-uart", .data = &jz4760_uart_config },
{ .compatible = "ingenic,jz4780-uart", .data = &jz4780_uart_config },
{ /* sentinel */ }
--
2.11.0

2017-06-20 15:22:04

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v2 06/17] serial: core: Make uart_parse_options take const char* argument

The pointed string is never modified from within uart_parse_options, so
it should be marked as const in the function prototype.

Signed-off-by: Paul Cercueil <[email protected]>
---
drivers/tty/serial/serial_core.c | 5 +++--
include/linux/serial_core.h | 2 +-
2 files changed, 4 insertions(+), 3 deletions(-)

v2: New patch in this series

diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 13bfd5dcffce..95d3770bdb37 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -1954,9 +1954,10 @@ EXPORT_SYMBOL_GPL(uart_parse_earlycon);
* eg: 115200n8r
*/
void
-uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow)
+uart_parse_options(const char *options, int *baud, int *parity,
+ int *bits, int *flow)
{
- char *s = options;
+ const char *s = options;

*baud = simple_strtoul(s, NULL, 10);
while (*s >= '0' && *s <= '9')
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 64d892f1e5cd..67f88fb53195 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -386,7 +386,7 @@ struct uart_port *uart_get_console(struct uart_port *ports, int nr,
struct console *c);
int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr,
char **options);
-void uart_parse_options(char *options, int *baud, int *parity, int *bits,
+void uart_parse_options(const char *options, int *baud, int *parity, int *bits,
int *flow);
int uart_set_options(struct uart_port *port, struct console *co, int baud,
int parity, int bits, int flow);
--
2.11.0

2017-06-20 15:22:18

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v2 04/17] clk: ingenic: Add code to enable/disable PLLs

This commit permits the PLLs to be dynamically enabled and disabled when
their children clocks are enabled and disabled.

Signed-off-by: Paul Cercueil <[email protected]>
---
drivers/clk/ingenic/cgu.c | 89 +++++++++++++++++++++++++++++++++++++++--------
1 file changed, 74 insertions(+), 15 deletions(-)

v2: No change

diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
index 75b083ba294c..08613b803b14 100644
--- a/drivers/clk/ingenic/cgu.c
+++ b/drivers/clk/ingenic/cgu.c
@@ -107,9 +107,6 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
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;
@@ -153,17 +150,25 @@ ingenic_pll_calc(const struct ingenic_cgu_clk_info *clk_info,
return div_u64((u64)parent_rate * m, n * od);
}

-static long
-ingenic_pll_round_rate(struct clk_hw *hw, unsigned long req_rate,
- unsigned long *prate)
+static inline const struct ingenic_cgu_clk_info *to_clk_info(
+ struct ingenic_clk *ingenic_clk)
{
- struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
struct ingenic_cgu *cgu = ingenic_clk->cgu;
const struct ingenic_cgu_clk_info *clk_info;

clk_info = &cgu->clock_info[ingenic_clk->idx];
BUG_ON(clk_info->type != CGU_CLK_PLL);

+ return clk_info;
+}
+
+static long
+ingenic_pll_round_rate(struct clk_hw *hw, unsigned long req_rate,
+ unsigned long *prate)
+{
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
+ const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
+
return ingenic_pll_calc(clk_info, req_rate, *prate, NULL, NULL, NULL);
}

@@ -171,19 +176,14 @@ static int
ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
unsigned long parent_rate)
{
- const unsigned timeout = 100;
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
struct ingenic_cgu *cgu = ingenic_clk->cgu;
- const struct ingenic_cgu_clk_info *clk_info;
- const struct ingenic_cgu_pll_info *pll_info;
+ const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
+ const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
unsigned long rate, flags;
- unsigned m, n, od, i;
+ unsigned int m, n, od;
u32 ctl;

- clk_info = &cgu->clock_info[ingenic_clk->idx];
- BUG_ON(clk_info->type != CGU_CLK_PLL);
- pll_info = &clk_info->pll;
-
rate = ingenic_pll_calc(clk_info, req_rate, parent_rate,
&m, &n, &od);
if (rate != req_rate)
@@ -202,6 +202,26 @@ ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
ctl &= ~(GENMASK(pll_info->od_bits - 1, 0) << pll_info->od_shift);
ctl |= pll_info->od_encoding[od - 1] << pll_info->od_shift;

+ writel(ctl, cgu->base + pll_info->reg);
+ spin_unlock_irqrestore(&cgu->lock, flags);
+
+ return 0;
+}
+
+static int ingenic_pll_enable(struct clk_hw *hw)
+{
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
+ struct ingenic_cgu *cgu = ingenic_clk->cgu;
+ const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
+ const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
+ const unsigned int timeout = 100;
+ unsigned long flags;
+ unsigned int i;
+ u32 ctl;
+
+ spin_lock_irqsave(&cgu->lock, flags);
+ ctl = readl(cgu->base + pll_info->reg);
+
ctl &= ~BIT(pll_info->bypass_bit);
ctl |= BIT(pll_info->enable_bit);

@@ -223,10 +243,48 @@ ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
return 0;
}

+static void ingenic_pll_disable(struct clk_hw *hw)
+{
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
+ struct ingenic_cgu *cgu = ingenic_clk->cgu;
+ const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
+ const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
+ unsigned long flags;
+ u32 ctl;
+
+ spin_lock_irqsave(&cgu->lock, flags);
+ ctl = readl(cgu->base + pll_info->reg);
+
+ ctl &= ~BIT(pll_info->enable_bit);
+
+ writel(ctl, cgu->base + pll_info->reg);
+ spin_unlock_irqrestore(&cgu->lock, flags);
+}
+
+static int ingenic_pll_is_enabled(struct clk_hw *hw)
+{
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
+ struct ingenic_cgu *cgu = ingenic_clk->cgu;
+ const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
+ const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
+ unsigned long flags;
+ u32 ctl;
+
+ spin_lock_irqsave(&cgu->lock, flags);
+ ctl = readl(cgu->base + pll_info->reg);
+ spin_unlock_irqrestore(&cgu->lock, flags);
+
+ return !!(ctl & BIT(pll_info->enable_bit));
+}
+
static const struct clk_ops ingenic_pll_ops = {
.recalc_rate = ingenic_pll_recalc_rate,
.round_rate = ingenic_pll_round_rate,
.set_rate = ingenic_pll_set_rate,
+
+ .enable = ingenic_pll_enable,
+ .disable = ingenic_pll_disable,
+ .is_enabled = ingenic_pll_is_enabled,
};

/*
@@ -601,6 +659,7 @@ static int ingenic_register_clock(struct ingenic_cgu *cgu, unsigned idx)
}
} else if (caps & CGU_CLK_PLL) {
clk_init.ops = &ingenic_pll_ops;
+ clk_init.flags |= CLK_SET_RATE_GATE;

caps &= ~CGU_CLK_PLL;

--
2.11.0

2017-06-20 15:22:38

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v2 03/17] clk: ingenic: support PLLs with no bypass bit

The second PLL of the JZ4770 does not have a bypass bit.
This commit makes it possible to support it with the current common CGU
code.

Signed-off-by: Paul Cercueil <[email protected]>
---
drivers/clk/ingenic/cgu.c | 3 ++-
drivers/clk/ingenic/cgu.h | 2 ++
2 files changed, 4 insertions(+), 1 deletion(-)

v2: No change

diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
index eb9002ccf3fc..75b083ba294c 100644
--- a/drivers/clk/ingenic/cgu.c
+++ b/drivers/clk/ingenic/cgu.c
@@ -100,7 +100,8 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
n += pll_info->n_offset;
od_enc = ctl >> pll_info->od_shift;
od_enc &= GENMASK(pll_info->od_bits - 1, 0);
- bypass = !!(ctl & BIT(pll_info->bypass_bit));
+ bypass = !pll_info->no_bypass_bit &&
+ !!(ctl & BIT(pll_info->bypass_bit));
enable = !!(ctl & BIT(pll_info->enable_bit));

if (bypass)
diff --git a/drivers/clk/ingenic/cgu.h b/drivers/clk/ingenic/cgu.h
index da448b0cac18..21420b455985 100644
--- a/drivers/clk/ingenic/cgu.h
+++ b/drivers/clk/ingenic/cgu.h
@@ -48,6 +48,7 @@
* @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
+ * @no_bypass_bit: if set, the PLL has no bypass functionality
*/
struct ingenic_cgu_pll_info {
unsigned reg;
@@ -58,6 +59,7 @@ struct ingenic_cgu_pll_info {
u8 bypass_bit;
u8 enable_bit;
u8 stable_bit;
+ bool no_bypass_bit;
};

/**
--
2.11.0

2017-06-20 15:19:10

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v2 01/17] clk: ingenic: Use const pointer to clk_ops in struct

The CGU common code does not modify the pointed clk_ops structure, so it
should be marked as const.

Signed-off-by: Paul Cercueil <[email protected]>
---
drivers/clk/ingenic/cgu.h | 2 +-
drivers/clk/ingenic/jz4780-cgu.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)

v2: New patch in this series

diff --git a/drivers/clk/ingenic/cgu.h b/drivers/clk/ingenic/cgu.h
index 09700b2c555d..da448b0cac18 100644
--- a/drivers/clk/ingenic/cgu.h
+++ b/drivers/clk/ingenic/cgu.h
@@ -120,7 +120,7 @@ struct ingenic_cgu_gate_info {
* @clk_ops: custom clock operation callbacks
*/
struct ingenic_cgu_custom_info {
- struct clk_ops *clk_ops;
+ const struct clk_ops *clk_ops;
};

/**
diff --git a/drivers/clk/ingenic/jz4780-cgu.c b/drivers/clk/ingenic/jz4780-cgu.c
index b35d6d9dd5aa..a21698fb202c 100644
--- a/drivers/clk/ingenic/jz4780-cgu.c
+++ b/drivers/clk/ingenic/jz4780-cgu.c
@@ -203,7 +203,7 @@ static int jz4780_otg_phy_set_rate(struct clk_hw *hw, unsigned long req_rate,
return 0;
}

-static struct clk_ops jz4780_otg_phy_ops = {
+static const struct clk_ops jz4780_otg_phy_ops = {
.get_parent = jz4780_otg_phy_get_parent,
.set_parent = jz4780_otg_phy_set_parent,

--
2.11.0

2017-06-21 21:50:44

by Stephen Boyd

[permalink] [raw]
Subject: Re: [PATCH v2 01/17] clk: ingenic: Use const pointer to clk_ops in struct

On 06/20, Paul Cercueil wrote:
> The CGU common code does not modify the pointed clk_ops structure, so it
> should be marked as const.
>
> Signed-off-by: Paul Cercueil <[email protected]>
> ---

How did you want to merge this series? I can ack clk patches if
you like, or apply the clk patches to the clk tree.

--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

2017-06-22 07:21:08

by Marcin Nowakowski

[permalink] [raw]
Subject: Re: [PATCH v2 15/17] MIPS: JZ4770: Workaround for corrupted DMA transfers

Hi Paul, Maarten,

On 20.06.2017 17:18, Paul Cercueil wrote:
> From: Maarten ter Huurne <[email protected]>
>
> We have seen MMC DMA transfers read corrupted data from SDRAM when
> a burst interval ends at physical address 0x10000000. To avoid this
> problem, we remove the final page of low memory from the memory map.
>
> Signed-off-by: Maarten ter Huurne <[email protected]>
> ---
> arch/mips/jz4740/setup.c | 24 ++++++++++++++++++++++++
> arch/mips/kernel/setup.c | 8 ++++++++
> 2 files changed, 32 insertions(+)
>
> v2: No change
>
> diff --git a/arch/mips/jz4740/setup.c b/arch/mips/jz4740/setup.c
> index afd84ee966e8..6948b133a15d 100644
> --- a/arch/mips/jz4740/setup.c
> +++ b/arch/mips/jz4740/setup.c
> @@ -23,6 +23,7 @@
>
> #include <asm/bootinfo.h>
> #include <asm/mips_machine.h>
> +#include <asm/page.h>
> #include <asm/prom.h>
>
> #include <asm/mach-jz4740/base.h>
> @@ -102,6 +103,29 @@ void __init arch_init_irq(void)
> irqchip_init();
> }
>
> +/*
> + * We have seen MMC DMA transfers read corrupted data from SDRAM when a burst
> + * interval ends at physical address 0x10000000. To avoid this problem, we
> + * remove the final page of low memory from the memory map.
> + */
> +void __init jz4770_reserve_unsafe_for_dma(void)
> +{
> + int i;
> +
> + for (i = 0; i < boot_mem_map.nr_map; i++) {
> + struct boot_mem_map_entry *entry = boot_mem_map.map + i;
> +
> + if (entry->type != BOOT_MEM_RAM)
> + continue;
> +
> + if (entry->addr + entry->size != 0x10000000)
> + continue;
> +
> + entry->size -= PAGE_SIZE;
> + break;
> + }
> +}
> +
> static int __init jz4740_machine_setup(void)
> {
> mips_machine_setup();
> diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
> index 89785600fde4..cccfd7ba89fe 100644
> --- a/arch/mips/kernel/setup.c
> +++ b/arch/mips/kernel/setup.c
> @@ -838,6 +838,14 @@ static void __init arch_mem_init(char **cmdline_p)
>
> parse_early_param();
>
> +#ifdef CONFIG_MACH_JZ4770
> + if (current_cpu_type() == CPU_JZRISC &&
> + mips_machtype == MACH_INGENIC_JZ4770) {
> + extern void __init jz4770_reserve_unsafe_for_dma(void);
> + jz4770_reserve_unsafe_for_dma();
> + }
> +#endif
> +

This part doesn't look good in the platform-agnostic code ... is there a
reason why you wouldn't do that from within plat_mem_setup()?


> if (usermem) {
> pr_info("User-defined physical RAM map:\n");
> print_memory_map();
>


Marcin

2017-06-26 13:38:05

by Paul Cercueil

[permalink] [raw]
Subject: Re: [PATCH v2 15/17] MIPS: JZ4770: Workaround for corrupted DMA transfers

Hi,

Le 2017-06-22 09:21, Marcin Nowakowski a écrit :
> Hi Paul, Maarten,
>
> On 20.06.2017 17:18, Paul Cercueil wrote:
>> From: Maarten ter Huurne <[email protected]>
>>
>> We have seen MMC DMA transfers read corrupted data from SDRAM when
>> a burst interval ends at physical address 0x10000000. To avoid this
>> problem, we remove the final page of low memory from the memory map.
>>
>> Signed-off-by: Maarten ter Huurne <[email protected]>
>> ---
>> arch/mips/jz4740/setup.c | 24 ++++++++++++++++++++++++
>> arch/mips/kernel/setup.c | 8 ++++++++
>> 2 files changed, 32 insertions(+)
>>
>> v2: No change
>>
>> diff --git a/arch/mips/jz4740/setup.c b/arch/mips/jz4740/setup.c
>> index afd84ee966e8..6948b133a15d 100644
>> --- a/arch/mips/jz4740/setup.c
>> +++ b/arch/mips/jz4740/setup.c
>> @@ -23,6 +23,7 @@
>> #include <asm/bootinfo.h>
>> #include <asm/mips_machine.h>
>> +#include <asm/page.h>
>> #include <asm/prom.h>
>> #include <asm/mach-jz4740/base.h>
>> @@ -102,6 +103,29 @@ void __init arch_init_irq(void)
>> irqchip_init();
>> }
>> +/*
>> + * We have seen MMC DMA transfers read corrupted data from SDRAM when
>> a burst
>> + * interval ends at physical address 0x10000000. To avoid this
>> problem, we
>> + * remove the final page of low memory from the memory map.
>> + */
>> +void __init jz4770_reserve_unsafe_for_dma(void)
>> +{
>> + int i;
>> +
>> + for (i = 0; i < boot_mem_map.nr_map; i++) {
>> + struct boot_mem_map_entry *entry = boot_mem_map.map + i;
>> +
>> + if (entry->type != BOOT_MEM_RAM)
>> + continue;
>> +
>> + if (entry->addr + entry->size != 0x10000000)
>> + continue;
>> +
>> + entry->size -= PAGE_SIZE;
>> + break;
>> + }
>> +}
>> +
>> static int __init jz4740_machine_setup(void)
>> {
>> mips_machine_setup();
>> diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
>> index 89785600fde4..cccfd7ba89fe 100644
>> --- a/arch/mips/kernel/setup.c
>> +++ b/arch/mips/kernel/setup.c
>> @@ -838,6 +838,14 @@ static void __init arch_mem_init(char
>> **cmdline_p)
>> parse_early_param();
>> +#ifdef CONFIG_MACH_JZ4770
>> + if (current_cpu_type() == CPU_JZRISC &&
>> + mips_machtype == MACH_INGENIC_JZ4770) {
>> + extern void __init jz4770_reserve_unsafe_for_dma(void);
>> + jz4770_reserve_unsafe_for_dma();
>> + }
>> +#endif
>> +
>
> This part doesn't look good in the platform-agnostic code ... is there
> a reason why you wouldn't do that from within plat_mem_setup()?
>

I agree, but, doing it in plat_mem_setup() is too early, as the 'boot
mem map' hasn't been initialized yet then...

>> if (usermem) {
>> pr_info("User-defined physical RAM map:\n");
>> print_memory_map();
>>
>
>
> Marcin

2017-06-26 13:43:32

by Paul Cercueil

[permalink] [raw]
Subject: Re: [PATCH v2 01/17] clk: ingenic: Use const pointer to clk_ops in struct

Hi,

Le 2017-06-21 23:50, Stephen Boyd a écrit :
> On 06/20, Paul Cercueil wrote:
>> The CGU common code does not modify the pointed clk_ops structure, so
>> it
>> should be marked as const.
>>
>> Signed-off-by: Paul Cercueil <[email protected]>
>> ---
>
> How did you want to merge this series? I can ack clk patches if
> you like, or apply the clk patches to the clk tree.

The clk patches refer to CONFIG_MACH_JZ4770 in the Kconfig, so they
indirectly depend on the other patches. I think it's better that you ack
them then.

2017-06-26 13:50:17

by Paul Cercueil

[permalink] [raw]
Subject: Re: [PATCH 04/15] clk: Add Ingenic jz4770 CGU driver

Hi,

Le 2017-06-07 22:59, Stephen Boyd a écrit :
> On 06/07, Paul Cercueil wrote:
>> Add support for the clocks provided by the CGU in the Ingenic JZ4770
>> SoC.
>>
>> Signed-off-by: Paul Cercueil <[email protected]>
>> Signed-off-by: Maarten ter Huurne <[email protected]>

[...]

>> diff --git a/include/dt-bindings/clock/jz4770-cgu.h
>> b/include/dt-bindings/clock/jz4770-cgu.h
>> new file mode 100644
>> index 000000000000..54b8b2ae4a73
>> --- /dev/null
>> +++ b/include/dt-bindings/clock/jz4770-cgu.h
>
> Can you split this file off into a different patch? That way clk
> tree can apply clk patches on top of a stable branch where this
> file lives by itself.

Oops, I forgot that in the v2.

The jz4770-cgu.c file includes and uses
<dt-bindings/clock/jz4770-cgu.h>, so I don't think
it would make sense to split it, since it wouldn't compile without it.

2017-06-26 22:57:30

by Stephen Boyd

[permalink] [raw]
Subject: Re: [PATCH 04/15] clk: Add Ingenic jz4770 CGU driver

On 06/26, Paul Cercueil wrote:
> Hi,
>
> Le 2017-06-07 22:59, Stephen Boyd a ?crit?:
> >On 06/07, Paul Cercueil wrote:
> >>Add support for the clocks provided by the CGU in the Ingenic JZ4770
> >>SoC.
> >>
> >>Signed-off-by: Paul Cercueil <[email protected]>
> >>Signed-off-by: Maarten ter Huurne <[email protected]>
>
> [...]
>
> >>diff --git a/include/dt-bindings/clock/jz4770-cgu.h
> >>b/include/dt-bindings/clock/jz4770-cgu.h
> >>new file mode 100644
> >>index 000000000000..54b8b2ae4a73
> >>--- /dev/null
> >>+++ b/include/dt-bindings/clock/jz4770-cgu.h
> >
> >Can you split this file off into a different patch? That way clk
> >tree can apply clk patches on top of a stable branch where this
> >file lives by itself.
>
> Oops, I forgot that in the v2.
>
> The jz4770-cgu.c file includes and uses
> <dt-bindings/clock/jz4770-cgu.h>, so I don't think
> it would make sense to split it, since it wouldn't compile without it.

I was suggesting this header file be a patch before the driver C
file patch, so that it would still compile. Does that change
anything?

--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

2017-07-02 16:30:26

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v3 00/18] JZ4770 support

This is the v3 of my patchset that introduces support for the jz4770 SoC
from Ingenic.

The only change in the whole series is that now
<dt-bindings/clock/jz4770-cgu.h> is introduced in a separate patch (05/18).

2017-07-02 16:30:31

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v3 04/18] clk: ingenic: Add code to enable/disable PLLs

This commit permits the PLLs to be dynamically enabled and disabled when
their children clocks are enabled and disabled.

Signed-off-by: Paul Cercueil <[email protected]>
---
drivers/clk/ingenic/cgu.c | 89 +++++++++++++++++++++++++++++++++++++++--------
1 file changed, 74 insertions(+), 15 deletions(-)

v2: No change
v3: No change

diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
index 75b083ba294c..08613b803b14 100644
--- a/drivers/clk/ingenic/cgu.c
+++ b/drivers/clk/ingenic/cgu.c
@@ -107,9 +107,6 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
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;
@@ -153,17 +150,25 @@ ingenic_pll_calc(const struct ingenic_cgu_clk_info *clk_info,
return div_u64((u64)parent_rate * m, n * od);
}

-static long
-ingenic_pll_round_rate(struct clk_hw *hw, unsigned long req_rate,
- unsigned long *prate)
+static inline const struct ingenic_cgu_clk_info *to_clk_info(
+ struct ingenic_clk *ingenic_clk)
{
- struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
struct ingenic_cgu *cgu = ingenic_clk->cgu;
const struct ingenic_cgu_clk_info *clk_info;

clk_info = &cgu->clock_info[ingenic_clk->idx];
BUG_ON(clk_info->type != CGU_CLK_PLL);

+ return clk_info;
+}
+
+static long
+ingenic_pll_round_rate(struct clk_hw *hw, unsigned long req_rate,
+ unsigned long *prate)
+{
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
+ const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
+
return ingenic_pll_calc(clk_info, req_rate, *prate, NULL, NULL, NULL);
}

@@ -171,19 +176,14 @@ static int
ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
unsigned long parent_rate)
{
- const unsigned timeout = 100;
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
struct ingenic_cgu *cgu = ingenic_clk->cgu;
- const struct ingenic_cgu_clk_info *clk_info;
- const struct ingenic_cgu_pll_info *pll_info;
+ const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
+ const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
unsigned long rate, flags;
- unsigned m, n, od, i;
+ unsigned int m, n, od;
u32 ctl;

- clk_info = &cgu->clock_info[ingenic_clk->idx];
- BUG_ON(clk_info->type != CGU_CLK_PLL);
- pll_info = &clk_info->pll;
-
rate = ingenic_pll_calc(clk_info, req_rate, parent_rate,
&m, &n, &od);
if (rate != req_rate)
@@ -202,6 +202,26 @@ ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
ctl &= ~(GENMASK(pll_info->od_bits - 1, 0) << pll_info->od_shift);
ctl |= pll_info->od_encoding[od - 1] << pll_info->od_shift;

+ writel(ctl, cgu->base + pll_info->reg);
+ spin_unlock_irqrestore(&cgu->lock, flags);
+
+ return 0;
+}
+
+static int ingenic_pll_enable(struct clk_hw *hw)
+{
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
+ struct ingenic_cgu *cgu = ingenic_clk->cgu;
+ const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
+ const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
+ const unsigned int timeout = 100;
+ unsigned long flags;
+ unsigned int i;
+ u32 ctl;
+
+ spin_lock_irqsave(&cgu->lock, flags);
+ ctl = readl(cgu->base + pll_info->reg);
+
ctl &= ~BIT(pll_info->bypass_bit);
ctl |= BIT(pll_info->enable_bit);

@@ -223,10 +243,48 @@ ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
return 0;
}

+static void ingenic_pll_disable(struct clk_hw *hw)
+{
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
+ struct ingenic_cgu *cgu = ingenic_clk->cgu;
+ const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
+ const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
+ unsigned long flags;
+ u32 ctl;
+
+ spin_lock_irqsave(&cgu->lock, flags);
+ ctl = readl(cgu->base + pll_info->reg);
+
+ ctl &= ~BIT(pll_info->enable_bit);
+
+ writel(ctl, cgu->base + pll_info->reg);
+ spin_unlock_irqrestore(&cgu->lock, flags);
+}
+
+static int ingenic_pll_is_enabled(struct clk_hw *hw)
+{
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
+ struct ingenic_cgu *cgu = ingenic_clk->cgu;
+ const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
+ const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
+ unsigned long flags;
+ u32 ctl;
+
+ spin_lock_irqsave(&cgu->lock, flags);
+ ctl = readl(cgu->base + pll_info->reg);
+ spin_unlock_irqrestore(&cgu->lock, flags);
+
+ return !!(ctl & BIT(pll_info->enable_bit));
+}
+
static const struct clk_ops ingenic_pll_ops = {
.recalc_rate = ingenic_pll_recalc_rate,
.round_rate = ingenic_pll_round_rate,
.set_rate = ingenic_pll_set_rate,
+
+ .enable = ingenic_pll_enable,
+ .disable = ingenic_pll_disable,
+ .is_enabled = ingenic_pll_is_enabled,
};

/*
@@ -601,6 +659,7 @@ static int ingenic_register_clock(struct ingenic_cgu *cgu, unsigned idx)
}
} else if (caps & CGU_CLK_PLL) {
clk_init.ops = &ingenic_pll_ops;
+ clk_init.flags |= CLK_SET_RATE_GATE;

caps &= ~CGU_CLK_PLL;

--
2.11.0

2017-07-02 16:30:34

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v3 08/18] serial: 8250_ingenic: Add support for the JZ4770 SoC

The JZ4770 SoC's UART is no different from the other JZ SoCs, so this
commit simply adds the ingenic,jz4770-uart compatible string.

Signed-off-by: Paul Cercueil <[email protected]>
Acked-by: Rob Herring <[email protected]>
---
Documentation/devicetree/bindings/serial/ingenic,uart.txt | 8 ++++++--
drivers/tty/serial/8250/8250_ingenic.c | 5 +++++
2 files changed, 11 insertions(+), 2 deletions(-)

v2: List one compatible entry per line
v3: No change

diff --git a/Documentation/devicetree/bindings/serial/ingenic,uart.txt b/Documentation/devicetree/bindings/serial/ingenic,uart.txt
index 02cb7fe59cb7..c3c6406d5cfe 100644
--- a/Documentation/devicetree/bindings/serial/ingenic,uart.txt
+++ b/Documentation/devicetree/bindings/serial/ingenic,uart.txt
@@ -1,8 +1,12 @@
* Ingenic SoC UART

Required properties:
-- compatible : "ingenic,jz4740-uart", "ingenic,jz4760-uart",
- "ingenic,jz4775-uart" or "ingenic,jz4780-uart"
+- compatible : One of:
+ - "ingenic,jz4740-uart",
+ - "ingenic,jz4760-uart",
+ - "ingenic,jz4770-uart",
+ - "ingenic,jz4775-uart",
+ - "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.
diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c
index 4d9dc10e265c..b31b2ca552d1 100644
--- a/drivers/tty/serial/8250/8250_ingenic.c
+++ b/drivers/tty/serial/8250/8250_ingenic.c
@@ -133,6 +133,10 @@ EARLYCON_DECLARE(jz4740_uart, ingenic_early_console_setup);
OF_EARLYCON_DECLARE(jz4740_uart, "ingenic,jz4740-uart",
ingenic_early_console_setup);

+EARLYCON_DECLARE(jz4770_uart, ingenic_early_console_setup);
+OF_EARLYCON_DECLARE(jz4770_uart, "ingenic,jz4770-uart",
+ ingenic_early_console_setup);
+
EARLYCON_DECLARE(jz4775_uart, ingenic_early_console_setup);
OF_EARLYCON_DECLARE(jz4775_uart, "ingenic,jz4775-uart",
ingenic_early_console_setup);
@@ -327,6 +331,7 @@ static const struct ingenic_uart_config jz4780_uart_config = {
static const struct of_device_id of_match[] = {
{ .compatible = "ingenic,jz4740-uart", .data = &jz4740_uart_config },
{ .compatible = "ingenic,jz4760-uart", .data = &jz4760_uart_config },
+ { .compatible = "ingenic,jz4770-uart", .data = &jz4760_uart_config },
{ .compatible = "ingenic,jz4775-uart", .data = &jz4760_uart_config },
{ .compatible = "ingenic,jz4780-uart", .data = &jz4780_uart_config },
{ /* sentinel */ }
--
2.11.0

2017-07-02 16:30:38

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v3 11/18] MIPS: ingenic: Use common cmdline handling code

From: Paul Burton <[email protected]>

jz4740_init_cmdline appends all arguments from argv (in fw_arg1) to
arcs_cmdline, up to argc (in fw_arg0). The common code in
fw_init_cmdline will do the exact same thing when run on a system where
fw_arg0 isn't a pointer to kseg0 (it'll also set _fw_envp but we don't
use it). Remove the custom implementation & use the generic code.

Signed-off-by: Paul Burton <[email protected]>
---
arch/mips/jz4740/prom.c | 24 ++----------------------
1 file changed, 2 insertions(+), 22 deletions(-)

v2: No change
v3: No change

diff --git a/arch/mips/jz4740/prom.c b/arch/mips/jz4740/prom.c
index 47e857194ce6..a62dd8e6ecf9 100644
--- a/arch/mips/jz4740/prom.c
+++ b/arch/mips/jz4740/prom.c
@@ -20,33 +20,13 @@
#include <linux/serial_reg.h>

#include <asm/bootinfo.h>
+#include <asm/fw/fw.h>
#include <asm/mach-jz4740/base.h>

-static __init void jz4740_init_cmdline(int argc, char *argv[])
-{
- unsigned int count = COMMAND_LINE_SIZE - 1;
- int i;
- char *dst = &(arcs_cmdline[0]);
- char *src;
-
- for (i = 1; i < argc && count; ++i) {
- src = argv[i];
- while (*src && count) {
- *dst++ = *src++;
- --count;
- }
- *dst++ = ' ';
- }
- if (i > 1)
- --dst;
-
- *dst = 0;
-}
-
void __init prom_init(void)
{
- jz4740_init_cmdline((int)fw_arg0, (char **)fw_arg1);
mips_machtype = MACH_INGENIC_JZ4740;
+ fw_init_cmdline();
}

void __init prom_free_prom_memory(void)
--
2.11.0

2017-07-02 16:30:28

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v3 01/18] clk: ingenic: Use const pointer to clk_ops in struct

The CGU common code does not modify the pointed clk_ops structure, so it
should be marked as const.

Signed-off-by: Paul Cercueil <[email protected]>
---
drivers/clk/ingenic/cgu.h | 2 +-
drivers/clk/ingenic/jz4780-cgu.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)

v2: New patch in this series
v3: No change

diff --git a/drivers/clk/ingenic/cgu.h b/drivers/clk/ingenic/cgu.h
index 09700b2c555d..da448b0cac18 100644
--- a/drivers/clk/ingenic/cgu.h
+++ b/drivers/clk/ingenic/cgu.h
@@ -120,7 +120,7 @@ struct ingenic_cgu_gate_info {
* @clk_ops: custom clock operation callbacks
*/
struct ingenic_cgu_custom_info {
- struct clk_ops *clk_ops;
+ const struct clk_ops *clk_ops;
};

/**
diff --git a/drivers/clk/ingenic/jz4780-cgu.c b/drivers/clk/ingenic/jz4780-cgu.c
index b35d6d9dd5aa..a21698fb202c 100644
--- a/drivers/clk/ingenic/jz4780-cgu.c
+++ b/drivers/clk/ingenic/jz4780-cgu.c
@@ -203,7 +203,7 @@ static int jz4780_otg_phy_set_rate(struct clk_hw *hw, unsigned long req_rate,
return 0;
}

-static struct clk_ops jz4780_otg_phy_ops = {
+static const struct clk_ops jz4780_otg_phy_ops = {
.get_parent = jz4780_otg_phy_get_parent,
.set_parent = jz4780_otg_phy_set_parent,

--
2.11.0

2017-07-02 16:30:48

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v3 17/18] devicetree/bindings: Add GCW vendor prefix

Game Consoles Worldwide, mostly known under the acronym GCW, is the
creator of the GCW Zero open-source video game system.

Signed-off-by: Paul Cercueil <[email protected]>
Acked-by: Rob Herring <[email protected]>
---
Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
1 file changed, 1 insertion(+)

v2: It's 'Game Consoles Worldwide', not 'Games Consoles Worldwide'
v3: No change

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index c03d20140366..5921aa1248fb 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -114,6 +114,7 @@ focaltech FocalTech Systems Co.,Ltd
friendlyarm Guangzhou FriendlyARM Computer Tech Co., Ltd
fsl Freescale Semiconductor
fujitsu Fujitsu Ltd.
+gcw Game Consoles Worldwide
ge General Electric Company
geekbuying GeekBuying
gef GE Fanuc Intelligent Platforms Embedded Systems, Inc.
--
2.11.0

2017-07-02 16:30:44

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v3 12/18] MIPS: platform: add machtype IDs for more Ingenic SoCs

Add a machtype ID for the JZ4780 SoC, which was missing, and one for the
newly supported JZ4770 SoC.

Signed-off-by: Paul Cercueil <[email protected]>
---
arch/mips/include/asm/bootinfo.h | 2 ++
1 file changed, 2 insertions(+)

v2: No change
v3: No change

diff --git a/arch/mips/include/asm/bootinfo.h b/arch/mips/include/asm/bootinfo.h
index e26a093bb17a..a301a8f4bc66 100644
--- a/arch/mips/include/asm/bootinfo.h
+++ b/arch/mips/include/asm/bootinfo.h
@@ -79,6 +79,8 @@ enum loongson_machine_type {
*/
#define MACH_INGENIC_JZ4730 0 /* JZ4730 SOC */
#define MACH_INGENIC_JZ4740 1 /* JZ4740 SOC */
+#define MACH_INGENIC_JZ4770 2 /* JZ4770 SOC */
+#define MACH_INGENIC_JZ4780 3 /* JZ4780 SOC */

extern char *system_type;
const char *get_system_type(void);
--
2.11.0

2017-07-02 16:31:10

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v3 18/18] MIPS: ingenic: Initial GCW Zero support

The GCW Zero (http://www.gcw-zero.com) is a retro-gaming focused
handheld game console, successfully kickstarted in ~2012, running Linux.

Signed-off-by: Paul Cercueil <[email protected]>
---
arch/mips/boot/dts/ingenic/Makefile | 1 +
arch/mips/boot/dts/ingenic/gcw0.dts | 60 +++++++++++++++++++++++++++++++++++++
arch/mips/configs/gcw0_defconfig | 28 +++++++++++++++++
arch/mips/jz4740/Kconfig | 4 +++
arch/mips/jz4740/boards.c | 1 +
5 files changed, 94 insertions(+)
create mode 100644 arch/mips/boot/dts/ingenic/gcw0.dts
create mode 100644 arch/mips/configs/gcw0_defconfig

v2: No change
v3: No change

diff --git a/arch/mips/boot/dts/ingenic/Makefile b/arch/mips/boot/dts/ingenic/Makefile
index f2b864f07850..f64ad1c27a28 100644
--- a/arch/mips/boot/dts/ingenic/Makefile
+++ b/arch/mips/boot/dts/ingenic/Makefile
@@ -1,4 +1,5 @@
dtb-$(CONFIG_JZ4740_QI_LB60) += qi_lb60.dtb
+dtb-$(CONFIG_JZ4770_GCW0) += gcw0.dtb
dtb-$(CONFIG_JZ4780_CI20) += ci20.dtb

obj-y += $(patsubst %.dtb, %.dtb.o, $(dtb-y))
diff --git a/arch/mips/boot/dts/ingenic/gcw0.dts b/arch/mips/boot/dts/ingenic/gcw0.dts
new file mode 100644
index 000000000000..9c9a0137ccdf
--- /dev/null
+++ b/arch/mips/boot/dts/ingenic/gcw0.dts
@@ -0,0 +1,60 @@
+/dts-v1/;
+
+#include "jz4770.dtsi"
+
+/ {
+ compatible = "gcw,zero", "ingenic,jz4770";
+
+ aliases {
+ serial0 = &uart0;
+ serial1 = &uart1;
+ serial2 = &uart2;
+ serial3 = &uart3;
+ };
+
+ chosen {
+ stdout-path = "serial2:57600n8";
+ };
+
+ board {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges = <>;
+
+ otg_phy: otg-phy {
+ compatible = "usb-nop-xceiv";
+ clocks = <&cgu JZ4770_CLK_OTG_PHY>;
+ clock-names = "main_clk";
+ };
+ };
+};
+
+&ext {
+ clock-frequency = <12000000>;
+};
+
+&uart2 {
+ status = "okay";
+};
+
+&cgu {
+ /* Put high-speed peripherals under PLL1, such that we can change the
+ * PLL0 frequency on demand without having to suspend peripherals.
+ * We use a rate of 432 MHz, which is the least common multiple of
+ * 27 MHz (required by TV encoder) and 48 MHz (required by USB host).
+ */
+ assigned-clocks =
+ <&cgu JZ4770_CLK_PLL1>,
+ <&cgu JZ4770_CLK_UHC>;
+ assigned-clock-parents =
+ <0>,
+ <&cgu JZ4770_CLK_PLL1>;
+ assigned-clock-rates =
+ <432000000>;
+};
+
+&uhc {
+ /* The WiFi module is connected to the UHC. */
+ status = "okay";
+};
diff --git a/arch/mips/configs/gcw0_defconfig b/arch/mips/configs/gcw0_defconfig
new file mode 100644
index 000000000000..471497033855
--- /dev/null
+++ b/arch/mips/configs/gcw0_defconfig
@@ -0,0 +1,28 @@
+CONFIG_MACH_INGENIC=y
+CONFIG_JZ4770_GCW0=y
+CONFIG_HIGHMEM=y
+# CONFIG_BOUNCE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_SECCOMP is not set
+CONFIG_CROSS_COMPILE="mipsel-gcw0-linux-uclibc-"
+CONFIG_NO_HZ_IDLE=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_EMBEDDED=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_NETDEVICES=y
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_INGENIC=y
+CONFIG_USB=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_TMPFS=y
diff --git a/arch/mips/jz4740/Kconfig b/arch/mips/jz4740/Kconfig
index 922850503271..db270653fe8c 100644
--- a/arch/mips/jz4740/Kconfig
+++ b/arch/mips/jz4740/Kconfig
@@ -7,6 +7,10 @@ config JZ4740_QI_LB60
bool "Qi Hardware Ben NanoNote"
select MACH_JZ4740

+config JZ4770_GCW0
+ bool "Game Consoles Worldwide GCW Zero"
+ select MACH_JZ4770
+
config JZ4780_CI20
bool "MIPS Creator CI20"
select MACH_JZ4780
diff --git a/arch/mips/jz4740/boards.c b/arch/mips/jz4740/boards.c
index a3cf64cf004a..98a4d8e68cf0 100644
--- a/arch/mips/jz4740/boards.c
+++ b/arch/mips/jz4740/boards.c
@@ -12,5 +12,6 @@
#include <asm/mips_machine.h>

MIPS_MACHINE(MACH_INGENIC_JZ4740, "qi,lb60", "Qi Hardware Ben Nanonote", NULL);
+MIPS_MACHINE(MACH_INGENIC_JZ4770, "gcw,zero", "GCW Zero", NULL);
MIPS_MACHINE(MACH_INGENIC_JZ4780, "img,ci20",
"Imagination Technologies CI20", NULL);
--
2.11.0

2017-07-02 16:30:41

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v3 14/18] MIPS: ingenic: Initial JZ4770 support

Provide just enough bits (clocks, clocksource, uart) to allow a kernel
to boot on the JZ4770 SoC to a initramfs userspace.

Signed-off-by: Paul Cercueil <[email protected]>
---
arch/mips/boot/dts/ingenic/jz4770.dtsi | 210 +++++++++++++++++++++++++++++++++
arch/mips/jz4740/Kconfig | 6 +
arch/mips/jz4740/time.c | 2 +-
3 files changed, 217 insertions(+), 1 deletion(-)
create mode 100644 arch/mips/boot/dts/ingenic/jz4770.dtsi

v2: No change
v3: No change

diff --git a/arch/mips/boot/dts/ingenic/jz4770.dtsi b/arch/mips/boot/dts/ingenic/jz4770.dtsi
new file mode 100644
index 000000000000..d8d0a741ff5d
--- /dev/null
+++ b/arch/mips/boot/dts/ingenic/jz4770.dtsi
@@ -0,0 +1,210 @@
+#include <dt-bindings/clock/jz4770-cgu.h>
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "ingenic,jz4770";
+
+ cpuintc: interrupt-controller {
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ compatible = "mti,cpu-interrupt-controller";
+ };
+
+ intc: interrupt-controller@10001000 {
+ compatible = "ingenic,jz4770-intc";
+ reg = <0x10001000 0x40>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpuintc>;
+ interrupts = <2>;
+ };
+
+ ext: ext {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ };
+
+ osc32k: osc32k {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ };
+
+ cgu: jz4770-cgu@10000000 {
+ compatible = "ingenic,jz4770-cgu";
+ reg = <0x10000000 0x100>;
+
+ clocks = <&ext>, <&osc32k>;
+ clock-names = "ext", "osc32k";
+
+ #clock-cells = <1>;
+ };
+
+ pinctrl: pin-controller@10010000 {
+ compatible = "ingenic,jz4770-pinctrl";
+ reg = <0x10010000 0x600>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ gpa: gpio@0 {
+ compatible = "ingenic,jz4770-gpio";
+ reg = <0>;
+
+ gpio-controller;
+ gpio-ranges = <&pinctrl 0 0 32>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <17>;
+ };
+
+ gpb: gpio@1 {
+ compatible = "ingenic,jz4770-gpio";
+ reg = <1>;
+
+ gpio-controller;
+ gpio-ranges = <&pinctrl 0 32 32>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <16>;
+ };
+
+ gpc: gpio@2 {
+ compatible = "ingenic,jz4770-gpio";
+ reg = <2>;
+
+ gpio-controller;
+ gpio-ranges = <&pinctrl 0 64 32>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <15>;
+ };
+
+ gpd: gpio@3 {
+ compatible = "ingenic,jz4770-gpio";
+ reg = <3>;
+
+ gpio-controller;
+ gpio-ranges = <&pinctrl 0 96 32>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <14>;
+ };
+
+ gpe: gpio@4 {
+ compatible = "ingenic,jz4770-gpio";
+ reg = <4>;
+
+ gpio-controller;
+ gpio-ranges = <&pinctrl 0 128 32>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <13>;
+ };
+
+ gpf: gpio@5 {
+ compatible = "ingenic,jz4770-gpio";
+ reg = <5>;
+
+ gpio-controller;
+ gpio-ranges = <&pinctrl 0 160 32>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <12>;
+ };
+ };
+
+ uart0: serial@10030000 {
+ compatible = "ingenic,jz4770-uart";
+ reg = <0x10030000 0x100>;
+
+ clocks = <&ext>, <&cgu JZ4770_CLK_UART0>;
+ clock-names = "baud", "module";
+
+ interrupt-parent = <&intc>;
+ interrupts = <5>;
+
+ status = "disabled";
+ };
+
+ uart1: serial@10031000 {
+ compatible = "ingenic,jz4770-uart";
+ reg = <0x10031000 0x100>;
+
+ clocks = <&ext>, <&cgu JZ4770_CLK_UART1>;
+ clock-names = "baud", "module";
+
+ interrupt-parent = <&intc>;
+ interrupts = <4>;
+
+ status = "disabled";
+ };
+
+ uart2: serial@10032000 {
+ compatible = "ingenic,jz4770-uart";
+ reg = <0x10032000 0x100>;
+
+ clocks = <&ext>, <&cgu JZ4770_CLK_UART2>;
+ clock-names = "baud", "module";
+
+ interrupt-parent = <&intc>;
+ interrupts = <3>;
+
+ status = "disabled";
+ };
+
+ uart3: serial@10033000 {
+ compatible = "ingenic,jz4770-uart";
+ reg = <0x10033000 0x100>;
+
+ clocks = <&ext>, <&cgu JZ4770_CLK_UART3>;
+ clock-names = "baud", "module";
+
+ interrupt-parent = <&intc>;
+ interrupts = <2>;
+
+ status = "disabled";
+ };
+
+ uhc: uhc@13430000 {
+ compatible = "generic-ohci";
+ reg = <0x13430000 0x1000>;
+
+ clocks = <&cgu JZ4770_CLK_UHC>, <&cgu JZ4770_CLK_UHC_PHY>;
+ assigned-clocks = <&cgu JZ4770_CLK_UHC>;
+ assigned-clock-rates = <48000000>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <20>;
+
+ status = "disabled";
+ };
+};
diff --git a/arch/mips/jz4740/Kconfig b/arch/mips/jz4740/Kconfig
index 36f82017695d..922850503271 100644
--- a/arch/mips/jz4740/Kconfig
+++ b/arch/mips/jz4740/Kconfig
@@ -17,6 +17,12 @@ config MACH_JZ4740
bool
select SYS_HAS_CPU_MIPS32_R1

+config MACH_JZ4770
+ bool
+ select MIPS_CPU_SCACHE
+ select SYS_HAS_CPU_MIPS32_R2
+ select SYS_SUPPORTS_HIGHMEM
+
config MACH_JZ4780
bool
select MIPS_CPU_SCACHE
diff --git a/arch/mips/jz4740/time.c b/arch/mips/jz4740/time.c
index bb1ad5119da4..2ca9160f642a 100644
--- a/arch/mips/jz4740/time.c
+++ b/arch/mips/jz4740/time.c
@@ -113,7 +113,7 @@ static struct clock_event_device jz4740_clockevent = {
#ifdef CONFIG_MACH_JZ4740
.irq = JZ4740_IRQ_TCU0,
#endif
-#ifdef CONFIG_MACH_JZ4780
+#if defined(CONFIG_MACH_JZ4770) || defined(CONFIG_MACH_JZ4780)
.irq = JZ4780_IRQ_TCU2,
#endif
};
--
2.11.0

2017-07-02 16:31:31

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v3 16/18] MIPS: JZ4770: Workaround for corrupted DMA transfers

From: Maarten ter Huurne <[email protected]>

We have seen MMC DMA transfers read corrupted data from SDRAM when
a burst interval ends at physical address 0x10000000. To avoid this
problem, we remove the final page of low memory from the memory map.

Signed-off-by: Maarten ter Huurne <[email protected]>
---
arch/mips/jz4740/setup.c | 24 ++++++++++++++++++++++++
arch/mips/kernel/setup.c | 8 ++++++++
2 files changed, 32 insertions(+)

v2: No change
v3: No change

diff --git a/arch/mips/jz4740/setup.c b/arch/mips/jz4740/setup.c
index afd84ee966e8..6948b133a15d 100644
--- a/arch/mips/jz4740/setup.c
+++ b/arch/mips/jz4740/setup.c
@@ -23,6 +23,7 @@

#include <asm/bootinfo.h>
#include <asm/mips_machine.h>
+#include <asm/page.h>
#include <asm/prom.h>

#include <asm/mach-jz4740/base.h>
@@ -102,6 +103,29 @@ void __init arch_init_irq(void)
irqchip_init();
}

+/*
+ * We have seen MMC DMA transfers read corrupted data from SDRAM when a burst
+ * interval ends at physical address 0x10000000. To avoid this problem, we
+ * remove the final page of low memory from the memory map.
+ */
+void __init jz4770_reserve_unsafe_for_dma(void)
+{
+ int i;
+
+ for (i = 0; i < boot_mem_map.nr_map; i++) {
+ struct boot_mem_map_entry *entry = boot_mem_map.map + i;
+
+ if (entry->type != BOOT_MEM_RAM)
+ continue;
+
+ if (entry->addr + entry->size != 0x10000000)
+ continue;
+
+ entry->size -= PAGE_SIZE;
+ break;
+ }
+}
+
static int __init jz4740_machine_setup(void)
{
mips_machine_setup();
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 89785600fde4..cccfd7ba89fe 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -838,6 +838,14 @@ static void __init arch_mem_init(char **cmdline_p)

parse_early_param();

+#ifdef CONFIG_MACH_JZ4770
+ if (current_cpu_type() == CPU_JZRISC &&
+ mips_machtype == MACH_INGENIC_JZ4770) {
+ extern void __init jz4770_reserve_unsafe_for_dma(void);
+ jz4770_reserve_unsafe_for_dma();
+ }
+#endif
+
if (usermem) {
pr_info("User-defined physical RAM map:\n");
print_memory_map();
--
2.11.0

2017-07-02 16:31:48

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v3 15/18] MIPS: JZ4770: Work around config2 misreporting associativity

From: Maarten ter Huurne <[email protected]>

According to config2, the associativity would be 5-ways, but the
documentation states 4-ways, which also matches the documented
L2 cache size of 256 kB.

Signed-off-by: Maarten ter Huurne <[email protected]>
---
arch/mips/mm/sc-mips.c | 9 +++++++++
1 file changed, 9 insertions(+)

v2: No change
v3: No change

diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c
index c909c3342729..67a3b4d88580 100644
--- a/arch/mips/mm/sc-mips.c
+++ b/arch/mips/mm/sc-mips.c
@@ -15,6 +15,7 @@
#include <asm/mmu_context.h>
#include <asm/r4kcache.h>
#include <asm/mips-cm.h>
+#include <asm/bootinfo.h>

/*
* MIPS32/MIPS64 L2 cache handling
@@ -228,6 +229,14 @@ static inline int __init mips_sc_probe(void)
else
return 0;

+ /*
+ * According to config2 it would be 5-ways, but that is contradicted
+ * by all documentation.
+ */
+ if (current_cpu_type() == CPU_JZRISC &&
+ mips_machtype == MACH_INGENIC_JZ4770)
+ c->scache.ways = 4;
+
c->scache.waysize = c->scache.sets * c->scache.linesz;
c->scache.waybit = __ffs(c->scache.waysize);

--
2.11.0

2017-07-02 16:32:05

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v3 13/18] MIPS: ingenic: Add machine info for supported boards

This makes sure that 'mips_machtype' will be initialized to the SoC
version used on the board.

Signed-off-by: Paul Cercueil <[email protected]>
---
arch/mips/Kconfig | 1 +
arch/mips/jz4740/Makefile | 2 +-
arch/mips/jz4740/boards.c | 16 ++++++++++++++++
arch/mips/jz4740/setup.c | 34 +++++++++++++++++++++++++++++-----
4 files changed, 47 insertions(+), 6 deletions(-)
create mode 100644 arch/mips/jz4740/boards.c

v2: No change
v3: No change

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 2828ecde133d..f36ffb93efd9 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -370,6 +370,7 @@ config MACH_INGENIC
select BUILTIN_DTB
select USE_OF
select LIBFDT
+ select MIPS_MACHINE

config LANTIQ
bool "Lantiq based platforms"
diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile
index 39d70bde8cfe..87feb246fafe 100644
--- a/arch/mips/jz4740/Makefile
+++ b/arch/mips/jz4740/Makefile
@@ -5,7 +5,7 @@
# Object file lists.

obj-y += prom.o time.o reset.o setup.o \
- platform.o timer.o
+ platform.o timer.o boards.o

obj-$(CONFIG_MACH_JZ4740) += gpio.o

diff --git a/arch/mips/jz4740/boards.c b/arch/mips/jz4740/boards.c
new file mode 100644
index 000000000000..a3cf64cf004a
--- /dev/null
+++ b/arch/mips/jz4740/boards.c
@@ -0,0 +1,16 @@
+/*
+ * Ingenic boards support
+ *
+ * Copyright 2017, Paul Cercueil <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or later
+ * as published by the Free Software Foundation.
+ */
+
+#include <asm/bootinfo.h>
+#include <asm/mips_machine.h>
+
+MIPS_MACHINE(MACH_INGENIC_JZ4740, "qi,lb60", "Qi Hardware Ben Nanonote", NULL);
+MIPS_MACHINE(MACH_INGENIC_JZ4780, "img,ci20",
+ "Imagination Technologies CI20", NULL);
diff --git a/arch/mips/jz4740/setup.c b/arch/mips/jz4740/setup.c
index 6d0152321819..afd84ee966e8 100644
--- a/arch/mips/jz4740/setup.c
+++ b/arch/mips/jz4740/setup.c
@@ -22,6 +22,7 @@
#include <linux/of_fdt.h>

#include <asm/bootinfo.h>
+#include <asm/mips_machine.h>
#include <asm/prom.h>

#include <asm/mach-jz4740/base.h>
@@ -53,16 +54,34 @@ static void __init jz4740_detect_mem(void)
add_memory_region(0, size, BOOT_MEM_RAM);
}

+static unsigned long __init get_board_mach_type(const void *fdt)
+{
+ const struct mips_machine *mach;
+
+ for (mach = (struct mips_machine *)&__mips_machines_start;
+ mach < (struct mips_machine *)&__mips_machines_end;
+ mach++) {
+ if (!fdt_node_check_compatible(fdt, 0, mach->mach_id))
+ return mach->mach_type;
+ }
+
+ return MACH_INGENIC_JZ4740;
+}
+
void __init plat_mem_setup(void)
{
int offset;

+ if (!early_init_dt_scan(__dtb_start))
+ return;
+
jz4740_reset_init();
- __dt_setup_arch(__dtb_start);

offset = fdt_path_offset(__dtb_start, "/memory");
if (offset < 0)
jz4740_detect_mem();
+
+ mips_machtype = get_board_mach_type(__dtb_start);
}

void __init device_tree_init(void)
@@ -75,13 +94,18 @@ void __init device_tree_init(void)

const char *get_system_type(void)
{
- if (IS_ENABLED(CONFIG_MACH_JZ4780))
- return "JZ4780";
-
- return "JZ4740";
+ return mips_get_machine_name();
}

void __init arch_init_irq(void)
{
irqchip_init();
}
+
+static int __init jz4740_machine_setup(void)
+{
+ mips_machine_setup();
+
+ return 0;
+}
+arch_initcall(jz4740_machine_setup);
--
2.11.0

2017-07-02 16:32:25

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v3 10/18] MIPS: Setup boot_command_line before plat_mem_setup

From: Paul Burton <[email protected]>

Platforms using DT will typically call __dt_setup_arch from
plat_mem_setup. This in turn calls early_init_dt_scan. When
CONFIG_CMDLINE is set, this leads to its value being copied into
boot_command_line by early_init_dt_scan_chosen. If this happens before
the code setting up boot_command_line in arch_mem_init runs, that code
will go on to append CONFIG_CMDLINE (via builtin_cmdline) to
boot_command_line again, duplicating it. For some command line
parameters (eg. earlycon) this can be a problem. Set up
boot_command_line before early_init_dt_scan_chosen gets called such that
it will not write CONFIG_CMDLINE in this scenario & the arguments aren't
duplicated.

Signed-off-by: Paul Burton <[email protected]>
---
arch/mips/kernel/setup.c | 39 ++++++++++++++++++++-------------------
1 file changed, 20 insertions(+), 19 deletions(-)

v2: No change
v3: No change

diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 01d1dbde5fbf..89785600fde4 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -785,25 +785,6 @@ static void __init arch_mem_init(char **cmdline_p)
struct memblock_region *reg;
extern void plat_mem_setup(void);

- /* call board setup routine */
- plat_mem_setup();
-
- /*
- * Make sure all kernel memory is in the maps. The "UP" and
- * "DOWN" are opposite for initdata since if it crosses over
- * into another memory section you don't want that to be
- * freed when the initdata is freed.
- */
- arch_mem_addpart(PFN_DOWN(__pa_symbol(&_text)) << PAGE_SHIFT,
- PFN_UP(__pa_symbol(&_edata)) << PAGE_SHIFT,
- BOOT_MEM_RAM);
- arch_mem_addpart(PFN_UP(__pa_symbol(&__init_begin)) << PAGE_SHIFT,
- PFN_DOWN(__pa_symbol(&__init_end)) << PAGE_SHIFT,
- BOOT_MEM_INIT_RAM);
-
- pr_info("Determined physical RAM map:\n");
- print_memory_map();
-
#if defined(CONFIG_CMDLINE_BOOL) && defined(CONFIG_CMDLINE_OVERRIDE)
strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
#else
@@ -831,6 +812,26 @@ static void __init arch_mem_init(char **cmdline_p)
}
#endif
#endif
+
+ /* call board setup routine */
+ plat_mem_setup();
+
+ /*
+ * Make sure all kernel memory is in the maps. The "UP" and
+ * "DOWN" are opposite for initdata since if it crosses over
+ * into another memory section you don't want that to be
+ * freed when the initdata is freed.
+ */
+ arch_mem_addpart(PFN_DOWN(__pa_symbol(&_text)) << PAGE_SHIFT,
+ PFN_UP(__pa_symbol(&_edata)) << PAGE_SHIFT,
+ BOOT_MEM_RAM);
+ arch_mem_addpart(PFN_UP(__pa_symbol(&__init_begin)) << PAGE_SHIFT,
+ PFN_DOWN(__pa_symbol(&__init_end)) << PAGE_SHIFT,
+ BOOT_MEM_INIT_RAM);
+
+ pr_info("Determined physical RAM map:\n");
+ print_memory_map();
+
strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);

*cmdline_p = command_line;
--
2.11.0

2017-07-02 16:32:44

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v3 09/18] serial: 8250_ingenic: Parse earlycon options

In the devicetree, it is possible to specify the baudrate, parity,
bits, flow of the early console, by passing a configuration string like
this:

aliases {
serial0 = &uart0;
};

chosen {
stdout-path = "serial0:57600n8";
};

This, for instance, will configure the early console for a baudrate of
57600 bps, no parity, and 8 bits per baud.

This patches implements parsing of this configuration string in the
8250_ingenic driver, which previously just ignored it.

Signed-off-by: Paul Cercueil <[email protected]>
---
drivers/tty/serial/8250/8250_ingenic.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)

v2: Don't create temp. buffer, now that uart_parse_options takes a const char*
v3: No change

diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c
index b31b2ca552d1..be4a07a24342 100644
--- a/drivers/tty/serial/8250/8250_ingenic.c
+++ b/drivers/tty/serial/8250/8250_ingenic.c
@@ -99,14 +99,22 @@ static int __init ingenic_early_console_setup(struct earlycon_device *dev,
const char *opt)
{
struct uart_port *port = &dev->port;
- unsigned int baud, divisor;
+ unsigned int divisor;
+ int baud = 115200;

if (!dev->port.membase)
return -ENODEV;

+ if (opt) {
+ unsigned int parity, bits, flow; /* unused for now */
+
+ uart_parse_options(opt, &baud, &parity, &bits, &flow);
+ }
+
ingenic_early_console_setup_clock(dev);

- baud = dev->baud ?: 115200;
+ if (dev->baud)
+ baud = dev->baud;
divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud);

early_out(port, UART_IER, 0);
--
2.11.0

2017-07-02 16:33:06

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v3 07/18] serial: core: Make uart_parse_options take const char* argument

The pointed string is never modified from within uart_parse_options, so
it should be marked as const in the function prototype.

Signed-off-by: Paul Cercueil <[email protected]>
---
drivers/tty/serial/serial_core.c | 5 +++--
include/linux/serial_core.h | 2 +-
2 files changed, 4 insertions(+), 3 deletions(-)

v2: New patch in this series
v3: No change

diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 13bfd5dcffce..95d3770bdb37 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -1954,9 +1954,10 @@ EXPORT_SYMBOL_GPL(uart_parse_earlycon);
* eg: 115200n8r
*/
void
-uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow)
+uart_parse_options(const char *options, int *baud, int *parity,
+ int *bits, int *flow)
{
- char *s = options;
+ const char *s = options;

*baud = simple_strtoul(s, NULL, 10);
while (*s >= '0' && *s <= '9')
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 64d892f1e5cd..67f88fb53195 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -386,7 +386,7 @@ struct uart_port *uart_get_console(struct uart_port *ports, int nr,
struct console *c);
int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr,
char **options);
-void uart_parse_options(char *options, int *baud, int *parity, int *bits,
+void uart_parse_options(const char *options, int *baud, int *parity, int *bits,
int *flow);
int uart_set_options(struct uart_port *port, struct console *co, int baud,
int parity, int bits, int flow);
--
2.11.0

2017-07-02 16:33:11

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v3 06/18] clk: Add Ingenic jz4770 CGU driver

Add support for the clocks provided by the CGU in the Ingenic JZ4770
SoC.

Signed-off-by: Paul Cercueil <[email protected]>
Signed-off-by: Maarten ter Huurne <[email protected]>
---
drivers/clk/ingenic/Makefile | 1 +
drivers/clk/ingenic/jz4770-cgu.c | 487 +++++++++++++++++++++++++++++++++++++++
2 files changed, 488 insertions(+)
create mode 100644 drivers/clk/ingenic/jz4770-cgu.c

v2: Make structures static const
v3: <dt-bindings/clock/jz4770-cgu.h> is now added in a separate patch

diff --git a/drivers/clk/ingenic/Makefile b/drivers/clk/ingenic/Makefile
index cd47b0664c2b..1456e4cdb562 100644
--- a/drivers/clk/ingenic/Makefile
+++ b/drivers/clk/ingenic/Makefile
@@ -1,3 +1,4 @@
obj-y += cgu.o
obj-$(CONFIG_MACH_JZ4740) += jz4740-cgu.o
+obj-$(CONFIG_MACH_JZ4770) += jz4770-cgu.o
obj-$(CONFIG_MACH_JZ4780) += jz4780-cgu.o
diff --git a/drivers/clk/ingenic/jz4770-cgu.c b/drivers/clk/ingenic/jz4770-cgu.c
new file mode 100644
index 000000000000..4b2411d8a491
--- /dev/null
+++ b/drivers/clk/ingenic/jz4770-cgu.c
@@ -0,0 +1,487 @@
+/*
+ * JZ4770 SoC CGU driver
+ *
+ * Copyright 2017, Paul Cercueil <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or later
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/syscore_ops.h>
+#include <dt-bindings/clock/jz4770-cgu.h>
+#include "cgu.h"
+
+/*
+ * CPM registers offset address definition
+ */
+#define CGU_REG_CPCCR 0x00
+#define CGU_REG_LCR 0x04
+#define CGU_REG_CPPCR0 0x10
+#define CGU_REG_CLKGR0 0x20
+#define CGU_REG_OPCR 0x24
+#define CGU_REG_CLKGR1 0x28
+#define CGU_REG_CPPCR1 0x30
+#define CGU_REG_USBPCR1 0x48
+#define CGU_REG_USBCDR 0x50
+#define CGU_REG_I2SCDR 0x60
+#define CGU_REG_LPCDR 0x64
+#define CGU_REG_MSC0CDR 0x68
+#define CGU_REG_UHCCDR 0x6c
+#define CGU_REG_SSICDR 0x74
+#define CGU_REG_CIMCDR 0x7c
+#define CGU_REG_GPSCDR 0x80
+#define CGU_REG_PCMCDR 0x84
+#define CGU_REG_GPUCDR 0x88
+#define CGU_REG_MSC1CDR 0xA4
+#define CGU_REG_MSC2CDR 0xA8
+#define CGU_REG_BCHCDR 0xAC
+
+/* bits within the LCR register */
+#define LCR_LPM BIT(0) /* Low Power Mode */
+
+/* bits within the OPCR register */
+#define OPCR_SPENDH BIT(5) /* UHC PHY suspend */
+#define OPCR_SPENDN BIT(7) /* OTG PHY suspend */
+
+/* bits within the USBPCR1 register */
+#define USBPCR1_UHC_POWER BIT(5) /* UHC PHY power down */
+
+static struct ingenic_cgu *cgu;
+
+static int jz4770_uhc_phy_enable(struct clk_hw *hw)
+{
+ void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
+ void __iomem *reg_usbpcr1 = cgu->base + CGU_REG_USBPCR1;
+
+ writel(readl(reg_opcr) & ~OPCR_SPENDH, reg_opcr);
+ writel(readl(reg_usbpcr1) | USBPCR1_UHC_POWER, reg_usbpcr1);
+ return 0;
+}
+
+static void jz4770_uhc_phy_disable(struct clk_hw *hw)
+{
+ void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
+ void __iomem *reg_usbpcr1 = cgu->base + CGU_REG_USBPCR1;
+
+ writel(readl(reg_usbpcr1) & ~USBPCR1_UHC_POWER, reg_usbpcr1);
+ writel(readl(reg_opcr) | OPCR_SPENDH, reg_opcr);
+}
+
+static int jz4770_uhc_phy_is_enabled(struct clk_hw *hw)
+{
+ void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
+ void __iomem *reg_usbpcr1 = cgu->base + CGU_REG_USBPCR1;
+
+ return !(readl(reg_opcr) & OPCR_SPENDH) &&
+ (readl(reg_usbpcr1) & USBPCR1_UHC_POWER);
+}
+
+static const struct clk_ops jz4770_uhc_phy_ops = {
+ .enable = jz4770_uhc_phy_enable,
+ .disable = jz4770_uhc_phy_disable,
+ .is_enabled = jz4770_uhc_phy_is_enabled,
+};
+
+static int jz4770_otg_phy_enable(struct clk_hw *hw)
+{
+ void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
+
+ writel(readl(reg_opcr) | OPCR_SPENDN, reg_opcr);
+
+ /* Wait for the clock to be stable */
+ udelay(50);
+ return 0;
+}
+
+static void jz4770_otg_phy_disable(struct clk_hw *hw)
+{
+ void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
+
+ writel(readl(reg_opcr) & ~OPCR_SPENDN, reg_opcr);
+}
+
+static int jz4770_otg_phy_is_enabled(struct clk_hw *hw)
+{
+ void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
+
+ return !!(readl(reg_opcr) & OPCR_SPENDN);
+}
+
+static const struct clk_ops jz4770_otg_phy_ops = {
+ .enable = jz4770_otg_phy_enable,
+ .disable = jz4770_otg_phy_disable,
+ .is_enabled = jz4770_otg_phy_is_enabled,
+};
+
+static const s8 pll_od_encoding[8] = {
+ 0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
+};
+
+static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
+
+ /* External clocks */
+
+ [JZ4770_CLK_EXT] = { "ext", CGU_CLK_EXT },
+ [JZ4770_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },
+
+ /* PLLs */
+
+ [JZ4770_CLK_PLL0] = {
+ "pll0", CGU_CLK_PLL,
+ .parents = { JZ4770_CLK_EXT },
+ .pll = {
+ .reg = CGU_REG_CPPCR0,
+ .m_shift = 24,
+ .m_bits = 7,
+ .m_offset = 1,
+ .n_shift = 18,
+ .n_bits = 5,
+ .n_offset = 1,
+ .od_shift = 16,
+ .od_bits = 2,
+ .od_max = 8,
+ .od_encoding = pll_od_encoding,
+ .bypass_bit = 9,
+ .enable_bit = 8,
+ .stable_bit = 10,
+ },
+ },
+
+ [JZ4770_CLK_PLL1] = {
+ /* TODO: PLL1 can depend on PLL0 */
+ "pll1", CGU_CLK_PLL,
+ .parents = { JZ4770_CLK_EXT },
+ .pll = {
+ .reg = CGU_REG_CPPCR1,
+ .m_shift = 24,
+ .m_bits = 7,
+ .m_offset = 1,
+ .n_shift = 18,
+ .n_bits = 5,
+ .n_offset = 1,
+ .od_shift = 16,
+ .od_bits = 2,
+ .od_max = 8,
+ .od_encoding = pll_od_encoding,
+ .enable_bit = 7,
+ .stable_bit = 6,
+ .no_bypass_bit = true,
+ },
+ },
+
+ /* Main clocks */
+
+ [JZ4770_CLK_CCLK] = {
+ "cclk", CGU_CLK_DIV,
+ .parents = { JZ4770_CLK_PLL0, },
+ .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 },
+ },
+ [JZ4770_CLK_H0CLK] = {
+ "h0clk", CGU_CLK_DIV,
+ .parents = { JZ4770_CLK_PLL0, },
+ .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 },
+ },
+ [JZ4770_CLK_H1CLK] = {
+ "h1clk", CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_PLL0, },
+ .div = { CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1 },
+ .gate = { CGU_REG_LCR, 30 },
+ },
+ [JZ4770_CLK_H2CLK] = {
+ "h2clk", CGU_CLK_DIV,
+ .parents = { JZ4770_CLK_PLL0, },
+ .div = { CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1 },
+ },
+ [JZ4770_CLK_C1CLK] = {
+ "c1clk", CGU_CLK_DIV,
+ .parents = { JZ4770_CLK_PLL0, },
+ .div = { CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1 },
+ },
+ [JZ4770_CLK_PCLK] = {
+ "pclk", CGU_CLK_DIV,
+ .parents = { JZ4770_CLK_PLL0, },
+ .div = { CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1 },
+ },
+
+ /* Those divided clocks can connect to PLL0 or PLL1 */
+
+ [JZ4770_CLK_MMC0_MUX] = {
+ "mmc0_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_MSC0CDR, 30, 1 },
+ .div = { CGU_REG_MSC0CDR, 0, 1, 7, -1, -1, 31 },
+ .gate = { CGU_REG_MSC0CDR, 31 },
+ },
+ [JZ4770_CLK_MMC1_MUX] = {
+ "mmc1_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_MSC1CDR, 30, 1 },
+ .div = { CGU_REG_MSC1CDR, 0, 1, 7, -1, -1, 31 },
+ .gate = { CGU_REG_MSC1CDR, 31 },
+ },
+ [JZ4770_CLK_MMC2_MUX] = {
+ "mmc2_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_MSC2CDR, 30, 1 },
+ .div = { CGU_REG_MSC2CDR, 0, 1, 7, -1, -1, 31 },
+ .gate = { CGU_REG_MSC2CDR, 31 },
+ },
+ [JZ4770_CLK_CIM] = {
+ "cim", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_CIMCDR, 31, 1 },
+ .div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 26 },
+ },
+ [JZ4770_CLK_UHC] = {
+ "uhc", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_UHCCDR, 29, 1 },
+ .div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 24 },
+ },
+ [JZ4770_CLK_GPU] = {
+ "gpu", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, -1 },
+ .mux = { CGU_REG_GPUCDR, 31, 1 },
+ .div = { CGU_REG_GPUCDR, 0, 1, 3, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR1, 9 },
+ },
+ [JZ4770_CLK_BCH] = {
+ "bch", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_BCHCDR, 31, 1 },
+ .div = { CGU_REG_BCHCDR, 0, 1, 3, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 1 },
+ },
+ [JZ4770_CLK_LPCLK_MUX] = {
+ "lpclk", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_LPCDR, 29, 1 },
+ .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 28 },
+ },
+ [JZ4770_CLK_GPS] = {
+ "gps", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_GPSCDR, 31, 1 },
+ .div = { CGU_REG_GPSCDR, 0, 1, 4, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 22 },
+ },
+
+ /* Those divided clocks can connect to EXT, PLL0 or PLL1 */
+
+ [JZ4770_CLK_SSI_MUX] = {
+ "ssi_mux", CGU_CLK_DIV | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_EXT, -1,
+ JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
+ .mux = { CGU_REG_SSICDR, 30, 2 },
+ .div = { CGU_REG_SSICDR, 0, 1, 6, -1, -1, -1 },
+ },
+ [JZ4770_CLK_PCM_MUX] = {
+ "pcm_mux", CGU_CLK_DIV | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_EXT, -1,
+ JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
+ .mux = { CGU_REG_PCMCDR, 30, 2 },
+ .div = { CGU_REG_PCMCDR, 0, 1, 9, -1, -1, -1 },
+ },
+ [JZ4770_CLK_I2S] = {
+ "i2s", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_EXT, -1,
+ JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
+ .mux = { CGU_REG_I2SCDR, 30, 2 },
+ .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR1, 13 },
+ },
+ [JZ4770_CLK_OTG] = {
+ "usb", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_EXT, -1,
+ JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
+ .mux = { CGU_REG_USBCDR, 30, 2 },
+ .div = { CGU_REG_USBCDR, 0, 1, 8, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 2 },
+ },
+
+ /* Gate-only clocks */
+
+ [JZ4770_CLK_SSI0] = {
+ "ssi0", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_SSI_MUX, },
+ .gate = { CGU_REG_CLKGR0, 4 },
+ },
+ [JZ4770_CLK_SSI1] = {
+ "ssi1", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_SSI_MUX, },
+ .gate = { CGU_REG_CLKGR0, 19 },
+ },
+ [JZ4770_CLK_SSI2] = {
+ "ssi2", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_SSI_MUX, },
+ .gate = { CGU_REG_CLKGR0, 20 },
+ },
+ [JZ4770_CLK_PCM0] = {
+ "pcm0", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_PCM_MUX, },
+ .gate = { CGU_REG_CLKGR1, 8 },
+ },
+ [JZ4770_CLK_PCM1] = {
+ "pcm1", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_PCM_MUX, },
+ .gate = { CGU_REG_CLKGR1, 10 },
+ },
+ [JZ4770_CLK_DMA] = {
+ "dma", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_H2CLK, },
+ .gate = { CGU_REG_CLKGR0, 21 },
+ },
+ [JZ4770_CLK_I2C0] = {
+ "i2c0", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 5 },
+ },
+ [JZ4770_CLK_I2C1] = {
+ "i2c1", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 6 },
+ },
+ [JZ4770_CLK_I2C2] = {
+ "i2c2", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR1, 15 },
+ },
+ [JZ4770_CLK_UART0] = {
+ "uart0", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 15 },
+ },
+ [JZ4770_CLK_UART1] = {
+ "uart1", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 16 },
+ },
+ [JZ4770_CLK_UART2] = {
+ "uart2", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 17 },
+ },
+ [JZ4770_CLK_UART3] = {
+ "uart3", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 18 },
+ },
+ [JZ4770_CLK_IPU] = {
+ "ipu", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_H0CLK, },
+ .gate = { CGU_REG_CLKGR0, 29 },
+ },
+ [JZ4770_CLK_ADC] = {
+ "adc", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 14 },
+ },
+ [JZ4770_CLK_AIC] = {
+ "aic", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 8 },
+ },
+ [JZ4770_CLK_AUX] = {
+ "aux", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_C1CLK, },
+ .gate = { CGU_REG_CLKGR1, 14 },
+ },
+ [JZ4770_CLK_VPU] = {
+ "vpu", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_H1CLK, },
+ .gate = { CGU_REG_CLKGR1, 7 },
+ },
+ [JZ4770_CLK_MMC0] = {
+ "mmc0", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_MMC0_MUX, },
+ .gate = { CGU_REG_CLKGR0, 3 },
+ },
+ [JZ4770_CLK_MMC1] = {
+ "mmc1", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_MMC1_MUX, },
+ .gate = { CGU_REG_CLKGR0, 11 },
+ },
+ [JZ4770_CLK_MMC2] = {
+ "mmc2", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_MMC2_MUX, },
+ .gate = { CGU_REG_CLKGR0, 12 },
+ },
+
+ /* Custom clocks */
+
+ [JZ4770_CLK_UHC_PHY] = {
+ "uhc_phy", CGU_CLK_CUSTOM,
+ .parents = { JZ4770_CLK_UHC, -1, -1, -1 },
+ .custom = { &jz4770_uhc_phy_ops },
+ },
+ [JZ4770_CLK_OTG_PHY] = {
+ "usb_phy", CGU_CLK_CUSTOM,
+ .parents = { JZ4770_CLK_OTG, -1, -1, -1 },
+ .custom = { &jz4770_otg_phy_ops },
+ },
+
+ [JZ4770_CLK_EXT512] = {
+ "ext/512", CGU_CLK_FIXDIV,
+ .parents = { JZ4770_CLK_EXT },
+ .fixdiv = { 512 },
+ },
+
+ [JZ4770_CLK_RTC] = {
+ "rtc", CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_EXT512, JZ4770_CLK_OSC32K, },
+ .mux = { CGU_REG_OPCR, 2, 1},
+ },
+};
+
+#if IS_ENABLED(CONFIG_PM_SLEEP)
+static int jz4770_cgu_pm_suspend(void)
+{
+ u32 val;
+
+ val = readl(cgu->base + CGU_REG_LCR);
+ writel(val | LCR_LPM, cgu->base + CGU_REG_LCR);
+ return 0;
+}
+
+static void jz4770_cgu_pm_resume(void)
+{
+ u32 val;
+
+ val = readl(cgu->base + CGU_REG_LCR);
+ writel(val & ~LCR_LPM, cgu->base + CGU_REG_LCR);
+}
+
+static struct syscore_ops jz4770_cgu_pm_ops = {
+ .suspend = jz4770_cgu_pm_suspend,
+ .resume = jz4770_cgu_pm_resume,
+};
+#endif /* CONFIG_PM_SLEEP */
+
+static void __init jz4770_cgu_init(struct device_node *np)
+{
+ int retval;
+
+ cgu = ingenic_cgu_new(jz4770_cgu_clocks,
+ ARRAY_SIZE(jz4770_cgu_clocks), np);
+ if (!cgu)
+ pr_err("%s: failed to initialise CGU\n", __func__);
+
+ retval = ingenic_cgu_register_clocks(cgu);
+ if (retval)
+ pr_err("%s: failed to register CGU Clocks\n", __func__);
+
+#if IS_ENABLED(CONFIG_PM_SLEEP)
+ register_syscore_ops(&jz4770_cgu_pm_ops);
+#endif
+}
+
+/* We only probe via devicetree, no need for a platform driver */
+CLK_OF_DECLARE(jz4770_cgu, "ingenic,jz4770-cgu", jz4770_cgu_init);
--
2.11.0

2017-07-02 16:33:38

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v3 05/18] dt-bindings: clock: Add jz4770-cgu.h header

This will be used from the devicetree bindings to specify the clocks
that should be obtained from the jz4770-cgu driver.

Signed-off-by: Paul Cercueil <[email protected]>
---
include/dt-bindings/clock/jz4770-cgu.h | 57 ++++++++++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
create mode 100644 include/dt-bindings/clock/jz4770-cgu.h

v3: New patch in this series

diff --git a/include/dt-bindings/clock/jz4770-cgu.h b/include/dt-bindings/clock/jz4770-cgu.h
new file mode 100644
index 000000000000..54b8b2ae4a73
--- /dev/null
+++ b/include/dt-bindings/clock/jz4770-cgu.h
@@ -0,0 +1,57 @@
+/*
+ * This header provides clock numbers for the ingenic,jz4770-cgu DT binding.
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_JZ4770_CGU_H__
+#define __DT_BINDINGS_CLOCK_JZ4770_CGU_H__
+
+#define JZ4770_CLK_EXT 0
+#define JZ4770_CLK_OSC32K 1
+#define JZ4770_CLK_PLL0 2
+#define JZ4770_CLK_PLL1 3
+#define JZ4770_CLK_CCLK 4
+#define JZ4770_CLK_H0CLK 5
+#define JZ4770_CLK_H1CLK 6
+#define JZ4770_CLK_H2CLK 7
+#define JZ4770_CLK_C1CLK 8
+#define JZ4770_CLK_PCLK 9
+#define JZ4770_CLK_MMC0_MUX 10
+#define JZ4770_CLK_MMC0 11
+#define JZ4770_CLK_MMC1_MUX 12
+#define JZ4770_CLK_MMC1 13
+#define JZ4770_CLK_MMC2_MUX 14
+#define JZ4770_CLK_MMC2 15
+#define JZ4770_CLK_CIM 16
+#define JZ4770_CLK_UHC 17
+#define JZ4770_CLK_GPU 18
+#define JZ4770_CLK_BCH 19
+#define JZ4770_CLK_LPCLK_MUX 20
+#define JZ4770_CLK_GPS 21
+#define JZ4770_CLK_SSI_MUX 22
+#define JZ4770_CLK_PCM_MUX 23
+#define JZ4770_CLK_I2S 24
+#define JZ4770_CLK_OTG 25
+#define JZ4770_CLK_SSI0 26
+#define JZ4770_CLK_SSI1 27
+#define JZ4770_CLK_SSI2 28
+#define JZ4770_CLK_PCM0 29
+#define JZ4770_CLK_PCM1 30
+#define JZ4770_CLK_DMA 31
+#define JZ4770_CLK_I2C0 32
+#define JZ4770_CLK_I2C1 33
+#define JZ4770_CLK_I2C2 34
+#define JZ4770_CLK_UART0 35
+#define JZ4770_CLK_UART1 36
+#define JZ4770_CLK_UART2 37
+#define JZ4770_CLK_UART3 38
+#define JZ4770_CLK_IPU 39
+#define JZ4770_CLK_ADC 40
+#define JZ4770_CLK_AIC 41
+#define JZ4770_CLK_AUX 42
+#define JZ4770_CLK_VPU 43
+#define JZ4770_CLK_UHC_PHY 44
+#define JZ4770_CLK_OTG_PHY 45
+#define JZ4770_CLK_EXT512 46
+#define JZ4770_CLK_RTC 47
+
+#endif /* __DT_BINDINGS_CLOCK_JZ4770_CGU_H__ */
--
2.11.0

2017-07-02 16:33:56

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v3 03/18] clk: ingenic: support PLLs with no bypass bit

The second PLL of the JZ4770 does not have a bypass bit.
This commit makes it possible to support it with the current common CGU
code.

Signed-off-by: Paul Cercueil <[email protected]>
---
drivers/clk/ingenic/cgu.c | 3 ++-
drivers/clk/ingenic/cgu.h | 2 ++
2 files changed, 4 insertions(+), 1 deletion(-)

v2: No change
v3: No change

diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
index eb9002ccf3fc..75b083ba294c 100644
--- a/drivers/clk/ingenic/cgu.c
+++ b/drivers/clk/ingenic/cgu.c
@@ -100,7 +100,8 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
n += pll_info->n_offset;
od_enc = ctl >> pll_info->od_shift;
od_enc &= GENMASK(pll_info->od_bits - 1, 0);
- bypass = !!(ctl & BIT(pll_info->bypass_bit));
+ bypass = !pll_info->no_bypass_bit &&
+ !!(ctl & BIT(pll_info->bypass_bit));
enable = !!(ctl & BIT(pll_info->enable_bit));

if (bypass)
diff --git a/drivers/clk/ingenic/cgu.h b/drivers/clk/ingenic/cgu.h
index da448b0cac18..21420b455985 100644
--- a/drivers/clk/ingenic/cgu.h
+++ b/drivers/clk/ingenic/cgu.h
@@ -48,6 +48,7 @@
* @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
+ * @no_bypass_bit: if set, the PLL has no bypass functionality
*/
struct ingenic_cgu_pll_info {
unsigned reg;
@@ -58,6 +59,7 @@ struct ingenic_cgu_pll_info {
u8 bypass_bit;
u8 enable_bit;
u8 stable_bit;
+ bool no_bypass_bit;
};

/**
--
2.11.0

2017-07-02 16:34:18

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v3 02/18] clk: ingenic: Fix recalc_rate for clocks with fixed divider

Previously, the clocks with a fixed divider would report their rate
as being the same as the one of their parent, independently of the
divider in use. This commit fixes this behaviour.

This went unnoticed as neither the jz4740 nor the jz4780 CGU code
have clocks with fixed dividers yet.

Signed-off-by: Paul Cercueil <[email protected]>
---
drivers/clk/ingenic/cgu.c | 2 ++
1 file changed, 2 insertions(+)

v2: No changes
v3: No changes

diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
index e8248f9185f7..eb9002ccf3fc 100644
--- a/drivers/clk/ingenic/cgu.c
+++ b/drivers/clk/ingenic/cgu.c
@@ -328,6 +328,8 @@ ingenic_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
div *= clk_info->div.div;

rate /= div;
+ } else if (clk_info->type & CGU_CLK_FIXDIV) {
+ rate /= clk_info->fixdiv.div;
}

return rate;
--
2.11.0

2017-07-12 23:20:42

by Stephen Boyd

[permalink] [raw]
Subject: Re: [PATCH v3 01/18] clk: ingenic: Use const pointer to clk_ops in struct

On 07/02, Paul Cercueil wrote:
> The CGU common code does not modify the pointed clk_ops structure, so it
> should be marked as const.
>
> Signed-off-by: Paul Cercueil <[email protected]>
> ---

Sorry I forgot, did you want an ack for these clk patches or for
me to take them through clk tree. If it's the ack case,

Acked-by: Stephen Boyd <[email protected]>

for patches 1 through 6.

--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

2017-07-13 10:07:30

by Paul Cercueil

[permalink] [raw]
Subject: Re: [PATCH v3 01/18] clk: ingenic: Use const pointer to clk_ops in struct

Le 2017-07-13 01:20, Stephen Boyd a écrit :
> On 07/02, Paul Cercueil wrote:
>> The CGU common code does not modify the pointed clk_ops structure, so
>> it
>> should be marked as const.
>>
>> Signed-off-by: Paul Cercueil <[email protected]>
>> ---
>
> Sorry I forgot, did you want an ack for these clk patches or for
> me to take them through clk tree. If it's the ack case,
>
> Acked-by: Stephen Boyd <[email protected]>
>
> for patches 1 through 6.

I think ACK; then Ralf can take them in 4.13 :)

Thanks,

-Paul

2017-07-13 11:49:37

by Ralf Baechle

[permalink] [raw]
Subject: Re: [PATCH v3 01/18] clk: ingenic: Use const pointer to clk_ops in struct

On Thu, Jul 13, 2017 at 12:07:25PM +0200, Paul Cercueil wrote:

> > Sorry I forgot, did you want an ack for these clk patches or for
> > me to take them through clk tree. If it's the ack case,
> >
> > Acked-by: Stephen Boyd <[email protected]>
> >
> > for patches 1 through 6.
>
> I think ACK; then Ralf can take them in 4.13 :)

My pull request for 4.13 is already finalized so it'd be great if this
could make it to 4.13 through the clk tree. If that should be impossible
I'd like to merge this via the MIPS tree for 4.14.

Thanks,

Ralf

2017-07-13 17:50:25

by Stephen Boyd

[permalink] [raw]
Subject: Re: [PATCH v3 01/18] clk: ingenic: Use const pointer to clk_ops in struct

On 07/13, Ralf Baechle wrote:
> On Thu, Jul 13, 2017 at 12:07:25PM +0200, Paul Cercueil wrote:
>
> > > Sorry I forgot, did you want an ack for these clk patches or for
> > > me to take them through clk tree. If it's the ack case,
> > >
> > > Acked-by: Stephen Boyd <[email protected]>
> > >
> > > for patches 1 through 6.
> >
> > I think ACK; then Ralf can take them in 4.13 :)
>
> My pull request for 4.13 is already finalized so it'd be great if this
> could make it to 4.13 through the clk tree. If that should be impossible
> I'd like to merge this via the MIPS tree for 4.14.
>

It's too late for v4.13, so you can take it for v4.14.

--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

2017-12-28 13:56:51

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v4 01/15] clk: ingenic: Use const pointer to clk_ops in struct

The CGU common code does not modify the pointed clk_ops structure, so it
should be marked as const.

Signed-off-by: Paul Cercueil <[email protected]>
Acked-by: Stephen Boyd <[email protected]>
---
drivers/clk/ingenic/cgu.h | 2 +-
drivers/clk/ingenic/jz4780-cgu.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)

v2: New patch in this series
v3: No change
v4: No change

diff --git a/drivers/clk/ingenic/cgu.h b/drivers/clk/ingenic/cgu.h
index e78b586536ea..f1527cf75b3f 100644
--- a/drivers/clk/ingenic/cgu.h
+++ b/drivers/clk/ingenic/cgu.h
@@ -120,7 +120,7 @@ struct ingenic_cgu_gate_info {
* @clk_ops: custom clock operation callbacks
*/
struct ingenic_cgu_custom_info {
- struct clk_ops *clk_ops;
+ const struct clk_ops *clk_ops;
};

/**
diff --git a/drivers/clk/ingenic/jz4780-cgu.c b/drivers/clk/ingenic/jz4780-cgu.c
index ac3585ed8228..6427be117ff1 100644
--- a/drivers/clk/ingenic/jz4780-cgu.c
+++ b/drivers/clk/ingenic/jz4780-cgu.c
@@ -203,7 +203,7 @@ static int jz4780_otg_phy_set_rate(struct clk_hw *hw, unsigned long req_rate,
return 0;
}

-static struct clk_ops jz4780_otg_phy_ops = {
+static const struct clk_ops jz4780_otg_phy_ops = {
.get_parent = jz4780_otg_phy_get_parent,
.set_parent = jz4780_otg_phy_set_parent,

--
2.11.0

2017-12-28 13:56:58

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v4 05/15] dt-bindings: clock: Add jz4770-cgu.h header

This will be used from the devicetree bindings to specify the clocks
that should be obtained from the jz4770-cgu driver.

Signed-off-by: Paul Cercueil <[email protected]>
---
include/dt-bindings/clock/jz4770-cgu.h | 57 ++++++++++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
create mode 100644 include/dt-bindings/clock/jz4770-cgu.h

v3: New patch in this series
v4: No change

diff --git a/include/dt-bindings/clock/jz4770-cgu.h b/include/dt-bindings/clock/jz4770-cgu.h
new file mode 100644
index 000000000000..54b8b2ae4a73
--- /dev/null
+++ b/include/dt-bindings/clock/jz4770-cgu.h
@@ -0,0 +1,57 @@
+/*
+ * This header provides clock numbers for the ingenic,jz4770-cgu DT binding.
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_JZ4770_CGU_H__
+#define __DT_BINDINGS_CLOCK_JZ4770_CGU_H__
+
+#define JZ4770_CLK_EXT 0
+#define JZ4770_CLK_OSC32K 1
+#define JZ4770_CLK_PLL0 2
+#define JZ4770_CLK_PLL1 3
+#define JZ4770_CLK_CCLK 4
+#define JZ4770_CLK_H0CLK 5
+#define JZ4770_CLK_H1CLK 6
+#define JZ4770_CLK_H2CLK 7
+#define JZ4770_CLK_C1CLK 8
+#define JZ4770_CLK_PCLK 9
+#define JZ4770_CLK_MMC0_MUX 10
+#define JZ4770_CLK_MMC0 11
+#define JZ4770_CLK_MMC1_MUX 12
+#define JZ4770_CLK_MMC1 13
+#define JZ4770_CLK_MMC2_MUX 14
+#define JZ4770_CLK_MMC2 15
+#define JZ4770_CLK_CIM 16
+#define JZ4770_CLK_UHC 17
+#define JZ4770_CLK_GPU 18
+#define JZ4770_CLK_BCH 19
+#define JZ4770_CLK_LPCLK_MUX 20
+#define JZ4770_CLK_GPS 21
+#define JZ4770_CLK_SSI_MUX 22
+#define JZ4770_CLK_PCM_MUX 23
+#define JZ4770_CLK_I2S 24
+#define JZ4770_CLK_OTG 25
+#define JZ4770_CLK_SSI0 26
+#define JZ4770_CLK_SSI1 27
+#define JZ4770_CLK_SSI2 28
+#define JZ4770_CLK_PCM0 29
+#define JZ4770_CLK_PCM1 30
+#define JZ4770_CLK_DMA 31
+#define JZ4770_CLK_I2C0 32
+#define JZ4770_CLK_I2C1 33
+#define JZ4770_CLK_I2C2 34
+#define JZ4770_CLK_UART0 35
+#define JZ4770_CLK_UART1 36
+#define JZ4770_CLK_UART2 37
+#define JZ4770_CLK_UART3 38
+#define JZ4770_CLK_IPU 39
+#define JZ4770_CLK_ADC 40
+#define JZ4770_CLK_AIC 41
+#define JZ4770_CLK_AUX 42
+#define JZ4770_CLK_VPU 43
+#define JZ4770_CLK_UHC_PHY 44
+#define JZ4770_CLK_OTG_PHY 45
+#define JZ4770_CLK_EXT512 46
+#define JZ4770_CLK_RTC 47
+
+#endif /* __DT_BINDINGS_CLOCK_JZ4770_CGU_H__ */
--
2.11.0

2017-12-28 13:57:10

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v4 14/15] devicetree/bindings: Add GCW vendor prefix

Game Consoles Worldwide, mostly known under the acronym GCW, is the
creator of the GCW Zero open-source video game system.

Signed-off-by: Paul Cercueil <[email protected]>
Acked-by: Rob Herring <[email protected]>
---
Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
1 file changed, 1 insertion(+)

v2: It's 'Game Consoles Worldwide', not 'Games Consoles Worldwide'
v3: No change
v4: No change

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 0994bdd82cd3..f40f4da39937 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -123,6 +123,7 @@ focaltech FocalTech Systems Co.,Ltd
friendlyarm Guangzhou FriendlyARM Computer Tech Co., Ltd
fsl Freescale Semiconductor
fujitsu Fujitsu Ltd.
+gcw Game Consoles Worldwide
ge General Electric Company
geekbuying GeekBuying
gef GE Fanuc Intelligent Platforms Embedded Systems, Inc.
--
2.11.0

2017-12-28 13:57:08

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v4 10/15] MIPS: ingenic: Add machine info for supported boards

This makes sure that 'mips_machtype' will be initialized to the SoC
version used on the board.

Signed-off-by: Paul Cercueil <[email protected]>
---
arch/mips/Kconfig | 1 +
arch/mips/jz4740/Makefile | 2 +-
arch/mips/jz4740/boards.c | 16 ++++++++++++++++
arch/mips/jz4740/setup.c | 34 +++++++++++++++++++++++++++++-----
4 files changed, 47 insertions(+), 6 deletions(-)
create mode 100644 arch/mips/jz4740/boards.c

v2: No change
v3: No change
v4: No change

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 350a990fc719..83243e427e36 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -376,6 +376,7 @@ config MACH_INGENIC
select BUILTIN_DTB
select USE_OF
select LIBFDT
+ select MIPS_MACHINE

config LANTIQ
bool "Lantiq based platforms"
diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile
index 88d6aa7d000b..fc2d3b3c4a80 100644
--- a/arch/mips/jz4740/Makefile
+++ b/arch/mips/jz4740/Makefile
@@ -6,7 +6,7 @@
# Object file lists.

obj-y += prom.o time.o reset.o setup.o \
- platform.o timer.o
+ platform.o timer.o boards.o

CFLAGS_setup.o = -I$(src)/../../../scripts/dtc/libfdt

diff --git a/arch/mips/jz4740/boards.c b/arch/mips/jz4740/boards.c
new file mode 100644
index 000000000000..a3cf64cf004a
--- /dev/null
+++ b/arch/mips/jz4740/boards.c
@@ -0,0 +1,16 @@
+/*
+ * Ingenic boards support
+ *
+ * Copyright 2017, Paul Cercueil <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or later
+ * as published by the Free Software Foundation.
+ */
+
+#include <asm/bootinfo.h>
+#include <asm/mips_machine.h>
+
+MIPS_MACHINE(MACH_INGENIC_JZ4740, "qi,lb60", "Qi Hardware Ben Nanonote", NULL);
+MIPS_MACHINE(MACH_INGENIC_JZ4780, "img,ci20",
+ "Imagination Technologies CI20", NULL);
diff --git a/arch/mips/jz4740/setup.c b/arch/mips/jz4740/setup.c
index 6d0152321819..afd84ee966e8 100644
--- a/arch/mips/jz4740/setup.c
+++ b/arch/mips/jz4740/setup.c
@@ -22,6 +22,7 @@
#include <linux/of_fdt.h>

#include <asm/bootinfo.h>
+#include <asm/mips_machine.h>
#include <asm/prom.h>

#include <asm/mach-jz4740/base.h>
@@ -53,16 +54,34 @@ static void __init jz4740_detect_mem(void)
add_memory_region(0, size, BOOT_MEM_RAM);
}

+static unsigned long __init get_board_mach_type(const void *fdt)
+{
+ const struct mips_machine *mach;
+
+ for (mach = (struct mips_machine *)&__mips_machines_start;
+ mach < (struct mips_machine *)&__mips_machines_end;
+ mach++) {
+ if (!fdt_node_check_compatible(fdt, 0, mach->mach_id))
+ return mach->mach_type;
+ }
+
+ return MACH_INGENIC_JZ4740;
+}
+
void __init plat_mem_setup(void)
{
int offset;

+ if (!early_init_dt_scan(__dtb_start))
+ return;
+
jz4740_reset_init();
- __dt_setup_arch(__dtb_start);

offset = fdt_path_offset(__dtb_start, "/memory");
if (offset < 0)
jz4740_detect_mem();
+
+ mips_machtype = get_board_mach_type(__dtb_start);
}

void __init device_tree_init(void)
@@ -75,13 +94,18 @@ void __init device_tree_init(void)

const char *get_system_type(void)
{
- if (IS_ENABLED(CONFIG_MACH_JZ4780))
- return "JZ4780";
-
- return "JZ4740";
+ return mips_get_machine_name();
}

void __init arch_init_irq(void)
{
irqchip_init();
}
+
+static int __init jz4740_machine_setup(void)
+{
+ mips_machine_setup();
+
+ return 0;
+}
+arch_initcall(jz4740_machine_setup);
--
2.11.0

2017-12-28 13:57:57

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v4 15/15] MIPS: ingenic: Initial GCW Zero support

The GCW Zero (http://www.gcw-zero.com) is a retro-gaming focused
handheld game console, successfully kickstarted in ~2012, running Linux.

Signed-off-by: Paul Cercueil <[email protected]>
---
arch/mips/boot/dts/ingenic/Makefile | 1 +
arch/mips/boot/dts/ingenic/gcw0.dts | 60 +++++++++++++++++++++++++++++++++++++
arch/mips/configs/gcw0_defconfig | 28 +++++++++++++++++
arch/mips/jz4740/Kconfig | 4 +++
arch/mips/jz4740/boards.c | 1 +
5 files changed, 94 insertions(+)
create mode 100644 arch/mips/boot/dts/ingenic/gcw0.dts
create mode 100644 arch/mips/configs/gcw0_defconfig

v2: No change
v3: No change
v4: No change

diff --git a/arch/mips/boot/dts/ingenic/Makefile b/arch/mips/boot/dts/ingenic/Makefile
index 6a31759839b4..5b1361a89e02 100644
--- a/arch/mips/boot/dts/ingenic/Makefile
+++ b/arch/mips/boot/dts/ingenic/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
dtb-$(CONFIG_JZ4740_QI_LB60) += qi_lb60.dtb
+dtb-$(CONFIG_JZ4770_GCW0) += gcw0.dtb
dtb-$(CONFIG_JZ4780_CI20) += ci20.dtb

obj-y += $(patsubst %.dtb, %.dtb.o, $(dtb-y))
diff --git a/arch/mips/boot/dts/ingenic/gcw0.dts b/arch/mips/boot/dts/ingenic/gcw0.dts
new file mode 100644
index 000000000000..9c9a0137ccdf
--- /dev/null
+++ b/arch/mips/boot/dts/ingenic/gcw0.dts
@@ -0,0 +1,60 @@
+/dts-v1/;
+
+#include "jz4770.dtsi"
+
+/ {
+ compatible = "gcw,zero", "ingenic,jz4770";
+
+ aliases {
+ serial0 = &uart0;
+ serial1 = &uart1;
+ serial2 = &uart2;
+ serial3 = &uart3;
+ };
+
+ chosen {
+ stdout-path = "serial2:57600n8";
+ };
+
+ board {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges = <>;
+
+ otg_phy: otg-phy {
+ compatible = "usb-nop-xceiv";
+ clocks = <&cgu JZ4770_CLK_OTG_PHY>;
+ clock-names = "main_clk";
+ };
+ };
+};
+
+&ext {
+ clock-frequency = <12000000>;
+};
+
+&uart2 {
+ status = "okay";
+};
+
+&cgu {
+ /* Put high-speed peripherals under PLL1, such that we can change the
+ * PLL0 frequency on demand without having to suspend peripherals.
+ * We use a rate of 432 MHz, which is the least common multiple of
+ * 27 MHz (required by TV encoder) and 48 MHz (required by USB host).
+ */
+ assigned-clocks =
+ <&cgu JZ4770_CLK_PLL1>,
+ <&cgu JZ4770_CLK_UHC>;
+ assigned-clock-parents =
+ <0>,
+ <&cgu JZ4770_CLK_PLL1>;
+ assigned-clock-rates =
+ <432000000>;
+};
+
+&uhc {
+ /* The WiFi module is connected to the UHC. */
+ status = "okay";
+};
diff --git a/arch/mips/configs/gcw0_defconfig b/arch/mips/configs/gcw0_defconfig
new file mode 100644
index 000000000000..471497033855
--- /dev/null
+++ b/arch/mips/configs/gcw0_defconfig
@@ -0,0 +1,28 @@
+CONFIG_MACH_INGENIC=y
+CONFIG_JZ4770_GCW0=y
+CONFIG_HIGHMEM=y
+# CONFIG_BOUNCE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_SECCOMP is not set
+CONFIG_CROSS_COMPILE="mipsel-gcw0-linux-uclibc-"
+CONFIG_NO_HZ_IDLE=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_EMBEDDED=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_NETDEVICES=y
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_INGENIC=y
+CONFIG_USB=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_TMPFS=y
diff --git a/arch/mips/jz4740/Kconfig b/arch/mips/jz4740/Kconfig
index 29a9361a2b77..4dd0c446ecec 100644
--- a/arch/mips/jz4740/Kconfig
+++ b/arch/mips/jz4740/Kconfig
@@ -8,6 +8,10 @@ config JZ4740_QI_LB60
bool "Qi Hardware Ben NanoNote"
select MACH_JZ4740

+config JZ4770_GCW0
+ bool "Game Consoles Worldwide GCW Zero"
+ select MACH_JZ4770
+
config JZ4780_CI20
bool "MIPS Creator CI20"
select MACH_JZ4780
diff --git a/arch/mips/jz4740/boards.c b/arch/mips/jz4740/boards.c
index a3cf64cf004a..98a4d8e68cf0 100644
--- a/arch/mips/jz4740/boards.c
+++ b/arch/mips/jz4740/boards.c
@@ -12,5 +12,6 @@
#include <asm/mips_machine.h>

MIPS_MACHINE(MACH_INGENIC_JZ4740, "qi,lb60", "Qi Hardware Ben Nanonote", NULL);
+MIPS_MACHINE(MACH_INGENIC_JZ4770, "gcw,zero", "GCW Zero", NULL);
MIPS_MACHINE(MACH_INGENIC_JZ4780, "img,ci20",
"Imagination Technologies CI20", NULL);
--
2.11.0

2017-12-28 13:57:06

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v4 08/15] MIPS: ingenic: Use common cmdline handling code

From: Paul Burton <[email protected]>

jz4740_init_cmdline appends all arguments from argv (in fw_arg1) to
arcs_cmdline, up to argc (in fw_arg0). The common code in
fw_init_cmdline will do the exact same thing when run on a system where
fw_arg0 isn't a pointer to kseg0 (it'll also set _fw_envp but we don't
use it). Remove the custom implementation & use the generic code.

Signed-off-by: Paul Burton <[email protected]>
---
arch/mips/jz4740/prom.c | 24 ++----------------------
1 file changed, 2 insertions(+), 22 deletions(-)

v2: No change
v3: No change
v4: No change

diff --git a/arch/mips/jz4740/prom.c b/arch/mips/jz4740/prom.c
index 47e857194ce6..a62dd8e6ecf9 100644
--- a/arch/mips/jz4740/prom.c
+++ b/arch/mips/jz4740/prom.c
@@ -20,33 +20,13 @@
#include <linux/serial_reg.h>

#include <asm/bootinfo.h>
+#include <asm/fw/fw.h>
#include <asm/mach-jz4740/base.h>

-static __init void jz4740_init_cmdline(int argc, char *argv[])
-{
- unsigned int count = COMMAND_LINE_SIZE - 1;
- int i;
- char *dst = &(arcs_cmdline[0]);
- char *src;
-
- for (i = 1; i < argc && count; ++i) {
- src = argv[i];
- while (*src && count) {
- *dst++ = *src++;
- --count;
- }
- *dst++ = ' ';
- }
- if (i > 1)
- --dst;
-
- *dst = 0;
-}
-
void __init prom_init(void)
{
- jz4740_init_cmdline((int)fw_arg0, (char **)fw_arg1);
mips_machtype = MACH_INGENIC_JZ4740;
+ fw_init_cmdline();
}

void __init prom_free_prom_memory(void)
--
2.11.0

2017-12-28 13:57:03

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v4 09/15] MIPS: platform: add machtype IDs for more Ingenic SoCs

Add a machtype ID for the JZ4780 SoC, which was missing, and one for the
newly supported JZ4770 SoC.

Signed-off-by: Paul Cercueil <[email protected]>
---
arch/mips/include/asm/bootinfo.h | 2 ++
1 file changed, 2 insertions(+)

v2: No change
v3: No change
v4: No change

diff --git a/arch/mips/include/asm/bootinfo.h b/arch/mips/include/asm/bootinfo.h
index e26a093bb17a..a301a8f4bc66 100644
--- a/arch/mips/include/asm/bootinfo.h
+++ b/arch/mips/include/asm/bootinfo.h
@@ -79,6 +79,8 @@ enum loongson_machine_type {
*/
#define MACH_INGENIC_JZ4730 0 /* JZ4730 SOC */
#define MACH_INGENIC_JZ4740 1 /* JZ4740 SOC */
+#define MACH_INGENIC_JZ4770 2 /* JZ4770 SOC */
+#define MACH_INGENIC_JZ4780 3 /* JZ4780 SOC */

extern char *system_type;
const char *get_system_type(void);
--
2.11.0

2017-12-28 13:58:43

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v4 12/15] MIPS: JZ4770: Work around config2 misreporting associativity

From: Maarten ter Huurne <[email protected]>

According to config2, the associativity would be 5-ways, but the
documentation states 4-ways, which also matches the documented
L2 cache size of 256 kB.

Signed-off-by: Maarten ter Huurne <[email protected]>
---
arch/mips/mm/sc-mips.c | 9 +++++++++
1 file changed, 9 insertions(+)

v2: No change
v3: No change
v4: Rebased on top of Linux 4.15-rc5

diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c
index 548acb7f8557..394673991bab 100644
--- a/arch/mips/mm/sc-mips.c
+++ b/arch/mips/mm/sc-mips.c
@@ -16,6 +16,7 @@
#include <asm/mmu_context.h>
#include <asm/r4kcache.h>
#include <asm/mips-cps.h>
+#include <asm/bootinfo.h>

/*
* MIPS32/MIPS64 L2 cache handling
@@ -220,6 +221,14 @@ static inline int __init mips_sc_probe(void)
else
return 0;

+ /*
+ * According to config2 it would be 5-ways, but that is contradicted
+ * by all documentation.
+ */
+ if (current_cpu_type() == CPU_JZRISC &&
+ mips_machtype == MACH_INGENIC_JZ4770)
+ c->scache.ways = 4;
+
c->scache.waysize = c->scache.sets * c->scache.linesz;
c->scache.waybit = __ffs(c->scache.waysize);

--
2.11.0

2017-12-28 13:58:25

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v4 13/15] MIPS: JZ4770: Workaround for corrupted DMA transfers

From: Maarten ter Huurne <[email protected]>

We have seen MMC DMA transfers read corrupted data from SDRAM when
a burst interval ends at physical address 0x10000000. To avoid this
problem, we remove the final page of low memory from the memory map.

Signed-off-by: Maarten ter Huurne <[email protected]>
---
arch/mips/jz4740/setup.c | 24 ++++++++++++++++++++++++
arch/mips/kernel/setup.c | 8 ++++++++
2 files changed, 32 insertions(+)

v2: No change
v3: No change
v4: No change

diff --git a/arch/mips/jz4740/setup.c b/arch/mips/jz4740/setup.c
index afd84ee966e8..6948b133a15d 100644
--- a/arch/mips/jz4740/setup.c
+++ b/arch/mips/jz4740/setup.c
@@ -23,6 +23,7 @@

#include <asm/bootinfo.h>
#include <asm/mips_machine.h>
+#include <asm/page.h>
#include <asm/prom.h>

#include <asm/mach-jz4740/base.h>
@@ -102,6 +103,29 @@ void __init arch_init_irq(void)
irqchip_init();
}

+/*
+ * We have seen MMC DMA transfers read corrupted data from SDRAM when a burst
+ * interval ends at physical address 0x10000000. To avoid this problem, we
+ * remove the final page of low memory from the memory map.
+ */
+void __init jz4770_reserve_unsafe_for_dma(void)
+{
+ int i;
+
+ for (i = 0; i < boot_mem_map.nr_map; i++) {
+ struct boot_mem_map_entry *entry = boot_mem_map.map + i;
+
+ if (entry->type != BOOT_MEM_RAM)
+ continue;
+
+ if (entry->addr + entry->size != 0x10000000)
+ continue;
+
+ entry->size -= PAGE_SIZE;
+ break;
+ }
+}
+
static int __init jz4740_machine_setup(void)
{
mips_machine_setup();
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 85bc601e9a0d..5a2c20145aee 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -879,6 +879,14 @@ static void __init arch_mem_init(char **cmdline_p)

parse_early_param();

+#ifdef CONFIG_MACH_JZ4770
+ if (current_cpu_type() == CPU_JZRISC &&
+ mips_machtype == MACH_INGENIC_JZ4770) {
+ extern void __init jz4770_reserve_unsafe_for_dma(void);
+ jz4770_reserve_unsafe_for_dma();
+ }
+#endif
+
if (usermem) {
pr_info("User-defined physical RAM map:\n");
print_memory_map();
--
2.11.0

2017-12-28 13:59:01

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v4 11/15] MIPS: ingenic: Initial JZ4770 support

Provide just enough bits (clocks, clocksource, uart) to allow a kernel
to boot on the JZ4770 SoC to a initramfs userspace.

Signed-off-by: Paul Cercueil <[email protected]>
---
arch/mips/boot/dts/ingenic/jz4770.dtsi | 210 +++++++++++++++++++++++++++++++++
arch/mips/jz4740/Kconfig | 6 +
arch/mips/jz4740/time.c | 2 +-
3 files changed, 217 insertions(+), 1 deletion(-)
create mode 100644 arch/mips/boot/dts/ingenic/jz4770.dtsi

v2: No change
v3: No change
v4: No change

diff --git a/arch/mips/boot/dts/ingenic/jz4770.dtsi b/arch/mips/boot/dts/ingenic/jz4770.dtsi
new file mode 100644
index 000000000000..d8d0a741ff5d
--- /dev/null
+++ b/arch/mips/boot/dts/ingenic/jz4770.dtsi
@@ -0,0 +1,210 @@
+#include <dt-bindings/clock/jz4770-cgu.h>
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "ingenic,jz4770";
+
+ cpuintc: interrupt-controller {
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ compatible = "mti,cpu-interrupt-controller";
+ };
+
+ intc: interrupt-controller@10001000 {
+ compatible = "ingenic,jz4770-intc";
+ reg = <0x10001000 0x40>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpuintc>;
+ interrupts = <2>;
+ };
+
+ ext: ext {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ };
+
+ osc32k: osc32k {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ };
+
+ cgu: jz4770-cgu@10000000 {
+ compatible = "ingenic,jz4770-cgu";
+ reg = <0x10000000 0x100>;
+
+ clocks = <&ext>, <&osc32k>;
+ clock-names = "ext", "osc32k";
+
+ #clock-cells = <1>;
+ };
+
+ pinctrl: pin-controller@10010000 {
+ compatible = "ingenic,jz4770-pinctrl";
+ reg = <0x10010000 0x600>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ gpa: gpio@0 {
+ compatible = "ingenic,jz4770-gpio";
+ reg = <0>;
+
+ gpio-controller;
+ gpio-ranges = <&pinctrl 0 0 32>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <17>;
+ };
+
+ gpb: gpio@1 {
+ compatible = "ingenic,jz4770-gpio";
+ reg = <1>;
+
+ gpio-controller;
+ gpio-ranges = <&pinctrl 0 32 32>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <16>;
+ };
+
+ gpc: gpio@2 {
+ compatible = "ingenic,jz4770-gpio";
+ reg = <2>;
+
+ gpio-controller;
+ gpio-ranges = <&pinctrl 0 64 32>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <15>;
+ };
+
+ gpd: gpio@3 {
+ compatible = "ingenic,jz4770-gpio";
+ reg = <3>;
+
+ gpio-controller;
+ gpio-ranges = <&pinctrl 0 96 32>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <14>;
+ };
+
+ gpe: gpio@4 {
+ compatible = "ingenic,jz4770-gpio";
+ reg = <4>;
+
+ gpio-controller;
+ gpio-ranges = <&pinctrl 0 128 32>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <13>;
+ };
+
+ gpf: gpio@5 {
+ compatible = "ingenic,jz4770-gpio";
+ reg = <5>;
+
+ gpio-controller;
+ gpio-ranges = <&pinctrl 0 160 32>;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <12>;
+ };
+ };
+
+ uart0: serial@10030000 {
+ compatible = "ingenic,jz4770-uart";
+ reg = <0x10030000 0x100>;
+
+ clocks = <&ext>, <&cgu JZ4770_CLK_UART0>;
+ clock-names = "baud", "module";
+
+ interrupt-parent = <&intc>;
+ interrupts = <5>;
+
+ status = "disabled";
+ };
+
+ uart1: serial@10031000 {
+ compatible = "ingenic,jz4770-uart";
+ reg = <0x10031000 0x100>;
+
+ clocks = <&ext>, <&cgu JZ4770_CLK_UART1>;
+ clock-names = "baud", "module";
+
+ interrupt-parent = <&intc>;
+ interrupts = <4>;
+
+ status = "disabled";
+ };
+
+ uart2: serial@10032000 {
+ compatible = "ingenic,jz4770-uart";
+ reg = <0x10032000 0x100>;
+
+ clocks = <&ext>, <&cgu JZ4770_CLK_UART2>;
+ clock-names = "baud", "module";
+
+ interrupt-parent = <&intc>;
+ interrupts = <3>;
+
+ status = "disabled";
+ };
+
+ uart3: serial@10033000 {
+ compatible = "ingenic,jz4770-uart";
+ reg = <0x10033000 0x100>;
+
+ clocks = <&ext>, <&cgu JZ4770_CLK_UART3>;
+ clock-names = "baud", "module";
+
+ interrupt-parent = <&intc>;
+ interrupts = <2>;
+
+ status = "disabled";
+ };
+
+ uhc: uhc@13430000 {
+ compatible = "generic-ohci";
+ reg = <0x13430000 0x1000>;
+
+ clocks = <&cgu JZ4770_CLK_UHC>, <&cgu JZ4770_CLK_UHC_PHY>;
+ assigned-clocks = <&cgu JZ4770_CLK_UHC>;
+ assigned-clock-rates = <48000000>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <20>;
+
+ status = "disabled";
+ };
+};
diff --git a/arch/mips/jz4740/Kconfig b/arch/mips/jz4740/Kconfig
index 643af2012e14..29a9361a2b77 100644
--- a/arch/mips/jz4740/Kconfig
+++ b/arch/mips/jz4740/Kconfig
@@ -18,6 +18,12 @@ config MACH_JZ4740
bool
select SYS_HAS_CPU_MIPS32_R1

+config MACH_JZ4770
+ bool
+ select MIPS_CPU_SCACHE
+ select SYS_HAS_CPU_MIPS32_R2
+ select SYS_SUPPORTS_HIGHMEM
+
config MACH_JZ4780
bool
select MIPS_CPU_SCACHE
diff --git a/arch/mips/jz4740/time.c b/arch/mips/jz4740/time.c
index bb1ad5119da4..2ca9160f642a 100644
--- a/arch/mips/jz4740/time.c
+++ b/arch/mips/jz4740/time.c
@@ -113,7 +113,7 @@ static struct clock_event_device jz4740_clockevent = {
#ifdef CONFIG_MACH_JZ4740
.irq = JZ4740_IRQ_TCU0,
#endif
-#ifdef CONFIG_MACH_JZ4780
+#if defined(CONFIG_MACH_JZ4770) || defined(CONFIG_MACH_JZ4780)
.irq = JZ4780_IRQ_TCU2,
#endif
};
--
2.11.0

2017-12-28 13:59:40

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v4 07/15] MIPS: Setup boot_command_line before plat_mem_setup

From: Paul Burton <[email protected]>

Platforms using DT will typically call __dt_setup_arch from
plat_mem_setup. This in turn calls early_init_dt_scan. When
CONFIG_CMDLINE is set, this leads to its value being copied into
boot_command_line by early_init_dt_scan_chosen. If this happens before
the code setting up boot_command_line in arch_mem_init runs, that code
will go on to append CONFIG_CMDLINE (via builtin_cmdline) to
boot_command_line again, duplicating it. For some command line
parameters (eg. earlycon) this can be a problem. Set up
boot_command_line before early_init_dt_scan_chosen gets called such that
it will not write CONFIG_CMDLINE in this scenario & the arguments aren't
duplicated.

Signed-off-by: Paul Burton <[email protected]>
---
arch/mips/kernel/setup.c | 39 ++++++++++++++++++++-------------------
1 file changed, 20 insertions(+), 19 deletions(-)

v2: New patch in this series
v3: No change
v4: No change

diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 702c678de116..85bc601e9a0d 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -826,25 +826,6 @@ static void __init arch_mem_init(char **cmdline_p)
struct memblock_region *reg;
extern void plat_mem_setup(void);

- /* call board setup routine */
- plat_mem_setup();
-
- /*
- * Make sure all kernel memory is in the maps. The "UP" and
- * "DOWN" are opposite for initdata since if it crosses over
- * into another memory section you don't want that to be
- * freed when the initdata is freed.
- */
- arch_mem_addpart(PFN_DOWN(__pa_symbol(&_text)) << PAGE_SHIFT,
- PFN_UP(__pa_symbol(&_edata)) << PAGE_SHIFT,
- BOOT_MEM_RAM);
- arch_mem_addpart(PFN_UP(__pa_symbol(&__init_begin)) << PAGE_SHIFT,
- PFN_DOWN(__pa_symbol(&__init_end)) << PAGE_SHIFT,
- BOOT_MEM_INIT_RAM);
-
- pr_info("Determined physical RAM map:\n");
- print_memory_map();
-
#if defined(CONFIG_CMDLINE_BOOL) && defined(CONFIG_CMDLINE_OVERRIDE)
strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
#else
@@ -872,6 +853,26 @@ static void __init arch_mem_init(char **cmdline_p)
}
#endif
#endif
+
+ /* call board setup routine */
+ plat_mem_setup();
+
+ /*
+ * Make sure all kernel memory is in the maps. The "UP" and
+ * "DOWN" are opposite for initdata since if it crosses over
+ * into another memory section you don't want that to be
+ * freed when the initdata is freed.
+ */
+ arch_mem_addpart(PFN_DOWN(__pa_symbol(&_text)) << PAGE_SHIFT,
+ PFN_UP(__pa_symbol(&_edata)) << PAGE_SHIFT,
+ BOOT_MEM_RAM);
+ arch_mem_addpart(PFN_UP(__pa_symbol(&__init_begin)) << PAGE_SHIFT,
+ PFN_DOWN(__pa_symbol(&__init_end)) << PAGE_SHIFT,
+ BOOT_MEM_INIT_RAM);
+
+ pr_info("Determined physical RAM map:\n");
+ print_memory_map();
+
strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);

*cmdline_p = command_line;
--
2.11.0

2017-12-28 13:59:56

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v4 06/15] clk: Add Ingenic jz4770 CGU driver

Add support for the clocks provided by the CGU in the Ingenic JZ4770
SoC.

Signed-off-by: Paul Cercueil <[email protected]>
Signed-off-by: Maarten ter Huurne <[email protected]>
---
drivers/clk/ingenic/Makefile | 1 +
drivers/clk/ingenic/jz4770-cgu.c | 487 +++++++++++++++++++++++++++++++++++++++
2 files changed, 488 insertions(+)
create mode 100644 drivers/clk/ingenic/jz4770-cgu.c

v2: Make structures static const
v3: <dt-bindings/clock/jz4770-cgu.h> is now added in a separate patch
v4: No change

diff --git a/drivers/clk/ingenic/Makefile b/drivers/clk/ingenic/Makefile
index cd47b0664c2b..1456e4cdb562 100644
--- a/drivers/clk/ingenic/Makefile
+++ b/drivers/clk/ingenic/Makefile
@@ -1,3 +1,4 @@
obj-y += cgu.o
obj-$(CONFIG_MACH_JZ4740) += jz4740-cgu.o
+obj-$(CONFIG_MACH_JZ4770) += jz4770-cgu.o
obj-$(CONFIG_MACH_JZ4780) += jz4780-cgu.o
diff --git a/drivers/clk/ingenic/jz4770-cgu.c b/drivers/clk/ingenic/jz4770-cgu.c
new file mode 100644
index 000000000000..4b2411d8a491
--- /dev/null
+++ b/drivers/clk/ingenic/jz4770-cgu.c
@@ -0,0 +1,487 @@
+/*
+ * JZ4770 SoC CGU driver
+ *
+ * Copyright 2017, Paul Cercueil <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or later
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/syscore_ops.h>
+#include <dt-bindings/clock/jz4770-cgu.h>
+#include "cgu.h"
+
+/*
+ * CPM registers offset address definition
+ */
+#define CGU_REG_CPCCR 0x00
+#define CGU_REG_LCR 0x04
+#define CGU_REG_CPPCR0 0x10
+#define CGU_REG_CLKGR0 0x20
+#define CGU_REG_OPCR 0x24
+#define CGU_REG_CLKGR1 0x28
+#define CGU_REG_CPPCR1 0x30
+#define CGU_REG_USBPCR1 0x48
+#define CGU_REG_USBCDR 0x50
+#define CGU_REG_I2SCDR 0x60
+#define CGU_REG_LPCDR 0x64
+#define CGU_REG_MSC0CDR 0x68
+#define CGU_REG_UHCCDR 0x6c
+#define CGU_REG_SSICDR 0x74
+#define CGU_REG_CIMCDR 0x7c
+#define CGU_REG_GPSCDR 0x80
+#define CGU_REG_PCMCDR 0x84
+#define CGU_REG_GPUCDR 0x88
+#define CGU_REG_MSC1CDR 0xA4
+#define CGU_REG_MSC2CDR 0xA8
+#define CGU_REG_BCHCDR 0xAC
+
+/* bits within the LCR register */
+#define LCR_LPM BIT(0) /* Low Power Mode */
+
+/* bits within the OPCR register */
+#define OPCR_SPENDH BIT(5) /* UHC PHY suspend */
+#define OPCR_SPENDN BIT(7) /* OTG PHY suspend */
+
+/* bits within the USBPCR1 register */
+#define USBPCR1_UHC_POWER BIT(5) /* UHC PHY power down */
+
+static struct ingenic_cgu *cgu;
+
+static int jz4770_uhc_phy_enable(struct clk_hw *hw)
+{
+ void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
+ void __iomem *reg_usbpcr1 = cgu->base + CGU_REG_USBPCR1;
+
+ writel(readl(reg_opcr) & ~OPCR_SPENDH, reg_opcr);
+ writel(readl(reg_usbpcr1) | USBPCR1_UHC_POWER, reg_usbpcr1);
+ return 0;
+}
+
+static void jz4770_uhc_phy_disable(struct clk_hw *hw)
+{
+ void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
+ void __iomem *reg_usbpcr1 = cgu->base + CGU_REG_USBPCR1;
+
+ writel(readl(reg_usbpcr1) & ~USBPCR1_UHC_POWER, reg_usbpcr1);
+ writel(readl(reg_opcr) | OPCR_SPENDH, reg_opcr);
+}
+
+static int jz4770_uhc_phy_is_enabled(struct clk_hw *hw)
+{
+ void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
+ void __iomem *reg_usbpcr1 = cgu->base + CGU_REG_USBPCR1;
+
+ return !(readl(reg_opcr) & OPCR_SPENDH) &&
+ (readl(reg_usbpcr1) & USBPCR1_UHC_POWER);
+}
+
+static const struct clk_ops jz4770_uhc_phy_ops = {
+ .enable = jz4770_uhc_phy_enable,
+ .disable = jz4770_uhc_phy_disable,
+ .is_enabled = jz4770_uhc_phy_is_enabled,
+};
+
+static int jz4770_otg_phy_enable(struct clk_hw *hw)
+{
+ void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
+
+ writel(readl(reg_opcr) | OPCR_SPENDN, reg_opcr);
+
+ /* Wait for the clock to be stable */
+ udelay(50);
+ return 0;
+}
+
+static void jz4770_otg_phy_disable(struct clk_hw *hw)
+{
+ void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
+
+ writel(readl(reg_opcr) & ~OPCR_SPENDN, reg_opcr);
+}
+
+static int jz4770_otg_phy_is_enabled(struct clk_hw *hw)
+{
+ void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
+
+ return !!(readl(reg_opcr) & OPCR_SPENDN);
+}
+
+static const struct clk_ops jz4770_otg_phy_ops = {
+ .enable = jz4770_otg_phy_enable,
+ .disable = jz4770_otg_phy_disable,
+ .is_enabled = jz4770_otg_phy_is_enabled,
+};
+
+static const s8 pll_od_encoding[8] = {
+ 0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
+};
+
+static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
+
+ /* External clocks */
+
+ [JZ4770_CLK_EXT] = { "ext", CGU_CLK_EXT },
+ [JZ4770_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },
+
+ /* PLLs */
+
+ [JZ4770_CLK_PLL0] = {
+ "pll0", CGU_CLK_PLL,
+ .parents = { JZ4770_CLK_EXT },
+ .pll = {
+ .reg = CGU_REG_CPPCR0,
+ .m_shift = 24,
+ .m_bits = 7,
+ .m_offset = 1,
+ .n_shift = 18,
+ .n_bits = 5,
+ .n_offset = 1,
+ .od_shift = 16,
+ .od_bits = 2,
+ .od_max = 8,
+ .od_encoding = pll_od_encoding,
+ .bypass_bit = 9,
+ .enable_bit = 8,
+ .stable_bit = 10,
+ },
+ },
+
+ [JZ4770_CLK_PLL1] = {
+ /* TODO: PLL1 can depend on PLL0 */
+ "pll1", CGU_CLK_PLL,
+ .parents = { JZ4770_CLK_EXT },
+ .pll = {
+ .reg = CGU_REG_CPPCR1,
+ .m_shift = 24,
+ .m_bits = 7,
+ .m_offset = 1,
+ .n_shift = 18,
+ .n_bits = 5,
+ .n_offset = 1,
+ .od_shift = 16,
+ .od_bits = 2,
+ .od_max = 8,
+ .od_encoding = pll_od_encoding,
+ .enable_bit = 7,
+ .stable_bit = 6,
+ .no_bypass_bit = true,
+ },
+ },
+
+ /* Main clocks */
+
+ [JZ4770_CLK_CCLK] = {
+ "cclk", CGU_CLK_DIV,
+ .parents = { JZ4770_CLK_PLL0, },
+ .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 },
+ },
+ [JZ4770_CLK_H0CLK] = {
+ "h0clk", CGU_CLK_DIV,
+ .parents = { JZ4770_CLK_PLL0, },
+ .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 },
+ },
+ [JZ4770_CLK_H1CLK] = {
+ "h1clk", CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_PLL0, },
+ .div = { CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1 },
+ .gate = { CGU_REG_LCR, 30 },
+ },
+ [JZ4770_CLK_H2CLK] = {
+ "h2clk", CGU_CLK_DIV,
+ .parents = { JZ4770_CLK_PLL0, },
+ .div = { CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1 },
+ },
+ [JZ4770_CLK_C1CLK] = {
+ "c1clk", CGU_CLK_DIV,
+ .parents = { JZ4770_CLK_PLL0, },
+ .div = { CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1 },
+ },
+ [JZ4770_CLK_PCLK] = {
+ "pclk", CGU_CLK_DIV,
+ .parents = { JZ4770_CLK_PLL0, },
+ .div = { CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1 },
+ },
+
+ /* Those divided clocks can connect to PLL0 or PLL1 */
+
+ [JZ4770_CLK_MMC0_MUX] = {
+ "mmc0_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_MSC0CDR, 30, 1 },
+ .div = { CGU_REG_MSC0CDR, 0, 1, 7, -1, -1, 31 },
+ .gate = { CGU_REG_MSC0CDR, 31 },
+ },
+ [JZ4770_CLK_MMC1_MUX] = {
+ "mmc1_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_MSC1CDR, 30, 1 },
+ .div = { CGU_REG_MSC1CDR, 0, 1, 7, -1, -1, 31 },
+ .gate = { CGU_REG_MSC1CDR, 31 },
+ },
+ [JZ4770_CLK_MMC2_MUX] = {
+ "mmc2_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_MSC2CDR, 30, 1 },
+ .div = { CGU_REG_MSC2CDR, 0, 1, 7, -1, -1, 31 },
+ .gate = { CGU_REG_MSC2CDR, 31 },
+ },
+ [JZ4770_CLK_CIM] = {
+ "cim", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_CIMCDR, 31, 1 },
+ .div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 26 },
+ },
+ [JZ4770_CLK_UHC] = {
+ "uhc", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_UHCCDR, 29, 1 },
+ .div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 24 },
+ },
+ [JZ4770_CLK_GPU] = {
+ "gpu", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, -1 },
+ .mux = { CGU_REG_GPUCDR, 31, 1 },
+ .div = { CGU_REG_GPUCDR, 0, 1, 3, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR1, 9 },
+ },
+ [JZ4770_CLK_BCH] = {
+ "bch", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_BCHCDR, 31, 1 },
+ .div = { CGU_REG_BCHCDR, 0, 1, 3, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 1 },
+ },
+ [JZ4770_CLK_LPCLK_MUX] = {
+ "lpclk", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_LPCDR, 29, 1 },
+ .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 28 },
+ },
+ [JZ4770_CLK_GPS] = {
+ "gps", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
+ .mux = { CGU_REG_GPSCDR, 31, 1 },
+ .div = { CGU_REG_GPSCDR, 0, 1, 4, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 22 },
+ },
+
+ /* Those divided clocks can connect to EXT, PLL0 or PLL1 */
+
+ [JZ4770_CLK_SSI_MUX] = {
+ "ssi_mux", CGU_CLK_DIV | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_EXT, -1,
+ JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
+ .mux = { CGU_REG_SSICDR, 30, 2 },
+ .div = { CGU_REG_SSICDR, 0, 1, 6, -1, -1, -1 },
+ },
+ [JZ4770_CLK_PCM_MUX] = {
+ "pcm_mux", CGU_CLK_DIV | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_EXT, -1,
+ JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
+ .mux = { CGU_REG_PCMCDR, 30, 2 },
+ .div = { CGU_REG_PCMCDR, 0, 1, 9, -1, -1, -1 },
+ },
+ [JZ4770_CLK_I2S] = {
+ "i2s", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_EXT, -1,
+ JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
+ .mux = { CGU_REG_I2SCDR, 30, 2 },
+ .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR1, 13 },
+ },
+ [JZ4770_CLK_OTG] = {
+ "usb", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_EXT, -1,
+ JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
+ .mux = { CGU_REG_USBCDR, 30, 2 },
+ .div = { CGU_REG_USBCDR, 0, 1, 8, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 2 },
+ },
+
+ /* Gate-only clocks */
+
+ [JZ4770_CLK_SSI0] = {
+ "ssi0", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_SSI_MUX, },
+ .gate = { CGU_REG_CLKGR0, 4 },
+ },
+ [JZ4770_CLK_SSI1] = {
+ "ssi1", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_SSI_MUX, },
+ .gate = { CGU_REG_CLKGR0, 19 },
+ },
+ [JZ4770_CLK_SSI2] = {
+ "ssi2", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_SSI_MUX, },
+ .gate = { CGU_REG_CLKGR0, 20 },
+ },
+ [JZ4770_CLK_PCM0] = {
+ "pcm0", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_PCM_MUX, },
+ .gate = { CGU_REG_CLKGR1, 8 },
+ },
+ [JZ4770_CLK_PCM1] = {
+ "pcm1", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_PCM_MUX, },
+ .gate = { CGU_REG_CLKGR1, 10 },
+ },
+ [JZ4770_CLK_DMA] = {
+ "dma", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_H2CLK, },
+ .gate = { CGU_REG_CLKGR0, 21 },
+ },
+ [JZ4770_CLK_I2C0] = {
+ "i2c0", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 5 },
+ },
+ [JZ4770_CLK_I2C1] = {
+ "i2c1", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 6 },
+ },
+ [JZ4770_CLK_I2C2] = {
+ "i2c2", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR1, 15 },
+ },
+ [JZ4770_CLK_UART0] = {
+ "uart0", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 15 },
+ },
+ [JZ4770_CLK_UART1] = {
+ "uart1", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 16 },
+ },
+ [JZ4770_CLK_UART2] = {
+ "uart2", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 17 },
+ },
+ [JZ4770_CLK_UART3] = {
+ "uart3", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 18 },
+ },
+ [JZ4770_CLK_IPU] = {
+ "ipu", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_H0CLK, },
+ .gate = { CGU_REG_CLKGR0, 29 },
+ },
+ [JZ4770_CLK_ADC] = {
+ "adc", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 14 },
+ },
+ [JZ4770_CLK_AIC] = {
+ "aic", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 8 },
+ },
+ [JZ4770_CLK_AUX] = {
+ "aux", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_C1CLK, },
+ .gate = { CGU_REG_CLKGR1, 14 },
+ },
+ [JZ4770_CLK_VPU] = {
+ "vpu", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_H1CLK, },
+ .gate = { CGU_REG_CLKGR1, 7 },
+ },
+ [JZ4770_CLK_MMC0] = {
+ "mmc0", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_MMC0_MUX, },
+ .gate = { CGU_REG_CLKGR0, 3 },
+ },
+ [JZ4770_CLK_MMC1] = {
+ "mmc1", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_MMC1_MUX, },
+ .gate = { CGU_REG_CLKGR0, 11 },
+ },
+ [JZ4770_CLK_MMC2] = {
+ "mmc2", CGU_CLK_GATE,
+ .parents = { JZ4770_CLK_MMC2_MUX, },
+ .gate = { CGU_REG_CLKGR0, 12 },
+ },
+
+ /* Custom clocks */
+
+ [JZ4770_CLK_UHC_PHY] = {
+ "uhc_phy", CGU_CLK_CUSTOM,
+ .parents = { JZ4770_CLK_UHC, -1, -1, -1 },
+ .custom = { &jz4770_uhc_phy_ops },
+ },
+ [JZ4770_CLK_OTG_PHY] = {
+ "usb_phy", CGU_CLK_CUSTOM,
+ .parents = { JZ4770_CLK_OTG, -1, -1, -1 },
+ .custom = { &jz4770_otg_phy_ops },
+ },
+
+ [JZ4770_CLK_EXT512] = {
+ "ext/512", CGU_CLK_FIXDIV,
+ .parents = { JZ4770_CLK_EXT },
+ .fixdiv = { 512 },
+ },
+
+ [JZ4770_CLK_RTC] = {
+ "rtc", CGU_CLK_MUX,
+ .parents = { JZ4770_CLK_EXT512, JZ4770_CLK_OSC32K, },
+ .mux = { CGU_REG_OPCR, 2, 1},
+ },
+};
+
+#if IS_ENABLED(CONFIG_PM_SLEEP)
+static int jz4770_cgu_pm_suspend(void)
+{
+ u32 val;
+
+ val = readl(cgu->base + CGU_REG_LCR);
+ writel(val | LCR_LPM, cgu->base + CGU_REG_LCR);
+ return 0;
+}
+
+static void jz4770_cgu_pm_resume(void)
+{
+ u32 val;
+
+ val = readl(cgu->base + CGU_REG_LCR);
+ writel(val & ~LCR_LPM, cgu->base + CGU_REG_LCR);
+}
+
+static struct syscore_ops jz4770_cgu_pm_ops = {
+ .suspend = jz4770_cgu_pm_suspend,
+ .resume = jz4770_cgu_pm_resume,
+};
+#endif /* CONFIG_PM_SLEEP */
+
+static void __init jz4770_cgu_init(struct device_node *np)
+{
+ int retval;
+
+ cgu = ingenic_cgu_new(jz4770_cgu_clocks,
+ ARRAY_SIZE(jz4770_cgu_clocks), np);
+ if (!cgu)
+ pr_err("%s: failed to initialise CGU\n", __func__);
+
+ retval = ingenic_cgu_register_clocks(cgu);
+ if (retval)
+ pr_err("%s: failed to register CGU Clocks\n", __func__);
+
+#if IS_ENABLED(CONFIG_PM_SLEEP)
+ register_syscore_ops(&jz4770_cgu_pm_ops);
+#endif
+}
+
+/* We only probe via devicetree, no need for a platform driver */
+CLK_OF_DECLARE(jz4770_cgu, "ingenic,jz4770-cgu", jz4770_cgu_init);
--
2.11.0

2017-12-28 13:56:56

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v4 03/15] clk: ingenic: support PLLs with no bypass bit

The second PLL of the JZ4770 does not have a bypass bit.
This commit makes it possible to support it with the current common CGU
code.

Signed-off-by: Paul Cercueil <[email protected]>
---
drivers/clk/ingenic/cgu.c | 3 ++-
drivers/clk/ingenic/cgu.h | 2 ++
2 files changed, 4 insertions(+), 1 deletion(-)

v2: No change
v3: No change
v4: No change

diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
index a2e73a6d60fd..381c4a17a1fc 100644
--- a/drivers/clk/ingenic/cgu.c
+++ b/drivers/clk/ingenic/cgu.c
@@ -100,7 +100,8 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
n += pll_info->n_offset;
od_enc = ctl >> pll_info->od_shift;
od_enc &= GENMASK(pll_info->od_bits - 1, 0);
- bypass = !!(ctl & BIT(pll_info->bypass_bit));
+ bypass = !pll_info->no_bypass_bit &&
+ !!(ctl & BIT(pll_info->bypass_bit));
enable = !!(ctl & BIT(pll_info->enable_bit));

if (bypass)
diff --git a/drivers/clk/ingenic/cgu.h b/drivers/clk/ingenic/cgu.h
index f1527cf75b3f..9da34910bd80 100644
--- a/drivers/clk/ingenic/cgu.h
+++ b/drivers/clk/ingenic/cgu.h
@@ -48,6 +48,7 @@
* @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
+ * @no_bypass_bit: if set, the PLL has no bypass functionality
*/
struct ingenic_cgu_pll_info {
unsigned reg;
@@ -58,6 +59,7 @@ struct ingenic_cgu_pll_info {
u8 bypass_bit;
u8 enable_bit;
u8 stable_bit;
+ bool no_bypass_bit;
};

/**
--
2.11.0

2017-12-28 13:56:54

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v4 02/15] clk: ingenic: Fix recalc_rate for clocks with fixed divider

Previously, the clocks with a fixed divider would report their rate
as being the same as the one of their parent, independently of the
divider in use. This commit fixes this behaviour.

This went unnoticed as neither the jz4740 nor the jz4780 CGU code
have clocks with fixed dividers yet.

Signed-off-by: Paul Cercueil <[email protected]>
---
drivers/clk/ingenic/cgu.c | 2 ++
1 file changed, 2 insertions(+)

v2: No changes
v3: No changes
v4: No changes

diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
index ab393637f7b0..a2e73a6d60fd 100644
--- a/drivers/clk/ingenic/cgu.c
+++ b/drivers/clk/ingenic/cgu.c
@@ -328,6 +328,8 @@ ingenic_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
div *= clk_info->div.div;

rate /= div;
+ } else if (clk_info->type & CGU_CLK_FIXDIV) {
+ rate /= clk_info->fixdiv.div;
}

return rate;
--
2.11.0

2017-12-28 14:00:48

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v4 04/15] clk: ingenic: Add code to enable/disable PLLs

This commit permits the PLLs to be dynamically enabled and disabled when
their children clocks are enabled and disabled.

Signed-off-by: Paul Cercueil <[email protected]>
---
drivers/clk/ingenic/cgu.c | 89 +++++++++++++++++++++++++++++++++++++++--------
1 file changed, 74 insertions(+), 15 deletions(-)

v2: No change
v3: No change
v4: No change

diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
index 381c4a17a1fc..56a712c9075f 100644
--- a/drivers/clk/ingenic/cgu.c
+++ b/drivers/clk/ingenic/cgu.c
@@ -107,9 +107,6 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
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;
@@ -153,17 +150,25 @@ ingenic_pll_calc(const struct ingenic_cgu_clk_info *clk_info,
return div_u64((u64)parent_rate * m, n * od);
}

-static long
-ingenic_pll_round_rate(struct clk_hw *hw, unsigned long req_rate,
- unsigned long *prate)
+static inline const struct ingenic_cgu_clk_info *to_clk_info(
+ struct ingenic_clk *ingenic_clk)
{
- struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
struct ingenic_cgu *cgu = ingenic_clk->cgu;
const struct ingenic_cgu_clk_info *clk_info;

clk_info = &cgu->clock_info[ingenic_clk->idx];
BUG_ON(clk_info->type != CGU_CLK_PLL);

+ return clk_info;
+}
+
+static long
+ingenic_pll_round_rate(struct clk_hw *hw, unsigned long req_rate,
+ unsigned long *prate)
+{
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
+ const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
+
return ingenic_pll_calc(clk_info, req_rate, *prate, NULL, NULL, NULL);
}

@@ -171,19 +176,14 @@ static int
ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
unsigned long parent_rate)
{
- const unsigned timeout = 100;
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
struct ingenic_cgu *cgu = ingenic_clk->cgu;
- const struct ingenic_cgu_clk_info *clk_info;
- const struct ingenic_cgu_pll_info *pll_info;
+ const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
+ const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
unsigned long rate, flags;
- unsigned m, n, od, i;
+ unsigned int m, n, od;
u32 ctl;

- clk_info = &cgu->clock_info[ingenic_clk->idx];
- BUG_ON(clk_info->type != CGU_CLK_PLL);
- pll_info = &clk_info->pll;
-
rate = ingenic_pll_calc(clk_info, req_rate, parent_rate,
&m, &n, &od);
if (rate != req_rate)
@@ -202,6 +202,26 @@ ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
ctl &= ~(GENMASK(pll_info->od_bits - 1, 0) << pll_info->od_shift);
ctl |= pll_info->od_encoding[od - 1] << pll_info->od_shift;

+ writel(ctl, cgu->base + pll_info->reg);
+ spin_unlock_irqrestore(&cgu->lock, flags);
+
+ return 0;
+}
+
+static int ingenic_pll_enable(struct clk_hw *hw)
+{
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
+ struct ingenic_cgu *cgu = ingenic_clk->cgu;
+ const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
+ const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
+ const unsigned int timeout = 100;
+ unsigned long flags;
+ unsigned int i;
+ u32 ctl;
+
+ spin_lock_irqsave(&cgu->lock, flags);
+ ctl = readl(cgu->base + pll_info->reg);
+
ctl &= ~BIT(pll_info->bypass_bit);
ctl |= BIT(pll_info->enable_bit);

@@ -223,10 +243,48 @@ ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
return 0;
}

+static void ingenic_pll_disable(struct clk_hw *hw)
+{
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
+ struct ingenic_cgu *cgu = ingenic_clk->cgu;
+ const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
+ const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
+ unsigned long flags;
+ u32 ctl;
+
+ spin_lock_irqsave(&cgu->lock, flags);
+ ctl = readl(cgu->base + pll_info->reg);
+
+ ctl &= ~BIT(pll_info->enable_bit);
+
+ writel(ctl, cgu->base + pll_info->reg);
+ spin_unlock_irqrestore(&cgu->lock, flags);
+}
+
+static int ingenic_pll_is_enabled(struct clk_hw *hw)
+{
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
+ struct ingenic_cgu *cgu = ingenic_clk->cgu;
+ const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
+ const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
+ unsigned long flags;
+ u32 ctl;
+
+ spin_lock_irqsave(&cgu->lock, flags);
+ ctl = readl(cgu->base + pll_info->reg);
+ spin_unlock_irqrestore(&cgu->lock, flags);
+
+ return !!(ctl & BIT(pll_info->enable_bit));
+}
+
static const struct clk_ops ingenic_pll_ops = {
.recalc_rate = ingenic_pll_recalc_rate,
.round_rate = ingenic_pll_round_rate,
.set_rate = ingenic_pll_set_rate,
+
+ .enable = ingenic_pll_enable,
+ .disable = ingenic_pll_disable,
+ .is_enabled = ingenic_pll_is_enabled,
};

/*
@@ -601,6 +659,7 @@ static int ingenic_register_clock(struct ingenic_cgu *cgu, unsigned idx)
}
} else if (caps & CGU_CLK_PLL) {
clk_init.ops = &ingenic_pll_ops;
+ clk_init.flags |= CLK_SET_RATE_GATE;

caps &= ~CGU_CLK_PLL;

--
2.11.0

2017-12-28 14:01:16

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v4 00/15] Ingenic JZ4770 and GCW Zero support

Hi,

This is my v4 of my patch series to support the JZ4770 SoC from Ingenic
as well as the GCW Zero handheld console.

Not much changed since v3, I dropped the three serial-related patches
(07-08-09/18) as I will submit them separately. The only other change is
that I rebased the patch series on top of v4.15-rc5.

Regards,
-Paul Cercueil

2017-12-28 18:36:10

by Stephen Boyd

[permalink] [raw]
Subject: Re: [PATCH v4 02/15] clk: ingenic: Fix recalc_rate for clocks with fixed divider

On 12/28, Paul Cercueil wrote:
> Previously, the clocks with a fixed divider would report their rate
> as being the same as the one of their parent, independently of the
> divider in use. This commit fixes this behaviour.
>
> This went unnoticed as neither the jz4740 nor the jz4780 CGU code
> have clocks with fixed dividers yet.
>
> Signed-off-by: Paul Cercueil <[email protected]>
> ---

Acked-by: Stephen Boyd <[email protected]>

--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

2017-12-28 18:36:20

by Stephen Boyd

[permalink] [raw]
Subject: Re: [PATCH v4 03/15] clk: ingenic: support PLLs with no bypass bit

On 12/28, Paul Cercueil wrote:
> The second PLL of the JZ4770 does not have a bypass bit.
> This commit makes it possible to support it with the current common CGU
> code.
>
> Signed-off-by: Paul Cercueil <[email protected]>
> ---

Acked-by: Stephen Boyd <[email protected]>

--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

2017-12-28 18:36:48

by Stephen Boyd

[permalink] [raw]
Subject: Re: [PATCH v4 05/15] dt-bindings: clock: Add jz4770-cgu.h header

On 12/28, Paul Cercueil wrote:
> This will be used from the devicetree bindings to specify the clocks
> that should be obtained from the jz4770-cgu driver.
>
> Signed-off-by: Paul Cercueil <[email protected]>
> ---

Acked-by: Stephen Boyd <[email protected]>

--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

2017-12-28 18:38:39

by Stephen Boyd

[permalink] [raw]
Subject: Re: [PATCH v4 06/15] clk: Add Ingenic jz4770 CGU driver

On 12/28, Paul Cercueil wrote:
> Add support for the clocks provided by the CGU in the Ingenic JZ4770
> SoC.
>
> Signed-off-by: Paul Cercueil <[email protected]>
> Signed-off-by: Maarten ter Huurne <[email protected]>
> ---

Acked-by: Stephen Boyd <[email protected]>

--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

2017-12-28 18:39:44

by Stephen Boyd

[permalink] [raw]
Subject: Re: [PATCH v4 04/15] clk: ingenic: Add code to enable/disable PLLs

On 12/28, Paul Cercueil wrote:
> This commit permits the PLLs to be dynamically enabled and disabled when
> their children clocks are enabled and disabled.
>
> Signed-off-by: Paul Cercueil <[email protected]>
> ---

Acked-by: Stephen Boyd <[email protected]>

--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

2017-12-29 12:55:57

by Philippe Ombredanne

[permalink] [raw]
Subject: Re: [PATCH v4 06/15] clk: Add Ingenic jz4770 CGU driver

Dear Mr Crapouillou-Cercueil-Sir,

On Thu, Dec 28, 2017 at 2:56 PM, Paul Cercueil <[email protected]> wrote:
> Add support for the clocks provided by the CGU in the Ingenic JZ4770
> SoC.

<snip>

> --- /dev/null
> +++ b/drivers/clk/ingenic/jz4770-cgu.c
> @@ -0,0 +1,487 @@
> +/*
> + * JZ4770 SoC CGU driver
> + *
> + * Copyright 2017, Paul Cercueil <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 or later
> + * as published by the Free Software Foundation.
> + */

Do you mind using a simpler one-line SPDX identifier instead of this
fine but clearly crapouillish legalese boilerplate? Unless you are
trying to turn the kernel in a legal compendium, of course ;)

This is documented in Thomas doc patches. This would apply to your
entire patch set.
Thank you for your kind consideration!
--
Cordially
Philippe Ombredanne

2017-12-29 15:02:31

by Paul Cercueil

[permalink] [raw]
Subject: Re: [PATCH v4 06/15] clk: Add Ingenic jz4770 CGU driver


Dear Mr. Ombredanne,

Le ven. 29 d?c. 2017 ? 13:55, Philippe Ombredanne
<[email protected]> a ?crit :
> Dear Mr Crapouillou-Cercueil-Sir,
>
> On Thu, Dec 28, 2017 at 2:56 PM, Paul Cercueil <[email protected]>
> wrote:
>> Add support for the clocks provided by the CGU in the Ingenic JZ4770
>> SoC.
>
> <snip>
>
>> --- /dev/null
>> +++ b/drivers/clk/ingenic/jz4770-cgu.c
>> @@ -0,0 +1,487 @@
>> +/*
>> + * JZ4770 SoC CGU driver
>> + *
>> + * Copyright 2017, Paul Cercueil <[email protected]>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> modify
>> + * it under the terms of the GNU General Public License version 2
>> or later
>> + * as published by the Free Software Foundation.
>> + */
>
> Do you mind using a simpler one-line SPDX identifier instead of this
> fine but clearly crapouillish legalese boilerplate? Unless you are
> trying to turn the kernel in a legal compendium, of course ;)
>
> This is documented in Thomas doc patches. This would apply to your
> entire patch set.
> Thank you for your kind consideration!

Sure, I wasn't aware about that new SPDX identifier thing. I'll do it
in V5.

Regards,
-Paul