1 /* 2 * (C) Copyright 2015 3 * Texas Instruments Incorporated - http://www.ti.com/ 4 * SPDX-License-Identifier: GPL-2.0+ 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; 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_load(int id, ulong addr, ulong size) 276 { 277 struct udevice *dev = NULL; 278 struct dm_rproc_uclass_pdata *uc_pdata; 279 const struct dm_rproc_ops *ops; 280 int ret; 281 282 ret = uclass_get_device_by_seq(UCLASS_REMOTEPROC, id, &dev); 283 if (ret) { 284 debug("Unknown remote processor id '%d' requested(%d)\n", 285 id, ret); 286 return ret; 287 } 288 289 uc_pdata = dev_get_uclass_platdata(dev); 290 291 ops = rproc_get_ops(dev); 292 if (!ops) { 293 debug("%s driver has no ops?\n", dev->name); 294 return -EINVAL; 295 } 296 297 debug("Loading to '%s' from address 0x%08lX size of %lu bytes\n", 298 uc_pdata->name, addr, size); 299 if (ops->load) 300 return ops->load(dev, addr, size); 301 302 debug("%s: data corruption?? mandatory function is missing!\n", 303 dev->name); 304 305 return -EINVAL; 306 }; 307 308 /* 309 * Completely internal helper enums.. 310 * Keeping this isolated helps this code evolve independent of other 311 * parts.. 312 */ 313 enum rproc_ops { 314 RPROC_START, 315 RPROC_STOP, 316 RPROC_RESET, 317 RPROC_PING, 318 RPROC_RUNNING, 319 }; 320 321 /** 322 * _rproc_ops_wrapper() - wrapper for invoking remote proc driver callback 323 * @id: id of the remote processor 324 * @op: one of rproc_ops that indicate what operation to invoke 325 * 326 * Most of the checks and verification for remoteproc operations are more 327 * or less same for almost all operations. This allows us to put a wrapper 328 * and use the common checks to allow the driver to function appropriately. 329 * 330 * Return: 0 if all ok, else appropriate error value. 331 */ 332 static int _rproc_ops_wrapper(int id, enum rproc_ops op) 333 { 334 struct udevice *dev = NULL; 335 struct dm_rproc_uclass_pdata *uc_pdata; 336 const struct dm_rproc_ops *ops; 337 int (*fn)(struct udevice *dev); 338 bool mandatory = false; 339 char *op_str; 340 int ret; 341 342 ret = uclass_get_device_by_seq(UCLASS_REMOTEPROC, id, &dev); 343 if (ret) { 344 debug("Unknown remote processor id '%d' requested(%d)\n", 345 id, ret); 346 return ret; 347 } 348 349 uc_pdata = dev_get_uclass_platdata(dev); 350 351 ops = rproc_get_ops(dev); 352 if (!ops) { 353 debug("%s driver has no ops?\n", dev->name); 354 return -EINVAL; 355 } 356 switch (op) { 357 case RPROC_START: 358 fn = ops->start; 359 mandatory = true; 360 op_str = "Starting"; 361 break; 362 case RPROC_STOP: 363 fn = ops->stop; 364 op_str = "Stopping"; 365 break; 366 case RPROC_RESET: 367 fn = ops->reset; 368 op_str = "Resetting"; 369 break; 370 case RPROC_RUNNING: 371 fn = ops->is_running; 372 op_str = "Checking if running:"; 373 break; 374 case RPROC_PING: 375 fn = ops->ping; 376 op_str = "Pinging"; 377 break; 378 default: 379 debug("what is '%d' operation??\n", op); 380 return -EINVAL; 381 } 382 383 debug("%s %s...\n", op_str, uc_pdata->name); 384 if (fn) 385 return fn(dev); 386 387 if (mandatory) 388 debug("%s: data corruption?? mandatory function is missing!\n", 389 dev->name); 390 391 return -ENOSYS; 392 } 393 394 int rproc_start(int id) 395 { 396 return _rproc_ops_wrapper(id, RPROC_START); 397 }; 398 399 int rproc_stop(int id) 400 { 401 return _rproc_ops_wrapper(id, RPROC_STOP); 402 }; 403 404 int rproc_reset(int id) 405 { 406 return _rproc_ops_wrapper(id, RPROC_RESET); 407 }; 408 409 int rproc_ping(int id) 410 { 411 return _rproc_ops_wrapper(id, RPROC_PING); 412 }; 413 414 int rproc_is_running(int id) 415 { 416 return _rproc_ops_wrapper(id, RPROC_RUNNING); 417 }; 418