ath79: GL-AR300M: provide NAND support; increase to 4 MB kernel
authorJeff Kletsky <git-commits@allycomm.com>
Sun, 2 Jun 2019 00:51:17 +0000 (17:51 -0700)
committerChuanhong Guo <gch981213@gmail.com>
Thu, 14 Nov 2019 06:38:58 +0000 (14:38 +0800)
The GL.iNet GL-AR300M has been supported by the ar71xx and ath79
platforms with access to its 16 MB NOR flash, but not its 128 MB
SPI NAND flash.

This commit provides support for the NAND through the upstream
SPI-NAND framework. Devices with both NOR and NAND flash can support
independent firmware on each, with U-Boot able to boot from either.
The OEM U-Boot will fall back to the NOR firmware after three
"unsuccessful" boots.

The family of GL-AR300M devices on the ath79 platform now includes:

  * glinet,gl-ar300m-lite       "generic" target, NOR-only board
  * glinet,gl-ar300m-nand       "nand" target
  * glinet,gl-ar300m-nor        "nand" target (NAND-aware)

NB: This commit increases the kernel size from 2 MB to 4 MB

"Force-less" sysupgrade is presently supported from the current
versions of following NOR-based firmwre images to the version of
glinet,gl-ar300m-nor firmware produced by this commit:

  * gl-ar300m            -- OEM v3 NOR    ar71xx (openwrt-ar300m16-*.bin)
  * gl-ar300m            -- OpenWrt 18.06 ar71xx
  * gl-ar300m            -- OpenWrt 19.07 ar71xx

Other upgrades to these images should be performed through U-Boot.

The GL-AR300M OEM U-Boot allows upload and flashing of either NOR
firmware (sysupgrade.bin) or NAND firmware (factory.img) through its
HTTP-based GUI. Serial connectivity is not required.

The glinet,gl-ar300m-nand and glinet,gl-ar300m-nor images generated
after this commit should safely flash each other using sysupgrade.

The boot counter is implemented by the OEM using u-boot-env. At this
time, it does not appear that the switch on the side of the unit can
be used to select NOR vs. NAND boot and the fail-over is only from
NAND to NOR. To save flash wear, it is only reset when running the
glinet,gl-ar300m-nand firmware.

NAND-specific base-files are used to remove impact on existing
generic and tiny targets.

As there is now no "generic" build appropriate for the GL-AR300M16,
(or for users of the GL-AR300M that do not need access to NAND)
it will be introduced in a subsequent commit.

Note: `mtd_get_mac_binary art 0x6` does not return the proper MAC
and the GL.iNet source indicates that only the 0x0 offset is valid

The ar71xx targets are unmodified.

Signed-off-by: Jeff Kletsky <git-commits@allycomm.com>
target/linux/ath79/dts/qca9531_glinet_gl-ar300m-lite.dts
target/linux/ath79/dts/qca9531_glinet_gl-ar300m-nand.dts
target/linux/ath79/dts/qca9531_glinet_gl-ar300m-nor.dts
target/linux/ath79/dts/qca9531_glinet_gl-ar300m.dtsi
target/linux/ath79/generic/base-files/etc/board.d/01_leds
target/linux/ath79/image/generic.mk
target/linux/ath79/image/nand.mk
target/linux/ath79/nand/base-files/etc/board.d/01_leds
target/linux/ath79/nand/base-files/etc/init.d/bootcount [new file with mode: 0755]
target/linux/ath79/nand/base-files/lib/upgrade/glinet.sh [new file with mode: 0644]
target/linux/ath79/nand/base-files/lib/upgrade/platform.sh

index 148d0175404b4f134510b2529bc6d2163f8939cb..ed00cdb585d9be50f35ac5ccd434cb45dc229c1f 100644 (file)
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+
 /dts-v1/;
 
 #include "qca9531_glinet_gl-ar300m.dtsi"
@@ -7,6 +9,8 @@
        model = "GL.iNet GL-AR300M-Lite";
 };
 
+/delete-node/ &nand_flash;
+
 // "Disable" unpopulated GMAC1
 
 &eth1 {
index 26c30f2b72b31d3bd80dfa08082d7bd031916e99..00f9f5c82ddef3b4f4eeaf7ef577d808db423bd4 100644 (file)
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+
 /dts-v1/;
 
 #include "qca9531_glinet_gl-ar300m.dtsi"
@@ -7,28 +9,10 @@
        model = "GL.iNet GL-AR300M (NAND)";
 };
 
-&spi {
-       num-cs = <1>;
-
-       flash@1 {
-               compatible = "spinand,mt29f";
-               reg = <1>;
-               spi-max-frequency = <25000000>;
-
-               partitions {
-                       compatible = "fixed-partitions";
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-
-                       partition@0 {
-                               label = "kernel";
-                               reg = <0x000000 0x0200000>;
-                       };
+&nand_kernel {
+       label = "kernel";
+};
 
-                       partition@1 {
-                               label = "ubi";
-                               reg = <0x200000 0x7e00000>;
-                       };
-               };
-       };
+&nand_ubi {
+       label = "ubi";
 };
index 22e5ae4e7480929bad47725aeb5aba1759e3a17e..34f48f5f612672682f52a11be81fe1d9faa7b37d 100644 (file)
@@ -6,3 +6,8 @@
        compatible = "glinet,gl-ar300m-nor", "qca,qca9531";
        model = "GL.iNet GL-AR300M (NOR)";
 };
+
+&nor_firmware {
+       compatible = "denx,uimage";
+       label = "firmware";
+};
index 78961bf71b5450f969073900bfceafeea1d9c05d..72bc2a6466e45055ef824570260eb577b05c33d1 100644 (file)
@@ -42,7 +42,7 @@
        leds {
                compatible = "gpio-leds";
 
-               // Colors from non-Lite versions
+               // Colors for non-Lite versions
 
                led_status: status {
                        label = "gl-ar300m:green:status";
 
 &spi {
        status = "okay";
-       num-cs = <0>;
+
+       num-cs = <2>;
+       cs-gpios = <0>, <0>;
 
        flash@0 {
-               compatible = "winbond,w25q128", "jedec,spi-nor";
+               compatible = "jedec,spi-nor";
                reg = <0>;
                spi-max-frequency = <25000000>;
 
                                read-only;
                        };
 
-                       partition@1 {
+                       partition@40000 {
                                label = "u-boot-env";
                                reg = <0x040000 0x010000>;
                        };
 
-                       partition@2 {
-                               compatible = "denx,uimage";
-                               label = "firmware";
+                       nor_firmware: partition@50000 {
+                               label = "nor_firmware";
                                reg = <0x050000 0xfa0000>;
                        };
 
-                       art: partition@3 {
+                       art: partition@ff0000 {
                                label = "art";
                                reg = <0xff0000 0x010000>;
                                read-only;
                        };
                };
        };
+
+       nand_flash: flash@1 {
+               compatible = "spi-nand";
+               reg = <1>;
+               spi-max-frequency = <25000000>;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       nand_kernel: partition@0 {
+                               label = "nand_kernel";
+                               reg = <0x000000 0x400000>;
+                       };
+
+                       nand_ubi: partition@400000 {
+                               label = "nand_ubi";
+                               reg = <0x400000 0x7c00000>;
+                       };
+               };
+       };
 };
 
 &uart {
index de2c8e919711bfeef2def4e127617710e136d733..4ab504654e3e6501847589951fd99ef34de0fcbf 100755 (executable)
@@ -94,9 +94,6 @@ glinet,gl-ar150)
        ucidef_set_led_netdev "wan" "WAN" "$boardname:green:wan" "eth1"
        ucidef_set_led_switch "lan" "LAN" "$boardname:green:lan" "switch0" "0x02"
        ;;
-glinet,gl-ar300m-nor)
-       ucidef_set_led_netdev "lan" "LAN" "gl-ar300m:green:lan" "eth0"
-       ;;
 glinet,gl-ar300m-lite)
        ucidef_set_led_netdev "lan" "LAN" "gl-ar300m-lite:green:lan" "eth0"
        ;;
index 70631c20d0f2fb9ffc66e075449b5ff1d58fd636..011bb41262069f3351c6ada5ce740061c536eb05 100644 (file)
@@ -562,12 +562,6 @@ define Device/glinet_gl-ar300m-lite
 endef
 TARGET_DEVICES += glinet_gl-ar300m-lite
 
-define Device/glinet_gl-ar300m-nor
-  $(Device/glinet_gl-ar300m-common-nor)
-  DEVICE_MODEL := GL-AR300M
-endef
-TARGET_DEVICES += glinet_gl-ar300m-nor
-
 define Device/glinet_gl-ar750
   ATH_SOC := qca9531
   DEVICE_VENDOR := GL.iNet
index ef6b607002055ec25333cca75de755274f972504..f9961840f0daf9faffbb9dc3c194a0da4418abb6 100644 (file)
@@ -45,22 +45,36 @@ define Device/aerohive_hiveap-121
 endef
 TARGET_DEVICES += aerohive_hiveap-121
 
-define Device/glinet_gl-ar300m-nand
+define Device/glinet_gl-ar300m-common-nand
   ATH_SOC := qca9531
   DEVICE_VENDOR := GL.iNet
   DEVICE_MODEL := GL-AR300M
+  DEVICE_PACKAGES := kmod-usb2
+  KERNEL_SIZE := 4096k
+  IMAGE_SIZE := 16000k
+  PAGESIZE := 2048
+  VID_HDR_OFFSET := 2048
+endef
+
+define Device/glinet_gl-ar300m-nand
+  $(Device/glinet_gl-ar300m-common-nand)
   DEVICE_VARIANT := NAND
-  DEVICE_PACKAGES := kmod-usb2 kmod-usb-storage kmod-usb-ledtrig-usbport
-  KERNEL_SIZE := 2048k
   BLOCKSIZE := 128k
-  PAGESIZE := 2048
-  VID_HDR_OFFSET := 512
-  IMAGES += factory.ubi
-  IMAGE/sysupgrade.bin := sysupgrade-tar
-  IMAGE/factory.ubi := append-kernel | pad-to $$$$(KERNEL_SIZE) | append-ubi
+  IMAGES += factory.img
+  IMAGE/factory.img := append-kernel | pad-to $$$$(KERNEL_SIZE) | append-ubi
+  IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata
+  SUPPORTED_DEVICES += glinet,gl-ar300m-nor
 endef
 TARGET_DEVICES += glinet_gl-ar300m-nand
 
+define Device/glinet_gl-ar300m-nor
+  $(Device/glinet_gl-ar300m-common-nand)
+  DEVICE_VARIANT := NOR
+  BLOCKSIZE := 64k
+  SUPPORTED_DEVICES += glinet,gl-ar300m-nand gl-ar300m
+endef
+TARGET_DEVICES += glinet_gl-ar300m-nor
+
 # fake rootfs is mandatory, pad-offset 129 equals (2 * uimage_header + 0xff)
 define Device/netgear_ath79_nand
   DEVICE_VENDOR := NETGEAR
index f851b3d8861ba97ac52bff4a0ac029644293b573..f58527d87e2edf2a4bad3ac1ec781eb7693b5b9e 100755 (executable)
@@ -8,7 +8,8 @@ board=$(board_name)
 boardname="${board##*,}"
 
 case "$board" in
-glinet,gl-ar300m-nand)
+glinet,gl-ar300m-nand|\
+glinet,gl-ar300m-nor)
        ucidef_set_led_netdev "lan" "LAN" "gl-ar300m:green:lan" "eth0"
        ;;
 netgear,wndr4300)
diff --git a/target/linux/ath79/nand/base-files/etc/init.d/bootcount b/target/linux/ath79/nand/base-files/etc/init.d/bootcount
new file mode 100755 (executable)
index 0000000..c82386b
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/sh /etc/rc.common
+
+# SPDX-License-Identifier: GPL-2.0
+
+START=99
+
+boot() {
+       case $(board_name) in
+       glinet,gl-ar300m-nand)
+               fw_setenv bootcount 0
+               ;;
+       esac
+}
diff --git a/target/linux/ath79/nand/base-files/lib/upgrade/glinet.sh b/target/linux/ath79/nand/base-files/lib/upgrade/glinet.sh
new file mode 100644 (file)
index 0000000..86729f8
--- /dev/null
@@ -0,0 +1,90 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (C) 2019 Jeff Kletsky
+#
+
+glinet_using_boot_dev_switch() {
+       if [ "$(fw_printenv -n boot_dev 2>/dev/null)" = "on" ] ; then
+               >&2 echo "NOTE: boot_dev=on; use switch to control boot partition"
+               true
+       else
+               false
+       fi
+}
+
+glinet_set_next_boot_nand() {
+       mkdir -p /var/lock
+       ! glinet_using_boot_dev_switch && \
+               fw_setenv bootcount 0 &&  \
+               >&2 echo "Next boot set for NAND"
+}
+
+glinet_set_next_boot_nor() {
+       mkdir -p /var/lock
+       ! glinet_using_boot_dev_switch && \
+               fw_setenv bootcount 3 &&  \
+               >&2 echo "Next boot set for NOR"
+}
+
+glinet_nand_nor_do_upgrade() {
+       set_next_boot_nand() { glinet_set_next_boot_nand; }
+       set_next_boot_nor() { glinet_set_next_boot_nor; }
+       nand_nor_do_upgrade "$1"
+}
+
+nand_nor_do_upgrade() {
+       local upgrade_file="$1"
+
+       local pn
+       local found=""
+       local err
+
+       case "$(get_magic_long "$upgrade_file")" in
+
+       "27051956")     # U-Boot Image Magic
+
+               for pn in "nor_${PART_NAME}" "$PART_NAME" ; do          # firmware
+                       if [ "$(find_mtd_index "$pn")" ] ; then
+                               PART_NAME="$pn"
+                               found="yes"
+                               break
+                       fi
+               done
+               if [ "$found" = "yes" ] ; then
+                       >&2 echo "Running NOR upgrade"
+                       default_do_upgrade "$upgrade_file"
+                       # At this time, default_do_upgrade() exits on error
+                       type set_next_boot_nor >/dev/null && set_next_boot_nor
+               else
+                       >&2 echo "ERROR: UPGRADE FAILED: Unable to locate '$PART_NAME' or 'nor_${PART_NAME}'"
+                       exit 1
+               fi
+               ;;
+
+       *)      # otherwise a file that nand_do_upgrade can process
+
+               for pn in "nand_${CI_KERNPART}" "$CI_KERNPART" ; do     # kernel
+                       if [ "$(find_mtd_index "$pn")" ] ; then
+                               CI_KERNPART="$pn"
+                               break
+                       fi
+               done
+               for pn in "nand_${CI_UBIPART}" "$CI_UBIPART" ; do       # ubi
+                       if [ "$(find_mtd_index "$pn")" ] ; then
+                               CI_UBIPART="$pn"
+                               break
+                       fi
+               done
+               for pn in "nand_${CI_ROOTPART}" "$CI_ROOTPART" ; do     #rootfs
+                       if [ "$(find_mtd_index "$pn")" ] ; then
+                               CI_ROOTPART="$pn"
+                               break
+                       fi
+               done
+               >&2 echo "Running NAND upgrade"
+               # TODO: change order when NAND upgrade offers return
+               type set_next_boot_nand >/dev/null && set_next_boot_nand
+               nand_do_upgrade "$upgrade_file"
+               ;;
+       esac
+}
index 3956d5d73f6c7e2f5bd409a6f60bf8a70346b61f..69105b166825f40de770e0045211c4a29b085923 100644 (file)
@@ -1,20 +1,22 @@
-#
 # Copyright (C) 2011 OpenWrt.org
-#
 
 PART_NAME=firmware
-REQUIRE_IMAGE_METADATA=1
 
+REQUIRE_IMAGE_METADATA=1
 platform_check_image() {
        return 0
 }
 
+RAMFS_COPY_BIN='fw_printenv fw_setenv'
+RAMFS_COPY_DATA='/etc/fw_env.config /var/lock/fw_printenv.lock'
+
 platform_do_upgrade() {
        local board=$(board_name)
 
        case "$board" in
-       glinet,gl-ar300m-nand)
-               default_do_upgrade "$1"
+       glinet,gl-ar300m-nand|\
+       glinet,gl-ar300m-nor)
+               glinet_nand_nor_do_upgrade "$1"
                ;;
        *)
                nand_do_upgrade "$1"