AnsweredAssumed Answered

Initialization of iMX8M ECSPI2 TPM 2.0 device Infineon SLB9670 failed when running TPM self test

Question asked by Alex Soo on May 16, 2019
Latest reply on May 24, 2019 by Alex Soo

Hi,

 

I am trying to enable a TPM 2.0 device (Infineon SLB9670XQ2.0)  which is connected to the ECSPI2 bus of an IMX8MQ processor, and when booting up the target board, I encountered an issue that the initialization of the TPM device failed with the below error messages:

tpm_tis_spi spi1.0: 2.0 TPM (device-id 0x1B, rev-id 16)

2.0 TPM (device-id 0x1B, rev-id 16)

tpm tpm0: A TPM error (256) occurred attempting to generate an interrupt

tpm tpm0: [Firmware Bug]: TPM interrupt not working, polling instead

tpm tpm0: A TPM error (256) occurred continue selftest

tpm tpm0: starting up the TPM manually

tpm tpm0: tpm_transmit: tpm_recv: error -5

tpm tpm0: TPM self test failed

tpm_tis_spi: probe of spi1.0 failed with error -5

  

The TPM self test failed because the TPM device is not able to generate an interrupt. Display of kernel debugging messages shows that, prior to the TPM self test, the TPM driver failed to set the Global Interrupt Enable bit on the TPM Interrupt Enable register to 1.

 

To find out why the driver can’t write to a TPM register, we tried to monitor the SPI Slave Select GPIO pin on oscilloscope during the SPI data transfer (interrupt-driven PIO, not DMA) to/from the TPM device, we observed that the Slave Select pin can be pulled Low during data transfer and set to High when data transfer is completed, and therefore we believe the SS pin is not hindering the data transfer, and afterwards, when we proceed to monitor the SPI clock pin, we observed that there is no clock signal comes out from the pin at all, as a result, we suspect that the failure to write to a TPM register is due to no SPI clock signal to the TPM device during data transfer.

 

When investigating why there is no SPI clock signal generated for the TPM device, we noticed that the clock enable function tpm_tis_clkrun_enable()in the TPM TIS driver (kernel version 4.14.78) supports only LPC bus on Intel platform but not the ECSPI bus on NXP IMX8M platform. It looks like the current TPM TIS driver is missing the implementation to support the enable/disable of clock signals from ECSPI bus to the TPM device during data transfer. Below is the code of function tpm_tis_clkrun_enable(),

 

static void tpm_tis_clkrun_enable(struct tpm_chip *chip, bool value)

{

        struct tpm_tis_data *data = dev_get_drvdata(&chip->dev);

        u32 clkrun_val;

 

        if (!IS_ENABLED(CONFIG_X86) || !is_bsw() ||

            !data->ilb_base_addr)

                return;

 

        if (value) {

                data->clkrun_enabled++;

                if (data->clkrun_enabled > 1)

                        return;

                clkrun_val = ioread32(data->ilb_base_addr + LPC_CNTRL_OFFSET);

 

                /* Disable LPC CLKRUN# */

                clkrun_val &= ~LPC_CLKRUN_EN;

                iowrite32(clkrun_val, data->ilb_base_addr + LPC_CNTRL_OFFSET);

 

                /*

                 * Write any random value on port 0x80 which is on LPC, to make

                 * sure LPC clock is running before sending any TPM command.

                 */

                outb(0xCC, 0x80);

        } else {

                data->clkrun_enabled--;

                if (data->clkrun_enabled)

                        return;

 

                clkrun_val = ioread32(data->ilb_base_addr + LPC_CNTRL_OFFSET);

 

                /* Enable LPC CLKRUN# */

                clkrun_val |= LPC_CLKRUN_EN;

                iowrite32(clkrun_val, data->ilb_base_addr + LPC_CNTRL_OFFSET);

 

                /*

                 * Write any random value on port 0x80 which is on LPC, to make

                 * sure LPC clock is running before sending any TPM command.

                 */

                outb(0xCC, 0x80);

        }

}

 

The schematic of IMX8M ECSPI2 pin interface:

 

 

 

 The schematic of TPM device interface to the IMX8M ECSPI2:

 

 

 The ECSPI2 configurations in the device tree file is as shown below:

 

pinctrl_ecspi2: ecspi2grp {

        fsl,pins = <

                MX8MQ_IOMUXC_ECSPI2_MOSI_ECSPI2_MOSI    0x19

                MX8MQ_IOMUXC_ECSPI2_MISO_ECSPI2_MISO    0x19

                MX8MQ_IOMUXC_ECSPI2_SCLK_ECSPI2_SCLK    0x19

                MX8MQ_IOMUXC_NAND_CE1_B_GPIO3_IO2       0x19

                MX8MQ_IOMUXC_NAND_CE2_B_GPIO3_IO3       0x17059

        >;

};

 

pinctrl_ecspi2_cs: ecspi2cs {

        fsl,pins = <

//              MX8MQ_IOMUXC_ECSPI2_SS0_ECSPI2_SS0      0x82

                MX8MQ_IOMUXC_ECSPI2_SS0_GPIO5_IO13      0x19

        >;

};

 

&ecspi2 {

        #address-cells = <1>;

        #size-cells = <0>;

        fsl,spi-num-chipselects = <1>;

        cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;

//      cs-gpios = <0>;

        pinctrl-names = "default";

        pinctrl-0 = <&pinctrl_ecspi2 &pinctrl_ecspi2_cs>;

        dmas = <&sdma1 3 7 0>, <&sdma1 4 7 0>;

        dma-names = "rx", "tx";

        status = "okay";

 

        tpm0: slb9670@0 {

                compatible = "infineon,slb9670";

                reg = <0>;

                resets = <&tpm_reset>;

                spi-max-frequency = <38000000>;

                interrupt-parent = <&gpio3>;

                interrupts = <3 IRQ_TYPE_LEVEL_LOW>;

                status = "okay";

        };

};

 

Really appreciate if someone can help point out what could have done wrong or can provide any solution or patch to this problem.

Outcomes