Home | History | Annotate | Download | only in uniphier
      1 /*
      2  * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
      3  *
      4  * SPDX-License-Identifier: BSD-3-Clause
      5  */
      6 
      7 #include <arch_helpers.h>
      8 #include <debug.h>
      9 #include <mmio.h>
     10 #include <psci.h>
     11 
     12 #include "uniphier.h"
     13 
     14 #define UNIPHIER_ROM_RSV0		0x59801200
     15 
     16 #define UNIPHIER_SLFRSTSEL		0x61843010
     17 #define   UNIPHIER_SLFRSTSEL_MASK		(0x3 << 0)
     18 #define UNIPHIER_SLFRSTCTL		0x61843014
     19 #define   UNIPHIER_SLFRSTCTL_RST		(1 << 0)
     20 
     21 #define MPIDR_AFFINITY_INVALID		((u_register_t)-1)
     22 
     23 uintptr_t uniphier_sec_entrypoint;
     24 
     25 void uniphier_warmboot_entrypoint(void);
     26 void __dead2 uniphier_fake_pwr_down(void);
     27 u_register_t uniphier_holding_pen_release;
     28 static int uniphier_psci_scp_mode;
     29 
     30 static int uniphier_psci_pwr_domain_on(u_register_t mpidr)
     31 {
     32 	uniphier_holding_pen_release = mpidr;
     33 	flush_dcache_range((uint64_t)&uniphier_holding_pen_release,
     34 			   sizeof(uniphier_holding_pen_release));
     35 
     36 	mmio_write_64(UNIPHIER_ROM_RSV0,
     37 		      (uint64_t)&uniphier_warmboot_entrypoint);
     38 	sev();
     39 
     40 	return PSCI_E_SUCCESS;
     41 }
     42 
     43 static void uniphier_psci_pwr_domain_off(const psci_power_state_t *target_state)
     44 {
     45 	uniphier_gic_cpuif_disable();
     46 }
     47 
     48 static void uniphier_psci_pwr_domain_on_finish(
     49 					const psci_power_state_t *target_state)
     50 {
     51 	uniphier_gic_pcpu_init();
     52 	uniphier_gic_cpuif_enable();
     53 
     54 	uniphier_cci_enable();
     55 }
     56 
     57 static void __dead2 uniphier_psci_pwr_domain_pwr_down_wfi(
     58 					const psci_power_state_t *target_state)
     59 {
     60 	/*
     61 	 * The Boot ROM cannot distinguish warn and cold resets.
     62 	 * Instead of the CPU reset, fake it.
     63 	 */
     64 	uniphier_holding_pen_release = MPIDR_AFFINITY_INVALID;
     65 	flush_dcache_range((uint64_t)&uniphier_holding_pen_release,
     66 			   sizeof(uniphier_holding_pen_release));
     67 
     68 	uniphier_fake_pwr_down();
     69 }
     70 
     71 static void uniphier_self_system_reset(void)
     72 {
     73 	mmio_clrbits_32(UNIPHIER_SLFRSTSEL, UNIPHIER_SLFRSTSEL_MASK);
     74 	mmio_setbits_32(UNIPHIER_SLFRSTCTL, UNIPHIER_SLFRSTCTL_RST);
     75 }
     76 
     77 static void __dead2 uniphier_psci_system_off(void)
     78 {
     79 	if (uniphier_psci_scp_mode) {
     80 		uniphier_scp_system_off();
     81 	} else {
     82 		NOTICE("SCP is disabled; can't shutdown the system.\n");
     83 		NOTICE("Resetting the system instead.\n");
     84 		uniphier_self_system_reset();
     85 	}
     86 
     87 	wfi();
     88 	ERROR("UniPhier System Off: operation not handled.\n");
     89 	panic();
     90 }
     91 
     92 static void __dead2 uniphier_psci_system_reset(void)
     93 {
     94 	if (uniphier_psci_scp_mode)
     95 		uniphier_scp_system_reset();
     96 	else
     97 		uniphier_self_system_reset();
     98 
     99 	wfi();
    100 	ERROR("UniPhier System Reset: operation not handled.\n");
    101 	panic();
    102 }
    103 
    104 static const struct plat_psci_ops uniphier_psci_ops = {
    105 	.pwr_domain_on = uniphier_psci_pwr_domain_on,
    106 	.pwr_domain_off = uniphier_psci_pwr_domain_off,
    107 	.pwr_domain_on_finish = uniphier_psci_pwr_domain_on_finish,
    108 	.pwr_domain_pwr_down_wfi = uniphier_psci_pwr_domain_pwr_down_wfi,
    109 	.system_off = uniphier_psci_system_off,
    110 	.system_reset = uniphier_psci_system_reset,
    111 };
    112 
    113 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
    114 			const struct plat_psci_ops **psci_ops)
    115 {
    116 	uniphier_sec_entrypoint = sec_entrypoint;
    117 	flush_dcache_range((uint64_t)&uniphier_sec_entrypoint,
    118 			   sizeof(uniphier_sec_entrypoint));
    119 
    120 	uniphier_psci_scp_mode = uniphier_scp_is_running();
    121 	flush_dcache_range((uint64_t)&uniphier_psci_scp_mode,
    122 			   sizeof(uniphier_psci_scp_mode));
    123 
    124 	if (uniphier_psci_scp_mode)
    125 		uniphier_scp_open_com();
    126 
    127 	*psci_ops = &uniphier_psci_ops;
    128 
    129 	return 0;
    130 }
    131