blob: f28636ca901550b76ea0df48e39c90b4e72dff42 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Christophe Leroyc0bc2a72018-03-16 17:21:01 +01002/*
3 * Copyright 2017 CS Systemes d'Information
Christophe Leroyc0bc2a72018-03-16 17:21:01 +01004 */
5
6#include <common.h>
Charles Freyea8de982020-02-19 16:50:15 +00007#include <env.h>
Christophe Leroy749c9aa2018-11-21 08:51:45 +00008#include <dm.h>
9#include <wdt.h>
Christophe Leroy26e8ebc2023-04-03 10:27:39 +020010#include <clock_legacy.h>
Christophe Leroyc0bc2a72018-03-16 17:21:01 +010011#include <asm/io.h>
12
Christophe Leroy26e8ebc2023-04-03 10:27:39 +020013struct mpc8xxx_wdt {
14 __be32 res0;
15 __be32 swcrr; /* System watchdog control register */
16#define SWCRR_SWTC 0xFFFF0000 /* Software Watchdog Time Count. */
17#define SWCRR_BME 0x00000080 /* Bus monitor enable (mpc8xx) */
18#define SWCRR_SWF 0x00000008 /* Software Watchdog Freeze (mpc8xx). */
19#define SWCRR_SWEN 0x00000004 /* Watchdog Enable bit. */
20#define SWCRR_SWRI 0x00000002 /* Software Watchdog Reset/Interrupt Select bit.*/
21#define SWCRR_SWPR 0x00000001 /* Software Watchdog Counter Prescale bit. */
22 __be32 swcnr; /* System watchdog count register */
23 u8 res1[2];
24 __be16 swsrr; /* System watchdog service register */
25 u8 res2[0xf0];
26};
Christophe Leroyc0bc2a72018-03-16 17:21:01 +010027
Christophe Leroy26e8ebc2023-04-03 10:27:39 +020028struct mpc8xxx_wdt_priv {
29 struct mpc8xxx_wdt __iomem *base;
30};
31
32static int mpc8xxx_wdt_reset(struct udevice *dev)
33{
34 struct mpc8xxx_wdt_priv *priv = dev_get_priv(dev);
35
36 out_be16(&priv->base->swsrr, 0x556c); /* write magic1 */
37 out_be16(&priv->base->swsrr, 0xaa39); /* write magic2 */
38
39 return 0;
Christophe Leroyc0bc2a72018-03-16 17:21:01 +010040}
41
Christophe Leroy21eaade2023-04-03 10:27:39 +020042static int mpc8xxx_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
Christophe Leroy749c9aa2018-11-21 08:51:45 +000043{
Christophe Leroy26e8ebc2023-04-03 10:27:39 +020044 struct mpc8xxx_wdt_priv *priv = dev_get_priv(dev);
Charles Freyea8de982020-02-19 16:50:15 +000045 const char *mode = env_get("watchdog_mode");
Christophe Leroy26e8ebc2023-04-03 10:27:39 +020046 ulong prescaler = dev_get_driver_data(dev);
47 u16 swtc = min_t(u16, timeout * get_board_sys_clk() / 1000 / prescaler, U16_MAX);
48 u32 val;
49
50 mpc8xxx_wdt_reset(dev);
Christophe Leroy749c9aa2018-11-21 08:51:45 +000051
Charles Freyea8de982020-02-19 16:50:15 +000052 if (strcmp(mode, "off") == 0)
Christophe Leroy26e8ebc2023-04-03 10:27:39 +020053 val = (swtc << 16) | SWCRR_SWPR;
Charles Freyea8de982020-02-19 16:50:15 +000054 else if (strcmp(mode, "nmi") == 0)
Christophe Leroy26e8ebc2023-04-03 10:27:39 +020055 val = (swtc << 16) | SWCRR_SWPR | SWCRR_SWEN;
56 else
57 val = (swtc << 16) | SWCRR_SWPR | SWCRR_SWEN | SWCRR_SWRI;
Charles Freyea8de982020-02-19 16:50:15 +000058
Christophe Leroy26e8ebc2023-04-03 10:27:39 +020059 if (IS_ENABLED(CONFIG_WDT_MPC8xxx_BME))
60 val |= (CONFIG_WDT_MPC8xxx_BMT << 8) | SWCRR_BME;
Christophe Leroy749c9aa2018-11-21 08:51:45 +000061
Christophe Leroy26e8ebc2023-04-03 10:27:39 +020062 out_be32(&priv->base->swcrr, val);
63
64 if (!(in_be32(&priv->base->swcrr) & SWCRR_SWEN))
Christophe Leroy749c9aa2018-11-21 08:51:45 +000065 return -EBUSY;
66 return 0;
67
68}
69
Christophe Leroy21eaade2023-04-03 10:27:39 +020070static int mpc8xxx_wdt_stop(struct udevice *dev)
Christophe Leroy749c9aa2018-11-21 08:51:45 +000071{
Christophe Leroy26e8ebc2023-04-03 10:27:39 +020072 struct mpc8xxx_wdt_priv *priv = dev_get_priv(dev);
Christophe Leroy749c9aa2018-11-21 08:51:45 +000073
Christophe Leroy26e8ebc2023-04-03 10:27:39 +020074 clrbits_be32(&priv->base->swcrr, SWCRR_SWEN);
Christophe Leroy749c9aa2018-11-21 08:51:45 +000075
Christophe Leroy26e8ebc2023-04-03 10:27:39 +020076 if (in_be32(&priv->base->swcrr) & SWCRR_SWEN)
Christophe Leroy749c9aa2018-11-21 08:51:45 +000077 return -EBUSY;
78 return 0;
79}
80
Christophe Leroy26e8ebc2023-04-03 10:27:39 +020081static int mpc8xxx_wdt_of_to_plat(struct udevice *dev)
Christophe Leroy749c9aa2018-11-21 08:51:45 +000082{
Christophe Leroy26e8ebc2023-04-03 10:27:39 +020083 struct mpc8xxx_wdt_priv *priv = dev_get_priv(dev);
84
85 priv->base = (void __iomem *)devfdt_remap_addr(dev);
86
87 if (!priv->base)
88 return -EINVAL;
Christophe Leroy749c9aa2018-11-21 08:51:45 +000089
90 return 0;
91}
92
Christophe Leroy21eaade2023-04-03 10:27:39 +020093static const struct wdt_ops mpc8xxx_wdt_ops = {
94 .start = mpc8xxx_wdt_start,
95 .reset = mpc8xxx_wdt_reset,
96 .stop = mpc8xxx_wdt_stop,
Christophe Leroy749c9aa2018-11-21 08:51:45 +000097};
98
Christophe Leroy21eaade2023-04-03 10:27:39 +020099static const struct udevice_id mpc8xxx_wdt_ids[] = {
Christophe Leroy26e8ebc2023-04-03 10:27:39 +0200100 { .compatible = "fsl,pq1-wdt", .data = 0x800 },
Christophe Leroy0fd79132023-04-03 10:39:59 +0200101 { .compatible = "fsl,pq2pro-wdt", .data = 0x10000 },
Christophe Leroy749c9aa2018-11-21 08:51:45 +0000102 {}
103};
104
Christophe Leroy21eaade2023-04-03 10:27:39 +0200105U_BOOT_DRIVER(wdt_mpc8xxx) = {
106 .name = "wdt_mpc8xxx",
Christophe Leroy749c9aa2018-11-21 08:51:45 +0000107 .id = UCLASS_WDT,
Christophe Leroy21eaade2023-04-03 10:27:39 +0200108 .of_match = mpc8xxx_wdt_ids,
109 .ops = &mpc8xxx_wdt_ops,
Christophe Leroy26e8ebc2023-04-03 10:27:39 +0200110 .of_to_plat = mpc8xxx_wdt_of_to_plat,
111 .priv_auto = sizeof(struct mpc8xxx_wdt_priv),
Christophe Leroy749c9aa2018-11-21 08:51:45 +0000112};