Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / arch / arm / mach-zynq / pm.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Zynq power management
4  *
5  *  Copyright (C) 2012 - 2014 Xilinx
6  *
7  *  Sören Brinkmann <soren.brinkmann@xilinx.com>
8  */
9
10 #include <linux/io.h>
11 #include <linux/of_address.h>
12 #include <linux/of_device.h>
13 #include "common.h"
14
15 /* register offsets */
16 #define DDRC_CTRL_REG1_OFFS             0x60
17 #define DDRC_DRAM_PARAM_REG3_OFFS       0x20
18
19 /* bitfields */
20 #define DDRC_CLOCKSTOP_MASK     BIT(23)
21 #define DDRC_SELFREFRESH_MASK   BIT(12)
22
23 static void __iomem *ddrc_base;
24
25 /**
26  * zynq_pm_ioremap() - Create IO mappings
27  * @comp:       DT compatible string
28  * Return: Pointer to the mapped memory or NULL.
29  *
30  * Remap the memory region for a compatible DT node.
31  */
32 static void __iomem *zynq_pm_ioremap(const char *comp)
33 {
34         struct device_node *np;
35         void __iomem *base = NULL;
36
37         np = of_find_compatible_node(NULL, NULL, comp);
38         if (np) {
39                 base = of_iomap(np, 0);
40                 of_node_put(np);
41         } else {
42                 pr_warn("%s: no compatible node found for '%s'\n", __func__,
43                                 comp);
44         }
45
46         return base;
47 }
48
49 /**
50  * zynq_pm_late_init() - Power management init
51  *
52  * Initialization of power management related features and infrastructure.
53  */
54 void __init zynq_pm_late_init(void)
55 {
56         u32 reg;
57
58         ddrc_base = zynq_pm_ioremap("xlnx,zynq-ddrc-a05");
59         if (!ddrc_base) {
60                 pr_warn("%s: Unable to map DDRC IO memory.\n", __func__);
61         } else {
62                 /*
63                  * Enable DDRC clock stop feature. The HW takes care of
64                  * entering/exiting the correct mode depending
65                  * on activity state.
66                  */
67                 reg = readl(ddrc_base + DDRC_DRAM_PARAM_REG3_OFFS);
68                 reg |= DDRC_CLOCKSTOP_MASK;
69                 writel(reg, ddrc_base + DDRC_DRAM_PARAM_REG3_OFFS);
70         }
71 }