Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

watchdog: s3c2410: Add Exynos850 support

Exynos850 is a bit different from SoCs already supported in WDT driver:
- AUTOMATIC_WDT_RESET_DISABLE register is removed, so its value is
always 0; .disable_auto_reset callback is not set for that reason
- MASK_WDT_RESET_REQUEST register is replaced with
CLUSTERx_NONCPU_IN_EN register; instead of masking (disabling) WDT
reset interrupt it's now enabled with the same value; .mask_reset
callback is reused for that functionality though
- To make WDT functional, WDT counter needs to be enabled in
CLUSTERx_NONCPU_OUT register; it's done using .enable_counter
callback

Also Exynos850 has two CPU clusters, each has its own dedicated WDT
instance. Different PMU registers and bits are used for each cluster. So
driver data is now modified in probe, adding needed info depending on
cluster index passed from device tree.

Signed-off-by: Sam Protsenko <semen.protsenko@linaro.org>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Link: https://lore.kernel.org/r/20211121165647.26706-13-semen.protsenko@linaro.org
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org>

authored by

Sam Protsenko and committed by
Wim Van Sebroeck
cd4eadf2 968011a2

+63 -1
+63 -1
drivers/watchdog/s3c2410_wdt.c
··· 56 56 #define EXYNOS5_RST_STAT_REG_OFFSET 0x0404 57 57 #define EXYNOS5_WDT_DISABLE_REG_OFFSET 0x0408 58 58 #define EXYNOS5_WDT_MASK_RESET_REG_OFFSET 0x040c 59 + #define EXYNOS850_CLUSTER0_NONCPU_OUT 0x1220 60 + #define EXYNOS850_CLUSTER0_NONCPU_INT_EN 0x1244 61 + #define EXYNOS850_CLUSTER1_NONCPU_OUT 0x1620 62 + #define EXYNOS850_CLUSTER1_NONCPU_INT_EN 0x1644 63 + 64 + #define EXYNOS850_CLUSTER0_WDTRESET_BIT 24 65 + #define EXYNOS850_CLUSTER1_WDTRESET_BIT 23 59 66 60 67 /** 61 68 * DOC: Quirk flags for different Samsung watchdog IP-cores ··· 212 205 QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_AUTO_DISABLE, 213 206 }; 214 207 208 + static const struct s3c2410_wdt_variant drv_data_exynos850_cl0 = { 209 + .mask_reset_reg = EXYNOS850_CLUSTER0_NONCPU_INT_EN, 210 + .mask_bit = 2, 211 + .mask_reset_inv = true, 212 + .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, 213 + .rst_stat_bit = EXYNOS850_CLUSTER0_WDTRESET_BIT, 214 + .cnt_en_reg = EXYNOS850_CLUSTER0_NONCPU_OUT, 215 + .cnt_en_bit = 7, 216 + .quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET | \ 217 + QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN, 218 + }; 219 + 220 + static const struct s3c2410_wdt_variant drv_data_exynos850_cl1 = { 221 + .mask_reset_reg = EXYNOS850_CLUSTER1_NONCPU_INT_EN, 222 + .mask_bit = 2, 223 + .mask_reset_inv = true, 224 + .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, 225 + .rst_stat_bit = EXYNOS850_CLUSTER1_WDTRESET_BIT, 226 + .cnt_en_reg = EXYNOS850_CLUSTER1_NONCPU_OUT, 227 + .cnt_en_bit = 7, 228 + .quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET | \ 229 + QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN, 230 + }; 231 + 215 232 static const struct of_device_id s3c2410_wdt_match[] = { 216 233 { .compatible = "samsung,s3c2410-wdt", 217 234 .data = &drv_data_s3c2410 }, ··· 247 216 .data = &drv_data_exynos5420 }, 248 217 { .compatible = "samsung,exynos7-wdt", 249 218 .data = &drv_data_exynos7 }, 219 + { .compatible = "samsung,exynos850-wdt", 220 + .data = &drv_data_exynos850_cl0 }, 250 221 {}, 251 222 }; 252 223 MODULE_DEVICE_TABLE(of, s3c2410_wdt_match); ··· 620 587 s3c2410_get_wdt_drv_data(struct platform_device *pdev) 621 588 { 622 589 const struct s3c2410_wdt_variant *variant; 590 + struct device *dev = &pdev->dev; 623 591 624 - variant = of_device_get_match_data(&pdev->dev); 592 + variant = of_device_get_match_data(dev); 625 593 if (!variant) { 626 594 /* Device matched by platform_device_id */ 627 595 variant = (struct s3c2410_wdt_variant *) 628 596 platform_get_device_id(pdev)->driver_data; 629 597 } 598 + 599 + #ifdef CONFIG_OF 600 + /* Choose Exynos850 driver data w.r.t. cluster index */ 601 + if (variant == &drv_data_exynos850_cl0) { 602 + u32 index; 603 + int err; 604 + 605 + err = of_property_read_u32(dev->of_node, 606 + "samsung,cluster-index", &index); 607 + if (err) { 608 + dev_err(dev, "failed to get cluster index\n"); 609 + return NULL; 610 + } 611 + 612 + switch (index) { 613 + case 0: 614 + return &drv_data_exynos850_cl0; 615 + case 1: 616 + return &drv_data_exynos850_cl1; 617 + default: 618 + dev_err(dev, "wrong cluster index: %u\n", index); 619 + return NULL; 620 + } 621 + } 622 + #endif 630 623 631 624 return variant; 632 625 } ··· 674 615 wdt->wdt_device = s3c2410_wdd; 675 616 676 617 wdt->drv_data = s3c2410_get_wdt_drv_data(pdev); 618 + if (!wdt->drv_data) 619 + return -EINVAL; 620 + 677 621 if (wdt->drv_data->quirks & QUIRKS_HAVE_PMUREG) { 678 622 wdt->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node, 679 623 "samsung,syscon-phandle");