Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | // SPDX-License-Identifier: GPL-2.0+ /* * Watchdog driver for the FTWDT010 Watch Dog Driver * * (c) Copyright 2004 Faraday Technology Corp. (www.faraday-tech.com) * Based on sa1100_wdt.c by Oleg Drokin <green@crimea.edu> * Based on SoftDog driver by Alan Cox <alan@redhat.com> * * Copyright (C) 2011 Andes Technology Corporation * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com> * * 27/11/2004 Initial release, Faraday. * 12/01/2011 Port to u-boot, Macpaul Lin. * 22/08/2022 Port to DM */ #include <dm.h> #include <wdt.h> #include <log.h> #include <asm/io.h> #include <faraday/ftwdt010_wdt.h> struct ftwdt010_wdt_priv { struct ftwdt010_wdt __iomem *regs; }; static int ftwdt010_wdt_reset(struct udevice *dev) { struct ftwdt010_wdt_priv *priv = dev_get_priv(dev); struct ftwdt010_wdt *wd = priv->regs; debug("Reset WDT..\n"); /* clear control register */ writel(0, &wd->wdcr); /* Write Magic number */ writel(FTWDT010_WDRESTART_MAGIC, &wd->wdrestart); /* Enable WDT */ writel(FTWDT010_WDCR_RST | FTWDT010_WDCR_ENABLE, &wd->wdcr); return 0; } /* * Set the watchdog time interval and start the timer. * Counter is 32 bit. */ static int ftwdt010_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) { struct ftwdt010_wdt_priv *priv = dev_get_priv(dev); struct ftwdt010_wdt *wd = priv->regs; unsigned int reg; debug("Activating WDT %llu ms\n", timeout_ms); /* Check if disabled */ if (readl(&wd->wdcr) & ~FTWDT010_WDCR_ENABLE) { printf("sorry, watchdog is disabled\n"); return -1; } /* * In a 66MHz system, * if you set WDLOAD as 0x03EF1480 (66000000) * the reset timer is 1 second. */ reg = FTWDT010_WDLOAD(timeout_ms * FTWDT010_TIMEOUT_FACTOR); writel(reg, &wd->wdload); return ftwdt010_wdt_reset(dev); } static int ftwdt010_wdt_stop(struct udevice *dev) { struct ftwdt010_wdt_priv *priv = dev_get_priv(dev); struct ftwdt010_wdt *wd = priv->regs; debug("Deactivating WDT..\n"); /* * It was defined with CONFIG_WATCHDOG_NOWAYOUT in Linux * * Shut off the timer. * Lock it in if it's a module and we defined ...NOWAYOUT */ writel(0, &wd->wdcr); return 0; } static int ftwdt010_wdt_expire_now(struct udevice *dev, ulong flags) { struct ftwdt010_wdt_priv *priv = dev_get_priv(dev); struct ftwdt010_wdt *wd = priv->regs; debug("Expiring WDT..\n"); writel(FTWDT010_WDLOAD(0), &wd->wdload); return ftwdt010_wdt_reset(dev); } static int ftwdt010_wdt_probe(struct udevice *dev) { struct ftwdt010_wdt_priv *priv = dev_get_priv(dev); priv->regs = dev_read_addr_ptr(dev); if (!priv->regs) return -EINVAL; return 0; } static const struct wdt_ops ftwdt010_wdt_ops = { .start = ftwdt010_wdt_start, .reset = ftwdt010_wdt_reset, .stop = ftwdt010_wdt_stop, .expire_now = ftwdt010_wdt_expire_now, }; static const struct udevice_id ftwdt010_wdt_ids[] = { { .compatible = "faraday,ftwdt010" }, {} }; U_BOOT_DRIVER(ftwdt010_wdt) = { .name = "ftwdt010_wdt", .id = UCLASS_WDT, .of_match = ftwdt010_wdt_ids, .ops = &ftwdt010_wdt_ops, .probe = ftwdt010_wdt_probe, .priv_auto = sizeof(struct ftwdt010_wdt_priv), }; |