blob: aa10cfc661e1767bc472dbe4ac686dfc557057fc [file] [log] [blame]
Pamidipati, Vijay7f413b52013-09-24 19:07:12 +05301
2/*
3 **************************************************************************
4 * Copyright (c) 2013, Qualcomm Atheros, Inc.
5 * Permission to use, copy, modify, and/or distribute this software for
6 * any purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
14 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 **************************************************************************
16 */
17/*
18 * nss_pm.c
19 * NSS Power Management APIs
20 *
21 */
22#include <linux/debugfs.h>
23#include <linux/module.h>
24#include <linux/netdevice.h>
Pamidipati, Vijay3e053882013-12-03 17:34:31 +053025#include "nss_clocks.h"
Pamidipati, Vijay7f413b52013-09-24 19:07:12 +053026
27#include "nss_pm.h"
28
29/*
30 * Global NSS PM structure
31 */
32struct nss_pm_global_ctx ctx;
33
34/*
35 * Bus vector table for GMAC driver
36 */
37static struct msm_bus_paths nss_gmac_bw_level_tbl[NSS_PM_PERF_MAX_LEVELS] = {
38 [NSS_PM_PERF_LEVEL_SUSPEND] = GMAC_BW_MBPS(0, 0),
39 /* 0 MHz to DDR, 0 MHz to TCM */
40 [NSS_PM_PERF_LEVEL_IDLE] = GMAC_BW_MBPS(133, 5),
41 /* 133 MHz to DDR, 5 MHz to TCM */
42 [NSS_PM_PERF_LEVEL_NOMINAL] = GMAC_BW_MBPS(200, 400),
43 /* 200 MHz to DDR, 10 MHz to TCM */
44 [NSS_PM_PERF_LEVEL_TURBO] = GMAC_BW_MBPS(266, 533),
45 /* 266 MHz to DDR, 20 MHz to TCM */
46};
47
48/*
49 * Bus vector table for Crypto driver
50 */
51static struct msm_bus_paths nss_crypto_bw_level_tbl[NSS_PM_PERF_MAX_LEVELS] = {
52 [NSS_PM_PERF_LEVEL_SUSPEND] = CRYPTO_BW_MBPS(0, 0),
53 /* 0 MHz to DDR, 0 MHz to TCM */
54 [NSS_PM_PERF_LEVEL_IDLE] = CRYPTO_BW_MBPS(133, 5),
55 /* 133 MHz to DDR, 5 MHz to TCM */
56 [NSS_PM_PERF_LEVEL_NOMINAL] = CRYPTO_BW_MBPS(200, 400),
57 /* 200 MHz to DDR, 10 MHz to TCM */
58 [NSS_PM_PERF_LEVEL_TURBO] = CRYPTO_BW_MBPS(266, 533),
59 /* 266 MHz to DDR, 20 MHz to TCM */
60};
61
Pamidipati, Vijay5d27d812013-11-22 16:48:11 +053062#ifdef NSS_PM_NETAP_GMAC_SCALING
63
64/*
65 * Bus vector table for NSS HLOS driver
66 * This requests bw for both NSS Fab0 and Fab1 on behalf of GMAC and NSS Drivers
67 */
68static struct msm_bus_paths nss_netap_bw_level_tbl[NSS_PM_PERF_MAX_LEVELS] = {
69 [NSS_PM_PERF_LEVEL_SUSPEND] = GMAC_BW_MBPS(0, 0),
70 /* 0 MHz to DDR, 0 MHz to TCM */
71 [NSS_PM_PERF_LEVEL_IDLE] = GMAC_BW_MBPS(133, 5),
72 /* 133 MHz to DDR, 5 MHz to TCM */
73 [NSS_PM_PERF_LEVEL_NOMINAL] = GMAC_BW_MBPS(200, 400),
74 /* 200 MHz to DDR, 10 MHz to TCM */
75 [NSS_PM_PERF_LEVEL_TURBO] = GMAC_BW_MBPS(266, 533),
76 /* 266 MHz to DDR, 20 MHz to TCM */
77};
78
79#else
80
Pamidipati, Vijay7f413b52013-09-24 19:07:12 +053081/*
82 * Bus vector table for NSS HLOS driver
83 */
84static struct msm_bus_paths nss_netap_bw_level_tbl[NSS_PM_PERF_MAX_LEVELS] = {
85 [NSS_PM_PERF_LEVEL_SUSPEND] = NETAP_BW_MBPS(0, 0),
Pamidipati, Vijay5d27d812013-11-22 16:48:11 +053086 /* 0 MHz to DDR, 0 MHz to TCM */
Pamidipati, Vijay7f413b52013-09-24 19:07:12 +053087 [NSS_PM_PERF_LEVEL_IDLE] = NETAP_BW_MBPS(133, 133),
Pamidipati, Vijay5d27d812013-11-22 16:48:11 +053088 /* 133 MHz to DDR and TCM */
Pamidipati, Vijay7f413b52013-09-24 19:07:12 +053089 [NSS_PM_PERF_LEVEL_NOMINAL] = NETAP_BW_MBPS(400, 400),
Pamidipati, Vijay5d27d812013-11-22 16:48:11 +053090 /* 400 MHz to DDR and TCM */
Pamidipati, Vijay7f413b52013-09-24 19:07:12 +053091 [NSS_PM_PERF_LEVEL_TURBO] = NETAP_BW_MBPS(533, 533),
Pamidipati, Vijay5d27d812013-11-22 16:48:11 +053092 /* 533 MHz to DDR and TCM */
Pamidipati, Vijay7f413b52013-09-24 19:07:12 +053093};
94
Pamidipati, Vijay5d27d812013-11-22 16:48:11 +053095#endif
96
Pamidipati, Vijay7f413b52013-09-24 19:07:12 +053097/*
98 * Bus Driver Platform data for GMAC, Crypto and Netap clients
99 */
100static struct msm_bus_scale_pdata nss_bus_scale[] = {
101 [NSS_PM_CLIENT_GMAC] = {
102 .usecase = nss_gmac_bw_level_tbl,
103 .num_usecases = ARRAY_SIZE(nss_gmac_bw_level_tbl),
104 .active_only = 1,
105 .name = "qca-nss-gmac",
106 },
107
108 [NSS_PM_CLIENT_CRYPTO] = {
109 .usecase = nss_crypto_bw_level_tbl,
110 .num_usecases = ARRAY_SIZE(nss_crypto_bw_level_tbl),
111 .active_only = 1,
112 .name = "qca-nss-crypto",
113 },
114
115 [NSS_PM_CLIENT_NETAP] = {
116 .usecase = nss_netap_bw_level_tbl,
117 .num_usecases = ARRAY_SIZE(nss_netap_bw_level_tbl),
118 .active_only = 1,
119 .name = "qca-nss-drv",
120 },
121};
122
123/*
124 * nss_pm_dbg_perf_level_get
125 * debugfs hook to get the current performance level
126 */
127static int nss_pm_dbg_perf_level_get(void *data, u64 *val)
128{
129 nss_pm_client_data_t *pm_client;
130
131 pm_client = (nss_pm_client_data_t *)data;
132 *val = pm_client->current_perf_lvl;
133
134 return NSS_PM_API_SUCCESS;
135}
136
137/*
138 * nss_pm_dbg_autoscale_get
139 * debugfs hook to get the current autoscale setting
140 */
141static int nss_pm_dbg_autoscale_get(void *data, u64 *val)
142{
143 nss_pm_client_data_t *pm_client;
144
145 pm_client = (nss_pm_client_data_t *)data;
146 *val = pm_client->auto_scale;
147
148 return NSS_PM_API_SUCCESS;
149}
150
151/*
152 * nss_pm_dbg_perf_level_set
153 * debugfs hook to set perf level for a client
154 */
155static int nss_pm_dbg_perf_level_set(void *data, u64 val)
156{
157 uint32_t perf_level;
158
159 perf_level = (uint32_t) val;
160
161 if (perf_level >= NSS_PM_PERF_MAX_LEVELS ||
162 perf_level < NSS_PM_PERF_LEVEL_IDLE) {
163 nss_pm_warning("unsupported performance level %d \n", perf_level);
164 return NSS_PM_API_FAILED;
165 }
166
167 nss_pm_set_perf_level(data, perf_level);
168 return NSS_PM_API_SUCCESS;
169}
170
171/*
172 * nss_pm_dbg_autoscale_set
173 * debugfs hook to enable auto scaling for a client
174 */
175static int nss_pm_dbg_autoscale_set(void *data, u64 val)
176{
177 nss_pm_client_data_t *pm_client;
178
179 if (val > 1) {
180 nss_pm_warning(" Invalid set value, valid values are 0/1 \n");
181 return NSS_PM_API_FAILED;
182 }
183
184 pm_client->auto_scale = (uint32_t)val;
185 return NSS_PM_API_SUCCESS;
186}
187
188DEFINE_SIMPLE_ATTRIBUTE(perf_level_fops, nss_pm_dbg_perf_level_get, nss_pm_dbg_perf_level_set, "%llu\n");
189
190DEFINE_SIMPLE_ATTRIBUTE(autoscale_fops, nss_pm_dbg_autoscale_get, nss_pm_dbg_autoscale_set, "%llu\n");
191
192/*
193 * nss_pm_client_register
194 * Initialize GMAC specific PM parameters
195 *
196 * Creates debugfs hooks for user-space control of NSS Client PM
197 * Initializes Bus BW to Idle Perf level
198 * Returns PM handle to the caller.
199 *
200 */
201void *nss_pm_client_register(nss_pm_client_t client_id)
202{
203 int ret;
204 struct dentry *pm_dentry;
205 nss_pm_client_data_t *pm_client;
206
207 if (unlikely(client_id >= NSS_PM_MAX_CLIENTS)) {
208 nss_pm_warning("nss_pm_client_register invalid client id %d \n", client_id);
209 goto error;
210 }
211
212 pm_client = &ctx.nss_pm_client[client_id];
213
214 pm_client->bus_perf_client = msm_bus_scale_register_client(&nss_bus_scale[client_id]);
215 if (!pm_client->bus_perf_client) {
216 nss_pm_warning("unable to register bus client \n");
217 goto error;
218 }
219
220 ret = msm_bus_scale_client_update_request(pm_client->bus_perf_client, NSS_PM_PERF_LEVEL_IDLE);
221 if (ret) {
222 nss_pm_warning("initial bandwidth req failed (%d)\n", ret);
223 msm_bus_scale_unregister_client((uint32_t) pm_client->bus_perf_client);
224 goto error;
225 }
226
227 pm_client->current_perf_lvl = NSS_PM_PERF_LEVEL_IDLE;
228
229 switch (client_id) {
230 case NSS_PM_CLIENT_GMAC:
231 pm_dentry = debugfs_create_dir("gmac" , ctx.pm_dentry);
232 break;
233
234 case NSS_PM_CLIENT_CRYPTO:
235 pm_dentry = debugfs_create_dir("crypto" , ctx.pm_dentry);
236 break;
237
238 case NSS_PM_CLIENT_NETAP:
239 pm_dentry = debugfs_create_dir("netap" , ctx.pm_dentry);
240 break;
241
242 default:
243 nss_pm_warning("debugfs create failed invalid client id %d \n", client_id);
244 msm_bus_scale_unregister_client((uint32_t) pm_client->bus_perf_client);
245 goto error;
246
247 }
248
249 if (unlikely(pm_dentry == NULL)) {
250 nss_pm_info("debugfs not created for %d client pm \n", client_id);
251 goto out;
252 }
253
254 pm_client->dentry = pm_dentry;
Pamidipati, Vijay3e053882013-12-03 17:34:31 +0530255 pm_client->client_id = client_id;
Pamidipati, Vijay7f413b52013-09-24 19:07:12 +0530256
257 if (!debugfs_create_file("perf_level", S_IRUGO | S_IWUSR, pm_dentry, pm_client, &perf_level_fops)) {
258 nss_pm_info("debugfs perf_level file not created for %d client pm \n", client_id);
259 }
260
261 if (!debugfs_create_file("auto-scale", S_IRUGO | S_IWUSR, pm_dentry, pm_client, &autoscale_fops)) {
262 nss_pm_info("debugfs auto-scale file not created for %d client pm \n", client_id);
263 }
264
265out:
266 return (void *)pm_client;
267error:
268 return NULL;
269}
270EXPORT_SYMBOL(nss_pm_client_register);
271
272/*
273 * nss_pm_client_unregister
274 * Unregister the client for any PM operations
275 */
276int nss_pm_client_unregister(nss_pm_client_t client_id)
277{
278 nss_pm_client_data_t *pm_client;
279
280 if (unlikely(client_id >= NSS_PM_MAX_CLIENTS)) {
281 nss_pm_warning("nss_pm_client_unregister invalid client id %d \n", client_id);
282 goto error;
283 }
284
285 pm_client = &ctx.nss_pm_client[client_id];
286
287 if (unlikely(pm_client == NULL)) {
288 nss_pm_warning("nss_pm_client_unregister client not registered %d \n", client_id);
289 goto error;
290 }
291
292 if (pm_client->bus_perf_client) {
293 msm_bus_scale_unregister_client((uint32_t) pm_client->bus_perf_client);
294 } else {
295 nss_pm_info("nss_pm_client_unregister: client not registered \n");
296 }
297
298 if (likely(pm_client->dentry != NULL)) {
299 debugfs_remove_recursive(pm_client->dentry);
300 }
301
302 return NSS_PM_API_SUCCESS;
303
304error:
305 return NSS_PM_API_FAILED;
306}
307
308/*
309 * nss_pm_set_perf_level()
310 * Sets the performance level of client specific Fabrics and Clocks to requested level
311 */
312nss_pm_interface_status_t nss_pm_set_perf_level(void *handle, nss_pm_perf_level_t lvl)
313{
314 int ret = 0;
315 nss_pm_client_data_t *pm_client;
316
317 pm_client = (nss_pm_client_data_t *) handle;
318 if (pm_client->current_perf_lvl == lvl) {
319 nss_pm_trace("Already at perf level %d , ignoring request \n", lvl);
320 return NSS_PM_API_SUCCESS;
321 }
322
323 if (!pm_client->bus_perf_client) {
324 nss_pm_warning("Bus driver client not registered.request failed \n");
325 return NSS_PM_API_FAILED;
326 }
327
Pamidipati, Vijay3e053882013-12-03 17:34:31 +0530328 /*
329 * Do client specific operations here
330 */
331 if (pm_client->client_id == NSS_PM_CLIENT_NETAP) {
332 if (lvl == NSS_PM_PERF_LEVEL_TURBO) {
333 /*
334 * For turbo perf level, switch TCM source to
335 * SRC1 to set TCM clock = 400 MHz
336 * SRC0 and SRC1 are set to 266 and 400 MHz resp.
337 * in nss_hal/ipq806x/nss_hal_pvt.c
338 */
339 writel(0x3, NSSTCM_CLK_SRC_CTL);
340 } else {
341 /*
342 * For Nominal and Idle perf level, switch to SRC0 to
343 * set TCM clock = 266 MHz
344 */
345 writel(0x2, NSSTCM_CLK_SRC_CTL);
346 }
347 }
348
Pamidipati, Vijay7f413b52013-09-24 19:07:12 +0530349 /* Update bandwidth if request has changed. This may sleep. */
350 ret = msm_bus_scale_client_update_request(pm_client->bus_perf_client, lvl);
351 if (ret) {
352 nss_pm_warning("bandwidth request failed (%d)\n", ret);
353 return NSS_PM_API_FAILED;
354 }
355
356 nss_pm_info("perf level request, current: %d new: %d \n", pm_client->current_perf_lvl, lvl);
357 pm_client->current_perf_lvl = lvl;
358
359 return NSS_PM_API_SUCCESS;
360}
361EXPORT_SYMBOL(nss_pm_set_perf_level);
362
363/*
364 * nss_pm_init()
365 * Initialize NSS PM top level structures
366 */
367void nss_pm_init(void) {
368
369 nss_pm_info("NSS Bus PM (platform - IPQ806x, build - %s:%s)\n", __DATE__, __TIME__);
370
371 ctx.pm_dentry = debugfs_create_dir("qca-nss-pm", NULL);
372
373 if (unlikely(ctx.pm_dentry == NULL)) {
374 nss_pm_warning("Failed to create qca-nss-drv directory in debugfs");
375 }
376}