blob: 6943b70e8a154f46a5543e944e81c855f522d4b1 [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;
Daniel Lezcanoc45662b2011-06-08 23:30:00 +020045} *clocks_info;
46
Daniel Lezcano9d5431c2011-06-08 23:30:00 +020047static struct tree *clock_tree = NULL;
Daniel Lezcanoc193b602011-06-08 23:30:00 +020048
Daniel Lezcano9dc3fb32011-03-26 22:06:08 +010049static int locate_debugfs(char *clk_path)
50{
51 const char *mtab = "/proc/mounts";
52 struct mntent *mntent;
53 int ret = -1;
54 FILE *file = NULL;
55
56 file = setmntent(mtab, "r");
57 if (!file)
58 return -1;
59
60 while ((mntent = getmntent(file))) {
61
62 if (strcmp(mntent->mnt_type, "debugfs"))
63 continue;
64
65 strcpy(clk_path, mntent->mnt_dir);
66 ret = 0;
67 break;
68 }
69
70 fclose(file);
71 return ret;
72}
73
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020074static struct clock_info *clock_alloc(void)
Amit Arora24ed7d12010-09-14 12:12:58 +053075{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020076 struct clock_info *ci;
Daniel Lezcano9dc3fb32011-03-26 22:06:08 +010077
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020078 ci = malloc(sizeof(*ci));
79 if (ci)
80 memset(ci, 0, sizeof(*ci));
Daniel Lezcanoc5a65bf2011-03-26 22:06:11 +010081
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020082 return ci;
Amit Arora24ed7d12010-09-14 12:12:58 +053083}
Amit Arora728e0c92010-09-14 12:06:09 +053084
Daniel Lezcanoafe62252011-06-08 23:30:00 +020085static inline const char *clock_rate(int *rate)
Daniel Lezcanoc6718332011-03-23 14:37:39 +010086{
Daniel Lezcanoafe62252011-06-08 23:30:00 +020087 int r;
Daniel Lezcanoc6718332011-03-23 14:37:39 +010088
Daniel Lezcanoafe62252011-06-08 23:30:00 +020089 /* GHZ */
90 r = *rate >> 30;
91 if (r) {
92 *rate = r;
93 return "GHZ";
94 }
Daniel Lezcanoc6718332011-03-23 14:37:39 +010095
Daniel Lezcanoafe62252011-06-08 23:30:00 +020096 /* MHZ */
97 r = *rate >> 20;
98 if (r) {
99 *rate = r;
100 return "MHZ";
101 }
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100102
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200103 /* KHZ */
104 r = *rate >> 10;
105 if (r) {
106 *rate = r;
107 return "KHZ";
108 }
109
110 return "";
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100111}
112
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200113static int dump_clock_cb(struct tree *t, void *data)
Daniel Lezcanoef323192011-03-26 22:06:20 +0100114{
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200115 struct clock_info *clk = t->private;
116 struct clock_info *pclk;
117 const char *unit;
118 int ret = 0;
119 int rate = clk->rate;
Daniel Lezcanoef323192011-03-26 22:06:20 +0100120
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200121 if (!t->parent) {
122 printf("/\n");
123 clk->prefix = "";
124 return 0;
Daniel Lezcanoef323192011-03-26 22:06:20 +0100125 }
126
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200127 pclk = t->parent->private;
128
129 if (!clk->prefix)
130 ret = asprintf(&clk->prefix, "%s%s%s", pclk->prefix,
131 t->depth > 1 ? " ": "", t->next ? "|" : " ");
132 if (ret < 0)
133 return -1;
134
135 unit = clock_rate(&rate);
136
137 printf("%s%s-- %s (flags:0x%x, usecount:%d, rate: %d %s)\n",
138 clk->prefix, !t->next ? "`" : "", t->name, clk->flags,
139 clk->usecount, rate, unit);
140
141 return 0;
Daniel Lezcanoef323192011-03-26 22:06:20 +0100142}
143
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200144int dump_clock_info(void)
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100145{
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200146 return tree_for_each(clock_tree, dump_clock_cb, NULL);
147}
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100148
Daniel Lezcano3e38e0f2011-06-08 23:30:00 +0200149static int dump_all_parents(char *clkarg)
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200150{
151 struct tree *tree;
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100152
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200153 tree = tree_find(clock_tree, clkarg);
154 if (!tree) {
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100155 printf("Clock NOT found!\n");
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200156 return -1;
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100157 }
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200158
159 return tree_for_each_parent(tree, dump_clock_cb, NULL);
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100160}
161
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200162static inline int read_clock_cb(struct tree *t, void *data)
Daniel Lezcanoef323192011-03-26 22:06:20 +0100163{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200164 struct clock_info *clk = t->private;
Daniel Lezcanoef323192011-03-26 22:06:20 +0100165
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200166 file_read_value(t->path, "flags", "%x", &clk->flags);
167 file_read_value(t->path, "rate", "%d", &clk->rate);
168 file_read_value(t->path, "usecount", "%d", &clk->usecount);
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
228 if (asprintf(&clkline, "%-55s 0x%-16x %-12s %-9d %-8d", clkname,
229 clk->flags, clkrate, clk->usecount, t->nrchild) < 0)
230 goto free_clkrate;
231
232free_clkrate:
233 free(clkrate);
234free_clkname:
235 free(clkname);
236
237 return clkline;
238}
239
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200240static int _clock_print_info_cb(struct tree *t, void *data)
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200241{
242 struct clock_info *clock = t->private;
243 int *line = data;
244 char *buffer;
245
Daniel Lezcano73b40022011-06-21 00:57:08 +0200246 /* we skip the root node of the tree */
247 if (!t->parent)
248 return 0;
249
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200250 buffer = clock_line(t);
251 if (!buffer)
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200252 return -1;
253
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200254 display_print_line(CLOCK, *line, buffer, clock->usecount, t);
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200255
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200256 (*line)++;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200257
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200258 free(buffer);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200259
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200260 return 0;
261}
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200262
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200263static int clock_print_info_cb(struct tree *t, void *data)
264{
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200265 /* show the clock when *all* its parent is expanded */
266 if (tree_for_each_parent(t->parent, is_collapsed, NULL))
267 return 0;
268
269 return _clock_print_info_cb(t, data);
270}
271
Daniel Lezcanofa453332011-06-21 00:57:08 +0200272static int clock_print_header(void)
273{
274 char *buf;
275 int ret;
276
277 if (asprintf(&buf, "%-55s %-16s %-12s %-9s %-8s",
278 "Name", "Flags", "Rate", "Usecount", "Children") < 0)
279 return -1;
280
Daniel Lezcano372ffba2011-06-21 00:57:08 +0200281 ret = display_column_name(buf);
Daniel Lezcanofa453332011-06-21 00:57:08 +0200282
283 free(buf);
284
285 return ret;
286}
287
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200288static int clock_print_info(struct tree *tree)
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200289{
290 int ret, line = 0;
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200291
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200292 display_reset_cursor(CLOCK);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200293
Daniel Lezcanofa453332011-06-21 00:57:08 +0200294 clock_print_header();
295
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200296 ret = tree_for_each(tree, clock_print_info_cb, &line);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200297
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200298 display_refresh_pad(CLOCK);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200299
300 return ret;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200301}
302
Daniel Lezcano73b40022011-06-21 00:57:08 +0200303static int clock_select(void)
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200304{
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200305 struct tree *t = display_get_row_data(CLOCK);
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200306 struct clock_info *clk = t->private;
307
308 clk->expanded = !clk->expanded;
309
310 return 0;
311}
312
313/*
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200314 * Read the clock information and fill the tree with the information
315 * found in the files. Then print the result to the text based interface
316 * Return 0 on success, < 0 otherwise
317 */
Daniel Lezcano75bd3952011-06-21 00:57:08 +0200318static int clock_display(void)
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200319{
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200320 if (read_clock_info(clock_tree))
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200321 return -1;
322
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200323 return clock_print_info(clock_tree);
324}
325
Daniel Lezcano73b40022011-06-21 00:57:08 +0200326static int clock_find(const char *name)
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200327{
328 struct tree **ptree = NULL;
329 int i, nr, line = 0, ret = 0;
330
331 nr = tree_finds(clock_tree, name, &ptree);
332
333 display_reset_cursor(CLOCK);
334
335 for (i = 0; i < nr; i++) {
336
337 ret = read_clock_info(ptree[i]);
338 if (ret)
339 break;
340
341 ret = _clock_print_info_cb(ptree[i], &line);
342 if (ret)
343 break;
344 }
345
346 display_refresh_pad(CLOCK);
347
348 free(ptree);
349
350 return ret;
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200351}
352
Daniel Lezcano73b40022011-06-21 00:57:08 +0200353static int clock_selectf(void)
354{
355 struct tree *t = display_get_row_data(CLOCK);
356 int line = 0;
357
358 display_reset_cursor(CLOCK);
359
360 if (tree_for_each_parent(t, _clock_print_info_cb, &line))
361 return -1;
362
363 return display_refresh_pad(CLOCK);
364}
365
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200366/*
367 * Read the clock information and fill the tree with the information
368 * found in the files. Then dump to stdout a formatted result.
369 * @clk : a name for a specific clock we want to show
370 * Return 0 on success, < 0 otherwise
371 */
Daniel Lezcano597892a2011-06-15 15:45:12 +0200372int clock_dump(char *clk)
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200373{
374 int ret;
375
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200376 if (read_clock_info(clock_tree))
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200377 return -1;
Amit Aroraeb6cba92010-10-25 16:03:21 +0530378
Daniel Lezcanoc7891942011-06-08 23:30:00 +0200379 if (clk) {
380 printf("\nParents for \"%s\" Clock :\n\n", clk);
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200381 ret = dump_all_parents(clk);
Daniel Lezcanoc7891942011-06-08 23:30:00 +0200382 printf("\n\n");
383 } else {
384 printf("\nClock Tree :\n");
385 printf("**********\n");
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200386 ret = dump_clock_info();
Daniel Lezcanoc7891942011-06-08 23:30:00 +0200387 printf("\n\n");
388 }
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200389
390 return ret;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200391}
Daniel Lezcanob301b082011-06-15 15:45:12 +0200392
393static struct display_ops clock_ops = {
394 .display = clock_display,
Daniel Lezcano73b40022011-06-21 00:57:08 +0200395 .select = clock_select,
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200396 .find = clock_find,
Daniel Lezcano73b40022011-06-21 00:57:08 +0200397 .selectf = clock_selectf,
Daniel Lezcanob301b082011-06-15 15:45:12 +0200398};
399
400/*
401 * Initialize the clock framework
402 */
403int clock_init(void)
404{
405 char clk_dir_path[PATH_MAX];
406
407 if (display_register(CLOCK, &clock_ops))
408 return -1;
409
410 if (locate_debugfs(clk_dir_path))
411 return -1;
412
413 sprintf(clk_dir_path, "%s/clock", clk_dir_path);
414
415 if (access(clk_dir_path, F_OK))
416 return -1;
417
418 clock_tree = tree_load(clk_dir_path, NULL);
419 if (!clock_tree)
420 return -1;
421
422 return fill_clock_tree();
423}