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 <assert.h> 84a079c75SCarlo Caione #include <errno.h> 94a079c75SCarlo Caione 104a079c75SCarlo Caione #include <platform_def.h> 114a079c75SCarlo Caione 124a079c75SCarlo Caione #include <arch_helpers.h> 134a079c75SCarlo Caione #include <common/debug.h> 144a079c75SCarlo Caione #include <drivers/arm/gicv2.h> 154a079c75SCarlo Caione #include <drivers/console.h> 164a079c75SCarlo Caione #include <lib/mmio.h> 174a079c75SCarlo Caione #include <lib/psci/psci.h> 184a079c75SCarlo Caione #include <plat/common/platform.h> 194a079c75SCarlo Caione 20e26864afSCarlo Caione #include "aml_private.h" 214a079c75SCarlo Caione 224a079c75SCarlo Caione #define SCPI_POWER_ON 0 234a079c75SCarlo Caione #define SCPI_POWER_RETENTION 1 244a079c75SCarlo Caione #define SCPI_POWER_OFF 3 254a079c75SCarlo Caione 264a079c75SCarlo Caione #define SCPI_SYSTEM_SHUTDOWN 0 274a079c75SCarlo Caione #define SCPI_SYSTEM_REBOOT 1 284a079c75SCarlo Caione 294a079c75SCarlo Caione static uintptr_t gxbb_sec_entrypoint; 304a079c75SCarlo Caione static volatile uint32_t gxbb_cpu0_go; 314a079c75SCarlo Caione 324a079c75SCarlo Caione static void gxbb_program_mailbox(u_register_t mpidr, uint64_t value) 334a079c75SCarlo Caione { 34f681c676SCarlo Caione unsigned int core = plat_calc_core_pos(mpidr); 354a079c75SCarlo Caione uintptr_t cpu_mailbox_addr = GXBB_PSCI_MAILBOX_BASE + (core << 4); 364a079c75SCarlo Caione 374a079c75SCarlo Caione mmio_write_64(cpu_mailbox_addr, value); 384a079c75SCarlo Caione flush_dcache_range(cpu_mailbox_addr, sizeof(uint64_t)); 394a079c75SCarlo Caione } 404a079c75SCarlo Caione 414a079c75SCarlo Caione static void __dead2 gxbb_system_reset(void) 424a079c75SCarlo Caione { 434a079c75SCarlo Caione INFO("BL31: PSCI_SYSTEM_RESET\n"); 444a079c75SCarlo Caione 454a079c75SCarlo Caione uint32_t status = mmio_read_32(GXBB_AO_RTI_STATUS_REG3); 464a079c75SCarlo Caione 474a079c75SCarlo Caione NOTICE("BL31: Reboot reason: 0x%x\n", status); 484a079c75SCarlo Caione 494a079c75SCarlo Caione status &= 0xFFFF0FF0; 504a079c75SCarlo Caione 514a079c75SCarlo Caione console_flush(); 524a079c75SCarlo Caione 534a079c75SCarlo Caione mmio_write_32(GXBB_AO_RTI_STATUS_REG3, status); 544a079c75SCarlo Caione 55*9a5616faSCarlo Caione int ret = aml_scpi_sys_power_state(SCPI_SYSTEM_REBOOT); 564a079c75SCarlo Caione 574a079c75SCarlo Caione if (ret != 0) { 584a079c75SCarlo Caione ERROR("BL31: PSCI_SYSTEM_RESET: SCP error: %u\n", ret); 594a079c75SCarlo Caione panic(); 604a079c75SCarlo Caione } 614a079c75SCarlo Caione 624a079c75SCarlo Caione wfi(); 634a079c75SCarlo Caione 644a079c75SCarlo Caione ERROR("BL31: PSCI_SYSTEM_RESET: Operation not handled\n"); 654a079c75SCarlo Caione panic(); 664a079c75SCarlo Caione } 674a079c75SCarlo Caione 684a079c75SCarlo Caione static void __dead2 gxbb_system_off(void) 694a079c75SCarlo Caione { 704a079c75SCarlo Caione INFO("BL31: PSCI_SYSTEM_OFF\n"); 714a079c75SCarlo Caione 72*9a5616faSCarlo Caione unsigned int ret = aml_scpi_sys_power_state(SCPI_SYSTEM_SHUTDOWN); 734a079c75SCarlo Caione 744a079c75SCarlo Caione if (ret != 0) { 754a079c75SCarlo Caione ERROR("BL31: PSCI_SYSTEM_OFF: SCP error %u\n", ret); 764a079c75SCarlo Caione panic(); 774a079c75SCarlo Caione } 784a079c75SCarlo Caione 794a079c75SCarlo Caione gxbb_program_mailbox(read_mpidr_el1(), 0); 804a079c75SCarlo Caione 814a079c75SCarlo Caione wfi(); 824a079c75SCarlo Caione 834a079c75SCarlo Caione ERROR("BL31: PSCI_SYSTEM_OFF: Operation not handled\n"); 844a079c75SCarlo Caione panic(); 854a079c75SCarlo Caione } 864a079c75SCarlo Caione 874a079c75SCarlo Caione static int32_t gxbb_pwr_domain_on(u_register_t mpidr) 884a079c75SCarlo Caione { 89f681c676SCarlo Caione unsigned int core = plat_calc_core_pos(mpidr); 904a079c75SCarlo Caione 914a079c75SCarlo Caione /* CPU0 can't be turned OFF, emulate it with a WFE loop */ 92f681c676SCarlo Caione if (core == AML_PRIMARY_CPU) { 934a079c75SCarlo Caione VERBOSE("BL31: Releasing CPU0 from wait loop...\n"); 944a079c75SCarlo Caione 954a079c75SCarlo Caione gxbb_cpu0_go = 1; 964a079c75SCarlo Caione flush_dcache_range((uintptr_t)&gxbb_cpu0_go, sizeof(gxbb_cpu0_go)); 974a079c75SCarlo Caione dsb(); 984a079c75SCarlo Caione isb(); 994a079c75SCarlo Caione 1004a079c75SCarlo Caione sev(); 1014a079c75SCarlo Caione 1024a079c75SCarlo Caione return PSCI_E_SUCCESS; 1034a079c75SCarlo Caione } 1044a079c75SCarlo Caione 1054a079c75SCarlo Caione gxbb_program_mailbox(mpidr, gxbb_sec_entrypoint); 106*9a5616faSCarlo Caione aml_scpi_set_css_power_state(mpidr, 1074a079c75SCarlo Caione SCPI_POWER_ON, SCPI_POWER_ON, SCPI_POWER_ON); 1084a079c75SCarlo Caione dmbsy(); 1094a079c75SCarlo Caione sev(); 1104a079c75SCarlo Caione 1114a079c75SCarlo Caione return PSCI_E_SUCCESS; 1124a079c75SCarlo Caione } 1134a079c75SCarlo Caione 1144a079c75SCarlo Caione static void gxbb_pwr_domain_on_finish(const psci_power_state_t *target_state) 1154a079c75SCarlo Caione { 116f681c676SCarlo Caione unsigned int core = plat_calc_core_pos(read_mpidr_el1()); 1174a079c75SCarlo Caione 1184a079c75SCarlo Caione assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] == 1194a079c75SCarlo Caione PLAT_LOCAL_STATE_OFF); 1204a079c75SCarlo Caione 121f681c676SCarlo Caione if (core == AML_PRIMARY_CPU) { 1224a079c75SCarlo Caione gxbb_cpu0_go = 0; 1234a079c75SCarlo Caione flush_dcache_range((uintptr_t)&gxbb_cpu0_go, sizeof(gxbb_cpu0_go)); 1244a079c75SCarlo Caione dsb(); 1254a079c75SCarlo Caione isb(); 1264a079c75SCarlo Caione } 1274a079c75SCarlo Caione 1284a079c75SCarlo Caione gicv2_pcpu_distif_init(); 1294a079c75SCarlo Caione gicv2_cpuif_enable(); 1304a079c75SCarlo Caione } 1314a079c75SCarlo Caione 1324a079c75SCarlo Caione static void gxbb_pwr_domain_off(const psci_power_state_t *target_state) 1334a079c75SCarlo Caione { 1344a079c75SCarlo Caione u_register_t mpidr = read_mpidr_el1(); 135f681c676SCarlo Caione unsigned int core = plat_calc_core_pos(mpidr); 1364a079c75SCarlo Caione uintptr_t addr = GXBB_PSCI_MAILBOX_BASE + 8 + (core << 4); 1374a079c75SCarlo Caione 1384a079c75SCarlo Caione mmio_write_32(addr, 0xFFFFFFFF); 1394a079c75SCarlo Caione flush_dcache_range(addr, sizeof(uint32_t)); 1404a079c75SCarlo Caione 1414a079c75SCarlo Caione gicv2_cpuif_disable(); 1424a079c75SCarlo Caione 1434a079c75SCarlo Caione /* CPU0 can't be turned OFF, emulate it with a WFE loop */ 144f681c676SCarlo Caione if (core == AML_PRIMARY_CPU) 1454a079c75SCarlo Caione return; 1464a079c75SCarlo Caione 147*9a5616faSCarlo Caione aml_scpi_set_css_power_state(mpidr, 1484a079c75SCarlo Caione SCPI_POWER_OFF, SCPI_POWER_ON, SCPI_POWER_ON); 1494a079c75SCarlo Caione } 1504a079c75SCarlo Caione 1514a079c75SCarlo Caione static void __dead2 gxbb_pwr_domain_pwr_down_wfi(const psci_power_state_t 1524a079c75SCarlo Caione *target_state) 1534a079c75SCarlo Caione { 154f681c676SCarlo Caione unsigned int core = plat_calc_core_pos(read_mpidr_el1()); 1554a079c75SCarlo Caione 1564a079c75SCarlo Caione /* CPU0 can't be turned OFF, emulate it with a WFE loop */ 157f681c676SCarlo Caione if (core == AML_PRIMARY_CPU) { 1584a079c75SCarlo Caione VERBOSE("BL31: CPU0 entering wait loop...\n"); 1594a079c75SCarlo Caione 1604a079c75SCarlo Caione while (gxbb_cpu0_go == 0) 1614a079c75SCarlo Caione wfe(); 1624a079c75SCarlo Caione 1634a079c75SCarlo Caione VERBOSE("BL31: CPU0 resumed.\n"); 1644a079c75SCarlo Caione 1654a079c75SCarlo Caione write_rmr_el3(RMR_EL3_RR_BIT | RMR_EL3_AA64_BIT); 1664a079c75SCarlo Caione } 1674a079c75SCarlo Caione 1684a079c75SCarlo Caione dsbsy(); 1694a079c75SCarlo Caione 1704a079c75SCarlo Caione for (;;) 1714a079c75SCarlo Caione wfi(); 1724a079c75SCarlo Caione } 1734a079c75SCarlo Caione 1744a079c75SCarlo Caione /******************************************************************************* 1754a079c75SCarlo Caione * Platform handlers and setup function. 1764a079c75SCarlo Caione ******************************************************************************/ 1774a079c75SCarlo Caione static const plat_psci_ops_t gxbb_ops = { 1784a079c75SCarlo Caione .pwr_domain_on = gxbb_pwr_domain_on, 1794a079c75SCarlo Caione .pwr_domain_on_finish = gxbb_pwr_domain_on_finish, 1804a079c75SCarlo Caione .pwr_domain_off = gxbb_pwr_domain_off, 1814a079c75SCarlo Caione .pwr_domain_pwr_down_wfi = gxbb_pwr_domain_pwr_down_wfi, 1824a079c75SCarlo Caione .system_off = gxbb_system_off, 1834a079c75SCarlo Caione .system_reset = gxbb_system_reset, 1844a079c75SCarlo Caione }; 1854a079c75SCarlo Caione 1864a079c75SCarlo Caione int plat_setup_psci_ops(uintptr_t sec_entrypoint, 1874a079c75SCarlo Caione const plat_psci_ops_t **psci_ops) 1884a079c75SCarlo Caione { 1894a079c75SCarlo Caione gxbb_sec_entrypoint = sec_entrypoint; 1904a079c75SCarlo Caione *psci_ops = &gxbb_ops; 1914a079c75SCarlo Caione gxbb_cpu0_go = 0; 1924a079c75SCarlo Caione return 0; 1934a079c75SCarlo Caione } 194