From 3890c3f33c1abc8296544d5e60bc1c26fa858fc7 Mon Sep 17 00:00:00 2001 From: Vyacheslav Bocharov Date: Thu, 28 Jan 2021 17:34:36 +0300 Subject: [PATCH 01/11] Fix init_j100 gpio: add comments, add reset ZigBee module on start --- .../rootfs-overlay/usr/lib/jethome/init_j100 | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/buildroot-external/board/jethome/jethub-d1/rootfs-overlay/usr/lib/jethome/init_j100 b/buildroot-external/board/jethome/jethub-d1/rootfs-overlay/usr/lib/jethome/init_j100 index 18f9b153018..aa579b483e9 100755 --- a/buildroot-external/board/jethome/jethub-d1/rootfs-overlay/usr/lib/jethome/init_j100 +++ b/buildroot-external/board/jethome/jethub-d1/rootfs-overlay/usr/lib/jethome/init_j100 @@ -7,12 +7,12 @@ GPIO_ACTIVE_LOW=0 GPIO_ACTIVE_HIGH=1 configure_gpio() { - echo "Configure: gpio=${1}, direction=${2}, active_level=${3}" + echo "${0}: Configure: gpio=${1}, direction=${2}, active_level=${3}" if [ ! -d /sys/class/gpio/gpio${1} ]; then echo ${1} > /sys/class/gpio/export if [ ! -d /sys/class/gpio/gpio${1} ]; then - echo "** Failed to configure GPIO ${1}" + echo "${0}: *** Error: Failed to configure GPIO ${1}" exit 1 fi fi @@ -30,19 +30,19 @@ configure_gpio() { echo "${0}: Configure GPIOs ..." -# Discrete inputs +# Discrete inputs: 1, 2, 3, 4 configure_gpio "472" "${GPIO_DIRECTION_INPUT}" "${GPIO_ACTIVE_HIGH}" configure_gpio "471" "${GPIO_DIRECTION_INPUT}" "${GPIO_ACTIVE_HIGH}" configure_gpio "470" "${GPIO_DIRECTION_INPUT}" "${GPIO_ACTIVE_HIGH}" configure_gpio "469" "${GPIO_DIRECTION_INPUT}" "${GPIO_ACTIVE_HIGH}" -# Relays +# Relays: 1, 2, 3 configure_gpio "456" "${GPIO_DIRECTION_OUTPUT}" "${GPIO_ACTIVE_HIGH}" configure_gpio "455" "${GPIO_DIRECTION_OUTPUT}" "${GPIO_ACTIVE_HIGH}" configure_gpio "454" "${GPIO_DIRECTION_OUTPUT}" "${GPIO_ACTIVE_HIGH}" -# ZigBee module +# Zigbee module: RESET, BOOT configure_gpio "467" "${GPIO_DIRECTION_OUTPUT}" "${GPIO_ACTIVE_HIGH}" configure_gpio "462" "${GPIO_DIRECTION_OUTPUT}" "${GPIO_ACTIVE_HIGH}" -# LEDs +# LEDs: RED, GREEN configure_gpio "452" "${GPIO_DIRECTION_OUTPUT}" "${GPIO_ACTIVE_LOW}" configure_gpio "453" "${GPIO_DIRECTION_OUTPUT}" "${GPIO_ACTIVE_LOW}" # Button @@ -52,6 +52,12 @@ echo "${0}: Turn off LEDs ..." echo 0 > /sys/class/gpio/gpio452/value echo 0 > /sys/class/gpio/gpio453/value +echo "${0}: Reset Zigbee module ..." +echo 1 > /sys/class/gpio/gpio462/value +echo 1 > /sys/class/gpio/gpio467/value +sleep 1 +echo 0 > /sys/class/gpio/gpio467/value + echo "${0}: Configure 1-Wire ..." modprobe ds2482 if [ ${?} != 0 ]; then From 46ae3d4966a5691e8531d262d8e3bd17bea435a8 Mon Sep 17 00:00:00 2001 From: Vyacheslav Bocharov Date: Fri, 29 Jan 2021 22:19:11 +0300 Subject: [PATCH 02/11] Fix env partition to internal --- buildroot-external/board/jethome/jethub-d1/meta | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildroot-external/board/jethome/jethub-d1/meta b/buildroot-external/board/jethome/jethub-d1/meta index ad9d5565f93..1a0682060d1 100644 --- a/buildroot-external/board/jethome/jethub-d1/meta +++ b/buildroot-external/board/jethome/jethub-d1/meta @@ -5,7 +5,7 @@ BOOTLOADER=uboot KERNEL_FILE=Image BOOT_SYS=mbr BOOT_SPL=false -BOOT_ENV_SIZE=0x2000 +BOOT_ENV_SIZE=0x10000 SUPERVISOR_MACHINE=odroid-c2 #SUPERVISOR_MACHINE=jethub-d1 TODO: add supervisor SUPERVISOR_ARCH=aarch64 From ac2a7beb078befcbe876679518e8e0481b519223 Mon Sep 17 00:00:00 2001 From: Vyacheslav Bocharov Date: Fri, 29 Jan 2021 22:19:54 +0300 Subject: [PATCH 03/11] Fix platform.conf generation Move common files to up folder --- .../board/jethome/jethub-d1/hassos-hook.sh | 20 +++++++++---------- .../configs/jethub_d1_defconfig | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/buildroot-external/board/jethome/jethub-d1/hassos-hook.sh b/buildroot-external/board/jethome/jethub-d1/hassos-hook.sh index 3e076f6cfda..849cb08d7bc 100755 --- a/buildroot-external/board/jethome/jethub-d1/hassos-hook.sh +++ b/buildroot-external/board/jethome/jethub-d1/hassos-hook.sh @@ -52,14 +52,14 @@ function create_disk_image() { function create_platform_conf () { echo 'Platform:0x0811' > ${BINARIES_DIR}/platform.conf - echo 'DDRLoad:0xfffc0000' > ${BINARIES_DIR}/platform.conf - echo 'DDRRun:0xfffc0000' > ${BINARIES_DIR}/platform.conf - echo 'UbootLoad:0x200c000' > ${BINARIES_DIR}/platform.conf - echo 'UbootRun:0xfffc0000' > ${BINARIES_DIR}/platform.conf - echo 'Control0=0xfffc0000:0x000000b1' > ${BINARIES_DIR}/platform.conf - echo 'Control1=0xfffc0000:0x00005183' > ${BINARIES_DIR}/platform.conf - echo 'Encrypt_reg:0xff800228' > ${BINARIES_DIR}/platform.conf - echo 'bl2ParaAddr=0xfffcc000' > ${BINARIES_DIR}/platform.conf + echo 'DDRLoad:0xfffc0000' >> ${BINARIES_DIR}/platform.conf + echo 'DDRRun:0xfffc0000' >> ${BINARIES_DIR}/platform.conf + echo 'UbootLoad:0x200c000' >> ${BINARIES_DIR}/platform.conf + echo 'UbootRun:0xfffc0000' >> ${BINARIES_DIR}/platform.conf + echo 'Control0=0xfffc0000:0x000000b1' >> ${BINARIES_DIR}/platform.conf + echo 'Control1=0xfffc0000:0x00005183' >> ${BINARIES_DIR}/platform.conf + echo 'Encrypt_reg:0xff800228' >> ${BINARIES_DIR}/platform.conf + echo 'bl2ParaAddr=0xfffcc000' >> ${BINARIES_DIR}/platform.conf } function _create_disk_aml() { @@ -93,8 +93,8 @@ function _create_disk_aml() { create_platform_conf - cc -o $BINARIES_DIR/dtbTool $BOARD_DIR/bin/dtbTool.c + cc -o $BINARIES_DIR/dtbTool $BOARD_DIR/../src/dtbTool.c $BINARIES_DIR/dtbTool -o $BINARIES_DIR/_aml_dtb.PARTITION ${BINARIES_DIR}/ - $BOARD_DIR/bin/aml_image_v2_packer -r ${BINARIES_DIR}/image.cfg ${BINARIES_DIR}/ $hdd_img + $BOARD_DIR/../bin/aml_image_v2_packer -r ${BINARIES_DIR}/image.cfg ${BINARIES_DIR}/ $hdd_img echo "Image created" } diff --git a/buildroot-external/configs/jethub_d1_defconfig b/buildroot-external/configs/jethub_d1_defconfig index 4795fc5eb64..f45470e082b 100644 --- a/buildroot-external/configs/jethub_d1_defconfig +++ b/buildroot-external/configs/jethub_d1_defconfig @@ -21,7 +21,7 @@ BR2_TARGET_GENERIC_ISSUE="Welcome to Home Assistant" BR2_INIT_SYSTEMD=y BR2_TARGET_GENERIC_GETTY_PORT="tty1" # BR2_TARGET_GENERIC_REMOUNT_ROOTFS_RW is not set -BR2_ROOTFS_OVERLAY="$(BR2_EXTERNAL_HASSOS_PATH)/rootfs-overlay $(BR2_EXTERNAL_HASSOS_PATH)/board/jethome/jethub-d1/rootfs-overlay" +BR2_ROOTFS_OVERLAY="$(BR2_EXTERNAL_HASSOS_PATH)/rootfs-overlay $(BR2_EXTERNAL_HASSOS_PATH)/board/jethome/rootfs-overlay $(BR2_EXTERNAL_HASSOS_PATH)/board/jethome/jethub-d1/rootfs-overlay" BR2_ROOTFS_POST_BUILD_SCRIPT="$(BR2_EXTERNAL_HASSOS_PATH)/scripts/post-build.sh" BR2_ROOTFS_POST_IMAGE_SCRIPT="$(BR2_EXTERNAL_HASSOS_PATH)/scripts/post-image.sh" BR2_ROOTFS_POST_SCRIPT_ARGS="$(BR2_EXTERNAL_HASSOS_PATH)/board/jethome/jethub-d1 $(BR2_EXTERNAL_HASSOS_PATH)/board/jethome/jethub-d1/hassos-hook.sh" @@ -32,7 +32,7 @@ BR2_LINUX_KERNEL_CUSTOM_REPO_VERSION="5.7" BR2_LINUX_KERNEL_VERSION="5.7" BR2_LINUX_KERNEL_PATCH="$(BR2_EXTERNAL_HASSOS_PATH)/board/jethome/patches/kernel/arm-64-current" BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y -BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="$(BR2_EXTERNAL_HASSOS_PATH)/board/jethome/jethub-d1/kernel.config" +BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="$(BR2_EXTERNAL_HASSOS_PATH)/board/jethome/kernel.config" BR2_LINUX_KERNEL_CONFIG_FRAGMENT_FILES="$(BR2_EXTERNAL_HASSOS_PATH)/kernel/hassos.config $(BR2_EXTERNAL_HASSOS_PATH)/kernel/docker.config $(BR2_EXTERNAL_HASSOS_PATH)/kernel/device-support.config" # BR2_LINUX_KERNEL_LZ4 is not set BR2_LINUX_KERNEL_LZO=y From d197ba5ee74504f5be51313d1c3e58e1aca702f7 Mon Sep 17 00:00:00 2001 From: Vyacheslav Bocharov Date: Fri, 29 Jan 2021 22:21:56 +0300 Subject: [PATCH 04/11] Split dts patch to j80 and j100 patches Add to dts efusekey --- ...ome-Makefile-dts-arm64-add-dts-files.patch | 19 + ...e-jethub-j80-dts-arm64-add-dts-files.patch | 374 ++++++++++++++++ ...-jethub-j100-dts-arm64-add-dts-files.patch | 401 ++++++++++++++++++ 3 files changed, 794 insertions(+) create mode 100644 buildroot-external/board/jethome/patches/kernel/arm-64-current/0004-jethome-Makefile-dts-arm64-add-dts-files.patch create mode 100644 buildroot-external/board/jethome/patches/kernel/arm-64-current/0005-jethome-jethub-j80-dts-arm64-add-dts-files.patch create mode 100644 buildroot-external/board/jethome/patches/kernel/arm-64-current/0006-jethome-jethub-j100-dts-arm64-add-dts-files.patch diff --git a/buildroot-external/board/jethome/patches/kernel/arm-64-current/0004-jethome-Makefile-dts-arm64-add-dts-files.patch b/buildroot-external/board/jethome/patches/kernel/arm-64-current/0004-jethome-Makefile-dts-arm64-add-dts-files.patch new file mode 100644 index 00000000000..6072e2ae268 --- /dev/null +++ b/buildroot-external/board/jethome/patches/kernel/arm-64-current/0004-jethome-Makefile-dts-arm64-add-dts-files.patch @@ -0,0 +1,19 @@ +diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile +index 666b1544c..903b9e1ab 100644 +--- a/arch/arm64/boot/dts/amlogic/Makefile ++++ b/arch/arm64/boot/dts/amlogic/Makefile +@@ -1,5 +1,6 @@ + # SPDX-License-Identifier: GPL-2.0 + dtb-$(CONFIG_ARCH_MESON) += meson-axg-s400.dtb ++dtb-$(CONFIG_ARCH_MESON) += meson-axg-jethome-jethub-j100.dtb + dtb-$(CONFIG_ARCH_MESON) += meson-g12a-sei510.dtb + dtb-$(CONFIG_ARCH_MESON) += meson-g12a-u200.dtb + dtb-$(CONFIG_ARCH_MESON) += meson-g12a-x96-max.dtb +@@ -35,6 +36,7 @@ dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s805x-p241.dtb + dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905w-p281.dtb + dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905w-tx3-mini.dtb + dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-libretech-pc.dtb ++dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905w-jethome-jethub-j80.dtb + dtb-$(CONFIG_ARCH_MESON) += meson-gxm-khadas-vim2.dtb + dtb-$(CONFIG_ARCH_MESON) += meson-gxm-nexbox-a1.dtb + dtb-$(CONFIG_ARCH_MESON) += meson-gxm-q200.dtb diff --git a/buildroot-external/board/jethome/patches/kernel/arm-64-current/0005-jethome-jethub-j80-dts-arm64-add-dts-files.patch b/buildroot-external/board/jethome/patches/kernel/arm-64-current/0005-jethome-jethub-j80-dts-arm64-add-dts-files.patch new file mode 100644 index 00000000000..00ba701be90 --- /dev/null +++ b/buildroot-external/board/jethome/patches/kernel/arm-64-current/0005-jethome-jethub-j80-dts-arm64-add-dts-files.patch @@ -0,0 +1,374 @@ +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905w-jethome-jethub-j80.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905w-jethome-jethub-j80.dts +new file mode 100644 +index 000000000..cf0e6e742 +--- /dev/null ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905w-jethome-jethub-j80.dts +@@ -0,0 +1,368 @@ ++ ++/dts-v1/; ++ ++#include "meson-gxl-s905x.dtsi" ++#include "meson-gx-p23x-q20x.dtsi" ++ ++/ { ++ compatible = "amlogic,p281", "amlogic,s905w", "amlogic,meson-gxl"; ++ model = "JetHome JetHub J80"; ++ amlogic-dt-id = "gxl_j80_1g"; ++ ++ /* 1G RAM */ ++ memory@0 { ++ device_type = "memory"; ++ reg = <0x0 0x0 0x0 0x40000000>; ++ }; ++ partitions: partitions{ ++ parts = <8>; ++ part-0 = <&boot>; ++ part-1 = <&bootstate>; ++ part-2 = <&kernela>; ++ part-3 = <&systema>; ++ part-4 = <&kernelb>; ++ part-5 = <&systemb>; ++ part-6 = <&overlay>; ++ part-7 = <&data>; ++ ++ boot:boot { ++ pname = "boot"; ++ size = <0x0 0x4000000>; ++ mask = <1>; ++ }; ++ bootstate:bootstate { ++ pname = "bootstate"; ++ size = <0x0 0x800000>; ++ mask = <4>; ++ }; ++ kernela:kernela { ++ pname = "kernela"; ++ size = <0x0 0x4000000>; ++ mask = <4>; ++ }; ++ systema:systema { ++ pname = "systema"; ++ size = <0x0 0x10000000>; ++ mask = <4>; ++ }; ++ kernelb:kernelb { ++ pname = "kernelb"; ++ size = <0x0 0x4000000>; ++ mask = <4>; ++ }; ++ systemb:systemb { ++ pname = "systemb"; ++ size = <0x0 0x10000000>; ++ mask = <4>; ++ }; ++ overlay:overlay { ++ pname = "overlay"; ++ size = <0x0 0x8000000>; ++ mask = <4>; ++ }; ++ data:data { ++ pname = "data"; ++ size = <0xffffffff 0xffffffff>; ++ mask = <4>; ++ }; ++ }; ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ linux,cma { ++ compatible = "shared-dma-pool"; ++ reusable; size = <0x0 0x400000>; ++ alignment = <0x0 0x400000>; ++ linux,cma-default; ++ }; ++ }; ++ aliases { ++ serial0 = &uart_AO; /* Console */ ++ serial1 = &uart_A; /* Bluetooth */ ++ serial2 = &uart_AO_B; /* Wireless module 1 */ ++ serial3 = &uart_C; /* Wireless module 2 */ ++ ethernet0 = ðmac; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ vddio_ao18: regulator-vddio_ao18 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VDDIO_AO18"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ }; ++ ++ vddio_boot: regulator-vddio_boot { ++ compatible = "regulator-fixed"; ++ regulator-name = "VDDIO_BOOT"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ }; ++ ++ vddao_3v3: regulator-vddao_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VDDAO_3V3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ vcc_3v3: regulator-vcc_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VCC_3V3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ emmc_pwrseq: emmc-pwrseq { ++ compatible = "mmc-pwrseq-emmc"; ++ reset-gpios = <&gpio BOOT_9 GPIO_ACTIVE_LOW>; ++ }; ++ ++ wifi32k: wifi32k { ++ compatible = "pwm-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <32768>; ++ pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */ ++ }; ++ ++ sdio_pwrseq: sdio-pwrseq { ++ compatible = "mmc-pwrseq-simple"; ++ reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>; ++ clocks = <&wifi32k>; ++ clock-names = "ext_clock"; ++ }; ++ ++ efusekey: efusekey { ++ keynum = <5>; ++ key0 = <&key_0>; ++ key1 = <&key_1>; ++ key2 = <&key_2>; ++ key3 = <&key_3>; ++ key4 = <&key_4>; ++ ++ key_0: key_0 { ++ keyname = "mac"; ++ offset = <0>; ++ size = <6>; ++ }; ++ key_1: key_1 { ++ keyname = "mac_bt"; ++ offset = <6>; ++ size = <6>; ++ }; ++ key_2: key_2 { ++ keyname = "mac_wifi"; ++ offset = <12>; ++ size = <6>; ++ }; ++ key_3: key_3 { ++ keyname = "usid"; ++ offset = <18>; ++ size = <32>; ++ }; ++ key_4: key_4 { ++ keyname = "serial"; ++ offset = <50>; ++ size = <32>; ++ }; ++ }; //End efusekey ++ ++ unifykey { ++ compatible = "amlogic, unifykey"; ++ status = "ok"; ++ unifykey-num = <6>; ++ unifykey-index-0 = <&keysn_0>; ++ unifykey-index-1 = <&keysn_1>; ++ unifykey-index-2 = <&keysn_2>; ++ unifykey-index-3 = <&keysn_3>; ++ unifykey-index-4 = <&keysn_4>; ++ unifykey-index-5 = <&keysn_5>; ++ ++ keysn_0: key_0 { ++ key-name = "usid"; ++ key-device = "efuse"; ++ key-permit = "read","write"; ++ }; ++ keysn_1: key_1 { ++ key-name = "mac"; ++ key-device = "efuse"; ++ key-permit = "read","write"; ++ }; ++ keysn_2: key_2 { ++ key-name = "mac_bt"; ++ key-device = "normal"; ++ key-permit = "read","write","del"; ++ key-type = "mac"; ++ }; ++ keysn_3: key_3 { ++ key-name = "mac_wifi"; ++ key-device = "normal"; ++ key-permit = "read","write","del"; ++ key-type = "mac"; ++ }; ++ keysn_4: key_4 { ++ key-name = "serial"; ++ key-device = "efuse"; ++ key-permit = "read","write"; ++ }; ++ keysn_5:key_5 { ++ key-name = "deviceid"; ++ key-device = "normal"; ++ key-permit = "read","write","del"; ++ }; ++ }; //End unifykey ++}; ++ ++&efuse { ++ status = "okay"; ++ compatible = "amlogic,meson-gxbb-efuse", "amlogic, efuse"; ++ read_cmd = <0x82000030>; ++ write_cmd = <0x82000031>; ++ get_max_cmd = <0x82000033>; ++ key = <&efusekey>; ++ clock-names = "efuse_clk"; ++}; ++ ++&pwm_ef { ++ status = "okay"; ++ pinctrl-0 = <&pwm_e_pins>; ++ pinctrl-names = "default"; ++ clocks = <&clkc CLKID_FCLK_DIV4>; ++ clock-names = "clkin0"; ++}; ++ ++&saradc { ++ status = "okay"; ++ vref-supply = <&vddio_ao18>; ++}; ++ ++/* Wireless SDIO Module */ ++&sd_emmc_a { ++ status = "okay"; ++ pinctrl-0 = <&sdio_pins>; ++ pinctrl-1 = <&sdio_clk_gate_pins>; ++ pinctrl-names = "default", "clk-gate"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ bus-width = <4>; ++ cap-sd-highspeed; ++ max-frequency = <50000000>; ++ ++ non-removable; ++ disable-wp; ++ ++ /* WiFi firmware requires power to be kept while in suspend */ ++ keep-power-in-suspend; ++ ++ mmc-pwrseq = <&sdio_pwrseq>; ++ ++ vmmc-supply = <&vddao_3v3>; ++ vqmmc-supply = <&vddio_boot>; ++}; ++ ++/* SD card */ ++&sd_emmc_b { ++ status = "okay"; ++ pinctrl-0 = <&sdcard_pins>; ++ pinctrl-1 = <&sdcard_clk_gate_pins>; ++ pinctrl-names = "default", "clk-gate"; ++ ++ bus-width = <4>; ++ cap-sd-highspeed; ++ max-frequency = <50000000>; ++ disable-wp; ++ ++ cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_LOW>; ++ ++ vmmc-supply = <&vddao_3v3>; ++ vqmmc-supply = <&vddio_boot>; ++}; ++ ++/* eMMC */ ++&sd_emmc_c { ++ status = "okay"; ++ pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>; ++ pinctrl-1 = <&emmc_clk_gate_pins>; ++ pinctrl-names = "default", "clk-gate"; ++ ++ bus-width = <8>; ++ cap-mmc-highspeed; ++ max-frequency = <200000000>; ++ non-removable; ++ disable-wp; ++ mmc-ddr-1_8v; ++ mmc-hs200-1_8v; ++ ++ mmc-pwrseq = <&emmc_pwrseq>; ++ vmmc-supply = <&vcc_3v3>; ++ vqmmc-supply = <&vddio_boot>; ++}; ++ ++/* Console UART */ ++&uart_AO { ++ status = "okay"; ++ pinctrl-0 = <&uart_ao_a_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&usb0 { ++ status = "okay"; ++}; ++ ++/* S905X only has access to its internal PHY */ ++ðmac { ++ status = "okay"; ++ phy-mode = "rmii"; ++ phy-handle = <&internal_phy>; ++}; ++ ++&internal_phy { ++ status = "okay"; ++ pinctrl-0 = <ð_link_led_pins>, <ð_act_led_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&uart_A { ++ status = "okay"; ++ pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; ++ pinctrl-names = "default"; ++ // uart-has-rtscts; ++ ++ /* ++ bluetooth { ++ compatible = "realtek,rtl8822cs-bt"; ++ enable-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; ++ }; ++ */ ++}; ++ ++&uart_C { ++ status = "okay"; ++ pinctrl-0 = <&uart_c_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&uart_AO_B { ++ status = "okay"; ++ pinctrl-0 = <&uart_ao_b_pins>, <&uart_ao_b_cts_rts_pins>; ++ pinctrl-names = "default"; ++ uart-has-rtscts; ++}; ++ ++&i2c_B { ++ status = "okay"; ++ pinctrl-names="default"; ++ pinctrl-0=<&i2c_b_pins>; ++ ++ pcf8563: pcf8563@51 { ++ compatible = "nxp,pcf8563"; ++ reg = <0x51>; ++ status = "okay"; ++ }; ++}; ++ diff --git a/buildroot-external/board/jethome/patches/kernel/arm-64-current/0006-jethome-jethub-j100-dts-arm64-add-dts-files.patch b/buildroot-external/board/jethome/patches/kernel/arm-64-current/0006-jethome-jethub-j100-dts-arm64-add-dts-files.patch new file mode 100644 index 00000000000..a43dd8c1a02 --- /dev/null +++ b/buildroot-external/board/jethome/patches/kernel/arm-64-current/0006-jethome-jethub-j100-dts-arm64-add-dts-files.patch @@ -0,0 +1,401 @@ +diff --git a/arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j100.dts b/arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j100.dts +new file mode 100644 +index 000000000..8e6bd30ca +--- /dev/null ++++ b/arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j100.dts +@@ -0,0 +1,395 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright (c) 2017 Amlogic, Inc. All rights reserved. ++ */ ++ ++/dts-v1/; ++ ++#include "meson-axg.dtsi" ++#include ++ ++/ { ++ compatible = "jethome,j100", "amlogic,a113d", "amlogic,meson-axg"; ++ model = "JetHome JetHub J100 Compatible Board"; ++ amlogic-dt-id = "jethome_j100_v1"; ++ ++ aliases { ++ serial0 = &uart_AO; /* Console */ ++ serial1 = &uart_B; /* Bluetooth */ ++ serial2 = &uart_AO_B; /* External UART (Wireless Module) */ ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ /* 512MB RAM */ ++ memory@0 { ++ device_type = "memory"; ++ reg = <0x0 0x0 0x0 0x20000000>; ++ }; ++ ++ emmc_pwrseq: emmc-pwrseq { ++ compatible = "mmc-pwrseq-emmc"; ++ reset-gpios = <&gpio BOOT_9 GPIO_ACTIVE_LOW>; ++ }; ++ ++ vcc_3v3: regulator-vcc_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VCC_3V3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ vin-supply = <&vddao_3v3>; ++ regulator-always-on; ++ }; ++ ++ vcc_5v: regulator-vcc_5v { ++ compatible = "regulator-fixed"; ++ regulator-name = "VCC5V"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-always-on; ++ }; ++ ++ vddao_3v3: regulator-vddao_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VDDAO_3V3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ vin-supply = <&vcc_5v>; ++ regulator-always-on; ++ }; ++ ++ vddio_ao18: regulator-vddio_ao18 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VDDIO_AO18"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ vin-supply = <&vddao_3v3>; ++ regulator-always-on; ++ }; ++ ++ vddio_boot: regulator-vddio_boot { ++ compatible = "regulator-fixed"; ++ regulator-name = "VDDIO_BOOT"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ vin-supply = <&vddao_3v3>; ++ regulator-always-on; ++ }; ++ ++ usb_pwr: regulator-usb_pwr { ++ compatible = "regulator-fixed"; ++ regulator-name = "USB_PWR"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ vin-supply = <&vcc_5v>; ++ regulator-always-on; ++ }; ++ ++ sdio_pwrseq: sdio-pwrseq { ++ compatible = "mmc-pwrseq-simple"; ++ reset-gpios = <&gpio GPIOX_7 GPIO_ACTIVE_LOW>; ++ clocks = <&wifi32k>; ++ clock-names = "ext_clock"; ++ }; ++ ++ wifi32k: wifi32k { ++ compatible = "pwm-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <32768>; ++ pwms = <&pwm_ab 0 30518 0>; /* PWM_A at 32.768KHz */ ++ }; ++ partitions: partitions{ ++ parts = <8>; ++ part-0 = <&boot>; ++ part-1 = <&bootstate>; ++ part-2 = <&kernela>; ++ part-3 = <&systema>; ++ part-4 = <&kernelb>; ++ part-5 = <&systemb>; ++ part-6 = <&overlay>; ++ part-7 = <&data>; ++ ++ boot:boot { ++ pname = "boot"; ++ size = <0x0 0x4000000>; ++ mask = <1>; ++ }; ++ bootstate:bootstate { ++ pname = "bootstate"; ++ size = <0x0 0x800000>; ++ mask = <4>; ++ }; ++ kernela:kernela { ++ pname = "kernela"; ++ size = <0x0 0x4000000>; ++ mask = <4>; ++ }; ++ systema:systema { ++ pname = "systema"; ++ size = <0x0 0x10000000>; ++ mask = <4>; ++ }; ++ kernelb:kernelb { ++ pname = "kernelb"; ++ size = <0x0 0x4000000>; ++ mask = <4>; ++ }; ++ systemb:systemb { ++ pname = "systemb"; ++ size = <0x0 0x10000000>; ++ mask = <4>; ++ }; ++ overlay:overlay { ++ pname = "overlay"; ++ size = <0x0 0x8000000>; ++ mask = <4>; ++ }; ++ data:data { ++ pname = "data"; ++ size = <0xffffffff 0xffffffff>; ++ mask = <4>; ++ }; ++ }; ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ linux,cma { ++ compatible = "shared-dma-pool"; ++ reusable; size = <0x0 0x400000>; ++ alignment = <0x0 0x400000>; ++ linux,cma-default; ++ }; ++ }; ++ // It is necessary only as key map to read efuse values from nvmem from Armbian OS. ++ efusekey:efusekey{ ++ keynum = <5>; ++ key0 = <&key_0>; ++ key1 = <&key_1>; ++ key2 = <&key_2>; ++ key3 = <&key_3>; ++ key4 = <&key_4>; ++ ++ key_0:key_0{ ++ keyname = "mac"; ++ offset = <0>; ++ size = <6>; ++ }; ++ key_1:key_1{ ++ keyname = "mac_bt"; ++ offset = <6>; ++ size = <6>; ++ }; ++ key_2:key_2{ ++ keyname = "mac_wifi"; ++ offset = <12>; ++ size = <6>; ++ }; ++ key_3:key_3{ ++ keyname = "usid"; ++ offset = <18>; ++ size = <32>; ++ }; ++ key_4: key_4 { ++ keyname = "serial"; ++ offset = <50>; ++ size = <32>; ++ }; ++ }; //End efusekey ++ ++ unifykey { ++ compatible = "amlogic, unifykey"; ++ status = "ok"; ++ unifykey-num = <6>; ++ unifykey-index-0 = <&keysn_0>; ++ unifykey-index-1 = <&keysn_1>; ++ unifykey-index-2 = <&keysn_2>; ++ unifykey-index-3 = <&keysn_3>; ++ unifykey-index-4 = <&keysn_4>; ++ unifykey-index-5 = <&keysn_5>; ++ ++ keysn_0: key_0 { ++ key-name = "usid"; ++ key-device = "normal"; ++ key-permit = "read"; ++ }; ++ keysn_1: key_1 { ++ key-name = "mac"; ++ key-device = "normal"; ++ key-permit = "read"; ++ }; ++ keysn_2: key_2 { ++ key-name = "mac_bt"; ++ key-device = "normal"; ++ key-permit = "read","write","del"; ++ key-type = "mac"; ++ }; ++ keysn_3: key_3 { ++ key-name = "mac_wifi"; ++ key-device = "normal"; ++ key-permit = "read","write","del"; ++ key-type = "mac"; ++ }; ++ keysn_4: key_4 { ++ key-name = "serial"; ++ key-device = "normal"; ++ key-permit = "read"; ++ }; ++ keysn_5:key_5 { ++ key-name = "deviceid"; ++ key-device = "normal"; ++ key-permit = "read","write","del"; ++ }; ++ }; //End unifykey ++}; ++ ++&efuse { ++ status = "okay"; ++ compatible = "amlogic,meson-gxbb-efuse", "amlogic, efuse"; ++ read_cmd = <0x82000030>; ++ write_cmd = <0x82000031>; ++ get_max_cmd = <0x82000033>; ++ key = <&efusekey>; ++ clock-names = "efuse_clk"; ++}; ++ ++ðmac { ++ status = "okay"; ++ pinctrl-0 = <ð_rmii_x_pins>; ++ pinctrl-names = "default"; ++ phy-handle = <ð_phy0>; ++ phy-mode = "rmii"; ++ internal_phy=<0>; ++ interrupts = ; ++ ++ mdio { ++ compatible = "snps,dwmac-mdio"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ /* ICPlus IP101A/G Ethernet PHY (vendor_id=0x0243, model_id=0x0c54) */ ++ eth_phy0: ethernet-phy@0 { ++ compatible = "ethernet-phy-id0243.0c54"; ++ max-speed = <100>; ++ reg = <0>; ++ }; ++ }; ++}; ++ ++/* Internal I2C bus (on CPU module) */ ++&i2c1 { ++ status = "okay"; ++ pinctrl-0 = <&i2c1_z_pins>; ++ pinctrl-names = "default"; ++ ++ /* RTC */ ++ pcf8563: pcf8563@51 { ++ compatible = "nxp,pcf8563"; ++ reg = <0x51>; ++ status = "okay"; ++ }; ++}; ++ ++/* Peripheral I2C bus (on motherboard) */ ++&i2c_AO { ++ status = "okay"; ++ pinctrl-0 = <&i2c_ao_sck_10_pins>, <&i2c_ao_sda_11_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&pwm_ab { ++ status = "okay"; ++ pinctrl-0 = <&pwm_a_x20_pins>; ++ pinctrl-names = "default"; ++}; ++ ++/* wifi module */ ++&sd_emmc_b { ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ pinctrl-0 = <&sdio_pins>; ++ pinctrl-1 = <&sdio_clk_gate_pins>; ++ pinctrl-names = "default", "clk-gate"; ++ ++ bus-width = <4>; ++ cap-sd-highspeed; ++ sd-uhs-sdr104; ++ max-frequency = <200000000>; ++ non-removable; ++ disable-wp; ++ ++ mmc-pwrseq = <&sdio_pwrseq>; ++ ++ vmmc-supply = <&vddao_3v3>; ++ vqmmc-supply = <&vddio_boot>; ++ ++ brcmf: wifi@1 { ++ reg = <1>; ++ compatible = "brcm,bcm4329-fmac"; ++ }; ++}; ++ ++/* emmc storage */ ++&sd_emmc_c { ++ status = "okay"; ++ pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>; ++ pinctrl-1 = <&emmc_clk_gate_pins>; ++ pinctrl-names = "default", "clk-gate"; ++ ++ bus-width = <8>; ++ cap-mmc-highspeed; ++ max-frequency = <200000000>; ++ non-removable; ++ disable-wp; ++ mmc-ddr-1_8v; ++ mmc-hs200-1_8v; ++ ++ mmc-pwrseq = <&emmc_pwrseq>; ++ ++ vmmc-supply = <&vcc_3v3>; ++ vqmmc-supply = <&vddio_boot>; ++}; ++ ++/* UART Bluetooth */ ++&uart_B { ++ status = "okay"; ++ pinctrl-0 = <&uart_b_z_pins>, <&uart_b_z_cts_rts_pins>; ++ pinctrl-names = "default"; ++ uart-has-rtscts; ++ ++ bluetooth { ++ compatible = "brcm,bcm43438-bt"; ++ shutdown-gpios = <&gpio GPIOZ_7 GPIO_ACTIVE_HIGH>; ++ }; ++}; ++ ++/* UART Console */ ++&uart_AO { ++ status = "okay"; ++ pinctrl-0 = <&uart_ao_a_pins>; ++ pinctrl-names = "default"; ++}; ++ ++/* UART Wireless module */ ++&uart_AO_B { ++ status = "okay"; ++ pinctrl-0 = <&uart_ao_b_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&usb0 { ++ status = "okay"; ++ phy-supply = <&usb_pwr>; ++}; ++ ++&spicc1 { ++ status = "okay"; ++}; ++ ++&audio { ++ status = "disabled"; ++}; From 3d53beff52964977ee93c45fe52f64f3b88c034e Mon Sep 17 00:00:00 2001 From: Vyacheslav Bocharov Date: Sat, 30 Jan 2021 17:25:39 +0300 Subject: [PATCH 05/11] Add firmware for RTL8822 WiFi --- .../usr/lib/firmware/rtlbt/ReadMe.txt | 2 ++ .../usr/lib/firmware/rtlbt/rtl8822cs_config | Bin 0 -> 73 bytes .../usr/lib/firmware/rtlbt/rtl8822cs_fw | Bin 0 -> 44628 bytes 3 files changed, 2 insertions(+) create mode 100644 buildroot-external/board/jethome/jethub-h1/rootfs-overlay/usr/lib/firmware/rtlbt/ReadMe.txt create mode 100644 buildroot-external/board/jethome/jethub-h1/rootfs-overlay/usr/lib/firmware/rtlbt/rtl8822cs_config create mode 100644 buildroot-external/board/jethome/jethub-h1/rootfs-overlay/usr/lib/firmware/rtlbt/rtl8822cs_fw diff --git a/buildroot-external/board/jethome/jethub-h1/rootfs-overlay/usr/lib/firmware/rtlbt/ReadMe.txt b/buildroot-external/board/jethome/jethub-h1/rootfs-overlay/usr/lib/firmware/rtlbt/ReadMe.txt new file mode 100644 index 00000000000..cfa919b72e4 --- /dev/null +++ b/buildroot-external/board/jethome/jethub-h1/rootfs-overlay/usr/lib/firmware/rtlbt/ReadMe.txt @@ -0,0 +1,2 @@ +Files rtl8822cs_config, rtl8822cs_fw are not from Linux_BT_UART_v3.10_20200301_8822CS_BTCOEX_20200103-1717. +They are from stb project. \ No newline at end of file diff --git a/buildroot-external/board/jethome/jethub-h1/rootfs-overlay/usr/lib/firmware/rtlbt/rtl8822cs_config b/buildroot-external/board/jethome/jethub-h1/rootfs-overlay/usr/lib/firmware/rtlbt/rtl8822cs_config new file mode 100644 index 0000000000000000000000000000000000000000..25aab2711b22e7bc74e8bb44f17c487f7e0455ee GIT binary patch literal 73 zcmWGtt=#U+z{4QG6u`g`aP*brL+QWk;~AH5?_*?=lHAS6XnTN>MSvlJkwJi);Xg|( Z12e;aAaD@i*5EKO0JH!9Kf=h!1OOq`7v literal 0 HcmV?d00001 diff --git a/buildroot-external/board/jethome/jethub-h1/rootfs-overlay/usr/lib/firmware/rtlbt/rtl8822cs_fw b/buildroot-external/board/jethome/jethub-h1/rootfs-overlay/usr/lib/firmware/rtlbt/rtl8822cs_fw new file mode 100644 index 0000000000000000000000000000000000000000..b9b361995d0d5fe67d5b706a450cea0f855bfd60 GIT binary patch literal 44628 zcmeFa33wD$x;K8Rw{-SOhb8Py61EU9WI;!9ECMP^hfQ=4ai%(6OVnhc5IEv#;WN|`w8af!jSv3FOTh*Ne2j|}TX72ag z?|J^obLv!`K6Tdjyyrdd`JJ~G*sRh@TUq&6SAU|{GLC7Oj{WuKO=GHO3~lTGq>KH%kbDJJ=8_-~||S&ADJ?sjFWi+e}l@_)|mNvCTo^E1SN()xu z=@~rPo0w$s$t|V^laD#&QzoC-#G!rC8iXUN6Az{N&F#W_qiT6Mm+H2QmkZ&~-_6Uv zfKO#dhspdKCi&eO)R#BOI@}xK3~&i>NpNxKM{99h)==joLA~D;oOwp?FFR#!XEtVg zBN6So-z3jO9td&#wJfgGa7=%+zfY{~zBILa^S>&Fpqq&g<^&vc_#Otk)3vyeJPN>Tyx2N1R{C7xH82>!@WvVYb+N z^o|ZGPtO;+iu29w)j?*XFlvLkp!-q=+Acw9J9p%J9!(W<#9PI>zg!+NOA2Z_H7K!g zgmb8EI`4NT8F@OH1Mf*&gWqj5bsRVwh`d-n-4aA?*8fa zFqeC--PExv#EDPYdFPKhxbf%O3mbOV6*kCqrqI4KVu4sN)>T&UT1Q!dF*o<%jH1TR z$QaHA8^SM>KMrOqEFneag-L67Fa^@zJx5%lW?ET z$}*B}VKyDl&BplQ#U}MF>N^%qyS%P@MW)!#XO7f+hL1v@xZVh*HJU=MbB(par3HIm z3#RAHs!8!%@@JkAJi5%X8Xf39J}1E^coG)tt?`Ws2U*5nZq`Uh+d&+O*@%v*pASz2 z-65ava2zx1AGn*!Sz0sQK7K{2n0udA%vlj9>i7vOa>R)%5=7>h#-pBB`d1Y2nf}0D zjq?V+tVXjUQPizS7r7N$QRie8qxhlz9eY37tLKOK-JNUpx;x+A8<-rJy!L|5IglUV z7b0u+3X!+>ULKg<;O;zBBSco$a8Buh)Ul@U5Mm`Ym?N8Nsza^|obyS~@`AD^-sucg zhpbKR?P@(ZN33ll;H@2~3-yaK_Ky<9>+O~fo!*@BA3wCTGv^SSF6S}(jJlWE*G&393m1QiQ9+8ZGjf+X*%hWe@AxntM;?P#z4vZqS7WKuS%Mwcyj>R7pcIfPE zL5|2dbgct@`qrs+7%9tiQf}~Tm%D3FMfsI}mFA2AErwPa|I9XZkLA1;oWwXT*(ZAR zS>~oBAItdgX7i~;f43yN1n=H(b#NbM6`?tCOTzm2bsT!gP_}MGoICi5m?3~crJgjzOqQTBk=1Aeiy!mA%&?+kzWu ztIHKTE4_&)v{{@h@#HA`EB>=Dvx=E= zXOi5!%0Bo*HuMMCLw@`33jLWQDIRlVt|#^6a(i-X@}_;EZpYft`i7@!QjQLOssD)$ z4RXzpE&Pd14RUpj-4c#Jsmn!JU3DPrqR9YNl?S~n)H*8;6CZZ-f-Zmr>MTjbaH6+pw^7z zgFmEp9`f7A8#&3nFDbk>{8)p$BPpC@Gunyk3N%Yd%Nvo#TSK-Ceko()pbZjIe6eOs zHgi2~ci5KJzuGp#CU>TJx|f?ocjruxzC0s%G-AA6mp98Ef11^rf|{VFoD;e7jj?emb|x|+4N zgzS6qt7O}2e*(NNxg!CspyQvAk~?bcbsfgd>q*>@kv@ z(J)SEj`0n8m*NODw>hO?UR9i!Ri(F5oGgiRa6F50n3z0KhIu%_abJkbIoHkyxvCVa z=vz>$&G`Ywj6UlJehy=031m#>TXg_b3o%`{`LeeY58_60%cg)IT=a^a$GmwM h||H$2g9(~vx zIqLb+uFDIzAD;YvyE*a!MtPS9J=;FB$~a&p0cQi3CL#={@) zAOCue4P)6WM3#DI(MWzJ!Pah{We*2kLGYm9k>E0WMbMZ7dAwGiqnn`3O~-rMOls{h zQij5_2Krc2B1*KP$s8$cV$Ol6rvWt_yMmj|q0PjWUO9~BVWNo`eGskCTt;#u(Gtmy zBsUU05Iy}2KG6%!5kxyQXKQ@s_URsGTm5sAvAUhrq1Cn1YW0>yp#%r@)?%fn&Fv=0 zQ51({JNfb+&$PX(_r4L-TTH?EXA>NYJBS{pdmT@`etN0H)bU1#sY4Aj1(%%`Ag@h> zEH*7)O@riJLxXr}QH{oF2{DHzOT2XNYE{;t-@41Vqj~uKks1x=Z|2lwikJRv^#q@_ zX@cL{LUU7T%UHjBN%nS^%a_i0pJ|dWJ?WJ%?}ag&J?eMxUi{5oj zkA6-)!>$A-SDs^6nkUoR;GM~s$*z?=ijOwut?e#m%%MFlU8{zgD zF@E8$!u>p5spm0>g#zVE%cEvnton6<;u4GLTLf~#QXiReRrFPwh^J4rK zx}&T-u0hV&JU;C#Hv?_aK5WrdtA2|P`H_6K8}aCk z!TuqjyEUM@n!Q_t`Vv#{?sK5KFwtF&cjGxzaBJ|nry$dME6*;K@DwtIVw4BETc8u$ zI{SfhXn68xo@x8S==@QTPOExcuY;!Zsmjl74DWKD*9)2C*#R z6y$X0WDeJvpWlFW+rs?7%Ozo?;IM>El5oLrTj5&$=NabF=C~dROJSIB@%=htNYo-Qu8iAWEo}?sZY?X(FuhF*~)~ z_q-2#e`*)l+YA}UcDyX zZ3y}It4w+GwrHH|r&u5*Y;OBvgj5|AcTrvil2}lVI*8j)>M-Sbz0_q;y%Y>=8z8L> z(p$RYhJfeCHc7WJ zuq{`Tf@(hhST3vnp4`TO(%cTc;S0O{mYd z3tQbggM-I!6+!I_66hkki&Uoa`nU)_FNWQ4`iA-ue{ zokmhpSO=Oz3~=C~7{z};*idKzzS*AjkQZb0Z$N%#Sv*PU9op zCtlj>(SW|=AmP325ik7+dR144iBIwG^kRmSj)bejOiCC<)g4iqls2Vn@L4_3AtG6L3@#iWld9(rZK+^_k|#%U(I-!=9MT z7E6ob=%R79BhK6jvDA9wB>JB82&hF$Rs!@1m0pb2kT%O4dETSp&5`Fka>luyl>62{ z(I+dl|K@woD(`K@d&xby#omjRJrQ-3p+%O0G`l5c8kMogIpZ3nAeTuJQ}N%t`#aSA zG#t^y93L+|)x=8y&+{Ftnk=NlxV*=^s>LY1-yt_~($1#mJMQ$!r*4v-YI*ZginO{# zzWkiGrpbLZrQ$jKKGml?p>IXMc)xPZyke?^G^uEFm{eVKi;uH3o@UOpCE};0?_agv z)UfIlFFn(8W5WxlmPkKqncR3|!@5(xQwC{rqY#l=8cqq3l`YV2wdAPn=c)@0$jbAJ zr+)7&ZMnh!<5L+<5iutCA3im~{|KBM5%JEB77_0(a`xwQ5Vr$y$N7Jx#FbjcAnq8% z9dk`wi&Ks)ZHaSYHv@G@@o`T1@&l-;*}u8DALIwUb9jSzh@2U^uGP&qIps@MtO81# z;;}w;s5)9(aya3^_rD1I9Y zR|rS)Ajx^LHNc~~Ex zM|y*+uv`>EY+0Ip22x|v6G|E=4_0e;5KUve@R?d@{m*@%ZEV zR)tQE#&1+5yHRKOMf9e0{$p#Qk{YEi1mlm#Z=6*Bmn*|6vGTVGTdDjxwi$NI#hG>? z_&pa^)W}%~*4X1W8n*~rZ_bmHwxD;Pn4zYPUPf6Y>{^f(QY)EJmbNYqWr?edm1D54 z%%f>3Yd2a;J=CJmN(UF&X9q3qPk=K*N_1+^SlZLBNl6dNp_KX|C1X!Ya>n`b>+H!} zlGZ0;Z4yUoA&@-&?n!SwPO>~t5oi*ACd z?(OL(&$)NC+Z+FAI)5Wp%Cy4t7J1sW)&#pIOesLK#wMWzPyqaqJ>{TjPIQ;Rs!0vYY$v+<7`4Lu!KkQpBr9^t(VJ}rmCn}{|?!Whp zIkNk0Xs93y8y7!ub)fY#?@aG8ug^R4kDu)=-D|LjnBBvnwP!@{vYx&uzCf$;K)#Om z1gWlWWrcYE!R|_Kx8>rj-3NA?BNyJD*;ciii>~XFFKqifu>0NK6vC8(8!413DTqo6 zmim$I?h4C=*>2Jh9B|M4%pCbmVC0@Ew`LE^V|f$WpKN1pXlkSD+2ZS_a?62k$f*l< zTG4~EY?hsgwsL!pZKl2C%y{Um>ff}!n)#|3dQaE+r#};RjrcxyKj}&HIeT#j z)m28SiFS>WDpP9P4Hy$W9cY1V` z#vf1JlCnM-Kk!_Pco*a$;*OAZbdtDL=(9%CNi5^wC`g9NZ?~ad z@xG-^(J*jR;zzwwB8_{JhiI;d@pXl3hf_|(ofJBa*+Qpb6m#m2>soJ3({D=I42f{r z>in7K46T9M>2_|`blkJr;o#**f+-PJb>zG|GDu8`a0`Zt20Y6V9ei$qQAD|`=82Gy zs~#4oWb$bV%CBi+lHv~&v06ZEji^l}oTb5J(WLy+Pwc1o!$n^4jp7A< zFz%My-4R|Kti;ue8PT|H{7~HG*#i+KqI6Y($Uv*^=t;iY1?_=!q@(VF;CKhxs7i3@ zBjHtr#FZoVxA^X5&)A*5+zW{16e@-7?-WTL;c#v^{3l zbsKZTuV7?WUXYfpw8CcJw$Pn59EJ|F&n!Y|?T zsZ5}X+zz7cY4~RgibeXBle$TVhB+oY_B*^`Lw5zWoV!+V)O8#|olC+a@$Ra^BWN3H zmsC*usBHDkc<4YzIJ#$BLTAPg;SC$8Z{R4WxYi3H|1{4b#HEzB1g}JA2W*Me|pThDoo-7(2*#IP9~L{A~0+vt7koCVE*zg_2{96jqM$fY(%tAb05Xm9gVA(x6&J)J*yOd_nz3=m*P^K6v(kJ zdQ$ux<~{ez$-cPkAC7`o$!?8qw`<8kD6$gbOnmBvQlz22Od zEk-9-%hF2uW2r~S_mNvscF1i>za_r7#5Ed{xcsslso9%dPi>XlnzTjSiuPDWGAuYm zDEDGAYR#n6_S}n06bUrZV2&i{<%}zN3AzkWw8~-cw{NO#q<+i$uoi1bj}cN^x*~6; zVW;^q`@+3?$Tf!6yY~v0 z${L`oNoaLf?b+)&iWTa<4)6AhBrQ5UMS;oS5f_s9J)U_A(u`VUlfot5^q>1>ataxU5O-&iV^RA6 zplg<$E>l+MM&$GZ>@1kD&#(@Z?y;+qd*Y(=*4~+#=4s+1G?&tRO*;SA;10qC!H?SE z7Jdh~2Jk3qQ|M|t@AD+&7@>E#!(%`mK9p6?SUzc$JvKg-{nMx(LgilAW$Wo7W+Q!2 za-;B5ZdP0lCnX(Zl`P}a(Yn?ophe`%Gd;#k>=3x#22d`MSD<>cPs zl{Mm(vh-5Zv9zOXS#f!$PjIfYW3MygmWe6)U)s%)t-FT%CYFZysG= zSFYQY>wC)eb|ucQaNq4ph|)oPA3BKZLkDULAHrJr2;2!c>^@IvOI$n#^9TN>?$@#6 z{YExze-fL%pJ%u4@5k=gpTX|jKa|bbZ)P+1XR}%R$FkY`bD3p-9xK^j$mZ<7iOt>5 z3yhg&Ac^G(!W1@dzrg12pUxKSpTX|hZ($4f&trG*U&!v+zleQr{}Q%nzsT<0zmzT6 zU(W8|FR}0MU(SB8edm^psRsChFv zBNI3ZXZ6M@#{I@3#^Tq~Bge+k{l3^U{VurG-+$4aFr}N#D$1Ub!!aRY$|&*?SIZKo zuqT{FedAJE*)zs-T4wG~_dm$j8Of(~fAQ-+=}=zogeg7cK@1~nQ_4)V3LIbO98YFu zKXtd8I3nn%>8F<0DHbl=FXG!S6L-D@H?85dvdr4Lq zW>F~_qx)Xqxqu^}J!G2y7w+I@#b?s)p!*|mSTEyOggCG_ zvIFCw1~@FoqEMan-)NnO$38i-8wm~yZi+WDX-WjvK!vpB(Ogfu@7<28o=O zu|G*jI|uDqQ(34Sl;-UbhelE?|rs&){g58xJK~oM8O%JDv$v*6{oEBdG_;lctsWl1yS^0HA$n9su zT5dKFav48eALIK}kD-MsPHqbFr96e21^Jq)G;5-7`gToKvNZv9=bVHB;Glt$n~mU` z>i$2*RTPs(Z9(`?+QX;4d`hRZhVRh^n(=;8PP~8V%iIc}aHKe-161U7(}|@K(|>~# zm1o;o7xaM{zZ`o6s4#sd%>hkgf%T-GkKqeY7Q%+{$Uipsv-0Kk+j#E5cu_l2^I)Qw z!jJUDpAK~X$P>>GSMDD7==hmGLJ^yXIq7PEuy8gw~{uD*9A=?^{-GhNWG%NF%ak zzaAK!<59x+GQu*%cpU@Ig_DHl=Q|93`4hN|6=P#ammc~BeJTA?$8~9|v_PEPT%hz{ zwC!VZ6>|d7+=SLzMu@WN^Pm^!Bj-K#5k6LK3YDB0?pwS)lmB?fyu$ULudXwHk+d?^ zI=JDPx``c$xq}*X$63bV(fX6Rjmil6M8BEmO%1=p_~K^Fx$s`c`yGL+PZd@NyQS*( zq=rv-G_{`sW!%4gPP=w2C}jJ>PY7%Fw7pjnqw*7dwbcQ;u|yq}ft= z4zX4Ojx{sYCvRs?Ani^i`&R+?Exe4Hxa7jRpp0ES;AJybO=1$|u?{n)F1pw5#@x}i zo|l0nZ&cfebq%WOCywkIQ3X9lm%d6b@;v8EK+7aS;&~8w4$g^L7|1iRiDV!O>7`>D z%S6X98Ahxd(KX1S0|rK)`Gc;s6#=X~+xXHN+AVtC_Cx>F=9$g2ns>j~TvOa!ZC~j- z-0Xd?vE^V(L(5OviapHv0RL}oyLP8mRvhREpWW>)dV6;`+_p1ejPrGQ|7#tFT=`9I z+4%Fz8q7z`zu}~}CzZZF&Q^VXrY-Xo$@ZLGMOCbNXS}_&Ft;Pg_T(#L?G}VT{n&N_llKQ45`_2PJuinv6bY%6iBj;B?sJC*<=$EMne)6Vf%+;-=M?50IMQ)X zkva0hn~MwY$Ug$S$dQhH*lC3n_GYp7OUN6MH*1>ZW=&3xUuf3cFwWQ3q#`d#XEFwI z^9cVm@1I>lS9*n^br?ADi=J_p235wL04C34#B~lvUVLk@mt=|rpf(AUG=!g4Ge{Xz zoKtuF&#wM{5&G3}mj+krl`(2)P2f3)@D_6jZ!<@)L?`c2RwTc8%g#Bv2Cf4Q5O0rR zl8C1fPL1%kGvZ<+Wr0h{Rq57r-{@N6(aKwx!i|R z8^qsnnCn)aVi|c~ud@?hjmw}2Ow3EM{J}Jo{Df)y=BIpVwb6^#L9LE?zF0@qG_>C)PhTo z$ehNfSB(_Y7i+EGtul&Jc*u#K@8rlCGWdTHU+mUYvy985pWI4%H0^yk;*(oh z#-B#Jw~ghot4HYhW;0*vW{z}zX;EX_s$HoSM>^izmEPF6PcD4FN{cuFYG8j z=&W7s+2v8^`DY5XD`~z=5z|-xz)C%`B>QHiM{e%vk-PZxhvr*1ZQnWFII5tLs|dVR z&?tY(0Y|dw6jG74h9)RTz(AzZdux_EvcQv4l_Mrp-Dn+y{FZv2_ROw*pg_AqCr)w9 z360De&!+=#uW;btaJ;$p%%+zq?V(EALt|-wqQ;>0$ILSU!scRSAm=bCk?)6H3u89+ zgg`MkpAqdV#(wgzY|Svl>FY3=>2x1Y=ENV7h-Mu&KSJ2OKTyBL z`HcRmQ%3&-a1xxHv2E-l(K9!6rea(xFTZ+}m+wEu%kel1GsdjTWM;-g-eg0~BN>B& z8qdsZc7B;@J{zB9{$L7k&Nil*&CFyLexHUo@c)1?mSS#_CnGL=rpC#`Z|?3i^9|&G zoo1d${#R+{3Giiv=aP@`@#G^s2fm2#apWU>Ecpl@17AS+Xz~$0ihP7;!#5*53%>Y= zG;=2TzgNp7ei|(!!bebigbybl;ltpY5k8dS|0c~mg!~WE%!A2)Kg~P{zJTxy@)16e ze1s2xZ$@~3@)6z-zBo6{oKF6nG_#5Pk~DJ~d;#G+`3O%XAK@wR%?MA1FW#AEP9pz~ zG;<>Px2KsC;0p+kCm-QP@(~^f-;8hr`3Tp;7vs{*I`R!^W-a;pG_wZ2fN+j{gk#NQ z7WC9NEP{u1bG52p2|s~p*7g6AMKtgSep$#^+hq31BR8}8(oL*fWDybJKm2m30ZTXK zejx5gGmYVvGP2q5MjS~Y%E5PczxLF`Ty4P?c zDGYC*rpmLKC2>4UL3xTbzt&IJd}rwZ?XzF?(=vXgR38_w7Cw^R!|!JJhvAQazXtwr z_%q-SgCBrD6uu092z&wlVE9{;^FhbR4}J#xqwoj9Uk85x{CV*E!#@naAN)1&)8Ws6 zZ-O6yp9Wus&%+nsr^5e8lMgyZ`tXzCFM^*0|0w)K`0L;&z@G;{9{yqYM)+&s$HAWg z-vB=VUk_h~uY)hZ*V6A?KIj;~!{_LC_>6w%(6$=ti*Ki888o~3I<#Dh@T*Z;ru!}5 zLd%S3nFB2k??cP1_!?S1+J~0cftHQcpyk26w9Nh+w44Px&W0NWHyUmX+*r82G|tTb zHI3h{tJ0QemunY;#)pH(ZP(B^==%{29q{s(*llK}%ck}Z9A?>QPlQLu%oL27Q(t4u zu$9_pF=poLmTQmeDztw4vp;R2ZJSYa++W3pvJaf&)Z& zbSZc5=%w8BTOQzAA1>#n&o{88c}7;x9$@zh35HMRB^fR~${VWhHW?De_A`v(XslBj z6z8U!Zps^L&fvf4fBC1s{PnA^8K>17jPZ%dDXFNkM&tPLCvzDq8vCdokN@&Nns1A+ zLMw`%r!B;~8@LASG!^;_vEC~57vWkIy-vpcWWRd75%)Lx+9Fm@TSShYGhNkl&a}*< zo-;K@NKUF&&YFr%ZILINVrNZP;i;@?Ov6~LZO2Bh<8Y7jxE|8_REOk9Wz(qWDc#Y? zZM1(3u4B}zQpRiUl@P4f6rAc6x!If&WV%FF%d2FL6e981i}WFRW*OBLn*l-OH-aS42_K{rv)vD#FWJ z>|i9=AXfn+Q{kF{9S-a;Y}HB?*va53bQ@m;a$3bri?sH2OaKyC`4zaAzOvPiq4$#E z{-<9oy2^vDVT3eH~j&SJPL=M(gK)m5zO5WGk#SQP##SOi#E-vF5U0nZf z=;A2N)GCveZx})Q&pUt+1ir@-O3K2XH}s(5?-GFs6FXhdRmArx6Up{#3QY1?l$rE} zhoJ{Ke1l0oCmNKp{&#eEMx-~U&$&`+>wZY9KeYqg-T$HLo&Gy|ytwP6)i<5kx)XE_ zU0$LOy$8K+OqWL`AzdD=UZYrrs4j121J(d=*(gs}*}&2P$NJ;+#ZtTJ==b_)^-}o> ziY{+4w0h%}yYEA*H&)T=&G(pEO`8%|P8PF$>k4Cq0Nz zdbcRYQjnBJzBtheYAkD3>>&+!215{NN1V^J!SSyCV9poUcPmjy6?dp#;7h3 z+R;y-9c`voRkTwIzl)7E8VkP!pQ7;~M0J9?Sj?zSa2I%7Y^~R;7tBJeUcI0>suvt_ z9lhX?s9sQad~m~HymhT!F#TKfg2_?6U}97+n5gIlaSis>3sOBct!IjEqXuie`ukO# z@lRf6ay`PSUb>^{N{uvjQy(26ujmLj&I?0b$oN6 z<16_a9p8)|9pCNH@lF3*9iMZRUF!Jm!KdE71N+9e;uP+SZ_O%#woih#Z#SK?rc(fu z8ytrwH)yhO;tg8XI?Pnq;W;#?U{d3e5O!MMx~E`q{t@U-js%w;5)Qeb`>WhV*ST*M z*JyHbLE~eT9Trswn4|PLY5&IdX#eEP3E!&yBi&y@>u|iqNpw}Ue?xn;e*^u7R{in7 zWsRc$>xUSBc740{FBQM5+COHi0gckULp*E%9PvXF9PKT<`{THtaZ5Zh9bwzLG<|ey z|ENAN1v!6HA4s&^SNjEQH^vF^{TLtkw{)HSCyaA-y!<`ApwUO?PgNdG*WS@F7-b&{ zNA*Y>pzBiyRX=En>Ia2B`oUu82hBbD!CMsl;7xQw6unTW=m#fRN7S3~9McbugMM%r zp55EVz`lUcJk&S*I@-a3eYAu95&K&0Am5`Mq}F0Kx?bBp!%>e{e+gS6&=KCcgUKau zG@ns_QC}7vax=y@N^0-a)2#GY^X^Q9C5CK=9r$ z>|L&dEt0rwy|Sy72Kg1UHLr8Hf;>+3JZ7KQ{Fogy7TvQPX&HnO0hDf2e;&vul$fWP zyovWE@;EgI&2K7Z!9kb>lU$rb$I~1Lou@&wdK+j*-;)z=T#(^`A-C=s)$)e?DJ}vrR-b zQ4MI{u|jmwm)7r(k5k4@Y>xbA^r7aim_BsAEf0N2-t(t2eR9O*;1!zX8mw|3#bxg;)L@O;+RvT#tI9ij?`9G(0QFlBRPBHF@u1DB54NfGM zT$Hd1L0Eg=RY+_NLg${laWc}IpAYwJI|Ve-@}PhcMMGp+$<{s zMz{}VnOoNlJ2%)_hfK5;GOfzbaJCHNV~v|+duAKqU+raG#Q2=kEi=_F38I{)&_9~yg3ag%EeP@K9j%v6l^F#S~E4I^DSW9xR@p2N@lJ~$TlDN)SE)`u*9BDC!p>@3-Cl9`0IC)^IBw0~+EZxDnW&|>n(MbCjK(3t{=*xDNwQ!xool9H# z`}+GUPFb9fxAgNbKV@*j`anydv(lX#N*JGpcDsagGrV$2=DW)2nBLQ^RK{4jZhuaz z?8i}gKSFuWz75-17*`g^)aAIRHHSJ{lA@?7T`MOg98{#l%D5Z@q)9?dsZzGeci(zh zO>-*R_EX5C6X0Uw2l6u7_{L1kZGQ6sVXHxU$fd(M7_LGJ4)X*1@eyILnQaL0S2Vhk zqHBHq@fr4qloKQd@HUzyg>CdM?kePBM>=se}@ec!ci z=LW6vo4VGF;Yp>SJ_oI|J+46r_TovOep;)f*8m#KLwi%2d=!By1qbA$929n2LaABj zcH4K)-2Ke%J-b_W%Y|;>6H6|HJBadJVJ)w=eoUuB<)d7Uno?1rvrSpat7pl6!!I&??y`~O_EnWpp?_77<7`g6!0W1%;q zIhL_X&Lpf9Y-<`FiB*CW3fk@30rBf zf+Exz{pDT_tW?2X8n^-MrI9}2eHCLwvIWVwIQjc`ZIr!@IG{86|F=;#_J71i8R>3F zhtmcdWexC2C$JR$5xB!}EpRlhuC-AHjaQ#>O?`9zlF9=hEf9)^ch}#X?vgJ)R>vkhdouypnWn}#d>k6_F(A9mGBVOMP`U*^$`=Omo( zd{58E-8ZU%BP$a}n6uelz-Ps5u6b0OYq0&ZB4%@Km|}A+5o@EE%{4u66fs+CfvEkp zG`=73t%qv9X>%>P;oEJl5tr@lWo9EDvj%fyJ=%b1jq0rE=6Yy*o3=DNrkSeO*kGlO|;`M@60st1wON~M!ac~<@_YS zuy446Tauvpn=J%|7w7|%Y$;re# zZpapzVfXYCoVY=*BNgQT3!y>d#ikMUBYfuV0xV}Rn{a*=&NI**VV#l{Z3kNON*ZcE zsFK>{Yv7;0X{$~>QNuw~7*`f+4_YG=ZO}XvlkH!`T(%DGa)`+^N0BT_GU?yiw0j-v z*|gS!ibcDFuoN|*wGnx9%NnCL?HYP)+SOmzrrq8?HtlMAY})O)#-`ow9-DSGNPEa{ zYcSi@&YlY4_B1Y}!2pZCbBQy9beCuT8u1e}PRqJ8at76>D}6 z;A*jz;hJQd(_`6Af@Qmf$aP)KK3KNRx5Vx zo>J`EJq0bO+$>|SmpLDYT|4<2yLOL#!>-*UkbkeWYxgknX10e^9oP!fHFoV1t;?0s zNNYQ>r2@M)oFl$f!!uX>Nh$gUf6W{5R(qc}IEPV*Z9G|8FYLhz2wJz8O+C$G;c$-i ze!t-Dmbh844zgHizRz#8Y8*oIVx>$ZryF=Jo^iest0d+S4r{>u7otb!ffI3(p|u1) z`(haQH)fUAxrq0*YmVRQWe#Yr9VLFZmq~NNno&SaO0)Xd*t-+_={K;kcfdOd{3X@X z_&Im?8+PuYH(+0HA8hLp$2sBIQ$+W#c_v<{!`&^7wY%!!cf0D^M^EgvwP((mj8dco zhvpRdiu{vb58&OdSKLu+doc@pb-@pUi8(ibYZ`Nm8w@$|n|rP7jYql1NSO*3&4QIZ zvhEeLvIk27Epce;UMqXOCncGUWJ#jQ7>yFWlFYLidug=(i0QRS_e=C>hNCqHtv#N8 z1AFOkG1}~!pwcVRK8*z*9MLw71EO=1QHd@UJ;70-<_RamK4xB(97%;`MxAvQYLO*9 z&kuyeI72xTqFF3Qw4x?YlXpAKhF4e~yQ0k_&0evhBc-`~sxp^rq_17(u2jrtgDaQv zg;k@hQ+!E58%}&ULpP%ZZdRm9X8R8EP_Bx$NSUjp8?kdlt2$llM5LvIrh-FiLKn^I z11fLji>q$4-hdW_O-7uGn20&{h0qAhu(`f&SdwC$Lo8w~&DONHJkGbdb{z6B>bt9w z#ry5c6_oFy&?w~$Ngz_~$yQ1*1pTOYKjmdZ=&eu*RnK@E-WoH`GtRfa@zSQ-70eM*X~N z1XK1EW4fF1^@5vQW;s7%By(c@4EvVj{5tH7P@BkKq@hJJDo3FPU%RT^uep!9=ek2~ zm%DehJ_5hF!nrszp>YnXk6BAL;)J6RAe|2<4fdH^lKDZ={!n#4xGMdjLoDitB=iHM z5@m#v28#NDq|L8gy&4|ub71{X^^4IT=>lktK=uA+Tc|SOQ2$WHlJ`(h1l@DxF?~V}x^mmr_u={*}%X*wwPS{ zCe|sWca5!$f#6Z>e)r|`wDymc|Eo8nI@qIGN;;XoKxCUI5P3wgEEI_R2>15^T|-(7 z20I9JR#6J(WDaf+aQZ@tKC6PSM?9Z7+}>f%aZWk3c#vq9f9K5uPAchj_%FipbxF zN&Mf7!zJ9Ug2Vk(#o-Enh+=~gu3&``PB>h`-4YI$@V11*CA=-+a0zcqI9$Tp5)PN} zwuHkaye;8y32#d{T*B894wvw?gu^9#E#YtpUz-k}@U?`)H6xsGxP+@!aJY9yakzJ= zI9$Tj5)PMewS>bZTrJ^n%?MX;xN%V&t|5xU)kkr-2v=~p2qzq_8R3M(6|^c2SI|Up zxSWc^H6xsGxMochBW*53JqRORtm!sP*ZgN$6tfEa-3;LG<^g}#Uk^N=PSU=54gQWr zjKD4q{PO=E{x&o4<74@(FD@~L0Zh^U>|qrLSpDC|0p6ocE?BI+oeefrA1^kPOpDBcaDI-PrC#eCrWc08)XQ2M|27sK8x0@qvQzxP0~@>PvRkPHz5&hkC~ zBIs44_r4h)f6q7b<7k-ri~nByesA=;825|)>h(U{-{)7aOMFY}#ZzsOsqVIjsGPWN ziJv!hQM`0f* z7nsC-bt-;wIpu+K6>G8Iw+P|12bkB-B#(sOh4g-c`LY4}>BoSF+zPp282mLT+kEU7 zmLvYpu~!&@PTC5eu#NBj7V-w(KL^_oZB(w0czGqB!>|`Y7|B5h??iouCSWfeb;yHF z;FCvr`QK2_WTg35>|Y&29g&trdK@=YiU(Ij@o{^jR` zyC6T2{!qdkR*m)6-#Z^nXSj55eX)xgJpZe(i&PdW2c=0`cQ_mD4myQe9pn@Wfj$m) z0%SN<2dA@p-3*qzVA(=2FHW_}dvuI;u*blZ=;Y3KIeFxZIz>mPJBqVI*cC84b#^H@FlSXwD&9|Z>6CGZU4aO#rYs@3 zldE|0s&3XQw-1X4Pbvn2 zTR!ip6s*`-=TlzR>G8_2PBHUr9M3wjhudlMlAJU1jDVe3D!XEVMk)V#$Vrq>OlBon z5^KX{I3ra~xV4P)1Np3ki+~Kzhs<}Hb>Ub7a%&~vg2U)FAkO{gpjUPw?W;b zd~=Rk21?@>|KPjdiM~sD$KIuH?sPBH*>l_L&U53E&3q5W)(9(4D#n(y_eMSeI{lGY z6;YkY4k*db>+D1;2l|{`BlUs^lGp|9B5s$ z#~iVEUjRo>gZzr`M(ja1LBfBU|o;z!em6)O2LW};?yWg-#o_u)fw@XRZ~Yd zYG#Y?bdxQNRw1lEo(28idb?pmX2Ybj!XeHvvT^!(dDq;aek09*WV74SA$7=a#pS{x zNyyMjS0))Y42Is5A3vx;tnu1kIgc~DuDbKak(Q8nNI#zT%ZZ9)?=&~(oCRwux{a}K zj;J=D1?*)I9Yd%%coe+-`~i*Zn#{>Y@O3-fzfIxfG`I!e#Y^$*2HiY>v8M7J=F(t2 zA+)~*v?WFyIFu!HzrDPr*P3TS4&hp0TPIT^0b!w_K@317PY2x_m0x=KkZn9C6Ak?2 z7EaMMoPd>6`J zydyrdT=`CpK2zt{HwZ6R<9xWvPv>Esi2d=eVp!osST@4x_tyLSpoRPMc~P`*3^)9J zPXeE-@JSwf@%qev969{i74Dxz4ine!iyVHX4{~_tHOOJ&Kg1`0_c`!Bcc|E5tsvPpq-MV#mFldciz8j&v1(6#CIrYS3FD)dhL?jOXV zpNA~<72F(@FP4U)Q79jLK;7f)mXff`DQruER$-*2zyE8826p>oFKDwl9lF==OJb7= z+AU~In__rCYH?tiFY$Dq;SzJGDF6`&%RR9#m#OC&h@ZZOwkJ%N9JrwGtqZ-V ziD>Y>vjJ8;uks(};Q2(9XSHCCEOo~#YXNg)dVnM&nun%iA262xXOKxRzs)J~Pz=NK zzYPmd?J)!U2gJJ@fQ1jBT}URq6>`W@gsbiGufxJqUVX9fw*w1L`NXjB0??$ec!AUO zuy#>ZAl}H2QhGnrPN?iG=$5klWl=4

-rAmCEQ-Tq_}Dmq(wBt%LDY5q*kp?e8mw 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 literal 0 HcmV?d00001 From 598f564368bc2d277f9767be39a4efeac1f34e93 Mon Sep 17 00:00:00 2001 From: Vyacheslav Bocharov Date: Sat, 30 Jan 2021 17:26:51 +0300 Subject: [PATCH 06/11] Add package rth-hciattach: bluetooth helper for Realtek chipset --- .../package/rtk-hciattach/Config.in | 6 + .../package/rtk-hciattach/rtk-hciattach.mk | 19 + .../package/rtk-hciattach/src/Makefile | 19 + .../package/rtk-hciattach/src/hciattach.c | 631 +++++ .../package/rtk-hciattach/src/hciattach.h | 188 ++ .../package/rtk-hciattach/src/hciattach_h4.c | 295 +++ .../package/rtk-hciattach/src/hciattach_h4.h | 7 + .../package/rtk-hciattach/src/hciattach_rtk.c | 2040 +++++++++++++++++ .../package/rtk-hciattach/src/rtb_fwc.c | 1233 ++++++++++ .../package/rtk-hciattach/src/rtb_fwc.h | 75 + 10 files changed, 4513 insertions(+) create mode 100644 buildroot-external/package/rtk-hciattach/Config.in create mode 100644 buildroot-external/package/rtk-hciattach/rtk-hciattach.mk create mode 100644 buildroot-external/package/rtk-hciattach/src/Makefile create mode 100644 buildroot-external/package/rtk-hciattach/src/hciattach.c create mode 100644 buildroot-external/package/rtk-hciattach/src/hciattach.h create mode 100644 buildroot-external/package/rtk-hciattach/src/hciattach_h4.c create mode 100644 buildroot-external/package/rtk-hciattach/src/hciattach_h4.h create mode 100644 buildroot-external/package/rtk-hciattach/src/hciattach_rtk.c create mode 100644 buildroot-external/package/rtk-hciattach/src/rtb_fwc.c create mode 100644 buildroot-external/package/rtk-hciattach/src/rtb_fwc.h diff --git a/buildroot-external/package/rtk-hciattach/Config.in b/buildroot-external/package/rtk-hciattach/Config.in new file mode 100644 index 00000000000..74a8d31fdf3 --- /dev/null +++ b/buildroot-external/package/rtk-hciattach/Config.in @@ -0,0 +1,6 @@ +menuconfig BR2_PACKAGE_RTK_HCIATTACH + bool "Realtek hciattach" + help + Hciattach is used to attach a serial UART to + the Bluetooth stack as HCI transport interface. + diff --git a/buildroot-external/package/rtk-hciattach/rtk-hciattach.mk b/buildroot-external/package/rtk-hciattach/rtk-hciattach.mk new file mode 100644 index 00000000000..2bdf69601d3 --- /dev/null +++ b/buildroot-external/package/rtk-hciattach/rtk-hciattach.mk @@ -0,0 +1,19 @@ +################################################################################ +# +# rtk-hciattach +# +################################################################################ + +RTK_HCIATTACH_VERSION = 1.0.0 +RTK_HCIATTACH_SITE = $(BR2_EXTERNAL_HASSOS_PATH)/package/rtk-hciattach/src +RTK_HCIATTACH_SITE_METHOD = local + +define RTK_HCIATTACH_BUILD_CMDS + $(TARGET_CONFIGURE_OPTS) make -C $(@D) +endef + +define RTK_HCIATTACH_INSTALL_TARGET_CMDS + $(INSTALL) -m 0755 -D $(@D)/rtk_hciattach $(TARGET_DIR)/usr/bin/rtk_hciattach +endef + +$(eval $(generic-package)) diff --git a/buildroot-external/package/rtk-hciattach/src/Makefile b/buildroot-external/package/rtk-hciattach/src/Makefile new file mode 100644 index 00000000000..218fb7305aa --- /dev/null +++ b/buildroot-external/package/rtk-hciattach/src/Makefile @@ -0,0 +1,19 @@ +CFLAGS := -Wall -g +all: rtk_hciattach +OBJS := hciattach.o hciattach_rtk.o hciattach_h4.o rtb_fwc.o + +rtk_hciattach: $(OBJS) + $(CC) -o rtk_hciattach $(OBJS) + +%.o: %.c + $(CC) -c $< -o $@ $(CFLAGS) + +clean: + rm -f $(OBJS) rtk_hciattach + +tags: FORCE + ctags -R + find ./ -name "*.h" -o -name "*.c" -o -name "*.cc" -o -name "*.cpp" > cscope.files + cscope -bkq -i cscope.files +PHONY += FORCE +FORCE: diff --git a/buildroot-external/package/rtk-hciattach/src/hciattach.c b/buildroot-external/package/rtk-hciattach/src/hciattach.c new file mode 100644 index 00000000000..0a4ca71da3c --- /dev/null +++ b/buildroot-external/package/rtk-hciattach/src/hciattach.c @@ -0,0 +1,631 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2000-2001 Qualcomm Incorporated + * Copyright (C) 2002-2003 Maxim Krasnyansky + * Copyright (C) 2002-2010 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hciattach.h" + +#define RFKILL_NODE "/sys/class/rfkill/rfkill0/state" + +#ifdef NEED_PPOLL +#include "ppoll.h" +#endif + +/* #define SCHED_ENABLE */ + +#ifdef SCHED_ENABLE +#include +#endif + +struct uart_t { + char *type; + int m_id; + int p_id; + int proto; + int init_speed; + int speed; + int flags; + int pm; + char *bdaddr; + int (*init) (int fd, struct uart_t *u, struct termios *ti); + int (*post) (int fd, struct uart_t *u, struct termios *ti); +}; + +#define FLOW_CTL 0x0001 +#define ENABLE_PM 1 +#define DISABLE_PM 0 + +static volatile sig_atomic_t __io_canceled = 0; + +static void sig_hup(int sig) +{ + RS_INFO("signal hup."); +} + +static void sig_term(int sig) +{ + switch (sig) { + case SIGINT: + RS_INFO("signal int."); + break; + case SIGTERM: + RS_INFO("signal term."); + break; + } + __io_canceled = 1; +} + +static void sig_alarm(int sig) +{ + RS_ERR("Initialization timed out."); + exit(1); +} + +static int uart_speed(int s) +{ + switch (s) { + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; +#ifdef B2500000 + case 2500000: + return B2500000; +#endif +#ifdef B3000000 + case 3000000: + return B3000000; +#endif +#ifdef B3500000 + case 3500000: + return B3500000; +#endif +#ifdef B4000000 + case 4000000: + return B4000000; +#endif + default: + return B57600; + } +} + +int set_speed(int fd, struct termios *ti, int speed) +{ + if (cfsetospeed(ti, uart_speed(speed)) < 0) + return -errno; + + if (cfsetispeed(ti, uart_speed(speed)) < 0) + return -errno; + + if (tcsetattr(fd, TCSANOW, ti) < 0) + return -errno; + + return 0; +} + +static int realtek_init(int fd, struct uart_t *u, struct termios *ti) +{ + + RS_INFO("Realtek Bluetooth init uart with init speed:%d, type:HCI UART %s", + u->init_speed, + (u->proto == HCI_UART_H4) ? "H4" : "H5"); + return rtb_init(fd, u->proto, u->speed, ti); +} + +static int realtek_post(int fd, struct uart_t *u, struct termios *ti) +{ + RS_INFO("Realtek Bluetooth post process"); + return rtb_post(fd, u->proto, ti); +} + +struct uart_t uart[] = { + { "any", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, DISABLE_PM, NULL, NULL}, + + /* Realtek Bluetooth H4 */ + { "rtk_h4", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, 0, DISABLE_PM, NULL, realtek_init, realtek_post }, + + /* Realtek Bluetooth H5 */ + { "rtk_h5", 0x0000, 0x0000, HCI_UART_3WIRE, 115200,115200, 0, DISABLE_PM, NULL, realtek_init, realtek_post }, + + { NULL, 0 } +}; + +static struct uart_t * get_by_id(int m_id, int p_id) +{ + int i; + for (i = 0; uart[i].type; i++) { + if (uart[i].m_id == m_id && uart[i].p_id == p_id) + return &uart[i]; + } + return NULL; +} + +static struct uart_t * get_by_type(char *type) +{ + int i; + for (i = 0; uart[i].type; i++) { + if (!strcmp(uart[i].type, type)) + return &uart[i]; + } + return NULL; +} + +/* Initialize UART driver */ +static int init_uart(char *dev, struct uart_t *u, int send_break, int raw) +{ + struct termios ti; + int fd, i; + unsigned long flags = 0; + + if (raw) + flags |= 1 << HCI_UART_RAW_DEVICE; + + fd = open(dev, O_RDWR | O_NOCTTY); + if (fd < 0) { + RS_ERR("Can't open serial port, %d, %s", errno, + strerror(errno)); + return -1; + } + + tcflush(fd, TCIOFLUSH); + + if (tcgetattr(fd, &ti) < 0) { + RS_ERR("Can't get port settings, %d, %s", errno, + strerror(errno)); + return -1; + } + + cfmakeraw(&ti); + + ti.c_cflag |= CLOCAL; + if (u->flags & FLOW_CTL) + ti.c_cflag |= CRTSCTS; + else + ti.c_cflag &= ~CRTSCTS; + + if (tcsetattr(fd, TCSANOW, &ti) < 0) { + RS_ERR("Can't set port settings, %d, %s", errno, + strerror(errno)); + return -1; + } + + /* Set initial baudrate */ + if (set_speed(fd, &ti, u->init_speed) < 0) { + RS_ERR("Can't set initial baud rate, %d, %s", errno, + strerror(errno)); + return -1; + } + + tcflush(fd, TCIOFLUSH); + + if (send_break) { + tcsendbreak(fd, 0); + usleep(500000); + } + + if (u->init && u->init(fd, u, &ti) < 0) + return -1; + + tcflush(fd, TCIOFLUSH); + + /* Set actual baudrate + * There is no need to change baudrate after uart init + * */ + /* if (set_speed(fd, &ti, u->speed) < 0) { + * perror("Can't set baud rate"); + * return -1; + * } + */ + + /* Set TTY to N_HCI line discipline */ + i = N_HCI; + if (ioctl(fd, TIOCSETD, &i) < 0) { + RS_ERR("Can't set line discipline %d, %s", errno, + strerror(errno)); + return -1; + } + + if (flags && ioctl(fd, HCIUARTSETFLAGS, flags) < 0) { + RS_ERR("Can't set UART flags %d, %s", errno, strerror(errno)); + return -1; + } + + if (ioctl(fd, HCIUARTSETPROTO, u->proto) < 0) { + RS_ERR("Can't set device %d, %s", errno, strerror(errno)); + return -1; + } + + if (u->post && u->post(fd, u, &ti) < 0) + return -1; + + return fd; +} + +static int reset_bluetooth(void) +{ + + int fd; + char state[2]; + int result; + + /* power off and power on BT */ + fd = open(RFKILL_NODE, O_RDWR); + if (fd < 0) { + RS_ERR("Cannot open %s, %d %s", RFKILL_NODE, errno, + strerror(errno)); + return -1; + } + state[0] = '0'; + state[1] = '\0'; + result = write(fd, state, strlen(state) + 1); + if (result != (strlen(state) + 1)) { + RS_ERR("Cannot write 0 to rfkill state %d %s", errno, + strerror(errno)); + close(fd); + return -1; + } + + usleep(500000); + + state[0] = '1'; + state[1] = '\0'; + result = write(fd, state, strlen(state) + 1); + if (result != (strlen(state) + 1)) { + RS_ERR("Cannot write 1 to rfkill state %d %s", errno, + strerror(errno)); + close(fd); + return -1; + } + + usleep(500000); + close(fd); + + return 0; +} + +static void usage(void) +{ + RS_INFO("hciattach - HCI UART driver initialization utility"); + RS_INFO("Usage:"); + RS_INFO("\thciattach [-n] [-p] [-b] [-r] [-t timeout] [-s initial_speed] [speed] [flow|noflow] [bdaddr]"); + RS_INFO("\thciattach -l"); +} + +int main(int argc, char *argv[]) +{ + struct uart_t *u = NULL; + int detach, printpid, raw, opt, i, n, ld, err; + int to = 10; + int init_speed = 0; + int send_break = 0; + pid_t pid; + struct sigaction sa; + struct pollfd p; + sigset_t sigs; + char dev[PATH_MAX]; +#ifdef SCHED_ENABLE + struct sched_param sched_par; +#endif + + detach = 1; + printpid = 0; + raw = 0; + + while ((opt=getopt(argc, argv, "bnpt:s:lr")) != EOF) { + switch(opt) { + case 'b': + send_break = 1; + break; + + case 'n': + detach = 0; + break; + + case 'p': + printpid = 1; + break; + + case 't': + to = atoi(optarg); + break; + + case 's': + init_speed = atoi(optarg); + break; + + case 'l': + for (i = 0; uart[i].type; i++) { + RS_INFO("%-10s0x%04x,0x%04x", uart[i].type, + uart[i].m_id, uart[i].p_id); + } + exit(0); + + case 'r': + raw = 1; + break; + + default: + usage(); + exit(1); + } + } + + n = argc - optind; + if (n < 2) { + usage(); + exit(1); + } + + for (n = 0; optind < argc; n++, optind++) { + char *opt; + + opt = argv[optind]; + + switch(n) { + case 0: + dev[0] = 0; + if (!strchr(opt, '/')) + strcpy(dev, "/dev/"); + strcat(dev, opt); + break; + + case 1: + if (strchr(argv[optind], ',')) { + int m_id, p_id; + sscanf(argv[optind], "%x,%x", &m_id, &p_id); + u = get_by_id(m_id, p_id); + } else { + u = get_by_type(opt); + } + + if (!u) { + RS_ERR("Unknown device type or id"); + exit(1); + } + + break; + + case 2: + u->speed = atoi(argv[optind]); + break; + + case 3: + if (!strcmp("flow", argv[optind])) + u->flags |= FLOW_CTL; + else + u->flags &= ~FLOW_CTL; + break; + + case 4: + if (!strcmp("sleep", argv[optind])) + u->pm = ENABLE_PM; + else + u->pm = DISABLE_PM; + break; + + case 5: + u->bdaddr = argv[optind]; + break; + } + } + + if (!u) { + RS_ERR("Unknown device type or id"); + exit(1); + } + +start: + +#ifdef SCHED_ENABLE + RS_INFO("Increase the priority of the process with set sched"); + memset(&sched_par, 0, sizeof(sched_par)); + sched_par.sched_priority = 99; + err = sched_setscheduler(0, SCHED_FIFO, &sched_par); + if (err == -1) { + RS_ERR("Call sched_setscheduler error, %s", + strerror(errno)); + } +/* #else + * RS_INFO("Increase the priority of the process with nice"); + * err = nice(-20); + * if (err == -1) { + * RS_ERR("Call nice error, %s", strerror(errno)); + * } + */ +#endif + + /* If user specified a initial speed, use that instead of + the hardware's default */ + if (init_speed) + u->init_speed = init_speed; + + memset(&sa, 0, sizeof(sa)); + sa.sa_flags = SA_NOCLDSTOP; + sa.sa_handler = sig_alarm; + sigaction(SIGALRM, &sa, NULL); + + /* 10 seconds should be enough for initialization */ + alarm(to); + + n = init_uart(dev, u, send_break, raw); + if (n < 0) { + RS_ERR("Can't initialize device %d, %s", errno, + strerror(errno)); + exit(1); + } + + RS_INFO("Device setup complete"); + + alarm(0); + + memset(&sa, 0, sizeof(sa)); + sa.sa_flags = SA_NOCLDSTOP; + sa.sa_handler = SIG_IGN; + sigaction(SIGCHLD, &sa, NULL); + sigaction(SIGPIPE, &sa, NULL); + + sa.sa_handler = sig_term; + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + + sa.sa_handler = sig_hup; + sigaction(SIGHUP, &sa, NULL); + + if (detach) { + if ((pid = fork())) { + if (printpid) + RS_INFO("%d", pid); + return 0; + } + + for (i = 0; i < 20; i++) + if (i != n) + close(i); + } + + p.fd = n; + p.events = POLLERR | POLLHUP; + + sigfillset(&sigs); + sigdelset(&sigs, SIGCHLD); + sigdelset(&sigs, SIGPIPE); + sigdelset(&sigs, SIGTERM); + sigdelset(&sigs, SIGINT); + sigdelset(&sigs, SIGHUP); + + while (!__io_canceled) { + p.revents = 0; + err = ppoll(&p, 1, NULL, &sigs); + if (err < 0 && errno == EINTR) { + RS_INFO("Got EINTR."); + continue; + } if (err) + break; + } + + RS_INFO("err %d, p->revents %04x", err, p.revents); + + /* Restore TTY line discipline */ + RS_INFO("Restore TTY line discipline"); + ld = N_TTY; + if (ioctl(n, TIOCSETD, &ld) < 0) { + RS_ERR("Can't restore line discipline %d, %s", errno, + strerror(errno)); + exit(1); + } + + if (p.revents & (POLLERR | POLLHUP)) { + RS_INFO("Recover..."); + reset_bluetooth(); + goto start; + } + + return 0; +} + +void util_hexdump(const uint8_t *buf, size_t len) +{ + static const char hexdigits[] = "0123456789abcdef"; + char str[16 * 3]; + size_t i; + + if (!buf || !len) + return; + + for (i = 0; i < len; i++) { + str[((i % 16) * 3)] = hexdigits[buf[i] >> 4]; + str[((i % 16) * 3) + 1] = hexdigits[buf[i] & 0xf]; + str[((i % 16) * 3) + 2] = ' '; + if ((i + 1) % 16 == 0) { + str[16 * 3 - 1] = '\0'; + RS_INFO("%s", str); + } + } + + if (i % 16 > 0) { + str[(i % 16) * 3 - 1] = '\0'; + RS_INFO("%s", str); + } +} + +int timeout_set(int fd, unsigned int msec) +{ + struct itimerspec itimer; + unsigned int sec = msec / 1000; + + memset(&itimer, 0, sizeof(itimer)); + itimer.it_interval.tv_sec = 0; + itimer.it_interval.tv_nsec = 0; + itimer.it_value.tv_sec = sec; + itimer.it_value.tv_nsec = (msec - (sec * 1000)) * 1000 * 1000; + + return timerfd_settime(fd, 0, &itimer, NULL); +} + diff --git a/buildroot-external/package/rtk-hciattach/src/hciattach.h b/buildroot-external/package/rtk-hciattach/src/hciattach.h new file mode 100644 index 00000000000..68d112f3279 --- /dev/null +++ b/buildroot-external/package/rtk-hciattach/src/hciattach.h @@ -0,0 +1,188 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2003-2009 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define cpu_to_le16(d) (d) +#define cpu_to_le32(d) (d) +#define le16_to_cpu(d) (d) +#define le32_to_cpu(d) (d) +#elif __BYTE_ORDER == __BIG_ENDIAN +#define cpu_to_le16(d) bswap_16(d) +#define cpu_to_le32(d) bswap_32(d) +#define le16_to_cpu(d) bswap_16(d) +#define le32_to_cpu(d) bswap_32(d) +#else +#error "Unknown byte order" +#endif + +#ifndef N_HCI +#define N_HCI 15 +#endif + +#define HCIUARTSETPROTO _IOW('U', 200, int) +#define HCIUARTGETPROTO _IOR('U', 201, int) +#define HCIUARTGETDEVICE _IOR('U', 202, int) +#define HCIUARTSETFLAGS _IOW('U', 203, int) +#define HCIUARTGETFLAGS _IOR('U', 204, int) + +#define HCI_UART_H4 0 +#define HCI_UART_BCSP 1 +#define HCI_UART_3WIRE 2 +#define HCI_UART_H4DS 3 +#define HCI_UART_LL 4 +#define HCI_UART_RAW_DEVICE 0 + +extern uint8_t DBG_ON; + +/* #define SYSLOG */ + +#define LOG_STR "Realtek Bluetooth" +#ifdef SYSLOG +#define RS_DBG(fmt, arg...) \ + do{ \ + if (DBG_ON) \ + syslog(LOG_DEBUG, "%s :" fmt "\n" , LOG_STR, ##arg); \ + }while(0) + +#define RS_INFO(fmt, arg...) \ + do{ \ + syslog(LOG_INFO, "%s :" fmt "\n", LOG_STR, ##arg); \ + }while(0) + +#define RS_WARN(fmt, arg...) \ + do{ \ + syslog(LOG_WARNING, "%s WARN: " fmt "\n", LOG_STR, ##arg); \ + }while(0) + +#define RS_ERR(fmt, arg...) \ + do{ \ + syslog(LOG_ERR, "%s ERROR: " fmt "\n", LOG_STR, ##arg); \ + }while(0) +#else +#define RS_DBG(fmt, arg...) \ + do{ \ + if (DBG_ON) \ + printf("%s :" fmt "\n" , LOG_STR, ##arg); \ + }while(0) + +#define RS_INFO(fmt, arg...) \ + do{ \ + printf("%s :" fmt "\n", LOG_STR, ##arg); \ + }while(0) + +#define RS_WARN(fmt, arg...) \ + do{ \ + printf("%s WARN: " fmt "\n", LOG_STR, ##arg); \ + }while(0) + +#define RS_ERR(fmt, arg...) \ + do{ \ + printf("%s ERROR: " fmt "\n", LOG_STR, ##arg); \ + }while(0) +#endif + +typedef enum _H5_RX_STATE { + H5_W4_PKT_DELIMITER, + H5_W4_PKT_START, + H5_W4_HDR, + H5_W4_DATA, + H5_W4_CRC +} H5_RX_STATE; + +typedef enum _H5_RX_ESC_STATE { + H5_ESCSTATE_NOESC, + H5_ESCSTATE_ESC +} H5_RX_ESC_STATE; + +typedef enum _H5_LINK_STATE { + H5_SYNC, + H5_CONFIG, + H5_INIT, + H5_PATCH, + H5_HCI_RESET, + H5_ACTIVE +} H5_LINK_STATE; + +struct patch_info; +typedef struct rtb_struct { + /* three wire releated */ + uint8_t rxseq_txack; /* expected rx seq number */ + uint8_t rxack; /* last packet that the peer ack'ed */ + uint8_t use_crc; + uint8_t is_txack_req; /* txack required */ + uint8_t msgq_txseq; /* next pkt seq */ + uint16_t message_crc; + uint32_t rx_count; /* expected pkts to recv */ + + H5_RX_STATE rx_state; + H5_RX_ESC_STATE rx_esc_state; + H5_LINK_STATE link_estab_state; + + struct sk_buff *rx_skb; + + uint16_t num_of_cmd_sent; + uint16_t lmp_subver; + uint16_t hci_rev; + uint8_t hci_ver; + uint8_t eversion; + uint8_t chip_type; + + uint32_t vendor_baud; + uint8_t dl_fw_flag; + int serial_fd; + uint32_t uart_flow_ctrl; + uint32_t parenb: 16; + uint32_t pareven: 16; + int final_speed; + int total_num; /* total pkt number */ + int tx_index; /* current sending pkt number */ + int rx_index; /* ack index from board */ + int fw_len; /* fw patch file len */ + int config_len; /* config patch file len */ + int total_len; /* fw & config extracted buf len */ + uint8_t *fw_buf; /* fw patch file buf */ + uint8_t *config_buf; /* config patch file buf */ + uint8_t *total_buf; /* fw & config extracted buf */ +#define CMD_STATE_UNKNOWN 0x00 +#define CMD_STATE_SUCCESS 0x01 + struct __cmd_state { + uint16_t opcode; + uint16_t state; + } cmd_state; + + struct patch_info *patch_ent; + + int proto; + int timerfd; + int epollfd; +} rtb_struct_t; +extern struct rtb_struct rtb_cfg; +int timeout_set(int fd, unsigned int msec); +int set_speed(int fd, struct termios *ti, int speed); +int rtb_init(int fd, int proto, int speed, struct termios *ti); +int rtb_post(int fd, int proto, struct termios *ti); +void util_hexdump(const uint8_t *buf, size_t len); diff --git a/buildroot-external/package/rtk-hciattach/src/hciattach_h4.c b/buildroot-external/package/rtk-hciattach/src/hciattach_h4.c new file mode 100644 index 00000000000..ae923953d50 --- /dev/null +++ b/buildroot-external/package/rtk-hciattach/src/hciattach_h4.c @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hciattach.h" +#include "hciattach_h4.h" + +extern struct rtb_struct rtb_cfg; + +static int start_xfer_wait(int fd, uint8_t *cmd, uint16_t len, uint32_t msec, + int retry, uint8_t *resp, uint16_t *resp_len) +{ + uint8_t buf[64]; + int result; + int state = 1; + int count = 0; + int params_len; + struct pollfd p[2]; + uint16_t opcode; + + if (fd == -1 || !cmd || len < 4) { + RS_ERR("%s: invalid parameter", __func__); + return -1; + } + + opcode = ((uint16_t)cmd[2] << 8) + cmd[1]; + +start_xfer: + result = write(fd, cmd, len); + if (result != len) { + RS_ERR("%s: Write cmd %04x error, %s", __func__, opcode, + strerror(errno)); + return -1; + } + +start_recv: + memset(buf, 0, sizeof(buf)); + memset(p, 0, sizeof(p)); + state = 1; + count = 0; + p[0].fd = fd; + p[0].events = POLLERR | POLLHUP | POLLIN; + for (;;) { + p[0].revents = 0; + result = poll(p, 1, msec); + if (result < 0) { + RS_ERR("Poll call error, %s", strerror(errno)); + result = -1; + break; + } + + if (result == 0) { + RS_WARN("%s: Timeout", __func__); + if (retry <= 0) { + RS_ERR("%s: Transfer exhausted", __func__); + tcflush(fd, TCIOFLUSH); + exit(EXIT_FAILURE); + } + retry--; + goto start_xfer; + } + + if (p[0].revents & (POLLERR | POLLHUP)) { + RS_ERR("POLLERR or POLLUP happens, %s", + strerror(errno)); + result = -1; + break; + } + + if (state == 1) { + result = read(p[0].fd, buf, 1); + if (result == -1 || result != 1) { + RS_ERR("%s: Read pkt type error, %s", __func__, + strerror(errno)); + result = -1; + break; + } + if (result == 1 && buf[0] == 0x04) { + count = 1; + state = 2; + } + } else if (state == 2) { + result = read(p[0].fd, buf + count, 2); + if (result == -1 || result != 2) { + RS_ERR("%s: Read pkt header error, %s", + __func__, strerror(errno)); + break; + } + count += result; + state = 3; + params_len = buf[2]; + if (params_len + 3 > sizeof(buf)) { + result = -1; + RS_ERR("%s: hci event too long", __func__); + break; + } + } else if (state == 3) { + result = read(p[0].fd, buf + count, params_len); + if (result == -1) { + RS_ERR("%s: Read pkt payload error, %s", + __func__, strerror(errno)); + break; + } + count += result; + params_len -= result; + if (!params_len) + break; + } + } + + if (result >= 0) { + if (buf[1] == 0x0e) { + uint16_t tmp_opcode; + + tmp_opcode = (uint16_t)buf[4] | buf[5] << 8; + if (tmp_opcode == opcode) { + RS_INFO("Cmd complete event for cmd %04x", + opcode); + /* Status is not zero indicating command not + * succeeded */ + if (buf[6]) + return -1; + if (!resp) + return 0; + if (*resp_len > count) + *resp_len = count; + memcpy(resp, buf, *resp_len); + return 0; + } else { + RS_WARN("Unexpected cmd complete event, %04x", + tmp_opcode); + return -1; + } + } else { + RS_INFO("%s: Unexpected hci event packet", __func__); + util_hexdump(buf, count); + /* Continue receiving */ + } + goto start_recv; + } + + return result; +} + +int h4_download_patch(int fd, int index, uint8_t *data, int len) +{ + uint8_t buf[257]; + uint16_t total_len; + int result; + uint8_t resp[8]; + uint16_t rlen = sizeof(resp); + + RS_DBG("fd: %d, index: %d, len: %d", fd, index, len); + + if (data) + memcpy(&buf[5], data, len); + buf[0] = 0x01; + buf[1] = 0x20; + buf[2] = 0xfc; + buf[3] = len + 1; + buf[4] = (uint8_t)index; + total_len = len + 5; + + result = start_xfer_wait(fd, buf, total_len, 1000, 0, resp, &rlen); + if (result < 0) { + RS_ERR("Transfer patch failed, index %d", index); + return -1; + } + + if (rlen != 8) { + RS_ERR("%s: Unexpected length %u", __func__, rlen); + return -1; + } + + return resp[7]; +} + +int h4_vendor_change_speed(int fd, uint32_t baudrate) +{ + int res; + uint8_t cmd[8] = { 0 }; + + cmd[0] = 1; + cmd[1] = 0x17; + cmd[2] = 0xfc; + cmd[3] = 4; + + baudrate = cpu_to_le32(baudrate); +#ifdef BAUDRATE_4BYTES + memcpy((uint16_t *) & cmd[4], &baudrate, 4); +#else + memcpy((uint16_t *) & cmd[4], &baudrate, 2); + cmd[6] = 0; + cmd[7] = 0; +#endif + + /* TODO: Wait for a while for device to up, just h4 need it */ + sleep(1); + + RS_DBG("baudrate in change speed command: 0x%02x 0x%02x 0x%02x 0x%02x", + cmd[4], cmd[5], cmd[6], cmd[7]); + + res = start_xfer_wait(fd, cmd, 8, 1000, 0, NULL, 0); + if (res < 0) + RS_ERR("Change Controller baud failed"); + + return res; +} + +int h4_hci_reset(int fd) +{ + int result; + uint8_t cmd[4] = { 0x01, 0x03, 0x0c, 0x00}; + + RS_INFO("%s: Issue hci reset cmd", __func__); + + result = start_xfer_wait(fd, cmd, sizeof(cmd), 1000, 0, NULL, 0); + if (result < 0) { + RS_ERR("%s: Failed to send reset cmd", __func__); + return -1; + } + + return 0; +} + +int h4_read_local_ver(int fd) +{ + uint8_t cmd[4] = { 0x01, 0x01, 0x10, 0x00 }; + uint8_t resp[16]; + uint16_t len = sizeof(resp); + int result; + + result = start_xfer_wait(fd, cmd, sizeof(cmd), 1000, 0, + resp, &len); + if (result < 0) { + RS_ERR("HCI Read local version info error"); + return -1; + } + + if (len != 15) { + RS_ERR("%s: Unexpected length %u", __func__, len); + return -1; + } + rtb_cfg.hci_ver = resp[7]; + rtb_cfg.hci_rev = (uint32_t)resp[9] << 8 | resp[8]; + rtb_cfg.lmp_subver = (uint32_t)resp[14] << 8 | resp[13]; + RS_INFO("hci ver %02x, hci_rev %04x, lmp_subver %04x", + rtb_cfg.hci_ver, rtb_cfg.hci_rev, rtb_cfg.lmp_subver); + return 0; +} + +int h4_vendor_read_rom_ver(int fd) +{ + uint8_t cmd[4] = { 0x01, 0x6d, 0xfc, 0x00 }; + uint8_t resp[16]; + uint16_t len = sizeof(resp); + int result; + + result = start_xfer_wait(fd, cmd, sizeof(cmd), 1000, 0, + resp, &len); + if (result < 0) { + RS_ERR("HCI Read local version info error"); + return -1; + } + + if (len != 8) { + RS_ERR("%s: Unexpected length %u", __func__, len); + return -1; + } + rtb_cfg.eversion = resp[7]; + RS_INFO("eversion %02x", rtb_cfg.eversion); + return 0; +} + diff --git a/buildroot-external/package/rtk-hciattach/src/hciattach_h4.h b/buildroot-external/package/rtk-hciattach/src/hciattach_h4.h new file mode 100644 index 00000000000..8549da7a54c --- /dev/null +++ b/buildroot-external/package/rtk-hciattach/src/hciattach_h4.h @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +int h4_download_patch(int fd, int index, uint8_t *data, int len); +int h4_vendor_change_speed(int fd, uint32_t baudrate); +int h4_hci_reset(int fd); +int h4_read_local_ver(int fd); +int h4_vendor_read_rom_ver(int fd); diff --git a/buildroot-external/package/rtk-hciattach/src/hciattach_rtk.c b/buildroot-external/package/rtk-hciattach/src/hciattach_rtk.c new file mode 100644 index 00000000000..5f80e839f65 --- /dev/null +++ b/buildroot-external/package/rtk-hciattach/src/hciattach_rtk.c @@ -0,0 +1,2040 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtb_fwc.h" +#include "hciattach.h" +#include "hciattach_h4.h" + +#define RTK_VERSION "3.1" + +#define TIMESTAMP_PR + +#define MAX_EVENTS 10 + +/* #define SERIAL_NONBLOCK_READ */ + +#ifdef SERIAL_NONBLOCK_READ +#define FD_BLOCK 0 +#define FD_NONBLOCK 1 +#endif + +/* #define RTL_8703A_SUPPORT */ +/* #define RTL8723DSH4_UART_HWFLOWC */ /* 8723DS H4 special */ + +uint8_t DBG_ON = 1; + +#define HCI_EVENT_HDR_SIZE 2 +#define PATCH_DATA_FIELD_MAX_SIZE 252 + +#define HCI_CMD_READ_BD_ADDR 0x1009 +#define HCI_VENDOR_CHANGE_BAUD 0xfc17 +#define HCI_VENDOR_READ_ROM_VER 0xfc6d +#define HCI_CMD_READ_LOCAL_VER 0x1001 +#define HCI_VENDOR_READ_CHIP_TYPE 0xfc61 +#define HCI_CMD_RESET 0x0c03 + +/* HCI data types */ +#define H5_ACK_PKT 0x00 +#define HCI_COMMAND_PKT 0x01 +#define HCI_ACLDATA_PKT 0x02 +#define HCI_SCODATA_PKT 0x03 +#define HCI_EVENT_PKT 0x04 +#define H5_VDRSPEC_PKT 0x0E +#define H5_LINK_CTL_PKT 0x0F + +#define H5_HDR_SEQ(hdr) ((hdr)[0] & 0x07) +#define H5_HDR_ACK(hdr) (((hdr)[0] >> 3) & 0x07) +#define H5_HDR_CRC(hdr) (((hdr)[0] >> 6) & 0x01) +#define H5_HDR_RELIABLE(hdr) (((hdr)[0] >> 7) & 0x01) +#define H5_HDR_PKT_TYPE(hdr) ((hdr)[1] & 0x0f) +#define H5_HDR_LEN(hdr) ((((hdr)[1] >> 4) & 0xff) + ((hdr)[2] << 4)) +#define H5_HDR_SIZE 4 + +struct sk_buff { + uint32_t max_len; + uint32_t data_len; + uint8_t *data; +}; + +struct hci_ev_cmd_complete { + uint8_t ncmd; + uint16_t opcode; +} __attribute__ ((packed)); + +#define OP_H5_SYNC 0x01 +#define OP_H5_CONFIG 0x02 +#define OP_ROM_VER ((1 << 24) | HCI_VENDOR_READ_ROM_VER) +#define OP_LMP_VER ((1 << 24) | HCI_CMD_READ_LOCAL_VER) +#define OP_CHIP_TYPE ((1 << 24) | HCI_VENDOR_READ_CHIP_TYPE) +#define OP_SET_BAUD ((1 << 24) | HCI_VENDOR_CHANGE_BAUD) +#define OP_HCI_RESET ((1 << 24) | HCI_CMD_RESET) + +struct rtb_struct rtb_cfg; + +/* bite reverse in bytes + * 00000001 -> 10000000 + * 00000100 -> 00100000 + */ +const uint8_t byte_rev_table[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, +}; + +static __inline uint8_t bit_rev8(uint8_t byte) +{ + return byte_rev_table[byte]; +} + +static __inline uint16_t bit_rev16(uint16_t x) +{ + return (bit_rev8(x & 0xff) << 8) | bit_rev8(x >> 8); +} + +static const uint16_t crc_table[] = { + 0x0000, 0x1081, 0x2102, 0x3183, + 0x4204, 0x5285, 0x6306, 0x7387, + 0x8408, 0x9489, 0xa50a, 0xb58b, + 0xc60c, 0xd68d, 0xe70e, 0xf78f +}; + +/* Initialise the crc calculator */ +#define H5_CRC_INIT(x) x = 0xffff + +static __inline struct sk_buff *skb_alloc(unsigned int len) +{ + struct sk_buff *skb = NULL; + + if ((skb = malloc(len + sizeof(*skb)))) { + skb->max_len = len; + skb->data_len = 0; + skb->data = ((uint8_t *)skb) + sizeof(*skb); + } else { + RS_ERR("Allocate skb fails!"); + skb = NULL; + return NULL; + } + memset(skb->data, 0, len); + return skb; +} + +static __inline void skb_free(struct sk_buff *skb) +{ + free(skb); + return; +} + +/* + * Add data to a buffer + * This function extends the used data area of the buffer. + */ +static uint8_t *skb_put(struct sk_buff *skb, uint32_t len) +{ + uint32_t old_len = skb->data_len; + + if ((skb->data_len + len) > (skb->max_len)) { + RS_ERR("Buffer too small"); + exit(EXIT_FAILURE); + } + skb->data_len += len; + return (skb->data + old_len); +} + +/* + * Remove end from a buffer + * Cut the length of a buffer down by removing data from the tail + */ +static void skb_trim(struct sk_buff *skb, uint32_t len) +{ + if (skb->data_len > len) { + skb->data_len = len; + } else { + RS_ERR("Trim error, data_len %u < len %u", skb->data_len, len); + } +} + +/* + * Remove data from the start of a buffer + * This function removes data from the start of a buffer. + * A pointer to the next data in the buffer is returned + */ +static uint8_t *skb_pull(struct sk_buff *skb, uint32_t len) +{ + if (len > skb->data_len) { + RS_ERR("Pull error, data_len %u < len %u", skb->data_len, len); + exit(EXIT_FAILURE); + } + skb->data_len -= len; + skb->data += len; + return skb->data; +} + +/** +* Add "d" into crc scope, caculate the new crc value +* +* @param crc crc data +* @param d one byte data +*/ +static void h5_crc_update(uint16_t * crc, uint8_t d) +{ + uint16_t reg = *crc; + + reg = (reg >> 4) ^ crc_table[(reg ^ d) & 0x000f]; + reg = (reg >> 4) ^ crc_table[(reg ^ (d >> 4)) & 0x000f]; + + *crc = reg; +} + +struct __una_u16 { + uint16_t x; +}; +static __inline uint16_t __get_unaligned_cpu16(const void *p) +{ + const struct __una_u16 *ptr = (const struct __una_u16 *)p; + return ptr->x; +} + +static __inline uint16_t get_unaligned_be16(const void *p) +{ + return __get_unaligned_cpu16((const uint8_t *)p); +} + +/* + * Get crc data. + */ +static uint16_t h5_get_crc(struct rtb_struct * h5) +{ + uint16_t crc = 0; + uint8_t *data = h5->rx_skb->data + h5->rx_skb->data_len - 2; + + crc = data[1] + (data[0] << 8); + return crc; + /* return get_unaligned_be16(&h5->rx_skb->data[h5->rx_skb->data_len - 2]); */ +} + +/* + * Add 0xc0 to buffer. + */ +static void h5_slip_msgdelim(struct sk_buff *skb) +{ + const char pkt_delim = 0xc0; + memcpy(skb_put(skb, 1), &pkt_delim, 1); +} + +/* + * Encode one byte in h5 proto + * 0xc0 -> 0xdb, 0xdc + * 0xdb -> 0xdb, 0xdd + * 0x11 -> 0xdb, 0xde + * 0x13 -> 0xdb, 0xdf + * others will not change + */ +static void h5_slip_one_byte(struct sk_buff *skb, uint8_t c) +{ + const uint8_t esc_c0[2] = { 0xdb, 0xdc }; + const uint8_t esc_db[2] = { 0xdb, 0xdd }; + const uint8_t esc_11[2] = { 0xdb, 0xde }; + const uint8_t esc_13[2] = { 0xdb, 0xdf }; + + switch (c) { + case 0xc0: + memcpy(skb_put(skb, 2), &esc_c0, 2); + break; + + case 0xdb: + memcpy(skb_put(skb, 2), &esc_db, 2); + break; + + case 0x11: + memcpy(skb_put(skb, 2), &esc_11, 2); + break; + + case 0x13: + memcpy(skb_put(skb, 2), &esc_13, 2); + break; + + default: + memcpy(skb_put(skb, 1), &c, 1); + break; + } +} + +/* + * Decode one byte in h5 proto + * 0xdb, 0xdc -> 0xc0 + * 0xdb, 0xdd -> 0xdb + * 0xdb, 0xde -> 0x11 + * 0xdb, 0xdf -> 0x13 + * others will not change + */ +static void h5_unslip_one_byte(struct rtb_struct * h5, unsigned char byte) +{ + const uint8_t c0 = 0xc0, db = 0xdb; + const uint8_t oof1 = 0x11, oof2 = 0x13; + + if (H5_ESCSTATE_NOESC == h5->rx_esc_state) { + if (0xdb == byte) { + h5->rx_esc_state = H5_ESCSTATE_ESC; + } else { + memcpy(skb_put(h5->rx_skb, 1), &byte, 1); + /* Check Pkt Header's CRC enable bit */ + if ((h5->rx_skb->data[0] & 0x40) != 0 && + h5->rx_state != H5_W4_CRC) { + h5_crc_update(&h5->message_crc, byte); + } + h5->rx_count--; + } + } else if (H5_ESCSTATE_ESC == h5->rx_esc_state) { + switch (byte) { + case 0xdc: + memcpy(skb_put(h5->rx_skb, 1), &c0, 1); + if ((h5->rx_skb->data[0] & 0x40) != 0 && + h5->rx_state != H5_W4_CRC) + h5_crc_update(&h5->message_crc, 0xc0); + h5->rx_esc_state = H5_ESCSTATE_NOESC; + h5->rx_count--; + break; + + case 0xdd: + memcpy(skb_put(h5->rx_skb, 1), &db, 1); + if ((h5->rx_skb->data[0] & 0x40) != 0 && + h5->rx_state != H5_W4_CRC) + h5_crc_update(&h5->message_crc, 0xdb); + h5->rx_esc_state = H5_ESCSTATE_NOESC; + h5->rx_count--; + break; + + case 0xde: + memcpy(skb_put(h5->rx_skb, 1), &oof1, 1); + if ((h5->rx_skb->data[0] & 0x40) != 0 && + h5->rx_state != H5_W4_CRC) + h5_crc_update(&h5->message_crc, oof1); + h5->rx_esc_state = H5_ESCSTATE_NOESC; + h5->rx_count--; + break; + + case 0xdf: + memcpy(skb_put(h5->rx_skb, 1), &oof2, 1); + if ((h5->rx_skb->data[0] & 0x40) != 0 && + h5->rx_state != H5_W4_CRC) + h5_crc_update(&h5->message_crc, oof2); + h5->rx_esc_state = H5_ESCSTATE_NOESC; + h5->rx_count--; + break; + + default: + RS_ERR("Error: Invalid byte %02x after esc byte", byte); + skb_free(h5->rx_skb); + h5->rx_skb = NULL; + h5->rx_state = H5_W4_PKT_DELIMITER; + h5->rx_count = 0; + break; + } + } +} + +/* + * Prepare h5 packet + * Refer to Core Spec Vol 4, Part D + * Three-wire UART Transport Layer: 4 PACKET HEADER + */ +static struct sk_buff *h5_prepare_pkt(struct rtb_struct * h5, uint8_t *data, + int len, int pkt_type) +{ + struct sk_buff *nskb; + uint8_t hdr[4]; + uint16_t H5_CRC_INIT(h5_txmsg_crc); + int rel, i; + + switch (pkt_type) { + case HCI_ACLDATA_PKT: + case HCI_COMMAND_PKT: + case HCI_EVENT_PKT: + rel = 1; /* reliable */ + break; + + case H5_ACK_PKT: + case H5_VDRSPEC_PKT: + case H5_LINK_CTL_PKT: + rel = 0; /* unreliable */ + break; + + default: + RS_ERR("Unknown packet type"); + return NULL; + } + + /* Max len of packet: (len + 4(h5 hdr) + 2(crc))*2 + * Because bytes 0xc0 and 0xdb are escaped, worst case is that the + * packet is only made of 0xc0 and 0xdb + * The additional 2-octets are 0xc0 delimiters at start and end of each + * packet. + */ + nskb = skb_alloc((len + 6) * 2 + 2); + if (!nskb) + return NULL; + + /* Add SLIP start byte: 0xc0 */ + h5_slip_msgdelim(nskb); + /* Set ack number in SLIP header */ + hdr[0] = h5->rxseq_txack << 3; + h5->is_txack_req = 0; + + /* RS_DBG("Request packet no(%u) to card", h5->rxseq_txack); */ + /* RS_DBG("Sending packet with seqno %u and wait %u", h5->msgq_txseq, + * h5->rxseq_txack); + */ + if (rel) { + /* Set reliable bit and seq number */ + hdr[0] |= 0x80 + h5->msgq_txseq; + /* RS_DBG("Sending packet with seqno(%u)", h5->msgq_txseq); */ + ++(h5->msgq_txseq); + h5->msgq_txseq = (h5->msgq_txseq) & 0x07; + } + /* Set DIC Present bit */ + if (h5->use_crc) + hdr[0] |= 0x40; + + /* Set packet type and payload length */ + hdr[1] = ((len << 4) & 0xff) | pkt_type; + hdr[2] = (uint8_t) (len >> 4); + /* Set header checksum */ + hdr[3] = ~(hdr[0] + hdr[1] + hdr[2]); + + /* Encode h5 header */ + for (i = 0; i < 4; i++) { + h5_slip_one_byte(nskb, hdr[i]); + + if (h5->use_crc) + h5_crc_update(&h5_txmsg_crc, hdr[i]); + } + + /* Encode payload */ + for (i = 0; i < len; i++) { + h5_slip_one_byte(nskb, data[i]); + + if (h5->use_crc) + h5_crc_update(&h5_txmsg_crc, data[i]); + } + + /* Encode CRC */ + if (h5->use_crc) { + h5_txmsg_crc = bit_rev16(h5_txmsg_crc); + h5_slip_one_byte(nskb, (uint8_t) ((h5_txmsg_crc >> 8) & 0x00ff)); + h5_slip_one_byte(nskb, (uint8_t) (h5_txmsg_crc & 0x00ff)); + } + /* Add 0xc0 at the end of the packet */ + h5_slip_msgdelim(nskb); + + return nskb; +} + +/* + * Remove controller acked packet from host unacked lists + */ +/* static void h5_remove_acked_pkt(struct rtb_struct * h5) + * { + * int pkts_to_be_removed = 0; + * int seqno = 0; + * int i = 0; + * + * seqno = h5->msgq_txseq; + * // pkts_to_be_removed = GetListLength(h5->unacked); + * + * while (pkts_to_be_removed) { + * if (h5->rxack == seqno) + * break; + * + * pkts_to_be_removed--; + * seqno = (seqno - 1) & 0x07; + * } + * + * if (h5->rxack != seqno) { + * RS_DBG("Peer acked invalid packet"); + * } + * // skb_queue_walk_safe(&h5->unack, skb, tmp) + * // remove ack'ed packet from h5->unack queue + * for (i = 0; i < 5; ++i) { + * if (i >= pkts_to_be_removed) + * break; + * i++; + * //__skb_unlink(skb, &h5->unack); + * //skb_free(skb); + * } + * + * // if (skb_queue_empty(&h5->unack)) + * // del_timer(&h5->th5); + * // spin_unlock_irqrestore(&h5->unack.lock, flags); + * + * if (i != pkts_to_be_removed) + * RS_DBG("Removed only (%u) out of (%u) pkts", i, + * pkts_to_be_removed); + * } + */ + +/* + * Send host ack. + */ +static void rtb_send_ack(int fd) +{ + int len; + struct sk_buff *nskb = h5_prepare_pkt(&rtb_cfg, NULL, 0, H5_ACK_PKT); + + len = write(fd, nskb->data, nskb->data_len); + if (len != nskb->data_len) + RS_ERR("Write pure ack fails"); + + skb_free(nskb); + return; +} + +/* + * Parse hci command complete event in h5 init state. + */ +static void h5_init_hci_cc(struct sk_buff *skb) +{ + struct hci_ev_cmd_complete *ev = NULL; + uint16_t opcode = 0; + uint8_t status = 0; + + skb_pull(skb, HCI_EVENT_HDR_SIZE); + ev = (struct hci_ev_cmd_complete *)skb->data; + opcode = le16_to_cpu(ev->opcode); + + RS_DBG("Receive cmd complete event of command: %04x", opcode); + + skb_pull(skb, sizeof(struct hci_ev_cmd_complete)); + + status = skb->data[0]; + if (status) { + RS_ERR("status is %u for cmd %04x", status, opcode); + return; + } + + if (rtb_cfg.cmd_state.opcode != opcode) { + RS_ERR("%s: Received unexpected cc for cmd %04x, %04x of cc", + __func__, rtb_cfg.cmd_state.opcode, opcode); + return; + } + + rtb_cfg.cmd_state.state = CMD_STATE_SUCCESS; + + switch (opcode) { + case HCI_VENDOR_CHANGE_BAUD: + RS_INFO("Received cc of vendor change baud"); + break; + case HCI_CMD_READ_BD_ADDR: + RS_INFO("BD Address: %02x:%02x:%02x:%02x:%02x:%02x", + skb->data[5], skb->data[4], skb->data[3], + skb->data[2], skb->data[1], skb->data[0]); + break; + + case HCI_CMD_READ_LOCAL_VER: + rtb_cfg.hci_ver = skb->data[1]; + rtb_cfg.hci_rev = (skb->data[2] | skb->data[3] << 8); + rtb_cfg.lmp_subver = (skb->data[7] | (skb->data[8] << 8)); + RS_INFO("HCI Version 0x%02x", rtb_cfg.hci_ver); + RS_INFO("HCI Revision 0x%04x", rtb_cfg.hci_rev); + RS_INFO("LMP Subversion 0x%04x", rtb_cfg.lmp_subver); + break; + + case HCI_VENDOR_READ_ROM_VER: + rtb_cfg.eversion = skb->data[1]; + RS_INFO("Read ROM version %02x", rtb_cfg.eversion); + break; + + case HCI_VENDOR_READ_CHIP_TYPE: + rtb_cfg.chip_type = (skb->data[1] & 0x0f); + RS_INFO("Read chip type %02x", rtb_cfg.chip_type); + break; + default: + return; + } + + /* Count the cmd num for makeing the seq number aligned */ + rtb_cfg.num_of_cmd_sent++; +} + +/* + * Parse hci command complete event in h5 post state. + */ +static void h5_post_hci_cc(struct sk_buff *skb) +{ + struct hci_ev_cmd_complete *ev = NULL; + uint16_t opcode = 0; + uint8_t status = 0; + + skb_pull(skb, HCI_EVENT_HDR_SIZE); + ev = (struct hci_ev_cmd_complete *)skb->data; + opcode = le16_to_cpu(ev->opcode); + + RS_DBG("Receive cmd complete event of command: %04x", opcode); + + skb_pull(skb, sizeof(struct hci_ev_cmd_complete)); + + status = skb->data[0]; + if (status) { + RS_ERR("status is %u for cmd %04x", status, opcode); + return; + } + + if (rtb_cfg.cmd_state.opcode != opcode) { + RS_ERR("%s: Received unexpected cc for cmd %04x, %04x of cc", + __func__, rtb_cfg.cmd_state.opcode, opcode); + return; + } + + rtb_cfg.cmd_state.state = CMD_STATE_SUCCESS; + + switch (opcode) { + case HCI_CMD_RESET: + RS_INFO("Received cc of hci reset cmd"); + rtb_cfg.link_estab_state = H5_ACTIVE; + break; + default: + break; + } +} + +/* + * Process a hci frame + */ +static void hci_recv_frame(struct sk_buff *skb) +{ + if (rtb_cfg.link_estab_state == H5_INIT) { + if (skb->data[0] == 0x0e) + h5_init_hci_cc(skb); + + /* + * rtb_send_ack(rtb_cfg.serial_fd); + * usleep(10000); + * rtb_send_ack(rtb_cfg.serial_fd); + */ + } else if (rtb_cfg.link_estab_state == H5_PATCH) { + if (skb->data[0] != 0x0e) { + RS_INFO("Received event 0x%x during download patch", + skb->data[0]); + return; + } + + rtb_cfg.rx_index = skb->data[6]; + + /* RS_INFO("rx_index %d", rtb_cfg.rx_index); */ + + /* Download fw/config done */ + if (rtb_cfg.rx_index & 0x80) { + rtb_cfg.rx_index &= ~0x80; + rtb_cfg.link_estab_state = H5_HCI_RESET; + } + } else if (rtb_cfg.link_estab_state == H5_HCI_RESET) { + if (skb->data[0] == 0x0e) + h5_post_hci_cc(skb); + } else { + RS_ERR("receive packets in active state"); + } +} + +static void h5_handle_internal_rx(struct sk_buff *skb) +{ + int len; + uint8_t sync_req[2] = { 0x01, 0x7E }; + uint8_t sync_resp[2] = { 0x02, 0x7D }; + uint8_t sync_resp_pkt[0x8] = { + 0xc0, 0x00, 0x2F, 0x00, 0xD0, 0x02, 0x7D, 0xc0 + }; + uint8_t conf_req[2] = { 0x03, 0xFC }; + uint8_t conf_resp[2] = { 0x04, 0x7B }; + uint8_t conf_resp_pkt[0x8] = { + 0xc0, 0x00, 0x2F, 0x00, 0xD0, 0x04, 0x7B, 0xc0 + }; + + if (rtb_cfg.link_estab_state == H5_SYNC) { + if (!memcmp(skb->data, sync_req, 2)) { + RS_INFO("[SYNC] Get SYNC Pkt\n"); + len = write(rtb_cfg.serial_fd, sync_resp_pkt, 0x8); + if (len != 0x08) + RS_ERR("Send h5 sync resp error, %s", + strerror(errno)); + } else if (!memcmp(skb->data, sync_resp, 2)) { + RS_INFO("[SYNC] Get SYNC Resp Pkt"); + rtb_cfg.link_estab_state = H5_CONFIG; + } + } else if (rtb_cfg.link_estab_state == H5_CONFIG) { + if (!memcmp(skb->data, sync_req, 0x2)) { + RS_INFO("[CONFIG] Get SYNC pkt"); + len = write(rtb_cfg.serial_fd, sync_resp_pkt, 0x8); + if (len != 0x08) + RS_ERR("Send h5 sync resp error, %s", + strerror(errno)); + } else if (!memcmp(skb->data, conf_req, 0x2)) { + RS_INFO("[CONFIG] Get CONFG pkt"); + len = write(rtb_cfg.serial_fd, conf_resp_pkt, 0x8); + if (len != 0x08) + RS_ERR("Send h5 sync resp to ctl error, %s", + strerror(errno)); + } else if (!memcmp(skb->data, conf_resp, 0x2)) { + RS_INFO("[CONFIG] Get CONFG resp pkt"); + /* Change state to H5_INIT after receiving a conf resp + */ + rtb_cfg.link_estab_state = H5_INIT; + if (skb->data_len > 2) { + rtb_cfg.use_crc = ((skb->data[2]) >> 4) & 0x01; + RS_INFO("dic is %u, cfg field 0x%02x", + rtb_cfg.use_crc, skb->data[2]); + } + } else { + RS_WARN("[CONFIG] Get unknown pkt"); + rtb_send_ack(rtb_cfg.serial_fd); + } + } +} + +/* + * Process the received complete h5 packet + */ +static void h5_complete_rx_pkt(struct rtb_struct *h5) +{ + int pass_up = 1; + uint8_t *h5_hdr = NULL; + + h5_hdr = (uint8_t *) (h5->rx_skb->data); + if (H5_HDR_RELIABLE(h5_hdr)) { + /* RS_DBG("Received reliable seqno %u from card", h5->rxseq_txack); + */ + h5->rxseq_txack = H5_HDR_SEQ(h5_hdr) + 1; + /* h5->rxseq_txack %= 8; */ + h5->rxseq_txack &= 0x07; + h5->is_txack_req = 1; + } + + h5->rxack = H5_HDR_ACK(h5_hdr); + + switch (H5_HDR_PKT_TYPE(h5_hdr)) { + case HCI_ACLDATA_PKT: + case HCI_EVENT_PKT: + case HCI_COMMAND_PKT: + /* h5_remove_acked_pkt(h5); */ + pass_up = 1; + break; + case HCI_SCODATA_PKT: + pass_up = 1; + break; + case H5_LINK_CTL_PKT: + pass_up = 0; + skb_pull(h5->rx_skb, H5_HDR_SIZE); + h5_handle_internal_rx(h5->rx_skb); + break; + default: /* Pure ack or other unexpected pkt */ + pass_up = 0; + break; + } + + if (pass_up) { + skb_pull(h5->rx_skb, H5_HDR_SIZE); + hci_recv_frame(h5->rx_skb); + } + + if (h5->is_txack_req) { + rtb_send_ack(rtb_cfg.serial_fd); + h5->is_txack_req = 0; + } + + skb_free(h5->rx_skb); + + h5->rx_state = H5_W4_PKT_DELIMITER; + h5->rx_skb = NULL; +} + +/* + * Parse the receive data in h5 proto. + */ +static int h5_recv(struct rtb_struct *h5, void *data, int count) +{ + unsigned char *ptr; + ptr = (unsigned char *)data; + + while (count) { + if (h5->rx_count) { + if (*ptr == 0xc0) { + RS_ERR("Short h5 packet"); + skb_free(h5->rx_skb); + h5->rx_state = H5_W4_PKT_START; + h5->rx_count = 0; + } else + h5_unslip_one_byte(h5, *ptr); + + ptr++; + count--; + continue; + } + + switch (h5->rx_state) { + case H5_W4_HDR: + /* Check header checksum */ + if ((0xff & (uint8_t)~(h5->rx_skb->data[0] + h5->rx_skb->data[1] + + h5->rx_skb->data[2])) != h5->rx_skb->data[3]) { + RS_ERR("h5 hdr checksum error"); + skb_free(h5->rx_skb); + h5->rx_state = H5_W4_PKT_DELIMITER; + h5->rx_count = 0; + continue; + } + + /* The received seq number is unexpected */ + if (h5->rx_skb->data[0] & 0x80 && + (h5->rx_skb->data[0] & 0x07) != h5->rxseq_txack) { + uint8_t rxseq_txack = (h5->rx_skb->data[0] & 0x07); + RS_ERR("Out-of-order packet arrived, got(%u)expected(%u)", + h5->rx_skb->data[0] & 0x07, + h5->rxseq_txack); + h5->is_txack_req = 1; + + skb_free(h5->rx_skb); + h5->rx_state = H5_W4_PKT_DELIMITER; + h5->rx_count = 0; + + /* Depend on whether Controller will reset ack + * number or not + */ + if (rtb_cfg.link_estab_state == H5_PATCH && + rtb_cfg.tx_index == rtb_cfg.total_num) + rtb_cfg.rxseq_txack = rxseq_txack; + + continue; + } + h5->rx_state = H5_W4_DATA; + h5->rx_count = + (h5->rx_skb->data[1] >> 4) + + (h5->rx_skb->data[2] << 4); + continue; + + case H5_W4_DATA: + /* Packet with crc */ + if (h5->rx_skb->data[0] & 0x40) { + h5->rx_state = H5_W4_CRC; + h5->rx_count = 2; + } else { + h5_complete_rx_pkt(h5); + } + continue; + + case H5_W4_CRC: + if (bit_rev16(h5->message_crc) != h5_get_crc(h5)) { + RS_ERR("Checksum failed, computed %04x received %04x", + bit_rev16(h5->message_crc), + h5_get_crc(h5)); + skb_free(h5->rx_skb); + h5->rx_state = H5_W4_PKT_DELIMITER; + h5->rx_count = 0; + continue; + } + skb_trim(h5->rx_skb, h5->rx_skb->data_len - 2); + h5_complete_rx_pkt(h5); + continue; + + case H5_W4_PKT_DELIMITER: + switch (*ptr) { + case 0xc0: + h5->rx_state = H5_W4_PKT_START; + break; + + default: + break; + } + ptr++; + count--; + break; + + case H5_W4_PKT_START: + switch (*ptr) { + case 0xc0: + ptr++; + count--; + break; + + default: + h5->rx_state = H5_W4_HDR; + h5->rx_count = 4; + h5->rx_esc_state = H5_ESCSTATE_NOESC; + H5_CRC_INIT(h5->message_crc); + + /* Do not increment ptr or decrement count + * Allocate packet. Max len of a H5 pkt= + * 0xFFF (payload) +4 (header) +2 (crc) + */ + h5->rx_skb = skb_alloc(0x1005); + if (!h5->rx_skb) { + RS_ERR("Can't alloc skb for new pkt"); + h5->rx_state = H5_W4_PKT_DELIMITER; + h5->rx_count = 0; + return 0; + } + break; + } + break; + + default: + break; + } + } + return count; +} + +static const char *op_string(uint32_t op) +{ + switch (op) { + case OP_SET_BAUD: + return "OP_SET_BAUD"; + case OP_H5_SYNC: + return "OP_H5_SYNC"; + case OP_H5_CONFIG: + return "OP_H5_CONFIG"; + case OP_HCI_RESET: + return "OP_HCI_RESET"; + case OP_CHIP_TYPE: + return "OP_CHIP_TYPE"; + case OP_ROM_VER: + return "OP_ROM_VER"; + case OP_LMP_VER: + return "OP_LMP_VER"; + default: + return "OP_UNKNOWN"; + } +} + +static int start_transmit_wait(int fd, struct sk_buff *skb, + uint32_t op, unsigned int msec, int retry) +{ + unsigned char buf[128]; + ssize_t result; + struct iovec iov; + ssize_t ret; + uint8_t *data; + int len; + int op_result = -1; + uint64_t expired; + int n; + struct epoll_event events[MAX_EVENTS]; + int nfds; + uint16_t opcode = 0; + + if (fd == -1 || !skb) { + RS_ERR("Invalid parameter"); + return -1; + } + + data = skb->data; + len = skb->data_len; + + if (op & (1 << 24)) { + opcode = (op & 0xffff); + if (opcode != rtb_cfg.cmd_state.opcode || + rtb_cfg.cmd_state.state != CMD_STATE_UNKNOWN) { + RS_ERR("Invalid opcode or cmd state"); + return -1; + } + } + + iov.iov_base = data; + iov.iov_len = len; + do { + ret = writev(fd, &iov, 1); + if (ret != len) + RS_WARN("Writev partially, ret %d", (int)ret); + } while (ret < 0 && errno == EINTR); + + if (ret < 0) { + RS_ERR("Call writev error, %s", strerror(errno)); + return -errno; + } + + /* Set timeout */ + if (rtb_cfg.timerfd > 0) + timeout_set(rtb_cfg.timerfd, msec); + + do { + nfds = epoll_wait(rtb_cfg.epollfd, events, MAX_EVENTS, msec); + if (nfds == -1) { + RS_ERR("epoll_wait, %s (%d)", strerror(errno), errno); + exit(EXIT_FAILURE); + } + + for (n = 0; n < nfds; ++n) { + if (events[n].data.fd == rtb_cfg.serial_fd) { + if (events[n].events & (EPOLLERR | EPOLLHUP | + EPOLLRDHUP)) { + RS_ERR("%s: Error happens on serial fd", + __func__); + exit(EXIT_FAILURE); + } + result = read(events[n].data.fd, buf, + sizeof(buf)); + if (result <= 0) { + RS_ERR("Read serial error, %s", + strerror(errno)); + continue; + } else { + h5_recv(&rtb_cfg, buf, result); + } + } else if (events[n].data.fd == rtb_cfg.timerfd) { + if (events[n].events & (EPOLLERR | EPOLLHUP | + EPOLLRDHUP)) { + RS_ERR("%s: Error happens on timer fd", + __func__); + exit(EXIT_FAILURE); + } + RS_WARN("%s Transmission timeout", + op_string(op)); + result = read(events[n].data.fd, &expired, + sizeof(expired)); + if (result != sizeof(expired)) { + RS_ERR("Skip retransmit"); + break; + } + if (retry <= 0) { + RS_ERR("Retransmission exhausts"); + tcflush(fd, TCIOFLUSH); + exit(EXIT_FAILURE); + } + + iov.iov_base = data; + iov.iov_len = len; + + do { + ret = writev(fd, &iov, 1); + if (ret != len) + RS_WARN("Writev partial, %d", + (int)ret); + } while (ret < 0 && errno == EINTR); + + if (ret < 0) { + RS_ERR("ReCall writev error, %s", + strerror(errno)); + return -errno; + } + + retry--; + timeout_set(rtb_cfg.timerfd, msec); + } + } + + if (!(op & (1 << 24))) { + /* h5 sync or config */ + if (op == OP_H5_SYNC && rtb_cfg.link_estab_state == + H5_CONFIG) { + op_result = 0; + break; + } + + if (op == OP_H5_CONFIG && rtb_cfg.link_estab_state == + H5_INIT) { + op_result = 0; + break; + } + continue; + } + + if (rtb_cfg.cmd_state.opcode == opcode && + rtb_cfg.cmd_state.state == CMD_STATE_SUCCESS) { + op_result = 0; + break; + } + } while (1); + + /* Disarms timer */ + timeout_set(rtb_cfg.timerfd, 0); + + return op_result; +} + +static int h5_download_patch(int dd, int index, uint8_t *data, int len, + struct termios *ti) +{ + unsigned char buf[64]; + int retlen; + struct iovec iov; + ssize_t ret; + int nfds; + struct epoll_event events[MAX_EVENTS]; + int n; + int timeout; + uint64_t expired; + int retry = 3; + struct sk_buff *nskb; + uint8_t hci_patch[PATCH_DATA_FIELD_MAX_SIZE + 4]; + + if (index & 0x80) { + rtb_cfg.tx_index = index & 0x7f; + timeout = 1000; + } else { + rtb_cfg.tx_index = index; + timeout = 800; + } + + /* download cmd: 0xfc20 */ + hci_patch[0] = 0x20; + hci_patch[1] = 0xfc; + hci_patch[2] = len + 1; + hci_patch[3] = (uint8_t)index; + if (data) + memcpy(&hci_patch[4], data, len); + + /* length: 2-byte opcode + 1-byte len + 1-byte index + payload */ + nskb = h5_prepare_pkt(&rtb_cfg, hci_patch, len + 4, HCI_COMMAND_PKT); + if (!nskb) { + RS_ERR("Prepare command packet for download"); + return -1; + } + + /* Save pkt address and length for re-transmission */ + len = nskb->data_len; + data = nskb->data; + + iov.iov_base = nskb->data; + iov.iov_len = nskb->data_len; + do { + ret = writev(dd, &iov, 1); + if (ret != len) + RS_WARN("Writev partially, ret %d", (int)ret); + } while (ret < 0 && errno == EINTR); + + if (ret < 0) { + RS_ERR("Call writev error, %s", strerror(errno)); + skb_free(nskb); + return -errno; + } + + /* RS_INFO("%s: tx_index %d, rx_index %d", __func__, + * rtb_cfg.tx_index, rtb_cfg.rx_index); + */ + + if (index & 0x80) { + /* For the last pkt, wait for its complete */ + tcdrain(dd); + + if (rtb_cfg.uart_flow_ctrl) { + RS_INFO("Enable host hw flow control"); + ti->c_cflag |= CRTSCTS; + } else { + RS_INFO("Disable host hw flow control"); + ti->c_cflag &= ~CRTSCTS; + } + + if (tcsetattr(dd, TCSANOW, ti) < 0) { + RS_ERR("Can't set port settings"); + skb_free(nskb); + return -1; + } + + /* RS_INFO("Change baud to %d", rtb_cfg.final_speed); + * if (set_speed(dd, ti, rtb_cfg.final_speed) < 0) { + * RS_ERR("Set final speed %d error", + * rtb_cfg.final_speed); + * } + */ + } + + if (rtb_cfg.timerfd > 0) + timeout_set(rtb_cfg.timerfd, timeout); + + do { + nfds = epoll_wait(rtb_cfg.epollfd, events, MAX_EVENTS, -1); + if (nfds == -1) { + RS_ERR("epoll_wait, %s (%d)", strerror(errno), errno); + exit(EXIT_FAILURE); + } + + for (n = 0; n < nfds; ++n) { + if (events[n].data.fd == dd) { + if (events[n].events & (EPOLLERR | EPOLLHUP | + EPOLLRDHUP)) { + RS_ERR("%s: Error happens on serial fd", + __func__); + exit(EXIT_FAILURE); + } + retlen = read(dd, buf, sizeof(buf)); + if (retlen <= 0) { + RS_ERR("Read serial error, %s", strerror(errno)); + continue; + } else { + h5_recv(&rtb_cfg, buf, retlen); + } + } else if (events[n].data.fd == rtb_cfg.timerfd) { + int fd = events[n].data.fd; + + if (events[n].events & (EPOLLERR | EPOLLHUP | + EPOLLRDHUP)) { + RS_ERR("%s: Error happens on timer fd", + __func__); + exit(EXIT_FAILURE); + } + RS_WARN("Patch pkt trans timeout, re-trans"); + ret = read(fd, &expired, sizeof(expired)); + if (ret != sizeof(expired)) { + RS_ERR("Read expired info error"); + exit(EXIT_FAILURE); + } + if (retry <= 0) { + RS_ERR("%s: Retransmission exhausts", + __func__); + tcflush(fd, TCIOFLUSH); + exit(EXIT_FAILURE); + } + + iov.iov_base = data; + iov.iov_len = len; + + do { + ret = writev(dd, &iov, 1); + if (ret != len) + RS_WARN("Writev partial, %d", + (int)ret); + } while (ret < 0 && errno == EINTR); + + if (ret < 0) { + RS_ERR("ReCall writev error, %s", + strerror(errno)); + skb_free(nskb); + return -errno; + } + + retry--; + timeout_set(fd, timeout); + } + } + } while (rtb_cfg.rx_index != rtb_cfg.tx_index); + + /* Disarms timer */ + if (rtb_cfg.timerfd > 0) + timeout_set(rtb_cfg.timerfd, 0); + + skb_free(nskb); + return 0; +} + +/* + * Change the Controller's UART speed. + */ +int h5_vendor_change_speed(int fd, uint32_t baudrate) +{ + struct sk_buff *nskb = NULL; + unsigned char cmd[16] = { 0 }; + int result; + + cmd[0] = 0x17; + cmd[1] = 0xfc; + cmd[2] = 4; + + baudrate = cpu_to_le32(baudrate); +#ifdef BAUDRATE_4BYTES + memcpy((uint16_t *) & cmd[3], &baudrate, 4); +#else + memcpy((uint16_t *) & cmd[3], &baudrate, 2); + + cmd[5] = 0; + cmd[6] = 0; +#endif + + RS_DBG("baudrate in change speed command: 0x%02x 0x%02x 0x%02x 0x%02x", + cmd[3], cmd[4], cmd[5], cmd[6]); + + nskb = h5_prepare_pkt(&rtb_cfg, cmd, 7, HCI_COMMAND_PKT); + if (!nskb) { + RS_ERR("Prepare command packet for change speed fail"); + return -1; + } + + rtb_cfg.cmd_state.opcode = HCI_VENDOR_CHANGE_BAUD;; + rtb_cfg.cmd_state.state = CMD_STATE_UNKNOWN; + result = start_transmit_wait(fd, nskb, OP_SET_BAUD, 1000, 0); + skb_free(nskb); + if (result < 0) { + RS_ERR("OP_SET_BAUD Transmission error"); + return result; + } + + return 0; +} + +/* + * Init realtek Bluetooth h5 proto. + * There are two steps: h5 sync and h5 config. + */ +int rtb_init_h5(int fd, struct termios *ti) +{ + struct sk_buff *nskb; + unsigned char h5sync[2] = { 0x01, 0x7E }; + /* 16-bit CCITT CRC may be used and the sliding win size is 4 */ + unsigned char h5conf[3] = { 0x03, 0xFC, 0x14 }; + int result; + + /* Disable CRTSCTS by default */ + ti->c_cflag &= ~CRTSCTS; + + /* set even parity */ + ti->c_cflag |= PARENB; + ti->c_cflag &= ~(PARODD); + if (tcsetattr(fd, TCSANOW, ti) < 0) { + RS_ERR("Can't set port settings"); + return -1; + } + + /* h5 sync */ + rtb_cfg.link_estab_state = H5_SYNC; + nskb = h5_prepare_pkt(&rtb_cfg, h5sync, sizeof(h5sync), + H5_LINK_CTL_PKT); + result = start_transmit_wait(fd, nskb, OP_H5_SYNC, 500, 10); + skb_free(nskb); + if (result < 0) { + RS_ERR("OP_H5_SYNC Transmission error"); + return -1; + } + + /* h5 config */ + nskb = h5_prepare_pkt(&rtb_cfg, h5conf, sizeof(h5conf), H5_LINK_CTL_PKT); + result = start_transmit_wait(fd, nskb, OP_H5_CONFIG, 500, 10); + skb_free(nskb); + if (result < 0) { + RS_ERR("OP_H5_CONFIG Transmission error"); + return -1; + } + + rtb_send_ack(fd); + RS_DBG("H5 init finished\n"); + + rtb_cfg.cmd_state.state = CMD_STATE_UNKNOWN; + + return 0; +} + +static int h5_hci_reset(int fd) +{ + uint8_t cmd[3] = { 0x03, 0x0c, 0x00}; + struct sk_buff *nskb; + int result; + + RS_INFO("%s: Issue hci reset cmd", __func__); + + nskb = h5_prepare_pkt(&rtb_cfg, cmd, sizeof(cmd), HCI_COMMAND_PKT); + if (!nskb) { + RS_ERR("%s: Failed to alloc mem for hci reset skb", __func__); + return -1; + } + + rtb_cfg.cmd_state.opcode = HCI_CMD_RESET; + rtb_cfg.cmd_state.state = CMD_STATE_UNKNOWN; + + result = start_transmit_wait(fd, nskb, OP_HCI_RESET, 1500, 1); + skb_free(nskb); + if (result < 0) + RS_ERR("hci reset failed"); + + return result; +} + +#ifdef SERIAL_NONBLOCK_READ +static int set_fd_nonblock(int fd) +{ + long arg; + int old_fl; + + arg = fcntl(fd, F_GETFL); + if (arg < 0) + return -errno; + + /* Return if already nonblock */ + if (arg & O_NONBLOCK) + return FD_NONBLOCK; + old_fl = FD_BLOCK; + + arg |= O_NONBLOCK; + if (fcntl(fd, F_SETFL, arg) < 0) + return -errno; + + return old_fl; +} + +static int set_fd_block(int fd) +{ + long arg; + + arg = fcntl(fd, F_GETFL); + if (arg < 0) + return -errno; + + /* Return if already block */ + if (!(arg & O_NONBLOCK)) + return 0; + + arg &= ~O_NONBLOCK; + if (fcntl(fd, F_SETFL, arg) < 0) + return -errno; + + return 0; +} +#endif + +/* + * Download Realtek Firmware and Config + */ +static int rtb_download_fwc(int fd, uint8_t *buf, int size, int proto, + struct termios *ti) +{ + uint8_t curr_idx = 0; + uint8_t curr_len = 0; + uint8_t lp_len = 0; + uint8_t add_pkts = 0; + uint16_t end_idx = 0; + uint16_t total_idx = 0; + uint16_t num; + unsigned char *pkt_buf; + uint16_t i, j; + int result; +#ifdef SERIAL_NONBLOCK_READ + int old_fl; +#endif + + end_idx = (uint16_t)((size - 1) / PATCH_DATA_FIELD_MAX_SIZE); + lp_len = size % PATCH_DATA_FIELD_MAX_SIZE; + + num = rtb_cfg.num_of_cmd_sent; + num += end_idx + 1; + + add_pkts = num % 8 ? (8 - num % 8) : 0; + +#ifdef SERIAL_NONBLOCK_READ + old_fl = set_fd_nonblock(fd); + if (old_fl < 0) { + RS_ERR("Set fd nonblock error, %s", strerror(errno)); + } + if (old_fl == FD_BLOCK) + RS_INFO("old fd state is block"); +#endif + + /* Make sure the next seqno is zero after download patch and + * hci reset + */ + if (proto == HCI_UART_3WIRE) { + if (add_pkts) + add_pkts -= 1; + else + add_pkts += 7; + } else + add_pkts = 0; /* No additional packets need */ + + total_idx = add_pkts + end_idx; + rtb_cfg.total_num = total_idx; + + RS_INFO("end_idx: %u, lp_len: %u, additional pkts: %u\n", end_idx, + lp_len, add_pkts); + RS_INFO("Start downloading..."); + + if (lp_len == 0) + lp_len = PATCH_DATA_FIELD_MAX_SIZE; + + pkt_buf = buf; + + for (i = 0; i <= total_idx; i++) { + /* Index will roll over when it reaches 0x80 + * 0, 1, 2, 3, ..., 126, 127(7f), 1, 2, 3, ... + */ + if (i > 0x7f) + j = (i & 0x7f) + 1; + else + j = i; + + if (i < end_idx) { + curr_idx = j; + curr_len = PATCH_DATA_FIELD_MAX_SIZE; + } else if (i == end_idx) { + /* Send last data packets */ + if (i == total_idx) + curr_idx = j | 0x80; + else + curr_idx = j; + curr_len = lp_len; + } else if (i < total_idx) { + /* Send additional packets */ + curr_idx = j; + pkt_buf = NULL; + curr_len = 0; + RS_INFO("Send additional packet %u", curr_idx); + } else { + /* Send last packet */ + curr_idx = j | 0x80; + pkt_buf = NULL; + curr_len = 0; + RS_INFO("Last packet %u", curr_idx); + } + + if (curr_idx & 0x80) + RS_INFO("Send last pkt"); + + if (proto == HCI_UART_H4) { + curr_idx = h4_download_patch(fd, curr_idx, pkt_buf, + curr_len); + if (curr_idx != j && i != total_idx) { + RS_ERR("Index mismatch %u, curr_idx %u", j, + curr_idx); + return -1; + } + } else if (proto == HCI_UART_3WIRE) { + if (h5_download_patch(fd, curr_idx, pkt_buf, curr_len, + ti) < 0) + return -1; + } + + if (curr_idx < end_idx) { + pkt_buf += PATCH_DATA_FIELD_MAX_SIZE; + } + } + + /* Make hci reset after Controller applies the Firmware and Config */ + if (proto == HCI_UART_H4) + result = h4_hci_reset(fd); + else + result = h5_hci_reset(fd); + + if (proto == HCI_UART_3WIRE) { + /* Make sure the last pure ack is sent */ + tcdrain(fd); + } + + if (result) + return result; + + +#ifdef SERIAL_NONBLOCK_READ + if (old_fl == FD_BLOCK) + set_fd_block(fd); +#endif + + return 0; +} + +#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]) ) +struct rtb_baud { + uint32_t rtb_speed; + int uart_speed; +}; + +#ifdef BAUDRATE_4BYTES +struct rtb_baud baudrates[] = { +#ifdef RTL_8703A_SUPPORT + {0x00004003, 1500000}, /* for rtl8703as */ +#endif + {0x0252C014, 115200}, + {0x0252C00A, 230400}, + {0x05F75004, 921600}, + {0x00005004, 1000000}, + {0x04928002, 1500000}, + {0x01128002, 1500000}, //8761AT + {0x00005002, 2000000}, + {0x0000B001, 2500000}, + {0x04928001, 3000000}, + {0x052A6001, 3500000}, + {0x00005001, 4000000}, +}; +#else +struct rtb_baud baudrates[] = { + {0x701d, 115200} + {0x6004, 921600}, + {0x4003, 1500000}, + {0x5002, 2000000}, + {0x8001, 3000000}, + {0x9001, 3000000}, + {0x7001, 3500000}, + {0x5001, 4000000}, +}; +#endif + +static void vendor_speed_to_std(uint32_t rtb_speed, uint32_t *uart_speed) +{ + *uart_speed = 115200; + + unsigned int i; + for (i = 0; i < ARRAY_SIZE(baudrates); i++) { + if (baudrates[i].rtb_speed == rtb_speed) { + *uart_speed = baudrates[i].uart_speed; + return; + } + } + return; +} + +static inline void std_speed_to_vendor(int uart_speed, uint32_t *rtb_speed) +{ + *rtb_speed = 0x701D; + + unsigned int i; + for (i = 0; i < ARRAY_SIZE(baudrates); i++) { + if (baudrates[i].uart_speed == uart_speed) { + *rtb_speed = baudrates[i].rtb_speed; + return; + } + } + + return; +} + +void rtb_read_chip_type(int dd) +{ + /* 0xB000A094 */ + unsigned char cmd_buff[] = { + 0x61, 0xfc, 0x05, 0x00, 0x94, 0xa0, 0x00, 0xb0 + }; + struct sk_buff *nskb; + int result; + + nskb = h5_prepare_pkt(&rtb_cfg, cmd_buff, sizeof(cmd_buff), + HCI_COMMAND_PKT); + if (!nskb) { + RS_ERR("Alloc chip type cmd skb buff error"); + exit(EXIT_FAILURE); + } + + rtb_cfg.cmd_state.opcode = HCI_VENDOR_READ_CHIP_TYPE; + rtb_cfg.cmd_state.state = CMD_STATE_UNKNOWN; + result = start_transmit_wait(dd, nskb, OP_CHIP_TYPE, 250, 3); + skb_free(nskb); + if (result < 0) + RS_ERR("OP_CHIP_TYPE Transmission error"); + + return; +} + +/* + * Read ECO version with vendor cmd 0xfc65 + */ +void rtb_read_eversion(int dd) +{ + int result; + unsigned char cmd_buf[3] = { 0x6d, 0xfc, 0x00 }; + struct sk_buff *nskb; + + nskb= h5_prepare_pkt(&rtb_cfg, cmd_buf, 3, HCI_COMMAND_PKT); + if (!nskb) { + RS_ERR("Alloc eversion cmd skb buff error"); + exit(EXIT_FAILURE); + } + + rtb_cfg.cmd_state.opcode = HCI_VENDOR_READ_ROM_VER; + rtb_cfg.cmd_state.state = CMD_STATE_UNKNOWN; + result = start_transmit_wait(dd, nskb, OP_ROM_VER, 500, 3); + skb_free(nskb); + if (result < 0) { + RS_ERR("OP_ROM_VER Transmit error"); + } + + return; +} + +void rtb_read_local_version(int dd) +{ + int result; + unsigned char cmd_buf[3] = { 0x01, 0x10, 0x00 }; + struct sk_buff *nskb; + + nskb = h5_prepare_pkt(&rtb_cfg, cmd_buf, 3, HCI_COMMAND_PKT); + if (!nskb) { + RS_ERR("Alloc local ver cmd skb buff error"); + exit(EXIT_FAILURE); + } + + rtb_cfg.cmd_state.state = CMD_STATE_UNKNOWN; + rtb_cfg.cmd_state.opcode = HCI_CMD_READ_LOCAL_VER; + result = start_transmit_wait(dd, nskb, OP_LMP_VER, 500, 3); + skb_free(nskb); + if (result < 0) { + RS_ERR("OP_LMP_VER Transmit error"); + } + + return; +} + +/* + * Config Realtek Bluetooth. + * Config parameters are got from Realtek Config file and FW. + * + * speed is the init_speed in uart struct + * Returns 0 on success + */ +static int rtb_config(int fd, int proto, int speed, struct termios *ti) +{ + int final_speed = 0; + int ret = 0; + int max_patch_size = 0; + + rtb_cfg.proto = proto; + + /* Read Local Version Information and RTK ROM version */ + if (proto == HCI_UART_3WIRE) { + RS_INFO("Realtek H5 IC"); + rtb_read_local_version(fd); + rtb_read_eversion(fd); + } else { + RS_INFO("Realtek H4 IC"); + + /* The following set is for special requirement that enables + * flow control before initializing */ +#ifdef RTL8723DSH4_UART_HWFLOWC + ti->c_cflag &= ~PARENB; + ti->c_cflag |= CRTSCTS; + if (tcsetattr(fd, TCSANOW, ti) < 0) { + RS_ERR("H4 Can't enable RTSCTS"); + return -1; + } + usleep(20 * 1000); +#endif + h4_read_local_ver(fd); + h4_vendor_read_rom_ver(fd); + if (rtb_cfg.lmp_subver == ROM_LMP_8761btc) { + /* 8761B Test Chip */ + rtb_cfg.chip_type = CHIP_8761BTC; + rtb_cfg.uart_flow_ctrl = 1; + /* TODO: Change to different uart baud */ + std_speed_to_vendor(1500000, &rtb_cfg.vendor_baud); + goto change_baud; + } else if (rtb_cfg.lmp_subver == ROM_LMP_8761a) { + if (rtb_cfg.hci_rev == 0x000b) { + /* 8761B Test Chip without download */ + rtb_cfg.chip_type = CHIP_8761BH4; + /* rtb_cfg.uart_flow_ctrl = 1; */ + /* TODO: Change to different uart baud */ + /* std_speed_to_vendor(1500000, &rtb_cfg.vendor_baud); + * goto change_baud; + */ + } else if (rtb_cfg.hci_rev == 0x000a) { + if (rtb_cfg.eversion == 3) + rtb_cfg.chip_type = CHIP_8761ATF; + else if (rtb_cfg.eversion == 2) + rtb_cfg.chip_type = CHIP_8761AT; + else + rtb_cfg.chip_type = CHIP_UNKNOWN; + } + } else if (rtb_cfg.lmp_subver == ROM_LMP_8723b) { + if (rtb_cfg.hci_ver == 0x08 && + rtb_cfg.hci_rev == 0x000d) { + rtb_cfg.chip_type = CHIP_8723DS; + } else if (rtb_cfg.hci_ver == 0x06 && + rtb_cfg.hci_rev == 0x000b) { + rtb_cfg.chip_type = CHIP_8723BS; + } else { + RS_ERR("H4: unknown chip"); + return -1; + } + } + + } + + RS_INFO("LMP Subversion 0x%04x", rtb_cfg.lmp_subver); + RS_INFO("EVersion %u", rtb_cfg.eversion); + + switch (rtb_cfg.lmp_subver) { + case ROM_LMP_8723a: + break; + case ROM_LMP_8723b: +#ifdef RTL_8703A_SUPPORT + /* Set chip type for matching fw/config entry */ + rtl->chip_type = CHIP_8703AS; +#endif + break; + case ROM_LMP_8821a: + break; + case ROM_LMP_8761a: + break; + case ROM_LMP_8703b: + rtb_read_chip_type(fd); + break; + } + + rtb_cfg.patch_ent = get_patch_entry(&rtb_cfg); + if (rtb_cfg.patch_ent) { + RS_INFO("IC: %s", rtb_cfg.patch_ent->ic_name); + RS_INFO("Firmware/config: %s, %s", + rtb_cfg.patch_ent->patch_file, + rtb_cfg.patch_ent->config_file); + } else { + RS_ERR("Can not find firmware/config entry"); + return -1; + } + + rtb_cfg.config_buf = rtb_read_config(rtb_cfg.patch_ent->config_file, + &rtb_cfg.config_len, + rtb_cfg.patch_ent->chip_type); + if (!rtb_cfg.config_buf) { + RS_ERR("Read Config file error, use eFuse settings"); + rtb_cfg.config_len = 0; + } + + rtb_cfg.fw_buf = rtb_read_firmware(&rtb_cfg, &rtb_cfg.fw_len); + if (!rtb_cfg.fw_buf) { + RS_ERR("Read Bluetooth firmware error"); + rtb_cfg.fw_len = 0; + /* Free config buf */ + if (rtb_cfg.config_buf) { + free(rtb_cfg.config_buf); + rtb_cfg.config_buf = NULL; + rtb_cfg.config_len = 0; + } + return -1; + } else { + rtb_cfg.total_buf = rtb_get_final_patch(fd, proto, + &rtb_cfg.total_len); + /* If the above function executes successfully, the Config and + * patch were copied to the total buf */ + + /* Free config buf */ + if (rtb_cfg.config_buf) { + free(rtb_cfg.config_buf); + rtb_cfg.config_buf = NULL; + } + /* Free the fw buf */ + free(rtb_cfg.fw_buf); + rtb_cfg.fw_buf = NULL; + rtb_cfg.fw_len = 0; + + if (!rtb_cfg.total_buf) { + RS_ERR("Failed to get the final patch"); + exit(EXIT_FAILURE); + } + } + + switch ((rtb_cfg.patch_ent)->chip_type) { + case CHIP_8822BS: + max_patch_size = 25 * 1024; + break; + case CHIP_8821CS: + case CHIP_8723DS: + case CHIP_8822CS: + case CHIP_8761B: + max_patch_size = 40 * 1024; + break; + default: + max_patch_size = 24 * 1024; + break; + } + + if (rtb_cfg.total_len > max_patch_size) { + RS_ERR("Total length of fwc is larger than allowed"); + goto buf_free; + } + + RS_INFO("Total len %d for fwc", rtb_cfg.total_len); + + /* rtl8723ds h4 */ + if (rtb_cfg.chip_type == CHIP_8723DS && + rtb_cfg.proto == HCI_UART_H4) { + if (rtb_cfg.parenb) { + /* set parity */ + ti->c_cflag |= PARENB; + if (rtb_cfg.pareven) + ti->c_cflag &= ~(PARODD); + else + ti->c_cflag |= PARODD; + if (tcsetattr(fd, TCSANOW, ti) < 0) { + RS_ERR("8723DSH4 Can't set parity"); + goto buf_free; + } + } + } + +change_baud: + /* change baudrate if needed + * rtb_cfg.vendor_baud is a __u32/__u16 vendor-specific variable + * parsed from config file + * */ + if (rtb_cfg.vendor_baud == 0) { + /* No baud setting in Config file */ + std_speed_to_vendor(speed, &rtb_cfg.vendor_baud); + RS_INFO("No baud from Config file, set baudrate: %d, 0x%08x", + speed, rtb_cfg.vendor_baud); + goto start_download; + } else + vendor_speed_to_std(rtb_cfg.vendor_baud, + (uint32_t *)&(rtb_cfg.final_speed)); + + if (rtb_cfg.final_speed == 115200) { + RS_INFO("Final speed is %d, no baud change needs", + rtb_cfg.final_speed); + goto start_download; + } + + if (proto == HCI_UART_3WIRE) + h5_vendor_change_speed(fd, rtb_cfg.vendor_baud); + else + h4_vendor_change_speed(fd, rtb_cfg.vendor_baud); + + /* Make sure the ack for cmd complete event is transmitted */ + tcdrain(fd); + usleep(50000); /* The same value as before */ + final_speed = rtb_cfg.final_speed ? rtb_cfg.final_speed : speed; + RS_INFO("Final speed %d", final_speed); + if (set_speed(fd, ti, final_speed) < 0) { + RS_ERR("Can't set baud rate: %d, %d, %d", final_speed, + rtb_cfg.final_speed, speed); + goto buf_free; + } + +start_download: + /* For 8761B Test chip, no patch to download */ + if (rtb_cfg.chip_type == CHIP_8761BTC) + goto done; + + if (rtb_cfg.total_len > 0 && rtb_cfg.dl_fw_flag) { + rtb_cfg.link_estab_state = H5_PATCH; + rtb_cfg.rx_index = -1; + + ret = rtb_download_fwc(fd, rtb_cfg.total_buf, rtb_cfg.total_len, + proto, ti); + free(rtb_cfg.total_buf); + if (ret < 0) + return ret; + } + +done: + + RS_DBG("Init Process finished"); + return 0; + +buf_free: + free(rtb_cfg.total_buf); + return -1; +} + +int rtb_init(int fd, int proto, int speed, struct termios *ti) +{ + struct epoll_event ev; + int result; + + RS_INFO("Realtek hciattach version %s \n", RTK_VERSION); + + memset(&rtb_cfg, 0, sizeof(rtb_cfg)); + rtb_cfg.serial_fd = fd; + rtb_cfg.dl_fw_flag = 1; + + rtb_cfg.epollfd = epoll_create(64); + if (rtb_cfg.epollfd == -1) { + RS_ERR("epoll_create1, %s (%d)", strerror(errno), errno); + exit(EXIT_FAILURE); + } + + ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLRDHUP; + ev.data.fd = fd; + if (epoll_ctl(rtb_cfg.epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) { + RS_ERR("epoll_ctl: epoll ctl add, %s (%d)", strerror(errno), + errno); + exit(EXIT_FAILURE); + } + + rtb_cfg.timerfd = timerfd_create(CLOCK_MONOTONIC, 0); + if (rtb_cfg.timerfd == -1) { + RS_ERR("timerfd_create error, %s (%d)", strerror(errno), errno); + return -1; + } + + if (rtb_cfg.timerfd > 0) { + ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLRDHUP; + ev.data.fd = rtb_cfg.timerfd; + if (epoll_ctl(rtb_cfg.epollfd, EPOLL_CTL_ADD, + rtb_cfg.timerfd, &ev) == -1) { + RS_ERR("epoll_ctl: epoll ctl add, %s (%d)", + strerror(errno), errno); + exit(EXIT_FAILURE); + } + } + + RS_INFO("Use epoll"); + + if (proto == HCI_UART_3WIRE) { + if (rtb_init_h5(fd, ti) < 0) + return -1;; + } + + result = rtb_config(fd, proto, speed, ti); + + epoll_ctl(rtb_cfg.epollfd, EPOLL_CTL_DEL, fd, NULL); + epoll_ctl(rtb_cfg.epollfd, EPOLL_CTL_DEL, rtb_cfg.timerfd, NULL); + close(rtb_cfg.timerfd); + rtb_cfg.timerfd = -1; + + return result; +} + +int rtb_post(int fd, int proto, struct termios *ti) +{ + /* No need to change baudrate */ + /* if (rtb_cfg.final_speed) + * return set_speed(fd, ti, rtb_cfg.final_speed); + */ + + return 0; +} diff --git a/buildroot-external/package/rtk-hciattach/src/rtb_fwc.c b/buildroot-external/package/rtk-hciattach/src/rtb_fwc.c new file mode 100644 index 00000000000..76affdc94e3 --- /dev/null +++ b/buildroot-external/package/rtk-hciattach/src/rtb_fwc.c @@ -0,0 +1,1233 @@ +/* + * Copyright (C) 2018 Realtek Semiconductor Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + +#include "hciattach.h" +#include "rtb_fwc.h" + +#define FIRMWARE_DIRECTORY "/lib/firmware/rtlbt/" +#define BT_CONFIG_DIRECTORY "/lib/firmware/rtlbt/" +#define EXTRA_CONFIG_FILE "/opt/rtk_btconfig.txt" +#define BT_ADDR_FILE "/opt/bdaddr" +#define BDADDR_STRING_LEN 17 + +struct list_head { + struct list_head *next, *prev; +}; + +struct cfg_list_item { + struct list_head list; + uint16_t offset; + uint8_t len; + uint8_t data[0]; +}; + +const uint8_t cfg_magic[4] = { 0x55, 0xab, 0x23, 0x87 }; +static struct list_head list_configs; +static struct list_head list_extracfgs; + +struct rtb_cfg_item { + uint16_t offset; + uint8_t len; + uint8_t data[0]; +} __attribute__ ((packed)); + +#define RTB_CFG_HDR_LEN 6 + +struct rtb_patch_entry { + uint16_t chip_id; + uint16_t patch_len; + uint32_t soffset; + uint32_t svn_ver; + uint32_t coex_ver; +} __attribute__ ((packed)); + +struct rtb_patch_hdr { + uint8_t signature[8]; + uint32_t fw_version; + uint16_t number_of_patch; + struct rtb_patch_entry entry[0]; +} __attribute__ ((packed)); + +uint16_t project_id[]= +{ + ROM_LMP_8723a, + ROM_LMP_8723b, /* RTL8723BS */ + ROM_LMP_8821a, /* RTL8821AS */ + ROM_LMP_8761a, /* RTL8761ATV */ + + ROM_LMP_8703a, + ROM_LMP_8763a, + ROM_LMP_8703b, + ROM_LMP_8723c, /* index 7 for 8723CS. What is for other 8723CS */ + ROM_LMP_8822b, /* RTL8822BS */ + ROM_LMP_8723b, /* RTL8723DS */ + ROM_LMP_8821a, /* id 10 for RTL8821CS, lmp subver 0x8821 */ + ROM_LMP_NONE, + ROM_LMP_NONE, + ROM_LMP_8822c, /* id 13 for RTL8822CS, lmp subver 0x8822 */ + ROM_LMP_8761a, /* id 14 for 8761B */ +}; + +static struct patch_info h4_patch_table[] = { + /* match flags, chip type, lmp subver, proj id(unused), hci_ver, + * hci_rev, ... + */ + + /* RTL8761AT */ + { RTL_FW_MATCH_CHIP_TYPE, CHIP_8761AT, + 0x8761, 0xffff, 0, 0x000a, + "rtl8761at_fw", "rtl8761at_config", "RTL8761AT" }, + /* RTL8761ATF */ + { RTL_FW_MATCH_CHIP_TYPE, CHIP_8761ATF, + 0x8761, 0xffff, 0, 0x000a, + "rtl8761atf_fw", "rtl8761atf_config", "RTL8761ATF" }, + /* RTL8761B(8763) H4 Test Chip without download + * FW/Config is not used. + */ + { RTL_FW_MATCH_CHIP_TYPE, CHIP_8761BTC, + 0x8763, 0xffff, 0, 0x000b, + "rtl8761btc_fw", "rtl8761btc_config", "RTL8761BTC" }, + /* RTL8761B H4 Test Chip wihtout download*/ + { RTL_FW_MATCH_CHIP_TYPE, CHIP_8761BH4, + 0x8761, 0xffff, 0, 0x000b, + "rtl8761bh4_fw", "rtl8761bh4_config", "RTL8761BH4" }, + + /* RTL8723DS */ + { RTL_FW_MATCH_HCI_VER | RTL_FW_MATCH_HCI_REV, CHIP_8723DS, + ROM_LMP_8723b, ROM_LMP_8723b, 8, 0x000d, + "rtl8723dsh4_fw", "rtl8723dsh4_config", "RTL8723DSH4"}, + + { 0, 0, 0, ROM_LMP_NONE, 0, 0, "rtl_none_fw", "rtl_none_config", "NONE"} +}; + +static struct patch_info patch_table[] = { + /* match flags, chip type, lmp subver, proj id(unused), hci_ver, + * hci_rev, ... + */ + + /* RTL8723AS */ + { 0, 0, ROM_LMP_8723a, ROM_LMP_8723a, 0, 0, + "rtl8723a_fw", "rtl8723a_config", "RTL8723AS"}, + /* RTL8821CS */ + { RTL_FW_MATCH_HCI_REV, CHIP_8821CS, + ROM_LMP_8821a, ROM_LMP_8821a, 0, 0x000c, + "rtl8821c_fw", "rtl8821c_config", "RTL8821CS"}, + /* RTL8821AS */ + { 0, 0, ROM_LMP_8821a, ROM_LMP_8821a, 0, 0, + "rtl8821a_fw", "rtl8821a_config", "RTL8821AS"}, + /* RTL8761ATV */ + { RTL_FW_MATCH_HCI_VER | RTL_FW_MATCH_HCI_REV, 0, + ROM_LMP_8761a, ROM_LMP_8761a, 0x06, 0x000a, + "rtl8761a_fw", "rtl8761a_config", "RTL8761ATV"}, + /* RTL8761BTV */ + { RTL_FW_MATCH_HCI_VER | RTL_FW_MATCH_HCI_REV, CHIP_8761B, + ROM_LMP_8761a, ROM_LMP_8761a, 0x0a, 0x000b, + "rtl8761b_fw", "rtl8761b_config", "RTL8761BTV"}, + + /* RTL8703AS + * RTL8822BS + * */ +#ifdef RTL_8703A_SUPPORT + { RTL_FW_MATCH_CHIP_TYPE, CHIP_8703AS, + ROM_LMP_8723b, ROM_LMP_8723b, 0, 0, + "rtl8703a_fw", "rtl8703a_config", "RTL8703AS"}, +#endif + { RTL_FW_MATCH_HCI_REV, CHIP_8822BS, + ROM_LMP_8822b, ROM_LMP_8822b, 0, 0x000b, + "rtl8822b_fw", "rtl8822b_config", "RTL8822BS"}, + { RTL_FW_MATCH_HCI_REV, CHIP_8822CS, + ROM_LMP_8822c, ROM_LMP_8822c, 0, 0x000c, + "rtl8822cs_fw", "rtl8822cs_config", "RTL8822CS"}, + + /* RTL8703BS + * RTL8723CS_XX + * RTL8723CS_CG + * RTL8723CS_VF + * Use the sampe lmp subversion 0x8703 + * */ + { RTL_FW_MATCH_CHIP_TYPE, CHIP_8703BS, + ROM_LMP_8703b, ROM_LMP_8703b, 0, 0, + "rtl8703b_fw", "rtl8703b_config", "RTL8703BS"}, + { RTL_FW_MATCH_CHIP_TYPE, CHIP_8723CS_XX, + ROM_LMP_8703b, ROM_LMP_8723cs_xx, 0, 0, + "rtl8723cs_fw", "rtl8723cs_config", "RTL8723CS_XX"}, + { RTL_FW_MATCH_CHIP_TYPE, CHIP_8723CS_CG, + ROM_LMP_8703b, ROM_LMP_8723cs_cg, 0, 0, + "rtl8723cs_fw", "rtl8723cs_config", "RTL8723CS_CG"}, + { RTL_FW_MATCH_CHIP_TYPE, CHIP_8723CS_VF, + ROM_LMP_8703b, ROM_LMP_8723cs_vf, 0, 0, + "rtl8723cs_fw", "rtl8723cs_config", "RTL8723CS_VF"}, + + /* RTL8723BS */ + { RTL_FW_MATCH_HCI_VER | RTL_FW_MATCH_HCI_REV, 0, + ROM_LMP_8723b, ROM_LMP_8723b, 6, 0x000b, + "rtl8723b_fw", "rtl8723b_config", "RTL8723BS"}, + /* RTL8723DS */ + { RTL_FW_MATCH_HCI_VER | RTL_FW_MATCH_HCI_REV, CHIP_8723DS, + ROM_LMP_8723b, ROM_LMP_8723b, 8, 0x000d, + "rtl8723d_fw", "rtl8723d_config", "RTL8723DS"}, + /* add entries here*/ + + { 0, 0, 0, ROM_LMP_NONE, 0, 0, "rtl_none_fw", "rtl_none_config", "NONE"} +}; + +static __inline uint16_t get_unaligned_le16(uint8_t * p) +{ + return (uint16_t) (*p) + ((uint16_t) (*(p + 1)) << 8); +} + +static __inline uint32_t get_unaligned_le32(uint8_t * p) +{ + return (uint32_t) (*p) + ((uint32_t) (*(p + 1)) << 8) + + ((uint32_t) (*(p + 2)) << 16) + ((uint32_t) (*(p + 3)) << 24); +} + +/* list head from kernel */ +#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER) + +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +static inline void __list_add(struct list_head *_new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = _new; + _new->next = next; + _new->prev = prev; + prev->next = _new; +} + +static inline void list_add_tail(struct list_head *_new, struct list_head *head) +{ + __list_add(_new, head->prev, head); +} + +static inline void __list_del(struct list_head *prev, struct list_head *next) +{ + next->prev = prev; + prev->next = next; +} + +#define LIST_POISON1 ((void *) 0x00100100) +#define LIST_POISON2 ((void *) 0x00200200) +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = (struct list_head*)LIST_POISON1; + entry->prev = (struct list_head*)LIST_POISON2; +} + +static inline void __list_splice(const struct list_head *list, + struct list_head *prev, + struct list_head *next) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + + first->prev = prev; + prev->next = first; + + last->next = next; + next->prev = last; +} + +static inline void list_splice_tail(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head->prev, head); +} + +static inline void list_replace(struct list_head *old, + struct list_head *new) +{ + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + +static inline void list_replace_init(struct list_head *old, + struct list_head *new) +{ + list_replace(old, new); + INIT_LIST_HEAD(old); +} + +static int config_lists_init(void) +{ + INIT_LIST_HEAD(&list_configs); + INIT_LIST_HEAD(&list_extracfgs); + + return 0; +} + +static void config_lists_free(void) +{ + struct list_head *iter; + struct list_head *tmp; + struct list_head *head; + struct cfg_list_item *n; + + if (!list_empty(&list_extracfgs)) + list_splice_tail(&list_extracfgs, &list_configs); + head = &list_configs; + list_for_each_safe(iter, tmp, head) { + n = list_entry(iter, struct cfg_list_item, list); + if (n) { + list_del(&n->list); + free(n); + } + } + + INIT_LIST_HEAD(&list_configs); + INIT_LIST_HEAD(&list_extracfgs); +} + +static void line_process(char *buf, int len /*@unused@*/) +{ + char *argv[32]; + int argc = 0; + char *ptr = buf; + char *head = buf; + unsigned long int offset; + uint8_t l; + uint8_t i = 0; + struct cfg_list_item *item; + + RS_INFO("%s", buf); + + while ((ptr = strsep(&head, ", \t")) != NULL) { + if (!ptr[0]) + continue; + argv[argc++] = ptr; + if (argc >= 32) { + RS_WARN("%s: Config item is too long", __func__); + break; + } + } + + if (argc < 4) { + RS_WARN("%s: Invalid Config item, ignore", __func__); + return; + } + + offset = strtoul(argv[0], NULL, 16); + offset = offset | (strtoul(argv[1], NULL, 16) << 8); + l = (uint8_t)strtoul(argv[2], NULL, 16); + if (l != (uint8_t)(argc - 3)) { + RS_ERR("Invalid Config item len %u", l); + return; + } + + item = malloc(sizeof(*item) + l); + if (!item) { + RS_WARN("%s: Cannot alloc mem for item, %04lx, %u", __func__, + offset, l); + return; + } + memset(item, 0, sizeof(*item)); + item->offset = (uint16_t)offset; + item->len = l; + for (i = 0; i < l; i++) + item->data[i] = (uint8_t)strtoul(argv[3 + i], NULL, 16); + list_add_tail(&item->list, &list_extracfgs); +} + +static void config_process(uint8_t *buf, int len /*@unused@*/) +{ + char *head = (void *)buf; + char *ptr = (void *)buf; + + while ((ptr = strsep(&head, "\n\r")) != NULL) { + if (!ptr[0]) + continue; + line_process(ptr, strlen(ptr) + 1); + } +} + +static void parse_extra_config(const char *path) +{ + int fd; + uint8_t buf[256]; + int result; + + fd = open(path, O_RDONLY); + if (fd == -1) { + RS_INFO("Couldnt open extra config %s, %s", path, + strerror(errno)); + return; + } + + result = read(fd, buf, sizeof(buf)); + if (result == -1) { + RS_ERR("Couldnt read %s, %s", path, strerror(errno)); + goto done; + } else if (result == 0) { + RS_ERR("File is empty"); + goto done; + } + + if (result > 254) { + RS_ERR("Extra Config file is too big"); + goto done; + } + buf[result++] = '\n'; + buf[result++] = '\0'; + + config_process(buf, result); + +done: + close(fd); +} + +/* Get the entry from patch_table according to LMP subversion */ +struct patch_info *get_patch_entry(struct rtb_struct *btrtl) +{ + struct patch_info *n = NULL; + + if (btrtl->proto == HCI_UART_3WIRE) + n = patch_table; + else + n = h4_patch_table; + for (; n->lmp_subver; n++) { + if ((n->match_flags & RTL_FW_MATCH_CHIP_TYPE) && + n->chip_type != btrtl->chip_type) + continue; + if ((n->match_flags & RTL_FW_MATCH_HCI_VER) && + n->hci_ver != btrtl->hci_ver) + continue; + if ((n->match_flags & RTL_FW_MATCH_HCI_REV) && + n->hci_rev != btrtl->hci_rev) + continue; + if (n->lmp_subver != btrtl->lmp_subver) + continue; + + break; + } + + return n; +} + +static int is_mac(uint8_t chip_type, uint16_t offset) +{ + int result = 0; + + switch (chip_type) { + case CHIP_8822BS: + case CHIP_8723DS: + case CHIP_8821CS: + case CHIP_8723CS_XX: + case CHIP_8723CS_CG: + case CHIP_8723CS_VF: + if (offset == 0x0044) + return 1; + break; + case CHIP_8822CS: + case CHIP_8761B: + if (offset == 0x0030) + return 1; + break; + case 0: /* special for not setting chip_type */ + case CHIP_8761AT: + case CHIP_8761ATF: + case CHIP_8761BTC: + case CHIP_8723BS: + if (offset == 0x003c) + return 1; + break; + default: + break; + } + + return result; +} + +static uint16_t get_mac_offset(uint8_t chip_type) +{ + switch (chip_type) { + case CHIP_8822BS: + case CHIP_8723DS: + case CHIP_8821CS: + return 0x0044; + case CHIP_8822CS: + case CHIP_8761B: + return 0x0030; + case 0: /* special for not setting chip_type */ + case CHIP_8761AT: + case CHIP_8761ATF: + case CHIP_8761BTC: + case CHIP_8723BS: + return 0x003c; + default: + return 0x003c; + } +} + +static void merge_configs(struct list_head *head, struct list_head *head2) +{ + struct list_head *epos, *enext; + struct list_head *pos, *next; + struct cfg_list_item *n; + struct cfg_list_item *extra; + + if (!head || !head2) + return; + + if (list_empty(head2)) + return; + + if (list_empty(head)) { + list_splice_tail(head2, head); + return; + } + + /* Add or update & replace */ + list_for_each_safe(epos, enext, head2) { + extra = list_entry(epos, struct cfg_list_item, list); + + list_for_each_safe(pos, next, head) { + n = list_entry(pos, struct cfg_list_item, list); + if (extra->offset == n->offset) { + if (extra->len < n->len) { + /* Update the cfg data */ + RS_INFO("Update cfg: ofs %04x len %u", + n->offset, n->len); + memcpy(n->data, extra->data, + extra->len); + list_del(epos); + free(extra); + } else { + /* Replace the item */ + list_del(epos); + list_replace_init(pos, epos); + /* free the old item */ + free(n); + } + } + + } + + } + + if (list_empty(head2)) + return; + list_for_each_safe(epos, enext, head2) { + extra = list_entry(epos, struct cfg_list_item, list); + RS_INFO("Add new cfg: ofs %04x, len %u", extra->offset, + extra->len); + /* Add the item to list */ + list_del(epos); + list_add_tail(epos, head); + } +} + +/* + * Parse realtek Bluetooth config file. + * The content starts with vendor magic: 55 ab 23 87 + */ +int rtb_parse_config(uint8_t *cfg_buf, size_t len) +{ + uint16_t cfg_len; + uint16_t tmp; + struct rtb_cfg_item *entry; + uint16_t i; + struct cfg_list_item *item; + + if (!cfg_buf || !len) { + RS_ERR("%s: Invalid parameter", __func__); + return -1; + } + + if (memcmp(cfg_buf, cfg_magic, 4)) { + RS_ERR("Signature %02x %02x %02x %02x is incorrect", + cfg_buf[0], cfg_buf[1], cfg_buf[2], cfg_buf[3]); + return -1; + } + + cfg_len = ((uint16_t)cfg_buf[5] << 8) + cfg_buf[4]; + if (cfg_len != len - RTB_CFG_HDR_LEN) { + RS_ERR("Config len %u is incorrect(%zd)", cfg_len, + len - RTB_CFG_HDR_LEN); + return -1; + } + + entry = (struct rtb_cfg_item *)(cfg_buf + 6); + i = 0; + while (i < cfg_len) { + /* Add config item to list */ + item = malloc(sizeof(*item) + entry->len); + if (item) { + memset(item, 0, sizeof(*item)); + item->offset = le16_to_cpu(entry->offset); + item->len = entry->len; + memcpy(item->data, entry->data, item->len); + list_add_tail(&item->list, &list_configs); + } else { + RS_ERR("Cannot alloc mem for entry %04x, %u", + entry->offset, entry->len); + } + + tmp = entry->len + sizeof(struct rtb_cfg_item); + i += tmp; + entry = (struct rtb_cfg_item *)((uint8_t *)entry + tmp); + } + + return 0; +} + +int bachk(const char *str) +{ + if (!str) + return -1; + + if (strlen(str) != 17) + return -1; + + while (*str) { + if (!isxdigit(*str++)) + return -1; + + if (!isxdigit(*str++)) + return -1; + + if (*str == 0) + break; + + if (*str++ != ':') + return -1; + } + + return 0; +} +/* + * Get random Bluetooth addr. + */ +/* static void rtb_get_ram_addr(char bt_addr[0]) + * { + * srand(time(NULL) + getpid() + getpid() * 987654 + rand()); + * + * uint32_t addr = rand(); + * memcpy(bt_addr, &addr, sizeof(uint8_t)); + * } + */ + +/* + * Write the random addr to the BT_ADDR_FILE. + */ +/* static void rtb_write_btmac2file(char bt_addr[6]) + * { + * int fd; + * fd = open(BT_ADDR_FILE, O_CREAT | O_RDWR | O_TRUNC); + * + * if (fd > 0) { + * chmod(BT_ADDR_FILE, 0666); + * char addr[18] = { 0 }; + * addr[17] = '\0'; + * sprintf(addr, "%2x:%2x:%2x:%2x:%2x:%2x", bt_addr[0], bt_addr[1], + * bt_addr[2], bt_addr[3], bt_addr[4], bt_addr[5]); + * write(fd, addr, strlen(addr)); + * close(fd); + * } else { + * RS_ERR("open file error:%s\n", BT_ADDR_FILE); + * } + * } + */ + +/* + * Read and parse Realtek Bluetooth Config file. + */ +uint8_t *rtb_read_config(const char *file, int *cfg_len, uint8_t chip_type) +{ + char *file_name; + struct stat st; + ssize_t file_len; + int fd; + uint8_t *buf; + size_t size; + size_t result; + struct list_head *pos, *next; + struct cfg_list_item *n; + uint16_t config_len; + uint16_t dlen; + uint32_t baudrate; + uint8_t *p; + + if (!file || !cfg_len) { + RS_ERR("%s: Invalid parameter", __func__); + return NULL; + } + + config_lists_init(); + + /* All extra configs will be added to list_extracfgs */ + parse_extra_config(EXTRA_CONFIG_FILE); + list_for_each_safe(pos, next, &list_extracfgs) { + n = list_entry(pos, struct cfg_list_item, list); + RS_INFO("extra cfg: ofs %04x, len %u", n->offset, n->len); + } + + if (stat(BT_ADDR_FILE, &st) < 0) { + RS_INFO("Couldnt access customer BT MAC file %s", + BT_ADDR_FILE); + + goto read_cfg; + } + + size = st.st_size; + /* Only read the first 17-byte if the file length is larger */ + if (size > BDADDR_STRING_LEN) + size = BDADDR_STRING_LEN; + + fd = open(BT_ADDR_FILE, O_RDONLY); + if (fd == -1) { + RS_INFO("Couldnt open BT MAC file %s, %s", BT_ADDR_FILE, + strerror(errno)); + } else { + uint16_t ofs; + char *str; + int i = 0; + uint8_t bdaddr[6]; + uint8_t tbuf[BDADDR_STRING_LEN + 1]; + + memset(tbuf, 0, sizeof(tbuf)); + result = read(fd, tbuf, size); + close(fd); + if (result == -1) { + RS_ERR("Couldnt read BT MAC file %s, err %s", + BT_ADDR_FILE, strerror(errno)); + goto read_cfg; + } + + if (bachk((const char *)tbuf) < 0) { + goto read_cfg; + } + + str = (char *)tbuf; + for (i = 5; i >= 0; i--) { + bdaddr[i] = (uint8_t)strtoul(str, NULL, 16); + str += 3; + } + + /* Reserve LAP addr from 0x9e8b00 to 0x9e8b3f, + * Change to 0x008bXX */ + if (0x9e == bdaddr[3] && 0x8b == bdaddr[4] && + bdaddr[5] <= 0x3f) + bdaddr[3] = 0x00; + + RS_DBG("BT MAC %02x:%02x:%02x:%02x:%02x:%02x", + bdaddr[5], bdaddr[4], bdaddr[3], bdaddr[2], + bdaddr[1], bdaddr[0]); + ofs = get_mac_offset(chip_type); + n = malloc(sizeof(*n) + 6); + if (n) { + n->offset = ofs; + n->len = 6; + memcpy(n->data, bdaddr, 6); + list_add_tail(&n->list, &list_extracfgs); + } else { + RS_ERR("Couldn't alloc cfg item for bdaddr"); + } + } + +read_cfg: + *cfg_len = 0; + file_name = malloc(PATH_MAX); + if (!file_name) { + RS_ERR("Can't allocate memory for Config file name"); + return NULL; + } + memset(file_name, 0, PATH_MAX); + snprintf(file_name, PATH_MAX, "%s%s", BT_CONFIG_DIRECTORY, file); + if (stat(file_name, &st) < 0) { + RS_ERR("Can't access Config file: %s, %s", + file_name, strerror(errno)); + goto err_stat; + } + + file_len = st.st_size; + + if ((fd = open(file_name, O_RDONLY)) < 0) { + perror("Can't open Config file"); + goto err_open; + } + + buf = malloc(file_len); + if (!buf) { + RS_ERR("Couldnt malloc buffer for Config %zd", file_len); + goto err_malloc; + } + + result = read(fd, buf, file_len); + if (result < (ssize_t)file_len) { + perror("Can't read Config file"); + goto err_read; + } + close(fd); + free(file_name); + + result = rtb_parse_config(buf, file_len); + if (result < 0) { + RS_ERR("Invalid Config content"); + close(fd); + free(buf); + config_lists_free(); + exit(EXIT_FAILURE); + } + RS_INFO("Origin cfg len %u", (uint16_t)file_len); + util_hexdump((const uint8_t *)buf, file_len); + + merge_configs(&list_configs, &list_extracfgs); + + config_len = 4; /* magic word length */ + config_len += 2; /* data length field */ + /* Calculate the config_len */ + dlen = 0; + list_for_each_safe(pos, next, &list_configs) { + n = list_entry(pos, struct cfg_list_item, list); + switch (n->offset) { + case 0x003c: + case 0x0030: + case 0x0044: + if (is_mac(chip_type, n->offset) && n->len == 6) { + char s[18]; + sprintf(s, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", + n->data[5], n->data[4], + n->data[3], n->data[2], + n->data[1], n->data[0]); + RS_INFO("bdaddr ofs %04x, %s", n->offset, s); + } + break; + case 0x000c: +#ifdef BAUDRATE_4BYTES + baudrate = get_unaligned_le32(n->data); +#else + baudrate = get_unaligned_le16(n->data); +#endif + rtb_cfg.vendor_baud = baudrate; + RS_INFO("Config baudrate: %08x", baudrate); + + if (n->len > 12) { + uint8_t d = n->data[12]; + rtb_cfg.uart_flow_ctrl = (d & 0x4) ? 1 : 0; + RS_INFO("uart flow ctrl: %u", + rtb_cfg.uart_flow_ctrl); + } + break; +#ifdef RTL8723DSH4_UART_HWFLOWC + case 0x0018: + if (chip_type == CHIP_8723DS && + rtb_cfg.proto == HCI_UART_H4) { + if (n->data[0] & (1 << 2)) + rtb_cfg.uart_flow_ctrl = 1; + RS_INFO("8723DSH4: hw flow control %u", + rtb_cfg.uart_flow_ctrl); + if (n->data[0] & 0x01) { + rtb_cfg.parenb = 1; + if (n->data[0] & 0x02) + rtb_cfg.pareven = 1; + else + rtb_cfg.pareven = 0; + } + RS_INFO("8723DSH4: parity %u, even %u", + rtb_cfg.parenb, + rtb_cfg.pareven); + } + break; +#endif + default: + break; + } + + config_len += (3 + n->len); + dlen += (3 + n->len); + + } + p = realloc(buf, config_len); + if (!p) { + /* block is left untouched; it is not freed or moved */ + RS_ERR("Couldn't realloc buf for configs"); + free(buf); + buf = NULL; + *cfg_len = 0; + goto done; + } + buf = p; + + memcpy(buf, cfg_magic, 4); + buf[4] = dlen & 0xff; + buf[5] = (dlen >> 8) & 0xff; + p = buf + 6; + list_for_each_safe(pos, next, &list_configs) { + n = list_entry(pos, struct cfg_list_item, list); + p[0] = n->offset & 0xff; + p[1] = (n->offset >> 8) & 0xff; + p[2] = n->len; + memcpy(p + 3, n->data, n->len); + p += (3 + n->len); + } + + RS_INFO("Vendor baud from Config file: %08x", rtb_cfg.vendor_baud); + + RS_INFO("New cfg len %u", config_len); + util_hexdump((const uint8_t *)buf, config_len); + + *cfg_len = config_len; + +done: + config_lists_free(); + + return buf; + +err_read: + free(buf); +err_malloc: + config_lists_free(); + close(fd); +err_open: +err_stat: + free(file_name); + return NULL; +} + +/* + * Read Realtek Bluetooth firmaware file. + */ +uint8_t *rtb_read_firmware(struct rtb_struct *btrtl, int *fw_len) +{ + char *filename; + struct stat st; + int fd = -1; + size_t fwsize; + uint8_t *fw_buf; + ssize_t result; + + if (!btrtl || !fw_len) { + RS_ERR("%s: Invalid parameter", __func__); + return NULL; + } + + filename = malloc(PATH_MAX); + if (!filename) { + RS_ERR("Can't allocate memory for fw name"); + return NULL; + } + + snprintf(filename, PATH_MAX, "%s%s", FIRMWARE_DIRECTORY, + btrtl->patch_ent->patch_file); + + if (stat(filename, &st) < 0) { + RS_ERR("Can't access firmware %s, %s", filename, + strerror(errno)); + goto err_stat; + } + + fwsize = st.st_size; + + if ((fd = open(filename, O_RDONLY)) < 0) { + RS_ERR("Can't open firmware, %s", strerror(errno)); + goto err_open; + } + + fw_buf = malloc(fwsize); + if (!fw_buf) { + RS_ERR("Can't allocate memory for fw, %s", strerror(errno)); + goto err_malloc; + } + + result = read(fd, fw_buf, fwsize); + if (result != (ssize_t) fwsize) { + RS_ERR("Read FW %s error, %s", filename, strerror(errno)); + goto err_read; + } + + *fw_len = (int)result; + RS_INFO("Load FW %s OK, size %zd", filename, result); + + close(fd); + free(filename); + + return fw_buf; + +err_read: + free(fw_buf); + *fw_len = 0; +err_malloc: + close(fd); +err_open: +err_stat: + free(filename); + return NULL; +} + +static uint8_t rtb_get_fw_project_id(uint8_t *p_buf) +{ + uint8_t opcode; + uint8_t len; + uint8_t data = 0; + + do { + opcode = *p_buf; + len = *(p_buf - 1); + if (opcode == 0x00) { + if (len == 1) { + data = *(p_buf - 2); + RS_INFO("%s: opcode %u, len %u, data %u", + __func__, opcode, len, data); + break; + } else { + RS_ERR("%s: Invalid len %u", __func__, len); + } + } + p_buf -= len + 2; + } while (*p_buf != 0xFF); + + return data; +} + +struct rtb_patch_entry *rtb_get_patch_entry(void) +{ + uint16_t i; + struct rtb_patch_hdr *patch; + struct rtb_patch_entry *entry; + uint32_t tmp; + uint8_t *ci_base; /* Chip id base */ + uint8_t *pl_base; /* Patch length base */ + uint8_t *so_base; /* Start offset base */ + + patch = (struct rtb_patch_hdr *)rtb_cfg.fw_buf; + entry = (struct rtb_patch_entry *)malloc(sizeof(*entry)); + if (!entry) { + RS_ERR("Failed to allocate mem for patch entry"); + return NULL; + } + + patch->number_of_patch = le16_to_cpu(patch->number_of_patch); + + RS_DBG("FW version 0x%08x, Patch num %u", + le32_to_cpu(patch->fw_version), patch->number_of_patch); + + ci_base = rtb_cfg.fw_buf + 14; + pl_base = ci_base + 2 * patch->number_of_patch; + so_base = pl_base + 2 * patch->number_of_patch; + for (i = 0; i < patch->number_of_patch; i++) { + uint16_t chip_id = get_unaligned_le16(ci_base + 2 * i); + + RS_INFO("Chip id 0x%04x", chip_id); + if (chip_id == rtb_cfg.eversion + 1) { + entry->chip_id = rtb_cfg.eversion + 1; + entry->patch_len = get_unaligned_le16(pl_base + 2 * i); + entry->soffset = get_unaligned_le32(so_base + 4 * i); + RS_DBG("Patch length 0x%04x", entry->patch_len); + RS_DBG("Start offset 0x%08x", entry->soffset); + + entry->svn_ver = get_unaligned_le32(rtb_cfg.fw_buf + + entry->soffset + + entry->patch_len - 8); + entry->coex_ver = get_unaligned_le32(rtb_cfg.fw_buf + + entry->soffset + + entry->patch_len - 12); + + RS_INFO("Svn version: %8u", entry->svn_ver); + tmp = ((entry->coex_ver >> 16) & 0x7ff) + + (entry->coex_ver >> 27) * 10000; + RS_INFO("Coexistence: BTCOEX_20%06u-%04x\n", tmp, + (entry->coex_ver & 0xffff)); + + break; + } + } + + if (i == patch->number_of_patch) { + RS_ERR("Failed to get entry"); + free(entry); + entry = NULL; + } + + return entry; +} + +uint8_t *rtb_get_final_patch(int fd, int proto, int *rlen) +{ + struct rtb_struct *rtl = &rtb_cfg; + uint8_t proj_id = 0; + struct rtb_patch_entry *entry = NULL; + struct rtb_patch_hdr *patch = (struct rtb_patch_hdr *)rtl->fw_buf; + uint32_t svn_ver, coex_ver, tmp; + const uint8_t rtb_patch_smagic[8] = { + 0x52, 0x65, 0x61, 0x6C, 0x74, 0x65, 0x63, 0x68 + }; + const uint8_t rtb_patch_emagic[4] = { 0x51, 0x04, 0xFD, 0x77 }; + uint8_t *buf; + int len; + + if (!rlen) { + RS_ERR("%s: Invalid parameter", __func__); + return NULL; + } + + /* Use single patch for 3wire && 8723a */ + if (proto == HCI_UART_3WIRE && rtl->lmp_subver == ROM_LMP_8723a) { + if (!memcmp(rtl->fw_buf, rtb_patch_smagic, 8)) { + RS_ERR("Unexpected signature"); + goto err; + } + + len = rtl->config_len + rtl->fw_len; + buf = malloc(len); + if (!buf) { + RS_ERR("Can't alloc mem for fwc, %s", strerror(errno)); + goto err; + } else { + uint8_t *b; + + RS_INFO("FWC copy directly"); + + b = rtl->fw_buf + rtl->fw_len; + svn_ver = get_unaligned_le32(b - 8); + coex_ver = get_unaligned_le32(b - 12); + + RS_INFO("Svn version: %u\n", svn_ver); + tmp = ((coex_ver >> 16) & 0x7ff) + + (coex_ver >> 27) * 10000; + RS_INFO("Coexistence: BTCOEX_20%06u-%04x\n", tmp, + (coex_ver & 0xffff)); + + /* Copy Patch and Config */ + memcpy(buf, rtl->fw_buf, rtl->fw_len); + if (rtl->config_len) + memcpy(buf + rtl->fw_len, + rtl->config_buf, rtl->config_len); + rtl->dl_fw_flag = 1; + *rlen = len; + return buf; + } + } + + if (memcmp(rtl->fw_buf, rtb_patch_smagic, 8)) { + RS_ERR("Signature error"); + goto err; + } + + if (memcmp(rtl->fw_buf + rtl->fw_len - 4, rtb_patch_emagic, 4)) { + RS_ERR("Extension section signature error"); + goto err; + } + + proj_id = rtb_get_fw_project_id(rtl->fw_buf + rtl->fw_len - 5); + +#ifdef RTL_8703A_SUPPORT + if (rtl->hci_ver == 0x4 && rtl->lmp_subver == ROM_LMP_8723b) { + RS_INFO("HCI version = 0x4, IC is 8703A."); + } else { + RS_ERR("error: lmp_version %x, hci_version %x, project_id %x", + rtl->lmp_subver, rtl->hci_ver, project_id[proj_id]); + goto err; + } +#else + if (rtl->lmp_subver != ROM_LMP_8703b) { + if (rtl->lmp_subver != project_id[proj_id]) { + RS_ERR("lmp_subver %04x, project id %04x, mismatch\n", + rtl->lmp_subver, project_id[proj_id]); + goto err; + } + } else { + if (rtb_cfg.patch_ent->proj_id != project_id[proj_id]) { + RS_ERR("proj_id %04x, version %04x from firmware " + "project_id[%u], mismatch", + rtb_cfg.patch_ent->proj_id, + project_id[proj_id], proj_id); + goto err; + } + } +#endif + + /* Entry is allocated dynamically. It should be freed later in the + * function. + */ + entry = rtb_get_patch_entry(); + + if (entry) { + len = entry->patch_len + rtl->config_len; + } else { + RS_ERR("Can't find the patch entry"); + goto err; + } + + buf = malloc(len); + if (!buf) { + RS_ERR("%s: Can't alloc memory for fwc, %s", __func__, + strerror(errno)); + free(entry); + goto err; + } else { + memcpy(buf, rtl->fw_buf + entry->soffset, entry->patch_len); + memcpy(buf + entry->patch_len - 4, &patch->fw_version, 4); + + if (rtl->config_len) + memcpy(buf + entry->patch_len, rtl->config_buf, + rtl->config_len); + rtl->dl_fw_flag = 1; + *rlen = len; + } + + RS_INFO("FW %s exists, Config file %s exists", + (rtl->fw_len > 0) ? "" : "not", + (rtl->config_len > 0) ? "" : "not"); + + free(entry); + return buf; + +err: + rtl->dl_fw_flag = 0; + *rlen = 0; + return NULL; +} + diff --git a/buildroot-external/package/rtk-hciattach/src/rtb_fwc.h b/buildroot-external/package/rtk-hciattach/src/rtb_fwc.h new file mode 100644 index 00000000000..1811f530686 --- /dev/null +++ b/buildroot-external/package/rtk-hciattach/src/rtb_fwc.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2018 Realtek Semiconductor Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +struct rtb_struct; + +#define BAUDRATE_4BYTES + +#define ROM_LMP_NONE 0x0000 +#define ROM_LMP_8723a 0x1200 +#define ROM_LMP_8723b 0x8723 +#define ROM_LMP_8821a 0x8821 +#define ROM_LMP_8761a 0x8761 +#define ROM_LMP_8761btc 0x8763 + +#define ROM_LMP_8703a 0x87b3 +#define ROM_LMP_8763a 0x8763 +#define ROM_LMP_8703b 0x8703 +#define ROM_LMP_8723c 0x87c3 /* ??????? */ +#define ROM_LMP_8822b 0x8822 +#define ROM_LMP_8822c 0x8822 +#define ROM_LMP_8723cs_xx 0x8704 +#define ROM_LMP_8723cs_cg 0x8705 +#define ROM_LMP_8723cs_vf 0x8706 + +/* Chip type */ +#define CHIP_8703AS 1 +#define CHIP_8723CS_CG 3 +#define CHIP_8723CS_VF 4 +#define CHIP_8723CS_XX 5 +#define CHIP_8703BS 7 + +/* software id */ +#define CHIP_UNKNOWN 0x00 +#define CHIP_8761AT 0x1F +#define CHIP_8761ATF 0x2F +#define CHIP_8761BTC 0x3F +#define CHIP_8761BH4 0x4F +#define CHIP_8723BS 0x5F +#define CHIP_BEFORE 0x6F +#define CHIP_8822BS 0x70 +#define CHIP_8723DS 0x71 +#define CHIP_8821CS 0x72 +#define CHIP_8822CS 0x73 +#define CHIP_8761B 0x74 + +#define RTL_FW_MATCH_CHIP_TYPE (1 << 0) +#define RTL_FW_MATCH_HCI_VER (1 << 1) +#define RTL_FW_MATCH_HCI_REV (1 << 2) +struct patch_info { + uint32_t match_flags; + uint8_t chip_type; + uint16_t lmp_subver; + uint16_t proj_id; + uint8_t hci_ver; + uint16_t hci_rev; + char *patch_file; + char *config_file; + char *ic_name; +}; + +struct patch_info *get_patch_entry(struct rtb_struct *btrtl); +uint8_t *rtb_read_config(const char *file, int *cfg_len, uint8_t chip_type); +uint8_t *rtb_read_firmware(struct rtb_struct *btrtl, int *fw_len); +uint8_t *rtb_get_final_patch(int fd, int proto, int *rlen); From 82f12727caf26c069e650e132e5b2fce29ef5f0e Mon Sep 17 00:00:00 2001 From: Vyacheslav Bocharov Date: Sat, 30 Jan 2021 17:28:22 +0300 Subject: [PATCH 07/11] Add buildroot package for rtl8822cs SDIO WiFi driver --- buildroot-external/Config.in | 2 ++ .../package/rtl8822cs/Config.in | 10 ++++++++++ .../package/rtl8822cs/rtl8822cs.mk | 20 +++++++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 buildroot-external/package/rtl8822cs/Config.in create mode 100644 buildroot-external/package/rtl8822cs/rtl8822cs.mk diff --git a/buildroot-external/Config.in b/buildroot-external/Config.in index b99ee1951b0..9ea785f76f1 100644 --- a/buildroot-external/Config.in +++ b/buildroot-external/Config.in @@ -7,4 +7,6 @@ source "$BR2_EXTERNAL_HASSOS_PATH/package/armbian-firmware-ap6255/Config.in" source "$BR2_EXTERNAL_HASSOS_PATH/package/qemu-guest-agent/Config.in" source "$BR2_EXTERNAL_HASSOS_PATH/package/intel-e1000e/Config.in" source "$BR2_EXTERNAL_HASSOS_PATH/package/rpi-eeprom/Config.in" +source "$BR2_EXTERNAL_HASSOS_PATH/package/rtk-hciattach/Config.in" source "$BR2_EXTERNAL_HASSOS_PATH/package/rtl8812au/Config.in" +source "$BR2_EXTERNAL_HASSOS_PATH/package/rtl8822cs/Config.in" diff --git a/buildroot-external/package/rtl8822cs/Config.in b/buildroot-external/package/rtl8822cs/Config.in new file mode 100644 index 00000000000..c902fd3dd8d --- /dev/null +++ b/buildroot-external/package/rtl8822cs/Config.in @@ -0,0 +1,10 @@ +comment "RTL8822CS needs a Linux kernel to be built" + depends on !BR2_LINUX_KERNEL + +config BR2_PACKAGE_RTL8822CS + bool "Realtek RTL8822CS SDIO Wi-Fi driver" + depends on BR2_LINUX_KERNEL + help + Install Realtek RTL8822CS Wi-Fi driver as a kernel module. + + https://github.com/jethome-ru/rtl88x2cs/ diff --git a/buildroot-external/package/rtl8822cs/rtl8822cs.mk b/buildroot-external/package/rtl8822cs/rtl8822cs.mk new file mode 100644 index 00000000000..346dbe55e2a --- /dev/null +++ b/buildroot-external/package/rtl8822cs/rtl8822cs.mk @@ -0,0 +1,20 @@ +################################################################################ +# +# Realtek RTL8822CS driver +# +################################################################################ + +RTL8822CS_VERSION = 65af8fc4a72aa6ebcb02fbe3a5ea6f6886eeaebe +RTL8822CS_SITE = $(call github,adeepn,rtl88x2cs,$(RTL8822CS_VERSION)) +RTL8822CS_LICENSE = Unknown +#RTL8822CS_LICENSE_FILES = COPYING +#RTL8822CS_MODULE_SUBDIRS = src + + +RTL8822CS_MODULE_MAKE_OPTS = \ + CONFIG_RTL8822CS=m \ + KVER=$(LINUX_VERSION_PROBED) \ + KSRC=$(LINUX_DIR) + +$(eval $(kernel-module)) +$(eval $(generic-package)) From 731c02721a4e49ee2e422bd13d384782c4732084 Mon Sep 17 00:00:00 2001 From: Vyacheslav Bocharov Date: Sat, 30 Jan 2021 17:29:39 +0300 Subject: [PATCH 08/11] Update commit id for JetHome Boot package --- buildroot-external/package/jethome-boot/jethome-boot.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/buildroot-external/package/jethome-boot/jethome-boot.mk b/buildroot-external/package/jethome-boot/jethome-boot.mk index e60ebba383e..84e64024887 100644 --- a/buildroot-external/package/jethome-boot/jethome-boot.mk +++ b/buildroot-external/package/jethome-boot/jethome-boot.mk @@ -5,6 +5,7 @@ ################################################################################ JETHOME_BOOT_VERSION = HEAD +#afe09f3df8d8fdaf03d764fc76e5ce7b6d0637a5 JETHOME_BOOT_SITE = https://github.com/adeepn/jethub-prebuilt-u-boot.git JETHOME_BOOT_SITE_METHOD = git JETHOME_BOOT_INSTALL_IMAGES = YES From f41f9d1f66cc5dc0e3eb64ae97a39cd7eee342c8 Mon Sep 17 00:00:00 2001 From: Vyacheslav Bocharov Date: Sat, 30 Jan 2021 17:33:39 +0300 Subject: [PATCH 09/11] Add basic support for JetHome JetHub H1 (j80) --- .../board/jethome/jethub-h1/hassos-hook.sh | 100 +++++++++++++++ .../board/jethome/jethub-h1/meta | 11 ++ .../rootfs-overlay/usr/lib/jethome/init_j80 | 59 +++++++++ .../usr/lib/jethome/rtk_hciattach_starter | 15 +++ .../system/jethome_rtk_hciattach.service | 15 +++ .../board/jethome/jethub-h1/uboot-boot.ush | 120 ++++++++++++++++++ .../board/jethome/jethub-h1/uboot.config | 4 + .../configs/jethub_h1_defconfig | 117 +++++++++++++++++ 8 files changed, 441 insertions(+) create mode 100755 buildroot-external/board/jethome/jethub-h1/hassos-hook.sh create mode 100644 buildroot-external/board/jethome/jethub-h1/meta create mode 100755 buildroot-external/board/jethome/jethub-h1/rootfs-overlay/usr/lib/jethome/init_j80 create mode 100755 buildroot-external/board/jethome/jethub-h1/rootfs-overlay/usr/lib/jethome/rtk_hciattach_starter create mode 100644 buildroot-external/board/jethome/jethub-h1/rootfs-overlay/usr/lib/systemd/system/jethome_rtk_hciattach.service create mode 100644 buildroot-external/board/jethome/jethub-h1/uboot-boot.ush create mode 100644 buildroot-external/board/jethome/jethub-h1/uboot.config create mode 100644 buildroot-external/configs/jethub_h1_defconfig diff --git a/buildroot-external/board/jethome/jethub-h1/hassos-hook.sh b/buildroot-external/board/jethome/jethub-h1/hassos-hook.sh new file mode 100755 index 00000000000..7f2ca1fc5ac --- /dev/null +++ b/buildroot-external/board/jethome/jethub-h1/hassos-hook.sh @@ -0,0 +1,100 @@ +#!/bin/bash +# shellcheck disable=SC2155 + +# Change size partitions +BOOT_SIZE=(64M 64M) +BOOTSTATE_SIZE=8M +SYSTEM_SIZE=256M +KERNEL_SIZE=64M +OVERLAY_SIZE=128M +DATA_SIZE=1G + +set -e # Exit immediately if a command exits with a non-zero status +set -u # Treat unset variables and parameters as an error + +# some functions +print_var() { + if [ -n "$1" ] ; then + echo "-- ${1}==${!1}" + else + echo "${FUNCNAME[0]}(): Null parameter passed to this function" + fi +} + +print_cmd_title() { + if [ -n "$1" ] ; then + echo "###### ${1} ######" + else + echo "${FUNCNAME[0]}(): Null parameter passed to this function" + fi +} + +self_name() { + echo ${0##*/} +} + + +function hassos_pre_image() { + local BOOT_DATA="$(path_boot_dir)" + + echo "console=tty0 console=ttyAML0,115200n8" > "${BOOT_DATA}/cmdline.txt" + cp "${BINARIES_DIR}/meson-gxl-s905w-jethome-jethub-j80.dtb" "${BOOT_DATA}/meson-gxl-s905w-jethome-jethub-j80.dtb" +} + +function hassos_post_image() { + convert_disk_image_xz +} + +function create_disk_image() { + _prepare_disk_image + _create_disk_aml +} + +function create_platform_conf () { + echo 'Platform:0x0811' > ${BINARIES_DIR}/platform.conf + echo 'DDRLoad:0xd9000000' >> ${BINARIES_DIR}/platform.conf + echo 'DDRRun:0xd9000000' >> ${BINARIES_DIR}/platform.conf + echo 'UbootLoad:0x200c000' >> ${BINARIES_DIR}/platform.conf + echo 'UbootRun:0xd9000000' >> ${BINARIES_DIR}/platform.conf + echo 'Control0=0xd9000000:0x000000b1' >> ${BINARIES_DIR}/platform.conf + echo 'Control1=0xd9000000:0x00005183' >> ${BINARIES_DIR}/platform.conf + echo 'Encrypt_reg:0xc8100228' >> ${BINARIES_DIR}/platform.conf + echo 'bl2ParaAddr=0xd900c000' >> ${BINARIES_DIR}/platform.conf +} + +function _create_disk_aml() { + local boot_img="$(path_boot_img)" + local rootfs_img="$(path_rootfs_img)" + local overlay_img="$(path_overlay_img)" + local data_img="$(path_data_img)" + local kernel_img="$(path_kernel_img)" + local hdd_img="$(hassos_image_name img)" + local hdd_count=${DISK_SIZE:-2} + local disk_layout="${BINARIES_DIR}/disk.layout" + local boot_start=$(size2sectors "8M") + local bootloader_img="u-boot.bin" # bootloader + local ubootbin_img="u-boot.bin.usb.tpl" # UBOOT + local ddrbin_img="u-boot.bin.usb.bl2" # DDR + + echo '[LIST_NORMAL]' > ${BINARIES_DIR}/image.cfg + echo 'file="'${ddrbin_img}'" main_type="USB" sub_type="DDR"' >> ${BINARIES_DIR}/image.cfg + echo 'file="'${ubootbin_img}'" main_type="USB" sub_type="UBOOT"' >> ${BINARIES_DIR}/image.cfg + echo 'file="_aml_dtb.PARTITION" main_type="dtb" sub_type="meson1"' >> ${BINARIES_DIR}/image.cfg + echo 'file="platform.conf" main_type="conf" sub_type="platform"' >> ${BINARIES_DIR}/image.cfg + echo '' >> ${BINARIES_DIR}/image.cfg + echo '[LIST_VERIFY]' >> ${BINARIES_DIR}/image.cfg + echo 'file="_aml_dtb.PARTITION" main_type="PARTITION" sub_type="_aml_dtb"' >> ${BINARIES_DIR}/image.cfg + echo 'file="'${bootloader_img}'" main_type="PARTITION" sub_type="bootloader"' >> ${BINARIES_DIR}/image.cfg + echo 'file="'${boot_img##*/}'" main_type="PARTITION" sub_type="boot"' >> ${BINARIES_DIR}/image.cfg + echo 'file="'${kernel_img##*/}'" main_type="PARTITION" sub_type="kernela"' >> ${BINARIES_DIR}/image.cfg + echo 'file="'${rootfs_img##*/}'" main_type="PARTITION" sub_type="systema"' >> ${BINARIES_DIR}/image.cfg + echo 'file="'${overlay_img##*/}'" main_type="PARTITION" sub_type="overlay"' >> ${BINARIES_DIR}/image.cfg + echo 'file="'${data_img##*/}'" main_type="PARTITION" sub_type="data"' >> ${BINARIES_DIR}/image.cfg + + create_platform_conf + + cc -o $BINARIES_DIR/dtbTool $BOARD_DIR/../src/dtbTool.c + $BINARIES_DIR/dtbTool -o $BINARIES_DIR/_aml_dtb.PARTITION ${BINARIES_DIR}/ + $BOARD_DIR/../bin/aml_image_v2_packer -r ${BINARIES_DIR}/image.cfg ${BINARIES_DIR}/ $hdd_img + echo "Image created" +} diff --git a/buildroot-external/board/jethome/jethub-h1/meta b/buildroot-external/board/jethome/jethub-h1/meta new file mode 100644 index 00000000000..af6f476b2a5 --- /dev/null +++ b/buildroot-external/board/jethome/jethub-h1/meta @@ -0,0 +1,11 @@ +BOARD_ID=jethub-h1 +BOARD_NAME="JetHome JetHub H1" +CHASSIS=embedded +BOOTLOADER=uboot +KERNEL_FILE=Image +BOOT_SYS=mbr +BOOT_SPL=false +BOOT_ENV_SIZE=0x10000 +SUPERVISOR_MACHINE=odroid-c2 +#SUPERVISOR_MACHINE=jethub-h1 TODO: add supervisor +SUPERVISOR_ARCH=aarch64 diff --git a/buildroot-external/board/jethome/jethub-h1/rootfs-overlay/usr/lib/jethome/init_j80 b/buildroot-external/board/jethome/jethub-h1/rootfs-overlay/usr/lib/jethome/init_j80 new file mode 100755 index 00000000000..ee2e2cc6211 --- /dev/null +++ b/buildroot-external/board/jethome/jethub-h1/rootfs-overlay/usr/lib/jethome/init_j80 @@ -0,0 +1,59 @@ +#!/bin/bash + +GPIO_DIRECTION_OUTPUT=0 +GPIO_DIRECTION_INPUT=1 + +GPIO_ACTIVE_LOW=0 +GPIO_ACTIVE_HIGH=1 + +configure_gpio() { + echo "${0}: Configure: gpio=${1}, direction=${2}, active_level=${3}" + + if [ ! -d /sys/class/gpio/gpio${1} ]; then + echo ${1} > /sys/class/gpio/export + if [ ! -d /sys/class/gpio/gpio${1} ]; then + echo "${0}: *** Error: Failed to configure GPIO ${1}" + exit 1 + fi + fi + + if [ "${2}" == "${GPIO_DIRECTION_OUTPUT}" ]; then + echo "out" > /sys/class/gpio/gpio${1}/direction + else + echo "in" > /sys/class/gpio/gpio${1}/direction + fi + + if [ "${3}" == "${GPIO_ACTIVE_LOW}" ]; then + echo 1 > /sys/class/gpio/gpio${1}/active_low + fi +} + +echo "${0}: Configure GPIOs ..." + +# Zigbee module: RESET, BOOT +configure_gpio "507" "${GPIO_DIRECTION_OUTPUT}" "${GPIO_ACTIVE_HIGH}" +configure_gpio "510" "${GPIO_DIRECTION_OUTPUT}" "${GPIO_ACTIVE_HIGH}" +# Z-Wave module: RESET, SUSPEND +configure_gpio "490" "${GPIO_DIRECTION_OUTPUT}" "${GPIO_ACTIVE_HIGH}" +configure_gpio "491" "${GPIO_DIRECTION_OUTPUT}" "${GPIO_ACTIVE_HIGH}" +# LED +configure_gpio "474" "${GPIO_DIRECTION_OUTPUT}" "${GPIO_ACTIVE_HIGH}" + + +echo "${0}: Turn off LED ..." +echo 0 > /sys/class/gpio/gpio474/value + +echo "${0}: Reset Zigbee module ..." +echo 1 > /sys/class/gpio/gpio510/value +echo 1 > /sys/class/gpio/gpio507/value +sleep 1 +echo 0 > /sys/class/gpio/gpio507/value + +echo "${0}: Reset Z-Wave module ..." +# Optional SUSPEND pin +#echo 1 > /sys/class/gpio/gpio491/value +echo 1 > /sys/class/gpio/gpio490/value +sleep 1 +echo 0 > /sys/class/gpio/gpio490/value + +exit 0 diff --git a/buildroot-external/board/jethome/jethub-h1/rootfs-overlay/usr/lib/jethome/rtk_hciattach_starter b/buildroot-external/board/jethome/jethub-h1/rootfs-overlay/usr/lib/jethome/rtk_hciattach_starter new file mode 100755 index 00000000000..abaf33ddbeb --- /dev/null +++ b/buildroot-external/board/jethome/jethub-h1/rootfs-overlay/usr/lib/jethome/rtk_hciattach_starter @@ -0,0 +1,15 @@ +#!/bin/bash + +if grep -Eq "^GXL.+S905W" /sys/devices/soc0/soc_id; then + if [ ! -f /sys/class/gpio/gpio497/value ]; then + echo 497 > /sys/class/gpio/export + echo out > /sys/class/gpio/gpio497/direction + fi + echo 0 > /sys/class/gpio/gpio497/value && sleep 0.1 + echo 1 > /sys/class/gpio/gpio497/value && sleep 0.1 + rtk_hciattach /dev/ttyAML1 -s 115200 rtk_h5 115200 +elif grep -Eq "^AXG" /sys/devices/soc0/soc_id; then + echo "Amlogic AXG detected. Skip rtk_hciattach execution." +else + echo "SoC detection failed. Unable to execute rtk_hciattach." +fi diff --git a/buildroot-external/board/jethome/jethub-h1/rootfs-overlay/usr/lib/systemd/system/jethome_rtk_hciattach.service b/buildroot-external/board/jethome/jethub-h1/rootfs-overlay/usr/lib/systemd/system/jethome_rtk_hciattach.service new file mode 100644 index 00000000000..3523a0bb055 --- /dev/null +++ b/buildroot-external/board/jethome/jethub-h1/rootfs-overlay/usr/lib/systemd/system/jethome_rtk_hciattach.service @@ -0,0 +1,15 @@ + +[Unit] +Description=rtk_hciattach +DefaultDependencies=no +After=local-fs.target +Conflicts=shutdown.target + +[Service] +Type=oneshot +ExecStart=/usr/bin/bash /usr/lib/jethome/rtk_hciattach_starter +RemainAfterExit=yes +TimeoutStartSec=30sec + +[Install] +WantedBy=sysinit.target diff --git a/buildroot-external/board/jethome/jethub-h1/uboot-boot.ush b/buildroot-external/board/jethome/jethub-h1/uboot-boot.ush new file mode 100644 index 00000000000..d27e9bfdd6d --- /dev/null +++ b/buildroot-external/board/jethome/jethub-h1/uboot-boot.ush @@ -0,0 +1,120 @@ + +########################################### + +part start mmc ${devnum} 9 mmc_env +mmc dev ${devnum} +setenv loadbootstate " \ + echo 'loading env...'; \ + mmc read ${ramdisk_addr_r} ${mmc_env} 0x10; \ + env import -c ${ramdisk_addr_r} 0x2000;" + +setenv storebootstate " \ + echo 'storing env...'; \ + env export -c -s 0x2000 ${ramdisk_addr_r} BOOT_ORDER BOOT_A_LEFT BOOT_B_LEFT MACHINE_ID; \ + mmc write ${ramdisk_addr_r} ${mmc_env} 0x10;" + +run loadbootstate +test -n "${BOOT_ORDER}" || setenv BOOT_ORDER "A B" +test -n "${BOOT_A_LEFT}" || setenv BOOT_A_LEFT 3 +test -n "${BOOT_B_LEFT}" || setenv BOOT_B_LEFT 3 + +# HassOS bootargs +setenv bootargs_hassos "console=ttyAML0,115200n8 no_console_suspend consoleblank=0 fsck.fix=yes fsck.repair=yes net.ifnames=0 zram.enabled=1 zram.num_devices=3 apparmor=1 security=apparmor systemd.machine_id=${MACHINE_ID} cgroup_enable=memory" + +# HassOS system A/B +setenv bootargs_a "root=PARTUUID=48617373-06 rootfstype=squashfs ro rootwait" +setenv bootargs_b "root=PARTUUID=48617373-08 rootfstype=squashfs ro rootwait" + +# Load extraargs +fileenv mmc ${devnum}:1 ${ramdisk_addr_r} cmdline.txt cmdline +fatload mmc ${devnum}:1 ${fdt_addr_r} meson-gxbb-odroidc2.dtb + +# logical volumes get numbered after physical ones. +# 1. boot +# 2. Extended partition +# 3. Overlay +# 4. Data +# 5. KernelA +# 6. SystemA +# 7. KernelB +# 8. SystemB +# 9. BootInfo +setenv bootargs +for BOOT_SLOT in "${BOOT_ORDER}"; do + if test "x${bootargs}" != "x"; then + # skip remaining slots + elif test "x${BOOT_SLOT}" = "xA"; then + if test ${BOOT_A_LEFT} -gt 0; then + setexpr BOOT_A_LEFT ${BOOT_A_LEFT} - 1 + echo "Trying to boot slot A, ${BOOT_A_LEFT} attempts remaining. Loading kernel ..." + if ext4load mmc ${devnum}:5 ${kernel_addr_r} Image; then + setenv bootargs "${bootargs_hassos} ${bootargs_a} rauc.slot=A ${cmdline}" + fi + fi + elif test "x${BOOT_SLOT}" = "xB"; then + if test ${BOOT_B_LEFT} -gt 0; then + setexpr BOOT_B_LEFT ${BOOT_B_LEFT} - 1 + echo "Trying to boot slot B, ${BOOT_B_LEFT} attempts remaining. Loading kernel ..." + if ext4load mmc ${devnum}:7 ${kernel_addr_r} Image; then + setenv bootargs "${bootargs_hassos} ${bootargs_b} rauc.slot=B ${cmdline}" + fi + fi + fi +done + +if test -n "${bootargs}"; then + run storebootstate +else + echo "No valid slot found, resetting tries to 3" + setenv BOOT_A_LEFT 3 + setenv BOOT_B_LEFT 3 + run storebootstate + reset +fi + +printenv bootargs +echo "Starting kernel" +booti ${kernel_addr_r} - ${fdt_addr_r} + +echo "Boot failed, resetting..." +reset + +echo "start amlogic old u-boot" +if printenv bootfromsd; then exit; fi; +if fatload mmc 0 ${loadaddr} boot_android; then if test ${ab} = 0; then setenv ab 1; saveenv; exit; else setenv ab 0; saveenv; fi; fi; +if fatload usb 0 ${loadaddr} boot_android; then if test ${ab} = 0; then setenv ab 1; saveenv; exit; else setenv ab 0; saveenv; fi; fi; +if fatload mmc 0 0x1000000 u-boot.ext; then go 0x1000000; fi; +if fatload usb 0 0x1000000 u-boot.ext; then go 0x1000000; fi; +setenv fdt_addr_r 0x1000000 +setenv env_addr 0x10400000 +setenv kernel_addr_r 0x11000000 +setenv ramdisk_addr_r 0x13000000 +setenv l_mmc "0" +setenv addmac 'if printenv mac; then setenv bootargs ${bootargs} mac=${mac}; elif printenv eth_mac; then setenv bootargs ${bootargs} mac=${eth_mac}; elif printenv ethaddr; then setenv bootargs ${bootargs} mac=${ethaddr}; fi' +for devtype in "mmc usb" ; do + if test "${devtype}" = "usb"; then + echo "start test usb"; + setenv l_mmc "0 1 2 3"; + fi; + for devnum in ${l_mmc} ; do + if test -e ${devtype} ${devnum} uEnv.txt; then + fatload ${devtype} ${devnum} ${env_addr} uEnv.txt; + env import -t ${env_addr} ${filesize}; + setenv bootargs ${APPEND}; + if printenv mac; then + setenv bootargs ${bootargs} mac=${mac}; + elif printenv eth_mac; then + setenv bootargs ${bootargs} mac=${eth_mac}; + fi; + if fatload ${devtype} ${devnum} ${kernel_addr_r} ${LINUX}; then + if fatload ${devtype} ${devnum} ${ramdisk_addr_r} ${INITRD}; then + if fatload ${devtype} ${devnum} ${fdt_addr_r} ${FDT}; then + fdt addr ${fdt_addr_r}; + run aadmac; + booti ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}; + fi; + fi; + fi; + fi; + done; +done; diff --git a/buildroot-external/board/jethome/jethub-h1/uboot.config b/buildroot-external/board/jethome/jethub-h1/uboot.config new file mode 100644 index 00000000000..4ab6d289f3c --- /dev/null +++ b/buildroot-external/board/jethome/jethub-h1/uboot.config @@ -0,0 +1,4 @@ +CONFIG_DOS_PARTITION=y +# CONFIG_EFI_PARTITION is not set +# CONFIG_USB_STORAGE is not set +CONFIG_DISPLAY_BOARDINFO=y diff --git a/buildroot-external/configs/jethub_h1_defconfig b/buildroot-external/configs/jethub_h1_defconfig new file mode 100644 index 00000000000..918856bd92a --- /dev/null +++ b/buildroot-external/configs/jethub_h1_defconfig @@ -0,0 +1,117 @@ +BR2_aarch64=y +BR2_cortex_a53=y +BR2_DL_DIR="/cache/dl" +BR2_CCACHE=y +BR2_CCACHE_DIR="/cache/cc" +BR2_OPTIMIZE_2=y +BR2_GLOBAL_PATCH_DIR="$(BR2_EXTERNAL_HASSOS_PATH)/patches $(BR2_EXTERNAL_HASSOS_PATH)/board/jethome/patches" + + +BR2_SSP_REGULAR=y +BR2_SSP_OPTION="-fstack-protector" +BR2_TOOLCHAIN_BUILDROOT_GLIBC=y + +BR2_BINUTILS_ENABLE_LTO=y + +BR2_GCC_VERSION_9_X=y +BR2_TOOLCHAIN_BUILDROOT_CXX=y +BR2_GCC_ENABLE_LTO=y +BR2_TARGET_GENERIC_HOSTNAME="homeassistant" +BR2_TARGET_GENERIC_ISSUE="Welcome to Home Assistant" +BR2_INIT_SYSTEMD=y +BR2_TARGET_GENERIC_GETTY_PORT="tty1" +# BR2_TARGET_GENERIC_REMOUNT_ROOTFS_RW is not set +BR2_ROOTFS_OVERLAY="$(BR2_EXTERNAL_HASSOS_PATH)/rootfs-overlay $(BR2_EXTERNAL_HASSOS_PATH)/board/jethome/rootfs-overlay $(BR2_EXTERNAL_HASSOS_PATH)/board/jethome/jethub-h1/rootfs-overlay" +BR2_ROOTFS_POST_BUILD_SCRIPT="$(BR2_EXTERNAL_HASSOS_PATH)/scripts/post-build.sh" +BR2_ROOTFS_POST_IMAGE_SCRIPT="$(BR2_EXTERNAL_HASSOS_PATH)/scripts/post-image.sh" +BR2_ROOTFS_POST_SCRIPT_ARGS="$(BR2_EXTERNAL_HASSOS_PATH)/board/jethome/jethub-h1 $(BR2_EXTERNAL_HASSOS_PATH)/board/jethome/jethub-h1/hassos-hook.sh" +BR2_LINUX_KERNEL=y +BR2_LINUX_KERNEL_CUSTOM_GIT=y +BR2_LINUX_KERNEL_CUSTOM_REPO_URL="https://github.com/jethome-ru/Amlogic_s905-kernel.git" +BR2_LINUX_KERNEL_CUSTOM_REPO_VERSION="5.7" +BR2_LINUX_KERNEL_VERSION="5.7" +BR2_LINUX_KERNEL_PATCH="$(BR2_EXTERNAL_HASSOS_PATH)/board/jethome/patches/kernel/arm-64-current" +BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y +BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="$(BR2_EXTERNAL_HASSOS_PATH)/board/jethome/kernel.config" +BR2_LINUX_KERNEL_CONFIG_FRAGMENT_FILES="$(BR2_EXTERNAL_HASSOS_PATH)/kernel/hassos.config $(BR2_EXTERNAL_HASSOS_PATH)/kernel/docker.config $(BR2_EXTERNAL_HASSOS_PATH)/kernel/device-support.config" +# BR2_LINUX_KERNEL_LZ4 is not set +BR2_LINUX_KERNEL_LZO=y +BR2_LINUX_KERNEL_DTS_SUPPORT=y +BR2_LINUX_KERNEL_INTREE_DTS_NAME="amlogic/meson-gxl-s905w-jethome-jethub-j80" +BR2_LINUX_KERNEL_CUSTOM_DTS_PATH="" +# BR2_LINUX_KERNEL_DTB_OVERLAY_SUPPORT=y +BR2_LINUX_KERNEL_NEEDS_HOST_OPENSSL=y +BR2_LINUX_KERNEL_NEEDS_HOST_LIBELF=y +BR2_PACKAGE_LINUX_FIRMWARE=y +BR2_PACKAGE_LINUX_FIRMWARE_RTL_88x2CS=y +BR2_PACKAGE_RTL8822CS=y + +BR2_PACKAGE_BUSYBOX_CONFIG="$(BR2_EXTERNAL_HASSOS_PATH)/busybox.config" +BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y +BR2_PACKAGE_PROCPS_NG=y +BR2_PACKAGE_JQ=y +BR2_PACKAGE_E2FSPROGS=y +BR2_PACKAGE_E2FSPROGS_E2IMAGE=y +BR2_PACKAGE_SQUASHFS=y +BR2_PACKAGE_CRDA=y +BR2_PACKAGE_GPTFDISK=y +BR2_PACKAGE_GPTFDISK_SGDISK=y +BR2_PACKAGE_UBOOT_TOOLS=y +BR2_PACKAGE_CA_CERTIFICATES=y +BR2_PACKAGE_LIBDNET=y +BR2_PACKAGE_LIBCGROUP=y +BR2_PACKAGE_LIBCGROUP_TOOLS=y +BR2_PACKAGE_BLUEZ5_UTILS=y +BR2_PACKAGE_BLUEZ5_UTILS_CLIENT=y +BR2_PACKAGE_BLUEZ5_UTILS_DEPRECATED=y +BR2_PACKAGE_DHCP=y +BR2_PACKAGE_DHCP_CLIENT=y +BR2_PACKAGE_DROPBEAR=y +BR2_PACKAGE_DROPBEAR_CLIENT=y +# BR2_PACKAGE_IFUPDOWN_SCRIPTS is not set +BR2_PACKAGE_NETWORK_MANAGER=y +BR2_PACKAGE_TINI=y +BR2_PACKAGE_DOCKER_ENGINE=y +BR2_PACKAGE_DOCKER_CLI=y +BR2_PACKAGE_RAUC=y +BR2_PACKAGE_RAUC_NETWORK=y +BR2_PACKAGE_RNG_TOOLS=y +# BR2_PACKAGE_SYSTEMD_HWDB is not set +# BR2_PACKAGE_SYSTEMD_NETWORKD is not set +BR2_PACKAGE_SYSTEMD_RANDOMSEED=y +BR2_PACKAGE_SYSTEMD_RESOLVED=y +BR2_PACKAGE_SYSTEMD_COREDUMP=y +BR2_PACKAGE_SYSTEMD_LOGIND=y +BR2_PACKAGE_UTIL_LINUX_PARTX=y +BR2_PACKAGE_UTIL_LINUX_ZRAMCTL=y +BR2_PACKAGE_UTIL_LINUX_LOGIN=y +BR2_PACKAGE_UTIL_LINUX_NOLOGIN=y +BR2_PACKAGE_USB_MODESWITCH=y +BR2_PACKAGE_USB_MODESWITCH_DATA=y +BR2_TARGET_ROOTFS_SQUASHFS=y +BR2_TARGET_ROOTFS_SQUASHFS4_LZ4=y +# BR2_TARGET_ROOTFS_TAR is not set +BR2_TARGET_UBOOT=y +BR2_TARGET_UBOOT_BOARD_DEFCONFIG="s400" +BR2_PACKAGE_HOST_UBOOT_TOOLS=y +BR2_PACKAGE_HOST_UBOOT_TOOLS_BOOT_SCRIPT=y +BR2_PACKAGE_HOST_UBOOT_TOOLS_BOOT_SCRIPT_SOURCE="$(BR2_EXTERNAL_HASSOS_PATH)/board/jethome/jethub-h1/uboot-boot.ush" +BR2_PACKAGE_HOST_LINUX_HEADERS_CUSTOM_5_7=y +BR2_PACKAGE_HOST_DOSFSTOOLS=y +BR2_PACKAGE_HOST_E2FSPROGS=y +BR2_PACKAGE_HOST_GPTFDISK=y +BR2_PACKAGE_HOST_MTOOLS=y +BR2_PACKAGE_HOST_RAUC=y +BR2_PACKAGE_HASSIO=y +BR2_PACKAGE_HASSIO_ARCH="aarch64" +#BR2_PACKAGE_HASSIO_MACHINE="jethub-h1" +BR2_PACKAGE_HASSIO_MACHINE="odroid-c2" +BR2_PACKAGE_APPARMOR=y +BR2_PACKAGE_APPARMOR_PROFILES=y +BR2_PACKAGE_JETHOME_BOOT=y +BR2_PACKAGE_JETHOME_BOOT_JETHUB_H1=y +BR2_PACKAGE_DOSFSTOOLS=y +BR2_PACKAGE_DOSFSTOOLS_FSCK_FAT=y + +BR2_PACKAGE_XZ=y +BR2_PACKAGE_RTK_HCIATTACH=y From 3cca6be4a6a956c7969d5271414ee2a96923d653 Mon Sep 17 00:00:00 2001 From: Vyacheslav Bocharov Date: Sat, 30 Jan 2021 17:36:44 +0300 Subject: [PATCH 10/11] Fix: remove unnecessary options for JetHub D1 --- buildroot-external/configs/jethub_d1_defconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/buildroot-external/configs/jethub_d1_defconfig b/buildroot-external/configs/jethub_d1_defconfig index f45470e082b..0a0cdfa5f7d 100644 --- a/buildroot-external/configs/jethub_d1_defconfig +++ b/buildroot-external/configs/jethub_d1_defconfig @@ -43,8 +43,6 @@ BR2_LINUX_KERNEL_CUSTOM_DTS_PATH="" BR2_LINUX_KERNEL_NEEDS_HOST_OPENSSL=y BR2_LINUX_KERNEL_NEEDS_HOST_LIBELF=y BR2_PACKAGE_LINUX_FIRMWARE=y -BR2_PACKAGE_LINUX_FIRMWARE_RTL_88x2CS=y -BR2_PACKAGE_RTL88x2CS=y BR2_PACKAGE_BUSYBOX_CONFIG="$(BR2_EXTERNAL_HASSOS_PATH)/busybox.config" BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y BR2_PACKAGE_PROCPS_NG=y From 38cf61994b808bed1ea41be7972621bbbe7e116a Mon Sep 17 00:00:00 2001 From: Vyacheslav Bocharov Date: Sat, 30 Jan 2021 17:37:22 +0300 Subject: [PATCH 11/11] Fix: rename and move common files for JetHome devices --- .../{jethub-d1 => }/bin/aml_image_v2_packer | Bin .../board/jethome/jethub-d1/bin/DDR.USB | Bin 49152 -> 0 bytes .../jethome/{jethub-d1 => }/kernel.config | 2 +- ...e-jethub-j80-dts-arm64-add-dts-files.patch | 15 +- ...add-dts-files.patch_enabled_ir_audio_hdmi} | 497 +++++++----------- .../etc/sysctl.d/20.min_free_kbytes.conf | 0 .../rootfs-overlay/usr/lib/jethome/initer | 1 + .../usr/lib/jethome/swap_file_maker | 0 .../lib/systemd/system/jethome-initer.service | 0 .../lib/systemd/system/jethome-swap.service | 0 .../usr/lib/udev/rules.d/aml-part.rules | 2 +- .../jethome/{jethub-d1/bin => src}/dtbTool.c | 0 12 files changed, 212 insertions(+), 305 deletions(-) rename buildroot-external/board/jethome/{jethub-d1 => }/bin/aml_image_v2_packer (100%) delete mode 100644 buildroot-external/board/jethome/jethub-d1/bin/DDR.USB rename buildroot-external/board/jethome/{jethub-d1 => }/kernel.config (99%) rename buildroot-external/board/jethome/patches/kernel/arm-64-current/{0004-jethome-0001-jethub-jxxx-dts-arm64-add-dts-files.patch => 0005-jethome-jethub-j80-dts-arm64-add-dts-files.patch_enabled_ir_audio_hdmi} (57%) rename buildroot-external/board/jethome/{jethub-d1 => }/rootfs-overlay/etc/sysctl.d/20.min_free_kbytes.conf (100%) rename buildroot-external/board/jethome/{jethub-d1 => }/rootfs-overlay/usr/lib/jethome/initer (93%) rename buildroot-external/board/jethome/{jethub-d1 => }/rootfs-overlay/usr/lib/jethome/swap_file_maker (100%) rename buildroot-external/board/jethome/{jethub-d1 => }/rootfs-overlay/usr/lib/systemd/system/jethome-initer.service (100%) rename buildroot-external/board/jethome/{jethub-d1 => }/rootfs-overlay/usr/lib/systemd/system/jethome-swap.service (100%) rename buildroot-external/board/jethome/{jethub-d1 => }/rootfs-overlay/usr/lib/udev/rules.d/aml-part.rules (83%) rename buildroot-external/board/jethome/{jethub-d1/bin => src}/dtbTool.c (100%) diff --git a/buildroot-external/board/jethome/jethub-d1/bin/aml_image_v2_packer b/buildroot-external/board/jethome/bin/aml_image_v2_packer similarity index 100% rename from buildroot-external/board/jethome/jethub-d1/bin/aml_image_v2_packer rename to buildroot-external/board/jethome/bin/aml_image_v2_packer diff --git a/buildroot-external/board/jethome/jethub-d1/bin/DDR.USB b/buildroot-external/board/jethome/jethub-d1/bin/DDR.USB deleted file mode 100644 index 5471a5a2bdff2d05d60d452946fa9f9105d3a985..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49152 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 diff --git a/buildroot-external/board/jethome/jethub-d1/kernel.config b/buildroot-external/board/jethome/kernel.config similarity index 99% rename from buildroot-external/board/jethome/jethub-d1/kernel.config rename to buildroot-external/board/jethome/kernel.config index aec734b362b..33f0f4037f7 100644 --- a/buildroot-external/board/jethome/jethub-d1/kernel.config +++ b/buildroot-external/board/jethome/kernel.config @@ -2897,7 +2897,7 @@ CONFIG_LSI_ET1011C_PHY=m CONFIG_LXT_PHY=m CONFIG_MARVELL_PHY=m CONFIG_MARVELL_10G_PHY=m -CONFIG_MESON_GXL_PHY=m +CONFIG_MESON_GXL_PHY=y CONFIG_MICREL_PHY=y CONFIG_MICROCHIP_PHY=m CONFIG_MICROCHIP_T1_PHY=m diff --git a/buildroot-external/board/jethome/patches/kernel/arm-64-current/0005-jethome-jethub-j80-dts-arm64-add-dts-files.patch b/buildroot-external/board/jethome/patches/kernel/arm-64-current/0005-jethome-jethub-j80-dts-arm64-add-dts-files.patch index 00ba701be90..5de89b0a076 100644 --- a/buildroot-external/board/jethome/patches/kernel/arm-64-current/0005-jethome-jethub-j80-dts-arm64-add-dts-files.patch +++ b/buildroot-external/board/jethome/patches/kernel/arm-64-current/0005-jethome-jethub-j80-dts-arm64-add-dts-files.patch @@ -3,7 +3,7 @@ new file mode 100644 index 000000000..cf0e6e742 --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905w-jethome-jethub-j80.dts -@@ -0,0 +1,368 @@ +@@ -0,0 +1,381 @@ + +/dts-v1/; + @@ -142,6 +142,10 @@ index 000000000..cf0e6e742 + clock-names = "ext_clock"; + }; + ++ sound { ++ status = "disabled"; ++ } ++ + efusekey: efusekey { + keynum = <5>; + key0 = <&key_0>; @@ -372,3 +376,12 @@ index 000000000..cf0e6e742 + }; +}; + ++&acodec { ++ status = "disabled"; ++}; ++&hdmi_tx { ++ status = "disabled"; ++}; ++&ir { ++ status = "disabled"; ++}; diff --git a/buildroot-external/board/jethome/patches/kernel/arm-64-current/0004-jethome-0001-jethub-jxxx-dts-arm64-add-dts-files.patch b/buildroot-external/board/jethome/patches/kernel/arm-64-current/0005-jethome-jethub-j80-dts-arm64-add-dts-files.patch_enabled_ir_audio_hdmi similarity index 57% rename from buildroot-external/board/jethome/patches/kernel/arm-64-current/0004-jethome-0001-jethub-jxxx-dts-arm64-add-dts-files.patch rename to buildroot-external/board/jethome/patches/kernel/arm-64-current/0005-jethome-jethub-j80-dts-arm64-add-dts-files.patch_enabled_ir_audio_hdmi index ea86d2210bf..00ba701be90 100644 --- a/buildroot-external/board/jethome/patches/kernel/arm-64-current/0004-jethome-0001-jethub-jxxx-dts-arm64-add-dts-files.patch +++ b/buildroot-external/board/jethome/patches/kernel/arm-64-current/0005-jethome-jethub-j80-dts-arm64-add-dts-files.patch_enabled_ir_audio_hdmi @@ -1,28 +1,9 @@ -diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile -index 666b1544c..903b9e1ab 100644 ---- a/arch/arm64/boot/dts/amlogic/Makefile -+++ b/arch/arm64/boot/dts/amlogic/Makefile -@@ -1,5 +1,6 @@ - # SPDX-License-Identifier: GPL-2.0 - dtb-$(CONFIG_ARCH_MESON) += meson-axg-s400.dtb -+dtb-$(CONFIG_ARCH_MESON) += meson-axg-jethome-jethub-j100.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-g12a-sei510.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-g12a-u200.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-g12a-x96-max.dtb -@@ -35,6 +36,7 @@ dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s805x-p241.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905w-p281.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905w-tx3-mini.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-libretech-pc.dtb -+dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905w-jethome-jethub-j80.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-gxm-khadas-vim2.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-gxm-nexbox-a1.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-gxm-q200.dtb diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905w-jethome-jethub-j80.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905w-jethome-jethub-j80.dts new file mode 100644 index 000000000..cf0e6e742 --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905w-jethome-jethub-j80.dts -@@ -0,0 +1,116 @@ +@@ -0,0 +1,368 @@ + +/dts-v1/; + @@ -32,22 +13,134 @@ index 000000000..cf0e6e742 +/ { + compatible = "amlogic,p281", "amlogic,s905w", "amlogic,meson-gxl"; + model = "JetHome JetHub J80"; -+ amlogic-dt-id = "gxl_jethubj80_v1"; ++ amlogic-dt-id = "gxl_j80_1g"; + ++ /* 1G RAM */ + memory@0 { + device_type = "memory"; + reg = <0x0 0x0 0x0 0x40000000>; + }; ++ partitions: partitions{ ++ parts = <8>; ++ part-0 = <&boot>; ++ part-1 = <&bootstate>; ++ part-2 = <&kernela>; ++ part-3 = <&systema>; ++ part-4 = <&kernelb>; ++ part-5 = <&systemb>; ++ part-6 = <&overlay>; ++ part-7 = <&data>; + -+ partitions: partitions { -+ parts = <1>; -+ part-0 = <&rootfs>; -+ rootfs: rootfs { -+ pname = "rootfs"; ++ boot:boot { ++ pname = "boot"; ++ size = <0x0 0x4000000>; ++ mask = <1>; ++ }; ++ bootstate:bootstate { ++ pname = "bootstate"; ++ size = <0x0 0x800000>; ++ mask = <4>; ++ }; ++ kernela:kernela { ++ pname = "kernela"; ++ size = <0x0 0x4000000>; ++ mask = <4>; ++ }; ++ systema:systema { ++ pname = "systema"; ++ size = <0x0 0x10000000>; ++ mask = <4>; ++ }; ++ kernelb:kernelb { ++ pname = "kernelb"; ++ size = <0x0 0x4000000>; ++ mask = <4>; ++ }; ++ systemb:systemb { ++ pname = "systemb"; ++ size = <0x0 0x10000000>; ++ mask = <4>; ++ }; ++ overlay:overlay { ++ pname = "overlay"; ++ size = <0x0 0x8000000>; ++ mask = <4>; ++ }; ++ data:data { ++ pname = "data"; + size = <0xffffffff 0xffffffff>; + mask = <4>; + }; + }; ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ linux,cma { ++ compatible = "shared-dma-pool"; ++ reusable; size = <0x0 0x400000>; ++ alignment = <0x0 0x400000>; ++ linux,cma-default; ++ }; ++ }; ++ aliases { ++ serial0 = &uart_AO; /* Console */ ++ serial1 = &uart_A; /* Bluetooth */ ++ serial2 = &uart_AO_B; /* Wireless module 1 */ ++ serial3 = &uart_C; /* Wireless module 2 */ ++ ethernet0 = ðmac; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ vddio_ao18: regulator-vddio_ao18 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VDDIO_AO18"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ }; ++ ++ vddio_boot: regulator-vddio_boot { ++ compatible = "regulator-fixed"; ++ regulator-name = "VDDIO_BOOT"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ }; ++ ++ vddao_3v3: regulator-vddao_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VDDAO_3V3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ vcc_3v3: regulator-vcc_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VCC_3V3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ emmc_pwrseq: emmc-pwrseq { ++ compatible = "mmc-pwrseq-emmc"; ++ reset-gpios = <&gpio BOOT_9 GPIO_ACTIVE_LOW>; ++ }; ++ ++ wifi32k: wifi32k { ++ compatible = "pwm-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <32768>; ++ pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */ ++ }; ++ ++ sdio_pwrseq: sdio-pwrseq { ++ compatible = "mmc-pwrseq-simple"; ++ reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>; ++ clocks = <&wifi32k>; ++ clock-names = "ext_clock"; ++ }; + + efusekey: efusekey { + keynum = <5>; @@ -139,287 +232,64 @@ index 000000000..cf0e6e742 + key = <&efusekey>; + clock-names = "efuse_clk"; +}; -diff --git a/arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j100.dts b/arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j100.dts -new file mode 100644 -index 000000000..8e6bd30ca ---- /dev/null -+++ b/arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j100.dts -@@ -0,0 +1,334 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+/* -+ * Copyright (c) 2017 Amlogic, Inc. All rights reserved. -+ */ -+ -+/dts-v1/; -+ -+#include "meson-axg.dtsi" -+#include -+ -+/ { -+ compatible = "jethome,j100", "amlogic,a113d", "amlogic,meson-axg"; -+ model = "JetHome JetHub J100 Compatible Board"; -+ amlogic-dt-id = "jethome_j100_v1"; -+ -+ aliases { -+ serial0 = &uart_AO; /* Console */ -+ serial1 = &uart_B; /* Bluetooth */ -+ serial2 = &uart_AO_B; /* External UART (Wireless Module) */ -+ }; -+ -+ chosen { -+ stdout-path = "serial0:115200n8"; -+ }; -+ -+ /* 512MB RAM */ -+ memory@0 { -+ device_type = "memory"; -+ reg = <0x0 0x0 0x0 0x20000000>; -+ }; -+ -+ emmc_pwrseq: emmc-pwrseq { -+ compatible = "mmc-pwrseq-emmc"; -+ reset-gpios = <&gpio BOOT_9 GPIO_ACTIVE_LOW>; -+ }; -+ -+ vcc_3v3: regulator-vcc_3v3 { -+ compatible = "regulator-fixed"; -+ regulator-name = "VCC_3V3"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ vin-supply = <&vddao_3v3>; -+ regulator-always-on; -+ }; -+ -+ vcc_5v: regulator-vcc_5v { -+ compatible = "regulator-fixed"; -+ regulator-name = "VCC5V"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ regulator-always-on; -+ }; -+ -+ vddao_3v3: regulator-vddao_3v3 { -+ compatible = "regulator-fixed"; -+ regulator-name = "VDDAO_3V3"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ vin-supply = <&vcc_5v>; -+ regulator-always-on; -+ }; -+ -+ vddio_ao18: regulator-vddio_ao18 { -+ compatible = "regulator-fixed"; -+ regulator-name = "VDDIO_AO18"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ vin-supply = <&vddao_3v3>; -+ regulator-always-on; -+ }; -+ -+ vddio_boot: regulator-vddio_boot { -+ compatible = "regulator-fixed"; -+ regulator-name = "VDDIO_BOOT"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ vin-supply = <&vddao_3v3>; -+ regulator-always-on; -+ }; -+ -+ usb_pwr: regulator-usb_pwr { -+ compatible = "regulator-fixed"; -+ regulator-name = "USB_PWR"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ vin-supply = <&vcc_5v>; -+ regulator-always-on; -+ }; -+ -+ sdio_pwrseq: sdio-pwrseq { -+ compatible = "mmc-pwrseq-simple"; -+ reset-gpios = <&gpio GPIOX_7 GPIO_ACTIVE_LOW>; -+ clocks = <&wifi32k>; -+ clock-names = "ext_clock"; -+ }; -+ -+ wifi32k: wifi32k { -+ compatible = "pwm-clock"; -+ #clock-cells = <0>; -+ clock-frequency = <32768>; -+ pwms = <&pwm_ab 0 30518 0>; /* PWM_A at 32.768KHz */ -+ }; -+ partitions: partitions{ -+ parts = <8>; -+ part-0 = <&boot>; -+ part-1 = <&bootstate>; -+ part-2 = <&kernela>; -+ part-3 = <&systema>; -+ part-4 = <&kernelb>; -+ part-5 = <&systemb>; -+ part-6 = <&overlay>; -+ part-7 = <&data>; -+ -+ boot:boot { -+ pname = "boot"; -+ size = <0x0 0x4000000>; -+ mask = <1>; -+ }; -+ bootstate:bootstate { -+ pname = "bootstate"; -+ size = <0x0 0x800000>; -+ mask = <4>; -+ }; -+ kernela:kernela { -+ pname = "kernela"; -+ size = <0x0 0x4000000>; -+ mask = <4>; -+ }; -+ systema:systema { -+ pname = "systema"; -+ size = <0x0 0x10000000>; -+ mask = <4>; -+ }; -+ kernelb:kernelb { -+ pname = "kernelb"; -+ size = <0x0 0x4000000>; -+ mask = <4>; -+ }; -+ systemb:systemb { -+ pname = "systemb"; -+ size = <0x0 0x10000000>; -+ mask = <4>; -+ }; -+ overlay:overlay { -+ pname = "overlay"; -+ size = <0x0 0x8000000>; -+ mask = <4>; -+ }; -+ data:data { -+ pname = "data"; -+ size = <0xffffffff 0xffffffff>; -+ mask = <4>; -+ }; -+ }; -+ // It is necessary only as key map to read efuse values from nvmem from Armbian OS. -+ efusekey:efusekey{ -+ keynum = <4>; -+ key0 = <&key_0>; -+ key1 = <&key_1>; -+ key2 = <&key_2>; -+ key3 = <&key_3>; -+ key_0:key_0{ -+ keyname = "mac"; -+ offset = <0>; -+ size = <6>; -+ }; -+ key_1:key_1{ -+ keyname = "mac_bt"; -+ offset = <6>; -+ size = <6>; -+ }; -+ key_2:key_2{ -+ keyname = "mac_wifi"; -+ offset = <12>; -+ size = <6>; -+ }; -+ key_3:key_3{ -+ keyname = "usid"; -+ offset = <18>; -+ size = <32>; -+ }; -+ }; -+ reserved-memory { -+ #address-cells = <2>; -+ #size-cells = <2>; -+ ranges; -+ linux,cma { -+ compatible = "shared-dma-pool"; -+ reusable; size = <0x0 0x400000>; -+ alignment = <0x0 0x400000>; -+ linux,cma-default; -+ }; -+ }; -+ -+}; + -+ðmac { ++&pwm_ef { + status = "okay"; -+ pinctrl-0 = <ð_rmii_x_pins>; ++ pinctrl-0 = <&pwm_e_pins>; + pinctrl-names = "default"; -+ phy-handle = <ð_phy0>; -+ phy-mode = "rmii"; -+ internal_phy=<0>; -+ interrupts = ; -+ -+ mdio { -+ compatible = "snps,dwmac-mdio"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ /* ICPlus IP101A/G Ethernet PHY (vendor_id=0x0243, model_id=0x0c54) */ -+ eth_phy0: ethernet-phy@0 { -+ compatible = "ethernet-phy-id0243.0c54"; -+ max-speed = <100>; -+ reg = <0>; -+ }; -+ }; ++ clocks = <&clkc CLKID_FCLK_DIV4>; ++ clock-names = "clkin0"; +}; + -+/* Internal I2C bus (on CPU module) */ -+&i2c1 { ++&saradc { + status = "okay"; -+ pinctrl-0 = <&i2c1_z_pins>; -+ pinctrl-names = "default"; -+ -+ /* RTC */ -+ pcf8563: pcf8563@51 { -+ compatible = "nxp,pcf8563"; -+ reg = <0x51>; -+ status = "okay"; -+ }; ++ vref-supply = <&vddio_ao18>; +}; + -+/* Peripheral I2C bus (on motherboard) */ -+&i2c_AO { ++/* Wireless SDIO Module */ ++&sd_emmc_a { + status = "okay"; -+ pinctrl-0 = <&i2c_ao_sck_10_pins>, <&i2c_ao_sda_11_pins>; -+ pinctrl-names = "default"; -+}; -+ -+&pwm_ab { -+ status = "okay"; -+ pinctrl-0 = <&pwm_a_x20_pins>; -+ pinctrl-names = "default"; -+}; -+ -+/* wifi module */ -+&sd_emmc_b { -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ + pinctrl-0 = <&sdio_pins>; + pinctrl-1 = <&sdio_clk_gate_pins>; + pinctrl-names = "default", "clk-gate"; ++ #address-cells = <1>; ++ #size-cells = <0>; + + bus-width = <4>; + cap-sd-highspeed; -+ sd-uhs-sdr104; -+ max-frequency = <200000000>; ++ max-frequency = <50000000>; ++ + non-removable; + disable-wp; + ++ /* WiFi firmware requires power to be kept while in suspend */ ++ keep-power-in-suspend; ++ + mmc-pwrseq = <&sdio_pwrseq>; + + vmmc-supply = <&vddao_3v3>; + vqmmc-supply = <&vddio_boot>; ++}; + -+ brcmf: wifi@1 { -+ reg = <1>; -+ compatible = "brcm,bcm4329-fmac"; -+ }; ++/* SD card */ ++&sd_emmc_b { ++ status = "okay"; ++ pinctrl-0 = <&sdcard_pins>; ++ pinctrl-1 = <&sdcard_clk_gate_pins>; ++ pinctrl-names = "default", "clk-gate"; ++ ++ bus-width = <4>; ++ cap-sd-highspeed; ++ max-frequency = <50000000>; ++ disable-wp; ++ ++ cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_LOW>; ++ ++ vmmc-supply = <&vddao_3v3>; ++ vqmmc-supply = <&vddio_boot>; +}; + -+/* emmc storage */ ++/* eMMC */ +&sd_emmc_c { + status = "okay"; + pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>; @@ -435,47 +305,70 @@ index 000000000..8e6bd30ca + mmc-hs200-1_8v; + + mmc-pwrseq = <&emmc_pwrseq>; -+ + vmmc-supply = <&vcc_3v3>; + vqmmc-supply = <&vddio_boot>; +}; + -+/* UART Bluetooth */ -+&uart_B { ++/* Console UART */ ++&uart_AO { + status = "okay"; -+ pinctrl-0 = <&uart_b_z_pins>, <&uart_b_z_cts_rts_pins>; ++ pinctrl-0 = <&uart_ao_a_pins>; + pinctrl-names = "default"; -+ uart-has-rtscts; ++}; + -+ bluetooth { -+ compatible = "brcm,bcm43438-bt"; -+ shutdown-gpios = <&gpio GPIOZ_7 GPIO_ACTIVE_HIGH>; -+ }; ++&usb0 { ++ status = "okay"; +}; + -+/* UART Console */ -+&uart_AO { ++/* S905X only has access to its internal PHY */ ++ðmac { + status = "okay"; -+ pinctrl-0 = <&uart_ao_a_pins>; ++ phy-mode = "rmii"; ++ phy-handle = <&internal_phy>; ++}; ++ ++&internal_phy { ++ status = "okay"; ++ pinctrl-0 = <ð_link_led_pins>, <ð_act_led_pins>; + pinctrl-names = "default"; +}; + -+/* UART Wireless module */ -+&uart_AO_B { ++&uart_A { + status = "okay"; -+ pinctrl-0 = <&uart_ao_b_pins>; ++ pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; + pinctrl-names = "default"; ++ // uart-has-rtscts; ++ ++ /* ++ bluetooth { ++ compatible = "realtek,rtl8822cs-bt"; ++ enable-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; ++ }; ++ */ +}; + -+&usb0 { ++&uart_C { + status = "okay"; -+ phy-supply = <&usb_pwr>; ++ pinctrl-0 = <&uart_c_pins>; ++ pinctrl-names = "default"; +}; + -+&spicc1 { ++&uart_AO_B { + status = "okay"; ++ pinctrl-0 = <&uart_ao_b_pins>, <&uart_ao_b_cts_rts_pins>; ++ pinctrl-names = "default"; ++ uart-has-rtscts; +}; + -+&audio { -+ status = "disabled"; ++&i2c_B { ++ status = "okay"; ++ pinctrl-names="default"; ++ pinctrl-0=<&i2c_b_pins>; ++ ++ pcf8563: pcf8563@51 { ++ compatible = "nxp,pcf8563"; ++ reg = <0x51>; ++ status = "okay"; ++ }; +}; ++ diff --git a/buildroot-external/board/jethome/jethub-d1/rootfs-overlay/etc/sysctl.d/20.min_free_kbytes.conf b/buildroot-external/board/jethome/rootfs-overlay/etc/sysctl.d/20.min_free_kbytes.conf similarity index 100% rename from buildroot-external/board/jethome/jethub-d1/rootfs-overlay/etc/sysctl.d/20.min_free_kbytes.conf rename to buildroot-external/board/jethome/rootfs-overlay/etc/sysctl.d/20.min_free_kbytes.conf diff --git a/buildroot-external/board/jethome/jethub-d1/rootfs-overlay/usr/lib/jethome/initer b/buildroot-external/board/jethome/rootfs-overlay/usr/lib/jethome/initer similarity index 93% rename from buildroot-external/board/jethome/jethub-d1/rootfs-overlay/usr/lib/jethome/initer rename to buildroot-external/board/jethome/rootfs-overlay/usr/lib/jethome/initer index ccbb7b5d618..d85429add5f 100755 --- a/buildroot-external/board/jethome/jethub-d1/rootfs-overlay/usr/lib/jethome/initer +++ b/buildroot-external/board/jethome/rootfs-overlay/usr/lib/jethome/initer @@ -4,6 +4,7 @@ SRC=$( cd -P -- "$(dirname -- "$(command -v -- "$0")")" && pwd -P ) if grep -Eq "^GXL.+S905W" /sys/devices/soc0/soc_id; then echo "Amlogic S905W detected." + bash "$SRC/init_j80" elif grep -Eq "^AXG" /sys/devices/soc0/soc_id; then echo "Amlogic AXG detected." bash "$SRC/init_j100" diff --git a/buildroot-external/board/jethome/jethub-d1/rootfs-overlay/usr/lib/jethome/swap_file_maker b/buildroot-external/board/jethome/rootfs-overlay/usr/lib/jethome/swap_file_maker similarity index 100% rename from buildroot-external/board/jethome/jethub-d1/rootfs-overlay/usr/lib/jethome/swap_file_maker rename to buildroot-external/board/jethome/rootfs-overlay/usr/lib/jethome/swap_file_maker diff --git a/buildroot-external/board/jethome/jethub-d1/rootfs-overlay/usr/lib/systemd/system/jethome-initer.service b/buildroot-external/board/jethome/rootfs-overlay/usr/lib/systemd/system/jethome-initer.service similarity index 100% rename from buildroot-external/board/jethome/jethub-d1/rootfs-overlay/usr/lib/systemd/system/jethome-initer.service rename to buildroot-external/board/jethome/rootfs-overlay/usr/lib/systemd/system/jethome-initer.service diff --git a/buildroot-external/board/jethome/jethub-d1/rootfs-overlay/usr/lib/systemd/system/jethome-swap.service b/buildroot-external/board/jethome/rootfs-overlay/usr/lib/systemd/system/jethome-swap.service similarity index 100% rename from buildroot-external/board/jethome/jethub-d1/rootfs-overlay/usr/lib/systemd/system/jethome-swap.service rename to buildroot-external/board/jethome/rootfs-overlay/usr/lib/systemd/system/jethome-swap.service diff --git a/buildroot-external/board/jethome/jethub-d1/rootfs-overlay/usr/lib/udev/rules.d/aml-part.rules b/buildroot-external/board/jethome/rootfs-overlay/usr/lib/udev/rules.d/aml-part.rules similarity index 83% rename from buildroot-external/board/jethome/jethub-d1/rootfs-overlay/usr/lib/udev/rules.d/aml-part.rules rename to buildroot-external/board/jethome/rootfs-overlay/usr/lib/udev/rules.d/aml-part.rules index 2f32d272962..10954b9b417 100644 --- a/buildroot-external/board/jethome/jethub-d1/rootfs-overlay/usr/lib/udev/rules.d/aml-part.rules +++ b/buildroot-external/board/jethome/rootfs-overlay/usr/lib/udev/rules.d/aml-part.rules @@ -1,5 +1,5 @@ KERNEL=="mmcblk1p6", SYMLINK+="disk/by-partlabel/hassos-boot" -KERNEL=="mmcblk1p7", SYMLINK+="disk/by-partlabel/hassos-bootstate" +KERNEL=="mmcblk1p5", SYMLINK+="disk/by-partlabel/hassos-bootstate" KERNEL=="mmcblk1p8", SYMLINK+="disk/by-partlabel/hassos-kernel0" KERNEL=="mmcblk1p9", SYMLINK+="disk/by-partlabel/hassos-system0" KERNEL=="mmcblk1p10", SYMLINK+="disk/by-partlabel/hassos-kernel1" diff --git a/buildroot-external/board/jethome/jethub-d1/bin/dtbTool.c b/buildroot-external/board/jethome/src/dtbTool.c similarity index 100% rename from buildroot-external/board/jethome/jethub-d1/bin/dtbTool.c rename to buildroot-external/board/jethome/src/dtbTool.c