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  */
zynq_pm_ioremap(const char * comp)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  */
zynq_pm_late_init(void)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 }
72