blob: 603ebe4482010714cfbd25dbc8297d1978b5f7cc [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 Lezcano9dc3fb32011-03-26 22:06:08 +010025#include <mntent.h>
Daniel Lezcanoef323192011-03-26 22:06:20 +010026#include <sys/stat.h>
Daniel Lezcano9dc3fb32011-03-26 22:06:08 +010027
Amit Arora728e0c92010-09-14 12:06:09 +053028#include "powerdebug.h"
Amit Aroraed3e5652010-10-27 12:02:53 +053029#include "clocks.h"
Daniel Lezcanoc193b602011-06-08 23:30:00 +020030#include "tree.h"
Amit Arora24ed7d12010-09-14 12:12:58 +053031
Daniel Lezcanoc45662b2011-06-08 23:30:00 +020032struct clock_info {
Daniel Lezcanoc45662b2011-06-08 23:30:00 +020033 int flags;
34 int rate;
35 int usecount;
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020036 bool expanded;
Daniel Lezcano9d5431c2011-06-08 23:30:00 +020037 char *prefix;
Daniel Lezcanoc45662b2011-06-08 23:30:00 +020038} *clocks_info;
39
Daniel Lezcano9d5431c2011-06-08 23:30:00 +020040static struct tree *clock_tree = NULL;
Daniel Lezcanoc193b602011-06-08 23:30:00 +020041
Daniel Lezcano9dc3fb32011-03-26 22:06:08 +010042static int locate_debugfs(char *clk_path)
43{
44 const char *mtab = "/proc/mounts";
45 struct mntent *mntent;
46 int ret = -1;
47 FILE *file = NULL;
48
49 file = setmntent(mtab, "r");
50 if (!file)
51 return -1;
52
53 while ((mntent = getmntent(file))) {
54
55 if (strcmp(mntent->mnt_type, "debugfs"))
56 continue;
57
58 strcpy(clk_path, mntent->mnt_dir);
59 ret = 0;
60 break;
61 }
62
63 fclose(file);
64 return ret;
65}
66
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020067static struct clock_info *clock_alloc(void)
Amit Arora24ed7d12010-09-14 12:12:58 +053068{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020069 struct clock_info *ci;
Daniel Lezcano9dc3fb32011-03-26 22:06:08 +010070
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020071 ci = malloc(sizeof(*ci));
72 if (ci)
73 memset(ci, 0, sizeof(*ci));
Daniel Lezcanoc5a65bf2011-03-26 22:06:11 +010074
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020075 return ci;
Amit Arora24ed7d12010-09-14 12:12:58 +053076}
Amit Arora728e0c92010-09-14 12:06:09 +053077
Daniel Lezcano141c0482011-06-08 23:30:00 +020078/*
79 * This functions is a helper to read a specific file content and store
80 * the content inside a variable pointer passed as parameter, the format
81 * parameter gives the variable type to be read from the file.
82 *
83 * @path : directory path containing the file
84 * @name : name of the file to be read
85 * @format : the format of the format
86 * @value : a pointer to a variable to store the content of the file
87 * Returns 0 on success, -1 otherwise
88 */
89int file_read_value(const char *path, const char *name,
90 const char *format, void *value)
91{
92 FILE *file;
93 char *rpath;
94 int ret;
95
96 ret = asprintf(&rpath, "%s/%s", path, name);
97 if (ret < 0)
98 return ret;
99
100 file = fopen(rpath, "r");
101 if (!file) {
102 ret = -1;
103 goto out_free;
104 }
105
106 ret = fscanf(file, format, value) == EOF ? -1 : 0;
107
108 fclose(file);
109out_free:
110 free(rpath);
111 return ret;
112}
113
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200114static int file_read_from_format(const char *file, int *value,
115 const char *format)
Amit Arora728e0c92010-09-14 12:06:09 +0530116{
Daniel Lezcano2d19ae82011-03-26 22:06:09 +0100117 FILE *f;
Amit Arora6e774cd2010-10-28 11:31:24 +0530118 int ret;
Amit Arora728e0c92010-09-14 12:06:09 +0530119
Daniel Lezcano2d19ae82011-03-26 22:06:09 +0100120 f = fopen(file, "r");
121 if (!f)
122 return -1;
123 ret = fscanf(f, format, value);
124 fclose(f);
Amit Arora728e0c92010-09-14 12:06:09 +0530125
Daniel Lezcano2d19ae82011-03-26 22:06:09 +0100126 return !ret ? -1 : 0;
127}
Amit Arora728e0c92010-09-14 12:06:09 +0530128
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200129static inline int file_read_int(const char *file, int *value)
Daniel Lezcano2d19ae82011-03-26 22:06:09 +0100130{
131 return file_read_from_format(file, value, "%d");
132}
Amit Arora728e0c92010-09-14 12:06:09 +0530133
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200134static inline int file_read_hex(const char *file, int *value)
Daniel Lezcano2d19ae82011-03-26 22:06:09 +0100135{
136 return file_read_from_format(file, value, "%x");
Amit Arora728e0c92010-09-14 12:06:09 +0530137}
138
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200139static inline const char *clock_rate(int *rate)
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100140{
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200141 int r;
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100142
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200143 /* GHZ */
144 r = *rate >> 30;
145 if (r) {
146 *rate = r;
147 return "GHZ";
148 }
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100149
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200150 /* MHZ */
151 r = *rate >> 20;
152 if (r) {
153 *rate = r;
154 return "MHZ";
155 }
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100156
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200157 /* KHZ */
158 r = *rate >> 10;
159 if (r) {
160 *rate = r;
161 return "KHZ";
162 }
163
164 return "";
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100165}
166
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200167static int dump_clock_cb(struct tree *t, void *data)
Daniel Lezcanoef323192011-03-26 22:06:20 +0100168{
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200169 struct clock_info *clk = t->private;
170 struct clock_info *pclk;
171 const char *unit;
172 int ret = 0;
173 int rate = clk->rate;
Daniel Lezcanoef323192011-03-26 22:06:20 +0100174
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200175 if (!t->parent) {
176 printf("/\n");
177 clk->prefix = "";
178 return 0;
Daniel Lezcanoef323192011-03-26 22:06:20 +0100179 }
180
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200181 pclk = t->parent->private;
182
183 if (!clk->prefix)
184 ret = asprintf(&clk->prefix, "%s%s%s", pclk->prefix,
185 t->depth > 1 ? " ": "", t->next ? "|" : " ");
186 if (ret < 0)
187 return -1;
188
189 unit = clock_rate(&rate);
190
191 printf("%s%s-- %s (flags:0x%x, usecount:%d, rate: %d %s)\n",
192 clk->prefix, !t->next ? "`" : "", t->name, clk->flags,
193 clk->usecount, rate, unit);
194
195 return 0;
Daniel Lezcanoef323192011-03-26 22:06:20 +0100196}
197
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200198int dump_clock_info(void)
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100199{
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200200 return tree_for_each(clock_tree, dump_clock_cb, NULL);
201}
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100202
Daniel Lezcano3e38e0f2011-06-08 23:30:00 +0200203static int dump_all_parents(char *clkarg)
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200204{
205 struct tree *tree;
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100206
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200207 tree = tree_find(clock_tree, clkarg);
208 if (!tree) {
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100209 printf("Clock NOT found!\n");
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200210 return -1;
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100211 }
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200212
213 return tree_for_each_parent(tree, dump_clock_cb, NULL);
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100214}
215
Daniel Lezcano897f7332011-03-26 22:06:06 +0100216void find_parents_for_clock(char *clkname, int complete)
Amit Arora3bd79162010-12-01 13:51:42 +0530217{
218 char name[256];
219
220 name[0] = '\0';
221 if (!complete) {
222 char str[256];
223
224 strcat(name, clkname);
225 sprintf(str, "Enter Clock Name : %s\n", name);
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200226 display_reset_cursor();
227 display_print_line(0, str, 1, NULL);
228 display_refresh_pad();
Amit Arora3bd79162010-12-01 13:51:42 +0530229 return;
230 }
231 sprintf(name, "Parents for \"%s\" Clock : \n", clkname);
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200232 display_reset_cursor();
233 display_print_line(0, name, 1, NULL);
234 display_refresh_pad();
Daniel Lezcano3e38e0f2011-06-08 23:30:00 +0200235 dump_all_parents(clkname);
Amit Kucheriaa0adae42011-01-12 10:54:23 -0600236}
Amit Arora3bd79162010-12-01 13:51:42 +0530237
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200238static inline int read_clock_cb(struct tree *t, void *data)
Daniel Lezcanoef323192011-03-26 22:06:20 +0100239{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200240 struct clock_info *clk = t->private;
Daniel Lezcanoef323192011-03-26 22:06:20 +0100241
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200242 file_read_value(t->path, "flags", "%x", &clk->flags);
243 file_read_value(t->path, "rate", "%d", &clk->rate);
244 file_read_value(t->path, "usecount", "%d", &clk->usecount);
Amit Arora3bc8c922010-11-16 11:27:38 +0530245
246 return 0;
247}
248
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200249static int read_clock_info(void)
Amit Aroraac4e8652010-11-09 11:16:53 +0530250{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200251 return tree_for_each(clock_tree, read_clock_cb, NULL);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200252}
253
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200254static int fill_clock_cb(struct tree *t, void *data)
255{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200256 struct clock_info *clk;
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200257
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200258 clk = clock_alloc();
259 if (!clk)
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200260 return -1;
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200261 t->private = clk;
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200262
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200263 /* we skip the root node but we set it expanded for its children */
264 if (!t->parent) {
265 clk->expanded = true;
266 return 0;
267 }
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200268
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200269 return read_clock_cb(t, data);
270}
271
272static int fill_clock_tree(void)
273{
274 return tree_for_each(clock_tree, fill_clock_cb, NULL);
275}
276
277static int is_collapsed(struct tree *t, void *data)
278{
279 struct clock_info *clk = t->private;
280
281 if (!clk->expanded)
282 return 1;
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200283
284 return 0;
285}
286
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200287static char *clock_line(struct tree *t)
Amit Aroraeb6cba92010-10-25 16:03:21 +0530288{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200289 struct clock_info *clk;
290 int rate;
291 const char *clkunit;
292 char *clkrate, *clkname, *clkline = NULL;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200293
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200294 clk = t->private;
295 rate = clk->rate;
296 clkunit = clock_rate(&rate);
297
298 if (asprintf(&clkname, "%*s%s", (t->depth - 1) * 2, "", t->name) < 0)
299 return NULL;
300
301 if (asprintf(&clkrate, "%d%s", rate, clkunit) < 0)
302 goto free_clkname;
303
304 if (asprintf(&clkline, "%-55s 0x%-16x %-12s %-9d %-8d", clkname,
305 clk->flags, clkrate, clk->usecount, t->nrchild) < 0)
306 goto free_clkrate;
307
308free_clkrate:
309 free(clkrate);
310free_clkname:
311 free(clkname);
312
313 return clkline;
314}
315
316static int clock_print_info_cb(struct tree *t, void *data)
317{
318 struct clock_info *clock = t->private;
319 int *line = data;
320 char *buffer;
321
322 /* we skip the root node of the tree */
323 if (!t->parent)
324 return 0;
325
326 /* show the clock when *all* its parent is expanded */
327 if (tree_for_each_parent(t->parent, is_collapsed, NULL))
328 return 0;
329
330 buffer = clock_line(t);
331 if (!buffer)
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200332 return -1;
333
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200334 display_print_line(*line, buffer, clock->usecount, t);
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200335
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200336 (*line)++;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200337
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200338 free(buffer);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200339
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200340 return 0;
341}
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200342
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200343static int clock_print_info(void)
344{
345 int ret, line = 0;
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200346
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200347 print_clock_header();
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200348
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200349 display_reset_cursor();
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200350
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200351 ret = tree_for_each(clock_tree, clock_print_info_cb, &line);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200352
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200353 display_refresh_pad();
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200354
355 return ret;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200356}
357
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200358int clock_toggle_expanded(void)
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200359{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200360 struct tree *t = display_get_row_data();
361 struct clock_info *clk = t->private;
362
363 clk->expanded = !clk->expanded;
364
365 return 0;
366}
367
368/*
369 * Initialize the clock framework
370 */
371int clock_init(void)
372{
373 char clk_dir_path[PATH_MAX];
374
375 if (locate_debugfs(clk_dir_path))
376 return -1;
377
378 sprintf(clk_dir_path, "%s/clock", clk_dir_path);
379
380 if (access(clk_dir_path, F_OK))
381 return -1;
382
383 clock_tree = tree_load(clk_dir_path, NULL);
384 if (!clock_tree)
385 return -1;
386
387 return fill_clock_tree();
388}
389
390/*
391 * Read the clock information and fill the tree with the information
392 * found in the files. Then print the result to the text based interface
393 * Return 0 on success, < 0 otherwise
394 */
Daniel Lezcano05916f82011-06-08 23:30:01 +0200395int read_and_print_clock_info(void)
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200396{
397 if (read_clock_info())
398 return -1;
399
400 return clock_print_info();
401}
402
403/*
404 * Read the clock information and fill the tree with the information
405 * found in the files. Then dump to stdout a formatted result.
406 * @clk : a name for a specific clock we want to show
407 * Return 0 on success, < 0 otherwise
408 */
409int read_and_dump_clock_info(char *clk)
410{
411 int ret;
412
413 if (read_clock_info())
414 return -1;
Amit Aroraeb6cba92010-10-25 16:03:21 +0530415
Daniel Lezcanoc7891942011-06-08 23:30:00 +0200416 if (clk) {
417 printf("\nParents for \"%s\" Clock :\n\n", clk);
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200418 ret = dump_all_parents(clk);
Daniel Lezcanoc7891942011-06-08 23:30:00 +0200419 printf("\n\n");
420 } else {
421 printf("\nClock Tree :\n");
422 printf("**********\n");
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200423 ret = dump_clock_info();
Daniel Lezcanoc7891942011-06-08 23:30:00 +0200424 printf("\n\n");
425 }
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200426
427 return ret;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200428}