@@ -225,5 +225,14 @@ config TCG_FTPM_TEE
help
This driver proxies for firmware TPM running in TEE.
+config TCG_LSSE
+ tristate "Loongson TPM Interface"
+ depends on MFD_LS6000SE
+ help
+ If you want to make Loongson TPM support available, say Yes and
+ it will be accessible from within Linux. To compile this
+ driver as a module, choose M here; the module will be called
+ tpm_lsse.
+
source "drivers/char/tpm/st33zp24/Kconfig"
endif # TCG_TPM
@@ -44,3 +44,4 @@ obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o
obj-$(CONFIG_TCG_CRB) += tpm_crb.o
obj-$(CONFIG_TCG_VTPM_PROXY) += tpm_vtpm_proxy.o
obj-$(CONFIG_TCG_FTPM_TEE) += tpm_ftpm_tee.o
+obj-$(CONFIG_TCG_LSSE) += tpm_lsse.o
new file mode 100644
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2025 Loongson Technology Corporation Limited. */
+
+#include <linux/device.h>
+#include <linux/mfd/ls6000se.h>
+#include <linux/platform_device.h>
+#include <linux/wait.h>
+
+#include "tpm.h"
+
+struct tpm_lsse_msg {
+ u32 cmd;
+ u32 data_off;
+ u32 data_len;
+ u32 info[5];
+};
+
+struct tpm_lsse_dev {
+ struct lsse_ch *se_ch;
+ struct completion tpm_lsse_completion;
+};
+
+static void tpm_lsse_complete(struct lsse_ch *ch)
+{
+ struct tpm_lsse_dev *td = ch->priv;
+
+ complete(&td->tpm_lsse_completion);
+}
+
+static int tpm_lsse_recv(struct tpm_chip *chip, u8 *buf, size_t count)
+{
+ struct tpm_lsse_dev *td = dev_get_drvdata(&chip->dev);
+ struct tpm_lsse_msg *rmsg;
+ int sig;
+
+ sig = wait_for_completion_interruptible(&td->tpm_lsse_completion);
+ if (sig)
+ return sig;
+
+ rmsg = td->se_ch->rmsg;
+ memcpy(buf, td->se_ch->data_buffer, rmsg->data_len);
+
+ return rmsg->data_len;
+}
+
+static int tpm_lsse_send(struct tpm_chip *chip, u8 *buf, size_t count)
+{
+ struct tpm_lsse_dev *td = dev_get_drvdata(&chip->dev);
+ struct tpm_lsse_msg *smsg = td->se_ch->smsg;
+
+ memcpy(td->se_ch->data_buffer, buf, count);
+ smsg->data_len = count;
+
+ return se_send_ch_requeset(td->se_ch);
+}
+
+static const struct tpm_class_ops tpm_lsse_ops = {
+ .flags = TPM_OPS_AUTO_STARTUP,
+ .recv = tpm_lsse_recv,
+ .send = tpm_lsse_send,
+};
+
+static int tpm_lsse_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct tpm_lsse_msg *smsg;
+ struct tpm_lsse_dev *td;
+ struct tpm_chip *chip;
+
+ td = devm_kzalloc(dev, sizeof(struct tpm_lsse_dev), GFP_KERNEL);
+ if (!td)
+ return -ENOMEM;
+
+ init_completion(&td->tpm_lsse_completion);
+ td->se_ch = se_init_ch(dev->parent, SE_CH_TPM, PAGE_SIZE,
+ 2 * sizeof(struct tpm_lsse_msg), td,
+ tpm_lsse_complete);
+ if (!td->se_ch)
+ return -ENODEV;
+ smsg = td->se_ch->smsg;
+ smsg->cmd = SE_CMD_TPM;
+ smsg->data_off = td->se_ch->off;
+
+ chip = tpmm_chip_alloc(dev, &tpm_lsse_ops);
+ if (IS_ERR(chip))
+ return PTR_ERR(chip);
+ chip->flags = TPM_CHIP_FLAG_TPM2 | TPM_CHIP_FLAG_IRQ;
+ dev_set_drvdata(&chip->dev, td);
+
+ return tpm_chip_register(chip);
+}
+
+static struct platform_driver tpm_lsse_driver = {
+ .probe = tpm_lsse_probe,
+ .driver = {
+ .name = "ls6000se-tpm",
+ },
+};
+module_platform_driver(tpm_lsse_driver);
+
+MODULE_ALIAS("platform:ls6000se-tpm");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Loongson TPM driver");