* [PATCH v2 4/7] arm64: dts: actions: Add uSD and eMMC support for Bubblegum96
From: Manivannan Sadhasivam @ 2019-08-21 2:40 UTC (permalink / raw)
To: ulf.hansson, afaerber, robh+dt, sboyd
Cc: devicetree, linux-mmc, linus.walleij, linux-actions, linux-kernel,
thomas.liau, Manivannan Sadhasivam, linux-clk, linux-arm-kernel
In-Reply-To: <20190821024014.14070-1-manivannan.sadhasivam@linaro.org>
Add uSD and eMMC support for Bubblegum96 board based on Actions Semi
Owl SoC. SD0 is connected to uSD slot and SD2 is connected to eMMC.
Since there is no PMIC support added yet, fixed regulator has been
used as a regulator node.
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
.../boot/dts/actions/s900-bubblegum-96.dts | 60 +++++++++++++++++++
1 file changed, 60 insertions(+)
diff --git a/arch/arm64/boot/dts/actions/s900-bubblegum-96.dts b/arch/arm64/boot/dts/actions/s900-bubblegum-96.dts
index 732daaa6e9d3..92376b71cb8f 100644
--- a/arch/arm64/boot/dts/actions/s900-bubblegum-96.dts
+++ b/arch/arm64/boot/dts/actions/s900-bubblegum-96.dts
@@ -12,6 +12,9 @@
model = "Bubblegum-96";
aliases {
+ mmc0 = &mmc0;
+ mmc1 = &mmc1;
+ mmc2 = &mmc2;
serial5 = &uart5;
};
@@ -23,6 +26,22 @@
device_type = "memory";
reg = <0x0 0x0 0x0 0x80000000>;
};
+
+ vcc_3v1: vcc-3v1 {
+ compatible = "regulator-fixed";
+ regulator-name = "fixed-3.1V";
+ regulator-min-microvolt = <3100000>;
+ regulator-max-microvolt = <3100000>;
+ regulator-always-on;
+ };
+
+ sd_vcc: sd-vcc {
+ compatible = "regulator-fixed";
+ regulator-name = "fixed-3.1V";
+ regulator-min-microvolt = <3100000>;
+ regulator-max-microvolt = <3100000>;
+ regulator-always-on;
+ };
};
&i2c0 {
@@ -241,6 +260,47 @@
bias-pull-up;
};
};
+
+ mmc0_default: mmc0_default {
+ pinmux {
+ groups = "sd0_d0_mfp", "sd0_d1_mfp", "sd0_d2_d3_mfp",
+ "sd0_cmd_mfp", "sd0_clk_mfp";
+ function = "sd0";
+ };
+ };
+
+ mmc2_default: mmc2_default {
+ pinmux {
+ groups = "nand0_d0_ceb3_mfp";
+ function = "sd2";
+ };
+ };
+};
+
+/* uSD */
+&mmc0 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_default>;
+ no-sdio;
+ no-mmc;
+ no-1-8-v;
+ cd-gpios = <&pinctrl 120 GPIO_ACTIVE_LOW>;
+ bus-width = <4>;
+ vmmc-supply = <&sd_vcc>;
+ vqmmc-supply = <&sd_vcc>;
+};
+
+/* eMMC */
+&mmc2 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_default>;
+ no-sdio;
+ no-sd;
+ non-removable;
+ bus-width = <8>;
+ vmmc-supply = <&vcc_3v1>;
};
&timer {
--
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] arm64: dts: actions: Add MMC controller support for S900
From: Manivannan Sadhasivam @ 2019-08-21 2:40 UTC (permalink / raw)
To: ulf.hansson, afaerber, robh+dt, sboyd
Cc: devicetree, linux-mmc, linus.walleij, linux-actions, linux-kernel,
thomas.liau, Manivannan Sadhasivam, linux-clk, linux-arm-kernel
In-Reply-To: <20190821024014.14070-1-manivannan.sadhasivam@linaro.org>
Add MMC controller support for Actions Semi S900 SoC. There are 4 MMC
controllers in this SoC which can be used for accessing SD/MMC/SDIO cards.
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
arch/arm64/boot/dts/actions/s900.dtsi | 45 +++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/arch/arm64/boot/dts/actions/s900.dtsi b/arch/arm64/boot/dts/actions/s900.dtsi
index df3a68a3ac97..eb35cf78ab73 100644
--- a/arch/arm64/boot/dts/actions/s900.dtsi
+++ b/arch/arm64/boot/dts/actions/s900.dtsi
@@ -4,6 +4,7 @@
*/
#include <dt-bindings/clock/actions,s900-cmu.h>
+#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/reset/actions,s900-reset.h>
@@ -284,5 +285,49 @@
dma-requests = <46>;
clocks = <&cmu CLK_DMAC>;
};
+
+ mmc0: mmc@e0330000 {
+ compatible = "actions,owl-mmc";
+ reg = <0x0 0xe0330000 0x0 0x4000>;
+ interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cmu CLK_SD0>;
+ resets = <&cmu RESET_SD0>;
+ dmas = <&dma 2>;
+ dma-names = "mmc";
+ status = "disabled";
+ };
+
+ mmc1: mmc@e0334000 {
+ compatible = "actions,owl-mmc";
+ reg = <0x0 0xe0334000 0x0 0x4000>;
+ interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cmu CLK_SD1>;
+ resets = <&cmu RESET_SD1>;
+ dmas = <&dma 3>;
+ dma-names = "mmc";
+ status = "disabled";
+ };
+
+ mmc2: mmc@e0338000 {
+ compatible = "actions,owl-mmc";
+ reg = <0x0 0xe0338000 0x0 0x4000>;
+ interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cmu CLK_SD2>;
+ resets = <&cmu RESET_SD2>;
+ dmas = <&dma 4>;
+ dma-names = "mmc";
+ status = "disabled";
+ };
+
+ mmc3: mmc@e033c000 {
+ compatible = "actions,owl-mmc";
+ reg = <0x0 0xe033c000 0x0 0x4000>;
+ interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cmu CLK_SD3>;
+ resets = <&cmu RESET_SD3>;
+ dmas = <&dma 46>;
+ dma-names = "mmc";
+ status = "disabled";
+ };
};
};
--
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: mmc: Add Actions Semi SD/MMC/SDIO controller binding
From: Manivannan Sadhasivam @ 2019-08-21 2:40 UTC (permalink / raw)
To: ulf.hansson, afaerber, robh+dt, sboyd
Cc: devicetree, linux-mmc, linus.walleij, linux-actions, linux-kernel,
thomas.liau, Manivannan Sadhasivam, linux-clk, linux-arm-kernel
In-Reply-To: <20190821024014.14070-1-manivannan.sadhasivam@linaro.org>
Add devicetree YAML binding for Actions Semi Owl SoC's SD/MMC/SDIO
controller.
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
.../devicetree/bindings/mmc/owl-mmc.yaml | 62 +++++++++++++++++++
1 file changed, 62 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mmc/owl-mmc.yaml
diff --git a/Documentation/devicetree/bindings/mmc/owl-mmc.yaml b/Documentation/devicetree/bindings/mmc/owl-mmc.yaml
new file mode 100644
index 000000000000..f7eff4c43017
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/owl-mmc.yaml
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mmc/owl-mmc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Actions Semi Owl SoCs SD/MMC/SDIO controller
+
+allOf:
+ - $ref: "mmc-controller.yaml"
+
+maintainers:
+ - Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+
+properties:
+ "#address-cells": true
+ "#size-cells": true
+
+ compatible:
+ const: actions,owl-mmc
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ minItems: 1
+
+ resets:
+ maxItems: 1
+
+ dmas:
+ maxItems: 1
+
+ dma-names:
+ const: mmc
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - resets
+ - dmas
+ - dma-names
+
+examples:
+ - |
+ mmc0: mmc@e0330000 {
+ compatible = "actions,owl-mmc";
+ reg = <0x0 0xe0330000 0x0 0x4000>;
+ interrupts = <0 42 4>;
+ clocks = <&cmu 56>;
+ resets = <&cmu 23>;
+ dmas = <&dma 2>;
+ dma-names = "mmc";
+ bus-width = <4>;
+ };
+
+...
--
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: actions: Fix factor clk struct member access
From: Manivannan Sadhasivam @ 2019-08-21 2:40 UTC (permalink / raw)
To: ulf.hansson, afaerber, robh+dt, sboyd
Cc: devicetree, linux-mmc, linus.walleij, linux-actions, linux-kernel,
thomas.liau, Manivannan Sadhasivam, linux-clk, linux-arm-kernel
In-Reply-To: <20190821024014.14070-1-manivannan.sadhasivam@linaro.org>
Since the helper "owl_factor_helper_round_rate" is shared between factor
and composite clocks, using the factor clk specific helper function
like "hw_to_owl_factor" to access its members will create issues when
called from composite clk specific code. Hence, pass the "factor_hw"
struct pointer directly instead of fetching it using factor clk specific
helpers.
This issue has been observed when a composite clock like "sd0_clk" tried
to call "owl_factor_helper_round_rate" resulting in pointer dereferencing
error.
While we are at it, let's rename the "clk_val_best" function to
"owl_clk_val_best" since this is an owl SoCs specific helper.
Fixes: 4bb78fc9744a ("clk: actions: Add factor clock support")
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Reviewed-by: Stephen Boyd <sboyd@kernel.org>
---
drivers/clk/actions/owl-factor.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/clk/actions/owl-factor.c b/drivers/clk/actions/owl-factor.c
index 317d4a9e112e..f15e2621fa18 100644
--- a/drivers/clk/actions/owl-factor.c
+++ b/drivers/clk/actions/owl-factor.c
@@ -64,11 +64,10 @@ static unsigned int _get_table_val(const struct clk_factor_table *table,
return val;
}
-static int clk_val_best(struct clk_hw *hw, unsigned long rate,
+static int owl_clk_val_best(const struct owl_factor_hw *factor_hw,
+ struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate)
{
- struct owl_factor *factor = hw_to_owl_factor(hw);
- struct owl_factor_hw *factor_hw = &factor->factor_hw;
const struct clk_factor_table *clkt = factor_hw->table;
unsigned long parent_rate, try_parent_rate, best = 0, cur_rate;
unsigned long parent_rate_saved = *best_parent_rate;
@@ -126,7 +125,7 @@ long owl_factor_helper_round_rate(struct owl_clk_common *common,
const struct clk_factor_table *clkt = factor_hw->table;
unsigned int val, mul = 0, div = 1;
- val = clk_val_best(&common->hw, rate, parent_rate);
+ val = owl_clk_val_best(factor_hw, &common->hw, rate, parent_rate);
_get_table_div_mul(clkt, val, &mul, &div);
return *parent_rate * mul / div;
--
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] Add SD/MMC driver for Actions Semi S900 SoC
From: Manivannan Sadhasivam @ 2019-08-21 2:40 UTC (permalink / raw)
To: ulf.hansson, afaerber, robh+dt, sboyd
Cc: devicetree, linux-mmc, linus.walleij, linux-actions, linux-kernel,
thomas.liau, Manivannan Sadhasivam, linux-clk, linux-arm-kernel
Hello,
This patchset adds SD/MMC driver for Actions Semi S900 SoC from Owl
family SoCs. There are 4 SD/MMC controller present in this SoC but
only 2 are enabled currently for Bubblegum96 board to access uSD and
onboard eMMC. SDIO support for this driver is not currently implemented.
Note: Currently, driver uses 2 completion mechanisms for maintaining
the coherency between SDC and DMA interrupts and I know that it is not
efficient. Hence, I'd like to hear any suggestions for reimplementing
the logic if anyone has.
With this driver, this patchset also fixes one clk driver issue and enables
the Actions Semi platform in ARM64 defconfig.
Thanks,
Mani
Changes in v2:
* Converted the devicetree bindings to YAML
* Misc changes to bubblegum devicetree as per the review from Andreas
* Dropped the read/write wrappers and renamed all functions to use owl-
prefix as per the review from Ulf
* Renamed clk_val_best to owl_clk_val_best and added Reviewed-by tag
from Stephen
Manivannan Sadhasivam (7):
clk: actions: Fix factor clk struct member access
dt-bindings: mmc: Add Actions Semi SD/MMC/SDIO controller binding
arm64: dts: actions: Add MMC controller support for S900
arm64: dts: actions: Add uSD and eMMC support for Bubblegum96
mmc: Add Actions Semi Owl SoCs SD/MMC driver
MAINTAINERS: Add entry for Actions Semi SD/MMC driver and binding
arm64: configs: Enable Actions Semi platform in defconfig
.../devicetree/bindings/mmc/owl-mmc.yaml | 62 ++
MAINTAINERS | 2 +
.../boot/dts/actions/s900-bubblegum-96.dts | 60 ++
arch/arm64/boot/dts/actions/s900.dtsi | 45 ++
arch/arm64/configs/defconfig | 1 +
drivers/clk/actions/owl-factor.c | 7 +-
drivers/mmc/host/Kconfig | 8 +
drivers/mmc/host/Makefile | 1 +
drivers/mmc/host/owl-mmc.c | 696 ++++++++++++++++++
9 files changed, 878 insertions(+), 4 deletions(-)
create mode 100644 Documentation/devicetree/bindings/mmc/owl-mmc.yaml
create mode 100644 drivers/mmc/host/owl-mmc.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 V2 2/4] watchdog: Add i.MX7ULP watchdog support
From: Anson Huang @ 2019-08-21 2:27 UTC (permalink / raw)
To: Guenter Roeck
Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, Leonard Crestez,
schnitzeltony@gmail.com, linux-watchdog@vger.kernel.org,
otavio@ossystems.com.br, festevam@gmail.com,
s.hauer@pengutronix.de, jan.tuerk@emtrion.com,
linux@armlinux.org.uk, linux-kernel@vger.kernel.org,
robh+dt@kernel.org, dl-linux-imx, kernel@pengutronix.de,
u.kleine-koenig@pengutronix.de, wim@linux-watchdog.org,
shawnguo@kernel.org, linux-arm-kernel@lists.infradead.org
In-Reply-To: <20190820154815.GA20033@roeck-us.net>
Hi, Guenter
> 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;
> ...
>
Ah, yes, I added the error handle but missed the remove case, thanks for your kindly
suggestion, please help review V3.
Thanks,
Anson.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH V3 4/4] ARM: dts: imx7ulp: Add wdog1 node
From: Anson Huang @ 2019-08-21 2:07 UTC (permalink / raw)
To: wim, linux, robh+dt, mark.rutland, shawnguo, s.hauer, kernel,
festevam, linux, otavio, leonard.crestez, schnitzeltony,
u.kleine-koenig, jan.tuerk, linux-watchdog, devicetree,
linux-arm-kernel, linux-kernel
Cc: Linux-imx
In-Reply-To: <1566353278-1884-1-git-send-email-Anson.Huang@nxp.com>
Add wdog1 node to support watchdog driver.
Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
---
No changes.
---
arch/arm/boot/dts/imx7ulp.dtsi | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/arm/boot/dts/imx7ulp.dtsi b/arch/arm/boot/dts/imx7ulp.dtsi
index 6859a3a..1fdb5a35 100644
--- a/arch/arm/boot/dts/imx7ulp.dtsi
+++ b/arch/arm/boot/dts/imx7ulp.dtsi
@@ -264,6 +264,16 @@
#clock-cells = <1>;
};
+ wdog1: wdog@403d0000 {
+ compatible = "fsl,imx7ulp-wdt";
+ reg = <0x403d0000 0x10000>;
+ interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&pcc2 IMX7ULP_CLK_WDG1>;
+ assigned-clocks = <&pcc2 IMX7ULP_CLK_WDG1>;
+ assigned-clocks-parents = <&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>;
+ timeout-sec = <40>;
+ };
+
pcc2: clock-controller@403f0000 {
compatible = "fsl,imx7ulp-pcc2";
reg = <0x403f0000 0x10000>;
--
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 5/7] mmc: Add Actions Semi Owl SoCs SD/MMC driver
From: Manivannan Sadhasivam @ 2019-08-21 2:26 UTC (permalink / raw)
To: Ulf Hansson
Cc: DTML, Stephen Boyd, linux-actions, Linus Walleij,
linux-mmc@vger.kernel.org, Linux Kernel Mailing List, thomas.liau,
linux-clk, Rob Herring, Andreas Färber, Linux ARM
In-Reply-To: <CAPDyKFqE1Vnmq4yeoQxjgOZTTrA_k7jAZHwq5RExX4hS-rTftw@mail.gmail.com>
Hi Ulf,
Sorry for the delay!
On Mon, Jul 22, 2019 at 03:41:59PM +0200, Ulf Hansson wrote:
> On Sat, 8 Jun 2019 at 21:54, Manivannan Sadhasivam
> <manivannan.sadhasivam@linaro.org> wrote:
> >
> > Add SD/MMC driver for Actions Semi Owl SoCs. This driver currently
> > supports standard, high speed, SDR12, SDR25 and SDR50. DDR50 mode is
> > supported but it is untested. There is no SDIO support for now.
> >
> > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > ---
> > drivers/mmc/host/Kconfig | 8 +
> > drivers/mmc/host/Makefile | 1 +
> > drivers/mmc/host/owl-mmc.c | 705 +++++++++++++++++++++++++++++++++++++
> > 3 files changed, 714 insertions(+)
> > create mode 100644 drivers/mmc/host/owl-mmc.c
> >
> > diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> > index 931770f17087..7ae65eff26a4 100644
> > --- a/drivers/mmc/host/Kconfig
> > +++ b/drivers/mmc/host/Kconfig
> > @@ -1006,3 +1006,11 @@ config MMC_SDHCI_AM654
> > If you have a controller with this interface, say Y or M here.
> >
> > If unsure, say N.
> > +
> > +config MMC_OWL
> > + tristate "Actions Semi Owl SD/MMC Host Controller support"
> > + depends on HAS_DMA
> > + depends on ARCH_ACTIONS || COMPILE_TEST
> > + help
> > + This selects support for the SD/MMC Host Controller on
> > + Actions Semi Owl SoCs.
> > diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
> > index 73578718f119..41a0b1728389 100644
> > --- a/drivers/mmc/host/Makefile
> > +++ b/drivers/mmc/host/Makefile
> > @@ -73,6 +73,7 @@ obj-$(CONFIG_MMC_SUNXI) += sunxi-mmc.o
> > obj-$(CONFIG_MMC_USDHI6ROL0) += usdhi6rol0.o
> > obj-$(CONFIG_MMC_TOSHIBA_PCI) += toshsd.o
> > obj-$(CONFIG_MMC_BCM2835) += bcm2835.o
> > +obj-$(CONFIG_MMC_OWL) += owl-mmc.o
> >
> > obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o
> > obj-$(CONFIG_MMC_REALTEK_USB) += rtsx_usb_sdmmc.o
> > diff --git a/drivers/mmc/host/owl-mmc.c b/drivers/mmc/host/owl-mmc.c
> > new file mode 100644
> > index 000000000000..8158ebedb2a4
> > --- /dev/null
> > +++ b/drivers/mmc/host/owl-mmc.c
> > @@ -0,0 +1,705 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + * Actions Semi Owl SoCs SD/MMC driver
> > + *
> > + * Copyright (c) 2014 Actions Semi Inc.
> > + * Copyright (c) 2019 Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > + *
> > + * TODO: SDIO support
> > + */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/delay.h>
> > +#include <linux/dmaengine.h>
> > +#include <linux/dma-direction.h>
> > +#include <linux/dma-mapping.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/mmc/host.h>
> > +#include <linux/mmc/slot-gpio.h>
> > +#include <linux/module.h>
> > +#include <linux/of_platform.h>
> > +#include <linux/reset.h>
> > +#include <linux/spinlock.h>
> > +
> > +/*
> > + * SDC registers
> > + */
> > +#define OWL_REG_SD_EN 0x0000
> > +#define OWL_REG_SD_CTL 0x0004
> > +#define OWL_REG_SD_STATE 0x0008
> > +#define OWL_REG_SD_CMD 0x000c
> > +#define OWL_REG_SD_ARG 0x0010
> > +#define OWL_REG_SD_RSPBUF0 0x0014
> > +#define OWL_REG_SD_RSPBUF1 0x0018
> > +#define OWL_REG_SD_RSPBUF2 0x001c
> > +#define OWL_REG_SD_RSPBUF3 0x0020
> > +#define OWL_REG_SD_RSPBUF4 0x0024
> > +#define OWL_REG_SD_DAT 0x0028
> > +#define OWL_REG_SD_BLK_SIZE 0x002c
> > +#define OWL_REG_SD_BLK_NUM 0x0030
> > +#define OWL_REG_SD_BUF_SIZE 0x0034
> > +
> > +/* SD_EN Bits */
> > +#define OWL_SD_EN_RANE BIT(31)
> > +#define OWL_SD_EN_RAN_SEED(x) (((x) & 0x3f) << 24)
> > +#define OWL_SD_EN_S18EN BIT(12)
> > +#define OWL_SD_EN_RESE BIT(10)
> > +#define OWL_SD_EN_DAT1_S BIT(9)
> > +#define OWL_SD_EN_CLK_S BIT(8)
> > +#define OWL_SD_ENABLE BIT(7)
> > +#define OWL_SD_EN_BSEL BIT(6)
> > +#define OWL_SD_EN_SDIOEN BIT(3)
> > +#define OWL_SD_EN_DDREN BIT(2)
> > +#define OWL_SD_EN_DATAWID(x) (((x) & 0x3) << 0)
> > +
> > +/* SD_CTL Bits */
> > +#define OWL_SD_CTL_TOUTEN BIT(31)
> > +#define OWL_SD_CTL_TOUTCNT(x) (((x) & 0x7f) << 24)
> > +#define OWL_SD_CTL_DELAY_MSK GENMASK(23, 16)
> > +#define OWL_SD_CTL_RDELAY(x) (((x) & 0xf) << 20)
> > +#define OWL_SD_CTL_WDELAY(x) (((x) & 0xf) << 16)
> > +#define OWL_SD_CTL_CMDLEN BIT(13)
> > +#define OWL_SD_CTL_SCC BIT(12)
> > +#define OWL_SD_CTL_TCN(x) (((x) & 0xf) << 8)
> > +#define OWL_SD_CTL_TS BIT(7)
> > +#define OWL_SD_CTL_LBE BIT(6)
> > +#define OWL_SD_CTL_C7EN BIT(5)
> > +#define OWL_SD_CTL_TM(x) (((x) & 0xf) << 0)
> > +
> > +#define OWL_SD_DELAY_LOW_CLK 0x0f
> > +#define OWL_SD_DELAY_MID_CLK 0x0a
> > +#define OWL_SD_DELAY_HIGH_CLK 0x09
> > +#define OWL_SD_RDELAY_DDR50 0x0a
> > +#define OWL_SD_WDELAY_DDR50 0x08
> > +
> > +/* SD_STATE Bits */
> > +#define OWL_SD_STATE_DAT1BS BIT(18)
> > +#define OWL_SD_STATE_SDIOB_P BIT(17)
> > +#define OWL_SD_STATE_SDIOB_EN BIT(16)
> > +#define OWL_SD_STATE_TOUTE BIT(15)
> > +#define OWL_SD_STATE_BAEP BIT(14)
> > +#define OWL_SD_STATE_MEMRDY BIT(12)
> > +#define OWL_SD_STATE_CMDS BIT(11)
> > +#define OWL_SD_STATE_DAT1AS BIT(10)
> > +#define OWL_SD_STATE_SDIOA_P BIT(9)
> > +#define OWL_SD_STATE_SDIOA_EN BIT(8)
> > +#define OWL_SD_STATE_DAT0S BIT(7)
> > +#define OWL_SD_STATE_TEIE BIT(6)
> > +#define OWL_SD_STATE_TEI BIT(5)
> > +#define OWL_SD_STATE_CLNR BIT(4)
> > +#define OWL_SD_STATE_CLC BIT(3)
> > +#define OWL_SD_STATE_WC16ER BIT(2)
> > +#define OWL_SD_STATE_RC16ER BIT(1)
> > +#define OWL_SD_STATE_CRC7ER BIT(0)
> > +
> > +struct owl_mmc_host {
> > + struct device *dev;
> > + struct reset_control *reset;
> > + void __iomem *base;
> > + struct clk *clk;
> > + struct completion sdc_complete;
> > + spinlock_t lock;
> > + int irq;
> > + u32 clock;
> > + bool ddr_50;
> > +
> > + enum dma_data_direction dma_dir;
> > + struct dma_chan *dma;
> > + struct dma_async_tx_descriptor *desc;
> > + struct dma_slave_config dma_cfg;
> > + struct completion dma_complete;
> > +
> > + struct mmc_host *mmc;
> > + struct mmc_request *mrq;
> > + struct mmc_command *cmd;
> > + struct mmc_data *data;
> > +};
> > +
> > +static inline void mmc_writel(struct owl_mmc_host *owl_host, u32 reg, u32 data)
> > +{
> > + writel(data, owl_host->base + reg);
> > +}
> > +
> > +static inline u32 mmc_readl(struct owl_mmc_host *owl_host, u32 reg)
> > +{
> > + return readl(owl_host->base + reg);
> > +}
>
> Please drop these wrappers, as they don't make the code more readable.
>
Okay.
> > +
> > +static void mmc_update_reg(void __iomem *reg, unsigned int val, bool state)
>
> Please use the "owl" as prefix for function names, that makes it more
> consistent.
>
Okay.
> > +{
> > + unsigned int regval;
> > +
> > + regval = readl(reg);
>
> Rather than reading the register here, perhaps you could use a
> variable for caching the register value. Thus avoiding to read the
> register for every update.
>
Some of the registers are non cacheable, for instance STATE register.
So, I'll keep this as it is.
Thanks,
Mani
>
> > +
> > + if (state)
> > + regval |= val;
> > + else
> > + regval &= ~val;
> > +
> > + writel(regval, reg);
> > +}
> > +
> > +static irqreturn_t owl_irq_handler(int irq, void *devid)
> > +{
> > + struct owl_mmc_host *owl_host = devid;
> > + unsigned long flags;
> > + u32 state;
> > +
> > + spin_lock_irqsave(&owl_host->lock, flags);
> > +
> > + state = mmc_readl(owl_host, OWL_REG_SD_STATE);
> > + if (state & OWL_SD_STATE_TEI) {
> > + state = mmc_readl(owl_host, OWL_REG_SD_STATE);
> > + state |= OWL_SD_STATE_TEI;
> > + mmc_writel(owl_host, OWL_REG_SD_STATE, state);
> > + complete(&owl_host->sdc_complete);
> > + }
> > +
> > + spin_unlock_irqrestore(&owl_host->lock, flags);
> > +
> > + return IRQ_HANDLED;
> > +}
> > +
> > +static void owl_mmc_finish_request(struct owl_mmc_host *owl_host)
> > +{
> > + struct mmc_request *mrq = owl_host->mrq;
> > + struct mmc_data *data = mrq->data;
> > +
> > + /* Should never be NULL */
> > + WARN_ON(!mrq);
> > +
> > + owl_host->mrq = NULL;
> > +
> > + if (data)
> > + dma_unmap_sg(owl_host->dma->device->dev, data->sg, data->sg_len,
> > + owl_host->dma_dir);
> > +
> > + /* Finally finish request */
> > + mmc_request_done(owl_host->mmc, mrq);
> > +}
> > +
> > +static void owl_mmc_send_cmd(struct owl_mmc_host *owl_host,
> > + struct mmc_command *cmd,
> > + struct mmc_data *data)
> > +{
> > + u32 mode, state, resp[2];
> > + u32 cmd_rsp_mask = 0;
> > +
> > + init_completion(&owl_host->sdc_complete);
> > +
> > + switch (mmc_resp_type(cmd)) {
> > + case MMC_RSP_NONE:
> > + mode = OWL_SD_CTL_TM(0);
> > + break;
> > +
> > + case MMC_RSP_R1:
> > + if (data) {
> > + if (data->flags & MMC_DATA_READ)
> > + mode = OWL_SD_CTL_TM(4);
> > + else
> > + mode = OWL_SD_CTL_TM(5);
> > + } else {
> > + mode = OWL_SD_CTL_TM(1);
> > + }
> > + cmd_rsp_mask = OWL_SD_STATE_CLNR | OWL_SD_STATE_CRC7ER;
> > +
> > + break;
> > +
> > + case MMC_RSP_R1B:
> > + mode = OWL_SD_CTL_TM(3);
> > + cmd_rsp_mask = OWL_SD_STATE_CLNR | OWL_SD_STATE_CRC7ER;
> > + break;
> > +
> > + case MMC_RSP_R2:
> > + mode = OWL_SD_CTL_TM(2);
> > + cmd_rsp_mask = OWL_SD_STATE_CLNR | OWL_SD_STATE_CRC7ER;
> > + break;
> > +
> > + case MMC_RSP_R3:
> > + mode = OWL_SD_CTL_TM(1);
> > + cmd_rsp_mask = OWL_SD_STATE_CLNR;
> > + break;
> > +
> > + default:
> > + dev_warn(owl_host->dev, "Unknown MMC command\n");
> > + cmd->error = -EINVAL;
> > + return;
> > + }
> > +
> > + /* Keep current WDELAY and RDELAY */
> > + mode |= (mmc_readl(owl_host, OWL_REG_SD_CTL) & (0xff << 16));
> > +
> > + /* Start to send corresponding command type */
> > + mmc_writel(owl_host, OWL_REG_SD_ARG, cmd->arg);
> > + mmc_writel(owl_host, OWL_REG_SD_CMD, cmd->opcode);
> > +
> > + /* Set LBE to send clk at the end of last read block */
> > + if (data) {
> > + mode |= (OWL_SD_CTL_TS | OWL_SD_CTL_LBE | 0x64000000);
> > + } else {
> > + mode &= ~(OWL_SD_CTL_TOUTEN | OWL_SD_CTL_LBE);
> > + mode |= OWL_SD_CTL_TS;
> > + }
> > +
> > + owl_host->cmd = cmd;
> > +
> > + /* Start transfer */
> > + mmc_writel(owl_host, OWL_REG_SD_CTL, mode);
> > +
> > + if (data)
> > + return;
> > +
> > + if (!wait_for_completion_timeout(&owl_host->sdc_complete, 30 * HZ)) {
> > + dev_err(owl_host->dev, "CMD interrupt timeout\n");
> > + cmd->error = -ETIMEDOUT;
> > + return;
> > + }
> > +
> > + state = mmc_readl(owl_host, OWL_REG_SD_STATE);
> > + if (mmc_resp_type(cmd) & MMC_RSP_PRESENT) {
> > + if (cmd_rsp_mask & state) {
> > + if (state & OWL_SD_STATE_CLNR) {
> > + dev_err(owl_host->dev, "Error CMD_NO_RSP\n");
> > + cmd->error = -EILSEQ;
> > + return;
> > + }
> > +
> > + if (state & OWL_SD_STATE_CRC7ER) {
> > + dev_err(owl_host->dev, "Error CMD_RSP_CRC\n");
> > + cmd->error = -EILSEQ;
> > + return;
> > + }
> > + }
> > +
> > + if (mmc_resp_type(cmd) & MMC_RSP_136) {
> > + cmd->resp[3] = mmc_readl(owl_host, OWL_REG_SD_RSPBUF0);
> > + cmd->resp[2] = mmc_readl(owl_host, OWL_REG_SD_RSPBUF1);
> > + cmd->resp[1] = mmc_readl(owl_host, OWL_REG_SD_RSPBUF2);
> > + cmd->resp[0] = mmc_readl(owl_host, OWL_REG_SD_RSPBUF3);
> > + } else {
> > + resp[0] = mmc_readl(owl_host, OWL_REG_SD_RSPBUF0);
> > + resp[1] = mmc_readl(owl_host, OWL_REG_SD_RSPBUF1);
> > + cmd->resp[0] = resp[1] << 24 | resp[0] >> 8;
> > + cmd->resp[1] = resp[1] >> 8;
> > + }
> > + }
> > +}
> > +
> > +static void owl_mmc_dma_complete(void *param)
> > +{
> > + struct owl_mmc_host *owl_host = param;
> > + struct mmc_data *data = owl_host->data;
> > +
> > + if (data)
> > + complete(&owl_host->dma_complete);
> > +}
> > +
> > +static int owl_mmc_prepare_data(struct owl_mmc_host *owl_host,
> > + struct mmc_data *data)
> > +{
> > + u32 total;
> > +
> > + mmc_update_reg(owl_host->base + OWL_REG_SD_EN, OWL_SD_EN_BSEL, true);
> > + mmc_writel(owl_host, OWL_REG_SD_BLK_NUM, data->blocks);
> > + mmc_writel(owl_host, OWL_REG_SD_BLK_SIZE, data->blksz);
> > + total = data->blksz * data->blocks;
> > +
> > + if (total < 512)
> > + mmc_writel(owl_host, OWL_REG_SD_BUF_SIZE, total);
> > + else
> > + mmc_writel(owl_host, OWL_REG_SD_BUF_SIZE, 512);
> > +
> > + if (data->flags & MMC_DATA_WRITE) {
> > + owl_host->dma_dir = DMA_TO_DEVICE;
> > + owl_host->dma_cfg.direction = DMA_MEM_TO_DEV;
> > + } else {
> > + owl_host->dma_dir = DMA_FROM_DEVICE;
> > + owl_host->dma_cfg.direction = DMA_DEV_TO_MEM;
> > + }
> > +
> > + dma_map_sg(owl_host->dma->device->dev, data->sg,
> > + data->sg_len, owl_host->dma_dir);
> > +
> > + dmaengine_slave_config(owl_host->dma, &owl_host->dma_cfg);
> > + owl_host->desc = dmaengine_prep_slave_sg(owl_host->dma, data->sg,
> > + data->sg_len,
> > + owl_host->dma_cfg.direction,
> > + DMA_PREP_INTERRUPT |
> > + DMA_CTRL_ACK);
> > + if (!owl_host->desc) {
> > + dev_err(owl_host->dev, "Can't prepare slave sg\n");
> > + return -EBUSY;
> > + }
> > +
> > + owl_host->data = data;
> > +
> > + owl_host->desc->callback = owl_mmc_dma_complete;
> > + owl_host->desc->callback_param = (void *)owl_host;
> > + data->error = 0;
> > +
> > + return 0;
> > +}
> > +
> > +static void owl_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
> > +{
> > + struct owl_mmc_host *owl_host = mmc_priv(mmc);
> > + struct mmc_data *data = mrq->data;
> > + int ret;
> > +
> > + owl_host->mrq = mrq;
> > + if (mrq->data) {
> > + ret = owl_mmc_prepare_data(owl_host, data);
> > + if (ret < 0) {
> > + data->error = ret;
> > + goto err_out;
> > + }
> > +
> > + init_completion(&owl_host->dma_complete);
> > + dmaengine_submit(owl_host->desc);
> > + dma_async_issue_pending(owl_host->dma);
> > + }
> > +
> > + owl_mmc_send_cmd(owl_host, mrq->cmd, data);
> > +
> > + if (data) {
> > + if (!wait_for_completion_timeout(&owl_host->sdc_complete,
> > + 10 * HZ)) {
> > + dev_err(owl_host->dev, "CMD interrupt timeout\n");
> > + mrq->cmd->error = -ETIMEDOUT;
> > + dmaengine_terminate_all(owl_host->dma);
> > + goto err_out;
> > + }
> > +
> > + if (!wait_for_completion_timeout(&owl_host->dma_complete,
> > + 5 * HZ)) {
> > + dev_err(owl_host->dev, "DMA interrupt timeout\n");
> > + mrq->cmd->error = -ETIMEDOUT;
> > + dmaengine_terminate_all(owl_host->dma);
> > + goto err_out;
> > + }
> > +
> > + if (data->stop)
> > + owl_mmc_send_cmd(owl_host, data->stop, NULL);
> > +
> > + data->bytes_xfered = data->blocks * data->blksz;
> > + }
> > +
> > +err_out:
> > + owl_mmc_finish_request(owl_host);
> > +}
> > +
> > +static int owl_mmc_set_clk_rate(struct owl_mmc_host *owl_host,
> > + unsigned int rate)
> > +{
> > + unsigned long clk_rate;
> > + int ret;
> > + u32 reg;
> > +
> > + reg = mmc_readl(owl_host, OWL_REG_SD_CTL);
> > + reg &= ~OWL_SD_CTL_DELAY_MSK;
> > +
> > + /* Set RDELAY and WDELAY based on the clock */
> > + if (rate <= 1000000) {
> > + mmc_writel(owl_host, OWL_REG_SD_CTL, reg |
> > + OWL_SD_CTL_RDELAY(OWL_SD_DELAY_LOW_CLK) |
> > + OWL_SD_CTL_WDELAY(OWL_SD_DELAY_LOW_CLK));
> > + } else if ((rate > 1000000) && (rate <= 26000000)) {
> > + mmc_writel(owl_host, OWL_REG_SD_CTL, reg |
> > + OWL_SD_CTL_RDELAY(OWL_SD_DELAY_MID_CLK) |
> > + OWL_SD_CTL_WDELAY(OWL_SD_DELAY_MID_CLK));
> > + } else if ((rate > 26000000) && (rate <= 52000000) && !owl_host->ddr_50) {
> > + mmc_writel(owl_host, OWL_REG_SD_CTL, reg |
> > + OWL_SD_CTL_RDELAY(OWL_SD_DELAY_HIGH_CLK) |
> > + OWL_SD_CTL_WDELAY(OWL_SD_DELAY_HIGH_CLK));
> > + /* DDR50 mode has special delay chain */
> > + } else if ((rate > 26000000) && (rate <= 52000000) && owl_host->ddr_50) {
> > + mmc_writel(owl_host, OWL_REG_SD_CTL, reg |
> > + OWL_SD_CTL_RDELAY(OWL_SD_RDELAY_DDR50) |
> > + OWL_SD_CTL_WDELAY(OWL_SD_WDELAY_DDR50));
> > + } else {
> > + dev_err(owl_host->dev, "SD clock rate not supported\n");
> > + return -EINVAL;
> > + }
> > +
> > + clk_rate = clk_round_rate(owl_host->clk, rate << 1);
> > + ret = clk_set_rate(owl_host->clk, clk_rate);
> > +
> > + return ret;
> > +}
> > +
> > +static void owl_mmc_set_clk(struct owl_mmc_host *owl_host, struct mmc_ios *ios)
> > +{
> > + if (!ios->clock)
> > + return;
> > +
> > + owl_host->clock = ios->clock;
> > + owl_mmc_set_clk_rate(owl_host, ios->clock);
> > +}
> > +
> > +static void owl_mmc_set_bus_width(struct owl_mmc_host *owl_host,
> > + struct mmc_ios *ios)
> > +{
> > + u32 reg;
> > +
> > + reg = mmc_readl(owl_host, OWL_REG_SD_EN);
> > + reg &= ~0x03;
> > + switch (ios->bus_width) {
> > + case MMC_BUS_WIDTH_1:
> > + break;
> > + case MMC_BUS_WIDTH_4:
> > + reg |= OWL_SD_EN_DATAWID(1);
> > + break;
> > + case MMC_BUS_WIDTH_8:
> > + reg |= OWL_SD_EN_DATAWID(2);
> > + break;
> > + }
> > +
> > + mmc_writel(owl_host, OWL_REG_SD_EN, reg);
> > +}
> > +
> > +static void owl_mmc_ctr_reset(struct owl_mmc_host *owl_host)
> > +{
> > + reset_control_assert(owl_host->reset);
> > + udelay(20);
> > + reset_control_deassert(owl_host->reset);
> > +}
> > +
> > +static void owl_mmc_power_on(struct owl_mmc_host *owl_host)
> > +{
> > + u32 mode;
> > +
> > + init_completion(&owl_host->sdc_complete);
> > +
> > + /* Enable transfer end IRQ */
> > + mmc_update_reg(owl_host->base + OWL_REG_SD_STATE,
> > + OWL_SD_STATE_TEIE, true);
> > +
> > + /* Send init clk */
> > + mode = (mmc_readl(owl_host, OWL_REG_SD_CTL) & (0xff << 16));
> > + mode |= OWL_SD_CTL_TS | OWL_SD_CTL_TCN(5) | OWL_SD_CTL_TM(8);
> > + mmc_writel(owl_host, OWL_REG_SD_CTL, mode);
> > +
> > + if (!wait_for_completion_timeout(&owl_host->sdc_complete, HZ)) {
> > + dev_err(owl_host->dev, "CMD interrupt timeout\n");
> > + return;
> > + }
> > +}
> > +
> > +static void owl_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> > +{
> > + struct owl_mmc_host *owl_host = mmc_priv(mmc);
> > +
> > + switch (ios->power_mode) {
> > + case MMC_POWER_UP:
> > + dev_dbg(owl_host->dev, "Powering card up\n");
> > +
> > + /* Reset the SDC controller to clear all previous states */
> > + owl_mmc_ctr_reset(owl_host);
> > + clk_prepare_enable(owl_host->clk);
> > + mmc_writel(owl_host, OWL_REG_SD_EN, OWL_SD_ENABLE |
> > + OWL_SD_EN_RESE);
> > +
> > + break;
> > +
> > + case MMC_POWER_ON:
> > + dev_dbg(owl_host->dev, "Powering card on\n");
> > + owl_mmc_power_on(owl_host);
> > +
> > + break;
> > +
> > + case MMC_POWER_OFF:
> > + dev_dbg(owl_host->dev, "Powering card off\n");
> > + clk_disable_unprepare(owl_host->clk);
> > +
> > + return;
> > +
> > + default:
> > + dev_dbg(owl_host->dev, "Ignoring unknown card power state\n");
> > + break;
> > + }
> > +
> > + if (ios->clock != owl_host->clock)
> > + owl_mmc_set_clk(owl_host, ios);
> > +
> > + owl_mmc_set_bus_width(owl_host, ios);
> > +
> > + /* Enable DDR mode if requested */
> > + if (ios->timing == MMC_TIMING_UHS_DDR50) {
> > + owl_host->ddr_50 = 1;
> > + mmc_update_reg(owl_host->base + OWL_REG_SD_EN,
> > + OWL_SD_EN_DDREN, true);
> > + } else {
> > + owl_host->ddr_50 = 0;
> > + }
> > +}
> > +
> > +static int owl_mmc_start_signal_voltage_switch(struct mmc_host *mmc,
> > + struct mmc_ios *ios)
> > +{
> > + struct owl_mmc_host *owl_host = mmc_priv(mmc);
> > +
> > + /* It is enough to change the pad ctrl bit for voltage switch */
> > + switch (ios->signal_voltage) {
> > + case MMC_SIGNAL_VOLTAGE_330:
> > + mmc_update_reg(owl_host->base + OWL_REG_SD_EN,
> > + OWL_SD_EN_S18EN, false);
> > + break;
> > + case MMC_SIGNAL_VOLTAGE_180:
> > + mmc_update_reg(owl_host->base + OWL_REG_SD_EN,
> > + OWL_SD_EN_S18EN, true);
> > + break;
> > + default:
> > + return -ENOTSUPP;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static const struct mmc_host_ops owl_mmc_ops = {
> > + .request = owl_mmc_request,
> > + .set_ios = owl_mmc_set_ios,
> > + .get_ro = mmc_gpio_get_ro,
> > + .get_cd = mmc_gpio_get_cd,
> > + .start_signal_voltage_switch = owl_mmc_start_signal_voltage_switch,
> > +};
> > +
> > +static int owl_mmc_probe(struct platform_device *pdev)
> > +{
> > + struct owl_mmc_host *owl_host;
> > + struct mmc_host *mmc;
> > + struct resource *res;
> > + int ret;
> > +
> > + mmc = mmc_alloc_host(sizeof(struct owl_mmc_host), &pdev->dev);
> > + if (!mmc) {
> > + dev_err(&pdev->dev, "mmc alloc host failed\n");
> > + return -ENOMEM;
> > + }
> > + platform_set_drvdata(pdev, mmc);
> > +
> > + owl_host = mmc_priv(mmc);
> > + owl_host->dev = &pdev->dev;
> > + owl_host->mmc = mmc;
> > + spin_lock_init(&owl_host->lock);
> > +
> > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > + owl_host->base = devm_ioremap_resource(&pdev->dev, res);
> > + if (IS_ERR(owl_host->base)) {
> > + dev_err(&pdev->dev, "Failed to remap registers\n");
> > + ret = PTR_ERR(owl_host->base);
> > + goto err_free_host;
> > + }
> > +
> > + owl_host->clk = devm_clk_get(&pdev->dev, NULL);
> > + if (IS_ERR(owl_host->clk)) {
> > + dev_err(&pdev->dev, "No clock defined\n");
> > + ret = PTR_ERR(owl_host->clk);
> > + goto err_free_host;
> > + }
> > +
> > + owl_host->reset = devm_reset_control_get_exclusive(&pdev->dev, NULL);
> > + if (IS_ERR(owl_host->reset)) {
> > + dev_err(&pdev->dev, "Could not get reset control\n");
> > + ret = PTR_ERR(owl_host->reset);
> > + goto err_free_host;
> > + }
> > +
> > + mmc->ops = &owl_mmc_ops;
> > + mmc->max_blk_count = 512;
> > + mmc->max_blk_size = 512;
> > + mmc->max_segs = 256;
> > + mmc->max_seg_size = 262144;
> > + mmc->max_req_size = 262144;
> > + /* 100kHz ~ 52MHz */
> > + mmc->f_min = 100000;
> > + mmc->f_max = 52000000;
> > + mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
> > + MMC_CAP_4_BIT_DATA;
> > + mmc->caps2 = (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_NO_SDIO);
> > + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34 |
> > + MMC_VDD_165_195;
> > +
> > + ret = mmc_of_parse(mmc);
> > + if (ret)
> > + goto err_free_host;
> > +
> > + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
> > + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
> > + owl_host->dma = dma_request_slave_channel(&pdev->dev, "mmc");
> > + if (!owl_host->dma) {
> > + dev_err(owl_host->dev, "Failed to get external DMA channel.\n");
> > + ret = -ENXIO;
> > + goto err_free_host;
> > + }
> > +
> > + dev_info(&pdev->dev, "Using %s for DMA transfers\n",
> > + dma_chan_name(owl_host->dma));
> > +
> > + owl_host->dma_cfg.src_addr = res->start + OWL_REG_SD_DAT;
> > + owl_host->dma_cfg.dst_addr = res->start + OWL_REG_SD_DAT;
> > + owl_host->dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
> > + owl_host->dma_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
> > + owl_host->dma_cfg.device_fc = false;
> > +
> > + owl_host->irq = platform_get_irq(pdev, 0);
> > + if (owl_host->irq < 0) {
> > + ret = -EINVAL;
> > + goto err_free_host;
> > + }
> > +
> > + ret = devm_request_irq(&pdev->dev, owl_host->irq, owl_irq_handler,
> > + 0, dev_name(&pdev->dev), owl_host);
> > + if (ret) {
> > + dev_err(&pdev->dev, "Failed to request irq %d\n",
> > + owl_host->irq);
> > + goto err_free_host;
> > + }
> > +
> > + ret = mmc_add_host(mmc);
> > + if (ret) {
> > + dev_err(&pdev->dev, "Failed to add host\n");
> > + goto err_free_host;
> > + }
> > +
> > + dev_dbg(&pdev->dev, "Owl MMC Controller Initialized\n");
> > +
> > + return 0;
> > +
> > +err_free_host:
> > + mmc_free_host(mmc);
> > +
> > + return ret;
> > +}
> > +
> > +static int owl_mmc_remove(struct platform_device *pdev)
> > +{
> > + struct mmc_host *mmc = platform_get_drvdata(pdev);
> > + struct owl_mmc_host *owl_host = mmc_priv(mmc);
> > +
> > + mmc_remove_host(mmc);
> > + disable_irq(owl_host->irq);
> > + mmc_free_host(mmc);
> > +
> > + return 0;
> > +}
> > +
> > +static const struct of_device_id owl_mmc_of_match[] = {
> > + {.compatible = "actions,owl-mmc",},
> > + { /* sentinel */ }
> > +};
> > +MODULE_DEVICE_TABLE(of, owl_mmc_of_match);
> > +
> > +static struct platform_driver owl_mmc_driver = {
> > + .driver = {
> > + .name = "owl_mmc",
> > + .of_match_table = of_match_ptr(owl_mmc_of_match),
> > + },
> > + .probe = owl_mmc_probe,
> > + .remove = owl_mmc_remove,
> > +};
> > +module_platform_driver(owl_mmc_driver);
> > +
> > +MODULE_DESCRIPTION("Actions Semi Owl SoCs SD/MMC Driver");
> > +MODULE_AUTHOR("Actions Semi");
> > +MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
> > +MODULE_LICENSE("GPL");
> > --
> > 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
* [PATCH V3 2/4] watchdog: Add i.MX7ULP watchdog support
From: Anson Huang @ 2019-08-21 2:07 UTC (permalink / raw)
To: wim, linux, robh+dt, mark.rutland, shawnguo, s.hauer, kernel,
festevam, linux, otavio, leonard.crestez, schnitzeltony,
u.kleine-koenig, jan.tuerk, linux-watchdog, devicetree,
linux-arm-kernel, linux-kernel
Cc: Linux-imx
In-Reply-To: <1566353278-1884-1-git-send-email-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>
---
Changes since V2:
- add devm_add_action_or_reset to disable clk for remove action.
---
drivers/watchdog/Kconfig | 13 +++
drivers/watchdog/Makefile | 1 +
drivers/watchdog/imx7ulp_wdt.c | 246 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 260 insertions(+)
create mode 100644 drivers/watchdog/imx7ulp_wdt.c
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index a8f5c81..d68e5b5 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -724,6 +724,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 b5a0aed..2ee352b 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -67,6 +67,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..5d37957
--- /dev/null
+++ b/drivers/watchdog/imx7ulp_wdt.c
@@ -0,0 +1,246 @@
+// 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 void imx7ulp_wdt_action(void *data)
+{
+ struct imx7ulp_wdt_device *imx7ulp_wdt = data;
+
+ clk_disable_unprepare(imx7ulp_wdt->clk);
+}
+
+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;
+
+ ret = devm_add_action_or_reset(dev, imx7ulp_wdt_action, imx7ulp_wdt);
+ 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);
+
+ return devm_watchdog_register_device(dev, wdog);
+}
+
+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");
--
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 V3 3/4] ARM: imx_v6_v7_defconfig: Enable CONFIG_IMX7ULP_WDT by default
From: Anson Huang @ 2019-08-21 2:07 UTC (permalink / raw)
To: wim, linux, robh+dt, mark.rutland, shawnguo, s.hauer, kernel,
festevam, linux, otavio, leonard.crestez, schnitzeltony,
u.kleine-koenig, jan.tuerk, linux-watchdog, devicetree,
linux-arm-kernel, linux-kernel
Cc: Linux-imx
In-Reply-To: <1566353278-1884-1-git-send-email-Anson.Huang@nxp.com>
Select CONFIG_IMX7ULP_WDT by default to support i.MX7ULP watchdog.
Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
---
No changes.
---
arch/arm/configs/imx_v6_v7_defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 9bfffbe..be2a694 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -236,6 +236,7 @@ CONFIG_DA9062_WATCHDOG=y
CONFIG_DA9063_WATCHDOG=m
CONFIG_RN5T618_WATCHDOG=y
CONFIG_IMX2_WDT=y
+CONFIG_IMX7ULP_WDT=y
CONFIG_MFD_DA9052_I2C=y
CONFIG_MFD_DA9062=y
CONFIG_MFD_DA9063=y
--
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 V3 1/4] dt-bindings: watchdog: Add i.MX7ULP bindings
From: Anson Huang @ 2019-08-21 2:07 UTC (permalink / raw)
To: wim, linux, robh+dt, mark.rutland, shawnguo, s.hauer, kernel,
festevam, linux, otavio, leonard.crestez, schnitzeltony,
u.kleine-koenig, jan.tuerk, linux-watchdog, devicetree,
linux-arm-kernel, linux-kernel
Cc: Linux-imx
Add the watchdog bindings for Freescale i.MX7ULP.
Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
---
No changes.
---
.../bindings/watchdog/fsl-imx7ulp-wdt.txt | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
create mode 100644 Documentation/devicetree/bindings/watchdog/fsl-imx7ulp-wdt.txt
diff --git a/Documentation/devicetree/bindings/watchdog/fsl-imx7ulp-wdt.txt b/Documentation/devicetree/bindings/watchdog/fsl-imx7ulp-wdt.txt
new file mode 100644
index 0000000..d83fc5c
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/fsl-imx7ulp-wdt.txt
@@ -0,0 +1,22 @@
+* Freescale i.MX7ULP Watchdog Timer (WDT) Controller
+
+Required properties:
+- compatible : Should be "fsl,imx7ulp-wdt"
+- reg : Should contain WDT registers location and length
+- interrupts : Should contain WDT interrupt
+- clocks: Should contain a phandle pointing to the gated peripheral clock.
+
+Optional properties:
+- timeout-sec : Contains the watchdog timeout in seconds
+
+Examples:
+
+wdog1: wdog@403d0000 {
+ compatible = "fsl,imx7ulp-wdt";
+ reg = <0x403d0000 0x10000>;
+ interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&pcc2 IMX7ULP_CLK_WDG1>;
+ assigned-clocks = <&pcc2 IMX7ULP_CLK_WDG1>;
+ assigned-clocks-parents = <&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>;
+ timeout-sec = <40>;
+};
--
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] usb: udc: lpc32xx: silence fall-through warning
From: Gustavo A. R. Silva @ 2019-08-21 2:16 UTC (permalink / raw)
To: Felipe Balbi, Greg Kroah-Hartman, Vladimir Zapolskiy,
Sylvain Lemieux
Cc: linux-usb, linux-kernel, linux-arm-kernel, Gustavo A. R. Silva
Silence the following fall-through warning by adding a break statement:
drivers/usb/gadget/udc/lpc32xx_udc.c:2230:3: warning: this statement may
fall through [-Wimplicit-fallthrough=]
Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com>
---
drivers/usb/gadget/udc/lpc32xx_udc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c
index e3f67023d935..606c8bc52db5 100644
--- a/drivers/usb/gadget/udc/lpc32xx_udc.c
+++ b/drivers/usb/gadget/udc/lpc32xx_udc.c
@@ -2264,7 +2264,7 @@ static void udc_handle_ep0_setup(struct lpc32xx_udc *udc)
default:
break;
}
-
+ break;
case USB_REQ_SET_ADDRESS:
if (reqtype == (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) {
--
2.23.0
_______________________________________________
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 1/3] ftrace: introdue ftrace_call_init
From: Jisheng Zhang @ 2019-08-21 2:12 UTC (permalink / raw)
To: Miroslav Benes
Cc: Mark Rutland, Catalin Marinas, Torsten Duwe,
linux-kernel@vger.kernel.org, Steven Rostedt, Will Deacon,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <alpine.LSU.2.21.1908201118190.9536@pobox.suse.cz>
Hi,
On Tue, 20 Aug 2019 11:27:38 +0200 (CEST) Miroslav Benes <mbenes@suse.cz> wrote:
>
>
> Hi,
>
> On Mon, 19 Aug 2019, Jisheng Zhang wrote:
>
> > On some arch, the FTRACE_WITH_REGS is implemented with gcc's
> > -fpatchable-function-entry (=2), gcc adds 2 NOPs at the beginning
> > of each function, so this makes the MCOUNT_ADDR useless. In ftrace
> > common framework, MCOUNT_ADDR is mostly used to "init" the nop, so
> > let's introcude ftrace_call_init().
> >
> > Signed-off-by: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
> > ---
> > include/linux/ftrace.h | 1 +
> > kernel/trace/ftrace.c | 4 ++++
> > 2 files changed, 5 insertions(+)
> >
> > diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
> > index 8a8cb3c401b2..8175ffb671f0 100644
> > --- a/include/linux/ftrace.h
> > +++ b/include/linux/ftrace.h
> > @@ -458,6 +458,7 @@ extern void ftrace_regs_caller(void);
> > extern void ftrace_call(void);
> > extern void ftrace_regs_call(void);
> > extern void mcount_call(void);
> > +extern int ftrace_call_init(struct module *mod, struct dyn_ftrace *rec);
> >
> > void ftrace_modify_all_code(int command);
> >
> > diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
> > index eca34503f178..9df5a66a6811 100644
> > --- a/kernel/trace/ftrace.c
> > +++ b/kernel/trace/ftrace.c
> > @@ -2500,7 +2500,11 @@ ftrace_code_disable(struct module *mod, struct dyn_ftrace *rec)
> > if (unlikely(ftrace_disabled))
> > return 0;
> >
> > +#ifdef MCOUNT_ADDR
> > ret = ftrace_make_nop(mod, rec, MCOUNT_ADDR);
> > +#else
> > + ret = ftrace_call_init(mod, rec);
> > +#endif
> > if (ret) {
> > ftrace_bug_type = FTRACE_BUG_INIT;
> > ftrace_bug(ret, rec);
>
> I may be missing something, but the patch does not seem to be complete.
> There is no ftrace_call_init() implemented. MCOUNT_ADDR is still defined,
> so it does not change much. I don't think it is what Mark had in his mind.
>
Yes, except arm64, MCOUNT_ADDR is still defined in other arch. If we want
to remove MCOUNT_ADDR from all arch, I will cook patches for this purpose.
Thanks
_______________________________________________
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 1/3] kprobes/x86: use instruction_pointer and instruction_pointer_set
From: Jisheng Zhang @ 2019-08-21 2:09 UTC (permalink / raw)
To: Masami Hiramatsu
Cc: Jonathan Corbet, Catalin Marinas, x86@kernel.org,
linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
Anil S Keshavamurthy, Ingo Molnar, Borislav Petkov,
H. Peter Anvin, Naveen N. Rao, Thomas Gleixner, Will Deacon,
David S. Miller, linux-arm-kernel@lists.infradead.org
In-Reply-To: <20190821105247.f0236d2c04b2c0c4d4e1847e@kernel.org>
Hi,
On Wed, 21 Aug 2019 10:52:47 +0900 Masami Hiramatsu wrote:
>
>
> Hi Jisheng,
>
> On Tue, 20 Aug 2019 09:02:59 +0000
> Jisheng Zhang <Jisheng.Zhang@synaptics.com> wrote:
>
> > Hi Thomas,
> >
> > On Tue, 20 Aug 2019 10:53:58 +0200 (CEST) Thomas Gleixner wrote:
> >
> > >
> > >
> > > On Tue, 20 Aug 2019, Jisheng Zhang wrote:
> > >
> > > > This is to make the x86 kprobe_ftrace_handler() more common so that
> > > > the code could be reused in future.
> > >
> > > While I agree with the change in general, I can't find anything which
> > > reuses that code. So the change log is pretty useless and I have no idea
> > > how this is related to the rest of the series.
> >
> > In v1, this code is moved from x86 to common kprobes.c [1]
> > But I agree with Masami, consolidation could be done when arm64 kprobes
> > on ftrace is stable.
>
> We'll revisit to consolidate the code after we got 3rd or 4th clones.
>
> >
> > In v2, actually, the arm64 version's kprobe_ftrace_handler() is the same
> > as x86's, the only difference is comment, e.g
> >
> > /* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
> >
> > while in arm64
> >
> > /* Kprobe handler expects regs->pc = ip + 1 as breakpoint hit */
>
> As Peter pointed, on arm64, is that really 1 or 4 bytes?
> This part is heavily depends on the processor software-breakpoint
> implementation.
Per my understanding, the "+1" here means "+ one kprobe_opcode_t".
>
> >
> >
> > W/ above, any suggestion about the suitable change log?
>
> I think you just need to keep the first half of the description.
> Since this patch itself is not related to the series, could you update
> the description and resend it as a single cleanup patch out of the series?
>
Got it. Will do today.
Thanks a lot
_______________________________________________
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/3] kprobes: adjust kprobe addr for KPROBES_ON_FTRACE
From: Masami Hiramatsu @ 2019-08-21 2:07 UTC (permalink / raw)
To: Jisheng Zhang, Steven Rostedt
Cc: Jonathan Corbet, Catalin Marinas, x86@kernel.org,
linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
Anil S Keshavamurthy, Ingo Molnar, Borislav Petkov,
H. Peter Anvin, Naveen N. Rao, Thomas Gleixner, Will Deacon,
David S. Miller, linux-arm-kernel@lists.infradead.org
In-Reply-To: <20190820114224.0c8963c4@xhacker.debian>
Hi Jisheng,
On Tue, 20 Aug 2019 03:53:31 +0000
Jisheng Zhang <Jisheng.Zhang@synaptics.com> wrote:
> For KPROBES_ON_FTRACE case, we need to adjust the kprobe's addr
> correspondingly.
Either KPROBES_ON_FTRACE=y or not, ftrace_location() check must be
done correctly. If it failed, kprobes can modify the instruction
which can be modified by ftrace.
>
> Signed-off-by: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
> ---
> kernel/kprobes.c | 10 +++++++---
> 1 file changed, 7 insertions(+), 3 deletions(-)
>
> diff --git a/kernel/kprobes.c b/kernel/kprobes.c
> index 9873fc627d61..3fd2f68644da 100644
> --- a/kernel/kprobes.c
> +++ b/kernel/kprobes.c
> @@ -1484,15 +1484,19 @@ static inline int check_kprobe_rereg(struct kprobe *p)
>
> int __weak arch_check_ftrace_location(struct kprobe *p)
> {
> - unsigned long ftrace_addr;
> + unsigned long ftrace_addr, addr = (unsigned long)p->addr;
>
> - ftrace_addr = ftrace_location((unsigned long)p->addr);
> +#ifdef CONFIG_KPROBES_ON_FTRACE
> + addr = ftrace_call_adjust(addr);
> +#endif
> + ftrace_addr = ftrace_location(addr);
No, this is not right way to do. If we always need to adjust address
before calling ftrace_location(), something wrong with ftrace_location()
interface.
ftrace_location(addr) must check the address is within the range which
can be changed by ftrace. (dyn->ip <= addr <= dyn->ip+MCOUNT_INSN_SIZE)
> if (ftrace_addr) {
> #ifdef CONFIG_KPROBES_ON_FTRACE
> /* Given address is not on the instruction boundary */
> - if ((unsigned long)p->addr != ftrace_addr)
> + if (addr != ftrace_addr)
> return -EILSEQ;
> p->flags |= KPROBE_FLAG_FTRACE;
> + p->addr = (kprobe_opcode_t *)addr;
And again, please don't change the p->addr silently.
Thank you,
> #else /* !CONFIG_KPROBES_ON_FTRACE */
> return -EINVAL;
> #endif
> --
> 2.23.0.rc1
>
--
Masami Hiramatsu <mhiramat@kernel.org>
_______________________________________________
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 1/3] kprobes/x86: use instruction_pointer and instruction_pointer_set
From: Jisheng Zhang @ 2019-08-21 2:02 UTC (permalink / raw)
To: Peter Zijlstra
Cc: Jonathan Corbet, Catalin Marinas, x86@kernel.org,
linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
Anil S Keshavamurthy, Ingo Molnar, Borislav Petkov,
Masami Hiramatsu, H. Peter Anvin, Naveen N. Rao, Thomas Gleixner,
Will Deacon, David S. Miller,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <20190820132110.GP2332@hirez.programming.kicks-ass.net>
Hi Peter,
On Tue, 20 Aug 2019 15:21:10 +0200 Peter Zijlstra wrote:
>
>
> On Tue, Aug 20, 2019 at 09:02:59AM +0000, Jisheng Zhang wrote:
> > In v2, actually, the arm64 version's kprobe_ftrace_handler() is the same
> > as x86's, the only difference is comment, e.g
> >
> > /* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
> >
> > while in arm64
> >
> > /* Kprobe handler expects regs->pc = ip + 1 as breakpoint hit */
>
> What's weird; I thought ARM has fixed sized instructions and they are
> all 4 bytes? So how does a single byte offset make sense for ARM?
I believe the "+1" here means + one kprobe_opcode_t.
Thanks
_______________________________________________
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/2] PM / devfreq: Use dev_pm_qos for sysfs min/max_freq
From: Chanwoo Choi @ 2019-08-21 2:04 UTC (permalink / raw)
To: Leonard Crestez, MyungJoo Ham, Kyungmin Park,
Artur Świgoń
Cc: Jacky Bai, Saravana Kannan, linux-pm, Viresh Kumar,
Krzysztof Kozlowski, Alexandre Bailon, cpgs (cpgs@samsung.com),
Georgi Djakov, linux-arm-kernel
In-Reply-To: <af14021b98254032e856397b54329756c1cc59c0.1566314535.git.leonard.crestez@nxp.com>
On 19. 8. 21. 오전 12:24, Leonard Crestez wrote:
> Now that devfreq supports dev_pm_qos requests we can use them to handle
> the min/max_freq values set by userspace in sysfs, similar to cpufreq.
>
> Since dev_pm_qos handles frequencies as kHz this change reduces the
> precision of min_freq and max_freq. This shouldn't introduce problems
> because frequencies which are not an integer number of kHz are likely
> not an integer number of Hz either.
>
> Try to ensure compatibilitity by rounding min values down and rounding
> max values up.
>
> Simplify the {min,max}_freq_store code by setting "null" values of 0 and
> MAX_S32 respectively instead of clamping to what freq tables are
> actually supported. Values are already automatically clamped on
> readback.
>
> Also simplify by droping the limitation that userspace min_freq must be
> lower than userspace max_freq, it is already documented that max_freq
> takes precedence.
>
> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
> ---
> drivers/devfreq/devfreq.c | 79 ++++++++++++++++-----------------------
> include/linux/devfreq.h | 9 +++--
> 2 files changed, 38 insertions(+), 50 deletions(-)
>
> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
> index 58deffa52a37..687deadd08ed 100644
> --- a/drivers/devfreq/devfreq.c
> +++ b/drivers/devfreq/devfreq.c
> @@ -101,21 +101,21 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>
> static unsigned long get_effective_min_freq(struct devfreq *devfreq)
> {
> lockdep_assert_held(&devfreq->lock);
>
> - return max3(devfreq->scaling_min_freq, devfreq->min_freq,
> + return max(devfreq->scaling_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,
> + return min(devfreq->scaling_max_freq,
> 1000 * (unsigned long)dev_pm_qos_read_value(
> devfreq->dev.parent,
> DEV_PM_QOS_MAX_FREQUENCY));
> }
>
> @@ -644,10 +644,12 @@ static void devfreq_dev_release(struct device *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);
> + dev_pm_qos_remove_request(&devfreq->max_freq_req);
> + dev_pm_qos_remove_request(&devfreq->min_freq_req);
> mutex_destroy(&devfreq->lock);
> kfree(devfreq);
> }
>
> /**
> @@ -698,10 +700,19 @@ struct devfreq *devfreq_add_device(struct device *dev,
> devfreq->previous_freq = profile->initial_freq;
> devfreq->last_status.current_frequency = profile->initial_freq;
> devfreq->data = data;
> devfreq->nb.notifier_call = devfreq_notifier_call;
>
> + err = dev_pm_qos_add_request(dev, &devfreq->min_freq_req,
> + DEV_PM_QOS_MIN_FREQUENCY, 0);
> + if (err < 0)
> + goto err_dev;
> + err = dev_pm_qos_add_request(dev, &devfreq->max_freq_req,
> + DEV_PM_QOS_MAX_FREQUENCY, S32_MAX);
> + if (err < 0)
> + goto err_dev;
> +
Please move them under dev_pm_qos_add_notifier()
because it seems that it request the qos without qos_notifier.
> /*
> * notifier from pm_qos
> *
> * initialized outside of devfreq->lock to avoid circular warning
> * between devfreq->lock and dev_pm_qos_mtx
> @@ -732,19 +743,17 @@ struct devfreq *devfreq_add_device(struct device *dev,
> if (!devfreq->scaling_min_freq) {
> mutex_unlock(&devfreq->lock);
> err = -EINVAL;
> goto err_dev;
> }
> - devfreq->min_freq = devfreq->scaling_min_freq;
>
> devfreq->scaling_max_freq = find_available_max_freq(devfreq);
> if (!devfreq->scaling_max_freq) {
> mutex_unlock(&devfreq->lock);
> err = -EINVAL;
> goto err_dev;
> }
> - devfreq->max_freq = devfreq->scaling_max_freq;
>
> devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
> atomic_set(&devfreq->suspend_count, 0);
>
> dev_set_name(&devfreq->dev, "devfreq%d",
> @@ -816,10 +825,14 @@ struct devfreq *devfreq_add_device(struct device *dev,
> 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);
> + if (dev_pm_qos_request_active(&devfreq->max_freq_req))
> + dev_pm_qos_remove_request(&devfreq->max_freq_req);
> + if (dev_pm_qos_request_active(&devfreq->min_freq_req))
> + dev_pm_qos_remove_request(&devfreq->min_freq_req);
> kfree(devfreq);
> err_out:
> return ERR_PTR(err);
> }
> EXPORT_SYMBOL(devfreq_add_device);
> @@ -1358,33 +1371,20 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
>
> ret = sscanf(buf, "%lu", &value);
> if (ret != 1)
> return -EINVAL;
>
> - mutex_lock(&df->lock);
> -
> - if (value) {
> - if (value > df->max_freq) {
> - ret = -EINVAL;
> - goto unlock;
> - }
Actually, the user can input the value they want.
So, the above code is not necessary because the devfreq->scaling_max_freq
is never overflow from supported maximum frequency. The devfreq->scaling_max_freq
is based on OPP entries from DT.
But, if we replace the existing request way of devfreq-cooling.c
with dev_pm_qos, devfreq->scaling_max_freq doesn't guarantee
the supported maximum frequency.
We need to keep the supported min_freq/max_freq value without dev_pm_qos
requirement because the dev_pm_qos requirement might have the overflow value.
the dev_pm_qos doesn't know the supported minimum and maximum frequency
of devfreq device.
> - } else {
> - unsigned long *freq_table = df->profile->freq_table;
> + if (value)
> + value = value / 1000;
Better to use KHZ definition instead of 1000 as I commented on patch1.
> + else
> + value = 0;
>
> - /* Get minimum frequency according to sorting order */
> - if (freq_table[0] < freq_table[df->profile->max_state - 1])
> - value = freq_table[0];
> - else
> - value = freq_table[df->profile->max_state - 1];
> - }
> + ret = dev_pm_qos_update_request(&df->min_freq_req, value);
> + if (ret < 0)
> + return ret;
>
> - df->min_freq = value;
> - update_devfreq(df);
> - ret = count;
> -unlock:
> - mutex_unlock(&df->lock);
> - return ret;
> + return count;
> }
>
> static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
> char *buf)
> {
> @@ -1407,33 +1407,20 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>
> ret = sscanf(buf, "%lu", &value);
> if (ret != 1)
> return -EINVAL;
>
> - mutex_lock(&df->lock);
> -
> - if (value) {
> - if (value < df->min_freq) {
> - ret = -EINVAL;
> - goto unlock;
> - }
> - } else {
> - unsigned long *freq_table = df->profile->freq_table;
> + if (value)
> + value = DIV_ROUND_UP(value, 1000);
> + else
> + value = S32_MAX;
>
> - /* Get maximum frequency according to sorting order */
> - if (freq_table[0] < freq_table[df->profile->max_state - 1])
> - value = freq_table[df->profile->max_state - 1];
> - else
> - value = freq_table[0];
> - }
> + ret = dev_pm_qos_update_request(&df->max_freq_req, value);
> + if (ret < 0)
> + return ret;
>
> - df->max_freq = value;
> - update_devfreq(df);
> - ret = count;
> -unlock:
> - mutex_unlock(&df->lock);
> - return ret;
> + return count;
> }
> static DEVICE_ATTR_RW(min_freq);
>
> static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
> char *buf)
> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
> index 8b92ccbd1962..d2c5bb7add0a 100644
> --- a/include/linux/devfreq.h
> +++ b/include/linux/devfreq.h
> @@ -11,10 +11,11 @@
> #define __LINUX_DEVFREQ_H__
>
> #include <linux/device.h>
> #include <linux/notifier.h>
> #include <linux/pm_opp.h>
> +#include <linux/pm_qos.h>
>
> #define DEVFREQ_NAME_LEN 16
>
> /* DEVFREQ governor name */
> #define DEVFREQ_GOV_SIMPLE_ONDEMAND "simple_ondemand"
> @@ -121,12 +122,12 @@ struct devfreq_dev_profile {
> * devfreq.nb to the corresponding register notifier call chain.
> * @work: delayed work for load monitoring.
> * @previous_freq: previously configured frequency value.
> * @data: Private data of the governor. The devfreq framework does not
> * touch this.
> - * @min_freq: Limit minimum frequency requested by user (0: none)
> - * @max_freq: Limit maximum frequency requested by user (0: none)
> + * @min_freq_req: Limit minimum frequency requested by user (0: none)
> + * @max_freq_req: Limit maximum frequency requested by user (0: none)
> * @scaling_min_freq: Limit minimum frequency requested by OPP interface
> * @scaling_max_freq: Limit maximum frequency requested by OPP interface
> * @stop_polling: devfreq polling status of a device.
> * @suspend_freq: frequency of a device set during suspend phase.
> * @resume_freq: frequency of a device set in resume phase.
> @@ -161,12 +162,12 @@ struct devfreq {
> unsigned long previous_freq;
> struct devfreq_dev_status last_status;
>
> void *data; /* private data for governors */
>
> - unsigned long min_freq;
> - unsigned long max_freq;
> + struct dev_pm_qos_request min_freq_req;
> + struct dev_pm_qos_request max_freq_req;
> unsigned long scaling_min_freq;
> unsigned long scaling_max_freq;
> bool stop_polling;
>
> unsigned long suspend_freq;
>
--
Best Regards,
Chanwoo Choi
Samsung Electronics
_______________________________________________
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 1/3] kprobes/x86: use instruction_pointer and instruction_pointer_set
From: Masami Hiramatsu @ 2019-08-21 1:52 UTC (permalink / raw)
To: Jisheng Zhang
Cc: Jonathan Corbet, Catalin Marinas, x86@kernel.org,
linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
Anil S Keshavamurthy, Ingo Molnar, Borislav Petkov,
Masami Hiramatsu, H. Peter Anvin, Naveen N. Rao, Thomas Gleixner,
Will Deacon, David S. Miller,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <20190820165152.20275268@xhacker.debian>
Hi Jisheng,
On Tue, 20 Aug 2019 09:02:59 +0000
Jisheng Zhang <Jisheng.Zhang@synaptics.com> wrote:
> Hi Thomas,
>
> On Tue, 20 Aug 2019 10:53:58 +0200 (CEST) Thomas Gleixner wrote:
>
> >
> >
> > On Tue, 20 Aug 2019, Jisheng Zhang wrote:
> >
> > > This is to make the x86 kprobe_ftrace_handler() more common so that
> > > the code could be reused in future.
> >
> > While I agree with the change in general, I can't find anything which
> > reuses that code. So the change log is pretty useless and I have no idea
> > how this is related to the rest of the series.
>
> In v1, this code is moved from x86 to common kprobes.c [1]
> But I agree with Masami, consolidation could be done when arm64 kprobes
> on ftrace is stable.
We'll revisit to consolidate the code after we got 3rd or 4th clones.
>
> In v2, actually, the arm64 version's kprobe_ftrace_handler() is the same
> as x86's, the only difference is comment, e.g
>
> /* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
>
> while in arm64
>
> /* Kprobe handler expects regs->pc = ip + 1 as breakpoint hit */
As Peter pointed, on arm64, is that really 1 or 4 bytes?
This part is heavily depends on the processor software-breakpoint
implementation.
>
>
> W/ above, any suggestion about the suitable change log?
I think you just need to keep the first half of the description.
Since this patch itself is not related to the series, could you update
the description and resend it as a single cleanup patch out of the series?
Thank you!
>
> Thanks
>
> [1] http://lists.infradead.org/pipermail/linux-arm-kernel/2019-August/674417.html
--
Masami Hiramatsu <mhiramat@kernel.org>
_______________________________________________
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 1/2] PM / devfreq: Add dev_pm_qos support
From: Chanwoo Choi @ 2019-08-21 1:44 UTC (permalink / raw)
To: Leonard Crestez, MyungJoo Ham, Kyungmin Park,
Artur Świgoń
Cc: Jacky Bai, Saravana Kannan, linux-pm, Viresh Kumar,
Krzysztof Kozlowski, Alexandre Bailon, cpgs (cpgs@samsung.com),
Georgi Djakov, linux-arm-kernel
In-Reply-To: <3b93af7e61a573ea2a123c353255645b5ad2a805.1566314535.git.leonard.crestez@nxp.com>
Hi,
On 19. 8. 21. 오전 12:24, Leonard Crestez wrote:
> 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)
I'm not sure that 'effective' expression is correct.
From this function, the devfreq can get the final target frequency.
I think that we need to use the more correct expression
to give the meaning of function as following:
get_min_freq
get_max_freq
or
get_biggest_min_freq
get_biggest_max_freq
or
others if there are more proper function name.
> +{
> + lockdep_assert_held(&devfreq->lock);
> +
> + return max3(devfreq->scaling_min_freq, devfreq->min_freq,
> + 1000 * (unsigned long)dev_pm_qos_read_value(
I prefer to use 'KHZ' defintion instead of 1000.
The constant definition is more easy to inform
the correct meaning of constant.
> + devfreq->dev.parent,
> + DEV_PM_QOS_MIN_FREQUENCY));
> +}
> +
> +static unsigned long get_effective_max_freq(struct devfreq *devfreq)
ditto.
> +{
> + lockdep_assert_held(&devfreq->lock);
> +
> + return min3(devfreq->scaling_max_freq, devfreq->max_freq,
> + 1000 * (unsigned long)dev_pm_qos_read_value(
ditto.
> + 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);
> +}
Although the all functions has not the function description in devfreq.c,
You need to add the function description for newly added functions.
> +
> /**
> * 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);
Basically, I think that it is safe to lock when touch
the variable of the devfreq.
it is not proper way for the dev_pm_qos because
it breaks the existing locking reason of devfreq's variables.
> 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;
>
--
Best Regards,
Chanwoo Choi
Samsung Electronics
_______________________________________________
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] ARM: dts: vf610-zii-cfu1: Slow I2C0 down to 100 kHz
From: Andrey Smirnov @ 2019-08-21 1:39 UTC (permalink / raw)
To: linux-arm-kernel
Cc: Andrey Smirnov, Fabio Estevam, Shawn Guo, linux-kernel,
Chris Healy
Fiber-optic modules attached to the bus are only rated to work at
100 kHz, so decrease the bus frequency to accommodate that.
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Chris Healy <cphealy@gmail.com>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
Changes since [v1]:
- Spelling fixes
[v1] lore.kernel.org/lkml/20190820030804.8892-1-andrew.smirnov@gmail.com
arch/arm/boot/dts/vf610-zii-cfu1.dts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/vf610-zii-cfu1.dts b/arch/arm/boot/dts/vf610-zii-cfu1.dts
index ff460a1de85a..28732249cfc0 100644
--- a/arch/arm/boot/dts/vf610-zii-cfu1.dts
+++ b/arch/arm/boot/dts/vf610-zii-cfu1.dts
@@ -207,7 +207,7 @@
};
&i2c0 {
- clock-frequency = <400000>;
+ clock-frequency = <100000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c0>;
status = "okay";
--
2.21.0
_______________________________________________
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] ARM: dts: vf610-zii-cfu1: Slow I2C0 down to 100kHz
From: Andrey Smirnov @ 2019-08-21 1:35 UTC (permalink / raw)
To: Andrew Lunn
Cc: Shawn Guo, Chris Healy, Fabio Estevam, linux-kernel,
linux-arm-kernel
In-Reply-To: <20190820152928.GK29991@lunn.ch>
On Tue, Aug 20, 2019 at 8:29 AM Andrew Lunn <andrew@lunn.ch> wrote:
>
> 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.
>
Yes, AFAICT, fiber-optic modules are present only on SCU4
(vf610-zii-scu4-aib.dts), CFU1 (vf610-zii-cfu1.dts) and VF610 Dev
board rev. B/C (vf610-zii-dev*.dts[i]). Of all three only CFU1 has
corresponding I2C bus running @ 400 kHz.
Thanks,
Andrey Smirnov
_______________________________________________
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: Andrey Smirnov @ 2019-08-21 1:30 UTC (permalink / raw)
To: Marc Gonzalez; +Cc: Fabio Estevam, Shawn Guo, Chris Healy, Linux ARM, LKML
In-Reply-To: <d735e851-cddf-f069-37f1-d27b013f3213@free.fr>
On Tue, Aug 20, 2019 at 7:41 AM Marc Gonzalez <marc.w.gonzalez@free.fr> wrote:
>
> On 20/08/2019 05:08, 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.
>
> s/100kHz/100 kHz
> s/frequncy/frequency
> s/accomodate/accommodate
>
Will fix in v2.
Thanks,
Andrey Smirnov
_______________________________________________
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: Chanwoo Choi @ 2019-08-21 1:20 UTC (permalink / raw)
To: Leonard Crestez
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: <VI1PR04MB7023C709356F9EBE0CA4E3C8EEAB0@VI1PR04MB7023.eurprd04.prod.outlook.com>
On 19. 8. 21. 오전 12:26, Leonard Crestez wrote:
> 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.
As I knew that, user don't need to enter the perfect supported clock
of devfreq0 because the final frequency is decided by device driver
with some limitations like the range of h/w clock.
The user can input the wanted frequency like 333333333,
but, the device driver try to find the similar frequency with policy
and the can decide the final supported frequency because the h/w clock
for devfreq0 might not support the perfect same clock frequency of user input.
Also, if it is the problem to lose the 3 significant digits,
it should be fixed on dev_pm_qos.
>
>>> 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?
Right. there are no upstream patch. But, ARM developer contributed
the devfreq-cooling.c in order to control ARM Mali frequency
according to temperature. If you want, you can check
the reference code from ARM Mali kernel driver.
>
> 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.
Ah. you're right. It is my misunderstand. I though that there are no
any way to get the 'devfreq' instance from device tree. But, I checked
the devfreq-cooling.c again, as you commented, the devfreq-cooling.c
provides the of_devfreq_cooling_reigster().
--
Best Regards,
Chanwoo Choi
Samsung Electronics
_______________________________________________
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 0/6] arm64: Add support for Amlogic SM1 SoC Family
From: Kevin Hilman @ 2019-08-20 23:06 UTC (permalink / raw)
To: Neil Armstrong
Cc: linux-amlogic, linux-kernel, linux-arm-kernel, Neil Armstrong
In-Reply-To: <7h4l2bej1c.fsf@baylibre.com>
Kevin Hilman <khilman@baylibre.com> writes:
> Neil Armstrong <narmstrong@baylibre.com> writes:
>
>> The new Amlogic SM1 SoC Family is a derivative of the Amlogic G12A
>> SoC Family, with the following changes :
>> - Cortex-A55 cores instead of A53
>> - more power domains, including USB & PCIe
>> - a neural network co-processor (NNA)
>> - a CSI input and image processor
>> - some changes in the audio complex, thus not yet enabled
>> - new clocks, for NNA, CSI and a clock tree for each CPU Core
>>
>> This serie does not add support for NNA, CSI, Audio, USB, Display
>> or DVFS, it only aligns with the current G12A Support.
>>
>> With this serie, the SEI610 Board has supported :
>> - Default-boot CPU frequency
>> - Ethernet
>> - LEDs
>> - IR
>> - GPIO Buttons
>> - eMMC
>> - SDCard
>> - SDIO WiFi
>> - UART Bluetooth
>>
>> Audio (HDMI, Embedded HP, MIcs), USB, HDMI, IR Output, & RGB Led
>> would be supported in following patchsets.
>>
>> Dependencies:
>> - g12-common.dtsi from the DVFS patchset at [1]
>>
>> Changes from rfc at [2]:
>> - Removed Power domain patches & display/USB support, will resend separately
>> - Removed applied AO-CEC patches
>> - Fixed clk-measure IDs
>> - Collected reviewed-by tags
>>
>> [1] https://patchwork.kernel.org/cover/11025309/
>> [2] https://patchwork.kernel.org/cover/11025511/
>
> Series queued for v5.4...
>> Neil Armstrong (6):
>> soc: amlogic: meson-gx-socinfo: Add SM1 and S905X3 IDs
>> dt-bindings: soc: amlogic: clk-measure: Add SM1 compatible
>> soc: amlogic: clk-measure: Add support for SM1
>
> ... these 3 in v5.4/drivers ...
>
>> dt-bindings: arm: amlogic: add SM1 bindings
>> dt-bindings: arm: amlogic: add SEI Robotics SEI610 bindings
>> arm64: dts: add support for SM1 based SEI Robotics SEI610
>
> ... and these 3 in v5.4/dt64 with Rob's tag.
And I forgot to add that I boot-tested this on an SEI610 as well.
Tested-by: Kevin Hilman <khilman@baylibre.com>
_______________________________________________
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 2/6] dt-bindings: net: sun8i-a83t-emac: Add phy-io-supply property
From: Ondřej Jirman @ 2019-08-20 22:36 UTC (permalink / raw)
To: Rob Herring
Cc: Mark Rutland, devicetree, Alexandre Torgue, netdev,
linux-kernel@vger.kernel.org, Maxime Ripard, linux-stm32,
Chen-Yu Tsai, Jose Abreu, Maxime Coquelin, Giuseppe Cavallaro,
David S. Miller,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <CAL_JsqJHNL91KMAP5ya97eiyTypGniCJ+tbP=NchPJK502i5FQ@mail.gmail.com>
On Tue, Aug 20, 2019 at 11:57:06AM -0500, Rob Herring wrote:
> On Tue, Aug 20, 2019 at 11:34 AM Ondřej Jirman <megous@megous.com> wrote:
> >
> > On Tue, Aug 20, 2019 at 11:20:22AM -0500, Rob Herring wrote:
> > > On Tue, Aug 20, 2019 at 9:53 AM <megous@megous.com> wrote:
> > > >
> > > > From: Ondrej Jirman <megous@megous.com>
> > > >
> > > > Some PHYs require separate power supply for I/O pins in some modes
> > > > of operation. Add phy-io-supply property, to allow enabling this
> > > > power supply.
> > >
> > > Perhaps since this is new, such phys should have *-supply in their nodes.
> >
> > Yes, I just don't understand, since external ethernet phys are so common,
> > and they require power, how there's no fairly generic mechanism for this
> > already in the PHY subsystem, or somewhere?
>
> Because generic mechanisms for this don't work. For example, what
> happens when the 2 supplies need to be turned on in a certain order
> and with certain timings? And then add in reset or control lines into
> the mix... You can see in the bindings we already have some of that.
I've looked at the emac bindings that have phy-supply, and don't see reason
why this can't be generic for the phy. Just like there's generic reset
properties for phys, now. Some bindings, like fsl-fec.txt even list
custom reset properties for phy as deprecated, and recommend using
generic ones.
From the point of the view of the emac driver, it just wants to power on/power
off the phy, and wait until it's ready to be communicated with.
It's probably better to have power supplies of the phy covered by generic
phy code, because then you don't have to duplicate all this special power
up logic in every emac driver, whenever a HW designer decides to combine
such emac with external phy that requires some special hadnling on powerup.
At the moment, this lack of flexibility is hacked around by adding multiple
regulators to the DTS, and making them dependent on each other (even if one
doesn't supply the other), just because this makes the regulator core driver
enable them all. Power up delays for the PHY are described as enable-ramp-delays
on the regulators (actual regulator ramp delay + wait time for PHY to initialize).
Basically just hacking the DT so that the Linux kernel in the end does what's
necessary, instead of DT describing the actual HW.
Adding a single supply property to the phy node, as you suggest will do nothing
to help this situation. It will just result in a more complicated dwmac-sun8i
driver and will not help anyone in the future.
So I think, maybe phy powerup should be moved to generic code, just like the
phy reset code was. Generic code can have multiple supplies and some generic
way to specify power up order and timings.
But I guess, this patch series is a dead end.
> > It looks like other ethernet mac drivers also implement supplies on phys
> > on the EMAC nodes. Just grep phy-supply through dt-bindings/net.
> >
> > Historical reasons, or am I missing something? It almost seems like I must
> > be missing something, since putting these properties to phy nodes
> > seems so obvious.
>
> Things get added one by one and one new property isn't that
> controversial. We've generally learned the lesson and avoid this
> pattern now, but ethernet phys are one of the older bindings.
Understood. So maybe the solution suggested above would improve the situation
eventually?
regards,
o.
> Rob
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox