1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2020 Wind River Systems, Inc.
4  *
5  * Author:
6  *   Bin Meng <bin.meng@windriver.com>
7  *
8  * A command interface to access misc devices with MISC uclass driver APIs.
9  */
10 
11 #include <common.h>
12 #include <command.h>
13 #include <dm.h>
14 #include <errno.h>
15 #include <misc.h>
16 
17 enum misc_op {
18 	MISC_OP_READ,
19 	MISC_OP_WRITE
20 };
21 
22 static char *misc_op_str[] = {
23 	"read",
24 	"write"
25 };
26 
do_misc_list(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])27 static int do_misc_list(struct cmd_tbl *cmdtp, int flag,
28 			int argc, char *const argv[])
29 {
30 	struct udevice *dev;
31 
32 	printf("Device               Index     Driver\n");
33 	printf("-------------------------------------\n");
34 	for (uclass_first_device(UCLASS_MISC, &dev);
35 	     dev;
36 	     uclass_next_device(&dev)) {
37 		printf("%-20s %5d %10s\n", dev->name, dev_seq(dev),
38 		       dev->driver->name);
39 	}
40 
41 	return 0;
42 }
43 
do_misc_op(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[],enum misc_op op)44 static int do_misc_op(struct cmd_tbl *cmdtp, int flag,
45 		      int argc, char *const argv[], enum misc_op op)
46 {
47 	struct udevice *dev;
48 	int offset;
49 	void *buf;
50 	int size;
51 	int ret;
52 
53 	ret = uclass_get_device_by_name(UCLASS_MISC, argv[0], &dev);
54 	if (ret) {
55 		printf("Unable to find device %s\n", argv[0]);
56 		return ret;
57 	}
58 
59 	offset = hextoul(argv[1], NULL);
60 	buf = (void *)hextoul(argv[2], NULL);
61 	size = hextoul(argv[3], NULL);
62 
63 	if (op == MISC_OP_READ)
64 		ret = misc_read(dev, offset, buf, size);
65 	else
66 		ret = misc_write(dev, offset, buf, size);
67 
68 	if (ret < 0) {
69 		if (ret == -ENOSYS) {
70 			printf("The device does not support %s\n",
71 			       misc_op_str[op]);
72 			ret = 0;
73 		}
74 	} else {
75 		if (ret == size)
76 			ret = 0;
77 		else
78 			printf("Partially %s %d bytes\n", misc_op_str[op], ret);
79 	}
80 
81 	return ret;
82 }
83 
do_misc_read(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])84 static int do_misc_read(struct cmd_tbl *cmdtp, int flag,
85 			int argc, char *const argv[])
86 {
87 	return do_misc_op(cmdtp, flag, argc, argv, MISC_OP_READ);
88 }
89 
do_misc_write(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])90 static int do_misc_write(struct cmd_tbl *cmdtp, int flag,
91 			 int argc, char *const argv[])
92 {
93 	return do_misc_op(cmdtp, flag, argc, argv, MISC_OP_WRITE);
94 }
95 
96 static struct cmd_tbl misc_commands[] = {
97 	U_BOOT_CMD_MKENT(list, 0, 1, do_misc_list, "", ""),
98 	U_BOOT_CMD_MKENT(read, 4, 1, do_misc_read, "", ""),
99 	U_BOOT_CMD_MKENT(write, 4, 1, do_misc_write, "", ""),
100 };
101 
do_misc(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])102 static int do_misc(struct cmd_tbl *cmdtp, int flag,
103 		   int argc, char *const argv[])
104 {
105 	struct cmd_tbl *misc_cmd;
106 	int ret;
107 
108 	if (argc < 2)
109 		return CMD_RET_USAGE;
110 	misc_cmd = find_cmd_tbl(argv[1], misc_commands,
111 				ARRAY_SIZE(misc_commands));
112 	argc -= 2;
113 	argv += 2;
114 	if (!misc_cmd || argc != misc_cmd->maxargs)
115 		return CMD_RET_USAGE;
116 
117 	ret = misc_cmd->cmd(misc_cmd, flag, argc, argv);
118 
119 	return cmd_process_error(misc_cmd, ret);
120 }
121 
122 U_BOOT_CMD(
123 	misc,	6,	1,	do_misc,
124 	"Access miscellaneous devices with MISC uclass driver APIs",
125 	"list                       - list all miscellaneous devices\n"
126 	"misc read  name offset addr len - read `len' bytes starting at\n"
127 	"				  `offset' of device `name'\n"
128 	"				  to memory at `addr'\n"
129 	"misc write name offset addr len - write `len' bytes starting at\n"
130 	"				  `offset' of device `name'\n"
131 	"				  from memory at `addr'"
132 );
133