Home | History | Annotate | Download | only in remoteproc
      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_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