forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
71 lines
1.6 KiB
71 lines
1.6 KiB
// SPDX-License-Identifier: GPL-2.0-or-later |
|
/* |
|
* Zynq power management |
|
* |
|
* Copyright (C) 2012 - 2014 Xilinx |
|
* |
|
* Sören Brinkmann <[email protected]> |
|
*/ |
|
|
|
#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); |
|
} |
|
}
|
|
|