The watchdog controller on the Meson-A/C series SoCs is moved to secure world,
We have to call SMC instruction to trap the ATF for watchdog operation. These
operations are different from previous SoCs, so we introduce a new watchdog
driver to support this kind of SoCs.
Changes since v2 at [1]:
- remove useless dependency in Kconfig
- return zero when getting left time value fails
Changes since v1 at [0]:
- add a new dependency in Kconfig
- simplify/add the return operation
- remove useless ping operation when setting the timeout
- fix some return values
- fix the license statement
[0]:https://lore.kernel.org/linux-amlogic/[email protected]
[1]:https://lore.kernel.org/linux-amlogic/[email protected]
Xingyu Chen (4):
firmware: meson_sm: add new SMC ID support for accessing secure
watchdog
dt-bindings: watchdog: add new binding for meson secure watchdog
watchdog: add meson secure watchdog driver
arm64: dts: a1: add secure watchdog controller
.../bindings/watchdog/amlogic,meson-sec-wdt.yaml | 34 ++++
arch/arm64/boot/dts/amlogic/meson-a1.dtsi | 6 +
drivers/firmware/meson/meson_sm.c | 1 +
drivers/watchdog/Kconfig | 16 ++
drivers/watchdog/Makefile | 1 +
drivers/watchdog/meson_sec_wdt.c | 187 +++++++++++++++++++++
include/linux/firmware/meson/meson_sm.h | 1 +
7 files changed, 246 insertions(+)
create mode 100644 Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml
create mode 100644 drivers/watchdog/meson_sec_wdt.c
--
2.7.4
The binding targets the Meson-A/C series compatible SoCs, in which the
watchdog registers are in secure world.
Signed-off-by: Xingyu Chen <[email protected]>
---
.../bindings/watchdog/amlogic,meson-sec-wdt.yaml | 34 ++++++++++++++++++++++
1 file changed, 34 insertions(+)
create mode 100644 Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml
diff --git a/Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml b/Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml
new file mode 100644
index 00000000..0bbc807
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+# Copyright (c) 2019 Amlogic, Inc
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/power/amlogic,meson-sec-wdt.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Amlogic Meson Secure Watchdog Timer
+
+maintainers:
+ - Xingyu Chen <[email protected]>
+
+description: |+
+ Secure Watchdog Timer used in Meson-A/C series Compatible SoCs
+
+properties:
+ compatible:
+ enum:
+ - amlogic,meson-sec-wdt
+
+ secure-monitor:
+ description: phandle to the secure-monitor node
+ $ref: /schemas/types.yaml#/definitions/phandle
+
+required:
+ - compatible
+ - secure-monitor
+
+examples:
+ - |
+ watchdog {
+ compatible = "amlogic,meson-sec-wdt";
+ secure-monitor = <&sm>;
+ };
--
2.7.4
Enable secure watchdog controller for Meson-A1 SoC
Signed-off-by: Xingyu Chen <[email protected]>
---
arch/arm64/boot/dts/amlogic/meson-a1.dtsi | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-a1.dtsi b/arch/arm64/boot/dts/amlogic/meson-a1.dtsi
index 7210ad0..047c323 100644
--- a/arch/arm64/boot/dts/amlogic/meson-a1.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-a1.dtsi
@@ -93,6 +93,12 @@
clock-names = "xtal", "pclk", "baud";
status = "disabled";
};
+
+ watchdog {
+ compatible = "amlogic,meson-sec-wdt";
+ secure-monitor = <&sm>;
+ status = "okay";
+ };
};
gic: interrupt-controller@ff901000 {
--
2.7.4
The new SMC ID is used to access secure registers by meson secure
watchdog driver.
Signed-off-by: Xingyu Chen <[email protected]>
---
drivers/firmware/meson/meson_sm.c | 1 +
include/linux/firmware/meson/meson_sm.h | 1 +
2 files changed, 2 insertions(+)
diff --git a/drivers/firmware/meson/meson_sm.c b/drivers/firmware/meson/meson_sm.c
index 1d5b4d7..46a44de 100644
--- a/drivers/firmware/meson/meson_sm.c
+++ b/drivers/firmware/meson/meson_sm.c
@@ -44,6 +44,7 @@ static const struct meson_sm_chip gxbb_chip = {
CMD(SM_EFUSE_WRITE, 0x82000031),
CMD(SM_EFUSE_USER_MAX, 0x82000033),
CMD(SM_GET_CHIP_ID, 0x82000044),
+ CMD(SM_WATCHDOG_OPS, 0x82000086),
{ /* sentinel */ },
},
};
diff --git a/include/linux/firmware/meson/meson_sm.h b/include/linux/firmware/meson/meson_sm.h
index 6669e2a..0934718 100644
--- a/include/linux/firmware/meson/meson_sm.h
+++ b/include/linux/firmware/meson/meson_sm.h
@@ -12,6 +12,7 @@ enum {
SM_EFUSE_WRITE,
SM_EFUSE_USER_MAX,
SM_GET_CHIP_ID,
+ SM_WATCHDOG_OPS,
};
struct meson_sm_firmware;
--
2.7.4
The watchdog controller on the Meson-A/C series SoCs is moved to secure
world, watchdog operation needs to be done in secure EL3 mode via ATF,
Non-secure world can call SMC instruction to trap to AFT for watchdog
operation.
Signed-off-by: Xingyu Chen <[email protected]>
---
drivers/watchdog/Kconfig | 16 ++++
drivers/watchdog/Makefile | 1 +
drivers/watchdog/meson_sec_wdt.c | 187 +++++++++++++++++++++++++++++++++++++++
3 files changed, 204 insertions(+)
create mode 100644 drivers/watchdog/meson_sec_wdt.c
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 58e7c10..e305fba 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -826,6 +826,22 @@ config MESON_GXBB_WATCHDOG
To compile this driver as a module, choose M here: the
module will be called meson_gxbb_wdt.
+config MESON_SEC_WATCHDOG
+ tristate "Amlogic Meson Secure watchdog support"
+ depends on MESON_SM
+ select WATCHDOG_CORE
+ help
+ The watchdog controller on the Meson-A/C series SoCs is moved to
+ secure world, watchdog operation needs to be done in secure EL3
+ mode via ATF, non-secure world can call SMC instruction to trap
+ to ATF for the watchdog operation.
+
+ Say Y here if watchdog controller on Meson SoCs is located in
+ secure world.
+
+ To compile this driver as a module, choose M here: the
+ module will be called meson_sec_wdt.
+
config MESON_WATCHDOG
tristate "Amlogic Meson SoCs watchdog support"
depends on ARCH_MESON || COMPILE_TEST
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 2ee352b..5e6b73d 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -78,6 +78,7 @@ obj-$(CONFIG_QCOM_WDT) += qcom-wdt.o
obj-$(CONFIG_BCM_KONA_WDT) += bcm_kona_wdt.o
obj-$(CONFIG_TEGRA_WATCHDOG) += tegra_wdt.o
obj-$(CONFIG_MESON_GXBB_WATCHDOG) += meson_gxbb_wdt.o
+obj-$(CONFIG_MESON_SEC_WATCHDOG) += meson_sec_wdt.o
obj-$(CONFIG_MESON_WATCHDOG) += meson_wdt.o
obj-$(CONFIG_MEDIATEK_WATCHDOG) += mtk_wdt.o
obj-$(CONFIG_DIGICOLOR_WATCHDOG) += digicolor_wdt.o
diff --git a/drivers/watchdog/meson_sec_wdt.c b/drivers/watchdog/meson_sec_wdt.c
new file mode 100644
index 00000000..a20657d
--- /dev/null
+++ b/drivers/watchdog/meson_sec_wdt.c
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
+ * Author: Xingyu Chen <[email protected]>
+ *
+ */
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/watchdog.h>
+#include <linux/firmware/meson/meson_sm.h>
+
+#define MESON_SIP_WDT_DISABLE 0x1
+#define MESON_SIP_WDT_ENABLE 0x2
+#define MESON_SIP_WDT_PING 0x3
+#define MESON_SIP_WDT_INIT 0x4
+#define MESON_SIP_WDT_RESETNOW 0x5
+#define MESON_SIP_WDT_SETTIMEOUT 0x6
+#define MESON_SIP_WDT_GETTIMELEFT 0x7
+
+#define DEFAULT_TIMEOUT 30 /* seconds */
+
+/*
+ * Watchdog timer tick is set to 1ms in secfw side, and tick count is
+ * stored in the bit[16-31] of WATCHDOG_CNT register, so the maximum
+ * timeout value is 0xffff ms.
+ */
+#define MAX_TIMEOUT_MS 0xFFFF
+
+struct meson_sec_wdt {
+ struct watchdog_device wdt_dev;
+ struct meson_sm_firmware *fw;
+};
+
+static int meson_sec_wdt_start(struct watchdog_device *wdt_dev)
+{
+ struct meson_sec_wdt *data = watchdog_get_drvdata(wdt_dev);
+
+ return meson_sm_call(data->fw, SM_WATCHDOG_OPS, NULL,
+ MESON_SIP_WDT_ENABLE, 0, 0, 0, 0);
+}
+
+static int meson_sec_wdt_stop(struct watchdog_device *wdt_dev)
+{
+ struct meson_sec_wdt *data = watchdog_get_drvdata(wdt_dev);
+
+ return meson_sm_call(data->fw, SM_WATCHDOG_OPS, NULL,
+ MESON_SIP_WDT_DISABLE, 0, 0, 0, 0);
+}
+
+static int meson_sec_wdt_ping(struct watchdog_device *wdt_dev)
+{
+ struct meson_sec_wdt *data = watchdog_get_drvdata(wdt_dev);
+
+ return meson_sm_call(data->fw, SM_WATCHDOG_OPS, NULL,
+ MESON_SIP_WDT_PING, 0, 0, 0, 0);
+}
+
+static int meson_sec_wdt_set_timeout(struct watchdog_device *wdt_dev,
+ unsigned int timeout)
+{
+ struct meson_sec_wdt *data = watchdog_get_drvdata(wdt_dev);
+
+ wdt_dev->timeout = timeout;
+
+ return meson_sm_call(data->fw, SM_WATCHDOG_OPS, NULL,
+ MESON_SIP_WDT_SETTIMEOUT,
+ wdt_dev->timeout, 0, 0, 0);
+}
+
+static unsigned int meson_sec_wdt_get_timeleft(struct watchdog_device *wdt_dev)
+{
+ int ret;
+ unsigned int timeleft;
+ struct meson_sec_wdt *data = watchdog_get_drvdata(wdt_dev);
+
+ ret = meson_sm_call(data->fw, SM_WATCHDOG_OPS, &timeleft,
+ MESON_SIP_WDT_GETTIMELEFT, 0, 0, 0, 0);
+
+ if (ret)
+ return 0;
+
+ return timeleft;
+}
+
+static const struct watchdog_ops meson_sec_wdt_ops = {
+ .start = meson_sec_wdt_start,
+ .stop = meson_sec_wdt_stop,
+ .ping = meson_sec_wdt_ping,
+ .set_timeout = meson_sec_wdt_set_timeout,
+ .get_timeleft = meson_sec_wdt_get_timeleft,
+};
+
+static const struct watchdog_info meson_sec_wdt_info = {
+ .identity = "Meson Secure Watchdog Timer",
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+};
+
+static int __maybe_unused meson_sec_wdt_resume(struct device *dev)
+{
+ struct meson_sec_wdt *data = dev_get_drvdata(dev);
+
+ if (watchdog_active(&data->wdt_dev))
+ return meson_sec_wdt_start(&data->wdt_dev);
+
+ return 0;
+}
+
+static int __maybe_unused meson_sec_wdt_suspend(struct device *dev)
+{
+ struct meson_sec_wdt *data = dev_get_drvdata(dev);
+
+ if (watchdog_active(&data->wdt_dev))
+ return meson_sec_wdt_stop(&data->wdt_dev);
+
+ return 0;
+}
+
+static const struct dev_pm_ops meson_sec_wdt_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(meson_sec_wdt_suspend, meson_sec_wdt_resume)
+};
+
+static const struct of_device_id meson_sec_wdt_dt_ids[] = {
+ { .compatible = "amlogic,meson-sec-wdt", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, meson_sec_wdt_dt_ids);
+
+static int meson_sec_wdt_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct meson_sec_wdt *data;
+ struct device_node *sm_np;
+ int ret;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ sm_np = of_parse_phandle(pdev->dev.of_node, "secure-monitor", 0);
+ if (!sm_np) {
+ dev_err(&pdev->dev, "no secure-monitor node\n");
+ return -EINVAL;
+ }
+
+ data->fw = meson_sm_get(sm_np);
+ of_node_put(sm_np);
+ if (!data->fw)
+ return -EPROBE_DEFER;
+
+ platform_set_drvdata(pdev, data);
+
+ data->wdt_dev.parent = dev;
+ data->wdt_dev.info = &meson_sec_wdt_info;
+ data->wdt_dev.ops = &meson_sec_wdt_ops;
+ data->wdt_dev.max_hw_heartbeat_ms = MAX_TIMEOUT_MS;
+ data->wdt_dev.min_timeout = 1;
+ data->wdt_dev.timeout = DEFAULT_TIMEOUT;
+ watchdog_set_drvdata(&data->wdt_dev, data);
+
+ ret = meson_sm_call(data->fw, SM_WATCHDOG_OPS, NULL,
+ MESON_SIP_WDT_INIT,
+ data->wdt_dev.timeout, 0, 0, 0);
+ if (ret)
+ return ret;
+
+ watchdog_stop_on_reboot(&data->wdt_dev);
+
+ return devm_watchdog_register_device(dev, &data->wdt_dev);
+}
+
+static struct platform_driver meson_sec_wdt_driver = {
+ .probe = meson_sec_wdt_probe,
+ .driver = {
+ .name = "meson-sec-wdt",
+ .pm = &meson_sec_wdt_pm_ops,
+ .of_match_table = meson_sec_wdt_dt_ids,
+ },
+};
+
+module_platform_driver(meson_sec_wdt_driver);
+
+MODULE_AUTHOR("Xingyu Chen <[email protected]>");
+MODULE_DESCRIPTION("Amlogic Secure Watchdog Timer Driver");
+MODULE_LICENSE("Dual MIT/GPL");
--
2.7.4
On Fri, Oct 25, 2019 at 02:13:02PM +0800, Xingyu Chen wrote:
> The binding targets the Meson-A/C series compatible SoCs, in which the
> watchdog registers are in secure world.
>
> Signed-off-by: Xingyu Chen <[email protected]>
> ---
> .../bindings/watchdog/amlogic,meson-sec-wdt.yaml | 34 ++++++++++++++++++++++
> 1 file changed, 34 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml
>
> diff --git a/Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml b/Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml
> new file mode 100644
> index 00000000..0bbc807
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml
> @@ -0,0 +1,34 @@
> +# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +# Copyright (c) 2019 Amlogic, Inc
> +%YAML 1.2
> +---
> +$id: "http://devicetree.org/schemas/power/amlogic,meson-sec-wdt.yaml#"
> +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
> +
> +title: Amlogic Meson Secure Watchdog Timer
> +
> +maintainers:
> + - Xingyu Chen <[email protected]>
> +
> +description: |+
> + Secure Watchdog Timer used in Meson-A/C series Compatible SoCs
> +
> +properties:
> + compatible:
> + enum:
> + - amlogic,meson-sec-wdt
If there are no other properties, then you don't need this. Just have
the secure firmware driver instantiate the watchdog.
> +
> + secure-monitor:
> + description: phandle to the secure-monitor node
> + $ref: /schemas/types.yaml#/definitions/phandle
> +
> +required:
> + - compatible
> + - secure-monitor
> +
> +examples:
> + - |
> + watchdog {
> + compatible = "amlogic,meson-sec-wdt";
> + secure-monitor = <&sm>;
> + };
> --
> 2.7.4
>
Hi, Rob
On 2019/10/26 4:30, Rob Herring wrote:
> On Fri, Oct 25, 2019 at 02:13:02PM +0800, Xingyu Chen wrote:
>> The binding targets the Meson-A/C series compatible SoCs, in which the
>> watchdog registers are in secure world.
>>
>> Signed-off-by: Xingyu Chen <[email protected]>
>> ---
>> .../bindings/watchdog/amlogic,meson-sec-wdt.yaml | 34 ++++++++++++++++++++++
>> 1 file changed, 34 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml b/Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml
>> new file mode 100644
>> index 00000000..0bbc807
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml
>> @@ -0,0 +1,34 @@
>> +# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>> +# Copyright (c) 2019 Amlogic, Inc
>> +%YAML 1.2
>> +---
>> +$id: "http://devicetree.org/schemas/power/amlogic,meson-sec-wdt.yaml#"
>> +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
>> +
>> +title: Amlogic Meson Secure Watchdog Timer
>> +
>> +maintainers:
>> + - Xingyu Chen <[email protected]>
>> +
>> +description: |+
>> + Secure Watchdog Timer used in Meson-A/C series Compatible SoCs
>> +
>> +properties:
>> + compatible:
>> + enum:
>> + - amlogic,meson-sec-wdt
>
> If there are no other properties, then you don't need this. Just have
> the secure firmware driver instantiate the watchdog.
I'am very sorry i don't understand how to initialize the watchdog driver
if the compatible property is removed, Could you give me more
suggestions or examples ? Thank you very much.
>
>> +
>> + secure-monitor:
>> + description: phandle to the secure-monitor node
>> + $ref: /schemas/types.yaml#/definitions/phandle
>> +
>> +required:
>> + - compatible
>> + - secure-monitor
>> +
>> +examples:
>> + - |
>> + watchdog {
>> + compatible = "amlogic,meson-sec-wdt";
>> + secure-monitor = <&sm>;
>> + };
>> --
>> 2.7.4
>>
>
> .
>
On Mon, Oct 28, 2019 at 3:35 AM Xingyu Chen <[email protected]> wrote:
>
> Hi, Rob
>
> On 2019/10/26 4:30, Rob Herring wrote:
> > On Fri, Oct 25, 2019 at 02:13:02PM +0800, Xingyu Chen wrote:
> >> The binding targets the Meson-A/C series compatible SoCs, in which the
> >> watchdog registers are in secure world.
> >>
> >> Signed-off-by: Xingyu Chen <[email protected]>
> >> ---
> >> .../bindings/watchdog/amlogic,meson-sec-wdt.yaml | 34 ++++++++++++++++++++++
> >> 1 file changed, 34 insertions(+)
> >> create mode 100644 Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml
> >>
> >> diff --git a/Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml b/Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml
> >> new file mode 100644
> >> index 00000000..0bbc807
> >> --- /dev/null
> >> +++ b/Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml
> >> @@ -0,0 +1,34 @@
> >> +# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> >> +# Copyright (c) 2019 Amlogic, Inc
> >> +%YAML 1.2
> >> +---
> >> +$id: "http://devicetree.org/schemas/power/amlogic,meson-sec-wdt.yaml#"
> >> +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
> >> +
> >> +title: Amlogic Meson Secure Watchdog Timer
> >> +
> >> +maintainers:
> >> + - Xingyu Chen <[email protected]>
> >> +
> >> +description: |+
> >> + Secure Watchdog Timer used in Meson-A/C series Compatible SoCs
> >> +
> >> +properties:
> >> + compatible:
> >> + enum:
> >> + - amlogic,meson-sec-wdt
> >
> > If there are no other properties, then you don't need this. Just have
> > the secure firmware driver instantiate the watchdog.
> I'am very sorry i don't understand how to initialize the watchdog driver
> if the compatible property is removed, Could you give me more
> suggestions or examples ? Thank you very much.
platform_device_register_simple() from the secure firmware driver.
Rob
Hi,Rob
On 2019/10/30 4:51, Rob Herring wrote:
> On Mon, Oct 28, 2019 at 3:35 AM Xingyu Chen <[email protected]> wrote:
>>
>> Hi, Rob
>>
>> On 2019/10/26 4:30, Rob Herring wrote:
>>> On Fri, Oct 25, 2019 at 02:13:02PM +0800, Xingyu Chen wrote:
>>>> The binding targets the Meson-A/C series compatible SoCs, in which the
>>>> watchdog registers are in secure world.
>>>>
>>>> Signed-off-by: Xingyu Chen <[email protected]>
>>>> ---
>>>> .../bindings/watchdog/amlogic,meson-sec-wdt.yaml | 34 ++++++++++++++++++++++
>>>> 1 file changed, 34 insertions(+)
>>>> create mode 100644 Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml b/Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml
>>>> new file mode 100644
>>>> index 00000000..0bbc807
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml
>>>> @@ -0,0 +1,34 @@
>>>> +# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>>>> +# Copyright (c) 2019 Amlogic, Inc
>>>> +%YAML 1.2
>>>> +---
>>>> +$id: "http://devicetree.org/schemas/power/amlogic,meson-sec-wdt.yaml#"
>>>> +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
>>>> +
>>>> +title: Amlogic Meson Secure Watchdog Timer
>>>> +
>>>> +maintainers:
>>>> + - Xingyu Chen <[email protected]>
>>>> +
>>>> +description: |+
>>>> + Secure Watchdog Timer used in Meson-A/C series Compatible SoCs
>>>> +
>>>> +properties:
>>>> + compatible:
>>>> + enum:
>>>> + - amlogic,meson-sec-wdt
>>>
>>> If there are no other properties, then you don't need this. Just have
>>> the secure firmware driver instantiate the watchdog.
>> I'am very sorry i don't understand how to initialize the watchdog driver
>> if the compatible property is removed, Could you give me more
>> suggestions or examples ? Thank you very much.
>
> platform_device_register_simple() from the secure firmware driver.
Thanks for your help. The device node of wdt looks useless if I use this
function to register device. if so, how should I get the pointer to
secure-monitor in wdt driver ? or should I use directly arm_smccc to
access the secfw ?
>
> Rob
>
> .
>
On Wed, Oct 30, 2019 at 7:59 AM Xingyu Chen <[email protected]> wrote:
>
> Hi,Rob
>
> On 2019/10/30 4:51, Rob Herring wrote:
> > On Mon, Oct 28, 2019 at 3:35 AM Xingyu Chen <[email protected]> wrote:
> >>
> >> Hi, Rob
> >>
> >> On 2019/10/26 4:30, Rob Herring wrote:
> >>> On Fri, Oct 25, 2019 at 02:13:02PM +0800, Xingyu Chen wrote:
> >>>> The binding targets the Meson-A/C series compatible SoCs, in which the
> >>>> watchdog registers are in secure world.
> >>>>
> >>>> Signed-off-by: Xingyu Chen <[email protected]>
> >>>> ---
> >>>> .../bindings/watchdog/amlogic,meson-sec-wdt.yaml | 34 ++++++++++++++++++++++
> >>>> 1 file changed, 34 insertions(+)
> >>>> create mode 100644 Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml
> >>>>
> >>>> diff --git a/Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml b/Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml
> >>>> new file mode 100644
> >>>> index 00000000..0bbc807
> >>>> --- /dev/null
> >>>> +++ b/Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml
> >>>> @@ -0,0 +1,34 @@
> >>>> +# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> >>>> +# Copyright (c) 2019 Amlogic, Inc
> >>>> +%YAML 1.2
> >>>> +---
> >>>> +$id: "http://devicetree.org/schemas/power/amlogic,meson-sec-wdt.yaml#"
> >>>> +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
> >>>> +
> >>>> +title: Amlogic Meson Secure Watchdog Timer
> >>>> +
> >>>> +maintainers:
> >>>> + - Xingyu Chen <[email protected]>
> >>>> +
> >>>> +description: |+
> >>>> + Secure Watchdog Timer used in Meson-A/C series Compatible SoCs
> >>>> +
> >>>> +properties:
> >>>> + compatible:
> >>>> + enum:
> >>>> + - amlogic,meson-sec-wdt
> >>>
> >>> If there are no other properties, then you don't need this. Just have
> >>> the secure firmware driver instantiate the watchdog.
> >> I'am very sorry i don't understand how to initialize the watchdog driver
> >> if the compatible property is removed, Could you give me more
> >> suggestions or examples ? Thank you very much.
> >
> > platform_device_register_simple() from the secure firmware driver.
> Thanks for your help. The device node of wdt looks useless if I use this
> function to register device. if so, how should I get the pointer to
> secure-monitor in wdt driver ? or should I use directly arm_smccc to
> access the secfw ?
You can use of_find_compatible_node(). There should only be one firmware node.
Rob
Hi, Rob
On 2019/10/30 21:41, Rob Herring wrote:
> On Wed, Oct 30, 2019 at 7:59 AM Xingyu Chen <[email protected]> wrote:
>>
>> Hi,Rob
>>
>> On 2019/10/30 4:51, Rob Herring wrote:
>>> On Mon, Oct 28, 2019 at 3:35 AM Xingyu Chen <[email protected]> wrote:
>>>>
>>>> Hi, Rob
>>>>
>>>> On 2019/10/26 4:30, Rob Herring wrote:
>>>>> On Fri, Oct 25, 2019 at 02:13:02PM +0800, Xingyu Chen wrote:
>>>>>> The binding targets the Meson-A/C series compatible SoCs, in which the
>>>>>> watchdog registers are in secure world.
>>>>>>
>>>>>> Signed-off-by: Xingyu Chen <[email protected]>
>>>>>> ---
>>>>>> .../bindings/watchdog/amlogic,meson-sec-wdt.yaml | 34 ++++++++++++++++++++++
>>>>>> 1 file changed, 34 insertions(+)
>>>>>> create mode 100644 Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml
>>>>>>
>>>>>> diff --git a/Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml b/Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml
>>>>>> new file mode 100644
>>>>>> index 00000000..0bbc807
>>>>>> --- /dev/null
>>>>>> +++ b/Documentation/devicetree/bindings/watchdog/amlogic,meson-sec-wdt.yaml
>>>>>> @@ -0,0 +1,34 @@
>>>>>> +# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>>>>>> +# Copyright (c) 2019 Amlogic, Inc
>>>>>> +%YAML 1.2
>>>>>> +---
>>>>>> +$id: "http://devicetree.org/schemas/power/amlogic,meson-sec-wdt.yaml#"
>>>>>> +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
>>>>>> +
>>>>>> +title: Amlogic Meson Secure Watchdog Timer
>>>>>> +
>>>>>> +maintainers:
>>>>>> + - Xingyu Chen <[email protected]>
>>>>>> +
>>>>>> +description: |+
>>>>>> + Secure Watchdog Timer used in Meson-A/C series Compatible SoCs
>>>>>> +
>>>>>> +properties:
>>>>>> + compatible:
>>>>>> + enum:
>>>>>> + - amlogic,meson-sec-wdt
>>>>>
>>>>> If there are no other properties, then you don't need this. Just have
>>>>> the secure firmware driver instantiate the watchdog.
>>>> I'am very sorry i don't understand how to initialize the watchdog driver
>>>> if the compatible property is removed, Could you give me more
>>>> suggestions or examples ? Thank you very much.
>>>
>>> platform_device_register_simple() from the secure firmware driver.
>> Thanks for your help. The device node of wdt looks useless if I use this
>> function to register device. if so, how should I get the pointer to
>> secure-monitor in wdt driver ? or should I use directly arm_smccc to
>> access the secfw ?
>
> You can use of_find_compatible_node(). There should only be one firmware node.
Thanks for your answer.
I seem to miss something about registration of watchdog device. The
secure watchdog driver is used only to A1/C1 compatible SoCs, but is not
support for previous SoCs (Eg: gxl axg).
I have to think about platform difference If I use the
platform_device_register_simple() to register the wdt device in secure
fw driver, because fw driver is compatible with all known SoCs, but the
secure wdt driver is only compatible with some SoCs. In other
words, the registered wdt device is useless for gxl or axg.
There is no such problem If I use the DT to describe the wdt device.
>
> Rob
>
> .
>
On Fri, Oct 25, 2019 at 02:13:03PM +0800, Xingyu Chen wrote:
> The watchdog controller on the Meson-A/C series SoCs is moved to secure
> world, watchdog operation needs to be done in secure EL3 mode via ATF,
> Non-secure world can call SMC instruction to trap to AFT for watchdog
> operation.
>
> Signed-off-by: Xingyu Chen <[email protected]>
For my reference:
Reviewed-by: Guenter Roeck <[email protected]>
Note to self and Wim: Do not apply until instantiation issues are resolved.
> ---
> drivers/watchdog/Kconfig | 16 ++++
> drivers/watchdog/Makefile | 1 +
> drivers/watchdog/meson_sec_wdt.c | 187 +++++++++++++++++++++++++++++++++++++++
> 3 files changed, 204 insertions(+)
> create mode 100644 drivers/watchdog/meson_sec_wdt.c
>
> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> index 58e7c10..e305fba 100644
> --- a/drivers/watchdog/Kconfig
> +++ b/drivers/watchdog/Kconfig
> @@ -826,6 +826,22 @@ config MESON_GXBB_WATCHDOG
> To compile this driver as a module, choose M here: the
> module will be called meson_gxbb_wdt.
>
> +config MESON_SEC_WATCHDOG
> + tristate "Amlogic Meson Secure watchdog support"
> + depends on MESON_SM
> + select WATCHDOG_CORE
> + help
> + The watchdog controller on the Meson-A/C series SoCs is moved to
> + secure world, watchdog operation needs to be done in secure EL3
> + mode via ATF, non-secure world can call SMC instruction to trap
> + to ATF for the watchdog operation.
> +
> + Say Y here if watchdog controller on Meson SoCs is located in
> + secure world.
> +
> + To compile this driver as a module, choose M here: the
> + module will be called meson_sec_wdt.
> +
> config MESON_WATCHDOG
> tristate "Amlogic Meson SoCs watchdog support"
> depends on ARCH_MESON || COMPILE_TEST
> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
> index 2ee352b..5e6b73d 100644
> --- a/drivers/watchdog/Makefile
> +++ b/drivers/watchdog/Makefile
> @@ -78,6 +78,7 @@ obj-$(CONFIG_QCOM_WDT) += qcom-wdt.o
> obj-$(CONFIG_BCM_KONA_WDT) += bcm_kona_wdt.o
> obj-$(CONFIG_TEGRA_WATCHDOG) += tegra_wdt.o
> obj-$(CONFIG_MESON_GXBB_WATCHDOG) += meson_gxbb_wdt.o
> +obj-$(CONFIG_MESON_SEC_WATCHDOG) += meson_sec_wdt.o
> obj-$(CONFIG_MESON_WATCHDOG) += meson_wdt.o
> obj-$(CONFIG_MEDIATEK_WATCHDOG) += mtk_wdt.o
> obj-$(CONFIG_DIGICOLOR_WATCHDOG) += digicolor_wdt.o
> diff --git a/drivers/watchdog/meson_sec_wdt.c b/drivers/watchdog/meson_sec_wdt.c
> new file mode 100644
> index 00000000..a20657d
> --- /dev/null
> +++ b/drivers/watchdog/meson_sec_wdt.c
> @@ -0,0 +1,187 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
> + * Author: Xingyu Chen <[email protected]>
> + *
> + */
> +#include <linux/err.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/types.h>
> +#include <linux/watchdog.h>
> +#include <linux/firmware/meson/meson_sm.h>
> +
> +#define MESON_SIP_WDT_DISABLE 0x1
> +#define MESON_SIP_WDT_ENABLE 0x2
> +#define MESON_SIP_WDT_PING 0x3
> +#define MESON_SIP_WDT_INIT 0x4
> +#define MESON_SIP_WDT_RESETNOW 0x5
> +#define MESON_SIP_WDT_SETTIMEOUT 0x6
> +#define MESON_SIP_WDT_GETTIMELEFT 0x7
> +
> +#define DEFAULT_TIMEOUT 30 /* seconds */
> +
> +/*
> + * Watchdog timer tick is set to 1ms in secfw side, and tick count is
> + * stored in the bit[16-31] of WATCHDOG_CNT register, so the maximum
> + * timeout value is 0xffff ms.
> + */
> +#define MAX_TIMEOUT_MS 0xFFFF
> +
> +struct meson_sec_wdt {
> + struct watchdog_device wdt_dev;
> + struct meson_sm_firmware *fw;
> +};
> +
> +static int meson_sec_wdt_start(struct watchdog_device *wdt_dev)
> +{
> + struct meson_sec_wdt *data = watchdog_get_drvdata(wdt_dev);
> +
> + return meson_sm_call(data->fw, SM_WATCHDOG_OPS, NULL,
> + MESON_SIP_WDT_ENABLE, 0, 0, 0, 0);
> +}
> +
> +static int meson_sec_wdt_stop(struct watchdog_device *wdt_dev)
> +{
> + struct meson_sec_wdt *data = watchdog_get_drvdata(wdt_dev);
> +
> + return meson_sm_call(data->fw, SM_WATCHDOG_OPS, NULL,
> + MESON_SIP_WDT_DISABLE, 0, 0, 0, 0);
> +}
> +
> +static int meson_sec_wdt_ping(struct watchdog_device *wdt_dev)
> +{
> + struct meson_sec_wdt *data = watchdog_get_drvdata(wdt_dev);
> +
> + return meson_sm_call(data->fw, SM_WATCHDOG_OPS, NULL,
> + MESON_SIP_WDT_PING, 0, 0, 0, 0);
> +}
> +
> +static int meson_sec_wdt_set_timeout(struct watchdog_device *wdt_dev,
> + unsigned int timeout)
> +{
> + struct meson_sec_wdt *data = watchdog_get_drvdata(wdt_dev);
> +
> + wdt_dev->timeout = timeout;
> +
> + return meson_sm_call(data->fw, SM_WATCHDOG_OPS, NULL,
> + MESON_SIP_WDT_SETTIMEOUT,
> + wdt_dev->timeout, 0, 0, 0);
> +}
> +
> +static unsigned int meson_sec_wdt_get_timeleft(struct watchdog_device *wdt_dev)
> +{
> + int ret;
> + unsigned int timeleft;
> + struct meson_sec_wdt *data = watchdog_get_drvdata(wdt_dev);
> +
> + ret = meson_sm_call(data->fw, SM_WATCHDOG_OPS, &timeleft,
> + MESON_SIP_WDT_GETTIMELEFT, 0, 0, 0, 0);
> +
> + if (ret)
> + return 0;
> +
> + return timeleft;
> +}
> +
> +static const struct watchdog_ops meson_sec_wdt_ops = {
> + .start = meson_sec_wdt_start,
> + .stop = meson_sec_wdt_stop,
> + .ping = meson_sec_wdt_ping,
> + .set_timeout = meson_sec_wdt_set_timeout,
> + .get_timeleft = meson_sec_wdt_get_timeleft,
> +};
> +
> +static const struct watchdog_info meson_sec_wdt_info = {
> + .identity = "Meson Secure Watchdog Timer",
> + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
> +};
> +
> +static int __maybe_unused meson_sec_wdt_resume(struct device *dev)
> +{
> + struct meson_sec_wdt *data = dev_get_drvdata(dev);
> +
> + if (watchdog_active(&data->wdt_dev))
> + return meson_sec_wdt_start(&data->wdt_dev);
> +
> + return 0;
> +}
> +
> +static int __maybe_unused meson_sec_wdt_suspend(struct device *dev)
> +{
> + struct meson_sec_wdt *data = dev_get_drvdata(dev);
> +
> + if (watchdog_active(&data->wdt_dev))
> + return meson_sec_wdt_stop(&data->wdt_dev);
> +
> + return 0;
> +}
> +
> +static const struct dev_pm_ops meson_sec_wdt_pm_ops = {
> + SET_SYSTEM_SLEEP_PM_OPS(meson_sec_wdt_suspend, meson_sec_wdt_resume)
> +};
> +
> +static const struct of_device_id meson_sec_wdt_dt_ids[] = {
> + { .compatible = "amlogic,meson-sec-wdt", },
> + { /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(of, meson_sec_wdt_dt_ids);
> +
> +static int meson_sec_wdt_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct meson_sec_wdt *data;
> + struct device_node *sm_np;
> + int ret;
> +
> + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
> + if (!data)
> + return -ENOMEM;
> +
> + sm_np = of_parse_phandle(pdev->dev.of_node, "secure-monitor", 0);
> + if (!sm_np) {
> + dev_err(&pdev->dev, "no secure-monitor node\n");
> + return -EINVAL;
> + }
> +
> + data->fw = meson_sm_get(sm_np);
> + of_node_put(sm_np);
> + if (!data->fw)
> + return -EPROBE_DEFER;
> +
> + platform_set_drvdata(pdev, data);
> +
> + data->wdt_dev.parent = dev;
> + data->wdt_dev.info = &meson_sec_wdt_info;
> + data->wdt_dev.ops = &meson_sec_wdt_ops;
> + data->wdt_dev.max_hw_heartbeat_ms = MAX_TIMEOUT_MS;
> + data->wdt_dev.min_timeout = 1;
> + data->wdt_dev.timeout = DEFAULT_TIMEOUT;
> + watchdog_set_drvdata(&data->wdt_dev, data);
> +
> + ret = meson_sm_call(data->fw, SM_WATCHDOG_OPS, NULL,
> + MESON_SIP_WDT_INIT,
> + data->wdt_dev.timeout, 0, 0, 0);
> + if (ret)
> + return ret;
> +
> + watchdog_stop_on_reboot(&data->wdt_dev);
> +
> + return devm_watchdog_register_device(dev, &data->wdt_dev);
> +}
> +
> +static struct platform_driver meson_sec_wdt_driver = {
> + .probe = meson_sec_wdt_probe,
> + .driver = {
> + .name = "meson-sec-wdt",
> + .pm = &meson_sec_wdt_pm_ops,
> + .of_match_table = meson_sec_wdt_dt_ids,
> + },
> +};
> +
> +module_platform_driver(meson_sec_wdt_driver);
> +
> +MODULE_AUTHOR("Xingyu Chen <[email protected]>");
> +MODULE_DESCRIPTION("Amlogic Secure Watchdog Timer Driver");
> +MODULE_LICENSE("Dual MIT/GPL");