* [PATCH v3] arm64: dts: qcom: apq8016-sbc-d3: Add Qualcomm APQ8016 SBC + D3Camera mezzanine
From: Robert Foss @ 2020-05-18 8:21 UTC (permalink / raw)
To: Vinod Koul, Bjorn Andersson, Rob Herring, linux-arm-msm,
devicetree, linux-kernel
Cc: Nicolas Dechesne, Robert Foss
Add device treee support for the Qualcomm APQ8016 SBC, otherwise known as
the Dragonboard 410c with the D3Camera mezzanine expansion board.
The D3Camera mezzanine ships in a kit with a OmniVision 5640 sensor module,
which is what this DT targets.
Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
Changes since v2:
- Vinod: Change copyright assignment to Linaro
Changes since v1:
- Vinod: Changed license to GPL+BSD
- Vinod: Changed copyright year to 2020
- Nico: Changed name of mezzanine to d3camera
arch/arm64/boot/dts/qcom/Makefile | 1 +
.../boot/dts/qcom/apq8016-sbc-d3camera.dts | 45 +++++++++++++++++++
2 files changed, 46 insertions(+)
create mode 100644 arch/arm64/boot/dts/qcom/apq8016-sbc-d3camera.dts
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index cc103f7020fd..3f95b522694e 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
dtb-$(CONFIG_ARCH_QCOM) += apq8016-sbc.dtb
+dtb-$(CONFIG_ARCH_QCOM) += apq8016-sbc-d3camera.dtb
dtb-$(CONFIG_ARCH_QCOM) += apq8096-db820c.dtb
dtb-$(CONFIG_ARCH_QCOM) += apq8096-ifc6640.dtb
dtb-$(CONFIG_ARCH_QCOM) += ipq6018-cp01-c1.dtb
diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc-d3camera.dts b/arch/arm64/boot/dts/qcom/apq8016-sbc-d3camera.dts
new file mode 100644
index 000000000000..752e5ec47499
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8016-sbc-d3camera.dts
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+/dts-v1/;
+
+#include "apq8016-sbc.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. APQ 8016 SBC w/ D3Camera Mezzanine";
+ compatible = "qcom,apq8016-sbc", "qcom,apq8016", "qcom,sbc";
+};
+
+&cci_i2c0 {
+ /delete-node/ camera_rear@3b;
+
+ camera_rear@76 {
+ compatible = "ovti,ov5640";
+ reg = <0x76>;
+
+ enable-gpios = <&msmgpio 34 GPIO_ACTIVE_HIGH>;
+ reset-gpios = <&msmgpio 35 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&camera_rear_default>;
+
+ clocks = <&gcc GCC_CAMSS_MCLK0_CLK>;
+ clock-names = "xclk";
+ clock-frequency = <23880000>;
+
+ vdddo-supply = <&camera_vdddo_1v8>;
+ vdda-supply = <&camera_vdda_2v8>;
+ vddd-supply = <&camera_vddd_1v5>;
+
+ status = "ok";
+
+ port {
+ ov5640_ep: endpoint {
+ clock-lanes = <1>;
+ data-lanes = <0 2>;
+ remote-endpoint = <&csiphy0_ep>;
+ };
+ };
+ };
+};
--
2.25.1
^ permalink raw reply related
* RE: [PATCH 1/2] dt-bindings: rtc: Convert MXC RTC to json-schema
From: Aisheng Dong @ 2020-05-18 8:22 UTC (permalink / raw)
To: Anson Huang, a.zummo@towertech.it, alexandre.belloni@bootlin.com,
robh+dt@kernel.org, tremyfr@gmail.com, p.bruenn@beckhoff.com,
linux-rtc@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org
Cc: dl-linux-imx
In-Reply-To: <1589436805-22923-1-git-send-email-Anson.Huang@nxp.com>
> From: Anson Huang <Anson.Huang@nxp.com>
> Sent: Thursday, May 14, 2020 2:13 PM
>
> Convert the MXC RTC binding to DT schema format using json-schema.
>
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
Reviewed-by: Dong Aisheng <aisheng.dong@nxp.com>
Regards
Aisheng
^ permalink raw reply
* RE: [PATCH 2/2] dt-bindings: rtc: Convert MXC RTC V2 to json-schema
From: Aisheng Dong @ 2020-05-18 8:23 UTC (permalink / raw)
To: Anson Huang, a.zummo@towertech.it, alexandre.belloni@bootlin.com,
robh+dt@kernel.org, tremyfr@gmail.com, p.bruenn@beckhoff.com,
linux-rtc@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org
Cc: dl-linux-imx
In-Reply-To: <1589436805-22923-2-git-send-email-Anson.Huang@nxp.com>
> From: Anson Huang <Anson.Huang@nxp.com>
> Sent: Thursday, May 14, 2020 2:13 PM
>
> Convert the MXC RTC V2 binding to DT schema format using json-schema.
>
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
Reviewed-by: Dong Aisheng <aisheng.dong@nxp.com>
Regards
Aisheng
^ permalink raw reply
* Re: [PATCH v1 8/9] arm64: dts: actions: Add MMC controller support for S700
From: André Przywara @ 2020-05-18 8:29 UTC (permalink / raw)
To: Manivannan Sadhasivam, Amit Tomer
Cc: Andreas Färber, Rob Herring, cristian.ciocaltea,
linux-arm-kernel, linux-actions, devicetree
In-Reply-To: <20200518061755.GA25113@mani>
On 18/05/2020 07:17, Manivannan Sadhasivam wrote:
> On 0518, Amit Tomer wrote:
>> Hi,
>>
>>> I recommend reading the DT spec, chapter 2.3.1 "compatible":
>>> https://github.com/devicetree-org/devicetree-specification/releases/download/v0.3/devicetree-specification-v0.3.pdf
>>
>> My point is more about, DT validation is not happy about this situation.
>> For instance when I run dt-validate, do see following:
>>
>> /home/amit/work/kernel_work/linux/arch/arm64/boot/dts/actions/s700-cubieboard7.dt.yaml:
>> mmc@e0210000: compatible: Additional items are not allowed
>> ('actions,s700-mmc' was unexpected)
>>
>> and I am not sure if this is because DT and driver has different
>> number of compatible strings.
This has nothing to do with the driver or the actual .dts(i), that's
purely a binding issue.
> Yeah, the DT YAML validation tool doesn't allow this. And there were patches
> removing the additional compatible from DTS.
There are tons of examples of how this is done in the .yaml bindings:
properties:
compatible:
oneOf:
- const: actions,owl-mmc
- items:
- const: action,s700-mmc
- const: actions,owl-mmc
Adding more alternatives would replace the lines after items:
- enum
- action,s700-mmc
- action,s900-mmc
- const: actions,owl-mmc
> I don't know if the DT fallback is discouraged or not.
I don't know if there is an "official" statement on this, but last thing
I heard, adding SoC specific compatibles to generic fallback strings was
encouraged. Hence my proposal, to add one.
> Anyway, is enough investigation done to justify that we need SoC specific tweaks
> in the driver? I think I did look into the downstream code for s700/s500 while
> upstreaming this driver and convinced myself that the same driver could be
> reused without modifications.
It wouldn't be the first time some tiny incompatibility would be
discovered later, also there is always the chance of a hardware errata.
So better safe than sorry.
Cheers,
Andre.
^ permalink raw reply
* Re: [PATCH] arm: dts: am33xx-bone-common: add gpio-line-names
From: Linus Walleij @ 2020-05-18 8:41 UTC (permalink / raw)
To: Felipe Balbi
Cc: Drew Fustini, Grygorii Strashko, Benoît Cousson,
Tony Lindgren, Rob Herring, Linux-OMAP,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
linux-kernel@vger.kernel.org, Jason Kridner, Robert Nelson
In-Reply-To: <875zcty7tt.fsf@kernel.org>
On Mon, May 18, 2020 at 10:18 AM Felipe Balbi <balbi@kernel.org> wrote:
> Linus Walleij <linus.walleij@linaro.org> writes:
> >> gpiochip0 - 32 lines:
> >> line 0: "ethernet" unused input active-high
> >> line 1: "ethernet" unused input active-high
> >
> > Why are the ethernet lines not tagged with respective signal name
> > when right below the SPI lines are explicitly tagged with
> > sclk, cs0 etc?
> >
> > Ethernet is usually RGMII and has signal names like
> > tx_clk, tx_d0, tx_en etc.
> >
> > Also some lines seem to be tagged with the pin number
> > like P9_22, P2_21 below, it seems a bit inconsistent
> > to have much information on some pins and very sketchy
> > information on some.
>
> the pin names match the beagle bone documentation and would help users
> figure out which pins on the expansion headers match to a gpio signal.
OK if it is how it looks in the documentation I agree that is what
users need, maybe the documentation is confusing but there is not
much to do about that.
Yours,
Linus Walleij
^ permalink raw reply
* RE: [PATCH 1/2] ARM: dts: imx6qdl: Use nvmem interface to get fuse data
From: Aisheng Dong @ 2020-05-18 8:44 UTC (permalink / raw)
To: Anson Huang, robh+dt@kernel.org, shawnguo@kernel.org,
s.hauer@pengutronix.de, kernel@pengutronix.de, festevam@gmail.com,
devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
Cc: dl-linux-imx
In-Reply-To: <1589418528-26410-1-git-send-email-Anson.Huang@nxp.com>
> From: Anson Huang <Anson.Huang@nxp.com>
> Sent: Thursday, May 14, 2020 9:09 AM
>
> Although ocotp clock is always ON for i.MX6QDL, OCOTP can be accessed
> directly, but since i.MX6QDL nvmem interface is supported, and
> fsl,tempmon-data is deprecated, use it instead of getting fuse data by reading
> ocotp directly, this makes all i.MX6 SoCs aligned.
>
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
Reviewed-by: Dong Aisheng <aisheng.dong@nxp.com>
Regards
Aisheng
^ permalink raw reply
* [PATCH V3] dt-bindings: interrupt-controller: Convert imx irqsteer to json-schema
From: Anson Huang @ 2020-05-18 8:35 UTC (permalink / raw)
To: tglx, jason, maz, robh+dt, l.stach, linux-kernel, devicetree; +Cc: Linux-imx
Convert the i.MX IRQSTEER binding to DT schema format using json-schema.
Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
Reviewed-by: Dong Aisheng <aisheng.dong@nxp.com>
---
Changes since V2:
- Improve the interrupt items description.
---
.../bindings/interrupt-controller/fsl,irqsteer.txt | 35 ---------
.../interrupt-controller/fsl,irqsteer.yaml | 89 ++++++++++++++++++++++
2 files changed, 89 insertions(+), 35 deletions(-)
delete mode 100644 Documentation/devicetree/bindings/interrupt-controller/fsl,irqsteer.txt
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/fsl,irqsteer.yaml
diff --git a/Documentation/devicetree/bindings/interrupt-controller/fsl,irqsteer.txt b/Documentation/devicetree/bindings/interrupt-controller/fsl,irqsteer.txt
deleted file mode 100644
index 582991c..0000000
--- a/Documentation/devicetree/bindings/interrupt-controller/fsl,irqsteer.txt
+++ /dev/null
@@ -1,35 +0,0 @@
-Freescale IRQSTEER Interrupt multiplexer
-
-Required properties:
-
-- compatible: should be:
- - "fsl,imx8m-irqsteer"
- - "fsl,imx-irqsteer"
-- reg: Physical base address and size of registers.
-- interrupts: Should contain the up to 8 parent interrupt lines used to
- multiplex the input interrupts. They should be specified sequentially
- from output 0 to 7.
-- clocks: Should contain one clock for entry in clock-names
- see Documentation/devicetree/bindings/clock/clock-bindings.txt
-- clock-names:
- - "ipg": main logic clock
-- interrupt-controller: Identifies the node as an interrupt controller.
-- #interrupt-cells: Specifies the number of cells needed to encode an
- interrupt source. The value must be 1.
-- fsl,channel: The output channel that all input IRQs should be steered into.
-- fsl,num-irqs: Number of input interrupts of this channel.
- Should be multiple of 32 input interrupts and up to 512 interrupts.
-
-Example:
-
- interrupt-controller@32e2d000 {
- compatible = "fsl,imx8m-irqsteer", "fsl,imx-irqsteer";
- reg = <0x32e2d000 0x1000>;
- interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clk IMX8MQ_CLK_DISP_APB_ROOT>;
- clock-names = "ipg";
- fsl,channel = <0>;
- fsl,num-irqs = <64>;
- interrupt-controller;
- #interrupt-cells = <1>;
- };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/fsl,irqsteer.yaml b/Documentation/devicetree/bindings/interrupt-controller/fsl,irqsteer.yaml
new file mode 100644
index 0000000..360a575
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/fsl,irqsteer.yaml
@@ -0,0 +1,89 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interrupt-controller/fsl,irqsteer.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Freescale IRQSTEER Interrupt Multiplexer
+
+maintainers:
+ - Lucas Stach <l.stach@pengutronix.de>
+
+properties:
+ compatible:
+ enum:
+ - fsl,imx8m-irqsteer
+ - fsl,imx-irqsteer
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ description: |
+ should contain the up to 8 parent interrupt lines used to multiplex
+ the input interrupts. They should be specified sequentially from
+ output 0 to 7.
+ items:
+ - description: output interrupt 0
+ - description: output interrupt 1
+ - description: output interrupt 2
+ - description: output interrupt 3
+ - description: output interrupt 4
+ - description: output interrupt 5
+ - description: output interrupt 6
+ - description: output interrupt 7
+ minItems: 1
+ maxItems: 8
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ const: ipg
+
+ interrupt-controller: true
+
+ "#interrupt-cells":
+ const: 1
+
+ fsl,channel:
+ $ref: '/schemas/types.yaml#/definitions/uint32'
+ description: |
+ u32 value representing the output channel that all input IRQs should be
+ steered into.
+
+ fsl,num-irqs:
+ $ref: '/schemas/types.yaml#/definitions/uint32'
+ description: |
+ u32 value representing the number of input interrupts of this channel,
+ should be multiple of 32 input interrupts and up to 512 interrupts.
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - clock-names
+ - interrupt-controller
+ - "#interrupt-cells"
+ - fsl,channel
+ - fsl,num-irqs
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/imx8mq-clock.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ interrupt-controller@32e2d000 {
+ compatible = "fsl,imx-irqsteer";
+ reg = <0x32e2d000 0x1000>;
+ interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk IMX8MQ_CLK_DISP_APB_ROOT>;
+ clock-names = "ipg";
+ fsl,channel = <0>;
+ fsl,num-irqs = <64>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
--
2.7.4
^ permalink raw reply related
* RE: [PATCH 2/2] ARM: dts: imx6sl: Use nvmem interface to get fuse data
From: Aisheng Dong @ 2020-05-18 8:45 UTC (permalink / raw)
To: Anson Huang, robh+dt@kernel.org, shawnguo@kernel.org,
s.hauer@pengutronix.de, kernel@pengutronix.de, festevam@gmail.com,
devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
Cc: dl-linux-imx
In-Reply-To: <1589418528-26410-2-git-send-email-Anson.Huang@nxp.com>
> From: Anson Huang <Anson.Huang@nxp.com>
> Sent: Thursday, May 14, 2020 9:09 AM
>
> Although ocotp clock is always ON for i.MX6SL, OCOTP can be accessed directly,
> but since i.MX6SL nvmem interface is supported, and fsl,tempmon-data is
> deprecated, use it instead of getting fuse data by reading ocotp directly, this
> makes all i.MX6 SoCs aligned.
>
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
Reviewed-by: Dong Aisheng <aisheng.dong@nxp.com>
Regards
Aisheng
^ permalink raw reply
* Re: [PATCH v3] arm64: dts: qcom: apq8016-sbc-d3: Add Qualcomm APQ8016 SBC + D3Camera mezzanine
From: Vinod Koul @ 2020-05-18 8:46 UTC (permalink / raw)
To: Robert Foss
Cc: Bjorn Andersson, Rob Herring, linux-arm-msm, devicetree,
linux-kernel, Nicolas Dechesne
In-Reply-To: <20200518082129.2103683-1-robert.foss@linaro.org>
On 18-05-20, 10:21, Robert Foss wrote:
> Add device treee support for the Qualcomm APQ8016 SBC, otherwise known as
> the Dragonboard 410c with the D3Camera mezzanine expansion board.
>
> The D3Camera mezzanine ships in a kit with a OmniVision 5640 sensor module,
> which is what this DT targets.
Reviewed-by: Vinod Koul <vkoul@kernel.org>
--
~Vinod
^ permalink raw reply
* Re: [PATCH 2/3] sdhci: sparx5: Add Sparx5 SoC eMMC driver
From: Lars Povlsen @ 2020-05-18 8:58 UTC (permalink / raw)
To: Adrian Hunter
Cc: Lars Povlsen, Ulf Hansson, SoC Team,
Microchip Linux Driver Support, linux-mmc, devicetree,
linux-arm-kernel, linux-kernel, Alexandre Belloni
In-Reply-To: <6398c7a6-ce5e-1df6-d5a6-08664a7fc123@intel.com>
Adrian Hunter writes:
> On 13/05/20 4:31 pm, Lars Povlsen wrote:
>> This adds the eMMC driver for the Sparx5 SoC. It is based upon the
>> designware IP, but requires some extra initialization and quirks.
>>
>> Reviewed-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
>> Signed-off-by: Lars Povlsen <lars.povlsen@microchip.com>
>> ---
>> drivers/mmc/host/Kconfig | 13 ++
>> drivers/mmc/host/Makefile | 1 +
>> drivers/mmc/host/sdhci-of-sparx5.c | 348 +++++++++++++++++++++++++++++
>> 3 files changed, 362 insertions(+)
>> create mode 100644 drivers/mmc/host/sdhci-of-sparx5.c
>>
>> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
>> index 462b5352fea75..1e8396d09df75 100644
>> --- a/drivers/mmc/host/Kconfig
>> +++ b/drivers/mmc/host/Kconfig
>> @@ -213,6 +213,19 @@ config MMC_SDHCI_OF_DWCMSHC
>> If you have a controller with this interface, say Y or M here.
>> If unsure, say N.
>>
>> +config MMC_SDHCI_OF_SPARX5
>> + tristate "SDHCI OF support for the MCHP Sparx5 SoC"
>> + depends on MMC_SDHCI_PLTFM
>> + depends on ARCH_SPARX5
>> + select MMC_SDHCI_IO_ACCESSORS
>> + help
>> + This selects the Secure Digital Host Controller Interface (SDHCI)
>> + found in the MCHP Sparx5 SoC.
>> +
>> + If you have a Sparx5 SoC with this interface, say Y or M here.
>> +
>> + If unsure, say N.
>> +
>> config MMC_SDHCI_CADENCE
>> tristate "SDHCI support for the Cadence SD/SDIO/eMMC controller"
>> depends on MMC_SDHCI_PLTFM
>> diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
>> index b929ef9412083..9f09b7ffaaa16 100644
>> --- a/drivers/mmc/host/Makefile
>> +++ b/drivers/mmc/host/Makefile
>> @@ -89,6 +89,7 @@ obj-$(CONFIG_MMC_SDHCI_OF_ARASAN) += sdhci-of-arasan.o
>> obj-$(CONFIG_MMC_SDHCI_OF_ASPEED) += sdhci-of-aspeed.o
>> obj-$(CONFIG_MMC_SDHCI_OF_AT91) += sdhci-of-at91.o
>> obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o
>> +obj-$(CONFIG_MMC_SDHCI_OF_SPARX5) += sdhci-of-sparx5.o
>> obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o
>> obj-$(CONFIG_MMC_SDHCI_OF_DWCMSHC) += sdhci-of-dwcmshc.o
>> obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o
>> diff --git a/drivers/mmc/host/sdhci-of-sparx5.c b/drivers/mmc/host/sdhci-of-sparx5.c
>> new file mode 100644
>> index 0000000000000..8253bf80e175a
>> --- /dev/null
>> +++ b/drivers/mmc/host/sdhci-of-sparx5.c
>> @@ -0,0 +1,348 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +/*
>> + * drivers/mmc/host/sdhci-of-sparx5.c
>> + *
>> + * MCHP Sparx5 SoC Secure Digital Host Controller Interface.
>> + *
>> + * Copyright (c) 2019 Microchip Inc.
>> + *
>> + * Author: Lars Povlsen <lars.povlsen@microchip.com>
>> + */
>> +
>> +//#define DEBUG
>> +//#define TRACE_REGISTER
>
> No commented out code please.
Yes, that's not relevant any more, I'll remove it.
>
>> +
>> +#include <linux/sizes.h>
>> +#include <linux/delay.h>
>> +#include <linux/module.h>
>> +#include <linux/regmap.h>
>> +#include <linux/of_device.h>
>> +#include <linux/mfd/syscon.h>
>> +#include <linux/dma-mapping.h>
>> +
>> +#include "sdhci-pltfm.h"
>> +
>> +#define CPU_REGS_GENERAL_CTRL (0x22 * 4)
>> +#define MSHC_DLY_CC_MASK GENMASK(16, 13)
>> +#define MSHC_DLY_CC_SHIFT 13
>> +#define MSHC_DLY_CC_MAX 15
>> +
>> +#define CPU_REGS_PROC_CTRL (0x2C * 4)
>> +#define ACP_CACHE_FORCE_ENA BIT(4)
>> +#define ACP_AWCACHE BIT(3)
>> +#define ACP_ARCACHE BIT(2)
>> +#define ACP_CACHE_MASK (ACP_CACHE_FORCE_ENA|ACP_AWCACHE|ACP_ARCACHE)
>> +
>> +#define MSHC2_VERSION 0x500 /* Off 0x140, reg 0x0 */
>> +#define MSHC2_TYPE 0x504 /* Off 0x140, reg 0x1 */
>> +#define MSHC2_EMMC_CTRL 0x52c /* Off 0x140, reg 0xB */
>> +#define MSHC2_EMMC_CTRL_EMMC_RST_N BIT(2)
>> +#define MSHC2_EMMC_CTRL_IS_EMMC BIT(0)
>> +
>> +struct sdhci_sparx5_data {
>> + struct sdhci_host *host;
>> + struct regmap *cpu_ctrl;
>> + int delay_clock;
>> + struct device_attribute dev_delay_clock;
>> +};
>> +
>> +#define BOUNDARY_OK(addr, len) \
>> + ((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1)))
>> +
>> +#if defined(TRACE_REGISTER)
>
> If you want this then add a Kconfig entry for it
>
No, I'll just remove it.
>> +static void sdhci_sparx5_writel(struct sdhci_host *host, u32 val, int reg)
>> +{
>> + pr_debug("$$$ writel(0x%08x, 0x%02x)\n", val, reg);
>> + writel(val, host->ioaddr + reg);
>> +}
>> +
>> +static void sdhci_sparx5_writew(struct sdhci_host *host, u16 val, int reg)
>> +{
>> + pr_debug("$$$ writew(0x%04x, 0x%02x)\n", val, reg);
>> + writew(val, host->ioaddr + reg);
>> +}
>> +
>> +static void sdhci_sparx5_writeb(struct sdhci_host *host, u8 val, int reg)
>> +{
>> + pr_debug("$$$ writeb(0x%02x, 0x%02x)\n", val, reg);
>> + writeb(val, host->ioaddr + reg);
>> +}
>> +#endif
>> +
>> +/*
>> + * If DMA addr spans 128MB boundary, we split the DMA transfer into two
>> + * so that each DMA transfer doesn't exceed the boundary.
>> + */
>> +static void sdhci_sparx5_adma_write_desc(struct sdhci_host *host, void **desc,
>> + dma_addr_t addr, int len,
>> + unsigned int cmd)
>> +{
>> + int tmplen, offset;
>> +
>> + pr_debug("write_desc: cmd %02x: len %d, offset 0x%0llx\n",
>> + cmd, len, addr);
>
> Please prefix all kernel messages by either the mmc or device e.g.
>
> pr_debug("%s: write_desc: cmd %02x: len %d, offset 0x%0llx\n",
> mmc_hostname(host->mmc), cmd, len, addr);
Will do.
>> +
>> + if (likely(!len || BOUNDARY_OK(addr, len))) {
>> + sdhci_adma_write_desc(host, desc, addr, len, cmd);
>> + return;
>> + }
>> +
>> + pr_debug("write_desc: splitting dma len %d, offset 0x%0llx\n",
>> + len, addr);
>> +
>> + offset = addr & (SZ_128M - 1);
>> + tmplen = SZ_128M - offset;
>> + sdhci_adma_write_desc(host, desc, addr, tmplen, cmd);
>> +
>> + addr += tmplen;
>> + len -= tmplen;
>> + sdhci_adma_write_desc(host, desc, addr, len, cmd);
>> +}
>> +
>> +static void sparx5_set_cacheable(struct sdhci_host *host, u32 value)
>> +{
>> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
>> + struct sdhci_sparx5_data *sdhci_sparx5 = sdhci_pltfm_priv(pltfm_host);
>> +
>> + pr_debug("%s: Set Cacheable = 0x%x\n", mmc_hostname(host->mmc), value);
>> +
>> + /* Update ACP caching attributes in HW */
>> + regmap_update_bits(sdhci_sparx5->cpu_ctrl,
>> + CPU_REGS_PROC_CTRL, ACP_CACHE_MASK, value);
>> +}
>> +
>> +static void sparx5_set_delay(struct sdhci_host *host, u8 value)
>> +{
>> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
>> + struct sdhci_sparx5_data *sdhci_sparx5 = sdhci_pltfm_priv(pltfm_host);
>> +
>> + pr_debug("%s: Set DLY_CC = %u\n", mmc_hostname(host->mmc), value);
>> +
>> + /* Update DLY_CC in HW */
>> + regmap_update_bits(sdhci_sparx5->cpu_ctrl,
>> + CPU_REGS_GENERAL_CTRL,
>> + MSHC_DLY_CC_MASK,
>> + (value << MSHC_DLY_CC_SHIFT));
>> +}
>> +
>> +static void sdhci_sparx5_set_emmc(struct sdhci_host *host)
>> +{
>> + if (!mmc_card_is_removable(host->mmc)) {
>> + u8 value;
>> +
>> + value = sdhci_readb(host, MSHC2_EMMC_CTRL);
>> + if (!(value & MSHC2_EMMC_CTRL_IS_EMMC)) {
>> + pr_debug("Get EMMC_CTRL: 0x%08x\n", value);
>> + value |= MSHC2_EMMC_CTRL_IS_EMMC;
>> + pr_debug("Set EMMC_CTRL: 0x%08x\n", value);
>> + sdhci_writeb(host, value, MSHC2_EMMC_CTRL);
>> + }
>> + }
>> +}
>> +
>> +static void sdhci_sparx5_reset_emmc(struct sdhci_host *host)
>> +{
>> + u8 value;
>> +
>> + pr_debug("Toggle EMMC_CTRL.EMMC_RST_N\n");
>> + value = sdhci_readb(host, MSHC2_EMMC_CTRL) &
>> + ~MSHC2_EMMC_CTRL_EMMC_RST_N;
>> + sdhci_writeb(host, value, MSHC2_EMMC_CTRL);
>> + /* For eMMC, minimum is 1us but give it 10us for good measure */
>> + udelay(10);
>> + sdhci_writeb(host, value | MSHC2_EMMC_CTRL_EMMC_RST_N,
>> + MSHC2_EMMC_CTRL);
>> + /* For eMMC, minimum is 200us but give it 300us for good measure */
>> + udelay(300);
>
> usleep_range() is better here
>
Got it.
>> +}
>> +
>> +static void sdhci_sparx5_reset(struct sdhci_host *host, u8 mask)
>> +{
>> + pr_debug("*** RESET: mask %d\n", mask);
>> +
>> + sdhci_reset(host, mask);
>> +
>> + /* Be sure CARD_IS_EMMC stays set */
>> + sdhci_sparx5_set_emmc(host);
>> +}
>> +
>> +static const struct sdhci_ops sdhci_sparx5_ops = {
>> +#if defined(TRACE_REGISTER)
>> + .write_l = sdhci_sparx5_writel,
>> + .write_w = sdhci_sparx5_writew,
>> + .write_b = sdhci_sparx5_writeb,
>> +#endif
>> + .set_clock = sdhci_set_clock,
>> + .set_bus_width = sdhci_set_bus_width,
>> + .set_uhs_signaling = sdhci_set_uhs_signaling,
>> + .get_max_clock = sdhci_pltfm_clk_get_max_clock,
>> + .reset = sdhci_sparx5_reset,
>> + .adma_write_desc = sdhci_sparx5_adma_write_desc,
>> +};
>> +
>> +static const struct sdhci_pltfm_data sdhci_sparx5_pdata = {
>> + .quirks = 0,
>> + .quirks2 = SDHCI_QUIRK2_HOST_NO_CMD23 | /* Card quirk */
>
> If this is a card quirk then it should be in drivers/mmc/core/quirks.h not here.
Yes, its supposedly a card quirk. I'll see to use the card quirks
methods in place.
>
>> + SDHCI_QUIRK2_NO_1_8_V, /* No sdr104, ddr50, etc */
>> + .ops = &sdhci_sparx5_ops,
>> +};
>> +
>> +static ssize_t sparx5_delay_clock_show(struct device *dev,
>> + struct device_attribute *attr,
>> + char *buf)
>> +{
>> + struct sdhci_sparx5_data *sdhci_sparx5;
>> +
>> + sdhci_sparx5 = container_of(attr, struct sdhci_sparx5_data,
>> + dev_delay_clock);
>> + return scnprintf(buf, PAGE_SIZE, "%d\n", sdhci_sparx5->delay_clock);
>> +}
>> +
>> +static ssize_t sparx5_delay_clock_store(struct device *dev,
>> + struct device_attribute *attr,
>> + const char *buf, size_t count)
>> +{
>> + unsigned int delay_clock;
>> + struct sdhci_sparx5_data *sdhci_sparx5;
>> +
>> + sdhci_sparx5 = container_of(attr, struct sdhci_sparx5_data,
>> + dev_delay_clock);
>> +
>> + if (kstrtoint(buf, 10, &delay_clock) ||
>> + delay_clock > MSHC_DLY_CC_MAX) {
>> + dev_err(dev, "sdhci-of-sparx5: wrong parameter format.\n");
>> + return -EINVAL;
>> + }
>> +
>> + sdhci_sparx5->delay_clock = delay_clock;
>> + sparx5_set_delay(sdhci_sparx5->host, sdhci_sparx5->delay_clock);
>> +
>> + return strlen(buf);
>> +}
>> +
>> +int sdhci_sparx5_probe(struct platform_device *pdev)
>> +{
>> + int ret;
>> + const char *syscon = "microchip,sparx5-cpu-syscon";
>> + struct sdhci_host *host;
>> + struct sdhci_pltfm_host *pltfm_host;
>> + struct sdhci_sparx5_data *sdhci_sparx5;
>> + struct device_node *np = pdev->dev.of_node;
>> + u32 value;
>> + u32 extra;
>> +
>> + host = sdhci_pltfm_init(pdev, &sdhci_sparx5_pdata,
>> + sizeof(*sdhci_sparx5));
>> +
>> + if (IS_ERR(host))
>> + return PTR_ERR(host);
>> +
>> + /*
>> + * extra adma table cnt for cross 128M boundary handling.
>> + */
>> + extra = DIV_ROUND_UP_ULL(dma_get_required_mask(&pdev->dev), SZ_128M);
>> + if (extra > SDHCI_MAX_SEGS)
>> + extra = SDHCI_MAX_SEGS;
>> + host->adma_table_cnt += extra;
>> +
>> + pltfm_host = sdhci_priv(host);
>> + sdhci_sparx5 = sdhci_pltfm_priv(pltfm_host);
>> + sdhci_sparx5->host = host;
>> +
>> + pltfm_host->clk = devm_clk_get(&pdev->dev, "core");
>> + if (IS_ERR(pltfm_host->clk)) {
>> + ret = PTR_ERR(pltfm_host->clk);
>> + dev_err(&pdev->dev, "failed to get core clk: %d\n", ret);
>> + goto free_pltfm;
>> + }
>> + ret = clk_prepare_enable(pltfm_host->clk);
>> + if (ret)
>> + goto free_pltfm;
>> +
>> + if (!of_property_read_u32(np, "microchip,clock-delay", &value) &&
>> + value <= MSHC_DLY_CC_MAX)
>> + sdhci_sparx5->delay_clock = value;
>> + else
>> + sdhci_sparx5->delay_clock = -1; /* Autotune */
>> +
>> + /* Sysfs delay_clock interface */
>> + sdhci_sparx5->dev_delay_clock.show = sparx5_delay_clock_show;
>> + sdhci_sparx5->dev_delay_clock.store = sparx5_delay_clock_store;
>> + sysfs_attr_init(&sdhci_sparx5->dev_delay_clock.attr);
>> + sdhci_sparx5->dev_delay_clock.attr.name = "delay_clock";
>> + sdhci_sparx5->dev_delay_clock.attr.mode = 0644;
>> + ret = device_create_file(&pdev->dev, &sdhci_sparx5->dev_delay_clock);
>
> Why is this needed? It seems doubtful that user space knows what value to
> put here if neither the board information nor the driver have that information.
The interface was provided to do tuning with a scope attached. As it is
not a requirement, I'll remove it.
>
>> + if (ret)
>> + dev_err(&pdev->dev, "failure creating '%s' device file",
>> + sdhci_sparx5->dev_delay_clock.attr.name);
>> +
>> + sdhci_get_of_property(pdev);
>> +
>> + ret = mmc_of_parse(host->mmc);
>> + if (ret)
>> + goto err_clk;
>> +
>> + sdhci_sparx5->cpu_ctrl = syscon_regmap_lookup_by_compatible(syscon);
>> + if (IS_ERR(sdhci_sparx5->cpu_ctrl)) {
>> + dev_err(&pdev->dev, "No CPU syscon regmap !\n");
>> + ret = PTR_ERR(sdhci_sparx5->cpu_ctrl);
>> + goto err_clk;
>> + }
>> +
>> + if (sdhci_sparx5->delay_clock >= 0)
>> + sparx5_set_delay(host, sdhci_sparx5->delay_clock);
>> +
>> + if (!mmc_card_is_removable(host->mmc)) {
>> + /* Do a HW reset of eMMC card */
>> + sdhci_sparx5_reset_emmc(host);
>> + /* Update EMMC_CTRL */
>> + sdhci_sparx5_set_emmc(host);
>> + /* If eMMC, disable SD and SDIO */
>> + host->mmc->caps2 |= (MMC_CAP2_NO_SDIO|MMC_CAP2_NO_SD);
>> + }
>> +
>> + /* Enable v4 mode */
>> + //sdhci_enable_v4_mode(host);
>
> No commented out code please.
I'll remove this.
>
>> +
>> + ret = sdhci_add_host(host);
>> + if (ret)
>> + dev_err(&pdev->dev, "sdhci_add_host() failed (%d)\n", ret);
>> +
>> + /* Set AXI bus master to use un-cached access (for DMA) */
>> + if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA) &&
>> + IS_ENABLED(CONFIG_DMA_DECLARE_COHERENT))
>> + sparx5_set_cacheable(host, ACP_CACHE_FORCE_ENA);
>> +
>> + pr_debug("SDHC version: 0x%08x\n", sdhci_readl(host, MSHC2_VERSION));
>> + pr_debug("SDHC type: 0x%08x\n", sdhci_readl(host, MSHC2_TYPE));
>> +
>> + return ret;
>> +
>> +err_clk:
>> + clk_disable_unprepare(pltfm_host->clk);
>> +free_pltfm:
>> + sdhci_pltfm_free(pdev);
>> + return ret;
>> +}
>> +
>> +static const struct of_device_id sdhci_sparx5_of_match[] = {
>> + { .compatible = "microchip,dw-sparx5-sdhci" },
>> + { }
>> +};
>> +MODULE_DEVICE_TABLE(of, sdhci_sparx5_of_match);
>> +
>> +static struct platform_driver sdhci_sparx5_driver = {
>> + .driver = {
>> + .name = "sdhci-sparx5",
>> + .of_match_table = sdhci_sparx5_of_match,
>> + .pm = &sdhci_pltfm_pmops,
>> + },
>> + .probe = sdhci_sparx5_probe,
>> + .remove = sdhci_pltfm_unregister,
>> +};
>> +
>> +module_platform_driver(sdhci_sparx5_driver);
>> +
>> +MODULE_DESCRIPTION("Sparx5 SDHCI OF driver");
>> +MODULE_AUTHOR("Lars Povlsen <lars.povlsen@microchip.com>");
>> +MODULE_LICENSE("GPL v2");
>> --
>> 2.26.2
>>
Thank you very much for your comments, I will make the suggested changes
and submit an new series asap.
--
Lars Povlsen,
Microchip
^ permalink raw reply
* Re: [PATCH 03/17] ARM: dts: r8a7742: Add I2C and IIC support
From: Lad, Prabhakar @ 2020-05-18 8:58 UTC (permalink / raw)
To: Wolfram Sang
Cc: Lad Prabhakar, Geert Uytterhoeven, Jens Axboe, Rob Herring,
Ulf Hansson, Sergei Shtylyov, David S. Miller, Wim Van Sebroeck,
Guenter Roeck, linux-ide,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, LKML,
linux-i2c, Linux MMC List, netdev, Linux-Renesas, linux-watchdog
In-Reply-To: <20200515171031.GB19423@ninjato>
Hi Wolfram,
Thank for the review.
On Fri, May 15, 2020 at 6:10 PM Wolfram Sang
<wsa+renesas@sang-engineering.com> wrote:
>
> On Fri, May 15, 2020 at 04:08:43PM +0100, Lad Prabhakar wrote:
> > Add the I2C[0-3] and IIC[0-3] devices nodes to the R8A7742 device tree.
> >
> > Automatic transmission for PMIC control is not available on IIC3 hence
> > compatible string "renesas,rcar-gen2-iic" and "renesas,rmobile-iic" is
> > not added to iic3 node.
>
> Makes sense.
>
> However, both versions (with and without automatic transmission) are
> described with the same "renesas,iic-r8a7742" compatible. Is it possible
> to detect the reduced variant at runtime somehow?
>
I couldn't find anything the manual that would be useful to detect at runtime.
> My concern is that the peculiarity of this SoC might be forgotten if we
> describe it like this and ever add "automatic transmissions" somewhen.
>
Agreed.
Cheers,
--Prabhakar
^ permalink raw reply
* RE: [PATCH] dt-bindings: reset: Convert i.MX reset to json-schema
From: Aisheng Dong @ 2020-05-18 9:07 UTC (permalink / raw)
To: Anson Huang, p.zabel@pengutronix.de, robh+dt@kernel.org,
shawnguo@kernel.org, s.hauer@pengutronix.de,
kernel@pengutronix.de, festevam@gmail.com,
devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
Cc: dl-linux-imx
In-Reply-To: <1589250194-29441-1-git-send-email-Anson.Huang@nxp.com>
> From: Anson Huang <Anson.Huang@nxp.com>
> Sent: Tuesday, May 12, 2020 10:23 AM
>
> Convert the i.MX reset binding to DT schema format using json-schema.
>
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
> ---
> .../devicetree/bindings/reset/fsl,imx-src.txt | 49 ------------------
> .../devicetree/bindings/reset/fsl,imx-src.yaml | 58
> ++++++++++++++++++++++
> 2 files changed, 58 insertions(+), 49 deletions(-) delete mode 100644
> Documentation/devicetree/bindings/reset/fsl,imx-src.txt
> create mode 100644
> Documentation/devicetree/bindings/reset/fsl,imx-src.yaml
>
> diff --git a/Documentation/devicetree/bindings/reset/fsl,imx-src.txt
> b/Documentation/devicetree/bindings/reset/fsl,imx-src.txt
> deleted file mode 100644
> index 6ed79e6..0000000
> --- a/Documentation/devicetree/bindings/reset/fsl,imx-src.txt
> +++ /dev/null
> @@ -1,49 +0,0 @@
> -Freescale i.MX System Reset Controller
> -======================================
> -
> -Please also refer to reset.txt in this directory for common reset -controller
> binding usage.
> -
> -Required properties:
> -- compatible: Should be "fsl,<chip>-src"
> -- reg: should be register base and length as documented in the
> - datasheet
> -- interrupts: Should contain SRC interrupt and CPU WDOG interrupt,
> - in this order.
> -- #reset-cells: 1, see below
> -
> -example:
> -
> -src: src@20d8000 {
> - compatible = "fsl,imx6q-src";
> - reg = <0x020d8000 0x4000>;
> - interrupts = <0 91 0x04 0 96 0x04>;
> - #reset-cells = <1>;
> -};
> -
> -Specifying reset lines connected to IP modules
> -==============================================
> -
> -The system reset controller can be used to reset the GPU, VPU, -IPU, and
> OpenVG IP modules on i.MX5 and i.MX6 ICs. Those device -nodes should
> specify the reset line on the SRC in their resets -property, containing a phandle
> to the SRC device node and a -RESET_INDEX specifying which module to reset,
> as described in -reset.txt
> -
> -example:
> -
> - ipu1: ipu@2400000 {
> - resets = <&src 2>;
> - };
> - ipu2: ipu@2800000 {
> - resets = <&src 4>;
> - };
> -
> -The following RESET_INDEX values are valid for i.MX5:
> -GPU_RESET 0
> -VPU_RESET 1
> -IPU1_RESET 2
> -OPEN_VG_RESET 3
> -The following additional RESET_INDEX value is valid for i.MX6:
> -IPU2_RESET 4
> diff --git a/Documentation/devicetree/bindings/reset/fsl,imx-src.yaml
> b/Documentation/devicetree/bindings/reset/fsl,imx-src.yaml
> new file mode 100644
> index 0000000..276a533
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/reset/fsl,imx-src.yaml
> @@ -0,0 +1,58 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
> +---
> +title: Freescale i.MX System Reset Controller
> +
> +maintainers:
> + - Philipp Zabel <p.zabel@pengutronix.de>
> +
> +description: |
> + The system reset controller can be used to reset the GPU, VPU,
> + IPU, and OpenVG IP modules on i.MX5 and i.MX6 ICs. Those device
> + nodes should specify the reset line on the SRC in their resets
> + property, containing a phandle to the SRC device node and a
> + RESET_INDEX specifying which module to reset, as described in
> + reset.txt
> +
> + The following RESET_INDEX values are valid for i.MX5:
> + GPU_RESET 0
> + VPU_RESET 1
> + IPU1_RESET 2
> + OPEN_VG_RESET 3
> + The following additional RESET_INDEX value is valid for i.MX6:
> + IPU2_RESET 4
> +
> +properties:
> + compatible:
> + items:
> + - const: "fsl,imx51-src"
What about mx6?
> +
> + reg:
> + maxItems: 1
> +
> + interrupts:
Need description here
> + minItems: 1
> + maxItems: 2
> +
> + '#reset-cells':
> + const: 1
> +
> +required:
> + - compatible
> + - reg
> + - interrupts
> + - '#reset-cells'
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + src@73fd0000 {
s/src/reset-controller
Regards
Aisheng
> + compatible = "fsl,imx51-src";
> + reg = <0x73fd0000 0x4000>;
> + interrupts = <75>;
> + #reset-cells = <1>;
> + };
> --
> 2.7.4
^ permalink raw reply
* RE: [PATCH 1/2] ARM: dts: imx51: Add src node interrupt
From: Aisheng Dong @ 2020-05-18 9:09 UTC (permalink / raw)
To: Anson Huang, robh+dt@kernel.org, shawnguo@kernel.org,
s.hauer@pengutronix.de, kernel@pengutronix.de, festevam@gmail.com,
devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
Cc: dl-linux-imx
In-Reply-To: <1589250307-29662-1-git-send-email-Anson.Huang@nxp.com>
> From: Anson Huang <Anson.Huang@nxp.com>
> Sent: Tuesday, May 12, 2020 10:25 AM
>
> Interrupt is a required property according to SRC binding, add it for SRC node.
>
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
Reviewed-by: Dong Aisheng <aisheng.dong@nxp.com>
Regards
Aisheng
> ---
> arch/arm/boot/dts/imx51.dtsi | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi index
> 92fbb90..3f1e913 100644
> --- a/arch/arm/boot/dts/imx51.dtsi
> +++ b/arch/arm/boot/dts/imx51.dtsi
> @@ -442,6 +442,7 @@
> src: src@73fd0000 {
> compatible = "fsl,imx51-src";
> reg = <0x73fd0000 0x4000>;
> + interrupts = <75>;
> #reset-cells = <1>;
> };
>
> --
> 2.7.4
^ permalink raw reply
* RE: [PATCH 2/2] ARM: dts: imx53: Add src node interrupt
From: Aisheng Dong @ 2020-05-18 9:10 UTC (permalink / raw)
To: Anson Huang, robh+dt@kernel.org, shawnguo@kernel.org,
s.hauer@pengutronix.de, kernel@pengutronix.de, festevam@gmail.com,
devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
Cc: dl-linux-imx
In-Reply-To: <1589250307-29662-2-git-send-email-Anson.Huang@nxp.com>
> From: Anson Huang <Anson.Huang@nxp.com>
> Sent: Tuesday, May 12, 2020 10:25 AM
>
> Interrupt is a required property according to SRC binding, add it for SRC node.
>
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
Reviewed-by: Dong Aisheng <aisheng.dong@nxp.com>
Regards
Aisheng
> ---
> arch/arm/boot/dts/imx53.dtsi | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi index
> 8536f59..0d06dbd 100644
> --- a/arch/arm/boot/dts/imx53.dtsi
> +++ b/arch/arm/boot/dts/imx53.dtsi
> @@ -591,6 +591,7 @@
> src: src@53fd0000 {
> compatible = "fsl,imx53-src", "fsl,imx51-src";
> reg = <0x53fd0000 0x4000>;
> + interrupts = <75>;
> #reset-cells = <1>;
> };
>
> --
> 2.7.4
^ permalink raw reply
* Re: [PATCH v2 2/7] ASoC: qcom: Add common array to initialize soc based core clocks
From: Srinivas Kandagatla @ 2020-05-18 9:11 UTC (permalink / raw)
To: Ajit Pandey, broonie, plai, bgoswami; +Cc: alsa-devel, devicetree, linux-kernel
On 14/05/2020 17:38, Ajit Pandey wrote:
> AHB-I/X bus clocks inside LPASS coreis not a mandatory clocks for
> SC7180 soc lpass variants, hence make it an optional one.
>
> Signed-off-by: Ajit Pandey <ajitp@codeaurora.org>
> ---
For some reason patch subject seems messed up!
I see two patches with same subject "[PATCH v2 2/7] ASoC: qcom: Add
common array to initialize soc based core clocks" and totally different
content and PATCH v2 3/7 is missing as well!
--srini
> sound/soc/qcom/lpass-cpu.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
> index e00a4af..729ca78 100644
> --- a/sound/soc/qcom/lpass-cpu.c
> +++ b/sound/soc/qcom/lpass-cpu.c
> @@ -594,7 +594,7 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
> }
> }
>
> - drvdata->ahbix_clk = devm_clk_get(dev, "ahbix-clk");
> + drvdata->ahbix_clk = devm_clk_get_optional(dev, "ahbix-clk");
> if (IS_ERR(drvdata->ahbix_clk)) {
> dev_err(dev, "error getting ahbix-clk: %ld\n",
> PTR_ERR(drvdata->ahbix_clk));
>
^ permalink raw reply
* Re: [PATCH 17/17] ARM: dts: r8a7742: Add RWDT node
From: Lad, Prabhakar @ 2020-05-18 9:16 UTC (permalink / raw)
To: Wolfram Sang
Cc: Lad Prabhakar, Geert Uytterhoeven, Jens Axboe, Rob Herring,
Wolfram Sang, Ulf Hansson, Sergei Shtylyov, David S. Miller,
Wim Van Sebroeck, Guenter Roeck, linux-ide,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, LKML,
linux-i2c, Linux MMC List, netdev, Linux-Renesas, linux-watchdog
In-Reply-To: <20200517210837.GL1370@kunai>
[-- Attachment #1: Type: text/plain, Size: 1211 bytes --]
Hi Wolfram,
On Sun, May 17, 2020 at 10:08 PM Wolfram Sang <wsa@the-dreams.de> wrote:
>
> On Fri, May 15, 2020 at 04:08:57PM +0100, Lad Prabhakar wrote:
> > Add a device node for the Watchdog Timer (RWDT) controller on the Renesas
> > RZ/G1H (r8a7742) SoC.
> >
> > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > Reviewed-by: Marian-Cristian Rotariu <marian-cristian.rotariu.rb@bp.renesas.com>
>
> The DTS change looks fine, I checked it against similar SoCs (like the
> previous patched). So, for that:
>
> Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
>
Thank you for review.
> However, just to make sure, have you checked the WDT (especially reboot)
> with SMP and multiple CPU cores enabled? Some early Gen2 SoCs had issues
> there.
>
Its similar to as seen on Rcar-H2 where just the A15 cores are up and
A7 cores fail to boot. Attached is the boot log where reboot works as
expected with all A15 core up. Although I have tested the internal
release based on 3.10 where all the cores are up which used bootarg
apmu=multicluster (https://patchwork.kernel.org/patch/3948791/). So
there is some work involved to get all the A7's up and running.
Cheers,
--Prabhakar
[-- Attachment #2: log.txt --]
[-- Type: text/plain, Size: 25436 bytes --]
iW-RainboW-G21M SPI_LOADER V0.31 2015.11.10
DEVICE SST25VF016B
U-Boot 2013.01.01-gcb82c56-dirty (Aug 18 2016 - 10:13:48)
CPU: Renesas Electronics R8A7742 rev 3.0
Board: RZ/G1H iW-RainboW-G21M-Q7
DRAM: 2 GiB
MMC: sh-sdhi: 0, sh_mmcif: 1
SF: Detected SST25VF016B with page size 4 KiB, total 2 MiB
In: serial
Out: serial
Err: serial
Board Info:
BSP Version : iW-PREXZ-SC-01-R2.0-REL1.0-Linux3.10.31
SOM Version : iW-PREXZ-AP-01-R2.0
Net: ether_avb
Hit any key to stop autoboot: 0
iWave-G21M >boot
ether_avb Waiting for PHY auto negotiation to complete... done
ether_avb: 1000Base /Full
BOOTP broadcast 1
BOOTP broadcast 2
DHCP client bound to address 192.168.10.10
ether_avb:3 is connected to ether_avb. Reconnecting to ether_avb
ether_avb Waiting for PHY auto negotiation to complete... done
ether_avb: 1000Base /Full
Using ether_avb device
TFTP from server 192.168.10.1; our IP address is 192.168.10.10
Filename 'g1h/uImage'.
Load address: 0x40007fc0
Loading: T #################################################################
#################################################################
#################################################################
#################################################################
#################################################################
###########
647.5 KiB/s
done
Bytes transferred = 4927976 (4b31e8 hex)
ether_avb:3 is connected to ether_avb. Reconnecting to ether_avb
ether_avb Waiting for PHY auto negotiation to complete... done
ether_avb: 1000Base /Full
Using ether_avb device
TFTP from server 192.168.10.1; our IP address is 192.168.10.10
Filename 'g1h/r8a7742-iwg21d-q7.dtb'.
Load address: 0x40f00000
Loading: T ###
4.9 KiB/s
done
Bytes transferred = 29675 (73eb hex)
## Booting kernel from Legacy Image at 40007fc0 ...
Image Name: Linux-5.7.0-rc3-00058-g857bcc07a
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 4927912 Bytes = 4.7 MiB
Load Address: 40008000
Entry Point: 40008000
Verifying Checksum ... OK
## Flattened Device Tree blob at 40f00000
Booting using the fdt blob at 0x40f00000
XIP Kernel Image ... OK
OK
Loading Device Tree to 41ef5000, end 41eff3ea ... OK
Unable to update property <NULL>:mac-address, err=FDT_ERR_BADPATH
Unable to update property <NULL>:local-mac-address, err=FDT_ERR_BADPATH
Unable to update property <NULL>:mac-address, err=FDT_ERR_BADPATH
Unable to update property <NULL>:local-mac-address, err=FDT_ERR_BADPATH
Unable to update property /iwg21m_q7_common:som-rev, err=FDT_ERR_NOTFOUND
Unable to update property /iwg21m_q7_common:vin0-ov5640, err=FDT_ERR_NOTFOUND
Unable to update property /iwg21m_q7_common:vin1-ov5640, err=FDT_ERR_NOTFOUND
Unable to update property /iwg21m_q7_common:vin2-ov5640, err=FDT_ERR_NOTFOUND
Unable to update property /iwg21m_q7_common:vin3-ov5640, err=FDT_ERR_NOTFOUND
Unable to update property /iwg21m_q7_common:vin0-status, err=FDT_ERR_NOTFOUND
Unable to update property /ethernet@e6800000:status, err=FDT_ERR_NOTFOUND
Unable to update property /pfc@e6060000:pinctrl-1, err=FDT_ERR_NOTFOUND
Unable to update property /pfc@e6060000:pinctrl-2, err=FDT_ERR_NOTFOUND
Starting kernel ...
[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Linux version 5.7.0-rc3-00058-g857bcc07ad1e-dirty (prasmi@prasmi) (gcc version 7.5.0 (Ubuntu/Linaro 7.5.0-3ubuntu1~18.04), GNU ld (GNU Binutils for Ubuntu) 2.30) #223 SMP Fri May 15 18:11:09 0
[ 0.000000] CPU: ARMv7 Processor [413fc0f2] revision 2 (ARMv7), cr=10c5387d
[ 0.000000] CPU: div instructions available: patching division code
[ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, PIPT instruction cache
[ 0.000000] OF: fdt: Machine model: iWave Systems RainboW-G21D-Qseven board based on RZ/G1H
[ 0.000000] OF: fdt: Ignoring memory block 0x200000000 - 0x240000000
[ 0.000000] printk: debug: ignoring loglevel setting.
[ 0.000000] Memory policy: Data cache writealloc
[ 0.000000] cma: Reserved 256 MiB at 0x70000000
[ 0.000000] cma: Reserved 64 MiB at 0x6c000000
[ 0.000000] On node 0 totalpages: 262144
[ 0.000000] Normal zone: 1264 pages used for memmap
[ 0.000000] Normal zone: 0 pages reserved
[ 0.000000] Normal zone: 161792 pages, LIFO batch:31
[ 0.000000] HighMem zone: 100352 pages, LIFO batch:31
[ 0.000000] percpu: Embedded 19 pages/cpu s47500 r8192 d22132 u77824
[ 0.000000] pcpu-alloc: s47500 r8192 d22132 u77824 alloc=19*4096
[ 0.000000] pcpu-alloc: [0] 0 [0] 1 [0] 2 [0] 3 [0] 4 [0] 5 [0] 6 [0] 7
[ 0.000000] Built 1 zonelists, mobility grouping on. Total pages: 260880
[ 0.000000] Kernel command line: console=ttySC2,115200n8 earlyprintk ignore_loglevel ip=dhcp vmalloc=384M rw root=/dev/nfs nfsroot=192.168.10.1:/mnt/g1h,vers=4,tcp apmu=multicluster
[ 0.000000] Dentry cache hash table entries: 131072 (order: 7, 524288 bytes, linear)
[ 0.000000] Inode-cache hash table entries: 65536 (order: 6, 262144 bytes, linear)
[ 0.000000] mem auto-init: stack:off, heap alloc:off, heap free:off
[ 0.000000] Memory: 698984K/1048576K available (7168K kernel code, 645K rwdata, 2556K rodata, 1024K init, 272K bss, 21912K reserved, 327680K cma-reserved, 73728K highmem)
[ 0.000000] rcu: Hierarchical RCU implementation.
[ 0.000000] rcu: RCU event tracing is enabled.
[ 0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 10 jiffies.
[ 0.000000] NR_IRQS: 16, nr_irqs: 16, preallocated irqs: 16
[ 0.000000] random: get_random_bytes called from start_kernel+0x298/0x490 with crng_init=0
[ 0.000000] arch_timer: cp15 timer(s) running at 10.00MHz (virt).
[ 0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0x24e6a1710, max_idle_ns: 440795202120 ns
[ 0.000004] sched_clock: 56 bits at 10MHz, resolution 100ns, wraps every 4398046511100ns
[ 0.000013] Switching to timer-based delay loop, resolution 100ns
[ 0.000351] Console: colour dummy device 80x30
[ 0.000382] Calibrating delay loop (skipped), value calculated using timer frequency.. 20.00 BogoMIPS (lpj=100000)
[ 0.000392] pid_max: default: 32768 minimum: 301
[ 0.000535] Mount-cache hash table entries: 2048 (order: 1, 8192 bytes, linear)
[ 0.000548] Mountpoint-cache hash table entries: 2048 (order: 1, 8192 bytes, linear)
[ 0.001015] CPU: Testing write buffer coherency: ok
[ 0.001041] CPU0: Spectre v2: firmware did not set auxiliary control register IBE bit, system vulnerable
[ 0.001241] cpu_capacity: missing /cpus/cpu@100 raw capacity
[ 0.001248] cpu_capacity: partial information: fallback to 1024 for all CPUs
[ 0.001303] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
[ 0.001919] Setting up static identity map for 0x40100000 - 0x40100060
[ 0.001995] rcu: Hierarchical SRCU implementation.
[ 0.002261] Detected Renesas RZ/G1 r8a7742 ES3.0
[ 0.002838] smp: Bringing up secondary CPUs ...
[ 0.005006] CPU1: thread -1, cpu 1, socket 0, mpidr 80000001
[ 0.005015] CPU1: Spectre v2: firmware did not set auxiliary control register IBE bit, system vulnerable
[ 0.006100] CPU2: thread -1, cpu 2, socket 0, mpidr 80000002
[ 0.006109] CPU2: Spectre v2: firmware did not set auxiliary control register IBE bit, system vulnerable
[ 0.007200] CPU3: thread -1, cpu 3, socket 0, mpidr 80000003
[ 0.007209] CPU3: Spectre v2: firmware did not set auxiliary control register IBE bit, system vulnerable
[ 0.007948] CPU4: failed to boot: -22
[ 0.008699] CPU5: failed to boot: -22
[ 0.009446] CPU6: failed to boot: -22
[ 0.010236] CPU7: failed to boot: -22
[ 0.010372] smp: Brought up 1 node, 4 CPUs
[ 0.010380] SMP: Total of 4 processors activated (80.00 BogoMIPS).
[ 0.010387] CPU: All CPU(s) started in SVC mode.
[ 0.010974] devtmpfs: initialized
[ 0.015160] VFP support v0.3: implementor 41 architecture 4 part 30 variant f rev 0
[ 0.015384] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
[ 0.015399] futex hash table entries: 2048 (order: 5, 131072 bytes, linear)
[ 0.020137] pinctrl core: initialized pinctrl subsystem
[ 0.020788] thermal_sys: Registered thermal governor 'step_wise'
[ 0.021194] NET: Registered protocol family 16
[ 0.022202] DMA: preallocated 256 KiB pool for atomic coherent allocations
[ 0.022985] No ATAGs?
[ 0.023081] hw-breakpoint: found 5 (+1 reserved) breakpoint and 4 watchpoint registers.
[ 0.023091] hw-breakpoint: maximum watchpoint size is 8 bytes.
[ 0.025378] sh-pfc e6060000.pin-controller: r8a77420_pfc support registered
[ 0.041108] vgaarb: loaded
[ 0.041366] SCSI subsystem initialized
[ 0.041515] libata version 3.00 loaded.
[ 0.041660] usbcore: registered new interface driver usbfs
[ 0.041694] usbcore: registered new interface driver hub
[ 0.041784] usbcore: registered new device driver usb
[ 0.042248] mc: Linux media interface: v0.10
[ 0.042274] videodev: Linux video capture interface: v2.00
[ 0.042328] pps_core: LinuxPPS API ver. 1 registered
[ 0.042335] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
[ 0.042350] PTP clock support registered
[ 0.042881] Advanced Linux Sound Architecture Driver Initialized.
[ 0.043502] clocksource: Switched to clocksource arch_sys_counter
[ 0.622434] NET: Registered protocol family 2
[ 0.622767] tcp_listen_portaddr_hash hash table entries: 512 (order: 0, 6144 bytes, linear)
[ 0.622787] TCP established hash table entries: 8192 (order: 3, 32768 bytes, linear)
[ 0.622834] TCP bind hash table entries: 8192 (order: 4, 65536 bytes, linear)
[ 0.622924] TCP: Hash tables configured (established 8192 bind 8192)
[ 0.623017] UDP hash table entries: 512 (order: 2, 16384 bytes, linear)
[ 0.623043] UDP-Lite hash table entries: 512 (order: 2, 16384 bytes, linear)
[ 0.623183] NET: Registered protocol family 1
[ 0.623550] RPC: Registered named UNIX socket transport module.
[ 0.623558] RPC: Registered udp transport module.
[ 0.623564] RPC: Registered tcp transport module.
[ 0.623570] RPC: Registered tcp NFSv4.1 backchannel transport module.
[ 0.623580] PCI: CLS 0 bytes, default 64
[ 0.624215] hw perfevents: enabled with armv7_cortex_a15 PMU driver, 7 counters available
[ 0.624391] hw perfevents: /pmu-1: failed to probe PMU!
[ 0.624401] hw perfevents: /pmu-1: failed to register PMU devices!
[ 0.625672] workingset: timestamp_bits=30 max_order=18 bucket_order=0
[ 0.626110] NFS: Registering the id_resolver key type
[ 0.626134] Key type id_resolver registered
[ 0.626140] Key type id_legacy registered
[ 0.626153] nfs4filelayout_init: NFSv4 File Layout Driver Registering...
[ 0.626244] bounce: pool size: 64 pages
[ 0.626276] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 246)
[ 0.626284] io scheduler mq-deadline registered
[ 0.626291] io scheduler kyber registered
[ 0.627694] gpio_rcar e6050000.gpio: driving 32 GPIOs
[ 0.627994] gpio_rcar e6051000.gpio: driving 30 GPIOs
[ 0.628279] gpio_rcar e6052000.gpio: driving 30 GPIOs
[ 0.628555] gpio_rcar e6053000.gpio: driving 32 GPIOs
[ 0.628829] gpio_rcar e6054000.gpio: driving 32 GPIOs
[ 0.629102] gpio_rcar e6055000.gpio: driving 32 GPIOs
[ 0.629817] pci-rcar-gen2 ee0b0000.pci: PCI: bus0 revision 11
[ 0.629931] pci-rcar-gen2 ee0b0000.pci: PCI host bridge to bus 0000:01
[ 0.629942] pci_bus 0000:01: root bus resource [mem 0xee0a0000-0xee0a10ff]
[ 0.629951] pci_bus 0000:01: No busn resource found for root bus, will use [bus 01-ff]
[ 0.629981] pci 0000:01:00.0: [1033:0000] type 00 class 0x060000
[ 0.630007] pci 0000:01:00.0: reg 0x10: [mem 0xee0b0800-0xee0b0bff]
[ 0.630019] pci 0000:01:00.0: reg 0x14: [mem 0x40000000-0x7fffffff pref]
[ 0.630275] pci 0000:01:01.0: [1033:0035] type 00 class 0x0c0310
[ 0.630299] pci 0000:01:01.0: reg 0x10: [mem 0x00000000-0x00000fff]
[ 0.630363] pci 0000:01:01.0: supports D1 D2
[ 0.630371] pci 0000:01:01.0: PME# supported from D0 D1 D2 D3hot
[ 0.630567] pci 0000:01:02.0: [1033:00e0] type 00 class 0x0c0320
[ 0.630590] pci 0000:01:02.0: reg 0x10: [mem 0x00000000-0x000000ff]
[ 0.630653] pci 0000:01:02.0: supports D1 D2
[ 0.630660] pci 0000:01:02.0: PME# supported from D0 D1 D2 D3hot
[ 0.631807] PCI: bus1: Fast back to back transfers disabled
[ 0.631818] pci_bus 0000:01: busn_res: [bus 01-ff] end is updated to 01
[ 0.631836] pci 0000:01:01.0: BAR 0: assigned [mem 0xee0a0000-0xee0a0fff]
[ 0.631848] pci 0000:01:02.0: BAR 0: assigned [mem 0xee0a1000-0xee0a10ff]
[ 0.631890] pci 0000:01:01.0: enabling device (0140 -> 0142)
[ 0.631926] pci 0000:01:02.0: enabling device (0140 -> 0142)
[ 0.641511] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
[ 0.642431] SuperH (H)SCI(F) driver initialized
[ 0.642848] e6c60000.serial: ttySC2 at MMIO 0xe6c60000 (irq = 76, base_baud = 0) is a scifa
[ 1.505342] printk: console [ttySC2] enabled
[ 1.510110] e6ce0000.serial: ttySC4 at MMIO 0xe6ce0000 (irq = 77, base_baud = 0) is a scifb
[ 1.523630] libphy: Fixed MDIO Bus: probed
[ 1.528035] CAN device driver interface
[ 1.533083] ravb e6800000.ethernet: no valid MAC address supplied, using a random one
[ 1.541248] libphy: ravb_mii: probed
[ 1.546374] ravb e6800000.ethernet eth0: Base address at 0xe6800000, f6:35:bc:36:75:d3, IRQ 75.
[ 1.555246] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
[ 1.561763] ehci-pci: EHCI PCI platform driver
[ 1.566336] ehci-pci 0000:01:02.0: EHCI Host Controller
[ 1.571571] ehci-pci 0000:01:02.0: new USB bus registered, assigned bus number 1
[ 1.579110] ehci-pci 0000:01:02.0: irq 107, io mem 0xee0a1000
[ 1.613503] ehci-pci 0000:01:02.0: USB 2.0 started, EHCI 1.00
[ 1.619766] hub 1-0:1.0: USB hub found
[ 1.623549] hub 1-0:1.0: 1 port detected
[ 1.627831] ehci-platform: EHCI generic platform driver
[ 1.633164] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
[ 1.639358] ohci-pci: OHCI PCI platform driver
[ 1.643889] ohci-pci 0000:01:01.0: OHCI PCI host controller
[ 1.649464] ohci-pci 0000:01:01.0: new USB bus registered, assigned bus number 2
[ 1.656934] ohci-pci 0000:01:01.0: irq 107, io mem 0xee0a0000
[ 1.754022] hub 2-0:1.0: USB hub found
[ 1.757790] hub 2-0:1.0: 1 port detected
[ 1.762044] ohci-platform: OHCI generic platform driver
[ 1.767706] xhci-hcd ee000000.usb: xHCI Host Controller
[ 1.772936] xhci-hcd ee000000.usb: new USB bus registered, assigned bus number 3
[ 1.795359] xhci-hcd ee000000.usb: hcc params 0x014051ce hci version 0x100 quirks 0x0000000000830410
[ 1.804522] xhci-hcd ee000000.usb: irq 106, io mem 0xee000000
[ 1.810914] hub 3-0:1.0: USB hub found
[ 1.814697] hub 3-0:1.0: 1 port detected
[ 1.818860] xhci-hcd ee000000.usb: xHCI Host Controller
[ 1.824096] xhci-hcd ee000000.usb: new USB bus registered, assigned bus number 4
[ 1.831487] xhci-hcd ee000000.usb: Host supports USB 3.0 SuperSpeed
[ 1.837819] usb usb4: We don't know the algorithms for LPM for this host, disabling LPM.
[ 1.846358] hub 4-0:1.0: USB hub found
[ 1.850125] hub 4-0:1.0: 1 port detected
[ 1.854508] usbcore: registered new interface driver usb-storage
[ 1.860912] renesas_usbhs e6590000.usb: host probed
[ 1.865809] renesas_usbhs e6590000.usb: no transceiver found
[ 1.871560] renesas_usbhs e6590000.usb: gadget probed
[ 1.876682] renesas_usbhs e6590000.usb: probed
[ 1.881628] i2c /dev entries driver
[ 1.885986] i2c-rcar e6530000.i2c: probed
[ 1.893044] sh_mobile_sdhi ee140000.sd: Got CD GPIO
[ 1.897963] sh_mobile_sdhi ee140000.sd: Got WP GPIO
[ 1.943520] sh_mmcif ee220000.mmc: Chip version 0x0003, clock rate 12MHz
[ 1.950761] usbcore: registered new interface driver usbhid
[ 1.956335] usbhid: USB HID core driver
[ 1.963818] sgtl5000 0-000a: sgtl5000 revision 0x11
[ 1.976816] rcar_sound ec500000.sound: probed
[ 1.981527] NET: Registered protocol family 10
[ 1.986614] Segment Routing with IPv6
[ 1.990318] sit: IPv6, IPv4 and MPLS over IPv4 tunneling driver
[ 1.996688] NET: Registered protocol family 17
[ 2.001130] can: controller area network core (rev 20170425 abi 9)
[ 2.007356] NET: Registered protocol family 29
[ 2.011794] can: raw protocol (rev 20170425)
[ 2.016066] can: broadcast manager protocol (rev 20170425 t)
[ 2.021721] can: netlink gateway (rev 20190810) max_hops=1
[ 2.027268] Key type dns_resolver registered
[ 2.031658] Registering SWP/SWPB emulation handler
[ 2.049452] renesas_irqc e61c0000.interrupt-controller: driving 4 irqs
[ 2.057368] sh_mobile_sdhi ee140000.sd: Got CD GPIO
[ 2.062267] sh_mobile_sdhi ee140000.sd: Got WP GPIO
[ 2.067350] usb 1-1: new high-speed USB device number 2 using ehci-pci
[ 2.123791] random: fast init done
[ 2.183730] sh_mobile_sdhi ee140000.sd: mmc1 base at 0xee140000, max clock rate 97 MHz
[ 2.194666] asoc-simple-card sound: sgtl5000 <-> ec500000.sound mapping ok
[ 2.263517] Micrel KSZ9031 Gigabit PHY e6800000.ethernet-ffffffff:03: attached PHY driver [Micrel KSZ9031 Gigabit PHY] (mii_bus:phy_addr=e6800000.ethernet-ffffffff:03, irq=POLL)
[ 2.284401] hub 1-1:1.0: USB hub found
[ 2.288213] hub 1-1:1.0: 2 ports detected
[ 2.461776] mmc0: new high speed MMC card at address 0001
[ 2.467624] mmcblk0: mmc0:0001 MMC04G 3.52 GiB
[ 2.472282] mmcblk0boot0: mmc0:0001 MMC04G partition 1 16.0 MiB
[ 2.478353] mmcblk0boot1: mmc0:0001 MMC04G partition 2 16.0 MiB
[ 2.486474] mmcblk0: p1
[ 6.484450] ravb e6800000.ethernet eth0: Link is Up - 1Gbps/Full - flow control off
[ 6.513521] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
[ 6.543501] Sending DHCP requests ., OK
[ 7.607358] IP-Config: Got DHCP answer from 192.168.10.1, my address is 192.168.10.131
[ 7.615282] IP-Config: Complete:
[ 7.618506] device=eth0, hwaddr=f6:35:bc:36:75:d3, ipaddr=192.168.10.131, mask=255.255.255.0, gw=192.168.10.1
[ 7.628853] host=192.168.10.131, domain=example.org, nis-domain=(none)
[ 7.635814] bootserver=192.168.10.1, rootserver=192.168.10.1, rootpath=
[ 7.635817] nameserver0=192.168.10.1
[ 7.647172] ALSA device list:
[ 7.650136] #0: rsnd-dai.0-sgtl5000
[ 7.653937] SDHI2 Vcc: disabling
[ 7.657163] SDHI2 VccQ: disabling
[ 7.689869] VFS: Mounted root (nfs4 filesystem) on device 0:14.
[ 7.696616] devtmpfs: mounted
[ 7.700259] Freeing unused kernel memory: 1024K
[ 7.753689] Run /sbin/init as init process
[ 7.757778] with arguments:
[ 7.760738] /sbin/init
[ 7.763438] earlyprintk
[ 7.766239] with environment:
[ 7.769373] HOME=/
[ 7.771726] TERM=linux
[ 7.774446] apmu=multicluster
INIT: version 2.88 booting
Framebuffer /dev/fb0 not detected
Boot splashscreen disabled
Starting udev
[ 8.419998] udevd[171]: starting version 3.2.2
[ 8.453832] random: udevd: uninitialized urandom read (16 bytes read)
[ 8.463252] random: udevd: uninitialized urandom read (16 bytes read)
[ 8.473886] random: udevd: uninitialized urandom read (16 bytes read)
[ 8.600827] udevd[172]: starting eudev-3.2.2
hwclock: can't open '/dev/misc/rtc': No such file or directory
Wed Apr 15 18:16:48 UTC 2020
hwclock: can't open '/dev/misc/rtc': No such file or directory
[ 9.714098] urandom_read: 1 callbacks suppressed
[ 9.714102] random: dd: uninitialized urandom read (512 bytes read)
INIT: Entering runlevel: 5
Configuring network interfaces... RTNETLINK answers: File exists
[ 10.051752] random: crng init done
Successfully initialized wpa_supplicant
nl80211: 'nl80211' generic netlink not found
Failed to initialize driver 'nl80211'
wlan0: Unsupported driver 'nl80211'
Cannot find device "wlan0"
ifup skipped for nfsroot interface eth0
run-parts: /etc/network/if-pre-up.d/nfsroot exited with code 1
Starting system message bus: dbus.
PVR_SRVKM_PARAMS=
Module pvrsrvkm failed to load. Retrying.
Running /sbin/depmod
[ 10.841416] Mass Storage Function, version: 2009/09/11
[ 10.846619] LUN: removable file: (no medium)
[ 10.850994] LUN: removable file: /dev/mmcblk0
[ 10.855360] Number of LUNs=1
[ 10.858338] g_mass_storage gadget: Mass Storage Gadget, version: 2009/09/11
[ 10.865462] g_mass_storage gadget: userspace failed to provide iSerialNumber
[ 10.872501] g_mass_storage gadget: g_mass_storage ready
Simple mixer control 'DVC In',0
Capabilities: cvolume
Capture channels: Front Left - Front Right
Limits: Capture 0 - 8388607
Front Left: Capture 4194304 [50%]
Front Right: Capture 4194304 [50%]
Simple mixer control 'DVC Out',0
Capabilities: pvolume
Playback channels: Front Left - Front Right
Limits: Playback 0 - 8388607
Mono:
Front Left: Playback 4194304 [50%]
Front Right: Playback 4194304 [50%]
Starting Dropbear SSH server: dropbear.
Starting rpcbind daemon...done.
Starting atd: OK
Starting bluetooth: bluetoothd.
hwclock: can't open '/dev/misc/rtc': No such file or directory
Simple mixer control 'DVC In',0
Capabilities: cvolume
Capture channels: Front Left - Front Right
Limits: Capture 0 - 8388607
Front Left: Capture 4194304 [50%]
Front Right: Capture 4194304 [50%]
Simple mixer control 'DVC Out',0
Capabilities: pvolume
Playback channels: Front Left - Front Right
Limits: Playback 0 - 8388607
Mono:
Front Left: Playback 4194304 [50%]
Front Right: Playback 4194304 [50%]
Starting PulseAudio
Simple mixer control 'PCM',0
Capabilities: pvolume
Playback channels: Front Left - Front Right
Limits: Playback 0 - 192
Mono:
Front Left: Playback 135 [70%]
Front Right: Playback 135 [70%]
Simple mixer control 'Headphone',0
Capabilities: pvolume pswitch pswitch-joined
Playback channels: Front Left - Front Right
Limits: Playback 0 - 127
Mono:
Front Left: Playback 127 [100%] [12.00dB] [on]
Front Right: Playback 127 [100%] [12.00dB] [on]
Simple mixer control 'Mic',0
Capabilities: volume volume-joined
Playback channels: Mono
Capture channels: Mono
Limits: 0 - 3
Mono: 2 [67%] [30.00dB]
/etc/rc5.d/S20pulseaudio: line 19: pulseaudio: command not found
[ ok ]rting Avahi mDNS/DNS-SD Daemon: avahi-daemon
Starting crond: OK
umount: /mnt/.psplash: not mounted.
BSP: RZG1H/iWave/2.1.4
LSI: RZG1H
Version: 2.1.4
iwg21m login: root
Simple mixer control 'DVC In',0
Capabilities: cvolume
Capture channels: Front Left - Front Right
Limits: Capture 0 - 8388607
Front Left: Capture 4194304 [50%]
Front Right: Capture 4194304 [50%]
Simple mixer control 'DVC Out',0
Capabilities: pvolume
Playback channels: Front Left - Front Right
Limits: Playback 0 - 8388607
Mono:
Front Left: Playback 4194304 [50%]
Front Right: Playback 4194304 [50%]
root@iwg21m:~#
root@iwg21m:~#
root@iwg21m:~#
root@iwg21m:~# reboot -p
Broadcast message from root@iwg21m (ttySC2) (Wed Apr 15 18:17:07 2020):
INIT: Sending processes the TERM signal
Stopping Weston
Stopping ohci-pci
rmmod: ERROR: Module ohci_pci is builtin.
Stopping ohci-hcd
rmmod: ERROR: Module ohci_hcd is builtin.
Stopping Dropbear SSH server: stopped /usr/sbin/dropbear (pid 424)
dropbear.
[ ok ]pping Avahi mDNS/DNS-SD Daemon: avahi-daemon
Stopping atd: OK
Stopping bluetooth: bluetoothd.
Stopping system message bus: dbus.
hwclock: can't open '/dev/misc/rtc': No such file or directory
Framebuffer /dev/fb0 not detected
Boot splashscreen disabled
Simple mixer control 'DVC In',0
Capabilities: cvolume
Capture channels: Front Left - Front Right
Limits: Capture 0 - 8388607
Front Left: Capture 4194304 [50%]
Front Right: Capture 4194304 [50%]
Simple mixer control 'DVC Out',0
Capabilities: pvolume
Playback channels: Front Left - Front Right
Limits: Playback 0 - 8388607
Mono:
Front Left: Playback 4194304 [50%]
Front Right: Playback 4194304 [50%]
Stoping PulseAudio
Stopping crond: OK
Stopping rpcbind daemon...
done.
modprobe: FATAL: Module dc_linuxfb not found.
Warning: Could not unload dc_linuxfb
PVRSRVDebugLogDeinitUM 973: create key failed
modprobe: FATAL: Module pvrsrvkm not found.
Couldn't unload modules
not deconfiguring network interfaces: network file systems still mounted.
Sending all processes the TERM signal...
logout
Sending all processes the KILL signal...
Unmounting remote filesystems...
Deactivating swap...
Unmounting local filesystems...
Rebooting... [ 37.924556] reboot: Restarting system
iW-RainboW-G21M SPI_LOADER V0.31 2015.11.10
DEVICE SST25VF016B
U-Boot 2013.01.01-gcb82c56-dirty (Aug 18 2016 - 10:13:48)
CPU: Renesas Electronics R8A7742 rev 3.0
Board: RZ/G1H iW-RainboW-G21M-Q7
DRAM: 2 GiB
MMC: sh-sdhi: 0, sh_mmcif: 1
SF: Detected SST25VF016B with page size 4 KiB, total 2 MiB
In: serial
Out: serial
Err: serial
Board Info:
BSP Version : iW-PREXZ-SC-01-R2.0-REL1.0-Linux3.10.31
SOM Version : iW-PREXZ-AP-01-R2.0
Net: ether_avb
Hit any key to stop autoboot: 0
iWave-G21M >
^ permalink raw reply
* Re: [PATCH v2 5/7] include: dt-bindings: sound: Add sc7180-lpass bindings header
From: Srinivas Kandagatla @ 2020-05-18 9:22 UTC (permalink / raw)
To: Ajit Pandey, broonie, plai, bgoswami; +Cc: alsa-devel, devicetree, linux-kernel
On 14/05/2020 17:38, Ajit Pandey wrote:
> Add header defining dai-id and mclk id for SC7180 lpass soc.
>
> Signed-off-by: Ajit Pandey <ajitp@codeaurora.org>
> ---
> include/dt-bindings/sound/sc7180-lpass.h | 10 ++++++++++
Why not reuse or rename include/dt-bindings/sound/apq8016-lpass.h to
include/dt-bindings/sound/lpass.h and reuse across all the LPASS variants?
--srini
> 1 file changed, 10 insertions(+)
> create mode 100644 include/dt-bindings/sound/sc7180-lpass.h
>
> diff --git a/include/dt-bindings/sound/sc7180-lpass.h b/include/dt-bindings/sound/sc7180-lpass.h
> new file mode 100644
> index 0000000..7d988f6
> --- /dev/null
> +++ b/include/dt-bindings/sound/sc7180-lpass.h
> @@ -0,0 +1,10 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef __DT_SC7180_LPASS_H
> +#define __DT_SC7180_LPASS_H
> +
> +#define MI2S_PRIMARY 0
> +#define MI2S_SECONDARY 1
> +
> +#define LPASS_MCLK0 0
> +
> +#endif /* __DT_APQ8016_LPASS_H */
>
^ permalink raw reply
* [PATCH v8 0/3] PM / AVS: SVS: Introduce SVS engine
From: Roger Lu @ 2020-05-18 9:24 UTC (permalink / raw)
To: Kevin Hilman, Rob Herring, Nicolas Boichat, Stephen Boyd
Cc: Fan Chen, HenryC Chen, YT Lee, Xiaoqing Liu, Charles Yang,
Angus Lin, Mark Rutland, Matthias Brugger, Nishanth Menon,
Roger Lu, devicetree, linux-arm-kernel, linux-mediatek,
linux-kernel, linux-pm
1. SVS driver use OPP adjust event in [1] to update OPP table voltage part.
2. SVS dts node refers to CPU opp table [2] and GPU opp table [3].
3. SVS and thermal dts use the same thermal efuse [4].
4. SVS dts needs power-domain [5][6] and PMIC regulator [7].
[1] https://patchwork.kernel.org/patch/11193513/
[2] https://patchwork.kernel.org/patch/11304935/
[3] https://patchwork.kernel.org/patch/11423009/
[4] https://patchwork.kernel.org/patch/11316495/
[5] https://lore.kernel.org/patchwork/patch/1236875/
[6] https://lore.kernel.org/patchwork/patch/1236878/
[7] https://patchwork.kernel.org/patch/11284617/
pending discussion:
- SVS sub-node architecture concern in below patch.
https://lore.kernel.org/patchwork/patch/1175994/
https://lore.kernel.org/patchwork/patch/1175994/
changes since v7:
- Add "mtk_svs.yaml" for device-tree binding document.
- Add svs_add_thermal_device_link() in driver for svs device (consumer)
to link thermal device (supplier).
- replace pm_qos_add_request() with cpu_latency_qos_add_request() for
letting CPUs leave idle-off state.
Roger Lu (3):
dt-bindings: power: avs: add mtk svs dt-bindings
arm64: dts: mt8183: add svs device information
PM / AVS: SVS: Introduce SVS engine
.../bindings/power/avs/mtk_svs.yaml | 141 ++
arch/arm64/boot/dts/mediatek/mt8183-evb.dts | 16 +
arch/arm64/boot/dts/mediatek/mt8183.dtsi | 41 +
drivers/power/avs/Kconfig | 10 +
drivers/power/avs/Makefile | 1 +
drivers/power/avs/mtk_svs.c | 2119 +++++++++++++++++
include/linux/power/mtk_svs.h | 23 +
7 files changed, 2351 insertions(+)
create mode 100644 Documentation/devicetree/bindings/power/avs/mtk_svs.yaml
create mode 100644 drivers/power/avs/mtk_svs.c
create mode 100644 include/linux/power/mtk_svs.h
^ permalink raw reply
* [PATCH v8 1/3] dt-bindings: power: avs: add mtk svs dt-bindings
From: Roger Lu @ 2020-05-18 9:24 UTC (permalink / raw)
To: Kevin Hilman, Rob Herring, Nicolas Boichat, Stephen Boyd
Cc: Fan Chen, HenryC Chen, YT Lee, Xiaoqing Liu, Charles Yang,
Angus Lin, Mark Rutland, Matthias Brugger, Nishanth Menon,
Roger Lu, devicetree, linux-arm-kernel, linux-mediatek,
linux-kernel, linux-pm
In-Reply-To: <20200518092403.22647-1-roger.lu@mediatek.com>
Document the binding for enabling mtk svs on MediaTek SoC.
Signed-off-by: Roger Lu <roger.lu@mediatek.com>
---
.../bindings/power/avs/mtk_svs.yaml | 141 ++++++++++++++++++
1 file changed, 141 insertions(+)
create mode 100644 Documentation/devicetree/bindings/power/avs/mtk_svs.yaml
diff --git a/Documentation/devicetree/bindings/power/avs/mtk_svs.yaml b/Documentation/devicetree/bindings/power/avs/mtk_svs.yaml
new file mode 100644
index 000000000000..77ab606814ce
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/avs/mtk_svs.yaml
@@ -0,0 +1,141 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/power/avs/mtk_svs.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Introduce SVS engine
+
+maintainers:
+ - Kevin Hilman <khilman@kernel.org>
+ - Nishanth Menon <nm@ti.com>
+
+description: |+
+ The SVS (Smart Voltage Scaling) engine is a piece of hardware which is
+ used to calculate optimized voltage values of several power domains,
+ e.g. CPU/GPU/CCI, according to chip process corner, temperatures,
+ and other factors. Then DVFS driver could apply those optimized voltage
+ values to reduce power consumption.
+
+properties:
+ compatible:
+ const: mediatek,mt8183-svs
+
+ reg:
+ description: Address range of the MTK SVS controller.
+ maxItems: 1
+
+ interrupts:
+ description: IRQ for the MTK SVS controller.
+ maxItems: 1
+
+ clocks:
+ description: Main clock for svs controller to work.
+
+ clock-names:
+ const: main
+
+ nvmem-cells:
+ maxItems: 2
+ description:
+ Phandle to the calibration data provided by a nvmem device.
+
+ nvmem-cell-names:
+ items:
+ - const: svs-calibration-data
+ - const: calibration-data
+
+patternProperties:
+ "^svs-(cpu-little|cpu-big|cci|gpu)$":
+ type: object
+ description:
+ Each subnode represents one SVS bank.
+ - svs-cpu-little (SVS bank device node of little CPU)
+ - svs-cpu-big (SVS bank device node of big CPU)
+ - svs-cci (SVS bank device node of CCI)
+ - svs-gpu (SVS bank device node of GPU)
+
+ properties:
+ compatible:
+ enum:
+ - mediatek,mt8183-svs-cpu-little
+ - mediatek,mt8183-svs-cpu-big
+ - mediatek,mt8183-svs-cci
+ - mediatek,mt8183-svs-gpu
+
+ power-domains:
+ description: Phandle to the associated power domain
+ maxItems: 1
+
+ operating-points-v2: true
+
+ vcpu-little-supply:
+ description: PMIC buck of little CPU
+
+ vcpu-big-supply:
+ description: PMIC buck of big CPU
+
+ vcci-supply:
+ description: PMIC buck of CCI
+
+ vgpu-spply:
+ description: PMIC buck of GPU
+
+ required:
+ - compatible
+ - operating-points-v2
+
+ additionalProperties: false
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - clock-names
+ - nvmem-cells
+ - nvmem-cell-names
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/mt8183-clk.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/power/mt8183-power.h>
+
+ svs: svs@1100b000 {
+ compatible = "mediatek,mt8183-svs";
+ reg = <0 0x1100b000 0 0x1000>;
+ interrupts = <GIC_SPI 127 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&infracfg CLK_INFRA_THERM>;
+ clock-names = "main";
+ nvmem-cells = <&svs_calibration>, <&thermal_calibration>;
+ nvmem-cell-names = "svs-calibration-data", "calibration-data";
+
+ svs_cpu_little: svs-cpu-little {
+ compatible = "mediatek,mt8183-svs-cpu-little";
+ operating-points-v2 = <&cluster0_opp>;
+ vcpu-little-supply = <&mt6358_vproc12_reg>;
+ };
+
+ svs_cpu_big: svs-cpu-big {
+ compatible = "mediatek,mt8183-svs-cpu-big";
+ operating-points-v2 = <&cluster1_opp>;
+ vcpu-big-supply = <&mt6358_vproc11_reg>;
+ };
+
+ svs_cci: svs-cci {
+ compatible = "mediatek,mt8183-svs-cci";
+ operating-points-v2 = <&cci_opp>;
+ vcci-supply = <&mt6358_vproc12_reg>;
+ };
+
+ svs_gpu: svs-gpu {
+ compatible = "mediatek,mt8183-svs-gpu";
+ power-domains = <&scpsys MT8183_POWER_DOMAIN_MFG_2D>;
+ operating-points-v2 = <&gpu_opp_table>;
+ vgpu-spply = <&mt6358_vgpu_reg>;
+ };
+ };
--
2.18.0
^ permalink raw reply related
* [PATCH v8 2/3] arm64: dts: mt8183: add svs device information
From: Roger Lu @ 2020-05-18 9:24 UTC (permalink / raw)
To: Kevin Hilman, Rob Herring, Nicolas Boichat, Stephen Boyd
Cc: Fan Chen, HenryC Chen, YT Lee, Xiaoqing Liu, Charles Yang,
Angus Lin, Mark Rutland, Matthias Brugger, Nishanth Menon,
Roger Lu, devicetree, linux-arm-kernel, linux-mediatek,
linux-kernel, linux-pm
In-Reply-To: <20200518092403.22647-1-roger.lu@mediatek.com>
add pmic/clock/irq/efuse setting in svs node
Signed-off-by: Roger Lu <roger.lu@mediatek.com>
---
arch/arm64/boot/dts/mediatek/mt8183-evb.dts | 16 ++++++++
arch/arm64/boot/dts/mediatek/mt8183.dtsi | 41 +++++++++++++++++++++
2 files changed, 57 insertions(+)
diff --git a/arch/arm64/boot/dts/mediatek/mt8183-evb.dts b/arch/arm64/boot/dts/mediatek/mt8183-evb.dts
index 1fb195c683c3..6ae1d9a1bcbf 100644
--- a/arch/arm64/boot/dts/mediatek/mt8183-evb.dts
+++ b/arch/arm64/boot/dts/mediatek/mt8183-evb.dts
@@ -231,6 +231,22 @@
};
};
+&svs_cpu_little {
+ vcpu-little-supply = <&mt6358_vproc12_reg>;
+};
+
+&svs_cpu_big {
+ vcpu-big-supply = <&mt6358_vproc11_reg>;
+};
+
+&svs_cci {
+ vcci-supply = <&mt6358_vproc12_reg>;
+};
+
+&svs_gpu {
+ vgpu-spply = <&mt6358_vgpu_reg>;
+};
+
&uart0 {
status = "okay";
};
diff --git a/arch/arm64/boot/dts/mediatek/mt8183.dtsi b/arch/arm64/boot/dts/mediatek/mt8183.dtsi
index 97863adb7bc0..6b6b8dc1824f 100644
--- a/arch/arm64/boot/dts/mediatek/mt8183.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8183.dtsi
@@ -453,6 +453,39 @@
status = "disabled";
};
+ svs: svs@1100b000 {
+ compatible = "mediatek,mt8183-svs";
+ reg = <0 0x1100b000 0 0x1000>;
+ interrupts = <GIC_SPI 127 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&infracfg CLK_INFRA_THERM>;
+ clock-names = "main";
+ nvmem-cells = <&svs_calibration>,
+ <&thermal_calibration>;
+ nvmem-cell-names = "svs-calibration-data",
+ "calibration-data";
+
+ svs_cpu_little: svs-cpu-little {
+ compatible = "mediatek,mt8183-svs-cpu-little";
+ operating-points-v2 = <&cluster0_opp>;
+ };
+
+ svs_cpu_big: svs-cpu-big {
+ compatible = "mediatek,mt8183-svs-cpu-big";
+ operating-points-v2 = <&cluster1_opp>;
+ };
+
+ svs_cci: svs-cci {
+ compatible = "mediatek,mt8183-svs-cci";
+ operating-points-v2 = <&cci_opp>;
+ };
+
+ svs_gpu: svs-gpu {
+ compatible = "mediatek,mt8183-svs-gpu";
+ power-domains = <&scpsys MT8183_POWER_DOMAIN_MFG_2D>;
+ operating-points-v2 = <&gpu_opp_table>;
+ };
+ };
+
i2c3: i2c@1100f000 {
compatible = "mediatek,mt8183-i2c";
reg = <0 0x1100f000 0 0x1000>,
@@ -644,6 +677,14 @@
compatible = "mediatek,mt8183-efuse",
"mediatek,efuse";
reg = <0 0x11f10000 0 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ thermal_calibration: calib@180 {
+ reg = <0x180 0xc>;
+ };
+ svs_calibration: calib@580 {
+ reg = <0x580 0x64>;
+ };
};
mfgcfg: syscon@13000000 {
--
2.18.0
^ permalink raw reply related
* [PATCH v8 3/3] PM / AVS: SVS: Introduce SVS engine
From: Roger Lu @ 2020-05-18 9:24 UTC (permalink / raw)
To: Kevin Hilman, Rob Herring, Nicolas Boichat, Stephen Boyd
Cc: Fan Chen, HenryC Chen, YT Lee, Xiaoqing Liu, Charles Yang,
Angus Lin, Mark Rutland, Matthias Brugger, Nishanth Menon,
Roger Lu, devicetree, linux-arm-kernel, linux-mediatek,
linux-kernel, linux-pm
In-Reply-To: <20200518092403.22647-1-roger.lu@mediatek.com>
The SVS (Smart Voltage Scaling) engine is a piece
of hardware which is used to calculate optimized
voltage values of several power domains,
e.g. CPU/GPU/CCI, according to chip process corner,
temperatures, and other factors. Then DVFS driver
could apply those optimized voltage values to reduce
power consumption.
Signed-off-by: Roger Lu <roger.lu@mediatek.com>
---
drivers/power/avs/Kconfig | 10 +
drivers/power/avs/Makefile | 1 +
drivers/power/avs/mtk_svs.c | 2119 +++++++++++++++++++++++++++++++++
include/linux/power/mtk_svs.h | 23 +
4 files changed, 2153 insertions(+)
create mode 100644 drivers/power/avs/mtk_svs.c
create mode 100644 include/linux/power/mtk_svs.h
diff --git a/drivers/power/avs/Kconfig b/drivers/power/avs/Kconfig
index cdb4237bfd02..67089ac6040e 100644
--- a/drivers/power/avs/Kconfig
+++ b/drivers/power/avs/Kconfig
@@ -35,3 +35,13 @@ config ROCKCHIP_IODOMAIN
Say y here to enable support io domains on Rockchip SoCs. It is
necessary for the io domain setting of the SoC to match the
voltage supplied by the regulators.
+
+config MTK_SVS
+ bool "MediaTek Smart Voltage Scaling(SVS)"
+ depends on POWER_AVS && MTK_EFUSE && NVMEM
+ help
+ The SVS engine is a piece of hardware which is used to calculate
+ optimized voltage values of several power domains, e.g.
+ CPU clusters/GPU/CCI, according to chip process corner, temperatures,
+ and other factors. Then DVFS driver could apply those optimized voltage
+ values to reduce power consumption.
diff --git a/drivers/power/avs/Makefile b/drivers/power/avs/Makefile
index 9007d05853e2..231adf078582 100644
--- a/drivers/power/avs/Makefile
+++ b/drivers/power/avs/Makefile
@@ -2,3 +2,4 @@
obj-$(CONFIG_POWER_AVS_OMAP) += smartreflex.o
obj-$(CONFIG_QCOM_CPR) += qcom-cpr.o
obj-$(CONFIG_ROCKCHIP_IODOMAIN) += rockchip-io-domain.o
+obj-$(CONFIG_MTK_SVS) += mtk_svs.o
diff --git a/drivers/power/avs/mtk_svs.c b/drivers/power/avs/mtk_svs.c
new file mode 100644
index 000000000000..a4083b3ef175
--- /dev/null
+++ b/drivers/power/avs/mtk_svs.c
@@ -0,0 +1,2119 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 MediaTek Inc.
+ */
+
+#define pr_fmt(fmt) "[mtk_svs] " fmt
+
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_opp.h>
+#include <linux/pm_qos.h>
+#include <linux/pm_runtime.h>
+#include <linux/power/mtk_svs.h>
+#include <linux/proc_fs.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/thermal.h>
+#include <linux/uaccess.h>
+
+/* svs 1-line sw id */
+#define SVS_CPU_LITTLE BIT(0)
+#define SVS_CPU_BIG BIT(1)
+#define SVS_CCI BIT(2)
+#define SVS_GPU BIT(3)
+
+/* svs bank mode support */
+#define SVSB_MODE_ALL_DISABLE (0)
+#define SVSB_MODE_INIT01 BIT(1)
+#define SVSB_MODE_INIT02 BIT(2)
+#define SVSB_MODE_MON BIT(3)
+
+/* svs bank init01 condition */
+#define SVSB_INIT01_VOLT_IGNORE BIT(1)
+#define SVSB_INIT01_VOLT_INC_ONLY BIT(2)
+
+/* svs bank common setting */
+#define HIGH_TEMP_MAX (U32_MAX)
+#define RUNCONFIG_DEFAULT (0x80000000)
+#define DC_SIGNED_BIT (0x8000)
+#define INTEN_INIT0x (0x00005f01)
+#define INTEN_MONVOPEN (0x00ff0000)
+#define SVSEN_OFF (0x0)
+#define SVSEN_MASK (0x7)
+#define SVSEN_INIT01 (0x1)
+#define SVSEN_INIT02 (0x5)
+#define SVSEN_MON (0x2)
+#define INTSTS_MONVOP (0x00ff0000)
+#define INTSTS_COMPLETE (0x1)
+#define INTSTS_CLEAN (0x00ffffff)
+
+#define proc_fops_rw(name) \
+ static int name ## _proc_open(struct inode *inode, \
+ struct file *file) \
+ { \
+ return single_open(file, name ## _proc_show, \
+ PDE_DATA(inode)); \
+ } \
+ static const struct proc_ops name ## _proc_fops = { \
+ .proc_open = name ## _proc_open, \
+ .proc_read = seq_read, \
+ .proc_lseek = seq_lseek, \
+ .proc_release = single_release, \
+ .proc_write = name ## _proc_write, \
+ }
+
+#define proc_fops_ro(name) \
+ static int name ## _proc_open(struct inode *inode, \
+ struct file *file) \
+ { \
+ return single_open(file, name ## _proc_show, \
+ PDE_DATA(inode)); \
+ } \
+ static const struct proc_ops name ## _proc_fops = { \
+ .proc_open = name ## _proc_open, \
+ .proc_read = seq_read, \
+ .proc_lseek = seq_lseek, \
+ .proc_release = single_release, \
+ }
+
+#define proc_entry(name) {__stringify(name), &name ## _proc_fops}
+
+static DEFINE_SPINLOCK(mtk_svs_lock);
+struct mtk_svs;
+
+enum svsb_phase {
+ SVSB_PHASE_INIT01 = 0,
+ SVSB_PHASE_INIT02,
+ SVSB_PHASE_MON,
+ SVSB_PHASE_ERROR,
+};
+
+enum reg_index {
+ TEMPMONCTL0 = 0,
+ TEMPMONCTL1,
+ TEMPMONCTL2,
+ TEMPMONINT,
+ TEMPMONINTSTS,
+ TEMPMONIDET0,
+ TEMPMONIDET1,
+ TEMPMONIDET2,
+ TEMPH2NTHRE,
+ TEMPHTHRE,
+ TEMPCTHRE,
+ TEMPOFFSETH,
+ TEMPOFFSETL,
+ TEMPMSRCTL0,
+ TEMPMSRCTL1,
+ TEMPAHBPOLL,
+ TEMPAHBTO,
+ TEMPADCPNP0,
+ TEMPADCPNP1,
+ TEMPADCPNP2,
+ TEMPADCMUX,
+ TEMPADCEXT,
+ TEMPADCEXT1,
+ TEMPADCEN,
+ TEMPPNPMUXADDR,
+ TEMPADCMUXADDR,
+ TEMPADCEXTADDR,
+ TEMPADCEXT1ADDR,
+ TEMPADCENADDR,
+ TEMPADCVALIDADDR,
+ TEMPADCVOLTADDR,
+ TEMPRDCTRL,
+ TEMPADCVALIDMASK,
+ TEMPADCVOLTAGESHIFT,
+ TEMPADCWRITECTRL,
+ TEMPMSR0,
+ TEMPMSR1,
+ TEMPMSR2,
+ TEMPADCHADDR,
+ TEMPIMMD0,
+ TEMPIMMD1,
+ TEMPIMMD2,
+ TEMPMONIDET3,
+ TEMPADCPNP3,
+ TEMPMSR3,
+ TEMPIMMD3,
+ TEMPPROTCTL,
+ TEMPPROTTA,
+ TEMPPROTTB,
+ TEMPPROTTC,
+ TEMPSPARE0,
+ TEMPSPARE1,
+ TEMPSPARE2,
+ TEMPSPARE3,
+ TEMPMSR0_1,
+ TEMPMSR1_1,
+ TEMPMSR2_1,
+ TEMPMSR3_1,
+ DESCHAR,
+ TEMPCHAR,
+ DETCHAR,
+ AGECHAR,
+ DCCONFIG,
+ AGECONFIG,
+ FREQPCT30,
+ FREQPCT74,
+ LIMITVALS,
+ VBOOT,
+ DETWINDOW,
+ CONFIG,
+ TSCALCS,
+ RUNCONFIG,
+ SVSEN,
+ INIT2VALS,
+ DCVALUES,
+ AGEVALUES,
+ VOP30,
+ VOP74,
+ TEMP,
+ INTSTS,
+ INTSTSRAW,
+ INTEN,
+ CHKINT,
+ CHKSHIFT,
+ STATUS,
+ VDESIGN30,
+ VDESIGN74,
+ DVT30,
+ DVT74,
+ AGECOUNT,
+ SMSTATE0,
+ SMSTATE1,
+ CTL0,
+ DESDETSEC,
+ TEMPAGESEC,
+ CTRLSPARE0,
+ CTRLSPARE1,
+ CTRLSPARE2,
+ CTRLSPARE3,
+ CORESEL,
+ THERMINTST,
+ INTST,
+ THSTAGE0ST,
+ THSTAGE1ST,
+ THSTAGE2ST,
+ THAHBST0,
+ THAHBST1,
+ SPARE0,
+ SPARE1,
+ SPARE2,
+ SPARE3,
+ THSLPEVEB,
+ reg_num,
+};
+
+static const u32 svs_regs_v2[] = {
+ [TEMPMONCTL0] = 0x000,
+ [TEMPMONCTL1] = 0x004,
+ [TEMPMONCTL2] = 0x008,
+ [TEMPMONINT] = 0x00c,
+ [TEMPMONINTSTS] = 0x010,
+ [TEMPMONIDET0] = 0x014,
+ [TEMPMONIDET1] = 0x018,
+ [TEMPMONIDET2] = 0x01c,
+ [TEMPH2NTHRE] = 0x024,
+ [TEMPHTHRE] = 0x028,
+ [TEMPCTHRE] = 0x02c,
+ [TEMPOFFSETH] = 0x030,
+ [TEMPOFFSETL] = 0x034,
+ [TEMPMSRCTL0] = 0x038,
+ [TEMPMSRCTL1] = 0x03c,
+ [TEMPAHBPOLL] = 0x040,
+ [TEMPAHBTO] = 0x044,
+ [TEMPADCPNP0] = 0x048,
+ [TEMPADCPNP1] = 0x04c,
+ [TEMPADCPNP2] = 0x050,
+ [TEMPADCMUX] = 0x054,
+ [TEMPADCEXT] = 0x058,
+ [TEMPADCEXT1] = 0x05c,
+ [TEMPADCEN] = 0x060,
+ [TEMPPNPMUXADDR] = 0x064,
+ [TEMPADCMUXADDR] = 0x068,
+ [TEMPADCEXTADDR] = 0x06c,
+ [TEMPADCEXT1ADDR] = 0x070,
+ [TEMPADCENADDR] = 0x074,
+ [TEMPADCVALIDADDR] = 0x078,
+ [TEMPADCVOLTADDR] = 0x07c,
+ [TEMPRDCTRL] = 0x080,
+ [TEMPADCVALIDMASK] = 0x084,
+ [TEMPADCVOLTAGESHIFT] = 0x088,
+ [TEMPADCWRITECTRL] = 0x08c,
+ [TEMPMSR0] = 0x090,
+ [TEMPMSR1] = 0x094,
+ [TEMPMSR2] = 0x098,
+ [TEMPADCHADDR] = 0x09c,
+ [TEMPIMMD0] = 0x0a0,
+ [TEMPIMMD1] = 0x0a4,
+ [TEMPIMMD2] = 0x0a8,
+ [TEMPMONIDET3] = 0x0b0,
+ [TEMPADCPNP3] = 0x0b4,
+ [TEMPMSR3] = 0x0b8,
+ [TEMPIMMD3] = 0x0bc,
+ [TEMPPROTCTL] = 0x0c0,
+ [TEMPPROTTA] = 0x0c4,
+ [TEMPPROTTB] = 0x0c8,
+ [TEMPPROTTC] = 0x0cc,
+ [TEMPSPARE0] = 0x0f0,
+ [TEMPSPARE1] = 0x0f4,
+ [TEMPSPARE2] = 0x0f8,
+ [TEMPSPARE3] = 0x0fc,
+ [TEMPMSR0_1] = 0x190,
+ [TEMPMSR1_1] = 0x194,
+ [TEMPMSR2_1] = 0x198,
+ [TEMPMSR3_1] = 0x1b8,
+ [DESCHAR] = 0xc00,
+ [TEMPCHAR] = 0xc04,
+ [DETCHAR] = 0xc08,
+ [AGECHAR] = 0xc0c,
+ [DCCONFIG] = 0xc10,
+ [AGECONFIG] = 0xc14,
+ [FREQPCT30] = 0xc18,
+ [FREQPCT74] = 0xc1c,
+ [LIMITVALS] = 0xc20,
+ [VBOOT] = 0xc24,
+ [DETWINDOW] = 0xc28,
+ [CONFIG] = 0xc2c,
+ [TSCALCS] = 0xc30,
+ [RUNCONFIG] = 0xc34,
+ [SVSEN] = 0xc38,
+ [INIT2VALS] = 0xc3c,
+ [DCVALUES] = 0xc40,
+ [AGEVALUES] = 0xc44,
+ [VOP30] = 0xc48,
+ [VOP74] = 0xc4c,
+ [TEMP] = 0xc50,
+ [INTSTS] = 0xc54,
+ [INTSTSRAW] = 0xc58,
+ [INTEN] = 0xc5c,
+ [CHKINT] = 0xc60,
+ [CHKSHIFT] = 0xc64,
+ [STATUS] = 0xc68,
+ [VDESIGN30] = 0xc6c,
+ [VDESIGN74] = 0xc70,
+ [DVT30] = 0xc74,
+ [DVT74] = 0xc78,
+ [AGECOUNT] = 0xc7c,
+ [SMSTATE0] = 0xc80,
+ [SMSTATE1] = 0xc84,
+ [CTL0] = 0xc88,
+ [DESDETSEC] = 0xce0,
+ [TEMPAGESEC] = 0xce4,
+ [CTRLSPARE0] = 0xcf0,
+ [CTRLSPARE1] = 0xcf4,
+ [CTRLSPARE2] = 0xcf8,
+ [CTRLSPARE3] = 0xcfc,
+ [CORESEL] = 0xf00,
+ [THERMINTST] = 0xf04,
+ [INTST] = 0xf08,
+ [THSTAGE0ST] = 0xf0c,
+ [THSTAGE1ST] = 0xf10,
+ [THSTAGE2ST] = 0xf14,
+ [THAHBST0] = 0xf18,
+ [THAHBST1] = 0xf1c,
+ [SPARE0] = 0xf20,
+ [SPARE1] = 0xf24,
+ [SPARE2] = 0xf28,
+ [SPARE3] = 0xf2c,
+ [THSLPEVEB] = 0xf30,
+};
+
+struct thermal_parameter {
+ int adc_ge_t;
+ int adc_oe_t;
+ int ge;
+ int oe;
+ int gain;
+ int o_vtsabb;
+ int o_vtsmcu1;
+ int o_vtsmcu2;
+ int o_vtsmcu3;
+ int o_vtsmcu4;
+ int o_vtsmcu5;
+ int degc_cali;
+ int adc_cali_en_t;
+ int o_slope;
+ int o_slope_sign;
+ int ts_id;
+};
+
+struct svs_bank_ops {
+ void (*set_freqs_pct)(struct mtk_svs *svs);
+ void (*get_vops)(struct mtk_svs *svs);
+};
+
+struct svs_bank {
+ struct svs_bank_ops *ops;
+ struct completion init_completion;
+ struct device *dev;
+ struct regulator *buck;
+ struct mutex lock; /* Lock to protect update voltage process */
+ bool suspended;
+ bool mtcmos_request;
+ s32 volt_offset;
+ u32 mode_support;
+ u32 opp_freqs[16];
+ u32 freqs_pct[16];
+ u32 opp_volts[16];
+ u32 init02_volts[16];
+ u32 volts[16];
+ u32 reg_data[3][reg_num];
+ u32 freq_base;
+ u32 vboot;
+ u32 volt_step;
+ u32 volt_base;
+ u32 init01_volt_flag;
+ u32 phase;
+ u32 vmax;
+ u32 vmin;
+ u32 bts;
+ u32 mts;
+ u32 bdes;
+ u32 mdes;
+ u32 mtdes;
+ u32 dcbdet;
+ u32 dcmdet;
+ u32 dthi;
+ u32 dtlo;
+ u32 det_window;
+ u32 det_max;
+ u32 age_config;
+ u32 age_voffset_in;
+ u32 agem;
+ u32 dc_config;
+ u32 dc_voffset_in;
+ u32 dvt_fixed;
+ u32 vco;
+ u32 chk_shift;
+ u32 svs_temp;
+ u32 upper_temp_bound;
+ u32 lower_temp_bound;
+ u32 high_temp_threashold;
+ u32 high_temp_offset;
+ u32 low_temp_threashold;
+ u32 low_temp_offset;
+ u32 core_sel;
+ u32 opp_count;
+ u32 int_st;
+ u32 systemclk_en;
+ u32 sw_id;
+ u32 bank_id;
+ u32 ctl0;
+ u8 *of_compatible;
+ u8 *name;
+ u8 *tzone_name;
+ u8 *buck_name;
+};
+
+struct svs_platform {
+ struct svs_bank *banks;
+ bool (*efuse_parsing)(struct mtk_svs *svs);
+ bool fake_efuse;
+ bool need_hw_reset;
+ const u32 *regs;
+ unsigned long irqflags;
+ u32 bank_num;
+ u32 efuse_num;
+ u32 efuse_check;
+ u32 thermal_efuse_num;
+ u8 *name;
+};
+
+struct mtk_svs {
+ const struct svs_platform *platform;
+ struct svs_bank *bank;
+ struct device *dev;
+ void __iomem *base;
+ struct clk *main_clk;
+ u32 *efuse;
+ u32 *thermal_efuse;
+};
+
+unsigned long claim_mtk_svs_lock(void)
+ __acquires(&mtk_svs_lock)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mtk_svs_lock, flags);
+
+ return flags;
+}
+EXPORT_SYMBOL_GPL(claim_mtk_svs_lock);
+
+void release_mtk_svs_lock(unsigned long flags)
+ __releases(&mtk_svs_lock)
+{
+ spin_unlock_irqrestore(&mtk_svs_lock, flags);
+}
+EXPORT_SYMBOL_GPL(release_mtk_svs_lock);
+
+static u32 percent(u32 numerator, u32 denominator)
+{
+ u32 pct;
+
+ /* If not divide 1000, "numerator * 100" would be data overflow. */
+ numerator /= 1000;
+ denominator /= 1000;
+ pct = ((numerator * 100) + denominator - 1) / denominator;
+ pct &= GENMASK(7, 0);
+
+ return pct;
+}
+
+static u32 svs_readl(struct mtk_svs *svs, enum reg_index rg_i)
+{
+ return readl(svs->base + svs->platform->regs[rg_i]);
+}
+
+static void svs_writel(struct mtk_svs *svs, u32 val, enum reg_index rg_i)
+{
+ writel(val, svs->base + svs->platform->regs[rg_i]);
+}
+
+static void svs_switch_bank(struct mtk_svs *svs)
+{
+ struct svs_bank *svsb = svs->bank;
+
+ svs_writel(svs, svsb->core_sel, CORESEL);
+}
+
+static u32 svsb_volt_to_opp_volt(u32 svsb_volt, u32 svsb_volt_step,
+ u32 svsb_volt_base)
+{
+ u32 u_volt;
+
+ u_volt = (svsb_volt * svsb_volt_step) + svsb_volt_base;
+
+ return u_volt;
+}
+
+static int svsb_get_zone_temperature(struct svs_bank *svsb, int *tzone_temp)
+{
+ struct thermal_zone_device *tzd;
+
+ tzd = thermal_zone_get_zone_by_name(svsb->tzone_name);
+ if (IS_ERR(tzd))
+ return PTR_ERR(tzd);
+
+ return thermal_zone_get_temp(tzd, tzone_temp);
+}
+
+static int svsb_set_volts(struct svs_bank *svsb, bool force_update)
+{
+ u32 i, svsb_volt, opp_volt, temp_offset = 0;
+ int tzone_temp, ret;
+
+ mutex_lock(&svsb->lock);
+
+ /*
+ * If bank is suspended, it means signed-off voltages are applied.
+ * Don't need to update opp voltage anymore.
+ */
+ if (svsb->suspended && !force_update) {
+ pr_notice("%s: bank is suspended\n", svsb->name);
+ mutex_unlock(&svsb->lock);
+ return -EPERM;
+ }
+
+ /* Get thermal effect */
+ if (svsb->phase == SVSB_PHASE_MON) {
+ if (svsb->svs_temp > svsb->upper_temp_bound &&
+ svsb->svs_temp < svsb->lower_temp_bound) {
+ pr_err("%s: svs_temp is abnormal (0x%x)?\n",
+ svsb->name, svsb->svs_temp);
+ mutex_unlock(&svsb->lock);
+ return -EINVAL;
+ }
+
+ ret = svsb_get_zone_temperature(svsb, &tzone_temp);
+ if (ret) {
+ pr_err("%s: cannot get zone \"%s\" temperature(%d)\n",
+ svsb->name, svsb->tzone_name, ret);
+ pr_err("%s: set signed-off voltage this time.\n",
+ svsb->name);
+ svsb->phase = SVSB_PHASE_ERROR;
+ }
+
+ if (tzone_temp >= svsb->high_temp_threashold)
+ temp_offset += svsb->high_temp_offset;
+
+ if (tzone_temp <= svsb->low_temp_threashold)
+ temp_offset += svsb->low_temp_offset;
+ }
+
+ /* vmin <= svsb_volt (opp_volt) <= signed-off voltage */
+ for (i = 0; i < svsb->opp_count; i++) {
+ if (svsb->phase == SVSB_PHASE_MON) {
+ svsb_volt = max((svsb->volts[i] + svsb->volt_offset +
+ temp_offset), svsb->vmin);
+ opp_volt = svsb_volt_to_opp_volt(svsb_volt,
+ svsb->volt_step,
+ svsb->volt_base);
+ } else if (svsb->phase == SVSB_PHASE_INIT02) {
+ svsb_volt = max((svsb->init02_volts[i] +
+ svsb->volt_offset), svsb->vmin);
+ opp_volt = svsb_volt_to_opp_volt(svsb_volt,
+ svsb->volt_step,
+ svsb->volt_base);
+ } else if (svsb->phase == SVSB_PHASE_ERROR) {
+ opp_volt = svsb->opp_volts[i];
+ } else {
+ pr_err("%s: unknown phase: %u?\n",
+ svsb->name, svsb->phase);
+ mutex_unlock(&svsb->lock);
+ return -EINVAL;
+ }
+
+ opp_volt = min(opp_volt, svsb->opp_volts[i]);
+ ret = dev_pm_opp_adjust_voltage(svsb->dev, svsb->opp_freqs[i],
+ opp_volt, opp_volt,
+ svsb->opp_volts[i]);
+ if (ret) {
+ pr_err("%s: set voltage failed: %d\n", svsb->name, ret);
+ mutex_unlock(&svsb->lock);
+ return ret;
+ }
+ }
+
+ mutex_unlock(&svsb->lock);
+
+ return 0;
+}
+
+static u32 interpolate(u32 f0, u32 f1, u32 v0, u32 v1, u32 fx)
+{
+ u32 vy;
+
+ if (v0 == v1 || f0 == f1)
+ return v0;
+
+ /* *100 to have decimal fraction factor, +99 for rounding up. */
+ vy = (v0 * 100) - ((((v0 - v1) * 100) / (f0 - f1)) * (f0 - fx));
+ vy = (vy + 99) / 100;
+
+ return vy;
+}
+
+static void svs_get_vops_v2(struct mtk_svs *svs)
+{
+ struct svs_bank *svsb = svs->bank;
+ u32 temp, i;
+
+ temp = svs_readl(svs, VOP30);
+ svsb->volts[6] = (temp >> 24) & GENMASK(7, 0);
+ svsb->volts[4] = (temp >> 16) & GENMASK(7, 0);
+ svsb->volts[2] = (temp >> 8) & GENMASK(7, 0);
+ svsb->volts[0] = (temp & GENMASK(7, 0));
+
+ temp = svs_readl(svs, VOP74);
+ svsb->volts[14] = (temp >> 24) & GENMASK(7, 0);
+ svsb->volts[12] = (temp >> 16) & GENMASK(7, 0);
+ svsb->volts[10] = (temp >> 8) & GENMASK(7, 0);
+ svsb->volts[8] = (temp & GENMASK(7, 0));
+
+ for (i = 0; i <= 7; i++) {
+ if (i < 7) {
+ svsb->volts[(i * 2) + 1] =
+ interpolate(svsb->freqs_pct[i * 2],
+ svsb->freqs_pct[(i + 1) * 2],
+ svsb->volts[i * 2],
+ svsb->volts[(i + 1) * 2],
+ svsb->freqs_pct[(i * 2) + 1]);
+ } else if (i == 7) {
+ svsb->volts[(i * 2) + 1] =
+ interpolate(svsb->freqs_pct[(i - 1) * 2],
+ svsb->freqs_pct[i * 2],
+ svsb->volts[(i - 1) * 2],
+ svsb->volts[i * 2],
+ svsb->freqs_pct[(i * 2) + 1]);
+ }
+ }
+}
+
+static void svs_set_freqs_pct_v2(struct mtk_svs *svs)
+{
+ struct svs_bank *svsb = svs->bank;
+
+ svs_writel(svs,
+ ((svsb->freqs_pct[6] << 24) & GENMASK(31, 24)) |
+ ((svsb->freqs_pct[4] << 16) & GENMASK(23, 16)) |
+ ((svsb->freqs_pct[2] << 8) & GENMASK(15, 8)) |
+ (svsb->freqs_pct[0] & GENMASK(7, 0)),
+ FREQPCT30);
+ svs_writel(svs,
+ ((svsb->freqs_pct[14] << 24) & GENMASK(31, 24)) |
+ ((svsb->freqs_pct[12] << 16) & GENMASK(23, 16)) |
+ ((svsb->freqs_pct[10] << 8) & GENMASK(15, 8)) |
+ ((svsb->freqs_pct[8]) & GENMASK(7, 0)),
+ FREQPCT74);
+}
+
+static void svs_set_phase(struct mtk_svs *svs, u32 target_phase)
+{
+ struct svs_bank *svsb = svs->bank;
+ u32 des_char, temp_char, det_char, limit_vals;
+ u32 init2vals, ts_calcs, val, filter, i;
+
+ svs_switch_bank(svs);
+
+ des_char = ((svsb->bdes << 8) & GENMASK(15, 8)) |
+ (svsb->mdes & GENMASK(7, 0));
+ svs_writel(svs, des_char, DESCHAR);
+
+ temp_char = ((svsb->vco << 16) & GENMASK(23, 16)) |
+ ((svsb->mtdes << 8) & GENMASK(15, 8)) |
+ (svsb->dvt_fixed & GENMASK(7, 0));
+ svs_writel(svs, temp_char, TEMPCHAR);
+
+ det_char = ((svsb->dcbdet << 8) & GENMASK(15, 8)) |
+ (svsb->dcmdet & GENMASK(7, 0));
+ svs_writel(svs, det_char, DETCHAR);
+
+ svs_writel(svs, svsb->dc_config, DCCONFIG);
+ svs_writel(svs, svsb->age_config, AGECONFIG);
+
+ if (!svsb->agem) {
+ svs_writel(svs, RUNCONFIG_DEFAULT, RUNCONFIG);
+ } else {
+ val = 0x0;
+
+ for (i = 0; i < 24; i += 2) {
+ filter = 0x3 << i;
+
+ if (!(svsb->age_config & filter))
+ val |= (0x1 << i);
+ else
+ val |= (svsb->age_config & filter);
+ }
+ svs_writel(svs, val, RUNCONFIG);
+ }
+
+ svsb->ops->set_freqs_pct(svs);
+
+ limit_vals = ((svsb->vmax << 24) & GENMASK(31, 24)) |
+ ((svsb->vmin << 16) & GENMASK(23, 16)) |
+ ((svsb->dthi << 8) & GENMASK(15, 8)) |
+ (svsb->dtlo & GENMASK(7, 0));
+ svs_writel(svs, limit_vals, LIMITVALS);
+ svs_writel(svs, (svsb->vboot & GENMASK(7, 0)), VBOOT);
+ svs_writel(svs, (svsb->det_window & GENMASK(15, 0)), DETWINDOW);
+ svs_writel(svs, (svsb->det_max & GENMASK(15, 0)), CONFIG);
+
+ if (svsb->chk_shift)
+ svs_writel(svs, (svsb->chk_shift & GENMASK(7, 0)), CHKSHIFT);
+
+ if (svsb->ctl0)
+ svs_writel(svs, svsb->ctl0, CTL0);
+
+ svs_writel(svs, INTSTS_CLEAN, INTSTS);
+
+ switch (target_phase) {
+ case SVSB_PHASE_INIT01:
+ svs_writel(svs, INTEN_INIT0x, INTEN);
+ svs_writel(svs, SVSEN_INIT01, SVSEN);
+ break;
+ case SVSB_PHASE_INIT02:
+ svs_writel(svs, INTEN_INIT0x, INTEN);
+ init2vals = ((svsb->age_voffset_in << 16) & GENMASK(31, 16)) |
+ (svsb->dc_voffset_in & GENMASK(15, 0));
+ svs_writel(svs, init2vals, INIT2VALS);
+ svs_writel(svs, SVSEN_INIT02, SVSEN);
+ break;
+ case SVSB_PHASE_MON:
+ ts_calcs = ((svsb->bts << 12) & GENMASK(23, 12)) |
+ (svsb->mts & GENMASK(11, 0));
+ svs_writel(svs, ts_calcs, TSCALCS);
+ svs_writel(svs, INTEN_MONVOPEN, INTEN);
+ svs_writel(svs, SVSEN_MON, SVSEN);
+ break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+}
+
+static inline void svs_init01_isr_handler(struct mtk_svs *svs)
+{
+ struct svs_bank *svsb = svs->bank;
+ enum reg_index rg_i;
+
+ pr_notice("%s: %s: VDN74:0x%08x, VDN30:0x%08x, DCVALUES:0x%08x\n",
+ svsb->name, __func__, svs_readl(svs, VDESIGN74),
+ svs_readl(svs, VDESIGN30), svs_readl(svs, DCVALUES));
+
+ for (rg_i = TEMPMONCTL0; rg_i < reg_num; rg_i++)
+ svsb->reg_data[SVSB_PHASE_INIT01][rg_i] = svs_readl(svs, rg_i);
+
+ svsb->phase = SVSB_PHASE_INIT01;
+ svsb->dc_voffset_in = ~(svs_readl(svs, DCVALUES) & GENMASK(15, 0)) + 1;
+ if (svsb->init01_volt_flag == SVSB_INIT01_VOLT_IGNORE)
+ svsb->dc_voffset_in = 0;
+ else if ((svsb->dc_voffset_in & DC_SIGNED_BIT) &&
+ (svsb->init01_volt_flag == SVSB_INIT01_VOLT_INC_ONLY))
+ svsb->dc_voffset_in = 0;
+
+ svsb->age_voffset_in = svs_readl(svs, AGEVALUES) & GENMASK(15, 0);
+
+ svs_writel(svs, SVSEN_OFF, SVSEN);
+ svs_writel(svs, INTSTS_COMPLETE, INTSTS);
+
+ /* svs init01 clock gating */
+ svsb->core_sel &= ~svsb->systemclk_en;
+ complete(&svsb->init_completion);
+}
+
+static inline void svs_init02_isr_handler(struct mtk_svs *svs)
+{
+ struct svs_bank *svsb = svs->bank;
+ enum reg_index rg_i;
+
+ pr_notice("%s: %s: VOP74:0x%08x, VOP30:0x%08x, DCVALUES:0x%08x\n",
+ svsb->name, __func__, svs_readl(svs, VOP74),
+ svs_readl(svs, VOP30), svs_readl(svs, DCVALUES));
+
+ for (rg_i = TEMPMONCTL0; rg_i < reg_num; rg_i++)
+ svsb->reg_data[SVSB_PHASE_INIT02][rg_i] = svs_readl(svs, rg_i);
+
+ svsb->phase = SVSB_PHASE_INIT02;
+ svsb->ops->get_vops(svs);
+ memcpy(svsb->init02_volts, svsb->volts, sizeof(u32) * svsb->opp_count);
+
+ svs_writel(svs, SVSEN_OFF, SVSEN);
+ svs_writel(svs, INTSTS_COMPLETE, INTSTS);
+
+ complete(&svsb->init_completion);
+}
+
+static inline void svs_mon_mode_isr_handler(struct mtk_svs *svs)
+{
+ struct svs_bank *svsb = svs->bank;
+ enum reg_index rg_i;
+
+ for (rg_i = TEMPMONCTL0; rg_i < reg_num; rg_i++)
+ svsb->reg_data[SVSB_PHASE_MON][rg_i] = svs_readl(svs, rg_i);
+
+ svsb->phase = SVSB_PHASE_MON;
+ svsb->svs_temp = svs_readl(svs, TEMP) & GENMASK(7, 0);
+ svsb->ops->get_vops(svs);
+
+ svs_writel(svs, INTSTS_MONVOP, INTSTS);
+}
+
+static inline void svs_error_isr_handler(struct mtk_svs *svs)
+{
+ const struct svs_platform *svsp = svs->platform;
+ struct svs_bank *svsb = svs->bank;
+ enum reg_index rg_i;
+
+ pr_err("%s(): %s(%s)", __func__, svsp->name, svsb->name);
+ pr_err("CORESEL(0x%x) = 0x%08x\n",
+ svsp->regs[CORESEL], svs_readl(svs, CORESEL)),
+ pr_err("SVSEN(0x%x) = 0x%08x, INTSTS(0x%x) = 0x%08x\n",
+ svsp->regs[SVSEN], svs_readl(svs, SVSEN),
+ svsp->regs[INTSTS], svs_readl(svs, INTSTS));
+ pr_err("SMSTATE0(0x%x) = 0x%08x, SMSTATE1(0x%x) = 0x%08x\n",
+ svsp->regs[SMSTATE0], svs_readl(svs, SMSTATE0),
+ svsp->regs[SMSTATE1], svs_readl(svs, SMSTATE1));
+ pr_err("TEMP(0x%x) = 0x%08x, TEMPMSR0(0x%x) = 0x%08x\n",
+ svsp->regs[TEMP], svs_readl(svs, TEMP),
+ svsp->regs[TEMPMSR0], svs_readl(svs, TEMPMSR0));
+ pr_err("TEMPMSR1(0x%x) = 0x%08x, TEMPMSR2(0x%x) = 0x%08x\n",
+ svsp->regs[TEMPMSR1], svs_readl(svs, TEMPMSR1),
+ svsp->regs[TEMPMSR2], svs_readl(svs, TEMPMSR2));
+ pr_err("TEMPMONCTL0(0x%x) = 0x%08x, TEMPMSRCTL1(0x%x) = 0x%08x\n",
+ svsp->regs[TEMPMONCTL0], svs_readl(svs, TEMPMONCTL0),
+ svsp->regs[TEMPMSRCTL1], svs_readl(svs, TEMPMSRCTL1));
+
+ for (rg_i = TEMPMONCTL0; rg_i < reg_num; rg_i++)
+ svsb->reg_data[SVSB_PHASE_MON][rg_i] = svs_readl(svs, rg_i);
+
+ svsb->mode_support = SVSB_MODE_ALL_DISABLE;
+
+ if (svsb->phase != SVSB_PHASE_INIT01)
+ svsb->phase = SVSB_PHASE_ERROR;
+
+ svs_writel(svs, SVSEN_OFF, SVSEN);
+ svs_writel(svs, INTSTS_CLEAN, INTSTS);
+}
+
+static irqreturn_t svs_isr(int irq, void *data)
+{
+ struct mtk_svs *svs = (struct mtk_svs *)data;
+ const struct svs_platform *svsp = svs->platform;
+ struct svs_bank *svsb = NULL;
+ unsigned long flags;
+ u32 idx, int_sts, svs_en;
+
+ flags = claim_mtk_svs_lock();
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+ svs->bank = svsb;
+
+ if (svsb->int_st & svs_readl(svs, INTST))
+ continue;
+
+ if (!svsb->suspended) {
+ svs_switch_bank(svs);
+ int_sts = svs_readl(svs, INTSTS);
+ svs_en = svs_readl(svs, SVSEN);
+
+ if (int_sts == INTSTS_COMPLETE &&
+ ((svs_en & SVSEN_MASK) == SVSEN_INIT01))
+ svs_init01_isr_handler(svs);
+ else if ((int_sts == INTSTS_COMPLETE) &&
+ ((svs_en & SVSEN_MASK) == SVSEN_INIT02))
+ svs_init02_isr_handler(svs);
+ else if (!!(int_sts & INTSTS_MONVOP))
+ svs_mon_mode_isr_handler(svs);
+ else
+ svs_error_isr_handler(svs);
+ }
+
+ break;
+ }
+ release_mtk_svs_lock(flags);
+
+ if (svsb->phase != SVSB_PHASE_INIT01)
+ svsb_set_volts(svsb, false);
+
+ return IRQ_HANDLED;
+}
+
+static void svs_mon_mode(struct mtk_svs *svs)
+{
+ const struct svs_platform *svsp = svs->platform;
+ struct svs_bank *svsb;
+ unsigned long flags;
+ u32 idx;
+
+ flags = claim_mtk_svs_lock();
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+ svs->bank = svsb;
+
+ if (!(svsb->mode_support & SVSB_MODE_MON))
+ continue;
+
+ svs_set_phase(svs, SVSB_PHASE_MON);
+ }
+ release_mtk_svs_lock(flags);
+}
+
+static int svs_init02(struct mtk_svs *svs)
+{
+ const struct svs_platform *svsp = svs->platform;
+ struct svs_bank *svsb;
+ unsigned long flags, time_left;
+ u32 idx;
+
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+ svs->bank = svsb;
+
+ if (!(svsb->mode_support & SVSB_MODE_INIT02))
+ continue;
+
+ reinit_completion(&svsb->init_completion);
+ flags = claim_mtk_svs_lock();
+ svs_set_phase(svs, SVSB_PHASE_INIT02);
+ release_mtk_svs_lock(flags);
+ time_left =
+ wait_for_completion_timeout(&svsb->init_completion,
+ msecs_to_jiffies(2000));
+ if (!time_left) {
+ pr_err("%s: init02 completion timeout\n", svsb->name);
+ return -EBUSY;
+ }
+ }
+
+ return 0;
+}
+
+static int svs_init01(struct mtk_svs *svs)
+{
+ const struct svs_platform *svsp = svs->platform;
+ struct svs_bank *svsb;
+ struct pm_qos_request *qos_request;
+ unsigned long flags, time_left;
+ bool search_done;
+ int ret = -EPERM;
+ u32 opp_freqs, opp_vboot, buck_volt, idx, i;
+
+ qos_request = kzalloc(sizeof(*qos_request), GFP_KERNEL);
+ if (!qos_request)
+ return -ENOMEM;
+
+ /* Let CPUs leave idle-off state for initializing svs_init01. */
+ cpu_latency_qos_add_request(qos_request, 0);
+
+ /*
+ * Sometimes two svs banks use the same buck.
+ * Therefore, we set each svs bank to vboot voltage first.
+ */
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+ search_done = false;
+
+ ret = regulator_set_mode(svsb->buck, REGULATOR_MODE_FAST);
+ if (ret)
+ pr_notice("%s: fail to set fast mode: %d\n",
+ svsb->name, ret);
+
+ if (svsb->mtcmos_request) {
+ ret = regulator_enable(svsb->buck);
+ if (ret) {
+ pr_err("%s: fail to enable %s power: %d\n",
+ svsb->name, svsb->buck_name, ret);
+ goto init01_finish;
+ }
+
+ ret = dev_pm_domain_attach(svsb->dev, false);
+ if (ret) {
+ pr_err("%s: attach pm domain fail: %d\n",
+ svsb->name, ret);
+ goto init01_finish;
+ }
+
+ pm_runtime_enable(svsb->dev);
+ ret = pm_runtime_get_sync(svsb->dev);
+ if (ret < 0) {
+ pr_err("%s: turn mtcmos on fail: %d\n",
+ svsb->name, ret);
+ goto init01_finish;
+ }
+ }
+
+ /*
+ * Find the fastest freq that can be run at vboot and
+ * fix to that freq until svs_init01 is done.
+ */
+ opp_vboot = svsb_volt_to_opp_volt(svsb->vboot,
+ svsb->volt_step,
+ svsb->volt_base);
+
+ for (i = 0; i < svsb->opp_count; i++) {
+ opp_freqs = svsb->opp_freqs[i];
+ if (!search_done && svsb->opp_volts[i] <= opp_vboot) {
+ ret = dev_pm_opp_adjust_voltage(svsb->dev,
+ opp_freqs,
+ opp_vboot,
+ opp_vboot,
+ opp_vboot);
+ if (ret) {
+ pr_err("%s: set voltage failed: %d\n",
+ svsb->name, ret);
+ goto init01_finish;
+ }
+
+ search_done = true;
+ } else {
+ dev_pm_opp_disable(svsb->dev,
+ svsb->opp_freqs[i]);
+ }
+ }
+ }
+
+ /* svs bank init01 begins */
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+ svs->bank = svsb;
+
+ if (!(svsb->mode_support & SVSB_MODE_INIT01))
+ continue;
+
+ opp_vboot = svsb_volt_to_opp_volt(svsb->vboot,
+ svsb->volt_step,
+ svsb->volt_base);
+
+ buck_volt = regulator_get_voltage(svsb->buck);
+ if (buck_volt != opp_vboot) {
+ pr_err("%s: buck voltage: %u, expected vboot: %u\n",
+ svsb->name, buck_volt, opp_vboot);
+ ret = -EPERM;
+ goto init01_finish;
+ }
+
+ init_completion(&svsb->init_completion);
+ flags = claim_mtk_svs_lock();
+ svs_set_phase(svs, SVSB_PHASE_INIT01);
+ release_mtk_svs_lock(flags);
+ time_left =
+ wait_for_completion_timeout(&svsb->init_completion,
+ msecs_to_jiffies(2000));
+ if (!time_left) {
+ pr_err("%s: init01 completion timeout\n", svsb->name);
+ ret = -EBUSY;
+ goto init01_finish;
+ }
+ }
+
+init01_finish:
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+
+ for (i = 0; i < svsb->opp_count; i++)
+ dev_pm_opp_enable(svsb->dev, svsb->opp_freqs[i]);
+
+ if (regulator_set_mode(svsb->buck, REGULATOR_MODE_NORMAL))
+ pr_notice("%s: fail to set normal mode: %d\n",
+ svsb->name, ret);
+
+ if (svsb->mtcmos_request) {
+ if (pm_runtime_put_sync(svsb->dev))
+ pr_err("%s: turn mtcmos off fail: %d\n",
+ svsb->name, ret);
+ pm_runtime_disable(svsb->dev);
+ dev_pm_domain_detach(svsb->dev, 0);
+ if (regulator_disable(svsb->buck))
+ pr_err("%s: fail to disable %s power: %d\n",
+ svsb->name, svsb->buck_name, ret);
+ }
+ }
+
+ cpu_latency_qos_remove_request(qos_request);
+ kfree(qos_request);
+
+ return ret;
+}
+
+static int svs_start(struct mtk_svs *svs)
+{
+ int ret;
+
+ ret = svs_init01(svs);
+ if (ret)
+ return ret;
+
+ ret = svs_init02(svs);
+ if (ret)
+ return ret;
+
+ svs_mon_mode(svs);
+
+ return ret;
+}
+
+static bool svs_mt8183_efuse_parsing(struct mtk_svs *svs)
+{
+ const struct svs_platform *svsp = svs->platform;
+ struct thermal_parameter tp;
+ struct svs_bank *svsb;
+ bool mon_mode_support = true;
+ int format[6], x_roomt[6], tb_roomt = 0;
+ struct nvmem_cell *cell;
+ size_t len;
+ u32 idx, i, ft_pgm, mts, temp0, temp1, temp2;
+
+ if (svsp->fake_efuse) {
+ pr_notice("fake efuse\n");
+ svs->efuse[0] = 0x00310080;
+ svs->efuse[1] = 0xabfbf757;
+ svs->efuse[2] = 0x47c747c7;
+ svs->efuse[3] = 0xabfbf757;
+ svs->efuse[4] = 0xe7fca0ec;
+ svs->efuse[5] = 0x47bf4b88;
+ svs->efuse[6] = 0xabfb8fa5;
+ svs->efuse[7] = 0xabfb217b;
+ svs->efuse[8] = 0x4bf34be1;
+ svs->efuse[9] = 0xabfb670d;
+ svs->efuse[16] = 0xabfbc653;
+ svs->efuse[17] = 0x47f347e1;
+ svs->efuse[18] = 0xabfbd848;
+ }
+
+ for (i = 0; i < svsp->efuse_num; i++)
+ if (svs->efuse[i])
+ pr_notice("M_HW_RES%d: 0x%08x\n", i, svs->efuse[i]);
+
+ /* svs efuse parsing */
+ ft_pgm = (svs->efuse[0] >> 4) & GENMASK(3, 0);
+
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+ if (ft_pgm <= 1)
+ svsb->init01_volt_flag = SVSB_INIT01_VOLT_IGNORE;
+
+ switch (svsb->sw_id) {
+ case SVS_CPU_LITTLE:
+ svsb->bdes = svs->efuse[16] & GENMASK(7, 0);
+ svsb->mdes = (svs->efuse[16] >> 8) & GENMASK(7, 0);
+ svsb->dcbdet = (svs->efuse[16] >> 16) & GENMASK(7, 0);
+ svsb->dcmdet = (svs->efuse[16] >> 24) & GENMASK(7, 0);
+ svsb->mtdes = (svs->efuse[17] >> 16) & GENMASK(7, 0);
+
+ if (ft_pgm <= 3)
+ svsb->volt_offset += 10;
+ else
+ svsb->volt_offset += 2;
+ break;
+ case SVS_CPU_BIG:
+ svsb->bdes = svs->efuse[18] & GENMASK(7, 0);
+ svsb->mdes = (svs->efuse[18] >> 8) & GENMASK(7, 0);
+ svsb->dcbdet = (svs->efuse[18] >> 16) & GENMASK(7, 0);
+ svsb->dcmdet = (svs->efuse[18] >> 24) & GENMASK(7, 0);
+ svsb->mtdes = svs->efuse[17] & GENMASK(7, 0);
+
+ if (ft_pgm <= 3)
+ svsb->volt_offset += 15;
+ else
+ svsb->volt_offset += 12;
+ break;
+ case SVS_CCI:
+ svsb->bdes = svs->efuse[4] & GENMASK(7, 0);
+ svsb->mdes = (svs->efuse[4] >> 8) & GENMASK(7, 0);
+ svsb->dcbdet = (svs->efuse[4] >> 16) & GENMASK(7, 0);
+ svsb->dcmdet = (svs->efuse[4] >> 24) & GENMASK(7, 0);
+ svsb->mtdes = (svs->efuse[5] >> 16) & GENMASK(7, 0);
+
+ if (ft_pgm <= 3)
+ svsb->volt_offset += 10;
+ else
+ svsb->volt_offset += 2;
+ break;
+ case SVS_GPU:
+ svsb->bdes = svs->efuse[6] & GENMASK(7, 0);
+ svsb->mdes = (svs->efuse[6] >> 8) & GENMASK(7, 0);
+ svsb->dcbdet = (svs->efuse[6] >> 16) & GENMASK(7, 0);
+ svsb->dcmdet = (svs->efuse[6] >> 24) & GENMASK(7, 0);
+ svsb->mtdes = svs->efuse[5] & GENMASK(7, 0);
+
+ if (ft_pgm >= 2) {
+ svsb->freq_base = 800000000; /* 800MHz */
+ svsb->dvt_fixed = 2;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (svsp->fake_efuse) {
+ svs->thermal_efuse[0] = 0x02873f69;
+ svs->thermal_efuse[1] = 0xa11d9142;
+ svs->thermal_efuse[2] = 0xa2526900;
+ } else {
+ /* Get thermal efuse by nvmem */
+ cell = nvmem_cell_get(svs->dev, "calibration-data");
+ if (IS_ERR(cell)) {
+ pr_err("no thermal efuse? disable mon mode\n");
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+ svsb->mode_support &= ~SVSB_MODE_MON;
+ }
+
+ return true;
+ }
+
+ svs->thermal_efuse = (u32 *)nvmem_cell_read(cell, &len);
+ nvmem_cell_put(cell);
+ }
+
+ /* Thermal efuse parsing */
+ tp.adc_ge_t = (svs->thermal_efuse[1] >> 22) & GENMASK(9, 0);
+ tp.adc_oe_t = (svs->thermal_efuse[1] >> 12) & GENMASK(9, 0);
+
+ tp.o_vtsmcu1 = (svs->thermal_efuse[0] >> 17) & GENMASK(8, 0);
+ tp.o_vtsmcu2 = (svs->thermal_efuse[0] >> 8) & GENMASK(8, 0);
+ tp.o_vtsmcu3 = svs->thermal_efuse[1] & GENMASK(8, 0);
+ tp.o_vtsmcu4 = (svs->thermal_efuse[2] >> 23) & GENMASK(8, 0);
+ tp.o_vtsmcu5 = (svs->thermal_efuse[2] >> 5) & GENMASK(8, 0);
+ tp.o_vtsabb = (svs->thermal_efuse[2] >> 14) & GENMASK(8, 0);
+
+ tp.degc_cali = (svs->thermal_efuse[0] >> 1) & GENMASK(5, 0);
+ tp.adc_cali_en_t = svs->thermal_efuse[0] & BIT(0);
+ tp.o_slope_sign = (svs->thermal_efuse[0] >> 7) & BIT(0);
+
+ tp.ts_id = (svs->thermal_efuse[1] >> 9) & BIT(0);
+ tp.o_slope = (svs->thermal_efuse[0] >> 26) & GENMASK(5, 0);
+
+ if (tp.adc_cali_en_t == 1) {
+ if (!tp.ts_id)
+ tp.o_slope = 0;
+
+ if ((tp.adc_ge_t < 265 || tp.adc_ge_t > 758) ||
+ (tp.adc_oe_t < 265 || tp.adc_oe_t > 758) ||
+ (tp.o_vtsmcu1 < -8 || tp.o_vtsmcu1 > 484) ||
+ (tp.o_vtsmcu2 < -8 || tp.o_vtsmcu2 > 484) ||
+ (tp.o_vtsmcu3 < -8 || tp.o_vtsmcu3 > 484) ||
+ (tp.o_vtsmcu4 < -8 || tp.o_vtsmcu4 > 484) ||
+ (tp.o_vtsmcu5 < -8 || tp.o_vtsmcu5 > 484) ||
+ (tp.o_vtsabb < -8 || tp.o_vtsabb > 484) ||
+ (tp.degc_cali < 1 || tp.degc_cali > 63)) {
+ pr_err("bad thermal efuse data, disable mon mode\n");
+ mon_mode_support = false;
+ }
+ } else {
+ pr_err("no thermal efuse data, disable mon mode\n");
+ mon_mode_support = false;
+ }
+
+ if (!mon_mode_support) {
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+ svsb->mode_support &= ~SVSB_MODE_MON;
+ }
+
+ return true;
+ }
+
+ tp.ge = ((tp.adc_ge_t - 512) * 10000) / 4096;
+ tp.oe = (tp.adc_oe_t - 512);
+ tp.gain = (10000 + tp.ge);
+
+ format[0] = (tp.o_vtsmcu1 + 3350 - tp.oe);
+ format[1] = (tp.o_vtsmcu2 + 3350 - tp.oe);
+ format[2] = (tp.o_vtsmcu3 + 3350 - tp.oe);
+ format[3] = (tp.o_vtsmcu4 + 3350 - tp.oe);
+ format[4] = (tp.o_vtsmcu5 + 3350 - tp.oe);
+ format[5] = (tp.o_vtsabb + 3350 - tp.oe);
+
+ for (i = 0; i < 6; i++)
+ x_roomt[i] = (((format[i] * 10000) / 4096) * 10000) / tp.gain;
+
+ temp0 = (10000 * 100000 / tp.gain) * 15 / 18;
+
+ if (!tp.o_slope_sign)
+ mts = (temp0 * 10) / (1534 + tp.o_slope * 10);
+ else
+ mts = (temp0 * 10) / (1534 - tp.o_slope * 10);
+
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+ svsb->mts = mts;
+
+ switch (svsb->sw_id) {
+ case SVS_CPU_LITTLE:
+ tb_roomt = x_roomt[3];
+ break;
+ case SVS_CPU_BIG:
+ tb_roomt = x_roomt[4];
+ break;
+ case SVS_CCI:
+ tb_roomt = x_roomt[3];
+ break;
+ case SVS_GPU:
+ tb_roomt = x_roomt[1];
+ break;
+ default:
+ break;
+ }
+
+ temp0 = (tp.degc_cali * 10 / 2);
+ temp1 = ((10000 * 100000 / 4096 / tp.gain) *
+ tp.oe + tb_roomt * 10) * 15 / 18;
+
+ if (!tp.o_slope_sign)
+ temp2 = temp1 * 100 / (1534 + tp.o_slope * 10);
+ else
+ temp2 = temp1 * 100 / (1534 - tp.o_slope * 10);
+
+ svsb->bts = (temp0 + temp2 - 250) * 4 / 10;
+ }
+
+ return true;
+}
+
+static bool svs_is_supported(struct mtk_svs *svs)
+{
+ const struct svs_platform *svsp = svs->platform;
+ struct nvmem_cell *cell;
+ size_t len;
+ bool ret;
+
+ if (svsp->fake_efuse) {
+ len = svsp->efuse_num * sizeof(u32);
+ svs->efuse = devm_kzalloc(svs->dev, len, GFP_KERNEL);
+ if (!svs->efuse) {
+ pr_err("no memory for allocating svs_efuse\n");
+ return false;
+ }
+
+ len = svsp->thermal_efuse_num * sizeof(u32);
+ svs->thermal_efuse = devm_kzalloc(svs->dev, len, GFP_KERNEL);
+ if (!svs->thermal_efuse) {
+ pr_err("no memory for allocating svs_thermal_efuse\n");
+ return false;
+ }
+
+ goto svsp_efuse_parsing;
+ }
+
+ /* Get svs efuse by nvmem */
+ cell = nvmem_cell_get(svs->dev, "svs-calibration-data");
+ if (IS_ERR(cell)) {
+ pr_err("no \"svs-calibration-data\" from dts? disable svs\n");
+ return false;
+ }
+
+ svs->efuse = (u32 *)nvmem_cell_read(cell, &len);
+ nvmem_cell_put(cell);
+
+ if (!svs->efuse[svsp->efuse_check]) {
+ pr_err("svs_efuse[%u] = 0x%x?\n",
+ svsp->efuse_check, svs->efuse[svsp->efuse_check]);
+ return false;
+ }
+
+svsp_efuse_parsing:
+ ret = svsp->efuse_parsing(svs);
+
+ return ret;
+}
+
+static int svs_resource_setup(struct mtk_svs *svs)
+{
+ const struct svs_platform *svsp = svs->platform;
+ struct svs_bank *svsb;
+ struct platform_device *pdev;
+ struct device_node *np = NULL;
+ struct dev_pm_opp *opp;
+ unsigned long freq;
+ int count, ret;
+ u32 idx, i;
+
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+
+ switch (svsb->sw_id) {
+ case SVS_CPU_LITTLE:
+ svsb->name = "SVS_CPU_LITTLE";
+ break;
+ case SVS_CPU_BIG:
+ svsb->name = "SVS_CPU_BIG";
+ break;
+ case SVS_CCI:
+ svsb->name = "SVS_CCI";
+ break;
+ case SVS_GPU:
+ svsb->name = "SVS_GPU";
+ break;
+ default:
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ /* Add svs bank device for opp-table/mtcmos/buck control */
+ pdev = platform_device_alloc(svsb->name, 0);
+ if (!pdev) {
+ pr_err("%s: fail to alloc pdev for svs_bank\n",
+ svsb->name);
+ return -ENOMEM;
+ }
+
+ for_each_child_of_node(svs->dev->of_node, np) {
+ if (of_device_is_compatible(np, svsb->of_compatible)) {
+ pdev->dev.of_node = np;
+ break;
+ }
+ }
+
+ ret = platform_device_add(pdev);
+ if (ret) {
+ pr_err("%s: fail to add svs_bank device: %d\n",
+ svsb->name, ret);
+ return ret;
+ }
+
+ svsb->dev = &pdev->dev;
+ dev_set_drvdata(svsb->dev, svs);
+ ret = dev_pm_opp_of_add_table(svsb->dev);
+ if (ret) {
+ pr_err("%s: fail to add opp table: %d\n",
+ svsb->name, ret);
+ return ret;
+ }
+
+ mutex_init(&svsb->lock);
+
+ svsb->buck = devm_regulator_get_optional(svsb->dev,
+ svsb->buck_name);
+ if (IS_ERR(svsb->buck)) {
+ pr_err("%s: cannot get regulator \"%s-supply\"\n",
+ svsb->name, svsb->buck_name);
+ return PTR_ERR(svsb->buck);
+ }
+
+ count = dev_pm_opp_get_opp_count(svsb->dev);
+ if (svsb->opp_count != count) {
+ pr_err("%s: opp_count not \"%u\" but get \"%d\"?\n",
+ svsb->name, svsb->opp_count, count);
+ return count;
+ }
+
+ for (i = 0, freq = U32_MAX; i < svsb->opp_count; i++, freq--) {
+ opp = dev_pm_opp_find_freq_floor(svsb->dev, &freq);
+ if (IS_ERR(opp)) {
+ pr_err("%s: error opp entry!!, err = %ld\n",
+ svsb->name, PTR_ERR(opp));
+ return PTR_ERR(opp);
+ }
+
+ svsb->opp_freqs[i] = freq;
+ svsb->opp_volts[i] = dev_pm_opp_get_voltage(opp);
+ svsb->freqs_pct[i] = percent(svsb->opp_freqs[i],
+ svsb->freq_base);
+ dev_pm_opp_put(opp);
+ }
+ }
+
+ return 0;
+}
+
+static int svs_suspend(struct device *dev)
+{
+ struct mtk_svs *svs = dev_get_drvdata(dev);
+ const struct svs_platform *svsp = svs->platform;
+ struct svs_bank *svsb;
+ unsigned long flags;
+ int ret;
+ u32 idx;
+
+ /* Wait if there is processing svs_isr(). Suspend all banks. */
+ flags = claim_mtk_svs_lock();
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+ svs->bank = svsb;
+ svs_switch_bank(svs);
+ svs_writel(svs, SVSEN_OFF, SVSEN);
+ svs_writel(svs, INTSTS_CLEAN, INTSTS);
+ svsb->suspended = true;
+ }
+ release_mtk_svs_lock(flags);
+
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+ if (svsb->phase != SVSB_PHASE_INIT01) {
+ svsb->phase = SVSB_PHASE_ERROR;
+ svsb_set_volts(svsb, true);
+ }
+ }
+
+ if (svsp->need_hw_reset) {
+ ret = device_reset(svs->dev);
+ if (ret) {
+ pr_err("%s: ret = %d\n", __func__, ret);
+ return ret;
+ }
+ }
+
+ clk_disable_unprepare(svs->main_clk);
+
+ return 0;
+}
+
+static int svs_resume(struct device *dev)
+{
+ struct mtk_svs *svs = dev_get_drvdata(dev);
+ const struct svs_platform *svsp = svs->platform;
+ struct svs_bank *svsb;
+ int ret;
+ u32 idx;
+
+ ret = clk_prepare_enable(svs->main_clk);
+ if (ret) {
+ pr_err("cannot enable main_clk, disable svs\n");
+ return ret;
+ }
+
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+ svsb->suspended = false;
+ }
+
+ ret = svs_init02(svs);
+ if (ret)
+ return ret;
+
+ svs_mon_mode(svs);
+
+ return 0;
+}
+
+static int svs_debug_proc_show(struct seq_file *m, void *v)
+{
+ struct svs_bank *svsb = (struct svs_bank *)m->private;
+
+ if (svsb->phase == SVSB_PHASE_INIT01)
+ seq_puts(m, "init1\n");
+ else if (svsb->phase == SVSB_PHASE_INIT02)
+ seq_puts(m, "init2\n");
+ else if (svsb->phase == SVSB_PHASE_MON)
+ seq_puts(m, "mon mode\n");
+ else if (svsb->phase == SVSB_PHASE_ERROR)
+ seq_puts(m, "disabled\n");
+ else
+ seq_puts(m, "unknown\n");
+
+ return 0;
+}
+
+static ssize_t svs_debug_proc_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *pos)
+{
+ struct svs_bank *svsb = (struct svs_bank *)PDE_DATA(file_inode(file));
+ struct mtk_svs *svs = dev_get_drvdata(svsb->dev);
+ unsigned long flags;
+ int enabled, ret;
+ char *buf = NULL;
+
+ if (count >= PAGE_SIZE)
+ return -EINVAL;
+
+ buf = (char *)memdup_user_nul(buffer, count);
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
+
+ ret = kstrtoint(buf, 10, &enabled);
+ if (ret)
+ return ret;
+
+ if (!enabled) {
+ flags = claim_mtk_svs_lock();
+ svs->bank = svsb;
+ svsb->mode_support = SVSB_MODE_ALL_DISABLE;
+ svs_switch_bank(svs);
+ svs_writel(svs, SVSEN_OFF, SVSEN);
+ svs_writel(svs, INTSTS_CLEAN, INTSTS);
+ release_mtk_svs_lock(flags);
+
+ svsb->phase = SVSB_PHASE_ERROR;
+ svsb_set_volts(svsb, true);
+ }
+
+ kfree(buf);
+
+ return count;
+}
+
+proc_fops_rw(svs_debug);
+
+static int svs_dump_proc_show(struct seq_file *m, void *v)
+{
+ struct mtk_svs *svs = (struct mtk_svs *)m->private;
+ const struct svs_platform *svsp = svs->platform;
+ struct svs_bank *svsb;
+ unsigned long svs_reg_addr;
+ u32 idx, i, j;
+
+ for (i = 0; i < svsp->efuse_num; i++)
+ if (svs->efuse && svs->efuse[i])
+ seq_printf(m, "M_HW_RES%d = 0x%08x\n",
+ i, svs->efuse[i]);
+
+ for (i = 0; i < svsp->thermal_efuse_num; i++)
+ if (svs->thermal_efuse)
+ seq_printf(m, "THERMAL_EFUSE%d = 0x%08x\n",
+ i, svs->thermal_efuse[i]);
+
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+
+ for (i = SVSB_PHASE_INIT01; i <= SVSB_PHASE_MON; i++) {
+ seq_printf(m, "Bank_number = %u\n", svsb->bank_id);
+
+ if (i < SVSB_PHASE_MON)
+ seq_printf(m, "mode = init%d\n", i + 1);
+ else
+ seq_puts(m, "mode = mon\n");
+
+ for (j = TEMPMONCTL0; j < reg_num; j++) {
+ svs_reg_addr = (unsigned long)(svs->base +
+ svsp->regs[j]);
+ seq_printf(m, "0x%08lx = 0x%08x\n",
+ svs_reg_addr, svsb->reg_data[i][j]);
+ }
+ }
+ }
+
+ return 0;
+}
+
+proc_fops_ro(svs_dump);
+
+static int svs_status_proc_show(struct seq_file *m, void *v)
+{
+ struct svs_bank *svsb = (struct svs_bank *)m->private;
+ struct dev_pm_opp *opp;
+ unsigned long freq;
+ int tzone_temp, ret;
+ u32 i;
+
+ ret = svsb_get_zone_temperature(svsb, &tzone_temp);
+ if (ret)
+ seq_printf(m, "%s: cannot get zone \"%s\" temperature\n",
+ svsb->name, svsb->tzone_name);
+ else
+ seq_printf(m, "%s: temperature = %d\n", svsb->name, tzone_temp);
+
+ for (i = 0, freq = U32_MAX; i < svsb->opp_count; i++, freq--) {
+ opp = dev_pm_opp_find_freq_floor(svsb->dev, &freq);
+ if (IS_ERR(opp)) {
+ seq_printf(m, "%s: error opp entry!!, err = %ld\n",
+ svsb->name, PTR_ERR(opp));
+ return PTR_ERR(opp);
+ }
+
+ seq_printf(m, "opp_freqs[%02u]: %lu, volts[%02u]: %lu, ",
+ i, freq, i, dev_pm_opp_get_voltage(opp));
+ seq_printf(m, "svsb_volts[%02u]: 0x%x, freqs_pct[%02u]: %u\n",
+ i, svsb->volts[i], i, svsb->freqs_pct[i]);
+ dev_pm_opp_put(opp);
+ }
+
+ return 0;
+}
+
+proc_fops_ro(svs_status);
+
+static int svs_volt_offset_proc_show(struct seq_file *m, void *v)
+{
+ struct svs_bank *svsb = (struct svs_bank *)m->private;
+
+ seq_printf(m, "%d\n", svsb->volt_offset);
+
+ return 0;
+}
+
+static ssize_t svs_volt_offset_proc_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *pos)
+{
+ struct svs_bank *svsb = (struct svs_bank *)PDE_DATA(file_inode(file));
+ char *buf = NULL;
+ s32 volt_offset;
+
+ if (count >= PAGE_SIZE)
+ return -EINVAL;
+
+ buf = (char *)memdup_user_nul(buffer, count);
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
+
+ if (!kstrtoint(buf, 10, &volt_offset)) {
+ svsb->volt_offset = volt_offset;
+ svsb_set_volts(svsb, true);
+ }
+
+ kfree(buf);
+
+ return count;
+}
+
+proc_fops_rw(svs_volt_offset);
+
+static int svs_create_svs_procfs(struct mtk_svs *svs)
+{
+ const struct svs_platform *svsp = svs->platform;
+ struct svs_bank *svsb;
+ struct proc_dir_entry *svs_dir, *bank_dir;
+ u32 idx, i;
+
+ struct pentry {
+ const char *name;
+ const struct proc_ops *fops;
+ };
+
+ struct pentry svs_entries[] = {
+ proc_entry(svs_dump),
+ };
+
+ struct pentry bank_entries[] = {
+ proc_entry(svs_debug),
+ proc_entry(svs_status),
+ proc_entry(svs_volt_offset),
+ };
+
+ svs_dir = proc_mkdir("svs", NULL);
+ if (!svs_dir) {
+ pr_err("mkdir /proc/svs failed\n");
+ return -EPERM;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(svs_entries); i++) {
+ if (!proc_create_data(svs_entries[i].name, 0664,
+ svs_dir, svs_entries[i].fops, svs)) {
+ pr_err("create /proc/svs/%s failed\n",
+ svs_entries[i].name);
+ return -EPERM;
+ }
+ }
+
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+
+ if (svsb->mode_support == SVSB_MODE_ALL_DISABLE)
+ continue;
+
+ bank_dir = proc_mkdir(svsb->name, svs_dir);
+ if (!bank_dir) {
+ pr_err("mkdir /proc/svs/%s failed\n", svsb->name);
+ return -EPERM;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(bank_entries); i++) {
+ if (!proc_create_data(bank_entries[i].name, 0664,
+ bank_dir, bank_entries[i].fops,
+ svsb)) {
+ pr_err("create /proc/svs/%s/%s failed\n",
+ svsb->name, bank_entries[i].name);
+ return -EPERM;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static struct svs_bank_ops svs_mt8183_banks_ops = {
+ .set_freqs_pct = svs_set_freqs_pct_v2,
+ .get_vops = svs_get_vops_v2,
+};
+
+static struct svs_bank svs_mt8183_banks[4] = {
+ {
+ .of_compatible = "mediatek,mt8183-svs-cpu-little",
+ .sw_id = SVS_CPU_LITTLE,
+ .bank_id = 0,
+ .ops = &svs_mt8183_banks_ops,
+ .tzone_name = "tzts4",
+ .buck_name = "vcpu-little",
+ .mtcmos_request = false,
+ .init01_volt_flag = SVSB_INIT01_VOLT_INC_ONLY,
+ .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02,
+ .opp_count = 16,
+ .freq_base = 1989000000,
+ .vboot = 0x30,
+ .volt_step = 6250,
+ .volt_base = 500000,
+ .volt_offset = 0,
+ .vmax = 0x64,
+ .vmin = 0x18,
+ .dthi = 0x1,
+ .dtlo = 0xfe,
+ .det_window = 0xa28,
+ .det_max = 0xffff,
+ .age_config = 0x555555,
+ .agem = 0,
+ .dc_config = 0x555555,
+ .dvt_fixed = 0x7,
+ .vco = 0x10,
+ .chk_shift = 0x77,
+ .upper_temp_bound = 0x64,
+ .lower_temp_bound = 0xb2,
+ .high_temp_threashold = HIGH_TEMP_MAX,
+ .low_temp_threashold = 25000,
+ .low_temp_offset = 0,
+ .core_sel = 0x8fff0000,
+ .systemclk_en = BIT(31),
+ .int_st = BIT(0),
+ .ctl0 = 0x00010001,
+ },
+ {
+ .of_compatible = "mediatek,mt8183-svs-cpu-big",
+ .sw_id = SVS_CPU_BIG,
+ .bank_id = 1,
+ .ops = &svs_mt8183_banks_ops,
+ .tzone_name = "tzts5",
+ .buck_name = "vcpu-big",
+ .mtcmos_request = false,
+ .init01_volt_flag = SVSB_INIT01_VOLT_INC_ONLY,
+ .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02,
+ .opp_count = 16,
+ .freq_base = 1989000000,
+ .vboot = 0x30,
+ .volt_step = 6250,
+ .volt_base = 500000,
+ .volt_offset = 0,
+ .vmax = 0x58,
+ .vmin = 0x10,
+ .dthi = 0x1,
+ .dtlo = 0xfe,
+ .det_window = 0xa28,
+ .det_max = 0xffff,
+ .age_config = 0x555555,
+ .agem = 0,
+ .dc_config = 0x555555,
+ .dvt_fixed = 0x7,
+ .vco = 0x10,
+ .chk_shift = 0x77,
+ .upper_temp_bound = 0x64,
+ .lower_temp_bound = 0xb2,
+ .high_temp_threashold = HIGH_TEMP_MAX,
+ .low_temp_threashold = 25000,
+ .low_temp_offset = 0,
+ .core_sel = 0x8fff0001,
+ .systemclk_en = BIT(31),
+ .int_st = BIT(1),
+ .ctl0 = 0x00000001,
+ },
+ {
+ .of_compatible = "mediatek,mt8183-svs-cci",
+ .sw_id = SVS_CCI,
+ .bank_id = 2,
+ .ops = &svs_mt8183_banks_ops,
+ .tzone_name = "tzts4",
+ .buck_name = "vcci",
+ .mtcmos_request = false,
+ .init01_volt_flag = SVSB_INIT01_VOLT_INC_ONLY,
+ .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02,
+ .opp_count = 16,
+ .freq_base = 1196000000,
+ .vboot = 0x30,
+ .volt_step = 6250,
+ .volt_base = 500000,
+ .volt_offset = 0,
+ .vmax = 0x64,
+ .vmin = 0x18,
+ .dthi = 0x1,
+ .dtlo = 0xfe,
+ .det_window = 0xa28,
+ .det_max = 0xffff,
+ .age_config = 0x555555,
+ .agem = 0,
+ .dc_config = 0x555555,
+ .dvt_fixed = 0x7,
+ .vco = 0x10,
+ .chk_shift = 0x77,
+ .upper_temp_bound = 0x64,
+ .lower_temp_bound = 0xb2,
+ .high_temp_threashold = HIGH_TEMP_MAX,
+ .low_temp_threashold = 25000,
+ .low_temp_offset = 0,
+ .core_sel = 0x8fff0002,
+ .systemclk_en = BIT(31),
+ .int_st = BIT(2),
+ .ctl0 = 0x00100003,
+ },
+ {
+ .of_compatible = "mediatek,mt8183-svs-gpu",
+ .sw_id = SVS_GPU,
+ .bank_id = 3,
+ .ops = &svs_mt8183_banks_ops,
+ .tzone_name = "tzts2",
+ .buck_name = "vgpu",
+ .mtcmos_request = true,
+ .init01_volt_flag = SVSB_INIT01_VOLT_INC_ONLY,
+ .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02 |
+ SVSB_MODE_MON,
+ .opp_count = 16,
+ .freq_base = 900000000,
+ .vboot = 0x30,
+ .volt_step = 6250,
+ .volt_base = 500000,
+ .volt_offset = 0,
+ .vmax = 0x40,
+ .vmin = 0x14,
+ .dthi = 0x1,
+ .dtlo = 0xfe,
+ .det_window = 0xa28,
+ .det_max = 0xffff,
+ .age_config = 0x555555,
+ .agem = 0,
+ .dc_config = 0x555555,
+ .dvt_fixed = 0x3,
+ .vco = 0x10,
+ .chk_shift = 0x77,
+ .upper_temp_bound = 0x64,
+ .lower_temp_bound = 0xb2,
+ .high_temp_threashold = HIGH_TEMP_MAX,
+ .low_temp_threashold = 25000,
+ .low_temp_offset = 3,
+ .core_sel = 0x8fff0003,
+ .systemclk_en = BIT(31),
+ .int_st = BIT(3),
+ .ctl0 = 0x00050001,
+ },
+};
+
+static const struct svs_platform svs_mt8183_platform = {
+ .name = "mt8183-svs",
+ .banks = svs_mt8183_banks,
+ .efuse_parsing = svs_mt8183_efuse_parsing,
+ .regs = svs_regs_v2,
+ .irqflags = IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ .need_hw_reset = false,
+ .fake_efuse = false,
+ .bank_num = 4,
+ .efuse_num = 25,
+ .efuse_check = 2,
+ .thermal_efuse_num = 3,
+};
+
+static const struct of_device_id mtk_svs_of_match[] = {
+ {
+ .compatible = "mediatek,mt8183-svs",
+ .data = &svs_mt8183_platform,
+ }, {
+ /* Sentinel */
+ },
+};
+
+static int svs_add_thermal_device_link(struct platform_device *svs_pdev)
+{
+ struct device_node *therm_node;
+ struct platform_device *therm_pdev;
+ struct device_link *sup_link;
+ char const *therm_node_name[] = {"thermal"};
+ u32 i;
+
+ for (i = 0; i < ARRAY_SIZE(therm_node_name); i++) {
+ therm_node = of_find_node_by_name(NULL, therm_node_name[i]);
+ if (therm_node)
+ break;
+ }
+
+ if (!therm_node) {
+ pr_err("no available thermal node? pass device link\n");
+ return 0;
+ }
+
+ therm_pdev = of_find_device_by_node(therm_node);
+ if (!therm_pdev) {
+ pr_err("no \"%pOF\" platform device? pass device link\n",
+ therm_node);
+ of_node_put(therm_node);
+ return 0;
+ }
+
+ of_node_put(therm_node);
+
+ sup_link = device_link_add(&svs_pdev->dev, &therm_pdev->dev,
+ DL_FLAG_AUTOREMOVE_CONSUMER);
+
+ if (sup_link->status == DL_STATE_DORMANT)
+ return -EPROBE_DEFER;
+
+ return 0;
+}
+
+static int svs_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *of_dev_id;
+ struct mtk_svs *svs;
+ int ret;
+ u32 svs_irq;
+
+ ret = svs_add_thermal_device_link(pdev);
+ if (ret)
+ return ret;
+
+ svs = devm_kzalloc(&pdev->dev, sizeof(*svs), GFP_KERNEL);
+ if (!svs)
+ return -ENOMEM;
+
+ svs->dev = &pdev->dev;
+ if (!svs->dev->of_node) {
+ pr_err("cannot find device node\n");
+ return -ENODEV;
+ }
+
+ svs->base = of_iomap(svs->dev->of_node, 0);
+ if (IS_ERR(svs->base)) {
+ pr_err("cannot find svs register base\n");
+ return PTR_ERR(svs->base);
+ }
+
+ of_dev_id = of_match_node(mtk_svs_of_match, svs->dev->of_node);
+ if (!of_dev_id || !of_dev_id->data)
+ return -EINVAL;
+
+ svs->platform = of_dev_id->data;
+ dev_set_drvdata(svs->dev, svs);
+
+ svs_irq = irq_of_parse_and_map(svs->dev->of_node, 0);
+ ret = devm_request_threaded_irq(svs->dev, svs_irq, NULL, svs_isr,
+ svs->platform->irqflags, "mtk-svs",
+ svs);
+ if (ret) {
+ pr_err("register irq(%d) failed: %d\n", svs_irq, ret);
+ return ret;
+ }
+
+ svs->main_clk = devm_clk_get(svs->dev, "main");
+ if (IS_ERR(svs->main_clk)) {
+ pr_err("failed to get clock: %ld\n", PTR_ERR(svs->main_clk));
+ return PTR_ERR(svs->main_clk);
+ }
+
+ ret = clk_prepare_enable(svs->main_clk);
+ if (ret) {
+ pr_err("cannot enable main clk: %d\n", ret);
+ return ret;
+ }
+
+ if (!svs_is_supported(svs)) {
+ pr_notice("svs is not supported\n");
+ ret = -EPERM;
+ goto svs_probe_fail;
+ }
+
+ ret = svs_resource_setup(svs);
+ if (ret)
+ goto svs_probe_fail;
+
+ ret = svs_start(svs);
+ if (ret)
+ goto svs_probe_fail;
+
+ ret = svs_create_svs_procfs(svs);
+ if (ret)
+ goto svs_probe_fail;
+
+ return 0;
+
+svs_probe_fail:
+ clk_disable_unprepare(svs->main_clk);
+
+ return ret;
+}
+
+static const struct dev_pm_ops svs_pm_ops = {
+ .suspend = svs_suspend,
+ .resume = svs_resume,
+};
+
+static struct platform_driver svs_driver = {
+ .probe = svs_probe,
+ .driver = {
+ .name = "mtk-svs",
+ .pm = &svs_pm_ops,
+ .of_match_table = of_match_ptr(mtk_svs_of_match),
+ },
+};
+
+static int __init svs_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&svs_driver);
+ if (ret) {
+ pr_err("svs platform driver register failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+late_initcall_sync(svs_init);
+
+MODULE_DESCRIPTION("MediaTek SVS Driver v1.0");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/power/mtk_svs.h b/include/linux/power/mtk_svs.h
new file mode 100644
index 000000000000..5c03982e3576
--- /dev/null
+++ b/include/linux/power/mtk_svs.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2020 MediaTek Inc.
+ */
+
+#ifndef __MTK_SVS_H__
+#define __MTK_SVS_H__
+
+#if IS_ENABLED(CONFIG_MTK_SVS)
+unsigned long claim_mtk_svs_lock(void);
+void release_mtk_svs_lock(unsigned long flags);
+#else
+static inline unsigned long claim_mtk_svs_lock(void)
+{
+ return 0;
+}
+
+static inline void release_mtk_svs_lock(unsigned long flags)
+{
+}
+#endif /* CONFIG_MTK_SVS */
+
+#endif /* __MTK_SVS_H__ */
--
2.18.0
^ permalink raw reply related
* Re: [PATCH 03/17] ARM: dts: r8a7742: Add I2C and IIC support
From: Wolfram Sang @ 2020-05-18 9:26 UTC (permalink / raw)
To: Lad, Prabhakar
Cc: Lad Prabhakar, Geert Uytterhoeven, Jens Axboe, Rob Herring,
Ulf Hansson, Sergei Shtylyov, David S. Miller, Wim Van Sebroeck,
Guenter Roeck, linux-ide,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, LKML,
linux-i2c, Linux MMC List, netdev, Linux-Renesas, linux-watchdog
In-Reply-To: <CA+V-a8t6rPs4s8uMCpBQEAUvwsVn7Cte-vX3z2atWRhy_RFLQw@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 641 bytes --]
> > However, both versions (with and without automatic transmission) are
> > described with the same "renesas,iic-r8a7742" compatible. Is it possible
> > to detect the reduced variant at runtime somehow?
> >
> I couldn't find anything the manual that would be useful to detect at runtime.
>
> > My concern is that the peculiarity of this SoC might be forgotten if we
> > describe it like this and ever add "automatic transmissions" somewhen.
> >
> Agreed.
Well, I guess reading from a register which is supposed to not be there
on the modified IP core is too hackish.
Leaves us with a seperate compatible entry for it?
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH 17/17] ARM: dts: r8a7742: Add RWDT node
From: Wolfram Sang @ 2020-05-18 9:28 UTC (permalink / raw)
To: Lad, Prabhakar
Cc: Lad Prabhakar, Geert Uytterhoeven, Jens Axboe, Rob Herring,
Ulf Hansson, Sergei Shtylyov, David S. Miller, Wim Van Sebroeck,
Guenter Roeck, linux-ide,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, LKML,
linux-i2c, Linux MMC List, netdev, Linux-Renesas, linux-watchdog
In-Reply-To: <CA+V-a8t1yJF=2+N+g=doVgFpZmtiRaZX-d_1=KGuWa3zYv9uPw@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 473 bytes --]
> Its similar to as seen on Rcar-H2 where just the A15 cores are up and
> A7 cores fail to boot. Attached is the boot log where reboot works as
> expected with all A15 core up. Although I have tested the internal
> release based on 3.10 where all the cores are up which used bootarg
> apmu=multicluster (https://patchwork.kernel.org/patch/3948791/). So
> there is some work involved to get all the A7's up and running.
Sounds good enough to me. Thanks for the heads up!
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH v2 2/2] media: cec: i2c: ch7322: Add ch7322 CEC controller driver
From: Hans Verkuil @ 2020-05-18 9:34 UTC (permalink / raw)
To: Jeff Chase, linux-media; +Cc: mchehab, robh+dt, devicetree
In-Reply-To: <20200515025159.101081-3-jnchase@google.com>
On 15/05/2020 04:51, Jeff Chase wrote:
> Add a CEC device driver for the Chrontel ch7322 CEC conroller.
> This is an I2C device capable of sending and receiving CEC messages.
>
> Signed-off-by: Jeff Chase <jnchase@google.com>
> ---
> MAINTAINERS | 1 +
> drivers/media/cec/Kconfig | 1 +
> drivers/media/cec/Makefile | 2 +-
> drivers/media/cec/i2c/Kconfig | 14 +
> drivers/media/cec/i2c/Makefile | 5 +
> drivers/media/cec/i2c/ch7322.c | 499 +++++++++++++++++++++++++++++++++
> 6 files changed, 521 insertions(+), 1 deletion(-)
> create mode 100644 drivers/media/cec/i2c/Kconfig
> create mode 100644 drivers/media/cec/i2c/Makefile
> create mode 100644 drivers/media/cec/i2c/ch7322.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 34c6d30e61e5..43e876395686 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -4053,6 +4053,7 @@ L: linux-media@vger.kernel.org
> S: Maintained
> T: git git://linuxtv.org/media_tree.git
> F: Documentation/devicetree/bindings/media/i2c/chontel,ch7322.yaml
> +F: drivers/media/cec/i2c/ch7322.c
>
> CIRRUS LOGIC AUDIO CODEC DRIVERS
> M: James Schulman <james.schulman@cirrus.com>
> diff --git a/drivers/media/cec/Kconfig b/drivers/media/cec/Kconfig
> index eea74b7cfa8c..3e934aa239ab 100644
> --- a/drivers/media/cec/Kconfig
> +++ b/drivers/media/cec/Kconfig
> @@ -33,6 +33,7 @@ menuconfig MEDIA_CEC_SUPPORT
> adapter that supports HDMI CEC.
>
> if MEDIA_CEC_SUPPORT
> +source "drivers/media/cec/i2c/Kconfig"
> source "drivers/media/cec/platform/Kconfig"
> source "drivers/media/cec/usb/Kconfig"
> endif
> diff --git a/drivers/media/cec/Makefile b/drivers/media/cec/Makefile
> index 74e80e1b3571..23539339bc81 100644
> --- a/drivers/media/cec/Makefile
> +++ b/drivers/media/cec/Makefile
> @@ -1,2 +1,2 @@
> # SPDX-License-Identifier: GPL-2.0
> -obj-y += core/ platform/ usb/
> +obj-y += core/ i2c/ platform/ usb/
> diff --git a/drivers/media/cec/i2c/Kconfig b/drivers/media/cec/i2c/Kconfig
> new file mode 100644
> index 000000000000..e445ca2110b3
> --- /dev/null
> +++ b/drivers/media/cec/i2c/Kconfig
> @@ -0,0 +1,14 @@
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# I2C drivers
> +
> +config CEC_CH7322
> + tristate "Chrontel CH7322 CEC controller"
> + select I2C
> + select REGMAP_I2C
> + select CEC_CORE
> + help
> + This is a driver for the Chrontel CH7322 CEC controller. It uses the
> + generic CEC framework interface.
> + CEC bus is present in the HDMI connector and enables communication
> + between compatible devices.
> diff --git a/drivers/media/cec/i2c/Makefile b/drivers/media/cec/i2c/Makefile
> new file mode 100644
> index 000000000000..d7496dfd0fa4
> --- /dev/null
> +++ b/drivers/media/cec/i2c/Makefile
> @@ -0,0 +1,5 @@
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# Makefile for the CEC I2C device drivers.
> +#
> +obj-$(CONFIG_CEC_CH7322) += ch7322.o
> diff --git a/drivers/media/cec/i2c/ch7322.c b/drivers/media/cec/i2c/ch7322.c
> new file mode 100644
> index 000000000000..40bc87ae5282
> --- /dev/null
> +++ b/drivers/media/cec/i2c/ch7322.c
> @@ -0,0 +1,499 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Driver for the Chrontel CH7322 CEC Controller
> + *
> + * Copyright 2020 Google LLC.
> + */
> +
> +/*
> + * Notes
> + *
> + * - This device powers on in Auto Mode which has limited functionality. This
> + * driver disables Auto Mode when it attaches.
> + *
> + */
> +
> +#include <linux/cec.h>
> +#include <linux/i2c.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/regmap.h>
> +#include <media/cec.h>
> +
> +#define CH7322_WRITE 0x00
> +#define CH7322_WRITE_MSENT 0x80
> +#define CH7322_WRITE_BOK 0x40
> +#define CH7322_WRITE_NMASK 0x0F
The coding style is to use lowercase for hex values. So 0x0f in this case.
> +
> +/* Write buffer is 0x01-0x10 */
> +#define CH7322_WRBUF 0x01
> +#define CH7322_WRBUF_LEN 0x10
> +
> +#define CH7322_READ 0x40
> +#define CH7322_READ_NRDT 0x80
> +#define CH7322_READ_MSENT 0x20
> +#define CH7322_READ_NMASK 0x0F
> +
> +/* Read buffer is 0x41-0x50 */
> +#define CH7322_RDBUF 0x41
> +#define CH7322_RDBUF_LEN 0x10
> +
> +#define CH7322_MODE 0x11
> +#define CH7322_MODE_AUTO 0x78
> +#define CH7322_MODE_SW 0xB5
> +
> +#define CH7322_RESET 0x12
> +#define CH7322_POWER 0x13
> +
> +#define CH7322_CFG0 0x17
> +#define CH7322_CFG0_EOBEN 0x40
> +#define CH7322_CFG0_PEOB 0x20
> +#define CH7322_CFG0_CLRSPP 0x10
> +#define CH7322_CFG0_FLOW 0x08
> +
> +#define CH7322_CFG1 0x1A
> +#define CH7322_CFG1_STDBYO 0x04
> +#define CH7322_CFG1_HPBP 0x02
> +#define CH7322_CFG1_PIO 0x01
> +
> +#define CH7322_INTCTL 0x1B
> +#define CH7322_INTCTL_INTPB 0x80
> +#define CH7322_INTCTL_STDBY 0x40
> +#define CH7322_INTCTL_HPDFALL 0x20
> +#define CH7322_INTCTL_HPDRISE 0x10
> +#define CH7322_INTCTL_RXMSG 0x08
> +#define CH7322_INTCTL_TXMSG 0x04
> +#define CH7322_INTCTL_NEWPHA 0x02
> +#define CH7322_INTCTL_ERROR 0x01
> +
> +#define CH7322_DVCLKFNH 0x1D
> +#define CH7322_DVCLKFNL 0x1E
> +
> +#define CH7322_CTL 0x31
> +#define CH7322_CTL_FSTDBY 0x80
> +#define CH7322_CTL_PLSEN 0x40
> +#define CH7322_CTL_PLSPB 0x20
> +#define CH7322_CTL_SPADL 0x10
> +#define CH7322_CTL_HINIT 0x08
> +#define CH7322_CTL_WPHYA 0x04
> +#define CH7322_CTL_H1T 0x02
> +#define CH7322_CTL_S1T 0x01
> +
> +#define CH7322_PAWH 0x32
> +#define CH7322_PAWL 0x33
> +
> +#define CH7322_ADDLW 0x34
> +#define CH7322_ADDLW_MASK 0xF0
> +
> +#define CH7322_ADDLR 0x3D
> +#define CH7322_ADDLR_HPD 0x80
> +#define CH7322_ADDLR_MASK 0x0F
> +
> +#define CH7322_INTDATA 0x3E
> +#define CH7322_INTDATA_MODE 0x80
> +#define CH7322_INTDATA_STDBY 0x40
> +#define CH7322_INTDATA_HPDFALL 0x20
> +#define CH7322_INTDATA_HPDRISE 0x10
> +#define CH7322_INTDATA_RXMSG 0x08
> +#define CH7322_INTDATA_TXMSG 0x04
> +#define CH7322_INTDATA_NEWPHA 0x02
> +#define CH7322_INTDATA_ERROR 0x01
> +
> +#define CH7322_EVENT 0x3F
> +#define CH7322_EVENT_TXERR 0x80
> +#define CH7322_EVENT_HRST 0x40
> +#define CH7322_EVENT_HFST 0x20
> +#define CH7322_EVENT_PHACHG 0x10
> +#define CH7322_EVENT_ACTST 0x08
> +#define CH7322_EVENT_PHARDY 0x04
> +#define CH7322_EVENT_BSOK 0x02
> +#define CH7322_EVENT_ERRADCF 0x01
> +
> +#define CH7322_DID 0x51
> +#define CH7322_DID_CH7322 0x5B
> +#define CH7322_DID_CH7323 0x5F
> +
> +#define CH7322_REVISIONID 0x52
> +
> +#define CH7322_PARH 0x53
> +#define CH7322_PARL 0x54
> +
> +#define CH7322_IOCFG2 0x75
> +#define CH7322_IOCFG_CIO 0x80
> +#define CH7322_IOCFG_IOCFGMASK 0x78
> +#define CH7322_IOCFG_AUDIO 0x04
> +#define CH7322_IOCFG_SPAMST 0x02
> +#define CH7322_IOCFG_SPAMSP 0x01
> +
> +#define CH7322_CTL3 0x7B
> +#define CH7322_CTL3_SWENA 0x80
> +#define CH7322_CTL3_FC_INIT 0x40
> +#define CH7322_CTL3_SML_FL 0x20
> +#define CH7322_CTL3_SM_RDST 0x10
> +#define CH7322_CTL3_SPP_CIAH 0x08
> +#define CH7322_CTL3_SPP_CIAL 0x04
> +#define CH7322_CTL3_SPP_ACTH 0x02
> +#define CH7322_CTL3_SPP_ACTL 0x01
> +
> +/* BOK status means NACK */
> +#define CH7322_TX_FLAG_NACK BIT(0)
> +/* Device will retry automatically */
> +#define CH7322_TX_FLAG_RETRY BIT(1)
> +
> +struct ch7322 {
> + struct i2c_client *i2c;
> + struct regmap *regmap;
> + struct cec_adapter *cec;
> + struct mutex mutex; /* device access mutex */
> + u8 tx_flags;
> +};
> +
> +static const struct regmap_config ch7322_regmap = {
> + .reg_bits = 8,
> + .val_bits = 8,
> + .max_register = 0x7F,
> + .disable_locking = true,
> +};
> +
> +static int ch7322_send_message(struct ch7322 *ch7322, const struct cec_msg *msg)
> +{
> + unsigned int val;
> + unsigned int len = msg->len;
> + int ret;
> + int i;
> +
> + WARN_ON(!mutex_is_locked(&ch7322->mutex));
> +
> + if (len > CH7322_WRBUF_LEN || len < 1)
> + return -EINVAL;
> +
> + ret = regmap_read(ch7322->regmap, CH7322_WRITE, &val);
> + if (ret)
> + return ret;
> +
> + /* Buffer not ready */
> + if (!(val & CH7322_WRITE_MSENT))
> + return -EBUSY;
> +
> + if (cec_msg_opcode(msg) == -1 &&
> + cec_msg_initiator(msg) == cec_msg_destination(msg)) {
> + ch7322->tx_flags = CH7322_TX_FLAG_NACK | CH7322_TX_FLAG_RETRY;
> + } else if (cec_msg_is_broadcast(msg)) {
> + ch7322->tx_flags = CH7322_TX_FLAG_NACK;
> + } else {
> + ch7322->tx_flags = CH7322_TX_FLAG_RETRY;
> + }
> +
> + ret = regmap_write(ch7322->regmap, CH7322_WRITE, len - 1);
> + if (ret)
> + return ret;
> +
> + for (i = 0; i < len; i++) {
> + ret = regmap_write(ch7322->regmap,
> + CH7322_WRBUF + i, msg->msg[i]);
> + if (ret)
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int ch7322_receive_message(struct ch7322 *ch7322, struct cec_msg *msg)
> +{
> + unsigned int val;
> + int ret = 0;
> + int i;
> +
> + WARN_ON(!mutex_is_locked(&ch7322->mutex));
> +
> + ret = regmap_read(ch7322->regmap, CH7322_READ, &val);
> + if (ret)
> + return ret;
> +
> + /* Message not ready */
> + if (!(val & CH7322_READ_NRDT))
> + return -EIO;
> +
> + msg->len = (val & CH7322_READ_NMASK) + 1;
> +
> + /* Read entire RDBUF to clear state */
> + for (i = 0; i < CH7322_RDBUF_LEN; i++) {
> + ret = regmap_read(ch7322->regmap, CH7322_RDBUF + i, &val);
> + if (ret)
> + return ret;
> + msg->msg[i] = (u8)val;
> + }
> +
> + return 0;
> +}
> +
> +static void ch7322_tx_done(struct ch7322 *ch7322)
> +{
> + int ret;
> + unsigned int val;
> + u8 status, flags;
> +
> + mutex_lock(&ch7322->mutex);
> + ret = regmap_read(ch7322->regmap, CH7322_WRITE, &val);
> + flags = ch7322->tx_flags;
> + mutex_unlock(&ch7322->mutex);
> +
> + /*
> + * The device returns a one-bit OK status which usually means ACK but
> + * actually means NACK when sending a logical address query or a
> + * broadcast.
> + */
> + if (ret)
> + status = CEC_TX_STATUS_ERROR;
> + else if ((val & CH7322_WRITE_BOK) && (flags & CH7322_TX_FLAG_NACK))
> + status = CEC_TX_STATUS_NACK;
> + else if (val & CH7322_WRITE_BOK)
> + status = CEC_TX_STATUS_OK;
> + else if (flags & CH7322_TX_FLAG_NACK)
> + status = CEC_TX_STATUS_OK;
> + else
> + status = CEC_TX_STATUS_NACK;
> +
> + if (status == CEC_TX_STATUS_NACK && (flags & CH7322_TX_FLAG_RETRY))
> + status |= CEC_TX_STATUS_MAX_RETRIES;
> +
> + cec_transmit_attempt_done(ch7322->cec, status);
> +}
> +
> +static void ch7322_rx_done(struct ch7322 *ch7322)
> +{
> + struct cec_msg msg;
> + int ret;
> +
> + mutex_lock(&ch7322->mutex);
> + ret = ch7322_receive_message(ch7322, &msg);
> + mutex_unlock(&ch7322->mutex);
> +
> + if (ret)
> + dev_err(&ch7322->i2c->dev, "cec receive error: %d\n", ret);
> + else
> + cec_received_msg(ch7322->cec, &msg);
> +}
> +
> +/*
> + * This device can either monitor the DDC lines to obtain the physical address
> + * or it can allow the host to program it. This driver lets the device obtain
> + * it.
> + */
> +static void ch7322_phys_addr(struct ch7322 *ch7322)
> +{
> + unsigned int pah, pal;
> + int ret = 0;
> +
> + mutex_lock(&ch7322->mutex);
> + ret |= regmap_read(ch7322->regmap, CH7322_PARH, &pah);
> + ret |= regmap_read(ch7322->regmap, CH7322_PARL, &pal);
> + mutex_unlock(&ch7322->mutex);
> +
> + if (ret)
> + dev_err(&ch7322->i2c->dev, "phys addr error\n");
> + else
> + cec_s_phys_addr(ch7322->cec, pal | (pah << 8), false);
> +}
> +
> +static void ch7322_handle_events(struct ch7322 *ch7322)
> +{
> + unsigned int data = 0;
> +
> + mutex_lock(&ch7322->mutex);
> + regmap_read(ch7322->regmap, CH7322_INTDATA, &data);
> + regmap_write(ch7322->regmap, CH7322_INTDATA, data);
> + mutex_unlock(&ch7322->mutex);
> +
> + if (data & CH7322_INTDATA_HPDFALL)
> + cec_phys_addr_invalidate(ch7322->cec);
> +
> + if (data & CH7322_INTDATA_TXMSG)
> + ch7322_tx_done(ch7322);
> +
> + if (data & CH7322_INTDATA_RXMSG)
> + ch7322_rx_done(ch7322);
> +
> + if (data & CH7322_INTDATA_NEWPHA)
> + ch7322_phys_addr(ch7322);
> +
> + if (data & CH7322_INTDATA_ERROR)
> + dev_dbg(&ch7322->i2c->dev, "unknown error\n");
> +}
> +
> +static irqreturn_t ch7322_irq(int irq, void *dev)
> +{
> + struct ch7322 *ch7322 = dev;
> +
> + ch7322_handle_events(ch7322);
> +
> + return IRQ_HANDLED;
> +}
> +
> +/* This device is always enabled */
> +static int ch7322_cec_adap_enable(struct cec_adapter *adap, bool enable)
> +{
I'd disable the interrupt here if enable is false.
There is a power down mode as well, so perhaps that's something that can be
done here too.
> + return 0;
> +}
> +
> +static int ch7322_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
> +{
> + struct ch7322 *ch7322 = cec_get_drvdata(adap);
> + int ret;
> +
> + mutex_lock(&ch7322->mutex);
> + ret = regmap_update_bits(ch7322->regmap, CH7322_ADDLW,
> + CH7322_ADDLW_MASK, log_addr << 4);
> + mutex_unlock(&ch7322->mutex);
If log_addr is CEC_LOG_ADDR_INVALID, then that means that the current
logical address configuration is to be cleared. In this case the logical
address is set to 0xf (unregistered/broadcast). That should mean that the
CEC device will not Ack any logical addresses, correct?
But it does receive broadcast messages and (I think) also messages from
other logical addresses, except that those will not be Acked by this
CEC adapter.
If it still receives messages from other LAs, then that means that you can
add the CEC_CAP_MONITOR_ALL capability. I.e., 'sudo cec-ctl -M' without
configuring anything should see all CEC traffic.
What is the default value of CH7322_ADDLW? It should start with 0xf as
the logical address (i.e. no received messages should be Acked).
Regards,
Hans
> +
> + return ret;
> +}
> +
> +static int ch7322_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
> + u32 signal_free_time, struct cec_msg *msg)
> +{
> + struct ch7322 *ch7322 = cec_get_drvdata(adap);
> + int ret;
> +
> + mutex_lock(&ch7322->mutex);
> + ret = ch7322_send_message(ch7322, msg);
> + mutex_unlock(&ch7322->mutex);
> +
> + return ret;
> +}
> +
> +static const struct cec_adap_ops ch7322_cec_adap_ops = {
> + .adap_enable = ch7322_cec_adap_enable,
> + .adap_log_addr = ch7322_cec_adap_log_addr,
> + .adap_transmit = ch7322_cec_adap_transmit,
> +};
> +
> +static int ch7322_probe(struct i2c_client *client)
> +{
> + struct ch7322 *ch7322;
> + int ret;
> + unsigned int val;
> +
> + ch7322 = devm_kzalloc(&client->dev, sizeof(*ch7322), GFP_KERNEL);
> + if (!ch7322)
> + return -ENOMEM;
> +
> + ch7322->regmap = devm_regmap_init_i2c(client, &ch7322_regmap);
> + if (IS_ERR(ch7322->regmap))
> + return PTR_ERR(ch7322->regmap);
> +
> + ret = regmap_read(ch7322->regmap, CH7322_DID, &val);
> + if (ret)
> + return ret;
> +
> + if (val != CH7322_DID_CH7322)
> + return -ENOTSUPP;
> +
> + mutex_init(&ch7322->mutex);
> + ch7322->i2c = client;
> + ch7322->tx_flags = 0;
> +
> + i2c_set_clientdata(client, ch7322);
> +
> + /* Disable auto mode */
> + ret = regmap_write(ch7322->regmap, CH7322_MODE, CH7322_MODE_SW);
> + if (ret)
> + goto err_mutex;
> +
> + /* Enable logical address register */
> + ret = regmap_update_bits(ch7322->regmap, CH7322_CTL,
> + CH7322_CTL_SPADL, CH7322_CTL_SPADL);
> + if (ret)
> + goto err_mutex;
> +
> + ch7322->cec = cec_allocate_adapter(&ch7322_cec_adap_ops, ch7322,
> + dev_name(&client->dev),
> + CEC_CAP_DEFAULTS, 1);
> +
> + if (IS_ERR(ch7322->cec)) {
> + ret = PTR_ERR(ch7322->cec);
> + goto err_mutex;
> + }
> +
> + ret = cec_register_adapter(ch7322->cec, &client->dev);
> + if (ret) {
> + cec_delete_adapter(ch7322->cec);
> + goto err_mutex;
> + }
> +
> + /* Configure and mask interrupt */
> + ret = regmap_write(ch7322->regmap, CH7322_CFG1, 0);
> + if (ret)
> + goto err_cec;
> +
> + ret = regmap_write(ch7322->regmap, CH7322_INTCTL, CH7322_INTCTL_INTPB);
> + if (ret)
> + goto err_cec;
> +
> + ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,
> + ch7322_irq,
> + IRQF_ONESHOT | IRQF_TRIGGER_RISING,
> + client->name, ch7322);
> + if (ret)
> + goto err_cec;
> +
> + ch7322_handle_events(ch7322);
> +
> + /* Unmask interrupt */
> + mutex_lock(&ch7322->mutex);
> + ret = regmap_write(ch7322->regmap, CH7322_INTCTL, 0xff);
> + mutex_unlock(&ch7322->mutex);
> +
> + if (ret)
> + goto err_cec;
> +
> + dev_info(&client->dev, "device registered\n");
> +
> + return 0;
> +
> +err_cec:
> + cec_unregister_adapter(ch7322->cec);
> +
> +err_mutex:
> + mutex_destroy(&ch7322->mutex);
> + return ret;
> +}
> +
> +static int ch7322_remove(struct i2c_client *client)
> +{
> + struct ch7322 *ch7322 = i2c_get_clientdata(client);
> +
> + /* Mask interrupt */
> + mutex_lock(&ch7322->mutex);
> + regmap_write(ch7322->regmap, CH7322_INTCTL, CH7322_INTCTL_INTPB);
> + mutex_unlock(&ch7322->mutex);
> +
> + cec_unregister_adapter(ch7322->cec);
> + mutex_destroy(&ch7322->mutex);
> +
> + dev_info(&client->dev, "device unregistered\n");
> +
> + return 0;
> +}
> +
> +static const struct of_device_id ch7322_of_match[] = {
> + { .compatible = "chrontel,ch7322", },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, ch7322_of_match);
> +
> +static struct i2c_driver ch7322_i2c_driver = {
> + .driver = {
> + .name = "ch7322",
> + .of_match_table = of_match_ptr(ch7322_of_match),
> + },
> + .probe_new = ch7322_probe,
> + .remove = ch7322_remove,
> +};
> +
> +module_i2c_driver(ch7322_i2c_driver);
> +
> +MODULE_DESCRIPTION("Chrontel CH7322 CEC Controller Driver");
> +MODULE_AUTHOR("Jeff Chase <jnchase@google.com>");
> +MODULE_LICENSE("GPL");
>
^ permalink raw reply
* Re: [PATCH] dt-bindings: reset: Convert i.MX reset to json-schema
From: Philipp Zabel @ 2020-05-18 9:41 UTC (permalink / raw)
To: Anson Huang, robh+dt, shawnguo, s.hauer, kernel, festevam,
devicetree, linux-arm-kernel, linux-kernel
Cc: Linux-imx
In-Reply-To: <1589250194-29441-1-git-send-email-Anson.Huang@nxp.com>
Hi Anson,
On Tue, 2020-05-12 at 10:23 +0800, Anson Huang wrote:
> Convert the i.MX reset binding to DT schema format using json-schema.
>
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
thank you for the conversion.
> ---
> .../devicetree/bindings/reset/fsl,imx-src.txt | 49 ------------------
> .../devicetree/bindings/reset/fsl,imx-src.yaml | 58 ++++++++++++++++++++++
> 2 files changed, 58 insertions(+), 49 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/reset/fsl,imx-src.txt
> create mode 100644 Documentation/devicetree/bindings/reset/fsl,imx-src.yaml
>
> diff --git a/Documentation/devicetree/bindings/reset/fsl,imx-src.txt b/Documentation/devicetree/bindings/reset/fsl,imx-src.txt
> deleted file mode 100644
> index 6ed79e6..0000000
> --- a/Documentation/devicetree/bindings/reset/fsl,imx-src.txt
> +++ /dev/null
> @@ -1,49 +0,0 @@
> -Freescale i.MX System Reset Controller
> -======================================
> -
> -Please also refer to reset.txt in this directory for common reset
> -controller binding usage.
> -
> -Required properties:
> -- compatible: Should be "fsl,<chip>-src"
> -- reg: should be register base and length as documented in the
> - datasheet
> -- interrupts: Should contain SRC interrupt and CPU WDOG interrupt,
> - in this order.
> -- #reset-cells: 1, see below
> -
> -example:
> -
> -src: src@20d8000 {
> - compatible = "fsl,imx6q-src";
> - reg = <0x020d8000 0x4000>;
> - interrupts = <0 91 0x04 0 96 0x04>;
> - #reset-cells = <1>;
> -};
> -
> -Specifying reset lines connected to IP modules
> -==============================================
> -
> -The system reset controller can be used to reset the GPU, VPU,
> -IPU, and OpenVG IP modules on i.MX5 and i.MX6 ICs. Those device
> -nodes should specify the reset line on the SRC in their resets
> -property, containing a phandle to the SRC device node and a
> -RESET_INDEX specifying which module to reset, as described in
> -reset.txt
> -
> -example:
> -
> - ipu1: ipu@2400000 {
> - resets = <&src 2>;
> - };
> - ipu2: ipu@2800000 {
> - resets = <&src 4>;
> - };
> -
> -The following RESET_INDEX values are valid for i.MX5:
> -GPU_RESET 0
> -VPU_RESET 1
> -IPU1_RESET 2
> -OPEN_VG_RESET 3
> -The following additional RESET_INDEX value is valid for i.MX6:
> -IPU2_RESET 4
> diff --git a/Documentation/devicetree/bindings/reset/fsl,imx-src.yaml b/Documentation/devicetree/bindings/reset/fsl,imx-src.yaml
> new file mode 100644
> index 0000000..276a533
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/reset/fsl,imx-src.yaml
> @@ -0,0 +1,58 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/reset/fsl,imx-src.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Freescale i.MX System Reset Controller
> +
> +maintainers:
> + - Philipp Zabel <p.zabel@pengutronix.de>
> +
> +description: |
> + The system reset controller can be used to reset the GPU, VPU,
> + IPU, and OpenVG IP modules on i.MX5 and i.MX6 ICs. Those device
> + nodes should specify the reset line on the SRC in their resets
> + property, containing a phandle to the SRC device node and a
> + RESET_INDEX specifying which module to reset, as described in
> + reset.txt
> +
> + The following RESET_INDEX values are valid for i.MX5:
> + GPU_RESET 0
> + VPU_RESET 1
> + IPU1_RESET 2
> + OPEN_VG_RESET 3
> + The following additional RESET_INDEX value is valid for i.MX6:
> + IPU2_RESET 4
> +
> +properties:
> + compatible:
> + items:
> + - const: "fsl,imx51-src"
"fsl,imx51-src" is the only compatible the driver matches on, but we
have these combinations on compatible SRCs in the device trees:
"fsl,imx50-src", "fsl,imx51-src"
"fsl,imx51-src"
"fsl,imx53-src", "fsl,imx51-src"
"fsl,imx6q-src", "fsl,imx51-src"
"fsl,imx6sl-src", "fsl,imx51-src"
"fsl,imx6sll-src", "fsl,imx51-src"
"fsl,imx6sx-src", "fsl,imx51-src"
"fsl,imx6ul-src", "fsl,imx51-src"
That could be described using oneOf and and an items list of const
values per SoC like in the qcom bindings.
regards
Philipp
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox