* [PATCH RESEND v2 0/4] clk/exynos convert clock IDs to macros
From: Andrzej Hajda @ 2014-02-24 13:22 UTC (permalink / raw)
To: linux-arm-kernel
Cc: Andrzej Hajda, Tomasz Figa, Kukjin Kim, Mike Turquette,
Kyungmin Park, moderated list:OPEN FIRMWARE AND...,
moderated list:ARM/S5P EXYNOS AR...
Hi,
This patch set converts dts files to use macros instead
of magic numbers or enums to describe clock bindings.
The patch set is rebased on the latest kgene/for-next branch.
The patches are generated by script.
Many clocks I have verified by hand.
I have also tested it successfully on exynos4 based board.
This is the 2nd version of the patchset.
Changes:
- corrected devicetree mailing list,
- added comments to include/dt-bindings/clock/exynos4.h for
clocks present only in particular chip,
- added tab alignement in headers,
- added comment to CLK_NR_CLKS,
- added copyright headers,
- split long lines in dts,
- corrected example in bindings/clock/exynos5250-clock.txt, to point
appropriate clocks.
Regards
Andrzej
Andrzej Hajda (4):
ARM: dts: exynos4: convert magic numbers to macros in clock bindings
ARM: dts: exynos5250: convert magic numbers to macros in clock
bindings
ARM: dts: exynos5420: convert magic numbers to macros in clock
bindings
ARM: dts: exynos5440: convert magic numbers to macros in clock
bindings
.../devicetree/bindings/clock/exynos4-clock.txt | 259 +--------------------
.../devicetree/bindings/clock/exynos5250-clock.txt | 163 +------------
.../devicetree/bindings/clock/exynos5420-clock.txt | 184 +--------------
.../devicetree/bindings/clock/exynos5440-clock.txt | 45 +---
arch/arm/boot/dts/exynos4.dtsi | 73 +++---
arch/arm/boot/dts/exynos4210.dtsi | 9 +-
arch/arm/boot/dts/exynos4x12.dtsi | 34 +--
arch/arm/boot/dts/exynos5250.dtsi | 105 +++++----
arch/arm/boot/dts/exynos5420.dtsi | 95 ++++----
arch/arm/boot/dts/exynos5440.dtsi | 33 +--
10 files changed, 207 insertions(+), 793 deletions(-)
--
1.8.3.2
^ permalink raw reply
* Re: [PATCH RFC v8 5/5] dma: mpc512x: register for device tree channel lookup
From: Andy Shevchenko @ 2014-02-24 13:08 UTC (permalink / raw)
To: Alexander Popov
Cc: Gerhard Sittig, Dan Williams, Vinod Koul, Lars-Peter Clausen,
Arnd Bergmann, Anatolij Gustschin,
linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ,
dmaengine-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1393240172-18769-6-git-send-email-a13xp0p0v88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
On Mon, 2014-02-24 at 15:09 +0400, Alexander Popov wrote:
> From: Gerhard Sittig <gsi-ynQEQJNshbs@public.gmane.org>
>
> register the controller for device tree based lookup of DMA channels
> (non-fatal for backwards compatibility with older device trees) and
> provide the '#dma-cells' property in the shared mpc5121.dtsi file
>
> Signed-off-by: Gerhard Sittig <gsi-ynQEQJNshbs@public.gmane.org>
> [ a13xp0p0v88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org: resolve little patch conflict and put
> MPC512x DMA controller bindings document to a separate patch ]
> ---
> arch/powerpc/boot/dts/mpc5121.dtsi | 1 +
> drivers/dma/mpc512x_dma.c | 21 ++++++++++++++++++---
> 2 files changed, 19 insertions(+), 3 deletions(-)
>
> diff --git a/arch/powerpc/boot/dts/mpc5121.dtsi b/arch/powerpc/boot/dts/mpc5121.dtsi
> index 2c0e155..7f9d14f 100644
> --- a/arch/powerpc/boot/dts/mpc5121.dtsi
> +++ b/arch/powerpc/boot/dts/mpc5121.dtsi
> @@ -498,6 +498,7 @@
> compatible = "fsl,mpc5121-dma";
> reg = <0x14000 0x1800>;
> interrupts = <65 0x8>;
> + #dma-cells = <1>;
> };
> };
>
> diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
> index 8f504cb..d9f8740 100644
> --- a/drivers/dma/mpc512x_dma.c
> +++ b/drivers/dma/mpc512x_dma.c
> @@ -52,6 +52,7 @@
> #include <linux/of_address.h>
> #include <linux/of_device.h>
> #include <linux/of_irq.h>
> +#include <linux/of_dma.h>
> #include <linux/of_platform.h>
>
> #include <linux/random.h>
> @@ -1018,11 +1019,23 @@ static int mpc_dma_probe(struct platform_device *op)
> /* Register DMA engine */
> dev_set_drvdata(dev, mdma);
> retval = dma_async_device_register(dma);
> - if (retval) {
> - devm_free_irq(dev, mdma->irq, mdma);
> - irq_dispose_mapping(mdma->irq);
> + if (retval)
> + goto out_irq;
> +
> + /* register with OF helpers for DMA lookups (nonfatal) */
> + if (dev->of_node) {
> + retval = of_dma_controller_register(dev->of_node,
> + of_dma_xlate_by_chan_id,
> + mdma);
> + if (retval)
> + dev_warn(dev, "could not register for OF lookup\n");
> }
>
> + return 0;
> +
> +out_irq:
> + devm_free_irq(dev, mdma->irq, mdma);
Something wrong either with devm_request_irq() or you don't need to call
devm_free_irq() explicitly. Once we already try to discuss this earlier
in this mailing list with Lars-Peter(?), though there were no solution
how to keep devm_*_irq usability.
> + irq_dispose_mapping(mdma->irq);
> return retval;
> }
>
> @@ -1031,6 +1044,8 @@ static int mpc_dma_remove(struct platform_device *op)
> struct device *dev = &op->dev;
> struct mpc_dma *mdma = dev_get_drvdata(dev);
>
> + if (dev->of_node)
> + of_dma_controller_free(dev->of_node);
> dma_async_device_unregister(&mdma->dma);
> devm_free_irq(dev, mdma->irq, mdma);
> irq_dispose_mapping(mdma->irq);
--
Andy Shevchenko <andriy.shevchenko-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
Intel Finland Oy
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH 2/2] ARM: u300: switch SSP/SPI clock name to "SSPCLK"
From: Linus Walleij @ 2014-02-24 12:57 UTC (permalink / raw)
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Arnd Bergmann,
Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: Mark Brown, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
Pawel Moll, Russell King, Linus Walleij
As noted in recent discussions the name of the core clock for
the PL022 derived SPI blocks is erroneously named in the
U300 device tree. The kernel doesn't currently use the name,
but may do so soon so let use rename all these clocks in
accordance with the name given in the PL022 TRM (ARM DDI 0194G).
Signed-off-by: Linus Walleij <linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
arch/arm/boot/dts/ste-u300.dts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/ste-u300.dts b/arch/arm/boot/dts/ste-u300.dts
index a9da4800daf0..6fe688e9e4da 100644
--- a/arch/arm/boot/dts/ste-u300.dts
+++ b/arch/arm/boot/dts/ste-u300.dts
@@ -457,7 +457,7 @@
interrupt-parent = <&vica>;
interrupts = <23>;
clocks = <&spi_clk>, <&spi_clk>;
- clock-names = "apb_pclk", "spi_clk";
+ clock-names = "SSPCLK", "apb_pclk";
dmas = <&dmac 27 &dmac 28>;
dma-names = "tx", "rx";
num-cs = <3>;
--
1.8.5.3
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* Re: [PATCHv2 03/16] Documentation: dt: add OMAP iommu bindings
From: Florian Vaussard @ 2014-02-24 12:57 UTC (permalink / raw)
To: Tony Lindgren, iommu, devicetree
Cc: Suman Anna, Joerg Roedel, Laurent Pinchart, linux-omap,
linux-arm-kernel
In-Reply-To: <1392315347-32967-4-git-send-email-s-anna@ti.com>
Hi,
On 02/13/2014 07:15 PM, Suman Anna wrote:
> From: Florian Vaussard <florian.vaussard@epfl.ch>
>
> This patch adds the iommu bindings for all OMAP2+ SoCs. Apart from
> the standard bindings used by OMAP peripherals, this patch uses a
> 'dma-window' (already used by Tegra SMMU) and adds two OMAP custom
> bindings - 'ti,#tlb-entries' and 'ti,iommu-bus-err-back'.
>
> Signed-off-by: Florian Vaussard <florian.vaussard@epfl.ch>
> [s-anna@ti.com: split bindings document, add dra7 and bus error back]
> Signed-off-by: Suman Anna <s-anna@ti.com>
> ---
> .../devicetree/bindings/iommu/ti,omap-iommu.txt | 28 ++++++++++++++++++++++
> 1 file changed, 28 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/iommu/ti,omap-iommu.txt
>
> diff --git a/Documentation/devicetree/bindings/iommu/ti,omap-iommu.txt b/Documentation/devicetree/bindings/iommu/ti,omap-iommu.txt
> new file mode 100644
> index 0000000..116492d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iommu/ti,omap-iommu.txt
> @@ -0,0 +1,28 @@
> +OMAP2+ IOMMU
> +
> +Required properties:
> +- compatible : Should be one of,
> + "ti,omap2-iommu" for OMAP2/OMAP3 IOMMU instances
> + "ti,omap4-iommu" for OMAP4/OMAP5 IOMMU instances
> + "ti,dra7-iommu" for DRA7xx IOMMU instances
> +- ti,hwmods : Name of the hwmod associated with the IOMMU instance
> +- reg : Address space for the configuration registers
> +- interrupts : Interrupt specifier for the IOMMU instance
> +- dma-window : IOVA start address and length
> +
> +Optional properties:
> +- ti,#tlb-entries : Number of entries in the translation look-aside buffer.
> + Should be either 8 or 32 (default: 32)
> +- ti,iommu-bus-err-back : Indicates the IOMMU instance supports throwing
> + back a bus error response on MMU faults.
> +
> +Example:
> + /* OMAP3 ISP MMU */
> + mmu_isp: mmu@480bd400 {
> + compatible = "ti,omap2-iommu";
> + reg = <0x480bd400 0x80>;
> + interrupts = <24>;
> + ti,hwmods = "mmu_isp";
> + ti,#tlb-entries = <8>;
> + dma-window = <0 0xfffff000>;
> + };
>
Any comments on this binding?
Regards,
Florian
^ permalink raw reply
* [PATCH 1/2] ARM: ux500: switch SSP/SPI clock name to "SSPCLK"
From: Linus Walleij @ 2014-02-24 12:56 UTC (permalink / raw)
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Arnd Bergmann,
Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: Mark Brown, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
Pawel Moll, Russell King, Linus Walleij
As noted in recent discussions the name of the core clock for
the PL022 derived SPI blocks is erroneously named in the
Ux500 device trees. The kernel doesn't currently use the name,
but may do so soon so let use rename all these clocks in
accordance with the name given in the PL022 TRM (ARM DDI 0194G).
Signed-off-by: Linus Walleij <linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
arch/arm/boot/dts/ste-dbx5x0.dtsi | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/arch/arm/boot/dts/ste-dbx5x0.dtsi b/arch/arm/boot/dts/ste-dbx5x0.dtsi
index e0853ea02df2..e41eedca3ce3 100644
--- a/arch/arm/boot/dts/ste-dbx5x0.dtsi
+++ b/arch/arm/boot/dts/ste-dbx5x0.dtsi
@@ -705,7 +705,7 @@
#address-cells = <1>;
#size-cells = <0>;
clocks = <&prcc_kclk 3 1>, <&prcc_pclk 3 1>;
- clock-names = "ssp0clk", "apb_pclk";
+ clock-names = "SSPCLK", "apb_pclk";
dmas = <&dma 8 0 0x2>, /* Logical - DevToMem */
<&dma 8 0 0x0>; /* Logical - MemToDev */
dma-names = "rx", "tx";
@@ -718,7 +718,7 @@
#address-cells = <1>;
#size-cells = <0>;
clocks = <&prcc_kclk 3 2>, <&prcc_pclk 3 2>;
- clock-names = "ssp1clk", "apb_pclk";
+ clock-names = "SSPCLK", "apb_pclk";
dmas = <&dma 9 0 0x2>, /* Logical - DevToMem */
<&dma 9 0 0x0>; /* Logical - MemToDev */
dma-names = "rx", "tx";
@@ -732,7 +732,7 @@
#size-cells = <0>;
/* Same clock wired to kernel and pclk */
clocks = <&prcc_pclk 2 8>, <&prcc_pclk 2 8>;
- clock-names = "spi0clk", "apb_pclk";
+ clock-names = "SSPCLK", "apb_pclk";
dmas = <&dma 0 0 0x2>, /* Logical - DevToMem */
<&dma 0 0 0x0>; /* Logical - MemToDev */
dma-names = "rx", "tx";
@@ -746,7 +746,7 @@
#size-cells = <0>;
/* Same clock wired to kernel and pclk */
clocks = <&prcc_pclk 2 2>, <&prcc_pclk 2 2>;
- clock-names = "spi1clk", "apb_pclk";
+ clock-names = "SSPCLK", "apb_pclk";
dmas = <&dma 35 0 0x2>, /* Logical - DevToMem */
<&dma 35 0 0x0>; /* Logical - MemToDev */
dma-names = "rx", "tx";
@@ -760,7 +760,7 @@
#size-cells = <0>;
/* Same clock wired to kernel and pclk */
clocks = <&prcc_pclk 2 1>, <&prcc_pclk 2 1>;
- clock-names = "spi2clk", "apb_pclk";
+ clock-names = "SSPCLK", "apb_pclk";
dmas = <&dma 33 0 0x2>, /* Logical - DevToMem */
<&dma 33 0 0x0>; /* Logical - MemToDev */
dma-names = "rx", "tx";
@@ -774,7 +774,7 @@
#size-cells = <0>;
/* Same clock wired to kernel and pclk */
clocks = <&prcc_pclk 1 7>, <&prcc_pclk 1 7>;
- clock-names = "spi3clk", "apb_pclk";
+ clock-names = "SSPCLK", "apb_pclk";
dmas = <&dma 40 0 0x2>, /* Logical - DevToMem */
<&dma 40 0 0x0>; /* Logical - MemToDev */
dma-names = "rx", "tx";
--
1.8.5.3
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* Re: [PATCH 4/7] spi: pl022: attempt to get sspclk by name
From: Linus Walleij @ 2014-02-24 12:26 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Mark Rutland,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Pawel Moll,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org, Mark Brown
In-Reply-To: <12776368.fUp5TWIUAS@wuerfel>
On Wed, Feb 12, 2014 at 5:31 PM, Arnd Bergmann <arnd-r2nGTMty4D4@public.gmane.org> wrote:
> Ok. Both ssp{0,1}clk and spi{0,1,2,3}clk /only/ appear in
> arch/arm/boot/dts/ste-dbx5x0.dtsi and are clearly a bug, so unless
> Linus Walleij has objections, I'd declare those to be bugs that
> should be fixed by changing the DT file to spi_clk.
OK I'll fix. But didn't Mark just say that the preferred name should be
SSPCLK?
Here is the PL022 TRM:
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0194g/index.html
The clock name on the silicon side is clearly "SSPCLK" so let's
stick with this.
Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v11] gpio: add a driver for the Synopsys DesignWare APB GPIO block
From: Linus Walleij @ 2014-02-24 12:20 UTC (permalink / raw)
To: delicious quinoa
Cc: Linus Walleij, linux-kernel@vger.kernel.org,
linux-gpio@vger.kernel.org, linux-doc@vger.kernel.org, Jamie Iles,
devicetree@vger.kernel.org, Mark Rutland, Grant Likely,
Rob Herring, Steffen Trumtrar, Sebastian Hesselbarth,
Heiko Stuebner, Alan Tull, Dinh Nguyen, Yves Vandervennet
In-Reply-To: <CANk1AXTnnhSnt_ayJYwDHRth44CWAwmxVA5kkbvnjqW39ssLQg@mail.gmail.com>
On Wed, Feb 12, 2014 at 5:17 PM, delicious quinoa
<delicious.quinoa@gmail.com> wrote:
> I am wondering about the change in usage of
> irq_find_mapping/irq_create_mapping. It seems like all the GPIO
> drivers that use irq domains do it the way I was doing it
It is a well known problems that the kernel contain many bad
examples. When in doubt ask for a good example to be provided.
In gpio-omap.c you will find that this is done in the probe()
path.
> (that's
> where I got the idea in the first place): irq_create_mapping is used
> in the to_irq() function. I guess this is a general direction all the
> other drivers will be encouraged to go in also?
Yes. The reason is that it should be possible to reques an IRQ
from an irqchip no matter whether the gpio_to_irq() function
was called first, as the APIs are orthogonal.
Yours,
Linus Walleij
^ permalink raw reply
* Re: [PATCH 2/2] arm/xen: Don't use xen DMA ops when the device is protected by an IOMMU
From: Stefano Stabellini @ 2014-02-24 12:19 UTC (permalink / raw)
To: Ian Campbell
Cc: Julien Grall, linux-kernel, stefano.stabellini, linux-arm-kernel,
xen-devel, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
Kumar Gala, Rob Landley, Russell King, devicetree,
gregkh@linuxfoundation.org
In-Reply-To: <1392914159.32657.18.camel@kazak.uk.xensource.com>
CC'ing Greg.
On Thu, 20 Feb 2014, Ian Campbell wrote:
> On Thu, 2014-02-20 at 16:21 +0000, Julien Grall wrote:
> > Only Xen is able to know if a device can safely avoid to use xen-swiotlb.
> > This patch introduce a new property "protected-devices" for the hypervisor
> > node which list device which the IOMMU are been correctly programmed by Xen.
> >
> > During Linux boot, Xen specific code will create an hash table which
> > contains all these devices. The hash table will be used in need_xen_dma_ops
> > to check if the Xen DMA ops needs to be used for the current device.
>
> Is it out of the question to find a field within struct device itself to
> store this e.g. in struct device_dma_parameters perhaps and avoid the
> need for a hashtable lookup.
>
> device->iommu_group might be another option, if we can create our own
> group?
I agree that a field in struct device would be ideal.
Greg, get_maintainer.pl points at you as main maintainer of device.h, do
you have an opinion on this?
^ permalink raw reply
* Re: [PATCH v2 1/2] of/gpio: Define OF_GPIO_OPEN_DRAIN and OF_GPIO_OPEN_SOURCE flags.
From: Linus Walleij @ 2014-02-24 12:11 UTC (permalink / raw)
To: David Daney
Cc: Grant Likely, Rob Herring, devicetree@vger.kernel.org,
Alexandre Courbot, linux-gpio@vger.kernel.org,
linux-kernel@vger.kernel.org, David Daney
In-Reply-To: <1392148200-5393-2-git-send-email-ddaney.cavm@gmail.com>
On Tue, Feb 11, 2014 at 8:49 PM, David Daney <ddaney.cavm@gmail.com> wrote:
> enum of_gpio_flags {
> OF_GPIO_ACTIVE_LOW = 0x1,
> + OF_GPIO_OPEN_DRAIN = 0x2,
> + OF_GPIO_OPEN_SOURCE = 0x4,
> };
BTW I think this enum shall be deleted and replaced by
#include <dt-bindings/gpio/gpio.h> and use the definition from
there.
Yours,
Linus Walleij
^ permalink raw reply
* Re: [PATCH RFC 04/10] base: power: Add generic OF-based power domain look-up
From: Ulf Hansson @ 2014-02-24 12:11 UTC (permalink / raw)
To: Tomasz Figa
Cc: Stephen Boyd, linux-pm@vger.kernel.org, Mark Rutland, devicetree,
linux-samsung-soc, Russell King, Pawel Moll, Len Brown,
Greg Kroah-Hartman, Tomasz Figa, Ian Campbell, Rafael J. Wysocki,
linux-kernel@vger.kernel.org, Rob Herring,
Bartlomiej Zolnierkiewicz, Kukjin Kim, Pavel Machek, Kumar Gala,
Stephen Warren, linux-arm-kernel@lists.infradead.org,
Kevin Hilman
In-Reply-To: <52E062D8.1060206@gmail.com>
On 23 January 2014 01:31, Tomasz Figa <tomasz.figa@gmail.com> wrote:
> Hi Stephen,
>
>
> On 23.01.2014 01:18, Stephen Boyd wrote:
>>
>> On 01/11, Tomasz Figa wrote:
>>>
>>> +
>>> +/**
>>> + * of_genpd_lock() - Lock access to of_genpd_providers list
>>> + */
>>> +static void of_genpd_lock(void)
>>> +{
>>> + mutex_lock(&of_genpd_mutex);
>>> +}
>>> +
>>> +/**
>>> + * of_genpd_unlock() - Unlock access to of_genpd_providers list
>>> + */
>>> +static void of_genpd_unlock(void)
>>> +{
>>> + mutex_unlock(&of_genpd_mutex);
>>> +}
>>
>>
>> Why do we need these functions? Can't we just call
>> mutex_lock/unlock directly?
>
>
> That would be fine as well, I guess. Just duplicated the pattern used in
> CCF, but can remove them in next version if it's found to be better.
>
>
>>
>>> +
>>> +/**
>>> + * of_genpd_add_provider() - Register a domain provider for a node
>>> + * @np: Device node pointer associated with domain provider
>>> + * @genpd_src_get: callback for decoding domain
>>> + * @data: context pointer for @genpd_src_get callback.
>>
>>
>> These look a little outdated.
>
>
> Oops, missed this.
>
>
>>
>>> + */
>>> +int of_genpd_add_provider(struct device_node *np, genpd_xlate_t xlate,
>>> + void *data)
>>> +{
>>> + struct of_genpd_provider *cp;
>>> +
>>> + cp = kzalloc(sizeof(struct of_genpd_provider), GFP_KERNEL);
>>
>>
>> Please use sizeof(*cp) instead.
>
>
> Right.
>
>
>>
>>> + if (!cp)
>>> + return -ENOMEM;
>>> +
>>> + cp->node = of_node_get(np);
>>> + cp->data = data;
>>> + cp->xlate = xlate;
>>> +
>>> + of_genpd_lock();
>>> + list_add(&cp->link, &of_genpd_providers);
>>> + of_genpd_unlock();
>>> + pr_debug("Added domain provider from %s\n", np->full_name);
>>> +
>>> + return 0;
>>> +}
>>> +EXPORT_SYMBOL_GPL(of_genpd_add_provider);
>>> +
>>
>> [...]
>>>
>>> +
>>> +/* See of_genpd_get_from_provider(). */
>>> +static struct generic_pm_domain *__of_genpd_get_from_provider(
>>> + struct of_phandle_args
>>> *genpdspec)
>>> +{
>>> + struct of_genpd_provider *provider;
>>> + struct generic_pm_domain *genpd = ERR_PTR(-ENOENT);
>>
>>
>> Can this be -EPROBE_DEFER so that we can defer probe until a
>> later time if the power domain provider hasn't registered yet?
>
>
> Yes, this could be useful. Makes me wonder why clock code (on which I based
> this code) doesn't have it done this way.
>
>
>>
>>> +
>>> + /* Check if we have such a provider in our array */
>>> + list_for_each_entry(provider, &of_genpd_providers, link) {
>>> + if (provider->node == genpdspec->np)
>>> + genpd = provider->xlate(genpdspec,
>>> provider->data);
>>> + if (!IS_ERR(genpd))
>>> + break;
>>> + }
>>> +
>>> + return genpd;
>>> +}
>>> +
>>
>> [...]
>>>
>>> +static int of_genpd_notifier_call(struct notifier_block *nb,
>>> + unsigned long event, void *data)
>>> +{
>>> + struct device *dev = data;
>>> + int ret;
>>> +
>>> + if (!dev->of_node)
>>> + return NOTIFY_DONE;
>>> +
>>> + switch (event) {
>>> + case BUS_NOTIFY_BIND_DRIVER:
>>> + ret = of_genpd_add_to_domain(dev);
>>> + break;
>>> +
>>> + case BUS_NOTIFY_UNBOUND_DRIVER:
>>> + ret = of_genpd_del_from_domain(dev);
>>> + break;
>>> +
>>> + default:
>>> + return NOTIFY_DONE;
>>> + }
>>> +
>>> + return notifier_from_errno(ret);
>>> +}
>>> +
>>> +static struct notifier_block of_genpd_notifier_block = {
>>> + .notifier_call = of_genpd_notifier_call,
>>> +};
>>> +
>>> +static int of_genpd_init(void)
>>> +{
>>> + return bus_register_notifier(&platform_bus_type,
>>> + &of_genpd_notifier_block);
>>> +}
>>> +core_initcall(of_genpd_init);
>>
>>
>> Would it be possible to call the of_genpd_add_to_domain() and
>> of_genpd_del_from_domain() functions directly in the driver core,
>> similar to how the pinctrl framework has a hook in there? That
>> way we're not relying on any initcall ordering for this.
>
>
> Hmm, the initcall here just registers a notifier, which needs to be done
> just before any driver registers. So, IMHO, current variant is safe, given
> an early enough initcall level is used.
>
> However, doing it the pinctrl way might still have an advantage of not
> relying on specific bus type, so this is worth consideration indeed. I'd
> like to hear Rafael's and Kevin's opinions on this (and other comments above
> too).
As you say; certainly there will be other bus types that we need to
support as well. For example the amba bus (drivers/amba/bus.c).
Additionally I believe similar reasons, why we added the pinctrl
handling to driver core, applies to generic power domains. So I think
we should give it a try!
Kind regards
Ulf Hansson
>
> Best regards,
> Tomasz
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
^ permalink raw reply
* Re: [PATCH v2 1/2] of/gpio: Define OF_GPIO_OPEN_DRAIN and OF_GPIO_OPEN_SOURCE flags.
From: Linus Walleij @ 2014-02-24 12:09 UTC (permalink / raw)
To: David Daney
Cc: Grant Likely, Rob Herring, devicetree@vger.kernel.org,
Alexandre Courbot, linux-gpio@vger.kernel.org,
linux-kernel@vger.kernel.org, David Daney
In-Reply-To: <1392148200-5393-2-git-send-email-ddaney.cavm@gmail.com>
On Tue, Feb 11, 2014 at 8:49 PM, David Daney <ddaney.cavm@gmail.com> wrote:
> From: David Daney <david.daney@cavium.com>
>
> When we have a GPIO pin connected to an open-drain network, we want a
> standard way of specifying this in the device tree. So we choose bit
> 1 of the flag field to indicate open drain.
Same comments as for v1...
Yours,
Linus Walleij
^ permalink raw reply
* Re: [PATCH] of/gpio: Define OF_GPIO_OPEN_DRAIN flag for Open Drain outputs.
From: Linus Walleij @ 2014-02-24 12:08 UTC (permalink / raw)
To: David Daney
Cc: Grant Likely, Rob Herring,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Alexandre Courbot,
linux-gpio-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, David Daney
In-Reply-To: <1392069908-22017-1-git-send-email-ddaney.cavm-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
On Mon, Feb 10, 2014 at 11:05 PM, David Daney <ddaney.cavm-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> From: David Daney <david.daney-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
>
> When we have a GPIO pin connected to an open-drain network, we want a
> standard way of specifying this in the device tree. So we choose bit
> 1 of the flag field to indicate open drain.
This is a good idea.
But the patch is missing two things:
- Add open source as well, as indicated.
- Add this definition to include/dt-bindings/gpio/gpio.h
- Add this *and* the missing active low property to the binding
documentation in:
Documentation/devicetree/bindings/gpio/gpio.txt
(pls help with this!)
Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 1/1] ARM: Exynos: Add generic compatible string
From: Sachin Kamat @ 2014-02-24 12:03 UTC (permalink / raw)
To: Tomasz Figa
Cc: Arnd Bergmann, linux-arm-kernel, Mark Rutland,
devicetree@vger.kernel.org, Kukjin Kim, Ian Campbell, Rob Herring,
Grant Likely, linux-samsung-soc, Olof Johansson
In-Reply-To: <53077160.5030202@samsung.com>
On 21 February 2014 21:01, Tomasz Figa <t.figa@samsung.com> wrote:
> On 21.02.2014 16:21, Tomasz Figa wrote:
>>
>> On 21.02.2014 15:48, Arnd Bergmann wrote:
>>>
>>> On Friday 21 February 2014 14:18:49 Tomasz Figa wrote:
>>>>
>>>>
>>>>> Now that we have a broader agreement on this, I think we can go
>>>>> ahead with the
>>>>> following steps as an initial approach:
>>>>> 1. Have a common machine file for both exynos4 and 5 files,
>>>>> mach-exynos-dt.c.
>>>>> 2. Introduce a generic compatible string "samsung,exynos".
>>>>> 3. Append this to the compatible property list for existing boards.
>>>>>
>>>>> If this plan looks OK, I can send across patches doing this.
>>>>>
>>>>
>>>> Looks good. I would also merge common.c with this resulting
>>>> mach-exynos-dt.c, as it would be the only user of the code there.
>>>
>>>
>>> Sounds good. While the naming is not important, I would just call the
>>> file 'exynos.c', in line with some of the other platforms we have.
>>> Both the 'mach-' and the '-dt' part of the file name are redundant.
>>>
>>> Alternatively, you could merge it all into common.c.
>>
>>
>> exynos.c sounds good to me.
>
>
> One minor thing. It might be a good idea to base on top of my PM
> consolidation part 2 series, to avoid merge conflicts:
>
> http://thread.gmane.org/gmane.linux.ports.arm.kernel/299340
>
> It should hit Kgene's tree this weekend.
Sure.
--
With warm regards,
Sachin
^ permalink raw reply
* Re: [PATCH 1/1] ARM: Exynos: Add generic compatible string
From: Sachin Kamat @ 2014-02-24 12:02 UTC (permalink / raw)
To: Tomasz Figa
Cc: Arnd Bergmann, linux-arm-kernel, Mark Rutland,
devicetree@vger.kernel.org, Kukjin Kim, Ian Campbell, Rob Herring,
Grant Likely, linux-samsung-soc, Olof Johansson
In-Reply-To: <53076F00.7000001@samsung.com>
On 21 February 2014 20:51, Tomasz Figa <t.figa@samsung.com> wrote:
> On 21.02.2014 15:48, Arnd Bergmann wrote:
>>
>> On Friday 21 February 2014 14:18:49 Tomasz Figa wrote:
>>>
>>>
>>>> Now that we have a broader agreement on this, I think we can go ahead
>>>> with the
>>>> following steps as an initial approach:
>>>> 1. Have a common machine file for both exynos4 and 5 files,
>>>> mach-exynos-dt.c.
>>>> 2. Introduce a generic compatible string "samsung,exynos".
>>>> 3. Append this to the compatible property list for existing boards.
>>>>
>>>> If this plan looks OK, I can send across patches doing this.
>>>>
>>>
>>> Looks good. I would also merge common.c with this resulting
>>> mach-exynos-dt.c, as it would be the only user of the code there.
>>
>>
>> Sounds good. While the naming is not important, I would just call the
>> file 'exynos.c', in line with some of the other platforms we have.
>> Both the 'mach-' and the '-dt' part of the file name are redundant.
>>
>> Alternatively, you could merge it all into common.c.
>
>
> exynos.c sounds good to me.
Sounds good to me too.
--
With warm regards,
Sachin
^ permalink raw reply
* Re: [PATCH 00/10] pinctrl: mvebu: remove hard-coded addresses from Dove pinctrl
From: Linus Walleij @ 2014-02-24 11:50 UTC (permalink / raw)
To: Sebastian Hesselbarth
Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
Rob Landley, Russell King, Jason Cooper, Andrew Lunn,
Gregory Clement,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-doc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <530B1CF4.2060208-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
On Mon, Feb 24, 2014 at 11:20 AM, Sebastian Hesselbarth
<sebastian.hesselbarth-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> Although, I guess instead of applying them separately, it would have
> been better to pull them from Jason's stable topic branch. But that is
> also up to you and Jason may give valuable hints on how to proceed in
> the future.
Yeah I concluded that I should take a branch pull instead, so I'm
just waiting for an indication of which branch to pull in.
Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] ASoC: cs42888: Add codec driver support
From: Mark Brown @ 2014-02-24 11:30 UTC (permalink / raw)
To: Nicolin Chen
Cc: brian.austin-jGc1dHjMKG3QT0dZR+AlfA,
Paul.Handrigan-jGc1dHjMKG3QT0dZR+AlfA,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, pawel.moll-5wv7dgnIgG8,
mark.rutland-5wv7dgnIgG8, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
galak-sgV2jX0FEOL9JmXXK+q4OQ, rob-VoJi6FS/r0vR7s880joybQ,
lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
grant.likely-QSEj5FYQhm4dnm+yROfE0A,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw
In-Reply-To: <1393224929-7555-1-git-send-email-Guangyu.Chen-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 2613 bytes --]
On Mon, Feb 24, 2014 at 02:55:29PM +0800, Nicolin Chen wrote:
> This patch adds support for the Cirrus Logic CS42888 Audio CODEC that
> has four 24-bit A/D and eight 24-bit D/A converters.
Looks generally good, some fairly small nits below.
> [ CS42888 supports both I2C and SPI control ports. As initial patch,
> this patch only adds the support for I2C. ]
> 5 files changed, 795 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/sound/cs42888.txt
> create mode 100644 sound/soc/codecs/cs42888.c
> create mode 100644 sound/soc/codecs/cs42888.h
Given that we're starting to split out separate bus drivers for the I2C
and SPI CODECs (look at the recent submissions from Lars-Peter) it'd be
good to start this off with a separate bus driver for I2C even if the
SPI one is still to be done - that way the Kconfig stuff for machine
drivers is all in place and doesn't need updating.
> + - clocks : phandle to the clock source for MCLK
> +
> + - clock-names : must contain "mclk".
These should really be lists though there's only one documented element
so it's purely a documentation update.
> + /* Disable auto-mute */
> + regmap_update_bits(cs42888->regmap, CS42888_TXCTL,
> + CS42888_TXCTL_AMUTE | CS42888_TXCTL_DAC_SZC_MASK,
> + CS42888_TXCTL_DAC_SZC_SR);
Does this interfere with the manual mute controls or is it a separate
thing? If it plays nicely with the manual controls it's probably better
to leave it enabled since it improves performance in some benchmarks
(that's why hardware tends to have the feature).
> + /*
> + * We haven't marked the chip revision as volatile due to
> + * sharing a register with the right input volume; explicitly
> + * bypass the cache to read it.
> + */
> + regcache_cache_bypass(cs42888->regmap, true);
The other option here is to just not provide a default so that the first
time it's read it goes to hardware. It doesn't make much difference
either way though.
> +static int cs42888_i2c_remove(struct i2c_client *i2c_client)
> +{
> + snd_soc_unregister_codec(&i2c_client->dev);
> + return 0;
> +}
The driver ought to disable runtime PM, the clock and the regulators here.
> + /*
> + * In case the device was put to hard reset during sleep,
> + * we need to wait 500ns here before any I2C communication
> + */
> + mdelay(5);
Do we need 500ns or 5ms?
> + regcache_sync(cs42888->regmap);
Should really check the return value here.
> + if (!IS_ERR(cs42888->clk))
> + clk_disable_unprepare(cs42888->clk);
Does the device work without MCLK?
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* [PATCH] ARM: kernel: respect device tree status of cpu nodes
From: Jürg Billeter @ 2014-02-24 11:22 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-kernel, devicetree, Jürg Billeter, linux-kernel
Skip 'disabled' cpu nodes when building the cpu logical map. This avoids
booting cpus that have been disabled in the device tree.
Signed-off-by: Jürg Billeter <j@bitron.ch>
Reviewed-by: Ben Dooks <ben.dooks@codethink.co.uk>
---
arch/arm/kernel/devtree.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c
index 739c3df..9aed299 100644
--- a/arch/arm/kernel/devtree.c
+++ b/arch/arm/kernel/devtree.c
@@ -95,6 +95,10 @@ void __init arm_dt_init_cpu_maps(void)
if (of_node_cmp(cpu->type, "cpu"))
continue;
+ /* Check if CPU is enabled */
+ if (!of_device_is_available(cpu))
+ continue;
+
pr_debug(" * %s...\n", cpu->full_name);
/*
* A device tree containing CPU nodes with missing "reg"
--
1.9.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH RFC v8 5/5] dma: mpc512x: register for device tree channel lookup
From: Alexander Popov @ 2014-02-24 11:09 UTC (permalink / raw)
To: Gerhard Sittig, Dan Williams, Vinod Koul, Lars-Peter Clausen,
Arnd Bergmann, Anatolij Gustschin, Alexander Popov,
linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ,
dmaengine-u79uwXL29TY76Z2rM5mHXA
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1393240172-18769-1-git-send-email-a13xp0p0v88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
From: Gerhard Sittig <gsi-ynQEQJNshbs@public.gmane.org>
register the controller for device tree based lookup of DMA channels
(non-fatal for backwards compatibility with older device trees) and
provide the '#dma-cells' property in the shared mpc5121.dtsi file
Signed-off-by: Gerhard Sittig <gsi-ynQEQJNshbs@public.gmane.org>
[ a13xp0p0v88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org: resolve little patch conflict and put
MPC512x DMA controller bindings document to a separate patch ]
---
arch/powerpc/boot/dts/mpc5121.dtsi | 1 +
drivers/dma/mpc512x_dma.c | 21 ++++++++++++++++++---
2 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/arch/powerpc/boot/dts/mpc5121.dtsi b/arch/powerpc/boot/dts/mpc5121.dtsi
index 2c0e155..7f9d14f 100644
--- a/arch/powerpc/boot/dts/mpc5121.dtsi
+++ b/arch/powerpc/boot/dts/mpc5121.dtsi
@@ -498,6 +498,7 @@
compatible = "fsl,mpc5121-dma";
reg = <0x14000 0x1800>;
interrupts = <65 0x8>;
+ #dma-cells = <1>;
};
};
diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
index 8f504cb..d9f8740 100644
--- a/drivers/dma/mpc512x_dma.c
+++ b/drivers/dma/mpc512x_dma.c
@@ -52,6 +52,7 @@
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
+#include <linux/of_dma.h>
#include <linux/of_platform.h>
#include <linux/random.h>
@@ -1018,11 +1019,23 @@ static int mpc_dma_probe(struct platform_device *op)
/* Register DMA engine */
dev_set_drvdata(dev, mdma);
retval = dma_async_device_register(dma);
- if (retval) {
- devm_free_irq(dev, mdma->irq, mdma);
- irq_dispose_mapping(mdma->irq);
+ if (retval)
+ goto out_irq;
+
+ /* register with OF helpers for DMA lookups (nonfatal) */
+ if (dev->of_node) {
+ retval = of_dma_controller_register(dev->of_node,
+ of_dma_xlate_by_chan_id,
+ mdma);
+ if (retval)
+ dev_warn(dev, "could not register for OF lookup\n");
}
+ return 0;
+
+out_irq:
+ devm_free_irq(dev, mdma->irq, mdma);
+ irq_dispose_mapping(mdma->irq);
return retval;
}
@@ -1031,6 +1044,8 @@ static int mpc_dma_remove(struct platform_device *op)
struct device *dev = &op->dev;
struct mpc_dma *mdma = dev_get_drvdata(dev);
+ if (dev->of_node)
+ of_dma_controller_free(dev->of_node);
dma_async_device_unregister(&mdma->dma);
devm_free_irq(dev, mdma->irq, mdma);
irq_dispose_mapping(mdma->irq);
--
1.8.4.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH RFC v8 4/5] dma: mpc512x: add device tree binding document
From: Alexander Popov @ 2014-02-24 11:09 UTC (permalink / raw)
To: Gerhard Sittig, Dan Williams, Vinod Koul, Lars-Peter Clausen,
Arnd Bergmann, Anatolij Gustschin, Alexander Popov,
linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ,
dmaengine-u79uwXL29TY76Z2rM5mHXA
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1393240172-18769-1-git-send-email-a13xp0p0v88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
From: Gerhard Sittig <gsi-ynQEQJNshbs@public.gmane.org>
introduce a device tree binding document for the MPC512x DMA controller
Signed-off-by: Gerhard Sittig <gsi-ynQEQJNshbs@public.gmane.org>
[ a13xp0p0v88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org: turn this into a separate patch ]
---
.../devicetree/bindings/dma/mpc512x-dma.txt | 55 ++++++++++++++++++++++
1 file changed, 55 insertions(+)
create mode 100644 Documentation/devicetree/bindings/dma/mpc512x-dma.txt
diff --git a/Documentation/devicetree/bindings/dma/mpc512x-dma.txt b/Documentation/devicetree/bindings/dma/mpc512x-dma.txt
new file mode 100644
index 0000000..a4867d5
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/mpc512x-dma.txt
@@ -0,0 +1,55 @@
+* Freescale MPC512x DMA Controller
+
+The DMA controller in the Freescale MPC512x SoC can move blocks of
+memory contents between memory and peripherals or memory to memory.
+
+Refer to the "Generic DMA Controller and DMA request bindings" description
+in the dma.txt file for a more detailled discussion of the binding. The
+MPC512x DMA engine binding follows the common scheme, but doesn't provide
+support for the optional channels and requests counters (those values are
+derived from the detected hardware features) and has a fixed client
+specifier length of 1 integer cell (the value is the DMA channel, since
+the DMA controller uses a fixed assignment of request lines per channel).
+
+
+DMA controller node properties:
+
+Required properties:
+- compatible: should be "fsl,mpc5121-dma"
+- reg: address and size of the DMA controller's register set
+- interrupts: interrupt spec for the DMA controller
+
+Optional properties:
+- #dma-cells: must be <1>, describes the number of integer cells
+ needed to specify the 'dmas' property in client nodes,
+ strongly recommended since common client helper code
+ uses this property
+
+Example:
+
+ dma0: dma@14000 {
+ compatible = "fsl,mpc5121-dma";
+ reg = <0x14000 0x1800>;
+ interrupts = <65 0x8>;
+ #dma-cells = <1>;
+ };
+
+
+Client node properties:
+
+Required properties:
+- dmas: list of DMA specifiers, consisting each of a handle
+ for the DMA controller and integer cells to specify
+ the channel used within the DMA controller
+- dma-names: list of identifier strings for the DMA specifiers,
+ client device driver code uses these strings to
+ have DMA channels looked up at the controller
+
+Example:
+
+ sdhc@1500 {
+ compatible = "fsl,mpc5121-sdhc";
+ /* ... */
+ dmas = <&dma0 30>;
+ dma-names = "rx-tx";
+ };
--
1.8.4.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH RFC v8 3/5] dma: of: Add common xlate function for matching by channel id
From: Alexander Popov @ 2014-02-24 11:09 UTC (permalink / raw)
To: Gerhard Sittig, Dan Williams, Vinod Koul, Lars-Peter Clausen,
Arnd Bergmann, Anatolij Gustschin, Alexander Popov,
linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ,
dmaengine-u79uwXL29TY76Z2rM5mHXA
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1393240172-18769-1-git-send-email-a13xp0p0v88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
This patch adds a new common OF dma xlate callback function which will match a
channel by it's id. The binding expects one integer argument which it will use to
lookup the channel by the id.
Unlike of_dma_simple_xlate this function is able to handle a system with
multiple DMA controllers. When registering the of dma provider with
of_dma_controller_register a pointer to the dma_device struct which is
associated with the dt node needs to passed as the data parameter.
New function will use this pointer to match only channels which belong to the
specified DMA controller.
Signed-off-by: Alexander Popov <a13xp0p0v88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
drivers/dma/of-dma.c | 35 +++++++++++++++++++++++++++++++++++
include/linux/of_dma.h | 4 ++++
2 files changed, 39 insertions(+)
diff --git a/drivers/dma/of-dma.c b/drivers/dma/of-dma.c
index e8fe9dc..d5fbeaa 100644
--- a/drivers/dma/of-dma.c
+++ b/drivers/dma/of-dma.c
@@ -218,3 +218,38 @@ struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec,
&dma_spec->args[0]);
}
EXPORT_SYMBOL_GPL(of_dma_simple_xlate);
+
+/**
+ * of_dma_xlate_by_chan_id - Translate dt property to DMA channel by channel id
+ * @dma_spec: pointer to DMA specifier as found in the device tree
+ * @of_dma: pointer to DMA controller data
+ *
+ * This function can be used as the of xlate callback for DMA driver which wants
+ * to match the channel based on the channel id. When using this xlate function
+ * the #dma-cells propety of the DMA controller dt node needs to be set to 1.
+ * The data parameter of of_dma_controller_register must be a pointer to the
+ * dma_device struct the function should match upon.
+ *
+ * Returns pointer to appropriate dma channel on success or NULL on error.
+ */
+struct dma_chan *of_dma_xlate_by_chan_id(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma)
+{
+ struct dma_device *dev = ofdma->of_dma_data;
+ struct dma_chan *chan, *candidate = NULL;
+
+ if (!dev || dma_spec->args_count != 1)
+ return NULL;
+
+ list_for_each_entry(chan, &dev->channels, device_node)
+ if (chan->chan_id == dma_spec->args[0]) {
+ candidate = chan;
+ break;
+ }
+
+ if (!candidate)
+ return NULL;
+
+ return dma_get_slave_channel(candidate);
+}
+EXPORT_SYMBOL_GPL(of_dma_xlate_by_chan_id);
diff --git a/include/linux/of_dma.h b/include/linux/of_dma.h
index ae36298..56bc026 100644
--- a/include/linux/of_dma.h
+++ b/include/linux/of_dma.h
@@ -41,6 +41,8 @@ extern struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
const char *name);
extern struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec,
struct of_dma *ofdma);
+extern struct dma_chan *of_dma_xlate_by_chan_id(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma);
#else
static inline int of_dma_controller_register(struct device_node *np,
struct dma_chan *(*of_dma_xlate)
@@ -66,6 +68,8 @@ static inline struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_s
return NULL;
}
+#define of_dma_xlate_by_chan_id NULL
+
#endif
#endif /* __LINUX_OF_DMA_H */
--
1.8.4.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH RFC v8 0/5] MPC512x DMA slave s/g support, OF DMA lookup
From: Alexander Popov @ 2014-02-24 11:09 UTC (permalink / raw)
To: Gerhard Sittig, Dan Williams, Vinod Koul, Lars-Peter Clausen,
Arnd Bergmann, Anatolij Gustschin, Alexander Popov,
linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ,
dmaengine-u79uwXL29TY76Z2rM5mHXA
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA
2013/7/14 Gerhard Sittig <gsi-ynQEQJNshbs@public.gmane.org>:
> this series
> - introduces slave s/g support (that's support for DMA transfers which
> involve peripherals in contrast to mem-to-mem transfers)
> - adds device tree based lookup support for DMA channels
> - combines floating patches and related feedback which already covered
> several aspects of what the suggested LPB driver needs, to demonstrate
> how integration might be done
> - carries Q&D SD card support to enable another DMA client during test,
> while this patch needs to get dropped upon pickup
Changes in v2:
> - re-order mpc8308 related code paths for improved readability, no
> change in behaviour, introduction of symbolic channel names here
> already
> - squash 'execute() start condition' and 'terminate all' into the
> introduction of 'slave s/g prep' and 'device control' support; refuse
> s/g lists with more than one item since slave support is operational
> yet proper s/g support is missing (can get addressed later)
> - always start transfers from software on MPC8308 as there are no
> external request lines for peripheral flow control
> - drop dt-bindings header file and symbolic channel names in OF nodes
Changes in v3 and v4:
Part 1/5:
- use #define instead of enum since individual channels don't require
special handling.
Part 2/5:
- add a flag "will_access_peripheral" to DMA transfer descriptor
according recommendations of Gerhard Sittig.
This flag is set in mpc_dma_prep_memcpy() and mpc_dma_prep_slave_sg()
and is evaluated in mpc_dma_execute() to choose a type of start for
the transfer.
- prevent descriptors of transfers which involve peripherals from
being chained together;
each of such transfers needs hardware initiated start.
- add locking while working with struct mpc_dma_chan
according recommendations of Lars-Peter Clausen.
- remove default nbytes value. Client kernel modules must set
src_maxburst and dst_maxburst fields of struct dma_slave_config (dmaengine.h).
Changes in v5:
Part 2/5:
- add and improve comments;
- improve the code moving transfer descriptors from 'queued' to 'active' list
in mpc_dma_execute();
- allow mpc_dma_prep_slave_sg() to run with non-empty 'active' list;
- take 'mdesc' back to 'free' list in case of error in mpc_dma_prep_slave_sg();
- improve checks of the transfer parameters;
- provide the default value for 'maxburst' in mpc_dma_device_control().
Changes in v6:
Part 2/5:
- remove doubtful comment;
- fix coding style issues;
- set default value for 'maxburst' to 1 which applies to most cases;
Part 3/5:
- use dma_get_slave_channel() instead of dma_request_channel()
in new function of_dma_xlate_by_chan_id() according recommendations of
Arnd Bergmann;
Part 4/5:
- set DMA_PRIVATE flag for MPC512x DMA controller since its driver relies on
of_dma_xlate_by_chan_id() which doesn't use dma_request_channel()
any more; (removed in v7)
- resolve little patch conflict;
Part 5/5:
- resolve little patch conflict;
Changes in v7:
Part 2:
- improve comment;
Part 4:
- split in two separate patches. Part 4/6 contains device tree
binding document and in part 5/6 MPC512x DMA controller is registered
for device tree channel lookup;
- remove setting DMA_PRIVATE flag for MPC512x DMA controller from part 5/6;
Changes in v8:
Part 2:
- improve comments;
- fix style issues;
Part 6:
- remove since it has become obsolete;
> known issues:
> - it's yet to get confirmed whether MPC8308 can use slave support or
> whether the DMA controller's driver shall actively reject it, the
> information that's available so far suggests that peripheral transfers
> to IP bus attached I/O is useful and shall not get blocked right away
- adding support for transfers which don't increment the RAM address or
do increment the peripheral "port's" address is easy with
this implementation; but which options of the common API
should be used for specifying such transfers?
2014/02/13 Gerhard Sittig <gsi-ynQEQJNshbs@public.gmane.org>:
> - The MPC512x DMA completely lacks a binding document, so one
> should get added.
> - The MPC8308 hardware is similar and can re-use the MPC512x
> binding, which should be stated.
> - The Linux implementation currently has no OF based channel
> lookup support, so '#dma-cells' is "a future feature". I guess
> the binding can and should already discuss the feature,
> regardless of whether all implementations support it.
Alexander Popov (3):
dma: mpc512x: reorder mpc8308 specific instructions
dma: mpc512x: add support for peripheral transfers
dma: of: Add common xlate function for matching by channel id
Gerhard Sittig (2):
dma: mpc512x: add device tree binding document
dma: mpc512x: register for device tree channel lookup
.../devicetree/bindings/dma/mpc512x-dma.txt | 55 ++++
arch/powerpc/boot/dts/mpc5121.dtsi | 1 +
drivers/dma/mpc512x_dma.c | 298 +++++++++++++++++++--
drivers/dma/of-dma.c | 35 +++
include/linux/of_dma.h | 4 +
5 files changed, 368 insertions(+), 25 deletions(-)
create mode 100644 Documentation/devicetree/bindings/dma/mpc512x-dma.txt
--
1.8.4.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 1/2] usb: dwc3: core: continue probing if usb phy library returns -ENODEV/-ENXIO
From: Roger Quadros @ 2014-02-24 11:05 UTC (permalink / raw)
To: Kishon Vijay Abraham I, Heikki Krogerus, Felipe Balbi
Cc: george.cherian, devicetree, linux-doc, linux-kernel, linux-omap,
linux-arm-kernel, linux-usb
In-Reply-To: <530B1609.8030804@ti.com>
On 02/24/2014 11:51 AM, Kishon Vijay Abraham I wrote:
> Hi Roger,
>
> On Friday 21 February 2014 05:59 PM, Roger Quadros wrote:
>> On 02/21/2014 02:25 PM, Kishon Vijay Abraham I wrote:
>>> Hi Roger,
>>>
>>> On Wednesday 19 February 2014 06:07 PM, Roger Quadros wrote:
>>>> Hi,
>>>>
>>>> On 02/12/2014 11:46 AM, Kishon Vijay Abraham I wrote:
>>>>> On Wednesday 29 January 2014 08:17 PM, Heikki Krogerus wrote:
>>>>>> Hi,
>>>>>>
>>>>>> On Tue, Jan 28, 2014 at 10:30:36AM -0600, Felipe Balbi wrote:
>>>>>>> On Tue, Jan 28, 2014 at 05:32:30PM +0200, Heikki Krogerus wrote:
>>>>>>>> On Mon, Jan 27, 2014 at 10:05:20AM -0600, Felipe Balbi wrote:
>>>>>>>> For the controller drivers the PHYs are just a resource like any
>>>>>>>> other. The controller drivers can't have any responsibility of
>>>>>>>> them. They should not care if PHY drivers are available for them or
>>>>>>>> not, or even if the PHY framework is available or not.
>>>>>>>
>>>>>>> huh? If memory isn't available you don't continue probing, right ? If
>>>>>>> your IORESOURCE_MEM is missing, you also don't continue probing, if your
>>>>>>> IRQ line is missing, you bail too. Those are also nothing but resources
>>>>>>> to the driver, what you're asking here is to treat PHY as a _different_
>>>>>>> resource; which might be fine, but we need to make sure we don't
>>>>>>> continue probing when a PHY is missing in a platform that certainly
>>>>>>> needs a PHY.
>>>>>>
>>>>>> Yes, true. In my head I was comparing the PHY only to resources like
>>>>>> gpios, clocks, dma channels, etc. that are often optional to the
>>>>>> drivers.
>>>>>>
>>>>>>>>>>> But I really want to see the argument against using no-op. As far as I
>>>>>>>>>>> could see, everybody needs a PHY driver one way or another, some
>>>>>>>>>>> platforms just haven't sent any PHY driver upstream and have their own
>>>>>>>>>>> hacked up solution to avoid using the PHY layer.
>>>>>>>>>>
>>>>>>>>>> Not true in our case. Platforms using Intel's SoCs and chip sets may
>>>>>>>>>> or may not have controllable USB PHY. Quite often they don't. The
>>>>>>>>>> Baytrails have usually ULPI PHY for USB2, but that does not mean they
>>>>>>>>>> provide any vendor specific functions or any need for a driver in any
>>>>>>>>>> case.
>>>>>>>>>
>>>>>>>>> that's different from what I heard.
>>>>>>>>
>>>>>>>> I don't know where you got that impression, but it's not true. The
>>>>>>>> Baytrail SoCs for example don't have internal USB PHYs, which means
>>>>>>>> the manufacturers using it can select what they want. So we have
>>>>>>>> boards where PHY driver(s) is needed and boards where it isn't.
>>>>>>>
>>>>>>> alright, that explains it ;-) So you have external USB2 and USB3 PHYs ?
>>>>>>> You have an external PIPE3 interface ? That's quite an achievement,
>>>>>>> kudos to your HW designers. Getting timing closure on PIPE3 is a
>>>>>>> difficult task.
>>>>>>
>>>>>> No, only the USB2 PHY is external. I'm giving you wrong information,
>>>>>> I'm sorry about that. Need to concentrate on what I'm writing.
>>>>>>
>>>>>> <snip>
>>>>>>
>>>>>>>> This is really good to get. We have some projects where we are dealing
>>>>>>>> with more embedded environments, like IVI, where the kernel should be
>>>>>>>> stripped of everything useless. Since the PHYs are autonomous, we
>>>>>>>> should be able to disable the PHY libraries/frameworks.
>>>>>>>
>>>>>>> hmmm, in that case it's a lot easier to treat. We can use
>>>>>>> ERR_PTR(-ENXIO) as an indication that the framework is disabled, or
>>>>>>> something like that.
>>>>>>>
>>>>>>> The difficult is really reliably supporting e.g. OMAP5 (which won't work
>>>>>>> without a PHY) and your BayTrail with autonomous PHYs. What can we use
>>>>>>> as an indication ?
>>>>>>
>>>>>> OMAP has it's own glue driver, so shouldn't it depend on the PHY
>>>>>> layer?
>>>>>
>>>>> right, but the PHY is connected to the dwc3 core and not to the glue.
>>>>>>
>>>>>>> I mean, I need to know that a particular platform depends on a PHY
>>>>>>> driver before I decide to return -EPROBE_DEFER or just assume the PHY
>>>>>>> isn't needed ;-)
>>>>>>
>>>>>> I don't think dwc3 (core) should care about that. The PHY layer needs
>>>>>> to tell us that. If the PHY driver that the platform depends is not
>>>>>> available yet, the PHY layer returns -EPROBE_DEFER and dwc3 ends up
>>>>>> returning -EPROBE_DEFER.
>>>>>
>>>>> I don't think the PHY layer can 'reliably' tell if PHY driver is available or
>>>>> not. Consider when the phy_provider_register fails, there is no way to know if
>>>>> PHY driver is available or not. There are a few cases where PHY layer returns
>>>>> -EPROBE_DEFER but none of them can tell for sure that PHY driver is either
>>>>> available and failed or not available at all. It would be best for us to leave
>>>>> that to the platforms if we want to be sure if the platform needs a PHY or not.
>>>>>
>>>>
>>>> Just to summarize this thread on what we need
>>>
>>> Thanks for summarizing.
>>>>
>>>> 1) dwc3 core shouldn't worry about platform specific stuff i.e. PHY needed or not.
>>>> It should be as generic as possible.
>>>>
>>>> 2) dwc3 core should continue probe even if PHY layer is not enabled, as not all platforms need it.
>>>>
>>>> 3) dwc3 core should continue probe if PHY device is not available. (-ENODEV?)
>>>>
>>>> 4) dwc3 core should error out on any error condition if PHY device is available and caused some error,
>>>> e.g. init error.
>>>>
>>>> 5) dwc3 core should return EPROBE_DEFER if PHY device is available but device driver is not yet loaded.
>>>>
>>>> 6) platform glue should do the necessary sanity checks for availability of all resources like PHY device, PHY layer, etc, before populating the dwc3 device. e.g. in OMAP5 case we could check if both usb2 and usb3 PHY
>>>> nodes are available in the DT and PHY layer is enabled, from dwc3-omap.c? In J6 case we could check that at least usb2 phy node is there for the High-Speed only controller, and so on.
>>>
>>> The PHY is connected to the dwc3 core. So I'm not sure if we should be doing
>>> checks for PHY in the glue layer.
>>
>> Sorry, I didn't get you. My reasoning was that since OMAP platform has this strict requirement of requiring
>> explicit PHY control in order to work, we must do the sanity checks in OMAP specific code and not in the dwc3 core code. It has nothing to do with how hardware is laid out.
>
> What kind of sanity check do you think can be done in OMAP code? We don't use
> any of the PHY API's in glue code. If we add the same PHY APIs in glue code it
> will be duplication of the same code without much value besides breaking the
> design guideline of the software to be modelled similar to hardware.
>
I wasn't saying about using PHY APIs in glue code, but just doing the basic sanity checks like
presence of PHY layer, the required USB PHY DT nodes and the required drivers for the platform.
> However in Kconfig of dwc3 glue we can add 'select GENERIC_PHY, select
> PHY_OMAP_USB2, select OMAP_USB3' I guess.
That won't be required if we can print to the user about the things we are missing for the device
to work.
cheers,
-roger
^ permalink raw reply
* Re: [PATCH RFC 04/10] base: power: Add generic OF-based power domain look-up
From: Philipp Zabel @ 2014-02-24 10:56 UTC (permalink / raw)
To: Tomasz Figa
Cc: linux-pm, Mark Rutland, devicetree, linux-samsung-soc,
Russell King, Pawel Moll, Len Brown, Greg Kroah-Hartman,
Tomasz Figa, Ian Campbell, Rafael J. Wysocki, linux-kernel,
Rob Herring, Bartlomiej Zolnierkiewicz, Kukjin Kim, Pavel Machek,
Kumar Gala, Stephen Warren, linux-arm-kernel
In-Reply-To: <530A2ADF.902@gmail.com>
Hi Tomasz,
Am Sonntag, den 23.02.2014, 18:07 +0100 schrieb Tomasz Figa:
> Hi Philipp,
>
> On 19.02.2014 17:53, Philipp Zabel wrote:
> > Am Samstag, den 11.01.2014, 20:42 +0100 schrieb Tomasz Figa:
>
> [snip]
>
> >> + pd = of_genpd_get_from_provider(&pd_args);
> >> + if (IS_ERR(pd))
> >> + return PTR_ERR(pd);
> >> +
> >> + dev_dbg(dev, "adding to power domain %s\n", pd->name);
> >> +
> >> + while (1) {
> >> + ret = pm_genpd_add_device(pd, dev);
> >
> > Since pm_genpd_add_device is used here, no gpd_timing_data can be
> > provided. Do you have a plan to solve this? Should the timing data be
> > provided from the device tree?
>
> Hmm, a quick grep over kernel sources for genpd_.*_add_device
> gives just a single user of __pm_genpd_name_add_device(), with custom
> timing data:
I had added this to my work progress i.MX patches to silence the noisy
"... latency exceeded, new value ..." warnings emitted by the power
domain framework: http://patchwork.ozlabs.org/patch/320084/
[...]
> Moreover the timings used there are just defaults, which makes me wonder
> if there is any reason to specify them explicitly. Even more interesting
> is the fact that genpd code can measure those latencies itself.
>
> Do you have a particular use case for those timing data or just
> wondering? I don't think we need to implement support for them right
> away, if there is no real need to do so. The code and bindings can be
> extended later to handle them, if needed.
You are right, this is just superficial.
> As for whether DT is appropriate place to define them, I'm not quite
> sure. Stop and start latencies look like hardware parameters, but state
> save and restore are likely to be driver-specific, as it depends on
> driver code how much time it takes to save and restore needed state
> (e.g. driver with register cache will not need to do any state save), if
> I understand these timing data correctly.
I have one more, on i.MX6 I manually need to enable the clocks of
devices in the power domain during the power-up sequence so that the
reset signals can propagate.
So far, I have implemented this by registering the device clocks of
devices in the power domain with pm_clk_add and then let the genpd
power_on callback temporarily enable them using pm_clk_resume:
http://patchwork.ozlabs.org/patch/320085/
Whether this is needed seems to me to be a property of the power domain.
Do you think this is something we could add to of_genpd_add_to_domain,
depending on some flag set in struct generic_pm_domain?
I'd like to avoid having to register my own bus notifier and to deal
with ordering issues between that and of_genpd_notifier_call.
regards
Philipp
^ permalink raw reply
* Re: [PATCH RFC v1 1/3] clk: Add function to parse an arbitrary clocks list property
From: Sylwester Nawrocki @ 2014-02-24 10:43 UTC (permalink / raw)
To: Mike Turquette, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: linux-lFZ/pmaqli7XmaaqVzeoHQ, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
grant.likely-QSEj5FYQhm4dnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
galak-sgV2jX0FEOL9JmXXK+q4OQ,
kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ,
sw0312.kim-Sze3O3UU22JBDgjK7y7TUQ,
m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ,
t.figa-Sze3O3UU22JBDgjK7y7TUQ
In-Reply-To: <20140224004335.22529.74369@quantum>
On 24/02/14 01:43, Mike Turquette wrote:
[...]
>> > +/**
>> > + * of_clk_get_list_entry() - Parse and lookup a clock referenced by a device node
>> > + * @np: pointer to clock consumer node
>> > + * @list_name: name of the clock list property
>> > + * @index: index to the clock list
>> > + *
>> > + * This function parses the @list_name property and together with @index
>> > + * value indicating an entry of the list uses it to look up the struct clk
>> > + * from the registered list of clock providers.
>> > + */
>> > +struct clk *of_clk_get_list_entry(struct device_node *np,
>> > + const char *list_name, int index)
>
> Bikeshed alert: how about of_clk_get_by_property or of_clk_get_by_prop?
That sounds better to me, thanks for the suggestion.
For the next iteration I'm going to use of_clk_get_by_property() .
Regards,
Sylwester
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH v5 8/8] mtd: spi-nor: Add Freescale QuadSPI driver
From: Huang Shijie @ 2014-02-24 10:37 UTC (permalink / raw)
To: dwmw2
Cc: computersforpeace, angus.clark, lee.jones, pekon, sourav.poddar,
broonie, linux-mtd, linux-spi, linux-arm-kernel, linux-doc,
b44548, b18965, devicetree, shawn.guo, Huang Shijie
In-Reply-To: <1393238262-8622-1-git-send-email-b32955@freescale.com>
(0) What is the QuadSPI controller?
The QuadSPI(Quad Serial Peripheral Interface) acts as an interface to
one single or two external serial flash devices, each with up to 4
bidirectional data lines.
(1) The QuadSPI controller is driven by the LUT(Look-up Table) registers.
The LUT registers are a look-up-table for sequences of instructions.
A valid sequence consists of four LUT registers.
(2) The definition of the LUT register shows below:
---------------------------------------------------
| INSTR1 | PAD1 | OPRND1 | INSTR0 | PAD0 | OPRND0 |
---------------------------------------------------
There are several types of INSTRx, such as:
CMD : the SPI NOR command.
ADDR : the address for the SPI NOR command.
DUMMY : the dummy cycles needed by the SPI NOR command.
....
There are several types of PADx, such as:
PAD1 : use a singe I/O line.
PAD2 : use two I/O lines.
PAD4 : use quad I/O lines.
....
(3) Test this driver with the JFFS2 and UBIFS:
For jffs2:
-------------
#flash_eraseall /dev/mtd0
#mount -t jffs2 /dev/mtdblock0 tmp
#bonnie++ -d tmp -u 0 -s 10 -r 5
For ubifs:
-------------
#flash_eraseall /dev/mtd0
#ubiattach /dev/ubi_ctrl -m 0
#ubimkvol /dev/ubi0 -N test -m
#mount -t ubifs ubi0:test tmp
#bonnie++ -d tmp -u 0 -s 10 -r 5
Signed-off-by: Huang Shijie <b32955@freescale.com>
---
drivers/mtd/spi-nor/Kconfig | 6 +
drivers/mtd/spi-nor/Makefile | 1 +
drivers/mtd/spi-nor/fsl-quadspi.c | 1009 +++++++++++++++++++++++++++++++++++++
3 files changed, 1016 insertions(+), 0 deletions(-)
create mode 100644 drivers/mtd/spi-nor/fsl-quadspi.c
diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
index 41591af..64cfc39 100644
--- a/drivers/mtd/spi-nor/Kconfig
+++ b/drivers/mtd/spi-nor/Kconfig
@@ -4,3 +4,9 @@ config MTD_SPI_NOR_BASE
help
This is the framework for the SPI NOR which can be used by the SPI
device drivers and the SPI-NOR device driver.
+config SPI_FSL_QUADSPI
+ tristate "Freescale Quad SPI controller"
+ depends on ARCH_MXC && MTD_SPI_NOR_BASE
+ help
+ This enables support for the Quad SPI controller in master mode.
+ We only connect the NOR to this controller now.
diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
index 7dfe1f9..51f9d8b 100644
--- a/drivers/mtd/spi-nor/Makefile
+++ b/drivers/mtd/spi-nor/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_MTD_SPI_NOR_BASE) += spi-nor.o
+obj-$(CONFIG_SPI_FSL_QUADSPI) += fsl-quadspi.o
diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c
new file mode 100644
index 0000000..6dc08ed
--- /dev/null
+++ b/drivers/mtd/spi-nor/fsl-quadspi.c
@@ -0,0 +1,1009 @@
+/*
+ * Freescale QuadSPI driver.
+ *
+ * Copyright (C) 2013 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <linux/completion.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/spi-nor.h>
+
+/* The registers */
+#define QUADSPI_MCR 0x00
+#define QUADSPI_MCR_RESERVED_SHIFT 16
+#define QUADSPI_MCR_RESERVED_MASK (0xF << QUADSPI_MCR_RESERVED_SHIFT)
+#define QUADSPI_MCR_MDIS_SHIFT 14
+#define QUADSPI_MCR_MDIS_MASK (1 << QUADSPI_MCR_MDIS_SHIFT)
+#define QUADSPI_MCR_CLR_TXF_SHIFT 11
+#define QUADSPI_MCR_CLR_TXF_MASK (1 << QUADSPI_MCR_CLR_TXF_SHIFT)
+#define QUADSPI_MCR_CLR_RXF_SHIFT 10
+#define QUADSPI_MCR_CLR_RXF_MASK (1 << QUADSPI_MCR_CLR_RXF_SHIFT)
+#define QUADSPI_MCR_DDR_EN_SHIFT 7
+#define QUADSPI_MCR_DDR_EN_MASK (1 << QUADSPI_MCR_DDR_EN_SHIFT)
+#define QUADSPI_MCR_END_CFG_SHIFT 2
+#define QUADSPI_MCR_END_CFG_MASK (3 << QUADSPI_MCR_END_CFG_SHIFT)
+#define QUADSPI_MCR_SWRSTHD_SHIFT 1
+#define QUADSPI_MCR_SWRSTHD_MASK (1 << QUADSPI_MCR_SWRSTHD_SHIFT)
+#define QUADSPI_MCR_SWRSTSD_SHIFT 0
+#define QUADSPI_MCR_SWRSTSD_MASK (1 << QUADSPI_MCR_SWRSTSD_SHIFT)
+
+#define QUADSPI_IPCR 0x08
+#define QUADSPI_IPCR_SEQID_SHIFT 24
+#define QUADSPI_IPCR_SEQID_MASK (0xF << QUADSPI_IPCR_SEQID_SHIFT)
+
+#define QUADSPI_BUF0CR 0x10
+#define QUADSPI_BUF1CR 0x14
+#define QUADSPI_BUF2CR 0x18
+#define QUADSPI_BUFXCR_INVALID_MSTRID 0xe
+
+#define QUADSPI_BUF3CR 0x1c
+#define QUADSPI_BUF3CR_ALLMST_SHIFT 31
+#define QUADSPI_BUF3CR_ALLMST (1 << QUADSPI_BUF3CR_ALLMST_SHIFT)
+
+#define QUADSPI_BFGENCR 0x20
+#define QUADSPI_BFGENCR_PAR_EN_SHIFT 16
+#define QUADSPI_BFGENCR_PAR_EN_MASK (1 << (QUADSPI_BFGENCR_PAR_EN_SHIFT))
+#define QUADSPI_BFGENCR_SEQID_SHIFT 12
+#define QUADSPI_BFGENCR_SEQID_MASK (0xF << QUADSPI_BFGENCR_SEQID_SHIFT)
+
+#define QUADSPI_BUF0IND 0x30
+#define QUADSPI_BUF1IND 0x34
+#define QUADSPI_BUF2IND 0x38
+#define QUADSPI_SFAR 0x100
+
+#define QUADSPI_SMPR 0x108
+#define QUADSPI_SMPR_DDRSMP_SHIFT 16
+#define QUADSPI_SMPR_DDRSMP_MASK (7 << QUADSPI_SMPR_DDRSMP_SHIFT)
+#define QUADSPI_SMPR_FSDLY_SHIFT 6
+#define QUADSPI_SMPR_FSDLY_MASK (1 << QUADSPI_SMPR_FSDLY_SHIFT)
+#define QUADSPI_SMPR_FSPHS_SHIFT 5
+#define QUADSPI_SMPR_FSPHS_MASK (1 << QUADSPI_SMPR_FSPHS_SHIFT)
+#define QUADSPI_SMPR_HSENA_SHIFT 0
+#define QUADSPI_SMPR_HSENA_MASK (1 << QUADSPI_SMPR_HSENA_SHIFT)
+
+#define QUADSPI_RBSR 0x10c
+#define QUADSPI_RBSR_RDBFL_SHIFT 8
+#define QUADSPI_RBSR_RDBFL_MASK (0x3F << QUADSPI_RBSR_RDBFL_SHIFT)
+
+#define QUADSPI_RBCT 0x110
+#define QUADSPI_RBCT_WMRK_MASK 0x1F
+#define QUADSPI_RBCT_RXBRD_SHIFT 8
+#define QUADSPI_RBCT_RXBRD_USEIPS (0x1 << QUADSPI_RBCT_RXBRD_SHIFT)
+
+#define QUADSPI_TBSR 0x150
+#define QUADSPI_TBDR 0x154
+#define QUADSPI_SR 0x15c
+#define QUADSPI_SR_IP_ACC_SHIFT 1
+#define QUADSPI_SR_IP_ACC_MASK (0x1 << QUADSPI_SR_IP_ACC_SHIFT)
+#define QUADSPI_SR_AHB_ACC_SHIFT 2
+#define QUADSPI_SR_AHB_ACC_MASK (0x1 << QUADSPI_SR_AHB_ACC_SHIFT)
+
+#define QUADSPI_FR 0x160
+#define QUADSPI_FR_TFF_MASK 0x1
+
+#define QUADSPI_SFA1AD 0x180
+#define QUADSPI_SFA2AD 0x184
+#define QUADSPI_SFB1AD 0x188
+#define QUADSPI_SFB2AD 0x18c
+#define QUADSPI_RBDR 0x200
+
+#define QUADSPI_LUTKEY 0x300
+#define QUADSPI_LUTKEY_VALUE 0x5AF05AF0
+
+#define QUADSPI_LCKCR 0x304
+#define QUADSPI_LCKER_LOCK 0x1
+#define QUADSPI_LCKER_UNLOCK 0x2
+
+#define QUADSPI_RSER 0x164
+#define QUADSPI_RSER_TFIE (0x1 << 0)
+
+#define QUADSPI_LUT_BASE 0x310
+
+/*
+ * The definition of the LUT register shows below:
+ *
+ * ---------------------------------------------------
+ * | INSTR1 | PAD1 | OPRND1 | INSTR0 | PAD0 | OPRND0 |
+ * ---------------------------------------------------
+ */
+#define OPRND0_SHIFT 0
+#define PAD0_SHIFT 8
+#define INSTR0_SHIFT 10
+#define OPRND1_SHIFT 16
+
+/* Instruction set for the LUT register. */
+#define LUT_STOP 0
+#define LUT_CMD 1
+#define LUT_ADDR 2
+#define LUT_DUMMY 3
+#define LUT_MODE 4
+#define LUT_MODE2 5
+#define LUT_MODE4 6
+#define LUT_READ 7
+#define LUT_WRITE 8
+#define LUT_JMP_ON_CS 9
+#define LUT_ADDR_DDR 10
+#define LUT_MODE_DDR 11
+#define LUT_MODE2_DDR 12
+#define LUT_MODE4_DDR 13
+#define LUT_READ_DDR 14
+#define LUT_WRITE_DDR 15
+#define LUT_DATA_LEARN 16
+
+/*
+ * The PAD definitions for LUT register.
+ *
+ * The pad stands for the lines number of IO[0:3].
+ * For example, the Quad read need four IO lines, so you should
+ * set LUT_PAD4 which means we use four IO lines.
+ */
+#define LUT_PAD1 0
+#define LUT_PAD2 1
+#define LUT_PAD4 2
+
+/* Oprands for the LUT register. */
+#define ADDR24BIT 0x18
+#define ADDR32BIT 0x20
+
+/* Macros for constructing the LUT register. */
+#define LUT0(ins, pad, opr) \
+ (((opr) << OPRND0_SHIFT) | ((LUT_##pad) << PAD0_SHIFT) | \
+ ((LUT_##ins) << INSTR0_SHIFT))
+
+#define LUT1(ins, pad, opr) (LUT0(ins, pad, opr) << OPRND1_SHIFT)
+
+/* other macros for LUT register. */
+#define QUADSPI_LUT(x) (QUADSPI_LUT_BASE + (x) * 4)
+#define QUADSPI_LUT_NUM 64
+
+/* SEQID -- we can have 16 seqids at most. */
+#define SEQID_QUAD_READ 0
+#define SEQID_WREN 1
+#define SEQID_WRDI 2
+#define SEQID_RDSR 3
+#define SEQID_SE 4
+#define SEQID_CHIP_ERASE 5
+#define SEQID_PP 6
+#define SEQID_RDID 7
+#define SEQID_WRSR 8
+#define SEQID_RDCR 9
+#define SEQID_EN4B 10
+#define SEQID_BRWR 11
+
+enum fsl_qspi_devtype {
+ FSL_QUADSPI_VYBRID,
+ FSL_QUADSPI_IMX6SX,
+};
+
+struct fsl_qspi_devtype_data {
+ enum fsl_qspi_devtype devtype;
+ int rxfifo;
+ int txfifo;
+};
+
+static struct fsl_qspi_devtype_data vybrid_data = {
+ .devtype = FSL_QUADSPI_VYBRID,
+ .rxfifo = 128,
+ .txfifo = 64
+};
+
+static struct fsl_qspi_devtype_data imx6sx_data = {
+ .devtype = FSL_QUADSPI_IMX6SX,
+ .rxfifo = 128,
+ .txfifo = 512
+};
+
+#define FSL_QSPI_MAX_CHIP 4
+struct fsl_qspi {
+ struct mtd_info mtd[FSL_QSPI_MAX_CHIP];
+ struct spi_nor nor[FSL_QSPI_MAX_CHIP];
+ void __iomem *iobase;
+ void __iomem *ahb_base; /* Used when read from AHB bus */
+ u32 memmap_phy;
+ struct clk *clk, *clk_en;
+ struct device *dev;
+ struct completion c;
+ struct fsl_qspi_devtype_data *devtype_data;
+ u32 nor_size;
+ u32 nor_num;
+ u32 clk_rate;
+ unsigned int chip_base_addr; /* We may support two chips. */
+};
+
+static inline int is_vybrid_qspi(struct fsl_qspi *q)
+{
+ return q->devtype_data->devtype == FSL_QUADSPI_VYBRID;
+}
+
+static inline int is_imx6sx_qspi(struct fsl_qspi *q)
+{
+ return q->devtype_data->devtype == FSL_QUADSPI_IMX6SX;
+}
+
+/*
+ * An IC bug makes us to re-arrange the 32-bit data.
+ * The following chips, such as IMX6SLX, have fixed this bug.
+ */
+static inline u32 fsl_qspi_endian_xchg(struct fsl_qspi *q, u32 a)
+{
+ return is_vybrid_qspi(q) ? __swab32(a) : a;
+}
+
+static inline void fsl_qspi_unlock_lut(struct fsl_qspi *q)
+{
+ writel(QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY);
+ writel(QUADSPI_LCKER_UNLOCK, q->iobase + QUADSPI_LCKCR);
+}
+
+static inline void fsl_qspi_lock_lut(struct fsl_qspi *q)
+{
+ writel(QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY);
+ writel(QUADSPI_LCKER_LOCK, q->iobase + QUADSPI_LCKCR);
+}
+
+static irqreturn_t fsl_qspi_irq_handler(int irq, void *dev_id)
+{
+ struct fsl_qspi *q = dev_id;
+ u32 reg;
+
+ /* clear interrupt */
+ reg = readl(q->iobase + QUADSPI_FR);
+ writel(reg, q->iobase + QUADSPI_FR);
+
+ if (reg & QUADSPI_FR_TFF_MASK)
+ complete(&q->c);
+
+ dev_dbg(q->dev, "QUADSPI_FR : 0x%.8x:0x%.8x\n", q->chip_base_addr, reg);
+ return IRQ_HANDLED;
+}
+
+static void fsl_qspi_init_lut(struct fsl_qspi *q)
+{
+ void *__iomem base = q->iobase;
+ int rxfifo = q->devtype_data->rxfifo;
+ u32 lut_base;
+ u8 cmd, addrlen, dummy;
+ int i;
+
+ fsl_qspi_unlock_lut(q);
+
+ /* Clear all the LUT table */
+ for (i = 0; i < QUADSPI_LUT_NUM; i++)
+ writel(0, base + QUADSPI_LUT_BASE + i * 4);
+
+ /* Quad Read */
+ lut_base = SEQID_QUAD_READ * 4;
+
+ if (q->nor_size <= SZ_16M) {
+ cmd = OPCODE_QUAD_READ;
+ addrlen = ADDR24BIT;
+ dummy = 8;
+ } else {
+ /* use the 4-byte address */
+ cmd = OPCODE_QUAD_READ;
+ addrlen = ADDR32BIT;
+ dummy = 8;
+ }
+
+ writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
+ base + QUADSPI_LUT(lut_base));
+ writel(LUT0(DUMMY, PAD1, dummy) | LUT1(READ, PAD4, rxfifo),
+ base + QUADSPI_LUT(lut_base + 1));
+
+ /* Write enable */
+ lut_base = SEQID_WREN * 4;
+ writel(LUT0(CMD, PAD1, OPCODE_WREN), base + QUADSPI_LUT(lut_base));
+
+ /* Page Program */
+ lut_base = SEQID_PP * 4;
+
+ if (q->nor_size <= SZ_16M) {
+ cmd = OPCODE_PP;
+ addrlen = ADDR24BIT;
+ } else {
+ /* use the 4-byte address */
+ cmd = OPCODE_PP;
+ addrlen = ADDR32BIT;
+ }
+
+ writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
+ base + QUADSPI_LUT(lut_base));
+ writel(LUT0(WRITE, PAD1, 0), base + QUADSPI_LUT(lut_base + 1));
+
+ /* Read Status */
+ lut_base = SEQID_RDSR * 4;
+ writel(LUT0(CMD, PAD1, OPCODE_RDSR) | LUT1(READ, PAD1, 0x1),
+ base + QUADSPI_LUT(lut_base));
+
+ /* Erase a sector */
+ lut_base = SEQID_SE * 4;
+
+ if (q->nor_size <= SZ_16M) {
+ cmd = OPCODE_SE;
+ addrlen = ADDR24BIT;
+ } else {
+ /* use the 4-byte address */
+ cmd = OPCODE_SE;
+ addrlen = ADDR32BIT;
+ }
+
+ writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
+ base + QUADSPI_LUT(lut_base));
+
+ /* Erase the whole chip */
+ lut_base = SEQID_CHIP_ERASE * 4;
+ writel(LUT0(CMD, PAD1, OPCODE_CHIP_ERASE),
+ base + QUADSPI_LUT(lut_base));
+
+ /* READ ID */
+ lut_base = SEQID_RDID * 4;
+ writel(LUT0(CMD, PAD1, OPCODE_RDID) | LUT1(READ, PAD1, 0x8),
+ base + QUADSPI_LUT(lut_base));
+
+ /* Write Register */
+ lut_base = SEQID_WRSR * 4;
+ writel(LUT0(CMD, PAD1, OPCODE_WRSR) | LUT1(WRITE, PAD1, 0x2),
+ base + QUADSPI_LUT(lut_base));
+
+ /* Read Configuration Register */
+ lut_base = SEQID_RDCR * 4;
+ writel(LUT0(CMD, PAD1, OPCODE_RDCR) | LUT1(READ, PAD1, 0x1),
+ base + QUADSPI_LUT(lut_base));
+
+ /* Write disable */
+ lut_base = SEQID_WRDI * 4;
+ writel(LUT0(CMD, PAD1, OPCODE_WRDI), base + QUADSPI_LUT(lut_base));
+
+ /* Enter 4 Byte Mode (Micron) */
+ lut_base = SEQID_EN4B * 4;
+ writel(LUT0(CMD, PAD1, OPCODE_EN4B), base + QUADSPI_LUT(lut_base));
+
+ /* Enter 4 Byte Mode (Spansion) */
+ lut_base = SEQID_BRWR * 4;
+ writel(LUT0(CMD, PAD1, OPCODE_BRWR), base + QUADSPI_LUT(lut_base));
+
+ fsl_qspi_lock_lut(q);
+}
+
+/* Get the SEQID for the command */
+static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd)
+{
+ switch (cmd) {
+ case OPCODE_QUAD_READ:
+ return SEQID_QUAD_READ;
+ case OPCODE_WREN:
+ return SEQID_WREN;
+ case OPCODE_WRDI:
+ return SEQID_WRDI;
+ case OPCODE_RDSR:
+ return SEQID_RDSR;
+ case OPCODE_SE:
+ return SEQID_SE;
+ case OPCODE_CHIP_ERASE:
+ return SEQID_CHIP_ERASE;
+ case OPCODE_PP:
+ return SEQID_PP;
+ case OPCODE_RDID:
+ return SEQID_RDID;
+ case OPCODE_WRSR:
+ return SEQID_WRSR;
+ case OPCODE_RDCR:
+ return SEQID_RDCR;
+ case OPCODE_EN4B:
+ return SEQID_EN4B;
+ case OPCODE_BRWR:
+ return SEQID_BRWR;
+ default:
+ dev_err(q->dev, "Unsupported cmd 0x%.2x\n", cmd);
+ break;
+ }
+ return -EINVAL;
+}
+
+static int
+fsl_qspi_runcmd(struct fsl_qspi *q, u8 cmd, unsigned int addr, int len)
+{
+ void *__iomem base = q->iobase;
+ int seqid;
+ u32 reg, reg2;
+ int err;
+
+ init_completion(&q->c);
+ dev_dbg(q->dev, "to 0x%.8x:0x%.8x, len:%d, cmd:%.2x\n",
+ q->chip_base_addr, addr, len, cmd);
+
+ /* save the reg */
+ reg = readl(base + QUADSPI_MCR);
+
+ writel(q->memmap_phy + q->chip_base_addr + addr, base + QUADSPI_SFAR);
+ writel(QUADSPI_RBCT_WMRK_MASK | QUADSPI_RBCT_RXBRD_USEIPS,
+ base + QUADSPI_RBCT);
+ writel(reg | QUADSPI_MCR_CLR_RXF_MASK, base + QUADSPI_MCR);
+
+ do {
+ reg2 = readl(base + QUADSPI_SR);
+ if (reg2 & (QUADSPI_SR_IP_ACC_MASK | QUADSPI_SR_AHB_ACC_MASK)) {
+ udelay(1);
+ dev_dbg(q->dev, "The controller is busy, 0x%x\n", reg2);
+ continue;
+ }
+ break;
+ } while (1);
+
+ /* trigger the LUT now */
+ seqid = fsl_qspi_get_seqid(q, cmd);
+ writel((seqid << QUADSPI_IPCR_SEQID_SHIFT) | len, base + QUADSPI_IPCR);
+
+ /* Wait for the interrupt. */
+ err = wait_for_completion_timeout(&q->c, msecs_to_jiffies(1000));
+ if (!err) {
+ dev_err(q->dev,
+ "cmd 0x%.2x timeout, addr@%.8x, FR:0x%.8x, SR:0x%.8x\n",
+ cmd, addr, readl(base + QUADSPI_FR),
+ readl(base + QUADSPI_SR));
+ err = -ETIMEDOUT;
+ } else {
+ err = 0;
+ }
+
+ /* restore the MCR */
+ writel(reg, base + QUADSPI_MCR);
+
+ return err;
+}
+
+/* Read out the data from the QUADSPI_RBDR buffer registers. */
+static void fsl_qspi_read_data(struct fsl_qspi *q, int len, u8 *rxbuf)
+{
+ u32 tmp;
+ int i = 0;
+
+ while (len > 0) {
+ tmp = readl(q->iobase + QUADSPI_RBDR + i * 4);
+ tmp = fsl_qspi_endian_xchg(q, tmp);
+ dev_dbg(q->dev, "chip addr:0x%.8x, rcv:0x%.8x\n",
+ q->chip_base_addr, tmp);
+
+ if (len >= 4) {
+ *((u32 *)rxbuf) = tmp;
+ rxbuf += 4;
+ } else {
+ memcpy(rxbuf, &tmp, len);
+ break;
+ }
+
+ len -= 4;
+ i++;
+ }
+}
+
+/*
+ * If we have changed the content of the flash by writing or erasing,
+ * we need to invalidate the AHB buffer. If we do not do so, we may read out
+ * the wrong data. The spec tells us reset the AHB domain and Serial Flash
+ * domain at the same time.
+ */
+static inline void fsl_qspi_invalid(struct fsl_qspi *q)
+{
+ u32 reg;
+
+ reg = readl(q->iobase + QUADSPI_MCR);
+ reg |= QUADSPI_MCR_SWRSTHD_MASK | QUADSPI_MCR_SWRSTSD_MASK;
+ writel(reg, q->iobase + QUADSPI_MCR);
+
+ /*
+ * The minimum delay : 1 AHB + 2 SFCK clocks.
+ * Delay 1 us is enough.
+ */
+ udelay(1);
+
+ reg &= ~(QUADSPI_MCR_SWRSTHD_MASK | QUADSPI_MCR_SWRSTSD_MASK);
+ writel(reg, q->iobase + QUADSPI_MCR);
+}
+
+static int fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor,
+ u8 opcode, unsigned int to, u32 *txbuf,
+ unsigned count, size_t *retlen)
+{
+ int ret, i, j;
+ u32 tmp;
+
+ dev_dbg(q->dev, "to 0x%.8x:0x%.8x, len : %d\n",
+ q->chip_base_addr, to, count);
+
+ /* clear the TX FIFO. */
+ tmp = readl(q->iobase + QUADSPI_MCR);
+ writel(tmp | QUADSPI_MCR_CLR_RXF_MASK, q->iobase + QUADSPI_MCR);
+
+ /* fill the TX data to the FIFO */
+ for (j = 0, i = ((count + 3) / 4); j < i; j++) {
+ tmp = fsl_qspi_endian_xchg(q, *txbuf);
+ writel(tmp, q->iobase + QUADSPI_TBDR);
+ txbuf++;
+ }
+
+ /* Trigger it */
+ ret = fsl_qspi_runcmd(q, opcode, to, count);
+
+ if (ret == 0 && retlen)
+ *retlen += count;
+
+ return ret;
+}
+
+static void fsl_qspi_set_map_addr(struct fsl_qspi *q)
+{
+ int nor_size = q->nor_size;
+ void __iomem *base = q->iobase;
+
+ writel(nor_size + q->memmap_phy, base + QUADSPI_SFA1AD);
+ writel(nor_size * 2 + q->memmap_phy, base + QUADSPI_SFA2AD);
+ writel(nor_size * 3 + q->memmap_phy, base + QUADSPI_SFB1AD);
+ writel(nor_size * 4 + q->memmap_phy, base + QUADSPI_SFB2AD);
+}
+
+/*
+ * There are two different ways to read out the data from the flash:
+ * the "IP Command Read" and the "AHB Command Read".
+ *
+ * The IC guy suggests we use the "AHB Command Read" which is faster
+ * then the "IP Command Read". (What's more is that there is a bug in
+ * the "IP Command Read" in the Vybrid.)
+ *
+ * After we set up the registers for the "AHB Command Read", we can use
+ * the memcpy to read the data directly. A "missed" access to the buffer
+ * causes the controller to clear the buffer, and use the sequence pointed
+ * by the QUADSPI_BFGENCR[SEQID] to initiate a read from the flash.
+ */
+static void fsl_qspi_init_abh_read(struct fsl_qspi *q)
+{
+ void __iomem *base = q->iobase;
+ int seqid;
+
+ /* AHB configuration for access buffer 0/1/2 .*/
+ writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF0CR);
+ writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF1CR);
+ writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF2CR);
+ writel(QUADSPI_BUF3CR_ALLMST, base + QUADSPI_BUF3CR);
+
+ /* We only use the buffer3 */
+ writel(0, base + QUADSPI_BUF0IND);
+ writel(0, base + QUADSPI_BUF1IND);
+ writel(0, base + QUADSPI_BUF2IND);
+
+ /* Set the default lut sequence for AHB Read. */
+ seqid = fsl_qspi_get_seqid(q, q->nor[0].read_opcode);
+ writel(seqid << QUADSPI_BFGENCR_SEQID_SHIFT,
+ q->iobase + QUADSPI_BFGENCR);
+}
+
+/* We use this function to do some basic init for spi_nor_scan(). */
+static int fsl_qspi_nor_setup(struct fsl_qspi *q)
+{
+ void __iomem *base = q->iobase;
+ u32 reg;
+ int ret;
+
+ /* the default frequency, we will change it in the future.*/
+ ret = clk_set_rate(q->clk, 66000000);
+ if (ret)
+ return ret;
+
+ /* Init the LUT table. */
+ fsl_qspi_init_lut(q);
+
+ /* Disable the module */
+ writel(QUADSPI_MCR_MDIS_MASK | QUADSPI_MCR_RESERVED_MASK,
+ base + QUADSPI_MCR);
+
+ reg = readl(base + QUADSPI_SMPR);
+ writel(reg & ~(QUADSPI_SMPR_FSDLY_MASK
+ | QUADSPI_SMPR_FSPHS_MASK
+ | QUADSPI_SMPR_HSENA_MASK
+ | QUADSPI_SMPR_DDRSMP_MASK), base + QUADSPI_SMPR);
+
+ /* Enable the module */
+ writel(QUADSPI_MCR_RESERVED_MASK | QUADSPI_MCR_END_CFG_MASK,
+ base + QUADSPI_MCR);
+
+ /* enable the interrupt */
+ writel(QUADSPI_RSER_TFIE, q->iobase + QUADSPI_RSER);
+
+ return 0;
+}
+
+static int fsl_qspi_nor_setup_last(struct fsl_qspi *q)
+{
+ unsigned long rate = q->clk_rate;
+ int ret;
+
+ if (is_imx6sx_qspi(q))
+ rate *= 4;
+
+ ret = clk_set_rate(q->clk, rate);
+ if (ret)
+ return ret;
+
+ /* Init the LUT table again. */
+ fsl_qspi_init_lut(q);
+
+ /* Init for AHB read */
+ fsl_qspi_init_abh_read(q);
+
+ return 0;
+}
+
+static struct of_device_id fsl_qspi_dt_ids[] = {
+ { .compatible = "fsl,vf610-qspi", .data = (void *)&vybrid_data, },
+ { .compatible = "fsl,imx6sx-qspi", .data = (void *)&imx6sx_data, },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, fsl_qspi_dt_ids);
+
+static void fsl_qspi_set_base_addr(struct fsl_qspi *q, struct spi_nor *nor)
+{
+ q->chip_base_addr = q->nor_size * (nor - q->nor);
+}
+
+static int fsl_qspi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
+{
+ int ret;
+ struct fsl_qspi *q = nor->priv;
+
+ ret = fsl_qspi_runcmd(q, opcode, 0, len);
+ if (ret)
+ return ret;
+
+ fsl_qspi_read_data(q, len, buf);
+ return 0;
+}
+
+static int fsl_qspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len,
+ int write_enable)
+{
+ struct fsl_qspi *q = nor->priv;
+ int ret;
+
+ if (!buf) {
+ ret = fsl_qspi_runcmd(q, opcode, 0, 1);
+ if (ret)
+ return ret;
+
+ if (opcode == OPCODE_CHIP_ERASE)
+ fsl_qspi_invalid(q);
+
+ } else if (len > 0) {
+ ret = fsl_qspi_nor_write(q, nor, opcode, 0,
+ (u32 *)buf, len, NULL);
+ } else {
+ dev_err(q->dev, "invalid cmd %d\n", opcode);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static void fsl_qspi_write(struct spi_nor *nor, loff_t to,
+ size_t len, size_t *retlen, const u_char *buf)
+{
+ struct fsl_qspi *q = nor->priv;
+
+ fsl_qspi_nor_write(q, nor, nor->program_opcode, to,
+ (u32 *)buf, len, retlen);
+
+ /* invalid the data in the AHB buffer. */
+ fsl_qspi_invalid(q);
+}
+
+static int fsl_qspi_read(struct spi_nor *nor, loff_t from,
+ size_t len, size_t *retlen, u_char *buf)
+{
+ struct fsl_qspi *q = nor->priv;
+ u8 cmd = nor->read_opcode;
+ int ret;
+
+ dev_dbg(q->dev, "cmd [%x],read from (0x%p, 0x%.8x, 0x%.8x),len:%d\n",
+ cmd, q->ahb_base, q->chip_base_addr, (unsigned int)from, len);
+
+ /* Wait until the previous command is finished. */
+ ret = nor->wait_till_ready(nor);
+ if (ret)
+ return ret;
+
+ /* Read out the data directly from the AHB buffer.*/
+ memcpy(buf, q->ahb_base + q->chip_base_addr + from, len);
+
+ *retlen += len;
+ return 0;
+}
+
+static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs)
+{
+ struct fsl_qspi *q = nor->priv;
+ int ret;
+
+ dev_dbg(nor->dev, "%dKiB at 0x%08x:0x%08x\n",
+ nor->mtd->erasesize / 1024, q->chip_base_addr, (u32)offs);
+
+ /* Wait until finished previous write command. */
+ ret = nor->wait_till_ready(nor);
+ if (ret)
+ return ret;
+
+ /* Send write enable, then erase commands. */
+ ret = nor->write_reg(nor, OPCODE_WREN, NULL, 0, 0);
+ if (ret)
+ return ret;
+
+ ret = fsl_qspi_runcmd(q, nor->erase_opcode, offs, 0);
+ if (ret)
+ return ret;
+
+ fsl_qspi_invalid(q);
+ return 0;
+}
+
+static int fsl_qspi_prep(struct spi_nor *nor, enum spi_nor_ops ops)
+{
+ struct fsl_qspi *q = nor->priv;
+ int ret;
+
+ ret = clk_enable(q->clk_en);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(q->clk);
+ if (ret) {
+ clk_disable(q->clk_en);
+ return ret;
+ }
+
+ fsl_qspi_set_base_addr(q, nor);
+ return 0;
+}
+
+static void fsl_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
+{
+ struct fsl_qspi *q = nor->priv;
+
+ clk_disable(q->clk);
+ clk_disable(q->clk_en);
+}
+
+static int fsl_qspi_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct mtd_part_parser_data ppdata;
+ struct device *dev = &pdev->dev;
+ struct fsl_qspi *q;
+ struct resource *res;
+ struct spi_nor *nor;
+ struct mtd_info *mtd;
+ int ret, i = 0;
+ bool has_second_chip = false;
+ const struct of_device_id *of_id =
+ of_match_device(fsl_qspi_dt_ids, &pdev->dev);
+
+ q = devm_kzalloc(dev, sizeof(*q), GFP_KERNEL);
+ if (!q)
+ return -ENOMEM;
+
+ q->nor_num = of_get_child_count(dev->of_node);
+ if (!q->nor_num || q->nor_num > FSL_QSPI_MAX_CHIP)
+ return -ENODEV;
+
+ /* find the resources */
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "QuadSPI");
+ q->iobase = devm_ioremap_resource(dev, res);
+ if (IS_ERR(q->iobase)) {
+ ret = PTR_ERR(q->iobase);
+ goto map_failed;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "QuadSPI-memory");
+ q->ahb_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(q->ahb_base)) {
+ ret = PTR_ERR(q->ahb_base);
+ goto map_failed;
+ }
+ q->memmap_phy = res->start;
+
+ /* find the clocks */
+ q->clk_en = devm_clk_get(dev, "qspi_en");
+ if (IS_ERR(q->clk_en)) {
+ ret = PTR_ERR(q->clk_en);
+ goto map_failed;
+ }
+
+ q->clk = devm_clk_get(dev, "qspi");
+ if (IS_ERR(q->clk)) {
+ ret = PTR_ERR(q->clk);
+ goto map_failed;
+ }
+
+ ret = clk_prepare_enable(q->clk_en);
+ if (ret) {
+ dev_err(dev, "can not enable the qspi_en clock\n");
+ goto map_failed;
+ }
+
+ ret = clk_prepare_enable(q->clk);
+ if (ret) {
+ clk_disable_unprepare(q->clk_en);
+ dev_err(dev, "can not enable the qspi clock\n");
+ goto map_failed;
+ }
+
+ /* find the irq */
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0) {
+ dev_err(dev, "failed to get the irq\n");
+ goto irq_failed;
+ }
+
+ ret = devm_request_irq(dev, ret,
+ fsl_qspi_irq_handler, 0, pdev->name, q);
+ if (ret) {
+ dev_err(dev, "failed to request irq.\n");
+ goto irq_failed;
+ }
+
+ q->dev = dev;
+ q->devtype_data = (struct fsl_qspi_devtype_data *)of_id->data;
+ platform_set_drvdata(pdev, q);
+
+ ret = fsl_qspi_nor_setup(q);
+ if (ret)
+ goto irq_failed;
+
+ if (of_get_property(np, "fsl,qspi-has-second-chip", NULL))
+ has_second_chip = true;
+
+ /* iterate the subnodes. */
+ for_each_available_child_of_node(dev->of_node, np) {
+ const struct spi_device_id *id;
+ char modalias[40];
+
+ /* skip the holes */
+ if (!has_second_chip)
+ i *= 2;
+
+ nor = &q->nor[i];
+ mtd = &q->mtd[i];
+
+ nor->mtd = mtd;
+ nor->dev = dev;
+ nor->priv = q;
+ mtd->priv = nor;
+
+ /* fill the hooks */
+ nor->read_reg = fsl_qspi_read_reg;
+ nor->write_reg = fsl_qspi_write_reg;
+ nor->read = fsl_qspi_read;
+ nor->write = fsl_qspi_write;
+ nor->erase = fsl_qspi_erase;
+
+ nor->prepare = fsl_qspi_prep;
+ nor->unprepare = fsl_qspi_unprep;
+
+ if (of_modalias_node(np, modalias, sizeof(modalias)) < 0)
+ goto map_failed;
+
+ id = spi_nor_match_id(modalias);
+ if (!id)
+ goto map_failed;
+
+ ret = of_property_read_u32(np, "spi-max-frequency",
+ &q->clk_rate);
+ if (ret < 0)
+ goto map_failed;
+
+ /* set the chip address for READID */
+ fsl_qspi_set_base_addr(q, nor);
+
+ ret = spi_nor_scan(nor, id, SPI_NOR_QUAD);
+ if (ret)
+ goto map_failed;
+
+ ppdata.of_node = np;
+ ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
+ if (ret)
+ goto map_failed;
+
+ /* Set the correct NOR size now. */
+ if (q->nor_size == 0) {
+ q->nor_size = mtd->size;
+
+ /* Map the SPI NOR to accessiable address */
+ fsl_qspi_set_map_addr(q);
+ }
+
+ /*
+ * The TX FIFO is 64 bytes in the Vybrid, but the Page Program
+ * may writes 265 bytes per time. The write is working in the
+ * unit of the TX FIFO, not in the unit of the SPI NOR's page
+ * size.
+ *
+ * So shrink the spi_nor->page_size if it is larger then the
+ * TX FIFO.
+ */
+ if (nor->page_size > q->devtype_data->txfifo)
+ nor->page_size = q->devtype_data->txfifo;
+
+ i++;
+ }
+
+ /* finish the rest init. */
+ ret = fsl_qspi_nor_setup_last(q);
+ if (ret)
+ goto last_init_failed;
+
+ clk_disable(q->clk);
+ clk_disable(q->clk_en);
+ dev_info(dev, "QuadSPI SPI NOR flash driver\n");
+ return 0;
+
+last_init_failed:
+ for (i = 0; i < q->nor_num; i++)
+ mtd_device_unregister(&q->mtd[i]);
+
+irq_failed:
+ clk_disable_unprepare(q->clk);
+ clk_disable_unprepare(q->clk_en);
+map_failed:
+ dev_err(dev, "Freescale QuadSPI probe failed\n");
+ return ret;
+}
+
+static int fsl_qspi_remove(struct platform_device *pdev)
+{
+ struct fsl_qspi *q = platform_get_drvdata(pdev);
+ int i;
+
+ for (i = 0; i < q->nor_num; i++)
+ mtd_device_unregister(&q->mtd[i]);
+
+ /* disable the hardware */
+ writel(QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR);
+ writel(0x0, q->iobase + QUADSPI_RSER);
+
+ clk_unprepare(q->clk);
+ clk_unprepare(q->clk_en);
+ return 0;
+}
+
+static struct platform_driver fsl_qspi_driver = {
+ .driver = {
+ .name = "fsl-quadspi",
+ .bus = &platform_bus_type,
+ .owner = THIS_MODULE,
+ .of_match_table = fsl_qspi_dt_ids,
+ },
+ .probe = fsl_qspi_probe,
+ .remove = fsl_qspi_remove,
+};
+module_platform_driver(fsl_qspi_driver);
+
+MODULE_DESCRIPTION("Freescale QuadSPI Controller Driver");
+MODULE_AUTHOR("Freescale Semiconductor Inc.");
+MODULE_LICENSE("GPL v2");
--
1.7.2.rc3
^ 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