Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  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 <thomas.lendacky@amd.com>
  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
 28struct sp_platform {
 29	int coherent;
 30	unsigned int irq_count;
 31};
 32
 33static 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
 42static const struct acpi_device_id sp_acpi_match[] = {
 43	{ "AMDI0C00", (kernel_ulong_t)&dev_vdata[0] },
 44	{ },
 45};
 46MODULE_DEVICE_TABLE(acpi, sp_acpi_match);
 47
 48static const struct of_device_id sp_of_match[] = {
 49	{ .compatible = "amd,ccp-seattle-v1a",
 50	  .data = (const void *)&dev_vdata[0] },
 51	{ },
 52};
 53MODULE_DEVICE_TABLE(of, sp_of_match);
 54
 55static 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
 66static 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
 77static 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
108static 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
172e_err:
173	dev_notice(dev, "initialization failed\n");
174	return ret;
175}
176
177static 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
188static 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
197static 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
206static 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
220int sp_platform_init(void)
221{
222	return platform_driver_register(&sp_platform_driver);
223}
224
225void sp_platform_exit(void)
226{
227	platform_driver_unregister(&sp_platform_driver);
228}