1 /*
2 * Copyright (c) 2021 IP-Logix Inc.
3 * Copyright 2023 NXP
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <zephyr/shell/shell.h>
9 #include <stdlib.h>
10 #include <zephyr/drivers/mdio.h>
11 #include <string.h>
12 #include <zephyr/sys/util.h>
13 #include <zephyr/devicetree.h>
14
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(mdio_shell, CONFIG_LOG_DEFAULT_LEVEL);
17
device_is_mdio(const struct device * dev)18 static bool device_is_mdio(const struct device *dev)
19 {
20 return DEVICE_API_IS(mdio, dev);
21 }
22
device_name_get(size_t idx,struct shell_static_entry * entry)23 static void device_name_get(size_t idx, struct shell_static_entry *entry)
24 {
25 const struct device *dev = shell_device_filter(idx, device_is_mdio);
26
27 entry->syntax = (dev != NULL) ? dev->name : NULL;
28 entry->handler = NULL;
29 entry->help = NULL;
30 entry->subcmd = NULL;
31 }
32
33 SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get);
34
parse_device_arg(const struct shell * sh,size_t argc,char ** argv,const struct device ** dev)35 static int parse_device_arg(const struct shell *sh, size_t argc,
36 char **argv, const struct device **dev)
37 {
38 if (argc < 2) {
39 shell_error(sh, "not enough arguments");
40 return -EINVAL;
41 }
42 *dev = shell_device_get_binding(argv[1]);
43 if (!*dev) {
44 shell_error(sh, "device %s not found", argv[1]);
45 return -ENODEV;
46 }
47 return 0;
48 }
49
50 /*
51 * Scan the entire 5-bit address space of the MDIO bus
52 *
53 * scan <device> [<reg_addr>]
54 */
cmd_mdio_scan(const struct shell * sh,size_t argc,char ** argv)55 static int cmd_mdio_scan(const struct shell *sh, size_t argc, char **argv)
56 {
57 const struct device *dev;
58 int cnt;
59 uint16_t data;
60 uint16_t reg_addr;
61 int ret;
62
63 ret = parse_device_arg(sh, argc, argv, &dev);
64 if (ret < 0) {
65 return ret;
66 }
67
68 if (argc >= 3) {
69 reg_addr = strtol(argv[2], NULL, 16);
70 } else {
71 reg_addr = 0;
72 }
73
74 shell_print(sh,
75 "Scanning bus for devices. Reading register 0x%x",
76 reg_addr);
77 cnt = 0;
78
79 for (int i = 0; i < 32; i++) {
80 data = 0;
81 if (mdio_read(dev, i, reg_addr, &data) >= 0 &&
82 data != UINT16_MAX) {
83 cnt++;
84 shell_print(sh, "Found MDIO device @ 0x%x", i);
85 }
86 }
87
88 shell_print(sh, "%u devices found on %s", cnt, dev->name);
89
90 return 0;
91 }
92
93 /* mdio write <device> <port_addr> <reg_addr> <data> */
cmd_mdio_write(const struct shell * sh,size_t argc,char ** argv)94 static int cmd_mdio_write(const struct shell *sh, size_t argc, char **argv)
95 {
96 const struct device *dev;
97 uint16_t data;
98 uint16_t reg_addr;
99 uint16_t port_addr;
100 int ret;
101
102 ret = parse_device_arg(sh, argc, argv, &dev);
103 if (ret < 0) {
104 return ret;
105 }
106
107 port_addr = strtol(argv[2], NULL, 16);
108 reg_addr = strtol(argv[3], NULL, 16);
109 data = strtol(argv[4], NULL, 16);
110
111 if (mdio_write(dev, port_addr, reg_addr, data) < 0) {
112 shell_error(sh, "Failed to write to device: %s", dev->name);
113
114 return -EIO;
115 }
116
117 return 0;
118 }
119
120 /* mdio read <device> <port_addr> <reg_addr> */
cmd_mdio_read(const struct shell * sh,size_t argc,char ** argv)121 static int cmd_mdio_read(const struct shell *sh, size_t argc, char **argv)
122 {
123 const struct device *dev;
124 uint16_t data;
125 uint16_t reg_addr;
126 uint16_t port_addr;
127 int ret;
128
129 ret = parse_device_arg(sh, argc, argv, &dev);
130 if (ret < 0) {
131 return ret;
132 }
133
134 port_addr = strtol(argv[2], NULL, 16);
135 reg_addr = strtol(argv[3], NULL, 16);
136
137 if (mdio_read(dev, port_addr, reg_addr, &data) < 0) {
138 shell_error(sh, "Failed to read from device: %s", dev->name);
139
140 return -EIO;
141 }
142
143 shell_print(sh, "%x[%x]: 0x%x", port_addr, reg_addr, data);
144
145 return 0;
146 }
147
148 /* mdio write_c45 <device> <port_addr> <dev_addr> <reg_addr> <value> */
cmd_mdio_write_45(const struct shell * sh,size_t argc,char ** argv)149 static int cmd_mdio_write_45(const struct shell *sh, size_t argc, char **argv)
150 {
151 const struct device *dev;
152 uint16_t data;
153 uint16_t reg_addr;
154 uint8_t dev_addr;
155 uint8_t port_addr;
156 int ret;
157
158 ret = parse_device_arg(sh, argc, argv, &dev);
159 if (ret < 0) {
160 return ret;
161 }
162
163 port_addr = strtol(argv[2], NULL, 16);
164 dev_addr = strtol(argv[3], NULL, 16);
165 reg_addr = strtol(argv[4], NULL, 16);
166 data = strtol(argv[5], NULL, 16);
167
168 if (mdio_write_c45(dev, port_addr, dev_addr, reg_addr, data) < 0) {
169 shell_error(sh, "Failed to write to device: %s", dev->name);
170
171 return -EIO;
172 }
173
174 return 0;
175 }
176
177 /* mdio read_c45 <device> <port_addr> <dev_addr> <reg_addr> */
cmd_mdio_read_c45(const struct shell * sh,size_t argc,char ** argv)178 static int cmd_mdio_read_c45(const struct shell *sh, size_t argc, char **argv)
179 {
180 const struct device *dev;
181 uint16_t data;
182 uint16_t reg_addr;
183 uint8_t dev_addr;
184 uint8_t port_addr;
185 int ret;
186
187 ret = parse_device_arg(sh, argc, argv, &dev);
188 if (ret < 0) {
189 return ret;
190 }
191
192 port_addr = strtol(argv[2], NULL, 16);
193 dev_addr = strtol(argv[3], NULL, 16);
194 reg_addr = strtol(argv[4], NULL, 16);
195
196 if (mdio_read_c45(dev, port_addr, dev_addr, reg_addr, &data) < 0) {
197 shell_error(sh, "Failed to read from device: %s", dev->name);
198
199 return -EIO;
200 }
201
202 shell_print(sh, "%x[%x:%x]: 0x%x", port_addr, dev_addr, reg_addr, data);
203
204 return 0;
205 }
206
207 SHELL_STATIC_SUBCMD_SET_CREATE(sub_mdio_cmds,
208 SHELL_CMD_ARG(scan, &dsub_device_name,
209 "Scan MDIO bus for devices: scan <device> [<reg_addr>]",
210 cmd_mdio_scan, 2, 1),
211 SHELL_CMD_ARG(read, &dsub_device_name,
212 "Read from MDIO device: read <device> <phy_addr> <reg_addr>",
213 cmd_mdio_read, 4, 0),
214 SHELL_CMD_ARG(write, &dsub_device_name,
215 "Write to MDIO device: write <device> <phy_addr> <reg_addr> <value>",
216 cmd_mdio_write, 5, 0),
217 SHELL_CMD_ARG(read_c45, &dsub_device_name,
218 "Read from MDIO Clause 45 device: "
219 "read_c45 <device> <port_addr> <dev_addr> <reg_addr>",
220 cmd_mdio_read_c45, 5, 0),
221 SHELL_CMD_ARG(write_c45, &dsub_device_name,
222 "Write to MDIO Clause 45 device: "
223 "write_c45 <device> <port_addr> <dev_addr> <reg_addr> <value>",
224 cmd_mdio_write_45, 6, 0),
225 SHELL_SUBCMD_SET_END /* Array terminated. */
226 );
227
228 SHELL_CMD_REGISTER(mdio, &sub_mdio_cmds, "MDIO commands", NULL);
229