Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/char/tpm/tpm_tis_synquacer.c
26292 views
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/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 support
20
*/
21
struct tpm_tis_synquacer_info {
22
struct resource res;
23
int irq;
24
};
25
26
struct tpm_tis_synquacer_phy {
27
struct tpm_tis_data priv;
28
void __iomem *iobase;
29
};
30
31
static 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
36
static 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
61
static 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
88
static 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
93
static 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
110
static SIMPLE_DEV_PM_OPS(tpm_tis_synquacer_pm, tpm_pm_suspend, tpm_tis_resume);
111
112
static 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
129
static 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_OF
138
static const struct of_device_id tis_synquacer_of_platform_match[] = {
139
{.compatible = "socionext,synquacer-tpm-mmio"},
140
{},
141
};
142
MODULE_DEVICE_TABLE(of, tis_synquacer_of_platform_match);
143
#endif
144
145
#ifdef CONFIG_ACPI
146
static const struct acpi_device_id tpm_synquacer_acpi_tbl[] = {
147
{ "SCX0009" },
148
{},
149
};
150
MODULE_DEVICE_TABLE(acpi, tpm_synquacer_acpi_tbl);
151
#endif
152
153
static struct platform_driver tis_synquacer_drv = {
154
.probe = tpm_tis_synquacer_probe,
155
.remove = 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
164
module_platform_driver(tis_synquacer_drv);
165
166
MODULE_DESCRIPTION("TPM MMIO Driver for Socionext SynQuacer platform");
167
MODULE_LICENSE("GPL");
168
169