Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * CDX host controller driver for AMD versal-net platform.
  4 *
  5 * Copyright (C) 2022-2023, Advanced Micro Devices, Inc.
  6 */
  7
  8#include <linux/mod_devicetable.h>
  9#include <linux/platform_device.h>
 10#include <linux/slab.h>
 11#include <linux/cdx/cdx_bus.h>
 12
 13#include "cdx_controller.h"
 14#include "../cdx.h"
 15#include "mcdi_functions.h"
 16#include "mcdi.h"
 17
 18static unsigned int cdx_mcdi_rpc_timeout(struct cdx_mcdi *cdx, unsigned int cmd)
 19{
 20	return MCDI_RPC_TIMEOUT;
 21}
 22
 23static void cdx_mcdi_request(struct cdx_mcdi *cdx,
 24			     const struct cdx_dword *hdr, size_t hdr_len,
 25			     const struct cdx_dword *sdu, size_t sdu_len)
 26{
 27	if (cdx_rpmsg_send(cdx, hdr, hdr_len, sdu, sdu_len))
 28		dev_err(&cdx->rpdev->dev, "Failed to send rpmsg data\n");
 29}
 30
 31static const struct cdx_mcdi_ops mcdi_ops = {
 32	.mcdi_rpc_timeout = cdx_mcdi_rpc_timeout,
 33	.mcdi_request = cdx_mcdi_request,
 34};
 35
 36static int cdx_bus_enable(struct cdx_controller *cdx, u8 bus_num)
 37{
 38	return cdx_mcdi_bus_enable(cdx->priv, bus_num);
 39}
 40
 41static int cdx_bus_disable(struct cdx_controller *cdx, u8 bus_num)
 42{
 43	return cdx_mcdi_bus_disable(cdx->priv, bus_num);
 44}
 45
 46void cdx_rpmsg_post_probe(struct cdx_controller *cdx)
 47{
 48	/* Register CDX controller with CDX bus driver */
 49	if (cdx_register_controller(cdx))
 50		dev_err(cdx->dev, "Failed to register CDX controller\n");
 51}
 52
 53void cdx_rpmsg_pre_remove(struct cdx_controller *cdx)
 54{
 55	cdx_unregister_controller(cdx);
 56	cdx_mcdi_wait_for_quiescence(cdx->priv, MCDI_RPC_TIMEOUT);
 57}
 58
 59static int cdx_configure_device(struct cdx_controller *cdx,
 60				u8 bus_num, u8 dev_num,
 61				struct cdx_device_config *dev_config)
 62{
 63	int ret = 0;
 64
 65	switch (dev_config->type) {
 66	case CDX_DEV_RESET_CONF:
 67		ret = cdx_mcdi_reset_device(cdx->priv, bus_num, dev_num);
 68		break;
 69	case CDX_DEV_BUS_MASTER_CONF:
 70		ret = cdx_mcdi_bus_master_enable(cdx->priv, bus_num, dev_num,
 71						 dev_config->bus_master_enable);
 72		break;
 73	default:
 74		ret = -EINVAL;
 75	}
 76
 77	return ret;
 78}
 79
 80static int cdx_scan_devices(struct cdx_controller *cdx)
 81{
 82	struct cdx_mcdi *cdx_mcdi = cdx->priv;
 83	u8 bus_num, dev_num, num_cdx_bus;
 84	int ret;
 85
 86	/* MCDI FW Read: Fetch the number of CDX buses on this controller */
 87	ret = cdx_mcdi_get_num_buses(cdx_mcdi);
 88	if (ret < 0) {
 89		dev_err(cdx->dev,
 90			"Get number of CDX buses failed: %d\n", ret);
 91		return ret;
 92	}
 93	num_cdx_bus = (u8)ret;
 94
 95	for (bus_num = 0; bus_num < num_cdx_bus; bus_num++) {
 96		struct device *bus_dev;
 97		u8 num_cdx_dev;
 98
 99		/* Add the bus on cdx subsystem */
100		bus_dev = cdx_bus_add(cdx, bus_num);
101		if (!bus_dev)
102			continue;
103
104		/* MCDI FW Read: Fetch the number of devices present */
105		ret = cdx_mcdi_get_num_devs(cdx_mcdi, bus_num);
106		if (ret < 0) {
107			dev_err(cdx->dev,
108				"Get devices on CDX bus %d failed: %d\n", bus_num, ret);
109			continue;
110		}
111		num_cdx_dev = (u8)ret;
112
113		for (dev_num = 0; dev_num < num_cdx_dev; dev_num++) {
114			struct cdx_dev_params dev_params;
115
116			/* MCDI FW: Get the device config */
117			ret = cdx_mcdi_get_dev_config(cdx_mcdi, bus_num,
118						      dev_num, &dev_params);
119			if (ret) {
120				dev_err(cdx->dev,
121					"CDX device config get failed for %d(bus):%d(dev), %d\n",
122					bus_num, dev_num, ret);
123				continue;
124			}
125			dev_params.cdx = cdx;
126			dev_params.parent = bus_dev;
127
128			/* Add the device to the cdx bus */
129			ret = cdx_device_add(&dev_params);
130			if (ret) {
131				dev_err(cdx->dev, "registering cdx dev: %d failed: %d\n",
132					dev_num, ret);
133				continue;
134			}
135
136			dev_dbg(cdx->dev, "CDX dev: %d on cdx bus: %d created\n",
137				dev_num, bus_num);
138		}
139	}
140
141	return 0;
142}
143
144static struct cdx_ops cdx_ops = {
145	.bus_enable		= cdx_bus_enable,
146	.bus_disable	= cdx_bus_disable,
147	.scan		= cdx_scan_devices,
148	.dev_configure	= cdx_configure_device,
149};
150
151static int xlnx_cdx_probe(struct platform_device *pdev)
152{
153	struct cdx_controller *cdx;
154	struct cdx_mcdi *cdx_mcdi;
155	int ret;
156
157	cdx_mcdi = kzalloc(sizeof(*cdx_mcdi), GFP_KERNEL);
158	if (!cdx_mcdi)
159		return -ENOMEM;
160
161	/* Store the MCDI ops */
162	cdx_mcdi->mcdi_ops = &mcdi_ops;
163	/* MCDI FW: Initialize the FW path */
164	ret = cdx_mcdi_init(cdx_mcdi);
165	if (ret) {
166		dev_err_probe(&pdev->dev, ret, "MCDI Initialization failed\n");
167		goto mcdi_init_fail;
168	}
169
170	cdx = kzalloc(sizeof(*cdx), GFP_KERNEL);
171	if (!cdx) {
172		ret = -ENOMEM;
173		goto cdx_alloc_fail;
174	}
175	platform_set_drvdata(pdev, cdx);
176
177	cdx->dev = &pdev->dev;
178	cdx->priv = cdx_mcdi;
179	cdx->ops = &cdx_ops;
180
181	ret = cdx_setup_rpmsg(pdev);
182	if (ret) {
183		if (ret != -EPROBE_DEFER)
184			dev_err(&pdev->dev, "Failed to register CDX RPMsg transport\n");
185		goto cdx_rpmsg_fail;
186	}
187
188	dev_info(&pdev->dev, "Successfully registered CDX controller with RPMsg as transport\n");
189	return 0;
190
191cdx_rpmsg_fail:
192	kfree(cdx);
193cdx_alloc_fail:
194	cdx_mcdi_finish(cdx_mcdi);
195mcdi_init_fail:
196	kfree(cdx_mcdi);
197
198	return ret;
199}
200
201static int xlnx_cdx_remove(struct platform_device *pdev)
202{
203	struct cdx_controller *cdx = platform_get_drvdata(pdev);
204	struct cdx_mcdi *cdx_mcdi = cdx->priv;
205
206	cdx_destroy_rpmsg(pdev);
207
208	kfree(cdx);
209
210	cdx_mcdi_finish(cdx_mcdi);
211	kfree(cdx_mcdi);
212
213	return 0;
214}
215
216static const struct of_device_id cdx_match_table[] = {
217	{.compatible = "xlnx,versal-net-cdx",},
218	{ },
219};
220
221MODULE_DEVICE_TABLE(of, cdx_match_table);
222
223static struct platform_driver cdx_pdriver = {
224	.driver = {
225		   .name = "cdx-controller",
226		   .pm = NULL,
227		   .of_match_table = cdx_match_table,
228		   },
229	.probe = xlnx_cdx_probe,
230	.remove = xlnx_cdx_remove,
231};
232
233static int __init cdx_controller_init(void)
234{
235	int ret;
236
237	ret = platform_driver_register(&cdx_pdriver);
238	if (ret)
239		pr_err("platform_driver_register() failed: %d\n", ret);
240
241	return ret;
242}
243
244static void __exit cdx_controller_exit(void)
245{
246	platform_driver_unregister(&cdx_pdriver);
247}
248
249module_init(cdx_controller_init);
250module_exit(cdx_controller_exit);
251
252MODULE_AUTHOR("AMD Inc.");
253MODULE_DESCRIPTION("CDX controller for AMD devices");
254MODULE_LICENSE("GPL");
255MODULE_IMPORT_NS(CDX_BUS_CONTROLLER);