156893Sfenner// SPDX-License-Identifier: GPL-2.0-only 256893Sfenner/* 356893Sfenner * AMD Secure Processor device driver 456893Sfenner * 556893Sfenner * Copyright (C) 2014,2018 Advanced Micro Devices, Inc. 656893Sfenner * 756893Sfenner * Author: Tom Lendacky <thomas.lendacky@amd.com> 856893Sfenner */ 956893Sfenner 1056893Sfenner#include <linux/module.h> 1156893Sfenner#include <linux/kernel.h> 1256893Sfenner#include <linux/device.h> 1356893Sfenner#include <linux/platform_device.h> 1456893Sfenner#include <linux/ioport.h> 1556893Sfenner#include <linux/dma-mapping.h> 1656893Sfenner#include <linux/kthread.h> 1756893Sfenner#include <linux/sched.h> 1856893Sfenner#include <linux/interrupt.h> 1956893Sfenner#include <linux/spinlock.h> 2056893Sfenner#include <linux/delay.h> 2156893Sfenner#include <linux/ccp.h> 2256893Sfenner#include <linux/of.h> 2356893Sfenner#include <linux/of_address.h> 2456893Sfenner#include <linux/acpi.h> 2556893Sfenner 2656893Sfenner#include "ccp-dev.h" 2756893Sfenner 2856893Sfennerstruct sp_platform { 2956893Sfenner int coherent; 3056893Sfenner unsigned int irq_count; 3156893Sfenner}; 3256893Sfenner 3356893Sfennerstatic const struct sp_dev_vdata dev_vdata[] = { 3456893Sfenner { 3556893Sfenner .bar = 0, 3656893Sfenner#ifdef CONFIG_CRYPTO_DEV_SP_CCP 3756893Sfenner .ccp_vdata = &ccpv3_platform, 3856893Sfenner#endif 3956893Sfenner }, 4056893Sfenner}; 4156893Sfenner 4256893Sfenner#ifdef CONFIG_ACPI 4356893Sfennerstatic const struct acpi_device_id sp_acpi_match[] = { 4456893Sfenner { "AMDI0C00", (kernel_ulong_t)&dev_vdata[0] }, 4556893Sfenner { }, 4656893Sfenner}; 4756893SfennerMODULE_DEVICE_TABLE(acpi, sp_acpi_match); 4856893Sfenner#endif 4956893Sfenner 5056893Sfenner#ifdef CONFIG_OF 5156893Sfennerstatic const struct of_device_id sp_of_match[] = { 5256893Sfenner { .compatible = "amd,ccp-seattle-v1a", 5356893Sfenner .data = (const void *)&dev_vdata[0] }, 5456893Sfenner { }, 5556893Sfenner}; 5656893SfennerMODULE_DEVICE_TABLE(of, sp_of_match); 5756893Sfenner#endif 5856893Sfenner 5956893Sfennerstatic struct sp_dev_vdata *sp_get_of_version(struct platform_device *pdev) 6056893Sfenner{ 6156893Sfenner#ifdef CONFIG_OF 6256893Sfenner const struct of_device_id *match; 6356893Sfenner 6456893Sfenner match = of_match_node(sp_of_match, pdev->dev.of_node); 6556893Sfenner if (match && match->data) 6656893Sfenner return (struct sp_dev_vdata *)match->data; 6756893Sfenner#endif 6856893Sfenner return NULL; 6956893Sfenner} 7056893Sfenner 7156893Sfennerstatic struct sp_dev_vdata *sp_get_acpi_version(struct platform_device *pdev) 7256893Sfenner{ 7356893Sfenner#ifdef CONFIG_ACPI 7456893Sfenner const struct acpi_device_id *match; 7556893Sfenner 7656893Sfenner match = acpi_match_device(sp_acpi_match, &pdev->dev); 7756893Sfenner if (match && match->driver_data) 7856893Sfenner return (struct sp_dev_vdata *)match->driver_data; 7956893Sfenner#endif 8056893Sfenner return NULL; 8156893Sfenner} 8256893Sfenner 8356893Sfennerstatic int sp_get_irqs(struct sp_device *sp) 8456893Sfenner{ 8556893Sfenner struct sp_platform *sp_platform = sp->dev_specific; 8656893Sfenner struct device *dev = sp->dev; 8756893Sfenner struct platform_device *pdev = to_platform_device(dev); 8856893Sfenner int ret; 8956893Sfenner 9056893Sfenner sp_platform->irq_count = platform_irq_count(pdev); 9156893Sfenner 9256893Sfenner ret = platform_get_irq(pdev, 0); 9356893Sfenner if (ret < 0) { 9456893Sfenner dev_notice(dev, "unable to get IRQ (%d)\n", ret); 9556893Sfenner return ret; 9656893Sfenner } 9756893Sfenner 9856893Sfenner sp->psp_irq = ret; 9956893Sfenner if (sp_platform->irq_count == 1) { 10056893Sfenner sp->ccp_irq = ret; 10156893Sfenner } else { 10256893Sfenner ret = platform_get_irq(pdev, 1); 10356893Sfenner if (ret < 0) { 10456893Sfenner dev_notice(dev, "unable to get IRQ (%d)\n", ret); 10556893Sfenner return ret; 10656893Sfenner } 10756893Sfenner 10856893Sfenner sp->ccp_irq = ret; 10956893Sfenner } 11056893Sfenner 11156893Sfenner return 0; 11256893Sfenner} 11356893Sfenner 11456893Sfennerstatic int sp_platform_probe(struct platform_device *pdev) 11556893Sfenner{ 11656893Sfenner struct sp_device *sp; 11756893Sfenner struct sp_platform *sp_platform; 11856893Sfenner struct device *dev = &pdev->dev; 11956893Sfenner enum dev_dma_attr attr; 12056893Sfenner int ret; 12156893Sfenner 12256893Sfenner ret = -ENOMEM; 12356893Sfenner sp = sp_alloc_struct(dev); 12456893Sfenner if (!sp) 12556893Sfenner goto e_err; 12656893Sfenner 12756893Sfenner sp_platform = devm_kzalloc(dev, sizeof(*sp_platform), GFP_KERNEL); 12856893Sfenner if (!sp_platform) 12956893Sfenner goto e_err; 13056893Sfenner 13156893Sfenner sp->dev_specific = sp_platform; 13256893Sfenner sp->dev_vdata = pdev->dev.of_node ? sp_get_of_version(pdev) 13356893Sfenner : sp_get_acpi_version(pdev); 13456893Sfenner if (!sp->dev_vdata) { 13556893Sfenner ret = -ENODEV; 13656893Sfenner dev_err(dev, "missing driver data\n"); 13756893Sfenner goto e_err; 13856893Sfenner } 13956893Sfenner 14056893Sfenner sp->io_map = devm_platform_ioremap_resource(pdev, 0); 14156893Sfenner if (IS_ERR(sp->io_map)) { 14256893Sfenner ret = PTR_ERR(sp->io_map); 14356893Sfenner goto e_err; 14456893Sfenner } 14556893Sfenner 14656893Sfenner attr = device_get_dma_attr(dev); 14756893Sfenner if (attr == DEV_DMA_NOT_SUPPORTED) { 14856893Sfenner dev_err(dev, "DMA is not supported"); 14956893Sfenner goto e_err; 15056893Sfenner } 15156893Sfenner 15256893Sfenner sp_platform->coherent = (attr == DEV_DMA_COHERENT); 15356893Sfenner if (sp_platform->coherent) 15456893Sfenner sp->axcache = CACHE_WB_NO_ALLOC; 15556893Sfenner else 15656893Sfenner sp->axcache = CACHE_NONE; 15756893Sfenner 15856893Sfenner ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48)); 15956893Sfenner if (ret) { 16056893Sfenner dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n", ret); 16156893Sfenner goto e_err; 16256893Sfenner } 16356893Sfenner 16456893Sfenner ret = sp_get_irqs(sp); 16556893Sfenner if (ret) 16656893Sfenner goto e_err; 16756893Sfenner 16856893Sfenner dev_set_drvdata(dev, sp); 16956893Sfenner 17056893Sfenner ret = sp_init(sp); 17156893Sfenner if (ret) 17256893Sfenner goto e_err; 17356893Sfenner 17456893Sfenner dev_notice(dev, "enabled\n"); 17556893Sfenner 17656893Sfenner return 0; 17756893Sfenner 17856893Sfennere_err: 17956893Sfenner dev_notice(dev, "initialization failed\n"); 18056893Sfenner return ret; 18156893Sfenner} 18256893Sfenner 18356893Sfennerstatic void sp_platform_remove(struct platform_device *pdev) 18456893Sfenner{ 18556893Sfenner struct device *dev = &pdev->dev; 18656893Sfenner struct sp_device *sp = dev_get_drvdata(dev); 18756893Sfenner 18856893Sfenner sp_destroy(sp); 18956893Sfenner 19056893Sfenner dev_notice(dev, "disabled\n"); 19156893Sfenner} 19256893Sfenner 19356893Sfenner#ifdef CONFIG_PM 19456893Sfennerstatic int sp_platform_suspend(struct platform_device *pdev, 19556893Sfenner pm_message_t state) 19656893Sfenner{ 19756893Sfenner struct device *dev = &pdev->dev; 19856893Sfenner struct sp_device *sp = dev_get_drvdata(dev); 19956893Sfenner 20056893Sfenner return sp_suspend(sp); 20156893Sfenner} 20256893Sfenner 20356893Sfennerstatic int sp_platform_resume(struct platform_device *pdev) 20456893Sfenner{ 20556893Sfenner struct device *dev = &pdev->dev; 20656893Sfenner struct sp_device *sp = dev_get_drvdata(dev); 20756893Sfenner 20856893Sfenner return sp_resume(sp); 20956893Sfenner} 21056893Sfenner#endif 21156893Sfenner 21256893Sfennerstatic struct platform_driver sp_platform_driver = { 21356893Sfenner .driver = { 21456893Sfenner .name = "ccp", 21556893Sfenner#ifdef CONFIG_ACPI 21656893Sfenner .acpi_match_table = sp_acpi_match, 21756893Sfenner#endif 21856893Sfenner#ifdef CONFIG_OF 21956893Sfenner .of_match_table = sp_of_match, 22056893Sfenner#endif 22156893Sfenner }, 22256893Sfenner .probe = sp_platform_probe, 22356893Sfenner .remove_new = sp_platform_remove, 22456893Sfenner#ifdef CONFIG_PM 22556893Sfenner .suspend = sp_platform_suspend, 22656893Sfenner .resume = sp_platform_resume, 22756893Sfenner#endif 22856893Sfenner}; 229 230int sp_platform_init(void) 231{ 232 return platform_driver_register(&sp_platform_driver); 233} 234 235void sp_platform_exit(void) 236{ 237 platform_driver_unregister(&sp_platform_driver); 238} 239