hc
2023-12-09 b22da3d8526a935aa31e086e63f60ff3246cb61c
kernel/drivers/power/reset/at91-sama5d2_shdwc.c
....@@ -19,6 +19,7 @@
1919 */
2020
2121 #include <linux/clk.h>
22
+#include <linux/clk/at91_pmc.h>
2223 #include <linux/io.h>
2324 #include <linux/module.h>
2425 #include <linux/of.h>
....@@ -56,20 +57,38 @@
5657
5758 #define SHDW_WK_PIN(reg, cfg) ((reg) & AT91_SHDW_WKUPIS((cfg)->wkup_pin_input))
5859 #define SHDW_RTCWK(reg, cfg) (((reg) >> ((cfg)->sr_rtcwk_shift)) & 0x1)
60
+#define SHDW_RTTWK(reg, cfg) (((reg) >> ((cfg)->sr_rttwk_shift)) & 0x1)
5961 #define SHDW_RTCWKEN(cfg) (1 << ((cfg)->mr_rtcwk_shift))
62
+#define SHDW_RTTWKEN(cfg) (1 << ((cfg)->mr_rttwk_shift))
6063
6164 #define DBC_PERIOD_US(x) DIV_ROUND_UP_ULL((1000000 * (x)), \
6265 SLOW_CLOCK_FREQ)
6366
64
-struct shdwc_config {
67
+#define SHDW_CFG_NOT_USED (32)
68
+
69
+struct shdwc_reg_config {
6570 u8 wkup_pin_input;
6671 u8 mr_rtcwk_shift;
72
+ u8 mr_rttwk_shift;
6773 u8 sr_rtcwk_shift;
74
+ u8 sr_rttwk_shift;
75
+};
76
+
77
+struct pmc_reg_config {
78
+ u8 mckr;
79
+};
80
+
81
+struct reg_config {
82
+ struct shdwc_reg_config shdwc;
83
+ struct pmc_reg_config pmc;
6884 };
6985
7086 struct shdwc {
71
- const struct shdwc_config *cfg;
72
- void __iomem *at91_shdwc_base;
87
+ const struct reg_config *rcfg;
88
+ struct clk *sclk;
89
+ void __iomem *shdwc_base;
90
+ void __iomem *mpddrc_base;
91
+ void __iomem *pmc_base;
7392 };
7493
7594 /*
....@@ -77,8 +96,6 @@
7796 * since pm_power_off itself is global.
7897 */
7998 static struct shdwc *at91_shdwc;
80
-static struct clk *sclk;
81
-static void __iomem *mpddrc_base;
8299
83100 static const unsigned long long sdwc_dbc_period[] = {
84101 0, 3, 32, 512, 4096, 32768,
....@@ -87,10 +104,11 @@
87104 static void __init at91_wakeup_status(struct platform_device *pdev)
88105 {
89106 struct shdwc *shdw = platform_get_drvdata(pdev);
107
+ const struct reg_config *rcfg = shdw->rcfg;
90108 u32 reg;
91109 char *reason = "unknown";
92110
93
- reg = readl(shdw->at91_shdwc_base + AT91_SHDW_SR);
111
+ reg = readl(shdw->shdwc_base + AT91_SHDW_SR);
94112
95113 dev_dbg(&pdev->dev, "%s: status = %#x\n", __func__, reg);
96114
....@@ -98,21 +116,17 @@
98116 if (!reg)
99117 return;
100118
101
- if (SHDW_WK_PIN(reg, shdw->cfg))
119
+ if (SHDW_WK_PIN(reg, &rcfg->shdwc))
102120 reason = "WKUP pin";
103
- else if (SHDW_RTCWK(reg, shdw->cfg))
121
+ else if (SHDW_RTCWK(reg, &rcfg->shdwc))
104122 reason = "RTC";
123
+ else if (SHDW_RTTWK(reg, &rcfg->shdwc))
124
+ reason = "RTT";
105125
106126 pr_info("AT91: Wake-Up source: %s\n", reason);
107127 }
108128
109129 static void at91_poweroff(void)
110
-{
111
- writel(AT91_SHDW_KEY | AT91_SHDW_SHDW,
112
- at91_shdwc->at91_shdwc_base + AT91_SHDW_CR);
113
-}
114
-
115
-static void at91_lpddr_poweroff(void)
116130 {
117131 asm volatile(
118132 /* Align to cache lines */
....@@ -122,16 +136,30 @@
122136 " ldr r6, [%2, #" __stringify(AT91_SHDW_CR) "]\n\t"
123137
124138 /* Power down SDRAM0 */
139
+ " tst %0, #0\n\t"
140
+ " beq 1f\n\t"
125141 " str %1, [%0, #" __stringify(AT91_DDRSDRC_LPR) "]\n\t"
142
+
143
+ /* Switch the master clock source to slow clock. */
144
+ "1: ldr r6, [%4, %5]\n\t"
145
+ " bic r6, r6, #" __stringify(AT91_PMC_CSS) "\n\t"
146
+ " str r6, [%4, %5]\n\t"
147
+ /* Wait for clock switch. */
148
+ "2: ldr r6, [%4, #" __stringify(AT91_PMC_SR) "]\n\t"
149
+ " tst r6, #" __stringify(AT91_PMC_MCKRDY) "\n\t"
150
+ " beq 2b\n\t"
151
+
126152 /* Shutdown CPU */
127153 " str %3, [%2, #" __stringify(AT91_SHDW_CR) "]\n\t"
128154
129155 " b .\n\t"
130156 :
131
- : "r" (mpddrc_base),
157
+ : "r" (at91_shdwc->mpddrc_base),
132158 "r" cpu_to_le32(AT91_DDRSDRC_LPDDR2_PWOFF),
133
- "r" (at91_shdwc->at91_shdwc_base),
134
- "r" cpu_to_le32(AT91_SHDW_KEY | AT91_SHDW_SHDW)
159
+ "r" (at91_shdwc->shdwc_base),
160
+ "r" cpu_to_le32(AT91_SHDW_KEY | AT91_SHDW_SHDW),
161
+ "r" (at91_shdwc->pmc_base),
162
+ "r" (at91_shdwc->rcfg->pmc.mckr)
135163 : "r6");
136164 }
137165
....@@ -198,6 +226,7 @@
198226 static void at91_shdwc_dt_configure(struct platform_device *pdev)
199227 {
200228 struct shdwc *shdw = platform_get_drvdata(pdev);
229
+ const struct reg_config *rcfg = shdw->rcfg;
201230 struct device_node *np = pdev->dev.of_node;
202231 u32 mode = 0, tmp, input;
203232
....@@ -210,30 +239,63 @@
210239 mode |= AT91_SHDW_WKUPDBC(at91_shdwc_debouncer_value(pdev, tmp));
211240
212241 if (of_property_read_bool(np, "atmel,wakeup-rtc-timer"))
213
- mode |= SHDW_RTCWKEN(shdw->cfg);
242
+ mode |= SHDW_RTCWKEN(&rcfg->shdwc);
243
+
244
+ if (of_property_read_bool(np, "atmel,wakeup-rtt-timer"))
245
+ mode |= SHDW_RTTWKEN(&rcfg->shdwc);
214246
215247 dev_dbg(&pdev->dev, "%s: mode = %#x\n", __func__, mode);
216
- writel(mode, shdw->at91_shdwc_base + AT91_SHDW_MR);
248
+ writel(mode, shdw->shdwc_base + AT91_SHDW_MR);
217249
218250 input = at91_shdwc_get_wakeup_input(pdev, np);
219
- writel(input, shdw->at91_shdwc_base + AT91_SHDW_WUIR);
251
+ writel(input, shdw->shdwc_base + AT91_SHDW_WUIR);
220252 }
221253
222
-static const struct shdwc_config sama5d2_shdwc_config = {
223
- .wkup_pin_input = 0,
224
- .mr_rtcwk_shift = 17,
225
- .sr_rtcwk_shift = 5,
254
+static const struct reg_config sama5d2_reg_config = {
255
+ .shdwc = {
256
+ .wkup_pin_input = 0,
257
+ .mr_rtcwk_shift = 17,
258
+ .mr_rttwk_shift = SHDW_CFG_NOT_USED,
259
+ .sr_rtcwk_shift = 5,
260
+ .sr_rttwk_shift = SHDW_CFG_NOT_USED,
261
+ },
262
+ .pmc = {
263
+ .mckr = 0x30,
264
+ },
265
+};
266
+
267
+static const struct reg_config sam9x60_reg_config = {
268
+ .shdwc = {
269
+ .wkup_pin_input = 0,
270
+ .mr_rtcwk_shift = 17,
271
+ .mr_rttwk_shift = 16,
272
+ .sr_rtcwk_shift = 5,
273
+ .sr_rttwk_shift = 4,
274
+ },
275
+ .pmc = {
276
+ .mckr = 0x28,
277
+ },
226278 };
227279
228280 static const struct of_device_id at91_shdwc_of_match[] = {
229281 {
230282 .compatible = "atmel,sama5d2-shdwc",
231
- .data = &sama5d2_shdwc_config,
283
+ .data = &sama5d2_reg_config,
284
+ },
285
+ {
286
+ .compatible = "microchip,sam9x60-shdwc",
287
+ .data = &sam9x60_reg_config,
232288 }, {
233289 /*sentinel*/
234290 }
235291 };
236292 MODULE_DEVICE_TABLE(of, at91_shdwc_of_match);
293
+
294
+static const struct of_device_id at91_pmc_ids[] = {
295
+ { .compatible = "atmel,sama5d2-pmc" },
296
+ { .compatible = "microchip,sam9x60-pmc" },
297
+ { /* Sentinel. */ }
298
+};
237299
238300 static int __init at91_shdwc_probe(struct platform_device *pdev)
239301 {
....@@ -256,20 +318,20 @@
256318 platform_set_drvdata(pdev, at91_shdwc);
257319
258320 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
259
- at91_shdwc->at91_shdwc_base = devm_ioremap_resource(&pdev->dev, res);
260
- if (IS_ERR(at91_shdwc->at91_shdwc_base)) {
321
+ at91_shdwc->shdwc_base = devm_ioremap_resource(&pdev->dev, res);
322
+ if (IS_ERR(at91_shdwc->shdwc_base)) {
261323 dev_err(&pdev->dev, "Could not map reset controller address\n");
262
- return PTR_ERR(at91_shdwc->at91_shdwc_base);
324
+ return PTR_ERR(at91_shdwc->shdwc_base);
263325 }
264326
265327 match = of_match_node(at91_shdwc_of_match, pdev->dev.of_node);
266
- at91_shdwc->cfg = match->data;
328
+ at91_shdwc->rcfg = match->data;
267329
268
- sclk = devm_clk_get(&pdev->dev, NULL);
269
- if (IS_ERR(sclk))
270
- return PTR_ERR(sclk);
330
+ at91_shdwc->sclk = devm_clk_get(&pdev->dev, NULL);
331
+ if (IS_ERR(at91_shdwc->sclk))
332
+ return PTR_ERR(at91_shdwc->sclk);
271333
272
- ret = clk_prepare_enable(sclk);
334
+ ret = clk_prepare_enable(at91_shdwc->sclk);
273335 if (ret) {
274336 dev_err(&pdev->dev, "Could not enable slow clock\n");
275337 return ret;
....@@ -279,41 +341,70 @@
279341
280342 at91_shdwc_dt_configure(pdev);
281343
282
- pm_power_off = at91_poweroff;
344
+ np = of_find_matching_node(NULL, at91_pmc_ids);
345
+ if (!np) {
346
+ ret = -ENODEV;
347
+ goto clk_disable;
348
+ }
283349
284
- np = of_find_compatible_node(NULL, NULL, "atmel,sama5d3-ddramc");
285
- if (!np)
286
- return 0;
287
-
288
- mpddrc_base = of_iomap(np, 0);
350
+ at91_shdwc->pmc_base = of_iomap(np, 0);
289351 of_node_put(np);
290352
291
- if (!mpddrc_base)
292
- return 0;
353
+ if (!at91_shdwc->pmc_base) {
354
+ ret = -ENOMEM;
355
+ goto clk_disable;
356
+ }
293357
294
- ddr_type = readl(mpddrc_base + AT91_DDRSDRC_MDR) & AT91_DDRSDRC_MD;
295
- if ((ddr_type == AT91_DDRSDRC_MD_LPDDR2) ||
296
- (ddr_type == AT91_DDRSDRC_MD_LPDDR3))
297
- pm_power_off = at91_lpddr_poweroff;
298
- else
299
- iounmap(mpddrc_base);
358
+ np = of_find_compatible_node(NULL, NULL, "atmel,sama5d3-ddramc");
359
+ if (!np) {
360
+ ret = -ENODEV;
361
+ goto unmap;
362
+ }
363
+
364
+ at91_shdwc->mpddrc_base = of_iomap(np, 0);
365
+ of_node_put(np);
366
+
367
+ if (!at91_shdwc->mpddrc_base) {
368
+ ret = -ENOMEM;
369
+ goto unmap;
370
+ }
371
+
372
+ pm_power_off = at91_poweroff;
373
+
374
+ ddr_type = readl(at91_shdwc->mpddrc_base + AT91_DDRSDRC_MDR) &
375
+ AT91_DDRSDRC_MD;
376
+ if (ddr_type != AT91_DDRSDRC_MD_LPDDR2 &&
377
+ ddr_type != AT91_DDRSDRC_MD_LPDDR3) {
378
+ iounmap(at91_shdwc->mpddrc_base);
379
+ at91_shdwc->mpddrc_base = NULL;
380
+ }
300381
301382 return 0;
383
+
384
+unmap:
385
+ iounmap(at91_shdwc->pmc_base);
386
+clk_disable:
387
+ clk_disable_unprepare(at91_shdwc->sclk);
388
+
389
+ return ret;
302390 }
303391
304392 static int __exit at91_shdwc_remove(struct platform_device *pdev)
305393 {
306394 struct shdwc *shdw = platform_get_drvdata(pdev);
307395
308
- if (pm_power_off == at91_poweroff ||
309
- pm_power_off == at91_lpddr_poweroff)
396
+ if (pm_power_off == at91_poweroff)
310397 pm_power_off = NULL;
311398
312399 /* Reset values to disable wake-up features */
313
- writel(0, shdw->at91_shdwc_base + AT91_SHDW_MR);
314
- writel(0, shdw->at91_shdwc_base + AT91_SHDW_WUIR);
400
+ writel(0, shdw->shdwc_base + AT91_SHDW_MR);
401
+ writel(0, shdw->shdwc_base + AT91_SHDW_WUIR);
315402
316
- clk_disable_unprepare(sclk);
403
+ if (shdw->mpddrc_base)
404
+ iounmap(shdw->mpddrc_base);
405
+ iounmap(shdw->pmc_base);
406
+
407
+ clk_disable_unprepare(shdw->sclk);
317408
318409 return 0;
319410 }