* [PATCH v4 0/4] st33zp24 new architecture proposal and st33zp24 spi driver @ 2015-01-25 21:11 Christophe Ricard [not found] ` <1422220293-21005-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org> 0 siblings, 1 reply; 11+ messages in thread From: Christophe Ricard @ 2015-01-25 21:11 UTC (permalink / raw) To: PeterHuewe-Mmb7MZpHnFY Cc: ashley-fm2HMyfA2y6tG0bUXCXiUA, tpmdd-yWjUBOtONefk1uMJSBkQmQ, tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, christophe-h.ricard-qxv4g6HH51o, jean-luc.blanc-qxv4g6HH51o, benoit.houyere-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA, jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/, jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA Hi, The following patchset: - propose a new architecture allowing to share a core st33zp24 data management layer with different phy (i2c & spi). For st33zp24 both phy have a proprietary transport protocol. Both are relying on the TCG TIS protocol. At the end, it simplifies the maintenance. - Add an spi phy allowing to support st33zp24 using with an SPI bus. The complete solution got tested in polling and interrupt mode successfully with i2c & spi phy. This patchset applies on top of Peter's tree https://github.com/PeterHuewe/linux-tpmdd.git for-james branch on top of: d4989d9f693b9502f9288da5db279c2f8c2e50be tpm/tpm_tis: Add missing ifdef CONFIG_ACPI for pnp_acpi_device I confirm also Jarkko Sakkinen's changes are working with this product with both phy's. - v2 takes into account feedbacks from Jason Gunthorpe. - v3 is reduced to 4 patches as 6 out of 10 got accepted for 3.20. Also compare to v2: * Fix build issue with patch v2 04/10 "Replace access to io_lpcpd from struct st33zp24_platform_data to tpm_stm_dev" * Fix link issue with patch v2 08/10 "Split tpm_i2c_tpm_st33 in 2 layers (core + phy)" when building as a module. The symbols wasn't exported in st33zp24.c. * Add missing MODULE_LICENSE in patch v2 09/10 "Add st33zp24 spi phy" * Fix node example in dts spi documentation in patch v2 10/10 "Add dts documentation for st33zp24 spi phy" * Fix typo on Jason Gunthorpe first name. Sorry for that :(... * Change contact email address as tpmsupport-qxv4g6HH51o@public.gmane.org is no more valid - v4 adds missing module_license in st33zp24 Best Regards Christophe Christophe Ricard (4): tpm/tpm_i2c_stm_st33: Replace access to io_lpcpd from struct st33zp24_platform_data to tpm_stm_dev tpm/tpm_i2c_stm_st33: Split tpm_i2c_tpm_st33 in 2 layers (core + phy) tpm/st33zp24/spi: Add st33zp24 spi phy tpm/st33zp24/dts/st33zp24-spi: Add dts documentation for st33zp24 spi phy .../bindings/security/tpm/st33zp24-spi.txt | 34 + drivers/char/tpm/Kconfig | 11 +- drivers/char/tpm/Makefile | 2 +- drivers/char/tpm/st33zp24/Kconfig | 30 + drivers/char/tpm/st33zp24/Makefile | 12 + drivers/char/tpm/st33zp24/i2c.c | 278 +++++++ drivers/char/tpm/st33zp24/spi.c | 386 +++++++++ drivers/char/tpm/st33zp24/st33zp24.c | 691 ++++++++++++++++ drivers/char/tpm/st33zp24/st33zp24.h | 34 + drivers/char/tpm/tpm_i2c_stm_st33.c | 911 --------------------- include/linux/platform_data/st33zp24.h | 28 + include/linux/platform_data/tpm_stm_st33.h | 39 - 12 files changed, 1495 insertions(+), 961 deletions(-) create mode 100644 Documentation/devicetree/bindings/security/tpm/st33zp24-spi.txt create mode 100644 drivers/char/tpm/st33zp24/Kconfig create mode 100644 drivers/char/tpm/st33zp24/Makefile create mode 100644 drivers/char/tpm/st33zp24/i2c.c create mode 100644 drivers/char/tpm/st33zp24/spi.c create mode 100644 drivers/char/tpm/st33zp24/st33zp24.c create mode 100644 drivers/char/tpm/st33zp24/st33zp24.h delete mode 100644 drivers/char/tpm/tpm_i2c_stm_st33.c create mode 100644 include/linux/platform_data/st33zp24.h delete mode 100644 include/linux/platform_data/tpm_stm_st33.h -- 2.1.0 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 11+ messages in thread
[parent not found: <1422220293-21005-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>]
* [PATCH v4 1/4] tpm/tpm_i2c_stm_st33: Replace access to io_lpcpd from struct st33zp24_platform_data to tpm_stm_dev [not found] ` <1422220293-21005-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org> @ 2015-01-25 21:11 ` Christophe Ricard [not found] ` <1422220293-21005-2-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org> 2015-01-25 21:11 ` [PATCH v4 2/4] tpm/tpm_i2c_stm_st33: Split tpm_i2c_tpm_st33 in 2 layers (core + phy) Christophe Ricard ` (3 subsequent siblings) 4 siblings, 1 reply; 11+ messages in thread From: Christophe Ricard @ 2015-01-25 21:11 UTC (permalink / raw) To: PeterHuewe-Mmb7MZpHnFY Cc: ashley-fm2HMyfA2y6tG0bUXCXiUA, tpmdd-yWjUBOtONefk1uMJSBkQmQ, tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, christophe-h.ricard-qxv4g6HH51o, jean-luc.blanc-qxv4g6HH51o, benoit.houyere-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA, jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/, jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA io_lpcpd is accessible from struct tpm_stm_dev. struct st33zp24_platform_data is only valid when using static platform configuration data, not when using dts. Reviewed-by: Jason Gunthorpe <jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org> Signed-off-by: Christophe Ricard <christophe-h.ricard-qxv4g6HH51o@public.gmane.org> --- drivers/char/tpm/tpm_i2c_stm_st33.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index 612845b..882c60a 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -837,11 +837,14 @@ static int tpm_stm_i2c_remove(struct i2c_client *client) */ static int tpm_stm_i2c_pm_suspend(struct device *dev) { - struct st33zp24_platform_data *pin_infos = dev->platform_data; + struct tpm_chip *chip = dev_get_drvdata(dev); + struct tpm_stm_dev *tpm_dev; int ret = 0; - if (gpio_is_valid(pin_infos->io_lpcpd)) - gpio_set_value(pin_infos->io_lpcpd, 0); + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); + + if (gpio_is_valid(tpm_dev->io_lpcpd)) + gpio_set_value(tpm_dev->io_lpcpd, 0); else ret = tpm_pm_suspend(dev); @@ -856,12 +859,13 @@ static int tpm_stm_i2c_pm_suspend(struct device *dev) static int tpm_stm_i2c_pm_resume(struct device *dev) { struct tpm_chip *chip = dev_get_drvdata(dev); - struct st33zp24_platform_data *pin_infos = dev->platform_data; - + struct tpm_stm_dev *tpm_dev; int ret = 0; - if (gpio_is_valid(pin_infos->io_lpcpd)) { - gpio_set_value(pin_infos->io_lpcpd, 1); + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); + + if (gpio_is_valid(tpm_dev->io_lpcpd)) { + gpio_set_value(tpm_dev->io_lpcpd, 1); ret = wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_b, &chip->vendor.read_queue, false); -- 2.1.0 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 11+ messages in thread
[parent not found: <1422220293-21005-2-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>]
* Re: [PATCH v4 1/4] tpm/tpm_i2c_stm_st33: Replace access to io_lpcpd from struct st33zp24_platform_data to tpm_stm_dev [not found] ` <1422220293-21005-2-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org> @ 2015-01-26 22:15 ` Peter Hüwe [not found] ` <201501262315.07543.PeterHuewe-Mmb7MZpHnFY@public.gmane.org> 0 siblings, 1 reply; 11+ messages in thread From: Peter Hüwe @ 2015-01-26 22:15 UTC (permalink / raw) To: Christophe Ricard Cc: ashley-fm2HMyfA2y6tG0bUXCXiUA, tpmdd-yWjUBOtONefk1uMJSBkQmQ, tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, christophe-h.ricard-qxv4g6HH51o, jean-luc.blanc-qxv4g6HH51o, benoit.houyere-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA, jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/, jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA Hi Christophe, Am Sonntag, 25. Januar 2015, 22:11:30 schrieb Christophe Ricard: > io_lpcpd is accessible from struct tpm_stm_dev. > struct st33zp24_platform_data is only valid when using static platform > configuration data, not when using dts. > > Reviewed-by: Jason Gunthorpe <jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org> > Signed-off-by: Christophe Ricard <christophe-h.ricard-qxv4g6HH51o@public.gmane.org> > --- > drivers/char/tpm/tpm_i2c_stm_st33.c | 18 +++++++++++------- > 1 file changed, 11 insertions(+), 7 deletions(-) > > diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c > b/drivers/char/tpm/tpm_i2c_stm_st33.c index 612845b..882c60a 100644 > --- a/drivers/char/tpm/tpm_i2c_stm_st33.c > +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c > @@ -837,11 +837,14 @@ static int tpm_stm_i2c_remove(struct i2c_client > *client) */ > static int tpm_stm_i2c_pm_suspend(struct device *dev) > { > - struct st33zp24_platform_data *pin_infos = dev->platform_data; > + struct tpm_chip *chip = dev_get_drvdata(dev); > + struct tpm_stm_dev *tpm_dev; > int ret = 0; > > - if (gpio_is_valid(pin_infos->io_lpcpd)) > - gpio_set_value(pin_infos->io_lpcpd, 0); > + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); > + > + if (gpio_is_valid(tpm_dev->io_lpcpd)) > + gpio_set_value(tpm_dev->io_lpcpd, 0); > else > ret = tpm_pm_suspend(dev); I know this is not changed by this patch, but don't you need to send a tpm savestate? or is this implicit by pulling io_lpcpd ? > > @@ -856,12 +859,13 @@ static int tpm_stm_i2c_pm_suspend(struct device *dev) > static int tpm_stm_i2c_pm_resume(struct device *dev) > { > struct tpm_chip *chip = dev_get_drvdata(dev); > - struct st33zp24_platform_data *pin_infos = dev->platform_data; > - > + struct tpm_stm_dev *tpm_dev; > int ret = 0; > > - if (gpio_is_valid(pin_infos->io_lpcpd)) { > - gpio_set_value(pin_infos->io_lpcpd, 1); > + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); > + > + if (gpio_is_valid(tpm_dev->io_lpcpd)) { > + gpio_set_value(tpm_dev->io_lpcpd, 1); > ret = wait_for_stat(chip, > TPM_STS_VALID, chip->vendor.timeout_b, > &chip->vendor.read_queue, false); Same applies to startup(STATE) on resume? Peter -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 11+ messages in thread
[parent not found: <201501262315.07543.PeterHuewe-Mmb7MZpHnFY@public.gmane.org>]
* Re: [PATCH v4 1/4] tpm/tpm_i2c_stm_st33: Replace access to io_lpcpd from struct st33zp24_platform_data to tpm_stm_dev [not found] ` <201501262315.07543.PeterHuewe-Mmb7MZpHnFY@public.gmane.org> @ 2015-01-26 22:18 ` christophe.ricard 0 siblings, 0 replies; 11+ messages in thread From: christophe.ricard @ 2015-01-26 22:18 UTC (permalink / raw) To: Peter Hüwe Cc: ashley-fm2HMyfA2y6tG0bUXCXiUA, tpmdd-yWjUBOtONefk1uMJSBkQmQ, tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, christophe-h.ricard-qxv4g6HH51o, jean-luc.blanc-qxv4g6HH51o, benoit.houyere-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA, jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/, jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA Hi Peter, The lpcpd pin allow the tpm to go in low power mode keeping the current context in RAM. As mention in the dts documentation: "If set, power must be present when the platform is going into sleep/hibernate mode." The gpio state is enough to save and restore the context. This allows for example saving some memory wear or quicker state changes... Best Regards Christophe On 26/01/2015 23:15, Peter Hüwe wrote: > Hi Christophe, > Am Sonntag, 25. Januar 2015, 22:11:30 schrieb Christophe Ricard: >> io_lpcpd is accessible from struct tpm_stm_dev. >> struct st33zp24_platform_data is only valid when using static platform >> configuration data, not when using dts. >> >> Reviewed-by: Jason Gunthorpe <jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org> >> Signed-off-by: Christophe Ricard <christophe-h.ricard-qxv4g6HH51o@public.gmane.org> >> --- >> drivers/char/tpm/tpm_i2c_stm_st33.c | 18 +++++++++++------- >> 1 file changed, 11 insertions(+), 7 deletions(-) >> >> diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c >> b/drivers/char/tpm/tpm_i2c_stm_st33.c index 612845b..882c60a 100644 >> --- a/drivers/char/tpm/tpm_i2c_stm_st33.c >> +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c >> @@ -837,11 +837,14 @@ static int tpm_stm_i2c_remove(struct i2c_client >> *client) */ >> static int tpm_stm_i2c_pm_suspend(struct device *dev) >> { >> - struct st33zp24_platform_data *pin_infos = dev->platform_data; >> + struct tpm_chip *chip = dev_get_drvdata(dev); >> + struct tpm_stm_dev *tpm_dev; >> int ret = 0; >> >> - if (gpio_is_valid(pin_infos->io_lpcpd)) >> - gpio_set_value(pin_infos->io_lpcpd, 0); >> + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); >> + >> + if (gpio_is_valid(tpm_dev->io_lpcpd)) >> + gpio_set_value(tpm_dev->io_lpcpd, 0); >> else >> ret = tpm_pm_suspend(dev); > I know this is not changed by this patch, but > don't you need to send a tpm savestate? or is this implicit by pulling > io_lpcpd ? > > > >> @@ -856,12 +859,13 @@ static int tpm_stm_i2c_pm_suspend(struct device *dev) >> static int tpm_stm_i2c_pm_resume(struct device *dev) >> { >> struct tpm_chip *chip = dev_get_drvdata(dev); >> - struct st33zp24_platform_data *pin_infos = dev->platform_data; >> - >> + struct tpm_stm_dev *tpm_dev; >> int ret = 0; >> >> - if (gpio_is_valid(pin_infos->io_lpcpd)) { >> - gpio_set_value(pin_infos->io_lpcpd, 1); >> + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); >> + >> + if (gpio_is_valid(tpm_dev->io_lpcpd)) { >> + gpio_set_value(tpm_dev->io_lpcpd, 1); >> ret = wait_for_stat(chip, >> TPM_STS_VALID, chip->vendor.timeout_b, >> &chip->vendor.read_queue, false); > > Same applies to startup(STATE) on resume? > > Peter -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v4 2/4] tpm/tpm_i2c_stm_st33: Split tpm_i2c_tpm_st33 in 2 layers (core + phy) [not found] ` <1422220293-21005-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org> 2015-01-25 21:11 ` [PATCH v4 1/4] tpm/tpm_i2c_stm_st33: Replace access to io_lpcpd from struct st33zp24_platform_data to tpm_stm_dev Christophe Ricard @ 2015-01-25 21:11 ` Christophe Ricard [not found] ` <1422220293-21005-3-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org> 2015-01-25 21:11 ` [PATCH v4 3/4] tpm/st33zp24/spi: Add st33zp24 spi phy Christophe Ricard ` (2 subsequent siblings) 4 siblings, 1 reply; 11+ messages in thread From: Christophe Ricard @ 2015-01-25 21:11 UTC (permalink / raw) To: PeterHuewe-Mmb7MZpHnFY Cc: ashley-fm2HMyfA2y6tG0bUXCXiUA, tpmdd-yWjUBOtONefk1uMJSBkQmQ, tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, christophe-h.ricard-qxv4g6HH51o, jean-luc.blanc-qxv4g6HH51o, benoit.houyere-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA, jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/, jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA tpm_i2c_stm_st33 is a TIS 1.2 TPM with a core interface which can be used by different phy such as i2c or spi. The core part is called st33zp24 which is also the main part reference. include/linux/platform_data/tpm_stm_st33.h is renamed consequently. The driver is also split into an i2c phy in charge of sending/receiving data as well as managing platform data or dts configuration. Reviewed-by: Jason Gunthorpe <jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org> Signed-off-by: Christophe Ricard <christophe-h.ricard-qxv4g6HH51o@public.gmane.org> --- drivers/char/tpm/Kconfig | 11 +- drivers/char/tpm/Makefile | 2 +- drivers/char/tpm/st33zp24/Kconfig | 20 + drivers/char/tpm/st33zp24/Makefile | 9 + drivers/char/tpm/st33zp24/i2c.c | 278 +++++++++ drivers/char/tpm/st33zp24/st33zp24.c | 691 ++++++++++++++++++++++ drivers/char/tpm/st33zp24/st33zp24.h | 34 ++ drivers/char/tpm/tpm_i2c_stm_st33.c | 915 ----------------------------- include/linux/platform_data/st33zp24.h | 28 + include/linux/platform_data/tpm_stm_st33.h | 39 -- 10 files changed, 1062 insertions(+), 965 deletions(-) create mode 100644 drivers/char/tpm/st33zp24/Kconfig create mode 100644 drivers/char/tpm/st33zp24/Makefile create mode 100644 drivers/char/tpm/st33zp24/i2c.c create mode 100644 drivers/char/tpm/st33zp24/st33zp24.c create mode 100644 drivers/char/tpm/st33zp24/st33zp24.h delete mode 100644 drivers/char/tpm/tpm_i2c_stm_st33.c create mode 100644 include/linux/platform_data/st33zp24.h delete mode 100644 include/linux/platform_data/tpm_stm_st33.h diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 9d4e375..2dc16d3 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -100,16 +100,6 @@ config TCG_IBMVTPM will be accessible from within Linux. To compile this driver as a module, choose M here; the module will be called tpm_ibmvtpm. -config TCG_TIS_I2C_ST33 - tristate "TPM Interface Specification 1.2 Interface (I2C - STMicroelectronics)" - depends on I2C - depends on GPIOLIB - ---help--- - If you have a TPM security chip from STMicroelectronics working with - an I2C bus 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_i2c_stm_st33. - config TCG_XEN tristate "XEN TPM Interface" depends on TCG_TPM && XEN @@ -131,4 +121,5 @@ config TCG_CRB from within Linux. To compile this driver as a module, choose M here; the module will be called tpm_crb. +source "drivers/char/tpm/st33zp24/Kconfig" endif # TCG_TPM diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index 990cf18..56e8f1f 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -20,6 +20,6 @@ obj-$(CONFIG_TCG_NSC) += tpm_nsc.o obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o -obj-$(CONFIG_TCG_TIS_I2C_ST33) += tpm_i2c_stm_st33.o +obj-$(CONFIG_TCG_TIS_ST33ZP24) += st33zp24/ obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o obj-$(CONFIG_TCG_CRB) += tpm_crb.o diff --git a/drivers/char/tpm/st33zp24/Kconfig b/drivers/char/tpm/st33zp24/Kconfig new file mode 100644 index 0000000..51dcef5 --- /dev/null +++ b/drivers/char/tpm/st33zp24/Kconfig @@ -0,0 +1,20 @@ +config TCG_TIS_ST33ZP24 + tristate "STMicroelectronics TPM Interface Specification 1.2 Interface" + depends on GPIOLIB + ---help--- + STMicroelectronics ST33ZP24 core driver. It implements the core + TPM1.2 logic and hooks into the TPM kernel APIs. Physical layers will + register against it. + + To compile this driver as a module, choose m here. The module will be called + tpm_st33zp24. + +config TCG_TIS_ST33ZP24_I2C + tristate "TPM 1.2 ST33ZP24 I2C support" + depends on TCG_TIS_ST33ZP24 + depends on I2C + ---help--- + This module adds support for the STMicroelectronics TPM security chip + ST33ZP24 with i2c interface. + To compile this driver as a module, choose M here; the module will be + called tpm_st33zp24_i2c. diff --git a/drivers/char/tpm/st33zp24/Makefile b/drivers/char/tpm/st33zp24/Makefile new file mode 100644 index 0000000..414497f --- /dev/null +++ b/drivers/char/tpm/st33zp24/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for ST33ZP24 TPM 1.2 driver +# + +tpm_st33zp24-objs = st33zp24.o +obj-$(CONFIG_TCG_TIS_ST33ZP24) += tpm_st33zp24.o + +tpm_st33zp24_i2c-objs = i2c.o +obj-$(CONFIG_TCG_TIS_ST33ZP24_I2C) += tpm_st33zp24_i2c.o diff --git a/drivers/char/tpm/st33zp24/i2c.c b/drivers/char/tpm/st33zp24/i2c.c new file mode 100644 index 0000000..95e3091 --- /dev/null +++ b/drivers/char/tpm/st33zp24/i2c.c @@ -0,0 +1,278 @@ +/* + * STMicroelectronics TPM I2C Linux driver for TPM ST33ZP24 + * Copyright (C) 2009 - 2015 STMicroelectronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#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 <linux/platform_data/st33zp24.h> + +#include "st33zp24.h" + +#define TPM_DUMMY_BYTE 0xAA +#define TPM_WRITE_DIRECTION 0x80 +#define TPM_BUFSIZE 2048 + +struct st33zp24_i2c_phy { + struct i2c_client *client; + u8 buf[TPM_BUFSIZE + 1]; + int io_lpcpd; +}; + +/* + * write8_reg + * Send byte to the TIS register according to the ST33ZP24 I2C protocol. + * @param: tpm_register, the tpm tis register where the data should be written + * @param: tpm_data, the tpm_data to write inside the tpm_register + * @param: tpm_size, The length of the data + * @return: Returns negative errno, or else the number of bytes written. + */ +static int write8_reg(void *phy_id, u8 tpm_register, u8 *tpm_data, int tpm_size) +{ + struct st33zp24_i2c_phy *phy = phy_id; + + phy->buf[0] = tpm_register; + memcpy(phy->buf + 1, tpm_data, tpm_size); + return i2c_master_send(phy->client, phy->buf, tpm_size + 1); +} /* write8_reg() */ + +/* + * read8_reg + * Recv byte from the TIS register according to the ST33ZP24 I2C protocol. + * @param: tpm_register, the tpm tis register where the data should be read + * @param: tpm_data, the TPM response + * @param: tpm_size, tpm TPM response size to read. + * @return: number of byte read successfully: should be one if success. + */ +static int read8_reg(void *phy_id, u8 tpm_register, u8 *tpm_data, int tpm_size) +{ + struct st33zp24_i2c_phy *phy = phy_id; + u8 status = 0; + u8 data; + + data = TPM_DUMMY_BYTE; + status = write8_reg(phy, tpm_register, &data, 1); + if (status == 2) + status = i2c_master_recv(phy->client, tpm_data, tpm_size); + return status; +} /* read8_reg() */ + +/* + * st33zp24_i2c_send + * Send byte to the TIS register according to the ST33ZP24 I2C protocol. + * @param: phy_id, the phy description + * @param: tpm_register, the tpm tis register where the data should be written + * @param: tpm_data, the tpm_data to write inside the tpm_register + * @param: tpm_size, the length of the data + * @return: number of byte written successfully: should be one if success. + */ +static int st33zp24_i2c_send(void *phy_id, u8 tpm_register, u8 *tpm_data, + int tpm_size) +{ + return write8_reg(phy_id, tpm_register | TPM_WRITE_DIRECTION, tpm_data, + tpm_size); +} + +/* + * st33zp24_i2c_recv + * Recv byte from the TIS register according to the ST33ZP24 I2C protocol. + * @param: phy_id, the phy description + * @param: tpm_register, the tpm tis register where the data should be read + * @param: tpm_data, the TPM response + * @param: tpm_size, tpm TPM response size to read. + * @return: number of byte read successfully: should be one if success. + */ +static int st33zp24_i2c_recv(void *phy_id, u8 tpm_register, u8 *tpm_data, + int tpm_size) +{ + return read8_reg(phy_id, tpm_register, tpm_data, tpm_size); +} + +static const struct st33zp24_phy_ops i2c_phy_ops = { + .send = st33zp24_i2c_send, + .recv = st33zp24_i2c_recv, +}; + +#ifdef CONFIG_OF +static int st33zp24_i2c_of_request_resources(struct st33zp24_i2c_phy *phy) +{ + struct device_node *pp; + struct i2c_client *client = phy->client; + int gpio; + int ret; + + pp = client->dev.of_node; + if (!pp) { + dev_err(&client->dev, "No platform data\n"); + return -ENODEV; + } + + /* Get GPIO from device tree */ + gpio = of_get_named_gpio(pp, "lpcpd-gpios", 0); + if (gpio < 0) { + dev_err(&client->dev, + "Failed to retrieve lpcpd-gpios from dts.\n"); + phy->io_lpcpd = -1; + /* + * lpcpd pin is not specified. This is not an issue as + * power management can be also managed by TPM specific + * commands. So leave with a success status code. + */ + return 0; + } + /* GPIO request and configuration */ + ret = devm_gpio_request_one(&client->dev, gpio, + GPIOF_OUT_INIT_HIGH, "TPM IO LPCPD"); + if (ret) { + dev_err(&client->dev, "Failed to request lpcpd pin\n"); + return -ENODEV; + } + phy->io_lpcpd = gpio; + + return 0; +} +#else +static int st33zp24_i2c_of_request_resources(struct st33zp24_i2c_phy *phy) +{ + return -ENODEV; +} +#endif + +static int st33zp24_i2c_request_resources(struct i2c_client *client, + struct st33zp24_i2c_phy *phy) +{ + struct st33zp24_platform_data *pdata; + int ret; + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->dev, "No platform data\n"); + return -ENODEV; + } + + /* store for late use */ + phy->io_lpcpd = pdata->io_lpcpd; + + if (gpio_is_valid(pdata->io_lpcpd)) { + ret = devm_gpio_request_one(&client->dev, + pdata->io_lpcpd, GPIOF_OUT_INIT_HIGH, + "TPM IO_LPCPD"); + if (ret) { + dev_err(&client->dev, "Failed to request lpcpd pin\n"); + return ret; + } + } + + return 0; +} + +/* + * st33zp24_i2c_probe initialize the TPM device + * @param: client, the i2c_client drescription (TPM I2C description). + * @param: id, the i2c_device_id struct. + * @return: 0 in case of success. + * -1 in other case. + */ +static int st33zp24_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct st33zp24_platform_data *pdata; + struct st33zp24_i2c_phy *phy; + + if (!client) { + pr_info("%s: i2c client is NULL. Device not accessible.\n", + __func__); + return -ENODEV; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_info(&client->dev, "client not i2c capable\n"); + return -ENODEV; + } + + phy = devm_kzalloc(&client->dev, sizeof(struct st33zp24_i2c_phy), + GFP_KERNEL); + if (!phy) + return -ENOMEM; + + phy->client = client; + pdata = client->dev.platform_data; + if (!pdata && client->dev.of_node) { + ret = st33zp24_i2c_of_request_resources(phy); + if (ret) + return ret; + } else if (pdata) { + ret = st33zp24_i2c_request_resources(client, phy); + if (ret) + return ret; + } + + return st33zp24_probe(phy, &i2c_phy_ops, &client->dev, client->irq, + phy->io_lpcpd); +} + +/* + * st33zp24_i2c_remove remove the TPM device + * @param: client, the i2c_client description (TPM I2C description). + * @return: 0 in case of success. + */ +static int st33zp24_i2c_remove(struct i2c_client *client) +{ + struct tpm_chip *chip = i2c_get_clientdata(client); + + return st33zp24_remove(chip); +} + +static const struct i2c_device_id st33zp24_i2c_id[] = { + {TPM_ST33_I2C, 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, st33zp24_i2c_id); + +#ifdef CONFIG_OF +static const struct of_device_id of_st33zp24_i2c_match[] = { + { .compatible = "st,st33zp24-i2c", }, + {} +}; +MODULE_DEVICE_TABLE(of, of_st33zp24_i2c_match); +#endif + +static SIMPLE_DEV_PM_OPS(st33zp24_i2c_ops, st33zp24_pm_suspend, + st33zp24_pm_resume); + +static struct i2c_driver st33zp24_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = TPM_ST33_I2C, + .pm = &st33zp24_i2c_ops, + .of_match_table = of_match_ptr(of_st33zp24_i2c_match), + }, + .probe = st33zp24_i2c_probe, + .remove = st33zp24_i2c_remove, + .id_table = st33zp24_i2c_id +}; + +module_i2c_driver(st33zp24_i2c_driver); + +MODULE_AUTHOR("TPM support (TPMsupport-nkJGhpqTU55BDgjK7y7TUQ@public.gmane.org)"); +MODULE_DESCRIPTION("STM TPM 1.2 I2C ST33 Driver"); +MODULE_VERSION("1.3.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/tpm/st33zp24/st33zp24.c b/drivers/char/tpm/st33zp24/st33zp24.c new file mode 100644 index 0000000..83d2686 --- /dev/null +++ b/drivers/char/tpm/st33zp24/st33zp24.c @@ -0,0 +1,691 @@ +/* + * STMicroelectronics TPM Linux driver for TPM ST33ZP24 + * Copyright (C) 2009 - 2015 STMicroelectronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/wait.h> +#include <linux/freezer.h> +#include <linux/string.h> +#include <linux/interrupt.h> +#include <linux/gpio.h> +#include <linux/sched.h> +#include <linux/uaccess.h> +#include <linux/io.h> +#include <linux/slab.h> + +#include "../tpm.h" +#include "st33zp24.h" + +#define DRIVER_DESC "ST33ZP24 TPM 1.2 driver" + +#define TPM_ACCESS 0x0 +#define TPM_STS 0x18 +#define TPM_DATA_FIFO 0x24 +#define TPM_INTF_CAPABILITY 0x14 +#define TPM_INT_STATUS 0x10 +#define TPM_INT_ENABLE 0x08 + +#define TPM_HEADER_SIZE 10 +#define TPM_BUFSIZE 2048 + +#define LOCALITY0 0 + +enum st33zp24_access { + TPM_ACCESS_VALID = 0x80, + TPM_ACCESS_ACTIVE_LOCALITY = 0x20, + TPM_ACCESS_REQUEST_PENDING = 0x04, + TPM_ACCESS_REQUEST_USE = 0x02, +}; + +enum st33zp24_status { + TPM_STS_VALID = 0x80, + TPM_STS_COMMAND_READY = 0x40, + TPM_STS_GO = 0x20, + TPM_STS_DATA_AVAIL = 0x10, + TPM_STS_DATA_EXPECT = 0x08, +}; + +enum st33zp24_int_flags { + TPM_GLOBAL_INT_ENABLE = 0x80, + TPM_INTF_CMD_READY_INT = 0x080, + TPM_INTF_FIFO_AVALAIBLE_INT = 0x040, + TPM_INTF_WAKE_UP_READY_INT = 0x020, + TPM_INTF_LOCALITY_CHANGE_INT = 0x004, + TPM_INTF_STS_VALID_INT = 0x002, + TPM_INTF_DATA_AVAIL_INT = 0x001, +}; + +enum tis_defaults { + TIS_SHORT_TIMEOUT = 750, + TIS_LONG_TIMEOUT = 2000, +}; + +struct st33zp24_dev { + struct tpm_chip *chip; + void *phy_id; + const struct st33zp24_phy_ops *ops; + u32 intrs; + int io_lpcpd; +}; + +/* + * clear_interruption clear the pending interrupt. + * @param: tpm_dev, the tpm device device. + * @return: the interrupt status value. + */ +static u8 clear_interruption(struct st33zp24_dev *tpm_dev) +{ + u8 interrupt; + + tpm_dev->ops->recv(tpm_dev->phy_id, TPM_INT_STATUS, &interrupt, 1); + tpm_dev->ops->send(tpm_dev->phy_id, TPM_INT_STATUS, &interrupt, 1); + return interrupt; +} /* clear_interruption() */ + +/* + * st33zp24_cancel, cancel is not implemented. + * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h + */ +static void st33zp24_cancel(struct tpm_chip *chip) +{ + struct st33zp24_dev *tpm_dev; + u8 data; + + tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip); + + data = TPM_STS_COMMAND_READY; + tpm_dev->ops->send(tpm_dev->phy_id, TPM_STS, &data, 1); +} /* st33zp24_cancel() */ + +/* + * st33zp24_status return the TPM_STS register + * @param: chip, the tpm chip description + * @return: the TPM_STS register value. + */ +static u8 st33zp24_status(struct tpm_chip *chip) +{ + struct st33zp24_dev *tpm_dev; + u8 data; + + tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip); + + tpm_dev->ops->recv(tpm_dev->phy_id, TPM_STS, &data, 1); + return data; +} /* st33zp24_status() */ + +/* + * check_locality if the locality is active + * @param: chip, the tpm chip description + * @return: the active locality or -EACCESS. + */ +static int check_locality(struct tpm_chip *chip) +{ + struct st33zp24_dev *tpm_dev; + u8 data; + u8 status; + + tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip); + + status = tpm_dev->ops->recv(tpm_dev->phy_id, TPM_ACCESS, &data, 1); + if (status && (data & + (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == + (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) + return chip->vendor.locality; + + return -EACCES; +} /* check_locality() */ + +/* + * request_locality request the TPM locality + * @param: chip, the chip description + * @return: the active locality or negative value. + */ +static int request_locality(struct tpm_chip *chip) +{ + unsigned long stop; + long ret; + struct st33zp24_dev *tpm_dev; + u8 data; + + if (check_locality(chip) == chip->vendor.locality) + return chip->vendor.locality; + + tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip); + + data = TPM_ACCESS_REQUEST_USE; + ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_ACCESS, &data, 1); + if (ret < 0) + goto end; + + stop = jiffies + chip->vendor.timeout_a; + + /* Request locality is usually effective after the request */ + do { + if (check_locality(chip) >= 0) + return chip->vendor.locality; + msleep(TPM_TIMEOUT); + } while (time_before(jiffies, stop)); + ret = -EACCES; +end: + return ret; +} /* request_locality() */ + +/* + * release_locality release the active locality + * @param: chip, the tpm chip description. + */ +static void release_locality(struct tpm_chip *chip) +{ + struct st33zp24_dev *tpm_dev; + u8 data; + + tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip); + data = TPM_ACCESS_ACTIVE_LOCALITY; + + tpm_dev->ops->send(tpm_dev->phy_id, TPM_ACCESS, &data, 1); +} + +/* + * get_burstcount return the burstcount address 0x19 0x1A + * @param: chip, the chip description + * return: the burstcount or negative value. + */ +static int get_burstcount(struct tpm_chip *chip) +{ + unsigned long stop; + int burstcnt, status; + u8 tpm_reg, temp; + struct st33zp24_dev *tpm_dev; + + tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip); + + stop = jiffies + chip->vendor.timeout_d; + do { + tpm_reg = TPM_STS + 1; + status = tpm_dev->ops->recv(tpm_dev->phy_id, tpm_reg, &temp, 1); + if (status < 0) + goto end; + + tpm_reg = tpm_reg + 1; + burstcnt = temp; + status = tpm_dev->ops->recv(tpm_dev->phy_id, tpm_reg, &temp, 1); + if (status < 0) + goto end; + + burstcnt |= temp << 8; + if (burstcnt) + return burstcnt; + msleep(TPM_TIMEOUT); + } while (time_before(jiffies, stop)); + +end: + return -EBUSY; +} /* get_burstcount() */ + + +/* + * wait_for_tpm_stat_cond + * @param: chip, chip description + * @param: mask, expected mask value + * @param: check_cancel, does the command expected to be canceled ? + * @param: canceled, did we received a cancel request ? + * @return: true if status == mask or if the command is canceled. + * false in other cases. + */ +static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, + bool check_cancel, bool *canceled) +{ + u8 status = chip->ops->status(chip); + + *canceled = false; + if ((status & mask) == mask) + return true; + if (check_cancel && chip->ops->req_canceled(chip, status)) { + *canceled = true; + return true; + } + return false; +} + +/* + * wait_for_stat wait for a TPM_STS value + * @param: chip, the tpm chip description + * @param: mask, the value mask to wait + * @param: timeout, the timeout + * @param: queue, the wait queue. + * @param: check_cancel, does the command can be cancelled ? + * @return: the tpm status, 0 if success, -ETIME if timeout is reached. + */ +static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, + wait_queue_head_t *queue, bool check_cancel) +{ + unsigned long stop; + int ret; + bool canceled = false; + bool condition; + u32 cur_intrs; + u8 status; + struct st33zp24_dev *tpm_dev; + + tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip); + + /* check current status */ + status = st33zp24_status(chip); + if ((status & mask) == mask) + return 0; + + stop = jiffies + timeout; + + if (chip->vendor.irq) { + cur_intrs = tpm_dev->intrs; + clear_interruption(tpm_dev); + enable_irq(chip->vendor.irq); + +again: + timeout = stop - jiffies; + if ((long) timeout <= 0) + return -1; + + ret = wait_event_interruptible_timeout(*queue, + cur_intrs != tpm_dev->intrs, timeout); + clear_interruption(tpm_dev); + condition = wait_for_tpm_stat_cond(chip, mask, + check_cancel, &canceled); + if (ret >= 0 && condition) { + if (canceled) + return -ECANCELED; + return 0; + } + if (ret == -ERESTARTSYS && freezing(current)) { + clear_thread_flag(TIF_SIGPENDING); + goto again; + } + disable_irq_nosync(chip->vendor.irq); + + } else { + do { + msleep(TPM_TIMEOUT); + status = chip->ops->status(chip); + if ((status & mask) == mask) + return 0; + } while (time_before(jiffies, stop)); + } + + return -ETIME; +} /* wait_for_stat() */ + +/* + * recv_data receive data + * @param: chip, the tpm chip description + * @param: buf, the buffer where the data are received + * @param: count, the number of data to receive + * @return: the number of bytes read from TPM FIFO. + */ +static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) +{ + int size = 0, burstcnt, len, ret; + struct st33zp24_dev *tpm_dev; + + tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip); + + while (size < count && + wait_for_stat(chip, + TPM_STS_DATA_AVAIL | TPM_STS_VALID, + chip->vendor.timeout_c, + &chip->vendor.read_queue, true) == 0) { + burstcnt = get_burstcount(chip); + if (burstcnt < 0) + return burstcnt; + len = min_t(int, burstcnt, count - size); + ret = tpm_dev->ops->recv(tpm_dev->phy_id, TPM_DATA_FIFO, + buf + size, len); + if (ret < 0) + return ret; + + size += len; + } + return size; +} + +/* + * tpm_ioserirq_handler the serirq irq handler + * @param: irq, the tpm chip description + * @param: dev_id, the description of the chip + * @return: the status of the handler. + */ +static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id) +{ + struct tpm_chip *chip = dev_id; + struct st33zp24_dev *tpm_dev; + + tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip); + + tpm_dev->intrs++; + wake_up_interruptible(&chip->vendor.read_queue); + disable_irq_nosync(chip->vendor.irq); + + return IRQ_HANDLED; +} /* tpm_ioserirq_handler() */ + +/* + * st33zp24_send send TPM commands through the I2C bus. + * + * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h + * @param: buf, the buffer to send. + * @param: count, the number of bytes to send. + * @return: In case of success the number of bytes sent. + * In other case, a < 0 value describing the issue. + */ +static int st33zp24_send(struct tpm_chip *chip, unsigned char *buf, + size_t len) +{ + u32 status, i, size; + int burstcnt = 0; + int ret; + u8 data; + struct st33zp24_dev *tpm_dev; + + if (!chip) + return -EBUSY; + if (len < TPM_HEADER_SIZE) + return -EBUSY; + + tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip); + + ret = request_locality(chip); + if (ret < 0) + return ret; + + status = st33zp24_status(chip); + if ((status & TPM_STS_COMMAND_READY) == 0) { + st33zp24_cancel(chip); + if (wait_for_stat + (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b, + &chip->vendor.read_queue, false) < 0) { + ret = -ETIME; + goto out_err; + } + } + + for (i = 0; i < len - 1;) { + burstcnt = get_burstcount(chip); + if (burstcnt < 0) + return burstcnt; + size = min_t(int, len - i - 1, burstcnt); + ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_DATA_FIFO, + buf + i, size); + if (ret < 0) + goto out_err; + + i += size; + } + + status = st33zp24_status(chip); + if ((status & TPM_STS_DATA_EXPECT) == 0) { + ret = -EIO; + goto out_err; + } + + ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_DATA_FIFO, + buf + len - 1, 1); + if (ret < 0) + goto out_err; + + status = st33zp24_status(chip); + if ((status & TPM_STS_DATA_EXPECT) != 0) { + ret = -EIO; + goto out_err; + } + + data = TPM_STS_GO; + ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_STS, &data, 1); + if (ret < 0) + goto out_err; + + return len; +out_err: + st33zp24_cancel(chip); + release_locality(chip); + return ret; +} + +/* + * st33zp24_recv received TPM response through TPM phy. + * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h. + * @param: buf, the buffer to store datas. + * @param: count, the number of bytes to send. + * @return: In case of success the number of bytes received. + * In other case, a < 0 value describing the issue. + */ +static int st33zp24_recv(struct tpm_chip *chip, unsigned char *buf, + size_t count) +{ + int size = 0; + int expected; + + if (!chip) + return -EBUSY; + + if (count < TPM_HEADER_SIZE) { + size = -EIO; + goto out; + } + + size = recv_data(chip, buf, TPM_HEADER_SIZE); + 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) { + 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; + } + +out: + st33zp24_cancel(chip); + release_locality(chip); + return size; +} + +/* + * st33zp24_req_canceled + * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h. + * @param: status, the TPM status. + * @return: Does TPM ready to compute a new command ? true. + */ +static bool st33zp24_req_canceled(struct tpm_chip *chip, u8 status) +{ + return (status == TPM_STS_COMMAND_READY); +} + +static const struct tpm_class_ops st33zp24_tpm = { + .send = st33zp24_send, + .recv = st33zp24_recv, + .cancel = st33zp24_cancel, + .status = st33zp24_status, + .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, + .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, + .req_canceled = st33zp24_req_canceled, +}; + +/* + * st33zp24_probe initialize the TPM device + * @param: client, the i2c_client drescription (TPM I2C description). + * @param: id, the i2c_device_id struct. + * @return: 0 in case of success. + * -1 in other case. + */ +int st33zp24_probe(void *phy_id, const struct st33zp24_phy_ops *ops, + struct device *dev, int irq, int io_lpcpd) +{ + int ret; + u8 intmask = 0; + struct tpm_chip *chip; + struct st33zp24_dev *tpm_dev; + + chip = tpmm_chip_alloc(dev, &st33zp24_tpm); + if (IS_ERR(chip)) + return PTR_ERR(chip); + + tpm_dev = devm_kzalloc(dev, sizeof(struct st33zp24_dev), + GFP_KERNEL); + if (!tpm_dev) + return -ENOMEM; + + TPM_VPRIV(chip) = tpm_dev; + tpm_dev->phy_id = phy_id; + tpm_dev->ops = ops; + + chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); + chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); + chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); + chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); + + chip->vendor.locality = LOCALITY0; + + if (irq) { + /* INTERRUPT Setup */ + init_waitqueue_head(&chip->vendor.read_queue); + tpm_dev->intrs = 0; + + if (request_locality(chip) != LOCALITY0) { + ret = -ENODEV; + goto _tpm_clean_answer; + } + + clear_interruption(tpm_dev); + ret = devm_request_irq(dev, irq, tpm_ioserirq_handler, + IRQF_TRIGGER_HIGH, "TPM SERIRQ management", + chip); + if (ret < 0) { + dev_err(&chip->dev , "TPM SERIRQ signals %d not available\n", + irq); + goto _tpm_clean_answer; + } + + intmask |= TPM_INTF_CMD_READY_INT + | TPM_INTF_STS_VALID_INT + | TPM_INTF_DATA_AVAIL_INT; + + ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_INT_ENABLE, + &intmask, 1); + if (ret < 0) + goto _tpm_clean_answer; + + intmask = TPM_GLOBAL_INT_ENABLE; + ret = tpm_dev->ops->send(tpm_dev->phy_id, (TPM_INT_ENABLE + 3), + &intmask, 1); + if (ret < 0) + goto _tpm_clean_answer; + + chip->vendor.irq = irq; + + disable_irq_nosync(chip->vendor.irq); + + tpm_gen_interrupt(chip); + } + + tpm_get_timeouts(chip); + tpm_do_selftest(chip); + + return tpm_chip_register(chip); +_tpm_clean_answer: + dev_info(&chip->dev, "TPM initialization fail\n"); + return ret; +} +EXPORT_SYMBOL(st33zp24_probe); + +/* + * st33zp24_remove remove the TPM device + * @param: tpm_data, the tpm phy. + * @return: 0 in case of success. + */ +int st33zp24_remove(struct tpm_chip *chip) +{ + tpm_chip_unregister(chip); + return 0; +} +EXPORT_SYMBOL(st33zp24_remove); + +#ifdef CONFIG_PM_SLEEP +/* + * st33zp24_pm_suspend suspend the TPM device + * @param: tpm_data, the tpm phy. + * @param: mesg, the power management message. + * @return: 0 in case of success. + */ +int st33zp24_pm_suspend(struct device *dev) +{ + struct tpm_chip *chip = dev_get_drvdata(dev); + struct st33zp24_dev *tpm_dev; + int ret = 0; + + tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip); + + if (gpio_is_valid(tpm_dev->io_lpcpd)) + gpio_set_value(tpm_dev->io_lpcpd, 0); + else + ret = tpm_pm_suspend(dev); + + return ret; +} /* st33zp24_pm_suspend() */ +EXPORT_SYMBOL(st33zp24_pm_suspend); + +/* + * st33zp24_pm_resume resume the TPM device + * @param: tpm_data, the tpm phy. + * @return: 0 in case of success. + */ +int st33zp24_pm_resume(struct device *dev) +{ + struct tpm_chip *chip = dev_get_drvdata(dev); + struct st33zp24_dev *tpm_dev; + int ret = 0; + + tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip); + + if (gpio_is_valid(tpm_dev->io_lpcpd)) { + gpio_set_value(tpm_dev->io_lpcpd, 1); + ret = wait_for_stat(chip, + TPM_STS_VALID, chip->vendor.timeout_b, + &chip->vendor.read_queue, false); + } else { + ret = tpm_pm_resume(dev); + if (!ret) + tpm_do_selftest(chip); + } + return ret; +} /* st33zp24_pm_resume() */ +EXPORT_SYMBOL(st33zp24_pm_resume); +#endif + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/char/tpm/st33zp24/st33zp24.h b/drivers/char/tpm/st33zp24/st33zp24.h new file mode 100644 index 0000000..68f77b2 --- /dev/null +++ b/drivers/char/tpm/st33zp24/st33zp24.h @@ -0,0 +1,34 @@ +/* + * STMicroelectronics TPM Linux driver for TPM ST33ZP24 + * Copyright (C) 2009 - 2015 STMicroelectronics + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __LOCAL_ST33ZP24_H__ +#define __LOCAL_ST33ZP24_H__ + +struct st33zp24_phy_ops { + int (*send)(void *dev_id, u8 tpm_register, u8 *tpm_data, int tpm_size); + int (*recv)(void *dev_id, u8 tpm_register, u8 *tpm_data, int tpm_size); +}; + +#ifdef CONFIG_PM_SLEEP +int st33zp24_pm_suspend(struct device *dev); +int st33zp24_pm_resume(struct device *dev); +#endif + +int st33zp24_probe(void *phy_id, const struct st33zp24_phy_ops *ops, + struct device *dev, int irq, int io_lpcpd); +int st33zp24_remove(struct tpm_chip *chip); +#endif /* __LOCAL_ST33ZP24_H__ */ diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c deleted file mode 100644 index 882c60a..0000000 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ /dev/null @@ -1,915 +0,0 @@ -/* - * STMicroelectronics TPM I2C Linux driver for TPM ST33ZP24 - * Copyright (C) 2009, 2010, 2014 STMicroelectronics - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * - * STMicroelectronics version 1.2.1, Copyright (C) 2014 - * STMicroelectronics comes with ABSOLUTELY NO WARRANTY. - * This is free software, and you are welcome to redistribute it - * under certain conditions. - * - * @Author: Christophe RICARD tpmsupport-qxv4g6HH51o@public.gmane.org - * - * @File: tpm_stm_st33_i2c.c - * - * @Synopsis: - * 09/15/2010: First shot driver tpm_tis driver for - * lpc is used as model. - */ - -#include <linux/pci.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/i2c.h> -#include <linux/fs.h> -#include <linux/miscdevice.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/wait.h> -#include <linux/freezer.h> -#include <linux/string.h> -#include <linux/interrupt.h> -#include <linux/sysfs.h> -#include <linux/gpio.h> -#include <linux/sched.h> -#include <linux/uaccess.h> -#include <linux/io.h> -#include <linux/slab.h> -#include <linux/of_irq.h> -#include <linux/of_gpio.h> - -#include <linux/platform_data/tpm_stm_st33.h> -#include "tpm.h" - -#define TPM_ACCESS 0x0 -#define TPM_STS 0x18 -#define TPM_HASH_END 0x20 -#define TPM_DATA_FIFO 0x24 -#define TPM_HASH_DATA 0x24 -#define TPM_HASH_START 0x28 -#define TPM_INTF_CAPABILITY 0x14 -#define TPM_INT_STATUS 0x10 -#define TPM_INT_ENABLE 0x08 - -#define TPM_DUMMY_BYTE 0xAA -#define TPM_WRITE_DIRECTION 0x80 -#define TPM_HEADER_SIZE 10 -#define TPM_BUFSIZE 2048 - -#define LOCALITY0 0 - - -enum stm33zp24_access { - TPM_ACCESS_VALID = 0x80, - TPM_ACCESS_ACTIVE_LOCALITY = 0x20, - TPM_ACCESS_REQUEST_PENDING = 0x04, - TPM_ACCESS_REQUEST_USE = 0x02, -}; - -enum stm33zp24_status { - TPM_STS_VALID = 0x80, - TPM_STS_COMMAND_READY = 0x40, - TPM_STS_GO = 0x20, - TPM_STS_DATA_AVAIL = 0x10, - TPM_STS_DATA_EXPECT = 0x08, -}; - -enum stm33zp24_int_flags { - TPM_GLOBAL_INT_ENABLE = 0x80, - TPM_INTF_CMD_READY_INT = 0x080, - TPM_INTF_FIFO_AVALAIBLE_INT = 0x040, - TPM_INTF_WAKE_UP_READY_INT = 0x020, - TPM_INTF_LOCALITY_CHANGE_INT = 0x004, - TPM_INTF_STS_VALID_INT = 0x002, - TPM_INTF_DATA_AVAIL_INT = 0x001, -}; - -enum tis_defaults { - TIS_SHORT_TIMEOUT = 750, - TIS_LONG_TIMEOUT = 2000, -}; - -struct tpm_stm_dev { - struct i2c_client *client; - struct tpm_chip *chip; - u8 buf[TPM_BUFSIZE + 1]; - u32 intrs; - int io_lpcpd; -}; - -/* - * write8_reg - * Send byte to the TIS register according to the ST33ZP24 I2C protocol. - * @param: tpm_register, the tpm tis register where the data should be written - * @param: tpm_data, the tpm_data to write inside the tpm_register - * @param: tpm_size, The length of the data - * @return: Returns negative errno, or else the number of bytes written. - */ -static int write8_reg(struct tpm_stm_dev *tpm_dev, u8 tpm_register, - u8 *tpm_data, u16 tpm_size) -{ - tpm_dev->buf[0] = tpm_register; - memcpy(tpm_dev->buf + 1, tpm_data, tpm_size); - return i2c_master_send(tpm_dev->client, tpm_dev->buf, tpm_size + 1); -} /* write8_reg() */ - -/* - * read8_reg - * Recv byte from the TIS register according to the ST33ZP24 I2C protocol. - * @param: tpm_register, the tpm tis register where the data should be read - * @param: tpm_data, the TPM response - * @param: tpm_size, tpm TPM response size to read. - * @return: number of byte read successfully: should be one if success. - */ -static int read8_reg(struct tpm_stm_dev *tpm_dev, u8 tpm_register, - u8 *tpm_data, int tpm_size) -{ - u8 status = 0; - u8 data; - - data = TPM_DUMMY_BYTE; - status = write8_reg(tpm_dev, tpm_register, &data, 1); - if (status == 2) - status = i2c_master_recv(tpm_dev->client, tpm_data, tpm_size); - return status; -} /* read8_reg() */ - -/* - * I2C_WRITE_DATA - * Send byte to the TIS register according to the ST33ZP24 I2C protocol. - * @param: tpm_dev, the chip description - * @param: tpm_register, the tpm tis register where the data should be written - * @param: tpm_data, the tpm_data to write inside the tpm_register - * @param: tpm_size, The length of the data - * @return: number of byte written successfully: should be one if success. - */ -#define I2C_WRITE_DATA(tpm_dev, tpm_register, tpm_data, tpm_size) \ - (write8_reg(tpm_dev, tpm_register | \ - TPM_WRITE_DIRECTION, tpm_data, tpm_size)) - -/* - * I2C_READ_DATA - * Recv byte from the TIS register according to the ST33ZP24 I2C protocol. - * @param: tpm_dev, the chip description - * @param: tpm_register, the tpm tis register where the data should be read - * @param: tpm_data, the TPM response - * @param: tpm_size, tpm TPM response size to read. - * @return: number of byte read successfully: should be one if success. - */ -#define I2C_READ_DATA(tpm_dev, tpm_register, tpm_data, tpm_size) \ - (read8_reg(tpm_dev, tpm_register, tpm_data, tpm_size)) - -/* - * clear_interruption - * clear the TPM interrupt register. - * @param: tpm, the chip description - * @return: the TPM_INT_STATUS value - */ -static u8 clear_interruption(struct tpm_stm_dev *tpm_dev) -{ - u8 interrupt; - - I2C_READ_DATA(tpm_dev, TPM_INT_STATUS, &interrupt, 1); - I2C_WRITE_DATA(tpm_dev, TPM_INT_STATUS, &interrupt, 1); - return interrupt; -} /* clear_interruption() */ - -/* - * tpm_stm_i2c_cancel, cancel is not implemented. - * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h - */ -static void tpm_stm_i2c_cancel(struct tpm_chip *chip) -{ - struct tpm_stm_dev *tpm_dev; - u8 data; - - tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); - - data = TPM_STS_COMMAND_READY; - I2C_WRITE_DATA(tpm_dev, TPM_STS, &data, 1); -} /* tpm_stm_i2c_cancel() */ - -/* - * tpm_stm_spi_status return the TPM_STS register - * @param: chip, the tpm chip description - * @return: the TPM_STS register value. - */ -static u8 tpm_stm_i2c_status(struct tpm_chip *chip) -{ - struct tpm_stm_dev *tpm_dev; - u8 data; - - tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); - - I2C_READ_DATA(tpm_dev, TPM_STS, &data, 1); - return data; -} /* tpm_stm_i2c_status() */ - - -/* - * check_locality if the locality is active - * @param: chip, the tpm chip description - * @return: the active locality or -EACCESS. - */ -static int check_locality(struct tpm_chip *chip) -{ - struct tpm_stm_dev *tpm_dev; - u8 data; - u8 status; - - tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); - - status = I2C_READ_DATA(tpm_dev, TPM_ACCESS, &data, 1); - if (status && (data & - (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == - (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) - return chip->vendor.locality; - - return -EACCES; -} /* check_locality() */ - -/* - * request_locality request the TPM locality - * @param: chip, the chip description - * @return: the active locality or EACCESS. - */ -static int request_locality(struct tpm_chip *chip) -{ - unsigned long stop; - long ret; - struct tpm_stm_dev *tpm_dev; - u8 data; - - if (check_locality(chip) == chip->vendor.locality) - return chip->vendor.locality; - - tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); - - data = TPM_ACCESS_REQUEST_USE; - ret = I2C_WRITE_DATA(tpm_dev, TPM_ACCESS, &data, 1); - if (ret < 0) - goto end; - - stop = jiffies + chip->vendor.timeout_a; - - /* Request locality is usually effective after the request */ - do { - if (check_locality(chip) >= 0) - return chip->vendor.locality; - msleep(TPM_TIMEOUT); - } while (time_before(jiffies, stop)); - ret = -EACCES; -end: - return ret; -} /* request_locality() */ - -/* - * release_locality release the active locality - * @param: chip, the tpm chip description. - */ -static void release_locality(struct tpm_chip *chip) -{ - struct tpm_stm_dev *tpm_dev; - u8 data; - - tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); - data = TPM_ACCESS_ACTIVE_LOCALITY; - - I2C_WRITE_DATA(tpm_dev, TPM_ACCESS, &data, 1); -} - -/* - * get_burstcount return the burstcount address 0x19 0x1A - * @param: chip, the chip description - * return: the burstcount. - */ -static int get_burstcount(struct tpm_chip *chip) -{ - unsigned long stop; - int burstcnt, status; - u8 tpm_reg, temp; - struct tpm_stm_dev *tpm_dev; - - tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); - - stop = jiffies + chip->vendor.timeout_d; - do { - tpm_reg = TPM_STS + 1; - status = I2C_READ_DATA(tpm_dev, tpm_reg, &temp, 1); - if (status < 0) - goto end; - - tpm_reg = tpm_reg + 1; - burstcnt = temp; - status = I2C_READ_DATA(tpm_dev, tpm_reg, &temp, 1); - if (status < 0) - goto end; - - burstcnt |= temp << 8; - if (burstcnt) - return burstcnt; - msleep(TPM_TIMEOUT); - } while (time_before(jiffies, stop)); - -end: - return -EBUSY; -} /* get_burstcount() */ - -static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, - bool check_cancel, bool *canceled) -{ - u8 status = chip->ops->status(chip); - - *canceled = false; - if ((status & mask) == mask) - return true; - if (check_cancel && chip->ops->req_canceled(chip, status)) { - *canceled = true; - return true; - } - return false; -} - -/* - * interrupt_to_status - * @param: irq_mask, the irq mask value to wait - * @return: the corresponding tpm_sts value - */ -static u8 interrupt_to_status(u8 irq_mask) -{ - u8 status = 0; - - if ((irq_mask & TPM_INTF_STS_VALID_INT) == TPM_INTF_STS_VALID_INT) - status |= TPM_STS_VALID; - if ((irq_mask & TPM_INTF_DATA_AVAIL_INT) == TPM_INTF_DATA_AVAIL_INT) - status |= TPM_STS_DATA_AVAIL; - if ((irq_mask & TPM_INTF_CMD_READY_INT) == TPM_INTF_CMD_READY_INT) - status |= TPM_STS_COMMAND_READY; - - return status; -} /* status_to_interrupt() */ - -/* - * wait_for_stat wait for a TPM_STS value - * @param: chip, the tpm chip description - * @param: mask, the value mask to wait - * @param: timeout, the timeout - * @param: queue, the wait queue. - * @param: check_cancel, does the command can be cancelled ? - * @return: the tpm status, 0 if success, -ETIME if timeout is reached. - */ -static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, - wait_queue_head_t *queue, bool check_cancel) -{ - unsigned long stop; - int ret; - bool canceled = false; - bool condition; - u32 cur_intrs; - u8 interrupt, status; - struct tpm_stm_dev *tpm_dev; - - tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); - - /* check current status */ - status = tpm_stm_i2c_status(chip); - if ((status & mask) == mask) - return 0; - - stop = jiffies + timeout; - - if (chip->vendor.irq) { - cur_intrs = tpm_dev->intrs; - interrupt = clear_interruption(tpm_dev); - enable_irq(chip->vendor.irq); - -again: - timeout = stop - jiffies; - if ((long) timeout <= 0) - return -1; - - ret = wait_event_interruptible_timeout(*queue, - cur_intrs != tpm_dev->intrs, timeout); - - interrupt |= clear_interruption(tpm_dev); - status = interrupt_to_status(interrupt); - condition = wait_for_tpm_stat_cond(chip, mask, - check_cancel, &canceled); - - if (ret >= 0 && condition) { - if (canceled) - return -ECANCELED; - return 0; - } - if (ret == -ERESTARTSYS && freezing(current)) { - clear_thread_flag(TIF_SIGPENDING); - goto again; - } - disable_irq_nosync(chip->vendor.irq); - - } else { - do { - msleep(TPM_TIMEOUT); - status = chip->ops->status(chip); - if ((status & mask) == mask) - return 0; - } while (time_before(jiffies, stop)); - } - - return -ETIME; -} /* wait_for_stat() */ - -/* - * recv_data receive data - * @param: chip, the tpm chip description - * @param: buf, the buffer where the data are received - * @param: count, the number of data to receive - * @return: the number of bytes read from TPM FIFO. - */ -static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) -{ - int size = 0, burstcnt, len, ret; - struct tpm_stm_dev *tpm_dev; - - tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); - - while (size < count && - wait_for_stat(chip, - TPM_STS_DATA_AVAIL | TPM_STS_VALID, - chip->vendor.timeout_c, - &chip->vendor.read_queue, true) == 0) { - burstcnt = get_burstcount(chip); - if (burstcnt < 0) - return burstcnt; - len = min_t(int, burstcnt, count - size); - ret = I2C_READ_DATA(tpm_dev, TPM_DATA_FIFO, buf + size, len); - if (ret < 0) - return ret; - - size += len; - } - return size; -} - -/* - * tpm_ioserirq_handler the serirq irq handler - * @param: irq, the tpm chip description - * @param: dev_id, the description of the chip - * @return: the status of the handler. - */ -static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id) -{ - struct tpm_chip *chip = dev_id; - struct tpm_stm_dev *tpm_dev; - - tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); - - tpm_dev->intrs++; - wake_up_interruptible(&chip->vendor.read_queue); - disable_irq_nosync(chip->vendor.irq); - - return IRQ_HANDLED; -} /* tpm_ioserirq_handler() */ - - -/* - * tpm_stm_i2c_send send TPM commands through the I2C bus. - * - * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h - * @param: buf, the buffer to send. - * @param: count, the number of bytes to send. - * @return: In case of success the number of bytes sent. - * In other case, a < 0 value describing the issue. - */ -static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf, - size_t len) -{ - u32 status, i, size; - int burstcnt = 0; - int ret; - u8 data; - struct i2c_client *client; - struct tpm_stm_dev *tpm_dev; - - if (!chip) - return -EBUSY; - if (len < TPM_HEADER_SIZE) - return -EBUSY; - - tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); - client = tpm_dev->client; - - client->flags = 0; - - ret = request_locality(chip); - if (ret < 0) - return ret; - - status = tpm_stm_i2c_status(chip); - if ((status & TPM_STS_COMMAND_READY) == 0) { - tpm_stm_i2c_cancel(chip); - if (wait_for_stat - (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b, - &chip->vendor.read_queue, false) < 0) { - ret = -ETIME; - goto out_err; - } - } - - for (i = 0; i < len - 1;) { - burstcnt = get_burstcount(chip); - if (burstcnt < 0) - return burstcnt; - size = min_t(int, len - i - 1, burstcnt); - ret = I2C_WRITE_DATA(tpm_dev, TPM_DATA_FIFO, buf + i, size); - if (ret < 0) - goto out_err; - - i += size; - } - - status = tpm_stm_i2c_status(chip); - if ((status & TPM_STS_DATA_EXPECT) == 0) { - ret = -EIO; - goto out_err; - } - - ret = I2C_WRITE_DATA(tpm_dev, TPM_DATA_FIFO, buf + len - 1, 1); - if (ret < 0) - goto out_err; - - status = tpm_stm_i2c_status(chip); - if ((status & TPM_STS_DATA_EXPECT) != 0) { - ret = -EIO; - goto out_err; - } - - data = TPM_STS_GO; - I2C_WRITE_DATA(tpm_dev, TPM_STS, &data, 1); - - return len; -out_err: - tpm_stm_i2c_cancel(chip); - release_locality(chip); - return ret; -} - -/* - * tpm_stm_i2c_recv received TPM response through the I2C bus. - * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h. - * @param: buf, the buffer to store datas. - * @param: count, the number of bytes to send. - * @return: In case of success the number of bytes received. - * In other case, a < 0 value describing the issue. - */ -static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf, - size_t count) -{ - int size = 0; - int expected; - - if (!chip) - return -EBUSY; - - if (count < TPM_HEADER_SIZE) { - size = -EIO; - goto out; - } - - size = recv_data(chip, buf, TPM_HEADER_SIZE); - if (size < TPM_HEADER_SIZE) { - dev_err(chip->pdev, "Unable to read header\n"); - goto out; - } - - expected = be32_to_cpu(*(__be32 *)(buf + 2)); - if (expected > count) { - size = -EIO; - goto out; - } - - size += recv_data(chip, &buf[TPM_HEADER_SIZE], - expected - TPM_HEADER_SIZE); - if (size < expected) { - dev_err(chip->pdev, "Unable to read remainder of result\n"); - size = -ETIME; - goto out; - } - -out: - chip->ops->cancel(chip); - release_locality(chip); - return size; -} - -static bool tpm_stm_i2c_req_canceled(struct tpm_chip *chip, u8 status) -{ - return (status == TPM_STS_COMMAND_READY); -} - -static const struct tpm_class_ops st_i2c_tpm = { - .send = tpm_stm_i2c_send, - .recv = tpm_stm_i2c_recv, - .cancel = tpm_stm_i2c_cancel, - .status = tpm_stm_i2c_status, - .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, - .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, - .req_canceled = tpm_stm_i2c_req_canceled, -}; - -#ifdef CONFIG_OF -static int tpm_stm_i2c_of_request_resources(struct tpm_chip *chip) -{ - struct device_node *pp; - struct tpm_stm_dev *tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); - struct i2c_client *client = tpm_dev->client; - int gpio; - int ret; - - pp = client->dev.of_node; - if (!pp) { - dev_err(chip->pdev, "No platform data\n"); - return -ENODEV; - } - - /* Get GPIO from device tree */ - gpio = of_get_named_gpio(pp, "lpcpd-gpios", 0); - if (gpio < 0) { - dev_err(chip->pdev, "Failed to retrieve lpcpd-gpios from dts.\n"); - tpm_dev->io_lpcpd = -1; - /* - * lpcpd pin is not specified. This is not an issue as - * power management can be also managed by TPM specific - * commands. So leave with a success status code. - */ - return 0; - } - /* GPIO request and configuration */ - ret = devm_gpio_request_one(&client->dev, gpio, - GPIOF_OUT_INIT_HIGH, "TPM IO LPCPD"); - if (ret) { - dev_err(chip->pdev, "Failed to request lpcpd pin\n"); - return -ENODEV; - } - tpm_dev->io_lpcpd = gpio; - - return 0; -} -#else -static int tpm_stm_i2c_of_request_resources(struct tpm_chip *chip) -{ - return -ENODEV; -} -#endif - -static int tpm_stm_i2c_request_resources(struct i2c_client *client, - struct tpm_chip *chip) -{ - struct st33zp24_platform_data *pdata; - struct tpm_stm_dev *tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); - int ret; - - pdata = client->dev.platform_data; - if (!pdata) { - dev_err(chip->pdev, "No platform data\n"); - return -ENODEV; - } - - /* store for late use */ - tpm_dev->io_lpcpd = pdata->io_lpcpd; - - if (gpio_is_valid(pdata->io_lpcpd)) { - ret = devm_gpio_request_one(&client->dev, - pdata->io_lpcpd, GPIOF_OUT_INIT_HIGH, - "TPM IO_LPCPD"); - if (ret) { - dev_err(chip->pdev, "%s : reset gpio_request failed\n", - __FILE__); - return ret; - } - } - - return 0; -} - -/* - * tpm_stm_i2c_probe initialize the TPM device - * @param: client, the i2c_client drescription (TPM I2C description). - * @param: id, the i2c_device_id struct. - * @return: 0 in case of success. - * -1 in other case. - */ -static int -tpm_stm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) -{ - int ret; - u8 intmask = 0; - struct tpm_chip *chip; - struct st33zp24_platform_data *platform_data; - struct tpm_stm_dev *tpm_dev; - - if (!client) { - pr_info("%s: i2c client is NULL. Device not accessible.\n", - __func__); - return -ENODEV; - } - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - dev_info(&client->dev, "client not i2c capable\n"); - return -ENODEV; - } - - tpm_dev = devm_kzalloc(&client->dev, sizeof(struct tpm_stm_dev), - GFP_KERNEL); - if (!tpm_dev) - return -ENOMEM; - - chip = tpmm_chip_alloc(&client->dev, &st_i2c_tpm); - if (IS_ERR(chip)) - return PTR_ERR(chip); - - TPM_VPRIV(chip) = tpm_dev; - tpm_dev->client = client; - - platform_data = client->dev.platform_data; - if (!platform_data && client->dev.of_node) { - ret = tpm_stm_i2c_of_request_resources(chip); - if (ret) - goto _tpm_clean_answer; - } else if (platform_data) { - ret = tpm_stm_i2c_request_resources(client, chip); - if (ret) - goto _tpm_clean_answer; - } - - chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); - chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); - chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); - chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); - - chip->vendor.locality = LOCALITY0; - - if (client->irq) { - /* INTERRUPT Setup */ - init_waitqueue_head(&chip->vendor.read_queue); - tpm_dev->intrs = 0; - - if (request_locality(chip) != LOCALITY0) { - ret = -ENODEV; - goto _tpm_clean_answer; - } - - clear_interruption(tpm_dev); - ret = devm_request_irq(&client->dev, client->irq, - tpm_ioserirq_handler, - IRQF_TRIGGER_HIGH, - "TPM SERIRQ management", chip); - if (ret < 0) { - dev_err(chip->pdev, "TPM SERIRQ signals %d not available\n", - client->irq); - goto _tpm_clean_answer; - } - - intmask |= TPM_INTF_CMD_READY_INT - | TPM_INTF_STS_VALID_INT - | TPM_INTF_DATA_AVAIL_INT; - - ret = I2C_WRITE_DATA(tpm_dev, TPM_INT_ENABLE, &intmask, 1); - if (ret < 0) - goto _tpm_clean_answer; - - intmask = TPM_GLOBAL_INT_ENABLE; - ret = I2C_WRITE_DATA(tpm_dev, (TPM_INT_ENABLE + 3), - &intmask, 1); - if (ret < 0) - goto _tpm_clean_answer; - - chip->vendor.irq = client->irq; - - disable_irq_nosync(chip->vendor.irq); - - tpm_gen_interrupt(chip); - } - - tpm_get_timeouts(chip); - tpm_do_selftest(chip); - - return tpm_chip_register(chip); -_tpm_clean_answer: - dev_info(chip->pdev, "TPM I2C initialisation fail\n"); - return ret; -} - -/* - * tpm_stm_i2c_remove remove the TPM device - * @param: client, the i2c_client description (TPM I2C description). - * @return: 0 in case of success. - */ -static int tpm_stm_i2c_remove(struct i2c_client *client) -{ - struct tpm_chip *chip = - (struct tpm_chip *) i2c_get_clientdata(client); - - if (chip) - tpm_chip_unregister(chip); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -/* - * tpm_stm_i2c_pm_suspend suspend the TPM device - * @param: client, the i2c_client drescription (TPM I2C description). - * @param: mesg, the power management message. - * @return: 0 in case of success. - */ -static int tpm_stm_i2c_pm_suspend(struct device *dev) -{ - struct tpm_chip *chip = dev_get_drvdata(dev); - struct tpm_stm_dev *tpm_dev; - int ret = 0; - - tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); - - if (gpio_is_valid(tpm_dev->io_lpcpd)) - gpio_set_value(tpm_dev->io_lpcpd, 0); - else - ret = tpm_pm_suspend(dev); - - return ret; -} /* tpm_stm_i2c_suspend() */ - -/* - * tpm_stm_i2c_pm_resume resume the TPM device - * @param: client, the i2c_client drescription (TPM I2C description). - * @return: 0 in case of success. - */ -static int tpm_stm_i2c_pm_resume(struct device *dev) -{ - struct tpm_chip *chip = dev_get_drvdata(dev); - struct tpm_stm_dev *tpm_dev; - int ret = 0; - - tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); - - if (gpio_is_valid(tpm_dev->io_lpcpd)) { - gpio_set_value(tpm_dev->io_lpcpd, 1); - ret = wait_for_stat(chip, - TPM_STS_VALID, chip->vendor.timeout_b, - &chip->vendor.read_queue, false); - } else { - ret = tpm_pm_resume(dev); - if (!ret) - tpm_do_selftest(chip); - } - return ret; -} /* tpm_stm_i2c_pm_resume() */ -#endif - -static const struct i2c_device_id tpm_stm_i2c_id[] = { - {TPM_ST33_I2C, 0}, - {} -}; -MODULE_DEVICE_TABLE(i2c, tpm_stm_i2c_id); - -#ifdef CONFIG_OF -static const struct of_device_id of_st33zp24_i2c_match[] = { - { .compatible = "st,st33zp24-i2c", }, - {} -}; -MODULE_DEVICE_TABLE(of, of_st33zp24_i2c_match); -#endif - -static SIMPLE_DEV_PM_OPS(tpm_stm_i2c_ops, tpm_stm_i2c_pm_suspend, - tpm_stm_i2c_pm_resume); - -static struct i2c_driver tpm_stm_i2c_driver = { - .driver = { - .owner = THIS_MODULE, - .name = TPM_ST33_I2C, - .pm = &tpm_stm_i2c_ops, - .of_match_table = of_match_ptr(of_st33zp24_i2c_match), - }, - .probe = tpm_stm_i2c_probe, - .remove = tpm_stm_i2c_remove, - .id_table = tpm_stm_i2c_id -}; - -module_i2c_driver(tpm_stm_i2c_driver); - -MODULE_AUTHOR("Christophe Ricard (tpmsupport-qxv4g6HH51o@public.gmane.org)"); -MODULE_DESCRIPTION("STM TPM I2C ST33 Driver"); -MODULE_VERSION("1.2.1"); -MODULE_LICENSE("GPL"); diff --git a/include/linux/platform_data/st33zp24.h b/include/linux/platform_data/st33zp24.h new file mode 100644 index 0000000..817dfdb --- /dev/null +++ b/include/linux/platform_data/st33zp24.h @@ -0,0 +1,28 @@ +/* + * STMicroelectronics TPM Linux driver for TPM 1.2 ST33ZP24 + * Copyright (C) 2009 - 2015 STMicroelectronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ +#ifndef __ST33ZP24_H__ +#define __ST33ZP24_H__ + +#define TPM_ST33_I2C "st33zp24-i2c" +#define TPM_ST33_SPI "st33zp24-spi" + +struct st33zp24_platform_data { + int io_lpcpd; +}; + +#endif /* __ST33ZP24_H__ */ diff --git a/include/linux/platform_data/tpm_stm_st33.h b/include/linux/platform_data/tpm_stm_st33.h deleted file mode 100644 index ff75310..0000000 --- a/include/linux/platform_data/tpm_stm_st33.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * STMicroelectronics TPM I2C Linux driver for TPM ST33ZP24 - * Copyright (C) 2009, 2010 STMicroelectronics - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * - * STMicroelectronics version 1.2.0, Copyright (C) 2010 - * STMicroelectronics comes with ABSOLUTELY NO WARRANTY. - * This is free software, and you are welcome to redistribute it - * under certain conditions. - * - * @Author: Christophe RICARD tpmsupport-qxv4g6HH51o@public.gmane.org - * - * @File: stm_st33_tpm.h - * - * @Date: 09/15/2010 - */ -#ifndef __STM_ST33_TPM_H__ -#define __STM_ST33_TPM_H__ - -#define TPM_ST33_I2C "st33zp24-i2c" -#define TPM_ST33_SPI "st33zp24-spi" - -struct st33zp24_platform_data { - int io_lpcpd; -}; - -#endif /* __STM_ST33_TPM_H__ */ -- 2.1.0 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 11+ messages in thread
[parent not found: <1422220293-21005-3-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>]
* Re: [PATCH v4 2/4] tpm/tpm_i2c_stm_st33: Split tpm_i2c_tpm_st33 in 2 layers (core + phy) [not found] ` <1422220293-21005-3-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org> @ 2015-01-26 23:07 ` Peter Hüwe 0 siblings, 0 replies; 11+ messages in thread From: Peter Hüwe @ 2015-01-26 23:07 UTC (permalink / raw) To: Christophe Ricard Cc: ashley-fm2HMyfA2y6tG0bUXCXiUA, tpmdd-yWjUBOtONefk1uMJSBkQmQ, tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, christophe-h.ricard-qxv4g6HH51o, jean-luc.blanc-qxv4g6HH51o, benoit.houyere-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA, jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/, jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA Hi Christophe, some superficial (and picky) reviews below - in general I like it. Peter Am Sonntag, 25. Januar 2015, 22:11:31 schrieb Christophe Ricard: > tpm_i2c_stm_st33 is a TIS 1.2 TPM with a core interface which can be used > by different phy such as i2c or spi. The core part is called st33zp24 which > is also the main part reference. > > include/linux/platform_data/tpm_stm_st33.h is renamed consequently. > The driver is also split into an i2c phy in charge of sending/receiving > data as well as managing platform data or dts configuration. > > Reviewed-by: Jason Gunthorpe <jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org> > Signed-off-by: Christophe Ricard <christophe-h.ricard-qxv4g6HH51o@public.gmane.org> > --- > drivers/char/tpm/Kconfig | 11 +- > drivers/char/tpm/Makefile | 2 +- > drivers/char/tpm/st33zp24/Kconfig | 20 + > drivers/char/tpm/st33zp24/Makefile | 9 + > drivers/char/tpm/st33zp24/i2c.c | 278 +++++++++ > drivers/char/tpm/st33zp24/st33zp24.c | 691 ++++++++++++++++++++++ > drivers/char/tpm/st33zp24/st33zp24.h | 34 ++ > drivers/char/tpm/tpm_i2c_stm_st33.c | 915 > ----------------------------- include/linux/platform_data/st33zp24.h | > 28 + > include/linux/platform_data/tpm_stm_st33.h | 39 -- > 10 files changed, 1062 insertions(+), 965 deletions(-) > create mode 100644 drivers/char/tpm/st33zp24/Kconfig > create mode 100644 drivers/char/tpm/st33zp24/Makefile > create mode 100644 drivers/char/tpm/st33zp24/i2c.c > create mode 100644 drivers/char/tpm/st33zp24/st33zp24.c > create mode 100644 drivers/char/tpm/st33zp24/st33zp24.h > delete mode 100644 drivers/char/tpm/tpm_i2c_stm_st33.c > create mode 100644 include/linux/platform_data/st33zp24.h > delete mode 100644 include/linux/platform_data/tpm_stm_st33.h > > diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig > index 9d4e375..2dc16d3 100644 > --- a/drivers/char/tpm/Kconfig > +++ b/drivers/char/tpm/Kconfig > @@ -100,16 +100,6 @@ config TCG_IBMVTPM > will be accessible from within Linux. To compile this driver > as a module, choose M here; the module will be called tpm_ibmvtpm. > > -config TCG_TIS_I2C_ST33 > - tristate "TPM Interface Specification 1.2 Interface (I2C - > STMicroelectronics)" - depends on I2C > - depends on GPIOLIB > - ---help--- > - If you have a TPM security chip from STMicroelectronics working with > - an I2C bus 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_i2c_stm_st33. > - > config TCG_XEN > tristate "XEN TPM Interface" > depends on TCG_TPM && XEN > @@ -131,4 +121,5 @@ config TCG_CRB > from within Linux. To compile this driver as a module, choose > M here; the module will be called tpm_crb. > > +source "drivers/char/tpm/st33zp24/Kconfig" > endif # TCG_TPM > diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile > index 990cf18..56e8f1f 100644 > --- a/drivers/char/tpm/Makefile > +++ b/drivers/char/tpm/Makefile > @@ -20,6 +20,6 @@ obj-$(CONFIG_TCG_NSC) += tpm_nsc.o > obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o > obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o > obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o > -obj-$(CONFIG_TCG_TIS_I2C_ST33) += tpm_i2c_stm_st33.o > +obj-$(CONFIG_TCG_TIS_ST33ZP24) += st33zp24/ > obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o > obj-$(CONFIG_TCG_CRB) += tpm_crb.o > diff --git a/drivers/char/tpm/st33zp24/Kconfig > b/drivers/char/tpm/st33zp24/Kconfig new file mode 100644 > index 0000000..51dcef5 > --- /dev/null > +++ b/drivers/char/tpm/st33zp24/Kconfig > @@ -0,0 +1,20 @@ > +config TCG_TIS_ST33ZP24 > + tristate "STMicroelectronics TPM Interface Specification 1.2 Interface" > + depends on GPIOLIB > + ---help--- > + STMicroelectronics ST33ZP24 core driver. It implements the core > + TPM1.2 logic and hooks into the TPM kernel APIs. Physical layers will > + register against it. > + > + To compile this driver as a module, choose m here. The module will be > called + tpm_st33zp24. > + > +config TCG_TIS_ST33ZP24_I2C > + tristate "TPM 1.2 ST33ZP24 I2C support" > + depends on TCG_TIS_ST33ZP24 > + depends on I2C > + ---help--- > + This module adds support for the STMicroelectronics TPM security chip > + ST33ZP24 with i2c interface. > + To compile this driver as a module, choose M here; the module will be > + called tpm_st33zp24_i2c. > diff --git a/drivers/char/tpm/st33zp24/Makefile > b/drivers/char/tpm/st33zp24/Makefile new file mode 100644 > index 0000000..414497f > --- /dev/null > +++ b/drivers/char/tpm/st33zp24/Makefile > @@ -0,0 +1,9 @@ > +# > +# Makefile for ST33ZP24 TPM 1.2 driver > +# > + > +tpm_st33zp24-objs = st33zp24.o > +obj-$(CONFIG_TCG_TIS_ST33ZP24) += tpm_st33zp24.o > + > +tpm_st33zp24_i2c-objs = i2c.o > +obj-$(CONFIG_TCG_TIS_ST33ZP24_I2C) += tpm_st33zp24_i2c.o > diff --git a/drivers/char/tpm/st33zp24/i2c.c > b/drivers/char/tpm/st33zp24/i2c.c new file mode 100644 > index 0000000..95e3091 > --- /dev/null > +++ b/drivers/char/tpm/st33zp24/i2c.c > @@ -0,0 +1,278 @@ > +/* > + * STMicroelectronics TPM I2C Linux driver for TPM ST33ZP24 > + * Copyright (C) 2009 - 2015 STMicroelectronics > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, see <http://www.gnu.org/licenses/>. > + */ > + > +#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 <linux/platform_data/st33zp24.h> > + > +#include "st33zp24.h" > + > +#define TPM_DUMMY_BYTE 0xAA > +#define TPM_WRITE_DIRECTION 0x80 Defined in i2c.c spi.c -> move to header? > +#define TPM_BUFSIZE 2048 Defined in i2c.c spi.c and st33zp24, (but not used in st33zp24.c) -> move to header? > + > +struct st33zp24_i2c_phy { > + struct i2c_client *client; > + u8 buf[TPM_BUFSIZE + 1]; > + int io_lpcpd; > +}; > + > +/* > + * write8_reg > + * Send byte to the TIS register according to the ST33ZP24 I2C protocol. > + * @param: tpm_register, the tpm tis register where the data should be > written + * @param: tpm_data, the tpm_data to write inside the > tpm_register + * @param: tpm_size, The length of the data > + * @return: Returns negative errno, or else the number of bytes written. > + */ > +static int write8_reg(void *phy_id, u8 tpm_register, u8 *tpm_data, int > tpm_size) +{ > + struct st33zp24_i2c_phy *phy = phy_id; > + > + phy->buf[0] = tpm_register; > + memcpy(phy->buf + 1, tpm_data, tpm_size); > + return i2c_master_send(phy->client, phy->buf, tpm_size + 1); > +} /* write8_reg() */ > + > +/* > + * read8_reg > + * Recv byte from the TIS register according to the ST33ZP24 I2C protocol. > + * @param: tpm_register, the tpm tis register where the data should be > read + * @param: tpm_data, the TPM response > + * @param: tpm_size, tpm TPM response size to read. > + * @return: number of byte read successfully: should be one if success. > + */ > +static int read8_reg(void *phy_id, u8 tpm_register, u8 *tpm_data, int > tpm_size) +{ > + struct st33zp24_i2c_phy *phy = phy_id; > + u8 status = 0; > + u8 data; > + > + data = TPM_DUMMY_BYTE; > + status = write8_reg(phy, tpm_register, &data, 1); > + if (status == 2) > + status = i2c_master_recv(phy->client, tpm_data, tpm_size); > + return status; > +} /* read8_reg() */ > + > +/* > + * st33zp24_i2c_send > + * Send byte to the TIS register according to the ST33ZP24 I2C protocol. > + * @param: phy_id, the phy description > + * @param: tpm_register, the tpm tis register where the data should be > written + * @param: tpm_data, the tpm_data to write inside the > tpm_register + * @param: tpm_size, the length of the data > + * @return: number of byte written successfully: should be one if success. > + */ > +static int st33zp24_i2c_send(void *phy_id, u8 tpm_register, u8 *tpm_data, > + int tpm_size) > +{ > + return write8_reg(phy_id, tpm_register | TPM_WRITE_DIRECTION, tpm_data, > + tpm_size); > +} > + > +/* > + * st33zp24_i2c_recv > + * Recv byte from the TIS register according to the ST33ZP24 I2C protocol. > + * @param: phy_id, the phy description > + * @param: tpm_register, the tpm tis register where the data should be > read + * @param: tpm_data, the TPM response > + * @param: tpm_size, tpm TPM response size to read. > + * @return: number of byte read successfully: should be one if success. > + */ > +static int st33zp24_i2c_recv(void *phy_id, u8 tpm_register, u8 *tpm_data, > + int tpm_size) > +{ > + return read8_reg(phy_id, tpm_register, tpm_data, tpm_size); > +} > + > +static const struct st33zp24_phy_ops i2c_phy_ops = { > + .send = st33zp24_i2c_send, > + .recv = st33zp24_i2c_recv, > +}; > + > +#ifdef CONFIG_OF > +static int st33zp24_i2c_of_request_resources(struct st33zp24_i2c_phy *phy) > +{ > + struct device_node *pp; > + struct i2c_client *client = phy->client; > + int gpio; > + int ret; > + > + pp = client->dev.of_node; > + if (!pp) { > + dev_err(&client->dev, "No platform data\n"); > + return -ENODEV; > + } > + > + /* Get GPIO from device tree */ > + gpio = of_get_named_gpio(pp, "lpcpd-gpios", 0); > + if (gpio < 0) { > + dev_err(&client->dev, > + "Failed to retrieve lpcpd-gpios from dts.\n"); > + phy->io_lpcpd = -1; > + /* > + * lpcpd pin is not specified. This is not an issue as > + * power management can be also managed by TPM specific > + * commands. So leave with a success status code. > + */ > + return 0; > + } > + /* GPIO request and configuration */ > + ret = devm_gpio_request_one(&client->dev, gpio, > + GPIOF_OUT_INIT_HIGH, "TPM IO LPCPD"); > + if (ret) { > + dev_err(&client->dev, "Failed to request lpcpd pin\n"); > + return -ENODEV; > + } > + phy->io_lpcpd = gpio; > + > + return 0; > +} > +#else > +static int st33zp24_i2c_of_request_resources(struct st33zp24_i2c_phy *phy) > +{ > + return -ENODEV; > +} > +#endif > + > +static int st33zp24_i2c_request_resources(struct i2c_client *client, > + struct st33zp24_i2c_phy *phy) > +{ > + struct st33zp24_platform_data *pdata; > + int ret; > + > + pdata = client->dev.platform_data; > + if (!pdata) { > + dev_err(&client->dev, "No platform data\n"); > + return -ENODEV; > + } > + > + /* store for late use */ > + phy->io_lpcpd = pdata->io_lpcpd; > + > + if (gpio_is_valid(pdata->io_lpcpd)) { > + ret = devm_gpio_request_one(&client->dev, > + pdata->io_lpcpd, GPIOF_OUT_INIT_HIGH, > + "TPM IO_LPCPD"); > + if (ret) { > + dev_err(&client->dev, "Failed to request lpcpd pin\n"); > + return ret; > + } > + } > + > + return 0; > +} > + > +/* > + * st33zp24_i2c_probe initialize the TPM device > + * @param: client, the i2c_client drescription (TPM I2C description). > + * @param: id, the i2c_device_id struct. > + * @return: 0 in case of success. > + * -1 in other case. > + */ > +static int st33zp24_i2c_probe(struct i2c_client *client, > + const struct i2c_device_id *id) > +{ > + int ret; > + struct st33zp24_platform_data *pdata; > + struct st33zp24_i2c_phy *phy; > + > + if (!client) { > + pr_info("%s: i2c client is NULL. Device not accessible.\n", > + __func__); > + return -ENODEV; > + } > + > + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { > + dev_info(&client->dev, "client not i2c capable\n"); > + return -ENODEV; > + } > + > + phy = devm_kzalloc(&client->dev, sizeof(struct st33zp24_i2c_phy), > + GFP_KERNEL); > + if (!phy) > + return -ENOMEM; > + > + phy->client = client; > + pdata = client->dev.platform_data; > + if (!pdata && client->dev.of_node) { > + ret = st33zp24_i2c_of_request_resources(phy); > + if (ret) > + return ret; > + } else if (pdata) { > + ret = st33zp24_i2c_request_resources(client, phy); > + if (ret) > + return ret; > + } > + > + return st33zp24_probe(phy, &i2c_phy_ops, &client->dev, client->irq, > + phy->io_lpcpd); > +} > + > +/* > + * st33zp24_i2c_remove remove the TPM device > + * @param: client, the i2c_client description (TPM I2C description). > + * @return: 0 in case of success. > + */ > +static int st33zp24_i2c_remove(struct i2c_client *client) > +{ > + struct tpm_chip *chip = i2c_get_clientdata(client); > + > + return st33zp24_remove(chip); > +} > + > +static const struct i2c_device_id st33zp24_i2c_id[] = { > + {TPM_ST33_I2C, 0}, > + {} > +}; > +MODULE_DEVICE_TABLE(i2c, st33zp24_i2c_id); > + > +#ifdef CONFIG_OF > +static const struct of_device_id of_st33zp24_i2c_match[] = { > + { .compatible = "st,st33zp24-i2c", }, > + {} > +}; > +MODULE_DEVICE_TABLE(of, of_st33zp24_i2c_match); > +#endif > + > +static SIMPLE_DEV_PM_OPS(st33zp24_i2c_ops, st33zp24_pm_suspend, > + st33zp24_pm_resume); > + > +static struct i2c_driver st33zp24_i2c_driver = { > + .driver = { > + .owner = THIS_MODULE, > + .name = TPM_ST33_I2C, > + .pm = &st33zp24_i2c_ops, > + .of_match_table = of_match_ptr(of_st33zp24_i2c_match), > + }, > + .probe = st33zp24_i2c_probe, > + .remove = st33zp24_i2c_remove, > + .id_table = st33zp24_i2c_id > +}; > + > +module_i2c_driver(st33zp24_i2c_driver); > + > +MODULE_AUTHOR("TPM support (TPMsupport-nkJGhpqTU55BDgjK7y7TUQ@public.gmane.org)"); > +MODULE_DESCRIPTION("STM TPM 1.2 I2C ST33 Driver"); > +MODULE_VERSION("1.3.0"); > +MODULE_LICENSE("GPL"); > diff --git a/drivers/char/tpm/st33zp24/st33zp24.c > b/drivers/char/tpm/st33zp24/st33zp24.c new file mode 100644 > index 0000000..83d2686 > --- /dev/null > +++ b/drivers/char/tpm/st33zp24/st33zp24.c > @@ -0,0 +1,691 @@ > +/* > + * STMicroelectronics TPM Linux driver for TPM ST33ZP24 > + * Copyright (C) 2009 - 2015 STMicroelectronics > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, see <http://www.gnu.org/licenses/>. > + */ > + > +#include <linux/module.h> > +#include <linux/fs.h> > +#include <linux/miscdevice.h> > +#include <linux/kernel.h> > +#include <linux/delay.h> > +#include <linux/wait.h> > +#include <linux/freezer.h> > +#include <linux/string.h> > +#include <linux/interrupt.h> > +#include <linux/gpio.h> > +#include <linux/sched.h> > +#include <linux/uaccess.h> > +#include <linux/io.h> > +#include <linux/slab.h> > + > +#include "../tpm.h" > +#include "st33zp24.h" > + > +#define DRIVER_DESC "ST33ZP24 TPM 1.2 driver" > + > +#define TPM_ACCESS 0x0 > +#define TPM_STS 0x18 > +#define TPM_DATA_FIFO 0x24 > +#define TPM_INTF_CAPABILITY 0x14 > +#define TPM_INT_STATUS 0x10 > +#define TPM_INT_ENABLE 0x08 > + > +#define TPM_HEADER_SIZE 10 already in ../tpm.h > +#define TPM_BUFSIZE 2048 used in spi.c i2c.c and st33zp24.c -> move to header? > + > +#define LOCALITY0 0 used in spi.c and st33zp24.c -> move to header? > + > +enum st33zp24_access { > + TPM_ACCESS_VALID = 0x80, > + TPM_ACCESS_ACTIVE_LOCALITY = 0x20, > + TPM_ACCESS_REQUEST_PENDING = 0x04, > + TPM_ACCESS_REQUEST_USE = 0x02, > +}; > + > +enum st33zp24_status { > + TPM_STS_VALID = 0x80, > + TPM_STS_COMMAND_READY = 0x40, > + TPM_STS_GO = 0x20, > + TPM_STS_DATA_AVAIL = 0x10, > + TPM_STS_DATA_EXPECT = 0x08, > +}; > + > +enum st33zp24_int_flags { > + TPM_GLOBAL_INT_ENABLE = 0x80, > + TPM_INTF_CMD_READY_INT = 0x080, > + TPM_INTF_FIFO_AVALAIBLE_INT = 0x040, > + TPM_INTF_WAKE_UP_READY_INT = 0x020, > + TPM_INTF_LOCALITY_CHANGE_INT = 0x004, > + TPM_INTF_STS_VALID_INT = 0x002, > + TPM_INTF_DATA_AVAIL_INT = 0x001, > +}; > + > +enum tis_defaults { > + TIS_SHORT_TIMEOUT = 750, > + TIS_LONG_TIMEOUT = 2000, > +}; > + > +struct st33zp24_dev { > + struct tpm_chip *chip; > + void *phy_id; > + const struct st33zp24_phy_ops *ops; > + u32 intrs; > + int io_lpcpd; > +}; > + > +/* > + * clear_interruption clear the pending interrupt. > + * @param: tpm_dev, the tpm device device. > + * @return: the interrupt status value. > + */ > +static u8 clear_interruption(struct st33zp24_dev *tpm_dev) > +{ > + u8 interrupt; > + > + tpm_dev->ops->recv(tpm_dev->phy_id, TPM_INT_STATUS, &interrupt, 1); > + tpm_dev->ops->send(tpm_dev->phy_id, TPM_INT_STATUS, &interrupt, 1); > + return interrupt; > +} /* clear_interruption() */ > + > +/* > + * st33zp24_cancel, cancel is not implemented. cancel is not implemented? then what does the function do? > + * @param: chip, the tpm_chip description as specified in > driver/char/tpm/tpm.h + */ > +static void st33zp24_cancel(struct tpm_chip *chip) > +{ > + struct st33zp24_dev *tpm_dev; > + u8 data; > + > + tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip); > + > + data = TPM_STS_COMMAND_READY; > + tpm_dev->ops->send(tpm_dev->phy_id, TPM_STS, &data, 1); > +} /* st33zp24_cancel() */ > + > +/* > + * st33zp24_status return the TPM_STS register > + * @param: chip, the tpm chip description > + * @return: the TPM_STS register value. > + */ > +static u8 st33zp24_status(struct tpm_chip *chip) > +{ > + struct st33zp24_dev *tpm_dev; > + u8 data; > + > + tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip); > + > + tpm_dev->ops->recv(tpm_dev->phy_id, TPM_STS, &data, 1); > + return data; > +} /* st33zp24_status() */ > + > +/* > + * check_locality if the locality is active > + * @param: chip, the tpm chip description > + * @return: the active locality or -EACCESS. > + */ > +static int check_locality(struct tpm_chip *chip) > +{ > + struct st33zp24_dev *tpm_dev; > + u8 data; > + u8 status; > + > + tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip); > + > + status = tpm_dev->ops->recv(tpm_dev->phy_id, TPM_ACCESS, &data, 1); > + if (status && (data & > + (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == > + (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) > + return chip->vendor.locality; > + > + return -EACCES; > +} /* check_locality() */ > + > +/* > + * request_locality request the TPM locality > + * @param: chip, the chip description > + * @return: the active locality or negative value. > + */ > +static int request_locality(struct tpm_chip *chip) > +{ > + unsigned long stop; > + long ret; > + struct st33zp24_dev *tpm_dev; > + u8 data; > + > + if (check_locality(chip) == chip->vendor.locality) > + return chip->vendor.locality; > + > + tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip); > + > + data = TPM_ACCESS_REQUEST_USE; > + ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_ACCESS, &data, 1); > + if (ret < 0) > + goto end; return ret; directly > + > + stop = jiffies + chip->vendor.timeout_a; > + > + /* Request locality is usually effective after the request */ > + do { > + if (check_locality(chip) >= 0) > + return chip->vendor.locality; > + msleep(TPM_TIMEOUT); > + } while (time_before(jiffies, stop)); /* could not get locality */ return -EACCES; > + ret = -EACCES; > +end: > + return ret; > +} /* request_locality() */ > + > +/* > + * release_locality release the active locality > + * @param: chip, the tpm chip description. > + */ > +static void release_locality(struct tpm_chip *chip) > +{ > + struct st33zp24_dev *tpm_dev; > + u8 data; > + > + tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip); > + data = TPM_ACCESS_ACTIVE_LOCALITY; > + > + tpm_dev->ops->send(tpm_dev->phy_id, TPM_ACCESS, &data, 1); > +} > + > +/* > + * get_burstcount return the burstcount address 0x19 0x1A return the burstcount address? > + * @param: chip, the chip description > + * return: the burstcount or negative value. > + */ > +static int get_burstcount(struct tpm_chip *chip) > +{ > + unsigned long stop; > + int burstcnt, status; > + u8 tpm_reg, temp; > + struct st33zp24_dev *tpm_dev; > + > + tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip); > + > + stop = jiffies + chip->vendor.timeout_d; > + do { > + tpm_reg = TPM_STS + 1; > + status = tpm_dev->ops->recv(tpm_dev->phy_id, tpm_reg, &temp, 1); > + if (status < 0) > + goto end; return -EBUSY; directly > + > + tpm_reg = tpm_reg + 1; TPM_STS + 2; is more readable > + burstcnt = temp; > + status = tpm_dev->ops->recv(tpm_dev->phy_id, tpm_reg, &temp, 1); > + if (status < 0) > + goto end; return -EBUSY; directly > + > + burstcnt |= temp << 8; > + if (burstcnt) > + return burstcnt; > + msleep(TPM_TIMEOUT); > + } while (time_before(jiffies, stop)); > + > +end: > + return -EBUSY; return -EBUSY; directly above > +} /* get_burstcount() */ > + > + > +/* > + * wait_for_tpm_stat_cond > + * @param: chip, chip description > + * @param: mask, expected mask value > + * @param: check_cancel, does the command expected to be canceled ? > + * @param: canceled, did we received a cancel request ? > + * @return: true if status == mask or if the command is canceled. > + * false in other cases. > + */ > +static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, > + bool check_cancel, bool *canceled) > +{ > + u8 status = chip->ops->status(chip); > + > + *canceled = false; > + if ((status & mask) == mask) > + return true; > + if (check_cancel && chip->ops->req_canceled(chip, status)) { > + *canceled = true; > + return true; > + } > + return false; > +} > + > +/* > + * wait_for_stat wait for a TPM_STS value > + * @param: chip, the tpm chip description > + * @param: mask, the value mask to wait > + * @param: timeout, the timeout > + * @param: queue, the wait queue. > + * @param: check_cancel, does the command can be cancelled ? > + * @return: the tpm status, 0 if success, -ETIME if timeout is reached. > + */ > +static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long > timeout, + wait_queue_head_t *queue, bool check_cancel) > +{ > + unsigned long stop; > + int ret; > + bool canceled = false; > + bool condition; > + u32 cur_intrs; > + u8 status; > + struct st33zp24_dev *tpm_dev; > + > + tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip); > + > + /* check current status */ > + status = st33zp24_status(chip); > + if ((status & mask) == mask) > + return 0; > + > + stop = jiffies + timeout; > + > + if (chip->vendor.irq) { > + cur_intrs = tpm_dev->intrs; > + clear_interruption(tpm_dev); > + enable_irq(chip->vendor.irq); > + > +again: > + timeout = stop - jiffies; > + if ((long) timeout <= 0) > + return -1; > + > + ret = wait_event_interruptible_timeout(*queue, > + cur_intrs != tpm_dev->intrs, timeout); > + clear_interruption(tpm_dev); > + condition = wait_for_tpm_stat_cond(chip, mask, > + check_cancel, &canceled); > + if (ret >= 0 && condition) { > + if (canceled) > + return -ECANCELED; > + return 0; > + } > + if (ret == -ERESTARTSYS && freezing(current)) { > + clear_thread_flag(TIF_SIGPENDING); > + goto again; ugh... can you please use a do_while loop or something? I usually dislike jumping to a higher location. > + } > + disable_irq_nosync(chip->vendor.irq); > + > + } else { > + do { > + msleep(TPM_TIMEOUT); > + status = chip->ops->status(chip); > + if ((status & mask) == mask) > + return 0; > + } while (time_before(jiffies, stop)); > + } > + > + return -ETIME; > +} /* wait_for_stat() */ > + > +/* > + * recv_data receive data > + * @param: chip, the tpm chip description > + * @param: buf, the buffer where the data are received > + * @param: count, the number of data to receive > + * @return: the number of bytes read from TPM FIFO. > + */ > +static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) > +{ > + int size = 0, burstcnt, len, ret; > + struct st33zp24_dev *tpm_dev; > + > + tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip); > + > + while (size < count && > + wait_for_stat(chip, > + TPM_STS_DATA_AVAIL | TPM_STS_VALID, > + chip->vendor.timeout_c, > + &chip->vendor.read_queue, true) == 0) { > + burstcnt = get_burstcount(chip); > + if (burstcnt < 0) > + return burstcnt; > + len = min_t(int, burstcnt, count - size); > + ret = tpm_dev->ops->recv(tpm_dev->phy_id, TPM_DATA_FIFO, > + buf + size, len); > + if (ret < 0) > + return ret; > + > + size += len; > + } > + return size; > +} > + > +/* > + * tpm_ioserirq_handler the serirq irq handler > + * @param: irq, the tpm chip description > + * @param: dev_id, the description of the chip > + * @return: the status of the handler. > + */ > +static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id) > +{ > + struct tpm_chip *chip = dev_id; > + struct st33zp24_dev *tpm_dev; > + > + tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip); > + > + tpm_dev->intrs++; > + wake_up_interruptible(&chip->vendor.read_queue); > + disable_irq_nosync(chip->vendor.irq); > + > + return IRQ_HANDLED; > +} /* tpm_ioserirq_handler() */ > + > +/* > + * st33zp24_send send TPM commands through the I2C bus. > + * > + * @param: chip, the tpm_chip description as specified in > driver/char/tpm/tpm.h + * @param: buf, the buffer to send. > + * @param: count, the number of bytes to send. > + * @return: In case of success the number of bytes sent. > + * In other case, a < 0 value describing the issue. > + */ > +static int st33zp24_send(struct tpm_chip *chip, unsigned char *buf, > + size_t len) > +{ > + u32 status, i, size; > + int burstcnt = 0; > + int ret; > + u8 data; > + struct st33zp24_dev *tpm_dev; > + > + if (!chip) > + return -EBUSY; > + if (len < TPM_HEADER_SIZE) > + return -EBUSY; > + > + tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip); > + > + ret = request_locality(chip); > + if (ret < 0) > + return ret; > + > + status = st33zp24_status(chip); > + if ((status & TPM_STS_COMMAND_READY) == 0) { > + st33zp24_cancel(chip); > + if (wait_for_stat > + (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b, > + &chip->vendor.read_queue, false) < 0) { > + ret = -ETIME; > + goto out_err; > + } > + } > + > + for (i = 0; i < len - 1;) { > + burstcnt = get_burstcount(chip); > + if (burstcnt < 0) > + return burstcnt; > + size = min_t(int, len - i - 1, burstcnt); > + ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_DATA_FIFO, > + buf + i, size); > + if (ret < 0) > + goto out_err; > + > + i += size; > + } > + > + status = st33zp24_status(chip); > + if ((status & TPM_STS_DATA_EXPECT) == 0) { > + ret = -EIO; > + goto out_err; > + } > + > + ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_DATA_FIFO, > + buf + len - 1, 1); > + if (ret < 0) > + goto out_err; > + > + status = st33zp24_status(chip); > + if ((status & TPM_STS_DATA_EXPECT) != 0) { > + ret = -EIO; > + goto out_err; > + } > + > + data = TPM_STS_GO; > + ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_STS, &data, 1); > + if (ret < 0) > + goto out_err; > + > + return len; > +out_err: > + st33zp24_cancel(chip); > + release_locality(chip); > + return ret; > +} > + > +/* > + * st33zp24_recv received TPM response through TPM phy. > + * @param: chip, the tpm_chip description as specified in > driver/char/tpm/tpm.h. + * @param: buf, the buffer to store datas. > + * @param: count, the number of bytes to send. > + * @return: In case of success the number of bytes received. > + * In other case, a < 0 value describing the issue. > + */ > +static int st33zp24_recv(struct tpm_chip *chip, unsigned char *buf, > + size_t count) > +{ > + int size = 0; > + int expected; > + > + if (!chip) > + return -EBUSY; > + > + if (count < TPM_HEADER_SIZE) { > + size = -EIO; > + goto out; > + } > + > + size = recv_data(chip, buf, TPM_HEADER_SIZE); > + 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) { > + 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; goto not really needed here, but can be kept. > + } > + > +out: > + st33zp24_cancel(chip); > + release_locality(chip); > + return size; > +} > + > +/* > + * st33zp24_req_canceled > + * @param: chip, the tpm_chip description as specified in > driver/char/tpm/tpm.h. + * @param: status, the TPM status. > + * @return: Does TPM ready to compute a new command ? true. > + */ > +static bool st33zp24_req_canceled(struct tpm_chip *chip, u8 status) > +{ > + return (status == TPM_STS_COMMAND_READY); > +} > + > +static const struct tpm_class_ops st33zp24_tpm = { > + .send = st33zp24_send, > + .recv = st33zp24_recv, > + .cancel = st33zp24_cancel, > + .status = st33zp24_status, > + .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, > + .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, > + .req_canceled = st33zp24_req_canceled, > +}; > + > +/* > + * st33zp24_probe initialize the TPM device > + * @param: client, the i2c_client drescription (TPM I2C description). > + * @param: id, the i2c_device_id struct. > + * @return: 0 in case of success. > + * -1 in other case. > + */ > +int st33zp24_probe(void *phy_id, const struct st33zp24_phy_ops *ops, > + struct device *dev, int irq, int io_lpcpd) > +{ > + int ret; > + u8 intmask = 0; > + struct tpm_chip *chip; > + struct st33zp24_dev *tpm_dev; > + > + chip = tpmm_chip_alloc(dev, &st33zp24_tpm); > + if (IS_ERR(chip)) > + return PTR_ERR(chip); > + > + tpm_dev = devm_kzalloc(dev, sizeof(struct st33zp24_dev), > + GFP_KERNEL); > + if (!tpm_dev) > + return -ENOMEM; > + > + TPM_VPRIV(chip) = tpm_dev; > + tpm_dev->phy_id = phy_id; > + tpm_dev->ops = ops; > + > + chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); > + chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); > + chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); > + chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); > + > + chip->vendor.locality = LOCALITY0; > + > + if (irq) { > + /* INTERRUPT Setup */ > + init_waitqueue_head(&chip->vendor.read_queue); > + tpm_dev->intrs = 0; > + > + if (request_locality(chip) != LOCALITY0) { > + ret = -ENODEV; > + goto _tpm_clean_answer; > + } > + > + clear_interruption(tpm_dev); > + ret = devm_request_irq(dev, irq, tpm_ioserirq_handler, > + IRQF_TRIGGER_HIGH, "TPM SERIRQ management", > + chip); > + if (ret < 0) { > + dev_err(&chip->dev , "TPM SERIRQ signals %d not available\n", ^ remove the blank :) > + irq); > + goto _tpm_clean_answer; > + } > + > + intmask |= TPM_INTF_CMD_READY_INT > + | TPM_INTF_STS_VALID_INT > + | TPM_INTF_DATA_AVAIL_INT; > + > + ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_INT_ENABLE, > + &intmask, 1); > + if (ret < 0) > + goto _tpm_clean_answer; > + > + intmask = TPM_GLOBAL_INT_ENABLE; > + ret = tpm_dev->ops->send(tpm_dev->phy_id, (TPM_INT_ENABLE + 3), > + &intmask, 1); > + if (ret < 0) > + goto _tpm_clean_answer; > + > + chip->vendor.irq = irq; > + > + disable_irq_nosync(chip->vendor.irq); > + > + tpm_gen_interrupt(chip); > + } > + > + tpm_get_timeouts(chip); > + tpm_do_selftest(chip); > + > + return tpm_chip_register(chip); > +_tpm_clean_answer: > + dev_info(&chip->dev, "TPM initialization fail\n"); > + return ret; > +} > +EXPORT_SYMBOL(st33zp24_probe); > + > +/* > + * st33zp24_remove remove the TPM device > + * @param: tpm_data, the tpm phy. > + * @return: 0 in case of success. > + */ > +int st33zp24_remove(struct tpm_chip *chip) > +{ > + tpm_chip_unregister(chip); > + return 0; > +} > +EXPORT_SYMBOL(st33zp24_remove); > + > +#ifdef CONFIG_PM_SLEEP > +/* > + * st33zp24_pm_suspend suspend the TPM device > + * @param: tpm_data, the tpm phy. > + * @param: mesg, the power management message. > + * @return: 0 in case of success. > + */ > +int st33zp24_pm_suspend(struct device *dev) > +{ > + struct tpm_chip *chip = dev_get_drvdata(dev); > + struct st33zp24_dev *tpm_dev; > + int ret = 0; > + > + tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip); > + > + if (gpio_is_valid(tpm_dev->io_lpcpd)) > + gpio_set_value(tpm_dev->io_lpcpd, 0); > + else > + ret = tpm_pm_suspend(dev); > + > + return ret; > +} /* st33zp24_pm_suspend() */ > +EXPORT_SYMBOL(st33zp24_pm_suspend); > + > +/* > + * st33zp24_pm_resume resume the TPM device > + * @param: tpm_data, the tpm phy. > + * @return: 0 in case of success. > + */ > +int st33zp24_pm_resume(struct device *dev) > +{ > + struct tpm_chip *chip = dev_get_drvdata(dev); > + struct st33zp24_dev *tpm_dev; > + int ret = 0; > + > + tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip); > + > + if (gpio_is_valid(tpm_dev->io_lpcpd)) { > + gpio_set_value(tpm_dev->io_lpcpd, 1); > + ret = wait_for_stat(chip, > + TPM_STS_VALID, chip->vendor.timeout_b, > + &chip->vendor.read_queue, false); > + } else { > + ret = tpm_pm_resume(dev); > + if (!ret) > + tpm_do_selftest(chip); > + } > + return ret; > +} /* st33zp24_pm_resume() */ > +EXPORT_SYMBOL(st33zp24_pm_resume); > +#endif > + > +MODULE_LICENSE("GPL"); > +MODULE_DESCRIPTION(DRIVER_DESC); Maybe also add MODULE_AUTHOR ? I'd use DRIVER_DESC directly? > diff --git a/drivers/char/tpm/st33zp24/st33zp24.h > b/drivers/char/tpm/st33zp24/st33zp24.h new file mode 100644 > index 0000000..68f77b2 > --- /dev/null > +++ b/drivers/char/tpm/st33zp24/st33zp24.h > @@ -0,0 +1,34 @@ > +/* > + * STMicroelectronics TPM Linux driver for TPM ST33ZP24 > + * Copyright (C) 2009 - 2015 STMicroelectronics > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms and conditions of the GNU General Public License, > + * version 2, as published by the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, see <http://www.gnu.org/licenses/>. > + */ > + > +#ifndef __LOCAL_ST33ZP24_H__ > +#define __LOCAL_ST33ZP24_H__ > + > +struct st33zp24_phy_ops { > + int (*send)(void *dev_id, u8 tpm_register, u8 *tpm_data, int tpm_size); > + int (*recv)(void *dev_id, u8 tpm_register, u8 *tpm_data, int tpm_size); in spi.c and i2c.c you use phy_id instead of dev_id - altough it doesn't matter to the compiler, I like consistency :) > +}; > + > +#ifdef CONFIG_PM_SLEEP > +int st33zp24_pm_suspend(struct device *dev); > +int st33zp24_pm_resume(struct device *dev); > +#endif > + > +int st33zp24_probe(void *phy_id, const struct st33zp24_phy_ops *ops, > + struct device *dev, int irq, int io_lpcpd); > +int st33zp24_remove(struct tpm_chip *chip); > +#endif /* __LOCAL_ST33ZP24_H__ */ > diff --git a/include/linux/platform_data/st33zp24.h > b/include/linux/platform_data/st33zp24.h new file mode 100644 > index 0000000..817dfdb > --- /dev/null > +++ b/include/linux/platform_data/st33zp24.h > @@ -0,0 +1,28 @@ > +/* > + * STMicroelectronics TPM Linux driver for TPM 1.2 ST33ZP24 > + * Copyright (C) 2009 - 2015 STMicroelectronics > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, see <http://www.gnu.org/licenses/>. > + */ > +#ifndef __ST33ZP24_H__ > +#define __ST33ZP24_H__ > + > +#define TPM_ST33_I2C "st33zp24-i2c" > +#define TPM_ST33_SPI "st33zp24-spi" > + > +struct st33zp24_platform_data { > + int io_lpcpd; > +}; > + > +#endif /* __ST33ZP24_H__ */ -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v4 3/4] tpm/st33zp24/spi: Add st33zp24 spi phy [not found] ` <1422220293-21005-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org> 2015-01-25 21:11 ` [PATCH v4 1/4] tpm/tpm_i2c_stm_st33: Replace access to io_lpcpd from struct st33zp24_platform_data to tpm_stm_dev Christophe Ricard 2015-01-25 21:11 ` [PATCH v4 2/4] tpm/tpm_i2c_stm_st33: Split tpm_i2c_tpm_st33 in 2 layers (core + phy) Christophe Ricard @ 2015-01-25 21:11 ` Christophe Ricard [not found] ` <1422220293-21005-4-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org> 2015-01-25 21:11 ` [PATCH v4 4/4] tpm/st33zp24/dts/st33zp24-spi: Add dts documentation for " Christophe Ricard 2015-01-26 21:39 ` [PATCH v4 0/4] st33zp24 new architecture proposal and st33zp24 spi driver Peter Hüwe 4 siblings, 1 reply; 11+ messages in thread From: Christophe Ricard @ 2015-01-25 21:11 UTC (permalink / raw) To: PeterHuewe-Mmb7MZpHnFY Cc: ashley-fm2HMyfA2y6tG0bUXCXiUA, tpmdd-yWjUBOtONefk1uMJSBkQmQ, tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, christophe-h.ricard-qxv4g6HH51o, jean-luc.blanc-qxv4g6HH51o, benoit.houyere-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA, jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/, jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA st33zp24 TIS 1.2 support also SPI. It is using a proprietary protocol to transport TIS data. Reviewed-by: Jason Gunthorpe <jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org> Signed-off-by: Christophe Ricard <christophe-h.ricard-qxv4g6HH51o@public.gmane.org> --- drivers/char/tpm/st33zp24/Kconfig | 10 + drivers/char/tpm/st33zp24/Makefile | 3 + drivers/char/tpm/st33zp24/spi.c | 386 +++++++++++++++++++++++++++++++++++++ 3 files changed, 399 insertions(+) create mode 100644 drivers/char/tpm/st33zp24/spi.c diff --git a/drivers/char/tpm/st33zp24/Kconfig b/drivers/char/tpm/st33zp24/Kconfig index 51dcef5..09cb7278 100644 --- a/drivers/char/tpm/st33zp24/Kconfig +++ b/drivers/char/tpm/st33zp24/Kconfig @@ -18,3 +18,13 @@ config TCG_TIS_ST33ZP24_I2C ST33ZP24 with i2c interface. To compile this driver as a module, choose M here; the module will be called tpm_st33zp24_i2c. + +config TCG_TIS_ST33ZP24_SPI + tristate "TPM 1.2 ST33ZP24 SPI support" + depends on TCG_TIS_ST33ZP24 + depends on SPI + ---help--- + This module adds support for the STMicroelectronics TPM security chip + ST33ZP24 with spi interface. + To compile this driver as a module, choose M here; the module will be + called tpm_st33zp24_spi. diff --git a/drivers/char/tpm/st33zp24/Makefile b/drivers/char/tpm/st33zp24/Makefile index 414497f..74a722e 100644 --- a/drivers/char/tpm/st33zp24/Makefile +++ b/drivers/char/tpm/st33zp24/Makefile @@ -7,3 +7,6 @@ obj-$(CONFIG_TCG_TIS_ST33ZP24) += tpm_st33zp24.o tpm_st33zp24_i2c-objs = i2c.o obj-$(CONFIG_TCG_TIS_ST33ZP24_I2C) += tpm_st33zp24_i2c.o + +tpm_st33zp24_spi-objs = spi.o +obj-$(CONFIG_TCG_TIS_ST33ZP24_SPI) += tpm_st33zp24_spi.o diff --git a/drivers/char/tpm/st33zp24/spi.c b/drivers/char/tpm/st33zp24/spi.c new file mode 100644 index 0000000..d481478 --- /dev/null +++ b/drivers/char/tpm/st33zp24/spi.c @@ -0,0 +1,386 @@ +/* + * STMicroelectronics TPM SPI Linux driver for TPM ST33ZP24 + * Copyright (C) 2009 - 2015 STMicroelectronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/module.h> +#include <linux/spi/spi.h> +#include <linux/gpio.h> +#include <linux/of_irq.h> +#include <linux/of_gpio.h> +#include <linux/tpm.h> +#include <linux/platform_data/st33zp24.h> + +#include "st33zp24.h" + +#define TPM_DATA_FIFO 0x24 +#define TPM_INTF_CAPABILITY 0x14 + +#define TPM_DUMMY_BYTE 0x00 +#define TPM_WRITE_DIRECTION 0x80 +#define TPM_BUFSIZE 2048 + +#define MAX_SPI_LATENCY 15 +#define LOCALITY0 0 + +#define ST33ZP24_OK 0x5A +#define ST33ZP24_UNDEFINED_ERR 0x80 +#define ST33ZP24_BADLOCALITY 0x81 +#define ST33ZP24_TISREGISTER_UKNOWN 0x82 +#define ST33ZP24_LOCALITY_NOT_ACTIVATED 0x83 +#define ST33ZP24_HASH_END_BEFORE_HASH_START 0x84 +#define ST33ZP24_BAD_COMMAND_ORDER 0x85 +#define ST33ZP24_INCORECT_RECEIVED_LENGTH 0x86 +#define ST33ZP24_TPM_FIFO_OVERFLOW 0x89 +#define ST33ZP24_UNEXPECTED_READ_FIFO 0x8A +#define ST33ZP24_UNEXPECTED_WRITE_FIFO 0x8B +#define ST33ZP24_CMDRDY_SET_WHEN_PROCESSING_HASH_END 0x90 +#define ST33ZP24_DUMMY_BYTES 0x00 + +struct st33zp24_spi_phy { + struct spi_device *spi_device; + struct spi_transfer spi_xfer; + int io_lpcpd; + int latency; +}; + +static int st33zp24_status_to_errno(u8 code) +{ + switch (code) { + case ST33ZP24_OK: + return 0; + case ST33ZP24_UNDEFINED_ERR: + case ST33ZP24_BADLOCALITY: + case ST33ZP24_TISREGISTER_UKNOWN: + case ST33ZP24_LOCALITY_NOT_ACTIVATED: + case ST33ZP24_HASH_END_BEFORE_HASH_START: + case ST33ZP24_BAD_COMMAND_ORDER: + case ST33ZP24_UNEXPECTED_READ_FIFO: + case ST33ZP24_UNEXPECTED_WRITE_FIFO: + case ST33ZP24_CMDRDY_SET_WHEN_PROCESSING_HASH_END: + return -EPROTO; + case ST33ZP24_INCORECT_RECEIVED_LENGTH: + case ST33ZP24_TPM_FIFO_OVERFLOW: + return -EMSGSIZE; + case ST33ZP24_DUMMY_BYTES: + default: + return -ENOSYS; + } +} + +/* + * st33zp24_spi_send + * Send byte to the TIS register according to the ST33ZP24 SPI protocol. + * @param: tpm, the chip description + * @param: tpm_register, the tpm tis register where the data should be written + * @param: tpm_data, the tpm_data to write inside the tpm_register + * @param: tpm_size, The length of the data + * @return: should be zero if success else a negative error code. + */ +static int st33zp24_spi_send(void *phy_id, u8 tpm_register, u8 *tpm_data, + int tpm_size) +{ + u8 data = 0; + int total_length = 0, nbr_dummy_bytes = 0, ret = 0; + struct st33zp24_spi_phy *phy = phy_id; + struct spi_device *dev = phy->spi_device; + u8 *tx_buf = (u8 *)phy->spi_xfer.tx_buf; + u8 *rx_buf = phy->spi_xfer.rx_buf; + + /* Pre-Header */ + data = TPM_WRITE_DIRECTION | LOCALITY0; + memcpy(tx_buf + total_length, &data, sizeof(data)); + total_length++; + data = tpm_register; + memcpy(tx_buf + total_length, &data, sizeof(data)); + total_length++; + + if (tpm_size > 0 && tpm_register == TPM_DATA_FIFO) { + tx_buf[total_length++] = tpm_size >> 8; + tx_buf[total_length++] = tpm_size; + } + + memcpy(&tx_buf[total_length], tpm_data, tpm_size); + total_length += tpm_size; + + nbr_dummy_bytes = phy->latency; + memset(&tx_buf[total_length], TPM_DUMMY_BYTE, nbr_dummy_bytes); + + phy->spi_xfer.len = total_length + nbr_dummy_bytes; + + ret = spi_sync_transfer(dev, &phy->spi_xfer, 1); + + if (ret == 0) + ret = rx_buf[total_length + nbr_dummy_bytes - 1]; + + return st33zp24_status_to_errno(ret); +} /* st33zp24_spi_send() */ + +/* + * read8_recv + * Recv byte from the TIS register according to the ST33ZP24 SPI protocol. + * @param: tpm, the chip description + * @param: tpm_register, the tpm tis register where the data should be read + * @param: tpm_data, the TPM response + * @param: tpm_size, tpm TPM response size to read. + * @return: should be zero if success else a negative error code. + */ +static int read8_reg(void *phy_id, u8 tpm_register, u8 *tpm_data, int tpm_size) +{ + u8 data = 0; + int total_length = 0, nbr_dummy_bytes, ret; + struct st33zp24_spi_phy *phy = phy_id; + struct spi_device *dev = phy->spi_device; + u8 *tx_buf = (u8 *)phy->spi_xfer.tx_buf; + u8 *rx_buf = phy->spi_xfer.rx_buf; + + /* Pre-Header */ + data = LOCALITY0; + memcpy(tx_buf + total_length, &data, sizeof(data)); + total_length++; + data = tpm_register; + memcpy(tx_buf + total_length, &data, sizeof(data)); + total_length++; + + nbr_dummy_bytes = phy->latency; + memset(&tx_buf[total_length], TPM_DUMMY_BYTE, + nbr_dummy_bytes + tpm_size); + + phy->spi_xfer.len = total_length + nbr_dummy_bytes + tpm_size; + + /* header + status byte + size of the data + status byte */ + ret = spi_sync_transfer(dev, &phy->spi_xfer, 1); + if (tpm_size > 0 && ret == 0) { + ret = rx_buf[total_length + nbr_dummy_bytes - 1]; + + memcpy(tpm_data, rx_buf + total_length + nbr_dummy_bytes, + tpm_size); + } + + return ret; +} /* read8_reg() */ + +/* + * st33zp24_spi_recv + * Recv byte from the TIS register according to the ST33ZP24 SPI protocol. + * @param: tpm, the chip description + * @param: tpm_register, the tpm tis register where the data should be read + * @param: tpm_data, the TPM response + * @param: tpm_size, tpm TPM response size to read. + * @return: number of byte written successfully: should be one if success. + */ +static int st33zp24_spi_recv(void *phy_id, u8 tpm_register, u8 *tpm_data, + int tpm_size) +{ + int ret; + + ret = read8_reg(phy_id, tpm_register, tpm_data, tpm_size); + if (!ret) + return tpm_size; + return ret; +} /* st33zp24_spi_recv() */ + +static int evaluate_latency(void *phy_id) +{ + struct st33zp24_spi_phy *phy = phy_id; + int latency = 1, status = 0; + u8 data = 0; + + while (!status && latency < MAX_SPI_LATENCY) { + phy->latency = latency; + status = read8_reg(phy_id, TPM_INTF_CAPABILITY, &data, 1); + latency++; + } + return latency - 1; +} /* evaluate_latency() */ + +static const struct st33zp24_phy_ops spi_phy_ops = { + .send = st33zp24_spi_send, + .recv = st33zp24_spi_recv, +}; + +#ifdef CONFIG_OF +static int tpm_stm_spi_of_request_resources(struct st33zp24_spi_phy *phy) +{ + struct device_node *pp; + struct spi_device *dev = phy->spi_device; + int gpio; + int ret; + + pp = dev->dev.of_node; + if (!pp) { + dev_err(&dev->dev, "No platform data\n"); + return -ENODEV; + } + + /* Get GPIO from device tree */ + gpio = of_get_named_gpio(pp, "lpcpd-gpios", 0); + if (gpio < 0) { + dev_err(&dev->dev, + "Failed to retrieve lpcpd-gpios from dts.\n"); + phy->io_lpcpd = -1; + /* + * lpcpd pin is not specified. This is not an issue as + * power management can be also managed by TPM specific + * commands. So leave with a success status code. + */ + return 0; + } + /* GPIO request and configuration */ + ret = devm_gpio_request_one(&dev->dev, gpio, + GPIOF_OUT_INIT_HIGH, "TPM IO LPCPD"); + if (ret) { + dev_err(&dev->dev, "Failed to request lpcpd pin\n"); + return -ENODEV; + } + phy->io_lpcpd = gpio; + + return 0; +} +#else +static int tpm_stm_spi_of_request_resources(struct st33zp24_spi_phy *phy) +{ + return -ENODEV; +} +#endif + +static int tpm_stm_spi_request_resources(struct spi_device *dev, + struct st33zp24_spi_phy *phy) +{ + struct st33zp24_platform_data *pdata; + int ret; + + pdata = dev->dev.platform_data; + if (!pdata) { + dev_err(&dev->dev, "No platform data\n"); + return -ENODEV; + } + + /* store for late use */ + phy->io_lpcpd = pdata->io_lpcpd; + + if (gpio_is_valid(pdata->io_lpcpd)) { + ret = devm_gpio_request_one(&dev->dev, + pdata->io_lpcpd, GPIOF_OUT_INIT_HIGH, + "TPM IO_LPCPD"); + if (ret) { + dev_err(&dev->dev, "%s : reset gpio_request failed\n", + __FILE__); + return ret; + } + } + + return 0; +} + +/* + * tpm_st33_spi_probe initialize the TPM device + * @param: client, the spi_device drescription (TPM SPI description). + * @param: id, the spi_device_id struct. + * @return: 0 in case of success. + * -1 in other case. + */ +static int +tpm_st33_spi_probe(struct spi_device *dev) +{ + int ret; + struct st33zp24_platform_data *pdata; + struct st33zp24_spi_phy *phy; + + /* Check SPI platform functionnalities */ + if (!dev) { + pr_info("%s: dev is NULL. Device is not accessible.\n", + __func__); + return -ENODEV; + } + + phy = devm_kzalloc(&dev->dev, sizeof(struct st33zp24_spi_phy), + GFP_KERNEL); + if (!phy) + return -ENOMEM; + + phy->spi_device = dev; + pdata = dev->dev.platform_data; + if (!pdata && dev->dev.of_node) { + ret = tpm_stm_spi_of_request_resources(phy); + if (ret) + return ret; + } else if (pdata) { + ret = tpm_stm_spi_request_resources(dev, phy); + if (ret) + return ret; + } + + phy->spi_xfer.tx_buf = devm_kmalloc(&dev->dev, (TPM_BUFSIZE + + (TPM_BUFSIZE / 2) + TPM_DIGEST_SIZE) * + sizeof(u8), GFP_KERNEL); + if (!phy->spi_xfer.tx_buf) + return -ENOMEM; + + phy->spi_xfer.rx_buf = devm_kmalloc(&dev->dev, (TPM_BUFSIZE + + (TPM_BUFSIZE / 2) + TPM_DIGEST_SIZE) * + sizeof(u8), GFP_KERNEL); + if (!phy->spi_xfer.rx_buf) + return -ENOMEM; + + phy->latency = evaluate_latency(phy); + if (phy->latency <= 0) + return -ENODEV; + + return st33zp24_probe(phy, &spi_phy_ops, &dev->dev, dev->irq, + phy->io_lpcpd); +} + +/* + * tpm_st33_spi_remove remove the TPM device + * @param: client, the spi_device drescription (TPM SPI description). + * @return: 0 in case of success. + */ +static int tpm_st33_spi_remove(struct spi_device *dev) +{ + struct tpm_chip *chip = spi_get_drvdata(dev); + + return st33zp24_remove(chip); +} + +#ifdef CONFIG_OF +static const struct of_device_id of_st33zp24_spi_match[] = { + { .compatible = "st,st33zp24-spi", }, + {} +}; +MODULE_DEVICE_TABLE(of, of_st33zp24_spi_match); +#endif + +static SIMPLE_DEV_PM_OPS(st33zp24_spi_ops, st33zp24_pm_suspend, + st33zp24_pm_resume); + +static struct spi_driver tpm_st33_spi_driver = { + .driver = { + .owner = THIS_MODULE, + .name = TPM_ST33_SPI, + .pm = &st33zp24_spi_ops, + .of_match_table = of_match_ptr(of_st33zp24_spi_match), + }, + .probe = tpm_st33_spi_probe, + .remove = tpm_st33_spi_remove, +}; + +module_spi_driver(tpm_st33_spi_driver); + +MODULE_AUTHOR("TPM support (TPMsupport-nkJGhpqTU55BDgjK7y7TUQ@public.gmane.org)"); +MODULE_DESCRIPTION("STM TPM 1.2 SPI ST33 Driver"); +MODULE_VERSION("1.3.0"); +MODULE_LICENSE("GPL"); -- 2.1.0 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 11+ messages in thread
[parent not found: <1422220293-21005-4-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>]
* Re: [PATCH v4 3/4] tpm/st33zp24/spi: Add st33zp24 spi phy [not found] ` <1422220293-21005-4-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org> @ 2015-01-26 23:28 ` Peter Hüwe 0 siblings, 0 replies; 11+ messages in thread From: Peter Hüwe @ 2015-01-26 23:28 UTC (permalink / raw) To: Christophe Ricard Cc: ashley-fm2HMyfA2y6tG0bUXCXiUA, tpmdd-yWjUBOtONefk1uMJSBkQmQ, tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, christophe-h.ricard-qxv4g6HH51o, jean-luc.blanc-qxv4g6HH51o, benoit.houyere-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA, jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/, jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA Am Sonntag, 25. Januar 2015, 22:11:32 schrieb Christophe Ricard: > st33zp24 TIS 1.2 support also SPI. It is using a proprietary protocol to > transport TIS data. > > Reviewed-by: Jason Gunthorpe <jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org> > Signed-off-by: Christophe Ricard <christophe-h.ricard-qxv4g6HH51o@public.gmane.org> > --- > drivers/char/tpm/st33zp24/Kconfig | 10 + > drivers/char/tpm/st33zp24/Makefile | 3 + > drivers/char/tpm/st33zp24/spi.c | 386 > +++++++++++++++++++++++++++++++++++++ 3 files changed, 399 insertions(+) > create mode 100644 drivers/char/tpm/st33zp24/spi.c > > diff --git a/drivers/char/tpm/st33zp24/Kconfig > b/drivers/char/tpm/st33zp24/Kconfig index 51dcef5..09cb7278 100644 > --- a/drivers/char/tpm/st33zp24/Kconfig > +++ b/drivers/char/tpm/st33zp24/Kconfig > @@ -18,3 +18,13 @@ config TCG_TIS_ST33ZP24_I2C > ST33ZP24 with i2c interface. > To compile this driver as a module, choose M here; the module will be > called tpm_st33zp24_i2c. > + > +config TCG_TIS_ST33ZP24_SPI > + tristate "TPM 1.2 ST33ZP24 SPI support" > + depends on TCG_TIS_ST33ZP24 > + depends on SPI > + ---help--- > + This module adds support for the STMicroelectronics TPM security chip > + ST33ZP24 with spi interface. > + To compile this driver as a module, choose M here; the module will be > + called tpm_st33zp24_spi. > diff --git a/drivers/char/tpm/st33zp24/Makefile > b/drivers/char/tpm/st33zp24/Makefile index 414497f..74a722e 100644 > --- a/drivers/char/tpm/st33zp24/Makefile > +++ b/drivers/char/tpm/st33zp24/Makefile > @@ -7,3 +7,6 @@ obj-$(CONFIG_TCG_TIS_ST33ZP24) += tpm_st33zp24.o > > tpm_st33zp24_i2c-objs = i2c.o > obj-$(CONFIG_TCG_TIS_ST33ZP24_I2C) += tpm_st33zp24_i2c.o > + > +tpm_st33zp24_spi-objs = spi.o > +obj-$(CONFIG_TCG_TIS_ST33ZP24_SPI) += tpm_st33zp24_spi.o > diff --git a/drivers/char/tpm/st33zp24/spi.c > b/drivers/char/tpm/st33zp24/spi.c new file mode 100644 > index 0000000..d481478 > --- /dev/null > +++ b/drivers/char/tpm/st33zp24/spi.c > @@ -0,0 +1,386 @@ > +/* > + * STMicroelectronics TPM SPI Linux driver for TPM ST33ZP24 > + * Copyright (C) 2009 - 2015 STMicroelectronics > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, see <http://www.gnu.org/licenses/>. > + */ > + > +#include <linux/module.h> > +#include <linux/spi/spi.h> > +#include <linux/gpio.h> > +#include <linux/of_irq.h> > +#include <linux/of_gpio.h> > +#include <linux/tpm.h> > +#include <linux/platform_data/st33zp24.h> > + > +#include "st33zp24.h" > + > +#define TPM_DATA_FIFO 0x24 > +#define TPM_INTF_CAPABILITY 0x14 > + > +#define TPM_DUMMY_BYTE 0x00 > +#define TPM_WRITE_DIRECTION 0x80 > +#define TPM_BUFSIZE 2048 see previous email :) > + > +#define MAX_SPI_LATENCY 15 > +#define LOCALITY0 0 > + > +#define ST33ZP24_OK 0x5A > +#define ST33ZP24_UNDEFINED_ERR 0x80 > +#define ST33ZP24_BADLOCALITY 0x81 > +#define ST33ZP24_TISREGISTER_UKNOWN 0x82 > +#define ST33ZP24_LOCALITY_NOT_ACTIVATED 0x83 > +#define ST33ZP24_HASH_END_BEFORE_HASH_START 0x84 > +#define ST33ZP24_BAD_COMMAND_ORDER 0x85 > +#define ST33ZP24_INCORECT_RECEIVED_LENGTH 0x86 > +#define ST33ZP24_TPM_FIFO_OVERFLOW 0x89 > +#define ST33ZP24_UNEXPECTED_READ_FIFO 0x8A > +#define ST33ZP24_UNEXPECTED_WRITE_FIFO 0x8B > +#define ST33ZP24_CMDRDY_SET_WHEN_PROCESSING_HASH_END 0x90 > +#define ST33ZP24_DUMMY_BYTES 0x00 > + > +struct st33zp24_spi_phy { > + struct spi_device *spi_device; > + struct spi_transfer spi_xfer; > + int io_lpcpd; > + int latency; > +}; > + > +static int st33zp24_status_to_errno(u8 code) > +{ > + switch (code) { > + case ST33ZP24_OK: > + return 0; > + case ST33ZP24_UNDEFINED_ERR: > + case ST33ZP24_BADLOCALITY: > + case ST33ZP24_TISREGISTER_UKNOWN: > + case ST33ZP24_LOCALITY_NOT_ACTIVATED: > + case ST33ZP24_HASH_END_BEFORE_HASH_START: > + case ST33ZP24_BAD_COMMAND_ORDER: > + case ST33ZP24_UNEXPECTED_READ_FIFO: > + case ST33ZP24_UNEXPECTED_WRITE_FIFO: > + case ST33ZP24_CMDRDY_SET_WHEN_PROCESSING_HASH_END: > + return -EPROTO; > + case ST33ZP24_INCORECT_RECEIVED_LENGTH: > + case ST33ZP24_TPM_FIFO_OVERFLOW: > + return -EMSGSIZE; > + case ST33ZP24_DUMMY_BYTES: > + default: > + return -ENOSYS; > + } > +} > + > +/* > + * st33zp24_spi_send > + * Send byte to the TIS register according to the ST33ZP24 SPI protocol. > + * @param: tpm, the chip description no such parameter :) > + * @param: tpm_register, the tpm tis register where the data should be > written + * @param: tpm_data, the tpm_data to write inside the > tpm_register + * @param: tpm_size, The length of the data > + * @return: should be zero if success else a negative error code. > + */ > +static int st33zp24_spi_send(void *phy_id, u8 tpm_register, u8 *tpm_data, > + int tpm_size) > +{ > + u8 data = 0; > + int total_length = 0, nbr_dummy_bytes = 0, ret = 0; > + struct st33zp24_spi_phy *phy = phy_id; > + struct spi_device *dev = phy->spi_device; > + u8 *tx_buf = (u8 *)phy->spi_xfer.tx_buf; > + u8 *rx_buf = phy->spi_xfer.rx_buf; > + > + /* Pre-Header */ > + data = TPM_WRITE_DIRECTION | LOCALITY0; > + memcpy(tx_buf + total_length, &data, sizeof(data)); > + total_length++; > + data = tpm_register; > + memcpy(tx_buf + total_length, &data, sizeof(data)); > + total_length++; > + > + if (tpm_size > 0 && tpm_register == TPM_DATA_FIFO) { > + tx_buf[total_length++] = tpm_size >> 8; > + tx_buf[total_length++] = tpm_size; > + } > + > + memcpy(&tx_buf[total_length], tpm_data, tpm_size); > + total_length += tpm_size; > + > + nbr_dummy_bytes = phy->latency; > + memset(&tx_buf[total_length], TPM_DUMMY_BYTE, nbr_dummy_bytes); > + > + phy->spi_xfer.len = total_length + nbr_dummy_bytes; > + > + ret = spi_sync_transfer(dev, &phy->spi_xfer, 1); > + > + if (ret == 0) > + ret = rx_buf[total_length + nbr_dummy_bytes - 1]; > + > + return st33zp24_status_to_errno(ret); > +} /* st33zp24_spi_send() */ > + > +/* > + * read8_recv > + * Recv byte from the TIS register according to the ST33ZP24 SPI protocol. > + * @param: tpm, the chip description no such parameter :) > + * @param: tpm_register, the tpm tis register where the data should be > read + * @param: tpm_data, the TPM response > + * @param: tpm_size, tpm TPM response size to read. > + * @return: should be zero if success else a negative error code. > + */ > +static int read8_reg(void *phy_id, u8 tpm_register, u8 *tpm_data, int > tpm_size) +{ > + u8 data = 0; > + int total_length = 0, nbr_dummy_bytes, ret; > + struct st33zp24_spi_phy *phy = phy_id; > + struct spi_device *dev = phy->spi_device; > + u8 *tx_buf = (u8 *)phy->spi_xfer.tx_buf; > + u8 *rx_buf = phy->spi_xfer.rx_buf; > + > + /* Pre-Header */ > + data = LOCALITY0; > + memcpy(tx_buf + total_length, &data, sizeof(data)); > + total_length++; > + data = tpm_register; > + memcpy(tx_buf + total_length, &data, sizeof(data)); > + total_length++; > + > + nbr_dummy_bytes = phy->latency; > + memset(&tx_buf[total_length], TPM_DUMMY_BYTE, > + nbr_dummy_bytes + tpm_size); > + > + phy->spi_xfer.len = total_length + nbr_dummy_bytes + tpm_size; > + > + /* header + status byte + size of the data + status byte */ > + ret = spi_sync_transfer(dev, &phy->spi_xfer, 1); > + if (tpm_size > 0 && ret == 0) { > + ret = rx_buf[total_length + nbr_dummy_bytes - 1]; > + > + memcpy(tpm_data, rx_buf + total_length + nbr_dummy_bytes, > + tpm_size); > + } > + > + return ret; > +} /* read8_reg() */ > + > +/* > + * st33zp24_spi_recv > + * Recv byte from the TIS register according to the ST33ZP24 SPI protocol. > + * @param: tpm, the chip description no such parameter :) > + * @param: tpm_register, the tpm tis register where the data should be > read + * @param: tpm_data, the TPM response > + * @param: tpm_size, tpm TPM response size to read. > + * @return: number of byte written successfully: should be one if success. s ^^^^^^^ written on recv? > + */ > +static int st33zp24_spi_recv(void *phy_id, u8 tpm_register, u8 *tpm_data, > + int tpm_size) > +{ > + int ret; > + > + ret = read8_reg(phy_id, tpm_register, tpm_data, tpm_size); > + if (!ret) > + return tpm_size; > + return ret; > +} /* st33zp24_spi_recv() */ > + > +static int evaluate_latency(void *phy_id) > +{ > + struct st33zp24_spi_phy *phy = phy_id; > + int latency = 1, status = 0; > + u8 data = 0; > + > + while (!status && latency < MAX_SPI_LATENCY) { > + phy->latency = latency; > + status = read8_reg(phy_id, TPM_INTF_CAPABILITY, &data, 1); > + latency++; > + } > + return latency - 1; why start at 1 and then deduce -1 at the end? > +} /* evaluate_latency() */ > + > +static const struct st33zp24_phy_ops spi_phy_ops = { > + .send = st33zp24_spi_send, > + .recv = st33zp24_spi_recv, > +}; > + > +#ifdef CONFIG_OF > +static int tpm_stm_spi_of_request_resources(struct st33zp24_spi_phy *phy) > +{ > + struct device_node *pp; > + struct spi_device *dev = phy->spi_device; > + int gpio; > + int ret; > + > + pp = dev->dev.of_node; > + if (!pp) { > + dev_err(&dev->dev, "No platform data\n"); > + return -ENODEV; > + } > + > + /* Get GPIO from device tree */ > + gpio = of_get_named_gpio(pp, "lpcpd-gpios", 0); > + if (gpio < 0) { > + dev_err(&dev->dev, > + "Failed to retrieve lpcpd-gpios from dts.\n"); > + phy->io_lpcpd = -1; > + /* > + * lpcpd pin is not specified. This is not an issue as > + * power management can be also managed by TPM specific > + * commands. So leave with a success status code. > + */ > + return 0; > + } > + /* GPIO request and configuration */ > + ret = devm_gpio_request_one(&dev->dev, gpio, > + GPIOF_OUT_INIT_HIGH, "TPM IO LPCPD"); > + if (ret) { > + dev_err(&dev->dev, "Failed to request lpcpd pin\n"); > + return -ENODEV; > + } > + phy->io_lpcpd = gpio; > + > + return 0; > +} > +#else > +static int tpm_stm_spi_of_request_resources(struct st33zp24_spi_phy *phy) > +{ > + return -ENODEV; > +} > +#endif > + > +static int tpm_stm_spi_request_resources(struct spi_device *dev, > + struct st33zp24_spi_phy *phy) > +{ > + struct st33zp24_platform_data *pdata; > + int ret; > + > + pdata = dev->dev.platform_data; > + if (!pdata) { > + dev_err(&dev->dev, "No platform data\n"); > + return -ENODEV; > + } > + > + /* store for late use */ > + phy->io_lpcpd = pdata->io_lpcpd; > + > + if (gpio_is_valid(pdata->io_lpcpd)) { > + ret = devm_gpio_request_one(&dev->dev, > + pdata->io_lpcpd, GPIOF_OUT_INIT_HIGH, > + "TPM IO_LPCPD"); > + if (ret) { > + dev_err(&dev->dev, "%s : reset gpio_request failed\n", > + __FILE__); > + return ret; > + } > + } > + > + return 0; > +} > + > +/* > + * tpm_st33_spi_probe initialize the TPM device > + * @param: client, the spi_device drescription (TPM SPI description). > + * @param: id, the spi_device_id struct. the params don't match the function below so again no such parameters :) > + * @return: 0 in case of success. > + * -1 in other case. is this true? I guess not. > + */ > +static int > +tpm_st33_spi_probe(struct spi_device *dev) > +{ > + int ret; > + struct st33zp24_platform_data *pdata; > + struct st33zp24_spi_phy *phy; > + > + /* Check SPI platform functionnalities */ > + if (!dev) { > + pr_info("%s: dev is NULL. Device is not accessible.\n", > + __func__); > + return -ENODEV; > + } > + > + phy = devm_kzalloc(&dev->dev, sizeof(struct st33zp24_spi_phy), > + GFP_KERNEL); > + if (!phy) > + return -ENOMEM; > + > + phy->spi_device = dev; > + pdata = dev->dev.platform_data; > + if (!pdata && dev->dev.of_node) { > + ret = tpm_stm_spi_of_request_resources(phy); > + if (ret) > + return ret; > + } else if (pdata) { > + ret = tpm_stm_spi_request_resources(dev, phy); > + if (ret) > + return ret; > + } > + > + phy->spi_xfer.tx_buf = devm_kmalloc(&dev->dev, (TPM_BUFSIZE + > + (TPM_BUFSIZE / 2) + TPM_DIGEST_SIZE) * I don't get this calculation, why is this bugger so big? > + sizeof(u8), GFP_KERNEL); sizeof(u8) can be removed. > + if (!phy->spi_xfer.tx_buf) > + return -ENOMEM; > + > + phy->spi_xfer.rx_buf = devm_kmalloc(&dev->dev, (TPM_BUFSIZE + > + (TPM_BUFSIZE / 2) + TPM_DIGEST_SIZE) * I don't get this calculation. > + sizeof(u8), GFP_KERNEL); sizeof(u8) can be removed. > + if (!phy->spi_xfer.rx_buf) > + return -ENOMEM; > + > + phy->latency = evaluate_latency(phy); > + if (phy->latency <= 0) > + return -ENODEV; > + > + return st33zp24_probe(phy, &spi_phy_ops, &dev->dev, dev->irq, > + phy->io_lpcpd); > +} > + > +/* > + * tpm_st33_spi_remove remove the TPM device > + * @param: client, the spi_device drescription (TPM SPI description). > + * @return: 0 in case of success. > + */ > +static int tpm_st33_spi_remove(struct spi_device *dev) > +{ > + struct tpm_chip *chip = spi_get_drvdata(dev); > + > + return st33zp24_remove(chip); > +} > + > +#ifdef CONFIG_OF > +static const struct of_device_id of_st33zp24_spi_match[] = { > + { .compatible = "st,st33zp24-spi", }, > + {} > +}; > +MODULE_DEVICE_TABLE(of, of_st33zp24_spi_match); > +#endif > + > +static SIMPLE_DEV_PM_OPS(st33zp24_spi_ops, st33zp24_pm_suspend, > + st33zp24_pm_resume); > + > +static struct spi_driver tpm_st33_spi_driver = { > + .driver = { > + .owner = THIS_MODULE, > + .name = TPM_ST33_SPI, > + .pm = &st33zp24_spi_ops, > + .of_match_table = of_match_ptr(of_st33zp24_spi_match), > + }, > + .probe = tpm_st33_spi_probe, > + .remove = tpm_st33_spi_remove, > +}; > + > +module_spi_driver(tpm_st33_spi_driver); > + > +MODULE_AUTHOR("TPM support (TPMsupport-nkJGhpqTU55BDgjK7y7TUQ@public.gmane.org)"); > +MODULE_DESCRIPTION("STM TPM 1.2 SPI ST33 Driver"); > +MODULE_VERSION("1.3.0"); > +MODULE_LICENSE("GPL"); -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v4 4/4] tpm/st33zp24/dts/st33zp24-spi: Add dts documentation for st33zp24 spi phy [not found] ` <1422220293-21005-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org> ` (2 preceding siblings ...) 2015-01-25 21:11 ` [PATCH v4 3/4] tpm/st33zp24/spi: Add st33zp24 spi phy Christophe Ricard @ 2015-01-25 21:11 ` Christophe Ricard 2015-01-26 21:39 ` [PATCH v4 0/4] st33zp24 new architecture proposal and st33zp24 spi driver Peter Hüwe 4 siblings, 0 replies; 11+ messages in thread From: Christophe Ricard @ 2015-01-25 21:11 UTC (permalink / raw) To: PeterHuewe-Mmb7MZpHnFY Cc: ashley-fm2HMyfA2y6tG0bUXCXiUA, tpmdd-yWjUBOtONefk1uMJSBkQmQ, tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, christophe-h.ricard-qxv4g6HH51o, jean-luc.blanc-qxv4g6HH51o, benoit.houyere-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA, jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/, jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA Reviewed-by: Jason Gunthorpe <jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org> Signed-off-by: Christophe Ricard <christophe-h.ricard-qxv4g6HH51o@public.gmane.org> --- .../bindings/security/tpm/st33zp24-spi.txt | 34 ++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 Documentation/devicetree/bindings/security/tpm/st33zp24-spi.txt diff --git a/Documentation/devicetree/bindings/security/tpm/st33zp24-spi.txt b/Documentation/devicetree/bindings/security/tpm/st33zp24-spi.txt new file mode 100644 index 0000000..158b016 --- /dev/null +++ b/Documentation/devicetree/bindings/security/tpm/st33zp24-spi.txt @@ -0,0 +1,34 @@ +* STMicroelectronics SAS. ST33ZP24 TPM SoC + +Required properties: +- compatible: Should be "st,st33zp24-spi". +- spi-max-frequency: Maximum SPI frequency (<= 10000000). + +Optional ST33ZP24 Properties: +- interrupt-parent: phandle for the interrupt gpio controller +- interrupts: GPIO interrupt to which the chip is connected +- lpcpd-gpios: Output GPIO pin used for ST33ZP24 power management D1/D2 state. +If set, power must be present when the platform is going into sleep/hibernate mode. + +Optional SoC Specific Properties: +- pinctrl-names: Contains only one value - "default". +- pintctrl-0: Specifies the pin control groups used for this controller. + +Example (for ARM-based BeagleBoard xM with ST33ZP24 on SPI4): + +&mcspi4 { + + status = "okay"; + + st33zp24@0 { + + compatible = "st,st33zp24-spi"; + + spi-max-frequency = <10000000>; + + interrupt-parent = <&gpio5>; + interrupts = <7 IRQ_TYPE_LEVEL_HIGH>; + + lpcpd-gpios = <&gpio5 15 GPIO_ACTIVE_HIGH>; + }; +}; -- 2.1.0 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v4 0/4] st33zp24 new architecture proposal and st33zp24 spi driver [not found] ` <1422220293-21005-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org> ` (3 preceding siblings ...) 2015-01-25 21:11 ` [PATCH v4 4/4] tpm/st33zp24/dts/st33zp24-spi: Add dts documentation for " Christophe Ricard @ 2015-01-26 21:39 ` Peter Hüwe [not found] ` <201501262239.25303.PeterHuewe-Mmb7MZpHnFY@public.gmane.org> 4 siblings, 1 reply; 11+ messages in thread From: Peter Hüwe @ 2015-01-26 21:39 UTC (permalink / raw) To: Christophe Ricard Cc: ashley-fm2HMyfA2y6tG0bUXCXiUA, tpmdd-yWjUBOtONefk1uMJSBkQmQ, tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, christophe-h.ricard-qxv4g6HH51o, jean-luc.blanc-qxv4g6HH51o, benoit.houyere-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA, jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/, jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA Hi Christophe, Am Sonntag, 25. Januar 2015, 22:11:29 schrieb Christophe Ricard: > Hi, > > The following patchset: > - propose a new architecture allowing to share a core st33zp24 data > management layer with different phy (i2c & spi). For st33zp24 both phy > have a proprietary transport protocol. Both are relying on the TCG TIS > protocol. At the end, it simplifies the maintenance. - Add an spi phy > allowing to support st33zp24 using with an SPI bus. > > The complete solution got tested in polling and interrupt mode successfully > with i2c & spi phy. This patchset applies on top of Peter's tree > https://github.com/PeterHuewe/linux-tpmdd.git for-james branch on top of: > d4989d9f693b9502f9288da5db279c2f8c2e50be tpm/tpm_tis: Add missing ifdef > CONFIG_ACPI for pnp_acpi_device > > I confirm also Jarkko Sakkinen's changes are working with this product with > both phy's. > > - v2 takes into account feedbacks from Jason Gunthorpe. > - v3 is reduced to 4 patches as 6 out of 10 got accepted for 3.20. Also > compare to v2: * Fix build issue with patch v2 04/10 "Replace access to > io_lpcpd from struct st33zp24_platform_data to tpm_stm_dev" * Fix link > issue with patch v2 08/10 "Split tpm_i2c_tpm_st33 in 2 layers (core + > phy)" when building as a module. The symbols wasn't exported in > st33zp24.c. > * Add missing MODULE_LICENSE in patch v2 09/10 "Add st33zp24 spi > phy" * Fix node example in dts spi documentation in patch v2 10/10 "Add > dts documentation for st33zp24 spi phy" * Fix typo on Jason Gunthorpe > first name. Sorry for that :(... * Change contact email address as > tpmsupport-qxv4g6HH51o@public.gmane.org is no more valid - v4 adds missing module_license in > st33zp24 I'll review the stuff (since I cannot test :) during the next few days. Meanwhile I added to my 'staging tree' https://github.com/PeterHuewe/linux-tpmdd/tree/testing-and-review I doubt that James will accept it for 3.20. Thanks, Peter -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 11+ messages in thread
[parent not found: <201501262239.25303.PeterHuewe-Mmb7MZpHnFY@public.gmane.org>]
* Re: [PATCH v4 0/4] st33zp24 new architecture proposal and st33zp24 spi driver [not found] ` <201501262239.25303.PeterHuewe-Mmb7MZpHnFY@public.gmane.org> @ 2015-01-26 22:11 ` christophe.ricard 0 siblings, 0 replies; 11+ messages in thread From: christophe.ricard @ 2015-01-26 22:11 UTC (permalink / raw) To: Peter Hüwe Cc: ashley-fm2HMyfA2y6tG0bUXCXiUA, tpmdd-yWjUBOtONefk1uMJSBkQmQ, tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, christophe-h.ricard-qxv4g6HH51o, jean-luc.blanc-qxv4g6HH51o, benoit.houyere-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA, jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/, jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA Hi Peter, Thanks for your time. I think it will be fine to wait for kernel 3.21. Best Regards Christophe On 26/01/2015 22:39, Peter Hüwe wrote: > Hi Christophe, > > Am Sonntag, 25. Januar 2015, 22:11:29 schrieb Christophe Ricard: >> Hi, >> >> The following patchset: >> - propose a new architecture allowing to share a core st33zp24 data >> management layer with different phy (i2c & spi). For st33zp24 both phy >> have a proprietary transport protocol. Both are relying on the TCG TIS >> protocol. At the end, it simplifies the maintenance. - Add an spi phy >> allowing to support st33zp24 using with an SPI bus. >> >> The complete solution got tested in polling and interrupt mode successfully >> with i2c & spi phy. This patchset applies on top of Peter's tree >> https://github.com/PeterHuewe/linux-tpmdd.git for-james branch on top of: >> d4989d9f693b9502f9288da5db279c2f8c2e50be tpm/tpm_tis: Add missing ifdef >> CONFIG_ACPI for pnp_acpi_device >> >> I confirm also Jarkko Sakkinen's changes are working with this product with >> both phy's. >> >> - v2 takes into account feedbacks from Jason Gunthorpe. >> - v3 is reduced to 4 patches as 6 out of 10 got accepted for 3.20. Also >> compare to v2: * Fix build issue with patch v2 04/10 "Replace access to >> io_lpcpd from struct st33zp24_platform_data to tpm_stm_dev" * Fix link >> issue with patch v2 08/10 "Split tpm_i2c_tpm_st33 in 2 layers (core + >> phy)" when building as a module. The symbols wasn't exported in >> st33zp24.c. >> * Add missing MODULE_LICENSE in patch v2 09/10 "Add st33zp24 spi >> phy" * Fix node example in dts spi documentation in patch v2 10/10 "Add >> dts documentation for st33zp24 spi phy" * Fix typo on Jason Gunthorpe >> first name. Sorry for that :(... * Change contact email address as >> tpmsupport-qxv4g6HH51o@public.gmane.org is no more valid - v4 adds missing module_license in >> st33zp24 > I'll review the stuff (since I cannot test :) during the next few days. > Meanwhile I added to my 'staging tree' > https://github.com/PeterHuewe/linux-tpmdd/tree/testing-and-review > > I doubt that James will accept it for 3.20. > > Thanks, > Peter -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2015-01-26 23:28 UTC | newest] Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2015-01-25 21:11 [PATCH v4 0/4] st33zp24 new architecture proposal and st33zp24 spi driver Christophe Ricard [not found] ` <1422220293-21005-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org> 2015-01-25 21:11 ` [PATCH v4 1/4] tpm/tpm_i2c_stm_st33: Replace access to io_lpcpd from struct st33zp24_platform_data to tpm_stm_dev Christophe Ricard [not found] ` <1422220293-21005-2-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org> 2015-01-26 22:15 ` Peter Hüwe [not found] ` <201501262315.07543.PeterHuewe-Mmb7MZpHnFY@public.gmane.org> 2015-01-26 22:18 ` christophe.ricard 2015-01-25 21:11 ` [PATCH v4 2/4] tpm/tpm_i2c_stm_st33: Split tpm_i2c_tpm_st33 in 2 layers (core + phy) Christophe Ricard [not found] ` <1422220293-21005-3-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org> 2015-01-26 23:07 ` Peter Hüwe 2015-01-25 21:11 ` [PATCH v4 3/4] tpm/st33zp24/spi: Add st33zp24 spi phy Christophe Ricard [not found] ` <1422220293-21005-4-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org> 2015-01-26 23:28 ` Peter Hüwe 2015-01-25 21:11 ` [PATCH v4 4/4] tpm/st33zp24/dts/st33zp24-spi: Add dts documentation for " Christophe Ricard 2015-01-26 21:39 ` [PATCH v4 0/4] st33zp24 new architecture proposal and st33zp24 spi driver Peter Hüwe [not found] ` <201501262239.25303.PeterHuewe-Mmb7MZpHnFY@public.gmane.org> 2015-01-26 22:11 ` christophe.ricard
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.