162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Zynq power management 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2012 - 2014 Xilinx 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Sören Brinkmann <soren.brinkmann@xilinx.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/io.h> 1162306a36Sopenharmony_ci#include <linux/of.h> 1262306a36Sopenharmony_ci#include <linux/of_address.h> 1362306a36Sopenharmony_ci#include "common.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* register offsets */ 1662306a36Sopenharmony_ci#define DDRC_CTRL_REG1_OFFS 0x60 1762306a36Sopenharmony_ci#define DDRC_DRAM_PARAM_REG3_OFFS 0x20 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* bitfields */ 2062306a36Sopenharmony_ci#define DDRC_CLOCKSTOP_MASK BIT(23) 2162306a36Sopenharmony_ci#define DDRC_SELFREFRESH_MASK BIT(12) 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic void __iomem *ddrc_base; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/** 2662306a36Sopenharmony_ci * zynq_pm_ioremap() - Create IO mappings 2762306a36Sopenharmony_ci * @comp: DT compatible string 2862306a36Sopenharmony_ci * Return: Pointer to the mapped memory or NULL. 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * Remap the memory region for a compatible DT node. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_cistatic void __iomem *zynq_pm_ioremap(const char *comp) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci struct device_node *np; 3562306a36Sopenharmony_ci void __iomem *base = NULL; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, comp); 3862306a36Sopenharmony_ci if (np) { 3962306a36Sopenharmony_ci base = of_iomap(np, 0); 4062306a36Sopenharmony_ci of_node_put(np); 4162306a36Sopenharmony_ci } else { 4262306a36Sopenharmony_ci pr_warn("%s: no compatible node found for '%s'\n", __func__, 4362306a36Sopenharmony_ci comp); 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci return base; 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/** 5062306a36Sopenharmony_ci * zynq_pm_late_init() - Power management init 5162306a36Sopenharmony_ci * 5262306a36Sopenharmony_ci * Initialization of power management related features and infrastructure. 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_civoid __init zynq_pm_late_init(void) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci u32 reg; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci ddrc_base = zynq_pm_ioremap("xlnx,zynq-ddrc-a05"); 5962306a36Sopenharmony_ci if (!ddrc_base) { 6062306a36Sopenharmony_ci pr_warn("%s: Unable to map DDRC IO memory.\n", __func__); 6162306a36Sopenharmony_ci } else { 6262306a36Sopenharmony_ci /* 6362306a36Sopenharmony_ci * Enable DDRC clock stop feature. The HW takes care of 6462306a36Sopenharmony_ci * entering/exiting the correct mode depending 6562306a36Sopenharmony_ci * on activity state. 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_ci reg = readl(ddrc_base + DDRC_DRAM_PARAM_REG3_OFFS); 6862306a36Sopenharmony_ci reg |= DDRC_CLOCKSTOP_MASK; 6962306a36Sopenharmony_ci writel(reg, ddrc_base + DDRC_DRAM_PARAM_REG3_OFFS); 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci} 72