1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2013 Xilinx, Inc. 4 */ 5#include <common.h> 6#include <command.h> 7#include <clk.h> 8#if defined(CONFIG_DM) && defined(CONFIG_CLK) 9#include <dm.h> 10#include <dm/device.h> 11#include <dm/root.h> 12#include <dm/device-internal.h> 13#include <linux/clk-provider.h> 14#endif 15 16#if defined(CONFIG_DM) && defined(CONFIG_CLK) 17static void show_clks(struct udevice *dev, int depth, int last_flag) 18{ 19 int i, is_last; 20 struct udevice *child; 21 struct clk *clkp, *parent; 22 u32 rate; 23 24 clkp = dev_get_clk_ptr(dev); 25 if (clkp) { 26 parent = clk_get_parent(clkp); 27 if (!IS_ERR(parent) && depth == -1) 28 return; 29 depth++; 30 rate = clk_get_rate(clkp); 31 32 printf(" %-12u %8d ", rate, clkp->enable_count); 33 34 for (i = depth; i >= 0; i--) { 35 is_last = (last_flag >> i) & 1; 36 if (i) { 37 if (is_last) 38 printf(" "); 39 else 40 printf("| "); 41 } else { 42 if (is_last) 43 printf("`-- "); 44 else 45 printf("|-- "); 46 } 47 } 48 49 printf("%s\n", dev->name); 50 } 51 52 device_foreach_child_probe(child, dev) { 53 if (device_get_uclass_id(child) != UCLASS_CLK) 54 continue; 55 if (child == dev) 56 continue; 57 is_last = list_is_last(&child->sibling_node, &dev->child_head); 58 show_clks(child, depth, (last_flag << 1) | is_last); 59 } 60} 61 62static int soc_clk_dump(void) 63{ 64 struct udevice *dev; 65 const struct clk_ops *ops; 66 67 printf(" Rate Usecnt Name\n"); 68 printf("------------------------------------------\n"); 69 70 uclass_foreach_dev_probe(UCLASS_CLK, dev) 71 show_clks(dev, -1, 0); 72 73 uclass_foreach_dev_probe(UCLASS_CLK, dev) { 74 ops = dev_get_driver_ops(dev); 75 if (ops && ops->dump) { 76 printf("\n%s %s:\n", dev->driver->name, dev->name); 77 ops->dump(dev); 78 } 79 } 80 81 return 0; 82} 83#else 84static int soc_clk_dump(void) 85{ 86 puts("Not implemented\n"); 87 return 1; 88} 89#endif 90 91static int do_clk_dump(struct cmd_tbl *cmdtp, int flag, int argc, 92 char *const argv[]) 93{ 94 int ret; 95 96 ret = soc_clk_dump(); 97 if (ret < 0) { 98 printf("Clock dump error %d\n", ret); 99 ret = CMD_RET_FAILURE; 100 } 101 102 return ret; 103} 104 105#if CONFIG_IS_ENABLED(DM) && CONFIG_IS_ENABLED(CLK) 106static int do_clk_setfreq(struct cmd_tbl *cmdtp, int flag, int argc, 107 char *const argv[]) 108{ 109 struct clk *clk = NULL; 110 s32 freq; 111 struct udevice *dev; 112 113 if (argc != 3) 114 return CMD_RET_USAGE; 115 116 freq = dectoul(argv[2], NULL); 117 118 if (!uclass_get_device_by_name(UCLASS_CLK, argv[1], &dev)) 119 clk = dev_get_clk_ptr(dev); 120 121 if (!clk) { 122 printf("clock '%s' not found.\n", argv[1]); 123 return CMD_RET_FAILURE; 124 } 125 126 freq = clk_set_rate(clk, freq); 127 if (freq < 0) { 128 printf("set_rate failed: %d\n", freq); 129 return CMD_RET_FAILURE; 130 } 131 132 printf("set_rate returns %u\n", freq); 133 return 0; 134} 135#endif 136 137static struct cmd_tbl cmd_clk_sub[] = { 138 U_BOOT_CMD_MKENT(dump, 1, 1, do_clk_dump, "", ""), 139#if CONFIG_IS_ENABLED(DM) && CONFIG_IS_ENABLED(CLK) 140 U_BOOT_CMD_MKENT(setfreq, 3, 1, do_clk_setfreq, "", ""), 141#endif 142}; 143 144static int do_clk(struct cmd_tbl *cmdtp, int flag, int argc, 145 char *const argv[]) 146{ 147 struct cmd_tbl *c; 148 149 if (argc < 2) 150 return CMD_RET_USAGE; 151 152 /* Strip off leading 'clk' command argument */ 153 argc--; 154 argv++; 155 156 c = find_cmd_tbl(argv[0], &cmd_clk_sub[0], ARRAY_SIZE(cmd_clk_sub)); 157 158 if (c) 159 return c->cmd(cmdtp, flag, argc, argv); 160 else 161 return CMD_RET_USAGE; 162} 163 164U_BOOT_LONGHELP(clk, 165 "dump - Print clock frequencies\n" 166 "clk setfreq [clk] [freq] - Set clock frequency"); 167 168U_BOOT_CMD(clk, 4, 1, do_clk, "CLK sub-system", clk_help_text); 169