* [PATCH v2 0/7] stmmac: dwmac-meson8b: configurable RGMII TX delay
From: Martin Blumenstingl @ 2016-11-25 13:01 UTC (permalink / raw)
To: linux-amlogic, devicetree, netdev, davem, khilman, mark.rutland,
robh+dt
Cc: linux-arm-kernel, alexandre.torgue, peppe.cavallaro, will.deacon,
catalin.marinas, carlo, f.fainelli, Martin Blumenstingl
In-Reply-To: <20161124143417.10178-1-martin.blumenstingl@googlemail.com>
Currently the dwmac-meson8b stmmac glue driver uses a hardcoded 1/4
cycle TX clock delay. This seems to work fine for many boards (for
example Odroid-C2 or Amlogic's reference boards) but there are some
others where TX traffic is simply broken.
There are probably multiple reasons why it's working on some boards
while it's broken on others:
- some of Amlogic's reference boards are using a Micrel PHY
- hardware circuit design
- maybe more...
iperf3 results on my Mecool BB2 board (Meson GXM, RTL8211F PHY) with
TX clock delay disabled on the MAC (as it's enabled in the PHY driver).
TX throughput was virtually zero before:
$ iperf3 -c 192.168.1.100 -R
Connecting to host 192.168.1.100, port 5201
Reverse mode, remote host 192.168.1.100 is sending
[ 4] local 192.168.1.206 port 52828 connected to 192.168.1.100 port 5201
[ ID] Interval Transfer Bandwidth
[ 4] 0.00-1.00 sec 108 MBytes 901 Mbits/sec
[ 4] 1.00-2.00 sec 94.2 MBytes 791 Mbits/sec
[ 4] 2.00-3.00 sec 96.5 MBytes 810 Mbits/sec
[ 4] 3.00-4.00 sec 96.2 MBytes 808 Mbits/sec
[ 4] 4.00-5.00 sec 96.6 MBytes 810 Mbits/sec
[ 4] 5.00-6.00 sec 96.5 MBytes 810 Mbits/sec
[ 4] 6.00-7.00 sec 96.6 MBytes 810 Mbits/sec
[ 4] 7.00-8.00 sec 96.5 MBytes 809 Mbits/sec
[ 4] 8.00-9.00 sec 105 MBytes 884 Mbits/sec
[ 4] 9.00-10.00 sec 111 MBytes 934 Mbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bandwidth Retr
[ 4] 0.00-10.00 sec 1000 MBytes 839 Mbits/sec 0 sender
[ 4] 0.00-10.00 sec 998 MBytes 837 Mbits/sec receiver
iperf Done.
$ iperf3 -c 192.168.1.100
Connecting to host 192.168.1.100, port 5201
[ 4] local 192.168.1.206 port 52832 connected to 192.168.1.100 port 5201
[ ID] Interval Transfer Bandwidth Retr Cwnd
[ 4] 0.00-1.01 sec 99.5 MBytes 829 Mbits/sec 117 139 KBytes
[ 4] 1.01-2.00 sec 105 MBytes 884 Mbits/sec 129 70.7 KBytes
[ 4] 2.00-3.01 sec 107 MBytes 889 Mbits/sec 106 187 KBytes
[ 4] 3.01-4.01 sec 105 MBytes 878 Mbits/sec 92 143 KBytes
[ 4] 4.01-5.00 sec 105 MBytes 882 Mbits/sec 140 129 KBytes
[ 4] 5.00-6.01 sec 106 MBytes 883 Mbits/sec 115 195 KBytes
[ 4] 6.01-7.00 sec 102 MBytes 863 Mbits/sec 133 70.7 KBytes
[ 4] 7.00-8.01 sec 106 MBytes 884 Mbits/sec 143 97.6 KBytes
[ 4] 8.01-9.01 sec 104 MBytes 875 Mbits/sec 124 107 KBytes
[ 4] 9.01-10.01 sec 105 MBytes 876 Mbits/sec 90 139 KBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bandwidth Retr
[ 4] 0.00-10.01 sec 1.02 GBytes 874 Mbits/sec 1189 sender
[ 4] 0.00-10.01 sec 1.02 GBytes 873 Mbits/sec receiver
iperf Done.
I get similar TX throughput on my Meson GXBB "MXQ Pro+" board when I
disable the PHY's TX-delay and configure a 4ms TX-delay on the MAC.
So changes to at least the RTL8211F PHY driver are needed to get it
working properly in all situations.
NOTE: patches 3-7 should be taken though the Amlogic tree. patches 1
and 2 can be taken through the net-tree or through the Amlogic tree.
There shouldn't be a runtime dependency as long as phy-mode "rgmii"
(or the not-relevant-for-this-case "rmii") is used (which is currently
the case for all ARM64 meson-gx boards) due to the dwmac-meson8b's
default 2ns TX-delay.
Changes since v1:
- renamed the devicetree property "amlogic,tx-delay" to
"amlogic,tx-delay-ns", which makes the .dts easier to read as we can
simply specify human-readable values instead of having "preprocessor
defines and calculation in human brain". Thanks to Andrew Lunn for
the suggestion!
- improved documentation to indicate when the MAC TX-delay should be
configured and how to use the PHY's TX-delay
- changed the default TX-delay in the dwmac-meson8b driver from 2ns
to 0ms when any of the rgmii-*id modes are used (the 2ns default
value still applies for phy-mode "rgmii")
- added patches to properly reset the PHY on Meson GXBB devices and to
use a similar configuration than the one we use on Meson GXL devices
(by passing a phy-handle to stmmac and defining the PHY in the mdio0
bus - patch 3-6)
- add the "amlogic,tx-delay-ns" property to all boards which are using
the RGMII PHY (patch 7)
Martin Blumenstingl (7):
net: dt-bindings: add RGMII TX delay configuration to meson8b-dwmac
net: stmmac: dwmac-meson8b: make the RGMII TX delay configurable
ARM64: dts: meson-gx: move the MDIO node to meson-gx
ARM64: dts: meson-gxbb-odroidc2: add reset for the ethernet PHY
ARM64: dts: meson-gxbb-p20x: add reset for the ethernet PHY
ARM64: dts: meson-gxbb-vega-s95: add reset for the ethernet PHY
ARM64: dts: amlogic: add the ethernet TX delay configuration
.../devicetree/bindings/net/meson-dwmac.txt | 14 ++++++++++++
arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 6 +++++
.../arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts | 17 ++++++++++++++
arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi | 17 ++++++++++++++
.../boot/dts/amlogic/meson-gxbb-vega-s95.dtsi | 17 ++++++++++++++
.../boot/dts/amlogic/meson-gxl-s905d-p230.dts | 2 ++
arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 6 -----
.../arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts | 2 ++
.../arm64/boot/dts/amlogic/meson-gxm-s912-q200.dts | 2 ++
.../net/ethernet/stmicro/stmmac/dwmac-meson8b.c | 26 +++++++++++++++++-----
10 files changed, 97 insertions(+), 12 deletions(-)
--
2.10.2
^ permalink raw reply
* Re: [PATCH 6/10] mmc: sdhci-xenon: Add Marvell Xenon SDHC core functionality
From: Ulf Hansson @ 2016-11-25 13:01 UTC (permalink / raw)
To: Ziji Hu
Cc: Adrian Hunter, Gregory CLEMENT,
linux-mmc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Jason Cooper,
Andrew Lunn, Sebastian Hesselbarth, Rob Herring,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Thomas Petazzoni,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
Jimmy Xu, Jisheng Zhang, Nadav Haklai, Ryan Gao, Doug Jones,
Victor Gu, Wei(SOCP) Liu, Wilson Ding
In-Reply-To: <76ce72f8-4b86-3b83-544f-b9a7ef871393-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
[...]
>>
>> Moreover, we have ->enable_sdio_irq() ops that deals with this.
>>
> Yes. I mean the SDIO irqs on DAT1 line in async mode.
> This field enables our host to recognize the async SDIO irq from SDIO device.
> It controls our host side behavior, other than the SDIO device.
>
> I think ->enable_sdio_irq() is a more reasonable place to put this workraound.
> I will export sdhci_enable_sdio_irq() and implement out host own
> enable_sdio_irq() calling sdhci_enable_sdio)irq() plus this workaround.
> Does it sound reasonable to you?
Yes.
[...]
>>
>> Got it. Although I think we can cope with that fine just by using the
>> different SD/eMMC speed modes settings defined in DT (or from the
>> SDHCI caps register)
>>
> In my very opinion, I'm not sure if there is any corner case that driver cannot
> determine the eMMC card type from DT and SDHC caps.
>
>>> Unfortunately, MMC driver cannot determine the card type yet when eMMC voltage
>>> setting should be executed.
>>> Thus an flag is required here to tell driver to execute eMMC voltage setting.
>>>
>>> Besides, additional eMMC specific settings might be implemented in future, besides
>>> voltage setting. Most of them should be completed before MMC driver recognizes the
>>> card type. Thus I have to keep this flag to indicate current SDHC is for eMMC.
>>
>> I doubt you will need a generic "eMMC" flag, but let's see when we go forward.
>>
>> Currently it's clear you don't need such a flag, so I will submit a
>> change adding a DT binding for "mmc-ddr-3_3v" then we can take it from
>> there, to see if it suits your needs.
>>
>
> Actually, our eMMC is usually fixed as 1.8V.
>
> The pair "no-sd" + "no-sdio" can provide the similar information.
> But I'm not sure if it is proper to use those two property in such a way.
Well, potentially those could be used like that.
The point of why we added them was to allow hosts that don't support
the different protocols (which is somewhat true for your case, because
of signal voltage issues) to tell the mmc core about it. That instead
of having to all kind of crazy hacks in the drives, that in then
didn't work out so well.
Kind regards
Uffe
--
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 6/8] ASoC: sun4i-codec: Add support for H3 codec
From: Maxime Ripard @ 2016-11-25 12:58 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: devicetree, alsa-devel, Liam Girdwood, linux-kernel, Mark Brown,
Mylene Josserand, Lee Jones, linux-arm-kernel
In-Reply-To: <20161125123442.28410-7-wens@csie.org>
[-- Attachment #1.1: Type: text/plain, Size: 753 bytes --]
On Fri, Nov 25, 2016 at 08:34:40PM +0800, Chen-Yu Tsai wrote:
> The codec on the H3 is similar to the one found on the A31. One key
> difference is the analog path controls are routed through the PRCM
> block. This is supported by the sun8i-codec-analog driver, and tied
> into this codec driver with the audio card's aux_dev.
>
> In addition, the H3 has no HP (headphone) and HBIAS support, and no
> MIC3 input. The FIFO related registers are slightly rearranged.
>
> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
> Acked-by: Rob Herring <robh@kernel.org>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Thanks,
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
[-- Attachment #2: Type: text/plain, Size: 176 bytes --]
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v2 2/8] ASoC: sun4i-codec: Add support for A23 codec
From: Maxime Ripard @ 2016-11-25 12:57 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Liam Girdwood, Mark Brown, Lee Jones,
alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Mylene Josserand
In-Reply-To: <20161125123442.28410-3-wens-jdAy2FN1RRM@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 805 bytes --]
On Fri, Nov 25, 2016 at 08:34:36PM +0800, Chen-Yu Tsai wrote:
> The codec in the A23 is similar to the one found on the A31. One key
> difference is the analog path controls are routed through the PRCM
> block. This is supported by the sun8i-codec-analog driver, and tied
> into this codec driver with the audio card's aux_dev.
>
> In addition, the A23 does not have LINEOUT, and it does not support
> headset jack detection or buttons.
>
> Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
> Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Acked-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: [PATCH v2 1/8] mfd: sun6i-prcm: Add codec analog controls sub-device for Allwinner A23
From: Maxime Ripard @ 2016-11-25 12:57 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Liam Girdwood, Mark Brown, Lee Jones,
alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Mylene Josserand
In-Reply-To: <20161125123442.28410-2-wens-jdAy2FN1RRM@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 512 bytes --]
On Fri, Nov 25, 2016 at 08:34:35PM +0800, Chen-Yu Tsai wrote:
> The PRCM block on the A23 contains a message box like interface to
> the registers for the analog path controls of the internal codec.
>
> Add a sub-device for it.
>
> Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
Acked-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: [PATCH] devicetree: bindings: Add vendor prefix for Oki
From: Simon Horman @ 2016-11-25 12:56 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Rob Herring, Mark Rutland, devicetree, linux-renesas-soc
In-Reply-To: <1480068945-29822-1-git-send-email-geert+renesas@glider.be>
On Fri, Nov 25, 2016 at 11:15:45AM +0100, Geert Uytterhoeven wrote:
> Already in use for "oki,ml86v7667".
>
> Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Reviewed-by: Simon Horman <horms+renesas@verge.net.au>
^ permalink raw reply
* Re: [RFC PATCH] ARM: dts: Add support for Turris Omnia
From: Tomas Hlavacek @ 2016-11-25 12:49 UTC (permalink / raw)
To: Andrew Lunn
Cc: Mark Rutland, devicetree, Jason Cooper, Uwe Kleine-König,
Russell King, linux-kernel, Rob Herring, Gregory Clement,
linux-arm-kernel, Sebastian Hesselbarth
In-Reply-To: <20161124150700.GD7155@lunn.ch>
Hi!
On Thu, Nov 24, 2016 at 4:07 PM, Andrew Lunn <andrew@lunn.ch> wrote:
>> @Tomas: I think it doesn't make sense when we alternate sending
>> patches
>> without prior arrangement. Do you already work on a v5? If not I
>> can do
>> that to fix the last few comments. Not sure when a submission is too
>> late to enter v4.10, but I think the window isn't that big any more.
>
> It is getting a bit late. But maybe Linus will add in another -rc
> week.
>
>>
>> > No leds? No buttons via gpio-keys?
>>
>> The leds are controlled by a Cortex-M0 and without intervention
>> blink
>> according to a hardware function (network, power, pci). IMHO that's
>> ok
>> for an initial setup.
>
> Yes. That is fine. It is just unusual. Most boards have gpio-led and
> gpio-keys, which are easy to add. That is why i asked. Adding an LED
> driver which talks to this M0 can be added later.
Actually the WiP driver for MCU LED interface, that we use in our
kernel is here:
https://github.com/tmshlvck/omnia-linux/commit/2121afd8fbd2e4c720edcdd472b11b5303bc0dfb
It definitely needs some cleanup and it adds non-standard features
(main PWM for all LEDs, autonomous blink mode, colors) via custom /sys
files, which I suspect that is not going to be acceptable for upstream.
Let's keep it for the next iteration.
Regarding the button, we actually have one, that is connected to the
MCU and by default it sets LED brigtness autonomously, but it should be
able to generate IRQs via the MCU if we change the mode in the MCU.
I'll look into that.
Tomas
^ permalink raw reply
* Re: [PATCH v9 3/4] dtc: Plugin and fixup support
From: Pantelis Antoniou @ 2016-11-25 12:44 UTC (permalink / raw)
To: David Gibson
Cc: Jon Loeliger, Grant Likely, Frank Rowand, Rob Herring, Jan Luebbe,
Sascha Hauer, Phil Elwell, Simon Glass, Maxime Ripard,
Thomas Petazzoni, Boris Brezillon, Antoine Tenart, Stephen Boyd,
Devicetree Compiler, devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20161125112613.GK12287-K0bRW+63XPQe6aEkudXLsA@public.gmane.org>
Hi David,
> On Nov 25, 2016, at 13:26 , David Gibson <david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org> wrote:
>
> On Fri, Nov 25, 2016 at 12:55:25PM +0200, Pantelis Antoniou wrote:
>> Hi David,
>>
>>> On Nov 25, 2016, at 06:11 , David Gibson <david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org> wrote:
>>>
>>> On Thu, Nov 24, 2016 at 02:31:32PM +0200, Pantelis Antoniou wrote:
>>>> This patch enable the generation of symbols & local fixup information
>>>> for trees compiled with the -@ (--symbols) option.
>>>>
>>>> Using this patch labels in the tree and their users emit information
>>>> in __symbols__ and __local_fixups__ nodes.
>>>>
>>>> The __fixups__ node make possible the dynamic resolution of phandle
>>>> references which are present in the plugin tree but lie in the
>>>> tree that are applying the overlay against.
>>>>
>>>> While there is a new magic number for dynamic device tree/overlays blobs
>>>> it is by default disabled. This is in order to give time for DT blob
>>>> methods to be updated.
>>>>
>>>> Signed-off-by: Pantelis Antoniou <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
>>>> Signed-off-by: Sascha Hauer <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
>>>> Signed-off-by: Jan Luebbe <jlu-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
>>>> ---
>>>> Documentation/manual.txt | 25 +++++-
>>>> checks.c | 8 +-
>>>> dtc-lexer.l | 5 ++
>>>> dtc-parser.y | 49 +++++++++--
>>>> dtc.c | 39 +++++++-
>>>> dtc.h | 20 ++++-
>>>> fdtdump.c | 2 +-
>>>> flattree.c | 17 ++--
>>>> fstree.c | 2 +-
>>>> libfdt/fdt.c | 2 +-
>>>> libfdt/fdt.h | 3 +-
>>>> livetree.c | 225 ++++++++++++++++++++++++++++++++++++++++++++++-
>>>> tests/mangle-layout.c | 7 +-
>>>> treesource.c | 7 +-
>>>> 14 files changed, 380 insertions(+), 31 deletions(-)
>>>>
>>>> diff --git a/Documentation/manual.txt b/Documentation/manual.txt
>>>> index 398de32..65fbf09 100644
>>>> --- a/Documentation/manual.txt
>>>> +++ b/Documentation/manual.txt
>>>> @@ -119,6 +119,24 @@ Options:
>>>> Make space for <number> reserve map entries
>>>> Relevant for dtb and asm output only.
>>>>
>>>> + -@
>>>> + Generates a __symbols__ node at the root node of the resulting blob
>>>> + for any node labels used, and for any local references using phandles
>>>> + it also generates a __local_fixups__ node that tracks them.
>>>> +
>>>> + When using the /plugin/ tag all unresolved label references to
>>>> + be tracked in the __fixups__ node, making dynamic resolution possible.
>>>> +
>>>> + -A
>>>> + Generate automatically aliases for all node labels. This is similar to
>>>> + the -@ option (the __symbols__ node contain identical information) but
>>>> + the semantics are slightly different since no phandles are automatically
>>>> + generated for labeled nodes.
>>>> +
>>>> + -M
>>>> + Generate blobs with the new FDT magic number. By default blobs with the
>>>> + standard FDT magic number are generated.
>>>
>>> First, this description is incomplete since -M *only* affects the
>>> magic number for /plugin/ input, not in other cases. Second, the
>>> default is the wrong way around. If we make old-style the default,
>>> then new-style will never be used, which defeats the purpose.
>>
>> Then we’ll break user-space that has this assumption (i.e. that the magic is the same).
>> I can certainly do it the other way around.
>
> Which userspace in particular?
>
Kernel unflatteners in various OSes/bootloaders? All those would have to be updated since
they don’t grok the new magic number.
>>>> +
>>>> -S <bytes>
>>>> Ensure the blob at least <bytes> long, adding additional
>>>> space if needed.
>>>> @@ -146,13 +164,18 @@ Additionally, dtc performs various sanity checks on the tree.
>>>> Here is a very rough overview of the layout of a DTS source file:
>>>>
>>>>
>>>> - sourcefile: list_of_memreserve devicetree
>>>> + sourcefile: versioninfo plugindecl list_of_memreserve devicetree
>>>>
>>>> memreserve: label 'memreserve' ADDR ADDR ';'
>>>> | label 'memreserve' ADDR '-' ADDR ';'
>>>>
>>>> devicetree: '/' nodedef
>>>>
>>>> + versioninfo: '/' 'dts-v1' '/' ';'
>>>> +
>>>> + plugindecl: '/' 'plugin' '/' ';'
>>>> + | /* empty */
>>>> +
>>>> nodedef: '{' list_of_property list_of_subnode '}' ';'
>>>>
>>>> property: label PROPNAME '=' propdata ';'
>>>> diff --git a/checks.c b/checks.c
>>>> index 609975a..bc03d42 100644
>>>> --- a/checks.c
>>>> +++ b/checks.c
>>>> @@ -486,8 +486,12 @@ static void fixup_phandle_references(struct check *c, struct boot_info *bi,
>>>>
>>>> refnode = get_node_by_ref(dt, m->ref);
>>>> if (! refnode) {
>>>> - FAIL(c, "Reference to non-existent node or label \"%s\"\n",
>>>> - m->ref);
>>>> + if (!(bi->versionflags & VF_PLUGIN))
>>>> + FAIL(c, "Reference to non-existent node or "
>>>> + "label \"%s\"\n", m->ref);
>>>> + else /* mark the entry as unresolved */
>>>> + *((cell_t *)(prop->val.val + m->offset)) =
>>>> + cpu_to_fdt32(0xffffffff);
>>>> continue;
>>>> }
>>>>
>>>> diff --git a/dtc-lexer.l b/dtc-lexer.l
>>>> index 790fbf6..40bbc87 100644
>>>> --- a/dtc-lexer.l
>>>> +++ b/dtc-lexer.l
>>>> @@ -121,6 +121,11 @@ static void lexical_error(const char *fmt, ...);
>>>> return DT_V1;
>>>> }
>>>>
>>>> +<*>"/plugin/" {
>>>> + DPRINT("Keyword: /plugin/\n");
>>>> + return DT_PLUGIN;
>>>> + }
>>>> +
>>>> <*>"/memreserve/" {
>>>> DPRINT("Keyword: /memreserve/\n");
>>>> BEGIN_DEFAULT();
>>>> diff --git a/dtc-parser.y b/dtc-parser.y
>>>> index 14aaf2e..4afc592 100644
>>>> --- a/dtc-parser.y
>>>> +++ b/dtc-parser.y
>>>> @@ -19,6 +19,7 @@
>>>> */
>>>> %{
>>>> #include <stdio.h>
>>>> +#include <inttypes.h>
>>>>
>>>> #include "dtc.h"
>>>> #include "srcpos.h"
>>>> @@ -33,6 +34,9 @@ extern void yyerror(char const *s);
>>>>
>>>> extern struct boot_info *the_boot_info;
>>>> extern bool treesource_error;
>>>> +
>>>> +/* temporary while the tree is not built */
>>>> +static unsigned int the_versionflags;
>>>
>>> Hrm. Using a global during parsing is pretty dangerous - it makes
>>> assumptions about the order in which bison will execute semantic
>>> actions that may not always be correct.
>>>
>>> It'll probably work in practice, so I *might* be convinced it's
>>> adequate for a first cut. I'm a bit reluctant though, since I suspect
>>> once merged it will become entrenched.
>>>
>>
>> We use bison, globals are the way of life. It’s not going to be used
>> anywhere else, it’s static in the parser file.
>
> Using globals to communicate the final result is inevitable (well, not
> without using the whole different re-entrant interface stuff). That
> just assumes that the start symbol's semantic action is executed
> before the parser competes, which is guaranteed.
>
> This is a different matter - using a global to communicate between
> different parts of the parser. More specifically different parts of
> the parser that are in different arms of the parse tree. That makes
> assumptions about the relative order of semantic actions which are
> *not* guaranteed. In theory the parser could generate the entire
> parse tree and semantic action dependency graph, then execute them in
> an arbitrary order (well, it would have to be a topologically sorted
> order, but that won't help).
>
I’ve given it a little bit more thought and it’s easily fixed by using
inherited attributes which is safe to do and avoid the global all together.
>> We could allocate the boot_info earlier (when the v1tag is detected) but
>> that would be quite a big change for something as trivial.
>
> That wouldn't help. You still wouldn't have a guarantee on the order
> between setting the version flags and using the version flags.
>
>>> The correct way to handle this, IMO, is not to ever attempt to apply
>>> overlays during the parse. Basically, we'd change the overall
>>> structure so that the output from the parser is not a single tree, but
>>> a list of overlays / fragments. Then, once the parse is complete, so
>>> versioninfo (which could now become a member of bootinfo) is well
>>> defined, we either apply the fragments in place (base tree) or encode
>>> them into the overlay structure (plugin mode).
>>>
>>> See https://github.com/dgibson/dtc/tree/overlay for some incomplete
>>> work I did in this direction.
>>>
>>
>> This tree is pretty stale; last commit was back in march.
>
> Yes, it was a while since I worked on it. It rebased clean, though.
>
>> I thing there’s a wrong assumption here. The purpose of this patch is not
>> to apply overlays during compile time, is to generate a blob that can be
>> applied at runtime by another piece of software.
>
> No, I realise what you're doing. But the input is in the form of a
> batch of overlays, regardless. You then have two modes of operation:
> for base trees you resolve those overlays during the compile, for
> plugins you assemble those overlays into a blob which can be applied
> later.
>
> Because it wasn't designed with runtime overlays in mind, the current
> code handles the resolution of those overlays during the parse. Your
> patch extends that by rather than resolving them, just putting them
> together with metadata into the dtbo.
>
> I'm saying that resolution or assembly should be moved out of the
> parser. Instead, the parser output would be an (ordered) list of
> overlay fragments. In the main program the two modes of operation
> become explicit: for base trees we resolve the overlays into a single
> tree, for plugins we collate the pieces into the dtbo format.
>
The case for building an overlay is only for the syntactic sugar version.
This is not the common use case at all. I could easily remove it and then
there would be no overlays built at all in the parser.
In fact the extra fixup nodes are generated now after the parse stage,
after the check stage and before the sort stage.
Perhaps it should be separated out so that we don’t get sidetracked?
>>> In addition to not making unsafe assumptions about parser operation, I
>>> think this will also allow for better error reporting. It also moves
>>> more code into plain-old-C instead of potentially hard to follow bison
>>> code fragments.
>>>
>>
>> We don’t try to apply overlays during parse, and especially in the parse code.
>
> The existing code does this, and you don't change it. Furthermore you
> absolutely do do the assembly of the fragments within the parser -
> that's exactly what add_orphan_node() called directly from semantic
> actions does. To verify this, all you need to do is look at the
> parser output: the boot_info structure has just a single tree, not a
> list of overlays.
>
Only for the un-common case.
>> The global is used only for the syntactic sugar method of turning a &ref { };
>> node into an overlay.
>
> I'm saying that treating that as mere syntactic sugar is a fundamental
> error in design. We could get away with it when the &ref {} stuff was
> always resolved immediately. Now that that resolution can be delayed
> until later, it gets worse. We should move that resolution outside of
> the parser.
>
The &ref { } stuff is sidetracking us. This is not the core issue.
In fact out in the community there are not a lot of cases where it is used.
>>
>>>> %}
>>>>
>>>> %union {
>>>> @@ -52,9 +56,11 @@ extern bool treesource_error;
>>>> struct node *nodelist;
>>>> struct reserve_info *re;
>>>> uint64_t integer;
>>>> + unsigned int flags;
>>>> }
>>>>
>>>> %token DT_V1
>>>> +%token DT_PLUGIN
>>>> %token DT_MEMRESERVE
>>>> %token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
>>>> %token DT_BITS
>>>> @@ -71,6 +77,8 @@ extern bool treesource_error;
>>>>
>>>> %type <data> propdata
>>>> %type <data> propdataprefix
>>>> +%type <flags> versioninfo
>>>> +%type <flags> plugindecl
>>>> %type <re> memreserve
>>>> %type <re> memreserves
>>>> %type <array> arrayprefix
>>>> @@ -101,16 +109,36 @@ extern bool treesource_error;
>>>> %%
>>>>
>>>> sourcefile:
>>>> - v1tag memreserves devicetree
>>>> + versioninfo plugindecl memreserves devicetree
>>>> + {
>>>> + the_boot_info = build_boot_info($1 | $2, $3, $4,
>>>> + guess_boot_cpuid($4));
>>>> + }
>>>> + ;
>>>> +
>>>> +versioninfo:
>>>> + v1tag
>>>> {
>>>> - the_boot_info = build_boot_info($2, $3,
>>>> - guess_boot_cpuid($3));
>>>> + the_versionflags |= VF_DT_V1;
>>>> + $$ = the_versionflags;
>>>> }
>>>> ;
>>>>
>>>> v1tag:
>>>> DT_V1 ';'
>>>> + | DT_V1
>>>> | DT_V1 ';' v1tag
>>>> +
>>>> +plugindecl:
>>>> + DT_PLUGIN ';'
>>>> + {
>>>> + the_versionflags |= VF_PLUGIN;
>>>> + $$ = VF_PLUGIN;
>>>> + }
>>>> + | /* empty */
>>>> + {
>>>> + $$ = 0;
>>>> + }
>>>> ;
>>>>
>>>> memreserves:
>>>> @@ -161,10 +189,14 @@ devicetree:
>>>> {
>>>> struct node *target = get_node_by_ref($1, $2);
>>>>
>>>> - if (target)
>>>> + if (target) {
>>>> merge_nodes(target, $3);
>>>> - else
>>>> - ERROR(&@2, "Label or path %s not found", $2);
>>>> + } else {
>>>> + if (the_versionflags & VF_PLUGIN)
>>>> + add_orphan_node($1, $3, $2);
>>>> + else
>>>> + ERROR(&@2, "Label or path %s not found", $2);
>>>> + }
>>>> $$ = $1;
>>>> }
>>>> | devicetree DT_DEL_NODE DT_REF ';'
>>>> @@ -179,6 +211,11 @@ devicetree:
>>>>
>>>> $$ = $1;
>>>> }
>>>> + | /* empty */
>>>> + {
>>>> + /* build empty node */
>>>> + $$ = name_node(build_node(NULL, NULL), "");
>>>> + }
>>>> ;
>>>>
>>>> nodedef:
>>>> diff --git a/dtc.c b/dtc.c
>>>> index 9dcf640..a654267 100644
>>>> --- a/dtc.c
>>>> +++ b/dtc.c
>>>> @@ -32,6 +32,9 @@ int minsize; /* Minimum blob size */
>>>> int padsize; /* Additional padding to blob */
>>>> int alignsize; /* Additional padding to blob accroding to the alignsize */
>>>> int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */
>>>> +int symbol_fixup_support; /* enable symbols & fixup support */
>>>> +int auto_label_aliases; /* auto generate labels -> aliases */
>>>> +int new_magic; /* use new FDT magic values for objects */
>>>>
>>>> static int is_power_of_2(int x)
>>>> {
>>>> @@ -59,7 +62,7 @@ static void fill_fullpaths(struct node *tree, const char *prefix)
>>>> #define FDT_VERSION(version) _FDT_VERSION(version)
>>>> #define _FDT_VERSION(version) #version
>>>> static const char usage_synopsis[] = "dtc [options] <input file>";
>>>> -static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:hv";
>>>> +static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@AMhv";
>>>> static struct option const usage_long_opts[] = {
>>>> {"quiet", no_argument, NULL, 'q'},
>>>> {"in-format", a_argument, NULL, 'I'},
>>>> @@ -78,6 +81,9 @@ static struct option const usage_long_opts[] = {
>>>> {"phandle", a_argument, NULL, 'H'},
>>>> {"warning", a_argument, NULL, 'W'},
>>>> {"error", a_argument, NULL, 'E'},
>>>> + {"symbols", no_argument, NULL, '@'},
>>>> + {"auto-alias", no_argument, NULL, 'A'},
>>>> + {"new-magic", no_argument, NULL, 'M'},
>>>> {"help", no_argument, NULL, 'h'},
>>>> {"version", no_argument, NULL, 'v'},
>>>> {NULL, no_argument, NULL, 0x0},
>>>> @@ -109,6 +115,9 @@ static const char * const usage_opts_help[] = {
>>>> "\t\tboth - Both \"linux,phandle\" and \"phandle\" properties",
>>>> "\n\tEnable/disable warnings (prefix with \"no-\")",
>>>> "\n\tEnable/disable errors (prefix with \"no-\")",
>>>> + "\n\tEnable symbols/fixup support",
>>>> + "\n\tEnable auto-alias of labels",
>>>> + "\n\tUse new blog magic value",
>>>> "\n\tPrint this help and exit",
>>>> "\n\tPrint version and exit",
>>>> NULL,
>>>> @@ -153,7 +162,7 @@ static const char *guess_input_format(const char *fname, const char *fallback)
>>>> fclose(f);
>>>>
>>>> magic = fdt32_to_cpu(magic);
>>>> - if (magic == FDT_MAGIC)
>>>> + if (magic == FDT_MAGIC || magic == FDT_MAGIC_DTBO)
>>>> return "dtb";
>>>>
>>>> return guess_type_by_name(fname, fallback);
>>>> @@ -172,6 +181,7 @@ int main(int argc, char *argv[])
>>>> FILE *outf = NULL;
>>>> int outversion = DEFAULT_FDT_VERSION;
>>>> long long cmdline_boot_cpuid = -1;
>>>> + fdt32_t out_magic = FDT_MAGIC;
>>>>
>>>> quiet = 0;
>>>> reservenum = 0;
>>>> @@ -249,6 +259,16 @@ int main(int argc, char *argv[])
>>>> parse_checks_option(false, true, optarg);
>>>> break;
>>>>
>>>> + case '@':
>>>> + symbol_fixup_support = 1;
>>>> + break;
>>>> + case 'A':
>>>> + auto_label_aliases = 1;
>>>> + break;
>>>> + case 'M':
>>>> + new_magic = 1;
>>>> + break;
>>>> +
>>>> case 'h':
>>>> usage(NULL);
>>>> default:
>>>> @@ -306,6 +326,14 @@ int main(int argc, char *argv[])
>>>> fill_fullpaths(bi->dt, "");
>>>> process_checks(force, bi);
>>>>
>>>> + if (auto_label_aliases)
>>>> + generate_label_tree(bi->dt, "aliases", false);
>>>> +
>>>> + if (symbol_fixup_support) {
>>>> + generate_label_tree(bi->dt, "__symbols__", true);
>>>> + generate_fixups_tree(bi->dt);
>>>> + }
>>>> +
>>>> if (sort)
>>>> sort_tree(bi);
>>>>
>>>> @@ -318,12 +346,15 @@ int main(int argc, char *argv[])
>>>> outname, strerror(errno));
>>>> }
>>>>
>>>> + if (new_magic && (bi->versionflags & VF_PLUGIN))
>>>> + out_magic = FDT_MAGIC_DTBO;
>>>> +
>>>> if (streq(outform, "dts")) {
>>>> dt_to_source(outf, bi);
>>>> } else if (streq(outform, "dtb")) {
>>>> - dt_to_blob(outf, bi, outversion);
>>>> + dt_to_blob(outf, bi, out_magic, outversion);
>>>> } else if (streq(outform, "asm")) {
>>>> - dt_to_asm(outf, bi, outversion);
>>>> + dt_to_asm(outf, bi, out_magic, outversion);
>>>> } else if (streq(outform, "null")) {
>>>> /* do nothing */
>>>> } else {
>>>> diff --git a/dtc.h b/dtc.h
>>>> index 32009bc..889b8f8 100644
>>>> --- a/dtc.h
>>>> +++ b/dtc.h
>>>> @@ -55,6 +55,9 @@ extern int minsize; /* Minimum blob size */
>>>> extern int padsize; /* Additional padding to blob */
>>>> extern int alignsize; /* Additional padding to blob accroding to the alignsize */
>>>> extern int phandle_format; /* Use linux,phandle or phandle properties */
>>>> +extern int symbol_fixup_support;/* enable symbols & fixup support */
>>>> +extern int auto_label_aliases; /* auto generate labels -> aliases */
>>>> +extern int new_magic; /* use new FDT magic values for objects */
>>>>
>>>> #define PHANDLE_LEGACY 0x1
>>>> #define PHANDLE_EPAPR 0x2
>>>> @@ -195,6 +198,7 @@ struct node *build_node_delete(void);
>>>> struct node *name_node(struct node *node, char *name);
>>>> struct node *chain_node(struct node *first, struct node *list);
>>>> struct node *merge_nodes(struct node *old_node, struct node *new_node);
>>>> +void add_orphan_node(struct node *old_node, struct node *new_node, char *ref);
>>>>
>>>> void add_property(struct node *node, struct property *prop);
>>>> void delete_property_by_name(struct node *node, char *name);
>>>> @@ -202,6 +206,8 @@ void delete_property(struct property *prop);
>>>> void add_child(struct node *parent, struct node *child);
>>>> void delete_node_by_name(struct node *parent, char *name);
>>>> void delete_node(struct node *node);
>>>> +void append_to_property(struct node *node,
>>>> + char *name, const void *data, int len);
>>>>
>>>> const char *get_unitname(struct node *node);
>>>> struct property *get_property(struct node *node, const char *propname);
>>>> @@ -237,14 +243,22 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
>>>>
>>>>
>>>> struct boot_info {
>>>> + unsigned int versionflags;
>>>> struct reserve_info *reservelist;
>>>> struct node *dt; /* the device tree */
>>>> uint32_t boot_cpuid_phys;
>>>> };
>>>>
>>>> -struct boot_info *build_boot_info(struct reserve_info *reservelist,
>>>> +/* version flags definitions */
>>>> +#define VF_DT_V1 0x0001 /* /dts-v1/ */
>>>> +#define VF_PLUGIN 0x0002 /* /plugin/ */
>>>> +
>>>> +struct boot_info *build_boot_info(unsigned int versionflags,
>>>> + struct reserve_info *reservelist,
>>>> struct node *tree, uint32_t boot_cpuid_phys);
>>>> void sort_tree(struct boot_info *bi);
>>>> +void generate_label_tree(struct node *dt, char *gen_node_name, bool allocph);
>>>> +void generate_fixups_tree(struct node *dt);
>>>>
>>>> /* Checks */
>>>>
>>>> @@ -253,8 +267,8 @@ void process_checks(bool force, struct boot_info *bi);
>>>>
>>>> /* Flattened trees */
>>>>
>>>> -void dt_to_blob(FILE *f, struct boot_info *bi, int version);
>>>> -void dt_to_asm(FILE *f, struct boot_info *bi, int version);
>>>> +void dt_to_blob(FILE *f, struct boot_info *bi, fdt32_t magic, int version);
>>>> +void dt_to_asm(FILE *f, struct boot_info *bi, fdt32_t magic, int version);
>>>>
>>>> struct boot_info *dt_from_blob(const char *fname);
>>>>
>>>> diff --git a/fdtdump.c b/fdtdump.c
>>>> index a9a2484..dd63ac2 100644
>>>> --- a/fdtdump.c
>>>> +++ b/fdtdump.c
>>>> @@ -201,7 +201,7 @@ int main(int argc, char *argv[])
>>>> p = memchr(p, smagic[0], endp - p - FDT_MAGIC_SIZE);
>>>> if (!p)
>>>> break;
>>>> - if (fdt_magic(p) == FDT_MAGIC) {
>>>> + if (fdt_magic(p) == FDT_MAGIC || fdt_magic(p) == FDT_MAGIC_DTBO) {
>>>> /* try and validate the main struct */
>>>> off_t this_len = endp - p;
>>>> fdt32_t max_version = 17;
>>>> diff --git a/flattree.c b/flattree.c
>>>> index a9d9520..57d76cf 100644
>>>> --- a/flattree.c
>>>> +++ b/flattree.c
>>>> @@ -335,6 +335,7 @@ static struct data flatten_reserve_list(struct reserve_info *reservelist,
>>>> }
>>>>
>>>> static void make_fdt_header(struct fdt_header *fdt,
>>>> + fdt32_t magic,
>>>> struct version_info *vi,
>>>> int reservesize, int dtsize, int strsize,
>>>> int boot_cpuid_phys)
>>>> @@ -345,7 +346,7 @@ static void make_fdt_header(struct fdt_header *fdt,
>>>>
>>>> memset(fdt, 0xff, sizeof(*fdt));
>>>>
>>>> - fdt->magic = cpu_to_fdt32(FDT_MAGIC);
>>>> + fdt->magic = cpu_to_fdt32(magic);
>>>> fdt->version = cpu_to_fdt32(vi->version);
>>>> fdt->last_comp_version = cpu_to_fdt32(vi->last_comp_version);
>>>>
>>>> @@ -366,7 +367,7 @@ static void make_fdt_header(struct fdt_header *fdt,
>>>> fdt->size_dt_struct = cpu_to_fdt32(dtsize);
>>>> }
>>>>
>>>> -void dt_to_blob(FILE *f, struct boot_info *bi, int version)
>>>> +void dt_to_blob(FILE *f, struct boot_info *bi, fdt32_t magic, int version)
>>>> {
>>>> struct version_info *vi = NULL;
>>>> int i;
>>>> @@ -390,7 +391,7 @@ void dt_to_blob(FILE *f, struct boot_info *bi, int version)
>>>> reservebuf = flatten_reserve_list(bi->reservelist, vi);
>>>>
>>>> /* Make header */
>>>> - make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len,
>>>> + make_fdt_header(&fdt, magic, vi, reservebuf.len, dtbuf.len, strbuf.len,
>>>> bi->boot_cpuid_phys);
>>>>
>>>> /*
>>>> @@ -467,7 +468,7 @@ static void dump_stringtable_asm(FILE *f, struct data strbuf)
>>>> }
>>>> }
>>>>
>>>> -void dt_to_asm(FILE *f, struct boot_info *bi, int version)
>>>> +void dt_to_asm(FILE *f, struct boot_info *bi, fdt32_t magic, int version)
>>>> {
>>>> struct version_info *vi = NULL;
>>>> int i;
>>>> @@ -830,6 +831,7 @@ struct boot_info *dt_from_blob(const char *fname)
>>>> struct node *tree;
>>>> uint32_t val;
>>>> int flags = 0;
>>>> + unsigned int versionflags = VF_DT_V1;
>>>>
>>>> f = srcfile_relative_open(fname, NULL);
>>>>
>>>> @@ -845,9 +847,12 @@ struct boot_info *dt_from_blob(const char *fname)
>>>> }
>>>>
>>>> magic = fdt32_to_cpu(magic);
>>>> - if (magic != FDT_MAGIC)
>>>> + if (magic != FDT_MAGIC && magic != FDT_MAGIC_DTBO)
>>>> die("Blob has incorrect magic number\n");
>>>>
>>>> + if (magic == FDT_MAGIC_DTBO)
>>>> + versionflags |= VF_PLUGIN;
>>>> +
>>>> rc = fread(&totalsize, sizeof(totalsize), 1, f);
>>>> if (ferror(f))
>>>> die("Error reading DT blob size: %s\n", strerror(errno));
>>>> @@ -942,5 +947,5 @@ struct boot_info *dt_from_blob(const char *fname)
>>>>
>>>> fclose(f);
>>>>
>>>> - return build_boot_info(reservelist, tree, boot_cpuid_phys);
>>>> + return build_boot_info(versionflags, reservelist, tree, boot_cpuid_phys);
>>>> }
>>>> diff --git a/fstree.c b/fstree.c
>>>> index 6d1beec..54f520b 100644
>>>> --- a/fstree.c
>>>> +++ b/fstree.c
>>>> @@ -86,6 +86,6 @@ struct boot_info *dt_from_fs(const char *dirname)
>>>> tree = read_fstree(dirname);
>>>> tree = name_node(tree, "");
>>>>
>>>> - return build_boot_info(NULL, tree, guess_boot_cpuid(tree));
>>>> + return build_boot_info(VF_DT_V1, NULL, tree, guess_boot_cpuid(tree));
>>>> }
>>>>
>>>> diff --git a/libfdt/fdt.c b/libfdt/fdt.c
>>>> index 22286a1..28d422c 100644
>>>> --- a/libfdt/fdt.c
>>>> +++ b/libfdt/fdt.c
>>>> @@ -57,7 +57,7 @@
>>>>
>>>> int fdt_check_header(const void *fdt)
>>>> {
>>>> - if (fdt_magic(fdt) == FDT_MAGIC) {
>>>> + if (fdt_magic(fdt) == FDT_MAGIC || fdt_magic(fdt) == FDT_MAGIC_DTBO) {
>>>> /* Complete tree */
>>>> if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
>>>> return -FDT_ERR_BADVERSION;
>>>> diff --git a/libfdt/fdt.h b/libfdt/fdt.h
>>>> index 526aedb..493cd55 100644
>>>> --- a/libfdt/fdt.h
>>>> +++ b/libfdt/fdt.h
>>>> @@ -55,7 +55,7 @@
>>>> #ifndef __ASSEMBLY__
>>>>
>>>> struct fdt_header {
>>>> - fdt32_t magic; /* magic word FDT_MAGIC */
>>>> + fdt32_t magic; /* magic word FDT_MAGIC[|_DTBO] */
>>>> fdt32_t totalsize; /* total size of DT block */
>>>> fdt32_t off_dt_struct; /* offset to structure */
>>>> fdt32_t off_dt_strings; /* offset to strings */
>>>> @@ -93,6 +93,7 @@ struct fdt_property {
>>>> #endif /* !__ASSEMBLY */
>>>>
>>>> #define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */
>>>> +#define FDT_MAGIC_DTBO 0xd00dfdb0 /* DTBO magic */
>>>> #define FDT_TAGSIZE sizeof(fdt32_t)
>>>>
>>>> #define FDT_BEGIN_NODE 0x1 /* Start node: full name */
>>>> diff --git a/livetree.c b/livetree.c
>>>> index 3dc7559..1a2f4b1 100644
>>>> --- a/livetree.c
>>>> +++ b/livetree.c
>>>> @@ -216,6 +216,31 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
>>>> return old_node;
>>>> }
>>>>
>>>> +void add_orphan_node(struct node *dt, struct node *new_node, char *ref)
>>>> +{
>>>> + static unsigned int next_orphan_fragment = 0;
>>>> + struct node *node = xmalloc(sizeof(*node));
>>>
>>> You shouldn't use a bare malloc() for a node. Use build_node() instead.
>>>
>>
>> OK.
>>
>>>> + struct property *p;
>>>> + struct data d = empty_data;
>>>> + char *name;
>>>> +
>>>> + memset(node, 0, sizeof(*node));
>>>> +
>>>> + d = data_add_marker(d, REF_PHANDLE, ref);
>>>> + d = data_append_integer(d, 0xffffffff, 32);
>>>> +
>>>> + p = build_property("target", d);
>>>> + add_property(node, p);
>>>> +
>>>> + xasprintf(&name, "fragment@%u",
>>>> + next_orphan_fragment++);
>>>> + name_node(node, name);
>>>> + name_node(new_node, "__overlay__");
>>>> +
>>>> + add_child(dt, node);
>>>> + add_child(node, new_node);
>>>> +}
>>>> +
>>>> struct node *chain_node(struct node *first, struct node *list)
>>>> {
>>>> assert(first->next_sibling == NULL);
>>>> @@ -296,6 +321,23 @@ void delete_node(struct node *node)
>>>> delete_labels(&node->labels);
>>>> }
>>>>
>>>> +void append_to_property(struct node *node,
>>>> + char *name, const void *data, int len)
>>>> +{
>>>> + struct data d;
>>>> + struct property *p;
>>>> +
>>>> + p = get_property(node, name);
>>>> + if (p) {
>>>> + d = data_append_data(p->val, data, len);
>>>> + p->val = d;
>>>> + } else {
>>>> + d = data_append_data(empty_data, data, len);
>>>> + p = build_property(name, d);
>>>> + add_property(node, p);
>>>> + }
>>>> +}
>>>> +
>>>> struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size)
>>>> {
>>>> struct reserve_info *new = xmalloc(sizeof(*new));
>>>> @@ -335,12 +377,14 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
>>>> return list;
>>>> }
>>>>
>>>> -struct boot_info *build_boot_info(struct reserve_info *reservelist,
>>>> +struct boot_info *build_boot_info(unsigned int versionflags,
>>>> + struct reserve_info *reservelist,
>>>> struct node *tree, uint32_t boot_cpuid_phys)
>>>> {
>>>> struct boot_info *bi;
>>>>
>>>> bi = xmalloc(sizeof(*bi));
>>>> + bi->versionflags = versionflags;
>>>> bi->reservelist = reservelist;
>>>> bi->dt = tree;
>>>> bi->boot_cpuid_phys = boot_cpuid_phys;
>>>> @@ -709,3 +753,182 @@ void sort_tree(struct boot_info *bi)
>>>> sort_reserve_entries(bi);
>>>> sort_node(bi->dt);
>>>> }
>>>> +
>>>> +/* utility helper to avoid code duplication */
>>>> +static struct node *build_and_name_child_node(struct node *parent, char *name)
>>>> +{
>>>> + struct node *node;
>>>> +
>>>> + node = build_node(NULL, NULL);
>>>> + name_node(node, xstrdup(name));
>>>> + add_child(parent, node);
>>>> +
>>>> + return node;
>>>> +}
>>>> +
>>>> +static void generate_label_tree_internal(struct node *dt, struct node *node,
>>>> + struct node *an, bool allocph)
>>>> +{
>>>> + struct node *c;
>>>> + struct property *p;
>>>> + struct label *l;
>>>> +
>>>> + /* if if there are labels */
>>>> + if (node->labels) {
>>>> + /* now add the label in the node */
>>>> + for_each_label(node->labels, l) {
>>>> + /* check whether the label already exists */
>>>> + p = get_property(an, l->label);
>>>> + if (p) {
>>>> + fprintf(stderr, "WARNING: label %s already"
>>>> + " exists in /%s", l->label,
>>>> + an->name);
>>>> + continue;
>>>> + }
>>>> +
>>>> + /* insert it */
>>>> + p = build_property(l->label,
>>>> + data_copy_escape_string(node->fullpath,
>>>> + strlen(node->fullpath)));
>>>
>>> Um.. what? The node path should absolutely not be an escape string.
>>> It shouldn't contain escapes to begin with, and if it does, we
>>> absolutely shouldn't be turning them into special characters here.
>>>
>>
>> OK, trivial enough to do. I tried to play it safe here but this is an overkill.
>
> It's not overkill, it's Just Plain Wrong. Resolving escapes is not
> idempotent. If you somehow had a node path with a backslash in it -
> well, that would be bad to begin with - but trying to resolve that
> backslash as an escape would be unambiguously worse.
>
>>>> + add_property(an, p);
>>>> + }
>>>> +
>>>> + /* force allocation of a phandle for this node */
>>>> + if (allocph)
>>>> + (void)get_node_phandle(dt, node);
>>>> + }
>>>> +
>>>> + for_each_child(node, c)
>>>> + generate_label_tree_internal(dt, c, an, allocph);
>>>> +}
>>>> +
>>>> +void generate_label_tree(struct node *dt, char *gen_node_name, bool allocph)
>>>> +{
>>>> + struct node *an;
>>>> +
>>>> + for_each_child(dt, an)
>>>> + if (streq(gen_node_name, an->name))
>>>> + break;
>>>> +
>>>> + if (!an)
>>>> + an = build_and_name_child_node(dt, gen_node_name);
>>>> + if (!an)
>>>> + die("Could not build label node /%s\n", gen_node_name);
>>>> +
>>>> + generate_label_tree_internal(dt, dt, an, allocph);
>>>> +}
>>>> +
>>>> +static char *fixups_name = "__fixups__";
>>>> +static char *local_fixups_name = "__local_fixups__";
>>>
>>> I'd actually prefer #defines for these, and all-caps names, so it's
>>> more obvious when they're used that these are global constants.
>>>
>>
>> OK.
>>
>>>> +
>>>> +static void add_fixup_entry(struct node *dt, struct node *node,
>>>> + struct property *prop, struct marker *m)
>>>> +{
>>>> + struct node *fn; /* fixup node */
>>>> + char *entry;
>>>> +
>>>> + /* m->ref can only be a REF_PHANDLE, but check anyway */
>>>> + assert(m->type == REF_PHANDLE);
>>>> +
>>>> + /* fn is the node we're putting entries in */
>>>> + fn = get_subnode(dt, fixups_name);
>>>> + assert(fn != NULL);
>>>> +
>>>> + /* there shouldn't be any ':' in the arguments */
>>>> + if (strchr(node->fullpath, ':') || strchr(prop->name, ':'))
>>>> + die("arguments should not contain ':'\n");
>>>> +
>>>> + xasprintf(&entry, "%s:%s:%u",
>>>> + node->fullpath, prop->name, m->offset);
>>>> + append_to_property(fn, m->ref, entry, strlen(entry) + 1);
>>>> +}
>>>> +
>>>> +static void add_local_fixup_entry(struct node *dt, struct node *node,
>>>> + struct property *prop, struct marker *m,
>>>> + struct node *refnode)
>>>> +{
>>>> + struct node *lfn, *wn, *nwn; /* local fixup node, walk node, new */
>>>> + uint32_t value_32;
>>>> + char *s, *e, *comp;
>>>> + int len;
>>>> +
>>>> + /* fn is the node we're putting entries in */
>>>> + lfn = get_subnode(dt, local_fixups_name);
>>>> + assert(lfn != NULL);
>>>> +
>>>> + /* walk the path components creating nodes if they don't exist */
>>>> + comp = xmalloc(strlen(node->fullpath) + 1);
>>>> + /* start skipping the first / */
>>>> + s = node->fullpath + 1;
>>>> + wn = lfn;
>>>> + while (*s) {
>>>> + /* retrieve path component */
>>>> + e = strchr(s, '/');
>>>> + if (e == NULL)
>>>> + e = s + strlen(s);
>>>> + len = e - s;
>>>> + memcpy(comp, s, len);
>>>> + comp[len] = '\0';
>>>> +
>>>> + /* if no node exists, create it */
>>>> + nwn = get_subnode(wn, comp);
>>>> + if (!nwn)
>>>> + nwn = build_and_name_child_node(wn, comp);
>>>> + wn = nwn;
>>>> +
>>>> + /* last path component */
>>>> + if (!*e)
>>>> + break;
>>>> +
>>>> + /* next path component */
>>>> + s = e + 1;
>>>> + }
>>>> + free(comp);
>>>> +
>>>> + value_32 = cpu_to_fdt32(m->offset);
>>>> + append_to_property(wn, prop->name, &value_32, sizeof(value_32));
>>>> +}
>>>> +
>>>> +static void generate_fixups_tree_internal(struct node *dt, struct node *node)
>>>> +{
>>>> + struct node *c;
>>>> + struct property *prop;
>>>> + struct marker *m;
>>>> + struct node *refnode;
>>>> +
>>>> + for_each_property(node, prop) {
>>>> + m = prop->val.markers;
>>>> + for_each_marker_of_type(m, REF_PHANDLE) {
>>>> + refnode = get_node_by_ref(dt, m->ref);
>>>> + if (!refnode)
>>>> + add_fixup_entry(dt, node, prop, m);
>>>> + else
>>>> + add_local_fixup_entry(dt, node, prop, m,
>>>> + refnode);
>>>> + }
>>>> + }
>>>> +
>>>> + for_each_child(node, c)
>>>> + generate_fixups_tree_internal(dt, c);
>>>> +}
>>>> +
>>>> +void generate_fixups_tree(struct node *dt)
>>>> +{
>>>> + struct node *an;
>>>> +
>>>> + for_each_child(dt, an)
>>>> + if (streq(fixups_name, an->name))
>>>> + break;
>>>> +
>>>> + if (!an)
>>>> + build_and_name_child_node(dt, fixups_name);
>>>> +
>>>> + for_each_child(dt, an)
>>>> + if (streq(local_fixups_name, an->name))
>>>> + break;
>>>> +
>>>> + if (!an)
>>>> + build_and_name_child_node(dt, local_fixups_name);
>>>> +
>>>> + generate_fixups_tree_internal(dt, dt);
>>>> +}
>>>> diff --git a/tests/mangle-layout.c b/tests/mangle-layout.c
>>>> index a76e51e..d29ebc6 100644
>>>> --- a/tests/mangle-layout.c
>>>> +++ b/tests/mangle-layout.c
>>>> @@ -42,7 +42,8 @@ static void expand_buf(struct bufstate *buf, int newsize)
>>>> buf->size = newsize;
>>>> }
>>>>
>>>> -static void new_header(struct bufstate *buf, int version, const void *fdt)
>>>> +static void new_header(struct bufstate *buf, fdt32_t magic, int version,
>>>> + const void *fdt)
>>>> {
>>>> int hdrsize;
>>>>
>>>> @@ -56,7 +57,7 @@ static void new_header(struct bufstate *buf, int version, const void *fdt)
>>>> expand_buf(buf, hdrsize);
>>>> memset(buf->buf, 0, hdrsize);
>>>>
>>>> - fdt_set_magic(buf->buf, FDT_MAGIC);
>>>> + fdt_set_magic(buf->buf, magic);
>>>> fdt_set_version(buf->buf, version);
>>>> fdt_set_last_comp_version(buf->buf, 16);
>>>> fdt_set_boot_cpuid_phys(buf->buf, fdt_boot_cpuid_phys(fdt));
>>>> @@ -145,7 +146,7 @@ int main(int argc, char *argv[])
>>>> if (fdt_version(fdt) < 17)
>>>> CONFIG("Input tree must be v17");
>>>>
>>>> - new_header(&buf, version, fdt);
>>>> + new_header(&buf, FDT_MAGIC, version, fdt);
>>>>
>>>> while (*blockorder) {
>>>> add_block(&buf, version, *blockorder, fdt);
>>>> diff --git a/treesource.c b/treesource.c
>>>> index a55d1d1..75e920d 100644
>>>> --- a/treesource.c
>>>> +++ b/treesource.c
>>>> @@ -267,7 +267,12 @@ void dt_to_source(FILE *f, struct boot_info *bi)
>>>> {
>>>> struct reserve_info *re;
>>>>
>>>> - fprintf(f, "/dts-v1/;\n\n");
>>>> + fprintf(f, "/dts-v1/");
>>>> +
>>>> + if (bi->versionflags & VF_PLUGIN)
>>>> + fprintf(f, " /plugin/");
>>>> +
>>>> + fprintf(f, ";\n\n");
>>>
>>> I'm not sure this really makes sense. The /plugin/ tag triggers the
>>> fixup construction and encoding of overlay fragments. But in an
>>> incoming dtb, that processing has already been done once, doing it
>>> again would not make sense. So I think the output should not have the
>>> /plugin/ tag, even if the input did.
>>>
>>> Unless, of course, you parsed the input into an explicit list of
>>> overlays, then output it here again as a list of overlays, not the
>>> encoded fragments. i.e. if this was the original tree:
>>>
>>> /dts-v1/ /plugin/;
>>>
>>> &somwhere {
>>> name = "value";
>>> };
>>>
>>> then legitimately the output of -I dts -O dts could be either:
>>>
>>> /dts-v1/ /plugin/;
>>>
>>> &somwhere {
>>> name = "value";
>>> };
>>>
>>> OR
>>>
>>> /dts-v1/;
>>>
>>> / {
>>> fragment@0 {
>>> target = <0xffffffff>;
>>> __overlay__{
>>> name = "value";
>>> };
>>> };
>>> __fixups__ {
>>> somewhere = "/fragment@0:target:0";
>>> };
>>> };
>>>
>>> But it doesn't make sense to combine the two: the second structure
>>> with the "/plugin/" tag.
>>>
>>
>>> Another advantage of moving the overlay application out of the parser
>>> is you can sanely produce either output, both of which could be useful
>>> in the right circumstances. You can potentially even produce the
>>> first output (or something close) from dtb input, with correct parsing
>>> of the overlay structure on dtb input.
>>>
>>
>> Yes, this makes sense. For now I’ll remove the plugin tag, but if the blob
>> was compiled with -@ you could conceivably reverse back to a form that contains
>> labels and phandle references correctly.
>>
>> But this is quite complicated to undertake in this patch series.
>>
>> To re-iterate though there is no overlay application here :)
>
> Well, I think we've both been a bit sloppy with terminology - does
> "overlay" refer to a dtbo file, or to one of the &ref { ... }
> fragments in the source, or to both.
>
> But whatever the right term is for the &ref { .. } fragments in the
> source they absolutely *are* applied during compile for the base tree
> case. And while they're not resolved fully, they are encoded into
> part of a larger tree structure for the plugin case.
>
> The confusion will be reduced if we make these
> overlays/fragments/whatever first class objects in the "live tree"
> phase of the compile, and move the resolution and/or assembly of them
> a stage that's separate from the parse. In addition, it opens the way
> for decompiling a dtbo more naturally, though as you say that's a
> moderate amount of extra work.
>
How about we get the non &ref { } case sorted out and we can talk about
the syntactic sugar version done?
v10 has been sent out.
> --
> David Gibson | I'll have my music baroque, and my code
> david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
> | _way_ _around_!
> http://www.ozlabs.org/~dgibson
Regards
— Pantelis
^ permalink raw reply
* Re: Question regarding clocks in the DW-HDMI DT bindings
From: Fabio Estevam @ 2016-11-25 12:43 UTC (permalink / raw)
To: Laurent Pinchart
Cc: devicetree@vger.kernel.org, Mike Turquette, Stephen Boyd,
DRI mailing list, Andy Yan, Vladimir Zapolskiy
In-Reply-To: <4461318.dYHS3nW9CP@avalon>
Hi Laurent,
On Thu, Nov 24, 2016 at 9:26 PM, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
> Another question I have about the bus clock (CC'ing the devicetree mailing
> list as well as the clock maintainers) is whether it should be made optional.
> The clock is obviously mandatory from a hardware point of view (given that APB
> is a synchronous bus and thus requires a clock), but in some SoCs
> (specifically for the Renesas SoCs) that clock is always on and can't be
> controlled. We already omit bus clocks in DT for most IP cores when the clock
> can never be controlled (and we also omit a bunch of other clocks that we
> don't even know exist), so it could make sense to make the clock optional.
> Otherwise there would be runtime overhead trying to handle a clock that can't
> be controlled.
What if you register the clock as a "dummy" clock instead?
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* [PATCH v2 8/8] ARM: dts: sun8i-h3: orange-pi-pc: Enable audio codec
From: Chen-Yu Tsai @ 2016-11-25 12:34 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Maxime Ripard, Lee Jones
Cc: devicetree, alsa-devel, linux-kernel, Chen-Yu Tsai,
Mylene Josserand, linux-arm-kernel
In-Reply-To: <20161125123442.28410-1-wens@csie.org>
The Orange Pi PC routes the LINEOUT pins to the audio out jack on the
board. The onboard microphone is routed to MIC1, with MBIAS providing
power.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
index 98b85be61e17..d43978d3294e 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
@@ -90,6 +90,14 @@
};
};
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
&ehci1 {
status = "okay";
};
--
2.10.2
^ permalink raw reply related
* [PATCH v2 7/8] ARM: dts: sun8i-h3: Add device nodes for audio codec and its analog controls
From: Chen-Yu Tsai @ 2016-11-25 12:34 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Maxime Ripard, Lee Jones
Cc: devicetree, alsa-devel, linux-kernel, Chen-Yu Tsai,
Mylene Josserand, linux-arm-kernel
In-Reply-To: <20161125123442.28410-1-wens@csie.org>
Now that we support the audio codec found on the Allwinner H3 SoC, add
device nodes for it.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
arch/arm/boot/dts/sun8i-h3.dtsi | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
index fca66bf2dec5..496efc564bbe 100644
--- a/arch/arm/boot/dts/sun8i-h3.dtsi
+++ b/arch/arm/boot/dts/sun8i-h3.dtsi
@@ -465,6 +465,20 @@
status = "disabled";
};
+ codec: codec@01c22c00 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun8i-h3-codec";
+ reg = <0x01c22c00 0x400>;
+ interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>;
+ clock-names = "apb", "codec";
+ resets = <&ccu RST_BUS_CODEC>;
+ dmas = <&dma 15>, <&dma 15>;
+ dma-names = "rx", "tx";
+ allwinner,codec-analog-controls = <&codec_analog>;
+ status = "disabled";
+ };
+
uart0: serial@01c28000 {
compatible = "snps,dw-apb-uart";
reg = <0x01c28000 0x400>;
@@ -580,6 +594,11 @@
#reset-cells = <1>;
};
+ codec_analog: codec-analog@01f015c0 {
+ compatible = "allwinner,sun8i-h3-codec-analog";
+ reg = <0x01f015c0 0x4>;
+ };
+
ir: ir@01f02000 {
compatible = "allwinner,sun5i-a13-ir";
clocks = <&apb0_gates 1>, <&ir_clk>;
--
2.10.2
^ permalink raw reply related
* [PATCH v2 6/8] ASoC: sun4i-codec: Add support for H3 codec
From: Chen-Yu Tsai @ 2016-11-25 12:34 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Maxime Ripard, Lee Jones
Cc: devicetree, alsa-devel, linux-kernel, Chen-Yu Tsai,
Mylene Josserand, linux-arm-kernel
In-Reply-To: <20161125123442.28410-1-wens@csie.org>
The codec on the H3 is similar to the one found on the A31. One key
difference is the analog path controls are routed through the PRCM
block. This is supported by the sun8i-codec-analog driver, and tied
into this codec driver with the audio card's aux_dev.
In addition, the H3 has no HP (headphone) and HBIAS support, and no
MIC3 input. The FIFO related registers are slightly rearranged.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Acked-by: Rob Herring <robh@kernel.org>
---
.../devicetree/bindings/sound/sun4i-codec.txt | 3 +
sound/soc/sunxi/sun4i-codec.c | 71 ++++++++++++++++++++++
2 files changed, 74 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/sun4i-codec.txt b/Documentation/devicetree/bindings/sound/sun4i-codec.txt
index f7a548b604fc..3033bd8aab0f 100644
--- a/Documentation/devicetree/bindings/sound/sun4i-codec.txt
+++ b/Documentation/devicetree/bindings/sound/sun4i-codec.txt
@@ -6,6 +6,7 @@ Required properties:
- "allwinner,sun6i-a31-codec"
- "allwinner,sun7i-a20-codec"
- "allwinner,sun8i-a23-codec"
+ - "allwinner,sun8i-h3-codec"
- reg: must contain the registers location and length
- interrupts: must contain the codec interrupt
- dmas: DMA channels for tx and rx dma. See the DMA client binding,
@@ -23,6 +24,7 @@ Optional properties:
Required properties for the following compatibles:
- "allwinner,sun6i-a31-codec"
- "allwinner,sun8i-a23-codec"
+ - "allwinner,sun8i-h3-codec"
- resets: phandle to the reset control for this device
- allwinner,audio-routing: A list of the connections between audio components.
Each entry is a pair of strings, the first being the
@@ -52,6 +54,7 @@ Required properties for the following compatibles:
Required properties for the following compatibles:
- "allwinner,sun8i-a23-codec"
+ - "allwinner,sun8i-h3-codec"
- allwinner,codec-analog-controls: A phandle to the codec analog controls
block in the PRCM.
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index ada5fa055950..848af01692a0 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -217,6 +217,13 @@
#define SUN8I_A23_CODEC_DAC_TXCNT (0x1c)
#define SUN8I_A23_CODEC_ADC_RXCNT (0x20)
+/* TX FIFO moved on H3 */
+#define SUN8I_H3_CODEC_DAC_TXDATA (0x20)
+#define SUN8I_H3_CODEC_DAC_DBG (0x48)
+#define SUN8I_H3_CODEC_ADC_DBG (0x4c)
+
+/* TODO H3 DAP (Digital Audio Processing) bits */
+
struct sun4i_codec {
struct device *dev;
struct regmap *regmap;
@@ -1293,6 +1300,44 @@ static struct snd_soc_card *sun8i_a23_codec_create_card(struct device *dev)
return card;
};
+static struct snd_soc_card *sun8i_h3_codec_create_card(struct device *dev)
+{
+ struct snd_soc_card *card;
+ int ret;
+
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return ERR_PTR(-ENOMEM);
+
+ aux_dev.codec_of_node = of_parse_phandle(dev->of_node,
+ "allwinner,codec-analog-controls",
+ 0);
+ if (!aux_dev.codec_of_node) {
+ dev_err(dev, "Can't find analog controls for codec.\n");
+ return ERR_PTR(-EINVAL);
+ };
+
+ card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
+ if (!card->dai_link)
+ return ERR_PTR(-ENOMEM);
+
+ card->dev = dev;
+ card->name = "H3 Audio Codec";
+ card->dapm_widgets = sun6i_codec_card_dapm_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
+ card->dapm_routes = sun8i_codec_card_routes;
+ card->num_dapm_routes = ARRAY_SIZE(sun8i_codec_card_routes);
+ card->aux_dev = &aux_dev;
+ card->num_aux_devs = 1;
+ card->fully_routed = true;
+
+ ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
+ if (ret)
+ dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
+
+ return card;
+};
+
static const struct regmap_config sun4i_codec_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
@@ -1321,6 +1366,13 @@ static const struct regmap_config sun8i_a23_codec_regmap_config = {
.max_register = SUN8I_A23_CODEC_ADC_RXCNT,
};
+static const struct regmap_config sun8i_h3_codec_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = SUN8I_H3_CODEC_ADC_DBG,
+};
+
struct sun4i_codec_quirks {
const struct regmap_config *regmap_config;
const struct snd_soc_codec_driver *codec;
@@ -1369,6 +1421,21 @@ static const struct sun4i_codec_quirks sun8i_a23_codec_quirks = {
.has_reset = true,
};
+static const struct sun4i_codec_quirks sun8i_h3_codec_quirks = {
+ .regmap_config = &sun8i_h3_codec_regmap_config,
+ /*
+ * TODO Share the codec structure with A23 for now.
+ * This should be split out when adding digital audio
+ * processing support for the H3.
+ */
+ .codec = &sun8i_a23_codec_codec,
+ .create_card = sun8i_h3_codec_create_card,
+ .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
+ .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA,
+ .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
+ .has_reset = true,
+};
+
static const struct of_device_id sun4i_codec_of_match[] = {
{
.compatible = "allwinner,sun4i-a10-codec",
@@ -1386,6 +1453,10 @@ static const struct of_device_id sun4i_codec_of_match[] = {
.compatible = "allwinner,sun8i-a23-codec",
.data = &sun8i_a23_codec_quirks,
},
+ {
+ .compatible = "allwinner,sun8i-h3-codec",
+ .data = &sun8i_h3_codec_quirks,
+ },
{}
};
MODULE_DEVICE_TABLE(of, sun4i_codec_of_match);
--
2.10.2
^ permalink raw reply related
* [PATCH v2 5/8] ARM: dts: sun8i-a23: q8-tablet: Enable internal audio codec
From: Chen-Yu Tsai @ 2016-11-25 12:34 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Maxime Ripard, Lee Jones
Cc: devicetree, alsa-devel, linux-kernel, Chen-Yu Tsai,
Mylene Josserand, linux-arm-kernel
In-Reply-To: <20161125123442.28410-1-wens@csie.org>
The A23 Q8 tablets have an internal mono speaker w/ external amp
which has a shutdown control tied to a GPIO pin. Both the speaker
amp and the headphone jack are tied to the HP output pins. While
the speaker is mono, the headset jack is stereo. Unfortunately
the driver does not support automatic switching of this.
In addition, the headset is DC coupled, or "direct drive" enabled.
The headset's microphone is tied to MIC2 with HBIAS providing power.
A separate internal microphone is tied to MIC1 with MBIAS providing
power.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
arch/arm/boot/dts/sun8i-a23-q8-tablet.dts | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-a23-q8-tablet.dts b/arch/arm/boot/dts/sun8i-a23-q8-tablet.dts
index 956320a6cc78..3ab5c0c09d93 100644
--- a/arch/arm/boot/dts/sun8i-a23-q8-tablet.dts
+++ b/arch/arm/boot/dts/sun8i-a23-q8-tablet.dts
@@ -48,3 +48,26 @@
model = "Q8 A23 Tablet";
compatible = "allwinner,q8-a23", "allwinner,sun8i-a23";
};
+
+&codec {
+ pinctrl-0 = <&codec_pa_pin>;
+ allwinner,pa-gpios = <&pio 7 9 GPIO_ACTIVE_HIGH>; /* PH9 */
+ allwinner,audio-routing =
+ "Headphone", "HP",
+ "Headphone", "HPCOM",
+ "Speaker", "HP",
+ "MIC1", "Mic",
+ "MIC2", "Headset Mic",
+ "Mic", "MBIAS",
+ "Headset Mic", "HBIAS";
+ status = "okay";
+};
+
+&pio {
+ codec_pa_pin: codec_pa_pin@0 {
+ allwinner,pins = "PH9";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
--
2.10.2
^ permalink raw reply related
* [PATCH v2 4/8] ARM: dts: sun8i-a23: Add device node for internal audio codec
From: Chen-Yu Tsai @ 2016-11-25 12:34 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Maxime Ripard, Lee Jones
Cc: devicetree, alsa-devel, linux-kernel, Chen-Yu Tsai,
Mylene Josserand, linux-arm-kernel
In-Reply-To: <20161125123442.28410-1-wens@csie.org>
Now that we have a device tree binding and driver for the A23's
internal audio codec, add a device node for it.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
arch/arm/boot/dts/sun8i-a23.dtsi | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-a23.dtsi b/arch/arm/boot/dts/sun8i-a23.dtsi
index 54d045dab825..4d1f929780a8 100644
--- a/arch/arm/boot/dts/sun8i-a23.dtsi
+++ b/arch/arm/boot/dts/sun8i-a23.dtsi
@@ -48,6 +48,22 @@
memory {
reg = <0x40000000 0x40000000>;
};
+
+ soc@01c00000 {
+ codec: codec@01c22c00 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun8i-a23-codec";
+ reg = <0x01c22c00 0x400>;
+ interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>;
+ clock-names = "apb", "codec";
+ resets = <&ccu RST_BUS_CODEC>;
+ dmas = <&dma 15>, <&dma 15>;
+ dma-names = "rx", "tx";
+ allwinner,codec-analog-controls = <&codec_analog>;
+ status = "disabled";
+ };
+ };
};
&ccu {
--
2.10.2
^ permalink raw reply related
* [PATCH v2 3/8] ARM: dts: sun8i: Add codec analog path controls node in PRCM for A23/A33
From: Chen-Yu Tsai @ 2016-11-25 12:34 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Maxime Ripard, Lee Jones
Cc: devicetree, alsa-devel, linux-kernel, Chen-Yu Tsai,
Mylene Josserand, linux-arm-kernel
In-Reply-To: <20161125123442.28410-1-wens@csie.org>
On the A23/A33, the internal codec's analog path controls are located in
the PRCM node.
Add a sub-device node to the PRCM for it.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
arch/arm/boot/dts/sun8i-a23-a33.dtsi | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-a23-a33.dtsi b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
index bc3e936edfcf..d9c6f16f95f1 100644
--- a/arch/arm/boot/dts/sun8i-a23-a33.dtsi
+++ b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
@@ -538,6 +538,10 @@
compatible = "allwinner,sun6i-a31-clock-reset";
#reset-cells = <1>;
};
+
+ codec_analog: codec-analog {
+ compatible = "allwinner,sun8i-a23-codec-analog";
+ };
};
cpucfg@01f01c00 {
--
2.10.2
^ permalink raw reply related
* [PATCH v2 2/8] ASoC: sun4i-codec: Add support for A23 codec
From: Chen-Yu Tsai @ 2016-11-25 12:34 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Maxime Ripard, Lee Jones
Cc: devicetree, alsa-devel, linux-kernel, Chen-Yu Tsai,
Mylene Josserand, linux-arm-kernel
In-Reply-To: <20161125123442.28410-1-wens@csie.org>
The codec in the A23 is similar to the one found on the A31. One key
difference is the analog path controls are routed through the PRCM
block. This is supported by the sun8i-codec-analog driver, and tied
into this codec driver with the audio card's aux_dev.
In addition, the A23 does not have LINEOUT, and it does not support
headset jack detection or buttons.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Acked-by: Rob Herring <robh@kernel.org>
---
.../devicetree/bindings/sound/sun4i-codec.txt | 11 ++-
sound/soc/sunxi/sun4i-codec.c | 108 +++++++++++++++++++++
2 files changed, 117 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/sound/sun4i-codec.txt b/Documentation/devicetree/bindings/sound/sun4i-codec.txt
index d91a95377f49..f7a548b604fc 100644
--- a/Documentation/devicetree/bindings/sound/sun4i-codec.txt
+++ b/Documentation/devicetree/bindings/sound/sun4i-codec.txt
@@ -5,6 +5,7 @@ Required properties:
- "allwinner,sun4i-a10-codec"
- "allwinner,sun6i-a31-codec"
- "allwinner,sun7i-a20-codec"
+ - "allwinner,sun8i-a23-codec"
- reg: must contain the registers location and length
- interrupts: must contain the codec interrupt
- dmas: DMA channels for tx and rx dma. See the DMA client binding,
@@ -21,6 +22,7 @@ Optional properties:
Required properties for the following compatibles:
- "allwinner,sun6i-a31-codec"
+ - "allwinner,sun8i-a23-codec"
- resets: phandle to the reset control for this device
- allwinner,audio-routing: A list of the connections between audio components.
Each entry is a pair of strings, the first being the
@@ -31,10 +33,10 @@ Required properties for the following compatibles:
"HP"
"HPCOM"
"LINEIN"
- "LINEOUT"
+ "LINEOUT" (not on sun8i-a23)
"MIC1"
"MIC2"
- "MIC3"
+ "MIC3" (sun6i-a31 only)
Microphone biases from the SoC:
"HBIAS"
@@ -48,6 +50,11 @@ Required properties for the following compatibles:
"Mic"
"Speaker"
+Required properties for the following compatibles:
+ - "allwinner,sun8i-a23-codec"
+- allwinner,codec-analog-controls: A phandle to the codec analog controls
+ block in the PRCM.
+
Example:
codec: codec@01c22c00 {
#sound-dai-cells = <0>;
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 092fdcf6de95..ada5fa055950 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -213,6 +213,10 @@
/* TODO sun6i DAP (Digital Audio Processing) bits */
+/* FIFO counters moved on A23 */
+#define SUN8I_A23_CODEC_DAC_TXCNT (0x1c)
+#define SUN8I_A23_CODEC_ADC_RXCNT (0x20)
+
struct sun4i_codec {
struct device *dev;
struct regmap *regmap;
@@ -1067,6 +1071,32 @@ static struct snd_soc_codec_driver sun6i_codec_codec = {
},
};
+/* sun8i A23 codec */
+static const struct snd_kcontrol_new sun8i_a23_codec_codec_controls[] = {
+ SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC,
+ SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1,
+ sun6i_codec_dvol_scale),
+};
+
+static const struct snd_soc_dapm_widget sun8i_a23_codec_codec_widgets[] = {
+ /* Digital parts of the ADCs */
+ SND_SOC_DAPM_SUPPLY("ADC Enable", SUN6I_CODEC_ADC_FIFOC,
+ SUN6I_CODEC_ADC_FIFOC_EN_AD, 0, NULL, 0),
+ /* Digital parts of the DACs */
+ SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC,
+ SUN4I_CODEC_DAC_DPC_EN_DA, 0, NULL, 0),
+
+};
+
+static struct snd_soc_codec_driver sun8i_a23_codec_codec = {
+ .component_driver = {
+ .controls = sun8i_a23_codec_codec_controls,
+ .num_controls = ARRAY_SIZE(sun8i_a23_codec_codec_controls),
+ .dapm_widgets = sun8i_a23_codec_codec_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sun8i_a23_codec_codec_widgets),
+ },
+};
+
static const struct snd_soc_component_driver sun4i_codec_component = {
.name = "sun4i-codec",
};
@@ -1206,6 +1236,63 @@ static struct snd_soc_card *sun6i_codec_create_card(struct device *dev)
return card;
};
+/* Connect digital side enables to analog side widgets */
+static const struct snd_soc_dapm_route sun8i_codec_card_routes[] = {
+ /* ADC Routes */
+ { "Left ADC", NULL, "ADC Enable" },
+ { "Right ADC", NULL, "ADC Enable" },
+ { "Codec Capture", NULL, "Left ADC" },
+ { "Codec Capture", NULL, "Right ADC" },
+
+ /* DAC Routes */
+ { "Left DAC", NULL, "DAC Enable" },
+ { "Right DAC", NULL, "DAC Enable" },
+ { "Left DAC", NULL, "Codec Playback" },
+ { "Right DAC", NULL, "Codec Playback" },
+};
+
+static struct snd_soc_aux_dev aux_dev = {
+ .name = "Codec Analog Controls",
+};
+
+static struct snd_soc_card *sun8i_a23_codec_create_card(struct device *dev)
+{
+ struct snd_soc_card *card;
+ int ret;
+
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return ERR_PTR(-ENOMEM);
+
+ aux_dev.codec_of_node = of_parse_phandle(dev->of_node,
+ "allwinner,codec-analog-controls",
+ 0);
+ if (!aux_dev.codec_of_node) {
+ dev_err(dev, "Can't find analog controls for codec.\n");
+ return ERR_PTR(-EINVAL);
+ };
+
+ card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
+ if (!card->dai_link)
+ return ERR_PTR(-ENOMEM);
+
+ card->dev = dev;
+ card->name = "A23 Audio Codec";
+ card->dapm_widgets = sun6i_codec_card_dapm_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
+ card->dapm_routes = sun8i_codec_card_routes;
+ card->num_dapm_routes = ARRAY_SIZE(sun8i_codec_card_routes);
+ card->aux_dev = &aux_dev;
+ card->num_aux_devs = 1;
+ card->fully_routed = true;
+
+ ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
+ if (ret)
+ dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
+
+ return card;
+};
+
static const struct regmap_config sun4i_codec_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
@@ -1227,6 +1314,13 @@ static const struct regmap_config sun7i_codec_regmap_config = {
.max_register = SUN7I_CODEC_AC_MIC_PHONE_CAL,
};
+static const struct regmap_config sun8i_a23_codec_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = SUN8I_A23_CODEC_ADC_RXCNT,
+};
+
struct sun4i_codec_quirks {
const struct regmap_config *regmap_config;
const struct snd_soc_codec_driver *codec;
@@ -1265,6 +1359,16 @@ static const struct sun4i_codec_quirks sun7i_codec_quirks = {
.reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA,
};
+static const struct sun4i_codec_quirks sun8i_a23_codec_quirks = {
+ .regmap_config = &sun8i_a23_codec_regmap_config,
+ .codec = &sun8i_a23_codec_codec,
+ .create_card = sun8i_a23_codec_create_card,
+ .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
+ .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
+ .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
+ .has_reset = true,
+};
+
static const struct of_device_id sun4i_codec_of_match[] = {
{
.compatible = "allwinner,sun4i-a10-codec",
@@ -1278,6 +1382,10 @@ static const struct of_device_id sun4i_codec_of_match[] = {
.compatible = "allwinner,sun7i-a20-codec",
.data = &sun7i_codec_quirks,
},
+ {
+ .compatible = "allwinner,sun8i-a23-codec",
+ .data = &sun8i_a23_codec_quirks,
+ },
{}
};
MODULE_DEVICE_TABLE(of, sun4i_codec_of_match);
--
2.10.2
^ permalink raw reply related
* [PATCH v2 1/8] mfd: sun6i-prcm: Add codec analog controls sub-device for Allwinner A23
From: Chen-Yu Tsai @ 2016-11-25 12:34 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Maxime Ripard, Lee Jones
Cc: devicetree, alsa-devel, linux-kernel, Chen-Yu Tsai,
Mylene Josserand, linux-arm-kernel
In-Reply-To: <20161125123442.28410-1-wens@csie.org>
The PRCM block on the A23 contains a message box like interface to
the registers for the analog path controls of the internal codec.
Add a sub-device for it.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
drivers/mfd/sun6i-prcm.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/drivers/mfd/sun6i-prcm.c b/drivers/mfd/sun6i-prcm.c
index 011fcc555945..2b658bed47db 100644
--- a/drivers/mfd/sun6i-prcm.c
+++ b/drivers/mfd/sun6i-prcm.c
@@ -12,6 +12,9 @@
#include <linux/init.h>
#include <linux/of.h>
+#define SUN8I_CODEC_ANALOG_BASE 0x1c0
+#define SUN8I_CODEC_ANALOG_SIZE 0x4
+
struct prcm_data {
int nsubdevs;
const struct mfd_cell *subdevs;
@@ -57,6 +60,10 @@ static const struct resource sun6i_a31_apb0_rstc_res[] = {
},
};
+static const struct resource sun8i_codec_analog_res[] = {
+ DEFINE_RES_MEM(SUN8I_CODEC_ANALOG_BASE, SUN8I_CODEC_ANALOG_SIZE),
+};
+
static const struct mfd_cell sun6i_a31_prcm_subdevs[] = {
{
.name = "sun6i-a31-ar100-clk",
@@ -109,6 +116,12 @@ static const struct mfd_cell sun8i_a23_prcm_subdevs[] = {
.num_resources = ARRAY_SIZE(sun6i_a31_apb0_rstc_res),
.resources = sun6i_a31_apb0_rstc_res,
},
+ {
+ .name = "sun8i-codec-analog",
+ .of_compatible = "allwinner,sun8i-a23-codec-analog",
+ .num_resources = ARRAY_SIZE(sun8i_codec_analog_res),
+ .resources = sun8i_codec_analog_res,
+ },
};
static const struct prcm_data sun6i_a31_prcm_data = {
--
2.10.2
^ permalink raw reply related
* [PATCH v2 0/8] ASoC: sunxi: Add support for audio codec in A23/H3 SoCs
From: Chen-Yu Tsai @ 2016-11-25 12:34 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Maxime Ripard, Lee Jones
Cc: devicetree, alsa-devel, linux-kernel, Chen-Yu Tsai,
Mylene Josserand, linux-arm-kernel
Hi everyone,
This is v2 of my Allwinner A23 and H3 audio codec support series.
Changes since v1:
- Use DEFINE_RES_MEM for the analog path controls block resources.
- Added Rob's ack.
This series adds support for the audio codec found in Allwinner A23 and
H3 SoCs. The design and data paths are similar to the audio codec found
in earlier SoCs such as the A31. The analog audio paths are symmetrical
with left/right channels and down-mix selectors for mono differential
output.
What deviates from previous SoCs is that the analog path controls have
been moved to a separate control bus, accessed through a message box
like register interface in the PRCM block. This necessitates writing
a separate component driver for it, which is then tied into the sound
card as an ASoC auxiliary device.
Patch 1 adds the analog path controls block to the sun6i-prcm driver as
a sub-device, for the A23. The H3 currently does not use the PRCM driver.
Patch 2 adds PCM and card support for the A23 codec to the sun4i-codec
driver.
Patch 3 adds a device node for the analog path controls block to the A23
dtsi.
Patch 4 adds a device node for the audio codec, and the phandle for the
analog path controls block to the A23 dtsi.
Patch 5 enables the audio codec for the A23 Q8 tablets. On these tablets
the headphone output is driven in DC coupled, or "direct drive", mode.
Patch 6 adds PCM and card support for the H3 codec to the sun4i-codec
driver.
Patch 7 adds device nodes for the audio codec and analog path controls
block to the H3 dtsi.
Patch 8 enables the audio codec on the Orange Pi PC. The audio output
jack on the board is tied to the line out pins on the SoC.
Please take a look and let me know what you think.
In addition, the sun4i-codec driver is getting pretty large. Maybe we
want to split the different parts into different files?
Regards
ChenYu
Chen-Yu Tsai (8):
mfd: sun6i-prcm: Add codec analog controls sub-device for Allwinner
A23
ASoC: sun4i-codec: Add support for A23 codec
ARM: dts: sun8i: Add codec analog path controls node in PRCM for
A23/A33
ARM: dts: sun8i-a23: Add device node for internal audio codec
ARM: dts: sun8i-a23: q8-tablet: Enable internal audio codec
ASoC: sun4i-codec: Add support for H3 codec
ARM: dts: sun8i-h3: Add device nodes for audio codec and its analog
controls
ARM: dts: sun8i-h3: orange-pi-pc: Enable audio codec
.../devicetree/bindings/sound/sun4i-codec.txt | 14 +-
arch/arm/boot/dts/sun8i-a23-a33.dtsi | 4 +
arch/arm/boot/dts/sun8i-a23-q8-tablet.dts | 23 +++
arch/arm/boot/dts/sun8i-a23.dtsi | 16 ++
arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts | 8 +
arch/arm/boot/dts/sun8i-h3.dtsi | 19 +++
drivers/mfd/sun6i-prcm.c | 13 ++
sound/soc/sunxi/sun4i-codec.c | 179 +++++++++++++++++++++
8 files changed, 274 insertions(+), 2 deletions(-)
--
2.10.2
^ permalink raw reply
* [PATCH v10 4/4] tests: Add overlay tests
From: Pantelis Antoniou @ 2016-11-25 12:32 UTC (permalink / raw)
To: David Gibson
Cc: Jon Loeliger, Grant Likely, Frank Rowand, Rob Herring, Jan Luebbe,
Sascha Hauer, Phil Elwell, Simon Glass, Maxime Ripard,
Thomas Petazzoni, Boris Brezillon, Antoine Tenart, Stephen Boyd,
Devicetree Compiler, devicetree-u79uwXL29TY76Z2rM5mHXA,
Pantelis Antoniou
In-Reply-To: <1480077131-14526-1-git-send-email-pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
Add a number of tests for dynamic objects/overlays.
Re-use the original test by moving the contents to a .dtsi include
Signed-off-by: Pantelis Antoniou <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
---
tests/overlay_overlay_dtc.dts | 76 +----------------------------------
tests/overlay_overlay_dtc.dtsi | 83 +++++++++++++++++++++++++++++++++++++++
tests/overlay_overlay_new_dtc.dts | 11 ++++++
tests/overlay_overlay_simple.dts | 12 ++++++
tests/run_tests.sh | 20 ++++++++++
5 files changed, 127 insertions(+), 75 deletions(-)
create mode 100644 tests/overlay_overlay_dtc.dtsi
create mode 100644 tests/overlay_overlay_new_dtc.dts
create mode 100644 tests/overlay_overlay_simple.dts
diff --git a/tests/overlay_overlay_dtc.dts b/tests/overlay_overlay_dtc.dts
index 30d2362..ca943ea 100644
--- a/tests/overlay_overlay_dtc.dts
+++ b/tests/overlay_overlay_dtc.dts
@@ -8,78 +8,4 @@
/dts-v1/;
/plugin/;
-/ {
- /* Test that we can change an int by another */
- fragment@0 {
- target = <&test>;
-
- __overlay__ {
- test-int-property = <43>;
- };
- };
-
- /* Test that we can replace a string by a longer one */
- fragment@1 {
- target = <&test>;
-
- __overlay__ {
- test-str-property = "foobar";
- };
- };
-
- /* Test that we add a new property */
- fragment@2 {
- target = <&test>;
-
- __overlay__ {
- test-str-property-2 = "foobar2";
- };
- };
-
- /* Test that we add a new node (by phandle) */
- fragment@3 {
- target = <&test>;
-
- __overlay__ {
- new-node {
- new-property;
- };
- };
- };
-
- fragment@5 {
- target = <&test>;
-
- __overlay__ {
- local: new-local-node {
- new-property;
- };
- };
- };
-
- fragment@6 {
- target = <&test>;
-
- __overlay__ {
- test-phandle = <&test>, <&local>;
- };
- };
-
- fragment@7 {
- target = <&test>;
-
- __overlay__ {
- test-several-phandle = <&local>, <&local>;
- };
- };
-
- fragment@8 {
- target = <&test>;
-
- __overlay__ {
- sub-test-node {
- new-sub-test-property;
- };
- };
- };
-};
+/include/ "overlay_overlay_dtc.dtsi"
diff --git a/tests/overlay_overlay_dtc.dtsi b/tests/overlay_overlay_dtc.dtsi
new file mode 100644
index 0000000..8ea8d5d
--- /dev/null
+++ b/tests/overlay_overlay_dtc.dtsi
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2016 NextThing Co
+ * Copyright (c) 2016 Free Electrons
+ * Copyright (c) 2016 Konsulko Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/ {
+ /* Test that we can change an int by another */
+ fragment@0 {
+ target = <&test>;
+
+ __overlay__ {
+ test-int-property = <43>;
+ };
+ };
+
+ /* Test that we can replace a string by a longer one */
+ fragment@1 {
+ target = <&test>;
+
+ __overlay__ {
+ test-str-property = "foobar";
+ };
+ };
+
+ /* Test that we add a new property */
+ fragment@2 {
+ target = <&test>;
+
+ __overlay__ {
+ test-str-property-2 = "foobar2";
+ };
+ };
+
+ /* Test that we add a new node (by phandle) */
+ fragment@3 {
+ target = <&test>;
+
+ __overlay__ {
+ new-node {
+ new-property;
+ };
+ };
+ };
+
+ fragment@5 {
+ target = <&test>;
+
+ __overlay__ {
+ local: new-local-node {
+ new-property;
+ };
+ };
+ };
+
+ fragment@6 {
+ target = <&test>;
+
+ __overlay__ {
+ test-phandle = <&test>, <&local>;
+ };
+ };
+
+ fragment@7 {
+ target = <&test>;
+
+ __overlay__ {
+ test-several-phandle = <&local>, <&local>;
+ };
+ };
+
+ fragment@8 {
+ target = <&test>;
+
+ __overlay__ {
+ sub-test-node {
+ new-sub-test-property;
+ };
+ };
+ };
+};
diff --git a/tests/overlay_overlay_new_dtc.dts b/tests/overlay_overlay_new_dtc.dts
new file mode 100644
index 0000000..14d3f54
--- /dev/null
+++ b/tests/overlay_overlay_new_dtc.dts
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2016 NextThing Co
+ * Copyright (c) 2016 Free Electrons
+ * Copyright (c) 2016 Konsulko Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/dts-v1/ /plugin/;
+
+/include/ "overlay_overlay_dtc.dtsi"
diff --git a/tests/overlay_overlay_simple.dts b/tests/overlay_overlay_simple.dts
new file mode 100644
index 0000000..8657e1e
--- /dev/null
+++ b/tests/overlay_overlay_simple.dts
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2016 Konsulko Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/dts-v1/;
+/plugin/;
+
+&test {
+ test-int-property = <43>;
+};
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index e4139dd..99c09bc 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -181,6 +181,26 @@ overlay_tests () {
run_dtc_test -@ -I dts -O dtb -o overlay_base_with_symbols.test.dtb overlay_base.dts
run_dtc_test -@ -I dts -O dtb -o overlay_overlay_with_symbols.test.dtb overlay_overlay_dtc.dts
run_test overlay overlay_base_with_symbols.test.dtb overlay_overlay_with_symbols.test.dtb
+
+ # new /plugin/ format
+ run_dtc_test -@ -I dts -O dtb -o overlay_overlay_new_with_symbols.test.dtb overlay_overlay_new_dtc.dts
+
+ # test new magic option
+ run_dtc_test -M@ -I dts -O dtb -o overlay_overlay_with_symbols_new_magic.test.dtb overlay_overlay_dtc.dts
+
+ # test plugin source to dtb and back
+ run_dtc_test -@ -I dtb -O dts -o overlay_overlay_dtc.test.dts overlay_overlay_with_symbols.test.dtb
+ run_dtc_test -@ -I dts -O dtb -o overlay_overlay_with_symbols.test.test.dtb overlay_overlay_dtc.test.dts
+ run_test dtbs_equal_ordered overlay_overlay_with_symbols.test.dtb overlay_overlay_with_symbols.test.test.dtb
+
+ # test simplified plugin syntax
+ run_dtc_test -@ -I dts -O dtb -o overlay_overlay_simple.dtb overlay_overlay_simple.dts
+
+ # test plugin source to dtb and back (with new magic)
+ run_dtc_test -@ -I dtb -O dts -o overlay_overlay_dtc_new_magic.test.dts overlay_overlay_with_symbols_new_magic.test.dtb
+ run_dtc_test -@ -I dts -O dtb -o overlay_overlay_with_symbols_new_magic.test.test.dtb overlay_overlay_dtc_new_magic.test.dts
+ run_test dtbs_equal_ordered overlay_overlay_with_symbols_new_magic.test.dtb overlay_overlay_with_symbols_new_magic.test.test.dtb
+
fi
# Bad fixup tests
--
2.1.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 related
* [PATCH v10 3/4] dtc: Plugin and fixup support
From: Pantelis Antoniou @ 2016-11-25 12:32 UTC (permalink / raw)
To: David Gibson
Cc: Jon Loeliger, Grant Likely, Frank Rowand, Rob Herring, Jan Luebbe,
Sascha Hauer, Phil Elwell, Simon Glass, Maxime Ripard,
Thomas Petazzoni, Boris Brezillon, Antoine Tenart, Stephen Boyd,
Devicetree Compiler, devicetree-u79uwXL29TY76Z2rM5mHXA,
Pantelis Antoniou
In-Reply-To: <1480077131-14526-1-git-send-email-pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
This patch enable the generation of symbols & local fixup information
for trees compiled with the -@ (--symbols) option.
Using this patch labels in the tree and their users emit information
in __symbols__ and __local_fixups__ nodes.
The __fixups__ node make possible the dynamic resolution of phandle
references which are present in the plugin tree but lie in the
tree that are applying the overlay against.
While there is a new magic number for dynamic device tree/overlays blobs
it is by default enabled. Remember to use -M to generate compatible
blobs.
Signed-off-by: Pantelis Antoniou <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
Signed-off-by: Sascha Hauer <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Signed-off-by: Jan Luebbe <jlu-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
---
Documentation/manual.txt | 25 +++++-
checks.c | 8 +-
dtc-lexer.l | 5 ++
dtc-parser.y | 50 +++++++++--
dtc.c | 39 +++++++-
dtc.h | 20 ++++-
fdtdump.c | 2 +-
flattree.c | 17 ++--
fstree.c | 2 +-
libfdt/fdt.c | 2 +-
libfdt/fdt.h | 3 +-
livetree.c | 225 ++++++++++++++++++++++++++++++++++++++++++++++-
tests/mangle-layout.c | 7 +-
13 files changed, 375 insertions(+), 30 deletions(-)
diff --git a/Documentation/manual.txt b/Documentation/manual.txt
index 398de32..094893b 100644
--- a/Documentation/manual.txt
+++ b/Documentation/manual.txt
@@ -119,6 +119,24 @@ Options:
Make space for <number> reserve map entries
Relevant for dtb and asm output only.
+ -@
+ Generates a __symbols__ node at the root node of the resulting blob
+ for any node labels used, and for any local references using phandles
+ it also generates a __local_fixups__ node that tracks them.
+
+ When using the /plugin/ tag all unresolved label references to
+ be tracked in the __fixups__ node, making dynamic resolution possible.
+
+ -A
+ Generate automatically aliases for all node labels. This is similar to
+ the -@ option (the __symbols__ node contain identical information) but
+ the semantics are slightly different since no phandles are automatically
+ generated for labeled nodes.
+
+ -M
+ Generate blobs with the old FDT magic number for device tree objects.
+ By default blobs use the DTBO FDT magic number instead.
+
-S <bytes>
Ensure the blob at least <bytes> long, adding additional
space if needed.
@@ -146,13 +164,18 @@ Additionally, dtc performs various sanity checks on the tree.
Here is a very rough overview of the layout of a DTS source file:
- sourcefile: list_of_memreserve devicetree
+ sourcefile: versioninfo plugindecl list_of_memreserve devicetree
memreserve: label 'memreserve' ADDR ADDR ';'
| label 'memreserve' ADDR '-' ADDR ';'
devicetree: '/' nodedef
+ versioninfo: '/' 'dts-v1' '/' ';'
+
+ plugindecl: '/' 'plugin' '/' ';'
+ | /* empty */
+
nodedef: '{' list_of_property list_of_subnode '}' ';'
property: label PROPNAME '=' propdata ';'
diff --git a/checks.c b/checks.c
index 2bd27a4..4292f4b 100644
--- a/checks.c
+++ b/checks.c
@@ -487,8 +487,12 @@ static void fixup_phandle_references(struct check *c, struct boot_info *bi,
refnode = get_node_by_ref(dt, m->ref);
if (! refnode) {
- FAIL(c, "Reference to non-existent node or label \"%s\"\n",
- m->ref);
+ if (!(bi->versionflags & VF_PLUGIN))
+ FAIL(c, "Reference to non-existent node or "
+ "label \"%s\"\n", m->ref);
+ else /* mark the entry as unresolved */
+ *((cell_t *)(prop->val.val + m->offset)) =
+ cpu_to_fdt32(0xffffffff);
continue;
}
diff --git a/dtc-lexer.l b/dtc-lexer.l
index 790fbf6..40bbc87 100644
--- a/dtc-lexer.l
+++ b/dtc-lexer.l
@@ -121,6 +121,11 @@ static void lexical_error(const char *fmt, ...);
return DT_V1;
}
+<*>"/plugin/" {
+ DPRINT("Keyword: /plugin/\n");
+ return DT_PLUGIN;
+ }
+
<*>"/memreserve/" {
DPRINT("Keyword: /memreserve/\n");
BEGIN_DEFAULT();
diff --git a/dtc-parser.y b/dtc-parser.y
index 14aaf2e..1a1f660 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -19,6 +19,7 @@
*/
%{
#include <stdio.h>
+#include <inttypes.h>
#include "dtc.h"
#include "srcpos.h"
@@ -33,6 +34,7 @@ extern void yyerror(char const *s);
extern struct boot_info *the_boot_info;
extern bool treesource_error;
+
%}
%union {
@@ -52,9 +54,11 @@ extern bool treesource_error;
struct node *nodelist;
struct reserve_info *re;
uint64_t integer;
+ unsigned int flags;
}
%token DT_V1
+%token DT_PLUGIN
%token DT_MEMRESERVE
%token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
%token DT_BITS
@@ -71,6 +75,8 @@ extern bool treesource_error;
%type <data> propdata
%type <data> propdataprefix
+%type <flags> versioninfo
+%type <flags> plugindecl
%type <re> memreserve
%type <re> memreserves
%type <array> arrayprefix
@@ -101,16 +107,34 @@ extern bool treesource_error;
%%
sourcefile:
- v1tag memreserves devicetree
+ versioninfo plugindecl memreserves devicetree
+ {
+ the_boot_info = build_boot_info($1 | $2, $3, $4,
+ guess_boot_cpuid($4));
+ }
+ ;
+
+versioninfo:
+ v1tag
{
- the_boot_info = build_boot_info($2, $3,
- guess_boot_cpuid($3));
+ $$ = VF_DT_V1;
}
;
v1tag:
DT_V1 ';'
+ | DT_V1
| DT_V1 ';' v1tag
+
+plugindecl:
+ DT_PLUGIN ';'
+ {
+ $$ = VF_PLUGIN;
+ }
+ | /* empty */
+ {
+ $$ = 0;
+ }
;
memreserves:
@@ -161,10 +185,19 @@ devicetree:
{
struct node *target = get_node_by_ref($1, $2);
- if (target)
+ if (target) {
merge_nodes(target, $3);
- else
- ERROR(&@2, "Label or path %s not found", $2);
+ } else {
+ /*
+ * We rely on the rule being always:
+ * versioninfo plugindecl memreserves devicetree
+ * so $-1 is what we want (plugindecl)
+ */
+ if ($<flags>-1 & VF_PLUGIN)
+ add_orphan_node($1, $3, $2);
+ else
+ ERROR(&@2, "Label or path %s not found", $2);
+ }
$$ = $1;
}
| devicetree DT_DEL_NODE DT_REF ';'
@@ -179,6 +212,11 @@ devicetree:
$$ = $1;
}
+ | /* empty */
+ {
+ /* build empty node */
+ $$ = name_node(build_node(NULL, NULL), "");
+ }
;
nodedef:
diff --git a/dtc.c b/dtc.c
index 9dcf640..06e91bc 100644
--- a/dtc.c
+++ b/dtc.c
@@ -32,6 +32,9 @@ int minsize; /* Minimum blob size */
int padsize; /* Additional padding to blob */
int alignsize; /* Additional padding to blob accroding to the alignsize */
int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */
+int symbol_fixup_support; /* enable symbols & fixup support */
+int auto_label_aliases; /* auto generate labels -> aliases */
+int no_dtbo_magic; /* use old FDT magic values for objects */
static int is_power_of_2(int x)
{
@@ -59,7 +62,7 @@ static void fill_fullpaths(struct node *tree, const char *prefix)
#define FDT_VERSION(version) _FDT_VERSION(version)
#define _FDT_VERSION(version) #version
static const char usage_synopsis[] = "dtc [options] <input file>";
-static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:hv";
+static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@AMhv";
static struct option const usage_long_opts[] = {
{"quiet", no_argument, NULL, 'q'},
{"in-format", a_argument, NULL, 'I'},
@@ -78,6 +81,9 @@ static struct option const usage_long_opts[] = {
{"phandle", a_argument, NULL, 'H'},
{"warning", a_argument, NULL, 'W'},
{"error", a_argument, NULL, 'E'},
+ {"symbols", no_argument, NULL, '@'},
+ {"auto-alias", no_argument, NULL, 'A'},
+ {"no-dtbo-magic", no_argument, NULL, 'M'},
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'v'},
{NULL, no_argument, NULL, 0x0},
@@ -109,6 +115,9 @@ static const char * const usage_opts_help[] = {
"\t\tboth - Both \"linux,phandle\" and \"phandle\" properties",
"\n\tEnable/disable warnings (prefix with \"no-\")",
"\n\tEnable/disable errors (prefix with \"no-\")",
+ "\n\tEnable symbols/fixup support",
+ "\n\tEnable auto-alias of labels",
+ "\n\tDo not use DTBO magic value for plugin objects",
"\n\tPrint this help and exit",
"\n\tPrint version and exit",
NULL,
@@ -153,7 +162,7 @@ static const char *guess_input_format(const char *fname, const char *fallback)
fclose(f);
magic = fdt32_to_cpu(magic);
- if (magic == FDT_MAGIC)
+ if (magic == FDT_MAGIC || magic == FDT_MAGIC_DTBO)
return "dtb";
return guess_type_by_name(fname, fallback);
@@ -172,6 +181,7 @@ int main(int argc, char *argv[])
FILE *outf = NULL;
int outversion = DEFAULT_FDT_VERSION;
long long cmdline_boot_cpuid = -1;
+ fdt32_t out_magic = FDT_MAGIC;
quiet = 0;
reservenum = 0;
@@ -249,6 +259,16 @@ int main(int argc, char *argv[])
parse_checks_option(false, true, optarg);
break;
+ case '@':
+ symbol_fixup_support = 1;
+ break;
+ case 'A':
+ auto_label_aliases = 1;
+ break;
+ case 'M':
+ no_dtbo_magic = 1;
+ break;
+
case 'h':
usage(NULL);
default:
@@ -306,6 +326,14 @@ int main(int argc, char *argv[])
fill_fullpaths(bi->dt, "");
process_checks(force, bi);
+ if (auto_label_aliases)
+ generate_label_tree(bi->dt, "aliases", false);
+
+ if (symbol_fixup_support) {
+ generate_label_tree(bi->dt, "__symbols__", true);
+ generate_fixups_tree(bi->dt);
+ }
+
if (sort)
sort_tree(bi);
@@ -318,12 +346,15 @@ int main(int argc, char *argv[])
outname, strerror(errno));
}
+ if (!no_dtbo_magic && (bi->versionflags & VF_PLUGIN))
+ out_magic = FDT_MAGIC_DTBO;
+
if (streq(outform, "dts")) {
dt_to_source(outf, bi);
} else if (streq(outform, "dtb")) {
- dt_to_blob(outf, bi, outversion);
+ dt_to_blob(outf, bi, out_magic, outversion);
} else if (streq(outform, "asm")) {
- dt_to_asm(outf, bi, outversion);
+ dt_to_asm(outf, bi, out_magic, outversion);
} else if (streq(outform, "null")) {
/* do nothing */
} else {
diff --git a/dtc.h b/dtc.h
index 32009bc..581b3bf 100644
--- a/dtc.h
+++ b/dtc.h
@@ -55,6 +55,9 @@ extern int minsize; /* Minimum blob size */
extern int padsize; /* Additional padding to blob */
extern int alignsize; /* Additional padding to blob accroding to the alignsize */
extern int phandle_format; /* Use linux,phandle or phandle properties */
+extern int symbol_fixup_support;/* enable symbols & fixup support */
+extern int auto_label_aliases; /* auto generate labels -> aliases */
+extern int no_dtbo_magic; /* use old FDT magic values for objects */
#define PHANDLE_LEGACY 0x1
#define PHANDLE_EPAPR 0x2
@@ -195,6 +198,7 @@ struct node *build_node_delete(void);
struct node *name_node(struct node *node, char *name);
struct node *chain_node(struct node *first, struct node *list);
struct node *merge_nodes(struct node *old_node, struct node *new_node);
+void add_orphan_node(struct node *old_node, struct node *new_node, char *ref);
void add_property(struct node *node, struct property *prop);
void delete_property_by_name(struct node *node, char *name);
@@ -202,6 +206,8 @@ void delete_property(struct property *prop);
void add_child(struct node *parent, struct node *child);
void delete_node_by_name(struct node *parent, char *name);
void delete_node(struct node *node);
+void append_to_property(struct node *node,
+ char *name, const void *data, int len);
const char *get_unitname(struct node *node);
struct property *get_property(struct node *node, const char *propname);
@@ -237,14 +243,22 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
struct boot_info {
+ unsigned int versionflags;
struct reserve_info *reservelist;
struct node *dt; /* the device tree */
uint32_t boot_cpuid_phys;
};
-struct boot_info *build_boot_info(struct reserve_info *reservelist,
+/* version flags definitions */
+#define VF_DT_V1 0x0001 /* /dts-v1/ */
+#define VF_PLUGIN 0x0002 /* /plugin/ */
+
+struct boot_info *build_boot_info(unsigned int versionflags,
+ struct reserve_info *reservelist,
struct node *tree, uint32_t boot_cpuid_phys);
void sort_tree(struct boot_info *bi);
+void generate_label_tree(struct node *dt, char *gen_node_name, bool allocph);
+void generate_fixups_tree(struct node *dt);
/* Checks */
@@ -253,8 +267,8 @@ void process_checks(bool force, struct boot_info *bi);
/* Flattened trees */
-void dt_to_blob(FILE *f, struct boot_info *bi, int version);
-void dt_to_asm(FILE *f, struct boot_info *bi, int version);
+void dt_to_blob(FILE *f, struct boot_info *bi, fdt32_t magic, int version);
+void dt_to_asm(FILE *f, struct boot_info *bi, fdt32_t magic, int version);
struct boot_info *dt_from_blob(const char *fname);
diff --git a/fdtdump.c b/fdtdump.c
index a9a2484..dd63ac2 100644
--- a/fdtdump.c
+++ b/fdtdump.c
@@ -201,7 +201,7 @@ int main(int argc, char *argv[])
p = memchr(p, smagic[0], endp - p - FDT_MAGIC_SIZE);
if (!p)
break;
- if (fdt_magic(p) == FDT_MAGIC) {
+ if (fdt_magic(p) == FDT_MAGIC || fdt_magic(p) == FDT_MAGIC_DTBO) {
/* try and validate the main struct */
off_t this_len = endp - p;
fdt32_t max_version = 17;
diff --git a/flattree.c b/flattree.c
index a9d9520..57d76cf 100644
--- a/flattree.c
+++ b/flattree.c
@@ -335,6 +335,7 @@ static struct data flatten_reserve_list(struct reserve_info *reservelist,
}
static void make_fdt_header(struct fdt_header *fdt,
+ fdt32_t magic,
struct version_info *vi,
int reservesize, int dtsize, int strsize,
int boot_cpuid_phys)
@@ -345,7 +346,7 @@ static void make_fdt_header(struct fdt_header *fdt,
memset(fdt, 0xff, sizeof(*fdt));
- fdt->magic = cpu_to_fdt32(FDT_MAGIC);
+ fdt->magic = cpu_to_fdt32(magic);
fdt->version = cpu_to_fdt32(vi->version);
fdt->last_comp_version = cpu_to_fdt32(vi->last_comp_version);
@@ -366,7 +367,7 @@ static void make_fdt_header(struct fdt_header *fdt,
fdt->size_dt_struct = cpu_to_fdt32(dtsize);
}
-void dt_to_blob(FILE *f, struct boot_info *bi, int version)
+void dt_to_blob(FILE *f, struct boot_info *bi, fdt32_t magic, int version)
{
struct version_info *vi = NULL;
int i;
@@ -390,7 +391,7 @@ void dt_to_blob(FILE *f, struct boot_info *bi, int version)
reservebuf = flatten_reserve_list(bi->reservelist, vi);
/* Make header */
- make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len,
+ make_fdt_header(&fdt, magic, vi, reservebuf.len, dtbuf.len, strbuf.len,
bi->boot_cpuid_phys);
/*
@@ -467,7 +468,7 @@ static void dump_stringtable_asm(FILE *f, struct data strbuf)
}
}
-void dt_to_asm(FILE *f, struct boot_info *bi, int version)
+void dt_to_asm(FILE *f, struct boot_info *bi, fdt32_t magic, int version)
{
struct version_info *vi = NULL;
int i;
@@ -830,6 +831,7 @@ struct boot_info *dt_from_blob(const char *fname)
struct node *tree;
uint32_t val;
int flags = 0;
+ unsigned int versionflags = VF_DT_V1;
f = srcfile_relative_open(fname, NULL);
@@ -845,9 +847,12 @@ struct boot_info *dt_from_blob(const char *fname)
}
magic = fdt32_to_cpu(magic);
- if (magic != FDT_MAGIC)
+ if (magic != FDT_MAGIC && magic != FDT_MAGIC_DTBO)
die("Blob has incorrect magic number\n");
+ if (magic == FDT_MAGIC_DTBO)
+ versionflags |= VF_PLUGIN;
+
rc = fread(&totalsize, sizeof(totalsize), 1, f);
if (ferror(f))
die("Error reading DT blob size: %s\n", strerror(errno));
@@ -942,5 +947,5 @@ struct boot_info *dt_from_blob(const char *fname)
fclose(f);
- return build_boot_info(reservelist, tree, boot_cpuid_phys);
+ return build_boot_info(versionflags, reservelist, tree, boot_cpuid_phys);
}
diff --git a/fstree.c b/fstree.c
index 6d1beec..54f520b 100644
--- a/fstree.c
+++ b/fstree.c
@@ -86,6 +86,6 @@ struct boot_info *dt_from_fs(const char *dirname)
tree = read_fstree(dirname);
tree = name_node(tree, "");
- return build_boot_info(NULL, tree, guess_boot_cpuid(tree));
+ return build_boot_info(VF_DT_V1, NULL, tree, guess_boot_cpuid(tree));
}
diff --git a/libfdt/fdt.c b/libfdt/fdt.c
index 22286a1..28d422c 100644
--- a/libfdt/fdt.c
+++ b/libfdt/fdt.c
@@ -57,7 +57,7 @@
int fdt_check_header(const void *fdt)
{
- if (fdt_magic(fdt) == FDT_MAGIC) {
+ if (fdt_magic(fdt) == FDT_MAGIC || fdt_magic(fdt) == FDT_MAGIC_DTBO) {
/* Complete tree */
if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
return -FDT_ERR_BADVERSION;
diff --git a/libfdt/fdt.h b/libfdt/fdt.h
index 526aedb..493cd55 100644
--- a/libfdt/fdt.h
+++ b/libfdt/fdt.h
@@ -55,7 +55,7 @@
#ifndef __ASSEMBLY__
struct fdt_header {
- fdt32_t magic; /* magic word FDT_MAGIC */
+ fdt32_t magic; /* magic word FDT_MAGIC[|_DTBO] */
fdt32_t totalsize; /* total size of DT block */
fdt32_t off_dt_struct; /* offset to structure */
fdt32_t off_dt_strings; /* offset to strings */
@@ -93,6 +93,7 @@ struct fdt_property {
#endif /* !__ASSEMBLY */
#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */
+#define FDT_MAGIC_DTBO 0xd00dfdb0 /* DTBO magic */
#define FDT_TAGSIZE sizeof(fdt32_t)
#define FDT_BEGIN_NODE 0x1 /* Start node: full name */
diff --git a/livetree.c b/livetree.c
index 3dc7559..f2c86bd 100644
--- a/livetree.c
+++ b/livetree.c
@@ -216,6 +216,31 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
return old_node;
}
+void add_orphan_node(struct node *dt, struct node *new_node, char *ref)
+{
+ static unsigned int next_orphan_fragment = 0;
+ struct node *node = build_node(NULL, NULL);
+ struct property *p;
+ struct data d = empty_data;
+ char *name;
+
+ memset(node, 0, sizeof(*node));
+
+ d = data_add_marker(d, REF_PHANDLE, ref);
+ d = data_append_integer(d, 0xffffffff, 32);
+
+ p = build_property("target", d);
+ add_property(node, p);
+
+ xasprintf(&name, "fragment@%u",
+ next_orphan_fragment++);
+ name_node(node, name);
+ name_node(new_node, "__overlay__");
+
+ add_child(dt, node);
+ add_child(node, new_node);
+}
+
struct node *chain_node(struct node *first, struct node *list)
{
assert(first->next_sibling == NULL);
@@ -296,6 +321,23 @@ void delete_node(struct node *node)
delete_labels(&node->labels);
}
+void append_to_property(struct node *node,
+ char *name, const void *data, int len)
+{
+ struct data d;
+ struct property *p;
+
+ p = get_property(node, name);
+ if (p) {
+ d = data_append_data(p->val, data, len);
+ p->val = d;
+ } else {
+ d = data_append_data(empty_data, data, len);
+ p = build_property(name, d);
+ add_property(node, p);
+ }
+}
+
struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size)
{
struct reserve_info *new = xmalloc(sizeof(*new));
@@ -335,12 +377,14 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
return list;
}
-struct boot_info *build_boot_info(struct reserve_info *reservelist,
+struct boot_info *build_boot_info(unsigned int versionflags,
+ struct reserve_info *reservelist,
struct node *tree, uint32_t boot_cpuid_phys)
{
struct boot_info *bi;
bi = xmalloc(sizeof(*bi));
+ bi->versionflags = versionflags;
bi->reservelist = reservelist;
bi->dt = tree;
bi->boot_cpuid_phys = boot_cpuid_phys;
@@ -709,3 +753,182 @@ void sort_tree(struct boot_info *bi)
sort_reserve_entries(bi);
sort_node(bi->dt);
}
+
+/* utility helper to avoid code duplication */
+static struct node *build_and_name_child_node(struct node *parent, char *name)
+{
+ struct node *node;
+
+ node = build_node(NULL, NULL);
+ name_node(node, xstrdup(name));
+ add_child(parent, node);
+
+ return node;
+}
+
+static void generate_label_tree_internal(struct node *dt, struct node *node,
+ struct node *an, bool allocph)
+{
+ struct node *c;
+ struct property *p;
+ struct label *l;
+
+ /* if if there are labels */
+ if (node->labels) {
+ /* now add the label in the node */
+ for_each_label(node->labels, l) {
+ /* check whether the label already exists */
+ p = get_property(an, l->label);
+ if (p) {
+ fprintf(stderr, "WARNING: label %s already"
+ " exists in /%s", l->label,
+ an->name);
+ continue;
+ }
+
+ /* insert it */
+ p = build_property(l->label,
+ data_copy_mem(node->fullpath,
+ strlen(node->fullpath) + 1));
+ add_property(an, p);
+ }
+
+ /* force allocation of a phandle for this node */
+ if (allocph)
+ (void)get_node_phandle(dt, node);
+ }
+
+ for_each_child(node, c)
+ generate_label_tree_internal(dt, c, an, allocph);
+}
+
+void generate_label_tree(struct node *dt, char *gen_node_name, bool allocph)
+{
+ struct node *an;
+
+ for_each_child(dt, an)
+ if (streq(gen_node_name, an->name))
+ break;
+
+ if (!an)
+ an = build_and_name_child_node(dt, gen_node_name);
+ if (!an)
+ die("Could not build label node /%s\n", gen_node_name);
+
+ generate_label_tree_internal(dt, dt, an, allocph);
+}
+
+#define FIXUPS "__fixups__"
+#define LOCAL_FIXUPS "__local_fixups__"
+
+static void add_fixup_entry(struct node *dt, struct node *node,
+ struct property *prop, struct marker *m)
+{
+ struct node *fn; /* fixup node */
+ char *entry;
+
+ /* m->ref can only be a REF_PHANDLE, but check anyway */
+ assert(m->type == REF_PHANDLE);
+
+ /* fn is the node we're putting entries in */
+ fn = get_subnode(dt, FIXUPS);
+ assert(fn != NULL);
+
+ /* there shouldn't be any ':' in the arguments */
+ if (strchr(node->fullpath, ':') || strchr(prop->name, ':'))
+ die("arguments should not contain ':'\n");
+
+ xasprintf(&entry, "%s:%s:%u",
+ node->fullpath, prop->name, m->offset);
+ append_to_property(fn, m->ref, entry, strlen(entry) + 1);
+}
+
+static void add_local_fixup_entry(struct node *dt, struct node *node,
+ struct property *prop, struct marker *m,
+ struct node *refnode)
+{
+ struct node *lfn, *wn, *nwn; /* local fixup node, walk node, new */
+ uint32_t value_32;
+ char *s, *e, *comp;
+ int len;
+
+ /* fn is the node we're putting entries in */
+ lfn = get_subnode(dt, LOCAL_FIXUPS);
+ assert(lfn != NULL);
+
+ /* walk the path components creating nodes if they don't exist */
+ comp = xmalloc(strlen(node->fullpath) + 1);
+ /* start skipping the first / */
+ s = node->fullpath + 1;
+ wn = lfn;
+ while (*s) {
+ /* retrieve path component */
+ e = strchr(s, '/');
+ if (e == NULL)
+ e = s + strlen(s);
+ len = e - s;
+ memcpy(comp, s, len);
+ comp[len] = '\0';
+
+ /* if no node exists, create it */
+ nwn = get_subnode(wn, comp);
+ if (!nwn)
+ nwn = build_and_name_child_node(wn, comp);
+ wn = nwn;
+
+ /* last path component */
+ if (!*e)
+ break;
+
+ /* next path component */
+ s = e + 1;
+ }
+ free(comp);
+
+ value_32 = cpu_to_fdt32(m->offset);
+ append_to_property(wn, prop->name, &value_32, sizeof(value_32));
+}
+
+static void generate_fixups_tree_internal(struct node *dt, struct node *node)
+{
+ struct node *c;
+ struct property *prop;
+ struct marker *m;
+ struct node *refnode;
+
+ for_each_property(node, prop) {
+ m = prop->val.markers;
+ for_each_marker_of_type(m, REF_PHANDLE) {
+ refnode = get_node_by_ref(dt, m->ref);
+ if (!refnode)
+ add_fixup_entry(dt, node, prop, m);
+ else
+ add_local_fixup_entry(dt, node, prop, m,
+ refnode);
+ }
+ }
+
+ for_each_child(node, c)
+ generate_fixups_tree_internal(dt, c);
+}
+
+void generate_fixups_tree(struct node *dt)
+{
+ struct node *an;
+
+ for_each_child(dt, an)
+ if (streq(FIXUPS, an->name))
+ break;
+
+ if (!an)
+ build_and_name_child_node(dt, FIXUPS);
+
+ for_each_child(dt, an)
+ if (streq(LOCAL_FIXUPS, an->name))
+ break;
+
+ if (!an)
+ build_and_name_child_node(dt, LOCAL_FIXUPS);
+
+ generate_fixups_tree_internal(dt, dt);
+}
diff --git a/tests/mangle-layout.c b/tests/mangle-layout.c
index a76e51e..d29ebc6 100644
--- a/tests/mangle-layout.c
+++ b/tests/mangle-layout.c
@@ -42,7 +42,8 @@ static void expand_buf(struct bufstate *buf, int newsize)
buf->size = newsize;
}
-static void new_header(struct bufstate *buf, int version, const void *fdt)
+static void new_header(struct bufstate *buf, fdt32_t magic, int version,
+ const void *fdt)
{
int hdrsize;
@@ -56,7 +57,7 @@ static void new_header(struct bufstate *buf, int version, const void *fdt)
expand_buf(buf, hdrsize);
memset(buf->buf, 0, hdrsize);
- fdt_set_magic(buf->buf, FDT_MAGIC);
+ fdt_set_magic(buf->buf, magic);
fdt_set_version(buf->buf, version);
fdt_set_last_comp_version(buf->buf, 16);
fdt_set_boot_cpuid_phys(buf->buf, fdt_boot_cpuid_phys(fdt));
@@ -145,7 +146,7 @@ int main(int argc, char *argv[])
if (fdt_version(fdt) < 17)
CONFIG("Input tree must be v17");
- new_header(&buf, version, fdt);
+ new_header(&buf, FDT_MAGIC, version, fdt);
while (*blockorder) {
add_block(&buf, version, *blockorder, fdt);
--
2.1.4
^ permalink raw reply related
* [PATCH v10 2/4] dtc: Document the dynamic plugin internals
From: Pantelis Antoniou @ 2016-11-25 12:32 UTC (permalink / raw)
To: David Gibson
Cc: Jon Loeliger, Grant Likely, Frank Rowand, Rob Herring, Jan Luebbe,
Sascha Hauer, Phil Elwell, Simon Glass, Maxime Ripard,
Thomas Petazzoni, Boris Brezillon, Antoine Tenart, Stephen Boyd,
Devicetree Compiler, devicetree-u79uwXL29TY76Z2rM5mHXA,
Pantelis Antoniou
In-Reply-To: <1480077131-14526-1-git-send-email-pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
Provides the document explaining the internal mechanics of
plugins and options.
Signed-off-by: Pantelis Antoniou <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
---
Documentation/dt-object-internal.txt | 318 +++++++++++++++++++++++++++++++++++
1 file changed, 318 insertions(+)
create mode 100644 Documentation/dt-object-internal.txt
diff --git a/Documentation/dt-object-internal.txt b/Documentation/dt-object-internal.txt
new file mode 100644
index 0000000..d5b841e
--- /dev/null
+++ b/Documentation/dt-object-internal.txt
@@ -0,0 +1,318 @@
+Device Tree Dynamic Object format internals
+-------------------------------------------
+
+The Device Tree for most platforms is a static representation of
+the hardware capabilities. This is insufficient for many platforms
+that need to dynamically insert device tree fragments to the
+running kernel's live tree.
+
+This document explains the the device tree object format and the
+modifications made to the device tree compiler, which make it possible.
+
+1. Simplified Problem Definition
+--------------------------------
+
+Assume we have a platform which boots using following simplified device tree.
+
+---- foo.dts -----------------------------------------------------------------
+ /* FOO platform */
+ / {
+ compatible = "corp,foo";
+
+ /* shared resources */
+ res: res {
+ };
+
+ /* On chip peripherals */
+ ocp: ocp {
+ /* peripherals that are always instantiated */
+ peripheral1 { ... };
+ };
+ };
+---- foo.dts -----------------------------------------------------------------
+
+We have a number of peripherals that after probing (using some undefined method)
+should result in different device tree configuration.
+
+We cannot boot with this static tree because due to the configuration of the
+foo platform there exist multiple conficting peripherals DT fragments.
+
+So for the bar peripheral we would have this:
+
+---- foo+bar.dts -------------------------------------------------------------
+ /* FOO platform + bar peripheral */
+ / {
+ compatible = "corp,foo";
+
+ /* shared resources */
+ res: res {
+ };
+
+ /* On chip peripherals */
+ ocp: ocp {
+ /* peripherals that are always instantiated */
+ peripheral1 { ... };
+
+ /* bar peripheral */
+ bar {
+ compatible = "corp,bar";
+ ... /* various properties and child nodes */
+ };
+ };
+ };
+---- foo+bar.dts -------------------------------------------------------------
+
+While for the baz peripheral we would have this:
+
+---- foo+baz.dts -------------------------------------------------------------
+ /* FOO platform + baz peripheral */
+ / {
+ compatible = "corp,foo";
+
+ /* shared resources */
+ res: res {
+ /* baz resources */
+ baz_res: res_baz { ... };
+ };
+
+ /* On chip peripherals */
+ ocp: ocp {
+ /* peripherals that are always instantiated */
+ peripheral1 { ... };
+
+ /* baz peripheral */
+ baz {
+ compatible = "corp,baz";
+ /* reference to another point in the tree */
+ ref-to-res = <&baz_res>;
+ ... /* various properties and child nodes */
+ };
+ };
+ };
+---- foo+baz.dts -------------------------------------------------------------
+
+We note that the baz case is more complicated, since the baz peripheral needs to
+reference another node in the DT tree.
+
+2. Device Tree Object Format Requirements
+-----------------------------------------
+
+Since the device tree is used for booting a number of very different hardware
+platforms it is imperative that we tread very carefully.
+
+2.a) No changes to the Device Tree binary format for the base tree. We cannot
+modify the tree format at all and all the information we require should be
+encoded using device tree itself. We can add nodes that can be safely ignored
+by both bootloaders and the kernel. The plugin dtb's are optionally tagged
+with a different magic number in the header but otherwise they too are simple
+blobs.
+
+2.b) Changes to the DTS source format should be absolutely minimal, and should
+only be needed for the DT fragment definitions, and not the base boot DT.
+
+2.c) An explicit option should be used to instruct DTC to generate the required
+information needed for object resolution. Platforms that don't use the
+dynamic object format can safely ignore it.
+
+2.d) Finally, DT syntax changes should be kept to a minimum. It should be
+possible to express everything using the existing DT syntax.
+
+3. Implementation
+-----------------
+
+The basic unit of addressing in Device Tree is the phandle. Turns out it's
+relatively simple to extend the way phandles are generated and referenced
+so that it's possible to dynamically convert symbolic references (labels)
+to phandle values. This is a valid assumption as long as the author uses
+reference syntax and does not assign phandle values manually (which might
+be a problem with decompiled source files).
+
+We can roughly divide the operation into two steps.
+
+3.a) Compilation of the base board DTS file using the '-@' option
+generates a valid DT blob with an added __symbols__ node at the root node,
+containing a list of all nodes that are marked with a label.
+
+Using the foo.dts file above the following node will be generated;
+
+$ dtc -@ -O dtb -o foo.dtb -b 0 foo.dts
+$ fdtdump foo.dtb
+...
+/ {
+ ...
+ res {
+ ...
+ phandle = <0x00000001>;
+ ...
+ };
+ ocp {
+ ...
+ phandle = <0x00000002>;
+ ...
+ };
+ __symbols__ {
+ res="/res";
+ ocp="/ocp";
+ };
+};
+
+Notice that all the nodes that had a label have been recorded, and that
+phandles have been generated for them.
+
+This blob can be used to boot the board normally, the __symbols__ node will
+be safely ignored both by the bootloader and the kernel (the only loss will
+be a few bytes of memory and disk space).
+
+3.b) The Device Tree fragments must be compiled with the same option but they
+must also have a tag (/plugin/) that allows undefined references to nodes
+that are not present at compilation time to be recorded so that the runtime
+loader can fix them.
+
+So the bar peripheral's DTS format would be of the form:
+
+/dts-v1/ /plugin/; /* allow undefined references and record them */
+/ {
+ .... /* various properties for loader use; i.e. part id etc. */
+ fragment@0 {
+ target = <&ocp>;
+ __overlay__ {
+ /* bar peripheral */
+ bar {
+ compatible = "corp,bar";
+ ... /* various properties and child nodes */
+ }
+ };
+ };
+};
+
+Note that there's a target property that specifies the location where the
+contents of the overlay node will be placed, and it references the node
+in the foo.dts file.
+
+$ dtc -@ -O dtb -o bar.dtbo -b 0 bar.dts
+$ fdtdump bar.dtbo
+...
+/ {
+ ... /* properties */
+ fragment@0 {
+ target = <0xffffffff>;
+ __overlay__ {
+ bar {
+ compatible = "corp,bar";
+ ... /* various properties and child nodes */
+ }
+ };
+ };
+ __fixups__ {
+ ocp = "/fragment@0:target:0";
+ };
+};
+
+No __symbols__ has been generated (no label in bar.dts).
+Note that the target's ocp label is undefined, so the phandle handle
+value is filled with the illegal value '0xffffffff', while a __fixups__
+node has been generated, which marks the location in the tree where
+the label lookup should store the runtime phandle value of the ocp node.
+
+The format of the __fixups__ node entry is
+
+ <label> = "<local-full-path>:<property-name>:<offset>";
+
+<label> Is the label we're referring
+<local-full-path> Is the full path of the node the reference is
+<property-name> Is the name of the property containing the
+ reference
+<offset> The offset (in bytes) of where the property's
+ phandle value is located.
+
+Doing the same with the baz peripheral's DTS format is a little bit more
+involved, since baz contains references to local labels which require
+local fixups.
+
+/dts-v1/ /plugin/; /* allow undefined label references and record them */
+/ {
+ .... /* various properties for loader use; i.e. part id etc. */
+ fragment@0 {
+ target = <&res>;
+ __overlay__ {
+ /* baz resources */
+ baz_res: res_baz { ... };
+ };
+ };
+ fragment@1 {
+ target = <&ocp>;
+ __overlay__ {
+ /* baz peripheral */
+ baz {
+ compatible = "corp,baz";
+ /* reference to another point in the tree */
+ ref-to-res = <&baz_res>;
+ ... /* various properties and child nodes */
+ }
+ };
+ };
+};
+
+Note that &bar_res reference.
+
+$ dtc -@ -O dtb -o baz.dtbo -b 0 baz.dts
+$ fdtdump baz.dtbo
+...
+/ {
+ ... /* properties */
+ fragment@0 {
+ target = <0xffffffff>;
+ __overlay__ {
+ res_baz {
+ ....
+ phandle = <0x00000001>;
+ };
+ };
+ };
+ fragment@1 {
+ target = <0xffffffff>;
+ __overlay__ {
+ baz {
+ compatible = "corp,baz";
+ ... /* various properties and child nodes */
+ ref-to-res = <0x00000001>;
+ }
+ };
+ };
+ __fixups__ {
+ res = "/fragment@0:target:0";
+ ocp = "/fragment@1:target:0";
+ };
+ __local_fixups__ {
+ fragment@1 {
+ __overlay__ {
+ baz {
+ ref-to-res = <0>;
+ };
+ };
+ };
+ };
+};
+
+This is similar to the bar case, but the reference of a local label by the
+baz node generates a __local_fixups__ entry that records the place that the
+local reference is being made. No matter how phandles are allocated from dtc
+the run time loader must apply an offset to each phandle in every dynamic
+DT object loaded. The __local_fixups__ node records the place of every
+local reference so that the loader can apply the offset.
+
+There is an alternative syntax to the expanded form for overlays with phandle
+targets which makes the format similar to the one using in .dtsi include files.
+
+So for the &ocp target example above one can simply write:
+
+/dts-v1/ /plugin/;
+&ocp {
+ /* bar peripheral */
+ bar {
+ compatible = "corp,bar";
+ ... /* various properties and child nodes */
+ }
+};
+
+The resulting dtb object is identical.
--
2.1.4
^ permalink raw reply related
* [PATCH v10 1/4] checks: Pass boot_info instead of root node
From: Pantelis Antoniou @ 2016-11-25 12:32 UTC (permalink / raw)
To: David Gibson
Cc: Jon Loeliger, Grant Likely, Frank Rowand, Rob Herring, Jan Luebbe,
Sascha Hauer, Phil Elwell, Simon Glass, Maxime Ripard,
Thomas Petazzoni, Boris Brezillon, Antoine Tenart, Stephen Boyd,
Devicetree Compiler, devicetree-u79uwXL29TY76Z2rM5mHXA,
Pantelis Antoniou
In-Reply-To: <1480077131-14526-1-git-send-email-pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
As preparation for overlay support we need to pass the boot info
parameter instead of the root node to each check method.
The root node can be retrieved by accessing boot info's dt member.
No other functional changes are made.
Signed-off-by: Pantelis Antoniou <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
---
checks.c | 78 ++++++++++++++++++++++++++++++++++------------------------------
1 file changed, 42 insertions(+), 36 deletions(-)
diff --git a/checks.c b/checks.c
index 0381c98..2bd27a4 100644
--- a/checks.c
+++ b/checks.c
@@ -40,7 +40,7 @@ enum checkstatus {
struct check;
-typedef void (*check_fn)(struct check *c, struct node *dt, struct node *node);
+typedef void (*check_fn)(struct check *c, struct boot_info *bi, struct node *node);
struct check {
const char *name;
@@ -97,20 +97,21 @@ static inline void check_msg(struct check *c, const char *fmt, ...)
check_msg((c), __VA_ARGS__); \
} while (0)
-static void check_nodes_props(struct check *c, struct node *dt, struct node *node)
+static void check_nodes_props(struct check *c, struct boot_info *bi, struct node *node)
{
struct node *child;
TRACE(c, "%s", node->fullpath);
if (c->fn)
- c->fn(c, dt, node);
+ c->fn(c, bi, node);
for_each_child(node, child)
- check_nodes_props(c, dt, child);
+ check_nodes_props(c, bi, child);
}
-static bool run_check(struct check *c, struct node *dt)
+static bool run_check(struct check *c, struct boot_info *bi)
{
+ struct node *dt = bi->dt;
bool error = false;
int i;
@@ -123,7 +124,7 @@ static bool run_check(struct check *c, struct node *dt)
for (i = 0; i < c->num_prereqs; i++) {
struct check *prq = c->prereq[i];
- error = error || run_check(prq, dt);
+ error = error || run_check(prq, bi);
if (prq->status != PASSED) {
c->status = PREREQ;
check_msg(c, "Failed prerequisite '%s'",
@@ -134,7 +135,7 @@ static bool run_check(struct check *c, struct node *dt)
if (c->status != UNCHECKED)
goto out;
- check_nodes_props(c, dt, dt);
+ check_nodes_props(c, bi, dt);
if (c->status == UNCHECKED)
c->status = PASSED;
@@ -153,14 +154,14 @@ out:
*/
/* A check which always fails, for testing purposes only */
-static inline void check_always_fail(struct check *c, struct node *dt,
+static inline void check_always_fail(struct check *c, struct boot_info *bi,
struct node *node)
{
FAIL(c, "always_fail check");
}
CHECK(always_fail, check_always_fail, NULL);
-static void check_is_string(struct check *c, struct node *root,
+static void check_is_string(struct check *c, struct boot_info *bi,
struct node *node)
{
struct property *prop;
@@ -179,7 +180,7 @@ static void check_is_string(struct check *c, struct node *root,
#define ERROR_IF_NOT_STRING(nm, propname) \
ERROR(nm, check_is_string, (propname))
-static void check_is_cell(struct check *c, struct node *root,
+static void check_is_cell(struct check *c, struct boot_info *bi,
struct node *node)
{
struct property *prop;
@@ -202,7 +203,7 @@ static void check_is_cell(struct check *c, struct node *root,
* Structural check functions
*/
-static void check_duplicate_node_names(struct check *c, struct node *dt,
+static void check_duplicate_node_names(struct check *c, struct boot_info *bi,
struct node *node)
{
struct node *child, *child2;
@@ -217,7 +218,7 @@ static void check_duplicate_node_names(struct check *c, struct node *dt,
}
ERROR(duplicate_node_names, check_duplicate_node_names, NULL);
-static void check_duplicate_property_names(struct check *c, struct node *dt,
+static void check_duplicate_property_names(struct check *c, struct boot_info *bi,
struct node *node)
{
struct property *prop, *prop2;
@@ -239,7 +240,7 @@ ERROR(duplicate_property_names, check_duplicate_property_names, NULL);
#define DIGITS "0123456789"
#define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-"
-static void check_node_name_chars(struct check *c, struct node *dt,
+static void check_node_name_chars(struct check *c, struct boot_info *bi,
struct node *node)
{
int n = strspn(node->name, c->data);
@@ -250,7 +251,7 @@ static void check_node_name_chars(struct check *c, struct node *dt,
}
ERROR(node_name_chars, check_node_name_chars, PROPNODECHARS "@");
-static void check_node_name_format(struct check *c, struct node *dt,
+static void check_node_name_format(struct check *c, struct boot_info *bi,
struct node *node)
{
if (strchr(get_unitname(node), '@'))
@@ -259,8 +260,8 @@ static void check_node_name_format(struct check *c, struct node *dt,
}
ERROR(node_name_format, check_node_name_format, NULL, &node_name_chars);
-static void check_unit_address_vs_reg(struct check *c, struct node *dt,
- struct node *node)
+static void check_unit_address_vs_reg(struct check *c, struct boot_info *bi,
+ struct node *node)
{
const char *unitname = get_unitname(node);
struct property *prop = get_property(node, "reg");
@@ -283,7 +284,7 @@ static void check_unit_address_vs_reg(struct check *c, struct node *dt,
}
WARNING(unit_address_vs_reg, check_unit_address_vs_reg, NULL);
-static void check_property_name_chars(struct check *c, struct node *dt,
+static void check_property_name_chars(struct check *c, struct boot_info *bi,
struct node *node)
{
struct property *prop;
@@ -305,10 +306,11 @@ ERROR(property_name_chars, check_property_name_chars, PROPNODECHARS);
((prop) ? (prop)->name : ""), \
((prop) ? "' in " : ""), (node)->fullpath
-static void check_duplicate_label(struct check *c, struct node *dt,
+static void check_duplicate_label(struct check *c, struct boot_info *bi,
const char *label, struct node *node,
struct property *prop, struct marker *mark)
{
+ struct node *dt = bi->dt;
struct node *othernode = NULL;
struct property *otherprop = NULL;
struct marker *othermark = NULL;
@@ -331,30 +333,31 @@ static void check_duplicate_label(struct check *c, struct node *dt,
DESCLABEL_ARGS(othernode, otherprop, othermark));
}
-static void check_duplicate_label_node(struct check *c, struct node *dt,
+static void check_duplicate_label_node(struct check *c, struct boot_info *bi,
struct node *node)
{
struct label *l;
struct property *prop;
for_each_label(node->labels, l)
- check_duplicate_label(c, dt, l->label, node, NULL, NULL);
+ check_duplicate_label(c, bi, l->label, node, NULL, NULL);
for_each_property(node, prop) {
struct marker *m = prop->val.markers;
for_each_label(prop->labels, l)
- check_duplicate_label(c, dt, l->label, node, prop, NULL);
+ check_duplicate_label(c, bi, l->label, node, prop, NULL);
for_each_marker_of_type(m, LABEL)
- check_duplicate_label(c, dt, m->ref, node, prop, m);
+ check_duplicate_label(c, bi, m->ref, node, prop, m);
}
}
ERROR(duplicate_label, check_duplicate_label_node, NULL);
-static cell_t check_phandle_prop(struct check *c, struct node *root,
+static cell_t check_phandle_prop(struct check *c, struct boot_info *bi,
struct node *node, const char *propname)
{
+ struct node *root = bi->dt;
struct property *prop;
struct marker *m;
cell_t phandle;
@@ -398,18 +401,19 @@ static cell_t check_phandle_prop(struct check *c, struct node *root,
return phandle;
}
-static void check_explicit_phandles(struct check *c, struct node *root,
+static void check_explicit_phandles(struct check *c, struct boot_info *bi,
struct node *node)
{
+ struct node *root = bi->dt;
struct node *other;
cell_t phandle, linux_phandle;
/* Nothing should have assigned phandles yet */
assert(!node->phandle);
- phandle = check_phandle_prop(c, root, node, "phandle");
+ phandle = check_phandle_prop(c, bi, node, "phandle");
- linux_phandle = check_phandle_prop(c, root, node, "linux,phandle");
+ linux_phandle = check_phandle_prop(c, bi, node, "linux,phandle");
if (!phandle && !linux_phandle)
/* No valid phandles; nothing further to check */
@@ -433,7 +437,7 @@ static void check_explicit_phandles(struct check *c, struct node *root,
}
ERROR(explicit_phandles, check_explicit_phandles, NULL);
-static void check_name_properties(struct check *c, struct node *root,
+static void check_name_properties(struct check *c, struct boot_info *bi,
struct node *node)
{
struct property **pp, *prop = NULL;
@@ -467,9 +471,10 @@ ERROR(name_properties, check_name_properties, NULL, &name_is_string);
* Reference fixup functions
*/
-static void fixup_phandle_references(struct check *c, struct node *dt,
+static void fixup_phandle_references(struct check *c, struct boot_info *bi,
struct node *node)
{
+ struct node *dt = bi->dt;
struct property *prop;
for_each_property(node, prop) {
@@ -495,9 +500,10 @@ static void fixup_phandle_references(struct check *c, struct node *dt,
ERROR(phandle_references, fixup_phandle_references, NULL,
&duplicate_node_names, &explicit_phandles);
-static void fixup_path_references(struct check *c, struct node *dt,
+static void fixup_path_references(struct check *c, struct boot_info *bi,
struct node *node)
{
+ struct node *dt = bi->dt;
struct property *prop;
for_each_property(node, prop) {
@@ -534,7 +540,7 @@ WARNING_IF_NOT_STRING(device_type_is_string, "device_type");
WARNING_IF_NOT_STRING(model_is_string, "model");
WARNING_IF_NOT_STRING(status_is_string, "status");
-static void fixup_addr_size_cells(struct check *c, struct node *dt,
+static void fixup_addr_size_cells(struct check *c, struct boot_info *bi,
struct node *node)
{
struct property *prop;
@@ -558,7 +564,7 @@ WARNING(addr_size_cells, fixup_addr_size_cells, NULL,
#define node_size_cells(n) \
(((n)->size_cells == -1) ? 1 : (n)->size_cells)
-static void check_reg_format(struct check *c, struct node *dt,
+static void check_reg_format(struct check *c, struct boot_info *bi,
struct node *node)
{
struct property *prop;
@@ -587,7 +593,7 @@ static void check_reg_format(struct check *c, struct node *dt,
}
WARNING(reg_format, check_reg_format, NULL, &addr_size_cells);
-static void check_ranges_format(struct check *c, struct node *dt,
+static void check_ranges_format(struct check *c, struct boot_info *bi,
struct node *node)
{
struct property *prop;
@@ -631,7 +637,7 @@ WARNING(ranges_format, check_ranges_format, NULL, &addr_size_cells);
/*
* Style checks
*/
-static void check_avoid_default_addr_size(struct check *c, struct node *dt,
+static void check_avoid_default_addr_size(struct check *c, struct boot_info *bi,
struct node *node)
{
struct property *reg, *ranges;
@@ -657,9 +663,10 @@ WARNING(avoid_default_addr_size, check_avoid_default_addr_size, NULL,
&addr_size_cells);
static void check_obsolete_chosen_interrupt_controller(struct check *c,
- struct node *dt,
+ struct boot_info *bi,
struct node *node)
{
+ struct node *dt = bi->dt;
struct node *chosen;
struct property *prop;
@@ -765,7 +772,6 @@ void parse_checks_option(bool warn, bool error, const char *arg)
void process_checks(bool force, struct boot_info *bi)
{
- struct node *dt = bi->dt;
int i;
int error = 0;
@@ -773,7 +779,7 @@ void process_checks(bool force, struct boot_info *bi)
struct check *c = check_table[i];
if (c->warn || c->error)
- error = error || run_check(c, dt);
+ error = error || run_check(c, bi);
}
if (error) {
--
2.1.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 related
* [PATCH v10 0/4] dtc: Dynamic DT support
From: Pantelis Antoniou @ 2016-11-25 12:32 UTC (permalink / raw)
To: David Gibson
Cc: Jon Loeliger, Grant Likely, Frank Rowand, Rob Herring, Jan Luebbe,
Sascha Hauer, Phil Elwell, Simon Glass, Maxime Ripard,
Thomas Petazzoni, Boris Brezillon, Antoine Tenart, Stephen Boyd,
Devicetree Compiler, devicetree-u79uwXL29TY76Z2rM5mHXA,
Pantelis Antoniou
This patchset adds Dynamic DT support in the DTC compiler
as used in a number of boards like the beaglebone/rpi/chip and others.
The first patch passes a boot_info argument instead of the root node
to the check methods.
The second patch documents the internals of overlay generation, while
the third one adds dynamic object/overlay support proper.
The last patch simply adds a few overlay tests verifying operation.
This patchset is against DTC mainline and is also available for a pull
request from https://github.com/pantoniou/dtc/tree/overlays
Regards
-- Pantelis
Changes since v9:
* Reversed -M switch to by default use new DTBO magic value.
* Removed global versionflags in the parser by using inherited
attributes.
* build_node instead of malloc at add_orphan_node().
* Do not use escape for path copy
* Do not generate /plugin/ when generating a dts file even when
the plugin flag is set..
Changes since v8:
* Removed extra member of boot_info in each node; passing boot_info
parameter to the check methods instead.
* Reworked yacc syntax that supports both old and new plugin syntax
* Added handling for new magic number (enabled by 'M' switch).
* Dropped dtbo/asmo formats.
* Added overlay testsuite.
* Addressed last version maintainer comments.
Changes since v7:
* Dropped xasprintf & backward compatibility patch
* Rebased against dgibson's overlay branch
* Minor doc wording fixes.
Changes since v6:
* Introduced xasprintf
* Added append_to_property and used it
* Changed some die()'s to assert
* Reordered node generation to respect sort
* Addressed remaining maintainer changes from v6
Changes since v5:
* Rebase to latest dtc version.
* Addressed all the maintainer requested changes from v5
* Added new magic value for dynamic objects and new format
Changes since v4:
* Rebase to latest dtc version.
* Completely redesigned the generation of resolution data.
Now instead of being generated as part of blob generation
they are created in the live tree.
* Consequently the patchset is much smaller.
* Added -A auto-label alias generation option.
* Addressed maintainer comments.
* Added syntactic sugar for overlays in the form of .dtsi
* Added /dts-v1/ /plugin/ preferred plugin form and deprecate
the previous form (although still works for backward compatibility)
Changes since v3:
* Rebase to latest dtc version.
Changes since v2:
* Split single patch to a patchset.
* Updated to dtc mainline.
* Changed __local_fixups__ format
* Clean up for better legibility.
Pantelis Antoniou (4):
checks: Pass boot_info instead of root node
dtc: Document the dynamic plugin internals
dtc: Plugin and fixup support
tests: Add overlay tests
Documentation/dt-object-internal.txt | 318 +++++++++++++++++++++++++++++++++++
Documentation/manual.txt | 25 ++-
checks.c | 86 +++++-----
dtc-lexer.l | 5 +
dtc-parser.y | 50 +++++-
dtc.c | 39 ++++-
dtc.h | 20 ++-
fdtdump.c | 2 +-
flattree.c | 17 +-
fstree.c | 2 +-
libfdt/fdt.c | 2 +-
libfdt/fdt.h | 3 +-
livetree.c | 225 ++++++++++++++++++++++++-
tests/mangle-layout.c | 7 +-
tests/overlay_overlay_dtc.dts | 76 +--------
tests/overlay_overlay_dtc.dtsi | 83 +++++++++
tests/overlay_overlay_new_dtc.dts | 11 ++
tests/overlay_overlay_simple.dts | 12 ++
tests/run_tests.sh | 20 +++
19 files changed, 862 insertions(+), 141 deletions(-)
create mode 100644 Documentation/dt-object-internal.txt
create mode 100644 tests/overlay_overlay_dtc.dtsi
create mode 100644 tests/overlay_overlay_new_dtc.dts
create mode 100644 tests/overlay_overlay_simple.dts
--
2.1.4
^ permalink raw reply
* Re: [RFC v2: PATCH 1/2] dt-bindings: Document the hi3660 reset bindings
From: zhangfei @ 2016-11-25 12:08 UTC (permalink / raw)
To: Philipp Zabel
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, Arnd Bergmann, Stephen Boyd
In-Reply-To: <1480071241.4058.23.camel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
On 2016年11月25日 18:54, Philipp Zabel wrote:
> Am Freitag, den 25.11.2016, 18:42 +0800 schrieb zhangfei:
>> On 2016年11月25日 18:25, Philipp Zabel wrote:
>>> Am Donnerstag, den 24.11.2016, 18:20 +0800 schrieb zhangfei:
>>>> On 2016年11月24日 17:50, Philipp Zabel wrote:
>>>>> Am Donnerstag, den 24.11.2016, 17:40 +0800 schrieb zhangfei:
>>>>>> On 2016年11月24日 17:26, Philipp Zabel wrote:
>>>>>>> Am Mittwoch, den 23.11.2016, 16:07 +0800 schrieb Zhangfei Gao:
>>>>>>>> Add DT bindings documentation for hi3660 SoC reset controller.
>>>>>>>>
>>>>>>>> Signed-off-by: Zhangfei Gao <zhangfei.gao-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
>>>>>>>> ---
>>>>>>>> .../bindings/reset/hisilicon,hi3660-reset.txt | 51 ++++++++++++++++++++++
>>>>>>>> 1 file changed, 51 insertions(+)
>>>>>>>> create mode 100644 Documentation/devicetree/bindings/reset/hisilicon,hi3660-reset.txt
>>>>>>>>
>>>>>>>> diff --git a/Documentation/devicetree/bindings/reset/hisilicon,hi3660-reset.txt b/Documentation/devicetree/bindings/reset/hisilicon,hi3660-reset.txt
>>>>>>>> new file mode 100644
>>>>>>>> index 0000000..250daf2
>>>>>>>> --- /dev/null
>>>>>>>> +++ b/Documentation/devicetree/bindings/reset/hisilicon,hi3660-reset.txt
>>>>>>>> @@ -0,0 +1,51 @@
>>>>>>>> +Hisilicon System Reset Controller
>>>>>>>> +======================================
>>>>>>>> +
>>>>>>>> +Please also refer to reset.txt in this directory for common reset
>>>>>>>> +controller binding usage.
>>>>>>>> +
>>>>>>>> +The reset controller registers are part of the system-ctl block on
>>>>>>>> +hi3660 SoC.
>>>>>>>> +
>>>>>>>> +Required properties:
>>>>>>>> +- compatible: should be
>>>>>>>> + "hisilicon,hi3660-reset"
>>>>>>>> +- #reset-cells: 1, see below
>>>>>>>> +- hisi,rst-syscon: phandle of the reset's syscon.
>>>>>>>> +- hisi,reset-bits: Contains the reset control register information
>>>>>>>> + Should contain 2 cells for each reset exposed to
>>>>>>>> + consumers, defined as:
>>>>>>>> + Cell #1 : offset from the syscon register base
>>>>>>>> + Cell #2 : bits position of the control register
>>>>>>>> +
>>>>>>>> +Example:
>>>>>>>> + iomcu: iomcu@ffd7e000 {
>>>>>>>> + compatible = "hisilicon,hi3660-iomcu", "syscon";
>>>>>>>> + reg = <0x0 0xffd7e000 0x0 0x1000>;
>>>>>>>> + };
>>>>>>>> +
>>>>>>>> + iomcu_rst: iomcu_rst_controller {
>>>>>>> This should be
>>>>>>> iomcu_rst: reset-controller {
>>>>>>>
>>>>>>>> + compatible = "hisilicon,hi3660-reset";
>>>>>>>> + #reset-cells = <1>;
>>>>>>>> + hisi,rst-syscon = <&iomcu>;
>>>>>>>> + hisi,reset-bits = <0x20 0x8 /* 0: i2c0 */
>>>>>>>> + 0x20 0x10 /* 1: i2c1 */
>>>>>>>> + 0x20 0x20 /* 2: i2c2 */
>>>>>>>> + 0x20 0x8000000>; /* 3: i2c6 */
>>>>>>>> + };
>>>>>>> The reset lines are controlled through iomcu bits, is there a reason not
>>>>>>> to put the iomcu_rst node inside the iomcu node? That way the
>>>>>>> hisi,rst-syscon property could be removed and the syscon could be
>>>>>>> retrieved via the reset-controller parent node.
>>>>>> iomcu is common registers, controls clock and reset, etc.
>>>>>> So we use syscon, without mapping the registers everywhere.
>>>>>> It is common case in hisilicon, same in hi6220.
>>>>>>
>>>>>> Also the #clock-cells and #reset-cells can not be put in the same node,
>>>>>> if they are both using probe, since reset_probe will not be called.
>>>>>>
>>>>>> So we use hisi,rst-syscon as a general solution.
>>>>> What I meant is this:
>>>>>
>>>>> iomcu: iomcu@ffd7e000 {
>>>>> compatible = "hisilicon,hi3660-iomcu", "syscon", "simple-mfd";
>>>>> reg = <0x0 0xffd7e000 0x0 0x1000>;
>>>> #clock-cells = <1>;
>>>>
>>>> In my test, if there add #clock-cells = <1>, reset_probe will not be
>>>> called any more.
>>>> Since clk_probe is called first.
>>>> No matter iomcu_rst is child node or not.
>>> I don't understand this, does the clock driver bind to the iomcu node
>>> using CLK_OF_DECLARE_DRIVER(..., "hisilicon,hi3660-iomcu", ...)?
>> This method:CLK_OF_DECLARE_DRIVER is not prefered in clock,
>> and we have to use probe instead, to make all driver build as modules as
>> possible.
>>
>> For example hi3660.
>> static struct platform_driver hi3660_clk_driver = {
>> .probe = hi3660_clk_probe,
>> .driver = {
>> .name = "hi3660-clk",
>> .of_match_table = hi3660_clk_match_table,
>> },
>> };
> hi3660_clk_match_table contains the "hisilicon,hi3660-iomcu" compatible?
> If so, you could call
> of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
> from hi3660_clk_probe instead of using "simple-mfd" to probe the iomcu
> node's children.
Not using simple-mfd:
Like
static const struct of_device_id hi3660_clk_match_table[] = {
{ .compatible = "hisilicon,hi3660-iomcu", },
{ }
};
MODULE_DEVICE_TABLE(of, hi3660_clk_match_table);
static int hi3660_clk_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *of_id;
enum hi3660_clk_type type;
of_id = of_match_device(hi3660_clk_match_table, dev);
if (!of_id)
return -EINVAL;
~
}
If put iomcu_rst as child node, and set #clock-cells = <1> to iomcu,
then hi3660_clk_probe is called, hi3660_reset_probe will not be called.
So using "hisi,rst-syscon" as pointer does not have the issue.
Thanks
--
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/2] pinctrl: tegra: Add driver to configure voltage and power of io pads
From: Laxman Dewangan @ 2016-11-25 12:04 UTC (permalink / raw)
To: Thierry Reding
Cc: linus.walleij, robh+dt, mark.rutland, swarren, gnurou, jonathanh,
joe, yamada.masahiro, linux-gpio, devicetree, linux-tegra,
linux-kernel
In-Reply-To: <20161125095744.GB11512@ulmo.ba.sec>
Thanks Thierry for review.
On Friday 25 November 2016 03:27 PM, Thierry Reding wrote:
> * PGP Signed by an unknown key
>
> On Thu, Nov 24, 2016 at 02:08:54PM +0530, Laxman Dewangan wrote:
>> + NVIDIA Tegra124/210 SoC has IO pads which supports multi-voltage
>> + level of interfacing and deep power down mode of IO pads. The
>> + voltage of IO pads are SW configurable based on IO rail of that
>> + pads on T210. This driver provides the interface to change IO pad
>> + voltage and power state via pincontrol interface.
> This has a lot of chip-specific text. Will all of that have to be
> updated if support for new chips is added?
Then saying that Tegra124 and later..
Hoping, people know our chip releasing sequence as numbering are not in
sequence.
>
>> +#include <linux/regulator/consumer.h>
>> +#include <soc/tegra/pmc.h>
> Have you considered moving this code into the PMC driver? It seems a
> little over the top to go through all of the platform device creation
> and driver registration dance only to call into a public API later on.
Yes, we had discussion on this and suggestion came to use the pinctrl
framework.
If we do in the pmc driver then we will need lots of DT processing for
getting information from DT which we can directly get from the pinctrl
core framework.
Also client driver may need to have the control dynamically and get the
IO pads from DT. So implementing all in pmc will be huge duplication
over already existing framework.
>
>> +#include "../core.h"
>> +#include "../pinconf.h"
>> +#include "../pinctrl-utils.h"
>> +
>> +#define TEGRA_IO_RAIL_1800000UV 1800000
>> +#define TEGRA_IO_RAIL_3300000UV 3300000
> Is there really a point in having these defines? They are really long
> and effectively don't carry more information than just the plain
> numbers.
using macros is always good instead of magic number in code and hence it
is there.
>
>
>> +#define tegra_io_uv_to_io_pads_uv(io_uv) \
>> + (((io_uv) == TEGRA_IO_RAIL_1800000UV) ? \
>> + TEGRA_IO_PAD_1800000UV : TEGRA_IO_PAD_3300000UV)
>> +
>> +#define tegra_io_voltage_is_valid(io_uv) \
>> + ({ typeof(io_uv) io_uv_ = (io_uv); \
>> + ((io_uv_ == TEGRA_IO_RAIL_1800000UV) || \
>> + (io_uv_ == TEGRA_IO_RAIL_3300000UV)); })
>>
> Maybe make both of these static inline functions to improve readability?
> I find the above very hard to read.
OK, will convert to the inline but dont think it will be less complex.
>> + enum tegra_io_pad_voltage pad_volt;
>>
>> +
>>
>> +
>> +#define TEGRA_IO_PAD_INFO(_pin, _name, _id, _lpstate, _vsupply) \
>> + { \
>> + .name = _name, \
>> + .pins = {(_pin)}, \
>> + .id = TEGRA_IO_PAD_##_id, \
>> + .vsupply = (_vsupply), \
>> + .supports_low_power = (_lpstate), \
>> + }
>> +
>> +static const struct tegra_io_pads_cfg tegra124_io_pads_cfg_info[] = {
>> + TEGRA124_PAD_INFO_TABLE(TEGRA_IO_PAD_INFO),
>> +};
>> +
>> +static const struct tegra_io_pads_cfg tegra210_io_pads_cfg_info[] = {
>> + TEGRA210_PAD_INFO_TABLE(TEGRA_IO_PAD_INFO),
>> +};
> That's a weird way of writing these tables. Why not do something simpler
> and much more common such as:
>
> #define TEGRA_IO_PAD_INFO(...) ...
>
> static const struct tegra_io_pads_cfg tegra124_io_pads_cfgs[] = {
> TEGRA_IO_PAD_INFO(...),
> ...
> };
>
> static const struct tegra_io_pads_cfg tegra210_io_pad_cfgs[] = {
> TEGRA_IO_PAD_INFO(...),
> ...
> };
This is done to use the same table for initialing two different
structure. If we go as above then we will endup with the two tables.
or define and then redefine the TEGRA_IO_PAD_INFO.
>
>> +
>>
>> +
>> +module_platform_driver(tegra_io_pads_pinctrl_driver);
>> +
>> +MODULE_DESCRIPTION("NVIDIA TEGRA IO pad Control Driver");
>> +MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
>> +MODULE_LICENSE("GPL v2");
> Like I said above, I think there's a lot of boilerplate in here that's
> simply there to create a virtual device and bind a driver to it. All of
> that comes with very little to no benefit. I think this could all just
> be moved into the PMC driver and be simplified quite a bit.
>
What did you not like here?
Let me specific to my query to get idea about your view:
1. Do you agree for the interface as pinctrl here?
2. Do you want to call the probe() function implemented here as simple
function call from pmc's probe?
3. If (2) is yes then how do you want to differentiate T124 or T210? Via
argument?
It will be really help if you can provide the pseudo code from PMC and
this driver so that I can implement the same in the next patch.
^ permalink raw reply
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