* [PATCH v8 2/8] tpm: tpm_tis: Add verify_data_integrity handle toy tpm_tis_phy_ops
From: amirmizi6 @ 2020-05-12 14:14 UTC (permalink / raw)
To: Eyal.Cohen, jarkko.sakkinen, oshrialkoby85, alexander.steffen,
robh+dt, "benoit.houyere, peterhuewe, christophe-h.richard,
jgg, arnd, gregkh
Cc: devicetree, linux-kernel, linux-integrity, oshri.alkoby,
tmaimon77, gcwilson, kgoldman, Dan.Morav, oren.tanami,
shmulik.hager, amir.mizinski, Amir Mizinski, Christophe Ricard
In-Reply-To: <20200512141431.83833-1-amirmizi6@gmail.com>
From: Amir Mizinski <amirmizi6@gmail.com>
To validate data integrity we need to compute the CRC over the data
sent at a lower layer (I2C for instance).
To do this, tpm_tis_verify_data_integrity() calls a "verify_data_integrity"
operation (if available).
If the data integrity check fails, a retry to save the sent/received
data is implemented in the tpm_tis_send_main()/tpm_tis_recv() functions.
Co-developed-by: Christophe Ricard <christophe-h.ricard@st.com>
Signed-off-by: Christophe Ricard <christophe-h.ricard@st.com>
Signed-off-by: Amir Mizinski <amirmizi6@gmail.com>
---
drivers/char/tpm/tpm_tis_core.c | 104 +++++++++++++++++++++++++---------------
drivers/char/tpm/tpm_tis_core.h | 3 ++
2 files changed, 69 insertions(+), 38 deletions(-)
diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
index 27c6ca0..5dd5604 100644
--- a/drivers/char/tpm/tpm_tis_core.c
+++ b/drivers/char/tpm/tpm_tis_core.c
@@ -242,6 +242,17 @@ static u8 tpm_tis_status(struct tpm_chip *chip)
return status;
}
+static bool tpm_tis_verify_data_integrity(struct tpm_chip *chip, const u8 *buf,
+ size_t len)
+{
+ struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
+
+ if (priv->phy_ops->verify_data_integrity)
+ return priv->phy_ops->verify_data_integrity(priv, buf, len);
+
+ return true;
+}
+
static void tpm_tis_ready(struct tpm_chip *chip)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
@@ -308,47 +319,59 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
int size = 0;
- int status;
+ int status, i;
u32 expected;
+ bool data_valid = false;
- if (count < TPM_HEADER_SIZE) {
- size = -EIO;
- goto out;
- }
+ for (i = 0; i < TPM_RETRY; i++) {
+ if (count < TPM_HEADER_SIZE) {
+ size = -EIO;
+ goto out;
+ }
- size = recv_data(chip, buf, TPM_HEADER_SIZE);
- /* read first 10 bytes, including tag, paramsize, and result */
- if (size < TPM_HEADER_SIZE) {
- dev_err(&chip->dev, "Unable to read header\n");
- goto out;
- }
+ size = recv_data(chip, buf, TPM_HEADER_SIZE);
+ /* read first 10 bytes, including tag, paramsize, and result */
+ if (size < TPM_HEADER_SIZE) {
+ dev_err(&chip->dev, "Unable to read header\n");
+ goto out;
+ }
- expected = be32_to_cpu(*(__be32 *) (buf + 2));
- if (expected > count || expected < TPM_HEADER_SIZE) {
- size = -EIO;
- goto out;
- }
+ expected = be32_to_cpu(*(__be32 *) (buf + 2));
+ if (expected > count || expected < TPM_HEADER_SIZE) {
+ size = -EIO;
+ goto out;
+ }
- size += recv_data(chip, &buf[TPM_HEADER_SIZE],
- expected - TPM_HEADER_SIZE);
- if (size < expected) {
- dev_err(&chip->dev, "Unable to read remainder of result\n");
- size = -ETIME;
- goto out;
- }
+ size += recv_data(chip, &buf[TPM_HEADER_SIZE],
+ expected - TPM_HEADER_SIZE);
+ if (size < expected) {
+ dev_err(&chip->dev, "Unable to read remainder of result\n");
+ size = -ETIME;
+ goto out;
+ }
- if (wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c,
- &priv->int_queue, false) < 0) {
- size = -ETIME;
- goto out;
+ if (wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c,
+ &priv->int_queue, false) < 0) {
+ size = -ETIME;
+ goto out;
+ }
+
+ status = tpm_tis_status(chip);
+ if (status & TPM_STS_DATA_AVAIL) { /* retry? */
+ dev_err(&chip->dev, "Error left over data\n");
+ size = -EIO;
+ goto out;
+ }
+
+ data_valid = tpm_tis_verify_data_integrity(chip, buf, size);
+ if (!data_valid)
+ tpm_tis_write8(priv, TPM_STS(priv->locality),
+ TPM_STS_RESPONSE_RETRY);
+ else
+ break;
}
- status = tpm_tis_status(chip);
- if (status & TPM_STS_DATA_AVAIL) { /* retry? */
- dev_err(&chip->dev, "Error left over data\n");
+ if (!data_valid)
size = -EIO;
- goto out;
- }
-
out:
tpm_tis_ready(chip);
return size;
@@ -453,14 +476,19 @@ static void disable_interrupts(struct tpm_chip *chip)
static int tpm_tis_send_main(struct tpm_chip *chip, const u8 *buf, size_t len)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
- int rc;
+ int rc, i;
u32 ordinal;
unsigned long dur;
+ bool data_valid = false;
- rc = tpm_tis_send_data(chip, buf, len);
- if (rc < 0)
- return rc;
-
+ for (i = 0; i < TPM_RETRY && !data_valid; i++) {
+ rc = tpm_tis_send_data(chip, buf, len);
+ if (rc < 0)
+ return rc;
+ data_valid = tpm_tis_verify_data_integrity(chip, buf, len);
+ }
+ if (!data_valid)
+ return -EIO;
/* go and do it */
rc = tpm_tis_write8(priv, TPM_STS(priv->locality), TPM_STS_GO);
if (rc < 0)
diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h
index d06c65b..cd97c01 100644
--- a/drivers/char/tpm/tpm_tis_core.h
+++ b/drivers/char/tpm/tpm_tis_core.h
@@ -34,6 +34,7 @@ enum tis_status {
TPM_STS_GO = 0x20,
TPM_STS_DATA_AVAIL = 0x10,
TPM_STS_DATA_EXPECT = 0x08,
+ TPM_STS_RESPONSE_RETRY = 0x02,
};
enum tis_int_flags {
@@ -106,6 +107,8 @@ struct tpm_tis_phy_ops {
int (*read16)(struct tpm_tis_data *data, u32 addr, u16 *result);
int (*read32)(struct tpm_tis_data *data, u32 addr, u32 *result);
int (*write32)(struct tpm_tis_data *data, u32 addr, u32 src);
+ bool (*verify_data_integrity)(struct tpm_tis_data *data, const u8 *buf,
+ size_t len);
};
static inline int tpm_tis_read_bytes(struct tpm_tis_data *data, u32 addr,
--
2.7.4
^ permalink raw reply related
* [PATCH v8 8/8] tpm: tpm_tis: add tpm_tis_i2c driver
From: amirmizi6 @ 2020-05-12 14:14 UTC (permalink / raw)
To: Eyal.Cohen, jarkko.sakkinen, oshrialkoby85, alexander.steffen,
robh+dt, "benoit.houyere, peterhuewe, christophe-h.richard,
jgg, arnd, gregkh
Cc: devicetree, linux-kernel, linux-integrity, oshri.alkoby,
tmaimon77, gcwilson, kgoldman, Dan.Morav, oren.tanami,
shmulik.hager, amir.mizinski, Amir Mizinski, Eddie James,
Joel Stanley
In-Reply-To: <20200512141431.83833-1-amirmizi6@gmail.com>
From: Amir Mizinski <amirmizi6@gmail.com>
Implements the functionality needed to communicate with an I2C TPM
according to the TCG TPM I2C Interface Specification.
Signed-off-by: Amir Mizinski <amirmizi6@gmail.com>
Tested-by: Eddie James <eajames@linux.ibm.com>
Tested-by: Joel Stanley <joel@jms.id.au>
---
drivers/char/tpm/Kconfig | 12 ++
drivers/char/tpm/Makefile | 1 +
drivers/char/tpm/tpm_tis_i2c.c | 292 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 305 insertions(+)
create mode 100644 drivers/char/tpm/tpm_tis_i2c.c
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index aacdeed..2116d94 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -74,6 +74,18 @@ config TCG_TIS_SPI_CR50
If you have a H1 secure module running Cr50 firmware on SPI bus,
say Yes and it will be accessible from within Linux.
+config TCG_TIS_I2C
+ tristate "TPM I2C Interface Specification"
+ depends on I2C
+ select CRC_CCITT
+ select TCG_TIS_CORE
+ help
+ If you have a TPM security chip which is connected to a regular
+ I2C master (i.e. most embedded platforms) that is compliant with the
+ TCG TPM I2C Interface Specification 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_tis_i2c.
+
config TCG_TIS_I2C_ATMEL
tristate "TPM Interface Specification 1.2 Interface (I2C - Atmel)"
depends on I2C
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
index 9567e51..97999cf 100644
--- a/drivers/char/tpm/Makefile
+++ b/drivers/char/tpm/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_TCG_TIS_SPI) += tpm_tis_spi.o
tpm_tis_spi-y := tpm_tis_spi_main.o
tpm_tis_spi-$(CONFIG_TCG_TIS_SPI_CR50) += tpm_tis_spi_cr50.o
+obj-$(CONFIG_TCG_TIS_I2C) += tpm_tis_i2c.o
obj-$(CONFIG_TCG_TIS_I2C_ATMEL) += tpm_i2c_atmel.o
obj-$(CONFIG_TCG_TIS_I2C_INFINEON) += tpm_i2c_infineon.o
obj-$(CONFIG_TCG_TIS_I2C_NUVOTON) += tpm_i2c_nuvoton.o
diff --git a/drivers/char/tpm/tpm_tis_i2c.c b/drivers/char/tpm/tpm_tis_i2c.c
new file mode 100644
index 0000000..4c9bad0
--- /dev/null
+++ b/drivers/char/tpm/tpm_tis_i2c.c
@@ -0,0 +1,292 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2014-2019 Nuvoton Technology corporation
+ *
+ * TPM TIS I2C
+ *
+ * TPM TIS I2C Device Driver Interface for devices that implement the TPM I2C
+ * Interface defined by TCG PC Client Platform TPM Profile (PTP) Specification
+ * Revision 01.03 v22 at www.trustedcomputinggroup.org
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/acpi.h>
+#include <linux/freezer.h>
+#include <linux/crc-ccitt.h>
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
+#include <linux/tpm.h>
+#include "tpm.h"
+#include "tpm_tis_core.h"
+
+#define TPM_LOC_SEL 0x04
+#define TPM_I2C_INTERFACE_CAPABILITY 0x30
+#define TPM_I2C_DEVICE_ADDRESS 0x38
+#define TPM_DATA_CSUM_ENABLE 0x40
+#define TPM_DATA_CSUM 0x44
+#define TPM_I2C_DID_VID 0x48
+#define TPM_I2C_RID 0x4C
+
+//#define I2C_IS_TPM2 1
+
+struct tpm_tis_i2c_phy {
+ struct tpm_tis_data priv;
+ struct i2c_client *i2c_client;
+ bool data_csum;
+ u8 *iobuf;
+};
+
+static inline struct tpm_tis_i2c_phy *to_tpm_tis_i2c_phy(struct tpm_tis_data
+ *data)
+{
+ return container_of(data, struct tpm_tis_i2c_phy, priv);
+}
+
+static u8 address_to_register(u32 addr)
+{
+ addr &= 0xFFF;
+
+ switch (addr) {
+ // adapt register addresses that have changed compared to
+ // older TIS versions
+ case TPM_ACCESS(0):
+ return 0x04;
+ case TPM_LOC_SEL:
+ return 0x00;
+ case TPM_DID_VID(0):
+ return 0x48;
+ case TPM_RID(0):
+ return 0x4C;
+ default:
+ return addr;
+ }
+}
+
+static int tpm_tis_i2c_read_bytes(struct tpm_tis_data *data, u32 addr,
+ u16 len, u8 *result)
+{
+ struct tpm_tis_i2c_phy *phy = to_tpm_tis_i2c_phy(data);
+ int ret = 0;
+ int i = 0;
+ u8 reg = address_to_register(addr);
+ struct i2c_msg msgs[] = {
+ {
+ .addr = phy->i2c_client->addr,
+ .len = sizeof(reg),
+ .buf = ®,
+ },
+ {
+ .addr = phy->i2c_client->addr,
+ .len = len,
+ .buf = result,
+ .flags = I2C_M_RD,
+ },
+ };
+
+ do {
+ ret = i2c_transfer(phy->i2c_client->adapter, msgs,
+ ARRAY_SIZE(msgs));
+ usleep_range(250, 300); // wait default GUARD_TIME of 250µs
+
+ } while (ret < 0 && i++ < TPM_RETRY);
+
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int tpm_tis_i2c_write_bytes(struct tpm_tis_data *data, u32 addr,
+ u16 len, const u8 *value)
+{
+ struct tpm_tis_i2c_phy *phy = to_tpm_tis_i2c_phy(data);
+ int ret = 0;
+ int i = 0;
+
+ if (phy->iobuf) {
+ if (len > TPM_BUFSIZE - 1)
+ return -EIO;
+
+ phy->iobuf[0] = address_to_register(addr);
+ memcpy(phy->iobuf + 1, value, len);
+
+ {
+ struct i2c_msg msgs[] = {
+ {
+ .addr = phy->i2c_client->addr,
+ .len = len + 1,
+ .buf = phy->iobuf,
+ },
+ };
+
+ do {
+ ret = i2c_transfer(phy->i2c_client->adapter,
+ msgs, ARRAY_SIZE(msgs));
+ // wait default GUARD_TIME of 250µs
+ usleep_range(250, 300);
+ } while (ret < 0 && i++ < TPM_RETRY);
+ }
+ } else {
+ u8 reg = address_to_register(addr);
+
+ struct i2c_msg msgs[] = {
+ {
+ .addr = phy->i2c_client->addr,
+ .len = sizeof(reg),
+ .buf = ®,
+ },
+ {
+ .addr = phy->i2c_client->addr,
+ .len = len,
+ .buf = (u8 *)value,
+ .flags = I2C_M_NOSTART,
+ },
+ };
+ do {
+ ret = i2c_transfer(phy->i2c_client->adapter, msgs,
+ ARRAY_SIZE(msgs));
+ // wait default GUARD_TIME of 250µs
+ usleep_range(250, 300);
+ } while (ret < 0 && i++ < TPM_RETRY);
+ }
+
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static bool tpm_tis_i2c_verify_data_integrity(struct tpm_tis_data *data,
+ const u8 *buf, size_t len)
+{
+ struct tpm_tis_i2c_phy *phy = to_tpm_tis_i2c_phy(data);
+ u16 crc, crc_tpm;
+ int rc;
+
+ if (phy->data_csum) {
+ crc = crc_ccitt(0x0000, buf, len);
+ rc = tpm_tis_read16(data, TPM_DATA_CSUM, &crc_tpm);
+ if (rc < 0)
+ return false;
+
+ crc_tpm = be16_to_cpu(crc_tpm);
+ return crc == crc_tpm;
+ }
+
+ return true;
+}
+
+static SIMPLE_DEV_PM_OPS(tpm_tis_pm, tpm_pm_suspend, tpm_tis_resume);
+
+static int csum_state_store(struct tpm_tis_data *data, u8 new_state)
+{
+ struct tpm_tis_i2c_phy *phy = to_tpm_tis_i2c_phy(data);
+ u8 cur_state;
+ int rc;
+
+ rc = tpm_tis_i2c_write_bytes(&phy->priv, TPM_DATA_CSUM_ENABLE,
+ 1, &new_state);
+ if (rc < 0)
+ return rc;
+
+ rc = tpm_tis_i2c_read_bytes(&phy->priv, TPM_DATA_CSUM_ENABLE,
+ 1, &cur_state);
+ if (rc < 0)
+ return rc;
+
+ if (new_state == cur_state)
+ phy->data_csum = (bool)new_state;
+
+ return rc;
+}
+
+static const struct tpm_tis_phy_ops tpm_i2c_phy_ops = {
+ .read_bytes = tpm_tis_i2c_read_bytes,
+ .write_bytes = tpm_tis_i2c_write_bytes,
+ .verify_data_integrity = tpm_tis_i2c_verify_data_integrity,
+};
+
+static int tpm_tis_i2c_probe(struct i2c_client *dev,
+ const struct i2c_device_id *id)
+{
+ struct tpm_tis_i2c_phy *phy;
+ int rc;
+ int crc_checksum = 0;
+ const u8 loc_init = 0;
+ struct device_node *np;
+
+ phy = devm_kzalloc(&dev->dev, sizeof(struct tpm_tis_i2c_phy),
+ GFP_KERNEL);
+ if (!phy)
+ return -ENOMEM;
+
+ phy->i2c_client = dev;
+
+ if (!i2c_check_functionality(dev->adapter, I2C_FUNC_NOSTART)) {
+ phy->iobuf = devm_kmalloc(&dev->dev, TPM_BUFSIZE, GFP_KERNEL);
+ if (!phy->iobuf)
+ return -ENOMEM;
+ }
+
+ // select locality 0 (the driver will access only via locality 0)
+ rc = tpm_tis_i2c_write_bytes(&phy->priv, TPM_LOC_SEL, 1, &loc_init);
+ if (rc < 0)
+ return rc;
+
+ // set CRC checksum calculation enable
+ np = dev->dev.of_node;
+ if (of_property_read_bool(np, "crc-checksum"))
+ crc_checksum = 1;
+
+ rc = csum_state_store(&phy->priv, crc_checksum);
+ if (rc < 0)
+ return rc;
+
+ return tpm_tis_core_init(&dev->dev, &phy->priv, -1, &tpm_i2c_phy_ops,
+ NULL);
+}
+
+static const struct i2c_device_id tpm_tis_i2c_id[] = {
+ {"tpm_tis_i2c", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, tpm_tis_i2c_id);
+
+static const struct of_device_id of_tis_i2c_match[] = {
+ { .compatible = "nuvoton,npct75x", },
+ { .compatible = "tcg,tpm-tis-i2c", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, of_tis_i2c_match);
+
+static const struct acpi_device_id acpi_tis_i2c_match[] = {
+ {"SMO0768", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(acpi, acpi_tis_i2c_match);
+
+static struct i2c_driver tpm_tis_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "tpm_tis_i2c",
+ .pm = &tpm_tis_pm,
+ .of_match_table = of_match_ptr(of_tis_i2c_match),
+ .acpi_match_table = ACPI_PTR(acpi_tis_i2c_match),
+ },
+ .probe = tpm_tis_i2c_probe,
+ .id_table = tpm_tis_i2c_id,
+};
+
+module_i2c_driver(tpm_tis_i2c_driver);
+
+MODULE_DESCRIPTION("TPM Driver");
+MODULE_LICENSE("GPL");
--
2.7.4
^ permalink raw reply related
* [PATCH v8 5/8] tpm: Handle an exception for TPM Firmware Update mode.
From: amirmizi6 @ 2020-05-12 14:14 UTC (permalink / raw)
To: Eyal.Cohen, jarkko.sakkinen, oshrialkoby85, alexander.steffen,
robh+dt, "benoit.houyere, peterhuewe, christophe-h.richard,
jgg, arnd, gregkh
Cc: devicetree, linux-kernel, linux-integrity, oshri.alkoby,
tmaimon77, gcwilson, kgoldman, Dan.Morav, oren.tanami,
shmulik.hager, amir.mizinski, Amir Mizinski, Benoit Houyere
In-Reply-To: <20200512141431.83833-1-amirmizi6@gmail.com>
From: Amir Mizinski <amirmizi6@gmail.com>
An extra precaution for TPM Firmware Update Mode.
For example if TPM power was cut while in Firmware update, platform
should ignore "selftest" failure and skip TPM initialization sequence.
Suggested-by: Benoit Houyere <benoit.houyere@st.com>
Signed-off-by: Amir Mizinski <amirmizi6@gmail.com>
---
drivers/char/tpm/tpm2-cmd.c | 4 ++++
include/linux/tpm.h | 1 +
2 files changed, 5 insertions(+)
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 7603295..6e42946 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -727,6 +727,10 @@ int tpm2_auto_startup(struct tpm_chip *chip)
goto out;
rc = tpm2_do_selftest(chip);
+
+ if (rc == TPM2_RC_UPGRADE || rc == TPM2_RC_COMMAND_CODE)
+ return 0;
+
if (rc && rc != TPM2_RC_INITIALIZE)
goto out;
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index 03e9b18..5a2e031 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -199,6 +199,7 @@ enum tpm2_return_codes {
TPM2_RC_INITIALIZE = 0x0100, /* RC_VER1 */
TPM2_RC_FAILURE = 0x0101,
TPM2_RC_DISABLED = 0x0120,
+ TPM2_RC_UPGRADE = 0x012D,
TPM2_RC_COMMAND_CODE = 0x0143,
TPM2_RC_TESTING = 0x090A, /* RC_WARN */
TPM2_RC_REFERENCE_H0 = 0x0910,
--
2.7.4
^ permalink raw reply related
* [PATCH v8 3/8] tpm: tpm_tis: Rewrite "tpm_tis_req_canceled()"
From: amirmizi6 @ 2020-05-12 14:14 UTC (permalink / raw)
To: Eyal.Cohen, jarkko.sakkinen, oshrialkoby85, alexander.steffen,
robh+dt, "benoit.houyere, peterhuewe, christophe-h.richard,
jgg, arnd, gregkh
Cc: devicetree, linux-kernel, linux-integrity, oshri.alkoby,
tmaimon77, gcwilson, kgoldman, Dan.Morav, oren.tanami,
shmulik.hager, amir.mizinski, Amir Mizinski
In-Reply-To: <20200512141431.83833-1-amirmizi6@gmail.com>
From: Amir Mizinski <amirmizi6@gmail.com>
Using this function while reading/writing data resulted in an aborted
operation.
After investigating the issue according to the TCG TPM Profile (PTP)
Specifications, I found that "request to cancel" should occur only if
TPM_STS.commandReady bit is lit.
Note that i couldn't find a case where the present condition
(in the linux kernel) is valid, so I'm removing the case for
"TPM_VID_WINBOND" since we have no need for it.
Also, the default comparison is wrong. Only cmdReady bit needs to be
compared instead of the full lower status register byte.
Fixes: 1f866057291f (tpm: Fix cancellation of TPM commands (polling mode))
Signed-off-by: Amir Mizinski <amirmizi6@gmail.com>
---
drivers/char/tpm/tpm_tis_core.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
index 5dd5604..682f950 100644
--- a/drivers/char/tpm/tpm_tis_core.c
+++ b/drivers/char/tpm/tpm_tis_core.c
@@ -715,13 +715,11 @@ static bool tpm_tis_req_canceled(struct tpm_chip *chip, u8 status)
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
switch (priv->manufacturer_id) {
- case TPM_VID_WINBOND:
- return ((status == TPM_STS_VALID) ||
- (status == (TPM_STS_VALID | TPM_STS_COMMAND_READY)));
case TPM_VID_STM:
return (status == (TPM_STS_VALID | TPM_STS_COMMAND_READY));
default:
- return (status == TPM_STS_COMMAND_READY);
+ return ((status & TPM_STS_COMMAND_READY) ==
+ TPM_STS_COMMAND_READY);
}
}
--
2.7.4
^ permalink raw reply related
* [PATCH v8 7/8] tpm: Add YAML schema for TPM TIS I2C options
From: amirmizi6 @ 2020-05-12 14:14 UTC (permalink / raw)
To: Eyal.Cohen, jarkko.sakkinen, oshrialkoby85, alexander.steffen,
robh+dt, "benoit.houyere, peterhuewe, christophe-h.richard,
jgg, arnd, gregkh
Cc: devicetree, linux-kernel, linux-integrity, oshri.alkoby,
tmaimon77, gcwilson, kgoldman, Dan.Morav, oren.tanami,
shmulik.hager, amir.mizinski, Amir Mizinski
In-Reply-To: <20200512141431.83833-1-amirmizi6@gmail.com>
From: Amir Mizinski <amirmizi6@gmail.com>
Added a YAML schema to support tpm tis i2c related dt-bindings for the I2c
PTP based physical layer.
This patch adds the documentation for corresponding device tree bindings of
I2C based Physical TPM.
Refer to the 'I2C Interface Definition' section in
'TCG PC Client PlatformTPMProfile(PTP) Specification' publication
for specification.
Signed-off-by: Amir Mizinski <amirmizi6@gmail.com>
---
.../bindings/security/tpm/tpm-tis-i2c.yaml | 51 ++++++++++++++++++++++
1 file changed, 51 insertions(+)
create mode 100644 Documentation/devicetree/bindings/security/tpm/tpm-tis-i2c.yaml
diff --git a/Documentation/devicetree/bindings/security/tpm/tpm-tis-i2c.yaml b/Documentation/devicetree/bindings/security/tpm/tpm-tis-i2c.yaml
new file mode 100644
index 0000000..628c8f3
--- /dev/null
+++ b/Documentation/devicetree/bindings/security/tpm/tpm-tis-i2c.yaml
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/security/tpm/tpm-tis-i2c.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: I2C PTP based TPM Device Tree Bindings
+
+maintainers:
+ - Amir Mizinski <amirmizi6@gmail.com>
+
+description:
+ Device Tree Bindings for I2C based Trusted Platform Module(TPM).
+
+properties:
+ compatible:
+ oneOf:
+ - items:
+ - enum:
+ # Nuvoton's Trusted Platform Module (TPM) (NPCT75x)
+ - nuvoton,npct75x
+ - const: tcg,tpm-tis-i2c
+
+ reg:
+ maxItems: 1
+
+ interrupt:
+ maxItems: 1
+
+ crc-checksum:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description:
+ Set this flag to enable CRC checksum.
+
+required:
+ - compatible
+ - reg
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ tpm_tis@2e {
+ compatible = "nuvoton,npct75x", "tcg,tpm-tis-i2c";
+ reg = <0x2e>;
+ crc-checksum;
+ };
+ };
+...
--
2.7.4
^ permalink raw reply related
* [PATCH v8 0/8] Add tpm i2c ptp driver
From: amirmizi6 @ 2020-05-12 14:14 UTC (permalink / raw)
To: Eyal.Cohen, jarkko.sakkinen, oshrialkoby85, alexander.steffen,
robh+dt, "benoit.houyere, peterhuewe, christophe-h.richard,
jgg, arnd, gregkh
Cc: devicetree, linux-kernel, linux-integrity, oshri.alkoby,
tmaimon77, gcwilson, kgoldman, Dan.Morav, oren.tanami,
shmulik.hager, amir.mizinski, Amir Mizinski
From: Amir Mizinski <amirmizi6@gmail.com>
This patch set adds support for TPM devices that implement the I2C.
Interface defined by TCG PTP specification:
https://trustedcomputinggroup.org/wp-content/uploads/TCG_PC_Client_Platform_TPM_Profile_PTP_2.0_r1.03_v22.pdf
The driver was tested on Raspberry-Pie 3, using Nuvoton NPCT75X TPM.
Interrupts are not implemented yet, preparing it for the next patch.
This patch is based on initial work by oshri Alkoby, Alexander Steffen and Christophe Ricard
Changes since version 1:
-"char:tpm:Add check_data handle to tpm_tis_phy_ops in order to check data integrity"
- Fixed and extended commit description.
- Fixed an issue regarding handling max retries.
-"dt-bindings: tpm: Add YAML schema for TPM TIS I2C options":
-Converted "tpm_tis_i2c.txt" to "tpm-tis-i2c.yaml".
- Renamed "tpm_tis-i2c" to "tpm-tis-i2c".
- Removed interrupts properties.
-"char: tpm: add tpm_tis_i2c driver"
- Replaced "tpm_tis-i2c" with "tpm-tis-i2c" in "tpm_tis_i2c.c".
Addressed comments from:
- Jarkko Sakkinen: https://patchwork.kernel.org/patch/11236257/
- Rob Herring: https://patchwork.kernel.org/patch/11236253/
Changes since version 2:
- Added 2 new commits with improvements suggested by Benoit Houyere.
-"Fix expected bit handling and send all bytes in one shot without last byte in exception"
-"Handle an exception for TPM Firmware Update mode."
- Updated patch to latest v5.5
-"dt-bindings: tpm: Add YAML schema for TPM TIS I2C options"
- Added "interrupts" and "crc-checksum" to properties.
- Updated binding description and commit info.
-"char: tpm: add tpm_tis_i2c driver" (suggested by Benoit Houyere)
- Added repeat I2C frame after NACK.
- Checksum I2C feature activation in DTS file configuration.
Addressed comments from:
- Rob Herring: https://lore.kernel.org/patchwork/patch/1161287/
Changes since version 3:
- Updated patch to latest v5.6
- Updated commits headlines and development credit format by Jarkko Sakkinen suggestion
-"tpm: tpm_tis: Make implementation of read16 read32 write32 optional"
- Updated commit description.
-"dt-bindings: tpm: Add YAML schema for TPM TIS I2C options"
- Fixed 'make dt_binding_check' errors on YAML file.
- Removed interrupts from required and examples since there is no use for them in current patch.
Addressed comments from:
- Jarkko Sakkinen: https://lore.kernel.org/patchwork/patch/1192101/
- Rob Herring: https://lore.kernel.org/patchwork/patch/1192099/
Changes since version 4:
-"tpm: tpm_tis: Make implementation of read16 read32 write32 optional"
-Added a "Reviewed-by" tag:
-"tpm: tpm_tis: Add check_data handle to tpm_tis_phy_ops in order to check data integrity"
-Fixed credit typos.
-"tpm: tpm_tis: rewrite "tpm_tis_req_canceled()""
-Added fixes tag and removed changes for STM.
-"tpm: tpm_tis: Fix expected bit handling and send all bytes in one shot without last byte in exception"
-Fixed typos, edited description to be clearer, and added a "Suggested-by" tag.
-"tpm: Handle an exception for TPM Firmware Update mode."
-Added a "Suggested-by" tag.
-"dt-bindings: tpm: Add YAML schema for TPM TIS I2C options"
-Fixed 'make dt_binding_check' errors.
-"tpm: tpm_tis: add tpm_tis_i2c driver"
-Added tested-by tag by Eddie James.
-Fixed indent in Kconfig file.
-Fixed 'MODULE_DESCRIPTION'.
Addressed comments from:
- Jarkko Sakkinen: https://patchwork.kernel.org/patch/11467645/
https://patchwork.kernel.org/patch/11467655/
https://patchwork.kernel.org/patch/11467643/
https://patchwork.kernel.org/patch/11467659/
https://patchwork.kernel.org/patch/11467651/
- Rob Herring: https://patchwork.kernel.org/patch/11467653/
- Randy Dunlap: https://patchwork.kernel.org/patch/11467651/
- Eddie James: https://lore.kernel.org/patchwork/patch/1192104/
Changes since version 5:
-"tpm: tpm_tis: Add check_data handle to tpm_tis_phy_ops"
-Updated short description and fixed long description to be more clear.
Addressed comments from:
- Jarkko Sakkinen: https://lkml.org/lkml/2020/4/6/748
Changes since version 6:
-"tpm: tpm_tis: Make implementation of read16, read32 and write32 optional"
-Fixed short description.
-fixed long description proofreading issues.
-"tpm: tpm_tis: Add check_data handle to tpm_tis_phy_ops"
-Fixed long description by Jarkko comments and proofreading issues.
-Replaced "check_data" with verify_data_integrity".
-New line before return statement.
-"tpm: tpm_tis: rewrite "tpm_tis_req_canceled()"
-Fixed line over 80 characters.
-fixed long description proofreading issues.
-" tpm: tpm_tis: Fix expected bit handling and send all bytes in one shot"
-fixed long description proofreading issues.
-"dt-bindings: tpm: Add YAML schema for TPM TIS I2C option"
-Replaced "tpm-tis-i2c@2e" with "tpm_tis@2e".
-Fixed CRC_Checksum description.
-"tpm: tpm_tis: add tpm_tis_i2c driver"
-Replaced "depends on CRC_CCIT" with "select CRC_CCIT".
-Added tested-by tag by Joel Stanley.
-Fixed checkpatch.pl warnings.
Addressed comments from:
- Jarkko Sakkinen:
https://lore.kernel.org/patchwork/patch/1221336/
https://lore.kernel.org/patchwork/patch/1221337/
https://lore.kernel.org/patchwork/patch/1221339/
- Joel Stanley:
https://lore.kernel.org/patchwork/patch/1220543/
- Rob Herring:
https://lore.kernel.org/patchwork/patch/1221334/
Changes since version 7:
- Added a new commit with improvements suggested by Benoit Houyere.
-"tpm: tpm_tis: verify TPM_STS register is valid after locality request"
-"tpm: tpm_tis: Rewrite "tpm_tis_req_canceled()""
-Fixed Hash for Fixes tag.
-"tpm: Add YAML schema for TPM TIS I2C options"
-Added a compatible string specific to the nuvoton npct75x chip.
-"tpm: tpm_tis: add tpm_tis_i2c driver"
- added a compatible string according to yaml file.
Addressed comments from:
- Jarkko Sakkinen:
https://lore.kernel.org/patchwork/patch/1231524/
- Rob Herring:
https://lore.kernel.org/patchwork/patch/1231526/
Amir Mizinski (8):
tpm: tpm_tis: Make implementation of read16, read32 and write32
optional
tpm: tpm_tis: Add verify_data_integrity handle toy tpm_tis_phy_ops
tpm: tpm_tis: Rewrite "tpm_tis_req_canceled()"
tpm: tpm_tis: Fix expected bit handling and send all bytes in one shot
without last byte in exception
tpm: Handle an exception for TPM Firmware Update mode.
verify TPM_STS register is valid after locality request
tpm: Add YAML schema for TPM TIS I2C options
tpm: tpm_tis: add tpm_tis_i2c driver
.../bindings/security/tpm/tpm-tis-i2c.yaml | 51 ++++
drivers/char/tpm/Kconfig | 12 +
drivers/char/tpm/Makefile | 1 +
drivers/char/tpm/tpm2-cmd.c | 4 +
drivers/char/tpm/tpm_tis_core.c | 188 +++++++------
drivers/char/tpm/tpm_tis_core.h | 41 ++-
drivers/char/tpm/tpm_tis_i2c.c | 292 +++++++++++++++++++++
drivers/char/tpm/tpm_tis_spi_main.c | 41 ---
include/linux/tpm.h | 1 +
9 files changed, 502 insertions(+), 129 deletions(-)
create mode 100644 Documentation/devicetree/bindings/security/tpm/tpm-tis-i2c.yaml
create mode 100644 drivers/char/tpm/tpm_tis_i2c.c
--
2.7.4
^ permalink raw reply
* [PATCH v8 4/8] tpm: tpm_tis: Fix expected bit handling and send all bytes in one shot without last byte in exception
From: amirmizi6 @ 2020-05-12 14:14 UTC (permalink / raw)
To: Eyal.Cohen, jarkko.sakkinen, oshrialkoby85, alexander.steffen,
robh+dt, "benoit.houyere, peterhuewe, christophe-h.richard,
jgg, arnd, gregkh
Cc: devicetree, linux-kernel, linux-integrity, oshri.alkoby,
tmaimon77, gcwilson, kgoldman, Dan.Morav, oren.tanami,
shmulik.hager, amir.mizinski, Amir Mizinski, Benoit Houyere
In-Reply-To: <20200512141431.83833-1-amirmizi6@gmail.com>
From: Amir Mizinski <amirmizi6@gmail.com>
Incorrect implementation of send message was detected. We polled only
TPM_STS.stsValid bit and then we single-checked the TPM_STS.expect bit
value.
TPM_STS.expected bit should be checked at the same time as
TPM_STS.stsValid bit, and this should be repeated until timeout_A.
To detect a TPM_STS.expected bit reset, the "wait_for_tpm_stat" function is
modified to "wait_for_tpm_stat_result". This function regularly reads the
status register and check the bits defined by "mask" to reach the value
defined in "mask_result".
This correct implementation is required for using the new CRC calculation
on I2C TPM command bytes or I2C TPM answer bytes. TPM_STS.expected bit is
reset after all bytes are acquired and the CRC result is inserted in the
dedicated register. It introduces a normal latency for TPM_STS.expected
bit reset.
Respectively, to send a message, as defined in
TCG_DesignPrinciples_TPM2p0Driver_vp24_pubrev.pdf, all bytes should be
sent in one shot instead of sending the last byte separately.
Suggested-by: Benoit Houyere <benoit.houyere@st.com>
Signed-off-by: Amir Mizinski <amirmizi6@gmail.com>
---
drivers/char/tpm/tpm_tis_core.c | 74 +++++++++++++++++------------------------
1 file changed, 30 insertions(+), 44 deletions(-)
diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
index 682f950..f71ecd8 100644
--- a/drivers/char/tpm/tpm_tis_core.c
+++ b/drivers/char/tpm/tpm_tis_core.c
@@ -44,9 +44,10 @@ static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask,
return false;
}
-static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask,
- unsigned long timeout, wait_queue_head_t *queue,
- bool check_cancel)
+static int wait_for_tpm_stat_result(struct tpm_chip *chip, u8 mask,
+ u8 mask_result, unsigned long timeout,
+ wait_queue_head_t *queue,
+ bool check_cancel)
{
unsigned long stop;
long rc;
@@ -55,7 +56,7 @@ static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask,
/* check current status */
status = chip->ops->status(chip);
- if ((status & mask) == mask)
+ if ((status & mask) == mask_result)
return 0;
stop = jiffies + timeout;
@@ -83,7 +84,7 @@ static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask,
usleep_range(TPM_TIMEOUT_USECS_MIN,
TPM_TIMEOUT_USECS_MAX);
status = chip->ops->status(chip);
- if ((status & mask) == mask)
+ if ((status & mask) == mask_result)
return 0;
} while (time_before(jiffies, stop));
}
@@ -292,10 +293,13 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
int size = 0, burstcnt, rc;
while (size < count) {
- rc = wait_for_tpm_stat(chip,
- TPM_STS_DATA_AVAIL | TPM_STS_VALID,
- chip->timeout_c,
- &priv->read_queue, true);
+ rc = wait_for_tpm_stat_result(chip,
+ TPM_STS_DATA_AVAIL |
+ TPM_STS_VALID,
+ TPM_STS_DATA_AVAIL |
+ TPM_STS_VALID,
+ chip->timeout_c,
+ &priv->read_queue, true);
if (rc < 0)
return rc;
burstcnt = get_burstcount(chip);
@@ -350,8 +354,9 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
goto out;
}
- if (wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c,
- &priv->int_queue, false) < 0) {
+ if (wait_for_tpm_stat_result(chip, TPM_STS_VALID,
+ TPM_STS_VALID, chip->timeout_c,
+ &priv->int_queue, false) < 0) {
size = -ETIME;
goto out;
}
@@ -387,61 +392,40 @@ static int tpm_tis_send_data(struct tpm_chip *chip, const u8 *buf, size_t len)
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
int rc, status, burstcnt;
size_t count = 0;
- bool itpm = priv->flags & TPM_TIS_ITPM_WORKAROUND;
status = tpm_tis_status(chip);
if ((status & TPM_STS_COMMAND_READY) == 0) {
tpm_tis_ready(chip);
- if (wait_for_tpm_stat
- (chip, TPM_STS_COMMAND_READY, chip->timeout_b,
- &priv->int_queue, false) < 0) {
+ if (wait_for_tpm_stat_result(chip, TPM_STS_COMMAND_READY,
+ TPM_STS_COMMAND_READY,
+ chip->timeout_b,
+ &priv->int_queue, false) < 0) {
rc = -ETIME;
goto out_err;
}
}
- while (count < len - 1) {
+ while (count < len) {
burstcnt = get_burstcount(chip);
if (burstcnt < 0) {
dev_err(&chip->dev, "Unable to read burstcount\n");
rc = burstcnt;
goto out_err;
}
- burstcnt = min_t(int, burstcnt, len - count - 1);
+ burstcnt = min_t(int, burstcnt, len - count);
rc = tpm_tis_write_bytes(priv, TPM_DATA_FIFO(priv->locality),
burstcnt, buf + count);
if (rc < 0)
goto out_err;
count += burstcnt;
-
- if (wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c,
- &priv->int_queue, false) < 0) {
- rc = -ETIME;
- goto out_err;
- }
- status = tpm_tis_status(chip);
- if (!itpm && (status & TPM_STS_DATA_EXPECT) == 0) {
- rc = -EIO;
- goto out_err;
- }
}
-
- /* write last byte */
- rc = tpm_tis_write8(priv, TPM_DATA_FIFO(priv->locality), buf[count]);
- if (rc < 0)
- goto out_err;
-
- if (wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c,
- &priv->int_queue, false) < 0) {
+ if (wait_for_tpm_stat_result(chip, TPM_STS_VALID | TPM_STS_DATA_EXPECT,
+ TPM_STS_VALID, chip->timeout_a,
+ &priv->int_queue, false) < 0) {
rc = -ETIME;
goto out_err;
}
- status = tpm_tis_status(chip);
- if (!itpm && (status & TPM_STS_DATA_EXPECT) != 0) {
- rc = -EIO;
- goto out_err;
- }
return 0;
@@ -498,9 +482,11 @@ static int tpm_tis_send_main(struct tpm_chip *chip, const u8 *buf, size_t len)
ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
dur = tpm_calc_ordinal_duration(chip, ordinal);
- if (wait_for_tpm_stat
- (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, dur,
- &priv->read_queue, false) < 0) {
+ if (wait_for_tpm_stat_result(chip,
+ TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+ TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+ dur,
+ &priv->read_queue, false) < 0) {
rc = -ETIME;
goto out_err;
}
--
2.7.4
^ permalink raw reply related
* [PATCH v8 1/8] tpm: tpm_tis: Make implementation of read16, read32 and write32 optional
From: amirmizi6 @ 2020-05-12 14:14 UTC (permalink / raw)
To: Eyal.Cohen, jarkko.sakkinen, oshrialkoby85, alexander.steffen,
robh+dt, "benoit.houyere, peterhuewe, christophe-h.richard,
jgg, arnd, gregkh
Cc: devicetree, linux-kernel, linux-integrity, oshri.alkoby,
tmaimon77, gcwilson, kgoldman, Dan.Morav, oren.tanami,
shmulik.hager, amir.mizinski, Amir Mizinski, Alexander Steffen
In-Reply-To: <20200512141431.83833-1-amirmizi6@gmail.com>
From: Amir Mizinski <amirmizi6@gmail.com>
Only tpm_tis can use memory-mapped I/O, which is truly mapped into
the kernel's memory space. Therefore, using ioread16/ioread32/iowrite32
turns into a straightforward pointer dereference.
Every other driver requires more complicated operations to read more than
one byte at a time and will just fall back to read_bytes/write_bytes.
Therefore, move this common code out of tpm_tis_spi and into tpm_tis_core
so that it is used automatically when low-level drivers do not implement
the specialized methods.
Co-developed-by: Alexander Steffen <Alexander.Steffen@infineon.com>
Signed-off-by: Alexander Steffen <Alexander.Steffen@infineon.com>
Signed-off-by: Amir Mizinski <amirmizi6@gmail.com>
Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
drivers/char/tpm/tpm_tis_core.h | 38 +++++++++++++++++++++++++++++++---
drivers/char/tpm/tpm_tis_spi_main.c | 41 -------------------------------------
2 files changed, 35 insertions(+), 44 deletions(-)
diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h
index 7337819..d06c65b 100644
--- a/drivers/char/tpm/tpm_tis_core.h
+++ b/drivers/char/tpm/tpm_tis_core.h
@@ -122,13 +122,35 @@ static inline int tpm_tis_read8(struct tpm_tis_data *data, u32 addr, u8 *result)
static inline int tpm_tis_read16(struct tpm_tis_data *data, u32 addr,
u16 *result)
{
- return data->phy_ops->read16(data, addr, result);
+ __le16 result_le;
+ int rc;
+
+ if (data->phy_ops->read16)
+ return data->phy_ops->read16(data, addr, result);
+
+ rc = data->phy_ops->read_bytes(data, addr, sizeof(u16),
+ (u8 *)&result_le);
+ if (!rc)
+ *result = le16_to_cpu(result_le);
+
+ return rc;
}
static inline int tpm_tis_read32(struct tpm_tis_data *data, u32 addr,
u32 *result)
{
- return data->phy_ops->read32(data, addr, result);
+ __le32 result_le;
+ int rc;
+
+ if (data->phy_ops->read32)
+ return data->phy_ops->read32(data, addr, result);
+
+ rc = data->phy_ops->read_bytes(data, addr, sizeof(u32),
+ (u8 *)&result_le);
+ if (!rc)
+ *result = le32_to_cpu(result_le);
+
+ return rc;
}
static inline int tpm_tis_write_bytes(struct tpm_tis_data *data, u32 addr,
@@ -145,7 +167,17 @@ static inline int tpm_tis_write8(struct tpm_tis_data *data, u32 addr, u8 value)
static inline int tpm_tis_write32(struct tpm_tis_data *data, u32 addr,
u32 value)
{
- return data->phy_ops->write32(data, addr, value);
+ __le32 value_le;
+ int rc;
+
+ if (data->phy_ops->write32)
+ return data->phy_ops->write32(data, addr, value);
+
+ value_le = cpu_to_le32(value);
+ rc = data->phy_ops->write_bytes(data, addr, sizeof(u32),
+ (u8 *)&value_le);
+
+ return rc;
}
static inline bool is_bsw(void)
diff --git a/drivers/char/tpm/tpm_tis_spi_main.c b/drivers/char/tpm/tpm_tis_spi_main.c
index d1754fd..95fef9d 100644
--- a/drivers/char/tpm/tpm_tis_spi_main.c
+++ b/drivers/char/tpm/tpm_tis_spi_main.c
@@ -152,44 +152,6 @@ static int tpm_tis_spi_write_bytes(struct tpm_tis_data *data, u32 addr,
return tpm_tis_spi_transfer(data, addr, len, NULL, value);
}
-int tpm_tis_spi_read16(struct tpm_tis_data *data, u32 addr, u16 *result)
-{
- __le16 result_le;
- int rc;
-
- rc = data->phy_ops->read_bytes(data, addr, sizeof(u16),
- (u8 *)&result_le);
- if (!rc)
- *result = le16_to_cpu(result_le);
-
- return rc;
-}
-
-int tpm_tis_spi_read32(struct tpm_tis_data *data, u32 addr, u32 *result)
-{
- __le32 result_le;
- int rc;
-
- rc = data->phy_ops->read_bytes(data, addr, sizeof(u32),
- (u8 *)&result_le);
- if (!rc)
- *result = le32_to_cpu(result_le);
-
- return rc;
-}
-
-int tpm_tis_spi_write32(struct tpm_tis_data *data, u32 addr, u32 value)
-{
- __le32 value_le;
- int rc;
-
- value_le = cpu_to_le32(value);
- rc = data->phy_ops->write_bytes(data, addr, sizeof(u32),
- (u8 *)&value_le);
-
- return rc;
-}
-
int tpm_tis_spi_init(struct spi_device *spi, struct tpm_tis_spi_phy *phy,
int irq, const struct tpm_tis_phy_ops *phy_ops)
{
@@ -205,9 +167,6 @@ int tpm_tis_spi_init(struct spi_device *spi, struct tpm_tis_spi_phy *phy,
static const struct tpm_tis_phy_ops tpm_spi_phy_ops = {
.read_bytes = tpm_tis_spi_read_bytes,
.write_bytes = tpm_tis_spi_write_bytes,
- .read16 = tpm_tis_spi_read16,
- .read32 = tpm_tis_spi_read32,
- .write32 = tpm_tis_spi_write32,
};
static int tpm_tis_spi_probe(struct spi_device *dev)
--
2.7.4
^ permalink raw reply related
* [PATCH v8 6/8] verify TPM_STS register is valid after locality request
From: amirmizi6 @ 2020-05-12 14:14 UTC (permalink / raw)
To: Eyal.Cohen, jarkko.sakkinen, oshrialkoby85, alexander.steffen,
robh+dt, "benoit.houyere, peterhuewe, christophe-h.richard,
jgg, arnd, gregkh
Cc: devicetree, linux-kernel, linux-integrity, oshri.alkoby,
tmaimon77, gcwilson, kgoldman, Dan.Morav, oren.tanami,
shmulik.hager, amir.mizinski, Amir Mizinski
In-Reply-To: <20200512141431.83833-1-amirmizi6@gmail.com>
From: Amir Mizinski <amirmizi6@gmail.com>
Issue could result when the TPM does not update TPM_STS register after
a locality request (TPM_STS Initial value = 0xFF) and a TPM_STS register
read occurs (tpm_tis_status(chip)).
Checking the next condition("if ((status & TPM_STS_COMMAND_READY) == 0)"),
the status will be at 0xFF and will be considered, wrongly, in "Ready"
state (by checking only one bit). However, at this moment the TPM is, in
fact, in "Idle" state and remains in "Idle" state because
"tpm_tis_ready(chip);" was not executed.
Signed-off-by: Amir Mizinski <amirmizi6@gmail.com>
---
drivers/char/tpm/tpm_tis_core.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
index f71ecd8..196cd28 100644
--- a/drivers/char/tpm/tpm_tis_core.c
+++ b/drivers/char/tpm/tpm_tis_core.c
@@ -222,8 +222,14 @@ static int request_locality(struct tpm_chip *chip, int l)
} else {
/* wait for burstcount */
do {
- if (check_locality(chip, l))
+ if (check_locality(chip, l)) {
+ if (wait_for_tpm_stat_result(chip, TPM_STS_GO,
+ 0, chip->timeout_c,
+ &priv->int_queue,
+ false) < 0)
+ return -ETIME;
return l;
+ }
tpm_msleep(TPM_TIMEOUT);
} while (time_before(jiffies, stop));
}
--
2.7.4
^ permalink raw reply related
* Re: [PATCH 0/4] Add I2C controller support for MT6797 SoC
From: Manivannan Sadhasivam @ 2020-05-12 14:12 UTC (permalink / raw)
To: matthias.bgg, robh+dt
Cc: devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
adamboardman
In-Reply-To: <20200222162444.11590-1-manivannan.sadhasivam@linaro.org>
Hi Matthias,
On Sat, Feb 22, 2020 at 09:54:40PM +0530, Manivannan Sadhasivam wrote:
> Hello,
>
> This patchset adds I2C controller support for Mediatek MT6797 SoC. There
> are a total of 8 I2C controllers in this SoC (2 being shared) and they are
> same as the controllers present in MT6577 SoC. Hence, the driver support is
> added with DT fallback method.
>
> As per the datasheet, there are controllers with _imm prefix like i2c2_imm
> and i2c3_imm. These appears to be in different memory regions but sharing
> the same pins with i2c2 and i2c3 respectively. Since there is no clear
> evidence of what they really are, I've adapted the numbering/naming scheme
> from the downstream code by Mediatek.
>
> This patchset has been tested on 96Boards X20 development board.
>
Looks like this series has slipped through the cracks...
Thanks,
Mani
> Thanks,
> Mani
>
> Manivannan Sadhasivam (4):
> dt-bindings: i2c: Document I2C controller binding for MT6797 SoC
> arm64: dts: mediatek: Add I2C support for MT6797 SoC
> arm64: dts: mediatek: Enable I2C support for 96Boards X20 Development
> board
> arm64: dts: mediatek: Switch to SPDX license identifier for MT6797 SoC
>
> .../devicetree/bindings/i2c/i2c-mt65xx.txt | 1 +
> .../boot/dts/mediatek/mt6797-x20-dev.dts | 49 ++++
> arch/arm64/boot/dts/mediatek/mt6797.dtsi | 229 +++++++++++++++++-
> 3 files changed, 271 insertions(+), 8 deletions(-)
>
> --
> 2.17.1
>
^ permalink raw reply
* Re: [PATCH v2 5/6] dmaengine: dw: Introduce max burst length hw config
From: Serge Semin @ 2020-05-12 14:08 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Serge Semin, Vinod Koul, Viresh Kumar, Dan Williams,
Alexey Malahov, Thomas Bogendoerfer, Paul Burton, Ralf Baechle,
Arnd Bergmann, Rob Herring, linux-mips, devicetree, dmaengine,
linux-kernel
In-Reply-To: <20200508114153.GK185537@smile.fi.intel.com>
On Fri, May 08, 2020 at 02:41:53PM +0300, Andy Shevchenko wrote:
> On Fri, May 08, 2020 at 01:53:03PM +0300, Serge Semin wrote:
> > IP core of the DW DMA controller may be synthesized with different
> > max burst length of the transfers per each channel. According to Synopsis
> > having the fixed maximum burst transactions length may provide some
> > performance gain. At the same time setting up the source and destination
> > multi size exceeding the max burst length limitation may cause a serious
> > problems. In our case the system just hangs up. In order to fix this
> > lets introduce the max burst length platform config of the DW DMA
> > controller device and don't let the DMA channels configuration code
> > exceed the burst length hardware limitation. Depending on the IP core
> > configuration the maximum value can vary from channel to channel.
> > It can be detected either in runtime from the DWC parameter registers
> > or from the dedicated dts property.
>
> I'm wondering what can be the scenario when your peripheral will ask something
> which is not supported by DMA controller?
I may misunderstood your statement, because seeing your activity around my
patchsets including the SPI patchset and sometimes very helpful comments,
this question answer seems too obvious to see you asking it.
No need to go far for an example. See the DW APB SSI driver. Its DMA module
specifies the burst length to be 16, while not all of ours channels supports it.
Yes, originally it has been developed for the Intel Midfield SPI, but since I
converted the driver into a generic code we can't use a fixed value. For instance
in our hardware only two DMA channels of total 16 are capable of bursting up to
16 bytes (data items) at a time, the rest of them are limited with up to 4 bytes
burst length. While there are two SPI interfaces, each of which need to have two
DMA channels for communications. So I need four channels in total to allocate to
provide the DMA capability for all interfaces. In order to set the SPI controller
up with valid optimized parameters the max-burst-length is required. Otherwise we
can end up with buffers overrun/underrun.
>
> Peripheral needs to supply a lot of configuration parameters specific to the
> DMA controller in use (that's why we have struct dw_dma_slave).
> So, seems to me the feasible approach is supply correct data in the first place.
How to supply a valid data if clients don't know the DMA controller limitations
in general?
>
> If you have specific channels to acquire then you probably need to provide a
> custom xlate / filter functions. Because above seems a bit hackish workaround
> of dynamic channel allocation mechanism.
No, I don't have a specific channel to acquire and in general you may use any
returned from the DMA subsystem (though some platforms may need a dedicated
channels to use, in this case xlate / filter is required). In our SoC any DW DMAC
channel can be used for any DMA-capable peripherals like SPI, I2C, UART. But the
their DMA settings must properly and optimally configured. It can be only done
if you know the DMA controller parameters like max burst length, max block-size,
etc.
So no. The change proposed by this patch isn't workaround, but a useful feature,
moreover expected to be supported by the generic DMA subsystem.
>
> But let's see what we can do better. Since maximum is defined on the slave side
> device, it probably needs to define minimum as well, otherwise it's possible
> that some hardware can't cope underrun bursts.
There is no need to define minimum if such limit doesn't exists except a
natural 1. Moreover it doesn't exist for all DMA controllers seeing noone has
added such capability into the generic DMA subsystem so far.
-Sergey
>
> Vinod, what do you think?
>
> --
> With Best Regards,
> Andy Shevchenko
>
>
^ permalink raw reply
* Re: [PATCH V5 1/7] soc: qcom: geni: Support for ICC voting
From: Akash Asthana @ 2020-05-12 14:02 UTC (permalink / raw)
To: Matthias Kaehlcke
Cc: gregkh, agross, bjorn.andersson, wsa, broonie, mark.rutland,
robh+dt, linux-i2c, linux-spi, devicetree, swboyd, mgautam,
linux-arm-msm, linux-serial, dianders, evgreen, georgi.djakov
In-Reply-To: <20200508171352.GA4525@google.com>
On 5/8/2020 10:43 PM, Matthias Kaehlcke wrote:
> Hi Akash,
>
> note: my comments below are clearly entering bikeshed territory. Please
> take what you agree with and feel free to ignore the rest.
>
> On Fri, May 08, 2020 at 12:03:33PM +0530, Akash Asthana wrote:
>> Add necessary macros and structure variables to support ICC BW
>> voting from individual SE drivers.
>>
>> Signed-off-by: Akash Asthana <akashast@codeaurora.org>
>> ---
>> Changes in V2:
>> - As per Bjorn's comment dropped enums for ICC paths, given the three
>> paths individual members
>>
>> Changes in V3:
>> - Add geni_icc_get, geni_icc_vote_on and geni_icc_vote_off as helper API.
>> - Add geni_icc_path structure in common header
>>
>> Changes in V4:
>> - As per Bjorn's comment print error message in geni_icc_get if return
>> value is not -EPROBE_DEFER.
>> - As per Bjorn's comment remove NULL on path before calling icc_set_bw
>> API.
>> - As per Bjorn's comment drop __func__ print.
>> - As per Matthias's comment, make ICC path a array instead of individual
>> member entry in geni_se struct.
>>
>> Note: I have ignored below check patch suggestion because it was throwing
>> compilation error as 'icc_ddr' is not compile time comstant.
>>
>> WARNING: char * array declaration might be better as static const
>> - FILE: drivers/soc/qcom/qcom-geni-se.c:726:
>> - const char *icc_names[] = {"qup-core", "qup-config", icc_ddr};
>>
>> Changes in V5:
>> - As per Matthias's comment defined enums for ICC paths.
>> - Integrate icc_enable/disable with power on/off call for driver.
>> - As per Matthias's comment added icc_path_names array to print icc path name
>> in failure case.
>> - As per Georgi's suggestion assume peak_bw = avg_bw if not mentioned.
>>
>> drivers/soc/qcom/qcom-geni-se.c | 92 +++++++++++++++++++++++++++++++++++++++++
>> include/linux/qcom-geni-se.h | 42 +++++++++++++++++++
>> 2 files changed, 134 insertions(+)
>>
>> diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c
>> index 7d622ea..63403bf 100644
>> --- a/drivers/soc/qcom/qcom-geni-se.c
>> +++ b/drivers/soc/qcom/qcom-geni-se.c
>> @@ -92,6 +92,9 @@ struct geni_wrapper {
>> struct clk_bulk_data ahb_clks[NUM_AHB_CLKS];
>> };
>>
>> +static const char * const icc_path_names[] = {"qup-core", "qup-config",
>> + "qup-memory"};
> nit: the indentation is a bit odd. I would align it either with "qup-core" or
> at a tab stop nearby.
ok
>
>> +
>> #define QUP_HW_VER_REG 0x4
>>
>> /* Common SE registers */
>> @@ -720,6 +723,95 @@ void geni_se_rx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len)
>> }
>> EXPORT_SYMBOL(geni_se_rx_dma_unprep);
>>
>> +int geni_icc_get(struct geni_se *se, const char *icc_ddr)
>> +{
>> + int i, icc_err;
> nit: the 'icc_' prefix doesn't add value here, just 'err' would be less
> 'noisy' IMO.
ok
>
>> + const char *icc_names[] = {"qup-core", "qup-config", icc_ddr};
> nit: you could avoid repeating the first to strings by referencing
> icc_path_names[GENI_TO_CORE] and icc_path_names[CPU_TO_GENI]. Not sure
> if it's really better, it avoids the redundant names, but is slightly
> less readable.
I thought of that but current implementation looks neater to me.
>
>> +
>> + for (i = 0; i < ARRAY_SIZE(se->icc_paths); i++) {
>> + if (!icc_names[i])
>> + continue;
>> +
>> + se->icc_paths[i].path = devm_of_icc_get(se->dev, icc_names[i]);
>> + if (IS_ERR(se->icc_paths[i].path))
>> + goto icc_get_failure;
> nit: since there is only a single label it isn't really necessary to be so
> precise. 'goto err' is very common in the kernel, 'err_icc_get' would be
> another alternative.
okay
>
>> + }
>> +
>> + return 0;
>> +
>> +icc_get_failure:
>> + icc_err = PTR_ERR(se->icc_paths[i].path);
>> + if (icc_err != -EPROBE_DEFER)
>> + dev_err_ratelimited(se->dev, "Failed to get ICC path:%s, ret:%d\n",
> All the logs in this patch result in something like "... path:qup-core, ret:42".
> For humans I think it is more intuitive to parse "... path 'qup-core': 42".
ok
Thanks for review and feedback
Regards,
Akash
>
> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,\na Linux Foundation Collaborative Project
^ permalink raw reply
* Re: [PATCH v3 0/6] allow ramoops to collect all kmesg_dump events
From: Pavel Tatashin @ 2020-05-12 14:03 UTC (permalink / raw)
To: Petr Mladek
Cc: Kees Cook, Anton Vorontsov, Colin Cross, Tony Luck,
Jonathan Corbet, Rob Herring, Benson Leung,
Enric Balletbo i Serra, Sergey Senozhatsky, Steven Rostedt,
James Morris, Sasha Levin, Linux Doc Mailing List, LKML,
devicetree
In-Reply-To: <20200512131655.GE17734@linux-b0ei>
Hi Petr,
> Alternative solution is to dump all messages using ramoops. The
> problem is that it currently works only during Oops and panic
> situation. This is solved by this patchset.
>
>
> OK, I personally see this as two separate problems:
>
> 1. Missing support to set loglevel per console.
> 2. Missing support to dump messages for other reasons.
>
> I would remove the paragraph about console log levels completely.
OK, I see your point, this paragraph can be removed, however, I think
it makes it clear to understand the rationale for this change. As I
understand, the per console loglevel has been proposed but were never
accepted.
> It is your reason to use ramoops. But it is not reason to modify
> the logic about max_reason.
>
>
> Now, the max_reason logic makes sense only when all the values
> have some ordering. Is this the case?
>
> I see it as two distinct sets:
>
> + panic, oops, emerg: describe how critical is an error situation
> + restart, halt, poweroff: describe behavior when the system goes down
>
> Let's say that panic is more critical than oops. Is restart more
> critical than halt?
>
> If you want the dump during restart. Does it mean that you want it
> also during emergency situation?
>
> My fear is that this patchset is going to introduce user interface
> (max_reason) with a weird logic. IMHO, max_reason is confusing even
> in the code and we should not spread this to users.
>
> Is there any reason why the existing printk.always_kmsg_dump option
> is not enough for you?
printk.always_kmsg_dump is not working for me because ramoops has its
own filtering based on dump_oops boolean, and ignores everything but
panics and conditionally oops.
max_reason makes the ramoops internal logic cleaner compared to using dump_oops.
I agree, the reasons in kmsg_dump_reason do not order well (I
actually want to add another reason for kexec type reboots, and where
do I put it?), so how about if we change the ordering list to
bitfield/flags, and instead of max_reason provide: "reasons" bitset?
Thank you,
Pasha
^ permalink raw reply
* Re: [PATCH v4 1/2] clk: qcom: Add DT bindings for MSM8939 GCC
From: Rob Herring @ 2020-05-12 13:58 UTC (permalink / raw)
To: Bryan O'Donoghue
Cc: linux-clk, p.zabel, vincent.knecht, devicetree, shawn.guo,
robh+dt, linux-arm-msm, konradybcio, sboyd, mturquette,
linux-kernel, agross, bjorn.andersson
In-Reply-To: <20200512115023.2856617-2-bryan.odonoghue@linaro.org>
On Tue, 12 May 2020 12:50:22 +0100, Bryan O'Donoghue wrote:
> Add compatible strings and the include files for the MSM8939 GCC.
>
> Cc: Andy Gross <agross@kernel.org>
> Cc: Bjorn Andersson <bjorn.andersson@linaro.org>
> Cc: Michael Turquette <mturquette@baylibre.com>
> Cc: Stephen Boyd <sboyd@kernel.org>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: linux-arm-msm@vger.kernel.org
> Cc: linux-clk@vger.kernel.org
> Cc: devicetree@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org
> Tested-by: Vincent Knecht <vincent.knecht@mailoo.org>
> Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
> ---
> .../devicetree/bindings/clock/qcom,gcc.yaml | 3 +
> include/dt-bindings/clock/qcom,gcc-msm8939.h | 206 ++++++++++++++++++
> include/dt-bindings/reset/qcom,gcc-msm8939.h | 110 ++++++++++
> 3 files changed, 319 insertions(+)
> create mode 100644 include/dt-bindings/clock/qcom,gcc-msm8939.h
> create mode 100644 include/dt-bindings/reset/qcom,gcc-msm8939.h
>
Reviewed-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* Re: [PATCH] dt-bindings: media: venus: Add an optional power domain for perf voting
From: Rob Herring @ 2020-05-12 13:55 UTC (permalink / raw)
To: Rajendra Nayak
Cc: mka, linux-arm-msm, robh+dt, agross, devicetree, bjorn.andersson,
linux-kernel, stanimir.varbanov, linux-media
In-Reply-To: <1589281966-13436-1-git-send-email-rnayak@codeaurora.org>
On Tue, 12 May 2020 16:42:46 +0530, Rajendra Nayak wrote:
> Add an optional power domain which when specified can be used for
> setting the performance state of Venus.
>
> Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
> ---
> Documentation/devicetree/bindings/media/qcom,sc7180-venus.yaml | 4 +++-
> Documentation/devicetree/bindings/media/qcom,sdm845-venus-v2.yaml | 4 +++-
> 2 files changed, 6 insertions(+), 2 deletions(-)
>
My bot found errors running 'make dt_binding_check' on your patch:
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/media/qcom,sdm845-venus-v2.example.dt.yaml: video-codec@aa00000: power-domain-names: ['venus', 'vcodec0', 'vcodec1'] is too short
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/media/qcom,sc7180-venus.example.dt.yaml: video-codec@aa00000: power-domain-names: ['venus', 'vcodec0'] is too short
See https://patchwork.ozlabs.org/patch/1288381
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure dt-schema is up to date:
pip3 install git+https://github.com/devicetree-org/dt-schema.git@master --upgrade
Please check and re-submit.
^ permalink raw reply
* Re: [PATCH] arm: dts: am33xx-bone-common: add gpio-line-names
From: Tony Lindgren @ 2020-05-12 13:52 UTC (permalink / raw)
To: Linus Walleij
Cc: Grygorii Strashko, Benoît Cousson, Rob Herring, linux-omap,
devicetree, linux-kernel, Jason Kridner, Robert Nelson,
Drew Fustini
In-Reply-To: <20200508165821.GA14555@x1>
Hi,
Adding Linus W to Cc, would be good to get some comments on this.
* Drew Fustini <drew@beagleboard.org> [200508 09:58]:
> Add gpio-line-names properties to the gpio controller nodes.
> BeagleBone boards have P8 and P9 headers [0] which expose many the
> AM3358 SoC balls to stacking expansion boards called "capes", or to
> other external connections like jumper wires to a breadboard.
>
> Many of the P8/P9 header pins can muxed to a gpio line. The
> gpio-line-names describe which P8/P9 pin that line goes to and the
> default mux for that P8/P9 pin. Some lines are not routed to the
> P8/P9 headers, but instead are dedicated to some functionality such as
> status LEDs. The line name will indicate this. Some line names are
> left empty as the corresponding AM3358 balls are not connected.
>
> The goal is to make it easier for a user viewing the output of gpioinfo
> to determine which P8/P9 pin is connected to a line. The output of
> gpioinfo on a BeagleBone Black will now look like this:
>
> gpiochip0 - 32 lines:
> line 0: "ethernet" unused input active-high
> line 1: "ethernet" unused input active-high
> line 2: "P9_22 spi0_sclk" unused input active-high
> line 3: "P9_21 spi0_d0" unused input active-high
> line 4: "P9_18 spi0_d1" unused input active-high
> line 5: "P9_17 spi0_cs0" unused input active-high
> line 6: "sd card" "cd" input active-low [used]
> line 7: "P9_42A ecappwm0" unused input active-high
> line 8: "P8_35 hdmi" unused input active-high
> line 9: "P8_33 hdmi" unused input active-high
> line 10: "P8_31 hdmi" unused input active-high
> line 11: "P8_32 hdmi" unused input active-high
> line 12: "P9_20 i2c2_sda" unused input active-high
> line 13: "P9_19 i2c2_scl" unused input active-high
> line 14: "P9_26 uart1_rxd" unused input active-high
> line 15: "P9_24 uart1_txd" unused input active-high
> line 16: "ethernet" unused input active-high
> line 17: "ethernet" unused input active-high
> line 18: "usb" unused input active-high
> line 19: "hdmi" unused input active-high
> line 20: "P9_41B gpio" unused input active-high
> line 21: "ethernet" unused input active-high
> line 22: "P8_19 ehrpwm2a" unused input active-high
> line 23: "P8_13 ehrpwm2b" unused input active-high
> line 24: unnamed unused input active-high
> line 25: unnamed unused input active-high
> line 26: "P8_14 gpio" unused input active-high
> line 27: "P8_17 gpio" unused input active-high
> line 28: "ethernet" unused input active-high
> line 29: "ethernet" unused input active-high
> line 30: "P9_11 uart4_rxd" unused input active-high
> line 31: "P9_13 uart4_txd" unused input active-high
> gpiochip1 - 32 lines:
> line 0: "P8_25 emmc" unused input active-high
> line 1: "emmc" unused input active-high
> line 2: "P8_5 emmc" unused input active-high
> line 3: "P8_6 emmc" unused input active-high
> line 4: "P8_23 emmc" unused input active-high
> line 5: "P8_22 emmc" unused input active-high
> line 6: "P8_3 emmc" unused input active-high
> line 7: "P8_4 emmc" unused input active-high
> line 8: unnamed unused input active-high
> line 9: unnamed unused input active-high
> line 10: unnamed unused input active-high
> line 11: unnamed unused input active-high
> line 12: "P8_12 gpio" unused input active-high
> line 13: "P8_11 gpio" unused input active-high
> line 14: "P8_16 gpio" unused input active-high
> line 15: "P8_15 gpio" unused input active-high
> line 16: "P9_15A gpio" unused input active-high
> line 17: "P9_23 gpio" unused input active-high
> line 18: "P9_14 ehrpwm1a" unused input active-high
> line 19: "P9_16 ehrpwm1b" unused input active-high
> line 20: "emmc" unused input active-high
> line 21: "usr0 led" "beaglebone:green:heart" output active-high [used]
> line 22: "usr1 led" "beaglebone:green:mmc0" output active-high [used]
> line 23: "usr2 led" "beaglebone:green:usr2" output active-high [used]
> line 24: "usr3 led" "beaglebone:green:usr3" output active-high [used]
> line 25: "hdmi" "interrupt" input active-high [used]
> line 26: "usb" unused input active-high
> line 27: "hdmi audio" "enable" output active-high [used]
> line 28: "P9_12 gpio" unused input active-high
> line 29: "P8_26 gpio" unused input active-high
> line 30: "P8_21 emmc" unused input active-high
> line 31: "P8_20 emmc" unused input active-high
> gpiochip2 - 32 lines:
> line 0: "P9_15B gpio" unused input active-high
> line 1: "P8_18 gpio" unused input active-high
> line 2: "P8_7 gpio" unused input active-high
> line 3: "P8_8 gpio" unused input active-high
> line 4: "P8_10 gpio" unused input active-high
> line 5: "P8_9 gpio" unused input active-high
> line 6: "P8_45 hdmi" unused input active-high
> line 7: "P8_46 hdmi" unused input active-high
> line 8: "P8_43 hdmi" unused input active-high
> line 9: "P8_44 hdmi" unused input active-high
> line 10: "P8_41 hdmi" unused input active-high
> line 11: "P8_42 hdmi" unused input active-high
> line 12: "P8_39 hdmi" unused input active-high
> line 13: "P8_40 hdmi" unused input active-high
> line 14: "P8_37 hdmi" unused input active-high
> line 15: "P8_38 hdmi" unused input active-high
> line 16: "P8_36 hdmi" unused input active-high
> line 17: "P8_34 hdmi" unused input active-high
> line 18: "ethernet" unused input active-high
> line 19: "ethernet" unused input active-high
> line 20: "ethernet" unused input active-high
> line 21: "ethernet" unused input active-high
> line 22: "P8_27 hdmi" unused input active-high
> line 23: "P8_29 hdmi" unused input active-high
> line 24: "P8_28 hdmi" unused input active-high
> line 25: "P8_30 hdmi" unused input active-high
> line 26: "emmc" unused input active-high
> line 27: "emmc" unused input active-high
> line 28: "emmc" unused input active-high
> line 29: "emmc" unused input active-high
> line 30: "emmc" unused input active-high
> line 31: "emmc" unused input active-high
> gpiochip3 - 32 lines:
> line 0: "ethernet" unused input active-high
> line 1: "ethernet" unused input active-high
> line 2: "ethernet" unused input active-high
> line 3: "ethernet" unused input active-high
> line 4: "ethernet" unused input active-high
> line 5: "i2c0" unused input active-high
> line 6: "i2c0" unused input active-high
> line 7: "emu" unused input active-high
> line 8: "emu" unused input active-high
> line 9: "ethernet" unused input active-high
> line 10: "ethernet" unused input active-high
> line 11: unnamed unused input active-high
> line 12: unnamed unused input active-high
> line 13: "usb" unused input active-high
> line 14: "P9_31 spi1_sclk" unused input active-high
> line 15: "P9_29 spi1_d0" unused input active-high
> line 16: "P9_30 spi1_d1" unused input active-high
> line 17: "P9_28 spi1_cs0" unused input active-high
> line 18: "P9_42B ecappwm0" unused input active-high
> line 19: "P9_27 gpio" unused input active-high
> line 20: "P9_41A gpio" unused input active-high
> line 21: "P9_25 gpio" unused input active-high
> line 22: unnamed unused input active-high
> line 23: unnamed unused input active-high
> line 24: unnamed unused input active-high
> line 25: unnamed unused input active-high
> line 26: unnamed unused input active-high
> line 27: unnamed unused input active-high
> line 28: unnamed unused input active-high
> line 29: unnamed unused input active-high
> line 30: unnamed unused input active-high
> line 31: unnamed unused input active-high
>
> [0] https://beagleboard.org/Support/bone101
> [1] https://beagleboard.org/capes
>
> Reviewed-by: Jason Kridner <jason@beagleboard.org>
> Reviewed-by: Robert Nelson <robertcnelson@gmail.com>
> Signed-off-by: Drew Fustini <drew@beagleboard.org>
> ---
> arch/arm/boot/dts/am335x-bone-common.dtsi | 144 ++++++++++++++++++++++
> 1 file changed, 144 insertions(+)
>
> diff --git a/arch/arm/boot/dts/am335x-bone-common.dtsi b/arch/arm/boot/dts/am335x-bone-common.dtsi
> index 6c9187bc0f17..defdf68edb58 100644
> --- a/arch/arm/boot/dts/am335x-bone-common.dtsi
> +++ b/arch/arm/boot/dts/am335x-bone-common.dtsi
> @@ -397,3 +397,147 @@
> clocks = <&clk_32768_ck>, <&clk_24mhz_clkctrl AM3_CLK_24MHZ_CLKDIV32K_CLKCTRL 0>;
> clock-names = "ext-clk", "int-clk";
> };
> +
> +&gpio0 {
> + gpio-line-names =
> + "ethernet",
> + "ethernet",
> + "P9_22 spi0_sclk",
> + "P9_21 spi0_d0",
> + "P9_18 spi0_d1",
> + "P9_17 spi0_cs0",
> + "sd card",
> + "P9_42A ecappwm0",
> + "P8_35 hdmi",
> + "P8_33 hdmi",
> + "P8_31 hdmi",
> + "P8_32 hdmi",
> + "P9_20 i2c2_sda",
> + "P9_19 i2c2_scl",
> + "P9_26 uart1_rxd",
> + "P9_24 uart1_txd",
> + "ethernet",
> + "ethernet",
> + "usb",
> + "hdmi",
> + "P9_41B gpio",
> + "ethernet",
> + "P8_19 ehrpwm2a",
> + "P8_13 ehrpwm2b",
> + "",
> + "",
> + "P8_14 gpio",
> + "P8_17 gpio",
> + "ethernet",
> + "ethernet",
> + "P9_11 uart4_rxd",
> + "P9_13 uart4_txd";
> +};
> +
> +&gpio1 {
> + gpio-line-names =
> + "P8_25 emmc",
> + "emmc",
> + "P8_5 emmc",
> + "P8_6 emmc",
> + "P8_23 emmc",
> + "P8_22 emmc",
> + "P8_3 emmc",
> + "P8_4 emmc",
> + "",
> + "",
> + "",
> + "",
> + "P8_12 gpio",
> + "P8_11 gpio",
> + "P8_16 gpio",
> + "P8_15 gpio",
> + "P9_15A gpio",
> + "P9_23 gpio",
> + "P9_14 ehrpwm1a",
> + "P9_16 ehrpwm1b",
> + "emmc",
> + "usr0 led",
> + "usr1 led",
> + "usr2 led",
> + "usr3 led",
> + "hdmi",
> + "usb",
> + "hdmi audio",
> + "P9_12 gpio",
> + "P8_26 gpio",
> + "P8_21 emmc",
> + "P8_20 emmc";
> +};
> +
> +&gpio2 {
> + gpio-line-names =
> + "P9_15B gpio",
> + "P8_18 gpio",
> + "P8_7 gpio",
> + "P8_8 gpio",
> + "P8_10 gpio",
> + "P8_9 gpio",
> + "P8_45 hdmi",
> + "P8_46 hdmi",
> + "P8_43 hdmi",
> + "P8_44 hdmi",
> + "P8_41 hdmi",
> + "P8_42 hdmi",
> + "P8_39 hdmi",
> + "P8_40 hdmi",
> + "P8_37 hdmi",
> + "P8_38 hdmi",
> + "P8_36 hdmi",
> + "P8_34 hdmi",
> + "ethernet",
> + "ethernet",
> + "ethernet",
> + "ethernet",
> + "P8_27 hdmi",
> + "P8_29 hdmi",
> + "P8_28 hdmi",
> + "P8_30 hdmi",
> + "emmc",
> + "emmc",
> + "emmc",
> + "emmc",
> + "emmc",
> + "emmc";
> +};
> +
> +&gpio3 {
> + gpio-line-names =
> + "ethernet",
> + "ethernet",
> + "ethernet",
> + "ethernet",
> + "ethernet",
> + "i2c0",
> + "i2c0",
> + "emu",
> + "emu",
> + "ethernet",
> + "ethernet",
> + "",
> + "",
> + "usb",
> + "P9_31 spi1_sclk",
> + "P9_29 spi1_d0",
> + "P9_30 spi1_d1",
> + "P9_28 spi1_cs0",
> + "P9_42B ecappwm0",
> + "P9_27 gpio",
> + "P9_41A gpio",
> + "P9_25 gpio",
> + "",
> + "",
> + "",
> + "",
> + "",
> + "",
> + "",
> + "",
> + "",
> + "";
> +};
> --
> 2.20.1
>
^ permalink raw reply
* Re: [PATCH v2 5/5] mfd: lochnagar: Move binding over to dtschema
From: Rob Herring @ 2020-05-12 13:49 UTC (permalink / raw)
To: Charles Keepax
Cc: lee.jones, broonie, mturquette, sboyd, jdelvare, linux,
linus.walleij, lgirdwood, linux-kernel, devicetree, patches
In-Reply-To: <20200504154757.17519-5-ckeepax@opensource.cirrus.com>
On Mon, May 04, 2020 at 04:47:57PM +0100, Charles Keepax wrote:
> Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
> ---
>
> Changes since v1:
> - Removed contains on the compatible
> - Moved all sub-nodes into here directly only using $ref for properties
> - As the regulator binding only contained subnodes that file is now deleted
> - Removed some pointless descriptions
>
> A little nervous about the amount of clock and regulator stuff this
> pulls into the MFD file, any comments on that welcome? Would it be worth
> looking into something along the lines of the definitions stuff to keep
> some of that out in the clock and regulator bindings?
It's fine like this. Other than my comments on patch 3, looks fine.
Respin and I'll apply.
>
> Thanks,
> Charles
>
> .../devicetree/bindings/mfd/cirrus,lochnagar.txt | 85 -----
> .../devicetree/bindings/mfd/cirrus,lochnagar.yaml | 352 +++++++++++++++++++++
> .../bindings/regulator/cirrus,lochnagar.txt | 82 -----
> MAINTAINERS | 11 +-
> 4 files changed, 357 insertions(+), 173 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/mfd/cirrus,lochnagar.txt
> create mode 100644 Documentation/devicetree/bindings/mfd/cirrus,lochnagar.yaml
> delete mode 100644 Documentation/devicetree/bindings/regulator/cirrus,lochnagar.txt
^ permalink raw reply
* Re: [PATCH v2 3/5] pinctrl: lochnagar: Move binding over to dtschema
From: Rob Herring @ 2020-05-12 13:44 UTC (permalink / raw)
To: Charles Keepax
Cc: lee.jones, broonie, mturquette, sboyd, jdelvare, linux,
linus.walleij, lgirdwood, linux-kernel, devicetree, patches
In-Reply-To: <20200504154757.17519-3-ckeepax@opensource.cirrus.com>
On Mon, May 04, 2020 at 04:47:55PM +0100, Charles Keepax wrote:
> Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
> ---
>
> Changes since v1:
> - Moved sub-node into MFD file leaving just the properties in here
> - Removed contains on the compatible
> - Added a required -pins suffix for pinmux/ctrl nodes
> - Added some extra blank lines for readability
>
> Thanks,
> Charles
>
> .../bindings/pinctrl/cirrus,lochnagar.txt | 141 ---------------
> .../bindings/pinctrl/cirrus,lochnagar.yaml | 191 +++++++++++++++++++++
> 2 files changed, 191 insertions(+), 141 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/pinctrl/cirrus,lochnagar.txt
> create mode 100644 Documentation/devicetree/bindings/pinctrl/cirrus,lochnagar.yaml
> diff --git a/Documentation/devicetree/bindings/pinctrl/cirrus,lochnagar.yaml b/Documentation/devicetree/bindings/pinctrl/cirrus,lochnagar.yaml
> new file mode 100644
> index 0000000000000..2d6f832f1e4c5
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pinctrl/cirrus,lochnagar.yaml
> @@ -0,0 +1,191 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/pinctrl/cirrus,lochnagar.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Cirrus Logic Lochnagar Audio Development Board
> +
> +maintainers:
> + - patches@opensource.cirrus.com
> +
> +description: |
> + Lochnagar is an evaluation and development board for Cirrus Logic
> + Smart CODEC and Amp devices. It allows the connection of most Cirrus
> + Logic devices on mini-cards, as well as allowing connection of various
> + application processor systems to provide a full evaluation platform.
> + Audio system topology, clocking and power can all be controlled through
> + the Lochnagar, allowing the device under test to be used in a variety of
> + possible use cases.
> +
> + This binding document describes the binding for the pinctrl portion of
> + the driver.
> +
> + Also see these documents for generic binding information:
> + [1] GPIO : ../gpio/gpio.txt
> + [2] Pinctrl: ../pinctrl/pinctrl-bindings.txt
> +
> + And these for relevant defines:
> + [3] include/dt-bindings/pinctrl/lochnagar.h
> +
> + This binding must be part of the Lochnagar MFD binding:
> + [4] ../mfd/cirrus,lochnagar.yaml
> +
> +properties:
> + compatible:
> + enum:
> + - cirrus,lochnagar-pinctrl
> +
> + gpio-controller:
> + description:
> + Indicates this device is a GPIO controller.
No need to re-describe common properties unless you have something
specific about this device to say. Just:
gpio-controller: true
> +
> + '#gpio-cells':
> + description:
> + The first cell is the pin number and the second cell is used
> + to specify optional parameters.
> + const: 2
> +
> + gpio-ranges:
> + description:
> + Range of pins managed by the GPIO controller, see [1]. Both the
> + GPIO and Pinctrl base should be set to zero and the count to the
> + appropriate of the LOCHNAGARx_PIN_NUM_GPIOS define, see [3].
> + maxItems: 1
> +
> + pinctrl-0:
> + description:
> + A phandle to the default pinctrl state.
> +
> + pinctrl-names:
> + description:
> + A pinctrl state named "default" must be defined.
> + const: default
> +
> +patternProperties:
> + '^.*$':
No need to allow anything here. Use 'pin-settings' instead.
Needs 'type: object' too.
> + patternProperties:
> + '^.*-pins$':
Just '-pins$' is equivalent.
> + description:
> + The pin configurations are defined as a child of the pinctrl
> + states node, see [2]. Each sub-node can have the following
> + properties.
> + type: object
> + allOf:
> + - $ref: pincfg-node.yaml#
> + - $ref: pinmux-node.yaml#
> +
> + properties:
> + groups:
> + description:
> + A list of groups to select (either this or "pins" must be
> + specified), available groups.
> + enum: [ codec-aif1, codec-aif2, codec-aif3, dsp-aif1,
> + dsp-aif2, psia1, psia2, gf-aif1, gf-aif2, gf-aif3,
> + gf-aif4, spdif-aif, usb-aif1, usb-aif2, adat-aif,
> + soundcard-aif ]
> +
> + pins:
> + description:
> + A list of pin names to select (either this or "groups" must
> + be specified), available pins.
> + enum: [ fpga-gpio1, fpga-gpio2, fpga-gpio3, fpga-gpio4,
> + fpga-gpio5, fpga-gpio6, codec-gpio1, codec-gpio2,
> + codec-gpio3, codec-gpio4, codec-gpio5, codec-gpio6,
> + codec-gpio7, codec-gpio8, dsp-gpio1, dsp-gpio2,
> + dsp-gpio3, dsp-gpio4, dsp-gpio5, dsp-gpio6,
> + gf-gpio2, gf-gpio3, gf-gpio7, codec-aif1-bclk,
> + codec-aif1-rxdat, codec-aif1-lrclk, codec-aif1-txdat,
> + codec-aif2-bclk, codec-aif2-rxdat, codec-aif2-lrclk,
> + codec-aif2-txdat, codec-aif3-bclk, codec-aif3-rxdat,
> + codec-aif3-lrclk, codec-aif3-txdat, dsp-aif1-bclk,
> + dsp-aif1-rxdat, dsp-aif1-lrclk, dsp-aif1-txdat,
> + dsp-aif2-bclk, dsp-aif2-rxdat, dsp-aif2-lrclk,
> + dsp-aif2-txdat, psia1-bclk, psia1-rxdat, psia1-lrclk,
> + psia1-txdat, psia2-bclk, psia2-rxdat, psia2-lrclk,
> + psia2-txdat, gf-aif3-bclk, gf-aif3-rxdat,
> + gf-aif3-lrclk, gf-aif3-txdat, gf-aif4-bclk,
> + gf-aif4-rxdat, gf-aif4-lrclk, gf-aif4-txdat,
> + gf-aif1-bclk, gf-aif1-rxdat, gf-aif1-lrclk,
> + gf-aif1-txdat, gf-aif2-bclk, gf-aif2-rxdat,
> + gf-aif2-lrclk, gf-aif2-txdat, dsp-uart1-rx,
> + dsp-uart1-tx, dsp-uart2-rx, dsp-uart2-tx,
> + gf-uart2-rx, gf-uart2-tx, usb-uart-rx, codec-pdmclk1,
> + codec-pdmdat1, codec-pdmclk2, codec-pdmdat2,
> + codec-dmicclk1, codec-dmicdat1, codec-dmicclk2,
> + codec-dmicdat2, codec-dmicclk3, codec-dmicdat3,
> + codec-dmicclk4, codec-dmicdat4, dsp-dmicclk1,
> + dsp-dmicdat1, dsp-dmicclk2, dsp-dmicdat2, i2c2-scl,
> + i2c2-sda, i2c3-scl, i2c3-sda, i2c4-scl, i2c4-sda,
> + dsp-standby, codec-mclk1, codec-mclk2, dsp-clkin,
> + psia1-mclk, psia2-mclk, gf-gpio1, gf-gpio5,
> + dsp-gpio20, led1, led2 ]
> +
> + function:
> + description:
> + The mux function to select, available functions.
> + enum: [ aif, fpga-gpio1, fpga-gpio2, fpga-gpio3, fpga-gpio4,
> + fpga-gpio5, fpga-gpio6, codec-gpio1, codec-gpio2,
> + codec-gpio3, codec-gpio4, codec-gpio5, codec-gpio6,
> + codec-gpio7, codec-gpio8, dsp-gpio1, dsp-gpio2,
> + dsp-gpio3, dsp-gpio4, dsp-gpio5, dsp-gpio6,
> + gf-gpio2, gf-gpio3, gf-gpio7, gf-gpio1, gf-gpio5,
> + dsp-gpio20, codec-clkout, dsp-clkout, pmic-32k,
> + spdif-clkout, clk-12m288, clk-11m2986, clk-24m576,
> + clk-22m5792, xmos-mclk, gf-clkout1, gf-mclk1,
> + gf-mclk3, gf-mclk2, gf-clkout2, codec-mclk1,
> + codec-mclk2, dsp-clkin, psia1-mclk, psia2-mclk,
> + spdif-mclk, codec-irq, codec-reset, dsp-reset,
> + dsp-irq, dsp-standby, codec-pdmclk1, codec-pdmdat1,
> + codec-pdmclk2, codec-pdmdat2, codec-dmicclk1,
> + codec-dmicdat1, codec-dmicclk2, codec-dmicdat2,
> + codec-dmicclk3, codec-dmicdat3, codec-dmicclk4,
> + codec-dmicdat4, dsp-dmicclk1, dsp-dmicdat1,
> + dsp-dmicclk2, dsp-dmicdat2, dsp-uart1-rx,
> + dsp-uart1-tx, dsp-uart2-rx, dsp-uart2-tx,
> + gf-uart2-rx, gf-uart2-tx, usb-uart-rx, usb-uart-tx,
> + i2c2-scl, i2c2-sda, i2c3-scl, i2c3-sda, i2c4-scl,
> + i2c4-sda, spdif-aif, psia1, psia1-bclk, psia1-lrclk,
> + psia1-rxdat, psia1-txdat, psia2, psia2-bclk,
> + psia2-lrclk, psia2-rxdat, psia2-txdat, codec-aif1,
> + codec-aif1-bclk, codec-aif1-lrclk, codec-aif1-rxdat,
> + codec-aif1-txdat, codec-aif2, codec-aif2-bclk,
> + codec-aif2-lrclk, codec-aif2-rxdat, codec-aif2-txdat,
> + codec-aif3, codec-aif3-bclk, codec-aif3-lrclk,
> + codec-aif3-rxdat, codec-aif3-txdat, dsp-aif1,
> + dsp-aif1-bclk, dsp-aif1-lrclk, dsp-aif1-rxdat,
> + dsp-aif1-txdat, dsp-aif2, dsp-aif2-bclk,
> + dsp-aif2-lrclk, dsp-aif2-rxdat, dsp-aif2-txdat,
> + gf-aif3, gf-aif3-bclk, gf-aif3-lrclk, gf-aif3-rxdat,
> + gf-aif3-txdat, gf-aif4, gf-aif4-bclk, gf-aif4-lrclk,
> + gf-aif4-rxdat, gf-aif4-txdat, gf-aif1, gf-aif1-bclk,
> + gf-aif1-lrclk, gf-aif1-rxdat, gf-aif1-txdat, gf-aif2,
> + gf-aif2-bclk, gf-aif2-lrclk, gf-aif2-rxdat,
> + gf-aif2-txdat, usb-aif1, usb-aif2, adat-aif,
> + soundcard-aif ]
> +
> + output-enable:
> + description:
> + Specifies that an AIF group will be used as a master
> + interface (either this or input-enable is required if a
> + group is being muxed to an AIF)
> +
> + input-enable:
> + description:
> + Specifies that an AIF group will be used as a slave
> + interface (either this or output-enable is required if a
> + group is being muxed to an AIF)
> +
> + additionalProperties: false
Blank line.
> + required:
> + - function
> +
> + additionalProperties: false
> +
> +required:
> + - compatible
> + - gpio-controller
> + - '#gpio-cells'
> + - gpio-ranges
> + - pinctrl-0
> + - pinctrl-names
> --
> 2.11.0
>
^ permalink raw reply
* Re: [PATCH 1/2] dt-bindings: chrome: Add cros-ec-typec mux props
From: Heikki Krogerus @ 2020-05-12 13:41 UTC (permalink / raw)
To: Prashant Malani
Cc: Rob Herring, linux-kernel, twawrzynczak, Benson Leung,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Enric Balletbo i Serra, Guenter Roeck
In-Reply-To: <20200511204635.GC136540@google.com>
Hi guys,
On Mon, May 11, 2020 at 01:46:35PM -0700, Prashant Malani wrote:
> Hi Rob,
>
> Thank you for reviewing the patch. Kindly see my comments inline:
>
> On Mon, May 11, 2020 at 02:28:00PM -0500, Rob Herring wrote:
> > On Wed, Apr 22, 2020 at 03:22:39PM -0700, Prashant Malani wrote:
> > > Add properties for mode, orientation and USB data role switches for
> > > Type C connectors. When available, these will allow the Type C connector
> > > class port driver to configure the various switches according to USB PD
> > > information (like orientation, alt mode etc.) provided by the Chrome OS
> > > EC controller.
> > >
> > > Signed-off-by: Prashant Malani <pmalani@chromium.org>
> > > ---
> > > .../bindings/chrome/google,cros-ec-typec.yaml | 27 ++++++++++++++++++-
> > > 1 file changed, 26 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/Documentation/devicetree/bindings/chrome/google,cros-ec-typec.yaml b/Documentation/devicetree/bindings/chrome/google,cros-ec-typec.yaml
> > > index 6d7396ab8bee..b5814640aa32 100644
> > > --- a/Documentation/devicetree/bindings/chrome/google,cros-ec-typec.yaml
> > > +++ b/Documentation/devicetree/bindings/chrome/google,cros-ec-typec.yaml
> > > @@ -21,7 +21,21 @@ properties:
> > > const: google,cros-ec-typec
> > >
> > > connector:
> > > - $ref: /schemas/connector/usb-connector.yaml#
> > > + allOf:
> > > + - $ref: /schemas/connector/usb-connector.yaml#
> > > + - type: object
> > > + properties:
> >
> > These don't seem CrOS EC specific, so why document them as such.
>
> Are you referring to the "mode-switch", "orientation-switch" and
> "usb-role-switch" properties? If so, then yes, they aren't Cros EC
> specific. The Type C connector class framework requires the nodes to be
> named like this, and the cros-ec-typec driver uses this framework, hence
> the description here (the Type C connector class framework doesn't have
> any bindings).
>
> Would it be better to add in the description string that Type Connector
> class expects these switches to be named this way? :
>
> " Reference to a DT node for the USB Type C Multiplexer controlling the
> data lines routing for this connector. This switch is assumed registered
> with the Type C connector class framework, which requires it to be named
> this way."
> >
> > > + mode-switch:
> > > + description: Reference to a DT node for the USB Type C Multiplexer
> > > + controlling the data lines routing for this connector.
> >
> > This is for alternate mode muxing I presume.
>
> Yes, that's right.
> >
> > We already have a mux-control binding. Why not use that here?
>
> Heikki might be able to offer more insight into why this is the case,
> since the connector class framework seems to expect a phandle and for
> the device driver to implement a "set" command. Heikki, would you happen to know?
The mode-switch here would actually represent the "consumer" part in
the mux-control bindings. So the mux-controls would describe the
relationship between the "mode-switch" and the mux controller(s),
while the mode-switch property describes the relationship between
something like USB Type-C Port Manager (or this cros_ec function) and
the "mux consumer".
> > > +
> > > + orientation-switch:
> > > + description: Reference to a DT node for the USB Type C orientation
> > > + switch for this connector.
> >
> > What's in this node?
>
> Similar to the other "-switch", this will contain a phandle to a device
> which can control orientation settings for the Type C Mux. The connector
> class API assumes the switches are named this way. For example:
>
> orientation-switch:
> https://elixir.bootlin.com/linux/v5.7-rc2/source/drivers/usb/typec/mux.c#L64
>
> mode-switch:
> https://elixir.bootlin.com/linux/v5.7-rc2/source/drivers/usb/typec/mux.c#L258
>
> >
> > > +
> > > + usb-role-switch:
> > > + description: Reference to a DT node for the USB Data role switch
> > > + for this connector.
> > >
> > > required:
> > > - compatible
> > > @@ -49,6 +63,17 @@ examples:
> > > data-role = "dual";
> > > try-power-role = "source";
> > > };
> > > +
> > > + connector@1 {
> > > + compatible = "usb-c-connector";
> > > + reg = <1>;
> > > + power-role = "dual";
> > > + data-role = "host";
> > > + try-power-role = "source";
> > > + mode-switch = <&typec_mux>;
> > > + orientation-switch = <&typec_orientation_switch>;
> > > + usb-role-switch = <&typec_mux>;
> > > + };
> > > };
> > > };
> > > };
> > > --
> > > 2.26.1.301.g55bc3eb7cb9-goog
> > >
thanks,
--
heikki
^ permalink raw reply
* Re: [PATCH v2 3/5] pinctrl: lochnagar: Move binding over to dtschema
From: Rob Herring @ 2020-05-12 13:33 UTC (permalink / raw)
To: Linus Walleij
Cc: Charles Keepax, Lee Jones, Mark Brown, Michael Turquette,
Stephen Boyd, Jean Delvare, Guenter Roeck, Liam Girdwood,
linux-kernel@vger.kernel.org,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
patches
In-Reply-To: <CACRpkdYSzdUgZgA6jtdP3K9bWTF=-whkQCr=bKkr_Z0VXywdkA@mail.gmail.com>
On Tue, May 12, 2020 at 03:06:59PM +0200, Linus Walleij wrote:
> On Mon, May 4, 2020 at 5:48 PM Charles Keepax
> <ckeepax@opensource.cirrus.com> wrote:
>
> > Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
> > ---
> >
> > Changes since v1:
> > - Moved sub-node into MFD file leaving just the properties in here
> > - Removed contains on the compatible
> > - Added a required -pins suffix for pinmux/ctrl nodes
> > - Added some extra blank lines for readability
>
> Backed out v1 since I see there is some discussion on these still (sorry for
> missing this).
>
> I'll hold this off until there is consensus.
The whole series needs to go in together.
Rob
^ permalink raw reply
* [PATCH v2 1/6] dt-bindings: mfd: add Khadas Microcontroller bindings
From: Neil Armstrong @ 2020-05-12 13:26 UTC (permalink / raw)
To: lee.jones, rui.zhang, daniel.lezcano, amit.kucheria,
srinivas.kandagatla, devicetree
Cc: Neil Armstrong, linux-amlogic, linux-pm, linux-arm-kernel,
linux-kernel, Rob Herring
In-Reply-To: <20200512132613.31507-1-narmstrong@baylibre.com>
This Microcontroller is present on the Khadas VIM1, VIM2, VIM3 and Edge
boards.
It has multiple boot control features like password check, power-on
options, power-off control and system FAN control on recent boards.
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---
.../devicetree/bindings/mfd/khadas,mcu.yaml | 44 +++++++++++++++++++
1 file changed, 44 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mfd/khadas,mcu.yaml
diff --git a/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml b/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml
new file mode 100644
index 000000000000..a3b976f101e8
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/khadas,mcu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Khadas on-board Microcontroller Device Tree Bindings
+
+maintainers:
+ - Neil Armstrong <narmstrong@baylibre.com>
+
+description: |
+ Khadas embeds a microcontroller on their VIM and Edge boards adding some
+ system feature as PWM Fan control (for VIM2 rev14 or VIM3), User memory
+ storage, IR/Key resume control, system power LED control and more.
+
+properties:
+ compatible:
+ enum:
+ - khadas,mcu # MCU revision is discoverable
+
+ "#cooling-cells": # Only needed for boards having FAN control feature
+ const: 2
+
+ reg:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ khadas_mcu: system-controller@18 {
+ compatible = "khadas,mcu";
+ reg = <0x18>;
+ #cooling-cells = <2>;
+ };
+ };
--
2.22.0
^ permalink raw reply related
* Re: [PATCH v3 0/6] allow ramoops to collect all kmesg_dump events
From: Petr Mladek @ 2020-05-12 13:16 UTC (permalink / raw)
To: Kees Cook
Cc: Pavel Tatashin, Anton Vorontsov, Colin Cross, Tony Luck,
Jonathan Corbet, Rob Herring, Benson Leung,
Enric Balletbo i Serra, Sergey Senozhatsky, Steven Rostedt,
jmorris, sashal, linux-doc, linux-kernel, devicetree
In-Reply-To: <20200506211523.15077-1-keescook@chromium.org>
On Wed 2020-05-06 14:15:17, Kees Cook wrote:
> Hi!
>
> This is my stab at rearranging a few things based on Pavel's series. Most
> things remain the same; I just tweaked how defaults are arranged and
> detected and expanded the wording in a few places. Pavel, how does this
> v3 look to you?
>
> Pavel's original cover letter:
>
> pstore /mnt/console-ramoops-0 outputs only messages below the console
> loglevel, and our console loglevel is set to 3 due to slowness of
> serial console. Which means only errors and worse types of messages
> are recorded. There is no way to have different log levels for
> different consoles.
>
> This patch series adds a new option to ramoops: max_reason that enables
> it to collect kmdesg dumps for other reasons beside oops and panics.
I was a bit confused by the above explanation. It talks about two
different numbering schemes:
+ console loglevels: emerg, alert, crit, err, warning, ...
+ dump reason: panic, oops, emerg, restart, halt, poweroff
This difference and also the jump from consoles to ramoops is far from
obvious.
My understanding is the following:
It is not possible to set loglevel per console. The global value must
be set by the slowest one. This prevents seeing all messages even
on fast consoles.
Alternative solution is to dump all messages using ramoops. The
problem is that it currently works only during Oops and panic
situation. This is solved by this patchset.
OK, I personally see this as two separate problems:
1. Missing support to set loglevel per console.
2. Missing support to dump messages for other reasons.
I would remove the paragraph about console log levels completely.
It is your reason to use ramoops. But it is not reason to modify
the logic about max_reason.
Now, the max_reason logic makes sense only when all the values
have some ordering. Is this the case?
I see it as two distinct sets:
+ panic, oops, emerg: describe how critical is an error situation
+ restart, halt, poweroff: describe behavior when the system goes down
Let's say that panic is more critical than oops. Is restart more
critical than halt?
If you want the dump during restart. Does it mean that you want it
also during emergency situation?
My fear is that this patchset is going to introduce user interface
(max_reason) with a weird logic. IMHO, max_reason is confusing even
in the code and we should not spread this to users.
Is there any reason why the existing printk.always_kmsg_dump option
is not enough for you?
Best Regards,
Petr
^ permalink raw reply
* [PATCH v2 0/3] ASoC: ti: Add support for audio on J721e EVM
From: Peter Ujfalusi @ 2020-05-12 13:16 UTC (permalink / raw)
To: broonie, lgirdwood, robh+dt; +Cc: alsa-devel, devicetree, linux-kernel
Hi,
Changes since v1:
- Fixed DT binding documentation errors
- Rebased on ASoC head and updated the driver to compile and work
This series adds support for the analog audio setup on the j721e EVM.
The audio setup of the EVM is:
Common Processor Board (CPB): McASP10 <-> pcm3168a
Infotainment Expansion Board (IVI): McASP0 <-> 2x pcm3168a
Both CPB and IVI wired in parallel serializer setup.
The first patch adds the stream_name for McASP driver as it is needed in
multicodec (and would be needed in DPCM) setup for proper DAPM handling.
The second patch adds two DT schema, one for the cpb and one for the cpb+ivi
card.
Regards,
Peter
---
Peter Ujfalusi (3):
ASoC: ti: davinci-mcasp: Specify stream_name for playback/capture
bindings: sound: Add documentation for TI j721e EVM (CPB and IVI)
ASoC: ti: Add custom machine driver for j721e EVM (CPB and IVI)
.../bindings/sound/ti,j721e-cpb-audio.yaml | 93 ++
.../sound/ti,j721e-cpb-ivi-audio.yaml | 142 +++
sound/soc/ti/Kconfig | 8 +
sound/soc/ti/Makefile | 2 +
sound/soc/ti/davinci-mcasp.c | 3 +
sound/soc/ti/j721e-evm.c | 867 ++++++++++++++++++
6 files changed, 1115 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/ti,j721e-cpb-audio.yaml
create mode 100644 Documentation/devicetree/bindings/sound/ti,j721e-cpb-ivi-audio.yaml
create mode 100644 sound/soc/ti/j721e-evm.c
--
Peter
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
^ permalink raw reply
* [PATCH v2 2/3] bindings: sound: Add documentation for TI j721e EVM (CPB and IVI)
From: Peter Ujfalusi @ 2020-05-12 13:16 UTC (permalink / raw)
To: broonie, lgirdwood, robh+dt; +Cc: alsa-devel, devicetree, linux-kernel
In-Reply-To: <20200512131633.32668-1-peter.ujfalusi@ti.com>
The audio support on the Common Processor Board board is using
pcm3168a codec connected to McASP10 serializers in parallel setup.
The Infotainment board plugs into the Common Processor Board, the support
of the extension board is extending the CPB audio support by adding
the two codecs on the expansion board.
The audio support on the Infotainment Expansion Board consists of McASP0
connected to two pcm3168a codecs with dedicated set of serializers to each.
The SCKI for pcm3168a is sourced from j721e AUDIO_REFCLK0 pin.
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
---
.../bindings/sound/ti,j721e-cpb-audio.yaml | 93 ++++++++++++
.../sound/ti,j721e-cpb-ivi-audio.yaml | 142 ++++++++++++++++++
2 files changed, 235 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/ti,j721e-cpb-audio.yaml
create mode 100644 Documentation/devicetree/bindings/sound/ti,j721e-cpb-ivi-audio.yaml
diff --git a/Documentation/devicetree/bindings/sound/ti,j721e-cpb-audio.yaml b/Documentation/devicetree/bindings/sound/ti,j721e-cpb-audio.yaml
new file mode 100644
index 000000000000..0355ffc2b01b
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/ti,j721e-cpb-audio.yaml
@@ -0,0 +1,93 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/ti,j721e-cpb-audio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Texas Instruments J721e Common Processor Board Audio Support
+
+maintainers:
+ - Peter Ujfalusi <peter.ujfalusi@ti.com>
+
+description: |
+ The audio support on the board is using pcm3168a codec connected to McASP10
+ serializers in parallel setup.
+ The pcm3168a SCKI clock is sourced from j721e AUDIO_REFCLK2 pin.
+ In order to support 48KHz and 44.1KHz family of sampling rates the parent
+ clock for AUDIO_REFCLK2 needs to be changed between PLL4 (for 48KHz) and
+ PLL15 (for 44.1KHz). The same PLLs are used for McASP10's AUXCLK clock via
+ different HSDIVIDER.
+
+properties:
+ compatible:
+ items:
+ - const: ti,j721e-cpb-audio
+
+ model:
+ $ref: /schemas/types.yaml#/definitions/string
+ description: User specified audio sound card name
+
+ ti,cpb-mcasp:
+ description: phandle to McASP10
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/phandle
+
+ ti,cpb-codec:
+ description: phandle to the pcm3168a codec used on the CPB
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/phandle
+
+ clocks:
+ items:
+ - description: PLL4 clock
+ - description: PLL15 clock
+ - description: McASP10 auxclk clock
+ - description: PLL4_HSDIV0 parent for McASP10 auxclk (for 48KHz)
+ - description: PLL15_HSDIV0 parent for McASP10 auxclk (for 44.1KHz)
+ - description: AUDIO_REFCLK2 clock
+ - description: PLL4_HSDIV2 parent for AUDIO_REFCLK2 clock (for 48KHz)
+ - description: PLL15_HSDIV2 parent for AUDIO_REFCLK2 clock (for 44.1KHz)
+
+ clock-names:
+ items:
+ - const: pll4
+ - const: pll15
+ - const: cpb-mcasp
+ - const: cpb-mcasp-48000
+ - const: cpb-mcasp-44100
+ - const: audio-refclk2
+ - const: audio-refclk2-48000
+ - const: audio-refclk2-44100
+
+required:
+ - compatible
+ - model
+ - ti,cpb-mcasp
+ - ti,cpb-codec
+ - clocks
+ - clock-names
+
+additionalProperties: false
+
+examples:
+ - |+
+ sound {
+ compatible = "ti,j721e-cpb-audio";
+ model = "j721e-cpb";
+
+ status = "okay";
+
+ ti,cpb-mcasp = <&mcasp10>;
+ ti,cpb-codec = <&pcm3168a_1>;
+
+ clocks = <&pll4>, <&pll15>,
+ <&k3_clks 184 1>,
+ <&k3_clks 184 2>, <&k3_clks 184 4>,
+ <&k3_clks 157 371>,
+ <&k3_clks 157 400>, <&k3_clks 157 401>;
+ clock-names = "pll4", "pll15",
+ "cpb-mcasp",
+ "cpb-mcasp-48000", "cpb-mcasp-44100",
+ "audio-refclk2",
+ "audio-refclk2-48000", "audio-refclk2-44100";
+ };
diff --git a/Documentation/devicetree/bindings/sound/ti,j721e-cpb-ivi-audio.yaml b/Documentation/devicetree/bindings/sound/ti,j721e-cpb-ivi-audio.yaml
new file mode 100644
index 000000000000..3951c1320fae
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/ti,j721e-cpb-ivi-audio.yaml
@@ -0,0 +1,142 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/ti,j721e-cpb-ivi-audio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Texas Instruments J721e Common Processor Board Audio Support
+
+maintainers:
+ - Peter Ujfalusi <peter.ujfalusi@ti.com>
+
+description: |
+ The Infotainment board plugs into the Common Processor Board, the support of the
+ extension board is extending the CPB audio support, decribed in:
+ sound/ti,j721e-cpb-audio.txt
+
+ The audio support on the Infotainment Expansion Board consists of McASP0
+ connected to two pcm3168a codecs with dedicated set of serializers to each.
+ The SCKI for pcm3168a is sourced from j721e AUDIO_REFCLK0 pin.
+
+ In order to support 48KHz and 44.1KHz family of sampling rates the parent clock
+ for AUDIO_REFCLK0 needs to be changed between PLL4 (for 48KHz) and PLL15 (for
+ 44.1KHz). The same PLLs are used for McASP0's AUXCLK clock via different
+ HSDIVIDER.
+
+ Note: the same PLL4 and PLL15 is used by the audio support on the CPB!
+
+properties:
+ compatible:
+ items:
+ - const: ti,j721e-cpb-ivi-audio
+
+ model:
+ $ref: /schemas/types.yaml#/definitions/string
+ description: User specified audio sound card name
+
+ ti,cpb-mcasp:
+ description: phandle to McASP10
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/phandle
+
+ ti,cpb-codec:
+ description: phandle to the pcm3168a codec used on the CPB
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/phandle
+
+ ti,ivi-mcasp:
+ description: phandle to McASP9
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/phandle
+
+ ti,ivi-codec-a:
+ description: phandle to the pcm3168a-A codec on the expansion board
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/phandle
+
+ ti,ivi-codec-b:
+ description: phandle to the pcm3168a-B codec on the expansion board
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/phandle
+
+ clocks:
+ items:
+ - description: PLL4 clock
+ - description: PLL15 clock
+ - description: McASP10 auxclk clock
+ - description: PLL4_HSDIV0 parent for McASP10 auxclk (for 48KHz)
+ - description: PLL15_HSDIV0 parent for McASP10 auxclk (for 44.1KHz)
+ - description: AUDIO_REFCLK2 clock
+ - description: PLL4_HSDIV2 parent for AUDIO_REFCLK2 clock (for 48KHz)
+ - description: PLL15_HSDIV2 parent for AUDIO_REFCLK2 clock (for 44.1KHz)
+ - description: McASP0 auxclk clock
+ - description: PLL4_HSDIV0 parent for McASP0 auxclk (for 48KHz)
+ - description: PLL15_HSDIV0 parent for McASP0 auxclk (for 44.1KHz)
+ - description: AUDIO_REFCLK0 clock
+ - description: PLL4_HSDIV2 parent for AUDIO_REFCLK0 clock (for 48KHz)
+ - description: PLL15_HSDIV2 parent for AUDIO_REFCLK0 clock (for 44.1KHz)
+
+ clock-names:
+ items:
+ - const: pll4
+ - const: pll15
+ - const: cpb-mcasp
+ - const: cpb-mcasp-48000
+ - const: cpb-mcasp-44100
+ - const: audio-refclk2
+ - const: audio-refclk2-48000
+ - const: audio-refclk2-44100
+ - const: ivi-mcasp
+ - const: ivi-mcasp-48000
+ - const: ivi-mcasp-44100
+ - const: audio-refclk0
+ - const: audio-refclk0-48000
+ - const: audio-refclk0-44100
+
+required:
+ - compatible
+ - model
+ - ti,cpb-mcasp
+ - ti,cpb-codec
+ - ti,ivi-mcasp
+ - ti,ivi-codec-a
+ - ti,ivi-codec-b
+ - clocks
+ - clock-names
+
+additionalProperties: false
+
+examples:
+ - |+
+ sound {
+ compatible = "ti,j721e-cpb-ivi-audio";
+ model = "j721e-cpb-ivi";
+
+ status = "okay";
+
+ ti,cpb-mcasp = <&mcasp10>;
+ ti,cpb-codec = <&pcm3168a_1>;
+
+ ti,ivi-mcasp = <&mcasp0>;
+ ti,ivi-codec-a = <&pcm3168a_a>;
+ ti,ivi-codec-b = <&pcm3168a_b>;
+
+ clocks = <&pll4>, <&pll15>,
+ <&k3_clks 184 1>,
+ <&k3_clks 184 2>, <&k3_clks 184 4>,
+ <&k3_clks 157 371>,
+ <&k3_clks 157 400>, <&k3_clks 157 401>,
+ <&k3_clks 174 1>,
+ <&k3_clks 174 2>, <&k3_clks 174 4>,
+ <&k3_clks 157 301>,
+ <&k3_clks 157 330>, <&k3_clks 157 331>;
+ clock-names = "pll4", "pll15",
+ "cpb-mcasp",
+ "cpb-mcasp-48000", "cpb-mcasp-44100",
+ "audio-refclk2",
+ "audio-refclk2-48000", "audio-refclk2-44100",
+ "ivi-mcasp",
+ "ivi-mcasp-48000", "ivi-mcasp-44100",
+ "audio-refclk0",
+ "audio-refclk0-48000", "audio-refclk0-44100";
+ };
--
Peter
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
^ permalink raw reply related
* [PATCH v2 3/3] ASoC: ti: Add custom machine driver for j721e EVM (CPB and IVI)
From: Peter Ujfalusi @ 2020-05-12 13:16 UTC (permalink / raw)
To: broonie, lgirdwood, robh+dt; +Cc: alsa-devel, devicetree, linux-kernel
In-Reply-To: <20200512131633.32668-1-peter.ujfalusi@ti.com>
The audio support on the board is using pcm3168a codec connected to McASP10
serializers in parallel setup.
The pcm3168a SCKI clock is coming via the j721e AUDIO_REFCLK2 pin.
In order to support 48KHz and 44.1KHz family of sampling rates the parent clock
for AUDIO_REFCLK2 needs to be changed between PLL4 (for 48KHz) and PLL15 (for
44.1KHz). The same PLLs are used for McASP10's AUXCLK clock via different
HSDIVIDER.
Generic card can not be used for the board as we need to switch between
clock paths for different sampling rate families and also need to change
the slot_width between 16 and 24 bit audio.
The audio support on the Infotainment Expansion Board consists of McASP0
connected to two pcm3168a codecs with dedicated set of serializers to each.
The SCKI for pcm3168a is sourced from j721e AUDIO_REFCLK0 pin.
It is extending the audio support on the CPB.
Due to the fact that the same PLL4/15 is used by both domains (CPB/IVI)
there are cross restriction on sampling rates.
The IVI side is represented as multicodec setup.
PCMs available on a plain CPB (no IVI addon):
hw:0,0 - cpb playback (8 channels)
hw:0,1 - cpb capture (6 channels)
When the IVI addon is present, additional two PCMs will be present:
hw:0,2 - ivi multicodec playback (16 channels)
hw:0,3 - ivi multicodec capture (12 channels)
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
---
sound/soc/ti/Kconfig | 8 +
sound/soc/ti/Makefile | 2 +
sound/soc/ti/j721e-evm.c | 867 +++++++++++++++++++++++++++++++++++++++
3 files changed, 877 insertions(+)
create mode 100644 sound/soc/ti/j721e-evm.c
diff --git a/sound/soc/ti/Kconfig b/sound/soc/ti/Kconfig
index c5408c129f34..53df545efe0a 100644
--- a/sound/soc/ti/Kconfig
+++ b/sound/soc/ti/Kconfig
@@ -219,5 +219,13 @@ config SND_SOC_DM365_VOICE_CODEC_MODULE
The is an internal symbol needed to ensure that the codec
and MFD driver can be built as loadable modules if necessary.
+config SND_SOC_J721E_EVM
+ tristate "SoC Audio support for j721e EVM"
+ depends on ARCH_K3_J721E_SOC || COMPILE_TEST
+ select SND_SOC_PCM3168A_I2C
+ select SND_SOC_DAVINCI_MCASP
+ help
+ Say Y if you want to add support for SoC audio on j721e Common
+ Processor Board and Infotainment expansion board.
endmenu
diff --git a/sound/soc/ti/Makefile b/sound/soc/ti/Makefile
index ea48c6679cc7..a21e5b0061de 100644
--- a/sound/soc/ti/Makefile
+++ b/sound/soc/ti/Makefile
@@ -34,6 +34,7 @@ snd-soc-omap-abe-twl6040-objs := omap-abe-twl6040.o
snd-soc-ams-delta-objs := ams-delta.o
snd-soc-omap-hdmi-objs := omap-hdmi.o
snd-soc-osk5912-objs := osk5912.o
+snd-soc-j721e-evm-objs := j721e-evm.o
obj-$(CONFIG_SND_SOC_DAVINCI_EVM) += snd-soc-davinci-evm.o
obj-$(CONFIG_SND_SOC_NOKIA_N810) += snd-soc-n810.o
@@ -44,3 +45,4 @@ obj-$(CONFIG_SND_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o
obj-$(CONFIG_SND_SOC_OMAP_AMS_DELTA) += snd-soc-ams-delta.o
obj-$(CONFIG_SND_SOC_OMAP_HDMI) += snd-soc-omap-hdmi.o
obj-$(CONFIG_SND_SOC_OMAP_OSK5912) += snd-soc-osk5912.o
+obj-$(CONFIG_SND_SOC_J721E_EVM) += snd-soc-j721e-evm.o
diff --git a/sound/soc/ti/j721e-evm.c b/sound/soc/ti/j721e-evm.c
new file mode 100644
index 000000000000..c16c4a24d933
--- /dev/null
+++ b/sound/soc/ti/j721e-evm.c
@@ -0,0 +1,867 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "davinci-mcasp.h"
+
+/*
+ * Maximum number of configuration entries for prefixes:
+ * CPB: 2 (mcasp10 + codec)
+ * IVI: 3 (mcasp0 + 2x codec)
+ */
+#define J721E_CODEC_CONF_COUNT 5
+
+#define J721E_AUDIO_DOMAIN_CPB 0
+#define J721E_AUDIO_DOMAIN_IVI 1
+
+#define J721E_CLK_PARENT_48000 0
+#define J721E_CLK_PARENT_44100 1
+
+#define J721E_MAX_CLK_HSDIV 128
+#define PCM1368A_MAX_SYSCLK 36864000
+
+#define J721E_DAI_FMT (SND_SOC_DAIFMT_RIGHT_J | \
+ SND_SOC_DAIFMT_NB_NF | \
+ SND_SOC_DAIFMT_CBS_CFS)
+
+enum j721e_board_type {
+ J721E_BOARD_CPB = 1,
+ J721E_BOARD_CPB_IVI,
+};
+
+struct j721e_audio_match_data {
+ enum j721e_board_type board_type;
+ int num_links;
+};
+
+static unsigned int ratios_for_pcm3168a[] = {
+ 256,
+ 512,
+ 768,
+};
+
+struct j721e_audio_clocks {
+ struct clk *target;
+ struct clk *parent[2];
+};
+
+struct j721e_audio_domain {
+ struct j721e_audio_clocks codec;
+ struct j721e_audio_clocks mcasp;
+ int parent_clk_id;
+
+ int active;
+ unsigned int active_link;
+ unsigned int rate;
+};
+
+struct j721e_priv {
+ struct device *dev;
+ struct snd_soc_card card;
+ struct snd_soc_dai_link *dai_links;
+ struct snd_soc_codec_conf codec_conf[J721E_CODEC_CONF_COUNT];
+ struct snd_interval rate_range;
+ const struct j721e_audio_match_data *match_data;
+ u32 pll_rates[2];
+ unsigned int hsdiv_rates[2];
+
+ struct j721e_audio_domain audio_domains[2];
+
+ struct mutex mutex;
+};
+
+static const struct snd_soc_dapm_widget j721e_cpb_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("CPB Stereo HP 1", NULL),
+ SND_SOC_DAPM_HP("CPB Stereo HP 2", NULL),
+ SND_SOC_DAPM_HP("CPB Stereo HP 3", NULL),
+ SND_SOC_DAPM_LINE("CPB Line Out", NULL),
+ SND_SOC_DAPM_MIC("CPB Stereo Mic 1", NULL),
+ SND_SOC_DAPM_MIC("CPB Stereo Mic 2", NULL),
+ SND_SOC_DAPM_LINE("CPB Line In", NULL),
+};
+
+static const struct snd_soc_dapm_route j721e_cpb_dapm_routes[] = {
+ {"CPB Stereo HP 1", NULL, "codec-1 AOUT1L"},
+ {"CPB Stereo HP 1", NULL, "codec-1 AOUT1R"},
+ {"CPB Stereo HP 2", NULL, "codec-1 AOUT2L"},
+ {"CPB Stereo HP 2", NULL, "codec-1 AOUT2R"},
+ {"CPB Stereo HP 3", NULL, "codec-1 AOUT3L"},
+ {"CPB Stereo HP 3", NULL, "codec-1 AOUT3R"},
+ {"CPB Line Out", NULL, "codec-1 AOUT4L"},
+ {"CPB Line Out", NULL, "codec-1 AOUT4R"},
+
+ {"codec-1 AIN1L", NULL, "CPB Stereo Mic 1"},
+ {"codec-1 AIN1R", NULL, "CPB Stereo Mic 1"},
+ {"codec-1 AIN2L", NULL, "CPB Stereo Mic 2"},
+ {"codec-1 AIN2R", NULL, "CPB Stereo Mic 2"},
+ {"codec-1 AIN3L", NULL, "CPB Line In"},
+ {"codec-1 AIN3R", NULL, "CPB Line In"},
+};
+
+static const struct snd_soc_dapm_widget j721e_ivi_codec_a_dapm_widgets[] = {
+ SND_SOC_DAPM_LINE("IVI A Line Out 1", NULL),
+ SND_SOC_DAPM_LINE("IVI A Line Out 2", NULL),
+ SND_SOC_DAPM_LINE("IVI A Line Out 3", NULL),
+ SND_SOC_DAPM_LINE("IVI A Line Out 4", NULL),
+ SND_SOC_DAPM_MIC("IVI A Stereo Mic 1", NULL),
+ SND_SOC_DAPM_MIC("IVI A Stereo Mic 2", NULL),
+ SND_SOC_DAPM_LINE("IVI A Line In", NULL),
+};
+
+static const struct snd_soc_dapm_route j721e_codec_a_dapm_routes[] = {
+ {"IVI A Line Out 1", NULL, "codec-a AOUT1L"},
+ {"IVI A Line Out 1", NULL, "codec-a AOUT1R"},
+ {"IVI A Line Out 2", NULL, "codec-a AOUT2L"},
+ {"IVI A Line Out 2", NULL, "codec-a AOUT2R"},
+ {"IVI A Line Out 3", NULL, "codec-a AOUT3L"},
+ {"IVI A Line Out 3", NULL, "codec-a AOUT3R"},
+ {"IVI A Line Out 4", NULL, "codec-a AOUT4L"},
+ {"IVI A Line Out 4", NULL, "codec-a AOUT4R"},
+
+ {"codec-a AIN1L", NULL, "IVI A Stereo Mic 1"},
+ {"codec-a AIN1R", NULL, "IVI A Stereo Mic 1"},
+ {"codec-a AIN2L", NULL, "IVI A Stereo Mic 2"},
+ {"codec-a AIN2R", NULL, "IVI A Stereo Mic 2"},
+ {"codec-a AIN3L", NULL, "IVI A Line In"},
+ {"codec-a AIN3R", NULL, "IVI A Line In"},
+};
+
+static const struct snd_soc_dapm_widget j721e_ivi_codec_b_dapm_widgets[] = {
+ SND_SOC_DAPM_LINE("IVI B Line Out 1", NULL),
+ SND_SOC_DAPM_LINE("IVI B Line Out 2", NULL),
+ SND_SOC_DAPM_LINE("IVI B Line Out 3", NULL),
+ SND_SOC_DAPM_LINE("IVI B Line Out 4", NULL),
+ SND_SOC_DAPM_MIC("IVI B Stereo Mic 1", NULL),
+ SND_SOC_DAPM_MIC("IVI B Stereo Mic 2", NULL),
+ SND_SOC_DAPM_LINE("IVI B Line In", NULL),
+};
+
+static const struct snd_soc_dapm_route j721e_codec_b_dapm_routes[] = {
+ {"IVI B Line Out 1", NULL, "codec-b AOUT1L"},
+ {"IVI B Line Out 1", NULL, "codec-b AOUT1R"},
+ {"IVI B Line Out 2", NULL, "codec-b AOUT2L"},
+ {"IVI B Line Out 2", NULL, "codec-b AOUT2R"},
+ {"IVI B Line Out 3", NULL, "codec-b AOUT3L"},
+ {"IVI B Line Out 3", NULL, "codec-b AOUT3R"},
+ {"IVI B Line Out 4", NULL, "codec-b AOUT4L"},
+ {"IVI B Line Out 4", NULL, "codec-b AOUT4R"},
+
+ {"codec-b AIN1L", NULL, "IVI B Stereo Mic 1"},
+ {"codec-b AIN1R", NULL, "IVI B Stereo Mic 1"},
+ {"codec-b AIN2L", NULL, "IVI B Stereo Mic 2"},
+ {"codec-b AIN2R", NULL, "IVI B Stereo Mic 2"},
+ {"codec-b AIN3L", NULL, "IVI B Line In"},
+ {"codec-b AIN3R", NULL, "IVI B Line In"},
+};
+
+static int j721e_configure_refclk(struct j721e_priv *priv,
+ unsigned int audio_domain, unsigned int rate)
+{
+ struct j721e_audio_domain *domain = &priv->audio_domains[audio_domain];
+ unsigned int scki;
+ int ret = -EINVAL;
+ int i, clk_id;
+
+ if (!(rate % 8000))
+ clk_id = J721E_CLK_PARENT_48000;
+ else if (!(rate % 11025))
+ clk_id = J721E_CLK_PARENT_44100;
+ else
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(ratios_for_pcm3168a); i++) {
+ scki = ratios_for_pcm3168a[i] * rate;
+
+ if (priv->pll_rates[clk_id] / scki <= J721E_MAX_CLK_HSDIV) {
+ ret = 0;
+ break;
+ }
+ }
+
+ if (ret) {
+ dev_err(priv->dev, "No valid clock configuration for %u Hz\n",
+ rate);
+ return ret;
+ }
+
+ if (priv->hsdiv_rates[domain->parent_clk_id] != scki) {
+ dev_dbg(priv->dev,
+ "%s configuration for %u Hz: %s, %dxFS (SCKI: %u Hz)\n",
+ audio_domain == J721E_AUDIO_DOMAIN_CPB ? "CPB" : "IVI",
+ rate,
+ clk_id == J721E_CLK_PARENT_48000 ? "PLL4" : "PLL15",
+ ratios_for_pcm3168a[i], scki);
+
+ if (domain->parent_clk_id != clk_id) {
+ ret = clk_set_parent(domain->codec.target,
+ domain->codec.parent[clk_id]);
+ if (ret)
+ return ret;
+
+ ret = clk_set_parent(domain->mcasp.target,
+ domain->mcasp.parent[clk_id]);
+ if (ret)
+ return ret;
+
+ domain->parent_clk_id = clk_id;
+ }
+
+ ret = clk_set_rate(domain->codec.target, scki);
+ if (ret) {
+ dev_err(priv->dev, "codec set rate failed for %u Hz\n",
+ scki);
+ return ret;
+ }
+
+ ret = clk_set_rate(domain->mcasp.target, scki);
+ if (!ret) {
+ priv->hsdiv_rates[domain->parent_clk_id] = scki;
+ } else {
+ dev_err(priv->dev, "mcasp set rate failed for %u Hz\n",
+ scki);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static int j721e_rule_rate(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct snd_interval *t = rule->private;
+
+ return snd_interval_refine(hw_param_interval(params, rule->var), t);
+}
+
+static int j721e_audio_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct j721e_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+ unsigned int domain_id = rtd->dai_link->id;
+ struct j721e_audio_domain *domain = &priv->audio_domains[domain_id];
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai;
+ unsigned int active_rate;
+ int ret = 0;
+ int i;
+
+ mutex_lock(&priv->mutex);
+
+ domain->active++;
+
+ if (priv->audio_domains[J721E_AUDIO_DOMAIN_CPB].rate)
+ active_rate = priv->audio_domains[J721E_AUDIO_DOMAIN_CPB].rate;
+ else
+ active_rate = priv->audio_domains[J721E_AUDIO_DOMAIN_IVI].rate;
+
+ if (active_rate)
+ ret = snd_pcm_hw_constraint_single(substream->runtime,
+ SNDRV_PCM_HW_PARAM_RATE,
+ active_rate);
+ else
+ ret = snd_pcm_hw_rule_add(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ j721e_rule_rate, &priv->rate_range,
+ SNDRV_PCM_HW_PARAM_RATE, -1);
+
+ mutex_unlock(&priv->mutex);
+
+ if (ret)
+ return ret;
+
+ /* Reset TDM slots to 32 */
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 32);
+ if (ret && ret != -ENOTSUPP)
+ return ret;
+
+ for_each_rtd_codec_dais(rtd, i, codec_dai) {
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 0x3, 2, 32);
+ if (ret && ret != -ENOTSUPP)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int j721e_audio_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct j721e_priv *priv = snd_soc_card_get_drvdata(card);
+ unsigned int domain_id = rtd->dai_link->id;
+ struct j721e_audio_domain *domain = &priv->audio_domains[domain_id];
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai;
+ unsigned int sysclk_rate;
+ int slot_width = 32;
+ int ret;
+ int i;
+
+ mutex_lock(&priv->mutex);
+
+ if (domain->rate && domain->rate != params_rate(params)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (params_width(params) == 16)
+ slot_width = 16;
+
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, slot_width);
+ if (ret && ret != -ENOTSUPP)
+ goto out;
+
+ for_each_rtd_codec_dais(rtd, i, codec_dai) {
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 0x3, 2,
+ slot_width);
+ if (ret && ret != -ENOTSUPP)
+ return ret;
+ }
+
+ ret = j721e_configure_refclk(priv, domain_id, params_rate(params));
+ if (ret)
+ goto out;
+
+ sysclk_rate = priv->hsdiv_rates[domain->parent_clk_id];
+ for_each_rtd_codec_dais(rtd, i, codec_dai) {
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk_rate,
+ SND_SOC_CLOCK_IN);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(priv->dev,
+ "codec set_sysclk failed for %u Hz\n",
+ sysclk_rate);
+ goto out;
+ }
+ }
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, MCASP_CLK_HCLK_AUXCLK,
+ sysclk_rate, SND_SOC_CLOCK_IN);
+
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(priv->dev, "mcasp set_sysclk failed for %u Hz\n",
+ sysclk_rate);
+ } else {
+ domain->rate = params_rate(params);
+ ret = 0;
+ }
+
+out:
+ mutex_unlock(&priv->mutex);
+ return ret;
+}
+
+static void j721e_audio_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct j721e_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+ unsigned int domain_id = rtd->dai_link->id;
+ struct j721e_audio_domain *domain = &priv->audio_domains[domain_id];
+
+ mutex_lock(&priv->mutex);
+
+ domain->active--;
+ if (!domain->active) {
+ domain->rate = 0;
+ domain->active_link = 0;
+ }
+
+ mutex_unlock(&priv->mutex);
+}
+
+static const struct snd_soc_ops j721e_audio_ops = {
+ .startup = j721e_audio_startup,
+ .hw_params = j721e_audio_hw_params,
+ .shutdown = j721e_audio_shutdown,
+};
+
+static int j721e_audio_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct j721e_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+ unsigned int domain_id = rtd->dai_link->id;
+ struct j721e_audio_domain *domain = &priv->audio_domains[domain_id];
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai;
+ unsigned int sysclk_rate;
+ int i, ret;
+
+ /* Set up initial clock configuration */
+ ret = j721e_configure_refclk(priv, domain_id, 48000);
+ if (ret)
+ return ret;
+
+ sysclk_rate = priv->hsdiv_rates[domain->parent_clk_id];
+ for_each_rtd_codec_dais(rtd, i, codec_dai) {
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk_rate,
+ SND_SOC_CLOCK_IN);
+ if (ret && ret != -ENOTSUPP)
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, MCASP_CLK_HCLK_AUXCLK,
+ sysclk_rate, SND_SOC_CLOCK_IN);
+ if (ret && ret != -ENOTSUPP)
+ return ret;
+
+ /* Set initial tdm slots */
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 32);
+ if (ret && ret != -ENOTSUPP)
+ return ret;
+
+ for_each_rtd_codec_dais(rtd, i, codec_dai) {
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 0x3, 2, 32);
+ if (ret && ret != -ENOTSUPP)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int j721e_audio_init_ivi(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
+
+ snd_soc_dapm_new_controls(dapm, j721e_ivi_codec_a_dapm_widgets,
+ ARRAY_SIZE(j721e_ivi_codec_a_dapm_widgets));
+ snd_soc_dapm_add_routes(dapm, j721e_codec_a_dapm_routes,
+ ARRAY_SIZE(j721e_codec_a_dapm_routes));
+ snd_soc_dapm_new_controls(dapm, j721e_ivi_codec_b_dapm_widgets,
+ ARRAY_SIZE(j721e_ivi_codec_b_dapm_widgets));
+ snd_soc_dapm_add_routes(dapm, j721e_codec_b_dapm_routes,
+ ARRAY_SIZE(j721e_codec_b_dapm_routes));
+
+ return j721e_audio_init(rtd);
+}
+
+static int j721e_get_clocks(struct device *dev,
+ struct j721e_audio_clocks *clocks, char *prefix)
+{
+ struct clk *parent;
+ char *clk_name;
+ int ret;
+
+ clocks->target = devm_clk_get(dev, prefix);
+ if (IS_ERR(clocks->target)) {
+ ret = PTR_ERR(clocks->target);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to acquire %s': %d\n",
+ prefix, ret);
+ return ret;
+ }
+
+ clk_name = kasprintf(GFP_KERNEL, "%s-48000", prefix);
+ if (clk_name) {
+ parent = devm_clk_get(dev, clk_name);
+ kfree(clk_name);
+ if (IS_ERR(parent)) {
+ ret = PTR_ERR(parent);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to acquire %s': %d\n",
+ prefix, ret);
+ return ret;
+ }
+ clocks->parent[J721E_CLK_PARENT_48000] = parent;
+ } else {
+ return -ENOMEM;
+ }
+
+ clk_name = kasprintf(GFP_KERNEL, "%s-44100", prefix);
+ if (clk_name) {
+ parent = devm_clk_get(dev, clk_name);
+ kfree(clk_name);
+ if (IS_ERR(parent)) {
+ ret = PTR_ERR(parent);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to acquire %s': %d\n",
+ prefix, ret);
+ return ret;
+ }
+ clocks->parent[J721E_CLK_PARENT_44100] = parent;
+ } else {
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static const struct j721e_audio_match_data j721e_cpb_data = {
+ .board_type = J721E_BOARD_CPB,
+ .num_links = 2, /* CPB pcm3168a */
+};
+
+static const struct j721e_audio_match_data j721e_cpb_ivi_data = {
+ .board_type = J721E_BOARD_CPB_IVI,
+ .num_links = 4, /* CPB pcm3168a + 2x IVI pcm3168a */
+};
+
+static const struct of_device_id j721e_audio_of_match[] = {
+ {
+ .compatible = "ti,j721e-cpb-audio",
+ .data = &j721e_cpb_data,
+ }, {
+ .compatible = "ti,j721e-cpb-ivi-audio",
+ .data = &j721e_cpb_ivi_data,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, j721e_audio_of_match);
+
+static int j721e_calculate_rate_range(struct j721e_priv *priv)
+{
+ unsigned int min_rate, max_rate, pll_rate;
+ struct clk *pll;
+
+ pll = clk_get(priv->dev, "pll15");
+ if (IS_ERR(pll)) {
+ int ret = PTR_ERR(pll);
+
+ if (ret != -EPROBE_DEFER)
+ dev_err(priv->dev, "failed to acquire PLL15 clock\n");
+
+ return ret;
+ }
+ priv->pll_rates[J721E_CLK_PARENT_44100] = clk_get_rate(pll);
+ clk_put(pll);
+
+ pll_rate = priv->pll_rates[J721E_CLK_PARENT_44100];
+ min_rate = pll_rate / J721E_MAX_CLK_HSDIV;
+ min_rate /= ratios_for_pcm3168a[ARRAY_SIZE(ratios_for_pcm3168a) - 1];
+
+ pll = clk_get(priv->dev, "pll4");
+ if (IS_ERR(pll)) {
+ int ret = PTR_ERR(pll);
+
+ if (ret != -EPROBE_DEFER)
+ dev_err(priv->dev, "failed to acquire PLL4 clock\n");
+
+ return ret;
+ }
+ priv->pll_rates[J721E_CLK_PARENT_48000] = clk_get_rate(pll);
+ clk_put(pll);
+
+ pll_rate = priv->pll_rates[J721E_CLK_PARENT_48000];
+ if (pll_rate > PCM1368A_MAX_SYSCLK)
+ pll_rate = PCM1368A_MAX_SYSCLK;
+
+ max_rate = pll_rate / ratios_for_pcm3168a[0];
+
+ snd_interval_any(&priv->rate_range);
+ priv->rate_range.min = min_rate;
+ priv->rate_range.max = max_rate;
+
+ return 0;
+}
+
+static int j721e_soc_probe_cpb(struct j721e_priv *priv, int *link_idx,
+ int *conf_idx)
+{
+ struct device_node *node = priv->dev->of_node;
+ struct snd_soc_dai_link_component *compnent;
+ struct device_node *dai_node, *codec_node;
+ struct j721e_audio_domain *domain;
+ int comp_count, comp_idx;
+ int ret;
+
+ dai_node = of_parse_phandle(node, "ti,cpb-mcasp", 0);
+ if (!dai_node) {
+ dev_err(priv->dev, "CPB McASP node is not provided\n");
+ return -EINVAL;
+ }
+
+ codec_node = of_parse_phandle(node, "ti,cpb-codec", 0);
+ if (!codec_node) {
+ dev_err(priv->dev, "CPB codec node is not provided\n");
+ return -EINVAL;
+ }
+
+ domain = &priv->audio_domains[J721E_AUDIO_DOMAIN_CPB];
+ ret = j721e_get_clocks(priv->dev, &domain->codec, "audio-refclk2");
+ if (ret)
+ return ret;
+
+ ret = j721e_get_clocks(priv->dev, &domain->mcasp, "cpb-mcasp");
+ if (ret)
+ return ret;
+
+ /*
+ * Common Processor Board, two links
+ * Link 1: McASP10 -> pcm3168a_1 DAC
+ * Link 2: McASP10 <- pcm3168a_1 ADC
+ */
+ comp_count = 6;
+ compnent = devm_kzalloc(priv->dev, comp_count * sizeof(*compnent),
+ GFP_KERNEL);
+ if (!compnent)
+ return -ENOMEM;
+
+ comp_idx = 0;
+ priv->dai_links[*link_idx].cpus = &compnent[comp_idx++];
+ priv->dai_links[*link_idx].num_cpus = 1;
+ priv->dai_links[*link_idx].codecs = &compnent[comp_idx++];
+ priv->dai_links[*link_idx].num_codecs = 1;
+ priv->dai_links[*link_idx].platforms = &compnent[comp_idx++];
+ priv->dai_links[*link_idx].num_platforms = 1;
+
+ priv->dai_links[*link_idx].name = "CPB PCM3168A Playback";
+ priv->dai_links[*link_idx].stream_name = "CPB PCM3168A Analog";
+ priv->dai_links[*link_idx].cpus->of_node = dai_node;
+ priv->dai_links[*link_idx].platforms->of_node = dai_node;
+ priv->dai_links[*link_idx].codecs->of_node = codec_node;
+ priv->dai_links[*link_idx].codecs->dai_name = "pcm3168a-dac";
+ priv->dai_links[*link_idx].playback_only = 1;
+ priv->dai_links[*link_idx].id = J721E_AUDIO_DOMAIN_CPB;
+ priv->dai_links[*link_idx].dai_fmt = J721E_DAI_FMT;
+ priv->dai_links[*link_idx].init = j721e_audio_init;
+ priv->dai_links[*link_idx].ops = &j721e_audio_ops;
+ (*link_idx)++;
+
+ priv->dai_links[*link_idx].cpus = &compnent[comp_idx++];
+ priv->dai_links[*link_idx].num_cpus = 1;
+ priv->dai_links[*link_idx].codecs = &compnent[comp_idx++];
+ priv->dai_links[*link_idx].num_codecs = 1;
+ priv->dai_links[*link_idx].platforms = &compnent[comp_idx++];
+ priv->dai_links[*link_idx].num_platforms = 1;
+
+ priv->dai_links[*link_idx].name = "CPB PCM3168A Capture";
+ priv->dai_links[*link_idx].stream_name = "CPB PCM3168A Analog";
+ priv->dai_links[*link_idx].cpus->of_node = dai_node;
+ priv->dai_links[*link_idx].platforms->of_node = dai_node;
+ priv->dai_links[*link_idx].codecs->of_node = codec_node;
+ priv->dai_links[*link_idx].codecs->dai_name = "pcm3168a-adc";
+ priv->dai_links[*link_idx].capture_only = 1;
+ priv->dai_links[*link_idx].id = J721E_AUDIO_DOMAIN_CPB;
+ priv->dai_links[*link_idx].dai_fmt = J721E_DAI_FMT;
+ priv->dai_links[*link_idx].init = j721e_audio_init;
+ priv->dai_links[*link_idx].ops = &j721e_audio_ops;
+ (*link_idx)++;
+
+ priv->codec_conf[*conf_idx].dlc.of_node = codec_node;
+ priv->codec_conf[*conf_idx].name_prefix = "codec-1";
+ (*conf_idx)++;
+ priv->codec_conf[*conf_idx].dlc.of_node = dai_node;
+ priv->codec_conf[*conf_idx].name_prefix = "McASP10";
+ (*conf_idx)++;
+
+ return 0;
+}
+
+static int j721e_soc_probe_ivi(struct j721e_priv *priv, int *link_idx,
+ int *conf_idx)
+{
+ struct device_node *node = priv->dev->of_node;
+ struct snd_soc_dai_link_component *compnent;
+ struct device_node *dai_node, *codeca_node, *codecb_node;
+ struct j721e_audio_domain *domain;
+ int comp_count, comp_idx;
+ int ret;
+
+ if (priv->match_data->board_type != J721E_BOARD_CPB_IVI)
+ return 0;
+
+ dai_node = of_parse_phandle(node, "ti,ivi-mcasp", 0);
+ if (!dai_node) {
+ dev_err(priv->dev, "IVI McASP node is not provided\n");
+ return -EINVAL;
+ }
+
+ codeca_node = of_parse_phandle(node, "ti,ivi-codec-a", 0);
+ if (!codeca_node) {
+ dev_err(priv->dev, "IVI codec-a node is not provided\n");
+ return -EINVAL;
+ }
+
+ codecb_node = of_parse_phandle(node, "ti,ivi-codec-b", 0);
+ if (!codecb_node) {
+ dev_warn(priv->dev, "IVI codec-b node is not provided\n");
+ return 0;
+ }
+
+ domain = &priv->audio_domains[J721E_AUDIO_DOMAIN_IVI];
+ ret = j721e_get_clocks(priv->dev, &domain->codec,
+ "audio-refclk0");
+ if (ret)
+ return ret;
+
+ ret = j721e_get_clocks(priv->dev, &domain->mcasp, "ivi-mcasp");
+ if (ret)
+ return ret;
+
+ /*
+ * IVI extension, two links
+ * Link 1: McASP0 -> pcm3168a_a DAC
+ * \> pcm3168a_b DAC
+ * Link 2: McASP0 <- pcm3168a_a ADC
+ * \ pcm3168a_b ADC
+ */
+ comp_count = 8;
+ compnent = devm_kzalloc(priv->dev, comp_count * sizeof(*compnent),
+ GFP_KERNEL);
+ if (!compnent)
+ return -ENOMEM;
+
+ comp_idx = 0;
+ priv->dai_links[*link_idx].cpus = &compnent[comp_idx++];
+ priv->dai_links[*link_idx].num_cpus = 1;
+ priv->dai_links[*link_idx].platforms = &compnent[comp_idx++];
+ priv->dai_links[*link_idx].num_platforms = 1;
+ priv->dai_links[*link_idx].codecs = &compnent[comp_idx];
+ priv->dai_links[*link_idx].num_codecs = 2;
+ comp_idx += 2;
+
+ priv->dai_links[*link_idx].name = "IVI 2xPCM3168A Playback";
+ priv->dai_links[*link_idx].stream_name = "IVI 2xPCM3168A Analog";
+ priv->dai_links[*link_idx].cpus->of_node = dai_node;
+ priv->dai_links[*link_idx].platforms->of_node = dai_node;
+ priv->dai_links[*link_idx].codecs[0].of_node = codeca_node;
+ priv->dai_links[*link_idx].codecs[0].dai_name = "pcm3168a-dac";
+ priv->dai_links[*link_idx].codecs[1].of_node = codecb_node;
+ priv->dai_links[*link_idx].codecs[1].dai_name = "pcm3168a-dac";
+ priv->dai_links[*link_idx].playback_only = 1;
+ priv->dai_links[*link_idx].id = J721E_AUDIO_DOMAIN_IVI;
+ priv->dai_links[*link_idx].dai_fmt = J721E_DAI_FMT;
+ priv->dai_links[*link_idx].init = j721e_audio_init_ivi;
+ priv->dai_links[*link_idx].ops = &j721e_audio_ops;
+ (*link_idx)++;
+
+ priv->dai_links[*link_idx].cpus = &compnent[comp_idx++];
+ priv->dai_links[*link_idx].num_cpus = 1;
+ priv->dai_links[*link_idx].platforms = &compnent[comp_idx++];
+ priv->dai_links[*link_idx].num_platforms = 1;
+ priv->dai_links[*link_idx].codecs = &compnent[comp_idx];
+ priv->dai_links[*link_idx].num_codecs = 2;
+
+ priv->dai_links[*link_idx].name = "IVI 2xPCM3168A Capture";
+ priv->dai_links[*link_idx].stream_name = "IVI 2xPCM3168A Analog";
+ priv->dai_links[*link_idx].cpus->of_node = dai_node;
+ priv->dai_links[*link_idx].platforms->of_node = dai_node;
+ priv->dai_links[*link_idx].codecs[0].of_node = codeca_node;
+ priv->dai_links[*link_idx].codecs[0].dai_name = "pcm3168a-adc";
+ priv->dai_links[*link_idx].codecs[1].of_node = codecb_node;
+ priv->dai_links[*link_idx].codecs[1].dai_name = "pcm3168a-adc";
+ priv->dai_links[*link_idx].capture_only = 1;
+ priv->dai_links[*link_idx].id = J721E_AUDIO_DOMAIN_IVI;
+ priv->dai_links[*link_idx].dai_fmt = J721E_DAI_FMT;
+ priv->dai_links[*link_idx].init = j721e_audio_init;
+ priv->dai_links[*link_idx].ops = &j721e_audio_ops;
+ (*link_idx)++;
+
+ priv->codec_conf[*conf_idx].dlc.of_node = codeca_node;
+ priv->codec_conf[*conf_idx].name_prefix = "codec-a";
+ (*conf_idx)++;
+
+ priv->codec_conf[*conf_idx].dlc.of_node = codecb_node;
+ priv->codec_conf[*conf_idx].name_prefix = "codec-b";
+ (*conf_idx)++;
+
+ priv->codec_conf[*conf_idx].dlc.of_node = dai_node;
+ priv->codec_conf[*conf_idx].name_prefix = "McASP0";
+ (*conf_idx)++;
+
+ return 0;
+}
+
+static int j721e_soc_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct snd_soc_card *card;
+ const struct of_device_id *match;
+ struct j721e_priv *priv;
+ int link_cnt, conf_cnt, ret;
+
+ if (!node) {
+ dev_err(&pdev->dev, "of node is missing.\n");
+ return -ENODEV;
+ }
+
+ match = of_match_node(j721e_audio_of_match, node);
+ if (!match) {
+ dev_err(&pdev->dev, "No compatible match found\n");
+ return -ENODEV;
+ }
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->match_data = match->data;
+
+ priv->dai_links = devm_kcalloc(&pdev->dev, priv->match_data->num_links,
+ sizeof(*priv->dai_links), GFP_KERNEL);
+ if (!priv->dai_links)
+ return -ENOMEM;
+
+ priv->audio_domains[J721E_AUDIO_DOMAIN_CPB].parent_clk_id = -1;
+ priv->audio_domains[J721E_AUDIO_DOMAIN_IVI].parent_clk_id = -1;
+ priv->dev = &pdev->dev;
+ card = &priv->card;
+ card->dev = &pdev->dev;
+ card->owner = THIS_MODULE;
+ card->dapm_widgets = j721e_cpb_dapm_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(j721e_cpb_dapm_widgets);
+ card->dapm_routes = j721e_cpb_dapm_routes;
+ card->num_dapm_routes = ARRAY_SIZE(j721e_cpb_dapm_routes);
+ card->fully_routed = 1;
+
+ if (snd_soc_of_parse_card_name(card, "model")) {
+ dev_err(&pdev->dev, "Card name is not provided\n");
+ return -ENODEV;
+ }
+
+ link_cnt = 0;
+ conf_cnt = 0;
+ ret = j721e_soc_probe_cpb(priv, &link_cnt, &conf_cnt);
+ if (ret)
+ return ret;
+
+ ret = j721e_soc_probe_ivi(priv, &link_cnt, &conf_cnt);
+ if (ret)
+ return ret;
+
+ card->dai_link = priv->dai_links;
+ card->num_links = link_cnt;
+
+ card->codec_conf = priv->codec_conf;
+ card->num_configs = conf_cnt;
+
+ ret = j721e_calculate_rate_range(priv);
+ if (ret)
+ return ret;
+
+ snd_soc_card_set_drvdata(card, priv);
+
+ mutex_init(&priv->mutex);
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+ if (ret)
+ dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n",
+ ret);
+
+ return ret;
+}
+
+static struct platform_driver j721e_soc_driver = {
+ .driver = {
+ .name = "j721e-audio",
+ .pm = &snd_soc_pm_ops,
+ .of_match_table = of_match_ptr(j721e_audio_of_match),
+ },
+ .probe = j721e_soc_probe,
+};
+
+module_platform_driver(j721e_soc_driver);
+
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
+MODULE_DESCRIPTION("ASoC machine driver for j721e Common Processor Board");
+MODULE_LICENSE("GPL v2");
--
Peter
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox