blob: 95acf5721829af3a6f412e2c4ca62a8695ff29dc [file] [log] [blame]
Amit Arora728e0c92010-09-14 12:06:09 +05301/*******************************************************************************
Amit Kucheriac0e17fc2011-01-17 09:35:52 +02002 * Copyright (C) 2010, Linaro Limited.
Amit Arora728e0c92010-09-14 12:06:09 +05303 *
4 * This file is part of PowerDebug.
5 *
6 * All rights reserved. This program and the accompanying materials
7 * are made available under the terms of the Eclipse Public License v1.0
8 * which accompanies this distribution, and is available at
9 * http://www.eclipse.org/legal/epl-v10.html
10 *
11 * Contributors:
12 * Amit Arora <amit.arora@linaro.org> (IBM Corporation)
13 * - initial API and implementation
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020014 *
15 * Daniel Lezcano <daniel.lezcano@linaro.org> (IBM Corporation)
16 * - Rewrote code and API
17 *
Amit Arora728e0c92010-09-14 12:06:09 +053018 *******************************************************************************/
19
Daniel Lezcano141c0482011-06-08 23:30:00 +020020#ifndef _GNU_SOURCE
21#define _GNU_SOURCE
Daniel Lezcano9dc3fb32011-03-26 22:06:08 +010022#include <stdio.h>
Daniel Lezcano141c0482011-06-08 23:30:00 +020023#undef _GNU_SOURCE
24#endif
Daniel Lezcano15627482011-06-15 15:45:12 +020025#include <string.h>
26#include <stdbool.h>
27#include <stdlib.h>
28#include <unistd.h>
29#include <sys/param.h>
Daniel Lezcano9dc3fb32011-03-26 22:06:08 +010030#include <mntent.h>
Daniel Lezcanoef323192011-03-26 22:06:20 +010031#include <sys/stat.h>
Daniel Lezcano9dc3fb32011-03-26 22:06:08 +010032
Amit Arora728e0c92010-09-14 12:06:09 +053033#include "powerdebug.h"
Daniel Lezcanob301b082011-06-15 15:45:12 +020034#include "display.h"
Amit Aroraed3e5652010-10-27 12:02:53 +053035#include "clocks.h"
Daniel Lezcanoc193b602011-06-08 23:30:00 +020036#include "tree.h"
Daniel Lezcano88b38e32011-06-15 15:45:12 +020037#include "utils.h"
Amit Arora24ed7d12010-09-14 12:12:58 +053038
Daniel Lezcanoc45662b2011-06-08 23:30:00 +020039struct clock_info {
Daniel Lezcanoc45662b2011-06-08 23:30:00 +020040 int flags;
41 int rate;
42 int usecount;
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020043 bool expanded;
Daniel Lezcano9d5431c2011-06-08 23:30:00 +020044 char *prefix;
Sanjay Singh Rawat88fdebb2013-01-24 18:13:47 +053045 int preparecount;
46 int enablecount;
47 int notifiercount;
Daniel Lezcanoc45662b2011-06-08 23:30:00 +020048} *clocks_info;
49
Sanjay Singh Rawat88fdebb2013-01-24 18:13:47 +053050enum clock_fw_type{
51 CCF, /* common clock framework */
52 OCF, /* old clock framework */
53 MAX,
54};
55
Daniel Lezcano9d5431c2011-06-08 23:30:00 +020056static struct tree *clock_tree = NULL;
Sanjay Singh Rawat88fdebb2013-01-24 18:13:47 +053057static int clock_fw;
Daniel Lezcanoc193b602011-06-08 23:30:00 +020058
Daniel Lezcano9dc3fb32011-03-26 22:06:08 +010059static int locate_debugfs(char *clk_path)
60{
Nishanth Menona14971b2011-09-20 11:31:17 +020061 strcpy(clk_path, "/sys/kernel/debug");
62 return 0;
Daniel Lezcano9dc3fb32011-03-26 22:06:08 +010063}
64
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020065static struct clock_info *clock_alloc(void)
Amit Arora24ed7d12010-09-14 12:12:58 +053066{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020067 struct clock_info *ci;
Daniel Lezcano9dc3fb32011-03-26 22:06:08 +010068
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020069 ci = malloc(sizeof(*ci));
70 if (ci)
71 memset(ci, 0, sizeof(*ci));
Daniel Lezcanoc5a65bf2011-03-26 22:06:11 +010072
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020073 return ci;
Amit Arora24ed7d12010-09-14 12:12:58 +053074}
Amit Arora728e0c92010-09-14 12:06:09 +053075
Daniel Lezcanoafe62252011-06-08 23:30:00 +020076static inline const char *clock_rate(int *rate)
Daniel Lezcanoc6718332011-03-23 14:37:39 +010077{
Daniel Lezcanoafe62252011-06-08 23:30:00 +020078 int r;
Daniel Lezcanoc6718332011-03-23 14:37:39 +010079
Daniel Lezcanoafe62252011-06-08 23:30:00 +020080 /* GHZ */
81 r = *rate >> 30;
82 if (r) {
83 *rate = r;
84 return "GHZ";
85 }
Daniel Lezcanoc6718332011-03-23 14:37:39 +010086
Daniel Lezcanoafe62252011-06-08 23:30:00 +020087 /* MHZ */
88 r = *rate >> 20;
89 if (r) {
90 *rate = r;
91 return "MHZ";
92 }
Daniel Lezcanoc6718332011-03-23 14:37:39 +010093
Daniel Lezcanoafe62252011-06-08 23:30:00 +020094 /* KHZ */
95 r = *rate >> 10;
96 if (r) {
97 *rate = r;
98 return "KHZ";
99 }
100
101 return "";
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100102}
103
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200104static int dump_clock_cb(struct tree *t, void *data)
Daniel Lezcanoef323192011-03-26 22:06:20 +0100105{
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200106 struct clock_info *clk = t->private;
107 struct clock_info *pclk;
108 const char *unit;
109 int ret = 0;
110 int rate = clk->rate;
Daniel Lezcanoef323192011-03-26 22:06:20 +0100111
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200112 if (!t->parent) {
113 printf("/\n");
114 clk->prefix = "";
115 return 0;
Daniel Lezcanoef323192011-03-26 22:06:20 +0100116 }
117
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200118 pclk = t->parent->private;
119
120 if (!clk->prefix)
121 ret = asprintf(&clk->prefix, "%s%s%s", pclk->prefix,
122 t->depth > 1 ? " ": "", t->next ? "|" : " ");
123 if (ret < 0)
124 return -1;
125
126 unit = clock_rate(&rate);
127
128 printf("%s%s-- %s (flags:0x%x, usecount:%d, rate: %d %s)\n",
129 clk->prefix, !t->next ? "`" : "", t->name, clk->flags,
130 clk->usecount, rate, unit);
131
132 return 0;
Daniel Lezcanoef323192011-03-26 22:06:20 +0100133}
134
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200135int dump_clock_info(void)
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100136{
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200137 return tree_for_each(clock_tree, dump_clock_cb, NULL);
138}
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100139
Daniel Lezcano3e38e0f2011-06-08 23:30:00 +0200140static int dump_all_parents(char *clkarg)
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200141{
142 struct tree *tree;
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100143
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200144 tree = tree_find(clock_tree, clkarg);
145 if (!tree) {
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100146 printf("Clock NOT found!\n");
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200147 return -1;
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100148 }
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200149
150 return tree_for_each_parent(tree, dump_clock_cb, NULL);
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100151}
152
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200153static inline int read_clock_cb(struct tree *t, void *data)
Daniel Lezcanoef323192011-03-26 22:06:20 +0100154{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200155 struct clock_info *clk = t->private;
Daniel Lezcanoef323192011-03-26 22:06:20 +0100156
Sanjay Singh Rawat88fdebb2013-01-24 18:13:47 +0530157 if(clock_fw == CCF) {
158 file_read_value(t->path, "clk_flags", "%x", &clk->flags);
159 file_read_value(t->path, "clk_rate", "%d", &clk->rate);
160 file_read_value(t->path, "clk_prepare_count", "%d", &clk->preparecount);
161 file_read_value(t->path, "clk_enable_count", "%d", &clk->enablecount);
162 file_read_value(t->path, "clk_notifier_count", "%d", &clk->notifiercount);
163 }
164 else {
165 file_read_value(t->path, "flags", "%x", &clk->flags);
166 file_read_value(t->path, "rate", "%d", &clk->rate);
167 file_read_value(t->path, "usecount", "%d", &clk->usecount);
168 }
Amit Arora3bc8c922010-11-16 11:27:38 +0530169
170 return 0;
171}
172
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200173static int read_clock_info(struct tree *tree)
Amit Aroraac4e8652010-11-09 11:16:53 +0530174{
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200175 return tree_for_each(tree, read_clock_cb, NULL);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200176}
177
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200178static int fill_clock_cb(struct tree *t, void *data)
179{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200180 struct clock_info *clk;
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200181
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200182 clk = clock_alloc();
183 if (!clk)
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200184 return -1;
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200185 t->private = clk;
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200186
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200187 /* we skip the root node but we set it expanded for its children */
188 if (!t->parent) {
189 clk->expanded = true;
190 return 0;
191 }
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200192
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200193 return read_clock_cb(t, data);
194}
195
196static int fill_clock_tree(void)
197{
198 return tree_for_each(clock_tree, fill_clock_cb, NULL);
199}
200
201static int is_collapsed(struct tree *t, void *data)
202{
203 struct clock_info *clk = t->private;
204
205 if (!clk->expanded)
206 return 1;
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200207
208 return 0;
209}
210
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200211static char *clock_line(struct tree *t)
Amit Aroraeb6cba92010-10-25 16:03:21 +0530212{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200213 struct clock_info *clk;
214 int rate;
215 const char *clkunit;
216 char *clkrate, *clkname, *clkline = NULL;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200217
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200218 clk = t->private;
219 rate = clk->rate;
220 clkunit = clock_rate(&rate);
221
222 if (asprintf(&clkname, "%*s%s", (t->depth - 1) * 2, "", t->name) < 0)
223 return NULL;
224
225 if (asprintf(&clkrate, "%d%s", rate, clkunit) < 0)
226 goto free_clkname;
227
Sanjay Singh Rawat88fdebb2013-01-24 18:13:47 +0530228 if(clock_fw == CCF) {
229 if (asprintf(&clkline, "%-35s 0x%-8x %-12s %-10d %-11d %-15d %-14d %-10d",
230 clkname, clk->flags, clkrate, clk->usecount, t->nrchild,
231 clk->preparecount, clk->enablecount, clk->notifiercount) < 0)
232 goto free_clkrate;
233 }
234 else {
235 if (asprintf(&clkline, "%-55s 0x%-16x %-12s %-9d %-8d",
236 clkname, clk->flags, clkrate, clk->usecount, t->nrchild) < 0)
237 goto free_clkrate;
238 }
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200239
240free_clkrate:
241 free(clkrate);
242free_clkname:
243 free(clkname);
244
245 return clkline;
246}
247
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200248static int _clock_print_info_cb(struct tree *t, void *data)
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200249{
250 struct clock_info *clock = t->private;
251 int *line = data;
252 char *buffer;
253
Daniel Lezcano73b40022011-06-21 00:57:08 +0200254 /* we skip the root node of the tree */
255 if (!t->parent)
256 return 0;
257
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200258 buffer = clock_line(t);
259 if (!buffer)
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200260 return -1;
261
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200262 display_print_line(CLOCK, *line, buffer, clock->usecount, t);
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200263
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200264 (*line)++;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200265
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200266 free(buffer);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200267
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200268 return 0;
269}
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200270
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200271static int clock_print_info_cb(struct tree *t, void *data)
272{
Daniel Lezcanod577aaa2011-06-21 00:57:08 +0200273 /* we skip the root node of the tree */
274 if (!t->parent)
275 return 0;
276
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200277 /* show the clock when *all* its parent is expanded */
278 if (tree_for_each_parent(t->parent, is_collapsed, NULL))
279 return 0;
280
281 return _clock_print_info_cb(t, data);
282}
283
Daniel Lezcanofa453332011-06-21 00:57:08 +0200284static int clock_print_header(void)
285{
286 char *buf;
287 int ret;
288
Sanjay Singh Rawat88fdebb2013-01-24 18:13:47 +0530289 if(clock_fw == CCF) {
290 if (asprintf(&buf, "%-35s %-10s %-12s %-10s %-11s %-15s %-14s %-14s",
291 "Name", "Flags", "Rate", "Usecount", "Children", "Prepare_Count",
292 "Enable_Count", "Notifier_Count") < 0)
293 return -1;
294 }
295 else {
296 if (asprintf(&buf, "%-55s %-16s %-12s %-9s %-8s",
Daniel Lezcanofa453332011-06-21 00:57:08 +0200297 "Name", "Flags", "Rate", "Usecount", "Children") < 0)
298 return -1;
Sanjay Singh Rawat88fdebb2013-01-24 18:13:47 +0530299 }
Daniel Lezcanofa453332011-06-21 00:57:08 +0200300
Daniel Lezcano372ffba2011-06-21 00:57:08 +0200301 ret = display_column_name(buf);
Daniel Lezcanofa453332011-06-21 00:57:08 +0200302
303 free(buf);
304
305 return ret;
306}
307
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200308static int clock_print_info(struct tree *tree)
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200309{
310 int ret, line = 0;
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200311
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200312 display_reset_cursor(CLOCK);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200313
Daniel Lezcanofa453332011-06-21 00:57:08 +0200314 clock_print_header();
315
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200316 ret = tree_for_each(tree, clock_print_info_cb, &line);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200317
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200318 display_refresh_pad(CLOCK);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200319
320 return ret;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200321}
322
Daniel Lezcano73b40022011-06-21 00:57:08 +0200323static int clock_select(void)
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200324{
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200325 struct tree *t = display_get_row_data(CLOCK);
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200326 struct clock_info *clk = t->private;
327
328 clk->expanded = !clk->expanded;
329
330 return 0;
331}
332
333/*
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200334 * Read the clock information and fill the tree with the information
335 * found in the files. Then print the result to the text based interface
336 * Return 0 on success, < 0 otherwise
337 */
Daniel Lezcanod577aaa2011-06-21 00:57:08 +0200338static int clock_display(bool refresh)
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200339{
Daniel Lezcanod577aaa2011-06-21 00:57:08 +0200340 if (refresh && read_clock_info(clock_tree))
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200341 return -1;
342
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200343 return clock_print_info(clock_tree);
344}
345
Daniel Lezcano73b40022011-06-21 00:57:08 +0200346static int clock_find(const char *name)
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200347{
348 struct tree **ptree = NULL;
349 int i, nr, line = 0, ret = 0;
350
351 nr = tree_finds(clock_tree, name, &ptree);
352
353 display_reset_cursor(CLOCK);
354
355 for (i = 0; i < nr; i++) {
356
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200357 ret = _clock_print_info_cb(ptree[i], &line);
358 if (ret)
359 break;
Daniel Lezcanod577aaa2011-06-21 00:57:08 +0200360
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200361 }
362
363 display_refresh_pad(CLOCK);
364
365 free(ptree);
366
367 return ret;
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200368}
369
Daniel Lezcano73b40022011-06-21 00:57:08 +0200370static int clock_selectf(void)
371{
372 struct tree *t = display_get_row_data(CLOCK);
373 int line = 0;
374
375 display_reset_cursor(CLOCK);
376
377 if (tree_for_each_parent(t, _clock_print_info_cb, &line))
378 return -1;
379
380 return display_refresh_pad(CLOCK);
381}
382
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200383/*
384 * Read the clock information and fill the tree with the information
385 * found in the files. Then dump to stdout a formatted result.
386 * @clk : a name for a specific clock we want to show
387 * Return 0 on success, < 0 otherwise
388 */
Daniel Lezcano597892a2011-06-15 15:45:12 +0200389int clock_dump(char *clk)
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200390{
391 int ret;
392
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200393 if (read_clock_info(clock_tree))
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200394 return -1;
Amit Aroraeb6cba92010-10-25 16:03:21 +0530395
Daniel Lezcanoc7891942011-06-08 23:30:00 +0200396 if (clk) {
397 printf("\nParents for \"%s\" Clock :\n\n", clk);
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200398 ret = dump_all_parents(clk);
Daniel Lezcanoc7891942011-06-08 23:30:00 +0200399 printf("\n\n");
400 } else {
401 printf("\nClock Tree :\n");
402 printf("**********\n");
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200403 ret = dump_clock_info();
Daniel Lezcanoc7891942011-06-08 23:30:00 +0200404 printf("\n\n");
405 }
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200406
407 return ret;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200408}
Daniel Lezcanob301b082011-06-15 15:45:12 +0200409
410static struct display_ops clock_ops = {
411 .display = clock_display,
Daniel Lezcano73b40022011-06-21 00:57:08 +0200412 .select = clock_select,
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200413 .find = clock_find,
Daniel Lezcano73b40022011-06-21 00:57:08 +0200414 .selectf = clock_selectf,
Daniel Lezcanob301b082011-06-15 15:45:12 +0200415};
416
417/*
418 * Initialize the clock framework
419 */
420int clock_init(void)
421{
Sanjay Singh Rawat88fdebb2013-01-24 18:13:47 +0530422 char clk_dir_path[MAX+1][PATH_MAX];
Daniel Lezcanob301b082011-06-15 15:45:12 +0200423
Sanjay Singh Rawat88fdebb2013-01-24 18:13:47 +0530424 if (locate_debugfs(clk_dir_path[CCF]) || locate_debugfs(clk_dir_path[OCF]))
Daniel Lezcanob301b082011-06-15 15:45:12 +0200425 return -1;
426
Sanjay Singh Rawat88fdebb2013-01-24 18:13:47 +0530427 sprintf(clk_dir_path[CCF], "%s/clk", clk_dir_path[CCF]);
428 sprintf(clk_dir_path[OCF], "%s/clock", clk_dir_path[OCF]);
429 if (!access(clk_dir_path[CCF], F_OK)) {
430 clock_fw = CCF;
431 strcpy(clk_dir_path[MAX],clk_dir_path[CCF]);
432 }
433 else if(!access(clk_dir_path[OCF], F_OK)) {
434 clock_fw = OCF;
435 strcpy(clk_dir_path[MAX],clk_dir_path[OCF]);
436 }
437 else
Daniel Lezcanob301b082011-06-15 15:45:12 +0200438 return -1;
439
Sanjay Singh Rawat88fdebb2013-01-24 18:13:47 +0530440 clock_tree = tree_load(clk_dir_path[MAX], NULL, false);
Daniel Lezcanob301b082011-06-15 15:45:12 +0200441 if (!clock_tree)
442 return -1;
443
Daniel Lezcanocaafece2011-06-27 22:59:17 +0200444 if (fill_clock_tree())
445 return -1;
446
447 return display_register(CLOCK, &clock_ops);
Daniel Lezcanob301b082011-06-15 15:45:12 +0200448}