// SPDX-License-Identifier: GPL-2.0-only /* * TI K3 Cortex-M4 Remote Processor(s) driver * * Copyright (C) 2021-2024 Texas Instruments Incorporated - https://www.ti.com/ * Hari Nagalla */ #include #include #include #include #include #include #include #include #include #include "omap_remoteproc.h" #include "remoteproc_internal.h" #include "ti_sci_proc.h" #include "ti_k3_common.h" static const struct rproc_ops k3_m4_rproc_ops = { .prepare = k3_rproc_prepare, .unprepare = k3_rproc_unprepare, .start = k3_rproc_start, .stop = k3_rproc_stop, .attach = k3_rproc_attach, .detach = k3_rproc_detach, .kick = k3_rproc_kick, .da_to_va = k3_rproc_da_to_va, .get_loaded_rsc_table = k3_get_loaded_rsc_table, }; static int k3_m4_rproc_probe(struct platform_device *pdev) { const struct k3_rproc_dev_data *data; struct device *dev = &pdev->dev; struct k3_rproc *kproc; struct rproc *rproc; const char *fw_name; bool r_state = false; bool p_state = false; int ret; data = of_device_get_match_data(dev); if (!data) return -ENODEV; ret = rproc_of_parse_firmware(dev, 0, &fw_name); if (ret) return dev_err_probe(dev, ret, "failed to parse firmware-name property\n"); rproc = devm_rproc_alloc(dev, dev_name(dev), &k3_m4_rproc_ops, fw_name, sizeof(*kproc)); if (!rproc) return -ENOMEM; rproc->has_iommu = false; rproc->recovery_disabled = true; kproc = rproc->priv; kproc->dev = dev; kproc->rproc = rproc; kproc->data = data; platform_set_drvdata(pdev, rproc); kproc->ti_sci = devm_ti_sci_get_by_phandle(dev, "ti,sci"); if (IS_ERR(kproc->ti_sci)) return dev_err_probe(dev, PTR_ERR(kproc->ti_sci), "failed to get ti-sci handle\n"); ret = of_property_read_u32(dev->of_node, "ti,sci-dev-id", &kproc->ti_sci_id); if (ret) return dev_err_probe(dev, ret, "missing 'ti,sci-dev-id' property\n"); kproc->reset = devm_reset_control_get_exclusive(dev, NULL); if (IS_ERR(kproc->reset)) return dev_err_probe(dev, PTR_ERR(kproc->reset), "failed to get reset\n"); kproc->tsp = ti_sci_proc_of_get_tsp(dev, kproc->ti_sci); if (IS_ERR(kproc->tsp)) return dev_err_probe(dev, PTR_ERR(kproc->tsp), "failed to construct ti-sci proc control\n"); ret = ti_sci_proc_request(kproc->tsp); if (ret < 0) return dev_err_probe(dev, ret, "ti_sci_proc_request failed\n"); ret = devm_add_action_or_reset(dev, k3_release_tsp, kproc->tsp); if (ret) return ret; ret = k3_rproc_of_get_memories(pdev, kproc); if (ret) return ret; ret = k3_reserved_mem_init(kproc); if (ret) return dev_err_probe(dev, ret, "reserved memory init failed\n"); ret = kproc->ti_sci->ops.dev_ops.is_on(kproc->ti_sci, kproc->ti_sci_id, &r_state, &p_state); if (ret) return dev_err_probe(dev, ret, "failed to get initial state, mode cannot be determined\n"); /* configure devices for either remoteproc or IPC-only mode */ if (p_state) { rproc->state = RPROC_DETACHED; dev_info(dev, "configured M4F for IPC-only mode\n"); } else { dev_info(dev, "configured M4F for remoteproc mode\n"); } ret = k3_rproc_request_mbox(rproc); if (ret) return ret; ret = devm_rproc_add(dev, rproc); if (ret) return dev_err_probe(dev, ret, "failed to register device with remoteproc core\n"); return 0; } static const struct k3_rproc_mem_data am64_m4_mems[] = { { .name = "iram", .dev_addr = 0x0 }, { .name = "dram", .dev_addr = 0x30000 }, }; static const struct k3_rproc_dev_data am64_m4_data = { .mems = am64_m4_mems, .num_mems = ARRAY_SIZE(am64_m4_mems), .boot_align_addr = SZ_1K, .uses_lreset = true, }; static const struct of_device_id k3_m4_of_match[] = { { .compatible = "ti,am64-m4fss", .data = &am64_m4_data, }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, k3_m4_of_match); static struct platform_driver k3_m4_rproc_driver = { .probe = k3_m4_rproc_probe, .driver = { .name = "k3-m4-rproc", .of_match_table = k3_m4_of_match, }, }; module_platform_driver(k3_m4_rproc_driver); MODULE_AUTHOR("Hari Nagalla "); MODULE_DESCRIPTION("TI K3 M4 Remoteproc driver"); MODULE_LICENSE("GPL");