14a079c75SCarlo Caione /* 2e26864afSCarlo 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> 8b5621874SCarlo Caione #include <assert.h> 94a079c75SCarlo Caione #include <common/debug.h> 104a079c75SCarlo Caione #include <drivers/arm/gicv2.h> 114a079c75SCarlo Caione #include <drivers/console.h> 12b5621874SCarlo Caione #include <errno.h> 134a079c75SCarlo Caione #include <lib/mmio.h> 144a079c75SCarlo Caione #include <lib/psci/psci.h> 154a079c75SCarlo Caione #include <plat/common/platform.h> 16b5621874SCarlo 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 274a079c75SCarlo Caione static uintptr_t gxbb_sec_entrypoint; 284a079c75SCarlo Caione static volatile uint32_t gxbb_cpu0_go; 294a079c75SCarlo Caione 304a079c75SCarlo Caione static void gxbb_program_mailbox(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 flush_dcache_range(cpu_mailbox_addr, sizeof(uint64_t)); 374a079c75SCarlo Caione } 384a079c75SCarlo Caione 394a079c75SCarlo Caione static void __dead2 gxbb_system_reset(void) 404a079c75SCarlo Caione { 414a079c75SCarlo Caione INFO("BL31: PSCI_SYSTEM_RESET\n"); 424a079c75SCarlo Caione 430e1d7896SCarlo Caione uint32_t status = mmio_read_32(AML_AO_RTI_STATUS_REG3); 444a079c75SCarlo Caione 454a079c75SCarlo Caione NOTICE("BL31: Reboot reason: 0x%x\n", status); 464a079c75SCarlo Caione 474a079c75SCarlo Caione status &= 0xFFFF0FF0; 484a079c75SCarlo Caione 494a079c75SCarlo Caione console_flush(); 504a079c75SCarlo Caione 510e1d7896SCarlo Caione mmio_write_32(AML_AO_RTI_STATUS_REG3, status); 524a079c75SCarlo Caione 539a5616faSCarlo Caione int ret = aml_scpi_sys_power_state(SCPI_SYSTEM_REBOOT); 544a079c75SCarlo Caione 554a079c75SCarlo Caione if (ret != 0) { 564a079c75SCarlo Caione ERROR("BL31: PSCI_SYSTEM_RESET: SCP error: %u\n", ret); 574a079c75SCarlo Caione panic(); 584a079c75SCarlo Caione } 594a079c75SCarlo Caione 604a079c75SCarlo Caione wfi(); 614a079c75SCarlo Caione 624a079c75SCarlo Caione ERROR("BL31: PSCI_SYSTEM_RESET: Operation not handled\n"); 634a079c75SCarlo Caione panic(); 644a079c75SCarlo Caione } 654a079c75SCarlo Caione 664a079c75SCarlo Caione static void __dead2 gxbb_system_off(void) 674a079c75SCarlo Caione { 684a079c75SCarlo Caione INFO("BL31: PSCI_SYSTEM_OFF\n"); 694a079c75SCarlo Caione 709a5616faSCarlo Caione unsigned int ret = aml_scpi_sys_power_state(SCPI_SYSTEM_SHUTDOWN); 714a079c75SCarlo Caione 724a079c75SCarlo Caione if (ret != 0) { 734a079c75SCarlo Caione ERROR("BL31: PSCI_SYSTEM_OFF: SCP error %u\n", ret); 744a079c75SCarlo Caione panic(); 754a079c75SCarlo Caione } 764a079c75SCarlo Caione 774a079c75SCarlo Caione gxbb_program_mailbox(read_mpidr_el1(), 0); 784a079c75SCarlo Caione 794a079c75SCarlo Caione wfi(); 804a079c75SCarlo Caione 814a079c75SCarlo Caione ERROR("BL31: PSCI_SYSTEM_OFF: Operation not handled\n"); 824a079c75SCarlo Caione panic(); 834a079c75SCarlo Caione } 844a079c75SCarlo Caione 854a079c75SCarlo Caione static int32_t gxbb_pwr_domain_on(u_register_t mpidr) 864a079c75SCarlo Caione { 87f681c676SCarlo Caione unsigned int core = plat_calc_core_pos(mpidr); 884a079c75SCarlo Caione 894a079c75SCarlo Caione /* CPU0 can't be turned OFF, emulate it with a WFE loop */ 90f681c676SCarlo Caione if (core == AML_PRIMARY_CPU) { 914a079c75SCarlo Caione VERBOSE("BL31: Releasing CPU0 from wait loop...\n"); 924a079c75SCarlo Caione 934a079c75SCarlo Caione gxbb_cpu0_go = 1; 944a079c75SCarlo Caione flush_dcache_range((uintptr_t)&gxbb_cpu0_go, sizeof(gxbb_cpu0_go)); 954a079c75SCarlo Caione dsb(); 964a079c75SCarlo Caione isb(); 974a079c75SCarlo Caione 984a079c75SCarlo Caione sev(); 994a079c75SCarlo Caione 1004a079c75SCarlo Caione return PSCI_E_SUCCESS; 1014a079c75SCarlo Caione } 1024a079c75SCarlo Caione 1034a079c75SCarlo Caione gxbb_program_mailbox(mpidr, gxbb_sec_entrypoint); 1049a5616faSCarlo Caione aml_scpi_set_css_power_state(mpidr, 1054a079c75SCarlo Caione SCPI_POWER_ON, SCPI_POWER_ON, SCPI_POWER_ON); 1064a079c75SCarlo Caione dmbsy(); 1074a079c75SCarlo Caione sev(); 1084a079c75SCarlo Caione 1094a079c75SCarlo Caione return PSCI_E_SUCCESS; 1104a079c75SCarlo Caione } 1114a079c75SCarlo Caione 1124a079c75SCarlo Caione static void gxbb_pwr_domain_on_finish(const psci_power_state_t *target_state) 1134a079c75SCarlo Caione { 114f681c676SCarlo Caione unsigned int core = plat_calc_core_pos(read_mpidr_el1()); 1154a079c75SCarlo Caione 1164a079c75SCarlo Caione assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] == 1174a079c75SCarlo Caione PLAT_LOCAL_STATE_OFF); 1184a079c75SCarlo Caione 119f681c676SCarlo Caione if (core == AML_PRIMARY_CPU) { 1204a079c75SCarlo Caione gxbb_cpu0_go = 0; 1214a079c75SCarlo Caione flush_dcache_range((uintptr_t)&gxbb_cpu0_go, sizeof(gxbb_cpu0_go)); 1224a079c75SCarlo Caione dsb(); 1234a079c75SCarlo Caione isb(); 1244a079c75SCarlo Caione } 1254a079c75SCarlo Caione 1264a079c75SCarlo Caione gicv2_pcpu_distif_init(); 1274a079c75SCarlo Caione gicv2_cpuif_enable(); 1284a079c75SCarlo Caione } 1294a079c75SCarlo Caione 1304a079c75SCarlo Caione static void gxbb_pwr_domain_off(const psci_power_state_t *target_state) 1314a079c75SCarlo Caione { 1324a079c75SCarlo Caione u_register_t mpidr = read_mpidr_el1(); 133f681c676SCarlo Caione unsigned int core = plat_calc_core_pos(mpidr); 1340e1d7896SCarlo Caione uintptr_t addr = AML_PSCI_MAILBOX_BASE + 8 + (core << 4); 1354a079c75SCarlo Caione 1364a079c75SCarlo Caione mmio_write_32(addr, 0xFFFFFFFF); 1374a079c75SCarlo Caione flush_dcache_range(addr, sizeof(uint32_t)); 1384a079c75SCarlo Caione 1394a079c75SCarlo Caione gicv2_cpuif_disable(); 1404a079c75SCarlo Caione 1414a079c75SCarlo Caione /* CPU0 can't be turned OFF, emulate it with a WFE loop */ 142f681c676SCarlo Caione if (core == AML_PRIMARY_CPU) 1434a079c75SCarlo Caione return; 1444a079c75SCarlo Caione 1459a5616faSCarlo Caione aml_scpi_set_css_power_state(mpidr, 1464a079c75SCarlo Caione SCPI_POWER_OFF, SCPI_POWER_ON, SCPI_POWER_ON); 1474a079c75SCarlo Caione } 1484a079c75SCarlo Caione 1494a079c75SCarlo Caione static void __dead2 gxbb_pwr_domain_pwr_down_wfi(const psci_power_state_t 1504a079c75SCarlo Caione *target_state) 1514a079c75SCarlo Caione { 152f681c676SCarlo Caione unsigned int core = plat_calc_core_pos(read_mpidr_el1()); 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 VERBOSE("BL31: CPU0 entering wait loop...\n"); 1574a079c75SCarlo Caione 1584a079c75SCarlo Caione while (gxbb_cpu0_go == 0) 1594a079c75SCarlo Caione wfe(); 1604a079c75SCarlo Caione 1614a079c75SCarlo Caione VERBOSE("BL31: CPU0 resumed.\n"); 1624a079c75SCarlo Caione 1634a079c75SCarlo Caione write_rmr_el3(RMR_EL3_RR_BIT | RMR_EL3_AA64_BIT); 1644a079c75SCarlo Caione } 1654a079c75SCarlo Caione 1664a079c75SCarlo Caione dsbsy(); 1674a079c75SCarlo Caione 1684a079c75SCarlo Caione for (;;) 1694a079c75SCarlo Caione wfi(); 1704a079c75SCarlo Caione } 1714a079c75SCarlo Caione 1724a079c75SCarlo Caione /******************************************************************************* 1734a079c75SCarlo Caione * Platform handlers and setup function. 1744a079c75SCarlo Caione ******************************************************************************/ 1754a079c75SCarlo Caione static const plat_psci_ops_t gxbb_ops = { 1764a079c75SCarlo Caione .pwr_domain_on = gxbb_pwr_domain_on, 1774a079c75SCarlo Caione .pwr_domain_on_finish = gxbb_pwr_domain_on_finish, 1784a079c75SCarlo Caione .pwr_domain_off = gxbb_pwr_domain_off, 179*db5fe4f4SBoyan Karatotev .pwr_domain_pwr_down = gxbb_pwr_domain_pwr_down_wfi, 1804a079c75SCarlo Caione .system_off = gxbb_system_off, 1814a079c75SCarlo Caione .system_reset = gxbb_system_reset, 1824a079c75SCarlo Caione }; 1834a079c75SCarlo Caione 1844a079c75SCarlo Caione int plat_setup_psci_ops(uintptr_t sec_entrypoint, 1854a079c75SCarlo Caione const plat_psci_ops_t **psci_ops) 1864a079c75SCarlo Caione { 1874a079c75SCarlo Caione gxbb_sec_entrypoint = sec_entrypoint; 1884a079c75SCarlo Caione *psci_ops = &gxbb_ops; 1894a079c75SCarlo Caione gxbb_cpu0_go = 0; 1904a079c75SCarlo Caione return 0; 1914a079c75SCarlo Caione } 192