xref: /openbmc/linux/arch/arm/mach-zynq/pm.c (revision bb54e660)
11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
20beb2bd3SSoren Brinkmann /*
30beb2bd3SSoren Brinkmann  * Zynq power management
40beb2bd3SSoren Brinkmann  *
50beb2bd3SSoren Brinkmann  *  Copyright (C) 2012 - 2014 Xilinx
60beb2bd3SSoren Brinkmann  *
70beb2bd3SSoren Brinkmann  *  Sören Brinkmann <soren.brinkmann@xilinx.com>
80beb2bd3SSoren Brinkmann  */
90beb2bd3SSoren Brinkmann 
100beb2bd3SSoren Brinkmann #include <linux/io.h>
11*bb54e660SRob Herring #include <linux/of.h>
120beb2bd3SSoren Brinkmann #include <linux/of_address.h>
130beb2bd3SSoren Brinkmann #include "common.h"
140beb2bd3SSoren Brinkmann 
150beb2bd3SSoren Brinkmann /* register offsets */
160beb2bd3SSoren Brinkmann #define DDRC_CTRL_REG1_OFFS		0x60
170beb2bd3SSoren Brinkmann #define DDRC_DRAM_PARAM_REG3_OFFS	0x20
180beb2bd3SSoren Brinkmann 
190beb2bd3SSoren Brinkmann /* bitfields */
200beb2bd3SSoren Brinkmann #define DDRC_CLOCKSTOP_MASK	BIT(23)
210beb2bd3SSoren Brinkmann #define DDRC_SELFREFRESH_MASK	BIT(12)
220beb2bd3SSoren Brinkmann 
230beb2bd3SSoren Brinkmann static void __iomem *ddrc_base;
240beb2bd3SSoren Brinkmann 
250beb2bd3SSoren Brinkmann /**
260beb2bd3SSoren Brinkmann  * zynq_pm_ioremap() - Create IO mappings
270beb2bd3SSoren Brinkmann  * @comp:	DT compatible string
280beb2bd3SSoren Brinkmann  * Return: Pointer to the mapped memory or NULL.
290beb2bd3SSoren Brinkmann  *
300beb2bd3SSoren Brinkmann  * Remap the memory region for a compatible DT node.
310beb2bd3SSoren Brinkmann  */
zynq_pm_ioremap(const char * comp)320beb2bd3SSoren Brinkmann static void __iomem *zynq_pm_ioremap(const char *comp)
330beb2bd3SSoren Brinkmann {
340beb2bd3SSoren Brinkmann 	struct device_node *np;
350beb2bd3SSoren Brinkmann 	void __iomem *base = NULL;
360beb2bd3SSoren Brinkmann 
370beb2bd3SSoren Brinkmann 	np = of_find_compatible_node(NULL, NULL, comp);
380beb2bd3SSoren Brinkmann 	if (np) {
390beb2bd3SSoren Brinkmann 		base = of_iomap(np, 0);
400beb2bd3SSoren Brinkmann 		of_node_put(np);
410beb2bd3SSoren Brinkmann 	} else {
420beb2bd3SSoren Brinkmann 		pr_warn("%s: no compatible node found for '%s'\n", __func__,
430beb2bd3SSoren Brinkmann 				comp);
440beb2bd3SSoren Brinkmann 	}
450beb2bd3SSoren Brinkmann 
460beb2bd3SSoren Brinkmann 	return base;
470beb2bd3SSoren Brinkmann }
480beb2bd3SSoren Brinkmann 
490beb2bd3SSoren Brinkmann /**
500beb2bd3SSoren Brinkmann  * zynq_pm_late_init() - Power management init
510beb2bd3SSoren Brinkmann  *
52bb9cac24SMoritz Fischer  * Initialization of power management related features and infrastructure.
530beb2bd3SSoren Brinkmann  */
zynq_pm_late_init(void)540beb2bd3SSoren Brinkmann void __init zynq_pm_late_init(void)
550beb2bd3SSoren Brinkmann {
560beb2bd3SSoren Brinkmann 	u32 reg;
570beb2bd3SSoren Brinkmann 
580beb2bd3SSoren Brinkmann 	ddrc_base = zynq_pm_ioremap("xlnx,zynq-ddrc-a05");
590beb2bd3SSoren Brinkmann 	if (!ddrc_base) {
600beb2bd3SSoren Brinkmann 		pr_warn("%s: Unable to map DDRC IO memory.\n", __func__);
610beb2bd3SSoren Brinkmann 	} else {
620beb2bd3SSoren Brinkmann 		/*
630beb2bd3SSoren Brinkmann 		 * Enable DDRC clock stop feature. The HW takes care of
640beb2bd3SSoren Brinkmann 		 * entering/exiting the correct mode depending
650beb2bd3SSoren Brinkmann 		 * on activity state.
660beb2bd3SSoren Brinkmann 		 */
670beb2bd3SSoren Brinkmann 		reg = readl(ddrc_base + DDRC_DRAM_PARAM_REG3_OFFS);
680beb2bd3SSoren Brinkmann 		reg |= DDRC_CLOCKSTOP_MASK;
690beb2bd3SSoren Brinkmann 		writel(reg, ddrc_base + DDRC_DRAM_PARAM_REG3_OFFS);
700beb2bd3SSoren Brinkmann 	}
710beb2bd3SSoren Brinkmann }
72