1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * R-Car Gen1 RESET/WDT, R-Car Gen2, Gen3, and RZ/G RST Driver |
4 | * |
5 | * Copyright (C) 2016 Glider bvba |
6 | */ |
7 | |
8 | #include <linux/err.h> |
9 | #include <linux/io.h> |
10 | #include <linux/of_address.h> |
11 | #include <linux/soc/renesas/rcar-rst.h> |
12 | |
13 | #define WDTRSTCR_RESET 0xA55A0002 |
14 | #define WDTRSTCR 0x0054 |
15 | #define GEN4_WDTRSTCR 0x0010 |
16 | |
17 | #define CR7BAR 0x0070 |
18 | #define CR7BAREN BIT(4) |
19 | #define CR7BAR_MASK 0xFFFC0000 |
20 | |
21 | static void __iomem *rcar_rst_base; |
22 | static u32 saved_mode __initdata; |
23 | static int (*rcar_rst_set_rproc_boot_addr_func)(u64 boot_addr); |
24 | |
25 | static int rcar_rst_enable_wdt_reset(void __iomem *base) |
26 | { |
27 | iowrite32(WDTRSTCR_RESET, base + WDTRSTCR); |
28 | return 0; |
29 | } |
30 | |
31 | static int rcar_rst_v3u_enable_wdt_reset(void __iomem *base) |
32 | { |
33 | iowrite32(WDTRSTCR_RESET, base + GEN4_WDTRSTCR); |
34 | return 0; |
35 | } |
36 | |
37 | /* |
38 | * Most of the R-Car Gen3 SoCs have an ARM Realtime Core. |
39 | * Firmware boot address has to be set in CR7BAR before |
40 | * starting the realtime core. |
41 | * Boot address must be aligned on a 256k boundary. |
42 | */ |
43 | static int rcar_rst_set_gen3_rproc_boot_addr(u64 boot_addr) |
44 | { |
45 | if (boot_addr & ~(u64)CR7BAR_MASK) { |
46 | pr_err("Invalid boot address got %llx\n" , boot_addr); |
47 | return -EINVAL; |
48 | } |
49 | |
50 | iowrite32(boot_addr, rcar_rst_base + CR7BAR); |
51 | iowrite32(boot_addr | CR7BAREN, rcar_rst_base + CR7BAR); |
52 | |
53 | return 0; |
54 | } |
55 | |
56 | struct rst_config { |
57 | unsigned int modemr; /* Mode Monitoring Register Offset */ |
58 | int (*configure)(void __iomem *base); /* Platform specific config */ |
59 | int (*set_rproc_boot_addr)(u64 boot_addr); |
60 | }; |
61 | |
62 | static const struct rst_config rcar_rst_gen1 __initconst = { |
63 | .modemr = 0x20, |
64 | }; |
65 | |
66 | static const struct rst_config rcar_rst_gen2 __initconst = { |
67 | .modemr = 0x60, |
68 | .configure = rcar_rst_enable_wdt_reset, |
69 | }; |
70 | |
71 | static const struct rst_config rcar_rst_gen3 __initconst = { |
72 | .modemr = 0x60, |
73 | .set_rproc_boot_addr = rcar_rst_set_gen3_rproc_boot_addr, |
74 | }; |
75 | |
76 | /* V3U firmware doesn't enable WDT reset and there won't be updates anymore */ |
77 | static const struct rst_config rcar_rst_v3u __initconst = { |
78 | .modemr = 0x00, /* MODEMR0 and it has CPG related bits */ |
79 | .configure = rcar_rst_v3u_enable_wdt_reset, |
80 | }; |
81 | |
82 | static const struct rst_config rcar_rst_gen4 __initconst = { |
83 | .modemr = 0x00, /* MODEMR0 and it has CPG related bits */ |
84 | }; |
85 | |
86 | static const struct of_device_id rcar_rst_matches[] __initconst = { |
87 | /* RZ/G1 is handled like R-Car Gen2 */ |
88 | { .compatible = "renesas,r8a7742-rst" , .data = &rcar_rst_gen2 }, |
89 | { .compatible = "renesas,r8a7743-rst" , .data = &rcar_rst_gen2 }, |
90 | { .compatible = "renesas,r8a7744-rst" , .data = &rcar_rst_gen2 }, |
91 | { .compatible = "renesas,r8a7745-rst" , .data = &rcar_rst_gen2 }, |
92 | { .compatible = "renesas,r8a77470-rst" , .data = &rcar_rst_gen2 }, |
93 | /* RZ/G2 is handled like R-Car Gen3 */ |
94 | { .compatible = "renesas,r8a774a1-rst" , .data = &rcar_rst_gen3 }, |
95 | { .compatible = "renesas,r8a774b1-rst" , .data = &rcar_rst_gen3 }, |
96 | { .compatible = "renesas,r8a774c0-rst" , .data = &rcar_rst_gen3 }, |
97 | { .compatible = "renesas,r8a774e1-rst" , .data = &rcar_rst_gen3 }, |
98 | /* R-Car Gen1 */ |
99 | { .compatible = "renesas,r8a7778-reset-wdt" , .data = &rcar_rst_gen1 }, |
100 | { .compatible = "renesas,r8a7779-reset-wdt" , .data = &rcar_rst_gen1 }, |
101 | /* R-Car Gen2 */ |
102 | { .compatible = "renesas,r8a7790-rst" , .data = &rcar_rst_gen2 }, |
103 | { .compatible = "renesas,r8a7791-rst" , .data = &rcar_rst_gen2 }, |
104 | { .compatible = "renesas,r8a7792-rst" , .data = &rcar_rst_gen2 }, |
105 | { .compatible = "renesas,r8a7793-rst" , .data = &rcar_rst_gen2 }, |
106 | { .compatible = "renesas,r8a7794-rst" , .data = &rcar_rst_gen2 }, |
107 | /* R-Car Gen3 */ |
108 | { .compatible = "renesas,r8a7795-rst" , .data = &rcar_rst_gen3 }, |
109 | { .compatible = "renesas,r8a7796-rst" , .data = &rcar_rst_gen3 }, |
110 | { .compatible = "renesas,r8a77961-rst" , .data = &rcar_rst_gen3 }, |
111 | { .compatible = "renesas,r8a77965-rst" , .data = &rcar_rst_gen3 }, |
112 | { .compatible = "renesas,r8a77970-rst" , .data = &rcar_rst_gen3 }, |
113 | { .compatible = "renesas,r8a77980-rst" , .data = &rcar_rst_gen3 }, |
114 | { .compatible = "renesas,r8a77990-rst" , .data = &rcar_rst_gen3 }, |
115 | { .compatible = "renesas,r8a77995-rst" , .data = &rcar_rst_gen3 }, |
116 | /* R-Car Gen4 */ |
117 | { .compatible = "renesas,r8a779a0-rst" , .data = &rcar_rst_v3u }, |
118 | { .compatible = "renesas,r8a779f0-rst" , .data = &rcar_rst_gen4 }, |
119 | { .compatible = "renesas,r8a779g0-rst" , .data = &rcar_rst_gen4 }, |
120 | { .compatible = "renesas,r8a779h0-rst" , .data = &rcar_rst_gen4 }, |
121 | { /* sentinel */ } |
122 | }; |
123 | |
124 | static int __init rcar_rst_init(void) |
125 | { |
126 | const struct of_device_id *match; |
127 | const struct rst_config *cfg; |
128 | struct device_node *np; |
129 | void __iomem *base; |
130 | int error = 0; |
131 | |
132 | np = of_find_matching_node_and_match(NULL, matches: rcar_rst_matches, match: &match); |
133 | if (!np) |
134 | return -ENODEV; |
135 | |
136 | base = of_iomap(node: np, index: 0); |
137 | if (!base) { |
138 | pr_warn("%pOF: Cannot map regs\n" , np); |
139 | error = -ENOMEM; |
140 | goto out_put; |
141 | } |
142 | |
143 | rcar_rst_base = base; |
144 | cfg = match->data; |
145 | rcar_rst_set_rproc_boot_addr_func = cfg->set_rproc_boot_addr; |
146 | |
147 | saved_mode = ioread32(base + cfg->modemr); |
148 | if (cfg->configure) { |
149 | error = cfg->configure(base); |
150 | if (error) { |
151 | pr_warn("%pOF: Cannot run SoC specific configuration\n" , |
152 | np); |
153 | goto out_put; |
154 | } |
155 | } |
156 | |
157 | pr_debug("%pOF: MODE = 0x%08x\n" , np, saved_mode); |
158 | |
159 | out_put: |
160 | of_node_put(node: np); |
161 | return error; |
162 | } |
163 | |
164 | int __init rcar_rst_read_mode_pins(u32 *mode) |
165 | { |
166 | int error; |
167 | |
168 | if (!rcar_rst_base) { |
169 | error = rcar_rst_init(); |
170 | if (error) |
171 | return error; |
172 | } |
173 | |
174 | *mode = saved_mode; |
175 | return 0; |
176 | } |
177 | |
178 | int rcar_rst_set_rproc_boot_addr(u64 boot_addr) |
179 | { |
180 | if (!rcar_rst_set_rproc_boot_addr_func) |
181 | return -EIO; |
182 | |
183 | return rcar_rst_set_rproc_boot_addr_func(boot_addr); |
184 | } |
185 | EXPORT_SYMBOL_GPL(rcar_rst_set_rproc_boot_addr); |
186 | |