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