blob: 86ae948592ed16b6aed67cffc04a6a92e68a3820 [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"
Daniel Lezcanob301b082011-06-15 15:45:12 +020029#include "display.h"
Amit Aroraed3e5652010-10-27 12:02:53 +053030#include "clocks.h"
Daniel Lezcanoc193b602011-06-08 23:30:00 +020031#include "tree.h"
Daniel Lezcano88b38e32011-06-15 15:45:12 +020032#include "utils.h"
Amit Arora24ed7d12010-09-14 12:12:58 +053033
Daniel Lezcanoc45662b2011-06-08 23:30:00 +020034struct clock_info {
Daniel Lezcanoc45662b2011-06-08 23:30:00 +020035 int flags;
36 int rate;
37 int usecount;
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020038 bool expanded;
Daniel Lezcano9d5431c2011-06-08 23:30:00 +020039 char *prefix;
Daniel Lezcanoc45662b2011-06-08 23:30:00 +020040} *clocks_info;
41
Daniel Lezcano9d5431c2011-06-08 23:30:00 +020042static struct tree *clock_tree = NULL;
Daniel Lezcanoc193b602011-06-08 23:30:00 +020043
Daniel Lezcano9dc3fb32011-03-26 22:06:08 +010044static int locate_debugfs(char *clk_path)
45{
46 const char *mtab = "/proc/mounts";
47 struct mntent *mntent;
48 int ret = -1;
49 FILE *file = NULL;
50
51 file = setmntent(mtab, "r");
52 if (!file)
53 return -1;
54
55 while ((mntent = getmntent(file))) {
56
57 if (strcmp(mntent->mnt_type, "debugfs"))
58 continue;
59
60 strcpy(clk_path, mntent->mnt_dir);
61 ret = 0;
62 break;
63 }
64
65 fclose(file);
66 return ret;
67}
68
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020069static struct clock_info *clock_alloc(void)
Amit Arora24ed7d12010-09-14 12:12:58 +053070{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020071 struct clock_info *ci;
Daniel Lezcano9dc3fb32011-03-26 22:06:08 +010072
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020073 ci = malloc(sizeof(*ci));
74 if (ci)
75 memset(ci, 0, sizeof(*ci));
Daniel Lezcanoc5a65bf2011-03-26 22:06:11 +010076
Daniel Lezcano2adc48d2011-06-08 23:30:01 +020077 return ci;
Amit Arora24ed7d12010-09-14 12:12:58 +053078}
Amit Arora728e0c92010-09-14 12:06:09 +053079
Daniel Lezcanoafe62252011-06-08 23:30:00 +020080static inline const char *clock_rate(int *rate)
Daniel Lezcanoc6718332011-03-23 14:37:39 +010081{
Daniel Lezcanoafe62252011-06-08 23:30:00 +020082 int r;
Daniel Lezcanoc6718332011-03-23 14:37:39 +010083
Daniel Lezcanoafe62252011-06-08 23:30:00 +020084 /* GHZ */
85 r = *rate >> 30;
86 if (r) {
87 *rate = r;
88 return "GHZ";
89 }
Daniel Lezcanoc6718332011-03-23 14:37:39 +010090
Daniel Lezcanoafe62252011-06-08 23:30:00 +020091 /* MHZ */
92 r = *rate >> 20;
93 if (r) {
94 *rate = r;
95 return "MHZ";
96 }
Daniel Lezcanoc6718332011-03-23 14:37:39 +010097
Daniel Lezcanoafe62252011-06-08 23:30:00 +020098 /* KHZ */
99 r = *rate >> 10;
100 if (r) {
101 *rate = r;
102 return "KHZ";
103 }
104
105 return "";
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100106}
107
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200108static int dump_clock_cb(struct tree *t, void *data)
Daniel Lezcanoef323192011-03-26 22:06:20 +0100109{
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200110 struct clock_info *clk = t->private;
111 struct clock_info *pclk;
112 const char *unit;
113 int ret = 0;
114 int rate = clk->rate;
Daniel Lezcanoef323192011-03-26 22:06:20 +0100115
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200116 if (!t->parent) {
117 printf("/\n");
118 clk->prefix = "";
119 return 0;
Daniel Lezcanoef323192011-03-26 22:06:20 +0100120 }
121
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200122 pclk = t->parent->private;
123
124 if (!clk->prefix)
125 ret = asprintf(&clk->prefix, "%s%s%s", pclk->prefix,
126 t->depth > 1 ? " ": "", t->next ? "|" : " ");
127 if (ret < 0)
128 return -1;
129
130 unit = clock_rate(&rate);
131
132 printf("%s%s-- %s (flags:0x%x, usecount:%d, rate: %d %s)\n",
133 clk->prefix, !t->next ? "`" : "", t->name, clk->flags,
134 clk->usecount, rate, unit);
135
136 return 0;
Daniel Lezcanoef323192011-03-26 22:06:20 +0100137}
138
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200139int dump_clock_info(void)
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100140{
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200141 return tree_for_each(clock_tree, dump_clock_cb, NULL);
142}
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100143
Daniel Lezcano3e38e0f2011-06-08 23:30:00 +0200144static int dump_all_parents(char *clkarg)
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200145{
146 struct tree *tree;
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100147
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200148 tree = tree_find(clock_tree, clkarg);
149 if (!tree) {
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100150 printf("Clock NOT found!\n");
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200151 return -1;
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100152 }
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200153
154 return tree_for_each_parent(tree, dump_clock_cb, NULL);
Daniel Lezcanoc6718332011-03-23 14:37:39 +0100155}
156
Daniel Lezcano897f7332011-03-26 22:06:06 +0100157void find_parents_for_clock(char *clkname, int complete)
Amit Arora3bd79162010-12-01 13:51:42 +0530158{
159 char name[256];
160
161 name[0] = '\0';
162 if (!complete) {
163 char str[256];
164
165 strcat(name, clkname);
166 sprintf(str, "Enter Clock Name : %s\n", name);
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200167 display_reset_cursor(CLOCK);
168 display_print_line(CLOCK, 0, str, 1, NULL);
169 display_refresh_pad(CLOCK);
Amit Arora3bd79162010-12-01 13:51:42 +0530170 return;
171 }
172 sprintf(name, "Parents for \"%s\" Clock : \n", clkname);
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200173 display_reset_cursor(CLOCK);
174 display_print_line(CLOCK, 0, name, 1, NULL);
175 display_refresh_pad(CLOCK);
Daniel Lezcano3e38e0f2011-06-08 23:30:00 +0200176 dump_all_parents(clkname);
Amit Kucheriaa0adae42011-01-12 10:54:23 -0600177}
Amit Arora3bd79162010-12-01 13:51:42 +0530178
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200179static inline int read_clock_cb(struct tree *t, void *data)
Daniel Lezcanoef323192011-03-26 22:06:20 +0100180{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200181 struct clock_info *clk = t->private;
Daniel Lezcanoef323192011-03-26 22:06:20 +0100182
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200183 file_read_value(t->path, "flags", "%x", &clk->flags);
184 file_read_value(t->path, "rate", "%d", &clk->rate);
185 file_read_value(t->path, "usecount", "%d", &clk->usecount);
Amit Arora3bc8c922010-11-16 11:27:38 +0530186
187 return 0;
188}
189
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200190static int read_clock_info(void)
Amit Aroraac4e8652010-11-09 11:16:53 +0530191{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200192 return tree_for_each(clock_tree, read_clock_cb, NULL);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200193}
194
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200195static int fill_clock_cb(struct tree *t, void *data)
196{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200197 struct clock_info *clk;
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200198
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200199 clk = clock_alloc();
200 if (!clk)
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200201 return -1;
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200202 t->private = clk;
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200203
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200204 /* we skip the root node but we set it expanded for its children */
205 if (!t->parent) {
206 clk->expanded = true;
207 return 0;
208 }
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200209
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200210 return read_clock_cb(t, data);
211}
212
213static int fill_clock_tree(void)
214{
215 return tree_for_each(clock_tree, fill_clock_cb, NULL);
216}
217
218static int is_collapsed(struct tree *t, void *data)
219{
220 struct clock_info *clk = t->private;
221
222 if (!clk->expanded)
223 return 1;
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200224
225 return 0;
226}
227
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200228static char *clock_line(struct tree *t)
Amit Aroraeb6cba92010-10-25 16:03:21 +0530229{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200230 struct clock_info *clk;
231 int rate;
232 const char *clkunit;
233 char *clkrate, *clkname, *clkline = NULL;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200234
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200235 clk = t->private;
236 rate = clk->rate;
237 clkunit = clock_rate(&rate);
238
239 if (asprintf(&clkname, "%*s%s", (t->depth - 1) * 2, "", t->name) < 0)
240 return NULL;
241
242 if (asprintf(&clkrate, "%d%s", rate, clkunit) < 0)
243 goto free_clkname;
244
245 if (asprintf(&clkline, "%-55s 0x%-16x %-12s %-9d %-8d", clkname,
246 clk->flags, clkrate, clk->usecount, t->nrchild) < 0)
247 goto free_clkrate;
248
249free_clkrate:
250 free(clkrate);
251free_clkname:
252 free(clkname);
253
254 return clkline;
255}
256
257static int clock_print_info_cb(struct tree *t, void *data)
258{
259 struct clock_info *clock = t->private;
260 int *line = data;
261 char *buffer;
262
263 /* we skip the root node of the tree */
264 if (!t->parent)
265 return 0;
266
267 /* show the clock when *all* its parent is expanded */
268 if (tree_for_each_parent(t->parent, is_collapsed, NULL))
269 return 0;
270
271 buffer = clock_line(t);
272 if (!buffer)
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200273 return -1;
274
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200275 display_print_line(CLOCK, *line, buffer, clock->usecount, t);
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200276
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200277 (*line)++;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200278
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200279 free(buffer);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200280
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200281 return 0;
282}
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200283
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200284static int clock_print_info(void)
285{
286 int ret, line = 0;
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200287
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200288 print_clock_header();
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200289
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200290 display_reset_cursor(CLOCK);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200291
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200292 ret = tree_for_each(clock_tree, clock_print_info_cb, &line);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200293
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200294 display_refresh_pad(CLOCK);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200295
296 return ret;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200297}
298
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200299int clock_toggle_expanded(void)
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200300{
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200301 struct tree *t = display_get_row_data(CLOCK);
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200302 struct clock_info *clk = t->private;
303
304 clk->expanded = !clk->expanded;
305
306 return 0;
307}
308
309/*
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200310 * Read the clock information and fill the tree with the information
311 * found in the files. Then print the result to the text based interface
312 * Return 0 on success, < 0 otherwise
313 */
Daniel Lezcano597892a2011-06-15 15:45:12 +0200314int clock_display(void)
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200315{
316 if (read_clock_info())
317 return -1;
318
319 return clock_print_info();
320}
321
322/*
323 * Read the clock information and fill the tree with the information
324 * found in the files. Then dump to stdout a formatted result.
325 * @clk : a name for a specific clock we want to show
326 * Return 0 on success, < 0 otherwise
327 */
Daniel Lezcano597892a2011-06-15 15:45:12 +0200328int clock_dump(char *clk)
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200329{
330 int ret;
331
332 if (read_clock_info())
333 return -1;
Amit Aroraeb6cba92010-10-25 16:03:21 +0530334
Daniel Lezcanoc7891942011-06-08 23:30:00 +0200335 if (clk) {
336 printf("\nParents for \"%s\" Clock :\n\n", clk);
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200337 ret = dump_all_parents(clk);
Daniel Lezcanoc7891942011-06-08 23:30:00 +0200338 printf("\n\n");
339 } else {
340 printf("\nClock Tree :\n");
341 printf("**********\n");
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200342 ret = dump_clock_info();
Daniel Lezcanoc7891942011-06-08 23:30:00 +0200343 printf("\n\n");
344 }
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200345
346 return ret;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200347}
Daniel Lezcanob301b082011-06-15 15:45:12 +0200348
349static struct display_ops clock_ops = {
350 .display = clock_display,
351 .select = clock_toggle_expanded,
352};
353
354/*
355 * Initialize the clock framework
356 */
357int clock_init(void)
358{
359 char clk_dir_path[PATH_MAX];
360
361 if (display_register(CLOCK, &clock_ops))
362 return -1;
363
364 if (locate_debugfs(clk_dir_path))
365 return -1;
366
367 sprintf(clk_dir_path, "%s/clock", clk_dir_path);
368
369 if (access(clk_dir_path, F_OK))
370 return -1;
371
372 clock_tree = tree_load(clk_dir_path, NULL);
373 if (!clock_tree)
374 return -1;
375
376 return fill_clock_tree();
377}