Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v7 4/4] dt-bindings: i2c: pxa: Update the documentation for the Armada 3700
From: Wolfram Sang @ 2016-12-01 22:31 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161201110440.27530-5-romain.perier@free-electrons.com>

On Thu, Dec 01, 2016 at 12:04:40PM +0100, Romain Perier wrote:
> This commit documents the compatible string to have the compatibility for
> the I2C unit found in the Armada 3700.
> 
> Signed-off-by: Romain Perier <romain.perier@free-electrons.com>
> Acked-by: Rob Herring <robh@kernel.org>

Applied to for-next, thanks!

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161201/d20b196d/attachment.sig>

^ permalink raw reply

* [PATCH v3] PCI/ACPI: xgene: Add ECAM quirk for X-Gene PCIe controller
From: Jon Masters @ 2016-12-01 22:31 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CADaLNDkVPRPSg0aU-sxHsiJbVvEn=LxcekDt6gfXBBhc+fzhjw@mail.gmail.com>

Thanks Duc! I will test quickly if you have it today :)

-- 
Computer Architect | Sent from my 64-bit #ARM Powered phone

> On Dec 1, 2016, at 17:10, Duc Dang <dhdang@apm.com> wrote:
> 
>> On Thu, Dec 1, 2016 at 11:41 AM, Bjorn Helgaas <helgaas@kernel.org> wrote:
>>> On Thu, Dec 01, 2016 at 02:20:53PM -0500, Mark Salter wrote:
>>>> On Thu, 2016-12-01 at 12:33 -0600, Bjorn Helgaas wrote:
>>>> On Wed, Nov 30, 2016 at 03:42:53PM -0800, Duc Dang wrote:
>> 
>>>>> +static struct resource xgene_v1_csr_res[] = {
>>>>> + [0] = DEFINE_RES_MEM_NAMED(0x1f2b0000UL, SZ_64K, "PCIe CSR"),
>>>>> + [1] = DEFINE_RES_MEM_NAMED(0x1f2c0000UL, SZ_64K, "PCIe CSR"),
>>>>> + [2] = DEFINE_RES_MEM_NAMED(0x1f2d0000UL, SZ_64K, "PCIe CSR"),
>>>>> + [3] = DEFINE_RES_MEM_NAMED(0x1f500000UL, SZ_64K, "PCIe CSR"),
>>>>> + [4] = DEFINE_RES_MEM_NAMED(0x1f510000UL, SZ_64K, "PCIe CSR"),
>>>> I assume these ranges are not the actual ECAM space, right?
>>>> If they *were* ECAM, I assume you would have included them in the
>>>> quirk itself in the mcfg_quirks[] table.
>>> 
>>> These are base addresses for some RC mmio registers.
>>>> 
>>>>> 
>>>>> +static int xgene_v1_pcie_ecam_init(struct pci_config_window *cfg)
>>>>> +{
>>>>> + struct acpi_device *adev = to_acpi_device(cfg->parent);
>>>>> + struct acpi_pci_root *root = acpi_driver_data(adev);
>>>>> + struct device *dev = cfg->parent;
>>>>> + struct xgene_pcie_port *port;
>>>>> + struct resource *csr;
>>>>> +
>>>>> + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
>>>>> + if (!port)
>>>>> +         return -ENOMEM;
>>>>> +
>>>>> + csr = &xgene_v1_csr_res[root->segment];
>>>> This makes me nervous because root->segment comes from the ACPI _SEG,
>>>> and if firmware gives us junk in _SEG, we will reference something in
>>>> the weeds.
>>> 
>>> The SoC provide some number of RC bridges, each with a different base
>>> for some mmio registers. Even if segment is legitimate in MCFG, there
>>> is still a problem if a platform doesn't use the segment ordering
>>> implied by the code. But the PNP0A03 _CRS does have this base address
>>> as the first memory resource, so we could get it from there and not
>>> have hard-coded addresses and implied ording in the quirk code.
>> 
>> I'm confused.  Doesn't the current code treat every item in PNP0A03
>> _CRS as a window?  Do you mean the first resource is handled
>> differently somehow?  The Consumer/Producer bit could allow us to do
>> this by marking the RC MMIO space as "Consumer", but I didn't think
>> that strategy was quite working yet.
> 
> The first resource is defined like below. It was introduced long time
> ago to use with older version of X-Gene ECAM quirks.
> Memory32Fixed(ReadWrite, 0x1F2B0000, 0x10000, )
> 
> The resource discovered during booting will be like following:
> [    0.728117] ACPI: MCFG table detected, 1 entries
> [    0.735330] ACPI: Power Resource [SCVR] (on)
> [    0.767478] ACPI: PCI Root Bridge [PCI0] (domain 0000 [bus 00-ff])
> [    0.774013] acpi PNP0A08:00: _OSC: OS supports [ExtendedConfig ASPM
> ClockPM Segments MSI]
> [    0.782864] acpi PNP0A08:00: _OSC: OS now controls [PCIeHotplug PME
> AER PCIeCapability]
> [    0.791331] acpi PNP0A08:00: MCFG quirk: ECAM at [mem
> 0xe0d0000000-0xe0dfffffff] for [bus 00-ff] with xgene_v1_pcie_ecam_ops
> [    0.803207] acpi PNP0A08:00: ECAM at [mem
> 0xe0d0000000-0xe0dfffffff] for [bus 00-ff]
> [    0.811399] Remapped I/O 0x000000e010000000 to [io  0x0000-0xffff window]
> [    0.818678] PCI host bridge to bus 0000:00
> [    0.822990] pci_bus 0000:00: root bus resource [mem 0x1f2b0000-0x1f2bffff]
> [    0.830257] pci_bus 0000:00: root bus resource [io  0x0000-0xffff
> window] (bus address [0x10000000-0x1000ffff])
> [    0.840917] pci_bus 0000:00: root bus resource [mem
> 0xe040000000-0xe07fffffff window] (bus address
> [0x40000000-0x7fffffff])
> [    0.852675] pci_bus 0000:00: root bus resource [mem
> 0xf000000000-0xffffffffff window]
> [    0.860950] pci_bus 0000:00: root bus resource [bus 00-ff]
> [    0.866761] pci 0000:00:00.0: [10e8:e004] type 01 class 0x060400
> [    0.873175] pci 0000:00:00.0: supports D1 D2
> [    0.877980] pci 0000:01:00.0: [15b3:1003] type 00 class 0x020000
> [    0.884597] pci 0000:01:00.0: reg 0x10: [mem 0xe040000000-0xe0400fffff 64bit]
> [    0.892337] pci 0000:01:00.0: reg 0x18: [mem
> 0xe042000000-0xe043ffffff 64bit pref]
> [    0.900694] pci 0000:01:00.0: reg 0x30: [mem 0xfff00000-0xffffffff pref]
> [    0.923853] pci_bus 0000:00: on NUMA node 0
> [    0.928269] pci 0000:00:00.0: BAR 15: assigned [mem
> 0xf000000000-0xf001ffffff 64bit pref]
> [    0.936908] pci 0000:00:00.0: BAR 14: assigned [mem
> 0xe040000000-0xe0401fffff]
> [    0.944539] pci 0000:01:00.0: BAR 2: assigned [mem
> 0xf000000000-0xf001ffffff 64bit pref]
> [    0.953210] pci 0000:01:00.0: BAR 0: assigned [mem
> 0xe040000000-0xe0400fffff 64bit]
> [    0.961430] pci 0000:01:00.0: BAR 6: assigned [mem
> 0xe040100000-0xe0401fffff pref]
> [    0.969438] pci 0000:00:00.0: PCI bridge to [bus 01]
> [    0.974690] pci 0000:00:00.0:   bridge window [mem 0xe040000000-0xe0401fffff]
> [    0.982231] pci 0000:00:00.0:   bridge window [mem
> 0xf000000000-0xf001ffffff 64bit pref]
> 
>> 
>>> I have tested a modified version of these quirks using this to
>>> get the CSR base and it works on the 3 different platforms I have
>>> access to.
>>> 
>>> static int xgene_pcie_get_csr(struct device *dev, struct resource *r)
>>> {
>>>      struct acpi_device *adev = to_acpi_device(dev);
>>>      unsigned long flags;
>>>      struct list_head list;
>>>      struct resource_entry *entry;
>>>      int ret;
>>> 
>>>      INIT_LIST_HEAD(&list);
>>>      flags = IORESOURCE_MEM;
>>>      ret = acpi_dev_get_resources(adev, &list,
>>>                                   acpi_dev_filter_resource_type_cb,
>>>                                   (void *)flags);
>>>      if (ret < 0) {
>>>              dev_err(dev, "failed to parse _CRS, error: %d\n", ret);
>>>              return ret;
>>>      } else if (ret == 0) {
>>>              dev_err(dev, "no memory resources present in _CRS\n");
>>>              return -EINVAL;
>>>      }
>>> 
>>>      entry = list_first_entry(&list, struct resource_entry, node);
>>>      *r = *entry->res;
>>>      acpi_dev_free_resource_list(&list);
>>>      return 0;
>>> }
>> 
>> The code above is identical to acpi_get_rc_addr(), which is used in
>> the acpi_get_rc_resources() path by the other quirks.  Can you use
>> that path, too, instead of reimplementing it here?
> 
> I will post a new version using acpi_get_rc_resources and includes
> other changes that you suggested.
> 
> Regards,
> Duc Dang.

^ permalink raw reply

* [PATCH 2/2] arm64: xen: Split architecture-specific headers from 32bit ARM
From: Stefano Stabellini @ 2016-12-01 22:17 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480589074-809-3-git-send-email-marc.zyngier@arm.com>

On Thu, 1 Dec 2016, Marc Zyngier wrote:
> ARM and arm64 Xen ports share a number of headers, leading to
> packaging issues when these headers needs to be exported, as it
> breaks the reasonable requirement that an architecture port
> is standalone.
> 
> Solve the issue by copying the 5 header files over the arch
> barrier.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

I might be unhappy about making life more difficult for people building
out of tree modules (not really, but I can pretend), but copying the
headers over is not a solution. I really don't want two copies of them.

What does "standalone" mean in this context? What is the failure exactly?

If moving the headers out of arch/arm is necessary, then please move
them to another shared directory, maybe include/xen/arm.



>  arch/arm64/include/asm/xen/hypercall.h     |  88 ++++++++++++++++++++-
>  arch/arm64/include/asm/xen/hypervisor.h    |  40 +++++++++-
>  arch/arm64/include/asm/xen/interface.h     |  86 +++++++++++++++++++-
>  arch/arm64/include/asm/xen/page-coherent.h |  99 ++++++++++++++++++++++-
>  arch/arm64/include/asm/xen/page.h          | 123 ++++++++++++++++++++++++++++-
>  5 files changed, 431 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/xen/hypercall.h b/arch/arm64/include/asm/xen/hypercall.h
> index 74b0c42..9d874db 100644
> --- a/arch/arm64/include/asm/xen/hypercall.h
> +++ b/arch/arm64/include/asm/xen/hypercall.h
> @@ -1 +1,87 @@
> -#include <../../arm/include/asm/xen/hypercall.h>
> +/******************************************************************************
> + * hypercall.h
> + *
> + * Linux-specific hypervisor handling.
> + *
> + * Stefano Stabellini <stefano.stabellini@eu.citrix.com>, Citrix, 2012
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License version 2
> + * as published by the Free Software Foundation; or, when distributed
> + * separately from the Linux kernel or incorporated into other
> + * software packages, subject to the following license:
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this source file (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 "AS IS", 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.
> + */
> +
> +#ifndef _ASM_ARM_XEN_HYPERCALL_H
> +#define _ASM_ARM_XEN_HYPERCALL_H
> +
> +#include <linux/bug.h>
> +
> +#include <xen/interface/xen.h>
> +#include <xen/interface/sched.h>
> +#include <xen/interface/platform.h>
> +
> +long privcmd_call(unsigned call, unsigned long a1,
> +		unsigned long a2, unsigned long a3,
> +		unsigned long a4, unsigned long a5);
> +int HYPERVISOR_xen_version(int cmd, void *arg);
> +int HYPERVISOR_console_io(int cmd, int count, char *str);
> +int HYPERVISOR_grant_table_op(unsigned int cmd, void *uop, unsigned int count);
> +int HYPERVISOR_sched_op(int cmd, void *arg);
> +int HYPERVISOR_event_channel_op(int cmd, void *arg);
> +unsigned long HYPERVISOR_hvm_op(int op, void *arg);
> +int HYPERVISOR_memory_op(unsigned int cmd, void *arg);
> +int HYPERVISOR_physdev_op(int cmd, void *arg);
> +int HYPERVISOR_vcpu_op(int cmd, int vcpuid, void *extra_args);
> +int HYPERVISOR_tmem_op(void *arg);
> +int HYPERVISOR_vm_assist(unsigned int cmd, unsigned int type);
> +int HYPERVISOR_platform_op_raw(void *arg);
> +static inline int HYPERVISOR_platform_op(struct xen_platform_op *op)
> +{
> +	op->interface_version = XENPF_INTERFACE_VERSION;
> +	return HYPERVISOR_platform_op_raw(op);
> +}
> +int HYPERVISOR_multicall(struct multicall_entry *calls, uint32_t nr);
> +
> +static inline int
> +HYPERVISOR_suspend(unsigned long start_info_mfn)
> +{
> +	struct sched_shutdown r = { .reason = SHUTDOWN_suspend };
> +
> +	/* start_info_mfn is unused on ARM */
> +	return HYPERVISOR_sched_op(SCHEDOP_shutdown, &r);
> +}
> +
> +static inline void
> +MULTI_update_va_mapping(struct multicall_entry *mcl, unsigned long va,
> +			unsigned int new_val, unsigned long flags)
> +{
> +	BUG();
> +}
> +
> +static inline void
> +MULTI_mmu_update(struct multicall_entry *mcl, struct mmu_update *req,
> +		 int count, int *success_count, domid_t domid)
> +{
> +	BUG();
> +}
> +
> +#endif /* _ASM_ARM_XEN_HYPERCALL_H */
> diff --git a/arch/arm64/include/asm/xen/hypervisor.h b/arch/arm64/include/asm/xen/hypervisor.h
> index f263da8..9525151 100644
> --- a/arch/arm64/include/asm/xen/hypervisor.h
> +++ b/arch/arm64/include/asm/xen/hypervisor.h
> @@ -1 +1,39 @@
> -#include <../../arm/include/asm/xen/hypervisor.h>
> +#ifndef _ASM_ARM_XEN_HYPERVISOR_H
> +#define _ASM_ARM_XEN_HYPERVISOR_H
> +
> +#include <linux/init.h>
> +
> +extern struct shared_info *HYPERVISOR_shared_info;
> +extern struct start_info *xen_start_info;
> +
> +/* Lazy mode for batching updates / context switch */
> +enum paravirt_lazy_mode {
> +	PARAVIRT_LAZY_NONE,
> +	PARAVIRT_LAZY_MMU,
> +	PARAVIRT_LAZY_CPU,
> +};
> +
> +static inline enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
> +{
> +	return PARAVIRT_LAZY_NONE;
> +}
> +
> +extern struct dma_map_ops *xen_dma_ops;
> +
> +#ifdef CONFIG_XEN
> +void __init xen_early_init(void);
> +#else
> +static inline void xen_early_init(void) { return; }
> +#endif
> +
> +#ifdef CONFIG_HOTPLUG_CPU
> +static inline void xen_arch_register_cpu(int num)
> +{
> +}
> +
> +static inline void xen_arch_unregister_cpu(int num)
> +{
> +}
> +#endif
> +
> +#endif /* _ASM_ARM_XEN_HYPERVISOR_H */
> diff --git a/arch/arm64/include/asm/xen/interface.h b/arch/arm64/include/asm/xen/interface.h
> index 44457ae..75d5968 100644
> --- a/arch/arm64/include/asm/xen/interface.h
> +++ b/arch/arm64/include/asm/xen/interface.h
> @@ -1 +1,85 @@
> -#include <../../arm/include/asm/xen/interface.h>
> +/******************************************************************************
> + * Guest OS interface to ARM Xen.
> + *
> + * Stefano Stabellini <stefano.stabellini@eu.citrix.com>, Citrix, 2012
> + */
> +
> +#ifndef _ASM_ARM_XEN_INTERFACE_H
> +#define _ASM_ARM_XEN_INTERFACE_H
> +
> +#include <linux/types.h>
> +
> +#define uint64_aligned_t uint64_t __attribute__((aligned(8)))
> +
> +#define __DEFINE_GUEST_HANDLE(name, type) \
> +	typedef struct { union { type *p; uint64_aligned_t q; }; }  \
> +        __guest_handle_ ## name
> +
> +#define DEFINE_GUEST_HANDLE_STRUCT(name) \
> +	__DEFINE_GUEST_HANDLE(name, struct name)
> +#define DEFINE_GUEST_HANDLE(name) __DEFINE_GUEST_HANDLE(name, name)
> +#define GUEST_HANDLE(name)        __guest_handle_ ## name
> +
> +#define set_xen_guest_handle(hnd, val)			\
> +	do {						\
> +		if (sizeof(hnd) == 8)			\
> +			*(uint64_t *)&(hnd) = 0;	\
> +		(hnd).p = val;				\
> +	} while (0)
> +
> +#define __HYPERVISOR_platform_op_raw __HYPERVISOR_platform_op
> +
> +#ifndef __ASSEMBLY__
> +/* Explicitly size integers that represent pfns in the interface with
> + * Xen so that we can have one ABI that works for 32 and 64 bit guests.
> + * Note that this means that the xen_pfn_t type may be capable of
> + * representing pfn's which the guest cannot represent in its own pfn
> + * type. However since pfn space is controlled by the guest this is
> + * fine since it simply wouldn't be able to create any sure pfns in
> + * the first place.
> + */
> +typedef uint64_t xen_pfn_t;
> +#define PRI_xen_pfn "llx"
> +typedef uint64_t xen_ulong_t;
> +#define PRI_xen_ulong "llx"
> +typedef int64_t xen_long_t;
> +#define PRI_xen_long "llx"
> +/* Guest handles for primitive C types. */
> +__DEFINE_GUEST_HANDLE(uchar, unsigned char);
> +__DEFINE_GUEST_HANDLE(uint,  unsigned int);
> +DEFINE_GUEST_HANDLE(char);
> +DEFINE_GUEST_HANDLE(int);
> +DEFINE_GUEST_HANDLE(void);
> +DEFINE_GUEST_HANDLE(uint64_t);
> +DEFINE_GUEST_HANDLE(uint32_t);
> +DEFINE_GUEST_HANDLE(xen_pfn_t);
> +DEFINE_GUEST_HANDLE(xen_ulong_t);
> +
> +/* Maximum number of virtual CPUs in multi-processor guests. */
> +#define MAX_VIRT_CPUS 1
> +
> +struct arch_vcpu_info { };
> +struct arch_shared_info { };
> +
> +/* TODO: Move pvclock definitions some place arch independent */
> +struct pvclock_vcpu_time_info {
> +	u32   version;
> +	u32   pad0;
> +	u64   tsc_timestamp;
> +	u64   system_time;
> +	u32   tsc_to_system_mul;
> +	s8    tsc_shift;
> +	u8    flags;
> +	u8    pad[2];
> +} __attribute__((__packed__)); /* 32 bytes */
> +
> +/* It is OK to have a 12 bytes struct with no padding because it is packed */
> +struct pvclock_wall_clock {
> +	u32   version;
> +	u32   sec;
> +	u32   nsec;
> +	u32   sec_hi;
> +} __attribute__((__packed__));
> +#endif
> +
> +#endif /* _ASM_ARM_XEN_INTERFACE_H */
> diff --git a/arch/arm64/include/asm/xen/page-coherent.h b/arch/arm64/include/asm/xen/page-coherent.h
> index 2052102..95ce6ac 100644
> --- a/arch/arm64/include/asm/xen/page-coherent.h
> +++ b/arch/arm64/include/asm/xen/page-coherent.h
> @@ -1 +1,98 @@
> -#include <../../arm/include/asm/xen/page-coherent.h>
> +#ifndef _ASM_ARM_XEN_PAGE_COHERENT_H
> +#define _ASM_ARM_XEN_PAGE_COHERENT_H
> +
> +#include <asm/page.h>
> +#include <linux/dma-mapping.h>
> +
> +void __xen_dma_map_page(struct device *hwdev, struct page *page,
> +	     dma_addr_t dev_addr, unsigned long offset, size_t size,
> +	     enum dma_data_direction dir, unsigned long attrs);
> +void __xen_dma_unmap_page(struct device *hwdev, dma_addr_t handle,
> +		size_t size, enum dma_data_direction dir,
> +		unsigned long attrs);
> +void __xen_dma_sync_single_for_cpu(struct device *hwdev,
> +		dma_addr_t handle, size_t size, enum dma_data_direction dir);
> +
> +void __xen_dma_sync_single_for_device(struct device *hwdev,
> +		dma_addr_t handle, size_t size, enum dma_data_direction dir);
> +
> +static inline void *xen_alloc_coherent_pages(struct device *hwdev, size_t size,
> +		dma_addr_t *dma_handle, gfp_t flags, unsigned long attrs)
> +{
> +	return __generic_dma_ops(hwdev)->alloc(hwdev, size, dma_handle, flags, attrs);
> +}
> +
> +static inline void xen_free_coherent_pages(struct device *hwdev, size_t size,
> +		void *cpu_addr, dma_addr_t dma_handle, unsigned long attrs)
> +{
> +	__generic_dma_ops(hwdev)->free(hwdev, size, cpu_addr, dma_handle, attrs);
> +}
> +
> +static inline void xen_dma_map_page(struct device *hwdev, struct page *page,
> +	     dma_addr_t dev_addr, unsigned long offset, size_t size,
> +	     enum dma_data_direction dir, unsigned long attrs)
> +{
> +	unsigned long page_pfn = page_to_xen_pfn(page);
> +	unsigned long dev_pfn = XEN_PFN_DOWN(dev_addr);
> +	unsigned long compound_pages =
> +		(1<<compound_order(page)) * XEN_PFN_PER_PAGE;
> +	bool local = (page_pfn <= dev_pfn) &&
> +		(dev_pfn - page_pfn < compound_pages);
> +
> +	/*
> +	 * Dom0 is mapped 1:1, while the Linux page can span across
> +	 * multiple Xen pages, it's not possible for it to contain a
> +	 * mix of local and foreign Xen pages. So if the first xen_pfn
> +	 * == mfn the page is local otherwise it's a foreign page
> +	 * grant-mapped in dom0. If the page is local we can safely
> +	 * call the native dma_ops function, otherwise we call the xen
> +	 * specific function.
> +	 */
> +	if (local)
> +		__generic_dma_ops(hwdev)->map_page(hwdev, page, offset, size, dir, attrs);
> +	else
> +		__xen_dma_map_page(hwdev, page, dev_addr, offset, size, dir, attrs);
> +}
> +
> +static inline void xen_dma_unmap_page(struct device *hwdev, dma_addr_t handle,
> +		size_t size, enum dma_data_direction dir, unsigned long attrs)
> +{
> +	unsigned long pfn = PFN_DOWN(handle);
> +	/*
> +	 * Dom0 is mapped 1:1, while the Linux page can be spanned accross
> +	 * multiple Xen page, it's not possible to have a mix of local and
> +	 * foreign Xen page. Dom0 is mapped 1:1, so calling pfn_valid on a
> +	 * foreign mfn will always return false. If the page is local we can
> +	 * safely call the native dma_ops function, otherwise we call the xen
> +	 * specific function.
> +	 */
> +	if (pfn_valid(pfn)) {
> +		if (__generic_dma_ops(hwdev)->unmap_page)
> +			__generic_dma_ops(hwdev)->unmap_page(hwdev, handle, size, dir, attrs);
> +	} else
> +		__xen_dma_unmap_page(hwdev, handle, size, dir, attrs);
> +}
> +
> +static inline void xen_dma_sync_single_for_cpu(struct device *hwdev,
> +		dma_addr_t handle, size_t size, enum dma_data_direction dir)
> +{
> +	unsigned long pfn = PFN_DOWN(handle);
> +	if (pfn_valid(pfn)) {
> +		if (__generic_dma_ops(hwdev)->sync_single_for_cpu)
> +			__generic_dma_ops(hwdev)->sync_single_for_cpu(hwdev, handle, size, dir);
> +	} else
> +		__xen_dma_sync_single_for_cpu(hwdev, handle, size, dir);
> +}
> +
> +static inline void xen_dma_sync_single_for_device(struct device *hwdev,
> +		dma_addr_t handle, size_t size, enum dma_data_direction dir)
> +{
> +	unsigned long pfn = PFN_DOWN(handle);
> +	if (pfn_valid(pfn)) {
> +		if (__generic_dma_ops(hwdev)->sync_single_for_device)
> +			__generic_dma_ops(hwdev)->sync_single_for_device(hwdev, handle, size, dir);
> +	} else
> +		__xen_dma_sync_single_for_device(hwdev, handle, size, dir);
> +}
> +
> +#endif /* _ASM_ARM_XEN_PAGE_COHERENT_H */
> diff --git a/arch/arm64/include/asm/xen/page.h b/arch/arm64/include/asm/xen/page.h
> index bed87ec..415dbc6 100644
> --- a/arch/arm64/include/asm/xen/page.h
> +++ b/arch/arm64/include/asm/xen/page.h
> @@ -1 +1,122 @@
> -#include <../../arm/include/asm/xen/page.h>
> +#ifndef _ASM_ARM_XEN_PAGE_H
> +#define _ASM_ARM_XEN_PAGE_H
> +
> +#include <asm/page.h>
> +#include <asm/pgtable.h>
> +
> +#include <linux/pfn.h>
> +#include <linux/types.h>
> +#include <linux/dma-mapping.h>
> +
> +#include <xen/xen.h>
> +#include <xen/interface/grant_table.h>
> +
> +#define phys_to_machine_mapping_valid(pfn) (1)
> +
> +/* Xen machine address */
> +typedef struct xmaddr {
> +	phys_addr_t maddr;
> +} xmaddr_t;
> +
> +/* Xen pseudo-physical address */
> +typedef struct xpaddr {
> +	phys_addr_t paddr;
> +} xpaddr_t;
> +
> +#define XMADDR(x)	((xmaddr_t) { .maddr = (x) })
> +#define XPADDR(x)	((xpaddr_t) { .paddr = (x) })
> +
> +#define INVALID_P2M_ENTRY      (~0UL)
> +
> +/*
> + * The pseudo-physical frame (pfn) used in all the helpers is always based
> + * on Xen page granularity (i.e 4KB).
> + *
> + * A Linux page may be split across multiple non-contiguous Xen page so we
> + * have to keep track with frame based on 4KB page granularity.
> + *
> + * PV drivers should never make a direct usage of those helpers (particularly
> + * pfn_to_gfn and gfn_to_pfn).
> + */
> +
> +unsigned long __pfn_to_mfn(unsigned long pfn);
> +extern struct rb_root phys_to_mach;
> +
> +/* Pseudo-physical <-> Guest conversion */
> +static inline unsigned long pfn_to_gfn(unsigned long pfn)
> +{
> +	return pfn;
> +}
> +
> +static inline unsigned long gfn_to_pfn(unsigned long gfn)
> +{
> +	return gfn;
> +}
> +
> +/* Pseudo-physical <-> BUS conversion */
> +static inline unsigned long pfn_to_bfn(unsigned long pfn)
> +{
> +	unsigned long mfn;
> +
> +	if (phys_to_mach.rb_node != NULL) {
> +		mfn = __pfn_to_mfn(pfn);
> +		if (mfn != INVALID_P2M_ENTRY)
> +			return mfn;
> +	}
> +
> +	return pfn;
> +}
> +
> +static inline unsigned long bfn_to_pfn(unsigned long bfn)
> +{
> +	return bfn;
> +}
> +
> +#define bfn_to_local_pfn(bfn)	bfn_to_pfn(bfn)
> +
> +/* VIRT <-> GUEST conversion */
> +#define virt_to_gfn(v)		(pfn_to_gfn(virt_to_phys(v) >> XEN_PAGE_SHIFT))
> +#define gfn_to_virt(m)		(__va(gfn_to_pfn(m) << XEN_PAGE_SHIFT))
> +
> +/* Only used in PV code. But ARM guests are always HVM. */
> +static inline xmaddr_t arbitrary_virt_to_machine(void *vaddr)
> +{
> +	BUG();
> +}
> +
> +/* TODO: this shouldn't be here but it is because the frontend drivers
> + * are using it (its rolled in headers) even though we won't hit the code path.
> + * So for right now just punt with this.
> + */
> +static inline pte_t *lookup_address(unsigned long address, unsigned int *level)
> +{
> +	BUG();
> +	return NULL;
> +}
> +
> +extern int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops,
> +				   struct gnttab_map_grant_ref *kmap_ops,
> +				   struct page **pages, unsigned int count);
> +
> +extern int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops,
> +				     struct gnttab_unmap_grant_ref *kunmap_ops,
> +				     struct page **pages, unsigned int count);
> +
> +bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn);
> +bool __set_phys_to_machine_multi(unsigned long pfn, unsigned long mfn,
> +		unsigned long nr_pages);
> +
> +static inline bool set_phys_to_machine(unsigned long pfn, unsigned long mfn)
> +{
> +	return __set_phys_to_machine(pfn, mfn);
> +}
> +
> +#define xen_remap(cookie, size) ioremap_cache((cookie), (size))
> +#define xen_unmap(cookie) iounmap((cookie))
> +
> +bool xen_arch_need_swiotlb(struct device *dev,
> +			   phys_addr_t phys,
> +			   dma_addr_t dev_addr);
> +unsigned long xen_get_swiotlb_free_pages(unsigned int order);
> +
> +#endif /* _ASM_ARM_XEN_PAGE_H */
> -- 
> 2.1.4
> 

^ permalink raw reply

* [PATCH v3] PCI/ACPI: xgene: Add ECAM quirk for X-Gene PCIe controller
From: Duc Dang @ 2016-12-01 22:10 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161201194114.GA8263@bhelgaas-glaptop.roam.corp.google.com>

On Thu, Dec 1, 2016 at 11:41 AM, Bjorn Helgaas <helgaas@kernel.org> wrote:
> On Thu, Dec 01, 2016 at 02:20:53PM -0500, Mark Salter wrote:
>> On Thu, 2016-12-01 at 12:33 -0600, Bjorn Helgaas wrote:
>> > On Wed, Nov 30, 2016 at 03:42:53PM -0800, Duc Dang wrote:
>
>> > > +static struct resource xgene_v1_csr_res[] = {
>> > > + [0] = DEFINE_RES_MEM_NAMED(0x1f2b0000UL, SZ_64K, "PCIe CSR"),
>> > > + [1] = DEFINE_RES_MEM_NAMED(0x1f2c0000UL, SZ_64K, "PCIe CSR"),
>> > > + [2] = DEFINE_RES_MEM_NAMED(0x1f2d0000UL, SZ_64K, "PCIe CSR"),
>> > > + [3] = DEFINE_RES_MEM_NAMED(0x1f500000UL, SZ_64K, "PCIe CSR"),
>> > > + [4] = DEFINE_RES_MEM_NAMED(0x1f510000UL, SZ_64K, "PCIe CSR"),
>> > I assume these ranges are not the actual ECAM space, right?
>> > If they *were* ECAM, I assume you would have included them in the
>> > quirk itself in the mcfg_quirks[] table.
>>
>> These are base addresses for some RC mmio registers.
>> >
>> > >
>> > > +static int xgene_v1_pcie_ecam_init(struct pci_config_window *cfg)
>> > > +{
>> > > + struct acpi_device *adev = to_acpi_device(cfg->parent);
>> > > + struct acpi_pci_root *root = acpi_driver_data(adev);
>> > > + struct device *dev = cfg->parent;
>> > > + struct xgene_pcie_port *port;
>> > > + struct resource *csr;
>> > > +
>> > > + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
>> > > + if (!port)
>> > > +         return -ENOMEM;
>> > > +
>> > > + csr = &xgene_v1_csr_res[root->segment];
>> > This makes me nervous because root->segment comes from the ACPI _SEG,
>> > and if firmware gives us junk in _SEG, we will reference something in
>> > the weeds.
>>
>> The SoC provide some number of RC bridges, each with a different base
>> for some mmio registers. Even if segment is legitimate in MCFG, there
>> is still a problem if a platform doesn't use the segment ordering
>> implied by the code. But the PNP0A03 _CRS does have this base address
>> as the first memory resource, so we could get it from there and not
>> have hard-coded addresses and implied ording in the quirk code.
>
> I'm confused.  Doesn't the current code treat every item in PNP0A03
> _CRS as a window?  Do you mean the first resource is handled
> differently somehow?  The Consumer/Producer bit could allow us to do
> this by marking the RC MMIO space as "Consumer", but I didn't think
> that strategy was quite working yet.

The first resource is defined like below. It was introduced long time
ago to use with older version of X-Gene ECAM quirks.
Memory32Fixed(ReadWrite, 0x1F2B0000, 0x10000, )

The resource discovered during booting will be like following:
[    0.728117] ACPI: MCFG table detected, 1 entries
[    0.735330] ACPI: Power Resource [SCVR] (on)
[    0.767478] ACPI: PCI Root Bridge [PCI0] (domain 0000 [bus 00-ff])
[    0.774013] acpi PNP0A08:00: _OSC: OS supports [ExtendedConfig ASPM
ClockPM Segments MSI]
[    0.782864] acpi PNP0A08:00: _OSC: OS now controls [PCIeHotplug PME
AER PCIeCapability]
[    0.791331] acpi PNP0A08:00: MCFG quirk: ECAM at [mem
0xe0d0000000-0xe0dfffffff] for [bus 00-ff] with xgene_v1_pcie_ecam_ops
[    0.803207] acpi PNP0A08:00: ECAM at [mem
0xe0d0000000-0xe0dfffffff] for [bus 00-ff]
[    0.811399] Remapped I/O 0x000000e010000000 to [io  0x0000-0xffff window]
[    0.818678] PCI host bridge to bus 0000:00
[    0.822990] pci_bus 0000:00: root bus resource [mem 0x1f2b0000-0x1f2bffff]
[    0.830257] pci_bus 0000:00: root bus resource [io  0x0000-0xffff
window] (bus address [0x10000000-0x1000ffff])
[    0.840917] pci_bus 0000:00: root bus resource [mem
0xe040000000-0xe07fffffff window] (bus address
[0x40000000-0x7fffffff])
[    0.852675] pci_bus 0000:00: root bus resource [mem
0xf000000000-0xffffffffff window]
[    0.860950] pci_bus 0000:00: root bus resource [bus 00-ff]
[    0.866761] pci 0000:00:00.0: [10e8:e004] type 01 class 0x060400
[    0.873175] pci 0000:00:00.0: supports D1 D2
[    0.877980] pci 0000:01:00.0: [15b3:1003] type 00 class 0x020000
[    0.884597] pci 0000:01:00.0: reg 0x10: [mem 0xe040000000-0xe0400fffff 64bit]
[    0.892337] pci 0000:01:00.0: reg 0x18: [mem
0xe042000000-0xe043ffffff 64bit pref]
[    0.900694] pci 0000:01:00.0: reg 0x30: [mem 0xfff00000-0xffffffff pref]
[    0.923853] pci_bus 0000:00: on NUMA node 0
[    0.928269] pci 0000:00:00.0: BAR 15: assigned [mem
0xf000000000-0xf001ffffff 64bit pref]
[    0.936908] pci 0000:00:00.0: BAR 14: assigned [mem
0xe040000000-0xe0401fffff]
[    0.944539] pci 0000:01:00.0: BAR 2: assigned [mem
0xf000000000-0xf001ffffff 64bit pref]
[    0.953210] pci 0000:01:00.0: BAR 0: assigned [mem
0xe040000000-0xe0400fffff 64bit]
[    0.961430] pci 0000:01:00.0: BAR 6: assigned [mem
0xe040100000-0xe0401fffff pref]
[    0.969438] pci 0000:00:00.0: PCI bridge to [bus 01]
[    0.974690] pci 0000:00:00.0:   bridge window [mem 0xe040000000-0xe0401fffff]
[    0.982231] pci 0000:00:00.0:   bridge window [mem
0xf000000000-0xf001ffffff 64bit pref]

>
>> I have tested a modified version of these quirks using this to
>> get the CSR base and it works on the 3 different platforms I have
>> access to.
>>
>> static int xgene_pcie_get_csr(struct device *dev, struct resource *r)
>> {
>>       struct acpi_device *adev = to_acpi_device(dev);
>>       unsigned long flags;
>>       struct list_head list;
>>       struct resource_entry *entry;
>>       int ret;
>>
>>       INIT_LIST_HEAD(&list);
>>       flags = IORESOURCE_MEM;
>>       ret = acpi_dev_get_resources(adev, &list,
>>                                    acpi_dev_filter_resource_type_cb,
>>                                    (void *)flags);
>>       if (ret < 0) {
>>               dev_err(dev, "failed to parse _CRS, error: %d\n", ret);
>>               return ret;
>>       } else if (ret == 0) {
>>               dev_err(dev, "no memory resources present in _CRS\n");
>>               return -EINVAL;
>>       }
>>
>>       entry = list_first_entry(&list, struct resource_entry, node);
>>       *r = *entry->res;
>>       acpi_dev_free_resource_list(&list);
>>       return 0;
>> }
>
> The code above is identical to acpi_get_rc_addr(), which is used in
> the acpi_get_rc_resources() path by the other quirks.  Can you use
> that path, too, instead of reimplementing it here?

I will post a new version using acpi_get_rc_resources and includes
other changes that you suggested.

Regards,
Duc Dang.

^ permalink raw reply

* [PATCH v10 2/8] power: add power sequence library
From: Rafael J. Wysocki @ 2016-12-01 21:57 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161122035324.GA7497@b29397-desktop>

On Tue, Nov 22, 2016 at 4:53 AM, Peter Chen <hzpeterchen@gmail.com> wrote:
> On Tue, Nov 22, 2016 at 03:23:12AM +0100, Rafael J. Wysocki wrote:
>> > @@ -0,0 +1,237 @@
>> > +/*
>> > + * core.c      power sequence core file
>> > + *
>> > + * Copyright (C) 2016 Freescale Semiconductor, Inc.
>> > + * Author: Peter Chen <peter.chen@nxp.com>
>> > + *
>> > + * This program is free software: you can redistribute it and/or modify
>> > + * it under the terms of the GNU General Public License version 2  of
>> > + * the License as published by the Free Software Foundation.
>> > + *
>> > + * This program is distributed in the hope that it will be useful,
>> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> > + * GNU General Public License for more details.
>> > + *
>> > + * You should have received a copy of the GNU General Public License
>> > + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>>
>> The last paragraph is not necessary AFAICS.
>
> I just copy it from:
>
> https://www.gnu.org/licenses/gpl-howto.en.html
>
> If you are concerns about it, I can delete it.

It is redundant, so yes, please.

>> > +
>> > +static struct pwrseq *pwrseq_find_available_instance(struct device_node *np)
>> > +{
>> > +       struct pwrseq *pwrseq;
>> > +
>> > +       list_for_each_entry(pwrseq, &pwrseq_list, node) {
>> > +               if (pwrseq->used)
>> > +                       continue;
>> > +
>> > +               /* compare compatible string for pwrseq node */
>> > +               if (of_match_node(pwrseq->pwrseq_of_match_table, np)) {
>> > +                       pwrseq->used = true;
>> > +                       return pwrseq;
>> > +               }
>> > +
>> > +               /* return generic pwrseq instance */
>> > +               if (!strcmp(pwrseq->pwrseq_of_match_table->compatible,
>> > +                               "generic")) {
>> > +                       pr_debug("using generic pwrseq instance for %s\n",
>> > +                               np->full_name);
>> > +                       pwrseq->used = true;
>> > +                       return pwrseq;
>> > +               }
>> > +       }
>> > +       pr_warn("Can't find any pwrseq instances for %s\n", np->full_name);
>>
>> pr_debug() ?
>
> If there is no pwrseq instance for that node, the power sequence on routine will
> return fail, so I think an warning message is useful for user.

Useful in what way?  How is the user supposed to know what happened
from this message?

>>
>> > +
>> > +       return NULL;
>> > +}
>> > +
>> > +/**
>> > + * of_pwrseq_on: do power sequence on for device node
>>
>> of_pwrseq_on - Carry out power sequence on for device node
>>
>> Argument description should follow this line.
>>
>> > + *
>> > + * This API is used to power on single device, if the host
>> > + * controller only needs to handle one child device (this device
>> > + * node points to), use this API. If multiply devices are needed
>> > + * to handle on bus, use of_pwrseq_on_list.
>>
>> That's unclear.
>>
>> What about "Carry out a single device power on.  If multiple devices
>> need to be handled, use of_pwrseq_on_list() instead."
>>
>> > + *
>> > + * @np: the device node would like to power on
>> > + *
>> > + * On successful, it returns pwrseq instance, otherwise an error value.
>>
>> "Return a pointer to the power sequence instance on success, or an
>> error code otherwise."
>>
>
> Ok, will change.
>
>> > + */
>> > +struct pwrseq *of_pwrseq_on(struct device_node *np)
>> > +{
>> > +       struct pwrseq *pwrseq;
>> > +       int ret;
>> > +
>> > +       pwrseq = pwrseq_find_available_instance(np);
>>
>> What does guarantee the integrity of ths list at this point?
>
> Once the use selects the specific pwrseq library, the library will
> create an empty one instance during the initialization, and it
> will be called at postcore_initcall, the device driver has not
> probed yet.

Which doesn't matter really, because the list is global and some other
driver using it might have been probed already.

You have a mutex here and it is used for add/remove.  Why isn't it
used for list browsing?

>
>>
>> > +       if (!pwrseq)
>> > +               return ERR_PTR(-ENONET);
>>
>> ENOENT I suppose?
>>
>
> Good catch, thanks.
>
>> > +/**
>> > + * of_pwrseq_off: do power sequence off for this pwrseq instance
>> > + *
>> > + * This API is used to power off single device, it is the opposite
>> > + * operation for of_pwrseq_on.
>> > + *
>> > + * @pwrseq: the pwrseq instance which related device would like to be off
>> > + */
>> > +void of_pwrseq_off(struct pwrseq *pwrseq)
>> > +{
>> > +       pwrseq_off(pwrseq);
>> > +       pwrseq_put(pwrseq);
>> > +}
>> > +EXPORT_SYMBOL_GPL(of_pwrseq_off);
>>
>> What happens if two code paths attempt to turn the same power sequence
>> off in parallel?  Can it ever happen?  If not, then why not?
>>
>
> I don't think the same pwrseq instance off will be called at the same
> time, the of_pwrseq_off is supposed to be only called at error path
> during power-on and at device power-off routine, and only the power-on is
> successful, the device can be created, if the device is not created,
> its power-off routine is not supposed to be called.
>
>> > +
>> > +/**
>> > + * of_pwrseq_on_list: do power sequence on for list
>> > + *
>> > + * This API is used to power on multiple devices at single bus.
>> > + * If there are several devices on bus (eg, USB bus), uses this
>> > + * this API. Otherwise, use of_pwrseq_on. After the device
>> > + * is powered on successfully, it will be added to pwrseq list for
>> > + * this bus.
>> > + *
>> > + * @np: the device node would like to power on
>> > + * @head: the list head for pwrseq list on this bus
>> > + *
>> > + * On successful, it returns 0, otherwise an error value.
>>
>> Please format the kerneldoc comment in a usual way.
>>
>
> Ok.
>
>> > + */
>> > +int of_pwrseq_on_list(struct device_node *np, struct list_head *head)
>> > +{
>> > +       struct pwrseq *pwrseq;
>> > +       struct pwrseq_list_per_dev *pwrseq_list_node;
>> > +
>> > +       pwrseq = of_pwrseq_on(np);
>> > +       if (IS_ERR(pwrseq))
>> > +               return PTR_ERR(pwrseq);
>> > +
>> > +       pwrseq_list_node = kzalloc(sizeof(*pwrseq_list_node), GFP_KERNEL);
>>
>> Why don't you allocate memory before turning the power sequence on?
>>
>
> This list is only for power sequence on instance, if I allocate memory before
> power sequence on, I need to free it if power sequence on is failed.

So why is that a problem?

>> > +       if (!pwrseq_list_node) {
>> > +               of_pwrseq_off(pwrseq);
>> > +               return -ENOMEM;
>> > +       }
>> > +       pwrseq_list_node->pwrseq = pwrseq;
>> > +       list_add(&pwrseq_list_node->list, head);
>> > +
>> > +       return 0;
>> > +}
>> > +EXPORT_SYMBOL_GPL(of_pwrseq_on_list);
>>
>> So the caller is supposed to provide a list head of the list to put
>> the power sequence object into on success, right?
>
> Yes
>
>>
>> Can you explain to me what the idea here is, please?
>>
>
> Taking USB devices as an example, there is one power sequence on list
> per bus, and there are several USB devices on the bus. Using a list,
> we can record which device is powered sequence on, and only powers
> sequence off which has already powered sequence on at error path, and
> power sequence off all devices on the bus when the bus (eg, USB HUB)
> is removed. (eg, when the bus driver is removed)

Well, I'm not sure I understand this correctly.

What about system suspend/resume and such, for instance?

> Usually, the power sequence is only needed for hard-wired devices,
> the power sequence on is carried out during the bus driver probed,
> and off if carried out during the bus driver is removed,
> of_pwrseq_on_list/of_powerseq_off_list is not supposed to be
> called during the other bus driver life cycles.
>
>> Also, what's the protection of the list against concurrent access?
>>
>
> I will add comment that the list creator needs to take consideration
> of concurrent access if exists.
>
>> > +
>> > +/**
>> > + * of_pwrseq_off_list: do power sequence off for the list
>> > + *
>> > + * This API is used to power off all devices on this bus, it is
>> > + * the opposite operation for of_pwrseq_on_list.
>> > + *
>> > + * @head: the list head for pwrseq instance list on this bus
>> > + */
>> > +void of_pwrseq_off_list(struct list_head *head)
>> > +{
>> > +       struct pwrseq *pwrseq;
>> > +       struct pwrseq_list_per_dev *pwrseq_list_node, *tmp_node;
>> > +
>> > +       list_for_each_entry_safe(pwrseq_list_node, tmp_node, head, list) {
>> > +               pwrseq = pwrseq_list_node->pwrseq;
>> > +               of_pwrseq_off(pwrseq);
>> > +               list_del(&pwrseq_list_node->list);
>> > +               kfree(pwrseq_list_node);
>> > +       }
>> > +}
>> > +EXPORT_SYMBOL_GPL(of_pwrseq_off_list);
>>
>> This looks horribly inefficient.
>>
>> Is the user expected to create the list from scratch every time things
>> are turned on?
>>
>
> Like I explained above, the power sequence is for hard-wired device on
> board, the list creation and remove are only carried out on driver's
> probe and remove.

Which driver exactly are you referring to?

Thanks,
Rafael

^ permalink raw reply

* [PATCH] PM / Domains: Fix compatible for domain idle state
From: Rafael J. Wysocki @ 2016-12-01 21:21 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAPDyKFqFnk6+Rfdzp-4wzEy8KNkq=03q5qfbkQD4pPNF0Pc6ww@mail.gmail.com>

On Tuesday, November 29, 2016 09:47:03 AM Ulf Hansson wrote:
> On 10 November 2016 at 20:58, Rob Herring <robh@kernel.org> wrote:
> > On Mon, Nov 07, 2016 at 12:14:28PM +0100, Ulf Hansson wrote:
> >> On 3 November 2016 at 22:54, Lina Iyer <lina.iyer@linaro.org> wrote:
> >> > Re-using idle state definition provided by arm,idle-state for domain
> >> > idle states creates a lot of confusion and limits further evolution of
> >> > the domain idle definition. To keep things clear and simple, define a
> >> > idle states for domain using a new compatible "domain-idle-state".
> >> >
> >> > Fix existing PM domains code to look for the newly defined compatible.
> >> >
> >> > Cc: <devicetree@vger.kernel.org>
> >> > Cc: Rob Herring <robh@kernel.org>
> >> > Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> >> > ---
> >> >  .../bindings/power/domain-idle-state.txt           | 33 ++++++++++++++++++++++
> >> >  .../devicetree/bindings/power/power_domain.txt     |  8 +++---
> >> >  drivers/base/power/domain.c                        |  2 +-
> >> >  3 files changed, 38 insertions(+), 5 deletions(-)
> >> >  create mode 100644 Documentation/devicetree/bindings/power/domain-idle-state.txt
> >> >
> >> > diff --git a/Documentation/devicetree/bindings/power/domain-idle-state.txt b/Documentation/devicetree/bindings/power/domain-idle-state.txt
> >> > new file mode 100644
> >> > index 0000000..eefc7ed
> >> > --- /dev/null
> >> > +++ b/Documentation/devicetree/bindings/power/domain-idle-state.txt
> >> > @@ -0,0 +1,33 @@
> >> > +PM Domain Idle State Node:
> >> > +
> >> > +A domain idle state node represents the state parameters that will be used to
> >> > +select the state when there are no active components in the domain.
> >> > +
> >> > +The state node has the following parameters -
> >> > +
> >> > +- compatible:
> >> > +       Usage: Required
> >> > +       Value type: <string>
> >> > +       Definition: Must be "domain-idle-state".
> >> > +
> >> > +- entry-latency-us
> >> > +       Usage: Required
> >> > +       Value type: <prop-encoded-array>
> >> > +       Definition: u32 value representing worst case latency in
> >> > +                   microseconds required to enter the idle state.
> >> > +                   The exit-latency-us duration may be guaranteed
> >> > +                   only after entry-latency-us has passed.
> >>
> >> As we anyway are going to change this, why not use an u64 and have the
> >> value in ns instead of us?
> >
> > I can't imagine that you would need more resolution or range. For times
> > less than 1us, s/w and register access times are going to dominate the
> > time.
> >
> > Unless there is a real need, I'd keep alignment with the existing
> > binding.
> 
> Rob, are you fine with this? I thought it would be great to get this
> in for 4.10 rc1.

Rob, any objections here?

Thanks,
Rafael

^ permalink raw reply

* [PATCH v15] acpi, apei, arm64: APEI initial support for aarch64.
From: Rafael J. Wysocki @ 2016-12-01 21:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161201135112.15396-1-fu.wei@linaro.org>

On Thursday, December 01, 2016 09:51:12 PM fu.wei at linaro.org wrote:
> From: Tomasz Nowicki <tomasz.nowicki@linaro.org>
> 
> This patch provides APEI arch-specific bits for aarch64
> 
> Meanwhile,
> (1)move HEST type (ACPI_HEST_TYPE_IA32_CORRECTED_CHECK) checking to
> a generic place.
> (2)select HAVE_ACPI_APEI when EFI and ACPI is set on ARM64,
> because arch_apei_get_mem_attribute is using efi_mem_attributes on ARM64.
> 
> [Fu Wei: improve && upstream]
> 
> Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
> Tested-by: Jonathan (Zhixiong) Zhang <zjzhang@codeaurora.org>
> Signed-off-by: Fu Wei <fu.wei@linaro.org>
> Acked-by: Hanjun Guo <hanjun.guo@linaro.org>
> Tested-by: Tyler Baicar <tbaicar@codeaurora.org>
> Acked-by: Will Deacon <will.deacon@arm.com>
> Reviewed-by: Borislav Petkov <bp@suse.de>

Well, am I expected to pick up this one?

> ---
> This patchset has been tested on the following platforms:
>     (1)ARM Foundation v8 model
> 
> Changelog:
> v15:https://lkml.org/lkml/2016/12/1/
>     Improve the comment of acpi_disable_cmcff.
>     Rebase to 4.9.0-rc7-gd7c7bc3
> 
> v14:https://lkml.org/lkml/2016/8/10/231
>     Delete hest_ia32_init().
>     Fix a comment typo for acpi_disable_cmcff.
>     Rebase to 4.8.0-rc1-ge6c4d92
> 
> v13:https://lkml.org/lkml/2016/8/10/499
>     Fix a comment problem(add a "end").
>     Add a comment for the definition of acpi_disable_cmcff.
>     Rebase to 4.8.0-rc1-g372734a
> 
> v12:https://lkml.org/lkml/2016/7/29/97
>     Fix a comment problem(redundant "with").
>     Rebase to 4.7.0-g680eee2.
> 
> v11:https://lkml.org/lkml/2016/7/27/427
>     Rebase to v4.7-0e06f5c0.
> 
> v10:https://lkml.org/lkml/2016/4/14
>     Fix the Alphabetical order problem in arch/arm64/Kconfig.
> 
> v9: https://lkml.org/lkml/2016/4/5/522
>     Improve the comment for arch_apei_flush_tlb_one.
>     Using select "HAVE_ACPI_APEI if (ACPI && EFI)" to fix the EFI dependence
>     problem.
> 
> v8: https://lkml.org/lkml/2016/3/29/132
>     Fix a "undefined reference" bug by selecting EFI when ACPI_APEI is set
>     on ARM64.
> 
> v7: https://lkml.org/lkml/2016/3/17/183
>     Add comment for arch_apei_flush_tlb_one in arch/arm64/include/asm/acpi.h.
> 
> v6: https://lists.linaro.org/pipermail/linaro-acpi/2016-March/006644.html
>     Move HEST type (ACPI_HEST_TYPE_IA32_CORRECTED_CHECK) checking to
>     a generic place.
>     Delete HAVE_ACPI_APEI_HEST_IA32.
> 
> v5: https://lkml.org/lkml/2015/12/10/131
>     Add "HAVE_ACPI_APEI_HEST_IA32" instead of
>     "#if defined(__i386__) || defined(__x86_64__)".
> 
> v4: https://lkml.org/lkml/2015/12/8/188
>     Rebase to latest kernel version(4.4-rc4).
>     Move arch_apei_flush_tlb_one into header file as a inline function
>     Add a new subfunction "hest_ia_init" for "acpi_disable_cmcff".
> 
> v3: https://lkml.org/lkml/2015/12/3/521
>     Remove "acpi_disable_cmcff" from arm64 code,
>     and wrap it in hest.c by "#if defined(__i386__) || defined(__x86_64__)"
> 
> v2: https://lkml.org/lkml/2015/12/2/432
>     Rebase to latest kernel version(4.4-rc3).
>     Move arch_apei_flush_tlb_one() to arch/arm64/kernel/acpi.c
> 
> v1: https://lkml.org/lkml/2015/8/14/199
>     Move arch_apei_flush_tlb_one() to arch/arm64/include/asm/apci.h.
>     Delete arch/arm64/kernel/apei.c.
>     Add "#ifdef CONFIG_ACPI_APEI" for "acpi_disable_cmcff".
> 
>  arch/arm64/Kconfig            |  1 +
>  arch/arm64/include/asm/acpi.h | 23 ++++++++++++++++++++++-
>  arch/x86/kernel/acpi/apei.c   |  3 ---
>  drivers/acpi/apei/hest.c      | 13 ++++++++++---
>  4 files changed, 33 insertions(+), 7 deletions(-)
> 
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 969ef88..657be7f 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -52,6 +52,7 @@ config ARM64
>  	select GENERIC_TIME_VSYSCALL
>  	select HANDLE_DOMAIN_IRQ
>  	select HARDIRQS_SW_RESEND
> +	select HAVE_ACPI_APEI if (ACPI && EFI)
>  	select HAVE_ALIGNED_STRUCT_PAGE if SLUB
>  	select HAVE_ARCH_AUDITSYSCALL
>  	select HAVE_ARCH_BITREVERSE
> diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h
> index e517088..d0de0e0 100644
> --- a/arch/arm64/include/asm/acpi.h
> +++ b/arch/arm64/include/asm/acpi.h
> @@ -17,6 +17,7 @@
>  
>  #include <asm/cputype.h>
>  #include <asm/smp_plat.h>
> +#include <asm/tlbflush.h>
>  
>  /* Macros for consistency checks of the GICC subtable of MADT */
>  #define ACPI_MADT_GICC_LENGTH	\
> @@ -114,8 +115,28 @@ static inline const char *acpi_get_enable_method(int cpu)
>  }
>  
>  #ifdef	CONFIG_ACPI_APEI
> +/*
> + * acpi_disable_cmcff is used in drivers/acpi/apei/hest.c for disabling
> + * IA-32 Architecture Corrected Machine Check (CMC) Firmware-First mode
> + * with a kernel command line parameter "acpi=nocmcoff". But we don't
> + * have this IA-32 specific feature on ARM64, this definition is only
> + * for compatibility.
> + */
> +#define acpi_disable_cmcff 1
>  pgprot_t arch_apei_get_mem_attribute(phys_addr_t addr);
> -#endif
> +
> +/*
> + * Despite its name, this function must still broadcast the TLB
> + * invalidation in order to ensure other CPUs don't end up with junk
> + * entries as a result of speculation. Unusually, its also called in
> + * IRQ context (ghes_iounmap_irq) so if we ever need to use IPIs for
> + * TLB broadcasting, then we're in trouble here.
> + */
> +static inline void arch_apei_flush_tlb_one(unsigned long addr)
> +{
> +	flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
> +}
> +#endif /* CONFIG_ACPI_APEI */
>  
>  #ifdef CONFIG_ACPI_NUMA
>  int arm64_acpi_numa_init(void);
> diff --git a/arch/x86/kernel/acpi/apei.c b/arch/x86/kernel/acpi/apei.c
> index c280df6..ea3046e 100644
> --- a/arch/x86/kernel/acpi/apei.c
> +++ b/arch/x86/kernel/acpi/apei.c
> @@ -24,9 +24,6 @@ int arch_apei_enable_cmcff(struct acpi_hest_header *hest_hdr, void *data)
>  	struct acpi_hest_ia_corrected *cmc;
>  	struct acpi_hest_ia_error_bank *mc_bank;
>  
> -	if (hest_hdr->type != ACPI_HEST_TYPE_IA32_CORRECTED_CHECK)
> -		return 0;
> -
>  	cmc = (struct acpi_hest_ia_corrected *)hest_hdr;
>  	if (!cmc->enabled)
>  		return 0;
> diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c
> index 20b3fcf..8f2a98e 100644
> --- a/drivers/acpi/apei/hest.c
> +++ b/drivers/acpi/apei/hest.c
> @@ -123,7 +123,13 @@ EXPORT_SYMBOL_GPL(apei_hest_parse);
>   */
>  static int __init hest_parse_cmc(struct acpi_hest_header *hest_hdr, void *data)
>  {
> -	return arch_apei_enable_cmcff(hest_hdr, data);
> +	if (hest_hdr->type != ACPI_HEST_TYPE_IA32_CORRECTED_CHECK)
> +		return 0;
> +
> +	if (!acpi_disable_cmcff)
> +		return !arch_apei_enable_cmcff(hest_hdr, data);
> +
> +	return 0;
>  }
>  
>  struct ghes_arr {
> @@ -232,8 +238,9 @@ void __init acpi_hest_init(void)
>  		goto err;
>  	}
>  
> -	if (!acpi_disable_cmcff)
> -		apei_hest_parse(hest_parse_cmc, NULL);
> +	rc = apei_hest_parse(hest_parse_cmc, NULL);
> +	if (rc)
> +		goto err;
>  
>  	if (!ghes_disable) {
>  		rc = apei_hest_parse(hest_parse_ghes_count, &ghes_count);
> 

Thanks,
Rafael

^ permalink raw reply

* [PATCH 2/2] clk: bcm: Allow rate change propagation to PLLH_AUX on VEC clock
From: Boris Brezillon @ 2016-12-01 21:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480626020-20031-1-git-send-email-boris.brezillon@free-electrons.com>

The VEC clock requires needs to be set at exactly 108MHz. Allow rate
change propagation on PLLH_AUX to match this requirement wihtout
impacting other IPs (PLLH is currently only used by the HDMI encoder,
which cannot be enabled when the VEC encoder is enabled).

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/clk/bcm/clk-bcm2835.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index df96fe6dadab..eaf82f49dede 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -1861,7 +1861,12 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
 		.ctl_reg = CM_VECCTL,
 		.div_reg = CM_VECDIV,
 		.int_bits = 4,
-		.frac_bits = 0),
+		.frac_bits = 0,
+		/*
+		 * Allow rate change propagation only on PLLH_AUX which is
+		 * assigned index 7 in the parent array.
+		 */
+		.set_rate_parent = BIT(7)),
 
 	/* dsi clocks */
 	[BCM2835_CLOCK_DSI0E]	= REGISTER_PER_CLK(
-- 
2.7.4

^ permalink raw reply related

* [PATCH 1/2] clk: bcm: Support rate change propagation on bcm2835 clocks
From: Boris Brezillon @ 2016-12-01 21:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480626020-20031-1-git-send-email-boris.brezillon@free-electrons.com>

Some peripheral clocks, like the VEC (Video EnCoder) clock need to be set
to a precise rate (in our case 108MHz). With the current implementation,
where peripheral clocks are not allowed to forward rate change requests
to their parents, it is impossible to match this requirement unless the
bootloader has configured things correctly, or a specific rate has been
assigned through the DT (with the assigned-clk-rates property).

Add a new field to struct bcm2835_clock_data to specify which parent
clocks accept rate change propagation, and support set rate propagation
in bcm2835_clock_determine_rate().

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
Note: this approach is still fragile, since it does not prevent 2 clock
users from stepping on each other's toes.
We could use the clk rate constraints infrastructure, but it's only
applicable to leaf clocks in the clock tree (when you apply a constraint,
these constraints are not propagated to the clock tree).

Another approach would be to lock a rate on a clock, thus preventing
other users from changing it. Propagating rate locks would be easier than
propagating rate range constraints (see this patch
http://code.bulix.org/jwtzf8-107264), but it still requires that really
care about a specific clock rate explicitly lock the rate (using
clk_set_and_lock_rate()), and this means checking every drivers that have
such requirements.
---
 drivers/clk/bcm/clk-bcm2835.c | 67 ++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 63 insertions(+), 4 deletions(-)

diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 2acaa77ad482..df96fe6dadab 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -436,6 +436,9 @@ struct bcm2835_clock_data {
 	const char *const *parents;
 	int num_mux_parents;
 
+	/* Bitmap encoding which parents accept rate change propagation. */
+	unsigned int set_rate_parent;
+
 	u32 ctl_reg;
 	u32 div_reg;
 
@@ -1017,10 +1020,60 @@ bcm2835_clk_is_pllc(struct clk_hw *hw)
 	return strncmp(clk_hw_get_name(hw), "pllc", 4) == 0;
 }
 
+static unsigned long bcm2835_clock_choose_div_and_prate(struct clk_hw *hw,
+							int parent_idx,
+							unsigned long rate,
+							u32 *div,
+							unsigned long *prate)
+{
+	struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+	struct bcm2835_cprman *cprman = clock->cprman;
+	const struct bcm2835_clock_data *data = clock->data;
+	unsigned long best_rate;
+	u32 curdiv, mindiv, maxdiv;
+	struct clk_hw *parent;
+
+	parent = clk_hw_get_parent_by_index(hw, parent_idx);
+
+	if (!(BIT(parent_idx) & data->set_rate_parent)) {
+		*prate = clk_hw_get_rate(parent);
+		*div = bcm2835_clock_choose_div(hw, rate, *prate, true);
+
+		return bcm2835_clock_rate_from_divisor(clock, *prate,
+						       *div);
+	}
+
+	if (data->frac_bits)
+		dev_warn(cprman->dev,
+			"frac bits are not used when propagating rate change");
+
+	/* clamp to min divider of 2 if we're dealing with a mash clock */
+	mindiv = data->is_mash_clock ? 2 : 1;
+	maxdiv = BIT(data->int_bits) - 1;
+
+	/* TODO: Be smart, and only test a subset of the available divisors. */
+	for (curdiv = mindiv; curdiv <= maxdiv; curdiv++) {
+		unsigned long tmp_rate;
+
+		tmp_rate = clk_hw_round_rate(parent, rate * curdiv);
+		tmp_rate /= curdiv;
+		if (curdiv == mindiv ||
+		    (tmp_rate > best_rate && tmp_rate <= rate))
+			best_rate = tmp_rate;
+
+		if (best_rate == rate)
+			break;
+	}
+
+	*div = curdiv << CM_DIV_FRAC_BITS;
+	*prate = curdiv * best_rate;
+
+	return best_rate;
+}
+
 static int bcm2835_clock_determine_rate(struct clk_hw *hw,
 					struct clk_rate_request *req)
 {
-	struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
 	struct clk_hw *parent, *best_parent = NULL;
 	bool current_parent_is_pllc;
 	unsigned long rate, best_rate = 0;
@@ -1048,9 +1101,8 @@ static int bcm2835_clock_determine_rate(struct clk_hw *hw,
 		if (bcm2835_clk_is_pllc(parent) && !current_parent_is_pllc)
 			continue;
 
-		prate = clk_hw_get_rate(parent);
-		div = bcm2835_clock_choose_div(hw, req->rate, prate, true);
-		rate = bcm2835_clock_rate_from_divisor(clock, prate, div);
+		rate = bcm2835_clock_choose_div_and_prate(hw, i, req->rate,
+							  &div, &prate);
 		if (rate > best_rate && rate <= req->rate) {
 			best_parent = parent;
 			best_prate = prate;
@@ -1262,6 +1314,13 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman,
 	init.name = data->name;
 	init.flags = data->flags | CLK_IGNORE_UNUSED;
 
+	/*
+	 * Pass the CLK_SET_RATE_PARENT flag if we are allowed to propagate
+	 * rate changes on at least of the parents.
+	 */
+	if (data->set_rate_parent)
+		init.flags |= CLK_SET_RATE_PARENT;
+
 	if (data->is_vpu_clock) {
 		init.ops = &bcm2835_vpu_clock_clk_ops;
 	} else {
-- 
2.7.4

^ permalink raw reply related

* [PATCH 0/2] clk: bcm2835: Propage rate change to PLLH
From: Boris Brezillon @ 2016-12-01 21:00 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

The VEC (Video EnCoder) clock needs to be running at precisely 108Mhz
for the VEC IP to work properly.
Unfortunately, the current implementation does not propate peripheral
clock rate change to their parents, which prevents us from getting
the 108Mhz rate unless the PLLH and PLLH_AUX clocks are already
configured (by the bootloader) to a multiple of 108Mhz.

This series adds support for optional per-periph-clk rate change
propagation and enables this feature on the VEC clock.

Regards,

Boris

Boris Brezillon (2):
  clk: bcm: Support rate change propagation on bcm2835 clocks
  clk: bcm: Allow rate change propagation to PLLH_AUX on VEC clock

 drivers/clk/bcm/clk-bcm2835.c | 74 ++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 69 insertions(+), 5 deletions(-)

-- 
2.7.4

^ permalink raw reply

* [PATCH v2 7/7] ARM: bcm/dt: Enable the VEC IP on all RaspeberryPi boards
From: Eric Anholt @ 2016-12-01 20:47 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480622970-8714-8-git-send-email-boris.brezillon@free-electrons.com>

Boris Brezillon <boris.brezillon@free-electrons.com> writes:

> Enable the VEC IP on all RaspeberryPi boards.

Typo in the subject and body, "Raspberry".  Don't worry about resending
for that, though.
-------------- 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/20161201/373b2a31/attachment.sig>

^ permalink raw reply

* [PATCH] clk: bcm2835: Avoid overwriting the div info when disabling a pll_div clk
From: Eric Anholt @ 2016-12-01 20:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480620441-5442-1-git-send-email-boris.brezillon@free-electrons.com>

Boris Brezillon <boris.brezillon@free-electrons.com> writes:

> bcm2835_pll_divider_off() is resetting the divider field in the A2W reg
> to zero when disabling the clock.
>
> Make sure we preserve this value by reading the previous a2w_reg value
> first and ORing the result with A2W_PLL_CHANNEL_DISABLE.
>
> Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
> Fixes: 41691b8862e2 ("clk: bcm2835: Add support for programming the audio domain clocks")
> Cc: <stable@vger.kernel.org>

Reviewed-by: Eric Anholt <eric@anholt.net>
-------------- 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/20161201/9182a06b/attachment.sig>

^ permalink raw reply

* [PATCH pci/host-iproc] pci-iproc: skip check for legacy IRQ on PAXC buses
From: Ray Jui @ 2016-12-01 20:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480624492-32420-1-git-send-email-gospo@broadcom.com>

Hi Andy,

On 12/1/2016 12:34 PM, Andy Gospodarek wrote:
> PAXC and PAXCv2 buses do not support legacy IRQs so there is no reason
> to even try and map them.  Without a change like this, one cannot create
> VFs on Nitro ports since legacy interrupts are checked as part of the
> PCI device creation process.  Testing on PAXC hardware showed that VFs
> are properly created with only the change to not set pcie->map_irq, but
> just to be safe the change in iproc_pcie_setup will ensure that
> pdev_fixup_irq will not panic.
> 
> Signed-off-by: Andy Gospodarek <gospo@broadcom.com>
> Signed-off-by: Ray Jui <rjui@broadcom.com>

This should be replaced Acked-by: Ray Jui <ray.jui@broadcom.com>

And this patch looks good to me. Thanks!

Ray

> ---
>  drivers/pci/host/pcie-iproc-platform.c | 9 ++++++++-
>  drivers/pci/host/pcie-iproc.c          | 5 ++++-
>  2 files changed, 12 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/pci/host/pcie-iproc-platform.c b/drivers/pci/host/pcie-iproc-platform.c
> index fd3ed9b..22d814a 100644
> --- a/drivers/pci/host/pcie-iproc-platform.c
> +++ b/drivers/pci/host/pcie-iproc-platform.c
> @@ -108,7 +108,14 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev)
>  		return ret;
>  	}
>  
> -	pcie->map_irq = of_irq_parse_and_map_pci;
> +	/* PAXC doesn't support legacy IRQs, skip mapping */
> +	switch (pcie->type) {
> +	case IPROC_PCIE_PAXC:
> +	case IPROC_PCIE_PAXC_V2:
> +		break;
> +	default:
> +		pcie->map_irq = of_irq_parse_and_map_pci;
> +	}
>  
>  	ret = iproc_pcie_setup(pcie, &res);
>  	if (ret)
> diff --git a/drivers/pci/host/pcie-iproc.c b/drivers/pci/host/pcie-iproc.c
> index cd51334..3ebc025 100644
> --- a/drivers/pci/host/pcie-iproc.c
> +++ b/drivers/pci/host/pcie-iproc.c
> @@ -1274,7 +1274,10 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
>  
>  	pci_scan_child_bus(bus);
>  	pci_assign_unassigned_bus_resources(bus);
> -	pci_fixup_irqs(pci_common_swizzle, pcie->map_irq);
> +
> +	if (pcie->map_irq)
> +		pci_fixup_irqs(pci_common_swizzle, pcie->map_irq);
> +
>  	pci_bus_add_devices(bus);
>  
>  	return 0;
> 

^ permalink raw reply

* [PATCH pci/host-iproc] pci-iproc: skip check for legacy IRQ on PAXC buses
From: Andy Gospodarek @ 2016-12-01 20:34 UTC (permalink / raw)
  To: linux-arm-kernel

PAXC and PAXCv2 buses do not support legacy IRQs so there is no reason
to even try and map them.  Without a change like this, one cannot create
VFs on Nitro ports since legacy interrupts are checked as part of the
PCI device creation process.  Testing on PAXC hardware showed that VFs
are properly created with only the change to not set pcie->map_irq, but
just to be safe the change in iproc_pcie_setup will ensure that
pdev_fixup_irq will not panic.

Signed-off-by: Andy Gospodarek <gospo@broadcom.com>
Signed-off-by: Ray Jui <rjui@broadcom.com>
---
 drivers/pci/host/pcie-iproc-platform.c | 9 ++++++++-
 drivers/pci/host/pcie-iproc.c          | 5 ++++-
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/host/pcie-iproc-platform.c b/drivers/pci/host/pcie-iproc-platform.c
index fd3ed9b..22d814a 100644
--- a/drivers/pci/host/pcie-iproc-platform.c
+++ b/drivers/pci/host/pcie-iproc-platform.c
@@ -108,7 +108,14 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	pcie->map_irq = of_irq_parse_and_map_pci;
+	/* PAXC doesn't support legacy IRQs, skip mapping */
+	switch (pcie->type) {
+	case IPROC_PCIE_PAXC:
+	case IPROC_PCIE_PAXC_V2:
+		break;
+	default:
+		pcie->map_irq = of_irq_parse_and_map_pci;
+	}
 
 	ret = iproc_pcie_setup(pcie, &res);
 	if (ret)
diff --git a/drivers/pci/host/pcie-iproc.c b/drivers/pci/host/pcie-iproc.c
index cd51334..3ebc025 100644
--- a/drivers/pci/host/pcie-iproc.c
+++ b/drivers/pci/host/pcie-iproc.c
@@ -1274,7 +1274,10 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
 
 	pci_scan_child_bus(bus);
 	pci_assign_unassigned_bus_resources(bus);
-	pci_fixup_irqs(pci_common_swizzle, pcie->map_irq);
+
+	if (pcie->map_irq)
+		pci_fixup_irqs(pci_common_swizzle, pcie->map_irq);
+
 	pci_bus_add_devices(bus);
 
 	return 0;
-- 
2.1.0

^ permalink raw reply related

* [PATCH][v2] arm64: Add DTS support for FSL's LS1012A SoC
From: Leo Li @ 2016-12-01 20:30 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1479320647-24460-1-git-send-email-harninder.rai@nxp.com>

On Wed, Nov 16, 2016 at 12:24 PM, Harninder Rai <harninder.rai@nxp.com> wrote:
> LS1012A features an advanced 64-bit ARM v8 CortexA53 processor
> with 32 KB of parity protected L1-I cache, 32 KB of ECC protected
> L1-D cache, as well as 256 KB of ECC protected L2 cache.
>
> Features summary
>  One 64-bit ARM-v8 Cortex-A53 core with the following capabilities
>   - Arranged as a cluster of one core supporting a 256 KB L2 cache with ECC
>     protection
>   - Speed up to 800 MHz
>   - Parity-protected 32 KB L1 instruction cache and 32 KB L1 data cache
>   - Neon SIMD engine
>   - ARM v8 cryptography extensions
>  One 16-bit DDR3L SDRAM memory controller
>  ARM core-link CCI-400 cache coherent interconnect
>  Cryptography acceleration (SEC)
>  One Configurable x3 SerDes
>  One PCI Express Gen2 controller, supporting x1 operation
>  One serial ATA (SATA Gen 3.0) controller
>  One USB 3.0/2.0 controller with integrated PHY
>
>  Following levels of DTSI/DTS files have been created for the LS1012A
>    SoC family:
>
>            - fsl-ls1012a.dtsi:
>                    DTS-Include file for FSL LS1012A SoC.
>
>            - fsl-ls1012a-frdm.dts:
>                    DTS file for FSL LS1012A FRDM board.
>
>            - fsl-ls1012a-qds.dts:
>                    DTS file for FSL LS1012A QDS board.
>
>            - fsl-ls1012a-rdb.dts:
>                     DTS file for FSL LS1012A RDB board.
>
> Signed-off-by: Harninder Rai <harninder.rai@nxp.com>
> Signed-off-by: Bhaskar Upadhaya <Bhaskar.Upadhaya@nxp.com>
> ---
> Changes in v2: Incorporated Shawn's comments
> - Brief introduction of the SoC in commit message
> - Alphabetic ordering of labeled nodes
> - Better naming to be used for regulator node
> - Make timer node's comments more readable
> - Sort nodes with unit-address in order of the address
>
>  arch/arm64/boot/dts/freescale/Makefile             |   3 +
>  arch/arm64/boot/dts/freescale/fsl-ls1012a-frdm.dts | 115 ++++++++++
>  arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts  | 128 +++++++++++
>  arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts  |  59 +++++
>  arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi     | 245 +++++++++++++++++++++
>  5 files changed, 550 insertions(+)
>  create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1012a-frdm.dts
>  create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts
>  create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts
>  create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
>
> diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
> index 6602718..39db645 100644
> --- a/arch/arm64/boot/dts/freescale/Makefile
> +++ b/arch/arm64/boot/dts/freescale/Makefile
> @@ -1,3 +1,6 @@
> +dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1012a-frdm.dtb
> +dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1012a-qds.dtb
> +dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1012a-rdb.dtb
>  dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-qds.dtb
>  dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-rdb.dtb
>  dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-qds.dtb
> diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a-frdm.dts b/arch/arm64/boot/dts/freescale/fsl-ls1012a-frdm.dts
> new file mode 100644
> index 0000000..81bd689
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-frdm.dts
> @@ -0,0 +1,115 @@
> +/*
> + * Device Tree file for Freescale LS1012A Freedom Board.
> + *
> + * Copyright 2016, Freescale Semiconductor
> + *
> + * This file is dual-licensed: you can use it either under the terms
> + * of the GPLv2 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 library 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 library 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 "AS IS", 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.
> + */
> +/dts-v1/;
> +
> +#include "fsl-ls1012a.dtsi"
> +
> +/ {
> +       model = "LS1012A Freedom Board";
> +       compatible = "fsl,ls1012a-frdm", "fsl,ls1012a";
> +
> +       sys_mclk: clock-mclk {
> +               compatible = "fixed-clock";
> +               #clock-cells = <0>;
> +               clock-frequency = <25000000>;
> +       };
> +
> +       regulator_1p8v: regulator {
> +               compatible = "regulator-fixed";
> +               regulator-name = "1P8V";
> +               regulator-min-microvolt = <1800000>;
> +               regulator-max-microvolt = <1800000>;
> +               regulator-always-on;
> +       };
> +
> +       sound {
> +               compatible = "simple-audio-card";
> +               simple-audio-card,format = "i2s";
> +               simple-audio-card,widgets =
> +                       "Microphone", "Microphone Jack",
> +                       "Headphone", "Headphone Jack",
> +                       "Speaker", "Speaker Ext",
> +                       "Line", "Line In Jack";
> +               simple-audio-card,routing =
> +                       "MIC_IN", "Microphone Jack",
> +                       "Microphone Jack", "Mic Bias",
> +                       "LINE_IN", "Line In Jack",
> +                       "Headphone Jack", "HP_OUT",
> +                       "Speaker Ext", "LINE_OUT";
> +
> +               simple-audio-card,cpu {
> +                       sound-dai = <&sai2>;
> +                       frame-master;
> +                       bitclock-master;
> +               };
> +
> +               simple-audio-card,codec {
> +                       sound-dai = <&codec>;
> +                       frame-master;
> +                       bitclock-master;
> +                       system-clock-frequency = <25000000>;
> +               };
> +       };
> +};
> +
> +&duart0 {
> +       status = "okay";
> +};
> +
> +&i2c0 {
> +       status = "okay";
> +
> +       codec: sgtl5000 at a {
> +               #sound-dai-cells = <0>;
> +               compatible = "fsl,sgtl5000";
> +               reg = <0xa>;
> +               VDDA-supply = <&regulator_1p8v>;
> +               VDDIO-supply = <&regulator_1p8v>;
> +               clocks = <&sys_mclk>;
> +       };
> +};
> +
> +&sai2 {
> +       status = "okay";
> +};
> diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts b/arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts
> new file mode 100644
> index 0000000..b841251
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts
> @@ -0,0 +1,128 @@
> +/*
> + * Device Tree file for Freescale LS1012A QDS Board.
> + *
> + * Copyright 2016, Freescale Semiconductor
> + *
> + * This file is dual-licensed: you can use it either under the terms
> + * of the GPLv2 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 library 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 library 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 "AS IS", 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.
> + */
> +/dts-v1/;
> +
> +#include "fsl-ls1012a.dtsi"
> +
> +/ {
> +       model = "LS1012A QDS Board";
> +       compatible = "fsl,ls1012a-qds", "fsl,ls1012a";
> +
> +       sys_mclk: clock-mclk {
> +               compatible = "fixed-clock";
> +               #clock-cells = <0>;
> +               clock-frequency = <24576000>;
> +       };
> +
> +       regulator_3p3v: regulator {
> +               compatible = "regulator-fixed";
> +               regulator-name = "3P3V";
> +               regulator-min-microvolt = <3300000>;
> +               regulator-max-microvolt = <3300000>;
> +               regulator-always-on;
> +       };
> +
> +       sound {
> +               compatible = "simple-audio-card";
> +               simple-audio-card,format = "i2s";
> +               simple-audio-card,widgets =
> +                       "Microphone", "Microphone Jack",
> +                       "Headphone", "Headphone Jack",
> +                       "Speaker", "Speaker Ext",
> +                       "Line", "Line In Jack";
> +               simple-audio-card,routing =
> +                       "MIC_IN", "Microphone Jack",
> +                       "Microphone Jack", "Mic Bias",
> +                       "LINE_IN", "Line In Jack",
> +                       "Headphone Jack", "HP_OUT",
> +                       "Speaker Ext", "LINE_OUT";
> +
> +               simple-audio-card,cpu {
> +                       sound-dai = <&sai2>;
> +                       frame-master;
> +                       bitclock-master;
> +               };
> +
> +               simple-audio-card,codec {
> +                       sound-dai = <&codec>;
> +                       frame-master;
> +                       bitclock-master;
> +                       system-clock-frequency = <24576000>;
> +               };
> +       };
> +};
> +
> +&duart0 {
> +       status = "okay";
> +};
> +
> +&i2c0 {
> +       status = "okay";
> +
> +       pca9547 at 77 {
> +               compatible = "nxp,pca9547";
> +               reg = <0x77>;
> +               #address-cells = <1>;
> +               #size-cells = <0>;
> +
> +               i2c at 4 {
> +                       #address-cells = <1>;
> +                       #size-cells = <0>;
> +                       reg = <0x4>;
> +
> +                       codec: sgtl5000 at a {
> +                               #sound-dai-cells = <0>;
> +                               compatible = "fsl,sgtl5000";
> +                               reg = <0xa>;
> +                               VDDA-supply = <&regulator_3p3v>;
> +                               VDDIO-supply = <&regulator_3p3v>;
> +                               clocks = <&sys_mclk>;
> +                       };
> +               };
> +       };
> +};
> +
> +&sai2 {
> +       status = "okay";
> +};
> diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts b/arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts
> new file mode 100644
> index 0000000..62c5c71
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts
> @@ -0,0 +1,59 @@
> +/*
> + * Device Tree file for Freescale LS1012A RDB Board.
> + *
> + * Copyright 2016, Freescale Semiconductor
> + *
> + * This file is dual-licensed: you can use it either under the terms
> + * of the GPLv2 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 library 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 library 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 "AS IS", 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.
> + */
> +/dts-v1/;
> +
> +#include "fsl-ls1012a.dtsi"
> +
> +/ {
> +       model = "LS1012A RDB Board";
> +       compatible = "fsl,ls1012a-rdb", "fsl,ls1012a";
> +};
> +
> +&duart0 {
> +       status = "okay";
> +};
> +
> +&i2c0 {
> +       status = "okay";
> +};
> diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
> new file mode 100644
> index 0000000..24874d7
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
> @@ -0,0 +1,245 @@
> +/*
> + * Device Tree Include file for Freescale Layerscape-1012A family SoC.
> + *
> + * Copyright 2016, Freescale Semiconductor
> + *
> + * This file is dual-licensed: you can use it either under the terms
> + * of the GPLv2 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 library 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 library 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 "AS IS", 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.
> + */
> +
> +#include <dt-bindings/interrupt-controller/irq.h>
> +
> +/ {
> +       compatible = "fsl,ls1012a";
> +       interrupt-parent = <&gic>;
> +       #address-cells = <2>;
> +       #size-cells = <2>;
> +
> +       cpus {
> +               #address-cells = <1>;
> +               #size-cells = <0>;
> +
> +               cpu0: cpu at 0 {
> +                       device_type = "cpu";
> +                       compatible = "arm,cortex-a53";
> +                       reg = <0x0>;
> +                       clocks = <&clockgen 1 0>;
> +                       #cooling-cells = <2>;
> +               };
> +       };
> +
> +       sysclk: sysclk {
> +               compatible = "fixed-clock";
> +               #clock-cells = <0>;
> +               clock-frequency = <100000000>;
> +               clock-output-names = "sysclk";
> +       };
> +
> +       timer {
> +               compatible = "arm,armv8-timer";
> +
> +               interrupts = <1 13 IRQ_TYPE_LEVEL_LOW>,/* Physical Secure PPI */
> +                            <1 14 IRQ_TYPE_LEVEL_LOW>,/* Physical Non-Secure PPI */
> +                            <1 11 IRQ_TYPE_LEVEL_LOW>,/* Virtual PPI */
> +                            <1 10 IRQ_TYPE_LEVEL_LOW>;/* Hypervisor PPI */
> +       };
> +
> +       pmu {
> +               compatible = "arm,armv8-pmuv3";
> +               interrupts = <0 106 IRQ_TYPE_LEVEL_LOW>;
> +       };
> +
> +       gic: interrupt-controller at 1400000 {
> +               compatible = "arm,gic-400";
> +               #interrupt-cells = <3>;
> +               interrupt-controller;
> +               reg = <0x0 0x1401000 0 0x1000>, /* GICD */
> +                     <0x0 0x1402000 0 0x2000>, /* GICC */
> +                     <0x0 0x1404000 0 0x2000>, /* GICH */
> +                     <0x0 0x1406000 0 0x2000>; /* GICV */
> +               interrupts = <1 9 IRQ_TYPE_LEVEL_LOW>;
> +       };
> +
> +       reboot {
> +               compatible = "syscon-reboot";
> +               regmap = <&dcfg>;
> +               offset = <0xb0>;
> +               mask = <0x02>;
> +       };
> +
> +       soc {
> +               compatible = "simple-bus";
> +               #address-cells = <2>;
> +               #size-cells = <2>;
> +               ranges;
> +
> +               scfg: scfg at 1570000 {
> +                       compatible = "fsl,ls1012a-scfg", "syscon";
> +                       reg = <0x0 0x1570000 0x0 0x10000>;
> +                       big-endian;
> +               };
> +
> +               dcfg: dcfg at 1ee0000 {
> +                       compatible = "fsl,ls1012a-dcfg",
> +                                    "syscon";
> +                       reg = <0x0 0x1ee0000 0x0 0x10000>;
> +                       big-endian;
> +               };
> +
> +               clockgen: clocking at 1ee1000 {
> +                       compatible = "fsl,ls1012a-clockgen";
> +                       reg = <0x0 0x1ee1000 0x0 0x1000>;
> +                       #clock-cells = <2>;
> +                       clocks = <&sysclk>;
> +               };
> +
> +               i2c0: i2c at 2180000 {
> +                       compatible = "fsl,vf610-i2c";
> +                       #address-cells = <1>;
> +                       #size-cells = <0>;
> +                       reg = <0x0 0x2180000 0x0 0x10000>;
> +                       interrupts = <0 56 IRQ_TYPE_LEVEL_LOW>;

All the SPI interrupts connected to GIC400 should be level high.  This
is also true for the interrupts below.

> +                       clocks = <&clockgen 4 0>;
> +                       status = "disabled";
> +               };
> +
> +               i2c1: i2c at 2190000 {
> +                       compatible = "fsl,vf610-i2c";
> +                       #address-cells = <1>;
> +                       #size-cells = <0>;
> +                       reg = <0x0 0x2190000 0x0 0x10000>;
> +                       interrupts = <0 57 IRQ_TYPE_LEVEL_LOW>;
> +                       clocks = <&clockgen 4 0>;
> +                       status = "disabled";
> +               };
> +
> +               duart0: serial at 21c0500 {
> +                       compatible = "fsl,ns16550", "ns16550a";
> +                       reg = <0x00 0x21c0500 0x0 0x100>;
> +                       interrupts = <0 54 IRQ_TYPE_LEVEL_HIGH>;
> +                       clocks = <&clockgen 4 0>;
> +               };
> +
> +               duart1: serial at 21c0600 {
> +                       compatible = "fsl,ns16550", "ns16550a";
> +                       reg = <0x00 0x21c0600 0x0 0x100>;
> +                       interrupts = <0 54 IRQ_TYPE_LEVEL_HIGH>;
> +                       clocks = <&clockgen 4 0>;
> +               };
> +
> +               gpio0: gpio at 2300000 {
> +                       compatible = "fsl,qoriq-gpio";
> +                       reg = <0x0 0x2300000 0x0 0x10000>;
> +                       interrupts = <0 66 IRQ_TYPE_LEVEL_LOW>;
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpio1: gpio at 2310000 {
> +                       compatible = "fsl,qoriq-gpio";
> +                       reg = <0x0 0x2310000 0x0 0x10000>;
> +                       interrupts = <0 67 IRQ_TYPE_LEVEL_LOW>;
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               wdog0: wdog at 2ad0000 {
> +                       compatible = "fsl,ls1012a-wdt",
> +                                    "fsl,imx21-wdt";
> +                       reg = <0x0 0x2ad0000 0x0 0x10000>;
> +                       interrupts = <0 83 IRQ_TYPE_LEVEL_LOW>;
> +                       clocks = <&clockgen 4 0>;
> +                       big-endian;
> +               };
> +
> +               sai1: sai at 2b50000 {
> +                       #sound-dai-cells = <0>;
> +                       compatible = "fsl,vf610-sai";
> +                       reg = <0x0 0x2b50000 0x0 0x10000>;
> +                       interrupts = <0 148 IRQ_TYPE_LEVEL_LOW>;
> +                       clocks = <&clockgen 4 3>, <&clockgen 4 3>,
> +                                <&clockgen 4 3>, <&clockgen 4 3>;
> +                       clock-names = "bus", "mclk1", "mclk2", "mclk3";
> +                       dma-names = "tx", "rx";
> +                       dmas = <&edma0 1 47>,
> +                              <&edma0 1 46>;
> +                       status = "disabled";
> +               };
> +
> +               sai2: sai at 2b60000 {
> +                       #sound-dai-cells = <0>;
> +                       compatible = "fsl,vf610-sai";
> +                       reg = <0x0 0x2b60000 0x0 0x10000>;
> +                       interrupts = <0 149 IRQ_TYPE_LEVEL_LOW>;
> +                       clocks = <&clockgen 4 3>, <&clockgen 4 3>,
> +                                <&clockgen 4 3>, <&clockgen 4 3>;
> +                       clock-names = "bus", "mclk1", "mclk2", "mclk3";
> +                       dma-names = "tx", "rx";
> +                       dmas = <&edma0 1 45>,
> +                              <&edma0 1 44>;
> +                       status = "disabled";
> +               };
> +
> +               edma0: edma at 2c00000 {
> +                       #dma-cells = <2>;
> +                       compatible = "fsl,vf610-edma";
> +                       reg = <0x0 0x2c00000 0x0 0x10000>,
> +                             <0x0 0x2c10000 0x0 0x10000>,
> +                             <0x0 0x2c20000 0x0 0x10000>;
> +                       interrupts = <0 103 IRQ_TYPE_LEVEL_LOW>,
> +                                    <0 103 IRQ_TYPE_LEVEL_LOW>;
> +                       interrupt-names = "edma-tx", "edma-err";
> +                       dma-channels = <32>;
> +                       big-endian;
> +                       clock-names = "dmamux0", "dmamux1";
> +                       clocks = <&clockgen 4 3>,
> +                                <&clockgen 4 3>;
> +               };
> +
> +               sata: sata at 3200000 {
> +                       compatible = "fsl,ls1012a-ahci", "fsl,ls1043a-ahci";
> +                       reg = <0x0 0x3200000 0x0 0x10000>;
> +                       interrupts = <0 69 IRQ_TYPE_LEVEL_LOW>;
> +                       clocks = <&clockgen 4 0>;
> +               };
> +       };
> +};
> --
> 1.9.1

^ permalink raw reply

* [RFC v2 PATCH 23/23] ARM: Allow ARCH_MULTIPLATFORM to be selected for NOMMU
From: Chris Brandt @ 2016-12-01 20:11 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <583EA390.7000705@arm.com>

On 11/29/2016, Vladimir Murzin wrote:
> >> motivation behind of this patch:
> >> - bring build coverage for NOMMU configurations
> >> - allow known working NOMMU platforms (like R-class) to be used
> >> - pave a way to add support for single address space (aka 1:1 mapping)
> >>   for MMU platforms, so they can be usable in NOMMU configurations


I use XIP_KERNEL with a MMU platform (Renesas RZ/A1, Cortex A9) which is
also ARCH_MULTIPLATFORM.

So I also have to hack the Kconfig to get it to build.

I had proposed this patch to allow you to select which multiplatform
devices are XIP capable, but it never made it in.

https://patchwork.kernel.org/patch/8395661/


Maybe you can do the same idea for !MMU platforms as well (just
say whether the device can do XIP regardless of MMU or !MMU)


Chris

^ permalink raw reply

* [PATCH v2 7/7] ARM: bcm/dt: Enable the VEC IP on all RaspeberryPi boards
From: Boris Brezillon @ 2016-12-01 20:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480622970-8714-1-git-send-email-boris.brezillon@free-electrons.com>

Enable the VEC IP on all RaspeberryPi boards.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 arch/arm/boot/dts/bcm2835-rpi.dtsi | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi
index e9b47b2bbc33..8893240da5f6 100644
--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
@@ -84,3 +84,8 @@
 	power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
 	status = "okay";
 };
+
+&vec {
+	power-domains = <&power RPI_POWER_DOMAIN_VEC>;
+	status = "okay";
+};
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 6/7] ARM: bcm/dt: Add VEC node in bcm283x.dtsi
From: Boris Brezillon @ 2016-12-01 20:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480622970-8714-1-git-send-email-boris.brezillon@free-electrons.com>

Add the VEC (Video EnCoder) node definition in bcm283x.dtsi.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 arch/arm/boot/dts/bcm283x.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi
index 46d46d894a44..44a9c0539437 100644
--- a/arch/arm/boot/dts/bcm283x.dtsi
+++ b/arch/arm/boot/dts/bcm283x.dtsi
@@ -266,6 +266,14 @@
 			status = "disabled";
 		};
 
+		vec: vec at 7e806000 {
+			compatible = "brcm,bcm2835-vec";
+			reg = <0x7e806000 0x1000>;
+			clocks = <&clocks BCM2835_CLOCK_VEC>;
+			interrupts = <2 27>;
+			status = "disabled";
+		};
+
 		pixelvalve at 7e807000 {
 			compatible = "brcm,bcm2835-pixelvalve2";
 			reg = <0x7e807000 0x100>;
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 5/7] drm/vc4: Document VEC DT binding
From: Boris Brezillon @ 2016-12-01 20:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480622970-8714-1-git-send-email-boris.brezillon@free-electrons.com>

Document the DT binding for the VEC (Video EnCoder) IP.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt b/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt
index a5ea451e67fc..e2768703ac2b 100644
--- a/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt
+++ b/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt
@@ -43,6 +43,13 @@ Required properties for DPI:
 - port:		Port node with a single endpoint connecting to the panel
 		  device, as defined in [1]
 
+Required properties for VEC:
+- compatible:	Should be "brcm,bcm2835-vec"
+- reg:		Physical base address and length of the registers
+- clocks:	The core clock the unit runs on
+- interrupts:	The interrupt number
+		  See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt
+
 Required properties for V3D:
 - compatible:	Should be "brcm,bcm2835-v3d"
 - reg:		Physical base address and length of the V3D's registers
@@ -92,6 +99,13 @@ dpi: dpi at 7e208000 {
 	};
 };
 
+vec: vec at 7e806000 {
+	compatible = "brcm,bcm2835-vec";
+	reg = <0x7e806000 0x1000>;
+	clocks = <&clocks BCM2835_CLOCK_VEC>;
+	interrupts = <2 27>;
+};
+
 v3d: v3d at 7ec00000 {
 	compatible = "brcm,bcm2835-v3d";
 	reg = <0x7ec00000 0x1000>;
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 4/7] drm/vc4: Add support for the VEC (Video Encoder) IP
From: Boris Brezillon @ 2016-12-01 20:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480622970-8714-1-git-send-email-boris.brezillon@free-electrons.com>

The VEC IP is a TV DAC, providing support for PAL and NTSC standards.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/gpu/drm/vc4/Makefile      |   1 +
 drivers/gpu/drm/vc4/vc4_debugfs.c |   1 +
 drivers/gpu/drm/vc4/vc4_drv.c     |   1 +
 drivers/gpu/drm/vc4/vc4_drv.h     |   5 +
 drivers/gpu/drm/vc4/vc4_vec.c     | 657 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 665 insertions(+)
 create mode 100644 drivers/gpu/drm/vc4/vc4_vec.c

diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile
index fb77db755e0a..7757f69a8a77 100644
--- a/drivers/gpu/drm/vc4/Makefile
+++ b/drivers/gpu/drm/vc4/Makefile
@@ -11,6 +11,7 @@ vc4-y := \
 	vc4_kms.o \
 	vc4_gem.o \
 	vc4_hdmi.o \
+	vc4_vec.o \
 	vc4_hvs.o \
 	vc4_irq.o \
 	vc4_plane.o \
diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c
index 245115d49c46..caf817bac885 100644
--- a/drivers/gpu/drm/vc4/vc4_debugfs.c
+++ b/drivers/gpu/drm/vc4/vc4_debugfs.c
@@ -19,6 +19,7 @@ static const struct drm_info_list vc4_debugfs_list[] = {
 	{"bo_stats", vc4_bo_stats_debugfs, 0},
 	{"dpi_regs", vc4_dpi_debugfs_regs, 0},
 	{"hdmi_regs", vc4_hdmi_debugfs_regs, 0},
+	{"vec_regs", vc4_vec_debugfs_regs, 0},
 	{"hvs_regs", vc4_hvs_debugfs_regs, 0},
 	{"crtc0_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)0},
 	{"crtc1_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)1},
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
index 8703f56b7947..3e6cb78f7381 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.c
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
@@ -289,6 +289,7 @@ static const struct component_master_ops vc4_drm_ops = {
 
 static struct platform_driver *const component_drivers[] = {
 	&vc4_hdmi_driver,
+	&vc4_vec_driver,
 	&vc4_dpi_driver,
 	&vc4_hvs_driver,
 	&vc4_crtc_driver,
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index 946d48c33668..b3a46a51f9d0 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -17,6 +17,7 @@ struct vc4_dev {
 	struct vc4_crtc *crtc[3];
 	struct vc4_v3d *v3d;
 	struct vc4_dpi *dpi;
+	struct vc4_vec *vec;
 
 	struct drm_fbdev_cma *fbdev;
 
@@ -484,6 +485,10 @@ int vc4_queue_seqno_cb(struct drm_device *dev,
 extern struct platform_driver vc4_hdmi_driver;
 int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused);
 
+/* vc4_hdmi.c */
+extern struct platform_driver vc4_vec_driver;
+int vc4_vec_debugfs_regs(struct seq_file *m, void *unused);
+
 /* vc4_irq.c */
 irqreturn_t vc4_irq(int irq, void *arg);
 void vc4_irq_preinstall(struct drm_device *dev);
diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
new file mode 100644
index 000000000000..2d4256fcc6f2
--- /dev/null
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
@@ -0,0 +1,657 @@
+/*
+ * Copyright (C) 2016 Broadcom Limited
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * DOC: VC4 SDTV module
+ */
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_panel.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/of_graph.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+
+#include "vc4_drv.h"
+#include "vc4_regs.h"
+
+/* WSE Registers */
+#define VEC_WSE_RESET			0xc0
+
+#define VEC_WSE_CONTROL			0xc4
+#define VEC_WSE_WSS_ENABLE		BIT(7)
+
+#define VEC_WSE_WSS_DATA		0xc8
+#define VEC_WSE_VPS_DATA1		0xcc
+#define VEC_WSE_VPS_CONTROL		0xd0
+
+/* VEC Registers */
+#define VEC_REVID			0x100
+
+#define VEC_CONFIG0			0x104
+#define VEC_CONFIG0_YDEL_MASK		GENMASK(28, 26)
+#define VEC_CONFIG0_YDEL(x)		((x) << 26)
+#define VEC_CONFIG0_CDEL_MASK		GENMASK(25, 24)
+#define VEC_CONFIG0_CDEL(x)		((x) << 24)
+#define VEC_CONFIG0_PBPR_FIL		BIT(18)
+#define VEC_CONFIG0_CHROMA_GAIN_MASK	GENMASK(17, 16)
+#define VEC_CONFIG0_CHROMA_GAIN_UNITY	(0 << 16)
+#define VEC_CONFIG0_CHROMA_GAIN_1_32	(1 << 16)
+#define VEC_CONFIG0_CHROMA_GAIN_1_16	(2 << 16)
+#define VEC_CONFIG0_CHROMA_GAIN_1_8	(3 << 16)
+#define VEC_CONFIG0_CBURST_GAIN_MASK	GENMASK(14, 13)
+#define VEC_CONFIG0_CBURST_GAIN_UNITY	(0 << 13)
+#define VEC_CONFIG0_CBURST_GAIN_1_128	(1 << 13)
+#define VEC_CONFIG0_CBURST_GAIN_1_64	(2 << 13)
+#define VEC_CONFIG0_CBURST_GAIN_1_32	(3 << 13)
+#define VEC_CONFIG0_CHRBW1		BIT(11)
+#define VEC_CONFIG0_CHRBW0		BIT(10)
+#define VEC_CONFIG0_SYNCDIS		BIT(9)
+#define VEC_CONFIG0_BURDIS		BIT(8)
+#define VEC_CONFIG0_CHRDIS		BIT(7)
+#define VEC_CONFIG0_PDEN		BIT(6)
+#define VEC_CONFIG0_YCDELAY		BIT(4)
+#define VEC_CONFIG0_RAMPEN		BIT(2)
+#define VEC_CONFIG0_YCDIS		BIT(2)
+#define VEC_CONFIG0_STD_MASK		GENMASK(1, 0)
+#define VEC_CONFIG0_NTSC_STD		0
+#define VEC_CONFIG0_PAL_BDGHI_STD	1
+#define VEC_CONFIG0_PAL_N_STD		3
+
+#define VEC_SCHPH			0x108
+#define VEC_SOFT_RESET			0x10c
+#define VEC_CLMP0_START			0x144
+#define VEC_CLMP0_END			0x148
+#define VEC_FREQ3_2			0x180
+#define VEC_FREQ1_0			0x184
+
+#define VEC_CONFIG1			0x188
+#define VEC_CONFIG_VEC_RESYNC_OFF	BIT(18)
+#define VEC_CONFIG_RGB219		BIT(17)
+#define VEC_CONFIG_CBAR_EN		BIT(16)
+#define VEC_CONFIG_TC_OBB		BIT(15)
+#define VEC_CONFIG1_OUTPUT_MODE_MASK	GENMASK(12, 10)
+#define VEC_CONFIG1_C_Y_CVBS		(0 << 10)
+#define VEC_CONFIG1_CVBS_Y_C		(1 << 10)
+#define VEC_CONFIG1_PR_Y_PB		(2 << 10)
+#define VEC_CONFIG1_RGB			(4 << 10)
+#define VEC_CONFIG1_Y_C_CVBS		(5 << 10)
+#define VEC_CONFIG1_C_CVBS_Y		(6 << 10)
+#define VEC_CONFIG1_C_CVBS_CVBS		(7 << 10)
+#define VEC_CONFIG1_DIS_CHR		BIT(9)
+#define VEC_CONFIG1_DIS_LUMA		BIT(8)
+#define VEC_CONFIG1_YCBCR_IN		BIT(6)
+#define VEC_CONFIG1_DITHER_TYPE_LFSR	0
+#define VEC_CONFIG1_DITHER_TYPE_COUNTER	BIT(5)
+#define VEC_CONFIG1_DITHER_EN		BIT(4)
+#define VEC_CONFIG1_CYDELAY		BIT(3)
+#define VEC_CONFIG1_LUMADIS		BIT(2)
+#define VEC_CONFIG1_COMPDIS		BIT(1)
+#define VEC_CONFIG1_CUSTOM_FREQ		BIT(0)
+
+#define VEC_CONFIG2			0x18c
+#define VEC_CONFIG2_PROG_SCAN		BIT(15)
+#define VEC_CONFIG2_SYNC_ADJ_MASK	GENMASK(14, 12)
+#define VEC_CONFIG2_SYNC_ADJ(x)		(((x) / 2) << 12)
+#define VEC_CONFIG2_PBPR_EN		BIT(10)
+#define VEC_CONFIG2_UV_DIG_DIS		BIT(6)
+#define VEC_CONFIG2_RGB_DIG_DIS		BIT(5)
+#define VEC_CONFIG2_TMUX_MASK		GENMASK(3, 2)
+#define VEC_CONFIG2_TMUX_DRIVE0		(0 << 2)
+#define VEC_CONFIG2_TMUX_RG_COMP	(1 << 2)
+#define VEC_CONFIG2_TMUX_UV_YC		(2 << 2)
+#define VEC_CONFIG2_TMUX_SYNC_YC	(3 << 2)
+
+#define VEC_INTERRUPT_CONTROL		0x190
+#define VEC_INTERRUPT_STATUS		0x194
+#define VEC_FCW_SECAM_B			0x198
+#define VEC_SECAM_GAIN_VAL		0x19c
+
+#define VEC_CONFIG3			0x1a0
+#define VEC_CONFIG3_HORIZ_LEN_STD	(0 << 0)
+#define VEC_CONFIG3_HORIZ_LEN_MPEG1_SIF	(1 << 0)
+#define VEC_CONFIG3_SHAPE_NON_LINEAR	BIT(1)
+
+#define VEC_STATUS0			0x200
+#define VEC_MASK0			0x204
+
+#define VEC_CFG				0x208
+#define VEC_CFG_SG_MODE_MASK		GENMASK(6, 5)
+#define VEC_CFG_SG_MODE(x)		((x) << 5)
+#define VEC_CFG_SG_EN			BIT(4)
+#define VEC_CFG_VEC_EN			BIT(3)
+#define VEC_CFG_MB_EN			BIT(2)
+#define VEC_CFG_ENABLE			BIT(1)
+#define VEC_CFG_TB_EN			BIT(0)
+
+#define VEC_DAC_TEST			0x20c
+
+#define VEC_DAC_CONFIG			0x210
+#define VEC_DAC_CONFIG_LDO_BIAS_CTRL(x)	((x) << 24)
+#define VEC_DAC_CONFIG_DRIVER_CTRL(x)	((x) << 16)
+#define VEC_DAC_CONFIG_DAC_CTRL(x)	(x)
+
+#define VEC_DAC_MISC			0x214
+#define VEC_DAC_MISC_VCD_CTRL_MASK	GENMASK(31, 16)
+#define VEC_DAC_MISC_VCD_CTRL(x)	((x) << 16)
+#define VEC_DAC_MISC_VID_ACT		BIT(8)
+#define VEC_DAC_MISC_VCD_PWRDN		BIT(6)
+#define VEC_DAC_MISC_BIAS_PWRDN		BIT(5)
+#define VEC_DAC_MISC_DAC_PWRDN		BIT(2)
+#define VEC_DAC_MISC_LDO_PWRDN		BIT(1)
+#define VEC_DAC_MISC_DAC_RST_N		BIT(0)
+
+
+/* General VEC hardware state. */
+struct vc4_vec {
+	struct platform_device *pdev;
+
+	struct drm_encoder *encoder;
+	struct drm_connector *connector;
+
+	void __iomem *regs;
+
+	struct clk *clock;
+
+	const struct vc4_vec_tv_mode *tv_mode;
+};
+
+#define VEC_READ(offset) readl(vec->regs + (offset))
+#define VEC_WRITE(offset, val) writel(val, vec->regs + (offset))
+
+/* VC4 VEC encoder KMS struct */
+struct vc4_vec_encoder {
+	struct vc4_encoder base;
+	struct vc4_vec *vec;
+};
+
+static inline struct vc4_vec_encoder *
+to_vc4_vec_encoder(struct drm_encoder *encoder)
+{
+	return container_of(encoder, struct vc4_vec_encoder, base.base);
+}
+
+/* VC4 VEC connector KMS struct */
+struct vc4_vec_connector {
+	struct drm_connector base;
+	struct vc4_vec *vec;
+
+	/* Since the connector is attached to just the one encoder,
+	 * this is the reference to it so we can do the best_encoder()
+	 * hook.
+	 */
+	struct drm_encoder *encoder;
+};
+
+static inline struct vc4_vec_connector *
+to_vc4_vec_connector(struct drm_connector *connector)
+{
+	return container_of(connector, struct vc4_vec_connector, base);
+}
+
+enum vc4_vec_tv_mode_id {
+	VC4_VEC_TV_MODE_NTSC,
+	VC4_VEC_TV_MODE_NTSC_J,
+	VC4_VEC_TV_MODE_PAL,
+	VC4_VEC_TV_MODE_PAL_M,
+};
+
+struct vc4_vec_tv_mode {
+	const struct drm_display_mode *mode;
+	void (*mode_set)(struct vc4_vec *vec);
+};
+
+#define VEC_REG(reg) { reg, #reg }
+static const struct {
+	u32 reg;
+	const char *name;
+} vec_regs[] = {
+	VEC_REG(VEC_WSE_CONTROL),
+	VEC_REG(VEC_WSE_WSS_DATA),
+	VEC_REG(VEC_WSE_VPS_DATA1),
+	VEC_REG(VEC_WSE_VPS_CONTROL),
+	VEC_REG(VEC_REVID),
+	VEC_REG(VEC_CONFIG0),
+	VEC_REG(VEC_SCHPH),
+	VEC_REG(VEC_CLMP0_START),
+	VEC_REG(VEC_CLMP0_END),
+	VEC_REG(VEC_FREQ3_2),
+	VEC_REG(VEC_FREQ1_0),
+	VEC_REG(VEC_CONFIG1),
+	VEC_REG(VEC_CONFIG2),
+	VEC_REG(VEC_INTERRUPT_CONTROL),
+	VEC_REG(VEC_INTERRUPT_STATUS),
+	VEC_REG(VEC_FCW_SECAM_B),
+	VEC_REG(VEC_SECAM_GAIN_VAL),
+	VEC_REG(VEC_CONFIG3),
+	VEC_REG(VEC_STATUS0),
+	VEC_REG(VEC_MASK0),
+	VEC_REG(VEC_CFG),
+	VEC_REG(VEC_DAC_TEST),
+	VEC_REG(VEC_DAC_CONFIG),
+	VEC_REG(VEC_DAC_MISC),
+};
+
+#ifdef CONFIG_DEBUG_FS
+int vc4_vec_debugfs_regs(struct seq_file *m, void *unused)
+{
+	struct drm_info_node *node = (struct drm_info_node *)m->private;
+	struct drm_device *dev = node->minor->dev;
+	struct vc4_dev *vc4 = to_vc4_dev(dev);
+	struct vc4_vec *vec = vc4->vec;
+	int i;
+
+	if (!vec)
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(vec_regs); i++) {
+		seq_printf(m, "%s (0x%04x): 0x%08x\n",
+			   vec_regs[i].name, vec_regs[i].reg,
+			   VEC_READ(vec_regs[i].reg));
+	}
+
+	return 0;
+}
+#endif
+
+static void vc4_vec_ntsc_mode_set(struct vc4_vec *vec)
+{
+	VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN);
+	VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
+}
+
+static void vc4_vec_ntsc_j_mode_set(struct vc4_vec *vec)
+{
+	VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD);
+	VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
+}
+
+static const struct drm_display_mode ntsc_mode = {
+	DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 13500,
+		 720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0,
+		 480, 480 + 3, 480 + 3 + 3, 480 + 3 + 3 + 16, 0,
+		 DRM_MODE_FLAG_INTERLACE)
+};
+
+static void vc4_vec_pal_mode_set(struct vc4_vec *vec)
+{
+	VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD);
+	VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
+}
+
+static void vc4_vec_pal_m_mode_set(struct vc4_vec *vec)
+{
+	VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD);
+	VEC_WRITE(VEC_CONFIG1,
+		  VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ);
+	VEC_WRITE(VEC_FREQ3_2, 0x223b);
+	VEC_WRITE(VEC_FREQ1_0, 0x61d1);
+}
+
+static const struct drm_display_mode pal_mode = {
+	DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 13500,
+		 720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0,
+		 576, 576 + 2, 576 + 2 + 3, 576 + 2 + 3 + 20, 0,
+		 DRM_MODE_FLAG_INTERLACE)
+};
+
+static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
+	[VC4_VEC_TV_MODE_NTSC] = {
+		.mode = &ntsc_mode,
+		.mode_set = vc4_vec_ntsc_mode_set,
+	},
+	[VC4_VEC_TV_MODE_NTSC_J] = {
+		.mode = &ntsc_mode,
+		.mode_set = vc4_vec_ntsc_j_mode_set,
+	},
+	[VC4_VEC_TV_MODE_PAL] = {
+		.mode = &pal_mode,
+		.mode_set = vc4_vec_pal_mode_set,
+	},
+	[VC4_VEC_TV_MODE_PAL_M] = {
+		.mode = &pal_mode,
+		.mode_set = vc4_vec_pal_m_mode_set,
+	},
+};
+
+static enum drm_connector_status
+vc4_vec_connector_detect(struct drm_connector *connector, bool force)
+{
+	return connector_status_unknown;
+}
+
+static void vc4_vec_connector_destroy(struct drm_connector *connector)
+{
+	drm_connector_unregister(connector);
+	drm_connector_cleanup(connector);
+}
+
+static int vc4_vec_connector_get_modes(struct drm_connector *connector)
+{
+	struct drm_connector_state *state = connector->state;
+	struct drm_display_mode *mode;
+
+	mode = drm_mode_duplicate(connector->dev,
+				  vc4_vec_tv_modes[state->tv.mode].mode);
+	if (!mode) {
+		DRM_ERROR("Failed to create a new display mode\n");
+		return -ENOMEM;
+	}
+
+	drm_mode_probed_add(connector, mode);
+
+	return 1;
+}
+
+static const struct drm_connector_funcs vc4_vec_connector_funcs = {
+	.dpms = drm_atomic_helper_connector_dpms,
+	.detect = vc4_vec_connector_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.set_property = drm_atomic_helper_connector_set_property,
+	.destroy = vc4_vec_connector_destroy,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static const struct drm_connector_helper_funcs vc4_vec_connector_helper_funcs = {
+	.get_modes = vc4_vec_connector_get_modes,
+};
+
+static struct drm_connector *vc4_vec_connector_init(struct drm_device *dev,
+						    struct vc4_vec *vec)
+{
+	struct drm_connector *connector = NULL;
+	struct vc4_vec_connector *vec_connector;
+
+	vec_connector = devm_kzalloc(dev->dev, sizeof(*vec_connector),
+				     GFP_KERNEL);
+	if (!vec_connector)
+		return ERR_PTR(-ENOMEM);
+
+	connector = &vec_connector->base;
+	connector->interlace_allowed = true;
+
+	vec_connector->encoder = vec->encoder;
+	vec_connector->vec = vec;
+
+	drm_connector_init(dev, connector, &vc4_vec_connector_funcs,
+			   DRM_MODE_CONNECTOR_Composite);
+	drm_connector_helper_add(connector, &vc4_vec_connector_helper_funcs);
+
+	drm_object_attach_property(&connector->base,
+				   dev->mode_config.tv_mode_property,
+				   VC4_VEC_TV_MODE_NTSC);
+	vec->tv_mode = &vc4_vec_tv_modes[VC4_VEC_TV_MODE_NTSC];
+
+	drm_mode_connector_attach_encoder(connector, vec->encoder);
+
+	return connector;
+}
+
+static const struct drm_encoder_funcs vc4_vec_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+static void vc4_vec_encoder_disable(struct drm_encoder *encoder)
+{
+	struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder);
+	struct vc4_vec *vec = vc4_vec_encoder->vec;
+	int ret;
+
+	VEC_WRITE(VEC_CFG, 0);
+	VEC_WRITE(VEC_DAC_MISC,
+		  VEC_DAC_MISC_VCD_PWRDN |
+		  VEC_DAC_MISC_BIAS_PWRDN |
+		  VEC_DAC_MISC_DAC_PWRDN |
+		  VEC_DAC_MISC_LDO_PWRDN);
+
+	clk_disable_unprepare(vec->clock);
+
+	ret = pm_runtime_put(&vec->pdev->dev);
+	if (ret < 0) {
+		DRM_ERROR("Failed to release power domain: %d\n", ret);
+		return;
+	}
+}
+
+static void vc4_vec_encoder_enable(struct drm_encoder *encoder)
+{
+	struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder);
+	struct vc4_vec *vec = vc4_vec_encoder->vec;
+	int ret;
+
+	ret = pm_runtime_get_sync(&vec->pdev->dev);
+	if (ret < 0) {
+		DRM_ERROR("Failed to retain power domain: %d\n", ret);
+		return;
+	}
+
+	/*
+	 * We need to set the clock rate each time we enable the encoder
+	 * because there's a chance we share the same parent with the HDMI
+	 * clock, and both drivers are requesting different rates.
+	 * The good news is, these 2 encoders cannot be enabled@the same
+	 * time, thus preventing incompatible rate requests.
+	 */
+	ret = clk_set_rate(vec->clock, 108000000);
+	if (ret) {
+		DRM_ERROR("Failed to set clock rate: %d\n", ret);
+		return;
+	}
+
+	ret = clk_prepare_enable(vec->clock);
+	if (ret) {
+		DRM_ERROR("Failed to turn on core clock: %d\n", ret);
+		return;
+	}
+
+	/* Reset the different blocks */
+	VEC_WRITE(VEC_WSE_RESET, 1);
+	VEC_WRITE(VEC_SOFT_RESET, 1);
+
+	/* Disable the CGSM-A and WSE blocks */
+	VEC_WRITE(VEC_WSE_CONTROL, 0);
+
+	/* Write config common to all modes. */
+
+	/*
+	 * Color subcarrier phase: phase = 360 * SCHPH / 256.
+	 * 0x28 <=> 39.375 deg.
+	 */
+	VEC_WRITE(VEC_SCHPH, 0x28);
+
+	/*
+	 * Reset to default values.
+	 */
+	VEC_WRITE(VEC_CLMP0_START, 0xac);
+	VEC_WRITE(VEC_CLMP0_END, 0xec);
+	VEC_WRITE(VEC_CONFIG2,
+		  VEC_CONFIG2_UV_DIG_DIS | VEC_CONFIG2_RGB_DIG_DIS);
+	VEC_WRITE(VEC_CONFIG3, VEC_CONFIG3_HORIZ_LEN_STD);
+	VEC_WRITE(VEC_DAC_CONFIG,
+		  VEC_DAC_CONFIG_DAC_CTRL(0xc) |
+		  VEC_DAC_CONFIG_DRIVER_CTRL(0xc) |
+		  VEC_DAC_CONFIG_LDO_BIAS_CTRL(0x46));
+
+	/* Mask all interrupts. */
+	VEC_WRITE(VEC_MASK0, 0);
+
+	vec->tv_mode->mode_set(vec);
+
+	VEC_WRITE(VEC_DAC_MISC,
+		  VEC_DAC_MISC_VID_ACT | VEC_DAC_MISC_DAC_RST_N);
+	VEC_WRITE(VEC_CFG, VEC_CFG_VEC_EN);
+}
+
+
+static bool vc4_vec_encoder_mode_fixup(struct drm_encoder *encoder,
+				       const struct drm_display_mode *mode,
+				       struct drm_display_mode *adjusted_mode)
+{
+	return true;
+}
+
+static void vc4_vec_encoder_atomic_mode_set(struct drm_encoder *encoder,
+					struct drm_crtc_state *crtc_state,
+					struct drm_connector_state *conn_state)
+{
+	struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder);
+	struct vc4_vec *vec = vc4_vec_encoder->vec;
+
+	vec->tv_mode = &vc4_vec_tv_modes[conn_state->tv.mode];
+}
+
+static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder,
+					struct drm_crtc_state *crtc_state,
+					struct drm_connector_state *conn_state)
+{
+	const struct vc4_vec_tv_mode *vec_mode;
+
+	vec_mode = &vc4_vec_tv_modes[conn_state->tv.mode];
+
+	if (conn_state->crtc &&
+	    !drm_mode_equal(vec_mode->mode, &crtc_state->adjusted_mode))
+		return -EINVAL;
+
+	return 0;
+}
+
+static const struct drm_encoder_helper_funcs vc4_vec_encoder_helper_funcs = {
+	.disable = vc4_vec_encoder_disable,
+	.enable = vc4_vec_encoder_enable,
+	.mode_fixup = vc4_vec_encoder_mode_fixup,
+	.atomic_check = vc4_vec_encoder_atomic_check,
+	.atomic_mode_set = vc4_vec_encoder_atomic_mode_set,
+};
+
+static const struct of_device_id vc4_vec_dt_match[] = {
+	{ .compatible = "brcm,bcm2835-vec", .data = NULL },
+	{ /* sentinel */ },
+};
+
+static const char * const tv_mode_names[] = {
+	[VC4_VEC_TV_MODE_NTSC] = "NTSC",
+	[VC4_VEC_TV_MODE_NTSC_J] = "NTSC-J",
+	[VC4_VEC_TV_MODE_PAL] = "PAL",
+	[VC4_VEC_TV_MODE_PAL_M] = "PAL-M",
+};
+
+static int vc4_vec_bind(struct device *dev, struct device *master, void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct drm_device *drm = dev_get_drvdata(master);
+	struct vc4_dev *vc4 = to_vc4_dev(drm);
+	struct vc4_vec *vec;
+	struct vc4_vec_encoder *vc4_vec_encoder;
+	int ret;
+
+	ret = drm_mode_create_tv_properties(drm, ARRAY_SIZE(tv_mode_names),
+					    tv_mode_names);
+	if (ret)
+		return ret;
+
+	vec = devm_kzalloc(dev, sizeof(*vec), GFP_KERNEL);
+	if (!vec)
+		return -ENOMEM;
+
+	vc4_vec_encoder = devm_kzalloc(dev, sizeof(*vc4_vec_encoder),
+				       GFP_KERNEL);
+	if (!vc4_vec_encoder)
+		return -ENOMEM;
+	vc4_vec_encoder->base.type = VC4_ENCODER_TYPE_VEC;
+	vc4_vec_encoder->vec = vec;
+	vec->encoder = &vc4_vec_encoder->base.base;
+
+	vec->pdev = pdev;
+	vec->regs = vc4_ioremap_regs(pdev, 0);
+	if (IS_ERR(vec->regs))
+		return PTR_ERR(vec->regs);
+
+	vec->clock = devm_clk_get(dev, NULL);
+	if (IS_ERR(vec->clock)) {
+		ret = PTR_ERR(vec->clock);
+		if (ret != -EPROBE_DEFER)
+			DRM_ERROR("Failed to get clock: %d\n", ret);
+		return ret;
+	}
+
+	pm_runtime_enable(dev);
+
+	drm_encoder_init(drm, vec->encoder, &vc4_vec_encoder_funcs,
+			 DRM_MODE_ENCODER_TVDAC, NULL);
+	drm_encoder_helper_add(vec->encoder, &vc4_vec_encoder_helper_funcs);
+
+	vec->connector = vc4_vec_connector_init(drm, vec);
+	if (IS_ERR(vec->connector)) {
+		ret = PTR_ERR(vec->connector);
+		goto err_destroy_encoder;
+	}
+
+	dev_set_drvdata(dev, vec);
+
+	vc4->vec = vec;
+
+	return 0;
+
+err_destroy_encoder:
+	drm_encoder_cleanup(vec->encoder);
+	pm_runtime_disable(dev);
+
+	return ret;
+}
+
+static void vc4_vec_unbind(struct device *dev, struct device *master,
+			   void *data)
+{
+	struct drm_device *drm = dev_get_drvdata(master);
+	struct vc4_dev *vc4 = to_vc4_dev(drm);
+	struct vc4_vec *vec = dev_get_drvdata(dev);
+
+	vc4_vec_connector_destroy(vec->connector);
+	drm_encoder_cleanup(vec->encoder);
+	pm_runtime_disable(dev);
+
+	vc4->vec = NULL;
+}
+
+static const struct component_ops vc4_vec_ops = {
+	.bind   = vc4_vec_bind,
+	.unbind = vc4_vec_unbind,
+};
+
+static int vc4_vec_dev_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &vc4_vec_ops);
+}
+
+static int vc4_vec_dev_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &vc4_vec_ops);
+	return 0;
+}
+
+struct platform_driver vc4_vec_driver = {
+	.probe = vc4_vec_dev_probe,
+	.remove = vc4_vec_dev_remove,
+	.driver = {
+		.name = "vc4_vec",
+		.of_match_table = vc4_vec_dt_match,
+	},
+};
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 3/7] drm: Add TV connector states to drm_connector_state
From: Boris Brezillon @ 2016-12-01 20:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480622970-8714-1-git-send-email-boris.brezillon@free-electrons.com>

Some generic TV connector properties are exposed in drm_mode_config, but
they are currently handled independently in each DRM encoder driver.

Extend the drm_connector_state to store TV related states, and modify the
drm_atomic_connector_{set,get}_property() helpers to fill the connector
state accordingly.

Each driver is then responsible for checking and applying the new config
in its ->atomic_mode_{check,set}() operations.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
Changes in v2
- fix copy/paste errors
- use an enum for the subconnector field
- switch all fields to unsigned int
---
 drivers/gpu/drm/drm_atomic.c | 50 ++++++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_connector.h  | 32 ++++++++++++++++++++++++++++
 2 files changed, 82 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index e6862a744210..f93395c3c181 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -989,12 +989,38 @@ int drm_atomic_connector_set_property(struct drm_connector *connector,
 		 * now?) atomic writes to DPMS property:
 		 */
 		return -EINVAL;
+	} else if (property == config->tv_select_subconnector_property) {
+		state->tv.subconnector = val;
+	} else if (property == config->tv_left_margin_property) {
+		state->tv.margins.left = val;
+	} else if (property == config->tv_right_margin_property) {
+		state->tv.margins.right = val;
+	} else if (property == config->tv_top_margin_property) {
+		state->tv.margins.top = val;
+	} else if (property == config->tv_bottom_margin_property) {
+		state->tv.margins.bottom = val;
+	} else if (property == config->tv_mode_property) {
+		state->tv.mode = val;
+	} else if (property == config->tv_brightness_property) {
+		state->tv.brightness = val;
+	} else if (property == config->tv_contrast_property) {
+		state->tv.contrast = val;
+	} else if (property == config->tv_flicker_reduction_property) {
+		state->tv.flicker_reduction = val;
+	} else if (property == config->tv_overscan_property) {
+		state->tv.overscan = val;
+	} else if (property == config->tv_saturation_property) {
+		state->tv.saturation = val;
+	} else if (property == config->tv_hue_property) {
+		state->tv.hue = val;
 	} else if (connector->funcs->atomic_set_property) {
 		return connector->funcs->atomic_set_property(connector,
 				state, property, val);
 	} else {
 		return -EINVAL;
 	}
+
+	return 0;
 }
 EXPORT_SYMBOL(drm_atomic_connector_set_property);
 
@@ -1025,6 +1051,30 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
 		*val = (state->crtc) ? state->crtc->base.id : 0;
 	} else if (property == config->dpms_property) {
 		*val = connector->dpms;
+	} else if (property == config->tv_select_subconnector_property) {
+		*val = state->tv.subconnector;
+	} else if (property == config->tv_left_margin_property) {
+		*val = state->tv.margins.left;
+	} else if (property == config->tv_right_margin_property) {
+		*val = state->tv.margins.right;
+	} else if (property == config->tv_top_margin_property) {
+		*val = state->tv.margins.top;
+	} else if (property == config->tv_bottom_margin_property) {
+		*val = state->tv.margins.bottom;
+	} else if (property == config->tv_mode_property) {
+		*val = state->tv.mode;
+	} else if (property == config->tv_brightness_property) {
+		*val = state->tv.brightness;
+	} else if (property == config->tv_contrast_property) {
+		*val = state->tv.contrast;
+	} else if (property == config->tv_flicker_reduction_property) {
+		*val = state->tv.flicker_reduction;
+	} else if (property == config->tv_overscan_property) {
+		*val = state->tv.overscan;
+	} else if (property == config->tv_saturation_property) {
+		*val = state->tv.saturation;
+	} else if (property == config->tv_hue_property) {
+		*val = state->tv.hue;
 	} else if (connector->funcs->atomic_get_property) {
 		return connector->funcs->atomic_get_property(connector,
 				state, property, val);
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index ac9d7d8e0e43..2645e8038572 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -194,10 +194,40 @@ int drm_display_info_set_bus_formats(struct drm_display_info *info,
 				     unsigned int num_formats);
 
 /**
+ * struct drm_tv_connector_state - TV connector related states
+ * @subconnector: selected subconnector
+ * @margins: left/right/top/bottom margins
+ * @mode: TV mode
+ * @brightness: brightness in percent
+ * @contrast: contrast in percent
+ * @flicker_reduction: flicker reduction in percent
+ * @overscan: overscan in percent
+ * @saturation: saturation in percent
+ * @hue: hue in percent
+ */
+struct drm_tv_connector_state {
+	enum drm_mode_subconnector subconnector;
+	struct {
+		unsigned int left;
+		unsigned int right;
+		unsigned int top;
+		unsigned int bottom;
+	} margins;
+	unsigned int mode;
+	unsigned int brightness;
+	unsigned int contrast;
+	unsigned int flicker_reduction;
+	unsigned int overscan;
+	unsigned int saturation;
+	unsigned int hue;
+};
+
+/**
  * struct drm_connector_state - mutable connector state
  * @connector: backpointer to the connector
  * @best_encoder: can be used by helpers and drivers to select the encoder
  * @state: backpointer to global drm_atomic_state
+ * @tv: TV connector state
  */
 struct drm_connector_state {
 	struct drm_connector *connector;
@@ -213,6 +243,8 @@ struct drm_connector_state {
 	struct drm_encoder *best_encoder;
 
 	struct drm_atomic_state *state;
+
+	struct drm_tv_connector_state tv;
 };
 
 /**
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 2/7] drm: Turn DRM_MODE_SUBCONNECTOR_xx definitions into an enum
From: Boris Brezillon @ 2016-12-01 20:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480622970-8714-1-git-send-email-boris.brezillon@free-electrons.com>

List of values like the DRM_MODE_SUBCONNECTOR_xx ones are better
represented with enums.

Turn the DRM_MODE_SUBCONNECTOR_xx macros into an enum.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 include/uapi/drm/drm_mode.h | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index df0e3504c349..970bfc0d7107 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -220,14 +220,16 @@ struct drm_mode_get_encoder {
 
 /* This is for connectors with multiple signal types. */
 /* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */
-#define DRM_MODE_SUBCONNECTOR_Automatic	0
-#define DRM_MODE_SUBCONNECTOR_Unknown	0
-#define DRM_MODE_SUBCONNECTOR_DVID	3
-#define DRM_MODE_SUBCONNECTOR_DVIA	4
-#define DRM_MODE_SUBCONNECTOR_Composite	5
-#define DRM_MODE_SUBCONNECTOR_SVIDEO	6
-#define DRM_MODE_SUBCONNECTOR_Component	8
-#define DRM_MODE_SUBCONNECTOR_SCART	9
+enum drm_mode_subconnector {
+	DRM_MODE_SUBCONNECTOR_Automatic = 0,
+	DRM_MODE_SUBCONNECTOR_Unknown = 0,
+	DRM_MODE_SUBCONNECTOR_DVID = 3,
+	DRM_MODE_SUBCONNECTOR_DVIA = 4,
+	DRM_MODE_SUBCONNECTOR_Composite = 5,
+	DRM_MODE_SUBCONNECTOR_SVIDEO = 6,
+	DRM_MODE_SUBCONNECTOR_Component = 8,
+	DRM_MODE_SUBCONNECTOR_SCART = 9,
+};
 
 #define DRM_MODE_CONNECTOR_Unknown	0
 #define DRM_MODE_CONNECTOR_VGA		1
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 1/7] drm/vc4: Fix ->clock_select setting for the VEC encoder
From: Boris Brezillon @ 2016-12-01 20:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480622970-8714-1-git-send-email-boris.brezillon@free-electrons.com>

PV_CONTROL_CLK_SELECT_VEC is actually 2 and not 0. Fix the definition and
rework the vc4_set_crtc_possible_masks() to cover the full range of the
PV_CONTROL_CLK_SELECT field.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/gpu/drm/vc4/vc4_crtc.c | 38 +++++++++++++++++++++++---------------
 drivers/gpu/drm/vc4/vc4_drv.h  |  1 +
 drivers/gpu/drm/vc4/vc4_regs.h |  3 ++-
 3 files changed, 26 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
index 7f08d681a74b..c317e9103f9b 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -83,8 +83,7 @@ struct vc4_crtc_data {
 	/* Which channel of the HVS this pixelvalve sources from. */
 	int hvs_channel;
 
-	enum vc4_encoder_type encoder0_type;
-	enum vc4_encoder_type encoder1_type;
+	enum vc4_encoder_type encoder_types[4];
 };
 
 #define CRTC_WRITE(offset, val) writel(val, vc4_crtc->regs + (offset))
@@ -859,20 +858,26 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
 
 static const struct vc4_crtc_data pv0_data = {
 	.hvs_channel = 0,
-	.encoder0_type = VC4_ENCODER_TYPE_DSI0,
-	.encoder1_type = VC4_ENCODER_TYPE_DPI,
+	.encoder_types = {
+		[PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI0,
+		[PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_DPI,
+	},
 };
 
 static const struct vc4_crtc_data pv1_data = {
 	.hvs_channel = 2,
-	.encoder0_type = VC4_ENCODER_TYPE_DSI1,
-	.encoder1_type = VC4_ENCODER_TYPE_SMI,
+	.encoder_types = {
+		[PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI1,
+		[PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_SMI,
+	},
 };
 
 static const struct vc4_crtc_data pv2_data = {
 	.hvs_channel = 1,
-	.encoder0_type = VC4_ENCODER_TYPE_VEC,
-	.encoder1_type = VC4_ENCODER_TYPE_HDMI,
+	.encoder_types = {
+		[PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_HDMI,
+		[PV_CONTROL_CLK_SELECT_VEC] = VC4_ENCODER_TYPE_VEC,
+	},
 };
 
 static const struct of_device_id vc4_crtc_dt_match[] = {
@@ -886,17 +891,20 @@ static void vc4_set_crtc_possible_masks(struct drm_device *drm,
 					struct drm_crtc *crtc)
 {
 	struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+	const struct vc4_crtc_data *crtc_data = vc4_crtc->data;
+	const enum vc4_encoder_type *encoder_types = crtc_data->encoder_types;
 	struct drm_encoder *encoder;
 
 	drm_for_each_encoder(encoder, drm) {
 		struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
-
-		if (vc4_encoder->type == vc4_crtc->data->encoder0_type) {
-			vc4_encoder->clock_select = 0;
-			encoder->possible_crtcs |= drm_crtc_mask(crtc);
-		} else if (vc4_encoder->type == vc4_crtc->data->encoder1_type) {
-			vc4_encoder->clock_select = 1;
-			encoder->possible_crtcs |= drm_crtc_mask(crtc);
+		int i;
+
+		for (i = 0; i < ARRAY_SIZE(crtc_data->encoder_types); i++) {
+			if (vc4_encoder->type == encoder_types[i]) {
+				vc4_encoder->clock_select = i;
+				encoder->possible_crtcs |= drm_crtc_mask(crtc);
+				break;
+			}
 		}
 	}
 }
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index 7c1e4d97486f..946d48c33668 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -194,6 +194,7 @@ to_vc4_plane(struct drm_plane *plane)
 }
 
 enum vc4_encoder_type {
+	VC4_ENCODER_TYPE_NONE,
 	VC4_ENCODER_TYPE_HDMI,
 	VC4_ENCODER_TYPE_VEC,
 	VC4_ENCODER_TYPE_DSI0,
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
index 1aa44c2db556..39f6886b2410 100644
--- a/drivers/gpu/drm/vc4/vc4_regs.h
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
@@ -177,8 +177,9 @@
 # define PV_CONTROL_WAIT_HSTART			BIT(12)
 # define PV_CONTROL_PIXEL_REP_MASK		VC4_MASK(5, 4)
 # define PV_CONTROL_PIXEL_REP_SHIFT		4
-# define PV_CONTROL_CLK_SELECT_DSI_VEC		0
+# define PV_CONTROL_CLK_SELECT_DSI		0
 # define PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI	1
+# define PV_CONTROL_CLK_SELECT_VEC		2
 # define PV_CONTROL_CLK_SELECT_MASK		VC4_MASK(3, 2)
 # define PV_CONTROL_CLK_SELECT_SHIFT		2
 # define PV_CONTROL_FIFO_CLR			BIT(1)
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 0/7] drm/vc4: VEC (SDTV) output support
From: Boris Brezillon @ 2016-12-01 20:09 UTC (permalink / raw)
  To: linux-arm-kernel

Here is the 2nd version of the VC4/VEC series.

We still miss the two clock patches mentioned by Eric in the first
version to make the encoder work no matter the setting applied by the
bootloader.

Regards,

Boris

Boris Brezillon (7):
  drm/vc4: Fix ->clock_select setting for the VEC encoder
  drm: Turn DRM_MODE_SUBCONNECTOR_xx definitions into an enum
  drm: Add TV connector states to drm_connector_state
  drm/vc4: Add support for the VEC (Video Encoder) IP
  drm/vc4: Document VEC DT binding
  ARM: bcm/dt: Add VEC node in bcm283x.dtsi
  ARM: bcm/dt: Enable the VEC IP on all RaspeberryPi boards

 .../devicetree/bindings/display/brcm,bcm-vc4.txt   |  14 +
 arch/arm/boot/dts/bcm2835-rpi.dtsi                 |   5 +
 arch/arm/boot/dts/bcm283x.dtsi                     |   8 +
 drivers/gpu/drm/drm_atomic.c                       |  50 ++
 drivers/gpu/drm/vc4/Makefile                       |   1 +
 drivers/gpu/drm/vc4/vc4_crtc.c                     |  38 +-
 drivers/gpu/drm/vc4/vc4_debugfs.c                  |   1 +
 drivers/gpu/drm/vc4/vc4_drv.c                      |   1 +
 drivers/gpu/drm/vc4/vc4_drv.h                      |   6 +
 drivers/gpu/drm/vc4/vc4_regs.h                     |   3 +-
 drivers/gpu/drm/vc4/vc4_vec.c                      | 657 +++++++++++++++++++++
 include/drm/drm_connector.h                        |  32 +
 include/uapi/drm/drm_mode.h                        |  18 +-
 13 files changed, 810 insertions(+), 24 deletions(-)
 create mode 100644 drivers/gpu/drm/vc4/vc4_vec.c

-- 
2.7.4

^ permalink raw reply

* [PATCH v3] PCI/ACPI: xgene: Add ECAM quirk for X-Gene PCIe controller
From: Duc Dang @ 2016-12-01 19:58 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <f4b949c0-f992-b0fb-5f23-f71cb1f9713e@redhat.com>

On Thu, Dec 1, 2016 at 11:17 AM, Jon Masters <jcm@redhat.com> wrote:
> On 12/01/2016 10:08 AM, Mark Salter wrote:
>> On Wed, 2016-11-30 at 15:42 -0800, Duc Dang wrote:
>
>>> +static int xgene_v1_pcie_ecam_init(struct pci_config_window *cfg)
>>> +{
>>> +    struct acpi_device *adev = to_acpi_device(cfg->parent);
>>> +    struct acpi_pci_root *root = acpi_driver_data(adev);
>>> +    struct device *dev = cfg->parent;
>>> +    struct xgene_pcie_port *port;
>>> +    struct resource *csr;
>>> +
>>> +    port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
>>> +    if (!port)
>>> +            return -ENOMEM;
>>> +
>>> +    csr = &xgene_v1_csr_res[root->segment];
>>
>> This hard-coded assumption that segment N uses controller N breaks
>> for m400 where segment 0 is using controller 3.

I think the latest firmware released from us a few months back use
segment 3 for PCIe controller 3 in MCFG table.
>
> This seems very fragile. So in addition to Bjorn's comment about not
> trusting firmware provided data for the segment offset in the CSR list,
> you will want to also determine the controller from the ACPI tree. The
> existing code walks the ACPI hierarchy and finds the CSR that way.
> Obviously, the goal is to avoid that in the latest incarnation, but you
> could still determine which controller matches a given device.

Yes, I will look into that more.

>
> Jon.
>
> --
> Computer Architect | Sent from my Fedora powered laptop
>
Regards,
Duc Dang.

^ permalink raw reply


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