Beim Ultra96-V2 ist das Ausgangssignal vom ZynqMP-E / A-Port mit dem KILL_N-Eingangsport des Ein- / Ausschalt-LSI verbunden. Wenn dieses Signal auf L gesetzt ist, kann der Ultra96-V2 ausgeschaltet werden.
Es scheint jedoch, dass dieses Signal nicht gesteuert werden kann, wenn BOOT.BIN und Linux mit der üblichen Methode erstellt werden, und selbst wenn das Herunterfahren von Linux durch den Ausschaltbefehl usw. ausgeführt wird, wird Ultra96-V2 nicht zum Ausschaltzustand. Hmm. Übrigens, wenn Sie das Gerät ausschalten, müssen Sie den Ein- / Ausschalter (SW4) drücken und gedrückt halten, aber das Drücken und Halten des kleinen Knopfes ist für Ihre Finger ziemlich schmerzhaft (dies ist das Motiv).
In diesem Artikel wird durch Ändern der in BOOT.BIN enthaltenen PMUFW (Platform Management Unit Firmware), wenn das Herunterfahren unter Linux durch den Ausschaltbefehl usw. ausgeführt wird, dieses Signal auf L gesetzt und der Ultra96-V2 automatisch ausgeschaltet. Hier erfahren Sie, wie es geht.
Außerdem wird gezeigt, wie Sie Linux herunterfahren, wenn Sie während des Startvorgangs von Linux den Netzschalter drücken.
Abb.1 zeigt die Schaltung um das Ausschalten von Ultra96-V2.
Abb.1 Ultra96-V2 MIO34_POWER_KILL_N-Signal
Der KILL_N-Port des LSI (SLG4G42480V), der ein- und ausgeschaltet wird, ist über eine Pegelumwandlungsschaltung mit dem MIO34-Port von ZynqMP verbunden. Das Ausgangssignal vom MIO34-Port des ZynqMP wird vom Einschalten bis zur Konfiguration des MIO34 hochgezogen und auf H festgelegt.
Durch die Ausgabe von L vom MIO34-Port von ZynqMP wird der KILL_N-Eingangsport des ein- und auszuschaltenden LSI zu L und schaltet den Ultra96-V2 aus.
Der INT-Port des LSI (SLG4G42480V), der ein- und ausgeschaltet wird, ist mit dem MIO26-Port von ZynqMP verbunden.
Abbildung 2 zeigt, wie die ZynqMP MIO26- und MIO34-Ports in Vivado auf dem Ultra96-V2 konfiguriert sind.
Abb.2 Ultra96-V2 ZynqMP MIO26 / MIO34-Porteinstellungen
In Ultra96-V2 ist der MIO26-Port von ZynqMP für die Verbindung mit GPI0 der PMU (Platform Management Unit) konfiguriert, und der MIO34-Port ist für die Verbindung mit GPO2 konfiguriert.
PMU(Platform Management Unit)
Die PMU (Platform Management Unit) ist ein in ZynqMP integriertes Subsystem zum Einschalten, Zurücksetzen und Überwachen von Ressourcen in ZynqMP mithilfe von Interprozessor-Interrupts und Energieverwaltungsregistern. Die PMU besteht aus einem MicroBlaze-Prozessor, einem 32-KByte-ROM und einem 128-KByte-RAM. Unmittelbar nach dem Einschalten von ZynqMP startet die PMU zuerst, um den Stage 0-Bootloader im ROM auszuführen. Der Bootloader der Stufe 0 lädt den in BOOT.BIN im Speicher (SD-Karte usw.) enthaltenen Bootloader der Stufe 1 (FSBL) in den internen RAM und überträgt die Steuerung an die APU (Application Processing Unit).
PMUFW(Platform Management Unit Firmware)
Der Stage 1 Boot Loader (FSBL) lädt die in BOOT.BIN enthaltene PMUFW (Platform Management Unit Firmware) in den RAM der PMU. Die PMU schaltet dann die Ressourcen in ZynqMP gemäß PMUFW ein, setzt sie zurück und überwacht sie. Es akzeptiert auch verschiedene Anforderungen von APU und RPU als Systemaufrufe (PM-API-Aufrufe).
Beim Ausschalten unter Linux rufen Sie diesen PMUFW-PM-API-Aufruf zum Herunterfahren auf.
Den Quellcode von PMUFW finden Sie unter [PMUFW erstellen].
PmProcessRequest()
Wenn die PMU einen PM-API-Aufruf akzeptiert, ruft sie PmProcessRequest () von PMUFW auf. PmProcessRequest () ist in pm_core.c definiert.
Die PMU ruft PmSystemShutdown () auf, wenn der PM-API-Aufruf eine Anforderung zum Herunterfahren ist.
pm_core.c
/**
* PmProcessApiCall() - Called to process PM API call
* @master Pointer to a requesting master structure
* @pload Pointer to array of integers with the information about the pm call
* (api id + arguments of the api)
*
* @note Called to process PM API call. If specific PM API receives less
* than 4 arguments, extra arguments are ignored.
*/
void PmProcessRequest(PmMaster *const master, const u32 *pload)
{
(Unterlassung)
case PM_SYSTEM_SHUTDOWN:
PmSystemShutdown(master, pload[1], pload[2]);
break;
(Unterlassung)
}
PmSystemShutdown()
PmSystemShutdown () befindet sich in pm_core.c.
pm_core.c
/**
* PmSystemShutdown() - Request system shutdown or restart
* @master Master requesting system shutdown
* @type Shutdown type
* @subtype Shutdown subtype
*/
static void PmSystemShutdown(PmMaster* const master, const u32 type,
const u32 subtype)
{
s32 status = XST_SUCCESS;
PmInfo("%s> SystemShutdown(%lu, %lu)\\r\\n", master->name, type, subtype);
/* For shutdown type the subtype is irrelevant: shut the caller down */
if (PMF_SHUTDOWN_TYPE_SHUTDOWN == type) {
status = PmMasterFsm(master, PM_MASTER_EVENT_FORCE_DOWN);
#if defined(BOARD_SHUTDOWN_PIN) && defined(BOARD_SHUTDOWN_PIN_STATE)
if (PMF_SHUTDOWN_SUBTYPE_SYSTEM == subtype) {
PmKillBoardPower();
}
#endif
goto done;
}
if (PMF_SHUTDOWN_TYPE_RESET != type) {
status = XST_INVALID_PARAM;
goto done;
}
/* Now distinguish the restart scope depending on the subtype */
switch (subtype) {
case PMF_SHUTDOWN_SUBTYPE_SUBSYSTEM:
status = PmMasterRestart(master);
break;
case PMF_SHUTDOWN_SUBTYPE_PS_ONLY:
XPfw_ResetPsOnly();
break;
case PMF_SHUTDOWN_SUBTYPE_SYSTEM:
XPfw_ResetSystem();
break;
default:
PmLog(PM_ERRNO_INVALID_SUBTYPE, subtype, master->name);
status = XST_INVALID_PARAM;
break;
}
done:
IPI_RESPONSE1(master->ipiMask, status);
}
Der Fokus liegt hier darauf, was passiert, wenn BOARD_SHUTDOWN_PIN und BOARD_SHUTDOWN_PIN_STATE definiert werden. In diesem Teil wird PmKillBoardPower () aufgerufen, wenn der Typ des PM-API-Aufrufs PMF_SHUTDOWN_TYPE_SHUTDOWN und der Subtyp PMF_SHUTDOWN_SUBTYPE_SYSTEM ist.
PmKillBoardPower()
PmKillBoardPower () befindet sich in pm_core.c.
pm_core.c
/**
* PmKillBoardPower() - Power-off board by sending KILL signal to power chip
*/
#if defined(BOARD_SHUTDOWN_PIN) && defined(BOARD_SHUTDOWN_PIN_STATE)
static void PmKillBoardPower(void)
{
u32 reg = XPfw_Read32(PMU_LOCAL_GPO1_READ);
u32 mask = PMU_IOMODULE_GPO1_MIO_0_MASK << BOARD_SHUTDOWN_PIN;
u32 value = BOARD_SHUTDOWN_PIN_STATE << BOARD_SHUTDOWN_PIN;
u32 mioPinOffset;
mioPinOffset = IOU_SLCR_MIO_PIN_34_OFFSET + (BOARD_SHUTDOWN_PIN - 2U)*4U;
reg = (reg & (~mask)) | (mask & value);
XPfw_Write32(PMU_IOMODULE_GPO1, reg);
/* Configure board shutdown pin to be controlled by the PMU */
XPfw_RMW32((IOU_SLCR_BASE + mioPinOffset),
0x000000FEU, 0x00000008U);
}
#endif
In diesem PmKillBoardPower () wird der angegebene MIO (MIO34-Port auf Ultra96-V2) auf L gesetzt, um die Karte während eines PM-API-Aufrufs zum Herunterfahren auszuschalten. Insbesondere wird nach dem Setzen des angegebenen Werts (0 für Ultra96-V2) auf das Bit (GPO2 für Ultra96-V2), das dem Port des GPO-Registers entspricht, das angegebene MIO (MIO34-Port für Ultra96-V2) ausgegeben. Ich bin im Modus.
XPfw_PmWakeHandler()
Das Eingangssignal vom ZynqMP MIO26-Port ist mit GPI0 auf der PMU verbunden. Wenn dieses Signal eingegeben wird, wird die PMU unterbrochen. Der Interrupt-Handler XPfw_PmWakeHandler () befindet sich in pm_binding.c.
pm_binding.c
/**
* XPfw_PmWakeHandler() - Call from GPI1 interrupt to process wake request
* @srcMask Value read from GPI1 register which determines interrupt source
*
* @return Status of performing wake-up (XST_INVALID_PARAM if wake is a
* processor wake event but processor is not found, status of
* performing wake otherwise)
*
* @note Call from GPI1 interrupt routine to process wake request. Must not
* clear GPI1 interrupt before this function returns.
* If the wake source is one of GIC wakes, source of the interrupt
* (peripheral that actually generated interrupt to GIC) cannot be
* determined, and target should be immediately woken-up (target is
* processor whose GIC wake bit is set in srcMask). If the wake is the
* FPD GIC Proxy interrupt, the APU needs to be woken up.
*/
s32 XPfw_PmWakeHandler(const u32 srcMask)
{
s32 status = XST_INVALID_PARAM;
#if defined(PMU_MIO_INPUT_PIN) && (PMU_MIO_INPUT_PIN >= 0U) \\
&& (PMU_MIO_INPUT_PIN <= 5U)
if ((PMU_IOMODULE_GPI1_MIO_WAKE_0_MASK << PMU_MIO_INPUT_PIN) == srcMask) {
PmShutdownInterruptHandler();
return XST_SUCCESS;
}
#endif
if (0U != (PMU_IOMODULE_GPI1_GIC_WAKES_ALL_MASK & srcMask)) {
/* Processor GIC wake */
PmProc* proc = PmProcGetByWakeMask(srcMask);
if ((NULL != proc) && (NULL != proc->master)) {
status = PmMasterWakeProc(proc);
} else {
status = XST_INVALID_PARAM;
}
} else if (0U != (PMU_IOMODULE_GPI1_FPD_WAKE_GIC_PROXY_MASK & srcMask)) {
status = PmMasterWake(&pmMasterApu_g);
} else if (0U != (PMU_IOMODULE_GPI1_MIO_WAKE_ALL_MASK & srcMask)) {
status = PmExternWakeMasters();
} else if (0U != (PMU_IOMODULE_GPI1_USB_0_WAKE_MASK & srcMask)) {
status = PmWakeMasterBySlave(&pmSlaveUsb0_g.slv);
} else if (0U != (PMU_IOMODULE_GPI1_USB_1_WAKE_MASK & srcMask)) {
status = PmWakeMasterBySlave(&pmSlaveUsb1_g.slv);
} else {
}
return status;
}
Der hier zu beachtende Punkt ist PmShutdownInterruptHandler (), der aufgerufen wird, wenn PMU_MIO_INPUT_PIN definiert ist und sein Wert im Bereich von 0 bis 5 liegt.
PmShutdownInterruptHandler()
PmShutdownInterruptHandler () befindet sich in pm_core.c.
pm_core.c
/**
* PmShutdownInterruptHandler() - Send suspend request to all active masters
*/
void PmShutdownInterruptHandler(void)
{
#if defined(PMU_MIO_INPUT_PIN) && (PMU_MIO_INPUT_PIN >= 0U) \\
&& (PMU_MIO_INPUT_PIN <= 5U)
/*
* Default status of MIO26 pin is 1. So MIO wake event bit in GPI1
* register is always 1, which is used to identify shutdown event.
*
* GPI event occurs only when any bit of GPI register changes from
* 0 to 1. When any GPI1 event occurs Gpi1InterruptHandler() checks
* GPI1 register and process interrupts for the bits which are 1.
* Because of MIO wake bit is 1 in GPI1 register, shutdown handler
* will be called every time when any of GPI1 event occurs.
*
* There is no way to identify which bit cause GPI1 interrupt.
* So every time Gpi1InterruptHandler() is checking bit which are 1
* And calls respective handlers.
*
* To handle such case avoid power off when any other (other than MIO
* wake)bit in GPI1 register is 1. If no other bit is 1 in GPI1 register
* and still PMU gets GPI1 interrupt means that MIO26 pin state is
* changed from (1 to 0 and 0 to 1). In this case it is confirmed that
* it is event for shutdown only and not because of other events.
* There are chances that some shutdown events are missed (1 out of 50)
* but it should not harm.
*/
if (XPfw_Read32(PMU_IOMODULE_GPI1) !=
(PMU_IOMODULE_GPI1_MIO_WAKE_0_MASK << PMU_MIO_INPUT_PIN)) {
return;
}
#endif
u32 rpu_mode = XPfw_Read32(RPU_RPU_GLBL_CNTL);
if (PM_MASTER_STATE_ACTIVE == PmMasterIsActive(&pmMasterApu_g)) {
PmInitSuspendCb(&pmMasterApu_g,
SUSPEND_REASON_SYS_SHUTDOWN, 1U, 0U, 0U);
}
if (0U == (rpu_mode & RPU_RPU_GLBL_CNTL_SLSPLIT_MASK)) {
if (PM_MASTER_STATE_ACTIVE == PmMasterIsActive(&pmMasterRpu0_g)) {
PmInitSuspendCb(&pmMasterRpu0_g,
SUSPEND_REASON_SYS_SHUTDOWN, 1U, 0U, 0U);
}
if (PM_MASTER_STATE_ACTIVE == PmMasterIsActive(&pmMasterRpu1_g)) {
PmInitSuspendCb(&pmMasterRpu1_g,
SUSPEND_REASON_SYS_SHUTDOWN, 1U, 0U, 0U);
}
} else {
if (PM_MASTER_STATE_ACTIVE == PmMasterIsActive(&pmMasterRpu_g)) {
PmInitSuspendCb(&pmMasterRpu_g,
SUSPEND_REASON_SYS_SHUTDOWN, 1U, 0U, 0U);
}
}
}
PmShutdownInterruptHandler () überprüft den Status jedes Prozessors (APU, RPU0, RPU1, RPU) und fordert an, dass jeder Prozessor angehalten wird, wenn er aktiv ist. Eine APU unter Linux akzeptiert diese Suspend-Anforderung und führt die Shutdown-Sequenz aus.
xpfw_config.h
PMU_MIO_INPUT_PIN, BOARD_SHUTDOWN_PIN und BOARD_SHUTDOWN_PIN_STATE sind in xpfw_config.h definiert.
xpfw_config.h
(Unterlassung)
/*
* PMU Firmware code include options
*
* PMU Firmware by default disables some functionality and enables some
* Here we are listing all the build flags with the default option.
* User can modify these flags to enable or disable any module/functionality
* - ENABLE_PM : Enables Power Management Module
* - ENABLE_EM : Enables Error Management Module
* - ENABLE_SCHEDULER : Enables the scheduler
* - ENABLE_RECOVERY : Enables WDT based restart of APU sub-system
* - ENABLE_RECOVERY_RESET_SYSTEM : Enables WDT based restart of system
* - ENABLE_RECOVERY_RESET_PS_ONLY : Enables WDT based restart of PS
* - ENABLE_ESCALATION : Enables escalation of sub-system restart to
* SRST/PS-only if the first restart attempt fails
* - ENABLE_WDT : Enables WDT based restart functionality for PMU
* - ENABLE_STL : Enables STL Module
* - ENABLE_RTC_TEST : Enables RTC Event Handler Test Module
* - ENABLE_IPI_CRC_VAL : Enables CRC calculation for IPI messages
* - ENABLE_FPGA_LOAD : Enables FPGA bit stream loading feature
* - ENABLE_SECURE : Enables security features
* - XPU_INTR_DEBUG_PRINT_ENABLE : Enables debug for XMPU/XPPU functionality
*
* - PM_LOG_LEVEL : Enables print based debug functions for PM. Possible
* values are: 1 (alerts), 2 (errors), 3 (warnings),
* 4 (info). Higher numbers include the debug scope of
* lower number, i.e. enabling 3 (warnings) also enables
* 1 (alerts) and 2 (errors).
* - IDLE_PERIPHERALS : Enables idling peripherals before PS or System reset
* - ENABLE_NODE_IDLING : Enables idling and reset of nodes before force
* of a sub-system
* - DEBUG_MODE : This macro enables PM debug prints if XPFW_DEBUG_DETAILED
* macro is also defined
* - ENABLE_POS : Enables Power Off Suspend feature
* - ENABLE_DDR_SR_WR : Enables DDR self refresh over warm restart feature
* - ENABLE_UNUSED_RPU_PWR_DWN : Enables unused RPU power down feature
* - DISABLE_CLK_PERMS : Disable clock permission checking (it is not safe
* to ever disable clock permission checking). Do this at
* your own responsibility.
* - ENABLE_EFUSE_ACCESS : Enables efuse access feature
*
* These macros are specific to ZCU100 design where it uses GPO1[2] as a
* board power line and
* - PMU_MIO_INPUT_PIN : Enables board shutdown related code for ZCU100
* - BOARD_SHUTDOWN_PIN : Tells board shutdown pin. In case of ZCU100,
* GPO1[2] is the board power line.
* - BOARD_SHUTDOWN_PIN_STATE : Tells what should be the state of board power
* line when system shutdown request comes
*/
#define ENABLE_PM_VAL (1U)
#define ENABLE_EM_VAL (0U)
#define ENABLE_SCHEDULER_VAL (0U)
#define ENABLE_RECOVERY_VAL (0U)
#define ENABLE_RECOVERY_RESET_SYSTEM_VAL (0U)
#define ENABLE_RECOVERY_RESET_PS_ONLY_VAL (0U)
#define ENABLE_ESCALATION_VAL (0U)
#define CHECK_HEALTHY_BOOT_VAL (0U)
#define ENABLE_WDT_VAL (0U)
#define ENABLE_CUSTOM_MOD_VAL (0U)
#define ENABLE_STL_VAL (0U)
#define ENABLE_RTC_TEST_VAL (0U)
#define ENABLE_IPI_CRC_VAL (0U)
#define ENABLE_FPGA_LOAD_VAL (1U)
#define ENABLE_SECURE_VAL (1U)
#define ENABLE_EFUSE_ACCESS (0U)
#define XPU_INTR_DEBUG_PRINT_ENABLE_VAL (0U)
#define PM_LOG_LEVEL_VAL (0U)
#define IDLE_PERIPHERALS_VAL (0U)
#define ENABLE_NODE_IDLING_VAL (0U)
#define DEBUG_MODE_VAL (0U)
#define ENABLE_POS_VAL (0U)
#define ENABLE_DDR_SR_WR_VAL (0U)
#define DISABLE_CLK_PERMS_VAL (0U)
#define ENABLE_UNUSED_RPU_PWR_DWN_VAL (1U)
#define PMU_MIO_INPUT_PIN_VAL (0U)
#define BOARD_SHUTDOWN_PIN_VAL (1U)
#define BOARD_SHUTDOWN_PIN_STATE_VAL (1U)
#define PMU_MIO_INPUT_PIN_VAL (0U)
#define BOARD_SHUTDOWN_PIN_VAL (0U)
#define BOARD_SHUTDOWN_PIN_STATE_VAL (0U)
:
(Unterlassung)
:
#if PMU_MIO_INPUT_PIN_VAL
#define PMU_MIO_INPUT_PIN 0U
#endif
#if BOARD_SHUTDOWN_PIN_VAL
#define BOARD_SHUTDOWN_PIN 2U
#endif
#if BOARD_SHUTDOWN_PIN_STATE_VAL
#define BOARD_SHUTDOWN_PIN_STATE 0U
#endif
:
(Unterlassung)
BOARD_SHUTDOWN_PIN ist die Portnummer des Gruppenrichtlinienobjekts. Der Ultra96-V2 ist auf 2 eingestellt, um das an den MIO34-Port angeschlossene GPO2 anzuzeigen.
BOARD_SHUTDOWN_PIN_STATE ist der Wert, der an den GPO-Port ausgegeben wird. Ultra96-V2 gibt 0 (niedrig) aus.
PMU_MIO_INPUT_PIN ist die Portnummer des GPI. Der Ultra96-V2 ist auf 0 gesetzt, was anzeigt, dass GPI0 an den MIO26-Port angeschlossen ist.
Zum Erstellen von PMUFW sind Beispielinformationen zur FPGA-Design-Hardware erforderlich. Erstellen Sie das Ziel / Ultra96-V2 / build-v2019.1 / fpga / project.sdk / design_1 \ _wrapper.hdf unter [Erstellen eines einfachen FPGA-Designs].
Ändern Sie xpfw_config.h beim Erstellen der PMUFW. Setzen Sie PMU_MIO_INPUT_PIN_VAL, BOARD_SHUTDOWN_PIN_VAL und BOARD_SHUTDOWN_PIN_STATE_VAL auf 1U.
Es ist eine gute Idee, beim Erstellen ein Skript wie das folgende zu verwenden.
Tcl:target/Ultra96-V2/build-v2019.1/fpga/build_zynqmp_pmufw.hsi
#!/usr/bin/tclsh
set app_name "pmufw"
set app_type "zynqmp_pmufw"
set hwspec_file "design_1_wrapper.hdf"
set proc_name "psu_pmu_0"
set project_name "project"
set project_dir [pwd]
set sdk_workspace [file join $project_dir $project_name.sdk]
set app_dir [file join $sdk_workspace $app_name]
set app_release_dir [file join [pwd] ".." ]
set app_release_elf "zynqmp_pmufw.elf"
set board_shutdown true
set board_power_sw true
set hw_design [hsi::open_hw_design [file join $sdk_workspace $hwspec_file]]
hsi::generate_app -hw $hw_design -os standalone -proc $proc_name -app $app_type -dir $app_dir
if {$board_shutdown || $board_power_sw} {
file copy -force [file join $app_dir "xpfw_config.h"] [file join $app_dir "xpfw_config.h.org"]
set xpfw_config_old [open [file join $app_dir "xpfw_config.h.org"] r]
set xpfw_config_new [open [file join $app_dir "xpfw_config.h.new"] w]
while {[gets $xpfw_config_old line] >= 0} {
if {$board_shutdown && [regexp {^#define\\s+BOARD_SHUTDOWN_PIN_VAL\\s+\\S+} $line]} {
puts $xpfw_config_new "#define BOARD_SHUTDOWN_PIN_VAL (1U)"
} elseif {$board_shutdown && [regexp {^#define\\s+BOARD_SHUTDOWN_PIN_STATE_VAL\\s+\\S+} $line]} {
puts $xpfw_config_new "#define BOARD_SHUTDOWN_PIN_STATE_VAL (1U)"
} elseif {$board_power_sw && [regexp {^#define\\s+PMU_MIO_INPUT_PIN_VAL\\s+\\S+} $line]} {
puts $xpfw_config_new "#define PMU_MIO_INPUT_PIN_VAL (1U)"
} else {
puts $xpfw_config_new $line
}
}
close $xpfw_config_old
close $xpfw_config_new
file rename -force [file join $app_dir "xpfw_config.h.new"] [file join $app_dir "xpfw_config.h"]
}
exec make -C $app_dir all >&@ stdout
file copy -force [file join $app_dir "executable.elf"] [file join $app_release_dir $app_release_elf]
Wenn Sie build_zynqmp_pmufw.hsi unter Vivado ausführen, wird das Ziel / Ultra96-V2 / build-v2019.1 / zynqmp_pmufw.elf generiert.
vivado% cd target/Ultra96-V2/build-v2019.1/fpga/
vivado% hsi -mode tcl -source build_zynqmp_pmufw.hsi
Hinweis) Ab Vivado 2019.2 ist das Vivado SDK veraltet und in Vitis integriert, sodass die oben beschriebene Methode nicht funktioniert. Der Hauptunterschied besteht darin, dass der Befehl hsi veraltet und durch den Befehl xsct ersetzt wurde und die Hardware-Info-Datei (hwspec_file) die Erweiterung .xsa anstelle von .hdf hat. Informationen zum Erstellen von FSBL mit Vitis finden Sie unter [Tcl-Skript zum Erstellen von Zynq FSBL (First Stage Boot Loader) mit Vivado (Vitis)] [Tcl-Skript zum Erstellen von FSBL mit Vitis].
Tcl:target/Ultra96-V2/build-v2019.2/fpga/build_zynqmp_pmufw.tcl
:
(target/Ultra96-V2/build-v2019.1/fpga/build_zynqmp_pmufw.Gleich wie hci)
:
set hwspec_file "design_1_wrapper.xsa"
:
(target/Ultra96-V2/build-v2019.1/fpga/build_zynqmp_pmufw.Gleich wie hci)
:
vivado% cd target/Ultra96-V2/build-v2019.2/fpga/
vivado% xsct build_zynqmp_pmufw.tcl
Integrieren Sie zynqmp_pmufw.elf, das im vorherigen Abschnitt erstellt wurde, in BOOT.BIN. Siehe insbesondere [BOOT.BIN erstellen].
Booten Sie Linux mit der im vorherigen Abschnitt erstellten BOOT.BIN. Durch Herunterfahren mit dem Ausschaltbefehl wird der Ultra96-V2 ausgeschaltet. Wenn der Ultra96-V2 ausgeschaltet ist, erlischt die Einschalt-LED (blaue LED) und der Luftkühlungslüfter stoppt.
Wenn Sie während des Bootens von Linux den Netzschalter (SW4) drücken, wechselt Linux in die Abschaltsequenz und der Ultra96-V2 wird ausgeschaltet.
root@debian-fpga:~# poweroff
[ OK ] Stopped target Sound Card.
[ OK ] Stopped tar■ OK ] Stopped Daily man-db regeneration.
[ OK ] Stopped target Multi-User System.
:
(Unterlassung)
:
[ OK ] Reached target Shutdown.
[ OK ] Reached target Final Step.
[ OK ] Started Power-Off.
[ OK ] Reached target Power-Off.
[ 226.399206] systemd-shutdow: 29 output lines suppressed due to ratelimiting
[ 226.486399] systemd-shutdown[1]: Syncing filesystems and block devices.
[ 226.581506] systemd-shutdown[1]: Sending SIGTERM to remaining processes...
[ 226.596568] systemd-journald[1777]: Received SIGTERM from PID 1 (systemd-shutdow).
[ 226.617967] systemd-shutdown[1]: Sending SIGKILL to remaining processes...
[ 226.631598] systemd-shutdown[1]: Unmounting file systems.
[ 226.639081] [3538]: Remounting '/' read-only in with options '(null)'.
[ 226.678576] EXT4-fs (mmcblk0p2): re-mounted. Opts: (null)
[ 226.698640] systemd-shutdown[1]: All filesystems unmounted.
[ 226.704248] systemd-shutdown[1]: Deactivating swaps.
[ 226.709451] systemd-shutdown[1]: All swaps deactivated.
[ 226.714691] systemd-shutdown[1]: Detaching loop devices.
[ 226.722646] systemd-shutdown[1]: All loop devices detached.
[ 226.728233] systemd-shutdown[1]: Detaching DM devices.
[ 226.745079] usb 1-1: USB disconnect, device number 2
[ 226.750065] usb 1-1.4: USB disconnect, device number 3
[ 226.869502] usb 2-1: USB disconnect, device number 2
[ 226.911441] reboot: Power down
Die in Building Simple FPGA Design erstellten Hardwareinformationen enthalten psu_init.c zum Konfigurieren der ZynqMP-Ports. psu_init.c enthält ein Programm für den Stage 1 Boot Loader (FSBL) zum Festlegen des Ports für ZynqMP. In psu_init.c, das für Ultra96-V2 erstellt wurde, gibt es einen merkwürdigen Teil.
psu_init.c
/*
* Register : MIO_PIN_33 @ 0XFF180084
* Level 0 Mux Select 0= Level 1 Mux Output 1= gem0, Input, gem0_rgmii_rxd[
* 0]- (RX RGMII data)
* PSU_IOU_SLCR_MIO_PIN_33_L0_SEL 0
* Level 1 Mux Select 0= Level 2 Mux Output 1= pcie, Input, pcie_reset_n- (
* PCIE Reset signal)
* PSU_IOU_SLCR_MIO_PIN_33_L1_SEL 0
* Level 2 Mux Select 0= Level 3 Mux Output 1= pmu, Output, pmu_gpo[1]- (PM
* U GPI) 2= test_scan, Input, test_scan_in[33]- (Test Scan Port) = test_sc
* an, Output, test_scan_out[33]- (Test Scan Port) 3= csu, Input, csu_ext_t
* amper- (CSU Ext Tamper)
* PSU_IOU_SLCR_MIO_PIN_33_L2_SEL 1
* Level 3 Mux Select 0= gpio1, Input, gpio_1_pin_in[7]- (GPIO bank 1) 0= g
* pio1, Output, gpio_1_pin_out[7]- (GPIO bank 1) 1= can1, Input, can1_phy_
* rx- (Can RX signal) 2= i2c1, Input, i2c1_sda_input- (SDA signal) 2= i2c1
* , Output, i2c1_sda_out- (SDA signal) 3= swdt1, Output, swdt1_rst_out- (W
* atch Dog Timer Output clock) 4= spi1, Output, spi1_n_ss_out[2]- (SPI Mas
* ter Selects) 5= ttc3, Output, ttc3_wave_out- (TTC Waveform Clock) 6= ua1
* , Input, ua1_rxd- (UART receiver serial input) 7= trace, Output, tracedq
* [11]- (Trace Port Databus)
* PSU_IOU_SLCR_MIO_PIN_33_L3_SEL 0
* Configures MIO Pin 33 peripheral interface mapping
* (OFFSET, MASK, VALUE) (0XFF180084, 0x000000FEU ,0x00000008U)
*/
PSU_Mask_Write(IOU_SLCR_MIO_PIN_33_OFFSET, 0x000000FEU, 0x00000008U);
/*##################################################################### */
/*
* Register : MIO_PIN_35 @ 0XFF18008C
* Level 0 Mux Select 0= Level 1 Mux Output 1= gem0, Input, gem0_rgmii_rxd[
* 2]- (RX RGMII data)
* PSU_IOU_SLCR_MIO_PIN_35_L0_SEL 0
* Level 1 Mux Select 0= Level 2 Mux Output 1= pcie, Input, pcie_reset_n- (
* PCIE Reset signal)
* PSU_IOU_SLCR_MIO_PIN_35_L1_SEL 0
* Level 2 Mux Select 0= Level 3 Mux Output 1= pmu, Output, pmu_gpo[3]- (PM
* U GPI) 2= test_scan, Input, test_scan_in[35]- (Test Scan Port) = test_sc
* an, Output, test_scan_out[35]- (Test Scan Port) 3= dpaux, Input, dp_hot_
* plug_detect- (Dp Aux Hot Plug)
* PSU_IOU_SLCR_MIO_PIN_35_L2_SEL 0
* Level 3 Mux Select 0= gpio1, Input, gpio_1_pin_in[9]- (GPIO bank 1) 0= g
* pio1, Output, gpio_1_pin_out[9]- (GPIO bank 1) 1= can0, Output, can0_phy
* _tx- (Can TX signal) 2= i2c0, Input, i2c0_sda_input- (SDA signal) 2= i2c
* 0, Output, i2c0_sda_out- (SDA signal) 3= swdt0, Output, swdt0_rst_out- (
* Watch Dog Timer Output clock) 4= spi1, Input, spi1_n_ss_in- (SPI Master
* Selects) 4= spi1, Output, spi1_n_ss_out[0]- (SPI Master Selects) 5= ttc2
* , Output, ttc2_wave_out- (TTC Waveform Clock) 6= ua0, Output, ua0_txd- (
* UART transmitter serial output) 7= trace, Output, tracedq[13]- (Trace Po
* rt Databus)
* PSU_IOU_SLCR_MIO_PIN_35_L3_SEL 0
* Configures MIO Pin 35 peripheral interface mapping
* (OFFSET, MASK, VALUE) (0XFF18008C, 0x000000FEU ,0x00000000U)
*/
PSU_Mask_Write(IOU_SLCR_MIO_PIN_35_OFFSET, 0x000000FEU, 0x00000000U);
/*##################################################################### */
Wie Sie sehen können, fehlt der MIO34-Port vollständig. Mit anderen Worten, der Stage 1 Bootloader (FSBL) konfiguriert den MIO34-Port nicht. Der MIO34-Port wird festgelegt, wenn PMUFW (Platform Management Unit Firmware) PmKillBoardPower () L an den MIO34-Port ausgibt. Zu diesem Zeitpunkt ist der MIO34-Port geöffnet und der KILL_N-Port am Ein- / Ausschalt-LSI ist H, da er hochgezogen wurde.
Dies ist eine Selbstverständlichkeit, wenn Sie die Startsequenz berücksichtigen. Während der Bootloader der Stufe 1 ausgeführt wird, wird PMUFW noch nicht ausgeführt, sodass GPO2 auf der PMU standardmäßig 0 ist. Wenn Sie den MIO34-Port in diesen Zustand versetzen, wird 0 (= Niedrig) in GPO2 der PMU an den MIO34-Port ausgegeben.
Mit anderen Worten, es wird ausgeschaltet, während der Stage 1-Bootloader ausgeführt wird. Um dies zu verhindern, konfiguriert psu_init.c den MIO34-Port wahrscheinlich nicht.
Betrachtet man den im vorherigen Abschnitt erläuterten Inhalt von psu_init.c und den Quellcode von PMUFW (insbesondere xpfw_config.h), so scheint der Port beim Ausschalten mit ZynqMP auf den MIO34-Port festgelegt zu sein.
Wenn Sie eine Karte mit ZynqMP entwerfen und ZynqMP ausschalten möchten, sollten Sie den MIO34-Port verwenden.
Der Gerätebaum, der zum Booten von Linux unter Ultra96 / Ultra96-V2 verwendet wird, weist die folgenden Knoten auf:
arch/arm64/boot/dts/xilinx/avnet-ultra96v2-rev1.dts
// SPDX-License-Identifier: GPL-2.0+
/*
* dts file for Avnet Ultra96-V2 rev1
*
*/
/dts-v1/;
:
(Unterlassung)
:
ltc2954: ltc2954 { /* U7 */
compatible = "lltc,ltc2954", "lltc,ltc2952";
status = "disabled";
trigger-gpios = <&gpio 26 GPIO_ACTIVE_LOW>; /* INT line - input */
/* If there is HW watchdog on mezzanine this signal should be connected there */
watchdog-gpios = <&gpio 35 GPIO_ACTIVE_HIGH>; /* MIO on PAD */
kill-gpios = <&gpio 34 GPIO_ACTIVE_LOW>; /* KILL signal - output */
};
:
(Unterlassung)
Dieser Knoten scheint einen Gerätetreiber zu definieren, der die LSI steuert, die ihn ein- und ausschaltet. Wie unter Konfigurieren von MIO26 / MIO34-Ports in ZynqMP beschrieben, konfiguriert Ultra96-V2 die MIO26 / MIO34-Ports so, dass sie von der PMU gesteuert werden und nicht von einer APU unter Linux gesteuert werden können. Daher ist dieser Knoten bedeutungslos und sollte deaktiviert werden. Geben Sie in der Statuseigenschaft insbesondere "disabled" an.
[Bootloader]: https://qiita.com/ikwzm/items/9c78e83298906447fe5d "Erstellen von Debian GNU / Linux (Version v2018.2) für Ultra96 (Bootloader)" @Qiita " [Einfaches FPGA-Design erstellen]: https://qiita.com/ikwzm/items/0489b02962c6f0455783 "Erstellen von Debian GNU / Linux (Version v2018.2) für Ultra96 (Beispiel-FPGA-Design)" @Qiita " [PMUFW erstellen]: https://qiita.com/ikwzm/items/00024adf956696dd51c6 "Erstellen von Debian GNU / Linux (Version v2018.2) für Ultra96 (PMUFW-Edition)" @Qiita " [BOOT.BIN erstellen]: https://qiita.com/ikwzm/items/af4420edd262e14feef9 "Erstellen von Debian GNU / Linux (Version v2018.2) für Ultra96 (BOOT.BIN-Edition)" @Qiita " [Tcl-Skript zum Erstellen von FSBL mit Vitis]: https://qiita.com/ikwzm/items/165481921c3e984a9e70 "Tcl-Skript zum Erstellen von Zynq FSBL (First Stage Boot Loader) mit Vivado (Vitis)" @Qiita " [ZynqMP-Boot- und Energieverwaltung]: https://www.slideshare.net/ssuser479fa3/zynq-mp-58490589 "" ZynqMP-Boot- und Energieverwaltung "@Vengineer ZynqMP-Lernsitzungsmaterialien (20.02.2016)" [UG1085]: https://www.xilinx.com/support/documentation/user_guides/ug1085-zynq-ultrascale-trm.pdf "「Zynq UltraScale+ MPSoC Technical Reference Manual, UG1085(v1.7) December 22,2017」" [UG1137]: https://www.xilinx.com/support/documentation/user_guides/ug1137-zynq-ultrascale-mpsoc-swdev.pdf "「Zynq UltraScale+ MPSoC Software Developer Guide, UG1137(v5.0) November 15,2017)」"
Recommended Posts