1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright 2017 CS Systemes d'Information 4 */ 5 6#include <common.h> 7#include <env.h> 8#include <dm.h> 9#include <wdt.h> 10#include <clock_legacy.h> 11#include <asm/io.h> 12 13struct 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}; 27 28struct 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; 40} 41 42static int mpc8xxx_wdt_start(struct udevice *dev, u64 timeout, ulong flags) 43{ 44 struct mpc8xxx_wdt_priv *priv = dev_get_priv(dev); 45 const char *mode = env_get("watchdog_mode"); 46 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); 51 52 if (strcmp(mode, "off") == 0) 53 val = (swtc << 16) | SWCRR_SWPR; 54 else if (strcmp(mode, "nmi") == 0) 55 val = (swtc << 16) | SWCRR_SWPR | SWCRR_SWEN; 56 else 57 val = (swtc << 16) | SWCRR_SWPR | SWCRR_SWEN | SWCRR_SWRI; 58 59 if (IS_ENABLED(CONFIG_WDT_MPC8xxx_BME)) 60 val |= (CONFIG_WDT_MPC8xxx_BMT << 8) | SWCRR_BME; 61 62 out_be32(&priv->base->swcrr, val); 63 64 if (!(in_be32(&priv->base->swcrr) & SWCRR_SWEN)) 65 return -EBUSY; 66 return 0; 67 68} 69 70static int mpc8xxx_wdt_stop(struct udevice *dev) 71{ 72 struct mpc8xxx_wdt_priv *priv = dev_get_priv(dev); 73 74 clrbits_be32(&priv->base->swcrr, SWCRR_SWEN); 75 76 if (in_be32(&priv->base->swcrr) & SWCRR_SWEN) 77 return -EBUSY; 78 return 0; 79} 80 81static int mpc8xxx_wdt_of_to_plat(struct udevice *dev) 82{ 83 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; 89 90 return 0; 91} 92 93static const struct wdt_ops mpc8xxx_wdt_ops = { 94 .start = mpc8xxx_wdt_start, 95 .reset = mpc8xxx_wdt_reset, 96 .stop = mpc8xxx_wdt_stop, 97}; 98 99static const struct udevice_id mpc8xxx_wdt_ids[] = { 100 { .compatible = "fsl,pq1-wdt", .data = 0x800 }, 101 { .compatible = "fsl,pq2pro-wdt", .data = 0x10000 }, 102 {} 103}; 104 105U_BOOT_DRIVER(wdt_mpc8xxx) = { 106 .name = "wdt_mpc8xxx", 107 .id = UCLASS_WDT, 108 .of_match = mpc8xxx_wdt_ids, 109 .ops = &mpc8xxx_wdt_ops, 110 .of_to_plat = mpc8xxx_wdt_of_to_plat, 111 .priv_auto = sizeof(struct mpc8xxx_wdt_priv), 112}; 113