xiaomi_r3d.patch 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095
  1. From c433730d889d0dfb31bdcf4f102ca47939606c46 Mon Sep 17 00:00:00 2001
  2. From: remittor <[email protected]>
  3. Date: Fri, 11 Aug 2023 12:08:30 +0300
  4. Subject: [PATCH] ipq806x: Add support for Xiaomi Mi Router HD (R3D)
  5. Xiaomi R3D is a 2.4/5 GHz band 11ac router, based on IPQ8064.
  6. Specification:
  7. * SoC: Qualcomm IPQ8064
  8. * RAM: 512MB DDR3
  9. * Flash: 256MB NAND (Macronix MX30UF2G18AC-TI)
  10. * Ethernet: 4x 10/100/1000 Mbps (1x WAN, 3x LAN)
  11. * WiFi: Qualcomm QCA9984 (5GHz, 4T4R, n/ac)
  12. * WiFi: Qualcomm QCA9980 (2.4GHz, 4T4R, b/g/n)
  13. * USB: 1x 3.0
  14. * SATA: 1x SATA 3.1 (only for internal HDD 3.5")
  15. * BTN: Power, Reset
  16. * LEDS: Status(Green/Blue/Red)
  17. * UART: present as 4-pads on the PCB (3.3V, 115200-8-N-1)
  18. MAC addresses as verified by stock firmware:
  19. | Interface | MAC | ART | Format |
  20. |-------------+-------------------+---------+--------|
  21. | WAN (label) | xx:xx:xx:xx:xx:B2 | 0x0 | binary |
  22. | LAN | xx:xx:xx:xx:xx:B3 | 0x6 | binary |
  23. | WiFi 2g | xx:xx:xx:xx:xx:B4 | 0x1006 | binary |
  24. | WiFi 5g | xx:xx:xx:xx:xx:B5 | 0x5006 | binary |
  25. ---
  26. package/boot/uboot-envtools/files/ipq806x | 6 +-
  27. .../ipq806x/base-files/etc/board.d/02_network | 4 +
  28. .../etc/hotplug.d/firmware/11-ath10k-caldata | 6 +
  29. .../ipq806x/base-files/etc/init.d/bootcount | 8 +
  30. .../base-files/lib/upgrade/platform.sh | 3 +
  31. .../ipq806x/base-files/lib/upgrade/xiaomi.sh | 441 ++++++++++++++++
  32. .../arch/arm/boot/dts/qcom-ipq8064-r3d.dts | 479 ++++++++++++++++++
  33. target/linux/ipq806x/image/generic.mk | 17 +
  34. 8 files changed, 963 insertions(+), 1 deletion(-)
  35. create mode 100644 target/linux/ipq806x/base-files/lib/upgrade/xiaomi.sh
  36. create mode 100644 target/linux/ipq806x/files-5.15/arch/arm/boot/dts/qcom-ipq8064-r3d.dts
  37. diff --git a/package/boot/uboot-envtools/files/ipq806x b/package/boot/uboot-envtools/files/ipq806x
  38. index 01a86c7b19fca..c0a781c1e21b4 100644
  39. --- a/package/boot/uboot-envtools/files/ipq806x
  40. +++ b/package/boot/uboot-envtools/files/ipq806x
  41. @@ -52,6 +52,10 @@ qcom,ipq8064-ap148|\
  42. qcom,ipq8064-db149)
  43. ubootenv_add_uci_config $(ubootenv_mtdinfo)
  44. ;;
  45. +xiaomi,r3d)
  46. + ubootenv_add_uci_config "/dev/mtd9" "0x0" "0x10000" "0x10000"
  47. + ubootenv_add_uci_sys_config "/dev/mtd12" "0x0" "0x10000" "0x10000"
  48. + ;;
  49. ubnt,unifi-ac-hd|\
  50. zyxel,nbg6817)
  51. ubootenv_add_uci_config "/dev/mtdblock9" "0x0" "0x10000" "0x10000"
  52. @@ -59,6 +63,6 @@ zyxel,nbg6817)
  53. esac
  54. config_load ubootenv
  55. -config_foreach ubootenv_add_app_config ubootenv
  56. +config_foreach ubootenv_add_app_config
  57. exit 0
  58. diff --git a/target/linux/ipq806x/base-files/etc/board.d/02_network b/target/linux/ipq806x/base-files/etc/board.d/02_network
  59. index 8dd52452b1739..df27cbde7c5d8 100644
  60. --- a/target/linux/ipq806x/base-files/etc/board.d/02_network
  61. +++ b/target/linux/ipq806x/base-files/etc/board.d/02_network
  62. @@ -89,6 +89,10 @@ nokia,ac400i |\
  63. ubnt,unifi-ac-hd)
  64. ucidef_set_interface_lan "eth0 eth1"
  65. ;;
  66. +xiaomi,r3d)
  67. + ucidef_add_switch "switch0" \
  68. + "1:lan:3" "2:lan:2" "3:lan:1" "6@eth1" "5:wan" "0@eth0"
  69. + ;;
  70. zyxel,nbg6817)
  71. hw_mac_addr=$(mtd_get_mac_ascii 0:appsblenv ethaddr)
  72. ucidef_add_switch "switch0" \
  73. diff --git a/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata b/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
  74. index 4c5019cf5bd24..aa8ed06aae4b3 100644
  75. --- a/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
  76. +++ b/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
  77. @@ -56,6 +56,9 @@ case "$FIRMWARE" in
  78. caldata_extract "0:art" 0x1000 0x2f20
  79. ath10k_patch_mac $(macaddr_add $(mtd_get_mac_ascii 0:appsblenv ethaddr) +2)
  80. ;;
  81. + xiaomi,r3d)
  82. + caldata_extract "ART" 0x1000 0x2f20
  83. + ;;
  84. zyxel,nbg6817)
  85. caldata_extract "0:art" 0x1000 0x2f20
  86. ath10k_patch_mac $(macaddr_add $(mtd_get_mac_ascii 0:appsblenv ethaddr) 1)
  87. @@ -92,6 +95,9 @@ case "$FIRMWARE" in
  88. caldata_extract "0:art" 0x5000 0x2f20
  89. ath10k_patch_mac $(macaddr_add $(mtd_get_mac_ascii 0:appsblenv ethaddr) +3)
  90. ;;
  91. + xiaomi,r3d)
  92. + caldata_extract "ART" 0x5000 0x2f20
  93. + ;;
  94. zyxel,nbg6817)
  95. caldata_extract "0:art" 0x5000 0x2f20
  96. ath10k_patch_mac $(mtd_get_mac_ascii 0:appsblenv ethaddr)
  97. diff --git a/target/linux/ipq806x/base-files/etc/init.d/bootcount b/target/linux/ipq806x/base-files/etc/init.d/bootcount
  98. index cb32a4ed3568d..9d9ab3f100fe2 100755
  99. --- a/target/linux/ipq806x/base-files/etc/init.d/bootcount
  100. +++ b/target/linux/ipq806x/base-files/etc/init.d/bootcount
  101. @@ -16,5 +16,13 @@ boot() {
  102. linksys,ea8500)
  103. mtd resetbc s_env || true
  104. ;;
  105. + xiaomi,r3d)
  106. + local boot_wait=$( fw_printenv boot_wait | cut -d = -f 2 )
  107. + [ "$boot_wait" != "on" ] && fw_setenv boot_wait on
  108. + local bootdelay=$( fw_printenv bootdelay | cut -d = -f 2 )
  109. + [ "$bootdelay" != "3" ] && fw_setenv bootdelay 3
  110. + local uart_en=$( fw_printenv uart_en | cut -d = -f 2 )
  111. + [ "$uart_en" != "1" ] && fw_setenv uart_en 1
  112. + ;;
  113. esac
  114. }
  115. diff --git a/target/linux/ipq806x/base-files/lib/upgrade/platform.sh b/target/linux/ipq806x/base-files/lib/upgrade/platform.sh
  116. index 5ec4f513bd33d..b142fce86a082 100644
  117. --- a/target/linux/ipq806x/base-files/lib/upgrade/platform.sh
  118. +++ b/target/linux/ipq806x/base-files/lib/upgrade/platform.sh
  119. @@ -71,6 +71,9 @@ platform_do_upgrade() {
  120. MTD_CONFIG_ARGS="-s 0x200000"
  121. default_do_upgrade "$1"
  122. ;;
  123. + xiaomi,r3d)
  124. + platform_do_upgrade_xiaomi "$1" 0x2800000
  125. + ;;
  126. zyxel,nbg6817)
  127. zyxel_do_upgrade "$1"
  128. ;;
  129. diff --git a/target/linux/ipq806x/base-files/lib/upgrade/xiaomi.sh b/target/linux/ipq806x/base-files/lib/upgrade/xiaomi.sh
  130. new file mode 100644
  131. index 0000000000000..9246e8f867e3f
  132. --- /dev/null
  133. +++ b/target/linux/ipq806x/base-files/lib/upgrade/xiaomi.sh
  134. @@ -0,0 +1,441 @@
  135. +# SPDX-License-Identifier: GPL-2.0-or-later OR MIT
  136. +
  137. +. /lib/functions.sh
  138. +
  139. +MAGIC_XIAOMI_HDR1="48445231" # "HDR1" - xiaomi image header
  140. +MAGIC_XIAOMI_BLK="beba0000"
  141. +MAGIC_UIMAGE="27051956" # uImage header
  142. +MAGIC_UBI="55424923" # "UBI#"
  143. +MAGIC_UBIFS="31181006"
  144. +MAGIC_HSQS="68737173" # "hsqs"
  145. +MAGIC_SYSUPG="7379737570677261" # TAR "sysupgrade"
  146. +
  147. +XIAOMI_PAGESIZE=2048
  148. +
  149. +XIAOMI_FW_FILE=""
  150. +XIAOMI_FW_SIZE=0
  151. +XIAOMI_KERNEL_PART=$CI_KERNPART
  152. +XIAOMI_KERNEL2_PART=""
  153. +XIAOMI_KERNEL2_NAMES="kernel_stock|kernel_dup"
  154. +XIAOMI_ROOTFS_PART=$CI_UBIPART
  155. +XIAOMI_ROOTFS_PARTSIZE=
  156. +
  157. +XIAOMI_RESTORE_ROOTFS2=
  158. +
  159. +log_msg() {
  160. + echo "$@"
  161. +}
  162. +
  163. +log_err() {
  164. + echo "ERROR: $@" >&2
  165. +}
  166. +
  167. +die() {
  168. + log_err "$@"
  169. + exit 1
  170. +}
  171. +
  172. +get_uint32_at() {
  173. + local offset=$1
  174. + local endianness=$2
  175. + local hex
  176. + if [ $(( $offset + 4 )) -gt $XIAOMI_FW_SIZE ]; then
  177. + echo ""
  178. + return
  179. + fi
  180. + local dd_args="if=$XIAOMI_FW_FILE skip=$offset bs=1 count=4"
  181. + if [ "$endianness" = "be" ]; then
  182. + hex=$( dd $dd_args 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"' )
  183. + else
  184. + hex=$( dd $dd_args 2>/dev/null | hexdump -v -e '1/4 "%02x"' )
  185. + fi
  186. + echo $( printf "%d" 0x$hex )
  187. +}
  188. +
  189. +get_hexdump_at() {
  190. + local offset=$1
  191. + local size=$2
  192. + if [ $(( $offset + $size )) -gt $XIAOMI_FW_SIZE ]; then
  193. + echo ""
  194. + return
  195. + fi
  196. + local dd_args="if=$XIAOMI_FW_FILE skip=$offset bs=1 count=$size"
  197. + echo $( dd $dd_args 2>/dev/null | hexdump -v -n $size -e '1/1 "%02x"' )
  198. +}
  199. +
  200. +get_round_up() {
  201. + local value=$1
  202. + local base=$2
  203. + local pad=0
  204. + if [ -z "$base" ]; then
  205. + base=$XIAOMI_PAGESIZE
  206. + else
  207. + base=$( printf "%d" $base )
  208. + fi
  209. + if [ $(( $value % $base )) != 0 ]; then
  210. + pad=$(( $base - $value % $base ))
  211. + fi
  212. + echo $(( $value + $pad ))
  213. +}
  214. +
  215. +get_part_size() {
  216. + local part_name=$1
  217. + local part=$( cat /proc/mtd | grep \"$part_name\" )
  218. + if [ -z "$part" ]; then
  219. + echo 0
  220. + else
  221. + local mtd_size_hex=$( echo $part | awk '{print "0x"$2}' )
  222. + echo $( printf "%d" $mtd_size_hex )
  223. + fi
  224. +}
  225. +
  226. +xiaomi_check_sizes() {
  227. + local part_name=$1
  228. + local img_offset=$2
  229. + local img_size=$3
  230. +
  231. + local mtd_size=$( get_part_size $part_name )
  232. + if [ "$mtd_size" = "0" ]; then
  233. + echo "cannot find mtd partition with name '$part_name'"
  234. + return 1
  235. + fi
  236. + local img_end=$(( $img_offset + $img_size ))
  237. + if [ $img_end -gt $XIAOMI_FW_SIZE ]; then
  238. + echo "incorrect image size (part: '$part_name')"
  239. + return 1
  240. + fi
  241. + if [ $img_size -gt $mtd_size ]; then
  242. + echo "image is greater than partition '$part_name'"
  243. + return 1
  244. + fi
  245. + echo ""
  246. + return 0
  247. +}
  248. +
  249. +xiaomi_mtd_write() {
  250. + local part_name=$1
  251. + local img_offset=$2
  252. + local img_size=$3
  253. + local part_skip=$4
  254. +
  255. + img_size=$( get_round_up $img_size )
  256. + local err=$( xiaomi_check_sizes $part_name $img_offset $img_size )
  257. + if [ -n "$err" ]; then
  258. + log_err $err
  259. + return 1
  260. + fi
  261. + if [ -n "$part_skip" ]; then
  262. + part_skip="-p $part_skip"
  263. + fi
  264. + local count=$(( $img_size / $XIAOMI_PAGESIZE ))
  265. + local dd_args="if=$XIAOMI_FW_FILE iflag=skip_bytes skip=$img_offset bs=$XIAOMI_PAGESIZE count=$count"
  266. + dd $dd_args | mtd -f $part_skip write - "$part_name" || {
  267. + log_err "Failed to flash '$part_name'"
  268. + return 1
  269. + }
  270. + return 0
  271. +}
  272. +
  273. +xiaomi_flash_images() {
  274. + local kernel_offset=$1
  275. + local kernel_size=$2
  276. + local rootfs_offset=$3
  277. + local rootfs_size=$4
  278. + local err
  279. + local part_skip=0
  280. +
  281. + kernel_size=$( get_round_up $kernel_size )
  282. + rootfs_size=$( get_round_up $rootfs_size )
  283. +
  284. + err=$( xiaomi_check_sizes $XIAOMI_KERNEL_PART $kernel_offset $kernel_size )
  285. + [ -n "$err" ] && { log_err $err; return 1; }
  286. +
  287. + if [ -n "$XIAOMI_KERNEL2_PART" ]; then
  288. + err=$( xiaomi_check_sizes $XIAOMI_KERNEL2_PART $kernel_offset $kernel_size )
  289. + [ -n "$err" ] && { log_err $err; return 1; }
  290. + fi
  291. +
  292. + err=$( xiaomi_check_sizes $XIAOMI_ROOTFS_PART $rootfs_offset $rootfs_size )
  293. + [ -n "$err" ] && { log_err $err; return 1; }
  294. +
  295. + if [ "$XIAOMI_RESTORE_ROOTFS2" = "true" -a -n "$XIAOMI_ROOTFS_PARTSIZE" ]; then
  296. + part_skip=$( printf "%d" $XIAOMI_ROOTFS_PARTSIZE )
  297. + if [ $part_skip -lt 1000000 ]; then
  298. + part_skip=0
  299. + fi
  300. + fi
  301. +
  302. + if [ $part_skip -gt 0 ]; then
  303. + local ksize=$(( $part_skip + $rootfs_size ))
  304. + local mtd_size=$( get_part_size $XIAOMI_ROOTFS_PART )
  305. + if [ $ksize -gt $mtd_size ]; then
  306. + log_err "double rootfs is greater than partition '$XIAOMI_ROOTFS_PART'"
  307. + return 1
  308. + fi
  309. + fi
  310. +
  311. + mtd erase "$XIAOMI_ROOTFS_PART" || {
  312. + log_err "Failed to erase partition '$part_name'"
  313. + return 1
  314. + }
  315. +
  316. + xiaomi_mtd_write $XIAOMI_KERNEL_PART $kernel_offset $kernel_size || {
  317. + log_err "Failed flash data to '$XIAOMI_KERNEL_PART' partition"
  318. + return 1
  319. + }
  320. + log_msg "Kernel image flashed to '$XIAOMI_KERNEL_PART'"
  321. +
  322. + if [ -n "$XIAOMI_KERNEL2_PART" ]; then
  323. + xiaomi_mtd_write $XIAOMI_KERNEL2_PART $kernel_offset $kernel_size || {
  324. + log_err "Failed flash data to '$XIAOMI_KERNEL2_PART' partition"
  325. + return 1
  326. + }
  327. + log_msg "Kernel image flashed to '$XIAOMI_KERNEL2_PART'"
  328. + fi
  329. +
  330. + xiaomi_mtd_write $XIAOMI_ROOTFS_PART $rootfs_offset $rootfs_size || {
  331. + log_err "Failed flash data to '$XIAOMI_ROOTFS_PART' partition"
  332. + return 1
  333. + }
  334. + log_msg "Rootfs image flashed to '$XIAOMI_ROOTFS_PART'!"
  335. +
  336. + if [ $part_skip -gt 0 ]; then
  337. + xiaomi_mtd_write $XIAOMI_ROOTFS_PART $rootfs_offset $rootfs_size $part_skip || {
  338. + log_err "Failed flash data to '$XIAOMI_ROOTFS_PART' partition (2)"
  339. + return 1
  340. + }
  341. + log_msg "Rootfs image flashed to '$XIAOMI_ROOTFS_PART':$XIAOMI_ROOTFS_PARTSIZE"
  342. + fi
  343. +
  344. + log_msg "Firmware write successful! Reboot..."
  345. + sync
  346. + umount -a
  347. + reboot -f
  348. + exit 0
  349. +}
  350. +
  351. +check_ubi_header() {
  352. + local offset=$1
  353. +
  354. + local magic=$( get_hexdump_at $offset 4 )
  355. + [ "$magic" != $MAGIC_UBI ] && { echo ""; return 1; }
  356. +
  357. + local magic_ubi2="55424921" # "UBI!"
  358. + offset=$(( $offset + $XIAOMI_PAGESIZE ))
  359. + magic=$( get_hexdump_at $offset 4 )
  360. + [ "$magic" != $magic_ubi2 ] && { echo ""; return 1; }
  361. +
  362. + echo "true"
  363. + return 0
  364. +}
  365. +
  366. +get_rootfs_offset() {
  367. + local start=$1
  368. + local pos offset align end
  369. +
  370. + for offset in 0 1 2 3 4; do
  371. + pos=$(( $start + $offset ))
  372. + [ -n "$( check_ubi_header $pos )" ] && { echo $pos; return 0; }
  373. + done
  374. +
  375. + for align in 4 8 16 32 64 128 256 512 1024 2048 4096; do
  376. + pos=$( get_round_up $start $align )
  377. + [ -n "$( check_ubi_header $pos )" ] && { echo $pos; return 0; }
  378. + done
  379. +
  380. + align=65536
  381. + pos=$( get_round_up $start $align )
  382. + end=$(( $pos + 3000000 ))
  383. + while true; do
  384. + [ $(( $pos + 150000 )) -gt $XIAOMI_FW_SIZE ] && break
  385. + [ -n "$( check_ubi_header $pos )" ] && { echo $pos; return 0; }
  386. + pos=$(( $pos + $align ))
  387. + [ $pos -ge $end ] && break
  388. + done
  389. +
  390. + echo ""
  391. + return 1
  392. +}
  393. +
  394. +xiaomi_do_factory_upgrade() {
  395. + local err
  396. + local magic
  397. + local kernel_offset kernel_size
  398. + local rootfs_offset rootfs_size
  399. +
  400. + local kernel_mtd="$( find_mtd_index $XIAOMI_KERNEL_PART )"
  401. + if [ -z "$kernel_mtd" ]; then
  402. + log_err "partition '$XIAOMI_KERNEL_PART' not found"
  403. + return 1
  404. + fi
  405. + log_msg "Forced factory upgrade..."
  406. +
  407. + kernel_offset=0
  408. + kernel_size=$( get_uint32_at 12 "be" )
  409. + kernel_size=$(( $kernel_size + 64 ))
  410. +
  411. + rootfs_offset=$( get_rootfs_offset $kernel_size )
  412. + if [ -z "$rootfs_offset" ]; then
  413. + log_err "can't find ubinized rootfs in the firmware image"
  414. + return 1
  415. + fi
  416. + rootfs_size=$(( $XIAOMI_FW_SIZE - $rootfs_offset ))
  417. + local rootfs_end=$(( $rootfs_offset + $rootfs_size ))
  418. +
  419. + XIAOMI_RESTORE_ROOTFS2=false
  420. + xiaomi_flash_images $kernel_offset $kernel_size $rootfs_offset $rootfs_size || {
  421. + log_err "can't flash factory image"
  422. + return 1
  423. + }
  424. + exit 0
  425. +}
  426. +
  427. +xiaomi_do_revert_stock() {
  428. + local err
  429. + local magic
  430. + local blk blkpos blk_magic offset file_size
  431. + local kernel_offset
  432. + local kernel_size=0
  433. + local rootfs_offset
  434. + local rootfs_size=0
  435. +
  436. + local kernel_mtd=$( find_mtd_index $XIAOMI_KERNEL_PART )
  437. + if [ -z "$kernel_mtd" ]; then
  438. + log_err "partition '$XIAOMI_KERNEL_PART' not found"
  439. + return 1
  440. + fi
  441. + log_msg "Forced revert to stock firmware..."
  442. +
  443. + for blk in 16 20 24 28 32 36; do
  444. + blkpos=$( get_uint32_at $blk )
  445. + [ -z "$blkpos" ] && continue
  446. + [ $blkpos -lt 48 ] && continue
  447. + blk_magic=$( get_hexdump_at $blkpos 4 )
  448. + [ "$blk_magic" != $MAGIC_XIAOMI_BLK ] && continue
  449. + offset=$(( $blkpos + 8 ))
  450. + file_size=$( get_uint32_at $offset 4 )
  451. + [ -z "$file_size" ] && continue
  452. + [ $file_size -lt 1000000 ] && continue
  453. + offset=$(( $blkpos + 48 ))
  454. + magic=$( get_hexdump_at $offset 4 )
  455. + if [ "$magic" = $MAGIC_UIMAGE ]; then
  456. + kernel_size=$file_size
  457. + kernel_offset=$offset
  458. + fi
  459. + if [ "$magic" = $MAGIC_UBI -o "$magic" = $MAGIC_HSQS ]; then
  460. + rootfs_size=$file_size
  461. + rootfs_offset=$offset
  462. + fi
  463. + done
  464. + if [ $kernel_size -eq 0 ]; then
  465. + log_err "incorrect stock firmware image (kernel not found)"
  466. + return 1
  467. + fi
  468. + if [ $rootfs_size -eq 0 ]; then
  469. + log_err "incorrect stock firmware image (rootfs not found)"
  470. + return 1
  471. + fi
  472. +
  473. + XIAOMI_RESTORE_ROOTFS2=true
  474. + xiaomi_flash_images $kernel_offset $kernel_size $rootfs_offset $rootfs_size || {
  475. + log_err "ERROR: can't revert to stock firmware"
  476. + return 1
  477. + }
  478. + exit 0
  479. +}
  480. +
  481. +platform_do_upgrade_xiaomi() {
  482. + XIAOMI_FW_FILE=$1
  483. + local stock_rootfs_size=$2
  484. + local magic
  485. + local kernel_mtd kernel2_mtd rootfs_mtd
  486. + local kernel2_part_list part_name
  487. +
  488. + XIAOMI_FW_SIZE=$( wc -c "$XIAOMI_FW_FILE" 2> /dev/null | awk '{print $1}' )
  489. + if [ -z "$XIAOMI_FW_SIZE" ]; then
  490. + log_err "File '$XIAOMI_FW_FILE' not found!"
  491. + exit 1
  492. + fi
  493. + if [ $XIAOMI_FW_SIZE -lt 1000000 ]; then
  494. + log_err "file '$XIAOMI_FW_FILE' is incorrect"
  495. + exit 1
  496. + fi
  497. +
  498. + kernel_mtd=$( find_mtd_index $XIAOMI_KERNEL_PART )
  499. + if [ -z "$kernel_mtd" ]; then
  500. + log_err "cannot find mtd partition for '$XIAOMI_KERNEL_PART'"
  501. + exit 1
  502. + fi
  503. + kernel2_part_list=$( echo "$XIAOMI_KERNEL2_NAMES" | sed 's/|/\n/g' )
  504. + for part_name in $kernel2_part_list; do
  505. + kernel2_mtd=$( find_mtd_index $part_name )
  506. + if [ -n "$kernel2_mtd" ]; then
  507. + XIAOMI_KERNEL2_PART="$part_name"
  508. + log_msg "Found alt kernel partition '$XIAOMI_KERNEL2_PART'"
  509. + break
  510. + fi
  511. + done
  512. + rootfs_mtd=$( find_mtd_index $XIAOMI_ROOTFS_PART )
  513. + if [ -z "$rootfs_mtd" ]; then
  514. + log_err "cannot find mtd partition for '$XIAOMI_ROOTFS_PART'"
  515. + exit 1
  516. + fi
  517. +
  518. + magic=$( get_hexdump_at 0 4 )
  519. +
  520. + # Flash factory image (uImage header)
  521. + if [ "$magic" = $MAGIC_UIMAGE ]; then
  522. + xiaomi_do_factory_upgrade
  523. + exit $?
  524. + fi
  525. +
  526. + # Revert to stock firmware ("HDR1" header)
  527. + if [ "$magic" = $MAGIC_XIAOMI_HDR1 ]; then
  528. + if [ -n "$stock_rootfs_size" ]; then
  529. + XIAOMI_ROOTFS_PARTSIZE=$stock_rootfs_size
  530. + fi
  531. + xiaomi_do_revert_stock
  532. + exit $?
  533. + fi
  534. +
  535. + magic=$( get_hexdump_at 0 8 )
  536. + if [ "$magic" != $MAGIC_SYSUPG ]; then
  537. + log_err "incorrect image for system upgrading!"
  538. + exit 1
  539. + fi
  540. + log_msg "SysUpgrade start..."
  541. + local tar_file=$XIAOMI_FW_FILE
  542. + local board_dir=$( tar tf $tar_file | grep -m 1 '^sysupgrade-.*/$' )
  543. + [ -z "$board_dir" ] && {
  544. + log_err "board dir not found"
  545. + exit 1
  546. + }
  547. + board_dir=${board_dir%/}
  548. +
  549. + local control_len=$( (tar xf $tar_file $board_dir/CONTROL -O | wc -c) 2> /dev/null)
  550. + if [ $control_len -lt 3 ]; then
  551. + log_err "incorrect stock firmware image (CONTROL not found)"
  552. + exit 1
  553. + fi
  554. + local kernel_len=$( (tar xf $tar_file $board_dir/kernel -O | wc -c) 2> /dev/null)
  555. + if [ $kernel_len -lt 1000000 ]; then
  556. + log_err "incorrect stock firmware image (kernel not found)"
  557. + exit 1
  558. + fi
  559. + local rootfs_len=$( (tar xf $tar_file $board_dir/root -O | wc -c) 2> /dev/null)
  560. + if [ $rootfs_len -lt 1000000 ]; then
  561. + log_err "incorrect stock firmware image (rootfs not found)"
  562. + exit 1
  563. + fi
  564. +
  565. + if [ -n "$XIAOMI_KERNEL2_PART" ]; then
  566. + tar Oxf $tar_file $board_dir/kernel | mtd -f write - $XIAOMI_KERNEL2_PART && {
  567. + log_msg "Kernel image flashed to '$XIAOMI_KERNEL2_PART'"
  568. + } || {
  569. + log_err "cannot flash partition '$XIAOMI_KERNEL2_PART'"
  570. + exit 1
  571. + }
  572. + fi
  573. +
  574. + nand_do_upgrade "$XIAOMI_FW_FILE"
  575. +}
  576. diff --git a/target/linux/ipq806x/files-5.15/arch/arm/boot/dts/qcom-ipq8064-r3d.dts b/target/linux/ipq806x/files-5.15/arch/arm/boot/dts/qcom-ipq8064-r3d.dts
  577. new file mode 100644
  578. index 0000000000000..fd952d230c5da
  579. --- /dev/null
  580. +++ b/target/linux/ipq806x/files-5.15/arch/arm/boot/dts/qcom-ipq8064-r3d.dts
  581. @@ -0,0 +1,479 @@
  582. +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
  583. +
  584. +#include "qcom-ipq8064-v2.0-smb208.dtsi"
  585. +
  586. +#include <dt-bindings/input/input.h>
  587. +
  588. +/ {
  589. + model = "Xiaomi Mi Router HD (R3D)";
  590. + compatible = "xiaomi,r3d", "qcom,ipq8064";
  591. +
  592. + memory@0 {
  593. + device_type = "memory";
  594. + reg = <0x42000000 0x1e000000>;
  595. + };
  596. +
  597. + reserved-memory {
  598. + rsvd@44600000 {
  599. + reg = <0x44600000 0x200000>; /* IPQ_TZ_APPS_ADDR */
  600. + no-map;
  601. + };
  602. + };
  603. +
  604. + aliases {
  605. + label-mac-device = &gmac1;
  606. +
  607. + mdio-gpio0 = &mdio0;
  608. +
  609. + led-boot = &led_status_yellow;
  610. + led-failsafe = &led_status_red;
  611. + led-running = &led_status_blue;
  612. + led-upgrade = &led_status_yellow;
  613. + };
  614. +
  615. + chosen {
  616. + bootargs = "rootfstype=squashfs noinitrd";
  617. + };
  618. +
  619. + keys {
  620. + compatible = "gpio-keys";
  621. + pinctrl-0 = <&button_pins>;
  622. + pinctrl-names = "default";
  623. +
  624. + reset {
  625. + label = "reset";
  626. + gpios = <&qcom_pinmux 16 GPIO_ACTIVE_LOW>;
  627. + linux,code = <KEY_RESTART>;
  628. + debounce-interval = <60>;
  629. + wakeup-source;
  630. + };
  631. +
  632. + power {
  633. + label = "power"; /* Labeled POWER on the device, but using for sleep mode */
  634. + gpios = <&qcom_pinmux 68 GPIO_ACTIVE_LOW>;
  635. + linux,code = <KEY_POWER>;
  636. + debounce-interval = <60>;
  637. + wakeup-source;
  638. + };
  639. + };
  640. +
  641. + leds {
  642. + compatible = "gpio-leds";
  643. + pinctrl-0 = <&led_pins>;
  644. + pinctrl-names = "default";
  645. +
  646. + led_status_red: led_status_red {
  647. + label = "red:status";
  648. + gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>;
  649. + default-state = "keep";
  650. + };
  651. +
  652. + led_status_blue: led_status_blue {
  653. + label = "blue:status";
  654. + gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>;
  655. + default-state = "keep";
  656. + };
  657. +
  658. + led_status_yellow: led_status_yellow {
  659. + label = "yellow:status";
  660. + gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>;
  661. + default-state = "keep";
  662. + };
  663. + };
  664. +
  665. + i2c_gpio_0 { // GSBI1
  666. + compatible = "i2c-gpio";
  667. + #address-cells = <1>;
  668. + #size-cells = <0>;
  669. + pinctrl-0 = <&i2c1_pins>;
  670. + pinctrl-names = "default";
  671. + sda-gpios = <&qcom_pinmux 53 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
  672. + scl-gpios = <&qcom_pinmux 54 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
  673. + i2c-gpio,delay-us = <5>;
  674. +
  675. + emc2301@2f {
  676. + compatible = "smsc,emc2301";
  677. + reg = <0x2f>;
  678. + #address-cells = <1>;
  679. + #size-cells = <0>;
  680. +
  681. + fan@0 {
  682. + reg = <0>;
  683. + pwm-output-mode = <1>;
  684. + };
  685. + };
  686. + };
  687. +
  688. + i2c_gpio_1 { // GSBI2
  689. + compatible = "i2c-gpio";
  690. + #address-cells = <1>;
  691. + #size-cells = <0>;
  692. + pinctrl-0 = <&i2c2_pins>;
  693. + pinctrl-names = "default";
  694. + sda-gpios = <&qcom_pinmux 24 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
  695. + scl-gpios = <&qcom_pinmux 25 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
  696. + i2c-gpio,delay-us = <5>;
  697. +
  698. + tmp75@48 {
  699. + compatible = "ti,tmp75";
  700. + reg = <0x48>;
  701. + #address-cells = <1>;
  702. + #size-cells = <0>;
  703. + #thermal-sensor-cells = <0>;
  704. + status = "okay";
  705. + };
  706. + };
  707. +};
  708. +
  709. +// https://github.com/openwrt/openwrt/commit/622ce713ca246aa465bf28d2a743f96999085ea2
  710. +// https://github.com/openwrt/openwrt/commit/2336c2dbb1929837f7e42d4315c8073342a5b46b
  711. +// https://forum.openwrt.org/t/failed-to-startup-an-ipq806x-router-on-kernel-5-4/60775/41
  712. +&CPU_SPC {
  713. + status = "disabled";
  714. +};
  715. +
  716. +&adm_dma {
  717. + status = "okay";
  718. +};
  719. +
  720. +&qcom_pinmux {
  721. + i2c1_pins: i2c1_pins { // GSBI1 - EMC2301
  722. + mux {
  723. + pins = "gpio53", "gpio54";
  724. + function = "gsbi1";
  725. + drive-strength = <12>;
  726. + bias-none;
  727. + input;
  728. + };
  729. + };
  730. +
  731. + i2c2_pins: i2c2_pins { // GSBI2 - TMP75
  732. + mux {
  733. + pins = "gpio24", "gpio25";
  734. + function = "gsbi2";
  735. + drive-strength = <12>;
  736. + bias-none;
  737. + input;
  738. + };
  739. + };
  740. +
  741. + button_pins: button_pins {
  742. + mux {
  743. + pins = "gpio16", "gpio68";
  744. + function = "gpio";
  745. + drive-strength = <2>;
  746. + bias-pull-up;
  747. + };
  748. + };
  749. +
  750. + led_pins: led_pins {
  751. + mux {
  752. + pins = "gpio7", "gpio8", "gpio9";
  753. + function = "gpio";
  754. + drive-strength = <2>;
  755. + bias-pull-up;
  756. + };
  757. + };
  758. +
  759. + usb_pwr_en_pins: usb_pwr_en_pins {
  760. + mux {
  761. + pins = "gpio56";
  762. + function = "gpio";
  763. + drive-strength = <12>;
  764. + bias-pull-up;
  765. + output-high;
  766. + };
  767. + };
  768. +};
  769. +
  770. +&sata_phy {
  771. + status = "okay";
  772. +};
  773. +
  774. +&sata {
  775. + status = "okay";
  776. +};
  777. +
  778. +&hs_phy_0 {
  779. + status = "okay";
  780. +};
  781. +
  782. +&ss_phy_0 {
  783. + status = "okay";
  784. +};
  785. +
  786. +&usb3_0 {
  787. + status = "okay";
  788. +};
  789. +
  790. +&hs_phy_1 {
  791. + status = "okay";
  792. +};
  793. +
  794. +&ss_phy_1 {
  795. + status = "okay";
  796. +};
  797. +
  798. +&usb3_1 {
  799. + status = "okay";
  800. + pinctrl-0 = <&usb_pwr_en_pins>;
  801. + pinctrl-names = "default";
  802. +};
  803. +
  804. +&pcie0 {
  805. + status = "okay";
  806. + reset-gpio = <&qcom_pinmux 3 GPIO_ACTIVE_LOW>;
  807. + pinctrl-0 = <&pcie0_pins>;
  808. + pinctrl-names = "default";
  809. +
  810. + bridge@0,0 {
  811. + reg = <0x00000000 0 0 0 0>;
  812. + #address-cells = <3>;
  813. + #size-cells = <2>;
  814. + ranges;
  815. +
  816. + wifi@1,0 {
  817. + compatible = "pci168c,0040";
  818. + reg = <0x00010000 0 0 0 0>;
  819. +
  820. + nvmem-cells = <&macaddr_art_1006>, <&precal_art_1000>;
  821. + nvmem-cell-names = "mac-address", "pre-calibration";
  822. + };
  823. + };
  824. +};
  825. +
  826. +&pcie1 {
  827. + status = "okay";
  828. + reset-gpio = <&qcom_pinmux 48 GPIO_ACTIVE_LOW>;
  829. + pinctrl-0 = <&pcie1_pins>;
  830. + pinctrl-names = "default";
  831. + max-link-speed = <1>;
  832. +
  833. + bridge@0,0 {
  834. + reg = <0x00000000 0 0 0 0>;
  835. + #address-cells = <3>;
  836. + #size-cells = <2>;
  837. + ranges;
  838. +
  839. + wifi@1,0 {
  840. + compatible = "pci168c,0040";
  841. + reg = <0x00010000 0 0 0 0>;
  842. +
  843. + nvmem-cells = <&macaddr_art_5006>, <&precal_art_5000>;
  844. + nvmem-cell-names = "mac-address", "pre-calibration";
  845. + };
  846. + };
  847. +};
  848. +
  849. +&nand {
  850. + status = "okay";
  851. +
  852. + pinctrl-0 = <&nand_pins>;
  853. + pinctrl-names = "default";
  854. +
  855. + nand@0 {
  856. + reg = <0>;
  857. + compatible = "qcom,nandcs";
  858. +
  859. + nand-bus-width = <8>;
  860. + nand-ecc-strength = <4>;
  861. + nand-ecc-step-size = <512>;
  862. +
  863. + nand-is-boot-medium;
  864. + qcom,boot-partitions = <0 0xf0000000>;
  865. +
  866. + partitions {
  867. + compatible = "fixed-partitions";
  868. + #address-cells = <1>;
  869. + #size-cells = <1>;
  870. +
  871. + partition@0 {
  872. + label = "SBL1";
  873. + reg = <0x0 0x40000>;
  874. + read-only;
  875. + };
  876. +
  877. + partition@40000 {
  878. + label = "MIBIB";
  879. + reg = <0x40000 0x80000>;
  880. + read-only;
  881. + };
  882. +
  883. + partition@c0000 {
  884. + label = "SBL2";
  885. + reg = <0xc0000 0x80000>;
  886. + read-only;
  887. + };
  888. +
  889. + partition@140000 {
  890. + label = "SBL3";
  891. + reg = <0x140000 0x80000>;
  892. + read-only;
  893. + };
  894. +
  895. + partition@1c0000 {
  896. + label = "DDRCONFIG";
  897. + reg = <0x1c0000 0x80000>;
  898. + read-only;
  899. + };
  900. +
  901. + partition@240000 {
  902. + label = "SSD";
  903. + reg = <0x240000 0x80000>;
  904. + read-only;
  905. + };
  906. +
  907. + partition@2c0000 {
  908. + label = "TZ";
  909. + reg = <0x2c0000 0x80000>;
  910. + read-only;
  911. + };
  912. +
  913. + partition@340000 {
  914. + label = "RPM";
  915. + reg = <0x340000 0x80000>;
  916. + read-only;
  917. + };
  918. +
  919. + partition@3c0000 {
  920. + label = "APPSBL";
  921. + reg = <0x3c0000 0x100000>;
  922. + read-only;
  923. + };
  924. +
  925. + partition@4c0000 {
  926. + label = "APPSBLENV";
  927. + reg = <0x4c0000 0x80000>;
  928. + };
  929. +
  930. + art: partition@540000 {
  931. + label = "ART";
  932. + reg = <0x540000 0x80000>;
  933. + read-only;
  934. +
  935. + compatible = "nvmem-cells";
  936. + #address-cells = <1>;
  937. + #size-cells = <1>;
  938. +
  939. + macaddr_art_0: macaddr@0 { // WAN (label)
  940. + reg = <0x0 0x6>;
  941. + };
  942. + macaddr_art_6: macaddr@6 { // LAN
  943. + reg = <0x6 0x6>;
  944. + };
  945. + macaddr_art_1006: macaddr@1006 { // WiFi 2g
  946. + reg = <0x1006 0x6>;
  947. + };
  948. + macaddr_art_5006: macaddr@5006 { // WiFi 5g
  949. + reg = <0x5006 0x6>;
  950. + };
  951. + precal_art_1000: precal@1000 {
  952. + reg = <0x1000 0x2f20>;
  953. + };
  954. + precal_art_5000: precal@5000 {
  955. + reg = <0x5000 0x2f20>;
  956. + };
  957. + };
  958. +
  959. + partition@5c0000 {
  960. + label = "BOOTCONFIG";
  961. + reg = <0x5c0000 0x40000>;
  962. + read-only;
  963. + };
  964. +
  965. + partition@600000 {
  966. + label = "bdata";
  967. + reg = <0x600000 0x80000>;
  968. + };
  969. +
  970. + partition@680000 {
  971. + label = "crash";
  972. + reg = <0x680000 0x80000>;
  973. + read-only;
  974. + };
  975. +
  976. + partition@700000 {
  977. + label = "crash_syslog";
  978. + reg = <0x700000 0x80000>;
  979. + read-only;
  980. + };
  981. +
  982. + partition@780000 {
  983. + label = "rsvd";
  984. + reg = <0x780000 0x80000>;
  985. + read-only;
  986. + };
  987. +
  988. + /* Stock U-Boot support Dual Boot */
  989. + partition@800000 {
  990. + label = "kernel_dup";
  991. + reg = <0x800000 0x400000>;
  992. + };
  993. +
  994. + partition@c00000 {
  995. + label = "kernel";
  996. + reg = <0xc00000 0x400000>;
  997. + };
  998. +
  999. + partition@1000000 {
  1000. + label = "ubi";
  1001. + reg = <0x1000000 0xf000000>;
  1002. + };
  1003. + };
  1004. + };
  1005. +};
  1006. +
  1007. +&mdio0 {
  1008. + status = "okay";
  1009. +
  1010. + pinctrl-0 = <&mdio0_pins>;
  1011. + pinctrl-names = "default";
  1012. +
  1013. + phy0: ethernet-phy@0 {
  1014. + reg = <0>;
  1015. + qca,ar8327-initvals = <
  1016. + 0x04 0x07600000 /* PAD0_MODE */
  1017. + 0x08 0x01000000 /* PAD5_MODE */
  1018. + 0x0c 0x00000080 /* PAD6_MODE */
  1019. + 0x7c 0x0000004e /* PORT0_STATUS */
  1020. + 0x94 0x0000004e /* PORT6_STATUS */
  1021. + 0xe0 0xc74164de /* SGMII_CTRL */
  1022. + 0xe4 0x0006a545 /* MAC_POWER_SEL */
  1023. + >;
  1024. + };
  1025. +
  1026. + phy4: ethernet-phy@4 {
  1027. + reg = <4>;
  1028. + };
  1029. +};
  1030. +
  1031. +&gmac1 {
  1032. + status = "okay";
  1033. + phy-mode = "rgmii";
  1034. + qcom,id = <1>;
  1035. +
  1036. + pinctrl-0 = <&rgmii2_pins>;
  1037. + pinctrl-names = "default";
  1038. +
  1039. + nvmem-cells = <&macaddr_art_0>;
  1040. + nvmem-cell-names = "mac-address";
  1041. +
  1042. + fixed-link {
  1043. + speed = <1000>;
  1044. + full-duplex;
  1045. + };
  1046. +};
  1047. +
  1048. +&gmac2 {
  1049. + status = "okay";
  1050. + phy-mode = "sgmii";
  1051. + qcom,id = <2>;
  1052. +
  1053. + nvmem-cells = <&macaddr_art_6>;
  1054. + nvmem-cell-names = "mac-address";
  1055. +
  1056. + fixed-link {
  1057. + speed = <1000>;
  1058. + full-duplex;
  1059. + };
  1060. +};
  1061. diff --git a/target/linux/ipq806x/image/generic.mk b/target/linux/ipq806x/image/generic.mk
  1062. index aac0a2c8fadfd..b437706cd445e 100644
  1063. --- a/target/linux/ipq806x/image/generic.mk
  1064. +++ b/target/linux/ipq806x/image/generic.mk
  1065. @@ -471,6 +471,23 @@ define Device/ubnt_unifi-ac-hd
  1066. endef
  1067. TARGET_DEVICES += ubnt_unifi-ac-hd
  1068. +define Device/xiaomi_r3d
  1069. + $(call Device/LegacyImage)
  1070. + DEVICE_VENDOR := Xiaomi
  1071. + DEVICE_MODEL := R3D
  1072. + SOC := qcom-ipq8064
  1073. + BLOCKSIZE := 128k
  1074. + PAGESIZE := 2048
  1075. + KERNEL_SIZE := 4096k
  1076. + IMAGE_SIZE := 86016k
  1077. + UBINIZE_OPTS := -E 5
  1078. + IMAGES := factory.bin sysupgrade.bin
  1079. + IMAGE/factory.bin := append-kernel | pad-to $$$$(KERNEL_SIZE) | append-ubi | pad-to $$$$(BLOCKSIZE) | check-size
  1080. + DEVICE_PACKAGES := kmod-i2c-gpio kmod-hwmon-lm75 kmod-hwmon-emc2305 hwmon-drivetemp \
  1081. + kmod-usb-storage-uas ath10k-firmware-qca9984-ct ath10k-firmware-qca99x0-ct
  1082. +endef
  1083. +TARGET_DEVICES += xiaomi_r3d
  1084. +
  1085. define Device/zyxel_nbg6817
  1086. DEVICE_VENDOR := ZyXEL
  1087. DEVICE_MODEL := NBG6817