cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

tpm_tis_synquacer.c (4623B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2020 Linaro Ltd.
      4 *
      5 * This device driver implements MMIO TPM on SynQuacer Platform.
      6 */
      7#include <linux/acpi.h>
      8#include <linux/init.h>
      9#include <linux/module.h>
     10#include <linux/slab.h>
     11#include <linux/of.h>
     12#include <linux/of_device.h>
     13#include <linux/kernel.h>
     14#include "tpm.h"
     15#include "tpm_tis_core.h"
     16
     17/*
     18 * irq > 0 means: use irq $irq;
     19 * irq = 0 means: autoprobe for an irq;
     20 * irq = -1 means: no irq support
     21 */
     22struct tpm_tis_synquacer_info {
     23	struct resource res;
     24	int irq;
     25};
     26
     27struct tpm_tis_synquacer_phy {
     28	struct tpm_tis_data priv;
     29	void __iomem *iobase;
     30};
     31
     32static inline struct tpm_tis_synquacer_phy *to_tpm_tis_tcg_phy(struct tpm_tis_data *data)
     33{
     34	return container_of(data, struct tpm_tis_synquacer_phy, priv);
     35}
     36
     37static int tpm_tis_synquacer_read_bytes(struct tpm_tis_data *data, u32 addr,
     38					u16 len, u8 *result,
     39					enum tpm_tis_io_mode io_mode)
     40{
     41	struct tpm_tis_synquacer_phy *phy = to_tpm_tis_tcg_phy(data);
     42	switch (io_mode) {
     43	case TPM_TIS_PHYS_8:
     44		while (len--)
     45			*result++ = ioread8(phy->iobase + addr);
     46		break;
     47	case TPM_TIS_PHYS_16:
     48		result[1] = ioread8(phy->iobase + addr + 1);
     49		result[0] = ioread8(phy->iobase + addr);
     50		break;
     51	case TPM_TIS_PHYS_32:
     52		result[3] = ioread8(phy->iobase + addr + 3);
     53		result[2] = ioread8(phy->iobase + addr + 2);
     54		result[1] = ioread8(phy->iobase + addr + 1);
     55		result[0] = ioread8(phy->iobase + addr);
     56		break;
     57	}
     58
     59	return 0;
     60}
     61
     62static int tpm_tis_synquacer_write_bytes(struct tpm_tis_data *data, u32 addr,
     63					 u16 len, const u8 *value,
     64					 enum tpm_tis_io_mode io_mode)
     65{
     66	struct tpm_tis_synquacer_phy *phy = to_tpm_tis_tcg_phy(data);
     67	switch (io_mode) {
     68	case TPM_TIS_PHYS_8:
     69		while (len--)
     70			iowrite8(*value++, phy->iobase + addr);
     71		break;
     72	case TPM_TIS_PHYS_16:
     73		return -EINVAL;
     74	case TPM_TIS_PHYS_32:
     75		/*
     76		 * Due to the limitation of SPI controller on SynQuacer,
     77		 * 16/32 bits access must be done in byte-wise and descending order.
     78		 */
     79		iowrite8(value[3], phy->iobase + addr + 3);
     80		iowrite8(value[2], phy->iobase + addr + 2);
     81		iowrite8(value[1], phy->iobase + addr + 1);
     82		iowrite8(value[0], phy->iobase + addr);
     83		break;
     84	}
     85
     86	return 0;
     87}
     88
     89static const struct tpm_tis_phy_ops tpm_tcg_bw = {
     90	.read_bytes	= tpm_tis_synquacer_read_bytes,
     91	.write_bytes	= tpm_tis_synquacer_write_bytes,
     92};
     93
     94static int tpm_tis_synquacer_init(struct device *dev,
     95				  struct tpm_tis_synquacer_info *tpm_info)
     96{
     97	struct tpm_tis_synquacer_phy *phy;
     98
     99	phy = devm_kzalloc(dev, sizeof(struct tpm_tis_synquacer_phy), GFP_KERNEL);
    100	if (phy == NULL)
    101		return -ENOMEM;
    102
    103	phy->iobase = devm_ioremap_resource(dev, &tpm_info->res);
    104	if (IS_ERR(phy->iobase))
    105		return PTR_ERR(phy->iobase);
    106
    107	return tpm_tis_core_init(dev, &phy->priv, tpm_info->irq, &tpm_tcg_bw,
    108				 ACPI_HANDLE(dev));
    109}
    110
    111static SIMPLE_DEV_PM_OPS(tpm_tis_synquacer_pm, tpm_pm_suspend, tpm_tis_resume);
    112
    113static int tpm_tis_synquacer_probe(struct platform_device *pdev)
    114{
    115	struct tpm_tis_synquacer_info tpm_info = {};
    116	struct resource *res;
    117
    118	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    119	if (res == NULL) {
    120		dev_err(&pdev->dev, "no memory resource defined\n");
    121		return -ENODEV;
    122	}
    123	tpm_info.res = *res;
    124
    125	tpm_info.irq = -1;
    126
    127	return tpm_tis_synquacer_init(&pdev->dev, &tpm_info);
    128}
    129
    130static int tpm_tis_synquacer_remove(struct platform_device *pdev)
    131{
    132	struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);
    133
    134	tpm_chip_unregister(chip);
    135	tpm_tis_remove(chip);
    136
    137	return 0;
    138}
    139
    140#ifdef CONFIG_OF
    141static const struct of_device_id tis_synquacer_of_platform_match[] = {
    142	{.compatible = "socionext,synquacer-tpm-mmio"},
    143	{},
    144};
    145MODULE_DEVICE_TABLE(of, tis_synquacer_of_platform_match);
    146#endif
    147
    148#ifdef CONFIG_ACPI
    149static const struct acpi_device_id tpm_synquacer_acpi_tbl[] = {
    150	{ "SCX0009" },
    151	{},
    152};
    153MODULE_DEVICE_TABLE(acpi, tpm_synquacer_acpi_tbl);
    154#endif
    155
    156static struct platform_driver tis_synquacer_drv = {
    157	.probe = tpm_tis_synquacer_probe,
    158	.remove = tpm_tis_synquacer_remove,
    159	.driver = {
    160		.name		= "tpm_tis_synquacer",
    161		.pm		= &tpm_tis_synquacer_pm,
    162		.of_match_table = of_match_ptr(tis_synquacer_of_platform_match),
    163		.acpi_match_table = ACPI_PTR(tpm_synquacer_acpi_tbl),
    164	},
    165};
    166
    167static int __init tpm_tis_synquacer_module_init(void)
    168{
    169	int rc;
    170
    171	rc = platform_driver_register(&tis_synquacer_drv);
    172	if (rc)
    173		return rc;
    174
    175	return 0;
    176}
    177
    178static void __exit tpm_tis_synquacer_module_exit(void)
    179{
    180	platform_driver_unregister(&tis_synquacer_drv);
    181}
    182
    183module_init(tpm_tis_synquacer_module_init);
    184module_exit(tpm_tis_synquacer_module_exit);
    185MODULE_DESCRIPTION("TPM MMIO Driver for Socionext SynQuacer platform");
    186MODULE_LICENSE("GPL");