1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Xilinx AXI platforms watchdog timer driver. 4 * 5 * Author(s): Michal Simek <michal.simek@amd.com> 6 * Shreenidhi Shedi <yesshedi@gmail.com> 7 * 8 * Copyright (c) 2011-2018 Xilinx Inc. 9 */ 10 11#include <dm.h> 12#include <log.h> 13#include <wdt.h> 14#include <linux/err.h> 15#include <linux/io.h> 16 17#define XWT_CSR0_WRS_MASK 0x00000008 /* Reset status Mask */ 18#define XWT_CSR0_WDS_MASK 0x00000004 /* Timer state Mask */ 19#define XWT_CSR0_EWDT1_MASK 0x00000002 /* Enable bit 1 Mask*/ 20#define XWT_CSRX_EWDT2_MASK 0x00000001 /* Enable bit 2 Mask */ 21 22struct watchdog_regs { 23 u32 twcsr0; /* 0x0 */ 24 u32 twcsr1; /* 0x4 */ 25 u32 tbr; /* 0x8 */ 26}; 27 28struct xlnx_wdt_plat { 29 bool enable_once; 30 struct watchdog_regs *regs; 31}; 32 33static int xlnx_wdt_reset(struct udevice *dev) 34{ 35 u32 reg; 36 struct xlnx_wdt_plat *plat = dev_get_plat(dev); 37 38 debug("%s ", __func__); 39 40 /* Read the current contents of TCSR0 */ 41 reg = readl(&plat->regs->twcsr0); 42 43 /* Clear the watchdog WDS bit */ 44 if (reg & (XWT_CSR0_EWDT1_MASK | XWT_CSRX_EWDT2_MASK)) 45 writel(reg | XWT_CSR0_WDS_MASK, &plat->regs->twcsr0); 46 47 return 0; 48} 49 50static int xlnx_wdt_stop(struct udevice *dev) 51{ 52 u32 reg; 53 struct xlnx_wdt_plat *plat = dev_get_plat(dev); 54 55 if (plat->enable_once) { 56 debug("Can't stop Xilinx watchdog.\n"); 57 return -EBUSY; 58 } 59 60 /* Read the current contents of TCSR0 */ 61 reg = readl(&plat->regs->twcsr0); 62 63 writel(reg & ~XWT_CSR0_EWDT1_MASK, &plat->regs->twcsr0); 64 writel(~XWT_CSRX_EWDT2_MASK, &plat->regs->twcsr1); 65 66 debug("Watchdog disabled!\n"); 67 68 return 0; 69} 70 71static int xlnx_wdt_start(struct udevice *dev, u64 timeout, ulong flags) 72{ 73 struct xlnx_wdt_plat *plat = dev_get_plat(dev); 74 75 debug("%s:\n", __func__); 76 77 writel((XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK | XWT_CSR0_EWDT1_MASK), 78 &plat->regs->twcsr0); 79 80 writel(XWT_CSRX_EWDT2_MASK, &plat->regs->twcsr1); 81 82 return 0; 83} 84 85static int xlnx_wdt_probe(struct udevice *dev) 86{ 87 debug("%s: Probing wdt%u\n", __func__, dev_seq(dev)); 88 89 return 0; 90} 91 92static int xlnx_wdt_of_to_plat(struct udevice *dev) 93{ 94 struct xlnx_wdt_plat *plat = dev_get_plat(dev); 95 96 plat->regs = dev_read_addr_ptr(dev); 97 if (!plat->regs) 98 return -EINVAL; 99 100 plat->enable_once = dev_read_u32_default(dev, "xlnx,wdt-enable-once", 101 0); 102 103 debug("%s: wdt-enable-once %d\n", __func__, plat->enable_once); 104 105 return 0; 106} 107 108static const struct wdt_ops xlnx_wdt_ops = { 109 .start = xlnx_wdt_start, 110 .reset = xlnx_wdt_reset, 111 .stop = xlnx_wdt_stop, 112}; 113 114static const struct udevice_id xlnx_wdt_ids[] = { 115 { .compatible = "xlnx,xps-timebase-wdt-1.00.a", }, 116 { .compatible = "xlnx,xps-timebase-wdt-1.01.a", }, 117 {}, 118}; 119 120U_BOOT_DRIVER(xlnx_wdt) = { 121 .name = "xlnx_wdt", 122 .id = UCLASS_WDT, 123 .of_match = xlnx_wdt_ids, 124 .probe = xlnx_wdt_probe, 125 .plat_auto = sizeof(struct xlnx_wdt_plat), 126 .of_to_plat = xlnx_wdt_of_to_plat, 127 .ops = &xlnx_wdt_ops, 128}; 129