blob: 684bf8831cba366969ac045f75a8aa535e91ce76 [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 Lezcano897f7332011-03-26 22:06:06 +0100162void find_parents_for_clock(char *clkname, int complete)
Amit Arora3bd79162010-12-01 13:51:42 +0530163{
164 char name[256];
165
166 name[0] = '\0';
167 if (!complete) {
168 char str[256];
169
170 strcat(name, clkname);
171 sprintf(str, "Enter Clock Name : %s\n", name);
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200172 display_reset_cursor(CLOCK);
173 display_print_line(CLOCK, 0, str, 1, NULL);
174 display_refresh_pad(CLOCK);
Amit Arora3bd79162010-12-01 13:51:42 +0530175 return;
176 }
177 sprintf(name, "Parents for \"%s\" Clock : \n", clkname);
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200178 display_reset_cursor(CLOCK);
179 display_print_line(CLOCK, 0, name, 1, NULL);
180 display_refresh_pad(CLOCK);
Daniel Lezcano3e38e0f2011-06-08 23:30:00 +0200181 dump_all_parents(clkname);
Amit Kucheriaa0adae42011-01-12 10:54:23 -0600182}
Amit Arora3bd79162010-12-01 13:51:42 +0530183
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200184static inline int read_clock_cb(struct tree *t, void *data)
Daniel Lezcanoef323192011-03-26 22:06:20 +0100185{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200186 struct clock_info *clk = t->private;
Daniel Lezcanoef323192011-03-26 22:06:20 +0100187
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200188 file_read_value(t->path, "flags", "%x", &clk->flags);
189 file_read_value(t->path, "rate", "%d", &clk->rate);
190 file_read_value(t->path, "usecount", "%d", &clk->usecount);
Amit Arora3bc8c922010-11-16 11:27:38 +0530191
192 return 0;
193}
194
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200195static int read_clock_info(void)
Amit Aroraac4e8652010-11-09 11:16:53 +0530196{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200197 return tree_for_each(clock_tree, read_clock_cb, NULL);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200198}
199
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200200static int fill_clock_cb(struct tree *t, void *data)
201{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200202 struct clock_info *clk;
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200203
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200204 clk = clock_alloc();
205 if (!clk)
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200206 return -1;
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200207 t->private = clk;
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200208
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200209 /* we skip the root node but we set it expanded for its children */
210 if (!t->parent) {
211 clk->expanded = true;
212 return 0;
213 }
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200214
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200215 return read_clock_cb(t, data);
216}
217
218static int fill_clock_tree(void)
219{
220 return tree_for_each(clock_tree, fill_clock_cb, NULL);
221}
222
223static int is_collapsed(struct tree *t, void *data)
224{
225 struct clock_info *clk = t->private;
226
227 if (!clk->expanded)
228 return 1;
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200229
230 return 0;
231}
232
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200233static char *clock_line(struct tree *t)
Amit Aroraeb6cba92010-10-25 16:03:21 +0530234{
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200235 struct clock_info *clk;
236 int rate;
237 const char *clkunit;
238 char *clkrate, *clkname, *clkline = NULL;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200239
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200240 clk = t->private;
241 rate = clk->rate;
242 clkunit = clock_rate(&rate);
243
244 if (asprintf(&clkname, "%*s%s", (t->depth - 1) * 2, "", t->name) < 0)
245 return NULL;
246
247 if (asprintf(&clkrate, "%d%s", rate, clkunit) < 0)
248 goto free_clkname;
249
250 if (asprintf(&clkline, "%-55s 0x%-16x %-12s %-9d %-8d", clkname,
251 clk->flags, clkrate, clk->usecount, t->nrchild) < 0)
252 goto free_clkrate;
253
254free_clkrate:
255 free(clkrate);
256free_clkname:
257 free(clkname);
258
259 return clkline;
260}
261
262static int clock_print_info_cb(struct tree *t, void *data)
263{
264 struct clock_info *clock = t->private;
265 int *line = data;
266 char *buffer;
267
268 /* we skip the root node of the tree */
269 if (!t->parent)
270 return 0;
271
272 /* show the clock when *all* its parent is expanded */
273 if (tree_for_each_parent(t->parent, is_collapsed, NULL))
274 return 0;
275
276 buffer = clock_line(t);
277 if (!buffer)
Daniel Lezcano9d5431c2011-06-08 23:30:00 +0200278 return -1;
279
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200280 display_print_line(CLOCK, *line, buffer, clock->usecount, t);
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200281
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200282 (*line)++;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200283
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200284 free(buffer);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200285
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200286 return 0;
287}
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200288
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200289static int clock_print_info(void)
290{
291 int ret, line = 0;
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200292
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200293 print_clock_header();
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200294
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200295 display_reset_cursor(CLOCK);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200296
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200297 ret = tree_for_each(clock_tree, clock_print_info_cb, &line);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200298
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200299 display_refresh_pad(CLOCK);
Daniel Lezcanob2565a82011-06-08 23:30:00 +0200300
301 return ret;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200302}
303
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200304int clock_toggle_expanded(void)
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200305{
Daniel Lezcanob3e6e812011-06-15 15:45:12 +0200306 struct tree *t = display_get_row_data(CLOCK);
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200307 struct clock_info *clk = t->private;
308
309 clk->expanded = !clk->expanded;
310
311 return 0;
312}
313
314/*
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200315 * Read the clock information and fill the tree with the information
316 * found in the files. Then print the result to the text based interface
317 * Return 0 on success, < 0 otherwise
318 */
Daniel Lezcano597892a2011-06-15 15:45:12 +0200319int clock_display(void)
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200320{
321 if (read_clock_info())
322 return -1;
323
324 return clock_print_info();
325}
326
327/*
328 * Read the clock information and fill the tree with the information
329 * found in the files. Then dump to stdout a formatted result.
330 * @clk : a name for a specific clock we want to show
331 * Return 0 on success, < 0 otherwise
332 */
Daniel Lezcano597892a2011-06-15 15:45:12 +0200333int clock_dump(char *clk)
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200334{
335 int ret;
336
337 if (read_clock_info())
338 return -1;
Amit Aroraeb6cba92010-10-25 16:03:21 +0530339
Daniel Lezcanoc7891942011-06-08 23:30:00 +0200340 if (clk) {
341 printf("\nParents for \"%s\" Clock :\n\n", clk);
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200342 ret = dump_all_parents(clk);
Daniel Lezcanoc7891942011-06-08 23:30:00 +0200343 printf("\n\n");
344 } else {
345 printf("\nClock Tree :\n");
346 printf("**********\n");
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200347 ret = dump_clock_info();
Daniel Lezcanoc7891942011-06-08 23:30:00 +0200348 printf("\n\n");
349 }
Daniel Lezcano2adc48d2011-06-08 23:30:01 +0200350
351 return ret;
Daniel Lezcano28b53cd2011-06-08 23:30:00 +0200352}
Daniel Lezcanob301b082011-06-15 15:45:12 +0200353
354static struct display_ops clock_ops = {
355 .display = clock_display,
356 .select = clock_toggle_expanded,
357};
358
359/*
360 * Initialize the clock framework
361 */
362int clock_init(void)
363{
364 char clk_dir_path[PATH_MAX];
365
366 if (display_register(CLOCK, &clock_ops))
367 return -1;
368
369 if (locate_debugfs(clk_dir_path))
370 return -1;
371
372 sprintf(clk_dir_path, "%s/clock", clk_dir_path);
373
374 if (access(clk_dir_path, F_OK))
375 return -1;
376
377 clock_tree = tree_load(clk_dir_path, NULL);
378 if (!clock_tree)
379 return -1;
380
381 return fill_clock_tree();
382}