tpm_tis_synquacer.c 4.5 KB

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