aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/soc/bcm/brcmstb/Kconfig2
-rw-r--r--drivers/soc/bcm/brcmstb/pm/Makefile1
-rw-r--r--drivers/soc/bcm/brcmstb/pm/pm-mips.c461
-rw-r--r--drivers/soc/bcm/brcmstb/pm/pm.h13
-rw-r--r--drivers/soc/bcm/brcmstb/pm/s2-mips.S200
-rw-r--r--drivers/soc/bcm/brcmstb/pm/s3-mips.S146
6 files changed, 821 insertions, 2 deletions
diff --git a/drivers/soc/bcm/brcmstb/Kconfig b/drivers/soc/bcm/brcmstb/Kconfig
index 4425430119fe..d36f6e03c1a6 100644
--- a/drivers/soc/bcm/brcmstb/Kconfig
+++ b/drivers/soc/bcm/brcmstb/Kconfig
@@ -4,7 +4,7 @@ config BRCMSTB_PM
4 bool "Support suspend/resume for STB platforms" 4 bool "Support suspend/resume for STB platforms"
5 default y 5 default y
6 depends on PM 6 depends on PM
7 depends on ARCH_BRCMSTB 7 depends on ARCH_BRCMSTB || BMIPS_GENERIC
8 select ARM_CPU_SUSPEND if ARM 8 select ARM_CPU_SUSPEND if ARM
9 9
10endif # SOC_BRCMSTB 10endif # SOC_BRCMSTB
diff --git a/drivers/soc/bcm/brcmstb/pm/Makefile b/drivers/soc/bcm/brcmstb/pm/Makefile
index 7c3d20135b7c..08bbd244ef11 100644
--- a/drivers/soc/bcm/brcmstb/pm/Makefile
+++ b/drivers/soc/bcm/brcmstb/pm/Makefile
@@ -1,2 +1,3 @@
1obj-$(CONFIG_ARM) += s2-arm.o pm-arm.o 1obj-$(CONFIG_ARM) += s2-arm.o pm-arm.o
2AFLAGS_s2-arm.o := -march=armv7-a 2AFLAGS_s2-arm.o := -march=armv7-a
3obj-$(CONFIG_BMIPS_GENERIC) += s2-mips.o s3-mips.o pm-mips.o
diff --git a/drivers/soc/bcm/brcmstb/pm/pm-mips.c b/drivers/soc/bcm/brcmstb/pm/pm-mips.c
new file mode 100644
index 000000000000..9300b5f62e56
--- /dev/null
+++ b/drivers/soc/bcm/brcmstb/pm/pm-mips.c
@@ -0,0 +1,461 @@
1/*
2 * MIPS-specific support for Broadcom STB S2/S3/S5 power management
3 *
4 * Copyright (C) 2016-2017 Broadcom
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <linux/kernel.h>
17#include <linux/printk.h>
18#include <linux/io.h>
19#include <linux/of.h>
20#include <linux/of_address.h>
21#include <linux/delay.h>
22#include <linux/suspend.h>
23#include <asm/bmips.h>
24#include <asm/tlbflush.h>
25
26#include "pm.h"
27
28#define S2_NUM_PARAMS 6
29#define MAX_NUM_MEMC 3
30
31/* S3 constants */
32#define MAX_GP_REGS 16
33#define MAX_CP0_REGS 32
34#define NUM_MEMC_CLIENTS 128
35#define AON_CTRL_RAM_SIZE 128
36#define BRCMSTB_S3_MAGIC 0x5AFEB007
37
38#define CLEAR_RESET_MASK 0x01
39
40/* Index each CP0 register that needs to be saved */
41#define CONTEXT 0
42#define USER_LOCAL 1
43#define PGMK 2
44#define HWRENA 3
45#define COMPARE 4
46#define STATUS 5
47#define CONFIG 6
48#define MODE 7
49#define EDSP 8
50#define BOOT_VEC 9
51#define EBASE 10
52
53struct brcmstb_memc {
54 void __iomem *ddr_phy_base;
55 void __iomem *arb_base;
56};
57
58struct brcmstb_pm_control {
59 void __iomem *aon_ctrl_base;
60 void __iomem *aon_sram_base;
61 void __iomem *timers_base;
62 struct brcmstb_memc memcs[MAX_NUM_MEMC];
63 int num_memc;
64};
65
66struct brcm_pm_s3_context {
67 u32 cp0_regs[MAX_CP0_REGS];
68 u32 memc0_rts[NUM_MEMC_CLIENTS];
69 u32 sc_boot_vec;
70};
71
72struct brcmstb_mem_transfer;
73
74struct brcmstb_mem_transfer {
75 struct brcmstb_mem_transfer *next;
76 void *src;
77 void *dst;
78 dma_addr_t pa_src;
79 dma_addr_t pa_dst;
80 u32 len;
81 u8 key;
82 u8 mode;
83 u8 src_remapped;
84 u8 dst_remapped;
85 u8 src_dst_remapped;
86};
87
88#define AON_SAVE_SRAM(base, idx, val) \
89 __raw_writel(val, base + (idx << 2))
90
91/* Used for saving registers in asm */
92u32 gp_regs[MAX_GP_REGS];
93
94#define BSP_CLOCK_STOP 0x00
95#define PM_INITIATE 0x01
96
97static struct brcmstb_pm_control ctrl;
98
99static void brcm_pm_save_cp0_context(struct brcm_pm_s3_context *ctx)
100{
101 /* Generic MIPS */
102 ctx->cp0_regs[CONTEXT] = read_c0_context();
103 ctx->cp0_regs[USER_LOCAL] = read_c0_userlocal();
104 ctx->cp0_regs[PGMK] = read_c0_pagemask();
105 ctx->cp0_regs[HWRENA] = read_c0_cache();
106 ctx->cp0_regs[COMPARE] = read_c0_compare();
107 ctx->cp0_regs[STATUS] = read_c0_status();
108
109 /* Broadcom specific */
110 ctx->cp0_regs[CONFIG] = read_c0_brcm_config();
111 ctx->cp0_regs[MODE] = read_c0_brcm_mode();
112 ctx->cp0_regs[EDSP] = read_c0_brcm_edsp();
113 ctx->cp0_regs[BOOT_VEC] = read_c0_brcm_bootvec();
114 ctx->cp0_regs[EBASE] = read_c0_ebase();
115
116 ctx->sc_boot_vec = bmips_read_zscm_reg(0xa0);
117}
118
119static void brcm_pm_restore_cp0_context(struct brcm_pm_s3_context *ctx)
120{
121 /* Restore cp0 state */
122 bmips_write_zscm_reg(0xa0, ctx->sc_boot_vec);
123
124 /* Generic MIPS */
125 write_c0_context(ctx->cp0_regs[CONTEXT]);
126 write_c0_userlocal(ctx->cp0_regs[USER_LOCAL]);
127 write_c0_pagemask(ctx->cp0_regs[PGMK]);
128 write_c0_cache(ctx->cp0_regs[HWRENA]);
129 write_c0_compare(ctx->cp0_regs[COMPARE]);
130 write_c0_status(ctx->cp0_regs[STATUS]);
131
132 /* Broadcom specific */
133 write_c0_brcm_config(ctx->cp0_regs[CONFIG]);
134 write_c0_brcm_mode(ctx->cp0_regs[MODE]);
135 write_c0_brcm_edsp(ctx->cp0_regs[EDSP]);
136 write_c0_brcm_bootvec(ctx->cp0_regs[BOOT_VEC]);
137 write_c0_ebase(ctx->cp0_regs[EBASE]);
138}
139
140static void brcmstb_pm_handshake(void)
141{
142 void __iomem *base = ctrl.aon_ctrl_base;
143 u32 tmp;
144
145 /* BSP power handshake, v1 */
146 tmp = __raw_readl(base + AON_CTRL_HOST_MISC_CMDS);
147 tmp &= ~1UL;
148 __raw_writel(tmp, base + AON_CTRL_HOST_MISC_CMDS);
149 (void)__raw_readl(base + AON_CTRL_HOST_MISC_CMDS);
150
151 __raw_writel(0, base + AON_CTRL_PM_INITIATE);
152 (void)__raw_readl(base + AON_CTRL_PM_INITIATE);
153 __raw_writel(BSP_CLOCK_STOP | PM_INITIATE,
154 base + AON_CTRL_PM_INITIATE);
155 /*
156 * HACK: BSP may have internal race on the CLOCK_STOP command.
157 * Avoid touching the BSP for a few milliseconds.
158 */
159 mdelay(3);
160}
161
162static void brcmstb_pm_s5(void)
163{
164 void __iomem *base = ctrl.aon_ctrl_base;
165
166 brcmstb_pm_handshake();
167
168 /* Clear magic s3 warm-boot value */
169 AON_SAVE_SRAM(ctrl.aon_sram_base, 0, 0);
170
171 /* Set the countdown */
172 __raw_writel(0x10, base + AON_CTRL_PM_CPU_WAIT_COUNT);
173 (void)__raw_readl(base + AON_CTRL_PM_CPU_WAIT_COUNT);
174
175 /* Prepare to S5 cold boot */
176 __raw_writel(PM_COLD_CONFIG, base + AON_CTRL_PM_CTRL);
177 (void)__raw_readl(base + AON_CTRL_PM_CTRL);
178
179 __raw_writel((PM_COLD_CONFIG | PM_PWR_DOWN), base +
180 AON_CTRL_PM_CTRL);
181 (void)__raw_readl(base + AON_CTRL_PM_CTRL);
182
183 __asm__ __volatile__(
184 " wait\n"
185 : : : "memory");
186}
187
188static int brcmstb_pm_s3(void)
189{
190 struct brcm_pm_s3_context s3_context;
191 void __iomem *memc_arb_base;
192 unsigned long flags;
193 u32 tmp;
194 int i;
195
196 /* Prepare for s3 */
197 AON_SAVE_SRAM(ctrl.aon_sram_base, 0, BRCMSTB_S3_MAGIC);
198 AON_SAVE_SRAM(ctrl.aon_sram_base, 1, (u32)&s3_reentry);
199 AON_SAVE_SRAM(ctrl.aon_sram_base, 2, 0);
200
201 /* Clear RESET_HISTORY */
202 tmp = __raw_readl(ctrl.aon_ctrl_base + AON_CTRL_RESET_CTRL);
203 tmp &= ~CLEAR_RESET_MASK;
204 __raw_writel(tmp, ctrl.aon_ctrl_base + AON_CTRL_RESET_CTRL);
205
206 local_irq_save(flags);
207
208 /* Inhibit DDR_RSTb pulse for both MMCs*/
209 for (i = 0; i < ctrl.num_memc; i++) {
210 tmp = __raw_readl(ctrl.memcs[i].ddr_phy_base +
211 DDR40_PHY_CONTROL_REGS_0_STANDBY_CTRL);
212
213 tmp &= ~0x0f;
214 __raw_writel(tmp, ctrl.memcs[i].ddr_phy_base +
215 DDR40_PHY_CONTROL_REGS_0_STANDBY_CTRL);
216 tmp |= (0x05 | BIT(5));
217 __raw_writel(tmp, ctrl.memcs[i].ddr_phy_base +
218 DDR40_PHY_CONTROL_REGS_0_STANDBY_CTRL);
219 }
220
221 /* Save CP0 context */
222 brcm_pm_save_cp0_context(&s3_context);
223
224 /* Save RTS(skip debug register) */
225 memc_arb_base = ctrl.memcs[0].arb_base + 4;
226 for (i = 0; i < NUM_MEMC_CLIENTS; i++) {
227 s3_context.memc0_rts[i] = __raw_readl(memc_arb_base);
228 memc_arb_base += 4;
229 }
230
231 /* Save I/O context */
232 local_flush_tlb_all();
233 _dma_cache_wback_inv(0, ~0);
234
235 brcm_pm_do_s3(ctrl.aon_ctrl_base, current_cpu_data.dcache.linesz);
236
237 /* CPU reconfiguration */
238 local_flush_tlb_all();
239 bmips_cpu_setup();
240 cpumask_clear(&bmips_booted_mask);
241
242 /* Restore RTS (skip debug register) */
243 memc_arb_base = ctrl.memcs[0].arb_base + 4;
244 for (i = 0; i < NUM_MEMC_CLIENTS; i++) {
245 __raw_writel(s3_context.memc0_rts[i], memc_arb_base);
246 memc_arb_base += 4;
247 }
248
249 /* restore CP0 context */
250 brcm_pm_restore_cp0_context(&s3_context);
251
252 local_irq_restore(flags);
253
254 return 0;
255}
256
257static int brcmstb_pm_s2(void)
258{
259 /*
260 * We need to pass 6 arguments to an assembly function. Lets avoid the
261 * stack and pass arguments in a explicit 4 byte array. The assembly
262 * code assumes all arguments are 4 bytes and arguments are ordered
263 * like so:
264 *
265 * 0: AON_CTRl base register
266 * 1: DDR_PHY base register
267 * 2: TIMERS base resgister
268 * 3: I-Cache line size
269 * 4: Restart vector address
270 * 5: Restart vector size
271 */
272 u32 s2_params[6];
273
274 /* Prepare s2 parameters */
275 s2_params[0] = (u32)ctrl.aon_ctrl_base;
276 s2_params[1] = (u32)ctrl.memcs[0].ddr_phy_base;
277 s2_params[2] = (u32)ctrl.timers_base;
278 s2_params[3] = (u32)current_cpu_data.icache.linesz;
279 s2_params[4] = (u32)BMIPS_WARM_RESTART_VEC;
280 s2_params[5] = (u32)(bmips_smp_int_vec_end -
281 bmips_smp_int_vec);
282
283 /* Drop to standby */
284 brcm_pm_do_s2(s2_params);
285
286 return 0;
287}
288
289static int brcmstb_pm_standby(bool deep_standby)
290{
291 brcmstb_pm_handshake();
292
293 /* Send IRQs to BMIPS_WARM_RESTART_VEC */
294 clear_c0_cause(CAUSEF_IV);
295 irq_disable_hazard();
296 set_c0_status(ST0_BEV);
297 irq_disable_hazard();
298
299 if (deep_standby)
300 brcmstb_pm_s3();
301 else
302 brcmstb_pm_s2();
303
304 /* Send IRQs to normal runtime vectors */
305 clear_c0_status(ST0_BEV);
306 irq_disable_hazard();
307 set_c0_cause(CAUSEF_IV);
308 irq_disable_hazard();
309
310 return 0;
311}
312
313static int brcmstb_pm_enter(suspend_state_t state)
314{
315 int ret = -EINVAL;
316
317 switch (state) {
318 case PM_SUSPEND_STANDBY:
319 ret = brcmstb_pm_standby(false);
320 break;
321 case PM_SUSPEND_MEM:
322 ret = brcmstb_pm_standby(true);
323 break;
324 }
325
326 return ret;
327}
328
329static int brcmstb_pm_valid(suspend_state_t state)
330{
331 switch (state) {
332 case PM_SUSPEND_STANDBY:
333 return true;
334 case PM_SUSPEND_MEM:
335 return true;
336 default:
337 return false;
338 }
339}
340
341static const struct platform_suspend_ops brcmstb_pm_ops = {
342 .enter = brcmstb_pm_enter,
343 .valid = brcmstb_pm_valid,
344};
345
346static const struct of_device_id aon_ctrl_dt_ids[] = {
347 { .compatible = "brcm,brcmstb-aon-ctrl" },
348 { /* sentinel */ }
349};
350
351static const struct of_device_id ddr_phy_dt_ids[] = {
352 { .compatible = "brcm,brcmstb-ddr-phy" },
353 { /* sentinel */ }
354};
355
356static const struct of_device_id arb_dt_ids[] = {
357 { .compatible = "brcm,brcmstb-memc-arb" },
358 { /* sentinel */ }
359};
360
361static const struct of_device_id timers_ids[] = {
362 { .compatible = "brcm,brcmstb-timers" },
363 { /* sentinel */ }
364};
365
366static inline void __iomem *brcmstb_ioremap_node(struct device_node *dn,
367 int index)
368{
369 return of_io_request_and_map(dn, index, dn->full_name);
370}
371
372static void __iomem *brcmstb_ioremap_match(const struct of_device_id *matches,
373 int index, const void **ofdata)
374{
375 struct device_node *dn;
376 const struct of_device_id *match;
377
378 dn = of_find_matching_node_and_match(NULL, matches, &match);
379 if (!dn)
380 return ERR_PTR(-EINVAL);
381
382 if (ofdata)
383 *ofdata = match->data;
384
385 return brcmstb_ioremap_node(dn, index);
386}
387
388static int brcmstb_pm_init(void)
389{
390 struct device_node *dn;
391 void __iomem *base;
392 int i;
393
394 /* AON ctrl registers */
395 base = brcmstb_ioremap_match(aon_ctrl_dt_ids, 0, NULL);
396 if (IS_ERR(base)) {
397 pr_err("error mapping AON_CTRL\n");
398 goto aon_err;
399 }
400 ctrl.aon_ctrl_base = base;
401
402 /* AON SRAM registers */
403 base = brcmstb_ioremap_match(aon_ctrl_dt_ids, 1, NULL);
404 if (IS_ERR(base)) {
405 pr_err("error mapping AON_SRAM\n");
406 goto sram_err;
407 }
408 ctrl.aon_sram_base = base;
409
410 ctrl.num_memc = 0;
411 /* Map MEMC DDR PHY registers */
412 for_each_matching_node(dn, ddr_phy_dt_ids) {
413 i = ctrl.num_memc;
414 if (i >= MAX_NUM_MEMC) {
415 pr_warn("Too many MEMCs (max %d)\n", MAX_NUM_MEMC);
416 break;
417 }
418 base = brcmstb_ioremap_node(dn, 0);
419 if (IS_ERR(base))
420 goto ddr_err;
421
422 ctrl.memcs[i].ddr_phy_base = base;
423 ctrl.num_memc++;
424 }
425
426 /* MEMC ARB registers */
427 base = brcmstb_ioremap_match(arb_dt_ids, 0, NULL);
428 if (IS_ERR(base)) {
429 pr_err("error mapping MEMC ARB\n");
430 goto ddr_err;
431 }
432 ctrl.memcs[0].arb_base = base;
433
434 /* Timer registers */
435 base = brcmstb_ioremap_match(timers_ids, 0, NULL);
436 if (IS_ERR(base)) {
437 pr_err("error mapping timers\n");
438 goto tmr_err;
439 }
440 ctrl.timers_base = base;
441
442 /* s3 cold boot aka s5 */
443 pm_power_off = brcmstb_pm_s5;
444
445 suspend_set_ops(&brcmstb_pm_ops);
446
447 return 0;
448
449tmr_err:
450 iounmap(ctrl.memcs[0].arb_base);
451ddr_err:
452 for (i = 0; i < ctrl.num_memc; i++)
453 iounmap(ctrl.memcs[i].ddr_phy_base);
454
455 iounmap(ctrl.aon_sram_base);
456sram_err:
457 iounmap(ctrl.aon_ctrl_base);
458aon_err:
459 return PTR_ERR(base);
460}
461arch_initcall(brcmstb_pm_init);
diff --git a/drivers/soc/bcm/brcmstb/pm/pm.h b/drivers/soc/bcm/brcmstb/pm/pm.h
index 142519fdb8f8..b7d35ac70e60 100644
--- a/drivers/soc/bcm/brcmstb/pm/pm.h
+++ b/drivers/soc/bcm/brcmstb/pm/pm.h
@@ -70,9 +70,20 @@
70 70
71#ifndef __ASSEMBLY__ 71#ifndef __ASSEMBLY__
72 72
73#ifndef CONFIG_MIPS
73extern const unsigned long brcmstb_pm_do_s2_sz; 74extern const unsigned long brcmstb_pm_do_s2_sz;
74extern asmlinkage int brcmstb_pm_do_s2(void __iomem *aon_ctrl_base, 75extern asmlinkage int brcmstb_pm_do_s2(void __iomem *aon_ctrl_base,
75 void __iomem *ddr_phy_pll_status); 76 void __iomem *ddr_phy_pll_status);
76#endif 77#else
78/* s2 asm */
79extern asmlinkage int brcm_pm_do_s2(u32 *s2_params);
80
81/* s3 asm */
82extern asmlinkage int brcm_pm_do_s3(void __iomem *aon_ctrl_base,
83 int dcache_linesz);
84extern int s3_reentry;
85#endif /* CONFIG_MIPS */
86
87#endif
77 88
78#endif /* __BRCMSTB_PM_H__ */ 89#endif /* __BRCMSTB_PM_H__ */
diff --git a/drivers/soc/bcm/brcmstb/pm/s2-mips.S b/drivers/soc/bcm/brcmstb/pm/s2-mips.S
new file mode 100644
index 000000000000..27a14bc46043
--- /dev/null
+++ b/drivers/soc/bcm/brcmstb/pm/s2-mips.S
@@ -0,0 +1,200 @@
1/*
2 * Copyright (C) 2016 Broadcom Corporation
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <asm/asm.h>
15#include <asm/regdef.h>
16#include <asm/mipsregs.h>
17#include <asm/stackframe.h>
18
19#include "pm.h"
20
21 .text
22 .set noreorder
23 .align 5
24
25/*
26 * a0: u32 params array
27 */
28LEAF(brcm_pm_do_s2)
29
30 subu sp, 64
31 sw ra, 0(sp)
32 sw s0, 4(sp)
33 sw s1, 8(sp)
34 sw s2, 12(sp)
35 sw s3, 16(sp)
36 sw s4, 20(sp)
37 sw s5, 24(sp)
38 sw s6, 28(sp)
39 sw s7, 32(sp)
40
41 /*
42 * Dereference the params array
43 * s0: AON_CTRL base register
44 * s1: DDR_PHY base register
45 * s2: TIMERS base register
46 * s3: I-Cache line size
47 * s4: Restart vector address
48 * s5: Restart vector size
49 */
50 move t0, a0
51
52 lw s0, 0(t0)
53 lw s1, 4(t0)
54 lw s2, 8(t0)
55 lw s3, 12(t0)
56 lw s4, 16(t0)
57 lw s5, 20(t0)
58
59 /* Lock this asm section into the I-cache */
60 addiu t1, s3, -1
61 not t1
62
63 la t0, brcm_pm_do_s2
64 and t0, t1
65
66 la t2, asm_end
67 and t2, t1
68
691: cache 0x1c, 0(t0)
70 bne t0, t2, 1b
71 addu t0, s3
72
73 /* Lock the interrupt vector into the I-cache */
74 move t0, zero
75
762: move t1, s4
77 cache 0x1c, 0(t1)
78 addu t1, s3
79 addu t0, s3
80 ble t0, s5, 2b
81 nop
82
83 sync
84
85 /* Power down request */
86 li t0, PM_S2_COMMAND
87 sw zero, AON_CTRL_PM_CTRL(s0)
88 lw zero, AON_CTRL_PM_CTRL(s0)
89 sw t0, AON_CTRL_PM_CTRL(s0)
90 lw t0, AON_CTRL_PM_CTRL(s0)
91
92 /* Enable CP0 interrupt 2 and wait for interrupt */
93 mfc0 t0, CP0_STATUS
94 /* Save cp0 sr for restoring later */
95 move s6, t0
96
97 li t1, ~(ST0_IM | ST0_IE)
98 and t0, t1
99 ori t0, STATUSF_IP2
100 mtc0 t0, CP0_STATUS
101 nop
102 nop
103 nop
104 ori t0, ST0_IE
105 mtc0 t0, CP0_STATUS
106
107 /* Wait for interrupt */
108 wait
109 nop
110
111 /* Wait for memc0 */
1121: lw t0, DDR40_PHY_CONTROL_REGS_0_PLL_STATUS(s1)
113 andi t0, 1
114 beqz t0, 1b
115 nop
116
117 /* 1ms delay needed for stable recovery */
118 /* Use TIMER1 to count 1 ms */
119 li t0, RESET_TIMER
120 sw t0, TIMER_TIMER1_CTRL(s2)
121 lw t0, TIMER_TIMER1_CTRL(s2)
122
123 li t0, START_TIMER
124 sw t0, TIMER_TIMER1_CTRL(s2)
125 lw t0, TIMER_TIMER1_CTRL(s2)
126
127 /* Prepare delay */
128 li t0, TIMER_MASK
129 lw t1, TIMER_TIMER1_STAT(s2)
130 and t1, t0
131 /* 1ms delay */
132 addi t1, 27000
133
134 /* Wait for the timer value to exceed t1 */
1351: lw t0, TIMER_TIMER1_STAT(s2)
136 sgtu t2, t1, t0
137 bnez t2, 1b
138 nop
139
140 /* Power back up */
141 li t1, 1
142 sw t1, AON_CTRL_HOST_MISC_CMDS(s0)
143 lw t1, AON_CTRL_HOST_MISC_CMDS(s0)
144
145 sw zero, AON_CTRL_PM_CTRL(s0)
146 lw zero, AON_CTRL_PM_CTRL(s0)
147
148 /* Unlock I-cache */
149 addiu t1, s3, -1
150 not t1
151
152 la t0, brcm_pm_do_s2
153 and t0, t1
154
155 la t2, asm_end
156 and t2, t1
157
1581: cache 0x00, 0(t0)
159 bne t0, t2, 1b
160 addu t0, s3
161
162 /* Unlock interrupt vector */
163 move t0, zero
164
1652: move t1, s4
166 cache 0x00, 0(t1)
167 addu t1, s3
168 addu t0, s3
169 ble t0, s5, 2b
170 nop
171
172 /* Restore cp0 sr */
173 sync
174 nop
175 mtc0 s6, CP0_STATUS
176 nop
177
178 /* Set return value to success */
179 li v0, 0
180
181 /* Return to caller */
182 lw s7, 32(sp)
183 lw s6, 28(sp)
184 lw s5, 24(sp)
185 lw s4, 20(sp)
186 lw s3, 16(sp)
187 lw s2, 12(sp)
188 lw s1, 8(sp)
189 lw s0, 4(sp)
190 lw ra, 0(sp)
191 addiu sp, 64
192
193 jr ra
194 nop
195END(brcm_pm_do_s2)
196
197 .globl asm_end
198asm_end:
199 nop
200
diff --git a/drivers/soc/bcm/brcmstb/pm/s3-mips.S b/drivers/soc/bcm/brcmstb/pm/s3-mips.S
new file mode 100644
index 000000000000..1242308a8868
--- /dev/null
+++ b/drivers/soc/bcm/brcmstb/pm/s3-mips.S
@@ -0,0 +1,146 @@
1/*
2 * Copyright (C) 2016 Broadcom Corporation
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <asm/asm.h>
15#include <asm/regdef.h>
16#include <asm/mipsregs.h>
17#include <asm/bmips.h>
18
19#include "pm.h"
20
21 .text
22 .set noreorder
23 .align 5
24 .global s3_reentry
25
26/*
27 * a0: AON_CTRL base register
28 * a1: D-Cache line size
29 */
30LEAF(brcm_pm_do_s3)
31
32 /* Get the address of s3_context */
33 la t0, gp_regs
34 sw ra, 0(t0)
35 sw s0, 4(t0)
36 sw s1, 8(t0)
37 sw s2, 12(t0)
38 sw s3, 16(t0)
39 sw s4, 20(t0)
40 sw s5, 24(t0)
41 sw s6, 28(t0)
42 sw s7, 32(t0)
43 sw gp, 36(t0)
44 sw sp, 40(t0)
45 sw fp, 44(t0)
46
47 /* Save CP0 Status */
48 mfc0 t1, CP0_STATUS
49 sw t1, 48(t0)
50
51 /* Write-back gp registers - cache will be gone */
52 addiu t1, a1, -1
53 not t1
54 and t0, t1
55
56 /* Flush at least 64 bytes */
57 addiu t2, t0, 64
58 and t2, t1
59
601: cache 0x17, 0(t0)
61 bne t0, t2, 1b
62 addu t0, a1
63
64 /* Drop to deep standby */
65 li t1, PM_WARM_CONFIG
66 sw zero, AON_CTRL_PM_CTRL(a0)
67 lw zero, AON_CTRL_PM_CTRL(a0)
68 sw t1, AON_CTRL_PM_CTRL(a0)
69 lw t1, AON_CTRL_PM_CTRL(a0)
70
71 li t1, (PM_WARM_CONFIG | PM_PWR_DOWN)
72 sw t1, AON_CTRL_PM_CTRL(a0)
73 lw t1, AON_CTRL_PM_CTRL(a0)
74
75 /* Enable CP0 interrupt 2 and wait for interrupt */
76 mfc0 t0, CP0_STATUS
77
78 li t1, ~(ST0_IM | ST0_IE)
79 and t0, t1
80 ori t0, STATUSF_IP2
81 mtc0 t0, CP0_STATUS
82 nop
83 nop
84 nop
85 ori t0, ST0_IE
86 mtc0 t0, CP0_STATUS
87
88 /* Wait for interrupt */
89 wait
90 nop
91
92s3_reentry:
93
94 /* Clear call/return stack */
95 li t0, (0x06 << 16)
96 mtc0 t0, $22, 2
97 ssnop
98 ssnop
99 ssnop
100
101 /* Clear jump target buffer */
102 li t0, (0x04 << 16)
103 mtc0 t0, $22, 2
104 ssnop
105 ssnop
106 ssnop
107
108 sync
109 nop
110
111 /* Setup mmu defaults */
112 mtc0 zero, CP0_WIRED
113 mtc0 zero, CP0_ENTRYHI
114 li k0, PM_DEFAULT_MASK
115 mtc0 k0, CP0_PAGEMASK
116
117 li sp, BMIPS_WARM_RESTART_VEC
118 la k0, plat_wired_tlb_setup
119 jalr k0
120 nop
121
122 /* Restore general purpose registers */
123 la t0, gp_regs
124 lw fp, 44(t0)
125 lw sp, 40(t0)
126 lw gp, 36(t0)
127 lw s7, 32(t0)
128 lw s6, 28(t0)
129 lw s5, 24(t0)
130 lw s4, 20(t0)
131 lw s3, 16(t0)
132 lw s2, 12(t0)
133 lw s1, 8(t0)
134 lw s0, 4(t0)
135 lw ra, 0(t0)
136
137 /* Restore CP0 status */
138 lw t1, 48(t0)
139 mtc0 t1, CP0_STATUS
140
141 /* Return to caller */
142 li v0, 0
143 jr ra
144 nop
145
146END(brcm_pm_do_s3)