blob: b234e1bfaf856dbbe353bfbfd8cac33bfe68ee0f [file] [log] [blame]
Tejas Patel354fe572018-12-14 00:55:37 -08001/*
2 * Copyright (c) 2019, Xilinx, Inc. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7/*
8 * APU specific definition of processors in the subsystem as well as functions
9 * for getting information about and changing state of the APU.
10 */
11
12#include <plat_ipi.h>
13#include <platform_def.h>
14#include <versal_def.h>
15#include <lib/bakery_lock.h>
Tejas Patelfe0e10a2019-12-08 23:29:44 -080016#include <lib/mmio.h>
17#include <drivers/arm/gicv3.h>
18#include <plat/common/platform.h>
Tejas Patel354fe572018-12-14 00:55:37 -080019#include "pm_client.h"
20
Tejas Patel7029dd82019-02-27 18:44:54 +053021#define UNDEFINED_CPUID (~0)
22
Tejas Patel354fe572018-12-14 00:55:37 -080023DEFINE_BAKERY_LOCK(pm_client_secure_lock);
24
25static const struct pm_ipi apu_ipi = {
26 .local_ipi_id = IPI_ID_APU,
27 .remote_ipi_id = IPI_ID_PMC,
28 .buffer_base = IPI_BUFFER_APU_BASE,
29};
30
31/* Order in pm_procs_all array must match cpu ids */
32static const struct pm_proc pm_procs_all[] = {
33 {
34 .node_id = XPM_DEVID_ACPU_0,
35 .ipi = &apu_ipi,
Tejas Patelfe0e10a2019-12-08 23:29:44 -080036 .pwrdn_mask = APU_0_PWRCTL_CPUPWRDWNREQ_MASK,
Tejas Patel354fe572018-12-14 00:55:37 -080037 },
38 {
39 .node_id = XPM_DEVID_ACPU_1,
40 .ipi = &apu_ipi,
Tejas Patelfe0e10a2019-12-08 23:29:44 -080041 .pwrdn_mask = APU_1_PWRCTL_CPUPWRDWNREQ_MASK,
Tejas Patel354fe572018-12-14 00:55:37 -080042 }
43};
44
45const struct pm_proc *primary_proc = &pm_procs_all[0];
Tejas Patelfe0e10a2019-12-08 23:29:44 -080046
47/**
48 * pm_client_suspend() - Client-specific suspend actions
49 *
50 * This function should contain any PU-specific actions
51 * required prior to sending suspend request to PMU
52 * Actions taken depend on the state system is suspending to.
53 */
54void pm_client_suspend(const struct pm_proc *proc, unsigned int state)
55{
56 bakery_lock_get(&pm_client_secure_lock);
57
58 /* Set powerdown request */
59 mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) |
60 proc->pwrdn_mask);
61
62 bakery_lock_release(&pm_client_secure_lock);
63}
64
65/**
66 * pm_client_abort_suspend() - Client-specific abort-suspend actions
67 *
68 * This function should contain any PU-specific actions
69 * required for aborting a prior suspend request
70 */
71void pm_client_abort_suspend(void)
72{
73 /* Enable interrupts at processor level (for current cpu) */
74 gicv3_cpuif_enable(plat_my_core_pos());
75
76 bakery_lock_get(&pm_client_secure_lock);
77
78 /* Clear powerdown request */
79 mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) &
80 ~primary_proc->pwrdn_mask);
81
82 bakery_lock_release(&pm_client_secure_lock);
83}
84
85/**
Tejas Patel7029dd82019-02-27 18:44:54 +053086 * pm_get_cpuid() - get the local cpu ID for a global node ID
87 * @nid: node id of the processor
88 *
89 * Return: the cpu ID (starting from 0) for the subsystem
90 */
91static unsigned int pm_get_cpuid(uint32_t nid)
92{
93 for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) {
94 if (pm_procs_all[i].node_id == nid)
95 return i;
96 }
97 return UNDEFINED_CPUID;
98}
99
100/**
101 * pm_client_wakeup() - Client-specific wakeup actions
102 *
103 * This function should contain any PU-specific actions
104 * required for waking up another APU core
105 */
106void pm_client_wakeup(const struct pm_proc *proc)
107{
108 unsigned int cpuid = pm_get_cpuid(proc->node_id);
109
110 if (cpuid == UNDEFINED_CPUID)
111 return;
112
113 bakery_lock_get(&pm_client_secure_lock);
114
115 /* clear powerdown bit for affected cpu */
116 uint32_t val = mmio_read_32(FPD_APU_PWRCTL);
117 val &= ~(proc->pwrdn_mask);
118 mmio_write_32(FPD_APU_PWRCTL, val);
119
120 bakery_lock_release(&pm_client_secure_lock);
121}
122
123/**
Tejas Patelfe0e10a2019-12-08 23:29:44 -0800124 * pm_get_proc() - returns pointer to the proc structure
125 * @cpuid: id of the cpu whose proc struct pointer should be returned
126 *
127 * Return: pointer to a proc structure if proc is found, otherwise NULL
128 */
129const struct pm_proc *pm_get_proc(unsigned int cpuid)
130{
131 if (cpuid < ARRAY_SIZE(pm_procs_all))
132 return &pm_procs_all[cpuid];
133
134 return NULL;
135}