From 33f27af2b9af79f0ccf18a9a8ee789c09e34a77a Mon Sep 17 00:00:00 2001 From: Sam Bobrowicz Date: Mon, 27 Feb 2017 15:11:48 -0800 Subject: [PATCH] add SDSoC generation files Decided to version control some files that are helpful for creating SDSoC platforms from this project. Also added an FSBL sdk project because it is needed for the SDSoC Platform --- sdk/fsbl/.cproject | 180 ++ sdk/fsbl/.gitignore | 1 + sdk/fsbl/.project | 33 + sdk/fsbl/bootimage/BOOT.bin | Bin 0 -> 4149824 bytes sdk/fsbl/bootimage/fsbl.bif | 6 + sdk/fsbl/src/Xilinx.spec | 2 + sdk/fsbl/src/fsbl.h | 546 ++++++ sdk/fsbl/src/fsbl_debug.h | 82 + sdk/fsbl/src/fsbl_handoff.S | 221 +++ sdk/fsbl/src/fsbl_hooks.c | 164 ++ sdk/fsbl/src/fsbl_hooks.h | 81 + sdk/fsbl/src/image_mover.c | 1335 ++++++++++++++ sdk/fsbl/src/image_mover.h | 161 ++ sdk/fsbl/src/lscript.ld | 313 ++++ sdk/fsbl/src/main.c | 1532 +++++++++++++++++ sdk/fsbl/src/md5.c | 484 ++++++ sdk/fsbl/src/md5.h | 120 ++ sdk/fsbl/src/nand.c | 295 ++++ sdk/fsbl/src/nand.h | 91 + sdk/fsbl/src/nor.c | 144 ++ sdk/fsbl/src/nor.h | 87 + sdk/fsbl/src/pcap.c | 816 +++++++++ sdk/fsbl/src/pcap.h | 108 ++ sdk/fsbl/src/ps7_parameters.xml | 638 +++++++ sdk/fsbl/src/qspi.c | 764 ++++++++ sdk/fsbl/src/qspi.h | 128 ++ sdk/fsbl/src/rsa.c | 361 ++++ sdk/fsbl/src/rsa.h | 80 + sdk/fsbl/src/sd.c | 191 ++ sdk/fsbl/src/sd.h | 79 + sdk/fsbl_bsp/.cproject | 13 + sdk/fsbl_bsp/.project | 75 + sdk/fsbl_bsp/.sdkproject | 4 + sdk/fsbl_bsp/Makefile | 31 + sdk/fsbl_bsp/system.mss | 305 ++++ src/others/.gitignore | 1 - .../Creating_SDSoC_Platform_archive.txt | 13 - .../SDSoC_Platform_creation_Guide.txt | 23 + .../SDSoC_Staging/boot_freertos/freertos.bif | 7 + .../SDSoC_Staging/boot_freertos/fsbl.elf | Bin 0 -> 349580 bytes .../boot_freertos/generic.readme | 8 + .../SDSoC_Staging/boot_standalone/fsbl.elf | Bin 0 -> 349580 bytes .../boot_standalone/generic.readme | 8 + .../boot_standalone/standalone.bif | 7 + src/others/{ => SDSoC_Staging}/hw_pfm_gen.tcl | 0 src/others/SDSoC_Staging/linux.bif | 7 + src/others/SDSoC_Staging/lscript.ld | 288 ++++ src/others/SDSoC_Staging/output/.gitignore | 1 + src/others/SDSoC_Staging/platform_builder.xml | 1 + .../new/board_files/arty-z7-10/A.0/board.xml | 601 +++++++ .../board_files/arty-z7-10/A.0/part0_pins.xml | 58 + .../new/board_files/arty-z7-10/A.0/preset.xml | 1080 ++++++++++++ .../new/board_files/arty-z7-20/A.0/board.xml | 674 ++++++++ .../board_files/arty-z7-20/A.0/part0_pins.xml | 74 + .../new/board_files/arty-z7-20/A.0/preset.xml | 1098 ++++++++++++ 55 files changed, 13406 insertions(+), 14 deletions(-) create mode 100644 sdk/fsbl/.cproject create mode 100644 sdk/fsbl/.gitignore create mode 100644 sdk/fsbl/.project create mode 100644 sdk/fsbl/bootimage/BOOT.bin create mode 100644 sdk/fsbl/bootimage/fsbl.bif create mode 100644 sdk/fsbl/src/Xilinx.spec create mode 100644 sdk/fsbl/src/fsbl.h create mode 100644 sdk/fsbl/src/fsbl_debug.h create mode 100644 sdk/fsbl/src/fsbl_handoff.S create mode 100644 sdk/fsbl/src/fsbl_hooks.c create mode 100644 sdk/fsbl/src/fsbl_hooks.h create mode 100644 sdk/fsbl/src/image_mover.c create mode 100644 sdk/fsbl/src/image_mover.h create mode 100644 sdk/fsbl/src/lscript.ld create mode 100644 sdk/fsbl/src/main.c create mode 100644 sdk/fsbl/src/md5.c create mode 100644 sdk/fsbl/src/md5.h create mode 100644 sdk/fsbl/src/nand.c create mode 100644 sdk/fsbl/src/nand.h create mode 100644 sdk/fsbl/src/nor.c create mode 100644 sdk/fsbl/src/nor.h create mode 100644 sdk/fsbl/src/pcap.c create mode 100644 sdk/fsbl/src/pcap.h create mode 100644 sdk/fsbl/src/ps7_parameters.xml create mode 100644 sdk/fsbl/src/qspi.c create mode 100644 sdk/fsbl/src/qspi.h create mode 100644 sdk/fsbl/src/rsa.c create mode 100644 sdk/fsbl/src/rsa.h create mode 100644 sdk/fsbl/src/sd.c create mode 100644 sdk/fsbl/src/sd.h create mode 100644 sdk/fsbl_bsp/.cproject create mode 100644 sdk/fsbl_bsp/.project create mode 100644 sdk/fsbl_bsp/.sdkproject create mode 100644 sdk/fsbl_bsp/Makefile create mode 100644 sdk/fsbl_bsp/system.mss delete mode 100644 src/others/.gitignore delete mode 100644 src/others/Creating_SDSoC_Platform_archive.txt create mode 100644 src/others/SDSoC_Staging/SDSoC_Platform_creation_Guide.txt create mode 100644 src/others/SDSoC_Staging/boot_freertos/freertos.bif create mode 100644 src/others/SDSoC_Staging/boot_freertos/fsbl.elf create mode 100644 src/others/SDSoC_Staging/boot_freertos/generic.readme create mode 100644 src/others/SDSoC_Staging/boot_standalone/fsbl.elf create mode 100644 src/others/SDSoC_Staging/boot_standalone/generic.readme create mode 100644 src/others/SDSoC_Staging/boot_standalone/standalone.bif rename src/others/{ => SDSoC_Staging}/hw_pfm_gen.tcl (100%) create mode 100644 src/others/SDSoC_Staging/linux.bif create mode 100644 src/others/SDSoC_Staging/lscript.ld create mode 100644 src/others/SDSoC_Staging/output/.gitignore create mode 100644 src/others/SDSoC_Staging/platform_builder.xml create mode 100644 src/others/SDSoC_Staging/vivado-boards/new/board_files/arty-z7-10/A.0/board.xml create mode 100644 src/others/SDSoC_Staging/vivado-boards/new/board_files/arty-z7-10/A.0/part0_pins.xml create mode 100644 src/others/SDSoC_Staging/vivado-boards/new/board_files/arty-z7-10/A.0/preset.xml create mode 100644 src/others/SDSoC_Staging/vivado-boards/new/board_files/arty-z7-20/A.0/board.xml create mode 100644 src/others/SDSoC_Staging/vivado-boards/new/board_files/arty-z7-20/A.0/part0_pins.xml create mode 100644 src/others/SDSoC_Staging/vivado-boards/new/board_files/arty-z7-20/A.0/preset.xml diff --git a/sdk/fsbl/.cproject b/sdk/fsbl/.cproject new file mode 100644 index 0000000..d4e9e01 --- /dev/null +++ b/sdk/fsbl/.cproject @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/fsbl/.gitignore b/sdk/fsbl/.gitignore new file mode 100644 index 0000000..3df573f --- /dev/null +++ b/sdk/fsbl/.gitignore @@ -0,0 +1 @@ +/Debug/ diff --git a/sdk/fsbl/.project b/sdk/fsbl/.project new file mode 100644 index 0000000..dc62026 --- /dev/null +++ b/sdk/fsbl/.project @@ -0,0 +1,33 @@ + + + fsbl + Created by SDK v2016.4. fsbl_bsp - ps7_cortexa9_0 + + fsbl_bsp + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + + src/ps7_init.c + 1 + WORKSPACE_LOC/Arty_Z7_20_wrapper_hw_platform_0/ps7_init.c + + + diff --git a/sdk/fsbl/bootimage/BOOT.bin b/sdk/fsbl/bootimage/BOOT.bin new file mode 100644 index 0000000000000000000000000000000000000000..19979c6777bee0c3ae3d80e28b14554410ca6339 GIT binary patch literal 4149824 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 z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB=EM3XD=(`O9zk{ojxL7x^`+(#le^GWGDT`EZ`+)eVCjquukk zjEc09(mQvJ&Zd=7OdOq=_fuN={+IvopSCf}?|IbxJ?%98Zp2d@#KCvKcc3rdf&UMM Cq`5%= literal 0 HcmV?d00001 diff --git a/sdk/fsbl/bootimage/fsbl.bif b/sdk/fsbl/bootimage/fsbl.bif new file mode 100644 index 0000000..d4d9eb6 --- /dev/null +++ b/sdk/fsbl/bootimage/fsbl.bif @@ -0,0 +1,6 @@ +//arch = zynq; split = false; format = BIN +the_ROM_image: +{ + [bootloader]C:\sam_work\git\digilent\Arty-Z7-20-base\sdk\fsbl\Debug\fsbl.elf + C:\sam_work\git\digilent\Arty-Z7-20-base\sdk\Arty_Z7_20_wrapper_hw_platform_0\Arty_Z7_20_wrapper.bit +} \ No newline at end of file diff --git a/sdk/fsbl/src/Xilinx.spec b/sdk/fsbl/src/Xilinx.spec new file mode 100644 index 0000000..8eea377 --- /dev/null +++ b/sdk/fsbl/src/Xilinx.spec @@ -0,0 +1,2 @@ +*startfile: +crti%O%s crtbegin%O%s diff --git a/sdk/fsbl/src/fsbl.h b/sdk/fsbl/src/fsbl.h new file mode 100644 index 0000000..b732c62 --- /dev/null +++ b/sdk/fsbl/src/fsbl.h @@ -0,0 +1,546 @@ +/****************************************************************************** +* +* Copyright (C) 2012 - 2016 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file fsbl.h +* +* Contains the function prototypes, defines and macros for the +* First Stage Boot Loader (FSBL) functionality +* +*
+* MODIFICATION HISTORY:
+*
+* Ver	Who	Date		Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a	jz	03/04/11	Initial release
+* 2.00a	mb 	06/06/12	Removed the qspi define, will be picked from
+*						xparameters.h file
+* 3.00a np/mb 08/08/12	Added the error codes for the FSBL hook errors.
+* 						Added the debug levels
+* 4.00a sgd 02/28/13	Removed DDR initialization check
+*                       Removed DDR ECC initialization code
+*						Modified hand off address check to 1MB
+*						Added RSA authentication support
+*						Removed LPBK_DLY_ADJ register setting code as we use
+* 					 	divisor 8
+*						Removed check for Fabric is already initialized
+*
+* 						CR's fixed and description
+* 						689026:	FSBL doesn't hold PL resets active during
+* 						bit download
+* 						Resolution: PL resets are released just before
+* 						handoff
+*
+* 						689077:	FSBL hangs at Handoff clearing the
+* 						TX UART buffer
+*						Resolution: STDOUT_BASEADDRESS macro value changes
+*						based UART select, hence used STDOUT_BASEADDRESS
+*						as UART base address
+*
+* 						695578: FSBL failed to load standalone application
+* 						in secure bootmode
+*               		Resolution: Application will be placed at load address
+*               		instead of DDR temporary address
+*
+*               		699475: FSBL functionality is broken and its
+*               		not able to boot in QSPI/NAND bootmode
+*               		Resolution: New flags are added DevCfg driver
+*               		for handling loopback
+*               		XDCFG_CONCURRENT_NONSEC_READ_WRITE
+*                       XDCFG_CONCURRENT_SECURE_READ_WRITE
+*
+*               		683145: Define stack area for FIQ, UNDEF modes
+*               		in linker file
+*               		Resolution: FSBL linker modified to create stack area
+*               		for FIQ, UNDEF
+*                       
+*                       705664: FSBL fails to decrypt the bitstream when 
+*                       the image is AES encrypted using non-zero key value
+*                       Resolution: Fabric cleaning will not be done
+*                       for AES-E-Fuse encryption
+*                       
+*                       Watchdog disabled for AES E-Fuse encryption
+*
+* 5.00a sgd 05/17/13    Fallback support for E-Fuse encryption
+*                       Added QSPI Flash Size > 128Mbit support
+* 					    QSPI Dual Stack support
+* 					    Added Md5 checksum support
+*
+*                       CR's fixed and description
+*                       692045	FSBL: Linker script of FSBL has PHDR workaround,
+* 					    this needs to be fixed
+* 					    Resolution: Removed PHDR from Linker file
+*                       
+*                       704287	FSBL: fsbl.h file has a few error codes that 
+*                       are not used by FSBL, that needs to be removed
+*                       Resolution: Removed unused error codes
+*
+*                       704379	FSBL: Check if DDR is in proper state before
+*                       handoff
+* 					    Resolution: Added DDR initialization check
+* 					                           
+*                       709077	If FSBL_DEBUG and FSBL_DEBUG_INFO are defined, 
+*                       the debug level is FSBL_DEBUG only.
+*                       
+*                       710128 FSBL: Linux boot failing without load attribute
+*                       set for Linux partitions in BIF
+*                       Resolution: FSBL will load partitions with valid load
+*                       address and stop loading if any invalid load address
+*
+*                       708728 Issues seen while making HP interconnect
+*                       32 bit wide
+*                       Resolution: ps7_post_config function generated by PCW
+*                       will be called after Bit stream download
+*                       Added MMC support
+* 6.00a	kc	07/31/2013	CR's fixed and description
+* 						724166 FSBL doesn’t use PPK authenticated by Boot ROM
+* 						 for authenticating the Partition images
+* 						Resolution: FSBL now uses the PPK left by Boot ROM in
+* 						OCM for authencating the SPK
+*
+* 						724165 Partition Header used by FSBL is not
+* 						authenticated
+* 						Resolution: FSBL now authenticates the partition header
+*
+* 						691150 ps7_init does not check for peripheral
+* 						initialization failures or timeout on polls
+* 						Resolution: Return value of ps7_init() is now checked
+* 						by FSBL and prints the error string
+*
+* 						708316  PS7_init.tcl file should have Error mechanism
+* 						for all mask_poll
+* 						Resolution: Return value of ps7_init() is now checked
+* 						by FSBL and prints the error string
+*
+* 						732062 FSBL fails to build if UART not available
+* 						Resolution: Added define to call xil_printf only
+* 						if uart is defined
+*
+* 						722979 Provide customer-friendly changelogs in FSBL
+* 						Resolution: Added CR description for all the files
+*
+* 						732865 Backward compatibility for ps7_init function
+*						Resolution: Added a new define for ps7_init success
+*						and value is defined based on ps7_init define
+*
+*						Fix for CR#739711 - FSBL not able to read Large
+*						QSPI (512M) in IO Mode
+*						Resolution: Modified the address calculation
+*						algorithm in dual parallel mode for QSPI
+*
+* 7.00a kc  10/18/13    Integrated SD/MMC driver
+*			10/23/13	Support for armcc compiler added
+*						741003 FSBL has to check the HMAC error status after 
+*						decryption
+*						Resolution: Added code for checking the error status 
+*						after PCAP completion
+*						739968 FSBL should do the QSPI config settings for 
+*						Dual parallel configuration in IO mode
+*						Resolution: Added QSPI config settings in qspi.c
+*						724620 FSBL: How to handle PCAP_MODE after bitstream 
+*						configuration.
+*						Resolution: PCAP_MODE and PCAP_PR bits are now cleared  
+* 						after PCAP transfer completion
+*						726178 In the 14.6 FSBL function FabricInit() PROG_B 
+*						is kept active for 5mS.
+*						Resolution: PROG_B is now kept active for 5mS only incase 
+*						if efuse is the aes key source.
+*						755245 FSBL does not load partition if eMMC has only 
+*						one partition
+*						Resolution: Changed the if condition for MMC
+*			12/04/13    764382 FSBL: How to handle PCAP_MODE after bitstream 
+*						configuration
+*						Resolution: Reverted back the changes of 724620. PCAP_MODE
+*						and PCAP_PR bits are not changed
+* 8.00a kc  01/16/13    767798 Fsbl MD5 Checksum failiure for encrypted images
+* 						Resolution: For checksum enabled partitions, total 
+*						total partition image length is copied now.
+*						761895 FSBL should authenticate image only if
+*						partition owner was not set to u-boot
+*						Resolution: Partition owner check added in 
+*						image_mover.c
+* 			02/20/14	775631 - FSBL: FsblGetGlobalTimer() is not proper
+*						Resolution: Function argument is updated from value
+*						to pointer to reflect updated value
+* 9.00a kc  04/16/14	773866 - SetPpk() will fail on secure fallback
+*						unless FSBL* and FSBL are identical in length
+*						Resolution: PPK is set only once now.
+*						785778 - FSBL takes 8 seconds to
+* 						authenticate (RSA) a bitstream on zc706
+* 						Resolution: Data Caches are enabled only for
+* 						authentication.
+* 						791245 - Use of xilrsa in fsbl
+* 						Resolution: Rsa library is removed from fsbl source
+* 						and xilrsa is used from BSP
+* 10.00a kc 07/15/14	804595 Zynq FSBL - Issues with
+* 						fallback image offset handling using MD5
+* 						Resolution: Updated the checksum offset to add with
+* 						image base address
+* 						782309 Fallback support for AES
+* 						encryption with E-Fuse - Enhancement
+* 						Resolution: Same as 773866
+* 						809336 Minor code cleanup
+* 						Resolution Minor code changes
+*        kc 08/27/14	820356 - FSBL compilation fails with IAR compiler
+* 						Resolution: Change of __asm__ to __asm
+* 11.00a kv 10/08/14	826030 - FSBL:LinearBootDeviceFlag is not initialized
+*						in IO mode case.Due to which the variable is
+*						remaining in unknown state.
+*						Resolution: LinearBootDeviceFlag is initialized 0
+*						in main.c
+* 12.00a ssc 12/11/14	839182 - FSBL -In the file sd.c, f_mount is called with
+*                       two arguments but f_mount is expecting the 3 arguments
+*                       from build 2015.1_1210_1, causing compilation error.
+*						Resolution: Arguments for f_mount in InitSD() are
+*						changed as per new signature.
+* 13.00a ssc 04/10/15	846899 - FSBL -In the file pcap.c, to clear DMA done
+*                       count, devcfg.INT_STS register is written to, which is
+*                       not correct.
+*                       Resolution: Corresponding fields in the devcfg.STATUS
+*                       register are written to, for clearing DMA done count.
+* 14.00a gan 01/13/16   869081 -(2016.1)FSBL -In qspi.c, FSBL picks the qspi
+*						read command from LQSPI_CFG register instead of hard
+*		   				coded read command (0x6B).
+* 15.00a gan 07/21/16   953654 -(2016.3)FSBL -In pcap.c/pcap.h/main.c,
+* 						Fabric Initialization sequence is modified to check
+* 						the PL power before sequence starts and checking INIT_B
+* 						reset status twice in case of failure.
+* 16.00a gan 08/02/16   Fix for CR# 955897 -(2016.3)FSBL -
+* 						In pcap.c, check pl power through MCTRL register
+* 						for 3.0 and later versions of silicon.
+* 
+* +* +* +* @note +* +* Flags in FSBL +* +* FSBL_PERF +* +* This Flag can be set at compilation time. This flag is set for +* measuring the performance of FSBL.That is the time taken to execute is +* measured.when this flag is set.Execution time with reference to +* global timer is taken here +* +* Total Execution time is the time taken for executing FSBL till handoff +* to any application . +* If there is a bitstream in the partition header then the +* execution time includes the copying of the bitstream to DDR +* (in case of SD/NAND bootmode) +* and programming the devcfg dma is accounted. +* +* FSBL provides two debug levels +* DEBUG GENERAL - fsbl_printf under this category will appear only when the +* FSBL_DEBUG flag is set during compilation +* DEBUG_INFO - fsbl_printf under this category will appear when the +* FSBL_DEBUG_INFO flag is set during compilation +* For a more detailed output log can be used. +* FSBL_DEBUG_RSA - Define this macro to print more detailed values used in +* RSA functions +* These macros are input to the fsbl_printf function +* +* DEBUG LEVELS +* FSBL_DEBUG level is level 1, when this flag is set all the fsbl_prints +* that are with the DEBUG_GENERAL argument are shown +* FSBL_DEBUG_INFO is level 2, when this flag is set during the +* compilation , the fsbl_printf with DEBUG_INFO will appear on the com port +* +* DEFAULT LEVEL +* By default no print messages will appear. +* +* NON_PS_INSTANTIATED_BITSTREAM +* +* FSBL will not enable the level shifters for a NON PS instantiated +* Bitstream.This flag can be set during compilation for a NON PS instantiated +* bitstream +* +* ECC_ENABLE +* This flag will be defined in the ps7_init.h file when ECC is enabled +* in the DDR configuration (XPS GUI) +* +* RSA_SUPPORT +* This flag is used to enable authentication feature +* Default this macro disabled, reason to avoid increase in code size +* +* MMC_SUPPORT +* This flag is used to enable MMC support feature +* +*******************************************************************************/ +#ifndef XIL_FSBL_H +#define XIL_FSBL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ +#include "xil_io.h" +#include "xparameters.h" +#include "xpseudo_asm.h" +#include "xil_printf.h" +#include "pcap.h" +#include "fsbl_debug.h" +#include "ps7_init.h" +#ifdef FSBL_PERF +#include "xtime_l.h" +#include +#endif + + +/************************** Constant Definitions *****************************/ +/* + * SDK release version + */ +#define SDK_RELEASE_YEAR 2016 +#define SDK_RELEASE_QUARTER 4 + +#define WORD_LENGTH_SHIFT 2 + +/* + * On a Successful handoff to an application FSBL sets this SUCCESS code + */ +#define SUCCESSFUL_HANDOFF 0x1 /* Successful Handoff */ + +/* + * Backward compatibility for ps7_init + */ +#ifdef NEW_PS7_ERR_CODE +#define FSBL_PS7_INIT_SUCCESS PS7_INIT_SUCCESS +#else +#define FSBL_PS7_INIT_SUCCESS (1) +#endif + +/* + * ERROR CODES + * The following are the Error codes that FSBL uses + * If the Debug prints are enabled only then the error codes will be + * seen on the com port.Without the debug prints enabled no error codes will + * be visible.There are not saved in any register + * Boot Mode States used for error and status output + * Error codes are defined below + */ +#define ILLEGAL_BOOT_MODE 0xA000 /**< Illegal boot mode */ +#define ILLEGAL_RETURN 0xA001 /**< Illegal return */ +#define PCAP_INIT_FAIL 0xA002 /**< Pcap driver Init Failed */ +#define DECRYPTION_FAIL 0xA003 /**< Decryption Failed */ +#define BITSTREAM_DOWNLOAD_FAIL 0xA004 /**< Bitstream download fail */ +#define DMA_TRANSFER_FAIL 0xA005 /**< DMA Transfer Fail */ +#define INVALID_FLASH_ADDRESS 0xA006 /**< Invalid Flash Address */ +#define DDR_INIT_FAIL 0xA007 /**< DDR Init Fail */ +#define NO_DDR 0xA008 /**< DDR missing */ +#define SD_INIT_FAIL 0xA009 /**< SD Init fail */ +#define NAND_INIT_FAIL 0xA00A /**< Nand Init Fail */ +#define PARTITION_MOVE_FAIL 0xA00B /**< Partition move fail */ +#define AUTHENTICATION_FAIL 0xA00C /**< Authentication fail */ +#define INVALID_HEADER_FAIL 0xA00D /**< Invalid header fail */ +#define GET_HEADER_INFO_FAIL 0xA00E /**< Get header fail */ +#define INVALID_LOAD_ADDRESS_FAIL 0xA00F /**< Invalid load address fail */ +#define PARTITION_CHECKSUM_FAIL 0xA010 /**< Partition checksum fail */ +#define RSA_SUPPORT_NOT_ENABLED_FAIL 0xA011 /**< RSA not enabled fail */ +#define PS7_INIT_FAIL 0xA012 /**< ps7 Init Fail */ +/* + * FSBL Exception error codes + */ +#define EXCEPTION_ID_UNDEFINED_INT 0xA301 /**< Undefined INT Exception */ +#define EXCEPTION_ID_SWI_INT 0xA302 /**< SWI INT Exception */ +#define EXCEPTION_ID_PREFETCH_ABORT_INT 0xA303 /**< Prefetch Abort xception */ +#define EXCEPTION_ID_DATA_ABORT_INT 0xA304 /**< Data Abort Exception */ +#define EXCEPTION_ID_IRQ_INT 0xA305 /**< IRQ Exception Occurred */ +#define EXCEPTION_ID_FIQ_INT 0xA306 /**< FIQ Exception Occurred */ + +/* + * FSBL hook routine failures + */ +#define FSBL_HANDOFF_HOOK_FAIL 0xA401 /**< FSBL handoff hook failed */ +#define FSBL_BEFORE_BSTREAM_HOOK_FAIL 0xA402 /**< FSBL before bit stream + download hook failed */ +#define FSBL_AFTER_BSTREAM_HOOK_FAIL 0xA403 /**< FSBL after bitstream + download hook failed */ + +/* + * Watchdog related Error codes + */ +#define WDT_RESET_OCCURED 0xA501 /**< WDT Reset happened in FSBL */ +#define WDT_INIT_FAIL 0xA502 /**< WDT driver INIT failed */ + +/* + * SLCR Registers + */ +#define PS_RST_CTRL_REG (XPS_SYS_CTRL_BASEADDR + 0x200) +#define FPGA_RESET_REG (XPS_SYS_CTRL_BASEADDR + 0x240) +#define RESET_REASON_REG (XPS_SYS_CTRL_BASEADDR + 0x250) +#define RESET_REASON_CLR (XPS_SYS_CTRL_BASEADDR + 0x254) +#define REBOOT_STATUS_REG (XPS_SYS_CTRL_BASEADDR + 0x258) +#define BOOT_MODE_REG (XPS_SYS_CTRL_BASEADDR + 0x25C) +#define PS_LVL_SHFTR_EN (XPS_SYS_CTRL_BASEADDR + 0x900) + +/* + * Efuse Status Register + */ +#define EFUSE_STATUS_REG (0xF800D010) /**< Efuse Status Register */ +#define EFUSE_STATUS_RSA_ENABLE_MASK (0x400) /**< Status of RSA enable */ + +/* + * PS reset control register define + */ +#define PS_RST_MASK 0x1 /**< PS software reset */ + +/* + * SLCR BOOT Mode Register defines + */ +#define BOOT_MODES_MASK 0x00000007 /**< FLASH types */ + +/* + * Boot Modes + */ +#define JTAG_MODE 0x00000000 /**< JTAG Boot Mode */ +#define QSPI_MODE 0x00000001 /**< QSPI Boot Mode */ +#define NOR_FLASH_MODE 0x00000002 /**< NOR Boot Mode */ +#define NAND_FLASH_MODE 0x00000004 /**< NAND Boot Mode */ +#define SD_MODE 0x00000005 /**< SD Boot Mode */ +#define MMC_MODE 0x00000006 /**< MMC Boot Device */ + +#define RESET_REASON_SRST 0x00000020 /**< Reason for reset is SRST */ +#define RESET_REASON_SWDT 0x00000001 /**< Reason for reset is SWDT */ + +/* + * Golden image offset + */ +#define GOLDEN_IMAGE_OFFSET 0x8000 + +/* + * Silicon Version + */ +#define SILICON_VERSION_1 0 +#define SILICON_VERSION_2 1 +#define SILICON_VERSION_3 2 +#define SILICON_VERSION_3_1 3 + +/* + * DDR start address for storing the data temporarily(1M) + * Need to finalize correct logic + */ +#ifdef XPAR_PS7_DDR_0_S_AXI_BASEADDR +#define DDR_START_ADDR XPAR_PS7_DDR_0_S_AXI_BASEADDR +#define DDR_END_ADDR XPAR_PS7_DDR_0_S_AXI_HIGHADDR +#else +/* + * In case of PL DDR, this macros defined based PL DDR address + */ +#define DDR_START_ADDR 0x00 +#define DDR_END_ADDR 0x00 +#endif + +#define DDR_TEMP_START_ADDR DDR_START_ADDR +/* + * DDR test pattern + */ +#define DDR_TEST_PATTERN 0xAA55AA55 +#define DDR_TEST_OFFSET 0x100000 +/* + * + */ +#define QSPI_DUAL_FLASH_SIZE 0x2000000; /*32MB*/ +#define QSPI_SINGLE_FLASH_SIZE 0x1000000; /*16MB*/ +#define NAND_FLASH_SIZE 0x8000000; /*128MB*/ +#define NOR_FLASH_SIZE 0x2000000; /*32MB*/ +#define LQSPI_CFG_OFFSET 0xA0 +#define LQSPI_CFG_DUAL_FLASH_MASK 0x40000000 + +/* + * These are the SLCR lock and unlock macros + */ +#define SlcrUnlock() Xil_Out32(XPS_SYS_CTRL_BASEADDR + 0x08, 0xDF0DDF0D) +#define SlcrLock() Xil_Out32(XPS_SYS_CTRL_BASEADDR + 0x04, 0x767B767B) + +#define IMAGE_HEADER_CHECKSUM_COUNT 10 + +/* Boot ROM Image defines */ +#define IMAGE_WIDTH_CHECK_OFFSET (0x020) /**< 0xaa995566 Width Detection word */ +#define IMAGE_IDENT_OFFSET (0x024) /**< 0x584C4E58 "XLNX" */ +#define IMAGE_ENC_FLAG_OFFSET (0x028) /**< 0xA5C3C5A3 */ +#define IMAGE_USR_DEF_OFFSET (0x02C) /**< undefined could be used as */ +#define IMAGE_SOURCE_ADDR_OFFSET (0x030) /**< start address of image */ +#define IMAGE_BYTE_LEN_OFFSET (0x034) /**< length of image> in bytes */ +#define IMAGE_DEST_ADDR_OFFSET (0x038) /**< destination address in OCM */ +#define IMAGE_EXECUTE_ADDR_OFFSET (0x03c) /**< address to start executing at */ +#define IMAGE_TOT_BYTE_LEN_OFFSET (0x040) /**< total length of image in bytes */ +#define IMAGE_QSPI_CFG_WORD_OFFSET (0x044) /**< QSPI configuration data */ +#define IMAGE_CHECKSUM_OFFSET (0x048) /**< Header Checksum offset */ +#define IMAGE_IDENT (0x584C4E58) /**< XLNX pattern */ + +/* Reboot status register defines: + * 0xF0000000 for FSBL fallback mask to notify Boot Rom + * 0x60000000 for FSBL to mark that FSBL has not handoff yet + * 0x00FFFFFF for user application to use across soft reset + */ +#define FSBL_FAIL_MASK 0xF0000000 +#define FSBL_IN_MASK 0x60000000 + +/* The address that holds the base address for the image Boot ROM found */ +#define BASEADDR_HOLDER 0xFFFFFFF8 + +/**************************** Type Definitions *******************************/ + +/************************** Function Prototypes ******************************/ + +void OutputStatus(u32 State); +void FsblFallback(void); + +int FsblSetNextPartition(int Num); +void *(memcpy_rom)(void * s1, const void * s2, u32 n); +char *strcpy_rom(char *Dest, const char *Src); + +void ClearFSBLIn(void); +void MarkFSBLIn(void); +void FsblHandoff(u32 FsblStartAddr); +u32 GetResetReason(void); + +#ifdef FSBL_PERF +void FsblGetGlobalTime (XTime * tCur); +void FsblMeasurePerfTime (XTime tCur, XTime tEnd); +#endif +void GetSiliconVersion(void); +void FsblHandoffExit(u32 FsblStartAddr); +void FsblHandoffJtagExit(); +/************************** Variable Definitions *****************************/ +extern int SkipPartition; + +/***************** Macros (Inline Functions) Definitions *********************/ + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ diff --git a/sdk/fsbl/src/fsbl_debug.h b/sdk/fsbl/src/fsbl_debug.h new file mode 100644 index 0000000..2c41c23 --- /dev/null +++ b/sdk/fsbl/src/fsbl_debug.h @@ -0,0 +1,82 @@ +/****************************************************************************** +* +* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file fsbl_debug.h +* +* This file contains the debug verbose information for FSBL print functionality +* +*
+* MODIFICATION HISTORY:
+*
+* Ver	Who	Date		Changes
+* ----- ---- -------- -------------------------------------------------------
+* 3.00a mb	01/09/12 Initial release
+*
+* 
+* +* @note +* +******************************************************************************/ + +#ifndef _FSBL_DEBUG_H +#define _FSBL_DEBUG_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#define DEBUG_GENERAL 0x00000001 /* general debug messages */ +#define DEBUG_INFO 0x00000002 /* More debug information */ + +#if defined (FSBL_DEBUG_INFO) +#define fsbl_dbg_current_types ((DEBUG_INFO) | (DEBUG_GENERAL)) +#elif defined (FSBL_DEBUG) +#define fsbl_dbg_current_types (DEBUG_GENERAL) +#else +#define fsbl_dbg_current_types 0 +#endif + +#ifdef STDOUT_BASEADDRESS +#define fsbl_printf(type,...) \ + if (((type) & fsbl_dbg_current_types)) {xil_printf (__VA_ARGS__); } +#else +#define fsbl_printf(type, ...) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _FSBL_DEBUG_H */ diff --git a/sdk/fsbl/src/fsbl_handoff.S b/sdk/fsbl/src/fsbl_handoff.S new file mode 100644 index 0000000..0b42c81 --- /dev/null +++ b/sdk/fsbl/src/fsbl_handoff.S @@ -0,0 +1,221 @@ +#ifdef __GNUC__ +/****************************************************************************** +* +* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file handoff.S +* +* Contains the code that does the handoff to the loaded application. This +* code lives high in the ROM. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver	Who	Date.word	Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a ecm	03/01/10 Initial release
+* 7.00a kc	10/23/13 Added support for armcc compiler
+* 
+* +* @note +* Assumes that the starting address of the FSBL is provided by the calling routine +* in R0. +* +******************************************************************************/ + +.globl FsblHandoffJtagExit + +.globl FsblHandoffExit + +.section .handoff,"axS" + +/***************************** Include Files *********************************/ + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +/************************** Variable Definitions *****************************/ + +FsblHandoffJtagExit: + mcr 15,0,r0,cr7,cr5,0 /* Invalidate Instruction cache */ + mcr 15,0,r0,cr7,cr5,6 /* Invalidate branch predictor array */ + + dsb + isb /* make sure it completes */ + + ldr r4, =0 + mcr 15,0,r4,cr1,cr0,0 /* disable the ICache and MMU */ + + isb /* make sure it completes */ +Loop: + wfe + b Loop + +FsblHandoffExit: + mov lr, r0 /* move the destination address into link register */ + + mcr 15,0,r0,cr7,cr5,0 /* Invalidate Instruction cache */ + mcr 15,0,r0,cr7,cr5,6 /* Invalidate branch predictor array */ + + dsb + isb /* make sure it completes */ + + ldr r4, =0 + mcr 15,0,r4,cr1,cr0,0 /* disable the ICache and MMU */ + + isb /* make sure it completes */ + + + bx lr /* force the switch, destination should have been in r0 */ + +.Ldone: b .Ldone /* Paranoia: we should never get here */ +.end + +#elif defined (__IASMARM__) + + PUBLIC FsblHandoffJtagExit + + PUBLIC FsblHandoffExit + + SECTION .handoff:CODE:NOROOT(2) + +/***************************** Include Files *********************************/ + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +/************************** Variable Definitions *****************************/ + +FsblHandoffJtagExit + mcr p15,0,r0,c7,c5,0 ;/* Invalidate Instruction cache */ + mcr p15,0,r0,c7,c5,6 ;/* Invalidate branch predictor array */ + + dsb + isb ;/* make sure it completes */ + + ldr r4, =0 + mcr p15,0,r4,c1,c0,0 ;/* disable the ICache and MMU */ + + isb ;/* make sure it completes */ +Loop + wfe + b Loop + +FsblHandoffExit + mov lr, r0 ;/* move the destination address into link register */ + + mcr p15,0,r0,c7,c5,0 ;/* Invalidate Instruction cache */ + mcr p15,0,r0,c7,c5,6 ;/* Invalidate branch predictor array */ + + dsb + isb ;/* make sure it completes */ + + ldr r4, =0 + mcr p15,0,r4,c1,c0,0 ;/* disable the ICache and MMU */ + + isb ;/* make sure it completes */ + + + bx lr ;/* force the switch, destination should have been in r0 */ + +.Ldone + b .Ldone ;/* Paranoia: we should never get here */ + + END + + +#else + EXPORT FsblHandoffJtagExit + + EXPORT FsblHandoffExit + + AREA |.handoff|,CODE + +;/***************************** Include Files *********************************/ + +;/************************** Constant Definitions *****************************/ + +;/**************************** Type Definitions *******************************/ + +;/***************** Macros (Inline Functions) Definitions *********************/ + +;/************************** Function Prototypes ******************************/ + +;/************************** Variable Definitions *****************************/ + + +FsblHandoffJtagExit + mcr p15,0,r0,c7,c5,0 ;/* Invalidate Instruction cache */ + mcr p15,0,r0,c7,c5,6 ;/* Invalidate branch predictor array */ + + dsb + isb ;/* make sure it completes */ + + ldr r4, =0 + mcr p15,0,r4,c1,c0,0 ;/* disable the ICache and MMU */ + + isb ;/* make sure it completes */ +Loop + wfe + b Loop + +FsblHandoffExit + mov lr, r0 ;/* move the destination address into link register */ + + mcr p15,0,r0,c7,c5,0 ;/* Invalidate Instruction cache */ + mcr p15,0,r0,c7,c5,6 ;/* Invalidate branch predictor array */ + + dsb + isb ;/* make sure it completes */ + + ldr r4, =0 + mcr p15,0,r4,c1,c0,0 ;/* disable the ICache and MMU */ + + isb ;/* make sure it completes */ + + + bx lr ;/* force the switch, destination should have been in r0 */ + +Ldone b Ldone ;/* Paranoia: we should never get here */ + END +#endif diff --git a/sdk/fsbl/src/fsbl_hooks.c b/sdk/fsbl/src/fsbl_hooks.c new file mode 100644 index 0000000..304a6db --- /dev/null +++ b/sdk/fsbl/src/fsbl_hooks.c @@ -0,0 +1,164 @@ +/****************************************************************************** +* +* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ + +/***************************************************************************** +* +* @file fsbl_hooks.c +* +* This file provides functions that serve as user hooks. The user can add the +* additional functionality required into these routines. This would help retain +* the normal FSBL flow unchanged. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date        Changes
+* ----- ---- -------- -------------------------------------------------------
+* 3.00a np   08/03/12 Initial release
+* 
+* +* @note +* +******************************************************************************/ + + +#include "fsbl.h" +#include "xstatus.h" +#include "fsbl_hooks.h" + +/************************** Variable Definitions *****************************/ + + +/************************** Function Prototypes ******************************/ + + +/****************************************************************************** +* This function is the hook which will be called before the bitstream download. +* The user can add all the customized code required to be executed before the +* bitstream download to this routine. +* +* @param None +* +* @return +* - XST_SUCCESS to indicate success +* - XST_FAILURE.to indicate failure +* +****************************************************************************/ +u32 FsblHookBeforeBitstreamDload(void) +{ + u32 Status; + + Status = XST_SUCCESS; + + /* + * User logic to be added here. Errors to be stored in the status variable + * and returned + */ + fsbl_printf(DEBUG_INFO,"In FsblHookBeforeBitstreamDload function \r\n"); + + return (Status); +} + +/****************************************************************************** +* This function is the hook which will be called after the bitstream download. +* The user can add all the customized code required to be executed after the +* bitstream download to this routine. +* +* @param None +* +* @return +* - XST_SUCCESS to indicate success +* - XST_FAILURE.to indicate failure +* +****************************************************************************/ +u32 FsblHookAfterBitstreamDload(void) +{ + u32 Status; + + Status = XST_SUCCESS; + + /* + * User logic to be added here. + * Errors to be stored in the status variable and returned + */ + fsbl_printf(DEBUG_INFO, "In FsblHookAfterBitstreamDload function \r\n"); + + return (Status); +} + +/****************************************************************************** +* This function is the hook which will be called before the FSBL does a handoff +* to the application. The user can add all the customized code required to be +* executed before the handoff to this routine. +* +* @param None +* +* @return +* - XST_SUCCESS to indicate success +* - XST_FAILURE.to indicate failure +* +****************************************************************************/ +u32 FsblHookBeforeHandoff(void) +{ + u32 Status; + + Status = XST_SUCCESS; + + /* + * User logic to be added here. + * Errors to be stored in the status variable and returned + */ + fsbl_printf(DEBUG_INFO,"In FsblHookBeforeHandoff function \r\n"); + + return (Status); +} + + +/****************************************************************************** +* This function is the hook which will be called in case FSBL fall back +* +* @param None +* +* @return None +* +****************************************************************************/ +void FsblHookFallback(void) +{ + /* + * User logic to be added here. + * Errors to be stored in the status variable and returned + */ + fsbl_printf(DEBUG_INFO,"In FsblHookFallback function \r\n"); + while(1); +} + + diff --git a/sdk/fsbl/src/fsbl_hooks.h b/sdk/fsbl/src/fsbl_hooks.h new file mode 100644 index 0000000..784f7ed --- /dev/null +++ b/sdk/fsbl/src/fsbl_hooks.h @@ -0,0 +1,81 @@ +/****************************************************************************** +* +* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file fsbl_hooks.h +* +* Contains the function prototypes, defines and macros required by fsbl_hooks.c +* +*
+* MODIFICATION HISTORY:
+*
+* Ver	Who	Date		Changes
+* ----- ---- -------- -------------------------------------------------------
+* 3.00a	np/mb	10/08/12	Initial release
+*				Corrected the prototype
+*
+* 
+* +* @note +* +******************************************************************************/ +#ifndef FSBL_HOOKS_H_ +#define FSBL_HOOKS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ +#include "fsbl.h" + + +/************************** Function Prototypes ******************************/ + +/* FSBL hook function which is called before bitstream download */ +u32 FsblHookBeforeBitstreamDload(void); + +/* FSBL hook function which is called after bitstream download */ +u32 FsblHookAfterBitstreamDload(void); + +/* FSBL hook function which is called before handoff to the application */ +u32 FsblHookBeforeHandoff(void); + +/* FSBL hook function which is called in FSBL fallback */ +void FsblHookFallback(void); + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ diff --git a/sdk/fsbl/src/image_mover.c b/sdk/fsbl/src/image_mover.c new file mode 100644 index 0000000..1bad673 --- /dev/null +++ b/sdk/fsbl/src/image_mover.c @@ -0,0 +1,1335 @@ +/****************************************************************************** +* +* Copyright (C) 2011 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file image_mover.c +* +* Move partitions to either DDR to execute or to program FPGA. +* It performs partition walk. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver	Who	Date		Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a jz	05/24/11	Initial release
+* 2.00a jz	06/30/11	Updated partition header defs for 64-byte
+*			 			alignment change in data2mem tool
+* 2.00a mb	05/25/12	Updated for standalone based bsp FSBL
+* 			 			Nand/SD encryption and review comments
+* 3.00a np	08/30/12	Added FSBL user hook calls
+* 						(before and after bitstream download.)
+* 4.00a sgd	02/28/13	Fix for CR#691148 Secure bootmode error in devcfg test
+*						Fix for CR#695578 FSBL failed to load standalone 
+*						application in secure bootmode
+*
+* 4.00a sgd	04/23/13	Fix for CR#710128 FSBL failed to load standalone 
+*						application in secure bootmode
+* 5.00a kc	07/30/13	Fix for CR#724165 Partition Header used by FSBL 
+*						is not authenticated
+* 						Fix for CR#724166 FSBL doesn�t use PPK authenticated 
+*						by Boot ROM for authenticating the Partition images 
+* 						Fix for CR#732062 FSBL fails to build if UART not 
+*						available 
+* 7.00a kc  10/30/13    Fix for CR#755245 FSBL does not load partition
+*                       if eMMC has only one partition
+* 8.00a kc  01/16/13    Fix for CR#767798  FSBL MD5 Checksum failure
+* 						for encrypted images
+*						Fix for CR#761895 FSBL should authenticate image
+*						only if partition owner was not set to u-boot
+* 9.00a kc  04/16/14    Fix for CR#785778  FSBL takes 8 seconds to 
+* 						authenticate (RSA) a bitstream on zc706
+* 10.00a kc 07/15/14	Fix for CR#804595 Zynq FSBL - Issues with
+* 						fallback image offset handling using MD5
+* 						Fix for PR#782309 Fallback support for AES
+* 						encryption with E-Fuse - Enhancement
+*
+* 
+* +* @note +* A partition is either an executable or a bitstream to program FPGA +* +******************************************************************************/ + +/***************************** Include Files *********************************/ +#include "fsbl.h" +#include "image_mover.h" +#include "xil_printf.h" +#include "xreg_cortexa9.h" +#include "pcap.h" +#include "fsbl_hooks.h" +#include "md5.h" + +#ifdef XPAR_XWDTPS_0_BASEADDR +#include "xwdtps.h" +#endif + +#ifdef RSA_SUPPORT +#include "rsa.h" +#include "xil_cache.h" +#endif +/************************** Constant Definitions *****************************/ + +/* We are 32-bit machine */ +#define MAXIMUM_IMAGE_WORD_LEN 0x40000000 +#define MD5_CHECKSUM_SIZE 16 + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ +u32 ValidateParition(u32 StartAddr, u32 Length, u32 ChecksumOffset); +u32 GetPartitionChecksum(u32 ChecksumOffset, u8 *Checksum); +u32 CalcPartitionChecksum(u32 SourceAddr, u32 DataLength, u8 *Checksum); + +/************************** Variable Definitions *****************************/ +/* + * Partition information flags + */ +u8 EncryptedPartitionFlag; +u8 PLPartitionFlag; +u8 PSPartitionFlag; +u8 SignedPartitionFlag; +u8 PartitionChecksumFlag; +u8 BitstreamFlag; +u8 ApplicationFlag; + +u32 ExecutionAddress; +ImageMoverType MoveImage; + +/* + * Header array + */ +PartHeader PartitionHeader[MAX_PARTITION_NUMBER]; +u32 PartitionCount; +u32 FsblLength; + +#ifdef XPAR_XWDTPS_0_BASEADDR +extern XWdtPs Watchdog; /* Instance of WatchDog Timer */ +#endif + +extern u32 Silicon_Version; +extern u32 FlashReadBaseAddress; +extern u8 LinearBootDeviceFlag; +extern XDcfg *DcfgInstPtr; + +/*****************************************************************************/ +/** +* +* This function +* +* @param +* +* @return +* +* +* @note None +* +****************************************************************************/ +u32 LoadBootImage(void) +{ + u32 RebootStatusRegister = 0; + u32 MultiBootReg = 0; + u32 ImageStartAddress = 0; + u32 PartitionNum; + u32 PartitionDataLength; + u32 PartitionImageLength; + u32 PartitionTotalSize; + u32 PartitionExecAddr; + u32 PartitionAttr; + u32 ExecAddress = 0; + u32 PartitionLoadAddr; + u32 PartitionStartAddr; + u32 PartitionChecksumOffset; + u8 ExecAddrFlag = 0 ; + u32 Status; + PartHeader *HeaderPtr; + u32 EfuseStatusRegValue; +#ifdef RSA_SUPPORT + u32 HeaderSize; +#endif + /* + * Resetting the Flags + */ + BitstreamFlag = 0; + ApplicationFlag = 0; + + RebootStatusRegister = Xil_In32(REBOOT_STATUS_REG); + fsbl_printf(DEBUG_INFO, + "Reboot status register: 0x%08lx\r\n",RebootStatusRegister); + + if (Silicon_Version == SILICON_VERSION_1) { + /* + * Clear out fallback mask from previous run + * We start from the first partition again + */ + if ((RebootStatusRegister & FSBL_FAIL_MASK) == + FSBL_FAIL_MASK) { + fsbl_printf(DEBUG_INFO, + "Reboot status shows previous run falls back\r\n"); + RebootStatusRegister &= ~(FSBL_FAIL_MASK); + Xil_Out32(REBOOT_STATUS_REG, RebootStatusRegister); + } + + /* + * Read the image start address + */ + ImageStartAddress = *(u32 *)BASEADDR_HOLDER; + } else { + /* + * read the multiboot register + */ + MultiBootReg = XDcfg_ReadReg(DcfgInstPtr->Config.BaseAddr, + XDCFG_MULTIBOOT_ADDR_OFFSET); + + fsbl_printf(DEBUG_INFO,"Multiboot Register: 0x%08lx\r\n",MultiBootReg); + + /* + * Compute the image start address + */ + ImageStartAddress = (MultiBootReg & PCAP_MBOOT_REG_REBOOT_OFFSET_MASK) + * GOLDEN_IMAGE_OFFSET; + } + + fsbl_printf(DEBUG_INFO,"Image Start Address: 0x%08lx\r\n",ImageStartAddress); + + /* + * Get partitions header information + */ + Status = GetPartitionHeaderInfo(ImageStartAddress); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL, "Partition Header Load Failed\r\n"); + OutputStatus(GET_HEADER_INFO_FAIL); + FsblFallback(); + } + + /* + * RSA is not implemented in 1.0 and 2.0 + * silicon + */ + if ((Silicon_Version != SILICON_VERSION_1) && + (Silicon_Version != SILICON_VERSION_2)) { + /* + * Read Efuse Status Register + */ + EfuseStatusRegValue = Xil_In32(EFUSE_STATUS_REG); + if (EfuseStatusRegValue & EFUSE_STATUS_RSA_ENABLE_MASK) { + fsbl_printf(DEBUG_GENERAL,"RSA enabled for Chip\r\n"); +#ifdef RSA_SUPPORT + /* + * Set the Ppk + */ + SetPpk(); + + /* + * Read partition header with signature + */ + Status = GetImageHeaderAndSignature(ImageStartAddress, + (u32 *)DDR_TEMP_START_ADDR); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL, + "Read Partition Header signature Failed\r\n"); + OutputStatus(GET_HEADER_INFO_FAIL); + FsblFallback(); + } + HeaderSize=TOTAL_HEADER_SIZE+RSA_SIGNATURE_SIZE; + + Status = AuthenticatePartition((u8 *)DDR_TEMP_START_ADDR, HeaderSize); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL, + "Partition Header signature Failed\r\n"); + OutputStatus(GET_HEADER_INFO_FAIL); + FsblFallback(); + } +#else + /* + * In case user not enabled RSA authentication feature + */ + fsbl_printf(DEBUG_GENERAL,"RSA_SUPPORT_NOT_ENABLED_FAIL\r\n"); + OutputStatus(RSA_SUPPORT_NOT_ENABLED_FAIL); + FsblFallback(); +#endif + } + } + +#ifdef MMC_SUPPORT + /* + * In case of MMC support + * boot image preset in MMC will not have FSBL partition + */ + PartitionNum = 0; +#else + /* + * First partition header was ignored by FSBL + * As it contain FSBL partition information + */ + PartitionNum = 1; +#endif + + while (PartitionNum < PartitionCount) { + + fsbl_printf(DEBUG_INFO, "Partition Number: %lu\r\n", PartitionNum); + + HeaderPtr = &PartitionHeader[PartitionNum]; + + /* + * Print partition header information + */ + HeaderDump(HeaderPtr); + + /* + * Validate partition header + */ + Status = ValidateHeader(HeaderPtr); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL, "INVALID_HEADER_FAIL\r\n"); + OutputStatus(INVALID_HEADER_FAIL); + FsblFallback(); + } + + /* + * Load partition header information in to local variables + */ + PartitionDataLength = HeaderPtr->DataWordLen; + PartitionImageLength = HeaderPtr->ImageWordLen; + PartitionExecAddr = HeaderPtr->ExecAddr; + PartitionAttr = HeaderPtr->PartitionAttr; + PartitionLoadAddr = HeaderPtr->LoadAddr; + PartitionChecksumOffset = HeaderPtr->CheckSumOffset; + PartitionStartAddr = HeaderPtr->PartitionStart; + PartitionTotalSize = HeaderPtr->PartitionWordLen; + + /* + * Partition owner should be FSBL to validate the partition + */ + if ((PartitionAttr & ATTRIBUTE_PARTITION_OWNER_MASK) != + ATTRIBUTE_PARTITION_OWNER_FSBL) { + /* + * if FSBL is not the owner of partition, + * skip this partition, continue with next partition + */ + fsbl_printf(DEBUG_INFO, "Skipping partition %0lx\r\n", + PartitionNum); + /* + * Increment partition number + */ + PartitionNum++; + continue; + } + + if (PartitionAttr & ATTRIBUTE_PL_IMAGE_MASK) { + fsbl_printf(DEBUG_INFO, "Bitstream\r\n"); + PLPartitionFlag = 1; + PSPartitionFlag = 0; + BitstreamFlag = 1; + if (ApplicationFlag == 1) { +#ifdef STDOUT_BASEADDRESS + xil_printf("\r\nFSBL Warning !!!" + "Bitstream not loaded into PL\r\n"); + xil_printf("Partition order invalid\r\n"); +#endif + break; + } + } + + if (PartitionAttr & ATTRIBUTE_PS_IMAGE_MASK) { + fsbl_printf(DEBUG_INFO, "Application\r\n"); + PSPartitionFlag = 1; + PLPartitionFlag = 0; + ApplicationFlag = 1; + } + + /* + * Encrypted partition will have different value + * for Image length and data length + */ + if (PartitionDataLength != PartitionImageLength) { + fsbl_printf(DEBUG_INFO, "Encrypted\r\n"); + EncryptedPartitionFlag = 1; + } else { + EncryptedPartitionFlag = 0; + } + + /* + * Check for partition checksum check + */ + if (PartitionAttr & ATTRIBUTE_CHECKSUM_TYPE_MASK) { + PartitionChecksumFlag = 1; + } else { + PartitionChecksumFlag = 0; + } + + /* + * RSA signature check + */ + if (PartitionAttr & ATTRIBUTE_RSA_PRESENT_MASK) { + fsbl_printf(DEBUG_INFO, "RSA Signed\r\n"); + SignedPartitionFlag = 1; + } else { + SignedPartitionFlag = 0; + } + + /* + * Load address check + * Loop will break when PS load address zero and partition is + * un-signed or un-encrypted + */ + if ((PSPartitionFlag == 1) && (PartitionLoadAddr < DDR_START_ADDR)) { + if ((PartitionLoadAddr == 0) && + (!((SignedPartitionFlag == 1) || + (EncryptedPartitionFlag == 1)))) { + break; + } else { + fsbl_printf(DEBUG_GENERAL, + "INVALID_LOAD_ADDRESS_FAIL\r\n"); + OutputStatus(INVALID_LOAD_ADDRESS_FAIL); + FsblFallback(); + } + } + + if (PSPartitionFlag && (PartitionLoadAddr > DDR_END_ADDR)) { + fsbl_printf(DEBUG_GENERAL, + "INVALID_LOAD_ADDRESS_FAIL\r\n"); + OutputStatus(INVALID_LOAD_ADDRESS_FAIL); + FsblFallback(); + } + + /* + * Load execution address of first PS partition + */ + if (PSPartitionFlag && (!ExecAddrFlag)) { + ExecAddrFlag++; + ExecAddress = PartitionExecAddr; + } + + /* + * FSBL user hook call before bitstream download + */ + if (PLPartitionFlag) { + Status = FsblHookBeforeBitstreamDload(); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL,"FSBL_BEFORE_BSTREAM_HOOK_FAIL\r\n"); + OutputStatus(FSBL_BEFORE_BSTREAM_HOOK_FAIL); + FsblFallback(); + } + } + + /* + * Move partitions from boot device + */ + Status = PartitionMove(ImageStartAddress, HeaderPtr); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL,"PARTITION_MOVE_FAIL\r\n"); + OutputStatus(PARTITION_MOVE_FAIL); + FsblFallback(); + } + + if ((SignedPartitionFlag) || (PartitionChecksumFlag)) { + if(PLPartitionFlag) { + /* + * PL partition loaded in to DDR temporary address + * for authentication and checksum verification + */ + PartitionStartAddr = DDR_TEMP_START_ADDR; + } else { + PartitionStartAddr = PartitionLoadAddr; + } + + if (PartitionChecksumFlag) { + /* + * Validate the partition data with checksum + */ + Status = ValidateParition(PartitionStartAddr, + (PartitionTotalSize << WORD_LENGTH_SHIFT), + ImageStartAddress + + (PartitionChecksumOffset << WORD_LENGTH_SHIFT)); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL,"PARTITION_CHECKSUM_FAIL\r\n"); + OutputStatus(PARTITION_CHECKSUM_FAIL); + FsblFallback(); + } + + fsbl_printf(DEBUG_INFO, "Partition Validation Done\r\n"); + } + + /* + * Authentication Partition + */ + if (SignedPartitionFlag == 1 ) { +#ifdef RSA_SUPPORT + Xil_DCacheEnable(); + Status = AuthenticatePartition((u8*)PartitionStartAddr, + (PartitionTotalSize << WORD_LENGTH_SHIFT)); + if (Status != XST_SUCCESS) { + Xil_DCacheFlush(); + Xil_DCacheDisable(); + fsbl_printf(DEBUG_GENERAL,"AUTHENTICATION_FAIL\r\n"); + OutputStatus(AUTHENTICATION_FAIL); + FsblFallback(); + } + fsbl_printf(DEBUG_INFO,"Authentication Done\r\n"); + Xil_DCacheFlush(); + Xil_DCacheDisable(); +#else + /* + * In case user not enabled RSA authentication feature + */ + fsbl_printf(DEBUG_GENERAL,"RSA_SUPPORT_NOT_ENABLED_FAIL\r\n"); + OutputStatus(RSA_SUPPORT_NOT_ENABLED_FAIL); + FsblFallback(); +#endif + } + + /* + * Decrypt PS partition + */ + if (EncryptedPartitionFlag && PSPartitionFlag) { + Status = DecryptPartition(PartitionStartAddr, + PartitionDataLength, + PartitionImageLength); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL,"DECRYPTION_FAIL\r\n"); + OutputStatus(DECRYPTION_FAIL); + FsblFallback(); + } + } + + /* + * Load Signed PL partition in Fabric + */ + if (PLPartitionFlag) { + Status = PcapLoadPartition((u32*)PartitionStartAddr, + (u32*)PartitionLoadAddr, + PartitionImageLength, + PartitionDataLength, + EncryptedPartitionFlag); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL,"BITSTREAM_DOWNLOAD_FAIL\r\n"); + OutputStatus(BITSTREAM_DOWNLOAD_FAIL); + FsblFallback(); + } + } + } + + + /* + * FSBL user hook call after bitstream download + */ + if (PLPartitionFlag) { + Status = FsblHookAfterBitstreamDload(); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL,"FSBL_AFTER_BSTREAM_HOOK_FAIL\r\n"); + OutputStatus(FSBL_AFTER_BSTREAM_HOOK_FAIL); + FsblFallback(); + } + } + /* + * Increment partition number + */ + PartitionNum++; + } + + return ExecAddress; +} + +/*****************************************************************************/ +/** +* +* This function loads all partition header information in global array +* +* @param ImageAddress is the start address of the image +* +* @return - XST_SUCCESS if Get partition Header information successful +* - XST_FAILURE if Get Partition Header information failed +* +* @note None +* +****************************************************************************/ +u32 GetPartitionHeaderInfo(u32 ImageBaseAddress) +{ + u32 PartitionHeaderOffset; + u32 Status; + + + /* + * Get the length of the FSBL from BootHeader + */ + Status = GetFsblLength(ImageBaseAddress, &FsblLength); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL, "Get Header Start Address Failed\r\n"); + return XST_FAILURE; + } + + /* + * Get the start address of the partition header table + */ + Status = GetPartitionHeaderStartAddr(ImageBaseAddress, + &PartitionHeaderOffset); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL, "Get Header Start Address Failed\r\n"); + return XST_FAILURE; + } + + /* + * Header offset on flash + */ + PartitionHeaderOffset += ImageBaseAddress; + + fsbl_printf(DEBUG_INFO,"Partition Header Offset:0x%08lx\r\n", + PartitionHeaderOffset); + + /* + * Load all partitions header data in to global variable + */ + Status = LoadPartitionsHeaderInfo(PartitionHeaderOffset, + &PartitionHeader[0]); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL, "Header Information Load Failed\r\n"); + return XST_FAILURE; + } + + /* + * Get partitions count from partitions header information + */ + PartitionCount = GetPartitionCount(&PartitionHeader[0]); + + fsbl_printf(DEBUG_INFO, "Partition Count: %lu\r\n", PartitionCount); + + /* + * Partition Count check + */ + if (PartitionCount >= MAX_PARTITION_NUMBER) { + fsbl_printf(DEBUG_GENERAL, "Invalid Partition Count\r\n"); + return XST_FAILURE; +#ifndef MMC_SUPPORT + } else if (PartitionCount <= 1) { + fsbl_printf(DEBUG_GENERAL, "There is no partition to load\r\n"); + return XST_FAILURE; +#endif + } + + return XST_SUCCESS; +} + + +/*****************************************************************************/ +/** +* +* This function goes to the partition header of the specified partition +* +* @param ImageAddress is the start address of the image +* +* @return Offset Partition header address of the image +* +* @return - XST_SUCCESS if Get Partition Header start address successful +* - XST_FAILURE if Get Partition Header start address failed +* +* @note None +* +****************************************************************************/ +u32 GetPartitionHeaderStartAddr(u32 ImageAddress, u32 *Offset) +{ + u32 Status; + + Status = MoveImage(ImageAddress + IMAGE_PHDR_OFFSET, (u32)Offset, 4); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL,"Move Image failed\r\n"); + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function goes to the partition header of the specified partition +* +* @param ImageAddress is the start address of the image +* +* @return Offset to Image header table address of the image +* +* @return - XST_SUCCESS if Get Partition Header start address successful +* - XST_FAILURE if Get Partition Header start address failed +* +* @note None +* +****************************************************************************/ +u32 GetImageHeaderStartAddr(u32 ImageAddress, u32 *Offset) +{ + u32 Status; + + Status = MoveImage(ImageAddress + IMAGE_HDR_OFFSET, (u32)Offset, 4); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL,"Move Image failed\r\n"); + return XST_FAILURE; + } + + return XST_SUCCESS; +} +/*****************************************************************************/ +/** +* +* This function gets the length of the FSBL +* +* @param ImageAddress is the start address of the image +* +* @return FsblLength is the length of the fsbl +* +* @return - XST_SUCCESS if fsbl length reading is successful +* - XST_FAILURE if fsbl length reading failed +* +* @note None +* +****************************************************************************/ +u32 GetFsblLength(u32 ImageAddress, u32 *FsblLength) +{ + u32 Status; + + Status = MoveImage(ImageAddress + IMAGE_TOT_BYTE_LEN_OFFSET, + (u32)FsblLength, 4); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL,"Move Image failed reading FsblLength\r\n"); + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +#ifdef RSA_SUPPORT +/*****************************************************************************/ +/** +* +* This function goes to read the image headers and its signature. Image +* header consists of image header table, image headers, partition +* headers +* +* @param ImageBaseAddress is the start address of the image header +* +* @return Offset Partition header address of the image +* +* @return - XST_SUCCESS if Get Partition Header start address successful +* - XST_FAILURE if Get Partition Header start address failed +* +* @note None +* +****************************************************************************/ +u32 GetImageHeaderAndSignature(u32 ImageBaseAddress, u32 *Offset) +{ + u32 Status; + u32 ImageHeaderOffset; + + /* + * Get the start address of the partition header table + */ + Status = GetImageHeaderStartAddr(ImageBaseAddress, &ImageHeaderOffset); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL, "Get Header Start Address Failed\r\n"); + return XST_FAILURE; + } + + Status = MoveImage(ImageBaseAddress+ImageHeaderOffset, (u32)Offset, + TOTAL_HEADER_SIZE + RSA_SIGNATURE_SIZE); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL,"Move Image failed\r\n"); + return XST_FAILURE; + } + + return XST_SUCCESS; +} +#endif +/*****************************************************************************/ +/** +* +* This function get the header information of the all the partitions and load into +* global array +* +* @param PartHeaderOffset Offset address where the header information present +* +* @param Header Partition header pointer +* +* @return - XST_SUCCESS if Load Partitions Header information successful +* - XST_FAILURE if Load Partitions Header information failed +* +* @note None +* +****************************************************************************/ +u32 LoadPartitionsHeaderInfo(u32 PartHeaderOffset, PartHeader *Header) +{ + u32 Status; + + Status = MoveImage(PartHeaderOffset, (u32)Header, sizeof(PartHeader)*MAX_PARTITION_NUMBER); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL,"Move Image failed\r\n"); + return XST_FAILURE; + } + + return XST_SUCCESS; +} + + +/*****************************************************************************/ +/** +* +* This function dumps the partition header. +* +* @param Header Partition header pointer +* +* @return None +* +* @note None +* +******************************************************************************/ +void HeaderDump(PartHeader *Header) +{ + fsbl_printf(DEBUG_INFO, "Header Dump\r\n"); + fsbl_printf(DEBUG_INFO, "Image Word Len: 0x%08lx\r\n", + Header->ImageWordLen); + fsbl_printf(DEBUG_INFO, "Data Word Len: 0x%08lx\r\n", + Header->DataWordLen); + fsbl_printf(DEBUG_INFO, "Partition Word Len:0x%08lx\r\n", + Header->PartitionWordLen); + fsbl_printf(DEBUG_INFO, "Load Addr: 0x%08lx\r\n", + Header->LoadAddr); + fsbl_printf(DEBUG_INFO, "Exec Addr: 0x%08lx\r\n", + Header->ExecAddr); + fsbl_printf(DEBUG_INFO, "Partition Start: 0x%08lx\r\n", + Header->PartitionStart); + fsbl_printf(DEBUG_INFO, "Partition Attr: 0x%08lx\r\n", + Header->PartitionAttr); + fsbl_printf(DEBUG_INFO, "Partition Checksum Offset: 0x%08lx\r\n", + Header->CheckSumOffset); + fsbl_printf(DEBUG_INFO, "Section Count: 0x%08lx\r\n", + Header->SectionCount); + fsbl_printf(DEBUG_INFO, "Checksum: 0x%08lx\r\n", + Header->CheckSum); +} + + +/******************************************************************************/ +/** +* +* This function calculates the partitions count from header information +* +* @param Header Partition header pointer +* +* @return Count Partition count +* +* @note None +* +*******************************************************************************/ +u32 GetPartitionCount(PartHeader *Header) +{ + u32 Count=0; + struct HeaderArray *Hap; + + for(Count = 0; Count < MAX_PARTITION_NUMBER; Count++) { + Hap = (struct HeaderArray *)&Header[Count]; + if(IsLastPartition(Hap)!=XST_FAILURE) + break; + } + + return Count; +} + +/******************************************************************************/ +/** +* This function check whether the current partition is the end of partitions +* +* The partition is the end of the partitions if it looks like this: +* 0x00000000 +* 0x00000000 +* .... +* 0x00000000 +* 0x00000000 +* 0xFFFFFFFF +* +* @param H is a pointer to struct HeaderArray +* +* @return +* - XST_SUCCESS if it is the last partition +* - XST_FAILURE if it is not last partition +* +****************************************************************************/ +u32 IsLastPartition(struct HeaderArray *H) +{ + int Index; + + if (H->Fields[PARTITION_HDR_CHECKSUM_WORD_COUNT] != 0xFFFFFFFF) { + return XST_FAILURE; + } + + for (Index = 0; Index < PARTITION_HDR_WORD_COUNT - 1; Index++) { + + if (H->Fields[Index] != 0x0) { + return XST_FAILURE; + } + } + + return XST_SUCCESS; +} + + +/******************************************************************************/ +/** +* +* This function validates the partition header. +* +* @param Header Partition header pointer +* +* @return +* - XST_FAILURE if bad header. +* - XST_SUCCESS if successful. +* +* @note None +* +*******************************************************************************/ +u32 ValidateHeader(PartHeader *Header) +{ + struct HeaderArray *Hap; + + Hap = (struct HeaderArray *)Header; + + /* + * If there are no partitions to load, fail + */ + if (IsEmptyHeader(Hap) == XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL, "IMAGE_HAS_NO_PARTITIONS\r\n"); + return XST_FAILURE; + } + + /* + * Validate partition header checksum + */ + if (ValidatePartitionHeaderChecksum(Hap) != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL, "PARTITION_HEADER_CORRUPTION\r\n"); + return XST_FAILURE; + } + + /* + * Validate partition data size + */ + if (Header->ImageWordLen > MAXIMUM_IMAGE_WORD_LEN) { + fsbl_printf(DEBUG_GENERAL, "INVALID_PARTITION_LENGTH\r\n"); + return XST_FAILURE; + } + + return XST_SUCCESS; +} + + +/******************************************************************************/ +/** +* This function check whether the current partition header is empty. +* A partition header is considered empty if image word length is 0 and the +* last word is 0. +* +* @param H is a pointer to struct HeaderArray +* +* @return +* - XST_SUCCESS , If the partition header is empty +* - XST_FAILURE , If the partition header is NOT empty +* +* @note Caller is responsible to make sure the address is valid. +* +* +****************************************************************************/ +u32 IsEmptyHeader(struct HeaderArray *H) +{ + int Index; + + for (Index = 0; Index < PARTITION_HDR_WORD_COUNT; Index++) { + if (H->Fields[Index] != 0x0) { + return XST_FAILURE; + } + } + + return XST_SUCCESS; +} + + +/******************************************************************************/ +/** +* +* This function checks the header checksum If the header checksum is not valid +* XST_FAILURE is returned. +* +* @param H is a pointer to struct HeaderArray +* +* @return +* - XST_SUCCESS is header checksum is ok +* - XST_FAILURE if the header checksum is not correct +* +* @note None. +* +****************************************************************************/ +u32 ValidatePartitionHeaderChecksum(struct HeaderArray *H) +{ + u32 Checksum; + u32 Count; + + Checksum = 0; + + for (Count = 0; Count < PARTITION_HDR_CHECKSUM_WORD_COUNT; Count++) { + /* + * Read the word from the header + */ + Checksum += H->Fields[Count]; + } + + /* + * Invert checksum, last bit of error checking + */ + Checksum ^= 0xFFFFFFFF; + + /* + * Validate the checksum + */ + if (H->Fields[PARTITION_HDR_CHECKSUM_WORD_COUNT] != Checksum) { + fsbl_printf(DEBUG_GENERAL, "Error: Checksum 0x%8.8lx != 0x%8.8lx\r\n", + Checksum, H->Fields[PARTITION_HDR_CHECKSUM_WORD_COUNT]); + return XST_FAILURE; + } + + return XST_SUCCESS; +} + + +/******************************************************************************/ +/** +* +* This function load the partition from boot device +* +* @param ImageBaseAddress Base address on flash +* @param Header Partition header pointer +* +* @return +* - XST_SUCCESS if partition move successful +* - XST_FAILURE if check failed move failed +* +* @note None +* +*******************************************************************************/ +u32 PartitionMove(u32 ImageBaseAddress, PartHeader *Header) +{ + u32 SourceAddr; + u32 Status; + u8 SecureTransferFlag = 0; + u32 LoadAddr; + u32 ImageWordLen; + u32 DataWordLen; + + SourceAddr = ImageBaseAddress; + SourceAddr += Header->PartitionStart<LoadAddr; + ImageWordLen = Header->ImageWordLen; + DataWordLen = Header->DataWordLen; + + /* + * Add flash base address for linear boot devices + */ + if (LinearBootDeviceFlag) { + SourceAddr += FlashReadBaseAddress; + } + + /* + * Partition encrypted + */ + if(EncryptedPartitionFlag) { + SecureTransferFlag = 1; + } + + /* + * For Signed or checksum enabled partition, + * Total partition image need to copied to DDR + */ + if (SignedPartitionFlag || PartitionChecksumFlag) { + ImageWordLen = Header->PartitionWordLen; + DataWordLen = Header->PartitionWordLen; + } + + /* + * Encrypted and Signed PS partition need to be loaded on to DDR + * without decryption + */ + if (PSPartitionFlag && + (SignedPartitionFlag || PartitionChecksumFlag) && + EncryptedPartitionFlag) { + SecureTransferFlag = 0; + } + + /* + * CPU is used for data transfer in case of non-linear + * boot device + */ + if (!LinearBootDeviceFlag) { + /* + * PL partition copied to DDR temporary location + */ + if (PLPartitionFlag) { + LoadAddr = DDR_TEMP_START_ADDR; + } + + Status = MoveImage(SourceAddr, + LoadAddr, + (ImageWordLen << WORD_LENGTH_SHIFT)); + if(Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL, "Move Image Failed\r\n"); + return XST_FAILURE; + } + + /* + * As image present at load address + */ + SourceAddr = LoadAddr; + } + + if ((LinearBootDeviceFlag && PLPartitionFlag && + (SignedPartitionFlag || PartitionChecksumFlag)) || + (LinearBootDeviceFlag && PSPartitionFlag) || + ((!LinearBootDeviceFlag) && PSPartitionFlag && SecureTransferFlag)) { + /* + * PL signed partition copied to DDR temporary location + * using non-secure PCAP for linear boot device + */ + if(PLPartitionFlag){ + SecureTransferFlag = 0; + LoadAddr = DDR_TEMP_START_ADDR; + } + + /* + * Data transfer using PCAP + */ + Status = PcapDataTransfer((u32*)SourceAddr, + (u32*)LoadAddr, + ImageWordLen, + DataWordLen, + SecureTransferFlag); + if(Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL, "PCAP Data Transfer Failed\r\n"); + return XST_FAILURE; + } + + /* + * As image present at load address + */ + SourceAddr = LoadAddr; + } + + /* + * Load Bitstream partition in to fabric only + * if checksum and authentication bits are not set + */ + if (PLPartitionFlag && (!(SignedPartitionFlag || PartitionChecksumFlag))) { + Status = PcapLoadPartition((u32*)SourceAddr, + (u32*)Header->LoadAddr, + Header->ImageWordLen, + Header->DataWordLen, + EncryptedPartitionFlag); + if(Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL, "PCAP Bitstream Download Failed\r\n"); + return XST_FAILURE; + } + } + + return XST_SUCCESS; +} + + +/******************************************************************************/ +/** +* +* This function load the decrypts partition +* +* @param StartAddr Source start address +* @param DataLength Data length in words +* @param ImageLength Image length in words +* +* @return +* - XST_SUCCESS if decryption successful +* - XST_FAILURE if decryption failed +* +* @note None +* +*******************************************************************************/ +u32 DecryptPartition(u32 StartAddr, u32 DataLength, u32 ImageLength) +{ + u32 Status; + u8 SecureTransferFlag =1; + + /* + * Data transfer using PCAP + */ + Status = PcapDataTransfer((u32*)StartAddr, + (u32*)StartAddr, + ImageLength, + DataLength, + SecureTransferFlag); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL,"PCAP Data Transfer failed \r\n"); + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/******************************************************************************/ +/** +* +* This function Validate Partition Data by using checksum preset in image +* +* @param Partition header pointer +* @param Partition check sum offset +* @return +* - XST_SUCCESS if partition data is ok +* - XST_FAILURE if partition data is corrupted +* +* @note None +* +*******************************************************************************/ +u32 ValidateParition(u32 StartAddr, u32 Length, u32 ChecksumOffset) +{ + u8 Checksum[MD5_CHECKSUM_SIZE]; + u8 CalcChecksum[MD5_CHECKSUM_SIZE]; + u32 Status; + u32 Index; + +#ifdef XPAR_XWDTPS_0_BASEADDR + /* + * Prevent WDT reset + */ + XWdtPs_RestartWdt(&Watchdog); +#endif + + /* + * Get checksum from flash + */ + Status = GetPartitionChecksum(ChecksumOffset, &Checksum[0]); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + fsbl_printf(DEBUG_INFO, "Actual checksum\r\n"); + + for (Index = 0; Index < MD5_CHECKSUM_SIZE; Index++) { + fsbl_printf(DEBUG_INFO, "0x%0x ",Checksum[Index]); + } + + fsbl_printf(DEBUG_INFO, "\r\n"); + + /* + * Calculate checksum for the partition + */ + Status = CalcPartitionChecksum(StartAddr, Length, &CalcChecksum[0]); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + fsbl_printf(DEBUG_INFO, "Calculated checksum\r\n"); + + for (Index = 0; Index < MD5_CHECKSUM_SIZE; Index++) { + fsbl_printf(DEBUG_INFO, "0x%0x ",CalcChecksum[Index]); + } + + fsbl_printf(DEBUG_INFO, "\r\n"); + + /* + * Compare actual checksum with the calculated checksum + */ + for (Index = 0; Index < MD5_CHECKSUM_SIZE; Index++) { + if(Checksum[Index] != CalcChecksum[Index]) { + fsbl_printf(DEBUG_GENERAL, "Error: " + "Partition DataChecksum 0x%0x!= 0x%0x\r\n", + Checksum[Index], CalcChecksum[Index]); + return XST_FAILURE; + } + } + + return XST_SUCCESS; +} + + +/******************************************************************************/ +/** +* +* This function gets partition checksum from flash +* +* @param Check sum offset +* @param Checksum pointer +* @return +* - XST_SUCCESS if checksum read success +* - XST_FAILURE if unable get checksum +* +* @note None +* +*******************************************************************************/ +u32 GetPartitionChecksum(u32 ChecksumOffset, u8 *Checksum) +{ + u32 Status; + + Status = MoveImage(ChecksumOffset, (u32)Checksum, MD5_CHECKSUM_SIZE); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + + +/******************************************************************************/ +/** +* +* This function calculates the checksum preset in image +* +* @param Start address +* @param Length of the data +* @param Checksum pointer +* +* @return +* - XST_SUCCESS if Checksum calculate successful +* - XST_FAILURE if Checksum calculate failed +* +* @note None +* +*******************************************************************************/ +u32 CalcPartitionChecksum(u32 SourceAddr, u32 DataLength, u8 *Checksum) +{ + /* + * Calculate checksum using MD5 algorithm + */ + md5((u8*)SourceAddr, DataLength, Checksum, 0 ); + + return XST_SUCCESS; +} + diff --git a/sdk/fsbl/src/image_mover.h b/sdk/fsbl/src/image_mover.h new file mode 100644 index 0000000..dad66f1 --- /dev/null +++ b/sdk/fsbl/src/image_mover.h @@ -0,0 +1,161 @@ +/****************************************************************************** +* +* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file image_mover.h +* +* This file contains the interface for moving the image from FLASH to OCM + +* +*
+* MODIFICATION HISTORY:
+*
+* Ver	Who	Date		Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a jz	03/04/11	Initial release
+* 2.00a jz	06/04/11	partition header expands to 12 words
+* 5.00a kc	07/30/13	Added defines for image header information
+* 8.00a kc	01/16/13	Added defines for partition owner attribute
+* 
+* +* @note +* +******************************************************************************/ +#ifndef ___IMAGE_MOVER_H___ +#define ___IMAGE_MOVER_H___ + + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ +#include "fsbl.h" + +/************************** Constant Definitions *****************************/ +#define PARTITION_NUMBER_SHIFT 24 +#define MAX_PARTITION_NUMBER (0xE) + +/* Boot Image Header defines */ +#define IMAGE_HDR_OFFSET 0x098 /* Start of image header table */ +#define IMAGE_PHDR_OFFSET 0x09C /* Start of partition headers */ +#define IMAGE_HEADER_SIZE (64) +#define IMAGE_HEADER_TABLE_SIZE (64) +#define TOTAL_PARTITION_HEADER_SIZE (MAX_PARTITION_NUMBER * IMAGE_HEADER_SIZE) +#define TOTAL_IMAGE_HEADER_SIZE (MAX_PARTITION_NUMBER * IMAGE_HEADER_SIZE) +#define TOTAL_HEADER_SIZE (IMAGE_HEADER_TABLE_SIZE + \ + TOTAL_IMAGE_HEADER_SIZE + \ + TOTAL_PARTITION_HEADER_SIZE + 64) + +/* Partition Header defines */ +#define PARTITION_IMAGE_WORD_LEN_OFFSET 0x00 /* Word length of image */ +#define PARTITION_DATA_WORD_LEN_OFFSET 0x04 /* Word length of data */ +#define PARTITION_WORD_LEN_OFFSET 0x08 /* Word length of partition */ +#define PARTITION_LOAD_ADDRESS_OFFSET 0x0C /* Load addr in DDR */ +#define PARTITION_EXEC_ADDRESS_OFFSET 0x10 /* Addr to start executing */ +#define PARTITION_ADDR_OFFSET 0x14 /* Partition word offset */ +#define PARTITION_ATTRIBUTE_OFFSET 0x18 /* Partition type */ +#define PARTITION_HDR_CHECKSUM_OFFSET 0x3C /* Header Checksum offset */ +#define PARTITION_HDR_CHECKSUM_WORD_COUNT 0xF /* Checksum word count */ +#define PARTITION_HDR_WORD_COUNT 0x10 /* Header word len */ +#define PARTITION_HDR_TOTAL_LEN 0x40 /* One partition hdr length*/ + +/* Attribute word defines */ +#define ATTRIBUTE_IMAGE_TYPE_MASK 0xF0 /* Destination Device type */ +#define ATTRIBUTE_PS_IMAGE_MASK 0x10 /* Code partition */ +#define ATTRIBUTE_PL_IMAGE_MASK 0x20 /* Bit stream partition */ +#define ATTRIBUTE_CHECKSUM_TYPE_MASK 0x7000 /* Checksum Type */ +#define ATTRIBUTE_RSA_PRESENT_MASK 0x8000 /* RSA Signature Present */ +#define ATTRIBUTE_PARTITION_OWNER_MASK 0x30000 /* Partition Owner */ + +#define ATTRIBUTE_PARTITION_OWNER_FSBL 0x00000 /* FSBL Partition Owner */ + + +/**************************** Type Definitions *******************************/ +typedef u32 (*ImageMoverType)( u32 SourceAddress, + u32 DestinationAddress, + u32 LengthBytes); + +typedef struct StructPartHeader { + u32 ImageWordLen; /* 0x0 */ + u32 DataWordLen; /* 0x4 */ + u32 PartitionWordLen; /* 0x8 */ + u32 LoadAddr; /* 0xC */ + u32 ExecAddr; /* 0x10 */ + u32 PartitionStart; /* 0x14 */ + u32 PartitionAttr; /* 0x18 */ + u32 SectionCount; /* 0x1C */ + u32 CheckSumOffset; /* 0x20 */ + u32 Pads1[1]; + u32 ACOffset; /* 0x28 */ + u32 Pads2[4]; + u32 CheckSum; /* 0x3C */ +}PartHeader; + +struct HeaderArray { + u32 Fields[16]; +}; + + +/***************** Macros (Inline Functions) Definitions *********************/ +#define MoverIn32 Xil_In32 +#define MoverOut32 Xil_Out32 + +/************************** Function Prototypes ******************************/ +u32 LoadBootImage(void); +u32 GetPartitionHeaderInfo(u32 ImageBaseAddress); +u32 PartitionMove(u32 ImageBaseAddress, PartHeader *Header); +u32 ValidatePartitionHeaderChecksum(struct HeaderArray *H); +u32 GetPartitionHeaderStartAddr(u32 ImageAddress, u32 *Offset); +u32 GetImageHeaderAndSignature(u32 ImageAddress, u32 *Offset); +u32 GetFsblLength(u32 ImageAddress, u32 *FsblLength); +u32 LoadPartitionsHeaderInfo(u32 PartHeaderOffset, PartHeader *Header); +u32 IsEmptyHeader(struct HeaderArray *H); +u32 IsLastPartition(struct HeaderArray *H); +void HeaderDump(PartHeader *Header); +u32 GetPartitionCount(PartHeader *Header); +u32 ValidateHeader(PartHeader *Header); +u32 DecryptPartition(u32 StartAddr, u32 DataLength, u32 ImageLength); + +/************************** Variable Definitions *****************************/ + +#ifdef __cplusplus +} +#endif + + +#endif /* ___IMAGE_MOVER_H___ */ + + + + diff --git a/sdk/fsbl/src/lscript.ld b/sdk/fsbl/src/lscript.ld new file mode 100644 index 0000000..fd76568 --- /dev/null +++ b/sdk/fsbl/src/lscript.ld @@ -0,0 +1,313 @@ +/****************************************************************************** +* +* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ + +_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x6000; +_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x2000; + +_RSA_AC_SIZE = DEFINED(_RSA_AC_SIZE) ? _RSA_AC_SIZE : 0x1000; + +_ABORT_STACK_SIZE = DEFINED(_ABORT_STACK_SIZE) ? _ABORT_STACK_SIZE : 1024; +_SUPERVISOR_STACK_SIZE = DEFINED(_SUPERVISOR_STACK_SIZE) ? _SUPERVISOR_STACK_SIZE : 2048; +_FIQ_STACK_SIZE = DEFINED(_FIQ_STACK_SIZE) ? _FIQ_STACK_SIZE : 1024; +_UNDEF_STACK_SIZE = DEFINED(_UNDEF_STACK_SIZE) ? _UNDEF_STACK_SIZE : 1024; + +/* Define Memories in the system */ + +MEMORY +{ + ps7_ram_0_S_AXI_BASEADDR : ORIGIN = 0x00000000, LENGTH = 0x00030000 + ps7_ram_1_S_AXI_BASEADDR : ORIGIN = 0xFFFF0000, LENGTH = 0x0000FE00 +} + +/* Specify the default entry point to the program */ + +ENTRY(_vector_table) + + +SECTIONS +{ +.text : { + *(.vectors) + *(.boot) + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + *(.plt) + *(.gnu_warning) + *(.gcc_execpt_table) + *(.glue_7) + *(.glue_7t) + *(.vfp11_veneer) + *(.ARM.extab) + *(.gnu.linkonce.armextab.*) +} > ps7_ram_0_S_AXI_BASEADDR + +.init : { + KEEP (*(.init)) +} > ps7_ram_0_S_AXI_BASEADDR + +.fini : { + KEEP (*(.fini)) +} > ps7_ram_0_S_AXI_BASEADDR + +.rodata : { + __rodata_start = .; + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + __rodata_end = .; +} > ps7_ram_0_S_AXI_BASEADDR + +.rodata1 : { + __rodata1_start = .; + *(.rodata1) + *(.rodata1.*) + __rodata1_end = .; +} > ps7_ram_0_S_AXI_BASEADDR + +.sdata2 : { + __sdata2_start = .; + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + __sdata2_end = .; +} > ps7_ram_0_S_AXI_BASEADDR + +.sbss2 : { + __sbss2_start = .; + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + __sbss2_end = .; +} > ps7_ram_0_S_AXI_BASEADDR + +.data : { + __data_start = .; + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.jcr) + *(.got) + *(.got.plt) + __data_end = .; +} > ps7_ram_0_S_AXI_BASEADDR + +.data1 : { + __data1_start = .; + *(.data1) + *(.data1.*) + __data1_end = .; +} > ps7_ram_0_S_AXI_BASEADDR + +.got : { + *(.got) +} > ps7_ram_0_S_AXI_BASEADDR + +.ctors : { + __CTOR_LIST__ = .; + ___CTORS_LIST___ = .; + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE(*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + __CTOR_END__ = .; + ___CTORS_END___ = .; +} > ps7_ram_0_S_AXI_BASEADDR + +.dtors : { + __DTOR_LIST__ = .; + ___DTORS_LIST___ = .; + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE(*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + __DTOR_END__ = .; + ___DTORS_END___ = .; +} > ps7_ram_0_S_AXI_BASEADDR + +.fixup : { + __fixup_start = .; + *(.fixup) + __fixup_end = .; +} > ps7_ram_0_S_AXI_BASEADDR + +.eh_frame : { + *(.eh_frame) +} > ps7_ram_0_S_AXI_BASEADDR + +.eh_framehdr : { + __eh_framehdr_start = .; + *(.eh_framehdr) + __eh_framehdr_end = .; +} > ps7_ram_0_S_AXI_BASEADDR + +.gcc_except_table : { + *(.gcc_except_table) +} > ps7_ram_0_S_AXI_BASEADDR + +.mmu_tbl (ALIGN(0x4000)): { + __mmu_tbl_start = .; + *(.mmu_tbl) + __mmu_tbl_end = .; +} > ps7_ram_0_S_AXI_BASEADDR + +.ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + *(.gnu.linkonce.armexidix.*.*) + __exidx_end = .; +} > ps7_ram_0_S_AXI_BASEADDR + +.preinit_array : { + __preinit_array_start = .; + KEEP (*(SORT(.preinit_array.*))) + KEEP (*(.preinit_array)) + __preinit_array_end = .; +} > ps7_ram_0_S_AXI_BASEADDR + +.init_array : { + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; +} > ps7_ram_0_S_AXI_BASEADDR + +.fini_array : { + __fini_array_start = .; + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array)) + __fini_array_end = .; +} > ps7_ram_0_S_AXI_BASEADDR + +.rsa_ac : { + . = ALIGN(64); + __rsa_ac_start = .; + . += _RSA_AC_SIZE; + __rsa_ac_end = .; +} > ps7_ram_0_S_AXI_BASEADDR + +.ARM.attributes : { + __ARM.attributes_start = .; + *(.ARM.attributes) + __ARM.attributes_end = .; +} > ps7_ram_0_S_AXI_BASEADDR + +.sdata : { + __sdata_start = .; + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + __sdata_end = .; +} > ps7_ram_0_S_AXI_BASEADDR + +.sbss (NOLOAD) : { + __sbss_start = .; + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + __sbss_end = .; +} > ps7_ram_0_S_AXI_BASEADDR + +.tdata : { + __tdata_start = .; + *(.tdata) + *(.tdata.*) + *(.gnu.linkonce.td.*) + __tdata_end = .; +} > ps7_ram_0_S_AXI_BASEADDR + +.tbss : { + __tbss_start = .; + *(.tbss) + *(.tbss.*) + *(.gnu.linkonce.tb.*) + __tbss_end = .; +} > ps7_ram_0_S_AXI_BASEADDR + +.bss (NOLOAD) : { + __bss_start = .; + __bss_start__ = .; + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + __bss_end = .; + __bss_end__ = .; +} > ps7_ram_0_S_AXI_BASEADDR + +_SDA_BASE_ = __sdata_start + ((__sbss_end - __sdata_start) / 2 ); + +_SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 ); + +/* Generate Stack and Heap definitions */ + +.heap (NOLOAD) : { + . = ALIGN(16); + _heap = .; + HeapBase = .; + _heap_start = .; + . += _HEAP_SIZE; + _heap_end = .; + HeapLimit = .; +} > ps7_ram_0_S_AXI_BASEADDR + +.stack (NOLOAD) : { + . = ALIGN(16); + _stack_end = .; + . += _STACK_SIZE; + _stack = .; + __stack = _stack; + . = ALIGN(16); + _irq_stack_end = .; + . += _STACK_SIZE; + __irq_stack = .; + _supervisor_stack_end = .; + . += _SUPERVISOR_STACK_SIZE; + . = ALIGN(16); + __supervisor_stack = .; + _abort_stack_end = .; + . += _ABORT_STACK_SIZE; + . = ALIGN(16); + __abort_stack = .; + _fiq_stack_end = .; + . += _FIQ_STACK_SIZE; + . = ALIGN(16); + __fiq_stack = .; + _undef_stack_end = .; + . += _UNDEF_STACK_SIZE; + . = ALIGN(16); + __undef_stack = .; +} > ps7_ram_1_S_AXI_BASEADDR + +_end = .; +} + diff --git a/sdk/fsbl/src/main.c b/sdk/fsbl/src/main.c new file mode 100644 index 0000000..958e3c0 --- /dev/null +++ b/sdk/fsbl/src/main.c @@ -0,0 +1,1532 @@ +/****************************************************************************** +* +* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file main.c +* +* The main file for the First Stage Boot Loader (FSBL). +* +*
+* MODIFICATION HISTORY:
+*
+* Ver	Who	Date		Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a jz	06/04/11	Initial release
+* 2.00a mb	25/05/12	standalone based FSBL
+* 3.00a np/mb	08/03/12	Added call to FSBL user hook - before handoff.
+*				DDR ECC initialization added
+* 				fsbl print with verbose added
+* 				Performance measurement added
+* 				Flushed the UART Tx buffer
+* 				Added the performance time for ECC DDR init
+* 				Added clearing of ECC Error Code
+* 				Added the watchdog timer value
+* 4.00a sgd 02/28/13	Code Cleanup
+* 						Fix for CR#681014 - ECC init in FSBL should not
+* 						                    call fabric_init()
+* 						Fix for CR#689077 - FSBL hangs at Handoff clearing the
+* 						                    TX UART buffer when using UART0
+* 						                    instead of UART1
+*						Fix for CR#694038 - FSBL debug logs always prints 14.3
+*											as the Revision number - this is
+*										    incorrect
+*						Fix for CR#694039 - FSBL prints "unsupported silicon
+*											version for v3.0" 3.0 Silicon
+*                       Fix for CR#699475 - FSBL functionality is broken and
+*                                           its not able to boot in QSPI/NAND
+*                                           bootmode
+*                       Removed DDR initialization check
+*                       Removed DDR ECC initialization code
+*						Modified hand off address check to 1MB
+*						Added RSA authentication support
+*						Watchdog disabled for AES E-Fuse encryption
+* 5.00a sgd 05/17/13	Fallback support for E-Fuse encryption
+*                       Fix for CR#708728 - Issues seen while making HP
+*                                           interconnect 32 bit wide
+* 6.00a kc  07/30/13    Fix for CR#708316 - PS7_init.tcl file should have
+*                                           Error mechanism for all mask_poll
+*                       Fix for CR#691150 - ps7_init does not check for
+*                                           peripheral initialization failures
+*                                           or timeout on polls
+*                       Fix for CR#724165 - Partition Header used by FSBL is
+*                                           not authenticated
+*                       Fix for CR#724166 - FSBL doesn’t use PPK authenticated
+*                                           by Boot ROM for authenticating
+*                                           the Partition images
+*                       Fix for CR#722979 - Provide customer-friendly
+*                                           changelogs in FSBL
+*                       Fix for CR#732865 - Backward compatibility for ps7_init
+*                       					function
+* 7.00a kc  10/18/13    Integrated SD/MMC driver
+* 8.00a kc  02/20/14	Fix for CR#775631 - FSBL: FsblGetGlobalTimer() 
+*											is not proper
+* 9.00a kc  04/16/14	Fix for CR#724166 - SetPpk() will fail on secure
+*		 									fallback unless FSBL* and FSBL
+*		 									are identical in length
+* 10.00a kc 07/24/14	Fix for CR#809336 - Minor code cleanup
+*        kc 08/27/14	Fix for CR#820356 - FSBL compilation fails with
+* 											IAR compiler
+* 11.00a kv 10/08/14	Fix for CR#826030 - LinearBootDeviceFlag should
+*											be initialized to 0 in IO mode
+*											case
+* 15.00a gan 07/21/16   Fix for CR# 953654 -(2016.3)FSBL -
+* 											In pcap.c/pcap.h/main.c,
+* 											Fabric Initialization sequence
+* 											is modified to check the PL power
+* 											before sequence starts and checking
+* 											INIT_B reset status twice in case
+* 											of failure.
+* 
+* +* @note +* FSBL runs from OCM, Based on the boot mode selected, FSBL will copy +* the partitions from the flash device. If the partition is bitstream then +* the bitstream is programmed in the Fabric and for an partition that is +* an application , FSBL will copy the application into DDR and does a +* handoff.The application should not be starting at the OCM address, +* FSBL does not remap the DDR. Application should use DDR starting from 1MB +* +* FSBL can be stitched along with bitstream and application using bootgen +* +* Refer to fsbl.h file for details on the compilation flags supported in FSBL +* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "fsbl.h" +#include "qspi.h" +#include "nand.h" +#include "nor.h" +#include "sd.h" +#include "pcap.h" +#include "image_mover.h" +#include "xparameters.h" +#include "xil_cache.h" +#include "xil_exception.h" +#include "xstatus.h" +#include "fsbl_hooks.h" +#include "xtime_l.h" + +#ifdef XPAR_XWDTPS_0_BASEADDR +#include "xwdtps.h" +#endif + +#ifdef STDOUT_BASEADDRESS +#ifdef XPAR_XUARTPS_0_BASEADDR +#include "xuartps_hw.h" +#endif +#endif + +#ifdef RSA_SUPPORT +#include "rsa.h" +#endif + +/************************** Constant Definitions *****************************/ + +#ifdef XPAR_XWDTPS_0_BASEADDR +#define WDT_DEVICE_ID XPAR_XWDTPS_0_DEVICE_ID +#define WDT_EXPIRE_TIME 100 +#define WDT_CRV_SHIFT 12 +#endif + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +#ifdef XPAR_XWDTPS_0_BASEADDR +XWdtPs Watchdog; /* Instance of WatchDog Timer */ +#endif +/************************** Function Prototypes ******************************/ +extern int ps7_init(); +extern char* getPS7MessageInfo(unsigned key); +#ifdef PS7_POST_CONFIG +extern int ps7_post_config(); +#endif + +static void Update_MultiBootRegister(void); +/* Exception handlers */ +static void RegisterHandlers(void); +static void Undef_Handler (void); +static void SVC_Handler (void); +static void PreFetch_Abort_Handler (void); +static void Data_Abort_Handler (void); +static void IRQ_Handler (void); +static void FIQ_Handler (void); + + +#ifdef XPAR_XWDTPS_0_BASEADDR +int InitWatchDog(void); +u32 ConvertTime_WdtCounter(u32 seconds); +void CheckWDTReset(void); +#endif + +u32 NextValidImageCheck(void); + +u32 DDRInitCheck(void); + +/************************** Variable Definitions *****************************/ +/* + * Base Address for the Read Functionality for Image Processing + */ +u32 FlashReadBaseAddress = 0; +/* + * Silicon Version + */ +u32 Silicon_Version; + +/* + * Boot Device flag + */ +u8 LinearBootDeviceFlag=0; + +u32 PcapCtrlRegVal; + +u8 SystemInitFlag; + +extern ImageMoverType MoveImage; +extern XDcfg *DcfgInstPtr; +extern u8 BitstreamFlag; +#ifdef XPAR_PS7_QSPI_LINEAR_0_S_AXI_BASEADDR +extern u32 QspiFlashSize; +#endif +/*****************************************************************************/ +/** +* +* This is the main function for the FSBL ROM code. +* +* +* @param None. +* +* @return +* - XST_SUCCESS to indicate success +* - XST_FAILURE.to indicate failure +* +* @note +* +****************************************************************************/ +int main(void) +{ + u32 BootModeRegister = 0; + u32 HandoffAddress = 0; + u32 Status = XST_SUCCESS; + + /* + * PCW initialization for MIO,PLL,CLK and DDR + */ + Status = ps7_init(); + if (Status != FSBL_PS7_INIT_SUCCESS) { + fsbl_printf(DEBUG_GENERAL,"PS7_INIT_FAIL : %s\r\n", + getPS7MessageInfo(Status)); + OutputStatus(PS7_INIT_FAIL); + /* + * Calling FsblHookFallback instead of Fallback + * since, devcfg driver is not yet initialized + */ + FsblHookFallback(); + } + + /* + * Unlock SLCR for SLCR register write + */ + SlcrUnlock(); + + /* If Performance measurement is required + * then read the Global Timer value , Please note that the + * time taken for mio, clock and ddr initialisation + * done in the ps7_init function is not accounted in the FSBL + * + */ +#ifdef FSBL_PERF + XTime tCur = 0; + FsblGetGlobalTime(&tCur); +#endif + + /* + * Flush the Caches + */ + Xil_DCacheFlush(); + + /* + * Disable Data Cache + */ + Xil_DCacheDisable(); + + /* + * Register the Exception handlers + */ + RegisterHandlers(); + + /* + * Print the FSBL Banner + */ + fsbl_printf(DEBUG_GENERAL,"\n\rXilinx First Stage Boot Loader \n\r"); + fsbl_printf(DEBUG_GENERAL,"Release %d.%d %s-%s\r\n", + SDK_RELEASE_YEAR, SDK_RELEASE_QUARTER, + __DATE__,__TIME__); + +#ifdef XPAR_PS7_DDR_0_S_AXI_BASEADDR + + /* + * DDR Read/write test + */ + Status = DDRInitCheck(); + if (Status == XST_FAILURE) { + fsbl_printf(DEBUG_GENERAL,"DDR_INIT_FAIL \r\n"); + /* Error Handling here */ + OutputStatus(DDR_INIT_FAIL); + /* + * Calling FsblHookFallback instead of Fallback + * since, devcfg driver is not yet initialized + */ + FsblHookFallback(); + } + + + /* + * PCAP initialization + */ + Status = InitPcap(); + if (Status == XST_FAILURE) { + fsbl_printf(DEBUG_GENERAL,"PCAP_INIT_FAIL \n\r"); + OutputStatus(PCAP_INIT_FAIL); + /* + * Calling FsblHookFallback instead of Fallback + * since, devcfg driver is not yet initialized + */ + FsblHookFallback(); + } + + fsbl_printf(DEBUG_INFO,"Devcfg driver initialized \r\n"); + + /* + * Get the Silicon Version + */ + GetSiliconVersion(); + +#ifdef XPAR_XWDTPS_0_BASEADDR + /* + * Check if WDT Reset has occurred or not + */ + CheckWDTReset(); + + /* + * Initialize the Watchdog Timer so that it is ready to use + */ + Status = InitWatchDog(); + if (Status == XST_FAILURE) { + fsbl_printf(DEBUG_GENERAL,"WATCHDOG_INIT_FAIL \n\r"); + OutputStatus(WDT_INIT_FAIL); + FsblFallback(); + } + fsbl_printf(DEBUG_INFO,"Watchdog driver initialized \r\n"); +#endif + + /* + * Get PCAP controller settings + */ + PcapCtrlRegVal = XDcfg_GetControlRegister(DcfgInstPtr); + + /* + * Check for AES source key + */ + if (PcapCtrlRegVal & XDCFG_CTRL_PCFG_AES_FUSE_MASK) { + /* + * For E-Fuse AES encryption Watch dog Timer disabled and + * User not allowed to do system reset + */ +#ifdef XPAR_XWDTPS_0_BASEADDR + fsbl_printf(DEBUG_INFO,"Watchdog Timer Disabled\r\n"); + XWdtPs_Stop(&Watchdog); +#endif + fsbl_printf(DEBUG_INFO,"User not allowed to do " + "any system resets\r\n"); + } + + /* + * Store FSBL run state in Reboot Status Register + */ + MarkFSBLIn(); + + /* + * Read bootmode register + */ + BootModeRegister = Xil_In32(BOOT_MODE_REG); + BootModeRegister &= BOOT_MODES_MASK; + + /* + * QSPI BOOT MODE + */ +#ifdef XPAR_PS7_QSPI_LINEAR_0_S_AXI_BASEADDR + +#ifdef MMC_SUPPORT + /* + * To support MMC boot + * QSPI boot mode detection ignored + */ + if (BootModeRegister == QSPI_MODE) { + BootModeRegister = MMC_MODE; + } +#endif + + if (BootModeRegister == QSPI_MODE) { + fsbl_printf(DEBUG_GENERAL,"Boot mode is QSPI\n\r"); + InitQspi(); + MoveImage = QspiAccess; + fsbl_printf(DEBUG_INFO,"QSPI Init Done \r\n"); + } else +#endif + + /* + * NAND BOOT MODE + */ +#ifdef XPAR_PS7_NAND_0_BASEADDR + if (BootModeRegister == NAND_FLASH_MODE) { + /* + * Boot ROM always initialize the nand at lower speed + * This is the chance to put it to an optimum speed for your nand + * device + */ + fsbl_printf(DEBUG_GENERAL,"Boot mode is NAND\n"); + + Status = InitNand(); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL,"NAND_INIT_FAIL \r\n"); + /* + * Error Handling here + */ + OutputStatus(NAND_INIT_FAIL); + FsblFallback(); + } + MoveImage = NandAccess; + fsbl_printf(DEBUG_INFO,"NAND Init Done \r\n"); + } else +#endif + + /* + * NOR BOOT MODE + */ + if (BootModeRegister == NOR_FLASH_MODE) { + fsbl_printf(DEBUG_GENERAL,"Boot mode is NOR\n\r"); + /* + * Boot ROM always initialize the nor at lower speed + * This is the chance to put it to an optimum speed for your nor + * device + */ + InitNor(); + fsbl_printf(DEBUG_INFO,"NOR Init Done \r\n"); + MoveImage = NorAccess; + } else + + /* + * SD BOOT MODE + */ +#if defined(XPAR_PS7_SD_0_S_AXI_BASEADDR) || defined(XPAR_XSDPS_0_BASEADDR) + + if (BootModeRegister == SD_MODE) { + fsbl_printf(DEBUG_GENERAL,"Boot mode is SD\r\n"); + + /* + * SD initialization returns file open error or success + */ + Status = InitSD("BOOT.BIN"); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL,"SD_INIT_FAIL\r\n"); + OutputStatus(SD_INIT_FAIL); + FsblFallback(); + } + MoveImage = SDAccess; + fsbl_printf(DEBUG_INFO,"SD Init Done \r\n"); + } else + + if (BootModeRegister == MMC_MODE) { + fsbl_printf(DEBUG_GENERAL,"Booting Device is MMC\r\n"); + + /* + * MMC initialization returns file open error or success + */ + Status = InitSD("BOOT.BIN"); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL,"MMC_INIT_FAIL\r\n"); + OutputStatus(SD_INIT_FAIL); + FsblFallback(); + } + MoveImage = SDAccess; + fsbl_printf(DEBUG_INFO,"MMC Init Done \r\n"); + } else + +#endif + + /* + * JTAG BOOT MODE + */ + if (BootModeRegister == JTAG_MODE) { + fsbl_printf(DEBUG_GENERAL,"Boot mode is JTAG\r\n"); + /* + * Stop the Watchdog before JTAG handoff + */ +#ifdef XPAR_XWDTPS_0_BASEADDR + XWdtPs_Stop(&Watchdog); +#endif + /* + * Clear our mark in reboot status register + */ + ClearFSBLIn(); + + /* + * SLCR lock + */ + SlcrLock(); + + FsblHandoffJtagExit(); + } else { + fsbl_printf(DEBUG_GENERAL,"ILLEGAL_BOOT_MODE \r\n"); + OutputStatus(ILLEGAL_BOOT_MODE); + /* + * fallback starts, no return + */ + FsblFallback(); + } + + fsbl_printf(DEBUG_INFO,"Flash Base Address: 0x%08lx\r\n", FlashReadBaseAddress); + + /* + * Check for valid flash address + */ + if ((FlashReadBaseAddress != XPS_QSPI_LINEAR_BASEADDR) && + (FlashReadBaseAddress != XPS_NAND_BASEADDR) && + (FlashReadBaseAddress != XPS_NOR_BASEADDR) && + (FlashReadBaseAddress != XPS_SDIO0_BASEADDR)) { + fsbl_printf(DEBUG_GENERAL,"INVALID_FLASH_ADDRESS \r\n"); + OutputStatus(INVALID_FLASH_ADDRESS); + FsblFallback(); + } + + /* + * NOR and QSPI (parallel) are linear boot devices + */ + if ((FlashReadBaseAddress == XPS_NOR_BASEADDR)) { + fsbl_printf(DEBUG_INFO, "Linear Boot Device\r\n"); + LinearBootDeviceFlag = 1; + } + +#ifdef XPAR_XWDTPS_0_BASEADDR + /* + * Prevent WDT reset + */ + XWdtPs_RestartWdt(&Watchdog); +#endif + + /* + * This used only in case of E-Fuse encryption + * For image search + */ + SystemInitFlag = 1; + + /* + * Load boot image + */ + HandoffAddress = LoadBootImage(); + + fsbl_printf(DEBUG_INFO,"Handoff Address: 0x%08lx\r\n",HandoffAddress); + + /* + * For Performance measurement + */ +#ifdef FSBL_PERF + XTime tEnd = 0; + fsbl_printf(DEBUG_GENERAL,"Total Execution time is "); + FsblMeasurePerfTime(tCur,tEnd); +#endif + + /* + * FSBL handoff to valid handoff address or + * exit in JTAG + */ + FsblHandoff(HandoffAddress); + +#else + OutputStatus(NO_DDR); + FsblFallback(); +#endif + + return Status; +} + +/******************************************************************************/ +/** +* +* This function reset the CPU and goes for Boot ROM fallback handling +* +* @param None +* +* @return None +* +* @note None +* +****************************************************************************/ +void FsblFallback(void) +{ + u32 RebootStatusReg; + u32 Status; + u32 HandoffAddr; + u32 BootModeRegister; + + /* + * Read bootmode register + */ + BootModeRegister = Xil_In32(BOOT_MODE_REG); + BootModeRegister &= BOOT_MODES_MASK; + + /* + * Fallback support check + */ + if (!((BootModeRegister == QSPI_MODE) || + (BootModeRegister == NAND_FLASH_MODE) || + (BootModeRegister == NOR_FLASH_MODE))) { + fsbl_printf(DEBUG_INFO,"\r\n" + "This Boot Mode Doesn't Support Fallback\r\n"); + ClearFSBLIn(); + FsblHookFallback(); + } + + /* + * update the Multiboot Register for Golden search hunt + */ + Update_MultiBootRegister(); + + /* + * Notify Boot ROM something is wrong + */ + RebootStatusReg = Xil_In32(REBOOT_STATUS_REG); + + /* + * Set the FSBL Fail mask + */ + Xil_Out32(REBOOT_STATUS_REG, RebootStatusReg | FSBL_FAIL_MASK); + + /* + * Barrier for synchronization + */ + __asm( + "dsb\n\t" + "isb" + ); + + /* + * Check for AES source key + */ + if (PcapCtrlRegVal & XDCFG_CTRL_PCFG_AES_FUSE_MASK) { + /* + * Next valid image search can happen only + * when system initialization done + */ + if (SystemInitFlag == 1) { + /* + * Clean the Fabric + */ + Status = FabricInit(); + if(Status != XST_SUCCESS){ + ClearFSBLIn(); + FsblHookFallback(); + } + +#ifdef RSA_SUPPORT + + /* + * Making sure PPK is set for efuse error cases + */ + SetPpk(); +#endif + + /* + * Search for next valid image + */ + Status = NextValidImageCheck(); + if(Status != XST_SUCCESS){ + fsbl_printf(DEBUG_INFO,"\r\nNo Image Found\r\n"); + ClearFSBLIn(); + FsblHookFallback(); + } + + /* + * Load next valid image + */ + HandoffAddr = LoadBootImage(); + + /* + * Handoff to next image + */ + FsblHandoff(HandoffAddr); + } else { + fsbl_printf(DEBUG_INFO,"System Initialization Failed\r\n"); + fsbl_printf(DEBUG_INFO,"\r\nNo Image Search\r\n"); + ClearFSBLIn(); + FsblHookFallback(); + } + } + + /* + * Reset PS, so Boot ROM will restart + */ + Xil_Out32(PS_RST_CTRL_REG, PS_RST_MASK); +} + + +/******************************************************************************/ +/** +* +* This function hands the A9/PS to the loaded user code. +* +* @param none +* +* @return none +* +* @note This function does not return. +* +****************************************************************************/ +void FsblHandoff(u32 FsblStartAddr) +{ + u32 Status; + + /* + * Enable level shifter + */ + if(BitstreamFlag) { + /* + * FSBL will not enable the level shifters for a NON PS instantiated + * Bitstream + * CR# 671028 + * This flag can be set during compilation for a NON PS instantiated + * bitstream + */ +#ifndef NON_PS_INSTANTIATED_BITSTREAM +#ifdef PS7_POST_CONFIG + ps7_post_config(); + /* + * Unlock SLCR for SLCR register write + */ + SlcrUnlock(); +#else + /* + * Set Level Shifters DT618760 + */ + Xil_Out32(PS_LVL_SHFTR_EN, LVL_PL_PS); + fsbl_printf(DEBUG_INFO,"Enabling Level Shifters PL to PS " + "Address = 0x%x Value = 0x%x \n\r", + PS_LVL_SHFTR_EN, Xil_In32(PS_LVL_SHFTR_EN)); + + /* + * Enable AXI interface + */ + Xil_Out32(FPGA_RESET_REG, 0); + fsbl_printf(DEBUG_INFO,"AXI Interface enabled \n\r"); + fsbl_printf(DEBUG_INFO, "FPGA Reset Register " + "Address = 0x%x , Value = 0x%x \r\n", + FPGA_RESET_REG ,Xil_In32(FPGA_RESET_REG)); +#endif +#endif + } + + /* + * FSBL user hook call before handoff to the application + */ + Status = FsblHookBeforeHandoff(); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL,"FSBL_HANDOFF_HOOK_FAIL\r\n"); + OutputStatus(FSBL_HANDOFF_HOOK_FAIL); + FsblFallback(); + } + +#ifdef XPAR_XWDTPS_0_BASEADDR + XWdtPs_Stop(&Watchdog); +#endif + + /* + * Clear our mark in reboot status register + */ + ClearFSBLIn(); + + if(FsblStartAddr == 0) { + /* + * SLCR lock + */ + SlcrLock(); + + fsbl_printf(DEBUG_INFO,"No Execution Address JTAG handoff \r\n"); + FsblHandoffJtagExit(); + } else { + fsbl_printf(DEBUG_GENERAL,"SUCCESSFUL_HANDOFF\r\n"); + OutputStatus(SUCCESSFUL_HANDOFF); + FsblHandoffExit(FsblStartAddr); + } + + OutputStatus(ILLEGAL_RETURN); + + FsblFallback(); +} + +/******************************************************************************/ +/** +* +* This function outputs the status for the provided State in the boot process. +* +* @param State is where in the boot process the output is desired. +* +* @return None. +* +* @note None. +* +****************************************************************************/ +void OutputStatus(u32 State) +{ +#ifdef STDOUT_BASEADDRESS +#ifdef XPAR_XUARTPS_0_BASEADDR + u32 UartReg = 0; +#endif + + fsbl_printf(DEBUG_GENERAL,"FSBL Status = 0x%.4lx\r\n", State); + /* + * The TX buffer needs to be flushed out + * If this is not done some of the prints will not appear on the + * serial output + */ +#ifdef XPAR_XUARTPS_0_BASEADDR + UartReg = Xil_In32(STDOUT_BASEADDRESS + XUARTPS_SR_OFFSET); + while ((UartReg & XUARTPS_SR_TXEMPTY) != XUARTPS_SR_TXEMPTY) { + UartReg = Xil_In32(STDOUT_BASEADDRESS + XUARTPS_SR_OFFSET); + } +#endif +#endif +} + +/******************************************************************************/ +/** +* +* This function handles the error and lockdown processing and outputs the status +* for the provided State in the boot process. +* +* This function is called upon exceptions. +* +* @param State - where in the boot process the error occured. +* +* @return None. +* +* @note This function does not return, the PS block is reset +* +****************************************************************************/ +void ErrorLockdown(u32 State) +{ + /* + * Store the error status + */ + OutputStatus(State); + + /* + * Fall back + */ + FsblFallback(); +} + +/******************************************************************************/ +/** +* +* This function copies a memory region to another memory region +* +* @param s1 is starting address for destination +* @param s2 is starting address for the source +* @param n is the number of bytes to copy +* +* @return Starting address for destination +* +****************************************************************************/ +void *(memcpy_rom)(void * s1, const void * s2, u32 n) +{ + char *dst = (char *)s1; + const char *src = (char *)s2; + + /* + * Loop and copy + */ + while (n-- != 0) + *dst++ = *src++; + return s1; +} +/******************************************************************************/ +/** +* +* This function copies a string to another, the source string must be null- +* terminated. +* +* @param Dest is starting address for the destination string +* @param Src is starting address for the source string +* +* @return Starting address for the destination string +* +****************************************************************************/ +char *strcpy_rom(char *Dest, const char *Src) +{ + unsigned i; + for (i=0; Src[i] != '\0'; ++i) + Dest[i] = Src[i]; + Dest[i] = '\0'; + return Dest; +} + + +/******************************************************************************/ +/** +* +* This function sets FSBL is running mask in reboot status register +* +* @param None. +* +* @return None. +* +* @note None. +* +****************************************************************************/ +void MarkFSBLIn(void) +{ + Xil_Out32(REBOOT_STATUS_REG, + Xil_In32(REBOOT_STATUS_REG) | FSBL_IN_MASK); +} + + +/******************************************************************************/ +/** +* +* This function clears FSBL is running mask in reboot status register +* +* @param None. +* +* @return None. +* +* @note None. +* +****************************************************************************/ +void ClearFSBLIn(void) +{ + Xil_Out32(REBOOT_STATUS_REG, + (Xil_In32(REBOOT_STATUS_REG)) & ~(FSBL_FAIL_MASK)); +} + +/******************************************************************************/ +/** +* +* This function Registers the Exception Handlers +* +* @param None. +* +* @return None. +* +* @note None. +* +****************************************************************************/ +static void RegisterHandlers(void) +{ + Xil_ExceptionInit(); + + /* + * Initialize the vector table. Register the stub Handler for each + * exception. + */ + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_UNDEFINED_INT, + (Xil_ExceptionHandler)Undef_Handler, + (void *) 0); + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_SWI_INT, + (Xil_ExceptionHandler)SVC_Handler, + (void *) 0); + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_PREFETCH_ABORT_INT, + (Xil_ExceptionHandler)PreFetch_Abort_Handler, + (void *) 0); + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_DATA_ABORT_INT, + (Xil_ExceptionHandler)Data_Abort_Handler, + (void *) 0); + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT, + (Xil_ExceptionHandler)IRQ_Handler,(void *) 0); + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_FIQ_INT, + (Xil_ExceptionHandler)FIQ_Handler,(void *) 0); + + Xil_ExceptionEnable(); + +} + +static void Undef_Handler (void) +{ + fsbl_printf(DEBUG_GENERAL,"UNDEFINED_HANDLER\r\n"); + ErrorLockdown (EXCEPTION_ID_UNDEFINED_INT); +} + +static void SVC_Handler (void) +{ + fsbl_printf(DEBUG_GENERAL,"SVC_HANDLER \r\n"); + ErrorLockdown (EXCEPTION_ID_SWI_INT); +} + +static void PreFetch_Abort_Handler (void) +{ + fsbl_printf(DEBUG_GENERAL,"PREFETCH_ABORT_HANDLER \r\n"); + ErrorLockdown (EXCEPTION_ID_PREFETCH_ABORT_INT); +} + +static void Data_Abort_Handler (void) +{ + fsbl_printf(DEBUG_GENERAL,"DATA_ABORT_HANDLER \r\n"); + ErrorLockdown (EXCEPTION_ID_DATA_ABORT_INT); +} + +static void IRQ_Handler (void) +{ + fsbl_printf(DEBUG_GENERAL,"IRQ_HANDLER \r\n"); + ErrorLockdown (EXCEPTION_ID_IRQ_INT); +} + +static void FIQ_Handler (void) +{ + fsbl_printf(DEBUG_GENERAL,"FIQ_HANDLER \r\n"); + ErrorLockdown (EXCEPTION_ID_FIQ_INT); +} + + +/******************************************************************************/ +/** +* +* This function Updates the Multi boot Register to enable golden image +* search for boot rom +* +* @param None +* +* @return +* return none +* +****************************************************************************/ +static void Update_MultiBootRegister(void) +{ + u32 MultiBootReg = 0; + + if (Silicon_Version != SILICON_VERSION_1) { + /* + * Read the mulitboot register + */ + MultiBootReg = XDcfg_ReadReg(DcfgInstPtr->Config.BaseAddr, + XDCFG_MULTIBOOT_ADDR_OFFSET); + + /* + * Incrementing multiboot register by one + */ + MultiBootReg++; + + XDcfg_WriteReg(DcfgInstPtr->Config.BaseAddr, + XDCFG_MULTIBOOT_ADDR_OFFSET, + MultiBootReg); + + fsbl_printf(DEBUG_INFO,"Updated MultiBootReg = 0x%08lx\r\n", + MultiBootReg); + } +} + + +/****************************************************************************** +* +* This function reset the CPU and goes for Boot ROM fallback handling +* +* @param None +* +* @return None +* +* @note None +* +*******************************************************************************/ + +u32 GetResetReason(void) +{ + u32 Regval; + + /* We are using REBOOT_STATUS_REG, we have to use bits 23:16 */ + /* for storing the RESET_REASON register value*/ + Regval = ((Xil_In32(REBOOT_STATUS_REG) >> 16) & 0xFF); + + return Regval; +} + + +/****************************************************************************** +* +* This function Gets the ticks from the Global Timer +* +* @param Current time +* +* @return +* None +* +* @note None +* +*******************************************************************************/ +#ifdef FSBL_PERF +void FsblGetGlobalTime (XTime *tCur) +{ + XTime_GetTime(tCur); +} + + +/****************************************************************************** +* +* This function Measures the execution time +* +* @param Current time , End time +* +* @return +* None +* +* @note None +* +*******************************************************************************/ +void FsblMeasurePerfTime (XTime tCur, XTime tEnd) +{ + double tDiff = 0.0; + double tPerfSeconds; + XTime_GetTime(&tEnd); + tDiff = (double)tEnd - (double)tCur; + + /* + * Convert tPerf into Seconds + */ + tPerfSeconds = tDiff/COUNTS_PER_SECOND; + +#if defined(STDOUT_BASEADDRESS) + printf("%f seconds \r\n",tPerfSeconds); +#endif + +} +#endif + +/****************************************************************************** +* +* This function initializes the Watchdog driver and starts the timer +* +* @param None +* +* @return +* - XST_SUCCESS if the Watchdog driver is initialized +* - XST_FAILURE if Watchdog driver initialization fails +* +* @note None +* +*******************************************************************************/ +#ifdef XPAR_XWDTPS_0_BASEADDR +int InitWatchDog(void) +{ + u32 Status = XST_SUCCESS; + XWdtPs_Config *ConfigPtr; /* Config structure of the WatchDog Timer */ + u32 CounterValue = 1; + + ConfigPtr = XWdtPs_LookupConfig(WDT_DEVICE_ID); + Status = XWdtPs_CfgInitialize(&Watchdog, + ConfigPtr, + ConfigPtr->BaseAddress); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_INFO,"Watchdog Driver init Failed \n\r"); + return XST_FAILURE; + } + + /* + * Setting the divider value + */ + XWdtPs_SetControlValue(&Watchdog, + XWDTPS_CLK_PRESCALE, + XWDTPS_CCR_PSCALE_4096); + /* + * Convert time to Watchdog counter reset value + */ + CounterValue = ConvertTime_WdtCounter(WDT_EXPIRE_TIME); + + /* + * Set the Watchdog counter reset value + */ + XWdtPs_SetControlValue(&Watchdog, + XWDTPS_COUNTER_RESET, + CounterValue); + /* + * enable reset output, as we are only using this as a basic counter + */ + XWdtPs_EnableOutput(&Watchdog, XWDTPS_RESET_SIGNAL); + + /* + * Start the Watchdog timer + */ + XWdtPs_Start(&Watchdog); + + XWdtPs_RestartWdt(&Watchdog); + + return XST_SUCCESS; +} + + +/******************************************************************************/ +/** +* +* This function checks whether WDT reset has happened during FSBL run +* +* If WDT reset happened during FSBL run, then need to fallback +* +* @param None. +* +* @return +* None +* +* @note None +* +****************************************************************************/ +void CheckWDTReset(void) +{ + u32 ResetReason; + u32 RebootStatusRegister; + + RebootStatusRegister = Xil_In32(REBOOT_STATUS_REG); + + /* + * For 1.0 Silicon the reason for Reset is in the ResetReason Register + * Hence this register can be read to know the cause for previous reset + * that happened. + * Check if that reset is a Software WatchDog reset that happened + */ + if (Silicon_Version == SILICON_VERSION_1) { + ResetReason = Xil_In32(RESET_REASON_REG); + } else { + ResetReason = GetResetReason(); + } + /* + * If the FSBL_IN_MASK Has not been cleared, WDT happened + * before FSBL exits + */ + if ((ResetReason & RESET_REASON_SWDT) == RESET_REASON_SWDT ) { + if ((RebootStatusRegister & FSBL_FAIL_MASK) == FSBL_IN_MASK) { + /* + * Clear the SWDT Reset bit + */ + ResetReason &= ~RESET_REASON_SWDT; + if (Silicon_Version == SILICON_VERSION_1) { + /* + * for 1.0 Silicon we need to write + * 1 to the RESET REASON Clear register + */ + Xil_Out32(RESET_REASON_CLR, 1); + } else { + Xil_Out32(REBOOT_STATUS_REG, ResetReason); + } + + fsbl_printf(DEBUG_GENERAL,"WDT_RESET_OCCURED \n\r"); + } + } +} + + +/****************************************************************************** +* +* This function converts time into Watchdog counter value +* +* @param watchdog expire time in seconds +* +* @return +* Counter value for Watchdog +* +* @note None +* +*******************************************************************************/ +u32 ConvertTime_WdtCounter(u32 seconds) +{ + double time = 0.0; + double CounterValue; + u32 Crv = 0; + u32 Prescaler,PrescalerValue; + + Prescaler = XWdtPs_GetControlValue(&Watchdog, XWDTPS_CLK_PRESCALE); + + if (Prescaler == XWDTPS_CCR_PSCALE_0008) + PrescalerValue = 8; + if (Prescaler == XWDTPS_CCR_PSCALE_0064) + PrescalerValue = 64; + if (Prescaler == XWDTPS_CCR_PSCALE_4096) + PrescalerValue = 4096; + + time = (double)(PrescalerValue) / (double)XPAR_PS7_WDT_0_WDT_CLK_FREQ_HZ; + + CounterValue = seconds / time; + + Crv = (u32)CounterValue; + Crv >>= WDT_CRV_SHIFT; + + return Crv; +} + +#endif + + +/****************************************************************************** +* +* This function Gets the Silicon Version stores in global variable +* +* @param None +* +* @return None +* +* @note None +* +*******************************************************************************/ +void GetSiliconVersion(void) +{ + /* + * Get the silicon version + */ + Silicon_Version = XDcfg_GetPsVersion(DcfgInstPtr); + if(Silicon_Version == SILICON_VERSION_3_1) { + fsbl_printf(DEBUG_GENERAL,"Silicon Version 3.1\r\n"); + } else { + fsbl_printf(DEBUG_GENERAL,"Silicon Version %lu.0\r\n", + Silicon_Version + 1); + } +} + + +/****************************************************************************** +* +* This function HeaderChecksum will calculates the header checksum and +* compares with checksum read from flash +* +* @param FlashOffsetAddress Flash offset address +* +* @return +* - XST_SUCCESS if ID matches +* - XST_FAILURE if ID mismatches +* +* @note None +* +*******************************************************************************/ +u32 HeaderChecksum(u32 FlashOffsetAddress){ + u32 Checksum = 0; + u32 Count; + u32 TempValue = 0; + + for (Count = 0; Count < IMAGE_HEADER_CHECKSUM_COUNT; Count++) { + /* + * Read the word from the header + */ + MoveImage(FlashOffsetAddress + IMAGE_WIDTH_CHECK_OFFSET + (Count*4), (u32)&TempValue, 4); + + /* + * Update checksum + */ + Checksum += TempValue; + } + + /* + * Invert checksum, last bit of error checking + */ + Checksum ^= 0xFFFFFFFF; + MoveImage(FlashOffsetAddress + IMAGE_CHECKSUM_OFFSET, (u32)&TempValue, 4); + + /* + * Validate the checksum + */ + if (TempValue != Checksum){ + fsbl_printf(DEBUG_INFO, "Checksum = %8.8lx\r\n", Checksum); + return XST_FAILURE; + } + + return XST_SUCCESS; +} + + +/****************************************************************************** +* +* This function ImageCheckID will do check for XLNX pattern +* +* @param FlashOffsetAddress Flash offset address +* +* @return +* - XST_SUCCESS if ID matches +* - XST_FAILURE if ID mismatches +* +* @note None +* +*******************************************************************************/ +u32 ImageCheckID(u32 FlashOffsetAddress){ + u32 ID; + + /* + * Read in the header info + */ + MoveImage(FlashOffsetAddress + IMAGE_IDENT_OFFSET, (u32)&ID, 4); + + /* + * Check the ID, make sure image is XLNX format + */ + if (ID != IMAGE_IDENT){ + return XST_FAILURE; + } + + return XST_SUCCESS; +} + + +/****************************************************************************** +* +* This function NextValidImageCheck search for valid boot image +* +* @param None +* +* @return +* - XST_SUCCESS if valid image found +* - XST_FAILURE if no image found +* +* @note None +* +*******************************************************************************/ +u32 NextValidImageCheck(void) +{ + u32 ImageBaseAddr; + u32 MultiBootReg; + u32 BootDevMaxSize=0; + + fsbl_printf(DEBUG_GENERAL, "Searching For Next Valid Image"); + + /* + * Setting variable with maximum flash size based on boot mode + */ +#ifdef XPAR_PS7_QSPI_LINEAR_0_S_AXI_BASEADDR + if (FlashReadBaseAddress == XPS_QSPI_LINEAR_BASEADDR) { + BootDevMaxSize = QspiFlashSize; + } +#endif + + if (FlashReadBaseAddress == XPS_NAND_BASEADDR) { + BootDevMaxSize = NAND_FLASH_SIZE; + } + + if (FlashReadBaseAddress == XPS_NOR_BASEADDR) { + BootDevMaxSize = NOR_FLASH_SIZE; + } + + /* + * Read the multiboot register + */ + MultiBootReg = XDcfg_ReadReg(DcfgInstPtr->Config.BaseAddr, + XDCFG_MULTIBOOT_ADDR_OFFSET); + + /* + * Compute the image start address + */ + ImageBaseAddr = (MultiBootReg & PCAP_MBOOT_REG_REBOOT_OFFSET_MASK) + * GOLDEN_IMAGE_OFFSET; + + /* + * Valid image search continue till end of the flash + * With increment 32KB in each iteration + */ + while (ImageBaseAddr < BootDevMaxSize) { + + fsbl_printf(DEBUG_INFO,"."); + + /* + * Valid image search using XLNX pattern at fixed offset + * and header checksum + */ + if ((ImageCheckID(ImageBaseAddr) == XST_SUCCESS) && + (HeaderChecksum(ImageBaseAddr) == XST_SUCCESS)) { + + fsbl_printf(DEBUG_GENERAL, "\r\nImage found, offset: 0x%.8lx\r\n", + ImageBaseAddr); + /* + * Update multiboot register + */ + XDcfg_WriteReg(DcfgInstPtr->Config.BaseAddr, + XDCFG_MULTIBOOT_ADDR_OFFSET, + MultiBootReg); + + return XST_SUCCESS; + } + + /* + * Increment mulitboot count + */ + MultiBootReg++; + + /* + * Compute the image start address + */ + ImageBaseAddr = (MultiBootReg & PCAP_MBOOT_REG_REBOOT_OFFSET_MASK) + * GOLDEN_IMAGE_OFFSET; + } + + return XST_FAILURE; +} + +/******************************************************************************/ +/** +* +* This function Checks for the ddr initialization completion +* +* @param None. +* +* @return +* - XST_SUCCESS if the initialization is successful +* - XST_FAILURE if the initialization is NOT successful +* +* @note None. +* +****************************************************************************/ +u32 DDRInitCheck(void) +{ + u32 ReadVal; + + /* + * Write and Read from the DDR location for sanity checks + */ + Xil_Out32(DDR_START_ADDR, DDR_TEST_PATTERN); + ReadVal = Xil_In32(DDR_START_ADDR); + if (ReadVal != DDR_TEST_PATTERN) { + return XST_FAILURE; + } + + /* + * Write and Read from the DDR location for sanity checks + */ + Xil_Out32(DDR_START_ADDR + DDR_TEST_OFFSET, DDR_TEST_PATTERN); + ReadVal = Xil_In32(DDR_START_ADDR + DDR_TEST_OFFSET); + if (ReadVal != DDR_TEST_PATTERN) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} diff --git a/sdk/fsbl/src/md5.c b/sdk/fsbl/src/md5.c new file mode 100644 index 0000000..e7cf7ea --- /dev/null +++ b/sdk/fsbl/src/md5.c @@ -0,0 +1,484 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/*****************************************************************************/ +/** +* +* @file md5.c +* +* Contains code to calculate checksum using md5 algorithm +* +*
+* MODIFICATION HISTORY:
+*
+* Ver	Who	Date		Changes
+* ----- ---- -------- -------------------------------------------------------
+* 5.00a sgd	05/17/13 Initial release
+*
+*
+* 
+* +* @note +* +******************************************************************************/ +/****************************** Include Files *********************************/ + +#include "md5.h" + +/******************************************************************************/ +/** +* +* This function sets the memory +* +* @param dest +* +* @param ch +* +* @param count +* +* @return None +* +* @note None +* +****************************************************************************/ +inline void * MD5Memset( void *dest, int ch, u32 count ) +{ + register char *dst8 = (char*)dest; + + while( count-- ) + *dst8++ = ch; + + return dest; +} + +/******************************************************************************/ +/** +* +* This function copy the memory +* +* @param dest +* +* @param ch +* +* @param count +* +* @return None +* +* @note None +* +****************************************************************************/ +inline void * MD5Memcpy( void *dest, const void *src, + u32 count, boolean doByteSwap ) +{ + register char * dst8 = (char*)dest; + register char * src8 = (char*)src; + + if( doByteSwap == FALSE ) { + while( count-- ) + *dst8++ = *src8++; + } else { + count /= sizeof( u32 ); + + while( count-- ) { + dst8[ 0 ] = src8[ 3 ]; + dst8[ 1 ] = src8[ 2 ]; + dst8[ 2 ] = src8[ 1 ]; + dst8[ 3 ] = src8[ 0 ]; + + dst8 += 4; + src8 += 4; + } + } + + return dest; +} + +/******************************************************************************/ +/** +* +* This function is the core of the MD5 algorithm, +* this alters an existing MD5 hash to +* reflect the addition of 16 longwords of new data. MD5Update blocks +* the data and converts bytes into longwords for this routine. +* +* Use binary integer part of the sine of integers (Radians) as constants. +* Calculated as: +* +* for( i = 0; i < 63; i++ ) +* k[ i ] := floor( abs( sin( i + 1 ) ) × pow( 2, 32 ) ) +* +* Following number is the per-round shift amount. +* +* @param dest +* +* @param ch +* +* @param count +* +* @return None +* +* @note None +* +****************************************************************************/ +void MD5Transform( u32 *buffer, u32 *intermediate ) +{ + register u32 a, b, c, d; + + a = buffer[ 0 ]; + b = buffer[ 1 ]; + c = buffer[ 2 ]; + d = buffer[ 3 ]; + + MD5_STEP( F1, a, b, c, d, intermediate[ 0 ] + 0xd76aa478, 7 ); + MD5_STEP( F1, d, a, b, c, intermediate[ 1 ] + 0xe8c7b756, 12 ); + MD5_STEP( F1, c, d, a, b, intermediate[ 2 ] + 0x242070db, 17 ); + MD5_STEP( F1, b, c, d, a, intermediate[ 3 ] + 0xc1bdceee, 22 ); + MD5_STEP( F1, a, b, c, d, intermediate[ 4 ] + 0xf57c0faf, 7 ); + MD5_STEP( F1, d, a, b, c, intermediate[ 5 ] + 0x4787c62a, 12 ); + MD5_STEP( F1, c, d, a, b, intermediate[ 6 ] + 0xa8304613, 17 ); + MD5_STEP( F1, b, c, d, a, intermediate[ 7 ] + 0xfd469501, 22 ); + MD5_STEP( F1, a, b, c, d, intermediate[ 8 ] + 0x698098d8, 7 ); + MD5_STEP( F1, d, a, b, c, intermediate[ 9 ] + 0x8b44f7af, 12 ); + MD5_STEP( F1, c, d, a, b, intermediate[ 10 ] + 0xffff5bb1, 17 ); + MD5_STEP( F1, b, c, d, a, intermediate[ 11 ] + 0x895cd7be, 22 ); + MD5_STEP( F1, a, b, c, d, intermediate[ 12 ] + 0x6b901122, 7 ); + MD5_STEP( F1, d, a, b, c, intermediate[ 13 ] + 0xfd987193, 12 ); + MD5_STEP( F1, c, d, a, b, intermediate[ 14 ] + 0xa679438e, 17 ); + MD5_STEP( F1, b, c, d, a, intermediate[ 15 ] + 0x49b40821, 22 ); + + MD5_STEP( F2, a, b, c, d, intermediate[ 1 ] + 0xf61e2562, 5 ); + MD5_STEP( F2, d, a, b, c, intermediate[ 6 ] + 0xc040b340, 9 ); + MD5_STEP( F2, c, d, a, b, intermediate[ 11 ] + 0x265e5a51, 14 ); + MD5_STEP( F2, b, c, d, a, intermediate[ 0 ] + 0xe9b6c7aa, 20 ); + MD5_STEP( F2, a, b, c, d, intermediate[ 5 ] + 0xd62f105d, 5 ); + MD5_STEP( F2, d, a, b, c, intermediate[ 10 ] + 0x02441453, 9 ); + MD5_STEP( F2, c, d, a, b, intermediate[ 15 ] + 0xd8a1e681, 14 ); + MD5_STEP( F2, b, c, d, a, intermediate[ 4 ] + 0xe7d3fbc8, 20 ); + MD5_STEP( F2, a, b, c, d, intermediate[ 9 ] + 0x21e1cde6, 5 ); + MD5_STEP( F2, d, a, b, c, intermediate[ 14 ] + 0xc33707d6, 9 ); + MD5_STEP( F2, c, d, a, b, intermediate[ 3 ] + 0xf4d50d87, 14 ); + MD5_STEP( F2, b, c, d, a, intermediate[ 8 ] + 0x455a14ed, 20 ); + MD5_STEP( F2, a, b, c, d, intermediate[ 13 ] + 0xa9e3e905, 5 ); + MD5_STEP( F2, d, a, b, c, intermediate[ 2 ] + 0xfcefa3f8, 9 ); + MD5_STEP( F2, c, d, a, b, intermediate[ 7 ] + 0x676f02d9, 14 ); + MD5_STEP( F2, b, c, d, a, intermediate[ 12 ] + 0x8d2a4c8a, 20 ); + + MD5_STEP( F3, a, b, c, d, intermediate[ 5 ] + 0xfffa3942, 4 ); + MD5_STEP( F3, d, a, b, c, intermediate[ 8 ] + 0x8771f681, 11 ); + MD5_STEP( F3, c, d, a, b, intermediate[ 11 ] + 0x6d9d6122, 16 ); + MD5_STEP( F3, b, c, d, a, intermediate[ 14 ] + 0xfde5380c, 23 ); + MD5_STEP( F3, a, b, c, d, intermediate[ 1 ] + 0xa4beea44, 4 ); + MD5_STEP( F3, d, a, b, c, intermediate[ 4 ] + 0x4bdecfa9, 11 ); + MD5_STEP( F3, c, d, a, b, intermediate[ 7 ] + 0xf6bb4b60, 16 ); + MD5_STEP( F3, b, c, d, a, intermediate[ 10 ] + 0xbebfbc70, 23 ); + MD5_STEP( F3, a, b, c, d, intermediate[ 13 ] + 0x289b7ec6, 4 ); + MD5_STEP( F3, d, a, b, c, intermediate[ 0 ] + 0xeaa127fa, 11 ); + MD5_STEP( F3, c, d, a, b, intermediate[ 3 ] + 0xd4ef3085, 16 ); + MD5_STEP( F3, b, c, d, a, intermediate[ 6 ] + 0x04881d05, 23 ); + MD5_STEP( F3, a, b, c, d, intermediate[ 9 ] + 0xd9d4d039, 4 ); + MD5_STEP( F3, d, a, b, c, intermediate[ 12 ] + 0xe6db99e5, 11 ); + MD5_STEP( F3, c, d, a, b, intermediate[ 15 ] + 0x1fa27cf8, 16 ); + MD5_STEP( F3, b, c, d, a, intermediate[ 2 ] + 0xc4ac5665, 23 ); + + MD5_STEP( F4, a, b, c, d, intermediate[ 0 ] + 0xf4292244, 6 ); + MD5_STEP( F4, d, a, b, c, intermediate[ 7 ] + 0x432aff97, 10 ); + MD5_STEP( F4, c, d, a, b, intermediate[ 14 ] + 0xab9423a7, 15 ); + MD5_STEP( F4, b, c, d, a, intermediate[ 5 ] + 0xfc93a039, 21 ); + MD5_STEP( F4, a, b, c, d, intermediate[ 12 ] + 0x655b59c3, 6 ); + MD5_STEP( F4, d, a, b, c, intermediate[ 3 ] + 0x8f0ccc92, 10 ); + MD5_STEP( F4, c, d, a, b, intermediate[ 10 ] + 0xffeff47d, 15 ); + MD5_STEP( F4, b, c, d, a, intermediate[ 1 ] + 0x85845dd1, 21 ); + MD5_STEP( F4, a, b, c, d, intermediate[ 8 ] + 0x6fa87e4f, 6 ); + MD5_STEP( F4, d, a, b, c, intermediate[ 15 ] + 0xfe2ce6e0, 10 ); + MD5_STEP( F4, c, d, a, b, intermediate[ 6 ] + 0xa3014314, 15 ); + MD5_STEP( F4, b, c, d, a, intermediate[ 13 ] + 0x4e0811a1, 21 ); + MD5_STEP( F4, a, b, c, d, intermediate[ 4 ] + 0xf7537e82, 6 ); + MD5_STEP( F4, d, a, b, c, intermediate[ 11 ] + 0xbd3af235, 10 ); + MD5_STEP( F4, c, d, a, b, intermediate[ 2 ] + 0x2ad7d2bb, 15 ); + MD5_STEP( F4, b, c, d, a, intermediate[ 9 ] + 0xeb86d391, 21 ); + + buffer[ 0 ] += a; + buffer[ 1 ] += b; + buffer[ 2 ] += c; + buffer[ 3 ] += d; + +} + +/******************************************************************************/ +/** +* +* This function Start MD5 accumulation +* Set bit count to 0 and buffer to mysterious initialization constants +* +* @param +* +* @return None +* +* @note None +* +****************************************************************************/ +inline void MD5Init( MD5Context *context ) +{ + + context->buffer[ 0 ] = 0x67452301; + context->buffer[ 1 ] = 0xefcdab89; + context->buffer[ 2 ] = 0x98badcfe; + context->buffer[ 3 ] = 0x10325476; + + context->bits[ 0 ] = 0; + context->bits[ 1 ] = 0; + +} + + +/******************************************************************************/ +/** +* +* This function updates context to reflect the concatenation of another +* buffer full of bytes +* +* @param +* +* @param +* +* @param +* +* @param +* +* @return None +* +* @note None +* +****************************************************************************/ +inline void MD5Update( MD5Context *context, u8 *buffer, + u32 len, boolean doByteSwap ) +{ + register u32 temp; + register u8 * p; + + /* + * Update bitcount + */ + + temp = context->bits[ 0 ]; + + if( ( context->bits[ 0 ] = temp + ( (u32)len << 3 ) ) < temp ) { + /* + * Carry from low to high + */ + context->bits[ 1 ]++; + } + + context->bits[ 1 ] += len >> 29; + + /* + * Bytes already in shsInfo->data + */ + + temp = ( temp >> 3 ) & 0x3f; + + /* + * Handle any leading odd-sized chunks + */ + + if( temp ) { + p = (u8 *)context->intermediate + temp; + + temp = MD5_SIGNATURE_BYTE_SIZE - temp; + + if( len < temp ) { + MD5Memcpy( p, buffer, len, doByteSwap ); + return; + } + + MD5Memcpy( p, buffer, temp, doByteSwap ); + + MD5Transform( context->buffer, (u32 *)context->intermediate ); + + buffer += temp; + len -= temp; + + } + + /* + * Process data in 64-byte, 512 bit, chunks + */ + + while( len >= MD5_SIGNATURE_BYTE_SIZE ) { + MD5Memcpy( context->intermediate, buffer, MD5_SIGNATURE_BYTE_SIZE, + doByteSwap ); + + MD5Transform( context->buffer, (u32 *)context->intermediate ); + + buffer += MD5_SIGNATURE_BYTE_SIZE; + len -= MD5_SIGNATURE_BYTE_SIZE; + + } + + /* + * Handle any remaining bytes of data + */ + MD5Memcpy( context->intermediate, buffer, len, doByteSwap ); + +} + +/******************************************************************************/ +/** +* +* This function final wrap-up - pad to 64-byte boundary with the bit pattern +* 1 0* (64-bit count of bits processed, MSB-first +* +* @param +* +* @param +* +* @param +* +* @param +* +* @return None +* +* @note None +* +****************************************************************************/ +inline void MD5Final( MD5Context *context, u8 *digest, + boolean doByteSwap ) +{ + u32 count; + u8 * p; + + /* + * Compute number of bytes mod 64 + */ + count = ( context->bits[ 0 ] >> 3 ) & 0x3F; + + /* + * Set the first char of padding to 0x80. This is safe since there is + * always at least one byte free + */ + p = context->intermediate + count; + *p++ = 0x80; + + /* + * Bytes of padding needed to make 64 bytes + */ + count = MD5_SIGNATURE_BYTE_SIZE - 1 - count; + + /* + * Pad out to 56 mod 64 + */ + if( count < 8 ) { + /* + * Two lots of padding: Pad the first block to 64 bytes + */ + MD5Memset( p, 0, count ); + + MD5Transform( context->buffer, (u32 *)context->intermediate ); + + /* + * Now fill the next block with 56 bytes + */ + MD5Memset( context->intermediate, 0, 56 ); + } else { + /* + * Pad block to 56 bytes + */ + MD5Memset( p, 0, count - 8 ); + } + + /* + * Append length in bits and transform + */ + ( (u32 *)context->intermediate )[ 14 ] = context->bits[ 0 ]; + ( (u32 *)context->intermediate )[ 15 ] = context->bits[ 1 ]; + + MD5Transform( context->buffer, (u32 *)context->intermediate ); + + /* + * Now return the digest + */ + MD5Memcpy( digest, context->buffer, 16, doByteSwap ); +} + +/******************************************************************************/ +/** +* +* This function calculate and store in 'digest' the MD5 digest of 'len' bytes at +* 'input'. 'digest' must have enough space to hold 16 bytes +* +* @param +* +* @param +* +* @param +* +* @param +* +* @return None +* +* @note None +* +****************************************************************************/ +void md5( u8 *input, u32 len, u8 *digest, boolean doByteSwap ) +{ + MD5Context context; + + MD5Init( &context ); + + MD5Update( &context, input, len, doByteSwap ); + + MD5Final( &context, digest, doByteSwap ); +} diff --git a/sdk/fsbl/src/md5.h b/sdk/fsbl/src/md5.h new file mode 100644 index 0000000..1b28ddd --- /dev/null +++ b/sdk/fsbl/src/md5.h @@ -0,0 +1,120 @@ +/****************************************************************************** +* +* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file md5.h +* +* +*
+* MODIFICATION HISTORY:
+*
+* Ver	Who	Date		Changes
+* ----- ---- -------- -------------------------------------------------------
+* 5.00a sgd	05/17/13 Initial release
+*
+* 
+* +* @note +* +******************************************************************************/ +#ifndef ___MD5_H___ +#define ___MD5_H___ + + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xil_types.h" + +/************************** Constant Definitions *****************************/ + +#define MD5_SIGNATURE_BYTE_SIZE 64 + +/**************************** Type Definitions *******************************/ + +typedef u8 boolean; +typedef u8 signature[ MD5_SIGNATURE_BYTE_SIZE ]; + +struct MD5Context + { + u32 buffer[ 4 ]; + u32 bits[ 2 ]; + signature intermediate; + }; +typedef struct MD5Context MD5Context; + +/***************** Macros (Inline Functions) Definitions *********************/ + +/* + * The four core functions - F1 is optimized somewhat + */ +#define F1( x, y, z ) ( z ^ ( x & ( y ^ z ) ) ) +#define F2( x, y, z ) F1( z, x, y ) +#define F3( x, y, z ) ( x ^ y ^ z ) +#define F4( x, y, z ) ( y ^ ( x | ~z ) ) + + +/* + * This is the central step in the MD5 algorithm + */ +#define MD5_STEP( f, w, x, y, z, data, s ) \ + ( w += f( x, y, z ) + data, w = w << s | w >> ( 32 - s ), w += x ) + + +/************************** Function Prototypes ******************************/ + +void * MD5Memset( void *dest, int ch, u32 count ); + +void * MD5Memcpy( void *dest, const void *src, u32 count, boolean doByteSwap ); + +void MD5Transform( u32 *buffer, u32 *intermediate ); + +void MD5Init( MD5Context *context ); + +void MD5Update( MD5Context *context, u8 *buffer, u32 len, boolean doByteSwap ); + +void MD5Final( MD5Context *context, u8 *digest, boolean doByteSwap ); + +void md5( u8 *input, u32 len, u8 *digest, boolean doByteSwap ); + +/************************** Variable Definitions *****************************/ + +#ifdef __cplusplus +} +#endif + + +#endif /* ___MD5_H___ */ diff --git a/sdk/fsbl/src/nand.c b/sdk/fsbl/src/nand.c new file mode 100644 index 0000000..9bf4ec0 --- /dev/null +++ b/sdk/fsbl/src/nand.c @@ -0,0 +1,295 @@ +/****************************************************************************** +* +* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file nand.c +* +* Contains code for the NAND FLASH functionality. Bad Block management +* is simple: skip the bad blocks and keep going. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver	Who	Date		Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a ecm	01/10/10 Initial release
+* 2.00a  mb	25/05/12 fsbl changes for standalone bsp based
+* 3.00a sgd	30/01/13 Code cleanup
+* 5.00a sgd	17/05/13 Support for Multi Boot
+* 
+* +* @note +* +******************************************************************************/ + +/***************************** Include Files *********************************/ +#include "xparameters.h" +#include "fsbl.h" +#ifdef XPAR_PS7_NAND_0_BASEADDR +#include "nand.h" +#include "xnandps_bbm.h" + + +/************************** Constant Definitions *****************************/ + +#define NAND_DEVICE_ID XPAR_XNANDPS_0_DEVICE_ID + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ +static u32 XNandPs_CalculateLength(XNandPs *NandInstPtr, + u64 Offset, + u32 Length); + +/************************** Variable Definitions *****************************/ + +extern u32 FlashReadBaseAddress; +extern u32 FlashOffsetAddress; + +XNandPs *NandInstPtr; +XNandPs NandInstance; /* XNand Instance. */ + +/******************************************************************************/ +/** +* +* This function initializes the controller for the NAND FLASH interface. +* +* @param none +* +* @return +* - XST_SUCCESS if the controller initializes correctly +* - XST_FAILURE if the controller fails to initializes correctly +* +* @note none. +* +****************************************************************************/ +u32 InitNand(void) +{ + + u32 Status; + XNandPs_Config *ConfigPtr; + + /* + * Set up pointers to instance and the config structure + */ + NandInstPtr = &NandInstance; + + /* + * Initialize the flash driver. + */ + ConfigPtr = XNandPs_LookupConfig(NAND_DEVICE_ID); + + if (ConfigPtr == NULL) { + fsbl_printf(DEBUG_GENERAL,"Nand Driver failed \n \r"); + return XST_FAILURE; + } + + Status = XNandPs_CfgInitialize(NandInstPtr, ConfigPtr, + ConfigPtr->SmcBase,ConfigPtr->FlashBase); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL,"NAND intialization failed \n \r"); + return XST_FAILURE; + } + + /* + * Set up base address for access + */ + FlashReadBaseAddress = XPS_NAND_BASEADDR; + + fsbl_printf(DEBUG_INFO,"InitNand: Geometry = 0x%x\r\n", + NandInstPtr->Geometry.FlashWidth); + + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_GENERAL,"InitNand: Status = 0x%.8x\r\n", + Status); + return XST_FAILURE; + } + + /* + * set up the FLASH access pointers + */ + fsbl_printf(DEBUG_INFO,"Nand driver initialized \n\r"); + + return XST_SUCCESS; +} + +/******************************************************************************/ +/** +* +* This function provides the NAND FLASH interface for the Simplified header +* functionality. This function handles bad blocks. +* +* The source address is the absolute good address, bad blocks are skipped +* without incrementing the source address. +* +* @param SourceAddress is address in FLASH data space, absolute good address +* @param DestinationAddress is address in OCM data space +* +* @return XST_SUCCESS if the transfer completes correctly +* XST_FAILURE if the transfer fails to completes correctly +* +* @note none. +* +****************************************************************************/ +u32 NandAccess(u32 SourceAddress, u32 DestinationAddress, u32 LengthBytes) +{ + u32 ActLen; + u32 BlockOffset; + u32 Block; + u32 Status; + u32 BytesLeft = LengthBytes; + u32 BlockSize = NandInstPtr->Geometry.BlockSize; + u8 *BufPtr = (u8 *)DestinationAddress; + u32 ReadLen; + u32 BlockReadLen; + u32 Offset; + u32 TmpAddress = 0 ; + u32 BlockCount = 0; + u32 BadBlocks = 0; + + /* + * First get bad blocks before the source address + */ + while (TmpAddress < SourceAddress) { + while (XNandPs_IsBlockBad(NandInstPtr, BlockCount) == + XST_SUCCESS) { + BlockCount ++; + BadBlocks ++; + } + + TmpAddress += BlockSize; + BlockCount ++; + } + + Offset = SourceAddress + BadBlocks * BlockSize; + + /* + * Calculate the actual length including bad blocks + */ + ActLen = XNandPs_CalculateLength(NandInstPtr, Offset, LengthBytes); + + /* + * Check if the actual length cross flash size + */ + if (Offset + ActLen > NandInstPtr->Geometry.DeviceSize) { + return XST_FAILURE; + } + + while (BytesLeft > 0) { + BlockOffset = Offset & (BlockSize - 1); + Block = (Offset & ~(BlockSize - 1))/BlockSize; + BlockReadLen = BlockSize - BlockOffset; + + Status = XNandPs_IsBlockBad(NandInstPtr, Block); + if (Status == XST_SUCCESS) { + /* Move to next block */ + Offset += BlockReadLen; + continue; + } + + /* + * Check if we cross block boundary + */ + if (BytesLeft < BlockReadLen) { + ReadLen = BytesLeft; + } else { + ReadLen = BlockReadLen; + } + + /* + * Read from the NAND flash + */ + Status = XNandPs_Read(NandInstPtr, Offset, ReadLen, BufPtr, NULL); + if (Status != XST_SUCCESS) { + return Status; + } + BytesLeft -= ReadLen; + Offset += ReadLen; + BufPtr += ReadLen; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function returns the length including bad blocks from a given offset and +* length. +* +* @param NandInstPtr is the pointer to the XNandPs instance. +* @param Offset is the flash data address to read from. +* @param Length is number of bytes to read. +* +* @return +* - Return actual length including bad blocks. +* +* @note None. +* +******************************************************************************/ +static u32 XNandPs_CalculateLength(XNandPs *NandInstPtr, + u64 Offset, + u32 Length) +{ + u32 BlockSize = NandInstPtr->Geometry.BlockSize; + u32 CurBlockLen; + u32 CurBlock; + u32 Status; + u32 TempLen = 0; + u32 ActLen = 0; + + while (TempLen < Length) { + CurBlockLen = BlockSize - (Offset & (BlockSize - 1)); + CurBlock = (Offset & ~(BlockSize - 1))/BlockSize; + + /* + * Check if the block is bad + */ + Status = XNandPs_IsBlockBad(NandInstPtr, CurBlock); + if (Status != XST_SUCCESS) { + /* Good Block */ + TempLen += CurBlockLen; + } + ActLen += CurBlockLen; + Offset += CurBlockLen; + if (Offset >= NandInstPtr->Geometry.DeviceSize) { + break; + } + } + + return ActLen; +} + +#endif diff --git a/sdk/fsbl/src/nand.h b/sdk/fsbl/src/nand.h new file mode 100644 index 0000000..1f5ee52 --- /dev/null +++ b/sdk/fsbl/src/nand.h @@ -0,0 +1,91 @@ +/****************************************************************************** +* +* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file nand.h +* +* This file contains the interface for the NAND FLASH functionality +* +*
+* MODIFICATION HISTORY:
+*
+* Ver	Who	Date		Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a ecm	01/10/10 Initial release
+* 2.00a mb	30/05/12 added the flag XPAR_PS7_NAND_0_BASEADDR
+* 10.00a kc 08/04/14 Fix for CR#809336 - Removed smc.h
+* 
+* +* @note +* +******************************************************************************/ +#ifndef ___NAND_H___ +#define ___NAND_H___ + + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + + +#ifdef XPAR_PS7_NAND_0_BASEADDR + +#include "xnandps.h" +#include "xnandps_bbm.h" +/**************************** Type Definitions *******************************/ + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ +u32 InitNand(void); + +u32 NandAccess( u32 SourceAddress, + u32 DestinationAddress, + u32 LengthWords); +#endif +/************************** Variable Definitions *****************************/ + + +#ifdef __cplusplus +} +#endif + + +#endif /* ___NAND_H___ */ + diff --git a/sdk/fsbl/src/nor.c b/sdk/fsbl/src/nor.c new file mode 100644 index 0000000..4705bcc --- /dev/null +++ b/sdk/fsbl/src/nor.c @@ -0,0 +1,144 @@ +/****************************************************************************** +* +* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file nor.c +* +* Contains code for the NOR FLASH functionality. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver	Who	Date		Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a ecm	01/10/10 Initial release
+* 2.00a mb	25/05/12 mio init removed
+* 3.00a sgd	30/01/13 Code cleanup
+*
+* 
+* +* @note +* +******************************************************************************/ + +/***************************** Include Files *********************************/ +#include "fsbl.h" +#include "nor.h" +#include "xstatus.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +/************************** Variable Definitions *****************************/ + +extern u32 FlashReadBaseAddress; + +/******************************************************************************/ +/******************************************************************************/ +/** +* +* This function initializes the controller for the NOR FLASH interface. +* +* @param None +* +* @return None +* +* @note None. +* +****************************************************************************/ +void InitNor(void) +{ + + /* + * Set up the base address for access + */ + FlashReadBaseAddress = XPS_NOR_BASEADDR; +} + +/******************************************************************************/ +/** +* +* This function provides the NOR FLASH interface for the Simplified header +* functionality. +* +* @param SourceAddress is address in FLASH data space +* @param DestinationAddress is address in OCM data space +* @param LengthBytes is the data length to transfer in bytes +* +* @return +* - XST_SUCCESS if the write completes correctly +* - XST_FAILURE if the write fails to completes correctly +* +* @note None. +* +****************************************************************************/ +u32 NorAccess(u32 SourceAddress, u32 DestinationAddress, u32 LengthBytes) +{ + u32 Data; + u32 Count; + u32 *SourceAddr; + u32 *DestAddr; + u32 LengthWords; + + /* + * check for non-word tail + * add bytes to cover the end + */ + if ((LengthBytes%4) != 0){ + + LengthBytes += (4 - (LengthBytes & 0x00000003)); + } + + LengthWords = LengthBytes >> WORD_LENGTH_SHIFT; + + SourceAddr = (u32 *)(SourceAddress + FlashReadBaseAddress); + DestAddr = (u32 *)(DestinationAddress); + + /* + * Word transfers, endianism isn't an issue + */ + for (Count=0; Count < LengthWords; Count++){ + + Data = Xil_In32((u32)(SourceAddr++)); + Xil_Out32((u32)(DestAddr++), Data); + } + + return XST_SUCCESS; +} + diff --git a/sdk/fsbl/src/nor.h b/sdk/fsbl/src/nor.h new file mode 100644 index 0000000..4c15825 --- /dev/null +++ b/sdk/fsbl/src/nor.h @@ -0,0 +1,87 @@ +/****************************************************************************** +* +* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file nor.h +* +* This file contains the interface for the NOR FLASH functionality +* +*
+* MODIFICATION HISTORY:
+*
+* Ver	Who	Date		Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a ecm	01/10/10 Initial release
+* 10.00a kc 08/04/14 Fix for CR#809336 - Removed smc.h
+*
+* 
+* +* @note +* +******************************************************************************/ +#ifndef ___NOR_H___ +#define ___NOR_H___ + + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +/************************** Constant Definitions *****************************/ + +#define XPS_NOR_BASEADDR XPS_PARPORT0_BASEADDR + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + + +void InitNor(void); + +u32 NorAccess( u32 SourceAddress, + u32 DestinationAddress, + u32 LengthBytes); + +/************************** Variable Definitions *****************************/ +#ifdef __cplusplus +} +#endif + + +#endif /* ___NOR_H___ */ + diff --git a/sdk/fsbl/src/pcap.c b/sdk/fsbl/src/pcap.c new file mode 100644 index 0000000..40351c8 --- /dev/null +++ b/sdk/fsbl/src/pcap.c @@ -0,0 +1,816 @@ +/***************************************************************************** +* +* Copyright (C) 2012 - 2016 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file pcap.c +* +* Contains code for enabling and accessing the PCAP +* +*
+* MODIFICATION HISTORY:
+*
+* Ver	Who	Date		Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a ecm	02/10/10	Initial release
+* 2.00a jz	05/28/11	Add SD support
+* 2.00a mb	25/05/12	using the EDK provided devcfg driver
+* 						Nand/SD encryption and review comments
+* 3.00a mb  16/08/12	Added the poll function
+*						Removed the FPGA_RST_CTRL define
+*						Added the flag for NON PS instantiated bitstream
+* 4.00a sgd 02/28/13	Fix for CR#681014 - ECC init in FSBL should not call
+*                                           fabric_init()
+* 						Fix for CR#689026 - FSBL doesn't hold PL resets active
+* 						                    during bit download
+* 						Fix for CR#699475 - FSBL functionality is broken and
+* 						                    its not able to boot in QSPI/NAND
+* 						                    bootmode
+*						Fix for CR#705664 - FSBL fails to decrypt the
+*						                    bitstream when the image is AES
+*						                    encrypted using non-zero key value
+* 6.00a kc  08/30/13    Fix for CR#722979 - Provide customer-friendly
+*                                           changelogs in FSBL
+* 7.00a kc	10/25/13	Fix for CR#724620 - How to handle PCAP_MODE after
+*						                    bitstream configuration
+*						Fix for CR#726178 - FabricInit() PROG_B is kept active
+*						                    for 5mS.
+* 						Fix for CR#731839 - FSBL has to check the
+* 											HMAC error status after decryption
+*			12/04/13	Fix for CR#764382 - How to handle PCAP_MODE after
+*						                    bitstream configuration - PCAP_MODE
+*											and PCAP_PR bits are not modified
+* 8.00a kc  2/20/14		Fix for CR#775631 - FSBL: FsblGetGlobalTimer() 
+*						is not proper
+* 10.00a kc 07/24/14    Fix for CR#809336 - Minor code cleanup
+* 13.00a ssc 04/10/15   Fix for CR#846899 - Corrected logic to clear
+*                                           DMA done count
+* 15.00a gan 07/21/16   Fix for CR# 953654 -(2016.3)FSBL -
+* 											In pcap.c/pcap.h/main.h,
+* 											Fabric Initialization sequence
+* 											is modified to check the PL power
+* 											before sequence starts and checking
+* 											INIT_B reset status twice in case
+* 											of failure.
+* 16.00a gan 08/02/16   Fix for CR# 955897 -(2016.3)FSBL -
+* 											In pcap.c, check pl power
+* 											through MCTRL register for
+* 											3.0 and later versions of silicon.
+* 
+* +* @note +* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "pcap.h" +#include "nand.h" /* For NAND geometry information */ +#include "fsbl.h" +#include "image_mover.h" /* For MoveImage */ +#include "xparameters.h" +#include "xil_exception.h" +#include "xdevcfg.h" +#include "sleep.h" +#include "xtime_l.h" + +#ifdef XPAR_XWDTPS_0_BASEADDR +#include "xwdtps.h" +#endif +/************************** Constant Definitions *****************************/ +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are only defined here such that a user can easily + * change all the needed parameters in one place. + */ + +#define DCFG_DEVICE_ID XPAR_XDCFG_0_DEVICE_ID + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ +extern int XDcfgPollDone(u32 MaskValue, u32 MaxCount); + +/************************** Variable Definitions *****************************/ +/* Devcfg driver instance */ +static XDcfg DcfgInstance; +XDcfg *DcfgInstPtr; +extern u32 Silicon_Version; +#ifdef XPAR_XWDTPS_0_BASEADDR +extern XWdtPs Watchdog; /* Instance of WatchDog Timer */ +#endif + +/******************************************************************************/ +/** +* +* This function transfer data using PCAP +* +* @param SourceDataPtr is a pointer to where the data is read from +* @param DestinationDataPtr is a pointer to where the data is written to +* @param SourceLength is the length of the data to be moved in words +* @param DestinationLength is the length of the data to be moved in words +* @param SecureTransfer indicated the encryption key location, 0 for +* non-encrypted +* +* @return +* - XST_SUCCESS if the transfer is successful +* - XST_FAILURE if the transfer fails +* +* @note None +* +****************************************************************************/ +u32 PcapDataTransfer(u32 *SourceDataPtr, u32 *DestinationDataPtr, + u32 SourceLength, u32 DestinationLength, u32 SecureTransfer) +{ + u32 Status; + u32 IntrStsReg; + u32 PcapTransferType = XDCFG_CONCURRENT_NONSEC_READ_WRITE; + + /* + * Check for secure transfer + */ + if (SecureTransfer) { + PcapTransferType = XDCFG_CONCURRENT_SECURE_READ_WRITE; + } + +#ifdef FSBL_PERF + XTime tXferCur = 0; + FsblGetGlobalTime(&tXferCur); +#endif + + /* + * Clear the PCAP status registers + */ + Status = ClearPcapStatus(); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_INFO,"PCAP_CLEAR_STATUS_FAIL \r\n"); + return XST_FAILURE; + } + +#ifdef XPAR_XWDTPS_0_BASEADDR + /* + * Prevent WDT reset + */ + XWdtPs_RestartWdt(&Watchdog); +#endif + + /* + * PCAP single DMA transfer setup + */ + SourceDataPtr = (u32*)((u32)SourceDataPtr | PCAP_LAST_TRANSFER); + DestinationDataPtr = (u32*)((u32)DestinationDataPtr | PCAP_LAST_TRANSFER); + + /* + * Transfer using Device Configuration + */ + Status = XDcfg_Transfer(DcfgInstPtr, (u8 *)SourceDataPtr, + SourceLength, + (u8 *)DestinationDataPtr, + DestinationLength, PcapTransferType); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_INFO,"Status of XDcfg_Transfer = %lu \r \n",Status); + return XST_FAILURE; + } + + /* + * Dump the PCAP registers + */ + PcapDumpRegisters(); + + /* + * Poll for the DMA done + */ + Status = XDcfgPollDone(XDCFG_IXR_DMA_DONE_MASK, MAX_COUNT); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_INFO,"PCAP_DMA_DONE_FAIL \r\n"); + return XST_FAILURE; + } + + fsbl_printf(DEBUG_INFO,"DMA Done ! \n\r"); + + /* + * Check for errors + */ + IntrStsReg = XDcfg_IntrGetStatus(DcfgInstPtr); + if (IntrStsReg & FSBL_XDCFG_IXR_ERROR_FLAGS_MASK) { + fsbl_printf(DEBUG_INFO,"Errors in PCAP \r\n"); + return XST_FAILURE; + } + + /* + * For Performance measurement + */ +#ifdef FSBL_PERF + XTime tXferEnd = 0; + fsbl_printf(DEBUG_GENERAL,"Time taken is "); + FsblMeasurePerfTime(tXferCur,tXferEnd); +#endif + + return XST_SUCCESS; +} + + +/******************************************************************************/ +/** +* +* This function loads PL partition using PCAP +* +* @param SourceDataPtr is a pointer to where the data is read from +* @param DestinationDataPtr is a pointer to where the data is written to +* @param SourceLength is the length of the data to be moved in words +* @param DestinationLength is the length of the data to be moved in words +* @param SecureTransfer indicated the encryption key location, 0 for +* non-encrypted +* +* @return +* - XST_SUCCESS if the transfer is successful +* - XST_FAILURE if the transfer fails +* +* @note None +* +****************************************************************************/ +u32 PcapLoadPartition(u32 *SourceDataPtr, u32 *DestinationDataPtr, + u32 SourceLength, u32 DestinationLength, u32 SecureTransfer) +{ + u32 Status; + u32 IntrStsReg; + u32 PcapTransferType = XDCFG_NON_SECURE_PCAP_WRITE; + + /* + * Check for secure transfer + */ + if (SecureTransfer) { + PcapTransferType = XDCFG_SECURE_PCAP_WRITE; + } + +#ifdef FSBL_PERF + XTime tXferCur = 0; + FsblGetGlobalTime(&tXferCur); +#endif + + /* + * Clear the PCAP status registers + */ + Status = ClearPcapStatus(); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_INFO,"PCAP_CLEAR_STATUS_FAIL \r\n"); + return XST_FAILURE; + } + + /* + * For Bitstream case destination address will be 0xFFFFFFFF + */ + DestinationDataPtr = (u32*)XDCFG_DMA_INVALID_ADDRESS; + + /* + * New Bitstream download initialization sequence + */ + Status = FabricInit(); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + +#ifdef XPAR_XWDTPS_0_BASEADDR + /* + * Prevent WDT reset + */ + XWdtPs_RestartWdt(&Watchdog); +#endif + + /* + * PCAP single DMA transfer setup + */ + SourceDataPtr = (u32*)((u32)SourceDataPtr | PCAP_LAST_TRANSFER); + DestinationDataPtr = (u32*)((u32)DestinationDataPtr | PCAP_LAST_TRANSFER); + + /* + * Transfer using Device Configuration + */ + Status = XDcfg_Transfer(DcfgInstPtr, (u8 *)SourceDataPtr, + SourceLength, + (u8 *)DestinationDataPtr, + DestinationLength, PcapTransferType); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_INFO,"Status of XDcfg_Transfer = %lu \r \n",Status); + return XST_FAILURE; + } + + + /* + * Dump the PCAP registers + */ + PcapDumpRegisters(); + + + /* + * Poll for the DMA done + */ + Status = XDcfgPollDone(XDCFG_IXR_DMA_DONE_MASK, MAX_COUNT); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_INFO,"PCAP_DMA_DONE_FAIL \r\n"); + return XST_FAILURE; + } + + fsbl_printf(DEBUG_INFO,"DMA Done ! \n\r"); + + /* + * Poll for FPGA Done + */ + Status = XDcfgPollDone(XDCFG_IXR_PCFG_DONE_MASK, MAX_COUNT); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_INFO,"PCAP_FPGA_DONE_FAIL\r\n"); + return XST_FAILURE; + } + + fsbl_printf(DEBUG_INFO,"FPGA Done ! \n\r"); + + /* + * Check for errors + */ + IntrStsReg = XDcfg_IntrGetStatus(DcfgInstPtr); + if (IntrStsReg & FSBL_XDCFG_IXR_ERROR_FLAGS_MASK) { + fsbl_printf(DEBUG_INFO,"Errors in PCAP \r\n"); + return XST_FAILURE; + } + + /* + * For Performance measurement + */ +#ifdef FSBL_PERF + XTime tXferEnd = 0; + fsbl_printf(DEBUG_GENERAL,"Time taken is "); + FsblMeasurePerfTime(tXferCur,tXferEnd); +#endif + + return XST_SUCCESS; +} + +/******************************************************************************/ +/** +* +* This function Initializes the PCAP driver. +* +* @param none +* +* @return +* - XST_SUCCESS if the pcap driver initialization is successful +* - XST_FAILURE if the pcap driver initialization fails +* +* @note none +* +****************************************************************************/ +int InitPcap(void) +{ + XDcfg_Config *ConfigPtr; + int Status = XST_SUCCESS; + DcfgInstPtr = &DcfgInstance; + + /* + * Initialize the Device Configuration Interface driver. + */ + ConfigPtr = XDcfg_LookupConfig(DCFG_DEVICE_ID); + + Status = XDcfg_CfgInitialize(DcfgInstPtr, ConfigPtr, + ConfigPtr->BaseAddr); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_INFO, "XDcfg_CfgInitialize failed \n\r"); + return XST_FAILURE; + } + + return XST_SUCCESS; +} +/******************************************************************************/ +/** +* +* This function programs the Fabric for use. +* +* @param None +* +* @return +* - XST_SUCCESS if the Fabric initialization is successful +* - XST_FAILURE if the Fabric initialization fails +* @note None +* +****************************************************************************/ +u32 FabricInit(void) +{ + u32 PcapReg; + u32 PcapCtrlRegVal; + u32 StatusReg; + u32 MctrlReg; + u32 PcfgInit; + u32 TimerExpired=0; + XTime tCur=0; + XTime tEnd=0; + + + /* + * Set Level Shifters DT618760 - PS to PL enabling + */ + Xil_Out32(PS_LVL_SHFTR_EN, LVL_PS_PL); + fsbl_printf(DEBUG_INFO,"Level Shifter Value = 0x%lx \r\n", + Xil_In32(PS_LVL_SHFTR_EN)); + + /* + * Get DEVCFG controller settings + */ + PcapReg = XDcfg_ReadReg(DcfgInstPtr->Config.BaseAddr, + XDCFG_CTRL_OFFSET); + + /* + * Check the PL power status + */ + if(Silicon_Version >= SILICON_VERSION_3) + { + MctrlReg = XDcfg_GetMiscControlRegister(DcfgInstPtr); + + if((MctrlReg & XDCFG_MCTRL_PCAP_PCFG_POR_B_MASK) != + XDCFG_MCTRL_PCAP_PCFG_POR_B_MASK) + { + fsbl_printf(DEBUG_INFO,"Fabric not powered up\r\n"); + return XST_FAILURE; + } + } + + + /* + * Setting PCFG_PROG_B signal to high + */ + XDcfg_WriteReg(DcfgInstPtr->Config.BaseAddr, XDCFG_CTRL_OFFSET, + (PcapReg | XDCFG_CTRL_PCFG_PROG_B_MASK)); + + /* + * Check for AES source key + */ + PcapCtrlRegVal = XDcfg_GetControlRegister(DcfgInstPtr); + if (PcapCtrlRegVal & XDCFG_CTRL_PCFG_AES_FUSE_MASK) { + /* + * 5msec delay + */ + usleep(5000); + } + + /* + * Setting PCFG_PROG_B signal to low + */ + XDcfg_WriteReg(DcfgInstPtr->Config.BaseAddr, XDCFG_CTRL_OFFSET, + (PcapReg & ~XDCFG_CTRL_PCFG_PROG_B_MASK)); + + /* + * Check for AES source key + */ + if (PcapCtrlRegVal & XDCFG_CTRL_PCFG_AES_FUSE_MASK) { + /* + * 5msec delay + */ + usleep(5000); + } + + /* + * Polling the PCAP_INIT status for Reset or timeout + */ + + XTime_GetTime(&tCur); + do + { + PcfgInit = (XDcfg_GetStatusRegister(DcfgInstPtr) & + XDCFG_STATUS_PCFG_INIT_MASK); + if(PcfgInit == 0) + { + break; + } + XTime_GetTime(&tEnd); + if((u64)((u64)tCur + (COUNTS_PER_MILLI_SECOND*30)) > (u64)tEnd) + { + TimerExpired = 1; + } + + } while(!TimerExpired); + + if(TimerExpired == 1) + { + TimerExpired = 0; + /* + * Came here due to expiration and PCAP_INIT is set. + * Retry PCFG_PROG_B High -> Low again + */ + + /* + * Setting PCFG_PROG_B signal to high + */ + XDcfg_WriteReg(DcfgInstPtr->Config.BaseAddr, XDCFG_CTRL_OFFSET, + (PcapReg | XDCFG_CTRL_PCFG_PROG_B_MASK)); + + /* + * Check for AES source key + */ + PcapCtrlRegVal = XDcfg_GetControlRegister(DcfgInstPtr); + if (PcapCtrlRegVal & XDCFG_CTRL_PCFG_AES_FUSE_MASK) { + /* + * 5msec delay + */ + usleep(5000); + } + + /* + * Setting PCFG_PROG_B signal to low + */ + XDcfg_WriteReg(DcfgInstPtr->Config.BaseAddr, XDCFG_CTRL_OFFSET, + (PcapReg & ~XDCFG_CTRL_PCFG_PROG_B_MASK)); + + /* + * Check for AES source key + */ + if (PcapCtrlRegVal & XDCFG_CTRL_PCFG_AES_FUSE_MASK) { + /* + * 5msec delay + */ + usleep(5000); + } + /* + * Polling the PCAP_INIT status for Reset or timeout (second iteration) + */ + + XTime_GetTime(&tCur); + do + { + PcfgInit = (XDcfg_GetStatusRegister(DcfgInstPtr) & + XDCFG_STATUS_PCFG_INIT_MASK); + if(PcfgInit == 0) + { + break; + } + XTime_GetTime(&tEnd); + if((u64)((u64)tCur + (COUNTS_PER_MILLI_SECOND*30)) > (u64)tEnd) + { + TimerExpired = 1; + } + + } while(!TimerExpired); + + if(TimerExpired == 1) + { + /* + * Came here due to PCAP_INIT is not getting reset + * for PCFG_PROG_B signal High -> Low + */ + fsbl_printf(DEBUG_INFO,"Fabric Init failed\r\n"); + return XST_FAILURE; + } + } + + /* + * Setting PCFG_PROG_B signal to high + */ + XDcfg_WriteReg(DcfgInstPtr->Config.BaseAddr, XDCFG_CTRL_OFFSET, + (PcapReg | XDCFG_CTRL_PCFG_PROG_B_MASK)); + + /* + * Polling the PCAP_INIT status for Set + */ + while(!(XDcfg_GetStatusRegister(DcfgInstPtr) & + XDCFG_STATUS_PCFG_INIT_MASK)); + + /* + * Get Device configuration status + */ + StatusReg = XDcfg_GetStatusRegister(DcfgInstPtr); + fsbl_printf(DEBUG_INFO,"Devcfg Status register = 0x%lx \r\n",StatusReg); + + fsbl_printf(DEBUG_INFO,"PCAP:Fabric is Initialized done\r\n"); + + return XST_SUCCESS; +} +/******************************************************************************/ +/** +* +* This function Clears the PCAP status registers. +* +* @param None +* +* @return +* - XST_SUCCESS if the pcap status registers are cleared +* - XST_FAILURE if errors are there +* - XST_DEVICE_BUSY if Pcap device is busy +* @note None +* +****************************************************************************/ +u32 ClearPcapStatus(void) +{ + + u32 StatusReg; + u32 IntStatusReg; + + /* + * Clear it all, so if Boot ROM comes back, it can proceed + */ + XDcfg_IntrClear(DcfgInstPtr, 0xFFFFFFFF); + + /* + * Get PCAP Interrupt Status Register + */ + IntStatusReg = XDcfg_IntrGetStatus(DcfgInstPtr); + if (IntStatusReg & FSBL_XDCFG_IXR_ERROR_FLAGS_MASK) { + fsbl_printf(DEBUG_INFO,"FATAL errors in PCAP %lx\r\n", + IntStatusReg); + return XST_FAILURE; + } + + /* + * Read the PCAP status register for DMA status + */ + StatusReg = XDcfg_GetStatusRegister(DcfgInstPtr); + + fsbl_printf(DEBUG_INFO,"PCAP:StatusReg = 0x%.8lx\r\n", StatusReg); + + /* + * If the queue is full, return w/ XST_DEVICE_BUSY + */ + if ((StatusReg & XDCFG_STATUS_DMA_CMD_Q_F_MASK) == + XDCFG_STATUS_DMA_CMD_Q_F_MASK) { + + fsbl_printf(DEBUG_INFO,"PCAP_DEVICE_BUSY\r\n"); + return XST_DEVICE_BUSY; + } + + fsbl_printf(DEBUG_INFO,"PCAP:device ready\r\n"); + + /* + * There are unacknowledged DMA commands outstanding + */ + if ((StatusReg & XDCFG_STATUS_DMA_CMD_Q_E_MASK) != + XDCFG_STATUS_DMA_CMD_Q_E_MASK) { + + IntStatusReg = XDcfg_IntrGetStatus(DcfgInstPtr); + + if ((IntStatusReg & XDCFG_IXR_DMA_DONE_MASK) != + XDCFG_IXR_DMA_DONE_MASK){ + /* + * Error state, transfer cannot occur + */ + fsbl_printf(DEBUG_INFO,"PCAP:IntStatus indicates error\r\n"); + return XST_FAILURE; + } + else { + /* + * clear out the status + */ + XDcfg_IntrClear(DcfgInstPtr, XDCFG_IXR_DMA_DONE_MASK); + } + } + + if ((StatusReg & XDCFG_STATUS_DMA_DONE_CNT_MASK) != 0) { + XDcfg_SetStatusRegister(DcfgInstPtr, StatusReg | + XDCFG_STATUS_DMA_DONE_CNT_MASK); + } + + fsbl_printf(DEBUG_INFO,"PCAP:Clear done\r\n"); + + return XST_SUCCESS; +} + +/******************************************************************************/ +/** +* +* This function prints PCAP register status. +* +* @param none +* +* @return none +* +* @note none +* +****************************************************************************/ +void PcapDumpRegisters (void) { + + fsbl_printf(DEBUG_INFO,"PCAP register dump:\r\n"); + + fsbl_printf(DEBUG_INFO,"PCAP CTRL 0x%x: 0x%08lx\r\n", + XPS_DEV_CFG_APB_BASEADDR + XDCFG_CTRL_OFFSET, + Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_CTRL_OFFSET)); + fsbl_printf(DEBUG_INFO,"PCAP LOCK 0x%x: 0x%08lx\r\n", + XPS_DEV_CFG_APB_BASEADDR + XDCFG_LOCK_OFFSET, + Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_LOCK_OFFSET)); + fsbl_printf(DEBUG_INFO,"PCAP CONFIG 0x%x: 0x%08lx\r\n", + XPS_DEV_CFG_APB_BASEADDR + XDCFG_CFG_OFFSET, + Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_CFG_OFFSET)); + fsbl_printf(DEBUG_INFO,"PCAP ISR 0x%x: 0x%08lx\r\n", + XPS_DEV_CFG_APB_BASEADDR + XDCFG_INT_STS_OFFSET, + Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_INT_STS_OFFSET)); + fsbl_printf(DEBUG_INFO,"PCAP IMR 0x%x: 0x%08lx\r\n", + XPS_DEV_CFG_APB_BASEADDR + XDCFG_INT_MASK_OFFSET, + Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_INT_MASK_OFFSET)); + fsbl_printf(DEBUG_INFO,"PCAP STATUS 0x%x: 0x%08lx\r\n", + XPS_DEV_CFG_APB_BASEADDR + XDCFG_STATUS_OFFSET, + Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_STATUS_OFFSET)); + fsbl_printf(DEBUG_INFO,"PCAP DMA SRC ADDR 0x%x: 0x%08lx\r\n", + XPS_DEV_CFG_APB_BASEADDR + XDCFG_DMA_SRC_ADDR_OFFSET, + Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_DMA_SRC_ADDR_OFFSET)); + fsbl_printf(DEBUG_INFO,"PCAP DMA DEST ADDR 0x%x: 0x%08lx\r\n", + XPS_DEV_CFG_APB_BASEADDR + XDCFG_DMA_DEST_ADDR_OFFSET, + Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_DMA_DEST_ADDR_OFFSET)); + fsbl_printf(DEBUG_INFO,"PCAP DMA SRC LEN 0x%x: 0x%08lx\r\n", + XPS_DEV_CFG_APB_BASEADDR + XDCFG_DMA_SRC_LEN_OFFSET, + Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_DMA_SRC_LEN_OFFSET)); + fsbl_printf(DEBUG_INFO,"PCAP DMA DEST LEN 0x%x: 0x%08lx\r\n", + XPS_DEV_CFG_APB_BASEADDR + XDCFG_DMA_DEST_LEN_OFFSET, + Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_DMA_DEST_LEN_OFFSET)); + fsbl_printf(DEBUG_INFO,"PCAP ROM SHADOW CTRL 0x%x: 0x%08lx\r\n", + XPS_DEV_CFG_APB_BASEADDR + XDCFG_ROM_SHADOW_OFFSET, + Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_ROM_SHADOW_OFFSET)); + fsbl_printf(DEBUG_INFO,"PCAP MBOOT 0x%x: 0x%08lx\r\n", + XPS_DEV_CFG_APB_BASEADDR + XDCFG_MULTIBOOT_ADDR_OFFSET, + Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_MULTIBOOT_ADDR_OFFSET)); + fsbl_printf(DEBUG_INFO,"PCAP SW ID 0x%x: 0x%08lx\r\n", + XPS_DEV_CFG_APB_BASEADDR + XDCFG_SW_ID_OFFSET, + Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_SW_ID_OFFSET)); + fsbl_printf(DEBUG_INFO,"PCAP UNLOCK 0x%x: 0x%08lx\r\n", + XPS_DEV_CFG_APB_BASEADDR + XDCFG_UNLOCK_OFFSET, + Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_UNLOCK_OFFSET)); + fsbl_printf(DEBUG_INFO,"PCAP MCTRL 0x%x: 0x%08lx\r\n", + XPS_DEV_CFG_APB_BASEADDR + XDCFG_MCTRL_OFFSET, + Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_MCTRL_OFFSET)); +} + +/******************************************************************************/ +/** +* +* This function Polls for the DMA done or FPGA done. +* +* @param none +* +* @return +* - XST_SUCCESS if polling for DMA/FPGA done is successful +* - XST_FAILURE if polling for DMA/FPGA done fails +* +* @note none +* +****************************************************************************/ +int XDcfgPollDone(u32 MaskValue, u32 MaxCount) +{ + int Count = MaxCount; + u32 IntrStsReg = 0; + + /* + * poll for the DMA done + */ + IntrStsReg = XDcfg_IntrGetStatus(DcfgInstPtr); + while ((IntrStsReg & MaskValue) != + MaskValue) { + IntrStsReg = XDcfg_IntrGetStatus(DcfgInstPtr); + Count -=1; + + if (IntrStsReg & FSBL_XDCFG_IXR_ERROR_FLAGS_MASK) { + fsbl_printf(DEBUG_INFO,"FATAL errors in PCAP %lx\r\n", + IntrStsReg); + PcapDumpRegisters(); + return XST_FAILURE; + } + + if(!Count) { + fsbl_printf(DEBUG_GENERAL,"PCAP transfer timed out \r\n"); + return XST_FAILURE; + } + if (Count > (MAX_COUNT-100)) { + fsbl_printf(DEBUG_GENERAL,"."); + } + } + + fsbl_printf(DEBUG_GENERAL,"\n\r"); + + XDcfg_IntrClear(DcfgInstPtr, IntrStsReg & MaskValue); + + return XST_SUCCESS; +} diff --git a/sdk/fsbl/src/pcap.h b/sdk/fsbl/src/pcap.h new file mode 100644 index 0000000..d9400b0 --- /dev/null +++ b/sdk/fsbl/src/pcap.h @@ -0,0 +1,108 @@ +/****************************************************************************** +* +* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file pcap.h +* +* This file contains the interface for intiializing and accessing the PCAP +* +* +*
+* MODIFICATION HISTORY:
+*
+* Ver	Who	Date		Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a ecm	02/10/10 Initial release
+* 2.00a mb  16/08/12 Added the macros and function prototypes
+* 15.00a gan 07/21/16   953654 -(2016.3)FSBL -In pcap.c/pcap.h/main.c,
+* 						Fabric Initialization sequence is modified to check
+* 						the PL power before sequence starts and checking INIT_B
+* 						reset status twice in case of failure.
+* 
+* +* @note +* +******************************************************************************/ +#ifndef ___PCAP_H___ +#define ___PCAP_H___ + + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ +#include "xdevcfg.h" + +/************************** Function Prototypes ******************************/ + + +/* Multiboot register offset mask */ +#define PCAP_MBOOT_REG_REBOOT_OFFSET_MASK 0x1FFF +#define PCAP_CTRL_PCFG_AES_FUSE_EFUSE_MASK 0x1000 +/*Miscellaneous Control Register mask*/ +#define XDCFG_MCTRL_PCAP_PCFG_POR_B_MASK 0x00000100 +#define COUNTS_PER_MILLI_SECOND (COUNTS_PER_SECOND/1000) + +#define PCAP_LAST_TRANSFER 1 +#define MAX_COUNT 1000000000 +#define LVL_PL_PS 0x0000000F +#define LVL_PS_PL 0x0000000A + +/* Fix for #672779 */ +#define FSBL_XDCFG_IXR_ERROR_FLAGS_MASK (XDCFG_IXR_AXI_WERR_MASK | \ + XDCFG_IXR_AXI_RTO_MASK | \ + XDCFG_IXR_AXI_RERR_MASK | \ + XDCFG_IXR_RX_FIFO_OV_MASK | \ + XDCFG_IXR_DMA_CMD_ERR_MASK |\ + XDCFG_IXR_DMA_Q_OV_MASK | \ + XDCFG_IXR_P2D_LEN_ERR_MASK |\ + XDCFG_IXR_PCFG_HMAC_ERR_MASK) + +int InitPcap(void); +void PcapDumpRegisters(void); +u32 ClearPcapStatus(void); +u32 FabricInit(void); +int XDcfgPollDone(u32 MaskValue, u32 MaxCount); +u32 PcapLoadPartition(u32 *SourceData, u32 *DestinationData, u32 SourceLength, + u32 DestinationLength, u32 Flags); +u32 PcapDataTransfer(u32 *SourceData, u32 *DestinationData, u32 SourceLength, + u32 DestinationLength, u32 Flags); +/************************** Variable Definitions *****************************/ +#ifdef __cplusplus +} +#endif + + +#endif /* ___PCAP_H___ */ + diff --git a/sdk/fsbl/src/ps7_parameters.xml b/sdk/fsbl/src/ps7_parameters.xml new file mode 100644 index 0000000..bc78eb8 --- /dev/null +++ b/sdk/fsbl/src/ps7_parameters.xml @@ -0,0 +1,638 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/fsbl/src/qspi.c b/sdk/fsbl/src/qspi.c new file mode 100644 index 0000000..6fdf055 --- /dev/null +++ b/sdk/fsbl/src/qspi.c @@ -0,0 +1,764 @@ +/****************************************************************************** +* +* Copyright (C) 2012 - 2016 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file qspi.c +* +* Contains code for the QSPI FLASH functionality. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver	Who	Date		Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a ecm	01/10/10 Initial release
+* 3.00a mb  25/06/12 InitQspi, data is read first and required config bits
+*                    are set
+* 4.00a sg	02/28/13 Cleanup
+* 					 Removed LPBK_DLY_ADJ register setting code as we use
+* 					 divisor 8
+* 5.00a sgd	05/17/13 Added Flash Size > 128Mbit support
+* 					 Dual Stack support
+*					 Fix for CR:721674 - FSBL- Failed to boot from Dual
+*					                     stacked QSPI
+* 6.00a kc  08/30/13 Fix for CR#722979 - Provide customer-friendly
+*                                        changelogs in FSBL
+*                    Fix for CR#739711 - FSBL not able to read Large QSPI
+*                    					 (512M) in IO Mode
+* 7.00a kc  10/25/13 Fix for CR#739968 - FSBL should do the QSPI config
+*                    					 settings for Dual parallel
+*                    					 configuration in IO mode
+* 14.0 gan 01/13/16  Fix for CR#869081 - (2016.1)FSBL picks the qspi read
+*                                        command from LQSPI_CFG register
+*					 					 instead of hard coded read
+*					 					 command (0x6B).
+*
+* 
+* +* @note +* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "qspi.h" +#include "image_mover.h" + +#ifdef XPAR_PS7_QSPI_LINEAR_0_S_AXI_BASEADDR +#include "xqspips_hw.h" +#include "xqspips.h" + +/************************** Constant Definitions *****************************/ + +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#define QSPI_DEVICE_ID XPAR_XQSPIPS_0_DEVICE_ID + +/* + * The following constants define the commands which may be sent to the FLASH + * device. + */ +#define QUAD_READ_CMD 0x6B +#define READ_ID_CMD 0x9F + +#define WRITE_ENABLE_CMD 0x06 +#define BANK_REG_RD 0x16 +#define BANK_REG_WR 0x17 +/* Bank register is called Extended Address Reg in Micron */ +#define EXTADD_REG_RD 0xC8 +#define EXTADD_REG_WR 0xC5 + +#define COMMAND_OFFSET 0 /* FLASH instruction */ +#define ADDRESS_1_OFFSET 1 /* MSB byte of address to read or write */ +#define ADDRESS_2_OFFSET 2 /* Middle byte of address to read or write */ +#define ADDRESS_3_OFFSET 3 /* LSB byte of address to read or write */ +#define DATA_OFFSET 4 /* Start of Data for Read/Write */ +#define DUMMY_OFFSET 4 /* Dummy byte offset for fast, dual and quad + reads */ +#define DUMMY_SIZE 1 /* Number of dummy bytes for fast, dual and + quad reads */ +#define RD_ID_SIZE 4 /* Read ID command + 3 bytes ID response */ +#define BANK_SEL_SIZE 2 /* BRWR or EARWR command + 1 byte bank value */ +#define WRITE_ENABLE_CMD_SIZE 1 /* WE command */ +/* + * The following constants specify the extra bytes which are sent to the + * FLASH on the QSPI interface, that are not data, but control information + * which includes the command and address + */ +#define OVERHEAD_SIZE 4 + +/* + * The following constants specify the max amount of data and the size of the + * the buffer required to hold the data and overhead to transfer the data to + * and from the FLASH. + */ +#define DATA_SIZE 4096 + +/* + * The following defines are for dual flash interface. + */ +#define LQSPI_CR_FAST_QUAD_READ 0x0000006B /* Fast Quad Read output */ +#define LQSPI_CR_1_DUMMY_BYTE 0x00000100 /* 1 Dummy Byte between + address and return data */ + +#define SINGLE_QSPI_CONFIG_QUAD_READ (XQSPIPS_LQSPI_CR_LINEAR_MASK | \ + LQSPI_CR_1_DUMMY_BYTE | \ + LQSPI_CR_FAST_QUAD_READ) + +#define DUAL_QSPI_CONFIG_QUAD_READ (XQSPIPS_LQSPI_CR_LINEAR_MASK | \ + XQSPIPS_LQSPI_CR_TWO_MEM_MASK | \ + XQSPIPS_LQSPI_CR_SEP_BUS_MASK | \ + LQSPI_CR_1_DUMMY_BYTE | \ + LQSPI_CR_FAST_QUAD_READ) + +#define DUAL_STACK_CONFIG_READ (XQSPIPS_LQSPI_CR_TWO_MEM_MASK | \ + LQSPI_CR_1_DUMMY_BYTE | \ + LQSPI_CR_FAST_QUAD_READ) + +#define SINGLE_QSPI_IO_CONFIG_QUAD_READ (LQSPI_CR_1_DUMMY_BYTE | \ + LQSPI_CR_FAST_QUAD_READ) + +#define DUAL_QSPI_IO_CONFIG_QUAD_READ (XQSPIPS_LQSPI_CR_TWO_MEM_MASK | \ + XQSPIPS_LQSPI_CR_SEP_BUS_MASK | \ + LQSPI_CR_1_DUMMY_BYTE | \ + LQSPI_CR_FAST_QUAD_READ) + + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +/************************** Variable Definitions *****************************/ + +XQspiPs QspiInstance; +XQspiPs *QspiInstancePtr; +u32 QspiFlashSize; +u32 QspiFlashMake; +extern u32 FlashReadBaseAddress; +extern u8 LinearBootDeviceFlag; + +/* + * The following variables are used to read and write to the eeprom and they + * are global to avoid having large buffers on the stack + */ +u8 ReadBuffer[DATA_SIZE + DATA_OFFSET + DUMMY_SIZE]; +u8 WriteBuffer[DATA_OFFSET + DUMMY_SIZE]; + +/******************************************************************************/ +/** +* +* This function initializes the controller for the QSPI interface. +* +* @param None +* +* @return None +* +* @note None +* +****************************************************************************/ +u32 InitQspi(void) +{ + XQspiPs_Config *QspiConfig; + int Status; + + QspiInstancePtr = &QspiInstance; + + /* + * Set up the base address for access + */ + FlashReadBaseAddress = XPS_QSPI_LINEAR_BASEADDR; + + /* + * Initialize the QSPI driver so that it's ready to use + */ + QspiConfig = XQspiPs_LookupConfig(QSPI_DEVICE_ID); + if (NULL == QspiConfig) { + return XST_FAILURE; + } + + Status = XQspiPs_CfgInitialize(QspiInstancePtr, QspiConfig, + QspiConfig->BaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Set Manual Chip select options and drive HOLD_B pin high. + */ + XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_FORCE_SSELECT_OPTION | + XQSPIPS_HOLD_B_DRIVE_OPTION); + + /* + * Set the prescaler for QSPI clock + */ + XQspiPs_SetClkPrescaler(QspiInstancePtr, XQSPIPS_CLK_PRESCALE_8); + + /* + * Assert the FLASH chip select. + */ + XQspiPs_SetSlaveSelect(QspiInstancePtr); + + /* + * Read Flash ID and extract Manufacture and Size information + */ + Status = FlashReadID(); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + if (XPAR_PS7_QSPI_0_QSPI_MODE == SINGLE_FLASH_CONNECTION) { + + fsbl_printf(DEBUG_INFO,"QSPI is in single flash connection\r\n"); + /* + * For Flash size <128Mbit controller configured in linear mode + */ + if (QspiFlashSize <= FLASH_SIZE_16MB) { + LinearBootDeviceFlag = 1; + + /* + * Enable linear mode + */ + XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_LQSPI_MODE_OPTION | + XQSPIPS_HOLD_B_DRIVE_OPTION); + + /* + * Single linear read + */ + XQspiPs_SetLqspiConfigReg(QspiInstancePtr, SINGLE_QSPI_CONFIG_QUAD_READ); + + /* + * Enable the controller + */ + XQspiPs_Enable(QspiInstancePtr); + } else { + /* + * Single flash IO read + */ + XQspiPs_SetLqspiConfigReg(QspiInstancePtr, SINGLE_QSPI_IO_CONFIG_QUAD_READ); + + /* + * Enable the controller + */ + XQspiPs_Enable(QspiInstancePtr); + } + } + + if (XPAR_PS7_QSPI_0_QSPI_MODE == DUAL_PARALLEL_CONNECTION) { + + fsbl_printf(DEBUG_INFO,"QSPI is in Dual Parallel connection\r\n"); + /* + * For Single Flash size <128Mbit controller configured in linear mode + */ + if (QspiFlashSize <= FLASH_SIZE_16MB) { + /* + * Setting linear access flag + */ + LinearBootDeviceFlag = 1; + + /* + * Enable linear mode + */ + XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_LQSPI_MODE_OPTION | + XQSPIPS_HOLD_B_DRIVE_OPTION); + + /* + * Dual linear read + */ + XQspiPs_SetLqspiConfigReg(QspiInstancePtr, DUAL_QSPI_CONFIG_QUAD_READ); + + /* + * Enable the controller + */ + XQspiPs_Enable(QspiInstancePtr); + } else { + /* + * Dual flash IO read + */ + XQspiPs_SetLqspiConfigReg(QspiInstancePtr, DUAL_QSPI_IO_CONFIG_QUAD_READ); + + /* + * Enable the controller + */ + XQspiPs_Enable(QspiInstancePtr); + + } + + /* + * Total flash size is two time of single flash size + */ + QspiFlashSize = 2 * QspiFlashSize; + } + + /* + * It is expected to same flash size for both chip selection + */ + if (XPAR_PS7_QSPI_0_QSPI_MODE == DUAL_STACK_CONNECTION) { + + fsbl_printf(DEBUG_INFO,"QSPI is in Dual Stack connection\r\n"); + + QspiFlashSize = 2 * QspiFlashSize; + + /* + * Enable two flash memories on separate buses + */ + XQspiPs_SetLqspiConfigReg(QspiInstancePtr, DUAL_STACK_CONFIG_READ); + } + + return XST_SUCCESS; +} + +/****************************************************************************** +* +* This function reads serial FLASH ID connected to the SPI interface. +* It then deduces the make and size of the flash and obtains the +* connection mode to point to corresponding parameters in the flash +* configuration table. The flash driver will function based on this and +* it presently supports Micron and Spansion - 128, 256 and 512Mbit and +* Winbond 128Mbit +* +* @param none +* +* @return XST_SUCCESS if read id, otherwise XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +u32 FlashReadID(void) +{ + u32 Status; + + /* + * Read ID in Auto mode. + */ + WriteBuffer[COMMAND_OFFSET] = READ_ID_CMD; + WriteBuffer[ADDRESS_1_OFFSET] = 0x00; /* 3 dummy bytes */ + WriteBuffer[ADDRESS_2_OFFSET] = 0x00; + WriteBuffer[ADDRESS_3_OFFSET] = 0x00; + + Status = XQspiPs_PolledTransfer(QspiInstancePtr, WriteBuffer, ReadBuffer, + RD_ID_SIZE); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + fsbl_printf(DEBUG_INFO,"Single Flash Information\r\n"); + + fsbl_printf(DEBUG_INFO,"FlashID=0x%x 0x%x 0x%x\r\n", ReadBuffer[1], + ReadBuffer[2], + ReadBuffer[3]); + + /* + * Deduce flash make + */ + if (ReadBuffer[1] == MICRON_ID) { + QspiFlashMake = MICRON_ID; + fsbl_printf(DEBUG_INFO, "MICRON "); + } else if(ReadBuffer[1] == SPANSION_ID) { + QspiFlashMake = SPANSION_ID; + fsbl_printf(DEBUG_INFO, "SPANSION "); + } else if(ReadBuffer[1] == WINBOND_ID) { + QspiFlashMake = WINBOND_ID; + fsbl_printf(DEBUG_INFO, "WINBOND "); + } else if(ReadBuffer[1] == MACRONIX_ID) { + QspiFlashMake = MACRONIX_ID; + fsbl_printf(DEBUG_INFO, "MACRONIX "); + } + + /* + * Deduce flash Size + */ + if (ReadBuffer[3] == FLASH_SIZE_ID_128M) { + QspiFlashSize = FLASH_SIZE_128M; + fsbl_printf(DEBUG_INFO, "128M Bits\r\n"); + } else if (ReadBuffer[3] == FLASH_SIZE_ID_256M) { + QspiFlashSize = FLASH_SIZE_256M; + fsbl_printf(DEBUG_INFO, "256M Bits\r\n"); + } else if ((ReadBuffer[3] == FLASH_SIZE_ID_512M) + || (ReadBuffer[3] == MACRONIX_FLASH_SIZE_ID_512M)) { + QspiFlashSize = FLASH_SIZE_512M; + fsbl_printf(DEBUG_INFO, "512M Bits\r\n"); + } else if ((ReadBuffer[3] == FLASH_SIZE_ID_1G) + || (ReadBuffer[3] == MACRONIX_FLASH_SIZE_ID_1G)) { + QspiFlashSize = FLASH_SIZE_1G; + fsbl_printf(DEBUG_INFO, "1G Bits\r\n"); + } + + return XST_SUCCESS; +} + + +/****************************************************************************** +* +* This function reads from the serial FLASH connected to the +* QSPI interface. +* +* @param Address contains the address to read data from in the FLASH. +* @param ByteCount contains the number of bytes to read. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void FlashRead(u32 Address, u32 ByteCount) +{ + /* + * Setup the write command with the specified address and data for the + * FLASH + */ + u32 LqspiCrReg; + u8 ReadCommand; + + LqspiCrReg = XQspiPs_GetLqspiConfigReg(QspiInstancePtr); + ReadCommand = (u8) (LqspiCrReg & XQSPIPS_LQSPI_CR_INST_MASK); + WriteBuffer[COMMAND_OFFSET] = ReadCommand; + WriteBuffer[ADDRESS_1_OFFSET] = (u8)((Address & 0xFF0000) >> 16); + WriteBuffer[ADDRESS_2_OFFSET] = (u8)((Address & 0xFF00) >> 8); + WriteBuffer[ADDRESS_3_OFFSET] = (u8)(Address & 0xFF); + + ByteCount += DUMMY_SIZE; + + /* + * Send the read command to the FLASH to read the specified number + * of bytes from the FLASH, send the read command and address and + * receive the specified number of bytes of data in the data buffer + */ + XQspiPs_PolledTransfer(QspiInstancePtr, WriteBuffer, ReadBuffer, + ByteCount + OVERHEAD_SIZE); +} + +/******************************************************************************/ +/** +* +* This function provides the QSPI FLASH interface for the Simplified header +* functionality. +* +* @param SourceAddress is address in FLASH data space +* @param DestinationAddress is address in DDR data space +* @param LengthBytes is the length of the data in Bytes +* +* @return +* - XST_SUCCESS if the write completes correctly +* - XST_FAILURE if the write fails to completes correctly +* +* @note none. +* +****************************************************************************/ +u32 QspiAccess( u32 SourceAddress, u32 DestinationAddress, u32 LengthBytes) +{ + u8 *BufferPtr; + u32 Length = 0; + u32 BankSel = 0; + u32 LqspiCrReg; + u32 Status; + u8 BankSwitchFlag = 1; + + /* + * Linear access check + */ + if (LinearBootDeviceFlag == 1) { + /* + * Check for non-word tail, add bytes to cover the end + */ + if ((LengthBytes%4) != 0){ + LengthBytes += (4 - (LengthBytes & 0x00000003)); + } + + memcpy((void*)DestinationAddress, + (const void*)(SourceAddress + FlashReadBaseAddress), + (size_t)LengthBytes); + } else { + /* + * Non Linear access + */ + BufferPtr = (u8*)DestinationAddress; + + /* + * Dual parallel connection actual flash is half + */ + if (XPAR_PS7_QSPI_0_QSPI_MODE == DUAL_PARALLEL_CONNECTION) { + SourceAddress = SourceAddress/2; + } + + while(LengthBytes > 0) { + /* + * Local of DATA_SIZE size used for read/write buffer + */ + if(LengthBytes > DATA_SIZE) { + Length = DATA_SIZE; + } else { + Length = LengthBytes; + } + + /* + * Dual stack connection + */ + if (XPAR_PS7_QSPI_0_QSPI_MODE == DUAL_STACK_CONNECTION) { + /* + * Get the current LQSPI configuration value + */ + LqspiCrReg = XQspiPs_GetLqspiConfigReg(QspiInstancePtr); + + /* + * Select lower or upper Flash based on sector address + */ + if (SourceAddress >= (QspiFlashSize/2)) { + /* + * Set selection to U_PAGE + */ + XQspiPs_SetLqspiConfigReg(QspiInstancePtr, + LqspiCrReg | XQSPIPS_LQSPI_CR_U_PAGE_MASK); + + /* + * Subtract first flash size when accessing second flash + */ + SourceAddress = SourceAddress - (QspiFlashSize/2); + + fsbl_printf(DEBUG_INFO, "stacked - upper CS \n\r"); + + /* + * Assert the FLASH chip select. + */ + XQspiPs_SetSlaveSelect(QspiInstancePtr); + } + } + + /* + * Select bank + */ + if ((SourceAddress >= FLASH_SIZE_16MB) && (BankSwitchFlag == 1)) { + BankSel = SourceAddress/FLASH_SIZE_16MB; + + fsbl_printf(DEBUG_INFO, "Bank Selection %lu\n\r", BankSel); + + Status = SendBankSelect(BankSel); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_INFO, "Bank Selection Failed\n\r"); + return XST_FAILURE; + } + + BankSwitchFlag = 0; + } + + /* + * If data to be read spans beyond the current bank, then + * calculate length in current bank else no change in length + */ + if (XPAR_PS7_QSPI_0_QSPI_MODE == DUAL_PARALLEL_CONNECTION) { + /* + * In dual parallel mode, check should be for half + * the length. + */ + if((SourceAddress & BANKMASK) != ((SourceAddress + (Length/2)) & BANKMASK)) + { + Length = (SourceAddress & BANKMASK) + FLASH_SIZE_16MB - SourceAddress; + /* + * Above length calculated is for single flash + * Length should be doubled since dual parallel + */ + Length = Length * 2; + BankSwitchFlag = 1; + } + } else { + if((SourceAddress & BANKMASK) != ((SourceAddress + Length) & BANKMASK)) + { + Length = (SourceAddress & BANKMASK) + FLASH_SIZE_16MB - SourceAddress; + BankSwitchFlag = 1; + } + } + + /* + * Copying the image to local buffer + */ + FlashRead(SourceAddress, Length); + + /* + * Moving the data from local buffer to DDR destination address + */ + memcpy(BufferPtr, &ReadBuffer[DATA_OFFSET + DUMMY_SIZE], Length); + + /* + * Updated the variables + */ + LengthBytes -= Length; + + /* + * For Dual parallel connection address increment should be half + */ + if (XPAR_PS7_QSPI_0_QSPI_MODE == DUAL_PARALLEL_CONNECTION) { + SourceAddress += Length/2; + } else { + SourceAddress += Length; + } + + BufferPtr = (u8*)((u32)BufferPtr + Length); + } + + /* + * Reset Bank selection to zero + */ + Status = SendBankSelect(0); + if (Status != XST_SUCCESS) { + fsbl_printf(DEBUG_INFO, "Bank Selection Reset Failed\n\r"); + return XST_FAILURE; + } + + if (XPAR_PS7_QSPI_0_QSPI_MODE == DUAL_STACK_CONNECTION) { + + /* + * Reset selection to L_PAGE + */ + XQspiPs_SetLqspiConfigReg(QspiInstancePtr, + LqspiCrReg & (~XQSPIPS_LQSPI_CR_U_PAGE_MASK)); + + fsbl_printf(DEBUG_INFO, "stacked - lower CS \n\r"); + + /* + * Assert the FLASH chip select. + */ + XQspiPs_SetSlaveSelect(QspiInstancePtr); + } + } + + return XST_SUCCESS; +} + + + +/****************************************************************************** +* +* This functions selects the current bank +* +* @param BankSel is the bank to be selected in the flash device(s). +* +* @return XST_SUCCESS if bank selected +* XST_FAILURE if selection failed +* @note None. +* +******************************************************************************/ +u32 SendBankSelect(u8 BankSel) +{ + u32 Status; + + /* + * bank select commands for Micron and Spansion are different + * Macronix bank select is same as Micron + */ + if (QspiFlashMake == MICRON_ID || QspiFlashMake == MACRONIX_ID) { + /* + * For micron command WREN should be sent first + * except for some specific feature set + */ + WriteBuffer[COMMAND_OFFSET] = WRITE_ENABLE_CMD; + Status = XQspiPs_PolledTransfer(QspiInstancePtr, WriteBuffer, NULL, + WRITE_ENABLE_CMD_SIZE); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Send the Extended address register write command + * written, no receive buffer required + */ + WriteBuffer[COMMAND_OFFSET] = EXTADD_REG_WR; + WriteBuffer[ADDRESS_1_OFFSET] = BankSel; + Status = XQspiPs_PolledTransfer(QspiInstancePtr, WriteBuffer, NULL, + BANK_SEL_SIZE); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + } + + if (QspiFlashMake == SPANSION_ID) { + WriteBuffer[COMMAND_OFFSET] = BANK_REG_WR; + WriteBuffer[ADDRESS_1_OFFSET] = BankSel; + + /* + * Send the Extended address register write command + * written, no receive buffer required + */ + Status = XQspiPs_PolledTransfer(QspiInstancePtr, WriteBuffer, NULL, + BANK_SEL_SIZE); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + } + + /* + * For testing - Read bank to verify + */ + if (QspiFlashMake == SPANSION_ID) { + WriteBuffer[COMMAND_OFFSET] = BANK_REG_RD; + WriteBuffer[ADDRESS_1_OFFSET] = 0x00; + + /* + * Send the Extended address register write command + * written, no receive buffer required + */ + Status = XQspiPs_PolledTransfer(QspiInstancePtr, WriteBuffer, ReadBuffer, + BANK_SEL_SIZE); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + } + + if (QspiFlashMake == MICRON_ID || QspiFlashMake == MACRONIX_ID) { + WriteBuffer[COMMAND_OFFSET] = EXTADD_REG_RD; + WriteBuffer[ADDRESS_1_OFFSET] = 0x00; + + /* + * Send the Extended address register write command + * written, no receive buffer required + */ + Status = XQspiPs_PolledTransfer(QspiInstancePtr, WriteBuffer, ReadBuffer, + BANK_SEL_SIZE); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + } + + if (ReadBuffer[1] != BankSel) { + fsbl_printf(DEBUG_INFO, "BankSel %d != Register Read %d\n\r", BankSel, + ReadBuffer[1]); + return XST_FAILURE; + } + + return XST_SUCCESS; +} +#endif + diff --git a/sdk/fsbl/src/qspi.h b/sdk/fsbl/src/qspi.h new file mode 100644 index 0000000..18dc374 --- /dev/null +++ b/sdk/fsbl/src/qspi.h @@ -0,0 +1,128 @@ +/****************************************************************************** +* +* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file qspi.h +* +* This file contains the interface for the QSPI FLASH functionality +* +*
+* MODIFICATION HISTORY:
+*
+* Ver	Who	Date		Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a ecm	01/10/10 Initial release
+* 3.00a mb  01/09/12 Added the Delay Values defines for qspi
+* 5.00a sgd	05/17/13 Added Flash Size > 128Mbit support
+* 					 Dual Stack support
+* 
+* +* @note +* +******************************************************************************/ +#ifndef ___QSPI_H___ +#define ___QSPI_H___ + +#include "fsbl.h" +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ +#include "fsbl.h" + +/************************** Constant Definitions *****************************/ +#define SINGLE_FLASH_CONNECTION 0 +#define DUAL_STACK_CONNECTION 1 +#define DUAL_PARALLEL_CONNECTION 2 +#define FLASH_SIZE_16MB 0x1000000 + +/* + * Bank mask + */ +#define BANKMASK 0xF000000 + +/* + * Identification of Flash + * Micron: + * Byte 0 is Manufacturer ID; + * Byte 1 is first byte of Device ID - 0xBB or 0xBA + * Byte 2 is second byte of Device ID describes flash size: + * 128Mbit : 0x18; 256Mbit : 0x19; 512Mbit : 0x20 + * Spansion: + * Byte 0 is Manufacturer ID; + * Byte 1 is Device ID - Memory Interface type - 0x20 or 0x02 + * Byte 2 is second byte of Device ID describes flash size: + * 128Mbit : 0x18; 256Mbit : 0x19; 512Mbit : 0x20 + */ + +#define MICRON_ID 0x20 +#define SPANSION_ID 0x01 +#define WINBOND_ID 0xEF +#define MACRONIX_ID 0xC2 + +#define FLASH_SIZE_ID_128M 0x18 +#define FLASH_SIZE_ID_256M 0x19 +#define FLASH_SIZE_ID_512M 0x20 +#define FLASH_SIZE_ID_1G 0x21 +/* Macronix size constants are different for 512M and 1G */ +#define MACRONIX_FLASH_SIZE_ID_512M 0x1A +#define MACRONIX_FLASH_SIZE_ID_1G 0x1B + +/* + * Size in bytes + */ +#define FLASH_SIZE_128M 0x1000000 +#define FLASH_SIZE_256M 0x2000000 +#define FLASH_SIZE_512M 0x4000000 +#define FLASH_SIZE_1G 0x8000000 + +/************************** Function Prototypes ******************************/ +u32 InitQspi(void); + +u32 QspiAccess( u32 SourceAddress, + u32 DestinationAddress, + u32 LengthBytes); + +u32 FlashReadID(void); +u32 SendBankSelect(u8 BankSel); +/************************** Variable Definitions *****************************/ + + +#ifdef __cplusplus +} +#endif + + +#endif /* ___QSPI_H___ */ + diff --git a/sdk/fsbl/src/rsa.c b/sdk/fsbl/src/rsa.c new file mode 100644 index 0000000..ef6e506 --- /dev/null +++ b/sdk/fsbl/src/rsa.c @@ -0,0 +1,361 @@ +/****************************************************************************** +* +* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file rsa.c +* +* Contains code for the RSA authentication +* +*
+* MODIFICATION HISTORY:
+*
+* Ver	Who	Date		Changes
+* ----- ---- -------- -------------------------------------------------------
+* 4.00a sgd	02/28/13 Initial release
+* 6.00a kc	07/30/13 Added FSBL_DEBUG_RSA to print more RSA buffers
+* 					 Fix for CR#724165 - Partition Header used by FSBL is
+*                                        not authenticated
+*                    Fix for CR#724166 - FSBL doesn’t use PPK authenticated
+*                                        by Boot ROM for authenticating
+*                                        the Partition images
+*                    Fix for CR#722979 - Provide customer-friendly
+*                                        changelogs in FSBL
+* 9.00a kc  04/16/14 Fix for CR#724166 - SetPpk() will fail on secure
+*					 					 fallback unless FSBL* and FSBL are
+*					 					 identical in length
+*					 Fix for CR#791245 - Use of xilrsa in FSBL
+* 
+* +* @note +* +******************************************************************************/ + +/***************************** Include Files *********************************/ +#ifdef RSA_SUPPORT +#include "fsbl.h" +#include "rsa.h" +#include "xilrsa.h" + +#ifdef XPAR_XWDTPS_0_BASEADDR +#include "xwdtps.h" +#endif + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ +#ifdef XPAR_XWDTPS_0_BASEADDR +extern XWdtPs Watchdog; /* Instance of WatchDog Timer */ +#endif + + +/************************** Variable Definitions *****************************/ + +static u8 *PpkModular; +static u8 *PpkModularEx; +static u32 PpkExp; +static u32 PpkAlreadySet=0; + +extern u32 FsblLength; + +void FsblPrintArray (u8 *Buf, u32 Len, char *Str) +{ +#ifdef FSBL_DEBUG_RSA + int Index; + fsbl_printf(DEBUG_INFO, "%s START\r\n", Str); + for (Index=0;Index +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 4.00a sg 02/28/13 Initial release +* +* +* +* @note +* +******************************************************************************/ +#ifndef ___RSA_H___ +#define ___RSA_H___ + +#ifdef __cplusplus +extern "C" { +#endif +/***************************** Include Files *********************************/ + + +#define RSA_PPK_MODULAR_SIZE 256 +#define RSA_PPK_MODULAR_EXT_SIZE 256 +#define RSA_PPK_EXPO_SIZE 64 +#define RSA_SPK_MODULAR_SIZE 256 +#define RSA_SPK_MODULAR_EXT_SIZE 256 +#define RSA_SPK_EXPO_SIZE 64 +#define RSA_SPK_SIGNATURE_SIZE 256 +#define RSA_PARTITION_SIGNATURE_SIZE 256 +#define RSA_SIGNATURE_SIZE 0x6C0 /* Signature size in bytes */ +#define RSA_HEADER_SIZE 4 /* Signature header size in bytes */ +#define RSA_MAGIC_WORD_SIZE 60 /* Magic word size in bytes */ + +void SetPpk(void ); +u32 AuthenticatePartition(u8 *Buffer, u32 Size); +u32 RecreatePaddingAndCheck(u8 *signature, u8 *hash); + +#ifdef __cplusplus +} +#endif + +#endif /* ___RSA_H___ */ diff --git a/sdk/fsbl/src/sd.c b/sdk/fsbl/src/sd.c new file mode 100644 index 0000000..9fb8086 --- /dev/null +++ b/sdk/fsbl/src/sd.c @@ -0,0 +1,191 @@ +/****************************************************************************** +* +* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file sd.c +* +* Contains code for the SD card FLASH functionality. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver	Who	Date		Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a jz	04/28/11 Initial release
+* 7.00a kc  10/18/13 Integrated SD/MMC driver
+* 12.00a ssc 12/11/14 Fix for CR# 839182
+*
+* 
+* +* @note +* +******************************************************************************/ + +/***************************** Include Files *********************************/ +#include "xparameters.h" +#include "fsbl.h" + +#if defined(XPAR_PS7_SD_0_S_AXI_BASEADDR) || defined(XPAR_XSDPS_0_BASEADDR) + +#ifndef XPAR_PS7_SD_0_S_AXI_BASEADDR +#define XPAR_PS7_SD_0_S_AXI_BASEADDR XPAR_XSDPS_0_BASEADDR +#endif + +#include "xstatus.h" + +#include "ff.h" +#include "sd.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +/************************** Variable Definitions *****************************/ + +extern u32 FlashReadBaseAddress; + + +static FIL fil; /* File object */ +static FATFS fatfs; +static char buffer[32]; +static char *boot_file = buffer; + +/******************************************************************************/ +/******************************************************************************/ +/** +* +* This function initializes the controller for the SD FLASH interface. +* +* @param filename of the file that is to be used +* +* @return +* - XST_SUCCESS if the controller initializes correctly +* - XST_FAILURE if the controller fails to initializes correctly +* +* @note None. +* +****************************************************************************/ +u32 InitSD(const char *filename) +{ + + FRESULT rc; + TCHAR *path = "0:/"; /* Logical drive number is 0 */ + + /* Register volume work area, initialize device */ + rc = f_mount(&fatfs, path, 0); + fsbl_printf(DEBUG_INFO,"SD: rc= %.8x\n\r", rc); + + if (rc != FR_OK) { + return XST_FAILURE; + } + + strcpy_rom(buffer, filename); + boot_file = (char *)buffer; + FlashReadBaseAddress = XPAR_PS7_SD_0_S_AXI_BASEADDR; + + rc = f_open(&fil, boot_file, FA_READ); + if (rc) { + fsbl_printf(DEBUG_GENERAL,"SD: Unable to open file %s: %d\n", boot_file, rc); + return XST_FAILURE; + } + + return XST_SUCCESS; + +} + +/******************************************************************************/ +/** +* +* This function provides the SD FLASH interface for the Simplified header +* functionality. +* +* @param SourceAddress is address in FLASH data space +* @param DestinationAddress is address in OCM data space +* @param LengthBytes is the number of bytes to move +* +* @return +* - XST_SUCCESS if the write completes correctly +* - XST_FAILURE if the write fails to completes correctly +* +* @note None. +* +****************************************************************************/ +u32 SDAccess( u32 SourceAddress, u32 DestinationAddress, u32 LengthBytes) +{ + + FRESULT rc; /* Result code */ + UINT br; + + rc = f_lseek(&fil, SourceAddress); + if (rc) { + fsbl_printf(DEBUG_INFO,"SD: Unable to seek to %lx\n", SourceAddress); + return XST_FAILURE; + } + + rc = f_read(&fil, (void*)DestinationAddress, LengthBytes, &br); + + if (rc) { + fsbl_printf(DEBUG_GENERAL,"*** ERROR: f_read returned %d\r\n", rc); + } + + return XST_SUCCESS; + +} /* End of SDAccess */ + + +/******************************************************************************/ +/** +* +* This function closes the file object +* +* @param None +* +* @return None. +* +* @note None. +* +****************************************************************************/ +void ReleaseSD(void) { + + f_close(&fil); + return; + + +} +#endif + + diff --git a/sdk/fsbl/src/sd.h b/sdk/fsbl/src/sd.h new file mode 100644 index 0000000..6283eb6 --- /dev/null +++ b/sdk/fsbl/src/sd.h @@ -0,0 +1,79 @@ +/****************************************************************************** +* +* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file sd.h +* +* This file contains the interface for the Secure Digital (SD) card +* +*
+* MODIFICATION HISTORY:
+*
+* Ver	Who	Date		Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a bh	03/10/11 Initial release
+* 7.00a kc  10/18/13 Integrated SD/MMC driver
+*
+* 
+* +* @note +* +******************************************************************************/ +#ifndef ___SD_H___ +#define ___SD_H___ + + +#ifdef __cplusplus +extern "C" { +#endif + + +/************************** Function Prototypes ******************************/ + +#if defined(XPAR_PS7_SD_0_S_AXI_BASEADDR) || defined(XPAR_XSDPS_0_BASEADDR) +u32 InitSD(const char *); + +u32 SDAccess( u32 SourceAddress, + u32 DestinationAddress, + u32 LengthWords); + +void ReleaseSD(void); +#endif +/************************** Variable Definitions *****************************/ +#ifdef __cplusplus +} +#endif + + +#endif /* ___SD_H___ */ + diff --git a/sdk/fsbl_bsp/.cproject b/sdk/fsbl_bsp/.cproject new file mode 100644 index 0000000..d7f6454 --- /dev/null +++ b/sdk/fsbl_bsp/.cproject @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/sdk/fsbl_bsp/.project b/sdk/fsbl_bsp/.project new file mode 100644 index 0000000..bd6b804 --- /dev/null +++ b/sdk/fsbl_bsp/.project @@ -0,0 +1,75 @@ + + + fsbl_bsp + Created by SDK v2016.4 + + + + + org.eclipse.cdt.make.core.makeBuilder + + + org.eclipse.cdt.core.errorOutputParser + org.eclipse.cdt.core.GASErrorParser;org.eclipse.cdt.core.GLDErrorParser;org.eclipse.cdt.core.GCCErrorParser;org.eclipse.cdt.core.GmakeErrorParser;org.eclipse.cdt.core.VCErrorParser;org.eclipse.cdt.core.CWDLocator;org.eclipse.cdt.core.MakeErrorParser; + + + org.eclipse.cdt.make.core.append_environment + true + + + org.eclipse.cdt.make.core.build.arguments + + + + org.eclipse.cdt.make.core.build.command + make + + + org.eclipse.cdt.make.core.build.target.auto + all + + + org.eclipse.cdt.make.core.build.target.clean + clean + + + org.eclipse.cdt.make.core.build.target.inc + all + + + org.eclipse.cdt.make.core.enableAutoBuild + true + + + org.eclipse.cdt.make.core.enableCleanBuild + true + + + org.eclipse.cdt.make.core.enableFullBuild + true + + + org.eclipse.cdt.make.core.enabledIncrementalBuild + true + + + org.eclipse.cdt.make.core.environment + + + + org.eclipse.cdt.make.core.stopOnError + false + + + org.eclipse.cdt.make.core.useDefaultBuildCmd + true + + + + + + com.xilinx.sdk.sw.SwProjectNature + org.eclipse.cdt.core.cnature + org.eclipse.cdt.make.core.makeNature + + diff --git a/sdk/fsbl_bsp/.sdkproject b/sdk/fsbl_bsp/.sdkproject new file mode 100644 index 0000000..08953ab --- /dev/null +++ b/sdk/fsbl_bsp/.sdkproject @@ -0,0 +1,4 @@ +THIRPARTY=false +HW_PROJECT_REFERENCE=Arty_Z7_20_wrapper_hw_platform_0 +PROCESSOR=ps7_cortexa9_0 +MSS_FILE=system.mss diff --git a/sdk/fsbl_bsp/Makefile b/sdk/fsbl_bsp/Makefile new file mode 100644 index 0000000..2bc77fb --- /dev/null +++ b/sdk/fsbl_bsp/Makefile @@ -0,0 +1,31 @@ +# Makefile generated by Xilinx. + +PROCESSOR = ps7_cortexa9_0 +LIBRARIES = ${PROCESSOR}/lib/libxil.a +BSP_MAKEFILES := $(wildcard $(PROCESSOR)/libsrc/*/src/Makefile) +SUBDIRS := $(patsubst %/Makefile, %, $(BSP_MAKEFILES)) + +ifneq (,$(findstring win,$(RDI_PLATFORM))) + SHELL = CMD +endif + +all: libs + @echo 'Finished building libraries' + +include: $(addsuffix /make.include,$(SUBDIRS)) + +libs: $(addsuffix /make.libs,$(SUBDIRS)) + +$(PROCESSOR)/lib/libxil.a: $(PROCESSOR)/lib/libxil_init.a + cp -f $< $@ + +%/make.include: $(if $(wildcard $(PROCESSOR)/lib/libxil_init.a),$(PROCESSOR)/lib/libxil.a,) + @echo "Running Make include in $(subst /make.include,,$@)" + $(MAKE) -C $(subst /make.include,,$@) -s include "SHELL=$(SHELL)" "COMPILER=arm-none-eabi-gcc" "ARCHIVER=arm-none-eabi-ar" "COMPILER_FLAGS= -O2 -c" "EXTRA_COMPILER_FLAGS=-mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard -nostartfiles" + +%/make.libs: include + @echo "Running Make libs in $(subst /make.libs,,$@)" + $(MAKE) -C $(subst /make.libs,,$@) -s libs "SHELL=$(SHELL)" "COMPILER=arm-none-eabi-gcc" "ARCHIVER=arm-none-eabi-ar" "COMPILER_FLAGS= -O2 -c" "EXTRA_COMPILER_FLAGS=-mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard -nostartfiles" + +clean: + rm -f ${PROCESSOR}/lib/libxil.a diff --git a/sdk/fsbl_bsp/system.mss b/sdk/fsbl_bsp/system.mss new file mode 100644 index 0000000..3aafdca --- /dev/null +++ b/sdk/fsbl_bsp/system.mss @@ -0,0 +1,305 @@ + + PARAMETER VERSION = 2.2.0 + + +BEGIN OS + PARAMETER OS_NAME = standalone + PARAMETER OS_VER = 6.1 + PARAMETER PROC_INSTANCE = ps7_cortexa9_0 + PARAMETER stdin = ps7_uart_0 + PARAMETER stdout = ps7_uart_0 +END + + +BEGIN PROCESSOR + PARAMETER DRIVER_NAME = cpu_cortexa9 + PARAMETER DRIVER_VER = 2.3 + PARAMETER HW_INSTANCE = ps7_cortexa9_0 +END + + +BEGIN DRIVER + PARAMETER DRIVER_NAME = generic + PARAMETER DRIVER_VER = 2.0 + PARAMETER HW_INSTANCE = axi_dynclk_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = gpio + PARAMETER DRIVER_VER = 4.3 + PARAMETER HW_INSTANCE = axi_gpio_hdmi +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = gpio + PARAMETER DRIVER_VER = 4.3 + PARAMETER HW_INSTANCE = axi_gpio_led +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = gpio + PARAMETER DRIVER_VER = 4.3 + PARAMETER HW_INSTANCE = axi_gpio_shield_1 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = gpio + PARAMETER DRIVER_VER = 4.3 + PARAMETER HW_INSTANCE = axi_gpio_shield_2 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = gpio + PARAMETER DRIVER_VER = 4.3 + PARAMETER HW_INSTANCE = axi_gpio_sw +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = axivdma + PARAMETER DRIVER_VER = 6.2 + PARAMETER HW_INSTANCE = axi_vdma_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = generic + PARAMETER DRIVER_VER = 2.0 + PARAMETER HW_INSTANCE = ps7_afi_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = generic + PARAMETER DRIVER_VER = 2.0 + PARAMETER HW_INSTANCE = ps7_afi_1 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = generic + PARAMETER DRIVER_VER = 2.0 + PARAMETER HW_INSTANCE = ps7_afi_2 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = generic + PARAMETER DRIVER_VER = 2.0 + PARAMETER HW_INSTANCE = ps7_afi_3 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = coresightps_dcc + PARAMETER DRIVER_VER = 1.3 + PARAMETER HW_INSTANCE = ps7_coresight_comp_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = ddrps + PARAMETER DRIVER_VER = 1.0 + PARAMETER HW_INSTANCE = ps7_ddr_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = generic + PARAMETER DRIVER_VER = 2.0 + PARAMETER HW_INSTANCE = ps7_ddrc_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = devcfg + PARAMETER DRIVER_VER = 3.4 + PARAMETER HW_INSTANCE = ps7_dev_cfg_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = dmaps + PARAMETER DRIVER_VER = 2.3 + PARAMETER HW_INSTANCE = ps7_dma_ns +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = dmaps + PARAMETER DRIVER_VER = 2.3 + PARAMETER HW_INSTANCE = ps7_dma_s +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = emacps + PARAMETER DRIVER_VER = 3.3 + PARAMETER HW_INSTANCE = ps7_ethernet_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = generic + PARAMETER DRIVER_VER = 2.0 + PARAMETER HW_INSTANCE = ps7_globaltimer_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = gpiops + PARAMETER DRIVER_VER = 3.1 + PARAMETER HW_INSTANCE = ps7_gpio_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = generic + PARAMETER DRIVER_VER = 2.0 + PARAMETER HW_INSTANCE = ps7_gpv_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = iicps + PARAMETER DRIVER_VER = 3.4 + PARAMETER HW_INSTANCE = ps7_i2c_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = iicps + PARAMETER DRIVER_VER = 3.4 + PARAMETER HW_INSTANCE = ps7_i2c_1 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = generic + PARAMETER DRIVER_VER = 2.0 + PARAMETER HW_INSTANCE = ps7_intc_dist_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = generic + PARAMETER DRIVER_VER = 2.0 + PARAMETER HW_INSTANCE = ps7_iop_bus_config_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = generic + PARAMETER DRIVER_VER = 2.0 + PARAMETER HW_INSTANCE = ps7_l2cachec_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = generic + PARAMETER DRIVER_VER = 2.0 + PARAMETER HW_INSTANCE = ps7_ocmc_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = generic + PARAMETER DRIVER_VER = 2.0 + PARAMETER HW_INSTANCE = ps7_pl310_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = generic + PARAMETER DRIVER_VER = 2.0 + PARAMETER HW_INSTANCE = ps7_pmu_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = qspips + PARAMETER DRIVER_VER = 3.3 + PARAMETER HW_INSTANCE = ps7_qspi_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = generic + PARAMETER DRIVER_VER = 2.0 + PARAMETER HW_INSTANCE = ps7_qspi_linear_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = generic + PARAMETER DRIVER_VER = 2.0 + PARAMETER HW_INSTANCE = ps7_ram_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = generic + PARAMETER DRIVER_VER = 2.0 + PARAMETER HW_INSTANCE = ps7_ram_1 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = generic + PARAMETER DRIVER_VER = 2.0 + PARAMETER HW_INSTANCE = ps7_scuc_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = scugic + PARAMETER DRIVER_VER = 3.5 + PARAMETER HW_INSTANCE = ps7_scugic_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = scutimer + PARAMETER DRIVER_VER = 2.1 + PARAMETER HW_INSTANCE = ps7_scutimer_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = scuwdt + PARAMETER DRIVER_VER = 2.1 + PARAMETER HW_INSTANCE = ps7_scuwdt_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = sdps + PARAMETER DRIVER_VER = 3.1 + PARAMETER HW_INSTANCE = ps7_sd_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = generic + PARAMETER DRIVER_VER = 2.0 + PARAMETER HW_INSTANCE = ps7_slcr_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = spips + PARAMETER DRIVER_VER = 3.0 + PARAMETER HW_INSTANCE = ps7_spi_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = uartps + PARAMETER DRIVER_VER = 3.3 + PARAMETER HW_INSTANCE = ps7_uart_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = usbps + PARAMETER DRIVER_VER = 2.4 + PARAMETER HW_INSTANCE = ps7_usb_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = xadcps + PARAMETER DRIVER_VER = 2.2 + PARAMETER HW_INSTANCE = ps7_xadc_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = vtc + PARAMETER DRIVER_VER = 7.2 + PARAMETER HW_INSTANCE = v_tc_0 +END + +BEGIN DRIVER + PARAMETER DRIVER_NAME = sysmon + PARAMETER DRIVER_VER = 7.3 + PARAMETER HW_INSTANCE = xadc_wiz_0 +END + + +BEGIN LIBRARY + PARAMETER LIBRARY_NAME = xilffs + PARAMETER LIBRARY_VER = 3.5 + PARAMETER PROC_INSTANCE = ps7_cortexa9_0 +END + + +BEGIN LIBRARY + PARAMETER LIBRARY_NAME = xilrsa + PARAMETER LIBRARY_VER = 1.2 + PARAMETER PROC_INSTANCE = ps7_cortexa9_0 +END + + diff --git a/src/others/.gitignore b/src/others/.gitignore deleted file mode 100644 index 46926d8..0000000 --- a/src/others/.gitignore +++ /dev/null @@ -1 +0,0 @@ -SDSoC_Staging/ \ No newline at end of file diff --git a/src/others/Creating_SDSoC_Platform_archive.txt b/src/others/Creating_SDSoC_Platform_archive.txt deleted file mode 100644 index 0c40743..0000000 --- a/src/others/Creating_SDSoC_Platform_archive.txt +++ /dev/null @@ -1,13 +0,0 @@ -Instructions for Archiving this project into an SDSoC Platform: -=================================================================== - -1) Open project in Vivado like normal using create_project.tcl -2) Archive the project. Uncheck "Use config options" and "Include runs". -3) Decompress the new archive -4) Open the .xpr in a text editor change the line below so that it matches: - -