brintos

brintos / linux-shallow public Read only

0
0
Text · 4.7 KiB · ff6ceb4 Raw
229 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * AMD Secure Processor device driver4 *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_CCP37		.ccp_vdata = &ccpv3_platform,38#endif39	},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	else150		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_PM188static 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#endif205 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_new = sp_platform_remove,214#ifdef CONFIG_PM215	.suspend = sp_platform_suspend,216	.resume = sp_platform_resume,217#endif218};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}229