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