summaryrefslogtreecommitdiff
path: root/plat/allwinner
diff options
context:
space:
mode:
authorAndre Przywara <andre.przywara@arm.com>2018-10-02 00:21:49 +0100
committerAndre Przywara <andre.przywara@arm.com>2018-10-20 16:23:59 +0100
commitf953c30fe58dcd7f924c5df63d631c5c4ca0517d (patch)
tree61f07920d08b23b6f1196ea408a37d4e189cccf0 /plat/allwinner
parentfe57c7d477d1fd4fb4a4b5b1dfb2c3873f58a664 (diff)
allwinner: A64/H5: Add basic and generic shutdown method
Some boards don't have a PMIC, so they can't easily turn their power off. To cover those boards anyway, let's turn off as many devices and clocks as possible, so that the power consumption is reduced. Then halt the last core, as before. This will later be extended with proper PMIC support for supported boards. Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Diffstat (limited to 'plat/allwinner')
-rw-r--r--plat/allwinner/sun50i_a64/sunxi_power.c100
1 files changed, 96 insertions, 4 deletions
diff --git a/plat/allwinner/sun50i_a64/sunxi_power.c b/plat/allwinner/sun50i_a64/sunxi_power.c
index a2110e95..452450d5 100644
--- a/plat/allwinner/sun50i_a64/sunxi_power.c
+++ b/plat/allwinner/sun50i_a64/sunxi_power.c
@@ -7,18 +7,110 @@
#include <arch_helpers.h>
#include <debug.h>
+#include <delay_timer.h>
+#include <errno.h>
+#include <mmio.h>
+#include <platform_def.h>
+#include <sunxi_def.h>
+#include <sunxi_mmap.h>
-int sunxi_pmic_setup(uint16_t socid)
+static enum pmic_type {
+ GENERIC_H5,
+ GENERIC_A64,
+} pmic;
+
+/*
+ * On boards without a proper PMIC we struggle to turn off the system properly.
+ * Try to turn off as much off the system as we can, to reduce power
+ * consumption. This should be entered with only one core running and SMP
+ * disabled.
+ * This function only cares about peripherals.
+ */
+void sunxi_turn_off_soc(uint16_t socid)
{
- /* STUB */
- NOTICE("BL31: STUB PMIC setup code called\n");
+ int i;
+
+ /** Turn off most peripherals, most importantly DRAM users. **/
+ /* Keep DRAM controller running for now. */
+ mmio_clrbits_32(SUNXI_CCU_BASE + 0x2c0, ~BIT_32(14));
+ mmio_clrbits_32(SUNXI_CCU_BASE + 0x60, ~BIT_32(14));
+ /* Contains msgbox (bit 21) and spinlock (bit 22) */
+ mmio_write_32(SUNXI_CCU_BASE + 0x2c4, 0);
+ mmio_write_32(SUNXI_CCU_BASE + 0x64, 0);
+ mmio_write_32(SUNXI_CCU_BASE + 0x2c8, 0);
+ /* Keep PIO controller running for now. */
+ mmio_clrbits_32(SUNXI_CCU_BASE + 0x68, ~(BIT_32(5)));
+ mmio_write_32(SUNXI_CCU_BASE + 0x2d0, 0);
+ /* Contains UART0 (bit 16) */
+ mmio_write_32(SUNXI_CCU_BASE + 0x2d8, 0);
+ mmio_write_32(SUNXI_CCU_BASE + 0x6c, 0);
+ mmio_write_32(SUNXI_CCU_BASE + 0x70, 0);
+
+ /** Turn off DRAM controller. **/
+ mmio_clrbits_32(SUNXI_CCU_BASE + 0x2c0, BIT_32(14));
+ mmio_clrbits_32(SUNXI_CCU_BASE + 0x60, BIT_32(14));
+ /** Migrate CPU and bus clocks away from the PLLs. **/
+ /* AHB1: use OSC24M/1, APB1 = AHB1 / 2 */
+ mmio_write_32(SUNXI_CCU_BASE + 0x54, 0x1000);
+ /* APB2: use OSC24M */
+ mmio_write_32(SUNXI_CCU_BASE + 0x58, 0x1000000);
+ /* AHB2: use AHB1 clock */
+ mmio_write_32(SUNXI_CCU_BASE + 0x5c, 0);
+ /* CPU: use OSC24M */
+ mmio_write_32(SUNXI_CCU_BASE + 0x50, 0x10000);
+
+ /** Turn off PLLs. **/
+ for (i = 0; i < 6; i++)
+ mmio_clrbits_32(SUNXI_CCU_BASE + i * 8, BIT(31));
+ switch (socid) {
+ case SUNXI_SOC_H5:
+ mmio_clrbits_32(SUNXI_CCU_BASE + 0x44, BIT(31));
+ break;
+ case SUNXI_SOC_A64:
+ mmio_clrbits_32(SUNXI_CCU_BASE + 0x2c, BIT(31));
+ mmio_clrbits_32(SUNXI_CCU_BASE + 0x4c, BIT(31));
+ break;
+ }
+}
+
+int sunxi_pmic_setup(uint16_t socid)
+{
+ switch (socid) {
+ case SUNXI_SOC_H5:
+ pmic = GENERIC_H5;
+ break;
+ case SUNXI_SOC_A64:
+ pmic = GENERIC_A64;
+ break;
+ default:
+ NOTICE("BL31: PMIC: No support for Allwinner %x SoC.\n", socid);
+ return -ENODEV;
+ }
return 0;
}
void __dead2 sunxi_power_down(void)
{
- ERROR("PSCI: Full shutdown not implemented, halting\n");
+ switch (pmic) {
+ case GENERIC_H5:
+ /* Turn off as many peripherals and clocks as we can. */
+ sunxi_turn_off_soc(SUNXI_SOC_H5);
+ /* Turn off the pin controller now. */
+ mmio_write_32(SUNXI_CCU_BASE + 0x68, 0);
+ break;
+ case GENERIC_A64:
+ /* Turn off as many peripherals and clocks as we can. */
+ sunxi_turn_off_soc(SUNXI_SOC_A64);
+ /* Turn off the pin controller now. */
+ mmio_write_32(SUNXI_CCU_BASE + 0x68, 0);
+ break;
+ default:
+ break;
+ }
+
+ udelay(1000);
+ ERROR("PSCI: Cannot turn off system, halting.\n");
wfi();
panic();
}