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 62 struct gti_match_data { 63 u32 gti_num_timers; 64 }; 65 66 static const struct gti_match_data match_data_octeontx2 = { 67 .gti_num_timers = 54, 68 }; 69 70 static const struct gti_match_data match_data_cn10k = { 71 .gti_num_timers = 64, 72 }; 73 74 struct 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 84 static 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 98 static 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 108 static 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 134 static 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 151 static 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 187 static 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 200 static void gti_clk_disable_unprepare(void *data) 201 { 202 clk_disable_unprepare(data); 203 } 204 205 static 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 226 static 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 232 static 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 241 static 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, err, 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 322 static 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 }; 327 MODULE_DEVICE_TABLE(of, gti_wdt_of_match); 328 329 static 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 }; 336 module_platform_driver(gti_wdt_driver); 337 338 MODULE_AUTHOR("Bharat Bhushan <bbhushan2@marvell.com>"); 339 MODULE_DESCRIPTION("Marvell GTI watchdog driver"); 340 MODULE_LICENSE("GPL"); 341