1// SPDX-License-Identifier: GPL-2.0 2/* Marvell GTI Watchdog driver 3 * 4 * Copyright (C) 2023 Marvell. 5 */ 6 7#include <linux/clk.h> 8#include <linux/interrupt.h> 9#include <linux/io.h> 10#include <linux/module.h> 11#include <linux/of_platform.h> 12#include <linux/platform_device.h> 13#include <linux/watchdog.h> 14 15/* 16 * Hardware supports following mode of operation: 17 * 1) Interrupt Only: 18 * This will generate the interrupt to arm core whenever timeout happens. 19 * 20 * 2) Interrupt + del3t (Interrupt to firmware (SCP processor)). 21 * This will generate interrupt to arm core on 1st timeout happens 22 * This will generate interrupt to SCP processor on 2nd timeout happens 23 * 24 * 3) Interrupt + Interrupt to SCP processor (called delt3t) + reboot. 25 * This will generate interrupt to arm core on 1st timeout happens 26 * Will generate interrupt to SCP processor on 2nd timeout happens, 27 * if interrupt is configured. 28 * Reboot on 3rd timeout. 29 * 30 * Driver will use hardware in mode-3 above so that system can reboot in case 31 * a hardware hang. Also h/w is configured not to generate SCP interrupt, so 32 * effectively 2nd timeout is ignored within hardware. 33 * 34 * First timeout is effectively watchdog pretimeout. 35 */ 36 37/* GTI CWD Watchdog (GTI_CWD_WDOG) Register */ 38#define GTI_CWD_WDOG(reg_offset) (0x8 * (reg_offset)) 39#define GTI_CWD_WDOG_MODE_INT_DEL3T_RST 0x3 40#define GTI_CWD_WDOG_MODE_MASK GENMASK_ULL(1, 0) 41#define GTI_CWD_WDOG_LEN_SHIFT 4 42#define GTI_CWD_WDOG_LEN_MASK GENMASK_ULL(19, 4) 43#define GTI_CWD_WDOG_CNT_SHIFT 20 44#define GTI_CWD_WDOG_CNT_MASK GENMASK_ULL(43, 20) 45 46/* GTI CWD Watchdog Interrupt (GTI_CWD_INT) Register */ 47#define GTI_CWD_INT 0x200 48#define GTI_CWD_INT_PENDING_STATUS(bit) BIT_ULL(bit) 49 50/* GTI CWD Watchdog Interrupt Enable Clear (GTI_CWD_INT_ENA_CLR) Register */ 51#define GTI_CWD_INT_ENA_CLR 0x210 52#define GTI_CWD_INT_ENA_CLR_VAL(bit) BIT_ULL(bit) 53 54/* GTI CWD Watchdog Interrupt Enable Set (GTI_CWD_INT_ENA_SET) Register */ 55#define GTI_CWD_INT_ENA_SET 0x218 56#define GTI_CWD_INT_ENA_SET_VAL(bit) BIT_ULL(bit) 57 58/* GTI CWD Watchdog Poke (GTI_CWD_POKE) Registers */ 59#define GTI_CWD_POKE(reg_offset) (0x10000 + 0x8 * (reg_offset)) 60#define GTI_CWD_POKE_VAL 1 61 62struct gti_match_data { 63 u32 gti_num_timers; 64}; 65 66static const struct gti_match_data match_data_octeontx2 = { 67 .gti_num_timers = 54, 68}; 69 70static const struct gti_match_data match_data_cn10k = { 71 .gti_num_timers = 64, 72}; 73 74struct gti_wdt_priv { 75 struct watchdog_device wdev; 76 void __iomem *base; 77 u32 clock_freq; 78 struct clk *sclk; 79 /* wdt_timer_idx used for timer to be used for system watchdog */ 80 u32 wdt_timer_idx; 81 const struct gti_match_data *data; 82}; 83 84static irqreturn_t gti_wdt_interrupt(int irq, void *data) 85{ 86 struct watchdog_device *wdev = data; 87 struct gti_wdt_priv *priv = watchdog_get_drvdata(wdev); 88 89 /* Clear Interrupt Pending Status */ 90 writeq(GTI_CWD_INT_PENDING_STATUS(priv->wdt_timer_idx), 91 priv->base + GTI_CWD_INT); 92 93 watchdog_notify_pretimeout(wdev); 94 95 return IRQ_HANDLED; 96} 97 98static int gti_wdt_ping(struct watchdog_device *wdev) 99{ 100 struct gti_wdt_priv *priv = watchdog_get_drvdata(wdev); 101 102 writeq(GTI_CWD_POKE_VAL, 103 priv->base + GTI_CWD_POKE(priv->wdt_timer_idx)); 104 105 return 0; 106} 107 108static int gti_wdt_start(struct watchdog_device *wdev) 109{ 110 struct gti_wdt_priv *priv = watchdog_get_drvdata(wdev); 111 u64 regval; 112 113 if (!wdev->pretimeout) 114 return -EINVAL; 115 116 set_bit(WDOG_HW_RUNNING, &wdev->status); 117 118 /* Clear any pending interrupt */ 119 writeq(GTI_CWD_INT_PENDING_STATUS(priv->wdt_timer_idx), 120 priv->base + GTI_CWD_INT); 121 122 /* Enable Interrupt */ 123 writeq(GTI_CWD_INT_ENA_SET_VAL(priv->wdt_timer_idx), 124 priv->base + GTI_CWD_INT_ENA_SET); 125 126 /* Set (Interrupt + SCP interrupt (DEL3T) + core domain reset) Mode */ 127 regval = readq(priv->base + GTI_CWD_WDOG(priv->wdt_timer_idx)); 128 regval |= GTI_CWD_WDOG_MODE_INT_DEL3T_RST; 129 writeq(regval, priv->base + GTI_CWD_WDOG(priv->wdt_timer_idx)); 130 131 return 0; 132} 133 134static int gti_wdt_stop(struct watchdog_device *wdev) 135{ 136 struct gti_wdt_priv *priv = watchdog_get_drvdata(wdev); 137 u64 regval; 138 139 /* Disable Interrupt */ 140 writeq(GTI_CWD_INT_ENA_CLR_VAL(priv->wdt_timer_idx), 141 priv->base + GTI_CWD_INT_ENA_CLR); 142 143 /* Set GTI_CWD_WDOG.Mode = 0 to stop the timer */ 144 regval = readq(priv->base + GTI_CWD_WDOG(priv->wdt_timer_idx)); 145 regval &= ~GTI_CWD_WDOG_MODE_MASK; 146 writeq(regval, priv->base + GTI_CWD_WDOG(priv->wdt_timer_idx)); 147 148 return 0; 149} 150 151static int gti_wdt_settimeout(struct watchdog_device *wdev, 152 unsigned int timeout) 153{ 154 struct gti_wdt_priv *priv = watchdog_get_drvdata(wdev); 155 u64 timeout_wdog, regval; 156 157 /* Update new timeout */ 158 wdev->timeout = timeout; 159 160 /* Pretimeout is 1/3 of timeout */ 161 wdev->pretimeout = timeout / 3; 162 163 /* Get clock cycles from pretimeout */ 164 timeout_wdog = (u64)priv->clock_freq * wdev->pretimeout; 165 166 /* Watchdog counts in 1024 cycle steps */ 167 timeout_wdog = timeout_wdog >> 10; 168 169 /* GTI_CWD_WDOG.CNT: reload counter is 16-bit */ 170 timeout_wdog = (timeout_wdog + 0xff) >> 8; 171 if (timeout_wdog >= 0x10000) 172 timeout_wdog = 0xffff; 173 174 /* 175 * GTI_CWD_WDOG.LEN is 24bit, lower 8-bits should be zero and 176 * upper 16-bits are same as GTI_CWD_WDOG.CNT 177 */ 178 regval = readq(priv->base + GTI_CWD_WDOG(priv->wdt_timer_idx)); 179 regval &= GTI_CWD_WDOG_MODE_MASK; 180 regval |= (timeout_wdog << (GTI_CWD_WDOG_CNT_SHIFT + 8)) | 181 (timeout_wdog << GTI_CWD_WDOG_LEN_SHIFT); 182 writeq(regval, priv->base + GTI_CWD_WDOG(priv->wdt_timer_idx)); 183 184 return 0; 185} 186 187static int gti_wdt_set_pretimeout(struct watchdog_device *wdev, 188 unsigned int timeout) 189{ 190 struct gti_wdt_priv *priv = watchdog_get_drvdata(wdev); 191 struct watchdog_device *wdog_dev = &priv->wdev; 192 193 /* pretimeout should 1/3 of max_timeout */ 194 if (timeout * 3 <= wdog_dev->max_timeout) 195 return gti_wdt_settimeout(wdev, timeout * 3); 196 197 return -EINVAL; 198} 199 200static void gti_clk_disable_unprepare(void *data) 201{ 202 clk_disable_unprepare(data); 203} 204 205static int gti_wdt_get_cntfrq(struct platform_device *pdev, 206 struct gti_wdt_priv *priv) 207{ 208 int err; 209 210 priv->sclk = devm_clk_get_enabled(&pdev->dev, NULL); 211 if (IS_ERR(priv->sclk)) 212 return PTR_ERR(priv->sclk); 213 214 err = devm_add_action_or_reset(&pdev->dev, 215 gti_clk_disable_unprepare, priv->sclk); 216 if (err) 217 return err; 218 219 priv->clock_freq = clk_get_rate(priv->sclk); 220 if (!priv->clock_freq) 221 return -EINVAL; 222 223 return 0; 224} 225 226static const struct watchdog_info gti_wdt_ident = { 227 .identity = "Marvell GTI watchdog", 228 .options = WDIOF_SETTIMEOUT | WDIOF_PRETIMEOUT | WDIOF_KEEPALIVEPING | 229 WDIOF_MAGICCLOSE | WDIOF_CARDRESET, 230}; 231 232static const struct watchdog_ops gti_wdt_ops = { 233 .owner = THIS_MODULE, 234 .start = gti_wdt_start, 235 .stop = gti_wdt_stop, 236 .ping = gti_wdt_ping, 237 .set_timeout = gti_wdt_settimeout, 238 .set_pretimeout = gti_wdt_set_pretimeout, 239}; 240 241static int gti_wdt_probe(struct platform_device *pdev) 242{ 243 struct gti_wdt_priv *priv; 244 struct device *dev = &pdev->dev; 245 struct watchdog_device *wdog_dev; 246 u64 max_pretimeout; 247 u32 wdt_idx; 248 int irq; 249 int err; 250 251 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 252 if (!priv) 253 return -ENOMEM; 254 255 priv->base = devm_platform_ioremap_resource(pdev, 0); 256 if (IS_ERR(priv->base)) 257 return dev_err_probe(&pdev->dev, PTR_ERR(priv->base), 258 "reg property not valid/found\n"); 259 260 err = gti_wdt_get_cntfrq(pdev, priv); 261 if (err) 262 return dev_err_probe(&pdev->dev, err, 263 "GTI clock frequency not valid/found"); 264 265 priv->data = of_device_get_match_data(dev); 266 267 /* default use last timer for watchdog */ 268 priv->wdt_timer_idx = priv->data->gti_num_timers - 1; 269 270 err = of_property_read_u32(dev->of_node, "marvell,wdt-timer-index", 271 &wdt_idx); 272 if (!err) { 273 if (wdt_idx >= priv->data->gti_num_timers) 274 return dev_err_probe(&pdev->dev, -EINVAL, 275 "GTI wdog timer index not valid"); 276 277 priv->wdt_timer_idx = wdt_idx; 278 } 279 280 wdog_dev = &priv->wdev; 281 wdog_dev->info = >i_wdt_ident, 282 wdog_dev->ops = >i_wdt_ops, 283 wdog_dev->parent = dev; 284 /* 285 * Watchdog counter is 24 bit where lower 8 bits are zeros 286 * This counter decrements every 1024 clock cycles. 287 */ 288 max_pretimeout = (GTI_CWD_WDOG_CNT_MASK >> GTI_CWD_WDOG_CNT_SHIFT); 289 max_pretimeout &= ~0xFFUL; 290 max_pretimeout = (max_pretimeout * 1024) / priv->clock_freq; 291 wdog_dev->pretimeout = max_pretimeout; 292 293 /* Maximum timeout is 3 times the pretimeout */ 294 wdog_dev->max_timeout = max_pretimeout * 3; 295 /* Minimum first timeout (pretimeout) is 1, so min_timeout as 3 */ 296 wdog_dev->min_timeout = 3; 297 wdog_dev->timeout = wdog_dev->pretimeout; 298 299 watchdog_set_drvdata(wdog_dev, priv); 300 platform_set_drvdata(pdev, priv); 301 gti_wdt_settimeout(wdog_dev, wdog_dev->timeout); 302 watchdog_stop_on_reboot(wdog_dev); 303 watchdog_stop_on_unregister(wdog_dev); 304 305 err = devm_watchdog_register_device(dev, wdog_dev); 306 if (err) 307 return err; 308 309 irq = platform_get_irq(pdev, 0); 310 if (irq < 0) 311 return dev_err_probe(&pdev->dev, irq, "IRQ resource not found\n"); 312 313 err = devm_request_irq(dev, irq, gti_wdt_interrupt, 0, 314 pdev->name, &priv->wdev); 315 if (err) 316 return dev_err_probe(dev, err, "Failed to register interrupt handler\n"); 317 318 dev_info(dev, "Watchdog enabled (timeout=%d sec)\n", wdog_dev->timeout); 319 return 0; 320} 321 322static const struct of_device_id gti_wdt_of_match[] = { 323 { .compatible = "marvell,cn9670-wdt", .data = &match_data_octeontx2}, 324 { .compatible = "marvell,cn10624-wdt", .data = &match_data_cn10k}, 325 { }, 326}; 327MODULE_DEVICE_TABLE(of, gti_wdt_of_match); 328 329static struct platform_driver gti_wdt_driver = { 330 .driver = { 331 .name = "gti-wdt", 332 .of_match_table = gti_wdt_of_match, 333 }, 334 .probe = gti_wdt_probe, 335}; 336module_platform_driver(gti_wdt_driver); 337 338MODULE_AUTHOR("Bharat Bhushan <bbhushan2@marvell.com>"); 339MODULE_DESCRIPTION("Marvell GTI watchdog driver"); 340MODULE_LICENSE("GPL"); 341