blob: 452450d5fabb41f609a39075d27ebdc699499748 [file] [log] [blame]
Icenowy Zheng7c26b6e2018-07-21 20:41:12 +08001/*
2 * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
3 * Copyright (c) 2018, Icenowy Zheng <icenowy@aosc.io>
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
Icenowy Zheng5069c1c2018-07-22 21:52:50 +08008#include <arch_helpers.h>
Icenowy Zheng7c26b6e2018-07-21 20:41:12 +08009#include <debug.h>
Andre Przywaraf953c302018-10-02 00:21:49 +010010#include <delay_timer.h>
11#include <errno.h>
12#include <mmio.h>
13#include <platform_def.h>
14#include <sunxi_def.h>
15#include <sunxi_mmap.h>
16
17static enum pmic_type {
18 GENERIC_H5,
19 GENERIC_A64,
20} pmic;
21
22/*
23 * On boards without a proper PMIC we struggle to turn off the system properly.
24 * Try to turn off as much off the system as we can, to reduce power
25 * consumption. This should be entered with only one core running and SMP
26 * disabled.
27 * This function only cares about peripherals.
28 */
29void sunxi_turn_off_soc(uint16_t socid)
30{
31 int i;
32
33 /** Turn off most peripherals, most importantly DRAM users. **/
34 /* Keep DRAM controller running for now. */
35 mmio_clrbits_32(SUNXI_CCU_BASE + 0x2c0, ~BIT_32(14));
36 mmio_clrbits_32(SUNXI_CCU_BASE + 0x60, ~BIT_32(14));
37 /* Contains msgbox (bit 21) and spinlock (bit 22) */
38 mmio_write_32(SUNXI_CCU_BASE + 0x2c4, 0);
39 mmio_write_32(SUNXI_CCU_BASE + 0x64, 0);
40 mmio_write_32(SUNXI_CCU_BASE + 0x2c8, 0);
41 /* Keep PIO controller running for now. */
42 mmio_clrbits_32(SUNXI_CCU_BASE + 0x68, ~(BIT_32(5)));
43 mmio_write_32(SUNXI_CCU_BASE + 0x2d0, 0);
44 /* Contains UART0 (bit 16) */
45 mmio_write_32(SUNXI_CCU_BASE + 0x2d8, 0);
46 mmio_write_32(SUNXI_CCU_BASE + 0x6c, 0);
47 mmio_write_32(SUNXI_CCU_BASE + 0x70, 0);
48
49 /** Turn off DRAM controller. **/
50 mmio_clrbits_32(SUNXI_CCU_BASE + 0x2c0, BIT_32(14));
51 mmio_clrbits_32(SUNXI_CCU_BASE + 0x60, BIT_32(14));
52
53 /** Migrate CPU and bus clocks away from the PLLs. **/
54 /* AHB1: use OSC24M/1, APB1 = AHB1 / 2 */
55 mmio_write_32(SUNXI_CCU_BASE + 0x54, 0x1000);
56 /* APB2: use OSC24M */
57 mmio_write_32(SUNXI_CCU_BASE + 0x58, 0x1000000);
58 /* AHB2: use AHB1 clock */
59 mmio_write_32(SUNXI_CCU_BASE + 0x5c, 0);
60 /* CPU: use OSC24M */
61 mmio_write_32(SUNXI_CCU_BASE + 0x50, 0x10000);
62
63 /** Turn off PLLs. **/
64 for (i = 0; i < 6; i++)
65 mmio_clrbits_32(SUNXI_CCU_BASE + i * 8, BIT(31));
66 switch (socid) {
67 case SUNXI_SOC_H5:
68 mmio_clrbits_32(SUNXI_CCU_BASE + 0x44, BIT(31));
69 break;
70 case SUNXI_SOC_A64:
71 mmio_clrbits_32(SUNXI_CCU_BASE + 0x2c, BIT(31));
72 mmio_clrbits_32(SUNXI_CCU_BASE + 0x4c, BIT(31));
73 break;
74 }
75}
Icenowy Zheng7c26b6e2018-07-21 20:41:12 +080076
Andre Przywarafe57c7d2018-09-08 19:18:37 +010077int sunxi_pmic_setup(uint16_t socid)
Icenowy Zheng7c26b6e2018-07-21 20:41:12 +080078{
Andre Przywaraf953c302018-10-02 00:21:49 +010079 switch (socid) {
80 case SUNXI_SOC_H5:
81 pmic = GENERIC_H5;
82 break;
83 case SUNXI_SOC_A64:
84 pmic = GENERIC_A64;
85 break;
86 default:
87 NOTICE("BL31: PMIC: No support for Allwinner %x SoC.\n", socid);
88 return -ENODEV;
89 }
Icenowy Zheng7c26b6e2018-07-21 20:41:12 +080090 return 0;
91}
Icenowy Zheng5069c1c2018-07-22 21:52:50 +080092
93void __dead2 sunxi_power_down(void)
94{
Andre Przywaraf953c302018-10-02 00:21:49 +010095 switch (pmic) {
96 case GENERIC_H5:
97 /* Turn off as many peripherals and clocks as we can. */
98 sunxi_turn_off_soc(SUNXI_SOC_H5);
99 /* Turn off the pin controller now. */
100 mmio_write_32(SUNXI_CCU_BASE + 0x68, 0);
101 break;
102 case GENERIC_A64:
103 /* Turn off as many peripherals and clocks as we can. */
104 sunxi_turn_off_soc(SUNXI_SOC_A64);
105 /* Turn off the pin controller now. */
106 mmio_write_32(SUNXI_CCU_BASE + 0x68, 0);
107 break;
108 default:
109 break;
110 }
111
112 udelay(1000);
113 ERROR("PSCI: Cannot turn off system, halting.\n");
Icenowy Zheng5069c1c2018-07-22 21:52:50 +0800114 wfi();
115 panic();
116}