* Re: [PATCH net-next v2 0/2] of: mdio: Fall back to mdiobus_register() with NULL device_node
From: Geert Uytterhoeven @ 2018-05-16 8:54 UTC (permalink / raw)
To: Florian Fainelli
Cc: netdev, Andrew Lunn, Vivien Didelot, David S. Miller,
Nicolas Ferre, Fugang Duan, Sergei Shtylyov, Giuseppe Cavallaro,
Alexandre Torgue, Jose Abreu, Grygorii Strashko, Woojung Huh,
Microchip Linux Driver Support, Rob Herring, Frank Rowand,
Antoine Tenart, Tobias Jordan, Russell King
In-Reply-To: <20180515235619.27773-1-f.fainelli@gmail.com>
Hi Florian,
Thanks for your series!
I like the effect on simplifying drivers.
On Wed, May 16, 2018 at 1:56 AM, Florian Fainelli <f.fainelli@gmail.com> wrote:
> This patch series updates of_mdiobus_register() such that when the device_node
> argument is NULL, it calls mdiobus_register() directly. This is consistent with
> the behavior of of_mdiobus_register() when CONFIG_OF=n.
IMHO the CONFIG_OF=n behavior of of_mdiobus_register() (which I wasn't
aware of) is inconsistent with the behavior of other of_*() functions,
which are just empty stubs.
So I'm wondering if you should do it the other way around, and let
mdiobus_register() call of_mdiobus_register() if dev->of_node exists?
This does mean mdiobus_register() should gain a struct device * parameter,
and thus changes to many more drivers are needed.
> I only converted the most obvious drivers, there are others that have a much
> less obvious behavior and specifically attempt to deal with CONFIG_ACPI.
I haven't looked at the ACPI handling, but perhaps this can be moved
inside mdiobus_register() as well?
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* RE: [PATCH 5/6 v3] bus: fsl-mc: supoprt dma configure for devices on fsl-mc bus
From: Nipun Gupta @ 2018-05-16 8:48 UTC (permalink / raw)
To: Laurentiu Tudor, robin.murphy-5wv7dgnIgG8@public.gmane.org,
will.deacon-5wv7dgnIgG8@public.gmane.org,
mark.rutland-5wv7dgnIgG8@public.gmane.org,
catalin.marinas-5wv7dgnIgG8@public.gmane.org
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
stuyoder-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org,
frowand.list-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org,
linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Leo Li,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
linux-pci-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
bhelgaas-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org,
shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
hch-jcswGhMUV9g@public.gmane.org,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
In-Reply-To: <5AF9916E.8000504-3arQi8VN3Tc@public.gmane.org>
> -----Original Message-----
> From: Laurentiu Tudor
> Sent: Monday, May 14, 2018 7:10 PM
> To: Nipun Gupta <nipun.gupta-3arQi8VN3Tc@public.gmane.org>; robin.murphy-5wv7dgnIgG8@public.gmane.org;
> will.deacon-5wv7dgnIgG8@public.gmane.org; mark.rutland-5wv7dgnIgG8@public.gmane.org; catalin.marinas-5wv7dgnIgG8@public.gmane.org
> Cc: hch-jcswGhMUV9g@public.gmane.org; gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org; joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org;
> robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org; m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org; shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org;
> frowand.list-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org; bhelgaas-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org; iommu-cunTk1MwBs/ROKNJybVBZg@public.gmane.org
> foundation.org; linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org;
> linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org; linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org; linux-
> pci-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; Bharat Bhushan <bharat.bhushan-3arQi8VN3Tc@public.gmane.org>;
> stuyoder-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org; Leo Li <leoyang.li-3arQi8VN3Tc@public.gmane.org>
> Subject: Re: [PATCH 5/6 v3] bus: fsl-mc: supoprt dma configure for devices
> on fsl-mc bus
>
> Hi Nipun,
>
> On 04/27/2018 01:27 PM, Nipun Gupta wrote:
> > Signed-off-by: Nipun Gupta <nipun.gupta-3arQi8VN3Tc@public.gmane.org>
> > ---
> > drivers/bus/fsl-mc/fsl-mc-bus.c | 16 ++++++++++++----
> > 1 file changed, 12 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-
> bus.c
> > index 5d8266c..624828b 100644
> > --- a/drivers/bus/fsl-mc/fsl-mc-bus.c
> > +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
> > @@ -127,6 +127,16 @@ static int fsl_mc_bus_uevent(struct device *dev,
> struct kobj_uevent_env *env)
> > return 0;
> > }
> >
> > +static int fsl_mc_dma_configure(struct device *dev)
> > +{
> > + struct device *dma_dev = dev;
> > +
> > + while (dev_is_fsl_mc(dma_dev))
> > + dma_dev = dma_dev->parent;
> > +
> > + return of_dma_configure(dev, dma_dev->of_node, 0);
> > +}
> > +
> > static ssize_t modalias_show(struct device *dev, struct device_attribute
> *attr,
> > char *buf)
> > {
> > @@ -148,6 +158,7 @@ struct bus_type fsl_mc_bus_type = {
> > .name = "fsl-mc",
> > .match = fsl_mc_bus_match,
> > .uevent = fsl_mc_bus_uevent,
> > + .dma_configure = fsl_mc_dma_configure,
> > .dev_groups = fsl_mc_dev_groups,
> > };
> > EXPORT_SYMBOL_GPL(fsl_mc_bus_type);
> > @@ -616,6 +627,7 @@ int fsl_mc_device_add(struct fsl_mc_obj_desc
> *obj_desc,
> > mc_dev->icid = parent_mc_dev->icid;
> > mc_dev->dma_mask = FSL_MC_DEFAULT_DMA_MASK;
> > mc_dev->dev.dma_mask = &mc_dev->dma_mask;
> > + mc_dev->dev.coherent_dma_mask = mc_dev->dma_mask;
>
> This change seems a bit unrelated to the patch subject. I wonder if it
> makes sense to split it it in a distinct patch.
Okay. I will spin a v5 after splitting this patch and adding changelog (Greg's comment), fixing typo (Bjorn's comment).
Regards,
Nipun
>
> ---
> Best Regards, Laurentiu
^ permalink raw reply
* Re: [PATCH v2 0/9] Input: support for latest Lenovo thinkpads (series 80)
From: Aaron Ma @ 2018-05-16 8:48 UTC (permalink / raw)
To: Teika Kazura, dmitry.torokhov
Cc: benjamin.tissoires, devicetree, linux-input, linux-kernel
In-Reply-To: <20180516.160915.1252752723511457980.teika@gmx.com>
On 05/16/2018 03:09 PM, Teika Kazura wrote:
> From: Aaron Ma <aaron.ma@canonical.com>
> Date: Tue, 17 Apr 2018 19:42:27 +0800
>
>> Could you apply my patch too?
>>
>> It add LEN0096 that Benjamin's patch doesn't include.
>>
>> + "LEN0096", /* X280 */
> Aaron, in your original patch in last Oct [1], both *LEN0092 and* LEN0096 were aded. Which should be the case, both two, or only LEN0096?
Hi Teika:
Both LEN0096/LENO0092 are needed, so I think my original patch should be
merged, Benjamin's patch only include one of them.
Regards,
Aaron
>
> [1] https://www.spinics.net/lists/kernel/msg2625450.html
>
> Teika (Teika kazura)
>
^ permalink raw reply
* Re: [RESEND PATCH v5 0/6] Add support for PWM input capture on STM32
From: Fabrice Gasnier @ 2018-05-16 8:43 UTC (permalink / raw)
To: Lee Jones
Cc: alexandre.torgue, thierry.reding, benjamin.gaignard, robh+dt,
mark.rutland, linux, mcoquelin.stm32, benjamin.gaignard,
devicetree, linux-arm-kernel, linux-kernel, linux-pwm
In-Reply-To: <20180516080635.GE5130@dell>
On 05/16/2018 10:06 AM, Lee Jones wrote:
> On Wed, 16 May 2018, Fabrice Gasnier wrote:
>
>> This series adds support for capture to stm32-pwm driver.
>> Capture is based on DMAs.
>> - First two patches add support for requesting DMAs to MFD core
>> - Next three patches add support for capture to stm32-pwm driver
>> - This has been tested on stm32429i-eval board.
>>
>> ---
>> Changes in v5:
>> - update patch 2 (mfd: stm32-timers: add support for dmas)
>> move stm32_timers_dma struct to header file,
>> fix warning on dma_mapping_error().
>>
>> Changes in v4:
>> - Lee's comments on patch 2 (mfd: stm32-timers: add support for dmas)
>> Add kerneldoc header, better format comments.
>>
>> Changes in v3:
>> - Dropped 2 precusor patches applied by Thierry in pwm tree:
>> "pwm: stm32: fix, remove unused struct device"
>> "pwm: stm32: protect common prescaler for all channels"
>> - Note: this series applies on top on pwm tree
>> - Implements Lee's comments on MFD part: rework stm32_timers_dma struct,
>> exported routine prototype now use generic device struct, more
>> various comments (see patch 2 changelog).
>>
>> Resend v2:
>> - Add collected Acks
>>
>> Changes in v2:
>> - Abstract DMA handling from child driver: move it to MFD core
>> - Rework pwm capture routines to adopt this change
>> - Comment on optional dma support, beautify DMAs probe
>>
>> Fabrice Gasnier (6):
>> dt-bindings: mfd: stm32-timers: add support for dmas
>> mfd: stm32-timers: add support for dmas
>> pwm: stm32: add capture support
>> pwm: stm32: improve capture by tuning counter prescaler
>> pwm: stm32: use input prescaler to improve period capture
>> ARM: dts: stm32: Enable pwm3 input capture on stm32f429i-eval
>
> Applied patches 1-5.
Many thanks Lee !
Maybe I missed something, but just in case...
In your pull request ("[GIT PULL] Immutable branch between MFD and PWM
due for the v4.18 merge window") I only see 4 patches:
Fabrice Gasnier (4):
mfd: stm32-timers: Add support for DMAs
pwm: stm32: Add capture support
pwm: stm32: Improve capture by tuning counter prescaler
pwm: stm32: Use input prescaler to improve period capture
I can't see patch 1 ("dt-bindings: mfd: stm32-timers: add support for dmas")
Is it applied on another tree ?
Best Regards,
Fabrice
>
>> .../devicetree/bindings/mfd/stm32-timers.txt | 20 ++
>> arch/arm/boot/dts/stm32429i-eval.dts | 3 +
>> drivers/mfd/stm32-timers.c | 201 +++++++++++++++-
>> drivers/pwm/pwm-stm32.c | 257 +++++++++++++++++++++
>> include/linux/mfd/stm32-timers.h | 58 +++++
>> 5 files changed, 537 insertions(+), 2 deletions(-)
>>
>
^ permalink raw reply
* RE: [PATCH v5 12/14] staging: typec: tcpci: keep the not connecting cc line open
From: Peter Chen @ 2018-05-16 8:35 UTC (permalink / raw)
To: Jun Li, robh+dt@kernel.org, gregkh@linuxfoundation.org,
heikki.krogerus@linux.intel.com, linux@roeck-us.net
Cc: a.hajda@samsung.com, cw00.choi@samsung.com,
shufan_lee@richtek.com, gsomlo@gmail.com,
devicetree@vger.kernel.org, linux-usb@vger.kernel.org,
dl-linux-imx
In-Reply-To: <1525307094-27402-13-git-send-email-jun.li@nxp.com>
>
> While set polarity, we should keep the not connecting cc line to be open.
>
keep the disconnected cc line open?
Peter
> Signed-off-by: Li Jun <jun.li@nxp.com>
> ---
> drivers/staging/typec/tcpci.c | 18 ++++++++++++++----
> 1 file changed, 14 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c index
> 5c48810..5c0c5e3 100644
> --- a/drivers/staging/typec/tcpci.c
> +++ b/drivers/staging/typec/tcpci.c
> @@ -185,15 +185,25 @@ static int tcpci_set_polarity(struct tcpc_dev *tcpc,
> enum typec_cc_polarity polarity) {
> struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
> + unsigned int reg;
> int ret;
>
> - ret = regmap_write(tcpci->regmap, TCPC_TCPC_CTRL,
> - (polarity == TYPEC_POLARITY_CC2) ?
> - TCPC_TCPC_CTRL_ORIENTATION : 0);
> + /* Keep the disconnect cc line open */
> + ret = regmap_read(tcpci->regmap, TCPC_ROLE_CTRL, ®);
> if (ret < 0)
> return ret;
>
> - return 0;
> + if (polarity == TYPEC_POLARITY_CC2)
> + reg |= TCPC_ROLE_CTRL_CC_OPEN <<
> TCPC_ROLE_CTRL_CC1_SHIFT;
> + else
> + reg |= TCPC_ROLE_CTRL_CC_OPEN <<
> TCPC_ROLE_CTRL_CC2_SHIFT;
> + ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> + if (ret < 0)
> + return ret;
> +
> + return regmap_write(tcpci->regmap, TCPC_TCPC_CTRL,
> + (polarity == TYPEC_POLARITY_CC2) ?
> + TCPC_TCPC_CTRL_ORIENTATION : 0);
> }
>
> static int tcpci_set_vconn(struct tcpc_dev *tcpc, bool enable)
> --
> 2.7.4
^ permalink raw reply
* [GIT PULL] Immutable branch between MFD and PWM due for the v4.18 merge window
From: Lee Jones @ 2018-05-16 8:19 UTC (permalink / raw)
To: Fabrice Gasnier
Cc: alexandre.torgue, thierry.reding, benjamin.gaignard, robh+dt,
mark.rutland, linux, mcoquelin.stm32, benjamin.gaignard,
devicetree, linux-arm-kernel, linux-kernel, linux-pwm
In-Reply-To: <1526456161-27865-1-git-send-email-fabrice.gasnier@st.com>
Enjoy!
The following changes since commit 60cc43fc888428bb2f18f08997432d426a243338:
Linux 4.17-rc1 (2018-04-15 18:24:20 -0700)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git ib-mfd-pwm-v4.18
for you to fetch changes up to ab3a897847834bf3e864fb07b733c444895a24ba:
pwm: stm32: Use input prescaler to improve period capture (2018-05-16 09:11:19 +0100)
----------------------------------------------------------------
Immutable branch between MFD and PWM due for the v4.18 merge window
----------------------------------------------------------------
Fabrice Gasnier (4):
mfd: stm32-timers: Add support for DMAs
pwm: stm32: Add capture support
pwm: stm32: Improve capture by tuning counter prescaler
pwm: stm32: Use input prescaler to improve period capture
drivers/mfd/stm32-timers.c | 201 +++++++++++++++++++++++++++++-
drivers/pwm/pwm-stm32.c | 257 +++++++++++++++++++++++++++++++++++++++
include/linux/mfd/stm32-timers.h | 58 +++++++++
3 files changed, 514 insertions(+), 2 deletions(-)
--
Lee Jones [李琼斯]
Linaro Services Technical Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* Re: [PATCH v6 09/17] media: rkisp1: add rockchip isp1 core driver
From: Tomasz Figa @ 2018-05-16 8:08 UTC (permalink / raw)
To: Jacob Chen, Shunqian Zheng
Cc: open list:ARM/Rockchip SoC..., Linux Kernel Mailing List,
list@263.net:IOMMU DRIVERS <iommu@lists.linux-foundation.org>, Joerg Roedel <joro@8bytes.org>,,
Mauro Carvalho Chehab, Linux Media Mailing List, Sakari Ailus,
Hans Verkuil, Laurent Pinchart, 钟以崇,
Eddie Cai, Jeffy, devicetree, Heiko Stübner, Chen Jacob,
陈城
In-Reply-To: <20180308094807.9443-10-jacob-chen@iotwrt.com>
Hi Jacob, Shunqian,
On Thu, Mar 8, 2018 at 6:49 PM Jacob Chen <jacob-chen@iotwrt.com> wrote:
[snip]
> +static const struct of_device_id rkisp1_plat_of_match[] = {
> + {
> + .compatible = "rockchip,rk3288-cif-isp",
> + .data = &rk3288_isp_clk_data,
> + }, {
> + .compatible = "rockchip,rk3399-cif-isp",
> + .data = &rk3399_isp_clk_data,
> + },
> + {},
> +};
We need MODULE_DEVICE_TABLE() here.
Best regards,
Tomasz
^ permalink raw reply
* Re: [RESEND PATCH v5 0/6] Add support for PWM input capture on STM32
From: Lee Jones @ 2018-05-16 8:06 UTC (permalink / raw)
To: Fabrice Gasnier
Cc: alexandre.torgue, thierry.reding, benjamin.gaignard, robh+dt,
mark.rutland, linux, mcoquelin.stm32, benjamin.gaignard,
devicetree, linux-arm-kernel, linux-kernel, linux-pwm
In-Reply-To: <1526456161-27865-1-git-send-email-fabrice.gasnier@st.com>
On Wed, 16 May 2018, Fabrice Gasnier wrote:
> This series adds support for capture to stm32-pwm driver.
> Capture is based on DMAs.
> - First two patches add support for requesting DMAs to MFD core
> - Next three patches add support for capture to stm32-pwm driver
> - This has been tested on stm32429i-eval board.
>
> ---
> Changes in v5:
> - update patch 2 (mfd: stm32-timers: add support for dmas)
> move stm32_timers_dma struct to header file,
> fix warning on dma_mapping_error().
>
> Changes in v4:
> - Lee's comments on patch 2 (mfd: stm32-timers: add support for dmas)
> Add kerneldoc header, better format comments.
>
> Changes in v3:
> - Dropped 2 precusor patches applied by Thierry in pwm tree:
> "pwm: stm32: fix, remove unused struct device"
> "pwm: stm32: protect common prescaler for all channels"
> - Note: this series applies on top on pwm tree
> - Implements Lee's comments on MFD part: rework stm32_timers_dma struct,
> exported routine prototype now use generic device struct, more
> various comments (see patch 2 changelog).
>
> Resend v2:
> - Add collected Acks
>
> Changes in v2:
> - Abstract DMA handling from child driver: move it to MFD core
> - Rework pwm capture routines to adopt this change
> - Comment on optional dma support, beautify DMAs probe
>
> Fabrice Gasnier (6):
> dt-bindings: mfd: stm32-timers: add support for dmas
> mfd: stm32-timers: add support for dmas
> pwm: stm32: add capture support
> pwm: stm32: improve capture by tuning counter prescaler
> pwm: stm32: use input prescaler to improve period capture
> ARM: dts: stm32: Enable pwm3 input capture on stm32f429i-eval
Applied patches 1-5.
> .../devicetree/bindings/mfd/stm32-timers.txt | 20 ++
> arch/arm/boot/dts/stm32429i-eval.dts | 3 +
> drivers/mfd/stm32-timers.c | 201 +++++++++++++++-
> drivers/pwm/pwm-stm32.c | 257 +++++++++++++++++++++
> include/linux/mfd/stm32-timers.h | 58 +++++
> 5 files changed, 537 insertions(+), 2 deletions(-)
>
--
Lee Jones [李琼斯]
Linaro Services Technical Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* Re: [PATCH 4/6] drm/panel: simple: Add support for Banana Pi 7" S070WV20-CT16 panel
From: Chen-Yu Tsai @ 2018-05-16 7:56 UTC (permalink / raw)
To: Jagan Teki
Cc: Mark Rutland, devicetree, Jonathan Liu, Rob Herring,
Maxime Ripard, linux-kernel, dri-devel, David Airlie,
Thierry Reding, linux-arm-kernel
In-Reply-To: <CAMty3ZBSkrdV=SPqK5UoBTN8b+KLD9vsgDkx6DYLxEfb9_TazA@mail.gmail.com>
On Wed, May 16, 2018 at 12:20 AM, Jagan Teki <jagan@amarulasolutions.com> wrote:
> On Wed, May 16, 2018 at 12:12 PM, Chen-Yu Tsai <wens@csie.org> wrote:
>> On Mon, May 14, 2018 at 11:03 AM, Jagan Teki <jagan@amarulasolutions.com> wrote:
>>> On Thu, Apr 19, 2018 at 3:02 PM, Chen-Yu Tsai <wens@csie.org> wrote:
>>>> This panel is marketed as Banana Pi 7" LCD display. On the back is
>>>> a sticker denoting the model name S070WV20-CT16.
>>>>
>>>> This is a 7" 800x480 panel connected through a 24-bit RGB interface.
>>>> However the panel only does 262k colors.
>>>>
>>>> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
>>>> ---
>>>> .../display/panel/bananapi,s070wv20-ct16.txt | 7 ++++++
>>>> drivers/gpu/drm/panel/panel-simple.c | 25 +++++++++++++++++++
>>>> 2 files changed, 32 insertions(+)
>>>> create mode 100644 Documentation/devicetree/bindings/display/panel/bananapi,s070wv20-ct16.txt
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/display/panel/bananapi,s070wv20-ct16.txt b/Documentation/devicetree/bindings/display/panel/bananapi,s070wv20-ct16.txt
>>>> new file mode 100644
>>>> index 000000000000..2ec35ce36e9a
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/display/panel/bananapi,s070wv20-ct16.txt
>>>> @@ -0,0 +1,7 @@
>>>> +Banana Pi 7" (S070WV20-CT16) TFT LCD Panel
>>>> +
>>>> +Required properties:
>>>> +- compatible: should be "bananapi,s070wv20-ct16"
>>>> +
>>>> +This binding is compatible with the simple-panel binding, which is specified
>>>> +in simple-panel.txt in this directory.
>>>> diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
>>>> index cbf1ab404ee7..9bc037f74d6c 100644
>>>> --- a/drivers/gpu/drm/panel/panel-simple.c
>>>> +++ b/drivers/gpu/drm/panel/panel-simple.c
>>>> @@ -745,6 +745,28 @@ static const struct panel_desc avic_tm070ddh03 = {
>>>> },
>>>> };
>>>>
>>>> +static const struct drm_display_mode bananapi_s070wv20_ct16_mode = {
>>>> + .clock = 30000,
>>>> + .hdisplay = 800,
>>>> + .hsync_start = 800 + 40,
>>>> + .hsync_end = 800 + 40 + 48,
>>>> + .htotal = 800 + 40 + 48 + 40,
>>>> + .vdisplay = 480,
>>>> + .vsync_start = 480 + 13,
>>>> + .vsync_end = 480 + 13 + 3,
>>>> + .vtotal = 480 + 13 + 3 + 29,
>>>> +};
>>>> +
>>>> +static const struct panel_desc bananapi_s070wv20_ct16 = {
>>>> + .modes = &bananapi_s070wv20_ct16_mode,
>>>> + .num_modes = 1,
>>>> + .bpc = 6,
>>>> + .size = {
>>>> + .width = 154,
>>>> + .height = 86,
>>>> + },
>>>> +};
>>>
>>> I think this parallel RGB interface right? I too have same display
>>> with DSI I'm sure these setting will not useful right? do we need to
>>> write separate panel driver for that?
>>
>> AFAIK the DSI model is an RGB panel with a MIPI DSI bridge on the
>> connector board. The model I have is dual interface.
>
> Yes, this is what I have [1] where same strip can use for both RGB and
> MIPI DSI. can bananapi,s070wv20-ct16 work for DSI interface as well?
In theory yes. You can use RGB with Banana Pi M1+ and DSI with Banana Pi M3.
However, DSI on A83T is not supported yet, and I don't intend to spend my
time writing a driver for the MIPI DSI bridge on that panel. The bridge IC
is the one on top of the DSI FPC connector.
ChenYu
> [1] https://www.aliexpress.com/item/New-Arrival-Banana-Pro-Pi-7-inch-LCD-Display-Touch-Screen-Raspberry-Pi-Car-GPS-FreeShipping/32335608836.html
>
> Jagan.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* Re: [PATCH 1/3] dt-bindings: media: rcar-vin: Add R8A77995 support
From: Simon Horman @ 2018-05-16 7:49 UTC (permalink / raw)
To: jacopo mondi
Cc: Jacopo Mondi, niklas.soderlund, laurent.pinchart, geert,
magnus.damm, robh+dt, linux-renesas-soc, devicetree,
linux-arm-kernel, linux-kernel
In-Reply-To: <20180515083627.GR5956@w540>
On Tue, May 15, 2018 at 10:36:27AM +0200, jacopo mondi wrote:
> Hi Simon,
>
> On Fri, May 11, 2018 at 03:35:14PM +0200, Simon Horman wrote:
> > On Fri, May 11, 2018 at 12:00:00PM +0200, Jacopo Mondi wrote:
> > > Add compatible string for R-Car D3 R8A7795 to list of SoCs supported by
> > > rcar-vin driver.
> > >
> > > Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
> >
> > Reviewed-by: Simon Horman <horms+renesas@verge.net.au>
> >
>
> Does this goes in through your tree? I will send a v2, should I
> include this one or you have collected it already?
No, it means I am reviewing it with the expectation that it will
go through someone else's tree. So if you need to post a v2 please include
this patch with my Reviewed-by tag.
^ permalink raw reply
* Re: [PATCH v10 00/27] ARM: davinci: convert to common clock framework
From: Bartosz Golaszewski @ 2018-05-16 7:47 UTC (permalink / raw)
To: Adam Ford
Cc: Bartosz Golaszewski, David Lechner, linux-clk, devicetree,
arm-soc, Michael Turquette, Stephen Boyd, Rob Herring,
Mark Rutland, Sekhar Nori, Kevin Hilman,
Linux Kernel Mailing List
In-Reply-To: <CAHCN7xJt=tsc2zHWu+6y_2z=+kHdaovh3TD_MJ1+UeUbTdyj8w@mail.gmail.com>
2018-05-16 0:44 GMT+02:00 Adam Ford <aford173@gmail.com>:
> On Tue, May 15, 2018 at 4:25 AM, Bartosz Golaszewski <brgl@bgdev.pl> wrote:
>> 2018-05-14 2:40 GMT+02:00 Adam Ford <aford173@gmail.com>:
>>> On Wed, May 9, 2018 at 12:25 PM, David Lechner <david@lechnology.com> wrote:
>>>> This series converts mach-davinci to use the common clock framework.
>>>>
>>>> The series works like this, the first 3 patches fix some issues with the clock
>>>> drivers that have already been accepted into the mainline kernel.
>>>>
>>>> Then, starting with "ARM: davinci: pass clock as parameter to
>>>> davinci_timer_init()", we get the mach code ready for the switch by adding the
>>>> code needed for the new clock drivers and adding #ifndef CONFIG_COMMON_CLK
>>>> around the legacy clocks so that we can switch easily between the old and the
>>>> new.
>>>>
>>>> "ARM: davinci: switch to common clock framework" actually flips the switch
>>>> to start using the new clock drivers. Then the next 8 patches remove all
>>>> of the old clock code.
>>>>
>>>> The final four patches add device tree clock support to the one SoC that
>>>> supports it.
>>>>
>>>> This series has been tested on TI OMAP-L138 LCDK (both device tree and legacy
>>>> board file).
>>>>
>>>
>>> I am not sure if I did something wrong, but I attempted to build and I
>>> wasn't able to boot the da850-evm.dtb your repo common-clk-v11,
>>> however the legacy board file boot was OK.
>>>
>>> make davinci_all_defconfig ARCH=arm
>>> make zImage modules da850-evm.dtb ARCH=arm CROSS_COMPILE=arm-linux- -j8
>>>
>>> 3140416 bytes read in 1464 ms (2 MiB/s)
>>> 20353 bytes read in 15 ms (1.3 MiB/s)
>>> ## Flattened Device Tree blob at c0600000
>>> Booting using the fdt blob at 0xc0600000
>>> Loading Device Tree to c7e57000, end c7e5ef80 ... OK
>>>
>>> Starting kernel ...
>>>
>>> Uncompressing Linux... done, booting the kernel.
>>>
>>> (and hang)
>>>
>>> If you have some suggestions, I am try them as I get time.
>>>
>>> adam
>>>
>>
>> Runs fine on da850-lcdk and dm365-evm. I'll test the da850-evm
>> tomorrow when I'll have access to it.
>
> I set the bootargs to: bootargs=console=ttyS2,115200n8
> clk_ignore_unused root=/dev/mmcblk0p2 rw rootfstype=ext4 rootwait
>
> I enabled DEBUG_LL and EARLY_PRINTK, yet when it loads, I only get:
>
> ## Flattened Device Tree blob at c0600000
> Booting using the fdt blob at 0xc0600000
> Loading Device Tree to c7e57000, end c7e5ef35 ... OK
>
> Starting kernel ...
>
> Uncompressing Linux... done, booting the kernel.
>
>
> I am doing this at my home, so I don't have a debugger for the
> DA850-EVM. I am using a SOM that is an AM1808, but I vaguely remember
> something about enabling a DSP clock somewhere, but I cannot seem to
> find the e-mail. I know its counter intuitive that we'd need to
> enable a clock that runs the DSP since it doesn't exist on the AM1808,
> but I would have thought the clk_ignore_unused would have worked
> around that issue.
>
> If someone else has a DA850-EVM or suggestions, I'm willing to try
> them as I have time.
>
> adam
Hi Adam,
everything works fine for me both when booting the DTB and in legacy
mode on da850-evm.
I'm using the following bootargs:
ip=dhcp console=ttyS2,115200n8 root=/dev/nfs rw nfsroot=<snip!>,v3
nfsrootdebug
Regular davinci_all_defconfig on David's common-clk-v11 branch.
Best regards,
Bartosz Golaszewski
^ permalink raw reply
* Re: [PATCH v2 2/2] soc: renesas: r8a77990-sysc: Add workaround for 3DG-{A,B}
From: Geert Uytterhoeven @ 2018-05-16 7:47 UTC (permalink / raw)
To: Yoshihiro Shimoda
Cc: Simon Horman, Magnus Damm, Rob Herring, Mark Rutland,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Linux-Renesas
In-Reply-To: <1526386059-6173-3-git-send-email-yoshihiro.shimoda.uh@renesas.com>
On Tue, May 15, 2018 at 2:07 PM, Yoshihiro Shimoda
<yoshihiro.shimoda.uh@renesas.com> wrote:
> This patch adds workaround for 3DG-{A,B} of R-Car E3 ES1.0 because
> the SoC has a restriction about the order.
>
> Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH v2 1/2] soc: renesas: rcar-sysc: Add support for R-Car E3 power areas
From: Geert Uytterhoeven @ 2018-05-16 7:45 UTC (permalink / raw)
To: Yoshihiro Shimoda
Cc: Simon Horman, Magnus Damm, Rob Herring, Mark Rutland,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Linux-Renesas, Takeshi Kihara
In-Reply-To: <1526386059-6173-2-git-send-email-yoshihiro.shimoda.uh@renesas.com>
On Tue, May 15, 2018 at 2:07 PM, Yoshihiro Shimoda
<yoshihiro.shimoda.uh@renesas.com> wrote:
> From: Takeshi Kihara <takeshi.kihara.df@renesas.com>
>
> This patch adds Cortex-A53 CPU{0,1}, Cortex-A53 SCU, Cortex-R7, A3VC,
> A2VC1 and 3DG-{A,B} power domain areas for the R8A77990 SoC.
>
> Signed-off-by: Takeshi Kihara <takeshi.kihara.df@renesas.com>
> [shimoda: fix 3DG-{A,B} and add SPDX-License-Identifier]
> Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH 3/3] arm64: dts: renesas: r8a7795: add ccree binding
From: Simon Horman @ 2018-05-16 7:43 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Gilad Ben-Yossef, Magnus Damm, Rob Herring, Mark Rutland,
Catalin Marinas, Will Deacon, Geert Uytterhoeven,
Michael Turquette, Stephen Boyd, Herbert Xu, David S. Miller,
Ofir Drang, Linux-Renesas,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Linux ARM, Linux Kernel Mailing List, linux-clk
In-Reply-To: <CAMuHMdWzeNqsho1V6ezZb81T3_HcRzrtuQpmGXsjtFgt9BtZDQ@mail.gmail.com>
On Tue, May 15, 2018 at 04:50:44PM +0200, Geert Uytterhoeven wrote:
> Hi Gilad,
>
> On Tue, May 15, 2018 at 2:29 PM, Gilad Ben-Yossef <gilad@benyossef.com> wrote:
> > Add bindings for CryptoCell instance in the SoC.
> >
> > Signed-off-by: Gilad Ben-Yossef <gilad@benyossef.com>
>
> Thanks for your patch!
>
> > --- a/arch/arm64/boot/dts/renesas/r8a7795.dtsi
> > +++ b/arch/arm64/boot/dts/renesas/r8a7795.dtsi
> > @@ -528,6 +528,14 @@
> > status = "disabled";
> > };
> >
> > + arm_cc630p: crypto@e6601000 {
> > + compatible = "arm,cryptocell-630p-ree";
> > + interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
> > + #interrupt-cells = <2>;
>
> I believe the #interrupt-cells property is not needed.
>
> > + reg = <0x0 0xe6601000 0 0x1000>;
> > + clocks = <&cpg CPG_MOD 229>;
> > + };
>
> The rest looks good, but I cannot verify the register block.
>
> > +
> > i2c3: i2c@e66d0000 {
> > #address-cells = <1>;
> > #size-cells = <0>;
Thanks, I have applied this after dropping the #interrupt-cells property.
^ permalink raw reply
* Re: [PATCH v2 2/2] ARM: dts: r8a7740: Add CEU0
From: Geert Uytterhoeven @ 2018-05-16 7:40 UTC (permalink / raw)
To: Jacopo Mondi
Cc: Simon Horman, Rob Herring, Mark Rutland, Linux-Renesas,
Linux Media Mailing List,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Linux Kernel Mailing List
In-Reply-To: <1524767083-19862-3-git-send-email-jacopo+renesas@jmondi.org>
Hi Jacopo,
On Thu, Apr 26, 2018 at 8:24 PM, Jacopo Mondi <jacopo+renesas@jmondi.org> wrote:
> Describe CEU0 peripheral for Renesas R-Mobile A1 R8A7740 Soc.
>
> Reported-by: Geert Uytterhoeven <geert@glider.be>
> Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
Thanks for your patch!
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Minor question below.
> --- a/arch/arm/boot/dts/r8a7740.dtsi
> +++ b/arch/arm/boot/dts/r8a7740.dtsi
> @@ -67,6 +67,16 @@
> power-domains = <&pd_d4>;
> };
>
> + ceu0: ceu@fe910000 {
> + reg = <0xfe910000 0x3000>;
> + compatible = "renesas,r8a7740-ceu";
> + interrupts = <GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>;
> + clocks = <&mstp1_clks R8A7740_CLK_CEU20>;
> + clock-names = "ceu20";
Why the "clock-names" property? It's not mentioned in the DT bindings, and
may cause issues if the bindings are ever amended.
> + power-domains = <&pd_a4r>;
> + status = "disabled";
> + };
> +
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* [RESEND PATCH v5 6/6] ARM: dts: stm32: Enable pwm3 input capture on stm32f429i-eval
From: Fabrice Gasnier @ 2018-05-16 7:36 UTC (permalink / raw)
To: lee.jones, alexandre.torgue
Cc: thierry.reding, benjamin.gaignard, robh+dt, mark.rutland, linux,
mcoquelin.stm32, fabrice.gasnier, benjamin.gaignard, devicetree,
linux-arm-kernel, linux-kernel, linux-pwm
In-Reply-To: <1526456161-27865-1-git-send-email-fabrice.gasnier@st.com>
Enable pwm3 input capture on stm32f429i-eval, by using DMA.
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
Reviewed-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
---
arch/arm/boot/dts/stm32429i-eval.dts | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/arm/boot/dts/stm32429i-eval.dts b/arch/arm/boot/dts/stm32429i-eval.dts
index 7eb786a..88d878a 100644
--- a/arch/arm/boot/dts/stm32429i-eval.dts
+++ b/arch/arm/boot/dts/stm32429i-eval.dts
@@ -290,6 +290,9 @@
&timers3 {
status = "okay";
+ /* Enable PWM input capture by using dma */
+ dmas = <&dma1 4 5 0x400 0x0>;
+ dma-names = "ch1";
pwm {
pinctrl-0 = <&pwm3_pins>;
pinctrl-names = "default";
--
1.9.1
^ permalink raw reply related
* [RESEND PATCH v5 5/6] pwm: stm32: use input prescaler to improve period capture
From: Fabrice Gasnier @ 2018-05-16 7:36 UTC (permalink / raw)
To: lee.jones, alexandre.torgue
Cc: mark.rutland, devicetree, benjamin.gaignard, linux-pwm, linux,
linux-kernel, robh+dt, thierry.reding, mcoquelin.stm32,
fabrice.gasnier, linux-arm-kernel, benjamin.gaignard
In-Reply-To: <1526456161-27865-1-git-send-email-fabrice.gasnier@st.com>
Using input prescaler, capture unit will trigger DMA once every
configurable /2, /4 or /8 events (rising edge). This helps improve
period (only) capture accuracy at high rates.
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
Reviewed-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
Acked-by: Thierry Reding <thierry.reding@gmail.com>
---
Changes in v2:
- Adopt DMA read from MFD core.
---
drivers/pwm/pwm-stm32.c | 63 ++++++++++++++++++++++++++++++++++++++--
include/linux/mfd/stm32-timers.h | 1 +
2 files changed, 62 insertions(+), 2 deletions(-)
diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
index 9a50acd..60bfc07 100644
--- a/drivers/pwm/pwm-stm32.c
+++ b/drivers/pwm/pwm-stm32.c
@@ -8,6 +8,7 @@
* pwm-atmel.c from Bo Shen
*/
+#include <linux/bitfield.h>
#include <linux/mfd/stm32-timers.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -168,7 +169,7 @@ static int stm32_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm,
struct stm32_pwm *priv = to_stm32_pwm_dev(chip);
unsigned long long prd, div, dty;
unsigned long rate;
- unsigned int psc = 0, scale;
+ unsigned int psc = 0, icpsc, scale;
u32 raw_prd, raw_dty;
int ret = 0;
@@ -222,6 +223,7 @@ static int stm32_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm,
/*
* Got a capture. Try to improve accuracy at high rates:
* - decrease counter clock prescaler, scale up to max rate.
+ * - use input prescaler, capture once every /2 /4 or /8 edges.
*/
if (raw_prd) {
u32 max_arr = priv->max_arr - 0x1000; /* arbitrary margin */
@@ -241,8 +243,65 @@ static int stm32_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm,
goto stop;
}
+ /* Compute intermediate period not to exceed timeout at low rates */
prd = (unsigned long long)raw_prd * (psc + 1) * NSEC_PER_SEC;
- result->period = DIV_ROUND_UP_ULL(prd, rate);
+ do_div(prd, rate);
+
+ for (icpsc = 0; icpsc < MAX_TIM_ICPSC ; icpsc++) {
+ /* input prescaler: also keep arbitrary margin */
+ if (raw_prd >= (priv->max_arr - 0x1000) >> (icpsc + 1))
+ break;
+ if (prd >= (tmo_ms * NSEC_PER_MSEC) >> (icpsc + 2))
+ break;
+ }
+
+ if (!icpsc)
+ goto done;
+
+ /* Last chance to improve period accuracy, using input prescaler */
+ regmap_update_bits(priv->regmap,
+ pwm->hwpwm < 2 ? TIM_CCMR1 : TIM_CCMR2,
+ TIM_CCMR_IC1PSC | TIM_CCMR_IC2PSC,
+ FIELD_PREP(TIM_CCMR_IC1PSC, icpsc) |
+ FIELD_PREP(TIM_CCMR_IC2PSC, icpsc));
+
+ ret = stm32_pwm_raw_capture(priv, pwm, tmo_ms, &raw_prd, &raw_dty);
+ if (ret)
+ goto stop;
+
+ if (raw_dty >= (raw_prd >> icpsc)) {
+ /*
+ * We may fall here using input prescaler, when input
+ * capture starts on high side (before falling edge).
+ * Example with icpsc to capture on each 4 events:
+ *
+ * start 1st capture 2nd capture
+ * v v v
+ * ___ _____ _____ _____ _____ ____
+ * TI1..4 |__| |__| |__| |__| |__|
+ * v v . . . . . v v
+ * icpsc1/3: . 0 . 1 . 2 . 3 . 0
+ * icpsc2/4: 0 1 2 3 0
+ * v v v v
+ * CCR1/3 ......t0..............................t2
+ * CCR2/4 ..t1..............................t1'...
+ * . . .
+ * Capture0: .<----------------------------->.
+ * Capture1: .<-------------------------->. .
+ * . . .
+ * Period: .<------> . .
+ * Low side: .<>.
+ *
+ * Result:
+ * - Period = Capture0 / icpsc
+ * - Duty = Period - Low side = Period - (Capture0 - Capture1)
+ */
+ raw_dty = (raw_prd >> icpsc) - (raw_prd - raw_dty);
+ }
+
+done:
+ prd = (unsigned long long)raw_prd * (psc + 1) * NSEC_PER_SEC;
+ result->period = DIV_ROUND_UP_ULL(prd, rate << icpsc);
dty = (unsigned long long)raw_dty * (psc + 1) * NSEC_PER_SEC;
result->duty_cycle = DIV_ROUND_UP_ULL(dty, rate);
stop:
diff --git a/include/linux/mfd/stm32-timers.h b/include/linux/mfd/stm32-timers.h
index d46f550..9da1d7e 100644
--- a/include/linux/mfd/stm32-timers.h
+++ b/include/linux/mfd/stm32-timers.h
@@ -82,6 +82,7 @@
#define TIM_DCR_DBL GENMASK(12, 8) /* DMA burst len */
#define MAX_TIM_PSC 0xFFFF
+#define MAX_TIM_ICPSC 0x3
#define TIM_CR2_MMS_SHIFT 4
#define TIM_CR2_MMS2_SHIFT 20
#define TIM_SMCR_TS_SHIFT 4
--
1.9.1
^ permalink raw reply related
* [RESEND PATCH v5 4/6] pwm: stm32: improve capture by tuning counter prescaler
From: Fabrice Gasnier @ 2018-05-16 7:35 UTC (permalink / raw)
To: lee.jones, alexandre.torgue
Cc: mark.rutland, devicetree, benjamin.gaignard, linux-pwm, linux,
linux-kernel, robh+dt, thierry.reding, mcoquelin.stm32,
fabrice.gasnier, linux-arm-kernel, benjamin.gaignard
In-Reply-To: <1526456161-27865-1-git-send-email-fabrice.gasnier@st.com>
Currently, capture is based on timeout window to configure prescaler.
PWM capture framework provides 1s window at the time of writing.
There's place for improvement, after input signal has been captured once:
- Finer tune counter clock prescaler, by using 1st capture result (with
arbitrary margin).
- Do a 2nd capture, with scaled capture window.
This increases accuracy, especially at high rates.
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
Reviewed-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
Acked-by: Thierry Reding <thierry.reding@gmail.com>
---
Changes in v2:
- Adopt DMA read from MFD core.
---
drivers/pwm/pwm-stm32.c | 24 +++++++++++++++++++++++-
1 file changed, 23 insertions(+), 1 deletion(-)
diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
index ed3961b..9a50acd 100644
--- a/drivers/pwm/pwm-stm32.c
+++ b/drivers/pwm/pwm-stm32.c
@@ -168,7 +168,7 @@ static int stm32_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm,
struct stm32_pwm *priv = to_stm32_pwm_dev(chip);
unsigned long long prd, div, dty;
unsigned long rate;
- unsigned int psc = 0;
+ unsigned int psc = 0, scale;
u32 raw_prd, raw_dty;
int ret = 0;
@@ -219,6 +219,28 @@ static int stm32_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm,
if (ret)
goto stop;
+ /*
+ * Got a capture. Try to improve accuracy at high rates:
+ * - decrease counter clock prescaler, scale up to max rate.
+ */
+ if (raw_prd) {
+ u32 max_arr = priv->max_arr - 0x1000; /* arbitrary margin */
+
+ scale = max_arr / min(max_arr, raw_prd);
+ } else {
+ scale = priv->max_arr; /* bellow resolution, use max scale */
+ }
+
+ if (psc && scale > 1) {
+ /* 2nd measure with new scale */
+ psc /= scale;
+ regmap_write(priv->regmap, TIM_PSC, psc);
+ ret = stm32_pwm_raw_capture(priv, pwm, tmo_ms, &raw_prd,
+ &raw_dty);
+ if (ret)
+ goto stop;
+ }
+
prd = (unsigned long long)raw_prd * (psc + 1) * NSEC_PER_SEC;
result->period = DIV_ROUND_UP_ULL(prd, rate);
dty = (unsigned long long)raw_dty * (psc + 1) * NSEC_PER_SEC;
--
1.9.1
^ permalink raw reply related
* [RESEND PATCH v5 3/6] pwm: stm32: add capture support
From: Fabrice Gasnier @ 2018-05-16 7:35 UTC (permalink / raw)
To: lee.jones, alexandre.torgue
Cc: thierry.reding, benjamin.gaignard, robh+dt, mark.rutland, linux,
mcoquelin.stm32, fabrice.gasnier, benjamin.gaignard, devicetree,
linux-arm-kernel, linux-kernel, linux-pwm
In-Reply-To: <1526456161-27865-1-git-send-email-fabrice.gasnier@st.com>
Add support for PMW input mode on pwm-stm32. STM32 timers support
period and duty cycle capture as long as they have at least two PWM
channels. One capture channel is used for period (rising-edge), one
for duty-cycle (falling-edge).
When there's only one channel available, only period can be captured.
Duty-cycle is simply zero'ed in such a case.
Capture requires exclusive access (e.g. no pwm output running at the
same time, to protect common prescaler).
Timer DMA burst mode (from MFD core) is being used, to take two
snapshots of capture registers (upon each period rising edge).
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
Reviewed-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
Acked-by: Thierry Reding <thierry.reding@gmail.com>
---
Changes in v3:
- update stm32_timers_dma_burst_read() call: don't pass ddata structure,
use MFD parent device structure instead since MFD core update.
Changes in v2:
- DMA handling has been moved to MFD core. Rework capture routines to
use it.
---
drivers/pwm/pwm-stm32.c | 176 +++++++++++++++++++++++++++++++++++++++
include/linux/mfd/stm32-timers.h | 11 +++
2 files changed, 187 insertions(+)
diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
index 2708212..ed3961b 100644
--- a/drivers/pwm/pwm-stm32.c
+++ b/drivers/pwm/pwm-stm32.c
@@ -25,6 +25,7 @@ struct stm32_pwm {
struct regmap *regmap;
u32 max_arr;
bool have_complementary_output;
+ u32 capture[4] ____cacheline_aligned; /* DMA'able buffer */
};
struct stm32_breakinput {
@@ -62,6 +63,178 @@ static int write_ccrx(struct stm32_pwm *dev, int ch, u32 value)
return -EINVAL;
}
+#define TIM_CCER_CC12P (TIM_CCER_CC1P | TIM_CCER_CC2P)
+#define TIM_CCER_CC12E (TIM_CCER_CC1E | TIM_CCER_CC2E)
+#define TIM_CCER_CC34P (TIM_CCER_CC3P | TIM_CCER_CC4P)
+#define TIM_CCER_CC34E (TIM_CCER_CC3E | TIM_CCER_CC4E)
+
+/*
+ * Capture using PWM input mode:
+ * ___ ___
+ * TI[1, 2, 3 or 4]: ........._| |________|
+ * ^0 ^1 ^2
+ * . . .
+ * . . XXXXX
+ * . . XXXXX |
+ * . XXXXX . |
+ * XXXXX . . |
+ * COUNTER: ______XXXXX . . . |_XXX
+ * start^ . . . ^stop
+ * . . . .
+ * v v . v
+ * v
+ * CCR1/CCR3: tx..........t0...........t2
+ * CCR2/CCR4: tx..............t1.........
+ *
+ * DMA burst transfer: | |
+ * v v
+ * DMA buffer: { t0, tx } { t2, t1 }
+ * DMA done: ^
+ *
+ * 0: IC1/3 snapchot on rising edge: counter value -> CCR1/CCR3
+ * + DMA transfer CCR[1/3] & CCR[2/4] values (t0, tx: doesn't care)
+ * 1: IC2/4 snapchot on falling edge: counter value -> CCR2/CCR4
+ * 2: IC1/3 snapchot on rising edge: counter value -> CCR1/CCR3
+ * + DMA transfer CCR[1/3] & CCR[2/4] values (t2, t1)
+ *
+ * DMA done, compute:
+ * - Period = t2 - t0
+ * - Duty cycle = t1 - t0
+ */
+static int stm32_pwm_raw_capture(struct stm32_pwm *priv, struct pwm_device *pwm,
+ unsigned long tmo_ms, u32 *raw_prd,
+ u32 *raw_dty)
+{
+ struct device *parent = priv->chip.dev->parent;
+ enum stm32_timers_dmas dma_id;
+ u32 ccen, ccr;
+ int ret;
+
+ /* Ensure registers have been updated, enable counter and capture */
+ regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
+ regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN);
+
+ /* Use cc1 or cc3 DMA resp for PWM input channels 1 & 2 or 3 & 4 */
+ dma_id = pwm->hwpwm < 2 ? STM32_TIMERS_DMA_CH1 : STM32_TIMERS_DMA_CH3;
+ ccen = pwm->hwpwm < 2 ? TIM_CCER_CC12E : TIM_CCER_CC34E;
+ ccr = pwm->hwpwm < 2 ? TIM_CCR1 : TIM_CCR3;
+ regmap_update_bits(priv->regmap, TIM_CCER, ccen, ccen);
+
+ /*
+ * Timer DMA burst mode. Request 2 registers, 2 bursts, to get both
+ * CCR1 & CCR2 (or CCR3 & CCR4) on each capture event.
+ * We'll get two capture snapchots: { CCR1, CCR2 }, { CCR1, CCR2 }
+ * or { CCR3, CCR4 }, { CCR3, CCR4 }
+ */
+ ret = stm32_timers_dma_burst_read(parent, priv->capture, dma_id, ccr, 2,
+ 2, tmo_ms);
+ if (ret)
+ goto stop;
+
+ /* Period: t2 - t0 (take care of counter overflow) */
+ if (priv->capture[0] <= priv->capture[2])
+ *raw_prd = priv->capture[2] - priv->capture[0];
+ else
+ *raw_prd = priv->max_arr - priv->capture[0] + priv->capture[2];
+
+ /* Duty cycle capture requires at least two capture units */
+ if (pwm->chip->npwm < 2)
+ *raw_dty = 0;
+ else if (priv->capture[0] <= priv->capture[3])
+ *raw_dty = priv->capture[3] - priv->capture[0];
+ else
+ *raw_dty = priv->max_arr - priv->capture[0] + priv->capture[3];
+
+ if (*raw_dty > *raw_prd) {
+ /*
+ * Race beetween PWM input and DMA: it may happen
+ * falling edge triggers new capture on TI2/4 before DMA
+ * had a chance to read CCR2/4. It means capture[1]
+ * contains period + duty_cycle. So, subtract period.
+ */
+ *raw_dty -= *raw_prd;
+ }
+
+stop:
+ regmap_update_bits(priv->regmap, TIM_CCER, ccen, 0);
+ regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
+
+ return ret;
+}
+
+static int stm32_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm,
+ struct pwm_capture *result, unsigned long tmo_ms)
+{
+ struct stm32_pwm *priv = to_stm32_pwm_dev(chip);
+ unsigned long long prd, div, dty;
+ unsigned long rate;
+ unsigned int psc = 0;
+ u32 raw_prd, raw_dty;
+ int ret = 0;
+
+ mutex_lock(&priv->lock);
+
+ if (active_channels(priv)) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ ret = clk_enable(priv->clk);
+ if (ret) {
+ dev_err(priv->chip.dev, "failed to enable counter clock\n");
+ goto unlock;
+ }
+
+ rate = clk_get_rate(priv->clk);
+ if (!rate) {
+ ret = -EINVAL;
+ goto clk_dis;
+ }
+
+ /* prescaler: fit timeout window provided by upper layer */
+ div = (unsigned long long)rate * (unsigned long long)tmo_ms;
+ do_div(div, MSEC_PER_SEC);
+ prd = div;
+ while ((div > priv->max_arr) && (psc < MAX_TIM_PSC)) {
+ psc++;
+ div = prd;
+ do_div(div, psc + 1);
+ }
+ regmap_write(priv->regmap, TIM_ARR, priv->max_arr);
+ regmap_write(priv->regmap, TIM_PSC, psc);
+
+ /* Map TI1 or TI2 PWM input to IC1 & IC2 (or TI3/4 to IC3 & IC4) */
+ regmap_update_bits(priv->regmap,
+ pwm->hwpwm < 2 ? TIM_CCMR1 : TIM_CCMR2,
+ TIM_CCMR_CC1S | TIM_CCMR_CC2S, pwm->hwpwm & 0x1 ?
+ TIM_CCMR_CC1S_TI2 | TIM_CCMR_CC2S_TI2 :
+ TIM_CCMR_CC1S_TI1 | TIM_CCMR_CC2S_TI1);
+
+ /* Capture period on IC1/3 rising edge, duty cycle on IC2/4 falling. */
+ regmap_update_bits(priv->regmap, TIM_CCER, pwm->hwpwm < 2 ?
+ TIM_CCER_CC12P : TIM_CCER_CC34P, pwm->hwpwm < 2 ?
+ TIM_CCER_CC2P : TIM_CCER_CC4P);
+
+ ret = stm32_pwm_raw_capture(priv, pwm, tmo_ms, &raw_prd, &raw_dty);
+ if (ret)
+ goto stop;
+
+ prd = (unsigned long long)raw_prd * (psc + 1) * NSEC_PER_SEC;
+ result->period = DIV_ROUND_UP_ULL(prd, rate);
+ dty = (unsigned long long)raw_dty * (psc + 1) * NSEC_PER_SEC;
+ result->duty_cycle = DIV_ROUND_UP_ULL(dty, rate);
+stop:
+ regmap_write(priv->regmap, TIM_CCER, 0);
+ regmap_write(priv->regmap, pwm->hwpwm < 2 ? TIM_CCMR1 : TIM_CCMR2, 0);
+ regmap_write(priv->regmap, TIM_PSC, 0);
+clk_dis:
+ clk_disable(priv->clk);
+unlock:
+ mutex_unlock(&priv->lock);
+
+ return ret;
+}
+
static int stm32_pwm_config(struct stm32_pwm *priv, int ch,
int duty_ns, int period_ns)
{
@@ -230,6 +403,9 @@ static int stm32_pwm_apply_locked(struct pwm_chip *chip, struct pwm_device *pwm,
static const struct pwm_ops stm32pwm_ops = {
.owner = THIS_MODULE,
.apply = stm32_pwm_apply_locked,
+#if IS_ENABLED(CONFIG_DMA_ENGINE)
+ .capture = stm32_pwm_capture,
+#endif
};
static int stm32_pwm_set_breakinput(struct stm32_pwm *priv,
diff --git a/include/linux/mfd/stm32-timers.h b/include/linux/mfd/stm32-timers.h
index 9596d5c..d46f550 100644
--- a/include/linux/mfd/stm32-timers.h
+++ b/include/linux/mfd/stm32-timers.h
@@ -51,13 +51,24 @@
#define TIM_EGR_UG BIT(0) /* Update Generation */
#define TIM_CCMR_PE BIT(3) /* Channel Preload Enable */
#define TIM_CCMR_M1 (BIT(6) | BIT(5)) /* Channel PWM Mode 1 */
+#define TIM_CCMR_CC1S (BIT(0) | BIT(1)) /* Capture/compare 1 sel */
+#define TIM_CCMR_IC1PSC GENMASK(3, 2) /* Input capture 1 prescaler */
+#define TIM_CCMR_CC2S (BIT(8) | BIT(9)) /* Capture/compare 2 sel */
+#define TIM_CCMR_IC2PSC GENMASK(11, 10) /* Input capture 2 prescaler */
+#define TIM_CCMR_CC1S_TI1 BIT(0) /* IC1/IC3 selects TI1/TI3 */
+#define TIM_CCMR_CC1S_TI2 BIT(1) /* IC1/IC3 selects TI2/TI4 */
+#define TIM_CCMR_CC2S_TI2 BIT(8) /* IC2/IC4 selects TI2/TI4 */
+#define TIM_CCMR_CC2S_TI1 BIT(9) /* IC2/IC4 selects TI1/TI3 */
#define TIM_CCER_CC1E BIT(0) /* Capt/Comp 1 out Ena */
#define TIM_CCER_CC1P BIT(1) /* Capt/Comp 1 Polarity */
#define TIM_CCER_CC1NE BIT(2) /* Capt/Comp 1N out Ena */
#define TIM_CCER_CC1NP BIT(3) /* Capt/Comp 1N Polarity */
#define TIM_CCER_CC2E BIT(4) /* Capt/Comp 2 out Ena */
+#define TIM_CCER_CC2P BIT(5) /* Capt/Comp 2 Polarity */
#define TIM_CCER_CC3E BIT(8) /* Capt/Comp 3 out Ena */
+#define TIM_CCER_CC3P BIT(9) /* Capt/Comp 3 Polarity */
#define TIM_CCER_CC4E BIT(12) /* Capt/Comp 4 out Ena */
+#define TIM_CCER_CC4P BIT(13) /* Capt/Comp 4 Polarity */
#define TIM_CCER_CCXE (BIT(0) | BIT(4) | BIT(8) | BIT(12))
#define TIM_BDTR_BKE BIT(12) /* Break input enable */
#define TIM_BDTR_BKP BIT(13) /* Break input polarity */
--
1.9.1
^ permalink raw reply related
* [RESEND PATCH v5 2/6] mfd: stm32-timers: add support for dmas
From: Fabrice Gasnier @ 2018-05-16 7:35 UTC (permalink / raw)
To: lee.jones, alexandre.torgue
Cc: thierry.reding, benjamin.gaignard, robh+dt, mark.rutland, linux,
mcoquelin.stm32, fabrice.gasnier, benjamin.gaignard, devicetree,
linux-arm-kernel, linux-kernel, linux-pwm
In-Reply-To: <1526456161-27865-1-git-send-email-fabrice.gasnier@st.com>
STM32 Timers can support up to 7 DMA requests:
- 4 channels, update, compare and trigger.
Optionally request part, or all DMAs from stm32-timers MFD core.
Also add routine to implement burst reads using DMA from timer registers.
This is exported. So, it can be used by child drivers, PWM capture
for instance (but not limited to).
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
Reviewed-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
---
Changes in v5:
- fix warning on dma_mapping_error() that doesn't return an error code.
- move stm32_timers_dma struct to header file as discussed with Lee.
This allows to remove alloc for this struct in stm32_timers_dma_probe.
Changes in v4:
- Lee's comments: Add kerneldoc header, better format comments.
Changes in v3:
- Basically Lee's comments:
- rather create a struct stm32_timers_dma, and place a reference to it
in existing ddata (instead of adding priv struct).
- rather use a struct device in exported routine prototype, and use
standard helpers instead of ddata. Get rid of to_stm32_timers_priv().
- simplify error handling in probe (remove a goto)
- comment on devm_of_platform_*populate() usage.
Changes in v2:
- Abstract DMA handling from child driver: move it to MFD core
- Add comments on optional dma support
---
drivers/mfd/stm32-timers.c | 201 ++++++++++++++++++++++++++++++++++++++-
include/linux/mfd/stm32-timers.h | 46 +++++++++
2 files changed, 245 insertions(+), 2 deletions(-)
diff --git a/drivers/mfd/stm32-timers.c b/drivers/mfd/stm32-timers.c
index 1d347e5..efcd4b9 100644
--- a/drivers/mfd/stm32-timers.c
+++ b/drivers/mfd/stm32-timers.c
@@ -4,16 +4,156 @@
* Author: Benjamin Gaignard <benjamin.gaignard@st.com>
*/
+#include <linux/bitfield.h>
#include <linux/mfd/stm32-timers.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/reset.h>
+#define STM32_TIMERS_MAX_REGISTERS 0x3fc
+
+/* DIER register DMA enable bits */
+static const u32 stm32_timers_dier_dmaen[STM32_TIMERS_MAX_DMAS] = {
+ TIM_DIER_CC1DE,
+ TIM_DIER_CC2DE,
+ TIM_DIER_CC3DE,
+ TIM_DIER_CC4DE,
+ TIM_DIER_UIE,
+ TIM_DIER_TDE,
+ TIM_DIER_COMDE
+};
+
+static void stm32_timers_dma_done(void *p)
+{
+ struct stm32_timers_dma *dma = p;
+ struct dma_tx_state state;
+ enum dma_status status;
+
+ status = dmaengine_tx_status(dma->chan, dma->chan->cookie, &state);
+ if (status == DMA_COMPLETE)
+ complete(&dma->completion);
+}
+
+/**
+ * stm32_timers_dma_burst_read - Read from timers registers using DMA.
+ *
+ * Read from STM32 timers registers using DMA on a single event.
+ * @dev: reference to stm32_timers MFD device
+ * @buf: DMA'able destination buffer
+ * @id: stm32_timers_dmas event identifier (ch[1..4], up, trig or com)
+ * @reg: registers start offset for DMA to read from (like CCRx for capture)
+ * @num_reg: number of registers to read upon each DMA request, starting @reg.
+ * @bursts: number of bursts to read (e.g. like two for pwm period capture)
+ * @tmo_ms: timeout (milliseconds)
+ */
+int stm32_timers_dma_burst_read(struct device *dev, u32 *buf,
+ enum stm32_timers_dmas id, u32 reg,
+ unsigned int num_reg, unsigned int bursts,
+ unsigned long tmo_ms)
+{
+ struct stm32_timers *ddata = dev_get_drvdata(dev);
+ unsigned long timeout = msecs_to_jiffies(tmo_ms);
+ struct regmap *regmap = ddata->regmap;
+ struct stm32_timers_dma *dma = &ddata->dma;
+ size_t len = num_reg * bursts * sizeof(u32);
+ struct dma_async_tx_descriptor *desc;
+ struct dma_slave_config config;
+ dma_cookie_t cookie;
+ dma_addr_t dma_buf;
+ u32 dbl, dba;
+ long err;
+ int ret;
+
+ /* Sanity check */
+ if (id < STM32_TIMERS_DMA_CH1 || id >= STM32_TIMERS_MAX_DMAS)
+ return -EINVAL;
+
+ if (!num_reg || !bursts || reg > STM32_TIMERS_MAX_REGISTERS ||
+ (reg + num_reg * sizeof(u32)) > STM32_TIMERS_MAX_REGISTERS)
+ return -EINVAL;
+
+ if (!dma->chans[id])
+ return -ENODEV;
+ mutex_lock(&dma->lock);
+
+ /* Select DMA channel in use */
+ dma->chan = dma->chans[id];
+ dma_buf = dma_map_single(dev, buf, len, DMA_FROM_DEVICE);
+ if (dma_mapping_error(dev, dma_buf)) {
+ ret = -ENOMEM;
+ goto unlock;
+ }
+
+ /* Prepare DMA read from timer registers, using DMA burst mode */
+ memset(&config, 0, sizeof(config));
+ config.src_addr = (dma_addr_t)dma->phys_base + TIM_DMAR;
+ config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ ret = dmaengine_slave_config(dma->chan, &config);
+ if (ret)
+ goto unmap;
+
+ desc = dmaengine_prep_slave_single(dma->chan, dma_buf, len,
+ DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
+ if (!desc) {
+ ret = -EBUSY;
+ goto unmap;
+ }
+
+ desc->callback = stm32_timers_dma_done;
+ desc->callback_param = dma;
+ cookie = dmaengine_submit(desc);
+ ret = dma_submit_error(cookie);
+ if (ret)
+ goto dma_term;
+
+ reinit_completion(&dma->completion);
+ dma_async_issue_pending(dma->chan);
+
+ /* Setup and enable timer DMA burst mode */
+ dbl = FIELD_PREP(TIM_DCR_DBL, bursts - 1);
+ dba = FIELD_PREP(TIM_DCR_DBA, reg >> 2);
+ ret = regmap_write(regmap, TIM_DCR, dbl | dba);
+ if (ret)
+ goto dma_term;
+
+ /* Clear pending flags before enabling DMA request */
+ ret = regmap_write(regmap, TIM_SR, 0);
+ if (ret)
+ goto dcr_clr;
+
+ ret = regmap_update_bits(regmap, TIM_DIER, stm32_timers_dier_dmaen[id],
+ stm32_timers_dier_dmaen[id]);
+ if (ret)
+ goto dcr_clr;
+
+ err = wait_for_completion_interruptible_timeout(&dma->completion,
+ timeout);
+ if (err == 0)
+ ret = -ETIMEDOUT;
+ else if (err < 0)
+ ret = err;
+
+ regmap_update_bits(regmap, TIM_DIER, stm32_timers_dier_dmaen[id], 0);
+ regmap_write(regmap, TIM_SR, 0);
+dcr_clr:
+ regmap_write(regmap, TIM_DCR, 0);
+dma_term:
+ dmaengine_terminate_all(dma->chan);
+unmap:
+ dma_unmap_single(dev, dma_buf, len, DMA_FROM_DEVICE);
+unlock:
+ dma->chan = NULL;
+ mutex_unlock(&dma->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(stm32_timers_dma_burst_read);
+
static const struct regmap_config stm32_timers_regmap_cfg = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = sizeof(u32),
- .max_register = 0x3fc,
+ .max_register = STM32_TIMERS_MAX_REGISTERS,
};
static void stm32_timers_get_arr_size(struct stm32_timers *ddata)
@@ -27,12 +167,45 @@ static void stm32_timers_get_arr_size(struct stm32_timers *ddata)
regmap_write(ddata->regmap, TIM_ARR, 0x0);
}
+static void stm32_timers_dma_probe(struct device *dev,
+ struct stm32_timers *ddata)
+{
+ int i;
+ char name[4];
+
+ init_completion(&ddata->dma.completion);
+ mutex_init(&ddata->dma.lock);
+
+ /* Optional DMA support: get valid DMA channel(s) or NULL */
+ for (i = STM32_TIMERS_DMA_CH1; i <= STM32_TIMERS_DMA_CH4; i++) {
+ snprintf(name, ARRAY_SIZE(name), "ch%1d", i + 1);
+ ddata->dma.chans[i] = dma_request_slave_channel(dev, name);
+ }
+ ddata->dma.chans[STM32_TIMERS_DMA_UP] =
+ dma_request_slave_channel(dev, "up");
+ ddata->dma.chans[STM32_TIMERS_DMA_TRIG] =
+ dma_request_slave_channel(dev, "trig");
+ ddata->dma.chans[STM32_TIMERS_DMA_COM] =
+ dma_request_slave_channel(dev, "com");
+}
+
+static void stm32_timers_dma_remove(struct device *dev,
+ struct stm32_timers *ddata)
+{
+ int i;
+
+ for (i = STM32_TIMERS_DMA_CH1; i < STM32_TIMERS_MAX_DMAS; i++)
+ if (ddata->dma.chans[i])
+ dma_release_channel(ddata->dma.chans[i]);
+}
+
static int stm32_timers_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct stm32_timers *ddata;
struct resource *res;
void __iomem *mmio;
+ int ret;
ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata)
@@ -43,6 +216,9 @@ static int stm32_timers_probe(struct platform_device *pdev)
if (IS_ERR(mmio))
return PTR_ERR(mmio);
+ /* Timer physical addr for DMA */
+ ddata->dma.phys_base = res->start;
+
ddata->regmap = devm_regmap_init_mmio_clk(dev, "int", mmio,
&stm32_timers_regmap_cfg);
if (IS_ERR(ddata->regmap))
@@ -54,9 +230,29 @@ static int stm32_timers_probe(struct platform_device *pdev)
stm32_timers_get_arr_size(ddata);
+ stm32_timers_dma_probe(dev, ddata);
+
platform_set_drvdata(pdev, ddata);
- return devm_of_platform_populate(&pdev->dev);
+ ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+ if (ret)
+ stm32_timers_dma_remove(dev, ddata);
+
+ return ret;
+}
+
+static int stm32_timers_remove(struct platform_device *pdev)
+{
+ struct stm32_timers *ddata = platform_get_drvdata(pdev);
+
+ /*
+ * Don't use devm_ here: enfore of_platform_depopulate() happens before
+ * DMA are released, to avoid race on DMA.
+ */
+ of_platform_depopulate(&pdev->dev);
+ stm32_timers_dma_remove(&pdev->dev, ddata);
+
+ return 0;
}
static const struct of_device_id stm32_timers_of_match[] = {
@@ -67,6 +263,7 @@ static int stm32_timers_probe(struct platform_device *pdev)
static struct platform_driver stm32_timers_driver = {
.probe = stm32_timers_probe,
+ .remove = stm32_timers_remove,
.driver = {
.name = "stm32-timers",
.of_match_table = stm32_timers_of_match,
diff --git a/include/linux/mfd/stm32-timers.h b/include/linux/mfd/stm32-timers.h
index 2aadab6..9596d5c 100644
--- a/include/linux/mfd/stm32-timers.h
+++ b/include/linux/mfd/stm32-timers.h
@@ -8,6 +8,8 @@
#define _LINUX_STM32_GPTIMER_H_
#include <linux/clk.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
#include <linux/regmap.h>
#define TIM_CR1 0x00 /* Control Register 1 */
@@ -27,6 +29,8 @@
#define TIM_CCR3 0x3C /* Capt/Comp Register 3 */
#define TIM_CCR4 0x40 /* Capt/Comp Register 4 */
#define TIM_BDTR 0x44 /* Break and Dead-Time Reg */
+#define TIM_DCR 0x48 /* DMA control register */
+#define TIM_DMAR 0x4C /* DMA register for transfer */
#define TIM_CR1_CEN BIT(0) /* Counter Enable */
#define TIM_CR1_DIR BIT(4) /* Counter Direction */
@@ -36,6 +40,13 @@
#define TIM_SMCR_SMS (BIT(0) | BIT(1) | BIT(2)) /* Slave mode selection */
#define TIM_SMCR_TS (BIT(4) | BIT(5) | BIT(6)) /* Trigger selection */
#define TIM_DIER_UIE BIT(0) /* Update interrupt */
+#define TIM_DIER_UDE BIT(8) /* Update DMA request Enable */
+#define TIM_DIER_CC1DE BIT(9) /* CC1 DMA request Enable */
+#define TIM_DIER_CC2DE BIT(10) /* CC2 DMA request Enable */
+#define TIM_DIER_CC3DE BIT(11) /* CC3 DMA request Enable */
+#define TIM_DIER_CC4DE BIT(12) /* CC4 DMA request Enable */
+#define TIM_DIER_COMDE BIT(13) /* COM DMA request Enable */
+#define TIM_DIER_TDE BIT(14) /* Trigger DMA request Enable */
#define TIM_SR_UIF BIT(0) /* Update interrupt flag */
#define TIM_EGR_UG BIT(0) /* Update Generation */
#define TIM_CCMR_PE BIT(3) /* Channel Preload Enable */
@@ -56,6 +67,8 @@
#define TIM_BDTR_BK2F (BIT(20) | BIT(21) | BIT(22) | BIT(23))
#define TIM_BDTR_BK2E BIT(24) /* Break 2 input enable */
#define TIM_BDTR_BK2P BIT(25) /* Break 2 input polarity */
+#define TIM_DCR_DBA GENMASK(4, 0) /* DMA base addr */
+#define TIM_DCR_DBL GENMASK(12, 8) /* DMA burst len */
#define MAX_TIM_PSC 0xFFFF
#define TIM_CR2_MMS_SHIFT 4
@@ -65,9 +78,42 @@
#define TIM_BDTR_BKF_SHIFT 16
#define TIM_BDTR_BK2F_SHIFT 20
+enum stm32_timers_dmas {
+ STM32_TIMERS_DMA_CH1,
+ STM32_TIMERS_DMA_CH2,
+ STM32_TIMERS_DMA_CH3,
+ STM32_TIMERS_DMA_CH4,
+ STM32_TIMERS_DMA_UP,
+ STM32_TIMERS_DMA_TRIG,
+ STM32_TIMERS_DMA_COM,
+ STM32_TIMERS_MAX_DMAS,
+};
+
+/**
+ * struct stm32_timers_dma - STM32 timer DMA handling.
+ * @completion: end of DMA transfer completion
+ * @phys_base: control registers physical base address
+ * @lock: protect DMA access
+ * @chan: DMA channel in use
+ * @chans: DMA channels available for this timer instance
+ */
+struct stm32_timers_dma {
+ struct completion completion;
+ phys_addr_t phys_base;
+ struct mutex lock;
+ struct dma_chan *chan;
+ struct dma_chan *chans[STM32_TIMERS_MAX_DMAS];
+};
+
struct stm32_timers {
struct clk *clk;
struct regmap *regmap;
u32 max_arr;
+ struct stm32_timers_dma dma; /* Only to be used by the parent */
};
+
+int stm32_timers_dma_burst_read(struct device *dev, u32 *buf,
+ enum stm32_timers_dmas id, u32 reg,
+ unsigned int num_reg, unsigned int bursts,
+ unsigned long tmo_ms);
#endif
--
1.9.1
^ permalink raw reply related
* [RESEND PATCH v5 1/6] dt-bindings: mfd: stm32-timers: add support for dmas
From: Fabrice Gasnier @ 2018-05-16 7:35 UTC (permalink / raw)
To: lee.jones, alexandre.torgue
Cc: thierry.reding, benjamin.gaignard, robh+dt, mark.rutland, linux,
mcoquelin.stm32, fabrice.gasnier, benjamin.gaignard, devicetree,
linux-arm-kernel, linux-kernel, linux-pwm
In-Reply-To: <1526456161-27865-1-git-send-email-fabrice.gasnier@st.com>
Add support for DMAs to STM32 timers. STM32 Timers can support up to 7
dma requests: up to 4 channels, update, compare and trigger.
DMAs may be used to transfer data from pwm capture for instance.
DMA support is made optional, PWM capture support is also an option.
This is much more wise system-wide to avoid shortage on DMA request
lines as there's significant amount of timer instances that can
request up to 7 channels.
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
Reviewed-by: Rob Herring <robh@kernel.org>
Reviewed-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
---
.../devicetree/bindings/mfd/stm32-timers.txt | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/Documentation/devicetree/bindings/mfd/stm32-timers.txt b/Documentation/devicetree/bindings/mfd/stm32-timers.txt
index 1db6e00..0e900b5 100644
--- a/Documentation/devicetree/bindings/mfd/stm32-timers.txt
+++ b/Documentation/devicetree/bindings/mfd/stm32-timers.txt
@@ -19,6 +19,11 @@ Required parameters:
Optional parameters:
- resets: Phandle to the parent reset controller.
See ../reset/st,stm32-rcc.txt
+- dmas: List of phandle to dma channels that can be used for
+ this timer instance. There may be up to 7 dma channels.
+- dma-names: List of dma names. Must match 'dmas' property. Valid
+ names are: "ch1", "ch2", "ch3", "ch4", "up", "trig",
+ "com".
Optional subnodes:
- pwm: See ../pwm/pwm-stm32.txt
@@ -44,3 +49,18 @@ Example:
reg = <0>;
};
};
+
+Example with all dmas:
+ timer@40010000 {
+ ...
+ dmas = <&dmamux1 11 0x400 0x0>,
+ <&dmamux1 12 0x400 0x0>,
+ <&dmamux1 13 0x400 0x0>,
+ <&dmamux1 14 0x400 0x0>,
+ <&dmamux1 15 0x400 0x0>,
+ <&dmamux1 16 0x400 0x0>,
+ <&dmamux1 17 0x400 0x0>;
+ dma-names = "ch1", "ch2", "ch3", "ch4", "up", "trig", "com";
+ ...
+ child nodes...
+ };
--
1.9.1
^ permalink raw reply related
* [RESEND PATCH v5 0/6] Add support for PWM input capture on STM32
From: Fabrice Gasnier @ 2018-05-16 7:35 UTC (permalink / raw)
To: lee.jones, alexandre.torgue
Cc: thierry.reding, benjamin.gaignard, robh+dt, mark.rutland, linux,
mcoquelin.stm32, fabrice.gasnier, benjamin.gaignard, devicetree,
linux-arm-kernel, linux-kernel, linux-pwm
This series adds support for capture to stm32-pwm driver.
Capture is based on DMAs.
- First two patches add support for requesting DMAs to MFD core
- Next three patches add support for capture to stm32-pwm driver
- This has been tested on stm32429i-eval board.
---
Changes in v5:
- update patch 2 (mfd: stm32-timers: add support for dmas)
move stm32_timers_dma struct to header file,
fix warning on dma_mapping_error().
Changes in v4:
- Lee's comments on patch 2 (mfd: stm32-timers: add support for dmas)
Add kerneldoc header, better format comments.
Changes in v3:
- Dropped 2 precusor patches applied by Thierry in pwm tree:
"pwm: stm32: fix, remove unused struct device"
"pwm: stm32: protect common prescaler for all channels"
- Note: this series applies on top on pwm tree
- Implements Lee's comments on MFD part: rework stm32_timers_dma struct,
exported routine prototype now use generic device struct, more
various comments (see patch 2 changelog).
Resend v2:
- Add collected Acks
Changes in v2:
- Abstract DMA handling from child driver: move it to MFD core
- Rework pwm capture routines to adopt this change
- Comment on optional dma support, beautify DMAs probe
Fabrice Gasnier (6):
dt-bindings: mfd: stm32-timers: add support for dmas
mfd: stm32-timers: add support for dmas
pwm: stm32: add capture support
pwm: stm32: improve capture by tuning counter prescaler
pwm: stm32: use input prescaler to improve period capture
ARM: dts: stm32: Enable pwm3 input capture on stm32f429i-eval
.../devicetree/bindings/mfd/stm32-timers.txt | 20 ++
arch/arm/boot/dts/stm32429i-eval.dts | 3 +
drivers/mfd/stm32-timers.c | 201 +++++++++++++++-
drivers/pwm/pwm-stm32.c | 257 +++++++++++++++++++++
include/linux/mfd/stm32-timers.h | 58 +++++
5 files changed, 537 insertions(+), 2 deletions(-)
--
1.9.1
^ permalink raw reply
* Re: [PATCH v6 1/4] drm/bridge: add support for sn65dsi86 bridge driver
From: Andrzej Hajda @ 2018-05-16 7:26 UTC (permalink / raw)
To: spanda, dri-devel, linux-arm-msm, freedreno, devicetree
Cc: hoegsberg, chandanu, ryadav, abhinavk
In-Reply-To: <e73be4c94b60622f8d3f18177c7ad865@codeaurora.org>
I suppose you wanted to respond on the list, so I have added back all
recipients.
On 16.05.2018 06:39, spanda@codeaurora.org wrote:
> On 2018-05-15 19:23, Andrzej Hajda wrote:
>> On 15.05.2018 07:52, Sandeep Panda wrote:
>>> Add support for TI's sn65dsi86 dsi2edp bridge chip.
>>> The chip converts DSI transmitted signal to eDP signal,
>>> which is fed to the connected eDP panel.
>>>
>>> This chip can be controlled via either i2c interface or
>>> dsi interface. Currently in driver all the control registers
>>> are being accessed through i2c interface only.
>>> Also as of now HPD support has not been added to bridge
>>> chip driver.
>>>
>>> Changes in v1:
>>> - Split the dt-bindings and the driver support into separate patches
>>> (Andrzej Hajda).
>>> - Use of gpiod APIs to parse and configure gpios instead of obsolete
>>> ones
>>> (Andrzej Hajda).
>>> - Use macros to define the register offsets (Andrzej Hajda).
>>>
>>> Changes in v2:
>>> - Separate out edp panel specific HW resource handling from bridge
>>> driver and create a separate edp panel drivers to handle panel
>>> specific mode information and HW resources (Sean Paul).
>>> - Replace pr_* APIs to DRM_* APIs to log error or debug information
>>> (Sean Paul).
>>> - Remove some of the unnecessary structure/variable from driver (Sean
>>> Paul).
>>> - Rename the function and structure prefix "sn65dsi86" to
>>> "ti_sn_bridge"
>>> (Sean Paul / Rob Herring).
>>> - Remove most of the hard-coding and modified the bridge init
>>> sequence
>>> based on current mode (Sean Paul).
>>> - Remove the existing function to retrieve the EDID data and
>>> implemented this as an i2c_adapter and use drm_get_edid() (Sean
>>> Paul).
>>> - Remove the dummy irq handler implementation, will add back the
>>> proper irq handling later (Sean Paul).
>>> - Capture the required enable gpios in a single array based on dt
>>> entry
>>> instead of having individual descriptor for each gpio (Sean Paul).
>>>
>>> Changes in v3:
>>> - Remove usage of irq_gpio and replace it as "interrupts" property
>>> (Rob
>>> Herring).
>>> - Remove the unnecessary header file inclusions (Sean Paul).
>>> - Rearrange the header files in alphabetical order (Sean Paul).
>>> - Use regmap interface to perform i2c transactions.
>>> - Update Copyright/License field and address other review comments
>>> (Jordan Crouse).
>>>
>>> Changes in v4:
>>> - Update License/Copyright (Sean Paul).
>>> - Add Kconfig and Makefile changes (Sean Paul).
>>> - Drop i2c gpio handling from this bridge driver, since i2c sda/scl
>>> gpios
>>> will be handled by i2c master.
>>> - Update required supplies names.
>>> - Remove unnecessary goto statements (Sean Paul).
>>> - Add mutex lock to power_ctrl API to avoid race conditions (Sean
>>> Paul).
>>> - Add support to parse reference clk frequency from dt(optional).
>>> - Update the bridge chip enable/disable sequence.
>>>
>>> Changes in v5:
>>> - Fixed Kbuild test service reported warnings.
>>>
>>> Changes in v6:
>>> - Use PM runtime based ref-counting instead of local ref_count
>>> mechanism
>>> (Stephen Boyd).
>>> - Clean up some debug logs and indentations (Sean Paul).
>>> - Simplify dp rate calculation (Sean Paul).
>>> - Add support to configure refclk based on input REFCLK pin or DACP/N
>>> pin (Stephen Boyd).
>>>
>>> Signed-off-by: Sandeep Panda <spanda@codeaurora.org>
>>> ---
>>> drivers/gpu/drm/bridge/Kconfig | 9 +
>>> drivers/gpu/drm/bridge/Makefile | 1 +
>>> drivers/gpu/drm/bridge/ti-sn65dsi86.c | 766
>>> ++++++++++++++++++++++++++++++++++
>>> 3 files changed, 776 insertions(+)
>>> create mode 100644 drivers/gpu/drm/bridge/ti-sn65dsi86.c
>>>
>>> diff --git a/drivers/gpu/drm/bridge/Kconfig
>>> b/drivers/gpu/drm/bridge/Kconfig
>>> index 3b99d5a..8153150 100644
>>> --- a/drivers/gpu/drm/bridge/Kconfig
>>> +++ b/drivers/gpu/drm/bridge/Kconfig
>>> @@ -108,6 +108,15 @@ config DRM_TI_TFP410
>>> ---help---
>>> Texas Instruments TFP410 DVI/HDMI Transmitter driver
>>>
>>> +config DRM_TI_SN65DSI86
>>> + tristate "TI SN65DSI86 DSI to eDP bridge"
>>> + depends on OF
>>> + select DRM_KMS_HELPER
>>> + select REGMAP_I2C
>>> + select DRM_PANEL
>>> + ---help---
>>> + Texas Instruments SN65DSI86 DSI to eDP Bridge driver
>>> +
>>> source "drivers/gpu/drm/bridge/analogix/Kconfig"
>>>
>>> source "drivers/gpu/drm/bridge/adv7511/Kconfig"
>>> diff --git a/drivers/gpu/drm/bridge/Makefile
>>> b/drivers/gpu/drm/bridge/Makefile
>>> index 373eb28..3711be8 100644
>>> --- a/drivers/gpu/drm/bridge/Makefile
>>> +++ b/drivers/gpu/drm/bridge/Makefile
>>> @@ -12,4 +12,5 @@ obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o
>>> obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/
>>> obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/
>>> obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o
>>> +obj-$(CONFIG_DRM_TI_SN65DSI86) += ti-sn65dsi86.o
>>> obj-y += synopsys/
>>> diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
>>> b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
>>> new file mode 100644
>>> index 0000000..1d3e549
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
>>> @@ -0,0 +1,766 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * Copyright (c) 2018, The Linux Foundation. All rights reserved.
>>> + */
>>> +
>>> +#include <drm/drmP.h>
>>> +#include <drm/drm_atomic.h>
>>> +#include <drm/drm_atomic_helper.h>
>>> +#include <drm/drm_crtc_helper.h>
>>> +#include <drm/drm_mipi_dsi.h>
>>> +#include <drm/drm_panel.h>
>>> +#include <linux/clk.h>
>>> +#include <linux/gpio.h>
>>> +#include <linux/i2c.h>
>>> +#include <linux/of_gpio.h>
>>> +#include <linux/of_graph.h>
>>> +#include <linux/pm_runtime.h>
>>> +#include <linux/regmap.h>
>>> +#include <linux/regulator/consumer.h>
>>> +
>>> +#define SN_BRIDGE_REVISION_ID 0x2
>>> +
>>> +/* Link Training specific registers */
>>> +#define SN_DEVICE_REV_REG 0x08
>>> +#define SN_HPD_DISABLE_REG 0x5C
>>> +#define SN_REFCLK_FREQ_REG 0x0A
>>> +#define SN_DSI_LANES_REG 0x10
>>> +#define SN_DSIA_CLK_FREQ_REG 0x12
>>> +#define SN_ENH_FRAME_REG 0x5A
>>> +#define SN_SSC_CONFIG_REG 0x93
>>> +#define SN_DATARATE_CONFIG_REG 0x94
>>> +#define SN_PLL_ENABLE_REG 0x0D
>>> +#define SN_SCRAMBLE_CONFIG_REG 0x95
>>> +#define SN_AUX_WDATA0_REG 0x64
>>> +#define SN_AUX_ADDR_19_16_REG 0x74
>>> +#define SN_AUX_ADDR_15_8_REG 0x75
>>> +#define SN_AUX_ADDR_7_0_REG 0x76
>>> +#define SN_AUX_LENGTH_REG 0x77
>>> +#define SN_AUX_CMD_REG 0x78
>>> +#define SN_ML_TX_MODE_REG 0x96
>>> +/* video config specific registers */
>>> +#define SN_CHA_ACTIVE_LINE_LENGTH_LOW_REG 0x20
>>> +#define SN_CHA_ACTIVE_LINE_LENGTH_HIGH_REG 0x21
>>> +#define SN_CHA_VERTICAL_DISPLAY_SIZE_LOW_REG 0x24
>>> +#define SN_CHA_VERTICAL_DISPLAY_SIZE_HIGH_REG 0x25
>>> +#define SN_CHA_HSYNC_PULSE_WIDTH_LOW_REG 0x2C
>>> +#define SN_CHA_HSYNC_PULSE_WIDTH_HIGH_REG 0x2D
>>> +#define SN_CHA_VSYNC_PULSE_WIDTH_LOW_REG 0x30
>>> +#define SN_CHA_VSYNC_PULSE_WIDTH_HIGH_REG 0x31
>>> +#define SN_CHA_HORIZONTAL_BACK_PORCH_REG 0x34
>>> +#define SN_CHA_VERTICAL_BACK_PORCH_REG 0x36
>>> +#define SN_CHA_HORIZONTAL_FRONT_PORCH_REG 0x38
>>> +#define SN_CHA_VERTICAL_FRONT_PORCH_REG 0x3A
>>> +#define SN_DATA_FORMAT_REG 0x5B
>>> +
>>> +#define MIN_DSI_CLK_FREQ_MHZ 40
>>> +
>>> +/* fudge factor required to account for 8b/10b encoding */
>>> +#define DP_CLK_FUDGE_NUM 10
>>> +#define DP_CLK_FUDGE_DEN 8
>>> +
>>> +#define DPPLL_CLK_SRC_REFCLK 0
>>> +#define DPPLL_CLK_SRC_DSICLK 1
>>> +
>>> +#define SN_DSIA_REFCLK_OFFSET 1
>>> +#define SN_DSIA_LANE_OFFSET 3
>>> +#define SN_DP_LANE_OFFSET 4
>>> +#define SN_DP_DATA_RATE_OFFSET 5
>>> +#define SN_TIMING_HIGH_OFFSET 8
>>> +
>>> +#define SN_ENABLE_VID_STREAM_BIT BIT(3)
>>> +#define SN_DSIA_NUM_LANES_BITS (BIT(4) | BIT(3))
>>> +#define SN_DP_NUM_LANES_BITS (BIT(5) | BIT(4))
>>> +#define SN_DP_DATA_RATE_BITS (BIT(7) | BIT(6) | BIT(5))
>>> +#define SN_HPD_DISABLE_BIT BIT(0)
>>> +
>>> +struct ti_sn_bridge {
>>> + struct device *dev;
>>> + struct regmap *regmap;
>> I have not spotted who advised you to use regmap, I think unless you
>> share hardware between multiple drivers it is an overkill.
>> Are there any features of this interface to use it over i2c?
>>
> Since we are using the i2c mechanism to update the control registers
> of the bridge, thought that regmap gives a proper interface for handling
> all the register control operations like read/write/update_bit/mask etc.
> Also most of the bridge driver present in drm are using this mechanism.
Yes, I know many ppl advertises it but also many are against using it in
such simple cases. Anyway I do not want to force you to remove it, do
what you prefer.
>
>>> + struct drm_bridge bridge;
>>> + struct drm_connector connector;
>>> + struct device_node *host_node;
>>> + struct mipi_dsi_device *dsi;
>>> + struct clk *refclk;
>>> + struct drm_panel *panel;
>>> + struct gpio_desc *enable_gpio;
>>> + unsigned int num_supplies;
>>> + struct regulator_bulk_data *supplies;
>>> + struct i2c_adapter *ddc;
>>> + struct drm_display_mode curr_mode;
>> I think you can drop this field, current mode is always available via:
>>
>> pdata->bridge.encoder.crtc->state->adjusted_mode;
>>
>>
> Ok. i will remove this curr_mode.
>
>>> +};
>>> +
>>> +static const struct regmap_range ti_sn_bridge_volatile_ranges[] = {
>>> + { .range_min = 0, .range_max = 0xff },
>>> +};
>>> +
>>> +static const struct regmap_access_table ti_sn_bridge_volatile_table =
>>> {
>>> + .yes_ranges = ti_sn_bridge_volatile_ranges,
>>> + .n_yes_ranges = ARRAY_SIZE(ti_sn_bridge_volatile_ranges),
>>> +};
>>> +
>>> +static const struct regmap_config ti_sn_bridge_regmap_config = {
>>> + .reg_bits = 8,
>>> + .val_bits = 8,
>>> + .volatile_table = &ti_sn_bridge_volatile_table,
>>> + .cache_type = REGCACHE_NONE,
>>> +};
>>> +
>>> +#ifdef CONFIG_PM
>> Please mark PM callbacks with __maybe_unused instead if conditional
>> macros.
>>
> Ok.
>
>>> +static int ti_sn_bridge_resume(struct device *dev)
>>> +{
>>> + struct ti_sn_bridge *pdata = dev_get_drvdata(dev);
>>> + int ret = 0;
>>> +
>>> + ret = regulator_bulk_enable(pdata->num_supplies, pdata->supplies);
>>> + if (ret) {
>>> + DRM_ERROR("failed to enable supplies %d\n", ret);
>>> + return ret;
>>> + }
>>> +
>>> + gpiod_set_value(pdata->enable_gpio, 1);
>>> +
>>> + return ret;
>>> +}
>>> +
>>> +static int ti_sn_bridge_suspend(struct device *dev)
>>> +{
>>> + struct ti_sn_bridge *pdata = dev_get_drvdata(dev);
>>> + int ret = 0;
>>> +
>>> + gpiod_set_value(pdata->enable_gpio, 0);
>>> +
>>> + ret = regulator_bulk_disable(pdata->num_supplies, pdata->supplies);
>>> + if (ret)
>>> + DRM_ERROR("failed to disable supplies %d\n", ret);
>>> +
>>> + return ret;
>>> +}
>>> +#endif
>>> +
>>> +static const struct dev_pm_ops ti_sn_bridge_pm_ops = {
>>> + SET_RUNTIME_PM_OPS(ti_sn_bridge_suspend, ti_sn_bridge_resume, NULL)
>>> +};
>>> +
>>> +/* Connector funcs */
>>> +static struct ti_sn_bridge *
>>> +connector_to_ti_sn_bridge(struct drm_connector *connector)
>>> +{
>>> + return container_of(connector, struct ti_sn_bridge, connector);
>>> +}
>>> +
>>> +static int ti_sn_bridge_connector_get_modes(struct drm_connector
>>> *connector)
>>> +{
>>> + struct ti_sn_bridge *pdata = connector_to_ti_sn_bridge(connector);
>>> + struct drm_panel *panel = pdata->panel;
>>> + struct edid *edid;
>>> + u32 num_modes;
>>> +
>>> + if (panel) {
>>> + DRM_DEBUG_KMS("get mode from connected drm_panel\n");
>>> + return drm_panel_get_modes(panel);
>>> + }
>>> +
>>> + if (!pdata->ddc)
>>> + return 0;
>>> +
>>> + pm_runtime_get_sync(pdata->dev);
>>> + edid = drm_get_edid(connector, pdata->ddc);
>>> + pm_runtime_put_sync(pdata->dev);
>>> + if (!edid)
>>> + return 0;
>>> +
>>> + drm_mode_connector_update_edid_property(connector, edid);
>>> + num_modes = drm_add_edid_modes(connector, edid);
>>> + kfree(edid);
>>> +
>>> + return num_modes;
>>> +}
>>> +
>>> +static enum drm_mode_status
>>> +ti_sn_bridge_connector_mode_valid(struct drm_connector *connector,
>>> + struct drm_display_mode *mode)
>>> +{
>>> + /* maximum supported resolution is 4K at 60 fps */
>>> + if (mode->clock > 594000)
>>> + return MODE_CLOCK_HIGH;
>>> +
>>> + return MODE_OK;
>>> +}
>>> +
>>> +static struct drm_connector_helper_funcs
>>> ti_sn_bridge_connector_helper_funcs = {
>>> + .get_modes = ti_sn_bridge_connector_get_modes,
>>> + .mode_valid = ti_sn_bridge_connector_mode_valid,
>>> +};
>>> +
>>> +static enum drm_connector_status
>>> +ti_sn_bridge_connector_detect(struct drm_connector *connector, bool
>>> force)
>>> +{
>>> + struct ti_sn_bridge *pdata = connector_to_ti_sn_bridge(connector);
>>> +
>>> + /**
>>> + * TODO: Currently if drm_panel is present, then always
>>> + * return the status as connected. Need to add support to detect
>>> + * device state for no panel(hot pluggable) scenarios.
>>> + */
>>> + if (pdata->panel)
>>> + return connector_status_connected;
>>> + else
>>> + return connector_status_unknown;
>>> +}
>>> +
>>> +static const struct drm_connector_funcs ti_sn_bridge_connector_funcs
>>> = {
>>> + .fill_modes = drm_helper_probe_single_connector_modes,
>>> + .detect = ti_sn_bridge_connector_detect,
>>> + .destroy = drm_connector_cleanup,
>>> + .reset = drm_atomic_helper_connector_reset,
>>> + .atomic_duplicate_state =
>>> drm_atomic_helper_connector_duplicate_state,
>>> + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
>>> +};
>>> +
>>> +static struct ti_sn_bridge *bridge_to_ti_sn_bridge(struct drm_bridge
>>> *bridge)
>>> +{
>>> + return container_of(bridge, struct ti_sn_bridge, bridge);
>>> +}
>>> +
>>> +static int ti_sn_bridge_read_device_rev(struct ti_sn_bridge *pdata)
>>> +{
>>> + unsigned int rev = 0;
>>> + int ret = 0;
>>> +
>>> + ret = regmap_read(pdata->regmap, SN_DEVICE_REV_REG, &rev);
>>> + if (ret) {
>>> + DRM_ERROR("Revision read failed %d\n", ret);
>>> + return ret;
>>> + }
>>> +
>>> + if (rev != SN_BRIDGE_REVISION_ID) {
>>> + DRM_ERROR("ti_sn_bridge revision id: 0x%x mismatch\n", rev);
>>> + ret = -EINVAL;
>>> + }
>> Are you sure it won't work with other revisions?
>>
> The datasheet which i have, mentions the revision to be 0x2. I am not
> sure whether this driver works with other revisions, that's why i have
> put this check.
> Also this check helps to confirm if the gpio and supplies of the bridge
> chip has been successfully enabled not depending on the value read.
So maybe better convert DRM_ERROR to warning and continue.
>
>>> +
>>> + return ret;
>>> +}
>>> +
>>> +static const char * const ti_sn_bridge_supply_names[] = {
>>> + "vcca",
>>> + "vcc",
>>> + "vccio",
>>> + "vpll",
>>> +};
>>> +
>>> +static int ti_sn_bridge_parse_regulators(struct ti_sn_bridge *pdata)
>>> +{
>>> + unsigned int i;
>>> +
>>> + pdata->num_supplies = ARRAY_SIZE(ti_sn_bridge_supply_names);
>>> +
>>> + pdata->supplies = devm_kcalloc(pdata->dev, pdata->num_supplies,
>>> + sizeof(*pdata->supplies), GFP_KERNEL);
>> It seems there is constant number of supplies. You can convert supplies
>> to array and avoid dynamic allocation.
>>
> Just want to understand here what is the issue with dynamic allocation
> here?
> We are using device managed allocation, so the resource management will
> be properly
> done by kernel.
Just less code, no extra allocations, no extra resource management.
Dynamic allocations in such case makes sense only if array size is
computed in runtime.
>
>>> + if (!pdata->supplies)
>>> + return -ENOMEM;
>>> +
>>> + for (i = 0; i < pdata->num_supplies; i++)
>>> + pdata->supplies[i].supply = ti_sn_bridge_supply_names[i];
>>> +
>>> + return devm_regulator_bulk_get(pdata->dev,
>>> + pdata->num_supplies, pdata->supplies);
>>> +}
>>> +
>>> +static int ti_sn_bridge_attach_panel(struct ti_sn_bridge *pdata)
>>> +{
>>> + struct device_node *panel_node, *port, *endpoint;
>>> +
>>> + pdata->panel = NULL;
>>> + port = of_graph_get_port_by_id(pdata->dev->of_node, 1);
>>> + if (!port)
>>> + return 0;
>>> +
>>> + endpoint = of_get_child_by_name(port, "endpoint");
>>> + of_node_put(port);
>>> + if (!endpoint) {
>>> + DRM_ERROR("no output endpoint found\n");
>>> + return -EINVAL;
>>> + }
>> Why not of_graph_get_endpoint_by_regs ?
>>
>>> +
>>> + panel_node = of_graph_get_remote_port_parent(endpoint);
>>> + of_node_put(endpoint);
>>> + if (!panel_node) {
>>> + DRM_ERROR("no output node found\n");
>>> + return -EINVAL;
>>> + }
>> Or even of_graph_get_remote_node?
>>
>>> +
>>> + pdata->panel = of_drm_find_panel(panel_node);
>>> + of_node_put(panel_node);
>> Or even, even drm_of_find_panel_or_bridge ? :)
> Ok. i will use drm_of_find_panel_or_bridge() here.
>
>>> + if (!pdata->panel) {
>>> + DRM_ERROR("no panel node found\n");
>>> + return -EINVAL;
>> You should probably return -EPROBE_DEFER here.
>>
> This API may not be called from probe(), is it ok if we return
> -EPROBE_DEFER here?
Ahh, OK, but in such case this is incorrect, see below.
>
>>> + }
>>> + drm_panel_attach(pdata->panel, &pdata->connector);
>>> + DRM_DEBUG_KMS("drm panel attached to ti_sn_bridge\n");
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int ti_sn_bridge_attach(struct drm_bridge *bridge)
>>> +{
>>> + struct mipi_dsi_host *host;
>>> + struct mipi_dsi_device *dsi;
>>> + struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge);
>>> + int ret;
>>> + const struct mipi_dsi_device_info info = { .type = "ti_sn_bridge",
>>> + .channel = 0,
>>> + .node = NULL,
>>> + };
>>> +
>>> + if (!bridge->encoder) {
>>> + DRM_ERROR("Parent encoder object not found\n");
>>> + return -ENODEV;
>>> + }
>>> +
>>> + /* HPD not supported */
>>> + pdata->connector.polled = 0;
>> You can skip this line.
>>
> OK.
>
>>> +
>>> + ret = drm_connector_init(bridge->dev, &pdata->connector,
>>> + &ti_sn_bridge_connector_funcs,
>>> + DRM_MODE_CONNECTOR_eDP);
>>> + if (ret) {
>>> + DRM_ERROR("Failed to initialize connector with drm\n");
>>> + return ret;
>>> + }
>>> +
>>> + drm_connector_helper_add(&pdata->connector,
>>> + &ti_sn_bridge_connector_helper_funcs);
>>> + drm_mode_connector_attach_encoder(&pdata->connector,
>>> bridge->encoder);
>>> +
>>> + host = of_find_mipi_dsi_host_by_node(pdata->host_node);
>>> + if (!host) {
>>> + DRM_ERROR("failed to find dsi host\n");
>>> + return -ENODEV;
>> Again -EPROBE_DEFER.
>>
> This API may not be called from probe(), is it ok if we return
> -EPROBE_DEFER here?
ditto
>
>>> + }
>>> +
>>> + dsi = mipi_dsi_device_register_full(host, &info);
>>> + if (IS_ERR(dsi)) {
>>> + DRM_ERROR("failed to create dsi device\n");
>>> + ret = PTR_ERR(dsi);
>>> + return ret;
>>> + }
>>> +
>>> + /* TODO: setting to 4 lanes always for now */
>>> + dsi->lanes = 4;
>>> + dsi->format = MIPI_DSI_FMT_RGB888;
>>> + dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
>>> MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
>>> + MIPI_DSI_MODE_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE;
>>> +
>>> + ret = mipi_dsi_attach(dsi);
>>> + if (ret < 0) {
>>> + DRM_ERROR("failed to attach dsi to host\n");
>>> + mipi_dsi_device_unregister(dsi);
>>> + return ret;
>>> + }
>>> +
>>> + pdata->dsi = dsi;
>>> +
>>> + DRM_DEBUG_KMS("ti_sn_bridge attached to dsi\n");
>>> + /* attach panel to bridge */
>>> + ti_sn_bridge_attach_panel(pdata);
>>
>> Function can fail, you should handle it.
>>
> This is not fatal, if this function fails then we assume there is no edp
> panel attached to this bridge.
So it seems wrong to me. You do not have guarantee that panel driver is
bound at this moment. So in case of different driver binding order you
will end up with incorrect setup: bridge will work with assumption there
is no panel behind it, but the panel is there, it will be just probed later.
I think the proper solution here is to do not advertise bridge (ie call
drm_bridge_add), until all required resources are present, including DSI
host and panel. And to make it clear, if the panel is defined in
bindings it means it is required.
>
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static void ti_sn_bridge_mode_set(struct drm_bridge *bridge,
>>> + struct drm_display_mode *mode,
>>> + struct drm_display_mode *adj_mode)
>>> +{
>>> + struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge);
>>> +
>>> + DRM_DEBUG("mode_set: hdisplay=%d, vdisplay=%d, vrefresh=%d,
>>> clock=%d\n",
>>> + adj_mode->hdisplay, adj_mode->vdisplay,
>>> + adj_mode->vrefresh, adj_mode->clock);
>>> +
>>> + drm_mode_copy(&pdata->curr_mode, adj_mode);
>>> +}
>> This callback can be dropped, see comment for curr_mode.
>>
>>> +
>>> +static void ti_sn_bridge_disable(struct drm_bridge *bridge)
>>> +{
>>> + struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge);
>>> + struct drm_panel *panel = pdata->panel;
>>> +
>>> + if (panel) {
>>> + drm_panel_disable(panel);
>>> + drm_panel_unprepare(panel);
>>> + }
>>> +
>>> + /* disable video stream */
>>> + regmap_update_bits(pdata->regmap, SN_ENH_FRAME_REG,
>>> + SN_ENABLE_VID_STREAM_BIT, 0);
>>> + /* semi auto link training mode OFF */
>>> + regmap_write(pdata->regmap, SN_ML_TX_MODE_REG, 0);
>>> + /* disable DP PLL */
>>> + regmap_write(pdata->regmap, SN_PLL_ENABLE_REG, 0);
>>> +}
>>> +
>>> +static u32 ti_sn_bridge_get_dsi_freq(struct ti_sn_bridge *pdata)
>>> +{
>>> + u32 bit_rate_khz, clk_freq_khz;
>>> + struct drm_display_mode *mode = &pdata->curr_mode;
>>> +
>>> + bit_rate_khz = mode->clock *
>>> + mipi_dsi_pixel_format_to_bpp(pdata->dsi->format);
>>> + clk_freq_khz = bit_rate_khz / (pdata->dsi->lanes * 2);
>>> +
>>> + return clk_freq_khz;
>>> +}
>>> +
>>> +#define REFCLK_LUT_SIZE 5
>>> +
>>> +/* clk frequencies supported by bridge in Hz in case derived from
>>> REFCLK pin */
>>> +static const u32 ti_sn_bridge_refclk_lut[] = {
>>> + 12000000,
>>> + 19200000,
>>> + 26000000,
>>> + 27000000,
>>> + 38400000,
>>> +};
>>> +
>>> +/* clk frequencies supported by bridge in Hz in case derived from
>>> DACP/N pin */
>>> +static const u32 ti_sn_bridge_dsiclk_lut[] = {
>>> + 468000000,
>>> + 384000000,
>>> + 416000000,
>>> + 486000000,
>>> + 460800000,
>>> +};
>>> +
>>> +static void ti_sn_bridge_set_refclk(struct ti_sn_bridge *pdata)
>>> +{
>>> + int i = 0;
>>> + u8 refclk_src;
>>> + u32 refclk_rate;
>>> + const u32 *refclk_lut;
>>> +
>>> + if (pdata->refclk) {
>>> + refclk_src = DPPLL_CLK_SRC_REFCLK;
>>> + refclk_rate = clk_get_rate(pdata->refclk);
>>> + refclk_lut = ti_sn_bridge_refclk_lut;
>>> + clk_prepare_enable(pdata->refclk);
>>> + } else {
>>> + refclk_src = DPPLL_CLK_SRC_DSICLK;
>>> + refclk_rate = ti_sn_bridge_get_dsi_freq(pdata) * 1000;
>>> + refclk_lut = ti_sn_bridge_dsiclk_lut;
>>> + }
>>> +
>>> + /* for i equals to REFCLK_LUT_SIZE means default frequency */
>>> + for (i = 0; i < REFCLK_LUT_SIZE; i++)
>>> + if (refclk_lut[i] == refclk_rate)
>>> + break;
>>> +
>>> + regmap_write(pdata->regmap, SN_REFCLK_FREQ_REG,
>>> + (refclk_src | (i << SN_DSIA_REFCLK_OFFSET)));
>>> +}
>>> +
>>> +/**
>>> + * LUT index corresponds to register value and
>>> + * LUT values corresponds to dp data rate supported
>>> + * by the bridge in Mbps unit.
>>> + */
>>> +static const unsigned int ti_sn_bridge_dp_rate_lut[] = {
>>> + 0, 1620, 2160, 2430, 2700, 3240, 4320, 5400
>>> +};
>>> +
>>> +static void ti_sn_bridge_set_dsi_dp_rate(struct ti_sn_bridge *pdata)
>>> +{
>>> + unsigned int bit_rate_mhz, clk_freq_mhz, dp_rate_mhz;
>>> + unsigned int val = 0, i = 0;
>>> + struct drm_display_mode *mode = &pdata->curr_mode;
>>> +
>>> + /* set DSIA clk frequency */
>>> + bit_rate_mhz = (mode->clock / 1000) *
>>> + mipi_dsi_pixel_format_to_bpp(pdata->dsi->format);
>>> + clk_freq_mhz = bit_rate_mhz / (pdata->dsi->lanes * 2);
>>> +
>>> + /* for each increment in val, frequency increases by 5MHz */
>>> + val = (MIN_DSI_CLK_FREQ_MHZ / 5) +
>>> + (((clk_freq_mhz - MIN_DSI_CLK_FREQ_MHZ) / 5) & 0xFF);
>>> + regmap_write(pdata->regmap, SN_DSIA_CLK_FREQ_REG, val);
>>> +
>>> + /* set DP data rate */
>>> + dp_rate_mhz = ((bit_rate_mhz / pdata->dsi->lanes) *
>>> DP_CLK_FUDGE_NUM) /
>>> + DP_CLK_FUDGE_DEN;
>>> + for (i = 0; i < ARRAY_SIZE(ti_sn_bridge_dp_rate_lut); i++)
>>> + if (ti_sn_bridge_dp_rate_lut[i] > dp_rate_mhz)
>>> + break;
>>> + if (i == ARRAY_SIZE(ti_sn_bridge_dp_rate_lut))
>>> + i--; /* set to maximum possible */
>> Just use: for (i = 0; i < ARRAY_SIZE(ti_sn_bridge_dp_rate_lut) - 1;
>> i++)
>>
> Ok.
>
>>> +
>>> + regmap_update_bits(pdata->regmap, SN_DATARATE_CONFIG_REG,
>>> + SN_DP_DATA_RATE_BITS, i << SN_DP_DATA_RATE_OFFSET);
>>> +}
>>> +
>>> +static void ti_sn_bridge_set_video_timings(struct ti_sn_bridge
>>> *pdata)
>>> +{
>>> + struct drm_display_mode *mode = &pdata->curr_mode;
>>> +
>>> + regmap_write(pdata->regmap, SN_CHA_ACTIVE_LINE_LENGTH_LOW_REG,
>>> + mode->hdisplay & 0xFF);
>>> + regmap_write(pdata->regmap, SN_CHA_ACTIVE_LINE_LENGTH_HIGH_REG,
>>> + (mode->hdisplay >> SN_TIMING_HIGH_OFFSET) & 0xFF);
>>> + regmap_write(pdata->regmap, SN_CHA_VERTICAL_DISPLAY_SIZE_LOW_REG,
>>> + mode->vdisplay & 0xFF);
>>> + regmap_write(pdata->regmap, SN_CHA_VERTICAL_DISPLAY_SIZE_HIGH_REG,
>>> + (mode->vdisplay >> SN_TIMING_HIGH_OFFSET) & 0xFF);
>>> + regmap_write(pdata->regmap, SN_CHA_HSYNC_PULSE_WIDTH_LOW_REG,
>>> + (mode->hsync_end - mode->hsync_start) & 0xFF);
>>> + regmap_write(pdata->regmap, SN_CHA_HSYNC_PULSE_WIDTH_HIGH_REG,
>>> + ((mode->hsync_end - mode->hsync_start) >>
>>> + SN_TIMING_HIGH_OFFSET) & 0xFF);
>>> + regmap_write(pdata->regmap, SN_CHA_VSYNC_PULSE_WIDTH_LOW_REG,
>>> + (mode->vsync_end - mode->vsync_start) & 0xFF);
>>> + regmap_write(pdata->regmap, SN_CHA_VSYNC_PULSE_WIDTH_HIGH_REG,
>>> + ((mode->vsync_end - mode->vsync_start) >>
>>> + SN_TIMING_HIGH_OFFSET) & 0xFF);
>>> + regmap_write(pdata->regmap, SN_CHA_HORIZONTAL_BACK_PORCH_REG,
>>> + (mode->htotal - mode->hsync_end) & 0xFF);
>>> + regmap_write(pdata->regmap, SN_CHA_VERTICAL_BACK_PORCH_REG,
>>> + (mode->vtotal - mode->vsync_end) & 0xFF);
>>> + regmap_write(pdata->regmap, SN_CHA_HORIZONTAL_FRONT_PORCH_REG,
>>> + (mode->hsync_start - mode->hdisplay) & 0xFF);
>>> + regmap_write(pdata->regmap, SN_CHA_VERTICAL_FRONT_PORCH_REG,
>>> + (mode->vsync_start - mode->vdisplay) & 0xFF);
>>> + usleep_range(10000, 10500); /* 10ms delay recommended by spec */
>>> +}
>>> +
>>> +static void ti_sn_bridge_enable(struct drm_bridge *bridge)
>>> +{
>>> + struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge);
>>> + struct drm_panel *panel = pdata->panel;
>>> + unsigned int val = 0;
>>> +
>>> + if (panel) {
>>> + drm_panel_prepare(panel);
>>> + /* in case drm_panel is connected then HPD is not supported */
>>> + regmap_update_bits(pdata->regmap, SN_HPD_DISABLE_REG,
>>> + SN_HPD_DISABLE_BIT, SN_HPD_DISABLE_BIT);
>>> + }
>>> +
>>> + /* DSI_A lane config */
>>> + val = (4 - pdata->dsi->lanes) << SN_DSIA_LANE_OFFSET;
>>> + regmap_update_bits(pdata->regmap, SN_DSI_LANES_REG,
>>> + SN_DSIA_NUM_LANES_BITS, val);
>>> +
>>> + /* DP lane config */
>>> + val = (pdata->dsi->lanes - 1) << SN_DP_LANE_OFFSET;
>>> + regmap_update_bits(pdata->regmap, SN_SSC_CONFIG_REG,
>>> + SN_DP_NUM_LANES_BITS, val);
>>> +
>>> + /* set dsi/dp clk frequency value */
>>> + ti_sn_bridge_set_dsi_dp_rate(pdata);
>>> +
>>> + /* enable DP PLL */
>>> + regmap_write(pdata->regmap, SN_PLL_ENABLE_REG, 1);
>>> + usleep_range(10000, 10500); /* 10ms delay recommended by spec */
>>> +
>>> + /**
>>> + * The SN65DSI86 only supports ASSR Display Authentication method
>>> and
>>> + * this method is enabled by default. An eDP panel must support this
>>> + * authentication method. We need to enable this method in the eDP
>>> panel
>>> + * at DisplayPort address 0x0010A prior to link training.
>>> + */
>>> + regmap_write(pdata->regmap, SN_AUX_WDATA0_REG, 0x01);
>>> + regmap_write(pdata->regmap, SN_AUX_ADDR_19_16_REG, 0x00);
>>> + regmap_write(pdata->regmap, SN_AUX_ADDR_15_8_REG, 0x01);
>>> + regmap_write(pdata->regmap, SN_AUX_ADDR_7_0_REG, 0x0A);
>>> + regmap_write(pdata->regmap, SN_AUX_LENGTH_REG, 0x01);
>>> + regmap_write(pdata->regmap, SN_AUX_CMD_REG, 0x81);
>>> + usleep_range(10000, 10500); /* 10ms delay recommended by spec */
>>> +
>>> + /* Semi auto link training mode */
>>> + regmap_write(pdata->regmap, SN_ML_TX_MODE_REG, 0x0A);
>>> + msleep(20); /* 20ms delay recommended by spec */
>>> +
>>> + /* config video parameters */
>>> + ti_sn_bridge_set_video_timings(pdata);
>>> +
>>> + /* enable video stream */
>>> + regmap_update_bits(pdata->regmap, SN_ENH_FRAME_REG,
>>> + SN_ENABLE_VID_STREAM_BIT, SN_ENABLE_VID_STREAM_BIT);
>>> +
>>> + if (panel)
>>> + drm_panel_enable(panel);
>>> +}
>>> +
>>> +static void ti_sn_bridge_pre_enable(struct drm_bridge *bridge)
>>> +{
>>> + struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge);
>>> +
>>> + pm_runtime_get_sync(pdata->dev);
>>> +
>>> + /* configure bridge CLK_SRC and ref_clk */
>>> + ti_sn_bridge_set_refclk(pdata);
>>> +}
>>> +
>>> +static void ti_sn_bridge_post_disable(struct drm_bridge *bridge)
>>> +{
>>> + struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge);
>>> +
>>> + if (pdata->refclk)
>>> + clk_disable_unprepare(pdata->refclk);
>>> +
>>> + pm_runtime_put_sync(pdata->dev);
>>> +}
>>> +
>>> +static const struct drm_bridge_funcs ti_sn_bridge_funcs = {
>>> + .attach = ti_sn_bridge_attach,
>>> + .pre_enable = ti_sn_bridge_pre_enable,
>>> + .enable = ti_sn_bridge_enable,
>>> + .disable = ti_sn_bridge_disable,
>>> + .post_disable = ti_sn_bridge_post_disable,
>>> + .mode_set = ti_sn_bridge_mode_set,
>>> +};
>>> +
>>> +static int ti_sn_bridge_parse_dsi_host(struct ti_sn_bridge *pdata)
>>> +{
>>> + struct device_node *np = pdata->dev->of_node;
>>> + struct device_node *end_node;
>>> +
>>> + end_node = of_graph_get_endpoint_by_regs(np, 0, 0);
>>> + if (!end_node) {
>>> + DRM_ERROR("remote endpoint not found\n");
>>> + return -ENODEV;
>>> + }
>>> +
>>> + pdata->host_node = of_graph_get_remote_port_parent(end_node);
>>> + of_node_put(end_node);
>>> + if (!pdata->host_node) {
>>> + DRM_ERROR("remote node not found\n");
>>> + return -ENODEV;
>>> + }
>>> + of_node_put(pdata->host_node);
>> Why not of_graph_get_remote_node ?
>>
> Just for my understanding, is of_graph_get_remote_port_parent not
> recommended? what is the benefit of using of_graph_get_remote_node()?
Because it encapsulates both of_graph_get_endpoint_by_regs and
of_graph_get_remote_port_parent with correct node reference management.
>
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int ti_sn_bridge_probe(struct i2c_client *client,
>>> + const struct i2c_device_id *id)
>>> +{
>>> + struct ti_sn_bridge *pdata;
>>> + struct device_node *ddc_node;
>>> + int ret = 0;
>>> +
>>> + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
>>> + DRM_ERROR("device doesn't support I2C\n");
>>> + return -ENODEV;
>>> + }
>>> +
>>> + pdata = devm_kzalloc(&client->dev, sizeof(struct ti_sn_bridge),
>>> + GFP_KERNEL);
>>> + if (!pdata)
>>> + return -ENOMEM;
>>> +
>>> + pdata->dev = &client->dev;
>>> + dev_set_drvdata(&client->dev, pdata);
>>> +
>>> + pdata->regmap = devm_regmap_init_i2c(client,
>>> + &ti_sn_bridge_regmap_config);
>>> + if (IS_ERR(pdata->regmap)) {
>>> + DRM_ERROR("regmap i2c init failed\n");
>>> + return PTR_ERR(pdata->regmap);
>>> + }
>>> +
>>> + pdata->enable_gpio = devm_gpiod_get(pdata->dev,
>>> + "enable", GPIOD_OUT_LOW);
>>> + if (IS_ERR(pdata->enable_gpio)) {
>>> + DRM_ERROR("failed to get enable gpio from DT\n");
>>> + ret = PTR_ERR(pdata->enable_gpio);
>>> + return ret;
>>> + }
>>> +
>>> + ret = ti_sn_bridge_parse_regulators(pdata);
>>> + if (ret) {
>>> + DRM_ERROR("failed to parse regulators\n");
>>> + return ret;
>>> + }
>>> +
>>> + ret = ti_sn_bridge_parse_dsi_host(pdata);
>>> + if (ret)
>>> + return ret;
>>> +
>>> + pm_runtime_enable(pdata->dev);
>>> + pm_runtime_get_sync(pdata->dev);
>>> + ret = ti_sn_bridge_read_device_rev(pdata);
>>> + pm_runtime_put_sync(pdata->dev);
>> I would put it into (pre) enable callbacks, maybe with marking it to
>> run
>> only once.
>>
> do you mean we should put the ti_sn_bridge_read_device_rev() in pre
> enable callback?
Yes, to avoid unnecessary switching on/off device.
Regards
Andrzej
>
>> Regards
>> Andrzej
>>
>>> + if (ret)
>>> + goto err_rev_read;
>>> +
>>> + pdata->refclk = devm_clk_get(pdata->dev, "refclk");
>>> +
>>> + ddc_node = of_parse_phandle(pdata->dev->of_node, "ddc-i2c-bus", 0);
>>> + if (ddc_node) {
>>> + pdata->ddc = of_find_i2c_adapter_by_node(ddc_node);
>>> + of_node_put(ddc_node);
>>> + if (!pdata->ddc) {
>>> + DRM_DEBUG_KMS("failed to read ddc node\n");
>>> + ret = -EPROBE_DEFER;
>>> + goto err_rev_read;
>>> + }
>>> + } else {
>>> + DRM_DEBUG_KMS("no ddc property found\n");
>>> + }
>>> +
>>> + i2c_set_clientdata(client, pdata);
>>> +
>>> + pdata->bridge.funcs = &ti_sn_bridge_funcs;
>>> + pdata->bridge.of_node = client->dev.of_node;
>>> +
>>> + drm_bridge_add(&pdata->bridge);
>>> +
>>> + return 0;
>>> +
>>> +err_rev_read:
>>> + pm_runtime_disable(pdata->dev);
>>> + return ret;
>>> +}
>>> +
>>> +static int ti_sn_bridge_remove(struct i2c_client *client)
>>> +{
>>> + struct ti_sn_bridge *pdata = i2c_get_clientdata(client);
>>> +
>>> + if (!pdata)
>>> + return -EINVAL;
>>> +
>>> + mipi_dsi_detach(pdata->dsi);
>>> + mipi_dsi_device_unregister(pdata->dsi);
>>> +
>>> + drm_bridge_remove(&pdata->bridge);
>>> + pm_runtime_disable(pdata->dev);
>>> + i2c_put_adapter(pdata->ddc);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static struct i2c_device_id ti_sn_bridge_id[] = {
>>> + { "ti,sn65dsi86", 0},
>>> + {},
>>> +};
>>> +MODULE_DEVICE_TABLE(i2c, ti_sn_bridge_id);
>>> +
>>> +static const struct of_device_id ti_sn_bridge_match_table[] = {
>>> + {.compatible = "ti,sn65dsi86"},
>>> + {},
>>> +};
>>> +MODULE_DEVICE_TABLE(of, ti_sn_bridge_match_table);
>>> +
>>> +static struct i2c_driver ti_sn_bridge_driver = {
>>> + .driver = {
>>> + .name = "ti_sn65dsi86",
>>> + .of_match_table = ti_sn_bridge_match_table,
>>> + .pm = &ti_sn_bridge_pm_ops,
>>> + },
>>> + .probe = ti_sn_bridge_probe,
>>> + .remove = ti_sn_bridge_remove,
>>> + .id_table = ti_sn_bridge_id,
>>> +};
>>> +
>>> +module_i2c_driver(ti_sn_bridge_driver);
>>> +MODULE_DESCRIPTION("sn65dsi86 DSI to eDP bridge driver");
>>> +MODULE_LICENSE("GPL v2");
>
>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* Re: [PATCH] ARM: dts: vf610-zii-dev: enable vf610 builtin temp sensor
From: Stefan Agner @ 2018-05-16 7:24 UTC (permalink / raw)
To: Nikita Yushchenko
Cc: Shawn Guo, Sascha Hauer, Pengutronix Kernel Team, Rob Herring,
Mark Rutland, linux-arm-kernel, devicetree, linux-kernel,
Chris Healy
In-Reply-To: <20180516063921.10406-1-nikita.yoush@cogentembedded.com>
On 16.05.2018 08:39, Nikita Yushchenko wrote:
> Vybrid has single internal temperature sensor connected to both internal
> ADC modules.
>
> vf610-zii-dev already has ADC0 enabled. Now, to get temperature sensor
> captured by iio_hwmon driver, need to configure iio_hwmon node to use
> that ADC.
That seems sensible.
Acked-by: Stefan Agner <stefan@agner.ch>
>
> Signed-off-by: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
> ---
> arch/arm/boot/dts/vf610-zii-dev.dtsi | 4 ++++
> arch/arm/boot/dts/vfxxx.dtsi | 2 +-
> 2 files changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm/boot/dts/vf610-zii-dev.dtsi
> b/arch/arm/boot/dts/vf610-zii-dev.dtsi
> index 4890b8a5aa44..5ae5abfe1d55 100644
> --- a/arch/arm/boot/dts/vf610-zii-dev.dtsi
> +++ b/arch/arm/boot/dts/vf610-zii-dev.dtsi
> @@ -222,6 +222,10 @@
> status = "okay";
> };
>
> +&tempsensor {
> + io-channels = <&adc0 16>;
> +};
> +
> &iomuxc {
> pinctrl_adc0_ad5: adc0ad5grp {
> fsl,pins = <
> diff --git a/arch/arm/boot/dts/vfxxx.dtsi b/arch/arm/boot/dts/vfxxx.dtsi
> index c3f09b737924..d392794d9c13 100644
> --- a/arch/arm/boot/dts/vfxxx.dtsi
> +++ b/arch/arm/boot/dts/vfxxx.dtsi
> @@ -84,7 +84,7 @@
> mask = <0x1000>;
> };
>
> - iio-hwmon {
> + tempsensor: iio-hwmon {
> compatible = "iio-hwmon";
> io-channels = <&adc0 16>, <&adc1 16>;
> };
^ permalink raw reply
* RE: [PATCH v5 01/14] dt-bindings: connector: add properties for typec
From: Peter Chen @ 2018-05-16 7:21 UTC (permalink / raw)
To: Jun Li, robh+dt@kernel.org, gregkh@linuxfoundation.org,
heikki.krogerus@linux.intel.com, linux@roeck-us.net
Cc: a.hajda@samsung.com, cw00.choi@samsung.com,
shufan_lee@richtek.com, gsomlo@gmail.com,
devicetree@vger.kernel.org, linux-usb@vger.kernel.org,
dl-linux-imx
In-Reply-To: <1525307094-27402-2-git-send-email-jun.li@nxp.com>
> Add bingdings supported by current typec driver, so user can pass all those
> properties via dt.
>
%s/bingdings/bindings
Peter
^ 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