[Guide] HD+ IP TV-Stick: How to install CoreELEC

CoreELEC on the HD+ IPTV Stick (SEI900HDPLUS)

The HD+ IPTV Stick is manufactered by SEI Robotics and sold by German TV provider HD PLUS GmbH. It features an Amlogic S905Y5 processor, comes with 2GB RAM and 32 GB eMMC.

The installation procedure for CoreELEC depends on your currently installed bootloader version, so we need to check it first.

1) Check bootloader version

Connect the stick to the HDMI port of your monitor/TV. Press and hold the physical button of the stick and then power it on by connecting it to your computer via USB. Do not use the USB-C cable shipped with the stick, it’s a pure charging cable and has no data function. Use the port next to the ethernet port (labeled “DC 5V”). Keep holding the button for about 10 seconds. On your monitor/TV, you will see that the stick enters fastboot mode at first and then, a few seconds later, switches to “USB burning mode”.

Now clone superna9999’s pyamlboot repository and download my (heavily vibe-coded) script env_flash.py.

git clone https://github.com/superna9999/pyamlboot
curl -o env_flash.py https://discourse.coreelec.org/uploads/short-url/5sCkovlpVLrp86RGeQeDPl14ldz.py

Create a new virtual environment and install Python dependencies:

python3 -m venv .venv
source .venv/bin/activate
pip3 install -r pyamlboot/requirements.txt

Now execute the script. At first, we only want to query the bootloader version (without flashing anything):

python3 env_flash.py --dry-run

If you have bootloader version 01.01.251120.134846 installed, the U-Boot environment needs to be modified in order to install CoreELEC. Go on with step 2.

For devices using older bootloader versions (e. g. 01.01.240902.195526 or 01.01.250702.103250) this is not necessary. Power off the stick, skip the next step and continue with step 3.

2) Flash modified U-Boot environment if needed

Keep in mind that flashing partitions to your TV stick always involves risks. If something goes wrong, you could end up with a (soft-)bricked device in the worst case. Proceed at your own risk. I am not responsible for any damage.

The problem with bootloader version 01.01.251120.134846 is that the update env variable in U-Boot doesn’t include the recovery_from_udisk command anymore. That’s why the CoreELEC recovery image and aml_autoscript never run – and we cannot boot into CoreELEC. Changing single env variables from fastboot/adnl is apparently not allowed by default, but flashing the env partition as a whole is possible. So that’s the workaround: I dumped a “fresh” env partition from the device, adjusted only the update variable and generated a new env image with mkenvimage. The result is env_modified.img.

Download env_modified.img from the attachments and store it into the same folder as env_flash.py. Then, while still being in USB burning mode, execute the Python script again – and flash the modified env partition:

curl -o env_modified.img https://discourse.coreelec.org/uploads/short-url/7wTAieRJ9zIvXtzgeu9rqHuR5Jz.img
python3 env_flash.py

Power off the stick afterwards and continue with step 3.

3) Install CoreELEC

From here, the installation process is similar to most CoreELEC-compatible devices.

Download the latest generic nightly build from here (CoreELEC nightly builds) and burn it onto a USB stick using your favorite software (dd, cat, balenaEtcher or anything else …).

Afterwards, mount the USB stick to your computer, open the COREELEC partition, copy s7_s905y5_sei_900_hdplus.dtb from device_trees to the root folder and rename it to dtb.img.

Eject the USB stick from your computer and put it into the “DC5V” port of your TV stick.

Put the USB-C cable (which was at “DC5V” before) into the “USB” port of the TV stick, press and hold the button again and then power the stick on (plug the USB cable into your computer or use the power supply of the stick).

Again, wait about 10 seconds before releasing the button – and let the magic happen :slight_smile: The stick will now load the CoreELEC recovery.img, run aml_autoscript, set up the needed environment variables and reboot into CoreELEC.

env_flash.py (8.1 KB)
env_modified.img (8 MB)

Sure it does not run recovery.img in update? Because it’s optional used if aml_autoscript is not supported what match with most of the newer devices. recovery.img do run fw_setenv what do the aml_autoscript job internal and then reboot.

I bet recovery.img method is supported OOTB by default env of the bootloader.
Otherwise the devices can’t be recovered at all, only by flashing the eMMC directly.

It did until the previous OTA update (running bootloader version 01.01.250702.103250).
Until then, the update variable in U-Boot looked like this:

update=run usb_burning; run recovery_from_sdcard; run recovery_from_udisk; run recovery_from_flash;

With the newest OTA update (running bootloader version 01.01.251120.134846) it was changed to this:

update=run usb_burning; run usb_burningcfg; run sdc_burningcfg; run recovery_from_flash;

So instead of run recovery_from_sdcard; run recovery_from_udisk we now have run usb_burningcfg; run sdc_burningcfg. Which means that U-Boot would look for a aml_sdc_burn.ini on the USB stick instead of the recovery.img by default.

In which context this is used?

Can you show whole printenv output with new bootloader?

EnableSelinux=enforcing
Irq_check_en=0
active_slot=normal
androidboot.dtbo_idx=0
arch=arm
baudrate=921600
bcb_cmd=get_avb_mode; get_valid_slot; if test ${vendor_boot_mode} = true; then setenv loadaddr_kernel 0x3000000; setenv dtb_mem_addr 0x1000000; fi; if test ${active_slot} != "normal"; then echo ab mode, read dtb from kernel; setenv common_dtb_load imgread dtb ${boot_part} ${dtb_mem_addr}; fi;
board=s7_bh202_baiyun
board_logo_part=odm_ext
board_name=s7_bh202_baiyun
boot_flag=0
boot_part=boot
bootcmd=run storeboot
bootdelay=0
bootloader_version=01.01.251120.134846
cmdline_keys=setenv region_code US; if keyman init 0x1234; then if keyman read usid ${loadaddr} str; then setenv bootconfig ${bootconfig} androidboot.serialno=${usid}; setenv serial ${usid}; setenv serial# ${usid}; else setenv bootconfig ${bootconfig} androidboot.serialno=${product}${cpu_id}; setenv serial ${product}${cpu_id}; setenv serial# ${product}${cpu_id}; fi; if keyman read region_code ${loadaddr} str; then fi; if keyman read mac ${loadaddr} str; then setenv bootargs ${bootargs} mac=${mac}; setenv bootconfig ${bootconfig} androidboot.mac=${mac}; fi; if keyman read deviceid ${loadaddr} str; then setenv bootconfig ${bootconfig} androidboot.deviceid=${deviceid}; fi; if keyman read oem ${loadaddr} str; then setenv bootconfig ${bootconfig} androidboot.oem=${oem}; fi; if keyman read modelgroup ${loadaddr} str; then setenv bootconfig ${bootconfig} androidboot.modelgroup=${modelgroup}; fi; if keyman read sku ${loadaddr} str; then setenv bootconfig ${bootconfig} androidboot.sku=${sku}; fi; if keyman read tenantCodename ${loadaddr} str; then setenv bootconfig ${bootconfig} androidboot.tenantCodename=${tenantCodename}; fi; fi; factory_provision init;
colorattribute=444,8bit
common_dtb_load=imgread dtb _aml_dtb ${dtb_mem_addr}
connector0_type=TV-1
cpu=armv8
cvbs_drv=0
cvbsmode=576cvbs
ddr_size=0
decaddr_kernel=0x01800000
default_governor=performance
defenv_para=-c
disable_ir=0
disableunlock=0
display_bpp=16
display_color_bg=0
display_color_fg=0xffff
display_color_index=16
display_height=1080
display_layer=osd0
display_width=1920
dolby_status=0
dolby_vision_on=0
dtb_mem_addr=0x01000000
dv_fw_addr=0xa00000
dv_fw_dir=/reserved/firmware/dovi_fw.bin
dv_fw_dir_odm_ext=/odm_ext/firmware/dovi_fw.bin
dv_fw_dir_vendor=/vendor/firmware/dovi_fw.bin
enable_console=0
env_enable_sdcBurningCfg=0
env_enable_usbBurningCfg=0
env_usb_cc_function=0x00000000
fastboot_step=0
fatload_dev=usb
fb_addr=0x00300000
fb_height=1080
fb_width=1920
fdt_high=0x20000000
firstboot=1
frac_rate_policy=1
fs_type=rootfstype=ramfs
gatewayip=10.18.9.1
get_os_type=if store read ${os_ident_addr} ${boot_part} 0 0x1000; then os_ident ${os_ident_addr}; fi
hdmichecksum=0x00000000
hdmimode=none
hdr_policy=0
hdr_priority=268435472
hostname=arm_gxbb
hw_id=0
init_display=get_rebootmode; echo reboot_mode:::: ${reboot_mode}; if test ${reboot_mode} = quiescent; then setenv reboot_mode_android "quiescent"; setenv dolby_status 0; setenv dolby_vision_on 0; setenv initconfig androidboot.quiescent=1 androidboot.bootreason=${reboot_mode}; run storeargs; osd open;osd clear; else if test ${reboot_mode} = recovery_quiescent; then setenv reboot_mode_android "quiescent"; setenv dolby_status 0; setenv dolby_vision_on 0; setenv initconfig androidboot.quiescent=1 androidboot.bootreason=recovery,quiescent; run storeargs; osd open;osd clear; else setenv reboot_mode_android "normal"; setenv initconfig androidboot.bootreason=${reboot_mode}; hdmitx hpd;hdmitx get_parse_edid; watermark_init;osd open;osd clear;run load_bmp_logo; bmp scale;vout output ${outputmode}; vpp hdrpkt; run storeargs; fi;fi;
initargs=init=/init ramoops.pstore_en=1 ramoops.record_size=0x8000 ramoops.console_size=0x4000 loop.max_part=4
ipaddr=10.18.9.97
is_default_50hz_mode=1
is_not_hdr_preference=0
jtag=disable
load_bmp_logo=if rdext4pic ${board_logo_part} $loadaddr; then bmp display $logoLoadAddr; else if imgread pic logo bootup $loadaddr; then bmp display $bootup_offset; fi; fi;
loadaddr=0x1080000
loadaddr_kernel=0x03000000
loadaddr_rtos=0x00080000
lock=10101000
loglevel=1
netmask=255.255.255.0
oemlock=lock
os_ident_addr=0x00500000
osd_reverse=0
otg_device=1
outputmode=576cvbs
preboot=run bcb_cmd; run upgrade_check;run init_display;run sei_cc_power_detect_function;run storeargs;run upgrade_key;bcb uboot-command;run switch_bootmode;
qms_en=1
recovery_from_fat_dev=setenv loadaddr ${loadaddr_kernel}; if fatload ${fatload_dev} 0 ${loadaddr} aml_autoscript; then autoscr ${loadaddr}; fi; if fatload ${fatload_dev} 0 ${loadaddr} recovery.img; then if fatload ${fatload_dev} 0 ${dtb_mem_addr} dtb.img; then echo ${fatload_dev} dtb.img loaded; fi; setenv bootargs ${bootargs} ${fs_type}; bootm ${loadaddr}; fi;
recovery_from_flash=echo active_slot: ${active_slot}; setenv loadaddr ${loadaddr_kernel}; setenv recovery_mode true; if test ${active_slot} = normal; then setenv bootargs ${bootargs} ${fs_type} aml_dt=${aml_dt} recovery_part=${recovery_part} recovery_offset=${recovery_offset}; avb recovery 1; if test ${upgrade_step} = 3; then if ext4load mmc 1:2 ${dtb_mem_addr} /recovery/dtb.img; then echo cache dtb.img loaded; fi; if test ${vendor_boot_mode} = true; then if imgread kernel ${recovery_part} ${loadaddr} ${recovery_offset}; then bootm ${loadaddr}; fi; else if ext4load mmc 1:2 ${loadaddr} /recovery/recovery.img; then echo cache recovery.img loaded; bootm ${loadaddr}; fi; fi; else if imgread dtb recovery ${dtb_mem_addr}; then else echo restore dtb; run common_dtb_load; fi; fi; if imgread kernel ${recovery_part} ${loadaddr} ${recovery_offset}; then bootm ${loadaddr}; fi; else if fdt addr ${dtb_mem_addr}; then else echo retry common dtb; run common_dtb_load; fi; if test ${vendor_boot_mode} = true; then setenv bootargs ${bootargs} ${fs_type} aml_dt=${aml_dt} recovery_part=${boot_part}; setenv bootconfig ${bootconfig} androidboot.slot_suffix=${active_slot}; if imgread kernel ${boot_part} ${loadaddr}; then bootm ${loadaddr}; fi; fi; fi;
recovery_from_sdcard=setenv fatload_dev mmc; if mmcinfo; then run recovery_from_fat_dev; fi;
recovery_from_udisk=setenv fatload_dev usb; if usb start 0; then run recovery_from_fat_dev; fi;
recovery_mode=false
recovery_offset=0
recovery_part=recovery
retry_recovery_times=7
rollback_flag=0
scramble_reg=0xfe02e030
sdc_burningcfg=echo env_enable_sdcBurningCfg=${env_enable_sdcBurningCfg}; if test ${env_enable_sdcBurningCfg} == 1; then sdc_burn aml_sdc_burn.ini; fi;
sdcburncfg=aml_sdc_burn.ini
sei_cc_power_detect_function=echo env_usb_cc_function=${env_usb_cc_function};sei_cc_power_detect
sei_colorattribute=444,8bit
sei_hdmimode=1080p60hz
sei_kernelcfg_hex=0xffffffff
serverip=10.18.9.113
silent=0
soc=s7
standby_reboot_quiescent=0
standby_reboot_sei_quiescent=0
storage_param=setenv bootargs ${bootargs} ${emmc_quirks}; store param; setenv bootargs ${bootargs} ${mtdbootparts};
storeargs=get_bootloaderversion; setenv bootargs ${initargs} loglevel=${loglevel} console=ttyS0,${baudrate} no_console_suspend earlycon=aml_uart,${uart_base} scramble_reg=${scramble_reg} cma_first_wm_low=on otg_device=${usb_is_slave} hw_id=${hw_id} sei_kernelcfg=${sei_kernelcfg_hex} disable_ir=${disable_ir} cpufreq.default_governor=${default_governor} logo=${display_layer},loaded,${fb_addr} vout=${outputmode},${vout_init} connector0_type=${connector0_type} hdmitx=${cecconfig},${colorattribute} hdmimode=${hdmimode} hdmichecksum=${hdmichecksum} dolby_vision_on=${dolby_vision_on} hdr_policy=${hdr_policy} hdr_priority=${hdr_priority} config_csc_en=${config_csc_en} hdr_force_mode=${hdr_force_mode} dolby_status=${dolby_status} frac_rate_policy=${actual_frac_rate} hdmi_read_edid=${hdmi_read_edid} cvbsmode=${cvbsmode} osd_reverse=${osd_reverse} video_reverse=${video_reverse} jtag=${jtag}; setenv bootargs ${bootargs} ${emmc_quirks} kvm-arm.mode=none init_on_alloc=0; setenv bootargs ${bootargs} enable_8bit_hdr=${enable_8bit_hdr}; setenv bootconfig ${initconfig} androidboot.selinux=${EnableSelinux}; setenv bootconfig ${bootconfig} androidboot.bootloader=${bootloader_version} androidboot.hardware=amlogic; setenv bootconfig ${bootconfig} androidboot.firstboot=${firstboot} androidboot.ddr_size=${ddr_size}; setenv bootconfig ${bootconfig} androidboot.cc.status=${usb_status}; setenv bootconfig ${bootconfig} androidboot.production_mode=${production_mode} androidboot.enable_console=${enable_console}; if test ${cc_enable} != 1; then else setenv bootconfig ${bootconfig} androidboot.cc_enable=${cc_enable}; fi; run cmdline_keys;
storeboot=run get_os_type; run storage_param; if test ${os_type} = rtos; then setenv loadaddr ${loadaddr_rtos}; store read ${loadaddr} ${boot_part} 0 0x400000; bootm ${loadaddr}; else if test ${os_type} = kernel; then get_avb_mode; echo active_slot in storeboot: ${active_slot}; if fdt addr ${dtb_mem_addr}; then else echo retry common dtb; run common_dtb_load; fi; setenv bootconfig ${bootconfig} androidboot.force_normal_boot=1; if test ${active_slot} != normal; then setenv bootconfig ${bootconfig} androidboot.slot_suffix=${active_slot}; fi; setenv bootconfig ${bootconfig} androidboot.rollback=${rollback_flag}; setenv loadaddr ${loadaddr_kernel}; if imgread kernel ${boot_part} ${loadaddr}; then bootm ${loadaddr}; fi; else echo wrong OS format ${os_type}; fi;fi; echo try upgrade as booting failure; check_ab; run update;
switch_bootmode=get_rebootmode; if test ${reboot_mode} = factory_reset; then run recovery_from_flash; else if test ${reboot_mode} = update; then run update; else if test ${reboot_mode} = quiescent; then setenv bootargs ${bootargs} androidboot.quiescent=1; run try_auto_burn; else if test ${reboot_mode} = recovery_quiescent; then setenv bootargs ${bootargs} androidboot.quiescent=1; run recovery_from_flash; else if test ${reboot_mode} = cold_boot; then run try_auto_burn; setenv upgrade_upgrading_offset 0x3720300; run usb_burningcfg; else if test ${reboot_mode} = fastboot; then fastboot 0; fi; fi;fi;fi;fi;fi;
try_auto_burn=adnl 2000 3000
uart_base=0xfe07a000
update=run usb_burning; run usb_burningcfg; run sdc_burningcfg; run recovery_from_flash;
upgrade_check=echo recovery_status=${recovery_status}; if itest.s "${recovery_status}" == "in_progress"; then run init_display; run storeargs; run recovery_from_flash; else fi; echo upgrade_step=${upgrade_step}; if itest ${upgrade_step} == 3; then run storeargs; run update; fi;
upgrade_key=if detect_upgradekey; then echo upgradekey_val:::: ${upgradekey_val};if test ${upgradekey_val} = fastboot; then osd clear;imgread pic logo fastboot $loadaddr;bmp display $fastboot_offset;bmp scale; echo detect fastboot key; fastboot 0;else if test ${upgradekey_val} = upgrade; then run update;fi;fi;fi;echo usr key;
upgrade_key_base=echo base env no upgrade key;
upgrade_step=0
usb_burning=adnl 1200
usb_burningcfg=echo env_enable_usbBurningCfg=${env_enable_usbBurningCfg}; if test ${env_enable_usbBurningCfg} == 1; then usb_burn aml_sdc_burn.ini; fi;
usb_is_slave=1
usb_status=detach
vendor=amlogic
vendor_boot_part=vendor_boot
video_reverse=0
write_boot=0

AML Burncard maker