diff options
Diffstat (limited to 'drivers/remoteproc/stm32_rproc.c')
| -rw-r--r-- | drivers/remoteproc/stm32_rproc.c | 205 | 
1 files changed, 110 insertions, 95 deletions
| diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c index ccb3c14a0023..7353f9e7e7af 100644 --- a/drivers/remoteproc/stm32_rproc.c +++ b/drivers/remoteproc/stm32_rproc.c @@ -28,7 +28,7 @@  #define RELEASE_BOOT		1  #define MBOX_NB_VQ		2 -#define MBOX_NB_MBX		3 +#define MBOX_NB_MBX		4  #define STM32_SMC_RCC		0x82001000  #define STM32_SMC_REG_WRITE	0x1 @@ -38,6 +38,7 @@  #define STM32_MBX_VQ1		"vq1"  #define STM32_MBX_VQ1_ID	1  #define STM32_MBX_SHUTDOWN	"shutdown" +#define STM32_MBX_DETACH	"detach"  #define RSC_TBL_SIZE		1024 @@ -207,16 +208,7 @@ static int stm32_rproc_mbox_idx(struct rproc *rproc, const unsigned char *name)  	return -EINVAL;  } -static int stm32_rproc_elf_load_rsc_table(struct rproc *rproc, -					  const struct firmware *fw) -{ -	if (rproc_elf_load_rsc_table(rproc, fw)) -		dev_warn(&rproc->dev, "no resource table found for this firmware\n"); - -	return 0; -} - -static int stm32_rproc_parse_memory_regions(struct rproc *rproc) +static int stm32_rproc_prepare(struct rproc *rproc)  {  	struct device *dev = rproc->dev.parent;  	struct device_node *np = dev->of_node; @@ -274,12 +266,10 @@ static int stm32_rproc_parse_memory_regions(struct rproc *rproc)  static int stm32_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)  { -	int ret = stm32_rproc_parse_memory_regions(rproc); - -	if (ret) -		return ret; +	if (rproc_elf_load_rsc_table(rproc, fw)) +		dev_warn(&rproc->dev, "no resource table found for this firmware\n"); -	return stm32_rproc_elf_load_rsc_table(rproc, fw); +	return 0;  }  static irqreturn_t stm32_rproc_wdg(int irq, void *data) @@ -347,6 +337,15 @@ static const struct stm32_mbox stm32_rproc_mbox[MBOX_NB_MBX] = {  			.tx_done = NULL,  			.tx_tout = 500, /* 500 ms time out */  		}, +	}, +	{ +		.name = STM32_MBX_DETACH, +		.vq_id = -1, +		.client = { +			.tx_block = true, +			.tx_done = NULL, +			.tx_tout = 200, /* 200 ms time out to detach should be fair enough */ +		},  	}  }; @@ -472,6 +471,25 @@ static int stm32_rproc_attach(struct rproc *rproc)  	return stm32_rproc_set_hold_boot(rproc, true);  } +static int stm32_rproc_detach(struct rproc *rproc) +{ +	struct stm32_rproc *ddata = rproc->priv; +	int err, dummy_data, idx; + +	/* Inform the remote processor of the detach */ +	idx = stm32_rproc_mbox_idx(rproc, STM32_MBX_DETACH); +	if (idx >= 0 && ddata->mb[idx].chan) { +		/* A dummy data is sent to allow to block on transmit */ +		err = mbox_send_message(ddata->mb[idx].chan, +					&dummy_data); +		if (err < 0) +			dev_warn(&rproc->dev, "warning: remote FW detach without ack\n"); +	} + +	/* Allow remote processor to auto-reboot */ +	return stm32_rproc_set_hold_boot(rproc, false); +} +  static int stm32_rproc_stop(struct rproc *rproc)  {  	struct stm32_rproc *ddata = rproc->priv; @@ -546,14 +564,89 @@ static void stm32_rproc_kick(struct rproc *rproc, int vqid)  	}  } +static int stm32_rproc_da_to_pa(struct rproc *rproc, +				u64 da, phys_addr_t *pa) +{ +	struct stm32_rproc *ddata = rproc->priv; +	struct device *dev = rproc->dev.parent; +	struct stm32_rproc_mem *p_mem; +	unsigned int i; + +	for (i = 0; i < ddata->nb_rmems; i++) { +		p_mem = &ddata->rmems[i]; + +		if (da < p_mem->dev_addr || +		    da >= p_mem->dev_addr + p_mem->size) +			continue; + +		*pa = da - p_mem->dev_addr + p_mem->bus_addr; +		dev_dbg(dev, "da %llx to pa %#x\n", da, *pa); + +		return 0; +	} + +	dev_err(dev, "can't translate da %llx\n", da); + +	return -EINVAL; +} + +static struct resource_table * +stm32_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz) +{ +	struct stm32_rproc *ddata = rproc->priv; +	struct device *dev = rproc->dev.parent; +	phys_addr_t rsc_pa; +	u32 rsc_da; +	int err; + +	/* The resource table has already been mapped, nothing to do */ +	if (ddata->rsc_va) +		goto done; + +	err = regmap_read(ddata->rsctbl.map, ddata->rsctbl.reg, &rsc_da); +	if (err) { +		dev_err(dev, "failed to read rsc tbl addr\n"); +		return ERR_PTR(-EINVAL); +	} + +	if (!rsc_da) +		/* no rsc table */ +		return ERR_PTR(-ENOENT); + +	err = stm32_rproc_da_to_pa(rproc, rsc_da, &rsc_pa); +	if (err) +		return ERR_PTR(err); + +	ddata->rsc_va = devm_ioremap_wc(dev, rsc_pa, RSC_TBL_SIZE); +	if (IS_ERR_OR_NULL(ddata->rsc_va)) { +		dev_err(dev, "Unable to map memory region: %pa+%zx\n", +			&rsc_pa, RSC_TBL_SIZE); +		ddata->rsc_va = NULL; +		return ERR_PTR(-ENOMEM); +	} + +done: +	/* +	 * Assuming the resource table fits in 1kB is fair. +	 * Notice for the detach, that this 1 kB memory area has to be reserved in the coprocessor +	 * firmware for the resource table. On detach, the remoteproc core re-initializes this +	 * entire area by overwriting it with the initial values stored in rproc->clean_table. +	 */ +	*table_sz = RSC_TBL_SIZE; +	return (struct resource_table *)ddata->rsc_va; +} +  static const struct rproc_ops st_rproc_ops = { +	.prepare	= stm32_rproc_prepare,  	.start		= stm32_rproc_start,  	.stop		= stm32_rproc_stop,  	.attach		= stm32_rproc_attach, +	.detach		= stm32_rproc_detach,  	.kick		= stm32_rproc_kick,  	.load		= rproc_elf_load_segments,  	.parse_fw	= stm32_rproc_parse_fw,  	.find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table, +	.get_loaded_rsc_table = stm32_rproc_get_loaded_rsc_table,  	.sanity_check	= rproc_elf_sanity_check,  	.get_boot_addr	= rproc_elf_get_boot_addr,  }; @@ -695,75 +788,6 @@ static int stm32_rproc_get_m4_status(struct stm32_rproc *ddata,  	return regmap_read(ddata->m4_state.map, ddata->m4_state.reg, state);  } -static int stm32_rproc_da_to_pa(struct platform_device *pdev, -				struct stm32_rproc *ddata, -				u64 da, phys_addr_t *pa) -{ -	struct device *dev = &pdev->dev; -	struct stm32_rproc_mem *p_mem; -	unsigned int i; - -	for (i = 0; i < ddata->nb_rmems; i++) { -		p_mem = &ddata->rmems[i]; - -		if (da < p_mem->dev_addr || -		    da >= p_mem->dev_addr + p_mem->size) -			continue; - -		*pa = da - p_mem->dev_addr + p_mem->bus_addr; -		dev_dbg(dev, "da %llx to pa %#x\n", da, *pa); - -		return 0; -	} - -	dev_err(dev, "can't translate da %llx\n", da); - -	return -EINVAL; -} - -static int stm32_rproc_get_loaded_rsc_table(struct platform_device *pdev, -					    struct rproc *rproc, -					    struct stm32_rproc *ddata) -{ -	struct device *dev = &pdev->dev; -	phys_addr_t rsc_pa; -	u32 rsc_da; -	int err; - -	err = regmap_read(ddata->rsctbl.map, ddata->rsctbl.reg, &rsc_da); -	if (err) { -		dev_err(dev, "failed to read rsc tbl addr\n"); -		return err; -	} - -	if (!rsc_da) -		/* no rsc table */ -		return 0; - -	err = stm32_rproc_da_to_pa(pdev, ddata, rsc_da, &rsc_pa); -	if (err) -		return err; - -	ddata->rsc_va = devm_ioremap_wc(dev, rsc_pa, RSC_TBL_SIZE); -	if (IS_ERR_OR_NULL(ddata->rsc_va)) { -		dev_err(dev, "Unable to map memory region: %pa+%zx\n", -			&rsc_pa, RSC_TBL_SIZE); -		ddata->rsc_va = NULL; -		return -ENOMEM; -	} - -	/* -	 * The resource table is already loaded in device memory, no need -	 * to work with a cached table. -	 */ -	rproc->cached_table = NULL; -	/* Assuming the resource table fits in 1kB is fair */ -	rproc->table_sz = RSC_TBL_SIZE; -	rproc->table_ptr = (struct resource_table *)ddata->rsc_va; - -	return 0; -} -  static int stm32_rproc_probe(struct platform_device *pdev)  {  	struct device *dev = &pdev->dev; @@ -797,18 +821,9 @@ static int stm32_rproc_probe(struct platform_device *pdev)  	if (ret)  		goto free_rproc; -	if (state == M4_STATE_CRUN) { +	if (state == M4_STATE_CRUN)  		rproc->state = RPROC_DETACHED; -		ret = stm32_rproc_parse_memory_regions(rproc); -		if (ret) -			goto free_resources; - -		ret = stm32_rproc_get_loaded_rsc_table(pdev, rproc, ddata); -		if (ret) -			goto free_resources; -	} -  	rproc->has_iommu = false;  	ddata->workqueue = create_workqueue(dev_name(dev));  	if (!ddata->workqueue) { | 
