[U-Boot] [PATCH v3 5/8] dm: pci: Add functions to emulate 8- and 16-bit access

Simon Glass sjg at chromium.org
Thu Nov 12 17:59:29 CET 2015


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

Signed-off-by: Simon Glass <sjg at chromium.org>
Reviewed-by: Stephen Warren <swarren at nvidia.com>
---

Changes in v3: None
Changes in v2: None

 drivers/pci/pci-uclass.c | 39 +++++++++++++++++++++++++++++++++++++++
 include/pci.h            | 31 +++++++++++++++++++++++++++++++
 2 files changed, 70 insertions(+)

diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
index 7b48879..e38e0b2 100644
--- a/drivers/pci/pci-uclass.c
+++ b/drivers/pci/pci-uclass.c
@@ -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",
diff --git a/include/pci.h b/include/pci.h
index ed135a5..ec2d104 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -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 at 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 {
-- 
2.6.0.rc2.230.g3dd15c0



More information about the U-Boot mailing list