Merge pull request #15 from hkfuertes/mifi_smb1360

Add Device MF68E With Display
This commit is contained in:
Miguel Fuertes authored and GitHub committed 2025-10-16 22:00:27 +02:00
commit abbd7ae450
25 files changed
+1466 -20

No files matched your search

+97
View File
@@ -0,0 +1,97 @@
name: OpenWrt Builder (MF68E)
on:
repository_dispatch:
workflow_dispatch:
env:
UPLOAD_BIN_DIR: true
UPLOAD_FIRMWARE: true
UPLOAD_RELEASE: false
TZ: Europe/Madrid
jobs:
build:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Initialization environment
env:
DEBIAN_FRONTEND: noninteractive
run: |
sudo rm -rf /etc/apt/sources.list.d/* /usr/share/dotnet /usr/local/lib/android /opt/ghc /opt/hostedtoolcache/CodeQL
sudo docker image prune --all --force
sudo -E apt-get -qq update
sudo -E ./devenv/dependencies.sh
sudo -E apt-get -qq autoremove --purge
sudo -E apt-get -qq clean
sudo timedatectl set-timezone "$TZ"
- name: "Clone OpenWrt source code"
run: |
df -hT $PWD
git clone --depth=1 --branch "main" https://git.openwrt.org/openwrt/openwrt.git openwrt
- name: Load msm89xx target and uz801 packages
run: |
git apply --unsafe-paths enable_wcn36xx_mac80211.patch
mv msm89xx openwrt/target/linux/msm89xx
mv packages openwrt/package/uz801
if [ "${{ inputs.openwrt_version }}" == "openwrt-24.10" ]; then
sed -i '/^KERNEL_PATCHVER/c\KERNEL_PATCHVER:=6.6' openwrt/target/linux/msm89xx/Makefile
fi
- name: Update and install feeds
run: |
cd openwrt
rm -rf tmp
./scripts/feeds update -a
./scripts/feeds install -a
- name: "Load diffconfig"
run: |
[ -f mf68e_diffconfig ] && mv mf68e_diffconfig openwrt/.config
- name: Download package
id: package
run: |
cd openwrt
make defconfig
make download -j8
find dl -size -1024c -exec ls -l {} \; || true
find dl -size -1024c -exec rm -f {} \; || true
- name: Compile the firmware
id: compile
run: |
cd openwrt
echo -e "$(nproc) thread compile"
make -j$(nproc) || make -j1 || make -j1 V=s
echo "status=success" >> $GITHUB_OUTPUT
grep '^CONFIG_TARGET.*DEVICE.*=y' .config | sed -r 's/.*DEVICE_(.*)=y/\1/' > DEVICE_NAME
[ -s DEVICE_NAME ] && echo "DEVICE_NAME=$(cat DEVICE_NAME)" >> $GITHUB_ENV
echo "FILE_DATE=$(date +"%Y%m%d%H%M")" >> $GITHUB_ENV
- name: Organize files
id: organize
if: env.UPLOAD_FIRMWARE == 'true' && !cancelled()
run: |
cd openwrt/bin/targets/*/*
rm -rf packages
echo "FIRMWARE=$PWD" >> $GITHUB_ENV
echo "status=success" >> $GITHUB_OUTPUT
- name: Upload firmware
uses: actions/upload-artifact@v4
if: steps.organize.outputs.status == 'success' && !cancelled()
with:
name: openwrt_firmware_${{ env.DEVICE_NAME }}_${{ env.FILE_DATE }}
path: |
${{ env.FIRMWARE }}/openwrt-msm89xx-msm8916-yiming-uz801v3-squashfs-gpt_both0.bin
${{ env.FIRMWARE }}/openwrt-msm89xx-msm8916-yiming-uz801v3-squashfs-boot.img
${{ env.FIRMWARE }}/openwrt-msm89xx-msm8916-yiming-uz801v3-squashfs-system.img
${{ env.FIRMWARE }}/openwrt-msm89xx-msm8916-yiming-uz801v3.manifest
${{ env.FIRMWARE }}/openwrt-msm89xx-msm8916-yiming-uz801v3-flash.sh
${{ env.FIRMWARE }}/openwrt-msm89xx-msm8916-yiming-uz801v3-firmware.zip
@@ -1,4 +1,4 @@
name: OpenWrt Builder
name: OpenWrt Builder (UZ801)
on:
repository_dispatch:
workflow_dispatch:
-1
View File
@@ -22,7 +22,6 @@ CONFIG_PACKAGE_kmod-tun=y
CONFIG_PACKAGE_kmod-udptunnel4=y
CONFIG_PACKAGE_kmod-udptunnel6=y
CONFIG_PACKAGE_kmod-wireguard=y
CONFIG_PACKAGE_ledcontrol=y
CONFIG_PACKAGE_libattr=y
CONFIG_PACKAGE_libdbus=y
CONFIG_PACKAGE_libexpat=y
+94
View File
@@ -0,0 +1,94 @@
CONFIG_TARGET_msm89xx=y
CONFIG_TARGET_msm89xx_msm8916=y
CONFIG_TARGET_msm89xx_msm8916_DEVICE_generic-mf68e=y
CONFIG_BUSYBOX_CUSTOM=y
CONFIG_BUSYBOX_CONFIG_FBSET=y
CONFIG_BUSYBOX_CONFIG_USLEEP=y
CONFIG_LIBQMI_COLLECTION_BASIC=y
CONFIG_LIBQMI_WITH_MBIM_QMUX=y
CONFIG_LIBQMI_WITH_QRTR_GLIB=y
CONFIG_MODEMMANAGER_WITH_MBIM=y
CONFIG_MODEMMANAGER_WITH_NETIFD=y
CONFIG_MODEMMANAGER_WITH_QMI=y
CONFIG_MODEMMANAGER_WITH_QRTR=y
CONFIG_PACKAGE_bash=y
CONFIG_PACKAGE_cgi-io=y
CONFIG_PACKAGE_dbus=y
CONFIG_PACKAGE_glib2=y
CONFIG_PACKAGE_ip-tiny=y
CONFIG_PACKAGE_kmod-crypto-kpp=y
CONFIG_PACKAGE_kmod-crypto-lib-chacha20=y
CONFIG_PACKAGE_kmod-crypto-lib-chacha20poly1305=y
CONFIG_PACKAGE_kmod-crypto-lib-curve25519=y
CONFIG_PACKAGE_kmod-crypto-lib-poly1305=y
CONFIG_PACKAGE_kmod-tun=y
CONFIG_PACKAGE_kmod-udptunnel4=y
CONFIG_PACKAGE_kmod-udptunnel6=y
CONFIG_PACKAGE_kmod-wireguard=y
CONFIG_PACKAGE_libattr=y
CONFIG_PACKAGE_libdbus=y
CONFIG_PACKAGE_libexpat=y
CONFIG_PACKAGE_libfdisk=y
CONFIG_PACKAGE_libffi=y
CONFIG_PACKAGE_libiwinfo=y
CONFIG_PACKAGE_libiwinfo-data=y
CONFIG_PACKAGE_liblua=y
CONFIG_PACKAGE_liblucihttp=y
CONFIG_PACKAGE_liblucihttp-lua=y
CONFIG_PACKAGE_liblucihttp-ucode=y
CONFIG_PACKAGE_libmbim=y
CONFIG_PACKAGE_libmount=y
CONFIG_PACKAGE_libncurses=y
CONFIG_PACKAGE_libpcre2=y
CONFIG_PACKAGE_libqmi=y
CONFIG_PACKAGE_libqrtr-glib=y
CONFIG_PACKAGE_libreadline=y
CONFIG_PACKAGE_libubus-lua=y
CONFIG_PACKAGE_lsblk=y
CONFIG_PACKAGE_lua=y
CONFIG_PACKAGE_luci=y
CONFIG_PACKAGE_luci-app-firewall=y
CONFIG_PACKAGE_luci-app-package-manager=y
CONFIG_PACKAGE_luci-app-usb-gadget=y
CONFIG_PACKAGE_luci-base=y
CONFIG_PACKAGE_luci-lib-base=y
CONFIG_PACKAGE_luci-lib-ip=y
CONFIG_PACKAGE_luci-lib-json=y
CONFIG_PACKAGE_luci-lib-jsonc=y
CONFIG_PACKAGE_luci-lib-nixio=y
CONFIG_PACKAGE_luci-lib-uqr=y
CONFIG_PACKAGE_luci-light=y
CONFIG_PACKAGE_luci-lua-runtime=y
CONFIG_PACKAGE_luci-mod-admin-full=y
CONFIG_PACKAGE_luci-mod-network=y
CONFIG_PACKAGE_luci-mod-rpc=y
CONFIG_PACKAGE_luci-mod-status=y
CONFIG_PACKAGE_luci-mod-system=y
CONFIG_PACKAGE_luci-proto-ipv6=y
CONFIG_PACKAGE_luci-proto-modemmanager=y
CONFIG_PACKAGE_luci-proto-ppp=y
CONFIG_PACKAGE_luci-proto-wireguard=y
CONFIG_PACKAGE_luci-theme-bootstrap=y
CONFIG_PACKAGE_modemmanager=y
CONFIG_PACKAGE_mount-utils=y
CONFIG_PACKAGE_mtools=y
CONFIG_PACKAGE_nano=y
CONFIG_PACKAGE_resize2fs=y
CONFIG_PACKAGE_resolveip=y
CONFIG_PACKAGE_rpcd=y
CONFIG_PACKAGE_rpcd-mod-file=y
CONFIG_PACKAGE_rpcd-mod-iwinfo=y
CONFIG_PACKAGE_rpcd-mod-luci=y
CONFIG_PACKAGE_rpcd-mod-rrdns=y
CONFIG_PACKAGE_rpcd-mod-ucode=y
CONFIG_PACKAGE_sfdisk=y
CONFIG_PACKAGE_terminfo=y
CONFIG_PACKAGE_tune2fs=y
CONFIG_PACKAGE_ucode-mod-html=y
CONFIG_PACKAGE_ucode-mod-log=y
CONFIG_PACKAGE_ucode-mod-lua=y
CONFIG_PACKAGE_ucode-mod-math=y
CONFIG_PACKAGE_uhttpd=y
CONFIG_PACKAGE_uhttpd-mod-ubus=y
CONFIG_PACKAGE_wireguard-tools=y
# CONFIG_TARGET_ROOTFS_EXT4FS is not set
+20 -12
View File
@@ -1,4 +1,5 @@
# CONFIG_ARM_MHU_V2 is not set
# CONFIG_ARM_MHU_V3 is not set
# CONFIG_ARM_QCOM_CPUFREQ_HW is not set
@@ -22,6 +23,7 @@
# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
# CONFIG_CMA_SYSFS is not set
# CONFIG_COMPAT_ALIGNMENT_FIXUPS is not set
# CONFIG_CONSOLE_TRANSLATIONS is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
@@ -35,9 +37,13 @@
# CONFIG_DEVFREQ_GOV_POWERSAVE is not set
# CONFIG_DEVFREQ_GOV_USERSPACE is not set
# CONFIG_DEVFREQ_THERMAL is not set
# CONFIG_DRM_MSM is not set
# CONFIG_DUMMY_CONSOLE is not set
# CONFIG_EC_ACER_ASPIRE1 is not set
# CONFIG_EXPERT is not set
# CONFIG_FIPS_SIGNATURE_SELFTEST is not set
# CONFIG_FORTIFY_SOURCE is not set
# CONFIG_FRAMEBUFFER_CONSOLE is not set
# CONFIG_FW_LOADER_USER_HELPER is not set
# CONFIG_GCC_PLUGIN_LATENT_ENTROPY is not set
# CONFIG_GCC_PLUGIN_STACKLEAK is not set
@@ -69,6 +75,7 @@
# CONFIG_KPSS_XCC is not set
# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set
# CONFIG_LEDS_TRIGGER_NETDEV is not set
# CONFIG_LOGO is not set
# CONFIG_LWTUNNEL_BPF is not set
# CONFIG_MAILBOX_TEST is not set
# CONFIG_MFD_HI6421_SPMI is not set
@@ -260,6 +267,9 @@
# CONFIG_VIRTIO_IOMMU is not set
# CONFIG_VIRTIO_MENU is not set
# CONFIG_VIRTIO_NET is not set
# CONFIG_VT is not set
# CONFIG_VT_CONSOLE is not set
# CONFIG_VT_HW_CONSOLE_BINDING is not set
CONFIG_64BIT=y
CONFIG_ARCH_BINFMT_ELF_EXTRA_PHDRS=y
CONFIG_ARCH_CORRECT_STACKTRACE_ON_KRETPROBE=y
@@ -323,7 +333,10 @@ CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y
CONFIG_AUTOFS_FS=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_BACKLIGHT_GPIO=y
CONFIG_BACKLIGHT_PWM=y
CONFIG_BATTERY_PM8916_BMS_VM=y
CONFIG_BATTERY_PM8916_BMS=y
CONFIG_BLK_DEBUG_FS=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_SD=y
@@ -342,6 +355,7 @@ CONFIG_BUILTIN_RETURN_ADDRESS_STRIPS_PAC=y
CONFIG_CACHESTAT_SYSCALL=y
CONFIG_CC_HAVE_SHADOW_CALL_STACK=y
CONFIG_CC_HAVE_STACKPROTECTOR_SYSREG=y
CONFIG_CHARGER_PM8916_LBC=y
CONFIG_CLONE_BACKWARDS=y
CONFIG_CLZ_TAB=y
CONFIG_CMA_ALIGNMENT=8
@@ -357,7 +371,6 @@ CONFIG_COMPAT_BINFMT_ELF=y
CONFIG_COMPAT_OLD_SIGACTION=y
CONFIG_COMPAT=y
CONFIG_CONFIGFS_FS=y
CONFIG_CONSOLE_TRANSLATIONS=y
CONFIG_CONTEXT_TRACKING_IDLE=y
CONFIG_CONTEXT_TRACKING=y
CONFIG_CONTIG_ALLOC=y
@@ -468,7 +481,6 @@ CONFIG_DST_CACHE=y
CONFIG_DT_IDLE_GENPD=y
CONFIG_DT_IDLE_STATES=y
CONFIG_DTC=y
CONFIG_DUMMY_CONSOLE=y
CONFIG_EDAC_SUPPORT=y
CONFIG_ELF_CORE=y
CONFIG_EXCLUSIVE_SYSTEM_RAM=y
@@ -481,8 +493,12 @@ CONFIG_EXTCON_USB_GPIO=y
CONFIG_EXTCON=y
CONFIG_FANOTIFY=y
CONFIG_FAT_FS=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_IMAGEBLIT=y
CONFIG_FB_CORE=y
CONFIG_FB=y
CONFIG_FB=y
CONFIG_FHANDLE=y
CONFIG_FIX_EARLYCON_MEM=y
CONFIG_FIXED_PHY=y
@@ -490,9 +506,6 @@ CONFIG_FONT_8x16=y
CONFIG_FONT_8x8=y
CONFIG_FONT_SUPPORT=y
CONFIG_FRAME_POINTER=y
CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_FS_IOMAP=y
CONFIG_FS_MBCACHE=y
CONFIG_FS_POSIX_ACL=y
@@ -632,10 +645,6 @@ CONFIG_LOCALVERSION_AUTO=y
CONFIG_LOCALVERSION="-msm8916"
CONFIG_LOCK_DEBUGGING_SUPPORT=y
CONFIG_LOCK_SPIN_ON_OWNER=y
CONFIG_LOGO_LINUX_CLUT224=y
CONFIG_LOGO_LINUX_MONO=y
CONFIG_LOGO_LINUX_VGA16=y
CONFIG_LOGO=y
CONFIG_LRU_GEN_WALKS_MMU=y
CONFIG_LSM="landlock,lockdown,yama,loadpin,safesetid,integrity,bpf"
CONFIG_LWTUNNEL=y
@@ -710,6 +719,7 @@ CONFIG_OF_DYNAMIC=y
CONFIG_OF_EARLY_FLATTREE=y
CONFIG_OF_FLATTREE=y
CONFIG_OF_GPIO=y
CONFIG_OF_GRAPH=y
CONFIG_OF_IOMMU=y
CONFIG_OF_IRQ=y
CONFIG_OF_KOBJ=y
@@ -959,15 +969,13 @@ CONFIG_UTS_NS=y
CONFIG_VDSO_GETRANDOM=y
CONFIG_VFAT_FS=y
CONFIG_VIDEO=y
CONFIG_VIDEOMODE_HELPERS=y
CONFIG_VIRTIO_ANCHOR=y
CONFIG_VIRTIO=y
CONFIG_VLAN_8021Q_GVRP=y
CONFIG_VLAN_8021Q_MVRP=y
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_VMAP_STACK=y
CONFIG_VT_CONSOLE=y
CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_VT=y
CONFIG_WANT_DEV_COREDUMP=y
CONFIG_WATCHDOG_CORE=y
CONFIG_WATCHDOG_SYSFS=y
+13 -1
View File
@@ -35,8 +35,20 @@ define Device/yiming-uz801v3
FILESYSTEMS := squashfs
DEVICE_PACKAGES := configs-uz801 wpad-basic-wolfssl rmtfs uci-usb-gadget \
block-mount f2fs-tools prepare-rootfs-data \
msm-firmware-dumper
msm-firmware-dumper ledcontrol
endef
TARGET_DEVICES += yiming-uz801v3
define Device/generic-mf68e
$(Device/msm8916)
DEVICE_VENDOR := Generic
DEVICE_MODEL := MF68E
FILESYSTEMS := squashfs
CMDLINE := "earlycon console=ttyMSM0,115200 quiet loglevel=0 vt.global_cursor_default=0 vt.cur_default=0 root=/dev/mmcblk0p14 rootfstype=squashfs rootwait"
DEVICE_PACKAGES := configs-mf68e wpad-basic-wolfssl rmtfs uci-usb-gadget \
block-mount f2fs-tools prepare-rootfs-data \
msm-firmware-dumper kmod-fbtft-gc9107 router-display
endef
TARGET_DEVICES += generic-mf68e
endif
@@ -0,0 +1,21 @@
From: hkfuertes <hkfuertes@example.com>
Date: Sat, 11 Oct 2025 11:49:00 +0200
Subject: [PATCH] arm64: dts: qcom: Add MF68E to Makefile
Add msm8916-generic-mf68e.dtb to Makefile.
Signed-off-by: hkfuertes <hkfuertes@example.com>
---
arch/arm64/boot/dts/qcom/Makefile | 1 +
1 file changed, 1 insertion(+)
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -23,6 +23,7 @@ dtb-$(CONFIG_ARCH_QCOM) += msm8916-samsu
dtb-$(CONFIG_ARCH_QCOM) += msm8916-samsung-gt58.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8916-samsung-j3ltetw.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8916-samsung-j5.dtb
+dtb-$(CONFIG_ARCH_QCOM) += msm8916-generic-mf68e.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8916-samsung-j5x.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8916-samsung-rossa.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8916-samsung-serranove.dtb
@@ -0,0 +1,168 @@
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8916-generic-mf68e.dts
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/dts-v1/;
+
+#include "msm8916-ufi.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/qcom,pmic-mpp.h>
+#include <dt-bindings/pwm/pwm.h>
+
+/ {
+ model = "MF68E 4G LTE Mobile WiFi Router";
+ compatible = "generic,mf68e", "qcom,msm8916";
+
+ bat: battery {
+ compatible = "simple-battery";
+ voltage-min-design-microvolt = <3400000>;
+ voltage-max-design-microvolt = <4350000>;
+ energy-full-design-microwatt-hours = <11100000>;
+ charge-full-design-microamp-hours = <3000000>;
+
+ ocv-capacity-celsius = <25>;
+ ocv-capacity-table-0 = <4330000 100>, <4265000 95>,
+ <4208000 90>, <4154000 85>, <4102000 80>,
+ <4063000 75>, <4006000 70>, <3972000 65>,
+ <3931000 60>, <3880000 55>, <3841000 50>,
+ <3817000 45>, <3798000 40>, <3783000 35>,
+ <3767000 30>, <3747000 25>, <3729000 20>,
+ <3700000 16>, <3687000 13>, <3683000 11>,
+ <3681000 10>, <3680000 9>, <3678000 8>,
+ <3674000 7>, <3666000 6>, <3641000 5>,
+ <3597000 4>, <3537000 3>, <3457000 2>,
+ <3336000 1>, <3000000 0>;
+ };
+
+ usb_id: usb-id {
+ compatible = "linux,extcon-usb-gpio";
+ id-gpios = <&tlmm 110 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb_id_default>;
+ };
+
+ backlight: backlight {
+ compatible = "pwm-backlight";
+ pwms = <&pm8916_pwm 0 100000>;
+ brightness-levels = <255 128 64 32 16 8 4 0>;
+ num-interpolated-steps = <255>;
+ default-brightness-level = <6>;
+ status = "okay";
+ };
+};
+
+/* GC9107 Panel on SPI5 (0x78b9000) */
+&blsp_spi5 {
+ status = "okay";
+
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&spi5_default>;
+ pinctrl-1 = <&spi5_sleep>;
+
+ panel@0 {
+ compatible = "galaxycore,gc9107";
+ reg = <0>;
+ spi-max-frequency = <16000000>;
+
+ reset-gpios = <&tlmm 11 GPIO_ACTIVE_LOW>;
+ dc-gpios = <&tlmm 30 GPIO_ACTIVE_HIGH>;
+ backlight = <&backlight>;
+
+ vdd-supply = <&pm8916_l17>;
+ vddio-supply = <&pm8916_l6>;
+
+ width-mm = <23>;
+ height-mm = <23>;
+
+ buswidth = <8>;
+ width = <128>;
+ height = <128>;
+ rotate = <0>;
+ bgr;
+ fps = <27>;
+ debug = <1>;
+ };
+};
+
+&pm8916_l6 {
+ regulator-always-on;
+};
+
+&pm8916_l13 {
+ regulator-boot-on;
+ regulator-allow-set-load;
+};
+
+&pm8916_rpm_regulators {
+ pm8916_l17: l17 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ regulator-always-on;
+ };
+};
+
+&pm8916_pwm {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm_out>;
+};
+
+&pm8916_mpps {
+ pwm_out: mpp4-state {
+ pins = "mpp4";
+ function = "digital";
+ output-low;
+ qcom,dtest = <1>;
+ power-source = <PM8916_MPP_VPH>;
+ };
+};
+
+&pm8916_bms {
+ status = "okay";
+ monitored-battery = <&bat>;
+ power-supplies = <&pm8916_charger>;
+};
+
+&pm8916_charger {
+ status = "okay";
+ monitored-battery = <&bat>;
+ qcom,fast-charge-safe-current = <900000>;
+ qcom,fast-charge-safe-voltage = <4350000>;
+};
+
+&usb {
+ status = "okay";
+ extcon = <&usb_id>, <&usb_id>;
+};
+
+&usb_hs_phy {
+ extcon = <&usb_id>;
+};
+
+&sdhc_1 {
+ status = "okay";
+};
+
+&tlmm {
+ spi5_default: spi5-default-state {
+ pins = "gpio16", "gpio17", "gpio19";
+ function = "blsp_spi5";
+ drive-strength = <12>;
+ bias-disable;
+ };
+
+ spi5_sleep: spi5-sleep-state {
+ pins = "gpio16", "gpio17", "gpio19";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ usb_id_default: usb-id-default-state {
+ pins = "gpio110";
+ function = "gpio";
+ drive-strength = <8>;
+ bias-pull-up;
+ };
+};
@@ -0,0 +1,218 @@
--- /dev/null
+++ b/drivers/staging/fbtft/fb_gc9107.c
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * FB driver for the GC9107 LCD Controller
+ *
+ * Copyright (C) 2025
+ * Based on:
+ * - Espressif ESP-IDF GC9107 driver (esp_lcd_gc9107.c)
+ * - Craig Bishop init sequence
+ * - Android MSM8916 MF68E device
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fb_gc9107"
+#define WIDTH 128
+#define HEIGHT 128
+#define BPP 16
+
+/* GC9107 Commands */
+#define GC9107_SWRESET 0x01
+#define GC9107_SLPOUT 0x11
+#define GC9107_INVON 0x21
+#define GC9107_INVOFF 0x20
+#define GC9107_DISPOFF 0x28
+#define GC9107_DISPON 0x29
+#define GC9107_CASET 0x2A
+#define GC9107_RASET 0x2B
+#define GC9107_RAMWR 0x2C
+#define GC9107_MADCTL 0x36
+#define GC9107_COLMOD 0x3A
+
+/*
+ * Init sequence from Espressif ESP-IDF driver
+ * Includes proper gamma, power control, and timing
+ */
+static int init_display(struct fbtft_par *par)
+{
+ par->fbtftops.reset(par);
+ mdelay(120);
+
+ /* Frame Rate Control */
+ write_reg(par, 0xB0, 0xC0);
+
+ /* Porch Control */
+ write_reg(par, 0xB2, 0x2F);
+ write_reg(par, 0xB3, 0x03);
+
+ /* Display Function Control */
+ write_reg(par, 0xB6, 0x19);
+ write_reg(par, 0xB7, 0x01);
+
+ /* Power Control Settings */
+ write_reg(par, 0xAC, 0xCB);
+ write_reg(par, 0xAB, 0x0E);
+ write_reg(par, 0xB4, 0x04);
+
+ /* Internal Register */
+ write_reg(par, 0xA8, 0x19);
+ write_reg(par, 0xB8, 0x08);
+
+ /* Tesla Control */
+ write_reg(par, 0xE8, 0x24);
+ write_reg(par, 0xE9, 0x48);
+ write_reg(par, 0xEA, 0x22);
+
+ /* Interface Control */
+ write_reg(par, 0xC6, 0x30);
+ write_reg(par, 0xC7, 0x18);
+
+ /* Positive Gamma Control */
+ write_reg(par, 0xF0,
+ 0x1F, 0x28, 0x04, 0x3E, 0x2A, 0x2E, 0x20,
+ 0x00, 0x0C, 0x06, 0x00, 0x1C, 0x1F, 0x0F);
+
+ /* Negative Gamma Control */
+ write_reg(par, 0xF1,
+ 0x00, 0x2D, 0x2F, 0x3C, 0x6F, 0x1C, 0x0B,
+ 0x00, 0x00, 0x00, 0x07, 0x0D, 0x11, 0x0F);
+
+ /* Tearing Effect Line ON */
+ write_reg(par, 0x35, 0x00);
+
+ /* Pixel Format: RGB565 (16 bits/pixel) */
+ write_reg(par, GC9107_COLMOD, 0x55);
+
+ /* Display Inversion OFF - looks bad with INVON */
+ write_reg(par, GC9107_INVOFF);
+
+ /* Sleep Out */
+ write_reg(par, GC9107_SLPOUT);
+ mdelay(120);
+
+ /* Display ON */
+ write_reg(par, GC9107_DISPON);
+ mdelay(20);
+
+ return 0;
+}
+
+/*
+ * Set address window with proper offsets for GC9107
+ * GC9107 GRAM is 132x130, but display is 128x128
+ * Requires COL_OFFSET=2, ROW_OFFSET=1
+ */
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ /* GC9107 specific offsets */
+ const int col_offset = 2;
+ const int row_offset = 1;
+
+ /* Column Address Set */
+ write_reg(par, GC9107_CASET,
+ (xs + col_offset) >> 8,
+ (xs + col_offset) & 0xFF,
+ (xe + col_offset) >> 8,
+ (xe + col_offset) & 0xFF);
+
+ /* Row Address Set */
+ write_reg(par, GC9107_RASET,
+ (ys + row_offset) >> 8,
+ (ys + row_offset) & 0xFF,
+ (ye + row_offset) >> 8,
+ (ye + row_offset) & 0xFF);
+
+ /* Memory Write */
+ write_reg(par, GC9107_RAMWR);
+}
+
+/*
+ * Memory Data Access Control (MADCTL)
+ * Controls rotation and BGR mode
+ */
+static int set_var(struct fbtft_par *par)
+{
+ u8 madctl = 0;
+
+ /* Rotation */
+ switch (par->info->var.rotate) {
+ case 0:
+ madctl = 0x00;
+ break;
+ case 90:
+ madctl = 0x60; /* MV | MX */
+ break;
+ case 180:
+ madctl = 0xC0; /* MY | MX */
+ break;
+ case 270:
+ madctl = 0xA0; /* MV | MY */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* BGR mode from DTS */
+ if (par->bgr)
+ madctl |= 0x08;
+
+ write_reg(par, GC9107_MADCTL, madctl);
+
+ return 0;
+}
+
+static struct fbtft_display display = {
+ .regwidth = 8,
+ .width = WIDTH,
+ .height = HEIGHT,
+ .bpp = BPP,
+ .fps = 30,
+ .fbtftops = {
+ .init_display = init_display,
+ .set_addr_win = set_addr_win,
+ .set_var = set_var,
+ },
+};
+
+FBTFT_REGISTER_DRIVER(DRVNAME, "galaxycore,gc9107", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:gc9107");
+MODULE_ALIAS("platform:gc9107");
+
+MODULE_DESCRIPTION("FB driver for GC9107 LCD Controller");
+MODULE_AUTHOR("Based on Espressif ESP-IDF driver");
+MODULE_LICENSE("GPL");
--- a/drivers/staging/fbtft/Kconfig
+++ b/drivers/staging/fbtft/Kconfig
@@ -39,6 +39,12 @@ config FB_TFT_AGM1264K_FL
help
Generic Framebuffer support for AGM1264K-FL LCD display
+config FB_TFT_GC9107
+ tristate "FB driver for the GC9107 LCD Controller"
+ depends on FB_TFT
+ help
+ Framebuffer support for GalaxyCore GC9107 128x128 LCD
+
config FB_TFT_BD663474
tristate "FB driver for the BD663474 LCD Controller"
depends on FB_TFT
--- a/drivers/staging/fbtft/Makefile
+++ b/drivers/staging/fbtft/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_FB_TFT) += fbtft.o
fbtft-y += fbtft-core.o fbtft-sysfs.o fbtft-bus.o fbtft-io.o
obj-$(CONFIG_FB_TFT_AGM1264K_FL) += fb_agm1264k-fl.o
+obj-$(CONFIG_FB_TFT_GC9107) += fb_gc9107.o
obj-$(CONFIG_FB_TFT_BD663474) += fb_bd663474.o
obj-$(CONFIG_FB_TFT_HX8340BN) += fb_hx8340bn.o
+55
View File
@@ -0,0 +1,55 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=configs-mf68e
PKG_VERSION:=1.0
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
include $(INCLUDE_DIR)/package.mk
define Package/$(PKG_NAME)
SECTION:=Utilities
CATEGORY:=Utilities
TITLE:=Default Settings For mf68e
DEPENDS:=+PACKAGE_luci:luci-proto-modemmanager
endef
# Optional description
define Package/$(PKG_NAME)/description
Tweaks and defaults for mf68e, including cleanup of problematic APK feeds and LuCI battery widget.
endef
define Build/Configure
endef
define Build/Compile
endef
# Install configuration files and payload you already had
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_BIN) ./files/uci_defaults $(1)/etc/uci-defaults/99-default-config
$(INSTALL_DIR) $(1)/root/
$(INSTALL_BIN) ./files/luci-app-tailscale*.apk $(1)/root/
# Battery widget for LuCI
$(INSTALL_DIR) $(1)/usr/lib/lua/luci/view/admin_status/index
$(INSTALL_DATA) ./files/battery.htm $(1)/usr/lib/lua/luci/view/admin_status/index/20_battery.htm
endef
define Package/$(PKG_NAME)/postinst
#!/bin/sh
set -e
FILE="/etc/apk/repositories.d/distfeeds.list"
ROOT="$${IPKG_INSTROOT:-/}"
TARGET_FILE="$$ROOT$$FILE"
if [ -f "$$TARGET_FILE" ]; then
sed -i '\|/targets/msm89xx/msm8916/packages|d' "$$TARGET_FILE" || true
fi
exit 0
endef
$(eval $(call BuildPackage,$(PKG_NAME)))
+69
View File
@@ -0,0 +1,69 @@
<%-
local sys = require "luci.sys"
local utl = require "luci.util"
local bms_path = "/sys/class/power_supply/pm8916-bms-vm"
local charger_path = "/sys/class/power_supply/pm8916-lbc-chgr"
local function read_file(path)
local f = io.open(path, "r")
if f then
local val = f:read("*all")
f:close()
return utl.trim(val)
end
return nil
end
local voltage = read_file(bms_path .. "/voltage_now")
local status = read_file(bms_path .. "/status")
local health = read_file(bms_path .. "/health")
local vmax = read_file(bms_path .. "/voltage_max_design")
local vmin = read_file(bms_path .. "/voltage_min_design")
local online = read_file(charger_path .. "/online")
-- Calcular porcentaje aproximado basado en voltaje
local percentage = "N/A"
if voltage and vmax and vmin then
local v = tonumber(voltage)
local vmax_n = tonumber(vmax)
local vmin_n = tonumber(vmin)
if v and vmax_n and vmin_n then
local pct = ((v - vmin_n) / (vmax_n - vmin_n)) * 100
pct = math.max(0, math.min(100, pct))
percentage = string.format("%.0f%%", pct)
end
end
-%>
<% if voltage then %>
<div class="cbi-section">
<legend><%:Battery Status%></legend>
<div class="table">
<div class="tr cbi-section-table-titles">
<div class="th"><%:Property%></div>
<div class="th"><%:Value%></div>
</div>
<div class="tr">
<div class="td left"><%:Estimated Capacity%></div>
<div class="td left"><strong><%=percentage%></strong></div>
</div>
<div class="tr">
<div class="td left"><%:Voltage%></div>
<div class="td left"><%=string.format("%.2f V", tonumber(voltage)/1000000)%></div>
</div>
<div class="tr">
<div class="td left"><%:Status%></div>
<div class="td left"><%=status%></div>
</div>
<div class="tr">
<div class="td left"><%:Health%></div>
<div class="td left"><%=health%></div>
</div>
<div class="tr">
<div class="td left"><%:Charger%></div>
<div class="td left"><%=online == "1" and "Connected" or "Disconnected"%></div>
</div>
</div>
</div>
<% end %>
+47
View File
@@ -0,0 +1,47 @@
#!/bin/sh
# Enabling WiFi
uci set wireless.@wifi-device[0].disabled='0'
uci set wireless.@wifi-iface[0].disabled='0'
# Create modem interface
uci set network.modem=interface
uci set network.modem.proto='modemmanager'
uci set network.modem.device='qcom-soc'
uci set network.modem.auth='none'
uci set network.modem.apn='internet'
uci set network.modem.allowedmode='4g|3g'
uci set network.modem.preferredmode='4g'
uci set network.modem.ifname='wwan0'
uci del_list firewall.@zone[1].network='modem'
uci add_list firewall.@zone[1].network='modem'
# We don't have eth0
uci -q del_list "network.@device[0].ports=eth0" 2>/dev/null || true
sed -i 's/"device": "eth0"/"device": "br-lan"/g' /etc/board.json
# Commit all changes
uci commit
# Apply network and wireless configuration
wifi reload
/etc/init.d/network restart
cat > /etc/rc.button/power << 'EOF'
#!/bin/sh
SECONDS=3
[ "${ACTION}" = "pressed" ] && exit ${SECONDS}
[ "${ACTION}" = "timeout" ] && {
logger "Power held for ${SECONDS}: Shutting down system"
poweroff
exit 0
}
exit 0
EOF
chmod +x /etc/rc.button/power
exit 0
+4 -5
View File
@@ -1,4 +1,3 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=configs-uz801
@@ -11,13 +10,13 @@ include $(INCLUDE_DIR)/package.mk
define Package/$(PKG_NAME)
SECTION:=Utilities
CATEGORY:=Utilities
TITLE:=Defaults Setting For uz801v3
TITLE:=Default Settings For uz801v3
DEPENDS:=+PACKAGE_luci:luci-proto-modemmanager
endef
# (Opcional) Descripción
# Optional description
define Package/$(PKG_NAME)/description
Tweaks y defaults para uz801v3, incluyendo limpieza de feeds APK problemáticos.
Tweaks and defaults for uz801v3, including cleanup of problematic APK feeds.
endef
define Build/Configure
@@ -26,7 +25,7 @@ endef
define Build/Compile
endef
# Instala ficheros de configuración y payload que ya tenías
# Install configuration files and payload you already had
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_BIN) ./files/uci_defaults $(1)/etc/uci-defaults/99-default-config
+56
View File
@@ -0,0 +1,56 @@
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=fbtft-gc9107
PKG_RELEASE:=1
include $(INCLUDE_DIR)/package.mk
define KernelPackage/fbtft-gc9107
SUBMENU:=Video Support
TITLE:=GC9107 Framebuffer Driver
DEPENDS:=@TARGET_msm89xx +kmod-backlight
KCONFIG:= \
CONFIG_FB=y \
CONFIG_FB_BACKLIGHT=y \
CONFIG_FB_DEFERRED_IO=y \
CONFIG_FB_SYS_FILLRECT=y \
CONFIG_FB_SYS_COPYAREA=y \
CONFIG_FB_SYS_IMAGEBLIT=y \
CONFIG_FB_SYS_FOPS=y \
CONFIG_FB_DMAMEM_HELPERS=y \
CONFIG_BACKLIGHT_CLASS_DEVICE=y \
CONFIG_BACKLIGHT_PWM=y \
CONFIG_FONTS=y \
CONFIG_FONT_8x16=y \
CONFIG_FRAMEBUFFER_CONSOLE=y \
CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=n \
CONFIG_VT_HW_CONSOLE_BINDING=y \
CONFIG_VT_CONSOLE_SLEEP=y \
CONFIG_STAGING=y \
CONFIG_FB_TFT=y \
CONFIG_FB_TFT_GC9107=y
FILES:= \
$(LINUX_DIR)/drivers/staging/fbtft/fbtft.ko \
$(LINUX_DIR)/drivers/staging/fbtft/fb_gc9107.ko
AUTOLOAD:=$(call AutoProbe,fbtft fb_gc9107)
endef
define KernelPackage/fbtft-gc9107/description
GC9107 framebuffer driver for MF68E device with boot logo support.
endef
define Build/Compile
endef
define KernelPackage/fbtft-gc9107/install
$(INSTALL_DIR) $(1)/etc
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_DIR) $(1)/lib/preinit
$(INSTALL_DATA) ./files/boot_logo.fb $(1)/etc/boot_logo.fb
$(INSTALL_DATA) ./files/poweroff_logo.fb $(1)/etc/poweroff_logo.fb
$(INSTALL_BIN) ./files/05_display_logo $(1)/lib/preinit/05_display_logo
$(INSTALL_BIN) ./files/01_poweroff_logo $(1)/etc/init.d/01_poweroff_logo
endef
$(eval $(call KernelPackage,fbtft-gc9107))
@@ -0,0 +1,13 @@
#!/bin/sh /etc/rc.common
START=99
STOP=01
start() {
return 0
}
stop() {
cat /etc/poweroff_logo.fb > /dev/fb0 2>/dev/null
sleep 2
}
@@ -0,0 +1,30 @@
#!/bin/sh
show_logo() {
(
local BACKLIGHT="/sys/class/backlight/backlight"
local i=0
while [ ! -c /dev/fb0 ] && [ $i -lt 100 ]; do
usleep 100000 # 100ms = 0.1s
i=$((i + 1))
done
if [ -c /dev/fb0 ] && [ -f /etc/boot_logo.fb ]; then
cat /etc/boot_logo.fb > /dev/fb0 2>/dev/null
fi
i=0
while [ ! -d "$BACKLIGHT" ] && [ $i -lt 50 ]; do
usleep 100000 # 100ms = 0.1s
i=$((i + 1))
done
if [ -d "$BACKLIGHT" ]; then
echo 0 > $BACKLIGHT/bl_power 2>/dev/null
echo 1 > $BACKLIGHT/brightness 2>/dev/null
fi
) &
}
boot_hook_add preinit_main show_logo
Binary file not shown.
Binary file not shown.
+5
View File
@@ -0,0 +1,5 @@
## Create boot image for framebuffer
We are converting the image using `ffmpeg`. Ensure you have it installed.
```
ffmpeg -i <image> -vf "scale=128:128" -pix_fmt rgb565le -f rawvideo <output>.fb
```
+67
View File
@@ -0,0 +1,67 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=router-display
PKG_VERSION:=1.0
PKG_RELEASE:=1
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
PKG_QRGEN_NAME:=QR-Code-generator
PKG_QRGEN_VERSION:=v1.8.0
PKG_QRGEN_SOURCE:=$(PKG_QRGEN_VERSION).tar.gz
PKG_QRGEN_URL:=https://github.com/nayuki/QR-Code-generator/archive/refs/tags
PKG_QRGEN_HASH:=skip
include $(INCLUDE_DIR)/package.mk
define Package/router-display
SECTION:=utils
CATEGORY:=Utilities
TITLE:=Framebuffer router status display
DEPENDS:=+libfreetype +kmod-button-hotplug +dejavu-fonts-ttf-DejaVuSans-Bold +dejavu-fonts-ttf-DejaVuSans
endef
define Package/router-display/description
Display router status on RGB565 framebuffer
endef
define Download/qrcodegen
URL:=$(PKG_QRGEN_URL)
FILE:=qrcodegen-$(PKG_QRGEN_VERSION).tar.gz
URL_FILE:=$(PKG_QRGEN_VERSION).tar.gz
HASH:=$(PKG_QRGEN_HASH)
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/main.c $(PKG_BUILD_DIR)/
$(eval $(call Download,qrcodegen))
tar -xzf $(DL_DIR)/qrcodegen-$(PKG_QRGEN_VERSION).tar.gz -C $(PKG_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/$(PKG_QRGEN_NAME)-*/c/qrcodegen.c $(PKG_BUILD_DIR)/
$(CP) $(PKG_BUILD_DIR)/$(PKG_QRGEN_NAME)-*/c/qrcodegen.h $(PKG_BUILD_DIR)/
endef
define Build/Compile
$(TARGET_CC) $(TARGET_CFLAGS) -O3 -ffast-math \
$(TARGET_CPPFLAGS) \
-I$(STAGING_DIR)/usr/include/freetype2 \
$(TARGET_LDFLAGS) \
-o $(PKG_BUILD_DIR)/router-display \
$(PKG_BUILD_DIR)/main.c \
$(PKG_BUILD_DIR)/qrcodegen.c \
-lfreetype -lm
endef
define Package/router-display/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/router-display $(1)/usr/bin/
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) ./files/update-display.sh $(1)/usr/sbin/update-display
$(INSTALL_DIR) $(1)/etc/hotplug.d/button
$(INSTALL_BIN) ./files/hotplugs/20_power_dimm $(1)/etc/hotplug.d/button/20_power_dimm
$(INSTALL_BIN) ./files/hotplugs/30_power_update $(1)/etc/hotplug.d/button/30_power_update
endef
$(eval $(call BuildPackage,router-display))
@@ -0,0 +1,91 @@
#!/bin/sh
# /etc/hotplug.d/button/20_power_dimm
# Only process power button events
[ "$BUTTON" = "power" ] || exit 0
# Configuration variables
TIMEOUT_DIM=5
TIMEOUT_OFF=3
BACKLIGHT_PATH="/sys/class/backlight/backlight"
BRIGHTNESS_DIM_DIVISOR=8
BRIGHTNESS_OFF=1
# Calculated variables
MAX_BRIGHTNESS=$(cat $BACKLIGHT_PATH/max_brightness 2>/dev/null || echo 1785)
BRIGHTNESS_FULL=$MAX_BRIGHTNESS
BRIGHTNESS_DIM=$((MAX_BRIGHTNESS / BRIGHTNESS_DIM_DIVISOR))
# PID file for timer management
TIMER_PID_FILE="/tmp/screen_timer.pid"
maybe_set_lockscreen(){
# Check if system is shutting down
if pgrep poweroff >/dev/null 2>&1 || \
pgrep halt >/dev/null 2>&1 || \
pgrep reboot >/dev/null 2>&1; then
logger -t display "System shutting down - skipping lockscreen"
return 0
fi
# Show lockscreen if brightness is OFF
[ -n "$1" ] && [ "$1" = "$BRIGHTNESS_OFF" ] && [ -f /etc/boot_logo.fb ] && \
cat /etc/boot_logo.fb > /dev/fb0 2>/dev/null
}
# Set brightness level
set_brightness() {
echo "$1" > "$BACKLIGHT_PATH/brightness"
# Check if we should show lockscreen
maybe_set_lockscreen "$1"
}
# Function to start a timer
# Parameters: $1=timeout (seconds), $2=brightness level, $3=log message
start_timer() {
local timeout=$1
local brightness=$2
local log_msg=$3
(
sleep "$timeout"
logger -t display "$log_msg"
set_brightness "$brightness"
) >/dev/null 2>&1 </dev/null &
echo $!
}
# Cancel all active timers
cancel_timers() {
if [ -f "$TIMER_PID_FILE" ]; then
while read pid; do
kill "$pid" 2>/dev/null
done < "$TIMER_PID_FILE"
rm -f "$TIMER_PID_FILE"
fi
}
# Only act on button release
[ "${ACTION}" = "released" ] && {
logger -t display "Button event detected"
# Cancel previous timers if any
cancel_timers
# Set full brightness immediately
logger -t display "Backlight: FULL"
set_brightness $BRIGHTNESS_FULL
# Start timer 1: DIM after TIMEOUT_DIM seconds
pid1=$(start_timer $TIMEOUT_DIM $BRIGHTNESS_DIM "Backlight: DIM")
echo "$pid1" >> "$TIMER_PID_FILE"
# Start timer 2: OFF after (TIMEOUT_DIM + TIMEOUT_OFF) seconds
TOTAL_TIMEOUT=$((TIMEOUT_DIM + TIMEOUT_OFF))
pid2=$(start_timer $TOTAL_TIMEOUT $BRIGHTNESS_OFF "Backlight: OFF")
echo "$pid2" >> "$TIMER_PID_FILE"
}
exit 0
@@ -0,0 +1,20 @@
#!/bin/sh
# /etc/hotplug.d/button/30_power_update
# Only process power button events
[ "$BUTTON" = "power" ] || exit 0
# Execute update-display on button release
[ "${ACTION}" = "released" ] && {
# Check if system is shutting down
if pgrep poweroff >/dev/null 2>&1 || \
pgrep halt >/dev/null 2>&1 || \
pgrep reboot >/dev/null 2>&1; then
logger -t display "System shutting down - skipping update-display"
exit 0
fi
/usr/sbin/update-display
}
exit 0
@@ -0,0 +1,85 @@
#!/bin/sh
# /usr/sbin/update-display
# Optimized display update script - caches operator name (requires reboot to change SIM)
# === BATTERY ===
BMS_PATH="/sys/class/power_supply/pm8916-bms-vm"
VOLTAGE=$(cat "$BMS_PATH/voltage_now" 2>/dev/null)
VMAX=$(cat "$BMS_PATH/voltage_max_design" 2>/dev/null)
VMIN=$(cat "$BMS_PATH/voltage_min_design" 2>/dev/null)
if [ -n "$VOLTAGE" ] && [ -n "$VMAX" ] && [ -n "$VMIN" ]; then
BATTERY=$(awk "BEGIN {pct = (($VOLTAGE - $VMIN) / ($VMAX - $VMIN)) * 100; if(pct < 0) pct=0; if(pct > 100) pct=100; printf \"%.0f\", pct}")
else
BATTERY=100
fi
# === WiFi AP ===
SHOW_QR=0
if ip link show phy0-ap0 2>/dev/null | grep -q "state UP"; then
SHOW_QR=1
fi
# === MODEM (OPTIMIZED - single mmcli call + operator cache) ===
OPERATOR_CACHE="/tmp/modem_operator.cache"
MODEM_IDX=$(mmcli -L 2>/dev/null | grep -oE 'Modem/[0-9]+' | head -1 | cut -d'/' -f2)
if [ -n "$MODEM_IDX" ]; then
# Single mmcli call - cache all modem data
MODEM_DATA=$(mmcli -m "$MODEM_IDX" -K 2>/dev/null)
# Try to get operator from cache first (SIM doesn't change without reboot)
if [ -f "$OPERATOR_CACHE" ]; then
OPERATOR=$(cat "$OPERATOR_CACHE")
else
# Cache miss - fetch operator from SIM
SIM_IDX=$(echo "$MODEM_DATA" | grep 'modem.generic.sim' | awk -F': ' '{print $2}' | grep -oE '[0-9]+$')
if [ -n "$SIM_IDX" ]; then
OPERATOR=$(mmcli -i "$SIM_IDX" -K 2>/dev/null | grep 'sim.properties.operator-name' | awk -F': ' '{print $2}')
fi
# Fallback: operator from network (use cached modem data)
if [ -z "$OPERATOR" ]; then
OPERATOR=$(echo "$MODEM_DATA" | grep 'modem.3gpp.operator-name' | awk -F': ' '{print $2}')
fi
# Cache operator for future calls
if [ -n "$OPERATOR" ]; then
echo "$OPERATOR" > "$OPERATOR_CACHE"
fi
fi
# Access technology (use cached modem data)
ACCESS_TECH=$(echo "$MODEM_DATA" | grep 'modem.generic.access-technologies' | awk -F': ' '{print $2}')
# Determine network type only if connected
if [ -n "$ACCESS_TECH" ] && [ "$ACCESS_TECH" != "unknown" ]; then
case "$ACCESS_TECH" in
*lte*) NETWORK="4G" ;;
*umts*|*hspa*|*hsupa*|*hsdpa*) NETWORK="3G" ;;
*edge*|*gprs*|*gsm*) NETWORK="2G" ;;
*) NETWORK="$ACCESS_TECH" ;;
esac
else
# No connection: show operator but no network type
NETWORK=""
fi
else
# No modem
OPERATOR=""
NETWORK=""
fi
# === WiFi Info ===
SSID=$(uci get wireless.@wifi-iface[0].ssid 2>/dev/null || echo "WiFi")
PASSWORD=$(uci get wireless.@wifi-iface[0].key 2>/dev/null || echo "")
HOSTNAME=$(uci get system.@system[0].hostname 2>/dev/null || echo "Router")
# === Update Display ===
if [ "$SHOW_QR" -eq 1 ]; then
/usr/bin/router-display -q -b "$BATTERY" -n "$OPERATOR" -t "$NETWORK" -s "$SSID" -p "$PASSWORD" -h "$HOSTNAME" > /dev/fb0
else
/usr/bin/router-display -b "$BATTERY" -n "$OPERATOR" -t "$NETWORK" -s "$SSID" -p "$PASSWORD" -h "$HOSTNAME" > /dev/fb0
fi
+292
View File
@@ -0,0 +1,292 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <getopt.h>
#include <unistd.h>
#include <ctype.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include "qrcodegen.h"
#define WIDTH 128
#define HEIGHT 128
#define RGB565(r,g,b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3))
#define COLOR_WHITE RGB565(255, 255, 255)
#define COLOR_BLACK RGB565(0, 0, 0)
#define QR_SIZE 108
#define QR_TOP_MARGIN 6
#define TEXT_HEIGHT 13
#define MIN_MODULE_SIZE 3 // Minimum pixels per QR module for readability
typedef struct {
uint16_t data[WIDTH * HEIGHT];
} Framebuffer;
typedef struct {
int battery;
char operator[32];
char network_type[8];
char ssid[64];
char password[64];
char hostname[32];
int show_qr;
int uppercase;
} DisplayConfig;
void fb_init(Framebuffer *fb) {
memset(fb->data, 0, sizeof(fb->data));
}
void fb_put_pixel(Framebuffer *fb, int x, int y, uint16_t color) {
if (x >= 0 && x < WIDTH && y >= 0 && y < HEIGHT) {
fb->data[y * WIDTH + x] = color;
}
}
void fb_blend_pixel(Framebuffer *fb, int x, int y, unsigned char gray) {
if (x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT) return;
if (gray == 0) return;
uint16_t bg_color = fb->data[y * WIDTH + x];
uint8_t bg_r = (bg_color >> 11) << 3;
uint8_t bg_g = ((bg_color >> 5) & 0x3F) << 2;
uint8_t bg_b = (bg_color & 0x1F) << 3;
float alpha = gray / 255.0f;
uint8_t r = (uint8_t)(255 * alpha + bg_r * (1.0f - alpha));
uint8_t g = (uint8_t)(255 * alpha + bg_g * (1.0f - alpha));
uint8_t b = (uint8_t)(255 * alpha + bg_b * (1.0f - alpha));
fb->data[y * WIDTH + x] = RGB565(r, g, b);
}
void fb_draw_rect(Framebuffer *fb, int x, int y, int w, int h, uint16_t color) {
for (int j = 0; j < h; j++) {
for (int i = 0; i < w; i++) {
fb_put_pixel(fb, x + i, y + j, color);
}
}
}
void fb_draw_text(Framebuffer *fb, FT_Face face, const char *text, int x, int y, int size) {
int pen_x = x;
for (const char *p = text; *p; p++) {
FT_Set_Pixel_Sizes(face, 0, size);
if (FT_Load_Char(face, *p, FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL)) {
continue;
}
FT_GlyphSlot slot = face->glyph;
FT_Bitmap bitmap = slot->bitmap;
for (unsigned int row = 0; row < bitmap.rows; row++) {
for (unsigned int col = 0; col < bitmap.width; col++) {
int px = pen_x + slot->bitmap_left + col;
int py = y - slot->bitmap_top + row;
unsigned char gray = bitmap.buffer[row * bitmap.pitch + col];
if (gray > 0) {
fb_blend_pixel(fb, px, py, gray);
}
}
}
pen_x += slot->advance.x >> 6;
}
}
int fb_get_text_width(FT_Face face, const char *text, int size) {
int width = 0;
FT_Set_Pixel_Sizes(face, 0, size);
for (const char *p = text; *p; p++) {
if (FT_Load_Char(face, *p, FT_LOAD_RENDER)) {
continue;
}
width += face->glyph->advance.x >> 6;
}
return width;
}
int fb_draw_qr(Framebuffer *fb, const char *text, int x, int y, int size) {
uint8_t qr_data[qrcodegen_BUFFER_LEN_MAX];
uint8_t temp_buffer[qrcodegen_BUFFER_LEN_MAX];
bool ok = qrcodegen_encodeText(text, temp_buffer, qr_data,
qrcodegen_Ecc_LOW,
qrcodegen_VERSION_MIN,
qrcodegen_VERSION_MAX,
qrcodegen_Mask_AUTO, true);
if (!ok) {
fprintf(stderr, "QR generation failed\n");
return 0;
}
int qr_modules = qrcodegen_getSize(qr_data);
int module_size = size / qr_modules;
// Check if QR modules are too small (minimum pixels per module)
if (module_size < MIN_MODULE_SIZE) {
fprintf(stderr, "QR too large for display area (needs %d modules, only fits %dpx modules)\n",
qr_modules, module_size);
return 0; // Don't draw, QR would be unreadable
}
// Calculate actual QR size and center horizontally, align top vertically
int actual_qr_size = qr_modules * module_size;
int offset_x = (size - actual_qr_size) / 2; // Center horizontally
int offset_y = 0; // Top aligned
for (int row = 0; row < qr_modules; row++) {
for (int col = 0; col < qr_modules; col++) {
if (qrcodegen_getModule(qr_data, col, row)) {
fb_draw_rect(fb,
x + offset_x + col * module_size,
y + offset_y + row * module_size,
module_size, module_size,
COLOR_WHITE);
}
}
}
return 1; // QR drawn successfully
}
void str_to_upper(char *str) {
for (char *p = str; *p; p++) {
*p = toupper((unsigned char)*p);
}
}
void generate_display(Framebuffer *fb, DisplayConfig *cfg, FT_Face face) {
fb_init(fb);
char operator_text[32], network_text[8], hostname_text[32];
strncpy(operator_text, cfg->operator, 31);
strncpy(network_text, cfg->network_type, 7);
strncpy(hostname_text, cfg->hostname, 31);
if (cfg->uppercase) {
str_to_upper(operator_text);
str_to_upper(network_text);
str_to_upper(hostname_text);
}
// Calculate QR position: centered horizontally, at top with margin
int qr_x = (WIDTH - QR_SIZE) / 2;
int qr_y = QR_TOP_MARGIN;
if (cfg->show_qr) {
char wifi_qr[256];
snprintf(wifi_qr, sizeof(wifi_qr),
"WIFI:T:WPA;S:%s;P:%s;;", cfg->ssid, cfg->password);
// Try to draw QR, if it doesn't fit (returns 0), screen stays black
fb_draw_qr(fb, wifi_qr, qr_x, qr_y, QR_SIZE);
}
// If no QR or QR too large: stay black (fb_init already cleared to black)
int fontsz = 12;
int line1_y = HEIGHT - fontsz - 3;
int line2_y = HEIGHT - 3;
fb_draw_text(fb, face, operator_text, 2, line1_y, fontsz);
int net_width = fb_get_text_width(face, network_text, fontsz);
fb_draw_text(fb, face, network_text, WIDTH - net_width - 2, line1_y, fontsz);
fb_draw_text(fb, face, hostname_text, 2, line2_y, fontsz);
char battery_text[8];
snprintf(battery_text, sizeof(battery_text), "%d%%", cfg->battery);
int battery_width = fb_get_text_width(face, battery_text, fontsz);
fb_draw_text(fb, face, battery_text, WIDTH - battery_width - 2, line2_y, fontsz);
}
void print_usage(const char *prog) {
fprintf(stderr, "Usage: %s [OPTIONS]\n", prog);
fprintf(stderr, " -b NUM Battery (0-100)\n");
fprintf(stderr, " -n NAME Operator name\n");
fprintf(stderr, " -t TYPE Network type (4G, LTE)\n");
fprintf(stderr, " -s SSID WiFi SSID\n");
fprintf(stderr, " -p PASS WiFi password\n");
fprintf(stderr, " -h HOST Hostname\n");
fprintf(stderr, " -q Show QR code (default: show logo)\n");
fprintf(stderr, " -c Convert text to UPPERCASE\n");
}
int main(int argc, char *argv[]) {
DisplayConfig cfg = {
.battery = 100,
.operator = "Unknown",
.network_type = "4G",
.ssid = "WiFi",
.password = "password",
.hostname = "Router",
.show_qr = 0,
.uppercase = 0
};
int opt;
while ((opt = getopt(argc, argv, "b:n:t:s:p:h:qc")) != -1) {
switch (opt) {
case 'b': cfg.battery = atoi(optarg); break;
case 'n': strncpy(cfg.operator, optarg, 31); break;
case 't': strncpy(cfg.network_type, optarg, 7); break;
case 's': strncpy(cfg.ssid, optarg, 63); break;
case 'p': strncpy(cfg.password, optarg, 63); break;
case 'h': strncpy(cfg.hostname, optarg, 31); break;
case 'q': cfg.show_qr = 1; break;
case 'c': cfg.uppercase = 1; break;
default:
print_usage(argv[0]);
return 1;
}
}
FT_Library ft;
if (FT_Init_FreeType(&ft)) {
fprintf(stderr, "FreeType init failed\n");
return 1;
}
FT_Face face;
const char *fonts[] = {
"/usr/share/fonts/ttf-dejavu/DejaVuSans.ttf",
"/usr/share/fonts/ttf-dejavu/DejaVuSans-Bold.ttf",
NULL
};
int found = 0;
for (int i = 0; fonts[i]; i++) {
if (FT_New_Face(ft, fonts[i], 0, &face) == 0) {
found = 1;
break;
}
}
if (!found) {
fprintf(stderr, "No font found\n");
FT_Done_FreeType(ft);
return 1;
}
Framebuffer fb;
generate_display(&fb, &cfg, face);
fwrite(fb.data, sizeof(uint16_t), WIDTH * HEIGHT, stdout);
FT_Done_Face(face);
FT_Done_FreeType(ft);
return 0;
}