aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/vithar/kbase/src/common/mali_kbase_pm_demand.c
blob: 4b56881a01d929f3a040b34ec7c8cfeb0e2a1fb3 (plain) (blame)
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
/*
 *
 * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
 *
 * This program is free software and is provided to you under the terms of the GNU General Public License version 2
 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
 * 
 * A copy of the licence is included with the program, and can also be obtained from Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 * 
 */



/**
 * @file mali_kbase_pm_demand.c
 * A simple demand based power management policy
 */

#include <osk/mali_osk.h>
#include <kbase/src/common/mali_kbase.h>
#include <kbase/src/common/mali_kbase_pm.h>

/* Forward declaration for state change function, as it is required by
 * the power up and down functions */
static void demand_state_changed(kbase_device *kbdev);

/** Turns the cores on.
 *
 * This function turns all the cores of the GPU on.
 */
static void demand_power_up(kbase_device *kbdev)
{
	/* Inform the system that the transition has started */
	kbase_pm_power_transitioning(kbdev);

	/* Turn clocks and interrupts on */
	kbase_pm_clock_on(kbdev);
	kbase_pm_enable_interrupts(kbdev);
	
	kbase_pm_check_transitions(kbdev);

	kbdev->pm.policy_data.demand.state = KBASEP_PM_DEMAND_STATE_POWERING_UP;
}

/** Turn the cores off.
 *
 * This function turns all the cores of the GPU off.
 */
static void demand_power_down(kbase_device *kbdev)
{
	u64 cores;

	/* Inform the system that the transition has started */
	kbase_pm_power_transitioning(kbdev);

	/* Turn the cores off */
	cores = kbase_pm_get_present_cores(kbdev, KBASE_PM_CORE_SHADER);
	kbase_pm_invoke_power_down(kbdev, KBASE_PM_CORE_SHADER, cores);

	cores = kbase_pm_get_present_cores(kbdev, KBASE_PM_CORE_TILER);
	kbase_pm_invoke_power_down(kbdev, KBASE_PM_CORE_TILER, cores);

	kbdev->pm.policy_data.demand.state = KBASEP_PM_DEMAND_STATE_POWERING_DOWN;

	kbase_pm_check_transitions(kbdev);
}

/** Turn some cores on/off.
 *
 * This function turns on/off the cores needed by the scheduler.
 */
static void demand_change_gpu_state(kbase_device *kbdev)
{
	/* Update the bitmap of the cores we need */
	kbdev->pm.desired_shader_state = kbdev->shader_needed_bitmap;
	kbdev->pm.desired_tiler_state = kbdev->tiler_needed_bitmap;

	kbase_pm_check_transitions(kbdev);
}

/** Function to handle a GPU state change for the demand power policy
 *
 * This function is called whenever the GPU has transitioned to another state. It first checks that the transition is 
 * complete and then moves the state machine to the next state.
 */
static void demand_state_changed(kbase_device *kbdev)
{
	kbasep_pm_policy_demand *data = &kbdev->pm.policy_data.demand;

	switch(data->state) {
		case KBASEP_PM_DEMAND_STATE_CHANGING_POLICY:
		case KBASEP_PM_DEMAND_STATE_POWERING_UP:
		case KBASEP_PM_DEMAND_STATE_POWERING_DOWN:
			if (kbase_pm_get_pwr_active(kbdev)) {
				/* Cores are still transitioning - ignore the event */
				return;
			}
			break;
		default:
			/* Must not call kbase_pm_get_pwr_active here as the clock may be turned off */
			break;
	}

	switch(data->state)
	{
		case KBASEP_PM_DEMAND_STATE_CHANGING_POLICY:
			/* Signal power events before switching the policy */
			kbase_pm_power_up_done(kbdev);
			kbase_pm_power_down_done(kbdev);
			kbase_pm_change_policy(kbdev);
			break;
		case KBASEP_PM_DEMAND_STATE_POWERING_UP:
			data->state = KBASEP_PM_DEMAND_STATE_POWERED_UP;
			kbase_pm_power_up_done(kbdev);
			/* State changed, try to run jobs */
			kbase_js_try_run_jobs(kbdev);
			break;
		case KBASEP_PM_DEMAND_STATE_POWERING_DOWN:
			data->state = KBASEP_PM_DEMAND_STATE_POWERED_DOWN;
			/* Disable interrupts and turn the clock off */
			kbase_pm_disable_interrupts(kbdev);
			kbase_pm_clock_off(kbdev);
			kbase_pm_power_down_done(kbdev);
			break;
		case KBASEP_PM_DEMAND_STATE_POWERED_UP:
			/* Core states may have been changed, try to run jobs */
			kbase_js_try_run_jobs(kbdev);
			break;
		default:
			break;
	}
}

/** The event callback function for the demand power policy.
 *
 * This function is called to handle the events for the power policy. It calls the relevant handler function depending 
 * on the type of the event.
 *
 * @param kbdev     The kbase device structure for the device
 * @param event     The event that should be processed
 */
static void demand_event(kbase_device *kbdev, kbase_pm_event event)
{
	kbasep_pm_policy_demand *data = &kbdev->pm.policy_data.demand;
	
	switch(event)
	{
		case KBASE_PM_EVENT_POLICY_INIT:
			demand_power_up(kbdev);
			break;
		case KBASE_PM_EVENT_POLICY_CHANGE:
			if (data->state == KBASEP_PM_DEMAND_STATE_POWERED_UP ||
			    data->state == KBASEP_PM_DEMAND_STATE_POWERED_DOWN)
			{
				kbase_pm_change_policy(kbdev);
			}
			else
			{
				data->state = KBASEP_PM_DEMAND_STATE_CHANGING_POLICY;
			}
			break;
		case KBASE_PM_EVENT_SYSTEM_RESUME:
		case KBASE_PM_EVENT_GPU_ACTIVE:
			switch (data->state)
			{
				case KBASEP_PM_DEMAND_STATE_POWERING_UP:
					break;
				case KBASEP_PM_DEMAND_STATE_POWERED_UP:
					kbase_pm_power_up_done(kbdev);
					break;
				default:	
					demand_power_up(kbdev);
			}
			break;
		case KBASE_PM_EVENT_SYSTEM_SUSPEND:
		case KBASE_PM_EVENT_GPU_IDLE:
			switch (data->state)
			{
				case KBASEP_PM_DEMAND_STATE_POWERING_DOWN:
					break;
				case KBASEP_PM_DEMAND_STATE_POWERED_DOWN:
					kbase_pm_power_down_done(kbdev);
					break;
				default:	
					demand_power_down(kbdev);
			}
			break;
		case KBASE_PM_EVENT_CHANGE_GPU_STATE:
			if (data->state != KBASEP_PM_DEMAND_STATE_POWERED_DOWN &&
			    data->state != KBASEP_PM_DEMAND_STATE_POWERING_DOWN)
			{
				demand_change_gpu_state(kbdev);
			}
			break;
		case KBASE_PM_EVENT_GPU_STATE_CHANGED:
			demand_state_changed(kbdev);
			break;
		default:
			/* unrecognized event, should never happen */
			OSK_ASSERT(0);
	}
}

/** Initialize the demand power policy.
 *
 * This sets up the private @ref kbase_pm_device_data.policy_data field of the device for use with the demand power 
 * policy.
 *
 * @param kbdev     The kbase device structure for the device
 */
static void demand_init(kbase_device *kbdev)
{
	kbdev->pm.policy_data.demand.state = KBASEP_PM_DEMAND_STATE_POWERED_UP;
}

/** Terminate the demand power policy.
 *
 * This frees the resources that were allocated by @ref demand_init.
 *
 * @param kbdev     The kbase device structure for the device
 */
static void demand_term(kbase_device *kbdev)
{
	CSTD_UNUSED(kbdev);
}

/** The @ref kbase_pm_policy structure for the demand power policy.
 *
 * This is the static structure that defines the demand power policy's callback and name.
 */
const kbase_pm_policy kbase_pm_demand_policy_ops =
{
	"demand",                   /* name */
	demand_init,                /* init */
	demand_term,                /* term */
	demand_event,               /* event */
};


KBASE_EXPORT_TEST_API(kbase_pm_demand_policy_ops)