So schalten Sie Linux unter Ultra96-V2 aus

Einführung

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.

Ausschaltmechanismus

Stromkreis um Ausschalten

Abb.1 zeigt die Schaltung um das Ausschalten von Ultra96-V2.

Fig.1 Ultra96-V2 の MIO34_POWER_KILL_N 信号

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.

Konfiguration des ZynqMP MIO26 / MIO34-Ports

Abbildung 2 zeigt, wie die ZynqMP MIO26- und MIO34-Ports in Vivado auf dem Ultra96-V2 konfiguriert sind.

Fig.2 Ultra96-V2 の ZynqMP の MIO26/MIO34 ポートの設定

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.

Ändern Sie BOOT.BIN

Fix PMUFW

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

Gebäude BOOT.BIN

Integrieren Sie zynqmp_pmufw.elf, das im vorherigen Abschnitt erstellt wurde, in BOOT.BIN. Siehe insbesondere [BOOT.BIN erstellen].

Ergebnis

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

Beiseite

Das Wunder von psu_init.c

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.

Ist nur der MIO34-Port ausgeschaltet?

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.

Gerätebaum LTC2954-Knoten

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.

Referenz

[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

So schalten Sie Linux unter Ultra96-V2 aus
Wie aktualisiere ich mit SQLAlchemy?
Wie man mit Theano besetzt
Wie mit SQLAlchemy ändern?
So trennen Sie Zeichenfolgen mit ','
Wie man RDP auf Fedora31 macht
Wie lösche ich mit SQLAlchemy?
Wie man Conda fernhält
So brechen Sie RT mit tweepy ab
Python: So verwenden Sie Async mit
So installieren Sie Python-Pip mit Ubuntu20.04LTS
Umgang mit unausgeglichenen Daten
So installieren Sie VMware-Tools unter Linux
So installieren Sie MBDyn (Linux Ubuntu)
Wie fange ich mit Scrapy an?
Erste Schritte mit Python
Umgang mit dem DistributionNotFound-Fehler
Wie fange ich mit Django an?
Aufblasen von Daten (Datenerweiterung) mit PyTorch
So berechnen Sie das Datum mit Python
So installieren Sie den MySQL-Connector mit pip3
So überprüfen Sie die Linux-Betriebssystemversion
So verbinden Sie INNER mit SQL Alchemy
So installieren Sie Anaconda mit pyenv
So erhalten Sie den gesamten Datenverkehr über VPN mit OpenVPN unter Linux
So führen Sie eine arithmetische Verarbeitung mit der Django-Vorlage durch
Wie baue ich meinen eigenen Linux-Server?
[Blender] So legen Sie shape_key mit dem Skript fest
So erhalten Sie die Eltern-ID mit sqlalchemy
So fügen Sie ein Paket mit PyCharm hinzu
Ich möchte wissen, wie LINUX funktioniert!
So installieren Sie DLIB mit aktiviertem 2020 / CUDA
Verwendung von ManyToManyField mit Djangos Admin
Verwendung von OpenVPN mit Ubuntu 18.04.3 LTS
Verwendung von Cmder mit PyCharm (Windows)
[Linux] Verwendung des Befehls echo
So arbeiten Sie mit BigQuery in Python
So aktualisieren Sie PHP unter Amazon Linux 2
Wie man Ass / Alembic mit HtoA benutzt
Umgang mit Enum-Kompatibilitätsfehlern
So zeigen Sie Piktogramme unter Manjaro Linux an
Verwendung von Japanisch mit NLTK-Plot
Wie man einen Taschentest mit Python macht
So suchen Sie in Google Colaboratory nach Google Drive
So zeigen Sie Python-Japanisch mit Lolipop an
So installieren Sie Pakete unter Alpine Linux
So laden Sie YouTube-Videos mit youtube-dl herunter
Stellen Sie über einen Remotedesktop eine Verbindung zu GNU / Linux her
Verwendung des Jupyter-Notebooks mit ABCI
So bedienen Sie Linux von der Konsole aus
So installieren Sie das Windows-Subsystem für Linux