2025年2月19日 星期三

Openwrt: Support Bluetooth in D-Link M32

這一篇是紀錄,不是要上什麼pr什麼的。感謝Openwrt論譠上的討論,一些東西讓我可以比較有根據的去驗證。

更新 2025-02-21

1. 看了一堆有的沒有的資料並且邊驗證邊試出來M32的藍芽是在MT7915AN的晶片上,經由UART3的TXD/RXD/CTS/RTS與MT7622B互連。

    1a. MT7622B自己也有藍芽但線路上是用0Ohm接地掉了,沒有拉天線出來使用。

    1b. 除了UART3的訊號外還有一個GPIO61會在Bootloader階段拉High。

    1c. 官方的M32的DTS與我手邊機器有些地方不一樣,在原始M32的討論篇中也有人提出來。所以改了也不少。參考連結Support for DLink M32 Mesh System and R32 Router

2. Openwrt論譠上有人提供了Unifi 6 Lite的Bluetooth Patch。幫助很大但也有限,後面再說明。參考連結 UART3 Bluetooth in UniFi 6 Lite

3. mt7915_patch_e2_hdr.bin這個檔案就自己想辦法了,不確定同平台的能不能通用。

4. 經過一連串的嘗試錯誤後的組合結果如下,不太會用diff與patch,打不進去的話再自己修改一下。

5. Build完後在目標機器上跑的時候需要先安裝WIFI Driver,接著安裝完btmtkuart後"必須"把/etc/modules.d/btmtkuart刪除,並在/etc/rc.local加入sleep 5;insmod btmtkuart;。

    5a. 因為MT7915的WIFI與BT的Reset控制是一起的,目前試出來的結論是由WIFI Driver控制。這樣在Software Reboot時才能正常。

    5b. 目前驗證的結論是要晚一點載入btmtkuart,才會正常的跑完Firmware Patch;否則隨機性的掉Frame後失敗。雖然可以寫進btmtkuart.c當中啦…但想想還是算了。

    5c. 順利的話開機會花9秒左右完成初始化,之後使用hciconfig hci0 up與hcitool -i hci0 lescan。


--- a/drivers/bluetooth/btmtkuart.c 2024-09-12 17:07:53.000000000 +0800
+++ b/drivers/bluetooth/btmtkuart.c 2025-02-20 14:58:49.174506937 +0800
@@ -21,6 +21,7 @@
 #include <linux/pinctrl/consumer.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
+#include <linux/nvmem-consumer.h>
 #include <linux/serdev.h>
 #include <linux/skbuff.h>
 
@@ -34,6 +35,7 @@
 #define FIRMWARE_MT7622 "mediatek/mt7622pr2h.bin"
 #define FIRMWARE_MT7663 "mediatek/mt7663pr2h.bin"
 #define FIRMWARE_MT7668 "mediatek/mt7668pr2h.bin"
+#define FIRMWARE_MT7915 "mediatek/mt7915_patch_e2_hdr.bin"
 
 #define MTK_STP_TLR_SIZE 2
 
@@ -43,6 +45,7 @@
 #define BTMTKUART_REQUIRED_WAKEUP 4
 
 #define BTMTKUART_FLAG_STANDALONE_HW BIT(0)
+#define BTMTKUART_FLAG_USE_FLOW_CONTROL  BIT(1)
 
 enum {
  MTK_WMT_PATCH_DWNLD = 0x1,
@@ -138,13 +141,27 @@
  u8 stp_cursor;
  u16 stp_dlen;
 
+ int have_bdaddr;
+ bdaddr_t bdaddr;
+ bool is_ble_stp;
+
  const struct btmtkuart_data *data;
 };
 
+struct btmtk_patch_header {
+ u8 datetime[16];
+ u8 platform[4];
+ __le16 hwver;
+ __le16 swver;
+ __le32 patchver;
+} __packed;
+
 #define btmtkuart_is_standalone(bdev) \
  ((bdev)->data->flags & BTMTKUART_FLAG_STANDALONE_HW)
 #define btmtkuart_is_builtin_soc(bdev) \
  !((bdev)->data->flags & BTMTKUART_FLAG_STANDALONE_HW)
+#define btmtkuart_use_flow_control(bdev) \
+ !!((bdev)->data->flags & BTMTKUART_FLAG_USE_FLOW_CONTROL)
 
 static int mtk_hci_wmt_sync(struct hci_dev *hdev,
      struct btmtk_hci_wmt_params *wmt_params)
@@ -158,6 +175,7 @@
  int err;
 
  hlen = sizeof(*hdr) + wmt_params->dlen;
+
  if (hlen > 255) {
  err = -EINVAL;
  goto err_free_skb;
@@ -239,9 +257,12 @@
  return err;
 }
 
+
+
 static int mtk_setup_firmware(struct hci_dev *hdev, const char *fwname)
 {
  struct btmtk_hci_wmt_params wmt_params;
+ struct btmtk_patch_header *hdr;
  const struct firmware *fw;
  const u8 *fw_ptr;
  size_t fw_size;
@@ -256,6 +277,10 @@
 
  fw_ptr = fw->data;
  fw_size = fw->size;
+ hdr = (struct btmtk_patch_header *)fw_ptr;
+
+ bt_dev_info(hdev, "HW/SW Version: 0x%04x%04x, Build Time: %s",
+     be16_to_cpu(hdr->hwver), be16_to_cpu(hdr->swver), hdr->datetime);
 
  /* The size of patch header is 30 bytes, should be skip */
  if (fw_size < 30) {
@@ -478,7 +503,7 @@
  int sz_left = count, sz_h4, adv;
  int err;
 
- while (sz_left > 0) {
+ while (bdev->is_ble_stp && sz_left > 0) {
  /*  The serial data received from MT7622 BT controller is
  *  at all time padded around with the STP header and tailer.
  *
@@ -516,6 +541,18 @@
  sz_left -= sz_h4;
  p_left += sz_h4;
  }
+ if(!bdev->is_ble_stp) {
+ bdev->rx_skb = h4_recv_buf(bdev->hdev, bdev->rx_skb, data,
+    count, mtk_recv_pkts,
+    ARRAY_SIZE(mtk_recv_pkts));
+ if (IS_ERR(bdev->rx_skb)) {
+ err = PTR_ERR(bdev->rx_skb);
+ bt_dev_err(bdev->hdev,
+    "btmtkuart_recv non-stp ERR(%d)", err);
+ bdev->rx_skb = NULL;
+ return;
+ }
+ }
 }
 
 static int btmtkuart_receive_buf(struct serdev_device *serdev, const u8 *data,
@@ -569,7 +606,7 @@
  goto  err_serdev_close;
  }
 
- serdev_device_set_flow_control(bdev->serdev, false);
+ serdev_device_set_flow_control(bdev->serdev, btmtkuart_use_flow_control(bdev));
  }
 
  bdev->stp_cursor = 2;
@@ -687,7 +724,7 @@
  return err;
  }
 
- serdev_device_set_flow_control(bdev->serdev, false);
+ serdev_device_set_flow_control(bdev->serdev, btmtkuart_use_flow_control(bdev));
 
  /* Send a dummy byte 0xff to activate the new baudrate */
  param = 0xff;
@@ -719,6 +756,25 @@
  return 0;
 }
 
+static int btmtkuart_set_bdaddr(struct hci_dev *hdev)
+{
+ struct btmtkuart_dev *bdev = hci_get_drvdata(hdev);
+ struct sk_buff *skb = 0;
+
+
+ if (!bdev->have_bdaddr) {
+ set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
+ }
+ else {
+ skb = __hci_cmd_sync(hdev, 0xfc1a, sizeof(bdaddr_t),
+      &bdev->bdaddr, HCI_INIT_TIMEOUT);
+ }
+ if (!IS_ERR(skb))
+ kfree_skb(skb);
+
+ return PTR_ERR_OR_ZERO(skb);
+}
+
 static int btmtkuart_setup(struct hci_dev *hdev)
 {
  struct btmtkuart_dev *bdev = hci_get_drvdata(hdev);
@@ -751,9 +807,13 @@
  clear_bit(BTMTKUART_REQUIRED_WAKEUP, &bdev->tx_state);
  }
 
+ if (err < 0)
+ return err;
+
  if (btmtkuart_is_standalone(bdev))
  btmtkuart_change_baudrate(hdev);
 
+
  /* Query whether the firmware is already download */
  wmt_params.op = MTK_WMT_SEMAPHORE;
  wmt_params.flag = 1;
@@ -825,6 +885,10 @@
  }
  kfree_skb(skb);
 
+ err = btmtkuart_set_bdaddr(hdev);
+ if (err) 
+ return err;
+
  rettime = ktime_get();
  delta = ktime_sub(rettime, calltime);
  duration = (unsigned long long)ktime_to_ns(delta) >> 10;
@@ -865,24 +929,26 @@
  /* Prepend skb with frame type */
  memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
 
- /* Make sure that there is enough rooms for STP header and trailer */
- if (unlikely(skb_headroom(skb) < sizeof(*shdr)) ||
-     (skb_tailroom(skb) < MTK_STP_TLR_SIZE)) {
- err = pskb_expand_head(skb, sizeof(*shdr), MTK_STP_TLR_SIZE,
-        GFP_ATOMIC);
- if (err < 0)
- return err;
- }
+ if (bdev->is_ble_stp) {
+ /* Make sure that there is enough rooms for STP header and trailer */
+ if (unlikely(skb_headroom(skb) < sizeof(*shdr)) ||
+     (skb_tailroom(skb) < MTK_STP_TLR_SIZE)) {
+ err = pskb_expand_head(skb, sizeof(*shdr), MTK_STP_TLR_SIZE,
+        GFP_ATOMIC);
+ if (err < 0)
+ return err;
+ }
 
- /* Add the STP header */
- dlen = skb->len;
- shdr = skb_push(skb, sizeof(*shdr));
- shdr->prefix = 0x80;
- shdr->dlen = cpu_to_be16((dlen & 0x0fff) | (type << 12));
- shdr->cs = 0; /* MT7622 doesn't care about checksum value */
+ /* Add the STP header */
+ dlen = skb->len;
+ shdr = skb_push(skb, sizeof(*shdr));
+ shdr->prefix = 0x80;
+ shdr->dlen = cpu_to_be16((dlen & 0x0fff) | (type << 12));
+ shdr->cs = 0; /* MT7622 doesn't care about checksum value */
 
- /* Add the STP trailer */
- skb_put_zero(skb, MTK_STP_TLR_SIZE);
+ /* Add the STP trailer */
+ skb_put_zero(skb, MTK_STP_TLR_SIZE);
+ }
 
  skb_queue_tail(&bdev->txq, skb);
 
@@ -895,6 +961,7 @@
  struct btmtkuart_dev *bdev = serdev_device_get_drvdata(serdev);
  struct device_node *node = serdev->dev.of_node;
  u32 speed = 921600;
+ struct nvmem_cell *bdaddr_cell;
  int err;
 
  if (btmtkuart_is_standalone(bdev)) {
@@ -902,6 +969,10 @@
 
  bdev->desired_speed = speed;
 
+ bdev->is_ble_stp = true;
+ if (of_property_read_bool(node, "not-stp"))
+ bdev->is_ble_stp = false;
+
  bdev->vcc = devm_regulator_get(&serdev->dev, "vcc");
  if (IS_ERR(bdev->vcc)) {
  err = PTR_ERR(bdev->vcc);
@@ -955,6 +1026,32 @@
  return PTR_ERR(bdev->clk);
  }
 
+ bdaddr_cell = nvmem_cell_get(&serdev->dev, "bd-address");
+ if (!IS_ERR(bdaddr_cell)) {
+ bdaddr_t *bdaddr;
+ size_t len;
+
+ bdaddr = nvmem_cell_read(bdaddr_cell, &len);
+ nvmem_cell_put(bdaddr_cell);
+ if (IS_ERR(bdaddr)) {
+ dev_err(&serdev->dev, "Failed to read nvmem bd-address\n");
+ return PTR_ERR(bdaddr);
+ }
+ if (len != sizeof(bdaddr_t)) {
+ dev_err(&serdev->dev, "Invalid nvmem bd-address length\n");
+ kfree(bdaddr);
+ return -EINVAL;
+ }
+
+ /* As per the device tree bindings, the value from nvmem is
+ * expected to be MSB first, but in the kernel it is expected
+ * that bdaddr_t is LSB first.
+ */
+ bdev->have_bdaddr = 1;
+ baswap(&bdev->bdaddr, bdaddr);
+ kfree(bdaddr);
+ }
+
  return 0;
 }
 
@@ -1101,11 +1198,18 @@
  .fwname = FIRMWARE_MT7668,
 };
 
+static const struct btmtkuart_data mt7915_data = {
+ .flags = BTMTKUART_FLAG_STANDALONE_HW | BTMTKUART_FLAG_USE_FLOW_CONTROL,
+ .fwname = FIRMWARE_MT7915,
+};
+
+
 #ifdef CONFIG_OF
 static const struct of_device_id mtk_of_match_table[] = {
  { .compatible = "mediatek,mt7622-bluetooth", .data = &mt7622_data},
  { .compatible = "mediatek,mt7663u-bluetooth", .data = &mt7663_data},
  { .compatible = "mediatek,mt7668u-bluetooth", .data = &mt7668_data},
+ { .compatible = "mediatek,mt7915-bluetooth", .data = &mt7915_data},
  { }
 };
 MODULE_DEVICE_TABLE(of, mtk_of_match_table);
--- a/target/linux/mediatek/dts/mt7622-dlink-eagle-pro-ai-ax3200-a1.dtsi 2024-09-24 06:53:33.000000000 +0800
+++ b/target/linux/mediatek/dts/mt7622-dlink-eagle-pro-ai-ax3200-a1.dtsi 2025-02-04 16:44:41.211442072 +0800
@@ -54,10 +54,6 @@
  status = "okay";
 };
 
-&btif {
- status = "okay";
-};
-
 &eth {
  pinctrl-names = "default";
  pinctrl-0 = <&eth_pins>;
@@ -119,12 +115,6 @@
  status = "okay";
 };
 
-&pcie1 {
- pinctrl-names = "default";
- pinctrl-0 = <&pcie1_pins>;
- status = "okay";
-};
-
 &pio {
  epa_elna_pins: epa-elna-pins {
  mux {
@@ -146,18 +136,7 @@
  pcie0_pins: pcie0-pins {
  mux {
  function = "pcie";
- groups = "pcie0_pad_perst",
- "pcie0_1_waken",
- "pcie0_1_clkreq";
- };
- };
-
- pcie1_pins: pcie1-pins {
- mux {
- function = "pcie";
- groups = "pcie1_pad_perst",
- "pcie1_0_waken",
- "pcie1_0_clkreq";
+ groups = "pcie0_pad_perst";
  };
  };
 
@@ -219,133 +198,6 @@
  };
 };
 
-&snfi {
- pinctrl-names = "default";
- pinctrl-0 = <&serial_nand_pins>;
- status = "okay";
-
- snand: flash@0 {
- compatible = "spi-nand";
- mediatek,bmt-table-size = <0x1000>;
- mediatek,bmt-v2;
- nand-ecc-engine = <&snfi>;
- reg = <0>;
- spi-rx-bus-width = <4>;
- spi-tx-bus-width = <4>;
-
- partitions {
- compatible = "fixed-partitions";
- #address-cells = <1>;
- #size-cells = <1>;
-
- partition@0 {
- label = "Preloader";
- reg = <0x00000000 0x00080000>;
- read-only;
- };
-
- partition@80000 {
- label = "ATF";
- reg = <0x00080000 0x00040000>;
- read-only;
- };
-
- partition@C0000 {
- label = "Bootloader";
- reg = <0x000C0000 0x00080000>;
- read-only;
- };
-
- partition@140000 {
- label = "BootConfig";
- reg = <0x00140000 0x00040000>;
- };
-
- partition@180000 {
- label = "Odm";
- reg = <0x00180000 0x00040000>;
- read-only;
- odm_partition: nvmem-layout {
- compatible = "fixed-layout";
- };
- };
-
- config1: partition@1C0000 {
- compatible = "nvmem-cells";
- label = "Config1";
- reg = <0x001C0000 0x00080000>;
- read-only;
- };
-
- partition@240000 {
- label = "Config2";
- reg = <0x00240000 0x00080000>;
- read-only;
- };
-
- partition@2C0000 {
- label = "Kernel1";
- reg = <0x002C0000 0x02D00000>;
-
- compatible = "denx,fit";
- openwrt,cmdline-match = "boot_part=Kernel1";
- partition@0 {
- label = "kernel";
- reg = <0x00000000 0x00800000>;
- };
-
- partition@800000 {
- label = "ubi";
- reg = <0x00800000 0x02500000>;
- };
- };
-
- partition@2FC0000 {
- label = "Kernel2";
- reg = <0x02FC0000 0x02D00000>;
-
- compatible = "denx,fit";
- openwrt,cmdline-match = "boot_part=Kernel2";
- partition@0 {
- label = "kernel";
- reg = <0x00000000 0x00800000>;
- };
-
- partition@800000 {
- label = "ubi";
- reg = <0x00800000 0x02500000>;
- };
- };
-
- factory: partition@5CC0000 {
- label = "Factory";
- reg = <0x05CC0000 0x00100000>;
- read-only;
- };
-
- partition@5DC0000 {
- label = "Mydlink";
- reg = <0x05DC0000 0x00200000>;
- read-only;
- };
-
- partition@5FC0000 {
- label = "Storage";
- reg = <0x05FC0000 0x00300000>;
- read-only;
- };
- };
- };
-};
-
-&ssusb {
- status = "disabled";
-};
-
-&u3phy {
- status = "disabled";
-};
-
 &uart0 {
  pinctrl-names = "default";
  pinctrl-0 = <&uart0_pins>;
--- a/target/linux/mediatek/dts/mt7622-dlink-eagle-pro-ai-m32-a1.dts 2024-09-24 06:53:33.000000000 +0800
+++ b/target/linux/mediatek/dts/mt7622-dlink-eagle-pro-ai-m32-a1.dts 2025-02-20 11:27:42.130339133 +0800
@@ -53,10 +53,215 @@
  };
 };
 
+&pio {
+
+ //uart1 for mgm210p
+ uart1_pins: uart1-pins {
+ mux {
+ function = "uart";
+ groups = "uart1_0_tx_rx",
+ "uart1_0_rts_cts";
+ };
+ };
+
+ //uart2 for J1
+ uart2_pins: uart2-pins {
+ mux {
+ function = "uart";
+ groups = "uart2_1_tx_rx";
+ };
+ };
+
+ //uart3 for MT7915 bluetooth
+ uart3_pins: uart3-pins {
+ mux {
+ function = "uart";
+ groups = "uart3_1_tx_rx",
+ "uart3_1_rts_cts";
+ };
+ };
+
+ //i2c0 for J1
+ i2c0_pins: i2c-pins {
+ mux {
+ function = "i2c";
+ groups = "i2c0";
+ };
+ };
+
+};
+
+&snfi {
+        pinctrl-names = "default";
+        pinctrl-0 = <&serial_nand_pins>;
+        status = "okay";
+
+        snand: flash@0 {
+                compatible = "spi-nand";
+                mediatek,bmt-table-size = <0x1000>;
+                mediatek,bmt-v2;
+                nand-ecc-engine = <&snfi>;
+                reg = <0>;
+                spi-rx-bus-width = <4>;
+                spi-tx-bus-width = <4>;
+
+                partitions {
+                        compatible = "fixed-partitions";
+                        #address-cells = <1>;
+                        #size-cells = <1>;
+
+                        partition@0 {
+                                label = "Preloader";
+                                reg = <0x00000000 0x00080000>;
+                                read-only;
+                        };
+
+                        partition@80000 {
+                                label = "ATF";
+                                reg = <0x00080000 0x00040000>;
+                                read-only;
+                        };
+
+                        partition@C0000 {
+                                label = "Bootloader";
+                                reg = <0x000C0000 0x00080000>;
+                                read-only;
+                        };
+
+                        partition@140000 {
+                                label = "BootConfig";
+                                reg = <0x00140000 0x00040000>;
+                        };
+
+                        partition@180000 {
+                                label = "Odm";
+                                reg = <0x00180000 0x00040000>;
+                                read-only;
+                                odm_partition: nvmem-layout {
+                                        compatible = "fixed-layout";
+                                };
+                        };
+
+                        config1: partition@1C0000 {
+                                compatible = "nvmem-cells";
+                                label = "Config1";
+                                reg = <0x001C0000 0x00080000>;
+                                read-only;
+                        };
+
+                        partition@240000 {
+                                label = "Config2";
+                                reg = <0x00240000 0x00080000>;
+                                read-only;
+                        };
+
+                        partition@2C0000 {
+                                label = "Kernel1";
+                                reg = <0x002C0000 0x05A00000>;
+
+                                compatible = "denx,fit";
+                                openwrt,cmdline-match = "boot_part=Kernel1";
+                                partition@0 {
+                                        label = "kernel";
+                                        reg = <0x00000000 0x00800000>;
+                                };
+
+                                partition@800000 {
+                                        label = "ubi";
+                                        reg = <0x00800000 0x05200000>;
+                                };
+                        };
+
+                        factory: partition@5CC0000 {
+                                label = "Factory";
+                                reg = <0x05CC0000 0x00100000>;
+                                read-only;
+                        };
+                        partition@5DC0000 {
+                                label = "Mydlink";
+                                reg = <0x05DC0000 0x00200000>;
+                                read-only;
+                        };
+
+                        partition@5FC0000 {
+                                label = "Storage";
+                                reg = <0x05FC0000 0x00300000>;
+                                read-only;
+                        };
+                };
+        };
+};
+
 &odm_partition {
- macaddr_odm: macaddr@83 {
- compatible = "mac-base";
- reg = <0x83 0x6>;
- #nvmem-cell-cells = <1>;
+        macaddr_odm: macaddr@81 {
+                compatible = "mac-base";
+                reg = <0x81 0x6>;
+                #nvmem-cell-cells = <1>;
+        };
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>;
+
+ status = "okay";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>;
+
+ status = "okay";
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins>;
+
+ status = "okay";
+};
+
+&uart3 {
+
+ /* The btmtkuart driver uses "runtime" not "default"
+ * use runtime here so that there isn't a clash when
+ * btmtkuart requests "runtime" 
+ */
+
+ pinctrl-names = "runtime";
+ pinctrl-0 = <&uart3_pins>;
+
+ status = "okay";
+
+ bluetooth {
+ compatible = "mediatek,mt7915-bluetooth";
+
+ current-speed = <921600>;
+
+ pinctrl-names = "runtime";
+ pinctrl-0 = <&uart3_pins>;
+ not-stp;
+
+ /* The bootloader uses this as the "boot" gpio
+ * it doesn't appear to do anything when the system
+ * is running, but omitting it causes the driver to
+ * attempt the same using the serial lines as gpio 
+ * which causes pinctrl woe
+ */
+ boot-gpios=<&pio 61 GPIO_ACTIVE_LOW>;
+
+ // Reset is shared between wifi and bt.
+ // reset-gpios=<&gpio  GPIO_ACTIVE_LOW>;
+
+ nvmem-cells = <&macaddr_odm 0>;
+ nvmem-cell-names = "bd-address";
  };
 };
+
+&ssusb {
+        status = "okay";
+};
+
+&u3phy {
+        status = "okay";
+};
--- a/target/linux/mediatek/dts/mt7622-dlink-eagle-pro-ai-r32-a1.dts 2024-09-24 06:53:33.000000000 +0800
+++ b/target/linux/mediatek/dts/mt7622-dlink-eagle-pro-ai-r32-a1.dts 2025-02-04 11:47:22.836414440 +0800
@@ -68,11 +68,137 @@
  };
 };
 
+&snfi {
+        pinctrl-names = "default";
+        pinctrl-0 = <&serial_nand_pins>;
+        status = "okay";
+
+        snand: flash@0 {
+                compatible = "spi-nand";
+                mediatek,bmt-table-size = <0x1000>;
+                mediatek,bmt-v2;
+                nand-ecc-engine = <&snfi>;
+                reg = <0>;
+                spi-rx-bus-width = <4>;
+                spi-tx-bus-width = <4>;
+
+                partitions {
+                        compatible = "fixed-partitions";
+                        #address-cells = <1>;
+                        #size-cells = <1>;
+
+                        partition@0 {
+                                label = "Preloader";
+                                reg = <0x00000000 0x00080000>;
+                                read-only;
+                        };
+
+                        partition@80000 {
+                                label = "ATF";
+                                reg = <0x00080000 0x00040000>;
+                                read-only;
+                        };
+
+                        partition@C0000 {
+                                label = "Bootloader";
+                                reg = <0x000C0000 0x00080000>;
+                                read-only;
+                        };
+
+                        partition@140000 {
+                                label = "BootConfig";
+                                reg = <0x00140000 0x00040000>;
+                        };
+
+                        partition@180000 {
+                                label = "Odm";
+                                reg = <0x00180000 0x00040000>;
+                                read-only;
+                                odm_partition: nvmem-layout {
+                                        compatible = "fixed-layout";
+                                };
+                        };
+
+                        config1: partition@1C0000 {
+                                compatible = "nvmem-cells";
+                                label = "Config1";
+                                reg = <0x001C0000 0x00080000>;
+                                read-only;
+                        };
+
+                        partition@240000 {
+                                label = "Config2";
+                                reg = <0x00240000 0x00080000>;
+                                read-only;
+                        };
+
+                        partition@2C0000 {
+                                label = "Kernel1";
+                                reg = <0x002C0000 0x02D00000>;
+
+                                compatible = "denx,fit";
+                                openwrt,cmdline-match = "boot_part=Kernel1";
+                                partition@0 {
+                                        label = "kernel";
+                                        reg = <0x00000000 0x00800000>;
+                                };
+
+                                partition@800000 {
+                                        label = "ubi";
+                                        reg = <0x00800000 0x02500000>;
+                                };
+                        };
+
+                        partition@2FC0000 {
+                                label = "Kernel2";
+                                reg = <0x02FC0000 0x02D00000>;
+
+                                compatible = "denx,fit";
+                                openwrt,cmdline-match = "boot_part=Kernel2";
+                                partition@0 {
+                                        label = "kernel";
+                                        reg = <0x00000000 0x00800000>;
+                                };
+
+                                partition@800000 {
+                                        label = "ubi";
+                                        reg = <0x00800000 0x02500000>;
+                                };
+                        };
+
+                        factory: partition@5CC0000 {
+                                label = "Factory";
+                                reg = <0x05CC0000 0x00100000>;
+                                read-only;
+                        };
+
+                        partition@5DC0000 {
+                                label = "Mydlink";
+                                reg = <0x05DC0000 0x00200000>;
+                                read-only;
+                        };
+
+                        partition@5FC0000 {
+                                label = "Storage";
+                                reg = <0x05FC0000 0x00300000>;
+                                read-only;
+                        };
+                };
+        };
+};
+
 &odm_partition {
- macaddr_odm: macaddr@81 {
- compatible = "mac-base";
- reg = <0x81 0x6>;
- #nvmem-cell-cells = <1>;
- };
+        macaddr_odm: macaddr@81 {
+                compatible = "mac-base";
+                reg = <0x81 0x6>;
+                #nvmem-cell-cells = <1>;
+        };
 };
 
+&ssusb {
+        status = "disabled";
+};
+
+&u3phy {
+        status = "disabled";
+};

與官方的dts不同的是
1. M32有留了不少界面,經過驗證後就把定義寫進去。
2. 有一些IO定義與實際不符。
3. Partition將Kernel 1/2合併。
4. MAC Address的位置與官方的M32不同(但是與R32同…)
5. USB部份我有焊連接器與DC小板所以可以用。

與Unifi 6 BT那一篇不同的是
1. 經過驗證不需要加no-loopback-test那些
2. btmtkuart.c使用STP去包裝H4的Frame,而我實際驗證是MT7915AN回傳的不含STP。所以加了一些判斷跟修改source code。
3. MAC Address忘了先看,先用跟WIFI MAC。

2025-02-21 更新

後來想想還是寫進dts+btmtkuart.c裡…
實際上驗證要大約10秒才會正常,整體完成時間與寫進rc.local的差不多,都是在21~23秒時完成。

dts裡新增下面一行
                current-speed = <921600>;
                not-stp;
                delay-load-fw = <10000>;

btmtkuart.c裡新增下面

struct btmtkuart_dev新增

        int have_bdaddr;
        bdaddr_t bdaddr;
        bool is_ble_stp;
        int delay_load_fw;
...

static int btmtkuart_setup(struct hci_dev *hdev)新增

        if (status == BTMTK_WMT_PATCH_DONE) {
                bt_dev_info(hdev, "Firmware already downloaded");
                goto ignore_setup_fw;
        }

        /* Setup a firmware which the device definitely requires */
        if (bdev->delay_load_fw > 0) {
                bt_dev_info(hdev, "Delay patch firmware in %d ms.", bdev->delay_load_fw);
                msleep(bdev->delay_load_fw);
        }
        err = mtk_setup_firmware(hdev, bdev->data->fwname);
        if (err < 0)
...

static int btmtkuart_parse_dt(struct serdev_device *serdev)新增

        struct nvmem_cell *bdaddr_cell;
        int err, delayed_ms = 0;
                
        if (btmtkuart_is_standalone(bdev)) {
                of_property_read_u32(node, "current-speed", &speed);

                bdev->desired_speed = speed;

                bdev->is_ble_stp = true;
                if (of_property_read_bool(node, "not-stp"))
                        bdev->is_ble_stp = false;
        
                of_property_read_u32(node, "delay-load-fw", &delayed_ms);
                bdev->delay_load_fw = delayed_ms;
 
                bdev->vcc = devm_regulator_get(&serdev->dev, "vcc");

沒有留言:

張貼留言