Comment mettre hors tension de Linux sur Ultra96-V2

introduction

L'Ultra96-V2 a le signal de sortie du port d'E / S ZynqMP connecté au port d'entrée KILL_N du LSI de mise sous / hors tension. Si ce signal est réglé sur L, l'Ultra96-V2 peut être mis hors tension.

Cependant, il semble que ce signal ne puisse pas être contrôlé lorsque BOOT.BIN et Linux sont construits par la méthode habituelle, et même si l'arrêt est exécuté à partir de Linux par la commande poweroff etc., l'Ultra96-V2 ne passe pas à l'état de mise hors tension. Hmm. À propos, lorsque vous éteignez l'appareil, vous devez appuyer sur le bouton d'alimentation (SW4) et le maintenir enfoncé, mais appuyer et maintenir le petit bouton est assez douloureux pour vos doigts (c'est le motif).

Dans cet article, en modifiant le PMUFW (Platform Management Unit Firmware) inclus dans BOOT.BIN, lorsqu'un arrêt est exécuté à partir de Linux par la commande poweroff etc., ce signal est mis à L et l'Ultra96-V2 est automatiquement mis hors tension. Voici comment procéder.

Il montre également comment arrêter Linux lorsque vous appuyez sur le bouton d'alimentation pendant le démarrage de Linux.

Mécanisme de mise hors tension

Circuit autour de la mise hors tension

La figure 1 montre le circuit autour de la mise hors tension de l'Ultra96-V2.

Fig.1 Ultra96-V2 の MIO34_POWER_KILL_N 信号

Fig.1 Signal Ultra96-V2 MIO34_POWER_KILL_N


Le port KILL_N du LSI (SLG4G42480V) qui s'allume / s'éteint est connecté au port MIO34 de ZynqMP via un circuit de conversion de niveau. Le signal de sortie du port ZynqMP MIO34 est tiré vers le haut et fixé à H à partir du moment où l'alimentation est mise sous tension jusqu'à ce que le MIO34 soit configuré.

En sortant L à partir du port MIO34 de ZynqMP, le port d'entrée KILL_N du LSI à mettre sous / hors tension devient L et met l'Ultra96-V2 hors tension.

Le port INT du LSI (SLG4G42480V) qui s'allume / s'éteint est connecté au port MIO26 de ZynqMP.

Configuration du port ZynqMP MIO26 / MIO34

La figure 2 montre comment les ports ZynqMP MIO26 et MIO34 sont configurés dans Vivado sur l'Ultra96-V2.

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

Fig.2 Paramètres du port Ultra96-V2 ZynqMP MIO26 / MIO34


Dans Ultra96-V2, le port MIO26 de ZynqMP est configuré pour se connecter à GPI0 de PMU (Platform Management Unit), et le port MIO34 est configuré pour se connecter à GPO2.

PMU(Platform Management Unit)

PMU (Platform Management Unit) est un sous-système intégré à ZynqMP pour mettre sous tension, réinitialiser et surveiller les ressources dans ZynqMP à l'aide d'interruptions interprocesseurs et de registres de gestion de l'alimentation. Le PMU se compose d'un processeur MicroBlaze, d'une ROM de 32 Ko et d'une RAM de 128 Ko. Immédiatement après la mise sous tension de ZynqMP, le PMU démarre d'abord pour exécuter le chargeur de démarrage Stage 0 dans la ROM. Le chargeur de démarrage de l'étape 0 charge le chargeur de démarrage de l'étape 1 (FSBL) contenu dans BOOT.BIN dans le stockage (carte SD, etc.) dans la RAM interne et transfère le contrôle à l'APU (Application Processing Unit).

PMUFW(Platform Management Unit Firmware)

Le chargeur de démarrage Stage 1 (FSBL) charge le PMUFW (Platform Management Unit Firmware) contenu dans BOOT.BIN dans la RAM du PMU. Le PMU met ensuite sous tension, réinitialise et surveille les ressources dans ZynqMP conformément au PMUFW. Il accepte également diverses demandes d'APU et de RPU en tant qu'appels système (appels PM API).

Lors de la mise hors tension sous Linux, vous appellerez éventuellement cet appel PMUFW shutdown PM API.

Veuillez vous référer à [Building PMUFW] pour le code source de PMUFW.

PmProcessRequest()

Lorsque le PMU accepte un appel PM API, il appelle PmProcessRequest () de PMUFW. PmProcessRequest () est défini dans pm_core.c.

Le PMU appelle PmSystemShutdown () lorsque l'appel de l'API PM est une demande d'arrêt.

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)
{
	(Omission)
	case PM_SYSTEM_SHUTDOWN:
		PmSystemShutdown(master, pload[1], pload[2]);
		break;
	(Omission)
}

PmSystemShutdown()

PmSystemShutdown () se trouve dans 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);
}

L'accent est mis ici sur ce qui se passe lorsque BOARD_SHUTDOWN_PIN et BOARD_SHUTDOWN_PIN_STATE sont définis. Dans cette partie, PmKillBoardPower () est appelé lorsque le type d'appel API PM est PMF_SHUTDOWN_TYPE_SHUTDOWN et le sous-type est PMF_SHUTDOWN_SUBTYPE_SYSTEM.

PmKillBoardPower()

PmKillBoardPower () se trouve dans 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

Ce PmKillBoardPower () est l'endroit où le MIO spécifié (port MIO34 sur Ultra96-V2) est mis en L pour mettre la carte hors tension pendant un appel PM API d'arrêt. Plus précisément, après avoir défini la valeur spécifiée (0 pour Ultra96-V2) sur le bit (GPO2 pour Ultra96-V2) correspondant au port du registre GPO, le MIO spécifié (port MIO34 pour Ultra96-V2) est émis. Je suis en mode.

XPfw_PmWakeHandler()

Le signal d'entrée du port ZynqMP MIO26 est connecté à GPI0 sur le PMU. Lorsque ce signal est entré, le PMU est interrompu. Son gestionnaire d'interruption XPfw_PmWakeHandler () se trouve dans 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;
}

Le point à noter ici est PmShutdownInterruptHandler (), qui est appelé si PMU_MIO_INPUT_PIN est défini et que sa valeur est comprise entre 0 et 5.

PmShutdownInterruptHandler()

PmShutdownInterruptHandler () se trouve dans 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 () vérifie l'état de chaque processeur (APU, RPU0, RPU1, RPU) et demande que chaque processeur soit suspendu s'il est actif. L'APU exécutant Linux accepte cette demande de suspension et exécute la séquence d'arrêt.

xpfw_config.h

PMU_MIO_INPUT_PIN, BOARD_SHUTDOWN_PIN et BOARD_SHUTDOWN_PIN_STATE sont définis dans xpfw_config.h.

xpfw_config.h


	(Omission)
/*
 * 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)
	:
	(Omission)
	:
#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
	:
	(Omission)

BOARD_SHUTDOWN_PIN est le numéro de port de l'objet de stratégie de groupe. L'Ultra96-V2 est réglé sur 2 pour indiquer le GPO2 connecté au port MIO34.

BOARD_SHUTDOWN_PIN_STATE est la valeur sortie vers le port GPO. Ultra96-V2 sorties 0 (faible).

PMU_MIO_INPUT_PIN est le numéro de port du GPI. L'Ultra96-V2 est réglé sur 0, ce qui indique que GPI0 est connecté au port MIO26.

Modifier BOOT.BIN

Réparer PMUFW

Des exemples d'informations sur le matériel de conception FPGA sont nécessaires pour créer PMUFW. Créez target / Ultra96-V2 / build-v2019.1 / fpga / project.sdk / design_1 \ _wrapper.hdf en vous référant à [Building Simple FPGA Design].

Modifiez xpfw_config.h lors de la construction du PMUFW. Plus précisément, définissez PMU_MIO_INPUT_PIN_VAL, BOARD_SHUTDOWN_PIN_VAL et BOARD_SHUTDOWN_PIN_STATE_VAL sur 1U.

C'est une bonne idée d'utiliser un script comme celui-ci lors de la construction.

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]

L'exécution de build_zynqmp_pmufw.hsi sur Vivado générera target / Ultra96-V2 / build-v2019.1 / zynqmp_pmufw.elf.

vivado% cd target/Ultra96-V2/build-v2019.1/fpga/
vivado% hsi -mode tcl -source build_zynqmp_pmufw.hsi

Remarque) Depuis Vivado 2019.2, le SDK Vivado est obsolète et intégré à Vitis, la méthode ci-dessus ne fonctionnera donc pas. La principale différence est que la commande hsi a été désapprouvée et remplacée par la commande xsct, et le fichier d'informations sur le matériel (hwspec_file) a une extension de .xsa au lieu de .hdf. Pour plus d'informations sur la construction de FSBL avec Vitis, reportez-vous à [Script Tcl pour la construction de Zynq FSBL (First Stage Boot Loader) avec Vivado (Vitis)] [Script Tcl pour la construction de FSBL avec Vitis].

Tcl:target/Ultra96-V2/build-v2019.2/fpga/build_zynqmp_pmufw.tcl


	:
(target/Ultra96-V2/build-v2019.1/fpga/build_zynqmp_pmufw.Identique à hci)
	:
set hwspec_file       "design_1_wrapper.xsa"
	:
(target/Ultra96-V2/build-v2019.1/fpga/build_zynqmp_pmufw.Identique à hci)
	:
vivado% cd target/Ultra96-V2/build-v2019.2/fpga/
vivado% xsct build_zynqmp_pmufw.tcl

Construire BOOT.BIN

Incorporez zynqmp_pmufw.elf construit dans la section précédente dans BOOT.BIN. Plus précisément, voir [Construire BOOT.BIN].

résultat

Démarrez Linux en utilisant le BOOT.BIN construit dans la section précédente. L'arrêt avec la commande poweroff met l'Ultra96-V2 en état de mise hors tension. Lorsque l'Ultra96-V2 est hors tension, le voyant d'alimentation (LED bleu) s'éteint et le ventilateur de refroidissement par air s'arrête.

De plus, si vous appuyez sur le bouton d'alimentation (SW4) pendant le démarrage de Linux, Linux passera à la séquence d'arrêt, puis l'Ultra96-V2 sera mis hors tension.

root@debian-fpga:~#  poweroff
[  OK  ] Stopped target Sound Card.
[  OK  ] Stopped tar■  OK  ] Stopped Daily man-db regeneration.
[  OK  ] Stopped target Multi-User System.
	:
	(Omission)
	:
[  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

De côté

La merveille de psu_init.c

Les informations sur le matériel créées dans Building Simple FPGA Design incluent psu_init.c pour configurer les ports ZynqMP. psu_init.c contient un programme pour le chargeur de démarrage de l'étape 1 (FSBL) pour définir le port pour ZynqMP. Il y a une partie étrange dans psu_init.c créée pour Ultra96-V2.

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);
/*##################################################################### */

Comme vous pouvez le voir, le port MIO34 est complètement absent. En d'autres termes, le chargeur de démarrage Stage 1 (FSBL) ne configure pas le port MIO34. Le port MIO34 est défini lorsque PMUFW (micrologiciel de l'unité de gestion de plate-forme) PmKillBoardPower () envoie L au port MIO34. À ce moment-là, le port MIO34 est ouvert et le port KILL_N sur le LSI de mise sous / hors tension est H car il a été tiré vers le haut.

C'est une évidence lorsque l'on considère la séquence de démarrage, et pendant que le chargeur de démarrage de l'étape 1 est en cours d'exécution, PMUFW n'est pas encore en cours d'exécution, donc GPO2 sur le PMU est défini par défaut sur 0. Si vous définissez le port MIO34 dans cet état, 0 (= Faible) défini dans GPO2 du PMU sera émis vers le port MIO34.

En d'autres termes, il sera mis hors tension pendant que le chargeur de démarrage Stage 1 est en cours d'exécution. Pour éviter cela, psu_init.c ne configure probablement pas le port MIO34.

Le port MIO34 est-il éteint uniquement?

En regardant le contenu de psu_init.c expliqué dans la section précédente et le code source de PMUFW (en particulier xpfw_config.h), il semble que le port lors de la mise hors tension avec ZynqMP soit fixé sur le port MIO34.

Si vous concevez une carte avec ZynqMP et que vous souhaitez mettre hors tension de ZynqMP, vous pouvez garder à l'esprit l'utilisation du port MIO34.

Nœud LTC2954 de l'arborescence des périphériques

L'arborescence des périphériques utilisée pour démarrer Linux sur Ultra96 / Ultra96-V2 comporte les nœuds suivants:

arch/arm64/boot/dts/xilinx/avnet-ultra96v2-rev1.dts


// SPDX-License-Identifier: GPL-2.0+
/*
 * dts file for Avnet Ultra96-V2 rev1
 *
 */
/dts-v1/;
	:
	(Omission)
	:
	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 */
	};
	:
	(Omission)

Ce nœud semble définir un pilote de périphérique qui contrôle le LSI qui le met sous et hors tension. Cependant, comme décrit dans Configuration des ports ZynqMP MIO26 / MIO34, l'Ultra96-V2 a les ports MIO26 / MIO34 configurés pour être contrôlés par le PMU, pas à partir d'un APU exécutant Linux. Par conséquent, ce nœud n'a pas de sens et doit être désactivé. Spécifiquement, spécifiez "désactivé" dans la propriété status.

référence

[Boot Loader]: https://qiita.com/ikwzm/items/9c78e83298906447fe5d "Construction de Debian GNU / Linux (version v2018.2) pour Ultra96 (Boot Loader)" @Qiita " [Création d'une conception FPGA simple]: https://qiita.com/ikwzm/items/0489b02962c6f0455783 "Construction de Debian GNU / Linux (version v2018.2) pour Ultra96 (exemple de conception FPGA)" @Qiita " [Construction de PMUFW]: https://qiita.com/ikwzm/items/00024adf956696dd51c6 "Construction de Debian GNU / Linux (version v2018.2) pour Ultra96 (édition PMUFW)" @Qiita " [Construction de BOOT.BIN]: https://qiita.com/ikwzm/items/af4420edd262e14feef9 "Construction de Debian GNU / Linux (version v2018.2) pour Ultra96 (édition BOOT.BIN)" @Qiita " [Script Tcl pour construire FSBL avec Vitis]: https://qiita.com/ikwzm/items/165481921c3e984a9e70 "Script Tcl pour construire Zynq FSBL (First Stage Boot Loader) avec Vivado (Vitis)" @Qiita " [Démarrage ZynqMP et gestion de l'alimentation]: https://www.slideshare.net/ssuser479fa3/zynq-mp-58490589 "" ZynqMP boot and power management "@Vengineer ZynqMP Study Session Materials (2016/2/20)" [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

Comment mettre hors tension de Linux sur Ultra96-V2
Comment mettre à jour avec SQLAlchemy?
Comment lancer avec Theano
Comment modifier avec SQLAlchemy?
Comment séparer les chaînes avec ','
Comment faire RDP sur Fedora31
Comment supprimer avec SQLAlchemy?
Comment garder le conda éteint
Comment annuler RT avec Tweepy
Python: comment utiliser async avec
Comment installer python-pip avec ubuntu20.04LTS
Comment gérer les données déséquilibrées
Comment installer VMware-Tools sur Linux
Comment installer MBDyn (Linux Ubuntu)
Comment démarrer avec Scrapy
Comment démarrer avec Python
Comment gérer l'erreur DistributionNotFound
Comment démarrer avec Django
Comment augmenter les données avec PyTorch
Comment calculer la date avec python
Comment installer mysql-connector avec pip3
Comment vérifier la version du système d'exploitation Linux
Comment INNER JOIN avec SQL Alchemy
Comment installer Anaconda avec pyenv
Comment obtenir tout le trafic via VPN avec OpenVPN sous Linux
Comment effectuer un traitement arithmétique avec le modèle Django
Comment créer mon propre serveur Linux
[Blender] Comment définir shape_key avec un script
Comment obtenir l'identifiant du parent avec sqlalchemy
Comment ajouter un package avec PyCharm
Je veux savoir comment fonctionne LINUX!
Comment installer DLIB avec 2020 / CUDA activé
Comment utiliser ManyToManyField avec l'administrateur de Django
Comment utiliser OpenVPN avec Ubuntu 18.04.3 LTS
Comment utiliser Cmder avec PyCharm (Windows)
[Linux] Comment utiliser la commande echo
Comment utiliser BigQuery en Python
Comment mettre à jour PHP sur Amazon Linux 2
Comment utiliser Ass / Alembic avec HtoA
Comment gérer les erreurs de compatibilité d'énumération
Comment afficher des pictogrammes sur Manjaro Linux
Comment utiliser le japonais avec le tracé NLTK
Comment faire un test de sac avec python
Comment rechercher Google Drive dans Google Colaboratory
Comment afficher le japonais python avec lolipop
Comment installer des packages sur Alpine Linux
Comment télécharger des vidéos YouTube avec youtube-dl
Connectez-vous à GNU / Linux avec un bureau distant
Comment utiliser le notebook Jupyter avec ABCI
Comment faire fonctionner Linux depuis la console
Comment installer le sous-système Windows pour Linux