1 // SPDX-License-Identifier: GPL-2.0
3 * Platform driver for CDX bus.
5 * Copyright (C) 2022-2023, Advanced Micro Devices, Inc.
8 #include <linux/rpmsg.h>
9 #include <linux/remoteproc.h>
11 #include <linux/platform_device.h>
12 #include <linux/cdx/cdx_bus.h>
13 #include <linux/module.h>
16 #include "cdx_controller.h"
17 #include "mcdi_functions.h"
20 static struct rpmsg_device_id cdx_rpmsg_id_table
[] = {
21 { .name
= "mcdi_ipc" },
24 MODULE_DEVICE_TABLE(rpmsg
, cdx_rpmsg_id_table
);
26 int cdx_rpmsg_send(struct cdx_mcdi
*cdx_mcdi
,
27 const struct cdx_dword
*hdr
, size_t hdr_len
,
28 const struct cdx_dword
*sdu
, size_t sdu_len
)
30 unsigned char *send_buf
;
33 send_buf
= kzalloc(hdr_len
+ sdu_len
, GFP_KERNEL
);
37 memcpy(send_buf
, hdr
, hdr_len
);
38 memcpy(send_buf
+ hdr_len
, sdu
, sdu_len
);
40 ret
= rpmsg_send(cdx_mcdi
->ept
, send_buf
, hdr_len
+ sdu_len
);
46 static int cdx_attach_to_rproc(struct platform_device
*pdev
)
48 struct device_node
*r5_core_node
;
49 struct cdx_controller
*cdx_c
;
50 struct cdx_mcdi
*cdx_mcdi
;
56 cdx_c
= platform_get_drvdata(pdev
);
57 cdx_mcdi
= cdx_c
->priv
;
59 r5_core_node
= of_parse_phandle(dev
->of_node
, "xlnx,rproc", 0);
61 dev_err(&pdev
->dev
, "xlnx,rproc: invalid phandle\n");
65 rp
= rproc_get_by_phandle(r5_core_node
->phandle
);
71 /* Attach to remote processor */
74 dev_err(&pdev
->dev
, "Failed to attach to remote processor\n");
79 cdx_mcdi
->r5_rproc
= rp
;
81 of_node_put(r5_core_node
);
85 static void cdx_detach_to_r5(struct platform_device
*pdev
)
87 struct cdx_controller
*cdx_c
;
88 struct cdx_mcdi
*cdx_mcdi
;
90 cdx_c
= platform_get_drvdata(pdev
);
91 cdx_mcdi
= cdx_c
->priv
;
93 rproc_detach(cdx_mcdi
->r5_rproc
);
94 rproc_put(cdx_mcdi
->r5_rproc
);
97 static int cdx_rpmsg_cb(struct rpmsg_device
*rpdev
, void *data
,
98 int len
, void *priv
, u32 src
)
100 struct cdx_controller
*cdx_c
= dev_get_drvdata(&rpdev
->dev
);
101 struct cdx_mcdi
*cdx_mcdi
= cdx_c
->priv
;
103 if (len
> MCDI_BUF_LEN
)
106 cdx_mcdi_process_cmd(cdx_mcdi
, (struct cdx_dword
*)data
, len
);
111 static void cdx_rpmsg_post_probe_work(struct work_struct
*work
)
113 struct cdx_controller
*cdx_c
;
114 struct cdx_mcdi
*cdx_mcdi
;
116 cdx_mcdi
= container_of(work
, struct cdx_mcdi
, work
);
117 cdx_c
= dev_get_drvdata(&cdx_mcdi
->rpdev
->dev
);
118 cdx_rpmsg_post_probe(cdx_c
);
121 static int cdx_rpmsg_probe(struct rpmsg_device
*rpdev
)
123 struct rpmsg_channel_info chinfo
= {0};
124 struct cdx_controller
*cdx_c
;
125 struct cdx_mcdi
*cdx_mcdi
;
127 cdx_c
= (struct cdx_controller
*)cdx_rpmsg_id_table
[0].driver_data
;
128 cdx_mcdi
= cdx_c
->priv
;
130 chinfo
.src
= RPMSG_ADDR_ANY
;
131 chinfo
.dst
= rpdev
->dst
;
132 strscpy(chinfo
.name
, cdx_rpmsg_id_table
[0].name
,
133 strlen(cdx_rpmsg_id_table
[0].name
));
135 cdx_mcdi
->ept
= rpmsg_create_ept(rpdev
, cdx_rpmsg_cb
, NULL
, chinfo
);
136 if (!cdx_mcdi
->ept
) {
137 dev_err_probe(&rpdev
->dev
, -ENXIO
,
138 "Failed to create ept for channel %s\n",
143 cdx_mcdi
->rpdev
= rpdev
;
144 dev_set_drvdata(&rpdev
->dev
, cdx_c
);
146 schedule_work(&cdx_mcdi
->work
);
150 static void cdx_rpmsg_remove(struct rpmsg_device
*rpdev
)
152 struct cdx_controller
*cdx_c
= dev_get_drvdata(&rpdev
->dev
);
153 struct cdx_mcdi
*cdx_mcdi
= cdx_c
->priv
;
155 flush_work(&cdx_mcdi
->work
);
156 cdx_rpmsg_pre_remove(cdx_c
);
158 rpmsg_destroy_ept(cdx_mcdi
->ept
);
159 dev_set_drvdata(&rpdev
->dev
, NULL
);
162 static struct rpmsg_driver cdx_rpmsg_driver
= {
163 .drv
.name
= KBUILD_MODNAME
,
164 .id_table
= cdx_rpmsg_id_table
,
165 .probe
= cdx_rpmsg_probe
,
166 .remove
= cdx_rpmsg_remove
,
167 .callback
= cdx_rpmsg_cb
,
170 int cdx_setup_rpmsg(struct platform_device
*pdev
)
172 struct cdx_controller
*cdx_c
;
173 struct cdx_mcdi
*cdx_mcdi
;
176 /* Attach to remote processor */
177 ret
= cdx_attach_to_rproc(pdev
);
181 cdx_c
= platform_get_drvdata(pdev
);
182 cdx_mcdi
= cdx_c
->priv
;
184 /* Register RPMsg driver */
185 cdx_rpmsg_id_table
[0].driver_data
= (kernel_ulong_t
)cdx_c
;
187 INIT_WORK(&cdx_mcdi
->work
, cdx_rpmsg_post_probe_work
);
188 ret
= register_rpmsg_driver(&cdx_rpmsg_driver
);
191 "Failed to register cdx RPMsg driver: %d\n", ret
);
192 cdx_detach_to_r5(pdev
);
198 void cdx_destroy_rpmsg(struct platform_device
*pdev
)
200 unregister_rpmsg_driver(&cdx_rpmsg_driver
);
202 cdx_detach_to_r5(pdev
);