blob: 1807639173b1293185992b9010b481e8be33ce87 [file] [log] [blame]
Gregory CLEMENT7444dad2012-08-02 11:17:51 +03001/*
2 * Power Management Service Unit(PMSU) support for Armada 370/XP platforms.
3 *
4 * Copyright (C) 2012 Marvell
5 *
6 * Yehuda Yitschak <yehuday@marvell.com>
7 * Gregory Clement <gregory.clement@free-electrons.com>
8 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
9 *
10 * This file is licensed under the terms of the GNU General Public
11 * License version 2. This program is licensed "as is" without any
12 * warranty of any kind, whether express or implied.
13 *
14 * The Armada 370 and Armada XP SOCs have a power management service
15 * unit which is responsible for powering down and waking up CPUs and
16 * other SOC units
17 */
18
19#include <linux/kernel.h>
20#include <linux/init.h>
21#include <linux/of_address.h>
22#include <linux/io.h>
23#include <linux/smp.h>
Thomas Petazzoni49754ff2014-04-14 15:50:29 +020024#include <linux/resource.h>
Gregory CLEMENT7444dad2012-08-02 11:17:51 +030025#include <asm/smp_plat.h>
Thomas Petazzoni49754ff2014-04-14 15:50:29 +020026#include "common.h"
Jisheng Zhangb12634e2013-11-07 17:02:38 +080027#include "pmsu.h"
Gregory CLEMENT7444dad2012-08-02 11:17:51 +030028
29static void __iomem *pmsu_mp_base;
Gregory CLEMENT7444dad2012-08-02 11:17:51 +030030
31#define PMSU_BOOT_ADDR_REDIRECT_OFFSET(cpu) ((cpu * 0x100) + 0x24)
Gregory CLEMENT7444dad2012-08-02 11:17:51 +030032
33static struct of_device_id of_pmsu_table[] = {
34 {.compatible = "marvell,armada-370-xp-pmsu"},
35 { /* end of list */ },
36};
37
38#ifdef CONFIG_SMP
39int armada_xp_boot_cpu(unsigned int cpu_id, void *boot_addr)
40{
Thomas Petazzoni49754ff2014-04-14 15:50:29 +020041 int hw_cpu, ret;
Gregory CLEMENT7444dad2012-08-02 11:17:51 +030042
Thomas Petazzoni49754ff2014-04-14 15:50:29 +020043 if (!pmsu_mp_base) {
Gregory CLEMENT7444dad2012-08-02 11:17:51 +030044 pr_warn("Can't boot CPU. PMSU is uninitialized\n");
Thomas Petazzoni49754ff2014-04-14 15:50:29 +020045 return -ENODEV;
Gregory CLEMENT7444dad2012-08-02 11:17:51 +030046 }
47
48 hw_cpu = cpu_logical_map(cpu_id);
49
50 writel(virt_to_phys(boot_addr), pmsu_mp_base +
51 PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu));
52
Thomas Petazzoni49754ff2014-04-14 15:50:29 +020053 ret = mvebu_cpu_reset_deassert(hw_cpu);
54 if (ret) {
55 pr_warn("unable to boot CPU: %d\n", ret);
56 return ret;
57 }
Gregory CLEMENT7444dad2012-08-02 11:17:51 +030058
59 return 0;
60}
61#endif
62
Jisheng Zhangb12634e2013-11-07 17:02:38 +080063static int __init armada_370_xp_pmsu_init(void)
Gregory CLEMENT7444dad2012-08-02 11:17:51 +030064{
65 struct device_node *np;
66
67 np = of_find_matching_node(NULL, of_pmsu_table);
68 if (np) {
69 pr_info("Initializing Power Management Service Unit\n");
70 pmsu_mp_base = of_iomap(np, 0);
Jisheng Zhangabe511a2013-08-27 12:41:14 +080071 of_node_put(np);
Gregory CLEMENT7444dad2012-08-02 11:17:51 +030072 }
73
74 return 0;
75}
76
77early_initcall(armada_370_xp_pmsu_init);