1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * TI K3 DSP Remote Processor(s) driver
4 *
5 * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/
6 * Suman Anna <s-anna@ti.com>
7 */
8
9#include <linux/io.h>
10#include <linux/mailbox_client.h>
11#include <linux/module.h>
12#include <linux/of.h>
13#include <linux/of_reserved_mem.h>
14#include <linux/omap-mailbox.h>
15#include <linux/platform_device.h>
16#include <linux/remoteproc.h>
17#include <linux/reset.h>
18#include <linux/slab.h>
19
20#include "omap_remoteproc.h"
21#include "remoteproc_internal.h"
22#include "ti_sci_proc.h"
23#include "ti_k3_common.h"
24
25/*
26 * Power up the DSP remote processor.
27 *
28 * This function will be invoked only after the firmware for this rproc
29 * was loaded, parsed successfully, and all of its resource requirements
30 * were met. This callback is invoked only in remoteproc mode.
31 */
32static int k3_dsp_rproc_start(struct rproc *rproc)
33{
34 struct k3_rproc *kproc = rproc->priv;
35 struct device *dev = kproc->dev;
36 u32 boot_addr;
37 int ret;
38
39 boot_addr = rproc->bootaddr;
40 if (boot_addr & (kproc->data->boot_align_addr - 1)) {
41 dev_err(dev, "invalid boot address 0x%x, must be aligned on a 0x%x boundary\n",
42 boot_addr, kproc->data->boot_align_addr);
43 return -EINVAL;
44 }
45
46 dev_dbg(dev, "booting DSP core using boot addr = 0x%x\n", boot_addr);
47 ret = ti_sci_proc_set_config(tsp: kproc->tsp, boot_vector: boot_addr, cfg_set: 0, cfg_clr: 0);
48 if (ret)
49 return ret;
50
51 /* Call the K3 common start function after doing DSP specific stuff */
52 ret = k3_rproc_start(rproc);
53 if (ret)
54 return ret;
55
56 return 0;
57}
58
59static const struct rproc_ops k3_dsp_rproc_ops = {
60 .start = k3_dsp_rproc_start,
61 .stop = k3_rproc_stop,
62 .attach = k3_rproc_attach,
63 .detach = k3_rproc_detach,
64 .kick = k3_rproc_kick,
65 .da_to_va = k3_rproc_da_to_va,
66 .get_loaded_rsc_table = k3_get_loaded_rsc_table,
67};
68
69static int k3_dsp_rproc_probe(struct platform_device *pdev)
70{
71 struct device *dev = &pdev->dev;
72 struct device_node *np = dev->of_node;
73 const struct k3_rproc_dev_data *data;
74 struct k3_rproc *kproc;
75 struct rproc *rproc;
76 const char *fw_name;
77 bool p_state = false;
78 int ret = 0;
79
80 data = of_device_get_match_data(dev);
81 if (!data)
82 return -ENODEV;
83
84 ret = rproc_of_parse_firmware(dev, index: 0, fw_name: &fw_name);
85 if (ret)
86 return dev_err_probe(dev, err: ret, fmt: "failed to parse firmware-name property\n");
87
88 rproc = devm_rproc_alloc(dev, name: dev_name(dev), ops: &k3_dsp_rproc_ops,
89 firmware: fw_name, len: sizeof(*kproc));
90 if (!rproc)
91 return -ENOMEM;
92
93 rproc->has_iommu = false;
94 rproc->recovery_disabled = true;
95 if (data->uses_lreset) {
96 rproc->ops->prepare = k3_rproc_prepare;
97 rproc->ops->unprepare = k3_rproc_unprepare;
98 }
99 kproc = rproc->priv;
100 kproc->rproc = rproc;
101 kproc->dev = dev;
102 kproc->data = data;
103
104 ret = k3_rproc_request_mbox(rproc);
105 if (ret)
106 return ret;
107
108 kproc->ti_sci = devm_ti_sci_get_by_phandle(dev, property: "ti,sci");
109 if (IS_ERR(ptr: kproc->ti_sci))
110 return dev_err_probe(dev, err: PTR_ERR(ptr: kproc->ti_sci),
111 fmt: "failed to get ti-sci handle\n");
112
113 ret = of_property_read_u32(np, propname: "ti,sci-dev-id", out_value: &kproc->ti_sci_id);
114 if (ret)
115 return dev_err_probe(dev, err: ret, fmt: "missing 'ti,sci-dev-id' property\n");
116
117 kproc->reset = devm_reset_control_get_exclusive(dev, NULL);
118 if (IS_ERR(ptr: kproc->reset))
119 return dev_err_probe(dev, err: PTR_ERR(ptr: kproc->reset),
120 fmt: "failed to get reset\n");
121
122 kproc->tsp = ti_sci_proc_of_get_tsp(dev, sci: kproc->ti_sci);
123 if (IS_ERR(ptr: kproc->tsp))
124 return dev_err_probe(dev, err: PTR_ERR(ptr: kproc->tsp),
125 fmt: "failed to construct ti-sci proc control\n");
126
127 ret = ti_sci_proc_request(tsp: kproc->tsp);
128 if (ret < 0) {
129 dev_err_probe(dev, err: ret, fmt: "ti_sci_proc_request failed\n");
130 return ret;
131 }
132 ret = devm_add_action_or_reset(dev, k3_release_tsp, kproc->tsp);
133 if (ret)
134 return ret;
135
136 ret = k3_rproc_of_get_memories(pdev, kproc);
137 if (ret)
138 return ret;
139
140 ret = k3_reserved_mem_init(kproc);
141 if (ret)
142 return dev_err_probe(dev, err: ret, fmt: "reserved memory init failed\n");
143
144 ret = kproc->ti_sci->ops.dev_ops.is_on(kproc->ti_sci, kproc->ti_sci_id,
145 NULL, &p_state);
146 if (ret)
147 return dev_err_probe(dev, err: ret, fmt: "failed to get initial state, mode cannot be determined\n");
148
149 /* configure J721E devices for either remoteproc or IPC-only mode */
150 if (p_state) {
151 dev_info(dev, "configured DSP for IPC-only mode\n");
152 rproc->state = RPROC_DETACHED;
153 } else {
154 dev_info(dev, "configured DSP for remoteproc mode\n");
155 }
156
157 ret = devm_rproc_add(dev, rproc);
158 if (ret)
159 return dev_err_probe(dev, err: ret, fmt: "failed to add register device with remoteproc core\n");
160
161 platform_set_drvdata(pdev, data: kproc);
162
163 return 0;
164}
165
166static void k3_dsp_rproc_remove(struct platform_device *pdev)
167{
168 struct k3_rproc *kproc = platform_get_drvdata(pdev);
169 struct rproc *rproc = kproc->rproc;
170 struct device *dev = &pdev->dev;
171 int ret;
172
173 if (rproc->state == RPROC_ATTACHED) {
174 ret = rproc_detach(rproc);
175 if (ret)
176 dev_err(dev, "failed to detach proc (%pe)\n", ERR_PTR(ret));
177 }
178}
179
180static const struct k3_rproc_mem_data c66_mems[] = {
181 { .name = "l2sram", .dev_addr = 0x800000 },
182 { .name = "l1pram", .dev_addr = 0xe00000 },
183 { .name = "l1dram", .dev_addr = 0xf00000 },
184};
185
186/* C71x cores only have a L1P Cache, there are no L1P SRAMs */
187static const struct k3_rproc_mem_data c71_mems[] = {
188 { .name = "l2sram", .dev_addr = 0x800000 },
189 { .name = "l1dram", .dev_addr = 0xe00000 },
190};
191
192static const struct k3_rproc_mem_data c7xv_mems[] = {
193 { .name = "l2sram", .dev_addr = 0x800000 },
194};
195
196static const struct k3_rproc_dev_data c66_data = {
197 .mems = c66_mems,
198 .num_mems = ARRAY_SIZE(c66_mems),
199 .boot_align_addr = SZ_1K,
200 .uses_lreset = true,
201};
202
203static const struct k3_rproc_dev_data c71_data = {
204 .mems = c71_mems,
205 .num_mems = ARRAY_SIZE(c71_mems),
206 .boot_align_addr = SZ_2M,
207 .uses_lreset = false,
208};
209
210static const struct k3_rproc_dev_data c7xv_data = {
211 .mems = c7xv_mems,
212 .num_mems = ARRAY_SIZE(c7xv_mems),
213 .boot_align_addr = SZ_2M,
214 .uses_lreset = false,
215};
216
217static const struct of_device_id k3_dsp_of_match[] = {
218 { .compatible = "ti,j721e-c66-dsp", .data = &c66_data, },
219 { .compatible = "ti,j721e-c71-dsp", .data = &c71_data, },
220 { .compatible = "ti,j721s2-c71-dsp", .data = &c71_data, },
221 { .compatible = "ti,am62a-c7xv-dsp", .data = &c7xv_data, },
222 { /* sentinel */ },
223};
224MODULE_DEVICE_TABLE(of, k3_dsp_of_match);
225
226static struct platform_driver k3_dsp_rproc_driver = {
227 .probe = k3_dsp_rproc_probe,
228 .remove = k3_dsp_rproc_remove,
229 .driver = {
230 .name = "k3-dsp-rproc",
231 .of_match_table = k3_dsp_of_match,
232 },
233};
234
235module_platform_driver(k3_dsp_rproc_driver);
236
237MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
238MODULE_LICENSE("GPL v2");
239MODULE_DESCRIPTION("TI K3 DSP Remoteproc driver");
240

source code of linux/drivers/remoteproc/ti_k3_dsp_remoteproc.c