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 } 72