blob: 5bb04a49a015b7f1c3f40d4a42538158529edfd7 [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
14 *******************************************************************************/
15
Daniel Lezcano141c0482011-06-08 23:30:00 +020016#ifndef _GNU_SOURCE
17#define _GNU_SOURCE
Daniel Lezcano9dc3fb32011-03-26 22:06:08 +010018#include <stdio.h>
Daniel Lezcano141c0482011-06-08 23:30:00 +020019#undef _GNU_SOURCE
20#endif
Daniel Lezcano9dc3fb32011-03-26 22:06:08 +010021#include <mntent.h>
Daniel Lezcanoef323192011-03-26 22:06:20 +010022#include <sys/stat.h>
Daniel Lezcano9dc3fb32011-03-26 22:06:08 +010023
Amit Arora728e0c92010-09-14 12:06:09 +053024#include "powerdebug.h"
Amit Aroraed3e5652010-10-27 12:02:53 +053025#include "clocks.h"
Daniel Lezcanoc193b602011-06-08 23:30:00 +020026#include "tree.h"
Amit Arora24ed7d12010-09-14 12:12:58 +053027
Daniel Lezcanoef323192011-03-26 22:06:20 +010028#define MAX_LINES 120
29
Amit Arora24ed7d12010-09-14 12:12:58 +053030static char clk_dir_path[PATH_MAX];
Amit Aroraac4e8652010-11-09 11:16:53 +053031static int bold[MAX_LINES];
Daniel Lezcanoef323192011-03-26 22:06:20 +010032static char clock_lines[MAX_LINES][128];
33static int clock_line_no;
34static int old_clock_line_no;
Amit Arora24ed7d12010-09-14 12:12:58 +053035
Daniel Lezcanoc45662b2011-06-08 23:30:00 +020036struct clock_info {
37 char name[NAME_MAX];
38 int flags;
39 int rate;
40 int usecount;
41 int num_children;
42 int last_child;
43 int expanded;
44 int level;
Daniel Lezcano9d5431c2011-06-08 23:30:00 +020045 char *prefix;
Daniel Lezcanoc45662b2011-06-08 23:30:00 +020046 struct clock_info *parent;
47 struct clock_info **children;
48} *clocks_info;
49
Daniel Lezcano9d5431c2011-06-08 23:30:00 +020050static struct tree *clock_tree = NULL;
Daniel Lezcanoc193b602011-06-08 23:30:00 +020051
Daniel Lezcano9dc3fb32011-03-26 22:06:08 +010052static int locate_debugfs(char *clk_path)
53{
54 const char *mtab = "/proc/mounts";
55 struct mntent *mntent;
56 int ret = -1;
57 FILE *file = NULL;
58
59 file = setmntent(mtab, "r");
60 if (!file)
61 return -1;
62
63 while ((mntent = getmntent(file))) {
64
65 if (strcmp(mntent->mnt_type, "debugfs"))
66 continue;
67
68 strcpy(clk_path, mntent->mnt_dir);
69 ret = 0;
70 break;
71 }
72
73 fclose(file);
74 return ret;
75}
76
Daniel Lezcanof0e06652011-03-26 22:06:19 +010077int clock_init(void)
Amit Arora24ed7d12010-09-14 12:12:58 +053078{
Daniel Lezcanof0e06652011-03-26 22:06:19 +010079 if (locate_debugfs(clk_dir_path))
80 return -1;
Daniel Lezcano9dc3fb32011-03-26 22:06:08 +010081
Amit Arora6e774cd2010-10-28 11:31:24 +053082 sprintf(clk_dir_path, "%s/clock", clk_dir_path);
Daniel Lezcanoc5a65bf2011-03-26 22:06:11 +010083
Daniel Lezcanoc193b602011-06-08 23:30:00 +020084 clock_tree = tree_load(clk_dir_path, NULL);
85 if (!clock_tree)
86 return -1;
87
Daniel Lezcanof0e06652011-03-26 22:06:19 +010088 return access(clk_dir_path, F_OK);
Amit Arora24ed7d12010-09-14 12:12:58 +053089}
Amit Arora728e0c92010-09-14 12:06:09 +053090
Daniel Lezcano141c0482011-06-08 23:30:00 +020091/*
92 * This functions is a helper to read a specific file content and store
93 * the content inside a variable pointer passed as parameter, the format
94 * parameter gives the variable type to be read from the file.
95 *
96 * @path : directory path containing the file
97 * @name : name of the file to be read
98 * @format : the format of the format
99 * @value : a pointer to a variable to store the content of the file
100 * Returns 0 on success, -1 otherwise
101 */
102int file_read_value(const char *path, const char *name,
103 const char *format, void *value)
104{
105 FILE *file;
106 char *rpath;
107 int ret;
108
109 ret = asprintf(&rpath, "%s/%s", path, name);
110 if (ret < 0)
111 return ret;
112
113 file = fopen(rpath, "r");
114 if (!file) {
115 ret = -1;
116 goto out_free;
117 }
118
119 ret = fscanf(file, format, value) == EOF ? -1 : 0;
120
121 fclose(file);
122out_free:
123 free(rpath);
124 return ret;
125}
126
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200127static int file_read_from_format(const char *file, int *value,
128 const char *format)
Amit Arora728e0c92010-09-14 12:06:09 +0530129{
Daniel Lezcano2d19ae82011-03-26 22:06:09 +0100130 FILE *f;
Amit Arora6e774cd2010-10-28 11:31:24 +0530131 int ret;
Amit Arora728e0c92010-09-14 12:06:09 +0530132
Daniel Lezcano2d19ae82011-03-26 22:06:09 +0100133 f = fopen(file, "r");
134 if (!f)
135 return -1;
136 ret = fscanf(f, format, value);
137 fclose(f);
Amit Arora728e0c92010-09-14 12:06:09 +0530138
Daniel Lezcano2d19ae82011-03-26 22:06:09 +0100139 return !ret ? -1 : 0;
140}
Amit Arora728e0c92010-09-14 12:06:09 +0530141
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200142static inline int file_read_int(const char *file, int *value)
Daniel Lezcano2d19ae82011-03-26 22:06:09 +0100143{
144 return file_read_from_format(file, value, "%d");
145}
Amit Arora728e0c92010-09-14 12:06:09 +0530146
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200147static inline int file_read_hex(const char *file, int *value)
Daniel Lezcano2d19ae82011-03-26 22:06:09 +0100148{
149 return file_read_from_format(file, value, "%x");
Amit Arora728e0c92010-09-14 12:06:09 +0530150}
151
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100152static void dump_parent(struct clock_info *clk, int line, bool dump)
153{
154 char *unit = "Hz";
155 double drate;
156 static char spaces[64];
157 char str[256];
158 static int maxline;
159
160 if (maxline < line)
161 maxline = line;
162
163 if (clk && clk->parent)
164 dump_parent(clk->parent, ++line, dump);
165
166 drate = (double)clk->rate;
167 if (drate > 1000 && drate < 1000000) {
168 unit = "KHz";
169 drate /= 1000;
170 }
171 if (drate > 1000000) {
172 unit = "MHz";
173 drate /= 1000000;
174 }
175 if (clk == clocks_info) {
176 line++;
177 strcpy(spaces, "");
Daniel Lezcano2d19ae82011-03-26 22:06:09 +0100178 sprintf(str, "%s%s (flags:0x%x,usecount:%d,rate:%5.2f %s)\n",
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100179 spaces, clk->name, clk->flags, clk->usecount, drate,
180 unit);
181 } else {
182 if (!(clk->parent == clocks_info))
183 strcat(spaces, " ");
Daniel Lezcano2d19ae82011-03-26 22:06:09 +0100184 sprintf(str, "%s`- %s (flags:0x%x,usecount:%d,rate:%5.2f %s)\n",
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100185 spaces, clk->name, clk->flags, clk->usecount, drate,
186 unit);
187 }
188 if (dump)
189 //printf("line=%d:m%d:l%d %s", maxline - line + 2, maxline, line, str);
190 printf("%s", str);
191 else
192 print_one_clock(maxline - line + 2, str, 1, 0);
193}
194
Daniel Lezcanoef323192011-03-26 22:06:20 +0100195static struct clock_info *find_clock(struct clock_info *clk, char *clkarg)
196{
197 int i;
198 struct clock_info *ret = clk;
199
200 if (!strcmp(clk->name, clkarg))
201 return ret;
202
203 if (clk->children) {
204 for (i = 0; i < clk->num_children; i++) {
205 if (!strcmp(clk->children[i]->name, clkarg))
206 return clk->children[i];
207 }
208 for (i = 0; i < clk->num_children; i++) {
209 ret = find_clock(clk->children[i], clkarg);
210 if (ret)
211 return ret;
212 }
213 }
214
215 return NULL;
216}
217
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100218static void dump_all_parents(char *clkarg, bool dump)
219{
220 struct clock_info *clk;
221 char spaces[1024];
222
223 strcpy(spaces, "");
224
225 clk = find_clock(clocks_info, clkarg);
226
227 if (!clk)
228 printf("Clock NOT found!\n");
229 else {
230 /* while(clk && clk != clocks_info) { */
231 /* printf("%s\n", clk->name); */
232 /* strcat(spaces, " "); */
233 /* clk = clk->parent; */
234 /* printf("%s <-- ", spaces); */
235 /* } */
236 /* printf(" /\n"); */
237 dump_parent(clk, 1, dump);
238 }
239}
240
Daniel Lezcano897f7332011-03-26 22:06:06 +0100241void find_parents_for_clock(char *clkname, int complete)
Amit Arora3bd79162010-12-01 13:51:42 +0530242{
243 char name[256];
244
245 name[0] = '\0';
246 if (!complete) {
247 char str[256];
248
249 strcat(name, clkname);
250 sprintf(str, "Enter Clock Name : %s\n", name);
251 print_one_clock(2, str, 1, 0);
252 return;
253 }
254 sprintf(name, "Parents for \"%s\" Clock : \n", clkname);
255 print_one_clock(0, name, 1, 1);
Daniel Lezcano897f7332011-03-26 22:06:06 +0100256 dump_all_parents(clkname, false);
Amit Kucheriaa0adae42011-01-12 10:54:23 -0600257}
Amit Arora3bd79162010-12-01 13:51:42 +0530258
Daniel Lezcanoef323192011-03-26 22:06:20 +0100259static void destroy_clocks_info_recur(struct clock_info *clock)
260{
261 int i;
262
263 if (clock && clock->num_children) {
264 for (i = (clock->num_children - 1); i >= 0; i--) {
265 fflush(stdin);
266 destroy_clocks_info_recur(clock->children[i]);
267 if (!i) {
268 free(clock->children);
269 clock->children = NULL;
270 clock->num_children = 0;
271 }
272 }
273 }
274}
275
276static void destroy_clocks_info(void)
277{
278 int i;
279
280 if (!clocks_info)
281 return;
282
283 if (clocks_info->num_children) {
284 for (i = (clocks_info->num_children - 1); i >= 0 ; i--) {
285 destroy_clocks_info_recur(clocks_info->children[i]);
286 if (!i) {
287 free(clocks_info->children);
288 clocks_info->children = NULL;
289 }
290 }
291 }
292 clocks_info->num_children = 0;
293 free(clocks_info);
294 clocks_info = NULL;
295}
296
297
Amit Arora24ed7d12010-09-14 12:12:58 +0530298int read_and_print_clock_info(int verbose, int hrow, int selected)
299{
Amit Arora3bd79162010-12-01 13:51:42 +0530300 print_one_clock(0, "Reading Clock Tree ...", 1, 1);
Amit Aroraa06a7302010-12-02 15:59:37 +0530301
302 if (!old_clock_line_no || selected == REFRESH_WINDOW) {
303 destroy_clocks_info();
Amit Aroraac4e8652010-11-09 11:16:53 +0530304 read_clock_info(clk_dir_path);
Amit Aroraa06a7302010-12-02 15:59:37 +0530305 }
Amit Arora29cb7572010-10-05 17:40:29 +0530306
Daniel Lezcano95b0dac2011-06-08 23:30:00 +0200307 if (!clocks_info || !clocks_info->num_children) {
Amit Arora031263a2010-11-09 11:12:41 +0530308 fprintf(stderr, "powerdebug: No clocks found. Exiting..\n");
309 exit(1);
Amit Arora6e774cd2010-10-28 11:31:24 +0530310 }
Amit Arora728e0c92010-09-14 12:06:09 +0530311
Amit Aroraa06a7302010-12-02 15:59:37 +0530312 if (selected == CLOCK_SELECTED)
313 selected = 1;
314 else
315 selected = 0;
316
Amit Aroraac4e8652010-11-09 11:16:53 +0530317 print_clock_info(verbose, hrow, selected);
Amit Aroraac4e8652010-11-09 11:16:53 +0530318 hrow = (hrow < old_clock_line_no) ? hrow : old_clock_line_no - 1;
319
320 return hrow;
321}
322
Daniel Lezcanoef323192011-03-26 22:06:20 +0100323static int calc_delta_screen_size(int hrow)
Amit Arora3bc8c922010-11-16 11:27:38 +0530324{
Amit Arora51d1b9c2010-11-30 13:55:15 +0530325 if (hrow >= (maxy - 3))
326 return hrow - (maxy - 4);
Amit Arora3bc8c922010-11-16 11:27:38 +0530327
328 return 0;
329}
330
Daniel Lezcanoef323192011-03-26 22:06:20 +0100331static void prepare_name_str(char *namestr, struct clock_info *clock)
Amit Aroraac4e8652010-11-09 11:16:53 +0530332{
333 int i;
334
335 strcpy(namestr, "");
336 if (clock->level > 1)
337 for (i = 0; i < (clock->level - 1); i++)
338 strcat(namestr, " ");
339 strcat(namestr, clock->name);
340}
341
Daniel Lezcanoef323192011-03-26 22:06:20 +0100342static void collapse_all_subclocks(struct clock_info *clock)
343{
344 int i;
345
346 clock->expanded = 0;
347 if (clock->num_children)
348 for (i = 0; i < clock->num_children; i++)
349 collapse_all_subclocks(clock->children[i]);
350}
351
352static void add_clock_details_recur(struct clock_info *clock,
353 int hrow, int selected)
Amit Arora031263a2010-11-09 11:12:41 +0530354{
355 int i;
356 char *unit = " Hz";
357 char rate_str[64];
Amit Aroraac4e8652010-11-09 11:16:53 +0530358 char name_str[256];
Amit Arora031263a2010-11-09 11:12:41 +0530359 double drate = (double)clock->rate;
360
361 if (drate > 1000 && drate < 1000000) {
362 unit = "KHz";
363 drate /= 1000;
364 }
365 if (drate > 1000000) {
366 unit = "MHz";
367 drate /= 1000000;
368 }
369 if (clock->usecount)
370 bold[clock_line_no] = 1;
371 else
372 bold[clock_line_no] = 0;
373
374 sprintf(rate_str, "%.2f %s", drate, unit);
Amit Aroraac4e8652010-11-09 11:16:53 +0530375 prepare_name_str(name_str, clock);
Daniel Lezcano4b669072011-05-24 15:27:49 +0200376 sprintf(clock_lines[clock_line_no++], "%-55s 0x%-4x %-12s %-12d %-12d",
Amit Aroraac4e8652010-11-09 11:16:53 +0530377 name_str, clock->flags, rate_str, clock->usecount,
378 clock->num_children);
379
380 if (selected && (hrow == (clock_line_no - 1))) {
381 if (clock->expanded)
382 collapse_all_subclocks(clock);
383 else
384 clock->expanded = 1;
385 selected = 0;
386 }
Amit Arora031263a2010-11-09 11:12:41 +0530387
388 if (clock->expanded && clock->num_children)
389 for (i = 0; i < clock->num_children; i++)
Amit Aroraac4e8652010-11-09 11:16:53 +0530390 add_clock_details_recur(clock->children[i],
391 hrow, selected);
Amit Arora031263a2010-11-09 11:12:41 +0530392 strcpy(clock_lines[clock_line_no], "");
393}
394
Daniel Lezcanoef323192011-03-26 22:06:20 +0100395void print_clock_info(int verbose, int hrow, int selected)
Amit Aroraac4e8652010-11-09 11:16:53 +0530396{
Daniel Lezcanoef323192011-03-26 22:06:20 +0100397 int i, count = 0, delta;
Amit Aroraac4e8652010-11-09 11:16:53 +0530398
Daniel Lezcanoef323192011-03-26 22:06:20 +0100399 (void)verbose;
Amit Aroraac4e8652010-11-09 11:16:53 +0530400
Daniel Lezcanoef323192011-03-26 22:06:20 +0100401 print_clock_header();
Amit Arora031263a2010-11-09 11:12:41 +0530402
Daniel Lezcanoef323192011-03-26 22:06:20 +0100403 for (i = 0; i < clocks_info->num_children; i++)
404 add_clock_details_recur(clocks_info->children[i],
405 hrow, selected);
Amit Aroraa06a7302010-12-02 15:59:37 +0530406
Daniel Lezcanoef323192011-03-26 22:06:20 +0100407 delta = calc_delta_screen_size(hrow);
408
409 while (clock_lines[count + delta] &&
410 strcmp(clock_lines[count + delta], "")) {
411 if (count < delta) {
412 count++;
413 continue;
Amit Arora031263a2010-11-09 11:12:41 +0530414 }
Daniel Lezcanoef323192011-03-26 22:06:20 +0100415 print_one_clock(count - delta, clock_lines[count + delta],
416 bold[count + delta], (hrow == (count + delta)));
417 count++;
Amit Arora031263a2010-11-09 11:12:41 +0530418 }
Amit Arora031263a2010-11-09 11:12:41 +0530419
Daniel Lezcanoef323192011-03-26 22:06:20 +0100420 old_clock_line_no = clock_line_no;
421 clock_line_no = 0;
Amit Arora728e0c92010-09-14 12:06:09 +0530422}
Amit Arora0e512722010-10-01 12:24:16 +0530423
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200424static void insert_children(struct clock_info **parent, struct clock_info *clk)
Amit Aroraf4fb8102010-11-30 13:55:50 +0530425{
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200426 if (!(*parent)->num_children || (*parent)->children == NULL) {
427 (*parent)->children = (struct clock_info **)
428 malloc(sizeof(struct clock_info *)*2);
429 (*parent)->num_children = 0;
430 } else
431 (*parent)->children = (struct clock_info **)
432 realloc((*parent)->children,
433 sizeof(struct clock_info *) *
434 ((*parent)->num_children + 2));
435 if ((*parent)->num_children > 0)
436 (*parent)->children[(*parent)->num_children - 1]->last_child
437 = 0;
438 clk->last_child = 1;
439 (*parent)->children[(*parent)->num_children] = clk;
440 (*parent)->children[(*parent)->num_children + 1] = NULL;
441 (*parent)->num_children++;
Amit Aroraf4fb8102010-11-30 13:55:50 +0530442}
443
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200444static struct clock_info *read_clock_info_recur(char *clkpath, int level,
445 struct clock_info *parent)
Amit Aroraeb6cba92010-10-25 16:03:21 +0530446{
Amit Arora6e774cd2010-10-28 11:31:24 +0530447 int ret = 0;
448 DIR *dir;
449 char filename[PATH_MAX];
450 struct dirent *item;
451 struct clock_info *cur = NULL;
452 struct stat buf;
Amit Aroraeb6cba92010-10-25 16:03:21 +0530453
Amit Arora6e774cd2010-10-28 11:31:24 +0530454 dir = opendir(clkpath);
455 if (!dir)
456 return NULL;
Amit Aroraeb6cba92010-10-25 16:03:21 +0530457
Amit Arora6e774cd2010-10-28 11:31:24 +0530458 while ((item = readdir(dir))) {
459 struct clock_info *child;
460 /* skip hidden dirs except ".." */
461 if (item->d_name[0] == '.' )
462 continue;
Amit Arora0e512722010-10-01 12:24:16 +0530463
Amit Arora6e774cd2010-10-28 11:31:24 +0530464 sprintf(filename, "%s/%s", clkpath, item->d_name);
Amit Arora0e512722010-10-01 12:24:16 +0530465
Amit Arora6e774cd2010-10-28 11:31:24 +0530466 ret = stat(filename, &buf);
Amit Arora0e512722010-10-01 12:24:16 +0530467
Amit Arora6e774cd2010-10-28 11:31:24 +0530468 if (ret < 0) {
469 printf("Error doing a stat on %s\n", filename);
470 exit(1);
471 }
Amit Aroraeb6cba92010-10-25 16:03:21 +0530472
Amit Arora6e774cd2010-10-28 11:31:24 +0530473 if (S_ISREG(buf.st_mode)) {
474 if (!strcmp(item->d_name, "flags"))
Daniel Lezcano2d19ae82011-03-26 22:06:09 +0100475 file_read_hex(filename, &parent->flags);
Amit Arora6e774cd2010-10-28 11:31:24 +0530476 if (!strcmp(item->d_name, "rate"))
Daniel Lezcano2d19ae82011-03-26 22:06:09 +0100477 file_read_int(filename, &parent->rate);
Amit Arora6e774cd2010-10-28 11:31:24 +0530478 if (!strcmp(item->d_name, "usecount"))
Daniel Lezcano2d19ae82011-03-26 22:06:09 +0100479 file_read_int(filename, &parent->usecount);
Amit Arora6e774cd2010-10-28 11:31:24 +0530480 continue;
481 }
Amit Aroraeb6cba92010-10-25 16:03:21 +0530482
Amit Arora6e774cd2010-10-28 11:31:24 +0530483 if (!S_ISDIR(buf.st_mode))
484 continue;
Amit Arora0e512722010-10-01 12:24:16 +0530485
Amit Arora6e774cd2010-10-28 11:31:24 +0530486 cur = (struct clock_info *)malloc(sizeof(struct clock_info));
487 memset(cur, 0, sizeof(cur));
488 strcpy(cur->name, item->d_name);
489 cur->children = NULL;
490 cur->parent = NULL;
491 cur->num_children = 0;
Amit Arora031263a2010-11-09 11:12:41 +0530492 cur->expanded = 0;
Amit Aroraac4e8652010-11-09 11:16:53 +0530493 cur->level = level;
Amit Arora6e774cd2010-10-28 11:31:24 +0530494 child = read_clock_info_recur(filename, level + 1, cur);
Amit Arora6e774cd2010-10-28 11:31:24 +0530495 insert_children(&parent, cur);
496 cur->parent = parent;
497 }
498 closedir(dir);
Amit Aroraeb6cba92010-10-25 16:03:21 +0530499
Amit Arora6e774cd2010-10-28 11:31:24 +0530500 return cur;
Amit Aroraeb6cba92010-10-25 16:03:21 +0530501}
502
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200503static struct clock_info *clock_alloc(const char *name)
504{
505 struct clock_info *ci;
506
507 ci = malloc(sizeof(*ci));
508 if (ci) {
509 memset(ci, 0, sizeof(*ci));
510 strcpy(ci->name, name);
511 }
512
513 return ci;
514}
515
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200516static int fill_clock_cb(struct tree *t, void *data)
517{
518 struct clock_info *clkinfo;
519
520 clkinfo = clock_alloc(t->name);
521 if (!clkinfo)
522 return -1;
523
524 t->private = clkinfo;
525 clkinfo->level = t->depth;
526
527 file_read_value(t->path, "flags", "%x", &clkinfo->flags);
528 file_read_value(t->path, "rate", "%d", &clkinfo->rate);
529 file_read_value(t->path, "usecount", "%d", &clkinfo->usecount);
530
531 return 0;
532}
533
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200534int read_clock_info(char *clkpath)
Amit Aroraeb6cba92010-10-25 16:03:21 +0530535{
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200536 DIR *dir;
537 struct dirent *item;
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200538 char filename[NAME_MAX];
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200539 struct clock_info *child;
540 struct clock_info *cur;
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200541 int ret = -1;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200542
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200543 if (tree_for_each(clock_tree, fill_clock_cb, NULL))
544 return -1;
545
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200546 dir = opendir(clkpath);
547 if (!dir)
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200548 return -1;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200549
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200550 clocks_info = clock_alloc("/");
551 if (!clocks_info)
552 return -1;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200553
554 while ((item = readdir(dir))) {
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200555
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200556 /* skip hidden dirs except ".." */
557 if (item->d_name[0] == '.')
558 continue;
559
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200560 sprintf(filename, "%s/%s", clkpath, item->d_name);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200561
562 cur = clock_alloc(item->d_name);
563 if (!cur)
564 goto out;
565
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200566 cur->parent = clocks_info;
567 cur->num_children = 0;
568 cur->expanded = 0;
569 cur->level = 1;
570 insert_children(&clocks_info, cur);
571 child = read_clock_info_recur(filename, 2, cur);
572 }
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200573
574 ret = 0;
575
576out:
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200577 closedir(dir);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200578
579 return ret;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200580}
581
582void read_and_dump_clock_info_one(char *clk, bool dump)
583{
584 printf("\nParents for \"%s\" Clock :\n\n", clk);
585 read_clock_info(clk_dir_path);
586 dump_all_parents(clk, dump);
587 printf("\n\n");
Amit Aroraeb6cba92010-10-25 16:03:21 +0530588}
589
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200590static inline const char *clock_rate(int *rate)
591{
592 int r;
593
594 /* GHZ */
595 r = *rate >> 30;
596 if (r) {
597 *rate = r;
598 return "GHZ";
599 }
600
601 /* MHZ */
602 r = *rate >> 20;
603 if (r) {
604 *rate = r;
605 return "MHZ";
606 }
607
608 /* KHZ */
609 r = *rate >> 10;
610 if (r) {
611 *rate = r;
612 return "KHZ";
613 }
614
615 return "";
616}
617
618static int dump_clock_cb(struct tree *t, void *data)
619{
620 struct clock_info *clk = t->private;
621 struct clock_info *pclk;
622 const char *unit;
623 int ret = 0;
624 int rate = clk->rate;
625
626 if (!t->parent) {
627 printf("/\n");
628 clk->prefix = "";
629 return 0;
630 }
631
632 pclk = t->parent->private;
633
634 if (!clk->prefix)
635 ret = asprintf(&clk->prefix, "%s%s%s", pclk->prefix,
636 t->depth > 1 ? " ": "", t->next ? "|" : " ");
637 if (ret < 0)
638 return -1;
639
640 unit = clock_rate(&rate);
641
642 printf("%s%s-- %s (flags:0x%x, usecount:%d, rate: %d %s)\n",
643 clk->prefix, !t->next ? "`" : "", t->name, clk->flags,
644 clk->usecount, rate, unit);
645
646 return 0;
647}
648
Amit Aroraac4e8652010-11-09 11:16:53 +0530649void dump_clock_info(struct clock_info *clk, int level, int bmp)
Amit Aroraeb6cba92010-10-25 16:03:21 +0530650{
Amit Arora6e774cd2010-10-28 11:31:24 +0530651 int i, j;
Amit Aroraeb6cba92010-10-25 16:03:21 +0530652
Amit Arora6e774cd2010-10-28 11:31:24 +0530653 if (!clk)
654 return;
Amit Aroraeb6cba92010-10-25 16:03:21 +0530655
Amit Arora6e774cd2010-10-28 11:31:24 +0530656 for (i = 1, j = 0; i < level; i++, j = (i - 1)) {
657 if (i == (level - 1)) {
658 if (clk->last_child)
659 printf("`-- ");
660 else
661 printf("|-- ");
662 } else {
663 if ((1<<j) & bmp)
664 printf("| ");
665 else
666 printf(" ");
667 }
668 }
Amit Arora031263a2010-11-09 11:12:41 +0530669
Amit Arora6e774cd2010-10-28 11:31:24 +0530670 if (clk == clocks_info)
671 printf("%s\n", clk->name);
672 else {
673 char *unit = "Hz";
674 double drate = (double)clk->rate;
Amit Kucheriaa0adae42011-01-12 10:54:23 -0600675
Amit Arora6e774cd2010-10-28 11:31:24 +0530676 if (drate > 1000 && drate < 1000000) {
677 unit = "KHz";
678 drate /= 1000;
679 }
680 if (drate > 1000000) {
681 unit = "MHz";
682 drate /= 1000000;
683 }
Daniel Lezcano2d19ae82011-03-26 22:06:09 +0100684 printf("%s (flags:0x%x,usecount:%d,rate:%5.2f %s)\n",
Amit Arora6e774cd2010-10-28 11:31:24 +0530685 clk->name, clk->flags, clk->usecount, drate, unit);
Amit Arora6e774cd2010-10-28 11:31:24 +0530686 }
687 if (clk->children) {
688 int tbmp = bmp;
689 int xbmp = -1;
Amit Aroraeb6cba92010-10-25 16:03:21 +0530690
Amit Arora6e774cd2010-10-28 11:31:24 +0530691 if (clk->last_child) {
692 xbmp ^= 1 << (level - 2);
693
694 xbmp = tbmp & xbmp;
695 } else
696 xbmp = bmp;
697 for (i = 0; i < clk->num_children; i++) {
Amit Arora6e774cd2010-10-28 11:31:24 +0530698 tbmp = xbmp | (1 << level);
Amit Aroraac4e8652010-11-09 11:16:53 +0530699 dump_clock_info(clk->children[i], level + 1, tbmp);
Amit Arora6e774cd2010-10-28 11:31:24 +0530700 }
701 }
Amit Arora0e512722010-10-01 12:24:16 +0530702}
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200703
704void read_and_dump_clock_info(int verbose)
705{
706 (void)verbose;
707 printf("\nClock Tree :\n");
708 printf("**********\n");
709 read_clock_info(clk_dir_path);
710 dump_clock_info(clocks_info, 1, 1);
711 printf("\n\n");
712}