* [PATCH V7 5/8] arm64/dma-mapping: Implement DMA_ATTR_PRIVILEGED
From: Robin Murphy @ 2016-12-13 19:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <005f01d25571$3f75b5f0$be6121d0$@codeaurora.org>
On 13/12/16 18:46, Sricharan wrote:
> Hi Robin,
>
> <snip..>
>
>>>>>> return prot | IOMMU_READ | IOMMU_WRITE;
>>>>>
>>>>> ...and applying against -next now also needs this hunk:
>>>>>
>>>>> @@ -639,7 +639,7 @@ dma_addr_t iommu_dma_map_resource(struct device
>>>>> *dev, phys_addr_t phys,
>>>>> size_t size, enum dma_data_direction dir, unsigned long attrs)
>>>>> {
>>>>> return __iommu_dma_map(dev, phys, size,
>>>>> - dma_direction_to_prot(dir, false) | IOMMU_MMIO);
>>>>> + dma_info_to_prot(dir, false, attrs) | IOMMU_MMIO);
>>>>> }
>>>>>
>>>>> void iommu_dma_unmap_resource(struct device *dev, dma_addr_t handle,
>>>>>
>>>>> With those two issues fixed up, I've given the series (applied to
>>>>> next-20161213) a spin on a SMMUv3/PL330 fast model and it still checks out.
>>>>>
>>>>
>>>> oops, sorry that i missed this in rebase. I can repost now with this fixed,
>>>> 'checks out' you mean something is not working correct ?
>>>
>>> No, I mean it _is_ still correct - I guess that's more of an idiom than
>>> I thought :)
>>>
>>
>> ha ok, thanks for the testing as well. I will just send a v8 with those two fixed now.
>
> Just while checking that i have not missed anything else, realized that the
> dma-mapping apis in arm as to be modified to pass the PRIVILIGED attributes
> as well. While my testing path was using the iommu_map directly i was not
> seeing this, but then i did a patch like below. I will just figure out another
> other codebase where the master uses the dma apis, test and add it in the
> V8 that i would send.
True, adding support to 32-bit as well can't hurt, and I guess it's
equally relevant to QC's GPU use-case. I haven't considered it myself
because AArch32 is immune to the specific PL330 problem which caught me
out - that subtle corner of VMSAv8 is unique to AArch64.
> From: Sricharan R <sricharan@codeaurora.org>
> Date: Tue, 13 Dec 2016 23:25:01 +0530
> Subject: [PATCH V8 6/9] arm/dma-mapping: Implement DMA_ATTR_PRIVILEGED
>
> The newly added DMA_ATTR_PRIVILEGED is useful for creating mappings that
> are only accessible to privileged DMA engines. Implementing it in dma-mapping
> for it to get used from the dma mappings apis.
>
> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
> ---
> arch/arm/mm/dma-mapping.c | 24 +++++++++++++++---------
> 1 file changed, 15 insertions(+), 9 deletions(-)
>
> diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
> index ab77100..e0d9923 100644
> --- a/arch/arm/mm/dma-mapping.c
> +++ b/arch/arm/mm/dma-mapping.c
> @@ -1394,7 +1394,8 @@ static int __iommu_free_buffer(struct device *dev, struct page **pages,
> * Create a mapping in device IO address space for specified pages
> */
> static dma_addr_t
> -__iommu_create_mapping(struct device *dev, struct page **pages, size_t size)
> +__iommu_create_mapping(struct device *dev, struct page **pages, size_t size,
> + unsigned long attrs)
> {
> struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
> unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
> @@ -1419,7 +1420,7 @@ static int __iommu_free_buffer(struct device *dev, struct page **pages,
>
> len = (j - i) << PAGE_SHIFT;
> ret = iommu_map(mapping->domain, iova, phys, len,
> - IOMMU_READ|IOMMU_WRITE);
> + __dma_info_to_prot(DMA_BIRECTIONAL, attrs));
> if (ret < 0)
> goto fail;
> iova += len;
> @@ -1476,7 +1477,8 @@ static struct page **__iommu_get_pages(void *cpu_addr, unsigned long attrs)
> }
>
> static void *__iommu_alloc_simple(struct device *dev, size_t size, gfp_t gfp,
> - dma_addr_t *handle, int coherent_flag)
> + dma_addr_t *handle, int coherent_flag,
> + unsigned long attrs)
> {
> struct page *page;
> void *addr;
> @@ -1488,7 +1490,7 @@ static void *__iommu_alloc_simple(struct device *dev, size_t size, gfp_t gfp,
> if (!addr)
> return NULL;
>
> - *handle = __iommu_create_mapping(dev, &page, size);
> + *handle = __iommu_create_mapping(dev, &page, size, attrs);
> if (*handle == DMA_ERROR_CODE)
> goto err_mapping;
>
> @@ -1522,7 +1524,8 @@ static void *__arm_iommu_alloc_attrs(struct device *dev, size_t size,
>
> if (coherent_flag == COHERENT || !gfpflags_allow_blocking(gfp))
> return __iommu_alloc_simple(dev, size, gfp, handle,
> - coherent_flag);
> + coherent_flag,
> + attrs);
Super-nit: unnecessary line break.
>
> /*
> * Following is a work-around (a.k.a. hack) to prevent pages
> @@ -1672,10 +1675,13 @@ static int arm_iommu_get_sgtable(struct device *dev, struct sg_table *sgt,
> GFP_KERNEL);
> }
>
> -static int __dma_direction_to_prot(enum dma_data_direction dir)
> +static int __dma_info_to_prot(enum dma_data_direction dir, unsigned long attrs)
> {
> int prot;
>
> + if (attrs & DMA_ATTR_PRIVILEGED)
> + prot |= IOMMU_PRIV;
> +
> switch (dir) {
> case DMA_BIDIRECTIONAL:
> prot = IOMMU_READ | IOMMU_WRITE;
> @@ -1722,7 +1728,7 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
> if (!is_coherent && (attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
> __dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir);
>
> - prot = __dma_direction_to_prot(dir);
> + prot = __dma_info_to_prot(dir, attrs);
>
> ret = iommu_map(mapping->domain, iova, phys, len, prot);
> if (ret < 0)
> @@ -1930,7 +1936,7 @@ static dma_addr_t arm_coherent_iommu_map_page(struct device *dev, struct page *p
> if (dma_addr == DMA_ERROR_CODE)
> return dma_addr;
>
> - prot = __dma_direction_to_prot(dir);
> + prot = __dma_info_to_prot(dir, attrs);
>
> ret = iommu_map(mapping->domain, dma_addr, page_to_phys(page), len, prot);
> if (ret < 0)
> @@ -2036,7 +2042,7 @@ static dma_addr_t arm_iommu_map_resource(struct device *dev,
> if (dma_addr == DMA_ERROR_CODE)
> return dma_addr;
>
> - prot = __dma_direction_to_prot(dir) | IOMMU_MMIO;
> + prot = __dma_info_to_prot(dir, attrs) | IOMMU_MMIO;
>
> ret = iommu_map(mapping->domain, dma_addr, addr, len, prot);
> if (ret < 0)
>
Looks reasonable to me. Assuming it survives testing:
Acked-by: Robin Murphy <robin.murphy@arm.com>
^ permalink raw reply
* [PATCH] Input: imx6ul_tsc - generalize the averaging property
From: Rob Herring @ 2016-12-13 19:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481440003-27168-1-git-send-email-guy.shapiro@mobi-wize.com>
On Sun, Dec 11, 2016 at 09:06:43AM +0200, Guy Shapiro wrote:
> Make the avarage-samples property a general touchscreen property
> rather than imx6ul device specific.
>
> Signed-off-by: Guy Shapiro <guy.shapiro@mobi-wize.com>
> ---
> .../bindings/input/touchscreen/imx6ul_tsc.txt | 11 ++----
> .../bindings/input/touchscreen/touchscreen.txt | 3 ++
> drivers/input/touchscreen/imx6ul_tsc.c | 46 ++++++++++++++++------
> 3 files changed, 41 insertions(+), 19 deletions(-)
You can't just switch existing bindings as that breaks compatibility
with old dtbs. The kernel driver would need to support both. Just
introduce the new common property and use it for your device.
Rob
^ permalink raw reply
* [PATCH V7 5/8] arm64/dma-mapping: Implement DMA_ATTR_PRIVILEGED
From: Sricharan @ 2016-12-13 18:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4e6ebf88-0138-afce-d752-56b66d69772f@arm.com>
Hi Robin,
<snip..>
>>>>> return prot | IOMMU_READ | IOMMU_WRITE;
>>>>
>>>> ...and applying against -next now also needs this hunk:
>>>>
>>>> @@ -639,7 +639,7 @@ dma_addr_t iommu_dma_map_resource(struct device
>>>> *dev, phys_addr_t phys,
>>>> size_t size, enum dma_data_direction dir, unsigned long attrs)
>>>> {
>>>> return __iommu_dma_map(dev, phys, size,
>>>> - dma_direction_to_prot(dir, false) | IOMMU_MMIO);
>>>> + dma_info_to_prot(dir, false, attrs) | IOMMU_MMIO);
>>>> }
>>>>
>>>> void iommu_dma_unmap_resource(struct device *dev, dma_addr_t handle,
>>>>
>>>> With those two issues fixed up, I've given the series (applied to
>>>> next-20161213) a spin on a SMMUv3/PL330 fast model and it still checks out.
>>>>
>>>
>>> oops, sorry that i missed this in rebase. I can repost now with this fixed,
>>> 'checks out' you mean something is not working correct ?
>>
>>No, I mean it _is_ still correct - I guess that's more of an idiom than
>>I thought :)
>>
>
>ha ok, thanks for the testing as well. I will just send a v8 with those two fixed now.
Just while checking that i have not missed anything else, realized that the
dma-mapping apis in arm as to be modified to pass the PRIVILIGED attributes
as well. While my testing path was using the iommu_map directly i was not
seeing this, but then i did a patch like below. I will just figure out another
other codebase where the master uses the dma apis, test and add it in the
V8 that i would send.
From: Sricharan R <sricharan@codeaurora.org>
Date: Tue, 13 Dec 2016 23:25:01 +0530
Subject: [PATCH V8 6/9] arm/dma-mapping: Implement DMA_ATTR_PRIVILEGED
The newly added DMA_ATTR_PRIVILEGED is useful for creating mappings that
are only accessible to privileged DMA engines. Implementing it in dma-mapping
for it to get used from the dma mappings apis.
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
arch/arm/mm/dma-mapping.c | 24 +++++++++++++++---------
1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index ab77100..e0d9923 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -1394,7 +1394,8 @@ static int __iommu_free_buffer(struct device *dev, struct page **pages,
* Create a mapping in device IO address space for specified pages
*/
static dma_addr_t
-__iommu_create_mapping(struct device *dev, struct page **pages, size_t size)
+__iommu_create_mapping(struct device *dev, struct page **pages, size_t size,
+ unsigned long attrs)
{
struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
@@ -1419,7 +1420,7 @@ static int __iommu_free_buffer(struct device *dev, struct page **pages,
len = (j - i) << PAGE_SHIFT;
ret = iommu_map(mapping->domain, iova, phys, len,
- IOMMU_READ|IOMMU_WRITE);
+ __dma_info_to_prot(DMA_BIRECTIONAL, attrs));
if (ret < 0)
goto fail;
iova += len;
@@ -1476,7 +1477,8 @@ static struct page **__iommu_get_pages(void *cpu_addr, unsigned long attrs)
}
static void *__iommu_alloc_simple(struct device *dev, size_t size, gfp_t gfp,
- dma_addr_t *handle, int coherent_flag)
+ dma_addr_t *handle, int coherent_flag,
+ unsigned long attrs)
{
struct page *page;
void *addr;
@@ -1488,7 +1490,7 @@ static void *__iommu_alloc_simple(struct device *dev, size_t size, gfp_t gfp,
if (!addr)
return NULL;
- *handle = __iommu_create_mapping(dev, &page, size);
+ *handle = __iommu_create_mapping(dev, &page, size, attrs);
if (*handle == DMA_ERROR_CODE)
goto err_mapping;
@@ -1522,7 +1524,8 @@ static void *__arm_iommu_alloc_attrs(struct device *dev, size_t size,
if (coherent_flag == COHERENT || !gfpflags_allow_blocking(gfp))
return __iommu_alloc_simple(dev, size, gfp, handle,
- coherent_flag);
+ coherent_flag,
+ attrs);
/*
* Following is a work-around (a.k.a. hack) to prevent pages
@@ -1672,10 +1675,13 @@ static int arm_iommu_get_sgtable(struct device *dev, struct sg_table *sgt,
GFP_KERNEL);
}
-static int __dma_direction_to_prot(enum dma_data_direction dir)
+static int __dma_info_to_prot(enum dma_data_direction dir, unsigned long attrs)
{
int prot;
+ if (attrs & DMA_ATTR_PRIVILEGED)
+ prot |= IOMMU_PRIV;
+
switch (dir) {
case DMA_BIDIRECTIONAL:
prot = IOMMU_READ | IOMMU_WRITE;
@@ -1722,7 +1728,7 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
if (!is_coherent && (attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
__dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir);
- prot = __dma_direction_to_prot(dir);
+ prot = __dma_info_to_prot(dir, attrs);
ret = iommu_map(mapping->domain, iova, phys, len, prot);
if (ret < 0)
@@ -1930,7 +1936,7 @@ static dma_addr_t arm_coherent_iommu_map_page(struct device *dev, struct page *p
if (dma_addr == DMA_ERROR_CODE)
return dma_addr;
- prot = __dma_direction_to_prot(dir);
+ prot = __dma_info_to_prot(dir, attrs);
ret = iommu_map(mapping->domain, dma_addr, page_to_phys(page), len, prot);
if (ret < 0)
@@ -2036,7 +2042,7 @@ static dma_addr_t arm_iommu_map_resource(struct device *dev,
if (dma_addr == DMA_ERROR_CODE)
return dma_addr;
- prot = __dma_direction_to_prot(dir) | IOMMU_MMIO;
+ prot = __dma_info_to_prot(dir, attrs) | IOMMU_MMIO;
ret = iommu_map(mapping->domain, dma_addr, addr, len, prot);
if (ret < 0)
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
Regards,
Sricharan
^ permalink raw reply related
* [PATCH RFC 2/2] ARM: nommu: remap exception base address to RAM
From: Afzal Mohammed @ 2016-12-13 18:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <584FC18D.2050908@arm.com>
Hi,
On Tue, Dec 13, 2016 at 09:38:21AM +0000, Vladimir Murzin wrote:
> On 11/12/16 13:12, Afzal Mohammed wrote:
> > this probably would have to be made robust so as to not cause issue on
> > other v7-A's upon trying to do !MMU (this won't affect normal MMU boot),
> > or specifically where security extensions are not enabled. Also effect
> > of hypervisor extension also need to be considered. Please let know if
> > any better ways to handle this.
> You might need to check ID_PFR1 for that.
Had been searching ARM ARM for this kind of a thing, thanks.
> > +#ifdef CONFIG_REMAP_VECTORS_TO_RAM
> > + mov r3, #CONFIG_VECTORS_BASE @ read VECTORS_BASE
> ldr r3,=CONFIG_VECTORS_BASE
>
> would be more robust. I hit this in [1]
>
> [1] https://www.spinics.net/lists/arm-kernel/msg546825.html
Russell suggested doing it in paging_init(), then probably assembly
circus can be avoided.
Regards
afzal
^ permalink raw reply
* [PATCH V8 3/3] irqchip: qcom: Add IRQ combiner driver
From: Marc Zyngier @ 2016-12-13 18:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481653317.29291.19.camel@perches.com>
On 13/12/16 18:21, Joe Perches wrote:
> On Tue, 2016-12-13 at 10:23 -0500, Agustin Vega-Frias wrote:
>> On 2016-12-07 13:16, Marc Zyngier wrote:
>>>> + }
>>>> +
>>>> + combiner->domain = irq_domain_create_linear(
>>>> + pdev->dev.fwnode, combiner->nirqs, &domain_ops, combiner);
>>>
>>> On a single line, please. Do no listen to the checkpatch police that
>>> will tell you otherwise. It really hurt my eyes to see this opening
>>> bracket and *nothing* after that.
>>
>> Will do.
>
> It seems generally preferred to have at least one argument on the
> same line as the function being called.
>
> So, here are some options:
>
> Maximally fill the lines to 80 columns with the value being set
> and function call while aligning to open parenthesis
>
> combiner->domain = irq_domain_create_linear(pdev->dev.fwnode,
> combiner->nirqs,
> &domain_ops, combiner);
I can live with something like this.
> Use a separate line for the function call:
>
> combiner->domain =
> irq_domain_create_linear(pdev->dev.fwnode, combiner->nirqs,
> &domain_ops, combiner);
But I find this one pretty horrid.
> Or just ignore the 80 column limit wherever you deem appropriate.
Which is my usual advise. I consider the 80 column rule a good way of
limiting the complexity of code (if the nesting pushes you too far on
the right of the screen, you're doing something wrong), but not for
simple statements such as this one.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply
* [PATCH V6 00/10] Add UEFI 2.6 and ACPI 6.1 updates for RAS on ARM64
From: Baicar, Tyler @ 2016-12-13 18:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <86258A5CC0A3704780874CF6004BA8A62DC9A081@lhreml502-mbs>
Hello Shiju,
Great! Thank you for testing! :)
Tyler
On 12/13/2016 4:10 AM, Shiju Jose wrote:
> Hi Tyler,
>
> We have tested V6 patch set on our platform. It worked fine.
>
> Thanks,
> Shiju
>
>> -----Original Message-----
>> From: Tyler Baicar [mailto:tbaicar at codeaurora.org]
>> Sent: 07 December 2016 21:48
>> To: christoffer.dall at linaro.org; marc.zyngier at arm.com;
>> pbonzini at redhat.com; rkrcmar at redhat.com; linux at armlinux.org.uk;
>> catalin.marinas at arm.com; will.deacon at arm.com; rjw at rjwysocki.net;
>> lenb at kernel.org; matt at codeblueprint.co.uk; robert.moore at intel.com;
>> lv.zheng at intel.com; nkaje at codeaurora.org; zjzhang at codeaurora.org;
>> mark.rutland at arm.com; james.morse at arm.com; akpm at linux-foundation.org;
>> eun.taik.lee at samsung.com; sandeepa.s.prabhu at gmail.com;
>> labbott at redhat.com; shijie.huang at arm.com; rruigrok at codeaurora.org;
>> paul.gortmaker at windriver.com; tn at semihalf.com; fu.wei at linaro.org;
>> rostedt at goodmis.org; bristot at redhat.com; linux-arm-
>> kernel at lists.infradead.org; kvmarm at lists.cs.columbia.edu;
>> kvm at vger.kernel.org; linux-kernel at vger.kernel.org; linux-
>> acpi at vger.kernel.org; linux-efi at vger.kernel.org; devel at acpica.org;
>> Suzuki.Poulose at arm.com; punit.agrawal at arm.com; astone at redhat.com;
>> harba at codeaurora.org; hanjun.guo at linaro.org; John Garry; Shiju Jose
>> Cc: Tyler Baicar
>> Subject: [PATCH V6 00/10] Add UEFI 2.6 and ACPI 6.1 updates for RAS on
>> ARM64
>>
>> When a memory error, CPU error, PCIe error, or other type of hardware
>> error that's covered by RAS occurs, firmware should populate the shared
>> GHES memory location with the proper GHES structures to notify the OS
>> of the error.
>> For example, platforms that implement firmware first handling may
>> implement separate GHES sources for corrected errors and uncorrected
>> errors. If the error is an uncorrectable error, then the firmware will
>> notify the OS immediately since the error needs to be handled ASAP. The
>> OS will then be able to take the appropriate action needed such as
>> offlining a page. If the error is a corrected error, then the firmware
>> will not interrupt the OS immediately.
>> Instead, the OS will see and report the error the next time it's GHES
>> timer expires. The kernel will first parse the GHES structures and
>> report the errors through the kernel logs and then notify the user
>> space through RAS trace events. This allows user space applications
>> such as RAS Daemon to see the errors and report them however the user
>> desires. This patchset extends the kernel functionality for RAS errors
>> based on updates in the UEFI 2.6 and ACPI 6.1 specifications.
>>
>> An example flow from firmware to user space could be:
>>
>> +---------------+
>> +-------->| |
>> | | GHES polling |--+
>> +-------------+ | source | | +---------------+ +----------
>> --+
>> | | +---------------+ | | Kernel GHES | |
>> |
>> | Firmware | +-->| CPER AER and |-->| RAS
>> trace |
>> | | +---------------+ | | EDAC drivers | | event
>> |
>> +-------------+ | | | +---------------+ +----------
>> --+
>> | | GHES sci |--+
>> +-------->| source |
>> +---------------+
>>
>> Add support for Generic Hardware Error Source (GHES) v2, which
>> introduces the capability for the OS to acknowledge the consumption of
>> the error record generated by the Reliability, Availability and
>> Serviceability (RAS) controller.
>> This eliminates potential race conditions between the OS and the RAS
>> controller.
>>
>> Add support for the timestamp field added to the Generic Error Data
>> Entry v3, allowing the OS to log the time that the error is generated
>> by the firmware, rather than the time the error is consumed. This
>> improves the correctness of event sequences when analyzing error logs.
>> The timestamp is added in ACPI 6.1, reference Table 18-343 Generic
>> Error Data Entry.
>>
>> Add support for ARMv8 Common Platform Error Record (CPER) per UEFI 2.6
>> specification. ARMv8 specific processor error information is reported
>> as part of the CPER records. This provides more detail on for
>> processor error logs. This can help describe ARMv8 cache, tlb, and bus
>> errors.
>>
>> Synchronous External Abort (SEA) represents a specific processor error
>> condition in ARM systems. A handler is added to recognize SEA errors,
>> and a notifier is added to parse and report the errors before the
>> process is killed. Refer to section N.2.1.1 in the Common Platform
>> Error Record appendix of the UEFI 2.6 specification.
>>
>> Currently the kernel ignores CPER records that are unrecognized.
>> On the other hand, UEFI spec allows for non-standard (eg. vendor
>> proprietary) error section type in CPER (Common Platform Error Record),
>> as defined in section N2.3 of UEFI version 2.5. Therefore, user is not
>> able to see hardware error data of non-standard section.
>>
>> If section Type field of Generic Error Data Entry is unrecognized,
>> prints out the raw data in dmesg buffer, and also adds a tracepoint for
>> reporting such hardware errors.
>>
>> Currently even if an error status block's severity is fatal, the kernel
>> does not honor the severity level and panic. With the firmware first
>> model, the platform could inform the OS about a fatal hardware error
>> through the non-NMI GHES notification type. The OS should panic when a
>> hardware error record is received with this severity.
>>
>> Add support to handle SEAs that occur while a KVM guest kernel is
>> running. Currently these are unsupported by the guest abort handling.
>>
>> Depends on: [PATCH v15] acpi, apei, arm64: APEI initial support for
>> aarch64.
>> https://lkml.org/lkml/2016/12/1/312
>>
>> V6: Change HEST_TYPE_GENERIC_V2 to IS_HEST_TYPE_GENERIC_V2 for
>> readability
>> Move APEI helper defines from cper.h to ghes.h
>> Add data_len decrement back into print loop
>> Change references to ARMv8 to just ARM
>> Rewrite ARM processor context info parsing
>> Check valid bit of ARM error info field before printing it
>> Add include of linux/uuid.h in ghes.c
>>
>> V5: Fix GHES goto logic for error conditions
>> Change ghes_do_read_ack to ghes_ack_error
>> Make sure data version check is >= 3
>> Use CPER helper functions in print functions
>> Make handle_guest_sea() dummy function static for arm
>> Add arm to subject line for KVM patch
>>
>> V4: Add bit offset left shift to read_ack_write value
>> Make HEST generic and generic_v2 structures a union in the ghes
>> structure
>> Move gdata v3 helper functions into ghes.h to avoid duplication
>> Reorder the timestamp print and avoid memcpy
>> Add helper functions for gdata size checking
>> Rename the SEA functions
>> Add helper function for GHES panics
>> Set fru_id to NULL UUID at variable declaration
>> Limit ARM trace event parameters to the needed structures
>> Reorder the ARM trace event variables to save space
>> Add comment for why we don't pass SEAs to the guest when it aborts
>> Move ARM trace event call into GHES driver instead of CPER
>>
>> V3: Fix unmapped address to the read_ack_register in ghes.c
>> Add helper function to get the proper payload based on generic data
>> entry
>> version
>> Move timestamp print to avoid changing function calls in cper.c
>> Remove patch "arm64: exception: handle instruction abort at current
>> EL"
>> since the el1_ia handler is already added in 4.8
>> Add EFI and ARM64 dependencies for HAVE_ACPI_APEI_SEA
>> Add a new trace event for ARM type errors
>> Add support to handle KVM guest SEAs
>>
>> V2: Add PSCI state print for the ARMv8 error type.
>> Separate timestamp year into year and century using BCD format.
>> Rebase on top of ACPICA 20160318 release and remove header file
>> changes
>> in include/acpi/actbl1.h.
>> Add panic OS with fatal error status block patch.
>> Add processing of unrecognized CPER error section patches with
>> updates
>> from previous comments. Original patches:
>> https://lkml.org/lkml/2015/9/8/646
>>
>> V1: https://lkml.org/lkml/2016/2/5/544
>>
>> Jonathan (Zhixiong) Zhang (1):
>> acpi: apei: panic OS with fatal error status block
>>
>> Tyler Baicar (9):
>> acpi: apei: read ack upon ghes record consumption
>> ras: acpi/apei: cper: generic error data entry v3 per ACPI 6.1
>> efi: parse ARM processor error
>> arm64: exception: handle Synchronous External Abort
>> acpi: apei: handle SEA notification type for ARMv8
>> efi: print unrecognized CPER section
>> ras: acpi / apei: generate trace event for unrecognized CPER section
>> trace, ras: add ARM processor error trace event
>> arm/arm64: KVM: add guest SEA support
>>
>> arch/arm/include/asm/kvm_arm.h | 1 +
>> arch/arm/include/asm/system_misc.h | 5 +
>> arch/arm/kvm/mmu.c | 18 +++-
>> arch/arm64/Kconfig | 1 +
>> arch/arm64/include/asm/kvm_arm.h | 1 +
>> arch/arm64/include/asm/system_misc.h | 15 +++
>> arch/arm64/mm/fault.c | 71 ++++++++++--
>> drivers/acpi/apei/Kconfig | 14 +++
>> drivers/acpi/apei/ghes.c | 189
>> +++++++++++++++++++++++++++++---
>> drivers/acpi/apei/hest.c | 7 +-
>> drivers/firmware/efi/cper.c | 204
>> ++++++++++++++++++++++++++++++++---
>> drivers/ras/ras.c | 2 +
>> include/acpi/ghes.h | 27 ++++-
>> include/linux/cper.h | 53 +++++++++
>> include/ras/ras_event.h | 100 +++++++++++++++++
>> 15 files changed, 664 insertions(+), 44 deletions(-)
>>
>> --
>> Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm
>> Technologies, Inc.
>> Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a
>> Linux Foundation Collaborative Project.
--
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project.
^ permalink raw reply
* [PATCH RFC 2/2] ARM: nommu: remap exception base address to RAM
From: Afzal Mohammed @ 2016-12-13 18:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161213100226.GW14217@n2100.armlinux.org.uk>
Hi,
On Tue, Dec 13, 2016 at 10:02:26AM +0000, Russell King - ARM Linux wrote:
> On Sun, Dec 11, 2016 at 06:42:55PM +0530, Afzal Mohammed wrote:
> > bic r0, r0, #CR_V
> > #endif
> > mcr p15, 0, r0, c1, c0, 0 @ write control reg
> > +
> > +#ifdef CONFIG_REMAP_VECTORS_TO_RAM
> > + mov r3, #CONFIG_VECTORS_BASE @ read VECTORS_BASE
> > + mcr p15, 0, r3, c12, c0, 0 @ write to VBAR
> > +#endif
> > +
> Is there really any need to do this in head.S ?
Seeing the high vector configuration done here, pounced upon it :)
> I believe it's
> entirely possible to do it later - arch/arm/mm/nommu.c:paging_init().
>
> Also, if the region setup for the vectors was moved as well, it would
> then be possible to check the ID registers to determine whether this
> is supported, and make the decision where to locate the vectors base
> more dynamically.
i will look into it.
Regards
afzal
^ permalink raw reply
* [RFC v2 PATCH 0/3] Fix dma_alloc_coherent() and friends for NOMMU
From: Robin Murphy @ 2016-12-13 18:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <58500D86.4070600@arm.com>
On 13/12/16 15:02, Vladimir Murzin wrote:
> On 13/12/16 14:25, Robin Murphy wrote:
>> On 13/12/16 14:14, Vladimir Murzin wrote:
>>> On 13/12/16 14:07, Russell King - ARM Linux wrote:
>>>> On Tue, Dec 13, 2016 at 01:45:01PM +0000, Vladimir Murzin wrote:
>>>>> This patch set is trying to address the issue by providing region of
>>>>> memory suitable for consistent DMA operations. It is supposed that such
>>>>> region is marked by MPU as non-cacheable. Since we have MPU support in
>>>>> Linux for R-class only and M-class setting MPU in bootloader, proposed
>>>>> interface to advertise such memory is via "memdma=size at start" command
>>>>> line option, to avoid clashing with normal memory (which usually comes
>>>>> from dts) it'd be safer to use it together with "mem=" command line
>>>>> option. Meanwhile, I'm open to suggestions for the better way telling
>>>>> Linux of such memory.
>>>>
>>>> For those nommu systems where the MPU is not used, how do they allocate
>>>> DMA memory without setting aside a chunk of memory?
>>>>
>>>> >From what I understand of the current nommu code, it would just use
>>>> the normal page allocator for DMA memory allocation, so now requiring
>>>> everything to fit the "nommu has mpu" case seems like it's going to
>>>> break older nommu.
>>>>
>>>
>>> Probably, it'd be better if we just fallback to dma-noop operations if there
>>> is no dma region, i.e. assume that platform is coherent. We still need a way
>>> to tell user that absence of such region can be reason of broken DMA.
>>
>> As I mentioned internally, I think it would be worth trying to use CMA
>> for this, because dma_map_ops are already wired to try that first, and
>> from what I can see it seems already set up to do precisely this via a
>> "shared-dma-pool" reserved memory region (see rmem_cma_setup() in
>> drivers/base/dma-contiguous.c) - mandating that for cached v7-M systems
>> whilst letting cache-less/non-MPU systems automatically fall back to the
>> normal page allocator in its absence would seem to solve all 3 cases.
>
> Unfortunately,
>
> config DMA_CMA
> bool "DMA Contiguous Memory Allocator"
> depends on HAVE_DMA_CONTIGUOUS && CMA
> help
> ...
> config CMA
> bool "Contiguous Memory Allocator"
> depends on HAVE_MEMBLOCK && MMU
> select MIGRATION
>
> and it blows up if I remove dependecy on MMU :(
Ah yes, fair enough.
> Another option would be drivers/base/dma-coherent.c, but, IIUC, in this case
> memory is reserved per device exclusively, so I'm in doubt if tiny M-class can
> afford that...
I think as usual I managed to conflate the two - it was actually
dma_alloc_from_coherent() I had in mind when I mentioned dma_map_ops. It
does seem from 7bfa5ab6fa1b that dma-coherent *can* handle multiple
devices per region, so it wouldn't appear to be too hard to implement a
default coherent region (possibly specific to ARM_MPU) for all devices
in a similar manner to the default contiguous region. Either way I do
still think a reserved memory region in the DT is nicer and probably
more robust than the command line parameter.
Robin.
>> Other than the allocator issue, though, the rest of the refactoring does
>> look nice.
>
> Thanks for going through it!
>
> Cheers
> Vladimir
^ permalink raw reply
* [PATCH V8 3/3] irqchip: qcom: Add IRQ combiner driver
From: Joe Perches @ 2016-12-13 18:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <78bfd90d47200347628f7dd98451122f@codeaurora.org>
On Tue, 2016-12-13 at 10:23 -0500, Agustin Vega-Frias wrote:
> On 2016-12-07 13:16, Marc Zyngier wrote:
> > > + }
> > > +
> > > + combiner->domain = irq_domain_create_linear(
> > > + pdev->dev.fwnode, combiner->nirqs, &domain_ops, combiner);
> >
> > On a single line, please. Do no listen to the checkpatch police that
> > will tell you otherwise. It really hurt my eyes to see this opening
> > bracket and *nothing* after that.
>
> Will do.
It seems generally preferred to have at least one argument on the
same line as the function being called.
So, here are some options:
Maximally fill the lines to 80 columns with the value being set
and function call while aligning to open parenthesis
combiner->domain = irq_domain_create_linear(pdev->dev.fwnode,
combiner->nirqs,
&domain_ops, combiner);
Use a separate line for the function call:
combiner->domain =
irq_domain_create_linear(pdev->dev.fwnode, combiner->nirqs,
&domain_ops, combiner);
Or just ignore the 80 column limit wherever you deem appropriate.
No single style is universal, use what you think best.
Anyway, long identifiers (24 chars here) make staying within the
"strongly preferred" 80 column limit produce quite silly looking
code.
^ permalink raw reply
* [PATCH 7/7] ARM: dts: NSP: Add SD/MMC support
From: Jon Mason @ 2016-12-13 18:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481652831-2744-1-git-send-email-jon.mason@broadcom.com>
Add SD/MMC support to the Broadcom NSP SVK and XMC.
Signed-off-by: Jon Mason <jon.mason@broadcom.com>
---
arch/arm/boot/dts/bcm-nsp.dtsi | 9 +++
arch/arm/boot/dts/bcm958525xmc.dts | 6 +-
arch/arm/boot/dts/bcm958625k.dts | 118 ++++++++++++++++++++++++-------------
3 files changed, 90 insertions(+), 43 deletions(-)
diff --git a/arch/arm/boot/dts/bcm-nsp.dtsi b/arch/arm/boot/dts/bcm-nsp.dtsi
index ecffc16..6c58c78 100644
--- a/arch/arm/boot/dts/bcm-nsp.dtsi
+++ b/arch/arm/boot/dts/bcm-nsp.dtsi
@@ -209,6 +209,15 @@
#dma-cells = <1>;
};
+ sdio: sdhci at 21000 {
+ compatible = "brcm,sdhci-iproc-cygnus";
+ reg = <0x21000 0x100>;
+ interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
+ sdhci,auto-cmd12;
+ clocks = <&lcpll0 BCM_NSP_LCPLL0_SDIO_CLK>;
+ status = "disabled";
+ };
+
amac0: ethernet at 22000 {
compatible = "brcm,nsp-amac";
reg = <0x022000 0x1000>,
diff --git a/arch/arm/boot/dts/bcm958525xmc.dts b/arch/arm/boot/dts/bcm958525xmc.dts
index 3912269..41e7fd3 100644
--- a/arch/arm/boot/dts/bcm958525xmc.dts
+++ b/arch/arm/boot/dts/bcm958525xmc.dts
@@ -59,7 +59,7 @@
};
};
-/* XHCI and SD/MMC support needed to be complete */
+/* XHCI support needed to be complete */
&amac0 {
status = "okay";
@@ -184,6 +184,10 @@
status = "okay";
};
+&sdio {
+ status = "ok";
+};
+
&uart0 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/bcm958625k.dts b/arch/arm/boot/dts/bcm958625k.dts
index 6e994f2..f8d47e5 100644
--- a/arch/arm/boot/dts/bcm958625k.dts
+++ b/arch/arm/boot/dts/bcm958625k.dts
@@ -117,58 +117,34 @@
&pinctrl {
pinctrl-names = "default";
- pinctrl-0 = <&nand_sel>;
+ pinctrl-0 = <&nand_sel>, <&gpiobs>, <&pwmc>;
+
nand_sel: nand_sel {
function = "nand";
groups = "nand_grp";
};
-};
-
-&srab {
- compatible = "brcm,bcm58625-srab", "brcm,nsp-srab";
- status = "okay";
-
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
-
- port at 0 {
- label = "port0";
- reg = <0>;
- };
-
- port at 1 {
- label = "port1";
- reg = <1>;
- };
-
- port at 2 {
- label = "port2";
- reg = <2>;
- };
- port at 3 {
- label = "port3";
- reg = <3>;
- };
+ gpiobs: gpiobs {
+ function = "gpio_b";
+ groups = "gpio_b_0_grp", "gpio_b_1_grp", "gpio_b_2_grp",
+ "gpio_b_3_grp";
+ };
- port at 4 {
- label = "port4";
- reg = <4>;
- };
+ pwmc: pwmc {
+ function = "pwm";
+ groups = "pwm0_grp", "pwm1_grp", "pwm2_grp", "pwm3_grp";
+ };
- port at 5 {
- ethernet = <&amac0>;
- label = "cpu";
- reg = <5>;
- fixed-link {
- speed = <1000>;
- full-duplex;
- };
- };
+ emmc_sel: emmc_sel {
+ function = "emmc";
+ groups = "emmc_grp";
};
};
+&pwm {
+ status = "okay";
+};
+
&qspi {
bspi-sel = <0>;
flash: m25p80 at 0 {
@@ -215,6 +191,64 @@
status = "okay";
};
+/*
+ * By default the sd slot is functional. For emmc to work add "<&emmc_sel>"
+ * and delete "<&nand_sel>" in "pinctrl-0" property of pinctrl node. Remove the
+ * bus-width property here and disable the nand node with status = "disabled";.
+ *
+ * Ex: pinctrl-0 = <&emmc_sel>, <&gpiobs>, <&pwmc>;
+ */
+&sdio {
+ bus-width = <4>;
+ no-1-8-v;
+ status = "ok";
+};
+
+&srab {
+ compatible = "brcm,bcm58625-srab", "brcm,nsp-srab";
+ status = "okay";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port at 0 {
+ label = "port0";
+ reg = <0>;
+ };
+
+ port at 1 {
+ label = "port1";
+ reg = <1>;
+ };
+
+ port at 2 {
+ label = "port2";
+ reg = <2>;
+ };
+
+ port at 3 {
+ label = "port3";
+ reg = <3>;
+ };
+
+ port at 4 {
+ label = "port4";
+ reg = <4>;
+ };
+
+ port at 5 {
+ ethernet = <&amac0>;
+ label = "cpu";
+ reg = <5>;
+ fixed-link {
+ speed = <1000>;
+ full-duplex;
+ };
+ };
+ };
+};
+
&uart0 {
status = "okay";
};
--
2.7.4
^ permalink raw reply related
* [PATCH 6/7] ARM: dts: NSP: Add Ethernet to NSP XMC
From: Jon Mason @ 2016-12-13 18:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481652831-2744-1-git-send-email-jon.mason@broadcom.com>
Enable the ethernet in the NSP XMC (bcm958525xmc) device tree
Signed-off-by: Jon Mason <jon.mason@broadcom.com>
---
arch/arm/boot/dts/bcm958525xmc.dts | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/bcm958525xmc.dts b/arch/arm/boot/dts/bcm958525xmc.dts
index 89d9abc..3912269 100644
--- a/arch/arm/boot/dts/bcm958525xmc.dts
+++ b/arch/arm/boot/dts/bcm958525xmc.dts
@@ -59,7 +59,11 @@
};
};
-/* XHCI, MMC, and Ethernet support needed to be complete */
+/* XHCI and SD/MMC support needed to be complete */
+
+&amac0 {
+ status = "okay";
+};
&i2c0 {
temperature-sensor at 4c {
--
2.7.4
^ permalink raw reply related
* [PATCH 5/7] ARM: dts: NSP: Add and enable amac2
From: Jon Mason @ 2016-12-13 18:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481652831-2744-1-git-send-email-jon.mason@broadcom.com>
Add and enable the third AMAC ethernet interface in the device trees for
the platforms where it is present. Also, enable amac1 on some of the
platforms where that was missing.
Signed-off-by: Jon Mason <jon.mason@broadcom.com>
---
arch/arm/boot/dts/bcm-nsp.dtsi | 9 +++++++++
arch/arm/boot/dts/bcm958622hr.dts | 8 ++++++++
arch/arm/boot/dts/bcm958623hr.dts | 8 ++++++++
arch/arm/boot/dts/bcm958625hr.dts | 8 ++++++++
arch/arm/boot/dts/bcm958625k.dts | 4 ++++
arch/arm/boot/dts/bcm988312hr.dts | 8 ++++++++
6 files changed, 45 insertions(+)
diff --git a/arch/arm/boot/dts/bcm-nsp.dtsi b/arch/arm/boot/dts/bcm-nsp.dtsi
index 9cd77ab..ecffc16 100644
--- a/arch/arm/boot/dts/bcm-nsp.dtsi
+++ b/arch/arm/boot/dts/bcm-nsp.dtsi
@@ -227,6 +227,15 @@
status = "disabled";
};
+ amac2: ethernet at 24000 {
+ compatible = "brcm,nsp-amac";
+ reg = <0x024000 0x1000>,
+ <0x112000 0x1000>;
+ reg-names = "amac_base", "idm_base";
+ interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
nand: nand at 26000 {
compatible = "brcm,nand-iproc", "brcm,brcmnand-v6.1";
reg = <0x026000 0x600>,
diff --git a/arch/arm/boot/dts/bcm958622hr.dts b/arch/arm/boot/dts/bcm958622hr.dts
index 18b8ffb..477c486 100644
--- a/arch/arm/boot/dts/bcm958622hr.dts
+++ b/arch/arm/boot/dts/bcm958622hr.dts
@@ -65,6 +65,14 @@
status = "okay";
};
+&amac1 {
+ status = "okay";
+};
+
+&amac2 {
+ status = "okay";
+};
+
&nand {
nandcs at 0 {
compatible = "brcm,nandcs";
diff --git a/arch/arm/boot/dts/bcm958623hr.dts b/arch/arm/boot/dts/bcm958623hr.dts
index 61499ae..c0a499d 100644
--- a/arch/arm/boot/dts/bcm958623hr.dts
+++ b/arch/arm/boot/dts/bcm958623hr.dts
@@ -65,6 +65,14 @@
status = "okay";
};
+&amac1 {
+ status = "okay";
+};
+
+&amac2 {
+ status = "okay";
+};
+
&nand {
nandcs at 0 {
compatible = "brcm,nandcs";
diff --git a/arch/arm/boot/dts/bcm958625hr.dts b/arch/arm/boot/dts/bcm958625hr.dts
index 94cce23..f7eb585 100644
--- a/arch/arm/boot/dts/bcm958625hr.dts
+++ b/arch/arm/boot/dts/bcm958625hr.dts
@@ -63,6 +63,14 @@
status = "okay";
};
+&amac1 {
+ status = "okay";
+};
+
+&amac2 {
+ status = "okay";
+};
+
&nand {
nandcs at 0 {
compatible = "brcm,nandcs";
diff --git a/arch/arm/boot/dts/bcm958625k.dts b/arch/arm/boot/dts/bcm958625k.dts
index 7aa86c7..6e994f2 100644
--- a/arch/arm/boot/dts/bcm958625k.dts
+++ b/arch/arm/boot/dts/bcm958625k.dts
@@ -61,6 +61,10 @@
status = "okay";
};
+&amac2 {
+ status = "okay";
+};
+
&nand {
nandcs at 0 {
compatible = "brcm,nandcs";
diff --git a/arch/arm/boot/dts/bcm988312hr.dts b/arch/arm/boot/dts/bcm988312hr.dts
index c324c9f..16666324 100644
--- a/arch/arm/boot/dts/bcm988312hr.dts
+++ b/arch/arm/boot/dts/bcm988312hr.dts
@@ -65,6 +65,14 @@
status = "okay";
};
+&amac1 {
+ status = "okay";
+};
+
+&amac2 {
+ status = "okay";
+};
+
&nand {
nandcs at 0 {
compatible = "brcm,nandcs";
--
2.7.4
^ permalink raw reply related
* [PATCH 4/7] ARM: dts: NSP: Add BCM958625K switch ports
From: Jon Mason @ 2016-12-13 18:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481652831-2744-1-git-send-email-jon.mason@broadcom.com>
Add the layout of the switch ports found on the BCM958625K reference
board. The CPU port is hooked up to the AMAC0 Ethernet controller
adapter.
Signed-off-by: Jon Mason <jon.mason@broadcom.com>
---
arch/arm/boot/dts/bcm958625k.dts | 45 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/arch/arm/boot/dts/bcm958625k.dts b/arch/arm/boot/dts/bcm958625k.dts
index dc24056..7aa86c7 100644
--- a/arch/arm/boot/dts/bcm958625k.dts
+++ b/arch/arm/boot/dts/bcm958625k.dts
@@ -120,6 +120,51 @@
};
};
+&srab {
+ compatible = "brcm,bcm58625-srab", "brcm,nsp-srab";
+ status = "okay";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port at 0 {
+ label = "port0";
+ reg = <0>;
+ };
+
+ port at 1 {
+ label = "port1";
+ reg = <1>;
+ };
+
+ port at 2 {
+ label = "port2";
+ reg = <2>;
+ };
+
+ port at 3 {
+ label = "port3";
+ reg = <3>;
+ };
+
+ port at 4 {
+ label = "port4";
+ reg = <4>;
+ };
+
+ port at 5 {
+ ethernet = <&amac0>;
+ label = "cpu";
+ reg = <5>;
+ fixed-link {
+ speed = <1000>;
+ full-duplex;
+ };
+ };
+ };
+};
+
&qspi {
bspi-sel = <0>;
flash: m25p80 at 0 {
--
2.7.4
^ permalink raw reply related
* [PATCH 3/7] ARM: dts: NSP: Add QSPI support to missing boards
From: Jon Mason @ 2016-12-13 18:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481652831-2744-1-git-send-email-jon.mason@broadcom.com>
QSPI device tree entries are present in bcm958625k, but missing from
bcm958522er, bcm958525er, bcm958525xmc, bcm958622hr, bcm958623hr,
bcm958625hr, and bcm988312hr. Duplicate the entry in bcm958625k for
all of those that are missing it (as they are identical).
Signed-off-by: Jon Mason <jon.mason@broadcom.com>
---
arch/arm/boot/dts/bcm958522er.dts | 34 ++++++++++++++++++++++++++++++++++
arch/arm/boot/dts/bcm958525er.dts | 34 ++++++++++++++++++++++++++++++++++
arch/arm/boot/dts/bcm958525xmc.dts | 34 ++++++++++++++++++++++++++++++++++
arch/arm/boot/dts/bcm958622hr.dts | 34 ++++++++++++++++++++++++++++++++++
arch/arm/boot/dts/bcm958623hr.dts | 34 ++++++++++++++++++++++++++++++++++
arch/arm/boot/dts/bcm958625hr.dts | 34 ++++++++++++++++++++++++++++++++++
arch/arm/boot/dts/bcm988312hr.dts | 34 ++++++++++++++++++++++++++++++++++
7 files changed, 238 insertions(+)
diff --git a/arch/arm/boot/dts/bcm958522er.dts b/arch/arm/boot/dts/bcm958522er.dts
index 7afd845..3f04a40 100644
--- a/arch/arm/boot/dts/bcm958522er.dts
+++ b/arch/arm/boot/dts/bcm958522er.dts
@@ -124,6 +124,40 @@
};
};
+&qspi {
+ bspi-sel = <0>;
+ flash: m25p80 at 0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "m25p80";
+ reg = <0x0>;
+ spi-max-frequency = <12500000>;
+ m25p,fast-read;
+ spi-cpol;
+ spi-cpha;
+
+ partition at 0 {
+ label = "boot";
+ reg = <0x00000000 0x000a0000>;
+ };
+
+ partition at a0000 {
+ label = "env";
+ reg = <0x000a0000 0x00060000>;
+ };
+
+ partition at 100000 {
+ label = "system";
+ reg = <0x00100000 0x00600000>;
+ };
+
+ partition at 700000 {
+ label = "rootfs";
+ reg = <0x00700000 0x01900000>;
+ };
+ };
+};
+
&uart0 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/bcm958525er.dts b/arch/arm/boot/dts/bcm958525er.dts
index 9da18cd..9fd5422 100644
--- a/arch/arm/boot/dts/bcm958525er.dts
+++ b/arch/arm/boot/dts/bcm958525er.dts
@@ -124,6 +124,40 @@
};
};
+&qspi {
+ bspi-sel = <0>;
+ flash: m25p80 at 0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "m25p80";
+ reg = <0x0>;
+ spi-max-frequency = <12500000>;
+ m25p,fast-read;
+ spi-cpol;
+ spi-cpha;
+
+ partition at 0 {
+ label = "boot";
+ reg = <0x00000000 0x000a0000>;
+ };
+
+ partition at a0000 {
+ label = "env";
+ reg = <0x000a0000 0x00060000>;
+ };
+
+ partition at 100000 {
+ label = "system";
+ reg = <0x00100000 0x00600000>;
+ };
+
+ partition at 700000 {
+ label = "rootfs";
+ reg = <0x00700000 0x01900000>;
+ };
+ };
+};
+
&sata_phy0 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/bcm958525xmc.dts b/arch/arm/boot/dts/bcm958525xmc.dts
index 4492f55..89d9abc 100644
--- a/arch/arm/boot/dts/bcm958525xmc.dts
+++ b/arch/arm/boot/dts/bcm958525xmc.dts
@@ -134,6 +134,40 @@
};
};
+&qspi {
+ bspi-sel = <0>;
+ flash: m25p80 at 0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "m25p80";
+ reg = <0x0>;
+ spi-max-frequency = <12500000>;
+ m25p,fast-read;
+ spi-cpol;
+ spi-cpha;
+
+ partition at 0 {
+ label = "boot";
+ reg = <0x00000000 0x000a0000>;
+ };
+
+ partition at a0000 {
+ label = "env";
+ reg = <0x000a0000 0x00060000>;
+ };
+
+ partition at 100000 {
+ label = "system";
+ reg = <0x00100000 0x00600000>;
+ };
+
+ partition at 700000 {
+ label = "rootfs";
+ reg = <0x00700000 0x01900000>;
+ };
+ };
+};
+
&sata_phy0 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/bcm958622hr.dts b/arch/arm/boot/dts/bcm958622hr.dts
index ad2aa87..18b8ffb 100644
--- a/arch/arm/boot/dts/bcm958622hr.dts
+++ b/arch/arm/boot/dts/bcm958622hr.dts
@@ -120,6 +120,40 @@
};
};
+&qspi {
+ bspi-sel = <0>;
+ flash: m25p80 at 0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "m25p80";
+ reg = <0x0>;
+ spi-max-frequency = <12500000>;
+ m25p,fast-read;
+ spi-cpol;
+ spi-cpha;
+
+ partition at 0 {
+ label = "boot";
+ reg = <0x00000000 0x000a0000>;
+ };
+
+ partition at a0000 {
+ label = "env";
+ reg = <0x000a0000 0x00060000>;
+ };
+
+ partition at 100000 {
+ label = "system";
+ reg = <0x00100000 0x00600000>;
+ };
+
+ partition at 700000 {
+ label = "rootfs";
+ reg = <0x00700000 0x01900000>;
+ };
+ };
+};
+
&srab {
compatible = "brcm,bcm58622-srab", "brcm,nsp-srab";
status = "okay";
diff --git a/arch/arm/boot/dts/bcm958623hr.dts b/arch/arm/boot/dts/bcm958623hr.dts
index 32ea59a..61499ae 100644
--- a/arch/arm/boot/dts/bcm958623hr.dts
+++ b/arch/arm/boot/dts/bcm958623hr.dts
@@ -128,6 +128,40 @@
status = "okay";
};
+&qspi {
+ bspi-sel = <0>;
+ flash: m25p80 at 0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "m25p80";
+ reg = <0x0>;
+ spi-max-frequency = <12500000>;
+ m25p,fast-read;
+ spi-cpol;
+ spi-cpha;
+
+ partition at 0 {
+ label = "boot";
+ reg = <0x00000000 0x000a0000>;
+ };
+
+ partition at a0000 {
+ label = "env";
+ reg = <0x000a0000 0x00060000>;
+ };
+
+ partition at 100000 {
+ label = "system";
+ reg = <0x00100000 0x00600000>;
+ };
+
+ partition at 700000 {
+ label = "rootfs";
+ reg = <0x00700000 0x01900000>;
+ };
+ };
+};
+
&srab {
compatible = "brcm,bcm58623-srab", "brcm,nsp-srab";
status = "okay";
diff --git a/arch/arm/boot/dts/bcm958625hr.dts b/arch/arm/boot/dts/bcm958625hr.dts
index e7a4cb1..94cce23 100644
--- a/arch/arm/boot/dts/bcm958625hr.dts
+++ b/arch/arm/boot/dts/bcm958625hr.dts
@@ -118,6 +118,40 @@
};
};
+&qspi {
+ bspi-sel = <0>;
+ flash: m25p80 at 0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "m25p80";
+ reg = <0x0>;
+ spi-max-frequency = <12500000>;
+ m25p,fast-read;
+ spi-cpol;
+ spi-cpha;
+
+ partition at 0 {
+ label = "boot";
+ reg = <0x00000000 0x000a0000>;
+ };
+
+ partition at a0000 {
+ label = "env";
+ reg = <0x000a0000 0x00060000>;
+ };
+
+ partition at 100000 {
+ label = "system";
+ reg = <0x00100000 0x00600000>;
+ };
+
+ partition at 700000 {
+ label = "rootfs";
+ reg = <0x00700000 0x01900000>;
+ };
+ };
+};
+
&sata_phy0 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/bcm988312hr.dts b/arch/arm/boot/dts/bcm988312hr.dts
index 104afe9..c324c9f 100644
--- a/arch/arm/boot/dts/bcm988312hr.dts
+++ b/arch/arm/boot/dts/bcm988312hr.dts
@@ -120,6 +120,40 @@
};
};
+&qspi {
+ bspi-sel = <0>;
+ flash: m25p80 at 0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "m25p80";
+ reg = <0x0>;
+ spi-max-frequency = <12500000>;
+ m25p,fast-read;
+ spi-cpol;
+ spi-cpha;
+
+ partition at 0 {
+ label = "boot";
+ reg = <0x00000000 0x000a0000>;
+ };
+
+ partition at a0000 {
+ label = "env";
+ reg = <0x000a0000 0x00060000>;
+ };
+
+ partition at 100000 {
+ label = "system";
+ reg = <0x00100000 0x00600000>;
+ };
+
+ partition at 700000 {
+ label = "rootfs";
+ reg = <0x00700000 0x01900000>;
+ };
+ };
+};
+
&sata_phy0 {
status = "okay";
};
--
2.7.4
^ permalink raw reply related
* [PATCH 2/7] ARM: dts: NSP: Correct NAND partition unit address
From: Jon Mason @ 2016-12-13 18:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481652831-2744-1-git-send-email-jon.mason@broadcom.com>
The NAND partition unit address does not match the other NSP device tree
files. This change makes them uniform.
Signed-off-by: Jon Mason <jon.mason@broadcom.com>
---
arch/arm/boot/dts/bcm958625k.dts | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/arch/arm/boot/dts/bcm958625k.dts b/arch/arm/boot/dts/bcm958625k.dts
index 98337d6..dc24056 100644
--- a/arch/arm/boot/dts/bcm958625k.dts
+++ b/arch/arm/boot/dts/bcm958625k.dts
@@ -80,19 +80,19 @@
reg = <0x00000000 0x00200000>;
read-only;
};
- partition at 1 {
+ partition at 200000 {
label = "nenv";
reg = <0x00200000 0x00400000>;
};
- partition at 2 {
+ partition at 600000 {
label = "nsystem";
reg = <0x00600000 0x00a00000>;
};
- partition at 3 {
+ partition at 1000000 {
label = "nrootfs";
reg = <0x01000000 0x03000000>;
};
- partition at 4 {
+ partition at 4000000 {
label = "ncustfs";
reg = <0x04000000 0x3c000000>;
};
--
2.7.4
^ permalink raw reply related
* [PATCH 1/7] ARM: dts: NSP: DT Clean-ups
From: Jon Mason @ 2016-12-13 18:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481652831-2744-1-git-send-email-jon.mason@broadcom.com>
The QSPI entry was added out of the sequental order that the rest of the
DTSI file is in. Move it to make it fit in properly. Also, some other
entries have been added in a non-alphabetical order in the DTS files,
making them different from the other NSP DTS files. Move the relevant
peices to make it match. Finally, remove errant new lines.
Signed-off-by: Jon Mason <jon.mason@broadcom.com>
---
arch/arm/boot/dts/bcm-nsp.dtsi | 46 +++++++++++++--------------
arch/arm/boot/dts/bcm958522er.dts | 1 -
arch/arm/boot/dts/bcm958525er.dts | 1 -
arch/arm/boot/dts/bcm958525xmc.dts | 26 ++++++++--------
arch/arm/boot/dts/bcm958623hr.dts | 16 +++++-----
arch/arm/boot/dts/bcm958625hr.dts | 30 +++++++++---------
arch/arm/boot/dts/bcm958625k.dts | 64 +++++++++++++++++++-------------------
7 files changed, 91 insertions(+), 93 deletions(-)
diff --git a/arch/arm/boot/dts/bcm-nsp.dtsi b/arch/arm/boot/dts/bcm-nsp.dtsi
index b6142bd..9cd77ab 100644
--- a/arch/arm/boot/dts/bcm-nsp.dtsi
+++ b/arch/arm/boot/dts/bcm-nsp.dtsi
@@ -241,29 +241,6 @@
brcm,nand-has-wp;
};
- gpiob: gpio at 30000 {
- compatible = "brcm,iproc-nsp-gpio", "brcm,iproc-gpio";
- reg = <0x30000 0x50>;
- #gpio-cells = <2>;
- gpio-controller;
- ngpios = <4>;
- interrupt-controller;
- interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
- };
-
- pwm: pwm at 31000 {
- compatible = "brcm,iproc-pwm";
- reg = <0x31000 0x28>;
- clocks = <&osc>;
- #pwm-cells = <3>;
- status = "disabled";
- };
-
- rng: rng at 33000 {
- compatible = "brcm,bcm-nsp-rng";
- reg = <0x33000 0x14>;
- };
-
qspi: qspi at 27200 {
compatible = "brcm,spi-bcm-qspi", "brcm,spi-nsp-qspi";
reg = <0x027200 0x184>,
@@ -293,6 +270,29 @@
#size-cells = <0>;
};
+ gpiob: gpio at 30000 {
+ compatible = "brcm,iproc-nsp-gpio", "brcm,iproc-gpio";
+ reg = <0x30000 0x50>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ ngpios = <4>;
+ interrupt-controller;
+ interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ pwm: pwm at 31000 {
+ compatible = "brcm,iproc-pwm";
+ reg = <0x31000 0x28>;
+ clocks = <&osc>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
+ rng: rng at 33000 {
+ compatible = "brcm,bcm-nsp-rng";
+ reg = <0x33000 0x14>;
+ };
+
ccbtimer0: timer at 34000 {
compatible = "arm,sp804";
reg = <0x34000 0x1000>;
diff --git a/arch/arm/boot/dts/bcm958522er.dts b/arch/arm/boot/dts/bcm958522er.dts
index a21b0fd..7afd845 100644
--- a/arch/arm/boot/dts/bcm958522er.dts
+++ b/arch/arm/boot/dts/bcm958522er.dts
@@ -65,7 +65,6 @@
status = "okay";
};
-
&amac1 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/bcm958525er.dts b/arch/arm/boot/dts/bcm958525er.dts
index be7f2f8..9da18cd 100644
--- a/arch/arm/boot/dts/bcm958525er.dts
+++ b/arch/arm/boot/dts/bcm958525er.dts
@@ -65,7 +65,6 @@
status = "okay";
};
-
&amac1 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/bcm958525xmc.dts b/arch/arm/boot/dts/bcm958525xmc.dts
index 959cde9..4492f55 100644
--- a/arch/arm/boot/dts/bcm958525xmc.dts
+++ b/arch/arm/boot/dts/bcm958525xmc.dts
@@ -59,6 +59,8 @@
};
};
+/* XHCI, MMC, and Ethernet support needed to be complete */
+
&i2c0 {
temperature-sensor at 4c {
compatible = "adi,adt7461a";
@@ -115,12 +117,6 @@
};
};
-/* XHCI, MMC, and Ethernet support needed to be complete */
-
-&uart0 {
- status = "okay";
-};
-
&pcie0 {
status = "okay";
};
@@ -129,6 +125,15 @@
status = "okay";
};
+&pinctrl {
+ pinctrl-names = "default";
+ pinctrl-0 = <&nand_sel>;
+ nand_sel: nand_sel {
+ function = "nand";
+ groups = "nand_grp";
+ };
+};
+
&sata_phy0 {
status = "okay";
};
@@ -141,11 +146,6 @@
status = "okay";
};
-&pinctrl {
- pinctrl-names = "default";
- pinctrl-0 = <&nand_sel>;
- nand_sel: nand_sel {
- function = "nand";
- groups = "nand_grp";
- };
+&uart0 {
+ status = "okay";
};
diff --git a/arch/arm/boot/dts/bcm958623hr.dts b/arch/arm/boot/dts/bcm958623hr.dts
index 4ceb8fe..32ea59a 100644
--- a/arch/arm/boot/dts/bcm958623hr.dts
+++ b/arch/arm/boot/dts/bcm958623hr.dts
@@ -120,6 +120,14 @@
};
};
+&sata_phy0 {
+ status = "okay";
+};
+
+&sata {
+ status = "okay";
+};
+
&srab {
compatible = "brcm,bcm58623-srab", "brcm,nsp-srab";
status = "okay";
@@ -165,14 +173,6 @@
};
};
-&sata_phy0 {
- status = "okay";
-};
-
-&sata {
- status = "okay";
-};
-
&uart0 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/bcm958625hr.dts b/arch/arm/boot/dts/bcm958625hr.dts
index 4420025..e7a4cb1 100644
--- a/arch/arm/boot/dts/bcm958625hr.dts
+++ b/arch/arm/boot/dts/bcm958625hr.dts
@@ -1,7 +1,7 @@
/*
* BSD LICENSE
*
- * Copyright (c) 2016 Broadcom. All rights reserved.
+ * Copyright(c) 2016 Broadcom. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -59,6 +59,10 @@
};
};
+&amac0 {
+ status = "okay";
+};
+
&nand {
nandcs at 0 {
compatible = "brcm,nandcs";
@@ -97,10 +101,6 @@
};
};
-&uart0 {
- status = "okay";
-};
-
&pcie0 {
status = "okay";
};
@@ -118,7 +118,15 @@
};
};
-&amac0 {
+&sata_phy0 {
+ status = "okay";
+};
+
+&sata_phy1 {
+ status = "okay";
+};
+
+&sata {
status = "okay";
};
@@ -167,14 +175,6 @@
};
};
-&sata_phy0 {
- status = "okay";
-};
-
-&sata_phy1 {
- status = "okay";
-};
-
-&sata {
+&uart0 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/bcm958625k.dts b/arch/arm/boot/dts/bcm958625k.dts
index 59d96fb..98337d6 100644
--- a/arch/arm/boot/dts/bcm958625k.dts
+++ b/arch/arm/boot/dts/bcm958625k.dts
@@ -53,14 +53,6 @@
};
};
-&uart0 {
- status = "okay";
-};
-
-&uart1 {
- status = "okay";
-};
-
&amac0 {
status = "okay";
};
@@ -69,30 +61,6 @@
status = "okay";
};
-&pcie0 {
- status = "okay";
-};
-
-&pcie1 {
- status = "okay";
-};
-
-&pcie2 {
- status = "okay";
-};
-
-&sata_phy0 {
- status = "okay";
-};
-
-&sata_phy1 {
- status = "okay";
-};
-
-&sata {
- status = "okay";
-};
-
&nand {
nandcs at 0 {
compatible = "brcm,nandcs";
@@ -131,6 +99,18 @@
};
};
+&pcie0 {
+ status = "okay";
+};
+
+&pcie1 {
+ status = "okay";
+};
+
+&pcie2 {
+ status = "okay";
+};
+
&pinctrl {
pinctrl-names = "default";
pinctrl-0 = <&nand_sel>;
@@ -173,3 +153,23 @@
};
};
};
+
+&sata_phy0 {
+ status = "okay";
+};
+
+&sata_phy1 {
+ status = "okay";
+};
+
+&sata {
+ status = "okay";
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&uart1 {
+ status = "okay";
+};
--
2.7.4
^ permalink raw reply related
* [PATCH 0/7] ARM: dts: NSP: DT Clean-ups and more
From: Jon Mason @ 2016-12-13 18:13 UTC (permalink / raw)
To: linux-arm-kernel
The Northstar Plus device tree files have gotten messy and out of sync.
The first 5 patches correct this, the next 2 add support for new things.
Jon Mason (7):
ARM: dts: NSP: DT Clean-ups
ARM: dts: NSP: Correct NAND partition unit address
ARM: dts: NSP: Add QSPI support to missing boards
ARM: dts: NSP: Add BCM958625K switch ports
ARM: dts: NSP: Add and enable amac2
ARM: dts: NSP: Add Ethernet to NSP XMC
ARM: dts: NSP: Add SD/MMC support
arch/arm/boot/dts/bcm-nsp.dtsi | 64 ++++++++++------
arch/arm/boot/dts/bcm958522er.dts | 35 ++++++++-
arch/arm/boot/dts/bcm958525er.dts | 35 ++++++++-
arch/arm/boot/dts/bcm958525xmc.dts | 68 +++++++++++++----
arch/arm/boot/dts/bcm958622hr.dts | 42 +++++++++++
arch/arm/boot/dts/bcm958623hr.dts | 58 ++++++++++++--
arch/arm/boot/dts/bcm958625hr.dts | 72 ++++++++++++++----
arch/arm/boot/dts/bcm958625k.dts | 151 ++++++++++++++++++++++++++++---------
arch/arm/boot/dts/bcm988312hr.dts | 42 +++++++++++
9 files changed, 472 insertions(+), 95 deletions(-)
--
2.7.4
^ permalink raw reply
* [PATCH 8/9] arm64: dts: rockchip: partially describe PWM regulators for Gru
From: Heiko Stuebner @ 2016-12-13 17:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161207170916.GA84287@google.com>
Am Mittwoch, 7. Dezember 2016, 09:09:17 CET schrieb Brian Norris:
> Hi Heiko,
>
> On Wed, Dec 07, 2016 at 05:48:24PM +0100, Heiko Stuebner wrote:
> > Am Donnerstag, 1. Dezember 2016, 18:27:32 CET schrieb Brian Norris:
> > > We need to add regulators to the CPU nodes, so cpufreq doesn't think it
> > > can crank up the clock speed without changing the voltage. However, we
> > > don't yet have the DT bindings to fully describe the Over Voltage
> > > Protection (OVP) circuits on these boards. Without that description, we
> > > might end up changing the voltage too much, too fast.
> > >
> > > Add the pwm-regulator descriptions and associate the CPU OPPs, but leave
> > > them disabled.
> > >
> > > Signed-off-by: Brian Norris <briannorris@chromium.org>
> >
> > is there a specific reason for keeping this change separate?
>
> Maybe not a great one. I figured they were somewhat controversial, so I
> at least wanted to split the "cpufreq patches" (i.e., this and the
> previous) from the main DTS(I) additions. I also figured we typically
> like to keep the base SoC changes separate from the board DTS(I)
> changes.
I was scratching my head for a bit where this was affecting the evb, until I
found the include at the end of patch5 :-) .
> > While it is nice for documentation reasons, as it stands now the previous
> > patch introduces a regression (cpufreq trying to scale without regulators)
> > and immediately fixes it here.
>
> Right. Additionally, as noted on the previous patch, we might do the
> same with EVB. But I don't know what the regulators are like for EVB.
> This is probably a bigger deal, since EVB has been working (allegedly)
> upstream for a while now.
Yep, it was at least booting :-) . I guess I should wire it up again. My shiny
new Gru somehow did take up its space recently.
> There's no way to split these up without either breaking compilation or
> breaking bisectability. For Kevin/Gru, they don't function at all before
> this series, so I figured some "settle" time wasn't a huge deal.
>
> > So if you're ok with it, I'd like to merge this one back into the previous
> > patch when applying.
>
> That'd be OK with me, as long as we're also confident about EVB.
That somehow sounds unrelated, as this patch only touches gru stuff anyway. So
if the evb breaks, it would do so after patch5 already.
> Maybe at a minimum, I should just patch in some empty regulator nodes,
> so cpufreq doesn't think there's no need to handle voltage.
So I guess going forward we could do, describe the evb pwm regulators (in
disabled state), add general OPPs, add gru with pwm regulators?
I'll try to hook up my evb and check on the pwm-regulators in the schematics
this week.
Heiko
^ permalink raw reply
* [PATCH v4 12/12] arm64: configs: enable SDHCI driver for Xenon
From: Gregory CLEMENT @ 2016-12-13 17:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.67d726f70f6bd48d38a2023513f2711080bc66c8.1481651244.git-series.gregory.clement@free-electrons.com>
This patch enables the driver for the SDHCI controller found on the
Marvell Armada 3700 and 7K/8K ARM64 SoCs.
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
arch/arm64/configs/defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index dab2cb0c1f1c..2d1f5ee62b18 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -353,6 +353,7 @@ CONFIG_MMC_DW=y
CONFIG_MMC_DW_EXYNOS=y
CONFIG_MMC_DW_K3=y
CONFIG_MMC_SUNXI=y
+CONFIG_MMC_SDHCI_XENON=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_GPIO=y
--
git-series 0.9.1
^ permalink raw reply related
* [PATCH v4 11/12] arm64: dts: marvell: add sdhci support for Armada 7K/8K
From: Gregory CLEMENT @ 2016-12-13 17:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.67d726f70f6bd48d38a2023513f2711080bc66c8.1481651244.git-series.gregory.clement@free-electrons.com>
Also enable it on the Armada 7040 DB board
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
arch/arm64/boot/dts/marvell/armada-7040-db.dts | 14 +++++++++++++-
arch/arm64/boot/dts/marvell/armada-ap806.dtsi | 9 ++++++++-
arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi | 10 +++++++++-
3 files changed, 33 insertions(+)
diff --git a/arch/arm64/boot/dts/marvell/armada-7040-db.dts b/arch/arm64/boot/dts/marvell/armada-7040-db.dts
index 070b589680c5..6adbfcd26369 100644
--- a/arch/arm64/boot/dts/marvell/armada-7040-db.dts
+++ b/arch/arm64/boot/dts/marvell/armada-7040-db.dts
@@ -146,3 +146,17 @@
&cpm_usb3_1 {
status = "okay";
};
+
+&ap_sdhci0 {
+ status = "okay";
+ bus-width = <4>;
+ no-1-8-v;
+ non-removable;
+};
+
+&cpm_sdhci0 {
+ status = "okay";
+ bus-width = <4>;
+ no-1-8-v;
+ non-removable;
+};
diff --git a/arch/arm64/boot/dts/marvell/armada-ap806.dtsi b/arch/arm64/boot/dts/marvell/armada-ap806.dtsi
index 7b6136182ad0..181e8c5de3bf 100644
--- a/arch/arm64/boot/dts/marvell/armada-ap806.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-ap806.dtsi
@@ -229,6 +229,15 @@
};
+ ap_sdhci0: sdhci at 6e0000 {
+ compatible = "marvell,armada-7000-sdhci";
+ reg = <0x6e0000 0x300>;
+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+ clock-names = "core";
+ clocks = <&cpm_syscon0 1 4>;
+ status = "disabled";
+ };
+
ap_syscon: system-controller at 6f4000 {
compatible = "marvell,ap806-system-controller",
"syscon";
diff --git a/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi
index e5e3ed678b6f..035b2b2fc9ca 100644
--- a/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi
@@ -164,6 +164,16 @@
clocks = <&cpm_syscon0 1 21>;
status = "disabled";
};
+
+ cpm_sdhci0: sdhci at 780000 {
+ compatible = "marvell,armada-7000-sdhci";
+ reg = <0x780000 0x300>;
+ interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
+ clock-names = "core";
+ clocks = <&cpm_syscon0 1 4>;
+ status = "disabled";
+ };
+
};
cpm_pcie0: pcie at f2600000 {
--
git-series 0.9.1
^ permalink raw reply related
* [PATCH v4 10/12] arm64: dts: marvell: add eMMC support for Armada 37xx
From: Gregory CLEMENT @ 2016-12-13 17:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.67d726f70f6bd48d38a2023513f2711080bc66c8.1481651244.git-series.gregory.clement@free-electrons.com>
Add the eMMC support for Armada 37xx SoC and enable it in the Armada 3720
DB board.
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
arch/arm64/boot/dts/marvell/armada-3720-db.dts | 17 +++++++++++++++++
arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 11 +++++++++++
2 files changed, 28 insertions(+)
diff --git a/arch/arm64/boot/dts/marvell/armada-3720-db.dts b/arch/arm64/boot/dts/marvell/armada-3720-db.dts
index 1372e9a6aaa4..707625031e29 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-db.dts
+++ b/arch/arm64/boot/dts/marvell/armada-3720-db.dts
@@ -72,6 +72,23 @@
status = "okay";
};
+&sdhci0 {
+ non-removable;
+ bus-width = <8>;
+ mmc-ddr-1_8v;
+ mmc-hs400-1_8v;
+ marvell,xenon-emmc;
+ marvell,pad-type = "fixed-1-8v";
+ status = "okay";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ mmccard: mmccard at 0 {
+ compatible = "mmc-card";
+ reg = <0>;
+ };
+};
+
/* CON31 */
&usb3 {
status = "okay";
diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
index c4762538ec01..0c4cafe92e66 100644
--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
@@ -161,6 +161,17 @@
};
};
+ sdhci0: sdhci at d8000 {
+ compatible = "marvell,armada-3700-sdhci",
+ "marvell,sdhci-xenon";
+ reg = <0xd8000 0x300
+ 0x17808 0x4>;
+ interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&nb_perih_clk 0>;
+ clock-names = "core";
+ status = "disabled";
+ };
+
sata: sata at e0000 {
compatible = "marvell,armada-3700-ahci";
reg = <0xe0000 0x2000>;
--
git-series 0.9.1
^ permalink raw reply related
* [PATCH v4 09/12] mmc: sdhci-xenon: Add SOC PHY PAD voltage control
From: Gregory CLEMENT @ 2016-12-13 17:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.67d726f70f6bd48d38a2023513f2711080bc66c8.1481651244.git-series.gregory.clement@free-electrons.com>
From: Hu Ziji <huziji@marvell.com>
Some SOCs have PHY PAD outside Xenon IP.
PHY PAD voltage should match signalling voltage in use.
Add generic SOC PHY PAD voltage control interface.
Implement Aramda-3700 SOC PHY PAD voltage control.
Signed-off-by: Hu Ziji <huziji@marvell.com>
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
drivers/mmc/host/sdhci-xenon-phy.c | 111 +++++++++++++++++++++++++++++-
drivers/mmc/host/sdhci-xenon.c | 2 +-
drivers/mmc/host/sdhci-xenon.h | 2 +-
3 files changed, 114 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/host/sdhci-xenon-phy.c b/drivers/mmc/host/sdhci-xenon-phy.c
index 453c5076761c..8b06bad34b26 100644
--- a/drivers/mmc/host/sdhci-xenon-phy.c
+++ b/drivers/mmc/host/sdhci-xenon-phy.c
@@ -148,6 +148,22 @@ enum phy_type_enum {
NR_PHY_TYPES
};
+struct soc_pad_ctrl_table {
+ const char *soc;
+ void (*set_soc_pad)(struct sdhci_host *host,
+ unsigned char signal_voltage);
+};
+
+struct soc_pad_ctrl {
+ /* Register address of SOC PHY PAD ctrl */
+ void __iomem *reg;
+ /* SOC PHY PAD ctrl type */
+ enum soc_pad_ctrl_type pad_type;
+ /* SOC specific operation to set SOC PHY PAD */
+ void (*set_soc_pad)(struct sdhci_host *host,
+ unsigned char signal_voltage);
+};
+
static struct xenon_emmc_phy_regs xenon_emmc_5_0_phy_regs = {
.timing_adj = SDHCI_EMMC_5_0_PHY_TIMING_ADJUST,
.func_ctrl = SDHCI_EMMC_5_0_PHY_FUNC_CONTROL,
@@ -181,6 +197,8 @@ struct emmc_phy_params {
u8 nr_tun_times;
/* Divider for calculating Tuning Step */
u8 tun_step_divider;
+
+ struct soc_pad_ctrl pad_ctrl;
};
static int alloc_emmc_phy(struct sdhci_xenon_priv *priv)
@@ -257,6 +275,45 @@ static int emmc_phy_init(struct sdhci_host *host)
return 0;
}
+#define ARMADA_3700_SOC_PAD_1_8V 0x1
+#define ARMADA_3700_SOC_PAD_3_3V 0x0
+
+static void armada_3700_soc_pad_voltage_set(struct sdhci_host *host,
+ unsigned char signal_voltage)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
+ struct emmc_phy_params *params = priv->phy_params;
+
+ if (params->pad_ctrl.pad_type == SOC_PAD_FIXED_1_8V) {
+ writel(ARMADA_3700_SOC_PAD_1_8V, params->pad_ctrl.reg);
+ } else if (params->pad_ctrl.pad_type == SOC_PAD_SD) {
+ if (signal_voltage == MMC_SIGNAL_VOLTAGE_180)
+ writel(ARMADA_3700_SOC_PAD_1_8V, params->pad_ctrl.reg);
+ else if (signal_voltage == MMC_SIGNAL_VOLTAGE_330)
+ writel(ARMADA_3700_SOC_PAD_3_3V, params->pad_ctrl.reg);
+ }
+}
+
+/*
+ * Set SOC PHY voltage PAD control register,
+ * according to the operation voltage on PAD.
+ * The detailed operation depends on SOC implementaion.
+ */
+static void emmc_phy_set_soc_pad(struct sdhci_host *host,
+ unsigned char signal_voltage)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
+ struct emmc_phy_params *params = priv->phy_params;
+
+ if (!params->pad_ctrl.reg)
+ return;
+
+ if (params->pad_ctrl.set_soc_pad)
+ params->pad_ctrl.set_soc_pad(host, signal_voltage);
+}
+
/*
* Enable eMMC PHY HW DLL
* DLL should be enabled and stable before HS200/SDR104 tuning,
@@ -630,6 +687,51 @@ static void emmc_phy_set(struct sdhci_host *host,
dev_dbg(mmc_dev(host->mmc), "eMMC PHY setting completes\n");
}
+static int get_dt_pad_ctrl_data(struct sdhci_host *host,
+ struct device_node *np,
+ struct emmc_phy_params *params)
+{
+ int ret = 0;
+ const char *name;
+ struct resource iomem;
+
+ if (of_device_is_compatible(np, "marvell,armada-3700-sdhci"))
+ params->pad_ctrl.set_soc_pad = armada_3700_soc_pad_voltage_set;
+ else
+ return 0;
+
+ if (of_address_to_resource(np, 1, &iomem)) {
+ dev_err(mmc_dev(host->mmc), "Unable to find SOC PAD ctrl register address for %s\n",
+ np->name);
+ return -EINVAL;
+ }
+
+ params->pad_ctrl.reg = devm_ioremap_resource(mmc_dev(host->mmc),
+ &iomem);
+ if (IS_ERR(params->pad_ctrl.reg)) {
+ dev_err(mmc_dev(host->mmc), "Unable to get SOC PHY PAD ctrl regiser for %s\n",
+ np->name);
+ return PTR_ERR(params->pad_ctrl.reg);
+ }
+
+ ret = of_property_read_string(np, "marvell,pad-type", &name);
+ if (ret) {
+ dev_err(mmc_dev(host->mmc), "Unable to determine SOC PHY PAD ctrl type\n");
+ return ret;
+ }
+ if (!strcmp(name, "sd")) {
+ params->pad_ctrl.pad_type = SOC_PAD_SD;
+ } else if (!strcmp(name, "fixed-1-8v")) {
+ params->pad_ctrl.pad_type = SOC_PAD_FIXED_1_8V;
+ } else {
+ dev_err(mmc_dev(host->mmc), "Unsupported SOC PHY PAD ctrl type %s\n",
+ name);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
static int emmc_phy_parse_param_dt(struct sdhci_host *host,
struct device_node *np,
struct emmc_phy_params *params)
@@ -663,7 +765,14 @@ static int emmc_phy_parse_param_dt(struct sdhci_host *host,
else
params->tun_step_divider = SDHCI_TUNING_STEP_DIVIDER;
- return 0;
+ return get_dt_pad_ctrl_data(host, np, params);
+}
+
+/* Set SOC PHY Voltage PAD */
+void xenon_soc_pad_ctrl(struct sdhci_host *host,
+ unsigned char signal_voltage)
+{
+ emmc_phy_set_soc_pad(host, signal_voltage);
}
/*
diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c
index 0347de533777..9b4fc4ac0216 100644
--- a/drivers/mmc/host/sdhci-xenon.c
+++ b/drivers/mmc/host/sdhci-xenon.c
@@ -322,6 +322,8 @@ static int xenon_start_signal_voltage_switch(struct mmc_host *mmc,
*/
enable_xenon_internal_clk(host);
+ xenon_soc_pad_ctrl(host, ios->signal_voltage);
+
if (priv->init_card_type == MMC_TYPE_MMC)
return xenon_emmc_signal_voltage_switch(mmc, ios);
diff --git a/drivers/mmc/host/sdhci-xenon.h b/drivers/mmc/host/sdhci-xenon.h
index 86b5d2b1f1aa..a8312e36a03c 100644
--- a/drivers/mmc/host/sdhci-xenon.h
+++ b/drivers/mmc/host/sdhci-xenon.h
@@ -106,4 +106,6 @@ struct sdhci_xenon_priv {
int xenon_phy_adj(struct sdhci_host *host, struct mmc_ios *ios);
int xenon_phy_parse_dt(struct device_node *np,
struct sdhci_host *host);
+void xenon_soc_pad_ctrl(struct sdhci_host *host,
+ unsigned char signal_voltage);
#endif
--
git-series 0.9.1
^ permalink raw reply related
* [PATCH v4 08/12] mmc: sdhci-xenon: Add support to PHYs of Marvell Xenon SDHC.
From: Gregory CLEMENT @ 2016-12-13 17:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.67d726f70f6bd48d38a2023513f2711080bc66c8.1481651244.git-series.gregory.clement@free-electrons.com>
From: Hu Ziji <huziji@marvell.com>
Marvell Xenon eMMC/SD/SDIO Host Controller contains PHY.
Multiple types of PHYs are supported.
Add support to multiple types of PHYs init and configuration.
Add register definitions of PHYs.
Xenon PHY cannot fit in kernel common PHY framework.
Xenon SDHC PHY register is a part of Xenon SDHC register set.
Besides, MMC initialization has to call several PHY functions
to complete timing setting.
Those PHY setting functions have to access SDHC registers
and know current MMC setting, such as bus width, clock frequency
and speed mode.
As a result, implement Xenon PHY in MMC host directory.
Signed-off-by: Hu Ziji <huziji@marvell.com>
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
drivers/mmc/host/Makefile | 2 +-
drivers/mmc/host/sdhci-xenon-phy.c | 799 ++++++++++++++++++++++++++++++-
drivers/mmc/host/sdhci-xenon.c | 3 +-
drivers/mmc/host/sdhci-xenon.h | 39 +-
4 files changed, 841 insertions(+), 2 deletions(-)
create mode 100644 drivers/mmc/host/sdhci-xenon-phy.c
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 75eaf743486c..4f2854556ff7 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -82,4 +82,4 @@ ifeq ($(CONFIG_CB710_DEBUG),y)
endif
obj-$(CONFIG_MMC_SDHCI_XENON) += sdhci-xenon-driver.o
-sdhci-xenon-driver-y += sdhci-xenon.o
+sdhci-xenon-driver-y += sdhci-xenon.o sdhci-xenon-phy.o
diff --git a/drivers/mmc/host/sdhci-xenon-phy.c b/drivers/mmc/host/sdhci-xenon-phy.c
new file mode 100644
index 000000000000..453c5076761c
--- /dev/null
+++ b/drivers/mmc/host/sdhci-xenon-phy.c
@@ -0,0 +1,799 @@
+/*
+ * PHY support for Xenon SDHC
+ *
+ * Copyright (C) 2016 Marvell, All Rights Reserved.
+ *
+ * Author: Hu Ziji <huziji@marvell.com>
+ * Date: 2016-8-24
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ */
+
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/of_address.h>
+
+#include "sdhci-pltfm.h"
+#include "sdhci-xenon.h"
+
+/* Register base for eMMC PHY 5.0 Version */
+#define SDHCI_EMMC_5_0_PHY_REG_BASE 0x0160
+/* Register base for eMMC PHY 5.1 Version */
+#define SDHCI_EMMC_PHY_REG_BASE 0x0170
+
+#define SDHCI_EMMC_PHY_TIMING_ADJUST SDHCI_EMMC_PHY_REG_BASE
+#define SDHCI_EMMC_5_0_PHY_TIMING_ADJUST SDHCI_EMMC_5_0_PHY_REG_BASE
+#define SDHCI_TIMING_ADJUST_SLOW_MODE BIT(29)
+#define SDHCI_TIMING_ADJUST_SDIO_MODE BIT(28)
+#define SDHCI_OUTPUT_QSN_PHASE_SELECT BIT(17)
+#define SDHCI_SAMPL_INV_QSP_PHASE_SELECT BIT(18)
+#define SDHCI_SAMPL_INV_QSP_PHASE_SELECT_SHIFT 18
+#define SDHCI_PHY_INITIALIZAION BIT(31)
+#define SDHCI_WAIT_CYCLE_BEFORE_USING_MASK 0xF
+#define SDHCI_WAIT_CYCLE_BEFORE_USING_SHIFT 12
+#define SDHCI_FC_SYNC_EN_DURATION_MASK 0xF
+#define SDHCI_FC_SYNC_EN_DURATION_SHIFT 8
+#define SDHCI_FC_SYNC_RST_EN_DURATION_MASK 0xF
+#define SDHCI_FC_SYNC_RST_EN_DURATION_SHIFT 4
+#define SDHCI_FC_SYNC_RST_DURATION_MASK 0xF
+#define SDHCI_FC_SYNC_RST_DURATION_SHIFT 0
+
+#define SDHCI_EMMC_PHY_FUNC_CONTROL (SDHCI_EMMC_PHY_REG_BASE + 0x4)
+#define SDHCI_EMMC_5_0_PHY_FUNC_CONTROL \
+ (SDHCI_EMMC_5_0_PHY_REG_BASE + 0x4)
+#define SDHCI_ASYNC_DDRMODE_MASK BIT(23)
+#define SDHCI_ASYNC_DDRMODE_SHIFT 23
+#define SDHCI_CMD_DDR_MODE BIT(16)
+#define SDHCI_DQ_DDR_MODE_SHIFT 8
+#define SDHCI_DQ_DDR_MODE_MASK 0xFF
+#define SDHCI_DQ_ASYNC_MODE BIT(4)
+
+#define SDHCI_EMMC_PHY_PAD_CONTROL (SDHCI_EMMC_PHY_REG_BASE + 0x8)
+#define SDHCI_EMMC_5_0_PHY_PAD_CONTROL \
+ (SDHCI_EMMC_5_0_PHY_REG_BASE + 0x8)
+#define SDHCI_REC_EN_SHIFT 24
+#define SDHCI_REC_EN_MASK 0xF
+#define SDHCI_FC_DQ_RECEN BIT(24)
+#define SDHCI_FC_CMD_RECEN BIT(25)
+#define SDHCI_FC_QSP_RECEN BIT(26)
+#define SDHCI_FC_QSN_RECEN BIT(27)
+#define SDHCI_OEN_QSN BIT(28)
+#define SDHCI_AUTO_RECEN_CTRL BIT(30)
+#define SDHCI_FC_ALL_CMOS_RECEIVER 0xF000
+
+#define SDHCI_EMMC5_FC_QSP_PD BIT(18)
+#define SDHCI_EMMC5_FC_QSP_PU BIT(22)
+#define SDHCI_EMMC5_FC_CMD_PD BIT(17)
+#define SDHCI_EMMC5_FC_CMD_PU BIT(21)
+#define SDHCI_EMMC5_FC_DQ_PD BIT(16)
+#define SDHCI_EMMC5_FC_DQ_PU BIT(20)
+
+#define SDHCI_EMMC_PHY_PAD_CONTROL1 (SDHCI_EMMC_PHY_REG_BASE + 0xC)
+#define SDHCI_EMMC5_1_FC_QSP_PD BIT(9)
+#define SDHCI_EMMC5_1_FC_QSP_PU BIT(25)
+#define SDHCI_EMMC5_1_FC_CMD_PD BIT(8)
+#define SDHCI_EMMC5_1_FC_CMD_PU BIT(24)
+#define SDHCI_EMMC5_1_FC_DQ_PD 0xFF
+#define SDHCI_EMMC5_1_FC_DQ_PU (0xFF << 16)
+
+#define SDHCI_EMMC_PHY_PAD_CONTROL2 (SDHCI_EMMC_PHY_REG_BASE + 0x10)
+#define SDHCI_EMMC_5_0_PHY_PAD_CONTROL2 \
+ (SDHCI_EMMC_5_0_PHY_REG_BASE + 0xC)
+#define SDHCI_ZNR_MASK 0x1F
+#define SDHCI_ZNR_SHIFT 8
+#define SDHCI_ZPR_MASK 0x1F
+/* Perferred ZNR and ZPR value vary between different boards.
+ * The specific ZNR and ZPR value should be defined here
+ * according to board actual timing.
+ */
+#define SDHCI_ZNR_DEF_VALUE 0xF
+#define SDHCI_ZPR_DEF_VALUE 0xF
+
+#define SDHCI_EMMC_PHY_DLL_CONTROL (SDHCI_EMMC_PHY_REG_BASE + 0x14)
+#define SDHCI_EMMC_5_0_PHY_DLL_CONTROL \
+ (SDHCI_EMMC_5_0_PHY_REG_BASE + 0x10)
+#define SDHCI_DLL_ENABLE BIT(31)
+#define SDHCI_DLL_UPDATE_STROBE_5_0 BIT(30)
+#define SDHCI_DLL_REFCLK_SEL BIT(30)
+#define SDHCI_DLL_UPDATE BIT(23)
+#define SDHCI_DLL_PHSEL1_SHIFT 24
+#define SDHCI_DLL_PHSEL0_SHIFT 16
+#define SDHCI_DLL_PHASE_MASK 0x3F
+#define SDHCI_DLL_PHASE_90_DEGREE 0x1F
+#define SDHCI_DLL_FAST_LOCK BIT(5)
+#define SDHCI_DLL_GAIN2X BIT(3)
+#define SDHCI_DLL_BYPASS_EN BIT(0)
+
+#define SDHCI_EMMC_5_0_PHY_LOGIC_TIMING_ADJUST \
+ (SDHCI_EMMC_5_0_PHY_REG_BASE + 0x14)
+#define SDHCI_EMMC_PHY_LOGIC_TIMING_ADJUST (SDHCI_EMMC_PHY_REG_BASE + 0x18)
+#define SDHCI_LOGIC_TIMING_VALUE 0x00AA8977
+
+enum soc_pad_ctrl_type {
+ SOC_PAD_SD,
+ SOC_PAD_FIXED_1_8V,
+};
+
+/*
+ * List offset of PHY registers and some special register values
+ * in eMMC PHY 5.0 or eMMC PHY 5.1
+ */
+struct xenon_emmc_phy_regs {
+ /* Offset of Timing Adjust register */
+ u16 timing_adj;
+ /* Offset of Func Control register */
+ u16 func_ctrl;
+ /* Offset of Pad Control register */
+ u16 pad_ctrl;
+ /* Offset of Pad Control register 2 */
+ u16 pad_ctrl2;
+ /* Offset of DLL Control register */
+ u16 dll_ctrl;
+ /* Offset of Logic Timing Adjust register */
+ u16 logic_timing_adj;
+ /* DLL Update Enable bit */
+ u32 dll_update;
+};
+
+static const char * const phy_types[] = {
+ "emmc 5.0 phy",
+ "emmc 5.1 phy"
+};
+
+enum phy_type_enum {
+ EMMC_5_0_PHY,
+ EMMC_5_1_PHY,
+ NR_PHY_TYPES
+};
+
+static struct xenon_emmc_phy_regs xenon_emmc_5_0_phy_regs = {
+ .timing_adj = SDHCI_EMMC_5_0_PHY_TIMING_ADJUST,
+ .func_ctrl = SDHCI_EMMC_5_0_PHY_FUNC_CONTROL,
+ .pad_ctrl = SDHCI_EMMC_5_0_PHY_PAD_CONTROL,
+ .pad_ctrl2 = SDHCI_EMMC_5_0_PHY_PAD_CONTROL2,
+ .dll_ctrl = SDHCI_EMMC_5_0_PHY_DLL_CONTROL,
+ .logic_timing_adj = SDHCI_EMMC_5_0_PHY_LOGIC_TIMING_ADJUST,
+ .dll_update = SDHCI_DLL_UPDATE_STROBE_5_0,
+};
+
+static struct xenon_emmc_phy_regs xenon_emmc_5_1_phy_regs = {
+ .timing_adj = SDHCI_EMMC_PHY_TIMING_ADJUST,
+ .func_ctrl = SDHCI_EMMC_PHY_FUNC_CONTROL,
+ .pad_ctrl = SDHCI_EMMC_PHY_PAD_CONTROL,
+ .pad_ctrl2 = SDHCI_EMMC_PHY_PAD_CONTROL2,
+ .dll_ctrl = SDHCI_EMMC_PHY_DLL_CONTROL,
+ .logic_timing_adj = SDHCI_EMMC_PHY_LOGIC_TIMING_ADJUST,
+ .dll_update = SDHCI_DLL_UPDATE,
+};
+
+/*
+ * eMMC PHY configuration and operations
+ */
+struct emmc_phy_params {
+ bool slow_mode;
+
+ u8 znr;
+ u8 zpr;
+
+ /* Nr of consecutive Sampling Points of a Valid Sampling Window */
+ u8 nr_tun_times;
+ /* Divider for calculating Tuning Step */
+ u8 tun_step_divider;
+};
+
+static int alloc_emmc_phy(struct sdhci_xenon_priv *priv)
+{
+ struct emmc_phy_params *params;
+
+ params = kzalloc(sizeof(*params), GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+
+ priv->phy_params = params;
+ if (priv->phy_type == EMMC_5_0_PHY)
+ priv->emmc_phy_regs = &xenon_emmc_5_0_phy_regs;
+ else
+ priv->emmc_phy_regs = &xenon_emmc_5_1_phy_regs;
+
+ return 0;
+}
+
+/*
+ * eMMC 5.0/5.1 PHY init/re-init.
+ * eMMC PHY init should be executed after:
+ * 1. SDCLK frequecny changes.
+ * 2. SDCLK is stopped and re-enabled.
+ * 3. config in emmc_phy_regs->timing_adj and emmc_phy_regs->func_ctrl
+ * are changed
+ */
+static int emmc_phy_init(struct sdhci_host *host)
+{
+ u32 reg;
+ u32 wait, clock;
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
+ struct xenon_emmc_phy_regs *phy_regs = priv->emmc_phy_regs;
+
+ reg = sdhci_readl(host, phy_regs->timing_adj);
+ reg |= SDHCI_PHY_INITIALIZAION;
+ sdhci_writel(host, reg, phy_regs->timing_adj);
+
+ /* Add duration of FC_SYNC_RST */
+ wait = ((reg >> SDHCI_FC_SYNC_RST_DURATION_SHIFT) &
+ SDHCI_FC_SYNC_RST_DURATION_MASK);
+ /* Add interval between FC_SYNC_EN and FC_SYNC_RST */
+ wait += ((reg >> SDHCI_FC_SYNC_RST_EN_DURATION_SHIFT) &
+ SDHCI_FC_SYNC_RST_EN_DURATION_MASK);
+ /* Add duration of asserting FC_SYNC_EN */
+ wait += ((reg >> SDHCI_FC_SYNC_EN_DURATION_SHIFT) &
+ SDHCI_FC_SYNC_EN_DURATION_MASK);
+ /* Add duration of waiting for PHY */
+ wait += ((reg >> SDHCI_WAIT_CYCLE_BEFORE_USING_SHIFT) &
+ SDHCI_WAIT_CYCLE_BEFORE_USING_MASK);
+ /* 4 addtional bus clock and 4 AXI bus clock are required */
+ wait += 8;
+ wait <<= 20;
+
+ clock = host->clock;
+ if (!clock)
+ /* Use the possibly slowest bus frequency value */
+ clock = SDHCI_LOWEST_SDCLK_FREQ;
+ /* get the wait time */
+ wait /= clock;
+ wait++;
+ /* wait for host eMMC PHY init completes */
+ udelay(wait);
+
+ reg = sdhci_readl(host, phy_regs->timing_adj);
+ reg &= SDHCI_PHY_INITIALIZAION;
+ if (reg) {
+ dev_err(mmc_dev(host->mmc), "eMMC PHY init cannot complete after %d us\n",
+ wait);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+/*
+ * Enable eMMC PHY HW DLL
+ * DLL should be enabled and stable before HS200/SDR104 tuning,
+ * and before HS400 data strobe setting.
+ */
+static int emmc_phy_enable_dll(struct sdhci_host *host)
+{
+ u32 reg;
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
+ struct xenon_emmc_phy_regs *phy_regs = priv->emmc_phy_regs;
+ u8 timeout;
+
+ if (WARN_ON(host->clock <= MMC_HIGH_52_MAX_DTR))
+ return -EINVAL;
+
+ reg = sdhci_readl(host, phy_regs->dll_ctrl);
+ if (reg & SDHCI_DLL_ENABLE)
+ return 0;
+
+ /* Enable DLL */
+ reg = sdhci_readl(host, phy_regs->dll_ctrl);
+ reg |= (SDHCI_DLL_ENABLE | SDHCI_DLL_FAST_LOCK);
+
+ /*
+ * Set Phase as 90 degree, which is most common value.
+ * Might set another value if necessary.
+ * The granularity is 1 degree.
+ */
+ reg &= ~((SDHCI_DLL_PHASE_MASK << SDHCI_DLL_PHSEL0_SHIFT) |
+ (SDHCI_DLL_PHASE_MASK << SDHCI_DLL_PHSEL1_SHIFT));
+ reg |= ((SDHCI_DLL_PHASE_90_DEGREE << SDHCI_DLL_PHSEL0_SHIFT) |
+ (SDHCI_DLL_PHASE_90_DEGREE << SDHCI_DLL_PHSEL1_SHIFT));
+
+ reg &= ~SDHCI_DLL_BYPASS_EN;
+ reg |= phy_regs->dll_update;
+ if (priv->phy_type == EMMC_5_1_PHY)
+ reg &= ~SDHCI_DLL_REFCLK_SEL;
+ sdhci_writel(host, reg, phy_regs->dll_ctrl);
+
+ /* Wait max 32 ms */
+ timeout = 32;
+ while (!(sdhci_readw(host, SDHCI_SLOT_EXT_PRESENT_STATE) &
+ SDHCI_DLL_LOCK_STATE)) {
+ if (!timeout) {
+ dev_err(mmc_dev(host->mmc), "Wait for DLL Lock time-out\n");
+ return -ETIMEDOUT;
+ }
+ timeout--;
+ mdelay(1);
+ }
+ return 0;
+}
+
+/*
+ * Config to eMMC PHY to prepare for tuning.
+ * Enable HW DLL and set the TUNING_STEP
+ */
+static int emmc_phy_config_tuning(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
+ struct emmc_phy_params *params = priv->phy_params;
+ u32 reg, tuning_step;
+ int ret;
+ unsigned long flags;
+
+ if (WARN_ON(host->clock <= MMC_HIGH_52_MAX_DTR))
+ return -EINVAL;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ ret = emmc_phy_enable_dll(host);
+ if (ret) {
+ spin_unlock_irqrestore(&host->lock, flags);
+ return ret;
+ }
+
+ /* Achieve TUNGING_STEP with HW DLL help */
+ reg = sdhci_readl(host, SDHCI_SLOT_DLL_CUR_DLY_VAL);
+ tuning_step = reg / params->tun_step_divider;
+ if (unlikely(tuning_step > SDHCI_TUNING_STEP_MASK)) {
+ dev_warn(mmc_dev(host->mmc),
+ "HS200 TUNING_STEP %d is larger than MAX value\n",
+ tuning_step);
+ tuning_step = SDHCI_TUNING_STEP_MASK;
+ }
+
+ /* Set TUNING_STEP for later tuning */
+ reg = sdhci_readl(host, SDHCI_SLOT_OP_STATUS_CTRL);
+ reg &= ~(SDHCI_TUN_CONSECUTIVE_TIMES_MASK <<
+ SDHCI_TUN_CONSECUTIVE_TIMES_SHIFT);
+ reg |= (params->nr_tun_times << SDHCI_TUN_CONSECUTIVE_TIMES_SHIFT);
+ reg &= ~(SDHCI_TUNING_STEP_MASK << SDHCI_TUNING_STEP_SHIFT);
+ reg |= (tuning_step << SDHCI_TUNING_STEP_SHIFT);
+ sdhci_writel(host, reg, SDHCI_SLOT_OP_STATUS_CTRL);
+
+ spin_unlock_irqrestore(&host->lock, flags);
+ return 0;
+}
+
+static void __emmc_phy_disable_data_strobe(struct sdhci_host *host)
+{
+ u32 reg;
+
+ /* Disable SDHC Data Strobe */
+ reg = sdhci_readl(host, SDHCI_SLOT_EMMC_CTRL);
+ reg &= ~SDHCI_ENABLE_DATA_STROBE;
+ sdhci_writel(host, reg, SDHCI_SLOT_EMMC_CTRL);
+}
+
+/* Set HS400 Data Strobe */
+static void emmc_phy_strobe_delay_adj(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
+ unsigned long flags;
+ u32 reg;
+
+ if (WARN_ON(host->timing != MMC_TIMING_MMC_HS400))
+ return;
+
+ if (host->clock <= MMC_HIGH_52_MAX_DTR)
+ return;
+
+ dev_dbg(mmc_dev(host->mmc), "starts HS400 strobe delay adjustment\n");
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ emmc_phy_enable_dll(host);
+
+ /* Enable SDHC Data Strobe */
+ reg = sdhci_readl(host, SDHCI_SLOT_EMMC_CTRL);
+ reg |= SDHCI_ENABLE_DATA_STROBE;
+ sdhci_writel(host, reg, SDHCI_SLOT_EMMC_CTRL);
+
+ /* Set Data Strobe Pull down */
+ if (priv->phy_type == EMMC_5_0_PHY) {
+ reg = sdhci_readl(host, SDHCI_EMMC_5_0_PHY_PAD_CONTROL);
+ reg |= SDHCI_EMMC5_FC_QSP_PD;
+ reg &= ~SDHCI_EMMC5_FC_QSP_PU;
+ sdhci_writel(host, reg, SDHCI_EMMC_5_0_PHY_PAD_CONTROL);
+ } else {
+ reg = sdhci_readl(host, SDHCI_EMMC_PHY_PAD_CONTROL1);
+ reg |= SDHCI_EMMC5_1_FC_QSP_PD;
+ reg &= ~SDHCI_EMMC5_1_FC_QSP_PU;
+ sdhci_writel(host, reg, SDHCI_EMMC_PHY_PAD_CONTROL1);
+ }
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static inline bool temp_stage_hs200_to_hs400(struct sdhci_host *host,
+ struct sdhci_xenon_priv *priv)
+{
+ /*
+ * Tmep stages from HS200 to HS400
+ * from HS200 to HS in 200MHz
+ * from 200MHz to 52MHz
+ */
+ if (((priv->timing == MMC_TIMING_MMC_HS200) &&
+ (host->timing == MMC_TIMING_MMC_HS)) ||
+ ((host->timing == MMC_TIMING_MMC_HS) &&
+ (priv->clock > host->clock)))
+ return true;
+
+ return false;
+}
+
+static inline bool temp_stage_hs400_to_h200(struct sdhci_host *host,
+ struct sdhci_xenon_priv *priv)
+{
+ /*
+ * Temp stages from HS400 t0 HS200:
+ * from 200MHz to 52MHz in HS400
+ * from HS400 to HS DDR in 52MHz
+ * from HS DDR to HS in 52MHz
+ * from HS to HS200 in 52MHz
+ */
+ if (((priv->timing == MMC_TIMING_MMC_HS400) &&
+ ((host->clock == MMC_HIGH_52_MAX_DTR) ||
+ (host->timing == MMC_TIMING_MMC_DDR52))) ||
+ ((priv->timing == MMC_TIMING_MMC_DDR52) &&
+ (host->timing == MMC_TIMING_MMC_HS)) ||
+ ((host->timing == MMC_TIMING_MMC_HS200) &&
+ (host->clock == MMC_HIGH_52_MAX_DTR)))
+ return true;
+
+ return false;
+}
+
+/*
+ * If eMMC PHY Slow Mode is required in lower speed mode in SDR mode
+ * (SDLCK < 55MHz), enable Slow Mode to bypass eMMC PHY.
+ * SDIO slower SDR mode also requires Slow Mode.
+ *
+ * If Slow Mode is enabled, return true.
+ * Otherwise, return false.
+ */
+static bool emmc_phy_slow_mode(struct sdhci_host *host,
+ unsigned char timing)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
+ struct emmc_phy_params *params = priv->phy_params;
+ struct xenon_emmc_phy_regs *phy_regs = priv->emmc_phy_regs;
+ u32 reg;
+
+ /* Skip temp stages from HS200 to HS400 */
+ if (temp_stage_hs200_to_hs400(host, priv))
+ return false;
+
+ /* Skip temp stages from HS400 t0 HS200 */
+ if (temp_stage_hs400_to_h200(host, priv))
+ return false;
+
+ reg = sdhci_readl(host, phy_regs->timing_adj);
+ /* Enable Slow Mode for SDIO in slower SDR mode */
+ if ((priv->init_card_type == MMC_TYPE_SDIO) &&
+ ((timing == MMC_TIMING_UHS_SDR25) ||
+ (timing == MMC_TIMING_UHS_SDR12) ||
+ (timing == MMC_TIMING_SD_HS) ||
+ (timing == MMC_TIMING_LEGACY))) {
+ reg |= SDHCI_TIMING_ADJUST_SLOW_MODE;
+ sdhci_writel(host, reg, phy_regs->timing_adj);
+ return true;
+ }
+
+ /* Check if Slow Mode is required in lower speed mode in SDR mode */
+ if (((timing == MMC_TIMING_UHS_SDR50) ||
+ (timing == MMC_TIMING_UHS_SDR25) ||
+ (timing == MMC_TIMING_UHS_SDR12) ||
+ (timing == MMC_TIMING_SD_HS) ||
+ (timing == MMC_TIMING_MMC_HS) ||
+ (timing == MMC_TIMING_LEGACY)) && params->slow_mode) {
+ reg |= SDHCI_TIMING_ADJUST_SLOW_MODE;
+ sdhci_writel(host, reg, phy_regs->timing_adj);
+ return true;
+ }
+
+ reg &= ~SDHCI_TIMING_ADJUST_SLOW_MODE;
+ sdhci_writel(host, reg, phy_regs->timing_adj);
+ return false;
+}
+
+/*
+ * Set-up eMMC 5.0/5.1 PHY.
+ * Specific onfiguration depends on the current speed mode in use.
+ */
+static void emmc_phy_set(struct sdhci_host *host,
+ unsigned char timing)
+{
+ u32 reg;
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
+ struct emmc_phy_params *params = priv->phy_params;
+ struct xenon_emmc_phy_regs *phy_regs = priv->emmc_phy_regs;
+ unsigned long flags;
+
+ dev_dbg(mmc_dev(host->mmc), "eMMC PHY setting starts\n");
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ reg = sdhci_readl(host, SDHCI_SYS_EXT_OP_CTRL);
+ reg |= SDHCI_MASK_CMD_CONFLICT_ERROR;
+ sdhci_writel(host, reg, SDHCI_SYS_EXT_OP_CTRL);
+
+ /* Setup pad, set bit[28] and bits[26:24] */
+ reg = sdhci_readl(host, phy_regs->pad_ctrl);
+ reg |= (SDHCI_FC_DQ_RECEN | SDHCI_FC_CMD_RECEN |
+ SDHCI_FC_QSP_RECEN | SDHCI_OEN_QSN);
+ /* All FC_XX_RECEIVCE should be set as CMOS Type */
+ reg |= SDHCI_FC_ALL_CMOS_RECEIVER;
+ sdhci_writel(host, reg, phy_regs->pad_ctrl);
+
+ /* Set CMD and DQ Pull Up */
+ if (priv->phy_type == EMMC_5_0_PHY) {
+ reg = sdhci_readl(host, SDHCI_EMMC_5_0_PHY_PAD_CONTROL);
+ reg |= (SDHCI_EMMC5_FC_CMD_PU | SDHCI_EMMC5_FC_DQ_PU);
+ reg &= ~(SDHCI_EMMC5_FC_CMD_PD | SDHCI_EMMC5_FC_DQ_PD);
+ sdhci_writel(host, reg, SDHCI_EMMC_5_0_PHY_PAD_CONTROL);
+ } else {
+ reg = sdhci_readl(host, SDHCI_EMMC_PHY_PAD_CONTROL1);
+ reg |= (SDHCI_EMMC5_1_FC_CMD_PU | SDHCI_EMMC5_1_FC_DQ_PU);
+ reg &= ~(SDHCI_EMMC5_1_FC_CMD_PD | SDHCI_EMMC5_1_FC_DQ_PD);
+ sdhci_writel(host, reg, SDHCI_EMMC_PHY_PAD_CONTROL1);
+ }
+
+ if (timing == MMC_TIMING_LEGACY)
+ goto phy_init;
+
+ /*
+ * FIXME: should depends on the specific board timing.
+ */
+ if ((timing == MMC_TIMING_MMC_HS400) ||
+ (timing == MMC_TIMING_MMC_HS200) ||
+ (timing == MMC_TIMING_UHS_SDR50) ||
+ (timing == MMC_TIMING_UHS_SDR104) ||
+ (timing == MMC_TIMING_UHS_DDR50) ||
+ (timing == MMC_TIMING_UHS_SDR25) ||
+ (timing == MMC_TIMING_MMC_DDR52)) {
+ reg = sdhci_readl(host, phy_regs->timing_adj);
+ reg &= ~SDHCI_OUTPUT_QSN_PHASE_SELECT;
+ sdhci_writel(host, reg, phy_regs->timing_adj);
+ }
+
+ /*
+ * If SDIO card, set SDIO Mode
+ * Otherwise, clear SDIO Mode
+ */
+ reg = sdhci_readl(host, phy_regs->timing_adj);
+ if (priv->init_card_type == MMC_TYPE_SDIO)
+ reg |= SDHCI_TIMING_ADJUST_SDIO_MODE;
+ else
+ reg &= ~SDHCI_TIMING_ADJUST_SDIO_MODE;
+ sdhci_writel(host, reg, phy_regs->timing_adj);
+
+ if (emmc_phy_slow_mode(host, timing))
+ goto phy_init;
+
+ /*
+ * Set preferred ZNR and ZPR value
+ * The ZNR and ZPR value vary between different boards.
+ * Define them both in sdhci-xenon-emmc-phy.h.
+ */
+ reg = sdhci_readl(host, phy_regs->pad_ctrl2);
+ reg &= ~((SDHCI_ZNR_MASK << SDHCI_ZNR_SHIFT) | SDHCI_ZPR_MASK);
+ reg |= ((params->znr << SDHCI_ZNR_SHIFT) | params->zpr);
+ sdhci_writel(host, reg, phy_regs->pad_ctrl2);
+
+ /*
+ * When setting EMMC_PHY_FUNC_CONTROL register,
+ * SD clock should be disabled
+ */
+ reg = sdhci_readl(host, SDHCI_CLOCK_CONTROL);
+ reg &= ~SDHCI_CLOCK_CARD_EN;
+ sdhci_writew(host, reg, SDHCI_CLOCK_CONTROL);
+
+ reg = sdhci_readl(host, phy_regs->func_ctrl);
+ if ((timing == MMC_TIMING_UHS_DDR50) ||
+ (timing == MMC_TIMING_MMC_HS400) ||
+ (timing == MMC_TIMING_MMC_DDR52))
+ reg |= (SDHCI_DQ_DDR_MODE_MASK << SDHCI_DQ_DDR_MODE_SHIFT) |
+ SDHCI_CMD_DDR_MODE;
+ else
+ reg &= ~((SDHCI_DQ_DDR_MODE_MASK << SDHCI_DQ_DDR_MODE_SHIFT) |
+ SDHCI_CMD_DDR_MODE);
+
+ if (timing == MMC_TIMING_MMC_HS400)
+ reg &= ~SDHCI_DQ_ASYNC_MODE;
+ else
+ reg |= SDHCI_DQ_ASYNC_MODE;
+ sdhci_writel(host, reg, phy_regs->func_ctrl);
+
+ /* Enable bus clock */
+ reg = sdhci_readl(host, SDHCI_CLOCK_CONTROL);
+ reg |= SDHCI_CLOCK_CARD_EN;
+ sdhci_writew(host, reg, SDHCI_CLOCK_CONTROL);
+
+ if (timing == MMC_TIMING_MMC_HS400)
+ /* Hardware team recommend a value for HS400 */
+ sdhci_writel(host, SDHCI_LOGIC_TIMING_VALUE,
+ phy_regs->logic_timing_adj);
+ else
+ __emmc_phy_disable_data_strobe(host);
+
+phy_init:
+ emmc_phy_init(host);
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ dev_dbg(mmc_dev(host->mmc), "eMMC PHY setting completes\n");
+}
+
+static int emmc_phy_parse_param_dt(struct sdhci_host *host,
+ struct device_node *np,
+ struct emmc_phy_params *params)
+{
+ u32 value;
+
+ if (of_property_read_bool(np, "marvell,xenon-phy-slow-mode"))
+ params->slow_mode = true;
+ else
+ params->slow_mode = false;
+
+ if (!of_property_read_u32(np, "marvell,xenon-phy-znr", &value))
+ params->znr = value & SDHCI_ZNR_MASK;
+ else
+ params->znr = SDHCI_ZNR_DEF_VALUE;
+
+ if (!of_property_read_u32(np, "marvell,xenon-phy-zpr", &value))
+ params->zpr = value & SDHCI_ZPR_MASK;
+ else
+ params->zpr = SDHCI_ZPR_DEF_VALUE;
+
+ if (!of_property_read_u32(np, "marvell,xenon-phy-nr-success-tun",
+ &value))
+ params->nr_tun_times = value & SDHCI_TUN_CONSECUTIVE_TIMES_MASK;
+ else
+ params->nr_tun_times = SDHCI_TUN_CONSECUTIVE_TIMES;
+
+ if (!of_property_read_u32(np, "marvell,xenon-phy-tun-step-divider",
+ &value))
+ params->tun_step_divider = value & 0xFF;
+ else
+ params->tun_step_divider = SDHCI_TUNING_STEP_DIVIDER;
+
+ return 0;
+}
+
+/*
+ * Setting PHY when card is working in High Speed Mode.
+ * HS400 set data strobe line.
+ * HS200/SDR104 set tuning config to prepare for tuning.
+ */
+static int xenon_hs_delay_adj(struct sdhci_host *host)
+{
+ int ret = 0;
+
+ if (WARN_ON(host->clock <= SDHCI_DEFAULT_SDCLK_FREQ))
+ return -EINVAL;
+
+ if (host->timing == MMC_TIMING_MMC_HS400) {
+ emmc_phy_strobe_delay_adj(host);
+ return 0;
+ }
+
+ if ((host->timing == MMC_TIMING_MMC_HS200) ||
+ (host->timing == MMC_TIMING_UHS_SDR104)) {
+ ret = emmc_phy_config_tuning(host);
+ if (!ret)
+ return 0;
+ }
+
+ /*
+ * DDR Mode requires driver to scan Sampling Fixed Delay Line,
+ * to find out a perfect operation sampling point.
+ * It is hard to implement such a scan in host driver since initiating
+ * commands by host driver is not safe.
+ * Thus so far just keep PHY Sampling Fixed Delay in default value
+ * in DDR mode.
+ *
+ * If any timing issue occrus in DDR mode on Marvell products,
+ * please contact maintainer to ask for internal support in Marvell.
+ */
+ if ((host->timing == MMC_TIMING_MMC_DDR52) ||
+ (host->timing == MMC_TIMING_UHS_DDR50))
+ dev_warn(mmc_dev(host->mmc), "Timing issue might occur in DDR mode\n");
+ return ret;
+}
+
+/*
+ * Adjust PHY setting.
+ * PHY setting should be adjusted when SDCLK frequency, Bus Width
+ * or Speed Mode is changed.
+ * Addtional config are required when card is working in High Speed mode,
+ * after leaving Legacy Mode.
+ */
+int xenon_phy_adj(struct sdhci_host *host, struct mmc_ios *ios)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
+ int ret = 0;
+
+ if (!host->clock) {
+ priv->clock = 0;
+ return 0;
+ }
+
+ /*
+ * The timing, frequency or bus width is changed,
+ * better to set eMMC PHY based on current setting
+ * and adjust Xenon SDHC delay.
+ */
+ if ((host->clock == priv->clock) &&
+ (ios->bus_width == priv->bus_width) &&
+ (ios->timing == priv->timing))
+ return 0;
+
+ emmc_phy_set(host, ios->timing);
+
+ /* Update the record */
+ priv->bus_width = ios->bus_width;
+
+ /* Skip temp stages from HS200 to HS400 */
+ if (temp_stage_hs200_to_hs400(host, priv))
+ return 0;
+
+ /* Skip temp stages from HS400 t0 HS200 */
+ if (temp_stage_hs400_to_h200(host, priv))
+ return 0;
+
+ priv->timing = ios->timing;
+ priv->clock = host->clock;
+
+ /* Legacy mode is a special case */
+ if (ios->timing == MMC_TIMING_LEGACY)
+ return 0;
+
+ if (host->clock > SDHCI_DEFAULT_SDCLK_FREQ)
+ ret = xenon_hs_delay_adj(host);
+ return ret;
+}
+
+static int add_xenon_phy(struct device_node *np, struct sdhci_host *host,
+ const char *phy_name)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
+ int i, ret;
+
+ for (i = 0; i < NR_PHY_TYPES; i++) {
+ if (!strcmp(phy_name, phy_types[i])) {
+ priv->phy_type = i;
+ break;
+ }
+ }
+ if (i == NR_PHY_TYPES) {
+ dev_err(mmc_dev(host->mmc),
+ "Unable to determine PHY name %s. Use default eMMC 5.1 PHY\n",
+ phy_name);
+ priv->phy_type = EMMC_5_1_PHY;
+ }
+
+ ret = alloc_emmc_phy(priv);
+ if (ret)
+ return ret;
+
+ return emmc_phy_parse_param_dt(host, np, priv->phy_params);
+}
+
+int xenon_phy_parse_dt(struct device_node *np, struct sdhci_host *host)
+{
+ const char *phy_type = NULL;
+
+ if (!of_property_read_string(np, "marvell,xenon-phy-type", &phy_type))
+ return add_xenon_phy(np, host, phy_type);
+
+ dev_info(mmc_dev(host->mmc), "Fail to get Xenon PHY type. Use default eMMC 5.1 PHY\n");
+ return add_xenon_phy(np, host, "emmc 5.1 phy");
+}
diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c
index c71439fbc308..0347de533777 100644
--- a/drivers/mmc/host/sdhci-xenon.c
+++ b/drivers/mmc/host/sdhci-xenon.c
@@ -244,6 +244,7 @@ static void xenon_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
spin_unlock_irqrestore(&host->lock, flags);
sdhci_set_ios(mmc, ios);
+ xenon_phy_adj(host, ios);
if (host->clock > SDHCI_DEFAULT_SDCLK_FREQ) {
spin_lock_irqsave(&host->lock, flags);
@@ -481,7 +482,7 @@ static int xenon_probe_dt(struct platform_device *pdev)
}
priv->tuning_count = tuning_count;
- return err;
+ return xenon_phy_parse_dt(np, host);
}
static int xenon_sdhc_probe(struct sdhci_host *host)
diff --git a/drivers/mmc/host/sdhci-xenon.h b/drivers/mmc/host/sdhci-xenon.h
index d50cd663a265..86b5d2b1f1aa 100644
--- a/drivers/mmc/host/sdhci-xenon.h
+++ b/drivers/mmc/host/sdhci-xenon.h
@@ -23,8 +23,19 @@
#define SDHCI_SLOT_ENABLE_SHIFT 0
#define SDHCI_SYS_EXT_OP_CTRL 0x010C
+#define SDHCI_MASK_CMD_CONFLICT_ERROR BIT(8)
+
+#define SDHCI_SLOT_OP_STATUS_CTRL 0x0128
+
+#define SDHCI_TUN_CONSECUTIVE_TIMES_SHIFT 16
+#define SDHCI_TUN_CONSECUTIVE_TIMES_MASK 0x7
+#define SDHCI_TUN_CONSECUTIVE_TIMES 0x4
+#define SDHCI_TUNING_STEP_SHIFT 12
+#define SDHCI_TUNING_STEP_MASK 0xF
+#define SDHCI_TUNING_STEP_DIVIDER BIT(6)
#define SDHCI_SLOT_EMMC_CTRL 0x0130
+#define SDHCI_ENABLE_DATA_STROBE BIT(24)
#define SDHCI_EMMC_VCCQ_MASK 0x3
#define SDHCI_EMMC_VCCQ_1_8V 0x1
#define SDHCI_EMMC_VCCQ_3_3V 0x3
@@ -33,11 +44,17 @@
/* retuning compatible */
#define SDHCI_RETUNING_COMPATIBLE 0x1
+#define SDHCI_SLOT_EXT_PRESENT_STATE 0x014C
+#define SDHCI_DLL_LOCK_STATE 0x1
+
+#define SDHCI_SLOT_DLL_CUR_DLY_VAL 0x0150
+
/* Tuning Parameter */
#define SDHCI_TMR_RETUN_NO_PRESENT 0xF
#define SDHCI_DEF_TUNING_COUNT 0x9
#define SDHCI_DEFAULT_SDCLK_FREQ (400000)
+#define SDHCI_LOWEST_SDCLK_FREQ (100000)
/* Xenon specific Mode Select value */
#define SDHCI_XENON_CTRL_HS200 0x5
@@ -65,6 +82,28 @@ struct sdhci_xenon_priv {
* initialization completes.
*/
unsigned int init_card_type;
+
+ /*
+ * The bus_width, timing, and clock fields in below
+ * record the current ios setting of Xenon SDHC.
+ * Driver will adjust PHY setting if any change to
+ * ios affects PHY timing.
+ */
+ unsigned char bus_width;
+ unsigned char timing;
+ unsigned int clock;
+
+ int phy_type;
+ /*
+ * Contains board-specific PHY parameters
+ * passed from device tree.
+ */
+ void *phy_params;
+ struct xenon_emmc_phy_regs *emmc_phy_regs;
};
+
+int xenon_phy_adj(struct sdhci_host *host, struct mmc_ios *ios);
+int xenon_phy_parse_dt(struct device_node *np,
+ struct sdhci_host *host);
#endif
--
git-series 0.9.1
^ permalink raw reply related
* [PATCH v4 07/12] mmc: sdhci-xenon: Add Marvell Xenon SDHC core functionality
From: Gregory CLEMENT @ 2016-12-13 17:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.67d726f70f6bd48d38a2023513f2711080bc66c8.1481651244.git-series.gregory.clement@free-electrons.com>
From: Hu Ziji <huziji@marvell.com>
Add Xenon eMMC/SD/SDIO host controller core functionality.
Add Xenon specific intialization process.
Add Xenon specific mmc_host_ops APIs.
Add Xenon specific register definitions.
Add CONFIG_MMC_SDHCI_XENON support in drivers/mmc/host/Kconfig.
Marvell Xenon SDHC conforms to SD Physical Layer Specification
Version 3.01 and is designed according to the guidelines provided
in the SD Host Controller Standard Specification Version 3.00.
Signed-off-by: Hu Ziji <huziji@marvell.com>
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
MAINTAINERS | 1 +-
drivers/mmc/host/Kconfig | 9 +-
drivers/mmc/host/Makefile | 3 +-
drivers/mmc/host/sdhci-xenon.c | 612 ++++++++++++++++++++++++++++++++++-
drivers/mmc/host/sdhci-xenon.h | 70 ++++-
5 files changed, 695 insertions(+)
create mode 100644 drivers/mmc/host/sdhci-xenon.c
create mode 100644 drivers/mmc/host/sdhci-xenon.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 850a0afb0c8d..bb33286aeb48 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7608,6 +7608,7 @@ MARVELL XENON MMC/SD/SDIO HOST CONTROLLER DRIVER
M: Ziji Hu <huziji@marvell.com>
L: linux-mmc at vger.kernel.org
S: Supported
+F: drivers/mmc/host/sdhci-xenon*
F: Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt
MATROX FRAMEBUFFER DRIVER
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 5274f503a39a..85a53623526a 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -798,3 +798,12 @@ config MMC_SDHCI_BRCMSTB
Broadcom STB SoCs.
If unsure, say Y.
+
+config MMC_SDHCI_XENON
+ tristate "Marvell Xenon eMMC/SD/SDIO SDHCI driver"
+ depends on MMC_SDHCI && MMC_SDHCI_PLTFM
+ help
+ This selects Marvell Xenon eMMC/SD/SDIO SDHCI.
+ If you have a machine with integrated Marvell Xenon SDHC IP,
+ say Y or M here.
+ If unsure, say N.
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index e2bdaaf43184..75eaf743486c 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -80,3 +80,6 @@ obj-$(CONFIG_MMC_SDHCI_BRCMSTB) += sdhci-brcmstb.o
ifeq ($(CONFIG_CB710_DEBUG),y)
CFLAGS-cb710-mmc += -DDEBUG
endif
+
+obj-$(CONFIG_MMC_SDHCI_XENON) += sdhci-xenon-driver.o
+sdhci-xenon-driver-y += sdhci-xenon.o
diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c
new file mode 100644
index 000000000000..c71439fbc308
--- /dev/null
+++ b/drivers/mmc/host/sdhci-xenon.c
@@ -0,0 +1,612 @@
+/*
+ * Driver for Marvell Xenon SDHC as a platform device
+ *
+ * Copyright (C) 2016 Marvell, All Rights Reserved.
+ *
+ * Author: Hu Ziji <huziji@marvell.com>
+ * Date: 2016-8-24
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * Inspired by Jisheng Zhang <jszhang@marvell.com>
+ * Special thanks to Video BG4 project team.
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#include "sdhci-pltfm.h"
+#include "sdhci-xenon.h"
+
+static int enable_xenon_internal_clk(struct sdhci_host *host)
+{
+ u32 reg;
+ u8 timeout;
+
+ reg = sdhci_readl(host, SDHCI_CLOCK_CONTROL);
+ reg |= SDHCI_CLOCK_INT_EN;
+ sdhci_writel(host, reg, SDHCI_CLOCK_CONTROL);
+ /* Wait max 20 ms */
+ timeout = 20;
+ while (!((reg = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
+ & SDHCI_CLOCK_INT_STABLE)) {
+ if (timeout == 0) {
+ pr_err("%s: Internal clock never stabilised.\n",
+ mmc_hostname(host->mmc));
+ return -ETIMEDOUT;
+ }
+ timeout--;
+ mdelay(1);
+ }
+
+ return 0;
+}
+
+/* Set SDCLK-off-while-idle */
+static void xenon_set_sdclk_off_idle(struct sdhci_host *host,
+ unsigned char sdhc_id, bool enable)
+{
+ u32 reg;
+ u32 mask;
+
+ reg = sdhci_readl(host, SDHCI_SYS_OP_CTRL);
+ /* Get the bit shift basing on the SDHC index */
+ mask = (0x1 << (SDHCI_SDCLK_IDLEOFF_ENABLE_SHIFT + sdhc_id));
+ if (enable)
+ reg |= mask;
+ else
+ reg &= ~mask;
+
+ sdhci_writel(host, reg, SDHCI_SYS_OP_CTRL);
+}
+
+/* Enable/Disable the Auto Clock Gating function */
+static void xenon_set_acg(struct sdhci_host *host, bool enable)
+{
+ u32 reg;
+
+ reg = sdhci_readl(host, SDHCI_SYS_OP_CTRL);
+ if (enable)
+ reg &= ~SDHCI_AUTO_CLKGATE_DISABLE_MASK;
+ else
+ reg |= SDHCI_AUTO_CLKGATE_DISABLE_MASK;
+ sdhci_writel(host, reg, SDHCI_SYS_OP_CTRL);
+}
+
+/* Enable this SDHC */
+static void xenon_enable_sdhc(struct sdhci_host *host,
+ unsigned char sdhc_id)
+{
+ u32 reg;
+
+ reg = sdhci_readl(host, SDHCI_SYS_OP_CTRL);
+ reg |= (BIT(sdhc_id) << SDHCI_SLOT_ENABLE_SHIFT);
+ sdhci_writel(host, reg, SDHCI_SYS_OP_CTRL);
+
+ /*
+ * Manually set the flag which all the card types require,
+ * including SD, eMMC, SDIO
+ */
+ host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
+}
+
+/* Disable this SDHC */
+static void xenon_disable_sdhc(struct sdhci_host *host,
+ unsigned char sdhc_id)
+{
+ u32 reg;
+
+ reg = sdhci_readl(host, SDHCI_SYS_OP_CTRL);
+ reg &= ~(BIT(sdhc_id) << SDHCI_SLOT_ENABLE_SHIFT);
+ sdhci_writel(host, reg, SDHCI_SYS_OP_CTRL);
+}
+
+/* Enable Parallel Transfer Mode */
+static void xenon_enable_sdhc_parallel_tran(struct sdhci_host *host,
+ unsigned char sdhc_id)
+{
+ u32 reg;
+
+ reg = sdhci_readl(host, SDHCI_SYS_EXT_OP_CTRL);
+ reg |= BIT(sdhc_id);
+ sdhci_writel(host, reg, SDHCI_SYS_EXT_OP_CTRL);
+}
+
+static void xenon_sdhc_tuning_setup(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
+ u32 reg;
+
+ /* Disable the Re-Tuning Request functionality */
+ reg = sdhci_readl(host, SDHCI_SLOT_RETUNING_REQ_CTRL);
+ reg &= ~SDHCI_RETUNING_COMPATIBLE;
+ sdhci_writel(host, reg, SDHCI_SLOT_RETUNING_REQ_CTRL);
+
+ /* Disable the Re-tuning Event Signal Enable */
+ reg = sdhci_readl(host, SDHCI_SIGNAL_ENABLE);
+ reg &= ~SDHCI_INT_RETUNE;
+ sdhci_writel(host, reg, SDHCI_SIGNAL_ENABLE);
+
+ /* Force to use Tuning Mode 1 */
+ host->tuning_mode = SDHCI_TUNING_MODE_1;
+ /* Set re-tuning period */
+ host->tuning_count = 1 << (priv->tuning_count - 1);
+}
+
+/*
+ * Operations inside struct sdhci_ops
+ */
+/* Recover the Register Setting cleared during SOFTWARE_RESET_ALL */
+static void sdhci_xenon_reset_exit(struct sdhci_host *host,
+ unsigned char sdhc_id, u8 mask)
+{
+ /* Only SOFTWARE RESET ALL will clear the register setting */
+ if (!(mask & SDHCI_RESET_ALL))
+ return;
+
+ /* Disable tuning request and auto-retuning again */
+ xenon_sdhc_tuning_setup(host);
+
+ xenon_set_acg(host, true);
+
+ xenon_set_sdclk_off_idle(host, sdhc_id, false);
+}
+
+static void sdhci_xenon_reset(struct sdhci_host *host, u8 mask)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
+
+ sdhci_reset(host, mask);
+ sdhci_xenon_reset_exit(host, priv->sdhc_id, mask);
+}
+
+/*
+ * Xenon defines different values for HS200 and HS400
+ * in Host_Control_2
+ */
+static void xenon_set_uhs_signaling(struct sdhci_host *host,
+ unsigned int timing)
+{
+ u16 ctrl_2;
+
+ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ /* Select Bus Speed Mode for host */
+ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+ if (timing == MMC_TIMING_MMC_HS200)
+ ctrl_2 |= SDHCI_XENON_CTRL_HS200;
+ else if (timing == MMC_TIMING_UHS_SDR104)
+ ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
+ else if (timing == MMC_TIMING_UHS_SDR12)
+ ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
+ else if (timing == MMC_TIMING_UHS_SDR25)
+ ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
+ else if (timing == MMC_TIMING_UHS_SDR50)
+ ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
+ else if ((timing == MMC_TIMING_UHS_DDR50) ||
+ (timing == MMC_TIMING_MMC_DDR52))
+ ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
+ else if (timing == MMC_TIMING_MMC_HS400)
+ ctrl_2 |= SDHCI_XENON_CTRL_HS400;
+ sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+}
+
+static const struct sdhci_ops sdhci_xenon_ops = {
+ .set_clock = sdhci_set_clock,
+ .set_bus_width = sdhci_set_bus_width,
+ .reset = sdhci_xenon_reset,
+ .set_uhs_signaling = xenon_set_uhs_signaling,
+ .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+};
+
+static const struct sdhci_pltfm_data sdhci_xenon_pdata = {
+ .ops = &sdhci_xenon_ops,
+ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
+ SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
+ SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
+};
+
+/*
+ * Xenon Specific Operations in mmc_host_ops
+ */
+static void xenon_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
+ unsigned long flags;
+ u32 reg;
+
+ /*
+ * HS400/HS200/eMMC HS doesn't have Preset Value register.
+ * However, sdhci_set_ios will read HS400/HS200 Preset register.
+ * Disable Preset Value register for HS400/HS200.
+ * eMMC HS with preset_enabled set will trigger a bug in
+ * get_preset_value().
+ */
+ spin_lock_irqsave(&host->lock, flags);
+ if ((ios->timing == MMC_TIMING_MMC_HS400) ||
+ (ios->timing == MMC_TIMING_MMC_HS200) ||
+ (ios->timing == MMC_TIMING_MMC_HS)) {
+ host->preset_enabled = false;
+ host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
+
+ reg = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ reg &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
+ sdhci_writew(host, reg, SDHCI_HOST_CONTROL2);
+ } else {
+ host->quirks2 &= ~SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
+ }
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ sdhci_set_ios(mmc, ios);
+
+ if (host->clock > SDHCI_DEFAULT_SDCLK_FREQ) {
+ spin_lock_irqsave(&host->lock, flags);
+ xenon_set_sdclk_off_idle(host, priv->sdhc_id, true);
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
+}
+
+static int xenon_emmc_signal_voltage_switch(struct mmc_host *mmc,
+ struct mmc_ios *ios)
+{
+ unsigned char voltage = ios->signal_voltage;
+ struct sdhci_host *host = mmc_priv(mmc);
+ unsigned char voltage_code;
+ u32 ctrl;
+
+ if ((voltage == MMC_SIGNAL_VOLTAGE_330) ||
+ (voltage == MMC_SIGNAL_VOLTAGE_180)) {
+ if (voltage == MMC_SIGNAL_VOLTAGE_330)
+ voltage_code = SDHCI_EMMC_VCCQ_3_3V;
+ else if (voltage == MMC_SIGNAL_VOLTAGE_180)
+ voltage_code = SDHCI_EMMC_VCCQ_1_8V;
+
+ /*
+ * This host is for eMMC, XENON self-defined
+ * eMMC control register should be accessed
+ * instead of Host Control 2
+ */
+ ctrl = sdhci_readl(host, SDHCI_SLOT_EMMC_CTRL);
+ ctrl &= ~SDHCI_EMMC_VCCQ_MASK;
+ ctrl |= voltage_code;
+ sdhci_writel(host, ctrl, SDHCI_SLOT_EMMC_CTRL);
+
+ /* There is no standard to determine this waiting period */
+ usleep_range(1000, 2000);
+
+ /* Check whether io voltage switch is done */
+ ctrl = sdhci_readl(host, SDHCI_SLOT_EMMC_CTRL);
+ ctrl &= SDHCI_EMMC_VCCQ_MASK;
+ /*
+ * This bit is set only when regulator feeds back
+ * the voltage switch results to Xenon SDHC.
+ * However, in actaul implementation, regulator might not
+ * provide this feedback.
+ * Thus we shall not rely on this bit to determine
+ * if switch failed.
+ * If the bit is not set, just throw a message.
+ * Besides, error code should not be returned.
+ */
+ if (ctrl != voltage_code)
+ dev_info(mmc_dev(mmc), "fail to detect eMMC signal voltage stable\n");
+ return 0;
+ }
+
+ dev_err(mmc_dev(mmc), "Unsupported signal voltage: %d\n", voltage);
+ return -EINVAL;
+}
+
+static int xenon_start_signal_voltage_switch(struct mmc_host *mmc,
+ struct mmc_ios *ios)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
+
+ /*
+ * Before SD/SDIO set signal voltage, SD bus clock should be
+ * disabled. However, sdhci_set_clock will also disable the Internal
+ * clock in mmc_set_signal_voltage().
+ * If Internal clock is disabled, the 3.3V/1.8V bit can not be updated.
+ * Thus here manually enable internal clock.
+ *
+ * After switch completes, it is unnecessary to disable internal clock,
+ * since keeping internal clock active obeys SD spec.
+ */
+ enable_xenon_internal_clk(host);
+
+ if (priv->init_card_type == MMC_TYPE_MMC)
+ return xenon_emmc_signal_voltage_switch(mmc, ios);
+
+ return sdhci_start_signal_voltage_switch(mmc, ios);
+}
+
+/*
+ * Update card type.
+ * priv->init_card_type will be used in PHY timing adjustment.
+ */
+static void xenon_init_card(struct mmc_host *mmc, struct mmc_card *card)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
+
+ /* Update card type*/
+ priv->init_card_type = card->type;
+}
+
+static int xenon_execute_tuning(struct mmc_host *mmc, u32 opcode)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+
+ if (host->timing == MMC_TIMING_UHS_DDR50)
+ return 0;
+
+ return sdhci_execute_tuning(mmc, opcode);
+}
+
+static void xenon_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
+ u32 reg;
+ u8 sdhc_id = priv->sdhc_id;
+
+ sdhci_enable_sdio_irq(mmc, enable);
+
+ if (enable) {
+ /*
+ * Set SDIO Card Inserted indication
+ * to enable detecting SDIO async irq.
+ */
+ reg = sdhci_readl(host, SDHCI_SYS_CFG_INFO);
+ reg |= (1 << (sdhc_id + SDHCI_SLOT_TYPE_SDIO_SHIFT));
+ sdhci_writel(host, reg, SDHCI_SYS_CFG_INFO);
+ } else {
+ /* Clear SDIO Card Inserted indication */
+ reg = sdhci_readl(host, SDHCI_SYS_CFG_INFO);
+ reg &= ~(1 << (sdhc_id + SDHCI_SLOT_TYPE_SDIO_SHIFT));
+ sdhci_writel(host, reg, SDHCI_SYS_CFG_INFO);
+ }
+}
+
+static void xenon_replace_mmc_host_ops(struct sdhci_host *host)
+{
+ host->mmc_host_ops.set_ios = xenon_set_ios;
+ host->mmc_host_ops.start_signal_voltage_switch =
+ xenon_start_signal_voltage_switch;
+ host->mmc_host_ops.init_card = xenon_init_card;
+ host->mmc_host_ops.execute_tuning = xenon_execute_tuning;
+ host->mmc_host_ops.enable_sdio_irq = xenon_enable_sdio_irq;
+}
+
+/*
+ * Parse child node in Xenon DT.
+ * Search for the following item(s):
+ * - eMMC card type
+ */
+static int xenon_child_node_of_parse(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct sdhci_host *host = platform_get_drvdata(pdev);
+ struct mmc_host *mmc = host->mmc;
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
+ struct device_node *child;
+ int nr_child;
+
+ priv->init_card_type = SDHCI_CARD_TYPE_UNKNOWN;
+
+ nr_child = of_get_child_count(np);
+ if (!nr_child)
+ return 0;
+
+ for_each_child_of_node(np, child) {
+ if (of_device_is_compatible(child, "mmc-card")) {
+ priv->init_card_type = MMC_TYPE_MMC;
+ mmc->caps |= MMC_CAP_NONREMOVABLE;
+
+ /*
+ * Force to clear BUS_TEST to
+ * skip bus_test_pre and bus_test_post
+ */
+ mmc->caps &= ~MMC_CAP_BUS_WIDTH_TEST;
+ mmc->caps2 |= MMC_CAP2_HC_ERASE_SZ |
+ MMC_CAP2_PACKED_CMD |
+ MMC_CAP2_NO_SD |
+ MMC_CAP2_NO_SDIO;
+ }
+ }
+
+ return 0;
+}
+
+static int xenon_probe_dt(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct sdhci_host *host = platform_get_drvdata(pdev);
+ struct mmc_host *mmc = host->mmc;
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
+ int err;
+ u32 sdhc_id, nr_sdhc;
+ u32 tuning_count;
+
+ /* Standard MMC property */
+ err = mmc_of_parse(mmc);
+ if (err)
+ return err;
+
+ /* Standard SDHCI property */
+ sdhci_get_of_property(pdev);
+
+ /*
+ * Xenon Specific property:
+ * init_card_type: check whether this SDHC is for eMMC
+ * sdhc-id: the index of current SDHC.
+ * Refer to SDHCI_SYS_CFG_INFO register
+ * tun-count: the interval between re-tuning
+ */
+ /* Parse child node, including checking emmc type */
+ err = xenon_child_node_of_parse(pdev);
+ if (err)
+ return err;
+
+ priv->sdhc_id = 0x0;
+ if (!of_property_read_u32(np, "marvell,xenon-sdhc-id", &sdhc_id)) {
+ nr_sdhc = sdhci_readl(host, SDHCI_SYS_CFG_INFO);
+ nr_sdhc &= SDHCI_NR_SUPPORTED_SLOT_MASK;
+ if (unlikely(sdhc_id > nr_sdhc)) {
+ dev_err(mmc_dev(mmc), "SDHC Index %d exceeds Number of SDHCs %d\n",
+ sdhc_id, nr_sdhc);
+ return -EINVAL;
+ }
+ }
+
+ tuning_count = SDHCI_DEF_TUNING_COUNT;
+ if (!of_property_read_u32(np, "marvell,xenon-tun-count",
+ &tuning_count)) {
+ if (unlikely(tuning_count >= SDHCI_TMR_RETUN_NO_PRESENT)) {
+ dev_err(mmc_dev(mmc), "Wrong Re-tuning Count. Set default value %d\n",
+ SDHCI_DEF_TUNING_COUNT);
+ tuning_count = SDHCI_DEF_TUNING_COUNT;
+ }
+ }
+ priv->tuning_count = tuning_count;
+
+ return err;
+}
+
+static int xenon_sdhc_probe(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
+ u8 sdhc_id = priv->sdhc_id;
+
+ /* Enable SDHC */
+ xenon_enable_sdhc(host, sdhc_id);
+
+ /* Enable ACG */
+ xenon_set_acg(host, true);
+
+ /* Enable Parallel Transfer Mode */
+ xenon_enable_sdhc_parallel_tran(host, sdhc_id);
+
+ /* Set tuning functionality of this SDHC */
+ xenon_sdhc_tuning_setup(host);
+
+ return 0;
+}
+
+static void xenon_sdhc_remove(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
+ u8 sdhc_id = priv->sdhc_id;
+
+ /* disable SDHC */
+ xenon_disable_sdhc(host, sdhc_id);
+}
+
+static int sdhci_xenon_probe(struct platform_device *pdev)
+{
+ struct sdhci_pltfm_host *pltfm_host;
+ struct sdhci_host *host;
+ struct sdhci_xenon_priv *priv;
+ int err;
+
+ host = sdhci_pltfm_init(pdev, &sdhci_xenon_pdata,
+ sizeof(struct sdhci_xenon_priv));
+ if (IS_ERR(host))
+ return PTR_ERR(host);
+
+ pltfm_host = sdhci_priv(host);
+ priv = sdhci_pltfm_priv(pltfm_host);
+
+ xenon_set_acg(host, false);
+
+ /*
+ * Link Xenon specific mmc_host_ops function,
+ * to replace standard ones in sdhci_ops.
+ */
+ xenon_replace_mmc_host_ops(host);
+
+ pltfm_host->clk = devm_clk_get(&pdev->dev, "core");
+ if (IS_ERR(pltfm_host->clk)) {
+ err = PTR_ERR(pltfm_host->clk);
+ dev_err(&pdev->dev, "Failed to setup input clk: %d\n", err);
+ goto free_pltfm;
+ }
+ err = clk_prepare_enable(pltfm_host->clk);
+ if (err)
+ goto free_pltfm;
+
+ err = xenon_probe_dt(pdev);
+ if (err)
+ goto err_clk;
+
+ err = xenon_sdhc_probe(host);
+ if (err)
+ goto err_clk;
+
+ err = sdhci_add_host(host);
+ if (err)
+ goto remove_sdhc;
+
+ return 0;
+
+remove_sdhc:
+ xenon_sdhc_remove(host);
+err_clk:
+ clk_disable_unprepare(pltfm_host->clk);
+free_pltfm:
+ sdhci_pltfm_free(pdev);
+ return err;
+}
+
+static int sdhci_xenon_remove(struct platform_device *pdev)
+{
+ struct sdhci_host *host = platform_get_drvdata(pdev);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xFFFFFFFF);
+
+ xenon_sdhc_remove(host);
+
+ sdhci_remove_host(host, dead);
+
+ clk_disable_unprepare(pltfm_host->clk);
+
+ sdhci_pltfm_free(pdev);
+
+ return 0;
+}
+
+static const struct of_device_id sdhci_xenon_dt_ids[] = {
+ { .compatible = "marvell,armada-7000-sdhci",},
+ { .compatible = "marvell,armada-3700-sdhci",},
+ {}
+};
+MODULE_DEVICE_TABLE(of, sdhci_xenon_dt_ids);
+
+static struct platform_driver sdhci_xenon_driver = {
+ .driver = {
+ .name = "xenon-sdhci",
+ .of_match_table = sdhci_xenon_dt_ids,
+ .pm = &sdhci_pltfm_pmops,
+ },
+ .probe = sdhci_xenon_probe,
+ .remove = sdhci_xenon_remove,
+};
+
+module_platform_driver(sdhci_xenon_driver);
+
+MODULE_DESCRIPTION("SDHCI platform driver for Marvell Xenon SDHC");
+MODULE_AUTHOR("Hu Ziji <huziji@marvell.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/sdhci-xenon.h b/drivers/mmc/host/sdhci-xenon.h
new file mode 100644
index 000000000000..d50cd663a265
--- /dev/null
+++ b/drivers/mmc/host/sdhci-xenon.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 Marvell, All Rights Reserved.
+ *
+ * Author: Hu Ziji <huziji@marvell.com>
+ * Date: 2016-8-24
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ */
+#ifndef SDHCI_XENON_H_
+#define SDHCI_XENON_H_
+
+
+/* Register Offset of Xenon SDHC self-defined register */
+#define SDHCI_SYS_CFG_INFO 0x0104
+#define SDHCI_SLOT_TYPE_SDIO_SHIFT 24
+#define SDHCI_NR_SUPPORTED_SLOT_MASK 0x7
+
+#define SDHCI_SYS_OP_CTRL 0x0108
+#define SDHCI_AUTO_CLKGATE_DISABLE_MASK BIT(20)
+#define SDHCI_SDCLK_IDLEOFF_ENABLE_SHIFT 8
+#define SDHCI_SLOT_ENABLE_SHIFT 0
+
+#define SDHCI_SYS_EXT_OP_CTRL 0x010C
+
+#define SDHCI_SLOT_EMMC_CTRL 0x0130
+#define SDHCI_EMMC_VCCQ_MASK 0x3
+#define SDHCI_EMMC_VCCQ_1_8V 0x1
+#define SDHCI_EMMC_VCCQ_3_3V 0x3
+
+#define SDHCI_SLOT_RETUNING_REQ_CTRL 0x0144
+/* retuning compatible */
+#define SDHCI_RETUNING_COMPATIBLE 0x1
+
+/* Tuning Parameter */
+#define SDHCI_TMR_RETUN_NO_PRESENT 0xF
+#define SDHCI_DEF_TUNING_COUNT 0x9
+
+#define SDHCI_DEFAULT_SDCLK_FREQ (400000)
+
+/* Xenon specific Mode Select value */
+#define SDHCI_XENON_CTRL_HS200 0x5
+#define SDHCI_XENON_CTRL_HS400 0x6
+
+/* Indicate Card Type is not clear yet */
+#define SDHCI_CARD_TYPE_UNKNOWN 0xF
+
+struct sdhci_xenon_priv {
+ unsigned char tuning_count;
+ /* idx of SDHC */
+ u8 sdhc_id;
+
+ /*
+ * eMMC/SD/SDIO require different PHY settings or
+ * voltage control. It's necessary for Xenon driver to
+ * recognize card type during, or even before initialization.
+ * However, mmc_host->card is not available yet at that time.
+ * This field records the card type during init.
+ * For eMMC, it is updated in dt parse. For SD/SDIO, it is
+ * updated in xenon_init_card().
+ *
+ * It is only valid during initialization after it is updated.
+ * Do not access this variable in normal transfers after
+ * initialization completes.
+ */
+ unsigned int init_card_type;
+};
+
+#endif
--
git-series 0.9.1
^ permalink raw reply related
* [PATCH v4 06/12] dt: bindings: Add bindings for Marvell Xenon SD Host Controller
From: Gregory CLEMENT @ 2016-12-13 17:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.67d726f70f6bd48d38a2023513f2711080bc66c8.1481651244.git-series.gregory.clement@free-electrons.com>
From: Hu Ziji <huziji@marvell.com>
Marvell Xenon SDHC can support eMMC/SD/SDIO.
Add Xenon-specific properties.
Also add properties for Xenon PHY setting.
Signed-off-by: Hu Ziji <huziji@marvell.com>
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt | 197 +++++++-
MAINTAINERS | 1 +-
2 files changed, 198 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt
diff --git a/Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt b/Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt
new file mode 100644
index 000000000000..c7589f8d4e3e
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt
@@ -0,0 +1,197 @@
+Marvell Xenon SDHCI Controller device tree bindings
+This file documents differences between the core mmc properties
+described by mmc.txt and the properties used by the Xenon implementation.
+
+Multiple SDHCs might be put into a single Xenon IP, to save size and cost.
+Each SDHC is independent and owns independent resources, such as register sets,
+clock and PHY.
+Each SDHC should have an independent device tree node.
+
+Required Properties:
+- compatible: should be one of the following
+ - "marvell,armada-3700-sdhci": For controllers on Armada-3700 SOC.
+ Must provide a second register area and marvell,pad-type.
+ - "marvell,armada-7000-sdhci": For controllers on Armada 7K/8K SOC.
+
+- clocks:
+ Array of clocks required for SDHC.
+ Require at least input clock for Xenon IP core.
+
+- clock-names:
+ Array of names corresponding to clocks property.
+ The input clock for Xenon IP core should be named as "core".
+
+- reg:
+ * For "marvell,armada-3700-sdhci", two register areas.
+ The first one for Xenon IP register. The second one for the Armada 3700 SOC
+ PHY PAD Voltage Control register.
+ Please follow the examples with compatible "marvell,armada-3700-sdhci"
+ in below.
+ Please also check property marvell,pad-type in below.
+
+ * For other compatible strings, one register area for Xenon IP.
+
+Optional Properties:
+- mmc-card:
+ mmc-card child node must be provided when current SDHC is for eMMC.
+ Xenon SDHC often can support both SD and eMMC. This child node indicates that
+ current SDHC is for eMMC card. Thus Xenon eMMC specific configuration and
+ operations can be enabled prior to eMMC init sequence.
+ Please refer to Documentation/devicetree/bindings/mmc/mmc-card.txt.
+ This child node should not be set if current Xenon SDHC is for SD/SDIO.
+
+- bus-width:
+ When 8-bit data bus width is in use for eMMC, this property should be
+ explicitly provided and set as 8.
+ It is optional when data bus width is 4-bit or 1-bit.
+
+- mmc-ddr-1_8v:
+ Select this property when eMMC HS DDR is supported on SDHC side.
+
+- mmc-hs400-1_8v:
+ Select this property when eMMC HS400 is supported on SDHC side.
+
+- no-1-8-v:
+ Select this property when 1.8V signaling voltage supply is unavailable.
+ When this property is enabled, both mmc-ddr-1_8v and mmc-hs400-1_8v should be
+ cleared.
+
+- marvell,xenon-sdhc-id:
+ Indicate the corresponding bit index of current SDHC in
+ SDHC System Operation Control Register Bit[7:0].
+ Set/clear the corresponding bit to enable/disable current SDHC.
+ If Xenon IP contains only one SDHC, this property is optional.
+
+- marvell,xenon-phy-type:
+ Xenon support mutilple types of PHYs.
+ To select eMMC 5.1 PHY, set:
+ marvell,xenon-phy-type = "emmc 5.1 phy"
+ eMMC 5.1 PHY is the default choice if this property is not provided.
+ To select eMMC 5.0 PHY, set:
+ marvell,xenon-phy-type = "emmc 5.0 phy"
+
+ All those types of PHYs can support eMMC, SD and SDIO.
+ Please note that this property only presents the type of PHY.
+ It doesn't stand for the entire SDHC type or property.
+ For example, "emmc 5.1 phy" doesn't mean that this Xenon SDHC only supports
+ eMMC 5.1.
+
+- marvell,xenon-phy-znr:
+ Set PHY ZNR value.
+ Only available for eMMC PHY 5.1 and eMMC PHY 5.0.
+ Valid range = [0:0x1F].
+ ZNR is set as 0xF by default if this property is not provided.
+
+- marvell,xenon-phy-zpr:
+ Set PHY ZPR value.
+ Only available for eMMC PHY 5.1 and eMMC PHY 5.0.
+ Valid range = [0:0x1F].
+ ZPR is set as 0xF by default if this property is not provided.
+
+- marvell,xenon-phy-nr-success-tun:
+ Set the number of required consecutive successful sampling points used to
+ identify a valid sampling window, in tuning process.
+ Valid range = [1:7].
+ Set as 0x4 by default if this property is not provided.
+
+- marvell,xenon-phy-tun-step-divider:
+ Set the divider for calculating TUN_STEP.
+ Set as 64 by default if this property is not provided.
+
+- marvell,xenon-phy-slow-mode:
+ If this property is selected, transfers will bypass PHY.
+ Only available when bus frequency lower than 55MHz in SDR mde.
+ Disabled by default. Please only try this property if timing issues always
+ occur with PHY enabled in eMMC HS SDR, SD SDR12, SD SDR25, SD SDR50 mode.
+
+- marvell,xenon-tun-count:
+ Xenon SDHC SOC usually doesn't provide re-tuning counter in
+ Capabilities Register 3 Bit[11:8].
+ This property provides the re-tuning counter.
+ If this property is not set, default re-tuning counter will
+ be set as 0x9 in driver.
+
+- marvell,pad-type:
+ Type of Armada 3700 SOC PHY PAD Voltage Controller register.
+ Only valid when "marvell,armada-3700-sdhci" is selected.
+ Two types: "sd" and "fixed-1-8v".
+ If "sd" is slected, SOC PHY PAD is set as 3.3V at the beginning and is
+ switched to 1.8V when SD in UHS-I.
+ If "fixed-1-8v" is slected, SOC PHY PAD is fixed 1.8V, such as for eMMC.
+ Please follow the examples with compatible "marvell,armada-3700-sdhci"
+ in below.
+
+Example:
+- For eMMC:
+
+ sdhci at aa0000 {
+ compatible = "marvell,armada-7000-sdhci";
+ reg = <0xaa0000 0x1000>;
+ interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>
+ clocks = <&emmc_clk>;
+ clock-names = "core";
+ bus-width = <8>;
+ mmc-ddr-1_8v;
+ mmc-hs400-1_8v;
+ marvell,xenon-sdhc-id = <0>;
+ marvell,xenon-phy-type = "emmc 5.1 phy";
+ marvell,xenon-tun-count = <11>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ mmccard: mmccard at 0 {
+ compatible = "mmc-card";
+ reg = <0>;
+ };
+ };
+
+- For SD/SDIO:
+
+ sdhci at ab0000 {
+ compatible = "marvell,armada-7000-sdhci";
+ reg = <0xab0000 0x1000>;
+ interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>
+ vqmmc-supply = <&sd_regulator>;
+ clocks = <&sdclk>;
+ clock-names = "core";
+ bus-width = <4>;
+ marvell,xenon-tun-count = <9>;
+ };
+
+- For eMMC with compatible "marvell,armada-3700-sdhci":
+
+ sdhci at aa0000 {
+ compatible = "marvell,armada-3700-sdhci";
+ reg = <0xaa0000 0x1000>,
+ <phy_addr 0x4>;
+ interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>
+ clocks = <&emmcclk>;
+ clock-names = "core";
+ bus-width = <8>;
+ mmc-ddr-1_8v;
+ mmc-hs400-1_8v;
+
+ marvell,pad-type = "fixed-1-8v";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ mmccard: mmccard at 0 {
+ compatible = "mmc-card";
+ reg = <0>;
+ };
+ };
+
+- For SD/SDIO with compatible "marvell,armada-3700-sdhci":
+
+ sdhci at ab0000 {
+ compatible = "marvell,armada-3700-sdhci";
+ reg = <0xab0000 0x1000>,
+ <phy_addr 0x4>;
+ interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>
+ vqmmc-supply = <&sd_regulator>;
+ clocks = <&sdclk>;
+ clock-names = "core";
+ bus-width = <4>;
+
+ marvell,pad-type = "sd";
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index 1a5c4c30ea24..850a0afb0c8d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7608,6 +7608,7 @@ MARVELL XENON MMC/SD/SDIO HOST CONTROLLER DRIVER
M: Ziji Hu <huziji@marvell.com>
L: linux-mmc at vger.kernel.org
S: Supported
+F: Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt
MATROX FRAMEBUFFER DRIVER
L: linux-fbdev at vger.kernel.org
--
git-series 0.9.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox