summaryrefslogtreecommitdiff
path: root/gxp-pm.h
blob: f9031ca8e8a3cce6ec5bb6e0f0a66c29526195f1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * GXP power management.
 *
 * Copyright (C) 2021 Google LLC
 */
#ifndef __GXP_PM_H__
#define __GXP_PM_H__

#include <soc/google/exynos_pm_qos.h>

#include "gxp-internal.h"

#define AUR_DVFS_MIN_RATE 178000
static const uint aur_power_state2rate[] = {
	0,		/* AUR_OFF */
	178000,		/* AUR_UUD */
	373000,		/* AUR_SUD */
	750000,		/* AUR_UD */
	1160000,	/* AUR_NOM */
	178000,		/* AUR_READY */
	268000,		/* AUR_UUD_PLUS */
	560000,		/* AUR_SUD_PLUS */
	975000,		/* AUR_UD_PLUS */
};

enum aur_power_state {
	AUR_OFF = 0,
	AUR_UUD = 1,
	AUR_SUD = 2,
	AUR_UD = 3,
	AUR_NOM = 4,
	AUR_READY = 5,
	AUR_UUD_PLUS = 6,
	AUR_SUD_PLUS = 7,
	AUR_UD_PLUS = 8,
};

enum aur_memory_power_state {
	AUR_MEM_UNDEFINED = 0,
	AUR_MEM_MIN = 1,
	AUR_MEM_VERY_LOW = 2,
	AUR_MEM_LOW = 3,
	AUR_MEM_HIGH = 4,
	AUR_MEM_VERY_HIGH = 5,
	AUR_MEM_MAX = 6,
};

enum aur_power_cmu_mux_state {
	AUR_CMU_MUX_LOW = 0,
	AUR_CMU_MUX_NORMAL = 1,
};

#define AUR_NUM_POWER_STATE (AUR_MAX_ALLOW_STATE + 1)
#define AUR_NUM_MEMORY_POWER_STATE (AUR_MAX_ALLOW_MEMORY_STATE + 1)

#define AUR_INIT_DVFS_STATE AUR_UUD

/*
 * These macros mean the maximum valid enum value of aur_power_state and
 * aur_memory_power_state, not necessarily the state with the maximum power
 * level.
 */
#define AUR_MAX_ALLOW_STATE AUR_UD_PLUS
#define AUR_MAX_ALLOW_MEMORY_STATE AUR_MEM_MAX

#define AUR_NUM_POWER_STATE_WORKER 16

struct gxp_pm_device_ops {
	int (*pre_blk_powerup)(struct gxp_dev *gxp);
	int (*post_blk_powerup)(struct gxp_dev *gxp);
	int (*pre_blk_poweroff)(struct gxp_dev *gxp);
	int (*post_blk_poweroff)(struct gxp_dev *gxp);
};

struct gxp_set_acpm_state_work {
	struct work_struct work;
	struct gxp_dev *gxp;
	unsigned long state;
	unsigned long prev_state;
	bool low_clkmux;
	bool prev_low_clkmux;
	bool using;
};

struct gxp_req_pm_qos_work {
	struct work_struct work;
	struct gxp_dev *gxp;
	s32 int_val;
	s32 mif_val;
	bool using;
};

struct gxp_power_manager {
	struct gxp_dev *gxp;
	struct mutex pm_lock;
	uint pwr_state_req_count[AUR_NUM_POWER_STATE];
	uint low_clkmux_pwr_state_req_count[AUR_NUM_POWER_STATE];
	uint mem_pwr_state_req_count[AUR_NUM_MEMORY_POWER_STATE];
	/*
	 * Last set CLKMUX state by asynchronous request handler.
	 * If a core is booting, we shouldn't change clock mux state. This is
	 * the expected state to set after all cores booting are finished.
	 * Otherwise, it's the real state of CLKMUX.
	 */
	bool curr_low_clkmux;
	/* Last requested clock mux state */
	bool last_scheduled_low_clkmux;
	int curr_state;
	int curr_memory_state;
	struct gxp_pm_device_ops *ops;
	struct gxp_set_acpm_state_work
		set_acpm_state_work[AUR_NUM_POWER_STATE_WORKER];
	/* Serializes searching for an open worker in set_acpm_state_work[] */
	struct mutex set_acpm_state_work_lock;
	struct gxp_req_pm_qos_work req_pm_qos_work[AUR_NUM_POWER_STATE_WORKER];
	/* Serializes searching for an open worker in req_pm_qos_work[] */
	struct mutex req_pm_qos_work_lock;
	struct workqueue_struct *wq;
	/* INT/MIF requests for memory bandwidth */
	struct exynos_pm_qos_request int_min;
	struct exynos_pm_qos_request mif_min;
	int force_mux_normal_count;
	/* Max frequency that the thermal driver/ACPM will allow in Hz */
	unsigned long thermal_limit;
	u64 blk_switch_count;
};

/**
 * gxp_pm_blk_on() - Turn on the power for BLK_AUR
 * @gxp: The GXP device to turn on
 *
 * Return:
 * * 0       - BLK ON successfully
 * * -ENODEV - Cannot find PM interface
 */
int gxp_pm_blk_on(struct gxp_dev *gxp);

/**
 * gxp_pm_blk_off() - Turn off the power for BLK_AUR
 * @gxp: The GXP device to turn off
 *
 * Return:
 * * 0       - BLK OFF successfully
 * * -ENODEV - Cannot find PM interface
 * * -EBUSY  - Wakelock is held, blk is still busy
 */
int gxp_pm_blk_off(struct gxp_dev *gxp);

/**
 * gxp_pm_get_blk_state() - Get the blk power state
 * @gxp: The GXP device to sample state
 *
 * Return:
 * * state   - State number represented in kHZ, or 0 if OFF
 */
int gxp_pm_get_blk_state(struct gxp_dev *gxp);

/**
 * gxp_pm_get_blk_switch_count() - Get the blk switch count number
 * @gxp: The GXP device to switch the blk
 *
 * Return:
 * * count   - Switch count number after the module initialization.
 */
int gxp_pm_get_blk_switch_count(struct gxp_dev *gxp);

/**
 * gxp_pm_core_on() - Turn on a core on GXP device
 * @gxp: The GXP device to operate
 * @core: The core ID to turn on
 * @verbose: A boolean flag to indicate whether to print the log
 *
 * Return:
 * * 0       - Core on process finished successfully
 * * -ETIMEDOUT - Core on process timed-out.
 */
int gxp_pm_core_on(struct gxp_dev *gxp, uint core, bool verbose);

/**
 * gxp_pm_core_off() - Turn off a core on GXP device
 * @gxp: The GXP device to operate
 * @core: The core ID to turn off
 *
 * Return:
 * * 0       - Core off process finished successfully
 */
int gxp_pm_core_off(struct gxp_dev *gxp, uint core);

/**
 * gxp_pm_init() - API for initialize PM interface for GXP, should only be
 * called once per probe
 * @gxp: The GXP device to operate
 *
 * Return:
 * * 0       - Initialization finished successfully
 * * -ENOMEM - Cannot get memory to finish init.
 */
int gxp_pm_init(struct gxp_dev *gxp);

/**
 * gxp_pm_destroy() - API for removing
 * the power management interface
 * @gxp: The GXP device to operate
 *
 * Return:
 * * 0       - Remove finished successfully
 */
int gxp_pm_destroy(struct gxp_dev *gxp);

/**
 * gxp_pm_blk_set_rate_acpm() - API for setting the block-level DVFS rate.
 * This function can be called at any point after block power on.
 * @gxp: The GXP device to operate
 * @rate: Rate number in khz that need to be set.
 *         Supported rate is in aur_power_state2rate,
 *         if experiment is needed for unsupported rate
 *         please refer to Lassen's ECT table.
 *
 * Return:
 * * 0       - Set finished successfully
 * * Other   - Set rate encounter issue in exynos_acpm_set_rate
 */
int gxp_pm_blk_set_rate_acpm(struct gxp_dev *gxp, unsigned long rate);

/**
 * gxp_pm_blk_get_state_acpm() - API for getting
 * the current DVFS state of the Aurora block.
 * @gxp: The GXP device to operate
 *
 * Return:
 * * State   - State number in Khz from ACPM
 */
int gxp_pm_blk_get_state_acpm(struct gxp_dev *gxp);

/**
 * gxp_pm_update_requested_power_states() - API for a GXP client to vote for a
 * requested power state and a requested memory power state.
 * @gxp: The GXP device to operate.
 * @origin_state: An existing old requested state, will be cleared. If this is
 *                the first vote, pass AUR_OFF.
 * @origin_requested_low_clkmux: Specify whether the existing vote was requested with
 *                               low frequency CLKMUX flag.
 * @requested_state: The new requested state.
 * @requested_low_clkmux: Specify whether the new vote is requested with low frequency
 *			  CLKMUX flag. Will take no effect if the @requested state is
 *			  AUR_OFF.
 * @origin_mem_state: An existing old requested state, will be cleared. If this is
 *                the first vote, pass AUR_MEM_UNDEFINED.
 * @requested_mem_state: The new requested state.
 *
 * Return:
 * * 0       - Voting registered
 * * -EINVAL - Invalid original state or requested state
 */

int gxp_pm_update_requested_power_states(
	struct gxp_dev *gxp, enum aur_power_state origin_state,
	bool origin_requested_low_clkmux, enum aur_power_state requested_state,
	bool requested_low_clkmux, enum aur_memory_power_state origin_mem_state,
	enum aur_memory_power_state requested_mem_state);

/*
 * gxp_pm_force_clkmux_normal() - Force PLL_CON0_NOC_USER and PLL_CON0_PLL_AUR MUX
 * switch to the normal state. This is required to guarantee LPM works when the core
 * is starting the firmware.
 */
void gxp_pm_force_clkmux_normal(struct gxp_dev *gxp);

/*
 * gxp_pm_resume_clkmux() - Check PLL_CON0_NOC_USER and PLL_CON0_PLL_AUR MUX state
 * modified by gxp_pm_force_clkmux_normal(). If the current vote is requested with low
 * frequency CLKMUX flag, should set the MUX state to AUR_CMU_MUX_LOW.
 */
void gxp_pm_resume_clkmux(struct gxp_dev *gxp);

/**
 * gxp_pm_set_thermal_limit() - Notify the power manager of a thermal limit
 * @gxp: The GXP device the limit is set for
 * @thermal_limit: The highest frequency, in Hz, the thermal limit allows
 *
 * The power management code will only use this information for logging.
 */
void gxp_pm_set_thermal_limit(struct gxp_dev *gxp, unsigned long thermal_limit);

#endif /* __GXP_PM_H__ */