diff mbox series

[v2,4/4] ipq40xx: add target for Google WiFi (Gale)

Message ID 20210117030707.1251501-5-computersforpeace@gmail.com
State Superseded, archived
Delegated to: Paul Spooren
Headers show
Series Add support for Chromium OS and Google WiFi | expand

Commit Message

Brian Norris Jan. 17, 2021, 3:07 a.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 3 partitions -- a spare FAT partition, a kernel partition
(using the custom "Chrome OS kernel" GUID type) and a root filesystem
partition. See below for flashing instructions.

Sysupgrade is only partially working.

"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.

Flashing instructions
=====================

[ NB: you may still need to tweak which drivers are built-in, if you
want to boot from a USB disk. ]

Chrome OS systems allow booting custom images only when transitioned
into Developer Mode. Existing sources document how to enter Developer
Mode on a Google WiFi system:

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

The OpenWRT-relevant summary:

1. Flash factory.bin to a USB storage device (e.g., with 'dd')
2. Pop off the case
3. Attach a USB-C hub with power delivery
4. Press the reset button on the back until light blinks orange (>16
   seconds)
5. Once blinking orange, hit the tiny bubble switch (SW7) found on the
   board
6. Device will start blinking purple and restart
7. Wait until device restarts and starts blinking purple again
7. Plug in USB stick
8. Hit bubble switch again

The device should boot to OpenWRT.

If you want to persist to the eMMC, flash factory.bin to /dev/mmcblk0.

Features
========

I've 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 requires some additional TrustZone / SCM
   configuration to disable Qualcomm's SDI. I have a proposal upstream,
   and based on IRC chats, this might be acceptable with additional DT
   logic:
     [RFC PATCH] firmware: qcom_scm: disable SDI at boot
     https://lore.kernel.org/linux-arm-msm/20200721080054.2803881-1-computersforpeace@gmail.com/
 * SMP: enabling secondary CPUs doesn't currently work using the stock
   bootloader, as the qcom_scm driver assumes newer features than this
   TrustZone firmware has. I posted notes here:
     [RFC] qcom_scm: IPQ4019 firmware does not support atomic API?
     https://lore.kernel.org/linux-arm-msm/20200913201608.GA3162100@bDebian/
 * There's a single external button, and a few useful internal GPIO
   switches. I haven't hooked them up.

Additional notes
================

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>
---
v2:
 * include more verbose flashing instructions
 * rename to "google_wifi" in most contexts, with "gale" only used as a
   secondary name, so the bootloader can find the DTB
 * other formalities (alphabetization, etc.)
---
 target/linux/ipq40xx/Makefile                 |   2 +-
 .../ipq40xx/base-files/etc/board.d/02_network |   1 +
 .../base-files/lib/upgrade/platform.sh        |  16 +
 .../arch/arm/boot/dts/qcom-ipq4019-wifi.dts   | 402 ++++++++++++++++++
 target/linux/ipq40xx/image/Makefile           |  13 +
 .../901-arm-boot-add-dts-files.patch          |   3 +-
 6 files changed, 435 insertions(+), 2 deletions(-)
 create mode 100644 target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-wifi.dts
diff mbox series

Patch

diff --git a/target/linux/ipq40xx/Makefile b/target/linux/ipq40xx/Makefile
index 4d9b2debcaed..7f4c084da6b4 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 fe21dc80352e..59f849092841 100755
--- a/target/linux/ipq40xx/base-files/etc/board.d/02_network
+++ b/target/linux/ipq40xx/base-files/etc/board.d/02_network
@@ -43,6 +43,7 @@  ipq40xx_setup_interfaces()
 	cilab,meshpoint-one|\
 	edgecore,ecw5211|\
 	edgecore,oap100|\
+	google,wifi|\
 	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 558269675935..5142907f7baa 100644
--- a/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh
+++ b/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh
@@ -40,6 +40,19 @@  askey_do_upgrade() {
 	nand_do_upgrade "$1"
 }
 
+vboot_do_upgrade() {
+	local tar_file="$1"
+
+	local board_dir=$(tar tf $tar_file | grep -m 1 '^sysupgrade-.*/$')
+	board_dir=${board_dir%/}
+
+	echo "Preparing to flash \"${board_dir}\" to /dev/mmcblk0p{1,2}"
+	ask_bool 0 "Abort" && exit 1
+
+	tar Oxf "${tar_file}" "${board_dir}/kernel" | dd of=/dev/mmcblk0p2 bs=1M
+	tar Oxf "${tar_file}" "${board_dir}/root" | dd of=/dev/mmcblk0p3 bs=1M
+}
+
 zyxel_do_upgrade() {
 	local tar_file="$1"
 
@@ -102,6 +115,9 @@  platform_do_upgrade() {
 	compex,wpj419)
 		nand_do_upgrade "$1"
 		;;
+	google,wifi)
+		vboot_do_upgrade "$1"
+		;;
 	linksys,ea6350v3 |\
 	linksys,ea8300 |\
 	linksys,mr8300)
diff --git a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-wifi.dts b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-wifi.dts
new file mode 100644
index 000000000000..732b10886c64
--- /dev/null
+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-wifi.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>
+
+/ {
+	model = "Google WiFi (Gale)";
+	compatible = "google,wifi", "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";
+		};
+	};
+};
+
+&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;
+		};
+	};
+};
+
+&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>;
+
+	flash@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 c19dcb40397d..81f2df61f8b4 100644
--- a/target/linux/ipq40xx/image/Makefile
+++ b/target/linux/ipq40xx/image/Makefile
@@ -522,6 +522,19 @@  define Device/glinet_gl-s1300
 endef
 TARGET_DEVICES += glinet_gl-s1300
 
+define Device/google_wifi
+	DEVICE_VENDOR := Google
+	DEVICE_MODEL := WiFi (Gale)
+	SOC := qcom-ipq4019
+	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_wifi
+
 define Device/linksys_ea6350v3
 	# The Linksys EA6350v3 has a uboot bootloader that does not
 	# support either booting lzma kernel images nor booting UBI
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 a3d3341587d8..9a138c6ed720 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,58 @@ dtb-$(CONFIG_ARCH_QCOM) += \
+@@ -837,11 +837,59 @@ dtb-$(CONFIG_ARCH_QCOM) += \
  	qcom-apq8074-dragonboard.dtb \
  	qcom-apq8084-ifc6540.dtb \
  	qcom-apq8084-mtp.dtb \
@@ -57,6 +57,7 @@  Signed-off-by: John Crispin <john@phrozen.org>
 +	qcom-ipq4019-pa2200.dtb \
 +	qcom-ipq4019-rtl30vw.dtb \
 +	qcom-ipq4019-u4019-32m.dtb \
++	qcom-ipq4019-wifi.dtb \
 +	qcom-ipq4019-wpj419.dtb \
 +	qcom-ipq4019-wtr-m2133hp.dtb \
 +	qcom-ipq4028-wpj428.dtb \