summaryrefslogtreecommitdiff
path: root/snd-alpx/alpx_xdma.c
blob: c6b4bf24219c989e94cef350ba2da704d676b9e7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// SPDX-License-Identifier: GPL-2.0-or-later
/*
*  Support for Digigram AlpX PCI-e boards
*
*  Copyright (c) 2024 Digigram Digital (info@digigram.com)
*/

#include <linux/version.h>

#include "alpx_xdma.h"


#if KERNEL_VERSION(6, 7, 0) > LINUX_VERSION_CODE
#include "core/generic/6.3/amd_xdma.h"
#include "include/6.3/amd_xdma.h"
#else
#include <linux/platform_data/amd_xdma.h>
#include <linux/dma/amd_xdma.h>
#endif


static struct xdma_chan_info alpx_xdma_chan_info[2] = {
	[0].dir = DMA_MEM_TO_DEV,
	[1].dir = DMA_DEV_TO_MEM,
};

struct alpx_xdma_platform_data {
	struct resource resources[2];
	struct dma_slave_map map[2];
	struct xdma_platdata platdata;
};

struct platform_device *alpx_xdma_register(struct pci_dev *pci_dev)
{
	struct alpx_xdma_platform_data *data;
	struct platform_device *xdma_pdev;
	int nvectors, vector, ret;

	data = devm_kzalloc(&pci_dev->dev, sizeof(*data), GFP_KERNEL);
	if (!data)
		return NULL;

	xdma_pdev = platform_device_alloc("xdma", PLATFORM_DEVID_AUTO);
	if (!xdma_pdev)
		return NULL;

	data->resources[0].start = pci_resource_start(pci_dev, 2);
	data->resources[0].end = pci_resource_end(pci_dev, 2);
	data->resources[0].flags = IORESOURCE_MEM;

	nvectors = pci_alloc_irq_vectors(pci_dev, 2, 2,
					 PCI_IRQ_MSIX | PCI_IRQ_MSI | PCI_IRQ_LEGACY);
	if (nvectors < 0)
		goto put_pdev;

	vector = pci_irq_vector(pci_dev, 0);
	data->resources[1].start = vector;
	data->resources[1].end = vector + nvectors - 1;
	data->resources[1].flags = IORESOURCE_IRQ;

	ret = platform_device_add_resources(xdma_pdev, data->resources,
					    ARRAY_SIZE(data->resources));
	if (ret)
		goto free_irq_vectors;

	data->map[0].devname = pci_name(pci_dev);
	data->map[0].slave = "h2c-0";
	data->map[0].param = &alpx_xdma_chan_info[0];

	data->map[1].devname = pci_name(pci_dev);
	data->map[1].slave = "c2h-0";
	data->map[1].param = &alpx_xdma_chan_info[1];

	data->platdata.max_dma_channels = 4;
	data->platdata.device_map = data->map;
	data->platdata.device_map_cnt = ARRAY_SIZE(data->map);

	ret = platform_device_add_data(xdma_pdev, &data->platdata, sizeof(data->platdata));
	if (ret)
		goto free_irq_vectors;

	xdma_pdev->dev.parent = &pci_dev->dev;

	ret = platform_device_add(xdma_pdev);
	if (ret)
		goto free_irq_vectors;

	return xdma_pdev;

free_irq_vectors:
	pci_free_irq_vectors(pci_dev);
put_pdev:
	platform_device_put(xdma_pdev);

	return NULL;
}

void alpx_xdma_unregister(struct pci_dev *pci_dev,
				 struct platform_device *xdma_pdev)
{
	platform_device_unregister(xdma_pdev);
	pci_free_irq_vectors(pci_dev);
}