[U-Boot] [PATCHv4 09/12] dm: pci: add APIs for capability accessors

Z.q. Hou zhiqiang.hou at nxp.com
Mon Mar 11 02:58:30 UTC 2019


From: Hou Zhiqiang <Zhiqiang.Hou at nxp.com>

This patch introduce a set of PCI/PCIe capability accessors,
including 16-bit and 32-bit read, write and clear_and_set
operations.

Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou at nxp.com>
---
V4:
 - New patch

 drivers/pci/pci-uclass.c | 153 +++++++++++++++++++++++++++++++++++++++
 include/pci.h            |  20 +++++
 2 files changed, 173 insertions(+)

diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
index 824fa11907..4bb30f5d2b 100644
--- a/drivers/pci/pci-uclass.c
+++ b/drivers/pci/pci-uclass.c
@@ -1443,6 +1443,159 @@ int dm_pci_find_ext_capability(struct udevice *dev, int cap)
 	return dm_pci_find_next_ext_capability(dev, 0, cap);
 }
 
+/**
+ * dm_pci_capability_read() - PCI capability register read
+ *
+ * @dev:	PCI device to read
+ * @cap:	capability code
+ * @pos:	register offset
+ * @val:	pointer to keep the read value
+ * @size:	register width
+ *
+ * Returns 0 if OK or appropriate error value.
+ */
+int dm_pci_capability_read(struct udevice *dev, int cap, int pos,
+			   ulong *val, enum pci_size_t size)
+{
+	u32 off;
+
+	switch (size) {
+	case PCI_SIZE_16:
+		if (pos & 1)
+			return -EINVAL;
+		break;
+	case PCI_SIZE_32:
+		if (pos & 3)
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	off = dm_pci_find_capability(dev, cap);
+	if (off)
+		return dm_pci_read_config(dev, off + pos, val, size);
+
+	return -EINVAL;
+}
+
+/**
+ * dm_pci_capability_write() - PCI capability register write
+ *
+ * @dev:	PCI device to write
+ * @cap:	capability code
+ * @pos:	register offset
+ * @val:	value to write
+ * @size:	register width
+ *
+ * Returns 0 if OK or appropriate error value.
+ */
+int dm_pci_capability_write(struct udevice *dev, int cap, int pos,
+			    ulong val, enum pci_size_t size)
+{
+	u32 off;
+
+	switch (size) {
+	case PCI_SIZE_16:
+		if (pos & 1)
+			return -EINVAL;
+		break;
+	case PCI_SIZE_32:
+		if (pos & 3)
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	off = dm_pci_find_capability(dev, cap);
+	if (off)
+		return dm_pci_write_config(dev, off + pos, val, size);
+
+	return -EINVAL;
+}
+
+int dm_pci_capability_read_word(struct udevice *dev, int cap, int pos, u16 *val)
+{
+	ulong value;
+	int ret;
+
+	ret = dm_pci_capability_read(dev, cap, pos, &value, PCI_SIZE_16);
+	if (ret)
+		return ret;
+	*val = value;
+
+	return 0;
+}
+
+int dm_pci_capability_write_word(struct udevice *dev, int cap, int pos, u16 val)
+{
+	return dm_pci_capability_write(dev, cap, pos, val, PCI_SIZE_16);
+}
+
+int dm_pci_capability_read_dword(struct udevice *dev, int cap,
+				 int pos, u32 *val)
+{
+	ulong value;
+	int ret;
+
+	return dm_pci_capability_read(dev, cap, pos, &value, PCI_SIZE_32);
+	if (ret)
+		return ret;
+	*val = value;
+
+	return 0;
+}
+
+int dm_pci_capability_write_dword(struct udevice *dev, int cap,
+				  int pos, u32 val)
+{
+	return dm_pci_capability_write(dev, cap, pos, val, PCI_SIZE_32);
+}
+
+/**
+ * dm_pci_capability_clear_and_set() - PCI capability register update
+ *
+ * @dev:	PCI device to update
+ * @cap:	capability code
+ * @pos:	register offset
+ * @clear:	bits to clear
+ * @set:	bits to set
+ * @size:	register width
+ *
+ * Returns 0 if OK or appropriate error value.
+ */
+int dm_pci_capability_clear_and_set(struct udevice *dev, int cap, int pos,
+				    ulong clear, ulong set,
+				    enum pci_size_t size)
+{
+	int ret;
+	ulong val;
+
+	ret = dm_pci_capability_read(dev, cap, pos, &val, size);
+	if (!ret) {
+		val &= ~clear;
+		val |= set;
+		ret = dm_pci_capability_write(dev, cap, pos, val, size);
+	}
+
+	return ret;
+}
+
+int dm_pci_capability_clear_and_set_word(struct udevice *dev, int cap,
+					 int pos, u16 clear, u16 set)
+{
+	return dm_pci_capability_clear_and_set(dev, cap, pos, clear,
+					       set, PCI_SIZE_16);
+}
+
+int dm_pci_capability_clear_and_set_dword(struct udevice *dev, int cap,
+					  int pos, u32 clear, u32 set)
+{
+	return dm_pci_capability_clear_and_set(dev, cap, pos, clear,
+					       set, PCI_SIZE_32);
+}
+
 UCLASS_DRIVER(pci) = {
 	.id		= UCLASS_PCI,
 	.name		= "pci",
diff --git a/include/pci.h b/include/pci.h
index 041f8e3747..d7b6d9f4ff 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -1405,6 +1405,26 @@ int dm_pci_find_next_ext_capability(struct udevice *dev, int start, int cap);
  */
 int dm_pci_find_ext_capability(struct udevice *dev, int cap);
 
+int dm_pci_capability_read(struct udevice *dev, int cap, int pos,
+			   ulong *val, enum pci_size_t size);
+int dm_pci_capability_write(struct udevice *dev, int cap, int pos,
+			    ulong val, enum pci_size_t size);
+int dm_pci_capability_read_word(struct udevice *dev, int cap,
+				int pos, u16 *val);
+int dm_pci_capability_write_word(struct udevice *dev, int cap,
+				 int pos, u16 val);
+int dm_pci_capability_read_dword(struct udevice *dev, int cap,
+				 int pos, u32 *val);
+int dm_pci_capability_write_dword(struct udevice *dev, int cap,
+				  int pos, u32 val);
+int dm_pci_capability_clear_and_set(struct udevice *dev, int cap, int pos,
+				    ulong clear, ulong set,
+				    enum pci_size_t size);
+int dm_pci_capability_clear_and_set_word(struct udevice *dev, int cap,
+					 int pos, u16 clear, u16 set);
+int dm_pci_capability_clear_and_set_dword(struct udevice *dev, int cap,
+					  int pos, u32 clear, u32 set);
+
 #define dm_pci_virt_to_bus(dev, addr, flags) \
 	dm_pci_phys_to_bus(dev, (virt_to_phys(addr)), (flags))
 #define dm_pci_bus_to_virt(dev, addr, flags, len, map_flags) \
-- 
2.17.1



More information about the U-Boot mailing list