diff options
Diffstat (limited to 'drivers/remoteproc/xlnx_r5_remoteproc.c')
-rw-r--r-- | drivers/remoteproc/xlnx_r5_remoteproc.c | 611 |
1 files changed, 438 insertions, 173 deletions
diff --git a/drivers/remoteproc/xlnx_r5_remoteproc.c b/drivers/remoteproc/xlnx_r5_remoteproc.c index 4395edea9a64..5aeedeaf3c41 100644 --- a/drivers/remoteproc/xlnx_r5_remoteproc.c +++ b/drivers/remoteproc/xlnx_r5_remoteproc.c @@ -25,6 +25,10 @@ /* RX mailbox client buffer max length */ #define MBOX_CLIENT_BUF_MAX (IPI_BUF_LEN_MAX + \ sizeof(struct zynqmp_ipi_message)) + +#define RSC_TBL_XLNX_MAGIC ((uint32_t)'x' << 24 | (uint32_t)'a' << 16 | \ + (uint32_t)'m' << 8 | (uint32_t)'p') + /* * settings for RPU cluster mode which * reflects possible values of xlnx,cluster-mode dt-property @@ -53,6 +57,17 @@ struct mem_bank_data { }; /** + * struct zynqmp_sram_bank - sram bank description + * + * @sram_res: sram address region information + * @da: device address of sram + */ +struct zynqmp_sram_bank { + struct resource sram_res; + u32 da; +}; + +/** * struct mbox_info * * @rx_mc_buf: to copy data from mailbox rx channel @@ -73,9 +88,29 @@ struct mbox_info { struct mbox_chan *rx_chan; }; +/** + * struct rsc_tbl_data + * + * Platform specific data structure used to sync resource table address. + * It's important to maintain order and size of each field on remote side. + * + * @version: version of data structure + * @magic_num: 32-bit magic number. + * @comp_magic_num: complement of above magic number + * @rsc_tbl_size: resource table size + * @rsc_tbl: resource table address + */ +struct rsc_tbl_data { + const int version; + const u32 magic_num; + const u32 comp_magic_num; + const u32 rsc_tbl_size; + const uintptr_t rsc_tbl; +} __packed; + /* - * Hardcoded TCM bank values. This will be removed once TCM bindings are - * accepted for system-dt specifications and upstreamed in linux kernel + * Hardcoded TCM bank values. This will stay in driver to maintain backward + * compatibility with device-tree that does not have TCM information. */ static const struct mem_bank_data zynqmp_tcm_banks_split[] = { {0xffe00000UL, 0x0, 0x10000UL, PD_R5_0_ATCM, "atcm0"}, /* TCM 64KB each */ @@ -84,31 +119,39 @@ static const struct mem_bank_data zynqmp_tcm_banks_split[] = { {0xffeb0000UL, 0x20000, 0x10000UL, PD_R5_1_BTCM, "btcm1"}, }; -/* In lockstep mode cluster combines each 64KB TCM and makes 128KB TCM */ +/* In lockstep mode cluster uses each 64KB TCM from second core as well */ static const struct mem_bank_data zynqmp_tcm_banks_lockstep[] = { - {0xffe00000UL, 0x0, 0x20000UL, PD_R5_0_ATCM, "atcm0"}, /* TCM 128KB each */ - {0xffe20000UL, 0x20000, 0x20000UL, PD_R5_0_BTCM, "btcm0"}, - {0, 0, 0, PD_R5_1_ATCM, ""}, - {0, 0, 0, PD_R5_1_BTCM, ""}, + {0xffe00000UL, 0x0, 0x10000UL, PD_R5_0_ATCM, "atcm0"}, /* TCM 64KB each */ + {0xffe20000UL, 0x20000, 0x10000UL, PD_R5_0_BTCM, "btcm0"}, + {0xffe10000UL, 0x10000, 0x10000UL, PD_R5_1_ATCM, "atcm1"}, + {0xffe30000UL, 0x30000, 0x10000UL, PD_R5_1_BTCM, "btcm1"}, }; /** * struct zynqmp_r5_core * + * @rsc_tbl_va: resource table virtual address + * @sram: Array of sram memories assigned to this core + * @num_sram: number of sram for this core * @dev: device of RPU instance * @np: device node of RPU instance * @tcm_bank_count: number TCM banks accessible to this RPU * @tcm_banks: array of each TCM bank data * @rproc: rproc handle + * @rsc_tbl_size: resource table size retrieved from remote * @pm_domain_id: RPU CPU power domain id * @ipi: pointer to mailbox information */ struct zynqmp_r5_core { + void __iomem *rsc_tbl_va; + struct zynqmp_sram_bank *sram; + int num_sram; struct device *dev; struct device_node *np; int tcm_bank_count; struct mem_bank_data **tcm_banks; struct rproc *rproc; + u32 rsc_tbl_size; u32 pm_domain_id; struct mbox_info *ipi; }; @@ -301,36 +344,6 @@ static void zynqmp_r5_rproc_kick(struct rproc *rproc, int vqid) } /* - * zynqmp_r5_set_mode() - * - * set RPU cluster and TCM operation mode - * - * @r5_core: pointer to zynqmp_r5_core type object - * @fw_reg_val: value expected by firmware to configure RPU cluster mode - * @tcm_mode: value expected by fw to configure TCM mode (lockstep or split) - * - * Return: 0 for success and < 0 for failure - */ -static int zynqmp_r5_set_mode(struct zynqmp_r5_core *r5_core, - enum rpu_oper_mode fw_reg_val, - enum rpu_tcm_comb tcm_mode) -{ - int ret; - - ret = zynqmp_pm_set_rpu_mode(r5_core->pm_domain_id, fw_reg_val); - if (ret < 0) { - dev_err(r5_core->dev, "failed to set RPU mode\n"); - return ret; - } - - ret = zynqmp_pm_set_tcm_config(r5_core->pm_domain_id, tcm_mode); - if (ret < 0) - dev_err(r5_core->dev, "failed to configure TCM\n"); - - return ret; -} - -/* * zynqmp_r5_rproc_start() * @rproc: single R5 core's corresponding rproc instance * @@ -486,6 +499,7 @@ static int add_mem_regions_carveout(struct rproc *rproc) } rproc_add_carveout(rproc, rproc_mem); + rproc_coredump_add_segment(rproc, rmem->base, rmem->size); dev_dbg(&rproc->dev, "reserved mem carveout %s addr=%llx, size=0x%llx", it.node->name, rmem->base, rmem->size); @@ -495,6 +509,45 @@ static int add_mem_regions_carveout(struct rproc *rproc) return 0; } +static int add_sram_carveouts(struct rproc *rproc) +{ + struct zynqmp_r5_core *r5_core = rproc->priv; + struct rproc_mem_entry *rproc_mem; + struct zynqmp_sram_bank *sram; + dma_addr_t dma_addr; + size_t len; + int da, i; + + for (i = 0; i < r5_core->num_sram; i++) { + sram = &r5_core->sram[i]; + + dma_addr = (dma_addr_t)sram->sram_res.start; + + len = resource_size(&sram->sram_res); + da = sram->da; + + rproc_mem = rproc_mem_entry_init(&rproc->dev, NULL, + dma_addr, + len, da, + zynqmp_r5_mem_region_map, + zynqmp_r5_mem_region_unmap, + sram->sram_res.name); + if (!rproc_mem) { + dev_err(&rproc->dev, "failed to add sram %s da=0x%x, size=0x%lx", + sram->sram_res.name, da, len); + return -ENOMEM; + } + + rproc_add_carveout(rproc, rproc_mem); + rproc_coredump_add_segment(rproc, da, len); + + dev_dbg(&rproc->dev, "sram carveout %s addr=%llx, da=0x%x, size=0x%lx", + sram->sram_res.name, dma_addr, da, len); + } + + return 0; +} + /* * tcm_mem_unmap() * @rproc: single R5 core's corresponding rproc instance @@ -540,14 +593,14 @@ static int tcm_mem_map(struct rproc *rproc, } /* - * add_tcm_carveout_split_mode() + * add_tcm_banks() * @rproc: single R5 core's corresponding rproc instance * - * allocate and add remoteproc carveout for TCM memory in split mode + * allocate and add remoteproc carveout for TCM memory * * return 0 on success, otherwise non-zero value on failure */ -static int add_tcm_carveout_split_mode(struct rproc *rproc) +static int add_tcm_banks(struct rproc *rproc) { struct rproc_mem_entry *rproc_mem; struct zynqmp_r5_core *r5_core; @@ -580,90 +633,20 @@ static int add_tcm_carveout_split_mode(struct rproc *rproc) ZYNQMP_PM_REQUEST_ACK_BLOCKING); if (ret < 0) { dev_err(dev, "failed to turn on TCM 0x%x", pm_domain_id); - goto release_tcm_split; + goto release_tcm; } - dev_dbg(dev, "TCM carveout split mode %s addr=%llx, da=0x%x, size=0x%lx", + dev_dbg(dev, "TCM carveout %s addr=%llx, da=0x%x, size=0x%lx", bank_name, bank_addr, da, bank_size); - rproc_mem = rproc_mem_entry_init(dev, NULL, bank_addr, - bank_size, da, - tcm_mem_map, tcm_mem_unmap, - bank_name); - if (!rproc_mem) { - ret = -ENOMEM; - zynqmp_pm_release_node(pm_domain_id); - goto release_tcm_split; - } - - rproc_add_carveout(rproc, rproc_mem); - } - - return 0; - -release_tcm_split: - /* If failed, Turn off all TCM banks turned on before */ - for (i--; i >= 0; i--) { - pm_domain_id = r5_core->tcm_banks[i]->pm_domain_id; - zynqmp_pm_release_node(pm_domain_id); - } - return ret; -} - -/* - * add_tcm_carveout_lockstep_mode() - * @rproc: single R5 core's corresponding rproc instance - * - * allocate and add remoteproc carveout for TCM memory in lockstep mode - * - * return 0 on success, otherwise non-zero value on failure - */ -static int add_tcm_carveout_lockstep_mode(struct rproc *rproc) -{ - struct rproc_mem_entry *rproc_mem; - struct zynqmp_r5_core *r5_core; - int i, num_banks, ret; - phys_addr_t bank_addr; - size_t bank_size = 0; - struct device *dev; - u32 pm_domain_id; - char *bank_name; - u32 da; - - r5_core = rproc->priv; - dev = r5_core->dev; - - /* Go through zynqmp banks for r5 node */ - num_banks = r5_core->tcm_bank_count; - - /* - * In lockstep mode, TCM is contiguous memory block - * However, each TCM block still needs to be enabled individually. - * So, Enable each TCM block individually. - * Although ATCM and BTCM is contiguous memory block, add two separate - * carveouts for both. - */ - for (i = 0; i < num_banks; i++) { - pm_domain_id = r5_core->tcm_banks[i]->pm_domain_id; - - /* Turn on each TCM bank individually */ - ret = zynqmp_pm_request_node(pm_domain_id, - ZYNQMP_PM_CAPABILITY_ACCESS, 0, - ZYNQMP_PM_REQUEST_ACK_BLOCKING); - if (ret < 0) { - dev_err(dev, "failed to turn on TCM 0x%x", pm_domain_id); - goto release_tcm_lockstep; - } - - bank_size = r5_core->tcm_banks[i]->size; - if (bank_size == 0) + /* + * In DETACHED state firmware is already running so no need to + * request add TCM registers. However, request TCM PD node to let + * platform management firmware know that TCM is in use. + */ + if (rproc->state == RPROC_DETACHED) continue; - bank_addr = r5_core->tcm_banks[i]->addr; - da = r5_core->tcm_banks[i]->da; - bank_name = r5_core->tcm_banks[i]->bank_name; - - /* Register TCM address range, TCM map and unmap functions */ rproc_mem = rproc_mem_entry_init(dev, NULL, bank_addr, bank_size, da, tcm_mem_map, tcm_mem_unmap, @@ -671,19 +654,16 @@ static int add_tcm_carveout_lockstep_mode(struct rproc *rproc) if (!rproc_mem) { ret = -ENOMEM; zynqmp_pm_release_node(pm_domain_id); - goto release_tcm_lockstep; + goto release_tcm; } - /* If registration is success, add carveouts */ rproc_add_carveout(rproc, rproc_mem); - - dev_dbg(dev, "TCM carveout lockstep mode %s addr=0x%llx, da=0x%x, size=0x%lx", - bank_name, bank_addr, da, bank_size); + rproc_coredump_add_segment(rproc, da, bank_size); } return 0; -release_tcm_lockstep: +release_tcm: /* If failed, Turn off all TCM banks turned on before */ for (i--; i >= 0; i--) { pm_domain_id = r5_core->tcm_banks[i]->pm_domain_id; @@ -693,45 +673,6 @@ release_tcm_lockstep: } /* - * add_tcm_banks() - * @rproc: single R5 core's corresponding rproc instance - * - * allocate and add remoteproc carveouts for TCM memory based on cluster mode - * - * return 0 on success, otherwise non-zero value on failure - */ -static int add_tcm_banks(struct rproc *rproc) -{ - struct zynqmp_r5_cluster *cluster; - struct zynqmp_r5_core *r5_core; - struct device *dev; - - r5_core = rproc->priv; - if (!r5_core) - return -EINVAL; - - dev = r5_core->dev; - - cluster = dev_get_drvdata(dev->parent); - if (!cluster) { - dev_err(dev->parent, "Invalid driver data\n"); - return -EINVAL; - } - - /* - * In lockstep mode TCM banks are one contiguous memory region of 256Kb - * In split mode, each TCM bank is 64Kb and not contiguous. - * We add memory carveouts accordingly. - */ - if (cluster->mode == SPLIT_MODE) - return add_tcm_carveout_split_mode(rproc); - else if (cluster->mode == LOCKSTEP_MODE) - return add_tcm_carveout_lockstep_mode(rproc); - - return -EINVAL; -} - -/* * zynqmp_r5_parse_fw() * @rproc: single R5 core's corresponding rproc instance * @fw: ptr to firmware to be loaded onto r5 core @@ -782,6 +723,12 @@ static int zynqmp_r5_rproc_prepare(struct rproc *rproc) return ret; } + ret = add_sram_carveouts(rproc); + if (ret) { + dev_err(&rproc->dev, "failed to get sram carveout %d\n", ret); + return ret; + } + return 0; } @@ -811,6 +758,107 @@ static int zynqmp_r5_rproc_unprepare(struct rproc *rproc) return 0; } +static struct resource_table *zynqmp_r5_get_loaded_rsc_table(struct rproc *rproc, + size_t *size) +{ + struct zynqmp_r5_core *r5_core; + + r5_core = rproc->priv; + + *size = r5_core->rsc_tbl_size; + + return (struct resource_table *)r5_core->rsc_tbl_va; +} + +static int zynqmp_r5_get_rsc_table_va(struct zynqmp_r5_core *r5_core) +{ + struct resource_table *rsc_tbl_addr; + struct device *dev = r5_core->dev; + struct rsc_tbl_data *rsc_data_va; + struct resource res_mem; + struct device_node *np; + int ret; + + /* + * It is expected from remote processor firmware to provide resource + * table address via struct rsc_tbl_data data structure. + * Start address of first entry under "memory-region" property list + * contains that data structure which holds resource table address, size + * and some magic number to validate correct resource table entry. + */ + np = of_parse_phandle(r5_core->np, "memory-region", 0); + if (!np) { + dev_err(dev, "failed to get memory region dev node\n"); + return -EINVAL; + } + + ret = of_address_to_resource(np, 0, &res_mem); + of_node_put(np); + if (ret) { + dev_err(dev, "failed to get memory-region resource addr\n"); + return -EINVAL; + } + + rsc_data_va = (struct rsc_tbl_data *)ioremap_wc(res_mem.start, + sizeof(struct rsc_tbl_data)); + if (!rsc_data_va) { + dev_err(dev, "failed to map resource table data address\n"); + return -EIO; + } + + /* + * If RSC_TBL_XLNX_MAGIC number and its complement isn't found then + * do not consider resource table address valid and don't attach + */ + if (rsc_data_va->magic_num != RSC_TBL_XLNX_MAGIC || + rsc_data_va->comp_magic_num != ~RSC_TBL_XLNX_MAGIC) { + dev_dbg(dev, "invalid magic number, won't attach\n"); + return -EINVAL; + } + + r5_core->rsc_tbl_va = ioremap_wc(rsc_data_va->rsc_tbl, + rsc_data_va->rsc_tbl_size); + if (!r5_core->rsc_tbl_va) { + dev_err(dev, "failed to get resource table va\n"); + return -EINVAL; + } + + rsc_tbl_addr = (struct resource_table *)r5_core->rsc_tbl_va; + + /* + * As of now resource table version 1 is expected. Don't fail to attach + * but warn users about it. + */ + if (rsc_tbl_addr->ver != 1) + dev_warn(dev, "unexpected resource table version %d\n", + rsc_tbl_addr->ver); + + r5_core->rsc_tbl_size = rsc_data_va->rsc_tbl_size; + + iounmap((void __iomem *)rsc_data_va); + + return 0; +} + +static int zynqmp_r5_attach(struct rproc *rproc) +{ + dev_dbg(&rproc->dev, "rproc %d attached\n", rproc->index); + + return 0; +} + +static int zynqmp_r5_detach(struct rproc *rproc) +{ + /* + * Generate last notification to remote after clearing virtio flag. + * Remote can avoid polling on virtio reset flag if kick is generated + * during detach by host and check virtio reset flag on kick interrupt. + */ + zynqmp_r5_rproc_kick(rproc, 0); + + return 0; +} + static const struct rproc_ops zynqmp_r5_rproc_ops = { .prepare = zynqmp_r5_rproc_prepare, .unprepare = zynqmp_r5_rproc_unprepare, @@ -822,6 +870,9 @@ static const struct rproc_ops zynqmp_r5_rproc_ops = { .sanity_check = rproc_elf_sanity_check, .get_boot_addr = rproc_elf_get_boot_addr, .kick = zynqmp_r5_rproc_kick, + .get_loaded_rsc_table = zynqmp_r5_get_loaded_rsc_table, + .attach = zynqmp_r5_attach, + .detach = zynqmp_r5_detach, }; /** @@ -853,6 +904,8 @@ static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev) return ERR_PTR(-ENOMEM); } + rproc_coredump_set_elf_info(r5_rproc, ELFCLASS32, EM_ARM); + r5_rproc->auto_boot = false; r5_core = r5_rproc->priv; r5_core->dev = cdev; @@ -870,6 +923,16 @@ static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev) goto free_rproc; } + /* + * If firmware is already available in the memory then move rproc state + * to DETACHED. Firmware can be preloaded via debugger or by any other + * agent (processors) in the system. + * If firmware isn't available in the memory and resource table isn't + * found, then rproc state remains OFFLINE. + */ + if (!zynqmp_r5_get_rsc_table_va(r5_core)) + r5_rproc->state = RPROC_DETACHED; + r5_core->rproc = r5_rproc; return r5_core; @@ -878,6 +941,174 @@ free_rproc: return ERR_PTR(ret); } +static int zynqmp_r5_get_sram_banks(struct zynqmp_r5_core *r5_core) +{ + struct device_node *np = r5_core->np; + struct device *dev = r5_core->dev; + struct zynqmp_sram_bank *sram; + struct device_node *sram_np; + int num_sram, i, ret; + u64 abs_addr, size; + + /* "sram" is optional property. Do not fail, if unavailable. */ + if (!of_property_present(r5_core->np, "sram")) + return 0; + + num_sram = of_property_count_elems_of_size(np, "sram", sizeof(phandle)); + if (num_sram <= 0) { + dev_err(dev, "Invalid sram property, ret = %d\n", + num_sram); + return -EINVAL; + } + + sram = devm_kcalloc(dev, num_sram, + sizeof(struct zynqmp_sram_bank), GFP_KERNEL); + if (!sram) + return -ENOMEM; + + for (i = 0; i < num_sram; i++) { + sram_np = of_parse_phandle(np, "sram", i); + if (!sram_np) { + dev_err(dev, "failed to get sram %d phandle\n", i); + return -EINVAL; + } + + if (!of_device_is_available(sram_np)) { + dev_err(dev, "sram device not available\n"); + ret = -EINVAL; + goto fail_sram_get; + } + + ret = of_address_to_resource(sram_np, 0, &sram[i].sram_res); + if (ret) { + dev_err(dev, "addr to res failed\n"); + goto fail_sram_get; + } + + /* Get SRAM device address */ + ret = of_property_read_reg(sram_np, i, &abs_addr, &size); + if (ret) { + dev_err(dev, "failed to get reg property\n"); + goto fail_sram_get; + } + + sram[i].da = (u32)abs_addr; + + of_node_put(sram_np); + + dev_dbg(dev, "sram %d: name=%s, addr=0x%llx, da=0x%x, size=0x%llx\n", + i, sram[i].sram_res.name, sram[i].sram_res.start, + sram[i].da, resource_size(&sram[i].sram_res)); + } + + r5_core->sram = sram; + r5_core->num_sram = num_sram; + + return 0; + +fail_sram_get: + of_node_put(sram_np); + + return ret; +} + +static int zynqmp_r5_get_tcm_node_from_dt(struct zynqmp_r5_cluster *cluster) +{ + int i, j, tcm_bank_count, ret, tcm_pd_idx, pd_count; + struct of_phandle_args out_args; + struct zynqmp_r5_core *r5_core; + struct platform_device *cpdev; + struct mem_bank_data *tcm; + struct device_node *np; + struct resource *res; + u64 abs_addr, size; + struct device *dev; + + for (i = 0; i < cluster->core_count; i++) { + r5_core = cluster->r5_cores[i]; + dev = r5_core->dev; + np = r5_core->np; + + pd_count = of_count_phandle_with_args(np, "power-domains", + "#power-domain-cells"); + + if (pd_count <= 0) { + dev_err(dev, "invalid power-domains property, %d\n", pd_count); + return -EINVAL; + } + + /* First entry in power-domains list is for r5 core, rest for TCM. */ + tcm_bank_count = pd_count - 1; + + if (tcm_bank_count <= 0) { + dev_err(dev, "invalid TCM count %d\n", tcm_bank_count); + return -EINVAL; + } + + r5_core->tcm_banks = devm_kcalloc(dev, tcm_bank_count, + sizeof(struct mem_bank_data *), + GFP_KERNEL); + if (!r5_core->tcm_banks) + return -ENOMEM; + + r5_core->tcm_bank_count = tcm_bank_count; + for (j = 0, tcm_pd_idx = 1; j < tcm_bank_count; j++, tcm_pd_idx++) { + tcm = devm_kzalloc(dev, sizeof(struct mem_bank_data), + GFP_KERNEL); + if (!tcm) + return -ENOMEM; + + r5_core->tcm_banks[j] = tcm; + + /* Get power-domains id of TCM. */ + ret = of_parse_phandle_with_args(np, "power-domains", + "#power-domain-cells", + tcm_pd_idx, &out_args); + if (ret) { + dev_err(r5_core->dev, + "failed to get tcm %d pm domain, ret %d\n", + tcm_pd_idx, ret); + return ret; + } + tcm->pm_domain_id = out_args.args[0]; + of_node_put(out_args.np); + + /* Get TCM address without translation. */ + ret = of_property_read_reg(np, j, &abs_addr, &size); + if (ret) { + dev_err(dev, "failed to get reg property\n"); + return ret; + } + + /* + * Remote processor can address only 32 bits + * so convert 64-bits into 32-bits. This will discard + * any unwanted upper 32-bits. + */ + tcm->da = (u32)abs_addr; + tcm->size = (u32)size; + + cpdev = to_platform_device(dev); + res = platform_get_resource(cpdev, IORESOURCE_MEM, j); + if (!res) { + dev_err(dev, "failed to get tcm resource\n"); + return -EINVAL; + } + + tcm->addr = (u32)res->start; + tcm->bank_name = (char *)res->name; + res = devm_request_mem_region(dev, tcm->addr, tcm->size, + tcm->bank_name); + if (!res) { + dev_err(dev, "failed to request tcm resource\n"); + return -EINVAL; + } + } + } + + return 0; +} + /** * zynqmp_r5_get_tcm_node() * Ideally this function should parse tcm node and store information @@ -954,11 +1185,18 @@ static int zynqmp_r5_core_init(struct zynqmp_r5_cluster *cluster, { struct device *dev = cluster->dev; struct zynqmp_r5_core *r5_core; - int ret, i; + int ret = -EINVAL, i; - ret = zynqmp_r5_get_tcm_node(cluster); - if (ret < 0) { - dev_err(dev, "can't get tcm node, err %d\n", ret); + r5_core = cluster->r5_cores[0]; + + /* Maintain backward compatibility for zynqmp by using hardcode TCM address. */ + if (of_property_present(r5_core->np, "reg")) + ret = zynqmp_r5_get_tcm_node_from_dt(cluster); + else if (device_is_compatible(dev, "xlnx,zynqmp-r5fss")) + ret = zynqmp_r5_get_tcm_node(cluster); + + if (ret) { + dev_err(dev, "can't get tcm, err %d\n", ret); return ret; } @@ -973,12 +1211,25 @@ static int zynqmp_r5_core_init(struct zynqmp_r5_cluster *cluster, return ret; } - ret = zynqmp_r5_set_mode(r5_core, fw_reg_val, tcm_mode); - if (ret) { - dev_err(dev, "failed to set r5 cluster mode %d, err %d\n", - cluster->mode, ret); + ret = zynqmp_pm_set_rpu_mode(r5_core->pm_domain_id, fw_reg_val); + if (ret < 0) { + dev_err(r5_core->dev, "failed to set RPU mode\n"); return ret; } + + if (of_property_present(dev_of_node(dev), "xlnx,tcm-mode") || + device_is_compatible(dev, "xlnx,zynqmp-r5fss")) { + ret = zynqmp_pm_set_tcm_config(r5_core->pm_domain_id, + tcm_mode); + if (ret < 0) { + dev_err(r5_core->dev, "failed to configure TCM\n"); + return ret; + } + } + + ret = zynqmp_r5_get_sram_banks(r5_core); + if (ret) + return ret; } return 0; @@ -1023,16 +1274,27 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster) * fail driver probe if either of that is not set in dts. */ if (cluster_mode == LOCKSTEP_MODE) { - tcm_mode = PM_RPU_TCM_COMB; fw_reg_val = PM_RPU_MODE_LOCKSTEP; } else if (cluster_mode == SPLIT_MODE) { - tcm_mode = PM_RPU_TCM_SPLIT; fw_reg_val = PM_RPU_MODE_SPLIT; } else { dev_err(dev, "driver does not support cluster mode %d\n", cluster_mode); return -EINVAL; } + if (of_property_present(dev_node, "xlnx,tcm-mode")) { + ret = of_property_read_u32(dev_node, "xlnx,tcm-mode", (u32 *)&tcm_mode); + if (ret) + return ret; + } else if (device_is_compatible(dev, "xlnx,zynqmp-r5fss")) { + if (cluster_mode == LOCKSTEP_MODE) + tcm_mode = PM_RPU_TCM_COMB; + else + tcm_mode = PM_RPU_TCM_SPLIT; + } else { + tcm_mode = PM_RPU_TCM_COMB; + } + /* * Number of cores is decided by number of child nodes of * r5f subsystem node in dts. If Split mode is used in dts @@ -1157,6 +1419,7 @@ static void zynqmp_r5_cluster_exit(void *data) for (i = 0; i < cluster->core_count; i++) { r5_core = cluster->r5_cores[i]; zynqmp_r5_free_mbox(r5_core->ipi); + iounmap(r5_core->rsc_tbl_va); of_reserved_mem_device_release(r5_core->dev); put_device(r5_core->dev); rproc_del(r5_core->rproc); @@ -1216,6 +1479,8 @@ static int zynqmp_r5_remoteproc_probe(struct platform_device *pdev) /* Match table for OF platform binding */ static const struct of_device_id zynqmp_r5_remoteproc_match[] = { + { .compatible = "xlnx,versal-net-r52fss", }, + { .compatible = "xlnx,versal-r5fss", }, { .compatible = "xlnx,zynqmp-r5fss", }, { /* end of list */ }, }; |