18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * R-Car Gen1 RESET/WDT, R-Car Gen2, Gen3, and RZ/G RST Driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2016 Glider bvba 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/err.h> 98c2ecf20Sopenharmony_ci#include <linux/io.h> 108c2ecf20Sopenharmony_ci#include <linux/of_address.h> 118c2ecf20Sopenharmony_ci#include <linux/soc/renesas/rcar-rst.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#define WDTRSTCR_RESET 0xA55A0002 148c2ecf20Sopenharmony_ci#define WDTRSTCR 0x0054 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistatic int rcar_rst_enable_wdt_reset(void __iomem *base) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci iowrite32(WDTRSTCR_RESET, base + WDTRSTCR); 198c2ecf20Sopenharmony_ci return 0; 208c2ecf20Sopenharmony_ci} 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistruct rst_config { 238c2ecf20Sopenharmony_ci unsigned int modemr; /* Mode Monitoring Register Offset */ 248c2ecf20Sopenharmony_ci int (*configure)(void __iomem *base); /* Platform specific config */ 258c2ecf20Sopenharmony_ci}; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic const struct rst_config rcar_rst_gen1 __initconst = { 288c2ecf20Sopenharmony_ci .modemr = 0x20, 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic const struct rst_config rcar_rst_gen2 __initconst = { 328c2ecf20Sopenharmony_ci .modemr = 0x60, 338c2ecf20Sopenharmony_ci .configure = rcar_rst_enable_wdt_reset, 348c2ecf20Sopenharmony_ci}; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic const struct rst_config rcar_rst_gen3 __initconst = { 378c2ecf20Sopenharmony_ci .modemr = 0x60, 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic const struct rst_config rcar_rst_r8a779a0 __initconst = { 418c2ecf20Sopenharmony_ci .modemr = 0x00, /* MODEMR0 and it has CPG related bits */ 428c2ecf20Sopenharmony_ci}; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic const struct of_device_id rcar_rst_matches[] __initconst = { 458c2ecf20Sopenharmony_ci /* RZ/G1 is handled like R-Car Gen2 */ 468c2ecf20Sopenharmony_ci { .compatible = "renesas,r8a7742-rst", .data = &rcar_rst_gen2 }, 478c2ecf20Sopenharmony_ci { .compatible = "renesas,r8a7743-rst", .data = &rcar_rst_gen2 }, 488c2ecf20Sopenharmony_ci { .compatible = "renesas,r8a7744-rst", .data = &rcar_rst_gen2 }, 498c2ecf20Sopenharmony_ci { .compatible = "renesas,r8a7745-rst", .data = &rcar_rst_gen2 }, 508c2ecf20Sopenharmony_ci { .compatible = "renesas,r8a77470-rst", .data = &rcar_rst_gen2 }, 518c2ecf20Sopenharmony_ci /* RZ/G2 is handled like R-Car Gen3 */ 528c2ecf20Sopenharmony_ci { .compatible = "renesas,r8a774a1-rst", .data = &rcar_rst_gen3 }, 538c2ecf20Sopenharmony_ci { .compatible = "renesas,r8a774b1-rst", .data = &rcar_rst_gen3 }, 548c2ecf20Sopenharmony_ci { .compatible = "renesas,r8a774c0-rst", .data = &rcar_rst_gen3 }, 558c2ecf20Sopenharmony_ci { .compatible = "renesas,r8a774e1-rst", .data = &rcar_rst_gen3 }, 568c2ecf20Sopenharmony_ci /* R-Car Gen1 */ 578c2ecf20Sopenharmony_ci { .compatible = "renesas,r8a7778-reset-wdt", .data = &rcar_rst_gen1 }, 588c2ecf20Sopenharmony_ci { .compatible = "renesas,r8a7779-reset-wdt", .data = &rcar_rst_gen1 }, 598c2ecf20Sopenharmony_ci /* R-Car Gen2 */ 608c2ecf20Sopenharmony_ci { .compatible = "renesas,r8a7790-rst", .data = &rcar_rst_gen2 }, 618c2ecf20Sopenharmony_ci { .compatible = "renesas,r8a7791-rst", .data = &rcar_rst_gen2 }, 628c2ecf20Sopenharmony_ci { .compatible = "renesas,r8a7792-rst", .data = &rcar_rst_gen2 }, 638c2ecf20Sopenharmony_ci { .compatible = "renesas,r8a7793-rst", .data = &rcar_rst_gen2 }, 648c2ecf20Sopenharmony_ci { .compatible = "renesas,r8a7794-rst", .data = &rcar_rst_gen2 }, 658c2ecf20Sopenharmony_ci /* R-Car Gen3 */ 668c2ecf20Sopenharmony_ci { .compatible = "renesas,r8a7795-rst", .data = &rcar_rst_gen3 }, 678c2ecf20Sopenharmony_ci { .compatible = "renesas,r8a7796-rst", .data = &rcar_rst_gen3 }, 688c2ecf20Sopenharmony_ci { .compatible = "renesas,r8a77961-rst", .data = &rcar_rst_gen3 }, 698c2ecf20Sopenharmony_ci { .compatible = "renesas,r8a77965-rst", .data = &rcar_rst_gen3 }, 708c2ecf20Sopenharmony_ci { .compatible = "renesas,r8a77970-rst", .data = &rcar_rst_gen3 }, 718c2ecf20Sopenharmony_ci { .compatible = "renesas,r8a77980-rst", .data = &rcar_rst_gen3 }, 728c2ecf20Sopenharmony_ci { .compatible = "renesas,r8a77990-rst", .data = &rcar_rst_gen3 }, 738c2ecf20Sopenharmony_ci { .compatible = "renesas,r8a77995-rst", .data = &rcar_rst_gen3 }, 748c2ecf20Sopenharmony_ci /* R-Car V3U */ 758c2ecf20Sopenharmony_ci { .compatible = "renesas,r8a779a0-rst", .data = &rcar_rst_r8a779a0 }, 768c2ecf20Sopenharmony_ci { /* sentinel */ } 778c2ecf20Sopenharmony_ci}; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic void __iomem *rcar_rst_base __initdata; 808c2ecf20Sopenharmony_cistatic u32 saved_mode __initdata; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic int __init rcar_rst_init(void) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci const struct of_device_id *match; 858c2ecf20Sopenharmony_ci const struct rst_config *cfg; 868c2ecf20Sopenharmony_ci struct device_node *np; 878c2ecf20Sopenharmony_ci void __iomem *base; 888c2ecf20Sopenharmony_ci int error = 0; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci np = of_find_matching_node_and_match(NULL, rcar_rst_matches, &match); 918c2ecf20Sopenharmony_ci if (!np) 928c2ecf20Sopenharmony_ci return -ENODEV; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci base = of_iomap(np, 0); 958c2ecf20Sopenharmony_ci if (!base) { 968c2ecf20Sopenharmony_ci pr_warn("%pOF: Cannot map regs\n", np); 978c2ecf20Sopenharmony_ci error = -ENOMEM; 988c2ecf20Sopenharmony_ci goto out_put; 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci rcar_rst_base = base; 1028c2ecf20Sopenharmony_ci cfg = match->data; 1038c2ecf20Sopenharmony_ci saved_mode = ioread32(base + cfg->modemr); 1048c2ecf20Sopenharmony_ci if (cfg->configure) { 1058c2ecf20Sopenharmony_ci error = cfg->configure(base); 1068c2ecf20Sopenharmony_ci if (error) { 1078c2ecf20Sopenharmony_ci pr_warn("%pOF: Cannot run SoC specific configuration\n", 1088c2ecf20Sopenharmony_ci np); 1098c2ecf20Sopenharmony_ci goto out_put; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci pr_debug("%pOF: MODE = 0x%08x\n", np, saved_mode); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ciout_put: 1168c2ecf20Sopenharmony_ci of_node_put(np); 1178c2ecf20Sopenharmony_ci return error; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ciint __init rcar_rst_read_mode_pins(u32 *mode) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci int error; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (!rcar_rst_base) { 1258c2ecf20Sopenharmony_ci error = rcar_rst_init(); 1268c2ecf20Sopenharmony_ci if (error) 1278c2ecf20Sopenharmony_ci return error; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci *mode = saved_mode; 1318c2ecf20Sopenharmony_ci return 0; 1328c2ecf20Sopenharmony_ci} 133