Skip to contentSkip to conversation

tpm: support PPC64 hardware

PATCH In review Kylene Jo Hall 3 participants 3 messages Oct 31, 2005 – Nov 1, 2005

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 tpm: support PPC64 hardware

The TPM is discovered differently on PPC64 because the device must be discovered through the device tree in order to open the proper holes in the io_page_mask for reading and writing in the low memory space. This does not happen automatically like most devices because the tpm is not a normal pci device and lives under the root node.

This patch contains the necessary changes to the tpm logic.

This depends on patches submitted by Jake Moilanen (10/28) to allow for the opening of holes in the io_page_mask for this device.

---

drivers/char/tpm/tpm_atmel.c +21 -42
diff -uprN --exclude='*.ko' --exclude='*.o' --exclude='.*' --exclude='*mod*' linux-2.6.14-rc4/drivers/char/tpm/tpm_atmel.c linux-2.6.14-rc4-tpm/drivers/char/tpm/tpm_atmel.c
@@ -20,10 +20,5 @@
  */
 
 #include "tpm.h"
- 
-/* Atmel definitions */
-enum tpm_atmel_addr {
-	TPM_ATMEL_BASE_ADDR_LO = 0x08,
-	TPM_ATMEL_BASE_ADDR_HI = 0x09
-};
+#include "tpm_atmel.h"
 
@@ -165,7 +166,7 @@ static void __devexit tpm_atml_remove(st
 {
 	struct tpm_chip *chip = dev_get_drvdata(dev);
 	if (chip) {
-		release_region(chip->vendor->base, 2);
+		atmel_release_region(chip->vendor->base, 2);
 		tpm_remove_hardware(chip->dev);
 	}
 }
@@ -181,59 +182,54 @@ static struct device_driver atml_drv = {
 static int __init init_atmel(void)
 {
 	int rc = 0;
-	int lo, hi;
 
+	if ( atmel_verify_tpm11() != 0 )
+		return -ENODEV;
+
 	driver_register(&atml_drv);
 
-	lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO);
-	hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI);
-
-	tpm_atmel.base = (hi<<8)|lo;
-
-	/* verify that it is an Atmel part */
-	if (tpm_read_index(TPM_ADDR, 4) != 'A' || tpm_read_index(TPM_ADDR, 5) != 'T'
-	    || tpm_read_index(TPM_ADDR, 6) != 'M' || tpm_read_index(TPM_ADDR, 7) != 'L') {
-		return -ENODEV;
+	tpm_atmel.base = atmel_get_base_addr(TPM_ADDR, 2);
+	if (tpm_atmel.base == 0) {
+		rc = -ENODEV;
+		goto err_unreg_drv;
 	}
 
-	/* verify chip version number is 1.1 */
-	if (	(tpm_read_index(TPM_ADDR, 0x00) != 0x01) ||
-		(tpm_read_index(TPM_ADDR, 0x01) != 0x01 ))
-		return -ENODEV;
-	
 	pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL);
-	if ( !pdev ) 
-		return -ENOMEM;
+	if ( !pdev ) {
+		rc = -ENOMEM; 
+		goto err_unreg_drv;
+	}
 
 	pdev->name = "tpm_atmel0";
 	pdev->id = -1;
 	pdev->num_resources = 0;
-	pdev->dev.release = tpm_atml_remove;	
+	pdev->dev.release = tpm_atml_remove;
 	pdev->dev.driver = &atml_drv;
 
-	if ((rc = platform_device_register(pdev)) < 0) {
-		kfree(pdev);
-		pdev = NULL;
-		return rc;
-	}
+	if ((rc = platform_device_register(pdev)) < 0) 
+		goto err_free_dev;
 
-	if (request_region(tpm_atmel.base, 2, "tpm_atmel0") == NULL ) {
-		platform_device_unregister(pdev);
-		kfree(pdev);
-		pdev = NULL;
-		return -EBUSY;
+	if (atmel_request_region(tpm_atmel.base, 2, "tpm_atmel0") == NULL ) {
+		rc = -EBUSY;
+		goto err_unreg_dev;
 	}
 
-	if ((rc = tpm_register_hardware(&pdev->dev, &tpm_atmel)) < 0) {
-		release_region(tpm_atmel.base, 2);
-		platform_device_unregister(pdev);
-		kfree(pdev);
-		pdev = NULL;
-		return rc;
-	}
+	if ((rc = tpm_register_hardware(&pdev->dev, &tpm_atmel)) < 0) 
+		goto err_rel_reg;
 
	dev_info(&pdev->dev, "Atmel TPM 1.1, Base Address: 0x%x\n",
			tpm_atmel.base);

return 0;
+
+err_rel_reg:
+ atmel_release_region(tpm_atmel.base, 2);
+err_unreg_dev:
+ platform_device_unregister(pdev);
+err_free_dev:
+ kfree(pdev);
+ pdev = NULL;
+err_unreg_drv:
+ driver_unregister(&atml_drv);
+ return rc;
}

static void __exit cleanup_atmel(void)

drivers/char/tpm/tpm_atmel.h +137 -0

137 lines not on this page · raw message

#1 lore raw
Quoted 10 lines · Kylene Jo Hall

The TPM is discovered differently on PPC64 because the device must be discovered through the device tree in order to open the proper holes in the io_page_mask for reading and writing in the low memory space. This does not happen automatically like most devices because the tpm is not a normal pci device and lives under the root node.

This patch contains the necessary changes to the tpm logic.

This depends on patches submitted by Jake Moilanen (10/28) to allow for the opening of holes in the io_page_mask for this device.

Please submit to the appropriate list ([email protected]). There are some issues with that patch. One, I intend to get rid of the io_page_mask, so that part at least is gone. I don't like the exporting of io_base_phys neither, it's an ugly hack.

Other comments inline.

drivers/char/tpm/tpm_atmel.h line 36

Quoted 8 lines
drivers/char/tpm/tpm_atmel.h +8 -0
+/* Verify this is a 1.1 Atmel TPM */
+static int atmel_verify_tpm11(void)
+{
+	struct device_node * dn;
+	char *compat;
+	int compat_len;
+
+	dn = find_devices("tpm");

find_devices() is a deprecated interface. Use the of_find_node_* series and do an of_node_put() once done.

drivers/char/tpm/tpm_atmel.h line 47

Quoted 10 lines
drivers/char/tpm/tpm_atmel.h +10 -0
+	if (!dn)
+		return 1;
+
+	compat = (char *) get_property(dn, "compatible", &compat_len);
+	if (!compat)
+		return 1;
+
+	if ( strcmp( compat,"AT97SC3201_r") == 0 )
+		return 0;
+

Testing the "compatible" property this way is bogus. Use device_is_compatible(). Or better, use of_find_compatible_node() which allows you to find by type & compatible in one step.

Review

Quoted 1 line
(quoted diff) +1 -0
+	dn = find_devices("tpm");

Same comment as above. In addition, why do you have to do it twice ? You should rethink your changes. Only one "probe" should be needed that retreives the base addresses.

Quoted 5 lines
drivers/char/tpm/tpm_atmel.h +5 -0
+	if (!dn)
+		return 0;
+
+	reg = (unsigned int *) get_property(dn, "reg", &reglen);
+	naddrc = prom_n_addr_cells(dn);

drivers/char/tpm/tpm_atmel.h line 79

Quoted 10 lines
drivers/char/tpm/tpm_atmel.h +10 -0
+	nsizec = prom_n_size_cells(dn);
+
+	for (i = 0; i < reglen; i = i + naddrc + nsizec) {
+
+		if (naddrc == 2)
+			address = ((unsigned long)reg[i] << 32) | reg[i+1];
+		else
+			address = reg[i];
+
+		address = address - pci_io_base_phys;

That is bogosity. Your address is an ISA IO address, It should be relative to the parent LPC bus and thus useable as is. It looks like the firmware folks crapped the device-tree. Please check that with them.

If they decide to stick with a broken device-tree, then you'll have to consider the address as an MMIO address. That mean you'll have to change the IO accesses of the TPM driver to use the iomap API thus making it immune of IO cs. MMIO distinction.

drivers/char/tpm/tpm_atmel.h line 90

Quoted 1 line
drivers/char/tpm/tpm_atmel.h +1 -0
+		allow_isa_address(address, address+size-1);

That is going away.

Ben.

#2 lore raw
In reply to Kylene Jo Hall
Quoted 5 lines · Kylene Jo Hall

The TPM is discovered differently on PPC64 because the device must be discovered through the device tree in order to open the proper holes in the io_page_mask for reading and writing in the low memory space. This does not happen automatically like most devices because the tpm is not a normal pci device and lives under the root node.

Please just do an ioremap on the physical address and use read[bwl]/write[bwl] or ioread{8,16,32}/iowrite{8,16,32}, or else persuade the firmware developers to put the tpm in the right place in the device tree.

Thanks,
Paul.