blob: 2611a0d99d740d1bbc2358f3306f959e433ebe9e [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{
Nishanth Menona14971b2011-09-20 11:31:17 +020051 strcpy(clk_path, "/sys/kernel/debug");
52 return 0;
Daniel Lezcano9dc3fb32011-03-26 22:06:08 +010053}
54
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020055static struct clock_info *clock_alloc(void)
Amit Arora24ed7d12010-09-14 12:12:58 +053056{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020057 struct clock_info *ci;
Daniel Lezcano9dc3fb32011-03-26 22:06:08 +010058
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020059 ci = malloc(sizeof(*ci));
60 if (ci)
61 memset(ci, 0, sizeof(*ci));
Daniel Lezcanoc5a65bf2011-03-26 22:06:11 +010062
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020063 return ci;
Amit Arora24ed7d12010-09-14 12:12:58 +053064}
Amit Arora728e0c92010-09-14 12:06:09 +053065
Daniel Lezcanoafe62252011-06-08 23:30:00 +020066static inline const char *clock_rate(int *rate)
Daniel Lezcanoc6718332011-03-23 14:37:39 +010067{
Daniel Lezcanoafe62252011-06-08 23:30:00 +020068 int r;
Daniel Lezcanoc6718332011-03-23 14:37:39 +010069
Daniel Lezcanoafe62252011-06-08 23:30:00 +020070 /* GHZ */
71 r = *rate >> 30;
72 if (r) {
73 *rate = r;
74 return "GHZ";
75 }
Daniel Lezcanoc6718332011-03-23 14:37:39 +010076
Daniel Lezcanoafe62252011-06-08 23:30:00 +020077 /* MHZ */
78 r = *rate >> 20;
79 if (r) {
80 *rate = r;
81 return "MHZ";
82 }
Daniel Lezcanoc6718332011-03-23 14:37:39 +010083
Daniel Lezcanoafe62252011-06-08 23:30:00 +020084 /* KHZ */
85 r = *rate >> 10;
86 if (r) {
87 *rate = r;
88 return "KHZ";
89 }
90
91 return "";
Daniel Lezcanoc6718332011-03-23 14:37:39 +010092}
93
Daniel Lezcanoafe62252011-06-08 23:30:00 +020094static int dump_clock_cb(struct tree *t, void *data)
Daniel Lezcanoef323192011-03-26 22:06:20 +010095{
Daniel Lezcanoafe62252011-06-08 23:30:00 +020096 struct clock_info *clk = t->private;
97 struct clock_info *pclk;
98 const char *unit;
99 int ret = 0;
100 int rate = clk->rate;
Daniel Lezcanoef323192011-03-26 22:06:20 +0100101
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200102 if (!t->parent) {
103 printf("/\n");
104 clk->prefix = "";
105 return 0;
Daniel Lezcanoef323192011-03-26 22:06:20 +0100106 }
107
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200108 pclk = t->parent->private;
109
110 if (!clk->prefix)
111 ret = asprintf(&clk->prefix, "%s%s%s", pclk->prefix,
112 t->depth > 1 ? " ": "", t->next ? "|" : " ");
113 if (ret < 0)
114 return -1;
115
116 unit = clock_rate(&rate);
117
118 printf("%s%s-- %s (flags:0x%x, usecount:%d, rate: %d %s)\n",
119 clk->prefix, !t->next ? "`" : "", t->name, clk->flags,
120 clk->usecount, rate, unit);
121
122 return 0;
Daniel Lezcanoef323192011-03-26 22:06:20 +0100123}
124
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200125int dump_clock_info(void)
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100126{
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200127 return tree_for_each(clock_tree, dump_clock_cb, NULL);
128}
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100129
Daniel Lezcano3e38e0f2011-06-08 23:30:00 +0200130static int dump_all_parents(char *clkarg)
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200131{
132 struct tree *tree;
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100133
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200134 tree = tree_find(clock_tree, clkarg);
135 if (!tree) {
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100136 printf("Clock NOT found!\n");
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200137 return -1;
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100138 }
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200139
140 return tree_for_each_parent(tree, dump_clock_cb, NULL);
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100141}
142
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200143static inline int read_clock_cb(struct tree *t, void *data)
Daniel Lezcanoef323192011-03-26 22:06:20 +0100144{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200145 struct clock_info *clk = t->private;
Daniel Lezcanoef323192011-03-26 22:06:20 +0100146
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200147 file_read_value(t->path, "flags", "%x", &clk->flags);
148 file_read_value(t->path, "rate", "%d", &clk->rate);
149 file_read_value(t->path, "usecount", "%d", &clk->usecount);
Amit Arora3bc8c922010-11-16 11:27:38 +0530150
151 return 0;
152}
153
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200154static int read_clock_info(struct tree *tree)
Amit Aroraac4e8652010-11-09 11:16:53 +0530155{
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200156 return tree_for_each(tree, read_clock_cb, NULL);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200157}
158
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200159static int fill_clock_cb(struct tree *t, void *data)
160{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200161 struct clock_info *clk;
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200162
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200163 clk = clock_alloc();
164 if (!clk)
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200165 return -1;
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200166 t->private = clk;
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200167
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200168 /* we skip the root node but we set it expanded for its children */
169 if (!t->parent) {
170 clk->expanded = true;
171 return 0;
172 }
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200173
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200174 return read_clock_cb(t, data);
175}
176
177static int fill_clock_tree(void)
178{
179 return tree_for_each(clock_tree, fill_clock_cb, NULL);
180}
181
182static int is_collapsed(struct tree *t, void *data)
183{
184 struct clock_info *clk = t->private;
185
186 if (!clk->expanded)
187 return 1;
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200188
189 return 0;
190}
191
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200192static char *clock_line(struct tree *t)
Amit Aroraeb6cba92010-10-25 16:03:21 +0530193{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200194 struct clock_info *clk;
195 int rate;
196 const char *clkunit;
197 char *clkrate, *clkname, *clkline = NULL;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200198
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200199 clk = t->private;
200 rate = clk->rate;
201 clkunit = clock_rate(&rate);
202
203 if (asprintf(&clkname, "%*s%s", (t->depth - 1) * 2, "", t->name) < 0)
204 return NULL;
205
206 if (asprintf(&clkrate, "%d%s", rate, clkunit) < 0)
207 goto free_clkname;
208
209 if (asprintf(&clkline, "%-55s 0x%-16x %-12s %-9d %-8d", clkname,
210 clk->flags, clkrate, clk->usecount, t->nrchild) < 0)
211 goto free_clkrate;
212
213free_clkrate:
214 free(clkrate);
215free_clkname:
216 free(clkname);
217
218 return clkline;
219}
220
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200221static int _clock_print_info_cb(struct tree *t, void *data)
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200222{
223 struct clock_info *clock = t->private;
224 int *line = data;
225 char *buffer;
226
Daniel Lezcano73b40022011-06-21 00:57:08 +0200227 /* we skip the root node of the tree */
228 if (!t->parent)
229 return 0;
230
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200231 buffer = clock_line(t);
232 if (!buffer)
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200233 return -1;
234
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200235 display_print_line(CLOCK, *line, buffer, clock->usecount, t);
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200236
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200237 (*line)++;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200238
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200239 free(buffer);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200240
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200241 return 0;
242}
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200243
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200244static int clock_print_info_cb(struct tree *t, void *data)
245{
Daniel Lezcanod577aaa2011-06-21 00:57:08 +0200246 /* we skip the root node of the tree */
247 if (!t->parent)
248 return 0;
249
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200250 /* show the clock when *all* its parent is expanded */
251 if (tree_for_each_parent(t->parent, is_collapsed, NULL))
252 return 0;
253
254 return _clock_print_info_cb(t, data);
255}
256
Daniel Lezcanofa453332011-06-21 00:57:08 +0200257static int clock_print_header(void)
258{
259 char *buf;
260 int ret;
261
262 if (asprintf(&buf, "%-55s %-16s %-12s %-9s %-8s",
263 "Name", "Flags", "Rate", "Usecount", "Children") < 0)
264 return -1;
265
Daniel Lezcano372ffba2011-06-21 00:57:08 +0200266 ret = display_column_name(buf);
Daniel Lezcanofa453332011-06-21 00:57:08 +0200267
268 free(buf);
269
270 return ret;
271}
272
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200273static int clock_print_info(struct tree *tree)
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200274{
275 int ret, line = 0;
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200276
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200277 display_reset_cursor(CLOCK);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200278
Daniel Lezcanofa453332011-06-21 00:57:08 +0200279 clock_print_header();
280
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200281 ret = tree_for_each(tree, clock_print_info_cb, &line);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200282
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200283 display_refresh_pad(CLOCK);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200284
285 return ret;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200286}
287
Daniel Lezcano73b40022011-06-21 00:57:08 +0200288static int clock_select(void)
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200289{
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200290 struct tree *t = display_get_row_data(CLOCK);
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200291 struct clock_info *clk = t->private;
292
293 clk->expanded = !clk->expanded;
294
295 return 0;
296}
297
298/*
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200299 * Read the clock information and fill the tree with the information
300 * found in the files. Then print the result to the text based interface
301 * Return 0 on success, < 0 otherwise
302 */
Daniel Lezcanod577aaa2011-06-21 00:57:08 +0200303static int clock_display(bool refresh)
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200304{
Daniel Lezcanod577aaa2011-06-21 00:57:08 +0200305 if (refresh && read_clock_info(clock_tree))
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200306 return -1;
307
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200308 return clock_print_info(clock_tree);
309}
310
Daniel Lezcano73b40022011-06-21 00:57:08 +0200311static int clock_find(const char *name)
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200312{
313 struct tree **ptree = NULL;
314 int i, nr, line = 0, ret = 0;
315
316 nr = tree_finds(clock_tree, name, &ptree);
317
318 display_reset_cursor(CLOCK);
319
320 for (i = 0; i < nr; i++) {
321
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200322 ret = _clock_print_info_cb(ptree[i], &line);
323 if (ret)
324 break;
Daniel Lezcanod577aaa2011-06-21 00:57:08 +0200325
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200326 }
327
328 display_refresh_pad(CLOCK);
329
330 free(ptree);
331
332 return ret;
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200333}
334
Daniel Lezcano73b40022011-06-21 00:57:08 +0200335static int clock_selectf(void)
336{
337 struct tree *t = display_get_row_data(CLOCK);
338 int line = 0;
339
340 display_reset_cursor(CLOCK);
341
342 if (tree_for_each_parent(t, _clock_print_info_cb, &line))
343 return -1;
344
345 return display_refresh_pad(CLOCK);
346}
347
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200348/*
349 * Read the clock information and fill the tree with the information
350 * found in the files. Then dump to stdout a formatted result.
351 * @clk : a name for a specific clock we want to show
352 * Return 0 on success, < 0 otherwise
353 */
Daniel Lezcano597892a2011-06-15 15:45:12 +0200354int clock_dump(char *clk)
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200355{
356 int ret;
357
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200358 if (read_clock_info(clock_tree))
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200359 return -1;
Amit Aroraeb6cba92010-10-25 16:03:21 +0530360
Daniel Lezcanoc7891942011-06-08 23:30:00 +0200361 if (clk) {
362 printf("\nParents for \"%s\" Clock :\n\n", clk);
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200363 ret = dump_all_parents(clk);
Daniel Lezcanoc7891942011-06-08 23:30:00 +0200364 printf("\n\n");
365 } else {
366 printf("\nClock Tree :\n");
367 printf("**********\n");
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200368 ret = dump_clock_info();
Daniel Lezcanoc7891942011-06-08 23:30:00 +0200369 printf("\n\n");
370 }
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200371
372 return ret;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200373}
Daniel Lezcanob301b082011-06-15 15:45:12 +0200374
375static struct display_ops clock_ops = {
376 .display = clock_display,
Daniel Lezcano73b40022011-06-21 00:57:08 +0200377 .select = clock_select,
Daniel Lezcanoa12163d2011-06-21 00:57:08 +0200378 .find = clock_find,
Daniel Lezcano73b40022011-06-21 00:57:08 +0200379 .selectf = clock_selectf,
Daniel Lezcanob301b082011-06-15 15:45:12 +0200380};
381
382/*
383 * Initialize the clock framework
384 */
385int clock_init(void)
386{
387 char clk_dir_path[PATH_MAX];
388
Daniel Lezcanob301b082011-06-15 15:45:12 +0200389 if (locate_debugfs(clk_dir_path))
390 return -1;
391
392 sprintf(clk_dir_path, "%s/clock", clk_dir_path);
393
394 if (access(clk_dir_path, F_OK))
395 return -1;
396
Daniel Lezcano25fc4a32011-08-25 15:46:13 +0200397 clock_tree = tree_load(clk_dir_path, NULL, false);
Daniel Lezcanob301b082011-06-15 15:45:12 +0200398 if (!clock_tree)
399 return -1;
400
Daniel Lezcanocaafece2011-06-27 22:59:17 +0200401 if (fill_clock_tree())
402 return -1;
403
404 return display_register(CLOCK, &clock_ops);
Daniel Lezcanob301b082011-06-15 15:45:12 +0200405}