Skip to contentSkip to conversation

dm: pci: tegra: Convert Tegra PCI to driver model

PATCH Superseded Simon Glass 2 participants 13 messages Nov 14, 2015 – Nov 16, 2015

Subsystems (5)

v4 of 5 Superseded Latest is v5 →

lore
Share & tools
lore
#0 lore raw

v4 cover dm: pci: tegra: Convert Tegra PCI to driver model

This series converts all Tegra boards to use driver model for PCI. The net effect should be no change in functionality.

A few additional features are added to make this possible:
- Helper functions to support accessing 8- and 16-bit values within a 32-bit word
- Fixing a build error for CONFIG_CMD_PCI_ENUM
- Decoding the PCI ranges property such that configuration ranges are ignored
- Supporting bus-master devices on boards where RAM does not start at 0

This series is tested on beaver. It is available at u-boot-dm/tegra-working.

Changes in v4:
- Fix Kconig typo in commit message
- Drop CONFIG_CMD_PCI_ENUM for p2371-2180 also
- Fix merge conflict resolution error in v3
- Add compatible string for T210 (from Stephen Warren)

Changes in v3:
- Rebase onto tegra/master
- Enable DM_PCI for Tegra 210 family too

Changes in v2:
- Update commit message to explain that the feature is not important
- Drop the feature from tegra boards
- Rename 'addr' to 'size'
- Correct logic for use of gd->pci_ram_top
- Update commit message to mention future work
- Use the device_is_on_pci_bus() API
- Leave pci_skip_dev() at the bottom of the file to reduce the diff size

Simon Glass (8):
dm: tegra: pci: Move CONFIG_PCI_TEGRA to Kconfig
dm: pci: Avoid a driver model build error with CONFIG_CMD_PCI_ENUM
dm: pci: Set up the SDRAM mapping correctly
dm: pci: Support decoding ranges with duplicate entries
dm: pci: Add functions to emulate 8- and 16-bit access
dm: pci: Add a function to get the controller for a bus
dm: pci: Add a function to find the regions for a PCI bus
dm: tegra: pci: Convert tegra boards to driver model for PCI

 arch/arm/mach-tegra/Kconfig  |   2 +
 common/cmd_pci.c             |   4 +
 configs/apalis_t30_defconfig |   1 +
 configs/beaver_defconfig     |   1 +
 configs/cardhu_defconfig     |   1 +
 configs/jetson-tk1_defconfig |   1 +
 configs/p2371-2180_defconfig |   1 +
 configs/trimslice_defconfig  |   1 +
 drivers/pci/Kconfig          |  10 +
 drivers/pci/pci-uclass.c     | 105 +++++++++-
 drivers/pci/pci_tegra.c      | 467 ++++++++++++++-----------------------------
 include/configs/apalis_t30.h |   2 -
 include/configs/beaver.h     |   2 -
 include/configs/cardhu.h     |   2 -
 include/configs/jetson-tk1.h |   2 -
 include/configs/p2371-2180.h |   2 -
 include/configs/trimslice.h  |   2 -
 include/fdtdec.h             |   4 -
 include/pci.h                |  51 +++++
 lib/fdtdec.c                 |   4 -
 20 files changed, 319 insertions(+), 346 deletions(-)
Signature · 1 line
2.6.0.rc2.230.g3dd15c0
#1 lore raw

PATCH v4 1/8 dm: tegra: pci: Move CONFIG_PCI_TEGRA to Kconfig

Move this option to Kconfig and fix up all users.

---

Changes in v4:
- Fix Kconig typo in commit message

Changes in v3: None
Changes in v2: None

 configs/apalis_t30_defconfig |  1 +
 configs/beaver_defconfig     |  1 +
 configs/cardhu_defconfig     |  1 +
 configs/jetson-tk1_defconfig |  1 +
 configs/p2371-2180_defconfig |  1 +
 configs/trimslice_defconfig  |  1 +
 drivers/pci/Kconfig          | 10 ++++++++++
 include/configs/apalis_t30.h |  1 -
 include/configs/beaver.h     |  1 -
 include/configs/cardhu.h     |  1 -
 include/configs/jetson-tk1.h |  1 -
 include/configs/p2371-2180.h |  1 -
 include/configs/trimslice.h  |  1 -
 13 files changed, 16 insertions(+), 6 deletions(-)
configs/apalis_t30_defconfig +1 -0
index 8971d29..871dc43 100644
@@ -12,6 +12,7 @@ CONFIG_SYS_PROMPT="Apalis T30 # "
 # CONFIG_CMD_NFS is not set
 CONFIG_NETDEVICES=y
 CONFIG_E1000=y
+CONFIG_PCI_TEGRA=y
 CONFIG_USB=y
 CONFIG_DM_USB=y
 CONFIG_USE_PRIVATE_LIBGCC=y
configs/beaver_defconfig +1 -0
index 4a6f6e4..dfc9adf 100644
@@ -12,6 +12,7 @@ CONFIG_SYS_PROMPT="Tegra30 (Beaver) # "
 # CONFIG_CMD_SETEXPR is not set
 # CONFIG_CMD_NFS is not set
 CONFIG_SPI_FLASH=y
+CONFIG_PCI_TEGRA=y
 CONFIG_USB=y
 CONFIG_DM_USB=y
 CONFIG_USE_PRIVATE_LIBGCC=y
configs/cardhu_defconfig +1 -0
index 722bbeb..9e4a123 100644
@@ -12,6 +12,7 @@ CONFIG_SYS_PROMPT="Tegra30 (Cardhu) # "
 # CONFIG_CMD_SETEXPR is not set
 # CONFIG_CMD_NFS is not set
 CONFIG_SPI_FLASH=y
+CONFIG_PCI_TEGRA=y
 CONFIG_USB=y
 CONFIG_DM_USB=y
 CONFIG_USE_PRIVATE_LIBGCC=y
configs/jetson-tk1_defconfig +1 -0
index 6df5c7e..7b1992b 100644
@@ -12,6 +12,7 @@ CONFIG_SYS_PROMPT="Tegra124 (Jetson TK1) # "
 # CONFIG_CMD_SETEXPR is not set
 # CONFIG_CMD_NFS is not set
 CONFIG_SPI_FLASH=y
+CONFIG_PCI_TEGRA=y
 CONFIG_TEGRA114_SPI=y
 CONFIG_USB=y
 CONFIG_DM_USB=y
configs/p2371-2180_defconfig +1 -0
index 8cd2fcc..4c37cdc 100644
@@ -12,5 +12,6 @@ CONFIG_SYS_PROMPT="Tegra210 (P2371-2180) # "
 # CONFIG_CMD_NFS is not set
 CONFIG_SPI_FLASH=y
 CONFIG_TEGRA114_SPI=y
+CONFIG_PCI_TEGRA=y
 CONFIG_USB=y
 CONFIG_DM_USB=y
configs/trimslice_defconfig +1 -0
index 18292e2..08e1b62 100644
@@ -12,6 +12,7 @@ CONFIG_SYS_PROMPT="Tegra20 (TrimSlice) # "
 # CONFIG_CMD_SETEXPR is not set
 # CONFIG_CMD_NFS is not set
 CONFIG_SPI_FLASH=y
+CONFIG_PCI_TEGRA=y
 CONFIG_USB=y
 CONFIG_DM_USB=y
 CONFIG_USE_PRIVATE_LIBGCC=y
drivers/pci/Kconfig +10 -0
index 167d405..c219c19 100644
@@ -19,4 +19,14 @@ config PCI_SANDBOX
 	  the device tree but the normal PCI scan technique is used to find
 	  then.
 
+config PCI_TEGRA
+	bool "Tegra PCI support"
+	depends on TEGRA
+	help
+	  Enable support for the PCIe controller found on some generations of
+	  Tegra. Tegra20 has 2 root ports with a total of 4 lanes, Tegra30 has
+	  3 root ports with a total of 6 lanes and Tegra124 has 2 root ports
+	  with a total of 5 lanes. Some boards require this for Ethernet
+	  support to work (e.g. beaver, jetson-tk1).
+
 endmenu
include/configs/apalis_t30.h +0 -1
index fe1ef9d..7552a80 100644
@@ -49,7 +49,6 @@
 
 /* PCI host support */
 #define CONFIG_PCI
-#define CONFIG_PCI_TEGRA
 #define CONFIG_PCI_PNP
 #define CONFIG_CMD_PCI
 #define CONFIG_CMD_PCI_ENUM
include/configs/beaver.h +0 -1
index 1790f60..9e8dcf3f7 100644
@@ -73,7 +73,6 @@
 
 /* PCI host support */
 #define CONFIG_PCI
-#define CONFIG_PCI_TEGRA
 #define CONFIG_PCI_PNP
 #define CONFIG_CMD_PCI
 #define CONFIG_CMD_PCI_ENUM
include/configs/cardhu.h +0 -1
index ce6b158..174bb48 100644
@@ -75,7 +75,6 @@
 
 /* PCI host support */
 #define CONFIG_PCI
-#define CONFIG_PCI_TEGRA
 #define CONFIG_PCI_PNP
 #define CONFIG_CMD_PCI
 #define CONFIG_CMD_PCI_ENUM
include/configs/jetson-tk1.h +0 -1
index f63957a..08cf563 100644
@@ -59,7 +59,6 @@
 
 /* PCI host support */
 #define CONFIG_PCI
-#define CONFIG_PCI_TEGRA
 #define CONFIG_PCI_PNP
 #define CONFIG_CMD_PCI
 #define CONFIG_CMD_PCI_ENUM
include/configs/p2371-2180.h +0 -1
index 94f8085..56b169f 100644
@@ -55,7 +55,6 @@
 
 /* PCI host support */
 #define CONFIG_PCI
-#define CONFIG_PCI_TEGRA
 #define CONFIG_PCI_PNP
 #define CONFIG_CMD_PCI
 #define CONFIG_CMD_PCI_ENUM
include/configs/trimslice.h +0 -1
index 2ab5511..bdf1bd4 100644
@@ -58,7 +58,6 @@
 
 /* PCI host support */
 #define CONFIG_PCI
-#define CONFIG_PCI_TEGRA
 #define CONFIG_PCI_PNP
 #define CONFIG_CMD_PCI
 #define CONFIG_CMD_PCI_ENUM
Signature · 1 line
2.6.0.rc2.230.g3dd15c0
#2 lore raw

PATCH v4 2/8 dm: pci: Avoid a driver model build error with CONFIG_CMD_PCI_ENUM

In reply to Simon Glass

This is not supported with driver model, so print a message instead of generating a build error. Rescanning PCI is not yet implemented.

This function will be implemented later once some additional PCI driver model improvements are merged. It was confirmed on the mailing list that no one on the tegra side will miss this feature, so it is disabled for tegra.

---

Changes in v4:
- Drop CONFIG_CMD_PCI_ENUM for p2371-2180 also

Changes in v3: None
Changes in v2:
- Update commit message to explain that the feature is not important
- Drop the feature from tegra boards

 common/cmd_pci.c             | 4 ++++
 include/configs/apalis_t30.h | 1 -
 include/configs/beaver.h     | 1 -
 include/configs/cardhu.h     | 1 -
 include/configs/jetson-tk1.h | 1 -
 include/configs/p2371-2180.h | 1 -
 include/configs/trimslice.h  | 1 -
 7 files changed, 4 insertions(+), 6 deletions(-)
common/cmd_pci.c +4 -0
index dcecef8..69c5332 100644
@@ -457,7 +457,11 @@ static int do_pci(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		return pci_cfg_display(bdf, addr, size, value);
 #ifdef CONFIG_CMD_PCI_ENUM
 	case 'e':
+# ifdef CONFIG_DM_PCI
+		printf("This command is not yet supported with driver model\n");
+# else
 		pci_init();
+# endif
 		return 0;
 #endif
 	case 'n':		/* next */
include/configs/apalis_t30.h +0 -1
index 7552a80..e1eb700 100644
@@ -51,7 +51,6 @@
 #define CONFIG_PCI
 #define CONFIG_PCI_PNP
 #define CONFIG_CMD_PCI
-#define CONFIG_CMD_PCI_ENUM
 
 /* PCI networking support */
 #define CONFIG_E1000_NO_NVM
include/configs/beaver.h +0 -1
index 9e8dcf3f7..a2c9622 100644
@@ -75,7 +75,6 @@
 #define CONFIG_PCI
 #define CONFIG_PCI_PNP
 #define CONFIG_CMD_PCI
-#define CONFIG_CMD_PCI_ENUM
 
 /* PCI networking support */
 #define CONFIG_RTL8169
include/configs/cardhu.h +0 -1
index 174bb48..0d857bb 100644
@@ -77,7 +77,6 @@
 #define CONFIG_PCI
 #define CONFIG_PCI_PNP
 #define CONFIG_CMD_PCI
-#define CONFIG_CMD_PCI_ENUM
 
 /* PCI networking support */
 #define CONFIG_RTL8169
include/configs/jetson-tk1.h +0 -1
index 08cf563..5da360f 100644
@@ -61,7 +61,6 @@
 #define CONFIG_PCI
 #define CONFIG_PCI_PNP
 #define CONFIG_CMD_PCI
-#define CONFIG_CMD_PCI_ENUM
 
 /* PCI networking support */
 #define CONFIG_RTL8169
include/configs/p2371-2180.h +0 -1
index 56b169f..6194c7e 100644
@@ -57,7 +57,6 @@
 #define CONFIG_PCI
 #define CONFIG_PCI_PNP
 #define CONFIG_CMD_PCI
-#define CONFIG_CMD_PCI_ENUM
 
 /* PCI networking support */
 #define CONFIG_RTL8169
include/configs/trimslice.h +0 -1
index bdf1bd4..add5d40 100644
@@ -60,7 +60,6 @@
 #define CONFIG_PCI
 #define CONFIG_PCI_PNP
 #define CONFIG_CMD_PCI
-#define CONFIG_CMD_PCI_ENUM
 
 /* PCI networking support */
 #define CONFIG_RTL8169
Signature · 1 line
2.6.0.rc2.230.g3dd15c0
#3 lore raw

PATCH v4 3/8 dm: pci: Set up the SDRAM mapping correctly

In reply to Simon Glass

SDRAM doesn't always start at 0. Adjust the region mapping so that it works on platforms where SDRAM is somewhere else.

This needs testing on other platforms.

---

Changes in v4: None
Changes in v3: None
Changes in v2:
- Rename 'addr' to 'size'
- Correct logic for use of gd->pci_ram_top

 drivers/pci/pci-uclass.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)
drivers/pci/pci-uclass.c +9 -6
index 1d93194..6d860c4 100644
@@ -680,8 +680,8 @@ static int decode_regions(struct pci_controller *hose, const void *blob,
 			  int parent_node, int node)
 {
 	int pci_addr_cells, addr_cells, size_cells;
+	phys_addr_t base = 0, size;
 	int cells_per_record;
-	phys_addr_t addr;
 	const u32 *prop;
 	int len;
 	int i;
@@ -732,11 +732,14 @@ static int decode_regions(struct pci_controller *hose, const void *blob,
 	}
 
 	/* Add a region for our local memory */
-	addr = gd->ram_size;
-	if (gd->pci_ram_top && gd->pci_ram_top < addr)
-		addr = gd->pci_ram_top;
-	pci_set_region(hose->regions + hose->region_count++, 0, 0, addr,
-		       PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+	size = gd->ram_size;
+#ifdef CONFIG_SYS_SDRAM_BASE
+	base = CONFIG_SYS_SDRAM_BASE;
+#endif
+	if (gd->pci_ram_top && gd->pci_ram_top < base + size)
+		size = gd->pci_ram_top - base;
+	pci_set_region(hose->regions + hose->region_count++, base, base,
+		       size, PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
 
 	return 0;
 }
Signature · 1 line
2.6.0.rc2.230.g3dd15c0
#4 lore raw

PATCH v4 4/8 dm: pci: Support decoding ranges with duplicate entries

In reply to Simon Glass

At present we add a new resource entry for every range entry. But some range entries refer to configuration regions. To make this work, avoid adding two regions of the same type. The later ranges will overwrite the earlier (configuration) ones.

There does not seem to be a way to distinguish the configuration ranges other than by ordering (as per the device tree binding).

We could perhaps instead just store one region of each type in a simple array. Once we are sure that we don't need to support multiple regions, we could change this. It would be easier to do it when all drivers are converted to use driver model for PCI.

---

Changes in v4: None
Changes in v3: None
Changes in v2:
- Update commit message to mention future work

 drivers/pci/pci-uclass.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)
drivers/pci/pci-uclass.c +10 -3
index 6d860c4..7b48879 100644
@@ -704,6 +704,7 @@ static int decode_regions(struct pci_controller *hose, const void *blob,
 		int space_code;
 		u32 flags;
 		int type;
+		int pos;
 
 		if (len < cells_per_record)
 			break;
@@ -726,9 +727,15 @@ static int decode_regions(struct pci_controller *hose, const void *blob,
 		} else {
 			continue;
 		}
-		debug(" - type=%d\n", type);
-		pci_set_region(hose->regions + hose->region_count++, pci_addr,
-			       addr, size, type);
+		pos = -1;
+		for (i = 0; i < hose->region_count; i++) {
+			if (hose->regions[i].flags == type)
+				pos = i;
+		}
+		if (pos == -1)
+			pos = hose->region_count++;
+		debug(" - type=%d, pos=%d\n", type, pos);
+		pci_set_region(hose->regions + pos, pci_addr, addr, size, type);
 	}
 
 	/* Add a region for our local memory */
Signature · 1 line
2.6.0.rc2.230.g3dd15c0
#5 lore raw

PATCH v4 5/8 dm: pci: Add functions to emulate 8- and 16-bit access

In reply to Simon Glass

Provide a few functions to support using 32-bit access to emulate 8- and 16-bit access.

---

Changes in v4: None
Changes in v3: None
Changes in v2: None

 drivers/pci/pci-uclass.c | 39 +++++++++++++++++++++++++++++++++++++++
 include/pci.h            | 31 +++++++++++++++++++++++++++++++
 2 files changed, 70 insertions(+)
drivers/pci/pci-uclass.c +39 -0
index 7b48879..e38e0b2 100644
@@ -927,6 +927,45 @@ int pci_find_first_device(struct udevice **devp)
 	return skip_to_next_device(bus, devp);
 }
 
+ulong pci_conv_32_to_size(ulong value, uint offset, enum pci_size_t size)
+{
+	switch (size) {
+	case PCI_SIZE_8:
+		return (value >> ((offset & 3) * 8)) & 0xff;
+	case PCI_SIZE_16:
+		return (value >> ((offset & 2) * 8)) & 0xffff;
+	default:
+		return value;
+	}
+}
+
+ulong pci_conv_size_to_32(ulong old, ulong value, uint offset,
+			  enum pci_size_t size)
+{
+	uint off_mask;
+	uint val_mask, shift;
+	ulong ldata, mask;
+
+	switch (size) {
+	case PCI_SIZE_8:
+		off_mask = 3;
+		val_mask = 0xff;
+		break;
+	case PCI_SIZE_16:
+		off_mask = 2;
+		val_mask = 0xffff;
+		break;
+	default:
+		return value;
+	}
+	shift = (offset & off_mask) * 8;
+	ldata = (value & val_mask) << shift;
+	mask = val_mask << shift;
+	value = (old & ~mask) | ldata;
+
+	return value;
+}
+
 UCLASS_DRIVER(pci) = {
 	.id		= UCLASS_PCI,
 	.name		= "pci",
include/pci.h +31 -0
index ed135a5..ec2d104 100644
@@ -1092,6 +1092,37 @@ static inline int pci_read_config_byte(pci_dev_t pcidev, int offset,
 }
 
 /**
+ * pci_conv_32_to_size() - convert a 32-bit read value to the given size
+ *
+ * Some PCI buses must always perform 32-bit reads. The data must then be
+ * shifted and masked to reflect the required access size and offset. This
+ * function performs this transformation.
+ *
+ * @value:	Value to transform (32-bit value read from @offset & ~3)
+ * @offset:	Register offset that was read
+ * @size:	Required size of the result
+ * @return the value that would have been obtained if the read had been
+ * performed@the given offset with the correct size
+ */
+ulong pci_conv_32_to_size(ulong value, uint offset, enum pci_size_t size);
+
+/**
+ * pci_conv_size_to_32() - update a 32-bit value to prepare for a write
+ *
+ * Some PCI buses must always perform 32-bit writes. To emulate a smaller
+ * write the old 32-bit data must be read, updated with the required new data
+ * and written back as a 32-bit value. This function performs the
+ * transformation from the old value to the new value.
+ *
+ * @value:	Value to transform (32-bit value read from @offset & ~3)
+ * @offset:	Register offset that should be written
+ * @size:	Required size of the write
+ * @return the value that should be written as a 32-bit access to @offset & ~3.
+ */
+ulong pci_conv_size_to_32(ulong old, ulong value, uint offset,
+			  enum pci_size_t size);
+
+/**
  * struct dm_pci_emul_ops - PCI device emulator operations
  */
 struct dm_pci_emul_ops {
Signature · 1 line
2.6.0.rc2.230.g3dd15c0
#6 lore raw

PATCH v4 6/8 dm: pci: Add a function to get the controller for a bus

In reply to Simon Glass

A PCI bus may be a bridge device where the controller is the bridge's parent. Add a function to return the controller device, given a PCI device.

---

Changes in v4: None
Changes in v3: None
Changes in v2:
- Use the device_is_on_pci_bus() API

 drivers/pci/pci-uclass.c | 8 ++++++++
 include/pci.h            | 8 ++++++++
 2 files changed, 16 insertions(+)
drivers/pci/pci-uclass.c +8 -0
index e38e0b2..f3f5f00 100644
@@ -53,6 +53,14 @@ struct pci_controller *pci_bus_to_hose(int busnum)
 	return dev_get_uclass_priv(bus);
 }
 
+struct udevice *pci_get_controller(struct udevice *dev)
+{
+	while (device_is_on_pci_bus(dev))
+		dev = dev->parent;
+
+	return dev;
+}
+
 pci_dev_t pci_get_bdf(struct udevice *dev)
 {
 	struct pci_child_platdata *pplat = dev_get_parent_platdata(dev);
include/pci.h +8 -0
index ec2d104..f3dda70 100644
@@ -1123,6 +1123,14 @@ ulong pci_conv_size_to_32(ulong old, ulong value, uint offset,
 			  enum pci_size_t size);
 
 /**
+ * pci_get_controller() - obtain the controller to use for a bus
+ *
+ * @dev:	Device to check
+ * @return pointer to the controller device for this bus
+ */
+struct udevice *pci_get_controller(struct udevice *dev);
+
+/**
  * struct dm_pci_emul_ops - PCI device emulator operations
  */
 struct dm_pci_emul_ops {
Signature · 1 line
2.6.0.rc2.230.g3dd15c0
#7 lore raw

PATCH v4 7/8 dm: pci: Add a function to find the regions for a PCI bus

In reply to Simon Glass

This function looks up the controller and returns a pointer to each region type.

---

Changes in v4: None
Changes in v3: None
Changes in v2: None

 drivers/pci/pci-uclass.c | 30 ++++++++++++++++++++++++++++++
 include/pci.h            | 12 ++++++++++++
 2 files changed, 42 insertions(+)
drivers/pci/pci-uclass.c +30 -0
index f3f5f00..5fe3072 100644
@@ -974,6 +974,36 @@ ulong pci_conv_size_to_32(ulong old, ulong value, uint offset,
 	return value;
 }
 
+int pci_get_regions(struct udevice *dev, struct pci_region **iop,
+		    struct pci_region **memp, struct pci_region **prefp)
+{
+	struct udevice *bus = pci_get_controller(dev);
+	struct pci_controller *hose = dev_get_uclass_priv(bus);
+	int i;
+
+	*iop = NULL;
+	*memp = NULL;
+	*prefp = NULL;
+	for (i = 0; i < hose->region_count; i++) {
+		switch (hose->regions[i].flags) {
+		case PCI_REGION_IO:
+			if (!*iop || (*iop)->size < hose->regions[i].size)
+				*iop = hose->regions + i;
+			break;
+		case PCI_REGION_MEM:
+			if (!*memp || (*memp)->size < hose->regions[i].size)
+				*memp = hose->regions + i;
+			break;
+		case (PCI_REGION_MEM | PCI_REGION_PREFETCH):
+			if (!*prefp || (*prefp)->size < hose->regions[i].size)
+				*prefp = hose->regions + i;
+			break;
+		}
+	}
+
+	return (*iop != NULL) + (*memp != NULL) + (*prefp != NULL);
+}
+
 UCLASS_DRIVER(pci) = {
 	.id		= UCLASS_PCI,
 	.name		= "pci",
include/pci.h +12 -0
index f3dda70..9c19482 100644
@@ -1131,6 +1131,18 @@ ulong pci_conv_size_to_32(ulong old, ulong value, uint offset,
 struct udevice *pci_get_controller(struct udevice *dev);
 
 /**
+ * pci_get_regions() - obtain pointers to all the region types
+ *
+ * @dev:	Device to check
+ * @iop:	Returns a pointer to the I/O region, or NULL if none
+ * @memp:	Returns a pointer to the memory region, or NULL if none
+ * @prefp:	Returns a pointer to the pre-fetch region, or NULL if none
+ * @return the number of non-NULL regions returned, normally 3
+ */
+int pci_get_regions(struct udevice *dev, struct pci_region **iop,
+		    struct pci_region **memp, struct pci_region **prefp);
+
+/**
  * struct dm_pci_emul_ops - PCI device emulator operations
  */
 struct dm_pci_emul_ops {
Signature · 1 line
2.6.0.rc2.230.g3dd15c0
#8 lore raw

PATCH v4 8/8 dm: tegra: pci: Convert tegra boards to driver model for PCI

In reply to Simon Glass

Adjust the Tegra PCI driver to support driver model and move all boards over at the same time. This can make use of some generic driver model code, such as the range-decoding logic.

---

Changes in v4:
- Fix merge conflict resolution error in v3
- Add compatible string for T210 (from Stephen Warren)

Changes in v3:
- Rebase onto tegra/master
- Enable DM_PCI for Tegra 210 family too

Changes in v2:
- Leave pci_skip_dev() at the bottom of the file to reduce the diff size

 arch/arm/mach-tegra/Kconfig |   2 +
 drivers/pci/pci_tegra.c     | 467 ++++++++++++++------------------------------
 include/fdtdec.h            |   4 -
 lib/fdtdec.c                |   4 -
 4 files changed, 152 insertions(+), 325 deletions(-)
arch/arm/mach-tegra/Kconfig +2 -0
index a5b7e0d..e5215ab 100644
@@ -12,6 +12,7 @@ config TEGRA_ARMV7_COMMON
 	select DM_I2C
 	select DM_SPI
 	select DM_GPIO
+	select DM_PCI
 
 choice
 	prompt "Tegra SoC select"
@@ -43,6 +44,7 @@ config TEGRA210
 	select DM_I2C
 	select DM_SPI
 	select DM_GPIO
+	select DM_PCI
 
 endchoice
 
drivers/pci/pci_tegra.c +150 -317

638 lines not on this page · raw message

include/fdtdec.h +0 -4
index 3a6ff1f..8e0f592 100644
@@ -129,10 +129,6 @@ enum fdt_compat_id {
 	COMPAT_NVIDIA_TEGRA124_SDMMC,	/* Tegra124 SDMMC controller */
 	COMPAT_NVIDIA_TEGRA30_SDMMC,	/* Tegra30 SDMMC controller */
 	COMPAT_NVIDIA_TEGRA20_SDMMC,	/* Tegra20 SDMMC controller */
-	COMPAT_NVIDIA_TEGRA124_PCIE,	/* Tegra 124 PCIe controller */
-	COMPAT_NVIDIA_TEGRA210_PCIE,	/* Tegra 210 PCIe controller */
-	COMPAT_NVIDIA_TEGRA30_PCIE,	/* Tegra 30 PCIe controller */
-	COMPAT_NVIDIA_TEGRA20_PCIE,	/* Tegra 20 PCIe controller */
 	COMPAT_NVIDIA_TEGRA124_XUSB_PADCTL,
 					/* Tegra124 XUSB pad controller */
 	COMPAT_NVIDIA_TEGRA210_XUSB_PADCTL,
lib/fdtdec.c +0 -4
index f1849bc..4534177 100644
@@ -35,10 +35,6 @@ static const char * const compat_names[COMPAT_COUNT] = {
 	COMPAT(NVIDIA_TEGRA124_SDMMC, "nvidia,tegra124-sdhci"),
 	COMPAT(NVIDIA_TEGRA30_SDMMC, "nvidia,tegra30-sdhci"),
 	COMPAT(NVIDIA_TEGRA20_SDMMC, "nvidia,tegra20-sdhci"),
-	COMPAT(NVIDIA_TEGRA124_PCIE, "nvidia,tegra124-pcie"),
-	COMPAT(NVIDIA_TEGRA210_PCIE, "nvidia,tegra210-pcie"),
-	COMPAT(NVIDIA_TEGRA30_PCIE, "nvidia,tegra30-pcie"),
-	COMPAT(NVIDIA_TEGRA20_PCIE, "nvidia,tegra20-pcie"),
 	COMPAT(NVIDIA_TEGRA124_XUSB_PADCTL, "nvidia,tegra124-xusb-padctl"),
 	COMPAT(NVIDIA_TEGRA210_XUSB_PADCTL, "nvidia,tegra210-xusb-padctl"),
 	COMPAT(SMSC_LAN9215, "smsc,lan9215"),
Signature · 1 line
2.6.0.rc2.230.g3dd15c0
#9 lore raw

PATCH v4 8/8 dm: tegra: pci: Convert tegra boards to driver model for PCI

Quoted 3 lines · Simon Glass

Adjust the Tegra PCI driver to support driver model and move all boards over at the same time. This can make use of some generic driver model code, such as the range-decoding logic.

To make this series work on Jetson TX1, two things need to happen.

First, this patch reverts a change I made earlier to move the call to tegra_pcie_board_init() to an earlier point in the initialization process, i.e. before /any/ part of the PCIe or pad HW is accessed. To solve that, apply the following:

Quoted 38 lines
drivers/pci/pci_tegra.c +7 -5
index ed363e4220c4..8f089b3f6bbe 100644
@@ -433,6 +435,11 @@ static int tegra_pcie_parse_port_info(const void *fdt, int node,
        return 0;
 }
 
+int __weak tegra_pcie_board_init(void)
+{
+       return 0;
+}
+
 static int tegra_pcie_parse_dt(const void *fdt, int node, enum tegra_pci_id id,
                               struct tegra_pcie *pcie)
 {
@@ -460,6 +467,8 @@ static int tegra_pcie_parse_dt(const void *fdt, int node, enum tegra_pci_id id,
                return err;
        }
 
+       tegra_pcie_board_init();
+
        pcie->phy = tegra_xusb_phy_get(TEGRA_XUSB_PADCTL_PCIE);
        if (pcie->phy) {
                err = tegra_xusb_phy_prepare(pcie->phy);
@@ -512,11 +521,6 @@ static int tegra_pcie_parse_dt(const void *fdt, int node, enum tegra_pci_id id,
        return 0;
 }
 
-int __weak tegra_pcie_board_init(void)
-{
-       return 0;
-}
-
 static int tegra_pcie_power_on(struct tegra_pcie *pcie)
 {
        const struct tegra_pcie_soc *soc = pcie->soc;

drivers/pci/pci_tegra.c static int tegra_pcie_power_on(struct tegra_pcie *pcie) · line 543

Quoted 8 lines
drivers/pci/pci_tegra.c +0 -2
@@ -534,8 +538,6 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie)
                return err;
        }
 
-       tegra_pcie_board_init();
-
        err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE,
                                                PERIPH_ID_PCIE);
        if (err < 0) {

Second, the removal of the following piece of code:

drivers/pci/pci_tegra.c static int tegra_pcie_enable(struct tegra_pcie *pcie) · line 1058

Quoted 13 lines
drivers/pci/pci_tegra.c +0 -10
 
-static int process_nodes(const void *fdt, int nodes[], unsigned int count)
  {
-	unsigned int i;
-	uint64_t dram_end;
-	uint32_t pci_dram_size;
-
-	/* Clip PCI-accessible DRAM to 32-bits */
-	dram_end = ((uint64_t)NV_PA_SDRAM_BASE) + gd->ram_size;
-	if (dram_end > 0x100000000)
-		dram_end = 0x100000000;
-	pci_dram_size = dram_end - NV_PA_SDRAM_BASE;

... means that the PCI resource structure that represents system memory ends up with size=0 rather than the expected size=0x80000000. That's because gd->ram_size is 4GB and sizeof(res->size)==4.

Perhaps I could solve this by defining CONFIG_SYS_PCI_64BIT, which changes the size of res->size to 8 bytes. However:

a) I'm a bit worried that changing the size of that type will lead to other unexpected behavioural changes, e.g. interactions with DT parsing due to cell count differences.

b) This only solves the integer overflow issue. In fact, res->base+res->size should fit inside 32-bits since IIRC the PCIe controller can only access 32-bit addresses, and hence we need to clip the RAM size to acknowledge that, which the code above was doing. Doing such a clipping operation in the generic/shared decode_regions() doesn't feel like a good idea, at least not unconditionally.

In practice, (a) doesn't seem to be a problem, and perhaps we can ignore (b), since board_get_usable_ram_top() (in arch/arm/mach-tegra/board2.c) limits usable RAM size to fit within 32 bits for similar reasons. So, I know that no allocated memory buffer will ever be above 32 bits, so it doesn't matter in practice whether a PCI region's base+size fits into 32 bits or not.

What are your thoughts on this?

BTW, your V4 plus these fixes is available at:

git://github.com/swarren/u-boot.git test-pci-dm-v4

#10 lore raw

PATCH v4 8/8 dm: tegra: pci: Convert tegra boards to driver model for PCI

Hi Stephen,

Quoted 8 lines · Stephen Warren
Quoted 6 lines · Simon Glass

Adjust the Tegra PCI driver to support driver model and move all boards over
at the same time. This can make use of some generic driver model code, such
as the range-decoding logic.

Thanks for looking at this.

Quoted 54 lines

To make this series work on Jetson TX1, two things need to happen.

First, this patch reverts a change I made earlier to move the call to tegra_pcie_board_init() to an earlier point in the initialization process, i.e. before /any/ part of the PCIe or pad HW is accessed. To solve that, apply the following:

Quoted 46 lines
drivers/pci/pci_tegra.c +5 -0
index ed363e4220c4..8f089b3f6bbe 100644
@@ -433,6 +435,11 @@ static int tegra_pcie_parse_port_info(const void
 *fdt, int node,
        return 0;
 }
 
+int __weak tegra_pcie_board_init(void)
+{
+       return 0;
+}
+
 static int tegra_pcie_parse_dt(const void *fdt, int node, enum
 tegra_pci_id id,

struct tegra_pcie *pcie)
{

drivers/pci/pci_tegra.c +2 -0
@@ -460,6 +467,8 @@ static int tegra_pcie_parse_dt(const void *fdt, int
 node, enum tegra_pci_id id,
                return err;
        }
 
+       tegra_pcie_board_init();
+
        pcie->phy = tegra_xusb_phy_get(TEGRA_XUSB_PADCTL_PCIE);
        if (pcie->phy) {
                err = tegra_xusb_phy_prepare(pcie->phy);
drivers/pci/pci_tegra.c +0 -5
@@ -512,11 +521,6 @@ static int tegra_pcie_parse_dt(const void *fdt, int
 node, enum tegra_pci_id id,
        return 0;
 }
 
-int __weak tegra_pcie_board_init(void)
-{
-       return 0;
-}
-
 static int tegra_pcie_power_on(struct tegra_pcie *pcie)
 {
        const struct tegra_pcie_soc *soc = pcie->soc;
drivers/pci/pci_tegra.c +0 -0
@@ -534,8 +538,6 @@ static int tegra_pcie_power_on(struct tegra_pcie
 *pcie)
                return err;
        }
 
Quoted 6 lines
Quoted 5 lines
drivers/pci/pci_tegra.c +0 -2
-       tegra_pcie_board_init();
-
        err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE,
                                                PERIPH_ID_PCIE);
        if (err < 0) {

OK

Quoted 38 lines

Second, the removal of the following piece of code:

Quoted 6 lines
drivers/pci/pci_tegra.c +0 -1
 
 
-static int process_nodes(const void *fdt, int nodes[], unsigned int

count)
{

drivers/pci/pci_tegra.c static int tegra_pcie_enable(struct tegra_pcie *pcie) · line 1058

Quoted 9 lines
drivers/pci/pci_tegra.c +0 -9
-       unsigned int i;
-       uint64_t dram_end;
-       uint32_t pci_dram_size;
-
-       /* Clip PCI-accessible DRAM to 32-bits */
-       dram_end = ((uint64_t)NV_PA_SDRAM_BASE) + gd->ram_size;
-       if (dram_end > 0x100000000)
-               dram_end = 0x100000000;
-       pci_dram_size = dram_end - NV_PA_SDRAM_BASE;

... means that the PCI resource structure that represents system memory ends up with size=0 rather than the expected size=0x80000000. That's because gd->ram_size is 4GB and sizeof(res->size)==4.

Perhaps I could solve this by defining CONFIG_SYS_PCI_64BIT, which changes the size of res->size to 8 bytes. However:

a) I'm a bit worried that changing the size of that type will lead to other unexpected behavioural changes, e.g. interactions with DT parsing due to cell count differences.

b) This only solves the integer overflow issue. In fact, res->base+res->size should fit inside 32-bits since IIRC the PCIe controller can only access 32-bit addresses, and hence we need to clip the RAM size to acknowledge that, which the code above was doing. Doing such a clipping operation in the generic/shared decode_regions() doesn't feel like a good idea, at least not unconditionally.

Quoted 8 lines

In practice, (a) doesn't seem to be a problem, and perhaps we can ignore (b), since board_get_usable_ram_top() (in arch/arm/mach-tegra/board2.c) limits usable RAM size to fit within 32 bits for similar reasons. So, I know that no allocated memory buffer will ever be above 32 bits, so it doesn't matter in practice whether a PCI region's base+size fits into 32 bits or not.

What are your thoughts on this?

Does gd->pci_ram_top in decode_regions() do what you want?

Quoted 4 lines

BTW, your V4 plus these fixes is available at:

git://github.com/swarren/u-boot.git test-pci-dm-v4

Thanks!

Regards,
Simon

#11 lore raw

PATCH v4 8/8 dm: tegra: pci: Convert tegra boards to driver model for PCI

Quoted 9 lines · Simon Glass
Quoted 4 lines · Stephen Warren
Quoted 3 lines · Simon Glass

Adjust the Tegra PCI driver to support driver model and move all boards over at the same time. This can make use of some generic driver model code, such as the range-decoding logic.

Thanks for looking at this.

Quoted 1 line

To make this series work on Jetson TX1, two things need to happen.

...

Quoted 41 lines
Quoted 41 lines
Quoted 5 lines
drivers/pci/pci_tegra.c +0 -1
 
-static int process_nodes(const void *fdt, int nodes[], unsigned int

count)
{

drivers/pci/pci_tegra.c static int tegra_pcie_enable(struct tegra_pcie *pcie) · line 1058

Quoted 9 lines
drivers/pci/pci_tegra.c +0 -9
-       unsigned int i;
-       uint64_t dram_end;
-       uint32_t pci_dram_size;
-
-       /* Clip PCI-accessible DRAM to 32-bits */
-       dram_end = ((uint64_t)NV_PA_SDRAM_BASE) + gd->ram_size;
-       if (dram_end > 0x100000000)
-               dram_end = 0x100000000;
-       pci_dram_size = dram_end - NV_PA_SDRAM_BASE;

... means that the PCI resource structure that represents system memory ends up with size=0 rather than the expected size=0x80000000. That's because gd->ram_size is 4GB and sizeof(res->size)==4.

Perhaps I could solve this by defining CONFIG_SYS_PCI_64BIT, which changes the size of res->size to 8 bytes. However:

a) I'm a bit worried that changing the size of that type will lead to other unexpected behavioural changes, e.g. interactions with DT parsing due to cell count differences.

b) This only solves the integer overflow issue. In fact, res->base+res->size should fit inside 32-bits since IIRC the PCIe controller can only access 32-bit addresses, and hence we need to clip the RAM size to acknowledge that, which the code above was doing. Doing such a clipping operation in the generic/shared decode_regions() doesn't feel like a good idea, at least not unconditionally.

In practice, (a) doesn't seem to be a problem, and perhaps we can ignore (b), since board_get_usable_ram_top() (in arch/arm/mach-tegra/board2.c) limits usable RAM size to fit within 32 bits for similar reasons. So, I know that no allocated memory buffer will ever be above 32 bits, so it doesn't matter in practice whether a PCI region's base+size fits into 32 bits or not.

Quoted 3 lines
Quoted 1 line

What are your thoughts on this?

Does gd->pci_ram_top in decode_regions() do what you want?

Ah of course; the following does solve the problem:

Quoted 13 lines
arch/arm/mach-tegra/board2.c +2 -0
index 8ba143d996ca..d2c957a2a426 100644
@@ -377,6 +377,8 @@ void dram_init_banksize(void)
 	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
 	gd->bd->bi_dram[0].size = usable_ram_size_below_4g();
 
+	gd->pci_ram_top = gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size;
+
 #ifdef CONFIG_PHYS_64BIT
 	if (gd->ram_size > SZ_2G) {
 		gd->bd->bi_dram[1].start = 0x100000000;
#12 lore raw

v4 cover dm: pci: tegra: Convert Tegra PCI to driver model

In reply to Simon Glass
Quoted 2 lines · Simon Glass

This series converts all Tegra boards to use driver model for PCI. The net effect should be no change in functionality.

In v4, Jetson TK1 now works as expected. However, the issues on p2371-2180 (Jetson TX1) still remain. I'll try and look into these.