* Re: [PATCH] dt-bindings: pinctrl: uniphier: add UniPhier pinctrl binding
From: Rob Herring @ 2017-11-30 20:24 UTC (permalink / raw)
To: Masahiro Yamada
Cc: linux-gpio-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Mark Rutland,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
Linux Kernel Mailing List, Mauro Carvalho Chehab, David S. Miller,
linux-arm-kernel
In-Reply-To: <CAK7LNAQYBe=x8sOBTrz8zE+5JEhOu+3eQKd8fbSAxi9Zuy18jQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On Tue, Nov 28, 2017 at 9:44 PM, Masahiro Yamada
<yamada.masahiro-uWyLwvC0a2jby3iVrkZq2A@public.gmane.org> wrote:
> Hi Rob,
>
>
> 2017-11-29 0:27 GMT+09:00 Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>:
>> On Tue, Nov 28, 2017 at 04:49:45PM +0900, Masahiro Yamada wrote:
>>> The driver has been in the tree for a while, but its binding document
>>> is missing. Hence, here it is.
>>>
>>> Signed-off-by: Masahiro Yamada <yamada.masahiro-uWyLwvC0a2jby3iVrkZq2A@public.gmane.org>
>>> ---
>>>
>>> .../pinctrl/socionext,uniphier-pinctrl.txt | 27 ++++++++++++++++++++++
>>> MAINTAINERS | 1 +
>>> 2 files changed, 28 insertions(+)
>>> create mode 100644 Documentation/devicetree/bindings/pinctrl/socionext,uniphier-pinctrl.txt
>>>
>>> diff --git a/Documentation/devicetree/bindings/pinctrl/socionext,uniphier-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/socionext,uniphier-pinctrl.txt
>>> new file mode 100644
>>> index 0000000..8173b12
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/pinctrl/socionext,uniphier-pinctrl.txt
>>> @@ -0,0 +1,27 @@
>>> +UniPhier SoCs pin controller
>>> +
>>> +Required properties:
>>> +- compatible: should be one of the following:
>>> + "socionext,uniphier-ld4-pinctrl" - for LD4 SoC
>>> + "socionext,uniphier-pro4-pinctrl" - for Pro4 SoC
>>> + "socionext,uniphier-sld8-pinctrl" - for sLD8 SoC
>>> + "socionext,uniphier-pro5-pinctrl" - for Pro5 SoC
>>> + "socionext,uniphier-pxs2-pinctrl" - for PXs2 SoC
>>> + "socionext,uniphier-ld6b-pinctrl" - for LD6b SoC
>>> + "socionext,uniphier-ld11-pinctrl" - for LD11 SoC
>>> + "socionext,uniphier-ld20-pinctrl" - for LD20 SoC
>>> + "socionext,uniphier-pxs3-pinctrl" - for PXs3 SoC
>>> +
>>> +Note:
>>> +The UniPhier pinctrl should be a subnode of a "syscon" compatible node.
>>> +
>>> +Example:
>>> + soc-glue@5f800000 {
>>> + compatible = "socionext,uniphier-pro4-soc-glue",
>>> + "simple-mfd", "syscon";
>>> + reg = <0x5f800000 0x2000>;
>>> +
>>> + pinctrl: pinctrl {
>>> + compatible = "socionext,uniphier-pro4-pinctrl";
>>
>> There's not a contiguous register range that can be put here?
>
>
> Right.
>
> I saw SATA PHY registers are inserted among the pinctrl registers.
Okay,
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Hardware engineers often make crazy design.
If there's 2 ways to do things, they will find a 3rd way.
Rob
--
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 v2 2/2] ARM: dts: at91: disable the nxp,se97b SMBUS timeout on the TSE-850
From: Guenter Roeck @ 2017-11-30 21:17 UTC (permalink / raw)
To: Peter Rosin
Cc: Alexandre Belloni, linux-kernel, Rob Herring, Mark Rutland,
Nicolas Ferre, Russell King, Jean Delvare, Ludovic Desroches,
devicetree, linux-arm-kernel, linux-hwmon
In-Reply-To: <acaea4f3-d273-444a-4df4-e6d1b35c876d@axentia.se>
On Thu, Nov 30, 2017 at 07:46:09PM +0100, Peter Rosin wrote:
> On 2017-11-30 18:26, Alexandre Belloni wrote:
> > On 30/11/2017 at 09:16:38 -0800, Guenter Roeck wrote:
> >> On Wed, Nov 29, 2017 at 09:56:29PM +0100, Alexandre Belloni wrote:
> >>> On 29/11/2017 at 12:53:11 -0800, Guenter Roeck wrote:
> >>>> On Mon, Nov 27, 2017 at 05:31:01PM +0100, Peter Rosin wrote:
> >>>>> The I2C adapter driver is sometimes slow, causing the SCL line to
> >>>>> be stuck low for more than the stipulated SMBUS timeout of 25-35 ms.
> >>>>> This causes the client device to give up which in turn causes silent
> >>>>> corruption of data. So, disable the SMBUS timeout in the client device.
> >>>>>
> >>>>> Signed-off-by: Peter Rosin <peda@axentia.se>
> >>>>
> >>>> Acked-by: Guenter Roeck <linux@roeck-us.net>
> >>>>
> >>>> I assume this will be sent upstream through an arm tree.
> >>>>
> >>>
> >>> Yes, I'm applying it right now.
> >>>
> >> Are you going to apply the patch for 4.15, or queue it up for 4.16 ?
> >> I have been arguing with myself if this is a feature or a bug fix.
> >> So far I queued the driver change up for 4.16, but I am open to
> >> applying it to 4.15. Any thoughts ?
> >>
> >
> > I was wondering that myself. I'm open to have it as a fix in 4.15. Or
> > maybe Peter can send the series to stable if he needs it in 4.14.
> >
> > Peter, what do you think/want?
>
> TL;DR Either way is fine.
>
> I think it's a bugfix; it fixes real problems where the application
> misbehave due to faulty content when reading from an eeprom. I'm
> expecting to make a new release for the hw in question RSN and these
> are the only local patches. So, it would be nice if they made it to
> 4.14.x before my release happens. However, it's not like it's difficult
> to rebase the patches should that backport not happen or take too long.
>
Good enough for me. I'll send it as a fix for v4.15, with Cc: stable.
Guenter
> The badness started to happen much more frequently due to some timing
> difference affecting the i2c bus driver, but in theory it's a problem
> that has been there from the start. I have just not noticed it before...
>
> Cheers,
> Peter
> --
> To unsubscribe from this list: send the line "unsubscribe linux-hwmon" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v4 2/8] MIPS: Octeon: Enable LMTDMA/LMTST operations.
From: James Hogan @ 2017-11-30 21:36 UTC (permalink / raw)
To: David Daney
Cc: Mark Rutland, linux-mips, devel, devicetree, netdev, linux-kernel,
ralf, Carlos Munoz, Rob Herring, Andrew Lunn, Steven J. Hill,
Greg Kroah-Hartman, Florian Fainelli, David S. Miller
In-Reply-To: <20171129005540.28829-3-david.daney@cavium.com>
[-- Attachment #1.1: Type: text/plain, Size: 3023 bytes --]
On Tue, Nov 28, 2017 at 04:55:34PM -0800, David Daney wrote:
> From: Carlos Munoz <cmunoz@cavium.com>
>
> LMTDMA/LMTST operations move data between cores and I/O devices:
>
> * LMTST operations can send an address and a variable length
> (up to 128 bytes) of data to an I/O device.
> * LMTDMA operations can send an address and a variable length
> (up to 128) of data to the I/O device and then return a
> variable length (up to 128 bytes) response from the IOI device.
Should that be "I/O"?
>
> Signed-off-by: Carlos Munoz <cmunoz@cavium.com>
> Signed-off-by: Steven J. Hill <Steven.Hill@cavium.com>
> Signed-off-by: David Daney <david.daney@cavium.com>
> ---
> arch/mips/cavium-octeon/setup.c | 6 ++++++
> arch/mips/include/asm/octeon/octeon.h | 12 ++++++++++--
> 2 files changed, 16 insertions(+), 2 deletions(-)
>
> diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c
> index a8034d0dcade..99e6a68bc652 100644
> --- a/arch/mips/cavium-octeon/setup.c
> +++ b/arch/mips/cavium-octeon/setup.c
> @@ -609,6 +609,12 @@ void octeon_user_io_init(void)
> #else
> cvmmemctl.s.cvmsegenak = 0;
> #endif
> + if (OCTEON_IS_OCTEON3()) {
> + /* Enable LMTDMA */
> + cvmmemctl.s.lmtena = 1;
> + /* Scratch line to use for LMT operation */
> + cvmmemctl.s.lmtline = 2;
Out of curiosity, is there significance to the value 2 and associated
virtual address 0xffffffffffff8100, or is it pretty arbitrary?
> + }
> /* R/W If set, CVMSEG is available for loads/stores in
> * supervisor mode. */
> cvmmemctl.s.cvmsegenas = 0;
> diff --git a/arch/mips/include/asm/octeon/octeon.h b/arch/mips/include/asm/octeon/octeon.h
> index c99c4b6a79f4..92a17d67c1fa 100644
> --- a/arch/mips/include/asm/octeon/octeon.h
> +++ b/arch/mips/include/asm/octeon/octeon.h
> @@ -179,7 +179,15 @@ union octeon_cvmemctl {
> /* RO 1 = BIST fail, 0 = BIST pass */
> __BITFIELD_FIELD(uint64_t wbfbist:1,
> /* Reserved */
> - __BITFIELD_FIELD(uint64_t reserved:17,
> + __BITFIELD_FIELD(uint64_t reserved_52_57:6,
> + /* When set, LMTDMA/LMTST operations are permitted */
> + __BITFIELD_FIELD(uint64_t lmtena:1,
> + /* Selects the CVMSEG LM cacheline used by LMTDMA
> + * LMTST and wide atomic store operations.
> + */
> + __BITFIELD_FIELD(uint64_t lmtline:6,
> + /* Reserved */
> + __BITFIELD_FIELD(uint64_t reserved_41_44:4,
> /* OCTEON II - TLB replacement policy: 0 = bitmask LRU; 1 = NLU.
> * This field selects between the TLB replacement policies:
> * bitmask LRU or NLU. Bitmask LRU maintains a mask of
> @@ -275,7 +283,7 @@ union octeon_cvmemctl {
> /* R/W Size of local memory in cache blocks, 54 (6912
> * bytes) is max legal value. */
> __BITFIELD_FIELD(uint64_t lmemsz:6,
> - ;)))))))))))))))))))))))))))))))))
> + ;))))))))))))))))))))))))))))))))))))
> } s;
> };
Regardless, the patch looks good to me.
Reviewed-by: James Hogan <jhogan@kernel.org>
Cheers
James
[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
[-- Attachment #2: Type: text/plain, Size: 169 bytes --]
_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
^ permalink raw reply
* Re: [PATCH RFC 2/2] arm64: allwinner: a64: Add Brava Keller initial support
From: Philippe Ombredanne @ 2017-11-30 21:36 UTC (permalink / raw)
To: Jagan Teki
Cc: Maxime Ripard, Chen-Yu Tsai, Icenowy Zheng, Rob Herring,
Mark Rutland, Catalin Marinas, Will Deacon, Michael Trimarchi,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, LKML,
Mark Janoff, Stuart Westerman, linux-sunxi, Jagan Teki
In-Reply-To: <1512067334-12761-2-git-send-email-jagan@amarulasolutions.com>
Jagan,
On Thu, Nov 30, 2017 at 7:42 PM, Jagan Teki <jagannadh.teki@gmail.com> wrote:
[]
> diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-brava-keller.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-brava-keller.dts
> new file mode 100644
> index 0000000..f5303a3
> --- /dev/null
> +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-brava-keller.dts
> @@ -0,0 +1,244 @@
> +/*
> + * Copyright (C) 2017 Jagan Teki <jagan@amarulasolutions.com>
> + *
> + * This file is dual-licensed: you can use it either under the terms
> + * of the GPL or the X11 license, at your option. Note that this dual
> + * licensing only applies to this file, and not this project as a
> + * whole.
> + *
> + * a) This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of the
> + * License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * Or, alternatively,
> + *
> + * b) Permission is hereby granted, free of charge, to any person
> + * obtaining a copy of this software and associated documentation
> + * files (the "Software"), to deal in the Software without
> + * restriction, including without limitation the rights to use,
> + * copy, modify, merge, publish, distribute, sublicense, and/or
> + * sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following
> + * conditions:
> + *
> + * The above copyright notice and this permission notice shall be
> + * included in all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
> + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
> + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
> + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + */
Rather than this long boilerplate, you might want to use the SPDX ids,
as started by Greg and documented by Thomas.
Noe that Linus wants the // comment style for the license line, and
since there is only two line left here I suggest using it for both
lines.
You can check also the recent doc patch posted by Thomas (tglx) and
comments from Linus and Greg.
So I guess you could use this:
> +// Copyright (C) 2017 Jagan Teki <jagan@amarulasolutions.com>
> +// SPDX-License-Indentifier: (GPL-2.0+ OR MIT)
NB: what you call X11 is has the MIT license id in the SPDX license list.
So you could replace 32 lines by only two lines :) it'[s neat right?
And this would also help as we have tagged already ~15K files, so it
would help to use this for new files so the amount of cleanup work
still left does not increase. Thank you for your kind consideration!
--
Cordially
Philippe Ombredanne
^ permalink raw reply
* Re: [PATCH v4 2/8] MIPS: Octeon: Enable LMTDMA/LMTST operations.
From: David Daney @ 2017-11-30 21:49 UTC (permalink / raw)
To: James Hogan, David Daney
Cc: linux-mips-6z/3iImG2C8G8FEW9MqTrA, ralf-6z/3iImG2C8G8FEW9MqTrA,
netdev-u79uwXL29TY76Z2rM5mHXA, David S. Miller, Rob Herring,
Mark Rutland, devel-gWbeCf7V1WCQmaza687I9mD2FQJk+8+b,
Greg Kroah-Hartman, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
Steven J. Hill, devicetree-u79uwXL29TY76Z2rM5mHXA, Andrew Lunn,
Florian Fainelli, Carlos Munoz
In-Reply-To: <20171130213635.GH27409-4bYivNCBEGSP4qXr0kR+DFHK5/nzsB32@public.gmane.org>
On 11/30/2017 01:36 PM, James Hogan wrote:
> On Tue, Nov 28, 2017 at 04:55:34PM -0800, David Daney wrote:
>> From: Carlos Munoz <cmunoz-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
>>
>> LMTDMA/LMTST operations move data between cores and I/O devices:
>>
>> * LMTST operations can send an address and a variable length
>> (up to 128 bytes) of data to an I/O device.
>> * LMTDMA operations can send an address and a variable length
>> (up to 128) of data to the I/O device and then return a
>> variable length (up to 128 bytes) response from the IOI device.
>
> Should that be "I/O"?
Yes, I will fix the changelog.
>
>>
>> Signed-off-by: Carlos Munoz <cmunoz-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
>> Signed-off-by: Steven J. Hill <Steven.Hill-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
>> Signed-off-by: David Daney <david.daney-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
>> ---
>> arch/mips/cavium-octeon/setup.c | 6 ++++++
>> arch/mips/include/asm/octeon/octeon.h | 12 ++++++++++--
>> 2 files changed, 16 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c
>> index a8034d0dcade..99e6a68bc652 100644
>> --- a/arch/mips/cavium-octeon/setup.c
>> +++ b/arch/mips/cavium-octeon/setup.c
>> @@ -609,6 +609,12 @@ void octeon_user_io_init(void)
>> #else
>> cvmmemctl.s.cvmsegenak = 0;
>> #endif
>> + if (OCTEON_IS_OCTEON3()) {
>> + /* Enable LMTDMA */
>> + cvmmemctl.s.lmtena = 1;
>> + /* Scratch line to use for LMT operation */
>> + cvmmemctl.s.lmtline = 2;
>
> Out of curiosity, is there significance to the value 2 and associated
> virtual address 0xffffffffffff8100, or is it pretty arbitrary?
Yes, there is significance.
CPU local memory starts at 0xffffffffffff8000, each line is 0x80 bytes.
so the 2nd line starts at 0xffffffffffff8100
>
>> + }
>> /* R/W If set, CVMSEG is available for loads/stores in
>> * supervisor mode. */
>> cvmmemctl.s.cvmsegenas = 0;
>> diff --git a/arch/mips/include/asm/octeon/octeon.h b/arch/mips/include/asm/octeon/octeon.h
>> index c99c4b6a79f4..92a17d67c1fa 100644
>> --- a/arch/mips/include/asm/octeon/octeon.h
>> +++ b/arch/mips/include/asm/octeon/octeon.h
>> @@ -179,7 +179,15 @@ union octeon_cvmemctl {
>> /* RO 1 = BIST fail, 0 = BIST pass */
>> __BITFIELD_FIELD(uint64_t wbfbist:1,
>> /* Reserved */
>> - __BITFIELD_FIELD(uint64_t reserved:17,
>> + __BITFIELD_FIELD(uint64_t reserved_52_57:6,
>> + /* When set, LMTDMA/LMTST operations are permitted */
>> + __BITFIELD_FIELD(uint64_t lmtena:1,
>> + /* Selects the CVMSEG LM cacheline used by LMTDMA
>> + * LMTST and wide atomic store operations.
>> + */
>> + __BITFIELD_FIELD(uint64_t lmtline:6,
>> + /* Reserved */
>> + __BITFIELD_FIELD(uint64_t reserved_41_44:4,
>> /* OCTEON II - TLB replacement policy: 0 = bitmask LRU; 1 = NLU.
>> * This field selects between the TLB replacement policies:
>> * bitmask LRU or NLU. Bitmask LRU maintains a mask of
>> @@ -275,7 +283,7 @@ union octeon_cvmemctl {
>> /* R/W Size of local memory in cache blocks, 54 (6912
>> * bytes) is max legal value. */
>> __BITFIELD_FIELD(uint64_t lmemsz:6,
>> - ;)))))))))))))))))))))))))))))))))
>> + ;))))))))))))))))))))))))))))))))))))
>> } s;
>> };
>
> Regardless, the patch looks good to me.
>
> Reviewed-by: James Hogan <jhogan-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>
> Cheers
> James
>
--
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] of: overlay: Remove else after goto
From: Frank Rowand @ 2017-11-30 21:52 UTC (permalink / raw)
To: Rob Herring
Cc: Geert Uytterhoeven, Pantelis Antoniou,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <CAL_JsqLjAJ0QG5r217bpT4ZLaKSras6taWHjooTsdL3GDp9_hg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On 11/30/17 10:34, Rob Herring wrote:
> On Wed, Nov 29, 2017 at 3:30 AM, Frank Rowand <frowand.list-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>> On 11/28/17 03:26, Geert Uytterhoeven wrote:
>>> If an "if" branch is terminated by a "goto", there's no need to have an
>>> "else" statement and an indented block of code.
>>>
>>> Remove the "else" statement to simplify the code flow for the casual
>>> reviewer.
>>>
>>> Signed-off-by: Geert Uytterhoeven <geert+renesas-gXvu3+zWzMSzQB+pC5nmwQ@public.gmane.org>
>>> ---
>>> drivers/of/overlay.c | 25 ++++++++++---------------
>>> 1 file changed, 10 insertions(+), 15 deletions(-)
>>>
>>> diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
>>> index 8676411bd3e6f29f..53bc9e3f0b985415 100644
>>> --- a/drivers/of/overlay.c
>>> +++ b/drivers/of/overlay.c
>>> @@ -580,9 +580,9 @@ static int init_overlay_changeset(struct overlay_changeset *ovcs,
>>> of_node_put(fragment->overlay);
>>> ret = -EINVAL;
>>> goto err_free_fragments;
>>> - } else {
>>> - cnt++;
>>> }
>>> +
>>> + cnt++;
>>> }
>>> }
>>>
>>> @@ -736,14 +736,12 @@ int of_overlay_apply(struct device_node *tree, int *ovcs_id)
>>> devicetree_state_flags |= DTSF_APPLY_FAIL;
>>> }
>>> goto err_free_overlay_changeset;
>>> - } else {
>>> - ret = __of_changeset_apply_notify(&ovcs->cset);
>>> - if (ret)
>>> - pr_err("overlay changeset entry notify error %d\n",
>>> - ret);
>>> - /* fall through */
>>> }
>>>
>>> + ret = __of_changeset_apply_notify(&ovcs->cset);
>>> + if (ret)
>>> + pr_err("overlay changeset entry notify error %d\n", ret);
>>> +
>>
>> The fall through comment was removed. It is important to document that we
>> are intentionally continuing despite the error.
>
> I've fixed these up like this:
Thanks, looks good.
-Frank
>
> diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
> index 53bc9e3f0b98..cb520169d679 100644
> --- a/drivers/of/overlay.c
> +++ b/drivers/of/overlay.c
> @@ -741,6 +741,7 @@ int of_overlay_apply(struct device_node *tree, int *ovcs_id)
> ret = __of_changeset_apply_notify(&ovcs->cset);
> if (ret)
> pr_err("overlay changeset entry notify error %d\n", ret);
> + /* notify failure is not fatal, continue */
>
> list_add_tail(&ovcs->ovcs_list, &ovcs_list);
> *ovcs_id = ovcs->id;
> @@ -934,6 +935,7 @@ int of_overlay_remove(int *ovcs_id)
> ret = __of_changeset_revert_notify(&ovcs->cset);
> if (ret)
> pr_err("overlay changeset entry notify error %d\n", ret);
> + /* notify failure is not fatal, continue */
>
> *ovcs_id = 0;
>
--
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 v3 4/4] DTS: Pandora: fix panel compatibility string
From: Sebastian Reichel @ 2017-11-30 22:06 UTC (permalink / raw)
To: Tony Lindgren
Cc: Mark Rutland, DTML, linux-fbdev,
Discussions about the Letux Kernel, Bartlomiej Zolnierkiewicz,
David Airlie, H. Nikolaus Schaller, dri-devel, Russell King,
Rob Herring, Linux Kernel Mailing List, Julia Lawall,
Tomi Valkeinen, Thierry Reding, Laurent Pinchart,
Benoît Cousson, kernel, linux-omap, Linux ARM
In-Reply-To: <20171130152430.GM28152@atomide.com>
[-- Attachment #1.1: Type: text/plain, Size: 1869 bytes --]
Hi,
On Thu, Nov 30, 2017 at 07:24:30AM -0800, Tony Lindgren wrote:
> * H. Nikolaus Schaller <hns@goldelico.com> [171128 18:35]:
> > Hi,
> >
> > > Am 28.11.2017 um 17:18 schrieb Tony Lindgren <tony@atomide.com>:
> > >
> > > * H. Nikolaus Schaller <hns@goldelico.com> [171128 16:17]:
> > >> Hi Tony,
> > >>
> > >>> Am 28.11.2017 um 17:04 schrieb Tony Lindgren <tony@atomide.com>:
> > >>>
> > >>> * H. Nikolaus Schaller <hns@goldelico.com> [171128 15:52]:
> > >>>> We can remove the unnecessary "omapdss," prefix because
> > >>>> the omapdrm driver takes care of it when matching with
> > >>>> the driver table.
> > >>>
> > >>> So is this needed as a fix or is this another clean-up?
> > >>>
> > >>> So is this is really needed as a fix?
> > >>
> > >> Hm. How do you differentiate between "fix" and "cleanup"?
> > >> Maybe it is more a wording than a content issue...
> > >>
> > >> For me it is a "fix" because it is semantically wrong to have
> > >> a prefix where it is not needed. And "fixing" it changes the
> > >> compiler output by 8 bytes.
> > >
> > > How about let's call it a "typo fix" then? :)
> >
> > Well, it is not really a typo.
>
> Well what if the stable people pick it into earlier stable series
> based on the word fix in the subject? That has happened before.
>
> I suggest you update the dts patches to use wording like
> "update compatible to use new naming" or something similar.
Patch 4/4 is a Fix and should be applied to stable trees. "omapdss,"
prefix was never supposed to be in the DTS files, is not supposed to
be in there now and will break some time in the future.
Explanation: The early init of omapdss adds the prefix at runtime,
so that the binding can use generic properties and the kernel can
use omapdss specific drivers until the generic ones can be used.
-- Sebastian
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
[-- Attachment #2: Type: text/plain, Size: 160 bytes --]
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* Re: [PATCH v4 3/8] MIPS: Octeon: Add a global resource manager.
From: James Hogan @ 2017-11-30 22:53 UTC (permalink / raw)
To: David Daney
Cc: linux-mips-6z/3iImG2C8G8FEW9MqTrA, ralf-6z/3iImG2C8G8FEW9MqTrA,
netdev-u79uwXL29TY76Z2rM5mHXA, David S. Miller, Rob Herring,
Mark Rutland, devel-gWbeCf7V1WCQmaza687I9mD2FQJk+8+b,
Greg Kroah-Hartman, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
Steven J. Hill, devicetree-u79uwXL29TY76Z2rM5mHXA, Andrew Lunn,
Florian Fainelli, Carlos Munoz
In-Reply-To: <20171129005540.28829-4-david.daney-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 14219 bytes --]
On Tue, Nov 28, 2017 at 04:55:35PM -0800, David Daney wrote:
> From: Carlos Munoz <cmunoz-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
>
> Add a global resource manager to manage tagged pointers within
> bootmem allocated memory. This is used by various functional
> blocks in the Octeon core like the FPA, Ethernet nexus, etc.
>
> Signed-off-by: Carlos Munoz <cmunoz-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
> Signed-off-by: Steven J. Hill <Steven.Hill-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
> Signed-off-by: David Daney <david.daney-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
> ---
> arch/mips/cavium-octeon/Makefile | 3 +-
> arch/mips/cavium-octeon/resource-mgr.c | 371 +++++++++++++++++++++++++++++++++
> arch/mips/include/asm/octeon/octeon.h | 18 ++
> 3 files changed, 391 insertions(+), 1 deletion(-)
> create mode 100644 arch/mips/cavium-octeon/resource-mgr.c
>
> diff --git a/arch/mips/cavium-octeon/Makefile b/arch/mips/cavium-octeon/Makefile
> index 7c02e542959a..0a299ab8719f 100644
> --- a/arch/mips/cavium-octeon/Makefile
> +++ b/arch/mips/cavium-octeon/Makefile
> @@ -9,7 +9,8 @@
> # Copyright (C) 2005-2009 Cavium Networks
> #
>
> -obj-y := cpu.o setup.o octeon-platform.o octeon-irq.o csrc-octeon.o
> +obj-y := cpu.o setup.o octeon-platform.o octeon-irq.o csrc-octeon.o \
> + resource-mgr.o
Maybe put that on a separate line like below.
> obj-y += dma-octeon.o
> obj-y += octeon-memcpy.o
> obj-y += executive/
> diff --git a/arch/mips/cavium-octeon/resource-mgr.c b/arch/mips/cavium-octeon/resource-mgr.c
> new file mode 100644
> index 000000000000..ca25fa953402
> --- /dev/null
> +++ b/arch/mips/cavium-octeon/resource-mgr.c
> @@ -0,0 +1,371 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Resource manager for Octeon.
> + *
> + * This file is subject to the terms and conditions of the GNU General Public
> + * License. See the file "COPYING" in the main directory of this archive
> + * for more details.
> + *
> + * Copyright (C) 2017 Cavium, Inc.
> + */
> +#include <linux/module.h>
> +
> +#include <asm/octeon/octeon.h>
> +#include <asm/octeon/cvmx-bootmem.h>
> +
> +#define RESOURCE_MGR_BLOCK_NAME "cvmx-global-resources"
> +#define MAX_RESOURCES 128
> +#define INST_AVAILABLE -88
> +#define OWNER 0xbadc0de
> +
> +struct global_resource_entry {
> + struct global_resource_tag tag;
> + u64 phys_addr;
> + u64 size;
> +};
> +
> +struct global_resources {
> +#ifdef __LITTLE_ENDIAN_BITFIELD
> + u32 rlock;
> + u32 pad;
> +#else
> + u32 pad;
> + u32 rlock;
> +#endif
> + u64 entry_cnt;
> + struct global_resource_entry resource_entry[];
> +};
> +
> +static struct global_resources *res_mgr_info;
> +
> +
> +/*
> + * The resource manager interacts with software running outside of the
> + * Linux kernel, which necessitates locking to maintain data structure
> + * consistency. These custom locking functions implement the locking
> + * protocol, and cannot be replaced by kernel locking functions that
> + * may use different in-memory structures.
> + */
> +
> +static void res_mgr_lock(void)
> +{
> + unsigned int tmp;
> + u64 lock = (u64)&res_mgr_info->rlock;
presumably this could be a u32 *, avoid the cast to u64, and still work
just fine below.
> +
> + __asm__ __volatile__(
> + ".set noreorder\n"
> + "1: ll %[tmp], 0(%[addr])\n"
> + " bnez %[tmp], 1b\n"
> + " li %[tmp], 1\n"
I believe the convention for .S files is for instructions in branch
delay slots to be indented an additional space for readability. Maybe
that would be worthwhile here.
> + " sc %[tmp], 0(%[addr])\n"
> + " beqz %[tmp], 1b\n"
> + " nop\n"
and here also.
> + ".set reorder\n" :
nit: strictly speaking there's no need for \n on the last line.
> + [tmp] "=&r"(tmp) :
> + [addr] "r"(lock) :
> + "memory");
minor style thing: its far more common to have : at the beginning of the
line rather than the end.
> +}
> +
> +static void res_mgr_unlock(void)
> +{
> + u64 lock = (u64)&res_mgr_info->rlock;
same again
> +
> + /* Wait until all resource operations finish before unlocking. */
> + mb();
> + __asm__ __volatile__(
> + "sw $0, 0(%[addr])\n" : :
> + [addr] "r"(lock) :
> + "memory");
> +
> + /* Force a write buffer flush. */
> + mb();
> +}
> +
> +static int res_mgr_find_resource(struct global_resource_tag tag)
> +{
> + struct global_resource_entry *res_entry;
> + int i;
> +
> + for (i = 0; i < res_mgr_info->entry_cnt; i++) {
> + res_entry = &res_mgr_info->resource_entry[i];
> + if (res_entry->tag.lo == tag.lo && res_entry->tag.hi == tag.hi)
> + return i;
> + }
> + return -1;
> +}
> +
> +/**
> + * res_mgr_create_resource - Create a resource.
> + * @tag: Identifies the resource.
> + * @inst_cnt: Number of resource instances to create.
> + *
> + * Returns 0 if the source was created successfully.
> + * Returns <0 for error codes.
Only -1 seems to be returned. Is it worth returning some standard Linux
error codes instead?
> + */
> +int res_mgr_create_resource(struct global_resource_tag tag, int inst_cnt)
> +{
> + struct global_resource_entry *res_entry;
> + u64 size;
> + u64 *res_addr;
> + int res_index, i, rc = 0;
> +
> + res_mgr_lock();
> +
> + /* Make sure resource doesn't already exist. */
> + res_index = res_mgr_find_resource(tag);
> + if (res_index >= 0) {
> + rc = -1;
> + goto err;
> + }
> +
> + if (res_mgr_info->entry_cnt >= MAX_RESOURCES) {
> + pr_err("Resource max limit reached, not created\n");
> + rc = -1;
> + goto err;
> + }
> +
> + /*
> + * Each instance is kept in an array of u64s. The first array element
> + * holds the number of allocated instances.
> + */
> + size = sizeof(u64) * (inst_cnt + 1);
> + res_addr = cvmx_bootmem_alloc_range(size, CVMX_CACHE_LINE_SIZE, 0, 0);
> + if (!res_addr) {
> + pr_err("Failed to allocate resource. not created\n");
> + rc = -1;
> + goto err;
> + }
> +
> + /* Initialize the newly created resource. */
> + *res_addr = inst_cnt;
> + for (i = 1; i < inst_cnt + 1; i++)
or "i <= inst_cnt"?
> + *(res_addr + i) = INST_AVAILABLE;
Nit: IMO res_addr[i] is marginally more readable
> +
> + res_index = res_mgr_info->entry_cnt;
> + res_entry = &res_mgr_info->resource_entry[res_index];
> + res_entry->tag.lo = tag.lo;
> + res_entry->tag.hi = tag.hi;
or res_entry->tag = tag;?
> + res_entry->phys_addr = virt_to_phys(res_addr);
> + res_entry->size = size;
> + res_mgr_info->entry_cnt++;
> +
> +err:
> + res_mgr_unlock();
> +
> + return rc;
> +}
> +EXPORT_SYMBOL(res_mgr_create_resource);
> +
> +/**
> + * res_mgr_alloc_range - Allocate a range of resource instances.
I don't know how strict kerndoc is on this, but I think it should be
res_mgr_alloc_range() here. Same elsewhere.
> + * @tag: Identifies the resource.
> + * @req_inst: Requested start of instance range to allocate.
> + * Range instances are guaranteed to be sequential
> + * (-1 for don't care).
> + * @req_cnt: Number of instances to allocate.
> + * @use_last_avail: Set to request the last available instance.
> + * @inst: Updated with the allocated instances.
> + *
> + * Returns 0 if the source was created successfully.
> + * Returns <0 for error codes.
> + */
> +int res_mgr_alloc_range(struct global_resource_tag tag, int req_inst,
> + int req_cnt, bool use_last_avail, int *inst)
> +{
> + struct global_resource_entry *res_entry;
> + int res_index;
> + u64 *res_addr;
> + u64 inst_cnt;
> + int alloc_cnt, i, rc = -1;
> +
> + /* Start with no instances allocated. */
> + for (i = 0; i < req_cnt; i++)
> + inst[i] = INST_AVAILABLE;
> +
> + res_mgr_lock();
> +
> + /* Find the resource. */
> + res_index = res_mgr_find_resource(tag);
> + if (res_index < 0) {
> + pr_err("Resource not found, can't allocate instance\n");
> + goto err;
> + }
> +
> + /* Get resource data. */
> + res_entry = &res_mgr_info->resource_entry[res_index];
> + res_addr = phys_to_virt(res_entry->phys_addr);
> + inst_cnt = *res_addr;
> +
> + /* Allocate the requested instances. */
> + if (req_inst >= 0) {
> + /* Specific instance range requested. */
> + if (req_inst + req_cnt >= inst_cnt) {
> + pr_err("Requested instance out of range\n");
> + goto err;
> + }
> +
> + for (i = 0; i < req_cnt; i++) {
> + if (*(res_addr + req_inst + 1 + i) == INST_AVAILABLE)
> + inst[i] = req_inst + i;
> + else {
braces on all branches if on any.
> + inst[0] = INST_AVAILABLE;
> + break;
> + }
> + }
> + } else if (use_last_avail) {
> + /* Last available instance requested. */
> + alloc_cnt = 0;
> + for (i = inst_cnt; i > 0; i--) {
> + if (*(res_addr + i) == INST_AVAILABLE) {
> + /*
> + * Instance off by 1 (first element holds the
> + * count).
> + */
> + inst[alloc_cnt] = i - 1;
> +
> + alloc_cnt++;
> + if (alloc_cnt == req_cnt)
> + break;
> + }
> + }
> +
> + if (i == 0)
> + inst[0] = INST_AVAILABLE;
> + } else {
> + /* Next available instance requested. */
> + alloc_cnt = 0;
> + for (i = 1; i <= inst_cnt; i++) {
> + if (*(res_addr + i) == INST_AVAILABLE) {
> + /*
> + * Instance off by 1 (first element holds the
> + * count).
> + */
> + inst[alloc_cnt] = i - 1;
> +
> + alloc_cnt++;
> + if (alloc_cnt == req_cnt)
> + break;
> + }
> + }
> +
> + if (i > inst_cnt)
> + inst[0] = INST_AVAILABLE;
> + }
> +
> + if (inst[0] != INST_AVAILABLE) {
> + for (i = 0; i < req_cnt; i++)
> + *(res_addr + inst[i] + 1) = OWNER;
> + rc = 0;
> + }
> +
> +err:
> + res_mgr_unlock();
> +
> + return rc;
> +}
> +EXPORT_SYMBOL(res_mgr_alloc_range);
> +
> +/**
> + * res_mgr_alloc - Allocate a resource instance.
> + * @tag: Identifies the resource.
> + * @req_inst: Requested instance to allocate (-1 for don't care).
> + * @use_last_avail: Set to request the last available instance.
> + *
> + * Returns: Allocated resource instance if successful.
> + * Returns <0 for error codes.
> + */
> +int res_mgr_alloc(struct global_resource_tag tag, int req_inst, bool use_last_avail)
> +{
> + int inst, rc;
> +
> + rc = res_mgr_alloc_range(tag, req_inst, 1, use_last_avail, &inst);
> + if (!rc)
> + return inst;
> + return rc;
> +}
> +EXPORT_SYMBOL(res_mgr_alloc);
> +
> +/**
> + * res_mgr_free_range - Free a resource instance range.
> + * @tag: Identifies the resource.
> + * @req_inst: Requested instance to free.
the parameter is called inst.
Other than these minor / style comments, it doesn't look unreasonable to
me.
Cheers
James
> + * @req_cnt: Number of instances to free.
> + */
> +void res_mgr_free_range(struct global_resource_tag tag, const int *inst, int req_cnt)
> +{
> + struct global_resource_entry *res_entry;
> + int res_index, i;
> + u64 *res_addr;
> +
> + res_mgr_lock();
> +
> + /* Find the resource. */
> + res_index = res_mgr_find_resource(tag);
> + if (res_index < 0) {
> + pr_err("Resource not found, can't free instance\n");
> + goto err;
> + }
> +
> + /* Get the resource data. */
> + res_entry = &res_mgr_info->resource_entry[res_index];
> + res_addr = phys_to_virt(res_entry->phys_addr);
> +
> + /* Free the resource instances. */
> + for (i = 0; i < req_cnt; i++) {
> + /* Instance off by 1 (first element holds the count). */
> + *(res_addr + inst[i] + 1) = INST_AVAILABLE;
> + }
> +
> +err:
> + res_mgr_unlock();
> +}
> +EXPORT_SYMBOL(res_mgr_free_range);
> +
> +/**
> + * res_mgr_free - Free a resource instance.
> + * @tag: Identifies the resource.
> + * @req_inst: Requested instance to free.
> + */
> +void res_mgr_free(struct global_resource_tag tag, int inst)
> +{
> + res_mgr_free_range(tag, &inst, 1);
> +}
> +EXPORT_SYMBOL(res_mgr_free);
> +
> +static int __init res_mgr_init(void)
> +{
> + struct cvmx_bootmem_named_block_desc *block;
> + int block_size;
> + u64 addr;
> +
> + cvmx_bootmem_lock();
> +
> + /* Search for the resource manager data in boot memory. */
> + block = cvmx_bootmem_phy_named_block_find(RESOURCE_MGR_BLOCK_NAME, CVMX_BOOTMEM_FLAG_NO_LOCKING);
> + if (block) {
> + /* Found. */
> + res_mgr_info = phys_to_virt(block->base_addr);
> + } else {
> + /* Create it. */
> + block_size = sizeof(struct global_resources) +
> + sizeof(struct global_resource_entry) * MAX_RESOURCES;
> + addr = cvmx_bootmem_phy_named_block_alloc(block_size, 0, 0,
> + CVMX_CACHE_LINE_SIZE, RESOURCE_MGR_BLOCK_NAME,
> + CVMX_BOOTMEM_FLAG_NO_LOCKING);
> + if (!addr) {
> + pr_err("Failed to allocate name block %s\n",
> + RESOURCE_MGR_BLOCK_NAME);
> + } else {
> + res_mgr_info = phys_to_virt(addr);
> + memset(res_mgr_info, 0, block_size);
> + }
> + }
> +
> + cvmx_bootmem_unlock();
> +
> + return 0;
> +}
> +device_initcall(res_mgr_init);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Cavium, Inc. Octeon resource manager");
> diff --git a/arch/mips/include/asm/octeon/octeon.h b/arch/mips/include/asm/octeon/octeon.h
> index 92a17d67c1fa..0411efdb465c 100644
> --- a/arch/mips/include/asm/octeon/octeon.h
> +++ b/arch/mips/include/asm/octeon/octeon.h
> @@ -346,6 +346,24 @@ void octeon_mult_restore3_end(void);
> void octeon_mult_restore2(void);
> void octeon_mult_restore2_end(void);
>
> +/*
> + * This definition must be kept in sync with the one in
> + * cvmx-global-resources.c
> + */
> +struct global_resource_tag {
> + uint64_t lo;
> + uint64_t hi;
> +};
> +
> +void res_mgr_free(struct global_resource_tag tag, int inst);
> +void res_mgr_free_range(struct global_resource_tag tag, const int *inst,
> + int req_cnt);
> +int res_mgr_alloc(struct global_resource_tag tag, int req_inst,
> + bool use_last_avail);
> +int res_mgr_alloc_range(struct global_resource_tag tag, int req_inst,
> + int req_cnt, bool use_last_avail, int *inst);
> +int res_mgr_create_resource(struct global_resource_tag tag, int inst_cnt);
> +
> /**
> * Read a 32bit value from the Octeon NPI register space
> *
> --
> 2.14.3
>
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* [PATCH v6 0/2] memory: Introduce ti-emif-sram driver
From: Dave Gerlach @ 2017-11-30 22:56 UTC (permalink / raw)
To: Tony Lindgren, Santosh Shilimkar
Cc: linux-arm-kernel, linux-omap, linux-kernel, devicetree,
Rob Herring, Dave Gerlach, Russell King, Keerthy J, Johan Hovold
This is a resend of v5 of this series found here [1]. It introduces
relocatable PM handlers for the emif that are copied to sram and
run from there during low power mode entry.
The patches still have the previous ACKs but have a small change to
accomodate a change made by Tony in commit cd57dc5a2099 ("ARM: dts:
Add missing hwmod related nodes for am33xx"). If there are objections
to this let me know ASAP.
Now that a hwmod is present for the am335x EMIF, on probe fail the call to
pm_runtime_put_sync causes the board to hang. In fact, this emif driver should
never alter the PM state of the hardware at all through normal kernel calls, it
is the job of the suspend handlers that are added, that is the whole point of
this driver. Because of this, I have dropped all runtime pm calls, as any
change to the PM state while the kernel is running is dangerous as we may shut
of the memory controller. It makes the most sense just to drop runtime PM from
the driver entirely. Besides that patch is unchanged.
This code is required for low-power modes to work on AM335x and AM437x and a
forthcoming PM series for those platforms will depend on this series. After
both this and the PM series are reviewed I will send the necessary device tree
changes for both, but in the meantime all remaining patches for am335x and
am437x PM can be found here [2].
Regards,
Dave
[1] https://www.spinics.net/lists/arm-kernel/msg611537.html
[2] https://github.com/dgerlach/linux-pm/tree/upstream/v4.15/amx3-suspend-v6
Dave Gerlach (2):
Documentation: dt: Update ti,emif bindings
memory: ti-emif-sram: introduce relocatable suspend/resume handlers
.../bindings/memory-controllers/ti/emif.txt | 17 +-
drivers/memory/Kconfig | 10 +
drivers/memory/Makefile | 8 +
drivers/memory/Makefile.asm-offsets | 5 +
drivers/memory/emif-asm-offsets.c | 92 ++++++
drivers/memory/emif.h | 17 ++
drivers/memory/ti-emif-pm.c | 325 ++++++++++++++++++++
drivers/memory/ti-emif-sram-pm.S | 334 +++++++++++++++++++++
include/linux/ti-emif-sram.h | 69 +++++
9 files changed, 876 insertions(+), 1 deletion(-)
create mode 100644 drivers/memory/Makefile.asm-offsets
create mode 100644 drivers/memory/emif-asm-offsets.c
create mode 100644 drivers/memory/ti-emif-pm.c
create mode 100644 drivers/memory/ti-emif-sram-pm.S
create mode 100644 include/linux/ti-emif-sram.h
--
2.15.0
^ permalink raw reply
* [PATCH v6 1/2] Documentation: dt: Update ti,emif bindings
From: Dave Gerlach @ 2017-11-30 22:56 UTC (permalink / raw)
To: Tony Lindgren, Santosh Shilimkar
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-omap-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Dave Gerlach,
Russell King, Keerthy J, Johan Hovold
In-Reply-To: <1512082568-5012-1-git-send-email-d-gerlach-l0cyMroinI0@public.gmane.org>
Update the Texas Instruments EMIF binding document to include the device
tree bindings for ti,emif-am3352 and ti,emif-am4372 which are used by
the ti-emif-sram driver to provide low-level PM functionality.
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Acked-by: Tony Lindgren <tony-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Dave Gerlach <d-gerlach-l0cyMroinI0@public.gmane.org>
---
.../devicetree/bindings/memory-controllers/ti/emif.txt | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/memory-controllers/ti/emif.txt b/Documentation/devicetree/bindings/memory-controllers/ti/emif.txt
index fd823d6091b2..29a99871e808 100644
--- a/Documentation/devicetree/bindings/memory-controllers/ti/emif.txt
+++ b/Documentation/devicetree/bindings/memory-controllers/ti/emif.txt
@@ -23,6 +23,13 @@ Required properties:
the value shall be "emif<n>" where <n> is the number of the EMIF
instance with base 1.
+Required only for "ti,emif-am3352" and "ti,emif-am4372":
+- sram : Phandles for generic sram driver nodes,
+ first should be type 'protect-exec' for the driver to use to copy
+ and run PM functions, second should be regular pool to be used for
+ data region for code. See Documentation/devicetree/bindings/sram/sram.txt
+ for more details.
+
Optional properties:
- cs1-used : Have this property if CS1 of this EMIF
instance has a memory part attached to it. If there is a memory
@@ -44,7 +51,7 @@ Optional properties:
- hw-caps-temp-alert : Have this property if the controller
has capability for generating SDRAM temperature alerts
-Example:
+-Examples:
emif1: emif@0x4c000000 {
compatible = "ti,emif-4d";
@@ -56,3 +63,11 @@ emif1: emif@0x4c000000 {
hw-caps-ll-interface;
hw-caps-temp-alert;
};
+
+/* From am33xx.dtsi */
+emif: emif@4c000000 {
+ compatible = "ti,emif-am3352";
+ reg = <0x4C000000 0x1000>;
+ sram = <&pm_sram_code
+ &pm_sram_data>;
+};
--
2.15.0
--
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 v6 2/2] memory: ti-emif-sram: introduce relocatable suspend/resume handlers
From: Dave Gerlach @ 2017-11-30 22:56 UTC (permalink / raw)
To: Tony Lindgren, Santosh Shilimkar
Cc: linux-arm-kernel, linux-omap, linux-kernel, devicetree,
Rob Herring, Dave Gerlach, Russell King, Keerthy J, Johan Hovold
In-Reply-To: <1512082568-5012-1-git-send-email-d-gerlach@ti.com>
Certain SoCs like Texas Instruments AM335x and AM437x require parts
of the EMIF PM code to run late in the suspend sequence from SRAM,
such as saving and restoring the EMIF context and placing the memory
into self-refresh.
One requirement for these SoCs to suspend and enter its lowest power
mode, called DeepSleep0, is that the PER power domain must be shut off.
Because the EMIF (DDR Controller) resides within this power domain, it
will lose context during a suspend operation, so we must save it so we
can restore once we resume. However, we cannot execute this code from
external memory, as it is not available at this point, so the code must
be executed late in the suspend path from SRAM.
This patch introduces a ti-emif-sram driver that includes several
functions written in ARM ASM that are relocatable so the PM SRAM
code can use them. It also allocates a region of writable SRAM to
be used by the code running in the executable region of SRAM to save
and restore the EMIF context. It can export a table containing the
absolute addresses of the available PM functions so that other SRAM
code can branch to them. This code is required for suspend/resume on
AM335x and AM437x to work.
In addition to this, to be able to share data structures between C and
the ti-emif-sram-pm assembly code, we can automatically generate all of
the C struct member offsets and sizes as macros by processing
emif-asm-offsets.c into assembly code and then extracting the relevant
data as is done for the generated platform asm-offsets.h files.
Acked-by: Tony Lindgren <tony@atomide.com>
Acked-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
---
drivers/memory/Kconfig | 10 ++
drivers/memory/Makefile | 8 +
drivers/memory/Makefile.asm-offsets | 5 +
drivers/memory/emif-asm-offsets.c | 92 ++++++++++
drivers/memory/emif.h | 17 ++
drivers/memory/ti-emif-pm.c | 325 +++++++++++++++++++++++++++++++++++
drivers/memory/ti-emif-sram-pm.S | 334 ++++++++++++++++++++++++++++++++++++
include/linux/ti-emif-sram.h | 69 ++++++++
8 files changed, 860 insertions(+)
create mode 100644 drivers/memory/Makefile.asm-offsets
create mode 100644 drivers/memory/emif-asm-offsets.c
create mode 100644 drivers/memory/ti-emif-pm.c
create mode 100644 drivers/memory/ti-emif-sram-pm.S
create mode 100644 include/linux/ti-emif-sram.h
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index ffc350258041..19a0e83f260d 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -84,6 +84,16 @@ config OMAP_GPMC_DEBUG
bootloader or else the GPMC timings won't be identical with the
bootloader timings.
+config TI_EMIF_SRAM
+ tristate "Texas Instruments EMIF SRAM driver"
+ depends on (SOC_AM33XX || SOC_AM43XX) && SRAM
+ help
+ This driver is for the EMIF module available on Texas Instruments
+ AM33XX and AM43XX SoCs and is required for PM. Certain parts of
+ the EMIF PM code must run from on-chip SRAM late in the suspend
+ sequence so this driver provides several relocatable PM functions
+ for the SoC PM code to use.
+
config MVEBU_DEVBUS
bool "Marvell EBU Device Bus Controller"
default y
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
index 929a601d4cd1..66f55240830e 100644
--- a/drivers/memory/Makefile
+++ b/drivers/memory/Makefile
@@ -23,3 +23,11 @@ obj-$(CONFIG_DA8XX_DDRCTL) += da8xx-ddrctl.o
obj-$(CONFIG_SAMSUNG_MC) += samsung/
obj-$(CONFIG_TEGRA_MC) += tegra/
+obj-$(CONFIG_TI_EMIF_SRAM) += ti-emif-sram.o
+ti-emif-sram-objs := ti-emif-pm.o ti-emif-sram-pm.o
+
+AFLAGS_ti-emif-sram-pm.o :=-Wa,-march=armv7-a
+
+include drivers/memory/Makefile.asm-offsets
+
+drivers/memory/ti-emif-sram-pm.o: include/generated/ti-emif-asm-offsets.h
diff --git a/drivers/memory/Makefile.asm-offsets b/drivers/memory/Makefile.asm-offsets
new file mode 100644
index 000000000000..843ff60ccb5a
--- /dev/null
+++ b/drivers/memory/Makefile.asm-offsets
@@ -0,0 +1,5 @@
+drivers/memory/emif-asm-offsets.s: drivers/memory/emif-asm-offsets.c
+ $(call if_changed_dep,cc_s_c)
+
+include/generated/ti-emif-asm-offsets.h: drivers/memory/emif-asm-offsets.s FORCE
+ $(call filechk,offsets,__TI_EMIF_ASM_OFFSETS_H__)
diff --git a/drivers/memory/emif-asm-offsets.c b/drivers/memory/emif-asm-offsets.c
new file mode 100644
index 000000000000..71a89d5d3efd
--- /dev/null
+++ b/drivers/memory/emif-asm-offsets.c
@@ -0,0 +1,92 @@
+/*
+ * TI AM33XX EMIF PM Assembly Offsets
+ *
+ * Copyright (C) 2016-2017 Texas Instruments 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/ti-emif-sram.h>
+
+int main(void)
+{
+ DEFINE(EMIF_SDCFG_VAL_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_sdcfg_val));
+ DEFINE(EMIF_TIMING1_VAL_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_timing1_val));
+ DEFINE(EMIF_TIMING2_VAL_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_timing2_val));
+ DEFINE(EMIF_TIMING3_VAL_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_timing3_val));
+ DEFINE(EMIF_REF_CTRL_VAL_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_ref_ctrl_val));
+ DEFINE(EMIF_ZQCFG_VAL_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_zqcfg_val));
+ DEFINE(EMIF_PMCR_VAL_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_pmcr_val));
+ DEFINE(EMIF_PMCR_SHDW_VAL_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_pmcr_shdw_val));
+ DEFINE(EMIF_RD_WR_LEVEL_RAMP_CTRL_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_rd_wr_level_ramp_ctrl));
+ DEFINE(EMIF_RD_WR_EXEC_THRESH_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_rd_wr_exec_thresh));
+ DEFINE(EMIF_COS_CONFIG_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_cos_config));
+ DEFINE(EMIF_PRIORITY_TO_COS_MAPPING_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_priority_to_cos_mapping));
+ DEFINE(EMIF_CONNECT_ID_SERV_1_MAP_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_connect_id_serv_1_map));
+ DEFINE(EMIF_CONNECT_ID_SERV_2_MAP_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_connect_id_serv_2_map));
+ DEFINE(EMIF_OCP_CONFIG_VAL_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_ocp_config_val));
+ DEFINE(EMIF_LPDDR2_NVM_TIM_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_lpddr2_nvm_tim));
+ DEFINE(EMIF_LPDDR2_NVM_TIM_SHDW_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_lpddr2_nvm_tim_shdw));
+ DEFINE(EMIF_DLL_CALIB_CTRL_VAL_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_dll_calib_ctrl_val));
+ DEFINE(EMIF_DLL_CALIB_CTRL_VAL_SHDW_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_dll_calib_ctrl_val_shdw));
+ DEFINE(EMIF_DDR_PHY_CTLR_1_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_ddr_phy_ctlr_1));
+ DEFINE(EMIF_EXT_PHY_CTRL_VALS_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_ext_phy_ctrl_vals));
+ DEFINE(EMIF_REGS_AMX3_SIZE, sizeof(struct emif_regs_amx3));
+
+ BLANK();
+
+ DEFINE(EMIF_PM_BASE_ADDR_VIRT_OFFSET,
+ offsetof(struct ti_emif_pm_data, ti_emif_base_addr_virt));
+ DEFINE(EMIF_PM_BASE_ADDR_PHYS_OFFSET,
+ offsetof(struct ti_emif_pm_data, ti_emif_base_addr_phys));
+ DEFINE(EMIF_PM_CONFIG_OFFSET,
+ offsetof(struct ti_emif_pm_data, ti_emif_sram_config));
+ DEFINE(EMIF_PM_REGS_VIRT_OFFSET,
+ offsetof(struct ti_emif_pm_data, regs_virt));
+ DEFINE(EMIF_PM_REGS_PHYS_OFFSET,
+ offsetof(struct ti_emif_pm_data, regs_phys));
+ DEFINE(EMIF_PM_DATA_SIZE, sizeof(struct ti_emif_pm_data));
+
+ BLANK();
+
+ DEFINE(EMIF_PM_SAVE_CONTEXT_OFFSET,
+ offsetof(struct ti_emif_pm_functions, save_context));
+ DEFINE(EMIF_PM_RESTORE_CONTEXT_OFFSET,
+ offsetof(struct ti_emif_pm_functions, restore_context));
+ DEFINE(EMIF_PM_ENTER_SR_OFFSET,
+ offsetof(struct ti_emif_pm_functions, enter_sr));
+ DEFINE(EMIF_PM_EXIT_SR_OFFSET,
+ offsetof(struct ti_emif_pm_functions, exit_sr));
+ DEFINE(EMIF_PM_ABORT_SR_OFFSET,
+ offsetof(struct ti_emif_pm_functions, abort_sr));
+ DEFINE(EMIF_PM_FUNCTIONS_SIZE, sizeof(struct ti_emif_pm_functions));
+
+ return 0;
+}
diff --git a/drivers/memory/emif.h b/drivers/memory/emif.h
index bfe08bae961a..9e9f8037955d 100644
--- a/drivers/memory/emif.h
+++ b/drivers/memory/emif.h
@@ -555,6 +555,9 @@
#define READ_LATENCY_SHDW_SHIFT 0
#define READ_LATENCY_SHDW_MASK (0x1f << 0)
+#define EMIF_SRAM_AM33_REG_LAYOUT 0x00000000
+#define EMIF_SRAM_AM43_REG_LAYOUT 0x00000001
+
#ifndef __ASSEMBLY__
/*
* Structure containing shadow of important registers in EMIF
@@ -585,5 +588,19 @@ struct emif_regs {
u32 ext_phy_ctrl_3_shdw;
u32 ext_phy_ctrl_4_shdw;
};
+
+struct ti_emif_pm_functions;
+
+extern unsigned int ti_emif_sram;
+extern unsigned int ti_emif_sram_sz;
+extern struct ti_emif_pm_data ti_emif_pm_sram_data;
+extern struct emif_regs_amx3 ti_emif_regs_amx3;
+
+void ti_emif_save_context(void);
+void ti_emif_restore_context(void);
+void ti_emif_enter_sr(void);
+void ti_emif_exit_sr(void);
+void ti_emif_abort_sr(void);
+
#endif /* __ASSEMBLY__ */
#endif /* __EMIF_H */
diff --git a/drivers/memory/ti-emif-pm.c b/drivers/memory/ti-emif-pm.c
new file mode 100644
index 000000000000..4ea1514fb9b2
--- /dev/null
+++ b/drivers/memory/ti-emif-pm.c
@@ -0,0 +1,325 @@
+/*
+ * TI AM33XX SRAM EMIF Driver
+ *
+ * Copyright (C) 2016-2017 Texas Instruments Inc.
+ * Dave Gerlach
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/genalloc.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/sram.h>
+#include <linux/ti-emif-sram.h>
+
+#include "emif.h"
+
+#define TI_EMIF_SRAM_SYMBOL_OFFSET(sym) ((unsigned long)(sym) - \
+ (unsigned long)&ti_emif_sram)
+
+#define EMIF_POWER_MGMT_WAIT_SELF_REFRESH_8192_CYCLES 0x00a0
+
+struct ti_emif_data {
+ phys_addr_t ti_emif_sram_phys;
+ phys_addr_t ti_emif_sram_data_phys;
+ unsigned long ti_emif_sram_virt;
+ unsigned long ti_emif_sram_data_virt;
+ struct gen_pool *sram_pool_code;
+ struct gen_pool *sram_pool_data;
+ struct ti_emif_pm_data pm_data;
+ struct ti_emif_pm_functions pm_functions;
+};
+
+static struct ti_emif_data *emif_instance;
+
+static u32 sram_suspend_address(struct ti_emif_data *emif_data,
+ unsigned long addr)
+{
+ return (emif_data->ti_emif_sram_virt +
+ TI_EMIF_SRAM_SYMBOL_OFFSET(addr));
+}
+
+static phys_addr_t sram_resume_address(struct ti_emif_data *emif_data,
+ unsigned long addr)
+{
+ return ((unsigned long)emif_data->ti_emif_sram_phys +
+ TI_EMIF_SRAM_SYMBOL_OFFSET(addr));
+}
+
+static void ti_emif_free_sram(struct ti_emif_data *emif_data)
+{
+ gen_pool_free(emif_data->sram_pool_code, emif_data->ti_emif_sram_virt,
+ ti_emif_sram_sz);
+ gen_pool_free(emif_data->sram_pool_data,
+ emif_data->ti_emif_sram_data_virt,
+ sizeof(struct emif_regs_amx3));
+}
+
+static int ti_emif_alloc_sram(struct device *dev,
+ struct ti_emif_data *emif_data)
+{
+ struct device_node *np = dev->of_node;
+ int ret;
+
+ emif_data->sram_pool_code = of_gen_pool_get(np, "sram", 0);
+ if (!emif_data->sram_pool_code) {
+ dev_err(dev, "Unable to get sram pool for ocmcram code\n");
+ return -ENODEV;
+ }
+
+ emif_data->ti_emif_sram_virt =
+ gen_pool_alloc(emif_data->sram_pool_code,
+ ti_emif_sram_sz);
+ if (!emif_data->ti_emif_sram_virt) {
+ dev_err(dev, "Unable to allocate code memory from ocmcram\n");
+ return -ENOMEM;
+ }
+
+ /* Save physical address to calculate resume offset during pm init */
+ emif_data->ti_emif_sram_phys =
+ gen_pool_virt_to_phys(emif_data->sram_pool_code,
+ emif_data->ti_emif_sram_virt);
+
+ /* Get sram pool for data section and allocate space */
+ emif_data->sram_pool_data = of_gen_pool_get(np, "sram", 1);
+ if (!emif_data->sram_pool_data) {
+ dev_err(dev, "Unable to get sram pool for ocmcram data\n");
+ ret = -ENODEV;
+ goto err_free_sram_code;
+ }
+
+ emif_data->ti_emif_sram_data_virt =
+ gen_pool_alloc(emif_data->sram_pool_data,
+ sizeof(struct emif_regs_amx3));
+ if (!emif_data->ti_emif_sram_data_virt) {
+ dev_err(dev, "Unable to allocate data memory from ocmcram\n");
+ ret = -ENOMEM;
+ goto err_free_sram_code;
+ }
+
+ /* Save physical address to calculate resume offset during pm init */
+ emif_data->ti_emif_sram_data_phys =
+ gen_pool_virt_to_phys(emif_data->sram_pool_data,
+ emif_data->ti_emif_sram_data_virt);
+ /*
+ * These functions are called during suspend path while MMU is
+ * still on so add virtual base to offset for absolute address
+ */
+ emif_data->pm_functions.save_context =
+ sram_suspend_address(emif_data,
+ (unsigned long)ti_emif_save_context);
+ emif_data->pm_functions.enter_sr =
+ sram_suspend_address(emif_data,
+ (unsigned long)ti_emif_enter_sr);
+ emif_data->pm_functions.abort_sr =
+ sram_suspend_address(emif_data,
+ (unsigned long)ti_emif_abort_sr);
+
+ /*
+ * These are called during resume path when MMU is not enabled
+ * so physical address is used instead
+ */
+ emif_data->pm_functions.restore_context =
+ sram_resume_address(emif_data,
+ (unsigned long)ti_emif_restore_context);
+ emif_data->pm_functions.exit_sr =
+ sram_resume_address(emif_data,
+ (unsigned long)ti_emif_exit_sr);
+
+ emif_data->pm_data.regs_virt =
+ (struct emif_regs_amx3 *)emif_data->ti_emif_sram_data_virt;
+ emif_data->pm_data.regs_phys = emif_data->ti_emif_sram_data_phys;
+
+ return 0;
+
+err_free_sram_code:
+ gen_pool_free(emif_data->sram_pool_code, emif_data->ti_emif_sram_virt,
+ ti_emif_sram_sz);
+ return ret;
+}
+
+static int ti_emif_push_sram(struct device *dev, struct ti_emif_data *emif_data)
+{
+ void *copy_addr;
+ u32 data_addr;
+
+ copy_addr = sram_exec_copy(emif_data->sram_pool_code,
+ (void *)emif_data->ti_emif_sram_virt,
+ &ti_emif_sram, ti_emif_sram_sz);
+ if (!copy_addr) {
+ dev_err(dev, "Cannot copy emif code to sram\n");
+ return -ENODEV;
+ }
+
+ data_addr = sram_suspend_address(emif_data,
+ (unsigned long)&ti_emif_pm_sram_data);
+ copy_addr = sram_exec_copy(emif_data->sram_pool_code,
+ (void *)data_addr,
+ &emif_data->pm_data,
+ sizeof(emif_data->pm_data));
+ if (!copy_addr) {
+ dev_err(dev, "Cannot copy emif data to code sram\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/*
+ * Due to Usage Note 3.1.2 "DDR3: JEDEC Compliance for Maximum
+ * Self-Refresh Command Limit" found in AM335x Silicon Errata
+ * (Document SPRZ360F Revised November 2013) we must configure
+ * the self refresh delay timer to 0xA (8192 cycles) to avoid
+ * generating too many refresh command from the EMIF.
+ */
+static void ti_emif_configure_sr_delay(struct ti_emif_data *emif_data)
+{
+ writel(EMIF_POWER_MGMT_WAIT_SELF_REFRESH_8192_CYCLES,
+ (emif_data->pm_data.ti_emif_base_addr_virt +
+ EMIF_POWER_MANAGEMENT_CONTROL));
+
+ writel(EMIF_POWER_MGMT_WAIT_SELF_REFRESH_8192_CYCLES,
+ (emif_data->pm_data.ti_emif_base_addr_virt +
+ EMIF_POWER_MANAGEMENT_CTRL_SHDW));
+}
+
+/**
+ * ti_emif_copy_pm_function_table - copy mapping of pm funcs in sram
+ * @sram_pool: pointer to struct gen_pool where dst resides
+ * @dst: void * to address that table should be copied
+ *
+ * Returns 0 if success other error code if table is not available
+ */
+int ti_emif_copy_pm_function_table(struct gen_pool *sram_pool, void *dst)
+{
+ void *copy_addr;
+
+ if (!emif_instance)
+ return -ENODEV;
+
+ copy_addr = sram_exec_copy(sram_pool, dst,
+ &emif_instance->pm_functions,
+ sizeof(emif_instance->pm_functions));
+ if (!copy_addr)
+ return -ENODEV;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ti_emif_copy_pm_function_table);
+
+/**
+ * ti_emif_get_mem_type - return type for memory type in use
+ *
+ * Returns memory type value read from EMIF or error code if fails
+ */
+int ti_emif_get_mem_type(void)
+{
+ unsigned long temp;
+
+ if (!emif_instance)
+ return -ENODEV;
+
+ temp = readl(emif_instance->pm_data.ti_emif_base_addr_virt +
+ EMIF_SDRAM_CONFIG);
+
+ temp = (temp & SDRAM_TYPE_MASK) >> SDRAM_TYPE_SHIFT;
+ return temp;
+}
+EXPORT_SYMBOL_GPL(ti_emif_get_mem_type);
+
+static const struct of_device_id ti_emif_of_match[] = {
+ { .compatible = "ti,emif-am3352", .data =
+ (void *)EMIF_SRAM_AM33_REG_LAYOUT, },
+ { .compatible = "ti,emif-am4372", .data =
+ (void *)EMIF_SRAM_AM43_REG_LAYOUT, },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ti_emif_of_match);
+
+static int ti_emif_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+ const struct of_device_id *match;
+ struct ti_emif_data *emif_data;
+
+ emif_data = devm_kzalloc(dev, sizeof(*emif_data), GFP_KERNEL);
+ if (!emif_data)
+ return -ENOMEM;
+
+ match = of_match_device(ti_emif_of_match, &pdev->dev);
+ if (!match)
+ return -ENODEV;
+
+ emif_data->pm_data.ti_emif_sram_config = (unsigned long)match->data;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ emif_data->pm_data.ti_emif_base_addr_virt = devm_ioremap_resource(dev,
+ res);
+ if (IS_ERR(emif_data->pm_data.ti_emif_base_addr_virt)) {
+ dev_err(dev, "could not ioremap emif mem\n");
+ ret = PTR_ERR(emif_data->pm_data.ti_emif_base_addr_virt);
+ return ret;
+ }
+
+ emif_data->pm_data.ti_emif_base_addr_phys = res->start;
+
+ ti_emif_configure_sr_delay(emif_data);
+
+ ret = ti_emif_alloc_sram(dev, emif_data);
+ if (ret)
+ return ret;
+
+ ret = ti_emif_push_sram(dev, emif_data);
+ if (ret)
+ goto fail_free_sram;
+
+ emif_instance = emif_data;
+
+ return 0;
+
+fail_free_sram:
+ ti_emif_free_sram(emif_data);
+
+ return ret;
+}
+
+static int ti_emif_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ti_emif_data *emif_data = emif_instance;
+
+ emif_instance = NULL;
+
+ ti_emif_free_sram(emif_data);
+
+ return 0;
+}
+
+static struct platform_driver ti_emif_driver = {
+ .probe = ti_emif_probe,
+ .remove = ti_emif_remove,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = of_match_ptr(ti_emif_of_match),
+ },
+};
+module_platform_driver(ti_emif_driver);
+
+MODULE_AUTHOR("Dave Gerlach <d-gerlach@ti.com>");
+MODULE_DESCRIPTION("Texas Instruments SRAM EMIF driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/memory/ti-emif-sram-pm.S b/drivers/memory/ti-emif-sram-pm.S
new file mode 100644
index 000000000000..a5369181e5c2
--- /dev/null
+++ b/drivers/memory/ti-emif-sram-pm.S
@@ -0,0 +1,334 @@
+/*
+ * Low level PM code for TI EMIF
+ *
+ * Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Dave Gerlach
+ *
+ * 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.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <generated/ti-emif-asm-offsets.h>
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/memory.h>
+
+#include "emif.h"
+
+#define EMIF_POWER_MGMT_WAIT_SELF_REFRESH_8192_CYCLES 0x00a0
+#define EMIF_POWER_MGMT_SR_TIMER_MASK 0x00f0
+#define EMIF_POWER_MGMT_SELF_REFRESH_MODE 0x0200
+#define EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK 0x0700
+
+#define EMIF_SDCFG_TYPE_DDR2 0x2 << SDRAM_TYPE_SHIFT
+#define EMIF_STATUS_READY 0x4
+
+#define AM43XX_EMIF_PHY_CTRL_REG_COUNT 0x120
+
+#define EMIF_AM437X_REGISTERS 0x1
+
+ .arm
+ .align 3
+
+ENTRY(ti_emif_sram)
+
+/*
+ * void ti_emif_save_context(void)
+ *
+ * Used during suspend to save the context of all required EMIF registers
+ * to local memory if the EMIF is going to lose context during the sleep
+ * transition. Operates on the VIRTUAL address of the EMIF.
+ */
+ENTRY(ti_emif_save_context)
+ stmfd sp!, {r4 - r11, lr} @ save registers on stack
+
+ adr r4, ti_emif_pm_sram_data
+ ldr r0, [r4, #EMIF_PM_BASE_ADDR_VIRT_OFFSET]
+ ldr r2, [r4, #EMIF_PM_REGS_VIRT_OFFSET]
+
+ /* Save EMIF configuration */
+ ldr r1, [r0, #EMIF_SDRAM_CONFIG]
+ str r1, [r2, #EMIF_SDCFG_VAL_OFFSET]
+
+ ldr r1, [r0, #EMIF_SDRAM_REFRESH_CONTROL]
+ str r1, [r2, #EMIF_REF_CTRL_VAL_OFFSET]
+
+ ldr r1, [r0, #EMIF_SDRAM_TIMING_1]
+ str r1, [r2, #EMIF_TIMING1_VAL_OFFSET]
+
+ ldr r1, [r0, #EMIF_SDRAM_TIMING_2]
+ str r1, [r2, #EMIF_TIMING2_VAL_OFFSET]
+
+ ldr r1, [r0, #EMIF_SDRAM_TIMING_3]
+ str r1, [r2, #EMIF_TIMING3_VAL_OFFSET]
+
+ ldr r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+ str r1, [r2, #EMIF_PMCR_VAL_OFFSET]
+
+ ldr r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
+ str r1, [r2, #EMIF_PMCR_SHDW_VAL_OFFSET]
+
+ ldr r1, [r0, #EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG]
+ str r1, [r2, #EMIF_ZQCFG_VAL_OFFSET]
+
+ ldr r1, [r0, #EMIF_DDR_PHY_CTRL_1]
+ str r1, [r2, #EMIF_DDR_PHY_CTLR_1_OFFSET]
+
+ ldr r1, [r0, #EMIF_COS_CONFIG]
+ str r1, [r2, #EMIF_COS_CONFIG_OFFSET]
+
+ ldr r1, [r0, #EMIF_PRIORITY_TO_CLASS_OF_SERVICE_MAPPING]
+ str r1, [r2, #EMIF_PRIORITY_TO_COS_MAPPING_OFFSET]
+
+ ldr r1, [r0, #EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_1_MAPPING]
+ str r1, [r2, #EMIF_CONNECT_ID_SERV_1_MAP_OFFSET]
+
+ ldr r1, [r0, #EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_2_MAPPING]
+ str r1, [r2, #EMIF_CONNECT_ID_SERV_2_MAP_OFFSET]
+
+ ldr r1, [r0, #EMIF_OCP_CONFIG]
+ str r1, [r2, #EMIF_OCP_CONFIG_VAL_OFFSET]
+
+ ldr r5, [r4, #EMIF_PM_CONFIG_OFFSET]
+ cmp r5, #EMIF_SRAM_AM43_REG_LAYOUT
+ bne emif_skip_save_extra_regs
+
+ ldr r1, [r0, #EMIF_READ_WRITE_LEVELING_RAMP_CONTROL]
+ str r1, [r2, #EMIF_RD_WR_LEVEL_RAMP_CTRL_OFFSET]
+
+ ldr r1, [r0, #EMIF_READ_WRITE_EXECUTION_THRESHOLD]
+ str r1, [r2, #EMIF_RD_WR_EXEC_THRESH_OFFSET]
+
+ ldr r1, [r0, #EMIF_LPDDR2_NVM_TIMING]
+ str r1, [r2, #EMIF_LPDDR2_NVM_TIM_OFFSET]
+
+ ldr r1, [r0, #EMIF_LPDDR2_NVM_TIMING_SHDW]
+ str r1, [r2, #EMIF_LPDDR2_NVM_TIM_SHDW_OFFSET]
+
+ ldr r1, [r0, #EMIF_DLL_CALIB_CTRL]
+ str r1, [r2, #EMIF_DLL_CALIB_CTRL_VAL_OFFSET]
+
+ ldr r1, [r0, #EMIF_DLL_CALIB_CTRL_SHDW]
+ str r1, [r2, #EMIF_DLL_CALIB_CTRL_VAL_SHDW_OFFSET]
+
+ /* Loop and save entire block of emif phy regs */
+ mov r5, #0x0
+ add r4, r2, #EMIF_EXT_PHY_CTRL_VALS_OFFSET
+ add r3, r0, #EMIF_EXT_PHY_CTRL_1
+ddr_phy_ctrl_save:
+ ldr r1, [r3, r5]
+ str r1, [r4, r5]
+ add r5, r5, #0x4
+ cmp r5, #AM43XX_EMIF_PHY_CTRL_REG_COUNT
+ bne ddr_phy_ctrl_save
+
+emif_skip_save_extra_regs:
+ ldmfd sp!, {r4 - r11, pc} @ restore regs and return
+ENDPROC(ti_emif_save_context)
+
+/*
+ * void ti_emif_restore_context(void)
+ *
+ * Used during resume to restore the context of all required EMIF registers
+ * from local memory after the EMIF has lost context during a sleep transition.
+ * Operates on the PHYSICAL address of the EMIF.
+ */
+ENTRY(ti_emif_restore_context)
+ adr r4, ti_emif_pm_sram_data
+ ldr r0, [r4, #EMIF_PM_BASE_ADDR_PHYS_OFFSET]
+ ldr r2, [r4, #EMIF_PM_REGS_PHYS_OFFSET]
+
+ /* Config EMIF Timings */
+ ldr r1, [r2, #EMIF_DDR_PHY_CTLR_1_OFFSET]
+ str r1, [r0, #EMIF_DDR_PHY_CTRL_1]
+ str r1, [r0, #EMIF_DDR_PHY_CTRL_1_SHDW]
+
+ ldr r1, [r2, #EMIF_TIMING1_VAL_OFFSET]
+ str r1, [r0, #EMIF_SDRAM_TIMING_1]
+ str r1, [r0, #EMIF_SDRAM_TIMING_1_SHDW]
+
+ ldr r1, [r2, #EMIF_TIMING2_VAL_OFFSET]
+ str r1, [r0, #EMIF_SDRAM_TIMING_2]
+ str r1, [r0, #EMIF_SDRAM_TIMING_2_SHDW]
+
+ ldr r1, [r2, #EMIF_TIMING3_VAL_OFFSET]
+ str r1, [r0, #EMIF_SDRAM_TIMING_3]
+ str r1, [r0, #EMIF_SDRAM_TIMING_3_SHDW]
+
+ ldr r1, [r2, #EMIF_REF_CTRL_VAL_OFFSET]
+ str r1, [r0, #EMIF_SDRAM_REFRESH_CONTROL]
+ str r1, [r0, #EMIF_SDRAM_REFRESH_CTRL_SHDW]
+
+ ldr r1, [r2, #EMIF_PMCR_VAL_OFFSET]
+ str r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+
+ ldr r1, [r2, #EMIF_PMCR_SHDW_VAL_OFFSET]
+ str r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
+
+ ldr r1, [r2, #EMIF_COS_CONFIG_OFFSET]
+ str r1, [r0, #EMIF_COS_CONFIG]
+
+ ldr r1, [r2, #EMIF_PRIORITY_TO_COS_MAPPING_OFFSET]
+ str r1, [r0, #EMIF_PRIORITY_TO_CLASS_OF_SERVICE_MAPPING]
+
+ ldr r1, [r2, #EMIF_CONNECT_ID_SERV_1_MAP_OFFSET]
+ str r1, [r0, #EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_1_MAPPING]
+
+ ldr r1, [r2, #EMIF_CONNECT_ID_SERV_2_MAP_OFFSET]
+ str r1, [r0, #EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_2_MAPPING]
+
+ ldr r1, [r2, #EMIF_OCP_CONFIG_VAL_OFFSET]
+ str r1, [r0, #EMIF_OCP_CONFIG]
+
+ ldr r5, [r4, #EMIF_PM_CONFIG_OFFSET]
+ cmp r5, #EMIF_SRAM_AM43_REG_LAYOUT
+ bne emif_skip_restore_extra_regs
+
+ ldr r1, [r2, #EMIF_RD_WR_LEVEL_RAMP_CTRL_OFFSET]
+ str r1, [r0, #EMIF_READ_WRITE_LEVELING_RAMP_CONTROL]
+
+ ldr r1, [r2, #EMIF_RD_WR_EXEC_THRESH_OFFSET]
+ str r1, [r0, #EMIF_READ_WRITE_EXECUTION_THRESHOLD]
+
+ ldr r1, [r2, #EMIF_LPDDR2_NVM_TIM_OFFSET]
+ str r1, [r0, #EMIF_LPDDR2_NVM_TIMING]
+
+ ldr r1, [r2, #EMIF_LPDDR2_NVM_TIM_SHDW_OFFSET]
+ str r1, [r0, #EMIF_LPDDR2_NVM_TIMING_SHDW]
+
+ ldr r1, [r2, #EMIF_DLL_CALIB_CTRL_VAL_OFFSET]
+ str r1, [r0, #EMIF_DLL_CALIB_CTRL]
+
+ ldr r1, [r2, #EMIF_DLL_CALIB_CTRL_VAL_SHDW_OFFSET]
+ str r1, [r0, #EMIF_DLL_CALIB_CTRL_SHDW]
+
+ ldr r1, [r2, #EMIF_ZQCFG_VAL_OFFSET]
+ str r1, [r0, #EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG]
+
+ /* Loop and restore entire block of emif phy regs */
+ mov r5, #0x0
+ /* Load ti_emif_regs_amx3 + EMIF_EXT_PHY_CTRL_VALS_OFFSET for address
+ * to phy register save space
+ */
+ add r3, r2, #EMIF_EXT_PHY_CTRL_VALS_OFFSET
+ add r4, r0, #EMIF_EXT_PHY_CTRL_1
+ddr_phy_ctrl_restore:
+ ldr r1, [r3, r5]
+ str r1, [r4, r5]
+ add r5, r5, #0x4
+ cmp r5, #AM43XX_EMIF_PHY_CTRL_REG_COUNT
+ bne ddr_phy_ctrl_restore
+
+emif_skip_restore_extra_regs:
+ /*
+ * Output impedence calib needed only for DDR3
+ * but since the initial state of this will be
+ * disabled for DDR2 no harm in restoring the
+ * old configuration
+ */
+ ldr r1, [r2, #EMIF_ZQCFG_VAL_OFFSET]
+ str r1, [r0, #EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG]
+
+ /* Write to sdcfg last for DDR2 only */
+ ldr r1, [r2, #EMIF_SDCFG_VAL_OFFSET]
+ and r2, r1, #SDRAM_TYPE_MASK
+ cmp r2, #EMIF_SDCFG_TYPE_DDR2
+ streq r1, [r0, #EMIF_SDRAM_CONFIG]
+
+ mov pc, lr
+ENDPROC(ti_emif_restore_context)
+
+/*
+ * void ti_emif_enter_sr(void)
+ *
+ * Programs the EMIF to tell the SDRAM to enter into self-refresh
+ * mode during a sleep transition. Operates on the VIRTUAL address
+ * of the EMIF.
+ */
+ENTRY(ti_emif_enter_sr)
+ stmfd sp!, {r4 - r11, lr} @ save registers on stack
+
+ adr r4, ti_emif_pm_sram_data
+ ldr r0, [r4, #EMIF_PM_BASE_ADDR_VIRT_OFFSET]
+ ldr r2, [r4, #EMIF_PM_REGS_VIRT_OFFSET]
+
+ ldr r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+ bic r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK
+ orr r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE
+ str r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+
+ ldmfd sp!, {r4 - r11, pc} @ restore regs and return
+ENDPROC(ti_emif_enter_sr)
+
+/*
+ * void ti_emif_exit_sr(void)
+ *
+ * Programs the EMIF to tell the SDRAM to exit self-refresh mode
+ * after a sleep transition. Operates on the PHYSICAL address of
+ * the EMIF.
+ */
+ENTRY(ti_emif_exit_sr)
+ adr r4, ti_emif_pm_sram_data
+ ldr r0, [r4, #EMIF_PM_BASE_ADDR_PHYS_OFFSET]
+ ldr r2, [r4, #EMIF_PM_REGS_PHYS_OFFSET]
+
+ /*
+ * Toggle EMIF to exit refresh mode:
+ * if EMIF lost context, PWR_MGT_CTRL is currently 0, writing disable
+ * (0x0), wont do diddly squat! so do a toggle from SR(0x2) to disable
+ * (0x0) here.
+ * *If* EMIF did not lose context, nothing broken as we write the same
+ * value(0x2) to reg before we write a disable (0x0).
+ */
+ ldr r1, [r2, #EMIF_PMCR_VAL_OFFSET]
+ bic r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK
+ orr r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE
+ str r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+ bic r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK
+ str r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+
+ /* Wait for EMIF to become ready */
+1: ldr r1, [r0, #EMIF_STATUS]
+ tst r1, #EMIF_STATUS_READY
+ beq 1b
+
+ mov pc, lr
+ENDPROC(ti_emif_exit_sr)
+
+/*
+ * void ti_emif_abort_sr(void)
+ *
+ * Disables self-refresh after a failed transition to a low-power
+ * state so the kernel can jump back to DDR and follow abort path.
+ * Operates on the VIRTUAL address of the EMIF.
+ */
+ENTRY(ti_emif_abort_sr)
+ stmfd sp!, {r4 - r11, lr} @ save registers on stack
+
+ adr r4, ti_emif_pm_sram_data
+ ldr r0, [r4, #EMIF_PM_BASE_ADDR_VIRT_OFFSET]
+ ldr r2, [r4, #EMIF_PM_REGS_VIRT_OFFSET]
+
+ ldr r1, [r2, #EMIF_PMCR_VAL_OFFSET]
+ bic r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK
+ str r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+
+ /* Wait for EMIF to become ready */
+1: ldr r1, [r0, #EMIF_STATUS]
+ tst r1, #EMIF_STATUS_READY
+ beq 1b
+
+ ldmfd sp!, {r4 - r11, pc} @ restore regs and return
+ENDPROC(ti_emif_abort_sr)
+
+ .align 3
+ENTRY(ti_emif_pm_sram_data)
+ .space EMIF_PM_DATA_SIZE
+ENTRY(ti_emif_sram_sz)
+ .word . - ti_emif_save_context
diff --git a/include/linux/ti-emif-sram.h b/include/linux/ti-emif-sram.h
new file mode 100644
index 000000000000..45bc6b376492
--- /dev/null
+++ b/include/linux/ti-emif-sram.h
@@ -0,0 +1,69 @@
+/*
+ * TI AM33XX EMIF Routines
+ *
+ * Copyright (C) 2016-2017 Texas Instruments Inc.
+ * Dave Gerlach
+ *
+ * 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.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __LINUX_TI_EMIF_H
+#define __LINUX_TI_EMIF_H
+
+#include <linux/kbuild.h>
+#include <linux/types.h>
+#ifndef __ASSEMBLY__
+
+struct emif_regs_amx3 {
+ u32 emif_sdcfg_val;
+ u32 emif_timing1_val;
+ u32 emif_timing2_val;
+ u32 emif_timing3_val;
+ u32 emif_ref_ctrl_val;
+ u32 emif_zqcfg_val;
+ u32 emif_pmcr_val;
+ u32 emif_pmcr_shdw_val;
+ u32 emif_rd_wr_level_ramp_ctrl;
+ u32 emif_rd_wr_exec_thresh;
+ u32 emif_cos_config;
+ u32 emif_priority_to_cos_mapping;
+ u32 emif_connect_id_serv_1_map;
+ u32 emif_connect_id_serv_2_map;
+ u32 emif_ocp_config_val;
+ u32 emif_lpddr2_nvm_tim;
+ u32 emif_lpddr2_nvm_tim_shdw;
+ u32 emif_dll_calib_ctrl_val;
+ u32 emif_dll_calib_ctrl_val_shdw;
+ u32 emif_ddr_phy_ctlr_1;
+ u32 emif_ext_phy_ctrl_vals[120];
+};
+
+struct ti_emif_pm_data {
+ void __iomem *ti_emif_base_addr_virt;
+ phys_addr_t ti_emif_base_addr_phys;
+ unsigned long ti_emif_sram_config;
+ struct emif_regs_amx3 *regs_virt;
+ phys_addr_t regs_phys;
+} __packed __aligned(8);
+
+struct ti_emif_pm_functions {
+ u32 save_context;
+ u32 restore_context;
+ u32 enter_sr;
+ u32 exit_sr;
+ u32 abort_sr;
+} __packed __aligned(8);
+
+struct gen_pool;
+
+int ti_emif_copy_pm_function_table(struct gen_pool *sram_pool, void *dst);
+int ti_emif_get_mem_type(void);
+
+#endif
+#endif /* __LINUX_TI_EMIF_H */
--
2.15.0
^ permalink raw reply related
* Re: [PATCH v4 2/8] MIPS: Octeon: Enable LMTDMA/LMTST operations.
From: James Hogan @ 2017-11-30 22:56 UTC (permalink / raw)
To: David Daney
Cc: David Daney, linux-mips, ralf, netdev, David S. Miller,
Rob Herring, Mark Rutland, devel, Greg Kroah-Hartman,
linux-kernel, Steven J. Hill, devicetree, Andrew Lunn,
Florian Fainelli, Carlos Munoz
In-Reply-To: <54c83e6b-35e2-be38-e4f1-87eb420938cb@caviumnetworks.com>
[-- Attachment #1: Type: text/plain, Size: 1462 bytes --]
On Thu, Nov 30, 2017 at 01:49:43PM -0800, David Daney wrote:
> On 11/30/2017 01:36 PM, James Hogan wrote:
> > On Tue, Nov 28, 2017 at 04:55:34PM -0800, David Daney wrote:
> >> Signed-off-by: Carlos Munoz <cmunoz@cavium.com>
> >> Signed-off-by: Steven J. Hill <Steven.Hill@cavium.com>
> >> Signed-off-by: David Daney <david.daney@cavium.com>
> >> ---
> >> arch/mips/cavium-octeon/setup.c | 6 ++++++
> >> arch/mips/include/asm/octeon/octeon.h | 12 ++++++++++--
> >> 2 files changed, 16 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c
> >> index a8034d0dcade..99e6a68bc652 100644
> >> --- a/arch/mips/cavium-octeon/setup.c
> >> +++ b/arch/mips/cavium-octeon/setup.c
> >> @@ -609,6 +609,12 @@ void octeon_user_io_init(void)
> >> #else
> >> cvmmemctl.s.cvmsegenak = 0;
> >> #endif
> >> + if (OCTEON_IS_OCTEON3()) {
> >> + /* Enable LMTDMA */
> >> + cvmmemctl.s.lmtena = 1;
> >> + /* Scratch line to use for LMT operation */
> >> + cvmmemctl.s.lmtline = 2;
> >
> > Out of curiosity, is there significance to the value 2 and associated
> > virtual address 0xffffffffffff8100, or is it pretty arbitrary?
>
> Yes, there is significance.
>
> CPU local memory starts at 0xffffffffffff8000, each line is 0x80 bytes.
> so the 2nd line starts at 0xffffffffffff8100
What I mean is, why is 2 chosen instead of any other value?
Cheers
James
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH 0/5] PCI: Add support to the Cadence PCIe controller
From: Bjorn Helgaas @ 2017-11-30 23:05 UTC (permalink / raw)
To: Cyrille Pitchen
Cc: Lorenzo Pieralisi, Kishon Vijay Abraham I, bhelgaas, linux-pci,
adouglas, stelford, dgary, kgopi, eandrews, thomas.petazzoni,
sureshp, nsekhar, linux-kernel, robh, devicetree
In-Reply-To: <058b2025-f55d-9210-a979-d00972259987@free-electrons.com>
On Thu, Nov 30, 2017 at 09:05:12PM +0100, Cyrille Pitchen wrote:
> Le 30/11/2017 à 19:45, Cyrille Pitchen a écrit :
> > Le 30/11/2017 à 19:18, Lorenzo Pieralisi a écrit :
> >> On Thu, Nov 30, 2017 at 12:43:20PM +0530, Kishon Vijay Abraham I wrote:
> >>> The reason to patch drivers/Makefile should be because
> >>> pcie-cadence-ep has to be compiled even when CONFIG_PCI is not
> >>> enabled. CONFIG_PCI enables host specific features and ENDPOINT
> >>> shouldn't depend on CONFIG_PCI.
> I know it's far from perfect but what do you think or something like that:
>
> ---8<---------------------------------------------------------------------------
> diff --git a/drivers/Makefile b/drivers/Makefile
> index 27bdd98784d9..9757199b9a65 100644
> --- a/drivers/Makefile
> +++ b/drivers/Makefile
> @@ -16,11 +16,7 @@ obj-$(CONFIG_PINCTRL) += pinctrl/
> obj-$(CONFIG_GPIOLIB) += gpio/
> obj-y += pwm/
>
> -obj-$(CONFIG_PCI) += pci/
> -obj-$(CONFIG_PCI_ENDPOINT) += pci/endpoint/
> -obj-$(CONFIG_PCI_CADENCE) += pci/cadence/
> -# PCI dwc controller drivers
> -obj-y += pci/dwc/
> +obj-y += pci/
>
> obj-$(CONFIG_PARISC) += parisc/
> obj-$(CONFIG_RAPIDIO) += rapidio/
> diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
> index 3d5e047f0a32..4e57fe4499ce 100644
> --- a/drivers/pci/Makefile
> +++ b/drivers/pci/Makefile
> @@ -3,6 +3,7 @@
> # Makefile for the PCI bus specific drivers.
> #
>
> +ifdef CONFIG_PCI
> obj-y += access.o bus.o probe.o host-bridge.o remove.o pci.o \
> pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \
> irq.o vpd.o setup-bus.o vc.o mmap.o setup-irq.o
> @@ -54,3 +55,9 @@ ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG
> # PCI host controller drivers
> obj-y += host/
> obj-y += switch/
> +endif
> +
> +obj-$(CONFIG_PCI_ENDPOINT) += endpoint/
> +obj-$(CONFIG_PCI_CADENCE) += cadence/
> +# PCI dwc controller drivers
> +obj-y += dwc/
> ---8<---------------------------------------------------------------------------
>
> I admit it doesn't solve the ordering issue but at least it cleans some mess
> in drivers/Makefile.
I like this a lot. I think the only things that would actually
require the ifdef are the generic symbol things (CONFIG_PROC_FS,
CONFIG_SYSFS, CONFIG_OF), so we could do this for most of it:
obj-$(CONFIG_PCI) += access.o bus.o probe.o ...
...
obj-$(CONFIG_PCI_QUIRKS) += quirks.o
obj-$(CONFIG_PCIEPORTBUS) += pcie/
obj-$(CONFIG_PCI) += host/
obj-$(CONFIG_PCI) += switch/
With possibly a few Kconfig dependency tweaks.
^ permalink raw reply
* Re: [PATCH v4 2/8] MIPS: Octeon: Enable LMTDMA/LMTST operations.
From: David Daney @ 2017-11-30 23:09 UTC (permalink / raw)
To: James Hogan
Cc: David Daney, linux-mips-6z/3iImG2C8G8FEW9MqTrA,
ralf-6z/3iImG2C8G8FEW9MqTrA, netdev-u79uwXL29TY76Z2rM5mHXA,
David S. Miller, Rob Herring, Mark Rutland,
devel-gWbeCf7V1WCQmaza687I9mD2FQJk+8+b, Greg Kroah-Hartman,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Steven J. Hill,
devicetree-u79uwXL29TY76Z2rM5mHXA, Andrew Lunn, Florian Fainelli,
Carlos Munoz
In-Reply-To: <20171130225614.GJ27409-4bYivNCBEGSP4qXr0kR+DFHK5/nzsB32@public.gmane.org>
On 11/30/2017 02:56 PM, James Hogan wrote:
> On Thu, Nov 30, 2017 at 01:49:43PM -0800, David Daney wrote:
>> On 11/30/2017 01:36 PM, James Hogan wrote:
>>> On Tue, Nov 28, 2017 at 04:55:34PM -0800, David Daney wrote:
>>>> Signed-off-by: Carlos Munoz <cmunoz-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
>>>> Signed-off-by: Steven J. Hill <Steven.Hill-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
>>>> Signed-off-by: David Daney <david.daney-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
>>>> ---
>>>> arch/mips/cavium-octeon/setup.c | 6 ++++++
>>>> arch/mips/include/asm/octeon/octeon.h | 12 ++++++++++--
>>>> 2 files changed, 16 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c
>>>> index a8034d0dcade..99e6a68bc652 100644
>>>> --- a/arch/mips/cavium-octeon/setup.c
>>>> +++ b/arch/mips/cavium-octeon/setup.c
>>>> @@ -609,6 +609,12 @@ void octeon_user_io_init(void)
>>>> #else
>>>> cvmmemctl.s.cvmsegenak = 0;
>>>> #endif
>>>> + if (OCTEON_IS_OCTEON3()) {
>>>> + /* Enable LMTDMA */
>>>> + cvmmemctl.s.lmtena = 1;
>>>> + /* Scratch line to use for LMT operation */
>>>> + cvmmemctl.s.lmtline = 2;
>>>
>>> Out of curiosity, is there significance to the value 2 and associated
>>> virtual address 0xffffffffffff8100, or is it pretty arbitrary?
>>
>> Yes, there is significance.
>>
>> CPU local memory starts at 0xffffffffffff8000, each line is 0x80 bytes.
>> so the 2nd line starts at 0xffffffffffff8100
>
> What I mean is, why is 2 chosen instead of any other value?
That is explained in the change log of patch 5/8:
1st 128-bytes: Use by IOBDMA
2nd 128-bytes: Reserved by kernel for scratch/TLS emulation.
3rd 128-bytes: OCTEON-III LMTLINE
>
> Cheers
> James
>
--
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 v4 2/8] MIPS: Octeon: Enable LMTDMA/LMTST operations.
From: James Hogan @ 2017-11-30 23:12 UTC (permalink / raw)
To: David Daney
Cc: David Daney, linux-mips-6z/3iImG2C8G8FEW9MqTrA,
ralf-6z/3iImG2C8G8FEW9MqTrA, netdev-u79uwXL29TY76Z2rM5mHXA,
David S. Miller, Rob Herring, Mark Rutland,
devel-gWbeCf7V1WCQmaza687I9mD2FQJk+8+b, Greg Kroah-Hartman,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Steven J. Hill,
devicetree-u79uwXL29TY76Z2rM5mHXA, Andrew Lunn, Florian Fainelli,
Carlos Munoz
In-Reply-To: <c90ac3a5-7230-38ff-691a-3d94a25702cd-M3mlKVOIwJVv6pq1l3V1OdBPR1lH4CV8@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 2030 bytes --]
On Thu, Nov 30, 2017 at 03:09:33PM -0800, David Daney wrote:
> On 11/30/2017 02:56 PM, James Hogan wrote:
> > On Thu, Nov 30, 2017 at 01:49:43PM -0800, David Daney wrote:
> >> On 11/30/2017 01:36 PM, James Hogan wrote:
> >>> On Tue, Nov 28, 2017 at 04:55:34PM -0800, David Daney wrote:
> >>>> Signed-off-by: Carlos Munoz <cmunoz-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
> >>>> Signed-off-by: Steven J. Hill <Steven.Hill-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
> >>>> Signed-off-by: David Daney <david.daney-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
> >>>> ---
> >>>> arch/mips/cavium-octeon/setup.c | 6 ++++++
> >>>> arch/mips/include/asm/octeon/octeon.h | 12 ++++++++++--
> >>>> 2 files changed, 16 insertions(+), 2 deletions(-)
> >>>>
> >>>> diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c
> >>>> index a8034d0dcade..99e6a68bc652 100644
> >>>> --- a/arch/mips/cavium-octeon/setup.c
> >>>> +++ b/arch/mips/cavium-octeon/setup.c
> >>>> @@ -609,6 +609,12 @@ void octeon_user_io_init(void)
> >>>> #else
> >>>> cvmmemctl.s.cvmsegenak = 0;
> >>>> #endif
> >>>> + if (OCTEON_IS_OCTEON3()) {
> >>>> + /* Enable LMTDMA */
> >>>> + cvmmemctl.s.lmtena = 1;
> >>>> + /* Scratch line to use for LMT operation */
> >>>> + cvmmemctl.s.lmtline = 2;
> >>>
> >>> Out of curiosity, is there significance to the value 2 and associated
> >>> virtual address 0xffffffffffff8100, or is it pretty arbitrary?
> >>
> >> Yes, there is significance.
> >>
> >> CPU local memory starts at 0xffffffffffff8000, each line is 0x80 bytes.
> >> so the 2nd line starts at 0xffffffffffff8100
> >
> > What I mean is, why is 2 chosen instead of any other value?
>
> That is explained in the change log of patch 5/8:
>
>
> 1st 128-bytes: Use by IOBDMA
> 2nd 128-bytes: Reserved by kernel for scratch/TLS emulation.
> 3rd 128-bytes: OCTEON-III LMTLINE
Ah yes. Perhaps it deserves a brief comment in the code, or even an
enum.
Cheers
James
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* [PATCH net-next v4 0/2] add UniPhier AVE ethernet support
From: Kunihiko Hayashi @ 2017-12-01 1:03 UTC (permalink / raw)
To: netdev-u79uwXL29TY76Z2rM5mHXA, Andrew Lunn, Florian Fainelli
Cc: Rob Herring, Mark Rutland,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Masahiro Yamada,
Masami Hiramatsu, Jassi Brar, Kunihiko Hayashi
This series adds support for Socionext AVE ethernet controller implemented
on UniPhier SoCs. This driver supports RGMII/RMII modes.
v3: http://www.spinics.net/lists/netdev/msg462550.html
The PHY patch included in v1 has already separated in:
http://www.spinics.net/lists/netdev/msg454595.html
Changes since v3:
- remove checking dma address and use dma_set_mask() to restirct address
- replace ave_mdio_busywait() with read_poll_timeout()
- replace functions to access to registers with readl/writel() directly
- replace a function to access to macaddr with ave_hw_write_macaddr()
- change return value of ave_dma_map() to error value
- move mdiobus_unregister() from ave_remove() to ave_uninit()
- eliminate else block at the end of ave_dma_map()
- add mask definitions for packet filter
- sort bitmap definitions in descending order
- add error check to some functions
- rename and sort functions to clear sub-categories
- fix error value consistency
- remove unneeded initializers
- change type of constant arrays
Changes since v2:
- replace clk_get() with devm_clk_get()
- replace reset_control_get() with devm_reset_control_get_optional_shared()
- add error return when the error occurs on the above *_get functions
- sort soc data and compatible strings
- remove clearly obvious comments
- modify dt-bindings document consistent with these modifications
Changes since v1:
- add/remove devicetree properties and sub-node
- remove "internal-phy-interrupt" and "desc-bits" property
- add SoC data structures based on compatible strings
- add node operation to apply "mdio" sub-node
- add support for features
- add support for {get,set}_pauseparam and pause frame operations
- add support for ndo_get_stats64 instead of ndo_get_stats
- replace with desiable functions
- replace check for valid phy_mode with phy_interface{_mode}_is_rgmii()
- replace phy attach message with phy_attached_info()
- replace 32bit operation with {upper,lower}_32_bits() on ave_wdesc_addr()
- replace nway_reset and get_link with generic functions
- move operations to proper functions
- move phy_start_aneg() to ndo_open,
and remove unnecessary PHY interrupt operations
See http://www.spinics.net/lists/netdev/msg454590.html
- move irq initialization and descriptor memory allocation to ndo_open
- move initialization of reset and clock and mdiobus to ndo_init
- fix skbuffer operations
- fix skb alignment operations and add Rx buffer adjustment for descriptor
See http://www.spinics.net/lists/netdev/msg456014.html
- add error returns when dma_map_single() failed
- clean up code structures
- clean up wait-loop and wake-queue conditions
- add ave_wdesc_addr() and offset definitions
- add ave_macaddr_init() to clean up mac-address operation
- fix checking whether Tx entry is not enough
- fix supported features of phydev
- add necessary free/disable operations
- add phydev check on ave_{get,set}_wol()
- remove netif_carrier functions, phydev initializer, and Tx budget check
- change obsolate codes
- replace ndev->{base_addr,irq} with the members of ave_private
- rename goto labels and mask definitions, and remove unused codes
Kunihiko Hayashi (2):
dt-bindings: net: add DT bindings for Socionext UniPhier AVE
net: ethernet: socionext: add AVE ethernet driver
.../bindings/net/socionext,uniphier-ave4.txt | 48 +
drivers/net/ethernet/Kconfig | 1 +
drivers/net/ethernet/Makefile | 1 +
drivers/net/ethernet/socionext/Kconfig | 22 +
drivers/net/ethernet/socionext/Makefile | 5 +
drivers/net/ethernet/socionext/sni_ave.c | 1744 ++++++++++++++++++++
6 files changed, 1821 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/socionext,uniphier-ave4.txt
create mode 100644 drivers/net/ethernet/socionext/Kconfig
create mode 100644 drivers/net/ethernet/socionext/Makefile
create mode 100644 drivers/net/ethernet/socionext/sni_ave.c
--
2.7.4
--
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 net-next v4 1/2] dt-bindings: net: add DT bindings for Socionext UniPhier AVE
From: Kunihiko Hayashi @ 2017-12-01 1:03 UTC (permalink / raw)
To: netdev, Andrew Lunn, Florian Fainelli
Cc: Rob Herring, Mark Rutland, linux-arm-kernel, linux-kernel,
devicetree, Masahiro Yamada, Masami Hiramatsu, Jassi Brar,
Kunihiko Hayashi
In-Reply-To: <1512090230-27594-1-git-send-email-hayashi.kunihiko@socionext.com>
DT bindings for the AVE ethernet controller found on Socionext's
UniPhier platforms.
Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
Acked-by: Rob Herring <robh@kernel.org>
---
.../bindings/net/socionext,uniphier-ave4.txt | 48 ++++++++++++++++++++++
1 file changed, 48 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/socionext,uniphier-ave4.txt
diff --git a/Documentation/devicetree/bindings/net/socionext,uniphier-ave4.txt b/Documentation/devicetree/bindings/net/socionext,uniphier-ave4.txt
new file mode 100644
index 0000000..4700377
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/socionext,uniphier-ave4.txt
@@ -0,0 +1,48 @@
+* Socionext AVE ethernet controller
+
+This describes the devicetree bindings for AVE ethernet controller
+implemented on Socionext UniPhier SoCs.
+
+Required properties:
+ - compatible: Should be
+ - "socionext,uniphier-pro4-ave4" : for Pro4 SoC
+ - "socionext,uniphier-pxs2-ave4" : for PXs2 SoC
+ - "socionext,uniphier-ld11-ave4" : for LD11 SoC
+ - "socionext,uniphier-ld20-ave4" : for LD20 SoC
+ - reg: Address where registers are mapped and size of region.
+ - interrupts: Should contain the MAC interrupt.
+ - phy-mode: See ethernet.txt in the same directory. Allow to choose
+ "rgmii", "rmii", or "mii" according to the PHY.
+ - phy-handle: Should point to the external phy device.
+ See ethernet.txt file in the same directory.
+ - clocks: A phandle to the clock for the MAC.
+
+Optional properties:
+ - resets: A phandle to the reset control for the MAC
+ - local-mac-address: See ethernet.txt in the same directory.
+
+Required subnode:
+ - mdio: Device tree subnode with the following required properties:
+ - #address-cells: Must be <1>.
+ - #size-cells: Must be <0>.
+ - reg: phy ID number, usually a small integer.
+
+Example:
+
+ ether: ethernet@65000000 {
+ compatible = "socionext,uniphier-ld20-ave4";
+ reg = <0x65000000 0x8500>;
+ interrupts = <0 66 4>;
+ phy-mode = "rgmii";
+ phy-handle = <ðphy>;
+ clocks = <&sys_clk 6>;
+ resets = <&sys_rst 6>;
+ local-mac-address = [00 00 00 00 00 00];
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ ethphy: ethphy@1 {
+ reg = <1>;
+ };
+ };
+ };
--
2.7.4
^ permalink raw reply related
* [PATCH net-next v4 2/2] net: ethernet: socionext: add AVE ethernet driver
From: Kunihiko Hayashi @ 2017-12-01 1:03 UTC (permalink / raw)
To: netdev, Andrew Lunn, Florian Fainelli
Cc: Rob Herring, Mark Rutland, linux-arm-kernel, linux-kernel,
devicetree, Masahiro Yamada, Masami Hiramatsu, Jassi Brar,
Kunihiko Hayashi
In-Reply-To: <1512090230-27594-1-git-send-email-hayashi.kunihiko@socionext.com>
The UniPhier platform from Socionext provides the AVE ethernet
controller that includes MAC and MDIO bus supporting RGMII/RMII
modes. The controller is named AVE.
Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
---
drivers/net/ethernet/Kconfig | 1 +
drivers/net/ethernet/Makefile | 1 +
drivers/net/ethernet/socionext/Kconfig | 22 +
drivers/net/ethernet/socionext/Makefile | 5 +
drivers/net/ethernet/socionext/sni_ave.c | 1744 ++++++++++++++++++++++++++++++
5 files changed, 1773 insertions(+)
create mode 100644 drivers/net/ethernet/socionext/Kconfig
create mode 100644 drivers/net/ethernet/socionext/Makefile
create mode 100644 drivers/net/ethernet/socionext/sni_ave.c
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index c604213..d50519e 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -170,6 +170,7 @@ source "drivers/net/ethernet/sis/Kconfig"
source "drivers/net/ethernet/sfc/Kconfig"
source "drivers/net/ethernet/sgi/Kconfig"
source "drivers/net/ethernet/smsc/Kconfig"
+source "drivers/net/ethernet/socionext/Kconfig"
source "drivers/net/ethernet/stmicro/Kconfig"
source "drivers/net/ethernet/sun/Kconfig"
source "drivers/net/ethernet/tehuti/Kconfig"
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index 39f62733..6cf5ade 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_SFC) += sfc/
obj-$(CONFIG_SFC_FALCON) += sfc/falcon/
obj-$(CONFIG_NET_VENDOR_SGI) += sgi/
obj-$(CONFIG_NET_VENDOR_SMSC) += smsc/
+obj-$(CONFIG_NET_VENDOR_SOCIONEXT) += socionext/
obj-$(CONFIG_NET_VENDOR_STMICRO) += stmicro/
obj-$(CONFIG_NET_VENDOR_SUN) += sun/
obj-$(CONFIG_NET_VENDOR_TEHUTI) += tehuti/
diff --git a/drivers/net/ethernet/socionext/Kconfig b/drivers/net/ethernet/socionext/Kconfig
new file mode 100644
index 0000000..3a1829e
--- /dev/null
+++ b/drivers/net/ethernet/socionext/Kconfig
@@ -0,0 +1,22 @@
+config NET_VENDOR_SOCIONEXT
+ bool "Socionext ethernet drivers"
+ default y
+ ---help---
+ Option to select ethernet drivers for Socionext platforms.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Socionext devices. If you say Y, you will be asked
+ for your specific card in the following questions.
+
+if NET_VENDOR_SOCIONEXT
+
+config SNI_AVE
+ tristate "Socionext AVE ethernet support"
+ depends on (ARCH_UNIPHIER || COMPILE_TEST) && OF
+ select PHYLIB
+ ---help---
+ Driver for gigabit ethernet MACs, called AVE, in the
+ Socionext UniPhier family.
+
+endif #NET_VENDOR_SOCIONEXT
diff --git a/drivers/net/ethernet/socionext/Makefile b/drivers/net/ethernet/socionext/Makefile
new file mode 100644
index 0000000..ab83df6
--- /dev/null
+++ b/drivers/net/ethernet/socionext/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for all ethernet ip drivers on Socionext platforms
+#
+obj-$(CONFIG_SNI_AVE) += sni_ave.o
diff --git a/drivers/net/ethernet/socionext/sni_ave.c b/drivers/net/ethernet/socionext/sni_ave.c
new file mode 100644
index 0000000..6f42f12
--- /dev/null
+++ b/drivers/net/ethernet/socionext/sni_ave.c
@@ -0,0 +1,1744 @@
+/**
+ * sni_ave.c - Socionext UniPhier AVE ethernet driver
+ *
+ * Copyright 2014 Panasonic Corporation
+ * Copyright 2015-2017 Socionext Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/etherdevice.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of_net.h>
+#include <linux/of_mdio.h>
+#include <linux/of_platform.h>
+#include <linux/phy.h>
+#include <linux/reset.h>
+#include <linux/types.h>
+#include <linux/u64_stats_sync.h>
+
+/* General Register Group */
+#define AVE_IDR 0x000 /* ID */
+#define AVE_VR 0x004 /* Version */
+#define AVE_GRR 0x008 /* Global Reset */
+#define AVE_CFGR 0x00c /* Configuration */
+
+/* Interrupt Register Group */
+#define AVE_GIMR 0x100 /* Global Interrupt Mask */
+#define AVE_GISR 0x104 /* Global Interrupt Status */
+
+/* MAC Register Group */
+#define AVE_TXCR 0x200 /* TX Setup */
+#define AVE_RXCR 0x204 /* RX Setup */
+#define AVE_RXMAC1R 0x208 /* MAC address (lower) */
+#define AVE_RXMAC2R 0x20c /* MAC address (upper) */
+#define AVE_MDIOCTR 0x214 /* MDIO Control */
+#define AVE_MDIOAR 0x218 /* MDIO Address */
+#define AVE_MDIOWDR 0x21c /* MDIO Data */
+#define AVE_MDIOSR 0x220 /* MDIO Status */
+#define AVE_MDIORDR 0x224 /* MDIO Rd Data */
+
+/* Descriptor Control Register Group */
+#define AVE_DESCC 0x300 /* Descriptor Control */
+#define AVE_TXDC 0x304 /* TX Descriptor Configuration */
+#define AVE_RXDC0 0x308 /* RX Descriptor Ring0 Configuration */
+#define AVE_IIRQC 0x34c /* Interval IRQ Control */
+
+/* Packet Filter Register Group */
+#define AVE_PKTF_BASE 0x800 /* PF Base Address */
+#define AVE_PFMBYTE_BASE 0xd00 /* PF Mask Byte Base Address */
+#define AVE_PFMBIT_BASE 0xe00 /* PF Mask Bit Base Address */
+#define AVE_PFSEL_BASE 0xf00 /* PF Selector Base Address */
+#define AVE_PFEN 0xffc /* Packet Filter Enable */
+#define AVE_PKTF(ent) (AVE_PKTF_BASE + (ent) * 0x40)
+#define AVE_PFMBYTE(ent) (AVE_PFMBYTE_BASE + (ent) * 8)
+#define AVE_PFMBIT(ent) (AVE_PFMBIT_BASE + (ent) * 4)
+#define AVE_PFSEL(ent) (AVE_PFSEL_BASE + (ent) * 4)
+
+/* 64bit descriptor memory */
+#define AVE_DESC_SIZE_64 12 /* Descriptor Size */
+
+#define AVE_TXDM_64 0x1000 /* Tx Descriptor Memory */
+#define AVE_RXDM_64 0x1c00 /* Rx Descriptor Memory */
+
+#define AVE_TXDM_SIZE_64 0x0ba0 /* Tx Descriptor Memory Size 3KB */
+#define AVE_RXDM_SIZE_64 0x6000 /* Rx Descriptor Memory Size 24KB */
+
+/* 32bit descriptor memory */
+#define AVE_DESC_SIZE_32 8 /* Descriptor Size */
+
+#define AVE_TXDM_32 0x1000 /* Tx Descriptor Memory */
+#define AVE_RXDM_32 0x1800 /* Rx Descriptor Memory */
+
+#define AVE_TXDM_SIZE_32 0x07c0 /* Tx Descriptor Memory Size 2KB */
+#define AVE_RXDM_SIZE_32 0x4000 /* Rx Descriptor Memory Size 16KB */
+
+/* RMII Bridge Register Group */
+#define AVE_RSTCTRL 0x8028 /* Reset control */
+#define AVE_RSTCTRL_RMIIRST BIT(16)
+#define AVE_LINKSEL 0x8034 /* Link speed setting */
+#define AVE_LINKSEL_100M BIT(0)
+
+/* AVE_GRR */
+#define AVE_GRR_RXFFR BIT(5) /* Reset RxFIFO */
+#define AVE_GRR_PHYRST BIT(4) /* Reset external PHY */
+#define AVE_GRR_GRST BIT(0) /* Reset all MAC */
+
+/* AVE_CFGR */
+#define AVE_CFGR_FLE BIT(31) /* Filter Function */
+#define AVE_CFGR_CHE BIT(30) /* Checksum Function */
+#define AVE_CFGR_MII BIT(27) /* Func mode (1:MII/RMII, 0:RGMII) */
+#define AVE_CFGR_IPFCEN BIT(24) /* IP fragment sum Enable */
+
+/* AVE_GISR (common with GIMR) */
+#define AVE_GI_PHY BIT(24) /* PHY interrupt */
+#define AVE_GI_TX BIT(16) /* Tx complete */
+#define AVE_GI_RXERR BIT(8) /* Receive frame more than max size */
+#define AVE_GI_RXOVF BIT(7) /* Overflow at the RxFIFO */
+#define AVE_GI_RXDROP BIT(6) /* Drop packet */
+#define AVE_GI_RXIINT BIT(5) /* Interval interrupt */
+
+/* AVE_TXCR */
+#define AVE_TXCR_FLOCTR BIT(18) /* Flow control */
+#define AVE_TXCR_TXSPD_1G BIT(17)
+#define AVE_TXCR_TXSPD_100 BIT(16)
+
+/* AVE_RXCR */
+#define AVE_RXCR_RXEN BIT(30) /* Rx enable */
+#define AVE_RXCR_FDUPEN BIT(22) /* Interface mode */
+#define AVE_RXCR_FLOCTR BIT(21) /* Flow control */
+#define AVE_RXCR_AFEN BIT(19) /* MAC address filter */
+#define AVE_RXCR_DRPEN BIT(18) /* Drop pause frame */
+#define AVE_RXCR_MPSIZ_MASK GENMASK(10, 0)
+
+/* AVE_MDIOCTR */
+#define AVE_MDIOCTR_RREQ BIT(3) /* Read request */
+#define AVE_MDIOCTR_WREQ BIT(2) /* Write request */
+
+/* AVE_MDIOSR */
+#define AVE_MDIOSR_STS BIT(0) /* access status */
+
+/* AVE_DESCC */
+#define AVE_DESCC_STATUS_MASK GENMASK(31, 16)
+#define AVE_DESCC_RD0 BIT(8) /* Enable Rx descriptor Ring0 */
+#define AVE_DESCC_RDSTP BIT(4) /* Pause Rx descriptor */
+#define AVE_DESCC_TD BIT(0) /* Enable Tx descriptor */
+
+/* AVE_TXDC */
+#define AVE_TXDC_SIZE GENMASK(27, 16) /* Size of Tx descriptor */
+#define AVE_TXDC_ADDR GENMASK(11, 0) /* Start address */
+#define AVE_TXDC_ADDR_START 0
+
+/* AVE_RXDC0 */
+#define AVE_RXDC0_SIZE GENMASK(30, 16) /* Size of Rx descriptor */
+#define AVE_RXDC0_ADDR GENMASK(14, 0) /* Start address */
+#define AVE_RXDC0_ADDR_START 0
+
+/* AVE_IIRQC */
+#define AVE_IIRQC_EN0 BIT(27) /* Enable interval interrupt Ring0 */
+#define AVE_IIRQC_BSCK GENMASK(15, 0) /* Interval count unit */
+
+/* Command status for descriptor */
+#define AVE_STS_OWN BIT(31) /* Descriptor ownership */
+#define AVE_STS_INTR BIT(29) /* Request for interrupt */
+#define AVE_STS_OK BIT(27) /* Normal transmit */
+/* TX */
+#define AVE_STS_NOCSUM BIT(28) /* No use HW checksum */
+#define AVE_STS_1ST BIT(26) /* Head of buffer chain */
+#define AVE_STS_LAST BIT(25) /* Tail of buffer chain */
+#define AVE_STS_OWC BIT(21) /* Out of window,Late Collision */
+#define AVE_STS_EC BIT(20) /* Excess collision occurred */
+#define AVE_STS_PKTLEN_TX_MASK GENMASK(15, 0)
+/* RX */
+#define AVE_STS_CSSV BIT(21) /* Checksum check performed */
+#define AVE_STS_CSER BIT(20) /* Checksum error detected */
+#define AVE_STS_PKTLEN_RX_MASK GENMASK(10, 0)
+
+/* Packet filter */
+#define AVE_PFMBYTE_MASK0 (~GENMASK(7, 6))
+#define AVE_PFMBYTE_MASK1 GENMASK(25, 0)
+#define AVE_PFMBIT_MASK GENMASK(15, 0)
+
+#define AVE_PF_SIZE 17 /* Number of all packet filter */
+#define AVE_PF_MULTICAST_SIZE 7 /* Number of multicast filter */
+
+#define AVE_PFNUM_FILTER 0 /* No.0 */
+#define AVE_PFNUM_UNICAST 1 /* No.1 */
+#define AVE_PFNUM_BROADCAST 2 /* No.2 */
+#define AVE_PFNUM_MULTICAST 11 /* No.11-17 */
+
+/* NETIF Message control */
+#define AVE_DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | \
+ NETIF_MSG_PROBE | \
+ NETIF_MSG_LINK | \
+ NETIF_MSG_TIMER | \
+ NETIF_MSG_IFDOWN | \
+ NETIF_MSG_IFUP | \
+ NETIF_MSG_RX_ERR | \
+ NETIF_MSG_TX_ERR)
+
+/* Parameter for descriptor */
+#define AVE_NR_TXDESC 32 /* Tx descriptor */
+#define AVE_NR_RXDESC 64 /* Rx descriptor */
+
+#define AVE_DESC_OFS_CMDSTS 0
+#define AVE_DESC_OFS_ADDRL 4
+#define AVE_DESC_OFS_ADDRU 8
+
+/* Parameter for ethernet frame */
+#define AVE_MAX_ETHFRAME 1518
+
+/* Parameter for interrupt */
+#define AVE_INTM_COUNT 20
+#define AVE_FORCE_TXINTCNT 1
+
+#define IS_DESC_64BIT(p) ((p)->data->is_desc_64bit)
+
+enum desc_id {
+ AVE_DESCID_RX,
+ AVE_DESCID_TX,
+};
+
+enum desc_state {
+ AVE_DESC_RX_PERMIT,
+ AVE_DESC_RX_SUSPEND,
+ AVE_DESC_START,
+ AVE_DESC_STOP,
+};
+
+struct ave_desc {
+ struct sk_buff *skbs;
+ dma_addr_t skbs_dma;
+ size_t skbs_dmalen;
+};
+
+struct ave_desc_info {
+ u32 ndesc; /* number of descriptor */
+ u32 daddr; /* start address of descriptor */
+ u32 proc_idx; /* index of processing packet */
+ u32 done_idx; /* index of processed packet */
+ struct ave_desc *desc; /* skb info related descriptor */
+};
+
+struct ave_soc_data {
+ bool is_desc_64bit;
+};
+
+struct ave_stats {
+ struct u64_stats_sync syncp;
+ u64 packets;
+ u64 bytes;
+ u64 errors;
+ u64 dropped;
+ u64 collisions;
+ u64 fifo_errors;
+};
+
+struct ave_private {
+ void __iomem *base;
+ int irq;
+ int phy_id;
+ unsigned int desc_size;
+ u32 msg_enable;
+ struct clk *clk;
+ struct reset_control *rst;
+ phy_interface_t phy_mode;
+ struct phy_device *phydev;
+ struct mii_bus *mdio;
+
+ /* stats */
+ struct ave_stats stats_rx;
+ struct ave_stats stats_tx;
+
+ /* NAPI support */
+ struct net_device *ndev;
+ struct napi_struct napi_rx;
+ struct napi_struct napi_tx;
+
+ /* descriptor */
+ struct ave_desc_info rx;
+ struct ave_desc_info tx;
+
+ /* flow control */
+ int pause_auto;
+ int pause_rx;
+ int pause_tx;
+
+ const struct ave_soc_data *data;
+};
+
+static inline u32 ave_desc_read(struct net_device *ndev, enum desc_id id,
+ int entry, int offset)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ u32 addr = (id == AVE_DESCID_TX) ? priv->tx.daddr : priv->rx.daddr;
+
+ addr += entry * priv->desc_size + offset;
+
+ return readl(priv->base + addr);
+}
+
+static inline u32 ave_desc_read_cmdsts(struct net_device *ndev, enum desc_id id,
+ int entry)
+{
+ return ave_desc_read(ndev, id, entry, AVE_DESC_OFS_CMDSTS);
+}
+
+static inline void ave_desc_write(struct net_device *ndev, enum desc_id id,
+ int entry, int offset, u32 val)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ u32 addr = (id == AVE_DESCID_TX) ? priv->tx.daddr : priv->rx.daddr;
+
+ addr += entry * priv->desc_size + offset;
+
+ writel(val, priv->base + addr);
+}
+
+static inline void ave_desc_write_cmdsts(struct net_device *ndev,
+ enum desc_id id, int entry, u32 val)
+{
+ ave_desc_write(ndev, id, entry, AVE_DESC_OFS_CMDSTS, val);
+}
+
+static inline void ave_desc_write_addr(struct net_device *ndev,
+ enum desc_id id, int entry,
+ dma_addr_t paddr)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+
+ ave_desc_write(ndev, id, entry, AVE_DESC_OFS_ADDRL,
+ lower_32_bits(paddr));
+ if (IS_DESC_64BIT(priv))
+ ave_desc_write(ndev, id,
+ entry, AVE_DESC_OFS_ADDRU,
+ upper_32_bits(paddr));
+}
+
+static inline u32 ave_irq_disable_all(struct net_device *ndev)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ u32 ret;
+
+ ret = readl(priv->base + AVE_GIMR);
+ writel(0, priv->base + AVE_GIMR);
+
+ return ret;
+}
+
+static inline void ave_irq_restore(struct net_device *ndev, u32 val)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+
+ writel(val, priv->base + AVE_GIMR);
+}
+
+static inline void ave_irq_enable(struct net_device *ndev, u32 bitflag)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+
+ writel(readl(priv->base + AVE_GIMR) | bitflag, priv->base + AVE_GIMR);
+ writel(bitflag, priv->base + AVE_GISR);
+}
+
+static inline void ave_irq_disable(struct net_device *ndev, u32 bitflag)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+
+ writel(readl(priv->base + AVE_GIMR) & ~bitflag, priv->base + AVE_GIMR);
+}
+
+static void ave_hw_write_macaddr(struct net_device *ndev,
+ const unsigned char *mac_addr,
+ int reg1, int reg2)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+
+ writel(mac_addr[0] | mac_addr[1] << 8 |
+ mac_addr[2] << 16 | mac_addr[3] << 24, priv->base + reg1);
+ writel(mac_addr[4] | mac_addr[5] << 8, priv->base + reg2);
+}
+
+static void ave_hw_read_version(struct net_device *ndev, char *buf, int len)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ u32 major, minor, vr;
+
+ vr = readl(priv->base + AVE_VR);
+ major = (vr & GENMASK(15, 8)) >> 8;
+ minor = (vr & GENMASK(7, 0));
+ snprintf(buf, len, "v%u.%u", major, minor);
+}
+
+static void ave_ethtool_get_drvinfo(struct net_device *ndev,
+ struct ethtool_drvinfo *info)
+{
+ struct device *dev = ndev->dev.parent;
+
+ strlcpy(info->driver, dev->driver->name, sizeof(info->driver));
+ strlcpy(info->bus_info, dev_name(dev), sizeof(info->bus_info));
+ ave_hw_read_version(ndev, info->fw_version, sizeof(info->fw_version));
+}
+
+static u32 ave_ethtool_get_msglevel(struct net_device *ndev)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+
+ return priv->msg_enable;
+}
+
+static void ave_ethtool_set_msglevel(struct net_device *ndev, u32 val)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+
+ priv->msg_enable = val;
+}
+
+static void ave_ethtool_get_wol(struct net_device *ndev,
+ struct ethtool_wolinfo *wol)
+{
+ wol->supported = 0;
+ wol->wolopts = 0;
+
+ if (ndev->phydev)
+ phy_ethtool_get_wol(ndev->phydev, wol);
+}
+
+static int ave_ethtool_set_wol(struct net_device *ndev,
+ struct ethtool_wolinfo *wol)
+{
+ int ret;
+
+ if (!ndev->phydev ||
+ (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE)))
+ return -EOPNOTSUPP;
+
+ ret = phy_ethtool_set_wol(ndev->phydev, wol);
+ if (!ret)
+ device_set_wakeup_enable(&ndev->dev, !!wol->wolopts);
+
+ return ret;
+}
+
+static void ave_ethtool_get_pauseparam(struct net_device *ndev,
+ struct ethtool_pauseparam *pause)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+
+ pause->autoneg = priv->pause_auto;
+ pause->rx_pause = priv->pause_rx;
+ pause->tx_pause = priv->pause_tx;
+}
+
+static int ave_ethtool_set_pauseparam(struct net_device *ndev,
+ struct ethtool_pauseparam *pause)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ struct phy_device *phydev = ndev->phydev;
+
+ if (!phydev)
+ return -EINVAL;
+
+ priv->pause_auto = pause->autoneg;
+ priv->pause_rx = pause->rx_pause;
+ priv->pause_tx = pause->tx_pause;
+
+ phydev->advertising &= ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
+ if (pause->rx_pause)
+ phydev->advertising |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;
+ if (pause->tx_pause)
+ phydev->advertising ^= ADVERTISED_Asym_Pause;
+
+ if (pause->autoneg) {
+ if (netif_running(ndev))
+ phy_start_aneg(phydev);
+ }
+
+ return 0;
+}
+
+static const struct ethtool_ops ave_ethtool_ops = {
+ .get_link_ksettings = phy_ethtool_get_link_ksettings,
+ .set_link_ksettings = phy_ethtool_set_link_ksettings,
+ .get_drvinfo = ave_ethtool_get_drvinfo,
+ .nway_reset = phy_ethtool_nway_reset,
+ .get_link = ethtool_op_get_link,
+ .get_msglevel = ave_ethtool_get_msglevel,
+ .set_msglevel = ave_ethtool_set_msglevel,
+ .get_wol = ave_ethtool_get_wol,
+ .set_wol = ave_ethtool_set_wol,
+ .get_pauseparam = ave_ethtool_get_pauseparam,
+ .set_pauseparam = ave_ethtool_set_pauseparam,
+};
+
+static int ave_mdiobus_read(struct mii_bus *bus, int phyid, int regnum)
+{
+ struct net_device *ndev = bus->priv;
+ struct ave_private *priv = netdev_priv(ndev);
+ u32 mdioctl, mdiosr;
+ int ret;
+
+ /* write address */
+ writel((phyid << 8) | regnum, priv->base + AVE_MDIOAR);
+
+ /* read request */
+ mdioctl = readl(priv->base + AVE_MDIOCTR);
+ writel((mdioctl | AVE_MDIOCTR_RREQ) & ~AVE_MDIOCTR_WREQ,
+ priv->base + AVE_MDIOCTR);
+
+ ret = readl_poll_timeout(priv->base + AVE_MDIOSR, mdiosr,
+ !(mdiosr & AVE_MDIOSR_STS), 20, 2000);
+ if (ret) {
+ netdev_err(ndev, "failed to read (phy:%d reg:%x)\n",
+ phyid, regnum);
+ return ret;
+ }
+
+ return readl(priv->base + AVE_MDIORDR) & GENMASK(15, 0);
+}
+
+static int ave_mdiobus_write(struct mii_bus *bus,
+ int phyid, int regnum, u16 val)
+{
+ struct net_device *ndev = bus->priv;
+ struct ave_private *priv = netdev_priv(ndev);
+ u32 mdioctl, mdiosr;
+ int ret;
+
+ /* write address */
+ writel((phyid << 8) | regnum, priv->base + AVE_MDIOAR);
+
+ /* write data */
+ writel(val, priv->base + AVE_MDIOWDR);
+
+ /* write request */
+ mdioctl = readl(priv->base + AVE_MDIOCTR);
+ writel((mdioctl | AVE_MDIOCTR_WREQ) & ~AVE_MDIOCTR_RREQ,
+ priv->base + AVE_MDIOCTR);
+
+ ret = readl_poll_timeout(priv->base + AVE_MDIOSR, mdiosr,
+ !(mdiosr & AVE_MDIOSR_STS), 20, 2000);
+ if (ret)
+ netdev_err(ndev, "failed to write (phy:%d reg:%x)\n",
+ phyid, regnum);
+
+ return ret;
+}
+
+static int ave_dma_map(struct net_device *ndev, struct ave_desc *desc,
+ void *ptr, size_t len,
+ enum dma_data_direction dir, dma_addr_t *paddr)
+{
+ dma_addr_t map_addr;
+
+ map_addr = dma_map_single(ndev->dev.parent, ptr, len, dir);
+ if (unlikely(dma_mapping_error(ndev->dev.parent, map_addr)))
+ return -ENOMEM;
+
+ desc->skbs_dma = map_addr;
+ desc->skbs_dmalen = len;
+ *paddr = map_addr;
+
+ return 0;
+}
+
+static void ave_dma_unmap(struct net_device *ndev, struct ave_desc *desc,
+ enum dma_data_direction dir)
+{
+ if (!desc->skbs_dma)
+ return;
+
+ dma_unmap_single(ndev->dev.parent,
+ desc->skbs_dma, desc->skbs_dmalen, dir);
+ desc->skbs_dma = 0;
+}
+
+/* Prepare Rx descriptor and memory */
+static int ave_rxdesc_prepare(struct net_device *ndev, int entry)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ struct sk_buff *skb;
+ dma_addr_t paddr;
+ int ret;
+
+ skb = priv->rx.desc[entry].skbs;
+ if (!skb) {
+ skb = netdev_alloc_skb_ip_align(ndev,
+ AVE_MAX_ETHFRAME);
+ if (!skb) {
+ netdev_err(ndev, "can't allocate skb for Rx\n");
+ return -ENOMEM;
+ }
+ }
+
+ /* set disable to cmdsts */
+ ave_desc_write_cmdsts(ndev, AVE_DESCID_RX, entry,
+ AVE_STS_INTR | AVE_STS_OWN);
+
+ /* map Rx buffer
+ * Rx buffer set to the Rx descriptor has two restrictions:
+ * - Rx buffer address is 4 byte aligned.
+ * - Rx buffer begins with 2 byte headroom, and data will be put from
+ * (buffer + 2).
+ * To satisfy this, specify the address to put back the buffer
+ * pointer advanced by NET_IP_ALIGN by netdev_alloc_skb_ip_align(),
+ * and expand the map size by NET_IP_ALIGN.
+ */
+ ret = ave_dma_map(ndev, &priv->rx.desc[entry],
+ skb->data - NET_IP_ALIGN,
+ AVE_MAX_ETHFRAME + NET_IP_ALIGN,
+ DMA_FROM_DEVICE, &paddr);
+ if (ret) {
+ netdev_err(ndev, "can't map skb for Rx\n");
+ dev_kfree_skb_any(skb);
+ return ret;
+ }
+ priv->rx.desc[entry].skbs = skb;
+
+ /* set buffer pointer */
+ ave_desc_write_addr(ndev, AVE_DESCID_RX, entry, paddr);
+
+ /* set enable to cmdsts */
+ ave_desc_write_cmdsts(ndev, AVE_DESCID_RX, entry,
+ AVE_STS_INTR | AVE_MAX_ETHFRAME);
+
+ return ret;
+}
+
+/* Switch state of descriptor */
+static int ave_desc_switch(struct net_device *ndev, enum desc_state state)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ int ret = 0;
+ u32 val;
+
+ switch (state) {
+ case AVE_DESC_START:
+ writel(AVE_DESCC_TD | AVE_DESCC_RD0, priv->base + AVE_DESCC);
+ break;
+
+ case AVE_DESC_STOP:
+ writel(0, priv->base + AVE_DESCC);
+ if (readl_poll_timeout(priv->base + AVE_DESCC, val, !val,
+ 150, 15000)) {
+ netdev_err(ndev, "can't stop descriptor\n");
+ ret = -EBUSY;
+ }
+ break;
+
+ case AVE_DESC_RX_SUSPEND:
+ val = readl(priv->base + AVE_DESCC);
+ val |= AVE_DESCC_RDSTP;
+ val &= ~AVE_DESCC_STATUS_MASK;
+ writel(val, priv->base + AVE_DESCC);
+ if (readl_poll_timeout(priv->base + AVE_DESCC, val,
+ val & (AVE_DESCC_RDSTP << 16),
+ 150, 150000)) {
+ netdev_err(ndev, "can't suspend descriptor\n");
+ ret = -EBUSY;
+ }
+ break;
+
+ case AVE_DESC_RX_PERMIT:
+ val = readl(priv->base + AVE_DESCC);
+ val &= ~AVE_DESCC_RDSTP;
+ val &= ~AVE_DESCC_STATUS_MASK;
+ writel(val, priv->base + AVE_DESCC);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int ave_tx_complete(struct net_device *ndev)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ u32 proc_idx, done_idx, ndesc, cmdsts;
+ unsigned int nr_freebuf = 0;
+ unsigned int tx_packets = 0;
+ unsigned int tx_bytes = 0;
+
+ proc_idx = priv->tx.proc_idx;
+ done_idx = priv->tx.done_idx;
+ ndesc = priv->tx.ndesc;
+
+ /* free pre-stored skb from done_idx to proc_idx */
+ while (proc_idx != done_idx) {
+ cmdsts = ave_desc_read_cmdsts(ndev, AVE_DESCID_TX, done_idx);
+
+ /* do nothing if owner is HW (==1 for Tx) */
+ if (cmdsts & AVE_STS_OWN)
+ break;
+
+ /* check Tx status and updates statistics */
+ if (cmdsts & AVE_STS_OK) {
+ tx_bytes += cmdsts & AVE_STS_PKTLEN_TX_MASK;
+ /* success */
+ if (cmdsts & AVE_STS_LAST)
+ tx_packets++;
+ } else {
+ /* error */
+ if (cmdsts & AVE_STS_LAST) {
+ priv->stats_tx.errors++;
+ if (cmdsts & (AVE_STS_OWC | AVE_STS_EC))
+ priv->stats_tx.collisions++;
+ }
+ }
+
+ /* release skb */
+ if (priv->tx.desc[done_idx].skbs) {
+ ave_dma_unmap(ndev, &priv->tx.desc[done_idx],
+ DMA_TO_DEVICE);
+ dev_consume_skb_any(priv->tx.desc[done_idx].skbs);
+ priv->tx.desc[done_idx].skbs = NULL;
+ nr_freebuf++;
+ }
+ done_idx = (done_idx + 1) % ndesc;
+ }
+
+ priv->tx.done_idx = done_idx;
+
+ /* update stats */
+ u64_stats_update_begin(&priv->stats_tx.syncp);
+ priv->stats_tx.packets += tx_packets;
+ priv->stats_tx.bytes += tx_bytes;
+ u64_stats_update_end(&priv->stats_tx.syncp);
+
+ /* wake queue for freeing buffer */
+ if (unlikely(netif_queue_stopped(ndev)) && nr_freebuf)
+ netif_wake_queue(ndev);
+
+ return nr_freebuf;
+}
+
+static int ave_rx_receive(struct net_device *ndev, int num)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ struct sk_buff *skb;
+ u32 proc_idx, done_idx, ndesc, cmdsts;
+ int restpkt, npkts;
+ unsigned int pktlen;
+ unsigned int rx_packets = 0;
+ unsigned int rx_bytes = 0;
+
+ proc_idx = priv->rx.proc_idx;
+ done_idx = priv->rx.done_idx;
+ ndesc = priv->rx.ndesc;
+ restpkt = ((proc_idx + ndesc - 1) - done_idx) % ndesc;
+
+ for (npkts = 0; npkts < num; npkts++) {
+ /* we can't receive more packet, so fill desc quickly */
+ if (--restpkt < 0)
+ break;
+
+ cmdsts = ave_desc_read_cmdsts(ndev, AVE_DESCID_RX, proc_idx);
+
+ /* do nothing if owner is HW (==0 for Rx) */
+ if (!(cmdsts & AVE_STS_OWN))
+ break;
+
+ if (!(cmdsts & AVE_STS_OK)) {
+ priv->stats_rx.errors++;
+ proc_idx = (proc_idx + 1) % ndesc;
+ continue;
+ }
+
+ pktlen = cmdsts & AVE_STS_PKTLEN_RX_MASK;
+
+ /* get skbuff for rx */
+ skb = priv->rx.desc[proc_idx].skbs;
+ priv->rx.desc[proc_idx].skbs = NULL;
+
+ ave_dma_unmap(ndev, &priv->rx.desc[proc_idx], DMA_FROM_DEVICE);
+
+ skb->dev = ndev;
+ skb_put(skb, pktlen);
+ skb->protocol = eth_type_trans(skb, ndev);
+
+ if ((cmdsts & AVE_STS_CSSV) && (!(cmdsts & AVE_STS_CSER)))
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ rx_packets++;
+ rx_bytes += pktlen;
+
+ netif_receive_skb(skb);
+
+ proc_idx = (proc_idx + 1) % ndesc;
+ }
+
+ priv->rx.proc_idx = proc_idx;
+
+ /* update stats */
+ u64_stats_update_begin(&priv->stats_rx.syncp);
+ priv->stats_rx.packets += rx_packets;
+ priv->stats_rx.bytes += rx_bytes;
+ u64_stats_update_end(&priv->stats_rx.syncp);
+
+ /* refill the Rx buffers */
+ while (proc_idx != done_idx) {
+ if (ave_rxdesc_prepare(ndev, done_idx))
+ break;
+ done_idx = (done_idx + 1) % ndesc;
+ }
+
+ priv->rx.done_idx = done_idx;
+
+ return npkts;
+}
+
+static int ave_napi_poll_rx(struct napi_struct *napi, int budget)
+{
+ struct ave_private *priv;
+ struct net_device *ndev;
+ int num;
+
+ priv = container_of(napi, struct ave_private, napi_rx);
+ ndev = priv->ndev;
+
+ num = ave_rx_receive(ndev, budget);
+ if (num < budget) {
+ napi_complete_done(napi, num);
+
+ /* enable Rx interrupt when NAPI finishes */
+ ave_irq_enable(ndev, AVE_GI_RXIINT);
+ }
+
+ return num;
+}
+
+static int ave_napi_poll_tx(struct napi_struct *napi, int budget)
+{
+ struct ave_private *priv;
+ struct net_device *ndev;
+ int num;
+
+ priv = container_of(napi, struct ave_private, napi_tx);
+ ndev = priv->ndev;
+
+ num = ave_tx_complete(ndev);
+ napi_complete(napi);
+
+ /* enable Tx interrupt when NAPI finishes */
+ ave_irq_enable(ndev, AVE_GI_TX);
+
+ return num;
+}
+
+static void ave_global_reset(struct net_device *ndev)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ u32 val;
+
+ /* set config register */
+ val = AVE_CFGR_FLE | AVE_CFGR_IPFCEN | AVE_CFGR_CHE;
+ if (!phy_interface_mode_is_rgmii(priv->phy_mode))
+ val |= AVE_CFGR_MII;
+ writel(val, priv->base + AVE_CFGR);
+
+ /* reset RMII register */
+ val = readl(priv->base + AVE_RSTCTRL);
+ val &= ~AVE_RSTCTRL_RMIIRST;
+ writel(val, priv->base + AVE_RSTCTRL);
+
+ /* assert reset */
+ writel(AVE_GRR_GRST | AVE_GRR_PHYRST, priv->base + AVE_GRR);
+ msleep(20);
+
+ /* 1st, negate PHY reset only */
+ writel(AVE_GRR_GRST, priv->base + AVE_GRR);
+ msleep(40);
+
+ /* negate reset */
+ writel(0, priv->base + AVE_GRR);
+ msleep(40);
+
+ /* negate RMII register */
+ val = readl(priv->base + AVE_RSTCTRL);
+ val |= AVE_RSTCTRL_RMIIRST;
+ writel(val, priv->base + AVE_RSTCTRL);
+
+ ave_irq_disable_all(ndev);
+}
+
+static void ave_rxfifo_reset(struct net_device *ndev)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ u32 rxcr_org;
+
+ /* save and disable MAC receive op */
+ rxcr_org = readl(priv->base + AVE_RXCR);
+ writel(rxcr_org & (~AVE_RXCR_RXEN), priv->base + AVE_RXCR);
+
+ /* suspend Rx descriptor */
+ ave_desc_switch(ndev, AVE_DESC_RX_SUSPEND);
+
+ /* receive all packets before descriptor starts */
+ ave_rx_receive(ndev, priv->rx.ndesc);
+
+ /* assert reset */
+ writel(AVE_GRR_RXFFR, priv->base + AVE_GRR);
+ usleep_range(40, 50);
+
+ /* negate reset */
+ writel(0, priv->base + AVE_GRR);
+ usleep_range(10, 20);
+
+ /* negate interrupt status */
+ writel(AVE_GI_RXOVF, priv->base + AVE_GISR);
+
+ /* permit descriptor */
+ ave_desc_switch(ndev, AVE_DESC_RX_PERMIT);
+
+ /* restore MAC reccieve op */
+ writel(rxcr_org, priv->base + AVE_RXCR);
+}
+
+static irqreturn_t ave_irq_handler(int irq, void *netdev)
+{
+ struct net_device *ndev = (struct net_device *)netdev;
+ struct ave_private *priv = netdev_priv(ndev);
+ u32 gimr_val, gisr_val;
+
+ gimr_val = ave_irq_disable_all(ndev);
+
+ /* get interrupt status */
+ gisr_val = readl(priv->base + AVE_GISR);
+
+ /* PHY */
+ if (gisr_val & AVE_GI_PHY)
+ writel(AVE_GI_PHY, priv->base + AVE_GISR);
+
+ /* check exceeding packet */
+ if (gisr_val & AVE_GI_RXERR) {
+ writel(AVE_GI_RXERR, priv->base + AVE_GISR);
+ netdev_err(ndev, "receive a packet exceeding frame buffer\n");
+ }
+
+ gisr_val &= gimr_val;
+ if (!gisr_val)
+ goto exit_isr;
+
+ /* RxFIFO overflow */
+ if (gisr_val & AVE_GI_RXOVF) {
+ priv->stats_rx.fifo_errors++;
+ ave_rxfifo_reset(ndev);
+ goto exit_isr;
+ }
+
+ /* Rx drop */
+ if (gisr_val & AVE_GI_RXDROP) {
+ priv->stats_rx.dropped++;
+ writel(AVE_GI_RXDROP, priv->base + AVE_GISR);
+ }
+
+ /* Rx interval */
+ if (gisr_val & AVE_GI_RXIINT) {
+ napi_schedule(&priv->napi_rx);
+ /* still force to disable Rx interrupt until NAPI finishes */
+ gimr_val &= ~AVE_GI_RXIINT;
+ }
+
+ /* Tx completed */
+ if (gisr_val & AVE_GI_TX) {
+ napi_schedule(&priv->napi_tx);
+ /* still force to disable Tx interrupt until NAPI finishes */
+ gimr_val &= ~AVE_GI_TX;
+ }
+
+exit_isr:
+ ave_irq_restore(ndev, gimr_val);
+
+ return IRQ_HANDLED;
+}
+
+static int ave_pfsel_start(struct net_device *ndev, unsigned int entry)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ u32 val;
+
+ if (WARN_ON(entry > AVE_PF_SIZE))
+ return -EINVAL;
+
+ val = readl(priv->base + AVE_PFEN);
+ writel(val | BIT(entry), priv->base + AVE_PFEN);
+
+ return 0;
+}
+
+static int ave_pfsel_stop(struct net_device *ndev, unsigned int entry)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ u32 val;
+
+ if (WARN_ON(entry > AVE_PF_SIZE))
+ return -EINVAL;
+
+ val = readl(priv->base + AVE_PFEN);
+ writel(val & ~BIT(entry), priv->base + AVE_PFEN);
+
+ return 0;
+}
+
+static int ave_pfsel_set_macaddr(struct net_device *ndev,
+ unsigned int entry,
+ const unsigned char *mac_addr,
+ unsigned int set_size)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+
+ if (WARN_ON(entry > AVE_PF_SIZE))
+ return -EINVAL;
+ if (WARN_ON(set_size > 6))
+ return -EINVAL;
+
+ ave_pfsel_stop(ndev, entry);
+
+ /* set MAC address for the filter */
+ ave_hw_write_macaddr(ndev, mac_addr,
+ AVE_PKTF(entry), AVE_PKTF(entry) + 4);
+
+ /* set byte mask */
+ writel(GENMASK(31, set_size) & AVE_PFMBYTE_MASK0,
+ priv->base + AVE_PFMBYTE(entry));
+ writel(AVE_PFMBYTE_MASK1, priv->base + AVE_PFMBYTE(entry) + 4);
+
+ /* set bit mask filter */
+ writel(AVE_PFMBIT_MASK, priv->base + AVE_PFMBIT(entry));
+
+ /* set selector to ring 0 */
+ writel(0, priv->base + AVE_PFSEL(entry));
+
+ /* restart filter */
+ ave_pfsel_start(ndev, entry);
+
+ return 0;
+}
+
+static void ave_pfsel_set_promisc(struct net_device *ndev,
+ unsigned int entry, u32 rxring)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+
+ if (WARN_ON(entry > AVE_PF_SIZE))
+ return;
+
+ ave_pfsel_stop(ndev, entry);
+
+ /* set byte mask */
+ writel(AVE_PFMBYTE_MASK0, priv->base + AVE_PFMBYTE(entry));
+ writel(AVE_PFMBYTE_MASK1, priv->base + AVE_PFMBYTE(entry) + 4);
+
+ /* set bit mask filter */
+ writel(AVE_PFMBIT_MASK, priv->base + AVE_PFMBIT(entry));
+
+ /* set selector to rxring */
+ writel(rxring, priv->base + AVE_PFSEL(entry));
+
+ ave_pfsel_start(ndev, entry);
+}
+
+static void ave_pfsel_init(struct net_device *ndev)
+{
+ int i;
+ unsigned char bcast_mac[ETH_ALEN];
+
+ eth_broadcast_addr(bcast_mac);
+
+ for (i = 0; i < AVE_PF_SIZE; i++)
+ ave_pfsel_stop(ndev, i);
+
+ /* promiscious entry, select ring 0 */
+ ave_pfsel_set_promisc(ndev, AVE_PFNUM_FILTER, 0);
+
+ /* unicast entry */
+ ave_pfsel_set_macaddr(ndev, AVE_PFNUM_UNICAST, ndev->dev_addr, 6);
+
+ /* broadcast entry */
+ ave_pfsel_set_macaddr(ndev, AVE_PFNUM_BROADCAST, bcast_mac, 6);
+}
+
+static void ave_phy_adjust_link(struct net_device *ndev)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ struct phy_device *phydev = ndev->phydev;
+ u32 val, txcr, rxcr, rxcr_org;
+ u16 rmt_adv = 0, lcl_adv = 0;
+ u8 cap;
+
+ /* set RGMII speed */
+ val = readl(priv->base + AVE_TXCR);
+ val &= ~(AVE_TXCR_TXSPD_100 | AVE_TXCR_TXSPD_1G);
+
+ if (phy_interface_is_rgmii(phydev) && phydev->speed == SPEED_1000)
+ val |= AVE_TXCR_TXSPD_1G;
+ else if (phydev->speed == SPEED_100)
+ val |= AVE_TXCR_TXSPD_100;
+
+ writel(val, priv->base + AVE_TXCR);
+
+ /* set RMII speed (100M/10M only) */
+ if (!phy_interface_is_rgmii(phydev)) {
+ val = readl(priv->base + AVE_LINKSEL);
+ if (phydev->speed == SPEED_10)
+ val &= ~AVE_LINKSEL_100M;
+ else
+ val |= AVE_LINKSEL_100M;
+ writel(val, priv->base + AVE_LINKSEL);
+ }
+
+ /* check current RXCR/TXCR */
+ rxcr = readl(priv->base + AVE_RXCR);
+ txcr = readl(priv->base + AVE_TXCR);
+ rxcr_org = rxcr;
+
+ if (phydev->duplex) {
+ rxcr |= AVE_RXCR_FDUPEN;
+
+ if (phydev->pause)
+ rmt_adv |= LPA_PAUSE_CAP;
+ if (phydev->asym_pause)
+ rmt_adv |= LPA_PAUSE_ASYM;
+ if (phydev->advertising & ADVERTISED_Pause)
+ lcl_adv |= ADVERTISE_PAUSE_CAP;
+ if (phydev->advertising & ADVERTISED_Asym_Pause)
+ lcl_adv |= ADVERTISE_PAUSE_ASYM;
+
+ cap = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
+ if (cap & FLOW_CTRL_TX)
+ txcr |= AVE_TXCR_FLOCTR;
+ else
+ txcr &= ~AVE_TXCR_FLOCTR;
+ if (cap & FLOW_CTRL_RX)
+ rxcr |= AVE_RXCR_FLOCTR;
+ else
+ rxcr &= ~AVE_RXCR_FLOCTR;
+ } else {
+ rxcr &= ~AVE_RXCR_FDUPEN;
+ rxcr &= ~AVE_RXCR_FLOCTR;
+ txcr &= ~AVE_TXCR_FLOCTR;
+ }
+
+ if (rxcr_org != rxcr) {
+ /* disable Rx mac */
+ writel(rxcr & ~AVE_RXCR_RXEN, priv->base + AVE_RXCR);
+ /* change and enable TX/Rx mac */
+ writel(txcr, priv->base + AVE_TXCR);
+ writel(rxcr, priv->base + AVE_RXCR);
+ }
+
+ phy_print_status(phydev);
+}
+
+static void ave_macaddr_init(struct net_device *ndev)
+{
+ ave_hw_write_macaddr(ndev, ndev->dev_addr, AVE_RXMAC1R, AVE_RXMAC2R);
+
+ /* pfsel unicast entry */
+ ave_pfsel_set_macaddr(ndev, AVE_PFNUM_UNICAST, ndev->dev_addr, 6);
+}
+
+static int ave_init(struct net_device *ndev)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ struct device *dev = ndev->dev.parent;
+ struct device_node *np = dev->of_node, *mdio_np;
+ struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
+ struct phy_device *phydev;
+ int ret;
+
+ /* enable clk because of hw access until ndo_open */
+ ret = clk_prepare_enable(priv->clk);
+ if (ret) {
+ dev_err(dev, "can't enable clock\n");
+ return ret;
+ }
+ ret = reset_control_deassert(priv->rst);
+ if (ret) {
+ dev_err(dev, "can't deassert reset\n");
+ goto out_clk_disable;
+ }
+
+ ave_global_reset(ndev);
+
+ mdio_np = of_get_child_by_name(np, "mdio");
+ if (!mdio_np) {
+ dev_err(dev, "mdio node not found\n");
+ ret = -EINVAL;
+ goto out_reset_assert;
+ }
+ ret = of_mdiobus_register(priv->mdio, mdio_np);
+ of_node_put(mdio_np);
+ if (ret) {
+ dev_err(dev, "failed to register mdiobus\n");
+ goto out_reset_assert;
+ }
+
+ phydev = of_phy_get_and_connect(ndev, np, ave_phy_adjust_link);
+ if (!phydev) {
+ dev_err(dev, "could not attach to PHY\n");
+ ret = -ENODEV;
+ goto out_mdio_unregister;
+ }
+
+ priv->phydev = phydev;
+
+ phy_ethtool_get_wol(phydev, &wol);
+ device_set_wakeup_capable(&ndev->dev, !!wol.supported);
+
+ if (!phy_interface_is_rgmii(phydev)) {
+ phydev->supported &= ~PHY_GBIT_FEATURES;
+ phydev->supported |= PHY_BASIC_FEATURES;
+ }
+ phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
+
+ phy_attached_info(phydev);
+
+ return 0;
+
+out_mdio_unregister:
+ mdiobus_unregister(priv->mdio);
+out_reset_assert:
+ reset_control_assert(priv->rst);
+out_clk_disable:
+ clk_disable_unprepare(priv->clk);
+
+ return ret;
+}
+
+static void ave_uninit(struct net_device *ndev)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+
+ phy_disconnect(priv->phydev);
+ mdiobus_unregister(priv->mdio);
+
+ /* disable clk because of hw access after ndo_stop */
+ reset_control_assert(priv->rst);
+ clk_disable_unprepare(priv->clk);
+}
+
+static int ave_open(struct net_device *ndev)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ int entry;
+ int ret;
+ u32 val;
+
+ ret = request_irq(priv->irq, ave_irq_handler, IRQF_SHARED, ndev->name,
+ ndev);
+ if (ret)
+ return ret;
+
+ priv->tx.desc = kcalloc(priv->tx.ndesc, sizeof(*priv->tx.desc),
+ GFP_KERNEL);
+ if (!priv->tx.desc) {
+ ret = -ENOMEM;
+ goto out_free_irq;
+ }
+
+ priv->rx.desc = kcalloc(priv->rx.ndesc, sizeof(*priv->rx.desc),
+ GFP_KERNEL);
+ if (!priv->rx.desc) {
+ kfree(priv->tx.desc);
+ ret = -ENOMEM;
+ goto out_free_irq;
+ }
+
+ /* initialize Tx work and descriptor */
+ priv->tx.proc_idx = 0;
+ priv->tx.done_idx = 0;
+ for (entry = 0; entry < priv->tx.ndesc; entry++) {
+ ave_desc_write_cmdsts(ndev, AVE_DESCID_TX, entry, 0);
+ ave_desc_write_addr(ndev, AVE_DESCID_TX, entry, 0);
+ }
+ writel(AVE_TXDC_ADDR_START
+ | (((priv->tx.ndesc * priv->desc_size) << 16) & AVE_TXDC_SIZE),
+ priv->base + AVE_TXDC);
+
+ /* initialize Rx work and descriptor */
+ priv->rx.proc_idx = 0;
+ priv->rx.done_idx = 0;
+ for (entry = 0; entry < priv->rx.ndesc; entry++) {
+ if (ave_rxdesc_prepare(ndev, entry))
+ break;
+ }
+ writel(AVE_RXDC0_ADDR_START
+ | (((priv->rx.ndesc * priv->desc_size) << 16) & AVE_RXDC0_SIZE),
+ priv->base + AVE_RXDC0);
+
+ ave_desc_switch(ndev, AVE_DESC_START);
+
+ ave_pfsel_init(ndev);
+ ave_macaddr_init(ndev);
+
+ /* set Rx configuration */
+ /* full duplex, enable pause drop, enalbe flow control */
+ val = AVE_RXCR_RXEN | AVE_RXCR_FDUPEN | AVE_RXCR_DRPEN |
+ AVE_RXCR_FLOCTR | (AVE_MAX_ETHFRAME & AVE_RXCR_MPSIZ_MASK);
+ writel(val, priv->base + AVE_RXCR);
+
+ /* set Tx configuration */
+ /* enable flow control, disable loopback */
+ writel(AVE_TXCR_FLOCTR, priv->base + AVE_TXCR);
+
+ /* enable timer, clear EN,INTM, and mask interval unit(BSCK) */
+ val = readl(priv->base + AVE_IIRQC) & AVE_IIRQC_BSCK;
+ val |= AVE_IIRQC_EN0 | (AVE_INTM_COUNT << 16);
+ writel(val, priv->base + AVE_IIRQC);
+
+ val = AVE_GI_RXIINT | AVE_GI_RXOVF | AVE_GI_TX;
+ ave_irq_restore(ndev, val);
+
+ napi_enable(&priv->napi_rx);
+ napi_enable(&priv->napi_tx);
+
+ phy_start(ndev->phydev);
+ phy_start_aneg(ndev->phydev);
+ netif_start_queue(ndev);
+
+ return 0;
+
+out_free_irq:
+ disable_irq(priv->irq);
+ free_irq(priv->irq, ndev);
+
+ return ret;
+}
+
+static int ave_stop(struct net_device *ndev)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ int entry;
+
+ ave_irq_disable_all(ndev);
+ disable_irq(priv->irq);
+ free_irq(priv->irq, ndev);
+
+ netif_tx_disable(ndev);
+ phy_stop(ndev->phydev);
+ napi_disable(&priv->napi_tx);
+ napi_disable(&priv->napi_rx);
+
+ ave_desc_switch(ndev, AVE_DESC_STOP);
+
+ /* free Tx buffer */
+ for (entry = 0; entry < priv->tx.ndesc; entry++) {
+ if (!priv->tx.desc[entry].skbs)
+ continue;
+
+ ave_dma_unmap(ndev, &priv->tx.desc[entry], DMA_TO_DEVICE);
+ dev_kfree_skb_any(priv->tx.desc[entry].skbs);
+ priv->tx.desc[entry].skbs = NULL;
+ }
+ priv->tx.proc_idx = 0;
+ priv->tx.done_idx = 0;
+
+ /* free Rx buffer */
+ for (entry = 0; entry < priv->rx.ndesc; entry++) {
+ if (!priv->rx.desc[entry].skbs)
+ continue;
+
+ ave_dma_unmap(ndev, &priv->rx.desc[entry], DMA_FROM_DEVICE);
+ dev_kfree_skb_any(priv->rx.desc[entry].skbs);
+ priv->rx.desc[entry].skbs = NULL;
+ }
+ priv->rx.proc_idx = 0;
+ priv->rx.done_idx = 0;
+
+ kfree(priv->tx.desc);
+ kfree(priv->rx.desc);
+
+ return 0;
+}
+
+static int ave_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ u32 proc_idx, done_idx, ndesc, cmdsts;
+ int ret, freepkt;
+ dma_addr_t paddr;
+
+ proc_idx = priv->tx.proc_idx;
+ done_idx = priv->tx.done_idx;
+ ndesc = priv->tx.ndesc;
+ freepkt = ((done_idx + ndesc - 1) - proc_idx) % ndesc;
+
+ /* stop queue when not enough entry */
+ if (unlikely(freepkt < 1)) {
+ netif_stop_queue(ndev);
+ return NETDEV_TX_BUSY;
+ }
+
+ /* add padding for short packet */
+ if (skb_put_padto(skb, ETH_ZLEN)) {
+ priv->stats_tx.dropped++;
+ return NETDEV_TX_OK;
+ }
+
+ /* map Tx buffer
+ * Tx buffer set to the Tx descriptor doesn't have any restriction.
+ */
+ ret = ave_dma_map(ndev, &priv->tx.desc[proc_idx],
+ skb->data, skb->len, DMA_TO_DEVICE, &paddr);
+ if (ret) {
+ dev_kfree_skb_any(skb);
+ priv->stats_tx.dropped++;
+ return NETDEV_TX_OK;
+ }
+
+ priv->tx.desc[proc_idx].skbs = skb;
+
+ ave_desc_write_addr(ndev, AVE_DESCID_TX, proc_idx, paddr);
+
+ cmdsts = AVE_STS_OWN | AVE_STS_1ST | AVE_STS_LAST
+ | (skb->len & AVE_STS_PKTLEN_TX_MASK);
+
+ /* set interrupt per AVE_FORCE_TXINTCNT or when queue is stopped */
+ if (!(proc_idx % AVE_FORCE_TXINTCNT) || netif_queue_stopped(ndev))
+ cmdsts |= AVE_STS_INTR;
+
+ /* disable checksum calculation when skb doesn't calurate checksum */
+ if (skb->ip_summed == CHECKSUM_NONE ||
+ skb->ip_summed == CHECKSUM_UNNECESSARY)
+ cmdsts |= AVE_STS_NOCSUM;
+
+ ave_desc_write_cmdsts(ndev, AVE_DESCID_TX, proc_idx, cmdsts);
+
+ priv->tx.proc_idx = (proc_idx + 1) % ndesc;
+
+ return NETDEV_TX_OK;
+}
+
+static int ave_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
+{
+ return phy_mii_ioctl(ndev->phydev, ifr, cmd);
+}
+
+static void ave_set_rx_mode(struct net_device *ndev)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ struct netdev_hw_addr *hw_adr;
+ int count, mc_cnt = netdev_mc_count(ndev);
+ u32 val;
+ static const u8 v4multi_macadr[6] = {
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ static const u8 v6multi_macadr[6] = {
+ 0x33, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ /* MAC addr filter enable for promiscious mode */
+ val = readl(priv->base + AVE_RXCR);
+ if (ndev->flags & IFF_PROMISC || !mc_cnt)
+ val &= ~AVE_RXCR_AFEN;
+ else
+ val |= AVE_RXCR_AFEN;
+ writel(val, priv->base + AVE_RXCR);
+
+ /* set all multicast address */
+ if ((ndev->flags & IFF_ALLMULTI) || mc_cnt > AVE_PF_MULTICAST_SIZE) {
+ ave_pfsel_set_macaddr(ndev, AVE_PFNUM_MULTICAST,
+ v4multi_macadr, 1);
+ ave_pfsel_set_macaddr(ndev, AVE_PFNUM_MULTICAST + 1,
+ v6multi_macadr, 1);
+ } else {
+ /* stop all multicast filter */
+ for (count = 0; count < AVE_PF_MULTICAST_SIZE; count++)
+ ave_pfsel_stop(ndev, AVE_PFNUM_MULTICAST + count);
+
+ /* set multicast addresses */
+ count = 0;
+ netdev_for_each_mc_addr(hw_adr, ndev) {
+ if (count == mc_cnt)
+ break;
+ ave_pfsel_set_macaddr(ndev, AVE_PFNUM_MULTICAST + count,
+ hw_adr->addr, 6);
+ count++;
+ }
+ }
+}
+
+static void ave_get_stats64(struct net_device *ndev,
+ struct rtnl_link_stats64 *stats)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ unsigned int start;
+
+ do {
+ start = u64_stats_fetch_begin_irq(&priv->stats_rx.syncp);
+ stats->rx_packets = priv->stats_rx.packets;
+ stats->rx_bytes = priv->stats_rx.bytes;
+ } while (u64_stats_fetch_retry_irq(&priv->stats_rx.syncp, start));
+
+ do {
+ start = u64_stats_fetch_begin_irq(&priv->stats_tx.syncp);
+ stats->tx_packets = priv->stats_tx.packets;
+ stats->tx_bytes = priv->stats_tx.bytes;
+ } while (u64_stats_fetch_retry_irq(&priv->stats_tx.syncp, start));
+
+ stats->rx_errors = priv->stats_rx.errors;
+ stats->tx_errors = priv->stats_tx.errors;
+ stats->rx_dropped = priv->stats_rx.dropped;
+ stats->tx_dropped = priv->stats_tx.dropped;
+ stats->rx_fifo_errors = priv->stats_rx.fifo_errors;
+ stats->collisions = priv->stats_tx.collisions;
+}
+
+static int ave_set_mac_address(struct net_device *ndev, void *p)
+{
+ int ret = eth_mac_addr(ndev, p);
+
+ if (ret)
+ return ret;
+
+ ave_macaddr_init(ndev);
+
+ return 0;
+}
+
+static const struct net_device_ops ave_netdev_ops = {
+ .ndo_init = ave_init,
+ .ndo_uninit = ave_uninit,
+ .ndo_open = ave_open,
+ .ndo_stop = ave_stop,
+ .ndo_start_xmit = ave_start_xmit,
+ .ndo_do_ioctl = ave_ioctl,
+ .ndo_set_rx_mode = ave_set_rx_mode,
+ .ndo_get_stats64 = ave_get_stats64,
+ .ndo_set_mac_address = ave_set_mac_address,
+};
+
+static int ave_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct ave_private *priv;
+ struct net_device *ndev;
+ struct resource *res;
+ const struct ave_soc_data *data;
+ const void *mac_addr;
+ phy_interface_t phy_mode;
+ void __iomem *base;
+ u32 ave_id;
+ u64 dma_mask;
+ int irq, ret;
+ char buf[ETHTOOL_FWVERS_LEN];
+
+ data = of_device_get_match_data(dev);
+ if (WARN_ON(!data))
+ return -EINVAL;
+
+ phy_mode = of_get_phy_mode(np);
+ if (phy_mode < 0) {
+ dev_err(dev, "phy-mode not found\n");
+ return -EINVAL;
+ }
+ if ((!phy_interface_mode_is_rgmii(phy_mode)) &&
+ phy_mode != PHY_INTERFACE_MODE_RMII &&
+ phy_mode != PHY_INTERFACE_MODE_MII) {
+ dev_err(dev, "phy-mode is invalid\n");
+ return -EINVAL;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "IRQ not found\n");
+ return irq;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ ndev = alloc_etherdev(sizeof(struct ave_private));
+ if (!ndev) {
+ dev_err(dev, "can't allocate ethernet device\n");
+ return -ENOMEM;
+ }
+
+ ndev->netdev_ops = &ave_netdev_ops;
+ ndev->ethtool_ops = &ave_ethtool_ops;
+ SET_NETDEV_DEV(ndev, dev);
+
+ ndev->features |= (NETIF_F_IP_CSUM | NETIF_F_RXCSUM);
+ ndev->hw_features |= (NETIF_F_IP_CSUM | NETIF_F_RXCSUM);
+
+ ndev->max_mtu = AVE_MAX_ETHFRAME - (ETH_HLEN + ETH_FCS_LEN);
+
+ mac_addr = of_get_mac_address(np);
+ if (mac_addr)
+ ether_addr_copy(ndev->dev_addr, mac_addr);
+
+ /* if the mac address is invalid, use random mac address */
+ if (!is_valid_ether_addr(ndev->dev_addr)) {
+ eth_hw_addr_random(ndev);
+ dev_warn(dev, "Using random MAC address: %pM\n",
+ ndev->dev_addr);
+ }
+
+ priv = netdev_priv(ndev);
+ priv->base = base;
+ priv->irq = irq;
+ priv->ndev = ndev;
+ priv->msg_enable = netif_msg_init(-1, AVE_DEFAULT_MSG_ENABLE);
+ priv->phy_mode = phy_mode;
+ priv->data = data;
+
+ if (IS_DESC_64BIT(priv)) {
+ priv->desc_size = AVE_DESC_SIZE_64;
+ priv->tx.daddr = AVE_TXDM_64;
+ priv->rx.daddr = AVE_RXDM_64;
+ dma_mask = DMA_BIT_MASK(64);
+ } else {
+ priv->desc_size = AVE_DESC_SIZE_32;
+ priv->tx.daddr = AVE_TXDM_32;
+ priv->rx.daddr = AVE_RXDM_32;
+ dma_mask = DMA_BIT_MASK(32);
+ }
+ ret = dma_set_mask(dev, dma_mask);
+ if (ret)
+ goto out_free_netdev;
+
+ priv->tx.ndesc = AVE_NR_TXDESC;
+ priv->rx.ndesc = AVE_NR_RXDESC;
+
+ u64_stats_init(&priv->stats_tx.syncp);
+ u64_stats_init(&priv->stats_rx.syncp);
+
+ priv->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ ret = PTR_ERR(priv->clk);
+ goto out_free_netdev;
+ }
+
+ priv->rst = devm_reset_control_get_optional_shared(dev, NULL);
+ if (IS_ERR(priv->rst)) {
+ ret = PTR_ERR(priv->rst);
+ goto out_free_netdev;
+ }
+
+ priv->mdio = devm_mdiobus_alloc(dev);
+ if (!priv->mdio) {
+ ret = -ENOMEM;
+ goto out_free_netdev;
+ }
+ priv->mdio->priv = ndev;
+ priv->mdio->parent = dev;
+ priv->mdio->read = ave_mdiobus_read;
+ priv->mdio->write = ave_mdiobus_write;
+ priv->mdio->name = "uniphier-mdio";
+ snprintf(priv->mdio->id, MII_BUS_ID_SIZE, "%s-%x",
+ pdev->name, pdev->id);
+
+ /* Register as a NAPI supported driver */
+ netif_napi_add(ndev, &priv->napi_rx, ave_napi_poll_rx, priv->rx.ndesc);
+ netif_tx_napi_add(ndev, &priv->napi_tx, ave_napi_poll_tx,
+ priv->tx.ndesc);
+
+ ret = register_netdev(ndev);
+ if (ret) {
+ dev_err(dev, "failed to register netdevice\n");
+ goto out_del_napi;
+ }
+
+ platform_set_drvdata(pdev, ndev);
+
+ /* get ID and version */
+ ave_id = readl(priv->base + AVE_IDR);
+ ave_hw_read_version(ndev, buf, sizeof(buf));
+
+ dev_info(dev, "Socionext %c%c%c%c Ethernet IP %s (irq=%d, phy=%s)\n",
+ (ave_id >> 24) & 0xff, (ave_id >> 16) & 0xff,
+ (ave_id >> 8) & 0xff, (ave_id >> 0) & 0xff,
+ buf, priv->irq, phy_modes(phy_mode));
+
+ return 0;
+
+out_del_napi:
+ netif_napi_del(&priv->napi_rx);
+ netif_napi_del(&priv->napi_tx);
+out_free_netdev:
+ free_netdev(ndev);
+
+ return ret;
+}
+
+static int ave_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct ave_private *priv = netdev_priv(ndev);
+
+ unregister_netdev(ndev);
+ netif_napi_del(&priv->napi_rx);
+ netif_napi_del(&priv->napi_tx);
+ free_netdev(ndev);
+
+ return 0;
+}
+
+static const struct ave_soc_data ave_pro4_data = {
+ .is_desc_64bit = false,
+};
+
+static const struct ave_soc_data ave_pxs2_data = {
+ .is_desc_64bit = false,
+};
+
+static const struct ave_soc_data ave_ld11_data = {
+ .is_desc_64bit = false,
+};
+
+static const struct ave_soc_data ave_ld20_data = {
+ .is_desc_64bit = true,
+};
+
+static const struct of_device_id of_ave_match[] = {
+ {
+ .compatible = "socionext,uniphier-pro4-ave4",
+ .data = &ave_pro4_data,
+ },
+ {
+ .compatible = "socionext,uniphier-pxs2-ave4",
+ .data = &ave_pxs2_data,
+ },
+ {
+ .compatible = "socionext,uniphier-ld11-ave4",
+ .data = &ave_ld11_data,
+ },
+ {
+ .compatible = "socionext,uniphier-ld20-ave4",
+ .data = &ave_ld20_data,
+ },
+ { /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_ave_match);
+
+static struct platform_driver ave_driver = {
+ .probe = ave_probe,
+ .remove = ave_remove,
+ .driver = {
+ .name = "ave",
+ .of_match_table = of_ave_match,
+ },
+};
+module_platform_driver(ave_driver);
+
+MODULE_DESCRIPTION("Socionext UniPhier AVE ethernet driver");
+MODULE_LICENSE("GPL v2");
--
2.7.4
^ permalink raw reply related
* Re: [PATCH v4 1/2] PCI: mobiveil: Add Mobiveil PCIe Host Bridge IP driver DT bindings
From: Rob Herring @ 2017-12-01 1:10 UTC (permalink / raw)
To: Subrahmanya Lingappa
Cc: linux-pci-u79uwXL29TY76Z2rM5mHXA, bhelgaas-hpIqsD4AKlfQT0dZR+AlfA,
lorenzo.pieralisi-5wv7dgnIgG8, devicetree-u79uwXL29TY76Z2rM5mHXA,
mingkai.hu-3arQi8VN3Tc, peter.newton-3arQi8VN3Tc,
minghuan.lian-3arQi8VN3Tc, rajesh.raina-3arQi8VN3Tc,
rajan.kapoor-3arQi8VN3Tc, prabhjot.singh-3arQi8VN3Tc
In-Reply-To: <1511878648-8188-1-git-send-email-l.subrahmanya-DTHOJn6Rh8lhmhkoCovsdw@public.gmane.org>
On Tue, Nov 28, 2017 at 09:17:28AM -0500, Subrahmanya Lingappa wrote:
> This patch adds the DT bindings for Mobiveil PCIe Host Bridge
> IP driver and updates the vendor prefixes file.
>
> Signed-off-by: Subrahmanya Lingappa <l.subrahmanya-DTHOJn6Rh8lhmhkoCovsdw@public.gmane.org>
> Cc: bhelgaas-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org
> Cc: lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org
> Cc: linux-pci-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
>
> ---
> Fixes:
> - used git mailer, as tabs were converted to spaces by thunderbird before
> - moved the entry to corrrect alphabetical order in vendor-prefixes.txt
> - DT binding file was modified to take care of v3 review comments
>
> .../devicetree/bindings/pci/mobiveil-pcie.txt | 73 ++++++++++++++++++++++
> .../devicetree/bindings/vendor-prefixes.txt | 1 +
> 2 files changed, 74 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/pci/mobiveil-pcie.txt
A few typos, otherwise:
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>
> diff --git a/Documentation/devicetree/bindings/pci/mobiveil-pcie.txt b/Documentation/devicetree/bindings/pci/mobiveil-pcie.txt
> new file mode 100644
> index 0000000..9f3160d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/mobiveil-pcie.txt
> @@ -0,0 +1,73 @@
> +* Mobiveil AXI PCIe Root Port Bridge DT description
> +
> +Mobiveil's GPEX 4.0 is PCIe gen4 a root port bridge IP. This configurable IP
...is a PCIe Gen4 root port...
> +has upto 8 outbound and inbound windows for the address translation.
s/upto/up to/
> +
> +Required properties:
> +- #address-cells: Address representation for root ports, set to <3>
> +- #size-cells: Size representation for root ports, set to <2>
> +- #interrupt-cells: specifies the number of cells needed to encode an
> + interrupt source. The value must be 1.
> +- compatible: Should contain "mbvl,gpex40-pcie"
> +- reg: Should contain PCIe registers location and length
> + "config_axi_slave": PCIe controller registers
> + "csr_axi_slave" : Bridge config registers
> + "gpio_slave" : GPIO registers to control slot power
> + "apb_csr" : MSI registers
> +
> +- device_type: must be "pci"
> +- apio-wins : number of requested apio outbound windows
> + default 2 outbound windows are configured -
> + 1. Config window
> + 2. Memory window
> +- ppio-wins : number of requested ppio inbound windows
> + default 1 inbound memory window is configured.
> +- bus-range: PCI bus numbers covered
> +- interrupt-controller: identifies the node as an interrupt controller
> +- #interrupt-cells: specifies the number of cells needed to encode an
> + interrupt source. The value must be 1.
> +- interrupt-parent : phandle to the interrupt controller that
> + it is attached to, it should be set to gic to point to
> + ARM's Generic Interrupt Controller node in system DT.
> +- interrupts: The interrupt line of the PCIe controller
> + last cell of this fild is set to 4 to
s/fild/field/
> + denote it as IRQ_TYPE_LEVEL_HIGH type interrupt.
> +- interrupt-map-mask,
> + interrupt-map: standard PCI properties to define the mapping of the
> + PCI interface to interrupt numbers.
> +- ranges: ranges for the PCI memory regions (I/O space region is not
> + supported by hardware)
> + Please refer to the standard PCI bus binding document for a more
> + detailed explanation
> +
> +
> +Example:
> +++++++++
> + pcie0: pcie@a0000000 {
> + #address-cells = <3>;
> + #size-cells = <2>;
> + compatible = "mbvl,gpex40-pcie";
> + reg = <0xa0000000 0x00001000>,
> + <0xb0000000 0x00010000>,
> + <0xff000000 0x00200000>,
> + <0xb0010000 0x00001000>;
> + reg-names = "config_axi_slave",
> + "csr_axi_slave",
> + "gpio_slave",
> + "apb_csr";
> + device_type = "pci";
> + apio-wins = <2>;
> + ppio-wins = <1>;
> + bus-range = <0x00000000 0x000000ff>;
> + interrupt-controller;
> + interrupt-parent = <&gic>;
> + #interrupt-cells = <1>;
> + interrupts = < 0 89 4 >;
> + interrupt-map-mask = <0 0 0 7>;
> + interrupt-map = <0 0 0 1 &pci_express 1>,
> + <0 0 0 2 &pci_express 2>,
> + <0 0 0 3 &pci_express 3>,
> + <0 0 0 4 &pci_express 4>;
> + ranges = < 0x83000000 0 0x00000000 0xa8000000 0 0x8000000>;
> +
> + };
> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
> index 0994bdd..8263cc7 100644
> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
> @@ -197,6 +197,7 @@ lwn Liebherr-Werk Nenzing GmbH
> macnica Macnica Americas
> marvell Marvell Technology Group Ltd.
> maxim Maxim Integrated Products
> +mbvl Mobiveil Inc.
> mcube mCube
> meas Measurement Specialties
> mediatek MediaTek Inc.
> --
> 1.8.3.1
>
> --
> 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
--
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 01/13] dt-bindings: Add vendor prefix for Microsemi Corporation
From: Rob Herring @ 2017-12-01 1:14 UTC (permalink / raw)
To: Alexandre Belloni
Cc: James Hogan, Ralf Baechle, linux-mips-6z/3iImG2C8G8FEW9MqTrA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20171128162245.GH21126-m++hUPXGwpdeoWH0uzbU5w@public.gmane.org>
On Tue, Nov 28, 2017 at 05:22:45PM +0100, Alexandre Belloni wrote:
> On 28/11/2017 at 16:10:14 +0000, James Hogan wrote:
> > On Tue, Nov 28, 2017 at 04:26:31PM +0100, Alexandre Belloni wrote:
> > > Microsemi Corporation provides semiconductor and system solutions for
> > > aerospace & defense, communications, data center and industrial markets.
> > >
> > > Signed-off-by: Alexandre Belloni <alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> > > ---
> > > Cc: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> > > Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> >
> > Nit: Usually the Cc list goes before the --- line so that it is included
> > in the git history (i.e. these people had the opportunity to comment).
> >
>
> Ok, it depends on the maintainer, some people prefer leaving that out of commit log.
> I'm fine with adding those back in.
Really? First, I've heard that.
In any case,
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
--
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 02/13] dt-bindings: interrupt-controller: Add binding for the Microsemi Ocelot interrupt controller
From: Rob Herring @ 2017-12-01 1:15 UTC (permalink / raw)
To: Alexandre Belloni
Cc: Ralf Baechle, linux-mips-6z/3iImG2C8G8FEW9MqTrA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Jason Cooper
In-Reply-To: <20171128152643.20463-3-alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
On Tue, Nov 28, 2017 at 04:26:32PM +0100, Alexandre Belloni wrote:
> Add the Device Tree binding documentation for the Microsemi Ocelot
> interrupt controller that is part of the ICPU. It is connected directly to
> the MIPS core interrupt controller.
>
> Signed-off-by: Alexandre Belloni <alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> ---
> Cc: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> To: Thomas Gleixner <tglx-hfZtesqFncYOwBW4kG4KsQ@public.gmane.org>
> Cc: Jason Cooper <jason-NLaQJdtUoK4Be96aLqz0jA@public.gmane.org>
>
> .../interrupt-controller/mscc,ocelot-icpu-intr.txt | 22 ++++++++++++++++++++++
> 1 file changed, 22 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/interrupt-controller/mscc,ocelot-icpu-intr.txt
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
--
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 04/13] dt-bindings: pinctrl: Add bindings for Microsemi Ocelot
From: Rob Herring @ 2017-12-01 1:16 UTC (permalink / raw)
To: Alexandre Belloni
Cc: Ralf Baechle, linux-mips, linux-kernel, devicetree, linux-gpio
In-Reply-To: <20171128152643.20463-5-alexandre.belloni@free-electrons.com>
On Tue, Nov 28, 2017 at 04:26:34PM +0100, Alexandre Belloni wrote:
> Add the documentation for the Microsemi Ocelot pinmuxing and gpio
> controller.
>
> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
> ---
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: devicetree@vger.kernel.org
> To: Linus Walleij <linus.walleij@linaro.org>
> Cc: linux-gpio@vger.kernel.org
>
> .../bindings/pinctrl/mscc,ocelot-pinctrl.txt | 39 ++++++++++++++++++++++
> 1 file changed, 39 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.txt
Acked-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* [PATCH v4 0/4] add clk controller driver for Meson-AXG SoC
From: Yixun Lan @ 2017-12-01 1:24 UTC (permalink / raw)
To: Neil Armstrong, Jerome Brunet, Kevin Hilman
Cc: Rob Herring, Mark Rutland, Michael Turquette, Stephen Boyd,
Carlo Caione, Yixun Lan, Qiufang Dai,
linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
Add driver for the clk controller which found in Meson AXG SoC
Note, we deliberately create a seperate source file for the Meson AXG
series, instead of sharing code with previous GXBB/GXL - the file axg.c
It would help us maintaining the code more easily.
Changes since v3 [3]:
- separate dt-bindings header file
- adjust license note as standard way
- replace of_iomap with platform/devm API
- add Rob's Ack to Patch 1,4
Changes since v2 [2]:
- drop register offset calculation
- update dt-bindings for new compatible variant
Changes since v1 [1]:
- rework register definion, use '(offset << 2)' to better match
the description from data sheet
- drop "#include dt-bindings/clock/gxbb-aoclkc.h" from dts
- rebase code to v4.15-rc1
[3]
http://lists.infradead.org/pipermail/linux-amlogic/2017-November/005487.html
http://lists.infradead.org/pipermail/linux-amlogic/2017-November/005488.html
http://lists.infradead.org/pipermail/linux-amlogic/2017-November/005489.html
http://lists.infradead.org/pipermail/linux-amlogic/2017-November/005490.html
[2]
http://lists.infradead.org/pipermail/linux-amlogic/2017-November/005468.html
http://lists.infradead.org/pipermail/linux-amlogic/2017-November/005469.html
http://lists.infradead.org/pipermail/linux-amlogic/2017-November/005470.html
[1]
http://lists.infradead.org/pipermail/linux-amlogic/2017-November/005239.html
http://lists.infradead.org/pipermail/linux-amlogic/2017-November/005240.html
http://lists.infradead.org/pipermail/linux-amlogic/2017-November/005241.html
Qiufang Dai (3):
clk: meson-axg: add clocks dt-bindings required header
clk: meson-axg: add clock controller drivers
arm64: dts: meson-axg: add clock DT info for Meson AXG SoC
Yixun Lan (1):
dt-bindings: clock: add compatible variant for the Meson-AXG
.../bindings/clock/amlogic,gxbb-clkc.txt | 7 +-
arch/arm64/Kconfig.platforms | 1 +
arch/arm64/boot/dts/amlogic/meson-axg.dtsi | 15 +
drivers/clk/meson/Kconfig | 8 +
drivers/clk/meson/Makefile | 1 +
drivers/clk/meson/axg.c | 944 +++++++++++++++++++++
drivers/clk/meson/axg.h | 126 +++
include/dt-bindings/clock/axg-clkc.h | 71 ++
8 files changed, 1171 insertions(+), 2 deletions(-)
create mode 100644 drivers/clk/meson/axg.c
create mode 100644 drivers/clk/meson/axg.h
create mode 100644 include/dt-bindings/clock/axg-clkc.h
--
2.15.0
--
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 v4 1/4] dt-bindings: clock: add compatible variant for the Meson-AXG
From: Yixun Lan @ 2017-12-01 1:24 UTC (permalink / raw)
To: Neil Armstrong, Jerome Brunet, Kevin Hilman
Cc: Mark Rutland, devicetree, Yixun Lan, Michael Turquette,
Stephen Boyd, linux-kernel, Qiufang Dai, Rob Herring,
Carlo Caione, linux-amlogic, linux-clk, linux-arm-kernel
In-Reply-To: <20171201012452.27086-1-yixun.lan@amlogic.com>
Update the documentation to support clock driver for the Amlogic's
Meson-AXG SoC.
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Yixun Lan <yixun.lan@amlogic.com>
---
Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt
index 924040769186..e2b377ed6f91 100644
--- a/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt
+++ b/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt
@@ -5,8 +5,11 @@ controllers within the SoC.
Required Properties:
-- compatible: should be "amlogic,gxbb-clkc" for GXBB SoC,
- or "amlogic,gxl-clkc" for GXL and GXM SoC.
+- compatible: should be:
+ "amlogic,gxbb-clkc" for GXBB SoC,
+ "amlogic,gxl-clkc" for GXL and GXM SoC,
+ "amlogic,axg-clkc" for AXG SoC.
+
- reg: physical base address of the clock controller and length of memory
mapped region.
--
2.15.0
^ permalink raw reply related
* [PATCH v4 2/4] clk: meson-axg: add clocks dt-bindings required header
From: Yixun Lan @ 2017-12-01 1:24 UTC (permalink / raw)
To: Neil Armstrong, Jerome Brunet, Kevin Hilman
Cc: Rob Herring, Mark Rutland, Michael Turquette, Stephen Boyd,
Carlo Caione, Yixun Lan, Qiufang Dai, linux-amlogic, devicetree,
linux-clk, linux-arm-kernel, linux-kernel
In-Reply-To: <20171201012452.27086-1-yixun.lan@amlogic.com>
From: Qiufang Dai <qiufang.dai@amlogic.com>
Add the required header for the clocks ID dt-bindings
exported from various subsystem in the Meson-AXG SoC.
Signed-off-by: Qiufang Dai <qiufang.dai@amlogic.com>
Signed-off-by: Yixun Lan <yixun.lan@amlogic.com>
---
include/dt-bindings/clock/axg-clkc.h | 71 ++++++++++++++++++++++++++++++++++++
1 file changed, 71 insertions(+)
create mode 100644 include/dt-bindings/clock/axg-clkc.h
diff --git a/include/dt-bindings/clock/axg-clkc.h b/include/dt-bindings/clock/axg-clkc.h
new file mode 100644
index 000000000000..941ac70e7f30
--- /dev/null
+++ b/include/dt-bindings/clock/axg-clkc.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Meson-AXG clock tree IDs
+ *
+ * Copyright (c) 2017 Amlogic, Inc. All rights reserved.
+ */
+
+#ifndef __AXG_CLKC_H
+#define __AXG_CLKC_H
+
+#define CLKID_SYS_PLL 0
+#define CLKID_FIXED_PLL 1
+#define CLKID_FCLK_DIV2 2
+#define CLKID_FCLK_DIV3 3
+#define CLKID_FCLK_DIV4 4
+#define CLKID_FCLK_DIV5 5
+#define CLKID_FCLK_DIV7 6
+#define CLKID_GP0_PLL 7
+#define CLKID_CLK81 10
+#define CLKID_MPLL0 11
+#define CLKID_MPLL1 12
+#define CLKID_MPLL2 13
+#define CLKID_MPLL3 14
+#define CLKID_DDR 15
+#define CLKID_AUDIO_LOCKER 16
+#define CLKID_MIPI_DSI_HOST 17
+#define CLKID_ISA 18
+#define CLKID_PL301 19
+#define CLKID_PERIPHS 20
+#define CLKID_SPICC0 21
+#define CLKID_I2C 22
+#define CLKID_RNG0 23
+#define CLKID_UART0 24
+#define CLKID_MIPI_DSI_PHY 25
+#define CLKID_SPICC1 26
+#define CLKID_PCIE_A 27
+#define CLKID_PCIE_B 28
+#define CLKID_HIU_IFACE 29
+#define CLKID_ASSIST_MISC 30
+#define CLKID_SD_EMMC_B 31
+#define CLKID_SD_EMMC_C 32
+#define CLKID_DMA 33
+#define CLKID_SPI 34
+#define CLKID_AUDIO 35
+#define CLKID_ETH 36
+#define CLKID_UART1 37
+#define CLKID_G2D 38
+#define CLKID_USB0 39
+#define CLKID_USB1 40
+#define CLKID_RESET 41
+#define CLKID_USB 42
+#define CLKID_AHB_ARB0 43
+#define CLKID_EFUSE 44
+#define CLKID_BOOT_ROM 45
+#define CLKID_AHB_DATA_BUS 46
+#define CLKID_AHB_CTRL_BUS 47
+#define CLKID_USB1_DDR_BRIDGE 48
+#define CLKID_USB0_DDR_BRIDGE 49
+#define CLKID_MMC_PCLK 50
+#define CLKID_VPU_INTR 51
+#define CLKID_SEC_AHB_AHB3_BRIDGE 52
+#define CLKID_GIC 53
+#define CLKID_AO_MEDIA_CPU 54
+#define CLKID_AO_AHB_SRAM 55
+#define CLKID_AO_AHB_BUS 56
+#define CLKID_AO_IFACE 57
+#define CLKID_AO_I2C 58
+#define CLKID_SD_EMMC_B_CLK0 59
+#define CLKID_SD_EMMC_C_CLK0 60
+
+#endif /* __AXG_CLKC_H */
--
2.15.0
^ 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