* Re: [PATCH V2 1/2] hwmon: pwm-fan: Add profile support and add remove module support
From: Guenter Roeck @ 2020-06-02 14:28 UTC (permalink / raw)
To: Sandipan Patra
Cc: treding, jonathanh, kamil, jdelvare, robh+dt, u.kleine-koenig,
bbasu, bbiswas, kyarlagadda, linux-pwm, linux-hwmon, devicetree,
linux-tegra, linux-kernel
In-Reply-To: <1590992354-12623-1-git-send-email-spatra@nvidia.com>
On Mon, Jun 01, 2020 at 11:49:13AM +0530, Sandipan Patra wrote:
> Add support for profiles mode settings.
> This allows different fan settings for trip point temp/hyst/pwm.
> Tegra194 has multiple fan-profiles support.
>
> Signed-off-by: Sandipan Patra <spatra@nvidia.com>
The subject says "remove module support". What is this supposed to be
about ?
The code adds support for multiple cooling "profiles" but, unless I am
really missing something, no means to actually select a profile.
This adds a lot of complexity to the code with zero value.
Either case, and I may have mentioned this before, functionality like this
should really reside in the thermal core and not in individual drivers.
> ---
>
> PATCH V2:
> Cleaned pwm_fan_remove support as it is not required.
>
> drivers/hwmon/pwm-fan.c | 92 ++++++++++++++++++++++++++++++++++++++++++-------
> 1 file changed, 80 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c
> index 30b7b3e..1d2a416 100644
> --- a/drivers/hwmon/pwm-fan.c
> +++ b/drivers/hwmon/pwm-fan.c
> @@ -3,8 +3,10 @@
> * pwm-fan.c - Hwmon driver for fans connected to PWM lines.
> *
> * Copyright (c) 2014 Samsung Electronics Co., Ltd.
> + * Copyright (c) 2020, NVIDIA Corporation.
> *
> * Author: Kamil Debski <k.debski@samsung.com>
> + * Author: Sandipan Patra <spatra@nvidia.com>
You can not claim authorship for a driver by adding a few lines of code
to it.
> */
>
> #include <linux/hwmon.h>
> @@ -21,6 +23,8 @@
> #include <linux/timer.h>
>
> #define MAX_PWM 255
> +/* Based on OF max device tree node name length */
> +#define MAX_PROFILE_NAME_LENGTH 31
>
> struct pwm_fan_ctx {
> struct mutex lock;
> @@ -38,6 +42,12 @@ struct pwm_fan_ctx {
> unsigned int pwm_fan_state;
> unsigned int pwm_fan_max_state;
> unsigned int *pwm_fan_cooling_levels;
> +
> + unsigned int pwm_fan_profiles;
> + const char **fan_profile_names;
> + unsigned int **fan_profile_cooling_levels;
> + unsigned int fan_current_profile;
> +
> struct thermal_cooling_device *cdev;
> };
>
> @@ -227,28 +237,86 @@ static int pwm_fan_of_get_cooling_data(struct device *dev,
> struct pwm_fan_ctx *ctx)
> {
> struct device_node *np = dev->of_node;
> + struct device_node *base_profile = NULL;
> + struct device_node *profile_np = NULL;
> + const char *default_profile = NULL;
> int num, i, ret;
>
> - if (!of_find_property(np, "cooling-levels", NULL))
> - return 0;
> + num = of_property_count_u32_elems(np, "cooling-levels");
> + if (num <= 0) {
> + base_profile = of_get_child_by_name(np, "profiles");
You can not just add new properties like this without documenting it
and getting approval by devicetree maintainers.
Guenter
> + if (!base_profile) {
> + dev_err(dev, "Wrong Data\n");
> + return -EINVAL;
> + }
> + }
> +
> + if (base_profile) {
> + ctx->pwm_fan_profiles =
> + of_get_available_child_count(base_profile);
>
> - ret = of_property_count_u32_elems(np, "cooling-levels");
> - if (ret <= 0) {
> - dev_err(dev, "Wrong data!\n");
> - return ret ? : -EINVAL;
> + if (ctx->pwm_fan_profiles <= 0) {
> + dev_err(dev, "Profiles used but not defined\n");
> + return -EINVAL;
> + }
> +
> + ctx->fan_profile_names = devm_kzalloc(dev,
> + sizeof(const char *) * ctx->pwm_fan_profiles,
> + GFP_KERNEL);
> + ctx->fan_profile_cooling_levels = devm_kzalloc(dev,
> + sizeof(int *) * ctx->pwm_fan_profiles,
> + GFP_KERNEL);
> +
> + if (!ctx->fan_profile_names
> + || !ctx->fan_profile_cooling_levels)
> + return -ENOMEM;
> +
> + ctx->fan_current_profile = 0;
> + i = 0;
> + for_each_available_child_of_node(base_profile, profile_np) {
> + num = of_property_count_u32_elems(profile_np,
> + "cooling-levels");
> + if (num <= 0) {
> + dev_err(dev, "No data in cooling-levels inside profile node!\n");
> + return -EINVAL;
> + }
> +
> + of_property_read_string(profile_np, "name",
> + &ctx->fan_profile_names[i]);
> + if (default_profile &&
> + !strncmp(default_profile,
> + ctx->fan_profile_names[i],
> + MAX_PROFILE_NAME_LENGTH))
> + ctx->fan_current_profile = i;
> +
> + ctx->fan_profile_cooling_levels[i] =
> + devm_kzalloc(dev, sizeof(int) * num,
> + GFP_KERNEL);
> + if (!ctx->fan_profile_cooling_levels[i])
> + return -ENOMEM;
> +
> + of_property_read_u32_array(profile_np, "cooling-levels",
> + ctx->fan_profile_cooling_levels[i], num);
> + i++;
> + }
> }
>
> - num = ret;
> ctx->pwm_fan_cooling_levels = devm_kcalloc(dev, num, sizeof(u32),
> GFP_KERNEL);
> if (!ctx->pwm_fan_cooling_levels)
> return -ENOMEM;
>
> - ret = of_property_read_u32_array(np, "cooling-levels",
> - ctx->pwm_fan_cooling_levels, num);
> - if (ret) {
> - dev_err(dev, "Property 'cooling-levels' cannot be read!\n");
> - return ret;
> + if (base_profile) {
> + memcpy(ctx->pwm_fan_cooling_levels,
> + ctx->fan_profile_cooling_levels[ctx->fan_current_profile],
> + num);
> + } else {
> + ret = of_property_read_u32_array(np, "cooling-levels",
> + ctx->pwm_fan_cooling_levels, num);
> + if (ret) {
> + dev_err(dev, "Property 'cooling-levels' cannot be read!\n");
> + return -EINVAL;
> + }
> }
>
> for (i = 0; i < num; i++) {
^ permalink raw reply
* Re: [v2] drm/msm: add shutdown support for display platform_driver
From: Emil Velikov @ 2020-06-02 14:13 UTC (permalink / raw)
To: Krishna Manikandan
Cc: ML dri-devel, linux-arm-msm, freedreno, devicetree,
Linux-Kernel@Vger. Kernel. Org, Sean Paul, kalyan_t,
Kristian H . Kristensen, mka
In-Reply-To: <1591009402-681-1-git-send-email-mkrishn@codeaurora.org>
Hi Krishna,
On Tue, 2 Jun 2020 at 08:17, Krishna Manikandan <mkrishn@codeaurora.org> wrote:
>
> Define shutdown callback for display drm driver,
> so as to disable all the CRTCS when shutdown
> notification is received by the driver.
>
> This change will turn off the timing engine so
> that no display transactions are requested
> while mmu translations are getting disabled
> during reboot sequence.
>
> Signed-off-by: Krishna Manikandan <mkrishn@codeaurora.org>
>
AFAICT atomics is setup in msm_drm_ops::bind and shutdown in
msm_drm_ops::unbind.
Are you saying that unbind never triggers? If so, then we should
really fix that instead, since this patch seems more like a
workaround.
-Emil
^ permalink raw reply
* Re: [PATCH] ARM: dts: AM33xx-l4: add gpio-ranges
From: Tony Lindgren @ 2020-06-02 13:51 UTC (permalink / raw)
To: Grygorii Strashko
Cc: Drew Fustini, linux-omap, linux-kernel, Benoît Cousson,
Rob Herring, devicetree, Santosh Shilimkar, Suman Anna,
Haojian Zhuang, Linus Walleij, linux-gpio
In-Reply-To: <803e2d78-28ba-0816-dbb5-d441d7659a91@ti.com>
* Grygorii Strashko <grygorii.strashko@ti.com> [200602 13:44]:
>
>
> On 02/06/2020 16:14, Drew Fustini wrote:
> > Add gpio-ranges properties to the gpio controller nodes.
> >
> > These gpio-ranges were created based on "Table 9-10. CONTROL_MODULE
> > REGISTERS" in the "AM335x Technical Reference Manual" [0] and "Table
> > 4-2. Pin Attributes" in the "AM335x Sitara Processor datasheet" [1].
> > A csv file with this data is available for reference [2].
>
> It will be good if you can explain not only "what" is changed, but
> also "why" it's needed in commit message.
Also, please check (again) that this is the same for all the am3
variants. For omap3, we had different pad assignments even between
SoC revisions. Different pad routings should be easy to deal with
in the dts if needed though.
Regards,
Tony
^ permalink raw reply
* Re: [PATCH] ARM: dts: AM33xx-l4: add gpio-ranges
From: Grygorii Strashko @ 2020-06-02 13:44 UTC (permalink / raw)
To: Drew Fustini, Tony Lindgren, linux-omap, linux-kernel,
Benoît Cousson, Rob Herring, devicetree
Cc: Santosh Shilimkar, Suman Anna, Haojian Zhuang, Linus Walleij,
linux-gpio
In-Reply-To: <20200602131428.GA496390@x1>
On 02/06/2020 16:14, Drew Fustini wrote:
> Add gpio-ranges properties to the gpio controller nodes.
>
> These gpio-ranges were created based on "Table 9-10. CONTROL_MODULE
> REGISTERS" in the "AM335x Technical Reference Manual" [0] and "Table
> 4-2. Pin Attributes" in the "AM335x Sitara Processor datasheet" [1].
> A csv file with this data is available for reference [2].
It will be good if you can explain not only "what" is changed, but
also "why" it's needed in commit message.
>
> [0] https://www.ti.com/lit/ug/spruh73q/spruh73q.pdf
> [1] http://www.ti.com/lit/ds/symlink/am3358.pdf
> [2] https://gist.github.com/pdp7/6ffaddc8867973c1c3e8612cfaf72020
>
> Signed-off-by: Drew Fustini <drew@beagleboard.org>
> ---
> Notes:
> There was previous dicussion relevant to this patch:
> https://lore.kernel.org/linux-gpio/20200525131731.GA948395@x1/
>
> Here is the list I compiled which shows the mapping between a gpioline
> and the pin number including the memory address for the pin control
> register
>
> gpiochip,gpio-line,pinctrl-PIN,pinctrl-address
> 0,0,82,44e10948
> 0,1,83,44e1094c
> 0,2,84,44e10950
> 0,3,85,44e10954
> 0,4,86,44e10958
> 0,5,87,44e1095c
...
> On a BeagleBlack Black board (AM3358) with this patch:
> cat /sys/kernel/debug/pinctrl/44e10800.pinmux-pinctrl-single/gpio-ranges
>
> GPIO ranges handled:
> 0: gpio-0-31 GPIOS [0 - 7] PINS [82 - 89]
> 8: gpio-0-31 GPIOS [8 - 11] PINS [52 - 55]
> 12: gpio-0-31 GPIOS [12 - 15] PINS [94 - 97]
> 16: gpio-0-31 GPIOS [16 - 17] PINS [71 - 72]
> 18: gpio-0-31 GPIOS [18 - 18] PINS [135 - 135]
> 19: gpio-0-31 GPIOS [19 - 20] PINS [108 - 109]
> 21: gpio-0-31 GPIOS [21 - 21] PINS [73 - 73]
> 22: gpio-0-31 GPIOS [22 - 23] PINS [8 - 9]
> 26: gpio-0-31 GPIOS [26 - 27] PINS [10 - 11]
> 28: gpio-0-31 GPIOS [28 - 28] PINS [74 - 74]
> 29: gpio-0-31 GPIOS [29 - 29] PINS [81 - 81]
> 30: gpio-0-31 GPIOS [30 - 31] PINS [28 - 29]
> 0: gpio-32-63 GPIOS [32 - 39] PINS [0 - 7]
> 8: gpio-32-63 GPIOS [40 - 43] PINS [90 - 93]
> 12: gpio-32-63 GPIOS [44 - 59] PINS [12 - 27]
> 28: gpio-32-63 GPIOS [60 - 63] PINS [30 - 33]
> 0: gpio-64-95 GPIOS [64 - 81] PINS [34 - 51]
> 18: gpio-64-95 GPIOS [82 - 85] PINS [77 - 80]
> 22: gpio-64-95 GPIOS [86 - 95] PINS [56 - 65]
> 0: gpio-96-127 GPIOS [96 - 100] PINS [66 - 70]
> 5: gpio-96-127 GPIOS [101 - 102] PINS [98 - 99]
> 7: gpio-96-127 GPIOS [103 - 104] PINS [75 - 76]
> 13: gpio-96-127 GPIOS [109 - 109] PINS [141 - 141]
> 14: gpio-96-127 GPIOS [110 - 117] PINS [100 - 107]
>
> arch/arm/boot/dts/am33xx-l4.dtsi | 24 ++++++++++++++++++++++++
> 1 file changed, 24 insertions(+)
>
> diff --git a/arch/arm/boot/dts/am33xx-l4.dtsi b/arch/arm/boot/dts/am33xx-l4.dtsi
> index 5ed7f3c58c0f..340ea331e54d 100644
> --- a/arch/arm/boot/dts/am33xx-l4.dtsi
> +++ b/arch/arm/boot/dts/am33xx-l4.dtsi
> @@ -151,6 +151,18 @@ SYSC_OMAP2_SOFTRESET |
>
> gpio0: gpio@0 {
> compatible = "ti,omap4-gpio";
> + gpio-ranges = <&am33xx_pinmux 0 82 8>,
> + <&am33xx_pinmux 8 52 4>,
> + <&am33xx_pinmux 12 94 4>,
> + <&am33xx_pinmux 16 71 2>,
> + <&am33xx_pinmux 18 135 1>,
> + <&am33xx_pinmux 19 108 2>,
> + <&am33xx_pinmux 21 73 1>,
> + <&am33xx_pinmux 22 8 2>,
> + <&am33xx_pinmux 26 10 2>,
> + <&am33xx_pinmux 28 74 1>,
> + <&am33xx_pinmux 29 81 1>,
> + <&am33xx_pinmux 30 28 2>;
> gpio-controller;
> #gpio-cells = <2>;
> interrupt-controller;
> @@ -1298,6 +1310,10 @@ SYSC_OMAP2_SOFTRESET |
>
> gpio1: gpio@0 {
> compatible = "ti,omap4-gpio";
> + gpio-ranges = <&am33xx_pinmux 0 0 8>,
> + <&am33xx_pinmux 8 90 4>,
> + <&am33xx_pinmux 12 12 16>,
> + <&am33xx_pinmux 28 30 4>;
> gpio-controller;
> #gpio-cells = <2>;
> interrupt-controller;
> @@ -1700,6 +1716,9 @@ SYSC_OMAP2_SOFTRESET |
>
> gpio2: gpio@0 {
> compatible = "ti,omap4-gpio";
> + gpio-ranges = <&am33xx_pinmux 0 34 18>,
> + <&am33xx_pinmux 18 77 4>,
> + <&am33xx_pinmux 22 56 10>;
> gpio-controller;
> #gpio-cells = <2>;
> interrupt-controller;
> @@ -1733,6 +1752,11 @@ SYSC_OMAP2_SOFTRESET |
>
> gpio3: gpio@0 {
> compatible = "ti,omap4-gpio";
> + gpio-ranges = <&am33xx_pinmux 0 66 5>,
> + <&am33xx_pinmux 5 98 2>,
> + <&am33xx_pinmux 7 75 2>,
> + <&am33xx_pinmux 13 141 1>,
> + <&am33xx_pinmux 14 100 8>;
> gpio-controller;
> #gpio-cells = <2>;
> interrupt-controller;
>
--
Best regards,
grygorii
^ permalink raw reply
* [PATCH] dt-bindings: clock: Convert imx7ulp clock to json-schema
From: Anson Huang @ 2020-06-02 13:16 UTC (permalink / raw)
To: mturquette, sboyd, robh+dt, shawnguo, s.hauer, kernel, festevam,
aisheng.dong, linux-clk, devicetree, linux-arm-kernel,
linux-kernel
Cc: Linux-imx
Convert the i.MX7ULP clock binding to DT schema format using json-schema,
the original binding doc is actually for two clock modules(SCG and PCC),
so split it to two binding docs, and the MPLL(mipi PLL) is NOT supposed
to be in clock module, so remove it from binding doc as well.
Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
---
.../devicetree/bindings/clock/imx7ulp-clock.txt | 103 ------------------
.../bindings/clock/imx7ulp-pcc-clock.yaml | 119 +++++++++++++++++++++
.../bindings/clock/imx7ulp-scg-clock.yaml | 97 +++++++++++++++++
3 files changed, 216 insertions(+), 103 deletions(-)
delete mode 100644 Documentation/devicetree/bindings/clock/imx7ulp-clock.txt
create mode 100644 Documentation/devicetree/bindings/clock/imx7ulp-pcc-clock.yaml
create mode 100644 Documentation/devicetree/bindings/clock/imx7ulp-scg-clock.yaml
diff --git a/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt b/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt
deleted file mode 100644
index 93d89ad..0000000
--- a/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt
+++ /dev/null
@@ -1,103 +0,0 @@
-* Clock bindings for Freescale i.MX7ULP
-
-i.MX7ULP Clock functions are under joint control of the System
-Clock Generation (SCG) modules, Peripheral Clock Control (PCC)
-modules, and Core Mode Controller (CMC)1 blocks
-
-The clocking scheme provides clear separation between M4 domain
-and A7 domain. Except for a few clock sources shared between two
-domains, such as the System Oscillator clock, the Slow IRC (SIRC),
-and and the Fast IRC clock (FIRCLK), clock sources and clock
-management are separated and contained within each domain.
-
-M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules.
-A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules.
-
-Note: this binding doc is only for A7 clock domain.
-
-System Clock Generation (SCG) modules:
----------------------------------------------------------------------
-The System Clock Generation (SCG) is responsible for clock generation
-and distribution across this device. Functions performed by the SCG
-include: clock reference selection, generation of clock used to derive
-processor, system, peripheral bus and external memory interface clocks,
-source selection for peripheral clocks and control of power saving
-clock gating mode.
-
-Required properties:
-
-- compatible: Should be "fsl,imx7ulp-scg1".
-- reg : Should contain registers location and length.
-- #clock-cells: Should be <1>.
-- clocks: Should contain the fixed input clocks.
-- clock-names: Should contain the following clock names:
- "rosc", "sosc", "sirc", "firc", "upll", "mpll".
-
-Peripheral Clock Control (PCC) modules:
----------------------------------------------------------------------
-The Peripheral Clock Control (PCC) is responsible for clock selection,
-optional division and clock gating mode for peripherals in their
-respected power domain
-
-Required properties:
-- compatible: Should be one of:
- "fsl,imx7ulp-pcc2",
- "fsl,imx7ulp-pcc3".
-- reg : Should contain registers location and length.
-- #clock-cells: Should be <1>.
-- clocks: Should contain the fixed input clocks.
-- clock-names: Should contain the following clock names:
- "nic1_bus_clk", "nic1_clk", "ddr_clk", "apll_pfd2",
- "apll_pfd1", "apll_pfd0", "upll", "sosc_bus_clk",
- "mpll", "firc_bus_clk", "rosc", "spll_bus_clk";
-
-The clock consumer should specify the desired clock by having the clock
-ID in its "clocks" phandle cell.
-See include/dt-bindings/clock/imx7ulp-clock.h
-for the full list of i.MX7ULP clock IDs of each module.
-
-Examples:
-
-#include <dt-bindings/clock/imx7ulp-clock.h>
-
-scg1: scg1@403e0000 {
- compatible = "fsl,imx7ulp-scg1;
- reg = <0x403e0000 0x10000>;
- clocks = <&rosc>, <&sosc>, <&sirc>,
- <&firc>, <&upll>, <&mpll>;
- clock-names = "rosc", "sosc", "sirc",
- "firc", "upll", "mpll";
- #clock-cells = <1>;
-};
-
-pcc2: pcc2@403f0000 {
- compatible = "fsl,imx7ulp-pcc2";
- reg = <0x403f0000 0x10000>;
- #clock-cells = <1>;
- clocks = <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>,
- <&scg1 IMX7ULP_CLK_NIC1_DIV>,
- <&scg1 IMX7ULP_CLK_DDR_DIV>,
- <&scg1 IMX7ULP_CLK_APLL_PFD2>,
- <&scg1 IMX7ULP_CLK_APLL_PFD1>,
- <&scg1 IMX7ULP_CLK_APLL_PFD0>,
- <&scg1 IMX7ULP_CLK_UPLL>,
- <&scg1 IMX7ULP_CLK_SOSC_BUS_CLK>,
- <&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>,
- <&scg1 IMX7ULP_CLK_ROSC>,
- <&scg1 IMX7ULP_CLK_SPLL_BUS_CLK>;
- clock-names = "nic1_bus_clk", "nic1_clk", "ddr_clk",
- "apll_pfd2", "apll_pfd1", "apll_pfd0",
- "upll", "sosc_bus_clk", "mpll",
- "firc_bus_clk", "rosc", "spll_bus_clk";
-};
-
-usdhc1: usdhc@40380000 {
- compatible = "fsl,imx7ulp-usdhc";
- reg = <0x40380000 0x10000>;
- interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>,
- <&scg1 IMX7ULP_CLK_NIC1_DIV>,
- <&pcc2 IMX7ULP_CLK_USDHC1>;
- clock-names ="ipg", "ahb", "per";
- bus-width = <4>;
-};
diff --git a/Documentation/devicetree/bindings/clock/imx7ulp-pcc-clock.yaml b/Documentation/devicetree/bindings/clock/imx7ulp-pcc-clock.yaml
new file mode 100644
index 0000000..d5fd286
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/imx7ulp-pcc-clock.yaml
@@ -0,0 +1,119 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/imx7ulp-pcc-clock.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Clock bindings for Freescale i.MX7ULP Peripheral Clock Control (PCC) modules
+
+maintainers:
+ - A.s. Dong <aisheng.dong@nxp.com>
+
+description: |
+ i.MX7ULP Clock functions are under joint control of the System
+ Clock Generation (SCG) modules, Peripheral Clock Control (PCC)
+ modules, and Core Mode Controller (CMC)1 blocks
+
+ The clocking scheme provides clear separation between M4 domain
+ and A7 domain. Except for a few clock sources shared between two
+ domains, such as the System Oscillator clock, the Slow IRC (SIRC),
+ and and the Fast IRC clock (FIRCLK), clock sources and clock
+ management are separated and contained within each domain.
+
+ M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules.
+ A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules.
+
+ Note: this binding doc is only for A7 clock domain.
+
+ The Peripheral Clock Control (PCC) is responsible for clock selection,
+ optional division and clock gating mode for peripherals in their
+ respected power domain.
+
+ The clock consumer should specify the desired clock by having the clock
+ ID in its "clocks" phandle cell.
+ See include/dt-bindings/clock/imx7ulp-clock.h for the full list of
+ i.MX7ULP clock IDs of each module.
+
+properties:
+ compatible:
+ enum:
+ - fsl,imx7ulp-pcc2
+ - fsl,imx7ulp-pcc3
+
+ reg:
+ maxItems: 1
+
+ '#clock-cells':
+ const: 1
+
+ clocks:
+ items:
+ - description: nic1 bus clock
+ - description: nic1 clock
+ - description: ddr clock
+ - description: apll pfd2
+ - description: apll pfd1
+ - description: apll pfd0
+ - description: usb pll
+ - description: system osc bus clock
+ - description: fast internal reference clock bus
+ - description: rtc osc
+ - description: system pll bus clock
+
+ clock-names:
+ items:
+ - const: nic1_bus_clk
+ - const: nic1_clk
+ - const: ddr_clk
+ - const: apll_pfd2
+ - const: apll_pfd1
+ - const: apll_pfd0
+ - const: upll
+ - const: sosc_bus_clk
+ - const: firc_bus_clk
+ - const: rosc
+ - const: spll_bus_clk
+
+required:
+ - compatible
+ - reg
+ - '#clock-cells'
+ - clocks
+ - clock-names
+
+examples:
+ - |
+ #include <dt-bindings/clock/imx7ulp-clock.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ clock-controller@403f0000 {
+ compatible = "fsl,imx7ulp-pcc2";
+ reg = <0x403f0000 0x10000>;
+ #clock-cells = <1>;
+ clocks = <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>,
+ <&scg1 IMX7ULP_CLK_NIC1_DIV>,
+ <&scg1 IMX7ULP_CLK_DDR_DIV>,
+ <&scg1 IMX7ULP_CLK_APLL_PFD2>,
+ <&scg1 IMX7ULP_CLK_APLL_PFD1>,
+ <&scg1 IMX7ULP_CLK_APLL_PFD0>,
+ <&scg1 IMX7ULP_CLK_UPLL>,
+ <&scg1 IMX7ULP_CLK_SOSC_BUS_CLK>,
+ <&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>,
+ <&scg1 IMX7ULP_CLK_ROSC>,
+ <&scg1 IMX7ULP_CLK_SPLL_BUS_CLK>;
+ clock-names = "nic1_bus_clk", "nic1_clk", "ddr_clk",
+ "apll_pfd2", "apll_pfd1", "apll_pfd0",
+ "upll", "sosc_bus_clk", "firc_bus_clk",
+ "rosc", "spll_bus_clk";
+ };
+
+ mmc@40380000 {
+ compatible = "fsl,imx7ulp-usdhc";
+ reg = <0x40380000 0x10000>;
+ interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>,
+ <&scg1 IMX7ULP_CLK_NIC1_DIV>,
+ <&pcc2 IMX7ULP_CLK_USDHC1>;
+ clock-names ="ipg", "ahb", "per";
+ bus-width = <4>;
+ };
diff --git a/Documentation/devicetree/bindings/clock/imx7ulp-scg-clock.yaml b/Documentation/devicetree/bindings/clock/imx7ulp-scg-clock.yaml
new file mode 100644
index 0000000..ae2a648
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/imx7ulp-scg-clock.yaml
@@ -0,0 +1,97 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/imx7ulp-scg-clock.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Clock bindings for Freescale i.MX7ULP System Clock Generation (SCG) modules
+
+maintainers:
+ - A.s. Dong <aisheng.dong@nxp.com>
+
+description: |
+ i.MX7ULP Clock functions are under joint control of the System
+ Clock Generation (SCG) modules, Peripheral Clock Control (PCC)
+ modules, and Core Mode Controller (CMC)1 blocks
+
+ The clocking scheme provides clear separation between M4 domain
+ and A7 domain. Except for a few clock sources shared between two
+ domains, such as the System Oscillator clock, the Slow IRC (SIRC),
+ and and the Fast IRC clock (FIRCLK), clock sources and clock
+ management are separated and contained within each domain.
+
+ M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules.
+ A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules.
+
+ Note: this binding doc is only for A7 clock domain.
+
+ The System Clock Generation (SCG) is responsible for clock generation
+ and distribution across this device. Functions performed by the SCG
+ include: clock reference selection, generation of clock used to derive
+ processor, system, peripheral bus and external memory interface clocks,
+ source selection for peripheral clocks and control of power saving
+ clock gating mode.
+
+ The clock consumer should specify the desired clock by having the clock
+ ID in its "clocks" phandle cell.
+ See include/dt-bindings/clock/imx7ulp-clock.h for the full list of
+ i.MX7ULP clock IDs of each module.
+
+properties:
+ compatible:
+ const: fsl,imx7ulp-scg1
+
+ reg:
+ maxItems: 1
+
+ '#clock-cells':
+ const: 1
+
+ clocks:
+ items:
+ - description: rtc osc
+ - description: system osc
+ - description: slow internal reference clock
+ - description: fast internal reference clock
+ - description: usb PLL
+
+ clock-names:
+ items:
+ - const: rosc
+ - const: sosc
+ - const: sirc
+ - const: firc
+ - const: upll
+
+required:
+ - compatible
+ - reg
+ - '#clock-cells'
+ - clocks
+ - clock-names
+
+examples:
+ - |
+ #include <dt-bindings/clock/imx7ulp-clock.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ clock-controller@403e0000 {
+ compatible = "fsl,imx7ulp-scg1";
+ reg = <0x403e0000 0x10000>;
+ clocks = <&rosc>, <&sosc>, <&sirc>,
+ <&firc>, <&upll>;
+ clock-names = "rosc", "sosc", "sirc",
+ "firc", "upll";
+ #clock-cells = <1>;
+ };
+
+ mmc@40380000 {
+ compatible = "fsl,imx7ulp-usdhc";
+ reg = <0x40380000 0x10000>;
+ interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>,
+ <&scg1 IMX7ULP_CLK_NIC1_DIV>,
+ <&pcc2 IMX7ULP_CLK_USDHC1>;
+ clock-names ="ipg", "ahb", "per";
+ bus-width = <4>;
+ };
--
2.7.4
^ permalink raw reply related
* [PATCH] ARM: dts: AM33xx-l4: add gpio-ranges
From: Drew Fustini @ 2020-06-02 13:14 UTC (permalink / raw)
To: Tony Lindgren, linux-omap, linux-kernel, Benoît Cousson,
Rob Herring, devicetree
Cc: Santosh Shilimkar, Suman Anna, Grygorii Strashko, Haojian Zhuang,
Linus Walleij, linux-gpio
Add gpio-ranges properties to the gpio controller nodes.
These gpio-ranges were created based on "Table 9-10. CONTROL_MODULE
REGISTERS" in the "AM335x Technical Reference Manual" [0] and "Table
4-2. Pin Attributes" in the "AM335x Sitara Processor datasheet" [1].
A csv file with this data is available for reference [2].
[0] https://www.ti.com/lit/ug/spruh73q/spruh73q.pdf
[1] http://www.ti.com/lit/ds/symlink/am3358.pdf
[2] https://gist.github.com/pdp7/6ffaddc8867973c1c3e8612cfaf72020
Signed-off-by: Drew Fustini <drew@beagleboard.org>
---
Notes:
There was previous dicussion relevant to this patch:
https://lore.kernel.org/linux-gpio/20200525131731.GA948395@x1/
Here is the list I compiled which shows the mapping between a gpioline
and the pin number including the memory address for the pin control
register
gpiochip,gpio-line,pinctrl-PIN,pinctrl-address
0,0,82,44e10948
0,1,83,44e1094c
0,2,84,44e10950
0,3,85,44e10954
0,4,86,44e10958
0,5,87,44e1095c
0,6,88,44e10960
0,7,89,44e10964
0,8,52,44e108d0
0,9,53,44e108d4
0,10,54,44e108d8
0,11,55,44e108dc
0,12,94,44e10978
0,13,95,44e1097c
0,14,96,44e10980
0,15,97,44e10984
0,16,71,44e1091c
0,17,72,44e10920
0,18,135,44e10a1c
0,19,108,44e109b0
0,20,109,44e109b4
0,21,73,44e10924
0,22,8,44e10820
0,23,9,44e10824
0,26,10,44e10828
0,27,11,44e1082c
0,28,74,44e10928
0,29,81,44e10944
0,30,28,44e10870
0,31,29,44e10874
1,0,0,44e10800
1,1,1,44e10804
1,2,2,44e10808
1,3,3,44e1080c
1,4,4,44e10810
1,5,5,44e10814
1,6,6,44e10818
1,7,7,44e1081c
1,8,90,44e10968
1,9,91,44e1096c
1,10,92,44e10970
1,11,93,44e10974
1,12,12,44e10830
1,13,13,44e10834
1,14,14,44e10838
1,15,15,44e1083c
1,16,16,44e10840
1,17,17,44e10844
1,18,18,44e10848
1,19,19,44e1084c
1,20,20,44e10850
1,21,21,44e10854
1,22,22,44e10858
1,23,23,44e1085c
1,24,24,44e10860
1,25,25,44e10864
1,26,26,44e10868
1,27,27,44e1086c
1,28,30,44e10878
1,29,31,44e1087c
1,30,32,44e10880
1,31,33,44e10884
2,0,34,44e10888
2,1,35,44e1088c
2,2,36,44e10890
2,3,37,44e10894
2,4,38,44e10898
2,5,39,44e1089c
2,6,40,44e108a0
2,7,41,44e108a4
2,8,42,44e108a8
2,9,43,44e108ac
2,10,44,44e108b0
2,11,45,44e108b4
2,12,46,44e108b8
2,13,47,44e108bc
2,14,48,44e108c0
2,15,49,44e108c4
2,16,50,44e108c8
2,17,51,44e108cc
2,18,77,44e10934
2,19,78,44e10938
2,20,79,44e1093c
2,21,80,44e10940
2,22,56,44e108e0
2,23,57,44e108e4
2,24,58,44e108e8
2,25,59,44e108ec
2,26,60,44e108f0
2,27,61,44e108f4
2,28,62,44e108f8
2,29,63,44e108fc
2,30,64,44e10900
2,31,65,44e10904
3,0,66,44e10908
3,1,67,44e1090c
3,2,68,44e10910
3,3,69,44e10914
3,4,70,44e10918
3,5,98,44e10988
3,6,99,44e1098c
3,9,75,44e1092c
3,10,76,44e10930
3,13,141,44e10a34
3,14,100,44e10990
3,15,101,44e10994
3,16,102,44e10998
3,17,103,44e1099c
3,18,104,44e109a0
3,19,105,44e109a4
3,20,106,44e109a8
3,21,107,44e109ac
On a BeagleBlack Black board (AM3358) with this patch:
cat /sys/kernel/debug/pinctrl/44e10800.pinmux-pinctrl-single/gpio-ranges
GPIO ranges handled:
0: gpio-0-31 GPIOS [0 - 7] PINS [82 - 89]
8: gpio-0-31 GPIOS [8 - 11] PINS [52 - 55]
12: gpio-0-31 GPIOS [12 - 15] PINS [94 - 97]
16: gpio-0-31 GPIOS [16 - 17] PINS [71 - 72]
18: gpio-0-31 GPIOS [18 - 18] PINS [135 - 135]
19: gpio-0-31 GPIOS [19 - 20] PINS [108 - 109]
21: gpio-0-31 GPIOS [21 - 21] PINS [73 - 73]
22: gpio-0-31 GPIOS [22 - 23] PINS [8 - 9]
26: gpio-0-31 GPIOS [26 - 27] PINS [10 - 11]
28: gpio-0-31 GPIOS [28 - 28] PINS [74 - 74]
29: gpio-0-31 GPIOS [29 - 29] PINS [81 - 81]
30: gpio-0-31 GPIOS [30 - 31] PINS [28 - 29]
0: gpio-32-63 GPIOS [32 - 39] PINS [0 - 7]
8: gpio-32-63 GPIOS [40 - 43] PINS [90 - 93]
12: gpio-32-63 GPIOS [44 - 59] PINS [12 - 27]
28: gpio-32-63 GPIOS [60 - 63] PINS [30 - 33]
0: gpio-64-95 GPIOS [64 - 81] PINS [34 - 51]
18: gpio-64-95 GPIOS [82 - 85] PINS [77 - 80]
22: gpio-64-95 GPIOS [86 - 95] PINS [56 - 65]
0: gpio-96-127 GPIOS [96 - 100] PINS [66 - 70]
5: gpio-96-127 GPIOS [101 - 102] PINS [98 - 99]
7: gpio-96-127 GPIOS [103 - 104] PINS [75 - 76]
13: gpio-96-127 GPIOS [109 - 109] PINS [141 - 141]
14: gpio-96-127 GPIOS [110 - 117] PINS [100 - 107]
arch/arm/boot/dts/am33xx-l4.dtsi | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/arch/arm/boot/dts/am33xx-l4.dtsi b/arch/arm/boot/dts/am33xx-l4.dtsi
index 5ed7f3c58c0f..340ea331e54d 100644
--- a/arch/arm/boot/dts/am33xx-l4.dtsi
+++ b/arch/arm/boot/dts/am33xx-l4.dtsi
@@ -151,6 +151,18 @@ SYSC_OMAP2_SOFTRESET |
gpio0: gpio@0 {
compatible = "ti,omap4-gpio";
+ gpio-ranges = <&am33xx_pinmux 0 82 8>,
+ <&am33xx_pinmux 8 52 4>,
+ <&am33xx_pinmux 12 94 4>,
+ <&am33xx_pinmux 16 71 2>,
+ <&am33xx_pinmux 18 135 1>,
+ <&am33xx_pinmux 19 108 2>,
+ <&am33xx_pinmux 21 73 1>,
+ <&am33xx_pinmux 22 8 2>,
+ <&am33xx_pinmux 26 10 2>,
+ <&am33xx_pinmux 28 74 1>,
+ <&am33xx_pinmux 29 81 1>,
+ <&am33xx_pinmux 30 28 2>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
@@ -1298,6 +1310,10 @@ SYSC_OMAP2_SOFTRESET |
gpio1: gpio@0 {
compatible = "ti,omap4-gpio";
+ gpio-ranges = <&am33xx_pinmux 0 0 8>,
+ <&am33xx_pinmux 8 90 4>,
+ <&am33xx_pinmux 12 12 16>,
+ <&am33xx_pinmux 28 30 4>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
@@ -1700,6 +1716,9 @@ SYSC_OMAP2_SOFTRESET |
gpio2: gpio@0 {
compatible = "ti,omap4-gpio";
+ gpio-ranges = <&am33xx_pinmux 0 34 18>,
+ <&am33xx_pinmux 18 77 4>,
+ <&am33xx_pinmux 22 56 10>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
@@ -1733,6 +1752,11 @@ SYSC_OMAP2_SOFTRESET |
gpio3: gpio@0 {
compatible = "ti,omap4-gpio";
+ gpio-ranges = <&am33xx_pinmux 0 66 5>,
+ <&am33xx_pinmux 5 98 2>,
+ <&am33xx_pinmux 7 75 2>,
+ <&am33xx_pinmux 13 141 1>,
+ <&am33xx_pinmux 14 100 8>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
--
2.25.1
^ permalink raw reply related
* Re: Security Random Number Generator support
From: Marc Zyngier @ 2020-06-02 13:02 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: Neal Liu,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Herbert Xu, Arnd Bergmann, Greg Kroah-Hartman, Sean Wang, lkml,
wsd_upstream, Rob Herring, linux-mediatek,
Linux Crypto Mailing List, Matt Mackall, Matthias Brugger,
Crystal Guo, Linux ARM
In-Reply-To: <CAMj1kXHjAdk5=-uSh_=S9j5cz42zr3h6t+YYGy+obevuQDp0fg@mail.gmail.com>
On 2020-06-02 13:14, Ard Biesheuvel wrote:
> On Tue, 2 Jun 2020 at 10:15, Neal Liu <neal.liu@mediatek.com> wrote:
>>
>> These patch series introduce a security random number generator
>> which provides a generic interface to get hardware rnd from Secure
>> state. The Secure state can be Arm Trusted Firmware(ATF), Trusted
>> Execution Environment(TEE), or even EL2 hypervisor.
>>
>> Patch #1..2 adds sec-rng kernel driver for Trustzone based SoCs.
>> For security awareness SoCs on ARMv8 with TrustZone enabled,
>> peripherals like entropy sources is not accessible from normal world
>> (linux) and rather accessible from secure world (HYP/ATF/TEE) only.
>> This driver aims to provide a generic interface to Arm Trusted
>> Firmware or Hypervisor rng service.
>>
>>
>> changes since v1:
>> - rename mt67xx-rng to mtk-sec-rng since all MediaTek ARMv8 SoCs can
>> reuse
>> this driver.
>> - refine coding style and unnecessary check.
>>
>> changes since v2:
>> - remove unused comments.
>> - remove redundant variable.
>>
>> changes since v3:
>> - add dt-bindings for MediaTek rng with TrustZone enabled.
>> - revise HWRNG SMC call fid.
>>
>> changes since v4:
>> - move bindings to the arm/firmware directory.
>> - revise driver init flow to check more property.
>>
>> changes since v5:
>> - refactor to more generic security rng driver which
>> is not platform specific.
>>
>> *** BLURB HERE ***
>>
>> Neal Liu (2):
>> dt-bindings: rng: add bindings for sec-rng
>> hwrng: add sec-rng driver
>>
>
> There is no reason to model a SMC call as a driver, and represent it
> via a DT node like this.
+1.
> It would be much better if this SMC interface is made truly generic,
> and wired into the arch_get_random() interface, which can be used much
> earlier.
Wasn't there a plan to standardize a SMC call to rule them all?
M.
--
Who you jivin' with that Cosmik Debris?
^ permalink raw reply
* Re: [PATCH v2 09/12] iio: imu: inv_icm42600: add buffer support in iio devices
From: Jean-Baptiste Maneyrol @ 2020-06-02 12:57 UTC (permalink / raw)
To: Jonathan Cameron
Cc: robh+dt@kernel.org, robh@kernel.org, mchehab+huawei@kernel.org,
davem@davemloft.net, gregkh@linuxfoundation.org,
linux-iio@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <20200531135615.7938fb96@archlinux>
Hi Jonathan,
I agree that this multiplexed watermark computation value is anything except simple and clear to understand.
I will add more documentation about it. And it also triggered a kbuild robot issue, because it is using 64 bits modulo without using math64 macros.
For buffer preenable/postenable/..., the sequence I am using currently is:
- preenable -> turn chip on (pm_runtime_get)
- update_scan_mode -> set FIFO en bits configuration (which sensor data is going into the fifo)
- hwfifo_watermark -> compute and set watermark value
- postenable -> turn FIFO on (and multiplexed with a FIFO on counter since used by accel & gyro)
- predisable -> turn FIFO off (multiplexed with counter)
- postdisable -> turn chip off (pm_runtime_put)
This setting is working well. Good to note that if there is an error when enabling the buffer, postdisable will always get called after preenable. So it ensures pm_runtime reference counter to be always OK.
Another way would be to only store configuration in internal state with update_scan_mode and hwfifo_watermark, and do everything in postenable/predisable. This is a possibility, but makes things a little more complex.
For hwfifo flush, this is an interesting feature when there is a need to have data immediately. Or when there is a need to do a clean change of configuration. In Android systems, Android framework is mainly using FIFO flush to change the sensor configuration (ODR, watermark) in a clean way. For our case with the FIFO interleaved this is a not an issue. If there are samples from the 2 sensors, it means the 2 buffers are enabled. And if data is coming to the iio buffer sooner than expected, that should not be a problem. The limitation I see when the 2 sensors are runnings, is that we will return less data than should have been possible. I limit FIFO reading to the provided n bytes, so we could read less than n samples of 1 sensor.
Something I have in mind, that would be really interesting to be able to set/change watermark value when the buffer is enabled. Otherwise, we are always loosing events by turning sensor off when we want to change the value. Is there any limitation to work this way, or should it be possible to implement this feature in the future ?
Thanks,
JB
From: Jonathan Cameron <jic23@kernel.org>
Sent: Sunday, May 31, 2020 14:56
To: Jean-Baptiste Maneyrol <JManeyrol@invensense.com>
Cc: robh+dt@kernel.org <robh+dt@kernel.org>; robh@kernel.org <robh@kernel.org>; mchehab+huawei@kernel.org <mchehab+huawei@kernel.org>; davem@davemloft.net <davem@davemloft.net>; gregkh@linuxfoundation.org <gregkh@linuxfoundation.org>; linux-iio@vger.kernel.org <linux-iio@vger.kernel.org>; devicetree@vger.kernel.org <devicetree@vger.kernel.org>; linux-kernel@vger.kernel.org <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v2 09/12] iio: imu: inv_icm42600: add buffer support in iio devices
CAUTION: This email originated from outside of the organization. Please make sure the sender is who they say they are and do not click links or open attachments unless you recognize the sender and know the content is safe.
On Wed, 27 May 2020 20:57:08 +0200
Jean-Baptiste Maneyrol <jmaneyrol@invensense.com> wrote:
> Add all FIFO parsing and reading functions. Add accel and gyro
> kfifo buffer and FIFO data parsing. Use device interrupt for
> reading data FIFO and launching accel and gyro parsing.
>
> Support hwfifo watermark by multiplexing gyro and accel settings.
> Support hwfifo flush.
Both of these are complex given the interactions of the two sensors
types and to be honest I couldn't figure out exactly what the intent was.
Needs more docs!
Thanks,
Jonathan
>
> Signed-off-by: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
> ---
> drivers/iio/imu/inv_icm42600/Kconfig | 1 +
> drivers/iio/imu/inv_icm42600/Makefile | 1 +
> drivers/iio/imu/inv_icm42600/inv_icm42600.h | 8 +
> .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 160 ++++-
> .../imu/inv_icm42600/inv_icm42600_buffer.c | 555 ++++++++++++++++++
> .../imu/inv_icm42600/inv_icm42600_buffer.h | 98 ++++
> .../iio/imu/inv_icm42600/inv_icm42600_core.c | 30 +
> .../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 160 ++++-
> 8 files changed, 1011 insertions(+), 2 deletions(-)
> create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
> create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h
>
> diff --git a/drivers/iio/imu/inv_icm42600/Kconfig b/drivers/iio/imu/inv_icm42600/Kconfig
> index 22390a72f0a3..50cbcfcb6cf1 100644
> --- a/drivers/iio/imu/inv_icm42600/Kconfig
> +++ b/drivers/iio/imu/inv_icm42600/Kconfig
> @@ -2,6 +2,7 @@
>
> config INV_ICM42600
> tristate
> + select IIO_BUFFER
>
> config INV_ICM42600_I2C
> tristate "InvenSense ICM-426xx I2C driver"
> diff --git a/drivers/iio/imu/inv_icm42600/Makefile b/drivers/iio/imu/inv_icm42600/Makefile
> index 48965824f00c..0f49f6df3647 100644
> --- a/drivers/iio/imu/inv_icm42600/Makefile
> +++ b/drivers/iio/imu/inv_icm42600/Makefile
> @@ -5,6 +5,7 @@ inv-icm42600-y += inv_icm42600_core.o
> inv-icm42600-y += inv_icm42600_gyro.o
> inv-icm42600-y += inv_icm42600_accel.o
> inv-icm42600-y += inv_icm42600_temp.o
> +inv-icm42600-y += inv_icm42600_buffer.o
>
> obj-$(CONFIG_INV_ICM42600_I2C) += inv-icm42600-i2c.o
> inv-icm42600-i2c-y += inv_icm42600_i2c.o
> diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
> index 43749f56426c..4d5811562a61 100644
> --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h
> +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
> @@ -14,6 +14,8 @@
> #include <linux/pm.h>
> #include <linux/iio/iio.h>
>
> +#include "inv_icm42600_buffer.h"
> +
> enum inv_icm42600_chip {
> INV_CHIP_ICM42600,
> INV_CHIP_ICM42602,
> @@ -123,6 +125,7 @@ struct inv_icm42600_suspended {
> * @indio_gyro: gyroscope IIO device.
> * @indio_accel: accelerometer IIO device.
> * @buffer: data transfer buffer aligned for DMA.
> + * @fifo: FIFO management structure.
> */
> struct inv_icm42600_state {
> struct mutex lock;
> @@ -137,6 +140,7 @@ struct inv_icm42600_state {
> struct iio_dev *indio_gyro;
> struct iio_dev *indio_accel;
> uint8_t buffer[2] ____cacheline_aligned;
> + struct inv_icm42600_fifo fifo;
> };
>
> /* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */
> @@ -377,6 +381,10 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq,
>
> int inv_icm42600_gyro_init(struct inv_icm42600_state *st);
>
> +int inv_icm42600_gyro_parse_fifo(struct iio_dev *indio_dev);
> +
> int inv_icm42600_accel_init(struct inv_icm42600_state *st);
>
> +int inv_icm42600_accel_parse_fifo(struct iio_dev *indio_dev);
> +
> #endif
> diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
> index 6a615d7ffb24..c73ce204efc6 100644
> --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
> +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
> @@ -11,9 +11,12 @@
> #include <linux/delay.h>
> #include <linux/math64.h>
> #include <linux/iio/iio.h>
> +#include <linux/iio/buffer.h>
> +#include <linux/iio/kfifo_buf.h>
>
> #include "inv_icm42600.h"
> #include "inv_icm42600_temp.h"
> +#include "inv_icm42600_buffer.h"
>
> #define INV_ICM42600_ACCEL_CHAN(_modifier, _index, _ext_info) \
> { \
> @@ -64,6 +67,76 @@ static const struct iio_chan_spec inv_icm42600_accel_channels[] = {
> INV_ICM42600_TEMP_CHAN(INV_ICM42600_ACCEL_SCAN_TEMP),
> };
>
> +/* IIO buffer data: 8 bytes */
> +struct inv_icm42600_accel_buffer {
> + struct inv_icm42600_fifo_sensor_data accel;
> + int8_t temp;
> + uint8_t padding;
> +};
> +
> +#define INV_ICM42600_SCAN_MASK_ACCEL_3AXIS \
> + (BIT(INV_ICM42600_ACCEL_SCAN_X) | \
> + BIT(INV_ICM42600_ACCEL_SCAN_Y) | \
> + BIT(INV_ICM42600_ACCEL_SCAN_Z))
> +
> +#define INV_ICM42600_SCAN_MASK_TEMP BIT(INV_ICM42600_ACCEL_SCAN_TEMP)
> +
> +static const unsigned long inv_icm42600_accel_scan_masks[] = {
> + /* 3-axis accel + temperature */
> + INV_ICM42600_SCAN_MASK_ACCEL_3AXIS | INV_ICM42600_SCAN_MASK_TEMP,
> + 0,
> +};
> +
> +/* enable accelerometer sensor and FIFO write */
> +static int inv_icm42600_accel_update_scan_mode(struct iio_dev *indio_dev,
> + const unsigned long *scan_mask)
> +{
> + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
> + struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
> + unsigned int fifo_en = 0;
> + unsigned int sleep_temp = 0;
> + unsigned int sleep_accel = 0;
> + unsigned int sleep;
> + int ret;
> +
> + mutex_lock(&st->lock);
> +
> + if (*scan_mask & INV_ICM42600_SCAN_MASK_TEMP) {
> + /* enable temp sensor */
> + ret = inv_icm42600_set_temp_conf(st, true, &sleep_temp);
> + if (ret)
> + goto out_unlock;
> + fifo_en |= INV_ICM42600_SENSOR_TEMP;
> + }
> +
> + if (*scan_mask & INV_ICM42600_SCAN_MASK_ACCEL_3AXIS) {
> + /* enable accel sensor */
> + conf.mode = INV_ICM42600_SENSOR_MODE_LOW_NOISE;
> + ret = inv_icm42600_set_accel_conf(st, &conf, &sleep_accel);
> + if (ret)
> + goto out_unlock;
> + fifo_en |= INV_ICM42600_SENSOR_ACCEL;
> + }
> +
> + /* update data FIFO write */
> + ret = inv_icm42600_buffer_set_fifo_en(st, fifo_en | st->fifo.en);
> + if (ret)
> + goto out_unlock;
> +
> + ret = inv_icm42600_buffer_update_watermark(st);
> +
> +out_unlock:
> + mutex_unlock(&st->lock);
> + /* sleep maximum required time */
> + if (sleep_accel > sleep_temp)
> + sleep = sleep_accel;
> + else
> + sleep = sleep_temp;
> + if (sleep)
> + msleep(sleep);
> + return ret;
> +}
> +
> static int inv_icm42600_accel_read_sensor(struct inv_icm42600_state *st,
> struct iio_chan_spec const *chan,
> int16_t *val)
> @@ -248,7 +321,12 @@ static int inv_icm42600_accel_write_odr(struct inv_icm42600_state *st,
> mutex_lock(&st->lock);
>
> ret = inv_icm42600_set_accel_conf(st, &conf, NULL);
> + if (ret)
> + goto out_unlock;
> + inv_icm42600_buffer_update_fifo_period(st);
> + inv_icm42600_buffer_update_watermark(st);
>
> +out_unlock:
> mutex_unlock(&st->lock);
> pm_runtime_mark_last_busy(dev);
> pm_runtime_put_autosuspend(dev);
> @@ -563,12 +641,51 @@ static int inv_icm42600_accel_write_raw_get_fmt(struct iio_dev *indio_dev,
> }
> }
>
> +static int inv_icm42600_accel_hwfifo_set_watermark(struct iio_dev *indio_dev,
> + unsigned int val)
> +{
> + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
> + int ret;
> +
> + mutex_lock(&st->lock);
> +
> + st->fifo.watermark.accel = val;
> + ret = inv_icm42600_buffer_update_watermark(st);
> +
> + mutex_unlock(&st->lock);
> +
> + return ret;
> +}
> +
> +static int inv_icm42600_accel_hwfifo_flush(struct iio_dev *indio_dev,
> + unsigned int count)
> +{
> + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
> + int ret;
> +
> + if (count == 0)
> + return 0;
> +
> + mutex_lock(&st->lock);
> +
> + ret = inv_icm42600_buffer_hwfifo_flush(st, count);
> + if (!ret)
> + ret = st->fifo.nb.accel;
> +
> + mutex_unlock(&st->lock);
> +
> + return ret;
> +}
> +
> static const struct iio_info inv_icm42600_accel_info = {
> .read_raw = inv_icm42600_accel_read_raw,
> .read_avail = inv_icm42600_accel_read_avail,
> .write_raw = inv_icm42600_accel_write_raw,
> .write_raw_get_fmt = inv_icm42600_accel_write_raw_get_fmt,
> .debugfs_reg_access = inv_icm42600_debugfs_reg,
> + .update_scan_mode = inv_icm42600_accel_update_scan_mode,
> + .hwfifo_set_watermark = inv_icm42600_accel_hwfifo_set_watermark,
> + .hwfifo_flush_to_buffer = inv_icm42600_accel_hwfifo_flush,
> };
>
> int inv_icm42600_accel_init(struct inv_icm42600_state *st)
> @@ -576,6 +693,7 @@ int inv_icm42600_accel_init(struct inv_icm42600_state *st)
> struct device *dev = regmap_get_device(st->map);
> const char *name;
> struct iio_dev *indio_dev;
> + struct iio_buffer *buffer;
>
> name = devm_kasprintf(dev, GFP_KERNEL, "%s-accel", st->name);
> if (!name)
> @@ -585,14 +703,54 @@ int inv_icm42600_accel_init(struct inv_icm42600_state *st)
> if (!indio_dev)
> return -ENOMEM;
>
> + buffer = devm_iio_kfifo_allocate(dev);
> + if (!buffer)
> + return -ENOMEM;
> +
> iio_device_set_drvdata(indio_dev, st);
> indio_dev->dev.parent = dev;
> indio_dev->name = name;
> indio_dev->info = &inv_icm42600_accel_info;
> - indio_dev->modes = INDIO_DIRECT_MODE;
> + indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
> indio_dev->channels = inv_icm42600_accel_channels;
> indio_dev->num_channels = ARRAY_SIZE(inv_icm42600_accel_channels);
> + indio_dev->available_scan_masks = inv_icm42600_accel_scan_masks;
> + indio_dev->setup_ops = &inv_icm42600_buffer_ops;
> +
> + iio_device_attach_buffer(indio_dev, buffer);
>
> st->indio_accel = indio_dev;
> return devm_iio_device_register(dev, st->indio_accel);
> }
> +
> +int inv_icm42600_accel_parse_fifo(struct iio_dev *indio_dev)
> +{
> + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
> + ssize_t i, size;
> + const void *accel, *gyro, *timestamp;
> + const int8_t *temp;
> + unsigned int odr;
> + struct inv_icm42600_accel_buffer buffer = {
> + .padding = 0,
> + };
> +
> + /* parse all fifo packets */
> + for (i = 0; i < st->fifo.count; i += size) {
> + size = inv_icm42600_fifo_decode_packet(&st->fifo.data[i],
> + &accel, &gyro, &temp, ×tamp, &odr);
> + /* quit if error or FIFO is empty */
> + if (size <= 0)
> + return size;
> +
> + /* skip packet if no accel data or data is invalid */
> + if (accel == NULL || !inv_icm42600_fifo_is_data_valid(accel))
> + continue;
> +
> + /* fill and push data buffer */
> + memcpy(&buffer.accel, accel, sizeof(buffer.accel));
> + buffer.temp = temp ? *temp : 0;
> + iio_push_to_buffers(indio_dev, &buffer);
> + }
> +
> + return 0;
> +}
> diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
> new file mode 100644
> index 000000000000..c91075f62231
> --- /dev/null
> +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
> @@ -0,0 +1,555 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2020 Invensense, Inc.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/device.h>
> +#include <linux/mutex.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> +#include <linux/delay.h>
> +#include <linux/math64.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/buffer.h>
> +
> +#include "inv_icm42600.h"
> +#include "inv_icm42600_buffer.h"
> +
> +/* FIFO header: 1 byte */
> +#define INV_ICM42600_FIFO_HEADER_MSG BIT(7)
> +#define INV_ICM42600_FIFO_HEADER_ACCEL BIT(6)
> +#define INV_ICM42600_FIFO_HEADER_GYRO BIT(5)
> +#define INV_ICM42600_FIFO_HEADER_TMST_FSYNC GENMASK(3, 2)
> +#define INV_ICM42600_FIFO_HEADER_ODR_ACCEL BIT(1)
> +#define INV_ICM42600_FIFO_HEADER_ODR_GYRO BIT(0)
> +
> +struct inv_icm42600_fifo_1sensor_packet {
> + uint8_t header;
> + struct inv_icm42600_fifo_sensor_data data;
> + int8_t temp;
> +} __packed;
> +#define INV_ICM42600_FIFO_1SENSOR_PACKET_SIZE 8
> +
> +struct inv_icm42600_fifo_2sensors_packet {
> + uint8_t header;
> + struct inv_icm42600_fifo_sensor_data accel;
> + struct inv_icm42600_fifo_sensor_data gyro;
> + int8_t temp;
> + __be16 timestamp;
> +} __packed;
> +#define INV_ICM42600_FIFO_2SENSORS_PACKET_SIZE 16
> +
> +ssize_t inv_icm42600_fifo_decode_packet(const void *packet, const void **accel,
> + const void **gyro, const int8_t **temp,
> + const void **timestamp, unsigned int *odr)
> +{
> + const struct inv_icm42600_fifo_1sensor_packet *pack1 = packet;
> + const struct inv_icm42600_fifo_2sensors_packet *pack2 = packet;
> + uint8_t header = *((const uint8_t *)packet);
> +
> + /* FIFO empty */
> + if (header & INV_ICM42600_FIFO_HEADER_MSG) {
> + *accel = NULL;
> + *gyro = NULL;
> + *temp = NULL;
> + *timestamp = NULL;
> + *odr = 0;
> + return 0;
> + }
> +
> + /* handle odr flags */
> + *odr = 0;
> + if (header & INV_ICM42600_FIFO_HEADER_ODR_GYRO)
> + *odr |= INV_ICM42600_SENSOR_GYRO;
> + if (header & INV_ICM42600_FIFO_HEADER_ODR_ACCEL)
> + *odr |= INV_ICM42600_SENSOR_ACCEL;
> +
> + /* accel + gyro */
> + if ((header & INV_ICM42600_FIFO_HEADER_ACCEL) &&
> + (header & INV_ICM42600_FIFO_HEADER_GYRO)) {
> + *accel = &pack2->accel;
> + *gyro = &pack2->gyro;
> + *temp = &pack2->temp;
> + *timestamp = &pack2->timestamp;
> + return INV_ICM42600_FIFO_2SENSORS_PACKET_SIZE;
> + }
> +
> + /* accel only */
> + if (header & INV_ICM42600_FIFO_HEADER_ACCEL) {
> + *accel = &pack1->data;
> + *gyro = NULL;
> + *temp = &pack1->temp;
> + *timestamp = NULL;
> + return INV_ICM42600_FIFO_1SENSOR_PACKET_SIZE;
> + }
> +
> + /* gyro only */
> + if (header & INV_ICM42600_FIFO_HEADER_GYRO) {
> + *accel = NULL;
> + *gyro = &pack1->data;
> + *temp = &pack1->temp;
> + *timestamp = NULL;
> + return INV_ICM42600_FIFO_1SENSOR_PACKET_SIZE;
> + }
> +
> + /* invalid packet if here */
> + return -EINVAL;
> +}
> +
> +void inv_icm42600_buffer_update_fifo_period(struct inv_icm42600_state *st)
> +{
> + uint32_t period_gyro, period_accel, period;
> +
> + if (st->fifo.en & INV_ICM42600_SENSOR_GYRO)
> + period_gyro = inv_icm42600_odr_to_period(st->conf.gyro.odr);
> + else
> + period_gyro = U32_MAX;
> +
> + if (st->fifo.en & INV_ICM42600_SENSOR_ACCEL)
> + period_accel = inv_icm42600_odr_to_period(st->conf.accel.odr);
> + else
> + period_accel = U32_MAX;
> +
> + if (period_gyro <= period_accel)
> + period = period_gyro;
> + else
> + period = period_accel;
> +
> + st->fifo.period = period;
> +}
> +
> +int inv_icm42600_buffer_set_fifo_en(struct inv_icm42600_state *st,
> + unsigned int fifo_en)
> +{
> + unsigned int mask, val;
> + int ret;
> +
> + /* update only FIFO EN bits */
> + mask = INV_ICM42600_FIFO_CONFIG1_TMST_FSYNC_EN |
> + INV_ICM42600_FIFO_CONFIG1_TEMP_EN |
> + INV_ICM42600_FIFO_CONFIG1_GYRO_EN |
> + INV_ICM42600_FIFO_CONFIG1_ACCEL_EN;
> +
> + val = 0;
> + if (fifo_en & INV_ICM42600_SENSOR_GYRO)
> + val |= INV_ICM42600_FIFO_CONFIG1_GYRO_EN;
> + if (fifo_en & INV_ICM42600_SENSOR_ACCEL)
> + val |= INV_ICM42600_FIFO_CONFIG1_ACCEL_EN;
> + if (fifo_en & INV_ICM42600_SENSOR_TEMP)
> + val |= INV_ICM42600_FIFO_CONFIG1_TEMP_EN;
> +
> + ret = regmap_update_bits(st->map, INV_ICM42600_REG_FIFO_CONFIG1,
> + mask, val);
> + if (ret)
> + return ret;
> +
> + st->fifo.en = fifo_en;
> + inv_icm42600_buffer_update_fifo_period(st);
> +
> + return 0;
> +}
> +
> +static size_t inv_icm42600_get_packet_size(unsigned int fifo_en)
> +{
> + size_t packet_size;
> +
> + if ((fifo_en & INV_ICM42600_SENSOR_GYRO) &&
> + (fifo_en & INV_ICM42600_SENSOR_ACCEL))
> + packet_size = INV_ICM42600_FIFO_2SENSORS_PACKET_SIZE;
> + else
> + packet_size = INV_ICM42600_FIFO_1SENSOR_PACKET_SIZE;
> +
> + return packet_size;
> +}
> +
> +static unsigned int inv_icm42600_wm_truncate(unsigned int watermark,
> + size_t packet_size)
> +{
> + size_t wm_size;
> + unsigned int wm;
> +
> + wm_size = watermark * packet_size;
> + if (wm_size > INV_ICM42600_FIFO_WATERMARK_MAX)
> + wm_size = INV_ICM42600_FIFO_WATERMARK_MAX;
> +
> + wm = wm_size / packet_size;
> +
> + return wm;
> +}
> +
I think some overview docs on how this is working would be good.
Set out the aims for the watermark selected and how it is achieved.
> +int inv_icm42600_buffer_update_watermark(struct inv_icm42600_state *st)
> +{
> + size_t packet_size, wm_size;
> + unsigned int wm_gyro, wm_accel, watermark;
> + uint32_t period_gyro, period_accel, period;
> + int64_t latency_gyro, latency_accel, latency;
> + bool restore;
> + __le16 raw_wm;
> + int ret;
> +
> + packet_size = inv_icm42600_get_packet_size(st->fifo.en);
> +
> + /* get minimal latency, depending on sensor watermark and odr */
> + wm_gyro = inv_icm42600_wm_truncate(st->fifo.watermark.gyro,
> + packet_size);
> + wm_accel = inv_icm42600_wm_truncate(st->fifo.watermark.accel,
> + packet_size);
> + period_gyro = inv_icm42600_odr_to_period(st->conf.gyro.odr);
> + period_accel = inv_icm42600_odr_to_period(st->conf.accel.odr);
> + latency_gyro = (int64_t)period_gyro * (int64_t)wm_gyro;
> + latency_accel = (int64_t)period_accel * (int64_t)wm_accel;
> + if (latency_gyro == 0) {
> + latency = latency_accel;
> + watermark = wm_accel;
> + } else if (latency_accel == 0) {
> + latency = latency_gyro;
> + watermark = wm_gyro;
> + } else {
> + /* compute the smallest latency that is a multiple of both */
> + if (latency_gyro <= latency_accel) {
> + latency = latency_gyro;
> + latency -= latency_accel % latency_gyro;
> + } else {
> + latency = latency_accel;
> + latency -= latency_gyro % latency_accel;
> + }
> + /* use the shortest period */
> + if (period_gyro <= period_accel)
> + period = period_gyro;
> + else
> + period = period_accel;
> + /* all this works because periods are multiple of each others */
> + watermark = div_s64(latency, period);
> + if (watermark < 1)
> + watermark = 1;
> + }
> + wm_size = watermark * packet_size;
> +
> + /* changing FIFO watermark requires to turn off watermark interrupt */
> + ret = regmap_update_bits_check(st->map, INV_ICM42600_REG_INT_SOURCE0,
> + INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN,
> + 0, &restore);
> + if (ret)
> + return ret;
> +
> + raw_wm = INV_ICM42600_FIFO_WATERMARK_VAL(wm_size);
> + memcpy(st->buffer, &raw_wm, sizeof(raw_wm));
> + ret = regmap_bulk_write(st->map, INV_ICM42600_REG_FIFO_WATERMARK,
> + st->buffer, sizeof(raw_wm));
> + if (ret)
> + return ret;
> +
> + /* restore watermark interrupt */
> + if (restore) {
> + ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_SOURCE0,
> + INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN,
> + INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN);
> + if (ret)
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int inv_icm42600_buffer_preenable(struct iio_dev *indio_dev)
> +{
> + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
> + struct device *dev = regmap_get_device(st->map);
> +
> + pm_runtime_get_sync(dev);
> +
> + return 0;
> +}
> +
> +/*
> + * update_scan_mode callback is turning sensors on and setting data FIFO enable
> + * bits.
> + */
> +static int inv_icm42600_buffer_postenable(struct iio_dev *indio_dev)
> +{
> + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
> + int ret;
> +
> + mutex_lock(&st->lock);
> +
> + /* exit if FIFO is already on */
> + if (st->fifo.on) {
> + ret = 0;
> + goto out_on;
> + }
> +
> + /* set FIFO threshold interrupt */
> + ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_SOURCE0,
> + INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN,
> + INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN);
> + if (ret)
> + goto out_unlock;
> +
> + /* flush FIFO data */
> + ret = regmap_write(st->map, INV_ICM42600_REG_SIGNAL_PATH_RESET,
> + INV_ICM42600_SIGNAL_PATH_RESET_FIFO_FLUSH);
> + if (ret)
> + goto out_unlock;
> +
> + /* set FIFO in streaming mode */
> + ret = regmap_write(st->map, INV_ICM42600_REG_FIFO_CONFIG,
> + INV_ICM42600_FIFO_CONFIG_STREAM);
> + if (ret)
> + goto out_unlock;
> +
> + /* workaround: first read of FIFO count after reset is always 0 */
> + ret = regmap_bulk_read(st->map, INV_ICM42600_REG_FIFO_COUNT, st->buffer, 2);
> + if (ret)
> + goto out_unlock;
> +
> +out_on:
> + /* increase FIFO on counter */
> + st->fifo.on++;
> +out_unlock:
> + mutex_unlock(&st->lock);
> + return ret;
> +}
> +
> +static int inv_icm42600_buffer_predisable(struct iio_dev *indio_dev)
> +{
> + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
> + int ret;
> +
> + mutex_lock(&st->lock);
> +
> + /* exit if there are several sensors using the FIFO */
> + if (st->fifo.on > 1) {
> + ret = 0;
> + goto out_off;
> + }
> +
> + /* set FIFO in bypass mode */
> + ret = regmap_write(st->map, INV_ICM42600_REG_FIFO_CONFIG,
> + INV_ICM42600_FIFO_CONFIG_BYPASS);
> + if (ret)
> + goto out_unlock;
> +
> + /* flush FIFO data */
> + ret = regmap_write(st->map, INV_ICM42600_REG_SIGNAL_PATH_RESET,
> + INV_ICM42600_SIGNAL_PATH_RESET_FIFO_FLUSH);
> + if (ret)
> + goto out_unlock;
> +
> + /* disable FIFO threshold interrupt */
> + ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_SOURCE0,
> + INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN, 0);
> + if (ret)
> + goto out_unlock;
> +
> +out_off:
> + /* decrease FIFO on counter */
> + st->fifo.on--;
> +out_unlock:
> + mutex_unlock(&st->lock);
> + return ret;
> +}
> +
> +static int inv_icm42600_buffer_postdisable(struct iio_dev *indio_dev)
> +{
> + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
> + struct device *dev = regmap_get_device(st->map);
> + unsigned int sensor;
> + unsigned int *watermark;
> + struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
> + unsigned int sleep_temp = 0;
> + unsigned int sleep_sensor = 0;
> + unsigned int sleep;
> + int ret;
> +
> + if (indio_dev == st->indio_gyro) {
> + sensor = INV_ICM42600_SENSOR_GYRO;
> + watermark = &st->fifo.watermark.gyro;
> + } else if (indio_dev == st->indio_accel) {
> + sensor = INV_ICM42600_SENSOR_ACCEL;
> + watermark = &st->fifo.watermark.accel;
> + } else {
> + return -EINVAL;
> + }
> +
> + mutex_lock(&st->lock);
> +
> + ret = inv_icm42600_buffer_set_fifo_en(st, st->fifo.en & ~sensor);
> + if (ret)
> + goto out_unlock;
> +
> + *watermark = 0;
> + ret = inv_icm42600_buffer_update_watermark(st);
> + if (ret)
> + goto out_unlock;
> +
> + conf.mode = INV_ICM42600_SENSOR_MODE_OFF;
> + if (sensor == INV_ICM42600_SENSOR_GYRO)
> + ret = inv_icm42600_set_gyro_conf(st, &conf, &sleep_sensor);
> + else
> + ret = inv_icm42600_set_accel_conf(st, &conf, &sleep_sensor);
> + if (ret)
> + goto out_unlock;
> +
> + /* if FIFO is off, turn temperature off */
> + if (!st->fifo.on)
> + ret = inv_icm42600_set_temp_conf(st, false, &sleep_temp);
> +
> +out_unlock:
> + mutex_unlock(&st->lock);
> +
> + /* sleep maximum required time */
> + if (sleep_sensor > sleep_temp)
> + sleep = sleep_sensor;
> + else
> + sleep = sleep_temp;
> + if (sleep)
> + msleep(sleep);
> +
> + pm_runtime_mark_last_busy(dev);
> + pm_runtime_put_autosuspend(dev);
> +
> + return ret;
> +}
> +
> +const struct iio_buffer_setup_ops inv_icm42600_buffer_ops = {
> + .preenable = inv_icm42600_buffer_preenable,
> + .postenable = inv_icm42600_buffer_postenable,
We've been slowly eroding the difference between preenable and posteenable.
Would be good to understand why you need to define both?
> + .predisable = inv_icm42600_buffer_predisable,
> + .postdisable = inv_icm42600_buffer_postdisable,
> +};
> +
> +int inv_icm42600_buffer_fifo_read(struct inv_icm42600_state *st,
> + unsigned int max)
> +{
> + size_t max_count;
> + __be16 *raw_fifo_count;
> + ssize_t i, size;
> + const void *accel, *gyro, *timestamp;
> + const int8_t *temp;
> + unsigned int odr;
> + int ret;
> +
> + /* reset all samples counters */
> + st->fifo.count = 0;
> + st->fifo.nb.gyro = 0;
> + st->fifo.nb.accel = 0;
> + st->fifo.nb.total = 0;
> +
> + /* compute maximum FIFO read size */
> + if (max == 0)
> + max_count = sizeof(st->fifo.data);
> + else
> + max_count = max * inv_icm42600_get_packet_size(st->fifo.en);
> +
> + /* read FIFO count value */
> + raw_fifo_count = (__be16 *)st->buffer;
> + ret = regmap_bulk_read(st->map, INV_ICM42600_REG_FIFO_COUNT,
> + raw_fifo_count, sizeof(*raw_fifo_count));
> + if (ret)
> + return ret;
> + st->fifo.count = be16_to_cpup(raw_fifo_count);
> +
> + /* check and clamp FIFO count value */
> + if (st->fifo.count == 0)
> + return 0;
> + if (st->fifo.count > max_count)
> + st->fifo.count = max_count;
> +
> + /* read all FIFO data in internal buffer */
> + ret = regmap_noinc_read(st->map, INV_ICM42600_REG_FIFO_DATA,
> + st->fifo.data, st->fifo.count);
> + if (ret)
> + return ret;
> +
> + /* compute number of samples for each sensor */
> + for (i = 0; i < st->fifo.count; i += size) {
> + size = inv_icm42600_fifo_decode_packet(&st->fifo.data[i],
> + &accel, &gyro, &temp, ×tamp, &odr);
> + if (size <= 0)
> + break;
> + if (gyro != NULL && inv_icm42600_fifo_is_data_valid(gyro))
> + st->fifo.nb.gyro++;
> + if (accel != NULL && inv_icm42600_fifo_is_data_valid(accel))
> + st->fifo.nb.accel++;
> + st->fifo.nb.total++;
> + }
> +
> + return 0;
> +}
> +
> +int inv_icm42600_buffer_fifo_parse(struct inv_icm42600_state *st)
> +{
> + int ret;
> +
> + if (st->fifo.nb.total == 0)
> + return 0;
> +
> + if (st->fifo.nb.gyro > 0) {
> + ret = inv_icm42600_gyro_parse_fifo(st->indio_gyro);
> + if (ret)
> + return ret;
> + }
> +
> + if (st->fifo.nb.accel > 0) {
> + ret = inv_icm42600_accel_parse_fifo(st->indio_accel);
> + if (ret)
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +int inv_icm42600_buffer_hwfifo_flush(struct inv_icm42600_state *st,
> + unsigned int count)
> +{
> + int ret;
> +
> + ret = inv_icm42600_buffer_fifo_read(st, count);
> + if (ret)
> + return ret;
Definitely searching my memory for how this works in the core, so
I may have it wrong.
This is a bit unusual (I think). The intent of the flush
is to read up to 'n' bytes because someone just did a read on the buffer
or select, and there was data in the hwfifo capable of satisfying the read
even though we haven't yet reached the watermark.
Given both sensor types are coming from one buffer, do we have a potential
issue here or under serving even though data is available?
The case I worry may be served late is when an poll / select
is waiting for sufficient data.
So what should we be doing? We want to guarantee to provide data
for each sensor type if it's in the hwfifo. As such we could keep reading
until we have enough, but that could cause some issues if the two data rates
are very different (overflow on the other kfifo)
Maybe what you have here is the best we can do.
I'm assuming the watermark level has a similar problem. One value represents
the sum of the two types of data.
> +
> + if (st->fifo.nb.total == 0)
> + return 0;
> +
> + if (st->fifo.nb.gyro > 0) {
> + ret = inv_icm42600_gyro_parse_fifo(st->indio_gyro);
> + if (ret)
> + return ret;
> + }
> +
> + if (st->fifo.nb.accel > 0) {
> + ret = inv_icm42600_accel_parse_fifo(st->indio_accel);
> + if (ret)
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +int inv_icm42600_buffer_init(struct inv_icm42600_state *st)
> +{
> + unsigned int val;
> + int ret;
> +
> + /*
> + * Default FIFO configuration (bits 7 to 5)
> + * - use invalid value
> + * - FIFO count in bytes
> + * - FIFO count in big endian
> + */
> + val = INV_ICM42600_INTF_CONFIG0_FIFO_COUNT_ENDIAN;
> + ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG0,
> + GENMASK(7, 5), val);
> + if (ret)
> + return ret;
> +
> + /*
> + * Enable FIFO partial read and continuous watermark interrupt.
> + * Disable all FIFO EN bits.
> + */
> + val = INV_ICM42600_FIFO_CONFIG1_RESUME_PARTIAL_RD |
> + INV_ICM42600_FIFO_CONFIG1_WM_GT_TH;
> + return regmap_update_bits(st->map, INV_ICM42600_REG_FIFO_CONFIG1,
> + GENMASK(6, 5) | GENMASK(3, 0), val);
> +}
> diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h
> new file mode 100644
> index 000000000000..de2a3949dcc7
> --- /dev/null
> +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h
> @@ -0,0 +1,98 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Copyright (C) 2020 Invensense, Inc.
> + */
> +
> +#ifndef INV_ICM42600_BUFFER_H_
> +#define INV_ICM42600_BUFFER_H_
> +
> +#include <linux/kernel.h>
> +#include <linux/bits.h>
> +
> +struct inv_icm42600_state;
> +
> +#define INV_ICM42600_SENSOR_GYRO BIT(0)
> +#define INV_ICM42600_SENSOR_ACCEL BIT(1)
> +#define INV_ICM42600_SENSOR_TEMP BIT(2)
> +
> +/**
> + * struct inv_icm42600_fifo - FIFO state variables
> + * @on: reference counter for FIFO on.
> + * @en: bits field of INV_ICM42600_SENSOR_* for FIFO EN bits.
> + * @period: FIFO internal period.
> + * @watermark: watermark configuration values for accel and gyro.
> + * @count: number of bytes in the FIFO data buffer.
> + * @nb: gyro, accel and total samples in the FIFO data buffer.
> + * @data: FIFO data buffer aligned for DMA (2kB + 32 bytes of read cache).
> + */
> +struct inv_icm42600_fifo {
> + unsigned int on;
> + unsigned int en;
> + uint32_t period;
> + struct {
> + unsigned int gyro;
> + unsigned int accel;
> + } watermark;
> + size_t count;
> + struct {
> + size_t gyro;
> + size_t accel;
> + size_t total;
> + } nb;
> + uint8_t data[2080] ____cacheline_aligned;
> +};
> +
> +/* FIFO data packet */
> +struct inv_icm42600_fifo_sensor_data {
> + __be16 x;
> + __be16 y;
> + __be16 z;
> +} __packed;
Why packed? Should be anyway I think.
> +#define INV_ICM42600_FIFO_DATA_INVALID -32768
> +
> +static inline int16_t inv_icm42600_fifo_get_sensor_data(__be16 d)
> +{
> + return be16_to_cpu(d);
> +}
> +
> +static inline bool
> +inv_icm42600_fifo_is_data_valid(const struct inv_icm42600_fifo_sensor_data *s)
> +{
> + int16_t x, y, z;
> +
> + x = inv_icm42600_fifo_get_sensor_data(s->x);
> + y = inv_icm42600_fifo_get_sensor_data(s->y);
> + z = inv_icm42600_fifo_get_sensor_data(s->z);
> +
> + if (x == INV_ICM42600_FIFO_DATA_INVALID &&
> + y == INV_ICM42600_FIFO_DATA_INVALID &&
> + z == INV_ICM42600_FIFO_DATA_INVALID)
> + return false;
> +
> + return true;
> +}
> +
> +ssize_t inv_icm42600_fifo_decode_packet(const void *packet, const void **accel,
> + const void **gyro, const int8_t **temp,
> + const void **timestamp, unsigned int *odr);
> +
> +extern const struct iio_buffer_setup_ops inv_icm42600_buffer_ops;
> +
> +int inv_icm42600_buffer_init(struct inv_icm42600_state *st);
> +
> +void inv_icm42600_buffer_update_fifo_period(struct inv_icm42600_state *st);
> +
> +int inv_icm42600_buffer_set_fifo_en(struct inv_icm42600_state *st,
> + unsigned int fifo_en);
> +
> +int inv_icm42600_buffer_update_watermark(struct inv_icm42600_state *st);
> +
> +int inv_icm42600_buffer_fifo_read(struct inv_icm42600_state *st,
> + unsigned int max);
> +
> +int inv_icm42600_buffer_fifo_parse(struct inv_icm42600_state *st);
> +
> +int inv_icm42600_buffer_hwfifo_flush(struct inv_icm42600_state *st,
> + unsigned int count);
> +
> +#endif
> diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
> index 246c1eb52231..6f1c1eb83953 100644
> --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
> +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
> @@ -18,6 +18,7 @@
> #include <linux/iio/iio.h>
>
> #include "inv_icm42600.h"
> +#include "inv_icm42600_buffer.h"
>
> static const struct regmap_range_cfg inv_icm42600_regmap_ranges[] = {
> {
> @@ -429,6 +430,18 @@ static irqreturn_t inv_icm42600_irq_handler(int irq, void *_data)
> if (status & INV_ICM42600_INT_STATUS_FIFO_FULL)
> dev_warn(dev, "FIFO full data lost!\n");
>
> + /* FIFO threshold reached */
> + if (status & INV_ICM42600_INT_STATUS_FIFO_THS) {
> + ret = inv_icm42600_buffer_fifo_read(st, 0);
> + if (ret) {
> + dev_err(dev, "FIFO read error %d\n", ret);
> + goto out_unlock;
> + }
> + ret = inv_icm42600_buffer_fifo_parse(st);
> + if (ret)
> + dev_err(dev, "FIFO parsing error %d\n", ret);
> + }
> +
> out_unlock:
> mutex_unlock(&st->lock);
> return IRQ_HANDLED;
> @@ -600,6 +613,10 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq,
> if (ret)
> return ret;
>
> + ret = inv_icm42600_buffer_init(st);
> + if (ret)
> + return ret;
> +
> ret = inv_icm42600_gyro_init(st);
> if (ret)
> return ret;
> @@ -645,6 +662,14 @@ static int __maybe_unused inv_icm42600_suspend(struct device *dev)
> goto out_unlock;
> }
>
> + /* disable FIFO data streaming */
> + if (st->fifo.on) {
> + ret = regmap_write(st->map, INV_ICM42600_REG_FIFO_CONFIG,
> + INV_ICM42600_FIFO_CONFIG_BYPASS);
> + if (ret)
> + goto out_unlock;
> + }
> +
> ret = inv_icm42600_set_pwr_mgmt0(st, INV_ICM42600_SENSOR_MODE_OFF,
> INV_ICM42600_SENSOR_MODE_OFF, false,
> NULL);
> @@ -684,6 +709,11 @@ static int __maybe_unused inv_icm42600_resume(struct device *dev)
> if (ret)
> goto out_unlock;
>
> + /* restore FIFO data streaming */
> + if (st->fifo.on)
> + ret = regmap_write(st->map, INV_ICM42600_REG_FIFO_CONFIG,
> + INV_ICM42600_FIFO_CONFIG_STREAM);
> +
> out_unlock:
> mutex_unlock(&st->lock);
> return ret;
> diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
> index 38654e0d217b..b05c33876b8d 100644
> --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
> +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
> @@ -11,9 +11,12 @@
> #include <linux/delay.h>
> #include <linux/math64.h>
> #include <linux/iio/iio.h>
> +#include <linux/iio/buffer.h>
> +#include <linux/iio/kfifo_buf.h>
>
> #include "inv_icm42600.h"
> #include "inv_icm42600_temp.h"
> +#include "inv_icm42600_buffer.h"
>
> #define INV_ICM42600_GYRO_CHAN(_modifier, _index, _ext_info) \
> { \
> @@ -64,6 +67,76 @@ static const struct iio_chan_spec inv_icm42600_gyro_channels[] = {
> INV_ICM42600_TEMP_CHAN(INV_ICM42600_GYRO_SCAN_TEMP),
> };
>
> +/* IIO buffer data: 8 bytes */
> +struct inv_icm42600_gyro_buffer {
> + struct inv_icm42600_fifo_sensor_data gyro;
> + int8_t temp;
> + uint8_t padding;
> +};
> +
> +#define INV_ICM42600_SCAN_MASK_GYRO_3AXIS \
> + (BIT(INV_ICM42600_GYRO_SCAN_X) | \
> + BIT(INV_ICM42600_GYRO_SCAN_Y) | \
> + BIT(INV_ICM42600_GYRO_SCAN_Z))
> +
> +#define INV_ICM42600_SCAN_MASK_TEMP BIT(INV_ICM42600_GYRO_SCAN_TEMP)
> +
> +static const unsigned long inv_icm42600_gyro_scan_masks[] = {
> + /* 3-axis gyro + temperature */
> + INV_ICM42600_SCAN_MASK_GYRO_3AXIS | INV_ICM42600_SCAN_MASK_TEMP,
> + 0,
> +};
> +
> +/* enable gyroscope sensor and FIFO write */
> +static int inv_icm42600_gyro_update_scan_mode(struct iio_dev *indio_dev,
> + const unsigned long *scan_mask)
> +{
> + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
> + struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
> + unsigned int fifo_en = 0;
> + unsigned int sleep_gyro = 0;
> + unsigned int sleep_temp = 0;
> + unsigned int sleep;
> + int ret;
> +
> + mutex_lock(&st->lock);
> +
> + if (*scan_mask & INV_ICM42600_SCAN_MASK_TEMP) {
> + /* enable temp sensor */
> + ret = inv_icm42600_set_temp_conf(st, true, &sleep_temp);
> + if (ret)
> + goto out_unlock;
> + fifo_en |= INV_ICM42600_SENSOR_TEMP;
> + }
> +
> + if (*scan_mask & INV_ICM42600_SCAN_MASK_GYRO_3AXIS) {
> + /* enable gyro sensor */
> + conf.mode = INV_ICM42600_SENSOR_MODE_LOW_NOISE;
> + ret = inv_icm42600_set_gyro_conf(st, &conf, &sleep_gyro);
> + if (ret)
> + goto out_unlock;
> + fifo_en |= INV_ICM42600_SENSOR_GYRO;
> + }
> +
> + /* update data FIFO write */
> + ret = inv_icm42600_buffer_set_fifo_en(st, fifo_en | st->fifo.en);
> + if (ret)
> + goto out_unlock;
> +
> + ret = inv_icm42600_buffer_update_watermark(st);
> +
> +out_unlock:
> + mutex_unlock(&st->lock);
> + /* sleep maximum required time */
> + if (sleep_gyro > sleep_temp)
> + sleep = sleep_gyro;
> + else
> + sleep = sleep_temp;
> + if (sleep)
> + msleep(sleep);
> + return ret;
> +}
> +
> static int inv_icm42600_gyro_read_sensor(struct inv_icm42600_state *st,
> struct iio_chan_spec const *chan,
> int16_t *val)
> @@ -260,7 +333,12 @@ static int inv_icm42600_gyro_write_odr(struct inv_icm42600_state *st,
> mutex_lock(&st->lock);
>
> ret = inv_icm42600_set_gyro_conf(st, &conf, NULL);
> + if (ret)
> + goto out_unlock;
> + inv_icm42600_buffer_update_fifo_period(st);
> + inv_icm42600_buffer_update_watermark(st);
>
> +out_unlock:
> mutex_unlock(&st->lock);
> pm_runtime_mark_last_busy(dev);
> pm_runtime_put_autosuspend(dev);
> @@ -574,12 +652,51 @@ static int inv_icm42600_gyro_write_raw_get_fmt(struct iio_dev *indio_dev,
> }
> }
>
> +static int inv_icm42600_gyro_hwfifo_set_watermark(struct iio_dev *indio_dev,
> + unsigned int val)
> +{
> + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
> + int ret;
> +
> + mutex_lock(&st->lock);
> +
> + st->fifo.watermark.gyro = val;
> + ret = inv_icm42600_buffer_update_watermark(st);
> +
> + mutex_unlock(&st->lock);
> +
> + return ret;
> +}
> +
> +static int inv_icm42600_gyro_hwfifo_flush(struct iio_dev *indio_dev,
> + unsigned int count)
> +{
Nothing to do with this patch, but I realised reading this that we have
some 'unusual' use of the word flush here. It's a straight forward
read function so not sure why we called it flush.
> + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
> + int ret;
> +
> + if (count == 0)
> + return 0;
> +
> + mutex_lock(&st->lock);
> +
> + ret = inv_icm42600_buffer_hwfifo_flush(st, count);
> + if (!ret)
> + ret = st->fifo.nb.gyro;
> +
> + mutex_unlock(&st->lock);
> +
> + return ret;
> +}
> +
> static const struct iio_info inv_icm42600_gyro_info = {
> .read_raw = inv_icm42600_gyro_read_raw,
> .read_avail = inv_icm42600_gyro_read_avail,
> .write_raw = inv_icm42600_gyro_write_raw,
> .write_raw_get_fmt = inv_icm42600_gyro_write_raw_get_fmt,
> .debugfs_reg_access = inv_icm42600_debugfs_reg,
> + .update_scan_mode = inv_icm42600_gyro_update_scan_mode,
> + .hwfifo_set_watermark = inv_icm42600_gyro_hwfifo_set_watermark,
> + .hwfifo_flush_to_buffer = inv_icm42600_gyro_hwfifo_flush,
> };
>
> int inv_icm42600_gyro_init(struct inv_icm42600_state *st)
> @@ -587,6 +704,7 @@ int inv_icm42600_gyro_init(struct inv_icm42600_state *st)
> struct device *dev = regmap_get_device(st->map);
> const char *name;
> struct iio_dev *indio_dev;
> + struct iio_buffer *buffer;
>
> name = devm_kasprintf(dev, GFP_KERNEL, "%s-gyro", st->name);
> if (!name)
> @@ -596,14 +714,54 @@ int inv_icm42600_gyro_init(struct inv_icm42600_state *st)
> if (!indio_dev)
> return -ENOMEM;
>
> + buffer = devm_iio_kfifo_allocate(dev);
> + if (!buffer)
> + return -ENOMEM;
> +
> iio_device_set_drvdata(indio_dev, st);
> indio_dev->dev.parent = dev;
> indio_dev->name = name;
> indio_dev->info = &inv_icm42600_gyro_info;
> - indio_dev->modes = INDIO_DIRECT_MODE;
> + indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
> indio_dev->channels = inv_icm42600_gyro_channels;
> indio_dev->num_channels = ARRAY_SIZE(inv_icm42600_gyro_channels);
> + indio_dev->available_scan_masks = inv_icm42600_gyro_scan_masks;
> + indio_dev->setup_ops = &inv_icm42600_buffer_ops;
> +
> + iio_device_attach_buffer(indio_dev, buffer);
>
> st->indio_gyro = indio_dev;
> return devm_iio_device_register(dev, st->indio_gyro);
> }
> +
> +int inv_icm42600_gyro_parse_fifo(struct iio_dev *indio_dev)
> +{
> + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
> + ssize_t i, size;
> + const void *accel, *gyro, *timestamp;
> + const int8_t *temp;
> + unsigned int odr;
> + struct inv_icm42600_gyro_buffer buffer = {
> + .padding = 0,
Might be worth a comment here or where the structure is defined
on why we make padding explicit.
> + };
> +
> + /* parse all fifo packets */
> + for (i = 0; i < st->fifo.count; i += size) {
> + size = inv_icm42600_fifo_decode_packet(&st->fifo.data[i],
> + &accel, &gyro, &temp, ×tamp, &odr);
> + /* quit if error or FIFO is empty */
> + if (size <= 0)
> + return size;
> +
> + /* skip packet if no gyro data or data is invalid */
> + if (gyro == NULL || !inv_icm42600_fifo_is_data_valid(gyro))
> + continue;
> +
> + /* fill and push data buffer */
> + memcpy(&buffer.gyro, gyro, sizeof(buffer.gyro));
> + buffer.temp = temp ? *temp : 0;
> + iio_push_to_buffers(indio_dev, &buffer);
> + }
> +
> + return 0;
> +}
^ permalink raw reply
* Re: [Linux-stm32] [PATCH v8 08/10] drm: stm: dw-mipi-dsi: let the bridge handle the HW version check
From: Emil Velikov @ 2020-06-02 12:53 UTC (permalink / raw)
To: Adrian Ratiu
Cc: Philippe CORNU, linux-arm-kernel@lists.infradead.org,
devicetree@vger.kernel.org, linux-rockchip@lists.infradead.org,
Laurent Pinchart, Jernej Skrabec, Adrian Pop, Jonas Karlman,
linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org,
Yannick FERTRE, Andrzej Hajda, linux-imx@nxp.com,
kernel@collabora.com, linux-stm32@st-md-mailman.stormreply.com,
Arnaud Ferraris, Benjamin GAIGNARD
In-Reply-To: <87blm387vt.fsf@iwork.i-did-not-set--mail-host-address--so-tickle-me>
Hi Adrian,
On Mon, 1 Jun 2020 at 10:14, Adrian Ratiu <adrian.ratiu@collabora.com> wrote:
>
> On Fri, 29 May 2020, Philippe CORNU <philippe.cornu@st.com> wrote:
> > Hi Adrian, and thank you very much for the patchset. Thank you
> > also for having tested it on STM32F769 and STM32MP1. Sorry for
> > the late response, Yannick and I will review it as soon as
> > possible and we will keep you posted. Note: Do not hesitate to
> > put us in copy for the next version (philippe.cornu@st.com,
> > yannick.fertre@st.com) Regards, Philippe :-)
>
> Hi Philippe,
>
> Thank you very much for your previous and future STM testing,
> really appreciate it! I've CC'd Yannick until now but I'll also CC
> you sure :)
>
> It's been over a month since I posted v8 and I was just gearing up
> to address all feedback, rebase & retest to prepare v9 but I'll
> wait a little longer, no problem, it's no rush.
>
Small idea, pardon for joining so late:
Might be a good idea to add inline comment, why the clocks are disabled so late.
Effectively a 2 line version of the commit summary.
Feel free to make that a separate/follow-up patch.
-Emil
^ permalink raw reply
* Re: [PATCH 2/2] drm/panel: simple: Add support for KOE TX26D202VM0BWA panel
From: Emil Velikov @ 2020-06-02 12:46 UTC (permalink / raw)
To: Liu Ying
Cc: ML dri-devel, devicetree, Thierry Reding, Sam Ravnborg,
NXP Linux Team
In-Reply-To: <1590991880-24273-1-git-send-email-victor.liu@nxp.com>
On Tue, 2 Jun 2020 at 08:17, Liu Ying <victor.liu@nxp.com> wrote:
>
> This patch adds support for Kaohsiung Opto-Electronics Inc.
> 10.1" TX26D202VM0BWA WUXGA(1920x1200) TFT LCD panel with LVDS interface.
> The panel has dual LVDS channels.
>
> My panel is manufactured by US Micro Products(USMP). There is a tag at
> the back of the panel, which indicates the panel type is 'TX26D202VM0BWA'
> and it's made by KOE in Taiwan.
>
> The panel spec from USMP can be found at:
> https://www.usmicroproducts.com/sites/default/files/datasheets/USMP-T101-192120NDU-A0.pdf
>
> The below panel spec from KOE is basically the same to the one from USMP.
> However, the panel type 'TX26D202VM0BAA' is a little bit different.
> It looks that the two types of panel are compatible with each other.
> http://www.koe.j-display.com/upload/product/TX26D202VM0BAA.pdf
>
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: Sam Ravnborg <sam@ravnborg.org>
> Signed-off-by: Liu Ying <victor.liu@nxp.com>
> ---
> drivers/gpu/drm/panel/panel-simple.c | 34 ++++++++++++++++++++++++++++++++++
> 1 file changed, 34 insertions(+)
>
> diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
> index b6ecd15..7c222ec 100644
> --- a/drivers/gpu/drm/panel/panel-simple.c
> +++ b/drivers/gpu/drm/panel/panel-simple.c
> @@ -2200,6 +2200,37 @@ static const struct panel_desc koe_tx14d24vm1bpa = {
> },
> };
>
> +static const struct display_timing koe_tx26d202vm0bwa_timing = {
> + .pixelclock = { 151820000, 156720000, 159780000 },
> + .hactive = { 1920, 1920, 1920 },
> + .hfront_porch = { 105, 130, 142 },
> + .hback_porch = { 45, 70, 82 },
> + .hsync_len = { 30, 30, 30 },
> + .vactive = { 1200, 1200, 1200},
> + .vfront_porch = { 3, 5, 10 },
> + .vback_porch = { 2, 5, 10 },
> + .vsync_len = { 5, 5, 5 },
> +};
> +
> +static const struct panel_desc koe_tx26d202vm0bwa = {
> + .timings = &koe_tx26d202vm0bwa_timing,
> + .num_timings = 1,
> + .bpc = 8,
> + .size = {
> + .width = 217,
> + .height = 136,
> + },
> + .delay = {
> + .prepare = 1000,
> + .enable = 1000,
> + .unprepare = 1000,
> + .disable = 1000,
Ouch 1s for each delay is huge. Nevertheless it matches the specs so,
the series is:
Reviewed-by: Emil Velikov <emil.l.velikov@gmail.com>
Sam, Thierry I assume you'll merge the series. Let me know if I should
pick it up.
-Emil
^ permalink raw reply
* [PATCH] dt-bindings: usb: ti,keystone-dwc3.yaml: Improve schema
From: Roger Quadros @ 2020-06-02 12:40 UTC (permalink / raw)
To: balbi; +Cc: robh+dt, devicetree, linux-kernel, Roger Quadros
There were some review comments after the patch was integrated.
Address those.
Fixes: 1883a934e156 ("dt-bindings: usb: convert keystone-usb.txt to YAML")
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
.../bindings/usb/ti,keystone-dwc3.yaml | 47 ++++++++++++++-----
1 file changed, 35 insertions(+), 12 deletions(-)
diff --git a/Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml b/Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml
index f127535feb0b..017c5883184b 100644
--- a/Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml
+++ b/Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml
@@ -11,30 +11,44 @@ maintainers:
properties:
compatible:
- oneOf:
- - const: "ti,keystone-dwc3"
- - const: "ti,am654-dwc3"
+ items:
+ - enum:
+ - "ti,keystone-dwc3"
+ - "ti,am654-dwc3"
reg:
maxItems: 1
- description: Address and length of the register set for the USB subsystem on
- the SOC.
+
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 1
+
+ ranges: true
interrupts:
maxItems: 1
- description: The irq number of this device that is used to interrupt the MPU.
-
clocks:
+ $ref: /schemas/types.yaml#definitions/phandle-array
description: Clock ID for USB functional clock.
+ assigned-clocks:
+ $ref: /schemas/types.yaml#definitions/phandle-array
+
+ assigned-clock-parents:
+ $ref: /schemas/types.yaml#definitions/phandle-array
+
power-domains:
+ $ref: /schemas/types.yaml#definitions/phandle-array
description: Should contain a phandle to a PM domain provider node
and an args specifier containing the USB device id
value. This property is as per the binding,
Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
phys:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
description:
PHY specifier for the USB3.0 PHY. Some SoCs need the USB3.0 PHY
to be turned on before the controller.
@@ -44,31 +58,40 @@ properties:
items:
- const: "usb3-phy"
- dwc3:
+ dma-coherent: true
+
+ dma-ranges: true
+
+patternProperties:
+ "usb@[a-f0-9]+$":
+ type: object
description: This is the node representing the DWC3 controller instance
Documentation/devicetree/bindings/usb/dwc3.txt
required:
- compatible
- reg
+ - "#address-cells"
+ - "#size-cells"
+ - ranges
- interrupts
- - clocks
+
+additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
- usb: usb@2680000 {
+ dwc3@2680000 {
compatible = "ti,keystone-dwc3";
#address-cells = <1>;
#size-cells = <1>;
reg = <0x2680000 0x10000>;
clocks = <&clkusb>;
- clock-names = "usb";
interrupts = <GIC_SPI 393 IRQ_TYPE_EDGE_RISING>;
ranges;
- dwc3@2690000 {
+ usb@2690000 {
compatible = "synopsys,dwc3";
reg = <0x2690000 0x70000>;
interrupts = <GIC_SPI 393 IRQ_TYPE_EDGE_RISING>;
--
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
^ permalink raw reply related
* Re: [PATCH 1/3] dt-bindings: usb: convert keystone-usb.txt to YAML
From: Roger Quadros @ 2020-06-02 12:36 UTC (permalink / raw)
To: Rob Herring; +Cc: balbi, vigneshr, linux-usb, devicetree, linux-kernel
In-Reply-To: <20200527013715.GA847644@bogus>
Rob,
Thanks for the review. Since this patch was already picked up I will
address the issues in a follow up patch.
cheers,
-roger
On 27/05/2020 04:37, Rob Herring wrote:
> On Wed, May 13, 2020 at 04:07:07PM +0300, Roger Quadros wrote:
>> Convert keystone-usb documentation to YAML format.
>>
>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>> ---
>> .../devicetree/bindings/usb/keystone-usb.txt | 56 ----------------
>> .../bindings/usb/ti,keystone-dwc3.yaml | 67 +++++++++++++++++++
>> 2 files changed, 67 insertions(+), 56 deletions(-)
>> delete mode 100644 Documentation/devicetree/bindings/usb/keystone-usb.txt
>> create mode 100644 Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/usb/keystone-usb.txt b/Documentation/devicetree/bindings/usb/keystone-usb.txt
>> deleted file mode 100644
>> index 77df82e36138..000000000000
>> --- a/Documentation/devicetree/bindings/usb/keystone-usb.txt
>> +++ /dev/null
>> @@ -1,56 +0,0 @@
>> -TI Keystone Soc USB Controller
>> -
>> -DWC3 GLUE
>> -
>> -Required properties:
>> - - compatible: should be
>> - "ti,keystone-dwc3" for Keystone 2 SoCs
>> - "ti,am654-dwc3" for AM654 SoC
>> - - #address-cells, #size-cells : should be '1' if the device has sub-nodes
>> - with 'reg' property.
>> - - reg : Address and length of the register set for the USB subsystem on
>> - the SOC.
>> - - interrupts : The irq number of this device that is used to interrupt the
>> - MPU.
>> - - ranges: allows valid 1:1 translation between child's address space and
>> - parent's address space.
>> -
>> -SoC-specific Required Properties:
>> -The following are mandatory properties for Keystone 2 66AK2HK, 66AK2L and 66AK2E
>> -SoCs only:
>> -
>> -- clocks: Clock ID for USB functional clock.
>> -- clock-names: Must be "usb".
>> -
>> -
>> -The following are mandatory properties for 66AK2G and AM654:
>> -
>> -- power-domains: Should contain a phandle to a PM domain provider node
>> - and an args specifier containing the USB device id
>> - value. This property is as per the binding,
>> - Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
>> -
>> -Sub-nodes:
>> -The dwc3 core should be added as subnode to Keystone DWC3 glue.
>> -- dwc3 :
>> - The binding details of dwc3 can be found in:
>> - Documentation/devicetree/bindings/usb/dwc3.txt
>> -
>> -Example:
>> - usb: usb@2680000 {
>> - compatible = "ti,keystone-dwc3";
>> - #address-cells = <1>;
>> - #size-cells = <1>;
>> - reg = <0x2680000 0x10000>;
>> - clocks = <&clkusb>;
>> - clock-names = "usb";
>> - interrupts = <GIC_SPI 393 IRQ_TYPE_EDGE_RISING>;
>> - ranges;
>> -
>> - dwc3@2690000 {
>> - compatible = "synopsys,dwc3";
>> - reg = <0x2690000 0x70000>;
>> - interrupts = <GIC_SPI 393 IRQ_TYPE_EDGE_RISING>;
>> - usb-phy = <&usb_phy>, <&usb_phy>;
>> - };
>> - };
>> diff --git a/Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml b/Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml
>> new file mode 100644
>> index 000000000000..14d2fe329b93
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml
>> @@ -0,0 +1,67 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/usb/ti,keystone-dwc3.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: TI Keystone Soc USB Controller
>> +
>> +maintainers:
>> + - Roger Quadros <rogerq@ti.com>
>> +
>> +properties:
>> + compatible:
>> + oneOf:
>> + - const: "ti,keystone-dwc3"
>> + - const: "ti,am654-dwc3"
>
> Use enum rather than oneOf+const.
>
>> +
>> + reg:
>> + maxItems: 1
>> + description: Address and length of the register set for the USB subsystem on
>> + the SOC.
>> +
>> + interrupts:
>> + maxItems: 1
>> + description: The irq number of this device that is used to interrupt the MPU.
>
> No need for genericish descriptions when a single item.
>
>> +
>> +
>> + clocks:
>> + description: Clock ID for USB functional clock.
>
> How many?
>
>> +
>> + power-domains:
>> + description: Should contain a phandle to a PM domain provider node
>> + and an args specifier containing the USB device id
>> + value. This property is as per the binding,
>> + Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
>
> How many?
>
>> +
>> + dwc3:
>
> This doesn't work because there's a unit address. You need a pattern.
>
>> + description: This is the node representing the DWC3 controller instance
>> + Documentation/devicetree/bindings/usb/dwc3.txt
>
> type: object
>
>> +
>> +required:
>> + - compatible
>> + - reg
>> + - interrupts
>> + - clocks
>
> additionalProperties: false
>
>> +
>> +examples:
>> + - |
>> + #include <dt-bindings/interrupt-controller/arm-gic.h>
>> +
>> + usb: usb@2680000 {
>> + compatible = "ti,keystone-dwc3";
>> + #address-cells = <1>;
>> + #size-cells = <1>;
>
> These have to be documented.
>
>> + reg = <0x2680000 0x10000>;
>> + clocks = <&clkusb>;
>> + clock-names = "usb";
>> + interrupts = <GIC_SPI 393 IRQ_TYPE_EDGE_RISING>;
>> + ranges;
>
> This too.
>
>> +
>> + dwc3@2690000 {
>> + compatible = "synopsys,dwc3";
>> + reg = <0x2690000 0x70000>;
>> + interrupts = <GIC_SPI 393 IRQ_TYPE_EDGE_RISING>;
>> + usb-phy = <&usb_phy>, <&usb_phy>;
>> + };
>> + };
>> --
>> Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
>> Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
>>
--
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
^ permalink raw reply
* Re: [PATCH v4 4/5] regulator: qcom: Add labibb driver
From: Mark Brown @ 2020-06-02 12:25 UTC (permalink / raw)
To: Sumit Semwal
Cc: agross, Bjorn Andersson, lgirdwood, robh+dt, Nisha Kumari,
linux-arm-msm, LKML, devicetree, kgunda, Rajendra Nayak
In-Reply-To: <CAO_48GGgNUGosN2PiL=U5JkR3Bh5wNK3N4xYYML1UwmdfDPRww@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1852 bytes --]
On Tue, Jun 02, 2020 at 05:40:45PM +0530, Sumit Semwal wrote:
> On Tue, 2 Jun 2020 at 17:02, Mark Brown <broonie@kernel.org> wrote:
> > On Tue, Jun 02, 2020 at 03:39:23PM +0530, Sumit Semwal wrote:
> > This should be a get_status() callback...
> From my (limited) understanding of downstream code, it seemed like for
> this set of regulators, the 'enabled' check is done via the
> 'REG_LABIBB_STATUS1 reg; for some reason, not via the same enable_reg
> / enable_mask ones. That's why I used it as is_enabled() callback.
> I will try and check with the QC folks to clarify this point about
> their hardware.
The way this is functioning at the minute the downstream code is just
buggy.
> > ...is_enabled() should just be regulator_is_enabled_regmap() and these
> > functions should just be removed entirely, you can use the regmap
> > operations directly as the ops without the wrapper.
> The 2 wrappers are a precursor to the next patch, where we keep track
> of regulator's enable status to check during SC handling.
Add the functions when they're useful, not before. TBH if the register
is write only you're probably better off adding a register cache.
> > > + match = of_match_device(qcom_labibb_match, &pdev->dev);
> > > + if (!match)
> > > + return -ENODEV;
> > > +
> > > + for (reg_data = match->data; reg_data->name; reg_data++) {
> > > + child = of_get_child_by_name(pdev->dev.of_node, reg_data->name);
> > > +
> > > + if (WARN_ON(child == NULL))
> > > + return -EINVAL;
> >
> > This feels like the DT bindings are confused - why do we need to search
> > like this?
> The WARN_ON? This was suggested by Bjorn to catch the case where the
> DT binding for a PMIC instantiates only one of the regulators.
No, this whole loop - why this whole match and get child stuff?
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH v4 5/5] regulator: qcom: labibb: Add SC interrupt handling
From: Mark Brown @ 2020-06-02 12:22 UTC (permalink / raw)
To: Sumit Semwal
Cc: agross, bjorn.andersson, lgirdwood, robh+dt, nishakumari,
linux-arm-msm, linux-kernel, devicetree, kgunda, rnayak
In-Reply-To: <20200602100924.26256-6-sumit.semwal@linaro.org>
[-- Attachment #1: Type: text/plain, Size: 1779 bytes --]
On Tue, Jun 02, 2020 at 03:39:24PM +0530, Sumit Semwal wrote:
> static int qcom_labibb_regulator_enable(struct regulator_dev *rdev)
> {
> - return regulator_enable_regmap(rdev);
> + int ret;
> + struct labibb_regulator *reg = rdev_get_drvdata(rdev);
> +
> + ret = regulator_enable_regmap(rdev);
> + if (ret >= 0)
> + reg->enabled = true;
Can we not read the register we just wrote to here?
> + /*
> + * The SC(short circuit) fault would trigger PBS(Portable Batch
> + * System) to disable regulators for protection. This would
> + * cause the SC_DETECT status being cleared so that it's not
> + * able to get the SC fault status.
> + * Check if the regulator is enabled in the driver but
> + * disabled in hardware, this means a SC fault had happened
> + * and SCP handling is completed by PBS.
> + */
> + if (!in_sc_err) {
> +
> + reg = labibb_reg->base + REG_LABIBB_ENABLE_CTL;
> +
> + ret = regmap_read_poll_timeout(labibb_reg->regmap,
> + reg, val,
> + !(val & LABIBB_CONTROL_ENABLE),
> + POLLING_SCP_DONE_INTERVAL_US,
> + POLLING_SCP_TIMEOUT);
Why do we need a timeout here?
> + NULL);
> + regulator_unlock(labibb_reg->rdev);
> + }
> + return IRQ_HANDLED;
This returns IRQ_HANDLED even if we didn't detect an interrupt source...
Especially given the need to check to see if the regulator was turned
off by the hardware it seems like there must be some false positives.
> + } else {
> + ret = devm_request_threaded_irq(reg->dev,
> + sc_irq,
> + NULL, labibb_sc_err_handler,
> + IRQF_ONESHOT,
> + "sc-err", reg);
This looks like we're requesting the interrupt before we register the
regulator which means the interrupt might fire without the regulator
being there. The order of registration should be reversed.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: Security Random Number Generator support
From: Ard Biesheuvel @ 2020-06-02 12:14 UTC (permalink / raw)
To: Neal Liu
Cc: Matt Mackall, Herbert Xu, Rob Herring, Matthias Brugger,
Sean Wang, Arnd Bergmann, Greg Kroah-Hartman,
Linux Crypto Mailing List,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Linux ARM, linux-mediatek, lkml, wsd_upstream, Crystal Guo
In-Reply-To: <1591085678-22764-1-git-send-email-neal.liu@mediatek.com>
On Tue, 2 Jun 2020 at 10:15, Neal Liu <neal.liu@mediatek.com> wrote:
>
> These patch series introduce a security random number generator
> which provides a generic interface to get hardware rnd from Secure
> state. The Secure state can be Arm Trusted Firmware(ATF), Trusted
> Execution Environment(TEE), or even EL2 hypervisor.
>
> Patch #1..2 adds sec-rng kernel driver for Trustzone based SoCs.
> For security awareness SoCs on ARMv8 with TrustZone enabled,
> peripherals like entropy sources is not accessible from normal world
> (linux) and rather accessible from secure world (HYP/ATF/TEE) only.
> This driver aims to provide a generic interface to Arm Trusted
> Firmware or Hypervisor rng service.
>
>
> changes since v1:
> - rename mt67xx-rng to mtk-sec-rng since all MediaTek ARMv8 SoCs can reuse
> this driver.
> - refine coding style and unnecessary check.
>
> changes since v2:
> - remove unused comments.
> - remove redundant variable.
>
> changes since v3:
> - add dt-bindings for MediaTek rng with TrustZone enabled.
> - revise HWRNG SMC call fid.
>
> changes since v4:
> - move bindings to the arm/firmware directory.
> - revise driver init flow to check more property.
>
> changes since v5:
> - refactor to more generic security rng driver which
> is not platform specific.
>
> *** BLURB HERE ***
>
> Neal Liu (2):
> dt-bindings: rng: add bindings for sec-rng
> hwrng: add sec-rng driver
>
There is no reason to model a SMC call as a driver, and represent it
via a DT node like this.
It would be much better if this SMC interface is made truly generic,
and wired into the arch_get_random() interface, which can be used much
earlier.
> .../devicetree/bindings/rng/sec-rng.yaml | 53 ++++++
> drivers/char/hw_random/Kconfig | 13 ++
> drivers/char/hw_random/Makefile | 1 +
> drivers/char/hw_random/sec-rng.c | 155 ++++++++++++++++++
> 4 files changed, 222 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/rng/sec-rng.yaml
> create mode 100644 drivers/char/hw_random/sec-rng.c
>
> --
> 2.18.0
^ permalink raw reply
* RE: [PATCH v7 21/24] iommu/arm-smmu-v3: Add stall support for platform devices
From: Shameerali Kolothum Thodi @ 2020-06-02 12:12 UTC (permalink / raw)
To: Jean-Philippe Brucker
Cc: devicetree@vger.kernel.org, kevin.tian@intel.com,
fenghua.yu@intel.com, linux-pci@vger.kernel.org,
felix.kuehling@amd.com, robin.murphy@arm.com,
christian.koenig@amd.com, hch@infradead.org, jgg@ziepe.ca,
iommu@lists.linux-foundation.org, catalin.marinas@arm.com,
zhangfei.gao@linaro.org, will@kernel.org, linux-mm@kvack.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <20200602114611.GB1029680@myrica>
> -----Original Message-----
> From: linux-arm-kernel [mailto:linux-arm-kernel-bounces@lists.infradead.org]
> On Behalf Of Jean-Philippe Brucker
> Sent: 02 June 2020 12:46
> To: Shameerali Kolothum Thodi <shameerali.kolothum.thodi@huawei.com>
> Cc: devicetree@vger.kernel.org; kevin.tian@intel.com; fenghua.yu@intel.com;
> linux-pci@vger.kernel.org; felix.kuehling@amd.com; robin.murphy@arm.com;
> christian.koenig@amd.com; hch@infradead.org; jgg@ziepe.ca;
> iommu@lists.linux-foundation.org; catalin.marinas@arm.com;
> zhangfei.gao@linaro.org; will@kernel.org; linux-mm@kvack.org;
> linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH v7 21/24] iommu/arm-smmu-v3: Add stall support for
> platform devices
>
> On Tue, Jun 02, 2020 at 10:31:29AM +0000, Shameerali Kolothum Thodi wrote:
> > Hi Jean,
> >
> > > -----Original Message-----
> > > From: linux-arm-kernel
> > > [mailto:linux-arm-kernel-bounces@lists.infradead.org]
> > > On Behalf Of Jean-Philippe Brucker
> > > Sent: 02 June 2020 10:39
> > > To: Shameerali Kolothum Thodi <shameerali.kolothum.thodi@huawei.com>
> > > Cc: devicetree@vger.kernel.org; kevin.tian@intel.com;
> > > will@kernel.org; fenghua.yu@intel.com; jgg@ziepe.ca;
> > > linux-pci@vger.kernel.org; felix.kuehling@amd.com;
> > > hch@infradead.org; linux-mm@kvack.org;
> > > iommu@lists.linux-foundation.org; catalin.marinas@arm.com;
> > > zhangfei.gao@linaro.org; robin.murphy@arm.com;
> > > christian.koenig@amd.com; linux-arm-kernel@lists.infradead.org
> > > Subject: Re: [PATCH v7 21/24] iommu/arm-smmu-v3: Add stall support
> > > for platform devices
> > >
> > > Hi Shameer,
> > >
> > > On Mon, Jun 01, 2020 at 12:42:15PM +0000, Shameerali Kolothum Thodi
> > > wrote:
> > > > > /* IRQ and event handlers */
> > > > > +static int arm_smmu_handle_evt(struct arm_smmu_device *smmu,
> > > > > +u64
> > > > > +*evt) {
> > > > > + int ret;
> > > > > + u32 perm = 0;
> > > > > + struct arm_smmu_master *master;
> > > > > + bool ssid_valid = evt[0] & EVTQ_0_SSV;
> > > > > + u8 type = FIELD_GET(EVTQ_0_ID, evt[0]);
> > > > > + u32 sid = FIELD_GET(EVTQ_0_SID, evt[0]);
> > > > > + struct iommu_fault_event fault_evt = { };
> > > > > + struct iommu_fault *flt = &fault_evt.fault;
> > > > > +
> > > > > + /* Stage-2 is always pinned at the moment */
> > > > > + if (evt[1] & EVTQ_1_S2)
> > > > > + return -EFAULT;
> > > > > +
> > > > > + master = arm_smmu_find_master(smmu, sid);
> > > > > + if (!master)
> > > > > + return -EINVAL;
> > > > > +
> > > > > + if (evt[1] & EVTQ_1_READ)
> > > > > + perm |= IOMMU_FAULT_PERM_READ;
> > > > > + else
> > > > > + perm |= IOMMU_FAULT_PERM_WRITE;
> > > > > +
> > > > > + if (evt[1] & EVTQ_1_EXEC)
> > > > > + perm |= IOMMU_FAULT_PERM_EXEC;
> > > > > +
> > > > > + if (evt[1] & EVTQ_1_PRIV)
> > > > > + perm |= IOMMU_FAULT_PERM_PRIV;
> > > > > +
> > > > > + if (evt[1] & EVTQ_1_STALL) {
> > > > > + flt->type = IOMMU_FAULT_PAGE_REQ;
> > > > > + flt->prm = (struct iommu_fault_page_request) {
> > > > > + .flags = IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE,
> > > > > + .pasid = FIELD_GET(EVTQ_0_SSID, evt[0]),
> > > > > + .grpid = FIELD_GET(EVTQ_1_STAG, evt[1]),
> > > > > + .perm = perm,
> > > > > + .addr = FIELD_GET(EVTQ_2_ADDR, evt[2]),
> > > > > + };
> > > > > +
> > > >
> > > > > + if (ssid_valid)
> > > > > + flt->prm.flags |=
> > > IOMMU_FAULT_PAGE_REQUEST_PASID_VALID;
> > > >
> > > > Do we need to set this for STALL mode only support? I had an issue
> > > > with this being set on a vSVA POC based on our D06 zip
> > > > device(which is a "fake " pci dev that supports STALL mode but no
> > > > PRI). The issue is, CMDQ_OP_RESUME doesn't have any ssid or SSV
> > > > params and works on sid
> > > and stag only.
> > >
> > > I don't understand the problem, arm_smmu_page_response() doesn't set
> > > SSID or SSV when sending a CMDQ_OP_RESUME. Could you detail the flow
> > > of a stall event and RESUME command in your prototype? Are you
> > > getting issues with the host driver or the guest driver?
> >
> > The issue is on the host side iommu_page_response(). The flow is
> > something like below.
> >
> > Stall: Host:-
> >
> > arm_smmu_handle_evt()
> > iommu_report_device_fault()
> > vfio_pci_iommu_dev_fault_handler()
> >
> > Stall: Qemu:-
> >
> > vfio_dma_fault_notifier_handler()
> > inject_faults()
> > smmuv3_inject_faults()
> >
> > Stall: Guest:-
> >
> > arm_smmu_handle_evt()
> > iommu_report_device_fault()
> > iommu_queue_iopf
> > ...
> > iopf_handle_group()
> > iopf_handle_single()
> > handle_mm_fault()
> > iopf_complete()
> > iommu_page_response()
> > arm_smmu_page_response()
> > arm_smmu_cmdq_issue_cmd(CMDQ_OP_RESUME)
> >
> > Resume: Qemu:-
> >
> > smmuv3_cmdq_consume(SMMU_CMD_RESUME)
> > smmuv3_notify_page_resp()
> > vfio:ioctl(page_response) --> struct iommu_page_response is filled
> > with only version, grpid and code.
> >
> > Resume: Host:-
> > ioctl(page_response)
> > iommu_page_response() --> fails as the pending req has PASID_VALID
> flag
> > set and it checks for a match.
>
> I believe the fix needs to be here. It's also wrong for PRI since not all PCIe
> endpoint require a PASID in the page response. Could you try the attached
> patch?
Going through the patch, yes, that will definitely fix the issue. But isn't it better if
the request itself indicate whether it expects a response msg with a valid pasid or
not? The response msg can come from userspace as well(vSVA) and if for some reason
doesn't set it for a req that expects pasid then it should be an error, right? In the temp
fix I had, I introduced another flag to indicate the endpoint has PRI support or not and
used that to verify the pasid requirement. But for the PRI case you mentioned
above, not sure it is easy to get that information or not. May be I am complicating things
here :)
Thanks,
Shameer
> Thanks,
> Jean
>
> > arm_smmu_page_response()
> >
> > Hope the above is clear.
> >
> > > We do need to forward the SSV flag all the way to the guest driver,
> > > so the guest can find the faulting address space using the SSID.
> > > Once the guest handled the fault, then we don't send the SSID back
> > > to the host as part of the RESUME command.
> >
> > True, the guest requires SSV flag to handle the page fault. But, as
> > shown in the flow above, the issue is on the host side
> > iommu_page_response() where it searches for a matching pending req
> > based on pasid. Not sure we can bypass that and call
> > arm_smmu_page_response() directly but then have to delete the pending req
> from the list as well.
> >
> > Please let me know if there is a better way to handle the host side
> > page response.
> >
> > Thanks,
> > Shameer
> >
> > > Thanks,
> > > Jean
> > >
> > > > Hence, it is difficult for
> > > > Qemu SMMUv3 to populate this fields while preparing a page
> > > > response. I can see that this flag is being checked in
> > > > iopf_handle_single() (patch
> > > > 04/24) as well. For POC, I used a temp fix[1] to work around this.
> > > > Please let
> > > me know your thoughts.
> > > >
> > > > Thanks,
> > > > Shameer
> > > >
> > > > 1.
> > > > https://github.com/hisilicon/kernel-dev/commit/99ff96146e924055f38
> > > > d97a
> > > > 5897e4becfa378d15
> > > >
> > >
> > > _______________________________________________
> > > 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 v4 4/5] regulator: qcom: Add labibb driver
From: Sumit Semwal @ 2020-06-02 12:10 UTC (permalink / raw)
To: Mark Brown
Cc: agross, Bjorn Andersson, lgirdwood, robh+dt, Nisha Kumari,
linux-arm-msm, LKML, devicetree, kgunda, Rajendra Nayak
In-Reply-To: <20200602113241.GE5684@sirena.org.uk>
Hi Mark,
Thank you very much for reviewing.
On Tue, 2 Jun 2020 at 17:02, Mark Brown <broonie@kernel.org> wrote:
>
> On Tue, Jun 02, 2020 at 03:39:23PM +0530, Sumit Semwal wrote:
>
> > +static int qcom_labibb_regulator_is_enabled(struct regulator_dev *rdev)
> > +{
> > + int ret;
> > + unsigned int val;
> > + struct labibb_regulator *reg = rdev_get_drvdata(rdev);
> > +
> > + ret = regmap_read(reg->regmap, reg->base + REG_LABIBB_STATUS1, &val);
> > + if (ret < 0) {
> > + dev_err(reg->dev, "Read register failed ret = %d\n", ret);
> > + return ret;
> > + }
> > + return !!(val & LABIBB_STATUS1_VREG_OK_BIT);
> > +}
>
> This should be a get_status() callback...
>
From my (limited) understanding of downstream code, it seemed like for
this set of regulators, the 'enabled' check is done via the
'REG_LABIBB_STATUS1 reg; for some reason, not via the same enable_reg
/ enable_mask ones. That's why I used it as is_enabled() callback.
I will try and check with the QC folks to clarify this point about
their hardware.
> > +static int qcom_labibb_regulator_enable(struct regulator_dev *rdev)
> > +{
> > + return regulator_enable_regmap(rdev);
> > +}
> > +
> > +static int qcom_labibb_regulator_disable(struct regulator_dev *rdev)
> > +{
> > + return regulator_disable_regmap(rdev);
> > +}
>
> ...is_enabled() should just be regulator_is_enabled_regmap() and these
> functions should just be removed entirely, you can use the regmap
> operations directly as the ops without the wrapper.
The 2 wrappers are a precursor to the next patch, where we keep track
of regulator's enable status to check during SC handling.
>
> > + match = of_match_device(qcom_labibb_match, &pdev->dev);
> > + if (!match)
> > + return -ENODEV;
> > +
> > + for (reg_data = match->data; reg_data->name; reg_data++) {
> > + child = of_get_child_by_name(pdev->dev.of_node, reg_data->name);
> > +
> > + if (WARN_ON(child == NULL))
> > + return -EINVAL;
>
> This feels like the DT bindings are confused - why do we need to search
> like this?
The WARN_ON? This was suggested by Bjorn to catch the case where the
DT binding for a PMIC instantiates only one of the regulators.
>
> > + dev_info(dev, "Registering %s regulator\n", child->full_name);
>
> This is noise, remove it. The regulator framework will announce new
> regulators anyway.
Agreed. will remove in the next iteration.
Best,
Sumit.
^ permalink raw reply
* Re: [PATCH v4 1/5] regulator: Allow regulators to verify enabled during enable()
From: Sumit Semwal @ 2020-06-02 11:57 UTC (permalink / raw)
To: Mark Brown
Cc: agross, Bjorn Andersson, lgirdwood, robh+dt, Nisha Kumari,
linux-arm-msm, LKML, devicetree, kgunda, Rajendra Nayak
In-Reply-To: <20200602112415.GD5684@sirena.org.uk>
Hi Mark,
Thanks for the review!
On Tue, 2 Jun 2020 at 16:54, Mark Brown <broonie@kernel.org> wrote:
>
> On Tue, Jun 02, 2020 at 03:39:20PM +0530, Sumit Semwal wrote:
>
> > +
> > + if (time_remaining <= 0) {
> > + rdev_err(rdev, "Enabled check failed.\n");
> > + return -ETIMEDOUT;
>
> s/failed/timed out/
Ack
>
> > + * @poll_enabled_time: Maximum time (in uS) to poll if the regulator is
> > + * actually enabled, after enable() call
> > + *
>
> This comment needs updating to reflect the new implementation.
Yes, I will update.
Best,
Sumit.
^ permalink raw reply
* [PATCH v5 01/11] PCI: qcom: Add missing ipq806x clocks in PCIe driver
From: Ansuel Smith @ 2020-06-02 11:53 UTC (permalink / raw)
To: Rob Herring
Cc: Ansuel Smith, Sham Muthayyan, Rob Herring, Andy Gross,
Bjorn Andersson, Bjorn Helgaas, Mark Rutland, Stanimir Varbanov,
Lorenzo Pieralisi, Andrew Murray, Philipp Zabel, linux-arm-msm,
linux-pci, devicetree, linux-kernel
In-Reply-To: <20200602115353.20143-1-ansuelsmth@gmail.com>
Aux and Ref clk are missing in PCIe qcom driver. Add support for this
optional clks for ipq8064/apq8064 SoC.
Fixes: 82a823833f4e ("PCI: qcom: Add Qualcomm PCIe controller driver")
Signed-off-by: Sham Muthayyan <smuthayy@codeaurora.org>
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---
drivers/pci/controller/dwc/pcie-qcom.c | 38 ++++++++++++++++++++++----
1 file changed, 33 insertions(+), 5 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
index 5ea527a6bd9f..4bf93ab8c7a7 100644
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -88,6 +88,8 @@ struct qcom_pcie_resources_2_1_0 {
struct clk *iface_clk;
struct clk *core_clk;
struct clk *phy_clk;
+ struct clk *aux_clk;
+ struct clk *ref_clk;
struct reset_control *pci_reset;
struct reset_control *axi_reset;
struct reset_control *ahb_reset;
@@ -246,6 +248,14 @@ static int qcom_pcie_get_resources_2_1_0(struct qcom_pcie *pcie)
if (IS_ERR(res->phy_clk))
return PTR_ERR(res->phy_clk);
+ res->aux_clk = devm_clk_get_optional(dev, "aux");
+ if (IS_ERR(res->aux_clk))
+ return PTR_ERR(res->aux_clk);
+
+ res->ref_clk = devm_clk_get_optional(dev, "ref");
+ if (IS_ERR(res->ref_clk))
+ return PTR_ERR(res->ref_clk);
+
res->pci_reset = devm_reset_control_get_exclusive(dev, "pci");
if (IS_ERR(res->pci_reset))
return PTR_ERR(res->pci_reset);
@@ -278,6 +288,8 @@ static void qcom_pcie_deinit_2_1_0(struct qcom_pcie *pcie)
clk_disable_unprepare(res->iface_clk);
clk_disable_unprepare(res->core_clk);
clk_disable_unprepare(res->phy_clk);
+ clk_disable_unprepare(res->aux_clk);
+ clk_disable_unprepare(res->ref_clk);
regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
}
@@ -307,16 +319,28 @@ static int qcom_pcie_init_2_1_0(struct qcom_pcie *pcie)
goto err_assert_ahb;
}
+ ret = clk_prepare_enable(res->core_clk);
+ if (ret) {
+ dev_err(dev, "cannot prepare/enable core clock\n");
+ goto err_clk_core;
+ }
+
ret = clk_prepare_enable(res->phy_clk);
if (ret) {
dev_err(dev, "cannot prepare/enable phy clock\n");
goto err_clk_phy;
}
- ret = clk_prepare_enable(res->core_clk);
+ ret = clk_prepare_enable(res->aux_clk);
if (ret) {
- dev_err(dev, "cannot prepare/enable core clock\n");
- goto err_clk_core;
+ dev_err(dev, "cannot prepare/enable aux clock\n");
+ goto err_clk_aux;
+ }
+
+ ret = clk_prepare_enable(res->ref_clk);
+ if (ret) {
+ dev_err(dev, "cannot prepare/enable ref clock\n");
+ goto err_clk_ref;
}
ret = reset_control_deassert(res->ahb_reset);
@@ -372,10 +396,14 @@ static int qcom_pcie_init_2_1_0(struct qcom_pcie *pcie)
return 0;
err_deassert_ahb:
- clk_disable_unprepare(res->core_clk);
-err_clk_core:
+ clk_disable_unprepare(res->ref_clk);
+err_clk_ref:
+ clk_disable_unprepare(res->aux_clk);
+err_clk_aux:
clk_disable_unprepare(res->phy_clk);
err_clk_phy:
+ clk_disable_unprepare(res->core_clk);
+err_clk_core:
clk_disable_unprepare(res->iface_clk);
err_assert_ahb:
regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
--
2.25.1
^ permalink raw reply related
* [PATCH v5 04/11] PCI: qcom: Add missing reset for ipq806x
From: Ansuel Smith @ 2020-06-02 11:53 UTC (permalink / raw)
To: Rob Herring
Cc: Ansuel Smith, Sham Muthayyan, stable, Rob Herring, Philipp Zabel,
Andy Gross, Bjorn Andersson, Bjorn Helgaas, Mark Rutland,
Stanimir Varbanov, Lorenzo Pieralisi, Andrew Murray,
linux-arm-msm, linux-pci, devicetree, linux-kernel
In-Reply-To: <20200602115353.20143-1-ansuelsmth@gmail.com>
Add missing ext reset used by ipq8064 SoC in PCIe qcom driver.
Fixes: 82a823833f4e ("PCI: qcom: Add Qualcomm PCIe controller driver")
Signed-off-by: Sham Muthayyan <smuthayy@codeaurora.org>
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
Cc: stable@vger.kernel.org # v4.5+
Reviewed-by: Rob Herring <robh@kernel.org>
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
---
drivers/pci/controller/dwc/pcie-qcom.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
index 4512c2c5f61c..4dab5ef630cc 100644
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -95,6 +95,7 @@ struct qcom_pcie_resources_2_1_0 {
struct reset_control *ahb_reset;
struct reset_control *por_reset;
struct reset_control *phy_reset;
+ struct reset_control *ext_reset;
struct regulator_bulk_data supplies[QCOM_PCIE_2_1_0_MAX_SUPPLY];
};
@@ -272,6 +273,10 @@ static int qcom_pcie_get_resources_2_1_0(struct qcom_pcie *pcie)
if (IS_ERR(res->por_reset))
return PTR_ERR(res->por_reset);
+ res->ext_reset = devm_reset_control_get_optional_exclusive(dev, "ext");
+ if (IS_ERR(res->ext_reset))
+ return PTR_ERR(res->ext_reset);
+
res->phy_reset = devm_reset_control_get_exclusive(dev, "phy");
return PTR_ERR_OR_ZERO(res->phy_reset);
}
@@ -285,6 +290,7 @@ static void qcom_pcie_deinit_2_1_0(struct qcom_pcie *pcie)
reset_control_assert(res->axi_reset);
reset_control_assert(res->ahb_reset);
reset_control_assert(res->por_reset);
+ reset_control_assert(res->ext_reset);
reset_control_assert(res->phy_reset);
clk_disable_unprepare(res->iface_clk);
clk_disable_unprepare(res->core_clk);
@@ -343,6 +349,12 @@ static int qcom_pcie_init_2_1_0(struct qcom_pcie *pcie)
goto err_deassert_ahb;
}
+ ret = reset_control_deassert(res->ext_reset);
+ if (ret) {
+ dev_err(dev, "cannot deassert ext reset\n");
+ goto err_deassert_ahb;
+ }
+
/* enable PCIe clocks and resets */
val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL);
val &= ~BIT(0);
--
2.25.1
^ permalink raw reply related
* [PATCH v5 02/11] dt-bindings: PCI: qcom: Add missing clks
From: Ansuel Smith @ 2020-06-02 11:53 UTC (permalink / raw)
To: Rob Herring
Cc: Ansuel Smith, Rob Herring, Andy Gross, Bjorn Andersson,
Bjorn Helgaas, Mark Rutland, Stanimir Varbanov, Lorenzo Pieralisi,
Andrew Murray, Philipp Zabel, linux-arm-msm, linux-pci,
devicetree, linux-kernel
In-Reply-To: <20200602115353.20143-1-ansuelsmth@gmail.com>
Document missing clks used in ipq8064 SoC.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
Acked-by: Rob Herring <robh@kernel.org>
---
Documentation/devicetree/bindings/pci/qcom,pcie.txt | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie.txt b/Documentation/devicetree/bindings/pci/qcom,pcie.txt
index 981b4de12807..becdbdc0fffa 100644
--- a/Documentation/devicetree/bindings/pci/qcom,pcie.txt
+++ b/Documentation/devicetree/bindings/pci/qcom,pcie.txt
@@ -90,6 +90,8 @@
Definition: Should contain the following entries
- "core" Clocks the pcie hw block
- "phy" Clocks the pcie PHY block
+ - "aux" Clocks the pcie AUX block
+ - "ref" Clocks the pcie ref block
- clock-names:
Usage: required for apq8084/ipq4019
Value type: <stringlist>
@@ -277,8 +279,10 @@
<0 0 0 4 &intc 0 39 IRQ_TYPE_LEVEL_HIGH>; /* int_d */
clocks = <&gcc PCIE_A_CLK>,
<&gcc PCIE_H_CLK>,
- <&gcc PCIE_PHY_CLK>;
- clock-names = "core", "iface", "phy";
+ <&gcc PCIE_PHY_CLK>,
+ <&gcc PCIE_AUX_CLK>,
+ <&gcc PCIE_ALT_REF_CLK>;
+ clock-names = "core", "iface", "phy", "aux", "ref";
resets = <&gcc PCIE_ACLK_RESET>,
<&gcc PCIE_HCLK_RESET>,
<&gcc PCIE_POR_RESET>,
--
2.25.1
^ permalink raw reply related
* [PATCH v5 05/11] dt-bindings: PCI: qcom: Add ext reset
From: Ansuel Smith @ 2020-06-02 11:53 UTC (permalink / raw)
To: Rob Herring
Cc: Ansuel Smith, Rob Herring, Andy Gross, Bjorn Andersson,
Bjorn Helgaas, Mark Rutland, Stanimir Varbanov, Lorenzo Pieralisi,
Andrew Murray, Philipp Zabel, linux-arm-msm, linux-pci,
devicetree, linux-kernel
In-Reply-To: <20200602115353.20143-1-ansuelsmth@gmail.com>
Document ext reset used in ipq8064 SoC by qcom PCIe driver.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
Acked-by: Rob Herring <robh@kernel.org>
---
Documentation/devicetree/bindings/pci/qcom,pcie.txt | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie.txt b/Documentation/devicetree/bindings/pci/qcom,pcie.txt
index becdbdc0fffa..6efcef040741 100644
--- a/Documentation/devicetree/bindings/pci/qcom,pcie.txt
+++ b/Documentation/devicetree/bindings/pci/qcom,pcie.txt
@@ -179,6 +179,7 @@
- "pwr" PWR reset
- "ahb" AHB reset
- "phy_ahb" PHY AHB reset
+ - "ext" EXT reset
- reset-names:
Usage: required for ipq8074
@@ -287,8 +288,9 @@
<&gcc PCIE_HCLK_RESET>,
<&gcc PCIE_POR_RESET>,
<&gcc PCIE_PCI_RESET>,
- <&gcc PCIE_PHY_RESET>;
- reset-names = "axi", "ahb", "por", "pci", "phy";
+ <&gcc PCIE_PHY_RESET>,
+ <&gcc PCIE_EXT_RESET>;
+ reset-names = "axi", "ahb", "por", "pci", "phy", "ext";
pinctrl-0 = <&pcie_pins_default>;
pinctrl-names = "default";
};
--
2.25.1
^ permalink raw reply related
* [PATCH v5 07/11] PCI: qcom: Define some PARF params needed for ipq8064 SoC
From: Ansuel Smith @ 2020-06-02 11:53 UTC (permalink / raw)
To: Rob Herring
Cc: Ansuel Smith, stable, Rob Herring, Andy Gross, Bjorn Andersson,
Bjorn Helgaas, Mark Rutland, Stanimir Varbanov, Lorenzo Pieralisi,
Andrew Murray, Philipp Zabel, linux-arm-msm, linux-pci,
devicetree, linux-kernel
In-Reply-To: <20200602115353.20143-1-ansuelsmth@gmail.com>
Set some specific value for Tx De-Emphasis, Tx Swing and Rx equalization
needed on some ipq8064 based device (Netgear R7800 for example). Without
this the system locks on kernel load.
Fixes: 82a823833f4e ("PCI: qcom: Add Qualcomm PCIe controller driver")
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
Cc: stable@vger.kernel.org # v4.5+
Reviewed-by: Rob Herring <robh@kernel.org>
---
drivers/pci/controller/dwc/pcie-qcom.c | 27 ++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
index f2ea1ab6f584..f5398b0d270c 100644
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -46,6 +46,9 @@
#define PCIE20_PARF_PHY_CTRL 0x40
#define PCIE20_PARF_PHY_REFCLK 0x4C
+#define PHY_REFCLK_SSP_EN BIT(16)
+#define PHY_REFCLK_USE_PAD BIT(12)
+
#define PCIE20_PARF_DBI_BASE_ADDR 0x168
#define PCIE20_PARF_SLV_ADDR_SPACE_SIZE 0x16C
#define PCIE20_PARF_MHI_CLOCK_RESET_CTRL 0x174
@@ -77,6 +80,18 @@
#define DBI_RO_WR_EN 1
#define PERST_DELAY_US 1000
+/* PARF registers */
+#define PCIE20_PARF_PCS_DEEMPH 0x34
+#define PCS_DEEMPH_TX_DEEMPH_GEN1(x) ((x) << 16)
+#define PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(x) ((x) << 8)
+#define PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(x) ((x) << 0)
+
+#define PCIE20_PARF_PCS_SWING 0x38
+#define PCS_SWING_TX_SWING_FULL(x) ((x) << 8)
+#define PCS_SWING_TX_SWING_LOW(x) ((x) << 0)
+
+#define PCIE20_PARF_CONFIG_BITS 0x50
+#define PHY_RX0_EQ(x) ((x) << 24)
#define PCIE20_v3_PARF_SLV_ADDR_SPACE_SIZE 0x358
#define SLV_ADDR_SPACE_SZ 0x10000000
@@ -293,6 +308,7 @@ static int qcom_pcie_init_2_1_0(struct qcom_pcie *pcie)
struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0;
struct dw_pcie *pci = pcie->pci;
struct device *dev = pci->dev;
+ struct device_node *node = dev->of_node;
u32 val;
int ret;
@@ -347,6 +363,17 @@ static int qcom_pcie_init_2_1_0(struct qcom_pcie *pcie)
val &= ~BIT(0);
writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL);
+ if (of_device_is_compatible(node, "qcom,pcie-ipq8064")) {
+ writel(PCS_DEEMPH_TX_DEEMPH_GEN1(24) |
+ PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(24) |
+ PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(34),
+ pcie->parf + PCIE20_PARF_PCS_DEEMPH);
+ writel(PCS_SWING_TX_SWING_FULL(120) |
+ PCS_SWING_TX_SWING_LOW(120),
+ pcie->parf + PCIE20_PARF_PCS_SWING);
+ writel(PHY_RX0_EQ(4), pcie->parf + PCIE20_PARF_CONFIG_BITS);
+ }
+
/* enable external reference clock */
val = readl(pcie->parf + PCIE20_PARF_PHY_REFCLK);
val |= BIT(16);
--
2.25.1
^ permalink raw reply related
* [PATCH v5 08/11] PCI: qcom: Add support for tx term offset for rev 2.1.0
From: Ansuel Smith @ 2020-06-02 11:53 UTC (permalink / raw)
To: Rob Herring
Cc: Ansuel Smith, Sham Muthayyan, stable, Andy Gross, Bjorn Andersson,
Bjorn Helgaas, Mark Rutland, Stanimir Varbanov, Lorenzo Pieralisi,
Andrew Murray, Philipp Zabel, linux-arm-msm, linux-pci,
devicetree, linux-kernel
In-Reply-To: <20200602115353.20143-1-ansuelsmth@gmail.com>
Add tx term offset support to pcie qcom driver need in some revision of
the ipq806x SoC. Ipq8064 needs tx term offset set to 7.
Fixes: 82a823833f4e ("PCI: qcom: Add Qualcomm PCIe controller driver")
Signed-off-by: Sham Muthayyan <smuthayy@codeaurora.org>
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
Cc: stable@vger.kernel.org # v4.5+
---
drivers/pci/controller/dwc/pcie-qcom.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
index f5398b0d270c..2cd6d1456210 100644
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -45,6 +45,9 @@
#define PCIE_CAP_CPL_TIMEOUT_DISABLE 0x10
#define PCIE20_PARF_PHY_CTRL 0x40
+#define PHY_CTRL_PHY_TX0_TERM_OFFSET_MASK GENMASK(20, 16)
+#define PHY_CTRL_PHY_TX0_TERM_OFFSET(x) ((x) << 16)
+
#define PCIE20_PARF_PHY_REFCLK 0x4C
#define PHY_REFCLK_SSP_EN BIT(16)
#define PHY_REFCLK_USE_PAD BIT(12)
@@ -374,9 +377,18 @@ static int qcom_pcie_init_2_1_0(struct qcom_pcie *pcie)
writel(PHY_RX0_EQ(4), pcie->parf + PCIE20_PARF_CONFIG_BITS);
}
+ if (of_device_is_compatible(node, "qcom,pcie-ipq8064")) {
+ /* set TX termination offset */
+ val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL);
+ val &= ~PHY_CTRL_PHY_TX0_TERM_OFFSET_MASK;
+ val |= PHY_CTRL_PHY_TX0_TERM_OFFSET(7);
+ writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL);
+ }
+
/* enable external reference clock */
val = readl(pcie->parf + PCIE20_PARF_PHY_REFCLK);
- val |= BIT(16);
+ val &= ~PHY_REFCLK_USE_PAD;
+ val |= PHY_REFCLK_SSP_EN;
writel(val, pcie->parf + PCIE20_PARF_PHY_REFCLK);
/* wait for clock acquisition */
--
2.25.1
^ permalink raw reply related
* [PATCH v5 09/11] PCI: qcom: Add ipq8064 rev2 variant
From: Ansuel Smith @ 2020-06-02 11:53 UTC (permalink / raw)
To: Rob Herring
Cc: Ansuel Smith, Andy Gross, Bjorn Andersson, Bjorn Helgaas,
Mark Rutland, Stanimir Varbanov, Lorenzo Pieralisi, Andrew Murray,
Philipp Zabel, linux-arm-msm, linux-pci, devicetree, linux-kernel
In-Reply-To: <20200602115353.20143-1-ansuelsmth@gmail.com>
Ipq8064-v2 have tx term offset set to 0. Introduce this variant to permit
different offset based on the revision.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/pci/controller/dwc/pcie-qcom.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
index 2cd6d1456210..259b627bf890 100644
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -366,7 +366,8 @@ static int qcom_pcie_init_2_1_0(struct qcom_pcie *pcie)
val &= ~BIT(0);
writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL);
- if (of_device_is_compatible(node, "qcom,pcie-ipq8064")) {
+ if (of_device_is_compatible(node, "qcom,pcie-ipq8064") ||
+ of_device_is_compatible(node, "qcom,pcie-ipq8064-v2")) {
writel(PCS_DEEMPH_TX_DEEMPH_GEN1(24) |
PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(24) |
PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(34),
@@ -1464,6 +1465,7 @@ static int qcom_pcie_probe(struct platform_device *pdev)
static const struct of_device_id qcom_pcie_match[] = {
{ .compatible = "qcom,pcie-apq8084", .data = &ops_1_0_0 },
{ .compatible = "qcom,pcie-ipq8064", .data = &ops_2_1_0 },
+ { .compatible = "qcom,pcie-ipq8064-v2", .data = &ops_2_1_0 },
{ .compatible = "qcom,pcie-apq8064", .data = &ops_2_1_0 },
{ .compatible = "qcom,pcie-msm8996", .data = &ops_2_3_2 },
{ .compatible = "qcom,pcie-ipq8074", .data = &ops_2_3_3 },
--
2.25.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox