// SPDX-License-Identifier: GPL-2.0-or-later /* * Zynq power management * * Copyright (C) 2012 - 2014 Xilinx * * Sören Brinkmann <soren.brinkmann@xilinx.com> */ #include <linux/io.h> #include <linux/of.h> #include <linux/of_address.h> #include "common.h" /* register offsets */ #define DDRC_CTRL_REG1_OFFS 0x60 #define DDRC_DRAM_PARAM_REG3_OFFS 0x20 /* bitfields */ #define DDRC_CLOCKSTOP_MASK BIT(23) #define DDRC_SELFREFRESH_MASK BIT(12) static void __iomem *ddrc_base; /** * zynq_pm_ioremap() - Create IO mappings * @comp: DT compatible string * Return: Pointer to the mapped memory or NULL. * * Remap the memory region for a compatible DT node. */ static void __iomem *zynq_pm_ioremap(const char *comp) { struct device_node *np; void __iomem *base = NULL; np = of_find_compatible_node(NULL, NULL, comp); if (np) { base = of_iomap(np, 0); of_node_put(np); } else { pr_warn("%s: no compatible node found for '%s'\n", __func__, comp); } return base; } /** * zynq_pm_late_init() - Power management init * * Initialization of power management related features and infrastructure. */ void __init zynq_pm_late_init(void) { u32 reg; ddrc_base = zynq_pm_ioremap("xlnx,zynq-ddrc-a05"); if (!ddrc_base) { pr_warn("%s: Unable to map DDRC IO memory.\n", __func__); } else { /* * Enable DDRC clock stop feature. The HW takes care of * entering/exiting the correct mode depending * on activity state. */ reg = readl(ddrc_base + DDRC_DRAM_PARAM_REG3_OFFS); reg |= DDRC_CLOCKSTOP_MASK; writel(reg, ddrc_base + DDRC_DRAM_PARAM_REG3_OFFS); } }