diff mbox series

[RFC,5/5] ipq40xx: add target for Google WiFi (Gale)

Message ID 20200718205148.1743807-6-computersforpeace@gmail.com
State Superseded
Headers show
Series Add support for Chromium OS and Google WiFi | expand

Commit Message

Brian Norris July 18, 2020, 8:51 p.m. UTC
Google WiFi (codename: Gale) is an IPQ4019-based AP, with 2 Ethernet
ports, 2x2 2.4+5GHz WiFi, 512 MB RAM, 4 GB eMMC, and a USB type C port.
In its stock configuration, it runs a Chromium OS-based system, but you
wouldn't know it, since you can only manage it via a "cloud" +
mobile-app system.

The "v2" label is coded into the bootloader, which prefers the
"google,gale-v2" compatible string. I believe "v1" must have been
pre-release hardware.

Note: this is *not* the Google Nest WiFi, released in 2019.

I include "factory.bin" support, where we generate a GPT-based disk
image with 2 partitions -- a kernel partition (using the custom "Chrome
OS kernel" GUID type) and a root filesystem partition. If the AP is in
Developer Mode, the stock bootloader can boot it via a USB disk or
(after gaining access via USB boot) flashed to the eMMC.

Sysupgrade also seems to work OK, although I've omitted some of the
(re)partitioning handling. I also hard-code /dev/mmcblk0 -- while MMC
device numbering can technically change, there's no other MMC controller
present (e.g., no SD card slot).

"FEATURES=boot-part rootfs-part" is required to get kernel and rootfs
partition sizes established. This adds extra (unused) configuration
parameters for other ipq40xx targets, so I'm not sure if this is the
"right" thing to do either.

Features I have tested:

 * Ethernet, both WAN and LAN ports
 * eMMC
 * USB-C (hub, power-delivery, peripherals)
 * LED0 (R/G/B)
 * WiFi (limited testing)
 * SPI flash
 * Serial console: once in developer mode, console can be accessed via
   the USB-C port with SuzyQable, or other similar "Closed Case
   Debugging" tools:
     https://chromium.googlesource.com/chromiumos/third_party/hdctools/+/master/docs/ccd.md#suzyq-suzyqable

Not tested:

 * TPM
 * LED1, LED2: I'm not even confident they are actually populated
   anywhere

Known not working:

 * Reboot: this seems to require some additional TrustZone / SCM
   configuration; with additional local patches, I have this working,
   but I'm still trying to figure out exactly the right way I should
   integrate this. Ideally, I could propose it upstream, instead of just
   adding a custom OpenWRT patch. Without this patch, reboot just hangs
   the system. (NB: I've found at least one other user report of this on
   an "IPQ4019" device, but I don't know yet if that's the same.)
 * There's a single external button, and a few useful internal GPIO
   switches. I haven't hooked them up.

Much of the DTS is pulled from the Chrome OS kernel 3.18 branch, which
the manufacturer image uses.

Note: the manufacturer bootloader knows how to patch in calibration data
via the wifi{0,1} aliases in the DTB, so while these properties aren't
present in the DTS, they are available at runtime:

  # ls -l
/sys/firmware/devicetree/base/soc/wifi@a*/qcom,ath10k-pre-calibration-data
  -r--r--r--    1 root     root         12064 Jul 15 19:11 /sys/firmware/devicetree/base/soc/wifi@a000000/qcom,ath10k-pre-calibration-data
  -r--r--r--    1 root     root         12064 Jul 15 19:11 /sys/firmware/devicetree/base/soc/wifi@a800000/qcom,ath10k-pre-calibration-data

Ethernet MAC addresses are similarly patched in via the ethernet{0,1} aliases.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
 target/linux/ipq40xx/Makefile                 |   2 +-
 .../ipq40xx/base-files/etc/board.d/02_network |   1 +
 .../base-files/lib/upgrade/platform.sh        |  13 +
 .../arm/boot/dts/qcom-ipq4019-gale-v2.dts     | 402 ++++++++++++++++++
 target/linux/ipq40xx/image/Makefile           |  14 +
 .../901-arm-boot-add-dts-files.patch          |   3 +-
 6 files changed, 433 insertions(+), 2 deletions(-)
 create mode 100644 target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-gale-v2.dts

Comments

Adrian Schmutzler July 18, 2020, 9:12 p.m. UTC | #1
Hi,

just some formal stuff below.

> -----Original Message-----
> From: openwrt-devel [mailto:openwrt-devel-bounces@lists.openwrt.org]
> On Behalf Of Brian Norris
> Sent: Samstag, 18. Juli 2020 22:52
> To: openwrt-devel@lists.openwrt.org
> Cc: Brian Norris <computersforpeace@gmail.com>
> Subject: [RFC PATCH 5/5] ipq40xx: add target for Google WiFi (Gale)
> 
> Google WiFi (codename: Gale) is an IPQ4019-based AP, with 2 Ethernet
> ports, 2x2 2.4+5GHz WiFi, 512 MB RAM, 4 GB eMMC, and a USB type C port.
> In its stock configuration, it runs a Chromium OS-based system, but you
> wouldn't know it, since you can only manage it via a "cloud" + mobile-app
> system.
> 
> The "v2" label is coded into the bootloader, which prefers the "google,gale-
> v2" compatible string. I believe "v1" must have been pre-release hardware.
> 
> Note: this is *not* the Google Nest WiFi, released in 2019.
> 
> I include "factory.bin" support, where we generate a GPT-based disk image
> with 2 partitions -- a kernel partition (using the custom "Chrome OS kernel"
> GUID type) and a root filesystem partition. If the AP is in Developer Mode,
> the stock bootloader can boot it via a USB disk or (after gaining access via USB
> boot) flashed to the eMMC.

I'd like a bit more detailed flashing instructions here. What you have right now only works if the reader knows what to do anyway.

> 
> Sysupgrade also seems to work OK, although I've omitted some of the
> (re)partitioning handling. I also hard-code /dev/mmcblk0 -- while MMC
> device numbering can technically change, there's no other MMC controller
> present (e.g., no SD card slot).
> 
> "FEATURES=boot-part rootfs-part" is required to get kernel and rootfs
> partition sizes established. This adds extra (unused) configuration
> parameters for other ipq40xx targets, so I'm not sure if this is the "right"
> thing to do either.
> 
> Features I have tested:
> 
>  * Ethernet, both WAN and LAN ports
>  * eMMC
>  * USB-C (hub, power-delivery, peripherals)
>  * LED0 (R/G/B)
>  * WiFi (limited testing)
>  * SPI flash
>  * Serial console: once in developer mode, console can be accessed via
>    the USB-C port with SuzyQable, or other similar "Closed Case
>    Debugging" tools:
> 
> https://chromium.googlesource.com/chromiumos/third_party/hdctools/+/
> master/docs/ccd.md#suzyq-suzyqable
> 
> Not tested:
> 
>  * TPM
>  * LED1, LED2: I'm not even confident they are actually populated
>    anywhere
> 
> Known not working:
> 
>  * Reboot: this seems to require some additional TrustZone / SCM
>    configuration; with additional local patches, I have this working,
>    but I'm still trying to figure out exactly the right way I should
>    integrate this. Ideally, I could propose it upstream, instead of just
>    adding a custom OpenWRT patch. Without this patch, reboot just hangs
>    the system. (NB: I've found at least one other user report of this on
>    an "IPQ4019" device, but I don't know yet if that's the same.)
>  * There's a single external button, and a few useful internal GPIO
>    switches. I haven't hooked them up.
> 
> Much of the DTS is pulled from the Chrome OS kernel 3.18 branch, which the
> manufacturer image uses.
> 
> Note: the manufacturer bootloader knows how to patch in calibration data
> via the wifi{0,1} aliases in the DTB, so while these properties aren't present in
> the DTS, they are available at runtime:
> 
>   # ls -l
> /sys/firmware/devicetree/base/soc/wifi@a*/qcom,ath10k-pre-calibration-
> data
>   -r--r--r--    1 root     root         12064 Jul 15 19:11
> /sys/firmware/devicetree/base/soc/wifi@a000000/qcom,ath10k-pre-
> calibration-data
>   -r--r--r--    1 root     root         12064 Jul 15 19:11
> /sys/firmware/devicetree/base/soc/wifi@a800000/qcom,ath10k-pre-
> calibration-data
> 
> Ethernet MAC addresses are similarly patched in via the ethernet{0,1}
> aliases.
> 
> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
> ---
>  target/linux/ipq40xx/Makefile                 |   2 +-
>  .../ipq40xx/base-files/etc/board.d/02_network |   1 +
>  .../base-files/lib/upgrade/platform.sh        |  13 +
>  .../arm/boot/dts/qcom-ipq4019-gale-v2.dts     | 402 ++++++++++++++++++
>  target/linux/ipq40xx/image/Makefile           |  14 +
>  .../901-arm-boot-add-dts-files.patch          |   3 +-
>  6 files changed, 433 insertions(+), 2 deletions(-)  create mode 100644
> target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-gale-v2.dts
> 
> diff --git a/target/linux/ipq40xx/Makefile b/target/linux/ipq40xx/Makefile
> index 94b47c4c96de..c114df620d5c 100644
> --- a/target/linux/ipq40xx/Makefile
> +++ b/target/linux/ipq40xx/Makefile
> @@ -3,7 +3,7 @@ include $(TOPDIR)/rules.mk  ARCH:=arm  BOARD:=ipq40xx
> BOARDNAME:=Qualcomm Atheros IPQ40XX -FEATURES:=squashfs fpu
> ramdisk nand
> +FEATURES:=squashfs fpu ramdisk nand boot-part rootfs-part
>  CPU_TYPE:=cortex-a7
>  CPU_SUBTYPE:=neon-vfpv4
>  SUBTARGETS:=generic
> diff --git a/target/linux/ipq40xx/base-files/etc/board.d/02_network
> b/target/linux/ipq40xx/base-files/etc/board.d/02_network
> index 61d02a17bcc9..f6b2f47e6ce6 100755
> --- a/target/linux/ipq40xx/base-files/etc/board.d/02_network
> +++ b/target/linux/ipq40xx/base-files/etc/board.d/02_network
> @@ -38,6 +38,7 @@ ipq40xx_setup_interfaces()
>  		;;
>  	asus,map-ac2200|\
>  	cilab,meshpoint-one|\
> +	google,gale-v2|\
>  	openmesh,a42|\
>  	openmesh,a62)
>  		ucidef_set_interfaces_lan_wan "eth1" "eth0"
> diff --git a/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh
> b/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh
> index 5b89710a2255..9cc77e8cb4d0 100644
> --- a/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh
> +++ b/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh
> @@ -40,6 +40,16 @@ askey_do_upgrade() {
>  	nand_do_upgrade "$1"
>  }
> 
> +vboot_do_upgrade() {
> +	local tar_file="$1"
> +
> +	echo "Preparing to flash to /dev/mmcblk0p{1,2}"
> +	ask_bool 0 "Abort" && exit 1
> +
> +	tar Oxf "${tar_file}" '*/kernel' | dd of=/dev/mmcblk0p1 bs=1M
> +	tar Oxf "${tar_file}" '*/root' | dd of=/dev/mmcblk0p2 bs=1M }
> +
>  zyxel_do_upgrade() {
>  	local tar_file="$1"
> 
> @@ -98,6 +108,9 @@ platform_do_upgrade() {
>  	compex,wpj419)
>  		nand_do_upgrade "$1"
>  		;;
> +	google,gale-v2)
> +		vboot_do_upgrade "$1"
> +		;;
>  	linksys,ea6350v3 |\
>  	linksys,ea8300)
>  		platform_do_upgrade_linksys "$1"
> diff --git a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-gale-
> v2.dts b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-gale-
> v2.dts
> new file mode 100644
> index 000000000000..ce0d2b91d05a
> --- /dev/null
> +++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-gale-v2.
> +++ dts
> @@ -0,0 +1,402 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2016, 2018 The Linux Foundation. All rights reserved.
> + * Copyright (c) 2016 Google, Inc
> + */
> +
> +#include "qcom-ipq4019.dtsi"
> +#include <dt-bindings/input/input.h>
> +#include <dt-bindings/gpio/gpio.h>
> +
> +&tlmm {

I'd have expected the root node first.

> +	fw_pinmux {
> +		wp {
> +			pins = "gpio53";
> +			output-low;
> +		};
> +		recovery {
> +			pins = "gpio57";
> +			bias-none;
> +		};
> +		developer {
> +			pins = "gpio41";
> +			bias-none;
> +		};
> +	};
> +
> +	reset802_15_4 {
> +		pins = "gpio60";
> +	};
> +
> +	led_reset {
> +		pins = "gpio22";
> +		output-high;
> +	};
> +
> +	sys_reset {
> +		pins = "gpio19";
> +		output-high;
> +	};
> +
> +	rx_active {
> +		pins = "gpio43";
> +		bias-pull,down;
> +	};
> +
> +	spi_0_pins: spi_0_pinmux {
> +		pinmux {
> +			function = "blsp_spi0";
> +			pins = "gpio13", "gpio14","gpio15";
> +		};
> +		pinmux_cs {
> +			function = "gpio";
> +			pins = "gpio12";
> +		};
> +		pinconf {
> +			pins = "gpio13", "gpio14","gpio15";
> +			drive-strength = <12>;
> +			bias-disable;
> +		};
> +		pinconf_cs {
> +			pins = "gpio12";
> +			drive-strength = <2>;
> +			bias-disable;
> +			output-high;
> +		};
> +	};
> +
> +	spi_1_pins: spi_1_pinmux {
> +		pinmux {
> +			function = "blsp_spi1";
> +			pins = "gpio44", "gpio46","gpio47";
> +		};
> +		pinmux_cs {
> +			function = "gpio";
> +			pins = "gpio45";
> +		};
> +		pinconf {
> +			pins = "gpio44", "gpio46","gpio47";
> +			drive-strength = <12>;
> +			bias-disable;
> +		};
> +		pinconf_cs {
> +			pins = "gpio45";
> +			drive-strength = <2>;
> +			bias-disable;
> +			output-high;
> +		};
> +	};
> +
> +	serial_0_pins: serial0_pinmux {
> +		mux {
> +			pins = "gpio16", "gpio17";
> +			function = "blsp_uart0";
> +			bias-disable;
> +		};
> +	};
> +
> +	serial_1_pins: serial1_pinmux {
> +		mux {
> +			pins = "gpio8", "gpio9", "gpio10", "gpio11";
> +			function = "blsp_uart1";
> +			bias-disable;
> +		};
> +	};
> +
> +	i2c_0_pins: i2c_0_pinmux {
> +		mux {
> +			pins = "gpio20", "gpio21";
> +			function = "blsp_i2c0";
> +			drive-open-drain;
> +		};
> +	};
> +
> +	i2c_1_pins: i2c_1_pinmux {
> +		mux {
> +			pins = "gpio34", "gpio35";
> +			function = "blsp_i2c1";
> +			drive-open-drain;
> +		};
> +	};
> +
> +	sd_0_pins: sd_0_pinmux {
> +		sd0 {
> +			pins = "gpio23", "gpio24", "gpio25", "gpio26",
> "gpio29", "gpio30", "gpio31", "gpio32";
> +			function = "sdio";
> +			drive-strength = <10>;
> +			bias-pull-up;
> +			pull-up-res = <0>;
> +		};
> +		sdclk {
> +			pins = "gpio27";
> +			function = "sdio";
> +			drive-strength = <2>;
> +			bias-pull-up;
> +			pull-up-res = <0>;
> +		};
> +		sdcmd {
> +			pins = "gpio28";
> +			function = "sdio";
> +			drive-strength = <10>;
> +			bias-pull-up;
> +			pull-up-res = <0>;
> +		};
> +	};
> +
> +	mdio_pins: mdio_pinmux {
> +		mux_1 {
> +			pins = "gpio6";
> +			function = "mdio";
> +			bias-disable;
> +		};
> +		mux_2 {
> +			pins = "gpio7";
> +			function = "mdc";
> +			bias-disable;
> +		};
> +		mux_3 {
> +			pins = "gpio40";
> +			function = "gpio";
> +			bias-disable;
> +			output-high;
> +		};
> +	};
> +
> +	wifi1_1_pins: wifi2_pinmux {
> +		mux {
> +			pins = "gpio58";
> +			output-low;
> +		};
> +	};
> +};
> +
> +/ {
> +	model = "Google IPQ4019/Gale";

This should be generally consistent with what you choose for DEVICE_MODEL. See my others comments there below.

> +	compatible = "google,gale-v2", "qcom,ipq4019";
> +
> +	chosen {
> +		stdout-path = &blsp1_uart1;
> +	};
> +
> +	memory {
> +		device_type = "memory";
> +		reg = <0x80000000 0x20000000>; /* 512MB */
> +	};
> +
> +	reserved-memory {
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		ranges;
> +
> +		rsvd@87000000 {
> +			/* Reserved for other subsystem */
> +			reg = <0x87000000 0x01000000>;
> +			no-map;
> +		};
> +	};
> +
> +	soc {
> +		blsp_dma: dma@7884000 {
> +			status = "okay";
> +		};
> +
> +		usb3: usb3@8af8800 {
> +			status = "okay";
> +		};
> +
> +		usb2: usb2@60f8800 {
> +			status = "okay";
> +		};
> +
> +		rng@22000 {
> +			status = "okay";
> +		};
> +
> +		ess-switch@c000000 {
> +			status = "okay";
> +		};
> +
> +		edma@c080000 {
> +			status = "okay";
> +		};
> +
> +		ess-psgmii@98000 {
> +			status = "okay";
> +		};
> +
> +		watchdog@b017000 {
> +			status = "okay";
> +		};
> +	};
> +};
> +
> +&blsp1_i2c3 {
> +	pinctrl-0 = <&i2c_0_pins>;
> +	pinctrl-names = "default";
> +	status = "okay";
> +
> +	trusted-platform-module@20 {
> +		compatible = "infineon,slb9645tt";
> +		reg = <0x20>;
> +		powered-while-suspended;
> +	};
> +};
> +
> +&blsp1_i2c4 {
> +	pinctrl-0 = <&i2c_1_pins>;
> +	pinctrl-names = "default";
> +	status = "okay";
> +
> +	lp55231@32 {
> +		compatible = "national,lp5523";
> +		reg = <0x32>;
> +		clock-mode = [01];
> +
> +		chan0 {
> +			chan-name = "LED0_Red";
> +			led-cur = [64];
> +			max-cur = [78];
> +		};
> +
> +		chan1 {
> +			chan-name = "LED0_Green";
> +			led-cur = [64];
> +			max-cur = [78];
> +		};
> +
> +		chan2 {
> +			chan-name = "LED0_Blue";
> +			led-cur = [64];
> +			max-cur = [78];
> +		};
> +
> +		chan3 {
> +			chan-name = "LED1_Red";
> +			led-cur = [64];
> +			max-cur = [78];
> +		};
> +
> +		chan4 {
> +			chan-name = "LED1_Green";
> +			led-cur = [64];
> +			max-cur = [78];
> +		};
> +
> +		chan5 {
> +			chan-name = "LED1_Blue";
> +			led-cur = [64];
> +			max-cur = [78];
> +		};
> +
> +		chan6 {
> +			chan-name = "LED2_Red";
> +			led-cur = [64];
> +			max-cur = [78];
> +		};
> +
> +		chan7 {
> +			chan-name = "LED2_Green";
> +			led-cur = [64];
> +			max-cur = [78];
> +		};
> +
> +		chan8 {
> +			chan-name = "LED2_Blue";
> +			led-cur = [64];
> +			max-cur = [78];
> +		};
> +	};
> +};
> +
> +&blsp1_spi1 {
> +	pinctrl-0 = <&spi_0_pins>;
> +	pinctrl-names = "default";
> +	status = "okay";
> +	cs-gpios = <&tlmm 12 0>;
> +
> +	spidev@0 {
> +		compatible = "jedec,spi-nor";
> +		reg = <0>;
> +		spi-max-frequency = <24000000>;
> +	};
> +};
> +
> +&blsp1_spi2 {
> +	pinctrl-0 = <&spi_1_pins>;
> +	pinctrl-names = "default";
> +	status = "okay";
> +	cs-gpios = <&tlmm 45 0>;
> +
> +	spidev@0 {
> +		compatible = "spidev";
> +		reg = <0>;
> +		spi-max-frequency = <24000000>;
> +	};
> +};
> +
> +&blsp1_uart1 {
> +	pinctrl-0 = <&serial_0_pins>;
> +	pinctrl-names = "default";
> +	status = "okay";
> +};
> +
> +&blsp1_uart2 {
> +	pinctrl-0 = <&serial_1_pins>;
> +	pinctrl-names = "default";
> +	status = "okay";
> +};
> +
> +&gmac0 {
> +	qcom,phy_mdio_addr = <4>;
> +	qcom,poll_required = <1>;
> +	qcom,forced_speed = <1000>;
> +	qcom,forced_duplex = <1>;
> +	vlan_tag = <2 0x20>;
> +};
> +
> +&gmac1 {
> +	qcom,phy_mdio_addr = <3>;
> +	qcom,forced_duplex = <1>;
> +	vlan_tag = <1 0x10>;
> +};
> +
> +&mdio {
> +	status = "okay";
> +	pinctrl-0 = <&mdio_pins>;
> +	pinctrl-names = "default";
> +};
> +
> +&sdhci {
> +	status = "okay";
> +	pinctrl-0 = <&sd_0_pins>;
> +	pinctrl-names = "default";
> +	clock-frequency = <192000000>;
> +	vqmmc-supply = <&vqmmc>;
> +	non-removable;
> +};
> +
> +&usb2_hs_phy {
> +	status = "okay";
> +};
> +
> +&usb3_ss_phy {
> +	status = "okay";
> +};
> +
> +&usb3_hs_phy {
> +	status = "okay";
> +};
> +
> +&vqmmc {
> +	status = "okay";
> +};
> +
> +&wifi0 {
> +	status = "okay";
> +};
> +
> +&wifi1 {
> +	status = "okay";
> +	pinctrl-0 = <&wifi1_1_pins>;
> +	pinctrl-names = "default";
> +};
> diff --git a/target/linux/ipq40xx/image/Makefile
> b/target/linux/ipq40xx/image/Makefile
> index 51e8bcc7e36d..83d148b90950 100644
> --- a/target/linux/ipq40xx/image/Makefile
> +++ b/target/linux/ipq40xx/image/Makefile
> @@ -218,6 +218,20 @@ define Device/avm_fritzbox-4040  endef
> TARGET_DEVICES += avm_fritzbox-4040
> 
> +define Device/google_gale-v2

Alphabetic sorting.

> +	DEVICE_VENDOR := Google
> +	DEVICE_MODEL := WiFi (Gale)

This uses yet another name compared to device definition/compatible and model in DTS.
Please be more consistent. Despite, if the device node (and thus the image) has a v2 in it, please also add

DEVICE_VARIANT := v2

here.

> +	SOC := qcom-ipq4019
> +	DEVICE_DTS := qcom-ipq4019-gale-v2

This line can be dropped, it will be calculated from SOC and device node name automatically.

Best

Adrian

> +	KERNEL_SUFFIX := -fit-zImage.itb.vboot
> +	KERNEL = kernel-bin | fit none $$(DTS_DIR)/$$(DEVICE_DTS).dtb |
> cros-vboot
> +	KERNEL_NAME := zImage
> +	IMAGES += factory.bin
> +	IMAGE/factory.bin := cros-image
> +	DEVICE_PACKAGES := partx-utils mkf2fs e2fsprogs endef
> TARGET_DEVICES
> ++= google_gale-v2
> +
>  define Device/avm_fritzbox-7530
>  	$(call Device/FitImageLzma)
>  	DEVICE_VENDOR := AVM
> diff --git a/target/linux/ipq40xx/patches-5.4/901-arm-boot-add-dts-
> files.patch b/target/linux/ipq40xx/patches-5.4/901-arm-boot-add-dts-
> files.patch
> index d281bb468daf..04630a85d679 100644
> --- a/target/linux/ipq40xx/patches-5.4/901-arm-boot-add-dts-files.patch
> +++ b/target/linux/ipq40xx/patches-5.4/901-arm-boot-add-dts-files.patch
> @@ -10,7 +10,7 @@ Signed-off-by: John Crispin <john@phrozen.org>
> 
>  --- a/arch/arm/boot/dts/Makefile
>  +++ b/arch/arm/boot/dts/Makefile
> -@@ -837,11 +837,50 @@ dtb-$(CONFIG_ARCH_QCOM) += \
> +@@ -837,11 +837,51 @@ dtb-$(CONFIG_ARCH_QCOM) += \
>   	qcom-apq8074-dragonboard.dtb \
>   	qcom-apq8084-ifc6540.dtb \
>   	qcom-apq8084-mtp.dtb \
> @@ -43,6 +43,7 @@ Signed-off-by: John Crispin <john@phrozen.org>
>  +	qcom-ipq4019-fritzbox-7530.dtb \
>  +	qcom-ipq4019-fritzrepeater-1200.dtb \
>  +	qcom-ipq4019-fritzrepeater-3000.dtb \
> ++	qcom-ipq4019-gale-v2.dtb \
>  +	qcom-ipq4019-map-ac2200.dtb \
>  +	qcom-ipq4019-e2600ac-c1.dtb \
>  +	qcom-ipq4019-e2600ac-c2.dtb \
> --
> 2.27.0
> 
> 
> _______________________________________________
> openwrt-devel mailing list
> openwrt-devel@lists.openwrt.org
> https://lists.openwrt.org/mailman/listinfo/openwrt-devel
Brian Norris July 21, 2020, 8:36 a.m. UTC | #2
Hi Adrian,

On Sat, Jul 18, 2020 at 2:13 PM <mail@adrianschmutzler.de> wrote:
> just some formal stuff below.

Thanks! It's useful, especially where I'm still learning the OpenWRT
Makefile structures.

I'll spin up a new revision sooner or later, but I'm hoping I'll get
some opinion on the RFC portion (cover letter / first ~3 patches)
before doing that.

> > -----Original Message-----
> > From: openwrt-devel [mailto:openwrt-devel-bounces@lists.openwrt.org]
> > On Behalf Of Brian Norris
> > Sent: Samstag, 18. Juli 2020 22:52
> > To: openwrt-devel@lists.openwrt.org
> > Cc: Brian Norris <computersforpeace@gmail.com>
> > Subject: [RFC PATCH 5/5] ipq40xx: add target for Google WiFi (Gale)
...
> > I include "factory.bin" support, where we generate a GPT-based disk image
> > with 2 partitions -- a kernel partition (using the custom "Chrome OS kernel"
> > GUID type) and a root filesystem partition. If the AP is in Developer Mode,
> > the stock bootloader can boot it via a USB disk or (after gaining access via USB
> > boot) flashed to the eMMC.
>
> I'd like a bit more detailed flashing instructions here. What you have right now only works if the reader knows what to do anyway.

Well, it's not exactly trivial, but I guess not that difficult,
relative to the average device OpenWRT supports. As luck would have
it, somebody has already documented it:

https://github.com/marcosscriven/galeforce#how-to-apply-an-image

Would it be best to summarize, link, or both?

> > +++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-gale-v2.
> > +++ dts
> > @@ -0,0 +1,402 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (c) 2016, 2018 The Linux Foundation. All rights reserved.
> > + * Copyright (c) 2016 Google, Inc
> > + */
> > +
> > +#include "qcom-ipq4019.dtsi"
> > +#include <dt-bindings/input/input.h>
> > +#include <dt-bindings/gpio/gpio.h>
> > +
> > +&tlmm {
>
> I'd have expected the root node first.

I've learned muscle memory to put things like pinctrl first, because
they're often referenced by other nodes (possibly including in the
root node) via phandle, and at least in the past, DTC would not
support out-of-order references for phandles.

But that doesn't apply here (no phandles from the root section), so
that doesn't apply. Will change.

> > +/ {
> > +     model = "Google IPQ4019/Gale";
>
> This should be generally consistent with what you choose for DEVICE_MODEL. See my others comments there below.
>
> > +     compatible = "google,gale-v2", "qcom,ipq4019";
...
> > --- a/target/linux/ipq40xx/image/Makefile
> > +++ b/target/linux/ipq40xx/image/Makefile
> > @@ -218,6 +218,20 @@ define Device/avm_fritzbox-4040  endef
> > TARGET_DEVICES += avm_fritzbox-4040
> >
> > +define Device/google_gale-v2
>
> Alphabetic sorting.
>
> > +     DEVICE_VENDOR := Google
> > +     DEVICE_MODEL := WiFi (Gale)
>
> This uses yet another name compared to device definition/compatible and model in DTS.
> Please be more consistent. Despite, if the device node (and thus the image) has a v2 in it, please also add
>
> DEVICE_VARIANT := v2
>
> here.

Thanks for the scrutiny! I do have some questions here: is the
VENDOR/MODEL supposed to match closer to a
marketing-friendly/user-friendly name, or a developer/low-level name?
Or just some balance of both? Because there's several constraints
here:
* The bootloader recognizes compatible="google,gale-v2" -- I don't
believe I can reliably drop the "v2" there, but I suppose that doesn't
require the file names, etc., to include it
* There really is no v1 publicly-available; as noted in the commit
message, I believe that was pre-release hardware, and the revisions
just stuck around through development
* the "v2" here does *not* mean second generation, as in
https://en.wikipedia.org/wiki/Google_Nest_Wifi#Second_generation
* "WiFi" doesn't really make for a good MODEL on its own, although
it's OK when paired with the VENDOR. But I still preferred sticking
the codename (Gale) around, since that's the unambiguous way hackers
can recognize the model.

What do you think? Should I try to keep the keywords "google", "wifi",
and "gale" in all of the config, image, and DTS name? And I'll avoid
the "v2" labeling (and DEVICE_VARIANT) outside of "compatible",
because I think that would be misleading.

Anyway, I'll try to figure out a better balance of the above on the
next version.

Thanks,
Brian

> > +     SOC := qcom-ipq4019
> > +     DEVICE_DTS := qcom-ipq4019-gale-v2
>
> This line can be dropped, it will be calculated from SOC and device node name automatically.
Adrian Schmutzler July 22, 2020, 1:58 p.m. UTC | #3
> I'll spin up a new revision sooner or later, but I'm hoping I'll get some opinion
> on the RFC portion (cover letter / first ~3 patches) before doing that.

Yes, just wait for some comments on the actual content. :-)

> > I'd like a bit more detailed flashing instructions here. What you have right
> now only works if the reader knows what to do anyway.
> 
> Well, it's not exactly trivial, but I guess not that difficult, relative to the
> average device OpenWRT supports. As luck would have it, somebody has
> already documented it:
> 
> https://github.com/marcosscriven/galeforce#how-to-apply-an-image
> 
> Would it be best to summarize, link, or both?

Both. I'm a fan of putting information directly into the commit message, as that is the safest way of preserving it when links change, content changes etc.

The linked resources seem to be too much content for just pasting, though, so a helpful summary seems to be appropriate here.

Despite, also consider adding the full information to our Wiki's device page.

> 
> > > +++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-gale-
> v2.
> > > +++ dts
> > > @@ -0,0 +1,402 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +/*
> > > + * Copyright (c) 2016, 2018 The Linux Foundation. All rights reserved.
> > > + * Copyright (c) 2016 Google, Inc
> > > + */
> > > +
> > > +#include "qcom-ipq4019.dtsi"
> > > +#include <dt-bindings/input/input.h> #include
> > > +<dt-bindings/gpio/gpio.h>
> > > +
> > > +&tlmm {
> >
> > I'd have expected the root node first.
> 
> I've learned muscle memory to put things like pinctrl first, because they're
> often referenced by other nodes (possibly including in the root node) via
> phandle, and at least in the past, DTC would not support out-of-order
> references for phandles.
> 
> But that doesn't apply here (no phandles from the root section), so that
> doesn't apply. Will change.
> 
> > > +/ {
> > > +     model = "Google IPQ4019/Gale";
> >
> > This should be generally consistent with what you choose for
> DEVICE_MODEL. See my others comments there below.
> >
> > > +     compatible = "google,gale-v2", "qcom,ipq4019";
> ...
> > > --- a/target/linux/ipq40xx/image/Makefile
> > > +++ b/target/linux/ipq40xx/image/Makefile
> > > @@ -218,6 +218,20 @@ define Device/avm_fritzbox-4040  endef
> > > TARGET_DEVICES += avm_fritzbox-4040
> > >
> > > +define Device/google_gale-v2
> >
> > Alphabetic sorting.
> >
> > > +     DEVICE_VENDOR := Google
> > > +     DEVICE_MODEL := WiFi (Gale)
> >
> > This uses yet another name compared to device definition/compatible and
> model in DTS.
> > Please be more consistent. Despite, if the device node (and thus the
> > image) has a v2 in it, please also add
> >
> > DEVICE_VARIANT := v2
> >
> > here.
> 
> Thanks for the scrutiny! I do have some questions here: is the
> VENDOR/MODEL supposed to match closer to a marketing-friendly/user-
> friendly name, or a developer/low-level name?

I typically prefer something that the user can read on the device, as everything else will add to the confusion.

> Or just some balance of both? Because there's several constraints
> here:
> * The bootloader recognizes compatible="google,gale-v2" -- I don't believe I
> can reliably drop the "v2" there, but I suppose that doesn't require the file
> names, etc., to include it
> * There really is no v1 publicly-available; as noted in the commit message, I
> believe that was pre-release hardware, and the revisions just stuck around
> through development
> * the "v2" here does *not* mean second generation, as in
> https://en.wikipedia.org/wiki/Google_Nest_Wifi#Second_generation

I don't think we have to care too much about the v1 here; however, if there is a different "second generation" with the same name, then we should include a "1st-gen" in the name somewhere, maybe even instead of the v2 if there is no v3 to be expected for the "1st-gen".

The Wiki article is not entirely precise here, so is the gale-v2 the "first generation" in the nest article or is there actually a 1st and 2nd generation of that Nest devices and gale something even different?

> * "WiFi" doesn't really make for a good MODEL on its own, although it's OK
> when paired with the VENDOR. But I still preferred sticking the codename
> (Gale) around, since that's the unambiguous way hackers can recognize the
> model.
> 
> What do you think? Should I try to keep the keywords "google", "wifi", and
> "gale" in all of the config, image, and DTS name? And I'll avoid the "v2"
> labeling (and DEVICE_VARIANT) outside of "compatible", because I think that
> would be misleading.

If you call this gale, the question is how you proceed with the nest series then. Will you switch to marketing-based "nest" then, or will you use the internal name though the user will read something different on the device?

Unfortunately, this stuff is never easy to decide. Personally, I always lean towards what's printed on the thing.

Best

Adrian

> 
> Anyway, I'll try to figure out a better balance of the above on the next
> version.
> 
> Thanks,
> Brian
> 
> > > +     SOC := qcom-ipq4019
> > > +     DEVICE_DTS := qcom-ipq4019-gale-v2
> >
> > This line can be dropped, it will be calculated from SOC and device node
> name automatically.
> 
> _______________________________________________
> openwrt-devel mailing list
> openwrt-devel@lists.openwrt.org
> https://lists.openwrt.org/mailman/listinfo/openwrt-devel
Brian Norris July 26, 2020, 12:09 a.m. UTC | #4
On Wed, Jul 22, 2020 at 03:58:34PM +0200, mail@adrianschmutzler.de wrote:
> > Thanks for the scrutiny! I do have some questions here: is the
> > VENDOR/MODEL supposed to match closer to a marketing-friendly/user-
> > friendly name, or a developer/low-level name?
> 
> I typically prefer something that the user can read on the device, as everything else will add to the confusion.
> 
> > Or just some balance of both? Because there's several constraints
> > here:
> > * The bootloader recognizes compatible="google,gale-v2" -- I don't believe I
> > can reliably drop the "v2" there, but I suppose that doesn't require the file
> > names, etc., to include it
> > * There really is no v1 publicly-available; as noted in the commit message, I
> > believe that was pre-release hardware, and the revisions just stuck around
> > through development
> > * the "v2" here does *not* mean second generation, as in
> > https://en.wikipedia.org/wiki/Google_Nest_Wifi#Second_generation
> 
> I don't think we have to care too much about the v1 here; however, if
> there is a different "second generation" with the same name, then we
> should include a "1st-gen" in the name somewhere, maybe even instead
> of the v2 if there is no v3 to be expected for the "1st-gen".

The "second generation" is labeled as "Nest WiFi" or "Google Nest WiFi".
I don't know if that's considered the "same" name by the layperson. I
could toss in a "1st-gen", if that helps.

I doubt there's a "v3" to be expected for 1st-gen. I'll drop the "v2"
everywhere but the 'compatible' property.

> The Wiki article is not entirely precise here, so is the gale-v2 the
> "first generation" in the nest article

Yes.

> or is there actually a 1st and
> 2nd generation of that Nest devices and gale something even different?

No, Gale is the thing called "first generation" there.

Google is excellent at naming things :D

I believe the 2 products here are named "Google WiFi" and "Nest WiFi"
(where Nest is part of Google...) -- there's some shift to using the
"Nest" brand for this type of hardware, I guess. I presume the Wikipedia
authors have retroactivey renamed the page to "Google Nest WiFi" to
follow the latest branding, even if the first generation had no such
"Nest" marketing.

  1st generation = Gale = Google WiFi
  2nd generation = Nest WiFi (by Google!)

> > * "WiFi" doesn't really make for a good MODEL on its own, although it's OK
> > when paired with the VENDOR. But I still preferred sticking the codename
> > (Gale) around, since that's the unambiguous way hackers can recognize the
> > model.
> > 
> > What do you think? Should I try to keep the keywords "google", "wifi", and
> > "gale" in all of the config, image, and DTS name? And I'll avoid the "v2"
> > labeling (and DEVICE_VARIANT) outside of "compatible", because I think that
> > would be misleading.
> 
> If you call this gale, the question is how you proceed with the nest
> series then. Will you switch to marketing-based "nest" then, or will
> you use the internal name though the user will read something
> different on the device?

(I have no plans for Nest WiFi support, FWIW.)

I could see it going either way.

I guess one thing that trips me up: suppose I call this
"Device/google_wifi" (and Nest WiFi -> "Device/nest_wifi"), then the DTS
file comes out as
 Google WiFi -> qcom-ipq4019-wifi.dts
 Nest WiFi -> qcom-ipqXXXX-wifi.dts

That seems...pretty obtuse to me. Is that a case where I override the
auto-naming for the DTS, and call them "qcom-ipq4019-google-wifi.dts"
and "qcom-ipqXXXX-nest-wifi.dts"?

Or I could use hyphens, so the DTS derivation is nicer
(Device/google-wifi, or even Device/google_google-wifi -- either of
those should produce ...-google-wifi.dts)?

> Unfortunately, this stuff is never easy to decide. Personally, I
> always lean towards what's printed on the thing.

Brian
diff mbox series

Patch

diff --git a/target/linux/ipq40xx/Makefile b/target/linux/ipq40xx/Makefile
index 94b47c4c96de..c114df620d5c 100644
--- a/target/linux/ipq40xx/Makefile
+++ b/target/linux/ipq40xx/Makefile
@@ -3,7 +3,7 @@  include $(TOPDIR)/rules.mk
 ARCH:=arm
 BOARD:=ipq40xx
 BOARDNAME:=Qualcomm Atheros IPQ40XX
-FEATURES:=squashfs fpu ramdisk nand
+FEATURES:=squashfs fpu ramdisk nand boot-part rootfs-part
 CPU_TYPE:=cortex-a7
 CPU_SUBTYPE:=neon-vfpv4
 SUBTARGETS:=generic
diff --git a/target/linux/ipq40xx/base-files/etc/board.d/02_network b/target/linux/ipq40xx/base-files/etc/board.d/02_network
index 61d02a17bcc9..f6b2f47e6ce6 100755
--- a/target/linux/ipq40xx/base-files/etc/board.d/02_network
+++ b/target/linux/ipq40xx/base-files/etc/board.d/02_network
@@ -38,6 +38,7 @@  ipq40xx_setup_interfaces()
 		;;
 	asus,map-ac2200|\
 	cilab,meshpoint-one|\
+	google,gale-v2|\
 	openmesh,a42|\
 	openmesh,a62)
 		ucidef_set_interfaces_lan_wan "eth1" "eth0"
diff --git a/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh b/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh
index 5b89710a2255..9cc77e8cb4d0 100644
--- a/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh
+++ b/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh
@@ -40,6 +40,16 @@  askey_do_upgrade() {
 	nand_do_upgrade "$1"
 }
 
+vboot_do_upgrade() {
+	local tar_file="$1"
+
+	echo "Preparing to flash to /dev/mmcblk0p{1,2}"
+	ask_bool 0 "Abort" && exit 1
+
+	tar Oxf "${tar_file}" '*/kernel' | dd of=/dev/mmcblk0p1 bs=1M
+	tar Oxf "${tar_file}" '*/root' | dd of=/dev/mmcblk0p2 bs=1M
+}
+
 zyxel_do_upgrade() {
 	local tar_file="$1"
 
@@ -98,6 +108,9 @@  platform_do_upgrade() {
 	compex,wpj419)
 		nand_do_upgrade "$1"
 		;;
+	google,gale-v2)
+		vboot_do_upgrade "$1"
+		;;
 	linksys,ea6350v3 |\
 	linksys,ea8300)
 		platform_do_upgrade_linksys "$1"
diff --git a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-gale-v2.dts b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-gale-v2.dts
new file mode 100644
index 000000000000..ce0d2b91d05a
--- /dev/null
+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-gale-v2.dts
@@ -0,0 +1,402 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016, 2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016 Google, Inc
+ */
+
+#include "qcom-ipq4019.dtsi"
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/gpio/gpio.h>
+
+&tlmm {
+	fw_pinmux {
+		wp {
+			pins = "gpio53";
+			output-low;
+		};
+		recovery {
+			pins = "gpio57";
+			bias-none;
+		};
+		developer {
+			pins = "gpio41";
+			bias-none;
+		};
+	};
+
+	reset802_15_4 {
+		pins = "gpio60";
+	};
+
+	led_reset {
+		pins = "gpio22";
+		output-high;
+	};
+
+	sys_reset {
+		pins = "gpio19";
+		output-high;
+	};
+
+	rx_active {
+		pins = "gpio43";
+		bias-pull,down;
+	};
+
+	spi_0_pins: spi_0_pinmux {
+		pinmux {
+			function = "blsp_spi0";
+			pins = "gpio13", "gpio14","gpio15";
+		};
+		pinmux_cs {
+			function = "gpio";
+			pins = "gpio12";
+		};
+		pinconf {
+			pins = "gpio13", "gpio14","gpio15";
+			drive-strength = <12>;
+			bias-disable;
+		};
+		pinconf_cs {
+			pins = "gpio12";
+			drive-strength = <2>;
+			bias-disable;
+			output-high;
+		};
+	};
+
+	spi_1_pins: spi_1_pinmux {
+		pinmux {
+			function = "blsp_spi1";
+			pins = "gpio44", "gpio46","gpio47";
+		};
+		pinmux_cs {
+			function = "gpio";
+			pins = "gpio45";
+		};
+		pinconf {
+			pins = "gpio44", "gpio46","gpio47";
+			drive-strength = <12>;
+			bias-disable;
+		};
+		pinconf_cs {
+			pins = "gpio45";
+			drive-strength = <2>;
+			bias-disable;
+			output-high;
+		};
+	};
+
+	serial_0_pins: serial0_pinmux {
+		mux {
+			pins = "gpio16", "gpio17";
+			function = "blsp_uart0";
+			bias-disable;
+		};
+	};
+
+	serial_1_pins: serial1_pinmux {
+		mux {
+			pins = "gpio8", "gpio9", "gpio10", "gpio11";
+			function = "blsp_uart1";
+			bias-disable;
+		};
+	};
+
+	i2c_0_pins: i2c_0_pinmux {
+		mux {
+			pins = "gpio20", "gpio21";
+			function = "blsp_i2c0";
+			drive-open-drain;
+		};
+	};
+
+	i2c_1_pins: i2c_1_pinmux {
+		mux {
+			pins = "gpio34", "gpio35";
+			function = "blsp_i2c1";
+			drive-open-drain;
+		};
+	};
+
+	sd_0_pins: sd_0_pinmux {
+		sd0 {
+			pins = "gpio23", "gpio24", "gpio25", "gpio26", "gpio29", "gpio30", "gpio31", "gpio32";
+			function = "sdio";
+			drive-strength = <10>;
+			bias-pull-up;
+			pull-up-res = <0>;
+		};
+		sdclk {
+			pins = "gpio27";
+			function = "sdio";
+			drive-strength = <2>;
+			bias-pull-up;
+			pull-up-res = <0>;
+		};
+		sdcmd {
+			pins = "gpio28";
+			function = "sdio";
+			drive-strength = <10>;
+			bias-pull-up;
+			pull-up-res = <0>;
+		};
+	};
+
+	mdio_pins: mdio_pinmux {
+		mux_1 {
+			pins = "gpio6";
+			function = "mdio";
+			bias-disable;
+		};
+		mux_2 {
+			pins = "gpio7";
+			function = "mdc";
+			bias-disable;
+		};
+		mux_3 {
+			pins = "gpio40";
+			function = "gpio";
+			bias-disable;
+			output-high;
+		};
+	};
+
+	wifi1_1_pins: wifi2_pinmux {
+		mux {
+			pins = "gpio58";
+			output-low;
+		};
+	};
+};
+
+/ {
+	model = "Google IPQ4019/Gale";
+	compatible = "google,gale-v2", "qcom,ipq4019";
+
+	chosen {
+		stdout-path = &blsp1_uart1;
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0x80000000 0x20000000>; /* 512MB */
+	};
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		rsvd@87000000 {
+			/* Reserved for other subsystem */
+			reg = <0x87000000 0x01000000>;
+			no-map;
+		};
+	};
+
+	soc {
+		blsp_dma: dma@7884000 {
+			status = "okay";
+		};
+
+		usb3: usb3@8af8800 {
+			status = "okay";
+		};
+
+		usb2: usb2@60f8800 {
+			status = "okay";
+		};
+
+		rng@22000 {
+			status = "okay";
+		};
+
+		ess-switch@c000000 {
+			status = "okay";
+		};
+
+		edma@c080000 {
+			status = "okay";
+		};
+
+		ess-psgmii@98000 {
+			status = "okay";
+		};
+
+		watchdog@b017000 {
+			status = "okay";
+		};
+	};
+};
+
+&blsp1_i2c3 {
+	pinctrl-0 = <&i2c_0_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	trusted-platform-module@20 {
+		compatible = "infineon,slb9645tt";
+		reg = <0x20>;
+		powered-while-suspended;
+	};
+};
+
+&blsp1_i2c4 {
+	pinctrl-0 = <&i2c_1_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	lp55231@32 {
+		compatible = "national,lp5523";
+		reg = <0x32>;
+		clock-mode = [01];
+
+		chan0 {
+			chan-name = "LED0_Red";
+			led-cur = [64];
+			max-cur = [78];
+		};
+
+		chan1 {
+			chan-name = "LED0_Green";
+			led-cur = [64];
+			max-cur = [78];
+		};
+
+		chan2 {
+			chan-name = "LED0_Blue";
+			led-cur = [64];
+			max-cur = [78];
+		};
+
+		chan3 {
+			chan-name = "LED1_Red";
+			led-cur = [64];
+			max-cur = [78];
+		};
+
+		chan4 {
+			chan-name = "LED1_Green";
+			led-cur = [64];
+			max-cur = [78];
+		};
+
+		chan5 {
+			chan-name = "LED1_Blue";
+			led-cur = [64];
+			max-cur = [78];
+		};
+
+		chan6 {
+			chan-name = "LED2_Red";
+			led-cur = [64];
+			max-cur = [78];
+		};
+
+		chan7 {
+			chan-name = "LED2_Green";
+			led-cur = [64];
+			max-cur = [78];
+		};
+
+		chan8 {
+			chan-name = "LED2_Blue";
+			led-cur = [64];
+			max-cur = [78];
+		};
+	};
+};
+
+&blsp1_spi1 {
+	pinctrl-0 = <&spi_0_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+	cs-gpios = <&tlmm 12 0>;
+
+	spidev@0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <24000000>;
+	};
+};
+
+&blsp1_spi2 {
+	pinctrl-0 = <&spi_1_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+	cs-gpios = <&tlmm 45 0>;
+
+	spidev@0 {
+		compatible = "spidev";
+		reg = <0>;
+		spi-max-frequency = <24000000>;
+	};
+};
+
+&blsp1_uart1 {
+	pinctrl-0 = <&serial_0_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&blsp1_uart2 {
+	pinctrl-0 = <&serial_1_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&gmac0 {
+	qcom,phy_mdio_addr = <4>;
+	qcom,poll_required = <1>;
+	qcom,forced_speed = <1000>;
+	qcom,forced_duplex = <1>;
+	vlan_tag = <2 0x20>;
+};
+
+&gmac1 {
+	qcom,phy_mdio_addr = <3>;
+	qcom,forced_duplex = <1>;
+	vlan_tag = <1 0x10>;
+};
+
+&mdio {
+	status = "okay";
+	pinctrl-0 = <&mdio_pins>;
+	pinctrl-names = "default";
+};
+
+&sdhci {
+	status = "okay";
+	pinctrl-0 = <&sd_0_pins>;
+	pinctrl-names = "default";
+	clock-frequency = <192000000>;
+	vqmmc-supply = <&vqmmc>;
+	non-removable;
+};
+
+&usb2_hs_phy {
+	status = "okay";
+};
+
+&usb3_ss_phy {
+	status = "okay";
+};
+
+&usb3_hs_phy {
+	status = "okay";
+};
+
+&vqmmc {
+	status = "okay";
+};
+
+&wifi0 {
+	status = "okay";
+};
+
+&wifi1 {
+	status = "okay";
+	pinctrl-0 = <&wifi1_1_pins>;
+	pinctrl-names = "default";
+};
diff --git a/target/linux/ipq40xx/image/Makefile b/target/linux/ipq40xx/image/Makefile
index 51e8bcc7e36d..83d148b90950 100644
--- a/target/linux/ipq40xx/image/Makefile
+++ b/target/linux/ipq40xx/image/Makefile
@@ -218,6 +218,20 @@  define Device/avm_fritzbox-4040
 endef
 TARGET_DEVICES += avm_fritzbox-4040
 
+define Device/google_gale-v2
+	DEVICE_VENDOR := Google
+	DEVICE_MODEL := WiFi (Gale)
+	SOC := qcom-ipq4019
+	DEVICE_DTS := qcom-ipq4019-gale-v2
+	KERNEL_SUFFIX := -fit-zImage.itb.vboot
+	KERNEL = kernel-bin | fit none $$(DTS_DIR)/$$(DEVICE_DTS).dtb | cros-vboot
+	KERNEL_NAME := zImage
+	IMAGES += factory.bin
+	IMAGE/factory.bin := cros-image
+	DEVICE_PACKAGES := partx-utils mkf2fs e2fsprogs
+endef
+TARGET_DEVICES += google_gale-v2
+
 define Device/avm_fritzbox-7530
 	$(call Device/FitImageLzma)
 	DEVICE_VENDOR := AVM
diff --git a/target/linux/ipq40xx/patches-5.4/901-arm-boot-add-dts-files.patch b/target/linux/ipq40xx/patches-5.4/901-arm-boot-add-dts-files.patch
index d281bb468daf..04630a85d679 100644
--- a/target/linux/ipq40xx/patches-5.4/901-arm-boot-add-dts-files.patch
+++ b/target/linux/ipq40xx/patches-5.4/901-arm-boot-add-dts-files.patch
@@ -10,7 +10,7 @@  Signed-off-by: John Crispin <john@phrozen.org>
 
 --- a/arch/arm/boot/dts/Makefile
 +++ b/arch/arm/boot/dts/Makefile
-@@ -837,11 +837,50 @@ dtb-$(CONFIG_ARCH_QCOM) += \
+@@ -837,11 +837,51 @@ dtb-$(CONFIG_ARCH_QCOM) += \
  	qcom-apq8074-dragonboard.dtb \
  	qcom-apq8084-ifc6540.dtb \
  	qcom-apq8084-mtp.dtb \
@@ -43,6 +43,7 @@  Signed-off-by: John Crispin <john@phrozen.org>
 +	qcom-ipq4019-fritzbox-7530.dtb \
 +	qcom-ipq4019-fritzrepeater-1200.dtb \
 +	qcom-ipq4019-fritzrepeater-3000.dtb \
++	qcom-ipq4019-gale-v2.dtb \
 +	qcom-ipq4019-map-ac2200.dtb \
 +	qcom-ipq4019-e2600ac-c1.dtb \
 +	qcom-ipq4019-e2600ac-c2.dtb \