[U-Boot] [PATCH v2 00/12] x86: dm: pci: Support pci uart devices with driver model

This is the 2nd attempt to support pci uart devices with driver model. The v1 patch series is at [1].
Instead of creating a pci-specific device driver for ns16550 in v1, this v2 patch supports binding pci devices using device tree.
As previously mentioned in the ML, we should call fsp_notify() immediately after pci bus enumeration. Unfortunately with driver model, we have to put this call inside the pci_uclass_post_probe().
With this series, pci uart now works on Intel Crown Bay with driver model.
[1]: http://lists.denx.de/pipermail/u-boot/2015-August/223876.html
Changes in v2: - Drop the following v1 patches: - dm: pci: Only allow serial device to be bound before relocation - drivers: serial: Add ns16550 compatible pci uart driver - drivers: serial: Remove special handling for pci uart in the ns16550 driver - x86: crownbay: Support Topcliff integrated pci uart devices - x86: queensbay: Call fsp_init_phase_pci() again - Add some comments in x86_fsp_init() for malloc() adjustment
Bin Meng (12): dm: pci: Support selected device/driver binding before relocation x86: fsp: Delay x86_fsp_init() call a little bit x86: fsp: Enlarge the size of malloc() pool before relocation x86: fsp: Add comments about U-Boot entering start.S twice x86: queensbay: Move unprotect_spi_flash() to arch_misc_init() x86: baytrail: Remove the fsp_init_phase_pci() call x86: fsp: Call fsp_init_phase_pci() in pci_uclass_post_probe() dm: pci: Remove the unnecessary pci_bus_find_devfn() in pci_bind_bus_devices() fdtdec: Fix possible infinite loop in fdtdec_get_pci_vendev() dm: pci: Save devfn without bus number in pci_uclass_child_post_bind() dm: pci: Really support binding pci device in the device tree dm: pci: Document binding of pci device drivers
arch/x86/Kconfig | 9 +- arch/x86/cpu/baytrail/valleyview.c | 8 +- arch/x86/cpu/queensbay/tnc.c | 4 +- arch/x86/cpu/start.S | 14 ++- arch/x86/lib/fsp/fsp_car.S | 2 +- arch/x86/lib/fsp/fsp_common.c | 16 ++- common/board_f.c | 6 +- doc/driver-model/pci-info.txt | 25 ++++- drivers/pci/pci-uclass.c | 204 ++++++++++++++++++++++++++++++------- include/pci.h | 11 ++ lib/fdtdec.c | 3 +- 11 files changed, 246 insertions(+), 56 deletions(-)

On some platforms pci devices behind bridge need to be probed (eg: a pci uart on recent x86 chipset) before relocation. But we won't bind all devices found during the enumeration. Only devices whose driver with DM_FLAG_PRE_RELOC set will be bound. Any other generic devices except bridges won't be bound.
Signed-off-by: Bin Meng bmeng.cn@gmail.com Acked-by: Simon Glass sjg@chromium.org
---
Changes in v2: - Drop the following v1 patches: - dm: pci: Only allow serial device to be bound before relocation - drivers: serial: Add ns16550 compatible pci uart driver - drivers: serial: Remove special handling for pci uart in the ns16550 driver - x86: crownbay: Support Topcliff integrated pci uart devices - x86: queensbay: Call fsp_init_phase_pci() again
drivers/pci/pci-uclass.c | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-)
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 7d41d56..4160274 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -461,6 +461,7 @@ static int pci_find_and_bind_driver(struct udevice *parent, int n_ents; int ret; char name[30], *str; + bool bridge;
*devp = NULL;
@@ -480,6 +481,17 @@ static int pci_find_and_bind_driver(struct udevice *parent, continue;
drv = entry->driver; + + /* + * In the pre-relocation phase, we only bind devices + * whose driver has the DM_FLAG_PRE_RELOC set, to save + * precious memory space as on some platforms as that + * space is pretty limited (ie: using Cache As RAM). + */ + if (!(gd->flags & GD_FLG_RELOC) && + !(drv->flags & DM_FLAG_PRE_RELOC)) + return 0; + /* * We could pass the descriptor to the driver as * platdata (instead of NULL) and allow its bind() @@ -499,14 +511,23 @@ static int pci_find_and_bind_driver(struct udevice *parent, } }
+ bridge = (find_id->class >> 8) == PCI_CLASS_BRIDGE_PCI; + /* + * In the pre-relocation phase, we only bind bridge devices to save + * precious memory space as on some platforms as that space is pretty + * limited (ie: using Cache As RAM). + */ + if (!(gd->flags & GD_FLG_RELOC) && !bridge) + return 0; + /* Bind a generic driver so that the device can be used */ sprintf(name, "pci_%x:%x.%x", parent->seq, PCI_DEV(bdf), PCI_FUNC(bdf)); str = strdup(name); if (!str) return -ENOMEM; - drv = (find_id->class >> 8) == PCI_CLASS_BRIDGE_PCI ? "pci_bridge_drv" : - "pci_generic_drv"; + drv = bridge ? "pci_bridge_drv" : "pci_generic_drv"; + ret = device_bind_driver(parent, drv, str, devp); if (ret) { debug("%s: Failed to bind generic driver: %d", __func__, ret); @@ -589,11 +610,13 @@ int pci_bind_bus_devices(struct udevice *bus) return ret;
/* Update the platform data */ - pplat = dev_get_parent_platdata(dev); - pplat->devfn = PCI_MASK_BUS(bdf); - pplat->vendor = vendor; - pplat->device = device; - pplat->class = class; + if (dev) { + pplat = dev_get_parent_platdata(dev); + pplat->devfn = PCI_MASK_BUS(bdf); + pplat->vendor = vendor; + pplat->device = device; + pplat->class = class; + } }
return 0; @@ -717,10 +740,6 @@ static int pci_uclass_post_probe(struct udevice *bus) { int ret;
- /* Don't scan buses before relocation */ - if (!(gd->flags & GD_FLG_RELOC)) - return 0; - debug("%s: probing bus %d\n", __func__, bus->seq); ret = pci_bind_bus_devices(bus); if (ret)

On 20 August 2015 at 07:40, Bin Meng bmeng.cn@gmail.com wrote:
On some platforms pci devices behind bridge need to be probed (eg: a pci uart on recent x86 chipset) before relocation. But we won't bind all devices found during the enumeration. Only devices whose driver with DM_FLAG_PRE_RELOC set will be bound. Any other generic devices except bridges won't be bound.
Signed-off-by: Bin Meng bmeng.cn@gmail.com Acked-by: Simon Glass sjg@chromium.org
Changes in v2:
- Drop the following v1 patches:
- dm: pci: Only allow serial device to be bound before relocation
- drivers: serial: Add ns16550 compatible pci uart driver
- drivers: serial: Remove special handling for pci uart in the ns16550 driver
- x86: crownbay: Support Topcliff integrated pci uart devices
- x86: queensbay: Call fsp_init_phase_pci() again
drivers/pci/pci-uclass.c | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-)
Applied to u-boot-x86, thanks!

Move x86_fsp_init() call after initf_malloc() so that we can fix up the gd->malloc_limit later.
Signed-off-by: Bin Meng bmeng.cn@gmail.com Acked-by: Simon Glass sjg@chromium.org ---
Changes in v2: None
common/board_f.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/common/board_f.c b/common/board_f.c index c959774..5155013 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -765,9 +765,6 @@ static init_fnc_t init_sequence_f[] = { #ifdef CONFIG_OF_CONTROL fdtdec_setup, #endif -#if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP) - x86_fsp_init, -#endif #ifdef CONFIG_TRACE trace_early_init, #endif @@ -776,6 +773,9 @@ static init_fnc_t init_sequence_f[] = { /* TODO: can this go into arch_cpu_init()? */ probecpu, #endif +#if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP) + x86_fsp_init, +#endif arch_cpu_init, /* basic arch cpu dependent setup */ mark_bootstage, initf_dm,

On 20 August 2015 at 07:40, Bin Meng bmeng.cn@gmail.com wrote:
Move x86_fsp_init() call after initf_malloc() so that we can fix up the gd->malloc_limit later.
Signed-off-by: Bin Meng bmeng.cn@gmail.com Acked-by: Simon Glass sjg@chromium.org
Changes in v2: None
common/board_f.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
Applied to u-boot-x86, thanks!

After fsp_init() returns, the stack has already been switched to a place within system memory as defined by CONFIG_FSP_TEMP_RAM_ADDR. Enlarge the size of malloc() pool before relocation since we have plenty of memory now.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
---
Changes in v2: - Add some comments in x86_fsp_init() for malloc() adjustment
arch/x86/Kconfig | 7 +++++++ arch/x86/cpu/start.S | 8 ++++++++ arch/x86/lib/fsp/fsp_common.c | 16 +++++++++++++++- 3 files changed, 30 insertions(+), 1 deletion(-)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 065bbe4..687208f 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -232,6 +232,13 @@ config FSP_TEMP_RAM_ADDR Stack top address which is used in FspInit after DRAM is ready and CAR is disabled.
+config FSP_SYS_MALLOC_F_LEN + hex + depends on HAVE_FSP + default 0x100000 + help + Additional size of malloc() pool before relocation. + config SMP bool "Enable Symmetric Multiprocessing" default n diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index e94ddc4..e2b5ef4 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -141,6 +141,14 @@ car_init_ret: jz skip_hob movl %esi, GD_HOB_LIST(%edx)
+ /* + * After fsp_init() returns, the stack has already been switched to a + * place within system memory as defined by CONFIG_FSP_TEMP_RAM_ADDR. + * Enlarge the size of malloc() pool before relocation since we have + * plenty of memory now. + */ + subl $CONFIG_FSP_SYS_MALLOC_F_LEN, %esp + movl %esp, GD_MALLOC_BASE(%edx) skip_hob: #else /* Store table pointer */ diff --git a/arch/x86/lib/fsp/fsp_common.c b/arch/x86/lib/fsp/fsp_common.c index d564cb9..658f32d 100644 --- a/arch/x86/lib/fsp/fsp_common.c +++ b/arch/x86/lib/fsp/fsp_common.c @@ -56,8 +56,22 @@ void board_final_cleanup(void)
int x86_fsp_init(void) { - if (!gd->arch.hob_list) + if (!gd->arch.hob_list) { + /* + * The first time we enter here, call fsp_init(). + * Note the execution does not return to this function, + * instead it jumps to fsp_continue(). + */ fsp_init(CONFIG_FSP_TEMP_RAM_ADDR, BOOT_FULL_CONFIG, NULL); + } else { + /* + * The second time we enter here, adjust the size of malloc() + * pool before relocation. Given gd->malloc_base was adjusted + * after the call to board_init_f_mem() in arch/x86/cpu/start.S, + * we should fix up gd->malloc_limit here. + */ + gd->malloc_limit += CONFIG_FSP_SYS_MALLOC_F_LEN; + }
return 0; }

On 20 August 2015 at 07:40, Bin Meng bmeng.cn@gmail.com wrote:
After fsp_init() returns, the stack has already been switched to a place within system memory as defined by CONFIG_FSP_TEMP_RAM_ADDR. Enlarge the size of malloc() pool before relocation since we have plenty of memory now.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
Changes in v2:
- Add some comments in x86_fsp_init() for malloc() adjustment
arch/x86/Kconfig | 7 +++++++ arch/x86/cpu/start.S | 8 ++++++++ arch/x86/lib/fsp/fsp_common.c | 16 +++++++++++++++- 3 files changed, 30 insertions(+), 1 deletion(-)
Acked-by: Simon Glass sjg@chromium.org

On 21 August 2015 at 17:27, Simon Glass sjg@chromium.org wrote:
On 20 August 2015 at 07:40, Bin Meng bmeng.cn@gmail.com wrote:
After fsp_init() returns, the stack has already been switched to a place within system memory as defined by CONFIG_FSP_TEMP_RAM_ADDR. Enlarge the size of malloc() pool before relocation since we have plenty of memory now.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
Changes in v2:
- Add some comments in x86_fsp_init() for malloc() adjustment
arch/x86/Kconfig | 7 +++++++ arch/x86/cpu/start.S | 8 ++++++++ arch/x86/lib/fsp/fsp_common.c | 16 +++++++++++++++- 3 files changed, 30 insertions(+), 1 deletion(-)
Acked-by: Simon Glass sjg@chromium.org
Applied to u-boot-x86, thanks!

Add some comments in start.S for the fact that with FSP U-Boot actually enters the code twice. Also change to use fsp_init() and fsp_continue for accuracy.
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: None
arch/x86/Kconfig | 2 +- arch/x86/cpu/start.S | 6 ++++-- arch/x86/lib/fsp/fsp_car.S | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 687208f..273f08f 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -229,7 +229,7 @@ config FSP_TEMP_RAM_ADDR depends on HAVE_FSP default 0x2000000 help - Stack top address which is used in FspInit after DRAM is ready and + Stack top address which is used in fsp_init() after DRAM is ready and CAR is disabled.
config FSP_SYS_MALLOC_F_LEN diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index e2b5ef4..d072825 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -115,8 +115,10 @@ car_init_ret: #endif #else /* - * When we get here after car_init(), esp points to a temporary stack - * and esi holds the HOB list address returned by the FSP. + * U-Boot enters here twice. For the first time it comes from + * car_init_done() with esp points to a temporary stack and esi + * set to zero. For the second time it comes from fsp_init_done() + * with esi holding the HOB list address returned by the FSP. */ #endif /* Set up global data */ diff --git a/arch/x86/lib/fsp/fsp_car.S b/arch/x86/lib/fsp/fsp_car.S index afbf3f9..15b3751 100644 --- a/arch/x86/lib/fsp/fsp_car.S +++ b/arch/x86/lib/fsp/fsp_car.S @@ -64,7 +64,7 @@ temp_ram_init_ret: .global fsp_init_done fsp_init_done: /* - * We come here from FspInit with eax pointing to the HOB list. + * We come here from fsp_continue() with eax pointing to the HOB list. * Save eax to esi temporarily. */ movl %eax, %esi

On 20 August 2015 at 07:40, Bin Meng bmeng.cn@gmail.com wrote:
Add some comments in start.S for the fact that with FSP U-Boot actually enters the code twice. Also change to use fsp_init() and fsp_continue for accuracy.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
Changes in v2: None
arch/x86/Kconfig | 2 +- arch/x86/cpu/start.S | 6 ++++-- arch/x86/lib/fsp/fsp_car.S | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-)
Acked-by: Simon Glass sjg@chromium.org

On 21 August 2015 at 17:27, Simon Glass sjg@chromium.org wrote:
On 20 August 2015 at 07:40, Bin Meng bmeng.cn@gmail.com wrote:
Add some comments in start.S for the fact that with FSP U-Boot actually enters the code twice. Also change to use fsp_init() and fsp_continue for accuracy.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
Changes in v2: None
arch/x86/Kconfig | 2 +- arch/x86/cpu/start.S | 6 ++++-- arch/x86/lib/fsp/fsp_car.S | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-)
Acked-by: Simon Glass sjg@chromium.org
Applied to u-boot-x86, thanks!

With dm pci conversion, pci config read/write in unprotect_spi_flash() silently fails as at that time dm pci is not ready and bus enumeration is not done yet. Actually we don't need to do this in that early phase, hence we delay this call to arch_misc_init().
Signed-off-by: Bin Meng bmeng.cn@gmail.com
--- Simon's patch (http://patchwork.ozlabs.org/patch/506810/) should fix this pci config read/write silently failure issue. But it does not do any harm we move this to some late phase.
Changes in v2: None
arch/x86/cpu/queensbay/tnc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/x86/cpu/queensbay/tnc.c b/arch/x86/cpu/queensbay/tnc.c index c465642..9682cff 100644 --- a/arch/x86/cpu/queensbay/tnc.c +++ b/arch/x86/cpu/queensbay/tnc.c @@ -36,8 +36,6 @@ int arch_cpu_init(void) if (ret) return ret;
- unprotect_spi_flash(); - return 0; }
@@ -80,5 +78,7 @@ void cpu_irq_init(void)
int arch_misc_init(void) { + unprotect_spi_flash(); + return pirq_init(); }

On 20 August 2015 at 07:40, Bin Meng bmeng.cn@gmail.com wrote:
With dm pci conversion, pci config read/write in unprotect_spi_flash() silently fails as at that time dm pci is not ready and bus enumeration is not done yet. Actually we don't need to do this in that early phase, hence we delay this call to arch_misc_init().
Signed-off-by: Bin Meng bmeng.cn@gmail.com
Simon's patch (http://patchwork.ozlabs.org/patch/506810/) should fix this pci config read/write silently failure issue. But it does not do any harm we move this to some late phase.
Changes in v2: None
arch/x86/cpu/queensbay/tnc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
Acked-by: Simon Glass sjg@chromium.org

On 21 August 2015 at 17:27, Simon Glass sjg@chromium.org wrote:
On 20 August 2015 at 07:40, Bin Meng bmeng.cn@gmail.com wrote:
With dm pci conversion, pci config read/write in unprotect_spi_flash() silently fails as at that time dm pci is not ready and bus enumeration is not done yet. Actually we don't need to do this in that early phase, hence we delay this call to arch_misc_init().
Signed-off-by: Bin Meng bmeng.cn@gmail.com
Simon's patch (http://patchwork.ozlabs.org/patch/506810/) should fix this pci config read/write silently failure issue. But it does not do any harm we move this to some late phase.
Changes in v2: None
arch/x86/cpu/queensbay/tnc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
Acked-by: Simon Glass sjg@chromium.org
Applied to u-boot-x86, thanks!

It turns out that calling fsp_init_phase_pci() in arch_misc_init() is subject to break pci device drivers as with driver model, when the bus enumeration happens is not deterministic.
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: None
arch/x86/cpu/baytrail/valleyview.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-)
diff --git a/arch/x86/cpu/baytrail/valleyview.c b/arch/x86/cpu/baytrail/valleyview.c index 6c3dfe8..4baaae6 100644 --- a/arch/x86/cpu/baytrail/valleyview.c +++ b/arch/x86/cpu/baytrail/valleyview.c @@ -9,7 +9,6 @@ #include <pci_ids.h> #include <asm/irq.h> #include <asm/post.h> -#include <asm/fsp/fsp_support.h>
static struct pci_device_id mmc_supported[] = { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VALLEYVIEW_SDIO }, @@ -41,14 +40,9 @@ int arch_cpu_init(void)
int arch_misc_init(void) { - int ret; - if (!ll_boot_init()) return 0; - ret = pirq_init(); - if (ret) - return ret;
- return fsp_init_phase_pci(); + return pirq_init(); } #endif

On 20 August 2015 at 07:40, Bin Meng bmeng.cn@gmail.com wrote:
It turns out that calling fsp_init_phase_pci() in arch_misc_init() is subject to break pci device drivers as with driver model, when the bus enumeration happens is not deterministic.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
Changes in v2: None
arch/x86/cpu/baytrail/valleyview.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-)
Acked-by: Simon Glass sjg@chromium.org

On 21 August 2015 at 17:27, Simon Glass sjg@chromium.org wrote:
On 20 August 2015 at 07:40, Bin Meng bmeng.cn@gmail.com wrote:
It turns out that calling fsp_init_phase_pci() in arch_misc_init() is subject to break pci device drivers as with driver model, when the bus enumeration happens is not deterministic.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
Changes in v2: None
arch/x86/cpu/baytrail/valleyview.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-)
Acked-by: Simon Glass sjg@chromium.org
Applied to u-boot-x86, thanks!

Per Intel FSP specification, we should call FSP notify API to inform FSP that PCI enumeration has been done so that FSP will do any necessary initialization as required by the chipset's BIOS Writer's Guide (BWG).
Unfortunately we have to put this call here as with driver model, the enumeration is all done on a lazy basis as needed, so until something is touched on PCI it won't happen.
Note we only call this after U-Boot is relocated and root bus has finished probing.
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: None
drivers/pci/pci-uclass.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 4160274..c90e7ac 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -14,6 +14,9 @@ #include <dm/lists.h> #include <dm/root.h> #include <dm/device-internal.h> +#if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP) +#include <asm/fsp/fsp_support.h> +#endif
DECLARE_GLOBAL_DATA_PTR;
@@ -749,6 +752,24 @@ static int pci_uclass_post_probe(struct udevice *bus) ret = pci_auto_config_devices(bus); #endif
+#if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP) + /* + * Per Intel FSP specification, we should call FSP notify API to + * inform FSP that PCI enumeration has been done so that FSP will + * do any necessary initialization as required by the chipset's + * BIOS Writer's Guide (BWG). + * + * Unfortunately we have to put this call here as with driver model, + * the enumeration is all done on a lazy basis as needed, so until + * something is touched on PCI it won't happen. + * + * Note we only call this 1) after U-Boot is relocated, and 2) + * root bus has finished probing. + */ + if ((gd->flags & GD_FLG_RELOC) && (bus->seq == 0)) + ret = fsp_init_phase_pci(); +#endif + return ret < 0 ? ret : 0; }

Hi Bin,
On 20 August 2015 at 07:40, Bin Meng bmeng.cn@gmail.com wrote:
Per Intel FSP specification, we should call FSP notify API to inform FSP that PCI enumeration has been done so that FSP will do any necessary initialization as required by the chipset's BIOS Writer's Guide (BWG).
Unfortunately we have to put this call here as with driver model, the enumeration is all done on a lazy basis as needed, so until something is touched on PCI it won't happen.
Note we only call this after U-Boot is relocated and root bus has finished probing.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
Changes in v2: None
drivers/pci/pci-uclass.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
Acked-by: Simon Glass sjg@chromium.org
Please see below.
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 4160274..c90e7ac 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -14,6 +14,9 @@ #include <dm/lists.h> #include <dm/root.h> #include <dm/device-internal.h> +#if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP)
Do we need CONFIG_X86 here? Do you think it is better to have it to be clearer?
+#include <asm/fsp/fsp_support.h> +#endif
DECLARE_GLOBAL_DATA_PTR;
@@ -749,6 +752,24 @@ static int pci_uclass_post_probe(struct udevice *bus) ret = pci_auto_config_devices(bus); #endif
+#if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP)
/*
* Per Intel FSP specification, we should call FSP notify API to
* inform FSP that PCI enumeration has been done so that FSP will
* do any necessary initialization as required by the chipset's
* BIOS Writer's Guide (BWG).
*
* Unfortunately we have to put this call here as with driver model,
* the enumeration is all done on a lazy basis as needed, so until
* something is touched on PCI it won't happen.
*
* Note we only call this 1) after U-Boot is relocated, and 2)
* root bus has finished probing.
*/
if ((gd->flags & GD_FLG_RELOC) && (bus->seq == 0))
ret = fsp_init_phase_pci();
+#endif
return ret < 0 ? ret : 0;
}
-- 1.8.2.1
Regards, Simon

Hi Simon,
On Sat, Aug 22, 2015 at 7:27 AM, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On 20 August 2015 at 07:40, Bin Meng bmeng.cn@gmail.com wrote:
Per Intel FSP specification, we should call FSP notify API to inform FSP that PCI enumeration has been done so that FSP will do any necessary initialization as required by the chipset's BIOS Writer's Guide (BWG).
Unfortunately we have to put this call here as with driver model, the enumeration is all done on a lazy basis as needed, so until something is touched on PCI it won't happen.
Note we only call this after U-Boot is relocated and root bus has finished probing.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
Changes in v2: None
drivers/pci/pci-uclass.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
Acked-by: Simon Glass sjg@chromium.org
Please see below.
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 4160274..c90e7ac 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -14,6 +14,9 @@ #include <dm/lists.h> #include <dm/root.h> #include <dm/device-internal.h> +#if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP)
Do we need CONFIG_X86 here? Do you think it is better to have it to be clearer?
Technically it is not needed as CONFIG_HAVE_FSP is dependent on CONFIG_X86 which is defined by Kconfig dependency. However I intentionally put it here, as I thought this is a common driver code for all architectures, and someone who is not familiar with x86 may wonder what CONFIG_HAVE_FSP is, so I put CONFIG_X86 at first to indicate this is x86-specific thing. What do you think?
+#include <asm/fsp/fsp_support.h> +#endif
DECLARE_GLOBAL_DATA_PTR;
@@ -749,6 +752,24 @@ static int pci_uclass_post_probe(struct udevice *bus) ret = pci_auto_config_devices(bus); #endif
+#if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP)
/*
* Per Intel FSP specification, we should call FSP notify API to
* inform FSP that PCI enumeration has been done so that FSP will
* do any necessary initialization as required by the chipset's
* BIOS Writer's Guide (BWG).
*
* Unfortunately we have to put this call here as with driver model,
* the enumeration is all done on a lazy basis as needed, so until
* something is touched on PCI it won't happen.
*
* Note we only call this 1) after U-Boot is relocated, and 2)
* root bus has finished probing.
*/
if ((gd->flags & GD_FLG_RELOC) && (bus->seq == 0))
ret = fsp_init_phase_pci();
+#endif
return ret < 0 ? ret : 0;
}
--
Regards, Bin

Hi Bin,
On 22 August 2015 at 03:05, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Sat, Aug 22, 2015 at 7:27 AM, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On 20 August 2015 at 07:40, Bin Meng bmeng.cn@gmail.com wrote:
Per Intel FSP specification, we should call FSP notify API to inform FSP that PCI enumeration has been done so that FSP will do any necessary initialization as required by the chipset's BIOS Writer's Guide (BWG).
Unfortunately we have to put this call here as with driver model, the enumeration is all done on a lazy basis as needed, so until something is touched on PCI it won't happen.
Note we only call this after U-Boot is relocated and root bus has finished probing.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
Changes in v2: None
drivers/pci/pci-uclass.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
Acked-by: Simon Glass sjg@chromium.org
Please see below.
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 4160274..c90e7ac 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -14,6 +14,9 @@ #include <dm/lists.h> #include <dm/root.h> #include <dm/device-internal.h> +#if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP)
Do we need CONFIG_X86 here? Do you think it is better to have it to be clearer?
Technically it is not needed as CONFIG_HAVE_FSP is dependent on CONFIG_X86 which is defined by Kconfig dependency. However I intentionally put it here, as I thought this is a common driver code for all architectures, and someone who is not familiar with x86 may wonder what CONFIG_HAVE_FSP is, so I put CONFIG_X86 at first to indicate this is x86-specific thing. What do you think?
Yes I thought that might be it. I agree.
Applied to u-boot-x86, thanks!
[snip]
Regards, Simon

During pci_bind_bus_devices() before finding a proper driver to bind the device, pci_bus_find_devfn() is called to find if this device already exists. However since device is even not bound, this call always returns -ENODEV. It is really unnecessary hence remove it.
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: None
drivers/pci/pci-uclass.c | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-)
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index c90e7ac..63e85b9 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -551,6 +551,8 @@ int pci_bind_bus_devices(struct udevice *bus) ulong header_type; pci_dev_t bdf, end; bool found_multi; + struct pci_device_id find_id; + ulong val; int ret;
found_multi = false; @@ -585,30 +587,21 @@ int pci_bind_bus_devices(struct udevice *bus) PCI_SIZE_32); class >>= 8;
- /* Find this device in the device tree */ - ret = pci_bus_find_devfn(bus, PCI_MASK_BUS(bdf), &dev); - /* Search for a driver */
- /* If nothing in the device tree, bind a generic device */ - if (ret == -ENODEV) { - struct pci_device_id find_id; - ulong val; - - memset(&find_id, '\0', sizeof(find_id)); - find_id.vendor = vendor; - find_id.device = device; - find_id.class = class; - if ((header_type & 0x7f) == PCI_HEADER_TYPE_NORMAL) { - pci_bus_read_config(bus, bdf, - PCI_SUBSYSTEM_VENDOR_ID, - &val, PCI_SIZE_32); - find_id.subvendor = val & 0xffff; - find_id.subdevice = val >> 16; - } - ret = pci_find_and_bind_driver(bus, &find_id, bdf, - &dev); + memset(&find_id, '\0', sizeof(find_id)); + find_id.vendor = vendor; + find_id.device = device; + find_id.class = class; + if ((header_type & 0x7f) == PCI_HEADER_TYPE_NORMAL) { + pci_bus_read_config(bus, bdf, + PCI_SUBSYSTEM_VENDOR_ID, + &val, PCI_SIZE_32); + find_id.subvendor = val & 0xffff; + find_id.subdevice = val >> 16; } + ret = pci_find_and_bind_driver(bus, &find_id, bdf, + &dev); if (ret) return ret;

Hi Bin,
On 20 August 2015 at 07:40, Bin Meng bmeng.cn@gmail.com wrote:
During pci_bind_bus_devices() before finding a proper driver to bind the device, pci_bus_find_devfn() is called to find if this device already exists. However since device is even not bound, this call always returns -ENODEV. It is really unnecessary hence remove it.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
Changes in v2: None
drivers/pci/pci-uclass.c | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-)
This doesn't look quite right to me.
The way this is supposed to work is that when the bus or bridge is bound, pci_uclass_post_bind() should add a device for each node it finds in the device tree on that bus.
I think the problem in your case is that in crownbay.dts you have:
pcie@17,0 { #address-cells = <3>; #size-cells = <2>; compatible = "intel,pci"; device_type = "pci";
and the compatible string for this doesn't match any driver. Thus the serial ports are never 'seen' during the initial bind and devices are not created.
If you add a driver for your device 17 and have it call dm_scan_fdt_node() then the devices should be bound correctly.
I think then your new code may not be needed, or a small smaller change may be needed.
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index c90e7ac..63e85b9 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -551,6 +551,8 @@ int pci_bind_bus_devices(struct udevice *bus) ulong header_type; pci_dev_t bdf, end; bool found_multi;
struct pci_device_id find_id;
ulong val; int ret; found_multi = false;
@@ -585,30 +587,21 @@ int pci_bind_bus_devices(struct udevice *bus) PCI_SIZE_32); class >>= 8;
/* Find this device in the device tree */
ret = pci_bus_find_devfn(bus, PCI_MASK_BUS(bdf), &dev);
/* Search for a driver */
/* If nothing in the device tree, bind a generic device */
if (ret == -ENODEV) {
struct pci_device_id find_id;
ulong val;
memset(&find_id, '\0', sizeof(find_id));
find_id.vendor = vendor;
find_id.device = device;
find_id.class = class;
if ((header_type & 0x7f) == PCI_HEADER_TYPE_NORMAL) {
pci_bus_read_config(bus, bdf,
PCI_SUBSYSTEM_VENDOR_ID,
&val, PCI_SIZE_32);
find_id.subvendor = val & 0xffff;
find_id.subdevice = val >> 16;
}
ret = pci_find_and_bind_driver(bus, &find_id, bdf,
&dev);
memset(&find_id, '\0', sizeof(find_id));
find_id.vendor = vendor;
find_id.device = device;
find_id.class = class;
if ((header_type & 0x7f) == PCI_HEADER_TYPE_NORMAL) {
pci_bus_read_config(bus, bdf,
PCI_SUBSYSTEM_VENDOR_ID,
&val, PCI_SIZE_32);
find_id.subvendor = val & 0xffff;
find_id.subdevice = val >> 16; }
ret = pci_find_and_bind_driver(bus, &find_id, bdf,
&dev); if (ret) return ret;
-- 1.8.2.1
Regards, Simon

When there is no valid compatible string in current list, we should advance to next one in the compatible string list.
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: None
lib/fdtdec.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/lib/fdtdec.c b/lib/fdtdec.c index d21fb74..39268a2 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -207,9 +207,8 @@ int fdtdec_get_pci_vendev(const void *blob, int node, u16 *vendor, u16 *device)
return 0; } - } else { - list += (len + 1); } + list += (len + 1); }
return -ENOENT;

On 20 August 2015 at 07:40, Bin Meng bmeng.cn@gmail.com wrote:
When there is no valid compatible string in current list, we should advance to next one in the compatible string list.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
Changes in v2: None
lib/fdtdec.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/lib/fdtdec.c b/lib/fdtdec.c index d21fb74..39268a2 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -207,9 +207,8 @@ int fdtdec_get_pci_vendev(const void *blob, int node, u16 *vendor, u16 *device)
return 0; }
} else {
list += (len + 1); }
list += (len + 1); } return -ENOENT;
-- 1.8.2.1
Acked-by: Simon Glass sjg@chromium.org

On 21 August 2015 at 17:27, Simon Glass sjg@chromium.org wrote:
On 20 August 2015 at 07:40, Bin Meng bmeng.cn@gmail.com wrote:
When there is no valid compatible string in current list, we should advance to next one in the compatible string list.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
Changes in v2: None
lib/fdtdec.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/lib/fdtdec.c b/lib/fdtdec.c index d21fb74..39268a2 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -207,9 +207,8 @@ int fdtdec_get_pci_vendev(const void *blob, int node, u16 *vendor, u16 *device)
return 0; }
} else {
list += (len + 1); }
list += (len + 1); } return -ENOENT;
-- 1.8.2.1
Acked-by: Simon Glass sjg@chromium.org
Applied to u-boot-x86, thanks!

In pci_uclass_child_post_bind(), bdf is extracted from fdt_pci_addr. Mask bus number before save it to pplat->devfn.
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: None
drivers/pci/pci-uclass.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 63e85b9..4a509a2 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -787,8 +787,8 @@ static int pci_uclass_child_post_bind(struct udevice *dev) if (ret != -ENOENT) return -EINVAL; } else { - /* extract the bdf from fdt_pci_addr */ - pplat->devfn = addr.phys_hi & 0xffff00; + /* extract the devfn from fdt_pci_addr */ + pplat->devfn = addr.phys_hi & 0xff00; }
return 0;

On 20 August 2015 at 07:40, Bin Meng bmeng.cn@gmail.com wrote:
In pci_uclass_child_post_bind(), bdf is extracted from fdt_pci_addr. Mask bus number before save it to pplat->devfn.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
Changes in v2: None
drivers/pci/pci-uclass.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 63e85b9..4a509a2 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -787,8 +787,8 @@ static int pci_uclass_child_post_bind(struct udevice *dev) if (ret != -ENOENT) return -EINVAL; } else {
/* extract the bdf from fdt_pci_addr */
pplat->devfn = addr.phys_hi & 0xffff00;
/* extract the devfn from fdt_pci_addr */
pplat->devfn = addr.phys_hi & 0xff00; } return 0;
-- 1.8.2.1
Acked-by: Simon Glass sjg@chromium.org

On 21 August 2015 at 17:27, Simon Glass sjg@chromium.org wrote:
On 20 August 2015 at 07:40, Bin Meng bmeng.cn@gmail.com wrote:
In pci_uclass_child_post_bind(), bdf is extracted from fdt_pci_addr. Mask bus number before save it to pplat->devfn.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
Changes in v2: None
drivers/pci/pci-uclass.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 63e85b9..4a509a2 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -787,8 +787,8 @@ static int pci_uclass_child_post_bind(struct udevice *dev) if (ret != -ENOENT) return -EINVAL; } else {
/* extract the bdf from fdt_pci_addr */
pplat->devfn = addr.phys_hi & 0xffff00;
/* extract the devfn from fdt_pci_addr */
pplat->devfn = addr.phys_hi & 0xff00; } return 0;
-- 1.8.2.1
Acked-by: Simon Glass sjg@chromium.org
Applied to u-boot-x86, thanks!

The dm pci doc says it supports binding pci device which appears in the device tree. However it is not true, at least on Intel Crown Bay. Currently the crownbay.dts defines 4 pci uart devices within the pci bus controller's node. pci_find_and_bind_driver() only scans U_BOOT_PCI_DEVICE defined driver list and if nothing is found, it binds devices to bridge driver or generic driver. Now we change the codes to first scan device tree for any pci devices listed there, if nothing go on with previous logic.
With this commit, we can get pci uart work on Intel Crown Bay. The previous 'dm tree' output before this commit is:
pci [ + ] | | `-- pci_1:0.0 pci_generic [ ] | | |-- pci_2:0.0 ...... pci_generic [ ] | | |-- pci_2:a.0 pci_generic [ ] | | |-- pci_2:a,1 pci_generic [ ] | | |-- pci_2:a,2 pci_generic [ ] | | |-- pci_2:a,3 pci_generic [ ] | | |-- pci_2:a,4 pci_generic [ ] | | |-- pci_2:c.0 ......
We have device nodes for 2:a,1/2:a,2/2:a,3/2:a,4, now we get:
pci [ + ] | | `-- pci_1:0.0 pci_generic [ ] | | |-- pci_2:0.0 ...... pci_generic [ ] | | |-- pci_2:a.0 serial [ ] | | |-- uart@a,1 serial [ ] | | |-- uart@a,2 serial [ ] | | |-- uart@a,3 serial [ ] | | |-- uart@a,4 pci_generic [ ] | | |-- pci_2:c.0 ......
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
Changes in v2: None
drivers/pci/pci-uclass.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++ include/pci.h | 11 +++++ 2 files changed, 114 insertions(+)
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 4a509a2..1e4d9be 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -450,6 +450,82 @@ static bool pci_match_one_id(const struct pci_device_id *id, return false; }
+static int pci_scan_fdt_node(struct udevice *bus, + struct pci_fdt_info **find_info, int *num) +{ + struct pci_root_priv *priv; + struct pci_fdt_info *fdt_info; + const void *fdt = gd->fdt_blob; + int offset, root_offset; + u16 vendor, device; + int i = 0; + + /* get root bus device */ + do { + if (device_get_uclass_id(bus->parent) == UCLASS_ROOT) + break; + bus = bus->parent; + } while (bus); + + priv = bus->priv; + if (!priv) { + priv = calloc(1, sizeof(struct pci_root_priv)); + if (!priv) + return -ENOMEM; + bus->priv = priv; + } + + /* + * Scan device tree from root bus node + * + * We scan device tree to check if any pci device is specified + * in the device tree. The device tree will be scanned twice. + * After the first scan we know how many pci device nodes are + * there. For the second scan we save pci device's vendor id & + * device id as well as its device tree node offset. + */ + if (!priv->fdt_scanned) { + root_offset = bus->of_offset; + + /* first scan */ + for (offset = fdt_next_node(fdt, root_offset, NULL); + offset >= 0; + offset = fdt_next_node(fdt, offset, NULL)) { + if (!fdtdec_get_pci_vendev(fdt, offset, + &vendor, &device)) + priv->fdt_info_entries++; + } + + if (priv->fdt_info_entries) { + fdt_info = calloc(priv->fdt_info_entries, + sizeof(struct pci_fdt_info)); + if (!fdt_info) + return -ENOMEM; + priv->fdt_info = fdt_info; + + /* second scan */ + for (offset = fdt_next_node(fdt, root_offset, NULL); + offset >= 0; + offset = fdt_next_node(fdt, offset, NULL)) { + if (!fdtdec_get_pci_vendev(fdt, offset, + &vendor, &device)) { + fdt_info[i].vendor = vendor; + fdt_info[i].device = device; + fdt_info[i].offset = offset; + i++; + } + } + } + + priv->fdt_scanned = true; + } + + *find_info = priv->fdt_info; + *num = priv->fdt_info_entries; + + return 0; +} + /** * pci_find_and_bind_driver() - Find and bind the right PCI driver * @@ -465,11 +541,33 @@ static int pci_find_and_bind_driver(struct udevice *parent, int ret; char name[30], *str; bool bridge; + struct pci_fdt_info *find_info; + int i, num;
*devp = NULL;
debug("%s: Searching for driver: vendor=%x, device=%x\n", __func__, find_id->vendor, find_id->device); + + /* Scan device tree to see if any pci device is listed */ + ret = pci_scan_fdt_node(parent, &find_info, &num); + if (ret) + goto error; + if (find_info) { + for (i = 0; i < num; i++) { + if (find_id->vendor == find_info->vendor && + find_id->device == find_info->device) { + ret = lists_bind_fdt(parent, gd->fdt_blob, + find_info->offset, devp); + if (ret) + goto error; + return 0; + } + find_info++; + } + } + + /* Then check U_BOOT_PCI_DEVICE defined driver list */ start = ll_entry_start(struct pci_driver_entry, pci_driver_entry); n_ents = ll_entry_count(struct pci_driver_entry, pci_driver_entry); for (entry = start; entry != start + n_ents; entry++) { @@ -514,6 +612,11 @@ static int pci_find_and_bind_driver(struct udevice *parent, } }
+ /* + * If we don't find any match driver above, bind the device to + * predefined driver - "pci_bridge_drv" or "pci_generic_drv". + */ + bridge = (find_id->class >> 8) == PCI_CLASS_BRIDGE_PCI; /* * In the pre-relocation phase, we only bind bridge devices to save diff --git a/include/pci.h b/include/pci.h index 488ff44..a2d4ef2 100644 --- a/include/pci.h +++ b/include/pci.h @@ -512,6 +512,17 @@ struct pci_device_id { unsigned long driver_data; /* Data private to the driver */ };
+struct pci_fdt_info { + unsigned int vendor, device; /* Vendor and device ID*/ + unsigned int offset; /* Device tree offset */ +}; + +struct pci_root_priv { + struct pci_fdt_info *fdt_info; + int fdt_info_entries; + bool fdt_scanned; +}; + struct pci_controller;
struct pci_config_table {

Document how pci devices are bound to device drivers. Also mention its limitation in the pre-relocation phase.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
---
Changes in v2: None
doc/driver-model/pci-info.txt | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-)
diff --git a/doc/driver-model/pci-info.txt b/doc/driver-model/pci-info.txt index cf69167..e016b98 100644 --- a/doc/driver-model/pci-info.txt +++ b/doc/driver-model/pci-info.txt @@ -34,9 +34,28 @@ under that bus. Note that this is all done on a lazy basis, as needed, so until something is touched on PCI (eg: a call to pci_find_devices()) it will not be probed.
-PCI devices can appear in the device tree. If they do this serves to specify -the driver to use for the device. In this case they will be bound at -start-up. +PCI devices can appear in the flattened device tree. If they do this serves to +specify the driver to use for the device. In this case they will be bound at +first. Each PCI device node must have a compatible string list as defined by +the IEEE Std 1275-1994 PCI bus binding document v2.1. An example like below: + + pciuart0: uart@a,1 { + compatible = "pci8086,8811.00", + "pci8086,8811", + "pciclass,070002", + "pciclass,0700", + "x86-uart"; + } + +Note the last string is the desired driver name which is supposed to work with +this PCI device. + +If PCI devices are not listed in the device tree, U_BOOT_PCI_DEVICE can be used +to specify the driver to use for the device. The device tree takes precedence +over U_BOOT_PCI_DEVICE. Plese note with U_BOOT_PCI_DEVICE, only drivers with +DM_FLAG_PRE_RELOC will be bound before relocation. If neither device tree nor +U_BOOT_PCI_DEVICE is provided, the built-in driver (either pci_bridge_drv or +pci_generic_drv) will be used.
Sandbox
participants (2)
-
Bin Meng
-
Simon Glass