blob: 6b92d1ea03fb2a53325c1437a82dfa7f27b34180 [file] [log] [blame]
Mahesh Sivasubramanianf2d6eb82011-11-22 16:33:48 -07001/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -06002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/io.h>
Maheshkumar Sivasubramanianc6c55032011-10-25 16:01:32 -060018#include <mach/msm_iomap.h>
19#include <mach/socinfo.h>
20#include <asm/mach-types.h>
21#include <asm/sizes.h>
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -060022#include "scm-boot.h"
23#include "idle.h"
24#include "pm-boot.h"
25
26static uint32_t *msm_pm_reset_vector;
27static uint32_t saved_vector[2];
28static void (*msm_pm_boot_before_pc)(unsigned int cpu, unsigned long entry);
29static void (*msm_pm_boot_after_pc)(unsigned int cpu);
30
31#ifdef CONFIG_MSM_SCM
32static int __init msm_pm_tz_boot_init(void)
33{
34 int flag = 0;
35 if (num_possible_cpus() == 1)
36 flag = SCM_FLAG_WARMBOOT_CPU0;
37 else if (num_possible_cpus() == 2)
38 flag = SCM_FLAG_WARMBOOT_CPU0 | SCM_FLAG_WARMBOOT_CPU1;
39 else
40 __WARN();
41
42 return scm_set_boot_addr((void *)virt_to_phys(msm_pm_boot_entry), flag);
43}
44
45static void msm_pm_config_tz_before_pc(unsigned int cpu,
46 unsigned long entry)
47{
48 msm_pm_write_boot_vector(cpu, entry);
49}
50#else
51static int __init msm_pm_tz_boot_init(void)
52{
53 return 0;
54};
55
56static inline void msm_pm_config_tz_before_pc(unsigned int cpu,
57 unsigned long entry) {}
58#endif
59
60static int __init msm_pm_boot_reset_vector_init(uint32_t *reset_vector)
61{
Maheshkumar Sivasubramanianc6c55032011-10-25 16:01:32 -060062 if (!reset_vector)
63 return -ENODEV;
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -060064 msm_pm_reset_vector = reset_vector;
65 mb();
66
67 return 0;
68}
69
70static void msm_pm_config_rst_vector_before_pc(unsigned int cpu,
71 unsigned long entry)
72{
73 saved_vector[0] = msm_pm_reset_vector[0];
74 saved_vector[1] = msm_pm_reset_vector[1];
75 msm_pm_reset_vector[0] = 0xE51FF004; /* ldr pc, 4 */
76 msm_pm_reset_vector[1] = entry;
77}
78
79static void msm_pm_config_rst_vector_after_pc(unsigned int cpu)
80{
81 msm_pm_reset_vector[0] = saved_vector[0];
82 msm_pm_reset_vector[1] = saved_vector[1];
83}
84
85void msm_pm_boot_config_before_pc(unsigned int cpu, unsigned long entry)
86{
87 if (msm_pm_boot_before_pc)
88 msm_pm_boot_before_pc(cpu, entry);
89}
90
91void msm_pm_boot_config_after_pc(unsigned int cpu)
92{
93 if (msm_pm_boot_after_pc)
94 msm_pm_boot_after_pc(cpu);
95}
Maheshkumar Sivasubramanianc6c55032011-10-25 16:01:32 -060096#define BOOT_REMAP_ENABLE BIT(0)
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -060097
Maheshkumar Sivasubramanianc6c55032011-10-25 16:01:32 -060098int __init msm_pm_boot_init(struct msm_pm_boot_platform_data *pdata)
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -060099{
100 int ret = 0;
101
Maheshkumar Sivasubramanianc6c55032011-10-25 16:01:32 -0600102 switch (pdata->mode) {
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -0600103 case MSM_PM_BOOT_CONFIG_TZ:
104 ret = msm_pm_tz_boot_init();
105 msm_pm_boot_before_pc = msm_pm_config_tz_before_pc;
106 msm_pm_boot_after_pc = NULL;
107 break;
Maheshkumar Sivasubramanianc6c55032011-10-25 16:01:32 -0600108 case MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS:
109 if (!pdata->p_addr)
110 return -ENODEV;
111 pdata->v_addr = ioremap(pdata->p_addr, PAGE_SIZE);
112 /* Fall through */
113 case MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT:
114
115 if (!pdata->v_addr)
116 return -ENODEV;
117
118 ret = msm_pm_boot_reset_vector_init(pdata->v_addr);
119 msm_pm_boot_before_pc
120 = msm_pm_config_rst_vector_before_pc;
121 msm_pm_boot_after_pc
122 = msm_pm_config_rst_vector_after_pc;
123 break;
124 case MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR:
125 /*
126 * Set the boot remap address and enable remapping of
127 * reset vector
128 */
129 if (!pdata->p_addr || !pdata->v_addr)
130 return -ENODEV;
131
132 __raw_writel((pdata->p_addr | BOOT_REMAP_ENABLE),
133 pdata->v_addr);
134
135 ret = msm_pm_boot_reset_vector_init(__va(pdata->p_addr));
136
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -0600137 msm_pm_boot_before_pc
138 = msm_pm_config_rst_vector_before_pc;
139 msm_pm_boot_after_pc
140 = msm_pm_config_rst_vector_after_pc;
141 break;
142 default:
143 __WARN();
144 }
145
146 return ret;
147}