Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3] arm64: mm: Fix NOMAP page initialization
From: Hanjun Guo @ 2017-01-05  2:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAKv+Gu_SmTNguC=tSCwYOL2kx-DogLvSYRZc56eGP=JhdrUOsA@mail.gmail.com>

On 2017/1/4 21:56, Ard Biesheuvel wrote:
> On 16 December 2016 at 16:54, Robert Richter <rrichter@cavium.com> wrote:
>> On ThunderX systems with certain memory configurations we see the
>> following BUG_ON():
>>
>>  kernel BUG at mm/page_alloc.c:1848!
>>
>> This happens for some configs with 64k page size enabled. The BUG_ON()
>> checks if start and end page of a memmap range belongs to the same
>> zone.
>>
>> The BUG_ON() check fails if a memory zone contains NOMAP regions. In
>> this case the node information of those pages is not initialized. This
>> causes an inconsistency of the page links with wrong zone and node
>> information for that pages. NOMAP pages from node 1 still point to the
>> mem zone from node 0 and have the wrong nid assigned.
>>
>> The reason for the mis-configuration is a change in pfn_valid() which
>> reports pages marked NOMAP as invalid:
>>
>>  68709f45385a arm64: only consider memblocks with NOMAP cleared for linear mapping
>>
>> This causes pages marked as nomap being no longer reassigned to the
>> new zone in memmap_init_zone() by calling __init_single_pfn().
>>
>> Fixing this by implementing an arm64 specific early_pfn_valid(). This
>> causes all pages of sections with memory including NOMAP ranges to be
>> initialized by __init_single_page() and ensures consistency of page
>> links to zone, node and section.
>>
>
> I like this solution a lot better than the first one, but I am still
> somewhat uneasy about having the kernel reason about attributes of
> pages it should not touch in the first place. But the fact that
> early_pfn_valid() is only used a single time in the whole kernel does
> give some confidence that we are not simply moving the problem
> elsewhere.
>
> Given that you are touching arch/arm/ as well as arch/arm64, could you
> explain why only arm64 needs this treatment? Is it simply because we
> don't have NUMA support there?
>
> Considering that Hisilicon D05 suffered from the same issue, I would
> like to get some coverage there as well. Hanjun, is this something you
> can arrange? Thanks

Sure, we will test this patch with LTP MM stress test (which triggers
the bug on D05), and give the feedback.

Thanks
Hanjun

^ permalink raw reply

* [PATCH v2 0/4] linux/const.h: cleanups of macros such as UL(), _BITUL(), BIT() etc.
From: Masahiro Yamada @ 2017-01-05  2:20 UTC (permalink / raw)
  To: linux-arm-kernel


ARM, ARM64, UniCore32 define UL() as a shorthand of _AC(..., UL).
In the future, more architectures may introduce it, so move
the definition to include/linux/const.h.

The _AC() is used for either (likely) UL or (unlikely) ULL.
Having UL(L) in a common place can avoid direct use of _AC().

The _AC() is defined under the uapi directory, so it compels
underscore-prefixed macros even for unexported headers.

I see similar situation for _BITUL().  This is available in
both C and assembly.  However, it is defined in an uapi header,
so direct use of the underscore macro is needed even for unexported
headers.  The 3/3 makes BIT() available in assembly too, which will
be more suitable for use in unexported headers.


Changes in v2:
  - Split out as a prerequisite patch

Masahiro Yamada (4):
  m68k: rename UL() to TO_UL()
  linux/const.h: move UL() macro to include/linux/const.h
  linux/const.h: refactor _BITUL and _BITULL a bit
  linux/const.h: move BIT(_ULL) to linux/const.h for use in assembly

 arch/arm/include/asm/memory.h       |  6 ------
 arch/arm64/include/asm/memory.h     |  6 ------
 arch/m68k/mm/init.c                 |  6 +++---
 arch/unicore32/include/asm/memory.h |  6 ------
 include/linux/bitops.h              |  3 +--
 include/linux/const.h               | 12 ++++++++++++
 include/uapi/linux/const.h          | 13 ++++++++-----
 7 files changed, 24 insertions(+), 28 deletions(-)
 create mode 100644 include/linux/const.h

-- 
2.7.4

^ permalink raw reply

* [PATCH v2 1/4] m68k: rename UL() to TO_UL()
From: Masahiro Yamada @ 2017-01-05  2:20 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1483582810-7046-1-git-send-email-yamada.masahiro@socionext.com>

ARM, ARM64 and UniCore32 define UL(x) like follows:

  #define UL(x) _AC(x, UL)

While, M68K defines it differently:
  #define UL(x) ((unsigned long) (x))

I am moving the former to a common header in the next commit.
Beforehand, this commit renames the latter to avoid name conflict.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>
---

Changes in v2:
  - Split out as a prerequisite patch

 arch/m68k/mm/init.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c
index 9c1e656..a625144 100644
--- a/arch/m68k/mm/init.c
+++ b/arch/m68k/mm/init.c
@@ -121,9 +121,9 @@ void free_initmem(void)
 
 void __init print_memmap(void)
 {
-#define UL(x) ((unsigned long) (x))
-#define MLK(b, t) UL(b), UL(t), (UL(t) - UL(b)) >> 10
-#define MLM(b, t) UL(b), UL(t), (UL(t) - UL(b)) >> 20
+#define TO_UL(x) ((unsigned long) (x))
+#define MLK(b, t) TO_UL(b), TO_UL(t), (TO_UL(t) - TO_UL(b)) >> 10
+#define MLM(b, t) TO_UL(b), TO_UL(t), (TO_UL(t) - TO_UL(b)) >> 20
 #define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), 1024)
 
 	pr_notice("Virtual kernel memory layout:\n"
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 2/4] linux/const.h: move UL() macro to include/linux/const.h
From: Masahiro Yamada @ 2017-01-05  2:20 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1483582810-7046-1-git-send-email-yamada.masahiro@socionext.com>

ARM, ARM64 and UniCore32 duplicate the definition of UL():

  #define UL(x) _AC(x, UL)

This is not actually arch-specific, so it will be useful to move it
to a common header.  Currently, we only have the uapi variant for
linux/const.h, so I am creating include/linux/const.h.

I am also adding _UL(), _ULL() and ULL() because _AC() is mostly
used in the form either _AC(..., UL) or _AC(..., ULL).  I expect
they will be replaced in later cleanups.  The underscore-prefixed
ones should be used for exported headers.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Acked-by: Guan Xuetao <gxt@mprc.pku.edu.cn>
---

Changes in v2: None

 arch/arm/include/asm/memory.h       | 6 ------
 arch/arm64/include/asm/memory.h     | 6 ------
 arch/unicore32/include/asm/memory.h | 6 ------
 include/linux/const.h               | 9 +++++++++
 include/uapi/linux/const.h          | 9 ++++++---
 5 files changed, 15 insertions(+), 21 deletions(-)
 create mode 100644 include/linux/const.h

diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index 76cbd9c..7558247 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -22,12 +22,6 @@
 #include <mach/memory.h>
 #endif
 
-/*
- * Allow for constants defined here to be used from assembly code
- * by prepending the UL suffix only with actual C code compilation.
- */
-#define UL(x) _AC(x, UL)
-
 /* PAGE_OFFSET - the virtual address of the start of the kernel image */
 #define PAGE_OFFSET		UL(CONFIG_PAGE_OFFSET)
 
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index bfe6328..4310bcc 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -28,12 +28,6 @@
 #include <asm/sizes.h>
 
 /*
- * Allow for constants defined here to be used from assembly code
- * by prepending the UL suffix only with actual C code compilation.
- */
-#define UL(x) _AC(x, UL)
-
-/*
  * Size of the PCI I/O space. This must remain a power of two so that
  * IO_SPACE_LIMIT acts as a mask for the low bits of I/O addresses.
  */
diff --git a/arch/unicore32/include/asm/memory.h b/arch/unicore32/include/asm/memory.h
index 3bb0a29..66bb9f6 100644
--- a/arch/unicore32/include/asm/memory.h
+++ b/arch/unicore32/include/asm/memory.h
@@ -20,12 +20,6 @@
 #include <mach/memory.h>
 
 /*
- * Allow for constants defined here to be used from assembly code
- * by prepending the UL suffix only with actual C code compilation.
- */
-#define UL(x) _AC(x, UL)
-
-/*
  * PAGE_OFFSET - the virtual address of the start of the kernel image
  * TASK_SIZE - the maximum size of a user space task.
  * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area
diff --git a/include/linux/const.h b/include/linux/const.h
new file mode 100644
index 0000000..7b55a55
--- /dev/null
+++ b/include/linux/const.h
@@ -0,0 +1,9 @@
+#ifndef _LINUX_CONST_H
+#define _LINUX_CONST_H
+
+#include <uapi/linux/const.h>
+
+#define UL(x)		(_UL(x))
+#define ULL(x)		(_ULL(x))
+
+#endif /* _LINUX_CONST_H */
diff --git a/include/uapi/linux/const.h b/include/uapi/linux/const.h
index c872bfd..76fb0f9 100644
--- a/include/uapi/linux/const.h
+++ b/include/uapi/linux/const.h
@@ -1,7 +1,7 @@
 /* const.h: Macros for dealing with constants.  */
 
-#ifndef _LINUX_CONST_H
-#define _LINUX_CONST_H
+#ifndef _UAPI_LINUX_CONST_H
+#define _UAPI_LINUX_CONST_H
 
 /* Some constant macros are used in both assembler and
  * C code.  Therefore we cannot annotate them always with
@@ -21,7 +21,10 @@
 #define _AT(T,X)	((T)(X))
 #endif
 
+#define _UL(x)		(_AC(x, UL))
+#define _ULL(x)		(_AC(x, ULL))
+
 #define _BITUL(x)	(_AC(1,UL) << (x))
 #define _BITULL(x)	(_AC(1,ULL) << (x))
 
-#endif /* !(_LINUX_CONST_H) */
+#endif /* _UAPI_LINUX_CONST_H */
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 3/4] linux/const.h: refactor _BITUL and _BITULL a bit
From: Masahiro Yamada @ 2017-01-05  2:20 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1483582810-7046-1-git-send-email-yamada.masahiro@socionext.com>

Minor cleanups available by _UL and _ULL.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---

Changes in v2: None

 include/uapi/linux/const.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/include/uapi/linux/const.h b/include/uapi/linux/const.h
index 76fb0f9..13e5165 100644
--- a/include/uapi/linux/const.h
+++ b/include/uapi/linux/const.h
@@ -24,7 +24,7 @@
 #define _UL(x)		(_AC(x, UL))
 #define _ULL(x)		(_AC(x, ULL))
 
-#define _BITUL(x)	(_AC(1,UL) << (x))
-#define _BITULL(x)	(_AC(1,ULL) << (x))
+#define _BITUL(x)	(_UL(1) << (x))
+#define _BITULL(x)	(_ULL(1) << (x))
 
 #endif /* _UAPI_LINUX_CONST_H */
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 4/4] linux/const.h: move BIT(_ULL) to linux/const.h for use in assembly
From: Masahiro Yamada @ 2017-01-05  2:20 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1483582810-7046-1-git-send-email-yamada.masahiro@socionext.com>

Commit 2fc016c5bd8a ("linux/const.h: Add _BITUL() and _BITULL()")
introduced _BITUL() and _BITULL().  Its git-log says the difference
from the already existing BIT() are:

  1. The namespace is such that they can be used in uapi definitions.
  2. The type is set with the _AC() macro to allow it to be used in
     assembly.
  3. The type is explicitly specified to be UL or ULL.

However, I found _BITUL() is often used for "2. use in assembly",
while "1. use in uapi" is unneeded.  If we address only "2.", we can
improve the existing BIT() for that.  It will allow us to replace
many _BITUL() instances with BIT(), i.e. avoid needless use of
underscore-prefixed macros, in the end, for better de-couple of
userspace/kernel headers.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---

Changes in v2: None

 include/linux/bitops.h | 3 +--
 include/linux/const.h  | 3 +++
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/include/linux/bitops.h b/include/linux/bitops.h
index a83c822..5f45fa5 100644
--- a/include/linux/bitops.h
+++ b/include/linux/bitops.h
@@ -1,10 +1,9 @@
 #ifndef _LINUX_BITOPS_H
 #define _LINUX_BITOPS_H
+#include <linux/const.h>
 #include <asm/types.h>
 
 #ifdef	__KERNEL__
-#define BIT(nr)			(1UL << (nr))
-#define BIT_ULL(nr)		(1ULL << (nr))
 #define BIT_MASK(nr)		(1UL << ((nr) % BITS_PER_LONG))
 #define BIT_WORD(nr)		((nr) / BITS_PER_LONG)
 #define BIT_ULL_MASK(nr)	(1ULL << ((nr) % BITS_PER_LONG_LONG))
diff --git a/include/linux/const.h b/include/linux/const.h
index 7b55a55..200892d 100644
--- a/include/linux/const.h
+++ b/include/linux/const.h
@@ -6,4 +6,7 @@
 #define UL(x)		(_UL(x))
 #define ULL(x)		(_ULL(x))
 
+#define BIT(x)		(_BITUL(x))
+#define BIT_ULL(x)	(_BITULL(x))
+
 #endif /* _LINUX_CONST_H */
-- 
2.7.4

^ permalink raw reply related

* [PATCH 1/3] linux/const.h: move UL() macro to include/linux/const.h
From: Masahiro Yamada @ 2017-01-05  2:22 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAMuHMdVyzF4xFPotburrP+cihjfyCDfHeAt4bienLG9kdG_zSg@mail.gmail.com>

Hi Geert,

2017-01-04 18:27 GMT+09:00 Geert Uytterhoeven <geert@linux-m68k.org>:
> Hi Yamada-san,
>
> On Wed, Jan 4, 2017 at 9:55 AM, Masahiro Yamada
> <yamada.masahiro@socionext.com> wrote:
>> Some architectures are duplicating the definition of UL():
>>
>>   #define UL(x) _AC(x, UL)
>>
>> This is not actually arch-specific, so it will be useful to move it
>> to a common header.  Currently, we only have the uapi variant for
>> linux/const.h, so I am creating include/linux/const.h.
>>
>> I am also adding _UL(x), _ULL(x), ULL(x) because _AC() is used for
>> UL in most places (and ULL in some places).  I expect _AC(..., UL)
>> will be replaced with _UL(...) or UL(...).  The underscore-prefixed
>> one should be used for exported headers.
>>
>> Note:
>> I renamed UL(x) in arch/m68k/mm/init.c, where it is used for a
>> different meaning.
>
> Shouldn't that be a separate (prerequisite) patch?


Yes, I did so in v2.

Thanks!



-- 
Best Regards
Masahiro Yamada

^ permalink raw reply

* [PATCH 1/2] mfd: micon: Add Buffalo Kurobox Pro, Terastation II Pro/Live driver
From: Florian Fainelli @ 2017-01-05  2:26 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170104112227.GA27589@dell>

Le 01/04/17 ? 03:22, Lee Jones a ?crit :
> On Wed, 28 Dec 2016, Florian Fainelli wrote:
> 
>> This driver is currently only used to reboot the devices, but the
>> microcontroller hanging off UART1 on the Buffalo Kurobox Pro and
>> Terastation II Pro/Live is capable of a lot more than that, which we
>> will support in subsequent patches. For now, just add the reboot
>> functionality to make the kernel reboot correctly.
> 
> This is not an MFD driver.  You have written a UART driver.
> 
> Please relocate it to drivers/char/tty/serial.

Not that simple, and as explained in the cover letter the UART attached
micro controller can do a lot more than just reboot the machine, but
someone else is working on the driver, so this patch series can be ignored.
-- 
Florian

^ permalink raw reply

* [RESEND 2/2] arm64: dts: Add dts files for Hisilicon Hi3660 SoC
From: Chen Feng @ 2017-01-05  3:28 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1482744972-56622-2-git-send-email-puck.chen@hisilicon.com>

Hi will&catalin,

Could you help review this part?

On 2016/12/26 17:36, Chen Feng wrote:
> Add initial dtsi file to support Hisilicon Hi3660 SoC with
> support of Octal core CPUs in two clusters(4 * A53 & 4 * A73).
> 
> Also add dts file to support HiKey960 development board which
> based on Hi3660 SoC.
> The output console is earlycon "earlycon=pl011,0xfdf05000".
> And the con_init uart5 with a fixed clock, which already
> configured at bootloader.
> 
> When clock is available, the uart5 will be modified.
> 
> Tested on HiKey960 Board.
> 
> Signed-off-by: Chen Feng <puck.chen@hisilicon.com>
> ---
>  arch/arm64/boot/dts/hisilicon/Makefile            |   1 +
>  arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dts |  34 +++++
>  arch/arm64/boot/dts/hisilicon/hi3660.dtsi         | 156 ++++++++++++++++++++++
>  3 files changed, 191 insertions(+)
>  create mode 100644 arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dts
>  create mode 100644 arch/arm64/boot/dts/hisilicon/hi3660.dtsi
> 
> diff --git a/arch/arm64/boot/dts/hisilicon/Makefile b/arch/arm64/boot/dts/hisilicon/Makefile
> index d5f43a0..b633b5d 100644
> --- a/arch/arm64/boot/dts/hisilicon/Makefile
> +++ b/arch/arm64/boot/dts/hisilicon/Makefile
> @@ -1,4 +1,5 @@
>  dtb-$(CONFIG_ARCH_HISI) += hi6220-hikey.dtb
> +dtb-$(CONFIG_ARCH_HISI) += hi3660-hikey960.dtb
>  dtb-$(CONFIG_ARCH_HISI) += hip05-d02.dtb
>  dtb-$(CONFIG_ARCH_HISI) += hip06-d03.dtb
>  
> diff --git a/arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dts b/arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dts
> new file mode 100644
> index 0000000..3d7aead
> --- /dev/null
> +++ b/arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dts
> @@ -0,0 +1,34 @@
> +/*
> + * dts file for Hisilicon HiKey960 Development Board
> + *
> + * Copyright (C) 2016, Hisilicon Ltd.
> + *
> + */
> +
> +/dts-v1/;
> +
> +#include "hi3660.dtsi"
> +
> +/ {
> +	model = "HiKey960";
> +	compatible = "hisilicon,hi3660";
> +
> +	aliases {
> +		serial5 = &uart5;       /* console UART */
> +	};
> +
> +	chosen {
> +		stdout-path = "serial5:115200n8";
> +	};
> +
> +	memory at 0 {
> +		device_type = "memory";
> +		reg = <0x0 0x00400000 0x0 0xBFE00000>;
> +	};
> +
> +	soc {
> +		uart5: uart at fdf05000 {
> +			status = "ok";
> +		};
> +	};
> +};
> diff --git a/arch/arm64/boot/dts/hisilicon/hi3660.dtsi b/arch/arm64/boot/dts/hisilicon/hi3660.dtsi
> new file mode 100644
> index 0000000..7f9805c
> --- /dev/null
> +++ b/arch/arm64/boot/dts/hisilicon/hi3660.dtsi
> @@ -0,0 +1,156 @@
> +/*
> + * dts file for Hisilicon Hi3660 SoC
> + *
> + * Copyright (C) 2016, Hisilicon Ltd.
> + */
> +
> +#include <dt-bindings/interrupt-controller/arm-gic.h>
> +
> +/ {
> +	compatible = "hisilicon,hi3660";
> +	interrupt-parent = <&gic>;
> +	#address-cells = <2>;
> +	#size-cells = <2>;
> +
> +	psci {
> +		compatible = "arm,psci-0.2";
> +		method = "smc";
> +	};
> +
> +	cpus {
> +		#address-cells = <2>;
> +		#size-cells = <0>;
> +
> +		cpu-map {
> +			cluster0 {
> +				core0 {
> +					cpu = <&cpu0>;
> +				};
> +				core1 {
> +					cpu = <&cpu1>;
> +				};
> +				core2 {
> +					cpu = <&cpu2>;
> +				};
> +				core3 {
> +					cpu = <&cpu3>;
> +				};
> +			};
> +			cluster1 {
> +				core0 {
> +					cpu = <&cpu4>;
> +				};
> +				core1 {
> +					cpu = <&cpu5>;
> +				};
> +				core2 {
> +					cpu = <&cpu6>;
> +				};
> +				core3 {
> +					cpu = <&cpu7>;
> +				};
> +			};
> +		};
> +
> +		cpu0: cpu at 0 {
> +			compatible = "arm,armv8";
> +			device_type = "cpu";
> +			reg = <0x0 0x0>;
> +			enable-method = "psci";
> +		};
> +
> +		cpu1: cpu at 1 {
> +			compatible = "arm,armv8";
> +			device_type = "cpu";
> +			reg = <0x0 0x1>;
> +			enable-method = "psci";
> +		};
> +
> +		cpu2: cpu at 2 {
> +			compatible = "arm,armv8";
> +			device_type = "cpu";
> +			reg = <0x0 0x2>;
> +			enable-method = "psci";
> +		};
> +
> +		cpu3: cpu at 3 {
> +			compatible = "arm,armv8";
> +			device_type = "cpu";
> +			reg = <0x0 0x3>;
> +			enable-method = "psci";
> +		};
> +
> +		cpu4: cpu at 100 {
> +			compatible = "arm,armv8";
> +			device_type = "cpu";
> +			reg = <0x0 0x100>;
> +			enable-method = "psci";
> +		};
> +
> +		cpu5: cpu at 101 {
> +			compatible = "arm,armv8";
> +			device_type = "cpu";
> +			reg = <0x0 0x101>;
> +			enable-method = "psci";
> +		};
> +
> +		cpu6: cpu at 102 {
> +			compatible = "arm,armv8";
> +			device_type = "cpu";
> +			reg = <0x0 0x102>;
> +			enable-method = "psci";
> +		};
> +
> +		cpu7: cpu at 103 {
> +			compatible = "arm,armv8";
> +			device_type = "cpu";
> +			reg = <0x0 0x103>;
> +			enable-method = "psci";
> +		};
> +	};
> +
> +	gic: interrupt-controller at e82b0000 {
> +		compatible = "arm,gic-400";
> +		reg = <0x0 0xe82b1000 0 0x1000>, /* GICD */
> +		      <0x0 0xe82b2000 0 0x2000>, /* GICC */
> +		      <0x0 0xe82b4000 0 0x2000>, /* GICH */
> +		      <0x0 0xe82b6000 0 0x2000>; /* GICV */
> +		#address-cells = <0>;
> +		#interrupt-cells = <3>;
> +		interrupt-controller;
> +		interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_HIGH)>;
> +	};
> +
> +	timer {
> +		compatible = "arm,armv8-timer";
> +		interrupt-parent = <&gic>;
> +		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
> +			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
> +			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
> +			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>;
> +		clock-frequency = <1920000>;
> +	};
> +
> +	soc {
> +		compatible = "simple-bus";
> +		#address-cells = <2>;
> +		#size-cells = <2>;
> +		ranges;
> +
> +		fixed_uart5: fixed_19_2M {
> +			compatible = "fixed-clock";
> +			#clock-cells = <0>;
> +			clock-frequency = <19200000>;
> +			clock-output-names = "fixed:uart5";
> +		};
> +
> +		uart5: uart at fdf05000 {
> +			compatible = "arm,pl011", "arm,primecell";
> +			reg = <0x0 0xfdf05000 0x0 0x1000>;
> +			interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
> +			clocks = <&fixed_uart5 &fixed_uart5>;
> +			clock-names = "uartclk", "apb_pclk";
> +			status = "ok";
> +		};
> +	};
> +};
> 

^ permalink raw reply

* [PATCHv2 0/5] Support for Marvell switches with integrated CPUs
From: Chris Packham @ 2017-01-05  3:36 UTC (permalink / raw)
  To: linux-arm-kernel

The 98DX3236, 98DX3336 and 98DX4251 are a set of switch ASICs with
integrated CPUs. They CPU block is common within these product lines and
(as far as I can tell/have been told) is based on the Armada XP. There
are a few differences due to the fact they have to squeeze the CPU into
the same package as the switch.

Chris Packham (4):
  clk: mvebu: support for 98DX3236 SoC
  arm: mvebu: support for SMP on 98DX3336 SoC
  arm: mvebu: Add device tree for 98DX3236 SoCs
  arm: mvebu: Add device tree for db-dxbc2 and db-xc3-24g4xg boards

Kalyan Kinthada (1):
  pinctrl: mvebu: pinctrl driver for 98DX3236 SoC

 Documentation/devicetree/bindings/arm/cpus.txt     |   1 +
 .../bindings/arm/marvell/98dx3236-resume-ctrl.txt  |  18 ++
 .../devicetree/bindings/arm/marvell/98dx3236.txt   |  23 ++
 .../devicetree/bindings/clock/mvebu-cpu-clock.txt  |   1 +
 .../pinctrl/marvell,armada-98dx3236-pinctrl.txt    |  46 ++++
 arch/arm/boot/dts/armada-xp-98dx3236.dtsi          | 247 +++++++++++++++++++++
 arch/arm/boot/dts/armada-xp-98dx3336.dtsi          |  78 +++++++
 arch/arm/boot/dts/armada-xp-98dx4251.dtsi          |  92 ++++++++
 arch/arm/boot/dts/db-dxbc2.dts                     | 159 +++++++++++++
 arch/arm/boot/dts/db-xc3-24g4xg.dts                | 155 +++++++++++++
 arch/arm/mach-mvebu/Makefile                       |   1 +
 arch/arm/mach-mvebu/common.h                       |   1 +
 arch/arm/mach-mvebu/platsmp.c                      |  43 ++++
 arch/arm/mach-mvebu/pmsu-98dx3236.c                |  69 ++++++
 drivers/clk/mvebu/Makefile                         |   2 +-
 drivers/clk/mvebu/armada-xp.c                      |  42 ++++
 drivers/clk/mvebu/clk-cpu.c                        |  33 ++-
 drivers/clk/mvebu/mv98dx3236-corediv.c             | 207 +++++++++++++++++
 drivers/pinctrl/mvebu/pinctrl-armada-xp.c          | 155 +++++++++++++
 19 files changed, 1369 insertions(+), 4 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/marvell/98dx3236-resume-ctrl.txt
 create mode 100644 Documentation/devicetree/bindings/arm/marvell/98dx3236.txt
 create mode 100644 Documentation/devicetree/bindings/pinctrl/marvell,armada-98dx3236-pinctrl.txt
 create mode 100644 arch/arm/boot/dts/armada-xp-98dx3236.dtsi
 create mode 100644 arch/arm/boot/dts/armada-xp-98dx3336.dtsi
 create mode 100644 arch/arm/boot/dts/armada-xp-98dx4251.dtsi
 create mode 100644 arch/arm/boot/dts/db-dxbc2.dts
 create mode 100644 arch/arm/boot/dts/db-xc3-24g4xg.dts
 create mode 100644 arch/arm/mach-mvebu/pmsu-98dx3236.c
 create mode 100644 drivers/clk/mvebu/mv98dx3236-corediv.c

-- 
2.11.0.24.ge6920cf

^ permalink raw reply

* [PATCHv2 1/5] clk: mvebu: support for 98DX3236 SoC
From: Chris Packham @ 2017-01-05  3:36 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170105033641.6212-1-chris.packham@alliedtelesis.co.nz>

The 98DX3236, 98DX3336, 98DX4521 and variants have a different TCLK from
the Armada XP (200MHz vs 250MHz). The CPU core clock is fixed at 800MHz.

The clock gating options are a subset of those on the Armada XP.

The core clock divider is different to the Armada XP also.

Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
---
Changes in v2:
- Update devicetree binding documentation for new compatible string

 .../devicetree/bindings/clock/mvebu-cpu-clock.txt  |   1 +
 drivers/clk/mvebu/Makefile                         |   2 +-
 drivers/clk/mvebu/armada-xp.c                      |  42 +++++
 drivers/clk/mvebu/clk-cpu.c                        |  33 +++-
 drivers/clk/mvebu/mv98dx3236-corediv.c             | 207 +++++++++++++++++++++
 5 files changed, 281 insertions(+), 4 deletions(-)
 create mode 100644 drivers/clk/mvebu/mv98dx3236-corediv.c

diff --git a/Documentation/devicetree/bindings/clock/mvebu-cpu-clock.txt b/Documentation/devicetree/bindings/clock/mvebu-cpu-clock.txt
index 99c214660bdc..7f28506eaee7 100644
--- a/Documentation/devicetree/bindings/clock/mvebu-cpu-clock.txt
+++ b/Documentation/devicetree/bindings/clock/mvebu-cpu-clock.txt
@@ -3,6 +3,7 @@ Device Tree Clock bindings for cpu clock of Marvell EBU platforms
 Required properties:
 - compatible : shall be one of the following:
 	"marvell,armada-xp-cpu-clock" - cpu clocks for Armada XP
+	"marvell,mv98dx3236-cpu-clock" - cpu clocks for 98DX3236 SoC
 - reg : Address and length of the clock complex register set, followed
         by address and length of the PMU DFS registers
 - #clock-cells : should be set to 1.
diff --git a/drivers/clk/mvebu/Makefile b/drivers/clk/mvebu/Makefile
index d9ae97fb43c4..6a3681e3d6db 100644
--- a/drivers/clk/mvebu/Makefile
+++ b/drivers/clk/mvebu/Makefile
@@ -9,7 +9,7 @@ obj-$(CONFIG_ARMADA_39X_CLK)	+= armada-39x.o
 obj-$(CONFIG_ARMADA_37XX_CLK)	+= armada-37xx-xtal.o
 obj-$(CONFIG_ARMADA_37XX_CLK)	+= armada-37xx-tbg.o
 obj-$(CONFIG_ARMADA_37XX_CLK)	+= armada-37xx-periph.o
-obj-$(CONFIG_ARMADA_XP_CLK)	+= armada-xp.o
+obj-$(CONFIG_ARMADA_XP_CLK)	+= armada-xp.o mv98dx3236-corediv.o
 obj-$(CONFIG_ARMADA_AP806_SYSCON) += ap806-system-controller.o
 obj-$(CONFIG_ARMADA_CP110_SYSCON) += cp110-system-controller.o
 obj-$(CONFIG_DOVE_CLK)		+= dove.o dove-divider.o
diff --git a/drivers/clk/mvebu/armada-xp.c b/drivers/clk/mvebu/armada-xp.c
index b3094315a3c0..0413bf8284e0 100644
--- a/drivers/clk/mvebu/armada-xp.c
+++ b/drivers/clk/mvebu/armada-xp.c
@@ -52,6 +52,12 @@ static u32 __init axp_get_tclk_freq(void __iomem *sar)
 	return 250000000;
 }
 
+/* MV98DX3236 TCLK frequency is fixed to 200MHz */
+static u32 __init mv98dx3236_get_tclk_freq(void __iomem *sar)
+{
+	return 200000000;
+}
+
 static const u32 axp_cpu_freqs[] __initconst = {
 	1000000000,
 	1066000000,
@@ -89,6 +95,12 @@ static u32 __init axp_get_cpu_freq(void __iomem *sar)
 	return cpu_freq;
 }
 
+/* MV98DX3236 CLK frequency is fixed to 800MHz */
+static u32 __init mv98dx3236_get_cpu_freq(void __iomem *sar)
+{
+	return 800000000;
+}
+
 static const int axp_nbclk_ratios[32][2] __initconst = {
 	{0, 1}, {1, 2}, {2, 2}, {2, 2},
 	{1, 2}, {1, 2}, {1, 1}, {2, 3},
@@ -158,6 +170,14 @@ static const struct coreclk_soc_desc axp_coreclks = {
 	.num_ratios = ARRAY_SIZE(axp_coreclk_ratios),
 };
 
+static const struct coreclk_soc_desc mv98dx3236_coreclks = {
+	.get_tclk_freq = mv98dx3236_get_tclk_freq,
+	.get_cpu_freq = mv98dx3236_get_cpu_freq,
+	.get_clk_ratio = NULL,
+	.ratios = NULL,
+	.num_ratios = 0,
+};
+
 /*
  * Clock Gating Control
  */
@@ -195,6 +215,15 @@ static const struct clk_gating_soc_desc axp_gating_desc[] __initconst = {
 	{ }
 };
 
+static const struct clk_gating_soc_desc mv98dx3236_gating_desc[] __initconst = {
+	{ "ge1", NULL, 3, 0 },
+	{ "ge0", NULL, 4, 0 },
+	{ "pex00", NULL, 5, 0 },
+	{ "sdio", NULL, 17, 0 },
+	{ "xor0", NULL, 22, 0 },
+	{ }
+};
+
 static void __init axp_clk_init(struct device_node *np)
 {
 	struct device_node *cgnp =
@@ -206,3 +235,16 @@ static void __init axp_clk_init(struct device_node *np)
 		mvebu_clk_gating_setup(cgnp, axp_gating_desc);
 }
 CLK_OF_DECLARE(axp_clk, "marvell,armada-xp-core-clock", axp_clk_init);
+
+static void __init mv98dx3236_clk_init(struct device_node *np)
+{
+	struct device_node *cgnp =
+		of_find_compatible_node(NULL, NULL, "marvell,armada-xp-gating-clock");
+
+	mvebu_coreclk_setup(np, &mv98dx3236_coreclks);
+
+	if (cgnp)
+		mvebu_clk_gating_setup(cgnp, mv98dx3236_gating_desc);
+}
+CLK_OF_DECLARE(mv98dx3236_clk, "marvell,mv98dx3236-core-clock",
+	       mv98dx3236_clk_init);
diff --git a/drivers/clk/mvebu/clk-cpu.c b/drivers/clk/mvebu/clk-cpu.c
index 5837eb8a212f..29f295e7a36b 100644
--- a/drivers/clk/mvebu/clk-cpu.c
+++ b/drivers/clk/mvebu/clk-cpu.c
@@ -165,7 +165,9 @@ static const struct clk_ops cpu_ops = {
 	.set_rate = clk_cpu_set_rate,
 };
 
-static void __init of_cpu_clk_setup(struct device_node *node)
+/* Add parameter to allow this to support different clock operations. */
+static void __init _of_cpu_clk_setup(struct device_node *node,
+			const struct clk_ops *cpu_clk_ops)
 {
 	struct cpu_clk *cpuclk;
 	void __iomem *clock_complex_base = of_iomap(node, 0);
@@ -218,7 +220,7 @@ static void __init of_cpu_clk_setup(struct device_node *node)
 		cpuclk[cpu].hw.init = &init;
 
 		init.name = cpuclk[cpu].clk_name;
-		init.ops = &cpu_ops;
+		init.ops = cpu_clk_ops;
 		init.flags = 0;
 		init.parent_names = &cpuclk[cpu].parent_name;
 		init.num_parents = 1;
@@ -243,5 +245,30 @@ static void __init of_cpu_clk_setup(struct device_node *node)
 	iounmap(clock_complex_base);
 }
 
+/* Use this function to call the generic setup with the correct
+ * clock operation
+ */
+static void __init of_cpu_clk_setup(struct device_node *node)
+{
+	_of_cpu_clk_setup(node, &cpu_ops);
+}
+
 CLK_OF_DECLARE(armada_xp_cpu_clock, "marvell,armada-xp-cpu-clock",
-					 of_cpu_clk_setup);
+					of_cpu_clk_setup);
+
+/* Define the clock and operations for the mv98dx3236 - it cannot perform
+ * any operations.
+ */
+static const struct clk_ops mv98dx3236_cpu_ops = {
+	.recalc_rate = NULL,
+	.round_rate = NULL,
+	.set_rate = NULL,
+};
+
+static void __init of_mv98dx3236_cpu_clk_setup(struct device_node *node)
+{
+	_of_cpu_clk_setup(node, &mv98dx3236_cpu_ops);
+}
+
+CLK_OF_DECLARE(mv98dx3236_cpu_clock, "marvell,mv98dx3236-cpu-clock",
+					 of_mv98dx3236_cpu_clk_setup);
diff --git a/drivers/clk/mvebu/mv98dx3236-corediv.c b/drivers/clk/mvebu/mv98dx3236-corediv.c
new file mode 100644
index 000000000000..3060764a8e5d
--- /dev/null
+++ b/drivers/clk/mvebu/mv98dx3236-corediv.c
@@ -0,0 +1,207 @@
+/*
+ * MV98DX3236 Core divider clock
+ *
+ * Copyright (C) 2015 Allied Telesis Labs
+ *
+ * Based on armada-xp-corediv.c
+ * Copyright (C) 2015 Marvell
+ *
+ * John Thompson <john.thompson@alliedtelesis.co.nz>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <linux/kernel.h>
+#include <linux/clk-provider.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "common.h"
+
+#define CORE_CLK_DIV_RATIO_MASK		0xff
+
+#define CLK_DIV_RATIO_NAND_MASK 0x0f
+#define CLK_DIV_RATIO_NAND_OFFSET 6
+#define CLK_DIV_RATIO_NAND_FORCE_RELOAD_BIT 26
+
+#define RATIO_RELOAD_BIT BIT(10)
+#define RATIO_REG_OFFSET 0x08
+
+/*
+ * This structure represents one core divider clock for the clock
+ * framework, and is dynamically allocated for each core divider clock
+ * existing in the current SoC.
+ */
+struct clk_corediv {
+	struct clk_hw hw;
+	void __iomem *reg;
+	spinlock_t lock;
+};
+
+static struct clk_onecell_data clk_data;
+
+
+#define to_corediv_clk(p) container_of(p, struct clk_corediv, hw)
+
+static int mv98dx3236_corediv_is_enabled(struct clk_hw *hwclk)
+{
+	/* Core divider is always active */
+	return 1;
+}
+
+static int mv98dx3236_corediv_enable(struct clk_hw *hwclk)
+{
+	/* always succeeds */
+	return 0;
+}
+
+static void mv98dx3236_corediv_disable(struct clk_hw *hwclk)
+{
+	/* can't be disabled so is left alone */
+}
+
+static unsigned long mv98dx3236_corediv_recalc_rate(struct clk_hw *hwclk,
+					 unsigned long parent_rate)
+{
+	struct clk_corediv *corediv = to_corediv_clk(hwclk);
+	u32 reg, div;
+
+	reg = readl(corediv->reg + RATIO_REG_OFFSET);
+	div = (reg >> CLK_DIV_RATIO_NAND_OFFSET) & CLK_DIV_RATIO_NAND_MASK;
+	return parent_rate / div;
+}
+
+static long mv98dx3236_corediv_round_rate(struct clk_hw *hwclk,
+			       unsigned long rate, unsigned long *parent_rate)
+{
+	/* Valid ratio are 1:4, 1:5, 1:6 and 1:8 */
+	u32 div;
+
+	div = *parent_rate / rate;
+	if (div < 4)
+		div = 4;
+	else if (div > 6)
+		div = 8;
+
+	return *parent_rate / div;
+}
+
+static int mv98dx3236_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate,
+			    unsigned long parent_rate)
+{
+	struct clk_corediv *corediv = to_corediv_clk(hwclk);
+	unsigned long flags = 0;
+	u32 reg, div;
+
+	div = parent_rate / rate;
+
+	spin_lock_irqsave(&corediv->lock, flags);
+
+	/* Write new divider to the divider ratio register */
+	reg = readl(corediv->reg + RATIO_REG_OFFSET);
+	reg &= ~(CLK_DIV_RATIO_NAND_MASK << CLK_DIV_RATIO_NAND_OFFSET);
+	reg |= (div & CLK_DIV_RATIO_NAND_MASK) << CLK_DIV_RATIO_NAND_OFFSET;
+	writel(reg, corediv->reg + RATIO_REG_OFFSET);
+
+	/* Set reload-force for this clock */
+	reg = readl(corediv->reg) | BIT(CLK_DIV_RATIO_NAND_FORCE_RELOAD_BIT);
+	writel(reg, corediv->reg);
+
+	/* Now trigger the clock update */
+	reg = readl(corediv->reg + RATIO_REG_OFFSET) | RATIO_RELOAD_BIT;
+	writel(reg, corediv->reg + RATIO_REG_OFFSET);
+
+	/*
+	 * Wait for clocks to settle down, and then clear all the
+	 * ratios request and the reload request.
+	 */
+	udelay(1000);
+	reg &= ~(CORE_CLK_DIV_RATIO_MASK | RATIO_RELOAD_BIT);
+	writel(reg, corediv->reg + RATIO_REG_OFFSET);
+	udelay(1000);
+
+	spin_unlock_irqrestore(&corediv->lock, flags);
+
+	return 0;
+}
+
+static const struct clk_ops ops = {
+	.enable = mv98dx3236_corediv_enable,
+	.disable = mv98dx3236_corediv_disable,
+	.is_enabled = mv98dx3236_corediv_is_enabled,
+	.recalc_rate = mv98dx3236_corediv_recalc_rate,
+	.round_rate = mv98dx3236_corediv_round_rate,
+	.set_rate = mv98dx3236_corediv_set_rate,
+};
+
+static void __init mv98dx3236_corediv_clk_init(struct device_node *node)
+{
+	struct clk_init_data init;
+	struct clk_corediv *corediv;
+	struct clk **clks;
+	void __iomem *base;
+	const __be32 *off;
+	const char *parent_name;
+	const char *clk_name;
+	int len;
+	struct device_node *dfx_node;
+
+	dfx_node = of_parse_phandle(node, "base", 0);
+	if (WARN_ON(!dfx_node))
+		return;
+
+	off = of_get_property(node, "reg", &len);
+	if (WARN_ON(!off))
+		return;
+
+	base = of_iomap(dfx_node, 0);
+	if (WARN_ON(!base))
+		return;
+
+	of_node_put(dfx_node);
+
+	parent_name = of_clk_get_parent_name(node, 0);
+
+	clk_data.clk_num = 1;
+
+	/* clks holds the clock array */
+	clks = kcalloc(clk_data.clk_num, sizeof(struct clk *),
+				GFP_KERNEL);
+	if (WARN_ON(!clks))
+		goto err_unmap;
+	/* corediv holds the clock specific array */
+	corediv = kcalloc(clk_data.clk_num, sizeof(struct clk_corediv),
+				GFP_KERNEL);
+	if (WARN_ON(!corediv))
+		goto err_free_clks;
+
+	spin_lock_init(&corediv->lock);
+
+	of_property_read_string_index(node, "clock-output-names",
+					  0, &clk_name);
+
+	init.num_parents = 1;
+	init.parent_names = &parent_name;
+	init.name = clk_name;
+	init.ops = &ops;
+	init.flags = 0;
+
+	corediv[0].reg = (void *)((int)base + be32_to_cpu(*off));
+	corediv[0].hw.init = &init;
+
+	clks[0] = clk_register(NULL, &corediv[0].hw);
+	WARN_ON(IS_ERR(clks[0]));
+
+	clk_data.clks = clks;
+	of_clk_add_provider(node, of_clk_src_onecell_get, &clk_data);
+	return;
+
+err_free_clks:
+	kfree(clks);
+err_unmap:
+	iounmap(base);
+}
+
+CLK_OF_DECLARE(mv98dx3236_corediv_clk, "marvell,mv98dx3236-corediv-clock",
+	       mv98dx3236_corediv_clk_init);
-- 
2.11.0.24.ge6920cf

^ permalink raw reply related

* [PATCHv2 2/5] arm: mvebu: support for SMP on 98DX3336 SoC
From: Chris Packham @ 2017-01-05  3:36 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170105033641.6212-1-chris.packham@alliedtelesis.co.nz>

Compared to the armada-xp the 98DX3336 uses different registers to set
the boot address for the secondary CPU so a new enable-method is needed.
This will only work if the machine definition doesn't define an overall
smp_ops because there is not currently a way of overriding this from the
device tree if it is set in the machine definition.

Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
---
Changes in v2:
- Document new enable-method value
- Correct some references from 98DX4521 to 98DX3236

 Documentation/devicetree/bindings/arm/cpus.txt     |  1 +
 .../bindings/arm/marvell/98dx3236-resume-ctrl.txt  | 18 ++++++
 arch/arm/mach-mvebu/Makefile                       |  1 +
 arch/arm/mach-mvebu/common.h                       |  1 +
 arch/arm/mach-mvebu/platsmp.c                      | 43 ++++++++++++++
 arch/arm/mach-mvebu/pmsu-98dx3236.c                | 69 ++++++++++++++++++++++
 6 files changed, 133 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/marvell/98dx3236-resume-ctrl.txt
 create mode 100644 arch/arm/mach-mvebu/pmsu-98dx3236.c

diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt
index a1bcfeed5f24..3c2fd72d0bf9 100644
--- a/Documentation/devicetree/bindings/arm/cpus.txt
+++ b/Documentation/devicetree/bindings/arm/cpus.txt
@@ -202,6 +202,7 @@ nodes to be present and contain the properties described below.
 			    "marvell,armada-380-smp"
 			    "marvell,armada-390-smp"
 			    "marvell,armada-xp-smp"
+			    "marvell,98dx3236-smp"
 			    "mediatek,mt6589-smp"
 			    "mediatek,mt81xx-tz-smp"
 			    "qcom,gcc-msm8660"
diff --git a/Documentation/devicetree/bindings/arm/marvell/98dx3236-resume-ctrl.txt b/Documentation/devicetree/bindings/arm/marvell/98dx3236-resume-ctrl.txt
new file mode 100644
index 000000000000..8082ba872edd
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/marvell/98dx3236-resume-ctrl.txt
@@ -0,0 +1,18 @@
+Resume Control
+--------------
+Available on Marvell SOCs: 98DX3336 and 98DX4251
+
+Required properties:
+
+- compatible: must be "marvell,98dx3336-resume-ctrl"
+
+- reg: Should contain resume control registers location and length
+
+Example:
+
+resume at 20980 {
+	compatible = "marvell,98dx3336-resume-ctrl";
+	reg = <0x20980 0x10>;
+};
+
+
diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile
index 6c6497e80a7b..2a2dd8324fb8 100644
--- a/arch/arm/mach-mvebu/Makefile
+++ b/arch/arm/mach-mvebu/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_MACH_MVEBU_ANY)	 += system-controller.o mvebu-soc-id.o
 
 ifeq ($(CONFIG_MACH_MVEBU_V7),y)
 obj-y				 += cpu-reset.o board-v7.o coherency.o coherency_ll.o pmsu.o pmsu_ll.o
+obj-y				 += pmsu-98dx3236.o
 
 obj-$(CONFIG_PM)		 += pm.o pm-board.o
 obj-$(CONFIG_SMP)		 += platsmp.o headsmp.o platsmp-a9.o headsmp-a9.o
diff --git a/arch/arm/mach-mvebu/common.h b/arch/arm/mach-mvebu/common.h
index 6b775492cfad..099dabf23461 100644
--- a/arch/arm/mach-mvebu/common.h
+++ b/arch/arm/mach-mvebu/common.h
@@ -27,4 +27,5 @@ void __iomem *mvebu_get_scu_base(void);
 
 int mvebu_pm_suspend_init(void (*board_pm_enter)(void __iomem *sdram_reg,
 							u32 srcmd));
+void mv98dx3236_resume_set_cpu_boot_addr(int hw_cpu, void *boot_addr);
 #endif
diff --git a/arch/arm/mach-mvebu/platsmp.c b/arch/arm/mach-mvebu/platsmp.c
index 46c742d3bd41..3c9ab9a008ad 100644
--- a/arch/arm/mach-mvebu/platsmp.c
+++ b/arch/arm/mach-mvebu/platsmp.c
@@ -182,5 +182,48 @@ const struct smp_operations armada_xp_smp_ops __initconst = {
 #endif
 };
 
+static int mv98dx3236_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+	int ret, hw_cpu;
+
+	pr_info("Booting CPU %d\n", cpu);
+
+	hw_cpu = cpu_logical_map(cpu);
+	set_secondary_cpu_clock(hw_cpu);
+	mv98dx3236_resume_set_cpu_boot_addr(hw_cpu,
+					    armada_xp_secondary_startup);
+
+	/*
+	 * This is needed to wake up CPUs in the offline state after
+	 * using CPU hotplug.
+	 */
+	arch_send_wakeup_ipi_mask(cpumask_of(cpu));
+
+	/*
+	 * This is needed to take secondary CPUs out of reset on the
+	 * initial boot.
+	 */
+	ret = mvebu_cpu_reset_deassert(hw_cpu);
+	if (ret) {
+		pr_warn("unable to boot CPU: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+struct smp_operations mv98dx3236_smp_ops __initdata = {
+	.smp_init_cpus		= armada_xp_smp_init_cpus,
+	.smp_prepare_cpus	= armada_xp_smp_prepare_cpus,
+	.smp_boot_secondary	= mv98dx3236_boot_secondary,
+	.smp_secondary_init     = armada_xp_secondary_init,
+#ifdef CONFIG_HOTPLUG_CPU
+	.cpu_die		= armada_xp_cpu_die,
+	.cpu_kill               = armada_xp_cpu_kill,
+#endif
+};
+
 CPU_METHOD_OF_DECLARE(armada_xp_smp, "marvell,armada-xp-smp",
 		      &armada_xp_smp_ops);
+CPU_METHOD_OF_DECLARE(mv98dx3236_smp, "marvell,98dx3236-smp",
+		      &mv98dx3236_smp_ops);
diff --git a/arch/arm/mach-mvebu/pmsu-98dx3236.c b/arch/arm/mach-mvebu/pmsu-98dx3236.c
new file mode 100644
index 000000000000..87ca42ef40c7
--- /dev/null
+++ b/arch/arm/mach-mvebu/pmsu-98dx3236.c
@@ -0,0 +1,69 @@
+/**
+ * CPU resume support for 98DX3236 internal CPU (a.k.a. MSYS).
+ */
+
+#define pr_fmt(fmt) "mv98dx3236-resume: " fmt
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/of_address.h>
+#include <linux/io.h>
+#include "common.h"
+
+static void __iomem *mv98dx3236_resume_base;
+#define MV98DX3236_CPU_RESUME_CTRL_OFFSET	0x08
+#define MV98DX3236_CPU_RESUME_ADDR_OFFSET	0x04
+
+static const struct of_device_id of_mv98dx3236_resume_table[] = {
+	{.compatible = "marvell,98dx3336-resume-ctrl",},
+	{ /* end of list */ },
+};
+
+void mv98dx3236_resume_set_cpu_boot_addr(int hw_cpu, void *boot_addr)
+{
+	WARN_ON(hw_cpu != 1);
+
+	writel(0, mv98dx3236_resume_base + MV98DX3236_CPU_RESUME_CTRL_OFFSET);
+	writel(virt_to_phys(boot_addr), mv98dx3236_resume_base +
+	       MV98DX3236_CPU_RESUME_ADDR_OFFSET);
+}
+
+static int __init mv98dx3236_resume_init(void)
+{
+	struct device_node *np;
+	struct resource res;
+	int ret = 0;
+
+	np = of_find_matching_node(NULL, of_mv98dx3236_resume_table);
+	if (!np)
+		return 0;
+
+	pr_info("Initializing 98DX3236 Resume\n");
+
+	if (of_address_to_resource(np, 0, &res)) {
+		pr_err("unable to get resource\n");
+		ret = -ENOENT;
+		goto out;
+	}
+
+	if (!request_mem_region(res.start, resource_size(&res),
+				np->full_name)) {
+		pr_err("unable to request region\n");
+		ret = -EBUSY;
+		goto out;
+	}
+
+	mv98dx3236_resume_base = ioremap(res.start, resource_size(&res));
+	if (!mv98dx3236_resume_base) {
+		pr_err("unable to map registers\n");
+		release_mem_region(res.start, resource_size(&res));
+		ret = -ENOMEM;
+		goto out;
+	}
+
+out:
+	of_node_put(np);
+	return ret;
+}
+
+early_initcall(mv98dx3236_resume_init);
-- 
2.11.0.24.ge6920cf

^ permalink raw reply related

* [PATCHv2 3/5] pinctrl: mvebu: pinctrl driver for 98DX3236 SoC
From: Chris Packham @ 2017-01-05  3:36 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170105033641.6212-1-chris.packham@alliedtelesis.co.nz>

From: Kalyan Kinthada <kalyan.kinthada@alliedtelesis.co.nz>

This pinctrl driver supports the 98DX3236, 98DX3336 and 98DX4251 SoCs
from Marvell.

Signed-off-by: Kalyan Kinthada <kalyan.kinthada@alliedtelesis.co.nz>
Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
---
Changes in v2:
- include sdio support for the 98DX4251

 .../pinctrl/marvell,armada-98dx3236-pinctrl.txt    |  46 ++++++
 drivers/pinctrl/mvebu/pinctrl-armada-xp.c          | 155 +++++++++++++++++++++
 2 files changed, 201 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/marvell,armada-98dx3236-pinctrl.txt

diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada-98dx3236-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,armada-98dx3236-pinctrl.txt
new file mode 100644
index 000000000000..d4e6ecdfc853
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,armada-98dx3236-pinctrl.txt
@@ -0,0 +1,46 @@
+* Marvell 98dx3236 pinctrl driver for mpp
+
+Please refer to marvell,mvebu-pinctrl.txt in this directory for common binding
+part and usage
+
+Required properties:
+- compatible: "marvell,98dx3236-pinctrl" or "marvell,98dx4251-pinctrl"
+- reg: register specifier of MPP registers
+
+This driver supports all 98dx3236, 98dx3336 and 98dx4251 variants
+
+name          pins     functions
+================================================================================
+mpp0          0        gpio, spi0(mosi), dev(ad8)
+mpp1          1        gpio, spi0(miso), dev(ad9)
+mpp2          2        gpio, spi0(sck), dev(ad10)
+mpp3          3        gpio, spi0(cs0), dev(ad11)
+mpp4          4        gpio, spi0(cs1), smi(mdc), dev(cs0)
+mpp5          5        gpio, pex(rsto), sd0(cmd), dev(bootcs)
+mpp6          6        gpio, sd0(clk), dev(a2)
+mpp7          7        gpio, sd0(d0), dev(ale0)
+mpp8          8        gpio, sd0(d1), dev(ale1)
+mpp9          9        gpio, sd0(d2), dev(ready0)
+mpp10         10       gpio, sd0(d3), dev(ad12)
+mpp11         11       gpio, uart1(rxd), uart0(cts), dev(ad13)
+mpp12         12       gpio, uart1(txd), uart0(rts), dev(ad14)
+mpp13         13       gpio, intr(out), dev(ad15)
+mpp14         14       gpio, i2c0(sck)
+mpp15         15       gpio, i2c0(sda)
+mpp16         16       gpio, dev(oe)
+mpp17         17       gpio, dev(clk)
+mpp18         18       gpio, uart1(txd)
+mpp19         19       gpio, uart1(rxd), dev(rb)
+mpp20         20       gpio, dev(we)
+mpp21         21       gpio, dev(ad0)
+mpp22         22       gpio, dev(ad1)
+mpp23         23       gpio, dev(ad2)
+mpp24         24       gpio, dev(ad3)
+mpp25         25       gpio, dev(ad4)
+mpp26         26       gpio, dev(ad5)
+mpp27         27       gpio, dev(ad6)
+mpp28         28       gpio, dev(ad7)
+mpp29         29       gpio, dev(a0)
+mpp30         30       gpio, dev(a1)
+mpp31         31       gpio, slv_smi(mdc), smi(mdc), dev(we1)
+mpp32         32       gpio, slv_smi(mdio), smi(mdio), dev(cs1)
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-xp.c b/drivers/pinctrl/mvebu/pinctrl-armada-xp.c
index e4ea71a9d985..554eeae8cd21 100644
--- a/drivers/pinctrl/mvebu/pinctrl-armada-xp.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-xp.c
@@ -49,6 +49,10 @@ enum armada_xp_variant {
 	V_MV78460	= BIT(2),
 	V_MV78230_PLUS	= (V_MV78230 | V_MV78260 | V_MV78460),
 	V_MV78260_PLUS	= (V_MV78260 | V_MV78460),
+	V_98DX3236	= BIT(3),
+	V_98DX3336	= BIT(4),
+	V_98DX4251	= BIT(5),
+	V_98DX3236_PLUS	= (V_98DX3236 | V_98DX3336 | V_98DX4251),
 };
 
 static struct mvebu_mpp_mode armada_xp_mpp_modes[] = {
@@ -360,6 +364,130 @@ static struct mvebu_mpp_mode armada_xp_mpp_modes[] = {
 		 MPP_VAR_FUNCTION(0x1, "dev", "ad31",       V_MV78260_PLUS)),
 };
 
+static struct mvebu_mpp_mode mv98dx3236_mpp_modes[] = {
+	MPP_MODE(0,
+		 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "spi0", "mosi",       V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "dev", "ad8",         V_98DX3236_PLUS)),
+	MPP_MODE(1,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "spi0", "miso",       V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "dev", "ad9",         V_98DX3236_PLUS)),
+	MPP_MODE(2,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "spi0", "csk",        V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "dev", "ad10",        V_98DX3236_PLUS)),
+	MPP_MODE(3,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "spi0", "cs0",        V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "dev", "ad11",        V_98DX3236_PLUS)),
+	MPP_MODE(4,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "spi0", "cs1",        V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "smi", "mdc",         V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "dev", "cs0",         V_98DX3236_PLUS)),
+	MPP_MODE(5,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "pex", "rsto",        V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "sd0", "cmd",         V_98DX4251),
+		 MPP_VAR_FUNCTION(0x4, "dev", "bootcs0",     V_98DX3236_PLUS)),
+	MPP_MODE(6,
+		 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "sd0", "clk",         V_98DX4251),
+		 MPP_VAR_FUNCTION(0x4, "dev", "a2",          V_98DX3236_PLUS)),
+	MPP_MODE(7,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "sd0", "d0",          V_98DX4251),
+		 MPP_VAR_FUNCTION(0x4, "dev", "ale0",        V_98DX3236_PLUS)),
+	MPP_MODE(8,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "sd0", "d1",          V_98DX4251),
+		 MPP_VAR_FUNCTION(0x4, "dev", "ale1",        V_98DX3236_PLUS)),
+	MPP_MODE(9,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "sd0", "d2",          V_98DX4251),
+		 MPP_VAR_FUNCTION(0x4, "dev", "ready0",      V_98DX3236_PLUS)),
+	MPP_MODE(10,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "sd0", "d3",          V_98DX4251),
+		 MPP_VAR_FUNCTION(0x4, "dev", "ad12",        V_98DX3236_PLUS)),
+	MPP_MODE(11,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "uart1", "rxd",       V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "uart0", "cts",       V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "dev", "ad13",        V_98DX3236_PLUS)),
+	MPP_MODE(12,
+		 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "uart1", "txd",       V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "uart0", "rts",       V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "dev", "ad14",        V_98DX3236_PLUS)),
+	MPP_MODE(13,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "intr", "out",        V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "dev", "ad15",        V_98DX3236_PLUS)),
+	MPP_MODE(14,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "i2c0", "sck",        V_98DX3236_PLUS)),
+	MPP_MODE(15,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "i2c0", "sda",        V_98DX3236_PLUS)),
+	MPP_MODE(16,
+		 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "dev", "oe",          V_98DX3236_PLUS)),
+	MPP_MODE(17,
+		 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "dev", "clkout",      V_98DX3236_PLUS)),
+	MPP_MODE(18,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "uart1", "txd",       V_98DX3236_PLUS)),
+	MPP_MODE(19,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "uart1", "rxd",       V_98DX3236_PLUS)),
+	MPP_MODE(20,
+		 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "dev", "we0",         V_98DX3236_PLUS)),
+	MPP_MODE(21,
+		 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "ad0",         V_98DX3236_PLUS)),
+	MPP_MODE(22,
+		 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "ad1",         V_98DX3236_PLUS)),
+	MPP_MODE(23,
+		 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "ad2",         V_98DX3236_PLUS)),
+	MPP_MODE(24,
+		 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "ad3",         V_98DX3236_PLUS)),
+	MPP_MODE(25,
+		 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "ad4",         V_98DX3236_PLUS)),
+	MPP_MODE(26,
+		 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "ad5",         V_98DX3236_PLUS)),
+	MPP_MODE(27,
+		 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "ad6",         V_98DX3236_PLUS)),
+	MPP_MODE(28,
+		 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "ad7",         V_98DX3236_PLUS)),
+	MPP_MODE(29,
+		 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "a0",          V_98DX3236_PLUS)),
+	MPP_MODE(30,
+		 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "a1",          V_98DX3236_PLUS)),
+	MPP_MODE(31,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "slv_smi", "mdc",     V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "smi", "mdc",         V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "dev", "we1",         V_98DX3236_PLUS)),
+	MPP_MODE(32,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "slv_smi", "mdio",    V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "smi", "mdio",        V_98DX3236_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "dev", "cs1",         V_98DX3236_PLUS)),
+};
+
 static struct mvebu_pinctrl_soc_info armada_xp_pinctrl_info;
 
 static const struct of_device_id armada_xp_pinctrl_of_match[] = {
@@ -375,6 +503,14 @@ static const struct of_device_id armada_xp_pinctrl_of_match[] = {
 		.compatible = "marvell,mv78460-pinctrl",
 		.data       = (void *) V_MV78460,
 	},
+	{
+		.compatible = "marvell,98dx3236-pinctrl",
+		.data       = (void *) V_98DX3236,
+	},
+	{
+		.compatible = "marvell,98dx4251-pinctrl",
+		.data       = (void *) V_98DX4251,
+	},
 	{ },
 };
 
@@ -407,6 +543,14 @@ static struct pinctrl_gpio_range mv78460_mpp_gpio_ranges[] = {
 	MPP_GPIO_RANGE(2,  64, 64,  3),
 };
 
+static struct mvebu_mpp_ctrl mv98dx3236_mpp_controls[] = {
+	MPP_FUNC_CTRL(0, 32, NULL, armada_xp_mpp_ctrl),
+};
+
+static struct pinctrl_gpio_range mv98dx3236_mpp_gpio_ranges[] = {
+	MPP_GPIO_RANGE(0,   0,  0, 32),
+};
+
 static int armada_xp_pinctrl_suspend(struct platform_device *pdev,
 				     pm_message_t state)
 {
@@ -488,6 +632,17 @@ static int armada_xp_pinctrl_probe(struct platform_device *pdev)
 		soc->gpioranges = mv78460_mpp_gpio_ranges;
 		soc->ngpioranges = ARRAY_SIZE(mv78460_mpp_gpio_ranges);
 		break;
+	case V_98DX3236:
+	case V_98DX3336:
+	case V_98DX4251:
+		/* fall-through */
+		soc->controls = mv98dx3236_mpp_controls;
+		soc->ncontrols = ARRAY_SIZE(mv98dx3236_mpp_controls);
+		soc->modes = mv98dx3236_mpp_modes;
+		soc->nmodes = mv98dx3236_mpp_controls[0].npins;
+		soc->gpioranges = mv98dx3236_mpp_gpio_ranges;
+		soc->ngpioranges = ARRAY_SIZE(mv98dx3236_mpp_gpio_ranges);
+		break;
 	}
 
 	nregs = DIV_ROUND_UP(soc->nmodes, MVEBU_MPPS_PER_REG);
-- 
2.11.0.24.ge6920cf

^ permalink raw reply related

* [PATCHv2 4/5] arm: mvebu: Add device tree for 98DX3236 SoCs
From: Chris Packham @ 2017-01-05  3:36 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170105033641.6212-1-chris.packham@alliedtelesis.co.nz>

The Marvell 98DX3236, 98DX3336, 98DX4521 and variants are switch ASICs
with integrated CPUs. They are similar to the Armada XP SoCs but have
different I/O interfaces.

Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
---
Changes in v2:
- Update devicetree binding documentation to reflect that 98DX3336 and
  984251 are supersets of 98DX3236.
- disable crypto block
- disable sdio for 98DX3236, enable for 98DX4251

 .../devicetree/bindings/arm/marvell/98dx3236.txt   |  23 ++
 arch/arm/boot/dts/armada-xp-98dx3236.dtsi          | 247 +++++++++++++++++++++
 arch/arm/boot/dts/armada-xp-98dx3336.dtsi          |  78 +++++++
 arch/arm/boot/dts/armada-xp-98dx4251.dtsi          |  92 ++++++++
 4 files changed, 440 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/marvell/98dx3236.txt
 create mode 100644 arch/arm/boot/dts/armada-xp-98dx3236.dtsi
 create mode 100644 arch/arm/boot/dts/armada-xp-98dx3336.dtsi
 create mode 100644 arch/arm/boot/dts/armada-xp-98dx4251.dtsi

diff --git a/Documentation/devicetree/bindings/arm/marvell/98dx3236.txt b/Documentation/devicetree/bindings/arm/marvell/98dx3236.txt
new file mode 100644
index 000000000000..64e8c73fc5ab
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/marvell/98dx3236.txt
@@ -0,0 +1,23 @@
+Marvell 98DX3236, 98DX3336 and 98DX4251 Platforms Device Tree Bindings
+----------------------------------------------------------------------
+
+Boards with a SoC of the Marvell 98DX3236, 98DX3336 and 98DX4251 families
+shall have the following property:
+
+Required root node property:
+
+compatible: must contain "marvell,armadaxp-98dx3236"
+
+In addition, boards using the Marvell 98DX3336 SoC shall have the
+following property:
+
+Required root node property:
+
+compatible: must contain "marvell,armadaxp-98dx3336"
+
+In addition, boards using the Marvell 98DX4251 SoC shall have the
+following property:
+
+Required root node property:
+
+compatible: must contain "marvell,armadaxp-98dx4251"
diff --git a/arch/arm/boot/dts/armada-xp-98dx3236.dtsi b/arch/arm/boot/dts/armada-xp-98dx3236.dtsi
new file mode 100644
index 000000000000..61bd3acc5cfe
--- /dev/null
+++ b/arch/arm/boot/dts/armada-xp-98dx3236.dtsi
@@ -0,0 +1,247 @@
+/*
+ * Device Tree Include file for Marvell 98dx3236 family SoC
+ *
+ * Copyright (C) 2016 Allied Telesis Labs
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file 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 file 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.
+ *
+ * Or, alternatively
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contains definitions specific to the 98dx3236 SoC that are not
+ * common to all Armada XP SoCs.
+ */
+
+#include "armada-xp.dtsi"
+
+/ {
+	model = "Marvell 98DX3236 SoC";
+	compatible = "marvell,armadaxp-98dx3236", "marvell,armadaxp", "marvell,armada-370-xp";
+
+	aliases {
+		gpio0 = &gpio0;
+		gpio1 = &gpio1;
+		gpio2 = &gpio2;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		enable-method = "marvell,98dx3236-smp";
+
+		cpu at 0 {
+			device_type = "cpu";
+			compatible = "marvell,sheeva-v7";
+			reg = <0>;
+			clocks = <&cpuclk 0>;
+			clock-latency = <1000000>;
+		};
+	};
+
+	soc {
+		ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000
+			  MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
+			  MBUS_ID(0x01, 0x2f) 0 0 0xf0000000 0x1000000
+			  MBUS_ID(0x03, 0x00) 0 0 0xa8000000 0x4000000
+			  MBUS_ID(0x08, 0x00) 0 0 0xac000000 0x100000>;
+
+		/*
+		 * 98DX3236 has 1 x1 PCIe unit Gen2.0: One unit can be
+		 */
+		pcie-controller {
+			compatible = "marvell,armada-xp-pcie";
+			status = "disabled";
+			device_type = "pci";
+
+			#address-cells = <3>;
+			#size-cells = <2>;
+
+			msi-parent = <&mpic>;
+			bus-range = <0x00 0xff>;
+
+			ranges =
+			       <0x82000000 0 0x40000 MBUS_ID(0xf0, 0x01) 0x40000 0 0x00002000   /* Port 0.0 registers */
+				0x82000000 0x1 0       MBUS_ID(0x04, 0xe8) 0 1 0 /* Port 0.0 MEM */
+				0x81000000 0x1 0       MBUS_ID(0x04, 0xe0) 0 1 0 /* Port 0.0 IO  */
+				0x82000000 0x2 0       MBUS_ID(0x04, 0xd8) 0 1 0 /* Port 0.1 MEM */>;
+
+			pcie at 1,0 {
+				device_type = "pci";
+				assigned-addresses = <0x82000800 0 0x40000 0 0x2000>;
+				reg = <0x0800 0 0 0 0>;
+				#address-cells = <3>;
+				#size-cells = <2>;
+				#interrupt-cells = <1>;
+				ranges = <0x82000000 0 0 0x82000000 0x1 0 1 0
+					  0x81000000 0 0 0x81000000 0x1 0 1 0>;
+				interrupt-map-mask = <0 0 0 0>;
+				interrupt-map = <0 0 0 0 &mpic 58>;
+				marvell,pcie-port = <0>;
+				marvell,pcie-lane = <0>;
+				clocks = <&gateclk 5>;
+				status = "disabled";
+			};
+		};
+
+		internal-regs {
+			coreclk: mvebu-sar at 18230 {
+				compatible = "marvell,mv98dx3236-core-clock";
+			};
+
+			cpuclk: clock-complex at 18700 {
+				compatible = "marvell,mv98dx3236-cpu-clock";
+			};
+
+			corediv-clock at 18740 {
+				compatible = "marvell,mv98dx3236-corediv-clock";
+				reg = <0xf8268 0xc>;
+				base = <&dfx>;
+				#clock-cells = <1>;
+				clocks = <&mainpll>;
+				clock-output-names = "nand";
+			};
+
+			xor at 60900 {
+				status = "disabled";
+			};
+
+			crypto at 90000 {
+				status = "disabled";
+			};
+
+			xor at f0900 {
+				status = "disabled";
+			};
+
+			xor at f0800 {
+				compatible = "marvell,orion-xor";
+				reg = <0xf0800 0x100
+				       0xf0a00 0x100>;
+				clocks = <&gateclk 22>;
+				status = "okay";
+
+				xor10 {
+					interrupts = <51>;
+					dmacap,memcpy;
+					dmacap,xor;
+				};
+				xor11 {
+					interrupts = <52>;
+					dmacap,memcpy;
+					dmacap,xor;
+					dmacap,memset;
+				};
+			};
+
+			gpio0: gpio at 18100 {
+				compatible = "marvell,orion-gpio";
+				reg = <0x18100 0x40>;
+				ngpios = <32>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				interrupts = <82>, <83>, <84>, <85>;
+			};
+
+			/* does not exist */
+			gpio1: gpio at 18140 {
+				compatible = "marvell,orion-gpio";
+				reg = <0x18140 0x40>;
+				status = "disabled";
+			};
+
+			gpio2: gpio at 18180 { /* rework some properties */
+				compatible = "marvell,orion-gpio";
+				reg = <0x18180 0x40>;
+				ngpios = <1>; /* only gpio #32 */
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				interrupts = <87>;
+			};
+		};
+
+		dfx-registers {
+			compatible = "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 MBUS_ID(0x08, 0x00) 0 0x100000>;
+
+			dfx: dfx at 0 {
+				compatible = "simple-bus";
+				reg = <0 0x100000>;
+			};
+		};
+
+		switch {
+			compatible = "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 MBUS_ID(0x03, 0x00) 0 0x100000>;
+
+			packet-processor at 0 {
+				compatible = "marvell,prestera-98dx3236";
+				reg = <0 0x4000000>;
+				interrupts = <33>, <34>, <35>;
+				dfx = <&dfx>;
+			};
+		};
+	};
+};
+
+&pinctrl {
+	compatible = "marvell,98dx3236-pinctrl";
+
+	spi0_pins: spi0-pins {
+		marvell,pins = "mpp0", "mpp1",
+			       "mpp2", "mpp3";
+		marvell,function = "spi0";
+	};
+};
+
+&sdio {
+	status = "disabled";
+};
+
+&crypto_sram0 {
+	status = "disabled";
+};
+
+&crypto_sram1 {
+	status = "disabled";
+};
diff --git a/arch/arm/boot/dts/armada-xp-98dx3336.dtsi b/arch/arm/boot/dts/armada-xp-98dx3336.dtsi
new file mode 100644
index 000000000000..9c9aa565fd82
--- /dev/null
+++ b/arch/arm/boot/dts/armada-xp-98dx3336.dtsi
@@ -0,0 +1,78 @@
+/*
+ * Device Tree Include file for Marvell 98dx3336 family SoC
+ *
+ * Copyright (C) 2016 Allied Telesis Labs
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file 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 file 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.
+ *
+ * Or, alternatively
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contains definitions specific to the 98dx3336 SoC that are not
+ * common to all Armada XP SoCs.
+ */
+
+#include "armada-xp-98dx3236.dtsi"
+
+/ {
+	model = "Marvell 98DX3336 SoC";
+	compatible = "marvell,armadaxp-98dx3336", "marvell,armadaxp-98dx3236", "marvell,armadaxp", "marvell,armada-370-xp";
+
+	cpus {
+		cpu at 1 {
+			device_type = "cpu";
+			compatible = "marvell,sheeva-v7";
+			reg = <1>;
+			clocks = <&cpuclk 1>;
+			clock-latency = <1000000>;
+		};
+	};
+
+	soc {
+		internal-regs {
+			resume at 20980 {
+				compatible = "marvell,98dx3336-resume-ctrl";
+				reg = <0x20980 0x10>;
+			};
+		};
+
+		switch {
+			packet-processor at 0 {
+				compatible = "marvell,prestera-98dx3336";
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/armada-xp-98dx4251.dtsi b/arch/arm/boot/dts/armada-xp-98dx4251.dtsi
new file mode 100644
index 000000000000..5f7edc23d5ae
--- /dev/null
+++ b/arch/arm/boot/dts/armada-xp-98dx4251.dtsi
@@ -0,0 +1,92 @@
+/*
+ * Device Tree Include file for Marvell 98dx4521 family SoC
+ *
+ * Copyright (C) 2016 Allied Telesis Labs
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file 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 file 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.
+ *
+ * Or, alternatively
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contains definitions specific to the 98dx4521 SoC that are not
+ * common to all Armada XP SoCs.
+ */
+
+#include "armada-xp-98dx3236.dtsi"
+
+/ {
+	model = "Marvell 98DX4251 SoC";
+	compatible = "marvell,armadaxp-98dx4521", "marvell,armadaxp-98dx3236", "marvell,armadaxp", "marvell,armada-370-xp";
+
+	cpus {
+		cpu at 1 {
+			device_type = "cpu";
+			compatible = "marvell,sheeva-v7";
+			reg = <1>;
+			clocks = <&cpuclk 1>;
+			clock-latency = <1000000>;
+		};
+	};
+
+	soc {
+		internal-regs {
+			resume at 20980 {
+				compatible = "marvell,98dx3336-resume-ctrl";
+				reg = <0x20980 0x10>;
+			};
+		};
+
+		switch {
+			packet-processor at 0 {
+				compatible = "marvell,prestera-98dx4521";
+			};
+		};
+	};
+};
+
+&sdio {
+	status = "okay";
+};
+
+&pinctrl {
+	compatible = "marvell,98dx4251-pinctrl";
+
+	sdio_pins: sdio-pins {
+		marvell,pins = "mpp5", "mpp6", "mpp7",
+			       "mpp8", "mpp9", "mpp10";
+		marvell,function = "sd0";
+	};
+};
-- 
2.11.0.24.ge6920cf

^ permalink raw reply related

* [PATCHv2 5/5] arm: mvebu: Add device tree for db-dxbc2 and db-xc3-24g4xg boards
From: Chris Packham @ 2017-01-05  3:36 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170105033641.6212-1-chris.packham@alliedtelesis.co.nz>

These boards are Marvell's evaluation boards for the 98DX4251 and
98DX3336 SoCs.

Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
---
Chaqnges in v2:
- None

 arch/arm/boot/dts/db-dxbc2.dts      | 159 ++++++++++++++++++++++++++++++++++++
 arch/arm/boot/dts/db-xc3-24g4xg.dts | 155 +++++++++++++++++++++++++++++++++++
 2 files changed, 314 insertions(+)
 create mode 100644 arch/arm/boot/dts/db-dxbc2.dts
 create mode 100644 arch/arm/boot/dts/db-xc3-24g4xg.dts

diff --git a/arch/arm/boot/dts/db-dxbc2.dts b/arch/arm/boot/dts/db-dxbc2.dts
new file mode 100644
index 000000000000..f56786cea5f8
--- /dev/null
+++ b/arch/arm/boot/dts/db-dxbc2.dts
@@ -0,0 +1,159 @@
+/*
+ * Device Tree file for DB-DXBC2 board
+ *
+ * Copyright (C) 2016 Allied Telesis Labs
+ *
+ * Based on armada-xp-db.dts
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file 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 file 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.
+ *
+ * Or, alternatively
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Note: this Device Tree assumes that the bootloader has remapped the
+ * internal registers to 0xf1000000 (instead of the default
+ * 0xd0000000). The 0xf1000000 is the default used by the recent,
+ * DT-capable, U-Boot bootloaders provided by Marvell. Some earlier
+ * boards were delivered with an older version of the bootloader that
+ * left internal registers mapped at 0xd0000000. If you are in this
+ * situation, you should either update your bootloader (preferred
+ * solution) or the below Device Tree should be adjusted.
+ */
+
+/dts-v1/;
+#include "armada-xp-98dx4251.dtsi"
+
+/ {
+	model = "Marvell Bobcat2 Evaluation Board";
+	compatible = "marvell,db-dxbc2", "marvell,armadaxp-98dx4251", "marvell,armadaxp", "marvell,armada-370-xp";
+
+	chosen {
+		bootargs = "console=ttyS0,115200 earlyprintk";
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0 0x00000000 0 0x20000000>; /* 512 MB */
+	};
+
+	soc {
+		ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000
+			  MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
+			  MBUS_ID(0x01, 0x2f) 0 0 0xf0000000 0x1000000
+			  MBUS_ID(0x03, 0x00) 0 0 0xa8000000 0x4000000
+			  MBUS_ID(0x08, 0x00) 0 0 0xac000000 0x100000>;
+
+		devbus-bootcs {
+			status = "okay";
+
+			/* Device Bus parameters are required */
+
+			/* Read parameters */
+			devbus,bus-width    = <16>;
+			devbus,turn-off-ps  = <60000>;
+			devbus,badr-skew-ps = <0>;
+			devbus,acc-first-ps = <124000>;
+			devbus,acc-next-ps  = <248000>;
+			devbus,rd-setup-ps  = <0>;
+			devbus,rd-hold-ps   = <0>;
+
+			/* Write parameters */
+			devbus,sync-enable = <0>;
+			devbus,wr-high-ps  = <60000>;
+			devbus,wr-low-ps   = <60000>;
+			devbus,ale-wr-ps   = <60000>;
+		};
+
+		internal-regs {
+			serial at 12000 {
+				status = "okay";
+			};
+			serial at 12100 {
+				status = "okay";
+			};
+
+			i2c at 11000 {
+				clock-frequency = <100000>;
+				status = "okay";
+			};
+
+			mvsdio at d4000 {
+				pinctrl-0 = <&sdio_pins>;
+				pinctrl-names = "default";
+				status = "okay";
+				/* No CD or WP GPIOs */
+				broken-cd;
+			};
+
+			nand at d0000 {
+				status = "okay";
+				num-cs = <1>;
+				marvell,nand-keep-config;
+				marvell,nand-enable-arbiter;
+				nand-on-flash-bbt;
+				nand-ecc-strength = <4>;
+				nand-ecc-step-size = <512>;
+			};
+		};
+	};
+};
+
+&spi0 {
+	status = "okay";
+
+	spi-flash at 0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "m25p64";
+		reg = <0>; /* Chip select 0 */
+		spi-max-frequency = <20000000>;
+		m25p,fast-read;
+
+		partition at u-boot {
+			reg = <0x00000000 0x00100000>;
+			label = "u-boot";
+		};
+		partition at u-boot-env {
+			reg = <0x00100000 0x00040000>;
+			label = "u-boot-env";
+		};
+		partition at unused {
+			reg = <0x00140000 0x00ec0000>;
+			label = "unused";
+		};
+
+	};
+};
diff --git a/arch/arm/boot/dts/db-xc3-24g4xg.dts b/arch/arm/boot/dts/db-xc3-24g4xg.dts
new file mode 100644
index 000000000000..5eb89ffb9a7d
--- /dev/null
+++ b/arch/arm/boot/dts/db-xc3-24g4xg.dts
@@ -0,0 +1,155 @@
+/*
+ * Device Tree file for DB-XC3-24G4XG board
+ *
+ * Copyright (C) 2016 Allied Telesis Labs
+ *
+ * Based on armada-xp-db.dts
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file 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 file 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.
+ *
+ * Or, alternatively
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Note: this Device Tree assumes that the bootloader has remapped the
+ * internal registers to 0xf1000000 (instead of the default
+ * 0xd0000000). The 0xf1000000 is the default used by the recent,
+ * DT-capable, U-Boot bootloaders provided by Marvell. Some earlier
+ * boards were delivered with an older version of the bootloader that
+ * left internal registers mapped at 0xd0000000. If you are in this
+ * situation, you should either update your bootloader (preferred
+ * solution) or the below Device Tree should be adjusted.
+ */
+
+/dts-v1/;
+#include "armada-xp-98dx3336.dtsi"
+
+/ {
+	model = "DB-XC3-24G4XG";
+	compatible = "marvell,db-xc3-24g4xg", "marvell,armadaxp-98dx3336", "marvell,armadaxp", "marvell,armada-370-xp";
+
+	chosen {
+		bootargs = "console=ttyS0,115200 earlyprintk";
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0 0x00000000 0 0x40000000>; /* 1 GB */
+	};
+
+	soc {
+		ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000
+			  MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
+			  MBUS_ID(0x01, 0x2f) 0 0 0xf0000000 0x1000000
+			  MBUS_ID(0x03, 0x00) 0 0 0xa8000000 0x4000000
+			  MBUS_ID(0x08, 0x00) 0 0 0xac000000 0x100000>;
+
+		devbus-bootcs {
+			status = "okay";
+
+			/* Device Bus parameters are required */
+
+			/* Read parameters */
+			devbus,bus-width    = <16>;
+			devbus,turn-off-ps  = <60000>;
+			devbus,badr-skew-ps = <0>;
+			devbus,acc-first-ps = <124000>;
+			devbus,acc-next-ps  = <248000>;
+			devbus,rd-setup-ps  = <0>;
+			devbus,rd-hold-ps   = <0>;
+
+			/* Write parameters */
+			devbus,sync-enable = <0>;
+			devbus,wr-high-ps  = <60000>;
+			devbus,wr-low-ps   = <60000>;
+			devbus,ale-wr-ps   = <60000>;
+		};
+
+		internal-regs {
+			serial at 12000 {
+				status = "okay";
+			};
+			serial at 12100 {
+				status = "okay";
+			};
+
+			i2c at 11000 {
+				clock-frequency = <100000>;
+				status = "okay";
+			};
+
+			mvsdio at d4000 {
+				status = "disabled";
+			};
+
+			nand at d0000 {
+				status = "okay";
+				num-cs = <1>;
+				marvell,nand-keep-config;
+				marvell,nand-enable-arbiter;
+				nand-on-flash-bbt;
+				nand-ecc-strength = <4>;
+				nand-ecc-step-size = <512>;
+			};
+		};
+	};
+};
+
+&spi0 {
+	status = "okay";
+
+	spi-flash at 0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "m25p64";
+		reg = <0>; /* Chip select 0 */
+		spi-max-frequency = <20000000>;
+		m25p,fast-read;
+
+		partition at u-boot {
+			reg = <0x00000000 0x00100000>;
+			label = "u-boot";
+		};
+		partition at u-boot-env {
+			reg = <0x00100000 0x00040000>;
+			label = "u-boot-env";
+		};
+		partition at unused {
+			reg = <0x00140000 0x00ec0000>;
+			label = "unused";
+		};
+
+	};
+};
-- 
2.11.0.24.ge6920cf

^ permalink raw reply related

* [QUESTION] Arm64: Query L3 cache info via DT
From: Tan Xiaojun @ 2017-01-05  3:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <81784854-11f8-468a-a280-69be0a714a3b@arm.com>

OK. Thank you very much. I will try it in my arm64 board.

Xiaojun.

On 2017/1/4 19:47, Sudeep Holla wrote:
> 
> Hi Tan,
> 
> On 28/12/16 03:42, Tan Xiaojun wrote:
>> Hi.
>>
>> I saw you discussed how to achieve querying cache information and
>> tend to implement the external ones(like L3 cache) via DT a few
>> months ago.
>>
>> http://lists.infradead.org/pipermail/linux-arm-kernel/2016-February/405399.html
>>
>>  Are these implementations progressing? Forgive me to take the
>> liberty to ask, we care about this thing.
>>
> 
> Yes the support to override the cache properties for DT was added in v4.10
> 
> However, it still depends on the the sysreg to get the total levels of
> caches supported in the system. You may need to tweak a bit around that
> to support what you need.
> 
>> If you've already implemented some codes, we can help with testing
>> (in Hisilicon D02, D03, D05) after you send it to the mail-list.
>>
> 
> Sure, that would help.
> 
>> We can try our best to help if there is any difficulty.
> 
> OK, you can start trying the patch below :). It's not even compile
> tested, so you make have to make some changes necessary. I just wanted
> to put my thoughts here. Make sure all the L3 cacheinfo is present in DT.
> 
> Regards,
> Sudeep
> 
> 
> --
> 
> diff --git i/arch/arm64/kernel/cacheinfo.c w/arch/arm64/kernel/cacheinfo.c
> index 9617301f76b5..88fbcd368104 100644
> --- i/arch/arm64/kernel/cacheinfo.c
> +++ w/arch/arm64/kernel/cacheinfo.c
> @@ -84,7 +84,7 @@ static void ci_leaf_init(struct cacheinfo *this_leaf,
> 
>  static int __init_cache_level(unsigned int cpu)
>  {
> -	unsigned int ctype, level, leaves;
> +	unsigned int ctype, level, leaves, of_level;
>  	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
> 
>  	for (level = 1, leaves = 0; level <= MAX_CACHE_LEVEL; level++) {
> @@ -97,6 +97,17 @@ static int __init_cache_level(unsigned int cpu)
>  		leaves += (ctype == CACHE_TYPE_SEPARATE) ? 2 : 1;
>  	}
> 
> +	of_level = of_count_cache_levels(cpu);
> +	if (level < of_level) {
> +		/*
> +		 * some external caches not specified in CLIDR_EL1
> +		 * the information may be available in the device tree
> +		 * only unified external caches are considered here
> +		 */
> +		level = of_level;
> +		leaves += (of_level - level);
> +	}
> +
>  	this_cpu_ci->num_levels = level;
>  	this_cpu_ci->num_leaves = leaves;
>  	return 0;
> diff --git i/drivers/of/base.c w/drivers/of/base.c
> index d4bea3c797d6..8007f3b06cb8 100644
> --- i/drivers/of/base.c
> +++ w/drivers/of/base.c
> @@ -2267,6 +2267,20 @@ struct device_node *of_find_next_cache_node(const
> struct device_node *np)
>  	return NULL;
>  }
> 
> +int of_count_cache_levels(unsigned int cpu)
> +{
> +	int level = 0;
> +	struct device *cpu_dev = get_cpu_device(cpu);
> +	struct device_node *np = cpu_dev->of_node;
> +
> +	while (np) {
> +		level++;
> +		np = of_find_next_cache_node(np);
> +	}
> +
> +	return level;
> +}
> +
>  /**
>   * of_graph_parse_endpoint() - parse common endpoint node properties
>   * @node: pointer to endpoint device_node
> diff --git i/include/linux/of.h w/include/linux/of.h
> index d72f01009297..c8597ae71ff3 100644
> --- i/include/linux/of.h
> +++ w/include/linux/of.h
> @@ -280,6 +280,7 @@ extern struct device_node
> *of_get_child_by_name(const struct device_node *node,
> 
>  /* cache lookup */
>  extern struct device_node *of_find_next_cache_node(const struct
> device_node *);
> +extern int of_count_cache_levels(unsigned int cpu);
>  extern struct device_node *of_find_node_with_property(
>  	struct device_node *from, const char *prop_name);
> 
> 
> .
> 

^ permalink raw reply

* [PATCH v2] PCI: exynos: refactor exynos pcie driver
From: Pankaj Dubey @ 2017-01-05  3:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CGME20170105035104epcas1p2de6c52e577dd78a4f3539fb32d1f0dfe@epcas1p2.samsung.com>

From: Niyas Ahmed S T <niyas.ahmed@samsung.com>

Currently Exynos PCIe driver is only supported for Exynos5440 SoC.
This patch does refactoring of Exynos PCIe driver to extend support
for other Exynos SoC.

Following are the main changes done via this patch:

1) It adds separate structs for memory, clock resources.

Reason behind this change is, moving ahead various Exynos SoC will
have different hardware resources such as iomem, clocks, regmap handles
etc. for PCIe controller, so keeping these resources in separate struct
will help us in intiailizing them via per SoC ops, and will avoid too
many of_machine_is_compatible in code, and help us simplifying
exynos_pcie struct.

2) It add exynos_pcie_ops struct which will allow us to support the
differences in resources in different Exynos SoC.

No functional change intended.

Signed-off-by: Niyas Ahmed S T <niyas.ahmed@samsung.com>
Signed-off-by: Pankaj Dubey <pankaj.dubey@samsung.com>
Acked-by: Krzysztof Kozlowski <krzk@kernel.org>
Reviewed-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
---
This patch set is prepared on top of Krzysztof's for-next and
PCIe driver cleanup patch [1] by Jaehoon Chung.

[1]: https://lkml.org/lkml/2016/12/19/44

Changes from v1:
 - Addressed review comments from Krzysztof and Jingoo Han.

 drivers/pci/host/pci-exynos.c | 348 ++++++++++++++++++++++++++----------------
 1 file changed, 219 insertions(+), 129 deletions(-)

diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-exynos.c
index 33562cf..d91751b 100644
--- a/drivers/pci/host/pci-exynos.c
+++ b/drivers/pci/host/pci-exynos.c
@@ -17,6 +17,7 @@
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/of_device.h>
 #include <linux/of_gpio.h>
 #include <linux/pci.h>
 #include <linux/platform_device.h>
@@ -28,16 +29,6 @@
 
 #define to_exynos_pcie(x)	container_of(x, struct exynos_pcie, pp)
 
-struct exynos_pcie {
-	struct pcie_port	pp;
-	void __iomem		*elbi_base;	/* DT 0th resource */
-	void __iomem		*phy_base;	/* DT 1st resource */
-	void __iomem		*block_base;	/* DT 2nd resource */
-	int			reset_gpio;
-	struct clk		*clk;
-	struct clk		*bus_clk;
-};
-
 /* PCIe ELBI registers */
 #define PCIE_IRQ_PULSE			0x000
 #define IRQ_INTA_ASSERT			BIT(0)
@@ -102,6 +93,122 @@ struct exynos_pcie {
 #define PCIE_PHY_TRSV3_PD_TSV		BIT(7)
 #define PCIE_PHY_TRSV3_LVCC		0x31c
 
+struct exynos_pcie_mem_res {
+	void __iomem *elbi_base; /* DT 0th resource: PCIE CTRL */
+	void __iomem *phy_base; /* DT 1st resource: PHY CTRL */
+	void __iomem *block_base; /* DT 2nd resource: PHY ADDITIONAL CTRL */
+};
+
+struct exynos_pcie_clk_res {
+	struct clk *clk;
+	struct clk *bus_clk;
+};
+
+struct exynos_pcie {
+	struct pcie_port		pp;
+	struct exynos_pcie_mem_res	*mem_res;
+	struct exynos_pcie_clk_res	*clk_res;
+	const struct exynos_pcie_ops	*ops;
+	int				reset_gpio;
+};
+
+struct exynos_pcie_ops {
+	int (*get_mem_resources)(struct platform_device *pdev,
+			struct exynos_pcie *ep);
+	int (*get_clk_resources)(struct exynos_pcie *ep);
+	int (*init_clk_resources)(struct exynos_pcie *ep);
+	void (*deinit_clk_resources)(struct exynos_pcie *ep);
+};
+
+static int exynos5440_pcie_get_mem_resources(struct platform_device *pdev,
+						struct exynos_pcie *ep)
+{
+	struct resource *res;
+	struct device *dev = ep->pp.dev;
+
+	ep->mem_res = devm_kzalloc(dev, sizeof(*ep->mem_res), GFP_KERNEL);
+	if (!ep->mem_res)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	ep->mem_res->elbi_base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(ep->mem_res->elbi_base))
+		return PTR_ERR(ep->mem_res->elbi_base);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	ep->mem_res->phy_base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(ep->mem_res->phy_base))
+		return PTR_ERR(ep->mem_res->phy_base);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	ep->mem_res->block_base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(ep->mem_res->block_base))
+		return PTR_ERR(ep->mem_res->block_base);
+
+	return 0;
+}
+
+static int exynos5440_pcie_get_clk_resources(struct exynos_pcie *ep)
+{
+	struct device *dev = ep->pp.dev;
+
+	ep->clk_res = devm_kzalloc(dev, sizeof(*ep->clk_res), GFP_KERNEL);
+	if (!ep->clk_res)
+		return -ENOMEM;
+
+	ep->clk_res->clk = devm_clk_get(dev, "pcie");
+	if (IS_ERR(ep->clk_res->clk)) {
+		dev_err(dev, "Failed to get pcie rc clock\n");
+		return PTR_ERR(ep->clk_res->clk);
+	}
+
+	ep->clk_res->bus_clk = devm_clk_get(dev, "pcie_bus");
+	if (IS_ERR(ep->clk_res->bus_clk)) {
+		dev_err(dev, "Failed to get pcie bus clock\n");
+		return PTR_ERR(ep->clk_res->bus_clk);
+	}
+
+	return 0;
+}
+
+static int exynos5440_pcie_init_clk_resources(struct exynos_pcie *ep)
+{
+	struct device *dev = ep->pp.dev;
+	int ret;
+
+	ret = clk_prepare_enable(ep->clk_res->clk);
+	if (ret) {
+		dev_err(dev, "cannot enable pcie rc clock");
+		return ret;
+	}
+
+	ret = clk_prepare_enable(ep->clk_res->bus_clk);
+	if (ret) {
+		dev_err(dev, "cannot enable pcie bus clock");
+		goto err_bus_clk;
+	}
+
+	return 0;
+
+err_bus_clk:
+	clk_disable_unprepare(ep->clk_res->clk);
+
+	return ret;
+}
+
+static void exynos5440_pcie_deinit_clk_resources(struct exynos_pcie *ep)
+{
+	clk_disable_unprepare(ep->clk_res->bus_clk);
+	clk_disable_unprepare(ep->clk_res->clk);
+}
+
+static const struct exynos_pcie_ops exynos5440_pcie_ops = {
+	.get_mem_resources	= exynos5440_pcie_get_mem_resources,
+	.get_clk_resources	= exynos5440_pcie_get_clk_resources,
+	.init_clk_resources	= exynos5440_pcie_init_clk_resources,
+	.deinit_clk_resources	= exynos5440_pcie_deinit_clk_resources,
+};
+
 static void exynos_pcie_writel(void __iomem *base, u32 val, u32 reg)
 {
 	writel(val, base + reg);
@@ -116,155 +223,155 @@ static void exynos_pcie_sideband_dbi_w_mode(struct exynos_pcie *ep, bool on)
 {
 	u32 val;
 
-	val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_AWMISC);
+	val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_SLV_AWMISC);
 	if (on)
 		val |= PCIE_ELBI_SLV_DBI_ENABLE;
 	else
 		val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
-	exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_AWMISC);
+	exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_ELBI_SLV_AWMISC);
 }
 
 static void exynos_pcie_sideband_dbi_r_mode(struct exynos_pcie *ep, bool on)
 {
 	u32 val;
 
-	val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_ARMISC);
+	val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_SLV_ARMISC);
 	if (on)
 		val |= PCIE_ELBI_SLV_DBI_ENABLE;
 	else
 		val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
-	exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_ARMISC);
+	exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_ELBI_SLV_ARMISC);
 }
 
 static void exynos_pcie_assert_core_reset(struct exynos_pcie *ep)
 {
 	u32 val;
 
-	val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET);
+	val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_CORE_RESET);
 	val &= ~PCIE_CORE_RESET_ENABLE;
-	exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET);
-	exynos_pcie_writel(ep->elbi_base, 0, PCIE_PWR_RESET);
-	exynos_pcie_writel(ep->elbi_base, 0, PCIE_STICKY_RESET);
-	exynos_pcie_writel(ep->elbi_base, 0, PCIE_NONSTICKY_RESET);
+	exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_CORE_RESET);
+	exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_PWR_RESET);
+	exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_STICKY_RESET);
+	exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_NONSTICKY_RESET);
 }
 
 static void exynos_pcie_deassert_core_reset(struct exynos_pcie *ep)
 {
 	u32 val;
 
-	val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET);
+	val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_CORE_RESET);
 	val |= PCIE_CORE_RESET_ENABLE;
 
-	exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET);
-	exynos_pcie_writel(ep->elbi_base, 1, PCIE_STICKY_RESET);
-	exynos_pcie_writel(ep->elbi_base, 1, PCIE_NONSTICKY_RESET);
-	exynos_pcie_writel(ep->elbi_base, 1, PCIE_APP_INIT_RESET);
-	exynos_pcie_writel(ep->elbi_base, 0, PCIE_APP_INIT_RESET);
-	exynos_pcie_writel(ep->block_base, 1, PCIE_PHY_MAC_RESET);
+	exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_CORE_RESET);
+	exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_STICKY_RESET);
+	exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_NONSTICKY_RESET);
+	exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_APP_INIT_RESET);
+	exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_APP_INIT_RESET);
+	exynos_pcie_writel(ep->mem_res->block_base, 1, PCIE_PHY_MAC_RESET);
 }
 
 static void exynos_pcie_assert_phy_reset(struct exynos_pcie *ep)
 {
-	exynos_pcie_writel(ep->block_base, 0, PCIE_PHY_MAC_RESET);
-	exynos_pcie_writel(ep->block_base, 1, PCIE_PHY_GLOBAL_RESET);
+	exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_MAC_RESET);
+	exynos_pcie_writel(ep->mem_res->block_base, 1, PCIE_PHY_GLOBAL_RESET);
 }
 
 static void exynos_pcie_deassert_phy_reset(struct exynos_pcie *ep)
 {
-	exynos_pcie_writel(ep->block_base, 0, PCIE_PHY_GLOBAL_RESET);
-	exynos_pcie_writel(ep->elbi_base, 1, PCIE_PWR_RESET);
-	exynos_pcie_writel(ep->block_base, 0, PCIE_PHY_COMMON_RESET);
-	exynos_pcie_writel(ep->block_base, 0, PCIE_PHY_CMN_REG);
-	exynos_pcie_writel(ep->block_base, 0, PCIE_PHY_TRSVREG_RESET);
-	exynos_pcie_writel(ep->block_base, 0, PCIE_PHY_TRSV_RESET);
+	exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_GLOBAL_RESET);
+	exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_PWR_RESET);
+	exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_COMMON_RESET);
+	exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_CMN_REG);
+	exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_TRSVREG_RESET);
+	exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_TRSV_RESET);
 }
 
 static void exynos_pcie_power_on_phy(struct exynos_pcie *ep)
 {
 	u32 val;
 
-	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_COMMON_POWER);
+	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_COMMON_POWER);
 	val &= ~PCIE_PHY_COMMON_PD_CMN;
-	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_COMMON_POWER);
+	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_COMMON_POWER);
 
-	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV0_POWER);
+	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV0_POWER);
 	val &= ~PCIE_PHY_TRSV0_PD_TSV;
-	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV0_POWER);
+	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV0_POWER);
 
-	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV1_POWER);
+	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV1_POWER);
 	val &= ~PCIE_PHY_TRSV1_PD_TSV;
-	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV1_POWER);
+	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV1_POWER);
 
-	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV2_POWER);
+	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV2_POWER);
 	val &= ~PCIE_PHY_TRSV2_PD_TSV;
-	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV2_POWER);
+	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV2_POWER);
 
-	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV3_POWER);
+	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV3_POWER);
 	val &= ~PCIE_PHY_TRSV3_PD_TSV;
-	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV3_POWER);
+	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV3_POWER);
 }
 
 static void exynos_pcie_power_off_phy(struct exynos_pcie *ep)
 {
 	u32 val;
 
-	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_COMMON_POWER);
+	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_COMMON_POWER);
 	val |= PCIE_PHY_COMMON_PD_CMN;
-	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_COMMON_POWER);
+	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_COMMON_POWER);
 
-	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV0_POWER);
+	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV0_POWER);
 	val |= PCIE_PHY_TRSV0_PD_TSV;
-	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV0_POWER);
+	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV0_POWER);
 
-	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV1_POWER);
+	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV1_POWER);
 	val |= PCIE_PHY_TRSV1_PD_TSV;
-	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV1_POWER);
+	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV1_POWER);
 
-	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV2_POWER);
+	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV2_POWER);
 	val |= PCIE_PHY_TRSV2_PD_TSV;
-	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV2_POWER);
+	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV2_POWER);
 
-	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV3_POWER);
+	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV3_POWER);
 	val |= PCIE_PHY_TRSV3_PD_TSV;
-	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV3_POWER);
+	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV3_POWER);
 }
 
 static void exynos_pcie_init_phy(struct exynos_pcie *ep)
 {
 	/* DCC feedback control off */
-	exynos_pcie_writel(ep->phy_base, 0x29, PCIE_PHY_DCC_FEEDBACK);
+	exynos_pcie_writel(ep->mem_res->phy_base, 0x29, PCIE_PHY_DCC_FEEDBACK);
 
 	/* set TX/RX impedance */
-	exynos_pcie_writel(ep->phy_base, 0xd5, PCIE_PHY_IMPEDANCE);
+	exynos_pcie_writel(ep->mem_res->phy_base, 0xd5, PCIE_PHY_IMPEDANCE);
 
 	/* set 50Mhz PHY clock */
-	exynos_pcie_writel(ep->phy_base, 0x14, PCIE_PHY_PLL_DIV_0);
-	exynos_pcie_writel(ep->phy_base, 0x12, PCIE_PHY_PLL_DIV_1);
+	exynos_pcie_writel(ep->mem_res->phy_base, 0x14, PCIE_PHY_PLL_DIV_0);
+	exynos_pcie_writel(ep->mem_res->phy_base, 0x12, PCIE_PHY_PLL_DIV_1);
 
 	/* set TX Differential output for lane 0 */
-	exynos_pcie_writel(ep->phy_base, 0x7f, PCIE_PHY_TRSV0_DRV_LVL);
+	exynos_pcie_writel(ep->mem_res->phy_base, 0x7f, PCIE_PHY_TRSV0_DRV_LVL);
 
 	/* set TX Pre-emphasis Level Control for lane 0 to minimum */
-	exynos_pcie_writel(ep->phy_base, 0x0, PCIE_PHY_TRSV0_EMP_LVL);
+	exynos_pcie_writel(ep->mem_res->phy_base, 0x0, PCIE_PHY_TRSV0_EMP_LVL);
 
 	/* set RX clock and data recovery bandwidth */
-	exynos_pcie_writel(ep->phy_base, 0xe7, PCIE_PHY_PLL_BIAS);
-	exynos_pcie_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV0_RXCDR);
-	exynos_pcie_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV1_RXCDR);
-	exynos_pcie_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV2_RXCDR);
-	exynos_pcie_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV3_RXCDR);
+	exynos_pcie_writel(ep->mem_res->phy_base, 0xe7, PCIE_PHY_PLL_BIAS);
+	exynos_pcie_writel(ep->mem_res->phy_base, 0x82, PCIE_PHY_TRSV0_RXCDR);
+	exynos_pcie_writel(ep->mem_res->phy_base, 0x82, PCIE_PHY_TRSV1_RXCDR);
+	exynos_pcie_writel(ep->mem_res->phy_base, 0x82, PCIE_PHY_TRSV2_RXCDR);
+	exynos_pcie_writel(ep->mem_res->phy_base, 0x82, PCIE_PHY_TRSV3_RXCDR);
 
 	/* change TX Pre-emphasis Level Control for lanes */
-	exynos_pcie_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV0_EMP_LVL);
-	exynos_pcie_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV1_EMP_LVL);
-	exynos_pcie_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV2_EMP_LVL);
-	exynos_pcie_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV3_EMP_LVL);
+	exynos_pcie_writel(ep->mem_res->phy_base, 0x39, PCIE_PHY_TRSV0_EMP_LVL);
+	exynos_pcie_writel(ep->mem_res->phy_base, 0x39, PCIE_PHY_TRSV1_EMP_LVL);
+	exynos_pcie_writel(ep->mem_res->phy_base, 0x39, PCIE_PHY_TRSV2_EMP_LVL);
+	exynos_pcie_writel(ep->mem_res->phy_base, 0x39, PCIE_PHY_TRSV3_EMP_LVL);
 
 	/* set LVCC */
-	exynos_pcie_writel(ep->phy_base, 0x20, PCIE_PHY_TRSV0_LVCC);
-	exynos_pcie_writel(ep->phy_base, 0xa0, PCIE_PHY_TRSV1_LVCC);
-	exynos_pcie_writel(ep->phy_base, 0xa0, PCIE_PHY_TRSV2_LVCC);
-	exynos_pcie_writel(ep->phy_base, 0xa0, PCIE_PHY_TRSV3_LVCC);
+	exynos_pcie_writel(ep->mem_res->phy_base, 0x20, PCIE_PHY_TRSV0_LVCC);
+	exynos_pcie_writel(ep->mem_res->phy_base, 0xa0, PCIE_PHY_TRSV1_LVCC);
+	exynos_pcie_writel(ep->mem_res->phy_base, 0xa0, PCIE_PHY_TRSV2_LVCC);
+	exynos_pcie_writel(ep->mem_res->phy_base, 0xa0, PCIE_PHY_TRSV3_LVCC);
 }
 
 static void exynos_pcie_assert_reset(struct exynos_pcie *exynos_pcie)
@@ -295,25 +402,27 @@ static int exynos_pcie_establish_link(struct exynos_pcie *exynos_pcie)
 	exynos_pcie_init_phy(exynos_pcie);
 
 	/* pulse for common reset */
-	exynos_pcie_writel(exynos_pcie->block_base, 1, PCIE_PHY_COMMON_RESET);
+	exynos_pcie_writel(exynos_pcie->mem_res->block_base, 1,
+				PCIE_PHY_COMMON_RESET);
 	udelay(500);
-	exynos_pcie_writel(exynos_pcie->block_base, 0, PCIE_PHY_COMMON_RESET);
+	exynos_pcie_writel(exynos_pcie->mem_res->block_base, 0,
+				PCIE_PHY_COMMON_RESET);
 
 	exynos_pcie_deassert_core_reset(exynos_pcie);
 	dw_pcie_setup_rc(pp);
 	exynos_pcie_assert_reset(exynos_pcie);
 
 	/* assert LTSSM enable */
-	exynos_pcie_writel(exynos_pcie->elbi_base, PCIE_ELBI_LTSSM_ENABLE,
-			  PCIE_APP_LTSSM_ENABLE);
+	exynos_pcie_writel(exynos_pcie->mem_res->elbi_base,
+			PCIE_ELBI_LTSSM_ENABLE, PCIE_APP_LTSSM_ENABLE);
 
 	/* check if the link is up or not */
 	if (!dw_pcie_wait_for_link(pp))
 		return 0;
 
-	while (exynos_pcie_readl(exynos_pcie->phy_base,
+	while (exynos_pcie_readl(exynos_pcie->mem_res->phy_base,
 				PCIE_PHY_PLL_LOCKED) == 0) {
-		val = exynos_pcie_readl(exynos_pcie->block_base,
+		val = exynos_pcie_readl(exynos_pcie->mem_res->block_base,
 				PCIE_PHY_PLL_LOCKED);
 		dev_info(dev, "PLL Locked: 0x%x\n", val);
 	}
@@ -325,8 +434,8 @@ static void exynos_pcie_clear_irq_pulse(struct exynos_pcie *ep)
 {
 	u32 val;
 
-	val = exynos_pcie_readl(ep->elbi_base, PCIE_IRQ_PULSE);
-	exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_PULSE);
+	val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_IRQ_PULSE);
+	exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_PULSE);
 }
 
 static void exynos_pcie_enable_irq_pulse(struct exynos_pcie *ep)
@@ -336,7 +445,7 @@ static void exynos_pcie_enable_irq_pulse(struct exynos_pcie *ep)
 	/* enable INTX interrupt */
 	val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT |
 		IRQ_INTC_ASSERT | IRQ_INTD_ASSERT;
-	exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_EN_PULSE);
+	exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_EN_PULSE);
 }
 
 static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg)
@@ -363,9 +472,9 @@ static void exynos_pcie_msi_init(struct exynos_pcie *ep)
 	dw_pcie_msi_init(pp);
 
 	/* enable MSI interrupt */
-	val = exynos_pcie_readl(ep->elbi_base, PCIE_IRQ_EN_LEVEL);
+	val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_IRQ_EN_LEVEL);
 	val |= IRQ_MSI_ENABLE;
-	exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_EN_LEVEL);
+	exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_EN_LEVEL);
 }
 
 static void exynos_pcie_enable_interrupts(struct exynos_pcie *exynos_pcie)
@@ -425,7 +534,8 @@ static int exynos_pcie_link_up(struct pcie_port *pp)
 	struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
 	u32 val;
 
-	val = exynos_pcie_readl(exynos_pcie->elbi_base, PCIE_ELBI_RDLH_LINKUP);
+	val = exynos_pcie_readl(exynos_pcie->mem_res->elbi_base,
+					PCIE_ELBI_RDLH_LINKUP);
 	if (val == PCIE_ELBI_LTSSM_ENABLE)
 		return 1;
 
@@ -503,7 +613,6 @@ static int __init exynos_pcie_probe(struct platform_device *pdev)
 	struct exynos_pcie *exynos_pcie;
 	struct pcie_port *pp;
 	struct device_node *np = dev->of_node;
-	struct resource *res;
 	int ret;
 
 	exynos_pcie = devm_kzalloc(dev, sizeof(*exynos_pcie), GFP_KERNEL);
@@ -513,59 +622,37 @@ static int __init exynos_pcie_probe(struct platform_device *pdev)
 	pp = &exynos_pcie->pp;
 	pp->dev = dev;
 
-	exynos_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
-
-	exynos_pcie->clk = devm_clk_get(dev, "pcie");
-	if (IS_ERR(exynos_pcie->clk)) {
-		dev_err(dev, "Failed to get pcie rc clock\n");
-		return PTR_ERR(exynos_pcie->clk);
-	}
-	ret = clk_prepare_enable(exynos_pcie->clk);
-	if (ret)
-		return ret;
+	exynos_pcie->ops = (const struct exynos_pcie_ops *)
+				of_device_get_match_data(dev);
 
-	exynos_pcie->bus_clk = devm_clk_get(dev, "pcie_bus");
-	if (IS_ERR(exynos_pcie->bus_clk)) {
-		dev_err(dev, "Failed to get pcie bus clock\n");
-		ret = PTR_ERR(exynos_pcie->bus_clk);
-		goto fail_clk;
-	}
-	ret = clk_prepare_enable(exynos_pcie->bus_clk);
-	if (ret)
-		goto fail_clk;
+	exynos_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	exynos_pcie->elbi_base = devm_ioremap_resource(dev, res);
-	if (IS_ERR(exynos_pcie->elbi_base)) {
-		ret = PTR_ERR(exynos_pcie->elbi_base);
-		goto fail_bus_clk;
+	if (exynos_pcie->ops && exynos_pcie->ops->get_mem_resources) {
+		ret = exynos_pcie->ops->get_mem_resources(pdev, exynos_pcie);
+		if (ret)
+			return ret;
 	}
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	exynos_pcie->phy_base = devm_ioremap_resource(dev, res);
-	if (IS_ERR(exynos_pcie->phy_base)) {
-		ret = PTR_ERR(exynos_pcie->phy_base);
-		goto fail_bus_clk;
-	}
+	if (exynos_pcie->ops && exynos_pcie->ops->get_clk_resources) {
+		ret = exynos_pcie->ops->get_clk_resources(exynos_pcie);
+		if (ret)
+			return ret;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
-	exynos_pcie->block_base = devm_ioremap_resource(dev, res);
-	if (IS_ERR(exynos_pcie->block_base)) {
-		ret = PTR_ERR(exynos_pcie->block_base);
-		goto fail_bus_clk;
+		ret = exynos_pcie->ops->init_clk_resources(exynos_pcie);
+		if (ret)
+			return ret;
 	}
 
 	ret = exynos_add_pcie_port(exynos_pcie, pdev);
 	if (ret < 0)
-		goto fail_bus_clk;
+		goto fail_probe;
 
 	platform_set_drvdata(pdev, exynos_pcie);
 	return 0;
 
-fail_bus_clk:
-	clk_disable_unprepare(exynos_pcie->bus_clk);
-fail_clk:
-	clk_disable_unprepare(exynos_pcie->clk);
+fail_probe:
+	if (exynos_pcie->ops && exynos_pcie->ops->deinit_clk_resources)
+		exynos_pcie->ops->deinit_clk_resources(exynos_pcie);
 	return ret;
 }
 
@@ -573,14 +660,17 @@ static int __exit exynos_pcie_remove(struct platform_device *pdev)
 {
 	struct exynos_pcie *exynos_pcie = platform_get_drvdata(pdev);
 
-	clk_disable_unprepare(exynos_pcie->bus_clk);
-	clk_disable_unprepare(exynos_pcie->clk);
+	if (exynos_pcie->ops && exynos_pcie->ops->deinit_clk_resources)
+		exynos_pcie->ops->deinit_clk_resources(exynos_pcie);
 
 	return 0;
 }
 
 static const struct of_device_id exynos_pcie_of_match[] = {
-	{ .compatible = "samsung,exynos5440-pcie", },
+	{
+		.compatible = "samsung,exynos5440-pcie",
+		.data = &exynos5440_pcie_ops
+	},
 	{},
 };
 
-- 
2.7.4

^ permalink raw reply related

* [PATCH v3] mfd: axp20x: Fix AXP806 access errors on cold boot
From: Chen-Yu Tsai @ 2017-01-05  4:01 UTC (permalink / raw)
  To: linux-arm-kernel

The AXP806 supports either master/standalone or slave mode.
Slave mode allows sharing the serial bus, even with multiple
AXP806 which all have the same hardware address.

This is done with extra "serial interface address extension",
or AXP806_BUS_ADDR_EXT, and "register address extension", or
AXP806_REG_ADDR_EXT, registers. The former is read-only, with
1 bit customizable at the factory, and 1 bit depending on the
state of an external pin. The latter is writable. Only when
the these device addressing bits (in the upper 4 bits of the
registers) match, will the device respond to operations on
its other registers.

The AXP806_REG_ADDR_EXT was previously configured by Allwinner's
bootloader. Work on U-boot SPL support now allows us to switch
to mainline U-boot, which doesn't do this for us. There might
be other bare minimum bootloaders out there which don't to this
either. It's best to handle this in the kernel.

This patch sets AXP806_REG_ADDR_EXT to 0x10, which is what we
know to be the proper value for a standard AXP806 in slave mode.
Afterwards it will reinitialize the regmap cache, to purge any
invalid stale values.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
Changes since v2:

  - Dropped regcache_sync_region() and regmap_reinit_cache() calls.
    The write immediately after getting the regmap from the caller
    of axp20x_device_probe() is enough.

  - Slightly rearranged a few sentences in the comment block.
---
 drivers/mfd/axp20x.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
index ed918de84238..81b9ddd10e6c 100644
--- a/drivers/mfd/axp20x.c
+++ b/drivers/mfd/axp20x.c
@@ -31,6 +31,8 @@
 
 #define AXP20X_OFF	0x80
 
+#define AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE	BIT(4)
+
 static const char * const axp20x_model_names[] = {
 	"AXP152",
 	"AXP202",
@@ -830,6 +832,30 @@ int axp20x_device_probe(struct axp20x_dev *axp20x)
 {
 	int ret;
 
+	/*
+	 * The AXP806 supports either master/standalone or slave mode.
+	 * Slave mode allows sharing the serial bus, even with multiple
+	 * AXP806 which all have the same hardware address.
+	 *
+	 * This is done with extra "serial interface address extension",
+	 * or AXP806_BUS_ADDR_EXT, and "register address extension", or
+	 * AXP806_REG_ADDR_EXT, registers. The former is read-only, with
+	 * 1 bit customizable at the factory, and 1 bit depending on the
+	 * state of an external pin. The latter is writable. The device
+	 * will only respond to operations to its other registers when
+	 * the these device addressing bits (in the upper 4 bits of the
+	 * registers) match.
+	 *
+	 * Since we only support an AXP806 chained to an AXP809 in slave
+	 * mode, and there isn't any existing hardware which uses AXP806
+	 * in master mode, or has 2 AXP806s in the same system, we can
+	 * just program the register address extension to the slave mode
+	 * address.
+	 */
+	if (axp20x->variant == AXP806_ID)
+		regmap_write(axp20x->regmap, AXP806_REG_ADDR_EXT,
+			     AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE);
+
 	ret = regmap_add_irq_chip(axp20x->regmap, axp20x->irq,
 				  IRQF_ONESHOT | IRQF_SHARED, -1,
 				  axp20x->regmap_irq_chip,
-- 
2.11.0

^ permalink raw reply related

* [PATCHv2 2/5] arm: mvebu: support for SMP on 98DX3336 SoC
From: Florian Fainelli @ 2017-01-05  4:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170105033641.6212-3-chris.packham@alliedtelesis.co.nz>

Le 01/04/17 ? 19:36, Chris Packham a ?crit :
> Compared to the armada-xp the 98DX3336 uses different registers to set
> the boot address for the secondary CPU so a new enable-method is needed.
> This will only work if the machine definition doesn't define an overall
> smp_ops because there is not currently a way of overriding this from the
> device tree if it is set in the machine definition.

Not sure I follow you here, in theory, each individual CPU could have a
different enable-method property, and considering how you leverage
existing DTS include files, you should be able to override the DTS with
the appropriate enable-method, or do you have a different problem?

 mv98dx3236_resume_set_cpu_boot_addr(int hw_cpu, void *boot_addr)
> +{
> +	WARN_ON(hw_cpu != 1);
> +
> +	writel(0, mv98dx3236_resume_base + MV98DX3236_CPU_RESUME_CTRL_OFFSET);
> +	writel(virt_to_phys(boot_addr), mv98dx3236_resume_base +
> +	       MV98DX3236_CPU_RESUME_ADDR_OFFSET);

I just submitted a patch series that switches such users to
__pa_symbol() instead of virt_to_phys() because this is a kernel image
symbol. For now this will work as-is, but depending on which patch
series makes it first, it may be a good idea to keep this on someone's
TODO list (yours or mine). I do expect having to make a second pass of
conversions anyway.

[1]: https://lkml.org/lkml/2017/1/4/1101

> +}
> +
> +static int __init mv98dx3236_resume_init(void)
> +{
> +	struct device_node *np;
> +	struct resource res;
> +	int ret = 0;
> +
> +	np = of_find_matching_node(NULL, of_mv98dx3236_resume_table);
> +	if (!np)
> +		return 0;
> +
> +	pr_info("Initializing 98DX3236 Resume\n");

This can be probably be dropped, you should know fairly quickly if this
succeeded or not.

Can't this function be implemented as a smp_ops::smp_init_cpus instead
of having this initialization done at arch_initcall time?

> +
> +	if (of_address_to_resource(np, 0, &res)) {
> +		pr_err("unable to get resource\n");
> +		ret = -ENOENT;
> +		goto out;
> +	}
> +
> +	if (!request_mem_region(res.start, resource_size(&res),
> +				np->full_name)) {
> +		pr_err("unable to request region\n");
> +		ret = -EBUSY;
> +		goto out;
> +	}

You should be able to use of_io_request_and_map() and here.
-- 
Florian

^ permalink raw reply

* [PATCH 01/22] dt-bindings: iio: adc: add AXP20X/AXP22X ADC DT binding
From: Chen-Yu Tsai @ 2017-01-05  4:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170103232035.wwsqmea5dxzu2r5m@rob-hp-laptop>

On Wed, Jan 4, 2017 at 7:20 AM, Rob Herring <robh@kernel.org> wrote:
> On Mon, Jan 02, 2017 at 05:37:01PM +0100, Quentin Schulz wrote:
>> The X-Powers AXP20X and AXP22X PMICs have multiple ADCs. They expose the
>> battery voltage, battery charge and discharge currents, AC-in and VBUS
>> voltages and currents, 2 GPIOs muxable in ADC mode and PMIC temperature.
>>
>> This adds the device tree binding documentation for the X-Powers AXP20X
>> and AXP22X PMICs ADCs.
>>
>> Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
>> ---
>>  .../devicetree/bindings/iio/adc/axp20x_adc.txt     | 24 ++++++++++++++++++++++
>>  1 file changed, 24 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/iio/adc/axp20x_adc.txt
>>
>> diff --git a/Documentation/devicetree/bindings/iio/adc/axp20x_adc.txt b/Documentation/devicetree/bindings/iio/adc/axp20x_adc.txt
>> new file mode 100644
>> index 0000000..1b60065
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/iio/adc/axp20x_adc.txt
>> @@ -0,0 +1,24 @@
>> +X-Powers AXP20X and AXP22X PMIC Analog to Digital Converter (ADC)
>> +
>> +The X-Powers AXP20X and AXP22X PMICs have multiple ADCs. They expose the
>> +battery voltage, battery charge and discharge currents, AC-in and VBUS
>> +voltages and currents, 2 GPIOs muxable in ADC mode and PMIC temperature.
>> +
>> +The AXP22X PMICs do not have all ADCs of the AXP20X though.
>> +
>> +Required properties:
>> + - compatible, one of:
>> +                     "x-powers,axp209-adc"
>> +                     "x-powers,axp221-adc"
>> + - #io-channel-cells = <1>;
>> +
>> +This is a subnode of the AXP20X PMIC.
>> +
>> +Example:
>> +
>> +&axp209 {
>> +     axp209_adc: axp209_adc {
>
> Use 'adc' for node name:
>
> With that,
>
> Acked-by: Rob Herring <robh@kernel.org>

Same comments as Rob.

Acked-by: Chen-Yu Tsai <wens@csie.org>

>
>> +             compatible = "x-powers,axp209-adc";
>> +             #io-channel-cells = <1>;
>> +     };
>> +};
>> --
>> 2.9.3
>>

^ permalink raw reply

* [PATCHv2 4/5] arm: mvebu: Add device tree for 98DX3236 SoCs
From: Florian Fainelli @ 2017-01-05  4:06 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170105033641.6212-5-chris.packham@alliedtelesis.co.nz>

Le 01/04/17 ? 19:36, Chris Packham a ?crit :
> The Marvell 98DX3236, 98DX3336, 98DX4521 and variants are switch ASICs
> with integrated CPUs. They are similar to the Armada XP SoCs but have
> different I/O interfaces.
> 
> Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
> ---
> +
> +		switch {
> +			packet-processor at 0 {
> +				compatible = "marvell,prestera-98dx4521";
> +			};
> +		};

This may be a bit premature if you are not providing a binding document
for this sub-node, you might as well add it once you also add a
corresponding driver (or if this will remain out of tree, at least
submitting a separate binding document).

Also, if this node's unit address is 0, you would expect at least a reg
property whose address cell is 0 to be present.
-- 
Florian

^ permalink raw reply

* [PATCHv2 0/5] Support for Marvell switches with integrated CPUs
From: Florian Fainelli @ 2017-01-05  4:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170105033641.6212-1-chris.packham@alliedtelesis.co.nz>

Le 01/04/17 ? 19:36, Chris Packham a ?crit :
> The 98DX3236, 98DX3336 and 98DX4251 are a set of switch ASICs with
> integrated CPUs. They CPU block is common within these product lines and
> (as far as I can tell/have been told) is based on the Armada XP. There
> are a few differences due to the fact they have to squeeze the CPU into
> the same package as the switch.

It's really great to see these changes, do you have a plan to also add
support for the integrated switch using a DSA/switchdev driver?

Thanks!
-- 
Florian

^ permalink raw reply

* [PATCH v2] PCI: exynos: refactor exynos pcie driver
From: Alim Akhtar @ 2017-01-05  4:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1483588418-2551-1-git-send-email-pankaj.dubey@samsung.com>

Hello Pankaj,

On 01/05/2017 09:23 AM, Pankaj Dubey wrote:
> From: Niyas Ahmed S T <niyas.ahmed@samsung.com>
>
> Currently Exynos PCIe driver is only supported for Exynos5440 SoC.
> This patch does refactoring of Exynos PCIe driver to extend support
> for other Exynos SoC.
>
> Following are the main changes done via this patch:
>
> 1) It adds separate structs for memory, clock resources.
>
> Reason behind this change is, moving ahead various Exynos SoC will
> have different hardware resources such as iomem, clocks, regmap handles
> etc. for PCIe controller, so keeping these resources in separate struct
> will help us in intiailizing them via per SoC ops, and will avoid too
> many of_machine_is_compatible in code, and help us simplifying
> exynos_pcie struct.
>
> 2) It add exynos_pcie_ops struct which will allow us to support the
> differences in resources in different Exynos SoC.
>
> No functional change intended.
>
> Signed-off-by: Niyas Ahmed S T <niyas.ahmed@samsung.com>
> Signed-off-by: Pankaj Dubey <pankaj.dubey@samsung.com>
> Acked-by: Krzysztof Kozlowski <krzk@kernel.org>
> Reviewed-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
> ---

Looks good.
Reviewed-by: Alim Akhtar <alim.akhtar@samsung.com>

> This patch set is prepared on top of Krzysztof's for-next and
> PCIe driver cleanup patch [1] by Jaehoon Chung.
>
> [1]: https://lkml.org/lkml/2016/12/19/44
>
> Changes from v1:
>  - Addressed review comments from Krzysztof and Jingoo Han.
>
>  drivers/pci/host/pci-exynos.c | 348 ++++++++++++++++++++++++++----------------
>  1 file changed, 219 insertions(+), 129 deletions(-)
>
> diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-exynos.c
> index 33562cf..d91751b 100644
> --- a/drivers/pci/host/pci-exynos.c
> +++ b/drivers/pci/host/pci-exynos.c
> @@ -17,6 +17,7 @@
>  #include <linux/interrupt.h>
>  #include <linux/kernel.h>
>  #include <linux/init.h>
> +#include <linux/of_device.h>
>  #include <linux/of_gpio.h>
>  #include <linux/pci.h>
>  #include <linux/platform_device.h>
> @@ -28,16 +29,6 @@
>
>  #define to_exynos_pcie(x)	container_of(x, struct exynos_pcie, pp)
>
> -struct exynos_pcie {
> -	struct pcie_port	pp;
> -	void __iomem		*elbi_base;	/* DT 0th resource */
> -	void __iomem		*phy_base;	/* DT 1st resource */
> -	void __iomem		*block_base;	/* DT 2nd resource */
> -	int			reset_gpio;
> -	struct clk		*clk;
> -	struct clk		*bus_clk;
> -};
> -
>  /* PCIe ELBI registers */
>  #define PCIE_IRQ_PULSE			0x000
>  #define IRQ_INTA_ASSERT			BIT(0)
> @@ -102,6 +93,122 @@ struct exynos_pcie {
>  #define PCIE_PHY_TRSV3_PD_TSV		BIT(7)
>  #define PCIE_PHY_TRSV3_LVCC		0x31c
>
> +struct exynos_pcie_mem_res {
> +	void __iomem *elbi_base; /* DT 0th resource: PCIE CTRL */
> +	void __iomem *phy_base; /* DT 1st resource: PHY CTRL */
> +	void __iomem *block_base; /* DT 2nd resource: PHY ADDITIONAL CTRL */
> +};
> +
> +struct exynos_pcie_clk_res {
> +	struct clk *clk;
> +	struct clk *bus_clk;
> +};
> +
> +struct exynos_pcie {
> +	struct pcie_port		pp;
> +	struct exynos_pcie_mem_res	*mem_res;
> +	struct exynos_pcie_clk_res	*clk_res;
> +	const struct exynos_pcie_ops	*ops;
> +	int				reset_gpio;
> +};
> +
> +struct exynos_pcie_ops {
> +	int (*get_mem_resources)(struct platform_device *pdev,
> +			struct exynos_pcie *ep);
> +	int (*get_clk_resources)(struct exynos_pcie *ep);
> +	int (*init_clk_resources)(struct exynos_pcie *ep);
> +	void (*deinit_clk_resources)(struct exynos_pcie *ep);
> +};
> +
> +static int exynos5440_pcie_get_mem_resources(struct platform_device *pdev,
> +						struct exynos_pcie *ep)
> +{
> +	struct resource *res;
> +	struct device *dev = ep->pp.dev;
> +
> +	ep->mem_res = devm_kzalloc(dev, sizeof(*ep->mem_res), GFP_KERNEL);
> +	if (!ep->mem_res)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	ep->mem_res->elbi_base = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(ep->mem_res->elbi_base))
> +		return PTR_ERR(ep->mem_res->elbi_base);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> +	ep->mem_res->phy_base = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(ep->mem_res->phy_base))
> +		return PTR_ERR(ep->mem_res->phy_base);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
> +	ep->mem_res->block_base = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(ep->mem_res->block_base))
> +		return PTR_ERR(ep->mem_res->block_base);
> +
> +	return 0;
> +}
> +
> +static int exynos5440_pcie_get_clk_resources(struct exynos_pcie *ep)
> +{
> +	struct device *dev = ep->pp.dev;
> +
> +	ep->clk_res = devm_kzalloc(dev, sizeof(*ep->clk_res), GFP_KERNEL);
> +	if (!ep->clk_res)
> +		return -ENOMEM;
> +
> +	ep->clk_res->clk = devm_clk_get(dev, "pcie");
> +	if (IS_ERR(ep->clk_res->clk)) {
> +		dev_err(dev, "Failed to get pcie rc clock\n");
> +		return PTR_ERR(ep->clk_res->clk);
> +	}
> +
> +	ep->clk_res->bus_clk = devm_clk_get(dev, "pcie_bus");
> +	if (IS_ERR(ep->clk_res->bus_clk)) {
> +		dev_err(dev, "Failed to get pcie bus clock\n");
> +		return PTR_ERR(ep->clk_res->bus_clk);
> +	}
> +
> +	return 0;
> +}
> +
> +static int exynos5440_pcie_init_clk_resources(struct exynos_pcie *ep)
> +{
> +	struct device *dev = ep->pp.dev;
> +	int ret;
> +
> +	ret = clk_prepare_enable(ep->clk_res->clk);
> +	if (ret) {
> +		dev_err(dev, "cannot enable pcie rc clock");
> +		return ret;
> +	}
> +
> +	ret = clk_prepare_enable(ep->clk_res->bus_clk);
> +	if (ret) {
> +		dev_err(dev, "cannot enable pcie bus clock");
> +		goto err_bus_clk;
> +	}
> +
> +	return 0;
> +
> +err_bus_clk:
> +	clk_disable_unprepare(ep->clk_res->clk);
> +
> +	return ret;
> +}
> +
> +static void exynos5440_pcie_deinit_clk_resources(struct exynos_pcie *ep)
> +{
> +	clk_disable_unprepare(ep->clk_res->bus_clk);
> +	clk_disable_unprepare(ep->clk_res->clk);
> +}
> +
> +static const struct exynos_pcie_ops exynos5440_pcie_ops = {
> +	.get_mem_resources	= exynos5440_pcie_get_mem_resources,
> +	.get_clk_resources	= exynos5440_pcie_get_clk_resources,
> +	.init_clk_resources	= exynos5440_pcie_init_clk_resources,
> +	.deinit_clk_resources	= exynos5440_pcie_deinit_clk_resources,
> +};
> +
>  static void exynos_pcie_writel(void __iomem *base, u32 val, u32 reg)
>  {
>  	writel(val, base + reg);
> @@ -116,155 +223,155 @@ static void exynos_pcie_sideband_dbi_w_mode(struct exynos_pcie *ep, bool on)
>  {
>  	u32 val;
>
> -	val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_AWMISC);
> +	val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_SLV_AWMISC);
>  	if (on)
>  		val |= PCIE_ELBI_SLV_DBI_ENABLE;
>  	else
>  		val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
> -	exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_AWMISC);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_ELBI_SLV_AWMISC);
>  }
>
>  static void exynos_pcie_sideband_dbi_r_mode(struct exynos_pcie *ep, bool on)
>  {
>  	u32 val;
>
> -	val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_ARMISC);
> +	val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_SLV_ARMISC);
>  	if (on)
>  		val |= PCIE_ELBI_SLV_DBI_ENABLE;
>  	else
>  		val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
> -	exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_ARMISC);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_ELBI_SLV_ARMISC);
>  }
>
>  static void exynos_pcie_assert_core_reset(struct exynos_pcie *ep)
>  {
>  	u32 val;
>
> -	val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET);
> +	val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_CORE_RESET);
>  	val &= ~PCIE_CORE_RESET_ENABLE;
> -	exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET);
> -	exynos_pcie_writel(ep->elbi_base, 0, PCIE_PWR_RESET);
> -	exynos_pcie_writel(ep->elbi_base, 0, PCIE_STICKY_RESET);
> -	exynos_pcie_writel(ep->elbi_base, 0, PCIE_NONSTICKY_RESET);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_CORE_RESET);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_PWR_RESET);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_STICKY_RESET);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_NONSTICKY_RESET);
>  }
>
>  static void exynos_pcie_deassert_core_reset(struct exynos_pcie *ep)
>  {
>  	u32 val;
>
> -	val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET);
> +	val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_CORE_RESET);
>  	val |= PCIE_CORE_RESET_ENABLE;
>
> -	exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET);
> -	exynos_pcie_writel(ep->elbi_base, 1, PCIE_STICKY_RESET);
> -	exynos_pcie_writel(ep->elbi_base, 1, PCIE_NONSTICKY_RESET);
> -	exynos_pcie_writel(ep->elbi_base, 1, PCIE_APP_INIT_RESET);
> -	exynos_pcie_writel(ep->elbi_base, 0, PCIE_APP_INIT_RESET);
> -	exynos_pcie_writel(ep->block_base, 1, PCIE_PHY_MAC_RESET);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_CORE_RESET);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_STICKY_RESET);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_NONSTICKY_RESET);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_APP_INIT_RESET);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_APP_INIT_RESET);
> +	exynos_pcie_writel(ep->mem_res->block_base, 1, PCIE_PHY_MAC_RESET);
>  }
>
>  static void exynos_pcie_assert_phy_reset(struct exynos_pcie *ep)
>  {
> -	exynos_pcie_writel(ep->block_base, 0, PCIE_PHY_MAC_RESET);
> -	exynos_pcie_writel(ep->block_base, 1, PCIE_PHY_GLOBAL_RESET);
> +	exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_MAC_RESET);
> +	exynos_pcie_writel(ep->mem_res->block_base, 1, PCIE_PHY_GLOBAL_RESET);
>  }
>
>  static void exynos_pcie_deassert_phy_reset(struct exynos_pcie *ep)
>  {
> -	exynos_pcie_writel(ep->block_base, 0, PCIE_PHY_GLOBAL_RESET);
> -	exynos_pcie_writel(ep->elbi_base, 1, PCIE_PWR_RESET);
> -	exynos_pcie_writel(ep->block_base, 0, PCIE_PHY_COMMON_RESET);
> -	exynos_pcie_writel(ep->block_base, 0, PCIE_PHY_CMN_REG);
> -	exynos_pcie_writel(ep->block_base, 0, PCIE_PHY_TRSVREG_RESET);
> -	exynos_pcie_writel(ep->block_base, 0, PCIE_PHY_TRSV_RESET);
> +	exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_GLOBAL_RESET);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_PWR_RESET);
> +	exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_COMMON_RESET);
> +	exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_CMN_REG);
> +	exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_TRSVREG_RESET);
> +	exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_TRSV_RESET);
>  }
>
>  static void exynos_pcie_power_on_phy(struct exynos_pcie *ep)
>  {
>  	u32 val;
>
> -	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_COMMON_POWER);
> +	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_COMMON_POWER);
>  	val &= ~PCIE_PHY_COMMON_PD_CMN;
> -	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_COMMON_POWER);
> +	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_COMMON_POWER);
>
> -	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV0_POWER);
> +	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV0_POWER);
>  	val &= ~PCIE_PHY_TRSV0_PD_TSV;
> -	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV0_POWER);
> +	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV0_POWER);
>
> -	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV1_POWER);
> +	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV1_POWER);
>  	val &= ~PCIE_PHY_TRSV1_PD_TSV;
> -	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV1_POWER);
> +	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV1_POWER);
>
> -	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV2_POWER);
> +	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV2_POWER);
>  	val &= ~PCIE_PHY_TRSV2_PD_TSV;
> -	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV2_POWER);
> +	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV2_POWER);
>
> -	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV3_POWER);
> +	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV3_POWER);
>  	val &= ~PCIE_PHY_TRSV3_PD_TSV;
> -	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV3_POWER);
> +	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV3_POWER);
>  }
>
>  static void exynos_pcie_power_off_phy(struct exynos_pcie *ep)
>  {
>  	u32 val;
>
> -	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_COMMON_POWER);
> +	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_COMMON_POWER);
>  	val |= PCIE_PHY_COMMON_PD_CMN;
> -	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_COMMON_POWER);
> +	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_COMMON_POWER);
>
> -	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV0_POWER);
> +	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV0_POWER);
>  	val |= PCIE_PHY_TRSV0_PD_TSV;
> -	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV0_POWER);
> +	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV0_POWER);
>
> -	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV1_POWER);
> +	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV1_POWER);
>  	val |= PCIE_PHY_TRSV1_PD_TSV;
> -	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV1_POWER);
> +	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV1_POWER);
>
> -	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV2_POWER);
> +	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV2_POWER);
>  	val |= PCIE_PHY_TRSV2_PD_TSV;
> -	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV2_POWER);
> +	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV2_POWER);
>
> -	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV3_POWER);
> +	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV3_POWER);
>  	val |= PCIE_PHY_TRSV3_PD_TSV;
> -	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV3_POWER);
> +	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV3_POWER);
>  }
>
>  static void exynos_pcie_init_phy(struct exynos_pcie *ep)
>  {
>  	/* DCC feedback control off */
> -	exynos_pcie_writel(ep->phy_base, 0x29, PCIE_PHY_DCC_FEEDBACK);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x29, PCIE_PHY_DCC_FEEDBACK);
>
>  	/* set TX/RX impedance */
> -	exynos_pcie_writel(ep->phy_base, 0xd5, PCIE_PHY_IMPEDANCE);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0xd5, PCIE_PHY_IMPEDANCE);
>
>  	/* set 50Mhz PHY clock */
> -	exynos_pcie_writel(ep->phy_base, 0x14, PCIE_PHY_PLL_DIV_0);
> -	exynos_pcie_writel(ep->phy_base, 0x12, PCIE_PHY_PLL_DIV_1);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x14, PCIE_PHY_PLL_DIV_0);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x12, PCIE_PHY_PLL_DIV_1);
>
>  	/* set TX Differential output for lane 0 */
> -	exynos_pcie_writel(ep->phy_base, 0x7f, PCIE_PHY_TRSV0_DRV_LVL);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x7f, PCIE_PHY_TRSV0_DRV_LVL);
>
>  	/* set TX Pre-emphasis Level Control for lane 0 to minimum */
> -	exynos_pcie_writel(ep->phy_base, 0x0, PCIE_PHY_TRSV0_EMP_LVL);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x0, PCIE_PHY_TRSV0_EMP_LVL);
>
>  	/* set RX clock and data recovery bandwidth */
> -	exynos_pcie_writel(ep->phy_base, 0xe7, PCIE_PHY_PLL_BIAS);
> -	exynos_pcie_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV0_RXCDR);
> -	exynos_pcie_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV1_RXCDR);
> -	exynos_pcie_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV2_RXCDR);
> -	exynos_pcie_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV3_RXCDR);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0xe7, PCIE_PHY_PLL_BIAS);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x82, PCIE_PHY_TRSV0_RXCDR);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x82, PCIE_PHY_TRSV1_RXCDR);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x82, PCIE_PHY_TRSV2_RXCDR);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x82, PCIE_PHY_TRSV3_RXCDR);
>
>  	/* change TX Pre-emphasis Level Control for lanes */
> -	exynos_pcie_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV0_EMP_LVL);
> -	exynos_pcie_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV1_EMP_LVL);
> -	exynos_pcie_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV2_EMP_LVL);
> -	exynos_pcie_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV3_EMP_LVL);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x39, PCIE_PHY_TRSV0_EMP_LVL);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x39, PCIE_PHY_TRSV1_EMP_LVL);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x39, PCIE_PHY_TRSV2_EMP_LVL);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x39, PCIE_PHY_TRSV3_EMP_LVL);
>
>  	/* set LVCC */
> -	exynos_pcie_writel(ep->phy_base, 0x20, PCIE_PHY_TRSV0_LVCC);
> -	exynos_pcie_writel(ep->phy_base, 0xa0, PCIE_PHY_TRSV1_LVCC);
> -	exynos_pcie_writel(ep->phy_base, 0xa0, PCIE_PHY_TRSV2_LVCC);
> -	exynos_pcie_writel(ep->phy_base, 0xa0, PCIE_PHY_TRSV3_LVCC);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x20, PCIE_PHY_TRSV0_LVCC);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0xa0, PCIE_PHY_TRSV1_LVCC);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0xa0, PCIE_PHY_TRSV2_LVCC);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0xa0, PCIE_PHY_TRSV3_LVCC);
>  }
>
>  static void exynos_pcie_assert_reset(struct exynos_pcie *exynos_pcie)
> @@ -295,25 +402,27 @@ static int exynos_pcie_establish_link(struct exynos_pcie *exynos_pcie)
>  	exynos_pcie_init_phy(exynos_pcie);
>
>  	/* pulse for common reset */
> -	exynos_pcie_writel(exynos_pcie->block_base, 1, PCIE_PHY_COMMON_RESET);
> +	exynos_pcie_writel(exynos_pcie->mem_res->block_base, 1,
> +				PCIE_PHY_COMMON_RESET);
>  	udelay(500);
> -	exynos_pcie_writel(exynos_pcie->block_base, 0, PCIE_PHY_COMMON_RESET);
> +	exynos_pcie_writel(exynos_pcie->mem_res->block_base, 0,
> +				PCIE_PHY_COMMON_RESET);
>
>  	exynos_pcie_deassert_core_reset(exynos_pcie);
>  	dw_pcie_setup_rc(pp);
>  	exynos_pcie_assert_reset(exynos_pcie);
>
>  	/* assert LTSSM enable */
> -	exynos_pcie_writel(exynos_pcie->elbi_base, PCIE_ELBI_LTSSM_ENABLE,
> -			  PCIE_APP_LTSSM_ENABLE);
> +	exynos_pcie_writel(exynos_pcie->mem_res->elbi_base,
> +			PCIE_ELBI_LTSSM_ENABLE, PCIE_APP_LTSSM_ENABLE);
>
>  	/* check if the link is up or not */
>  	if (!dw_pcie_wait_for_link(pp))
>  		return 0;
>
> -	while (exynos_pcie_readl(exynos_pcie->phy_base,
> +	while (exynos_pcie_readl(exynos_pcie->mem_res->phy_base,
>  				PCIE_PHY_PLL_LOCKED) == 0) {
> -		val = exynos_pcie_readl(exynos_pcie->block_base,
> +		val = exynos_pcie_readl(exynos_pcie->mem_res->block_base,
>  				PCIE_PHY_PLL_LOCKED);
>  		dev_info(dev, "PLL Locked: 0x%x\n", val);
>  	}
> @@ -325,8 +434,8 @@ static void exynos_pcie_clear_irq_pulse(struct exynos_pcie *ep)
>  {
>  	u32 val;
>
> -	val = exynos_pcie_readl(ep->elbi_base, PCIE_IRQ_PULSE);
> -	exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_PULSE);
> +	val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_IRQ_PULSE);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_PULSE);
>  }
>
>  static void exynos_pcie_enable_irq_pulse(struct exynos_pcie *ep)
> @@ -336,7 +445,7 @@ static void exynos_pcie_enable_irq_pulse(struct exynos_pcie *ep)
>  	/* enable INTX interrupt */
>  	val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT |
>  		IRQ_INTC_ASSERT | IRQ_INTD_ASSERT;
> -	exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_EN_PULSE);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_EN_PULSE);
>  }
>
>  static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg)
> @@ -363,9 +472,9 @@ static void exynos_pcie_msi_init(struct exynos_pcie *ep)
>  	dw_pcie_msi_init(pp);
>
>  	/* enable MSI interrupt */
> -	val = exynos_pcie_readl(ep->elbi_base, PCIE_IRQ_EN_LEVEL);
> +	val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_IRQ_EN_LEVEL);
>  	val |= IRQ_MSI_ENABLE;
> -	exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_EN_LEVEL);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_EN_LEVEL);
>  }
>
>  static void exynos_pcie_enable_interrupts(struct exynos_pcie *exynos_pcie)
> @@ -425,7 +534,8 @@ static int exynos_pcie_link_up(struct pcie_port *pp)
>  	struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
>  	u32 val;
>
> -	val = exynos_pcie_readl(exynos_pcie->elbi_base, PCIE_ELBI_RDLH_LINKUP);
> +	val = exynos_pcie_readl(exynos_pcie->mem_res->elbi_base,
> +					PCIE_ELBI_RDLH_LINKUP);
>  	if (val == PCIE_ELBI_LTSSM_ENABLE)
>  		return 1;
>
> @@ -503,7 +613,6 @@ static int __init exynos_pcie_probe(struct platform_device *pdev)
>  	struct exynos_pcie *exynos_pcie;
>  	struct pcie_port *pp;
>  	struct device_node *np = dev->of_node;
> -	struct resource *res;
>  	int ret;
>
>  	exynos_pcie = devm_kzalloc(dev, sizeof(*exynos_pcie), GFP_KERNEL);
> @@ -513,59 +622,37 @@ static int __init exynos_pcie_probe(struct platform_device *pdev)
>  	pp = &exynos_pcie->pp;
>  	pp->dev = dev;
>
> -	exynos_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
> -
> -	exynos_pcie->clk = devm_clk_get(dev, "pcie");
> -	if (IS_ERR(exynos_pcie->clk)) {
> -		dev_err(dev, "Failed to get pcie rc clock\n");
> -		return PTR_ERR(exynos_pcie->clk);
> -	}
> -	ret = clk_prepare_enable(exynos_pcie->clk);
> -	if (ret)
> -		return ret;
> +	exynos_pcie->ops = (const struct exynos_pcie_ops *)
> +				of_device_get_match_data(dev);
>
> -	exynos_pcie->bus_clk = devm_clk_get(dev, "pcie_bus");
> -	if (IS_ERR(exynos_pcie->bus_clk)) {
> -		dev_err(dev, "Failed to get pcie bus clock\n");
> -		ret = PTR_ERR(exynos_pcie->bus_clk);
> -		goto fail_clk;
> -	}
> -	ret = clk_prepare_enable(exynos_pcie->bus_clk);
> -	if (ret)
> -		goto fail_clk;
> +	exynos_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
>
> -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> -	exynos_pcie->elbi_base = devm_ioremap_resource(dev, res);
> -	if (IS_ERR(exynos_pcie->elbi_base)) {
> -		ret = PTR_ERR(exynos_pcie->elbi_base);
> -		goto fail_bus_clk;
> +	if (exynos_pcie->ops && exynos_pcie->ops->get_mem_resources) {
> +		ret = exynos_pcie->ops->get_mem_resources(pdev, exynos_pcie);
> +		if (ret)
> +			return ret;
>  	}
>
> -	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> -	exynos_pcie->phy_base = devm_ioremap_resource(dev, res);
> -	if (IS_ERR(exynos_pcie->phy_base)) {
> -		ret = PTR_ERR(exynos_pcie->phy_base);
> -		goto fail_bus_clk;
> -	}
> +	if (exynos_pcie->ops && exynos_pcie->ops->get_clk_resources) {
> +		ret = exynos_pcie->ops->get_clk_resources(exynos_pcie);
> +		if (ret)
> +			return ret;
>
> -	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
> -	exynos_pcie->block_base = devm_ioremap_resource(dev, res);
> -	if (IS_ERR(exynos_pcie->block_base)) {
> -		ret = PTR_ERR(exynos_pcie->block_base);
> -		goto fail_bus_clk;
> +		ret = exynos_pcie->ops->init_clk_resources(exynos_pcie);
> +		if (ret)
> +			return ret;
>  	}
>
>  	ret = exynos_add_pcie_port(exynos_pcie, pdev);
>  	if (ret < 0)
> -		goto fail_bus_clk;
> +		goto fail_probe;
>
>  	platform_set_drvdata(pdev, exynos_pcie);
>  	return 0;
>
> -fail_bus_clk:
> -	clk_disable_unprepare(exynos_pcie->bus_clk);
> -fail_clk:
> -	clk_disable_unprepare(exynos_pcie->clk);
> +fail_probe:
> +	if (exynos_pcie->ops && exynos_pcie->ops->deinit_clk_resources)
> +		exynos_pcie->ops->deinit_clk_resources(exynos_pcie);
>  	return ret;
>  }
>
> @@ -573,14 +660,17 @@ static int __exit exynos_pcie_remove(struct platform_device *pdev)
>  {
>  	struct exynos_pcie *exynos_pcie = platform_get_drvdata(pdev);
>
> -	clk_disable_unprepare(exynos_pcie->bus_clk);
> -	clk_disable_unprepare(exynos_pcie->clk);
> +	if (exynos_pcie->ops && exynos_pcie->ops->deinit_clk_resources)
> +		exynos_pcie->ops->deinit_clk_resources(exynos_pcie);
>
>  	return 0;
>  }
>
>  static const struct of_device_id exynos_pcie_of_match[] = {
> -	{ .compatible = "samsung,exynos5440-pcie", },
> +	{
> +		.compatible = "samsung,exynos5440-pcie",
> +		.data = &exynos5440_pcie_ops
> +	},
>  	{},
>  };
>
>

^ permalink raw reply

* [PATCH 02/22] mfd: axp20x: add ADC data regs to volatile regs for AXP22X
From: Chen-Yu Tsai @ 2017-01-05  4:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170102163723.7939-3-quentin.schulz@free-electrons.com>

On Tue, Jan 3, 2017 at 12:37 AM, Quentin Schulz
<quentin.schulz@free-electrons.com> wrote:
> The AXP22X PMICs have multiple ADCs, each one exposing data from the
> different power supplies connected to the PMIC.
>
> This adds the different ADC data registers to the volatile registers of
> the AXP22X PMIC.
>
> Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
> ---
>  drivers/mfd/axp20x.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
> index 619a83e..a33db5e 100644
> --- a/drivers/mfd/axp20x.c
> +++ b/drivers/mfd/axp20x.c
> @@ -100,6 +100,7 @@ static const struct regmap_range axp22x_writeable_ranges[] = {
>  static const struct regmap_range axp22x_volatile_ranges[] = {
>         regmap_reg_range(AXP20X_PWR_INPUT_STATUS, AXP20X_PWR_OP_MODE),
>         regmap_reg_range(AXP20X_VBUS_IPSOUT_MGMT, AXP20X_VBUS_IPSOUT_MGMT),
> +       regmap_reg_range(AXP22X_TEMP_ADC_H, AXP20X_BATT_DISCHRG_I_L),

You added this macro in the next patch. Please move that hunk to this patch.

ChenYu

>         regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ5_STATE),
>         regmap_reg_range(AXP22X_GPIO_STATE, AXP22X_GPIO_STATE),
>         regmap_reg_range(AXP22X_PMIC_ADC_H, AXP20X_IPSOUT_V_HIGH_L),
> --
> 2.9.3
>

^ permalink raw reply

* [PATCH v2] PCI: exynos: refactor exynos pcie driver
From: Jaehoon Chung @ 2017-01-05  4:17 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1483588418-2551-1-git-send-email-pankaj.dubey@samsung.com>

On 01/05/2017 12:53 PM, Pankaj Dubey wrote:
> From: Niyas Ahmed S T <niyas.ahmed@samsung.com>
> 
> Currently Exynos PCIe driver is only supported for Exynos5440 SoC.
> This patch does refactoring of Exynos PCIe driver to extend support
> for other Exynos SoC.
> 
> Following are the main changes done via this patch:
> 
> 1) It adds separate structs for memory, clock resources.
> 
> Reason behind this change is, moving ahead various Exynos SoC will
> have different hardware resources such as iomem, clocks, regmap handles
> etc. for PCIe controller, so keeping these resources in separate struct
> will help us in intiailizing them via per SoC ops, and will avoid too
> many of_machine_is_compatible in code, and help us simplifying
> exynos_pcie struct.
> 
> 2) It add exynos_pcie_ops struct which will allow us to support the
> differences in resources in different Exynos SoC.
> 
> No functional change intended.
> 
> Signed-off-by: Niyas Ahmed S T <niyas.ahmed@samsung.com>
> Signed-off-by: Pankaj Dubey <pankaj.dubey@samsung.com>
> Acked-by: Krzysztof Kozlowski <krzk@kernel.org>
> Reviewed-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>

Reviewed-by: Jaehoon Chung <jh80.chung@samsung.com>

Best Regards,
Jaehoon Chung

> ---
> This patch set is prepared on top of Krzysztof's for-next and
> PCIe driver cleanup patch [1] by Jaehoon Chung.
> 
> [1]: https://lkml.org/lkml/2016/12/19/44
> 
> Changes from v1:
>  - Addressed review comments from Krzysztof and Jingoo Han.
> 
>  drivers/pci/host/pci-exynos.c | 348 ++++++++++++++++++++++++++----------------
>  1 file changed, 219 insertions(+), 129 deletions(-)
> 
> diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-exynos.c
> index 33562cf..d91751b 100644
> --- a/drivers/pci/host/pci-exynos.c
> +++ b/drivers/pci/host/pci-exynos.c
> @@ -17,6 +17,7 @@
>  #include <linux/interrupt.h>
>  #include <linux/kernel.h>
>  #include <linux/init.h>
> +#include <linux/of_device.h>
>  #include <linux/of_gpio.h>
>  #include <linux/pci.h>
>  #include <linux/platform_device.h>
> @@ -28,16 +29,6 @@
>  
>  #define to_exynos_pcie(x)	container_of(x, struct exynos_pcie, pp)
>  
> -struct exynos_pcie {
> -	struct pcie_port	pp;
> -	void __iomem		*elbi_base;	/* DT 0th resource */
> -	void __iomem		*phy_base;	/* DT 1st resource */
> -	void __iomem		*block_base;	/* DT 2nd resource */
> -	int			reset_gpio;
> -	struct clk		*clk;
> -	struct clk		*bus_clk;
> -};
> -
>  /* PCIe ELBI registers */
>  #define PCIE_IRQ_PULSE			0x000
>  #define IRQ_INTA_ASSERT			BIT(0)
> @@ -102,6 +93,122 @@ struct exynos_pcie {
>  #define PCIE_PHY_TRSV3_PD_TSV		BIT(7)
>  #define PCIE_PHY_TRSV3_LVCC		0x31c
>  
> +struct exynos_pcie_mem_res {
> +	void __iomem *elbi_base; /* DT 0th resource: PCIE CTRL */
> +	void __iomem *phy_base; /* DT 1st resource: PHY CTRL */
> +	void __iomem *block_base; /* DT 2nd resource: PHY ADDITIONAL CTRL */
> +};
> +
> +struct exynos_pcie_clk_res {
> +	struct clk *clk;
> +	struct clk *bus_clk;
> +};
> +
> +struct exynos_pcie {
> +	struct pcie_port		pp;
> +	struct exynos_pcie_mem_res	*mem_res;
> +	struct exynos_pcie_clk_res	*clk_res;
> +	const struct exynos_pcie_ops	*ops;
> +	int				reset_gpio;
> +};
> +
> +struct exynos_pcie_ops {
> +	int (*get_mem_resources)(struct platform_device *pdev,
> +			struct exynos_pcie *ep);
> +	int (*get_clk_resources)(struct exynos_pcie *ep);
> +	int (*init_clk_resources)(struct exynos_pcie *ep);
> +	void (*deinit_clk_resources)(struct exynos_pcie *ep);
> +};
> +
> +static int exynos5440_pcie_get_mem_resources(struct platform_device *pdev,
> +						struct exynos_pcie *ep)
> +{
> +	struct resource *res;
> +	struct device *dev = ep->pp.dev;
> +
> +	ep->mem_res = devm_kzalloc(dev, sizeof(*ep->mem_res), GFP_KERNEL);
> +	if (!ep->mem_res)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	ep->mem_res->elbi_base = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(ep->mem_res->elbi_base))
> +		return PTR_ERR(ep->mem_res->elbi_base);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> +	ep->mem_res->phy_base = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(ep->mem_res->phy_base))
> +		return PTR_ERR(ep->mem_res->phy_base);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
> +	ep->mem_res->block_base = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(ep->mem_res->block_base))
> +		return PTR_ERR(ep->mem_res->block_base);
> +
> +	return 0;
> +}
> +
> +static int exynos5440_pcie_get_clk_resources(struct exynos_pcie *ep)
> +{
> +	struct device *dev = ep->pp.dev;
> +
> +	ep->clk_res = devm_kzalloc(dev, sizeof(*ep->clk_res), GFP_KERNEL);
> +	if (!ep->clk_res)
> +		return -ENOMEM;
> +
> +	ep->clk_res->clk = devm_clk_get(dev, "pcie");
> +	if (IS_ERR(ep->clk_res->clk)) {
> +		dev_err(dev, "Failed to get pcie rc clock\n");
> +		return PTR_ERR(ep->clk_res->clk);
> +	}
> +
> +	ep->clk_res->bus_clk = devm_clk_get(dev, "pcie_bus");
> +	if (IS_ERR(ep->clk_res->bus_clk)) {
> +		dev_err(dev, "Failed to get pcie bus clock\n");
> +		return PTR_ERR(ep->clk_res->bus_clk);
> +	}
> +
> +	return 0;
> +}
> +
> +static int exynos5440_pcie_init_clk_resources(struct exynos_pcie *ep)
> +{
> +	struct device *dev = ep->pp.dev;
> +	int ret;
> +
> +	ret = clk_prepare_enable(ep->clk_res->clk);
> +	if (ret) {
> +		dev_err(dev, "cannot enable pcie rc clock");
> +		return ret;
> +	}
> +
> +	ret = clk_prepare_enable(ep->clk_res->bus_clk);
> +	if (ret) {
> +		dev_err(dev, "cannot enable pcie bus clock");
> +		goto err_bus_clk;
> +	}
> +
> +	return 0;
> +
> +err_bus_clk:
> +	clk_disable_unprepare(ep->clk_res->clk);
> +
> +	return ret;
> +}
> +
> +static void exynos5440_pcie_deinit_clk_resources(struct exynos_pcie *ep)
> +{
> +	clk_disable_unprepare(ep->clk_res->bus_clk);
> +	clk_disable_unprepare(ep->clk_res->clk);
> +}
> +
> +static const struct exynos_pcie_ops exynos5440_pcie_ops = {
> +	.get_mem_resources	= exynos5440_pcie_get_mem_resources,
> +	.get_clk_resources	= exynos5440_pcie_get_clk_resources,
> +	.init_clk_resources	= exynos5440_pcie_init_clk_resources,
> +	.deinit_clk_resources	= exynos5440_pcie_deinit_clk_resources,
> +};
> +
>  static void exynos_pcie_writel(void __iomem *base, u32 val, u32 reg)
>  {
>  	writel(val, base + reg);
> @@ -116,155 +223,155 @@ static void exynos_pcie_sideband_dbi_w_mode(struct exynos_pcie *ep, bool on)
>  {
>  	u32 val;
>  
> -	val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_AWMISC);
> +	val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_SLV_AWMISC);
>  	if (on)
>  		val |= PCIE_ELBI_SLV_DBI_ENABLE;
>  	else
>  		val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
> -	exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_AWMISC);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_ELBI_SLV_AWMISC);
>  }
>  
>  static void exynos_pcie_sideband_dbi_r_mode(struct exynos_pcie *ep, bool on)
>  {
>  	u32 val;
>  
> -	val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_ARMISC);
> +	val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_SLV_ARMISC);
>  	if (on)
>  		val |= PCIE_ELBI_SLV_DBI_ENABLE;
>  	else
>  		val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
> -	exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_ARMISC);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_ELBI_SLV_ARMISC);
>  }
>  
>  static void exynos_pcie_assert_core_reset(struct exynos_pcie *ep)
>  {
>  	u32 val;
>  
> -	val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET);
> +	val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_CORE_RESET);
>  	val &= ~PCIE_CORE_RESET_ENABLE;
> -	exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET);
> -	exynos_pcie_writel(ep->elbi_base, 0, PCIE_PWR_RESET);
> -	exynos_pcie_writel(ep->elbi_base, 0, PCIE_STICKY_RESET);
> -	exynos_pcie_writel(ep->elbi_base, 0, PCIE_NONSTICKY_RESET);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_CORE_RESET);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_PWR_RESET);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_STICKY_RESET);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_NONSTICKY_RESET);
>  }
>  
>  static void exynos_pcie_deassert_core_reset(struct exynos_pcie *ep)
>  {
>  	u32 val;
>  
> -	val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET);
> +	val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_CORE_RESET);
>  	val |= PCIE_CORE_RESET_ENABLE;
>  
> -	exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET);
> -	exynos_pcie_writel(ep->elbi_base, 1, PCIE_STICKY_RESET);
> -	exynos_pcie_writel(ep->elbi_base, 1, PCIE_NONSTICKY_RESET);
> -	exynos_pcie_writel(ep->elbi_base, 1, PCIE_APP_INIT_RESET);
> -	exynos_pcie_writel(ep->elbi_base, 0, PCIE_APP_INIT_RESET);
> -	exynos_pcie_writel(ep->block_base, 1, PCIE_PHY_MAC_RESET);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_CORE_RESET);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_STICKY_RESET);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_NONSTICKY_RESET);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_APP_INIT_RESET);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_APP_INIT_RESET);
> +	exynos_pcie_writel(ep->mem_res->block_base, 1, PCIE_PHY_MAC_RESET);
>  }
>  
>  static void exynos_pcie_assert_phy_reset(struct exynos_pcie *ep)
>  {
> -	exynos_pcie_writel(ep->block_base, 0, PCIE_PHY_MAC_RESET);
> -	exynos_pcie_writel(ep->block_base, 1, PCIE_PHY_GLOBAL_RESET);
> +	exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_MAC_RESET);
> +	exynos_pcie_writel(ep->mem_res->block_base, 1, PCIE_PHY_GLOBAL_RESET);
>  }
>  
>  static void exynos_pcie_deassert_phy_reset(struct exynos_pcie *ep)
>  {
> -	exynos_pcie_writel(ep->block_base, 0, PCIE_PHY_GLOBAL_RESET);
> -	exynos_pcie_writel(ep->elbi_base, 1, PCIE_PWR_RESET);
> -	exynos_pcie_writel(ep->block_base, 0, PCIE_PHY_COMMON_RESET);
> -	exynos_pcie_writel(ep->block_base, 0, PCIE_PHY_CMN_REG);
> -	exynos_pcie_writel(ep->block_base, 0, PCIE_PHY_TRSVREG_RESET);
> -	exynos_pcie_writel(ep->block_base, 0, PCIE_PHY_TRSV_RESET);
> +	exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_GLOBAL_RESET);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_PWR_RESET);
> +	exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_COMMON_RESET);
> +	exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_CMN_REG);
> +	exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_TRSVREG_RESET);
> +	exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_TRSV_RESET);
>  }
>  
>  static void exynos_pcie_power_on_phy(struct exynos_pcie *ep)
>  {
>  	u32 val;
>  
> -	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_COMMON_POWER);
> +	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_COMMON_POWER);
>  	val &= ~PCIE_PHY_COMMON_PD_CMN;
> -	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_COMMON_POWER);
> +	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_COMMON_POWER);
>  
> -	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV0_POWER);
> +	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV0_POWER);
>  	val &= ~PCIE_PHY_TRSV0_PD_TSV;
> -	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV0_POWER);
> +	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV0_POWER);
>  
> -	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV1_POWER);
> +	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV1_POWER);
>  	val &= ~PCIE_PHY_TRSV1_PD_TSV;
> -	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV1_POWER);
> +	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV1_POWER);
>  
> -	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV2_POWER);
> +	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV2_POWER);
>  	val &= ~PCIE_PHY_TRSV2_PD_TSV;
> -	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV2_POWER);
> +	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV2_POWER);
>  
> -	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV3_POWER);
> +	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV3_POWER);
>  	val &= ~PCIE_PHY_TRSV3_PD_TSV;
> -	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV3_POWER);
> +	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV3_POWER);
>  }
>  
>  static void exynos_pcie_power_off_phy(struct exynos_pcie *ep)
>  {
>  	u32 val;
>  
> -	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_COMMON_POWER);
> +	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_COMMON_POWER);
>  	val |= PCIE_PHY_COMMON_PD_CMN;
> -	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_COMMON_POWER);
> +	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_COMMON_POWER);
>  
> -	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV0_POWER);
> +	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV0_POWER);
>  	val |= PCIE_PHY_TRSV0_PD_TSV;
> -	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV0_POWER);
> +	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV0_POWER);
>  
> -	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV1_POWER);
> +	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV1_POWER);
>  	val |= PCIE_PHY_TRSV1_PD_TSV;
> -	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV1_POWER);
> +	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV1_POWER);
>  
> -	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV2_POWER);
> +	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV2_POWER);
>  	val |= PCIE_PHY_TRSV2_PD_TSV;
> -	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV2_POWER);
> +	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV2_POWER);
>  
> -	val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV3_POWER);
> +	val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV3_POWER);
>  	val |= PCIE_PHY_TRSV3_PD_TSV;
> -	exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV3_POWER);
> +	exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV3_POWER);
>  }
>  
>  static void exynos_pcie_init_phy(struct exynos_pcie *ep)
>  {
>  	/* DCC feedback control off */
> -	exynos_pcie_writel(ep->phy_base, 0x29, PCIE_PHY_DCC_FEEDBACK);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x29, PCIE_PHY_DCC_FEEDBACK);
>  
>  	/* set TX/RX impedance */
> -	exynos_pcie_writel(ep->phy_base, 0xd5, PCIE_PHY_IMPEDANCE);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0xd5, PCIE_PHY_IMPEDANCE);
>  
>  	/* set 50Mhz PHY clock */
> -	exynos_pcie_writel(ep->phy_base, 0x14, PCIE_PHY_PLL_DIV_0);
> -	exynos_pcie_writel(ep->phy_base, 0x12, PCIE_PHY_PLL_DIV_1);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x14, PCIE_PHY_PLL_DIV_0);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x12, PCIE_PHY_PLL_DIV_1);
>  
>  	/* set TX Differential output for lane 0 */
> -	exynos_pcie_writel(ep->phy_base, 0x7f, PCIE_PHY_TRSV0_DRV_LVL);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x7f, PCIE_PHY_TRSV0_DRV_LVL);
>  
>  	/* set TX Pre-emphasis Level Control for lane 0 to minimum */
> -	exynos_pcie_writel(ep->phy_base, 0x0, PCIE_PHY_TRSV0_EMP_LVL);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x0, PCIE_PHY_TRSV0_EMP_LVL);
>  
>  	/* set RX clock and data recovery bandwidth */
> -	exynos_pcie_writel(ep->phy_base, 0xe7, PCIE_PHY_PLL_BIAS);
> -	exynos_pcie_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV0_RXCDR);
> -	exynos_pcie_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV1_RXCDR);
> -	exynos_pcie_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV2_RXCDR);
> -	exynos_pcie_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV3_RXCDR);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0xe7, PCIE_PHY_PLL_BIAS);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x82, PCIE_PHY_TRSV0_RXCDR);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x82, PCIE_PHY_TRSV1_RXCDR);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x82, PCIE_PHY_TRSV2_RXCDR);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x82, PCIE_PHY_TRSV3_RXCDR);
>  
>  	/* change TX Pre-emphasis Level Control for lanes */
> -	exynos_pcie_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV0_EMP_LVL);
> -	exynos_pcie_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV1_EMP_LVL);
> -	exynos_pcie_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV2_EMP_LVL);
> -	exynos_pcie_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV3_EMP_LVL);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x39, PCIE_PHY_TRSV0_EMP_LVL);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x39, PCIE_PHY_TRSV1_EMP_LVL);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x39, PCIE_PHY_TRSV2_EMP_LVL);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x39, PCIE_PHY_TRSV3_EMP_LVL);
>  
>  	/* set LVCC */
> -	exynos_pcie_writel(ep->phy_base, 0x20, PCIE_PHY_TRSV0_LVCC);
> -	exynos_pcie_writel(ep->phy_base, 0xa0, PCIE_PHY_TRSV1_LVCC);
> -	exynos_pcie_writel(ep->phy_base, 0xa0, PCIE_PHY_TRSV2_LVCC);
> -	exynos_pcie_writel(ep->phy_base, 0xa0, PCIE_PHY_TRSV3_LVCC);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0x20, PCIE_PHY_TRSV0_LVCC);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0xa0, PCIE_PHY_TRSV1_LVCC);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0xa0, PCIE_PHY_TRSV2_LVCC);
> +	exynos_pcie_writel(ep->mem_res->phy_base, 0xa0, PCIE_PHY_TRSV3_LVCC);
>  }
>  
>  static void exynos_pcie_assert_reset(struct exynos_pcie *exynos_pcie)
> @@ -295,25 +402,27 @@ static int exynos_pcie_establish_link(struct exynos_pcie *exynos_pcie)
>  	exynos_pcie_init_phy(exynos_pcie);
>  
>  	/* pulse for common reset */
> -	exynos_pcie_writel(exynos_pcie->block_base, 1, PCIE_PHY_COMMON_RESET);
> +	exynos_pcie_writel(exynos_pcie->mem_res->block_base, 1,
> +				PCIE_PHY_COMMON_RESET);
>  	udelay(500);
> -	exynos_pcie_writel(exynos_pcie->block_base, 0, PCIE_PHY_COMMON_RESET);
> +	exynos_pcie_writel(exynos_pcie->mem_res->block_base, 0,
> +				PCIE_PHY_COMMON_RESET);
>  
>  	exynos_pcie_deassert_core_reset(exynos_pcie);
>  	dw_pcie_setup_rc(pp);
>  	exynos_pcie_assert_reset(exynos_pcie);
>  
>  	/* assert LTSSM enable */
> -	exynos_pcie_writel(exynos_pcie->elbi_base, PCIE_ELBI_LTSSM_ENABLE,
> -			  PCIE_APP_LTSSM_ENABLE);
> +	exynos_pcie_writel(exynos_pcie->mem_res->elbi_base,
> +			PCIE_ELBI_LTSSM_ENABLE, PCIE_APP_LTSSM_ENABLE);
>  
>  	/* check if the link is up or not */
>  	if (!dw_pcie_wait_for_link(pp))
>  		return 0;
>  
> -	while (exynos_pcie_readl(exynos_pcie->phy_base,
> +	while (exynos_pcie_readl(exynos_pcie->mem_res->phy_base,
>  				PCIE_PHY_PLL_LOCKED) == 0) {
> -		val = exynos_pcie_readl(exynos_pcie->block_base,
> +		val = exynos_pcie_readl(exynos_pcie->mem_res->block_base,
>  				PCIE_PHY_PLL_LOCKED);
>  		dev_info(dev, "PLL Locked: 0x%x\n", val);
>  	}
> @@ -325,8 +434,8 @@ static void exynos_pcie_clear_irq_pulse(struct exynos_pcie *ep)
>  {
>  	u32 val;
>  
> -	val = exynos_pcie_readl(ep->elbi_base, PCIE_IRQ_PULSE);
> -	exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_PULSE);
> +	val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_IRQ_PULSE);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_PULSE);
>  }
>  
>  static void exynos_pcie_enable_irq_pulse(struct exynos_pcie *ep)
> @@ -336,7 +445,7 @@ static void exynos_pcie_enable_irq_pulse(struct exynos_pcie *ep)
>  	/* enable INTX interrupt */
>  	val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT |
>  		IRQ_INTC_ASSERT | IRQ_INTD_ASSERT;
> -	exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_EN_PULSE);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_EN_PULSE);
>  }
>  
>  static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg)
> @@ -363,9 +472,9 @@ static void exynos_pcie_msi_init(struct exynos_pcie *ep)
>  	dw_pcie_msi_init(pp);
>  
>  	/* enable MSI interrupt */
> -	val = exynos_pcie_readl(ep->elbi_base, PCIE_IRQ_EN_LEVEL);
> +	val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_IRQ_EN_LEVEL);
>  	val |= IRQ_MSI_ENABLE;
> -	exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_EN_LEVEL);
> +	exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_EN_LEVEL);
>  }
>  
>  static void exynos_pcie_enable_interrupts(struct exynos_pcie *exynos_pcie)
> @@ -425,7 +534,8 @@ static int exynos_pcie_link_up(struct pcie_port *pp)
>  	struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
>  	u32 val;
>  
> -	val = exynos_pcie_readl(exynos_pcie->elbi_base, PCIE_ELBI_RDLH_LINKUP);
> +	val = exynos_pcie_readl(exynos_pcie->mem_res->elbi_base,
> +					PCIE_ELBI_RDLH_LINKUP);
>  	if (val == PCIE_ELBI_LTSSM_ENABLE)
>  		return 1;
>  
> @@ -503,7 +613,6 @@ static int __init exynos_pcie_probe(struct platform_device *pdev)
>  	struct exynos_pcie *exynos_pcie;
>  	struct pcie_port *pp;
>  	struct device_node *np = dev->of_node;
> -	struct resource *res;
>  	int ret;
>  
>  	exynos_pcie = devm_kzalloc(dev, sizeof(*exynos_pcie), GFP_KERNEL);
> @@ -513,59 +622,37 @@ static int __init exynos_pcie_probe(struct platform_device *pdev)
>  	pp = &exynos_pcie->pp;
>  	pp->dev = dev;
>  
> -	exynos_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
> -
> -	exynos_pcie->clk = devm_clk_get(dev, "pcie");
> -	if (IS_ERR(exynos_pcie->clk)) {
> -		dev_err(dev, "Failed to get pcie rc clock\n");
> -		return PTR_ERR(exynos_pcie->clk);
> -	}
> -	ret = clk_prepare_enable(exynos_pcie->clk);
> -	if (ret)
> -		return ret;
> +	exynos_pcie->ops = (const struct exynos_pcie_ops *)
> +				of_device_get_match_data(dev);
>  
> -	exynos_pcie->bus_clk = devm_clk_get(dev, "pcie_bus");
> -	if (IS_ERR(exynos_pcie->bus_clk)) {
> -		dev_err(dev, "Failed to get pcie bus clock\n");
> -		ret = PTR_ERR(exynos_pcie->bus_clk);
> -		goto fail_clk;
> -	}
> -	ret = clk_prepare_enable(exynos_pcie->bus_clk);
> -	if (ret)
> -		goto fail_clk;
> +	exynos_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
>  
> -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> -	exynos_pcie->elbi_base = devm_ioremap_resource(dev, res);
> -	if (IS_ERR(exynos_pcie->elbi_base)) {
> -		ret = PTR_ERR(exynos_pcie->elbi_base);
> -		goto fail_bus_clk;
> +	if (exynos_pcie->ops && exynos_pcie->ops->get_mem_resources) {
> +		ret = exynos_pcie->ops->get_mem_resources(pdev, exynos_pcie);
> +		if (ret)
> +			return ret;
>  	}
>  
> -	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> -	exynos_pcie->phy_base = devm_ioremap_resource(dev, res);
> -	if (IS_ERR(exynos_pcie->phy_base)) {
> -		ret = PTR_ERR(exynos_pcie->phy_base);
> -		goto fail_bus_clk;
> -	}
> +	if (exynos_pcie->ops && exynos_pcie->ops->get_clk_resources) {
> +		ret = exynos_pcie->ops->get_clk_resources(exynos_pcie);
> +		if (ret)
> +			return ret;
>  
> -	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
> -	exynos_pcie->block_base = devm_ioremap_resource(dev, res);
> -	if (IS_ERR(exynos_pcie->block_base)) {
> -		ret = PTR_ERR(exynos_pcie->block_base);
> -		goto fail_bus_clk;
> +		ret = exynos_pcie->ops->init_clk_resources(exynos_pcie);
> +		if (ret)
> +			return ret;
>  	}
>  
>  	ret = exynos_add_pcie_port(exynos_pcie, pdev);
>  	if (ret < 0)
> -		goto fail_bus_clk;
> +		goto fail_probe;
>  
>  	platform_set_drvdata(pdev, exynos_pcie);
>  	return 0;
>  
> -fail_bus_clk:
> -	clk_disable_unprepare(exynos_pcie->bus_clk);
> -fail_clk:
> -	clk_disable_unprepare(exynos_pcie->clk);
> +fail_probe:
> +	if (exynos_pcie->ops && exynos_pcie->ops->deinit_clk_resources)
> +		exynos_pcie->ops->deinit_clk_resources(exynos_pcie);
>  	return ret;
>  }
>  
> @@ -573,14 +660,17 @@ static int __exit exynos_pcie_remove(struct platform_device *pdev)
>  {
>  	struct exynos_pcie *exynos_pcie = platform_get_drvdata(pdev);
>  
> -	clk_disable_unprepare(exynos_pcie->bus_clk);
> -	clk_disable_unprepare(exynos_pcie->clk);
> +	if (exynos_pcie->ops && exynos_pcie->ops->deinit_clk_resources)
> +		exynos_pcie->ops->deinit_clk_resources(exynos_pcie);
>  
>  	return 0;
>  }
>  
>  static const struct of_device_id exynos_pcie_of_match[] = {
> -	{ .compatible = "samsung,exynos5440-pcie", },
> +	{
> +		.compatible = "samsung,exynos5440-pcie",
> +		.data = &exynos5440_pcie_ops
> +	},
>  	{},
>  };
>  
> 

^ 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