Devicetree
 help / color / mirror / Atom feed
* [PATCH 07/21] MIPS memblock: Alter elfcorehdr parameters parser
From: Serge Semin @ 2016-12-19  2:07 UTC (permalink / raw)
  To: ralf, paul.burton, rabinv, matt.redfearn, james.hogan,
	alexander.sverdlin, robh+dt, frowand.list
  Cc: Sergey.Semin, linux-mips, devicetree, linux-kernel, Serge Semin
In-Reply-To: <1482113266-13207-1-git-send-email-fancer.lancer@gmail.com>

Memblock API can be successfully used to verify whether elfcorehdr
memory region belongs to lowmemory, then it can be reserved within
memblock allocator. There is also available default method for
early parameters parser in kernel/crash_dump.c: setup_elfcorehdr(),
so it's wise to use one instead of creating our own doing actually
the same thing.

Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
---
 arch/mips/kernel/setup.c | 91 +++++++++++++++++-------------
 1 file changed, 52 insertions(+), 39 deletions(-)

diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index cc6d06b..52205fb 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -426,6 +426,55 @@ static void __init mips_reserve_initrd_mem(void) { }
 
 #endif
 
+/*
+ * Reserve memory occupied by elfcorehdr
+ */
+static void __init mips_reserve_elfcorehdr(void)
+{
+#ifdef CONFIG_PROC_VMCORE
+	/*
+	 * Don't reserve anything if kernel isn't booting after a panic and
+	 * vmcore is usable (see linux/crash_dump.h for details)
+	 */
+	if (!is_vmcore_usable())
+		return;
+
+	/* Check whether the passed address belongs to low memory */
+	if (elfcorehdr_addr + elfcorehdr_size >= mips_lowmem_limit) {
+		pr_err("Elfcorehdr %08zx @ %pa doesn't belong to low memory",
+			(size_t)elfcorehdr_size, &elfcorehdr_addr);
+		return;
+	}
+
+	/*
+	 * If elfcorehdr_size hasn't been specified, then try to reserve upto
+	 * low memory limit
+	 */
+	if (!elfcorehdr_size)
+		elfcorehdr_size = mips_lowmem_limit - elfcorehdr_addr;
+
+	/* Check the region belongs to actual memory (size can be zero) */
+	if (!memblock_is_region_memory(elfcorehdr_addr, elfcorehdr_size)) {
+		pr_err("Elfcorehdr %08zx @ %pa is not a memory region",
+			(size_t)elfcorehdr_size, &elfcorehdr_addr);
+		return;
+	}
+
+	/* Check whether elfcorehdr region is free */
+	if (memblock_is_region_reserved(elfcorehdr_addr, elfcorehdr_size)) {
+		pr_err("Elfcorehdr %08zx @ %pa overlaps in-use memory",
+			(size_t)elfcorehdr_size, &elfcorehdr_addr);
+		return;
+	}
+
+	/* Reserve elfcorehdr within memblock */
+	memblock_reserve(elfcorehdr_addr, PAGE_ALIGN(elfcorehdr_size));
+
+	pr_info("Reserved memory for kdump at %08zx @ %pa\n",
+		(size_t)elfcorehdr_size, &elfcorehdr_addr);
+#endif /* CONFIG_PROC_VMCORE */
+}
+
 #ifdef CONFIG_KEXEC
 /*
  * Parse passed crashkernel parameter and reserve corresponding memory
@@ -499,6 +548,9 @@ static void __init bootmem_init(void)
 	/* Check and reserve memory occupied by initrd */
 	mips_reserve_initrd_mem();
 
+	/* Reserve memory for elfcorehdr */
+	mips_reserve_elfcorehdr();
+
 	/* Parse crashkernel parameter */
 	mips_parse_crashkernel();
 
@@ -719,37 +771,6 @@ static void __init bootmem_init(void)
  * initialization hook for anything else was introduced.
  */
 
-#ifdef CONFIG_PROC_VMCORE
-unsigned long setup_elfcorehdr, setup_elfcorehdr_size;
-static int __init early_parse_elfcorehdr(char *p)
-{
-	int i;
-
-	setup_elfcorehdr = memparse(p, &p);
-
-	for (i = 0; i < boot_mem_map.nr_map; i++) {
-		unsigned long start = boot_mem_map.map[i].addr;
-		unsigned long end = (boot_mem_map.map[i].addr +
-				     boot_mem_map.map[i].size);
-		if (setup_elfcorehdr >= start && setup_elfcorehdr < end) {
-			/*
-			 * Reserve from the elf core header to the end of
-			 * the memory segment, that should all be kdump
-			 * reserved memory.
-			 */
-			setup_elfcorehdr_size = end - setup_elfcorehdr;
-			break;
-		}
-	}
-	/*
-	 * If we don't find it in the memory map, then we shouldn't
-	 * have to worry about it, as the new kernel won't use it.
-	 */
-	return 0;
-}
-early_param("elfcorehdr", early_parse_elfcorehdr);
-#endif
-
 static void __init arch_mem_addpart(phys_addr_t mem, phys_addr_t end, int type)
 {
 	phys_addr_t size;
@@ -833,14 +854,6 @@ static void __init arch_mem_init(char **cmdline_p)
 	parse_early_param();
 
 	bootmem_init();
-#ifdef CONFIG_PROC_VMCORE
-	if (setup_elfcorehdr && setup_elfcorehdr_size) {
-		printk(KERN_INFO "kdump reserved memory at %lx-%lx\n",
-		       setup_elfcorehdr, setup_elfcorehdr_size);
-		reserve_bootmem(setup_elfcorehdr, setup_elfcorehdr_size,
-				BOOTMEM_DEFAULT);
-	}
-#endif
 
 	device_tree_init();
 	sparse_init();
-- 
2.6.6

^ permalink raw reply related

* [PATCH 06/21] MIPS memblock: Alter kexec-crashkernel parameters parser
From: Serge Semin @ 2016-12-19  2:07 UTC (permalink / raw)
  To: ralf, paul.burton, rabinv, matt.redfearn, james.hogan,
	alexander.sverdlin, robh+dt, frowand.list
  Cc: Sergey.Semin, linux-mips, devicetree, linux-kernel, Serge Semin
In-Reply-To: <1482113266-13207-1-git-send-email-fancer.lancer@gmail.com>

Memblock API can be successfully used to verify whether crashkernel
memory region belongs to low memory, then it can be reserved within
memblock allocator.

Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
---
 arch/mips/kernel/setup.c | 105 ++++++++++++++---------------
 1 file changed, 52 insertions(+), 53 deletions(-)

diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index d2f38ac..cc6d06b 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -426,6 +426,55 @@ static void __init mips_reserve_initrd_mem(void) { }
 
 #endif
 
+#ifdef CONFIG_KEXEC
+/*
+ * Parse passed crashkernel parameter and reserve corresponding memory
+ */
+static void __init mips_parse_crashkernel(void)
+{
+	unsigned long long total_mem;
+	unsigned long long crash_size, crash_base;
+	int ret;
+
+	/* Parse crachkernel parameter */
+	total_mem = memblock_phys_mem_size();
+	ret = parse_crashkernel(boot_command_line, total_mem,
+				&crash_size, &crash_base);
+	if (ret != 0 || crash_size <= 0)
+		return;
+
+	crashk_res.start = crash_base;
+	crashk_res.end	 = crash_base + crash_size - 1;
+
+	/* Check whether the region belogs to lowmem and valid */
+	if (!is_lowmem_and_valid("Crashkernel", crash_base, crash_size))
+		return;
+
+	/* Reserve crashkernel resource */
+	memblock_reserve(crash_base, crash_size);
+}
+
+/*
+ * Reserve crashkernel memory within passed RAM resource
+ */
+static void __init request_crashkernel(struct resource *res)
+{
+	int ret;
+
+	ret = request_resource(res, &crashk_res);
+	if (!ret)
+		pr_info("Reserving %ldMB of memory at %ldMB for crashkernel\n",
+			(unsigned long)((crashk_res.end -
+					 crashk_res.start + 1) >> 20),
+			(unsigned long)(crashk_res.start  >> 20));
+}
+#else /* !CONFIG_KEXEC */
+
+static void __init mips_parse_crashkernel(void) { }
+static void __init request_crashkernel(struct resource *res) { }
+
+#endif /* !CONFIG_KEXEC */
+
 /*
  * Initialize the bootmem allocator. It also setup initrd related data
  * if needed.
@@ -450,6 +499,9 @@ static void __init bootmem_init(void)
 	/* Check and reserve memory occupied by initrd */
 	mips_reserve_initrd_mem();
 
+	/* Parse crashkernel parameter */
+	mips_parse_crashkernel();
+
 	reserved_end = (unsigned long) PFN_UP(__pa_symbol(&_end));
 
 	/*
@@ -717,52 +769,6 @@ static void __init arch_mem_addpart(phys_addr_t mem, phys_addr_t end, int type)
 	add_memory_region(mem, size, type);
 }
 
-#ifdef CONFIG_KEXEC
-static inline unsigned long long get_total_mem(void)
-{
-	unsigned long long total;
-
-	total = max_pfn - min_low_pfn;
-	return total << PAGE_SHIFT;
-}
-
-static void __init mips_parse_crashkernel(void)
-{
-	unsigned long long total_mem;
-	unsigned long long crash_size, crash_base;
-	int ret;
-
-	total_mem = get_total_mem();
-	ret = parse_crashkernel(boot_command_line, total_mem,
-				&crash_size, &crash_base);
-	if (ret != 0 || crash_size <= 0)
-		return;
-
-	crashk_res.start = crash_base;
-	crashk_res.end	 = crash_base + crash_size - 1;
-}
-
-static void __init request_crashkernel(struct resource *res)
-{
-	int ret;
-
-	ret = request_resource(res, &crashk_res);
-	if (!ret)
-		pr_info("Reserving %ldMB of memory at %ldMB for crashkernel\n",
-			(unsigned long)((crashk_res.end -
-					 crashk_res.start + 1) >> 20),
-			(unsigned long)(crashk_res.start  >> 20));
-}
-#else /* !defined(CONFIG_KEXEC)		*/
-static void __init mips_parse_crashkernel(void)
-{
-}
-
-static void __init request_crashkernel(struct resource *res)
-{
-}
-#endif /* !defined(CONFIG_KEXEC)  */
-
 #define USE_PROM_CMDLINE	IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER)
 #define USE_DTB_CMDLINE		IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_DTB)
 #define EXTEND_WITH_PROM	IS_ENABLED(CONFIG_MIPS_CMDLINE_DTB_EXTEND)
@@ -836,13 +842,6 @@ static void __init arch_mem_init(char **cmdline_p)
 	}
 #endif
 
-	mips_parse_crashkernel();
-#ifdef CONFIG_KEXEC
-	if (crashk_res.start != crashk_res.end)
-		reserve_bootmem(crashk_res.start,
-				crashk_res.end - crashk_res.start + 1,
-				BOOTMEM_DEFAULT);
-#endif
 	device_tree_init();
 	sparse_init();
 	plat_swiotlb_setup();
-- 
2.6.6

^ permalink raw reply related

* [PATCH 05/21] MIPS memblock: Alter initrd memory reservation method
From: Serge Semin @ 2016-12-19  2:07 UTC (permalink / raw)
  To: ralf, paul.burton, rabinv, matt.redfearn, james.hogan,
	alexander.sverdlin, robh+dt, frowand.list
  Cc: Sergey.Semin, linux-mips, devicetree, linux-kernel, Serge Semin
In-Reply-To: <1482113266-13207-1-git-send-email-fancer.lancer@gmail.com>

Since memblock is used, initrd memory region can be easily
verified and reserved if looks ok. Verification method will be
useful for other reservation methods.

Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
---
 arch/mips/kernel/setup.c | 157 ++++++++++++++++-------------
 1 file changed, 87 insertions(+), 70 deletions(-)

diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 789aafe..d2f38ac 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -82,6 +82,8 @@ static struct resource data_resource = { .name = "Kernel data", };
 
 static void *detect_magic __initdata = detect_memory_region;
 
+static phys_addr_t __initdata mips_lowmem_limit;
+
 /*
  * General method to add RAM regions to the system
  *
@@ -266,6 +268,38 @@ static int __init early_parse_mem(char *p)
 early_param("mem", early_parse_mem);
 
 /*
+ * Helper method checking whether passed lowmem region is valid
+ */
+static bool __init is_lowmem_and_valid(const char *name, phys_addr_t base,
+				       phys_addr_t size)
+{
+	phys_addr_t end = base + size;
+
+	/* Check whether region belongs to actual memory */
+	if (!memblock_is_region_memory(base, size)) {
+		pr_err("%s %08zx @ %pa is not a memory region", name,
+			(size_t)size, &base);
+		return false;
+	}
+
+	/* Check whether region belongs to low memory */
+	if (end > mips_lowmem_limit) {
+		pr_err("%s %08zx @ %pa is out of low memory", name,
+			(size_t)size, &base);
+	       return false;
+	}
+
+	/* Check whether region is free */
+	if (memblock_is_region_reserved(base, size)) {
+		pr_err("%s %08zx @ %pa overlaps in-use memory", name,
+			(size_t)size, &base);
+		return false;
+	}
+
+	return true;
+}
+
+/*
  * Manage initrd
  */
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -292,47 +326,6 @@ static int __init rd_size_early(char *p)
 }
 early_param("rd_size", rd_size_early);
 
-/* it returns the next free pfn after initrd */
-static unsigned long __init init_initrd(void)
-{
-	unsigned long end;
-
-	/*
-	 * Board specific code or command line parser should have
-	 * already set up initrd_start and initrd_end. In these cases
-	 * perfom sanity checks and use them if all looks good.
-	 */
-	if (!initrd_start || initrd_end <= initrd_start)
-		goto disable;
-
-	if (initrd_start & ~PAGE_MASK) {
-		pr_err("initrd start must be page aligned\n");
-		goto disable;
-	}
-	if (initrd_start < PAGE_OFFSET) {
-		pr_err("initrd start < PAGE_OFFSET\n");
-		goto disable;
-	}
-
-	/*
-	 * Sanitize initrd addresses. For example firmware
-	 * can't guess if they need to pass them through
-	 * 64-bits values if the kernel has been built in pure
-	 * 32-bit. We need also to switch from KSEG0 to XKPHYS
-	 * addresses now, so the code can now safely use __pa().
-	 */
-	end = __pa(initrd_end);
-	initrd_end = (unsigned long)__va(end);
-	initrd_start = (unsigned long)__va(__pa(initrd_start));
-
-	ROOT_DEV = Root_RAM0;
-	return PFN_UP(end);
-disable:
-	initrd_start = 0;
-	initrd_end = 0;
-	return 0;
-}
-
 /* In some conditions (e.g. big endian bootloader with a little endian
    kernel), the initrd might appear byte swapped.  Try to detect this and
    byte swap it if needed.  */
@@ -362,26 +355,64 @@ static void __init maybe_bswap_initrd(void)
 #endif
 }
 
-static void __init finalize_initrd(void)
+/*
+ * Check and reserve memory occupied by initrd
+ */
+static void __init mips_reserve_initrd_mem(void)
 {
-	unsigned long size = initrd_end - initrd_start;
+	phys_addr_t phys_initrd_start, phys_initrd_end, phys_initrd_size;
 
-	if (size == 0) {
-		printk(KERN_INFO "Initrd not found or empty");
+	/*
+	 * Board specific code or command line parser should have already set
+	 * up initrd_start and initrd_end. In these cases perform sanity checks
+	 * and use them if all looks good.
+	 */
+	if (!initrd_start || initrd_end <= initrd_start) {
+		pr_info("No initrd found");
 		goto disable;
 	}
-	if (__pa(initrd_end) > PFN_PHYS(max_low_pfn)) {
-		printk(KERN_ERR "Initrd extends beyond end of memory");
+	if (initrd_start & ~PAGE_MASK) {
+		pr_err("Initrd start must be page aligned");
 		goto disable;
 	}
+	if (initrd_start < PAGE_OFFSET) {
+		pr_err("Initrd start < PAGE_OFFSET");
+		goto disable;
+	}
+
+	/*
+	 * Sanitize initrd addresses. For example firmware can't guess if they
+	 * need to pass them through 64-bits values if the kernel has been
+	 * built in pure 32-bit. We need also to switch from KSEG0 to XKPHYS
+	 * addresses now, so the code can now safely use __pa().
+	 */
+	phys_initrd_start = __pa(initrd_start);
+	phys_initrd_end = __pa(initrd_end);
+	phys_initrd_size = phys_initrd_end - phys_initrd_start;
 
+	/* Check whether initrd region is within available lowmem and free */
+	if (!is_lowmem_and_valid("Initrd", phys_initrd_start, phys_initrd_size))
+		goto disable;
+
+	/* Initrd may be byteswapped in Octeon */
 	maybe_bswap_initrd();
 
-	reserve_bootmem(__pa(initrd_start), size, BOOTMEM_DEFAULT);
+	/* Memory for initrd can be reserved now */
+	memblock_reserve(phys_initrd_start, phys_initrd_size);
+
+	/* Convert initrd to virtual addresses back (needed for x32 -> x64) */
+	initrd_start = (unsigned long)__va(phys_initrd_start);
+	initrd_end = (unsigned long)__va(phys_initrd_end);
+
+	/* It's OK to have initrd below actual memory start. Really? */
 	initrd_below_start_ok = 1;
 
-	pr_info("Initial ramdisk at: 0x%lx (%lu bytes)\n",
-		initrd_start, size);
+	pr_info("Initial ramdisk at: 0x%lx (%zu bytes)\n",
+		initrd_start, (size_t)phys_initrd_size);
+
+	/* Set root device to be first ram disk */
+	ROOT_DEV = Root_RAM0;
+
 	return;
 disable:
 	printk(KERN_CONT " - disabling initrd\n");
@@ -391,12 +422,7 @@ disable:
 
 #else  /* !CONFIG_BLK_DEV_INITRD */
 
-static unsigned long __init init_initrd(void)
-{
-	return 0;
-}
-
-#define finalize_initrd()	do {} while (0)
+static void __init mips_reserve_initrd_mem(void) { }
 
 #endif
 
@@ -408,8 +434,8 @@ static unsigned long __init init_initrd(void)
 
 static void __init bootmem_init(void)
 {
-	init_initrd();
-	finalize_initrd();
+	/* Check and reserve memory occupied by initrd */
+	mips_reserve_initrd_mem();
 }
 
 #else  /* !CONFIG_SGI_IP27 */
@@ -421,13 +447,9 @@ static void __init bootmem_init(void)
 	unsigned long bootmap_size;
 	int i;
 
-	/*
-	 * Sanity check any INITRD first. We don't take it into account
-	 * for bootmem setup initially, rely on the end-of-kernel-code
-	 * as our memory range starting point. Once bootmem is inited we
-	 * will reserve the area used for the initrd.
-	 */
-	init_initrd();
+	/* Check and reserve memory occupied by initrd */
+	mips_reserve_initrd_mem();
+
 	reserved_end = (unsigned long) PFN_UP(__pa_symbol(&_end));
 
 	/*
@@ -618,11 +640,6 @@ static void __init bootmem_init(void)
 #endif
 	}
 #endif
-
-	/*
-	 * Reserve initrd memory if needed.
-	 */
-	finalize_initrd();
 }
 
 #endif	/* CONFIG_SGI_IP27 */
-- 
2.6.6

^ permalink raw reply related

* [PATCH 04/21] MIPS memblock: Alter user-defined memory parameter parser
From: Serge Semin @ 2016-12-19  2:07 UTC (permalink / raw)
  To: ralf, paul.burton, rabinv, matt.redfearn, james.hogan,
	alexander.sverdlin, robh+dt, frowand.list
  Cc: Sergey.Semin, linux-mips, devicetree, linux-kernel, Serge Semin
In-Reply-To: <1482113266-13207-1-git-send-email-fancer.lancer@gmail.com>

Both new memblock and boot_mem_map subsystems need to be fully
cleared before a new memory region is added. So the early parser is
correspondingly modified.

Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
---
 arch/mips/kernel/setup.c | 67 +++++++++++++++++-------------
 1 file changed, 37 insertions(+), 30 deletions(-)

diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 9da6f8a..789aafe 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -229,6 +229,43 @@ static void __init print_memory_map(void)
 }
 
 /*
+ * Parse "mem=size@start" parameter rewriting a defined memory map
+ * We look for mem=size@start, where start and size are "value[KkMm]"
+ */
+static int __init early_parse_mem(char *p)
+{
+	static int usermem;
+	phys_addr_t start, size;
+
+	start = PHYS_OFFSET;
+	size = memparse(p, &p);
+	if (*p == '@')
+		start = memparse(p + 1, &p);
+
+	/*
+	 * If a user specifies memory size, we blow away any automatically
+	 * generated regions.
+	 */
+	if (usermem == 0) {
+		phys_addr_t ram_start = memblock_start_of_DRAM();
+		phys_addr_t ram_end = memblock_end_of_DRAM() - ram_start;
+
+		pr_notice("Discard memory layout %pa - %pa",
+			  &ram_start, &ram_end);
+
+		memblock_remove(ram_start, ram_end - ram_start);
+		boot_mem_map.nr_map = 0;
+		usermem = 1;
+	}
+	pr_notice("Add userdefined memory region %08zx @ %pa",
+		  (size_t)size, &start);
+
+	add_memory_region(start, size, BOOT_MEM_RAM);
+	return 0;
+}
+early_param("mem", early_parse_mem);
+
+/*
  * Manage initrd
  */
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -613,31 +650,6 @@ static void __init bootmem_init(void)
  * initialization hook for anything else was introduced.
  */
 
-static int usermem __initdata;
-
-static int __init early_parse_mem(char *p)
-{
-	phys_addr_t start, size;
-
-	/*
-	 * If a user specifies memory size, we
-	 * blow away any automatically generated
-	 * size.
-	 */
-	if (usermem == 0) {
-		boot_mem_map.nr_map = 0;
-		usermem = 1;
-	}
-	start = 0;
-	size = memparse(p, &p);
-	if (*p == '@')
-		start = memparse(p + 1, &p);
-
-	add_memory_region(start, size, BOOT_MEM_RAM);
-	return 0;
-}
-early_param("mem", early_parse_mem);
-
 #ifdef CONFIG_PROC_VMCORE
 unsigned long setup_elfcorehdr, setup_elfcorehdr_size;
 static int __init early_parse_elfcorehdr(char *p)
@@ -797,11 +809,6 @@ static void __init arch_mem_init(char **cmdline_p)
 
 	parse_early_param();
 
-	if (usermem) {
-		pr_info("User-defined physical RAM map:\n");
-		print_memory_map();
-	}
-
 	bootmem_init();
 #ifdef CONFIG_PROC_VMCORE
 	if (setup_elfcorehdr && setup_elfcorehdr_size) {
-- 
2.6.6

^ permalink raw reply related

* [PATCH 03/21] MIPS memblock: Alter traditional add_memory_region() method
From: Serge Semin @ 2016-12-19  2:07 UTC (permalink / raw)
  To: ralf, paul.burton, rabinv, matt.redfearn, james.hogan,
	alexander.sverdlin, robh+dt, frowand.list
  Cc: Sergey.Semin, linux-mips, devicetree, linux-kernel, Serge Semin
In-Reply-To: <1482113266-13207-1-git-send-email-fancer.lancer@gmail.com>

There is no safe and fast way to get rid of boot_mem_map usage in
the wide set of platform code. But it's luck, that the architecture
specific code doesn't make any direct changes in the boot_mem_map
structure. Additionally the platform specific code registers the
available memory using traditional add_memory_region() method.
It's obvious, that one needs to be modified adding regions to both
new memblock allocator and old boot_mem_map subsystem. In this way
most of architecture specific code won't be broken.

Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
---
 arch/mips/kernel/setup.c | 51 ++++++++++++++++++++++++++++--
 1 file changed, 48 insertions(+), 3 deletions(-)

diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 084ba6c..9da6f8a 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -82,10 +82,19 @@ static struct resource data_resource = { .name = "Kernel data", };
 
 static void *detect_magic __initdata = detect_memory_region;
 
+/*
+ * General method to add RAM regions to the system
+ *
+ * NOTE Historically this method has been used to register memory blocks within
+ *      MIPS kernel code in the boot_mem_map array. So we need to support it
+ * up until it's discarded from platform-depended code.
+ * On the other hand it might be good to have it, since we can check regions
+ * before actually adding them
+ */
 void __init add_memory_region(phys_addr_t start, phys_addr_t size, long type)
 {
 	int x = boot_mem_map.nr_map;
-	int i;
+	int ret, i;
 
 	/*
 	 * If the region reaches the top of the physical address space, adjust
@@ -94,15 +103,51 @@ void __init add_memory_region(phys_addr_t start, phys_addr_t size, long type)
 	if (start + size - 1 == (phys_addr_t)ULLONG_MAX)
 		--size;
 
-	/* Sanity check */
+	/* Sanity check the region */
 	if (start + size < start) {
 		pr_warn("Trying to add an invalid memory region, skipped\n");
 		return;
 	}
 
+	/* Make sure the type is supported */
+	if (type != BOOT_MEM_RAM && type != BOOT_MEM_INIT_RAM &&
+	    type != BOOT_MEM_ROM_DATA && type != BOOT_MEM_RESERVED) {
+		pr_warn("Invalid type of memory region, skipped\n");
+		return;
+	}
+
 	/*
-	 * Try to merge with existing entry, if any.
+	 * According to the request_resource logic RAM, INIT and ROM shouldn't
+	 * intersect each other but being subset of one memory space
 	 */
+	if (type != BOOT_MEM_RESERVED && memblock_is_memory(start)) {
+		pr_warn("Drop already added memory region %08zx @ %pa\n",
+			(size_t)size, &start);
+		return;
+	}
+
+	/*
+	 * Add the region to the memblock allocator. Reserved regions should be
+	 * in the memory as well to be actually reserved.
+	 */
+	ret = memblock_add_node(start, size, 0);
+	if (ret < 0) {
+		pr_err("Could't add memblock %08zx @ %pa\n",
+			(size_t)size, &start);
+		return;
+	}
+
+	/* Reserve memory region passed with the corresponding flags */
+	if (type != BOOT_MEM_RAM) {
+		ret = memblock_reserve(start, size);
+		if (ret < 0) {
+			pr_err("Could't reserve memblock %08zx @ %pa\n",
+				(size_t)size, &start);
+			return;
+		}
+	}
+
+	/* Try to combine with existing entry, if any. */
 	for (i = 0; i < boot_mem_map.nr_map; i++) {
 		struct boot_mem_map_entry *entry = boot_mem_map.map + i;
 		unsigned long top;
-- 
2.6.6

^ permalink raw reply related

* [PATCH 02/21] MIPS memblock: Add dts mem and reserved-mem callbacks
From: Serge Semin @ 2016-12-19  2:07 UTC (permalink / raw)
  To: ralf-6z/3iImG2C8G8FEW9MqTrA, paul.burton-1AXoQHu6uovQT0dZR+AlfA,
	rabinv-VrBV9hrLPhE, matt.redfearn-1AXoQHu6uovQT0dZR+AlfA,
	james.hogan-1AXoQHu6uovQT0dZR+AlfA,
	alexander.sverdlin-xNZwKgViW5gAvxtiuMwx3w,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w
  Cc: Sergey.Semin-vHJ8rsvMqnUPfZBKTuL5GA,
	linux-mips-6z/3iImG2C8G8FEW9MqTrA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Serge Semin
In-Reply-To: <1482113266-13207-1-git-send-email-fancer.lancer-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

In order to get a structured table of platform devices, it is
widespread amongst modern systems to use fdt'es.
MIPS should support one as well. Particularly /memory/ and
/reserved-memory/ should be analyzed and corresponding regions
registered with memblock subsystem.

Signed-off-by: Serge Semin <fancer.lancer-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 arch/mips/kernel/prom.c | 32 ++++++++++++++++++++++++++++++-
 1 file changed, 31 insertions(+), 1 deletion(-)

diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c
index 5fcec30..f21eb8c 100644
--- a/arch/mips/kernel/prom.c
+++ b/arch/mips/kernel/prom.c
@@ -17,6 +17,7 @@
 #include <linux/of.h>
 #include <linux/of_fdt.h>
 #include <linux/of_platform.h>
+#include <linux/memblock.h>
 
 #include <asm/bootinfo.h>
 #include <asm/page.h>
@@ -41,7 +42,36 @@ char *mips_get_machine_name(void)
 #ifdef CONFIG_USE_OF
 void __init early_init_dt_add_memory_arch(u64 base, u64 size)
 {
-	return add_memory_region(base, size, BOOT_MEM_RAM);
+	/* Check whether specified region is well formed */
+	if (sanity_check_dt_memory(&base, &size))
+		return;
+
+	/* Memory region should be in boot_mem_map, so use the old method */
+	add_memory_region(base, size, BOOT_MEM_RAM);
+}
+
+int __init early_init_dt_reserve_memory_arch(phys_addr_t base,
+					     phys_addr_t size, bool nomap)
+{
+	/*
+	 * NOTE We don't use add_memory_region() method here, since fdt
+	 * reserved-memory regions are declared within already added memory,
+	 * while boot_mem_map consists of unique regions
+	 */
+
+	/* Check whether region is free. If so just ignore it */
+	if (memblock_is_region_reserved(base, size)) {
+		pr_err("FDT reserve-node %08zx @ %pa overlaps in-use memory\n",
+			(size_t)size, &base);
+		return -EBUSY;
+	}
+
+	/* If it can be mapped, then just reserve the region */
+	if (!nomap)
+		return memblock_reserve(base, size);
+
+	/* Completely remove region if it shouldn't be mapped */
+	return memblock_remove(base, size);
 }
 
 void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
-- 
2.6.6

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH 01/21] MIPS memblock: Unpin dts memblock sanity check method
From: Serge Semin @ 2016-12-19  2:07 UTC (permalink / raw)
  To: ralf, paul.burton, rabinv, matt.redfearn, james.hogan,
	alexander.sverdlin, robh+dt, frowand.list
  Cc: Sergey.Semin, linux-mips, devicetree, linux-kernel, Serge Semin
In-Reply-To: <1482113266-13207-1-git-send-email-fancer.lancer@gmail.com>

It's necessary to check whether retrieved from dts memory regions
fits to page alignment and limits restrictions. Sometimes it is
necessary to perform the same checks, but ito add the memory regions
into a different subsystem. MIPS is going to be that case.

Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
---
 drivers/of/fdt.c       | 47 +++++++++++++++++++++++---------
 include/linux/of_fdt.h |  1 +
 2 files changed, 35 insertions(+), 13 deletions(-)

diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 1f98156..1ee958f 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -983,44 +983,65 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
 #define MAX_MEMBLOCK_ADDR	((phys_addr_t)~0)
 #endif
 
-void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
+int __init sanity_check_dt_memory(phys_addr_t *out_base,
+				  phys_addr_t *out_size)
 {
+	phys_addr_t base = *out_base, size = *out_size;
 	const u64 phys_offset = MIN_MEMBLOCK_ADDR;
 
 	if (!PAGE_ALIGNED(base)) {
 		if (size < PAGE_SIZE - (base & ~PAGE_MASK)) {
-			pr_warn("Ignoring memory block 0x%llx - 0x%llx\n",
+			pr_err("Memblock 0x%llx - 0x%llx isn't page aligned\n",
 				base, base + size);
-			return;
+			return -EINVAL;
 		}
+		pr_warn("Memblock 0x%llx - 0x%llx shifted to ",
+			base, base + size);
 		size -= PAGE_SIZE - (base & ~PAGE_MASK);
 		base = PAGE_ALIGN(base);
+		pr_cont("0x%llx - 0x%llx\n", base, base + size);
 	}
 	size &= PAGE_MASK;
 
 	if (base > MAX_MEMBLOCK_ADDR) {
-		pr_warning("Ignoring memory block 0x%llx - 0x%llx\n",
-				base, base + size);
-		return;
+		pr_err("Memblock 0x%llx - 0x%llx exceeds max address\n",
+			base, base + size);
+		return -EINVAL;
 	}
 
 	if (base + size - 1 > MAX_MEMBLOCK_ADDR) {
-		pr_warning("Ignoring memory range 0x%llx - 0x%llx\n",
-				((u64)MAX_MEMBLOCK_ADDR) + 1, base + size);
+		pr_warn("Memblock 0x%llx - 0x%llx truncated to ",
+			base, base + size);
 		size = MAX_MEMBLOCK_ADDR - base + 1;
+		pr_cont("0x%llx - 0x%llx\n", base, base + size);
 	}
 
 	if (base + size < phys_offset) {
-		pr_warning("Ignoring memory block 0x%llx - 0x%llx\n",
-			   base, base + size);
-		return;
+		pr_err("Memblock 0x%llx - 0x%llx is below phys offset\n",
+			base, base + size);
+		return -EINVAL;
 	}
+
 	if (base < phys_offset) {
-		pr_warning("Ignoring memory range 0x%llx - 0x%llx\n",
-			   base, phys_offset);
+		pr_warn("Memblock 0x%llx - 0x%llx truncated to ",
+			base, base + size);
 		size -= phys_offset - base;
 		base = phys_offset;
+		pr_cont("0x%llx - 0x%llx\n", base, base + size);
 	}
+
+	/* Set the output base address and size */
+	*out_base = base;
+	*out_size = size;
+
+	return 0;
+}
+
+void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
+{
+	if (sanity_check_dt_memory(&base, &size))
+		return;
+
 	memblock_add(base, size);
 }
 
diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
index df9ef38..ddf93c5 100644
--- a/include/linux/of_fdt.h
+++ b/include/linux/of_fdt.h
@@ -84,6 +84,7 @@ extern const void *of_flat_dt_match_machine(const void *default_match,
 		const void * (*get_next_compat)(const char * const**));
 
 /* Other Prototypes */
+extern int sanity_check_dt_memory(phys_addr_t *base, phys_addr_t *size);
 extern void unflatten_device_tree(void);
 extern void unflatten_and_copy_device_tree(void);
 extern void early_init_devtree(void *);
-- 
2.6.6

^ permalink raw reply related

* [PATCH 00/21] MIPS memblock: Remove bootmem code and switch to NO_BOOTMEM
From: Serge Semin @ 2016-12-19  2:07 UTC (permalink / raw)
  To: ralf, paul.burton, rabinv, matt.redfearn, james.hogan,
	alexander.sverdlin, robh+dt, frowand.list
  Cc: Sergey.Semin, linux-mips, devicetree, linux-kernel, Serge Semin

Most of the modern platforms supported by linux kernel have already
been cleaned up of old bootmem allocator by moving to nobootmem
interface wrapping up the memblock. This patchset is the first
attempt to do the similar improvement for MIPS for UMA systems
only.

Even though the porting was performed as much careful as possible
there still might be problem with support of some platforms,
especially Loonson3 or SGI IP27, which perform early memory manager
initialization by their self.

The patchset is split so individual patch being consistent in
functional and buildable ways. But the MIPS early memory manager
will work correctly only either with or without the whole set being
applied. For the same reason a reviewer should not pay much attention
to methods bootmem_init(), arch_mem_init(), paging_init() and
mem_init() until they are fully refactored.

The patchset is applied on top of kernel v4.9.

Signed-off-by: Serge Semin <fancer.lancer@gmail.com>

Serge Semin (21):
  MIPS memblock: Unpin dts memblock sanity check method
  MIPS memblock: Add dts mem and reserved-mem callbacks
  MIPS memblock: Alter traditional add_memory_region() method
  MIPS memblock: Alter user-defined memory parameter parser
  MIPS memblock: Alter initrd memory reservation method
  MIPS memblock: Alter kexec-crashkernel parameters parser
  MIPS memblock: Alter elfcorehdr parameters parser
  MIPS memblock: Move kernel parameters parser into individual method
  MIPS memblock: Move kernel memory reservation to individual method
  MIPS memblock: Discard bootmem allocator initialization
  MIPS memblock: Add memblock sanity check method
  MIPS memblock: Add memblock print outs in debug
  MIPS memblock: Add memblock allocator initialization
  MIPS memblock: Alter IO resources initialization method
  MIPS memblock: Alter weakened MAAR initialization method
  MIPS memblock: Alter paging initialization method
  MIPS memblock: Alter high memory freeing method
  MIPS memblock: Slightly improve buddy allocator init method
  MIPS memblock: Add print out method of kernel virtual memory layout
  MIPS memblock: Add free low memory test method call
  MIPS memblock: Deactivate old bootmem allocator

 arch/mips/Kconfig        |   2 +-
 arch/mips/kernel/prom.c  |  32 +-
 arch/mips/kernel/setup.c | 958 +++++++++++++++--------------
 arch/mips/mm/init.c      | 234 ++++---
 drivers/of/fdt.c         |  47 +-
 include/linux/of_fdt.h   |   1 +
 6 files changed, 739 insertions(+), 535 deletions(-)

-- 
2.6.6

^ permalink raw reply

* [PATCH v2 4/4] clk: rockchip: add new pll-type for rk3328
From: Elaine Zhang @ 2016-12-19  1:56 UTC (permalink / raw)
  To: heiko, mturquette, sboyd, xf
  Cc: robh+dt, mark.rutland, linux-clk, linux-arm-kernel, devicetree,
	huangtao, xxx, cl, linux-rockchip, linux-kernel, Elaine Zhang
In-Reply-To: <1482112573-11613-1-git-send-email-zhangqing@rock-chips.com>

The rk3328's pll and clock are similar with rk3036's,
it different with pll_mode_mask,there are different
control registers bit,
so these should be independent and separate from
the series of rk3328s.

Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
---
 drivers/clk/rockchip/clk-pll.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
index 6ed605776abd..9650c75f61d1 100644
--- a/drivers/clk/rockchip/clk-pll.c
+++ b/drivers/clk/rockchip/clk-pll.c
@@ -29,6 +29,7 @@
 #define PLL_MODE_SLOW		0x0
 #define PLL_MODE_NORM		0x1
 #define PLL_MODE_DEEP		0x2
+#define PLL_RK3328_MODE_MASK	0x1
 
 struct rockchip_clk_pll {
 	struct clk_hw		hw;
@@ -865,13 +866,17 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx,
 	pll_mux = &pll->pll_mux;
 	pll_mux->reg = ctx->reg_base + mode_offset;
 	pll_mux->shift = mode_shift;
-	pll_mux->mask = PLL_MODE_MASK;
+	if (pll_type == pll_rk3328)
+		pll_mux->mask = PLL_RK3328_MODE_MASK;
+	else
+		pll_mux->mask = PLL_MODE_MASK;
 	pll_mux->flags = 0;
 	pll_mux->lock = &ctx->lock;
 	pll_mux->hw.init = &init;
 
 	if (pll_type == pll_rk3036 ||
 	    pll_type == pll_rk3066 ||
+	    pll_type == pll_rk3328 ||
 	    pll_type == pll_rk3399)
 		pll_mux->flags |= CLK_MUX_HIWORD_MASK;
 
@@ -929,6 +934,12 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx,
 		else
 			init.ops = &rockchip_rk3066_pll_clk_ops;
 		break;
+	case pll_rk3328:
+		if (!pll->rate_table || IS_ERR(ctx->grf))
+			init.ops = &rockchip_rk3036_pll_clk_norate_ops;
+		else
+			init.ops = &rockchip_rk3036_pll_clk_ops;
+		break;
 	case pll_rk3399:
 		if (!pll->rate_table)
 			init.ops = &rockchip_rk3399_pll_clk_norate_ops;
-- 
1.9.1

^ permalink raw reply related

* [PATCH v2 3/4] clk: rockchip: add clock controller for rk3328
From: Elaine Zhang @ 2016-12-19  1:56 UTC (permalink / raw)
  To: heiko, mturquette, sboyd, xf
  Cc: robh+dt, mark.rutland, linux-clk, linux-arm-kernel, devicetree,
	huangtao, xxx, cl, linux-rockchip, linux-kernel, Elaine Zhang
In-Reply-To: <1482112573-11613-1-git-send-email-zhangqing@rock-chips.com>

Add the clock tree definition for the new rk3328 SoC.

Changes in v2:
  fix up these *_sample error description.

Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
---
 drivers/clk/rockchip/Makefile     |    1 +
 drivers/clk/rockchip/clk-rk3328.c | 1068 +++++++++++++++++++++++++++++++++++++
 drivers/clk/rockchip/clk.h        |   23 +
 3 files changed, 1092 insertions(+)
 create mode 100644 drivers/clk/rockchip/clk-rk3328.c

diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile
index 16e098c36f90..68b04bfca282 100644
--- a/drivers/clk/rockchip/Makefile
+++ b/drivers/clk/rockchip/Makefile
@@ -16,5 +16,6 @@ obj-y	+= clk-rk3036.o
 obj-y	+= clk-rk3188.o
 obj-y	+= clk-rk3228.o
 obj-y	+= clk-rk3288.o
+obj-y	+= clk-rk3328.o
 obj-y	+= clk-rk3368.o
 obj-y	+= clk-rk3399.o
diff --git a/drivers/clk/rockchip/clk-rk3328.c b/drivers/clk/rockchip/clk-rk3328.c
new file mode 100644
index 000000000000..d283796ec2f0
--- /dev/null
+++ b/drivers/clk/rockchip/clk-rk3328.c
@@ -0,0 +1,1068 @@
+/*
+ * Copyright (c) 2016 Rockchip Electronics Co. Ltd.
+ * Author: Elaine <zhangqing@rock-chips.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/syscore_ops.h>
+#include <dt-bindings/clock/rk3328-cru.h>
+#include "clk.h"
+
+#define RK3328_GRF_SOC_STATUS0		0x480
+#define RK3328_GRF_MAC_CON1		0x904
+#define RK3328_GRF_MAC_CON2		0x908
+
+enum rk3328_plls {
+	apll, dpll, cpll, gpll, npll,
+};
+
+static struct rockchip_pll_rate_table rk3328_pll_rates[] = {
+	/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
+	RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1584000000, 1, 66, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1560000000, 1, 65, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1536000000, 1, 64, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1512000000, 1, 63, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1488000000, 1, 62, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1464000000, 1, 61, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1440000000, 1, 60, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1416000000, 1, 59, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1392000000, 1, 58, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1368000000, 1, 57, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1344000000, 1, 56, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1320000000, 1, 55, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1296000000, 1, 54, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1272000000, 1, 53, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1248000000, 1, 52, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1104000000, 1, 46, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1100000000, 12, 550, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
+	RK3036_PLL_RATE(1000000000, 6, 500, 2, 1, 1, 0),
+	RK3036_PLL_RATE(984000000, 1, 82, 2, 1, 1, 0),
+	RK3036_PLL_RATE(960000000, 1, 80, 2, 1, 1, 0),
+	RK3036_PLL_RATE(936000000, 1, 78, 2, 1, 1, 0),
+	RK3036_PLL_RATE(912000000, 1, 76, 2, 1, 1, 0),
+	RK3036_PLL_RATE(900000000, 4, 300, 2, 1, 1, 0),
+	RK3036_PLL_RATE(888000000, 1, 74, 2, 1, 1, 0),
+	RK3036_PLL_RATE(864000000, 1, 72, 2, 1, 1, 0),
+	RK3036_PLL_RATE(840000000, 1, 70, 2, 1, 1, 0),
+	RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
+	RK3036_PLL_RATE(800000000, 6, 400, 2, 1, 1, 0),
+	RK3036_PLL_RATE(700000000, 6, 350, 2, 1, 1, 0),
+	RK3036_PLL_RATE(696000000, 1, 58, 2, 1, 1, 0),
+	RK3036_PLL_RATE(600000000, 1, 75, 3, 1, 1, 0),
+	RK3036_PLL_RATE(594000000, 2, 99, 2, 1, 1, 0),
+	RK3036_PLL_RATE(504000000, 1, 63, 3, 1, 1, 0),
+	RK3036_PLL_RATE(500000000, 6, 250, 2, 1, 1, 0),
+	RK3036_PLL_RATE(408000000, 1, 68, 2, 2, 1, 0),
+	RK3036_PLL_RATE(312000000, 1, 52, 2, 2, 1, 0),
+	RK3036_PLL_RATE(216000000, 1, 72, 4, 2, 1, 0),
+	RK3036_PLL_RATE(96000000, 1, 64, 4, 4, 1, 0),
+	{ /* sentinel */ },
+};
+
+static struct rockchip_pll_rate_table rk3328_pll_frac_rates[] = {
+	/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
+	RK3036_PLL_RATE(1016064000, 3, 127, 1, 1, 0, 134217),
+	/* vco = 1016064000 */
+	RK3036_PLL_RATE(983040000, 24, 983, 1, 1, 0, 671088),
+	/* vco = 983040000 */
+	RK3036_PLL_RATE(491520000, 24, 983, 2, 1, 0, 671088),
+	/* vco = 983040000 */
+	RK3036_PLL_RATE(61440000, 6, 215, 7, 2, 0, 671088),
+	/* vco = 860156000 */
+	RK3036_PLL_RATE(56448000, 12, 451, 4, 4, 0, 9797894),
+	/* vco = 903168000 */
+	RK3036_PLL_RATE(40960000, 12, 409, 4, 5, 0, 10066329),
+	/* vco = 819200000 */
+	{ /* sentinel */ },
+};
+
+#define RK3328_DIV_CPU_MASK		0x1f
+#define RK3328_DIV_CPU_SHIFT		8
+
+#define RK3328_DIV_PERI_MASK		0xf
+#define RK3328_DIV_PERI_SHIFT		0
+#define RK3328_DIV_ACLK_MASK		0x7
+#define RK3328_DIV_ACLK_SHIFT		4
+#define RK3328_DIV_HCLK_MASK		0x3
+#define RK3328_DIV_HCLK_SHIFT		8
+#define RK3328_DIV_PCLK_MASK		0x7
+#define RK3328_DIV_PCLK_SHIFT		12
+
+#define RK3328_CLKSEL1(_aclk_core, _pclk_dbg)				\
+{									\
+	.reg = RK3328_CLKSEL_CON(1),					\
+	.val = HIWORD_UPDATE(_aclk_core, RK3328_DIV_ACLKM_MASK,		\
+			     RK3328_DIV_ACLKM_SHIFT) |			\
+	       HIWORD_UPDATE(_pclk_dbg, RK3328_DIV_PCLK_DBG_MASK,	\
+			     RK3328_DIV_PCLK_DBG_SHIFT),		\
+}
+
+#define RK3328_CPUCLK_RATE(_prate, _aclk_core, _pclk_dbg)		\
+{									\
+	.prate = _prate,						\
+	.divs = {							\
+		RK3328_CLKSEL1(_aclk_core, _pclk_dbg),			\
+	},								\
+}
+
+static struct rockchip_cpuclk_rate_table rk3328_cpuclk_rates[] __initdata = {
+	RK3328_CPUCLK_RATE(1800000000, 1, 7),
+	RK3328_CPUCLK_RATE(1704000000, 1, 7),
+	RK3328_CPUCLK_RATE(1608000000, 1, 7),
+	RK3328_CPUCLK_RATE(1512000000, 1, 7),
+	RK3328_CPUCLK_RATE(1488000000, 1, 5),
+	RK3328_CPUCLK_RATE(1416000000, 1, 5),
+	RK3328_CPUCLK_RATE(1392000000, 1, 5),
+	RK3328_CPUCLK_RATE(1296000000, 1, 5),
+	RK3328_CPUCLK_RATE(1200000000, 1, 5),
+	RK3328_CPUCLK_RATE(1104000000, 1, 5),
+	RK3328_CPUCLK_RATE(1008000000, 1, 5),
+	RK3328_CPUCLK_RATE(912000000, 1, 5),
+	RK3328_CPUCLK_RATE(816000000, 1, 3),
+	RK3328_CPUCLK_RATE(696000000, 1, 3),
+	RK3328_CPUCLK_RATE(600000000, 1, 3),
+	RK3328_CPUCLK_RATE(408000000, 1, 1),
+	RK3328_CPUCLK_RATE(312000000, 1, 1),
+	RK3328_CPUCLK_RATE(216000000,  1, 1),
+	RK3328_CPUCLK_RATE(96000000, 1, 1),
+};
+
+static const struct rockchip_cpuclk_reg_data rk3328_cpuclk_data = {
+	.core_reg = RK3328_CLKSEL_CON(0),
+	.div_core_shift = 0,
+	.div_core_mask = 0x1f,
+	.mux_core_alt = 1,
+	.mux_core_main = 3,
+	.mux_core_shift = 6,
+	.mux_core_mask = 0x3,
+};
+
+PNAME(mux_pll_p)		= { "xin24m", "xin24m" };
+
+PNAME(mux_2plls_p)		= { "cpll", "gpll" };
+PNAME(mux_gpll_cpll_p)		= { "gpll", "cpll" };
+PNAME(mux_cpll_gpll_apll_p)	= { "cpll", "gpll", "apll" };
+PNAME(mux_2plls_xin24m_p)	= { "cpll", "gpll", "xin24m" };
+PNAME(mux_2plls_hdmiphy_p)	= { "cpll", "gpll",
+				    "dummy_hdmiphy" };
+PNAME(mux_4plls_p)		= { "cpll", "gpll",
+				    "dummy_hdmiphy",
+				    "usb480m" };
+PNAME(mux_2plls_u480m_p)	= { "cpll", "gpll",
+				    "usb480m" };
+PNAME(mux_2plls_24m_u480m_p)	= { "cpll", "gpll",
+				     "xin24m", "usb480m" };
+
+PNAME(mux_ddrphy_p)		= { "dpll", "apll", "cpll" };
+PNAME(mux_armclk_p)		= { "apll_core",
+				    "gpll_core",
+				    "dpll_core",
+				    "npll_core"};
+PNAME(mux_hdmiphy_p)		= { "hdmi_phy", "xin24m" };
+PNAME(mux_usb480m_p)		= { "usb480m_phy",
+				    "xin24m" };
+
+PNAME(mux_i2s0_p)		= { "clk_i2s0_div",
+				    "clk_i2s0_frac",
+				    "xin12m",
+				    "xin12m" };
+PNAME(mux_i2s1_p)		= { "clk_i2s1_div",
+				    "clk_i2s1_frac",
+				    "clkin_i2s1",
+				    "xin12m" };
+PNAME(mux_i2s2_p)		= { "clk_i2s2_div",
+				    "clk_i2s2_frac",
+				    "clkin_i2s2",
+				    "xin12m" };
+PNAME(mux_i2s1out_p)		= { "clk_i2s1", "xin12m"};
+PNAME(mux_i2s2out_p)		= { "clk_i2s2", "xin12m" };
+PNAME(mux_spdif_p)		= { "clk_spdif_div",
+				    "clk_spdif_frac",
+				    "xin12m",
+				    "xin12m" };
+PNAME(mux_uart0_p)		= { "clk_uart0_div",
+				    "clk_uart0_frac",
+				    "xin24m" };
+PNAME(mux_uart1_p)		= { "clk_uart1_div",
+				    "clk_uart1_frac",
+				    "xin24m" };
+PNAME(mux_uart2_p)		= { "clk_uart2_div",
+				    "clk_uart2_frac",
+				    "xin24m" };
+
+PNAME(mux_sclk_cif_p)		= { "clk_cif_src",
+				    "xin24m" };
+PNAME(mux_dclk_lcdc_p)		= { "hdmiphy",
+				    "dclk_lcdc_src" };
+PNAME(mux_aclk_peri_pre_p)	= { "cpll_peri",
+				    "gpll_peri",
+				    "hdmiphy_peri" };
+PNAME(mux_ref_usb3otg_src_p)	= { "xin24m",
+				    "clk_usb3otg_ref" };
+PNAME(mux_xin24m_32k_p)		= { "xin24m",
+				    "clk_rtc32k" };
+PNAME(mux_mac2io_src_p)		= { "clk_mac2io_src",
+				    "gmac_clkin" };
+PNAME(mux_mac2phy_src_p)	= { "clk_mac2phy_src",
+				    "phy_50m_out" };
+
+static struct rockchip_pll_clock rk3328_pll_clks[] __initdata = {
+	[apll] = PLL(pll_rk3328, PLL_APLL, "apll", mux_pll_p,
+		     0, RK3328_PLL_CON(0),
+		     RK3328_MODE_CON, 0, 4, 0, rk3328_pll_frac_rates),
+	[dpll] = PLL(pll_rk3328, PLL_DPLL, "dpll", mux_pll_p,
+		     0, RK3328_PLL_CON(8),
+		     RK3328_MODE_CON, 4, 3, 0, NULL),
+	[cpll] = PLL(pll_rk3328, PLL_CPLL, "cpll", mux_pll_p,
+		     0, RK3328_PLL_CON(16),
+		     RK3328_MODE_CON, 8, 2, 0, rk3328_pll_rates),
+	[gpll] = PLL(pll_rk3328, PLL_GPLL, "gpll", mux_pll_p,
+		     0, RK3328_PLL_CON(24),
+		     RK3328_MODE_CON, 12, 1, 0, rk3328_pll_frac_rates),
+	[npll] = PLL(pll_rk3328, PLL_NPLL, "npll", mux_pll_p,
+		     0, RK3328_PLL_CON(40),
+		     RK3328_MODE_CON, 1, 0, 0, rk3328_pll_rates),
+};
+
+#define MFLAGS CLK_MUX_HIWORD_MASK
+#define DFLAGS CLK_DIVIDER_HIWORD_MASK
+#define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE)
+
+static struct rockchip_clk_branch rk3328_i2s0_fracmux __initdata =
+	MUX(0, "i2s0_pre", mux_i2s0_p, CLK_SET_RATE_PARENT,
+	    RK3328_CLKSEL_CON(6), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3328_i2s1_fracmux __initdata =
+	MUX(0, "i2s1_pre", mux_i2s1_p, CLK_SET_RATE_PARENT,
+	    RK3328_CLKSEL_CON(8), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3328_i2s2_fracmux __initdata =
+	MUX(0, "i2s2_pre", mux_i2s2_p, CLK_SET_RATE_PARENT,
+	    RK3328_CLKSEL_CON(10), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3328_spdif_fracmux __initdata =
+	MUX(SCLK_SPDIF, "sclk_spdif", mux_spdif_p, CLK_SET_RATE_PARENT,
+	    RK3328_CLKSEL_CON(12), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3328_uart0_fracmux __initdata =
+	MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT,
+	    RK3328_CLKSEL_CON(14), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3328_uart1_fracmux __initdata =
+	MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT,
+	    RK3328_CLKSEL_CON(16), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3328_uart2_fracmux __initdata =
+	MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT,
+	    RK3328_CLKSEL_CON(18), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
+	/*
+	 * Clock-Architecture Diagram 1
+	 */
+
+	DIV(0, "clk_24m", "xin24m", CLK_IGNORE_UNUSED,
+	    RK3328_CLKSEL_CON(2), 8, 5, DFLAGS),
+	COMPOSITE(SCLK_RTC32K, "clk_rtc32k", mux_2plls_xin24m_p, 0,
+		  RK3328_CLKSEL_CON(38), 14, 2, MFLAGS, 0, 14, DFLAGS,
+		  RK3328_CLKGATE_CON(0), 11, GFLAGS),
+	/* PD_MISC */
+	MUX(HDMIPHY, "hdmiphy", mux_hdmiphy_p, CLK_SET_RATE_PARENT,
+	    RK3328_MISC_CON, 13, 1, MFLAGS),
+	MUX(USB480M, "usb480m", mux_usb480m_p, CLK_SET_RATE_PARENT,
+	    RK3328_MISC_CON, 15, 1, MFLAGS),
+
+	/*
+	 * Clock-Architecture Diagram 2
+	 */
+
+	/* PD_CORE */
+	GATE(0, "apll_core", "apll", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(0), 0, GFLAGS),
+	GATE(0, "gpll_core", "gpll", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(0), 2, GFLAGS),
+	GATE(0, "dpll_core", "dpll", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(0), 1, GFLAGS),
+	GATE(0, "npll_core", "npll", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(0), 12, GFLAGS),
+	COMPOSITE_NOMUX(0, "pclk_dbg", "armclk", CLK_IGNORE_UNUSED,
+			RK3328_CLKSEL_CON(1), 0, 4,
+			DFLAGS | CLK_DIVIDER_READ_ONLY,
+			RK3328_CLKGATE_CON(7), 0, GFLAGS),
+	COMPOSITE_NOMUX(0, "aclk_core", "armclk", CLK_IGNORE_UNUSED,
+			RK3328_CLKSEL_CON(1), 4, 3,
+			DFLAGS | CLK_DIVIDER_READ_ONLY,
+			RK3328_CLKGATE_CON(7), 1, GFLAGS),
+	GATE(0, "aclk_core_niu", "aclk_core", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(13), 0, GFLAGS),
+	GATE(0, "aclk_gic400", "aclk_core", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(13), 1, GFLAGS),
+
+	GATE(0, "clk_jtag", "jtag_clkin", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(7), 2, GFLAGS),
+
+	/* PD_GPU */
+	COMPOSITE(0, "aclk_gpu_pre", mux_4plls_p, 0,
+		  RK3328_CLKSEL_CON(44), 6, 2, MFLAGS, 0, 5, DFLAGS,
+		  RK3328_CLKGATE_CON(6), 6, GFLAGS),
+	GATE(ACLK_GPU, "aclk_gpu", "aclk_gpu_pre", CLK_SET_RATE_PARENT,
+	     RK3328_CLKGATE_CON(14), 0, GFLAGS),
+	GATE(0, "aclk_gpu_niu", "aclk_gpu_pre", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(14), 1, GFLAGS),
+
+	/* PD_DDR */
+	COMPOSITE(0, "clk_ddr", mux_ddrphy_p, CLK_IGNORE_UNUSED,
+		  RK3328_CLKSEL_CON(3), 8, 2, MFLAGS, 0, 3,
+		  DFLAGS | CLK_DIVIDER_POWER_OF_TWO,
+		  RK3328_CLKGATE_CON(0), 4, GFLAGS),
+	GATE(0, "clk_ddrmsch", "clk_ddr", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(18), 6, GFLAGS),
+	GATE(0, "clk_ddrupctl", "clk_ddr", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(18), 5, GFLAGS),
+	GATE(0, "aclk_ddrupctl", "clk_ddr", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(18), 4, GFLAGS),
+	GATE(0, "clk_ddrmon", "xin24m", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(0), 6, GFLAGS),
+
+	COMPOSITE(PCLK_DDR, "pclk_ddr", mux_2plls_hdmiphy_p, 0,
+		  RK3328_CLKSEL_CON(4), 13, 2, MFLAGS, 8, 3, DFLAGS,
+		  RK3328_CLKGATE_CON(7), 4, GFLAGS),
+	GATE(0, "pclk_ddrupctl", "pclk_ddr", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(18), 1, GFLAGS),
+	GATE(0, "pclk_ddr_msch", "pclk_ddr", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(18), 2, GFLAGS),
+	GATE(0, "pclk_ddr_mon", "pclk_ddr", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(18), 3, GFLAGS),
+	GATE(0, "pclk_ddrstdby", "pclk_ddr", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(18), 7, GFLAGS),
+	GATE(0, "pclk_ddr_grf", "pclk_ddr", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(18), 9, GFLAGS),
+
+	/*
+	 * Clock-Architecture Diagram 3
+	 */
+	/* PD_BUS */
+	COMPOSITE(ACLK_BUS_PRE, "aclk_bus_pre", mux_2plls_hdmiphy_p, 0,
+		  RK3328_CLKSEL_CON(0), 13, 2, MFLAGS, 8, 5, DFLAGS,
+		  RK3328_CLKGATE_CON(8), 0, GFLAGS),
+	COMPOSITE_NOMUX(HCLK_BUS_PRE, "hclk_bus_pre", "aclk_bus_pre", 0,
+			RK3328_CLKSEL_CON(1), 8, 2, DFLAGS,
+			RK3328_CLKGATE_CON(8), 1, GFLAGS),
+	COMPOSITE_NOMUX(PCLK_BUS_PRE, "pclk_bus_pre", "aclk_bus_pre", 0,
+			RK3328_CLKSEL_CON(1), 12, 3, DFLAGS,
+			RK3328_CLKGATE_CON(8), 2, GFLAGS),
+	GATE(0, "pclk_bus", "pclk_bus_pre", 0,
+	     RK3328_CLKGATE_CON(8), 3, GFLAGS),
+	GATE(0, "pclk_phy_pre", "pclk_bus_pre", 0,
+	     RK3328_CLKGATE_CON(8), 4, GFLAGS),
+
+	COMPOSITE(SCLK_TSP, "clk_tsp", mux_2plls_p, 0,
+		  RK3328_CLKSEL_CON(21), 15, 1, MFLAGS, 8, 5, DFLAGS,
+		  RK3328_CLKGATE_CON(2), 5, GFLAGS),
+	GATE(0, "clk_hsadc_tsp", "ext_gpio3a2", 0,
+	     RK3328_CLKGATE_CON(17), 13, GFLAGS),
+
+	/* PD_I2S */
+	COMPOSITE(0, "clk_i2s0_div", mux_2plls_p, 0,
+		  RK3328_CLKSEL_CON(6), 15, 1, MFLAGS, 0, 7, DFLAGS,
+		  RK3328_CLKGATE_CON(1), 1, GFLAGS),
+	COMPOSITE_FRACMUX(0, "clk_i2s0_frac", "clk_i2s0_div",
+			  CLK_SET_RATE_PARENT,
+			  RK3328_CLKSEL_CON(7), 0,
+			  RK3328_CLKGATE_CON(1), 2, GFLAGS,
+			  &rk3328_i2s0_fracmux),
+	GATE(SCLK_I2S0, "clk_i2s0", "i2s0_pre", CLK_SET_RATE_PARENT,
+	     RK3328_CLKGATE_CON(1), 3, GFLAGS),
+
+	COMPOSITE(0, "clk_i2s1_div", mux_2plls_p, 0,
+		  RK3328_CLKSEL_CON(8), 15, 1, MFLAGS, 0, 7, DFLAGS,
+		  RK3328_CLKGATE_CON(1), 4, GFLAGS),
+	COMPOSITE_FRACMUX(0, "clk_i2s1_frac", "clk_i2s1_div",
+			  CLK_SET_RATE_PARENT,
+			  RK3328_CLKSEL_CON(9), 0,
+			  RK3328_CLKGATE_CON(1), 5, GFLAGS,
+			  &rk3328_i2s1_fracmux),
+	GATE(SCLK_I2S1, "clk_i2s1", "i2s1_pre", CLK_SET_RATE_PARENT,
+	     RK3328_CLKGATE_CON(0), 6, GFLAGS),
+	COMPOSITE_NODIV(SCLK_I2S1_OUT, "i2s1_out", mux_i2s1out_p, 0,
+			RK3328_CLKSEL_CON(8), 12, 1, MFLAGS,
+			RK3328_CLKGATE_CON(1), 7, GFLAGS),
+
+	COMPOSITE(0, "clk_i2s2_div", mux_2plls_p, 0,
+		  RK3328_CLKSEL_CON(10), 15, 1, MFLAGS, 0, 7, DFLAGS,
+		  RK3328_CLKGATE_CON(1), 8, GFLAGS),
+	COMPOSITE_FRACMUX(0, "clk_i2s2_frac", "clk_i2s2_div",
+			  CLK_SET_RATE_PARENT,
+			  RK3328_CLKSEL_CON(11), 0,
+			  RK3328_CLKGATE_CON(1), 9, GFLAGS,
+			  &rk3328_i2s2_fracmux),
+	GATE(SCLK_I2S2, "clk_i2s2", "i2s2_pre", CLK_SET_RATE_PARENT,
+	     RK3328_CLKGATE_CON(1), 10, GFLAGS),
+	COMPOSITE_NODIV(SCLK_I2S2_OUT, "i2s2_out", mux_i2s2out_p, 0,
+			RK3328_CLKSEL_CON(10), 12, 1, MFLAGS,
+			RK3328_CLKGATE_CON(1), 11, GFLAGS),
+
+	COMPOSITE(0, "clk_spdif_div", mux_2plls_p, 0,
+		  RK3328_CLKSEL_CON(12), 15, 1, MFLAGS, 0, 7, DFLAGS,
+		  RK3328_CLKGATE_CON(1), 12, GFLAGS),
+	COMPOSITE_FRACMUX(0, "clk_spdif_frac", "clk_spdif_div",
+			  CLK_SET_RATE_PARENT,
+			  RK3328_CLKSEL_CON(13), 0,
+			  RK3328_CLKGATE_CON(1), 13, GFLAGS,
+			  &rk3328_spdif_fracmux),
+
+	/* PD_UART */
+	COMPOSITE(0, "clk_uart0_div", mux_2plls_u480m_p, 0,
+		  RK3328_CLKSEL_CON(14), 12, 2, MFLAGS, 0, 7, DFLAGS,
+		  RK3328_CLKGATE_CON(1), 14, GFLAGS),
+	COMPOSITE(0, "clk_uart1_div", mux_2plls_u480m_p, 0,
+		  RK3328_CLKSEL_CON(16), 12, 2, MFLAGS, 0, 7, DFLAGS,
+		  RK3328_CLKGATE_CON(2), 0, GFLAGS),
+	COMPOSITE(0, "clk_uart2_div", mux_2plls_u480m_p,
+		  0, RK3328_CLKSEL_CON(18), 12, 2, MFLAGS, 0, 7, DFLAGS,
+		  RK3328_CLKGATE_CON(2), 2, GFLAGS),
+	COMPOSITE_FRACMUX(0, "clk_uart0_frac", "clk_uart0_div",
+			  CLK_SET_RATE_PARENT,
+			  RK3328_CLKSEL_CON(15), 0,
+			  RK3328_CLKGATE_CON(1), 15, GFLAGS,
+			  &rk3328_uart0_fracmux),
+	COMPOSITE_FRACMUX(0, "clk_uart1_frac", "clk_uart1_div",
+			  CLK_SET_RATE_PARENT,
+			  RK3328_CLKSEL_CON(17), 0,
+			  RK3328_CLKGATE_CON(2), 1, GFLAGS,
+			  &rk3328_uart1_fracmux),
+	COMPOSITE_FRACMUX(0, "clk_uart2_frac", "clk_uart2_div",
+			  CLK_SET_RATE_PARENT,
+			  RK3328_CLKSEL_CON(19), 0,
+			  RK3328_CLKGATE_CON(2), 3, GFLAGS,
+			  &rk3328_uart2_fracmux),
+
+	/*
+	 * Clock-Architecture Diagram 4
+	 */
+	 COMPOSITE(SCLK_I2C0, "clk_i2c0", mux_2plls_p, 0,
+		   RK3328_CLKSEL_CON(34), 7, 1, MFLAGS, 0, 7, DFLAGS,
+		   RK3328_CLKGATE_CON(2), 9, GFLAGS),
+	COMPOSITE(SCLK_I2C1, "clk_i2c1", mux_2plls_p, 0,
+		  RK3328_CLKSEL_CON(34), 15, 1, MFLAGS, 8, 7, DFLAGS,
+		  RK3328_CLKGATE_CON(2), 10, GFLAGS),
+	COMPOSITE(SCLK_I2C2, "clk_i2c2", mux_2plls_p, 0,
+		  RK3328_CLKSEL_CON(35), 7, 1, MFLAGS, 0, 7, DFLAGS,
+		  RK3328_CLKGATE_CON(2), 11, GFLAGS),
+	COMPOSITE(SCLK_I2C3, "clk_i2c3", mux_2plls_p, 0,
+		  RK3328_CLKSEL_CON(35), 15, 1, MFLAGS, 8, 7, DFLAGS,
+		  RK3328_CLKGATE_CON(2), 12, GFLAGS),
+	COMPOSITE(SCLK_CRYPTO, "clk_crypto", mux_2plls_p, 0,
+		  RK3328_CLKSEL_CON(20), 7, 1, MFLAGS, 0, 7, DFLAGS,
+		  RK3328_CLKGATE_CON(2), 4, GFLAGS),
+	COMPOSITE_NOMUX(SCLK_TSADC, "clk_tsadc", "clk_24m", 0,
+			RK3328_CLKSEL_CON(22), 0, 10, DFLAGS,
+			RK3328_CLKGATE_CON(2), 6, GFLAGS),
+	COMPOSITE_NOMUX(SCLK_SARADC, "clk_saradc", "clk_24m", 0,
+			RK3328_CLKSEL_CON(23), 0, 10, DFLAGS,
+			RK3328_CLKGATE_CON(2), 14, GFLAGS),
+	COMPOSITE(SCLK_SPI, "clk_spi", mux_2plls_p, 0,
+		  RK3328_CLKSEL_CON(24), 7, 1, MFLAGS, 0, 7, DFLAGS,
+		  RK3328_CLKGATE_CON(2), 7, GFLAGS),
+	COMPOSITE(SCLK_PWM, "clk_pwm", mux_2plls_p, 0,
+		  RK3328_CLKSEL_CON(24), 15, 1, MFLAGS, 8, 7, DFLAGS,
+		  RK3328_CLKGATE_CON(2), 8, GFLAGS),
+	COMPOSITE(SCLK_OTP, "clk_otp", mux_2plls_xin24m_p, 0,
+		  RK3328_CLKSEL_CON(4), 6, 2, MFLAGS, 0, 6, DFLAGS,
+		  RK3328_CLKGATE_CON(3), 8, GFLAGS),
+	COMPOSITE(SCLK_EFUSE, "clk_efuse", mux_2plls_xin24m_p, 0,
+		  RK3328_CLKSEL_CON(5), 14, 2, MFLAGS, 8, 5, DFLAGS,
+		  RK3328_CLKGATE_CON(2), 13, GFLAGS),
+	COMPOSITE(SCLK_PDM, "clk_pdm", mux_cpll_gpll_apll_p,
+		  CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
+		  RK3328_CLKSEL_CON(20), 14, 2, MFLAGS, 8, 5, DFLAGS,
+		  RK3328_CLKGATE_CON(2), 15, GFLAGS),
+
+	GATE(SCLK_TIMER0, "sclk_timer0", "xin24m", 0,
+	     RK3328_CLKGATE_CON(8), 5, GFLAGS),
+	GATE(SCLK_TIMER1, "sclk_timer1", "xin24m", 0,
+	     RK3328_CLKGATE_CON(8), 6, GFLAGS),
+	GATE(SCLK_TIMER2, "sclk_timer2", "xin24m", 0,
+	     RK3328_CLKGATE_CON(8), 7, GFLAGS),
+	GATE(SCLK_TIMER3, "sclk_timer3", "xin24m", 0,
+	     RK3328_CLKGATE_CON(8), 8, GFLAGS),
+	GATE(SCLK_TIMER4, "sclk_timer4", "xin24m", 0,
+	     RK3328_CLKGATE_CON(8), 9, GFLAGS),
+	GATE(SCLK_TIMER5, "sclk_timer5", "xin24m", 0,
+	     RK3328_CLKGATE_CON(8), 10, GFLAGS),
+
+	COMPOSITE(SCLK_WIFI, "clk_wifi", mux_2plls_u480m_p, 0,
+		  RK3328_CLKSEL_CON(52), 6, 2, MFLAGS, 0, 6, DFLAGS,
+		  RK3328_CLKGATE_CON(0), 10, GFLAGS),
+
+	/*
+	 * Clock-Architecture Diagram 5
+	 */
+	/* PD_VIDEO */
+	COMPOSITE(ACLK_RKVDEC_PRE, "aclk_rkvdec_pre", mux_4plls_p, 0,
+		  RK3328_CLKSEL_CON(48), 6, 2, MFLAGS, 0, 5, DFLAGS,
+		  RK3328_CLKGATE_CON(6), 0, GFLAGS),
+	FACTOR_GATE(HCLK_RKVDEC_PRE, "hclk_rkvdec_pre", "aclk_rkvdec_pre",
+		    0, 1, 4,
+		    RK3328_CLKGATE_CON(11), 0, GFLAGS),
+	GATE(ACLK_RKVDEC, "aclk_rkvdec", "aclk_rkvdec_pre", CLK_SET_RATE_PARENT,
+	     RK3328_CLKGATE_CON(24), 0, GFLAGS),
+	GATE(HCLK_RKVDEC, "hclk_rkvdec", "hclk_rkvdec_pre", CLK_SET_RATE_PARENT,
+	     RK3328_CLKGATE_CON(24), 1, GFLAGS),
+	GATE(0, "aclk_rkvdec_niu", "aclk_rkvdec_pre", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(24), 2, GFLAGS),
+	GATE(0, "hclk_rkvdec_niu", "hclk_rkvdec_pre", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(24), 3, GFLAGS),
+
+	COMPOSITE(SCLK_VDEC_CABAC, "sclk_vdec_cabac", mux_4plls_p, 0,
+		  RK3328_CLKSEL_CON(48), 14, 2, MFLAGS, 8, 5, DFLAGS,
+		  RK3328_CLKGATE_CON(6), 1, GFLAGS),
+
+	COMPOSITE(SCLK_VDEC_CORE, "sclk_vdec_core", mux_4plls_p, 0,
+		  RK3328_CLKSEL_CON(49), 6, 2, MFLAGS, 0, 5, DFLAGS,
+		  RK3328_CLKGATE_CON(6), 2, GFLAGS),
+
+	COMPOSITE(ACLK_VPU_PRE, "aclk_vpu_pre", mux_4plls_p, 0,
+		  RK3328_CLKSEL_CON(50), 6, 2, MFLAGS, 0, 5, DFLAGS,
+		  RK3328_CLKGATE_CON(6), 5, GFLAGS),
+	FACTOR_GATE(HCLK_VPU_PRE, "hclk_vpu_pre", "aclk_vpu_pre", 0, 1, 4,
+		    RK3328_CLKGATE_CON(11), 8, GFLAGS),
+	GATE(ACLK_VPU, "aclk_vpu", "aclk_vpu_pre", CLK_SET_RATE_PARENT,
+	     RK3328_CLKGATE_CON(23), 0, GFLAGS),
+	GATE(HCLK_VPU, "hclk_vpu", "hclk_vpu_pre", CLK_SET_RATE_PARENT,
+	     RK3328_CLKGATE_CON(23), 1, GFLAGS),
+	GATE(0, "aclk_vpu_niu", "aclk_vpu_pre", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(23), 2, GFLAGS),
+	GATE(0, "hclk_vpu_niu", "hclk_vpu_pre", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(23), 3, GFLAGS),
+
+	COMPOSITE(ACLK_RKVENC, "aclk_rkvenc", mux_4plls_p, 0,
+		  RK3328_CLKSEL_CON(51), 6, 2, MFLAGS, 0, 5, DFLAGS,
+		  RK3328_CLKGATE_CON(6), 3, GFLAGS),
+	FACTOR_GATE(HCLK_RKVENC, "hclk_rkvenc", "aclk_rkvenc", 0, 1, 4,
+		    RK3328_CLKGATE_CON(11), 4, GFLAGS),
+	GATE(0, "aclk_rkvenc_niu", "aclk_rkvenc", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(25), 0, GFLAGS),
+	GATE(0, "hclk_rkvenc_niu", "hclk_rkvenc", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(25), 1, GFLAGS),
+	GATE(ACLK_H265, "aclk_h265", "aclk_rkvenc", 0,
+	     RK3328_CLKGATE_CON(25), 0, GFLAGS),
+	GATE(PCLK_H265, "pclk_h265", "hclk_rkvenc", 0,
+	     RK3328_CLKGATE_CON(25), 1, GFLAGS),
+	GATE(ACLK_H264, "aclk_h264", "aclk_rkvenc", 0,
+	     RK3328_CLKGATE_CON(25), 0, GFLAGS),
+	GATE(HCLK_H264, "hclk_h264", "hclk_rkvenc", 0,
+	     RK3328_CLKGATE_CON(25), 1, GFLAGS),
+	GATE(ACLK_AXISRAM, "aclk_axisram", "aclk_rkvenc", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(25), 0, GFLAGS),
+
+	COMPOSITE(SCLK_VENC_CORE, "sclk_venc_core", mux_4plls_p, 0,
+		  RK3328_CLKSEL_CON(51), 14, 2, MFLAGS, 8, 5, DFLAGS,
+		  RK3328_CLKGATE_CON(6), 4, GFLAGS),
+
+	COMPOSITE(SCLK_VENC_DSP, "sclk_venc_dsp", mux_4plls_p, 0,
+		  RK3328_CLKSEL_CON(52), 14, 2, MFLAGS, 8, 5, DFLAGS,
+		  RK3328_CLKGATE_CON(6), 7, GFLAGS),
+
+	/*
+	 * Clock-Architecture Diagram 6
+	 */
+	/* PD_VIO */
+	COMPOSITE(ACLK_VIO_PRE, "aclk_vio_pre", mux_4plls_p, 0,
+		  RK3328_CLKSEL_CON(37), 6, 2, MFLAGS, 0, 5, DFLAGS,
+		  RK3328_CLKGATE_CON(5), 2, GFLAGS),
+	DIV(HCLK_VIO_PRE, "hclk_vio_pre", "aclk_vio_pre", 0,
+	    RK3328_CLKSEL_CON(37), 8, 5, DFLAGS),
+
+	COMPOSITE(ACLK_RGA_PRE, "aclk_rga_pre", mux_4plls_p, 0,
+		  RK3328_CLKSEL_CON(36), 14, 2, MFLAGS, 8, 5, DFLAGS,
+		  RK3328_CLKGATE_CON(5), 0, GFLAGS),
+	COMPOSITE(SCLK_RGA, "clk_rga", mux_4plls_p, 0,
+		  RK3328_CLKSEL_CON(36), 6, 2, MFLAGS, 0, 5, DFLAGS,
+		  RK3328_CLKGATE_CON(5), 1, GFLAGS),
+	COMPOSITE(ACLK_VOP_PRE, "aclk_vop_pre", mux_4plls_p, 0,
+		  RK3328_CLKSEL_CON(39), 6, 2, MFLAGS, 0, 5, DFLAGS,
+		  RK3328_CLKGATE_CON(5), 5, GFLAGS),
+	GATE(0, "clk_hdmi_sfc", "xin24m", 0,
+	     RK3328_CLKGATE_CON(5), 4, GFLAGS),
+
+	COMPOSITE_NODIV(0, "clk_cif_src", mux_2plls_p, 0,
+			RK3328_CLKSEL_CON(42), 7, 1, MFLAGS,
+			RK3328_CLKGATE_CON(5), 3, GFLAGS),
+	COMPOSITE_NOGATE(SCLK_CIF_OUT, "clk_cif_out", mux_sclk_cif_p,
+			 CLK_SET_RATE_PARENT,
+			 RK3328_CLKSEL_CON(42), 5, 1, MFLAGS, 0, 5, DFLAGS),
+
+	COMPOSITE(DCLK_LCDC_SRC, "dclk_lcdc_src", mux_gpll_cpll_p, 0,
+		  RK3328_CLKSEL_CON(40), 0, 1, MFLAGS, 8, 8, DFLAGS,
+		  RK3328_CLKGATE_CON(5), 6, GFLAGS),
+	DIV(DCLK_HDMIPHY, "dclk_hdmiphy", "dclk_lcdc_src", 0,
+	    RK3328_CLKSEL_CON(40), 3, 3, DFLAGS),
+	MUX(DCLK_LCDC, "dclk_lcdc", mux_dclk_lcdc_p, 0,
+	    RK3328_CLKSEL_CON(40), 1, 1, MFLAGS),
+
+	/*
+	 * Clock-Architecture Diagram 7
+	 */
+	/* PD_PERI */
+	GATE(0, "gpll_peri", "gpll", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(4), 0, GFLAGS),
+	GATE(0, "cpll_peri", "cpll", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(4), 1, GFLAGS),
+	GATE(0, "hdmiphy_peri", "hdmiphy", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(4), 2, GFLAGS),
+	COMPOSITE_NOGATE(ACLK_PERI_PRE, "aclk_peri_pre", mux_aclk_peri_pre_p, 0,
+			 RK3328_CLKSEL_CON(28), 6, 2, MFLAGS, 0, 5, DFLAGS),
+	COMPOSITE_NOMUX(PCLK_PERI, "pclk_peri", "aclk_peri_pre",
+			CLK_IGNORE_UNUSED,
+			RK3328_CLKSEL_CON(29), 0, 2, DFLAGS,
+			RK3328_CLKGATE_CON(10), 2, GFLAGS),
+	COMPOSITE_NOMUX(HCLK_PERI, "hclk_peri", "aclk_peri_pre",
+			CLK_IGNORE_UNUSED,
+			RK3328_CLKSEL_CON(29), 4, 3, DFLAGS,
+			RK3328_CLKGATE_CON(10), 1, GFLAGS),
+	GATE(ACLK_PERI, "aclk_peri", "aclk_peri_pre",
+	     CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT,
+	     RK3328_CLKGATE_CON(10), 0, GFLAGS),
+
+	COMPOSITE(SCLK_SDMMC, "clk_sdmmc", mux_2plls_24m_u480m_p, 0,
+		  RK3328_CLKSEL_CON(30), 8, 2, MFLAGS, 0, 8, DFLAGS,
+		  RK3328_CLKGATE_CON(4), 3, GFLAGS),
+
+	COMPOSITE(SCLK_SDIO, "clk_sdio", mux_2plls_24m_u480m_p, 0,
+		  RK3328_CLKSEL_CON(31), 8, 2, MFLAGS, 0, 8, DFLAGS,
+		  RK3328_CLKGATE_CON(4), 4, GFLAGS),
+
+	COMPOSITE(SCLK_EMMC, "clk_emmc", mux_2plls_24m_u480m_p, 0,
+		  RK3328_CLKSEL_CON(32), 8, 2, MFLAGS, 0, 8, DFLAGS,
+		  RK3328_CLKGATE_CON(4), 5, GFLAGS),
+
+	COMPOSITE(SCLK_SDMMC_EXT, "clk_sdmmc_ext",
+		  mux_2plls_24m_u480m_p, 0,
+		  RK3328_CLKSEL_CON(43), 8, 2, MFLAGS, 0, 8, DFLAGS,
+		  RK3328_CLKGATE_CON(4), 10, GFLAGS),
+
+	COMPOSITE(SCLK_REF_USB3OTG_SRC, "clk_ref_usb3otg_src", mux_2plls_p, 0,
+		  RK3328_CLKSEL_CON(45), 7, 1, MFLAGS, 0, 7, DFLAGS,
+		  RK3328_CLKGATE_CON(4), 9, GFLAGS),
+
+	MUX(SCLK_REF_USB3OTG, "clk_ref_usb3otg",
+	    mux_ref_usb3otg_src_p, CLK_SET_RATE_PARENT,
+	    RK3328_CLKSEL_CON(45), 8, 1, MFLAGS),
+
+	GATE(SCLK_USB3OTG_REF, "clk_usb3otg_ref", "xin24m", 0,
+	     RK3328_CLKGATE_CON(4), 7, GFLAGS),
+
+	COMPOSITE(SCLK_USB3OTG_SUSPEND, "clk_usb3otg_suspend",
+		  mux_xin24m_32k_p, 0,
+		  RK3328_CLKSEL_CON(33), 15, 1, MFLAGS, 0, 10, DFLAGS,
+		  RK3328_CLKGATE_CON(4), 8, GFLAGS),
+
+	/*
+	 * Clock-Architecture Diagram 8
+	 */
+	/* PD_GMAC */
+
+	COMPOSITE(ACLK_GMAC, "aclk_gmac", mux_2plls_hdmiphy_p, 0,
+		  RK3328_CLKSEL_CON(35), 6, 2, MFLAGS, 0, 5, DFLAGS,
+		  RK3328_CLKGATE_CON(3), 2, GFLAGS),
+	COMPOSITE_NOMUX(PCLK_GMAC, "pclk_gmac", "aclk_gmac", 0,
+			RK3328_CLKSEL_CON(25), 8, 3, DFLAGS,
+			RK3328_CLKGATE_CON(9), 0, GFLAGS),
+
+	COMPOSITE(SCLK_MAC2IO_SRC, "clk_mac2io_src", mux_2plls_p, 0,
+		  RK3328_CLKSEL_CON(27), 7, 1, MFLAGS, 0, 5, DFLAGS,
+		  RK3328_CLKGATE_CON(3), 1, GFLAGS),
+	GATE(SCLK_MAC2IO_REF, "clk_mac2io_ref", "clk_mac2io", 0,
+	     RK3328_CLKGATE_CON(9), 7, GFLAGS),
+	GATE(SCLK_MAC2IO_RX, "clk_mac2io_rx", "clk_mac2io", 0,
+	     RK3328_CLKGATE_CON(9), 4, GFLAGS),
+	GATE(SCLK_MAC2IO_TX, "clk_mac2io_tx", "clk_mac2io", 0,
+	     RK3328_CLKGATE_CON(9), 5, GFLAGS),
+	GATE(SCLK_MAC2IO_REFOUT, "clk_mac2io_refout", "clk_mac2io", 0,
+	     RK3328_CLKGATE_CON(9), 6, GFLAGS),
+	COMPOSITE(SCLK_MAC2IO_OUT, "clk_mac2io_out", mux_2plls_p, 0,
+		  RK3328_CLKSEL_CON(27), 15, 1, MFLAGS, 8, 5, DFLAGS,
+		  RK3328_CLKGATE_CON(3), 5, GFLAGS),
+
+	COMPOSITE(SCLK_MAC2PHY_SRC, "clk_mac2phy_src", mux_2plls_p, 0,
+		  RK3328_CLKSEL_CON(26), 7, 1, MFLAGS, 0, 5, DFLAGS,
+		  RK3328_CLKGATE_CON(3), 0, GFLAGS),
+	GATE(SCLK_MAC2PHY_REF, "clk_mac2phy_ref", "clk_mac2phy", 0,
+	     RK3328_CLKGATE_CON(9), 3, GFLAGS),
+	GATE(SCLK_MAC2PHY_RXTX, "clk_mac2phy_rxtx", "clk_mac2phy", 0,
+	     RK3328_CLKGATE_CON(9), 1, GFLAGS),
+	COMPOSITE_NOMUX(SCLK_MAC2PHY_OUT, "clk_mac2phy_out", "clk_mac2phy", 0,
+			RK3328_CLKSEL_CON(26), 8, 2, DFLAGS,
+			RK3328_CLKGATE_CON(9), 2, GFLAGS),
+
+	FACTOR(0, "xin12m", "xin24m", 0, 1, 2),
+
+	/*
+	 * Clock-Architecture Diagram 9
+	 */
+
+	/* PD_VOP */
+	GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", 0,
+	     RK3328_CLKGATE_CON(21), 10, GFLAGS),
+	GATE(0, "aclk_rga_niu", "aclk_rga_pre", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(22), 3, GFLAGS),
+	GATE(ACLK_VOP, "aclk_vop", "aclk_vop_pre", 0,
+	     RK3328_CLKGATE_CON(21), 2, GFLAGS),
+	GATE(0, "aclk_vop_niu", "aclk_vop_pre", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(21), 4, GFLAGS),
+
+	GATE(ACLK_IEP, "aclk_iep", "aclk_vio_pre", 0,
+	     RK3328_CLKGATE_CON(21), 6, GFLAGS),
+	GATE(ACLK_CIF, "aclk_cif", "aclk_vio_pre", 0,
+	     RK3328_CLKGATE_CON(21), 8, GFLAGS),
+	GATE(ACLK_HDCP, "aclk_hdcp", "aclk_vio_pre", 0,
+	     RK3328_CLKGATE_CON(21), 15, GFLAGS),
+	GATE(0, "aclk_vio_niu", "aclk_vio_pre", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(22), 2, GFLAGS),
+
+	GATE(HCLK_VOP, "hclk_vop", "hclk_vio_pre", 0,
+	     RK3328_CLKGATE_CON(21), 3, GFLAGS),
+	GATE(0, "hclk_vop_niu", "hclk_vio_pre", 0,
+	     RK3328_CLKGATE_CON(21), 5, GFLAGS),
+	GATE(HCLK_IEP, "hclk_iep", "hclk_vio_pre", 0,
+	     RK3328_CLKGATE_CON(21), 7, GFLAGS),
+	GATE(HCLK_CIF, "hclk_cif", "hclk_vio_pre", 0,
+	     RK3328_CLKGATE_CON(21), 9, GFLAGS),
+	GATE(HCLK_RGA, "hclk_rga", "hclk_vio_pre", 0,
+	     RK3328_CLKGATE_CON(21), 11, GFLAGS),
+	GATE(0, "hclk_ahb1tom", "hclk_vio_pre", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(21), 12, GFLAGS),
+	GATE(0, "pclk_vio_h2p", "hclk_vio_pre", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(21), 13, GFLAGS),
+	GATE(0, "hclk_vio_h2p", "hclk_vio_pre", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(21), 14, GFLAGS),
+	GATE(HCLK_HDCP, "hclk_hdcp", "hclk_vio_pre", 0,
+	     RK3328_CLKGATE_CON(22), 0, GFLAGS),
+	GATE(HCLK_VIO, "hclk_vio", "hclk_vio_pre", 0,
+	     RK3328_CLKGATE_CON(22), 1, GFLAGS),
+	GATE(PCLK_HDMI, "pclk_hdmi", "hclk_vio_pre", 0,
+	     RK3328_CLKGATE_CON(22), 4, GFLAGS),
+	GATE(PCLK_HDCP, "pclk_hdcp", "hclk_vio_pre", 0,
+	     RK3328_CLKGATE_CON(22), 5, GFLAGS),
+
+	/* PD_PERI */
+	GATE(0, "aclk_peri_noc", "aclk_peri", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(19), 11, GFLAGS),
+	GATE(ACLK_USB3OTG, "aclk_usb3otg", "aclk_peri", 0,
+	     RK3328_CLKGATE_CON(19), 4, GFLAGS),
+
+	GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_peri", 0,
+	     RK3328_CLKGATE_CON(19), 0, GFLAGS),
+	GATE(HCLK_SDIO, "hclk_sdio", "hclk_peri", 0,
+	     RK3328_CLKGATE_CON(19), 1, GFLAGS),
+	GATE(HCLK_EMMC, "hclk_emmc", "hclk_peri", 0,
+	     RK3328_CLKGATE_CON(19), 2, GFLAGS),
+	GATE(HCLK_SDMMC_EXT, "hclk_sdmmc_ext", "hclk_peri", 0,
+	     RK3328_CLKGATE_CON(19), 15, GFLAGS),
+	GATE(HCLK_HOST0, "hclk_host0", "hclk_peri", 0,
+	     RK3328_CLKGATE_CON(19), 6, GFLAGS),
+	GATE(HCLK_HOST0_ARB, "hclk_host0_arb", "hclk_peri", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(19), 7, GFLAGS),
+	GATE(HCLK_OTG, "hclk_otg", "hclk_peri", 0,
+	     RK3328_CLKGATE_CON(19), 8, GFLAGS),
+	GATE(HCLK_OTG_PMU, "hclk_otg_pmu", "hclk_peri", 0,
+	     RK3328_CLKGATE_CON(19), 9, GFLAGS),
+	GATE(0, "hclk_peri_niu", "hclk_peri", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(19), 12, GFLAGS),
+	GATE(0, "pclk_peri_niu", "hclk_peri", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(19), 13, GFLAGS),
+
+	/* PD_GMAC */
+	GATE(ACLK_MAC2PHY, "aclk_mac2phy", "aclk_gmac", 0,
+	     RK3328_CLKGATE_CON(26), 0, GFLAGS),
+	GATE(ACLK_MAC2IO, "aclk_mac2io", "aclk_gmac", 0,
+	     RK3328_CLKGATE_CON(26), 2, GFLAGS),
+	GATE(0, "aclk_gmac_niu", "aclk_gmac", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(26), 4, GFLAGS),
+	GATE(PCLK_MAC2PHY, "pclk_mac2phy", "pclk_gmac", 0,
+	     RK3328_CLKGATE_CON(26), 1, GFLAGS),
+	GATE(PCLK_MAC2IO, "pclk_mac2io", "pclk_gmac", 0,
+	     RK3328_CLKGATE_CON(26), 3, GFLAGS),
+	GATE(0, "pclk_gmac_niu", "pclk_gmac", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(26), 5, GFLAGS),
+
+	/* PD_BUS */
+	GATE(0, "aclk_bus_niu", "aclk_bus_pre", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(15), 12, GFLAGS),
+	GATE(ACLK_DCF, "aclk_dcf", "aclk_bus_pre", 0,
+	     RK3328_CLKGATE_CON(15), 11, GFLAGS),
+	GATE(ACLK_TSP, "aclk_tsp", "aclk_bus_pre", 0,
+	     RK3328_CLKGATE_CON(17), 12, GFLAGS),
+	GATE(0, "aclk_intmem", "aclk_bus_pre", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(15), 0, GFLAGS),
+	GATE(ACLK_DMAC, "aclk_dmac_bus", "aclk_bus_pre", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(15), 1, GFLAGS),
+
+	GATE(0, "hclk_rom", "hclk_bus_pre", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(15), 2, GFLAGS),
+	GATE(HCLK_I2S0_8CH, "hclk_i2s0_8ch", "hclk_bus_pre", 0,
+	     RK3328_CLKGATE_CON(15), 3, GFLAGS),
+	GATE(HCLK_I2S1_8CH, "hclk_i2s1_8ch", "hclk_bus_pre", 0,
+	     RK3328_CLKGATE_CON(15), 4, GFLAGS),
+	GATE(HCLK_I2S2_2CH, "hclk_i2s2_2ch", "hclk_bus_pre", 0,
+	     RK3328_CLKGATE_CON(15), 5, GFLAGS),
+	GATE(HCLK_SPDIF_8CH, "hclk_spdif_8ch", "hclk_bus_pre", 0,
+	     RK3328_CLKGATE_CON(15), 6, GFLAGS),
+	GATE(HCLK_TSP, "hclk_tsp", "hclk_bus_pre", 0,
+	     RK3328_CLKGATE_CON(17), 11, GFLAGS),
+	GATE(HCLK_CRYPTO_MST, "hclk_crypto_mst", "hclk_bus_pre", 0,
+	     RK3328_CLKGATE_CON(15), 7, GFLAGS),
+	GATE(HCLK_CRYPTO_SLV, "hclk_crypto_slv", "hclk_bus_pre", 0,
+	     RK3328_CLKGATE_CON(15), 8, GFLAGS),
+	GATE(0, "hclk_bus_niu", "hclk_bus_pre", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(15), 13, GFLAGS),
+	GATE(HCLK_PDM, "hclk_pdm", "hclk_bus_pre", 0,
+	     RK3328_CLKGATE_CON(28), 0, GFLAGS),
+
+	GATE(0, "pclk_bus_niu", "pclk_bus", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(15), 14, GFLAGS),
+	GATE(0, "pclk_efuse", "pclk_bus", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(15), 9, GFLAGS),
+	GATE(0, "pclk_otp", "pclk_bus", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(28), 4, GFLAGS),
+	GATE(PCLK_I2C0, "pclk_i2c0", "pclk_bus", 0,
+	     RK3328_CLKGATE_CON(15), 10, GFLAGS),
+	GATE(PCLK_I2C1, "pclk_i2c1", "pclk_bus", 0,
+	     RK3328_CLKGATE_CON(16), 0, GFLAGS),
+	GATE(PCLK_I2C2, "pclk_i2c2", "pclk_bus", 0,
+	     RK3328_CLKGATE_CON(16), 1, GFLAGS),
+	GATE(PCLK_I2C3, "pclk_i2c3", "pclk_bus", 0,
+	     RK3328_CLKGATE_CON(16), 2, GFLAGS),
+	GATE(PCLK_TIMER, "pclk_timer0", "pclk_bus", 0,
+	     RK3328_CLKGATE_CON(16), 3, GFLAGS),
+	GATE(0, "pclk_stimer", "pclk_bus", 0,
+	     RK3328_CLKGATE_CON(16), 4, GFLAGS),
+	GATE(PCLK_SPI, "pclk_spi", "pclk_bus", 0,
+	     RK3328_CLKGATE_CON(16), 5, GFLAGS),
+	GATE(PCLK_PWM, "pclk_rk_pwm", "pclk_bus", 0,
+	     RK3328_CLKGATE_CON(16), 6, GFLAGS),
+	GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_bus", 0,
+	     RK3328_CLKGATE_CON(16), 7, GFLAGS),
+	GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_bus", 0,
+	     RK3328_CLKGATE_CON(16), 8, GFLAGS),
+	GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_bus", 0,
+	     RK3328_CLKGATE_CON(16), 9, GFLAGS),
+	GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_bus", 0,
+	     RK3328_CLKGATE_CON(16), 10, GFLAGS),
+	GATE(PCLK_UART0, "pclk_uart0", "pclk_bus", 0,
+	     RK3328_CLKGATE_CON(16), 11, GFLAGS),
+	GATE(PCLK_UART1, "pclk_uart1", "pclk_bus", 0,
+	     RK3328_CLKGATE_CON(16), 12, GFLAGS),
+	GATE(PCLK_UART2, "pclk_uart2", "pclk_bus", 0,
+	     RK3328_CLKGATE_CON(16), 13, GFLAGS),
+	GATE(PCLK_TSADC, "pclk_tsadc", "pclk_bus", 0,
+	     RK3328_CLKGATE_CON(16), 14, GFLAGS),
+	GATE(PCLK_DCF, "pclk_dcf", "pclk_bus", 0,
+	     RK3328_CLKGATE_CON(16), 15, GFLAGS),
+	GATE(PCLK_GRF, "pclk_grf", "pclk_bus", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(17), 0, GFLAGS),
+	GATE(0, "pclk_cru", "pclk_bus", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(17), 4, GFLAGS),
+	GATE(0, "pclk_sgrf", "pclk_bus", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(17), 6, GFLAGS),
+	GATE(0, "pclk_sim", "pclk_bus", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(17), 10, GFLAGS),
+	GATE(PCLK_SARADC, "pclk_saradc", "pclk_bus", 0,
+	     RK3328_CLKGATE_CON(17), 15, GFLAGS),
+	GATE(0, "pclk_pmu", "pclk_bus", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(28), 3, GFLAGS),
+
+	GATE(PCLK_USB3PHY_OTG, "pclk_usb3phy_otg", "pclk_phy_pre", 0,
+	     RK3328_CLKGATE_CON(28), 1, GFLAGS),
+	GATE(PCLK_USB3PHY_PIPE, "pclk_usb3phy_pipe", "pclk_phy_pre", 0,
+	     RK3328_CLKGATE_CON(28), 2, GFLAGS),
+	GATE(PCLK_USB3_GRF, "pclk_usb3_grf", "pclk_phy_pre", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(17), 2, GFLAGS),
+	GATE(PCLK_USB2_GRF, "pclk_usb2_grf", "pclk_phy_pre", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(17), 14, GFLAGS),
+	GATE(0, "pclk_ddrphy", "pclk_phy_pre", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(17), 13, GFLAGS),
+	GATE(0, "pclk_acodecphy", "pclk_phy_pre", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(17), 5, GFLAGS),
+	GATE(PCLK_HDMIPHY, "pclk_hdmiphy", "pclk_phy_pre", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(17), 7, GFLAGS),
+	GATE(0, "pclk_vdacphy", "pclk_phy_pre", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(17), 8, GFLAGS),
+	GATE(0, "pclk_phy_niu", "pclk_phy_pre", CLK_IGNORE_UNUSED,
+	     RK3328_CLKGATE_CON(15), 15, GFLAGS),
+
+	/* PD_MMC */
+	MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc",
+	    RK3328_SDMMC_CON0, 1),
+	MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc",
+	    RK3328_SDMMC_CON1, 1),
+
+	MMC(SCLK_SDIO_DRV, "sdio_drv", "sclk_sdio",
+	    RK3328_SDIO_CON0, 1),
+	MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "sclk_sdio",
+	    RK3328_SDIO_CON1, 1),
+
+	MMC(SCLK_EMMC_DRV, "emmc_drv", "sclk_emmc",
+	    RK3328_EMMC_CON0, 1),
+	MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc",
+	    RK3328_EMMC_CON1, 1),
+
+	MMC(SCLK_SDMMC_EXT_DRV, "sdmmc_ext_drv", "sclk_sdmmc_ext",
+	    RK3328_SDMMC_EXT_CON0, 1),
+	MMC(SCLK_SDMMC_EXT_SAMPLE, "sdmmc_ext_sample", "sclk_sdmmc_ext",
+	    RK3328_SDMMC_EXT_CON1, 1),
+};
+
+static struct rockchip_clk_branch rk3328_clk_grf_branches[] __initdata = {
+	/*
+	 * GRF CRU Clock-Architecture
+	 */
+	MUX(SCLK_MAC2IO, "clk_mac2io", mux_mac2io_src_p, 0,
+	    RK3328_GRF_MAC_CON1, 10, 1, MFLAGS),
+	MUX(SCLK_MAC2PHY, "clk_mac2phy", mux_mac2phy_src_p, 0,
+	    RK3328_GRF_MAC_CON2, 10, 1, MFLAGS),
+};
+
+static const char *const rk3328_critical_clocks[] __initconst = {
+	"aclk_bus",
+	"pclk_bus",
+	"hclk_bus",
+	"aclk_peri",
+	"hclk_peri",
+	"pclk_peri",
+	"pclk_dbg",
+	"aclk_core_niu",
+	"aclk_gic400",
+	"aclk_intmem",
+	"hclk_rom",
+	"pclk_grf",
+	"pclk_cru",
+	"pclk_sgrf",
+	"pclk_timer0",
+	"clk_timer0",
+	"pclk_ddr_msch",
+	"pclk_ddr_mon",
+	"pclk_ddr_grf",
+	"clk_ddrupctl",
+	"clk_ddrmsch",
+	"hclk_ahb1tom",
+	"clk_jtag",
+	"pclk_ddrphy",
+	"pclk_pmu",
+	"hclk_otg_pmu",
+	"aclk_rga_niu",
+	"pclk_vio_h2p",
+	"hclk_vio_h2p",
+};
+
+static void __iomem *rk3328_cru_base;
+
+void rk3328_dump_cru(void)
+{
+	if (rk3328_cru_base) {
+		pr_warn("CRU:\n");
+		print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET,
+			       32, 4, rk3328_cru_base,
+			       0x400, false);
+	}
+}
+EXPORT_SYMBOL_GPL(rk3328_dump_cru);
+
+static int rk3328_clk_panic(struct notifier_block *this,
+			    unsigned long ev, void *ptr)
+{
+	rk3328_dump_cru();
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block rk3328_clk_panic_block = {
+	.notifier_call = rk3328_clk_panic,
+};
+
+static void __init rk3328_clk_init(struct device_node *np)
+{
+	struct rockchip_clk_provider *ctx;
+	void __iomem *reg_base;
+
+	reg_base = of_iomap(np, 0);
+	if (!reg_base) {
+		pr_err("%s: could not map cru region\n", __func__);
+		return;
+	}
+
+	rk3328_cru_base = reg_base;
+
+	ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS);
+	if (IS_ERR(ctx)) {
+		pr_err("%s: rockchip clk init failed\n", __func__);
+		iounmap(reg_base);
+		return;
+	}
+
+	rockchip_clk_register_plls(ctx, rk3328_pll_clks,
+				   ARRAY_SIZE(rk3328_pll_clks),
+				   RK3328_GRF_SOC_STATUS0);
+	rockchip_clk_register_branches(ctx, rk3328_clk_branches,
+				       ARRAY_SIZE(rk3328_clk_branches));
+	rockchip_clk_protect_critical(rk3328_critical_clocks,
+				      ARRAY_SIZE(rk3328_critical_clocks));
+
+	rockchip_clk_register_armclk(ctx, ARMCLK, "armclk",
+				     mux_armclk_p, ARRAY_SIZE(mux_armclk_p),
+				     &rk3328_cpuclk_data, rk3328_cpuclk_rates,
+				     ARRAY_SIZE(rk3328_cpuclk_rates));
+
+	rockchip_register_softrst(np, 11, reg_base + RK3328_SOFTRST_CON(0),
+				  ROCKCHIP_SOFTRST_HIWORD_MASK);
+
+	rockchip_register_restart_notifier(ctx, RK3328_GLB_SRST_FST, NULL);
+
+	rockchip_clk_of_add_provider(np, ctx);
+
+	atomic_notifier_chain_register(&panic_notifier_list,
+				       &rk3328_clk_panic_block);
+}
+
+CLK_OF_DECLARE(rk3328_cru, "rockchip,rk3328-cru", rk3328_clk_init);
+
+static void __init rk3328_grf_clk_init(struct device_node *np)
+{
+	struct rockchip_clk_provider *ctx;
+	void __iomem *reg_base;
+
+	reg_base = of_iomap(np, 0);
+	if (!reg_base) {
+		pr_err("%s: could not map cru pmu region\n", __func__);
+		return;
+	}
+
+	ctx = rockchip_clk_init(np, reg_base, CLKGRF_NR_CLKS);
+	if (IS_ERR(ctx)) {
+		pr_err("%s: rockchip pmu clk init failed\n", __func__);
+		return;
+	}
+
+	rockchip_clk_register_branches(ctx, rk3328_clk_grf_branches,
+				       ARRAY_SIZE(rk3328_clk_grf_branches));
+
+	rockchip_clk_of_add_provider(np, ctx);
+}
+
+CLK_OF_DECLARE(rk3328_cru_grf, "rockchip,rk3328-grf", rk3328_grf_clk_init);
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index d67eecc4ade9..7225997f8d52 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -91,6 +91,28 @@
 #define RK3288_EMMC_CON0		0x218
 #define RK3288_EMMC_CON1		0x21c
 
+#define RK3328_PLL_CON(x)		RK2928_PLL_CON(x)
+#define RK3328_CLKSEL_CON(x)		((x) * 0x4 + 0x100)
+#define RK3328_CLKGATE_CON(x)		((x) * 0x4 + 0x200)
+#define RK3328_GRFCLKSEL_CON(x)		((x) * 0x4 + 0x100)
+#define RK3328_GLB_SRST_FST		0x9c
+#define RK3328_GLB_SRST_SND		0x98
+#define RK3328_SOFTRST_CON(x)		((x) * 0x4 + 0x300)
+#define RK3328_MODE_CON			0x80
+#define RK3328_MISC_CON			0x84
+#define RK3328_DIV_ACLKM_MASK		0x7
+#define RK3328_DIV_ACLKM_SHIFT		4
+#define RK3328_DIV_PCLK_DBG_MASK	0xf
+#define RK3328_DIV_PCLK_DBG_SHIFT	0
+#define RK3328_SDMMC_CON0		0x380
+#define RK3328_SDMMC_CON1		0x384
+#define RK3328_SDIO_CON0		0x388
+#define RK3328_SDIO_CON1		0x38c
+#define RK3328_EMMC_CON0		0x390
+#define RK3328_EMMC_CON1		0x394
+#define RK3328_SDMMC_EXT_CON0		0x398
+#define RK3328_SDMMC_EXT_CON1		0x39C
+
 #define RK3368_PLL_CON(x)		RK2928_PLL_CON(x)
 #define RK3368_CLKSEL_CON(x)		((x) * 0x4 + 0x100)
 #define RK3368_CLKGATE_CON(x)		((x) * 0x4 + 0x200)
@@ -130,6 +152,7 @@
 enum rockchip_pll_type {
 	pll_rk3036,
 	pll_rk3066,
+	pll_rk3328,
 	pll_rk3399,
 };
 
-- 
1.9.1

^ permalink raw reply related

* [PATCH v2 2/4] dt-bindings: add bindings for rk3328 clock controller
From: Elaine Zhang @ 2016-12-19  1:56 UTC (permalink / raw)
  To: heiko-4mtYJXux2i+zQB+pC5nmwQ, mturquette-rdvid1DuHRBWk0Htik3J/w,
	sboyd-sgV2jX0FEOL9JmXXK+q4OQ, xf-TNX95d0MmH7DzftRWevZcw
  Cc: mark.rutland-5wv7dgnIgG8, devicetree-u79uwXL29TY76Z2rM5mHXA,
	huangtao-TNX95d0MmH7DzftRWevZcw, xxx-TNX95d0MmH7DzftRWevZcw,
	Elaine Zhang, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, cl-TNX95d0MmH7DzftRWevZcw,
	linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <1482112573-11613-1-git-send-email-zhangqing-TNX95d0MmH7DzftRWevZcw@public.gmane.org>

Add devicetree bindings for Rockchip cru which found on
Rockchip SoCs.

Signed-off-by: Elaine Zhang <zhangqing-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
---
 .../bindings/clock/rockchip,rk3328-cru.txt         | 57 ++++++++++++++++++++++
 1 file changed, 57 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.txt

diff --git a/Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.txt b/Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.txt
new file mode 100644
index 000000000000..20053494d49f
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.txt
@@ -0,0 +1,57 @@
+* Rockchip RK3328 Clock and Reset Unit
+
+The RK3328 clock controller generates and supplies clock to various
+controllers within the SoC and also implements a reset controller for SoC
+peripherals.
+
+Required Properties:
+
+- compatible: should be "rockchip,rk3328-cru"
+- reg: physical base address of the controller and length of memory mapped
+  region.
+- #clock-cells: should be 1.
+- #reset-cells: should be 1.
+
+Optional Properties:
+
+- rockchip,grf: phandle to the syscon managing the "general register files"
+  If missing pll rates are not changeable, due to the missing pll lock status.
+
+Each clock is assigned an identifier and client nodes can use this identifier
+to specify the clock which they consume. All available clocks are defined as
+preprocessor macros in the dt-bindings/clock/rk3328-cru.h headers and can be
+used in device tree sources. Similar macros exist for the reset sources in
+these files.
+
+External clocks:
+
+There are several clocks that are generated outside the SoC. It is expected
+that they are defined using standard clock bindings with following
+clock-output-names:
+ - "xin24m" - crystal input - required,
+ - "clkin_i2s" - external I2S clock - optional,
+ - "gmac_clkin" - external GMAC clock - optional
+ - "phy_50m_out" - output clock of the pll in the mac phy
+
+Example: Clock controller node:
+
+	cru: clock-controller@ff440000 {
+		compatible = "rockchip,rk3328-cru", "rockchip,cru", "syscon";
+		reg = <0x0 0xff440000 0x0 0x1000>;
+		rockchip,grf = <&grf>;
+
+		#clock-cells = <1>;
+		#reset-cells = <1>;
+	};
+
+Example: UART controller node that consumes the clock generated by the clock
+  controller:
+
+	uart0: serial@ff120000 {
+		compatible = "snps,dw-apb-uart";
+		reg = <0xff120000 0x100>;
+		interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
+		reg-shift = <2>;
+		reg-io-width = <4>;
+		clocks = <&cru SCLK_UART0>;
+	};
-- 
1.9.1

^ permalink raw reply related

* [PATCH v2 1/4] clk: rockchip: add dt-binding header for rk3328
From: Elaine Zhang @ 2016-12-19  1:56 UTC (permalink / raw)
  To: heiko, mturquette, sboyd, xf
  Cc: robh+dt, mark.rutland, linux-clk, linux-arm-kernel, devicetree,
	huangtao, xxx, cl, linux-rockchip, linux-kernel, Elaine Zhang
In-Reply-To: <1482112573-11613-1-git-send-email-zhangqing@rock-chips.com>

Add the dt-bindings header for the rk3328, that gets shared between
the clock controller and the clock references in the dts.
Add softreset ID for rk3328.

Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
---
 include/dt-bindings/clock/rk3328-cru.h | 403 +++++++++++++++++++++++++++++++++
 1 file changed, 403 insertions(+)
 create mode 100644 include/dt-bindings/clock/rk3328-cru.h

diff --git a/include/dt-bindings/clock/rk3328-cru.h b/include/dt-bindings/clock/rk3328-cru.h
new file mode 100644
index 000000000000..545ed7541316
--- /dev/null
+++ b/include/dt-bindings/clock/rk3328-cru.h
@@ -0,0 +1,403 @@
+/*
+ * Copyright (c) 2016 Rockchip Electronics Co. Ltd.
+ * Author: Elaine <zhangqing@rock-chips.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _DT_BINDINGS_CLK_ROCKCHIP_RK3328_H
+#define _DT_BINDINGS_CLK_ROCKCHIP_RK3328_H
+
+/* core clocks */
+#define PLL_APLL		1
+#define PLL_DPLL		2
+#define PLL_CPLL		3
+#define PLL_GPLL		4
+#define PLL_NPLL		5
+#define ARMCLK			6
+
+/* sclk gates (special clocks) */
+#define SCLK_RTC32K		30
+#define SCLK_SDMMC_EXT		31
+#define SCLK_SPI		32
+#define SCLK_SDMMC		33
+#define SCLK_SDIO		34
+#define SCLK_EMMC		35
+#define SCLK_TSADC		36
+#define SCLK_SARADC		37
+#define SCLK_UART0		38
+#define SCLK_UART1		39
+#define SCLK_UART2		40
+#define SCLK_I2S0		41
+#define SCLK_I2S1		42
+#define SCLK_I2S2		43
+#define SCLK_I2S1_OUT		44
+#define SCLK_I2S2_OUT		45
+#define SCLK_SPDIF		46
+#define SCLK_TIMER0		47
+#define SCLK_TIMER1		48
+#define SCLK_TIMER2		49
+#define SCLK_TIMER3		50
+#define SCLK_TIMER4		51
+#define SCLK_TIMER5		52
+#define SCLK_WIFI		53
+#define SCLK_CIF_OUT		54
+#define SCLK_I2C0		55
+#define SCLK_I2C1		56
+#define SCLK_I2C2		57
+#define SCLK_I2C3		58
+#define SCLK_CRYPTO		59
+#define SCLK_PWM		60
+#define SCLK_PDM		61
+#define SCLK_EFUSE		62
+#define SCLK_OTP		63
+#define SCLK_DDRCLK		64
+#define SCLK_VDEC_CABAC		65
+#define SCLK_VDEC_CORE		66
+#define SCLK_VENC_DSP		67
+#define SCLK_VENC_CORE		68
+#define SCLK_RGA		69
+#define SCLK_HDMI_SFC		70
+#define SCLK_HDMI_CEC		71
+#define SCLK_USB3_REF		72
+#define SCLK_USB3_SUSPEND	73
+#define SCLK_SDMMC_DRV		74
+#define SCLK_SDIO_DRV		75
+#define SCLK_EMMC_DRV		76
+#define SCLK_SDMMC_EXT_DRV	77
+#define SCLK_SDMMC_SAMPLE	78
+#define SCLK_SDIO_SAMPLE	79
+#define SCLK_EMMC_SAMPLE	80
+#define SCLK_SDMMC_EXT_SAMPLE	81
+#define SCLK_VOP		82
+#define SCLK_MAC2PHY_RXTX	83
+#define SCLK_MAC2PHY_SRC	84
+#define SCLK_MAC2PHY_REF	85
+#define SCLK_MAC2PHY_OUT	86
+#define SCLK_MAC2IO_RX		87
+#define SCLK_MAC2IO_TX		88
+#define SCLK_MAC2IO_REFOUT	89
+#define SCLK_MAC2IO_REF		90
+#define SCLK_MAC2IO_OUT		91
+#define SCLK_TSP		92
+#define SCLK_HSADC_TSP		93
+#define SCLK_USB3PHY_REF	94
+#define SCLK_REF_USB3OTG	95
+#define SCLK_USB3OTG_REF	96
+#define SCLK_USB3OTG_SUSPEND	97
+#define SCLK_REF_USB3OTG_SRC	98
+#define SCLK_MAC2IO_SRC		99
+
+/* dclk gates */
+#define DCLK_LCDC		180
+#define DCLK_HDMIPHY		181
+#define HDMIPHY			182
+#define USB480M			183
+#define DCLK_LCDC_SRC		184
+
+/* aclk gates */
+#define ACLK_AXISRAM		190
+#define ACLK_VOP_PRE		191
+#define ACLK_USB3OTG		192
+#define ACLK_RGA_PRE		193
+#define ACLK_DMAC		194
+#define ACLK_GPU		195
+#define ACLK_BUS_PRE		196
+#define ACLK_PERI_PRE		197
+#define ACLK_RKVDEC_PRE		198
+#define ACLK_RKVDEC		199
+#define ACLK_RKVENC		200
+#define ACLK_VPU_PRE		201
+#define ACLK_VIO_PRE		202
+#define ACLK_VPU		203
+#define ACLK_VIO		204
+#define ACLK_VOP		205
+#define ACLK_GMAC		206
+#define ACLK_H265		207
+#define ACLK_H264		208
+#define ACLK_MAC2PHY		209
+#define ACLK_MAC2IO		210
+#define ACLK_DCF		211
+#define ACLK_TSP		212
+#define ACLK_PERI		213
+#define ACLK_RGA		214
+#define ACLK_IEP		215
+#define ACLK_CIF		216
+#define ACLK_HDCP		217
+
+/* pclk gates */
+#define PCLK_GPIO0		300
+#define PCLK_GPIO1		301
+#define PCLK_GPIO2		302
+#define PCLK_GPIO3		303
+#define PCLK_GRF		304
+#define PCLK_I2C0		305
+#define PCLK_I2C1		306
+#define PCLK_I2C2		307
+#define PCLK_I2C3		308
+#define PCLK_SPI		309
+#define PCLK_UART0		310
+#define PCLK_UART1		311
+#define PCLK_UART2		312
+#define PCLK_TSADC		313
+#define PCLK_PWM		314
+#define PCLK_TIMER		315
+#define PCLK_BUS_PRE		316
+#define PCLK_PERI_PRE		317
+#define PCLK_HDMI_CTRL		318
+#define PCLK_HDMI_PHY		319
+#define PCLK_GMAC		320
+#define PCLK_H265		321
+#define PCLK_MAC2PHY		322
+#define PCLK_MAC2IO		323
+#define PCLK_USB3PHY_OTG	324
+#define PCLK_USB3PHY_PIPE	325
+#define PCLK_USB3_GRF		326
+#define PCLK_USB2_GRF		327
+#define PCLK_HDMIPHY		328
+#define PCLK_DDR		329
+#define PCLK_PERI		330
+#define PCLK_HDMI		331
+#define PCLK_HDCP		332
+#define PCLK_DCF		333
+#define PCLK_SARADC		334
+
+/* hclk gates */
+#define HCLK_PERI		408
+#define HCLK_TSP		409
+#define HCLK_GMAC		410
+#define HCLK_I2S0_8CH		411
+#define HCLK_I2S1_8CH		413
+#define HCLK_I2S2_2CH		413
+#define HCLK_SPDIF_8CH		414
+#define HCLK_VOP		415
+#define HCLK_NANDC		416
+#define HCLK_SDMMC		417
+#define HCLK_SDIO		418
+#define HCLK_EMMC		419
+#define HCLK_SDMMC_EXT		420
+#define HCLK_RKVDEC_PRE		421
+#define HCLK_RKVDEC		422
+#define HCLK_RKVENC		423
+#define HCLK_VPU_PRE		424
+#define HCLK_VIO_PRE		425
+#define HCLK_VPU		426
+#define HCLK_VIO		427
+#define HCLK_BUS_PRE		428
+#define HCLK_PERI_PRE		429
+#define HCLK_H264		430
+#define HCLK_CIF		431
+#define HCLK_OTG_PMU		432
+#define HCLK_OTG		433
+#define HCLK_HOST0		434
+#define HCLK_HOST0_ARB		435
+#define HCLK_CRYPTO_MST		436
+#define HCLK_CRYPTO_SLV		437
+#define HCLK_PDM		438
+#define HCLK_IEP		439
+#define HCLK_RGA		440
+#define HCLK_HDCP		441
+
+#define CLK_NR_CLKS		(HCLK_HDCP + 1)
+
+#define SCLK_MAC2IO		0
+#define SCLK_MAC2PHY		1
+
+#define CLKGRF_NR_CLKS		(SCLK_MAC2PHY + 1)
+
+/* soft-reset indices */
+#define SRST_CORE0_PO		0
+#define SRST_CORE1_PO		1
+#define SRST_CORE2_PO		2
+#define SRST_CORE3_PO		3
+#define SRST_CORE0		4
+#define SRST_CORE1		5
+#define SRST_CORE2		6
+#define SRST_CORE3		7
+#define SRST_CORE0_DBG		8
+#define SRST_CORE1_DBG		9
+#define SRST_CORE2_DBG		10
+#define SRST_CORE3_DBG		11
+#define SRST_TOPDBG		12
+#define SRST_CORE_NIU		13
+#define SRST_STRC_A		14
+#define SRST_L2C		15
+
+#define SRST_A53_GIC		18
+#define SRST_DAP		19
+#define SRST_PMU_P		21
+#define SRST_EFUSE		22
+#define SRST_BUSSYS_H		23
+#define SRST_BUSSYS_P		24
+#define SRST_SPDIF		25
+#define SRST_INTMEM		26
+#define SRST_ROM		27
+#define SRST_GPIO0		28
+#define SRST_GPIO1		29
+#define SRST_GPIO2		30
+#define SRST_GPIO3		31
+
+#define SRST_I2S0		32
+#define SRST_I2S1		33
+#define SRST_I2S2		34
+#define SRST_I2S0_H		35
+#define SRST_I2S1_H		36
+#define SRST_I2S2_H		37
+#define SRST_UART0		38
+#define SRST_UART1		39
+#define SRST_UART2		40
+#define SRST_UART0_P		41
+#define SRST_UART1_P		42
+#define SRST_UART2_P		43
+#define SRST_I2C0		44
+#define SRST_I2C1		45
+#define SRST_I2C2		46
+#define SRST_I2C3		47
+
+#define SRST_I2C0_P		48
+#define SRST_I2C1_P		49
+#define SRST_I2C2_P		50
+#define SRST_I2C3_P		51
+#define SRST_EFUSE_SE_P		52
+#define SRST_EFUSE_NS_P		53
+#define SRST_PWM0		54
+#define SRST_PWM0_P		55
+#define SRST_DMA		56
+#define SRST_TSP_A		57
+#define SRST_TSP_H		58
+#define SRST_TSP		59
+#define SRST_TSP_HSADC		60
+#define SRST_DCF_A		61
+#define SRST_DCF_P		62
+
+#define SRST_SCR		64
+#define SRST_SPI		65
+#define SRST_TSADC		66
+#define SRST_TSADC_P		67
+#define SRST_CRYPTO		68
+#define SRST_SGRF		69
+#define SRST_GRF		70
+#define SRST_USB_GRF		71
+#define SRST_TIMER_6CH_P	72
+#define SRST_TIMER0		73
+#define SRST_TIMER1		74
+#define SRST_TIMER2		75
+#define SRST_TIMER3		76
+#define SRST_TIMER4		77
+#define SRST_TIMER5		78
+#define SRST_USB3GRF		79
+
+#define SRST_PHYNIU		80
+#define SRST_HDMIPHY		81
+#define SRST_VDAC		82
+#define SRST_ACODEC_p		83
+#define SRST_SARADC		85
+#define SRST_SARADC_P		86
+#define SRST_GRF_DDR		87
+#define SRST_DFIMON		88
+#define SRST_MSCH		89
+#define SRST_DDRMSCH		91
+#define SRST_DDRCTRL		92
+#define SRST_DDRCTRL_P		93
+#define SRST_DDRPHY		94
+#define SRST_DDRPHY_P		95
+
+#define SRST_GMAC_NIU_A		96
+#define SRST_GMAC_NIU_P		97
+#define SRST_GMAC2PHY_A		98
+#define SRST_GMAC2IO_A		99
+#define SRST_MACPHY		100
+#define SRST_OTP_PHY		101
+#define SRST_GPU_A		102
+#define SRST_GPU_NIU_A		103
+#define SRST_SDMMCEXT		104
+#define SRST_PERIPH_NIU_A	105
+#define SRST_PERIHP_NIU_H	106
+#define SRST_PERIHP_P		107
+#define SRST_PERIPHSYS_H	108
+#define SRST_MMC0		109
+#define SRST_SDIO		110
+#define SRST_EMMC		111
+
+#define SRST_USB2OTG_H		112
+#define SRST_USB2OTG		113
+#define SRST_USB2OTG_ADP	114
+#define SRST_USB2HOST_H		115
+#define SRST_USB2HOST_ARB	116
+#define SRST_USB2HOST_AUX	117
+#define SRST_USB2HOST_EHCIPHY	118
+#define SRST_USB2HOST_UTMI	119
+#define SRST_USB3OTG		120
+#define SRST_USBPOR		121
+#define SRST_USB2OTG_UTMI	122
+#define SRST_USB2HOST_PHY_UTMI	123
+#define SRST_USB3OTG_UTMI	124
+#define SRST_USB3PHY_U2		125
+#define SRST_USB3PHY_U3		126
+#define SRST_USB3PHY_PIPE	127
+
+#define SRST_VIO_A		128
+#define SRST_VIO_BUS_H		129
+#define SRST_VIO_H2P_H		130
+#define SRST_VIO_ARBI_H		131
+#define SRST_VOP_NIU_A		132
+#define SRST_VOP_A		133
+#define SRST_VOP_H		134
+#define SRST_VOP_D		135
+#define SRST_RGA		136
+#define SRST_RGA_NIU_A		137
+#define SRST_RGA_A		138
+#define SRST_RGA_H		139
+#define SRST_IEP_A		140
+#define SRST_IEP_H		141
+#define SRST_HDMI		142
+#define SRST_HDMI_P		143
+
+#define SRST_HDCP_A		144
+#define SRST_HDCP		145
+#define SRST_HDCP_H		146
+#define SRST_CIF_A		147
+#define SRST_CIF_H		148
+#define SRST_CIF_P		149
+#define SRST_OTP_P		150
+#define SRST_OTP_SBPI		151
+#define SRST_OTP_USER		152
+#define SRST_DDRCTRL_A		153
+#define SRST_DDRSTDY_P		154
+#define SRST_DDRSTDY		155
+#define SRST_PDM_H		156
+#define SRST_PDM		157
+#define SRST_USB3PHY_OTG_P	158
+#define SRST_USB3PHY_PIPE_P	159
+
+#define SRST_VCODEC_A		160
+#define SRST_VCODEC_NIU_A	161
+#define SRST_VCODEC_H		162
+#define SRST_VCODEC_NIU_H	163
+#define SRST_VDEC_A		164
+#define SRST_VDEC_NIU_A		165
+#define SRST_VDEC_H		166
+#define SRST_VDEC_NIU_H		167
+#define SRST_VDEC_CORE		168
+#define SRST_VDEC_CABAC		169
+#define SRST_DDRPHYDIV		175
+
+#define SRST_RKVENC_NIU_A	176
+#define SRST_RKVENC_NIU_H	177
+#define SRST_RKVENC_H265_A	178
+#define SRST_RKVENC_H265_P	179
+#define SRST_RKVENC_H265_CORE	180
+#define SRST_RKVENC_H265_DSP	181
+#define SRST_RKVENC_H264_A	182
+#define SRST_RKVENC_H264_H	183
+#define SRST_RKVENC_INTMEM	184
+
+#endif
-- 
1.9.1

^ permalink raw reply related

* [PATCH v2 0/4] clk: rockchip: support clk controller for rk3328 SoC
From: Elaine Zhang @ 2016-12-19  1:56 UTC (permalink / raw)
  To: heiko, mturquette, sboyd, xf
  Cc: robh+dt, mark.rutland, linux-clk, linux-arm-kernel, devicetree,
	huangtao, xxx, cl, linux-rockchip, linux-kernel, Elaine Zhang

Changes in v2:
  add bindings for rk3328 clock controller

Elaine Zhang (4):
  clk: rockchip: add dt-binding header for rk3328
  dt-bindings: add bindings for rk3328 clock controller
  clk: rockchip: add clock controller for rk3328
  clk: rockchip: add new pll-type for rk3328

 .../bindings/clock/rockchip,rk3328-cru.txt         |   57 ++
 drivers/clk/rockchip/Makefile                      |    1 +
 drivers/clk/rockchip/clk-pll.c                     |   13 +-
 drivers/clk/rockchip/clk-rk3328.c                  | 1068 ++++++++++++++++++++
 drivers/clk/rockchip/clk.h                         |   23 +
 include/dt-bindings/clock/rk3328-cru.h             |  403 ++++++++
 6 files changed, 1564 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.txt
 create mode 100644 drivers/clk/rockchip/clk-rk3328.c
 create mode 100644 include/dt-bindings/clock/rk3328-cru.h

-- 
1.9.1

^ permalink raw reply

* [PATCH 3/3] of/overlay: documentation for sysfs ABI
From: Heinrich Schuchardt @ 2016-12-19  1:10 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, Frank Rowand
  Cc: devicetree, linux-kernel, Heinrich Schuchardt
In-Reply-To: <1482109835-9000-1-git-send-email-xypron.glpk@gmx.de>

The sysfs filesystem ABI to load and unload devicetree
overlays is decribed.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
 .../ABI/testing/sysfs-firmware-devicetree-overlays | 24 ++++++++++++++++++++++
 1 file changed, 24 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-firmware-devicetree-overlays

diff --git a/Documentation/ABI/testing/sysfs-firmware-devicetree-overlays b/Documentation/ABI/testing/sysfs-firmware-devicetree-overlays
new file mode 100644
index 000000000000..ce25b637028c
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-firmware-devicetree-overlays
@@ -0,0 +1,24 @@
+What:		/sys/firmware/devicetree-overlays
+Date:		Dec 2016
+KernelVersion:	4.11
+Contact:	Heinrich Schuchardt <xypron.glpk@gmx.de>
+Description:	Devicetree overlays can be used to update the devicetree
+		while the system is running. For details see
+		Documentation/devicetree/overlay-notes.txt.
+
+		The following attributes are provided:
+
+		load:	This is a write only file.
+			A string written to it is interpreted as the path to a
+			flattened device tree overlay file. It is used to create
+			and apply the contained overlays.
+
+		loaded: This is a read only file.
+			It provides the count of loaded overlays as a decimal
+			number.
+
+		unload: This is a write only file.
+		        If a positive number n is wrtten to this file the n
+			most recent overlays are destroyed.
+			If a negative number is written to this file all
+			overlays are destroyed.
-- 
2.11.0

^ permalink raw reply related

* [PATCH 2/3] of/overlay: sysfs based ABI for dt overlays
From: Heinrich Schuchardt @ 2016-12-19  1:10 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, Frank Rowand
  Cc: devicetree, linux-kernel, Heinrich Schuchardt
In-Reply-To: <1482109835-9000-1-git-send-email-xypron.glpk@gmx.de>

Currently the kernel only supplies an internal API for creating
and destroying device tree overlays.

For some boards vendor specific kernel modules exist for
managing device tree overlays but the have not been
upstreamed.

This patch provides a sysfs based ABI for creation and destruction
of dt overlays in /sys/firmware/devicetree-overlay.

The following files are provided:

load:   This is a write only file.
        A string written to it is interpreted as the path to a
        flattened device tree overlay file. It is used to create
        and apply the contained overlays.

loaded: This is a read only file.
        It provides the count of loaded overlays as a decimal
        number.

unload: This is a write only file.
        If a positive number n is wrtten to this file the n
        most recent overlays are destroyed.
        If a negative number is written to this file all
        overlays are destroyed.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
 drivers/of/Kconfig    |  14 ++++
 drivers/of/Makefile   |   2 +
 drivers/of/ov_sysfs.c | 214 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 230 insertions(+)
 create mode 100644 drivers/of/ov_sysfs.c

diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index ba7b034b2b91..c981a7e84bcb 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -109,6 +109,20 @@ config OF_OVERLAY
 	  While this option is selected automatically when needed, you can
 	  enable it manually to improve device tree unit test coverage.
 
+if OF_OVERLAY
+
+config OF_OVERLAY_SYSFS
+
+	tristate "Sysfs support for device tree overlays"
+	default m
+	depends on SYSFS
+	help
+	  This module provides a sysfs based ABI to manage device tree
+	  overlays. You can use it to create overlays based on flattened
+	  device tree overlay files and to destroy them.
+
+endif # OF_OVERLAY
+
 config OF_NUMA
 	bool
 
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index d7efd9d458aa..7026de457a04 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -16,3 +16,5 @@ obj-$(CONFIG_OF_OVERLAY) += overlay.o
 obj-$(CONFIG_OF_NUMA) += of_numa.o
 
 obj-$(CONFIG_OF_UNITTEST) += unittest-data/
+
+obj-$(CONFIG_OF_OVERLAY_SYSFS) += ov_sysfs.o
diff --git a/drivers/of/ov_sysfs.c b/drivers/of/ov_sysfs.c
new file mode 100644
index 000000000000..eb1b8fd4bc32
--- /dev/null
+++ b/drivers/of/ov_sysfs.c
@@ -0,0 +1,214 @@
+/*
+ * Sysfs ABI for device tree overlays
+ *
+ * Copyright (C) 2016  Heinrich Schuchardt <xypron.glpk@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License,
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/fcntl.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/libfdt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/uaccess.h>
+
+static int of_create_overlay_from_file(const char *path)
+{
+	struct file *filp = NULL;
+	mm_segment_t fs;
+	int ret = 0;
+	loff_t size;
+	char *buffer = NULL;
+	ssize_t bytes_read;
+	loff_t offset = 0;
+	struct device_node *overlay = NULL;
+
+	fs = get_fs();
+	set_fs(get_ds());
+	filp = filp_open(path, O_RDONLY | O_LARGEFILE, 0);
+	if (IS_ERR(filp)) {
+		ret = PTR_ERR(filp);
+		goto err_file_open;
+	}
+
+	if (!S_ISREG(filp->f_inode->i_mode)) {
+		ret = -EISDIR;
+		goto err_file_read;
+	}
+	size = i_size_read(filp->f_inode);
+	buffer = vmalloc(size);
+	if (buffer == NULL) {
+		ret = -ENOMEM;
+		goto err_malloc;
+	}
+	for (; size > 0; ) {
+		bytes_read = vfs_read(filp, buffer, size, &offset);
+		if (bytes_read == 0)
+			break;
+		if (bytes_read < 0) {
+			ret = bytes_read;
+			goto err_file_read;
+		}
+		size -= bytes_read;
+	}
+	if (offset < sizeof(struct fdt_header) ||
+	    offset < fdt_totalsize(buffer)) {
+		pr_err("OF: Size of %s does not match header information\n",
+		       path);
+		ret = -EINVAL;
+		goto err_file_read;
+	}
+	overlay = of_fdt_unflatten_tree((unsigned long *) buffer, NULL, NULL);
+	if (overlay == NULL) {
+		pr_err("OF: Cannot unflatten %s\n", path);
+		ret = -EINVAL;
+		goto err_file_read;
+	}
+	of_node_set_flag(overlay, OF_DETACHED);
+	ret = of_resolve_phandles(overlay);
+	if (ret < 0) {
+		pr_err("OF: Failed to resolve phandles for %s\n", path);
+		goto err_overlay;
+	}
+	ret = of_overlay_create(overlay);
+	if (ret < 0) {
+		pr_err("OF: Cannot create overlay from %s\n", path);
+	} else {
+		pr_info("OF: Overlay %d created from %s\n", ret, path);
+		ret = 0;
+	}
+err_overlay:
+	of_node_put(overlay);
+err_file_read:
+	vfree(buffer);
+err_malloc:
+	fput(filp);
+err_file_open:
+	set_fs(fs);
+	return ret;
+}
+
+static ssize_t attribute_read(struct kobject *kobj,
+			      struct kobj_attribute *attr,
+			      char *buf)
+{
+	int ret;
+
+	if (strcmp(attr->attr.name, "loaded") == 0)
+		ret = sprintf(buf, "%d\n", of_overlay_count());
+	else
+		ret = -ENOENT;
+
+	return ret;
+}
+
+static ssize_t attribute_write(struct kobject *kobj,
+			       struct kobj_attribute *attr,
+			       const char *buf, size_t size)
+{
+	char *parameter;
+	int ret;
+	long count;
+
+	if (size > PATH_MAX)
+		return -ENAMETOOLONG;
+
+	/* The parameter has to be terminated either by LF or \0. */
+
+	switch (buf[size - 1]) {
+	case 0x00:
+	case 0x0a:
+		break;
+	default:
+		return -ENOENT;
+	}
+	parameter = vmalloc(size);
+	if (!parameter)
+		return -ENOMEM;
+	memcpy(parameter, buf, size);
+	parameter[size - 1] = 0x00;
+
+	if (strcmp(attr->attr.name, "load") == 0) {
+		ret = of_create_overlay_from_file(parameter);
+		if (!ret)
+			ret = size;
+	} else if (strcmp(attr->attr.name, "unload") == 0) {
+		ret = kstrtol(parameter, 0, &count);
+		if (ret)
+			goto out;
+		if (count < 0)
+			ret = of_overlay_destroy_all();
+		else
+			for (; count > 0; --count) {
+				ret = of_overlay_destroy_last();
+				if (ret)
+					goto out;
+			}
+		ret = size;
+	} else
+		ret = -ENOENT;
+out:
+	vfree(parameter);
+
+	return ret;
+}
+
+static struct kobject *kobj;
+
+static struct kobj_attribute load_attribute =
+	__ATTR(load, 0200, NULL, attribute_write);
+static struct kobj_attribute loaded_attribute =
+	__ATTR(loaded, 0444, attribute_read, NULL);
+static struct kobj_attribute unload_attribute =
+	__ATTR(unload, 0200, NULL, attribute_write);
+static struct attribute *attrs[] = {
+	&load_attribute.attr,
+	&loaded_attribute.attr,
+	&unload_attribute.attr,
+	NULL
+};
+static struct attribute_group attr_group = {
+	.attrs = attrs,
+};
+
+static int __init ov_sysfs_init(void)
+{
+	int ret;
+
+	kobj = kobject_create_and_add("devicetree-overlays", firmware_kobj);
+	if (kobj == 0)
+		return -ENOMEM;
+	ret = sysfs_create_group(kobj, &attr_group);
+	if (ret) {
+		kobject_put(kobj);
+		return ret;
+	}
+
+	/*
+	 * It is not possible to ensure that no sysfs io is started while
+	 * module_exit is called. So disable unloading.
+	 */
+	__module_get(THIS_MODULE);
+
+	return 0;
+}
+
+static void __exit ov_sysfs_exit(void)
+{
+	kobject_put(kobj);
+}
+
+module_init(ov_sysfs_init);
+module_exit(ov_sysfs_exit);
+
+MODULE_AUTHOR("Heinrich Schuchardt <xypron.glpk@gmx.de>");
+MODULE_DESCRIPTION("Sysfs ABI for device tree overlays");
+MODULE_LICENSE("GPL");
-- 
2.11.0

^ permalink raw reply related

* [PATCH 1/3] of/overlay: add API function to count and pop last
From: Heinrich Schuchardt @ 2016-12-19  1:10 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, Frank Rowand
  Cc: devicetree, linux-kernel, Heinrich Schuchardt
In-Reply-To: <1482109835-9000-1-git-send-email-xypron.glpk@gmx.de>

To allow building interfaces which are not id based
two new functions are added to the device tree
overlay API:

of_overlay_count        - counts the loaded overlays
of_overlay_destroy_last - removes the last overlay loaded

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
 Documentation/devicetree/overlay-notes.txt |  7 +++--
 drivers/of/overlay.c                       | 50 ++++++++++++++++++++++++++++++
 include/linux/of.h                         | 12 +++++++
 3 files changed, 67 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/overlay-notes.txt b/Documentation/devicetree/overlay-notes.txt
index d418a6ce9812..7c8099c81e91 100644
--- a/Documentation/devicetree/overlay-notes.txt
+++ b/Documentation/devicetree/overlay-notes.txt
@@ -89,17 +89,20 @@ Overlay in-kernel API
 
 The API is quite easy to use.
 
-1. Call of_overlay_create() to create and apply an overlay. The return value
+Call of_overlay_create() to create and apply an overlay. The return value
 is a cookie identifying this overlay.
 
-2. Call of_overlay_destroy() to remove and cleanup the overlay previously
+Call of_overlay_destroy() to remove and cleanup the overlay previously
 created via the call to of_overlay_create(). Removal of an overlay that
 is stacked by another will not be permitted.
+Or call of_overlay_destroy_last() to remove the most recent overlay.
 
 Finally, if you need to remove all overlays in one-go, just call
 of_overlay_destroy_all() which will remove every single one in the correct
 order.
 
+Call of_overlay_count() to determine the number of loaded overlays.
+
 Overlay DTS Format
 ------------------
 
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index 0d4cda7050e0..bd30253b26f9 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -587,3 +587,53 @@ int of_overlay_destroy_all(void)
 	return 0;
 }
 EXPORT_SYMBOL_GPL(of_overlay_destroy_all);
+
+/**
+ * of_overlay_destroy_last() - Removes the last overlay from the system
+ *
+ * It is allways possible to delete the last overlay.
+ *
+ * Returns 0 on success, or a negative error number
+ */
+int of_overlay_destroy_last(void)
+{
+	struct of_overlay *ov, *ovn;
+	int id;
+
+	mutex_lock(&of_mutex);
+
+	list_for_each_entry_safe_reverse(ov, ovn, &ov_list, node) {
+		id = ov->id;
+		mutex_unlock(&of_mutex);
+		return of_overlay_destroy(id);
+	}
+
+	mutex_unlock(&of_mutex);
+
+	pr_info("destroy: No overlay to destroy");
+
+	return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(of_overlay_destroy_last);
+
+/**
+ * of_overlay_count - Counts number of loaded overlays
+ *
+ * Returns number of loaded overlays
+ */
+int of_overlay_count(void)
+{
+	struct of_overlay *ov, *ovn;
+	int count = 0;
+
+	mutex_lock(&of_mutex);
+
+	list_for_each_entry_safe(ov, ovn, &ov_list, node) {
+		++count;
+	}
+
+	mutex_unlock(&of_mutex);
+
+	return count;
+}
+EXPORT_SYMBOL_GPL(of_overlay_count);
diff --git a/include/linux/of.h b/include/linux/of.h
index d72f01009297..73c8826c543b 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -1281,15 +1281,22 @@ struct of_overlay_notify_data {
 #ifdef CONFIG_OF_OVERLAY
 
 /* ID based overlays; the API for external users */
+int of_overlay_count(void);
 int of_overlay_create(struct device_node *tree);
 int of_overlay_destroy(int id);
 int of_overlay_destroy_all(void);
+int of_overlay_destroy_last(void);
 
 int of_overlay_notifier_register(struct notifier_block *nb);
 int of_overlay_notifier_unregister(struct notifier_block *nb);
 
 #else
 
+static int of_overlay_count(void)
+{
+	return -ENOTSUPP;
+}
+
 static inline int of_overlay_create(struct device_node *tree)
 {
 	return -ENOTSUPP;
@@ -1305,6 +1312,11 @@ static inline int of_overlay_destroy_all(void)
 	return -ENOTSUPP;
 }
 
+static inline int of_overlay_destroy_last(void)
+{
+	return -ENOTSUPP;
+}
+
 static inline int of_overlay_notifier_register(struct notifier_block *nb)
 {
 	return 0;
-- 
2.11.0

^ permalink raw reply related

* [PATCH 0/3] of/overlay: sysfs based ABI for dt overlays
From: Heinrich Schuchardt @ 2016-12-19  1:10 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, Frank Rowand
  Cc: devicetree, linux-kernel, Heinrich Schuchardt

Currently the kernel only supplies an internal API for creating
and destroying device tree overlays.

For some boards vendor specific kernel modules exist for
managing device tree overlays but they have not been
upstreamed or upstreaming stalled.
https://lkml.org/lkml/2015/6/12/624
https://lkml.org/lkml/2013/1/7/366

This patch series provides a sysfs based ABI for creation and
destruction of dt overlays in /sys/firmware/devicetree-overlay.

The following files are provided:

load:   This is a write only file.
        A string written to it is interpreted as the path to a
        flattened device tree overlay file. It is used to create
        and apply the contained overlays.

loaded: This is a read only file.
        It provides the count of loaded overlays as a decimal
        number.

unload: This is a write only file.
        If a positive number n is wrtten to this file the n
        most recent overlays are destroyed.
        If a negative number is written to this file all
        overlays are destroyed.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>

Heinrich Schuchardt (3):
  of/overlay: add API function to count and pop last
  of/overlay: sysfs based ABI for dt overlays
  of/overlay: documentation for sysfs ABI

 .../ABI/testing/sysfs-firmware-devicetree-overlays |  24 +++
 Documentation/devicetree/overlay-notes.txt         |   7 +-
 drivers/of/Kconfig                                 |  12 ++
 drivers/of/Makefile                                |   2 +
 drivers/of/ov_sysfs.c                              | 212 +++++++++++++++++++++
 drivers/of/overlay.c                               |  50 +++++
 include/linux/of.h                                 |  12 ++
 7 files changed, 317 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-firmware-devicetree-overlays
 create mode 100644 drivers/of/ov_sysfs.c

-- 
2.11.0

^ permalink raw reply

* Re: [PATCH] rtc: pcf8563: Do not disable clk out by default
From: Alexandre Belloni @ 2016-12-19  0:25 UTC (permalink / raw)
  To: Volodymyr Bendiuga
  Cc: a.zummo-BfzFCNDTiLLj+vYz1yj4TQ, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, rtc-linux-/JYPxA39Uh5TLH3MbocFFw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	volodymyr.bendiuga-Re5JQEeQqe8AvxtiuMwx3w, Mattias Walström
In-Reply-To: <1481295829-21974-1-git-send-email-volodymyr.bendiuga-qeDNsGSBLoYwFerOooGFRg@public.gmane.org>

On 09/12/2016 at 16:03:49 +0100, Volodymyr Bendiuga wrote :
> From: Mattias Walström <mattias.walstrom-qeDNsGSBLoYwFerOooGFRg@public.gmane.org>
> 
> Commit a39a6405d5f949bc651694028a disables CLKOUT of
> the rtc after power-up to improve power consumption.
> This is very useful, but some designs do require to
> have the rtc on all the time, otherwise devices will
> be bricked. Therefore this patch is a compromise that
> works for both cases, where the default case is when
> CLKOUT is on. If one wants to disable the CLKOUT,
> clkout-allow-disable can be added to devicetree's rtc node.
> 

Actually, the commit description is misleading. The CCF is the one
disabling the clock if it is not used. If any user of the clock is
declared, it will not be disabled so it already works in both cases
(provided you have a proper driver getting the clock).

-- 
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

-- 
You received this message because you are subscribed to "rtc-linux".
Membership options at http://groups.google.com/group/rtc-linux .
Please read http://groups.google.com/group/rtc-linux/web/checklist
before submitting a driver.
--- 
You received this message because you are subscribed to the Google Groups "rtc-linux" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rtc-linux+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/d/optout.

^ permalink raw reply

* Re: [PATCH 4/4] mmc: pwrseq-simple: add disable-post-power-on option
From: Matt Ranostay @ 2016-12-19  0:01 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: Rob Herring, devicetree@vger.kernel.org,
	linux-mmc@vger.kernel.org, Tony Lindgren, Liam Breck
In-Reply-To: <CAJ_EiST_kSDn=ypnnZJJJ-wmB7Avp+MT7uK00H+aDhQGc4Yddg@mail.gmail.com>

On Wed, Dec 14, 2016 at 5:46 PM, Matt Ranostay <matt@ranostay.consulting> wrote:
> On Tue, Dec 13, 2016 at 12:01 AM, Ulf Hansson <ulf.hansson@linaro.org> wrote:
>> On 9 December 2016 at 19:09, Rob Herring <robh@kernel.org> wrote:
>>> On Fri, Dec 02, 2016 at 01:06:47AM -0800, Matt Ranostay wrote:
>>>> On Fri, Dec 2, 2016 at 12:28 AM, Ulf Hansson <ulf.hansson@linaro.org> wrote:
>>>> > On 2 December 2016 at 08:22, Matt Ranostay <matt@ranostay.consulting> wrote:
>>>> >>
>>>> >>
>>>> >>> On Dec 1, 2016, at 23:13, Ulf Hansson <ulf.hansson@linaro.org> wrote:
>>>> >>>
>>>> >>>> On 2 December 2016 at 07:17, Matt Ranostay <matt@ranostay.consulting> wrote:
>>>> >>>> Add optional device-post-power-on parameters to disable post_power_on
>>>> >>>> function from being called since this breaks some device.
>>>> >>>>
>>>> >>>> Cc: Tony Lindgren <tony@atomide.com>
>>>> >>>> Cc: Ulf Hansson <ulf.hansson@linaro.org>
>>>> >>>> Signed-off-by: Matt Ranostay <matt@ranostay.consulting>
>>>> >>>> ---
>>>> >>>> Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt | 2 ++
>>>> >>>> drivers/mmc/core/pwrseq_simple.c                            | 7 +++++++
>>>> >>>> 2 files changed, 9 insertions(+)
>>>> >>>>
>>>> >>>> diff --git a/Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt b/Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt
>>>> >>>> index bea306d772d1..09fa153f743e 100644
>>>> >>>> --- a/Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt
>>>> >>>> +++ b/Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt
>>>> >>>> @@ -24,6 +24,8 @@ Optional properties:
>>>> >>>>        de-asserting the reset-gpios (if any)
>>>> >>>> - invert-off-state: Invert the power down state for the reset-gpios (if any)
>>>> >>>>        and pwrdn-gpios (if any)
>>>> >>>> +- disable-post-power-on : Avoid post_power_on function from being called since
>>>> >>>> +       this breaks some devices
>>>> >>>
>>>> >>> This is a bit weird. I would like to avoid this, if possible.
>>>> >>>
>>>> >>> Perhaps if you simply describe the sequence in detail for your device
>>>> >>> we can figure out the best option together.
>>>> >>
>>>> >> Yeah I know it is a bit weird but we need to keep that reset pin high for at least some time after pre power on.   So any case it would be another property
>>>> >
>>>> > This went offlist, please resend.
>>>> >
>>>> > Moreover, please try to describe the sequence you need in detail
>>>> > according to your HW spec.
>>>> >
>>>>
>>>> Yeah oops....
>>>>
>>>> So basically we need to drive the reset and powerdown lines high with
>>>> a 300 milliseconds delay between both...
>>>> can't have the reset line low with post power on (pretty sure but
>>>> would need a delay anyway), and we need both reset + powerdown line
>>>> set low on powerdown.
>>>>
>>>> So the power down sequence would need to be reversed for this
>>>> application in pwrseq-simple.
>>>
>>> This sounds like you need a device specific sequence to me. Otherwise,
>>> write a language to describe any power control waveforms rather than
>>> trying to bolt on more and more properties. (Don't really go write a
>>> language.)
>>
>> Actually this isn't so device specific. The cw1200 wifi chip which is
>> being used with ux500 SoCs has a very similar sequence. Allow me to
>> check the details and get back.
>
> Ok. It would be good to have something common than a bunch of one-off
> solutions for sure.
>
>>
>> Anyway, my point is that I think we can figure out a common sequence
>> to support these kind required sequences. That is to me preferred over
>> adding a new (two to support cw1200) device specific pwrseq driver.
>>

So briefly looked at the cw1200 driver (I'm guessing the datasheet is
NDA since I couldn't find it) and it seems like it would be a good fit
to have a common pwrseq driver.

So minor things I noticed that the cw1200 device has different from
our SD8787 chipset.

* SD8787 has a "powerdown" line, and CW1200 has a "powerup" line.. I
know this is a simple logic inversion.
* CW1200 has a clock control line, that seems to be asserted between
the powerup/reset steps.

Would there need to be some per driver functions that could be
registered for edge cases like this?

>> Kind regards
>> Uffe

^ permalink raw reply

* [PATCH 1/2 v2] iio: light: add DT bindings for Capella CM3605
From: Linus Walleij @ 2016-12-18 21:55 UTC (permalink / raw)
  To: Jonathan Cameron, linux-iio-u79uwXL29TY76Z2rM5mHXA
  Cc: Linus Walleij, devicetree-u79uwXL29TY76Z2rM5mHXA,
	Capella Microsystems, Kevin Tsai

This adds device tree bindings for the Capella Microsystems CM3605
ambient light sensor and short range proximity sensor.

Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Cc: Capella Microsystems <capellamicro-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Cc: Kevin Tsai <ktsai-GubuWUlQtMwciDkP5Hr2oA@public.gmane.org>
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Signed-off-by: Linus Walleij <linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
ChangeLog v1->v2:
- Rename aset-resistance to aset-resistance-ohms
---
 .../devicetree/bindings/iio/light/cm3605.txt       | 41 ++++++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/light/cm3605.txt

diff --git a/Documentation/devicetree/bindings/iio/light/cm3605.txt b/Documentation/devicetree/bindings/iio/light/cm3605.txt
new file mode 100644
index 000000000000..56331a79f9ab
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/light/cm3605.txt
@@ -0,0 +1,41 @@
+Capella Microsystems CM3605
+Ambient Light and Short Distance Proximity Sensor
+
+The CM3605 is an entirely analog part which however require quite a bit of
+software logic to interface a host operating system.
+
+This ALS and proximity sensor was one of the very first deployed in mobile
+handsets, notably it is used in the very first Nexus One Android phone from
+2010.
+
+Required properties:
+- compatible: must be: "capella,cm3605"
+- aset-gpios: GPIO line controlling the ASET line (drive low
+  to activate the ALS, should be flagged GPIO_ACTIVE_LOW)
+- interrupts: the IRQ line (such as a GPIO) that is connected to
+  the POUT (proximity sensor out) line. The edge detection must
+  be set to IRQ_TYPE_EDGE_BOTH so as to detect movements toward
+  and away from the proximity sensor.
+- io-channels: the ADC channel used for converting the voltage from
+  AOUT to a digital representation.
+- io-channel-names: must be "aout"
+
+Optional properties:
+- vdd-supply: regulator supplying VDD power to the component.
+- capella,aset-resistance-ohms: the sensitivity calibration resistance,
+  in Ohms. Valid values are: 50000, 100000, 300000 and 600000,
+  as these are the resistance values that we are supplied with
+  calibration curves for. If not supplied, 100 kOhm will be assumed
+  but it is strongly recommended to supply this.
+
+Example:
+
+cm3605 {
+	compatible = "capella,cm3605";
+	vdd-supply = <&foo_reg>;
+	aset-gpios = <&foo_gpio 1 GPIO_ACTIVE_LOW>;
+	capella,aset-resistance-ohms = <100000>;
+	interrupts = <1 IRQ_TYPE_EDGE_BOTH>;
+	io-channels = <&adc 0x01>;
+	io-channel-names = "aout";
+};
-- 
2.7.4

^ permalink raw reply related

* Re: [PATCH v2 01/13] devicetree/bindings: display: Document common panel properties
From: Laurent Pinchart @ 2016-12-18 20:54 UTC (permalink / raw)
  To: dri-devel
  Cc: Rob Herring, open list:MEDIA DRIVERS FOR RENESAS - FCP,
	devicetree@vger.kernel.org, Tomi Valkeinen, Laurent Pinchart
In-Reply-To: <2064799.n5laApbQHL@avalon>

Hi Rob,

On Tuesday 29 Nov 2016 20:23:41 Laurent Pinchart wrote:
> On Tuesday 29 Nov 2016 09:14:09 Rob Herring wrote:
> > On Tue, Nov 29, 2016 at 2:27 AM, Laurent Pinchart wrote:
> >> On Tuesday 22 Nov 2016 11:36:55 Laurent Pinchart wrote:
> >>> On Monday 21 Nov 2016 10:48:15 Rob Herring wrote:
> >>>> On Sat, Nov 19, 2016 at 05:28:01AM +0200, Laurent Pinchart wrote:
> >>>>> Document properties common to several display panels in a central
> >>>>> location that can be referenced by the panel device tree bindings.
> >>>> 
> >>>> Looks good. Just one comment...
> >>>> 
> >>>> [...]
> >>>> 
> >>>>> +Connectivity
> >>>>> +------------
> >>>>> +
> >>>>> +- ports: Panels receive video data through one or multiple
> >>>>> connections. While
> >>>>> +  the nature of those connections is specific to the panel type, the
> >>>>> +  connectivity is expressed in a standard fashion using ports as
> >>>>> specified in
> >>>>> +  the device graph bindings defined in
> >>>>> +  Documentation/devicetree/bindings/graph.txt.
> >>>> 
> >>>> We allow panels to either use graph binding or be a child of the
> >>>> display controller.
> >>> 
> >>> I knew that some display controllers use a phandle to the panel (see
> >>> the fsl,panel and nvidia,panel properties), but I didn't know we had
> >>> panels as children of display controller nodes. I don't think we should
> >>> allow that for anything but DSI panels, as the DT hierarchy is based on
> >>> control buses. Are you sure we have other panels instantiated through
> >>> that mechanism ?
> > 
> > Some panels have no control bus, so were do we place them?
> 
> I'd say under the root node, like all similar control-less devices.
> 
> > I would say the hierarchy is based on buses with a preference for the
> > control bus when there are multiple buses. I'm not a fan of just sticking
> > things are the top level.
> 
> OK, so much for my comment a few lines up :-)
> 
> The problem with placing non-DSI panels as children of the display
> controller and not using OF graph is that the panel bindings become
> dependent of the display controller being used. A display controller using
> OF graph would require the panel to do the same, while a display controller
> expecting a panel child node (with a specific name) would require DT
> properties for the panel node.
> 
> I'm also not sure the complexity of OF graph is really that prohibitive if
> you compare it to panels as child nodes. To get the panel driver to bind to
> the panel DT node the display controller driver would need to create a
> platform device for the panel and register it. That's not very difficult,
> but parsing a single port and endpoint isn't either (and we could even
> provide a helper function for that, a version of of_drm_find_panel() that
> would take as an argument the display controller device node instead of the
> panel device node).

Ping ?

I'd like to standardize on one model for panel DT bindings, but I'm not sure 
that can be achieved given that we already have multiple competing models. In 
any case, is that blocking to merge this patch ? I only describe one 
connectivity model here as that's what my panel driver needs, but I have no 
issue adding more models later when needed. I believe this patch is a good 
step forward already.

> >> Ping ?
> >> 
> >> Please note that this file documents properties common to multiple panel
> >> DT bindings, but in no way makes it mandatory to use the OF graph
> >> bindings for panels. The decision is left to individual bindings.
> > 
> > It is mandatory in the sense that we don't want more cases of "fsl,panel".
> 
> That I agree with :-)

-- 
Regards,

Laurent Pinchart

^ permalink raw reply

* Re: [PATCH v10 3/3] fpga: Add support for Lattice iCE40 FPGAs
From: Vladimir Zapolskiy @ 2016-12-18 19:18 UTC (permalink / raw)
  To: Joel Holdsworth, atull-yzvPICuk2ABMcg4IHK0kFoH6Mc4MB0Vx,
	moritz.fischer-+aYTwkv1SeIAvxtiuMwx3w,
	robh-DgEjT+Ai2ygdnm+yROfE0A, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-spi-u79uwXL29TY76Z2rM5mHXA, marex-ynQEQJNshbs,
	linux-fpga-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1482039234-21335-3-git-send-email-joel-IJEoVVyKhCJXvIrf17iDB/XRex20P6io@public.gmane.org>

Hi Joel,

On 12/18/2016 07:33 AM, Joel Holdsworth wrote:
> This patch adds support to the FPGA manager for configuring the SRAM of
> iCE40LM, iCE40LP, iCE40HX, iCE40 Ultra, iCE40 UltraLite and iCE40
> UltraPlus devices, through slave SPI.
> 
> Signed-off-by: Joel Holdsworth <joel-IJEoVVyKhCJXvIrf17iDB/XRex20P6io@public.gmane.org>
> Reviewed-by: Marek Vasut <marex-ynQEQJNshbs@public.gmane.org>
> Reviewed-by: Moritz Fischer <moritz.fischer-+aYTwkv1SeIAvxtiuMwx3w@public.gmane.org>
> Acked-by: Alan Tull <atull-yzvPICuk2ABMcg4IHK0kFoH6Mc4MB0Vx@public.gmane.org>
> ---

[snip]

> +
> +static int ice40_fpga_probe(struct spi_device *spi)
> +{
> +	struct device *dev = &spi->dev;
> +	struct device_node *np = spi->dev.of_node;

struct device_node *np = dev->of_node?

And actually I don't see why local variable 'np' is needed in the function,
see the next comment.

> +	struct ice40_fpga_priv *priv;
> +	int ret;
> +
> +	if (!np) {
> +		dev_err(dev, "No Device Tree entry\n");
> +		return -EINVAL;
> +	}

I would suggest to remove this check completely, I don't see a good
reason why it is needed.

> +
> +	priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->dev = spi;
> +
> +	/* Check board setup data. */
> +	if (spi->max_speed_hz > ICE40_SPI_MAX_SPEED) {
> +		dev_err(dev, "SPI speed is too high, maximum speed is "
> +			__stringify(ICE40_SPI_MAX_SPEED) "\n");
> +		return -EINVAL;
> +	}
> +
> +	if (spi->max_speed_hz < ICE40_SPI_MIN_SPEED) {
> +		dev_err(dev, "SPI speed is too low, minimum speed is "
> +			__stringify(ICE40_SPI_MIN_SPEED) "\n");
> +		return -EINVAL;
> +	}
> +
> +	if (spi->mode & SPI_CPHA) {
> +		dev_err(dev, "Bad SPI mode, CPHA not supported\n");
> +		return -EINVAL;
> +	}
> +
> +	/* Set up the GPIOs */
> +	priv->cdone = devm_gpiod_get(dev, "cdone", GPIOD_IN);
> +	if (IS_ERR(priv->cdone)) {
> +		dev_err(dev, "Failed to get CDONE GPIO: %ld\n",
> +			PTR_ERR(priv->cdone));
> +		return -EINVAL;

You should do 'return PTR_ERR(priv->cdone)' here, this will allow
to handle at lease -EPROBE_DEFER correctly.

> +	}
> +
> +	priv->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
> +	if (IS_ERR(priv->reset)) {
> +		dev_err(dev, "Failed to get CRESET_B GPIO: %ld\n",
> +			PTR_ERR(priv->reset));
> +		return -EINVAL;

Same as above.

> +	}
> +
> +	/* Register with the FPGA manager */
> +	ret = fpga_mgr_register(dev, "Lattice iCE40 FPGA Manager",
> +				&ice40_fpga_ops, priv);
> +	if (ret) {
> +		dev_err(dev, "Unable to register FPGA manager");
> +		return ret;

I would suggest to do just 'return fpga_mgr_register(dev, ....);' here,
if the driver is not registered, the core will let the user know about it.

> +	}
> +
> +	return 0;
> +}
> +

--
With best wishes,
Vladimir
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH net-next v4 2/2] net: stmmac: dwmac-meson8b: make the RGMII TX delay configurable
From: Martin Blumenstingl @ 2016-12-18 16:13 UTC (permalink / raw)
  To: David Miller
  Cc: netdev, devicetree, linux-amlogic, robh+dt, mark.rutland, carlo,
	khilman, peppe.cavallaro, alexandre.torgue, linux-arm-kernel
In-Reply-To: <20161218.104950.1013829528388480468.davem@davemloft.net>

On Sun, Dec 18, 2016 at 4:49 PM, David Miller <davem@davemloft.net> wrote:
> From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
> Date: Sat, 17 Dec 2016 19:21:19 +0100
>
>> Prior to this patch we were using a hardcoded RGMII TX clock delay of
>> 2ns (= 1/4 cycle of the 125MHz RGMII TX clock). This value works for
>> many boards, but unfortunately not for all (due to the way the actual
>> circuit is designed, sometimes because the TX delay is enabled in the
>> PHY, etc.). Making the TX delay on the MAC side configurable allows us
>> to support all possible hardware combinations.
>>
>> This allows fixing a compatibility issue on some boards, where the
>> RTL8211F PHY is configured to generate the TX delay. We can now turn
>> off the TX delay in the MAC, because otherwise we would be applying the
>> delay twice (which results in non-working TX traffic).
>>
>> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
>> Tested-by: Neil Armstrong <narmstrong@baylibre.com>
>
> Is this really the safest thing to do?
>
> If you say the existing hard-coded setting of 1/4 cycle works on most
> boards, and what you're trying to do is override it with an OF
> property value for boards where the existing setting does not work,
> then you _must_ use a default value that corresponds to what the
> existing code does not when you don't see this new OF property.
it's a bit more complicated in reality: 1/4 cycle works when the TX
delay of the RTL8211F PHY is turned off (until recently it was always
enabled for phy-mode RGMII).

> So please retain the current behavior of the 1/4 cycle TX delay
> setting when you don't see the amlogic,tx-delay-ns property.
>
> I really think you risk breaking existing boards by not doing so,
> unless you can have this patch tested on every such board that exists
> and I don't think you really can feasibly and rigorously do that.
there's a patch in my follow-up series which adds the 2ns to the .dts
for all RGMII based boards: [0] (and I would keep these even if we had
a default value, just to make it explicit and thus easier to
understand for other people).
however, we can add the 2ns default back (I can do this if you want -
Rob Herring was unhappy with the missing documentation of this default
value [1] - so note to myself: take care of that as well). but then we
have to decide when to apply this default value: only when we're in
RGMII mode or also in any of the RGMII_*ID modes?

please let me know how we should proceed


Regards,
Martin


[0] http://lists.infradead.org/pipermail/linux-amlogic/2016-December/001838.html
[1] http://lists.infradead.org/pipermail/linux-amlogic/2016-November/001817.html

^ permalink raw reply

* Re: [PATCH net-next v4 2/2] net: stmmac: dwmac-meson8b: make the RGMII TX delay configurable
From: David Miller @ 2016-12-18 15:49 UTC (permalink / raw)
  To: martin.blumenstingl
  Cc: netdev, devicetree, linux-amlogic, robh+dt, mark.rutland, carlo,
	khilman, peppe.cavallaro, alexandre.torgue, linux-arm-kernel
In-Reply-To: <20161217182119.4037-3-martin.blumenstingl@googlemail.com>

From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Sat, 17 Dec 2016 19:21:19 +0100

> Prior to this patch we were using a hardcoded RGMII TX clock delay of
> 2ns (= 1/4 cycle of the 125MHz RGMII TX clock). This value works for
> many boards, but unfortunately not for all (due to the way the actual
> circuit is designed, sometimes because the TX delay is enabled in the
> PHY, etc.). Making the TX delay on the MAC side configurable allows us
> to support all possible hardware combinations.
> 
> This allows fixing a compatibility issue on some boards, where the
> RTL8211F PHY is configured to generate the TX delay. We can now turn
> off the TX delay in the MAC, because otherwise we would be applying the
> delay twice (which results in non-working TX traffic).
> 
> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
> Tested-by: Neil Armstrong <narmstrong@baylibre.com>

Is this really the safest thing to do?

If you say the existing hard-coded setting of 1/4 cycle works on most
boards, and what you're trying to do is override it with an OF
property value for boards where the existing setting does not work,
then you _must_ use a default value that corresponds to what the
existing code does not when you don't see this new OF property.

So please retain the current behavior of the 1/4 cycle TX delay
setting when you don't see the amlogic,tx-delay-ns property.

I really think you risk breaking existing boards by not doing so,
unless you can have this patch tested on every such board that exists
and I don't think you really can feasibly and rigorously do that.

Thanks.

^ permalink raw reply

* Re: [PATCH net-next v3 0/4] Fix OdroidC2 Gigabit Tx link issue
From: Martin Blumenstingl @ 2016-12-18 13:37 UTC (permalink / raw)
  To: Florian Fainelli, jbrunet
  Cc: David Miller, netdev, devicetree, carlo, khilman, peppe.cavallaro,
	alexandre.torgue, neolynx, andrew, narmstrong, linux-amlogic,
	linux-arm-kernel, linux-kernel
In-Reply-To: <162595c2-d403-0070-3399-de03c1653065@gmail.com>

Hi Florian, Hi Jerome,

On Wed, Nov 30, 2016 at 2:15 AM, Florian Fainelli <f.fainelli@gmail.com> wrote:
> On 11/29/2016 05:13 PM, David Miller wrote:
>> From: Florian Fainelli <f.fainelli@gmail.com>
>> Date: Tue, 29 Nov 2016 16:43:20 -0800
>>
>>> On 11/29/2016 04:38 PM, David Miller wrote:
>>>> From: Jerome Brunet <jbrunet@baylibre.com>
>>>> Date: Mon, 28 Nov 2016 10:46:45 +0100
>>>>
>>>>> This patchset fixes an issue with the OdroidC2 board (DWMAC + RTL8211F).
>>>>> The platform seems to enter LPI on the Rx path too often while performing
>>>>> relatively high TX transfer. This eventually break the link (both Tx and
>>>>> Rx), and require to bring the interface down and up again to get the Rx
>>>>> path working again.
>>>>>
>>>>> The root cause of this issue is not fully understood yet but disabling EEE
>>>>> advertisement on the PHY prevent this feature to be negotiated.
>>>>> With this change, the link is stable and reliable, with the expected
>>>>> throughput performance.
>>>>>
>>>>> The patchset adds options in the generic phy driver to disable EEE
>>>>> advertisement, through device tree. The way it is done is very similar
>>>>> to the handling of the max-speed property.
>>>>
>>>> Patches 1-3 applied to net-next, thanks.
>>>
>>> Meh, there was a v4 submitted shortly after, and I objected to the whole
>>> idea of using that kind of Device Tree properties to disable EEE, we can
>>> send reverts though..
>>
>> Sorry, I lost this in all the discussion, I can revert.
>
> Yeah, I can understand why, these freaking PHYs tend to generate a lot
> of noise and discussion...
>
>>
>> Just send me a revert of the entire merge commit
>> a152c91889556df17ca6d8ea134fb2cb4ac9f893 with a short
>> description of why and I'll apply it.
>
> OK, I will talk with Jerome first to make sure that we are in agreement
> with the solution to deploy to fix the OdroidC2 problem first.
simply because I'm curious: what was the outcome of your discussion?
can we stay with the current solution or are any changes required?


Regards,
Martin

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox