Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/crypto/ccp/sp-platform.c
26282 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* AMD Secure Processor device driver
4
*
5
* Copyright (C) 2014,2018 Advanced Micro Devices, Inc.
6
*
7
* Author: Tom Lendacky <[email protected]>
8
*/
9
10
#include <linux/module.h>
11
#include <linux/kernel.h>
12
#include <linux/device.h>
13
#include <linux/platform_device.h>
14
#include <linux/ioport.h>
15
#include <linux/dma-mapping.h>
16
#include <linux/kthread.h>
17
#include <linux/sched.h>
18
#include <linux/interrupt.h>
19
#include <linux/spinlock.h>
20
#include <linux/delay.h>
21
#include <linux/ccp.h>
22
#include <linux/of.h>
23
#include <linux/of_address.h>
24
#include <linux/acpi.h>
25
26
#include "ccp-dev.h"
27
28
struct sp_platform {
29
int coherent;
30
unsigned int irq_count;
31
};
32
33
static const struct sp_dev_vdata dev_vdata[] = {
34
{
35
.bar = 0,
36
#ifdef CONFIG_CRYPTO_DEV_SP_CCP
37
.ccp_vdata = &ccpv3_platform,
38
#endif
39
},
40
};
41
42
static const struct acpi_device_id sp_acpi_match[] = {
43
{ "AMDI0C00", (kernel_ulong_t)&dev_vdata[0] },
44
{ },
45
};
46
MODULE_DEVICE_TABLE(acpi, sp_acpi_match);
47
48
static const struct of_device_id sp_of_match[] = {
49
{ .compatible = "amd,ccp-seattle-v1a",
50
.data = (const void *)&dev_vdata[0] },
51
{ },
52
};
53
MODULE_DEVICE_TABLE(of, sp_of_match);
54
55
static struct sp_dev_vdata *sp_get_of_version(struct platform_device *pdev)
56
{
57
const struct of_device_id *match;
58
59
match = of_match_node(sp_of_match, pdev->dev.of_node);
60
if (match && match->data)
61
return (struct sp_dev_vdata *)match->data;
62
63
return NULL;
64
}
65
66
static struct sp_dev_vdata *sp_get_acpi_version(struct platform_device *pdev)
67
{
68
const struct acpi_device_id *match;
69
70
match = acpi_match_device(sp_acpi_match, &pdev->dev);
71
if (match && match->driver_data)
72
return (struct sp_dev_vdata *)match->driver_data;
73
74
return NULL;
75
}
76
77
static int sp_get_irqs(struct sp_device *sp)
78
{
79
struct sp_platform *sp_platform = sp->dev_specific;
80
struct device *dev = sp->dev;
81
struct platform_device *pdev = to_platform_device(dev);
82
int ret;
83
84
sp_platform->irq_count = platform_irq_count(pdev);
85
86
ret = platform_get_irq(pdev, 0);
87
if (ret < 0) {
88
dev_notice(dev, "unable to get IRQ (%d)\n", ret);
89
return ret;
90
}
91
92
sp->psp_irq = ret;
93
if (sp_platform->irq_count == 1) {
94
sp->ccp_irq = ret;
95
} else {
96
ret = platform_get_irq(pdev, 1);
97
if (ret < 0) {
98
dev_notice(dev, "unable to get IRQ (%d)\n", ret);
99
return ret;
100
}
101
102
sp->ccp_irq = ret;
103
}
104
105
return 0;
106
}
107
108
static int sp_platform_probe(struct platform_device *pdev)
109
{
110
struct sp_device *sp;
111
struct sp_platform *sp_platform;
112
struct device *dev = &pdev->dev;
113
enum dev_dma_attr attr;
114
int ret;
115
116
ret = -ENOMEM;
117
sp = sp_alloc_struct(dev);
118
if (!sp)
119
goto e_err;
120
121
sp_platform = devm_kzalloc(dev, sizeof(*sp_platform), GFP_KERNEL);
122
if (!sp_platform)
123
goto e_err;
124
125
sp->dev_specific = sp_platform;
126
sp->dev_vdata = pdev->dev.of_node ? sp_get_of_version(pdev)
127
: sp_get_acpi_version(pdev);
128
if (!sp->dev_vdata) {
129
ret = -ENODEV;
130
dev_err(dev, "missing driver data\n");
131
goto e_err;
132
}
133
134
sp->io_map = devm_platform_ioremap_resource(pdev, 0);
135
if (IS_ERR(sp->io_map)) {
136
ret = PTR_ERR(sp->io_map);
137
goto e_err;
138
}
139
140
attr = device_get_dma_attr(dev);
141
if (attr == DEV_DMA_NOT_SUPPORTED) {
142
dev_err(dev, "DMA is not supported");
143
goto e_err;
144
}
145
146
sp_platform->coherent = (attr == DEV_DMA_COHERENT);
147
if (sp_platform->coherent)
148
sp->axcache = CACHE_WB_NO_ALLOC;
149
else
150
sp->axcache = CACHE_NONE;
151
152
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
153
if (ret) {
154
dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n", ret);
155
goto e_err;
156
}
157
158
ret = sp_get_irqs(sp);
159
if (ret)
160
goto e_err;
161
162
dev_set_drvdata(dev, sp);
163
164
ret = sp_init(sp);
165
if (ret)
166
goto e_err;
167
168
dev_notice(dev, "enabled\n");
169
170
return 0;
171
172
e_err:
173
dev_notice(dev, "initialization failed\n");
174
return ret;
175
}
176
177
static void sp_platform_remove(struct platform_device *pdev)
178
{
179
struct device *dev = &pdev->dev;
180
struct sp_device *sp = dev_get_drvdata(dev);
181
182
sp_destroy(sp);
183
184
dev_notice(dev, "disabled\n");
185
}
186
187
#ifdef CONFIG_PM
188
static int sp_platform_suspend(struct platform_device *pdev,
189
pm_message_t state)
190
{
191
struct device *dev = &pdev->dev;
192
struct sp_device *sp = dev_get_drvdata(dev);
193
194
return sp_suspend(sp);
195
}
196
197
static int sp_platform_resume(struct platform_device *pdev)
198
{
199
struct device *dev = &pdev->dev;
200
struct sp_device *sp = dev_get_drvdata(dev);
201
202
return sp_resume(sp);
203
}
204
#endif
205
206
static struct platform_driver sp_platform_driver = {
207
.driver = {
208
.name = "ccp",
209
.acpi_match_table = sp_acpi_match,
210
.of_match_table = sp_of_match,
211
},
212
.probe = sp_platform_probe,
213
.remove = sp_platform_remove,
214
#ifdef CONFIG_PM
215
.suspend = sp_platform_suspend,
216
.resume = sp_platform_resume,
217
#endif
218
};
219
220
int sp_platform_init(void)
221
{
222
return platform_driver_register(&sp_platform_driver);
223
}
224
225
void sp_platform_exit(void)
226
{
227
platform_driver_unregister(&sp_platform_driver);
228
}
229
230