blob: 3601ba93774730f78574b2fd74b8c513e7ce22e1 [file] [log] [blame]
Casey Connolly8ea99b82025-04-23 02:19:39 +00001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2014, The Linux Foundation. All rights reserved.
4 * Copyright (c) Linaro Ltd. 2024
5 *
6 * Authors:
7 * Casey Connolly <casey.connolly@linaro.org>
8 * Paul Sajna <hello@paulsajna.com>
9 *
10 * Derived from linux/drivers/watchdog/qcom-wdt.c
11 */
12
13#include <dm.h>
14#include <dm/device_compat.h>
15#include <wdt.h>
16
17#include <asm/io.h>
18
19enum wdt_reg {
20 WDT_RST,
21 WDT_EN,
22 WDT_STS,
23 WDT_BARK_TIME,
24 WDT_BITE_TIME,
25};
26
27struct qcom_wdt_match_data {
28 const u32 *offset;
29};
30
31struct qcom_wdt {
32 void __iomem *base;
33 const u32 *layout;
34};
35
36static const u32 reg_offset_data_kpss[] = {
37 [WDT_RST] = 0x4,
38 [WDT_EN] = 0x8,
39 [WDT_STS] = 0xC,
40 [WDT_BARK_TIME] = 0x10,
41 [WDT_BITE_TIME] = 0x14,
42};
43
44static const struct qcom_wdt_match_data match_data_kpss = {
45 .offset = reg_offset_data_kpss,
46};
47
48static void __iomem *wdt_addr(struct qcom_wdt *wdt, enum wdt_reg reg)
49{
50 return wdt->base + wdt->layout[reg];
51}
52
53int qcom_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
54{
55 struct qcom_wdt *wdt = dev_get_priv(dev);
56
57 writel(0, wdt_addr(wdt, WDT_EN));
58 writel(1, wdt_addr(wdt, WDT_RST));
59 writel(1, wdt_addr(wdt, WDT_EN));
60 if (readl(wdt_addr(wdt, WDT_EN)) != 1) {
61 dev_err(dev, "Failed to enable Qualcomm watchdog!\n");
62 return -EIO;
63 }
64 return 0;
65}
66
67int qcom_wdt_stop(struct udevice *dev)
68{
69 struct qcom_wdt *wdt = dev_get_priv(dev);
70
71 writel(0, wdt_addr(wdt, WDT_EN));
72 if (readl(wdt_addr(wdt, WDT_EN))) {
73 dev_err(dev, "Failed to disable Qualcomm watchdog!\n");
74 return -EIO;
75 }
76
77 return 0;
78}
79
80int qcom_wdt_reset(struct udevice *dev)
81{
82 struct qcom_wdt *wdt = dev_get_priv(dev);
83
84 writel(1, wdt_addr(wdt, WDT_RST));
85 return 0;
86}
87
88static int qcom_wdt_probe(struct udevice *dev)
89{
90 struct qcom_wdt *wdt = dev_get_priv(dev);
91 struct qcom_wdt_match_data *data = (void *)dev_get_driver_data(dev);
92
93 wdt->base = dev_read_addr_ptr(dev);
94 wdt->layout = data->offset;
95
96 return 0;
97}
98
99static const struct wdt_ops qcom_wdt_ops = {
100 .start = qcom_wdt_start,
101 .stop = qcom_wdt_stop,
102 .reset = qcom_wdt_reset,
103};
104
105static const struct udevice_id qcom_wdt_ids[] = {
106 { .compatible = "qcom,kpss-wdt", .data = (ulong)&match_data_kpss },
107 {}
108};
109
110U_BOOT_DRIVER(qcom_wdt) = {
111 .name = "qcom_wdt",
112 .id = UCLASS_WDT,
113 .of_match = qcom_wdt_ids,
114 .ops = &qcom_wdt_ops,
115 .probe = qcom_wdt_probe,
116 .priv_auto = sizeof(struct qcom_wdt),
117};