blob: db219d8f9ecd68cb9f8f311954901c29c0f6f1b7 [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"
Daniel Lezcano88b38e32011-06-15 15:45:12 +020031#include "utils.h"
Amit Arora24ed7d12010-09-14 12:12:58 +053032
Daniel Lezcanoc45662b2011-06-08 23:30:00 +020033struct clock_info {
Daniel Lezcanoc45662b2011-06-08 23:30:00 +020034 int flags;
35 int rate;
36 int usecount;
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020037 bool expanded;
Daniel Lezcano9d5431c2011-06-08 23:30:00 +020038 char *prefix;
Daniel Lezcanoc45662b2011-06-08 23:30:00 +020039} *clocks_info;
40
Daniel Lezcano9d5431c2011-06-08 23:30:00 +020041static struct tree *clock_tree = NULL;
Daniel Lezcanoc193b602011-06-08 23:30:00 +020042
Daniel Lezcano9dc3fb32011-03-26 22:06:08 +010043static int locate_debugfs(char *clk_path)
44{
45 const char *mtab = "/proc/mounts";
46 struct mntent *mntent;
47 int ret = -1;
48 FILE *file = NULL;
49
50 file = setmntent(mtab, "r");
51 if (!file)
52 return -1;
53
54 while ((mntent = getmntent(file))) {
55
56 if (strcmp(mntent->mnt_type, "debugfs"))
57 continue;
58
59 strcpy(clk_path, mntent->mnt_dir);
60 ret = 0;
61 break;
62 }
63
64 fclose(file);
65 return ret;
66}
67
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020068static struct clock_info *clock_alloc(void)
Amit Arora24ed7d12010-09-14 12:12:58 +053069{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020070 struct clock_info *ci;
Daniel Lezcano9dc3fb32011-03-26 22:06:08 +010071
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020072 ci = malloc(sizeof(*ci));
73 if (ci)
74 memset(ci, 0, sizeof(*ci));
Daniel Lezcanoc5a65bf2011-03-26 22:06:11 +010075
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020076 return ci;
Amit Arora24ed7d12010-09-14 12:12:58 +053077}
Amit Arora728e0c92010-09-14 12:06:09 +053078
Daniel Lezcanoafe62252011-06-08 23:30:00 +020079static inline const char *clock_rate(int *rate)
Daniel Lezcanoc6718332011-03-23 14:37:39 +010080{
Daniel Lezcanoafe62252011-06-08 23:30:00 +020081 int r;
Daniel Lezcanoc6718332011-03-23 14:37:39 +010082
Daniel Lezcanoafe62252011-06-08 23:30:00 +020083 /* GHZ */
84 r = *rate >> 30;
85 if (r) {
86 *rate = r;
87 return "GHZ";
88 }
Daniel Lezcanoc6718332011-03-23 14:37:39 +010089
Daniel Lezcanoafe62252011-06-08 23:30:00 +020090 /* MHZ */
91 r = *rate >> 20;
92 if (r) {
93 *rate = r;
94 return "MHZ";
95 }
Daniel Lezcanoc6718332011-03-23 14:37:39 +010096
Daniel Lezcanoafe62252011-06-08 23:30:00 +020097 /* KHZ */
98 r = *rate >> 10;
99 if (r) {
100 *rate = r;
101 return "KHZ";
102 }
103
104 return "";
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100105}
106
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200107static int dump_clock_cb(struct tree *t, void *data)
Daniel Lezcanoef323192011-03-26 22:06:20 +0100108{
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200109 struct clock_info *clk = t->private;
110 struct clock_info *pclk;
111 const char *unit;
112 int ret = 0;
113 int rate = clk->rate;
Daniel Lezcanoef323192011-03-26 22:06:20 +0100114
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200115 if (!t->parent) {
116 printf("/\n");
117 clk->prefix = "";
118 return 0;
Daniel Lezcanoef323192011-03-26 22:06:20 +0100119 }
120
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200121 pclk = t->parent->private;
122
123 if (!clk->prefix)
124 ret = asprintf(&clk->prefix, "%s%s%s", pclk->prefix,
125 t->depth > 1 ? " ": "", t->next ? "|" : " ");
126 if (ret < 0)
127 return -1;
128
129 unit = clock_rate(&rate);
130
131 printf("%s%s-- %s (flags:0x%x, usecount:%d, rate: %d %s)\n",
132 clk->prefix, !t->next ? "`" : "", t->name, clk->flags,
133 clk->usecount, rate, unit);
134
135 return 0;
Daniel Lezcanoef323192011-03-26 22:06:20 +0100136}
137
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200138int dump_clock_info(void)
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100139{
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200140 return tree_for_each(clock_tree, dump_clock_cb, NULL);
141}
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100142
Daniel Lezcano3e38e0f2011-06-08 23:30:00 +0200143static int dump_all_parents(char *clkarg)
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200144{
145 struct tree *tree;
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100146
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200147 tree = tree_find(clock_tree, clkarg);
148 if (!tree) {
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100149 printf("Clock NOT found!\n");
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200150 return -1;
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100151 }
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200152
153 return tree_for_each_parent(tree, dump_clock_cb, NULL);
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100154}
155
Daniel Lezcano897f7332011-03-26 22:06:06 +0100156void find_parents_for_clock(char *clkname, int complete)
Amit Arora3bd79162010-12-01 13:51:42 +0530157{
158 char name[256];
159
160 name[0] = '\0';
161 if (!complete) {
162 char str[256];
163
164 strcat(name, clkname);
165 sprintf(str, "Enter Clock Name : %s\n", name);
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200166 display_reset_cursor(CLOCK);
167 display_print_line(CLOCK, 0, str, 1, NULL);
168 display_refresh_pad(CLOCK);
Amit Arora3bd79162010-12-01 13:51:42 +0530169 return;
170 }
171 sprintf(name, "Parents for \"%s\" Clock : \n", clkname);
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200172 display_reset_cursor(CLOCK);
173 display_print_line(CLOCK, 0, name, 1, NULL);
174 display_refresh_pad(CLOCK);
Daniel Lezcano3e38e0f2011-06-08 23:30:00 +0200175 dump_all_parents(clkname);
Amit Kucheriaa0adae42011-01-12 10:54:23 -0600176}
Amit Arora3bd79162010-12-01 13:51:42 +0530177
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200178static inline int read_clock_cb(struct tree *t, void *data)
Daniel Lezcanoef323192011-03-26 22:06:20 +0100179{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200180 struct clock_info *clk = t->private;
Daniel Lezcanoef323192011-03-26 22:06:20 +0100181
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200182 file_read_value(t->path, "flags", "%x", &clk->flags);
183 file_read_value(t->path, "rate", "%d", &clk->rate);
184 file_read_value(t->path, "usecount", "%d", &clk->usecount);
Amit Arora3bc8c922010-11-16 11:27:38 +0530185
186 return 0;
187}
188
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200189static int read_clock_info(void)
Amit Aroraac4e8652010-11-09 11:16:53 +0530190{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200191 return tree_for_each(clock_tree, read_clock_cb, NULL);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200192}
193
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200194static int fill_clock_cb(struct tree *t, void *data)
195{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200196 struct clock_info *clk;
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200197
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200198 clk = clock_alloc();
199 if (!clk)
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200200 return -1;
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200201 t->private = clk;
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200202
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200203 /* we skip the root node but we set it expanded for its children */
204 if (!t->parent) {
205 clk->expanded = true;
206 return 0;
207 }
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200208
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200209 return read_clock_cb(t, data);
210}
211
212static int fill_clock_tree(void)
213{
214 return tree_for_each(clock_tree, fill_clock_cb, NULL);
215}
216
217static int is_collapsed(struct tree *t, void *data)
218{
219 struct clock_info *clk = t->private;
220
221 if (!clk->expanded)
222 return 1;
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200223
224 return 0;
225}
226
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200227static char *clock_line(struct tree *t)
Amit Aroraeb6cba92010-10-25 16:03:21 +0530228{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200229 struct clock_info *clk;
230 int rate;
231 const char *clkunit;
232 char *clkrate, *clkname, *clkline = NULL;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200233
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200234 clk = t->private;
235 rate = clk->rate;
236 clkunit = clock_rate(&rate);
237
238 if (asprintf(&clkname, "%*s%s", (t->depth - 1) * 2, "", t->name) < 0)
239 return NULL;
240
241 if (asprintf(&clkrate, "%d%s", rate, clkunit) < 0)
242 goto free_clkname;
243
244 if (asprintf(&clkline, "%-55s 0x%-16x %-12s %-9d %-8d", clkname,
245 clk->flags, clkrate, clk->usecount, t->nrchild) < 0)
246 goto free_clkrate;
247
248free_clkrate:
249 free(clkrate);
250free_clkname:
251 free(clkname);
252
253 return clkline;
254}
255
256static int clock_print_info_cb(struct tree *t, void *data)
257{
258 struct clock_info *clock = t->private;
259 int *line = data;
260 char *buffer;
261
262 /* we skip the root node of the tree */
263 if (!t->parent)
264 return 0;
265
266 /* show the clock when *all* its parent is expanded */
267 if (tree_for_each_parent(t->parent, is_collapsed, NULL))
268 return 0;
269
270 buffer = clock_line(t);
271 if (!buffer)
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200272 return -1;
273
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200274 display_print_line(CLOCK, *line, buffer, clock->usecount, t);
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200275
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200276 (*line)++;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200277
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200278 free(buffer);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200279
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200280 return 0;
281}
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200282
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200283static int clock_print_info(void)
284{
285 int ret, line = 0;
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200286
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200287 print_clock_header();
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200288
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200289 display_reset_cursor(CLOCK);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200290
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200291 ret = tree_for_each(clock_tree, clock_print_info_cb, &line);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200292
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200293 display_refresh_pad(CLOCK);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200294
295 return ret;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200296}
297
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200298int clock_toggle_expanded(void)
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200299{
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200300 struct tree *t = display_get_row_data(CLOCK);
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200301 struct clock_info *clk = t->private;
302
303 clk->expanded = !clk->expanded;
304
305 return 0;
306}
307
308/*
309 * Initialize the clock framework
310 */
311int clock_init(void)
312{
313 char clk_dir_path[PATH_MAX];
314
315 if (locate_debugfs(clk_dir_path))
316 return -1;
317
318 sprintf(clk_dir_path, "%s/clock", clk_dir_path);
319
320 if (access(clk_dir_path, F_OK))
321 return -1;
322
323 clock_tree = tree_load(clk_dir_path, NULL);
324 if (!clock_tree)
325 return -1;
326
327 return fill_clock_tree();
328}
329
330/*
331 * Read the clock information and fill the tree with the information
332 * found in the files. Then print the result to the text based interface
333 * Return 0 on success, < 0 otherwise
334 */
Daniel Lezcano597892a2011-06-15 15:45:12 +0200335int clock_display(void)
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200336{
337 if (read_clock_info())
338 return -1;
339
340 return clock_print_info();
341}
342
343/*
344 * Read the clock information and fill the tree with the information
345 * found in the files. Then dump to stdout a formatted result.
346 * @clk : a name for a specific clock we want to show
347 * Return 0 on success, < 0 otherwise
348 */
Daniel Lezcano597892a2011-06-15 15:45:12 +0200349int clock_dump(char *clk)
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200350{
351 int ret;
352
353 if (read_clock_info())
354 return -1;
Amit Aroraeb6cba92010-10-25 16:03:21 +0530355
Daniel Lezcanoc7891942011-06-08 23:30:00 +0200356 if (clk) {
357 printf("\nParents for \"%s\" Clock :\n\n", clk);
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200358 ret = dump_all_parents(clk);
Daniel Lezcanoc7891942011-06-08 23:30:00 +0200359 printf("\n\n");
360 } else {
361 printf("\nClock Tree :\n");
362 printf("**********\n");
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200363 ret = dump_clock_info();
Daniel Lezcanoc7891942011-06-08 23:30:00 +0200364 printf("\n\n");
365 }
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200366
367 return ret;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200368}