blob: 1b45236e371617f770e1663995ad96248978f389 [file] [log] [blame]
Thomas Gleixnerd2912cb2019-06-04 10:11:33 +02001// SPDX-License-Identifier: GPL-2.0-only
Tom Lendackyc4f4b322014-06-05 10:17:57 -05002/*
Brijesh Singhd0ebbc02017-07-06 09:59:16 -05003 * AMD Secure Processor device driver
Tom Lendackyc4f4b322014-06-05 10:17:57 -05004 *
Hook, Garyfa5cd1c2018-12-18 15:48:29 +00005 * Copyright (C) 2014,2018 Advanced Micro Devices, Inc.
Tom Lendackyc4f4b322014-06-05 10:17:57 -05006 *
7 * Author: Tom Lendacky <thomas.lendacky@amd.com>
Tom Lendackyc4f4b322014-06-05 10:17:57 -05008 */
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>
Tom Lendacky126ae9a2014-07-10 10:58:35 -050022#include <linux/of.h>
Tom Lendacky6c506342015-02-03 13:07:29 -060023#include <linux/of_address.h>
24#include <linux/acpi.h>
Tom Lendackyc4f4b322014-06-05 10:17:57 -050025
26#include "ccp-dev.h"
27
Brijesh Singhd0ebbc02017-07-06 09:59:16 -050028struct sp_platform {
Tom Lendacky6c506342015-02-03 13:07:29 -060029 int coherent;
Brijesh Singhf4d18d62017-07-06 09:59:15 -050030 unsigned int irq_count;
Tom Lendacky6c506342015-02-03 13:07:29 -060031};
32
Nathan Chancellor3512dcb2018-09-24 10:26:15 -070033static 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#ifdef CONFIG_ACPI
43static const struct acpi_device_id sp_acpi_match[] = {
44 { "AMDI0C00", (kernel_ulong_t)&dev_vdata[0] },
45 { },
46};
47MODULE_DEVICE_TABLE(acpi, sp_acpi_match);
48#endif
49
50#ifdef CONFIG_OF
51static const struct of_device_id sp_of_match[] = {
52 { .compatible = "amd,ccp-seattle-v1a",
53 .data = (const void *)&dev_vdata[0] },
54 { },
55};
56MODULE_DEVICE_TABLE(of, sp_of_match);
57#endif
Gary R Hookc7019c42016-03-01 13:49:15 -060058
Brijesh Singhd0ebbc02017-07-06 09:59:16 -050059static struct sp_dev_vdata *sp_get_of_version(struct platform_device *pdev)
Gary R Hookc7019c42016-03-01 13:49:15 -060060{
61#ifdef CONFIG_OF
62 const struct of_device_id *match;
63
Brijesh Singhd0ebbc02017-07-06 09:59:16 -050064 match = of_match_node(sp_of_match, pdev->dev.of_node);
Gary R Hookc7019c42016-03-01 13:49:15 -060065 if (match && match->data)
Brijesh Singh720419f2017-07-06 09:59:14 -050066 return (struct sp_dev_vdata *)match->data;
Gary R Hookc7019c42016-03-01 13:49:15 -060067#endif
pjambhlekar9d1fb192017-05-03 09:32:09 +053068 return NULL;
Gary R Hookc7019c42016-03-01 13:49:15 -060069}
70
Brijesh Singhd0ebbc02017-07-06 09:59:16 -050071static struct sp_dev_vdata *sp_get_acpi_version(struct platform_device *pdev)
Gary R Hookc7019c42016-03-01 13:49:15 -060072{
73#ifdef CONFIG_ACPI
74 const struct acpi_device_id *match;
75
Brijesh Singhd0ebbc02017-07-06 09:59:16 -050076 match = acpi_match_device(sp_acpi_match, &pdev->dev);
Gary R Hookc7019c42016-03-01 13:49:15 -060077 if (match && match->driver_data)
Brijesh Singh720419f2017-07-06 09:59:14 -050078 return (struct sp_dev_vdata *)match->driver_data;
Gary R Hookc7019c42016-03-01 13:49:15 -060079#endif
pjambhlekar9d1fb192017-05-03 09:32:09 +053080 return NULL;
Gary R Hookc7019c42016-03-01 13:49:15 -060081}
82
Brijesh Singhd0ebbc02017-07-06 09:59:16 -050083static int sp_get_irqs(struct sp_device *sp)
Tom Lendackyc4f4b322014-06-05 10:17:57 -050084{
Brijesh Singhd0ebbc02017-07-06 09:59:16 -050085 struct sp_platform *sp_platform = sp->dev_specific;
Brijesh Singhf4d18d62017-07-06 09:59:15 -050086 struct device *dev = sp->dev;
Geliang Tangc6c59bf2015-12-23 20:49:01 +080087 struct platform_device *pdev = to_platform_device(dev);
Brijesh Singhf4d18d62017-07-06 09:59:15 -050088 unsigned int i, count;
Tom Lendackyc4f4b322014-06-05 10:17:57 -050089 int ret;
90
Brijesh Singhf4d18d62017-07-06 09:59:15 -050091 for (i = 0, count = 0; i < pdev->num_resources; i++) {
92 struct resource *res = &pdev->resource[i];
93
94 if (resource_type(res) == IORESOURCE_IRQ)
95 count++;
96 }
97
Brijesh Singhd0ebbc02017-07-06 09:59:16 -050098 sp_platform->irq_count = count;
Brijesh Singhf4d18d62017-07-06 09:59:15 -050099
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500100 ret = platform_get_irq(pdev, 0);
Gustavo A. R. Silva28a2cc62017-06-30 00:59:52 -0500101 if (ret < 0) {
102 dev_notice(dev, "unable to get IRQ (%d)\n", ret);
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500103 return ret;
Gustavo A. R. Silva28a2cc62017-06-30 00:59:52 -0500104 }
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500105
Brijesh Singhf4d18d62017-07-06 09:59:15 -0500106 sp->psp_irq = ret;
107 if (count == 1) {
108 sp->ccp_irq = ret;
109 } else {
110 ret = platform_get_irq(pdev, 1);
111 if (ret < 0) {
112 dev_notice(dev, "unable to get IRQ (%d)\n", ret);
113 return ret;
114 }
115
116 sp->ccp_irq = ret;
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500117 }
118
119 return 0;
120}
121
Brijesh Singhd0ebbc02017-07-06 09:59:16 -0500122static int sp_platform_probe(struct platform_device *pdev)
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500123{
Brijesh Singh720419f2017-07-06 09:59:14 -0500124 struct sp_device *sp;
Brijesh Singhd0ebbc02017-07-06 09:59:16 -0500125 struct sp_platform *sp_platform;
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500126 struct device *dev = &pdev->dev;
Suthikulpanit, Suravee1831eff2015-10-28 15:50:50 -0700127 enum dev_dma_attr attr;
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500128 struct resource *ior;
129 int ret;
130
131 ret = -ENOMEM;
Brijesh Singh720419f2017-07-06 09:59:14 -0500132 sp = sp_alloc_struct(dev);
133 if (!sp)
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500134 goto e_err;
135
Brijesh Singhd0ebbc02017-07-06 09:59:16 -0500136 sp_platform = devm_kzalloc(dev, sizeof(*sp_platform), GFP_KERNEL);
137 if (!sp_platform)
Tom Lendacky6c506342015-02-03 13:07:29 -0600138 goto e_err;
139
Brijesh Singhd0ebbc02017-07-06 09:59:16 -0500140 sp->dev_specific = sp_platform;
141 sp->dev_vdata = pdev->dev.of_node ? sp_get_of_version(pdev)
142 : sp_get_acpi_version(pdev);
Brijesh Singh720419f2017-07-06 09:59:14 -0500143 if (!sp->dev_vdata) {
Gary R Hookc7019c42016-03-01 13:49:15 -0600144 ret = -ENODEV;
145 dev_err(dev, "missing driver data\n");
146 goto e_err;
147 }
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500148
Brijesh Singh970e8302017-07-06 09:59:13 -0500149 ior = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Brijesh Singh720419f2017-07-06 09:59:14 -0500150 sp->io_map = devm_ioremap_resource(dev, ior);
151 if (IS_ERR(sp->io_map)) {
152 ret = PTR_ERR(sp->io_map);
Tom Lendackybe03a3a2015-02-03 13:07:23 -0600153 goto e_err;
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500154 }
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500155
Suthikulpanit, Suravee1831eff2015-10-28 15:50:50 -0700156 attr = device_get_dma_attr(dev);
157 if (attr == DEV_DMA_NOT_SUPPORTED) {
158 dev_err(dev, "DMA is not supported");
159 goto e_err;
160 }
161
Brijesh Singhd0ebbc02017-07-06 09:59:16 -0500162 sp_platform->coherent = (attr == DEV_DMA_COHERENT);
163 if (sp_platform->coherent)
Brijesh Singh720419f2017-07-06 09:59:14 -0500164 sp->axcache = CACHE_WB_NO_ALLOC;
Suthikulpanit, Suravee1831eff2015-10-28 15:50:50 -0700165 else
Brijesh Singh720419f2017-07-06 09:59:14 -0500166 sp->axcache = CACHE_NONE;
Suthikulpanit, Suravee1831eff2015-10-28 15:50:50 -0700167
Tom Lendacky261bf072015-02-03 13:07:17 -0600168 ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
169 if (ret) {
170 dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n", ret);
Tom Lendackybe03a3a2015-02-03 13:07:23 -0600171 goto e_err;
Tom Lendacky261bf072015-02-03 13:07:17 -0600172 }
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500173
Brijesh Singhd0ebbc02017-07-06 09:59:16 -0500174 ret = sp_get_irqs(sp);
Brijesh Singhf4d18d62017-07-06 09:59:15 -0500175 if (ret)
176 goto e_err;
177
Brijesh Singh720419f2017-07-06 09:59:14 -0500178 dev_set_drvdata(dev, sp);
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500179
Brijesh Singh720419f2017-07-06 09:59:14 -0500180 ret = sp_init(sp);
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500181 if (ret)
Tom Lendackybe03a3a2015-02-03 13:07:23 -0600182 goto e_err;
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500183
184 dev_notice(dev, "enabled\n");
185
186 return 0;
187
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500188e_err:
189 dev_notice(dev, "initialization failed\n");
190 return ret;
191}
192
Brijesh Singhd0ebbc02017-07-06 09:59:16 -0500193static int sp_platform_remove(struct platform_device *pdev)
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500194{
195 struct device *dev = &pdev->dev;
Brijesh Singh720419f2017-07-06 09:59:14 -0500196 struct sp_device *sp = dev_get_drvdata(dev);
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500197
Brijesh Singh720419f2017-07-06 09:59:14 -0500198 sp_destroy(sp);
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500199
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500200 dev_notice(dev, "disabled\n");
201
202 return 0;
203}
204
205#ifdef CONFIG_PM
Brijesh Singhd0ebbc02017-07-06 09:59:16 -0500206static int sp_platform_suspend(struct platform_device *pdev,
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500207 pm_message_t state)
208{
209 struct device *dev = &pdev->dev;
Brijesh Singh720419f2017-07-06 09:59:14 -0500210 struct sp_device *sp = dev_get_drvdata(dev);
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500211
Brijesh Singh720419f2017-07-06 09:59:14 -0500212 return sp_suspend(sp, state);
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500213}
214
Brijesh Singhd0ebbc02017-07-06 09:59:16 -0500215static int sp_platform_resume(struct platform_device *pdev)
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500216{
217 struct device *dev = &pdev->dev;
Brijesh Singh720419f2017-07-06 09:59:14 -0500218 struct sp_device *sp = dev_get_drvdata(dev);
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500219
Brijesh Singh720419f2017-07-06 09:59:14 -0500220 return sp_resume(sp);
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500221}
222#endif
223
Brijesh Singhd0ebbc02017-07-06 09:59:16 -0500224static struct platform_driver sp_platform_driver = {
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500225 .driver = {
Tom Lendacky166db192015-10-01 16:32:50 -0500226 .name = "ccp",
Tom Lendacky6c506342015-02-03 13:07:29 -0600227#ifdef CONFIG_ACPI
Brijesh Singhd0ebbc02017-07-06 09:59:16 -0500228 .acpi_match_table = sp_acpi_match,
Tom Lendacky6c506342015-02-03 13:07:29 -0600229#endif
230#ifdef CONFIG_OF
Brijesh Singhd0ebbc02017-07-06 09:59:16 -0500231 .of_match_table = sp_of_match,
Tom Lendacky6c506342015-02-03 13:07:29 -0600232#endif
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500233 },
Brijesh Singhd0ebbc02017-07-06 09:59:16 -0500234 .probe = sp_platform_probe,
235 .remove = sp_platform_remove,
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500236#ifdef CONFIG_PM
Brijesh Singhd0ebbc02017-07-06 09:59:16 -0500237 .suspend = sp_platform_suspend,
238 .resume = sp_platform_resume,
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500239#endif
240};
241
Brijesh Singhd0ebbc02017-07-06 09:59:16 -0500242int sp_platform_init(void)
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500243{
Brijesh Singhd0ebbc02017-07-06 09:59:16 -0500244 return platform_driver_register(&sp_platform_driver);
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500245}
246
Brijesh Singhd0ebbc02017-07-06 09:59:16 -0500247void sp_platform_exit(void)
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500248{
Brijesh Singhd0ebbc02017-07-06 09:59:16 -0500249 platform_driver_unregister(&sp_platform_driver);
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500250}