* Re: [PATCH v2 2/2] watchdog: aspeed: Add support for AST2600
From: Guenter Roeck @ 2019-08-20 15:50 UTC (permalink / raw)
To: Joel Stanley
Cc: devicetree, Ryan Chen, linux-watchdog, linux-aspeed,
Andrew Jeffery, Rob Herring, Wim Van Sebroeck, linux-arm-kernel
In-Reply-To: <20190819051738.17370-3-joel@jms.id.au>
On Mon, Aug 19, 2019 at 02:47:38PM +0930, Joel Stanley wrote:
> From: Ryan Chen <ryan_chen@aspeedtech.com>
>
> The ast2600 can be supported by the same code as the ast2500.
>
> Signed-off-by: Ryan Chen <ryan_chen@aspeedtech.com>
> Signed-off-by: Joel Stanley <joel@jms.id.au>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
> ---
> v2:
> Reuse ast2500 config structure
> ---
> drivers/watchdog/aspeed_wdt.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/watchdog/aspeed_wdt.c b/drivers/watchdog/aspeed_wdt.c
> index cc71861e033a..5b64bc2e8788 100644
> --- a/drivers/watchdog/aspeed_wdt.c
> +++ b/drivers/watchdog/aspeed_wdt.c
> @@ -34,6 +34,7 @@ static const struct aspeed_wdt_config ast2500_config = {
> static const struct of_device_id aspeed_wdt_of_table[] = {
> { .compatible = "aspeed,ast2400-wdt", .data = &ast2400_config },
> { .compatible = "aspeed,ast2500-wdt", .data = &ast2500_config },
> + { .compatible = "aspeed,ast2600-wdt", .data = &ast2500_config },
> { },
> };
> MODULE_DEVICE_TABLE(of, aspeed_wdt_of_table);
> @@ -259,7 +260,8 @@ static int aspeed_wdt_probe(struct platform_device *pdev)
> set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
> }
>
> - if (of_device_is_compatible(np, "aspeed,ast2500-wdt")) {
> + if ((of_device_is_compatible(np, "aspeed,ast2500-wdt")) ||
> + (of_device_is_compatible(np, "aspeed,ast2600-wdt"))) {
> u32 reg = readl(wdt->base + WDT_RESET_WIDTH);
>
> reg &= config->ext_pulse_width_mask;
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v3 2/5] arm64: cpufeature: Add feature to detect heterogeneous systems
From: Mark Rutland @ 2019-08-20 15:49 UTC (permalink / raw)
To: Raphael Gault
Cc: raph.gault+kdev, peterz, catalin.marinas, will.deacon,
linux-kernel, acme, mingo, linux-arm-kernel
In-Reply-To: <20190820152316.GA38082@lakrids.cambridge.arm.com>
On Tue, Aug 20, 2019 at 04:23:17PM +0100, Mark Rutland wrote:
> Hi Raphael,
>
> On Fri, Aug 16, 2019 at 01:59:31PM +0100, Raphael Gault wrote:
> > This feature is required in order to enable PMU counters direct
> > access from userspace only when the system is homogeneous.
> > This feature checks the model of each CPU brought online and compares it
> > to the boot CPU. If it differs then it is heterogeneous.
>
> It would be worth noting that this patch prevents heterogeneous CPUs
> being brought online late if the system was uniform at boot time.
Looking again, I think I'd misunderstood how
ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU was dealt with, but we do have a
problem in this area.
[...]
>
> > + .capability = ARM64_HAS_HETEROGENEOUS_PMU,
> > + .type = ARM64_CPUCAP_SCOPE_LOCAL_CPU | ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU,
> > + .matches = has_heterogeneous_pmu,
> > + },
I had a quick chat with Will, and we concluded that we must permit late
onlining of heterogeneous CPUs here as people are likely to rely on
late CPU onlining on some heterogeneous systems.
I think the above permits that, but that also means that we need some
support code to fail gracefully in that case (e.g. without sending
a SIGILL to unaware userspace code).
That means that we'll need the counter emulation code that you had in
previous versions of this patch (e.g. to handle potential UNDEFs when a
new CPU has fewer counters than the previously online CPUs).
Further, I think the context switch (and event index) code needs to take
this cap into account, and disable direct access once the system becomes
heterogeneous.
Thanks,
Mark.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH V2 2/4] watchdog: Add i.MX7ULP watchdog support
From: Guenter Roeck @ 2019-08-20 15:48 UTC (permalink / raw)
To: Anson.Huang
Cc: mark.rutland, devicetree, leonard.crestez, schnitzeltony,
linux-watchdog, otavio, festevam, s.hauer, jan.tuerk, linux,
linux-kernel, robh+dt, Linux-imx, kernel, u.kleine-koenig, wim,
shawnguo, linux-arm-kernel
In-Reply-To: <20190820153155.GA19394@roeck-us.net>
On Tue, Aug 20, 2019 at 08:31:55AM -0700, Guenter Roeck wrote:
> On Mon, Aug 12, 2019 at 04:53:19PM +0800, Anson.Huang@nxp.com wrote:
> > From: Anson Huang <Anson.Huang@nxp.com>
> >
> > The i.MX7ULP Watchdog Timer (WDOG) module is an independent timer
> > that is available for system use.
> > It provides a safety feature to ensure that software is executing
> > as planned and that the CPU is not stuck in an infinite loop or
> > executing unintended code. If the WDOG module is not serviced
> > (refreshed) within a certain period, it resets the MCU.
> >
> > Add driver support for i.MX7ULP watchdog.
> >
> > Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
>
> Reviewed-by: Guenter Roeck <linux@roeck-us.net>
>
Wait, I have to withdraw that.
With clk_prepare_enable(), you'll also need to call clk_disable_unprepare()
on remove. An easy way to do this and keep the code simple would be:
static void imx7ulp_wdt_clk_disable_unprepare(void *data)
{
clk_disable_unprepare(data);
}
static int imx7ulp_wdt_probe(...)
{
...
ret = clk_prepare_enable(imx7ulp_wdt->clk);
if (ret)
return ret;
ret = devm_add_action_or_reset(dev, imx7ulp_wdt_clk_disable_unprepare);
if (ret)
return ret;
...
Thanks,
Guenter
> > ---
> > Changes since V1:
> > - Add clock operation;
> > - Remove unneccsary error message when registering watchdog device failed;
> > - Use BIT() instead of hard code;
> > ---
> > drivers/watchdog/Kconfig | 13 +++
> > drivers/watchdog/Makefile | 1 +
> > drivers/watchdog/imx7ulp_wdt.c | 244 +++++++++++++++++++++++++++++++++++++++++
> > 3 files changed, 258 insertions(+)
> > create mode 100644 drivers/watchdog/imx7ulp_wdt.c
> >
> > diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> > index 8188963..0884e53 100644
> > --- a/drivers/watchdog/Kconfig
> > +++ b/drivers/watchdog/Kconfig
> > @@ -740,6 +740,19 @@ config IMX_SC_WDT
> > To compile this driver as a module, choose M here: the
> > module will be called imx_sc_wdt.
> >
> > +config IMX7ULP_WDT
> > + tristate "IMX7ULP Watchdog"
> > + depends on ARCH_MXC || COMPILE_TEST
> > + select WATCHDOG_CORE
> > + help
> > + This is the driver for the hardware watchdog on the Freescale
> > + IMX7ULP and later processors. If you have one of these
> > + processors and wish to have watchdog support enabled,
> > + say Y, otherwise say N.
> > +
> > + To compile this driver as a module, choose M here: the
> > + module will be called imx7ulp_wdt.
> > +
> > config UX500_WATCHDOG
> > tristate "ST-Ericsson Ux500 watchdog"
> > depends on MFD_DB8500_PRCMU
> > diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
> > index 7caa920..7d32537 100644
> > --- a/drivers/watchdog/Makefile
> > +++ b/drivers/watchdog/Makefile
> > @@ -69,6 +69,7 @@ obj-$(CONFIG_TS4800_WATCHDOG) += ts4800_wdt.o
> > obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
> > obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
> > obj-$(CONFIG_IMX_SC_WDT) += imx_sc_wdt.o
> > +obj-$(CONFIG_IMX7ULP_WDT) += imx7ulp_wdt.o
> > obj-$(CONFIG_UX500_WATCHDOG) += ux500_wdt.o
> > obj-$(CONFIG_RETU_WATCHDOG) += retu_wdt.o
> > obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o
> > diff --git a/drivers/watchdog/imx7ulp_wdt.c b/drivers/watchdog/imx7ulp_wdt.c
> > new file mode 100644
> > index 0000000..c20fba4
> > --- /dev/null
> > +++ b/drivers/watchdog/imx7ulp_wdt.c
> > @@ -0,0 +1,244 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright 2019 NXP.
> > + */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/init.h>
> > +#include <linux/io.h>
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/reboot.h>
> > +#include <linux/watchdog.h>
> > +
> > +#define WDOG_CS 0x0
> > +#define WDOG_CS_CMD32EN BIT(13)
> > +#define WDOG_CS_ULK BIT(11)
> > +#define WDOG_CS_RCS BIT(10)
> > +#define WDOG_CS_EN BIT(7)
> > +#define WDOG_CS_UPDATE BIT(5)
> > +
> > +#define WDOG_CNT 0x4
> > +#define WDOG_TOVAL 0x8
> > +
> > +#define REFRESH_SEQ0 0xA602
> > +#define REFRESH_SEQ1 0xB480
> > +#define REFRESH ((REFRESH_SEQ1 << 16) | REFRESH_SEQ0)
> > +
> > +#define UNLOCK_SEQ0 0xC520
> > +#define UNLOCK_SEQ1 0xD928
> > +#define UNLOCK ((UNLOCK_SEQ1 << 16) | UNLOCK_SEQ0)
> > +
> > +#define DEFAULT_TIMEOUT 60
> > +#define MAX_TIMEOUT 128
> > +
> > +static bool nowayout = WATCHDOG_NOWAYOUT;
> > +module_param(nowayout, bool, 0000);
> > +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
> > + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
> > +
> > +struct imx7ulp_wdt_device {
> > + struct notifier_block restart_handler;
> > + struct watchdog_device wdd;
> > + void __iomem *base;
> > + struct clk *clk;
> > + int rate;
> > +};
> > +
> > +static inline void imx7ulp_wdt_enable(void __iomem *base, bool enable)
> > +{
> > + u32 val = readl(base + WDOG_CS);
> > +
> > + writel(UNLOCK, base + WDOG_CNT);
> > + if (enable)
> > + writel(val | WDOG_CS_EN, base + WDOG_CS);
> > + else
> > + writel(val & ~WDOG_CS_EN, base + WDOG_CS);
> > +}
> > +
> > +static inline bool imx7ulp_wdt_is_enabled(void __iomem *base)
> > +{
> > + u32 val = readl(base + WDOG_CS);
> > +
> > + return val & WDOG_CS_EN;
> > +}
> > +
> > +static int imx7ulp_wdt_ping(struct watchdog_device *wdog)
> > +{
> > + struct imx7ulp_wdt_device *wdt = watchdog_get_drvdata(wdog);
> > +
> > + writel(REFRESH, wdt->base + WDOG_CNT);
> > +
> > + return 0;
> > +}
> > +
> > +static int imx7ulp_wdt_start(struct watchdog_device *wdog)
> > +{
> > + struct imx7ulp_wdt_device *wdt = watchdog_get_drvdata(wdog);
> > +
> > + imx7ulp_wdt_enable(wdt->base, true);
> > +
> > + return 0;
> > +}
> > +
> > +static int imx7ulp_wdt_stop(struct watchdog_device *wdog)
> > +{
> > + struct imx7ulp_wdt_device *wdt = watchdog_get_drvdata(wdog);
> > +
> > + imx7ulp_wdt_enable(wdt->base, false);
> > +
> > + return 0;
> > +}
> > +
> > +static int imx7ulp_wdt_set_timeout(struct watchdog_device *wdog,
> > + unsigned int timeout)
> > +{
> > + struct imx7ulp_wdt_device *wdt = watchdog_get_drvdata(wdog);
> > + u32 val = wdt->rate * timeout;
> > +
> > + writel(UNLOCK, wdt->base + WDOG_CNT);
> > + writel(val, wdt->base + WDOG_TOVAL);
> > +
> > + wdog->timeout = timeout;
> > +
> > + return 0;
> > +}
> > +
> > +static const struct watchdog_ops imx7ulp_wdt_ops = {
> > + .owner = THIS_MODULE,
> > + .start = imx7ulp_wdt_start,
> > + .stop = imx7ulp_wdt_stop,
> > + .ping = imx7ulp_wdt_ping,
> > + .set_timeout = imx7ulp_wdt_set_timeout,
> > +};
> > +
> > +static const struct watchdog_info imx7ulp_wdt_info = {
> > + .identity = "i.MX7ULP watchdog timer",
> > + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
> > + WDIOF_MAGICCLOSE,
> > +};
> > +
> > +static inline void imx7ulp_wdt_init(void __iomem *base, unsigned int timeout)
> > +{
> > + u32 val;
> > +
> > + /* unlock the wdog for reconfiguration */
> > + writel_relaxed(UNLOCK_SEQ0, base + WDOG_CNT);
> > + writel_relaxed(UNLOCK_SEQ1, base + WDOG_CNT);
> > +
> > + /* set an initial timeout value in TOVAL */
> > + writel(timeout, base + WDOG_TOVAL);
> > + /* enable 32bit command sequence and reconfigure */
> > + val = BIT(13) | BIT(8) | BIT(5);
> > + writel(val, base + WDOG_CS);
> > +}
> > +
> > +static int imx7ulp_wdt_probe(struct platform_device *pdev)
> > +{
> > + struct imx7ulp_wdt_device *imx7ulp_wdt;
> > + struct device *dev = &pdev->dev;
> > + struct watchdog_device *wdog;
> > + int ret;
> > +
> > + imx7ulp_wdt = devm_kzalloc(dev, sizeof(*imx7ulp_wdt), GFP_KERNEL);
> > + if (!imx7ulp_wdt)
> > + return -ENOMEM;
> > +
> > + platform_set_drvdata(pdev, imx7ulp_wdt);
> > +
> > + imx7ulp_wdt->base = devm_platform_ioremap_resource(pdev, 0);
> > + if (IS_ERR(imx7ulp_wdt->base))
> > + return PTR_ERR(imx7ulp_wdt->base);
> > +
> > + imx7ulp_wdt->clk = devm_clk_get(dev, NULL);
> > + if (IS_ERR(imx7ulp_wdt->clk)) {
> > + dev_err(dev, "Failed to get watchdog clock\n");
> > + return PTR_ERR(imx7ulp_wdt->clk);
> > + }
> > +
> > + ret = clk_prepare_enable(imx7ulp_wdt->clk);
> > + if (ret)
> > + return ret;
> > +
> > + imx7ulp_wdt->rate = 1000;
> > + wdog = &imx7ulp_wdt->wdd;
> > + wdog->info = &imx7ulp_wdt_info;
> > + wdog->ops = &imx7ulp_wdt_ops;
> > + wdog->min_timeout = 1;
> > + wdog->max_timeout = MAX_TIMEOUT;
> > + wdog->parent = dev;
> > + wdog->timeout = DEFAULT_TIMEOUT;
> > +
> > + watchdog_init_timeout(wdog, 0, dev);
> > + watchdog_stop_on_reboot(wdog);
> > + watchdog_stop_on_unregister(wdog);
> > + watchdog_set_drvdata(wdog, imx7ulp_wdt);
> > + imx7ulp_wdt_init(imx7ulp_wdt->base, wdog->timeout * imx7ulp_wdt->rate);
> > +
> > + ret = devm_watchdog_register_device(dev, wdog);
> > + if (ret)
> > + goto disable_clk;
> > +
> > + return 0;
> > +
> > +disable_clk:
> > + clk_disable_unprepare(imx7ulp_wdt->clk);
> > +
> > + return ret;
> > +}
> > +
> > +static int __maybe_unused imx7ulp_wdt_suspend(struct device *dev)
> > +{
> > + struct imx7ulp_wdt_device *imx7ulp_wdt = dev_get_drvdata(dev);
> > +
> > + if (watchdog_active(&imx7ulp_wdt->wdd))
> > + imx7ulp_wdt_stop(&imx7ulp_wdt->wdd);
> > +
> > + clk_disable_unprepare(imx7ulp_wdt->clk);
> > +
> > + return 0;
> > +}
> > +
> > +static int __maybe_unused imx7ulp_wdt_resume(struct device *dev)
> > +{
> > + struct imx7ulp_wdt_device *imx7ulp_wdt = dev_get_drvdata(dev);
> > + u32 timeout = imx7ulp_wdt->wdd.timeout * imx7ulp_wdt->rate;
> > + int ret;
> > +
> > + ret = clk_prepare_enable(imx7ulp_wdt->clk);
> > + if (ret)
> > + return ret;
> > +
> > + if (imx7ulp_wdt_is_enabled(imx7ulp_wdt->base))
> > + imx7ulp_wdt_init(imx7ulp_wdt->base, timeout);
> > +
> > + if (watchdog_active(&imx7ulp_wdt->wdd))
> > + imx7ulp_wdt_start(&imx7ulp_wdt->wdd);
> > +
> > + return 0;
> > +}
> > +
> > +static SIMPLE_DEV_PM_OPS(imx7ulp_wdt_pm_ops, imx7ulp_wdt_suspend,
> > + imx7ulp_wdt_resume);
> > +
> > +static const struct of_device_id imx7ulp_wdt_dt_ids[] = {
> > + { .compatible = "fsl,imx7ulp-wdt", },
> > + { /* sentinel */ }
> > +};
> > +MODULE_DEVICE_TABLE(of, imx7ulp_wdt_dt_ids);
> > +
> > +static struct platform_driver imx7ulp_wdt_driver = {
> > + .probe = imx7ulp_wdt_probe,
> > + .driver = {
> > + .name = "imx7ulp-wdt",
> > + .pm = &imx7ulp_wdt_pm_ops,
> > + .of_match_table = imx7ulp_wdt_dt_ids,
> > + },
> > +};
> > +module_platform_driver(imx7ulp_wdt_driver);
> > +
> > +MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");
> > +MODULE_DESCRIPTION("Freescale i.MX7ULP watchdog driver");
> > +MODULE_LICENSE("GPL v2");
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 1/3] serial: atmel: Don't check for mctrl_gpio_to_gpiod() returning error
From: Richard Genoud @ 2019-08-20 15:47 UTC (permalink / raw)
To: Uwe Kleine-König, Geert Uytterhoeven
Cc: Alexandre Belloni, Pengutronix Kernel Team, Geert Uytterhoeven,
open list:SERIAL DRIVERS, Richard Genoud, Greg Kroah-Hartman,
Sascha Hauer, Frieder Schrempf, Linux-Renesas, Ludovic Desroches,
NXP Linux Team, Fabio Estevam, Jiri Slaby, Shawn Guo, Linux ARM
In-Reply-To: <20190814110804.2ceo2upc3su7muup@pengutronix.de>
Le 14/08/2019 à 13:08, Uwe Kleine-König a écrit :
> On Wed, Aug 14, 2019 at 12:20:33PM +0200, Geert Uytterhoeven wrote:
>> Hi Uwe,
>>
>> On Wed, Aug 14, 2019 at 11:36 AM Uwe Kleine-König
>> <u.kleine-koenig@pengutronix.de> wrote:
>>> On Wed, Aug 14, 2019 at 11:29:22AM +0200, Geert Uytterhoeven wrote:
>>>> Since commit 1d267ea6539f2663 ("serial: mctrl-gpio: simplify init
>>>> routine"), mctrl_gpio_init() returns failure if the assignment to any
>>>> member of the gpio array results in an error pointer.
>>>> Since commit c359522194593815 ("serial: mctrl_gpio: Avoid probe failures
>>>> in case of missing gpiolib"), mctrl_gpio_to_gpiod() returns NULL in the
>>>> !CONFIG_GPIOLIB case.
>>>> Hence there is no longer a need to check for mctrl_gpio_to_gpiod()
>>>> returning an error value. A simple NULL check is sufficient.
>>>>
>>>> This follows the spirit of commit 445df7ff3fd1a0a9 ("serial: mctrl-gpio:
>>>> drop usages of IS_ERR_OR_NULL") in the mctrl-gpio core.
>>>>
>>>> Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
>>>> ---
>>>> drivers/tty/serial/atmel_serial.c | 12 ++++--------
>>>> 1 file changed, 4 insertions(+), 8 deletions(-)
>>>>
>>>> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
>>>> index 19a85d6fe3d20541..e9620a81166b7dc1 100644
>>>> --- a/drivers/tty/serial/atmel_serial.c
>>>> +++ b/drivers/tty/serial/atmel_serial.c
>>>> @@ -303,32 +303,28 @@ static unsigned int atmel_get_lines_status(struct uart_port *port)
>>>>
>>>> mctrl_gpio_get(atmel_port->gpios, &ret);
>>>>
>>>> - if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
>>>> - UART_GPIO_CTS))) {
>>>> + if (mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS)) {
>>>> if (ret & TIOCM_CTS)
>>>> status &= ~ATMEL_US_CTS;
>>>> else
>>>> status |= ATMEL_US_CTS;
>>>> }
>>>
>>> The change is fine, but it seems the atmel driver doesn't use mctrl_gpio
>>> as expected (at least as expected by me). IMHO driving the hardware
>>> function of the CTS pin shouldn't be conditional on the presence of a
>>> cts-gpio. Is there a reason not to just drop the if completely?
>>
>> The above code returns the hardware status if CTS is not a GPIO, and
>> returns (overrides with) the GPIO status if CTS is a GPIO.
>> Isn't that correct, or am I missing something?
>
> I took a deeper look into this driver now. The task for
> atmel_get_lines_status() isn't to implement the get_mctrl() callback.
>
> Instead this is called in the irqhandler to set ATMEL_US_RI in a
> "pending" value that then later in atmel_handle_status() is translated
> to a "ring" event that is handled there.
>
> So the right cleanup would be to let atmel_get_lines_status() just be
>
> return atmel_uart_readl(port, ATMEL_US_CSR);
>
> . If something happend on the lines implemented as gpio the driver's irq
> function isn't called anyhow.
I'd like to give it a good test to be sure, and I'll get back to you.
Thanks,
Richard
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 3/6] net: stmmac: sun8i: Use devm_regulator_get for PHY regulator
From: Ondřej Jirman @ 2019-08-20 15:47 UTC (permalink / raw)
To: Andrew Lunn
Cc: Mark Rutland, Jose Abreu, Alexandre Torgue, devicetree, netdev,
linux-kernel, Maxime Ripard, linux-stm32, Chen-Yu Tsai,
Rob Herring, Maxime Coquelin, Giuseppe Cavallaro, David S. Miller,
linux-arm-kernel
In-Reply-To: <20190820153939.GL29991@lunn.ch>
Hi Andrew,
On Tue, Aug 20, 2019 at 05:39:39PM +0200, Andrew Lunn wrote:
> On Tue, Aug 20, 2019 at 04:53:40PM +0200, megous@megous.com wrote:
> > From: Ondrej Jirman <megous@megous.com>
> >
> > Use devm_regulator_get instead of devm_regulator_get_optional and rely
> > on dummy supply. This avoids NULL checks before regulator_enable/disable
> > calls.
>
> Hi Ondrej
>
> What do you mean by a dummy supply? I'm just trying to make sure you
> are not breaking backwards compatibility.
Sorry, I mean dummy regulator. See:
https://elixir.bootlin.com/linux/latest/source/drivers/regulator/core.c#L1874
On systems that use DT (i.e. have_full_constraints() == true), when the
regulator is not found (ENODEV, not specified in DT), regulator_get will return
a fake dummy regulator that can be enabled/disabled, but doesn't do anything
real.
This can be used to avoid NULL checks and make the code simpler.
regards,
Ondrej
> Thanks
> Andrew
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v2 7/7] arm64: dts: imx8mm: Add devfreq nodes
From: Leonard Crestez @ 2019-08-20 15:45 UTC (permalink / raw)
To: Stephen Boyd, Shawn Guo, MyungJoo Ham, Chanwoo Choi, Rob Herring
Cc: Mark Rutland, Artur Świgoń, Abel Vesa, Saravana Kannan,
Anson Huang, linux-arm-kernel, Viresh Kumar, Michael Turquette,
linux-pm, linux-imx, Krzysztof Kozlowski, linux-clk,
Kyungmin Park, Alexandre Bailon, kernel, Dong Aisheng,
Fabio Estevam, Georgi Djakov, devicetree, Jacky Bai
In-Reply-To: <cover.1566315740.git.leonard.crestez@nxp.com>
Add initial support for bus scaling on imx8m, starting with noc and ddrc
because they're the biggest power hogs.
Add a devfreq-event link to the PMU in order to support on-demand
scaling of ddrc based on measured dram bandwith usage. Make ddrc a
parent of the NOC because all traffic to ddrc goes through
Support for proactive scaling via interconnect and support for scaling
additional NICs will come later. The high-performance bus masters which
need that (display, vpu, gpu) are not yet enabled in upstream anyway.
Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
---
arch/arm64/boot/dts/freescale/imx8mm.dtsi | 53 ++++++++++++++++++++++-
1 file changed, 52 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/freescale/imx8mm.dtsi b/arch/arm64/boot/dts/freescale/imx8mm.dtsi
index 5f9d0da196e1..5474c50784c2 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mm.dtsi
@@ -139,10 +139,38 @@
clock-latency-ns = <150000>;
opp-suspend;
};
};
+ ddrc_opp_table: ddrc-opp-table {
+ compatible = "operating-points-v2";
+
+ opp-25M {
+ opp-hz = /bits/ 64 <25000000>;
+ };
+ opp-100M {
+ opp-hz = /bits/ 64 <100000000>;
+ };
+ opp-750M {
+ opp-hz = /bits/ 64 <750000000>;
+ };
+ };
+
+ noc_opp_table: noc-opp-table {
+ compatible = "operating-points-v2";
+
+ opp-150M {
+ opp-hz = /bits/ 64 <150000000>;
+ };
+ opp-375M {
+ opp-hz = /bits/ 64 <375000000>;
+ };
+ opp-750M {
+ opp-hz = /bits/ 64 <750000000>;
+ };
+ };
+
memory@40000000 {
device_type = "memory";
reg = <0x0 0x40000000 0 0x80000000>;
};
@@ -773,10 +801,18 @@
status = "disabled";
};
};
+ noc: noc@32700000 {
+ compatible = "fsl,imx8mm-noc", "fsl,imx8m-noc";
+ reg = <0x32700000 0x100000>;
+ clocks = <&clk IMX8MM_CLK_NOC>;
+ devfreq = <&ddrc>;
+ operating-points-v2 = <&noc_opp_table>;
+ };
+
aips4: bus@32c00000 {
compatible = "fsl,aips-bus", "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges = <0x32c00000 0x32c00000 0x400000>;
@@ -857,11 +893,26 @@
#interrupt-cells = <3>;
interrupt-controller;
interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
};
- ddr-pmu@3d800000 {
+ ddrc: dram-controller@3d400000 {
+ compatible = "fsl,imx8mm-ddrc", "fsl,imx8m-ddrc";
+ reg = <0x3d400000 0x400000>;
+ clock-names = "dram_core",
+ "dram_pll",
+ "dram_alt",
+ "dram_apb";
+ clocks = <&clk IMX8MM_CLK_DRAM_CORE>,
+ <&clk IMX8MM_DRAM_PLL>,
+ <&clk IMX8MM_CLK_DRAM_ALT>,
+ <&clk IMX8MM_CLK_DRAM_APB>;
+ devfreq-events = <&ddr_pmu>;
+ operating-points-v2 = <&ddrc_opp_table>;
+ };
+
+ ddr_pmu: ddr-pmu@3d800000 {
compatible = "fsl,imx8mm-ddr-pmu", "fsl,imx8m-ddr-pmu";
reg = <0x3d800000 0x400000>;
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
};
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 5/7] PM / devfreq: Add dynamic scaling for imx ddr controller
From: Leonard Crestez @ 2019-08-20 15:45 UTC (permalink / raw)
To: Stephen Boyd, Shawn Guo, MyungJoo Ham, Chanwoo Choi, Rob Herring
Cc: Mark Rutland, Artur Świgoń, Abel Vesa, Saravana Kannan,
Anson Huang, linux-arm-kernel, Viresh Kumar, Michael Turquette,
linux-pm, linux-imx, Krzysztof Kozlowski, linux-clk,
Kyungmin Park, Alexandre Bailon, kernel, Dong Aisheng,
Fabio Estevam, Georgi Djakov, devicetree, Jacky Bai
In-Reply-To: <cover.1566315740.git.leonard.crestez@nxp.com>
Add driver for dynamic scaling the DDR Controller on imx8m chips. Actual
frequency switching is implemented in TF-A, this driver just wraps the
SMC calls and updates the clk tree.
Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
---
drivers/devfreq/Makefile | 2 +-
drivers/devfreq/imx-ddrc.c | 374 +++++++++++++++++++++++++++++++++++++
2 files changed, 375 insertions(+), 1 deletion(-)
create mode 100644 drivers/devfreq/imx-ddrc.c
diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
index c2463ed4c934..eba138914c74 100644
--- a/drivers/devfreq/Makefile
+++ b/drivers/devfreq/Makefile
@@ -7,11 +7,11 @@ obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE) += governor_powersave.o
obj-$(CONFIG_DEVFREQ_GOV_USERSPACE) += governor_userspace.o
obj-$(CONFIG_DEVFREQ_GOV_PASSIVE) += governor_passive.o
# DEVFREQ Drivers
obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ) += exynos-bus.o
-obj-$(CONFIG_ARM_IMX_DEVFREQ) += imx-devfreq.o
+obj-$(CONFIG_ARM_IMX_DEVFREQ) += imx-devfreq.o imx-ddrc.o
obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o
obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra30-devfreq.o
obj-$(CONFIG_ARM_TEGRA20_DEVFREQ) += tegra20-devfreq.o
# DEVFREQ Event Drivers
diff --git a/drivers/devfreq/imx-ddrc.c b/drivers/devfreq/imx-ddrc.c
new file mode 100644
index 000000000000..253138f608e7
--- /dev/null
+++ b/drivers/devfreq/imx-ddrc.c
@@ -0,0 +1,374 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/devfreq.h>
+#include <linux/pm_opp.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/arm-smccc.h>
+
+#define IMX_SIP_DDR_DVFS 0xc2000004
+
+/* Values starting from 0 switch to specific frequency */
+#define IMX_SIP_DDR_FREQ_SET_HIGH 0x00
+
+/* Deprecated after moving IRQ handling to ATF */
+#define IMX_SIP_DDR_DVFS_WAIT_CHANGE 0x0F
+
+/* Query available frequencies. */
+#define IMX_SIP_DDR_DVFS_GET_FREQ_COUNT 0x10
+#define IMX_SIP_DDR_DVFS_GET_FREQ_INFO 0x11
+
+/*
+ * This should be in a 1:1 mapping with devicetree OPPs but
+ * firmware provides additional info.
+ */
+struct imx_ddrc_freq {
+ unsigned long rate;
+ unsigned long smcarg;
+ int dram_core_parent_index;
+ int dram_alt_parent_index;
+ int dram_apb_parent_index;
+};
+
+/* Hardware limitation */
+#define IMX_DDRC_MAX_FREQ_COUNT 4
+
+/*
+ * imx DRAM controller
+ *
+ * imx DRAM controller clocks have the following structure (abridged):
+ *
+ * +----------+ |\ +------+
+ * | dram_pll |-------|M| dram_core | |
+ * +----------+ |U|---------->| D |
+ * /--|X| | D |
+ * dram_alt_root | |/ | R |
+ * | | C |
+ * +---------+ | |
+ * |FIX DIV/4| | |
+ * +---------+ | |
+ * composite: | | |
+ * +----------+ | | |
+ * | dram_alt |----/ | |
+ * +----------+ | |
+ * | dram_apb |-------------------->| |
+ * +----------+ +------+
+ *
+ * The dram_pll is used for higher rates and dram_alt is used for lower rates.
+ *
+ * Frequency switching is implemented in TF-A (via SMC call) and can change the
+ * configuration of the clocks, including mux parents. The dram_alt and
+ * dram_apb clocks are "imx composite" and their parent can change too.
+ *
+ * We need to prepare/enable the new mux parents head of switching and update
+ * their information afterwards.
+ */
+struct imx_ddrc {
+ struct devfreq_dev_profile profile;
+ struct devfreq *devfreq;
+
+ /* For frequency switching: */
+ struct clk *dram_core;
+ struct clk *dram_pll;
+ struct clk *dram_alt;
+ struct clk *dram_apb;
+
+ int freq_count;
+ struct imx_ddrc_freq freq_table[IMX_DDRC_MAX_FREQ_COUNT];
+};
+
+static struct imx_ddrc_freq *imx_ddrc_find_freq(struct imx_ddrc *priv,
+ unsigned long rate)
+{
+ int i;
+
+ for (i = 0; i < priv->freq_count; ++i)
+ if (priv->freq_table[i].rate == rate)
+ return &priv->freq_table[i];
+
+ return NULL;
+}
+
+static void imx_ddrc_smc_set_freq(int target_freq)
+{
+ struct arm_smccc_res res;
+ u32 online_cpus = 0;
+ int cpu;
+
+ local_irq_disable();
+
+ for_each_online_cpu(cpu)
+ online_cpus |= (1 << (cpu * 8));
+
+ /* change the ddr freqency */
+ arm_smccc_smc(IMX_SIP_DDR_DVFS, target_freq, online_cpus,
+ 0, 0, 0, 0, 0, &res);
+
+ local_irq_enable();
+}
+
+struct clk *clk_get_parent_by_index(struct clk *clk, int index)
+{
+ struct clk_hw *hw;
+
+ hw = clk_hw_get_parent_by_index(__clk_get_hw(clk), index);
+
+ return hw ? hw->clk : NULL;
+}
+
+static int imx_ddrc_set_freq(struct device *dev, struct imx_ddrc_freq *freq)
+{
+ struct imx_ddrc *priv = dev_get_drvdata(dev);
+ struct clk *new_dram_core_parent;
+ struct clk *new_dram_alt_parent;
+ struct clk *new_dram_apb_parent;
+ int ret;
+
+ new_dram_core_parent = clk_get_parent_by_index(
+ priv->dram_core, freq->dram_core_parent_index - 1);
+ new_dram_alt_parent = clk_get_parent_by_index(
+ priv->dram_alt, freq->dram_alt_parent_index - 1);
+ new_dram_apb_parent = clk_get_parent_by_index(
+ priv->dram_apb, freq->dram_apb_parent_index - 1);
+
+ /* increase reference counts and ensure clks are ON before switch */
+ ret = clk_prepare_enable(new_dram_core_parent);
+ if (ret) {
+ dev_err(dev, "failed enable new dram_core parent: %d\n", ret);
+ goto out;
+ }
+ ret = clk_prepare_enable(new_dram_alt_parent);
+ if (ret) {
+ dev_err(dev, "failed enable new dram_alt parent: %d\n", ret);
+ goto out_dis_core;
+ }
+ ret = clk_prepare_enable(new_dram_apb_parent);
+ if (ret) {
+ dev_err(dev, "failed enable new dram_apb parent: %d\n", ret);
+ goto out_dis_alt;
+ }
+
+ imx_ddrc_smc_set_freq(freq->smcarg);
+
+ /* update parents in clk tree after switch. */
+ ret = clk_set_parent(priv->dram_core, new_dram_core_parent);
+ if (ret)
+ dev_err(dev, "failed set dram_core parent: %d\n", ret);
+ if (new_dram_alt_parent) {
+ ret = clk_set_parent(priv->dram_alt, new_dram_alt_parent);
+ if (ret)
+ dev_err(dev, "failed set dram_alt parent: %d\n", ret);
+ }
+ if (new_dram_apb_parent) {
+ ret = clk_set_parent(priv->dram_apb, new_dram_apb_parent);
+ if (ret)
+ dev_err(dev, "failed set dram_apb parent: %d\n", ret);
+ }
+
+ /*
+ * clk_set_parent transfer the reference count from old parent.
+ * now we drop extra reference counts used during the switch
+ */
+ clk_disable_unprepare(new_dram_apb_parent);
+out_dis_alt:
+ clk_disable_unprepare(new_dram_alt_parent);
+out_dis_core:
+ clk_disable_unprepare(new_dram_core_parent);
+out:
+ return ret;
+}
+
+static int imx_ddrc_target(struct device *dev, unsigned long *freq, u32 flags)
+{
+ struct imx_ddrc *priv = dev_get_drvdata(dev);
+ struct imx_ddrc_freq *freq_info;
+ struct dev_pm_opp *new_opp;
+ unsigned long new_freq, cur_freq;
+ int ret;
+
+ new_opp = devfreq_recommended_opp(dev, freq, flags);
+ if (IS_ERR(new_opp)) {
+ ret = PTR_ERR(new_opp);
+ dev_err(dev, "failed to get recommended opp: %d\n", ret);
+ return ret;
+ }
+ new_freq = dev_pm_opp_get_freq(new_opp);
+ dev_pm_opp_put(new_opp);
+ cur_freq = clk_get_rate(priv->dram_core);
+
+ if (new_freq == cur_freq)
+ return 0;
+
+ freq_info = imx_ddrc_find_freq(priv, new_freq);
+ if (!freq_info)
+ return -EINVAL;
+ ret = imx_ddrc_set_freq(dev, freq_info);
+ if (ret)
+ dev_err(dev, "ddrc failed to change freq %lu to %lu\n",
+ cur_freq, new_freq);
+ else
+ dev_dbg(dev, "ddrc changed freq %lu to %lu\n",
+ cur_freq, new_freq);
+
+ return ret;
+}
+
+static int imx_ddrc_get_cur_freq(struct device *dev, unsigned long *freq)
+{
+ struct imx_ddrc *priv = dev_get_drvdata(dev);
+
+ *freq = clk_get_rate(priv->dram_core);
+
+ return 0;
+}
+
+static int imx_ddrc_get_dev_status(struct device *dev,
+ struct devfreq_dev_status *stat)
+{
+ struct imx_ddrc *priv = dev_get_drvdata(dev);
+
+ stat->busy_time = 0;
+ stat->total_time = 0;
+ stat->current_frequency = clk_get_rate(priv->dram_core);
+
+ return 0;
+}
+
+static int imx_ddrc_init_freq_info(struct device *dev)
+{
+ struct imx_ddrc *priv = dev_get_drvdata(dev);
+ struct arm_smccc_res res;
+ int index;
+
+ /*
+ * An error here means DDR DVFS API not supported by firmware
+ */
+ arm_smccc_smc(IMX_SIP_DDR_DVFS, IMX_SIP_DDR_DVFS_GET_FREQ_COUNT,
+ 0, 0, 0, 0, 0, 0, &res);
+ priv->freq_count = res.a0;
+ if (priv->freq_count <= 0 || priv->freq_count > IMX_DDRC_MAX_FREQ_COUNT)
+ return -ENODEV;
+
+ for (index = 0; index < priv->freq_count; ++index) {
+ struct imx_ddrc_freq *freq = &priv->freq_table[index];
+
+ arm_smccc_smc(IMX_SIP_DDR_DVFS, IMX_SIP_DDR_DVFS_GET_FREQ_INFO,
+ index, 0, 0, 0, 0, 0, &res);
+ /* Result should be strictly positive */
+ if ((long)res.a0 <= 0)
+ return -ENODEV;
+
+ freq->rate = res.a0 * 250000;
+ freq->smcarg = index;
+ freq->dram_core_parent_index = res.a1;
+ freq->dram_alt_parent_index = res.a2;
+ freq->dram_apb_parent_index = res.a3;
+
+ /* dram_core has 2 options: dram_pll or dram_alt_root */
+ if (freq->dram_core_parent_index != 1 &&
+ freq->dram_core_parent_index != 2)
+ return -ENODEV;
+ /* dram_apb and dram_alt have exactly 8 possible parents */
+ if (freq->dram_alt_parent_index > 8 ||
+ freq->dram_apb_parent_index > 8)
+ return -ENODEV;
+ /* dram_core from alt requires explicit dram_alt parent */
+ if (freq->dram_core_parent_index == 2 &&
+ freq->dram_alt_parent_index == 0)
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void imx_ddrc_exit(struct device *dev)
+{
+ dev_pm_opp_of_remove_table(dev);
+}
+
+static int imx_ddrc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct imx_ddrc *priv;
+ struct device_node *events_node;
+ const char *gov = DEVFREQ_GOV_USERSPACE;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, priv);
+
+ ret = imx_ddrc_init_freq_info(dev);
+ if (ret) {
+ dev_err(dev, "failed to init firmware freq info: %d\n", ret);
+ return ret;
+ }
+
+ priv->dram_core = devm_clk_get(dev, "dram_core");
+ priv->dram_pll = devm_clk_get(dev, "dram_pll");
+ priv->dram_alt = devm_clk_get(dev, "dram_alt");
+ priv->dram_apb = devm_clk_get(dev, "dram_apb");
+ if (IS_ERR(priv->dram_core) ||
+ IS_ERR(priv->dram_pll) ||
+ IS_ERR(priv->dram_alt) ||
+ IS_ERR(priv->dram_apb)) {
+ ret = PTR_ERR(priv->devfreq);
+ dev_err(dev, "failed to fetch clocks: %d\n", ret);
+ return ret;
+ }
+
+ ret = dev_pm_opp_of_add_table(dev);
+ if (ret < 0) {
+ dev_err(dev, "failed to get OPP table\n");
+ return ret;
+ }
+
+ priv->profile.polling_ms = 1000;
+ priv->profile.target = imx_ddrc_target;
+ priv->profile.get_dev_status = imx_ddrc_get_dev_status;
+ priv->profile.exit = imx_ddrc_exit;
+ priv->profile.get_cur_freq = imx_ddrc_get_cur_freq;
+ priv->profile.initial_freq = clk_get_rate(priv->dram_core);
+
+ priv->devfreq = devm_devfreq_add_device(dev, &priv->profile,
+ gov, NULL);
+ if (IS_ERR(priv->devfreq)) {
+ ret = PTR_ERR(priv->devfreq);
+ dev_err(dev, "failed to add devfreq device: %d\n", ret);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ dev_pm_opp_of_remove_table(dev);
+ return ret;
+}
+
+static const struct of_device_id imx_ddrc_of_match[] = {
+ { .compatible = "fsl,imx8m-ddrc", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, imx_ddrc_of_match);
+
+static struct platform_driver imx_ddrc_platdrv = {
+ .probe = imx_ddrc_probe,
+ .driver = {
+ .name = "imx-ddrc-devfreq",
+ .of_match_table = of_match_ptr(imx_ddrc_of_match),
+ },
+};
+module_platform_driver(imx_ddrc_platdrv);
+
+MODULE_DESCRIPTION("i.MX DDR controller frequency driver");
+MODULE_AUTHOR("Leonard Crestez <leonard.crestez@nxp.com>");
+MODULE_LICENSE("GPL v2");
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 6/7] PM / devfreq: imx-ddrc: Measure bandwidth with perf
From: Leonard Crestez @ 2019-08-20 15:45 UTC (permalink / raw)
To: Stephen Boyd, Shawn Guo, MyungJoo Ham, Chanwoo Choi, Rob Herring
Cc: Mark Rutland, Artur Świgoń, Abel Vesa, Saravana Kannan,
Anson Huang, linux-arm-kernel, Viresh Kumar, Michael Turquette,
linux-pm, linux-imx, Krzysztof Kozlowski, linux-clk,
Kyungmin Park, Alexandre Bailon, kernel, Dong Aisheng,
Fabio Estevam, Georgi Djakov, devicetree, Jacky Bai
In-Reply-To: <cover.1566315740.git.leonard.crestez@nxp.com>
The imx8m ddrc has a performance monitoring block attached which can
be used to measure bandwidth usage and automatically adjust frequency.
There is already a perf driver for that block so instead of implementing
a devfreq events driver use the in-kernel perf API to implement
get_dev_status directly.
Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
---
drivers/devfreq/imx-ddrc.c | 146 ++++++++++++++++++++++++++++++++++++-
1 file changed, 143 insertions(+), 3 deletions(-)
diff --git a/drivers/devfreq/imx-ddrc.c b/drivers/devfreq/imx-ddrc.c
index 253138f608e7..f9a11a1825ea 100644
--- a/drivers/devfreq/imx-ddrc.c
+++ b/drivers/devfreq/imx-ddrc.c
@@ -11,10 +11,13 @@
#include <linux/pm_opp.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/arm-smccc.h>
+#include <asm/perf_event.h>
+#include <linux/perf_event.h>
+
#define IMX_SIP_DDR_DVFS 0xc2000004
/* Values starting from 0 switch to specific frequency */
#define IMX_SIP_DDR_FREQ_SET_HIGH 0x00
@@ -80,10 +83,22 @@ struct imx_ddrc {
struct clk *dram_alt;
struct clk *dram_apb;
int freq_count;
struct imx_ddrc_freq freq_table[IMX_DDRC_MAX_FREQ_COUNT];
+
+ /* For measuring load with perf events: */
+ struct platform_device *pmu_pdev;
+ struct pmu *pmu;
+
+ struct perf_event_attr rd_event_attr;
+ struct perf_event_attr wr_event_attr;
+ struct perf_event *rd_event;
+ struct perf_event *wr_event;
+
+ u64 last_rd_val, last_rd_ena, last_rd_run;
+ u64 last_wr_val, last_wr_ena, last_wr_run;
};
static struct imx_ddrc_freq *imx_ddrc_find_freq(struct imx_ddrc *priv,
unsigned long rate)
{
@@ -228,19 +243,127 @@ static int imx_ddrc_get_cur_freq(struct device *dev, unsigned long *freq)
return 0;
}
static int imx_ddrc_get_dev_status(struct device *dev,
- struct devfreq_dev_status *stat)
+ struct devfreq_dev_status *stat)
{
struct imx_ddrc *priv = dev_get_drvdata(dev);
- stat->busy_time = 0;
- stat->total_time = 0;
stat->current_frequency = clk_get_rate(priv->dram_core);
+ if (priv->rd_event && priv->wr_event) {
+ u64 rd_delta, rd_val, rd_ena, rd_run;
+ u64 wr_delta, wr_val, wr_ena, wr_run;
+
+ rd_val = perf_event_read_value(priv->rd_event,
+ &rd_ena, &rd_run);
+ wr_val = perf_event_read_value(priv->wr_event,
+ &wr_ena, &wr_run);
+
+ rd_delta = (rd_val - priv->last_rd_val) *
+ (rd_ena - priv->last_rd_ena) /
+ (rd_run - priv->last_rd_run);
+ priv->last_rd_val = rd_val;
+ priv->last_rd_ena = rd_ena;
+ priv->last_rd_run = rd_run;
+ wr_delta = (wr_val - priv->last_wr_val) *
+ (wr_ena - priv->last_wr_ena) /
+ (wr_run - priv->last_wr_run);
+ priv->last_wr_val = wr_val;
+ priv->last_wr_ena = wr_ena;
+ priv->last_wr_run = wr_run;
+
+ /* magic numbers, possibly wrong */
+ stat->busy_time = 4 * (rd_delta + wr_delta);
+ stat->total_time = stat->current_frequency;
+ } else {
+ stat->busy_time = 0;
+ stat->total_time = 0;
+ }
+
+ return 0;
+}
+
+static int imx_ddrc_perf_disable(struct imx_ddrc *priv)
+{
+ /* release and set to NULL */
+ if (!IS_ERR_OR_NULL(priv->rd_event))
+ perf_event_release_kernel(priv->rd_event);
+ if (!IS_ERR_OR_NULL(priv->wr_event))
+ perf_event_release_kernel(priv->wr_event);
+ priv->rd_event = NULL;
+ priv->wr_event = NULL;
+
+ return 0;
+}
+
+static int imx_ddrc_perf_enable(struct imx_ddrc *priv)
+{
+ int ret;
+
+ priv->rd_event_attr.size = sizeof(priv->rd_event_attr);
+ priv->rd_event_attr.type = priv->pmu->type;
+ priv->rd_event_attr.config = 0x2a;
+
+ priv->rd_event = perf_event_create_kernel_counter(
+ &priv->rd_event_attr, 0, NULL, NULL, NULL);
+ if (IS_ERR(priv->rd_event)) {
+ ret = PTR_ERR(priv->rd_event);
+ goto err;
+ }
+
+ priv->wr_event_attr.size = sizeof(priv->wr_event_attr);
+ priv->wr_event_attr.type = priv->pmu->type;
+ priv->wr_event_attr.config = 0x2b;
+
+ priv->wr_event = perf_event_create_kernel_counter(
+ &priv->wr_event_attr, 0, NULL, NULL, NULL);
+ if (IS_ERR(priv->wr_event)) {
+ ret = PTR_ERR(priv->wr_event);
+ goto err;
+ }
+
return 0;
+
+err:
+ imx_ddrc_perf_disable(priv);
+ return ret;
+}
+
+static int imx_ddrc_init_events(struct device *dev,
+ struct device_node *events_node)
+{
+ struct imx_ddrc *priv = dev_get_drvdata(dev);
+ struct device_driver *driver;
+
+ /*
+ * We need pmu->type for perf_event_attr but there is no API for
+ * mapping device_node to pmu. Fetch private data for imx-ddr-pmu and
+ * cast that to a struct pmu instead.
+ */
+ priv->pmu_pdev = of_find_device_by_node(events_node);
+ if (!priv->pmu_pdev)
+ return -EPROBE_DEFER;
+ driver = priv->pmu_pdev->dev.driver;
+ if (!driver)
+ return -EPROBE_DEFER;
+ if (strcmp(driver->name, "imx-ddr-pmu")) {
+ dev_warn(dev, "devfreq-events node %pOF has unexpected driver %s\n",
+ events_node, driver->name);
+ return -ENODEV;
+ }
+
+ priv->pmu = platform_get_drvdata(priv->pmu_pdev);
+ if (!priv->pmu) {
+ dev_err(dev, "devfreq-events device missing private data\n");
+ return -EINVAL;
+ }
+
+ dev_dbg(dev, "events from pmu %s\n", priv->pmu->name);
+
+ return imx_ddrc_perf_enable(priv);
}
static int imx_ddrc_init_freq_info(struct device *dev)
{
struct imx_ddrc *priv = dev_get_drvdata(dev);
@@ -288,10 +411,15 @@ static int imx_ddrc_init_freq_info(struct device *dev)
return 0;
}
static void imx_ddrc_exit(struct device *dev)
{
+ struct imx_ddrc *priv = dev_get_drvdata(dev);
+
+ imx_ddrc_perf_disable(priv);
+ platform_device_put(priv->pmu_pdev);
+
dev_pm_opp_of_remove_table(dev);
}
static int imx_ddrc_probe(struct platform_device *pdev)
{
@@ -337,10 +465,20 @@ static int imx_ddrc_probe(struct platform_device *pdev)
priv->profile.get_dev_status = imx_ddrc_get_dev_status;
priv->profile.exit = imx_ddrc_exit;
priv->profile.get_cur_freq = imx_ddrc_get_cur_freq;
priv->profile.initial_freq = clk_get_rate(priv->dram_core);
+ /* Handle devfreq-events */
+ events_node = of_parse_phandle(dev->of_node, "devfreq-events", 0);
+ if (events_node) {
+ ret = imx_ddrc_init_events(dev, events_node);
+ of_node_put(events_node);
+ if (ret)
+ goto err;
+ gov = DEVFREQ_GOV_SIMPLE_ONDEMAND;
+ }
+
priv->devfreq = devm_devfreq_add_device(dev, &priv->profile,
gov, NULL);
if (IS_ERR(priv->devfreq)) {
ret = PTR_ERR(priv->devfreq);
dev_err(dev, "failed to add devfreq device: %d\n", ret);
@@ -348,10 +486,12 @@ static int imx_ddrc_probe(struct platform_device *pdev)
}
return 0;
err:
+ imx_ddrc_perf_disable(priv);
+ platform_device_put(priv->pmu_pdev);
dev_pm_opp_of_remove_table(dev);
return ret;
}
static const struct of_device_id imx_ddrc_of_match[] = {
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 4/7] dt-bindings: devfreq: Add bindings for imx ddr controller
From: Leonard Crestez @ 2019-08-20 15:45 UTC (permalink / raw)
To: Stephen Boyd, Shawn Guo, MyungJoo Ham, Chanwoo Choi, Rob Herring
Cc: Mark Rutland, Artur Świgoń, Abel Vesa, Saravana Kannan,
Anson Huang, linux-arm-kernel, Viresh Kumar, Michael Turquette,
linux-pm, linux-imx, Krzysztof Kozlowski, linux-clk,
Kyungmin Park, Alexandre Bailon, kernel, Dong Aisheng,
Fabio Estevam, Georgi Djakov, devicetree, Jacky Bai
In-Reply-To: <cover.1566315740.git.leonard.crestez@nxp.com>
Add devicetree bindings for the i.MX DDR Controller on imx8m series
chips. It supports dynamic frequency switching between multiple data
rates and this is exposed to Linux via the devfreq subsystem.
Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
---
.../devicetree/bindings/devfreq/imx-ddrc.yaml | 60 +++++++++++++++++++
1 file changed, 60 insertions(+)
create mode 100644 Documentation/devicetree/bindings/devfreq/imx-ddrc.yaml
diff --git a/Documentation/devicetree/bindings/devfreq/imx-ddrc.yaml b/Documentation/devicetree/bindings/devfreq/imx-ddrc.yaml
new file mode 100644
index 000000000000..31db204e6845
--- /dev/null
+++ b/Documentation/devicetree/bindings/devfreq/imx-ddrc.yaml
@@ -0,0 +1,60 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/devfreq/imx-devfreq.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: i.MX DDR Controller
+
+maintainers:
+ - Leonard Crestez <leonard.crestez@nxp.com>
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - fsl,imx8mn-ddrc
+ - fsl,imx8mm-ddrc
+ - fsl,imx8mq-ddrc
+ - const: fsl,imx8m-ddrc
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 4
+
+ clock-names:
+ items:
+ - const: dram_core
+ - const: dram_pll
+ - const: dram_alt
+ - const: dram_apb
+
+ operating-points-v2: true
+
+ devfreq-events:
+ description: Phandle of PMU node
+ $ref: "/schemas/types.yaml#/definitions/phandle"
+
+required:
+ - reg
+ - compatible
+ - clocks
+ - clock-names
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/imx8mm-clock.h>
+ ddrc: dram-controller@3d400000 {
+ compatible = "fsl,imx8mm-ddrc", "fsl,imx8m-ddrc";
+ reg = <0x3d400000 0x400000>;
+ clock-names = "dram_core", "dram_pll", "dram_alt", "dram_apb";
+ clocks = <&clk IMX8MM_CLK_DRAM_CORE>,
+ <&clk IMX8MM_DRAM_PLL>,
+ <&clk IMX8MM_CLK_DRAM_ALT>,
+ <&clk IMX8MM_CLK_DRAM_APB>;
+ operating-points-v2 = <&ddrc_opp_table>;
+ };
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 3/7] PM / devfreq: Add generic imx bus driver
From: Leonard Crestez @ 2019-08-20 15:45 UTC (permalink / raw)
To: Stephen Boyd, Shawn Guo, MyungJoo Ham, Chanwoo Choi, Rob Herring
Cc: Mark Rutland, Artur Świgoń, Abel Vesa, Saravana Kannan,
Anson Huang, linux-arm-kernel, Viresh Kumar, Michael Turquette,
linux-pm, linux-imx, Krzysztof Kozlowski, linux-clk,
Kyungmin Park, Alexandre Bailon, kernel, Dong Aisheng,
Fabio Estevam, Georgi Djakov, devicetree, Jacky Bai
In-Reply-To: <cover.1566315740.git.leonard.crestez@nxp.com>
Add initial support for dynamic frequency switching on pieces of the imx
interconnect fabric.
All this driver actually does is set a clk rate based on an opp table.
No attempt is made to map registers or anything clever.
Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
---
drivers/devfreq/Kconfig | 12 +++
drivers/devfreq/Makefile | 1 +
drivers/devfreq/imx-devfreq.c | 148 ++++++++++++++++++++++++++++++++++
3 files changed, 161 insertions(+)
create mode 100644 drivers/devfreq/imx-devfreq.c
diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
index defe1d438710..9088a151bafe 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -90,10 +90,22 @@ config ARM_EXYNOS_BUS_DEVFREQ
Each memory bus group could contain many memoby bus block. It reads
PPMU counters of memory controllers by using DEVFREQ-event device
and adjusts the operating frequencies and voltages with OPP support.
This does not yet operate with optimal voltages.
+config ARM_IMX_DEVFREQ
+ tristate "i.MX DEVFREQ Driver"
+ depends on ARCH_MXC || COMPILE_TEST
+ select DEVFREQ_GOV_PASSIVE
+ select DEVFREQ_GOV_SIMPLE_ONDEMAND
+ select DEVFREQ_GOV_USERSPACE
+ select PM_OPP
+ help
+ This adds the DEVFREQ driver for the i.MX family of SoCs.
+ It allows adjusting frequencies for DDRC (DDR Controller) and various
+ NICs and NOCs which form the SOC interconnect fabric
+
config ARM_TEGRA_DEVFREQ
tristate "NVIDIA Tegra30/114/124/210 DEVFREQ Driver"
depends on ARCH_TEGRA_3x_SOC || ARCH_TEGRA_114_SOC || \
ARCH_TEGRA_132_SOC || ARCH_TEGRA_124_SOC || \
ARCH_TEGRA_210_SOC || \
diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
index 338ae8440db6..c2463ed4c934 100644
--- a/drivers/devfreq/Makefile
+++ b/drivers/devfreq/Makefile
@@ -7,10 +7,11 @@ obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE) += governor_powersave.o
obj-$(CONFIG_DEVFREQ_GOV_USERSPACE) += governor_userspace.o
obj-$(CONFIG_DEVFREQ_GOV_PASSIVE) += governor_passive.o
# DEVFREQ Drivers
obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ) += exynos-bus.o
+obj-$(CONFIG_ARM_IMX_DEVFREQ) += imx-devfreq.o
obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o
obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra30-devfreq.o
obj-$(CONFIG_ARM_TEGRA20_DEVFREQ) += tegra20-devfreq.o
# DEVFREQ Event Drivers
diff --git a/drivers/devfreq/imx-devfreq.c b/drivers/devfreq/imx-devfreq.c
new file mode 100644
index 000000000000..5c907b3ab9c0
--- /dev/null
+++ b/drivers/devfreq/imx-devfreq.c
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <linux/clk.h>
+#include <linux/devfreq.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_opp.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+struct imx_devfreq {
+ struct devfreq_dev_profile profile;
+ struct devfreq *devfreq;
+ struct clk *clk;
+ struct devfreq_passive_data passive_data;
+};
+
+static int imx_devfreq_target(struct device *dev, unsigned long *freq, u32 flags)
+{
+ struct imx_devfreq *priv = dev_get_drvdata(dev);
+ struct dev_pm_opp *new_opp;
+ unsigned long new_freq;
+ int ret;
+
+ new_opp = devfreq_recommended_opp(dev, freq, flags);
+ if (IS_ERR(new_opp)) {
+ ret = PTR_ERR(new_opp);
+ dev_err(dev, "failed to get recommended opp: %d\n", ret);
+ return ret;
+ }
+ new_freq = dev_pm_opp_get_freq(new_opp);
+ dev_pm_opp_put(new_opp);
+
+ return clk_set_rate(priv->clk, new_freq);
+}
+
+static int imx_devfreq_get_cur_freq(struct device *dev, unsigned long *freq)
+{
+ struct imx_devfreq *priv = dev_get_drvdata(dev);
+
+ *freq = clk_get_rate(priv->clk);
+
+ return 0;
+}
+
+static int imx_devfreq_get_dev_status(struct device *dev,
+ struct devfreq_dev_status *stat)
+{
+ struct imx_devfreq *priv = dev_get_drvdata(dev);
+
+ stat->busy_time = 0;
+ stat->total_time = 0;
+ stat->current_frequency = clk_get_rate(priv->clk);
+
+ return 0;
+}
+
+static void imx_devfreq_exit(struct device *dev)
+{
+ dev_pm_opp_of_remove_table(dev);
+}
+
+static int imx_devfreq_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct imx_devfreq *priv;
+ const char *gov = DEVFREQ_GOV_USERSPACE;
+ void *govdata = NULL;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ ret = PTR_ERR(priv->clk);
+ dev_err(dev, "failed to fetch clk: %d\n", ret);
+ return ret;
+ }
+ platform_set_drvdata(pdev, priv);
+
+ ret = dev_pm_opp_of_add_table(dev);
+ if (ret < 0) {
+ dev_err(dev, "failed to get OPP table\n");
+ return ret;
+ }
+
+ priv->profile.polling_ms = 1000;
+ priv->profile.target = imx_devfreq_target;
+ priv->profile.get_dev_status = imx_devfreq_get_dev_status;
+ priv->profile.exit = imx_devfreq_exit;
+ priv->profile.get_cur_freq = imx_devfreq_get_cur_freq;
+ priv->profile.initial_freq = clk_get_rate(priv->clk);
+
+ /* Handle passive devfreq parent link */
+ priv->passive_data.parent = devfreq_get_devfreq_by_phandle(dev, 0);
+ if (!IS_ERR(priv->passive_data.parent)) {
+ dev_info(dev, "passive link to %s\n",
+ dev_name(priv->passive_data.parent->dev.parent));
+ gov = DEVFREQ_GOV_PASSIVE;
+ govdata = &priv->passive_data;
+ } else if (priv->passive_data.parent != ERR_PTR(-ENODEV)) {
+ // -ENODEV means no parent: not an error.
+ ret = PTR_ERR(priv->passive_data.parent);
+ if (ret != -EPROBE_DEFER)
+ dev_warn(dev, "failed to get passive parent: %d\n", ret);
+ goto err;
+ }
+
+ priv->devfreq = devm_devfreq_add_device(dev, &priv->profile,
+ gov, govdata);
+ if (IS_ERR(priv->devfreq)) {
+ ret = PTR_ERR(priv->devfreq);
+ dev_err(dev, "failed to add devfreq device: %d\n", ret);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ dev_pm_opp_of_remove_table(dev);
+ return ret;
+}
+
+static const struct of_device_id imx_devfreq_of_match[] = {
+ { .compatible = "fsl,imx8m-noc", },
+ { .compatible = "fsl,imx8m-nic", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, imx_devfreq_of_match);
+
+static struct platform_driver imx_devfreq_platdrv = {
+ .probe = imx_devfreq_probe,
+ .driver = {
+ .name = "imx-devfreq",
+ .of_match_table = of_match_ptr(imx_devfreq_of_match),
+ },
+};
+module_platform_driver(imx_devfreq_platdrv);
+
+MODULE_DESCRIPTION("Generic i.MX bus frequency driver");
+MODULE_AUTHOR("Leonard Crestez <leonard.crestez@nxp.com>");
+MODULE_LICENSE("GPL v2");
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 2/7] dt-bindings: devfreq: Add bindings for generic imx buses
From: Leonard Crestez @ 2019-08-20 15:45 UTC (permalink / raw)
To: Stephen Boyd, Shawn Guo, MyungJoo Ham, Chanwoo Choi, Rob Herring
Cc: Mark Rutland, Artur Świgoń, Abel Vesa, Saravana Kannan,
Anson Huang, linux-arm-kernel, Viresh Kumar, Michael Turquette,
linux-pm, linux-imx, Krzysztof Kozlowski, linux-clk,
Kyungmin Park, Alexandre Bailon, kernel, Dong Aisheng,
Fabio Estevam, Georgi Djakov, devicetree, Jacky Bai
In-Reply-To: <cover.1566315740.git.leonard.crestez@nxp.com>
Add initial dt bindings for the interconnects inside i.MX chips.
Multiple external IPs are involved but SOC integration means the
software controllable interfaces are very similar.
This is initially only for imx8mm but add an "fsl,imx8m-nic" fallback
similar to exynos-bus.
Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
Acked-by: MyungJoo Ham <myungjoo.ham@samsung.com>
---
.../devicetree/bindings/devfreq/imx.yaml | 68 +++++++++++++++++++
1 file changed, 68 insertions(+)
create mode 100644 Documentation/devicetree/bindings/devfreq/imx.yaml
diff --git a/Documentation/devicetree/bindings/devfreq/imx.yaml b/Documentation/devicetree/bindings/devfreq/imx.yaml
new file mode 100644
index 000000000000..634870496d5e
--- /dev/null
+++ b/Documentation/devicetree/bindings/devfreq/imx.yaml
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/devfreq/imx.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Generic i.MX bus frequency device
+
+maintainers:
+ - Leonard Crestez <leonard.crestez@nxp.com>
+
+description: |
+ The i.MX SoC family has multiple buses for which clock frequency (and sometimes
+ voltage) can be adjusted.
+
+ Some of those buses expose register areas mentioned in the memory maps as GPV
+ ("Global Programmers View") but not all. Access to this area might be denied for
+ normal world.
+
+ The buses are based on externally licensed IPs such as ARM NIC-301 and Arteris
+ FlexNOC but DT bindings are specific to the integration of these bus
+ interconnect IPs into imx SOCs.
+
+properties:
+ compatible:
+ oneOf:
+ - items:
+ - enum:
+ - fsl,imx8mn-nic
+ - fsl,imx8mm-nic
+ - fsl,imx8mq-nic
+ - const: fsl,imx8m-nic
+ - items:
+ - enum:
+ - fsl,imx8mn-noc
+ - fsl,imx8mm-noc
+ - fsl,imx8mq-noc
+ - const: fsl,imx8m-noc
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ operating-points-v2: true
+
+ devfreq:
+ description: |
+ Phandle to another devfreq device to match OPPs with by using the
+ passive governor.
+ $ref: "/schemas/types.yaml#/definitions/phandle"
+
+required:
+ - compatible
+ - clocks
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/imx8mm-clock.h>
+ noc: noc@32700000 {
+ compatible = "fsl,imx8mm-noc", "fsl,imx8m-noc";
+ reg = <0x32700000 0x100000>;
+ clocks = <&clk IMX8MM_CLK_NOC>;
+ operating-points-v2 = <&noc_opp_table>;
+ };
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 1/7] clk: imx8m: Set CLK_GET_RATE_NOCACHE on dram_alt/apb
From: Leonard Crestez @ 2019-08-20 15:45 UTC (permalink / raw)
To: Stephen Boyd, Shawn Guo, MyungJoo Ham, Chanwoo Choi, Rob Herring
Cc: Mark Rutland, Artur Świgoń, Abel Vesa, Saravana Kannan,
Anson Huang, linux-arm-kernel, Viresh Kumar, Michael Turquette,
linux-pm, linux-imx, Krzysztof Kozlowski, linux-clk,
Kyungmin Park, Alexandre Bailon, kernel, Dong Aisheng,
Fabio Estevam, Georgi Djakov, devicetree, Jacky Bai
In-Reply-To: <cover.1566315740.git.leonard.crestez@nxp.com>
Dram frequency changes required modifying these clocks outside the
control of clk framework. Mark them as CLK_GET_RATE_NOCACHE so that
rates are always read back from registers.
Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
---
drivers/clk/imx/clk-imx8mm.c | 6 ++++--
drivers/clk/imx/clk-imx8mn.c | 6 ++++--
drivers/clk/imx/clk-imx8mq.c | 7 ++++---
3 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c
index 4ead3ea2713c..6cac80550f43 100644
--- a/drivers/clk/imx/clk-imx8mm.c
+++ b/drivers/clk/imx/clk-imx8mm.c
@@ -526,12 +526,14 @@ static int imx8mm_clocks_probe(struct platform_device *pdev)
/* IPG */
clks[IMX8MM_CLK_IPG_ROOT] = imx_clk_divider2("ipg_root", "ahb", base + 0x9080, 0, 1);
clks[IMX8MM_CLK_IPG_AUDIO_ROOT] = imx_clk_divider2("ipg_audio_root", "audio_ahb", base + 0x9180, 0, 1);
/* IP */
- clks[IMX8MM_CLK_DRAM_ALT] = imx8m_clk_composite("dram_alt", imx8mm_dram_alt_sels, base + 0xa000);
- clks[IMX8MM_CLK_DRAM_APB] = imx8m_clk_composite_critical("dram_apb", imx8mm_dram_apb_sels, base + 0xa080);
+ clks[IMX8MM_CLK_DRAM_ALT] = __imx8m_clk_composite("dram_alt", imx8mm_dram_alt_sels, base + 0xa000,
+ CLK_GET_RATE_NOCACHE);
+ clks[IMX8MM_CLK_DRAM_APB] = __imx8m_clk_composite("dram_apb", imx8mm_dram_apb_sels, base + 0xa080,
+ CLK_IS_CRITICAL | CLK_GET_RATE_NOCACHE);
clks[IMX8MM_CLK_VPU_G1] = imx8m_clk_composite("vpu_g1", imx8mm_vpu_g1_sels, base + 0xa100);
clks[IMX8MM_CLK_VPU_G2] = imx8m_clk_composite("vpu_g2", imx8mm_vpu_g2_sels, base + 0xa180);
clks[IMX8MM_CLK_DISP_DTRC] = imx8m_clk_composite("disp_dtrc", imx8mm_disp_dtrc_sels, base + 0xa200);
clks[IMX8MM_CLK_DISP_DC8000] = imx8m_clk_composite("disp_dc8000", imx8mm_disp_dc8000_sels, base + 0xa280);
clks[IMX8MM_CLK_PCIE1_CTRL] = imx8m_clk_composite("pcie1_ctrl", imx8mm_pcie1_ctrl_sels, base + 0xa300);
diff --git a/drivers/clk/imx/clk-imx8mn.c b/drivers/clk/imx/clk-imx8mn.c
index 4ea341e4e274..39ed8aa90d22 100644
--- a/drivers/clk/imx/clk-imx8mn.c
+++ b/drivers/clk/imx/clk-imx8mn.c
@@ -529,12 +529,14 @@ static int imx8mn_clocks_probe(struct platform_device *pdev)
clks[IMX8MN_CLK_AHB] = imx8m_clk_composite_critical("ahb", imx8mn_ahb_sels, base + 0x9000);
clks[IMX8MN_CLK_AUDIO_AHB] = imx8m_clk_composite("audio_ahb", imx8mn_audio_ahb_sels, base + 0x9100);
clks[IMX8MN_CLK_IPG_ROOT] = imx_clk_divider2("ipg_root", "ahb", base + 0x9080, 0, 1);
clks[IMX8MN_CLK_IPG_AUDIO_ROOT] = imx_clk_divider2("ipg_audio_root", "audio_ahb", base + 0x9180, 0, 1);
clks[IMX8MN_CLK_DRAM_CORE] = imx_clk_mux2_flags("dram_core_clk", base + 0x9800, 24, 1, imx8mn_dram_core_sels, ARRAY_SIZE(imx8mn_dram_core_sels), CLK_IS_CRITICAL);
- clks[IMX8MN_CLK_DRAM_ALT] = imx8m_clk_composite("dram_alt", imx8mn_dram_alt_sels, base + 0xa000);
- clks[IMX8MN_CLK_DRAM_APB] = imx8m_clk_composite_critical("dram_apb", imx8mn_dram_apb_sels, base + 0xa080);
+ clks[IMX8MN_CLK_DRAM_ALT] = __imx8m_clk_composite("dram_alt", imx8mn_dram_alt_sels, base + 0xa000,
+ CLK_GET_RATE_NOCACHE);
+ clks[IMX8MN_CLK_DRAM_APB] = __imx8m_clk_composite("dram_apb", imx8mn_dram_apb_sels, base + 0xa080,
+ CLK_IS_CRITICAL | CLK_GET_RATE_NOCACHE);
clks[IMX8MN_CLK_DISP_PIXEL] = imx8m_clk_composite("disp_pixel", imx8mn_disp_pixel_sels, base + 0xa500);
clks[IMX8MN_CLK_SAI2] = imx8m_clk_composite("sai2", imx8mn_sai2_sels, base + 0xa600);
clks[IMX8MN_CLK_SAI3] = imx8m_clk_composite("sai3", imx8mn_sai3_sels, base + 0xa680);
clks[IMX8MN_CLK_SAI5] = imx8m_clk_composite("sai5", imx8mn_sai5_sels, base + 0xa780);
clks[IMX8MN_CLK_SAI6] = imx8m_clk_composite("sai6", imx8mn_sai6_sels, base + 0xa800);
diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c
index 2350d0d84c37..5573bccb1130 100644
--- a/drivers/clk/imx/clk-imx8mq.c
+++ b/drivers/clk/imx/clk-imx8mq.c
@@ -436,13 +436,14 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
clks[IMX8MQ_CLK_IPG_ROOT] = imx_clk_divider2("ipg_root", "ahb", base + 0x9080, 0, 1);
clks[IMX8MQ_CLK_IPG_AUDIO_ROOT] = imx_clk_divider2("ipg_audio_root", "audio_ahb", base + 0x9180, 0, 1);
/* IP */
clks[IMX8MQ_CLK_DRAM_CORE] = imx_clk_mux2_flags("dram_core_clk", base + 0x9800, 24, 1, imx8mq_dram_core_sels, ARRAY_SIZE(imx8mq_dram_core_sels), CLK_IS_CRITICAL);
-
- clks[IMX8MQ_CLK_DRAM_ALT] = imx8m_clk_composite("dram_alt", imx8mq_dram_alt_sels, base + 0xa000);
- clks[IMX8MQ_CLK_DRAM_APB] = imx8m_clk_composite_critical("dram_apb", imx8mq_dram_apb_sels, base + 0xa080);
+ clks[IMX8MQ_CLK_DRAM_ALT] = __imx8m_clk_composite("dram_alt", imx8mq_dram_alt_sels, base + 0xa000,
+ CLK_GET_RATE_NOCACHE);
+ clks[IMX8MQ_CLK_DRAM_APB] = __imx8m_clk_composite("dram_apb", imx8mq_dram_apb_sels, base + 0xa080,
+ CLK_IS_CRITICAL | CLK_GET_RATE_NOCACHE);
clks[IMX8MQ_CLK_VPU_G1] = imx8m_clk_composite("vpu_g1", imx8mq_vpu_g1_sels, base + 0xa100);
clks[IMX8MQ_CLK_VPU_G2] = imx8m_clk_composite("vpu_g2", imx8mq_vpu_g2_sels, base + 0xa180);
clks[IMX8MQ_CLK_DISP_DTRC] = imx8m_clk_composite("disp_dtrc", imx8mq_disp_dtrc_sels, base + 0xa200);
clks[IMX8MQ_CLK_DISP_DC8000] = imx8m_clk_composite("disp_dc8000", imx8mq_disp_dc8000_sels, base + 0xa280);
clks[IMX8MQ_CLK_PCIE1_CTRL] = imx8m_clk_composite("pcie1_ctrl", imx8mq_pcie1_ctrl_sels, base + 0xa300);
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 0/7] PM / devfreq: Add initial imx support
From: Leonard Crestez @ 2019-08-20 15:45 UTC (permalink / raw)
To: Stephen Boyd, Shawn Guo, MyungJoo Ham, Chanwoo Choi, Rob Herring
Cc: Mark Rutland, Artur Świgoń, Abel Vesa, Saravana Kannan,
Anson Huang, linux-arm-kernel, Viresh Kumar, Michael Turquette,
linux-pm, linux-imx, Krzysztof Kozlowski, linux-clk,
Kyungmin Park, Alexandre Bailon, kernel, Dong Aisheng,
Fabio Estevam, Georgi Djakov, devicetree, Jacky Bai
This adds devfreq support for imx8mm, covering dynamic scaling of
internal NOC and DDR Controller
Scaling for simple busses (NIC/NOC) is done through the clk framework
while DRAM scaling is performed in firmware with an "imx-ddrc" wrapper
for devfreq.
Changes since v1:
* bindings: Stop using "contains" for "compatible"
* bindings: Set "additionalProperties: false" and document missing stuff.
* Remove (c) from NXP copyright notice
* Fix various checkpatch issues
* Remove unused dram_alt_root clk from imx-ddrc
Link to v1: https://patchwork.kernel.org/project/linux-arm-kernel/list/?series=158773
Changes since RFC v3:
* Implement passive support and set NOC's parent to DDRC
* Drop scaling AHB/AXI for now (NOC/DDRC use most power anyway)
* Stop relying on clk_min_rate
* Split into two devreq drivers (and bindings) because the ddrc is
really a distinct piece of hardware.
* Perform DRAM frequency inside devfreq instead of clk, mostly due to
objections to earlier RFCs for imx8m-dram-clk.
* Fetch info about dram clk parents from firmware instead of
hardcoding in driver. This can more easily support additional rates.
* Link: https://patchwork.kernel.org/cover/11056779/
* Link: https://patchwork.kernel.org/patch/11049429/
Scaling buses can cause problems for devices with realtime bandwith
requirements such as display, the intention is to use the interconnect
framework to make DEV_PM_QOS_MIN_FREQUENCY to devfreq. There are
separate patches for that:
* https://patchwork.kernel.org/cover/11104055/
* https://patchwork.kernel.org/cover/11078671/
Leonard Crestez (7):
clk: imx8m: Set CLK_GET_RATE_NOCACHE on dram_alt/apb
dt-bindings: devfreq: Add bindings for generic imx buses
PM / devfreq: Add generic imx bus driver
dt-bindings: devfreq: Add bindings for imx ddr controller
PM / devfreq: Add dynamic scaling for imx ddr controller
PM / devfreq: imx-ddrc: Measure bandwidth with perf
arm64: dts: imx8mm: Add devfreq nodes
.../devicetree/bindings/devfreq/imx-ddrc.yaml | 60 ++
.../devicetree/bindings/devfreq/imx.yaml | 68 +++
arch/arm64/boot/dts/freescale/imx8mm.dtsi | 53 +-
drivers/clk/imx/clk-imx8mm.c | 6 +-
drivers/clk/imx/clk-imx8mn.c | 6 +-
drivers/clk/imx/clk-imx8mq.c | 7 +-
drivers/devfreq/Kconfig | 12 +
drivers/devfreq/Makefile | 1 +
drivers/devfreq/imx-ddrc.c | 514 ++++++++++++++++++
drivers/devfreq/imx-devfreq.c | 148 +++++
10 files changed, 867 insertions(+), 8 deletions(-)
create mode 100644 Documentation/devicetree/bindings/devfreq/imx-ddrc.yaml
create mode 100644 Documentation/devicetree/bindings/devfreq/imx.yaml
create mode 100644 drivers/devfreq/imx-ddrc.c
create mode 100644 drivers/devfreq/imx-devfreq.c
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 3/6] net: stmmac: sun8i: Use devm_regulator_get for PHY regulator
From: Andrew Lunn @ 2019-08-20 15:39 UTC (permalink / raw)
To: megous
Cc: Mark Rutland, Jose Abreu, Alexandre Torgue, devicetree, netdev,
linux-kernel, Maxime Ripard, linux-stm32, Chen-Yu Tsai,
Rob Herring, Maxime Coquelin, Giuseppe Cavallaro, David S. Miller,
linux-arm-kernel
In-Reply-To: <20190820145343.29108-4-megous@megous.com>
On Tue, Aug 20, 2019 at 04:53:40PM +0200, megous@megous.com wrote:
> From: Ondrej Jirman <megous@megous.com>
>
> Use devm_regulator_get instead of devm_regulator_get_optional and rely
> on dummy supply. This avoids NULL checks before regulator_enable/disable
> calls.
Hi Ondrej
What do you mean by a dummy supply? I'm just trying to make sure you
are not breaking backwards compatibility.
Thanks
Andrew
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v6 4/4] ARM: dts: imx6ul-kontron-n6310: Add Kontron i.MX6UL N6310 SoM and boards
From: Krzysztof Kozlowski @ 2019-08-20 15:35 UTC (permalink / raw)
To: Schrempf Frieder, Rob Herring, Mark Rutland, Shawn Guo,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
NXP Linux Team, devicetree, linux-kernel, linux-arm-kernel
Cc: Krzysztof Kozlowski
In-Reply-To: <1566315318-30320-1-git-send-email-krzk@kernel.org>
Add support for i.MX6UL modules from Kontron Electronics GmbH (before
acquisition: Exceet Electronics) and evalkit boards based on it:
1. N6310 SOM: i.MX6 UL System-on-Module, a 25x25 mm solderable module
(LGA pads and pin castellations) with 256 MB RAM, 1 MB NOR-Flash,
256 MB NAND and other interfaces,
2. N6310 S: evalkit, w/wo eMMC, without display,
3. N6310 S 43: evalkit with 4.3" display,
The work is based on Exceet/Kontron source code (GPLv2) with numerous
changes:
1. Reorganize files,
2. Rename Exceet -> Kontron,
3. Rename models/compatibles to match newest Kontron product naming,
4. Fix coding style errors and adjust to device tree coding guidelines,
5. Fix DTC warnings,
6. Extend compatibles so eval boards inherit the SoM compatible,
7. Use defines instead of GPIO and interrupt flag values,
8. Use proper vendor compatible for Macronix SPI NOR,
9. Replace deprecated bindings with proper ones,
10. Sort nodes alphabetically,
11. Remove Admatec display nodes (not yet supported).
Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
Reviewed-by: Rob Herring <robh@kernel.org>
Reviewed-by: Frieder Schrempf <frieder.schrempf@kontron.de>
Reviewed-by: Fabio Estevam <festevam@gmail.com>
---
Changes since v5:
1. Split Documentation/devicetree/bindings/arm/fsl.yaml update to
separate patch.
Changes since v4:
1. Split Documentation/devicetree/bindings/eeprom/at25.txt update to
separate patch.
Changes since v3, after Shawn's review:
1. Split bindings update to patch 2/3,
2. Remove unsupported displays from (Admatec),
3. Remove N6310 S 50 board (same as N6310 S 43 since there is no Admatec
display),
4. Order iomux nodes by name, minor cleanup,
5. Use wakeup-source instead of enable-sdio-wakeup,
6. Add review tags.
Changes since v2, after Fabio's review:
1. Add "imx6ul" compatible to board name (that's what I understood from
review),
2. Add vendor/device prefix to eeprom and document the compatible,
3. Use "admatecde" as vendor compatible to avoid confusion with Admatec
AG in Switzerland (also making LCD panels),
4. Use generic names for nodes,
5. Use IRQ_TYPE_LEVEL_LOW,
6. Move iomux to the end of files,
7. Remove regulators node (include regulators in top level),
8. Remove cpu clock-frequency,
9. Other minor fixes pointed by Fabio.
Changes since v1, after Frieder's review:
1. Remove unneeded license notes,
2. Add Kontron copyright (2018),
3. Rename the files/models/compatibles to new naming - N6310,
4. Remove unneeded CPU operating points override,
5. Switch regulator nodes into simple children nodes without addresses
(so not simple bus),
6. Use proper vendor compatible for Macronix SPI NOR.
---
arch/arm/boot/dts/Makefile | 2 +
arch/arm/boot/dts/imx6ul-kontron-n6310-s-43.dts | 102 ++++++
arch/arm/boot/dts/imx6ul-kontron-n6310-s.dts | 420 ++++++++++++++++++++++++
arch/arm/boot/dts/imx6ul-kontron-n6310-som.dtsi | 134 ++++++++
4 files changed, 658 insertions(+)
create mode 100644 arch/arm/boot/dts/imx6ul-kontron-n6310-s-43.dts
create mode 100644 arch/arm/boot/dts/imx6ul-kontron-n6310-s.dts
create mode 100644 arch/arm/boot/dts/imx6ul-kontron-n6310-som.dtsi
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 9159fa2cea90..747eef501f95 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -569,6 +569,8 @@ dtb-$(CONFIG_SOC_IMX6UL) += \
imx6ul-geam.dtb \
imx6ul-isiot-emmc.dtb \
imx6ul-isiot-nand.dtb \
+ imx6ul-kontron-n6310-s.dtb \
+ imx6ul-kontron-n6310-s-43.dtb \
imx6ul-liteboard.dtb \
imx6ul-opos6uldev.dtb \
imx6ul-pico-hobbit.dtb \
diff --git a/arch/arm/boot/dts/imx6ul-kontron-n6310-s-43.dts b/arch/arm/boot/dts/imx6ul-kontron-n6310-s-43.dts
new file mode 100644
index 000000000000..5bad29683cc3
--- /dev/null
+++ b/arch/arm/boot/dts/imx6ul-kontron-n6310-s-43.dts
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 exceet electronics GmbH
+ * Copyright (C) 2018 Kontron Electronics GmbH
+ * Copyright (c) 2019 Krzysztof Kozlowski <krzk@kernel.org>
+ */
+
+#include "imx6ul-kontron-n6310-s.dts"
+
+/ {
+ model = "Kontron N6310 S 43";
+ compatible = "kontron,imx6ul-n6310-s-43", "kontron,imx6ul-n6310-s",
+ "kontron,imx6ul-n6310-som", "fsl,imx6ul";
+
+ backlight {
+ compatible = "pwm-backlight";
+ pwms = <&pwm7 0 5000000>;
+ brightness-levels = <0 4 8 16 32 64 128 255>;
+ default-brightness-level = <6>;
+ status = "okay";
+ };
+};
+
+&i2c4 {
+ touchscreen@5d {
+ compatible = "goodix,gt928";
+ reg = <0x5d>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_cap_touch>;
+ interrupt-parent = <&gpio5>;
+ interrupts = <6 IRQ_TYPE_LEVEL_LOW>;
+ reset-gpios = <&gpio5 8 GPIO_ACTIVE_HIGH>;
+ irq-gpios = <&gpio5 6 GPIO_ACTIVE_HIGH>;
+ };
+};
+
+&lcdif {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_lcdif_dat &pinctrl_lcdif_ctrl>;
+ /* Leave status disabled because of missing display panel node */
+};
+
+&pwm7 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm7>;
+ status = "okay";
+};
+
+&iomuxc {
+ pinctrl_cap_touch: captouchgrp {
+ fsl,pins = <
+ MX6UL_PAD_SNVS_TAMPER6__GPIO5_IO06 0x1b0b0 /* Touch Interrupt */
+ MX6UL_PAD_SNVS_TAMPER7__GPIO5_IO07 0x1b0b0 /* Touch Reset */
+ MX6UL_PAD_SNVS_TAMPER8__GPIO5_IO08 0x1b0b0 /* Touch Wake */
+ >;
+ };
+
+ pinctrl_lcdif_ctrl: lcdifctrlgrp {
+ fsl,pins = <
+ MX6UL_PAD_LCD_CLK__LCDIF_CLK 0x79
+ MX6UL_PAD_LCD_ENABLE__LCDIF_ENABLE 0x79
+ MX6UL_PAD_LCD_HSYNC__LCDIF_HSYNC 0x79
+ MX6UL_PAD_LCD_VSYNC__LCDIF_VSYNC 0x79
+ MX6UL_PAD_LCD_RESET__LCDIF_RESET 0x79
+ >;
+ };
+
+ pinctrl_lcdif_dat: lcdifdatgrp {
+ fsl,pins = <
+ MX6UL_PAD_LCD_DATA00__LCDIF_DATA00 0x79
+ MX6UL_PAD_LCD_DATA01__LCDIF_DATA01 0x79
+ MX6UL_PAD_LCD_DATA02__LCDIF_DATA02 0x79
+ MX6UL_PAD_LCD_DATA03__LCDIF_DATA03 0x79
+ MX6UL_PAD_LCD_DATA04__LCDIF_DATA04 0x79
+ MX6UL_PAD_LCD_DATA05__LCDIF_DATA05 0x79
+ MX6UL_PAD_LCD_DATA06__LCDIF_DATA06 0x79
+ MX6UL_PAD_LCD_DATA07__LCDIF_DATA07 0x79
+ MX6UL_PAD_LCD_DATA08__LCDIF_DATA08 0x79
+ MX6UL_PAD_LCD_DATA09__LCDIF_DATA09 0x79
+ MX6UL_PAD_LCD_DATA10__LCDIF_DATA10 0x79
+ MX6UL_PAD_LCD_DATA11__LCDIF_DATA11 0x79
+ MX6UL_PAD_LCD_DATA12__LCDIF_DATA12 0x79
+ MX6UL_PAD_LCD_DATA13__LCDIF_DATA13 0x79
+ MX6UL_PAD_LCD_DATA14__LCDIF_DATA14 0x79
+ MX6UL_PAD_LCD_DATA15__LCDIF_DATA15 0x79
+ MX6UL_PAD_LCD_DATA16__LCDIF_DATA16 0x79
+ MX6UL_PAD_LCD_DATA17__LCDIF_DATA17 0x79
+ MX6UL_PAD_LCD_DATA18__LCDIF_DATA18 0x79
+ MX6UL_PAD_LCD_DATA19__LCDIF_DATA19 0x79
+ MX6UL_PAD_LCD_DATA20__LCDIF_DATA20 0x79
+ MX6UL_PAD_LCD_DATA21__LCDIF_DATA21 0x79
+ MX6UL_PAD_LCD_DATA22__LCDIF_DATA22 0x79
+ MX6UL_PAD_LCD_DATA23__LCDIF_DATA23 0x79
+ >;
+ };
+
+ pinctrl_pwm7: pwm7grp {
+ fsl,pins = <
+ MX6UL_PAD_CSI_VSYNC__PWM7_OUT 0x110b0
+ >;
+ };
+};
diff --git a/arch/arm/boot/dts/imx6ul-kontron-n6310-s.dts b/arch/arm/boot/dts/imx6ul-kontron-n6310-s.dts
new file mode 100644
index 000000000000..0205fd56d975
--- /dev/null
+++ b/arch/arm/boot/dts/imx6ul-kontron-n6310-s.dts
@@ -0,0 +1,420 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 exceet electronics GmbH
+ * Copyright (C) 2018 Kontron Electronics GmbH
+ * Copyright (c) 2019 Krzysztof Kozlowski <krzk@kernel.org>
+ */
+
+/dts-v1/;
+
+#include "imx6ul-kontron-n6310-som.dtsi"
+
+/ {
+ model = "Kontron N6310 S";
+ compatible = "kontron,imx6ul-n6310-s", "kontron,imx6ul-n6310-som",
+ "fsl,imx6ul";
+
+ gpio-leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpio_leds>;
+
+ led1 {
+ label = "debug-led1";
+ gpios = <&gpio1 30 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ linux,default-trigger = "heartbeat";
+ };
+
+ led2 {
+ label = "debug-led2";
+ gpios = <&gpio5 3 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+
+ led3 {
+ label = "debug-led3";
+ gpios = <&gpio5 2 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+ };
+
+ pwm-beeper {
+ compatible = "pwm-beeper";
+ pwms = <&pwm8 0 5000>;
+ };
+
+ reg_3v3: regulator-3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ reg_usb_otg1_vbus: regulator-usb-otg1-vbus {
+ compatible = "regulator-fixed";
+ regulator-name = "usb_otg1_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&gpio1 4 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ reg_vref_adc: regulator-vref-adc {
+ compatible = "regulator-fixed";
+ regulator-name = "vref-adc";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+};
+
+&adc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_adc1>;
+ num-channels = <3>;
+ vref-supply = <®_vref_adc>;
+ status = "okay";
+};
+
+&can2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_flexcan2>;
+ status = "okay";
+};
+
+&ecspi1 {
+ cs-gpios = <&gpio4 26 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ecspi1>;
+ status = "okay";
+
+ eeprom@0 {
+ compatible = "anvo,anv32e61w", "atmel,at25";
+ reg = <0>;
+ spi-max-frequency = <20000000>;
+ spi-cpha;
+ spi-cpol;
+ pagesize = <1>;
+ size = <8192>;
+ address-width = <16>;
+ };
+};
+
+&fec1 {
+ pinctrl-0 = <&pinctrl_enet1>;
+ /delete-node/ mdio;
+};
+
+&fec2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enet2 &pinctrl_enet2_mdio>;
+ phy-mode = "rmii";
+ phy-handle = <ðphy2>;
+ status = "okay";
+
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ethphy1: ethernet-phy@1 {
+ reg = <1>;
+ micrel,led-mode = <0>;
+ clocks = <&clks IMX6UL_CLK_ENET_REF>;
+ clock-names = "rmii-ref";
+ };
+
+ ethphy2: ethernet-phy@2 {
+ reg = <2>;
+ micrel,led-mode = <0>;
+ clocks = <&clks IMX6UL_CLK_ENET2_REF>;
+ clock-names = "rmii-ref";
+ };
+ };
+};
+
+&i2c1 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ status = "okay";
+};
+
+&i2c4 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c4>;
+ status = "okay";
+
+ rtc@32 {
+ compatible = "epson,rx8900";
+ reg = <0x32>;
+ };
+};
+
+&pwm8 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm8>;
+ status = "okay";
+};
+
+&snvs_poweroff {
+ status = "okay";
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ status = "okay";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2>;
+ linux,rs485-enabled-at-boot-time;
+ rs485-rx-during-tx;
+ rs485-rts-active-low;
+ uart-has-rtscts;
+ status = "okay";
+};
+
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart3>;
+ fsl,uart-has-rtscts;
+ status = "okay";
+};
+
+&uart4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart4>;
+ status = "okay";
+};
+
+&usbotg1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usbotg1>;
+ dr_mode = "otg";
+ srp-disable;
+ hnp-disable;
+ adp-disable;
+ vbus-supply = <®_usb_otg1_vbus>;
+ status = "okay";
+};
+
+&usbotg2 {
+ dr_mode = "host";
+ disable-over-current;
+ status = "okay";
+};
+
+&usdhc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc1>;
+ cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;
+ keep-power-in-suspend;
+ wakeup-source;
+ vmmc-supply = <®_3v3>;
+ voltage-ranges = <3300 3300>;
+ no-1-8-v;
+ status = "okay";
+};
+
+&usdhc2 {
+ pinctrl-names = "default", "state_100mhz", "state_200mhz";
+ pinctrl-0 = <&pinctrl_usdhc2>;
+ pinctrl-1 = <&pinctrl_usdhc2_100mhz>;
+ pinctrl-2 = <&pinctrl_usdhc2_200mhz>;
+ non-removable;
+ keep-power-in-suspend;
+ wakeup-source;
+ vmmc-supply = <®_3v3>;
+ voltage-ranges = <3300 3300>;
+ no-1-8-v;
+ status = "okay";
+};
+
+&wdog1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_wdog>;
+ fsl,ext-reset-output;
+ status = "okay";
+};
+
+&iomuxc {
+ pinctrl-0 = <&pinctrl_reset_out &pinctrl_gpio>;
+
+ pinctrl_adc1: adc1grp {
+ fsl,pins = <
+ MX6UL_PAD_GPIO1_IO02__GPIO1_IO02 0xb0
+ MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0xb0
+ MX6UL_PAD_GPIO1_IO08__GPIO1_IO08 0xb0
+ >;
+ };
+
+ /* FRAM */
+ pinctrl_ecspi1: ecspi1grp {
+ fsl,pins = <
+ MX6UL_PAD_CSI_DATA07__ECSPI1_MISO 0x100b1
+ MX6UL_PAD_CSI_DATA06__ECSPI1_MOSI 0x100b1
+ MX6UL_PAD_CSI_DATA04__ECSPI1_SCLK 0x100b1
+ MX6UL_PAD_CSI_DATA05__GPIO4_IO26 0x100b1 /* ECSPI1-CS1 */
+ >;
+ };
+
+ pinctrl_enet2: enet2grp {
+ fsl,pins = <
+ MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN 0x1b0b0
+ MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER 0x1b0b0
+ MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00 0x1b0b0
+ MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01 0x1b0b0
+ MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN 0x1b0b0
+ MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00 0x1b0b0
+ MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01 0x1b0b0
+ MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 0x4001b009
+ >;
+ };
+
+ pinctrl_enet2_mdio: enet2mdiogrp {
+ fsl,pins = <
+ MX6UL_PAD_GPIO1_IO07__ENET2_MDC 0x1b0b0
+ MX6UL_PAD_GPIO1_IO06__ENET2_MDIO 0x1b0b0
+ >;
+ };
+
+ pinctrl_flexcan2: flexcan2grp{
+ fsl,pins = <
+ MX6UL_PAD_UART2_RTS_B__FLEXCAN2_RX 0x1b020
+ MX6UL_PAD_UART2_CTS_B__FLEXCAN2_TX 0x1b020
+ >;
+ };
+
+ pinctrl_gpio: gpiogrp {
+ fsl,pins = <
+ MX6UL_PAD_SNVS_TAMPER5__GPIO5_IO05 0x1b0b0 /* DOUT1 */
+ MX6UL_PAD_SNVS_TAMPER4__GPIO5_IO04 0x1b0b0 /* DIN1 */
+ MX6UL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x1b0b0 /* DOUT2 */
+ MX6UL_PAD_SNVS_TAMPER0__GPIO5_IO00 0x1b0b0 /* DIN2 */
+ >;
+ };
+
+ pinctrl_gpio_leds: gpioledsgrp {
+ fsl,pins = <
+ MX6UL_PAD_UART5_TX_DATA__GPIO1_IO30 0x1b0b0 /* LED H14 */
+ MX6UL_PAD_SNVS_TAMPER3__GPIO5_IO03 0x1b0b0 /* LED H15 */
+ MX6UL_PAD_SNVS_TAMPER2__GPIO5_IO02 0x1b0b0 /* LED H16 */
+ >;
+ };
+
+ pinctrl_i2c1: i2c1grp {
+ fsl,pins = <
+ MX6UL_PAD_CSI_PIXCLK__I2C1_SCL 0x4001b8b0
+ MX6UL_PAD_CSI_MCLK__I2C1_SDA 0x4001b8b0
+ >;
+ };
+
+ pinctrl_i2c4: i2c4grp {
+ fsl,pins = <
+ MX6UL_PAD_UART2_TX_DATA__I2C4_SCL 0x4001f8b0
+ MX6UL_PAD_UART2_RX_DATA__I2C4_SDA 0x4001f8b0
+ >;
+ };
+
+ pinctrl_pwm8: pwm8grp {
+ fsl,pins = <
+ MX6UL_PAD_CSI_HSYNC__PWM8_OUT 0x110b0
+ >;
+ };
+
+ pinctrl_uart1: uart1grp {
+ fsl,pins = <
+ MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1
+ MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart2: uart2grp {
+ fsl,pins = <
+ MX6UL_PAD_NAND_DATA04__UART2_DCE_TX 0x1b0b1
+ MX6UL_PAD_NAND_DATA05__UART2_DCE_RX 0x1b0b1
+ MX6UL_PAD_NAND_DATA06__UART2_DCE_CTS 0x1b0b1
+ /*
+ * mux unused RTS to make sure it doesn't cause
+ * any interrupts when it is undefined
+ */
+ MX6UL_PAD_NAND_DATA07__UART2_DCE_RTS 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart3: uart3grp {
+ fsl,pins = <
+ MX6UL_PAD_UART3_TX_DATA__UART3_DCE_TX 0x1b0b1
+ MX6UL_PAD_UART3_RX_DATA__UART3_DCE_RX 0x1b0b1
+ MX6UL_PAD_UART3_CTS_B__UART3_DCE_CTS 0x1b0b1
+ MX6UL_PAD_UART3_RTS_B__UART3_DCE_RTS 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart4: uart4grp {
+ fsl,pins = <
+ MX6UL_PAD_UART4_TX_DATA__UART4_DCE_TX 0x1b0b1
+ MX6UL_PAD_UART4_RX_DATA__UART4_DCE_RX 0x1b0b1
+ >;
+ };
+
+ pinctrl_usbotg1: usbotg1 {
+ fsl,pins = <
+ MX6UL_PAD_GPIO1_IO04__GPIO1_IO04 0x1b0b0
+ >;
+ };
+
+ pinctrl_usdhc1: usdhc1grp {
+ fsl,pins = <
+ MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x17059
+ MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x10059
+ MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x17059
+ MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x17059
+ MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x17059
+ MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x17059
+ MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x100b1 /* SD1_CD */
+ >;
+ };
+
+ pinctrl_usdhc2: usdhc2grp {
+ fsl,pins = <
+ MX6UL_PAD_NAND_RE_B__USDHC2_CLK 0x10059
+ MX6UL_PAD_NAND_WE_B__USDHC2_CMD 0x17059
+ MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x17059
+ MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x17059
+ MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x17059
+ MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x17059
+ >;
+ };
+
+ pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+ fsl,pins = <
+ MX6UL_PAD_NAND_RE_B__USDHC2_CLK 0x100b9
+ MX6UL_PAD_NAND_WE_B__USDHC2_CMD 0x170b9
+ MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x170b9
+ MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x170b9
+ MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x170b9
+ MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x170b9
+ >;
+ };
+
+ pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+ fsl,pins = <
+ MX6UL_PAD_NAND_RE_B__USDHC2_CLK 0x100f9
+ MX6UL_PAD_NAND_WE_B__USDHC2_CMD 0x170f9
+ MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x170f9
+ MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x170f9
+ MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x170f9
+ MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x170f9
+ >;
+ };
+
+ pinctrl_wdog: wdoggrp {
+ fsl,pins = <
+ MX6UL_PAD_GPIO1_IO09__WDOG1_WDOG_ANY 0x30b0
+ >;
+ };
+};
diff --git a/arch/arm/boot/dts/imx6ul-kontron-n6310-som.dtsi b/arch/arm/boot/dts/imx6ul-kontron-n6310-som.dtsi
new file mode 100644
index 000000000000..a896b2348dd2
--- /dev/null
+++ b/arch/arm/boot/dts/imx6ul-kontron-n6310-som.dtsi
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 exceet electronics GmbH
+ * Copyright (C) 2018 Kontron Electronics GmbH
+ * Copyright (c) 2019 Krzysztof Kozlowski <krzk@kernel.org>
+ */
+
+#include "imx6ul.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ model = "Kontron N6310 SOM";
+ compatible = "kontron,imx6ul-n6310-som", "fsl,imx6ul";
+
+ memory@80000000 {
+ reg = <0x80000000 0x10000000>;
+ device_type = "memory";
+ };
+};
+
+&ecspi2 {
+ cs-gpios = <&gpio4 22 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ecspi2>;
+ status = "okay";
+
+ spi-flash@0 {
+ compatible = "mxicy,mx25v8035f", "jedec,spi-nor";
+ spi-max-frequency = <50000000>;
+ reg = <0>;
+ };
+};
+
+&fec1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enet1 &pinctrl_enet1_mdio>;
+ phy-mode = "rmii";
+ phy-handle = <ðphy1>;
+ status = "okay";
+
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ethphy1: ethernet-phy@1 {
+ reg = <1>;
+ micrel,led-mode = <0>;
+ clocks = <&clks IMX6UL_CLK_ENET_REF>;
+ clock-names = "rmii-ref";
+ };
+ };
+};
+
+&fec2 {
+ phy-mode = "rmii";
+ status = "disabled";
+};
+
+&qspi {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_qspi>;
+ status = "okay";
+
+ spi-flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "spi-nand";
+ spi-max-frequency = <108000000>;
+ spi-tx-bus-width = <4>;
+ spi-rx-bus-width = <4>;
+ reg = <0>;
+
+ partition@0 {
+ label = "ubi1";
+ reg = <0x00000000 0x08000000>;
+ };
+
+ partition@8000000 {
+ label = "ubi2";
+ reg = <0x08000000 0x08000000>;
+ };
+ };
+};
+
+&iomuxc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_reset_out>;
+
+ pinctrl_ecspi2: ecspi2grp {
+ fsl,pins = <
+ MX6UL_PAD_CSI_DATA03__ECSPI2_MISO 0x100b1
+ MX6UL_PAD_CSI_DATA02__ECSPI2_MOSI 0x100b1
+ MX6UL_PAD_CSI_DATA00__ECSPI2_SCLK 0x100b1
+ MX6UL_PAD_CSI_DATA01__GPIO4_IO22 0x100b1
+ >;
+ };
+
+ pinctrl_enet1: enet1grp {
+ fsl,pins = <
+ MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN 0x1b0b0
+ MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER 0x1b0b0
+ MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00 0x1b0b0
+ MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01 0x1b0b0
+ MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN 0x1b0b0
+ MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00 0x1b0b0
+ MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01 0x1b0b0
+ MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 0x4001b009
+ >;
+ };
+
+ pinctrl_enet1_mdio: enet1mdiogrp {
+ fsl,pins = <
+ MX6UL_PAD_GPIO1_IO07__ENET1_MDC 0x1b0b0
+ MX6UL_PAD_GPIO1_IO06__ENET1_MDIO 0x1b0b0
+ >;
+ };
+
+ pinctrl_qspi: qspigrp {
+ fsl,pins = <
+ MX6UL_PAD_NAND_WP_B__QSPI_A_SCLK 0x70a1
+ MX6UL_PAD_NAND_READY_B__QSPI_A_DATA00 0x70a1
+ MX6UL_PAD_NAND_CE0_B__QSPI_A_DATA01 0x70a1
+ MX6UL_PAD_NAND_CE1_B__QSPI_A_DATA02 0x70a1
+ MX6UL_PAD_NAND_CLE__QSPI_A_DATA03 0x70a1
+ MX6UL_PAD_NAND_DQS__QSPI_A_SS0_B 0x70a1
+ >;
+ };
+
+ pinctrl_reset_out: rstoutgrp {
+ fsl,pins = <
+ MX6UL_PAD_SNVS_TAMPER9__GPIO5_IO09 0x1b0b0
+ >;
+ };
+};
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v6 3/4] dt-bindings: arm: fsl: Add Kontron i.MX6UL N6310 compatibles
From: Krzysztof Kozlowski @ 2019-08-20 15:35 UTC (permalink / raw)
To: Schrempf Frieder, Rob Herring, Mark Rutland, Shawn Guo,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
NXP Linux Team, devicetree, linux-kernel, linux-arm-kernel
Cc: Krzysztof Kozlowski
In-Reply-To: <1566315318-30320-1-git-send-email-krzk@kernel.org>
Add the compatibles for Kontron i.MX6UL N6310 SoM and boards.
Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
---
Changes since v5:
New patch
---
Documentation/devicetree/bindings/arm/fsl.yaml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
index 7294ac36f4c0..d07b3c06d7cf 100644
--- a/Documentation/devicetree/bindings/arm/fsl.yaml
+++ b/Documentation/devicetree/bindings/arm/fsl.yaml
@@ -161,6 +161,9 @@ properties:
items:
- enum:
- fsl,imx6ul-14x14-evk # i.MX6 UltraLite 14x14 EVK Board
+ - kontron,imx6ul-n6310-som # Kontron N6310 SOM
+ - kontron,imx6ul-n6310-s # Kontron N6310 S Board
+ - kontron,imx6ul-n6310-s-43 # Kontron N6310 S 43 Board
- const: fsl,imx6ul
- description: i.MX6ULL based Boards
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v6 2/4] dt-bindings: eeprom: at25: Add Anvo ANV32E61W
From: Krzysztof Kozlowski @ 2019-08-20 15:35 UTC (permalink / raw)
To: Schrempf Frieder, Rob Herring, Mark Rutland, Shawn Guo,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
NXP Linux Team, devicetree, linux-kernel, linux-arm-kernel
Cc: Krzysztof Kozlowski
In-Reply-To: <1566315318-30320-1-git-send-email-krzk@kernel.org>
Document the compatible for ANV32E61W 64kb Serial SPI non-volatile SRAM.
Although it is a SRAM device, it can be accessed through EEPROM
interface. At least until there is no proper SRAM driver support for
it.
Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
Reviewed-by: Fabio Estevam <festevam@gmail.com>
---
Changes since v4:
1. Update commit msg.
---
Documentation/devicetree/bindings/eeprom/at25.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/eeprom/at25.txt b/Documentation/devicetree/bindings/eeprom/at25.txt
index b3bde97dc199..42577dd113dd 100644
--- a/Documentation/devicetree/bindings/eeprom/at25.txt
+++ b/Documentation/devicetree/bindings/eeprom/at25.txt
@@ -3,6 +3,7 @@ EEPROMs (SPI) compatible with Atmel at25.
Required properties:
- compatible : Should be "<vendor>,<type>", and generic value "atmel,at25".
Example "<vendor>,<type>" values:
+ "anvo,anv32e61w"
"microchip,25lc040"
"st,m95m02"
"st,m95256"
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v6 1/4] dt-bindings: vendor-prefixes: Add Anvo-Systems
From: Krzysztof Kozlowski @ 2019-08-20 15:35 UTC (permalink / raw)
To: Schrempf Frieder, Rob Herring, Mark Rutland, Shawn Guo,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
NXP Linux Team, devicetree, linux-kernel, linux-arm-kernel
Cc: Krzysztof Kozlowski
Add vendor prefix for Anvo-Systems Dresden GmbH.
Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
Reviewed-by: Rob Herring <robh@kernel.org>
---
Changes since v4:
None
Changes since v3:
1. Add Rob's tag,
2. Remove Admatec (not needed anymore).
Changes since v2:
1. Use admatecde vendor prefix.
2. Add Anvo-Systems Dresden GmbH.
Changes since v1:
New patch
---
Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 6992bbbbffab..519889f5aec8 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -81,6 +81,8 @@ patternProperties:
description: Analogix Semiconductor, Inc.
"^andestech,.*":
description: Andes Technology Corporation
+ "^anvo,.*":
+ description: Anvo-Systems Dresden GmbH
"^apm,.*":
description: Applied Micro Circuits Corporation (APM)
"^aptina,.*":
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH v3 3/5] arm64: pmu: Add function implementation to update event index in userpage.
From: Mark Rutland @ 2019-08-20 15:34 UTC (permalink / raw)
To: Raphael Gault
Cc: raph.gault+kdev, peterz, catalin.marinas, will.deacon,
linux-kernel, acme, mingo, linux-arm-kernel
In-Reply-To: <20190816125934.18509-4-raphael.gault@arm.com>
On Fri, Aug 16, 2019 at 01:59:32PM +0100, Raphael Gault wrote:
> In order to be able to access the counter directly for userspace,
> we need to provide the index of the counter using the userpage.
> We thus need to override the event_idx function to retrieve and
> convert the perf_event index to armv8 hardware index.
>
> Since the arm_pmu driver can be used by any implementation, even
> if not armv8, two components play a role into making sure the
> behaviour is correct and consistent with the PMU capabilities:
>
> * the ARMPMU_EL0_RD_CNTR flag which denotes the capability to access
> counter from userspace.
> * the event_idx call back, which is implemented and initialized by
> the PMU implementation: if no callback is provided, the default
> behaviour applies, returning 0 as index value.
>
> Signed-off-by: Raphael Gault <raphael.gault@arm.com>
> ---
> arch/arm64/kernel/perf_event.c | 22 ++++++++++++++++++++++
> include/linux/perf/arm_pmu.h | 2 ++
> 2 files changed, 24 insertions(+)
>
> diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
> index a0b4f1bca491..9fe3f6909513 100644
> --- a/arch/arm64/kernel/perf_event.c
> +++ b/arch/arm64/kernel/perf_event.c
> @@ -818,6 +818,22 @@ static void armv8pmu_clear_event_idx(struct pmu_hw_events *cpuc,
> clear_bit(idx - 1, cpuc->used_mask);
> }
>
> +static int armv8pmu_access_event_idx(struct perf_event *event)
> +{
> + if (!(event->hw.flags & ARMPMU_EL0_RD_CNTR))
> + return 0;
> +
> + /*
> + * We remap the cycle counter index to 32 to
> + * match the offset applied to the rest of
> + * the counter indeces.
Typo: s/indeces/indices/
> + */
> + if (event->hw.idx == ARMV8_IDX_CYCLE_COUNTER)
> + return 32;
> +
> + return event->hw.idx;
> +}
> +
> /*
> * Add an event filter to a given event.
> */
> @@ -911,6 +927,9 @@ static int __armv8_pmuv3_map_event(struct perf_event *event,
> if (armv8pmu_event_is_64bit(event))
> event->hw.flags |= ARMPMU_EVT_64BIT;
>
> + if (!cpus_have_const_cap(ARM64_HAS_HETEROGENEOUS_PMU))
> + event->hw.flags |= ARMPMU_EL0_RD_CNTR;
> +
> /* Only expose micro/arch events supported by this PMU */
> if ((hw_event_id > 0) && (hw_event_id < ARMV8_PMUV3_MAX_COMMON_EVENTS)
> && test_bit(hw_event_id, armpmu->pmceid_bitmap)) {
> @@ -1031,6 +1050,8 @@ static int armv8_pmu_init(struct arm_pmu *cpu_pmu)
> cpu_pmu->set_event_filter = armv8pmu_set_event_filter;
> cpu_pmu->filter_match = armv8pmu_filter_match;
>
> + cpu_pmu->pmu.event_idx = armv8pmu_access_event_idx;
> +
> return 0;
> }
>
> @@ -1209,6 +1230,7 @@ void arch_perf_update_userpage(struct perf_event *event,
> */
> freq = arch_timer_get_rate();
> userpg->cap_user_time = 1;
> + userpg->cap_user_rdpmc = !!(event->hw.flags & ARMPMU_EL0_RD_CNTR);
For bisectability, we should only expose this to userspace once we have
the code to enable/disable it, so the code exposing the index and
setting up the user page cap needs to be added after the context switch
code.
Thanks,
Mark.
>
> clocks_calc_mult_shift(&userpg->time_mult, &shift, freq,
> NSEC_PER_SEC, 0);
> diff --git a/include/linux/perf/arm_pmu.h b/include/linux/perf/arm_pmu.h
> index 71f525a35ac2..1106a9ac00fd 100644
> --- a/include/linux/perf/arm_pmu.h
> +++ b/include/linux/perf/arm_pmu.h
> @@ -26,6 +26,8 @@
> */
> /* Event uses a 64bit counter */
> #define ARMPMU_EVT_64BIT 1
> +/* Allow access to hardware counter from userspace */
> +#define ARMPMU_EL0_RD_CNTR 2
>
> #define HW_OP_UNSUPPORTED 0xFFFF
> #define C(_x) PERF_COUNT_HW_CACHE_##_x
> --
> 2.17.1
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH V2 2/4] watchdog: Add i.MX7ULP watchdog support
From: Guenter Roeck @ 2019-08-20 15:31 UTC (permalink / raw)
To: Anson.Huang
Cc: mark.rutland, devicetree, leonard.crestez, schnitzeltony,
linux-watchdog, otavio, festevam, s.hauer, jan.tuerk, linux,
linux-kernel, robh+dt, Linux-imx, kernel, u.kleine-koenig, wim,
shawnguo, linux-arm-kernel
In-Reply-To: <20190812085321.13823-2-Anson.Huang@nxp.com>
On Mon, Aug 12, 2019 at 04:53:19PM +0800, Anson.Huang@nxp.com wrote:
> From: Anson Huang <Anson.Huang@nxp.com>
>
> The i.MX7ULP Watchdog Timer (WDOG) module is an independent timer
> that is available for system use.
> It provides a safety feature to ensure that software is executing
> as planned and that the CPU is not stuck in an infinite loop or
> executing unintended code. If the WDOG module is not serviced
> (refreshed) within a certain period, it resets the MCU.
>
> Add driver support for i.MX7ULP watchdog.
>
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
> ---
> Changes since V1:
> - Add clock operation;
> - Remove unneccsary error message when registering watchdog device failed;
> - Use BIT() instead of hard code;
> ---
> drivers/watchdog/Kconfig | 13 +++
> drivers/watchdog/Makefile | 1 +
> drivers/watchdog/imx7ulp_wdt.c | 244 +++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 258 insertions(+)
> create mode 100644 drivers/watchdog/imx7ulp_wdt.c
>
> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> index 8188963..0884e53 100644
> --- a/drivers/watchdog/Kconfig
> +++ b/drivers/watchdog/Kconfig
> @@ -740,6 +740,19 @@ config IMX_SC_WDT
> To compile this driver as a module, choose M here: the
> module will be called imx_sc_wdt.
>
> +config IMX7ULP_WDT
> + tristate "IMX7ULP Watchdog"
> + depends on ARCH_MXC || COMPILE_TEST
> + select WATCHDOG_CORE
> + help
> + This is the driver for the hardware watchdog on the Freescale
> + IMX7ULP and later processors. If you have one of these
> + processors and wish to have watchdog support enabled,
> + say Y, otherwise say N.
> +
> + To compile this driver as a module, choose M here: the
> + module will be called imx7ulp_wdt.
> +
> config UX500_WATCHDOG
> tristate "ST-Ericsson Ux500 watchdog"
> depends on MFD_DB8500_PRCMU
> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
> index 7caa920..7d32537 100644
> --- a/drivers/watchdog/Makefile
> +++ b/drivers/watchdog/Makefile
> @@ -69,6 +69,7 @@ obj-$(CONFIG_TS4800_WATCHDOG) += ts4800_wdt.o
> obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
> obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
> obj-$(CONFIG_IMX_SC_WDT) += imx_sc_wdt.o
> +obj-$(CONFIG_IMX7ULP_WDT) += imx7ulp_wdt.o
> obj-$(CONFIG_UX500_WATCHDOG) += ux500_wdt.o
> obj-$(CONFIG_RETU_WATCHDOG) += retu_wdt.o
> obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o
> diff --git a/drivers/watchdog/imx7ulp_wdt.c b/drivers/watchdog/imx7ulp_wdt.c
> new file mode 100644
> index 0000000..c20fba4
> --- /dev/null
> +++ b/drivers/watchdog/imx7ulp_wdt.c
> @@ -0,0 +1,244 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright 2019 NXP.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/reboot.h>
> +#include <linux/watchdog.h>
> +
> +#define WDOG_CS 0x0
> +#define WDOG_CS_CMD32EN BIT(13)
> +#define WDOG_CS_ULK BIT(11)
> +#define WDOG_CS_RCS BIT(10)
> +#define WDOG_CS_EN BIT(7)
> +#define WDOG_CS_UPDATE BIT(5)
> +
> +#define WDOG_CNT 0x4
> +#define WDOG_TOVAL 0x8
> +
> +#define REFRESH_SEQ0 0xA602
> +#define REFRESH_SEQ1 0xB480
> +#define REFRESH ((REFRESH_SEQ1 << 16) | REFRESH_SEQ0)
> +
> +#define UNLOCK_SEQ0 0xC520
> +#define UNLOCK_SEQ1 0xD928
> +#define UNLOCK ((UNLOCK_SEQ1 << 16) | UNLOCK_SEQ0)
> +
> +#define DEFAULT_TIMEOUT 60
> +#define MAX_TIMEOUT 128
> +
> +static bool nowayout = WATCHDOG_NOWAYOUT;
> +module_param(nowayout, bool, 0000);
> +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
> + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
> +
> +struct imx7ulp_wdt_device {
> + struct notifier_block restart_handler;
> + struct watchdog_device wdd;
> + void __iomem *base;
> + struct clk *clk;
> + int rate;
> +};
> +
> +static inline void imx7ulp_wdt_enable(void __iomem *base, bool enable)
> +{
> + u32 val = readl(base + WDOG_CS);
> +
> + writel(UNLOCK, base + WDOG_CNT);
> + if (enable)
> + writel(val | WDOG_CS_EN, base + WDOG_CS);
> + else
> + writel(val & ~WDOG_CS_EN, base + WDOG_CS);
> +}
> +
> +static inline bool imx7ulp_wdt_is_enabled(void __iomem *base)
> +{
> + u32 val = readl(base + WDOG_CS);
> +
> + return val & WDOG_CS_EN;
> +}
> +
> +static int imx7ulp_wdt_ping(struct watchdog_device *wdog)
> +{
> + struct imx7ulp_wdt_device *wdt = watchdog_get_drvdata(wdog);
> +
> + writel(REFRESH, wdt->base + WDOG_CNT);
> +
> + return 0;
> +}
> +
> +static int imx7ulp_wdt_start(struct watchdog_device *wdog)
> +{
> + struct imx7ulp_wdt_device *wdt = watchdog_get_drvdata(wdog);
> +
> + imx7ulp_wdt_enable(wdt->base, true);
> +
> + return 0;
> +}
> +
> +static int imx7ulp_wdt_stop(struct watchdog_device *wdog)
> +{
> + struct imx7ulp_wdt_device *wdt = watchdog_get_drvdata(wdog);
> +
> + imx7ulp_wdt_enable(wdt->base, false);
> +
> + return 0;
> +}
> +
> +static int imx7ulp_wdt_set_timeout(struct watchdog_device *wdog,
> + unsigned int timeout)
> +{
> + struct imx7ulp_wdt_device *wdt = watchdog_get_drvdata(wdog);
> + u32 val = wdt->rate * timeout;
> +
> + writel(UNLOCK, wdt->base + WDOG_CNT);
> + writel(val, wdt->base + WDOG_TOVAL);
> +
> + wdog->timeout = timeout;
> +
> + return 0;
> +}
> +
> +static const struct watchdog_ops imx7ulp_wdt_ops = {
> + .owner = THIS_MODULE,
> + .start = imx7ulp_wdt_start,
> + .stop = imx7ulp_wdt_stop,
> + .ping = imx7ulp_wdt_ping,
> + .set_timeout = imx7ulp_wdt_set_timeout,
> +};
> +
> +static const struct watchdog_info imx7ulp_wdt_info = {
> + .identity = "i.MX7ULP watchdog timer",
> + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
> + WDIOF_MAGICCLOSE,
> +};
> +
> +static inline void imx7ulp_wdt_init(void __iomem *base, unsigned int timeout)
> +{
> + u32 val;
> +
> + /* unlock the wdog for reconfiguration */
> + writel_relaxed(UNLOCK_SEQ0, base + WDOG_CNT);
> + writel_relaxed(UNLOCK_SEQ1, base + WDOG_CNT);
> +
> + /* set an initial timeout value in TOVAL */
> + writel(timeout, base + WDOG_TOVAL);
> + /* enable 32bit command sequence and reconfigure */
> + val = BIT(13) | BIT(8) | BIT(5);
> + writel(val, base + WDOG_CS);
> +}
> +
> +static int imx7ulp_wdt_probe(struct platform_device *pdev)
> +{
> + struct imx7ulp_wdt_device *imx7ulp_wdt;
> + struct device *dev = &pdev->dev;
> + struct watchdog_device *wdog;
> + int ret;
> +
> + imx7ulp_wdt = devm_kzalloc(dev, sizeof(*imx7ulp_wdt), GFP_KERNEL);
> + if (!imx7ulp_wdt)
> + return -ENOMEM;
> +
> + platform_set_drvdata(pdev, imx7ulp_wdt);
> +
> + imx7ulp_wdt->base = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(imx7ulp_wdt->base))
> + return PTR_ERR(imx7ulp_wdt->base);
> +
> + imx7ulp_wdt->clk = devm_clk_get(dev, NULL);
> + if (IS_ERR(imx7ulp_wdt->clk)) {
> + dev_err(dev, "Failed to get watchdog clock\n");
> + return PTR_ERR(imx7ulp_wdt->clk);
> + }
> +
> + ret = clk_prepare_enable(imx7ulp_wdt->clk);
> + if (ret)
> + return ret;
> +
> + imx7ulp_wdt->rate = 1000;
> + wdog = &imx7ulp_wdt->wdd;
> + wdog->info = &imx7ulp_wdt_info;
> + wdog->ops = &imx7ulp_wdt_ops;
> + wdog->min_timeout = 1;
> + wdog->max_timeout = MAX_TIMEOUT;
> + wdog->parent = dev;
> + wdog->timeout = DEFAULT_TIMEOUT;
> +
> + watchdog_init_timeout(wdog, 0, dev);
> + watchdog_stop_on_reboot(wdog);
> + watchdog_stop_on_unregister(wdog);
> + watchdog_set_drvdata(wdog, imx7ulp_wdt);
> + imx7ulp_wdt_init(imx7ulp_wdt->base, wdog->timeout * imx7ulp_wdt->rate);
> +
> + ret = devm_watchdog_register_device(dev, wdog);
> + if (ret)
> + goto disable_clk;
> +
> + return 0;
> +
> +disable_clk:
> + clk_disable_unprepare(imx7ulp_wdt->clk);
> +
> + return ret;
> +}
> +
> +static int __maybe_unused imx7ulp_wdt_suspend(struct device *dev)
> +{
> + struct imx7ulp_wdt_device *imx7ulp_wdt = dev_get_drvdata(dev);
> +
> + if (watchdog_active(&imx7ulp_wdt->wdd))
> + imx7ulp_wdt_stop(&imx7ulp_wdt->wdd);
> +
> + clk_disable_unprepare(imx7ulp_wdt->clk);
> +
> + return 0;
> +}
> +
> +static int __maybe_unused imx7ulp_wdt_resume(struct device *dev)
> +{
> + struct imx7ulp_wdt_device *imx7ulp_wdt = dev_get_drvdata(dev);
> + u32 timeout = imx7ulp_wdt->wdd.timeout * imx7ulp_wdt->rate;
> + int ret;
> +
> + ret = clk_prepare_enable(imx7ulp_wdt->clk);
> + if (ret)
> + return ret;
> +
> + if (imx7ulp_wdt_is_enabled(imx7ulp_wdt->base))
> + imx7ulp_wdt_init(imx7ulp_wdt->base, timeout);
> +
> + if (watchdog_active(&imx7ulp_wdt->wdd))
> + imx7ulp_wdt_start(&imx7ulp_wdt->wdd);
> +
> + return 0;
> +}
> +
> +static SIMPLE_DEV_PM_OPS(imx7ulp_wdt_pm_ops, imx7ulp_wdt_suspend,
> + imx7ulp_wdt_resume);
> +
> +static const struct of_device_id imx7ulp_wdt_dt_ids[] = {
> + { .compatible = "fsl,imx7ulp-wdt", },
> + { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, imx7ulp_wdt_dt_ids);
> +
> +static struct platform_driver imx7ulp_wdt_driver = {
> + .probe = imx7ulp_wdt_probe,
> + .driver = {
> + .name = "imx7ulp-wdt",
> + .pm = &imx7ulp_wdt_pm_ops,
> + .of_match_table = imx7ulp_wdt_dt_ids,
> + },
> +};
> +module_platform_driver(imx7ulp_wdt_driver);
> +
> +MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");
> +MODULE_DESCRIPTION("Freescale i.MX7ULP watchdog driver");
> +MODULE_LICENSE("GPL v2");
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH] ARM: dts: vf610-zii-cfu1: Slow I2C0 down to 100kHz
From: Andrew Lunn @ 2019-08-20 15:29 UTC (permalink / raw)
To: Andrey Smirnov
Cc: Shawn Guo, Chris Healy, Fabio Estevam, linux-kernel,
linux-arm-kernel
In-Reply-To: <20190820030804.8892-1-andrew.smirnov@gmail.com>
On Mon, Aug 19, 2019 at 08:08:04PM -0700, Andrey Smirnov wrote:
> Fiber-optic module attached to the bus is only rated to work at
> 100kHz, so drop the bus frequncy to accomodate that.
Hi Andrey
Did you review all the other ZII platforms? I could imaging the same
problem happening else where.
Thanks
Andrew
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCHv2] PM / devfreq: Add dev_pm_qos support
From: Leonard Crestez @ 2019-08-20 15:26 UTC (permalink / raw)
To: Chanwoo Choi
Cc: Artur Świgoń, Saravana Kannan, linux-pm@vger.kernel.org,
Viresh Kumar, Rafael J. Wysocki, Krzysztof Kozlowski, Lukasz Luba,
Kyungmin Park, MyungJoo Ham, Alexandre Bailon,
cpgs (cpgs@samsung.com), Georgi Djakov,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <195bef25-5235-4c24-cc7a-48d368da3bbd@samsung.com>
On 8/14/2019 4:14 AM, Chanwoo Choi wrote:
> On 19. 8. 14. 오전 10:06, Chanwoo Choi wrote:
>> On 19. 8. 13. 오후 8:27, Leonard Crestez wrote:
>>> On 13.08.2019 09:10, Chanwoo Choi wrote:
>>>> In case of cpufreq, cpufreq.c replace the body of store_min_freq()
>>>> and store_max_freq() by using struct dev_pm_qos_request instancce
>>>> with dev_pm_qos_update_request().
>>>>
>>>> If you use the new way with dev_pm_qos_update_request() for
>>>> min_freq_store() and max_freq_store(), it doesn't need to
>>>> get the final frequency from three candidate frequencies.
>>>
>>> Yes, I saw that but didn't implement the equivalent for devfreq because
>>> it's not clear what there is to gain.
>>
>> I think that it is clear. Just use the dev_pm_qos_request interface
>> for both user input through sysfs and device input with qos request.
>> Already PM_QOS has the feature to get the final freuency among
>> the multiple request. When use the dev_pm_qos request, the devfreq
>> doesn't need to compare between user input and device input with qos.
>> It make devfreq core more clear and simple
>>> Since dev_pm_qos is measured in khz it means that min_freq/max_req on
>>> sysfq would lose 3 significant digits, however those digits are probably
>>> useless anyway.
>>
>> I think that it doesn't matter. This patch already considers the this issue
>> by using '* 1000'. We can get either KHz or MHz with additional operation.
>> I think that it is not problem.
It introduces the following issue:
# echo 333333333 > /sys/class/devfreq/devfreq0/min_freq
# cat /sys/class/devfreq/devfreq0/min_freq
333333000
Changing rounding rules could confuse userspace tools. This is not
entirely a new issue because freq values which are not an integer number
of khz are likely not an integer number of hz either.
>> Actually, I think that I want to use the only dev_pm_qos_request
>> for all external request like devfreq cooling of thermal,
>> user input through sysfs and device request with dev_pm_qos_request.
>>
>> Already, dev_pm_qos_request is designed to consider the multiple requirements.
>> We don't need to use the various method (OPP interface, sysfs input, dev_pm_qos)
>> because make it more simple and easy.
>>
>> I think that after finished the review of this patch, I will do refactor the devfreq_cooling.c
>> by using the dev_pm_qos_request. Or, if there are some volunteeer,
>
> Sorry, I would withdraw the this opinion about replacing
> the OPP enable/disable interface with the dev_pm_qos_request
> because even if devfreq-cooling.c needs the 'dev' instance
> to use the dev_pm_qos_request method, it is not clear until now.
> It needs how to get the device instance of devfreq on device-tree.
I looked a bit at the devfreq-cooling implementation and it seems like
there aren't any users in upstream?
As far as I can tell a devfreq implementation needs to call
of_devfreq_cooling_register and then the devfreq cooling code could
register a dev_pm_qos request on devfreq->dev.parent. I'm not sure I
understand what problem you see.
--
Regards,
Leonard
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 3/4] iommu/io-pgtable-arm: Rationalise TCR handling
From: Robin Murphy @ 2019-08-20 15:25 UTC (permalink / raw)
To: Will Deacon; +Cc: robdclark, joro, jcrouse, iommu, linux-arm-kernel
In-Reply-To: <20190820103115.o7neehdethf7sbqi@willie-the-truck>
On 20/08/2019 11:31, Will Deacon wrote:
> On Mon, Aug 19, 2019 at 07:19:30PM +0100, Robin Murphy wrote:
>> Although it's conceptually nice for the io_pgtable_cfg to provide a
>> standard VMSA TCR value, the reality is that no VMSA-compliant IOMMU
>> looks exactly like an Arm CPU, and they all have various other TCR
>> controls which io-pgtable can't be expected to understand. Thus since
>> there is an expectation that drivers will have to add to the given TCR
>> value anyway, let's strip it down to just the essentials that are
>> directly relevant to io-pgatble's inner workings - namely the address
>> sizes, walk attributes, and where appropriate, format selection.
>>
>> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
>> ---
>> drivers/iommu/arm-smmu-v3.c | 7 +------
>> drivers/iommu/arm-smmu.c | 1 +
>> drivers/iommu/arm-smmu.h | 2 ++
>> drivers/iommu/io-pgtable-arm-v7s.c | 6 ++----
>> drivers/iommu/io-pgtable-arm.c | 4 ----
>> drivers/iommu/qcom_iommu.c | 2 +-
>> 6 files changed, 7 insertions(+), 15 deletions(-)
>
> Hmm, so I'm a bit nervous about this one since I think we really should
> be providing a TCR with EPD1 set if we're only giving you TTBR0. Relying
> on the driver to do this worries me. See my comments on the next patch.
The whole idea is that we already know we can't provide a *complete* TCR
value (not least because anything above bit 31 is the wild west), thus
there's really no point in io-pgtable trying to provide anything other
than the parts it definitely controls. It makes sense to provide this
partial TCR value "as if" for TTBR0, since that's the most common case,
but ultimately io-pgatble doesn't know (or need to) which TTBR the
caller intends to actually use for this table. Even if the caller *is*
allocating it for TTBR0, io-pgtable doesn't know that they haven't got
something live in TTBR1 already, so it still wouldn't be in a position
to make the EPD1 call either way.
Ultimately, it's the IOMMU drivers who decide what they put in which
TTBR, so it's the IOMMU drivers which have to take responsibility for
EPD*. Sure you can worry about it, but you can equally worry about them
them misprogramming the ASID or anything else...
Robin.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH RFC] dt-bindings: regulator: define a mux regulator
From: Uwe Kleine-König @ 2019-08-20 15:25 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland
Cc: linux-arm-kernel, devicetree, linux-kernel, kernel
A mux regulator is used to provide current on one of several outputs. It
might look as follows:
,------------.
--<OUT0 A0 <--
--<OUT1 A1 <--
--<OUT2 A2 <--
--<OUT3 |
--<OUT4 EN <--
--<OUT5 |
--<OUT6 IN <--
--<OUT7 |
`------------'
Depending on which address is encoded on the three address inputs A0, A1
and A2 the current provided on IN is provided on one of the eight
outputs.
What is new here is that the binding makes use of a #regulator-cells
property. This uses the approach known from other bindings (e.g. gpio)
to allow referencing all eight outputs with phandle arguments. This
requires an extention in of_get_regulator to use a new variant of
of_parse_phandle_with_args that has a cell_count_default parameter that
is used in absence of a $cell_name property. Even if we'd choose to
update all regulator-bindings to add #regulator-cells = <0>; we still
needed something to implement compatibility to the currently defined
bindings.
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
Hello,
the obvious alternative is to add (here) eight subnodes to represent the
eight outputs. This is IMHO less pretty, but wouldn't need to introduce
#regulator-cells.
Apart from reg = <..> and a phandle there is (I think) nothing that
needs to be specified in the subnodes because all properties of an
output (apart from the address) apply to all outputs.
What do you think?
Best regards
Uwe
.../bindings/regulator/mux-regulator.yaml | 52 +++++++++++++++++++
1 file changed, 52 insertions(+)
create mode 100644 Documentation/devicetree/bindings/regulator/mux-regulator.yaml
diff --git a/Documentation/devicetree/bindings/regulator/mux-regulator.yaml b/Documentation/devicetree/bindings/regulator/mux-regulator.yaml
new file mode 100644
index 000000000000..f06dbb969090
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/mux-regulator.yaml
@@ -0,0 +1,52 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/mux-regulator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MUX regulators
+
+properties:
+ compatible:
+ const: XXX,adb708
+
+ enable-gpios:
+ maxItems: 1
+
+ address-gpios:
+ description: Array of typically three GPIO pins used to select the
+ regulator's output. The least significant address GPIO must be listed
+ first. The others follow in order of significance.
+ minItems: 1
+
+ "#regulator-cells":
+ const: 1
+
+ regulator-name:
+ description: A string used to construct the sub regulator's names
+ $ref: "/schemas/types.yaml#/definitions/string"
+
+ supply:
+ description: input supply
+
+required:
+ - compatible
+ - regulator-name
+ - supply
+
+
+examples:
+ - |
+ mux-regulator {
+ compatible = "regulator-mux";
+
+ regulator-name = "blafasel";
+
+ supply = <&muxin_regulator>;
+
+ enable-gpios = <&gpio2 5 GPIO_ACTIVE_HIGH>;
+ address-gpios = <&gpio2 2 GPIO_ACTIVE_HIGH>,
+ <&gpio2 3 GPIO_ACTIVE_HIGH>,
+ <&gpio2 4 GPIO_ACTIVE_HIGH>,
+ };
+...
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v3 1/2] PM / devfreq: Add dev_pm_qos support
From: Leonard Crestez @ 2019-08-20 15:24 UTC (permalink / raw)
To: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Artur Świgoń
Cc: Jacky Bai, Saravana Kannan, linux-pm, Viresh Kumar,
Krzysztof Kozlowski, Alexandre Bailon, Georgi Djakov,
linux-arm-kernel
In-Reply-To: <cover.1566314535.git.leonard.crestez@nxp.com>
Add dev_pm_qos notifies to devfreq core in order to support frequency
limits via the dev_pm_qos_add_request.
Unlike the rest of devfreq the dev_pm_qos frequency is measured in Khz,
this is consistent with current dev_pm_qos usage for cpufreq and
allows frequencies above 2Ghz (pm_qos expresses limits as s32).
Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
---
drivers/devfreq/devfreq.c | 95 ++++++++++++++++++++++++++++++++++++---
include/linux/devfreq.h | 5 +++
2 files changed, 95 insertions(+), 5 deletions(-)
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 784c08e4f931..58deffa52a37 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -22,10 +22,11 @@
#include <linux/platform_device.h>
#include <linux/list.h>
#include <linux/printk.h>
#include <linux/hrtimer.h>
#include <linux/of.h>
+#include <linux/pm_qos.h>
#include "governor.h"
#define CREATE_TRACE_POINTS
#include <trace/events/devfreq.h>
@@ -96,10 +97,30 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
dev_pm_opp_put(opp);
return max_freq;
}
+static unsigned long get_effective_min_freq(struct devfreq *devfreq)
+{
+ lockdep_assert_held(&devfreq->lock);
+
+ return max3(devfreq->scaling_min_freq, devfreq->min_freq,
+ 1000 * (unsigned long)dev_pm_qos_read_value(
+ devfreq->dev.parent,
+ DEV_PM_QOS_MIN_FREQUENCY));
+}
+
+static unsigned long get_effective_max_freq(struct devfreq *devfreq)
+{
+ lockdep_assert_held(&devfreq->lock);
+
+ return min3(devfreq->scaling_max_freq, devfreq->max_freq,
+ 1000 * (unsigned long)dev_pm_qos_read_value(
+ devfreq->dev.parent,
+ DEV_PM_QOS_MAX_FREQUENCY));
+}
+
/**
* devfreq_get_freq_level() - Lookup freq_table for the frequency
* @devfreq: the devfreq instance
* @freq: the target frequency
*/
@@ -356,12 +377,12 @@ int update_devfreq(struct devfreq *devfreq)
*
* List from the highest priority
* max_freq
* min_freq
*/
- max_freq = min(devfreq->scaling_max_freq, devfreq->max_freq);
- min_freq = max(devfreq->scaling_min_freq, devfreq->min_freq);
+ max_freq = get_effective_max_freq(devfreq);
+ min_freq = get_effective_min_freq(devfreq);
if (freq < min_freq) {
freq = min_freq;
flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */
}
@@ -570,10 +591,37 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
mutex_unlock(&devfreq->lock);
return ret;
}
+static int devfreq_qos_notifier_call(struct devfreq *devfreq)
+{
+ int ret;
+
+ mutex_lock(&devfreq->lock);
+ ret = update_devfreq(devfreq);
+ mutex_unlock(&devfreq->lock);
+
+ return ret;
+}
+
+static int devfreq_qos_min_notifier_call(struct notifier_block *nb,
+ unsigned long val, void *ptr)
+{
+ struct devfreq *devfreq = container_of(nb, struct devfreq, nb_min);
+
+ return devfreq_qos_notifier_call(devfreq);
+}
+
+static int devfreq_qos_max_notifier_call(struct notifier_block *nb,
+ unsigned long val, void *ptr)
+{
+ struct devfreq *devfreq = container_of(nb, struct devfreq, nb_max);
+
+ return devfreq_qos_notifier_call(devfreq);
+}
+
/**
* devfreq_dev_release() - Callback for struct device to release the device.
* @dev: the devfreq device
*
* Remove devfreq from the list and release its resources.
@@ -592,10 +640,14 @@ static void devfreq_dev_release(struct device *dev)
mutex_unlock(&devfreq_list_lock);
if (devfreq->profile->exit)
devfreq->profile->exit(devfreq->dev.parent);
+ dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
+ DEV_PM_QOS_MAX_FREQUENCY);
+ dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
+ DEV_PM_QOS_MIN_FREQUENCY);
mutex_destroy(&devfreq->lock);
kfree(devfreq);
}
/**
@@ -636,21 +688,40 @@ struct devfreq *devfreq_add_device(struct device *dev,
err = -ENOMEM;
goto err_out;
}
mutex_init(&devfreq->lock);
- mutex_lock(&devfreq->lock);
devfreq->dev.parent = dev;
devfreq->dev.class = devfreq_class;
devfreq->dev.release = devfreq_dev_release;
devfreq->profile = profile;
strncpy(devfreq->governor_name, governor_name, DEVFREQ_NAME_LEN);
devfreq->previous_freq = profile->initial_freq;
devfreq->last_status.current_frequency = profile->initial_freq;
devfreq->data = data;
devfreq->nb.notifier_call = devfreq_notifier_call;
+ /*
+ * notifier from pm_qos
+ *
+ * initialized outside of devfreq->lock to avoid circular warning
+ * between devfreq->lock and dev_pm_qos_mtx
+ */
+ devfreq->nb_min.notifier_call = devfreq_qos_min_notifier_call;
+ devfreq->nb_max.notifier_call = devfreq_qos_max_notifier_call;
+
+ err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
+ DEV_PM_QOS_MIN_FREQUENCY);
+ if (err)
+ goto err_dev;
+
+ err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
+ DEV_PM_QOS_MAX_FREQUENCY);
+ if (err)
+ goto err_dev;
+
+ mutex_lock(&devfreq->lock);
if (!devfreq->profile->max_state && !devfreq->profile->freq_table) {
mutex_unlock(&devfreq->lock);
err = set_freq_table(devfreq);
if (err < 0)
goto err_dev;
@@ -741,10 +812,14 @@ struct devfreq *devfreq_add_device(struct device *dev,
mutex_unlock(&devfreq_list_lock);
err_devfreq:
devfreq_remove_device(devfreq);
devfreq = NULL;
err_dev:
+ dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
+ DEV_PM_QOS_MAX_FREQUENCY);
+ dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
+ DEV_PM_QOS_MIN_FREQUENCY);
kfree(devfreq);
err_out:
return ERR_PTR(err);
}
EXPORT_SYMBOL(devfreq_add_device);
@@ -1312,12 +1387,17 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct devfreq *df = to_devfreq(dev);
+ ssize_t ret;
+
+ mutex_lock(&df->lock);
+ ret = sprintf(buf, "%lu\n", get_effective_min_freq(df));
+ mutex_unlock(&df->lock);
- return sprintf(buf, "%lu\n", max(df->scaling_min_freq, df->min_freq));
+ return ret;
}
static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -1357,12 +1437,17 @@ static DEVICE_ATTR_RW(min_freq);
static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct devfreq *df = to_devfreq(dev);
+ ssize_t ret;
- return sprintf(buf, "%lu\n", min(df->scaling_max_freq, df->max_freq));
+ mutex_lock(&df->lock);
+ ret = sprintf(buf, "%lu\n", get_effective_max_freq(df));
+ mutex_unlock(&df->lock);
+
+ return ret;
}
static DEVICE_ATTR_RW(max_freq);
static ssize_t available_frequencies_show(struct device *d,
struct device_attribute *attr,
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index 2bae9ed3c783..8b92ccbd1962 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -134,10 +134,12 @@ struct devfreq_dev_profile {
* @total_trans: Number of devfreq transitions
* @trans_table: Statistics of devfreq transitions
* @time_in_state: Statistics of devfreq states
* @last_stat_updated: The last time stat updated
* @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
+ * @nb_min: Notifier block for DEV_PM_QOS_MIN_FREQUENCY
+ * @nb_max: Notifier block for DEV_PM_QOS_MAX_FREQUENCY
*
* This structure stores the devfreq information for a give device.
*
* Note that when a governor accesses entries in struct devfreq in its
* functions except for the context of callbacks defined in struct
@@ -176,10 +178,13 @@ struct devfreq {
unsigned int *trans_table;
unsigned long *time_in_state;
unsigned long last_stat_updated;
struct srcu_notifier_head transition_notifier_list;
+
+ struct notifier_block nb_min;
+ struct notifier_block nb_max;
};
struct devfreq_freqs {
unsigned long old;
unsigned long new;
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox