UART3 Bluetooth in UniFi 6 Lite

Knowledgeable ones,

I have 4 UniFi 6 Lite APs around my house with OpenWRT. I also have a few Bluetooth BLE sensor beacons around the house advertising humidity, temperature etc.

After some investigation I was surprised to discover that UniFi 6 Lite actually has Bluetooth. They are originally used for registering the device with UniFi cloud solution.

I am very committed to have these UniFi 6 Lite APs collect the sensor data via the built in Bluetooth and store it in a Prometheus DB somewhere else. However my coding expertise ends where the device driver starts, so I am a bit raw on Bluetooth interfaces using UART. Would somebody point me to the right direction? I have a few questions:

In the OpenWRT support commit I see a message:

Not Working
 - Bluetooth (connected to UART3)

https://git.openwrt.org/?p=openwrt/openwrt.git;a=commitdiff;h=fb4d7a9680117a00721936c98ce4

  1. Why would it not be working?
  2. To what Serial interface does UART3 map to in OpenWRT?
  3. How would you recommend I find out what Bluetooth chip this is?
  4. What driver would enable Bluetooth to work?
  5. Does this require OpenWRT to be compiled with additional drivers?

Thank you for your time!

1 Like
  1. Missing open source driver for the BT at the time when device got supported in OpenWrt?
  2. Probably that UART wasn't exposed in DTS.
  3. Based on the FCCID pictures (https://fccid.io/SWX-U6LITE/Internal-Photos/Internal-Photos-4831011) I would say that the MT7915 built-in Bluetooth is used in this device.
  4. I don't think it's supported but I would look at the btmtkuart and btmtk Linux drivers.
  5. You might need way more than that.

FWIW, I just tried that for fun. Enabled &uartlite3 and simply made a copy of the btmtkuart definition in target/linux/mediatek/modules.mk (modifying the TARGET dependency of course). But looking at the driver it seems to require at lot more both in DTS config and firmware. I did a half-assed attempt on simply using the mt7622 firmware and compatible:

&uartlite3 {
       status = "okay";
       bluetooth {
                compatible = "mediatek,mt7622-bluetooth";
      };
};

I believe that failed in the missing "ref" clock. Probe returned ENOENT. Didn't go further. Can't just stumble around blind like that, and don't have enough interest to actually start digging.

Tried hciattach ttyS1 any as well, but that juts results in HCI commands timing out. Pretty much as expected.

So "someone" has to do the real work digging out whatever is actually needed.

Of anyone is interested then there are some OEM DTS snippets in this discussion:
https://community.ui.com/questions/UniFi-U6-Lite-Bluetooth-Based-U-Boot-Implant/4892dd1d-9633-42c1-966f-dcdac90ef714
and more important, a link to a partial OEM bootlog:

Interesting to see that they actually enable BLE in U-Boot, and it pretty much confirms the theory that this is MT7915 bluetooth:

~~~ p_device_model:U6-LITE
~~~ is_default:1 ~~~
~~~ p_macaddr:78:45:58:46:fe:64 ~~~
~~~ is_ble_stp:1 ~~~
=========================GPIO INIT=====================
GPIO_16, action is output low
GPIO_16, action is output high
GPIO_19, action is output low
GPIO_19, action is output high
=========================UART_3 INIT=====================
uartlite0@1e000c00, 1e000c00
uartlite0@1e000e00 bring up, 1e000e00
=========================FLOW 1=====================
[BT Power On Result] Success

=========================FLOW 2=====================
[HCI RESET Result] Success

=========================Extend FLOW=====================
[HCI LE BT MAC ADDR Result] Success

=========================FLOW 3=====================
[HCI LE SET ADVERTISING PARAMETER Result] Success

=========================FLOW 4=====================
[HCI LE  SET ADVERTISING DATA Result] Success

=========================FLOW 5=====================
[HCI LE  SET SCAN RESPONSE Result] Success

=========================FLOW 6=====================
[HIC LE  SET ADVERISTING ENABLE Result] Success
MT7915 BLE broadcasting successfully

(on an unrelated note, I see that the Unifi 6 Lite seems to have the same TFTP recovery bug as the Unifi 6 LR - listening on some arbitrary 192.168.1.x address instead of the documented 192.168.1.20)

The OEM boot log confirms that the btmtkuart driver is correct:

[   13.368940] [btmtk_info] main_driver_init, BTMTK uart version: 7.0.20120401
[   13.376000] [btmtk_info] btmtk_cif_register
[   13.380201] [btmtk_info] uart_register
[   13.383949] [btmtk_info] uart_register done
[   13.388126] [btmtk_info] btmtk_cif_register: Done
[   13.392837] [btmtk_info] btmtk_fops_init: Start
[   13.397365] [btmtk_info] btmtk_fops_init: g_fwlog init
[   13.402799] Bluetooth: btmtk_fops_init: BT_majorfwlog 250, devIDfwlog 262144000
[   13.410128] [btmtk_info] main_driver_init: Done

But I guess it lost this part while being upstreamed. Or maybe it wasn't yet there? The original submission had a lot of bloat^Wcode: https://patchwork.kernel.org/project/linux-mediatek/patch/20201130071655.31515-1-peter.tsao@mediatek.com/#23805281

It looks like a straght dump from the SDK.... And you'll find those keywords for the OEM driver bootlog in there.

Something to work on? Looking forward to the result :slight_smile:

1 Like

Wow, only one day and all this already! Thank you!
This reads like above my current capabilities, seems I need to study more.

Anyways, in the meantime I managed to hack-dump the DTS from the original UnifiOS. I am not entirely sure how useful this actually is, but here it is:

/dts-v1/;

/ {
	#address-cells = < 0x01 >;
	#size-cells = < 0x01 >;
	compatible = "mediatek,mt7621-soc";
	model = "Ubiquiti Networks, Inc. U6-Lite";

	hnat@1e100000 {
		reset-names = "mtketh";
		resets = < 0x0c 0x00 >;
		compatible = "mediatek,mtk-hnat_v1";
		mtketh-ppd = "eth0";
		ext-devices = "rax0\0ra0\0rax1\0ra1\0rax2\0ra2\0rax3\0ra3\0apclix0\0apcli0";
		mtketh-max-gmac = < 0x02 >;
		status = "okay";
		mtketh-wan = "eth1";
		reg = < 0x1e100000 0x3000 >;
	};

	apll {
		#clock-cells = < 0x00 >;
		linux,phandle = < 0x03 >;
		compatible = "fixed-clock";
		phandle = < 0x03 >;
		clock-frequency = < 0x1017df80 >;
	};

	rstctrl {
		linux,phandle = < 0x04 >;
		compatible = "ralink,rt2880-reset";
		phandle = < 0x04 >;
		#reset-cells = < 0x01 >;
	};

	cpus {
		#address-cells = < 0x01 >;
		#size-cells = < 0x00 >;

		cpu@1 {
			compatible = "mips,mips1004Kc";
			device_type = "cpu";
			reg = < 0x01 >;
		};

		cpu@0 {
			compatible = "mips,mips1004Kc";
			device_type = "cpu";
			reg = < 0x00 >;
		};
	};

	cpuclock {
		#clock-cells = < 0x00 >;
		linux,phandle = < 0x15 >;
		compatible = "mtk,mt7621-cpu-clock";
		phandle = < 0x15 >;
	};

	ethernet@1e100000 {
		mediatek,ethsys = < 0x0c >;
		#address-cells = < 0x01 >;
		interrupt-parent = < 0x05 >;
		mtd-mac-address = < 0x0d 0x00 >;
		#size-cells = < 0x00 >;
		mac-address = [ d0 21 f9 b3 53 b0 ];
		compatible = "mediatek,mt7621-eth\0syscon";
		status = "okay";
		interrupts = < 0x00 0x03 0x04 >;
		reg = < 0x1e100000 0xe000 >;

		mac@1 {
			phy-mode = "rgmii";
			compatible = "mediatek,eth-mac";
			reg = < 0x01 >;

			fixed-link {
				pause;
				full-duplex;
				speed = < 0x3e8 >;
			};
		};

		mdio-bus {
			#address-cells = < 0x01 >;
			linux,phandle = < 0x0e >;
			#size-cells = < 0x00 >;
			phandle = < 0x0e >;

			ethernet-phy@1f {
				phy-mode = "rgmii";
				reg = < 0x1f >;
			};
		};

		mac@0 {
			phy-mode = "trgmii";
			compatible = "mediatek,eth-mac";
			reg = < 0x00 >;

			fixed-link {
				pause;
				full-duplex;
				speed = < 0x3e8 >;
			};
		};
	};

	gpio-leds {
		compatible = "gpio-leds";

		wifi {
			gpios = < 0x01 0x03 0x00 >;
			label = "ubnt:blue:personality";
			linux,default-trigger = "external1";
		};

		power {
			gpios = < 0x01 0x04 0x00 >;
			label = "ubnt:white:personality";
			linux,default-trigger = "external0";
		};
	};

	sysbusclock {
		#clock-cells = < 0x00 >;
		linux,phandle = < 0x07 >;
		compatible = "mtk,mt7621-sys-bus-clock";
		phandle = < 0x07 >;
	};

	ethsys@1e000000 {
		linux,phandle = < 0x0c >;
		compatible = "mediatek,mt7621-ethsys\0syscon";
		phandle = < 0x0c >;
		reg = < 0x1e000000 0x8000 >;
	};

	raeth@1e100000 {
		mediatek,ethsys = < 0x0c >;
		interrupt-parent = < 0x05 >;
		compatible = "mediatek,mt7621-eth";
		status = "disabled";
		interrupts = < 0x00 0x03 0x04 >;
		reg = < 0x1e100000 0xe000 >;
	};

	pinctrl {
		pinctrl-0 = < 0x16 >;
		compatible = "mtk,mtkmips-pinmux";
		pinctrl-names = "default";

		pinctrl0 {
			linux,phandle = < 0x16 >;
			phandle = < 0x16 >;

			gpio {
				mtk,group = "i2c\0uart2\0rgmii2\0jtag";
				mtk,function = "gpio";
			};

			uart3 {
				mtk,group = "uart3";
				mtk,function = "uart3";
			};
		};

		rgmii1 {

			rgmii1 {
				mtk,group = "rgmii1";
				mtk,function = "rgmii1";
			};
		};

		mdio {

			mdio {
				mtk,group = "mdio";
				mtk,function = "mdio";
			};
		};

		uart3 {

			uart3 {
				mtk,group = "uart3";
				mtk,function = "uart3";
			};
		};

		nand {
			linux,phandle = < 0x0b >;
			phandle = < 0x0b >;

			sdhci-nand {
				mtk,group = "sdhci";
				mtk,function = "nand2";
			};

			spi-nand {
				mtk,group = "spi";
				mtk,function = "nand1";
			};
		};

		spi {
			linux,phandle = < 0x08 >;
			phandle = < 0x08 >;

			spi {
				mtk,group = "spi";
				mtk,function = "spi";
			};
		};

		i2c {
			linux,phandle = < 0x02 >;
			phandle = < 0x02 >;

			i2c {
				mtk,group = "i2c";
				mtk,function = "gpio";
			};
		};

		sdhci {

			sdhci {
				mtk,group = "sdhci";
				mtk,function = "sdhci";
			};
		};

		uart2 {

			uart2 {
				mtk,group = "uart2";
				mtk,function = "uart2";
			};
		};

		pcie {
			linux,phandle = < 0x0f >;
			phandle = < 0x0f >;

			pcie {
				mtk,group = "pcie";
				mtk,function = "gpio";
			};
		};

		rgmii2 {

			rgmii2 {
				mtk,group = "rgmii2";
				mtk,function = "rgmii2";
			};
		};

		uart1 {

			uart1 {
				mtk,group = "uart1";
				mtk,function = "uart1";
			};
		};
	};

	gpio-keys-polled {
		#address-cells = < 0x01 >;
		#size-cells = < 0x00 >;
		compatible = "gpio-keys-polled";
		poll-interval = < 0x14 >;

		reset {
			gpios = < 0x01 0x0c 0x01 >;
			linux,code = < 0x198 >;
			label = "reset";
		};
	};

	sdhci@1e130000 {
		interrupt-parent = < 0x05 >;
		compatible = "mediatek,mt7621-sdhci";
		status = "disabled";
		interrupts = < 0x00 0x14 0x04 >;
		reg = < 0x1e130000 0x4000 >;
	};

	interrupt-controller@1fbc0000 {
		interrupt-controller;
		linux,phandle = < 0x05 >;
		compatible = "mti,gic";
		#interrupt-cells = < 0x03 >;
		phandle = < 0x05 >;
		mti,reserved-cpu-vectors = < 0x07 >;
		reg = < 0x1fbc0000 0x2000 >;

		timer {
			compatible = "mti,gic-timer";
			interrupts = < 0x01 0x01 0x00 >;
			clocks = < 0x15 >;
		};
	};

	cpuintc {
		interrupt-controller;
		#address-cells = < 0x00 >;
		compatible = "mti,cpu-interrupt-controller";
		#interrupt-cells = < 0x01 >;
	};

	clkctrl {
		#clock-cells = < 0x01 >;
		linux,phandle = < 0x10 >;
		compatible = "ralink,rt2880-clock";
		phandle = < 0x10 >;
	};

	sysclock125M {
		#clock-cells = < 0x00 >;
		linux,phandle = < 0x11 >;
		compatible = "fixed-clock";
		phandle = < 0x11 >;
		clock-frequency = < 0x7735940 >;
	};

	palmbus@1e000000 {
		#address-cells = < 0x01 >;
		#size-cells = < 0x01 >;
		compatible = "palmbus";
		ranges = < 0x00 0x1e000000 0xfffff >;
		reg = < 0x1e000000 0x100000 >;

		uartfull@e00 {
			reg-io-width = < 0x04 >;
			interrupt-parent = < 0x05 >;
			compatible = "mediatek,mt6577-uart\0ns16550a";
			reg-shift = < 0x02 >;
			status = "okay";
			clock-frequency = < 0x2faf080 >;
			interrupts = < 0x00 0x1c 0x04 >;
			no-loopback-test;
			clocks = < 0x09 >;
			reg = < 0xe00 0x100 >;
		};

		gdma@2800 {
			reset-names = "dma";
			#dma-channels = < 0x10 >;
			linux,phandle = < 0x06 >;
			interrupt-parent = < 0x05 >;
			resets = < 0x04 0x0e >;
			compatible = "mtk,rt3883-gdma";
			phandle = < 0x06 >;
			#dma-cells = < 0x01 >;
			status = "disabled";
			interrupts = < 0x00 0x0d 0x04 >;
			#dma-requests = < 0x10 >;
			reg = < 0x2800 0x800 >;
		};

		ecc@3800 {
			linux,phandle = < 0x0a >;
			compatible = "mediatek,mt7621-ecc";
			phandle = < 0x0a >;
			status = "disabled";
			reg = < 0x3800 0x800 >;
		};

		hsdma@7000 {
			reset-names = "hsdma";
			#dma-channels = < 0x01 >;
			interrupt-parent = < 0x05 >;
			resets = < 0x04 0x05 >;
			compatible = "mediatek,mt7621-hsdma";
			#dma-cells = < 0x01 >;
			status = "disabled";
			interrupts = < 0x00 0x0b 0x04 >;
			#dma-requests = < 0x01 >;
			reg = < 0x7000 0x1000 >;
		};

		nand@3000 {
			#address-cells = < 0x01 >;
			pinctrl-0 = < 0x0b >;
			#size-cells = < 0x01 >;
			compatible = "mediatek,mt7621-nfc";
			status = "disabled";
			pinctrl-names = "default";
			ecc-engine = < 0x0a >;
			reg = < 0x3000 0x800 >;
		};

		spi@b00 {
			reset-names = "spi";
			#address-cells = < 0x01 >;
			pinctrl-0 = < 0x08 >;
			#size-cells = < 0x00 >;
			resets = < 0x04 0x12 >;
			compatible = "mediatek,mt7621-spi";
			status = "okay";
			pinctrl-names = "default";
			clocks = < 0x07 >;
			reg = < 0xb00 0x100 >;

			mx25l12805d@0 {
				#address-cells = < 0x01 >;
				#size-cells = < 0x01 >;
				compatible = "jedec,spi-nor";
				m25p,chunked-io = < 0x20 >;
				spi-max-frequency = < 0x17d7840 >;
				reg = < 0x00 >;

				partition@70000 {
					read-only;
					label = "Factory";
					reg = < 0x70000 0x40000 >;
				};

				partition@90000 {
					label = "bs";
					reg = < 0xc0000 0x10000 >;
				};

				partition@60000 {
					label = "u-boot-env";
					reg = < 0x60000 0x10000 >;
				};

				partition@0 {
					label = "u-boot";
					reg = < 0x00 0x60000 >;
				};

				partition@80000 {
					linux,phandle = < 0x0d >;
					read-only;
					phandle = < 0x0d >;
					label = "EEPROM";
					reg = < 0xb0000 0x10000 >;
				};

				partition@1a0000 {
					label = "kernel0";
					reg = < 0x1d0000 0xf10000 >;
				};

				partition@10d0000 {
					label = "kernel1";
					reg = < 0x10e0000 0xf10000 >;
				};

				partition@a0000 {
					label = "cfg";
					reg = < 0xd0000 0x100000 >;
				};
			};
		};

		i2c@0 {
			gpios = < 0x01 0x03 0x01 0x01 0x04 0x01 >;
			#address-cells = < 0x01 >;
			i2c-gpio,delay-us = < 0x03 >;
			pinctrl-0 = < 0x02 >;
			#size-cells = < 0x00 >;
			compatible = "i2c-gpio";
			status = "disabled";
			pinctrl-names = "default";
		};

		memc@5000 {
			compatible = "mtk,mt7621-memc";
			reg = < 0x5000 0x1000 >;
		};

		sysc@0 {
			compatible = "mtk,mt7621-sysc";
			reg = < 0x00 0x100 >;
		};

		uartfull@d00 {
			reg-io-width = < 0x04 >;
			interrupt-parent = < 0x05 >;
			compatible = "mediatek,mt6577-uart\0ns16550a";
			reg-shift = < 0x02 >;
			status = "disabled";
			clock-frequency = < 0x2faf080 >;
			interrupts = < 0x00 0x1b 0x04 >;
			no-loopback-test;
			clocks = < 0x09 >;
			reg = < 0xd00 0x100 >;
		};

		wdt@100 {
			compatible = "mtk,mt7621-wdt";
			reg = < 0x100 0x100 >;
		};

		uartlite@c00 {
			reg-io-width = < 0x04 >;
			interrupt-parent = < 0x05 >;
			compatible = "mediatek,mt6577-uart\0ns16550a";
			reg-shift = < 0x02 >;
			clock-frequency = < 0x2faf080 >;
			interrupts = < 0x00 0x1a 0x04 >;
			no-loopback-test;
			clocks = < 0x09 >;
			reg = < 0xc00 0x100 >;
		};

		gpio@600 {
			#address-cells = < 0x01 >;
			#size-cells = < 0x00 >;
			compatible = "mtk,mt7621-gpio";
			reg = < 0x600 0x100 >;

			bank@2 {
				#gpio-cells = < 0x02 >;
				compatible = "mtk,mt7621-gpio-bank";
				gpio-controller;
				reg = < 0x02 >;
			};

			bank@0 {
				#gpio-cells = < 0x02 >;
				linux,phandle = < 0x01 >;
				compatible = "mtk,mt7621-gpio-bank";
				gpio-controller;
				phandle = < 0x01 >;
				reg = < 0x00 >;
			};

			bank@1 {
				#gpio-cells = < 0x02 >;
				compatible = "mtk,mt7621-gpio-bank";
				gpio-controller;
				reg = < 0x01 >;
			};
		};

		i2s@a00 {
			reset-names = "i2s";
			interrupt-parent = < 0x05 >;
			dma-names = "tx\0rx";
			resets = < 0x04 0x11 >;
			compatible = "mediatek,mt7621-i2s";
			txdma-req = < 0x02 >;
			status = "disabled";
			interrupts = < 0x00 0x10 0x04 >;
			dmas = < 0x06 0x04 0x06 0x06 >;
			clocks = < 0x03 >;
			rxdma-req = < 0x03 >;
			reg = < 0xa00 0x100 >;
		};
	};

	memory@0 {
		device_type = "memory";
		reg = < 0x00 0x8000000 >;
	};

	sysclock50M {
		#clock-cells = < 0x00 >;
		linux,phandle = < 0x09 >;
		compatible = "fixed-clock";
		phandle = < 0x09 >;
		clock-frequency = < 0x2faf080 >;
	};

	usb@1e1c0000 {
		interrupt-parent = < 0x05 >;
		compatible = "mediatek,mt7621-xhci\0mediatek,mt2701-xhci";
		phys = < 0x12 0x03 0x13 0x04 0x14 0x03 >;
		clock-names = "sys_ck\0free_ck\0ahb_ck\0dma_ck";
		status = "okay";
		interrupts = < 0x00 0x16 0x04 >;
		clocks = < 0x11 0x11 0x11 0x11 >;
		reg-names = "mac\0ippc";
		reg = < 0x1e1c0000 0x1000 0x1e1d0700 0x100 >;
	};

	gsw@1e110000 {
		reset-names = "mcm";
		#address-cells = < 0x01 >;
		mediatek,portmap = "lllll";
		#size-cells = < 0x00 >;
		resets = < 0x04 0x02 >;
		compatible = "mediatek,mt753x";
		mediatek,mdio = < 0x0e >;
		mediatek,mcm;
		reg = < 0x1e110000 0x8000 >;

		mdio-bus {
			#address-cells = < 0x01 >;
			#size-cells = < 0x00 >;
		};

		port@6 {
			phy-mode = "trgmii";
			compatible = "mediatek,mt753x-port";
			reg = < 0x06 >;

			fixed-link {
				full-duplex;
				speed = < 0x3e8 >;
			};
		};
	};

	pcie@1e140000 {
		reset-names = "pcie0\0pcie1\0pcie2";
		#address-cells = < 0x03 >;
		bus-range = < 0x00 0xff >;
		interrupt-parent = < 0x05 >;
		pinctrl-0 = < 0x0f >;
		#size-cells = < 0x02 >;
		resets = < 0x04 0x18 0x04 0x19 0x04 0x1a >;
		compatible = "mediatek,mt7621-pci";
		ranges = < 0x2000000 0x00 0x00 0x60000000 0x00 0x10000000 0x1000000 0x00 0x00 0x1e160000 0x00 0x10000 >;
		clock-names = "pcie0\0pcie1\0pcie2";
		reset-gpios = < 0x01 0x08 0x01 0x01 0x07 0x01 >;
		status = "okay";
		pinctrl-names = "default";
		interrupts = < 0x00 0x04 0x04 0x00 0x18 0x04 0x00 0x19 0x04 >;
		clocks = < 0x10 0x18 0x10 0x19 0x10 0x1a >;
		device_type = "pci";
		reset-gpio-names = "pcie0\0pcie1\0pcie2";
		reg = < 0x1e140000 0x100 0x1e142000 0x100 >;

		pcie@2,0 {
			#address-cells = < 0x03 >;
			#size-cells = < 0x02 >;
			ranges;
			reg = < 0x1000 0x00 0x00 0x00 0x00 >;
		};

		pcie@1,0 {
			#address-cells = < 0x03 >;
			#size-cells = < 0x02 >;
			ranges;
			reg = < 0x800 0x00 0x00 0x00 0x00 >;
		};

		pcie@0,0 {
			#address-cells = < 0x03 >;
			#size-cells = < 0x02 >;
			ranges;
			reg = < 0x00 0x00 0x00 0x00 0x00 >;
		};
	};

	sysclock225M {
		#clock-cells = < 0x00 >;
		compatible = "fixed-clock";
		clock-frequency = < 0xd693a40 >;
	};

	chosen {
		bootargs = "ubootver=v1.1.40.71 ramoops.mem_address=0xfff8000 ramoops.mem_size=32768 ramoops.ecc=1 mem=262111K ubntbootid=0";
	};

	aliases {
		serial0 = "/palmbus@1e000000/uartlite@c00";
	};

	usb-phy@1e1d0000 {
		#address-cells = < 0x01 >;
		#size-cells = < 0x01 >;
		compatible = "mediatek,mt7621-u3phy\0mediatek,mt2701-u3phy";
		ranges;
		status = "disabled";
		reg = < 0x1e1d0000 0x300 >;

		usb-phy@0x1e1d0900 {
			linux,phandle = < 0x13 >;
			phandle = < 0x13 >;
			#phy-cells = < 0x01 >;
			clock-names = "ref";
			clocks = < 0x11 >;
			reg = < 0x1e1d0900 0x700 >;
		};

		usb-phy@0x1e1d1000 {
			linux,phandle = < 0x14 >;
			phandle = < 0x14 >;
			#phy-cells = < 0x01 >;
			clock-names = "ref";
			clocks = < 0x11 >;
			reg = < 0x1e1d1000 0x100 >;
		};

		usb-phy@0x1e1d0800 {
			linux,phandle = < 0x12 >;
			phandle = < 0x12 >;
			#phy-cells = < 0x01 >;
			clock-names = "ref";
			clocks = < 0x11 >;
			reg = < 0x1e1d0800 0x100 >;
		};
	};
};

I am going to give up doing this myself =( I just don't have the time to research further about this. Here is some information I have been collecting about it in the case others want to follow through:

I have put it out there for somebody to do it:

1 Like

My understanding is that the whole Bluetooth stack on OpenWrt have not been maintained for a long time and is not in working condition. Has anyone been running Bluetooth at all on OpenWrt, such as with a basic USB dongle?

I do. Have a simple USB Bluetooth dongle in a Unifi AP AC Pro. Using it with conserver for a serial console with a "jdy-31" rfcom uart module (https://openwrt.org/toh/zyxel/nr7101#serial - mounted outdoors so this is required to keep the IP68 seal)

root@unifiac2:~# dmesg|grep -i blue
[   21.272685] Bluetooth: Core ver 2.22
[   21.281103] Bluetooth: HCI device and connection manager initialized
[   21.287666] Bluetooth: HCI socket layer initialized
[   21.292712] Bluetooth: L2CAP socket layer initialized
[   21.297953] Bluetooth: SCO socket layer initialized
[   21.330960] Bluetooth: BNEP (Ethernet Emulation) ver 1.3
[   21.336461] Bluetooth: BNEP filters: protocol multicast
[   21.341907] Bluetooth: BNEP socket layer initialized
[   21.410170] Bluetooth: hci0: CSR: Unbranded CSR clone detected; adding workarounds...
[   21.432186] Bluetooth: HCI UART driver ver 2.3
[   21.436799] Bluetooth: HCI UART protocol H4 registered
[   21.442137] Bluetooth: HCI UART protocol BCSP registered
[   21.461281] Bluetooth: HIDP (Human Interface Emulation) ver 1.2
[   21.467415] Bluetooth: HIDP socket layer initialized
[   21.516642] Bluetooth: RFCOMM TTY layer initialized
[   21.521763] Bluetooth: RFCOMM socket layer initialized
[   21.527090] Bluetooth: RFCOMM ver 1.11
root@unifiac2:~# cat /etc/rc.local 
# Put your custom commands here that should be executed once
# the system init finished. By default this file does nothing.

# connect /dev/rfcomm0 to nr7101 bluetooth console for conserver
/usr/bin/hciconfig hci0 up
/usr/bin/rfcomm bind 0 46:6E:00:00:81:82

exit 0
root@unifiac2:~# opkg list_installed|grep -i blue
bluez-libs - 5.62-2
bluez-utils - 5.62-2
kmod-bluetooth - 5.10.103-1

root@unifiac2:~# cat /sys/kernel/debug/usb/devices 

T:  Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=480  MxCh= 1
B:  Alloc=  4/800 us ( 1%), #Int=  1, #Iso=  0
D:  Ver= 2.00 Cls=09(hub  ) Sub=00 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=1d6b ProdID=0002 Rev= 5.10
S:  Manufacturer=Linux 5.10.103 ehci_hcd
S:  Product=EHCI Host Controller
S:  SerialNumber=1b000000.usb
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=  0mA
I:* If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub
E:  Ad=81(I) Atr=03(Int.) MxPS=   4 Ivl=256ms

T:  Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12   MxCh= 0
D:  Ver= 2.00 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=0a12 ProdID=0001 Rev=88.91
S:  Product=CSR8510 A10
C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA
I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=1ms
E:  Ad=02(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=03(O) Atr=01(Isoc) MxPS=   0 Ivl=1ms
E:  Ad=83(I) Atr=01(Isoc) MxPS=   0 Ivl=1ms
I:  If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=03(O) Atr=01(Isoc) MxPS=   9 Ivl=1ms
E:  Ad=83(I) Atr=01(Isoc) MxPS=   9 Ivl=1ms
I:  If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=03(O) Atr=01(Isoc) MxPS=  17 Ivl=1ms
E:  Ad=83(I) Atr=01(Isoc) MxPS=  17 Ivl=1ms
I:  If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=03(O) Atr=01(Isoc) MxPS=  25 Ivl=1ms
E:  Ad=83(I) Atr=01(Isoc) MxPS=  25 Ivl=1ms
I:  If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=03(O) Atr=01(Isoc) MxPS=  33 Ivl=1ms
E:  Ad=83(I) Atr=01(Isoc) MxPS=  33 Ivl=1ms
I:  If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=03(O) Atr=01(Isoc) MxPS=  49 Ivl=1ms
E:  Ad=83(I) Atr=01(Isoc) MxPS=  49 Ivl=1ms

root@unifiac2:~# tail -7 /etc/conserver/conserver.cf 
console nr7101 {
        master 127.0.0.1;
        type device;
        device /dev/rfcomm0;
        baud 57600;
        parity none;
}

The dongle is also working fine in other modes, like for example BLE. But I'm not using that.

In any case, there is nothing wrong with the Bluetooth support in OpenWrt. The Unifi 6 Lite problem is only lack of driver (and firmware?) support. Too bad since the 6 Lite doesn't have a USB port for a dongle, like the AC Pro has.

1 Like

The onboard bluetooth also appears to work on my map-ac2200, I just have no real use for i and leave it disabled.

(Edit: apologies, I just noticed the age of the post; below might be common knowledge by now)

Hey all,

Not sure if this is of interest any more; however, I stumbled on this thread while checking if I could install OpenWRT on my AP Lite 6.

FWIW, on the latest OEM FW, there's a bunch of files and settings regarding BLE, and some JSON config.

Some snippets:

  • fw_printenv shows ble_mode=serial. I'm going to unset this and see if it frees up the BLE for other uses.

  • /etc/persistent has a few JSON configs -- blebr.json & blebr2.json. The latter shows the SoC as a mt7915 and lists its BLE capabilities.

  • /var has bt_cmd_fifo (named pipe) and mtk_bt_service (socket)

  • /proc/ubnthal/system.info lists the chips MT7621, MT7603 and MT7915 (cpu, radio0, radio1)

  • /usr/share/bleconn has a bunch of shell scripts relating to parsing/setting config. as well as a shell script (udm-b-bt-dfu-loader.sh) that puts the BLE SoC into firmware upload mode, as well as udm-b-bt-firmware.gbl -- the file extension led me to: https://docs.silabs.com/mcu-bootloader/1.12/group-EblParserFormat

I'll see what I can dig into and report back if anything useful happens

2 Likes

Thanks! I am still interested in this. Let me know what else you find!

Did you look at https://github.com/blocktrron/u6-lite-gpl.git ?

Lots of good laughs there. See for example https://github.com/blocktrron/u6-lite-gpl/blob/master/gpl-uboot-u6lite-1.1.44/uboot-uap-mtk-1.1.44/common/ubnt_ble.c

I have this somewhat working - my last issue is that I get dropped bytes on the serial link to the mt7915 bluetooth chip. So I can't use it at 921600 baud as the OEM firmware does. It looks like they use flow control, but I didn't have much success getting that to work (yet). Running at a lower baudrate, some DTS fetzing, replacing the awful logic for unwrapping stp packets in btmtkuart.c, and a few other bits gets me this:

=== WARNING! =====================================
There is no root password defined on this device!
Use the "passwd" command to set up a new password
in order to prevent unauthorized SSH logins.
--------------------------------------------------
root@bonito6:~# grep machine /proc/cpuinfo
machine                 : Ubiquiti UniFi 6 Lite
root@bonito6:~# insmod btmtkuart.ko 
root@bonito6:~# hciconfig hci0 up
root@bonito6:~# hciconfig hci0
hci0:   Type: Primary  Bus: UART
        BD Address: 00:XX:XX:XX:XX:02  ACL MTU: 1021:6  SCO MTU: 244:4
        UP RUNNING 
        RX bytes:1093 acl:0 sco:0 events:50 errors:0
        TX bytes:834 acl:0 sco:0 commands:50 errors:0

root@bonito6:~# hcitool lescan
LE Scan ...
B8:XX:XX:XX:XX:1E (unknown)
B8:XX:XX:XX:XX:1E HUAWEI WATCH GT 2-XXX
58:XX:XX:XX:XX:43 (unknown)
58:XX:XX:XX:XX:43 MJ_HT_V1
[...]

I built some better tools...

root@bonito6:~# bluetoothctl
Agent registered
[bluetooth]# power off
Changing power off succeeded
[CHG] Controller 00:XX:XX:XX:XX:02 Powered: no
[CHG] Controller 00:XX:XX:XX:XX:02 Discovering: no
[bluetooth]# power on
Changing power on succeeded
[CHG] Controller 00:XX:XX:XX:XX:02 Powered: yes
[bluetooth]#
[bluetooth]# quit

root@bonito6:~# /usr/bin/gatttool -b 58:XX:XX:XX:XX:43 --char-write-req --handle=0x10 -n 0100 --listen
Characteristic value was written successfully
Notification handle = 0x000e value: 54 3d 31 38 2e 33 20 48 3d 35 30 2e 30 00
Notification handle = 0x000e value: 54 3d 31 38 2e 33 20 48 3d 34 39 2e 39 00
Notification handle = 0x000e value: 54 3d 31 38 2e 33 20 48 3d 35 30 2e 31 00
Notification handle = 0x000e value: 54 3d 31 38 2e 34 20 48 3d 34 39 2e 39 00
[openwrt@buildmachine ~]$ echo 54 3d 31 38 2e 34 20 48 3d 34 39 2e 39  | xxd -r -p
T=18.4 H=49.9

ooh, nice! Do you have a repo somewhere? I'd love to test it

Also interested here. Would any of this be transferable to the U6+ in any way?

So I fixed the mtk uart driver to support shared IRQs, made it play nicely with the boot console. With that driver hardware RTS/CTS started working, which fixed the dropped characters at 921600 baud.

It seems stable, I've not seen it fall over in the couple of hours I've played with it. Someone who knows more about unifi's product line can figure how how to merge this as I have no idea what else this might break.

The only gotcha is you'll need to reboot (or at least strobe the reset on the MT7915DACN chip which takes out some of the wifi) if you want to reload btmtkuart.ko as there's no way for it to know what the baud rate currently in use is.

Here's the relevant commit on a recent fork - there's one other patch to fix some meson misery which is unrelated to this patch. I built that with

CONFIG_PACKAGE_kmod-bluetooth=y

The OEM firmware has some firmware and patches it can download (I don't know if it does), but, at least on my U6 lite, the bootloader has already loaded the BT firmware into the device. The data sheet said it had ~300k of rom, so perhaps it doesn't need bootstrapping.

[    8.898965] btmtkuart serial0-0: supply vcc not found, using dummy regulator
[    8.982480] usbcore: registered new interface driver btusb
[    8.989249] Loading modules backported from Linux version v6.5-0-g2dde18cd1d8f
[    8.996527] Backport generated by backports.git v5.15.92-1-56-g5fb2ccb6b9e8
[    9.006516] Bluetooth: HCI UART driver ver 2.3
[    9.011078] Bluetooth: HCI UART protocol H4 registered
[    9.011078] Bluetooth: hci0: Firmware already downloaded
[    9.011094] Bluetooth: HCI UART protocol BCSP registered
[    9.013914] Bluetooth: HIDP (Human Interface Emulation) ver 1.2
[    9.032988] Bluetooth: HIDP socket layer initialized
[    9.052703] Bluetooth: RFCOMM TTY layer initialized
[    9.057735] Bluetooth: RFCOMM socket layer initialized
[    9.062929] Bluetooth: RFCOMM ver 1.11
[    9.127246] Bluetooth: hci0: Device setup in 145377 usecs
root@bonito6:~# opkg install bluez-utils bluez-tools
[...]
Configuring bluez-tools.
root@bonito6:~# bluetoothctl
Agent registered
[bluetooth]# power on
Changing power on succeeded
[bluetooth]# scan on
Discovery started
[CHG] Controller 00:XX:XX:XX:XX:02 Discovering: yes
[NEW] Device 58:XX:XX:XX:XX:C3 MJ_HT_V1
[NEW] Device A4:XX:XX:XX:XX:04 LYWSD03MMC
[CHG] Device 58:XX:XX:XX:XX:C3 ServiceData Key: 0000fe95-0000-1000-8000-00805f9b34fb

Thanks! Great work!

The mtk uart and bluetooth driver changes should be upstreamable. I assume we can use the same mt7621 symbol to enable this uart driver as we do for the mtk soc eth driver instead of dropping the mediatek dependency. But I wonder about the uart flag change: Is this mt7621 specific? I guess we either need to justify that change for all users or protect it behind some symbol. And the uart type change is probably related to the extra flags? Is that something we can get away with making global for every user? Or do we have to make it mt7621 specific as well?

The mtk bluetooth changes are already self contained and should be directly upstreamable with a comment and commit message cleanup. I consider the unload issue a minor thing. It would be nice if we could solve the problem, but this will be fine without a solution.

For the dts changes I think it actually makes sense to switch all the uarts to the mtk driver when we have that enabled. This is openwrt specific anyway, so that shouldn't be a problem in any case.

Works like a dream.

I was already testing 6.1 so I copied your patch and config there. It needs a trivial modification since the btmtkuart module depends on btmtk there, but that's all.

[   45.382425] hid: raw HID events driver (C) Jiri Kosina
[   45.495122] Bluetooth: Core ver 2.22
[   45.498947] NET: Registered PF_BLUETOOTH protocol family
[   45.504337] Bluetooth: HCI device and connection manager initialized
[   45.510773] Bluetooth: HCI socket layer initialized
[   45.515670] Bluetooth: L2CAP socket layer initialized
[   45.520793] Bluetooth: SCO socket layer initialized
[   45.527850] Bluetooth: BNEP (Ethernet Emulation) ver 1.3
[   45.533294] Bluetooth: BNEP filters: protocol multicast
[   45.538555] Bluetooth: BNEP socket layer initialized
[   45.549263] btmtkuart serial0-0: supply vcc not found, using dummy regulator
[   45.625127] usbcore: registered new interface driver btusb
[   45.631911] Loading modules backported from Linux version v6.6.15-0-g51f354b815c4
[   45.639499] Backport generated by backports.git 193becf2
[   45.647021] Bluetooth: HCI UART driver ver 2.3
[   45.651577] Bluetooth: HCI UART protocol H4 registered
[   45.653934] Bluetooth: hci0: Firmware already downloaded
[   45.656731] Bluetooth: HCI UART protocol BCSP registered
[   45.669608] Bluetooth: HIDP (Human Interface Emulation) ver 1.2
[   45.675611] Bluetooth: HIDP socket layer initialized
[   45.696988] Bluetooth: RFCOMM TTY layer initialized
[   45.702027] Bluetooth: RFCOMM socket layer initialized
[   45.707223] Bluetooth: RFCOMM ver 1.11
[   45.901190] pci 0000:00:00.0: enabling device (0006 -> 0007)
[   45.906947] mt7603e 0000:01:00.0: enabling device (0000 -> 0002)
[   45.913234] mt7603e 0000:01:00.0: ASIC revision: 76030010
[   46.167311] urngd: v1.0.2 started.
[   46.254511] Bluetooth: hci0: Device setup in 618339 usecs

Have a question about the controller mac address. I get this, which looks very suspiciously like a generic default (79:15 - right):

root@u6-2:/# hciconfig  hci0
hci0:   Type: Primary  Bus: UART
        BD Address: 00:00:46:79:15:02  ACL MTU: 1021:6  SCO MTU: 244:4
        UP RUNNING 
        RX bytes:3944 acl:4 sco:0 events:144 errors:0
        TX bytes:2058 acl:4 sco:0 commands:119 errors:0

Do you have the exact same? Should we pick up a real mac somewhere?

Other than that, it seems to work fine with the tests I'm able to do. My U6 lite is in a remote location, so I can't do much about the lack of other bluetooth devices. There are no active BLE devices within range it seems. But I do have an RPi4 showing up:

root@u6-2:/# hcitool scan
Scanning ...
        D8:3A:DD:37:D3:12       rattata
root@u6-2:/# hcitool info D8:3A:DD:37:D3:12
Requesting information ...
        BD Address:  D8:3A:DD:37:D3:12
        Device Name: rattata
        LMP Version: 5.0 (0x9) LMP Subversion: 0x6119
        Manufacturer: Cypress Semiconductor (305)
        Features page 0: 0xbf 0xfe 0xcf 0xfe 0xdb 0xff 0x7b 0x87
                <3-slot packets> <5-slot packets> <encryption> <slot offset> 
                <timing accuracy> <role switch> <sniff mode> <RSSI> 
                <channel quality> <SCO link> <HV2 packets> <HV3 packets> 
                <u-law log> <A-law log> <CVSD> <paging scheme> <power control> 
                <transparent SCO> <broadcast encrypt> <EDR ACL 2 Mbps> 
                <EDR ACL 3 Mbps> <enhanced iscan> <interlaced iscan> 
                <interlaced pscan> <inquiry with RSSI> <extended SCO> 
                <EV4 packets> <EV5 packets> <AFH cap. perip.> 
                <AFH cls. perip.> <LE support> <3-slot EDR ACL> 
                <5-slot EDR ACL> <sniff subrating> <pause encryption> 
                <AFH cap. central> <AFH cls. central> <EDR eSCO 2 Mbps> 
                <EDR eSCO 3 Mbps> <3-slot EDR eSCO> <extended inquiry> 
                <LE and BR/EDR> <simple pairing> <encapsulated PDU> 
                <err. data report> <non-flush flag> <LSTO> <inquiry TX power> 
                <EPC> <extended features> 
        Features page 1: 0x0b 0x00 0x00 0x00 0x00 0x00 0x00 0x00
        Features page 2: 0x7f 0x0b 0x00 0x00 0x00 0x00 0x00 0x00

But I wonder about the uart flag change: Is this mt7621 specific?

I think the original uart driver was lazy, almost all of the flags are derivable from the DTS properties of the interrupt, I'll have a go a doing the right thing.

Have a question about the controller mac address. I get this

as do I

hci0:   Type: Primary  Bus: UART
        BD Address: 00:00:46:79:15:02  ACL MTU: 1021:6  SCO MTU: 244:4
        UP RUNNING INQUIRY 
        RX bytes:7479315 acl:0 sco:0 events:116006 errors:0
        TX bytes:200764 acl:0 sco:0 commands:12302 errors:0

The bootloader is using a different mac...

 Board: Ubiquiti Networks MT7621 board (a612-23.0000)
 UBNT application initialized
  *WARNING*: Could not parse FW version, please check FW format
 is_default true
 is_ble_stp = true

 ~~~ p_device_model:U6-LITE
 ~~~ is_default:1 ~~~
 ~~~ p_macaddr:e4:XX:XX:XX:XX:61 ~~~
 ~~~ is_ble_stp:1 ~~~
 =========================GPIO INIT=====================
 GPIO_16, action is output low
 GPIO_16, action is output high
 GPIO_19, action is output low
 GPIO_19, action is output high
 =========================UART_3 INIT=====================
 uartlite0@1e000c00, 1e000c00
 uartlite0@1e000e00 bring up, 1e000e00
 =========================FLOW 1=====================
 [BT Power On Result] Success
[...]
 =========================FLOW 6=====================
 [HIC LE  SET ADVERISTING ENABLE Result] Success
 MT7915 BLE broadcasting successfully
 Autobooting in 2 seconds, press "<Esc><Esc>" to stop

which comes from the thing you linked above

but that's the same address we're using for the ethernet nic. I'll load the OEM firmware at some point and see what it does

root@bonito6:~# ip a s eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1504 qdisc mq state UP qlen 1000
    link/ether e4:XX:XX:XX:XX:61 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::XXXX:XXXX:XX61/64 scope link 
       valid_lft forever preferred_lft forever

The ti hci driver pulls it from DTS using a bd-address nvem-cells property, that method seems to be unique to it. The bcm and intel drivers fall back to looking in efi variables. The ti approach seems to be the most sensible unless you think it ought to should handle it higher up the stack in the user-land scripts. I'm happy to code that up (subject to whatever testing the OEM firmware reveals)

You mentioned you have some of these units in production, I'm looking at replacing a fleet of AC-Lites and home-brew BLE APs with these U6 lites, but whilst they seem equally capable as the AC-Lites doing 80MHz at 5G (~400Mbits), when I enabled 160MHz performance was awful (~37 down/ 2 up). But I only tested one client (a recent samsung phone). I did it in our lab's RF test room so I don't think it was suffering any interference.

Oh the only other thing I wanted to ask, since it's been a while since I've done embedded linux kernel work in anger: by default the uart has a pinctrl for its pins.

                uartlite3: uartlite3@e00 {
                        compatible = "ns16550a";
                        [....]
                        pinctrl-names = "default";
                        pinctrl-0 = <&uart3_pins>;
                        [....]
                };

The btmtkuart driver (for an external chip) is expecting two pinctrl schemes "default" and "runtime", if you do the naïve thing:

                uartlite3: uartlite3@e00 {
                        compatible = "ns16550a";
                        [....]
                        pinctrl-names = "default";
                        pinctrl-0 = <&uart3_pins>;
                        bluetooth {
                                compatible = "mediatek,mt7915-bluetooth";
                                pinctrl-names = "default","runtime";
                                pinctrl-0 = <&uart3_pins>;
                                pinctrl-1 = <&uart3_pins>;
                                [....]
                        };
                        [....]
                };

Then bdev->pinctrl = devm_pinctrl_get(&serdev->dev); fails in btmtkuart because the pinctrl is already exclusively owned by the containing uart device. I had a quick look for an api that allowed me to grab the pinctrl of 'containing' device but either didn't look hard enough, or it didn't exist, or there's some other better correct way of doing this - is there a "how pinctrl is designed for dummies" I can read? Apologies for a question to which the answer is presumably RTFM.