1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2015 4 * Texas Instruments Incorporated - http://www.ti.com/ 5 */ 6 #define pr_fmt(fmt) "%s: " fmt, __func__ 7 #include <common.h> 8 #include <errno.h> 9 #include <fdtdec.h> 10 #include <malloc.h> 11 #include <remoteproc.h> 12 #include <asm/io.h> 13 #include <dm/device-internal.h> 14 #include <dm.h> 15 #include <dm/uclass.h> 16 #include <dm/uclass-internal.h> 17 18 DECLARE_GLOBAL_DATA_PTR; 19 20 /** 21 * for_each_remoteproc_device() - iterate through the list of rproc devices 22 * @fn: check function to call per match, if this function returns fail, 23 * iteration is aborted with the resultant error value 24 * @skip_dev: Device to skip calling the callback about. 25 * @data: Data to pass to the callback function 26 * 27 * Return: 0 if none of the callback returned a non 0 result, else returns the 28 * result from the callback function 29 */ 30 static int for_each_remoteproc_device(int (*fn) (struct udevice *dev, 31 struct dm_rproc_uclass_pdata *uc_pdata, 32 const void *data), 33 struct udevice *skip_dev, 34 const void *data) 35 { 36 struct udevice *dev; 37 struct dm_rproc_uclass_pdata *uc_pdata; 38 int ret; 39 40 for (ret = uclass_find_first_device(UCLASS_REMOTEPROC, &dev); dev; 41 ret = uclass_find_next_device(&dev)) { 42 if (ret || dev == skip_dev) 43 continue; 44 uc_pdata = dev_get_uclass_platdata(dev); 45 ret = fn(dev, uc_pdata, data); 46 if (ret) 47 return ret; 48 } 49 50 return 0; 51 } 52 53 /** 54 * _rproc_name_is_unique() - iteration helper to check if rproc name is unique 55 * @dev: device that we are checking name for 56 * @uc_pdata: uclass platform data 57 * @data: compare data (this is the name we want to ensure is unique) 58 * 59 * Return: 0 is there is no match(is unique); if there is a match(we dont 60 * have a unique name), return -EINVAL. 61 */ 62 static int _rproc_name_is_unique(struct udevice *dev, 63 struct dm_rproc_uclass_pdata *uc_pdata, 64 const void *data) 65 { 66 const char *check_name = data; 67 68 /* devices not yet populated with data - so skip them */ 69 if (!uc_pdata->name || !check_name) 70 return 0; 71 72 /* Return 0 to search further if we dont match */ 73 if (strlen(uc_pdata->name) != strlen(check_name)) 74 return 0; 75 76 if (!strcmp(uc_pdata->name, check_name)) 77 return -EINVAL; 78 79 return 0; 80 } 81 82 /** 83 * rproc_name_is_unique() - Check if the rproc name is unique 84 * @check_dev: Device we are attempting to ensure is unique 85 * @check_name: Name we are trying to ensure is unique. 86 * 87 * Return: true if we have a unique name, false if name is not unique. 88 */ 89 static bool rproc_name_is_unique(struct udevice *check_dev, 90 const char *check_name) 91 { 92 int ret; 93 94 ret = for_each_remoteproc_device(_rproc_name_is_unique, 95 check_dev, check_name); 96 return ret ? false : true; 97 } 98 99 /** 100 * rproc_pre_probe() - Pre probe accessor for the uclass 101 * @dev: device for which we are preprobing 102 * 103 * Parses and fills up the uclass pdata for use as needed by core and 104 * remote proc drivers. 105 * 106 * Return: 0 if all wernt ok, else appropriate error value. 107 */ 108 static int rproc_pre_probe(struct udevice *dev) 109 { 110 struct dm_rproc_uclass_pdata *uc_pdata; 111 const struct dm_rproc_ops *ops; 112 113 uc_pdata = dev_get_uclass_platdata(dev); 114 115 /* See if we need to populate via fdt */ 116 117 if (!dev->platdata) { 118 #if CONFIG_IS_ENABLED(OF_CONTROL) 119 int node = dev_of_offset(dev); 120 const void *blob = gd->fdt_blob; 121 bool tmp; 122 if (!blob) { 123 debug("'%s' no dt?\n", dev->name); 124 return -EINVAL; 125 } 126 debug("'%s': using fdt\n", dev->name); 127 uc_pdata->name = fdt_getprop(blob, node, 128 "remoteproc-name", NULL); 129 130 /* Default is internal memory mapped */ 131 uc_pdata->mem_type = RPROC_INTERNAL_MEMORY_MAPPED; 132 tmp = fdtdec_get_bool(blob, node, 133 "remoteproc-internal-memory-mapped"); 134 if (tmp) 135 uc_pdata->mem_type = RPROC_INTERNAL_MEMORY_MAPPED; 136 #else 137 /* Nothing much we can do about this, can we? */ 138 return -EINVAL; 139 #endif 140 141 } else { 142 struct dm_rproc_uclass_pdata *pdata = dev->platdata; 143 144 debug("'%s': using legacy data\n", dev->name); 145 if (pdata->name) 146 uc_pdata->name = pdata->name; 147 uc_pdata->mem_type = pdata->mem_type; 148 uc_pdata->driver_plat_data = pdata->driver_plat_data; 149 } 150 151 /* Else try using device Name */ 152 if (!uc_pdata->name) 153 uc_pdata->name = dev->name; 154 if (!uc_pdata->name) { 155 debug("Unnamed device!"); 156 return -EINVAL; 157 } 158 159 if (!rproc_name_is_unique(dev, uc_pdata->name)) { 160 debug("%s duplicate name '%s'\n", dev->name, uc_pdata->name); 161 return -EINVAL; 162 } 163 164 ops = rproc_get_ops(dev); 165 if (!ops) { 166 debug("%s driver has no ops?\n", dev->name); 167 return -EINVAL; 168 } 169 170 if (!ops->load || !ops->start) { 171 debug("%s driver has missing mandatory ops?\n", dev->name); 172 return -EINVAL; 173 } 174 175 return 0; 176 } 177 178 /** 179 * rproc_post_probe() - post probe accessor for the uclass 180 * @dev: deivce we finished probing 181 * 182 * initiate init function after the probe is completed. This allows 183 * the remote processor drivers to split up the initializations between 184 * probe and init as needed. 185 * 186 * Return: if the remote proc driver has a init routine, invokes it and 187 * hands over the return value. overall, 0 if all went well, else appropriate 188 * error value. 189 */ 190 static int rproc_post_probe(struct udevice *dev) 191 { 192 const struct dm_rproc_ops *ops; 193 194 ops = rproc_get_ops(dev); 195 if (!ops) { 196 debug("%s driver has no ops?\n", dev->name); 197 return -EINVAL; 198 } 199 200 if (ops->init) 201 return ops->init(dev); 202 203 return 0; 204 } 205 206 UCLASS_DRIVER(rproc) = { 207 .id = UCLASS_REMOTEPROC, 208 .name = "remoteproc", 209 .flags = DM_UC_FLAG_SEQ_ALIAS, 210 .pre_probe = rproc_pre_probe, 211 .post_probe = rproc_post_probe, 212 .per_device_platdata_auto_alloc_size = 213 sizeof(struct dm_rproc_uclass_pdata), 214 }; 215 216 /* Remoteproc subsystem access functions */ 217 /** 218 * _rproc_probe_dev() - iteration helper to probe a rproc device 219 * @dev: device to probe 220 * @uc_pdata: uclass data allocated for the device 221 * @data: unused 222 * 223 * Return: 0 if all ok, else appropriate error value. 224 */ 225 static int _rproc_probe_dev(struct udevice *dev, 226 struct dm_rproc_uclass_pdata *uc_pdata, 227 const void *data) 228 { 229 int ret; 230 231 ret = device_probe(dev); 232 233 if (ret) 234 debug("%s: Failed to initialize - %d\n", dev->name, ret); 235 return ret; 236 } 237 238 /** 239 * _rproc_dev_is_probed() - check if the device has been probed 240 * @dev: device to check 241 * @uc_pdata: unused 242 * @data: unused 243 * 244 * Return: -EAGAIN if not probed else return 0 245 */ 246 static int _rproc_dev_is_probed(struct udevice *dev, 247 struct dm_rproc_uclass_pdata *uc_pdata, 248 const void *data) 249 { 250 if (dev->flags & DM_FLAG_ACTIVATED) 251 return 0; 252 253 return -EAGAIN; 254 } 255 256 bool rproc_is_initialized(void) 257 { 258 int ret = for_each_remoteproc_device(_rproc_dev_is_probed, NULL, NULL); 259 return ret ? false : true; 260 } 261 262 int rproc_init(void) 263 { 264 int ret; 265 266 if (rproc_is_initialized()) { 267 debug("Already initialized\n"); 268 return -EINVAL; 269 } 270 271 ret = for_each_remoteproc_device(_rproc_probe_dev, NULL, NULL); 272 return ret; 273 } 274 275 int rproc_dev_init(int id) 276 { 277 struct udevice *dev = NULL; 278 int ret; 279 280 ret = uclass_get_device_by_seq(UCLASS_REMOTEPROC, id, &dev); 281 if (ret) { 282 debug("Unknown remote processor id '%d' requested(%d)\n", 283 id, ret); 284 return ret; 285 } 286 287 ret = device_probe(dev); 288 if (ret) 289 debug("%s: Failed to initialize - %d\n", dev->name, ret); 290 291 return ret; 292 } 293 294 int rproc_load(int id, ulong addr, ulong size) 295 { 296 struct udevice *dev = NULL; 297 struct dm_rproc_uclass_pdata *uc_pdata; 298 const struct dm_rproc_ops *ops; 299 int ret; 300 301 ret = uclass_get_device_by_seq(UCLASS_REMOTEPROC, id, &dev); 302 if (ret) { 303 debug("Unknown remote processor id '%d' requested(%d)\n", 304 id, ret); 305 return ret; 306 } 307 308 uc_pdata = dev_get_uclass_platdata(dev); 309 310 ops = rproc_get_ops(dev); 311 if (!ops) { 312 debug("%s driver has no ops?\n", dev->name); 313 return -EINVAL; 314 } 315 316 debug("Loading to '%s' from address 0x%08lX size of %lu bytes\n", 317 uc_pdata->name, addr, size); 318 if (ops->load) 319 return ops->load(dev, addr, size); 320 321 debug("%s: data corruption?? mandatory function is missing!\n", 322 dev->name); 323 324 return -EINVAL; 325 }; 326 327 /* 328 * Completely internal helper enums.. 329 * Keeping this isolated helps this code evolve independent of other 330 * parts.. 331 */ 332 enum rproc_ops { 333 RPROC_START, 334 RPROC_STOP, 335 RPROC_RESET, 336 RPROC_PING, 337 RPROC_RUNNING, 338 }; 339 340 /** 341 * _rproc_ops_wrapper() - wrapper for invoking remote proc driver callback 342 * @id: id of the remote processor 343 * @op: one of rproc_ops that indicate what operation to invoke 344 * 345 * Most of the checks and verification for remoteproc operations are more 346 * or less same for almost all operations. This allows us to put a wrapper 347 * and use the common checks to allow the driver to function appropriately. 348 * 349 * Return: 0 if all ok, else appropriate error value. 350 */ 351 static int _rproc_ops_wrapper(int id, enum rproc_ops op) 352 { 353 struct udevice *dev = NULL; 354 struct dm_rproc_uclass_pdata *uc_pdata; 355 const struct dm_rproc_ops *ops; 356 int (*fn)(struct udevice *dev); 357 bool mandatory = false; 358 char *op_str; 359 int ret; 360 361 ret = uclass_get_device_by_seq(UCLASS_REMOTEPROC, id, &dev); 362 if (ret) { 363 debug("Unknown remote processor id '%d' requested(%d)\n", 364 id, ret); 365 return ret; 366 } 367 368 uc_pdata = dev_get_uclass_platdata(dev); 369 370 ops = rproc_get_ops(dev); 371 if (!ops) { 372 debug("%s driver has no ops?\n", dev->name); 373 return -EINVAL; 374 } 375 switch (op) { 376 case RPROC_START: 377 fn = ops->start; 378 mandatory = true; 379 op_str = "Starting"; 380 break; 381 case RPROC_STOP: 382 fn = ops->stop; 383 op_str = "Stopping"; 384 break; 385 case RPROC_RESET: 386 fn = ops->reset; 387 op_str = "Resetting"; 388 break; 389 case RPROC_RUNNING: 390 fn = ops->is_running; 391 op_str = "Checking if running:"; 392 break; 393 case RPROC_PING: 394 fn = ops->ping; 395 op_str = "Pinging"; 396 break; 397 default: 398 debug("what is '%d' operation??\n", op); 399 return -EINVAL; 400 } 401 402 debug("%s %s...\n", op_str, uc_pdata->name); 403 if (fn) 404 return fn(dev); 405 406 if (mandatory) 407 debug("%s: data corruption?? mandatory function is missing!\n", 408 dev->name); 409 410 return -ENOSYS; 411 } 412 413 int rproc_start(int id) 414 { 415 return _rproc_ops_wrapper(id, RPROC_START); 416 }; 417 418 int rproc_stop(int id) 419 { 420 return _rproc_ops_wrapper(id, RPROC_STOP); 421 }; 422 423 int rproc_reset(int id) 424 { 425 return _rproc_ops_wrapper(id, RPROC_RESET); 426 }; 427 428 int rproc_ping(int id) 429 { 430 return _rproc_ops_wrapper(id, RPROC_PING); 431 }; 432 433 int rproc_is_running(int id) 434 { 435 return _rproc_ops_wrapper(id, RPROC_RUNNING); 436 }; 437