* [RFC PATCH] Memory hotplug support for arm64 platform
From: Scott Branden @ 2016-12-22 1:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <7977063a-20bb-cc85-449f-51bb7d20761e@virtualopensystems.com>
Hi Maciej,
On 16-12-21 01:44 AM, Maciej Bielski wrote:
> Hi Scott,
>
> Thanks for testing it and providing us the feedback. For replicating the problem you have reported,
> could you provide more info on your system configuration, please?
> Among others, few questions that we have in mind are:
> * What is the RAM size at boot? Is it multiple of 1GB (or precisely `1<<MIN_MEMORY_BLOCK_SIZE`) ?
RAM size at boot is 64MB, not a multiple of 1GB. I will try next week
on a system with multi-GB@boot to see if it makes a difference.
SECTION_SIZE_BITS in sparsemem.h has been modified to 28 to allow for
256MB hotplug regions to be added.
> * Do you run the kernel with `mem=YYY` option?
no, memory is defined in dts file with a few reserved regions:
/memreserve/ 0x75000000 0x00800000;
/memreserve/ 0x77f00000 0x00100000;
&memory {
reg = <0x00000000 0x74000000 0x0 0x04000000>; /* 64MB */
};
> * Do you follow steps (1) and (2) for performing the hotplug?
no, only step 1 is done, auto-online is enabled. I'll try turning that
off and see if it makes a difference.
> * Do you have any other configuration flags enabled except for CONFIG_MEMORY_HOTPLUG?
> * Any other non-defaults?
Yes, a lot of config options have been disabled to reduce kernel size.
The memory auto-online is also enabled. I'll try with the default
defconfig to see if it makes a difference.
>
> Up to now the patch was passing our simple tests but if we miss something we will be very thankful
> if you could help us to sort it out. If you have found something after your deeper analysis, please
> keep us informed.
I think the path forward is to get a normal multi-GB system going and
then reduce the memory on boot and then hotplug it in after to see if
that works. Or, if you can reduce your memory down and give it a try
that might uncover a problem as well.
>
>
> On 20/12/2016 20:12, Scott Branden wrote:
>> Hi Maciej,
>>
>> I have applied that patch ontop of the patches I previously sent out
>> and tested.
>>
>> It does recognized the memory in /proc/iomem but I get memory corruption of the original system
>> RAM soon after. It appears the page allocation gets corrupted. I will try to dig into it further
>> but if somebody else could try it out in their system to see what results they get it would help.
>>
>> Regards,
>> Scott
>>
>> On 16-12-14 04:16 AM, Maciej Bielski wrote:
>>> This patch relates to the work previously announced in [1]. This builds on the
>>> work by Scott Branden [2] and, henceforth, it needs to be applied on top of
>>> Scott's patches [2]. Comments are very welcome.
>>>
>>> Changes from the original patchset and known issues:
>>>
>>> - Compared to Scott's original patchset, this work adds the mapping of
>>> the new hotplugged pages into the kernel page tables. This is done by
>>> copying the old swapper_pg_dir over a new page, adding the new mappings,
>>> and then switching to the newly built pg_dir (see `hotplug_paging` in
>>> arch/arm64/mmu.c). There might be better ways to to this: suggestions
>>> are more than welcome.
>>>
>>> - The stub function for `arch_remove_memory` has been removed for now; we
>>> are working in parallel on memory hot remove, and we plan to contribute
>>> it as a separate patch.
>>>
>>> - Corresponding Kconfig flags have been added;
>>>
>>> - Note that this patch does not work when NUMA is enabled; in fact,
>>> the function `memory_add_physaddr_to_nid` does not have an
>>> implementation when the NUMA flag is on: this function is supposed to
>>> return the nid the hotplugged memory should be associated with. However
>>> it is not really clear to us yet what the semantics of this function
>>> in the context of a NUMA system should be. A quick and dirty fix would
>>> be to always attach to the first available NUMA node.
>>>
>>> - In arch/arm64/mm/init.c `arch_add_memory`, we are doing a hack with the
>>> nomap memory block flags to satisfy preconditions and postconditions of
>>> `__add_pages` and postconditions of `arch_add_memory`. Compared to
>>> memory hotplug implementation for other architectures, the "issue"
>>> seems to be in the implemenation of `pfn_valid`. Suggestions on how
>>> to cleanly avoid this hack are welcome.
>>>
>>> This patchset can be tested by starting the kernel with the `mem=X` flag, where
>>> X is less than the total available physical memory and has to be multiple of
>>> MIN_MEMORY_BLOCK_SIZE. We also tested it on a customised version of QEMU
>>> capable to emulate physical hotplug on arm64 platform.
>>>
>>> To enable the feature the CONFIG_MEMORY_HOTPLUG compilation flag
>>> needs to be set to true. Then, after memory is physically hotplugged,
>>> the standard two steps to make it available (as also documented in
>>> Documentation/memory-hotplug.txt) are:
>>>
>>> (1) Notify memory hot-add
>>> echo '0xYY000000' > /sys/devices/system/memory/probe
>>>
>>> where 0xYY000000 is the first physical address of the new memory section.
>>>
>>> (2) Online new memory block(s)
>>> echo online > /sys/devices/system/memory/memoryXXX/state
>>>
>>> where XXX corresponds to the ids of newly added blocks.
>>>
>>> Onlining can optionally be automatic at hot-add notification by enabling
>>> the global flag:
>>> echo online > /sys/devices/system/memory/auto_online_blocks
>>> or by setting the corresponding config flag in the kernel build.
>>>
>>> Again, any comment is highly appreciated.
>>>
>>> [1] https://lkml.org/lkml/2016/11/17/49
>>> [2] https://lkml.org/lkml/2016/12/1/811
>>>
>>> Signed-off-by: Maciej Bielski <m.bielski@virtualopensystems.com>
>>> Signed-off-by: Andrea Reale <ar@linux.vnet.ibm.com>
>>> ---
>>> arch/arm64/Kconfig | 4 +--
>>> arch/arm64/include/asm/mmu.h | 3 +++
>>> arch/arm64/mm/init.c | 58 +++++++++++++++++++++++++++++++-------------
>>> arch/arm64/mm/mmu.c | 24 ++++++++++++++++++
>>> include/linux/memblock.h | 1 +
>>> mm/memblock.c | 10 ++++++++
>>> 6 files changed, 80 insertions(+), 20 deletions(-)
>>>
>>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>>> index 2482fdd..bd8ddf2 100644
>>> --- a/arch/arm64/Kconfig
>>> +++ b/arch/arm64/Kconfig
>>> @@ -577,9 +577,7 @@ config HOTPLUG_CPU
>>> can be controlled through /sys/devices/system/cpu.
>>>
>>> config ARCH_ENABLE_MEMORY_HOTPLUG
>>> - def_bool y
>>> -
>>> -config ARCH_ENABLE_MEMORY_HOTREMOVE
>>> + depends on !NUMA
>>> def_bool y
>>>
>>> # Common NUMA Features
>>> diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h
>>> index 8d9fce0..2499745 100644
>>> --- a/arch/arm64/include/asm/mmu.h
>>> +++ b/arch/arm64/include/asm/mmu.h
>>> @@ -36,5 +36,8 @@ extern void create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys,
>>> unsigned long virt, phys_addr_t size,
>>> pgprot_t prot, bool allow_block_mappings);
>>> extern void *fixmap_remap_fdt(phys_addr_t dt_phys);
>>> +#ifdef CONFIG_MEMORY_HOTPLUG
>>> +extern void hotplug_paging(phys_addr_t start, phys_addr_t size);
>>> +#endif
>>>
>>> #endif
>>> diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
>>> index 687d087..a7c740e 100644
>>> --- a/arch/arm64/mm/init.c
>>> +++ b/arch/arm64/mm/init.c
>>> @@ -544,37 +544,61 @@ int arch_add_memory(int nid, u64 start, u64 size, bool for_device)
>>> struct zone *zone;
>>> unsigned long start_pfn = start >> PAGE_SHIFT;
>>> unsigned long nr_pages = size >> PAGE_SHIFT;
>>> + unsigned long end_pfn = start_pfn + nr_pages;
>>> + unsigned long max_sparsemem_pfn = 1UL << (MAX_PHYSMEM_BITS-PAGE_SHIFT);
>>> + unsigned long pfn;
>>> int ret;
>>>
>>> + if (end_pfn > max_sparsemem_pfn) {
>>> + pr_err("end_pfn too big");
>>> + return -1;
>>> + }
>>> + hotplug_paging(start, size);
>>> +
>>> + /*
>>> + * Mark all the page range as unsuable.
>>> + * This is needed because __add_section (within __add_pages)
>>> + * wants pfn_valid to be false, and in arm64 pfn falid is implemented
>>> + * by just checking at the nomap flag for existing blocks
>>> + */
>>> + memblock_mark_nomap(start, size);
>>> +
>>> pgdat = NODE_DATA(nid);
>>>
>>> zone = pgdat->node_zones +
>>> zone_for_memory(nid, start, size, ZONE_NORMAL, for_device);
>>> ret = __add_pages(nid, zone, start_pfn, nr_pages);
>>>
>>> - if (ret)
>>> - pr_warn("%s: Problem encountered in __add_pages() ret=%d\n",
>>> - __func__, ret);
>>> + /*
>>> + * Make the pages usable after they have been added.
>>> + * This will make pfn_valid return true
>>> + */
>>> + memblock_clear_nomap(start, size);
>>>
>>> - return ret;
>>> -}
>>> + /*
>>> + * This is a hack to avoid having to mix arch specific code into arch
>>> + * independent code. SetPageReserved is supposed to be called by __add_zone
>>> + * (within __add_section, within __add_pages). However, when it is called
>>> + * there, it assumes that pfn_valid returns true. For the way pfn_valid is
>>> + * implemented in arm64 (a check on the nomap flag), the only way to make
>>> + * this evaluate true inside __add_zone is to clear the nomap flags of
>>> + * blocks in architecture independent code.
>>> + *
>>> + * To avoid this, we set the Reserved flag here after we cleared the nomap
>>> + * flag in the line above.
>>> + */
>>> + for (pfn = start_pfn; pfn < start_pfn + nr_pages; pfn++) {
>>> + if (!pfn_valid(pfn))
>>> + continue;
>>>
>>> -#ifdef CONFIG_MEMORY_HOTREMOVE
>>> -int arch_remove_memory(u64 start, u64 size)
>>> -{
>>> - unsigned long start_pfn = start >> PAGE_SHIFT;
>>> - unsigned long nr_pages = size >> PAGE_SHIFT;
>>> - struct zone *zone;
>>> - int ret;
>>> + SetPageReserved(pfn_to_page(pfn));
>>> + }
>>>
>>> - zone = page_zone(pfn_to_page(start_pfn));
>>> - ret = __remove_pages(zone, start_pfn, nr_pages);
>>> if (ret)
>>> - pr_warn("%s: Problem encountered in __remove_pages() ret=%d\n",
>>> + pr_warn("%s: Problem encountered in __add_pages() ret=%d\n",
>>> __func__, ret);
>>>
>>> return ret;
>>> }
>>> #endif
>>> -#endif
>>>
>>> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
>>> index 05615a3..9efa7d1 100644
>>> --- a/arch/arm64/mm/mmu.c
>>> +++ b/arch/arm64/mm/mmu.c
>>> @@ -493,6 +493,30 @@ void __init paging_init(void)
>>> SWAPPER_DIR_SIZE - PAGE_SIZE);
>>> }
>>>
>>> +#ifdef CONFIG_MEMORY_HOTPLUG
>>> +/*
>>> + * hotplug_paging() is used by memory hotplug to build new page tables
>>> + * for hot added memory.
>>> + */
>>> +void hotplug_paging(phys_addr_t start, phys_addr_t size)
>>> +{
>>> + phys_addr_t pgd_phys = pgd_pgtable_alloc();
>>> + pgd_t *pgd = pgd_set_fixmap(pgd_phys);
>>> +
>>> + memcpy(pgd, swapper_pg_dir, PAGE_SIZE);
>>> +
>>> + __create_pgd_mapping(pgd, start, __phys_to_virt(start), size,
>>> + PAGE_KERNEL, pgd_pgtable_alloc, false);
>>> +
>>> + cpu_replace_ttbr1(__va(pgd_phys));
>>> + memcpy(swapper_pg_dir, pgd, PAGE_SIZE);
>>> + cpu_replace_ttbr1(swapper_pg_dir);
>>> +
>>> + pgd_clear_fixmap();
>>> + memblock_free(pgd_phys, PAGE_SIZE);
>>> +}
>>> +#endif
>>> +
>>> /*
>>> * Check whether a kernel address is valid (derived from arch/x86/).
>>> */
>>> diff --git a/include/linux/memblock.h b/include/linux/memblock.h
>>> index 5b759c9..5f78257 100644
>>> --- a/include/linux/memblock.h
>>> +++ b/include/linux/memblock.h
>>> @@ -92,6 +92,7 @@ int memblock_mark_hotplug(phys_addr_t base, phys_addr_t size);
>>> int memblock_clear_hotplug(phys_addr_t base, phys_addr_t size);
>>> int memblock_mark_mirror(phys_addr_t base, phys_addr_t size);
>>> int memblock_mark_nomap(phys_addr_t base, phys_addr_t size);
>>> +int memblock_clear_nomap(phys_addr_t base, phys_addr_t size);
>>> ulong choose_memblock_flags(void);
>>>
>>> /* Low level functions */
>>> diff --git a/mm/memblock.c b/mm/memblock.c
>>> index 7608bc3..05e7676 100644
>>> --- a/mm/memblock.c
>>> +++ b/mm/memblock.c
>>> @@ -814,6 +814,16 @@ int __init_memblock memblock_mark_nomap(phys_addr_t base, phys_addr_t size)
>>> }
>>>
>>> /**
>>> + * memblock_clear_nomap - Clear a flag of MEMBLOCK_NOMAP memory region
>>> + * @base: the base phys addr of the region
>>> + * @size: the size of the region
>>> + */
>>> +int __init_memblock memblock_clear_nomap(phys_addr_t base, phys_addr_t size)
>>> +{
>>> + return memblock_setclr_flag(base, size, 0, MEMBLOCK_NOMAP);
>>> +}
>>> +
>>> +/**
>>> * __next_reserved_mem_region - next function for for_each_reserved_region()
>>> * @idx: pointer to u64 loop variable
>>> * @out_start: ptr to phys_addr_t for start address of the region, can be %NULL
>>>
>
> BR,
>
^ permalink raw reply
* [PATCH 02/11] clk: bcm2835: Register the DSI0/DSI1 pixel clocks.
From: Eric Anholt @ 2016-12-22 1:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161221231446.GA8288@codeaurora.org>
Stephen Boyd <sboyd@codeaurora.org> writes:
> On 12/14, Eric Anholt wrote:
>>
>> /* the gates */
>>
>> @@ -1890,8 +1976,18 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
>> if (IS_ERR(cprman->regs))
>> return PTR_ERR(cprman->regs);
>>
>> - cprman->osc_name = of_clk_get_parent_name(dev->of_node, 0);
>> - if (!cprman->osc_name)
>> + for (i = 0; i < ARRAY_SIZE(cprman_parent_names); i++) {
>> + cprman->real_parent_names[i] =
>> + of_clk_get_parent_name(dev->of_node, i);
>> + }
>
> Can we use of_clk_parent_fill() here? Or do we need to support
> holes in the parent array? If it's the latter please add a
> comment so we don't mistakenly change this later.
It looks like that will work fine. We'll only be missing parents from
the end of the array.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 832 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161221/0343dbad/attachment.sig>
^ permalink raw reply
* [PATCH 2/2] clk: hi3660: Clock driver support for Hisilicon hi3660 SoC
From: zhangfei @ 2016-12-22 2:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161221232551.GB8288@codeaurora.org>
Hi, Stephen
Thanks for the suggestion.
On 2016?12?22? 07:25, Stephen Boyd wrote:
> On 12/15, Zhangfei Gao wrote:
>> Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
> Add some commit text here?
OK
>
>> diff --git a/drivers/clk/hisilicon/clk-hi3660.c b/drivers/clk/hisilicon/clk-hi3660.c
>> new file mode 100644
>> index 0000000..42ca47d
>> --- /dev/null
>> +++ b/drivers/clk/hisilicon/clk-hi3660.c
>> @@ -0,0 +1,601 @@
>> +/*
>> + * Copyright (c) 2016-2017 Linaro Ltd.
>> + * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + */
>> +
>> +#include <dt-bindings/clock/hi3660-clock.h>
>> +#include <linux/clk-provider.h>
>> +#include <linux/module.h>
> This isn't needed.
>
>> +#include <linux/of_device.h>
>> +#include <linux/platform_device.h>
>> +#include "clk.h"
>> +
> [...]
>> +
>> +static int hi3660_clk_probe(struct platform_device *pdev)
>> +{
>> + struct device *dev = &pdev->dev;
>> + struct device_node *np = pdev->dev.of_node;
>> + const struct of_device_id *of_id;
>> + enum hi3660_clk_type type;
>> +
>> + of_id = of_match_device(hi3660_clk_match_table, dev);
>> + if (!of_id)
>> + return -EINVAL;
>> +
>> + type = (enum hi3660_clk_type)of_id->data;
> Use of_device_get_match_data() instead please.
Yes, this is simpler.
>
>> +
>> + switch (type) {
>> + case HI3660_CRGCTRL:
>> + hi3660_clk_crgctrl_init(np);
>> + break;
>> + case HI3660_PCTRL:
>> + hi3660_clk_pctrl_init(np);
>> + break;
>> + case HI3660_PMUCTRL:
>> + hi3660_clk_pmuctrl_init(np);
>> + break;
>> + case HI3660_SCTRL:
>> + hi3660_clk_sctrl_init(np);
>> + break;
>> + case HI3660_IOMCU:
>> + hi3660_clk_iomcu_init(np);
>> + break;
> This "multi-device" driver design is sort of odd. Why not have
> different files and struct drivers for the different devices in
> the system that are clock controllers? I don't really understand
> why we're controlling the devices with one struct driver
> instance. Is something shared between the devices?
Do you mean put in different .c / drivers?
They have to be put in the same file, since the parent / child relate to
each other.
They are for the same chip, but some put in different region for
privilege control.
>
>> + default:
>> + break;
>> + }
>> + return 0;
>> +}
> [...]
>> +
>> +MODULE_LICENSE("GPL");
>> +MODULE_ALIAS("platform:hi3660-clk");
>> +MODULE_DESCRIPTION("HiSilicon Hi3660 Clock Driver");
>
> You can drop these MODULE_* things as they're not going to be
> used in builtin only code.
ok, got it.
Thanks
^ permalink raw reply
* [PATCH v3 3/4] ARM: Add support for CONFIG_DEBUG_VIRTUAL
From: Laura Abbott @ 2016-12-22 2:40 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161209233628.6642-4-f.fainelli@gmail.com>
On 12/09/2016 03:36 PM, Florian Fainelli wrote:
> x86 has an option: CONFIG_DEBUG_VIRTUAL to do additional checks on
> virt_to_phys calls. The goal is to catch users who are calling
> virt_to_phys on non-linear addresses immediately. This includes caller
> using __virt_to_phys() on image addresses instead of __pa_symbol(). This
> is a generally useful debug feature to spot bad code (particulary in
> drivers).
>
> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
> ---
> arch/arm/Kconfig | 1 +
> arch/arm/include/asm/memory.h | 16 ++++++++++++--
> arch/arm/mm/Makefile | 1 +
> arch/arm/mm/physaddr.c | 51 +++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 67 insertions(+), 2 deletions(-)
> create mode 100644 arch/arm/mm/physaddr.c
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index b5d529fdffab..5e66173c5787 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -2,6 +2,7 @@ config ARM
> bool
> default y
> select ARCH_CLOCKSOURCE_DATA
> + select ARCH_HAS_DEBUG_VIRTUAL
> select ARCH_HAS_DEVMEM_IS_ALLOWED
> select ARCH_HAS_ELF_RANDOMIZE
> select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
> diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
> index bee7511c5098..d90300193adf 100644
> --- a/arch/arm/include/asm/memory.h
> +++ b/arch/arm/include/asm/memory.h
> @@ -213,7 +213,7 @@ extern const void *__pv_table_begin, *__pv_table_end;
> : "r" (x), "I" (__PV_BITS_31_24) \
> : "cc")
>
> -static inline phys_addr_t __virt_to_phys(unsigned long x)
> +static inline phys_addr_t __virt_to_phys_nodebug(unsigned long x)
> {
> phys_addr_t t;
>
> @@ -245,7 +245,7 @@ static inline unsigned long __phys_to_virt(phys_addr_t x)
> #define PHYS_OFFSET PLAT_PHYS_OFFSET
> #define PHYS_PFN_OFFSET ((unsigned long)(PHYS_OFFSET >> PAGE_SHIFT))
>
> -static inline phys_addr_t __virt_to_phys(unsigned long x)
> +static inline phys_addr_t __virt_to_phys_nodebug(unsigned long x)
> {
> return (phys_addr_t)x - PAGE_OFFSET + PHYS_OFFSET;
> }
> @@ -261,6 +261,16 @@ static inline unsigned long __phys_to_virt(phys_addr_t x)
> ((((unsigned long)(kaddr) - PAGE_OFFSET) >> PAGE_SHIFT) + \
> PHYS_PFN_OFFSET)
>
> +#define __pa_symbol_nodebug(x) __virt_to_phys_nodebug((x))
> +
> +#ifdef CONFIG_DEBUG_VIRTUAL
> +extern phys_addr_t __virt_to_phys(unsigned long x);
> +extern phys_addr_t __phys_addr_symbol(unsigned long x);
> +#else
> +#define __virt_to_phys(x) __virt_to_phys_nodebug(x)
> +#define __phys_addr_symbol(x) __pa_symbol_nodebug(x)
> +#endif
> +
> /*
> * These are *only* valid on the kernel direct mapped RAM memory.
> * Note: Drivers should NOT use these. They are the wrong
> @@ -283,9 +293,11 @@ static inline void *phys_to_virt(phys_addr_t x)
> * Drivers should NOT use these either.
> */
> #define __pa(x) __virt_to_phys((unsigned long)(x))
> +#define __pa_symbol(x) __phys_addr_symbol(RELOC_HIDE((unsigned long)(x), 0))
> #define __va(x) ((void *)__phys_to_virt((phys_addr_t)(x)))
> #define pfn_to_kaddr(pfn) __va((phys_addr_t)(pfn) << PAGE_SHIFT)
>
> +
> extern long long arch_phys_to_idmap_offset;
>
> /*
> diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
> index e8698241ece9..b3dea80715b4 100644
> --- a/arch/arm/mm/Makefile
> +++ b/arch/arm/mm/Makefile
> @@ -14,6 +14,7 @@ endif
>
> obj-$(CONFIG_ARM_PTDUMP) += dump.o
> obj-$(CONFIG_MODULES) += proc-syms.o
> +obj-$(CONFIG_DEBUG_VIRTUAL) += physaddr.o
>
> obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o
> obj-$(CONFIG_HIGHMEM) += highmem.o
> diff --git a/arch/arm/mm/physaddr.c b/arch/arm/mm/physaddr.c
> new file mode 100644
> index 000000000000..0288760306ce
> --- /dev/null
> +++ b/arch/arm/mm/physaddr.c
> @@ -0,0 +1,51 @@
> +#include <linux/bug.h>
> +#include <linux/export.h>
> +#include <linux/types.h>
> +#include <linux/mmdebug.h>
> +#include <linux/mm.h>
> +
> +#include <asm/sections.h>
> +#include <asm/memory.h>
> +#include <asm/fixmap.h>
> +#include <asm/dma.h>
> +
> +#include "mm.h"
> +
> +static inline bool __virt_addr_valid(unsigned long x)
> +{
> + /* high_memory does not get immediately defined, and there
> + * are early callers of __pa() against PAGE_OFFSET, just catch
> + * these here, then do normal checks, with the exception of
> + * MAX_DMA_ADDRESS.
> + */
> + if ((x >= PAGE_OFFSET && !high_memory) ||
> + (x >= PAGE_OFFSET &&
> + high_memory && x < (unsigned long)high_memory) ||
> + x == MAX_DMA_ADDRESS)
> + return true;
This is difficult to read, it's easier to read if it's split out:
if (!high_memory && x >= PAGE_OFFSET)
return true;
if (high_memory && x >= PAGE_OFFSET && x < (unsigned long) high_memory)
return true;
if (x == MAX_DMA_ADDRESS)
return true;
I'm really not a fan of the check for MAX_DMA_ADDRESS. arm64 gets away
with this because it uses the asm-generic version of dma.h which sets
MAX_DMA_ADDRESS to PAGE_OFFSET. __pa(MAX_DMA_ADDRESS) is used a
bunch of places in the kernel as a lower limit for memblock
allocation. The implication seems to be that MAX_DMA_ADDRESS
corresponds to something that corresponds to a real physical address.
The existing code happens to work because it will simply retry the
allocation if without the lower bound.
I don't see a good way to fix this though. It doesn't look like
MAX_DMA_ADDRESS can be changed if it's actually going to be used
for DMA and there isn't a unified way to just get a physical address.
Thanks,
Laura
> +
> + return false;
> +}
> +
> +phys_addr_t __virt_to_phys(unsigned long x)
> +{
> + WARN(!__virt_addr_valid(x),
> + "virt_to_phys used for non-linear address: %pK (%pS)\n",
> + (void *)x,
> + (void *)x);
> +
> + return __virt_to_phys_nodebug(x);
> +}
> +EXPORT_SYMBOL(__virt_to_phys);
> +
> +phys_addr_t __phys_addr_symbol(unsigned long x)
> +{
> + /* This is bounds checking against the kernel image only.
> + * __pa_symbol should only be used on kernel symbol addresses.
> + */
> + VIRTUAL_BUG_ON(x < (unsigned long)KERNEL_START ||
> + x > (unsigned long)KERNEL_END);
> +
> + return __pa_symbol_nodebug(x);
> +}
> +EXPORT_SYMBOL(__phys_addr_symbol);
>
^ permalink raw reply
* [PATCH 1/2] soc: ti: Use remoteproc auto_boot feature
From: Suman Anna @ 2016-12-22 3:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481846632-4778-1-git-send-email-spjoshi@codeaurora.org>
Hi Sarang,
On 12/15/2016 06:03 PM, Sarangdhar Joshi wrote:
> The function wkup_m3_rproc_boot_thread waits for asynchronous
> firmware loading to complete successfully before calling
> rproc_boot(). The same can be achieved by just setting
> rproc->auto_boot flag. Change this. As a result this change
> removes wkup_m3_rproc_boot_thread and moves m3_ipc->sync_complete
> initialization to the wkup_m3_ipc_probe().
>
> Other than the current usage, the firmware_loading_complete is
> only used in rproc_del() where it's no longer needed. This
> change is in preparation for removing firmware_loading_complete
> completely.
Based on the comments so far, I am assuming that you are dropping this
series.
In any case, this series did break our PM stack. We definitely don't
want to auto-boot the wkup_m3_rproc device, that responsibility will
need to stay with the wkup_m3_ipc driver.
regards
Suman
>
> CC: Dave Gerlach <d-gerlach@ti.com>
> CC: Suman Anna <s-anna@ti.com>
> CC: Bjorn Andersson <bjorn.andersson@linaro.org>
> Signed-off-by: Sarangdhar Joshi <spjoshi@codeaurora.org>
> ---
>
> Hi Suman,
>
> Unfortunately, I don't have a TI device and couldn't test this
> change. Is it possible for you to test this change on TI device?
>
> Thanks in advance.
>
> Regards,
> Sarang
>
> drivers/remoteproc/wkup_m3_rproc.c | 2 +-
> drivers/soc/ti/wkup_m3_ipc.c | 35 ++---------------------------------
> 2 files changed, 3 insertions(+), 34 deletions(-)
>
> diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c
> index 18175d0..79ea022 100644
> --- a/drivers/remoteproc/wkup_m3_rproc.c
> +++ b/drivers/remoteproc/wkup_m3_rproc.c
> @@ -167,7 +167,7 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev)
> goto err;
> }
>
> - rproc->auto_boot = false;
> + rproc->auto_boot = true;
>
> wkupm3 = rproc->priv;
> wkupm3->rproc = rproc;
> diff --git a/drivers/soc/ti/wkup_m3_ipc.c b/drivers/soc/ti/wkup_m3_ipc.c
> index 8823cc8..31090d70 100644
> --- a/drivers/soc/ti/wkup_m3_ipc.c
> +++ b/drivers/soc/ti/wkup_m3_ipc.c
> @@ -17,7 +17,6 @@
>
> #include <linux/err.h>
> #include <linux/kernel.h>
> -#include <linux/kthread.h>
> #include <linux/interrupt.h>
> #include <linux/irq.h>
> #include <linux/module.h>
> @@ -365,22 +364,6 @@ void wkup_m3_ipc_put(struct wkup_m3_ipc *m3_ipc)
> }
> EXPORT_SYMBOL_GPL(wkup_m3_ipc_put);
>
> -static void wkup_m3_rproc_boot_thread(struct wkup_m3_ipc *m3_ipc)
> -{
> - struct device *dev = m3_ipc->dev;
> - int ret;
> -
> - wait_for_completion(&m3_ipc->rproc->firmware_loading_complete);
> -
> - init_completion(&m3_ipc->sync_complete);
> -
> - ret = rproc_boot(m3_ipc->rproc);
> - if (ret)
> - dev_err(dev, "rproc_boot failed\n");
> -
> - do_exit(0);
> -}
> -
> static int wkup_m3_ipc_probe(struct platform_device *pdev)
> {
> struct device *dev = &pdev->dev;
> @@ -388,7 +371,6 @@ static int wkup_m3_ipc_probe(struct platform_device *pdev)
> phandle rproc_phandle;
> struct rproc *m3_rproc;
> struct resource *res;
> - struct task_struct *task;
> struct wkup_m3_ipc *m3_ipc;
>
> m3_ipc = devm_kzalloc(dev, sizeof(*m3_ipc), GFP_KERNEL);
> @@ -402,6 +384,8 @@ static int wkup_m3_ipc_probe(struct platform_device *pdev)
> return PTR_ERR(m3_ipc->ipc_mem_base);
> }
>
> + init_completion(&m3_ipc->sync_complete);
> +
> irq = platform_get_irq(pdev, 0);
> if (!irq) {
> dev_err(&pdev->dev, "no irq resource\n");
> @@ -449,25 +433,10 @@ static int wkup_m3_ipc_probe(struct platform_device *pdev)
>
> m3_ipc->ops = &ipc_ops;
>
> - /*
> - * Wait for firmware loading completion in a thread so we
> - * can boot the wkup_m3 as soon as it's ready without holding
> - * up kernel boot
> - */
> - task = kthread_run((void *)wkup_m3_rproc_boot_thread, m3_ipc,
> - "wkup_m3_rproc_loader");
> -
> - if (IS_ERR(task)) {
> - dev_err(dev, "can't create rproc_boot thread\n");
> - goto err_put_rproc;
> - }
> -
> m3_ipc_state = m3_ipc;
>
> return 0;
>
> -err_put_rproc:
> - rproc_put(m3_rproc);
> err_free_mbox:
> mbox_free_channel(m3_ipc->mbox);
> return ret;
>
^ permalink raw reply
* [PATCH 0/5] Support for Marvell switches with integrated CPUs
From: Chris Packham @ 2016-12-22 4:13 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
.../bindings/arm/marvell/98dx3236-resume-ctrl.txt | 18 ++
.../devicetree/bindings/arm/marvell/98dx3236.txt | 10 +
.../pinctrl/marvell,armada-98dx3236-pinctrl.txt | 46 ++++
arch/arm/boot/dts/armada-xp-98dx3236.dtsi | 231 +++++++++++++++++++++
arch/arm/boot/dts/armada-xp-98dx3336.dtsi | 78 +++++++
arch/arm/boot/dts/armada-xp-98dx4251.dtsi | 78 +++++++
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 | 145 +++++++++++++
17 files changed, 1314 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
* [PATCH 1/5] clk: mvebu: support for 98DX3236 SoC
From: Chris Packham @ 2016-12-22 4:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161222041328.3303-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>
---
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 +++++++++++++++++++++++++++++++++
4 files changed, 280 insertions(+), 4 deletions(-)
create mode 100644 drivers/clk/mvebu/mv98dx3236-corediv.c
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
* [PATCH 2/5] arm: mvebu: support for SMP on 98DX3336 SoC
From: Chris Packham @ 2016-12-22 4:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161222041328.3303-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>
---
.../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 ++++++++++++++++++++++
5 files changed, 132 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/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..fadc81d0c051
--- /dev/null
+++ b/arch/arm/mach-mvebu/pmsu-98dx3236.c
@@ -0,0 +1,69 @@
+/**
+ * CPU resume support for 98DX4521 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 98DX4521 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
* [PATCH 3/5] pinctrl: mvebu: pinctrl driver for 98DX3236 SoC
From: Chris Packham @ 2016-12-22 4:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161222041328.3303-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>
---
.../pinctrl/marvell,armada-98dx3236-pinctrl.txt | 46 +++++++
drivers/pinctrl/mvebu/pinctrl-armada-xp.c | 145 +++++++++++++++++++++
2 files changed, 191 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..34c1e380adaa
--- /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"
+- 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), dev(bootcs)
+mpp6 6 gpio, dev(a2)
+mpp7 7 gpio, dev(ale0)
+mpp8 8 gpio, dev(ale1)
+mpp9 9 gpio, dev(ready0)
+mpp10 10 gpio, 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..2586903c59f0 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,124 @@ 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(0x4, "dev", "bootcs0", V_98DX3236_PLUS)),
+ MPP_MODE(6,
+ MPP_VAR_FUNCTION(0x0, "gpo", NULL, V_98DX3236_PLUS),
+ MPP_VAR_FUNCTION(0x4, "dev", "a2", V_98DX3236_PLUS)),
+ MPP_MODE(7,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_98DX3236_PLUS),
+ MPP_VAR_FUNCTION(0x4, "dev", "ale0", V_98DX3236_PLUS)),
+ MPP_MODE(8,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_98DX3236_PLUS),
+ MPP_VAR_FUNCTION(0x4, "dev", "ale1", V_98DX3236_PLUS)),
+ MPP_MODE(9,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_98DX3236_PLUS),
+ MPP_VAR_FUNCTION(0x4, "dev", "ready0", V_98DX3236_PLUS)),
+ MPP_MODE(10,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_98DX3236_PLUS),
+ 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 +497,10 @@ 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,
+ },
{ },
};
@@ -407,6 +533,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 +622,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
* [PATCH 4/5] arm: mvebu: Add device tree for 98DX3236 SoCs
From: Chris Packham @ 2016-12-22 4:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161222041328.3303-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>
---
.../devicetree/bindings/arm/marvell/98dx3236.txt | 10 +
arch/arm/boot/dts/armada-xp-98dx3236.dtsi | 231 +++++++++++++++++++++
arch/arm/boot/dts/armada-xp-98dx3336.dtsi | 78 +++++++
arch/arm/boot/dts/armada-xp-98dx4251.dtsi | 78 +++++++
4 files changed, 397 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..e7dc9b2dd90b
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/marvell/98dx3236.txt
@@ -0,0 +1,10 @@
+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: one of "marvell,armadaxp-98dx3236", "marvell,armadaxp-98dx3336"
+ or "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..bac53f8b44af
--- /dev/null
+++ b/arch/arm/boot/dts/armada-xp-98dx3236.dtsi
@@ -0,0 +1,231 @@
+/*
+ * 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";
+ };
+
+ 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";
+ };
+};
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..5d1da8513fae
--- /dev/null
+++ b/arch/arm/boot/dts/armada-xp-98dx4251.dtsi
@@ -0,0 +1,78 @@
+/*
+ * 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";
+ };
+ };
+ };
+};
--
2.11.0.24.ge6920cf
^ permalink raw reply related
* [PATCH 5/5] arm: mvebu: Add device tree for db-dxbc2 and db-xc3-24g4xg boards
From: Chris Packham @ 2016-12-22 4:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161222041328.3303-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>
---
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
* [PATCH v5 00/14] ACPI platform MSI support and its example mbigen
From: Hanjun Guo @ 2016-12-22 5:35 UTC (permalink / raw)
To: linux-arm-kernel
From: Hanjun Guo <hanjun.guo@linaro.org>
v4 -> v5:
- Add mbigen support back with tested on with Agustin's patchset,
and it's a good example of how ACPI platform MSI works
- rebased on top of lastest Linus tree (commit 52bce91 splice: reinstate SIGPIPE/EPIPE handling)
v3 -> v4:
- Drop mbi-gen patches to just submit platform msi support because
will rebase mbi-gen patches on top of Agustin's patchset, and discusion
is going there.
- Add a patch to support device topology such as NC(named componant, paltform device)
->SMMU->ITS which suggested by Lorenzo;
- rebased on top of Lorenzo's v9 of ACPI IORT ARM SMMU support;
- rebased on top of 4.9-rc7
v2 -> v3:
- Drop RFC tag
- Rebase against v4.9-rc2 and Lorenzo's v6 of ACPI IORT ARM SMMU support [1]
- Add 3 cleanup patches (patch 1, 2, 3)
- Drop arch_init call patch from last version
- Introduce a callback for platform device to set msi domain
- Introduce a new API to get paltform device's domain instead of
reusing the PCI one in previous version
- Add a patch to rework iort_node_get_id()
[1]: http://www.mail-archive.com/linux-kernel at vger.kernel.org/msg1251993.html
v1 -> v2:
- Fix the bug of if multi Interrupt() resoures in single _PRS,
we need to calculate all the irq numbers (I missed it in previous
version);
- Rebased on Marc's irq/irqchip-4.9 branch and Lorenzo's v5
SMMU patches (also Robin's SMMu patches)
- Add patch irqchip: mbigen: promote mbigen init.
With platform msi support landed in the kernel, and the introduction
of IORT for GICv3 ITS (PCI MSI) and SMMU, the framework for platform msi
is ready, this patch set add few patches to enable the ACPI platform
msi support.
For platform device connecting to ITS on arm platform, we have IORT
table with the named componant node to describe the mappings of paltform
device and ITS, so we can retrieve the dev id and find its parent
irqdomain (ITS) from IORT table (simlar with the ACPI ITS support).
The fisrt 3 patches are cleanups;
Patch 4,5 are refactoring its_pmsi_prepare() for both DT and ACPI
then retrieve the dev id from iort;
Patch 6,7 to create platform msi domain to ACPI case which scanned
the MADT table;
Patch 8,9,10,11 to setup the msi domain for platform device based
on IORT table.
Patch 12,13,14 convert dt based mbigen driver to support ACPI.
Teasted on Hisilicon D03/D05.
Happy holidays!
Thanks
Hanjun
Hanjun Guo (12):
ACPI: ARM64: IORT: minor cleanup for iort_match_node_callback()
irqchip: gic-v3-its: keep the head file include in alphabetic order
ACPI: ARM64: IORT: add missing comment for iort_dev_find_its_id()
irqchip: gicv3-its: platform-msi: refactor its_pmsi_prepare()
ACPI: platform-msi: retrieve dev id from IORT
irqchip: gicv3-its: platform-msi: refactor its_pmsi_init() to prepare
for ACPI
irqchip: gicv3-its: platform-msi: scan MADT to create platform msi
domain
ACPI: ARM64: IORT: rework iort_node_get_id()
ACPI: platform: setup MSI domain for ACPI based platform device
ACPI: ARM64: IORT: rework iort_node_get_id() for NC->SMMU->ITS case
msi: platform: make platform_msi_create_device_domain() ACPI aware
irqchip: mbigen: Add ACPI support
Kefeng Wang (2):
irqchip: mbigen: drop module owner
irqchip: mbigen: introduce mbigen_of_create_domain()
drivers/acpi/acpi_platform.c | 11 ++
drivers/acpi/arm64/iort.c | 138 ++++++++++++++++++++------
drivers/base/platform-msi.c | 3 +-
drivers/base/platform.c | 3 +
drivers/irqchip/irq-gic-v3-its-platform-msi.c | 106 +++++++++++++++-----
drivers/irqchip/irq-gic-v3-its.c | 3 +-
drivers/irqchip/irq-mbigen.c | 109 ++++++++++++++++----
include/linux/acpi_iort.h | 11 ++
include/linux/platform_device.h | 3 +
9 files changed, 309 insertions(+), 78 deletions(-)
--
1.7.12.4
^ permalink raw reply
* [PATCH v5 01/14] ACPI: ARM64: IORT: minor cleanup for iort_match_node_callback()
From: Hanjun Guo @ 2016-12-22 5:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482384922-21507-1-git-send-email-guohanjun@huawei.com>
From: Hanjun Guo <hanjun.guo@linaro.org>
Cleanup iort_match_node_callback() a little bit to reduce
some lines of code, aslo fix the indentation in iort_scan_node().
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Tomasz Nowicki <tn@semihalf.com>
---
drivers/acpi/arm64/iort.c | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index e0d2e6e..46e2d82 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -225,7 +225,7 @@ static struct acpi_iort_node *iort_scan_node(enum acpi_iort_node_type type,
if (iort_node->type == type &&
ACPI_SUCCESS(callback(iort_node, context)))
- return iort_node;
+ return iort_node;
iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node,
iort_node->length);
@@ -253,17 +253,15 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
void *context)
{
struct device *dev = context;
- acpi_status status;
+ acpi_status status = AE_NOT_FOUND;
if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT) {
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_device *adev = to_acpi_device_node(dev->fwnode);
struct acpi_iort_named_component *ncomp;
- if (!adev) {
- status = AE_NOT_FOUND;
+ if (!adev)
goto out;
- }
status = acpi_get_name(adev->handle, ACPI_FULL_PATHNAME, &buf);
if (ACPI_FAILURE(status)) {
@@ -289,8 +287,6 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
*/
status = pci_rc->pci_segment_number == pci_domain_nr(bus) ?
AE_OK : AE_NOT_FOUND;
- } else {
- status = AE_NOT_FOUND;
}
out:
return status;
--
1.7.12.4
^ permalink raw reply related
* [PATCH v5 02/14] irqchip: gic-v3-its: keep the head file include in alphabetic order
From: Hanjun Guo @ 2016-12-22 5:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482384922-21507-1-git-send-email-guohanjun@huawei.com>
From: Hanjun Guo <hanjun.guo@linaro.org>
The head file is strictly in alphabetic order now, so let's
be the rule breaker. As acpi_iort.h includes acpi.h so remove
the duplidate acpi.h inclusion as well.
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Tomasz Nowicki <tn@semihalf.com>
---
drivers/irqchip/irq-gic-v3-its.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 69b040f..f471939 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -15,14 +15,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <linux/acpi.h>
+#include <linux/acpi_iort.h>
#include <linux/bitmap.h>
#include <linux/cpu.h>
#include <linux/delay.h>
#include <linux/dma-iommu.h>
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
-#include <linux/acpi_iort.h>
#include <linux/log2.h>
#include <linux/mm.h>
#include <linux/msi.h>
--
1.7.12.4
^ permalink raw reply related
* [PATCH v5 03/14] ACPI: ARM64: IORT: add missing comment for iort_dev_find_its_id()
From: Hanjun Guo @ 2016-12-22 5:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482384922-21507-1-git-send-email-guohanjun@huawei.com>
From: Hanjun Guo <hanjun.guo@linaro.org>
We are missing req_id's comment for iort_dev_find_its_id(),
add it back.
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Tomasz Nowicki <tn@semihalf.com>
---
drivers/acpi/arm64/iort.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 46e2d82..174e983 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -446,6 +446,7 @@ u32 iort_msi_map_rid(struct device *dev, u32 req_id)
/**
* iort_dev_find_its_id() - Find the ITS identifier for a device
* @dev: The device.
+ * @req_id: Device's Requster ID
* @idx: Index of the ITS identifier list.
* @its_id: ITS identifier.
*
--
1.7.12.4
^ permalink raw reply related
* [PATCH v5 04/14] irqchip: gicv3-its: platform-msi: refactor its_pmsi_prepare()
From: Hanjun Guo @ 2016-12-22 5:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482384922-21507-1-git-send-email-guohanjun@huawei.com>
From: Hanjun Guo <hanjun.guo@linaro.org>
Adding ACPI support for platform MSI, we need to retrieve the
dev id in ACPI way instead of device tree, we already have
a well formed function its_pmsi_prepare() to get the dev id
but it's OF dependent, so collect OF related code and put them
into a single function to make its_pmsi_prepare() more friendly
to ACPI later.
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Sinan Kaya <okaya@codeaurora.org>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
---
drivers/irqchip/irq-gic-v3-its-platform-msi.c | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3-its-platform-msi.c b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
index 470b4aa..3c94278 100644
--- a/drivers/irqchip/irq-gic-v3-its-platform-msi.c
+++ b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
@@ -24,15 +24,11 @@
.name = "ITS-pMSI",
};
-static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
- int nvec, msi_alloc_info_t *info)
+static int of_pmsi_get_dev_id(struct irq_domain *domain, struct device *dev,
+ u32 *dev_id)
{
- struct msi_domain_info *msi_info;
- u32 dev_id;
int ret, index = 0;
- msi_info = msi_get_domain_info(domain->parent);
-
/* Suck the DeviceID out of the msi-parent property */
do {
struct of_phandle_args args;
@@ -43,11 +39,24 @@ static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
if (args.np == irq_domain_get_of_node(domain)) {
if (WARN_ON(args.args_count != 1))
return -EINVAL;
- dev_id = args.args[0];
+ *dev_id = args.args[0];
break;
}
} while (!ret);
+ return ret;
+}
+
+static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
+ int nvec, msi_alloc_info_t *info)
+{
+ struct msi_domain_info *msi_info;
+ u32 dev_id;
+ int ret;
+
+ msi_info = msi_get_domain_info(domain->parent);
+
+ ret = of_pmsi_get_dev_id(domain, dev, &dev_id);
if (ret)
return ret;
--
1.7.12.4
^ permalink raw reply related
* [PATCH v5 05/14] ACPI: platform-msi: retrieve dev id from IORT
From: Hanjun Guo @ 2016-12-22 5:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482384922-21507-1-git-send-email-guohanjun@huawei.com>
From: Hanjun Guo <hanjun.guo@linaro.org>
For devices connecting to ITS, it needs dev id to identify
itself, and this dev id is represented in the IORT table in
named componant node [1] for platform devices, so in this
patch we will scan the IORT to retrieve device's dev id.
Introduce iort_pmsi_get_dev_id() with pointer dev passed
in for that purpose.
[1]: https://static.docs.arm.com/den0049/b/DEN0049B_IO_Remapping_Table.pdf
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Sinan Kaya <okaya@codeaurora.org>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
---
drivers/acpi/arm64/iort.c | 26 ++++++++++++++++++++++++++
drivers/irqchip/irq-gic-v3-its-platform-msi.c | 4 +++-
include/linux/acpi_iort.h | 8 ++++++++
3 files changed, 37 insertions(+), 1 deletion(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 174e983..ab7bae7 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -444,6 +444,32 @@ u32 iort_msi_map_rid(struct device *dev, u32 req_id)
}
/**
+ * iort_pmsi_get_dev_id() - Get the device id for a device
+ * @dev: The device for which the mapping is to be done.
+ * @dev_id: The device ID found.
+ *
+ * Returns: 0 for successful find a dev id, errors otherwise
+ */
+int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id)
+{
+ struct acpi_iort_node *node;
+
+ if (!iort_table)
+ return -ENODEV;
+
+ node = iort_find_dev_node(dev);
+ if (!node) {
+ dev_err(dev, "can't find related IORT node\n");
+ return -ENODEV;
+ }
+
+ if(!iort_node_get_id(node, dev_id, IORT_MSI_TYPE, 0))
+ return -ENODEV;
+
+ return 0;
+}
+
+/**
* iort_dev_find_its_id() - Find the ITS identifier for a device
* @dev: The device.
* @req_id: Device's Requster ID
diff --git a/drivers/irqchip/irq-gic-v3-its-platform-msi.c b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
index 3c94278..16587a9 100644
--- a/drivers/irqchip/irq-gic-v3-its-platform-msi.c
+++ b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
@@ -15,6 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/acpi_iort.h>
#include <linux/device.h>
#include <linux/msi.h>
#include <linux/of.h>
@@ -56,7 +57,8 @@ static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
msi_info = msi_get_domain_info(domain->parent);
- ret = of_pmsi_get_dev_id(domain, dev, &dev_id);
+ ret = dev->of_node ? of_pmsi_get_dev_id(domain, dev, &dev_id) :
+ iort_pmsi_get_dev_id(dev, &dev_id);
if (ret)
return ret;
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index 77e0809..ef99fd52 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -33,6 +33,7 @@
void acpi_iort_init(void);
bool iort_node_match(u8 type);
u32 iort_msi_map_rid(struct device *dev, u32 req_id);
+int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id);
struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id);
/* IOMMU interface */
void iort_set_dma_mask(struct device *dev);
@@ -42,9 +43,16 @@ static inline void acpi_iort_init(void) { }
static inline bool iort_node_match(u8 type) { return false; }
static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
{ return req_id; }
+
static inline struct irq_domain *iort_get_device_domain(struct device *dev,
u32 req_id)
{ return NULL; }
+
+static inline int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id)
+{
+ return -ENODEV;
+}
+
/* IOMMU interface */
static inline void iort_set_dma_mask(struct device *dev) { }
static inline
--
1.7.12.4
^ permalink raw reply related
* [PATCH v5 06/14] irqchip: gicv3-its: platform-msi: refactor its_pmsi_init() to prepare for ACPI
From: Hanjun Guo @ 2016-12-22 5:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482384922-21507-1-git-send-email-guohanjun@huawei.com>
From: Hanjun Guo <hanjun.guo@linaro.org>
Introduce its_pmsi_init_one() to refactor the code to isolate
ACPI&DT common code to prepare for ACPI later.
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Sinan Kaya <okaya@codeaurora.org>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
---
drivers/irqchip/irq-gic-v3-its-platform-msi.c | 45 ++++++++++++++++-----------
1 file changed, 27 insertions(+), 18 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3-its-platform-msi.c b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
index 16587a9..ff72704 100644
--- a/drivers/irqchip/irq-gic-v3-its-platform-msi.c
+++ b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
@@ -84,34 +84,43 @@ static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
{},
};
-static int __init its_pmsi_init(void)
+static int __init its_pmsi_init_one(struct fwnode_handle *fwnode,
+ const char *name)
{
- struct device_node *np;
struct irq_domain *parent;
+ parent = irq_find_matching_fwnode(fwnode, DOMAIN_BUS_NEXUS);
+ if (!parent || !msi_get_domain_info(parent)) {
+ pr_err("%s: unable to locate ITS domain\n", name);
+ return -ENXIO;
+ }
+
+ if (!platform_msi_create_irq_domain(fwnode, &its_pmsi_domain_info,
+ parent)) {
+ pr_err("%s: unable to create platform domain\n", name);
+ return -ENXIO;
+ }
+
+ pr_info("Platform MSI: %s domain created\n", name);
+ return 0;
+}
+
+static void __init its_pmsi_of_init(void)
+{
+ struct device_node *np;
+
for (np = of_find_matching_node(NULL, its_device_id); np;
np = of_find_matching_node(np, its_device_id)) {
if (!of_property_read_bool(np, "msi-controller"))
continue;
- parent = irq_find_matching_host(np, DOMAIN_BUS_NEXUS);
- if (!parent || !msi_get_domain_info(parent)) {
- pr_err("%s: unable to locate ITS domain\n",
- np->full_name);
- continue;
- }
-
- if (!platform_msi_create_irq_domain(of_node_to_fwnode(np),
- &its_pmsi_domain_info,
- parent)) {
- pr_err("%s: unable to create platform domain\n",
- np->full_name);
- continue;
- }
-
- pr_info("Platform MSI: %s domain created\n", np->full_name);
+ its_pmsi_init_one(of_node_to_fwnode(np), np->full_name);
}
+}
+static int __init its_pmsi_init(void)
+{
+ its_pmsi_of_init();
return 0;
}
early_initcall(its_pmsi_init);
--
1.7.12.4
^ permalink raw reply related
* [PATCH v5 07/14] irqchip: gicv3-its: platform-msi: scan MADT to create platform msi domain
From: Hanjun Guo @ 2016-12-22 5:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482384922-21507-1-git-send-email-guohanjun@huawei.com>
From: Hanjun Guo <hanjun.guo@linaro.org>
With the introduction of its_pmsi_init_one(), we can add some code
on top for ACPI support of platform MSI.
We are scanning the MADT table to get the ITS entry(ies), then use
the information to create the platform msi domain for devices connect
to it, just like the PCI MSI for ITS did.
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Sinan Kaya <okaya@codeaurora.org>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
---
drivers/irqchip/irq-gic-v3-its-platform-msi.c | 36 +++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/drivers/irqchip/irq-gic-v3-its-platform-msi.c b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
index ff72704..0be0437 100644
--- a/drivers/irqchip/irq-gic-v3-its-platform-msi.c
+++ b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
@@ -105,6 +105,41 @@ static int __init its_pmsi_init_one(struct fwnode_handle *fwnode,
return 0;
}
+#ifdef CONFIG_ACPI
+static int __init
+its_pmsi_parse_madt(struct acpi_subtable_header *header,
+ const unsigned long end)
+{
+ struct acpi_madt_generic_translator *its_entry;
+ struct fwnode_handle *domain_handle;
+ const char *node_name;
+ int err = -ENXIO;
+
+ its_entry = (struct acpi_madt_generic_translator *)header;
+ node_name = kasprintf(GFP_KERNEL, "ITS at 0x%lx",
+ (long)its_entry->base_address);
+ domain_handle = iort_find_domain_token(its_entry->translation_id);
+ if (!domain_handle) {
+ pr_err("%s: Unable to locate ITS domain handle\n", node_name);
+ goto out;
+ }
+
+ err = its_pmsi_init_one(domain_handle, node_name);
+
+out:
+ kfree(node_name);
+ return err;
+}
+
+static void __init its_acpi_pmsi_init(void)
+{
+ acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
+ its_pmsi_parse_madt, 0);
+}
+#else
+static inline void its_acpi_pmsi_init(void) { }
+#endif
+
static void __init its_pmsi_of_init(void)
{
struct device_node *np;
@@ -121,6 +156,7 @@ static void __init its_pmsi_of_init(void)
static int __init its_pmsi_init(void)
{
its_pmsi_of_init();
+ its_acpi_pmsi_init();
return 0;
}
early_initcall(its_pmsi_init);
--
1.7.12.4
^ permalink raw reply related
* [PATCH v5 08/14] ACPI: ARM64: IORT: rework iort_node_get_id()
From: Hanjun Guo @ 2016-12-22 5:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482384922-21507-1-git-send-email-guohanjun@huawei.com>
From: Hanjun Guo <hanjun.guo@linaro.org>
iort_node_get_id() has two output, one is the mapped ids,
the other is the referenced parent node which is returned
from the function.
For now we need a API just return its parent node for
single mapping, so just update this function slightly then
reuse it later.
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
---
drivers/acpi/arm64/iort.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index ab7bae7..bc68d93 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -347,7 +347,8 @@ struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
if (map[index].flags & ACPI_IORT_ID_SINGLE_MAPPING) {
if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT ||
node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
- *id_out = map[index].output_base;
+ if (id_out)
+ *id_out = map[index].output_base;
return parent;
}
}
--
1.7.12.4
^ permalink raw reply related
* [PATCH v5 09/14] ACPI: platform: setup MSI domain for ACPI based platform device
From: Hanjun Guo @ 2016-12-22 5:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482384922-21507-1-git-send-email-guohanjun@huawei.com>
From: Hanjun Guo <hanjun.guo@linaro.org>
With the platform msi domain created, we can set up the msi domain
for a platform device when it's probed.
In order to do that, we need to get the domain that the platform
device connecting to, so the iort_get_platform_device_domain() is
introduced to retrieve the domain from iort.
After the domain is retrieved, we need a proper way to set the
domain to paltform device, as some platform devices such as an
irqchip needs the msi irqdomain to be the interrupt parent domain,
we need to get irqdomain before platform device is probed but after
the platform device is allocated, so introduce a callback (pre_add_cb)
in pdevinfo to prepare firmware related information which is needed
for device probe, then set the msi domain in that callback.
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
---
drivers/acpi/acpi_platform.c | 11 +++++++++++
drivers/acpi/arm64/iort.c | 43 +++++++++++++++++++++++++++++++++++++++++
drivers/base/platform.c | 3 +++
include/linux/acpi_iort.h | 3 +++
include/linux/platform_device.h | 3 +++
5 files changed, 63 insertions(+)
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
index b4c1a6a..5d8d61b4 100644
--- a/drivers/acpi/acpi_platform.c
+++ b/drivers/acpi/acpi_platform.c
@@ -12,6 +12,7 @@
*/
#include <linux/acpi.h>
+#include <linux/acpi_iort.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/kernel.h>
@@ -48,6 +49,15 @@ static void acpi_platform_fill_resource(struct acpi_device *adev,
}
/**
+ * acpi_platform_pre_add_cb - callback before platform device is added, to
+ * prepare firmware related information which is needed for device probe
+ */
+static void acpi_platform_pre_add_cb(struct device *dev)
+{
+ acpi_configure_pmsi_domain(dev);
+}
+
+/**
* acpi_create_platform_device - Create platform device for ACPI device node
* @adev: ACPI device node to create a platform device for.
* @properties: Optional collection of build-in properties.
@@ -109,6 +119,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
pdevinfo.num_res = count;
pdevinfo.fwnode = acpi_fwnode_handle(adev);
pdevinfo.properties = properties;
+ pdevinfo.pre_add_cb = acpi_platform_pre_add_cb;
if (acpi_dma_supported(adev))
pdevinfo.dma_mask = DMA_BIT_MASK(32);
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index bc68d93..6b72fcb 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -527,6 +527,49 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
}
+/**
+ * iort_get_platform_device_domain() - Find MSI domain related to a
+ * platform device
+ * @dev: the dev pointer associated with the platform device
+ *
+ * Returns: the MSI domain for this device, NULL otherwise
+ */
+static struct irq_domain *iort_get_platform_device_domain(struct device *dev)
+{
+ struct acpi_iort_node *node, *msi_parent;
+ struct fwnode_handle *iort_fwnode;
+ struct acpi_iort_its_group *its;
+
+ /* find its associated iort node */
+ node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
+ iort_match_node_callback, dev);
+ if (!node)
+ return NULL;
+
+ /* then find its msi parent node */
+ msi_parent = iort_node_get_id(node, NULL, IORT_MSI_TYPE, 0);
+ if (!msi_parent)
+ return NULL;
+
+ /* Move to ITS specific data */
+ its = (struct acpi_iort_its_group *)msi_parent->node_data;
+
+ iort_fwnode = iort_find_domain_token(its->identifiers[0]);
+ if (!iort_fwnode)
+ return NULL;
+
+ return irq_find_matching_fwnode(iort_fwnode, DOMAIN_BUS_PLATFORM_MSI);
+}
+
+void acpi_configure_pmsi_domain(struct device *dev)
+{
+ struct irq_domain *msi_domain;
+
+ msi_domain = iort_get_platform_device_domain(dev);
+ if (msi_domain)
+ dev_set_msi_domain(dev, msi_domain);
+}
+
static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
{
u32 *rid = data;
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index c4af003..3e68f31 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -537,6 +537,9 @@ struct platform_device *platform_device_register_full(
goto err;
}
+ if (pdevinfo->pre_add_cb)
+ pdevinfo->pre_add_cb(&pdev->dev);
+
ret = platform_device_add(pdev);
if (ret) {
err:
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index ef99fd52..33f5ac3 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -38,6 +38,7 @@
/* IOMMU interface */
void iort_set_dma_mask(struct device *dev);
const struct iommu_ops *iort_iommu_configure(struct device *dev);
+void acpi_configure_pmsi_domain(struct device *dev);
#else
static inline void acpi_iort_init(void) { }
static inline bool iort_node_match(u8 type) { return false; }
@@ -58,6 +59,8 @@ static inline void iort_set_dma_mask(struct device *dev) { }
static inline
const struct iommu_ops *iort_iommu_configure(struct device *dev)
{ return NULL; }
+
+static inline void acpi_configure_pmsi_domain(struct device *dev) { }
#endif
#define IORT_ACPI_DECLARE(name, table_id, fn) \
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
index 98c2a7c..280d366fb 100644
--- a/include/linux/platform_device.h
+++ b/include/linux/platform_device.h
@@ -74,6 +74,9 @@ struct platform_device_info {
u64 dma_mask;
struct property_entry *properties;
+
+ /* preparation callback before the platform device is added */
+ void (*pre_add_cb)(struct device *);
};
extern struct platform_device *platform_device_register_full(
const struct platform_device_info *pdevinfo);
--
1.7.12.4
^ permalink raw reply related
* [PATCH v5 10/14] ACPI: ARM64: IORT: rework iort_node_get_id() for NC->SMMU->ITS case
From: Hanjun Guo @ 2016-12-22 5:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482384922-21507-1-git-send-email-guohanjun@huawei.com>
From: Hanjun Guo <hanjun.guo@linaro.org>
iort_node_get_id() for now only support NC(named componant)->SMMU
or NC->ITS cases, we also have other device topology such NC->
SMMU->ITS, so rework iort_node_get_id() for those cases.
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
---
drivers/acpi/arm64/iort.c | 59 ++++++++++++++++++++++++++---------------------
1 file changed, 33 insertions(+), 26 deletions(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 6b72fcb..9b3f268 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -292,22 +292,28 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
return status;
}
-static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
- u32 *rid_out)
+static int iort_id_single_map(struct acpi_iort_id_mapping *map, u8 type,
+ u32 *rid_out)
{
/* Single mapping does not care for input id */
if (map->flags & ACPI_IORT_ID_SINGLE_MAPPING) {
if (type == ACPI_IORT_NODE_NAMED_COMPONENT ||
type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
- *rid_out = map->output_base;
+ if (rid_out)
+ *rid_out = map->output_base;
return 0;
}
pr_warn(FW_BUG "[map %p] SINGLE MAPPING flag not allowed for node type %d, skipping ID map\n",
map, type);
- return -ENXIO;
}
+ return -ENXIO;
+}
+
+static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
+ u32 *rid_out)
+{
if (rid_in < map->input_base ||
(rid_in >= map->input_base + map->id_count))
return -ENXIO;
@@ -324,33 +330,34 @@ struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
struct acpi_iort_node *parent;
struct acpi_iort_id_mapping *map;
- if (!node->mapping_offset || !node->mapping_count ||
- index >= node->mapping_count)
- return NULL;
-
- map = ACPI_ADD_PTR(struct acpi_iort_id_mapping, node,
- node->mapping_offset);
+ while (node) {
+ if (!node->mapping_offset || !node->mapping_count ||
+ index >= node->mapping_count)
+ return NULL;
- /* Firmware bug! */
- if (!map->output_reference) {
- pr_err(FW_BUG "[node %p type %d] ID map has NULL parent reference\n",
- node, node->type);
- return NULL;
- }
+ map = ACPI_ADD_PTR(struct acpi_iort_id_mapping, node,
+ node->mapping_offset);
- parent = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
- map->output_reference);
+ /* Firmware bug! */
+ if (!map->output_reference) {
+ pr_err(FW_BUG "[node %p type %d] ID map has NULL parent reference\n",
+ node, node->type);
+ return NULL;
+ }
- if (!(IORT_TYPE_MASK(parent->type) & type_mask))
- return NULL;
+ parent = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
+ map->output_reference);
- if (map[index].flags & ACPI_IORT_ID_SINGLE_MAPPING) {
- if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT ||
- node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
- if (id_out)
- *id_out = map[index].output_base;
- return parent;
+ /* go upstream to find its parent */
+ if (!(IORT_TYPE_MASK(parent->type) & type_mask)) {
+ node = parent;
+ continue;
}
+
+ if (iort_id_single_map(&map[index], node->type, id_out))
+ break;
+
+ return parent;
}
return NULL;
--
1.7.12.4
^ permalink raw reply related
* [PATCH v5 11/14] msi: platform: make platform_msi_create_device_domain() ACPI aware
From: Hanjun Guo @ 2016-12-22 5:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482384922-21507-1-git-send-email-guohanjun@huawei.com>
From: Hanjun Guo <hanjun.guo@linaro.org>
With the platform msi domain created for ITS, irqchip such as
mbi-gen connecting ITS, which needs ctreate its own irqdomain.
Fortunately with the platform msi support upstreamed by Marc,
we just need to add minor code to make it run properly.
platform_msi_create_device_domain() is almost ready for ACPI use
except of_node_to_fwnode() is for dt only, make it ACPI aware then
things will work in both DTS and ACPI.
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Greg KH <gregkh@linuxfoundation.org>
---
drivers/base/platform-msi.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c
index be6a599..035ca3b 100644
--- a/drivers/base/platform-msi.c
+++ b/drivers/base/platform-msi.c
@@ -345,8 +345,7 @@ struct irq_domain *
data->host_data = host_data;
domain = irq_domain_create_hierarchy(dev->msi_domain, 0, nvec,
- of_node_to_fwnode(dev->of_node),
- ops, data);
+ dev->fwnode, ops, data);
if (!domain)
goto free_priv;
--
1.7.12.4
^ permalink raw reply related
* [PATCH v5 12/14] irqchip: mbigen: drop module owner
From: Hanjun Guo @ 2016-12-22 5:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482384922-21507-1-git-send-email-guohanjun@huawei.com>
From: Kefeng Wang <wangkefeng.wang@huawei.com>
Module owner will be set by driver core, so drop it.
Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ma Jun <majun258@huawei.com>
---
drivers/irqchip/irq-mbigen.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index 03b79b0..c01ab41 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -293,7 +293,6 @@ static int mbigen_device_probe(struct platform_device *pdev)
static struct platform_driver mbigen_platform_driver = {
.driver = {
.name = "Hisilicon MBIGEN-V2",
- .owner = THIS_MODULE,
.of_match_table = mbigen_of_match,
},
.probe = mbigen_device_probe,
--
1.7.12.4
^ permalink raw reply related
* [PATCH v5 13/14] irqchip: mbigen: introduce mbigen_of_create_domain()
From: Hanjun Guo @ 2016-12-22 5:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482384922-21507-1-git-send-email-guohanjun@huawei.com>
From: Kefeng Wang <wangkefeng.wang@huawei.com>
Introduce mbigen_of_create_domain() to consolidate OF related
code and prepare for ACPI later, no funtional change.
Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ma Jun <majun258@huawei.com>
---
drivers/irqchip/irq-mbigen.c | 42 +++++++++++++++++++++++++++---------------
1 file changed, 27 insertions(+), 15 deletions(-)
diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index c01ab41..4e11da5 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -236,27 +236,15 @@ static int mbigen_irq_domain_alloc(struct irq_domain *domain,
.free = irq_domain_free_irqs_common,
};
-static int mbigen_device_probe(struct platform_device *pdev)
+static int mbigen_of_create_domain(struct platform_device *pdev,
+ struct mbigen_device *mgn_chip)
{
- struct mbigen_device *mgn_chip;
+ struct device *parent;
struct platform_device *child;
struct irq_domain *domain;
struct device_node *np;
- struct device *parent;
- struct resource *res;
u32 num_pins;
- mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
- if (!mgn_chip)
- return -ENOMEM;
-
- mgn_chip->pdev = pdev;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- mgn_chip->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(mgn_chip->base))
- return PTR_ERR(mgn_chip->base);
-
for_each_child_of_node(pdev->dev.of_node, np) {
if (!of_property_read_bool(np, "interrupt-controller"))
continue;
@@ -280,6 +268,30 @@ static int mbigen_device_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ return 0;
+}
+
+static int mbigen_device_probe(struct platform_device *pdev)
+{
+ struct mbigen_device *mgn_chip;
+ struct resource *res;
+ int err;
+
+ mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
+ if (!mgn_chip)
+ return -ENOMEM;
+
+ mgn_chip->pdev = pdev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mgn_chip->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (IS_ERR(mgn_chip->base))
+ return PTR_ERR(mgn_chip->base);
+
+ err = mbigen_of_create_domain(pdev, mgn_chip);
+ if (err)
+ return err;
+
platform_set_drvdata(pdev, mgn_chip);
return 0;
}
--
1.7.12.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox