* Re: [PATCH 1/6] dt-bindings: pwm: allwinner: Add H6 PWM description
From: Maxime Ripard @ 2019-07-27 10:42 UTC (permalink / raw)
To: Jernej Skrabec
Cc: mark.rutland, linux-pwm, devicetree, linux-sunxi, linux-kernel,
robh+dt, wens, thierry.reding, linux-arm-kernel
In-Reply-To: <20190726184045.14669-2-jernej.skrabec@siol.net>
Hi,
On Fri, Jul 26, 2019 at 08:40:40PM +0200, Jernej Skrabec wrote:
> H6 PWM block is basically the same as A20 PWM, except that it also has
> bus clock and reset line which needs to be handled accordingly.
>
> Expand Allwinner PWM binding with H6 PWM specifics.
>
> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> ---
> .../bindings/pwm/allwinner,sun4i-a10-pwm.yaml | 36 ++++++++++++++++++-
> 1 file changed, 35 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml b/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml
> index 0ac52f83a58c..deca5d81802f 100644
> --- a/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml
> +++ b/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml
> @@ -30,13 +30,47 @@ properties:
> - items:
> - const: allwinner,sun50i-h5-pwm
> - const: allwinner,sun5i-a13-pwm
> + - const: allwinner,sun50i-h6-pwm
>
> reg:
> maxItems: 1
>
> - clocks:
> + # Even though it only applies to subschemas under the conditionals,
> + # not listing them here will trigger a warning because of the
> + # additionalsProperties set to false.
> + clocks: true
> + clock-names: true
> + resets:
> maxItems: 1
>
> +allOf:
> + - if:
There's only one condition, so you don't really need the allOf.
Maxime
--
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* Re: [PATCH v3 1/2] dt-bindings: i3c: Document MediaTek I3C master bindings
From: Boris Brezillon @ 2019-07-27 9:18 UTC (permalink / raw)
To: Qii Wang
Cc: Rob Herring, bbrezillon, matthias.bgg, mark.rutland, linux-i3c,
devicetree, linux-arm-kernel, linux-kernel, linux-mediatek,
srv_heupstream, leilk.liu, liguo.zhang, xinping.qian
In-Reply-To: <1564190613.24702.11.camel@mhfsdcap03>
On Sat, 27 Jul 2019 09:23:33 +0800
Qii Wang <qii.wang@mediatek.com> wrote:
> On Wed, 2019-07-24 at 14:21 -0600, Rob Herring wrote:
> > On Tue, Jul 09, 2019 at 09:09:21PM +0800, Qii Wang wrote:
> > > Document MediaTek I3C master DT bindings.
> > >
> > > Signed-off-by: Qii Wang <qii.wang@mediatek.com>
> > > ---
> > > .../devicetree/bindings/i3c/mtk,i3c-master.txt | 48 ++++++++++++++++++++
> > > 1 file changed, 48 insertions(+)
> > > create mode 100644 Documentation/devicetree/bindings/i3c/mtk,i3c-master.txt
> > >
> > > diff --git a/Documentation/devicetree/bindings/i3c/mtk,i3c-master.txt b/Documentation/devicetree/bindings/i3c/mtk,i3c-master.txt
> > > new file mode 100644
> > > index 0000000..d32eda6
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/i3c/mtk,i3c-master.txt
> > > @@ -0,0 +1,48 @@
> > > +Bindings for MediaTek I3C master block
> > > +=====================================
> > > +
> > > +Required properties:
> > > +--------------------
> > > +- compatible: shall be "mediatek,i3c-master"
> >
> > Needs to be SoC specific.
> >
>
> We hope that the SOCs will use the same driver and try to avoid big
> changes. If there are inevitable changes in the future, then we will
> modify the compatible to be SoC specific. cdns,i3c-master.txt is not SoC
> specific either.
The cadence case is a bit different I think. When the driver was
developed there was no SoC integrating this IP. I guess Mediatek knows
already which SoC(s) will embed the I3C master block.
>
> > > +- reg: physical base address of the controller and apdma base, length of
> > > + memory mapped region.
> > > +- reg-names: shall be "main" for master controller and "dma" for apdma.
> > > +- interrupts: the interrupt line connected to this I3C master.
> > > +- clocks: shall reference the i3c and apdma clocks.
> > > +- clock-names: shall include "main" and "dma".
> > > +
> > > +Mandatory properties defined by the generic binding (see
> > > +Documentation/devicetree/bindings/i3c/i3c.txt for more details):
> > > +
> > > +- #address-cells: shall be set to 3
> > > +- #size-cells: shall be set to 0
> > > +
> > > +Optional properties defined by the generic binding (see
> > > +Documentation/devicetree/bindings/i3c/i3c.txt for more details):
> > > +
> > > +- i2c-scl-hz
> > > +- i3c-scl-hz
> > > +
> > > +I3C device connected on the bus follow the generic description (see
> > > +Documentation/devicetree/bindings/i3c/i3c.txt for more details).
> > > +
> > > +Example:
> > > +
> > > + i3c0: i3c@1100d000 {
> > > + compatible = "mediatek,i3c-master";
> > > + reg = <0x1100d000 0x1000>,
> > > + <0x11000300 0x80>;
> > > + reg-names = "main", "dma";
> > > + interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_LOW>;
> > > + clocks = <&infracfg CLK_INFRA_I3C0>,
> > > + <&infracfg CLK_INFRA_AP_DMA>;
> > > + clock-names = "main", "dma";
> > > + #address-cells = <3>;
> > > + #size-cells = <0>;
> > > + i2c-scl-hz = <100000>;
> > > +
> > > + nunchuk: nunchuk@52 {
> > > + compatible = "nintendo,nunchuk";
> > > + reg = <0x52 0x0 0x10>;
> > > + };
> > > + };
> > > --
> > > 1.7.9.5
> > >
>
>
^ permalink raw reply
* Re: [PATCH net-next 3/3] net: dsa: mt7530: Add support for port 5
From: Florian Fainelli @ 2019-07-27 8:42 UTC (permalink / raw)
To: René van Dorst, netdev
Cc: frank-w, sean.wang, linux, davem, matthias.bgg, andrew,
vivien.didelot, john, linux-mediatek, linux-mips, robh+dt,
devicetree
In-Reply-To: <20190724192549.24615-4-opensource@vdorst.com>
On 7/24/2019 9:25 PM, René van Dorst wrote:
> Adding support for port 5.
>
> Port 5 can muxed/interface to:
> - internal 5th GMAC of the switch; can be used as 2nd CPU port or as
> extra port with an external phy for a 6th ethernet port.
> - internal PHY of port 0 or 4; Used in most applications so that port 0
> or 4 is the WAN port and interfaces with the 2nd GMAC of the SOC.
>
> Signed-off-by: René van Dorst <opensource@vdorst.com>
[snip]
> + /* Setup port 5 */
> + priv->p5_intf_sel = P5_DISABLED;
> + interface = PHY_INTERFACE_MODE_NA;
> +
> + if (!dsa_is_unused_port(ds, 5)) {
> + priv->p5_intf_sel = P5_INTF_SEL_GMAC5;
> + interface = of_get_phy_mode(ds->ports[5].dn);
> + } else {
> + /* Scan the ethernet nodes. Look for GMAC1, Lookup used phy */
> + for_each_child_of_node(dn, mac_np) {
> + if (!of_device_is_compatible(mac_np,
> + "mediatek,eth-mac"))
> + continue;
> + _id = of_get_property(mac_np, "reg", NULL);
> + if (be32_to_cpup(_id) != 1)
> + continue;
> +
> + interface = of_get_phy_mode(mac_np);
> + phy_node = of_parse_phandle(mac_np, "phy-handle", 0);
> +
> + if (phy_node->parent == priv->dev->of_node->parent) {
> + _id = of_get_property(phy_node, "reg", NULL);
> + id = be32_to_cpup(_id);
> + if (id == 0)
> + priv->p5_intf_sel = P5_INTF_SEL_PHY_P0;
> + if (id == 4)
> + priv->p5_intf_sel = P5_INTF_SEL_PHY_P4;
Can you use of_mdio_parse_addr() here?
--
Florian
^ permalink raw reply
* Re: [RFC PATCH v2 1/4] dt-bindings: input: Add support for the MPR121 without interrupt line
From: Dmitry Torokhov @ 2019-07-27 8:01 UTC (permalink / raw)
To: Rob Herring
Cc: Michal Vokáč, Mark Rutland, Shawn Guo, Sascha Hauer,
Fabio Estevam, linux-input, devicetree, linux-kernel,
Pengutronix Kernel Team
In-Reply-To: <20190613223945.GA938@bogus>
On Thu, Jun 13, 2019 at 04:39:45PM -0600, Rob Herring wrote:
> On Fri, May 17, 2019 at 03:12:50PM +0200, Michal Vokáč wrote:
> > Normally, the MPR121 controller uses separate interrupt line to notify
> > the I2C host that a key was touched/released. To support platforms that
> > can not use the interrupt line, polling of the MPR121 registers can be
> > used.
>
> 'separate' from what?
>
> >
> > Signed-off-by: Michal Vokáč <michal.vokac@ysoft.com>
> > ---
> > Changes since v1:
> > - Document the polled binding in the original file, do not create a new one.
> > (Rob)
> >
> > Documentation/devicetree/bindings/input/mpr121-touchkey.txt | 9 +++++++--
> > 1 file changed, 7 insertions(+), 2 deletions(-)
> >
> > diff --git a/Documentation/devicetree/bindings/input/mpr121-touchkey.txt b/Documentation/devicetree/bindings/input/mpr121-touchkey.txt
> > index b7c61ee5841b..97f55273d473 100644
> > --- a/Documentation/devicetree/bindings/input/mpr121-touchkey.txt
> > +++ b/Documentation/devicetree/bindings/input/mpr121-touchkey.txt
> > @@ -1,9 +1,14 @@
> > -* Freescale MPR121 Controllor
> > +* Freescale MPR121 Controller
> >
> > Required Properties:
> > -- compatible: Should be "fsl,mpr121-touchkey"
> > +- compatible: Should be one of:
> > + - "fsl,mpr121-touchkey" - MPR121 with interrupt line
> > + - "fsl,mpr121-touchkey-polled" - MPR121 with polling
> > - reg: The I2C slave address of the device.
> > - interrupts: The interrupt number to the cpu.
> > + In case of "fsl,mpr121-touchkey-polled" the interrupt
> > + line is not used and hence the interrupts property is
> > + not required.
>
> Absence of the interrupts property is enough to determine polled mode
> and you don't need a separate compatible string.
I would prefer if we could distinguish between chip working in polled
mode intentionally vs DT writer simply forgetting to specify interrupt
property. Should we key the polling mode off "linux,poll-interval"
property? We probably going to need it anyway as not everyone needs the
same polling frequency.
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH v2 00/12] Clean up "mediatek,larb" after adding device_link
From: Yong Wu @ 2019-07-27 7:51 UTC (permalink / raw)
To: CK Hu
Cc: youlin.pei-NuS5LvNUpcJWk0Htik3J/w,
devicetree-u79uwXL29TY76Z2rM5mHXA, Nicolas Boichat,
srv_heupstream-NuS5LvNUpcJWk0Htik3J/w, Will Deacon,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Evan Green, Tomasz Figa,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Rob Herring,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
joey.pan-NuS5LvNUpcJWk0Htik3J/w, Matthias Brugger,
yingjoe.chen-NuS5LvNUpcJWk0Htik3J/w,
anan.sun-NuS5LvNUpcJWk0Htik3J/w, Robin Murphy,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <1563849109.27558.14.camel@mtksdaap41>
On Tue, 2019-07-23 at 10:31 +0800, CK Hu wrote:
> Hi, Yong:
>
> I've added log in mtk_smi_clk_enable() and mtk_smi_clk_disable(), and I
> boot MT8183 with display, the log is
>
> [ 4.020340] mtk-smi-common 14019000.smi: mtk_smi_clk_enable()
> [ 4.331371] mtk-smi-common 14019000.smi: mtk_smi_clk_disable()
> [ 4.429578] mtk-smi-common 14019000.smi: mtk_smi_clk_enable()
> [ 4.719743] mtk-smi-common 14019000.smi: mtk_smi_clk_disable()
> [ 5.084770] mtk-smi-common 14019000.smi: mtk_smi_clk_enable()
> [ 5.904310] mtk-smi-common 14019000.smi: mtk_smi_clk_disable()
>
> From the log, the clock is finally turned off, but the display works
> normally. This is because scpsys has turn the clock on,
>
> scpsys: syscon@10006000 {
> compatible = "mediatek,mt8183-scpsys", "syscon";
> #power-domain-cells = <1>;
> reg = <0 0x10006000 0 0x1000>;
> clocks = <&topckgen CLK_TOP_MUX_AUD_INTBUS>,
> <&mmsys CLK_MM_SMI_COMMON>,
> <&mmsys CLK_MM_GALS_COMM0>,
> <&mmsys CLK_MM_GALS_COMM1>,
> clock-names = "audio","mm-0",
> "mm-1", "mm-2";
> }
>
> I'm worried that for MT8173, scpsys would not turn on subsys clock, this
> series would let display work abnormally, so I think smi common should
> not depend on scpsys to turn on the clock.
>
> You could simply remove the clock parameter in scpsys device node, and
> you would see the display works abnormally.
Thanks for the report. I have reproduced this issue by removing the smi
clock in scpsys node.
Now the probe sequence is like this:
a) mtk scpsys (genpd) probe
b) smi probe
c) iommu probe
d) display and the other MM probe.
The log above are called from device_link_add and rpm_idle which is
called between iommu-probe and display-probe.
At the beginning, all the clocks are enabled. But after this
mtk_smi_clk_enable and mtk_smi_clk_disable, the display clock will be
turned off. If the fastlogo is displayed before kernel, then the display
HW will work abnormally.
I have no mt8173 evb board now, I remembered that the screen only is
showed in display driver of kernel in mt8173, It may be ok in that case.
But It really is a problem when the fastlogo is showed before kernel.
This clock issue happened before display driver, It looks display driver
can not help this. I will try to fix it in SMI(smi try to help
display(larb0) to pm_runtime_get_sync one time and put later).
>
> Regards,
> CK
>
>
> On Mon, 2019-06-10 at 20:55 +0800, Yong Wu wrote:
> > MediaTek IOMMU block diagram always like below:
> >
> > M4U
> > |
> > smi-common
> > |
> > -------------
> > | | ...
> > | |
> > larb1 larb2
> > | |
> > vdec venc
> >
> > All the consumer connect with smi-larb, then connect with smi-common.
> >
> > MediaTek IOMMU don't have its power-domain. When the consumer works,
> > it should enable the smi-larb's power which also need enable the smi-common's
> > power firstly.
> >
> > Thus, Firstly, use the device link connect the consumer and the
> > smi-larbs. then add device link between the smi-larb and smi-common.
> >
> > After adding the device_link, then "mediatek,larb" property can be removed.
> > the iommu consumer don't need call the mtk_smi_larb_get/put to enable
> > the power and clock of smi-larb and smi-common.
> >
> > This patchset depends on "MT8183 IOMMU SUPPORT"[1].
> >
> > [1] https://lists.linuxfoundation.org/pipermail/iommu/2019-June/036552.html
> >
> > Change notes:
> > v2:
> > 1) rebase on v5.2-rc1.
> > 2) Move adding device_link between the consumer and smi-larb into
> > iommu_add_device from Robin.
> > 3) add DL_FLAG_AUTOREMOVE_CONSUMER even though the smi is built-in from Evan.
> > 4) Remove the shutdown callback in iommu.
> >
> > v1: https://lists.linuxfoundation.org/pipermail/iommu/2019-January/032387.html
> >
> > Yong Wu (12):
> > dt-binding: mediatek: Get rid of mediatek,larb for multimedia HW
> > iommu/mediatek: Add probe_defer for smi-larb
> > iommu/mediatek: Add device_link between the consumer and the larb
> > devices
> > memory: mtk-smi: Add device-link between smi-larb and smi-common
> > media: mtk-jpeg: Get rid of mtk_smi_larb_get/put
> > media: mtk-mdp: Get rid of mtk_smi_larb_get/put
> > media: mtk-vcodec: Get rid of mtk_smi_larb_get/put
> > drm/mediatek: Get rid of mtk_smi_larb_get/put
> > memory: mtk-smi: Get rid of mtk_smi_larb_get/put
> > iommu/mediatek: Use builtin_platform_driver
> > arm: dts: mediatek: Get rid of mediatek,larb for MM nodes
> > arm64: dts: mediatek: Get rid of mediatek,larb for MM nodes
> >
> > .../bindings/display/mediatek/mediatek,disp.txt | 9 -----
> > .../bindings/media/mediatek-jpeg-decoder.txt | 4 --
> > .../devicetree/bindings/media/mediatek-mdp.txt | 8 ----
> > .../devicetree/bindings/media/mediatek-vcodec.txt | 4 --
> > arch/arm/boot/dts/mt2701.dtsi | 1 -
> > arch/arm/boot/dts/mt7623.dtsi | 1 -
> > arch/arm64/boot/dts/mediatek/mt8173.dtsi | 15 -------
> > drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 11 -----
> > drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 26 ------------
> > drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h | 1 -
> > drivers/iommu/mtk_iommu.c | 45 +++++++--------------
> > drivers/iommu/mtk_iommu_v1.c | 39 +++++++-----------
> > drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c | 22 ----------
> > drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h | 2 -
> > drivers/media/platform/mtk-mdp/mtk_mdp_comp.c | 38 -----------------
> > drivers/media/platform/mtk-mdp/mtk_mdp_comp.h | 2 -
> > drivers/media/platform/mtk-mdp/mtk_mdp_core.c | 1 -
> > .../media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c | 21 ----------
> > drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h | 3 --
> > drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c | 1 -
> > .../media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c | 47 ----------------------
> > drivers/memory/mtk-smi.c | 31 ++++----------
> > include/soc/mediatek/smi.h | 20 ---------
> > 23 files changed, 36 insertions(+), 316 deletions(-)
> >
>
>
^ permalink raw reply
* Re: [RFC PATCH v2 0/4] Input: mpr121-polled: Add polled driver for MPR121
From: Dmitry Torokhov @ 2019-07-27 7:31 UTC (permalink / raw)
To: Michal Vokáč
Cc: Rob Herring, Mark Rutland, Shawn Guo, Sascha Hauer, Fabio Estevam,
linux-input, devicetree, linux-kernel, Pengutronix Kernel Team
In-Reply-To: <dcee1139-c53f-5ea0-f387-a3aa5a9bf39f@ysoft.com>
On Fri, Jul 26, 2019 at 01:31:31PM +0200, Michal Vokáč wrote:
> On 25. 07. 19 16:40, Dmitry Torokhov wrote:
> > On Thu, Jul 25, 2019 at 02:58:02PM +0200, Michal Vokáč wrote:
> > > On 25. 07. 19 10:57, Dmitry Torokhov wrote:
> > > > Hi Michal,
> > > >
> > > > On Tue, May 21, 2019 at 08:51:17AM +0200, Michal Vokáč wrote:
> > > > > On 21. 05. 19 7:37, Dmitry Torokhov wrote:
> > > > > > Hi Michal,
> > > > > >
> > > > > > On Fri, May 17, 2019 at 03:12:49PM +0200, Michal Vokáč wrote:
> > > > > > > Hi,
> > > > > > >
> > > > > > > I have to deal with a situation where we have a custom i.MX6 based
> > > > > > > platform in production that uses the MPR121 touchkey controller.
> > > > > > > Unfortunately the chip is connected using only the I2C interface.
> > > > > > > The interrupt line is not used. Back in 2015 (Linux v3.14), my
> > > > > > > colleague modded the existing mpr121_touchkey.c driver to use polling
> > > > > > > instead of interrupt.
> > > > > > >
> > > > > > > For quite some time yet I am in a process of updating the product from
> > > > > > > the ancient Freescale v3.14 kernel to the latest mainline and pushing
> > > > > > > any needed changes upstream. The DT files for our imx6dl-yapp4 platform
> > > > > > > already made it into v5.1-rc.
> > > > > > >
> > > > > > > I rebased and updated our mpr121 patch to the latest mainline.
> > > > > > > It is created as a separate driver, similarly to gpio_keys_polled.
> > > > > > >
> > > > > > > The I2C device is quite susceptible to ESD. An ESD test quite often
> > > > > > > causes reset of the chip or some register randomly changes its value.
> > > > > > > The [PATCH 3/4] adds a write-through register cache. With the cache
> > > > > > > this state can be detected and the device can be re-initialied.
> > > > > > >
> > > > > > > The main question is: Is there any chance that such a polled driver
> > > > > > > could be accepted? Is it correct to implement it as a separate driver
> > > > > > > or should it be done as an option in the existing driver? I can not
> > > > > > > really imagine how I would do that though..
> > > > > > >
> > > > > > > There are also certain worries that the MPR121 chip may no longer be
> > > > > > > available in nonspecifically distant future. In case of EOL I will need
> > > > > > > to add a polled driver for an other touchkey chip. May it be already
> > > > > > > in mainline or a completely new one.
> > > > > >
> > > > > > I think that my addition of input_polled_dev was ultimately a wrong
> > > > > > thing to do. I am looking into enabling polling mode for regular input
> > > > > > devices as we then can enable polling mode in existing drivers.
> > > > >
> > > > > OK, that sounds good. Especially when one needs to switch from one chip
> > > > > to another that is already in tree, the need for a whole new polling
> > > > > driver is eliminated.
> > > >
> > > > Could you please try the patch below and see if it works for your use
> > > > case? Note that I have not tried running it, but it compiles so it must
> > > > be good ;)
> > >
> > > Hi Dmitry,
> > > Thank you very much for the patch!
> > > I gave it a shot and it seems you forgot to add the input-poller.h file
> > > to the patch.. it does not compile on my side :(
> >
> > Oops ;) Please see the updated patch below.
>
> Thank you, now it is (almost) good as you said :D
>
> > >
> > > > Input: add support for polling to input devices
> > > >
> > > > From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> > > >
> > > > Separating "normal" and "polled" input devices was a mistake, as often we want
> > > > to allow the very same device work on both interrupt-driven and polled mode,
> > > > depending on the board on which the device is used.
> > > >
> > > > This introduces new APIs:
> > > >
> > > > - input_setup_polling
> > > > - input_set_poll_interval
> > > > - input_set_min_poll_interval
> > > > - input_set_max_poll_interval
> > > >
> > > > These new APIs allow switching an input device into polled mode with sysfs
> > > > attributes matching drivers using input_polled_dev APIs that will be eventually
> > > > removed.
> > >
> > > After reading this I am not really sure what else needs to be done
> > > to test/use the poller. I suspect I need to modify the input device
> > > driver (mpr121_touchkey.c in my case) like this:
> > >
> > > If the interrupt gpio is not provided in DT, the device driver probe
> > > function should:
> > > - not request the threaded interrupt
> > > - call input_setup_polling and provide it with poll_fn
> > > Can the mpr_touchkey_interrupt function be used as is for this
> > > purpose? The only problem I see is it returns IRQ_HANDLED.
> >
> > I'd factor out code suitable for polling from mpr_touchkey_interrupt()
> > and then do
> >
> > static irqreturn_t mpr_touchkey_interrupt(...)
> > {
> > mpr_touchkey_report(...);
> > return IRQ_HANDLED;
> > }
> >
>
> Probably a trivial problem for experienced kernel hacker but I can not
> wrap my head around this - the interrupt handler takes the mpr121
> device id as an argument while the poller poll_fn takes struct input_dev.
>
> I fail to figure out how to get the device id from the input device.
>
> Here is what I have:
>
> diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c
> index e9ceaa16b46a..1124f77ee10a 100644
> --- a/drivers/input/keyboard/mpr121_touchkey.c
> +++ b/drivers/input/keyboard/mpr121_touchkey.c
> @@ -54,6 +54,10 @@
> /* MPR121 has 12 keys */
> #define MPR121_MAX_KEY_COUNT 12
> +#define MPR121_POLL_INTERVAL 50
> +#define MPR121_MIN_POLL_INTERVAL 10
> +#define MPR121_MAX_POLL_INTERVAL 200
> +
> struct mpr121_touchkey {
> struct i2c_client *client;
> struct input_dev *input_dev;
> @@ -115,9 +119,12 @@ static struct regulator *mpr121_vdd_supply_init(struct device *dev)
> return vdd_supply;
> }
> -static irqreturn_t mpr_touchkey_interrupt(int irq, void *dev_id)
> +static void mpr_touchkey_report(struct input_dev *dev)
> {
> - struct mpr121_touchkey *mpr121 = dev_id;
> + /*
> + * TODO the input_dev dev needs to be converted to mpr121 device id.
> + */
> + struct mpr121_touchkey *mpr121 = /* TODO */;
Use input_set_drvdata() in probe() and you can do
struct mpr121_touchkey *mpr121 = input_get_drvdata(dev);
here.
> struct i2c_client *client = mpr121->client;
> struct input_dev *input = mpr121->input_dev;
> unsigned long bit_changed;
> @@ -127,14 +134,14 @@ static irqreturn_t mpr_touchkey_interrupt(int irq, void *dev_id)
> reg = i2c_smbus_read_byte_data(client, ELE_TOUCH_STATUS_1_ADDR);
> if (reg < 0) {
> dev_err(&client->dev, "i2c read error [%d]\n", reg);
> - goto out;
> + return;
> }
> reg <<= 8;
> reg |= i2c_smbus_read_byte_data(client, ELE_TOUCH_STATUS_0_ADDR);
> if (reg < 0) {
> dev_err(&client->dev, "i2c read error [%d]\n", reg);
> - goto out;
> + return;
> }
> reg &= TOUCH_STATUS_MASK;
> @@ -155,8 +162,17 @@ static irqreturn_t mpr_touchkey_interrupt(int irq, void *dev_id)
> }
> input_sync(input);
> +}
> +
> +static irqreturn_t mpr_touchkey_interrupt(int irq, void *dev_id)
> +{
> + /*
> + * TODO
> + * mpr_touchkey_report takes struct input_dev as an argument,
> + * not the device id.
> + */
struct mpr121_touchkey *mpr121 = dev_id;
mpr_touchkey_report(mpr121->input);
> + mpr_touchkey_report(/* TODO */);
> -out:
> return IRQ_HANDLED;
> }
> @@ -232,11 +248,6 @@ static int mpr_touchkey_probe(struct i2c_client *client,
> int error;
> int i;
> - if (!client->irq) {
> - dev_err(dev, "irq number should not be zero\n");
> - return -EINVAL;
> - }
> -
> vdd_supply = mpr121_vdd_supply_init(dev);
> if (IS_ERR(vdd_supply))
> return PTR_ERR(vdd_supply);
> @@ -289,13 +300,27 @@ static int mpr_touchkey_probe(struct i2c_client *client,
> return error;
> }
> - error = devm_request_threaded_irq(dev, client->irq, NULL,
> - mpr_touchkey_interrupt,
> - IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
> - dev->driver->name, mpr121);
> - if (error) {
> - dev_err(dev, "Failed to register interrupt\n");
> - return error;
> + if (client->irq) {
> + error = devm_request_threaded_irq(dev, client->irq, NULL,
> + mpr_touchkey_interrupt,
> + IRQF_TRIGGER_FALLING |
> + IRQF_ONESHOT,
> + dev->driver->name, mpr121);
> + if (error) {
> + dev_err(dev, "Failed to register interrupt\n");
> + return error;
> + }
> + } else {
> + dev_dbg(dev, "invalid IRQ number, using polling mode\n");
I think it would be better if we checked if poll interval device
property is present before setting polling mode, so that polling mode is
not activated simply because someone forgot to add interrupt
specification.
> + error = input_setup_polling(input_dev, mpr_touchkey_report);
> + if (error)
> + return error;
> +
> + input_set_poll_interval(input_dev, MPR121_POLL_INTERVAL);
> + input_set_min_poll_interval(input_dev,
> + MPR121_MIN_POLL_INTERVAL);
> + input_set_max_poll_interval(input_dev,
> + MPR121_MAX_POLL_INTERVAL);
> }
> error = input_register_device(input_dev);
> --
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH 00/15] thermal: qcom: tsens: Add interrupt support
From: Amit Kucheria @ 2019-07-27 7:28 UTC (permalink / raw)
To: Brian Masney
Cc: LKML, linux-arm-msm, Bjorn Andersson, Eduardo Valentin,
Andy Gross, Andy Gross, Daniel Lezcano, Mark Rutland, Rob Herring,
Zhang Rui, Marc Gonzalez,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Linux PM list
In-Reply-To: <20190726112954.GA3984@onstation.org>
On Fri, Jul 26, 2019 at 4:59 PM Brian Masney <masneyb@onstation.org> wrote:
>
> Hi Amit,
>
> On Fri, Jul 26, 2019 at 04:40:16PM +0530, Amit Kucheria wrote:
> > > The device tree nodes appear in sysfs:
> > >
> > > / # ls -1 /sys/class/thermal/
> > > cooling_device0
> > > cooling_device1
> > > thermal_zone0
> > > thermal_zone1
> > > thermal_zone2
> > > thermal_zone3
> > > thermal_zone4
> > > thermal_zone5
> > > thermal_zone6
> > > thermal_zone7
> > > thermal_zone8
> > > thermal_zone9
> >
> > Looks good. What are the contents of the files inside the two
> > cooling_device directories? The output of the following command would
> > be nice:
> >
> > $ grep "" cooling_device?/*
>
> /sys/class/thermal # grep "" cooling_device?/*
> cooling_device0/cur_state:100000
> cooling_device0/max_state:2500000
> cooling_device0/type:smbb-usbin
> cooling_device1/cur_state:500000
> cooling_device1/max_state:2500000
> cooling_device1/type:smbb-dcin
>
> > > The various temperatures were in the upper 40s and I threw some work at
> > > all four CPU cores to warm up the phone and watched the various
> > > temperatures rise:
> > >
> > > / # for i in $(seq 0 9) ; do
> > > > TYPE=$(cat /sys/class/thermal/thermal_zone$i/type)
> > > > TEMP=$(cat /sys/class/thermal/thermal_zone$i/temp)
> > > > echo "$TYPE = $TEMP"
> > > > done
> > > cpu-thermal0 = 66000
> > > cpu-thermal1 = 66000
> > > cpu-thermal2 = 66000
> > > cpu-thermal3 = 66000
> > > q6-dsp-thermal = 60000
> > > modemtx-thermal = 57000
> > > video-thermal = 61000
> > > wlan-thermal = 65000
> > > gpu-thermal-top = 61000
> > > gpu-thermal-bottom = 59000
> > >
> > > To test the interrupt support, I lowered all of the temperature trips to
> > > 51C but I'm not sure where to read that notification. I assume one of
> > > the cooling devices or a governor should be started? Sorry but I haven't
> > > done any work in the thermal subsystem yet and I'm short on time this
> > > morning to investigate right now.
> >
> > For now, just checking if the tsens interrupt in /proc/interrupts
> > fires should be fine. I have another patch to add some information to
> > debugs that I'll send at some point.
>
> An interrupt fires as each thermal zone exceeds the trip temperature and
> an interrupt fires again when it goes below that temperature.
> Here's my new test script:
>
> for i in $(seq 0 9) ; do
> TYPE=$(cat /sys/class/thermal/thermal_zone$i/type)
> TEMP=$(cat /sys/class/thermal/thermal_zone$i/temp)
> TRIP=$(cat /sys/class/thermal/thermal_zone$i/trip_point_0_temp)
> echo "$TYPE = $TEMP. trip = $TRIP"
> done
>
> # Warm the phone up
>
> /sys/class/thermal # /temp.sh
> cpu-thermal0 = 57000. trip = 51000
> cpu-thermal1 = 56000. trip = 51000
> cpu-thermal2 = 57000. trip = 51000
> cpu-thermal3 = 56000. trip = 51000
> q6-dsp-thermal = 51000. trip = 51000
> modemtx-thermal = 49000. trip = 51000
> video-thermal = 53000. trip = 51000
> wlan-thermal = 55000. trip = 51000
> gpu-thermal-top = 53000. trip = 51000
> gpu-thermal-bottom = 52000. trip = 51000
>
> /sys/class/thermal # grep tsens /proc/interrupts
> 27: 8 0 0 0 GIC-0 216 Level tsens
>
> # Let the phone cool off
>
> /sys/class/thermal # /temp.sh
> cpu-thermal0 = 48000. trip = 51000
> cpu-thermal1 = 48000. trip = 51000
> cpu-thermal2 = 49000. trip = 51000
> cpu-thermal3 = 48000. trip = 51000
> q6-dsp-thermal = 47000. trip = 51000
> modemtx-thermal = 45000. trip = 51000
> video-thermal = 48000. trip = 51000
> wlan-thermal = 48000. trip = 51000
> gpu-thermal-top = 48000. trip = 51000
> gpu-thermal-bottom = 47000. trip = 51000
>
> /sys/class/thermal # grep tsens /proc/interrupts
> 27: 19 0 0 0 GIC-0 216 Level tsens
OK, seems reasonable. I'll finish up a debugfs patch that'll dump more
state transition information to give more insight.
> > How well does cpufreq work on 8974? I haven't looked at it yet but
> > we'll need it for thermal throttling.
>
> I'm not sure how to tell if the frequency is dynamically changed during
> runtime on arm. x86-64 shows this information in /proc/cpuinfo. Here's
> the /proc/cpuinfo on the Nexus 5:
Nah. /proc/cpuinfo won't show what we need.
Try the following:
$ grep "" /sys/devices/system/cpu/cpufreq/policy?/*
More specifically, the following files have the information you need.
Run watch -n1 on them.
$ grep "" /sys/devices/system/cpu/cpufreq/policy?/scaling_*_freq
Thanks for your help.
Regards,
Amit
^ permalink raw reply
* Re: [PATCH 5/6] clk: imx8mq: Remove CLK_IS_CRITICAL flag for IMX8MQ_CLK_TMU_ROOT
From: Daniel Baluta @ 2019-07-27 6:33 UTC (permalink / raw)
To: Anson Huang
Cc: rui.zhang@intel.com, edubezval@gmail.com,
daniel.lezcano@linaro.org, Rob Herring, Mark Rutland, Shawn Guo,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Michael Turquette, Stephen Boyd, Lucas Stach, Abel Vesa,
Andrey Smirnov, Angus Ainslie (Purism), Carlo Caione,
Guido Günther, Leonard Crestez, linux-pm@vger.kernel.org,
Devicetree List, Linux Kernel Mailing List, linux-arm-kernel,
linux-clk@vger.kernel.org, dl-linux-imx
In-Reply-To: <DB3PR0402MB3916233A56CF5DF778115716F5C30@DB3PR0402MB3916.eurprd04.prod.outlook.com>
On Sat, Jul 27, 2019 at 9:19 AM Anson Huang <anson.huang@nxp.com> wrote:
>
> Hi, Daniel
>
> > Subject: Re: [PATCH 5/6] clk: imx8mq: Remove CLK_IS_CRITICAL flag for
> > IMX8MQ_CLK_TMU_ROOT
> >
> > Hi all,
> >
> > latest linux-next hangs at boot.
> >
> > commit fde50b96be821ac9673a7e00847cc4605bd88f34 (HEAD -> master, tag:
> > next-20190726, origin/master, origin/HEAD)
> > Author: Stephen Rothwell <sfr@canb.auug.org.au>
> > Date: Fri Jul 26 15:18:02 2019 +1000
> >
> > Add linux-next specific files for 20190726
> >
> > Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
> >
> >
> > I know this is crazy but reverting commit:
> >
> > commit 431bdd1df48ee2896ea9980d9153e3aeaf0c81ef (refs/bisect/bad)
> > Author: Anson Huang <Anson.Huang@nxp.com>
> > Date: Fri Jul 5 12:56:11 2019 +0800
> >
> > clk: imx8mq: Remove CLK_IS_CRITICAL flag for IMX8MQ_CLK_TMU_ROOT
> >
> > IMX8MQ_CLK_TMU_ROOT is ONLY used for thermal module, the driver
> > should manage this clock, so no need to have CLK_IS_CRITICAL flag
> > set.
> >
> >
> >
> > makes the boot work again.
> >
> > Any idea?
>
> I just found if disabling SDMA1, then kernel can boot up, it does NOT make sense
> TMU clock is related to SDMA1, I will check with design and get back to you soon.
>
Hi Anson,
Applying Abel's patch:
commit 8816c47db6a82f55bb4d64f62fd9dd3af680f0e4 (HEAD -> master)
Author: Abel Vesa <abel.vesa@nxp.com>
Date: Tue Jun 25 12:01:56 2019 +0300
clk: imx8mq: Mark AHB clock as critical
Keep the AHB clock always on since there is no driver to control it and
all the other clocks that use it as parent rely on it being always enabled.
The kernel boots up again.
It make some sense. I don't understand though why having
IMX8MQ_CLK_TMU_ROOT as critical also "unhangs" the kernel.
thanks,
Daniel.
^ permalink raw reply
* RE: [PATCH 5/6] clk: imx8mq: Remove CLK_IS_CRITICAL flag for IMX8MQ_CLK_TMU_ROOT
From: Anson Huang @ 2019-07-27 6:19 UTC (permalink / raw)
To: Daniel Baluta
Cc: Mark Rutland, Carlo Caione, Guido Günther,
Angus Ainslie (Purism), Leonard Crestez, Fabio Estevam,
linux-clk@vger.kernel.org, Abel Vesa, Andrey Smirnov,
daniel.lezcano@linaro.org, dl-linux-imx, rui.zhang@intel.com,
Michael Turquette, Devicetree List, linux-pm@vger.kernel.org,
Sascha Hauer, edubezval@gmail.com, Rob Herring, linux-arm-kernel,
Stephen Boyd
In-Reply-To: <CAEnQRZAZNMBx3ApVmRP8hYPw0XY_QgR-saE6WLcT8oZmHPCxSA@mail.gmail.com>
Hi, Daniel
> Subject: Re: [PATCH 5/6] clk: imx8mq: Remove CLK_IS_CRITICAL flag for
> IMX8MQ_CLK_TMU_ROOT
>
> Hi all,
>
> latest linux-next hangs at boot.
>
> commit fde50b96be821ac9673a7e00847cc4605bd88f34 (HEAD -> master, tag:
> next-20190726, origin/master, origin/HEAD)
> Author: Stephen Rothwell <sfr@canb.auug.org.au>
> Date: Fri Jul 26 15:18:02 2019 +1000
>
> Add linux-next specific files for 20190726
>
> Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
>
>
> I know this is crazy but reverting commit:
>
> commit 431bdd1df48ee2896ea9980d9153e3aeaf0c81ef (refs/bisect/bad)
> Author: Anson Huang <Anson.Huang@nxp.com>
> Date: Fri Jul 5 12:56:11 2019 +0800
>
> clk: imx8mq: Remove CLK_IS_CRITICAL flag for IMX8MQ_CLK_TMU_ROOT
>
> IMX8MQ_CLK_TMU_ROOT is ONLY used for thermal module, the driver
> should manage this clock, so no need to have CLK_IS_CRITICAL flag
> set.
>
>
>
> makes the boot work again.
>
> Any idea?
I just found if disabling SDMA1, then kernel can boot up, it does NOT make sense
TMU clock is related to SDMA1, I will check with design and get back to you soon.
Anson
^ permalink raw reply
* Re: [PATCH 00/11] JZ4740 SoC cleanup
From: Paul Cercueil @ 2019-07-27 3:19 UTC (permalink / raw)
To: Sam Ravnborg
Cc: Ralf Baechle, Paul Burton, James Hogan, Rob Herring, Mark Rutland,
Vinod Koul, Jean Delvare, Guenter Roeck, Lee Jones, Miquel Raynal,
Richard Weinberger, Sebastian Reichel, Bartlomiej Zolnierkiewicz,
Liam Girdwood, Mark Brown, linux-hwmon, devicetree, linux-fbdev,
alsa-devel, linux-pm, linux-mips, dri-devel
In-Reply-To: <20190726184649.GC14981@ravnborg.org>
Le ven. 26 juil. 2019 à 14:46, Sam Ravnborg <sam@ravnborg.org> a
écrit :
> Hi Paul.
>
> On Thu, Jul 25, 2019 at 06:02:04PM -0400, Paul Cercueil wrote:
>> Hi,
>>
>> This patchset converts the Qi LB60 MIPS board to devicetree and
>> makes it
>> use all the shiny new drivers that have been developed or updated
>> recently.
>>
>> All the crappy old drivers and custom code can be dropped since they
>> have been replaced by better alternatives.
>
> The overall diffstat is missing.
> Just for curiosity it would be nice to see what was dropped with this
> patch.
>
> Sam
Diffstat:
arch/mips/boot/dts/ingenic/jz4740.dtsi | 84 ++++++++++++
arch/mips/boot/dts/ingenic/qi_lb60.dts | 295
++++++++++++++++++++++++++++++++++++++++-
arch/mips/configs/qi_lb60_defconfig | 44 +++---
arch/mips/include/asm/mach-jz4740/gpio.h | 15 ---
arch/mips/include/asm/mach-jz4740/jz4740_fb.h | 58 --------
arch/mips/include/asm/mach-jz4740/jz4740_mmc.h | 12 --
arch/mips/include/asm/mach-jz4740/platform.h | 26 ----
arch/mips/jz4740/Makefile | 7 +-
arch/mips/jz4740/board-qi_lb60.c | 491
-------------------------------------------------------------------
arch/mips/jz4740/platform.c | 250
-----------------------------------
arch/mips/jz4740/prom.c | 5 -
arch/mips/jz4740/setup.c | 3 +-
drivers/dma/Kconfig | 6 -
drivers/dma/Makefile | 1 -
drivers/dma/dma-jz4740.c | 623
-------------------------------------------------------------------------------------
drivers/hwmon/Kconfig | 10 --
drivers/hwmon/Makefile | 1 -
drivers/hwmon/jz4740-hwmon.c | 135
-------------------
drivers/mfd/Kconfig | 9 --
drivers/mfd/Makefile | 1 -
drivers/mfd/jz4740-adc.c | 324
---------------------------------------------
drivers/mtd/nand/raw/ingenic/Kconfig | 7 -
drivers/mtd/nand/raw/ingenic/Makefile | 1 -
drivers/mtd/nand/raw/ingenic/jz4740_nand.c | 536
--------------------------------------------------------------------------
drivers/power/supply/Kconfig | 11 --
drivers/power/supply/Makefile | 1 -
drivers/power/supply/jz4740-battery.c | 421
----------------------------------------------------------
drivers/video/fbdev/Kconfig | 9 --
drivers/video/fbdev/Makefile | 1 -
drivers/video/fbdev/jz4740_fb.c | 690
-----------------------------------------------------------------------------------------------
sound/soc/jz4740/Kconfig | 25 +---
sound/soc/jz4740/Makefile | 5 -
sound/soc/jz4740/qi_lb60.c | 106 ---------------
33 files changed, 404 insertions(+), 3809 deletions(-)
^ permalink raw reply
* Re: [PATCH 3/3] drm/bridge: Add NWL MIPI DSI host controller support
From: Laurent Pinchart @ 2019-07-27 2:47 UTC (permalink / raw)
To: Guido Günther
Cc: Mark Rutland, devicetree, Jernej Skrabec, Pengutronix Kernel Team,
Neil Armstrong, David Airlie, Jonas Karlman, linux-kernel,
dri-devel, Rob Herring, NXP Linux Team, Robert Chiras, Lee Jones,
Shawn Guo, linux-arm-kernel
In-Reply-To: <3158f4f8c97c21f98c394e5631d74bc60d796522.1563983037.git.agx@sigxcpu.org>
Hello Guido,
Thank you for the patch.
On Wed, Jul 24, 2019 at 05:52:26PM +0200, Guido Günther wrote:
> This adds initial support for the NWL MIPI DSI Host controller found on
> i.MX8 SoCs.
>
> It adds support for the i.MX8MQ but the same IP can be found on
> e.g. the i.MX8QXP.
>
> It has been tested on the Librem 5 devkit using mxsfb.
>
> Signed-off-by: Guido Günther <agx@sigxcpu.org>
> Co-developed-by: Robert Chiras <robert.chiras@nxp.com>
> ---
> drivers/gpu/drm/bridge/Kconfig | 2 +
> drivers/gpu/drm/bridge/Makefile | 1 +
> drivers/gpu/drm/bridge/imx-nwl/Kconfig | 15 +
> drivers/gpu/drm/bridge/imx-nwl/Makefile | 2 +
> drivers/gpu/drm/bridge/imx-nwl/nwl-drv.c | 529 ++++++++++++++++
> drivers/gpu/drm/bridge/imx-nwl/nwl-drv.h | 72 +++
> drivers/gpu/drm/bridge/imx-nwl/nwl-dsi.c | 745 +++++++++++++++++++++++
> drivers/gpu/drm/bridge/imx-nwl/nwl-dsi.h | 111 ++++
> 8 files changed, 1477 insertions(+)
> create mode 100644 drivers/gpu/drm/bridge/imx-nwl/Kconfig
> create mode 100644 drivers/gpu/drm/bridge/imx-nwl/Makefile
> create mode 100644 drivers/gpu/drm/bridge/imx-nwl/nwl-drv.c
> create mode 100644 drivers/gpu/drm/bridge/imx-nwl/nwl-drv.h
> create mode 100644 drivers/gpu/drm/bridge/imx-nwl/nwl-dsi.c
> create mode 100644 drivers/gpu/drm/bridge/imx-nwl/nwl-dsi.h
>
> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
> index a6eec908c43e..38c3145a7e57 100644
> --- a/drivers/gpu/drm/bridge/Kconfig
> +++ b/drivers/gpu/drm/bridge/Kconfig
> @@ -152,6 +152,8 @@ source "drivers/gpu/drm/bridge/analogix/Kconfig"
>
> source "drivers/gpu/drm/bridge/adv7511/Kconfig"
>
> +source "drivers/gpu/drm/bridge/imx-nwl/Kconfig"
> +
As this doesn't seem to be an i.MX-specific IP, I wouldn't use the name
imx in file names or in the code, at least in the parts that are not
NXP-specific.
> source "drivers/gpu/drm/bridge/synopsys/Kconfig"
>
> endmenu
> diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
> index 4934fcf5a6f8..904a9eb3a20a 100644
> --- a/drivers/gpu/drm/bridge/Makefile
> +++ b/drivers/gpu/drm/bridge/Makefile
> @@ -16,4 +16,5 @@ obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/
> obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/
> obj-$(CONFIG_DRM_TI_SN65DSI86) += ti-sn65dsi86.o
> obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o
> +obj-y += imx-nwl/
> obj-y += synopsys/
> diff --git a/drivers/gpu/drm/bridge/imx-nwl/Kconfig b/drivers/gpu/drm/bridge/imx-nwl/Kconfig
> new file mode 100644
> index 000000000000..822dba1b380a
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/imx-nwl/Kconfig
> @@ -0,0 +1,15 @@
> +config DRM_IMX_NWL_DSI
> + tristate "Support for Northwest Logic MIPI DSI Host controller"
> + depends on DRM && (ARCH_MXC || ARCH_MULTIPLATFORM || COMPILE_TEST)
> + depends on COMMON_CLK
> + depends on OF && HAS_IOMEM
> + select DRM_KMS_HELPER
> + select DRM_MIPI_DSI
> + select DRM_PANEL_BRIDGE
> + select GENERIC_PHY_MIPI_DPHY
> + select MFD_SYSCON
> + select REGMAP_MMIO
> + help
> + This enables the Northwest Logic MIPI DSI Host controller as
> + found on NXP's i.MX8 Processors.
> +
> diff --git a/drivers/gpu/drm/bridge/imx-nwl/Makefile b/drivers/gpu/drm/bridge/imx-nwl/Makefile
> new file mode 100644
> index 000000000000..9fa63483da5b
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/imx-nwl/Makefile
> @@ -0,0 +1,2 @@
> +imx-nwl-objs := nwl-drv.o nwl-dsi.o
> +obj-$(CONFIG_DRM_IMX_NWL_DSI) += imx-nwl.o
> diff --git a/drivers/gpu/drm/bridge/imx-nwl/nwl-drv.c b/drivers/gpu/drm/bridge/imx-nwl/nwl-drv.c
> new file mode 100644
> index 000000000000..451f8f067c6f
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/imx-nwl/nwl-drv.c
> @@ -0,0 +1,529 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * i.MX8 NWL MIPI DSI host driver
> + *
> + * Copyright (C) 2017 NXP
> + * Copyright (C) 2019 Purism SPC
> + */
> +
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_of.h>
> +#include <drm/drm_panel.h>
> +#include <drm/drm_print.h>
> +#include <drm/drm_probe_helper.h>
> +#include <linux/clk-provider.h>
This doesn't seem to be needed.
> +#include <linux/clk.h>
> +#include <linux/component.h>
Same here.
> +#include <linux/gpio/consumer.h>
> +#include <linux/irq.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/mfd/syscon/imx8mq-iomuxc-gpr.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/phy/phy.h>
> +#include <linux/regmap.h>
> +#include <linux/sys_soc.h>
> +#include <video/videomode.h>
> +
> +#include "nwl-drv.h"
> +#include "nwl-dsi.h"
> +
> +#define DRV_NAME "imx-nwl-dsi"
> +
> +/* 8MQ SRC specific registers */
> +#define SRC_MIPIPHY_RCR 0x28
> +#define RESET_BYTE_N BIT(1)
> +#define RESET_N BIT(2)
> +#define DPI_RESET_N BIT(3)
> +#define ESC_RESET_N BIT(4)
> +#define PCLK_RESET_N BIT(5)
> +
> +/* Possible clocks */
> +#define CLK_PIXEL "pixel"
> +#define CLK_CORE "core"
> +#define CLK_BYPASS "bypass"
> +
> +enum imx_ext_regs {
> + IMX_REG_CSR = BIT(1),
> + IMX_REG_SRC = BIT(2),
> + IMX_REG_GPR = BIT(3),
> +};
> +
> +static const struct regmap_config nwl_dsi_regmap_config = {
> + .reg_bits = 16,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .max_register = IRQ_MASK2,
> + .name = DRV_NAME,
> +};
> +
> +struct imx_nwl_platform_data {
> + int (*poweron)(struct imx_nwl_dsi *dsi);
> + int (*poweroff)(struct imx_nwl_dsi *dsi);
> + u32 ext_regs; /* required external registers */
> + struct imx_nwl_clk_config clk_config[NWL_MAX_PLATFORM_CLOCKS];
> +};
> +
> +static inline struct imx_nwl_dsi *bridge_to_dsi(struct drm_bridge *bridge)
> +{
> + return container_of(bridge, struct imx_nwl_dsi, bridge);
> +}
> +
> +static void imx_nwl_dsi_set_clocks(struct imx_nwl_dsi *dsi, bool enable)
> +{
> + struct device *dev = dsi->dev;
> + const char *id;
> + struct clk *clk;
> + unsigned long new_rate, cur_rate;
> + bool enabled;
> + size_t i;
> + int ret;
> +
> + DRM_DEV_DEBUG_DRIVER(dev, "%sabling platform clocks",
> + enable ? "en" : "dis");
> + for (i = 0; i < ARRAY_SIZE(dsi->pdata->clk_config); i++) {
> + if (!dsi->clk_config[i].present)
> + continue;
> + id = dsi->clk_config[i].id;
> + clk = dsi->clk_config[i].clk;
> + new_rate = dsi->clk_config[i].rate;
> + cur_rate = clk_get_rate(clk);
> + enabled = dsi->clk_config[i].enabled;
> +
> + /* BYPASS clk must have the same rate as PHY_REF clk */
> + if (!strcmp(id, CLK_BYPASS))
> + new_rate = clk_get_rate(dsi->phy_ref_clk);
> +
> + if (enable) {
> + if (enabled && new_rate != cur_rate)
> + clk_disable_unprepare(clk);
> + else if (enabled && new_rate == cur_rate)
> + continue;
> + if (new_rate > 0)
> + clk_set_rate(clk, new_rate);
> + ret = clk_prepare_enable(clk);
> + if (ret < 0) {
> + DRM_DEV_ERROR(dev, "Failed to enable clock %s",
> + id);
> + }
> + dsi->clk_config[i].enabled = true;
> + cur_rate = clk_get_rate(clk);
> + DRM_DEV_DEBUG_DRIVER(
> + dev, "Enabled %s clk (rate: req=%lu act=%lu)\n",
> + id, new_rate, cur_rate);
> + } else if (enabled) {
> + clk_disable_unprepare(clk);
> + dsi->clk_config[i].enabled = false;
> + DRM_DEV_DEBUG_DRIVER(dev, "Disabled %s clk\n", id);
> + }
> + }
> +}
> +
> +static void imx_nwl_dsi_enable(struct imx_nwl_dsi *dsi)
> +{
> + struct device *dev = dsi->dev;
> + int ret;
> +
> + imx_nwl_dsi_set_clocks(dsi, true);
> +
> + ret = dsi->pdata->poweron(dsi);
> + if (ret < 0)
> + DRM_DEV_ERROR(dev, "Failed to power on DSI (%d)\n", ret);
> +}
> +
> +static void imx_nwl_dsi_disable(struct imx_nwl_dsi *dsi)
> +{
> + struct device *dev = dsi->dev;
> +
> + if (dsi->dpms_mode != DRM_MODE_DPMS_ON)
> + return;
> +
The DRM core should guarantee that the bridge won't be disabled twice,
so I don't think you need this check. Similarly I think the enabled flag
in the imx_nwl_clk_config structure can be removed.
> + DRM_DEV_DEBUG_DRIVER(dev, "Disabling encoder");
Is this really needed ?
> + dsi->pdata->poweroff(dsi);
> + imx_nwl_dsi_set_clocks(dsi, false);
> +}
> +
> +static void imx_nwl_select_input_source(struct imx_nwl_dsi *dsi)
> +{
> + struct device_node *remote;
> + u32 mux_val = IMX8MQ_GPR13_MIPI_MUX_SEL;
> +
> + remote = of_graph_get_remote_node(dsi->dev->of_node, 0, 0);
> + if (strcmp(remote->name, "lcdif") == 0)
> + mux_val = 0;
> +
Can't you check the remote node at probe time instead of every time the
bridge gets enabled, and program the IO mux accordingly there ?
This code is i.MX-specific, so it should be isolated in an operation in
struct imx_nwl_platform_data.
> + DRM_DEV_INFO(dsi->dev, "Using %s as input source\n",
> + (mux_val) ? "DCSS" : "LCDIF");
> + regmap_update_bits(dsi->mux_sel, IOMUXC_GPR13,
> + IMX8MQ_GPR13_MIPI_MUX_SEL, mux_val);
> + of_node_put(remote);
> +}
> +
> +static void imx_nwl_dsi_bridge_disable(struct drm_bridge *bridge)
> +{
> + struct imx_nwl_dsi *dsi = bridge_to_dsi(bridge);
> +
> + if (dsi->dpms_mode != DRM_MODE_DPMS_ON)
> + return;
> +
> + nwl_dsi_disable(dsi);
> + imx_nwl_dsi_disable(dsi);
> + pm_runtime_put_sync(dsi->dev);
Do you need a put_sync, wouldn't a put do ?
> + dsi->dpms_mode = DRM_MODE_DPMS_OFF;
> +}
> +
> +static bool
> +imx_nwl_dsi_bridge_mode_fixup(struct drm_bridge *bridge,
> + const struct drm_display_mode *mode,
> + struct drm_display_mode *adjusted_mode)
> +{
> + struct imx_nwl_dsi *dsi = bridge_to_dsi(bridge);
> + struct device *dev = dsi->dev;
> + union phy_configure_opts new_cfg;
> + unsigned long phy_ref_rate;
> + int ret;
> +
> + ret = nwl_dsi_get_dphy_params(dsi, adjusted_mode, &new_cfg);
> + if (ret < 0)
> + return ret;
> +
> + /*
> + * If hs clock is unchanged, we're all good - all parameters are
> + * derived from it atm.
> + */
> + if (new_cfg.mipi_dphy.hs_clk_rate == dsi->phy_cfg.mipi_dphy.hs_clk_rate)
> + return true;
> +
> + phy_ref_rate = clk_get_rate(dsi->phy_ref_clk);
> + DRM_DEV_DEBUG_DRIVER(dev, "PHY at ref rate: %lu\n", phy_ref_rate);
> + if (ret < 0) {
This can't happen. Or are you missing a function call before the check ?
> + DRM_DEV_ERROR(dsi->dev,
> + "Cannot setup PHY for mode: %ux%u @%d Hz\n",
> + adjusted_mode->hdisplay, adjusted_mode->vdisplay,
> + adjusted_mode->clock);
> + DRM_DEV_ERROR(dsi->dev, "PHY ref clk: %lu, bit clk: %lu\n",
> + phy_ref_rate, new_cfg.mipi_dphy.hs_clk_rate);
> + } else {
> + /* Save the new desired phy config */
> + memcpy(&dsi->phy_cfg, &new_cfg, sizeof(new_cfg));
The mode_fixup operation shall not change the device state, it can be
called multiple times when trying modes.
> + }
> +
> + /* LCDIF + NWL needs active high sync */
> + adjusted_mode->flags |= (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
> + adjusted_mode->flags &= ~(DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC);
> +
> + drm_display_mode_to_videomode(adjusted_mode, &dsi->vm);
> + drm_mode_debug_printmodeline(adjusted_mode);
> +
> + return ret == 0;
return 0;
> +}
> +
> +static enum drm_mode_status
> +imx_nwl_dsi_bridge_mode_valid(struct drm_bridge *bridge,
> + const struct drm_display_mode *mode)
> +{
> + struct imx_nwl_dsi *dsi = bridge_to_dsi(bridge);
> + int bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
> +
> + if (bpp < 0) {
> + DRM_DEV_ERROR(dsi->dev, "Invalid pixel format: %d\n",
> + dsi->format);
> + return MODE_BAD;
> + }
The format isn't part of the mode, so this doesn't belong here. You
should here instead check that the mode clock and other timing data
(especially the visible resolution) are within the range supported by
the device.
> +
> + return MODE_OK;
> +}
> +
> +static void imx_nwl_dsi_bridge_pre_enable(struct drm_bridge *bridge)
> +{
> + struct imx_nwl_dsi *dsi = bridge_to_dsi(bridge);
> +
> + if (dsi->dpms_mode == DRM_MODE_DPMS_ON)
> + return;
> +
> + imx_nwl_select_input_source(dsi);
> + pm_runtime_get_sync(dsi->dev);
> + imx_nwl_dsi_enable(dsi);
> + nwl_dsi_enable(dsi);
> + dsi->dpms_mode = DRM_MODE_DPMS_ON;
> +}
> +
> +static int imx_nwl_dsi_bridge_attach(struct drm_bridge *bridge)
> +{
> + struct imx_nwl_dsi *dsi = bridge->driver_private;
> + struct drm_encoder *encoder = bridge->encoder;
> +
> + if (!encoder) {
> + DRM_DEV_ERROR(dsi->dev, "Parent encoder object not found\n");
> + return -ENODEV;
> + }
Can't this happen ?
> +
> + /* Set the encoder type as caller does not know it */
> + bridge->encoder->encoder_type = DRM_MODE_ENCODER_DSI;
The encoder type is quite meaningless and userspace should not depend on
it, so I wouldn't set it here, especially that the encoder may not
expect the bridge to override its type.
> +
> + /* Attach the panel-bridge to the dsi bridge */
> + return drm_bridge_attach(bridge->encoder, dsi->panel_bridge, bridge);
> +}
> +
> +static void imx_nwl_dsi_bridge_detach(struct drm_bridge *bridge)
> +{
> + struct imx_nwl_dsi *dsi = bridge->driver_private;
> +
> + drm_of_panel_bridge_remove(dsi->dev->of_node, 1, 0);
This is already done in nwl_dsi_host_detach().
> +}
> +
> +/* see dw-mipi-dsi.c */
What for ? :-)
> +static const struct drm_bridge_funcs imx_nwl_dsi_bridge_funcs = {
> + .pre_enable = imx_nwl_dsi_bridge_pre_enable,
> + .disable = imx_nwl_dsi_bridge_disable,
> + .mode_fixup = imx_nwl_dsi_bridge_mode_fixup,
> + .mode_valid = imx_nwl_dsi_bridge_mode_valid,
> + .attach = imx_nwl_dsi_bridge_attach,
> + .detach = imx_nwl_dsi_bridge_detach,
> +};
> +
> +static int imx_nwl_dsi_parse_dt(struct imx_nwl_dsi *dsi)
> +{
> + struct device_node *np = dsi->dev->of_node;
> + struct platform_device *pdev = to_platform_device(dsi->dev);
> + struct resource *res;
> + struct clk *clk;
> + const char *clk_id;
> + void __iomem *base;
> + int i, ret;
> +
> + dsi->phy = devm_phy_get(dsi->dev, "dphy");
> + if (IS_ERR(dsi->phy)) {
> + ret = PTR_ERR(dsi->phy);
> + dev_err(dsi->dev, "Could not get PHY (%d)\n", ret);
> + return ret;
> + }
> +
> + /* Platform dependent clocks */
> + memcpy(dsi->clk_config, dsi->pdata->clk_config,
> + sizeof(dsi->pdata->clk_config));
> +
> + for (i = 0; i < ARRAY_SIZE(dsi->pdata->clk_config); i++) {
> + if (!dsi->clk_config[i].present)
> + continue;
> +
> + clk_id = dsi->clk_config[i].id;
> + clk = devm_clk_get(dsi->dev, clk_id);
> + if (IS_ERR(clk)) {
> + ret = PTR_ERR(clk);
> + dev_err(dsi->dev, "Failed to get %s clock (%d)\n",
> + clk_id, ret);
> + return ret;
> + }
> + DRM_DEV_DEBUG_DRIVER(dsi->dev, "Setup clk %s (rate: %lu)\n",
> + clk_id, clk_get_rate(clk));
> + dsi->clk_config[i].clk = clk;
> + }
> +
> + /* DSI clocks */
> + clk = devm_clk_get(dsi->dev, "phy_ref");
> + if (IS_ERR(clk)) {
> + ret = PTR_ERR(clk);
> + dev_err(dsi->dev, "Failed to get phy_ref clock: %d\n", ret);
> + return ret;
> + }
> + dsi->phy_ref_clk = clk;
> +
> + clk = devm_clk_get(dsi->dev, "rx_esc");
> + if (IS_ERR(clk)) {
> + ret = PTR_ERR(clk);
> + dev_err(dsi->dev, "Failed to get rx_esc clock: %d\n", ret);
> + return ret;
> + }
> + dsi->rx_esc_clk = clk;
> +
> + clk = devm_clk_get(dsi->dev, "tx_esc");
> + if (IS_ERR(clk)) {
> + ret = PTR_ERR(clk);
> + dev_err(dsi->dev, "Failed to get tx_esc clock: %d\n", ret);
> + return ret;
> + }
> + dsi->tx_esc_clk = clk;
> +
> + dsi->csr = syscon_regmap_lookup_by_phandle(np, "csr");
> + if (IS_ERR(dsi->csr) && dsi->pdata->ext_regs & IMX_REG_CSR) {
> + ret = PTR_ERR(dsi->csr);
> + DRM_DEV_ERROR(dsi->dev, "Failed to get CSR regmap: %d\n",
> + ret);
> + return ret;
> + }
This doesn't seem to be used anywhere.
> + dsi->reset = syscon_regmap_lookup_by_phandle(np, "src");
> + if (IS_ERR(dsi->reset) && (dsi->pdata->ext_regs & IMX_REG_SRC)) {
> + ret = PTR_ERR(dsi->reset);
> + DRM_DEV_ERROR(dsi->dev, "Failed to get SRC regmap: %d\n",
> + ret);
> + return ret;
> + }
Couldn't you model a reset controller in that syscon, and use the reset
controller API here ? It would allow moving the i.MX-specific power on
and off functions from this driver, making it more generic.
> + dsi->mux_sel = syscon_regmap_lookup_by_phandle(np, "mux-sel");
> + if (IS_ERR(dsi->mux_sel) && (dsi->pdata->ext_regs & IMX_REG_GPR)) {
> + ret = PTR_ERR(dsi->mux_sel);
> + DRM_DEV_ERROR(dsi->dev, "Failed to get GPR regmap: %d\n",
> + ret);
> + return ret;
> + }
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + base = devm_ioremap_resource(dsi->dev, res);
You can replace those two calls with devm_platform_ioremap_resource().
> + if (IS_ERR(base))
> + return PTR_ERR(base);
> +
> + dsi->regmap =
> + devm_regmap_init_mmio(dsi->dev, base, &nwl_dsi_regmap_config);
> + if (IS_ERR(dsi->regmap)) {
> + ret = PTR_ERR(dsi->regmap);
> + DRM_DEV_ERROR(dsi->dev,
> + "Failed to create NWL DSI regmap: %d\n", ret);
> + return ret;
> + }
> +
> + dsi->irq = platform_get_irq(pdev, 0);
> + if (dsi->irq < 0) {
> + DRM_DEV_ERROR(dsi->dev, "Failed to get device IRQ: %d\n",
> + dsi->irq);
> + return dsi->irq;
> + }
> +
> + return 0;
> +}
> +
> +static int imx8mq_dsi_poweron(struct imx_nwl_dsi *dsi)
> +{
> + /* otherwise the display stays blank */
> + usleep_range(200, 300);
> +
> + regmap_update_bits(dsi->reset, SRC_MIPIPHY_RCR, PCLK_RESET_N,
> + PCLK_RESET_N);
> + regmap_update_bits(dsi->reset, SRC_MIPIPHY_RCR, ESC_RESET_N,
> + ESC_RESET_N);
> + regmap_update_bits(dsi->reset, SRC_MIPIPHY_RCR, RESET_BYTE_N,
> + RESET_BYTE_N);
> + regmap_update_bits(dsi->reset, SRC_MIPIPHY_RCR, DPI_RESET_N,
> + DPI_RESET_N);
> +
> + return 0;
> +}
> +
> +static int imx8mq_dsi_poweroff(struct imx_nwl_dsi *dsi)
> +{
> + if (USE_SRC_RESET_QUIRK(dsi->quirks))
> + return 0;
> +
> + regmap_update_bits(dsi->reset, SRC_MIPIPHY_RCR, PCLK_RESET_N, 0);
> + regmap_update_bits(dsi->reset, SRC_MIPIPHY_RCR, ESC_RESET_N, 0);
> + regmap_update_bits(dsi->reset, SRC_MIPIPHY_RCR, RESET_BYTE_N, 0);
> + regmap_update_bits(dsi->reset, SRC_MIPIPHY_RCR, DPI_RESET_N, 0);
> + return 0;
> +}
> +
> +static const struct drm_bridge_timings imx_nwl_timings = {
> + .input_bus_flags = DRM_BUS_FLAG_DE_LOW,
> +};
> +
> +static struct imx_nwl_platform_data imx8mq_dev = {
This structure should be const, especially as it contains function
pointers.
> + .poweron = &imx8mq_dsi_poweron,
> + .poweroff = &imx8mq_dsi_poweroff,
> + .clk_config = {
> + { .id = CLK_CORE, .present = true },
> + { .id = CLK_PIXEL, .present = false },
> + { .id = CLK_BYPASS, .present = false },
> + },
> + .ext_regs = IMX_REG_SRC | IMX_REG_GPR,
> +};
> +
> +static const struct of_device_id imx_nwl_dsi_dt_ids[] = {
> + { .compatible = "fsl,imx8mq-nwl-dsi", .data = &imx8mq_dev, },
> + { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, imx_nwl_dsi_dt_ids);
> +
> +static const struct soc_device_attribute imx_nwl_quirks_match[] = {
> + { .soc_id = "i.MX8MQ", .revision = "2.0",
> + .data = (void *)(E11418_HS_MODE_QUIRK | SRC_RESET_QUIRK) },
> + { /* sentinel. */ },
> +};
> +
> +static int imx_nwl_dsi_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + const struct of_device_id *of_id =
> + of_match_device(imx_nwl_dsi_dt_ids, dev);
> + const struct imx_nwl_platform_data *pdata = of_id->data;
> + const struct soc_device_attribute *attr;
> + struct imx_nwl_dsi *dsi;
> + int ret;
> +
> + dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
> + if (!dsi)
> + return -ENOMEM;
> +
> + dsi->dev = dev;
> + dsi->pdata = pdata;
> + dsi->dpms_mode = DRM_MODE_DPMS_OFF;
DPMS is legacy, let's not use it within the driver.
> +
> + ret = imx_nwl_dsi_parse_dt(dsi);
> + if (ret)
> + return ret;
> +
> + ret = devm_request_irq(dev, dsi->irq, nwl_dsi_irq_handler, 0,
> + dev_name(dev), dsi);
> + if (ret < 0) {
> + DRM_DEV_ERROR(dev, "Failed to request IRQ: %d (%d)\n", dsi->irq,
> + ret);
> + return ret;
> + }
> +
> + dsi->dsi_host.ops = &nwl_dsi_host_ops;
> + dsi->dsi_host.dev = dev;
> + ret = mipi_dsi_host_register(&dsi->dsi_host);
> + if (ret) {
> + DRM_DEV_ERROR(dev, "Failed to register MIPI host: %d\n", ret);
> + goto err_cleanup;
> + }
> +
> + attr = soc_device_match(imx_nwl_quirks_match);
> + if (attr)
> + dsi->quirks = (uintptr_t)attr->data;
> +
> + dsi->bridge.driver_private = dsi;
> + dsi->bridge.funcs = &imx_nwl_dsi_bridge_funcs;
> + dsi->bridge.of_node = dev->of_node;
> + dsi->bridge.timings = &imx_nwl_timings;
> +
> + drm_bridge_add(&dsi->bridge);
> +
> + dev_set_drvdata(dev, dsi);
> + pm_runtime_enable(dev);
> + return 0;
> +
> +err_cleanup:
> + devm_free_irq(dev, dsi->irq, dsi);
> + return ret;
> +}
> +
> +static int imx_nwl_dsi_remove(struct platform_device *pdev)
> +{
> + pm_runtime_disable(&pdev->dev);
You should call drm_bridge_remove() here, not in nwl_dsi_host_detach().
> + return 0;
> +}
> +
> +static struct platform_driver imx_nwl_dsi_driver = {
> + .probe = imx_nwl_dsi_probe,
> + .remove = imx_nwl_dsi_remove,
> + .driver = {
> + .of_match_table = imx_nwl_dsi_dt_ids,
> + .name = DRV_NAME,
> + },
> +};
> +
> +module_platform_driver(imx_nwl_dsi_driver);
> +
> +MODULE_AUTHOR("NXP Semiconductor");
> +MODULE_AUTHOR("Purism SPC");
> +MODULE_DESCRIPTION("i.MX8 Northwest Logic MIPI-DSI driver");
> +MODULE_LICENSE("GPL"); /* GPLv2 or later */
> diff --git a/drivers/gpu/drm/bridge/imx-nwl/nwl-drv.h b/drivers/gpu/drm/bridge/imx-nwl/nwl-drv.h
> new file mode 100644
> index 000000000000..a1e30c58b627
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/imx-nwl/nwl-drv.h
> @@ -0,0 +1,72 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * i.MX8 NWL MIPI DSI host driver
> + *
> + * Copyright (C) 2017 NXP
> + * Copyright (C) 2019 Purism SPC
> + */
> +
> +#ifndef __NWL_DRV_H__
> +#define __NWL_DRV_H__
> +
> +#include <drm/drm_mipi_dsi.h>
> +#include <linux/phy/phy.h>
> +
> +struct imx_nwl_platform_data;
> +
> +/* i.MX8 NWL quirks */
> +/* i.MX8MQ errata E11418 */
> +#define E11418_HS_MODE_QUIRK BIT(0)
> +#define USE_E11418_HS_MODE_QUIRK(x) ((x) & E11418_HS_MODE_QUIRK)
> +
> +/* Skip DSI bits in SRC on disable to avoid blank display on enable */
> +#define SRC_RESET_QUIRK BIT(1)
> +#define USE_SRC_RESET_QUIRK(x) ((x) & SRC_RESET_QUIRK)
The USE_* macros are not shorter to type, so I would type out the &
check explicitly.
> +
> +#define NWL_MAX_PLATFORM_CLOCKS 3
> +struct imx_nwl_clk_config {
> + const char *id;
> + struct clk *clk;
> + bool present;
> + bool enabled;
> + u32 rate;
> +};
> +
> +struct imx_nwl_dsi {
> + struct drm_bridge bridge;
> + struct mipi_dsi_host dsi_host;
> + struct drm_bridge *panel_bridge;
> + struct device *dev;
> + struct phy *phy;
> + union phy_configure_opts phy_cfg;
> + unsigned int quirks;
> +
> + struct regmap *regmap;
> + int irq;
> +
> + /* External registers */
> + struct regmap *csr;
> + struct regmap *mux_sel;
> + struct regmap *reset;
> +
> + /* Platform dependent clocks */
> + struct imx_nwl_clk_config clk_config[3];
I would use NWL_MAX_PLATFORM_CLOCKS instead of 3 as
imx_nwl_platform_data uses the macro.
> + /* DSI clocks */
> + struct clk *phy_ref_clk;
> + struct clk *rx_esc_clk;
> + struct clk *tx_esc_clk;
> +
> + /* dsi lanes */
> + u32 lanes;
> + enum mipi_dsi_pixel_format format;
> + struct videomode vm;
> + unsigned long dsi_mode_flags;
> +
> + int dpms_mode;
> +
> + struct mipi_dsi_transfer *xfer;
> +
> + const struct imx_nwl_platform_data *pdata;
> +};
> +
> +#endif /* __NWL_DRV_H__ */
> diff --git a/drivers/gpu/drm/bridge/imx-nwl/nwl-dsi.c b/drivers/gpu/drm/bridge/imx-nwl/nwl-dsi.c
> new file mode 100644
> index 000000000000..0e1463af162f
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/imx-nwl/nwl-dsi.c
> @@ -0,0 +1,745 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * NWL DSI host driver
> + *
> + * Copyright (C) 2017 NXP
> + * Copyright (C) 2019 Purism SPC
> + */
> +
> +#include <asm/unaligned.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_of.h>
> +#include <drm/drm_panel.h>
> +#include <drm/drm_print.h>
> +#include <linux/clk.h>
> +#include <linux/irq.h>
> +#include <linux/regmap.h>
> +#include <video/mipi_display.h>
> +#include <video/videomode.h>
> +
> +#include "nwl-drv.h"
> +#include "nwl-dsi.h"
> +
> +#define MIPI_FIFO_TIMEOUT msecs_to_jiffies(500)
> +
> +/* PKT reg bit manipulation */
> +#define REG_MASK(e, s) (((1 << ((e) - (s) + 1)) - 1) << (s))
> +#define REG_PUT(x, e, s) (((x) << (s)) & REG_MASK(e, s))
> +#define REG_GET(x, e, s) (((x) & REG_MASK(e, s)) >> (s))
Let's not reinvent the wheel, linux/bits.h and linux/bitfield.h can be
used instead.
> +
> +/*
> + * PKT_CONTROL format:
> + * [15: 0] - word count
> + * [17:16] - virtual channel
> + * [23:18] - data type
> + * [24] - LP or HS select (0 - LP, 1 - HS)
> + * [25] - perform BTA after packet is sent
> + * [26] - perform BTA only, no packet tx
> + */
> +#define WC(x) REG_PUT((x), 15, 0)
> +#define TX_VC(x) REG_PUT((x), 17, 16)
> +#define TX_DT(x) REG_PUT((x), 23, 18)
> +#define HS_SEL(x) REG_PUT((x), 24, 24)
> +#define BTA_TX(x) REG_PUT((x), 25, 25)
> +#define BTA_NO_TX(x) REG_PUT((x), 26, 26)
> +
> +/*
> + * RX_PKT_HEADER format:
> + * [15: 0] - word count
> + * [21:16] - data type
> + * [23:22] - virtual channel
> + */
> +#define RX_DT(x) REG_GET((x), 21, 16)
> +#define RX_VC(x) REG_GET((x), 23, 22)
> +
> +/*
> + * DSI Video mode
> + */
> +#define VIDEO_MODE_BURST_MODE_WITH_SYNC_PULSES 0
> +#define VIDEO_MODE_NON_BURST_MODE_WITH_SYNC_EVENTS BIT(0)
> +#define VIDEO_MODE_BURST_MODE BIT(1)
> +
> +/*
> + * DPI color coding
> + */
> +#define DPI_16_BIT_565_PACKED 0
> +#define DPI_16_BIT_565_ALIGNED 1
> +#define DPI_16_BIT_565_SHIFTED 2
> +#define DPI_18_BIT_PACKED 3
> +#define DPI_18_BIT_ALIGNED 4
> +#define DPI_24_BIT 5
> +
> +/*
> + * DPI Pixel format
> + */
> +#define PIXEL_FORMAT_16 0
> +#define PIXEL_FORMAT_18 BIT(0)
> +#define PIXEL_FORMAT_18L BIT(1)
> +#define PIXEL_FORMAT_24 (BIT(0) | BIT(1))
> +
> +enum transfer_direction { DSI_PACKET_SEND, DSI_PACKET_RECEIVE };
Line breaks please.
> +
> +struct mipi_dsi_transfer {
Let's not use such a generic name for a driver-specific structure. You
should name is nwl_dsi_transfer.
> + const struct mipi_dsi_msg *msg;
> + struct mipi_dsi_packet packet;
> + struct completion completed;
> +
> + int status; /* status of transmission */
> + enum transfer_direction direction;
> + bool need_bta;
> + u8 cmd;
> + u16 rx_word_count;
> + size_t tx_len; /* bytes sent */
> + size_t rx_len; /* bytes received */
> +};
> +
> +static inline int nwl_dsi_write(struct imx_nwl_dsi *dsi, unsigned int reg,
> + u32 val)
> +{
> + int ret;
> +
> + ret = regmap_write(dsi->regmap, reg, val);
> + if (ret < 0)
> + DRM_DEV_ERROR(dsi->dev,
> + "Failed to write NWL DSI reg 0x%x: %d\n", reg,
> + ret);
> + return ret;
> +}
> +
> +static inline u32 nwl_dsi_read(struct imx_nwl_dsi *dsi, u32 reg)
> +{
> + unsigned int val;
> + int ret;
> +
> + ret = regmap_read(dsi->regmap, reg, &val);
> + if (ret < 0)
> + DRM_DEV_ERROR(dsi->dev, "Failed to read NWL DSI reg 0x%x: %d\n",
> + reg, ret);
> +
> + return val;
You're loosing the error...
> +}
> +
> +static u32 nwl_dsi_get_dpi_pixel_format(enum mipi_dsi_pixel_format format)
> +{
> + switch (format) {
> + case MIPI_DSI_FMT_RGB565:
> + return PIXEL_FORMAT_16;
> + case MIPI_DSI_FMT_RGB666:
> + return PIXEL_FORMAT_18L;
> + case MIPI_DSI_FMT_RGB666_PACKED:
> + return PIXEL_FORMAT_18;
> + case MIPI_DSI_FMT_RGB888:
> + return PIXEL_FORMAT_24;
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +int nwl_dsi_get_dphy_params(struct imx_nwl_dsi *dsi,
> + const struct drm_display_mode *mode,
> + union phy_configure_opts *phy_opts)
> +{
> + unsigned long rate;
> +
> + if (dsi->lanes < 1 || dsi->lanes > 4)
> + return -EINVAL;
> +
> + /*
> + * So far the DPHY spec minimal timings work for both mixel
> + * dphy and nwl dsi host
> + */
> + phy_mipi_dphy_get_default_config(
> + mode->crtc_clock * 1000,
> + mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes,
> + &phy_opts->mipi_dphy);
> + rate = clk_get_rate(dsi->tx_esc_clk);
> + DRM_DEV_DEBUG_DRIVER(dsi->dev, "LP clk is @%lu Hz\n", rate);
> + phy_opts->mipi_dphy.lp_clk_rate = rate;
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(nwl_dsi_get_dphy_params);
No need to export symbols, those fubctions are only meant to be called
from within the same module.
> +
> +#define PSEC_PER_SEC 1000000000000LL
> +/*
> + * ps2bc - Picoseconds to byte clock cycles
> + */
> +static u32 ps2bc(struct imx_nwl_dsi *dsi, unsigned long long ps)
> +{
> + int bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
> +
> + return DIV_ROUND_UP(ps * dsi->vm.pixelclock * bpp,
> + dsi->lanes * 8 * PSEC_PER_SEC);
> +}
> +
> +/**
> + * ui2bc - UI time periods to byte clock cycles
> + */
> +static u32 ui2bc(struct imx_nwl_dsi *dsi, unsigned long long ui)
> +{
> + int bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
> +
> + return DIV_ROUND_UP(ui * dsi->lanes, dsi->vm.pixelclock * bpp);
> +}
> +
> +#define USEC_PER_SEC 1000000L
> +/*
> + * us2bc - micro seconds to lp clock cycles
> + */
> +static u32 us2lp(u32 lp_clk_rate, unsigned long us)
> +{
> + return DIV_ROUND_UP(us * lp_clk_rate, USEC_PER_SEC);
> +}
> +
> +static int nwl_dsi_config_host(struct imx_nwl_dsi *dsi)
> +{
> + u32 cycles;
> + struct phy_configure_opts_mipi_dphy *cfg = &dsi->phy_cfg.mipi_dphy;
> +
> + if (dsi->lanes < 1 || dsi->lanes > 4)
> + return -EINVAL;
> +
> + DRM_DEV_DEBUG_DRIVER(dsi->dev, "DSI Lanes %d\n", dsi->lanes);
> + nwl_dsi_write(dsi, CFG_NUM_LANES, dsi->lanes - 1);
> +
> + if (dsi->dsi_mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) {
> + nwl_dsi_write(dsi, CFG_NONCONTINUOUS_CLK, 0x01);
> + nwl_dsi_write(dsi, CFG_AUTOINSERT_EOTP, 0x01);
> + } else {
> + nwl_dsi_write(dsi, CFG_NONCONTINUOUS_CLK, 0x00);
> + nwl_dsi_write(dsi, CFG_AUTOINSERT_EOTP, 0x00);
> + }
> +
> + /* values in byte clock cycles */
> + cycles = ui2bc(dsi, cfg->clk_pre);
> + DRM_DEV_DEBUG_DRIVER(dsi->dev, "cfg_t_pre: 0x%x\n", cycles);
> + nwl_dsi_write(dsi, CFG_T_PRE, cycles);
> + cycles = ps2bc(dsi, cfg->lpx + cfg->clk_prepare + cfg->clk_zero);
> + DRM_DEV_DEBUG_DRIVER(dsi->dev, "cfg_tx_gap (pre): 0x%x\n", cycles);
> + cycles += ui2bc(dsi, cfg->clk_pre);
> + DRM_DEV_DEBUG_DRIVER(dsi->dev, "cfg_tx_gap: 0x%x\n", cycles);
> + nwl_dsi_write(dsi, CFG_T_POST, cycles);
> + cycles = ps2bc(dsi, cfg->hs_exit);
> + DRM_DEV_DEBUG_DRIVER(dsi->dev, "cfg_tx_gap: 0x%x\n", cycles);
> + nwl_dsi_write(dsi, CFG_TX_GAP, cycles);
> +
> + nwl_dsi_write(dsi, CFG_EXTRA_CMDS_AFTER_EOTP, 0x01);
> + nwl_dsi_write(dsi, CFG_HTX_TO_COUNT, 0x00);
> + nwl_dsi_write(dsi, CFG_LRX_H_TO_COUNT, 0x00);
> + nwl_dsi_write(dsi, CFG_BTA_H_TO_COUNT, 0x00);
> + /* In LP clock cycles */
> + cycles = us2lp(cfg->lp_clk_rate, cfg->wakeup);
> + DRM_DEV_DEBUG_DRIVER(dsi->dev, "cfg_twakeup: 0x%x\n", cycles);
> + nwl_dsi_write(dsi, CFG_TWAKEUP, cycles);
> +
> + return 0;
> +}
> +
> +static int nwl_dsi_config_dpi(struct imx_nwl_dsi *dsi)
> +{
> + struct videomode *vm = &dsi->vm;
> + u32 color_format, mode;
> + bool burst_mode;
> +
> + DRM_DEV_DEBUG_DRIVER(dsi->dev, "hfront_porch = %d\n", vm->hfront_porch);
> + DRM_DEV_DEBUG_DRIVER(dsi->dev, "hback_porch = %d\n", vm->hback_porch);
> + DRM_DEV_DEBUG_DRIVER(dsi->dev, "hsync_len = %d\n", vm->hsync_len);
> + DRM_DEV_DEBUG_DRIVER(dsi->dev, "hactive = %d\n", vm->hactive);
> + DRM_DEV_DEBUG_DRIVER(dsi->dev, "vfront_porch = %d\n", vm->vfront_porch);
> + DRM_DEV_DEBUG_DRIVER(dsi->dev, "vback_porch = %d\n", vm->vback_porch);
> + DRM_DEV_DEBUG_DRIVER(dsi->dev, "vsync_len = %d\n", vm->vsync_len);
> + DRM_DEV_DEBUG_DRIVER(dsi->dev, "vactive = %d\n", vm->vactive);
> + DRM_DEV_DEBUG_DRIVER(dsi->dev, "clock = %lu kHz\n",
> + vm->pixelclock / 1000);
> +
> + color_format = nwl_dsi_get_dpi_pixel_format(dsi->format);
> + if (color_format < 0) {
> + DRM_DEV_ERROR(dsi->dev, "Invalid color format 0x%x\n",
> + dsi->format);
> + return color_format;
> + }
> + DRM_DEV_DEBUG_DRIVER(dsi->dev, "pixel fmt = %d\n", dsi->format);
> +
> + nwl_dsi_write(dsi, INTERFACE_COLOR_CODING, DPI_24_BIT);
> + nwl_dsi_write(dsi, PIXEL_FORMAT, color_format);
> + /*
> + * Adjusting input polarity based on the video mode results in
> + * a black screen so always pick active low:
> + */
> + nwl_dsi_write(dsi, VSYNC_POLARITY, VSYNC_POLARITY_ACTIVE_LOW);
> + nwl_dsi_write(dsi, HSYNC_POLARITY, HSYNC_POLARITY_ACTIVE_LOW);
> +
> + burst_mode = (dsi->dsi_mode_flags & MIPI_DSI_MODE_VIDEO_BURST) &&
> + !(dsi->dsi_mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE);
> +
> + if (burst_mode) {
> + nwl_dsi_write(dsi, VIDEO_MODE, VIDEO_MODE_BURST_MODE);
> + nwl_dsi_write(dsi, PIXEL_FIFO_SEND_LEVEL, 256);
> + } else {
> + mode = ((dsi->dsi_mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) ?
> + VIDEO_MODE_BURST_MODE_WITH_SYNC_PULSES :
> + VIDEO_MODE_NON_BURST_MODE_WITH_SYNC_EVENTS);
> + nwl_dsi_write(dsi, VIDEO_MODE, mode);
> + nwl_dsi_write(dsi, PIXEL_FIFO_SEND_LEVEL, vm->hactive);
> + }
> +
> + nwl_dsi_write(dsi, HFP, vm->hfront_porch);
> + nwl_dsi_write(dsi, HBP, vm->hback_porch);
> + nwl_dsi_write(dsi, HSA, vm->hsync_len);
> +
> + nwl_dsi_write(dsi, ENABLE_MULT_PKTS, 0x0);
> + nwl_dsi_write(dsi, BLLP_MODE, 0x1);
> + nwl_dsi_write(dsi, ENABLE_MULT_PKTS, 0x0);
> + nwl_dsi_write(dsi, USE_NULL_PKT_BLLP, 0x0);
> + nwl_dsi_write(dsi, VC, 0x0);
> +
> + nwl_dsi_write(dsi, PIXEL_PAYLOAD_SIZE, vm->hactive);
> + nwl_dsi_write(dsi, VACTIVE, vm->vactive - 1);
> + nwl_dsi_write(dsi, VBP, vm->vback_porch);
> + nwl_dsi_write(dsi, VFP, vm->vfront_porch);
> +
> + return 0;
> +}
> +
> +static int nwl_dsi_enable_tx_clock(struct imx_nwl_dsi *dsi)
> +{
> + struct device *dev = dsi->dev;
> + int ret;
> +
> + ret = clk_prepare_enable(dsi->tx_esc_clk);
> + if (ret < 0) {
> + DRM_DEV_ERROR(dev, "Failed to enable tx_esc clk: %d\n", ret);
> + return ret;
> + }
> +
> + DRM_DEV_DEBUG_DRIVER(dev, "Enabled tx_esc clk @%lu Hz\n",
> + clk_get_rate(dsi->tx_esc_clk));
> + return 0;
> +}
> +
> +static int nwl_dsi_enable_rx_clock(struct imx_nwl_dsi *dsi)
> +{
> + struct device *dev = dsi->dev;
> + int ret;
> +
> + ret = clk_prepare_enable(dsi->rx_esc_clk);
> + if (ret < 0) {
> + DRM_DEV_ERROR(dev, "Failed to enable rx_esc clk: %d\n", ret);
> + return ret;
> + }
> +
> + DRM_DEV_DEBUG_DRIVER(dev, "Enabled rx_esc clk @%lu Hz\n",
> + clk_get_rate(dsi->rx_esc_clk));
> + return 0;
> +}
> +
> +static void nwl_dsi_init_interrupts(struct imx_nwl_dsi *dsi)
> +{
> + u32 irq_enable;
> +
> + nwl_dsi_write(dsi, IRQ_MASK, 0xffffffff);
> + nwl_dsi_write(dsi, IRQ_MASK2, 0x7);
> +
> + irq_enable = ~(u32)(TX_PKT_DONE_MASK | RX_PKT_HDR_RCVD_MASK |
> + TX_FIFO_OVFLW_MASK | HS_TX_TIMEOUT_MASK);
> +
> + nwl_dsi_write(dsi, IRQ_MASK, irq_enable);
> +}
> +
> +static int nwl_dsi_host_attach(struct mipi_dsi_host *dsi_host,
> + struct mipi_dsi_device *device)
> +{
> + struct imx_nwl_dsi *dsi =
> + container_of(dsi_host, struct imx_nwl_dsi, dsi_host);
> + struct device *dev = dsi->dev;
> + struct drm_bridge *bridge;
> + struct drm_panel *panel;
> + int ret;
> +
> + DRM_DEV_INFO(dev, "lanes=%u, format=0x%x flags=0x%lx\n", device->lanes,
> + device->format, device->mode_flags);
> +
> + if (device->lanes < 1 || device->lanes > 4)
> + return -EINVAL;
> +
> + dsi->lanes = device->lanes;
> + dsi->format = device->format;
> + dsi->dsi_mode_flags = device->mode_flags;
> +
> + ret = drm_of_find_panel_or_bridge(dsi->dev->of_node, 1, 0, &panel,
> + &bridge);
> + if (ret)
> + return ret;
> +
> + if (panel) {
> + bridge = drm_panel_bridge_add(panel, DRM_MODE_CONNECTOR_DSI);
> + if (IS_ERR(bridge))
> + return PTR_ERR(bridge);
> + }
> +
> + dsi->panel_bridge = bridge;
> + drm_bridge_add(&dsi->bridge);
> +
> + return 0;
> +}
> +
> +static int nwl_dsi_host_detach(struct mipi_dsi_host *dsi_host,
> + struct mipi_dsi_device *device)
> +{
> + struct imx_nwl_dsi *dsi =
> + container_of(dsi_host, struct imx_nwl_dsi, dsi_host);
> +
> + drm_of_panel_bridge_remove(dsi->dev->of_node, 1, 0);
> + drm_bridge_remove(&dsi->bridge);
> +
> + return 0;
> +}
> +
> +static bool nwl_dsi_read_packet(struct imx_nwl_dsi *dsi, u32 status)
> +{
> + struct device *dev = dsi->dev;
> + struct mipi_dsi_transfer *xfer = dsi->xfer;
> + u8 *payload = xfer->msg->rx_buf;
> + u32 val;
> + u16 word_count;
> + u8 channel;
> + u8 data_type;
> +
> + xfer->status = 0;
> +
> + if (xfer->rx_word_count == 0) {
> + if (!(status & RX_PKT_HDR_RCVD))
> + return false;
> + /* Get the RX header and parse it */
> + val = nwl_dsi_read(dsi, RX_PKT_HEADER);
> + word_count = WC(val);
> + channel = RX_VC(val);
> + data_type = RX_DT(val);
> +
> + if (channel != xfer->msg->channel) {
> + DRM_DEV_ERROR(dev,
> + "[%02X] Channel mismatch (%u != %u)\n",
> + xfer->cmd, channel, xfer->msg->channel);
> + return true;
> + }
> +
> + switch (data_type) {
> + case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE:
> + /* Fall through */
> + case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
> + if (xfer->msg->rx_len > 1) {
> + /* read second byte */
> + payload[1] = word_count >> 8;
> + ++xfer->rx_len;
> + }
> + /* Fall through */
> + case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE:
> + /* Fall through */
> + case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
> + if (xfer->msg->rx_len > 0) {
> + /* read first byte */
> + payload[0] = word_count & 0xff;
> + ++xfer->rx_len;
> + }
> + xfer->status = xfer->rx_len;
> + return true;
> + case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
> + word_count &= 0xff;
> + DRM_DEV_ERROR(dev, "[%02X] DSI error report: 0x%02x\n",
> + xfer->cmd, word_count);
> + xfer->status = -EPROTO;
> + return true;
> + }
> +
> + if (word_count > xfer->msg->rx_len) {
> + DRM_DEV_ERROR(
> + dev,
> + "[%02X] Receive buffer too small: %lu (< %u)\n",
> + xfer->cmd, xfer->msg->rx_len, word_count);
> + return true;
> + }
> +
> + xfer->rx_word_count = word_count;
> + } else {
> + /* Set word_count from previous header read */
> + word_count = xfer->rx_word_count;
> + }
> +
> + /* If RX payload is not yet received, wait for it */
> + if (!(status & RX_PKT_PAYLOAD_DATA_RCVD))
> + return false;
> +
> + /* Read the RX payload */
> + while (word_count >= 4) {
> + val = nwl_dsi_read(dsi, RX_PAYLOAD);
> + payload[0] = (val >> 0) & 0xff;
> + payload[1] = (val >> 8) & 0xff;
> + payload[2] = (val >> 16) & 0xff;
> + payload[3] = (val >> 24) & 0xff;
> + payload += 4;
> + xfer->rx_len += 4;
> + word_count -= 4;
> + }
> +
> + if (word_count > 0) {
> + val = nwl_dsi_read(dsi, RX_PAYLOAD);
> + switch (word_count) {
> + case 3:
> + payload[2] = (val >> 16) & 0xff;
> + ++xfer->rx_len;
> + /* Fall through */
> + case 2:
> + payload[1] = (val >> 8) & 0xff;
> + ++xfer->rx_len;
> + /* Fall through */
> + case 1:
> + payload[0] = (val >> 0) & 0xff;
> + ++xfer->rx_len;
> + break;
> + }
> + }
> +
> + xfer->status = xfer->rx_len;
> +
> + return true;
> +}
> +
> +static void nwl_dsi_finish_transmission(struct imx_nwl_dsi *dsi, u32 status)
> +{
> + struct mipi_dsi_transfer *xfer = dsi->xfer;
> + bool end_packet = false;
> +
> + if (!xfer)
> + return;
> +
> + if (status & TX_FIFO_OVFLW) {
> + DRM_DEV_ERROR_RATELIMITED(dsi->dev, "tx fifo overflow\n");
> + return;
> + }
> +
> + if (status & HS_TX_TIMEOUT) {
> + DRM_DEV_ERROR_RATELIMITED(dsi->dev, "HS tx timeout\n");
> + return;
> + }
> +
> + if (xfer->direction == DSI_PACKET_SEND && status & TX_PKT_DONE) {
> + xfer->status = xfer->tx_len;
> + end_packet = true;
> + } else if (status & DPHY_DIRECTION &&
> + ((status & (RX_PKT_HDR_RCVD | RX_PKT_PAYLOAD_DATA_RCVD)))) {
> + end_packet = nwl_dsi_read_packet(dsi, status);
> + }
> +
> + if (end_packet)
> + complete(&xfer->completed);
> +}
> +
> +static void nwl_dsi_begin_transmission(struct imx_nwl_dsi *dsi)
> +{
> + struct mipi_dsi_transfer *xfer = dsi->xfer;
> + struct mipi_dsi_packet *pkt = &xfer->packet;
> + const u8 *payload;
> + size_t length;
> + u16 word_count;
> + u8 hs_mode;
> + u32 val;
> + u32 hs_workaround = 0;
> +
> + /* Send the payload, if any */
> + length = pkt->payload_length;
> + payload = pkt->payload;
> +
> + while (length >= 4) {
> + val = get_unaligned_le32(payload);
The framework doesn't guarantee the payload to be aligned on a multiple
of 4 bytes ?
> + hs_workaround |= !(val & 0xFFFF00);
> + nwl_dsi_write(dsi, TX_PAYLOAD, val);
> + payload += 4;
> + length -= 4;
> + }
> + /* Send the rest of the payload */
> + val = 0;
> + switch (length) {
> + case 3:
> + val |= payload[2] << 16;
> + /* Fall through */
> + case 2:
> + val |= payload[1] << 8;
> + hs_workaround |= !(val & 0xFFFF00);
> + /* Fall through */
> + case 1:
> + val |= payload[0];
> + nwl_dsi_write(dsi, TX_PAYLOAD, val);
> + break;
> + }
> + xfer->tx_len = pkt->payload_length;
> +
> + /*
> + * Send the header
> + * header[0] = Virtual Channel + Data Type
> + * header[1] = Word Count LSB (LP) or first param (SP)
> + * header[2] = Word Count MSB (LP) or second param (SP)
> + */
> + word_count = pkt->header[1] | (pkt->header[2] << 8);
> + if ((hs_workaround && USE_E11418_HS_MODE_QUIRK(dsi->quirks))) {
> + DRM_DEV_DEBUG_DRIVER(dsi->dev,
> + "Using hs mode workaround for cmd 0x%x\n",
> + xfer->cmd);
> + hs_mode = 1;
> + } else {
> + hs_mode = (xfer->msg->flags & MIPI_DSI_MSG_USE_LPM) ? 0 : 1;
> + }
> + val = WC(word_count) |
> + TX_VC(xfer->msg->channel) |
> + TX_DT(xfer->msg->type) |
> + HS_SEL(hs_mode) |
> + BTA_TX(xfer->need_bta);
> + nwl_dsi_write(dsi, PKT_CONTROL, val);
> +
> + /* Send packet command */
> + nwl_dsi_write(dsi, SEND_PACKET, 0x1);
> +}
> +
> +static ssize_t nwl_dsi_host_transfer(struct mipi_dsi_host *dsi_host,
> + const struct mipi_dsi_msg *msg)
> +{
> + struct imx_nwl_dsi *dsi =
> + container_of(dsi_host, struct imx_nwl_dsi, dsi_host);
> + struct mipi_dsi_transfer xfer;
> + ssize_t ret = 0;
> +
> + /* Create packet to be sent */
> + dsi->xfer = &xfer;
> + ret = mipi_dsi_create_packet(&xfer.packet, msg);
> + if (ret < 0) {
> + dsi->xfer = NULL;
> + return ret;
> + }
> +
> + if ((msg->type & MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM ||
> + msg->type & MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM ||
> + msg->type & MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM ||
> + msg->type & MIPI_DSI_DCS_READ) &&
> + msg->rx_len > 0 && msg->rx_buf != NULL)
> + xfer.direction = DSI_PACKET_RECEIVE;
> + else
> + xfer.direction = DSI_PACKET_SEND;
> +
> + xfer.need_bta = (xfer.direction == DSI_PACKET_RECEIVE);
> + xfer.need_bta |= (msg->flags & MIPI_DSI_MSG_REQ_ACK) ? 1 : 0;
> + xfer.msg = msg;
> + xfer.status = -ETIMEDOUT;
> + xfer.rx_word_count = 0;
> + xfer.rx_len = 0;
> + xfer.cmd = 0x00;
> + if (msg->tx_len > 0)
> + xfer.cmd = ((u8 *)(msg->tx_buf))[0];
> + init_completion(&xfer.completed);
> +
> + nwl_dsi_enable_rx_clock(dsi);
> +
> + /* Initiate the DSI packet transmision */
> + nwl_dsi_begin_transmission(dsi);
> +
> + if (!wait_for_completion_timeout(&xfer.completed, MIPI_FIFO_TIMEOUT)) {
> + DRM_DEV_ERROR(dsi_host->dev, "[%02X] DSI transfer timed out\n",
> + xfer.cmd);
> + ret = -ETIMEDOUT;
> + } else {
> + ret = xfer.status;
> + }
> +
> + clk_disable_unprepare(dsi->rx_esc_clk);
> +
> + return ret;
> +}
> +
> +const struct mipi_dsi_host_ops nwl_dsi_host_ops = {
> + .attach = nwl_dsi_host_attach,
> + .detach = nwl_dsi_host_detach,
> + .transfer = nwl_dsi_host_transfer,
> +};
> +
> +irqreturn_t nwl_dsi_irq_handler(int irq, void *data)
> +{
> + u32 irq_status;
> + struct imx_nwl_dsi *dsi = data;
> +
> + irq_status = nwl_dsi_read(dsi, IRQ_STATUS);
> +
> + if (irq_status & TX_PKT_DONE || irq_status & RX_PKT_HDR_RCVD ||
> + irq_status & RX_PKT_PAYLOAD_DATA_RCVD)
> + nwl_dsi_finish_transmission(dsi, irq_status);
> +
> + return IRQ_HANDLED;
> +}
> +EXPORT_SYMBOL_GPL(nwl_dsi_irq_handler);
> +
> +int nwl_dsi_enable(struct imx_nwl_dsi *dsi)
> +{
> + struct device *dev = dsi->dev;
> + union phy_configure_opts *phy_cfg = &dsi->phy_cfg;
> + int ret;
> +
> + if (!dsi->lanes) {
> + DRM_DEV_ERROR(dev, "Need DSI lanes: %d\n", dsi->lanes);
> + return -EINVAL;
> + }
> +
> + ret = phy_init(dsi->phy);
> + if (ret < 0) {
> + DRM_DEV_ERROR(dev, "Failed to init DSI phy: %d\n", ret);
> + return ret;
> + }
> +
> + ret = phy_configure(dsi->phy, phy_cfg);
> + if (ret < 0) {
> + DRM_DEV_ERROR(dev, "Failed to configure DSI phy: %d\n", ret);
> + return ret;
> + }
> +
> + ret = nwl_dsi_enable_tx_clock(dsi);
> + if (ret < 0) {
> + DRM_DEV_ERROR(dev, "Failed to enable tx clock: %d\n", ret);
> + return ret;
> + }
> +
> + ret = nwl_dsi_config_host(dsi);
> + if (ret < 0) {
> + DRM_DEV_ERROR(dev, "Failed to set up DSI: %d", ret);
> + return ret;
> + }
> +
> + ret = nwl_dsi_config_dpi(dsi);
> + if (ret < 0) {
> + DRM_DEV_ERROR(dev, "Failed to set up DPI: %d", ret);
> + return ret;
> + }
> +
> + ret = phy_power_on(dsi->phy);
> + if (ret < 0) {
> + DRM_DEV_ERROR(dev, "Failed to power on DPHY (%d)\n", ret);
> + return ret;
> + }
> +
> + nwl_dsi_init_interrupts(dsi);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(nwl_dsi_enable);
> +
> +int nwl_dsi_disable(struct imx_nwl_dsi *dsi)
> +{
> + struct device *dev = dsi->dev;
> +
> + DRM_DEV_DEBUG_DRIVER(dev, "Disabling clocks and phy\n");
> +
> + phy_power_off(dsi->phy);
> + phy_exit(dsi->phy);
> +
> + /* Disabling the clock before the phy breaks enabling dsi again */
> + clk_disable_unprepare(dsi->tx_esc_clk);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(nwl_dsi_disable);
> diff --git a/drivers/gpu/drm/bridge/imx-nwl/nwl-dsi.h b/drivers/gpu/drm/bridge/imx-nwl/nwl-dsi.h
> new file mode 100644
> index 000000000000..7bcf804843e2
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/imx-nwl/nwl-dsi.h
> @@ -0,0 +1,111 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * i.MX8 NWL MIPI DSI host driver
> + *
> + * Copyright (C) 2017 NXP
> + * Copyright (C) 2019 Purism SPC
> + */
> +#ifndef __NWL_DSI_H__
> +#define __NWL_DSI_H__
> +
> +#include <drm/drm_mipi_dsi.h>
> +
> +/* DSI HOST registers */
> +#define CFG_NUM_LANES 0x0
Some of the register names are quite prone to namespace clashes. I
recommend prefixing them all with NWL_DSI_.
> +#define CFG_NONCONTINUOUS_CLK 0x4
> +#define CFG_T_PRE 0x8
> +#define CFG_T_POST 0xc
> +#define CFG_TX_GAP 0x10
> +#define CFG_AUTOINSERT_EOTP 0x14
> +#define CFG_EXTRA_CMDS_AFTER_EOTP 0x18
> +#define CFG_HTX_TO_COUNT 0x1c
> +#define CFG_LRX_H_TO_COUNT 0x20
> +#define CFG_BTA_H_TO_COUNT 0x24
> +#define CFG_TWAKEUP 0x28
> +#define CFG_STATUS_OUT 0x2c
> +#define RX_ERROR_STATUS 0x30
> +
> +/* DSI DPI registers */
> +#define PIXEL_PAYLOAD_SIZE 0x200
> +#define PIXEL_FIFO_SEND_LEVEL 0x204
> +#define INTERFACE_COLOR_CODING 0x208
> +#define PIXEL_FORMAT 0x20c
> +#define VSYNC_POLARITY 0x210
> +#define VSYNC_POLARITY_ACTIVE_LOW 0
> +#define VSYNC_POLARITY_ACTIVE_HIGH BIT(1)
> +
> +#define HSYNC_POLARITY 0x214
> +#define HSYNC_POLARITY_ACTIVE_LOW 0
> +#define HSYNC_POLARITY_ACTIVE_HIGH BIT(1)
> +
> +#define VIDEO_MODE 0x218
> +#define HFP 0x21c
> +#define HBP 0x220
> +#define HSA 0x224
> +#define ENABLE_MULT_PKTS 0x228
> +#define VBP 0x22c
> +#define VFP 0x230
> +#define BLLP_MODE 0x234
> +#define USE_NULL_PKT_BLLP 0x238
> +#define VACTIVE 0x23c
> +#define VC 0x240
> +
> +/* DSI APB PKT control */
> +#define TX_PAYLOAD 0x280
> +#define PKT_CONTROL 0x284
> +#define SEND_PACKET 0x288
> +#define PKT_STATUS 0x28c
> +#define PKT_FIFO_WR_LEVEL 0x290
> +#define PKT_FIFO_RD_LEVEL 0x294
> +#define RX_PAYLOAD 0x298
> +#define RX_PKT_HEADER 0x29c
> +
> +/* DSI IRQ handling */
> +#define IRQ_STATUS 0x2a0
> +#define SM_NOT_IDLE BIT(0)
> +#define TX_PKT_DONE BIT(1)
> +#define DPHY_DIRECTION BIT(2)
> +#define TX_FIFO_OVFLW BIT(3)
> +#define TX_FIFO_UDFLW BIT(4)
> +#define RX_FIFO_OVFLW BIT(5)
> +#define RX_FIFO_UDFLW BIT(6)
> +#define RX_PKT_HDR_RCVD BIT(7)
> +#define RX_PKT_PAYLOAD_DATA_RCVD BIT(8)
> +#define BTA_TIMEOUT BIT(29)
> +#define LP_RX_TIMEOUT BIT(30)
> +#define HS_TX_TIMEOUT BIT(31)
> +
> +#define IRQ_STATUS2 0x2a4
> +#define SINGLE_BIT_ECC_ERR BIT(0)
> +#define MULTI_BIT_ECC_ERR BIT(1)
> +#define CRC_ERR BIT(2)
> +
> +#define IRQ_MASK 0x2a8
> +#define SM_NOT_IDLE_MASK BIT(0)
> +#define TX_PKT_DONE_MASK BIT(1)
> +#define DPHY_DIRECTION_MASK BIT(2)
> +#define TX_FIFO_OVFLW_MASK BIT(3)
> +#define TX_FIFO_UDFLW_MASK BIT(4)
> +#define RX_FIFO_OVFLW_MASK BIT(5)
> +#define RX_FIFO_UDFLW_MASK BIT(6)
> +#define RX_PKT_HDR_RCVD_MASK BIT(7)
> +#define RX_PKT_PAYLOAD_DATA_RCVD_MASK BIT(8)
> +#define BTA_TIMEOUT_MASK BIT(29)
> +#define LP_RX_TIMEOUT_MASK BIT(30)
> +#define HS_TX_TIMEOUT_MASK BIT(31)
> +
> +#define IRQ_MASK2 0x2ac
> +#define SINGLE_BIT_ECC_ERR_MASK BIT(0)
> +#define MULTI_BIT_ECC_ERR_MASK BIT(1)
> +#define CRC_ERR_MASK BIT(2)
> +
> +extern const struct mipi_dsi_host_ops nwl_dsi_host_ops;
> +
> +irqreturn_t nwl_dsi_irq_handler(int irq, void *data);
> +int nwl_dsi_enable(struct imx_nwl_dsi *dsi);
> +int nwl_dsi_disable(struct imx_nwl_dsi *dsi);
> +int nwl_dsi_get_dphy_params(struct imx_nwl_dsi *dsi,
> + const struct drm_display_mode *mode,
> + union phy_configure_opts *phy_opts);
> +
> +#endif /* __NWL_DSI_H__ */
--
Regards,
Laurent Pinchart
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* Re: [PATCH 3/3] drm/bridge: Add NWL MIPI DSI host controller support
From: Laurent Pinchart @ 2019-07-27 2:04 UTC (permalink / raw)
To: Fabio Estevam
Cc: Guido Günther, David Airlie, Daniel Vetter, Rob Herring,
Mark Rutland, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
NXP Linux Team, Andrzej Hajda, Neil Armstrong, Jonas Karlman,
Jernej Skrabec, Lee Jones, DRI mailing list,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS
In-Reply-To: <CAOMZO5BRbV_1du1b9eJqcBvvXSE2Mon3yxSPJxPpZgBqYNjBSg@mail.gmail.com>
Hello,
On Fri, Jul 26, 2019 at 05:01:52PM -0300, Fabio Estevam wrote:
> Hi Guido,
>
> Thanks for your work on this driver!
>
> On Wed, Jul 24, 2019 at 12:52 PM Guido Günther <agx@sigxcpu.org> wrote:
>
> > --- /dev/null
> > +++ b/drivers/gpu/drm/bridge/imx-nwl/Kconfig
> > @@ -0,0 +1,15 @@
> > +config DRM_IMX_NWL_DSI
> > + tristate "Support for Northwest Logic MIPI DSI Host controller"
> > + depends on DRM && (ARCH_MXC || ARCH_MULTIPLATFORM || COMPILE_TEST)
>
> This IP could potentially be found on other SoCs, so no need to make
> it depend on ARCH_MXC.
I'd go even further and not use the prefix imx in the driver name or
anywhere in the code.
[snip]
--
Regards,
Laurent Pinchart
^ permalink raw reply
* Re: [PATCH 2/3] dt-bindings: display/bridge: Add binding for IMX NWL mipi dsi host controller
From: Laurent Pinchart @ 2019-07-27 1:59 UTC (permalink / raw)
To: Sam Ravnborg
Cc: Guido Günther, David Airlie, Daniel Vetter, Rob Herring,
Mark Rutland, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, NXP Linux Team, Andrzej Hajda, Neil Armstrong,
Jonas Karlman, Jernej Skrabec, Lee Jones, dri-devel, devicetree,
linux-arm-kernel, linux-kernel, Robert Chiras
In-Reply-To: <20190726092315.GA9754@ravnborg.org>
Hello,
On Fri, Jul 26, 2019 at 11:23:15AM +0200, Sam Ravnborg wrote:
> On Wed, Jul 24, 2019 at 05:52:25PM +0200, Guido Günther wrote:
> > The Northwest Logic MIPI DSI IP core can be found in NXPs i.MX8 SoCs.
> >
> > Signed-off-by: Guido Günther <agx@sigxcpu.org>
> > ---
> > .../bindings/display/bridge/imx-nwl-dsi.txt | 89 +++++++++++++++++++
>
> New binding. Any chance we can get this in yaml format?
> This is the way forward and we have to convert the file anyway.
>
> None of the other bridges use yaml format, but someone has to be the
> first.
>
> > 1 file changed, 89 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/display/bridge/imx-nwl-dsi.txt
> >
> > diff --git a/Documentation/devicetree/bindings/display/bridge/imx-nwl-dsi.txt b/Documentation/devicetree/bindings/display/bridge/imx-nwl-dsi.txt
> > new file mode 100644
> > index 000000000000..288fdb726d5a
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/display/bridge/imx-nwl-dsi.txt
> > @@ -0,0 +1,89 @@
> > +Northwest Logic MIPI-DSI on imx SoCs
> > +=====================================
> > +
> > +NWL MIPI-DSI host controller found on i.MX8 platforms. This is a
> > +dsi bridge for the for the NWL MIPI-DSI host.
>
> To my best understanding a bridge is something that converts from one
> format to another format.
> Something that in the drm world are connected to an encoder.
>
> I do not know the HW here - but from this very brif description this
> sounds more like a display controller and not a bridge?
I would call it an encoder, that's the term usually employed for such
devices (similar to HDMI encoder).
> > +
> > +Required properties:
> > +- compatible: "fsl,<chip>-nwl-dsi"
> > + The following strings are expected:
> > + "fsl,imx8mq-nwl-dsi"
> > +- reg: the register range of the MIPI-DSI controller
> > +- interrupts: the interrupt number for this module
> > +- clock, clock-names: phandles to the MIPI-DSI clocks
> > + The following clocks are expected on all platforms:
> > + "core" - DSI core clock
> > + "tx_esc" - TX_ESC clock (used in escape mode)
> > + "rx_esc" - RX_ESC clock (used in escape mode)
> > + "phy_ref" - PHY_REF clock. Clock is managed by the phy. Only
> > + used to read the clock rate.
> > +- assigned-clocks: phandles to clocks that require initial configuration
> > +- assigned-clock-rates: rates of the clocks that require initial configuration
> > + The following clocks need to have an initial configuration:
> > + "tx_esc" (20 MHz) and "rx_esc" (80 Mhz).
> > +- phys: phandle to the phy module representing the DPHY
> > + inside the MIPI-DSI IP block
> > +- phy-names: should be "dphy"
> > +
> > +Optional properties:
> > +- power-domains phandle to the power domain
> > +- src phandle to the system reset controller (required on
> > + i.MX8MQ)
> Name is not very descriptive.
> Other bindings seems to use "resets" here?
>
> > +- mux-sel phandle to the MUX register set (required on i.MX8MQ)
> > +- assigned-clock-parents phandles to parent clocks that needs to be assigned as
> > + parents to clocks defined in assigned-clocks
> > +
> > +Example:
> > + mipi_dsi: mipi_dsi@30a00000 {
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > + compatible = "fsl,imx8mq-nwl-dsi";
> > + reg = <0x30A00000 0x300>;
> > + clocks = <&clk IMX8MQ_CLK_DSI_CORE>,
> > + <&clk IMX8MQ_CLK_DSI_AHB>,
> > + <&clk IMX8MQ_CLK_DSI_IPG_DIV>,
> > + <&clk IMX8MQ_CLK_DSI_PHY_REF>;
> > + clock-names = "core", "rx_esc", "tx_esc", "phy_ref";
> > + assigned-clocks = <&clk IMX8MQ_CLK_DSI_AHB>,
> > + <&clk IMX8MQ_CLK_DSI_CORE>,
> > + <&clk IMX8MQ_CLK_DSI_IPG_DIV>;
> > + assigned-clock-parents = <&clk IMX8MQ_SYS1_PLL_80M>,
> > + <&clk IMX8MQ_SYS1_PLL_266M>;
> > + assigned-clock-rates = <80000000>,
> > + <266000000>,
> > + <20000000>;
> > + interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
> > + power-domains = <&pgc_mipi>;
> > + src = <&src>;
> > + mux-sel = <&iomuxc_gpr>;
> > + phys = <&dphy>;
> > + phy-names = "dphy";
> > + status = "okay";
> I recall status should not be included in examples.
>
> > +
> > + panel@0 {
> > + compatible = "...";
> > + port {
> > + panel_in: endpoint {
> > + remote-endpoint = <&mipi_dsi_out>;
> > + };
> > + };
> > + };
> > +
> > + ports {
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > +
> > + port@0 {
> > + reg = <0>;
> > + mipi_dsi_in: endpoint {
> > + remote-endpoint = <&dcss_disp0_mipi_dsi>;
> > + };
> > + };
> > + port@1 {
> > + reg = <1>;
> > + mipi_dsi_out: endpoint {
> > + remote-endpoint = <&panel_in>;
> > + };
> > + };
> > + };
> > + };
--
Regards,
Laurent Pinchart
^ permalink raw reply
* Re: [PATCH 2/3] dt-bindings: display/bridge: Add binding for IMX NWL mipi dsi host controller
From: Laurent Pinchart @ 2019-07-27 1:57 UTC (permalink / raw)
To: Guido Günther
Cc: Mark Rutland, devicetree, Jernej Skrabec, Pengutronix Kernel Team,
Neil Armstrong, David Airlie, Jonas Karlman, linux-kernel,
dri-devel, Rob Herring, NXP Linux Team, Robert Chiras, Lee Jones,
Shawn Guo, linux-arm-kernel
In-Reply-To: <70a5c6617936a4a095e7608b96e3f9fae5ddfbb1.1563983037.git.agx@sigxcpu.org>
Hi Guido,
Thank you for the patch.
On Wed, Jul 24, 2019 at 05:52:25PM +0200, Guido Günther wrote:
> The Northwest Logic MIPI DSI IP core can be found in NXPs i.MX8 SoCs.
>
> Signed-off-by: Guido Günther <agx@sigxcpu.org>
> ---
> .../bindings/display/bridge/imx-nwl-dsi.txt | 89 +++++++++++++++++++
> 1 file changed, 89 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/display/bridge/imx-nwl-dsi.txt
>
> diff --git a/Documentation/devicetree/bindings/display/bridge/imx-nwl-dsi.txt b/Documentation/devicetree/bindings/display/bridge/imx-nwl-dsi.txt
> new file mode 100644
> index 000000000000..288fdb726d5a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/bridge/imx-nwl-dsi.txt
> @@ -0,0 +1,89 @@
> +Northwest Logic MIPI-DSI on imx SoCs
> +=====================================
There's one too many =.
> +
> +NWL MIPI-DSI host controller found on i.MX8 platforms. This is a
> +dsi bridge for the for the NWL MIPI-DSI host.
s/dsi/DSI/
s/for the for the /for the /
> +
> +Required properties:
> +- compatible: "fsl,<chip>-nwl-dsi"
> + The following strings are expected:
> + "fsl,imx8mq-nwl-dsi"
> +- reg: the register range of the MIPI-DSI controller
> +- interrupts: the interrupt number for this module
It's not just a number but a specifier (with flags).
> +- clock, clock-names: phandles to the MIPI-DSI clocks
That should be phandles and names.
> + The following clocks are expected on all platforms:
Expected or required ?
s/ on all platforms// as you only support a single platform.
> + "core" - DSI core clock
> + "tx_esc" - TX_ESC clock (used in escape mode)
> + "rx_esc" - RX_ESC clock (used in escape mode)
> + "phy_ref" - PHY_REF clock. Clock is managed by the phy. Only
> + used to read the clock rate.
> +- assigned-clocks: phandles to clocks that require initial configuration
> +- assigned-clock-rates: rates of the clocks that require initial configuration
> + The following clocks need to have an initial configuration:
> + "tx_esc" (20 MHz) and "rx_esc" (80 Mhz).
I think those two properties are out of scope for these bindings.
> +- phys: phandle to the phy module representing the DPHY
> + inside the MIPI-DSI IP block
> +- phy-names: should be "dphy"
> +
> +Optional properties:
> +- power-domains phandle to the power domain
> +- src phandle to the system reset controller (required on
> + i.MX8MQ)
Should this use the standard resets property ?
> +- mux-sel phandle to the MUX register set (required on i.MX8MQ)
> +- assigned-clock-parents phandles to parent clocks that needs to be assigned as
> + parents to clocks defined in assigned-clocks
This property is also out of scope.
> +
> +Example:
> + mipi_dsi: mipi_dsi@30a00000 {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + compatible = "fsl,imx8mq-nwl-dsi";
> + reg = <0x30A00000 0x300>;
> + clocks = <&clk IMX8MQ_CLK_DSI_CORE>,
> + <&clk IMX8MQ_CLK_DSI_AHB>,
> + <&clk IMX8MQ_CLK_DSI_IPG_DIV>,
> + <&clk IMX8MQ_CLK_DSI_PHY_REF>;
> + clock-names = "core", "rx_esc", "tx_esc", "phy_ref";
> + assigned-clocks = <&clk IMX8MQ_CLK_DSI_AHB>,
> + <&clk IMX8MQ_CLK_DSI_CORE>,
> + <&clk IMX8MQ_CLK_DSI_IPG_DIV>;
> + assigned-clock-parents = <&clk IMX8MQ_SYS1_PLL_80M>,
> + <&clk IMX8MQ_SYS1_PLL_266M>;
> + assigned-clock-rates = <80000000>,
> + <266000000>,
> + <20000000>;
> + interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
> + power-domains = <&pgc_mipi>;
> + src = <&src>;
> + mux-sel = <&iomuxc_gpr>;
> + phys = <&dphy>;
> + phy-names = "dphy";
> + status = "okay";
> +
> + panel@0 {
> + compatible = "...";
> + port {
> + panel_in: endpoint {
> + remote-endpoint = <&mipi_dsi_out>;
> + };
> + };
> + };
> +
> + ports {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + port@0 {
> + reg = <0>;
> + mipi_dsi_in: endpoint {
> + remote-endpoint = <&dcss_disp0_mipi_dsi>;
> + };
> + };
> + port@1 {
> + reg = <1>;
> + mipi_dsi_out: endpoint {
> + remote-endpoint = <&panel_in>;
> + };
> + };
> + };
The ports should be documented too. There are multiple example bindings
available.
> + };
--
Regards,
Laurent Pinchart
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* Re: [PATCH v3 1/2] dt-bindings: i3c: Document MediaTek I3C master bindings
From: Qii Wang @ 2019-07-27 1:23 UTC (permalink / raw)
To: Rob Herring
Cc: mark.rutland, devicetree, srv_heupstream, bbrezillon, leilk.liu,
linux-kernel, liguo.zhang, linux-mediatek, xinping.qian,
matthias.bgg, linux-i3c, linux-arm-kernel
In-Reply-To: <20190724202119.GA26566@bogus>
On Wed, 2019-07-24 at 14:21 -0600, Rob Herring wrote:
> On Tue, Jul 09, 2019 at 09:09:21PM +0800, Qii Wang wrote:
> > Document MediaTek I3C master DT bindings.
> >
> > Signed-off-by: Qii Wang <qii.wang@mediatek.com>
> > ---
> > .../devicetree/bindings/i3c/mtk,i3c-master.txt | 48 ++++++++++++++++++++
> > 1 file changed, 48 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/i3c/mtk,i3c-master.txt
> >
> > diff --git a/Documentation/devicetree/bindings/i3c/mtk,i3c-master.txt b/Documentation/devicetree/bindings/i3c/mtk,i3c-master.txt
> > new file mode 100644
> > index 0000000..d32eda6
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/i3c/mtk,i3c-master.txt
> > @@ -0,0 +1,48 @@
> > +Bindings for MediaTek I3C master block
> > +=====================================
> > +
> > +Required properties:
> > +--------------------
> > +- compatible: shall be "mediatek,i3c-master"
>
> Needs to be SoC specific.
>
We hope that the SOCs will use the same driver and try to avoid big
changes. If there are inevitable changes in the future, then we will
modify the compatible to be SoC specific. cdns,i3c-master.txt is not SoC
specific either.
> > +- reg: physical base address of the controller and apdma base, length of
> > + memory mapped region.
> > +- reg-names: shall be "main" for master controller and "dma" for apdma.
> > +- interrupts: the interrupt line connected to this I3C master.
> > +- clocks: shall reference the i3c and apdma clocks.
> > +- clock-names: shall include "main" and "dma".
> > +
> > +Mandatory properties defined by the generic binding (see
> > +Documentation/devicetree/bindings/i3c/i3c.txt for more details):
> > +
> > +- #address-cells: shall be set to 3
> > +- #size-cells: shall be set to 0
> > +
> > +Optional properties defined by the generic binding (see
> > +Documentation/devicetree/bindings/i3c/i3c.txt for more details):
> > +
> > +- i2c-scl-hz
> > +- i3c-scl-hz
> > +
> > +I3C device connected on the bus follow the generic description (see
> > +Documentation/devicetree/bindings/i3c/i3c.txt for more details).
> > +
> > +Example:
> > +
> > + i3c0: i3c@1100d000 {
> > + compatible = "mediatek,i3c-master";
> > + reg = <0x1100d000 0x1000>,
> > + <0x11000300 0x80>;
> > + reg-names = "main", "dma";
> > + interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_LOW>;
> > + clocks = <&infracfg CLK_INFRA_I3C0>,
> > + <&infracfg CLK_INFRA_AP_DMA>;
> > + clock-names = "main", "dma";
> > + #address-cells = <3>;
> > + #size-cells = <0>;
> > + i2c-scl-hz = <100000>;
> > +
> > + nunchuk: nunchuk@52 {
> > + compatible = "nintendo,nunchuk";
> > + reg = <0x52 0x0 0x10>;
> > + };
> > + };
> > --
> > 1.7.9.5
> >
^ permalink raw reply
* [GIT PULL] Devicetree fixes for 5.3-rc, take 2
From: Rob Herring @ 2019-07-27 0:03 UTC (permalink / raw)
To: Linus Torvalds
Cc: Frank Rowand, devicetree, linux-kernel@vger.kernel.org,
Greg Kroah-Hartman
Hi Linus,
Please pull some more DT fixes for 5.3. The nvmem changes would
typically go thru Greg's tree, but they were missed in the merge
window and I've been unable to get a response (partly because Srinivas
is out on vacation it appears).
Rob
The following changes since commit e2297f7c3ab3b68dda2ac732b1767212019d3bdf:
dt-bindings: pinctrl: stm32: Fix missing 'clocks' property in
examples (2019-07-20 20:28:53 -0600)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git
tags/devicetree-fixes-for-5.3-2
for you to fetch changes up to e1ff7390f58e609aa113a2452a953f669abce6cc:
dt-bindings: Fix more $id value mismatches filenames (2019-07-26
17:41:41 -0600)
----------------------------------------------------------------
Devicetree fixes for 5.3-rc:
- Fix mismatches in $id values and actual filenames. Now checked by
tools.
- Convert nvmem binding to DT schema
- Fix a typo in of_property_read_bool() kerneldoc
- Remove some redundant description in al-fic interrupt-controller
----------------------------------------------------------------
Maxime Ripard (2):
dt-bindings: nvmem: Add YAML schemas for the generic NVMEM bindings
dt-bindings: nvmem: SID: Fix the examples node names
Rob Herring (2):
dt-bindings: clk: allwinner,sun4i-a10-ccu: Correct path in $id
dt-bindings: Fix more $id value mismatches filenames
Talel Shenhar (1):
dt-bindings: interrupt-controller: al-fic: remove redundant binding
Thierry Reding (1):
of: Fix typo in kerneldoc
Documentation/devicetree/bindings/arm/renesas.yaml | 2 +-
.../bindings/arm/socionext/milbeaut.yaml | 2 +-
.../devicetree/bindings/arm/ti/ti,davinci.yaml | 2 +-
.../bindings/clock/allwinner,sun4i-a10-ccu.yaml | 2 +-
.../intel,ixp4xx-network-processing-engine.yaml | 2 +-
.../devicetree/bindings/iio/accel/adi,adxl345.yaml | 2 +-
.../devicetree/bindings/iio/accel/adi,adxl372.yaml | 2 +-
.../interrupt-controller/amazon,al-fic.txt | 16 ++--
.../intel,ixp4xx-interrupt.yaml | 2 +-
...er.yaml => intel,ixp4xx-ahb-queue-manager.yaml} | 2 +-
.../bindings/net/allwinner,sun8i-a83t-emac.yaml | 2 +-
.../bindings/nvmem/allwinner,sun4i-a10-sid.yaml | 4 +-
.../devicetree/bindings/nvmem/nvmem-consumer.yaml | 45 +++++++++++
Documentation/devicetree/bindings/nvmem/nvmem.txt | 81 +------------------
Documentation/devicetree/bindings/nvmem/nvmem.yaml | 93 ++++++++++++++++++++++
.../phy/allwinner,sun6i-a31-mipi-dphy.yaml | 2 +-
.../bindings/timer/intel,ixp4xx-timer.yaml | 2 +-
include/linux/of.h | 2 +-
18 files changed, 161 insertions(+), 104 deletions(-)
rename Documentation/devicetree/bindings/misc/{intel,ixp4xx-queue-manager.yaml
=> intel,ixp4xx-ahb-queue-manager.yaml} (95%)
create mode 100644 Documentation/devicetree/bindings/nvmem/nvmem-consumer.yaml
create mode 100644 Documentation/devicetree/bindings/nvmem/nvmem.yaml
^ permalink raw reply
* [PATCH] dt-bindings: Fix more $id value mismatches filenames
From: Rob Herring @ 2019-07-26 23:44 UTC (permalink / raw)
To: devicetree; +Cc: linux-kernel
The path in the schema '$id' values are wrong. Fix them.
Signed-off-by: Rob Herring <robh@kernel.org>
---
Documentation/devicetree/bindings/arm/renesas.yaml | 2 +-
Documentation/devicetree/bindings/arm/socionext/milbeaut.yaml | 2 +-
Documentation/devicetree/bindings/arm/ti/ti,davinci.yaml | 2 +-
.../firmware/intel,ixp4xx-network-processing-engine.yaml | 2 +-
Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml | 2 +-
Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml | 2 +-
.../bindings/interrupt-controller/intel,ixp4xx-interrupt.yaml | 2 +-
...x-queue-manager.yaml => intel,ixp4xx-ahb-queue-manager.yaml} | 2 +-
.../devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml | 2 +-
.../devicetree/bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml | 2 +-
Documentation/devicetree/bindings/timer/intel,ixp4xx-timer.yaml | 2 +-
11 files changed, 11 insertions(+), 11 deletions(-)
rename Documentation/devicetree/bindings/misc/{intel,ixp4xx-queue-manager.yaml => intel,ixp4xx-ahb-queue-manager.yaml} (95%)
diff --git a/Documentation/devicetree/bindings/arm/renesas.yaml b/Documentation/devicetree/bindings/arm/renesas.yaml
index 08c923f8c257..28eb458f761a 100644
--- a/Documentation/devicetree/bindings/arm/renesas.yaml
+++ b/Documentation/devicetree/bindings/arm/renesas.yaml
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
-$id: http://devicetree.org/schemas/arm/shmobile.yaml#
+$id: http://devicetree.org/schemas/arm/renesas.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas SH-Mobile, R-Mobile, and R-Car Platform Device Tree Bindings
diff --git a/Documentation/devicetree/bindings/arm/socionext/milbeaut.yaml b/Documentation/devicetree/bindings/arm/socionext/milbeaut.yaml
index aae53fc3cb1e..2bd519d2e855 100644
--- a/Documentation/devicetree/bindings/arm/socionext/milbeaut.yaml
+++ b/Documentation/devicetree/bindings/arm/socionext/milbeaut.yaml
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
-$id: http://devicetree.org/schemas/arm/milbeaut.yaml#
+$id: http://devicetree.org/schemas/arm/socionext/milbeaut.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Milbeaut platforms device tree bindings
diff --git a/Documentation/devicetree/bindings/arm/ti/ti,davinci.yaml b/Documentation/devicetree/bindings/arm/ti/ti,davinci.yaml
index 4326d2cfa15d..a8765ba29476 100644
--- a/Documentation/devicetree/bindings/arm/ti/ti,davinci.yaml
+++ b/Documentation/devicetree/bindings/arm/ti/ti,davinci.yaml
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
-$id: http://devicetree.org/schemas/arm/ti/davinci.yaml#
+$id: http://devicetree.org/schemas/arm/ti/ti,davinci.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments DaVinci Platforms Device Tree Bindings
diff --git a/Documentation/devicetree/bindings/firmware/intel,ixp4xx-network-processing-engine.yaml b/Documentation/devicetree/bindings/firmware/intel,ixp4xx-network-processing-engine.yaml
index 8cb136c376fb..4f0db8ee226a 100644
--- a/Documentation/devicetree/bindings/firmware/intel,ixp4xx-network-processing-engine.yaml
+++ b/Documentation/devicetree/bindings/firmware/intel,ixp4xx-network-processing-engine.yaml
@@ -2,7 +2,7 @@
# Copyright 2019 Linaro Ltd.
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/firmware/intel-ixp4xx-network-processing-engine.yaml#"
+$id: "http://devicetree.org/schemas/firmware/intel,ixp4xx-network-processing-engine.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Intel IXP4xx Network Processing Engine
diff --git a/Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml b/Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml
index 7ba167e2e1ea..c602b6fe1c0c 100644
--- a/Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml
+++ b/Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
-$id: http://devicetree.org/schemas/iio/accelerometers/adi,adxl345.yaml#
+$id: http://devicetree.org/schemas/iio/accel/adi,adxl345.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices ADXL345/ADXL375 3-Axis Digital Accelerometers
diff --git a/Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml b/Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml
index a7fafb9bf5c6..e7daffec88d3 100644
--- a/Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml
+++ b/Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
-$id: http://devicetree.org/schemas/iio/accelerometers/adi,adxl372.yaml#
+$id: http://devicetree.org/schemas/iio/accel/adi,adxl372.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices ADXL372 3-Axis, +/-(200g) Digital Accelerometer
diff --git a/Documentation/devicetree/bindings/interrupt-controller/intel,ixp4xx-interrupt.yaml b/Documentation/devicetree/bindings/interrupt-controller/intel,ixp4xx-interrupt.yaml
index bae10e261fa9..507c141ea760 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/intel,ixp4xx-interrupt.yaml
+++ b/Documentation/devicetree/bindings/interrupt-controller/intel,ixp4xx-interrupt.yaml
@@ -2,7 +2,7 @@
# Copyright 2018 Linaro Ltd.
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/interrupt/intel-ixp4xx-interrupt.yaml#"
+$id: "http://devicetree.org/schemas/interrupt-controller/intel,ixp4xx-interrupt.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Intel IXP4xx XScale Networking Processors Interrupt Controller
diff --git a/Documentation/devicetree/bindings/misc/intel,ixp4xx-queue-manager.yaml b/Documentation/devicetree/bindings/misc/intel,ixp4xx-ahb-queue-manager.yaml
similarity index 95%
rename from Documentation/devicetree/bindings/misc/intel,ixp4xx-queue-manager.yaml
rename to Documentation/devicetree/bindings/misc/intel,ixp4xx-ahb-queue-manager.yaml
index d2313b1d9405..0ea21a6f70b4 100644
--- a/Documentation/devicetree/bindings/misc/intel,ixp4xx-queue-manager.yaml
+++ b/Documentation/devicetree/bindings/misc/intel,ixp4xx-ahb-queue-manager.yaml
@@ -2,7 +2,7 @@
# Copyright 2019 Linaro Ltd.
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/misc/intel-ixp4xx-ahb-queue-manager.yaml#"
+$id: "http://devicetree.org/schemas/misc/intel,ixp4xx-ahb-queue-manager.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Intel IXP4xx AHB Queue Manager
diff --git a/Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml b/Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml
index d4084c149768..3fb0714e761e 100644
--- a/Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml
+++ b/Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
-$id: http://devicetree.org/schemas/net/allwinner,sun8i-a83t-gmac.yaml#
+$id: http://devicetree.org/schemas/net/allwinner,sun8i-a83t-emac.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Allwinner A83t EMAC Device Tree Bindings
diff --git a/Documentation/devicetree/bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml b/Documentation/devicetree/bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml
index 250f9d5aabdf..fa46670de299 100644
--- a/Documentation/devicetree/bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml
+++ b/Documentation/devicetree/bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
-$id: http://devicetree.org/schemas/display/allwinner,sun6i-a31-mipi-dphy.yaml#
+$id: http://devicetree.org/schemas/phy/allwinner,sun6i-a31-mipi-dphy.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Allwinner A31 MIPI D-PHY Controller Device Tree Bindings
diff --git a/Documentation/devicetree/bindings/timer/intel,ixp4xx-timer.yaml b/Documentation/devicetree/bindings/timer/intel,ixp4xx-timer.yaml
index a36a0746c056..2807225db902 100644
--- a/Documentation/devicetree/bindings/timer/intel,ixp4xx-timer.yaml
+++ b/Documentation/devicetree/bindings/timer/intel,ixp4xx-timer.yaml
@@ -2,7 +2,7 @@
# Copyright 2018 Linaro Ltd.
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/timer/intel-ixp4xx-timer.yaml#"
+$id: "http://devicetree.org/schemas/timer/intel,ixp4xx-timer.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Intel IXP4xx XScale Networking Processors Timers
--
2.20.1
^ permalink raw reply related
* Re: [PATCH] dt-bindings: nvmem: SID: Fix the examples node names
From: Rob Herring @ 2019-07-26 23:40 UTC (permalink / raw)
To: Maxime Ripard; +Cc: Mark Rutland, Frank Rowand, Srinivas Kandagatla, devicetree
In-Reply-To: <CAL_Jsq+fqJe5_H80xwimsjueVCEwxbNa2sVQCAg=RjD-n1VfXA@mail.gmail.com>
On Wed, Jul 03, 2019 at 01:04:53PM -0600, Rob Herring wrote:
> On Wed, Jul 3, 2019 at 3:54 AM Maxime Ripard <maxime.ripard@bootlin.com> wrote:
> >
> > Now that the examples are validated, the examples in the SID binding
> > generates an error since the node names aren't one of the valid ones.
> >
> > Let's switch for one that is ok.
> >
> > Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
> > ---
> > .../devicetree/bindings/nvmem/allwinner,sun4i-a10-sid.yaml | 4 ++--
> > 1 file changed, 2 insertions(+), 2 deletions(-)
>
> Reviewed-by: Rob Herring <robh@kernel.org>
Seems this one has been missed for 5.3, so I've applied it.
Rob
^ permalink raw reply
* [PATCH v4 3/3] OPP: Add helper function for bandwidth OPP tables
From: Saravana Kannan @ 2019-07-26 23:15 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Viresh Kumar, Nishanth Menon,
Stephen Boyd, Rafael J. Wysocki
Cc: Saravana Kannan, Georgi Djakov, vincent.guittot, seansw,
daidavid1, adharmap, Rajendra Nayak, sibis, bjorn.andersson,
evgreen, kernel-team, linux-pm, devicetree, linux-kernel
In-Reply-To: <20190726231558.175130-1-saravanak@google.com>
The frequency OPP tables have helper functions to search for entries in the
table based on frequency and get the frequency values for a given (or
suspend) OPP entry.
Add similar helper functions for bandwidth OPP tables to search for entries
in the table based on peak bandwidth and to get the peak and average
bandwidth for a given (or suspend) OPP entry.
Signed-off-by: Saravana Kannan <saravanak@google.com>
---
drivers/opp/core.c | 51 ++++++++++++++++++++++++++++++++++++++++++
include/linux/pm_opp.h | 19 ++++++++++++++++
2 files changed, 70 insertions(+)
diff --git a/drivers/opp/core.c b/drivers/opp/core.c
index c094d5d20fd7..b36bc69341dc 100644
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -127,6 +127,29 @@ unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp)
}
EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq);
+/**
+ * dev_pm_opp_get_bw() - Gets the bandwidth corresponding to an available opp
+ * @opp: opp for which frequency has to be returned for
+ * @avg_bw: Pointer where the corresponding average bandwidth is stored.
+ * Can be NULL.
+ *
+ * Return: Peak bandwidth in KBps corresponding to the opp, else
+ * return 0
+ */
+unsigned long dev_pm_opp_get_bw(struct dev_pm_opp *opp, unsigned long *avg_bw)
+{
+ if (IS_ERR_OR_NULL(opp) || !opp->available) {
+ pr_err("%s: Invalid parameters\n", __func__);
+ return 0;
+ }
+
+ if (avg_bw)
+ *avg_bw = opp->avg_bw;
+
+ return opp->rate;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_get_bw);
+
/**
* dev_pm_opp_get_level() - Gets the level corresponding to an available opp
* @opp: opp for which level value has to be returned for
@@ -299,6 +322,34 @@ unsigned long dev_pm_opp_get_suspend_opp_freq(struct device *dev)
}
EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp_freq);
+/**
+ * dev_pm_opp_get_suspend_opp_bw() - Get peak bandwidth of suspend opp in KBps
+ * @dev: device for which we do this operation
+ * @avg_bw: Pointer where the corresponding average bandwidth is stored.
+ * Can be NULL.
+ *
+ * Return: This function returns the peak bandwidth of the OPP marked as
+ * suspend_opp if one is available, else returns 0;
+ */
+unsigned long dev_pm_opp_get_suspend_opp_bw(struct device *dev,
+ unsigned long *avg_bw)
+{
+ struct opp_table *opp_table;
+ unsigned long peak_bw = 0;
+
+ opp_table = _find_opp_table(dev);
+ if (IS_ERR(opp_table))
+ return 0;
+
+ if (opp_table->suspend_opp && opp_table->suspend_opp->available)
+ peak_bw = dev_pm_opp_get_bw(opp_table->suspend_opp, avg_bw);
+
+ dev_pm_opp_put_opp_table(opp_table);
+
+ return peak_bw;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp_bw);
+
int _get_opp_count(struct opp_table *opp_table)
{
struct dev_pm_opp *opp;
diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h
index af5021f27cb7..799b1defe1f7 100644
--- a/include/linux/pm_opp.h
+++ b/include/linux/pm_opp.h
@@ -82,6 +82,7 @@ void dev_pm_opp_put_opp_table(struct opp_table *opp_table);
unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp);
unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp);
+unsigned long dev_pm_opp_get_bw(struct dev_pm_opp *opp, unsigned long *avg_bw);
unsigned int dev_pm_opp_get_level(struct dev_pm_opp *opp);
@@ -92,6 +93,8 @@ unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev);
unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev);
unsigned long dev_pm_opp_get_max_transition_latency(struct device *dev);
unsigned long dev_pm_opp_get_suspend_opp_freq(struct device *dev);
+unsigned long dev_pm_opp_get_suspend_opp_bw(struct device *dev,
+ unsigned long *avg_bw);
struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
unsigned long freq,
@@ -158,6 +161,11 @@ static inline unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp)
{
return 0;
}
+static inline unsigned long dev_pm_opp_get_bw(struct dev_pm_opp *opp,
+ unsigned long *avg_bw)
+{
+ return 0;
+}
static inline unsigned int dev_pm_opp_get_level(struct dev_pm_opp *opp)
{
@@ -194,6 +202,12 @@ static inline unsigned long dev_pm_opp_get_suspend_opp_freq(struct device *dev)
return 0;
}
+static inline unsigned long dev_pm_opp_get_suspend_opp_bw(struct device *dev,
+ unsigned long *avg_bw)
+{
+ return 0;
+}
+
static inline struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
unsigned long freq, bool available)
{
@@ -329,6 +343,11 @@ static inline void dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask
#endif /* CONFIG_PM_OPP */
+#define dev_pm_opp_find_peak_bw_exact dev_pm_opp_find_freq_exact
+#define dev_pm_opp_find_peak_bw_floor dev_pm_opp_find_freq_floor
+#define dev_pm_opp_find_peak_bw_ceil_by_volt dev_pm_opp_find_freq_ceil_by_volt
+#define dev_pm_opp_find_peak_bw_ceil dev_pm_opp_find_freq_ceil
+
#if defined(CONFIG_PM_OPP) && defined(CONFIG_OF)
int dev_pm_opp_of_add_table(struct device *dev);
int dev_pm_opp_of_add_table_indexed(struct device *dev, int index);
--
2.22.0.709.g102302147b-goog
^ permalink raw reply related
* [PATCH v4 2/3] OPP: Add support for bandwidth OPP tables
From: Saravana Kannan @ 2019-07-26 23:15 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Viresh Kumar, Nishanth Menon,
Stephen Boyd, Rafael J. Wysocki
Cc: Saravana Kannan, Georgi Djakov, vincent.guittot, seansw,
daidavid1, adharmap, Rajendra Nayak, sibis, bjorn.andersson,
evgreen, kernel-team, linux-pm, devicetree, linux-kernel
In-Reply-To: <20190726231558.175130-1-saravanak@google.com>
Not all devices quantify their performance points in terms of frequency.
Devices like interconnects quantify their performance points in terms of
bandwidth. We need a way to represent these bandwidth levels in OPP. So,
add support for parsing bandwidth OPPs from DT.
Signed-off-by: Saravana Kannan <saravanak@google.com>
---
drivers/opp/of.c | 41 ++++++++++++++++++++++++++++++++---------
drivers/opp/opp.h | 4 +++-
2 files changed, 35 insertions(+), 10 deletions(-)
diff --git a/drivers/opp/of.c b/drivers/opp/of.c
index b313aca9894f..ac73512f4416 100644
--- a/drivers/opp/of.c
+++ b/drivers/opp/of.c
@@ -523,6 +523,35 @@ void dev_pm_opp_of_remove_table(struct device *dev)
}
EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table);
+static int _read_opp_key(struct dev_pm_opp *new_opp, struct device_node *np)
+{
+ int ret;
+ u64 rate;
+ u32 bw;
+
+ ret = of_property_read_u64(np, "opp-hz", &rate);
+ if (!ret) {
+ /*
+ * Rate is defined as an unsigned long in clk API, and so
+ * casting explicitly to its type. Must be fixed once rate is 64
+ * bit guaranteed in clk API.
+ */
+ new_opp->rate = (unsigned long)rate;
+ return 0;
+ }
+
+ ret = of_property_read_u32(np, "opp-peak-KBps", &bw);
+ if (ret)
+ return ret;
+ new_opp->rate = (unsigned long) bw;
+
+ ret = of_property_read_u32(np, "opp-avg-KBps", &bw);
+ if (!ret)
+ new_opp->avg_bw = (unsigned long) bw;
+
+ return 0;
+}
+
/**
* _opp_add_static_v2() - Allocate static OPPs (As per 'v2' DT bindings)
* @opp_table: OPP table
@@ -560,22 +589,16 @@ static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,
if (!new_opp)
return ERR_PTR(-ENOMEM);
- ret = of_property_read_u64(np, "opp-hz", &rate);
+ ret = _read_opp_key(new_opp, np);
if (ret < 0) {
/* "opp-hz" is optional for devices like power domains. */
if (!opp_table->is_genpd) {
- dev_err(dev, "%s: opp-hz not found\n", __func__);
+ dev_err(dev, "%s: opp-hz or opp-peak-bw not found\n",
+ __func__);
goto free_opp;
}
rate_not_available = true;
- } else {
- /*
- * Rate is defined as an unsigned long in clk API, and so
- * casting explicitly to its type. Must be fixed once rate is 64
- * bit guaranteed in clk API.
- */
- new_opp->rate = (unsigned long)rate;
}
of_property_read_u32(np, "opp-level", &new_opp->level);
diff --git a/drivers/opp/opp.h b/drivers/opp/opp.h
index 01a500e2c40a..6bb238af9cac 100644
--- a/drivers/opp/opp.h
+++ b/drivers/opp/opp.h
@@ -56,7 +56,8 @@ extern struct list_head opp_tables;
* @turbo: true if turbo (boost) OPP
* @suspend: true if suspend OPP
* @pstate: Device's power domain's performance state.
- * @rate: Frequency in hertz
+ * @rate: Frequency in hertz OR Peak bandwidth in kilobytes per second
+ * @avg_bw: Average bandwidth in kilobytes per second
* @level: Performance level
* @supplies: Power supplies voltage/current values
* @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's
@@ -78,6 +79,7 @@ struct dev_pm_opp {
bool suspend;
unsigned int pstate;
unsigned long rate;
+ unsigned long avg_bw;
unsigned int level;
struct dev_pm_opp_supply *supplies;
--
2.22.0.709.g102302147b-goog
^ permalink raw reply related
* [PATCH v4 1/3] dt-bindings: opp: Introduce opp-peak-KBps and opp-avg-KBps bindings
From: Saravana Kannan @ 2019-07-26 23:15 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Viresh Kumar, Nishanth Menon,
Stephen Boyd, Rafael J. Wysocki
Cc: Saravana Kannan, Georgi Djakov, vincent.guittot, seansw,
daidavid1, adharmap, Rajendra Nayak, sibis, bjorn.andersson,
evgreen, kernel-team, linux-pm, devicetree, linux-kernel
In-Reply-To: <20190726231558.175130-1-saravanak@google.com>
Interconnects often quantify their performance points in terms of
bandwidth. So, add opp-peak-KBps (required) and opp-avg-KBps (optional) to
allow specifying Bandwidth OPP tables in DT.
opp-peak-KBps is a required property that replace opp-hz for Bandwidth OPP
tables.
opp-avg-KBps is an optional property that can be used in Bandwidth OPP
tables.
Signed-off-by: Saravana Kannan <saravanak@google.com>
---
Documentation/devicetree/bindings/opp/opp.txt | 15 ++++++++++++---
.../devicetree/bindings/property-units.txt | 4 ++++
2 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/opp/opp.txt b/Documentation/devicetree/bindings/opp/opp.txt
index 76b6c79604a5..b1eb49d6eab0 100644
--- a/Documentation/devicetree/bindings/opp/opp.txt
+++ b/Documentation/devicetree/bindings/opp/opp.txt
@@ -83,9 +83,14 @@ properties.
Required properties:
- opp-hz: Frequency in Hz, expressed as a 64-bit big-endian integer. This is a
- required property for all device nodes but devices like power domains. The
- power domain nodes must have another (implementation dependent) property which
- uniquely identifies the OPP nodes.
+ required property for all device nodes but for devices like power domains or
+ bandwidth opp tables. The power domain nodes must have another (implementation
+ dependent) property which uniquely identifies the OPP nodes. The interconnect
+ opps are required to have the opp-peak-KBps property.
+
+- opp-peak-KBps: Peak bandwidth in kilobytes per second, expressed as a 32-bit
+ big-endian integer. This is a required property for all devices that don't
+ have opp-hz. For example, bandwidth OPP tables for interconnect paths.
Optional properties:
- opp-microvolt: voltage in micro Volts.
@@ -132,6 +137,10 @@ Optional properties:
- opp-level: A value representing the performance level of the device,
expressed as a 32-bit integer.
+- opp-avg-KBps: Average bandwidth in kilobytes per second, expressed as a
+ 32-bit big-endian integer. This property is only meaningful in OPP tables
+ where opp-peak-KBps is present.
+
- clock-latency-ns: Specifies the maximum possible transition latency (in
nanoseconds) for switching to this OPP from any other OPP.
diff --git a/Documentation/devicetree/bindings/property-units.txt b/Documentation/devicetree/bindings/property-units.txt
index e9b8360b3288..ef4c4a199efa 100644
--- a/Documentation/devicetree/bindings/property-units.txt
+++ b/Documentation/devicetree/bindings/property-units.txt
@@ -41,3 +41,7 @@ Temperature
Pressure
----------------------------------------
-kpascal : kilopascal
+
+Throughput
+----------------------------------------
+-KBps : kilobytes per second
--
2.22.0.709.g102302147b-goog
^ permalink raw reply related
* [PATCH v4 0/3] Introduce Bandwidth OPPs for interconnects
From: Saravana Kannan @ 2019-07-26 23:15 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Viresh Kumar, Nishanth Menon,
Stephen Boyd, Rafael J. Wysocki
Cc: Saravana Kannan, Georgi Djakov, vincent.guittot, seansw,
daidavid1, adharmap, Rajendra Nayak, sibis, bjorn.andersson,
evgreen, kernel-team, linux-pm, devicetree, linux-kernel
Interconnects and interconnect paths quantify their performance levels in
terms of bandwidth and not in terms of frequency. So similar to how we have
frequency based OPP tables in DT and in the OPP framework, we need
bandwidth OPP table support in DT and in the OPP framework.
So with the DT bindings added in this patch series, the DT for a GPU
that does bandwidth voting from GPU to Cache and GPU to DDR would look
something like this:
gpu_cache_opp_table: gpu_cache_opp_table {
compatible = "operating-points-v2";
gpu_cache_3000: opp-3000 {
opp-peak-KBps = <3000000>;
opp-avg-KBps = <1000000>;
};
gpu_cache_6000: opp-6000 {
opp-peak-KBps = <6000000>;
opp-avg-KBps = <2000000>;
};
gpu_cache_9000: opp-9000 {
opp-peak-KBps = <9000000>;
opp-avg-KBps = <9000000>;
};
};
gpu_ddr_opp_table: gpu_ddr_opp_table {
compatible = "operating-points-v2";
gpu_ddr_1525: opp-1525 {
opp-peak-KBps = <1525000>;
opp-avg-KBps = <452000>;
};
gpu_ddr_3051: opp-3051 {
opp-peak-KBps = <3051000>;
opp-avg-KBps = <915000>;
};
gpu_ddr_7500: opp-7500 {
opp-peak-KBps = <7500000>;
opp-avg-KBps = <3000000>;
};
};
gpu_opp_table: gpu_opp_table {
compatible = "operating-points-v2";
opp-shared;
opp-200000000 {
opp-hz = /bits/ 64 <200000000>;
};
opp-400000000 {
opp-hz = /bits/ 64 <400000000>;
};
};
gpu@7864000 {
...
operating-points-v2 = <&gpu_opp_table>, <&gpu_cache_opp_table>, <&gpu_ddr_opp_table>;
...
};
v1 -> v3:
- Lots of patch additions that were later dropped
v3 -> v4:
- Fixed typo bugs pointed out by Sibi.
- Fixed bug that incorrectly reset rate to 0 all the time
- Added units documentation
- Dropped interconnect-opp-table property and related changes
Cheers,
Saravana
Saravana Kannan (3):
dt-bindings: opp: Introduce opp-peak-KBps and opp-avg-KBps bindings
OPP: Add support for bandwidth OPP tables
OPP: Add helper function for bandwidth OPP tables
Documentation/devicetree/bindings/opp/opp.txt | 15 ++++--
.../devicetree/bindings/property-units.txt | 4 ++
drivers/opp/core.c | 51 +++++++++++++++++++
drivers/opp/of.c | 41 +++++++++++----
drivers/opp/opp.h | 4 +-
include/linux/pm_opp.h | 19 +++++++
6 files changed, 121 insertions(+), 13 deletions(-)
--
2.22.0.709.g102302147b-goog
^ permalink raw reply
* Re: [PATCH] of: Fix typo in kerneldoc
From: Rob Herring @ 2019-07-26 23:01 UTC (permalink / raw)
To: Thierry Reding; +Cc: Frank Rowand, devicetree, linux-kernel
In-Reply-To: <20190726101744.27118-1-thierry.reding@gmail.com>
On Fri, 26 Jul 2019 12:17:44 +0200, Thierry Reding wrote:
> From: Thierry Reding <treding@nvidia.com>
>
> "Findfrom" is not a word. Replace the function synopsis by something
> that makes sense.
>
> Signed-off-by: Thierry Reding <treding@nvidia.com>
> ---
> include/linux/of.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
Applied, thanks.
Rob
^ permalink raw reply
* Re: [PATCH 2/2] dt-bindings: leds: document new "power-supply" property
From: Rob Herring @ 2019-07-26 22:44 UTC (permalink / raw)
To: Daniel Thompson, Jean-Jacques Hiblot
Cc: Jacek Anaszewski, Pavel Machek, Mark Rutland, Dan Murphy,
Linux LED Subsystem, linux-kernel@vger.kernel.org, devicetree
In-Reply-To: <20190726100607.j5bdmuuk33zpwa2r@holly.lan>
On Fri, Jul 26, 2019 at 4:06 AM Daniel Thompson
<daniel.thompson@linaro.org> wrote:
>
> On Thu, Jul 25, 2019 at 01:08:46PM +0200, Jean-Jacques Hiblot wrote:
> > Hi Rob,
> >
> > On 24/07/2019 18:47, Rob Herring wrote:
> > > On Mon, Jul 08, 2019 at 12:35:47PM +0200, Jean-Jacques Hiblot wrote:
> > > > Most of the LEDs are powered by a voltage/current regulator. describing in
> > > > the device-tree makes it possible for the LED core to enable/disable it
> > > > when needed.
> > > >
> > > > Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
> > > > ---
> > > > Documentation/devicetree/bindings/leds/common.txt | 5 +++++
> > > > 1 file changed, 5 insertions(+)
> > > >
> > > > diff --git a/Documentation/devicetree/bindings/leds/common.txt b/Documentation/devicetree/bindings/leds/common.txt
> > > > index 70876ac11367..e093a2b7eb90 100644
> > > > --- a/Documentation/devicetree/bindings/leds/common.txt
> > > > +++ b/Documentation/devicetree/bindings/leds/common.txt
> > > > @@ -61,6 +61,11 @@ Optional properties for child nodes:
> > > > - panic-indicator : This property specifies that the LED should be used,
> > > > if at all possible, as a panic indicator.
> > > > +- power-supply : A voltage/current regulator used to to power the LED. When a
> > > > + LED is turned off, the LED core disable its regulator. The
> > > > + same regulator can power many LED (or other) devices. It is
> > > > + turned off only when all of its users disabled it.
> > > Not sure this should be common. It wouldn't apply to cases where we have
> > > an LED controller parent nor gpio and pwm LEDs and those are most cases.
> >
> > It does make sense for GPIO and PWM bindings if the anode of LED is tied to
> > a regulated voltage and the cathod to the control line.
Okay. Is one of those your case, or you only have regulator control?
The latter would need a new binding. If you want to use power-supply
with either GPIO and PWM LED bindings, then it should still be listed
in those as an applicable property.
> > The same is true for a certain class of true LED controller that do not
> > deliver power but act like current sinks.
> >
> > JJ
> >
> > >
> > > Perhaps what makes sense here is an regulator-led binding.
>
> You didn't comment on this alternative... and I confess I'm not quite
> sure what Rob means by a regulator-led binding so I can't really comment
> either.
>
> Rob, is there any analogous example for a regulator-<something-else> binding
> to compare with?
regulator-haptic is the only one I found in a quick search.
Rob
^ permalink raw reply
* Re: [PATCH 5/6] clk: imx8mq: Remove CLK_IS_CRITICAL flag for IMX8MQ_CLK_TMU_ROOT
From: Daniel Baluta @ 2019-07-26 22:26 UTC (permalink / raw)
To: Anson Huang
Cc: rui.zhang, edubezval, daniel.lezcano, Rob Herring, Mark Rutland,
Shawn Guo, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Michael Turquette, Stephen Boyd, Lucas Stach, Abel Vesa,
Andrey Smirnov, Angus Ainslie (Purism), Carlo Caione,
Guido Günther, Leonard Crestez, linux-pm, Devicetree List
In-Reply-To: <20190705045612.27665-5-Anson.Huang@nxp.com>
Hi all,
latest linux-next hangs at boot.
commit fde50b96be821ac9673a7e00847cc4605bd88f34 (HEAD -> master, tag:
next-20190726, origin/master, origin/HEAD)
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date: Fri Jul 26 15:18:02 2019 +1000
Add linux-next specific files for 20190726
Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
I know this is crazy but reverting commit:
commit 431bdd1df48ee2896ea9980d9153e3aeaf0c81ef (refs/bisect/bad)
Author: Anson Huang <Anson.Huang@nxp.com>
Date: Fri Jul 5 12:56:11 2019 +0800
clk: imx8mq: Remove CLK_IS_CRITICAL flag for IMX8MQ_CLK_TMU_ROOT
IMX8MQ_CLK_TMU_ROOT is ONLY used for thermal module, the driver
should manage this clock, so no need to have CLK_IS_CRITICAL flag
set.
makes the boot work again.
Any idea?
On Fri, Jul 5, 2019 at 8:07 AM <Anson.Huang@nxp.com> wrote:
>
> From: Anson Huang <Anson.Huang@nxp.com>
>
> IMX8MQ_CLK_TMU_ROOT is ONLY used for thermal module, the driver
> should manage this clock, so no need to have CLK_IS_CRITICAL flag
> set.
>
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
> ---
> drivers/clk/imx/clk-imx8mq.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c
> index d407a07..91de69a 100644
> --- a/drivers/clk/imx/clk-imx8mq.c
> +++ b/drivers/clk/imx/clk-imx8mq.c
> @@ -539,7 +539,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
> clks[IMX8MQ_CLK_DISP_AXI_ROOT] = imx_clk_gate2_shared2("disp_axi_root_clk", "disp_axi", base + 0x45d0, 0, &share_count_dcss);
> clks[IMX8MQ_CLK_DISP_APB_ROOT] = imx_clk_gate2_shared2("disp_apb_root_clk", "disp_apb", base + 0x45d0, 0, &share_count_dcss);
> clks[IMX8MQ_CLK_DISP_RTRM_ROOT] = imx_clk_gate2_shared2("disp_rtrm_root_clk", "disp_rtrm", base + 0x45d0, 0, &share_count_dcss);
> - clks[IMX8MQ_CLK_TMU_ROOT] = imx_clk_gate4_flags("tmu_root_clk", "ipg_root", base + 0x4620, 0, CLK_IS_CRITICAL);
> + clks[IMX8MQ_CLK_TMU_ROOT] = imx_clk_gate4("tmu_root_clk", "ipg_root", base + 0x4620, 0);
> clks[IMX8MQ_CLK_VPU_DEC_ROOT] = imx_clk_gate2_flags("vpu_dec_root_clk", "vpu_bus", base + 0x4630, 0, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
> clks[IMX8MQ_CLK_CSI1_ROOT] = imx_clk_gate4("csi1_root_clk", "csi1_core", base + 0x4650, 0);
> clks[IMX8MQ_CLK_CSI2_ROOT] = imx_clk_gate4("csi2_root_clk", "csi2_core", base + 0x4660, 0);
> --
> 2.7.4
>
^ 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