|
| 1 | +.. _pcie_boot: |
| 2 | + |
| 3 | +============== |
| 4 | +PCIe Boot Mode |
| 5 | +============== |
| 6 | + |
| 7 | +Overview |
| 8 | +-------- |
| 9 | + |
| 10 | +PCIe (Peripheral Component Interconnect Express) boot mode allows |
| 11 | +|__PART_FAMILY_NAME__| family of devices, configured as a PCIe endpoint, to boot by |
| 12 | +receiving boot loader images over PCIe from a host system acting as a |
| 13 | +PCIe root complex (RC). In this mode, the root complex is |
| 14 | +responsible for discovering the endpoint device and transferring the |
| 15 | +required boot loader images for each boot stage. |
| 16 | + |
| 17 | +This document provides a step-by-step guide to configuring and using |
| 18 | +PCIe boot mode. PCIe boot is supported on the |__PART_FAMILY_NAME__| SoC family. The |
| 19 | +following instructions and switch settings are specific to the |__PART_FAMILY_NAME__| EVM; |
| 20 | +for other boards, consult the corresponding hardware documentation. |
| 21 | + |
| 22 | +Boot Mode Switch Settings |
| 23 | +------------------------- |
| 24 | + |
| 25 | +To enable PCIe boot mode, configure the boot mode switches as follows: |
| 26 | + |
| 27 | +.. ifconfig:: CONFIG_part_variant in ('AM64X') |
| 28 | + |
| 29 | + .. code-block:: text |
| 30 | +
|
| 31 | + SW2 (B0 - B7): 1 1 0 1 0 1 1 0 |
| 32 | + SW3 (B8 - B15): 0 0 0 0 0 0 0 0 |
| 33 | +
|
| 34 | +.. note:: |
| 35 | + |
| 36 | + DIP switch settings are EVM-specific and may not apply to all board designs. |
| 37 | + |
| 38 | +Board Setup (Connection Example) |
| 39 | +-------------------------------- |
| 40 | + |
| 41 | +The following is an example of a connection in which the root complex (host) and the |
| 42 | +endpoint (|__PART_FAMILY_NAME__| device) are physically connected using a PCIe cable |
| 43 | +or connector, as shown in the figure below. |
| 44 | + |
| 45 | +.. image:: /images/AM64X_PCIe_boot.jpg |
| 46 | + |
| 47 | +Both boards should be powered off before making the connection, and the PCIe link |
| 48 | +securely established before powering on the devices. |
| 49 | + |
| 50 | +Other hardware configurations are possible. So adapt the setup steps as |
| 51 | +applicable to your board design. |
| 52 | + |
| 53 | +Endpoint Configuration |
| 54 | +---------------------- |
| 55 | + |
| 56 | +The following configuration options are used to set up the |__PART_FAMILY_NAME__| device |
| 57 | +as a PCIe endpoint for PCIe boot. These options must be set in the |
| 58 | +board's defconfig in U-BOOT for the corresponding boot loader image. |
| 59 | + |
| 60 | +- ``CONFIG_PCI_DFU_BAR_SIZE``: |
| 61 | + Configures the size of the PCIe BAR (Base Address Register) that is |
| 62 | + exposed for device firmware update (DFU) and boot loader image download. |
| 63 | + |
| 64 | +- ``CONFIG_PCI_DFU_VENDOR_ID``: |
| 65 | + Specifies the PCIe vendor ID to be advertised by the endpoint. |
| 66 | + |
| 67 | +- ``CONFIG_PCI_DFU_DEVICE_ID``: |
| 68 | + Specifies the PCIe device ID to be advertised by the endpoint. |
| 69 | + |
| 70 | +- ``CONFIG_PCI_DFU_MAGIC_WORD``: |
| 71 | + Magic word written by the root complex at the end of the image transfer to |
| 72 | + signal to the endpoint that the boot loader image is ready for processing. |
| 73 | + |
| 74 | +- ``CONFIG_PCI_DFU_BOOT_PHASE``: |
| 75 | + Specify the current boot phase when booting via DFU over PCIe. |
| 76 | + This value can be read by the root complex to determine the |
| 77 | + current boot phase. Value of this config is written to memory |
| 78 | + location (BAR_start + PCI_DFU_BAR_SIZE - 70). Max size of this |
| 79 | + config is 63 bytes. |
| 80 | + |
| 81 | +.. ifconfig:: CONFIG_part_variant in ('AM64X') |
| 82 | + |
| 83 | + .. note:: |
| 84 | + |
| 85 | + All the configs required for PCIe boot are enabled in |
| 86 | + ``am64x_evm_a53_defconfig`` and ``am64x_evm_r5_defconfig`` by default. |
| 87 | + |
| 88 | + By default, PCIe root complex mode is enabled in the device tree. |
| 89 | + To enable endpoint mode, the boot loaders must be built with the |
| 90 | + device tree overlay ``k3-am642-evm-pcie0-ep.dtso``. |
| 91 | + |
| 92 | +Ensure these configuration options are set appropriately in the build |
| 93 | +environment to enable a successful PCIe boot process. |
| 94 | + |
| 95 | +PCIe Boot Procedure |
| 96 | +------------------- |
| 97 | + |
| 98 | +1. After configuring the boot mode switches on the endpoint and |
| 99 | + connecting it to the root complex as shown in the figure, power |
| 100 | + on the endpoint. |
| 101 | + |
| 102 | +2. On the root complex, rescan the PCIe bus to enumerate the PCIe |
| 103 | + endpoint. The endpoint will appear as a RAM device on the root |
| 104 | + complex. The enumeration may look similar to the following: |
| 105 | + |
| 106 | + .. code-block:: text |
| 107 | +
|
| 108 | + 01:00.0 RAM memory: Texas Instruments Device b010 |
| 109 | + Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+ |
| 110 | + Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx- |
| 111 | + Latency: 0 |
| 112 | + Interrupt: pin A routed to IRQ 526 |
| 113 | + Region 0: Memory at 68100000 (32-bit, non-prefetchable) [size=1M] |
| 114 | + Region 1: Memory at 68200000 (32-bit, prefetchable) [size=2M] |
| 115 | + Region 2: Memory at 6a000000 (64-bit, prefetchable) [size=32M] |
| 116 | + Region 4: Memory at 6c000000 (64-bit, prefetchable) [size=32M] |
| 117 | +
|
| 118 | +3. Copy ``tiboot3.bin`` to Region 1. |
| 119 | + |
| 120 | + .. ifconfig:: CONFIG_part_variant in ('AM64X') |
| 121 | + |
| 122 | + After the root complex has finished copying the image, |
| 123 | + it must write the PCIe boot data address to ``0x701BCFE0``. |
| 124 | + |
| 125 | + For example, if the root complex loads the image at offset |
| 126 | + ``0x1000``, then it should write ``0x70001000`` (Internal RAM |
| 127 | + memory base + offset) to ``0x701BCFE0``. This notifies the ROM |
| 128 | + that the image is ready to be authenticated and processed. |
| 129 | + |
| 130 | +4. Once ``tiboot3.bin`` is transferred, rescan the PCIe bus on the |
| 131 | + root complex to enumerate the PCIe endpoint device, in order to |
| 132 | + transfer the next stage boot loader. The enumeration may now look |
| 133 | + like the following: |
| 134 | + |
| 135 | + .. code-block:: text |
| 136 | +
|
| 137 | + 0000:01:00.0 RAM memory: Texas Instruments Device b010 |
| 138 | + Subsystem: Device 7003:beef |
| 139 | + Flags: bus master, fast devsel, latency 0, IRQ 644 |
| 140 | + Memory at 12000000 (32-bit, prefetchable) [size=4M] |
| 141 | + Capabilities: [80] Power Management version 3 |
| 142 | + Capabilities: [90] MSI: Enable+ Count=1/1 Maskable+ 64bit+ |
| 143 | + Capabilities: [b0] MSI-X: Enable- Count=1 Masked- |
| 144 | + Capabilities: [c0] Express Endpoint, IntMsgNum 0 |
| 145 | + Capabilities: [100] Advanced Error Reporting |
| 146 | +
|
| 147 | +5. At this stage, only one memory region will be visible. Copy |
| 148 | + ``tispl.bin`` to this region. After the copy, the root complex |
| 149 | + must write a 4-byte magic word (defined in the defconfig) at the |
| 150 | + end of the memory region. This indicates to the endpoint that the |
| 151 | + boot loader image has been copied. |
| 152 | + |
| 153 | +6. Repeat steps 4 and 5 to transfer ``u-boot.img`` using the same |
| 154 | + procedure. |
| 155 | + |
| 156 | +Sample Host Program for Image Transfer |
| 157 | +-------------------------------------- |
| 158 | + |
| 159 | +The following sample C program can be used on the root complex to |
| 160 | +copy boot loader images (such as ``tiboot3.bin``, ``tispl.bin``, and |
| 161 | +``u-boot.img``) to the PCIe endpoint device by writing them to the |
| 162 | +appropriate memory regions using ``/dev/mem``. |
| 163 | + |
| 164 | +.. code-block:: c |
| 165 | +
|
| 166 | + #include <sys/mman.h> |
| 167 | + #include <sys/stat.h> |
| 168 | + #include <fcntl.h> |
| 169 | + #include <unistd.h> |
| 170 | + #include <stdio.h> |
| 171 | + #include <stdlib.h> |
| 172 | + #include <string.h> |
| 173 | +
|
| 174 | + int main(int argc, char *argv[]) |
| 175 | + { |
| 176 | + char *bootfilename = NULL; |
| 177 | + off_t bar1_address = 0; |
| 178 | + int fd; |
| 179 | + void *map_base; |
| 180 | + long image_size, map_size; |
| 181 | + char *buffer; |
| 182 | + unsigned int *buffer_32; |
| 183 | + int i; |
| 184 | + FILE * fptr; |
| 185 | + off_t load_addr, load_addr_offset, start_addr_offset; |
| 186 | +
|
| 187 | + if (argc != 3) { |
| 188 | + printf("Usage: %s <bar_address> <binary_file>\n", argv[0]); |
| 189 | + return 0; |
| 190 | + } |
| 191 | +
|
| 192 | + bar1_address = strtoul(argv[1], NULL, 16); |
| 193 | + bootfilename = argv[2]; |
| 194 | +
|
| 195 | + printf("bootfilename: %s\n", bootfilename); |
| 196 | + printf("bar1_address: 0x%lx\n", bar1_address); |
| 197 | +
|
| 198 | + if(!strcmp(bootfilename,"tiboot3.bin")) |
| 199 | + { |
| 200 | + load_addr = 0x70000000; |
| 201 | + load_addr_offset = 0x1000; |
| 202 | + start_addr_offset = 0x1bcfe0; |
| 203 | + } |
| 204 | + else |
| 205 | + { |
| 206 | + load_addr = 0xdeadbeef; |
| 207 | + load_addr_offset = 0x00; |
| 208 | + start_addr_offset = 0x3ffffc; |
| 209 | + } |
| 210 | +
|
| 211 | + printf("load_addr: 0x%lx\n", load_addr); |
| 212 | + printf("load_addr_offset: 0x%lx\n", load_addr_offset); |
| 213 | + printf("start_addr_offset: 0x%lx\n", start_addr_offset); |
| 214 | +
|
| 215 | + printf("try to open /dev/mem.\n"); |
| 216 | + fd = open("/dev/mem", O_RDWR | O_SYNC); |
| 217 | + if (fd < 0) { |
| 218 | + printf("open /dev/mem failed.\n"); |
| 219 | + return 0; |
| 220 | + } |
| 221 | + printf("/dev/mem opened.\n"); |
| 222 | + (void)fflush(stdout); |
| 223 | +
|
| 224 | + fptr = fopen(bootfilename, "rb"); |
| 225 | + if (!fptr) { |
| 226 | + printf("open %s failed.\n", bootfilename); |
| 227 | + return 0; |
| 228 | + } |
| 229 | + printf("%s opened.\n", bootfilename); |
| 230 | +
|
| 231 | + (void)fseek(fptr, 0L, SEEK_END); |
| 232 | + image_size = ftell(fptr); |
| 233 | + printf("image_size: %ld\n", image_size); |
| 234 | + fseek(fptr, 0, SEEK_SET); |
| 235 | +
|
| 236 | + printf("%s: image_size: %ld\n", __func__, image_size); |
| 237 | +
|
| 238 | + map_size = 0x400000; |
| 239 | +
|
| 240 | + printf("%s: map_size: %ld\n", __func__, map_size); |
| 241 | +
|
| 242 | + map_base = mmap(0, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, bar1_address); |
| 243 | + if (map_base == MAP_FAILED) { |
| 244 | + printf("mmap failed.\n"); |
| 245 | + return 0; |
| 246 | + } |
| 247 | + printf("map_base: 0x%lx\n", (unsigned long)map_base); |
| 248 | + (void)fflush(stdout); |
| 249 | +
|
| 250 | + buffer = malloc(image_size); |
| 251 | + if (!buffer) { |
| 252 | + printf("malloc failed.\n"); |
| 253 | + return 0; |
| 254 | + } |
| 255 | +
|
| 256 | + buffer_32 = (unsigned int *)buffer; |
| 257 | + fread(buffer, (size_t)image_size, 1, fptr); |
| 258 | + printf("Read image of %ld bytes\n", image_size); |
| 259 | +
|
| 260 | + printf("Writing image to memory\n"); |
| 261 | + for(i = 0; i < (int)image_size; i+=4) |
| 262 | + { |
| 263 | + *(unsigned int *)( map_base + load_addr_offset + i) = buffer_32[i/4]; |
| 264 | + } |
| 265 | + printf("done.\n"); |
| 266 | + fflush(stdout); |
| 267 | +
|
| 268 | + sleep(1); |
| 269 | +
|
| 270 | + *(unsigned int *)(map_base + start_addr_offset) = (unsigned int)(load_addr_offset + load_addr); |
| 271 | + return 0; |
| 272 | + } |
| 273 | +
|
| 274 | +Usage Example |
| 275 | +^^^^^^^^^^^^^ |
| 276 | + |
| 277 | +To copy a boot loader file (e.g., ``tiboot3.bin``) to the PCIe device, |
| 278 | +run: |
| 279 | + |
| 280 | +.. code-block:: bash |
| 281 | +
|
| 282 | + sudo ./pcie_boot_copy 0x68200000 tiboot3.bin |
| 283 | +
|
| 284 | +Replace ``0x68200000`` with the appropriate BAR region address as |
| 285 | +enumerated on the root complex, and specify the correct binary file. |
0 commit comments