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 Brinkmannstatic 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 Brinkmannvoid __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