1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * 4 * Driver interface derived from: 5 * /cmd/host.c 6 * Copyright (c) 2012, Google Inc. 7 * 8 * Copyright (C) 2023 Johan Jonker <jbx6244@gmail.com> 9 */ 10 11#include <common.h> 12#include <blk.h> 13#include <command.h> 14#include <dm.h> 15#include <rkmtd.h> 16#include <stdio.h> 17#include <dm/device-internal.h> 18#include <dm/uclass-internal.h> 19 20static int do_rkmtd_bind(struct cmd_tbl *cmdtp, int flag, int argc, 21 char *const argv[]) 22{ 23 struct udevice *dev; 24 const char *label; 25 int ret; 26 27 argc--; 28 argv++; 29 30 if (argc < 1) 31 return CMD_RET_USAGE; 32 33 if (argc > 1) 34 return CMD_RET_USAGE; 35 36 label = argv[0]; 37 ret = rkmtd_create_attach_mtd(label, &dev); 38 if (ret) { 39 printf("Cannot create device / bind mtd\n"); 40 return CMD_RET_FAILURE; 41 } 42 43 return 0; 44} 45 46static struct udevice *parse_rkmtd_label(const char *label) 47{ 48 struct udevice *dev; 49 50 dev = rkmtd_find_by_label(label); 51 if (!dev) { 52 int devnum; 53 char *ep; 54 55 devnum = hextoul(label, &ep); 56 if (*ep || 57 uclass_find_device_by_seq(UCLASS_RKMTD, devnum, &dev)) { 58 printf("No such device '%s'\n", label); 59 return NULL; 60 } 61 } 62 63 return dev; 64} 65 66static int do_rkmtd_unbind(struct cmd_tbl *cmdtp, int flag, int argc, 67 char *const argv[]) 68{ 69 struct udevice *dev; 70 const char *label; 71 int ret; 72 73 if (argc < 2) 74 return CMD_RET_USAGE; 75 76 label = argv[1]; 77 dev = parse_rkmtd_label(label); 78 if (!dev) 79 return CMD_RET_FAILURE; 80 81 ret = rkmtd_detach(dev); 82 if (ret) { 83 printf("Cannot detach mtd\n"); 84 return CMD_RET_FAILURE; 85 } 86 87 ret = device_unbind(dev); 88 if (ret) { 89 printf("Cannot unbind device '%s'\n", dev->name); 90 return CMD_RET_FAILURE; 91 } 92 93 return 0; 94} 95 96static void show_rkmtd_dev(struct udevice *dev) 97{ 98 struct rkmtd_dev *plat = dev_get_plat(dev); 99 struct blk_desc *desc; 100 struct udevice *blk; 101 int ret; 102 103 printf("%3d ", dev_seq(dev)); 104 105 ret = blk_get_from_parent(dev, &blk); 106 if (ret) 107 return; 108 109 desc = dev_get_uclass_plat(blk); 110 printf("%12lu %-15s\n", (unsigned long)desc->lba, plat->label); 111} 112 113static int do_rkmtd_info(struct cmd_tbl *cmdtp, int flag, int argc, 114 char *const argv[]) 115{ 116 struct udevice *dev; 117 118 if (argc < 1) 119 return CMD_RET_USAGE; 120 121 dev = NULL; 122 if (argc >= 2) { 123 dev = parse_rkmtd_label(argv[1]); 124 if (!dev) 125 return CMD_RET_FAILURE; 126 } 127 128 printf("%3s %12s %-15s\n", "dev", "blocks", "label"); 129 if (dev) { 130 show_rkmtd_dev(dev); 131 } else { 132 struct uclass *uc; 133 134 uclass_id_foreach_dev(UCLASS_RKMTD, dev, uc) 135 show_rkmtd_dev(dev); 136 } 137 138 return 0; 139} 140 141static int do_rkmtd_dev(struct cmd_tbl *cmdtp, int flag, int argc, 142 char *const argv[]) 143{ 144 struct udevice *dev; 145 const char *label; 146 147 if (argc < 1 || argc > 3) 148 return CMD_RET_USAGE; 149 150 if (argc == 1) { 151 struct rkmtd_dev *plat; 152 153 dev = rkmtd_get_cur_dev(); 154 if (!dev) { 155 printf("No current rkmtd device\n"); 156 return CMD_RET_FAILURE; 157 } 158 plat = dev_get_plat(dev); 159 printf("Current rkmtd device: %d: %s\n", dev_seq(dev), 160 plat->label); 161 return 0; 162 } 163 164 label = argv[1]; 165 dev = parse_rkmtd_label(argv[1]); 166 if (!dev) 167 return CMD_RET_FAILURE; 168 169 rkmtd_set_cur_dev(dev); 170 171 return 0; 172} 173 174static struct cmd_tbl cmd_rkmtd_sub[] = { 175 U_BOOT_CMD_MKENT(bind, 4, 0, do_rkmtd_bind, "", ""), 176 U_BOOT_CMD_MKENT(unbind, 4, 0, do_rkmtd_unbind, "", ""), 177 U_BOOT_CMD_MKENT(info, 3, 0, do_rkmtd_info, "", ""), 178 U_BOOT_CMD_MKENT(dev, 0, 1, do_rkmtd_dev, "", ""), 179}; 180 181static int do_rkmtd(struct cmd_tbl *cmdtp, int flag, int argc, 182 char *const argv[]) 183{ 184 struct cmd_tbl *c; 185 186 argc--; 187 argv++; 188 189 c = find_cmd_tbl(argv[0], cmd_rkmtd_sub, ARRAY_SIZE(cmd_rkmtd_sub)); 190 191 if (c) 192 return c->cmd(cmdtp, flag, argc, argv); 193 else 194 return CMD_RET_USAGE; 195} 196 197U_BOOT_CMD( 198 rkmtd, 8, 1, do_rkmtd, 199 "Rockchip MTD sub-system", 200 "bind <label> - bind RKMTD device\n" 201 "rkmtd unbind <label> - unbind RKMTD device\n" 202 "rkmtd info [<label>] - show all available RKMTD devices\n" 203 "rkmtd dev [<label>] - show or set current RKMTD device\n" 204); 205