All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v2 0/7] x86: Support pci based uart as the U-Boot serial console
@ 2014-12-27 12:10 Bin Meng
  2014-12-27 12:10 ` [U-Boot] [PATCH v2 1/7] x86: Add missing DECLARE_GLOBAL_DATA_PTR for pci.c Bin Meng
                   ` (6 more replies)
  0 siblings, 7 replies; 20+ messages in thread
From: Bin Meng @ 2014-12-27 12:10 UTC (permalink / raw)
  To: u-boot

This series add support to the ns16550 compatible pci devices.

Newer x86 Platform Controller Hub chipset (like Topcliff, BayTrail)
starts to integrate ns16550 compatible pci uart devices. In order to
use them, we have to scan the pci bus and allocate memory/io address
in the early phase. A gd->hose is added to save the pci bus controller
hose in the early phase so that pci apis can be used.

On Intel Crown Bay board, there are 4 DB9 connectors, one of which
is from the superio legacy serial port and the other 3 are connected
to the Topcliff PCH UART devices. In order to use them as the U-Boot
serial console, we need describe those devices in the board's dts
file per Open Firmware PCI bus bindings and specify it as the console
via the 'stdout-path' in the chosen node. Several APIs are added in
fdtdec.c to provide help for decoding the pci device nodes.

Changes in v2:
- Add a commit message
- New patch to make pci apis usable before relocation
- New patch to add several apis to decode pci device node
- New patch to support ns16550 compatible pci uart devices
- New patch to use ePAPR defined properties for x86-uart
- New patch to add pci devices in crownbay.dts
- Drop v1 patch: Add an API for finding pci devices in the early phase
- Drop v1 patch: Support PCI UART in the x86_serial driver
- Drop v1 patch: Add PCI UART related defines in crownbay.h

Bin Meng (7):
  x86: Add missing DECLARE_GLOBAL_DATA_PTR for pci.c
  x86: Support pci bus scan in the early phase
  pci: Make pci apis usable before relocation
  fdt: Add several apis to decode pci device node
  serial: ns16550: Support ns16550 compatible pci uart devices
  x86: Use ePAPR defined properties for x86-uart
  x86: crownbay: Add pci devices in the dts file

 arch/x86/cpu/pci.c                 |  11 ++-
 arch/x86/dts/crownbay.dts          |  81 +++++++++++++++++++
 arch/x86/dts/serial.dtsi           |   5 +-
 arch/x86/include/asm/global_data.h |   1 -
 arch/x86/include/asm/pci.h         |   2 +-
 drivers/pci/pci.c                  |  25 ++++--
 drivers/serial/ns16550.c           |  33 +++++++-
 drivers/serial/serial_x86.c        |   8 +-
 include/asm-generic/global_data.h  |   6 ++
 include/fdtdec.h                   | 108 ++++++++++++++++++++++---
 lib/fdtdec.c                       | 157 +++++++++++++++++++++++++++++++++----
 11 files changed, 393 insertions(+), 44 deletions(-)

-- 
1.8.2.1

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH v2 1/7] x86: Add missing DECLARE_GLOBAL_DATA_PTR for pci.c
  2014-12-27 12:10 [U-Boot] [PATCH v2 0/7] x86: Support pci based uart as the U-Boot serial console Bin Meng
@ 2014-12-27 12:10 ` Bin Meng
  2014-12-28  1:55   ` Simon Glass
  2014-12-27 12:10 ` [U-Boot] [PATCH v2 2/7] x86: Support pci bus scan in the early phase Bin Meng
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 20+ messages in thread
From: Bin Meng @ 2014-12-27 12:10 UTC (permalink / raw)
  To: u-boot

arch/x86/cpu/pci.c has access to the U-Boot global data thus
DECLARE_GLOBAL_DATA_PTR is needed.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>

---

Changes in v2:
- Add a commit message

 arch/x86/cpu/pci.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/x86/cpu/pci.c b/arch/x86/cpu/pci.c
index f3492c3..404fbb6 100644
--- a/arch/x86/cpu/pci.c
+++ b/arch/x86/cpu/pci.c
@@ -15,6 +15,8 @@
 #include <pci.h>
 #include <asm/pci.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
 static struct pci_controller x86_hose;
 
 int pci_early_init_hose(struct pci_controller **hosep)
-- 
1.8.2.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH v2 2/7] x86: Support pci bus scan in the early phase
  2014-12-27 12:10 [U-Boot] [PATCH v2 0/7] x86: Support pci based uart as the U-Boot serial console Bin Meng
  2014-12-27 12:10 ` [U-Boot] [PATCH v2 1/7] x86: Add missing DECLARE_GLOBAL_DATA_PTR for pci.c Bin Meng
@ 2014-12-27 12:10 ` Bin Meng
  2014-12-28  1:55   ` Simon Glass
  2014-12-27 12:10 ` [U-Boot] [PATCH v2 3/7] pci: Make pci apis usable before relocation Bin Meng
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 20+ messages in thread
From: Bin Meng @ 2014-12-27 12:10 UTC (permalink / raw)
  To: u-boot

On x86, some peripherals on pci buses need to be accessed in the
early phase (eg: pci uart) with a valid pci memory/io address,
thus scan the pci bus and do the corresponding resource allocation.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
---

Changes in v2: None

 arch/x86/cpu/pci.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/x86/cpu/pci.c b/arch/x86/cpu/pci.c
index 404fbb6..1eee08b 100644
--- a/arch/x86/cpu/pci.c
+++ b/arch/x86/cpu/pci.c
@@ -29,6 +29,7 @@ int pci_early_init_hose(struct pci_controller **hosep)
 
 	board_pci_setup_hose(hose);
 	pci_setup_type1(hose);
+	hose->last_busno = pci_hose_scan(hose);
 	gd->arch.hose = hose;
 	*hosep = hose;
 
-- 
1.8.2.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH v2 3/7] pci: Make pci apis usable before relocation
  2014-12-27 12:10 [U-Boot] [PATCH v2 0/7] x86: Support pci based uart as the U-Boot serial console Bin Meng
  2014-12-27 12:10 ` [U-Boot] [PATCH v2 1/7] x86: Add missing DECLARE_GLOBAL_DATA_PTR for pci.c Bin Meng
  2014-12-27 12:10 ` [U-Boot] [PATCH v2 2/7] x86: Support pci bus scan in the early phase Bin Meng
@ 2014-12-27 12:10 ` Bin Meng
  2014-12-28  1:55   ` Simon Glass
  2014-12-27 12:10 ` [U-Boot] [PATCH v2 4/7] fdt: Add several apis to decode pci device node Bin Meng
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 20+ messages in thread
From: Bin Meng @ 2014-12-27 12:10 UTC (permalink / raw)
  To: u-boot

Introduce a gd->hose to save the pci hose in the early phase so that
apis in drivers/pci/pci.c can be used before relocation. Architecture
codes need assign a valid gd->hose in the early phase.

Some variables are declared as static so change them to be either
stack variable or global data member so that they can be used before
relocation, except the 'indent' used by CONFIG_PCI_SCAN_SHOW which
just affects some print format.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>

---

Changes in v2:
- New patch to make pci apis usable before relocation

 arch/x86/cpu/pci.c                 |  8 ++++----
 arch/x86/include/asm/global_data.h |  1 -
 arch/x86/include/asm/pci.h         |  2 +-
 drivers/pci/pci.c                  | 25 +++++++++++++++++--------
 include/asm-generic/global_data.h  |  6 ++++++
 5 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/arch/x86/cpu/pci.c b/arch/x86/cpu/pci.c
index 1eee08b..ab1aaaa 100644
--- a/arch/x86/cpu/pci.c
+++ b/arch/x86/cpu/pci.c
@@ -30,7 +30,7 @@ int pci_early_init_hose(struct pci_controller **hosep)
 	board_pci_setup_hose(hose);
 	pci_setup_type1(hose);
 	hose->last_busno = pci_hose_scan(hose);
-	gd->arch.hose = hose;
+	gd->hose = hose;
 	*hosep = hose;
 
 	return 0;
@@ -51,7 +51,7 @@ void pci_init_board(void)
 	struct pci_controller *hose = &x86_hose;
 
 	/* Stop using the early hose */
-	gd->arch.hose = NULL;
+	gd->hose = NULL;
 
 	board_pci_setup_hose(hose);
 	pci_setup_type1(hose);
@@ -64,8 +64,8 @@ void pci_init_board(void)
 
 static struct pci_controller *get_hose(void)
 {
-	if (gd->arch.hose)
-		return gd->arch.hose;
+	if (gd->hose)
+		return gd->hose;
 
 	return pci_bus_to_hose(0);
 }
diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h
index 03d491a..aeab3e5 100644
--- a/arch/x86/include/asm/global_data.h
+++ b/arch/x86/include/asm/global_data.h
@@ -43,7 +43,6 @@ struct arch_global_data {
 	uint32_t tsc_mhz;		/* TSC frequency in MHz */
 	void *new_fdt;			/* Relocated FDT */
 	uint32_t bist;			/* Built-in self test value */
-	struct pci_controller *hose;	/* PCI hose for early use */
 	enum pei_boot_mode_t pei_boot_mode;
 	const struct pch_gpio_map *gpio_map;	/* board GPIO map */
 	struct memory_info meminfo;	/* Memory information */
diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h
index ac1a808..c30dd4c 100644
--- a/arch/x86/include/asm/pci.h
+++ b/arch/x86/include/asm/pci.h
@@ -29,7 +29,7 @@ void board_pci_setup_hose(struct pci_controller *hose);
  * pci_early_init_hose() - Set up PCI host before relocation
  *
  * This allocates memory for, sets up and returns the PCI hose. It can be
- * called before relocation. The hose will be stored in gd->arch.hose for
+ * called before relocation. The hose will be stored in gd->hose for
  * later use, but will become invalid one DRAM is available.
  */
 int pci_early_init_hose(struct pci_controller **hosep);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 3daf73c..83fd9a0 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -19,6 +19,8 @@
 #include <asm/io.h>
 #include <pci.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
 #define PCI_HOSE_OP(rw, size, type)					\
 int pci_hose_##rw##_config_##size(struct pci_controller *hose,		\
 				  pci_dev_t dev,			\
@@ -123,6 +125,14 @@ void *pci_map_bar(pci_dev_t pdev, int bar, int flags)
 
 static struct pci_controller* hose_head;
 
+struct pci_controller *pci_get_hose_head(void)
+{
+	if (gd->hose)
+		return gd->hose;
+
+	return hose_head;
+}
+
 void pci_register_hose(struct pci_controller* hose)
 {
 	struct pci_controller **phose = &hose_head;
@@ -139,7 +149,7 @@ struct pci_controller *pci_bus_to_hose(int bus)
 {
 	struct pci_controller *hose;
 
-	for (hose = hose_head; hose; hose = hose->next) {
+	for (hose = pci_get_hose_head(); hose; hose = hose->next) {
 		if (bus >= hose->first_busno && bus <= hose->last_busno)
 			return hose;
 	}
@@ -152,7 +162,7 @@ struct pci_controller *find_hose_by_cfg_addr(void *cfg_addr)
 {
 	struct pci_controller *hose;
 
-	for (hose = hose_head; hose; hose = hose->next) {
+	for (hose = pci_get_hose_head(); hose; hose = hose->next) {
 		if (hose->cfg_addr == cfg_addr)
 			return hose;
 	}
@@ -162,7 +172,7 @@ struct pci_controller *find_hose_by_cfg_addr(void *cfg_addr)
 
 int pci_last_busno(void)
 {
-	struct pci_controller *hose = hose_head;
+	struct pci_controller *hose = pci_get_hose_head();
 
 	if (!hose)
 		return -1;
@@ -181,7 +191,7 @@ pci_dev_t pci_find_devices(struct pci_device_id *ids, int index)
 	pci_dev_t bdf;
 	int i, bus, found_multi = 0;
 
-	for (hose = hose_head; hose; hose = hose->next) {
+	for (hose = pci_get_hose_head(); hose; hose = hose->next) {
 #ifdef CONFIG_SYS_SCSI_SCAN_BUS_REVERSE
 		for (bus = hose->last_busno; bus >= hose->first_busno; bus--)
 #else
@@ -233,7 +243,7 @@ pci_dev_t pci_find_devices(struct pci_device_id *ids, int index)
 
 pci_dev_t pci_find_device(unsigned int vendor, unsigned int device, int index)
 {
-	static struct pci_device_id ids[2] = {{}, {0, 0}};
+	struct pci_device_id ids[2] = { {}, {0, 0} };
 
 	ids[0].vendor = vendor;
 	ids[0].device = device;
@@ -709,11 +719,10 @@ int pci_hose_scan_bus(struct pci_controller *hose, int bus)
 int pci_hose_scan(struct pci_controller *hose)
 {
 #if defined(CONFIG_PCI_BOOTDELAY)
-	static int pcidelay_done;
 	char *s;
 	int i;
 
-	if (!pcidelay_done) {
+	if (!gd->pcidelay_done) {
 		/* wait "pcidelay" ms (if defined)... */
 		s = getenv("pcidelay");
 		if (s) {
@@ -721,7 +730,7 @@ int pci_hose_scan(struct pci_controller *hose)
 			for (i = 0; i < val; i++)
 				udelay(1000);
 		}
-		pcidelay_done = 1;
+		gd->pcidelay_done = 1;
 	}
 #endif /* CONFIG_PCI_BOOTDELAY */
 
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index 9c5a1e1..3d14d5f 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -91,6 +91,12 @@ typedef struct global_data {
 	unsigned long malloc_limit;	/* limit address */
 	unsigned long malloc_ptr;	/* current address */
 #endif
+#ifdef CONFIG_PCI
+	struct pci_controller *hose;	/* PCI hose for early use */
+#endif
+#ifdef CONFIG_PCI_BOOTDELAY
+	int pcidelay_done;
+#endif
 	struct udevice *cur_serial_dev;	/* current serial device */
 	struct arch_global_data arch;	/* architecture-specific data */
 } gd_t;
-- 
1.8.2.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH v2 4/7] fdt: Add several apis to decode pci device node
  2014-12-27 12:10 [U-Boot] [PATCH v2 0/7] x86: Support pci based uart as the U-Boot serial console Bin Meng
                   ` (2 preceding siblings ...)
  2014-12-27 12:10 ` [U-Boot] [PATCH v2 3/7] pci: Make pci apis usable before relocation Bin Meng
@ 2014-12-27 12:10 ` Bin Meng
  2014-12-28  1:55   ` Simon Glass
  2014-12-27 12:10 ` [U-Boot] [PATCH v2 5/7] serial: ns16550: Support ns16550 compatible pci uart devices Bin Meng
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 20+ messages in thread
From: Bin Meng @ 2014-12-27 12:10 UTC (permalink / raw)
  To: u-boot

This commit adds several APIs to decode PCI device node according to
the Open Firmware PCI bus bindings, including:
- fdtdec_get_pci_addr() for encoded pci address
- fdtdec_get_pci_vendev() for vendor id and device id
- fdtdec_get_pci_bdf() for pci device bdf triplet
- fdtdec_get_pci_bar32() for pci device register bar

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>

---

Changes in v2:
- New patch to add several apis to decode pci device node

 include/fdtdec.h | 108 ++++++++++++++++++++++++++++++++++----
 lib/fdtdec.c     | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 240 insertions(+), 25 deletions(-)

diff --git a/include/fdtdec.h b/include/fdtdec.h
index d2b665c..2b2652f 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -50,6 +50,49 @@ struct fdt_resource {
 	fdt_addr_t end;
 };
 
+enum fdt_pci_space {
+	FDT_PCI_SPACE_CONFIG = 0,
+	FDT_PCI_SPACE_IO = 0x01000000,
+	FDT_PCI_SPACE_MEM32 = 0x02000000,
+	FDT_PCI_SPACE_MEM64 = 0x03000000,
+	FDT_PCI_SPACE_MEM32_PREF = 0x42000000,
+	FDT_PCI_SPACE_MEM64_PREF = 0x43000000,
+};
+
+#define FDT_PCI_ADDR_CELLS	3
+#define FDT_PCI_SIZE_CELLS	2
+#define FDT_PCI_REG_SIZE	\
+	((FDT_PCI_ADDR_CELLS + FDT_PCI_SIZE_CELLS) * sizeof(u32))
+
+/*
+ * The Open Firmware spec defines PCI physical address as follows:
+ *
+ *          bits# 31 .... 24 23 .... 16 15 .... 08 07 .... 00
+ *
+ * phys.hi  cell:  npt000ss   bbbbbbbb   dddddfff   rrrrrrrr
+ * phys.mid cell:  hhhhhhhh   hhhhhhhh   hhhhhhhh   hhhhhhhh
+ * phys.lo  cell:  llllllll   llllllll   llllllll   llllllll
+ *
+ * where:
+ *
+ * n:        is 0 if the address is relocatable, 1 otherwise
+ * p:        is 1 if addressable region is prefetchable, 0 otherwise
+ * t:        is 1 if the address is aliased (for non-relocatable I/O) below 1MB
+ *           (for Memory), or below 64KB (for relocatable I/O)
+ * ss:       is the space code, denoting the address space
+ * bbbbbbbb: is the 8-bit Bus Number
+ * ddddd:    is the 5-bit Device Number
+ * fff:      is the 3-bit Function Number
+ * rrrrrrrr: is the 8-bit Register Number
+ * hhhhhhhh: is a 32-bit unsigned number
+ * llllllll: is a 32-bit unsigned number
+ */
+struct fdt_pci_addr {
+	u32	phys_hi;
+	u32	phys_mid;
+	u32	phys_lo;
+};
+
 /**
  * Compute the size of a resource.
  *
@@ -252,6 +295,60 @@ fdt_addr_t fdtdec_get_addr_size(const void *blob, int node,
 		const char *prop_name, fdt_size_t *sizep);
 
 /**
+ * Look at an address property in a node and return the pci address which
+ * corresponds to the given type in the form of fdt_pci_addr.
+ * The property must hold one fdt_pci_addr with a lengh.
+ *
+ * @param blob		FDT blob
+ * @param node		node to examine
+ * @param type		pci address type (FDT_PCI_SPACE_xxx)
+ * @param prop_name	name of property to find
+ * @param addr		returns pci address in the form of fdt_pci_addr
+ * @return 0 if ok, negative on error
+ */
+int fdtdec_get_pci_addr(const void *blob, int node, enum fdt_pci_space type,
+		const char *prop_name, struct fdt_pci_addr *addr);
+
+/**
+ * Look at the compatible property of a device node that represents a PCI
+ * device and extract pci vendor id and device id from it.
+ *
+ * @param blob		FDT blob
+ * @param node		node to examine
+ * @param vendor	vendor id of the pci device
+ * @param device	device id of the pci device
+ * @return 0 if ok, negative on error
+ */
+int fdtdec_get_pci_vendev(const void *blob, int node,
+		u16 *vendor, u16 *device);
+
+/**
+ * Look at the pci address of a device node that represents a PCI device
+ * and parse the bus, device and function number from it.
+ *
+ * @param blob		FDT blob
+ * @param node		node to examine
+ * @param addr		pci address in the form of fdt_pci_addr
+ * @param bdf		returns bus, device, function triplet
+ * @return 0 if ok, negative on error
+ */
+int fdtdec_get_pci_bdf(const void *blob, int node,
+		struct fdt_pci_addr *addr, pci_dev_t *bdf);
+
+/**
+ * Look at the pci address of a device node that represents a PCI device
+ * and return base address of the pci device's registers.
+ *
+ * @param blob		FDT blob
+ * @param node		node to examine
+ * @param addr		pci address in the form of fdt_pci_addr
+ * @param bar		returns base address of the pci device's registers
+ * @return 0 if ok, negative on error
+ */
+int fdtdec_get_pci_bar32(const void *blob, int node,
+		struct fdt_pci_addr *addr, u32 *bar);
+
+/**
  * Look up a 32-bit integer property in a node and return it. The property
  * must have at least 4 bytes of data. The value of the first cell is
  * returned.
@@ -677,17 +774,6 @@ int fdt_get_named_resource(const void *fdt, int node, const char *property,
 			   struct fdt_resource *res);
 
 /**
- * Look at the reg property of a device node that represents a PCI device
- * and parse the bus, device and function number from it.
- *
- * @param fdt		FDT blob
- * @param node		node to examine
- * @param bdf		returns bus, device, function triplet
- * @return 0 if ok, negative on error
- */
-int fdtdec_pci_get_bdf(const void *fdt, int node, int *bdf);
-
-/**
  * Decode a named region within a memory bank of a given type.
  *
  * This function handles selection of a memory region. The region is
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 9d86dba..e40430e 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -121,6 +121,149 @@ fdt_addr_t fdtdec_get_addr(const void *blob, int node,
 	return fdtdec_get_addr_size(blob, node, prop_name, NULL);
 }
 
+#ifdef CONFIG_PCI
+int fdtdec_get_pci_addr(const void *blob, int node, enum fdt_pci_space type,
+		const char *prop_name, struct fdt_pci_addr *addr)
+{
+	const u32 *cell;
+	int len;
+
+	debug("%s: %s: ", __func__, prop_name);
+
+	/*
+	 * If we follow the pci bus bindings strictly, we should check
+	 * the value of the node's parant node's #address-cells and
+	 * #size-cells. They need to be 3 and 2 accordingly. However,
+	 * for simplicity we skip the check here.
+	 */
+	cell = fdt_getprop(blob, node, prop_name, &len);
+
+	if (cell && ((len % FDT_PCI_REG_SIZE) == 0)) {
+		int num = len / FDT_PCI_REG_SIZE;
+		int i;
+
+		for (i = 0; i < num; i++) {
+			if ((fdt_addr_to_cpu(*cell) & type) == type) {
+				addr->phys_hi = fdt_addr_to_cpu(cell[0]);
+				addr->phys_mid = fdt_addr_to_cpu(cell[1]);
+				addr->phys_lo = fdt_addr_to_cpu(cell[2]);
+				break;
+			} else {
+				cell += (FDT_PCI_ADDR_CELLS +
+					 FDT_PCI_SIZE_CELLS);
+			}
+		}
+
+		if (i == num)
+			goto fail;
+
+		return 0;
+	}
+
+fail:
+	debug("(not found)\n");
+	return -ENOENT;
+}
+
+int fdtdec_get_pci_vendev(const void *blob, int node, u16 *vendor, u16 *device)
+{
+	const char *list, *end;
+	int len;
+
+	list = fdt_getprop(blob, node, "compatible", &len);
+	if (!list)
+		return -ENOENT;
+
+	end = list + len;
+	while (list < end) {
+		int l = strlen(list);
+		char *s, v[5], d[5];
+
+		s = strstr(list, "pci");
+		/* check if the string is something like pciVVVV,DDDD */
+		if (s && s[7] == ',') {
+			s += 3;
+			strlcpy(v, s, 5);
+			s += 5;
+			strlcpy(d, s, 5);
+
+			*vendor = simple_strtol(v, NULL, 16);
+			*device = simple_strtol(d, NULL, 16);
+
+			return 0;
+		} else {
+			list += (l + 1);
+		}
+	}
+
+	return -ENOENT;
+}
+
+int fdtdec_get_pci_bdf(const void *blob, int node,
+		struct fdt_pci_addr *addr, pci_dev_t *bdf)
+{
+	u16 dt_vendor, dt_device, vendor, device;
+	int ret;
+
+	/* get vendor id & device id from the compatible string */
+	ret = fdtdec_get_pci_vendev(blob, node, &dt_vendor, &dt_device);
+	if (ret)
+		return ret;
+
+	/* extract the bdf from fdt_pci_addr */
+	*bdf = addr->phys_hi & 0xffff00;
+
+	/* read vendor id & device id based on bdf */
+	pci_read_config_word(*bdf, PCI_VENDOR_ID, &vendor);
+	pci_read_config_word(*bdf, PCI_DEVICE_ID, &device);
+
+	/*
+	 * Note there are two places in the device tree to fully describe
+	 * a pci device: one is via compatible string with a format of
+	 * "pciVVVV,DDDD" and the other one is the bdf numbers encoded in
+	 * the device node's reg address property. We read the vendor id
+	 * and device id based on bdf and compare the values with the
+	 * "VVVV,DDDD". If they are the same, then we are good to use bdf
+	 * to read device's bar. But if they are different, we have to rely
+	 * on the vendor id and device id extracted from the compatible
+	 * string and locate the real bdf by pci_find_device(). This is
+	 * because normally we may only know device's device number and
+	 * function number when writing device tree. The bus number is
+	 * dynamically assigned during the pci enumeration process.
+	 */
+	if ((dt_vendor != vendor) || (dt_device != device)) {
+		*bdf = pci_find_device(dt_vendor, dt_device, 0);
+		if (*bdf == -1)
+			return -ENODEV;
+	}
+
+	return 0;
+}
+
+int fdtdec_get_pci_bar32(const void *blob, int node,
+		struct fdt_pci_addr *addr, u32 *bar)
+{
+	pci_dev_t bdf;
+	int bn;
+	int ret;
+
+	/* get pci devices's bdf */
+	ret = fdtdec_get_pci_bdf(blob, node, addr, &bdf);
+	if (ret)
+		return ret;
+
+	/* extract the bar number from fdt_pci_addr */
+	bn = addr->phys_hi & 0xff;
+	if ((bn < PCI_BASE_ADDRESS_0) || (bn > PCI_CARDBUS_CIS))
+		return -EINVAL;
+
+	bn = (bn - PCI_BASE_ADDRESS_0) / 4;
+	*bar = pci_read_bar32(pci_bus_to_hose(PCI_BUS(bdf)), bdf, bn);
+
+	return 0;
+}
+#endif
+
 uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name,
 		uint64_t default_val)
 {
@@ -790,20 +933,6 @@ int fdt_get_named_resource(const void *fdt, int node, const char *property,
 	return fdt_get_resource(fdt, node, property, index, res);
 }
 
-int fdtdec_pci_get_bdf(const void *fdt, int node, int *bdf)
-{
-	const fdt32_t *prop;
-	int len;
-
-	prop = fdt_getprop(fdt, node, "reg", &len);
-	if (!prop)
-		return len;
-
-	*bdf = fdt32_to_cpu(*prop) & 0xffffff;
-
-	return 0;
-}
-
 int fdtdec_decode_memory_region(const void *blob, int config_node,
 				const char *mem_type, const char *suffix,
 				fdt_addr_t *basep, fdt_size_t *sizep)
-- 
1.8.2.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH v2 5/7] serial: ns16550: Support ns16550 compatible pci uart devices
  2014-12-27 12:10 [U-Boot] [PATCH v2 0/7] x86: Support pci based uart as the U-Boot serial console Bin Meng
                   ` (3 preceding siblings ...)
  2014-12-27 12:10 ` [U-Boot] [PATCH v2 4/7] fdt: Add several apis to decode pci device node Bin Meng
@ 2014-12-27 12:10 ` Bin Meng
  2014-12-28  1:55   ` Simon Glass
  2014-12-27 12:10 ` [U-Boot] [PATCH v2 6/7] x86: Use ePAPR defined properties for x86-uart Bin Meng
  2014-12-27 12:10 ` [U-Boot] [PATCH v2 7/7] x86: crownbay: Add pci devices in the dts file Bin Meng
  6 siblings, 1 reply; 20+ messages in thread
From: Bin Meng @ 2014-12-27 12:10 UTC (permalink / raw)
  To: u-boot

There are many pci uart devices which are ns16550 compatible. We can
describe them in the board dts file and use it as the U-Boot serial
console as specified in the chosen node 'stdout-path' property.

Those pci uart devices can have their register be memory mapped, or
i/o mapped. The driver will try to use memory mapped register if the
reg property in the node has an entry to describe the memory mapped
register, otherwise i/o mapped register will be used.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>

---

Changes in v2:
- New patch to support ns16550 compatible pci uart devices

 drivers/serial/ns16550.c | 33 ++++++++++++++++++++++++++++++++-
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
index af5beba..2001fac 100644
--- a/drivers/serial/ns16550.c
+++ b/drivers/serial/ns16550.c
@@ -289,10 +289,41 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev)
 	struct ns16550_platdata *plat = dev->platdata;
 	fdt_addr_t addr;
 
+	/* try plb device first */
 	addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
-	if (addr == FDT_ADDR_T_NONE)
+	if (addr == FDT_ADDR_T_NONE) {
+#ifdef CONFIG_PCI
+		/* then try pci device */
+		struct fdt_pci_addr pci_addr;
+		u32 bar;
+		int ret;
+
+		/* we prefer to use memory mapped register */
+		ret = fdtdec_get_pci_addr(gd->fdt_blob, dev->of_offset,
+					  FDT_PCI_SPACE_MEM32, "reg",
+					  &pci_addr);
+		if (ret) {
+			/* try if there is any io mapped register */
+			ret = fdtdec_get_pci_addr(gd->fdt_blob,
+						  dev->of_offset,
+						  FDT_PCI_SPACE_IO,
+						  "reg", &pci_addr);
+			if (ret)
+				return ret;
+		}
+
+		ret = fdtdec_get_pci_bar32(gd->fdt_blob, dev->of_offset,
+					   &pci_addr, &bar);
+		if (ret)
+			return ret;
+
+		addr = bar;
+		goto cont;
+#endif
 		return -EINVAL;
+	}
 
+cont:
 	plat->base = addr;
 	plat->reg_shift = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
 					 "reg-shift", 1);
-- 
1.8.2.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH v2 6/7] x86: Use ePAPR defined properties for x86-uart
  2014-12-27 12:10 [U-Boot] [PATCH v2 0/7] x86: Support pci based uart as the U-Boot serial console Bin Meng
                   ` (4 preceding siblings ...)
  2014-12-27 12:10 ` [U-Boot] [PATCH v2 5/7] serial: ns16550: Support ns16550 compatible pci uart devices Bin Meng
@ 2014-12-27 12:10 ` Bin Meng
  2014-12-28  1:55   ` Simon Glass
  2014-12-27 12:10 ` [U-Boot] [PATCH v2 7/7] x86: crownbay: Add pci devices in the dts file Bin Meng
  6 siblings, 1 reply; 20+ messages in thread
From: Bin Meng @ 2014-12-27 12:10 UTC (permalink / raw)
  To: u-boot

Use ePAPR defined properties for x86-uart: clock-frequency and
current-speed. Assign the value of clock-frequency in device tree
to plat->clock of x86-uart instead of using hardcoded number.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>

---

Changes in v2:
- New patch to use ePAPR defined properties for x86-uart

 arch/x86/dts/serial.dtsi    | 5 ++---
 drivers/serial/serial_x86.c | 8 +++++++-
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/arch/x86/dts/serial.dtsi b/arch/x86/dts/serial.dtsi
index ebdda76..9b097f4 100644
--- a/arch/x86/dts/serial.dtsi
+++ b/arch/x86/dts/serial.dtsi
@@ -3,8 +3,7 @@
 		compatible = "x86-uart";
 		reg = <0x3f8 8>;
 		reg-shift = <0>;
-		io-mapped = <1>;
-		multiplier = <1>;
-		baudrate = <115200>;
+		clock-frequency = <1843200>;
+		current-speed = <115200>;
 	};
 };
diff --git a/drivers/serial/serial_x86.c b/drivers/serial/serial_x86.c
index e81e035..4bf6062 100644
--- a/drivers/serial/serial_x86.c
+++ b/drivers/serial/serial_x86.c
@@ -6,9 +6,12 @@
 
 #include <common.h>
 #include <dm.h>
+#include <fdtdec.h>
 #include <ns16550.h>
 #include <serial.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
 static const struct udevice_id x86_serial_ids[] = {
 	{ .compatible = "x86-uart" },
 	{ }
@@ -22,10 +25,13 @@ static int x86_serial_ofdata_to_platdata(struct udevice *dev)
 	ret = ns16550_serial_ofdata_to_platdata(dev);
 	if (ret)
 		return ret;
-	plat->clock = 1843200;
+
+	plat->clock = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+				     "clock-frequency", 1843200);
 
 	return 0;
 }
+
 U_BOOT_DRIVER(serial_ns16550) = {
 	.name	= "serial_x86",
 	.id	= UCLASS_SERIAL,
-- 
1.8.2.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH v2 7/7] x86: crownbay: Add pci devices in the dts file
  2014-12-27 12:10 [U-Boot] [PATCH v2 0/7] x86: Support pci based uart as the U-Boot serial console Bin Meng
                   ` (5 preceding siblings ...)
  2014-12-27 12:10 ` [U-Boot] [PATCH v2 6/7] x86: Use ePAPR defined properties for x86-uart Bin Meng
@ 2014-12-27 12:10 ` Bin Meng
  2014-12-28  1:55   ` Simon Glass
  6 siblings, 1 reply; 20+ messages in thread
From: Bin Meng @ 2014-12-27 12:10 UTC (permalink / raw)
  To: u-boot

The Topcliff PCH has 4 UART devices integrated (Device 10, Funciton
1/2/3/4). Add the corresponding device nodes in the crownbay.dts per
Open Firmware PCI bus bindings.

Also a comment block is added for the 'stdout-path' property in the
chosen node, mentioning that by default the legacy superio serial
port (io addr 0x3f8) is still used on Crown Bay as the console port.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>

---

Changes in v2:
- New patch to add pci devices in crownbay.dts
- Drop v1 patch: Add an API for finding pci devices in the early phase
- Drop v1 patch: Support PCI UART in the x86_serial driver
- Drop v1 patch: Add PCI UART related defines in crownbay.h

 arch/x86/dts/crownbay.dts | 81 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 81 insertions(+)

diff --git a/arch/x86/dts/crownbay.dts b/arch/x86/dts/crownbay.dts
index 97f7a52..a42e0e4 100644
--- a/arch/x86/dts/crownbay.dts
+++ b/arch/x86/dts/crownbay.dts
@@ -32,6 +32,14 @@
 	};
 
 	chosen {
+		/*
+		 * By default the legacy superio serial port is used as the
+		 * U-Boot serial console. If we want to use UART from Topcliff
+		 * PCH as the console, change this property to &pciuart#.
+		 *
+		 * For example, stdout-path = &pciuart0 will use the first
+		 * UART on Topcliff PCH.
+		 */
 		stdout-path = "/serial";
 	};
 
@@ -52,4 +60,77 @@
 		};
 	};
 
+	pci {
+		#address-cells = <3>;
+		#size-cells = <2>;
+		compatible = "intel,pci";
+		device_type = "pci";
+
+		pcie at 17,0 {
+			#address-cells = <3>;
+			#size-cells = <2>;
+			compatible = "intel,pci";
+			device_type = "pci";
+
+			topcliff at 0,0 {
+				#address-cells = <3>;
+				#size-cells = <2>;
+				compatible = "intel,pci";
+				device_type = "pci";
+
+				pciuart0: uart at a,1 {
+					compatible = "pci8086,8811.0",
+							"pci8086,8811",
+							"pciclass070002",
+							"pciclass0700",
+							"x86-uart";
+					reg = <0x00025100 0x0 0x0 0x0 0x0
+					       0x01025110 0x0 0x0 0x0 0x0>;
+					reg-shift = <0>;
+					clock-frequency = <1843200>;
+					current-speed = <115200>;
+				};
+
+				pciuart1: uart at a,2 {
+					compatible = "pci8086,8812.0",
+							"pci8086,8812",
+							"pciclass070002",
+							"pciclass0700",
+							"x86-uart";
+					reg = <0x00025200 0x0 0x0 0x0 0x0
+					       0x01025210 0x0 0x0 0x0 0x0>;
+					reg-shift = <0>;
+					clock-frequency = <1843200>;
+					current-speed = <115200>;
+				};
+
+				pciuart2: uart at a,3 {
+					compatible = "pci8086,8813.0",
+							"pci8086,8813",
+							"pciclass070002",
+							"pciclass0700",
+							"x86-uart";
+					reg = <0x00025300 0x0 0x0 0x0 0x0
+					       0x01025310 0x0 0x0 0x0 0x0>;
+					reg-shift = <0>;
+					clock-frequency = <1843200>;
+					current-speed = <115200>;
+				};
+
+				pciuart3: uart at a,4 {
+					compatible = "pci8086,8814.0",
+							"pci8086,8814",
+							"pciclass070002",
+							"pciclass0700",
+							"x86-uart";
+					reg = <0x00025400 0x0 0x0 0x0 0x0
+					       0x01025410 0x0 0x0 0x0 0x0>;
+					reg-shift = <0>;
+					clock-frequency = <1843200>;
+					current-speed = <115200>;
+				};
+			};
+		};
+	};
+
 };
-- 
1.8.2.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH v2 1/7] x86: Add missing DECLARE_GLOBAL_DATA_PTR for pci.c
  2014-12-27 12:10 ` [U-Boot] [PATCH v2 1/7] x86: Add missing DECLARE_GLOBAL_DATA_PTR for pci.c Bin Meng
@ 2014-12-28  1:55   ` Simon Glass
  0 siblings, 0 replies; 20+ messages in thread
From: Simon Glass @ 2014-12-28  1:55 UTC (permalink / raw)
  To: u-boot

On 27 December 2014 at 05:10, Bin Meng <bmeng.cn@gmail.com> wrote:
> arch/x86/cpu/pci.c has access to the U-Boot global data thus
> DECLARE_GLOBAL_DATA_PTR is needed.
>
> Signed-off-by: Bin Meng <bmeng.cn@gmail.com>

Acked-by: Simon Glass <sjg@chromium.org>

>
> ---
>
> Changes in v2:
> - Add a commit message
>
>  arch/x86/cpu/pci.c | 2 ++
>  1 file changed, 2 insertions(+)

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH v2 2/7] x86: Support pci bus scan in the early phase
  2014-12-27 12:10 ` [U-Boot] [PATCH v2 2/7] x86: Support pci bus scan in the early phase Bin Meng
@ 2014-12-28  1:55   ` Simon Glass
  0 siblings, 0 replies; 20+ messages in thread
From: Simon Glass @ 2014-12-28  1:55 UTC (permalink / raw)
  To: u-boot

On 27 December 2014 at 05:10, Bin Meng <bmeng.cn@gmail.com> wrote:
> On x86, some peripherals on pci buses need to be accessed in the
> early phase (eg: pci uart) with a valid pci memory/io address,
> thus scan the pci bus and do the corresponding resource allocation.
>
> Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
> ---
>
> Changes in v2: None

Acked-by: Simon Glass <sjg@chromium.org>

>
>  arch/x86/cpu/pci.c | 1 +
>  1 file changed, 1 insertion(+)

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH v2 3/7] pci: Make pci apis usable before relocation
  2014-12-27 12:10 ` [U-Boot] [PATCH v2 3/7] pci: Make pci apis usable before relocation Bin Meng
@ 2014-12-28  1:55   ` Simon Glass
  0 siblings, 0 replies; 20+ messages in thread
From: Simon Glass @ 2014-12-28  1:55 UTC (permalink / raw)
  To: u-boot

On 27 December 2014 at 05:10, Bin Meng <bmeng.cn@gmail.com> wrote:
> Introduce a gd->hose to save the pci hose in the early phase so that
> apis in drivers/pci/pci.c can be used before relocation. Architecture
> codes need assign a valid gd->hose in the early phase.
>
> Some variables are declared as static so change them to be either
> stack variable or global data member so that they can be used before
> relocation, except the 'indent' used by CONFIG_PCI_SCAN_SHOW which
> just affects some print format.
>
> Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
>

I was actually thinking of making it available only for x86, but in
fact it makes sense so provide this as a global facility. The less
arch-specific stuff we add to global_data the better.

Acked-by: Simon Glass <sjg@chromium.org>

> ---
>
> Changes in v2:
> - New patch to make pci apis usable before relocation
>
>  arch/x86/cpu/pci.c                 |  8 ++++----
>  arch/x86/include/asm/global_data.h |  1 -
>  arch/x86/include/asm/pci.h         |  2 +-
>  drivers/pci/pci.c                  | 25 +++++++++++++++++--------
>  include/asm-generic/global_data.h  |  6 ++++++
>  5 files changed, 28 insertions(+), 14 deletions(-)

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH v2 4/7] fdt: Add several apis to decode pci device node
  2014-12-27 12:10 ` [U-Boot] [PATCH v2 4/7] fdt: Add several apis to decode pci device node Bin Meng
@ 2014-12-28  1:55   ` Simon Glass
  2014-12-30 14:45     ` Bin Meng
  0 siblings, 1 reply; 20+ messages in thread
From: Simon Glass @ 2014-12-28  1:55 UTC (permalink / raw)
  To: u-boot

Hi Bin,

On 27 December 2014 at 05:10, Bin Meng <bmeng.cn@gmail.com> wrote:
> This commit adds several APIs to decode PCI device node according to
> the Open Firmware PCI bus bindings, including:
> - fdtdec_get_pci_addr() for encoded pci address
> - fdtdec_get_pci_vendev() for vendor id and device id
> - fdtdec_get_pci_bdf() for pci device bdf triplet
> - fdtdec_get_pci_bar32() for pci device register bar
>
> Signed-off-by: Bin Meng <bmeng.cn@gmail.com>

Looks good - some minor comments below.

>
> ---
>
> Changes in v2:
> - New patch to add several apis to decode pci device node
>
>  include/fdtdec.h | 108 ++++++++++++++++++++++++++++++++++----
>  lib/fdtdec.c     | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
>  2 files changed, 240 insertions(+), 25 deletions(-)
>
> diff --git a/include/fdtdec.h b/include/fdtdec.h
> index d2b665c..2b2652f 100644
> --- a/include/fdtdec.h
> +++ b/include/fdtdec.h
> @@ -50,6 +50,49 @@ struct fdt_resource {
>         fdt_addr_t end;
>  };
>
> +enum fdt_pci_space {
> +       FDT_PCI_SPACE_CONFIG = 0,
> +       FDT_PCI_SPACE_IO = 0x01000000,
> +       FDT_PCI_SPACE_MEM32 = 0x02000000,
> +       FDT_PCI_SPACE_MEM64 = 0x03000000,
> +       FDT_PCI_SPACE_MEM32_PREF = 0x42000000,
> +       FDT_PCI_SPACE_MEM64_PREF = 0x43000000,
> +};
> +
> +#define FDT_PCI_ADDR_CELLS     3
> +#define FDT_PCI_SIZE_CELLS     2
> +#define FDT_PCI_REG_SIZE       \
> +       ((FDT_PCI_ADDR_CELLS + FDT_PCI_SIZE_CELLS) * sizeof(u32))
> +
> +/*
> + * The Open Firmware spec defines PCI physical address as follows:
> + *
> + *          bits# 31 .... 24 23 .... 16 15 .... 08 07 .... 00
> + *
> + * phys.hi  cell:  npt000ss   bbbbbbbb   dddddfff   rrrrrrrr
> + * phys.mid cell:  hhhhhhhh   hhhhhhhh   hhhhhhhh   hhhhhhhh
> + * phys.lo  cell:  llllllll   llllllll   llllllll   llllllll
> + *
> + * where:
> + *
> + * n:        is 0 if the address is relocatable, 1 otherwise
> + * p:        is 1 if addressable region is prefetchable, 0 otherwise
> + * t:        is 1 if the address is aliased (for non-relocatable I/O) below 1MB
> + *           (for Memory), or below 64KB (for relocatable I/O)
> + * ss:       is the space code, denoting the address space
> + * bbbbbbbb: is the 8-bit Bus Number
> + * ddddd:    is the 5-bit Device Number
> + * fff:      is the 3-bit Function Number
> + * rrrrrrrr: is the 8-bit Register Number
> + * hhhhhhhh: is a 32-bit unsigned number
> + * llllllll: is a 32-bit unsigned number
> + */
> +struct fdt_pci_addr {
> +       u32     phys_hi;
> +       u32     phys_mid;
> +       u32     phys_lo;
> +};
> +
>  /**
>   * Compute the size of a resource.
>   *
> @@ -252,6 +295,60 @@ fdt_addr_t fdtdec_get_addr_size(const void *blob, int node,
>                 const char *prop_name, fdt_size_t *sizep);
>
>  /**
> + * Look at an address property in a node and return the pci address which
> + * corresponds to the given type in the form of fdt_pci_addr.
> + * The property must hold one fdt_pci_addr with a lengh.
> + *
> + * @param blob         FDT blob
> + * @param node         node to examine
> + * @param type         pci address type (FDT_PCI_SPACE_xxx)
> + * @param prop_name    name of property to find
> + * @param addr         returns pci address in the form of fdt_pci_addr
> + * @return 0 if ok, negative on error
> + */
> +int fdtdec_get_pci_addr(const void *blob, int node, enum fdt_pci_space type,
> +               const char *prop_name, struct fdt_pci_addr *addr);
> +
> +/**
> + * Look at the compatible property of a device node that represents a PCI
> + * device and extract pci vendor id and device id from it.
> + *
> + * @param blob         FDT blob
> + * @param node         node to examine
> + * @param vendor       vendor id of the pci device
> + * @param device       device id of the pci device
> + * @return 0 if ok, negative on error
> + */
> +int fdtdec_get_pci_vendev(const void *blob, int node,
> +               u16 *vendor, u16 *device);
> +
> +/**
> + * Look at the pci address of a device node that represents a PCI device
> + * and parse the bus, device and function number from it.
> + *
> + * @param blob         FDT blob
> + * @param node         node to examine
> + * @param addr         pci address in the form of fdt_pci_addr
> + * @param bdf          returns bus, device, function triplet
> + * @return 0 if ok, negative on error
> + */
> +int fdtdec_get_pci_bdf(const void *blob, int node,
> +               struct fdt_pci_addr *addr, pci_dev_t *bdf);
> +
> +/**
> + * Look at the pci address of a device node that represents a PCI device
> + * and return base address of the pci device's registers.
> + *
> + * @param blob         FDT blob
> + * @param node         node to examine
> + * @param addr         pci address in the form of fdt_pci_addr
> + * @param bar          returns base address of the pci device's registers
> + * @return 0 if ok, negative on error
> + */
> +int fdtdec_get_pci_bar32(const void *blob, int node,
> +               struct fdt_pci_addr *addr, u32 *bar);
> +
> +/**
>   * Look up a 32-bit integer property in a node and return it. The property
>   * must have at least 4 bytes of data. The value of the first cell is
>   * returned.
> @@ -677,17 +774,6 @@ int fdt_get_named_resource(const void *fdt, int node, const char *property,
>                            struct fdt_resource *res);
>
>  /**
> - * Look at the reg property of a device node that represents a PCI device
> - * and parse the bus, device and function number from it.
> - *
> - * @param fdt          FDT blob
> - * @param node         node to examine
> - * @param bdf          returns bus, device, function triplet
> - * @return 0 if ok, negative on error
> - */
> -int fdtdec_pci_get_bdf(const void *fdt, int node, int *bdf);
> -
> -/**
>   * Decode a named region within a memory bank of a given type.
>   *
>   * This function handles selection of a memory region. The region is
> diff --git a/lib/fdtdec.c b/lib/fdtdec.c
> index 9d86dba..e40430e 100644
> --- a/lib/fdtdec.c
> +++ b/lib/fdtdec.c
> @@ -121,6 +121,149 @@ fdt_addr_t fdtdec_get_addr(const void *blob, int node,
>         return fdtdec_get_addr_size(blob, node, prop_name, NULL);
>  }
>
> +#ifdef CONFIG_PCI
> +int fdtdec_get_pci_addr(const void *blob, int node, enum fdt_pci_space type,
> +               const char *prop_name, struct fdt_pci_addr *addr)
> +{
> +       const u32 *cell;
> +       int len;
> +
> +       debug("%s: %s: ", __func__, prop_name);
> +
> +       /*
> +        * If we follow the pci bus bindings strictly, we should check
> +        * the value of the node's parant node's #address-cells and

parent

> +        * #size-cells. They need to be 3 and 2 accordingly. However,
> +        * for simplicity we skip the check here.
> +        */
> +       cell = fdt_getprop(blob, node, prop_name, &len);

I think it would be better to return -ENOENT if cell is NULL and
-EINVAL in the case where the number of cells is not a multiple of 5.

> +
> +       if (cell && ((len % FDT_PCI_REG_SIZE) == 0)) {
> +               int num = len / FDT_PCI_REG_SIZE;
> +               int i;
> +
> +               for (i = 0; i < num; i++) {
> +                       if ((fdt_addr_to_cpu(*cell) & type) == type) {
> +                               addr->phys_hi = fdt_addr_to_cpu(cell[0]);
> +                               addr->phys_mid = fdt_addr_to_cpu(cell[1]);
> +                               addr->phys_lo = fdt_addr_to_cpu(cell[2]);
> +                               break;
> +                       } else {
> +                               cell += (FDT_PCI_ADDR_CELLS +
> +                                        FDT_PCI_SIZE_CELLS);
> +                       }

You need a debug() in here to print stuff out, and a way of getting a
\n at the end.

> +               }
> +
> +               if (i == num)
> +                       goto fail;
> +
> +               return 0;
> +       }
> +
> +fail:
> +       debug("(not found)\n");
> +       return -ENOENT;
> +}
> +
> +int fdtdec_get_pci_vendev(const void *blob, int node, u16 *vendor, u16 *device)
> +{
> +       const char *list, *end;
> +       int len;
> +
> +       list = fdt_getprop(blob, node, "compatible", &len);
> +       if (!list)
> +               return -ENOENT;
> +
> +       end = list + len;
> +       while (list < end) {
> +               int l = strlen(list);

s/l/len/

> +               char *s, v[5], d[5];
> +
> +               s = strstr(list, "pci");
> +               /* check if the string is something like pciVVVV,DDDD */
> +               if (s && s[7] == ',') {

Should check that end - list > 7 otherwise s[7] might not exist. Also
how about checking for the '.'?

> +                       s += 3;
> +                       strlcpy(v, s, 5);
> +                       s += 5;
> +                       strlcpy(d, s, 5);
> +
> +                       *vendor = simple_strtol(v, NULL, 16);
> +                       *device = simple_strtol(d, NULL, 16);

I suspect you can avoid this - just use simple_strtol() directly on
the correct places in the string. The function will automatically stop
when it sees no more hex digits.

> +
> +                       return 0;
> +               } else {
> +                       list += (l + 1);
> +               }
> +       }
> +
> +       return -ENOENT;
> +}
> +
> +int fdtdec_get_pci_bdf(const void *blob, int node,
> +               struct fdt_pci_addr *addr, pci_dev_t *bdf)
> +{
> +       u16 dt_vendor, dt_device, vendor, device;
> +       int ret;
> +
> +       /* get vendor id & device id from the compatible string */
> +       ret = fdtdec_get_pci_vendev(blob, node, &dt_vendor, &dt_device);
> +       if (ret)
> +               return ret;
> +
> +       /* extract the bdf from fdt_pci_addr */
> +       *bdf = addr->phys_hi & 0xffff00;
> +
> +       /* read vendor id & device id based on bdf */
> +       pci_read_config_word(*bdf, PCI_VENDOR_ID, &vendor);
> +       pci_read_config_word(*bdf, PCI_DEVICE_ID, &device);

Check return values

> +
> +       /*
> +        * Note there are two places in the device tree to fully describe
> +        * a pci device: one is via compatible string with a format of
> +        * "pciVVVV,DDDD" and the other one is the bdf numbers encoded in
> +        * the device node's reg address property. We read the vendor id
> +        * and device id based on bdf and compare the values with the
> +        * "VVVV,DDDD". If they are the same, then we are good to use bdf
> +        * to read device's bar. But if they are different, we have to rely
> +        * on the vendor id and device id extracted from the compatible
> +        * string and locate the real bdf by pci_find_device(). This is
> +        * because normally we may only know device's device number and
> +        * function number when writing device tree. The bus number is
> +        * dynamically assigned during the pci enumeration process.
> +        */
> +       if ((dt_vendor != vendor) || (dt_device != device)) {
> +               *bdf = pci_find_device(dt_vendor, dt_device, 0);
> +               if (*bdf == -1)
> +                       return -ENODEV;
> +       }
> +
> +       return 0;
> +}
> +
> +int fdtdec_get_pci_bar32(const void *blob, int node,
> +               struct fdt_pci_addr *addr, u32 *bar)
> +{
> +       pci_dev_t bdf;
> +       int bn;

s/bn/barnum/ since it is self-documenting.

> +       int ret;
> +
> +       /* get pci devices's bdf */
> +       ret = fdtdec_get_pci_bdf(blob, node, addr, &bdf);
> +       if (ret)
> +               return ret;
> +
> +       /* extract the bar number from fdt_pci_addr */
> +       bn = addr->phys_hi & 0xff;
> +       if ((bn < PCI_BASE_ADDRESS_0) || (bn > PCI_CARDBUS_CIS))
> +               return -EINVAL;
> +
> +       bn = (bn - PCI_BASE_ADDRESS_0) / 4;
> +       *bar = pci_read_bar32(pci_bus_to_hose(PCI_BUS(bdf)), bdf, bn);
> +
> +       return 0;
> +}
> +#endif
> +
>  uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name,
>                 uint64_t default_val)
>  {
> @@ -790,20 +933,6 @@ int fdt_get_named_resource(const void *fdt, int node, const char *property,
>         return fdt_get_resource(fdt, node, property, index, res);
>  }
>
> -int fdtdec_pci_get_bdf(const void *fdt, int node, int *bdf)
> -{
> -       const fdt32_t *prop;
> -       int len;
> -
> -       prop = fdt_getprop(fdt, node, "reg", &len);
> -       if (!prop)
> -               return len;
> -
> -       *bdf = fdt32_to_cpu(*prop) & 0xffffff;
> -
> -       return 0;
> -}
> -
>  int fdtdec_decode_memory_region(const void *blob, int config_node,
>                                 const char *mem_type, const char *suffix,
>                                 fdt_addr_t *basep, fdt_size_t *sizep)
> --
> 1.8.2.1
>

Regards,
Simon

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH v2 5/7] serial: ns16550: Support ns16550 compatible pci uart devices
  2014-12-27 12:10 ` [U-Boot] [PATCH v2 5/7] serial: ns16550: Support ns16550 compatible pci uart devices Bin Meng
@ 2014-12-28  1:55   ` Simon Glass
  2014-12-29  6:15     ` Bin Meng
  0 siblings, 1 reply; 20+ messages in thread
From: Simon Glass @ 2014-12-28  1:55 UTC (permalink / raw)
  To: u-boot

Hi Bin,

On 27 December 2014 at 05:10, Bin Meng <bmeng.cn@gmail.com> wrote:
> There are many pci uart devices which are ns16550 compatible. We can
> describe them in the board dts file and use it as the U-Boot serial
> console as specified in the chosen node 'stdout-path' property.
>
> Those pci uart devices can have their register be memory mapped, or

memory-mapped

> i/o mapped. The driver will try to use memory mapped register if the

i/o-mapped

s/memory mapped/the memory-mapped/

> reg property in the node has an entry to describe the memory mapped

memory-mapped

> register, otherwise i/o mapped register will be used.

i/o-mapped

>
> Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
>
> ---
>
> Changes in v2:
> - New patch to support ns16550 compatible pci uart devices
>
>  drivers/serial/ns16550.c | 33 ++++++++++++++++++++++++++++++++-
>  1 file changed, 32 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
> index af5beba..2001fac 100644
> --- a/drivers/serial/ns16550.c
> +++ b/drivers/serial/ns16550.c
> @@ -289,10 +289,41 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev)
>         struct ns16550_platdata *plat = dev->platdata;
>         fdt_addr_t addr;
>
> +       /* try plb device first */

What is plb?

>         addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
> -       if (addr == FDT_ADDR_T_NONE)
> +       if (addr == FDT_ADDR_T_NONE) {
> +#ifdef CONFIG_PCI
> +               /* then try pci device */
> +               struct fdt_pci_addr pci_addr;
> +               u32 bar;
> +               int ret;
> +
> +               /* we prefer to use memory mapped register */

a memory-mapped

> +               ret = fdtdec_get_pci_addr(gd->fdt_blob, dev->of_offset,
> +                                         FDT_PCI_SPACE_MEM32, "reg",
> +                                         &pci_addr);
> +               if (ret) {
> +                       /* try if there is any io mapped register */
> +                       ret = fdtdec_get_pci_addr(gd->fdt_blob,
> +                                                 dev->of_offset,
> +                                                 FDT_PCI_SPACE_IO,
> +                                                 "reg", &pci_addr);
> +                       if (ret)
> +                               return ret;
> +               }
> +
> +               ret = fdtdec_get_pci_bar32(gd->fdt_blob, dev->of_offset,
> +                                          &pci_addr, &bar);
> +               if (ret)
> +                       return ret;
> +
> +               addr = bar;
> +               goto cont;
> +#endif
>                 return -EINVAL;
> +       }

Instead of the above 4 lines, move the #ifdef CONFIG_PCI up one line, then here:

   }
if (addr == FDT_ADDR_T_NONE)
   return -EINVAL;

This avoids the goto.

>
> +cont:
>         plat->base = addr;
>         plat->reg_shift = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
>                                          "reg-shift", 1);
> --
> 1.8.2.1
>

Regards,
Simon

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH v2 6/7] x86: Use ePAPR defined properties for x86-uart
  2014-12-27 12:10 ` [U-Boot] [PATCH v2 6/7] x86: Use ePAPR defined properties for x86-uart Bin Meng
@ 2014-12-28  1:55   ` Simon Glass
  2014-12-29  7:45     ` Bin Meng
  0 siblings, 1 reply; 20+ messages in thread
From: Simon Glass @ 2014-12-28  1:55 UTC (permalink / raw)
  To: u-boot

On 27 December 2014 at 05:10, Bin Meng <bmeng.cn@gmail.com> wrote:
> Use ePAPR defined properties for x86-uart: clock-frequency and
> current-speed. Assign the value of clock-frequency in device tree
> to plat->clock of x86-uart instead of using hardcoded number.
>
> Signed-off-by: Bin Meng <bmeng.cn@gmail.com>

>
> ---
>
> Changes in v2:
> - New patch to use ePAPR defined properties for x86-uart
>
>  arch/x86/dts/serial.dtsi    | 5 ++---
>  drivers/serial/serial_x86.c | 8 +++++++-
>  2 files changed, 9 insertions(+), 4 deletions(-)
>
> diff --git a/arch/x86/dts/serial.dtsi b/arch/x86/dts/serial.dtsi
> index ebdda76..9b097f4 100644
> --- a/arch/x86/dts/serial.dtsi
> +++ b/arch/x86/dts/serial.dtsi
> @@ -3,8 +3,7 @@
>                 compatible = "x86-uart";
>                 reg = <0x3f8 8>;
>                 reg-shift = <0>;
> -               io-mapped = <1>;
> -               multiplier = <1>;
> -               baudrate = <115200>;
> +               clock-frequency = <1843200>;
> +               current-speed = <115200>;

Where is current speed used? If it is needed, please update the
binding at doc/device-tree-bindings/serial/ns16550.txt

>         };
>  };
> diff --git a/drivers/serial/serial_x86.c b/drivers/serial/serial_x86.c
> index e81e035..4bf6062 100644
> --- a/drivers/serial/serial_x86.c
> +++ b/drivers/serial/serial_x86.c
> @@ -6,9 +6,12 @@
>
>  #include <common.h>
>  #include <dm.h>
> +#include <fdtdec.h>
>  #include <ns16550.h>
>  #include <serial.h>
>
> +DECLARE_GLOBAL_DATA_PTR;
> +
>  static const struct udevice_id x86_serial_ids[] = {
>         { .compatible = "x86-uart" },
>         { }
> @@ -22,10 +25,13 @@ static int x86_serial_ofdata_to_platdata(struct udevice *dev)
>         ret = ns16550_serial_ofdata_to_platdata(dev);
>         if (ret)
>                 return ret;
> -       plat->clock = 1843200;
> +
> +       plat->clock = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
> +                                    "clock-frequency", 1843200);
>
>         return 0;
>  }
> +
>  U_BOOT_DRIVER(serial_ns16550) = {
>         .name   = "serial_x86",
>         .id     = UCLASS_SERIAL,
> --
> 1.8.2.1
>

Regards,
Simon

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH v2 7/7] x86: crownbay: Add pci devices in the dts file
  2014-12-27 12:10 ` [U-Boot] [PATCH v2 7/7] x86: crownbay: Add pci devices in the dts file Bin Meng
@ 2014-12-28  1:55   ` Simon Glass
  0 siblings, 0 replies; 20+ messages in thread
From: Simon Glass @ 2014-12-28  1:55 UTC (permalink / raw)
  To: u-boot

On 27 December 2014 at 05:10, Bin Meng <bmeng.cn@gmail.com> wrote:
> The Topcliff PCH has 4 UART devices integrated (Device 10, Funciton
> 1/2/3/4). Add the corresponding device nodes in the crownbay.dts per
> Open Firmware PCI bus bindings.
>
> Also a comment block is added for the 'stdout-path' property in the
> chosen node, mentioning that by default the legacy superio serial
> port (io addr 0x3f8) is still used on Crown Bay as the console port.
>
> Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
>
> ---
>
> Changes in v2:
> - New patch to add pci devices in crownbay.dts
> - Drop v1 patch: Add an API for finding pci devices in the early phase
> - Drop v1 patch: Support PCI UART in the x86_serial driver
> - Drop v1 patch: Add PCI UART related defines in crownbay.h
>
>  arch/x86/dts/crownbay.dts | 81 +++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 81 insertions(+)

Acked-by: Simon Glass <sjg@chromium.org>

This looks like a very useful series. It should support just about any
serial port we might want to use.

Regards,
Simon

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH v2 5/7] serial: ns16550: Support ns16550 compatible pci uart devices
  2014-12-28  1:55   ` Simon Glass
@ 2014-12-29  6:15     ` Bin Meng
  2014-12-29 16:11       ` Simon Glass
  0 siblings, 1 reply; 20+ messages in thread
From: Bin Meng @ 2014-12-29  6:15 UTC (permalink / raw)
  To: u-boot

Hi Simon,

On Sun, Dec 28, 2014 at 9:55 AM, Simon Glass <sjg@chromium.org> wrote:
> Hi Bin,
>
> On 27 December 2014 at 05:10, Bin Meng <bmeng.cn@gmail.com> wrote:
>> There are many pci uart devices which are ns16550 compatible. We can
>> describe them in the board dts file and use it as the U-Boot serial
>> console as specified in the chosen node 'stdout-path' property.
>>
>> Those pci uart devices can have their register be memory mapped, or
>
> memory-mapped
>
>> i/o mapped. The driver will try to use memory mapped register if the
>
> i/o-mapped
>
> s/memory mapped/the memory-mapped/
>
>> reg property in the node has an entry to describe the memory mapped
>
> memory-mapped
>
>> register, otherwise i/o mapped register will be used.
>
> i/o-mapped
>
>>
>> Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
>>
>> ---
>>
>> Changes in v2:
>> - New patch to support ns16550 compatible pci uart devices
>>
>>  drivers/serial/ns16550.c | 33 ++++++++++++++++++++++++++++++++-
>>  1 file changed, 32 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
>> index af5beba..2001fac 100644
>> --- a/drivers/serial/ns16550.c
>> +++ b/drivers/serial/ns16550.c
>> @@ -289,10 +289,41 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev)
>>         struct ns16550_platdata *plat = dev->platdata;
>>         fdt_addr_t addr;
>>
>> +       /* try plb device first */
>
> What is plb?

I mean Processor Local Bus, a concept I believe is popular in the
embedded powerpc world, but I realized it might not be that popuar to
other architectures. Maybe I could just remove it.

>>         addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
>> -       if (addr == FDT_ADDR_T_NONE)
>> +       if (addr == FDT_ADDR_T_NONE) {
>> +#ifdef CONFIG_PCI
>> +               /* then try pci device */
>> +               struct fdt_pci_addr pci_addr;
>> +               u32 bar;
>> +               int ret;
>> +
>> +               /* we prefer to use memory mapped register */
>
> a memory-mapped
>
>> +               ret = fdtdec_get_pci_addr(gd->fdt_blob, dev->of_offset,
>> +                                         FDT_PCI_SPACE_MEM32, "reg",
>> +                                         &pci_addr);
>> +               if (ret) {
>> +                       /* try if there is any io mapped register */
>> +                       ret = fdtdec_get_pci_addr(gd->fdt_blob,
>> +                                                 dev->of_offset,
>> +                                                 FDT_PCI_SPACE_IO,
>> +                                                 "reg", &pci_addr);
>> +                       if (ret)
>> +                               return ret;
>> +               }
>> +
>> +               ret = fdtdec_get_pci_bar32(gd->fdt_blob, dev->of_offset,
>> +                                          &pci_addr, &bar);
>> +               if (ret)
>> +                       return ret;
>> +
>> +               addr = bar;
>> +               goto cont;
>> +#endif
>>                 return -EINVAL;
>> +       }
>
> Instead of the above 4 lines, move the #ifdef CONFIG_PCI up one line, then here:
>
>    }
> if (addr == FDT_ADDR_T_NONE)
>    return -EINVAL;
>
> This avoids the goto.

Yep, this is better. Will fix it.

>>
>> +cont:
>>         plat->base = addr;
>>         plat->reg_shift = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
>>                                          "reg-shift", 1);
>> --
>> 1.8.2.1
>>

Regards,
Bin

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH v2 6/7] x86: Use ePAPR defined properties for x86-uart
  2014-12-28  1:55   ` Simon Glass
@ 2014-12-29  7:45     ` Bin Meng
  2014-12-29 20:08       ` Simon Glass
  0 siblings, 1 reply; 20+ messages in thread
From: Bin Meng @ 2014-12-29  7:45 UTC (permalink / raw)
  To: u-boot

Hi Simon,

On Sun, Dec 28, 2014 at 9:55 AM, Simon Glass <sjg@chromium.org> wrote:
> On 27 December 2014 at 05:10, Bin Meng <bmeng.cn@gmail.com> wrote:
>> Use ePAPR defined properties for x86-uart: clock-frequency and
>> current-speed. Assign the value of clock-frequency in device tree
>> to plat->clock of x86-uart instead of using hardcoded number.
>>
>> Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
>
>>
>> ---
>>
>> Changes in v2:
>> - New patch to use ePAPR defined properties for x86-uart
>>
>>  arch/x86/dts/serial.dtsi    | 5 ++---
>>  drivers/serial/serial_x86.c | 8 +++++++-
>>  2 files changed, 9 insertions(+), 4 deletions(-)
>>
>> diff --git a/arch/x86/dts/serial.dtsi b/arch/x86/dts/serial.dtsi
>> index ebdda76..9b097f4 100644
>> --- a/arch/x86/dts/serial.dtsi
>> +++ b/arch/x86/dts/serial.dtsi
>> @@ -3,8 +3,7 @@
>>                 compatible = "x86-uart";
>>                 reg = <0x3f8 8>;
>>                 reg-shift = <0>;
>> -               io-mapped = <1>;
>> -               multiplier = <1>;
>> -               baudrate = <115200>;
>> +               clock-frequency = <1843200>;
>> +               current-speed = <115200>;
>
> Where is current speed used? If it is needed, please update the
> binding at doc/device-tree-bindings/serial/ns16550.txt
>

The current-speed is the baud rate of the serial port. Currently it is
put there for ePAPR completeness and not used by U-Boot as U-Boot is
using gd->baudrate for the serial console.

[snip]

Regards,
Bin

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH v2 5/7] serial: ns16550: Support ns16550 compatible pci uart devices
  2014-12-29  6:15     ` Bin Meng
@ 2014-12-29 16:11       ` Simon Glass
  0 siblings, 0 replies; 20+ messages in thread
From: Simon Glass @ 2014-12-29 16:11 UTC (permalink / raw)
  To: u-boot

Hi Bin,

On 28 December 2014 at 23:15, Bin Meng <bmeng.cn@gmail.com> wrote:
> Hi Simon,
>
> On Sun, Dec 28, 2014 at 9:55 AM, Simon Glass <sjg@chromium.org> wrote:
>> Hi Bin,
>>
>> On 27 December 2014 at 05:10, Bin Meng <bmeng.cn@gmail.com> wrote:
>>> There are many pci uart devices which are ns16550 compatible. We can
>>> describe them in the board dts file and use it as the U-Boot serial
>>> console as specified in the chosen node 'stdout-path' property.
>>>
>>> Those pci uart devices can have their register be memory mapped, or
>>
>> memory-mapped
>>
>>> i/o mapped. The driver will try to use memory mapped register if the
>>
>> i/o-mapped
>>
>> s/memory mapped/the memory-mapped/
>>
>>> reg property in the node has an entry to describe the memory mapped
>>
>> memory-mapped
>>
>>> register, otherwise i/o mapped register will be used.
>>
>> i/o-mapped
>>
>>>
>>> Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
>>>
>>> ---
>>>
>>> Changes in v2:
>>> - New patch to support ns16550 compatible pci uart devices
>>>
>>>  drivers/serial/ns16550.c | 33 ++++++++++++++++++++++++++++++++-
>>>  1 file changed, 32 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
>>> index af5beba..2001fac 100644
>>> --- a/drivers/serial/ns16550.c
>>> +++ b/drivers/serial/ns16550.c
>>> @@ -289,10 +289,41 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev)
>>>         struct ns16550_platdata *plat = dev->platdata;
>>>         fdt_addr_t addr;
>>>
>>> +       /* try plb device first */
>>
>> What is plb?
>
> I mean Processor Local Bus, a concept I believe is popular in the
> embedded powerpc world, but I realized it might not be that popuar to
> other architectures. Maybe I could just remove it.

Seems fine, but might want to write it out in full.

>
>>>         addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
>>> -       if (addr == FDT_ADDR_T_NONE)
>>> +       if (addr == FDT_ADDR_T_NONE) {
>>> +#ifdef CONFIG_PCI
>>> +               /* then try pci device */
>>> +               struct fdt_pci_addr pci_addr;
>>> +               u32 bar;
>>> +               int ret;
>>> +
>>> +               /* we prefer to use memory mapped register */
>>
>> a memory-mapped
>>
>>> +               ret = fdtdec_get_pci_addr(gd->fdt_blob, dev->of_offset,
>>> +                                         FDT_PCI_SPACE_MEM32, "reg",
>>> +                                         &pci_addr);
>>> +               if (ret) {
>>> +                       /* try if there is any io mapped register */
>>> +                       ret = fdtdec_get_pci_addr(gd->fdt_blob,
>>> +                                                 dev->of_offset,
>>> +                                                 FDT_PCI_SPACE_IO,
>>> +                                                 "reg", &pci_addr);
>>> +                       if (ret)
>>> +                               return ret;
>>> +               }
>>> +
>>> +               ret = fdtdec_get_pci_bar32(gd->fdt_blob, dev->of_offset,
>>> +                                          &pci_addr, &bar);
>>> +               if (ret)
>>> +                       return ret;
>>> +
>>> +               addr = bar;
>>> +               goto cont;
>>> +#endif
>>>                 return -EINVAL;
>>> +       }
>>
>> Instead of the above 4 lines, move the #ifdef CONFIG_PCI up one line, then here:
>>
>>    }
>> if (addr == FDT_ADDR_T_NONE)
>>    return -EINVAL;
>>
>> This avoids the goto.
>
> Yep, this is better. Will fix it.
>
>>>
>>> +cont:
>>>         plat->base = addr;
>>>         plat->reg_shift = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
>>>                                          "reg-shift", 1);
>>> --
>>> 1.8.2.1

Regards,
Simon

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH v2 6/7] x86: Use ePAPR defined properties for x86-uart
  2014-12-29  7:45     ` Bin Meng
@ 2014-12-29 20:08       ` Simon Glass
  0 siblings, 0 replies; 20+ messages in thread
From: Simon Glass @ 2014-12-29 20:08 UTC (permalink / raw)
  To: u-boot

Hi Bin,

On 29 December 2014 at 00:45, Bin Meng <bmeng.cn@gmail.com> wrote:
> Hi Simon,
>
> On Sun, Dec 28, 2014 at 9:55 AM, Simon Glass <sjg@chromium.org> wrote:
>> On 27 December 2014 at 05:10, Bin Meng <bmeng.cn@gmail.com> wrote:
>>> Use ePAPR defined properties for x86-uart: clock-frequency and
>>> current-speed. Assign the value of clock-frequency in device tree
>>> to plat->clock of x86-uart instead of using hardcoded number.
>>>
>>> Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
>>
>>>
>>> ---
>>>
>>> Changes in v2:
>>> - New patch to use ePAPR defined properties for x86-uart
>>>
>>>  arch/x86/dts/serial.dtsi    | 5 ++---
>>>  drivers/serial/serial_x86.c | 8 +++++++-
>>>  2 files changed, 9 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/arch/x86/dts/serial.dtsi b/arch/x86/dts/serial.dtsi
>>> index ebdda76..9b097f4 100644
>>> --- a/arch/x86/dts/serial.dtsi
>>> +++ b/arch/x86/dts/serial.dtsi
>>> @@ -3,8 +3,7 @@
>>>                 compatible = "x86-uart";
>>>                 reg = <0x3f8 8>;
>>>                 reg-shift = <0>;
>>> -               io-mapped = <1>;
>>> -               multiplier = <1>;
>>> -               baudrate = <115200>;
>>> +               clock-frequency = <1843200>;
>>> +               current-speed = <115200>;
>>
>> Where is current speed used? If it is needed, please update the
>> binding at doc/device-tree-bindings/serial/ns16550.txt
>>
>
> The current-speed is the baud rate of the serial port. Currently it is
> put there for ePAPR completeness and not used by U-Boot as U-Boot is
> using gd->baudrate for the serial console.

OK I see, thanks.

Acked-by: Simon Glass <sjg@chromium.org>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH v2 4/7] fdt: Add several apis to decode pci device node
  2014-12-28  1:55   ` Simon Glass
@ 2014-12-30 14:45     ` Bin Meng
  0 siblings, 0 replies; 20+ messages in thread
From: Bin Meng @ 2014-12-30 14:45 UTC (permalink / raw)
  To: u-boot

Hi Simon,

On Sun, Dec 28, 2014 at 9:55 AM, Simon Glass <sjg@chromium.org> wrote:
> Hi Bin,
>
> On 27 December 2014 at 05:10, Bin Meng <bmeng.cn@gmail.com> wrote:
>> This commit adds several APIs to decode PCI device node according to
>> the Open Firmware PCI bus bindings, including:
>> - fdtdec_get_pci_addr() for encoded pci address
>> - fdtdec_get_pci_vendev() for vendor id and device id
>> - fdtdec_get_pci_bdf() for pci device bdf triplet
>> - fdtdec_get_pci_bar32() for pci device register bar
>>
>> Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
>
> Looks good - some minor comments below.
>
>>
>> ---
>>
>> Changes in v2:
>> - New patch to add several apis to decode pci device node
>>
>>  include/fdtdec.h | 108 ++++++++++++++++++++++++++++++++++----
>>  lib/fdtdec.c     | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
>>  2 files changed, 240 insertions(+), 25 deletions(-)
>>
>> diff --git a/include/fdtdec.h b/include/fdtdec.h
>> index d2b665c..2b2652f 100644
>> --- a/include/fdtdec.h
>> +++ b/include/fdtdec.h
>> @@ -50,6 +50,49 @@ struct fdt_resource {
>>         fdt_addr_t end;
>>  };
>>
>> +enum fdt_pci_space {
>> +       FDT_PCI_SPACE_CONFIG = 0,
>> +       FDT_PCI_SPACE_IO = 0x01000000,
>> +       FDT_PCI_SPACE_MEM32 = 0x02000000,
>> +       FDT_PCI_SPACE_MEM64 = 0x03000000,
>> +       FDT_PCI_SPACE_MEM32_PREF = 0x42000000,
>> +       FDT_PCI_SPACE_MEM64_PREF = 0x43000000,
>> +};
>> +
>> +#define FDT_PCI_ADDR_CELLS     3
>> +#define FDT_PCI_SIZE_CELLS     2
>> +#define FDT_PCI_REG_SIZE       \
>> +       ((FDT_PCI_ADDR_CELLS + FDT_PCI_SIZE_CELLS) * sizeof(u32))
>> +
>> +/*
>> + * The Open Firmware spec defines PCI physical address as follows:
>> + *
>> + *          bits# 31 .... 24 23 .... 16 15 .... 08 07 .... 00
>> + *
>> + * phys.hi  cell:  npt000ss   bbbbbbbb   dddddfff   rrrrrrrr
>> + * phys.mid cell:  hhhhhhhh   hhhhhhhh   hhhhhhhh   hhhhhhhh
>> + * phys.lo  cell:  llllllll   llllllll   llllllll   llllllll
>> + *
>> + * where:
>> + *
>> + * n:        is 0 if the address is relocatable, 1 otherwise
>> + * p:        is 1 if addressable region is prefetchable, 0 otherwise
>> + * t:        is 1 if the address is aliased (for non-relocatable I/O) below 1MB
>> + *           (for Memory), or below 64KB (for relocatable I/O)
>> + * ss:       is the space code, denoting the address space
>> + * bbbbbbbb: is the 8-bit Bus Number
>> + * ddddd:    is the 5-bit Device Number
>> + * fff:      is the 3-bit Function Number
>> + * rrrrrrrr: is the 8-bit Register Number
>> + * hhhhhhhh: is a 32-bit unsigned number
>> + * llllllll: is a 32-bit unsigned number
>> + */
>> +struct fdt_pci_addr {
>> +       u32     phys_hi;
>> +       u32     phys_mid;
>> +       u32     phys_lo;
>> +};
>> +
>>  /**
>>   * Compute the size of a resource.
>>   *
>> @@ -252,6 +295,60 @@ fdt_addr_t fdtdec_get_addr_size(const void *blob, int node,
>>                 const char *prop_name, fdt_size_t *sizep);
>>
>>  /**
>> + * Look at an address property in a node and return the pci address which
>> + * corresponds to the given type in the form of fdt_pci_addr.
>> + * The property must hold one fdt_pci_addr with a lengh.
>> + *
>> + * @param blob         FDT blob
>> + * @param node         node to examine
>> + * @param type         pci address type (FDT_PCI_SPACE_xxx)
>> + * @param prop_name    name of property to find
>> + * @param addr         returns pci address in the form of fdt_pci_addr
>> + * @return 0 if ok, negative on error
>> + */
>> +int fdtdec_get_pci_addr(const void *blob, int node, enum fdt_pci_space type,
>> +               const char *prop_name, struct fdt_pci_addr *addr);
>> +
>> +/**
>> + * Look at the compatible property of a device node that represents a PCI
>> + * device and extract pci vendor id and device id from it.
>> + *
>> + * @param blob         FDT blob
>> + * @param node         node to examine
>> + * @param vendor       vendor id of the pci device
>> + * @param device       device id of the pci device
>> + * @return 0 if ok, negative on error
>> + */
>> +int fdtdec_get_pci_vendev(const void *blob, int node,
>> +               u16 *vendor, u16 *device);
>> +
>> +/**
>> + * Look at the pci address of a device node that represents a PCI device
>> + * and parse the bus, device and function number from it.
>> + *
>> + * @param blob         FDT blob
>> + * @param node         node to examine
>> + * @param addr         pci address in the form of fdt_pci_addr
>> + * @param bdf          returns bus, device, function triplet
>> + * @return 0 if ok, negative on error
>> + */
>> +int fdtdec_get_pci_bdf(const void *blob, int node,
>> +               struct fdt_pci_addr *addr, pci_dev_t *bdf);
>> +
>> +/**
>> + * Look at the pci address of a device node that represents a PCI device
>> + * and return base address of the pci device's registers.
>> + *
>> + * @param blob         FDT blob
>> + * @param node         node to examine
>> + * @param addr         pci address in the form of fdt_pci_addr
>> + * @param bar          returns base address of the pci device's registers
>> + * @return 0 if ok, negative on error
>> + */
>> +int fdtdec_get_pci_bar32(const void *blob, int node,
>> +               struct fdt_pci_addr *addr, u32 *bar);
>> +
>> +/**
>>   * Look up a 32-bit integer property in a node and return it. The property
>>   * must have at least 4 bytes of data. The value of the first cell is
>>   * returned.
>> @@ -677,17 +774,6 @@ int fdt_get_named_resource(const void *fdt, int node, const char *property,
>>                            struct fdt_resource *res);
>>
>>  /**
>> - * Look at the reg property of a device node that represents a PCI device
>> - * and parse the bus, device and function number from it.
>> - *
>> - * @param fdt          FDT blob
>> - * @param node         node to examine
>> - * @param bdf          returns bus, device, function triplet
>> - * @return 0 if ok, negative on error
>> - */
>> -int fdtdec_pci_get_bdf(const void *fdt, int node, int *bdf);
>> -
>> -/**
>>   * Decode a named region within a memory bank of a given type.
>>   *
>>   * This function handles selection of a memory region. The region is
>> diff --git a/lib/fdtdec.c b/lib/fdtdec.c
>> index 9d86dba..e40430e 100644
>> --- a/lib/fdtdec.c
>> +++ b/lib/fdtdec.c
>> @@ -121,6 +121,149 @@ fdt_addr_t fdtdec_get_addr(const void *blob, int node,
>>         return fdtdec_get_addr_size(blob, node, prop_name, NULL);
>>  }
>>
>> +#ifdef CONFIG_PCI
>> +int fdtdec_get_pci_addr(const void *blob, int node, enum fdt_pci_space type,
>> +               const char *prop_name, struct fdt_pci_addr *addr)
>> +{
>> +       const u32 *cell;
>> +       int len;
>> +
>> +       debug("%s: %s: ", __func__, prop_name);
>> +
>> +       /*
>> +        * If we follow the pci bus bindings strictly, we should check
>> +        * the value of the node's parant node's #address-cells and
>
> parent

Fixed in v3.

>> +        * #size-cells. They need to be 3 and 2 accordingly. However,
>> +        * for simplicity we skip the check here.
>> +        */
>> +       cell = fdt_getprop(blob, node, prop_name, &len);
>
> I think it would be better to return -ENOENT if cell is NULL and
> -EINVAL in the case where the number of cells is not a multiple of 5.

Will do in v3.

>> +
>> +       if (cell && ((len % FDT_PCI_REG_SIZE) == 0)) {
>> +               int num = len / FDT_PCI_REG_SIZE;
>> +               int i;
>> +
>> +               for (i = 0; i < num; i++) {
>> +                       if ((fdt_addr_to_cpu(*cell) & type) == type) {
>> +                               addr->phys_hi = fdt_addr_to_cpu(cell[0]);
>> +                               addr->phys_mid = fdt_addr_to_cpu(cell[1]);
>> +                               addr->phys_lo = fdt_addr_to_cpu(cell[2]);
>> +                               break;
>> +                       } else {
>> +                               cell += (FDT_PCI_ADDR_CELLS +
>> +                                        FDT_PCI_SIZE_CELLS);
>> +                       }
>
> You need a debug() in here to print stuff out, and a way of getting a
> \n at the end.

Will do in v3.

>> +               }
>> +
>> +               if (i == num)
>> +                       goto fail;
>> +
>> +               return 0;
>> +       }
>> +
>> +fail:
>> +       debug("(not found)\n");
>> +       return -ENOENT;
>> +}
>> +
>> +int fdtdec_get_pci_vendev(const void *blob, int node, u16 *vendor, u16 *device)
>> +{
>> +       const char *list, *end;
>> +       int len;
>> +
>> +       list = fdt_getprop(blob, node, "compatible", &len);
>> +       if (!list)
>> +               return -ENOENT;
>> +
>> +       end = list + len;
>> +       while (list < end) {
>> +               int l = strlen(list);
>
> s/l/len/

Will do in v3.

>> +               char *s, v[5], d[5];
>> +
>> +               s = strstr(list, "pci");
>> +               /* check if the string is something like pciVVVV,DDDD */
>> +               if (s && s[7] == ',') {
>
> Should check that end - list > 7 otherwise s[7] might not exist. Also
> how about checking for the '.'?

Will do in v3.

>> +                       s += 3;
>> +                       strlcpy(v, s, 5);
>> +                       s += 5;
>> +                       strlcpy(d, s, 5);
>> +
>> +                       *vendor = simple_strtol(v, NULL, 16);
>> +                       *device = simple_strtol(d, NULL, 16);
>
> I suspect you can avoid this - just use simple_strtol() directly on
> the correct places in the string. The function will automatically stop
> when it sees no more hex digits.

Yes, you are right. Will fix this.

>> +
>> +                       return 0;
>> +               } else {
>> +                       list += (l + 1);
>> +               }
>> +       }
>> +
>> +       return -ENOENT;
>> +}
>> +
>> +int fdtdec_get_pci_bdf(const void *blob, int node,
>> +               struct fdt_pci_addr *addr, pci_dev_t *bdf)
>> +{
>> +       u16 dt_vendor, dt_device, vendor, device;
>> +       int ret;
>> +
>> +       /* get vendor id & device id from the compatible string */
>> +       ret = fdtdec_get_pci_vendev(blob, node, &dt_vendor, &dt_device);
>> +       if (ret)
>> +               return ret;
>> +
>> +       /* extract the bdf from fdt_pci_addr */
>> +       *bdf = addr->phys_hi & 0xffff00;
>> +
>> +       /* read vendor id & device id based on bdf */
>> +       pci_read_config_word(*bdf, PCI_VENDOR_ID, &vendor);
>> +       pci_read_config_word(*bdf, PCI_DEVICE_ID, &device);
>
> Check return values

I think there is no need to check return values, as if there is
anything wrong with the pci_read_config_word() call, the vendor/device
will be set to 0xffff, which are invalid values and will fail at the
codes below.

>> +
>> +       /*
>> +        * Note there are two places in the device tree to fully describe
>> +        * a pci device: one is via compatible string with a format of
>> +        * "pciVVVV,DDDD" and the other one is the bdf numbers encoded in
>> +        * the device node's reg address property. We read the vendor id
>> +        * and device id based on bdf and compare the values with the
>> +        * "VVVV,DDDD". If they are the same, then we are good to use bdf
>> +        * to read device's bar. But if they are different, we have to rely
>> +        * on the vendor id and device id extracted from the compatible
>> +        * string and locate the real bdf by pci_find_device(). This is
>> +        * because normally we may only know device's device number and
>> +        * function number when writing device tree. The bus number is
>> +        * dynamically assigned during the pci enumeration process.
>> +        */
>> +       if ((dt_vendor != vendor) || (dt_device != device)) {
>> +               *bdf = pci_find_device(dt_vendor, dt_device, 0);
>> +               if (*bdf == -1)
>> +                       return -ENODEV;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +int fdtdec_get_pci_bar32(const void *blob, int node,
>> +               struct fdt_pci_addr *addr, u32 *bar)
>> +{
>> +       pci_dev_t bdf;
>> +       int bn;
>
> s/bn/barnum/ since it is self-documenting.

Will do in v3.

[snip]

Regards,
Bin

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2014-12-30 14:45 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-12-27 12:10 [U-Boot] [PATCH v2 0/7] x86: Support pci based uart as the U-Boot serial console Bin Meng
2014-12-27 12:10 ` [U-Boot] [PATCH v2 1/7] x86: Add missing DECLARE_GLOBAL_DATA_PTR for pci.c Bin Meng
2014-12-28  1:55   ` Simon Glass
2014-12-27 12:10 ` [U-Boot] [PATCH v2 2/7] x86: Support pci bus scan in the early phase Bin Meng
2014-12-28  1:55   ` Simon Glass
2014-12-27 12:10 ` [U-Boot] [PATCH v2 3/7] pci: Make pci apis usable before relocation Bin Meng
2014-12-28  1:55   ` Simon Glass
2014-12-27 12:10 ` [U-Boot] [PATCH v2 4/7] fdt: Add several apis to decode pci device node Bin Meng
2014-12-28  1:55   ` Simon Glass
2014-12-30 14:45     ` Bin Meng
2014-12-27 12:10 ` [U-Boot] [PATCH v2 5/7] serial: ns16550: Support ns16550 compatible pci uart devices Bin Meng
2014-12-28  1:55   ` Simon Glass
2014-12-29  6:15     ` Bin Meng
2014-12-29 16:11       ` Simon Glass
2014-12-27 12:10 ` [U-Boot] [PATCH v2 6/7] x86: Use ePAPR defined properties for x86-uart Bin Meng
2014-12-28  1:55   ` Simon Glass
2014-12-29  7:45     ` Bin Meng
2014-12-29 20:08       ` Simon Glass
2014-12-27 12:10 ` [U-Boot] [PATCH v2 7/7] x86: crownbay: Add pci devices in the dts file Bin Meng
2014-12-28  1:55   ` Simon Glass

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.