Bin Meng | b598648 | 2019-07-18 00:33:56 -0700 | [diff] [blame] | 1 | .. SPDX-License-Identifier: GPL-2.0+ |
| 2 | |
Simon Glass | ff3e077 | 2015-03-05 12:25:25 -0700 | [diff] [blame] | 3 | PCI with Driver Model |
| 4 | ===================== |
| 5 | |
| 6 | How busses are scanned |
| 7 | ---------------------- |
| 8 | |
| 9 | Any config read will end up at pci_read_config(). This uses |
| 10 | uclass_get_device_by_seq() to get the PCI bus for a particular bus number. |
Bin Meng | 947eb43 | 2015-07-27 00:33:43 -0700 | [diff] [blame] | 11 | Bus number 0 will need to be requested first, and the alias in the device |
Bin Meng | b598648 | 2019-07-18 00:33:56 -0700 | [diff] [blame] | 12 | tree file will point to the correct device:: |
Simon Glass | ff3e077 | 2015-03-05 12:25:25 -0700 | [diff] [blame] | 13 | |
| 14 | aliases { |
Tom Rini | 42c64d1 | 2020-02-11 12:41:23 -0500 | [diff] [blame] | 15 | pci0 = &pcic; |
Simon Glass | ff3e077 | 2015-03-05 12:25:25 -0700 | [diff] [blame] | 16 | }; |
| 17 | |
Tom Rini | 42c64d1 | 2020-02-11 12:41:23 -0500 | [diff] [blame] | 18 | pcic: pci@0 { |
Simon Glass | ff3e077 | 2015-03-05 12:25:25 -0700 | [diff] [blame] | 19 | compatible = "sandbox,pci"; |
| 20 | ... |
| 21 | }; |
| 22 | |
| 23 | |
| 24 | If there is no alias the devices will be numbered sequentially in the device |
| 25 | tree. |
| 26 | |
Bin Meng | 947eb43 | 2015-07-27 00:33:43 -0700 | [diff] [blame] | 27 | The call to uclass_get_device() will cause the PCI bus to be probed. |
Simon Glass | ff3e077 | 2015-03-05 12:25:25 -0700 | [diff] [blame] | 28 | This does a scan of the bus to locate available devices. These devices are |
| 29 | bound to their appropriate driver if available. If there is no driver, then |
| 30 | they are bound to a generic PCI driver which does nothing. |
| 31 | |
| 32 | After probing a bus, the available devices will appear in the device tree |
| 33 | under that bus. |
| 34 | |
| 35 | Note that this is all done on a lazy basis, as needed, so until something is |
Bin Meng | 947eb43 | 2015-07-27 00:33:43 -0700 | [diff] [blame] | 36 | touched on PCI (eg: a call to pci_find_devices()) it will not be probed. |
Simon Glass | ff3e077 | 2015-03-05 12:25:25 -0700 | [diff] [blame] | 37 | |
Marek Vasut | 92ed986 | 2018-10-10 21:27:07 +0200 | [diff] [blame] | 38 | PCI devices can appear in the flattened device tree. If they do, their node |
| 39 | often contains extra information which cannot be derived from the PCI IDs or |
| 40 | PCI class of the device. Each PCI device node must have a <reg> property, as |
| 41 | defined by the IEEE Std 1275-1994 PCI bus binding document v2.1. Compatible |
| 42 | string list is optional and generally not needed, since PCI is discoverable |
| 43 | bus, albeit there are justified exceptions. If the compatible string is |
| 44 | present, matching on it takes precedence over PCI IDs and PCI classes. |
| 45 | |
| 46 | Note we must describe PCI devices with the same bus hierarchy as the |
Bin Meng | f4b5db7 | 2015-08-24 01:14:04 -0700 | [diff] [blame] | 47 | hardware, otherwise driver model cannot detect the correct parent/children |
| 48 | relationship during PCI bus enumeration thus PCI devices won't be bound to |
Bin Meng | b598648 | 2019-07-18 00:33:56 -0700 | [diff] [blame] | 49 | their drivers accordingly. A working example like below:: |
Bin Meng | f4b5db7 | 2015-08-24 01:14:04 -0700 | [diff] [blame] | 50 | |
| 51 | pci { |
| 52 | #address-cells = <3>; |
| 53 | #size-cells = <2>; |
| 54 | compatible = "pci-x86"; |
| 55 | u-boot,dm-pre-reloc; |
| 56 | ranges = <0x02000000 0x0 0x40000000 0x40000000 0 0x80000000 |
| 57 | 0x42000000 0x0 0xc0000000 0xc0000000 0 0x20000000 |
| 58 | 0x01000000 0x0 0x2000 0x2000 0 0xe000>; |
| 59 | |
| 60 | pcie@17,0 { |
| 61 | #address-cells = <3>; |
| 62 | #size-cells = <2>; |
| 63 | compatible = "pci-bridge"; |
| 64 | u-boot,dm-pre-reloc; |
| 65 | reg = <0x0000b800 0x0 0x0 0x0 0x0>; |
| 66 | |
| 67 | topcliff@0,0 { |
| 68 | #address-cells = <3>; |
| 69 | #size-cells = <2>; |
| 70 | compatible = "pci-bridge"; |
| 71 | u-boot,dm-pre-reloc; |
| 72 | reg = <0x00010000 0x0 0x0 0x0 0x0>; |
| 73 | |
| 74 | pciuart0: uart@a,1 { |
| 75 | compatible = "pci8086,8811.00", |
| 76 | "pci8086,8811", |
| 77 | "pciclass,070002", |
| 78 | "pciclass,0700", |
| 79 | "x86-uart"; |
| 80 | u-boot,dm-pre-reloc; |
| 81 | reg = <0x00025100 0x0 0x0 0x0 0x0 |
| 82 | 0x01025110 0x0 0x0 0x0 0x0>; |
| 83 | ...... |
| 84 | }; |
| 85 | |
| 86 | ...... |
| 87 | }; |
| 88 | }; |
| 89 | |
| 90 | ...... |
| 91 | }; |
| 92 | |
| 93 | In this example, the root PCI bus node is the "/pci" which matches "pci-x86" |
| 94 | driver. It has a subnode "pcie@17,0" with driver "pci-bridge". "pcie@17,0" |
| 95 | also has subnode "topcliff@0,0" which is a "pci-bridge" too. Under that bridge, |
| 96 | a PCI UART device "uart@a,1" is described. This exactly reflects the hardware |
| 97 | bus hierarchy: on the root PCI bus, there is a PCIe root port which connects |
| 98 | to a downstream device Topcliff chipset. Inside Topcliff chipset, it has a |
| 99 | PCIe-to-PCI bridge and all the chipset integrated devices like the PCI UART |
| 100 | device are on the PCI bus. Like other devices in the device tree, if we want |
| 101 | to bind PCI devices before relocation, "u-boot,dm-pre-reloc" must be declared |
| 102 | in each of these nodes. |
| 103 | |
| 104 | If PCI devices are not listed in the device tree, U_BOOT_PCI_DEVICE can be used |
| 105 | to specify the driver to use for the device. The device tree takes precedence |
Simon Glass | bdaa976 | 2019-09-25 08:56:14 -0600 | [diff] [blame] | 106 | over U_BOOT_PCI_DEVICE. Please note with U_BOOT_PCI_DEVICE, only drivers with |
Bin Meng | f4b5db7 | 2015-08-24 01:14:04 -0700 | [diff] [blame] | 107 | DM_FLAG_PRE_RELOC will be bound before relocation. If neither device tree nor |
| 108 | U_BOOT_PCI_DEVICE is provided, the built-in driver (either pci_bridge_drv or |
| 109 | pci_generic_drv) will be used. |
Simon Glass | ff3e077 | 2015-03-05 12:25:25 -0700 | [diff] [blame] | 110 | |
| 111 | |
| 112 | Sandbox |
| 113 | ------- |
| 114 | |
| 115 | With sandbox we need a device emulator for each device on the bus since there |
Simon Glass | 9b69ba4 | 2019-09-25 08:56:10 -0600 | [diff] [blame] | 116 | is no real PCI bus. This works by looking in the device tree node for an |
| 117 | emulator driver. For example:: |
Simon Glass | ff3e077 | 2015-03-05 12:25:25 -0700 | [diff] [blame] | 118 | |
| 119 | pci@1f,0 { |
| 120 | compatible = "pci-generic"; |
| 121 | reg = <0xf800 0 0 0 0>; |
Simon Glass | 9b69ba4 | 2019-09-25 08:56:10 -0600 | [diff] [blame] | 122 | sandbox,emul = <&emul_1f>; |
| 123 | }; |
| 124 | pci-emul { |
| 125 | compatible = "sandbox,pci-emul-parent"; |
| 126 | emul_1f: emul@1f,0 { |
Simon Glass | ff3e077 | 2015-03-05 12:25:25 -0700 | [diff] [blame] | 127 | compatible = "sandbox,swap-case"; |
| 128 | }; |
| 129 | }; |
| 130 | |
| 131 | This means that there is a 'sandbox,swap-case' driver at that bus position. |
| 132 | Note that the first cell in the 'reg' value is the bus/device/function. See |
| 133 | PCI_BDF() for the encoding (it is also specified in the IEEE Std 1275-1994 |
| 134 | PCI bus binding document, v2.1) |
| 135 | |
Simon Glass | 9b69ba4 | 2019-09-25 08:56:10 -0600 | [diff] [blame] | 136 | The pci-emul node should go outside the pci bus node, since otherwise it will |
| 137 | be scanned as a PCI device, causing confusion. |
| 138 | |
Bin Meng | b598648 | 2019-07-18 00:33:56 -0700 | [diff] [blame] | 139 | When this bus is scanned we will end up with something like this:: |
Simon Glass | ff3e077 | 2015-03-05 12:25:25 -0700 | [diff] [blame] | 140 | |
Tom Rini | 42c64d1 | 2020-02-11 12:41:23 -0500 | [diff] [blame] | 141 | `- * pci@0 @ 05c660c8, 0 |
Bin Meng | b598648 | 2019-07-18 00:33:56 -0700 | [diff] [blame] | 142 | `- pci@1f,0 @ 05c661c8, 63488 |
Simon Glass | 9b69ba4 | 2019-09-25 08:56:10 -0600 | [diff] [blame] | 143 | `- emul@1f,0 @ 05c662c8 |
Simon Glass | ff3e077 | 2015-03-05 12:25:25 -0700 | [diff] [blame] | 144 | |
Simon Glass | 9b69ba4 | 2019-09-25 08:56:10 -0600 | [diff] [blame] | 145 | When accesses go to the pci@1f,0 device they are forwarded to its emulator. |
Bin Meng | 4345998 | 2018-08-03 01:14:45 -0700 | [diff] [blame] | 146 | |
| 147 | The sandbox PCI drivers also support dynamic driver binding, allowing device |
| 148 | driver to declare the driver binding information via U_BOOT_PCI_DEVICE(), |
| 149 | eliminating the need to provide any device tree node under the host controller |
| 150 | node. It is required a "sandbox,dev-info" property must be provided in the |
| 151 | host controller node for this functionality to work. |
| 152 | |
Bin Meng | b598648 | 2019-07-18 00:33:56 -0700 | [diff] [blame] | 153 | .. code-block:: none |
| 154 | |
Tom Rini | 42c64d1 | 2020-02-11 12:41:23 -0500 | [diff] [blame] | 155 | pci1: pci@1 { |
Bin Meng | 4345998 | 2018-08-03 01:14:45 -0700 | [diff] [blame] | 156 | compatible = "sandbox,pci"; |
| 157 | ... |
| 158 | sandbox,dev-info = <0x08 0x00 0x1234 0x5678 |
| 159 | 0x0c 0x00 0x1234 0x5678>; |
| 160 | }; |
| 161 | |
| 162 | The "sandbox,dev-info" property specifies all dynamic PCI devices on this bus. |
| 163 | Each dynamic PCI device is encoded as 4 cells a group. The first and second |
| 164 | cells are PCI device number and function number respectively. The third and |
| 165 | fourth cells are PCI vendor ID and device ID respectively. |
| 166 | |
Bin Meng | b598648 | 2019-07-18 00:33:56 -0700 | [diff] [blame] | 167 | When this bus is scanned we will end up with something like this:: |
Bin Meng | 4345998 | 2018-08-03 01:14:45 -0700 | [diff] [blame] | 168 | |
Tom Rini | 42c64d1 | 2020-02-11 12:41:23 -0500 | [diff] [blame] | 169 | pci [ + ] pci_sandbo |-- pci1 |
Bin Meng | 4345998 | 2018-08-03 01:14:45 -0700 | [diff] [blame] | 170 | pci_emul [ ] sandbox_sw | |-- sandbox_swap_case_emul |
| 171 | pci_emul [ ] sandbox_sw | `-- sandbox_swap_case_emul |