@@ -10,11 +10,18 @@ set -o errexit
1010# shellcheck disable=SC1091
1111. /usr/libexec/os-helpers-logging
1212
13- NEW_IMG=" ${1:- pieeprom.bin } "
13+ NEW_IMG=" ${1:- pieeprom.upd } "
1414CURR_IMG=pieeprom-current.bin.tmp
1515CURR_IMG_PATH=/tmp
1616NEW_IMG_PATH=/mnt/boot
1717SPI_SPEED=16000
18+ SPI_DEVICE=" "
19+ VCHIQ_UNBOUND=0
20+ SPI_WAS_UNBOUND=0
21+ SPI_IS_BOUND=0
22+ AUDIO_WAS_DISABLED=0
23+ SPI_OVERLAY_WAS_ENABLED=0
24+ MAILBOX_WAS_DISABLED=0
1825
1926# Unbind a device from a driver
2027# Usage: device=$(driver_unbind <driver_path> <device_pattern>)
@@ -86,19 +93,98 @@ vchiq_unbind() {
8693 driver_unbind " ${VCHIQ_DRIVER_PATH} " " *.mailbox"
8794}
8895
96+ cleanup () {
97+ exit_code=$?
98+ cleanup_failed=0
99+
100+ # Cleanup must be best-effort and should not fail the script.
101+ set +o errexit
102+
103+ rm -f " ${CURR_IMG_PATH} /${CURR_IMG} "
104+
105+ if [ " ${SPI_IS_BOUND} " = " 1" ] && [ -n " ${SPI_DEVICE} " ]; then
106+ if ! echo " ${SPI_DEVICE} " > " ${SPI_DRIVER_PATH} /unbind" 2> /dev/null; then
107+ warn " Failed to unbind ${SPI_DEVICE} during cleanup"
108+ else
109+ SPI_IS_BOUND=0
110+ fi
111+ fi
112+
113+ if [ " ${SPI_OVERLAY_WAS_ENABLED} " = " 1" ]; then
114+ /usr/bin/dtparam -d /mnt/boot/overlays/ -R spi-gpio40-45 || \
115+ {
116+ warn " Failed to remove spi-gpio40-45 overlay during cleanup"
117+ cleanup_failed=1
118+ }
119+ fi
120+
121+ if [ " ${AUDIO_WAS_DISABLED} " = " 1" ]; then
122+ /usr/bin/dtparam -d /mnt/boot/overlays/ audio=on || \
123+ {
124+ warn " Failed to restore audio=on during cleanup"
125+ cleanup_failed=1
126+ }
127+ fi
128+
129+ if [ " ${MAILBOX_WAS_DISABLED} " = " 1" ]; then
130+ /usr/bin/vcmailbox 0x00030056 4 4 1 > /dev/null || \
131+ {
132+ warn " Failed to restore mailbox state during cleanup"
133+ cleanup_failed=1
134+ }
135+ fi
136+
137+ if [ " ${SPI_WAS_UNBOUND} " = " 1" ] && [ " ${SPI_IS_BOUND} " = " 0" ] && [ -n " ${SPI_DEVICE} " ]; then
138+ if ! spi_bind " ${SPI_DEVICE} " ; then
139+ warn " Failed to restore SPI driver during cleanup"
140+ cleanup_failed=1
141+ fi
142+ fi
143+
144+ # VCHIQ cannot be restored at runtime due to firmware limitations.
145+ # Even with mailbox/audio restored, VideoCore services remain unavailable until reboot.
146+ # https://github.com/raspberrypi/rpi-eeprom/issues/801#issuecomment-3859373151
147+ if [ " ${VCHIQ_UNBOUND} " = " 1" ]; then
148+ warn " VCHIQ was unbound during EEPROM update and cannot be restored at runtime."
149+ warn " Audio, camera and other VideoCore services will not work until the next reboot."
150+ fi
151+
152+ if [ " ${exit_code} " -eq 0 ] && [ " ${cleanup_failed} " -eq 1 ]; then
153+ warn " EEPROM update was successful, but cleanup failed. Exiting."
154+ exit 2
155+ fi
156+
157+ exit " ${exit_code} "
158+ }
159+
160+ trap cleanup EXIT
161+
89162SPI_DEVICE=$( spi_unbind)
90163if [ -z " ${SPI_DEVICE} " ]; then
91164 fail " SPI device not found or failed to unbind, cannot proceed with EEPROM update"
92165fi
166+ SPI_WAS_UNBOUND=1
167+
168+ if /usr/bin/vcmailbox 0x00030056 4 4 0 > /dev/null; then
169+ MAILBOX_WAS_DISABLED=1
170+ else
171+ warn " Failed to disable mailbox before EEPROM update; continuing"
172+ fi
173+ if /usr/bin/dtparam -d /mnt/boot/overlays/ audio=off; then
174+ AUDIO_WAS_DISABLED=1
175+ else
176+ fail " Failed to disable audio before EEPROM update"
177+ fi
93178
94- /usr/bin/vcmailbox 0x00030056 4 4 0 > /dev/null || true
95- /usr/bin/dtparam -d /mnt/boot/overlays/ audio=off
96- /usr/bin/dtoverlay -d /mnt/boot/overlays/ spi-gpio40-45
179+ if /usr/bin/dtoverlay -d /mnt/boot/overlays/ spi-gpio40-45; then
180+ SPI_OVERLAY_WAS_ENABLED=1
181+ else
182+ fail " Failed to apply spi-gpio40-45 overlay before EEPROM update"
183+ fi
97184
98185# Try binding SPI; if it fails (pinctrl conflict with VCHIQ holding GPIO 40-45),
99186# unbind VCHIQ and retry. VCHIQ cannot be rebound at runtime, so audio/camera
100187# will be unavailable until reboot.
101- VCHIQ_UNBOUND=0
102188if ! spi_bind " $SPI_DEVICE " ; then
103189 warn " Unbinding VCHIQ to release GPIO 40-45 (audio/camera will be unavailable until reboot)"
104190 vchiq_unbind
@@ -107,6 +193,7 @@ if ! spi_bind "$SPI_DEVICE"; then
107193 fail " SPI bind failed even after VCHIQ unbind, cannot proceed"
108194 fi
109195fi
196+ SPI_IS_BOUND=1
110197
111198/usr/sbin/flashrom -p " linux_spi:dev=/dev/spidev0.0,spispeed=${SPI_SPEED} " --read " ${CURR_IMG_PATH} /${CURR_IMG} "
112199
@@ -120,25 +207,3 @@ else
120207 /usr/sbin/flashrom -p " linux_spi:dev=/dev/spidev0.0,spispeed=${SPI_SPEED} " --write " ${NEW_IMG_PATH} /${NEW_IMG} "
121208 info " SPI EEPROM fw update successful"
122209fi
123-
124- rm " ${CURR_IMG_PATH} /${CURR_IMG} "
125-
126- SPI_DEVICE=$( spi_unbind)
127- if [ -z " ${SPI_DEVICE} " ]; then
128- fail " SPI device not found during cleanup, cannot restore system state"
129- fi
130-
131- /usr/bin/dtparam -d /mnt/boot/overlays/ -R spi-gpio40-45
132- /usr/bin/dtparam -d /mnt/boot/overlays/ audio=on
133- /usr/bin/vcmailbox 0x00030056 4 4 1 > /dev/null || true
134-
135- if ! spi_bind " $SPI_DEVICE " ; then
136- fail " Failed to restore SPI driver during cleanup"
137- fi
138-
139- # In an ideal world we would restore the mailbox, but unfortunately this is impossible
140- # https://github.com/raspberrypi/rpi-eeprom/issues/801#issuecomment-3859373151
141- if [ " ${VCHIQ_UNBOUND} " = " 1" ]; then
142- warn " VCHIQ was unbound during EEPROM update and cannot be restored at runtime."
143- warn " Audio, camera and other VideoCore services will not work until the next reboot."
144- fi
0 commit comments