[PATCH v7 01/16] remoteproc: st_slim_rproc: add a slimcore rproc driver
Peter Griffin
peter.griffin at linaro.org
Thu Aug 25 09:41:24 PDT 2016
Hi Bjorn,
On Wed, 10 Aug 2016, Bjorn Andersson wrote:
> On Mon 01 Aug 10:10 PDT 2016, Peter Griffin wrote:
>
> Sorry for the slow response, but I have a few more (small) concerns.
No problem, thanks for reviewing. Equally I've been away on holiday last 3
weeks, so sorry about my delay as well :)
>
> [..]
> > diff --git a/drivers/remoteproc/st_slim_rproc.c b/drivers/remoteproc/st_slim_rproc.c
> [..]
> > +static int slim_rproc_start(struct rproc *rproc)
> > +{
> > + struct device *dev = &rproc->dev;
> > + struct st_slim_rproc *slim_rproc = rproc->priv;
> > + unsigned long hw_id, hw_ver, fw_rev;
> > + u32 val;
> > + int ret;
> > +
> > + ret = slim_clk_enable(slim_rproc);
> > + if (ret) {
> > + dev_err(dev, "Failed to enable clocks\n");
> > + goto err_clk;
>
> Nit. just return ret here and have a static "return 0" at the bottom.
Will fix.
>
> > + }
> > +
> > + /* disable CPU pipeline clock & reset cpu pipeline */
> > + val = SLIM_CLK_GATE_DIS | SLIM_CLK_GATE_RESET;
> > + writel(val, slim_rproc->slimcore + SLIM_CLK_GATE_OFST);
> > +
> > + /* disable SLIM core STBus sync */
> > + writel(SLIM_STBUS_SYNC_DIS, slim_rproc->peri + SLIM_STBUS_SYNC_OFST);
> > +
> > + /* enable cpu pipeline clock */
> > + writel(!SLIM_CLK_GATE_DIS,
> > + slim_rproc->slimcore + SLIM_CLK_GATE_OFST);
> > +
> > + /* clear int & cmd mailbox */
> > + writel(~0U, slim_rproc->peri + SLIM_INT_CLR_OFST);
> > + writel(~0U, slim_rproc->peri + SLIM_CMD_CLR_OFST);
> > +
> > + /* enable all channels cmd & int */
> > + writel(~0U, slim_rproc->peri + SLIM_INT_MASK_OFST);
> > + writel(~0U, slim_rproc->peri + SLIM_CMD_MASK_OFST);
> > +
> > + /* enable cpu */
> > + writel(SLIM_EN_RUN, slim_rproc->slimcore + SLIM_EN_OFST);
> > +
> > + hw_id = readl_relaxed(slim_rproc->slimcore + SLIM_ID_OFST);
> > + hw_ver = readl_relaxed(slim_rproc->slimcore + SLIM_VER_OFST);
> > +
> > + fw_rev = readl(slim_rproc->mem[SLIM_DMEM].cpu_addr +
> > + SLIM_REV_ID_OFST);
> > +
> > + dev_info(dev, "fw rev:%ld.%ld on SLIM %ld.%ld\n",
> > + SLIM_REV_ID_MAJ(fw_rev), SLIM_REV_ID_MIN(fw_rev),
> > + hw_id, hw_ver);
> > +
> > +err_clk:
> > + return ret;
> > +}
> > +
> > +static int slim_rproc_stop(struct rproc *rproc)
> > +{
> > + struct st_slim_rproc *slim_rproc = rproc->priv;
> > + u32 val;
> > +
> > + /* mask all (cmd & int) channels */
> > + writel(0UL, slim_rproc->peri + SLIM_INT_MASK_OFST);
> > + writel(0UL, slim_rproc->peri + SLIM_CMD_MASK_OFST);
> > +
> > + /* disable cpu pipeline clock */
> > + writel(SLIM_CLK_GATE_DIS
> > + , slim_rproc->slimcore + SLIM_CLK_GATE_OFST);
>
> Odd placement of ','
Will fix.
>
> > +
> > + writel(!SLIM_EN_RUN, slim_rproc->slimcore + SLIM_EN_OFST);
> > +
> > + val = readl(slim_rproc->slimcore + SLIM_EN_OFST);
> > + if (val & SLIM_EN_RUN)
> > + dev_warn(&rproc->dev, "Failed to disable SLIM");
> > +
> > + slim_clk_disable(slim_rproc);
> > +
> > + dev_dbg(&rproc->dev, "slim stopped\n");
> > +
> > + return 0;
> > +}
> > +
> > +static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> > +{
> > + struct st_slim_rproc *slim_rproc = rproc->priv;
> > + void *va = NULL;
> > + int i;
> > +
> > + for (i = 0; i < SLIM_MEM_MAX; i++) {
> > + if (da != slim_rproc->mem[i].bus_addr)
> > + continue;
>
> Are you sure you want to enforce this being called with da == base? (I'm
> not totally against it).
Yes.
>
> But you should probably double check that len is <= mem[i].size.
Good point, I will add a check for this.
>
> > + /* __force to make sparse happy with type conversion */
> > + va = (__force void *)slim_rproc->mem[i].cpu_addr;
> > + break;
> > + }
> > +
> > + dev_dbg(&rproc->dev, "%s: da = 0x%llx len = 0x%x va = 0x%p\n",
> > + __func__, da, len, va);
> > +
> > + return va;
> > +}
> > +
> > +static struct rproc_ops slim_rproc_ops = {
> > + .start = slim_rproc_start,
> > + .stop = slim_rproc_stop,
> > + .da_to_va = slim_rproc_da_to_va,
> > +};
> > +
> > +/**
> > + * Firmware handler operations: sanity, boot address, load ...
> > + */
> > +
> > +static struct resource_table empty_rsc_tbl = {
> > + .ver = 1,
> > + .num = 0,
> > +};
> > +
> > +static struct resource_table *slim_rproc_find_rsc_table(struct rproc *rproc,
> > + const struct firmware *fw,
> > + int *tablesz)
> > +{
> > + if (!fw)
> > + return NULL;
>
> I consider it a BUG in the core to get here with fw == NULL, so please
> drop this.
Ok will drop in next version.
>
> > +
> > + *tablesz = sizeof(empty_rsc_tbl);
> > + return &empty_rsc_tbl;
> > +}
> > +
> > +static struct resource_table *slim_rproc_find_loaded_rsc_table(struct rproc *rproc,
> > + const struct firmware *fw)
> > +{
> > + if (!fw)
> > + return NULL;
> > +
>
> fw can't be NULL, so please drop this check.
Ok will fix.
>
> > + return &empty_rsc_tbl;
>
> This function is supposed to return a pointer to the resource table as
> it appears in the space of the running firmware, so that any vring
> updates etc are visible to the remote.
>
> As your firmware doesn't do this you should return NULL here, rather
> than a pointer back to the fake resource table.
>
> But rproc_find_loaded_rsc_table() will do the same if you omit the
> reference in the fw_ops struct, so just make that NULL instead.
Good point. Will omit the reference in fw_ops struct in the next version.
>
> > +}
> > +
> > +static struct rproc_fw_ops slim_rproc_fw_ops = {
> > + .find_rsc_table = slim_rproc_find_rsc_table,
> > + .find_loaded_rsc_table = slim_rproc_find_loaded_rsc_table,
> > +};
> > +
> > +
> > +/**
> > + * slim_rproc_alloc() - allocate and initialise slim rproc
> > + * @pdev: Pointer to the platform_device struct
> > + * @fw_name: Name of firmware for rproc to use
> > + *
> > + * Function for allocating and initialising a slim rproc for use by
> > + * device drivers whose IP is based around the slim slim core. It
> > + * obtains and enables any clocks required by the slim core and also
> > + * ioremaps the various IO.
> > + *
> > + * Returns st_slim_rproc pointer or PTR_ERR() on error.
> > + */
> > +
> > +struct st_slim_rproc *slim_rproc_alloc(struct platform_device *pdev,
> > + char *fw_name)
> > +{
> > + struct device *dev = &pdev->dev;
> > + struct st_slim_rproc *slim_rproc;
> > + struct device_node *np = dev->of_node;
> > + struct rproc *rproc;
> > + struct resource *res;
> > + int err, i;
> > + const struct rproc_fw_ops *elf_ops;
> > +
> > + if (WARN_ON(!np || !fw_name))
> > + return ERR_PTR(-EINVAL);
> > +
> > + if (!of_device_is_compatible(np, "st,slim-rproc"))
> > + return ERR_PTR(-EINVAL);
> > +
> > + rproc = rproc_alloc(dev, np->name, &slim_rproc_ops,
> > + fw_name, sizeof(*slim_rproc));
> > + if (!rproc)
> > + return ERR_PTR(-ENOMEM);
> > +
> > + rproc->has_iommu = false;
> > +
> > + slim_rproc = rproc->priv;
> > + slim_rproc->rproc = rproc;
> > +
> > + elf_ops = rproc->fw_ops;
> > + /* Use some generic elf ops */
> > + slim_rproc_fw_ops.load = elf_ops->load;
> > + slim_rproc_fw_ops.sanity_check = elf_ops->sanity_check;
> > +
> > + rproc->fw_ops = &slim_rproc_fw_ops;
> > +
> > + /* get imem and dmem */
> > + for (i = 0; i < ARRAY_SIZE(mem_names); i++) {
> > +
> > + res = platform_get_resource_byname
> > + (pdev, IORESOURCE_MEM, mem_names[i]);
>
> This is an odd line breakage.
Will fix.
>
> > +
> > + slim_rproc->mem[i].cpu_addr = devm_ioremap_resource(dev, res);
> > + if (IS_ERR(slim_rproc->mem[i].cpu_addr)) {
> > + dev_err(&pdev->dev, "devm_ioremap_resource failed\n");
> > + err = PTR_ERR(slim_rproc->mem[i].cpu_addr);
> > + goto err;
> > + }
> > + slim_rproc->mem[i].bus_addr = res->start;
> > + slim_rproc->mem[i].size = resource_size(res);
> > + }
> > +
> > + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "slimcore");
> > +
> > + slim_rproc->slimcore = devm_ioremap_resource(dev, res);
> > + if (IS_ERR(slim_rproc->slimcore)) {
> > + dev_err(&pdev->dev,
> > + "devm_ioremap_resource failed for slimcore\n");
> > + err = PTR_ERR(slim_rproc->slimcore);
> > + goto err;
> > + }
> > +
> > + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "peripherals");
> > +
> > + slim_rproc->peri = devm_ioremap_resource(dev, res);
> > + if (IS_ERR(slim_rproc->peri)) {
> > + dev_err(&pdev->dev, "devm_ioremap_resource failed for peri\n");
> > + err = PTR_ERR(slim_rproc->peri);
> > + goto err;
> > + }
> > +
> > + err = slim_clk_get(slim_rproc, dev);
> > + if (err)
> > + goto err;
> > +
> > + /* Register as a remoteproc device */
> > + err = rproc_add(rproc);
> > + if (err) {
> > + dev_err(dev, "registration of slim remoteproc failed\n");
> > + goto err_clk;
> > + }
> > +
> > + return slim_rproc;
> > +
> > +err_clk:
> > + for (i = 0; i < SLIM_MAX_CLK && slim_rproc->clks[i]; i++)
> > + clk_put(slim_rproc->clks[i]);
>
> Is there any chance to could acquire these clocks by name instead of
> just picking up 4 "random" clocks from the DT node?
Not using clock names here was deliberate because the slim core is used as a
basis for various IP's in the SoC, the clock names and number of them in the
functional spec for the particular IP can change a lot.
For instance all fdma instances have 4 clocks of various names, but the
c8sectpfe demux IP also based around slim core only has one clock called STFE.
The inspiration for this approach was taken from ehci-platform.c and
ohci-platform.c drivers which have to work across a wide range of SoC's from different
vendors and can also have many different clocks and clock names / reset lines
and reset names & phys etc.
>
> You are generally supposed to use clock-names and could then use
> devm_clk_get() instead...
>
> > +err:
> > + rproc_put(rproc);
> > + return ERR_PTR(err);
> > +}
> > +EXPORT_SYMBOL(slim_rproc_alloc);
> > +
> > +/**
> > + * slim_rproc_put() - put slim rproc resources
> > + * @slim_rproc: Pointer to the st_slim_rproc struct
> > + *
> > + * Function for calling respective _put() functions on
> > + * slim_rproc resources.
> > + *
> > + */
> > +void slim_rproc_put(struct st_slim_rproc *slim_rproc)
> > +{
> > + int clk;
> > +
> > + if (!slim_rproc)
> > + return;
> > +
> > + for (clk = 0; clk < SLIM_MAX_CLK && slim_rproc->clks[clk]; clk++)
> > + clk_put(slim_rproc->clks[clk]);
> > +
>
> You need to rproc_del() here before calling rproc_put().
Will fix.
>
> > + rproc_put(slim_rproc->rproc);
> > +}
> > +EXPORT_SYMBOL(slim_rproc_put);
> > +
> > +MODULE_AUTHOR("Peter Griffin");
> > +MODULE_DESCRIPTION("STMicroelectronics SLIM rproc driver");
> > +MODULE_LICENSE("GPL v2");
> > diff --git a/include/linux/remoteproc/st_slim_rproc.h b/include/linux/remoteproc/st_slim_rproc.h
> > new file mode 100644
> > index 0000000..c300b3e
> > --- /dev/null
> > +++ b/include/linux/remoteproc/st_slim_rproc.h
> > @@ -0,0 +1,53 @@
> > +/*
> > + * st_slim_rproc.h
> > + *
> > + * Copyright (C) 2016 STMicroelectronics
> > + * Author: Peter Griffin <peter.griffin at linaro.org>
> > + * License terms: GNU General Public License (GPL), version 2
> > + */
> > +#ifndef _ST_SLIM_H
> > +#define _ST_SLIM_H
> > +
> > +#define SLIM_MEM_MAX 2
> > +#define SLIM_MAX_CLK 4
> > +
> > +enum {
> > + SLIM_DMEM,
> > + SLIM_IMEM,
> > +};
> > +
> > +/**
> > + * struct slim_mem - slim internal memory structure
> > + * @cpu_addr: MPU virtual address of the memory region
> > + * @bus_addr: Bus address used to access the memory region
> > + * @size: Size of the memory region
> > + */
> > +struct slim_mem {
> > + void __iomem *cpu_addr;
> > + phys_addr_t bus_addr;
> > + size_t size;
> > +};
> > +
>
> With things like slimbus being worked on I don't think it's appropriate
> to introduce public constants named SLIM_* or slim_*. Please rename
> these ST_SLIM_* and st_slim_*
Ok, will fix.
Regards,
Peter.
More information about the linux-arm-kernel
mailing list