14a079c75SCarlo Caione /* 24a079c75SCarlo Caione * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. 34a079c75SCarlo Caione * 44a079c75SCarlo Caione * SPDX-License-Identifier: BSD-3-Clause 54a079c75SCarlo Caione */ 64a079c75SCarlo Caione 74a079c75SCarlo Caione #include <arch_helpers.h> 84a079c75SCarlo Caione #include <assert.h> 94a079c75SCarlo Caione #include <common/debug.h> 104a079c75SCarlo Caione #include <drivers/arm/gicv2.h> 11*b5621874SCarlo Caione #include <drivers/console.h> 12*b5621874SCarlo Caione #include <errno.h> 134a079c75SCarlo Caione #include <lib/mmio.h> 14*b5621874SCarlo Caione #include <lib/psci/psci.h> 154a079c75SCarlo Caione #include <plat/common/platform.h> 164a079c75SCarlo Caione #include <platform_def.h> 174a079c75SCarlo Caione 18e26864afSCarlo Caione #include "aml_private.h" 194a079c75SCarlo Caione 204a079c75SCarlo Caione #define SCPI_POWER_ON 0 214a079c75SCarlo Caione #define SCPI_POWER_RETENTION 1 224a079c75SCarlo Caione #define SCPI_POWER_OFF 3 234a079c75SCarlo Caione 244a079c75SCarlo Caione #define SCPI_SYSTEM_SHUTDOWN 0 254a079c75SCarlo Caione #define SCPI_SYSTEM_REBOOT 1 264a079c75SCarlo Caione 270e1d7896SCarlo Caione static uintptr_t gxl_sec_entrypoint; 280e1d7896SCarlo Caione static volatile uint32_t gxl_cpu0_go; 294a079c75SCarlo Caione 304a079c75SCarlo Caione static void gxl_pm_set_reset_addr(u_register_t mpidr, uint64_t value) 314a079c75SCarlo Caione { 32f681c676SCarlo Caione unsigned int core = plat_calc_core_pos(mpidr); 330e1d7896SCarlo Caione uintptr_t cpu_mailbox_addr = AML_PSCI_MAILBOX_BASE + (core << 4); 344a079c75SCarlo Caione 354a079c75SCarlo Caione mmio_write_64(cpu_mailbox_addr, value); 364a079c75SCarlo Caione } 374a079c75SCarlo Caione 384a079c75SCarlo Caione static void gxl_pm_reset(u_register_t mpidr) 394a079c75SCarlo Caione { 40f681c676SCarlo Caione unsigned int core = plat_calc_core_pos(mpidr); 410e1d7896SCarlo Caione uintptr_t cpu_mailbox_addr = AML_PSCI_MAILBOX_BASE + (core << 4) + 8; 424a079c75SCarlo Caione 434a079c75SCarlo Caione mmio_write_32(cpu_mailbox_addr, 0); 444a079c75SCarlo Caione } 454a079c75SCarlo Caione 460e1d7896SCarlo Caione static void __dead2 gxl_system_reset(void) 474a079c75SCarlo Caione { 484a079c75SCarlo Caione INFO("BL31: PSCI_SYSTEM_RESET\n"); 494a079c75SCarlo Caione 504a079c75SCarlo Caione u_register_t mpidr = read_mpidr_el1(); 510e1d7896SCarlo Caione uint32_t status = mmio_read_32(AML_AO_RTI_STATUS_REG3); 524a079c75SCarlo Caione int ret; 534a079c75SCarlo Caione 544a079c75SCarlo Caione NOTICE("BL31: Reboot reason: 0x%x\n", status); 554a079c75SCarlo Caione 564a079c75SCarlo Caione status &= 0xFFFF0FF0; 574a079c75SCarlo Caione 584a079c75SCarlo Caione console_flush(); 594a079c75SCarlo Caione 600e1d7896SCarlo Caione mmio_write_32(AML_AO_RTI_STATUS_REG3, status); 614a079c75SCarlo Caione 629a5616faSCarlo Caione ret = aml_scpi_sys_power_state(SCPI_SYSTEM_REBOOT); 634a079c75SCarlo Caione 644a079c75SCarlo Caione if (ret != 0) { 654a079c75SCarlo Caione ERROR("BL31: PSCI_SYSTEM_RESET: SCP error: %i\n", ret); 664a079c75SCarlo Caione panic(); 674a079c75SCarlo Caione } 684a079c75SCarlo Caione 694a079c75SCarlo Caione gxl_pm_reset(mpidr); 704a079c75SCarlo Caione 714a079c75SCarlo Caione wfi(); 724a079c75SCarlo Caione 734a079c75SCarlo Caione ERROR("BL31: PSCI_SYSTEM_RESET: Operation not handled\n"); 744a079c75SCarlo Caione panic(); 754a079c75SCarlo Caione } 764a079c75SCarlo Caione 770e1d7896SCarlo Caione static void __dead2 gxl_system_off(void) 784a079c75SCarlo Caione { 794a079c75SCarlo Caione INFO("BL31: PSCI_SYSTEM_OFF\n"); 804a079c75SCarlo Caione 814a079c75SCarlo Caione u_register_t mpidr = read_mpidr_el1(); 824a079c75SCarlo Caione int ret; 834a079c75SCarlo Caione 849a5616faSCarlo Caione ret = aml_scpi_sys_power_state(SCPI_SYSTEM_SHUTDOWN); 854a079c75SCarlo Caione 864a079c75SCarlo Caione if (ret != 0) { 874a079c75SCarlo Caione ERROR("BL31: PSCI_SYSTEM_OFF: SCP error %i\n", ret); 884a079c75SCarlo Caione panic(); 894a079c75SCarlo Caione } 904a079c75SCarlo Caione 914a079c75SCarlo Caione gxl_pm_set_reset_addr(mpidr, 0); 924a079c75SCarlo Caione gxl_pm_reset(mpidr); 934a079c75SCarlo Caione 944a079c75SCarlo Caione wfi(); 954a079c75SCarlo Caione 964a079c75SCarlo Caione ERROR("BL31: PSCI_SYSTEM_OFF: Operation not handled\n"); 974a079c75SCarlo Caione panic(); 984a079c75SCarlo Caione } 994a079c75SCarlo Caione 1000e1d7896SCarlo Caione static int32_t gxl_pwr_domain_on(u_register_t mpidr) 1014a079c75SCarlo Caione { 102f681c676SCarlo Caione unsigned int core = plat_calc_core_pos(mpidr); 1034a079c75SCarlo Caione 1044a079c75SCarlo Caione /* CPU0 can't be turned OFF, emulate it with a WFE loop */ 105f681c676SCarlo Caione if (core == AML_PRIMARY_CPU) { 1064a079c75SCarlo Caione VERBOSE("BL31: Releasing CPU0 from wait loop...\n"); 1074a079c75SCarlo Caione 1080e1d7896SCarlo Caione gxl_cpu0_go = 1; 1090e1d7896SCarlo Caione flush_dcache_range((uintptr_t)&gxl_cpu0_go, 1100e1d7896SCarlo Caione sizeof(gxl_cpu0_go)); 1114a079c75SCarlo Caione dsb(); 1124a079c75SCarlo Caione isb(); 1134a079c75SCarlo Caione 1144a079c75SCarlo Caione sev(); 1154a079c75SCarlo Caione 1164a079c75SCarlo Caione return PSCI_E_SUCCESS; 1174a079c75SCarlo Caione } 1184a079c75SCarlo Caione 1190e1d7896SCarlo Caione gxl_pm_set_reset_addr(mpidr, gxl_sec_entrypoint); 1209a5616faSCarlo Caione aml_scpi_set_css_power_state(mpidr, 1214a079c75SCarlo Caione SCPI_POWER_ON, SCPI_POWER_ON, SCPI_POWER_ON); 1224a079c75SCarlo Caione dmbsy(); 1234a079c75SCarlo Caione sev(); 1244a079c75SCarlo Caione 1254a079c75SCarlo Caione return PSCI_E_SUCCESS; 1264a079c75SCarlo Caione } 1274a079c75SCarlo Caione 1280e1d7896SCarlo Caione static void gxl_pwr_domain_on_finish(const psci_power_state_t *target_state) 1294a079c75SCarlo Caione { 130f681c676SCarlo Caione unsigned int core = plat_calc_core_pos(read_mpidr_el1()); 1314a079c75SCarlo Caione 1324a079c75SCarlo Caione assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] == 1334a079c75SCarlo Caione PLAT_LOCAL_STATE_OFF); 1344a079c75SCarlo Caione 135f681c676SCarlo Caione if (core == AML_PRIMARY_CPU) { 1360e1d7896SCarlo Caione gxl_cpu0_go = 0; 1370e1d7896SCarlo Caione flush_dcache_range((uintptr_t)&gxl_cpu0_go, 1380e1d7896SCarlo Caione sizeof(gxl_cpu0_go)); 1394a079c75SCarlo Caione dsb(); 1404a079c75SCarlo Caione isb(); 1414a079c75SCarlo Caione } 1424a079c75SCarlo Caione 1434a079c75SCarlo Caione gicv2_pcpu_distif_init(); 1444a079c75SCarlo Caione gicv2_cpuif_enable(); 1454a079c75SCarlo Caione } 1464a079c75SCarlo Caione 1470e1d7896SCarlo Caione static void gxl_pwr_domain_off(const psci_power_state_t *target_state) 1484a079c75SCarlo Caione { 1494a079c75SCarlo Caione u_register_t mpidr = read_mpidr_el1(); 150f681c676SCarlo Caione unsigned int core = plat_calc_core_pos(mpidr); 1514a079c75SCarlo Caione 1524a079c75SCarlo Caione gicv2_cpuif_disable(); 1534a079c75SCarlo Caione 1544a079c75SCarlo Caione /* CPU0 can't be turned OFF, emulate it with a WFE loop */ 155f681c676SCarlo Caione if (core == AML_PRIMARY_CPU) 1564a079c75SCarlo Caione return; 1574a079c75SCarlo Caione 1589a5616faSCarlo Caione aml_scpi_set_css_power_state(mpidr, 1594a079c75SCarlo Caione SCPI_POWER_OFF, SCPI_POWER_ON, SCPI_POWER_ON); 1604a079c75SCarlo Caione } 1614a079c75SCarlo Caione 1620e1d7896SCarlo Caione static void __dead2 gxl_pwr_domain_pwr_down_wfi(const psci_power_state_t 1634a079c75SCarlo Caione *target_state) 1644a079c75SCarlo Caione { 1654a079c75SCarlo Caione u_register_t mpidr = read_mpidr_el1(); 166f681c676SCarlo Caione unsigned int core = plat_calc_core_pos(mpidr); 1674a079c75SCarlo Caione 1684a079c75SCarlo Caione /* CPU0 can't be turned OFF, emulate it with a WFE loop */ 169f681c676SCarlo Caione if (core == AML_PRIMARY_CPU) { 1704a079c75SCarlo Caione VERBOSE("BL31: CPU0 entering wait loop...\n"); 1714a079c75SCarlo Caione 1720e1d7896SCarlo Caione while (gxl_cpu0_go == 0) 1734a079c75SCarlo Caione wfe(); 1744a079c75SCarlo Caione 1754a079c75SCarlo Caione VERBOSE("BL31: CPU0 resumed.\n"); 1764a079c75SCarlo Caione 1774a079c75SCarlo Caione /* 1784a079c75SCarlo Caione * Because setting CPU0's warm reset entrypoint through PSCI 1794a079c75SCarlo Caione * mailbox and/or mmio mapped RVBAR (0xda834650) does not seem 1804a079c75SCarlo Caione * to work, jump to it manually. 1814a079c75SCarlo Caione * In order to avoid an assert, mmu has to be disabled. 1824a079c75SCarlo Caione */ 1834a079c75SCarlo Caione disable_mmu_el3(); 1840e1d7896SCarlo Caione ((void(*)(void))gxl_sec_entrypoint)(); 1854a079c75SCarlo Caione } 1864a079c75SCarlo Caione 1874a079c75SCarlo Caione dsbsy(); 1884a079c75SCarlo Caione gxl_pm_set_reset_addr(mpidr, 0); 1894a079c75SCarlo Caione gxl_pm_reset(mpidr); 1904a079c75SCarlo Caione 1914a079c75SCarlo Caione for (;;) 1924a079c75SCarlo Caione wfi(); 1934a079c75SCarlo Caione } 1944a079c75SCarlo Caione 1954a079c75SCarlo Caione /******************************************************************************* 1964a079c75SCarlo Caione * Platform handlers and setup function. 1974a079c75SCarlo Caione ******************************************************************************/ 1980e1d7896SCarlo Caione static const plat_psci_ops_t gxl_ops = { 1990e1d7896SCarlo Caione .pwr_domain_on = gxl_pwr_domain_on, 2000e1d7896SCarlo Caione .pwr_domain_on_finish = gxl_pwr_domain_on_finish, 2010e1d7896SCarlo Caione .pwr_domain_off = gxl_pwr_domain_off, 2020e1d7896SCarlo Caione .pwr_domain_pwr_down_wfi = gxl_pwr_domain_pwr_down_wfi, 2030e1d7896SCarlo Caione .system_off = gxl_system_off, 2040e1d7896SCarlo Caione .system_reset = gxl_system_reset, 2054a079c75SCarlo Caione }; 2064a079c75SCarlo Caione 2074a079c75SCarlo Caione int plat_setup_psci_ops(uintptr_t sec_entrypoint, 2084a079c75SCarlo Caione const plat_psci_ops_t **psci_ops) 2094a079c75SCarlo Caione { 2100e1d7896SCarlo Caione gxl_sec_entrypoint = sec_entrypoint; 2110e1d7896SCarlo Caione *psci_ops = &gxl_ops; 2120e1d7896SCarlo Caione gxl_cpu0_go = 0; 2134a079c75SCarlo Caione return 0; 2144a079c75SCarlo Caione } 215