diff options
Diffstat (limited to 'arch/arm/mach-zynq/pm.c')
-rw-r--r-- | arch/arm/mach-zynq/pm.c | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/arch/arm/mach-zynq/pm.c b/arch/arm/mach-zynq/pm.c new file mode 100644 index 000000000..8ba450ab5 --- /dev/null +++ b/arch/arm/mach-zynq/pm.c @@ -0,0 +1,71 @@ +// 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_address.h> +#include <linux/of_device.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); + } +} |