brintos

brintos / linux-shallow public Read only

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