diff --git a/config/boards/gateway-dk.conf b/config/boards/gateway-dk.conf new file mode 100644 index 000000000000..c12879510e11 --- /dev/null +++ b/config/boards/gateway-dk.conf @@ -0,0 +1,61 @@ +# NXP LS1046A quad core Cortex-A72 8GB RAM SoC eMMC GBE SFP+ +BOARD_NAME="Mono Gateway Development Kit" +BOARD_VENDOR="mono" +BOARDFAMILY="ls1046a" +BOARD_MAINTAINER="tomazzaman" +BOOTCONFIG="mono_gateway_dk_defconfig" +KERNEL_TARGET="current" +KERNEL_TEST_TARGET="current" +HAS_VIDEO_OUTPUT="no" +BOOT_FDT_FILE="freescale/mono-gateway-dk.dtb" +BOOTENV_FILE="gateway-dk.txt" + +# U-Boot, ATF, and RCW — Mono forks with custom DDR4 config and SERDES +declare -g BOOTSOURCE="https://github.com/we-are-mono/u-boot" +declare -g BOOTBRANCH="commit:9f13d11658f696d4d1b4f76fa88264c52bd2e7c2" +declare -g BOOTPATCHDIR="u-boot-ls1046a" +declare -g UBOOT_TARGET_MAP=";;u-boot.bin bl2_emmc.pbl fip.bin fsl_fman_ucode_ls1046_r1.0_108_4_9.bin u-boot-env.bin" + +declare -g ATFSOURCE="https://github.com/we-are-mono/atf" +declare -g ATFDIR="arm-trusted-firmware-ls1046a" +declare -g ATFBRANCH="commit:80a4fbc4d79b16549a2bad4e3532899ce7de4cef" +declare -g ATFPATCHDIR="atf-ls1046a" + +declare -g LS1046A_PLAT="gateway_dk" +declare -g RCW_SOURCE="https://github.com/we-are-mono/rcw" +declare -g RCW_BRANCH="commit:a37e83067fb9496dd0be6b4bc24e85361fd2e0a2" +declare -g RCW_BIN_PATH="NN_FFSSPSNP_1133_5A06/rcw_2100_emmcboot.bin" + +# ASK hardware offloading (disable with ENABLE_ASK=no for a basic networking image) +[[ "${ENABLE_ASK:-yes}" == "yes" ]] && enable_extension "gateway-dk-ask" + +# Board-specific kernel modules auto-load +function post_family_tweaks_bsp__gateway_dk_board() { + mkdir -p "${destination}/etc/modules-load.d" + printf '%s\n' sfp-led leds-lp5812 > "${destination}/etc/modules-load.d/gateway-dk-leds.conf" + + # Boot LED indicator (green off, white on = Linux booted) + install -Dm 755 "${SRC}/packages/bsp/gateway-dk/gateway-dk-leds.sh" \ + "${destination}/usr/local/bin/gateway-dk-leds.sh" + install -Dm 644 "${SRC}/packages/bsp/gateway-dk/gateway-dk-leds.service" \ + "${destination}/etc/systemd/system/gateway-dk-leds.service" + + # Fan control — EMC2305 driven by cluster_thermal CPU temperature + install -Dm 755 "${SRC}/packages/bsp/gateway-dk/generate-fancontrol-conf" \ + "${destination}/usr/local/bin/generate-fancontrol-conf" + install -Dm 644 "${SRC}/packages/bsp/gateway-dk/generate-fancontrol-conf.service" \ + "${destination}/etc/systemd/system/generate-fancontrol-conf.service" +} + +function post_family_tweaks__gateway_dk_services() { + # IP forwarding + echo "net.ipv4.ip_forward=1" > "${SDCARD}/etc/sysctl.d/99-ls1046a-forwarding.conf" + + # Fan control and sensor packages + display_alert "Installing fancontrol" "emc2305 + cluster_thermal" "info" + chroot_sdcard_apt_get_install fancontrol lm-sensors + + chroot_sdcard systemctl enable gateway-dk-leds.service + chroot_sdcard systemctl enable generate-fancontrol-conf.service + chroot_sdcard systemctl enable fancontrol.service +} diff --git a/config/bootenv/gateway-dk.txt b/config/bootenv/gateway-dk.txt new file mode 100644 index 000000000000..645c4247e6ed --- /dev/null +++ b/config/bootenv/gateway-dk.txt @@ -0,0 +1,26 @@ +# Base settings duplicated from ls1046a.txt (no include mechanism in bootenv) +baudrate=115200 +stderr=serial@21c0500 +stdin=serial@21c0500 +stdout=serial@21c0500 + +scriptaddr=0x80000000 +fdt_addr_r=0x88000000 +kernel_addr_r=0x82000000 +kernel_comp_addr_r=0x90000000 +kernel_comp_size=0x1600000 +ramdisk_addr_r=0x88080000 +load_addr=0xa0000000 +loadaddr=0xa0000000 + +# NOR flash partition layout (passed to kernel for /dev/mtd awareness even when booting from eMMC) +mtdparts=1550000.spi:1M(rcw-bl2),2M(uboot),1M(uboot-env),1M(fman-ucode),1M(recovery-dtb),4M(unallocated),-(kernel-initramfs) + +bootargs_console=console=ttyS0,115200 earlycon=uart8250,mmio,0x21c0500 mtdparts=${mtdparts} pstore.backend=mtdoops mtdoops.mtddev=backup +bootdelay=3 + +bootcmd=sysboot mmc 0:1 any ${scriptaddr} /boot/extlinux/extlinux.conf + +# Default Ethernet — fm1-mac5 is the first 1GbE SGMII port (SERDES lane H) +ethact=fm1-mac5 +ethprime=fm1-mac5 diff --git a/config/bootenv/ls1046a.txt b/config/bootenv/ls1046a.txt new file mode 100644 index 000000000000..8b145ebee593 --- /dev/null +++ b/config/bootenv/ls1046a.txt @@ -0,0 +1,18 @@ +baudrate=115200 +stderr=serial@21c0500 +stdin=serial@21c0500 +stdout=serial@21c0500 + +scriptaddr=0x80000000 +fdt_addr_r=0x88000000 +kernel_addr_r=0x82000000 +kernel_comp_addr_r=0x90000000 +kernel_comp_size=0x1600000 +ramdisk_addr_r=0x88080000 +load_addr=0xa0000000 +loadaddr=0xa0000000 + +bootargs_console=console=ttyS0,115200 earlycon=uart8250,mmio,0x21c0500 +bootdelay=3 + +bootcmd=sysboot mmc 0:1 any ${scriptaddr} /boot/extlinux/extlinux.conf diff --git a/config/kernel/linux-ls1046a-ask-current.config b/config/kernel/linux-ls1046a-ask-current.config new file mode 120000 index 000000000000..0203f35abbf3 --- /dev/null +++ b/config/kernel/linux-ls1046a-ask-current.config @@ -0,0 +1 @@ +linux-ls1046a-current.config \ No newline at end of file diff --git a/config/kernel/linux-ls1046a-current.config b/config/kernel/linux-ls1046a-current.config new file mode 100644 index 000000000000..d6394bfec84b --- /dev/null +++ b/config/kernel/linux-ls1046a-current.config @@ -0,0 +1,548 @@ +# Armbian defconfig generated with 6.12 +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ_IDLE=y +# CONFIG_CONTEXT_TRACKING_USER_FORCE is not set +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BPF_SYSCALL=y +CONFIG_BPF_JIT=y +CONFIG_BPF_JIT_ALWAYS_ON=y +CONFIG_PREEMPT_VOLUNTARY=y +CONFIG_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUP_FAVOR_DYNMODS=y +CONFIG_MEMCG=y +CONFIG_BLK_CGROUP=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_RDMA=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_HUGETLB=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_PERF=y +CONFIG_CGROUP_BPF=y +CONFIG_CGROUP_MISC=y +CONFIG_NAMESPACES=y +CONFIG_USER_NS=y +CONFIG_CHECKPOINT_RESTORE=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_EXPERT=y +CONFIG_KALLSYMS_ALL=y +CONFIG_PERF_EVENTS=y +CONFIG_ARCH_NXP=y +CONFIG_ARCH_LAYERSCAPE=y +CONFIG_ARM64_VA_BITS_48=y +CONFIG_SCHED_MC=y +CONFIG_NR_CPUS=16 +CONFIG_NUMA=y +CONFIG_HZ_1000=y +CONFIG_RANDOMIZE_BASE=y +CONFIG_ENERGY_MODEL=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m +CONFIG_CPUFREQ_DT=y +CONFIG_QORIQ_CPUFREQ=y +CONFIG_VIRTUALIZATION=y +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_MODULE_COMPRESS=y +CONFIG_MODULE_COMPRESS_ZSTD=y +CONFIG_BLK_DEV_THROTTLING=y +CONFIG_BLK_CGROUP_IOCOST=y +CONFIG_ZSWAP=y +CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y +CONFIG_MEMORY_HOTPLUG=y +CONFIG_MEMORY_HOTREMOVE=y +CONFIG_TRANSPARENT_HUGEPAGE=y +CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_PACKET_DIAG=y +CONFIG_UNIX=y +CONFIG_UNIX_DIAG=y +CONFIG_TLS=y +CONFIG_TLS_DEVICE=y +CONFIG_XFRM_USER=m +CONFIG_NET_KEY=y +CONFIG_XDP_SOCKETS=y +CONFIG_INET=y +CONFIG_CPE_FAST_PATH=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_NET_IPIP=m +CONFIG_IP_MROUTE=y +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_INET_ESP=m +CONFIG_INET_ESP_OFFLOAD=m +CONFIG_INET_IPSEC_OFFLOAD=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_ESP=y +CONFIG_INET6_ESP_OFFLOAD=y +CONFIG_INET6_IPSEC_OFFLOAD=y +CONFIG_IPV6_TUNNEL=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_IPV6_MROUTE=y +CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y +CONFIG_IPV6_PIMSM_V2=y +CONFIG_NETWORK_PHY_TIMESTAMPING=y +CONFIG_NETFILTER=y +CONFIG_BRIDGE_NETFILTER=m +CONFIG_NETFILTER_NETLINK_HOOK=m +CONFIG_NF_CONNTRACK_ZONES=y +CONFIG_NF_CONNTRACK_PROCFS=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_NETLINK=m +CONFIG_NETFILTER_NETLINK_GLUE_CT=y +CONFIG_NF_TABLES=m +CONFIG_NF_TABLES_INET=y +CONFIG_NF_TABLES_NETDEV=y +CONFIG_NFT_NUMGEN=m +CONFIG_NFT_CT=m +CONFIG_NFT_FLOW_OFFLOAD=m +CONFIG_NFT_CONNLIMIT=m +CONFIG_NFT_LOG=m +CONFIG_NFT_LIMIT=m +CONFIG_NFT_MASQ=m +CONFIG_NFT_REDIR=m +CONFIG_NFT_NAT=m +CONFIG_NFT_TUNNEL=m +CONFIG_NFT_QUEUE=m +CONFIG_NFT_QUOTA=m +CONFIG_NFT_REJECT=m +CONFIG_NFT_COMPAT=m +CONFIG_NFT_HASH=m +CONFIG_NFT_FIB_INET=m +CONFIG_NFT_XFRM=m +CONFIG_NFT_SOCKET=m +CONFIG_NFT_OSF=m +CONFIG_NFT_TPROXY=m +CONFIG_NFT_SYNPROXY=m +CONFIG_NFT_DUP_NETDEV=m +CONFIG_NFT_FWD_NETDEV=m +CONFIG_NFT_FIB_NETDEV=m +CONFIG_NFT_REJECT_NETDEV=m +CONFIG_NF_FLOW_TABLE=m +CONFIG_NETFILTER_XT_QOSMARK=m +CONFIG_NETFILTER_XT_QOSCONNMARK=m +CONFIG_NETFILTER_XT_SET=m +CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_HMARK=m +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m +CONFIG_NETFILTER_XT_TARGET_LED=m +CONFIG_NETFILTER_XT_TARGET_LOG=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_NOTRACK=m +CONFIG_NETFILTER_XT_TARGET_TEE=m +CONFIG_NETFILTER_XT_TARGET_TPROXY=m +CONFIG_NETFILTER_XT_TARGET_TRACE=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +CONFIG_NETFILTER_XT_MATCH_BPF=m +CONFIG_NETFILTER_XT_MATCH_CGROUP=m +CONFIG_NETFILTER_XT_MATCH_CLUSTER=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_CPU=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ECN=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_IPCOMP=m +CONFIG_NETFILTER_XT_MATCH_IPRANGE=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_NFACCT=m +CONFIG_NETFILTER_XT_MATCH_OSF=m +CONFIG_NETFILTER_XT_MATCH_OWNER=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_RATEEST=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_RECENT=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_SOCKET=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_IP_SET=m +CONFIG_IP_SET_BITMAP_IP=m +CONFIG_IP_SET_BITMAP_PORT=m +CONFIG_IP_SET_HASH_IP=m +CONFIG_IP_SET_HASH_IPPORT=m +CONFIG_IP_SET_HASH_IPPORTNET=m +CONFIG_IP_SET_HASH_NET=m +CONFIG_IP_SET_HASH_NETPORT=m +CONFIG_IP_VS=m +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_NFCT=y +CONFIG_NFT_DUP_IPV4=m +CONFIG_NFT_FIB_IPV4=m +CONFIG_NF_TABLES_ARP=y +CONFIG_NF_LOG_ARP=y +CONFIG_NF_LOG_IPV4=y +CONFIG_NF_REJECT_IPV4=y +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_RAW=m +CONFIG_NFT_DUP_IPV6=m +CONFIG_NFT_FIB_IPV6=m +CONFIG_NF_REJECT_IPV6=y +CONFIG_NF_LOG_IPV6=y +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_RPFILTER=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_SRH=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_TARGET_SYNPROXY=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_RAW=m +CONFIG_IP6_NF_NAT=m +CONFIG_IP6_NF_TARGET_MASQUERADE=m +CONFIG_IP6_NF_TARGET_NPT=m +CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m +CONFIG_NFT_BRIDGE_REJECT=m +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_L2TP=m +CONFIG_L2TP_V3=y +CONFIG_BRIDGE=y +CONFIG_BRIDGE_VLAN_FILTERING=y +CONFIG_NET_DSA=y +CONFIG_VLAN_8021Q=m +CONFIG_VLAN_8021Q_GVRP=y +CONFIG_VLAN_8021Q_MVRP=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_HFSC=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_MULTIQ=m +CONFIG_NET_SCH_RED=y +CONFIG_NET_SCH_SFQ=y +CONFIG_NET_SCH_TEQL=y +CONFIG_NET_SCH_TBF=y +CONFIG_NET_SCH_TAPRIO=m +CONFIG_NET_SCH_MQPRIO=m +CONFIG_NET_SCH_FQ_CODEL=y +CONFIG_NET_SCH_FQ=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_U32=y +CONFIG_NET_CLS_CGROUP=m +CONFIG_NET_CLS_FLOWER=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_IPT=m +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_PEDIT=y +CONFIG_NET_ACT_SKBEDIT=y +CONFIG_NET_ACT_VLAN=y +CONFIG_NET_ACT_SKBMOD=y +CONFIG_NETLINK_DIAG=y +CONFIG_CGROUP_NET_PRIO=y +CONFIG_BPF_STREAM_PARSER=y +CONFIG_BT=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_NXPUART=m +CONFIG_CFG80211=m +CONFIG_MAC80211=m +CONFIG_PCI=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIEAER=y +CONFIG_PCI_IOV=y +# CONFIG_VGA_ARB is not set +CONFIG_HOTPLUG_PCI=y +CONFIG_PCI_LAYERSCAPE=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FSL_MC_UAPI_SUPPORT=y +CONFIG_CONNECTOR=y +CONFIG_ARM_SCMI_PROTOCOL=y +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_PSTORE=y +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_SPI_NOR=y +CONFIG_ZRAM=m +CONFIG_ZRAM_BACKEND_LZ4=y +CONFIG_ZRAM_BACKEND_LZ4HC=y +CONFIG_ZRAM_BACKEND_ZSTD=y +CONFIG_ZRAM_BACKEND_DEFLATE=y +CONFIG_ZRAM_BACKEND_842=y +CONFIG_ZRAM_BACKEND_LZO=y +CONFIG_ZRAM_WRITEBACK=y +CONFIG_ZRAM_MEMORY_TRACKING=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=65536 +CONFIG_VIRTIO_BLK=y +CONFIG_EEPROM_AT24=y +CONFIG_EEPROM_93CX6=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_NETDEVICES=y +CONFIG_DUMMY=m +CONFIG_WIREGUARD=y +CONFIG_MACVLAN=m +CONFIG_MACVTAP=m +CONFIG_IPVLAN=m +CONFIG_VXLAN=m +CONFIG_MACSEC=y +CONFIG_TUN=y +CONFIG_VETH=m +CONFIG_VIRTIO_NET=y +CONFIG_NETKIT=y +CONFIG_NET_DSA_MSCC_FELIX=m +CONFIG_FSL_PQ_MDIO=y +CONFIG_FSL_XGMAC_MDIO=y +CONFIG_FSL_SDK_DPAA_ETH=y +CONFIG_FSL_DPAA_1588=y +CONFIG_FSL_DPAA_ETH_MAX_BUF_COUNT=640 +CONFIG_FSL_ENETC_MDIO=y +# CONFIG_NET_VENDOR_STMICRO is not set +CONFIG_SFP=y +CONFIG_AQUANTIA_PHY=y +CONFIG_BROADCOM_PHY=y +CONFIG_BCM87XX_PHY=y +CONFIG_CICADA_PHY=y +CONFIG_CORTINA_PHY=y +CONFIG_DAVICOM_PHY=y +CONFIG_ICPLUS_PHY=y +CONFIG_LXT_PHY=y +CONFIG_LSI_ET1011C_PHY=y +CONFIG_MARVELL_PHY=m +CONFIG_MARVELL_10G_PHY=y +CONFIG_MAXLINEAR_GPHY=y +CONFIG_MICROSEMI_PHY=y +CONFIG_NATIONAL_PHY=y +CONFIG_QSEMI_PHY=y +CONFIG_REALTEK_PHY=y +CONFIG_SMSC_PHY=y +CONFIG_STE10XP=y +CONFIG_TERANETICS_PHY=y +CONFIG_DP83867_PHY=y +CONFIG_VITESSE_PHY=y +CONFIG_MDIO_BUS_MUX_MULTIPLEXER=y +CONFIG_MTIP_BACKPLANE_PHY=y +CONFIG_PCS_XPCS=m +CONFIG_PPP=m +CONFIG_PPP_FILTER=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=m +CONFIG_PPP_ASYNC=m +# CONFIG_USB_NET_DRIVERS is not set +CONFIG_ATH10K=m +CONFIG_ATH10K_PCI=m +CONFIG_IWLWIFI=m +CONFIG_IWLDVM=m +CONFIG_IWLMVM=m +CONFIG_MT7921E=m +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=8 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_DW=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +CONFIG_SERIAL_DEV_BUS=y +CONFIG_VIRTIO_CONSOLE=y +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y +CONFIG_I2C_MUX_PCA954x=y +CONFIG_I2C_IMX=y +CONFIG_SPI=y +CONFIG_SPI_FSL_QUADSPI=y +CONFIG_SPI_NXP_FLEXSPI=y +CONFIG_SPI_FSL_DSPI=y +CONFIG_DP83640_PHY=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_MPC8XXX=y +CONFIG_GPIO_SYSCON=y +CONFIG_GPIO_PCA953X=y +CONFIG_SENSORS_LM75=y +CONFIG_SENSORS_EMC2103=y +CONFIG_SENSORS_EMC2305=y +CONFIG_SENSORS_INA2XX=y +CONFIG_SENSORS_INA238=y +CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_QORIQ_THERMAL=y +CONFIG_WATCHDOG=y +CONFIG_IMX2_WDT=y +CONFIG_USB=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_STORAGE=y +CONFIG_USB_UAS=y +CONFIG_USB_DWC3=y +CONFIG_TYPEC=y +CONFIG_TYPEC_HD3SS3220=y +CONFIG_USB_ROLE_SWITCH=y +CONFIG_MMC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_OF_ESDHC=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_CLASS_MULTICOLOR=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGER_ONESHOT=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_ACTIVITY=y +CONFIG_LEDS_TRIGGER_NETDEV=y +CONFIG_LEDS_TRIGGER_PATTERN=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_PCF2127=m +CONFIG_DMADEVICES=y +CONFIG_FSL_EDMA=y +CONFIG_FSL_QDMA=m +CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_MMIO=y +CONFIG_VHOST_NET=m +CONFIG_STAGING=y +CONFIG_FSL_SDK_DPA=y +CONFIG_COMMON_CLK_SCMI=y +CONFIG_IOMMU_IO_PGTABLE_LPAE=y +CONFIG_IOMMU_DEFAULT_PASSTHROUGH=y +CONFIG_FSL_MC_DPIO=y +CONFIG_FSL_RCPM=y +CONFIG_PM_DEVFREQ=y +CONFIG_PHY_FSL_LYNX_10G=y +CONFIG_PHY_FSL_LYNX_28G=y +CONFIG_NVMEM_LAYERSCAPE_SFP=m +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_BTRFS_FS=m +CONFIG_BTRFS_FS_POSIX_ACL=y +CONFIG_FANOTIFY=y +CONFIG_FUSE_FS=m +CONFIG_OVERLAY_FS=m +CONFIG_VFAT_FS=y +CONFIG_EXFAT_FS=y +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_HUGETLBFS=y +CONFIG_CONFIGFS_FS=y +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_BLK=y +CONFIG_EROFS_FS=m +CONFIG_NFS_FS=y +CONFIG_NFS_V4=y +CONFIG_ROOT_NFS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_UTF8=y +CONFIG_PERSISTENT_KEYRINGS=y +CONFIG_ENCRYPTED_KEYS=y +CONFIG_KEY_DH_OPERATIONS=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_FORTIFY_SOURCE=y +CONFIG_CRYPTO_USER=y +CONFIG_CRYPTO_CMAC=y +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_SHA512_ARM64_CE=m +CONFIG_CRYPTO_AES_ARM64_BS=m +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_DEV_FSL_CAAM=y +CONFIG_CRYPTO_DEV_FSL_CAAM_INTC=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO_DWARF5=y +CONFIG_DEBUG_INFO_BTF=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_FS_DISALLOW_MOUNT=y +CONFIG_SOFTLOCKUP_DETECTOR=y +# CONFIG_SCHED_DEBUG is not set +CONFIG_FUNCTION_TRACER=y +CONFIG_FTRACE_SYSCALLS=y +CONFIG_PID_IN_CONTEXTIDR=y diff --git a/config/sources/families/ls1046a.conf b/config/sources/families/ls1046a.conf new file mode 100644 index 000000000000..b6731b2b7649 --- /dev/null +++ b/config/sources/families/ls1046a.conf @@ -0,0 +1,160 @@ +# +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2026 Mono Technologies Inc. +# +# This file is a part of the Armbian Build Framework +# https://github.com/armbian/build/ +# +# NXP LS1046A (Layerscape) family +# Quad Cortex-A72 arm64, DPAA1 with FMAN +# + +declare -g ARCH="arm64" +declare -g KERNEL_IMAGE_TYPE="Image" +declare -g SERIALCON="ttyS0" +declare -g SRC_EXTLINUX="yes" +declare -g OFFSET=32 # rootfs partition starts at 32 MiB (bootloader area: PBL@4K, FIP@1M, env@3M, FMAN@4M) +declare -g OVERLAY_DIR="/boot/dtb/freescale/overlay" +declare -g LINUXFAMILY="ls1046a" + +# CPU frequency scaling +declare -g CPUMIN=300000 +declare -g CPUMAX=1600000 +declare -g GOVERNOR=ondemand + +# Kernel +declare -g KERNELSOURCE='https://github.com/nxp-qoriq/linux.git' + +case "${BRANCH}" in + + current) + declare -g KERNEL_MAJOR_MINOR="6.12" + declare -g KERNELBRANCH='tag:lf-6.12.49-2.2.0' + declare -g LINUXCONFIG="linux-ls1046a-current" + declare -g KERNEL_DESCRIPTION="NXP Layerscape SDK kernel" + ;; + +esac + +declare -g KERNELPATCHDIR="archive/ls1046a-${KERNEL_MAJOR_MINOR}" + +# U-Boot, ATF, and RCW — must be set by board config (sourced before family) +declare -g BOOTSOURCE="${BOOTSOURCE:?BOOTSOURCE must be set by board config}" +declare -g BOOTBRANCH="${BOOTBRANCH:?BOOTBRANCH must be set by board config}" +declare -g BOOTPATCHDIR="${BOOTPATCHDIR:-u-boot-ls1046a}" +declare -g UBOOT_TARGET_MAP="${UBOOT_TARGET_MAP:?UBOOT_TARGET_MAP must be set by board config}" + +declare -g ATFSOURCE="${ATFSOURCE:?ATFSOURCE must be set by board config}" +declare -g ATFDIR="${ATFDIR:-arm-trusted-firmware-ls1046a}" +declare -g ATFBRANCH="${ATFBRANCH:?ATFBRANCH must be set by board config}" +declare -g ATFPATCHDIR="${ATFPATCHDIR:-atf-ls1046a}" + +# ATF/RCW platform name and source — must be set by board config +declare -g LS1046A_PLAT="${LS1046A_PLAT:?LS1046A_PLAT must be set by board config}" +declare -g ATF_TARGET_MAP="PLAT=${LS1046A_PLAT} bl31;;build/${LS1046A_PLAT}/release/bl31.bin" + +declare -g RCW_SOURCE="${RCW_SOURCE:?RCW_SOURCE must be set by board config}" +declare -g RCW_BRANCH="${RCW_BRANCH:?RCW_BRANCH must be set by board config}" + +# FMAN microcode (fetched during family_tweaks) +declare -g FMAN_UCODE_SOURCE='https://github.com/NXP/qoriq-fm-ucode.git' +declare -g FMAN_UCODE_SRCREV='41d603a1ad78e0bb61365500828d9f484bf9bf10' +declare -g FMAN_UCODE_FILE='fsl_fman_ucode_ls1046_r1.0_108_4_9.bin' + +# Helper: ensure FMAN microcode is fetched and cached (sets FMAN_UCODE_DIR) +function ensure_fman_ucode_cached() { + fetch_from_repo "${FMAN_UCODE_SOURCE}" "qoriq-fm-ucode" "commit:${FMAN_UCODE_SRCREV}" + declare -g FMAN_UCODE_DIR="${SRC}/cache/sources/qoriq-fm-ucode" +} + +# RCW build needs tcl +function add_host_dependencies__ls1046a_deps() { + display_alert "Adding host dependencies for LS1046A" "tcl" "debug" + declare -g EXTRA_BUILD_DEPS="${EXTRA_BUILD_DEPS} tcl" +} + +# After ATF compiles bl31, save the ATF directory path for uboot postprocess +function atf_custom_postprocess() { + display_alert "ATF BL31 compiled" "saving paths for FIP assembly" "info" + declare -g ATF_LS1046A_DIR + ATF_LS1046A_DIR="$(pwd)" +} + +function uboot_custom_postprocess() { + local ubootdir + ubootdir="$(pwd)" + + display_alert "LS1046A boot chain" "fetching RCW" "info" + + # Fetch and build RCW + fetch_from_repo "${RCW_SOURCE}" "rcw-ls1046a" "${RCW_BRANCH}" "yes" + local rcwdir="${SRC}/cache/sources/rcw-ls1046a/${RCW_BRANCH##*:}" + pushd "${rcwdir}" || exit_with_error "Cannot enter RCW directory" + run_host_command_logged make BOARDS="${LS1046A_PLAT}" + popd + + declare -g RCW_BIN_PATH="${RCW_BIN_PATH:?RCW_BIN_PATH must be set by board config}" + local rcw_bin="${rcwdir}/${LS1046A_PLAT}/${RCW_BIN_PATH}" + [[ ! -f "${rcw_bin}" ]] && exit_with_error "RCW binary not found at ${rcw_bin}" + + # Re-enter ATF directory and build PBL + FIP with BL33=u-boot.bin + local atfdir="${ATF_LS1046A_DIR:-${SRC}/cache/sources/${ATFDIR}/${ATFBRANCH##*:}}" + pushd "${atfdir}" || exit_with_error "Cannot enter ATF directory" + + display_alert "LS1046A boot chain" "building PBL + FIP (emmc)" "info" + run_host_command_logged make realclean + run_host_command_logged "CROSS_COMPILE='${ATF_COMPILER}'" \ + "CFLAGS='-fdiagnostics-color=always'" \ + make pbl fip \ + PLAT="${LS1046A_PLAT}" \ + BOOT_MODE=emmc \ + "RCW=${rcw_bin}" \ + "BL33=${ubootdir}/u-boot.bin" \ + "${CTHREADS}" + + # Copy final boot chain binaries to uboot output directory + run_host_command_logged cp -pv "build/${LS1046A_PLAT}/release/bl2_emmc.pbl" "${ubootdir}/" + run_host_command_logged cp -pv "build/${LS1046A_PLAT}/release/fip.bin" "${ubootdir}/" + + popd + + # Fetch FMAN microcode and copy to uboot output dir so it gets packaged + display_alert "LS1046A boot chain" "fetching FMAN microcode" "info" + ensure_fman_ucode_cached + run_host_command_logged cp -pv "${FMAN_UCODE_DIR}/${FMAN_UCODE_FILE}" "${ubootdir}/" + + # Build U-Boot environment binary (8KB at 3MB offset on eMMC) + display_alert "LS1046A boot chain" "building U-Boot environment" "info" + "${ubootdir}/tools/mkenvimage" -s 0x2000 -o "${ubootdir}/u-boot-env.bin" "${SRC}/config/bootenv/${BOOTENV_FILE:-ls1046a.txt}" + + # Restore cwd — fetch_from_repo changes it, and the framework expects to be in ubootdir + cd "${ubootdir}" || exit_with_error "Cannot return to U-Boot directory" +} + +function write_uboot_platform() { + # LS1046A eMMC layout: + # - PBL (RCW + BL2) at 4K offset (block 8) + # - FIP (BL31 + U-Boot) at 1M offset (block 2048) + # - U-Boot env at 3M offset (block 6144) + # - FMAN microcode at 4M offset (block 8192) + local -a parts=( + "bl2_emmc.pbl:8" + "fip.bin:2048" + "u-boot-env.bin:6144" + "fsl_fman_ucode_ls1046_r1.0_108_4_9.bin:8192" + ) + for part in "${parts[@]}"; do + local file="${part%%:*}" seek="${part##*:}" + [[ -f "$1/${file}" ]] || { echo "write_uboot_platform: missing $1/${file}" >&2; return 1; } + dd if="$1/${file}" of="$2" bs=512 seek="${seek}" conv=notrunc status=noxfer > /dev/null 2>&1 || return 1 + done +} + +function family_tweaks() { + # Install FMAN microcode to rootfs + display_alert "Installing FMAN microcode" "${FMAN_UCODE_FILE}" "info" + ensure_fman_ucode_cached + mkdir -p "${SDCARD}/lib/firmware/updates/" + cp "${FMAN_UCODE_DIR}/${FMAN_UCODE_FILE}" "${SDCARD}/lib/firmware/updates/${FMAN_UCODE_FILE}" +} diff --git a/extensions/gateway-dk-ask.sh b/extensions/gateway-dk-ask.sh new file mode 100644 index 000000000000..a71f78e077ec --- /dev/null +++ b/extensions/gateway-dk-ask.sh @@ -0,0 +1,520 @@ +#!/usr/bin/env bash +# +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2026 Mono Technologies Inc. +# +# NXP ASK (Application Solutions Kit) extension for LS1046A +# Builds and installs: kernel modules (CDX, FCI, auto-bridge), +# userspace tools (fmlib, fmc, libfci, libcli, dpa-app, cmm), +# patched system libraries, and configuration files. +# +# All ASK sources, patches, and configs come from the ASK repo. +# + +# Source repos and refs (pinned to match Yocto) +# For local testing: set ASK_REPO="file:///path/to/ASK" — the Docker mount hook below handles it +declare -g ASK_REPO="https://github.com/we-are-mono/ASK.git" +declare -g ASK_BRANCH="tag:mt-6.12.49-2.2.0" +declare -g FMLIB_REPO="https://github.com/nxp-qoriq/fmlib.git" +declare -g FMLIB_COMMIT="7a58ecaf0d90d71d6b78d3ac7998282a472c4394" +declare -g FMC_REPO="https://github.com/nxp-qoriq/fmc.git" +declare -g FMC_COMMIT="5b9f4b16a864e9dfa58cdcc860be278a7f66ac18" +declare -g LIBCLI_REPO="https://github.com/dparrish/libcli.git" +declare -g LIBCLI_COMMIT="6a3b2f96c4f0916e2603a96bf24d704f6a904e7a" + +# ASK component directories +declare -g ASK_CDX_DIR="cdx" +declare -g ASK_FCI_DIR="fci" +declare -g ASK_AUTOBRIDGE_DIR="auto_bridge" +declare -g ASK_DPA_APP_DIR="dpa_app" +declare -g ASK_CMM_DIR="cmm" + +# Mount local ASK repo into Docker container when using file:// URL +function host_pre_docker_launch__mount_local_ask() { + if [[ "${ASK_REPO}" == file://* ]]; then + local local_path="${ASK_REPO#file://}" + DOCKER_EXTRA_ARGS+=("--mount" "type=bind,source=${local_path},target=${local_path},readonly") + display_alert "ASK extension" "mounting local ASK repo into Docker: ${local_path}" "info" + fi +} + +# Override LINUXFAMILY so ASK-enabled kernels get distinct .deb names. +# Without this, ASK and non-ASK kernels both produce linux-image-current-ls1046a, +# colliding in the apt repo despite having different content (the ASK kernel patch). +function post_family_config__000_ask_override_family() { + declare -g LINUXFAMILY="${LINUXFAMILY}-ask" + declare -g LINUXCONFIG="linux-${LINUXFAMILY}-${BRANCH}" + display_alert "ASK extension" "LINUXFAMILY=${LINUXFAMILY}, LINUXCONFIG=${LINUXCONFIG}" "info" +} + +# Fetch ASK repo (sets ASK_CACHE_DIR for all later build phases) +# Uses post_family_config because the kernel patch staging hook needs it before fetch_sources_tools runs +function post_family_config__ask_fetch_repo() { + # For local file:// repos in Docker, safe.directory is needed (container runs as root) + # Use env vars instead of git config --global to avoid persistent side effects + if [[ "${ASK_REPO}" == file://* ]]; then + local local_path="${ASK_REPO#file://}" + export GIT_CONFIG_COUNT=2 + export GIT_CONFIG_KEY_0="safe.directory" GIT_CONFIG_VALUE_0="${local_path}" + export GIT_CONFIG_KEY_1="safe.directory" GIT_CONFIG_VALUE_1="${local_path}/.git" + fi + fetch_from_repo "${ASK_REPO}" "ask-repo" "${ASK_BRANCH}" + unset GIT_CONFIG_COUNT GIT_CONFIG_KEY_0 GIT_CONFIG_VALUE_0 GIT_CONFIG_KEY_1 GIT_CONFIG_VALUE_1 2>/dev/null + declare -g ASK_CACHE_DIR="${SRC}/cache/sources/ask-repo" +} + +# Ensure kernel headers are available for module builds +function extension_finish_config__ask_enable_headers() { + declare -g INSTALL_HEADERS="yes" + # Derive multiarch triplet here (not at source time) — KERNEL_COMPILER is set by arch config + [[ -z "${KERNEL_COMPILER}" ]] && exit_with_error "ASK extension: KERNEL_COMPILER is not set, cannot derive host triplet" + declare -g ASK_HOST_TRIPLET="${KERNEL_COMPILER%-}" + display_alert "ASK extension" "enabling kernel headers for module builds" "info" +} + +# Host build dependencies — kernel module cross-compilation only needs the kernel source tree +# (libxml2-dev, libtclap-dev, libpcap-dev, pkg-config are installed in-chroot for userspace builds) + +# Copy ASK kernel patch to userpatches (gitignored) so it's applied during kernel build. +# userpatches/ is the Armbian-standard location for extension-provided patches — the build +# framework merges them with patches from patch/kernel/ at build time. The directory is +# gitignored and ephemeral; it does not persist across clean builds. +function post_family_config__ask_kernel_patch() { + local patch_src="${ASK_CACHE_DIR}/patches/kernel/002-mono-gateway-ask-kernel_linux_6_12.patch" + [[ -f "${patch_src}" ]] || exit_with_error "ASK kernel patch not found" "${patch_src}" + local patch_dst="${SRC}/userpatches/kernel/${KERNELPATCHDIR}" + mkdir -p "${patch_dst}" + # Renamed to 003- to apply after 001-ina234 and 002-device-tree in the Armbian patch dir + cp "${patch_src}" "${patch_dst}/003-mono-gateway-ask-kernel_linux_6_12.patch" + display_alert "ASK extension" "ASK kernel patch staged in userpatches" "info" +} + +function cleanup_ask_module_builddir() { + [[ -n "${ASK_MODULE_BUILDDIR}" && -d "${ASK_MODULE_BUILDDIR}" ]] && rm -rf "${ASK_MODULE_BUILDDIR}" || true +} + +# Build kernel modules after kernel debs are installed in chroot +function post_install_kernel_debs__build_ask_modules() { + [[ "${INSTALL_HEADERS}" != "yes" ]] && return 0 + + display_alert "ASK extension" "building kernel modules (host cross-compile)" "info" + + declare -g ASK_KERNEL_VER + ASK_KERNEL_VER=$(ls -1v "${SDCARD}/lib/modules/" | tail -1) + [[ -z "${ASK_KERNEL_VER}" ]] && exit_with_error "No kernel version found in ${SDCARD}/lib/modules/" + local kernel_ver="${ASK_KERNEL_VER}" + + # Full kernel source tree (needed for CDX — it includes ncsw_config.mk from the FMAN driver) + local ksrc="${SRC}/cache/sources/linux-kernel-worktree/${KERNEL_MAJOR_MINOR}__${LINUXFAMILY}__${ARCH}" + [[ -d "${ksrc}" ]] || exit_with_error "Kernel source tree not found at ${ksrc}" + + local cross="${KERNEL_COMPILER}" + local bsp_dir="${SRC}/packages/bsp/gateway-dk" + local builddir + builddir=$(mktemp -d) + declare -g ASK_MODULE_BUILDDIR="${builddir}" + add_cleanup_handler cleanup_ask_module_builddir + + # Copy ASK module sources to build dir + cp -a "${ASK_CACHE_DIR}/${ASK_CDX_DIR}" "${builddir}/cdx" + cp -a "${ASK_CACHE_DIR}/${ASK_FCI_DIR}" "${builddir}/fci" + cp -a "${ASK_CACHE_DIR}/${ASK_AUTOBRIDGE_DIR}" "${builddir}/auto-bridge" + + # Build CDX module (cross-compile on host against full kernel source) + # NXP ASK uses LS1043A as the DPAA1 platform ID for all DPAA1 SoCs (LS1043A/LS1046A) + display_alert "ASK extension" "building CDX kernel module" "info" + make -C "${builddir}/cdx" \ + KERNELDIR="${ksrc}" ARCH=arm64 CROSS_COMPILE="${cross}" PLATFORM=LS1043A \ + CFG_FLAGS="-DSEC_PROFILE_SUPPORT -DVLAN_FILTER -DWIFI_ENABLE -DENABLE_EGRESS_QOS" \ + || exit_with_error "CDX module build failed" + + # Build FCI module (depends on CDX Module.symvers) + display_alert "ASK extension" "building FCI kernel module" "info" + make -C "${builddir}/fci" \ + KERNEL_SOURCE="${ksrc}" ARCH=arm64 CROSS_COMPILE="${cross}" BOARD_ARCH=arm64 \ + KBUILD_EXTRA_SYMBOLS="${builddir}/cdx/Module.symvers" \ + || exit_with_error "FCI module build failed" + + # Build auto-bridge module (uses its own Makefile which adds -I for br_private.h) + display_alert "ASK extension" "building auto-bridge kernel module" "info" + make -C "${builddir}/auto-bridge" \ + KERNEL_SOURCE="${ksrc}" CROSS_COMPILE="${cross}" PLATFORM=LS1043A ENABLE_VLAN_FILTER=y \ + || exit_with_error "auto-bridge module build failed" + + # Board-specific modules (gateway-dk only) + if [[ "${BOARD}" == "gateway-dk" ]]; then + # SFP-LED: GPIO-based SFP port LED control + display_alert "ASK extension" "building SFP-LED kernel module" "info" + mkdir -p "${builddir}/sfp-led" + cp "${bsp_dir}/sfp-led.c" "${builddir}/sfp-led/" + cp "${bsp_dir}/sfp-led.mk" "${builddir}/sfp-led/Makefile" + pushd "${builddir}/sfp-led" + make KERNEL_SRC="${ksrc}" ARCH=arm64 CROSS_COMPILE="${cross}" \ + || exit_with_error "SFP-LED module build failed" + popd + + # LP5812: TI 4x3 LED matrix controller (not yet in mainline, targeting 6.19+) + display_alert "ASK extension" "building LP5812 LED driver" "info" + mkdir -p "${builddir}/lp5812" + cp "${bsp_dir}/leds-lp5812.c" "${builddir}/lp5812/" + cp "${bsp_dir}/leds-lp5812.h" "${builddir}/lp5812/" + cp "${bsp_dir}/leds-lp5812.mk" "${builddir}/lp5812/Makefile" + pushd "${builddir}/lp5812" + make KERNEL_SRC="${ksrc}" ARCH=arm64 CROSS_COMPILE="${cross}" \ + || exit_with_error "LP5812 module build failed" + popd + fi + + # Stage built modules for the combined .deb (packaged later in userspace phase) + display_alert "ASK extension" "staging kernel modules for packaging" "info" + declare -g ASK_MODULE_STAGING="${SRC}/cache/sources/ask-module-staging" + rm -rf "${ASK_MODULE_STAGING}" + mkdir -p "${ASK_MODULE_STAGING}" + + cp "${builddir}/cdx/cdx.ko" "${ASK_MODULE_STAGING}/" + cp "${builddir}/fci/fci.ko" "${ASK_MODULE_STAGING}/" + cp "${builddir}/auto-bridge/auto_bridge.ko" "${ASK_MODULE_STAGING}/" + [[ -f "${builddir}/sfp-led/sfp-led.ko" ]] && cp "${builddir}/sfp-led/sfp-led.ko" "${ASK_MODULE_STAGING}/" + [[ -f "${builddir}/lp5812/leds-lp5812.ko" ]] && cp "${builddir}/lp5812/leds-lp5812.ko" "${ASK_MODULE_STAGING}/" + + # Also install directly into rootfs so they're available during the rest of the build + mkdir -p "${SDCARD}/lib/modules/${kernel_ver}/extra" + cp "${ASK_MODULE_STAGING}"/*.ko "${SDCARD}/lib/modules/${kernel_ver}/extra/" + chroot_sdcard "depmod -a ${kernel_ver}" || exit_with_error "depmod failed" + cp "${ASK_CACHE_DIR}/config/ask-modules.conf" "${SDCARD}/etc/modules-load.d/" + + # Clean up build dir + rm -rf "${builddir}" + + display_alert "ASK extension" "kernel modules built and staged" "info" +} + +# Copy patches into chroot before patched library builds (runs before build_ask_userspace) +function pre_customize_image__000_prepare_ask_patches() { + mkdir -p "${SDCARD}/tmp/ask-patches" + local patch_dirs=("libnetfilter-conntrack" "libnfnetlink" "iptables") + for pdir in "${patch_dirs[@]}"; do + [[ -d "${ASK_CACHE_DIR}/patches/${pdir}" ]] || exit_with_error "ASK patch directory missing" "${ASK_CACHE_DIR}/patches/${pdir}" + cp "${ASK_CACHE_DIR}/patches/${pdir}/"*.patch "${SDCARD}/tmp/ask-patches/" + done + + # Enable deb-src for apt-get source + chroot_sdcard "if [ -f /etc/apt/sources.list.d/debian.sources ]; then \ + sed -i 's/^Types: deb\$/Types: deb deb-src/' /etc/apt/sources.list.d/debian.sources; \ + elif [ -f /etc/apt/sources.list ]; then \ + sed -i 's/^#\\s*deb-src/deb-src/' /etc/apt/sources.list; \ + fi && apt-get update -qq" + chroot_sdcard_apt_get_install dpkg-dev devscripts +} + +# Build and install all ASK userspace components +function pre_customize_image__001_build_ask_userspace() { + display_alert "ASK extension" "building userspace components" "info" + + local kernel_ver="${ASK_KERNEL_VER}" + local kdir="/usr/src/linux-headers-${kernel_ver}" + + # Install build dependencies in chroot + display_alert "ASK extension" "installing build dependencies" "info" + chroot_sdcard_apt_get_install build-essential \ + pkg-config libxml2-dev libpcap-dev libcrypt-dev libtclap-dev + + # Copy sources into chroot + mkdir -p "${SDCARD}/tmp/ask-userspace" + + # --- fmlib --- + display_alert "ASK extension" "building fmlib" "info" + fetch_from_repo "${FMLIB_REPO}" "fmlib" "commit:${FMLIB_COMMIT}" + cp -a "${SRC}/cache/sources/fmlib" "${SDCARD}/tmp/ask-userspace/fmlib" + cp "${ASK_CACHE_DIR}/patches/fmlib/"*.patch "${SDCARD}/tmp/ask-userspace/" + + chroot_sdcard "cd /tmp/ask-userspace/fmlib && \ + patch -p1 < /tmp/ask-userspace/01-mono-ask-extensions.patch && \ + make KERNEL_SRC=${kdir} libfm-arm.a && \ + make DESTDIR=/ PREFIX=/usr LIB_DEST_DIR=/usr/lib/${ASK_HOST_TRIPLET} install-libfm-arm" \ + || exit_with_error "fmlib build failed" + + # --- fmc --- + display_alert "ASK extension" "building fmc" "info" + fetch_from_repo "${FMC_REPO}" "fmc" "commit:${FMC_COMMIT}" + cp -a "${SRC}/cache/sources/fmc" "${SDCARD}/tmp/ask-userspace/fmc" + cp "${ASK_CACHE_DIR}/patches/fmc/"*.patch "${SDCARD}/tmp/ask-userspace/" + + chroot_sdcard "cd /tmp/ask-userspace/fmc && \ + patch -p1 < /tmp/ask-userspace/01-mono-ask-extensions.patch && \ + make MACHINE=ls1043 \ + FMD_USPACE_HEADER_PATH=/usr/include/fmd \ + FMD_USPACE_LIB_PATH=/usr/lib/${ASK_HOST_TRIPLET} \ + LIBXML2_HEADER_PATH=/usr/include/libxml2 \ + TCLAP_HEADER_PATH=/usr/include \ + -C source && \ + install -m 755 source/fmc /usr/bin/ && \ + install -d /usr/include/fmc && \ + install -m 644 source/fmc.h /usr/include/fmc/ && \ + install -m 644 source/libfmc.a /usr/lib/${ASK_HOST_TRIPLET}/ && \ + install -d /etc/fmc/config && \ + install -m 644 etc/fmc/config/* /etc/fmc/config/" \ + || exit_with_error "fmc build failed" + + # --- libcli --- + display_alert "ASK extension" "building libcli" "info" + fetch_from_repo "${LIBCLI_REPO}" "libcli" "commit:${LIBCLI_COMMIT}" + cp -a "${SRC}/cache/sources/libcli" "${SDCARD}/tmp/ask-userspace/libcli" + + chroot_sdcard "cd /tmp/ask-userspace/libcli && \ + make CFLAGS='-Wno-calloc-transposed-args' && \ + make PREFIX=/usr DESTDIR=/ install" \ + || exit_with_error "libcli build failed" + + # --- libfci --- + display_alert "ASK extension" "building libfci" "info" + cp -a "${ASK_CACHE_DIR}/${ASK_FCI_DIR}/lib" "${SDCARD}/tmp/ask-userspace/libfci" + + chroot_sdcard "cd /tmp/ask-userspace/libfci && \ + make && \ + install -m 644 libfci.a /usr/lib/${ASK_HOST_TRIPLET}/ && \ + install -m 644 include/libfci.h /usr/include/" \ + || exit_with_error "libfci build failed" + + # --- dpa-app --- + display_alert "ASK extension" "building dpa-app" "info" + cp -a "${ASK_CACHE_DIR}/${ASK_DPA_APP_DIR}" "${SDCARD}/tmp/ask-userspace/dpa-app" + # Copy CDX header + mkdir -p "${SDCARD}/usr/include/cdx" + cp "${ASK_CACHE_DIR}/${ASK_CDX_DIR}/cdx_ioctl.h" "${SDCARD}/usr/include/cdx/" + + chroot_sdcard "cd /tmp/ask-userspace/dpa-app && \ + make CC=gcc \ + CFLAGS='-DENDIAN_LITTLE -DLS1043 -DNCSW_LINUX -DDPAA_DEBUG_ENABLE -DSEC_PROFILE_SUPPORT -DVLAN_FILTER \ + -I/usr/include/fmc -I/usr/include/fmd -I/usr/include/fmd/integrations \ + -I/usr/include/fmd/Peripherals -I/usr/include/fmd/Peripherals/common -I/usr/include/cdx' \ + LDFLAGS='-lfmc -lfm-arm -lstdc++ -lxml2 -lpthread -lcli' && \ + install -m 755 dpa_app /usr/bin/" \ + || exit_with_error "dpa-app build failed" + + # Install DPA-App config files (from ASK repo) + cp "${ASK_CACHE_DIR}/config/gateway-dk/cdx_cfg.xml" "${SDCARD}/etc/" + cp "${ASK_CACHE_DIR}/${ASK_DPA_APP_DIR}/files/etc/cdx_pcd.xml" "${SDCARD}/etc/" + cp "${ASK_CACHE_DIR}/${ASK_DPA_APP_DIR}/files/etc/cdx_sp.xml" "${SDCARD}/etc/" + + # --- Patched system libraries (must be before CMM which depends on patched libnetfilter-conntrack) --- + build_ask_patched_libraries + + # --- cmm --- + display_alert "ASK extension" "building cmm" "info" + cp -a "${ASK_CACHE_DIR}/${ASK_CMM_DIR}" "${SDCARD}/tmp/ask-userspace/cmm" + # Copy auto-bridge header for CMM + cp "${ASK_CACHE_DIR}/${ASK_AUTOBRIDGE_DIR}/include/auto_bridge.h" "${SDCARD}/usr/include/" + + # CMM's Makefile sets base CFLAGS (with +=) internally and uses pkg-config for + # libnetfilter_conntrack. auto_bridge.h already at /usr/include, libfci built in-tree. + # Extra defines passed as env var so Makefile's += appends to them (not overrides). + chroot_sdcard "cd /tmp/ask-userspace/cmm && \ + make clean || true && \ + CFLAGS='-DFLOW_STATS -DSEC_PROFILE_SUPPORT -DUSE_QOSCONNMARK \ + -DENABLE_INGRESS_QOS -DIPSEC_NO_FLOW_CACHE -DVLAN_FILTER' \ + make \ + LIBFCI_DIR=/tmp/ask-userspace/libfci \ + ABM_DIR=/usr \ + SYSROOT=/ && \ + install -m 755 src/cmm /usr/bin/" \ + || exit_with_error "cmm build failed" + + # Install and enable CMM service (from ASK repo) + # Guarded by ConditionPathExists=/dev/cdx_ctrl — won't start without ASK FMAN ucode on NOR + cp "${ASK_CACHE_DIR}/config/cmm.service" "${SDCARD}/etc/systemd/system/" + mkdir -p "${SDCARD}/etc/config" + cp "${ASK_CACHE_DIR}/config/fastforward" "${SDCARD}/etc/config/" + chroot_sdcard systemctl enable cmm.service + + # Pin patched packages — ASK patches add kernel offloading hooks (comcerto-fp, + # QOSMARK/QOSCONNMARK) that don't exist upstream. An apt upgrade would replace + # them with vanilla Debian builds and break CMM/CDX data-plane acceleration. + # These are shipped as separate .debs (not bundled into gateway-dk-ask) because + # they replace system packages and must be managed by dpkg as proper overrides. + # The postinst re-applies holds on every upgrade. Security updates must be + # tracked and re-patched manually. + display_alert "ASK extension" "pinning patched packages" "info" + chroot_sdcard "apt-mark hold libnetfilter-conntrack3 libnfnetlink0 iptables" + + # Install sysctl tuning for conntrack + install -Dm 644 "${SRC}/packages/bsp/gateway-dk/99-ls1046a-conntrack.conf" \ + "${SDCARD}/etc/sysctl.d/99-ls1046a-conntrack.conf" + + # Cleanup build sources + rm -rf "${SDCARD}/tmp/ask-userspace" "${SDCARD}/tmp/ask-patches" + + # --- Package everything as a single gateway-dk-ask .deb --- + display_alert "ASK extension" "packaging combined ASK .deb" "info" + local pkgname="gateway-dk-ask" + local pkgdir + pkgdir=$(mktemp -d) + mkdir -p "${pkgdir}/DEBIAN" + + # Kernel modules (staged during post_install_kernel_debs phase) + local moddir="${pkgdir}/lib/modules/${kernel_ver}/extra" + mkdir -p "${moddir}" "${pkgdir}/etc/modules-load.d" + cp "${ASK_MODULE_STAGING}"/*.ko "${moddir}/" + cp "${ASK_CACHE_DIR}/config/ask-modules.conf" "${pkgdir}/etc/modules-load.d/" + rm -rf "${ASK_MODULE_STAGING}" + + # Snapshot userspace files into package tree + local -a ask_files=( + usr/bin/fmc + usr/bin/dpa_app + usr/bin/cmm + etc/fmc + etc/cdx_cfg.xml + etc/cdx_pcd.xml + etc/cdx_sp.xml + etc/systemd/system/cmm.service + etc/config/fastforward + etc/sysctl.d/99-ls1046a-conntrack.conf + usr/include/fmc + usr/include/fmd + usr/include/libfci.h + usr/include/cdx + usr/include/auto_bridge.h + ) + for f in "${ask_files[@]}"; do + if [[ -e "${SDCARD}/${f}" ]]; then + mkdir -p "$(dirname "${pkgdir}/${f}")" + cp -a "${SDCARD}/${f}" "${pkgdir}/${f}" + fi + done + # Libraries — snapshot all ASK-installed libs from chroot + mkdir -p "${pkgdir}/usr/lib/${ASK_HOST_TRIPLET}" + for lib in libfm-arm.a libfmc.a; do + [[ -f "${SDCARD}/usr/lib/${ASK_HOST_TRIPLET}/${lib}" ]] && \ + cp -a "${SDCARD}/usr/lib/${ASK_HOST_TRIPLET}/${lib}" "${pkgdir}/usr/lib/${ASK_HOST_TRIPLET}/" + done + for pattern in libcli libfci; do + for f in "${SDCARD}/usr/lib/${ASK_HOST_TRIPLET}/"${pattern}*; do + [[ -f "$f" ]] && cp -a "$f" "${pkgdir}/usr/lib/${ASK_HOST_TRIPLET}/" + done + done + + # Version: kernel version + build date — allows bugfix rebuilds without kernel change + local ask_version="${kernel_ver}+$(date +%Y%m%d)" + + # Depends uses >= (not =): this is intentional. The kernel may receive minor version bumps + # without ASK changes. Using = would require rebuilding ASK for every kernel point release + # even when the modules are unchanged. The modules are ABI-compatible within the same + # LINUXFAMILY and BRANCH. DKMS is not used — this is a controlled appliance where both + # packages are built and validated together. + cat > "${pkgdir}/DEBIAN/control" << EOF +Package: ${pkgname} +Version: ${ask_version} +Architecture: arm64 +Section: net +Priority: optional +Maintainer: Mono Technologies +Depends: linux-image-${BRANCH}-${LINUXFAMILY} (>= ${kernel_ver}), libxml2, libpcap0.8 +Description: NXP ASK hardware offloading for Mono Gateway DK + Kernel modules (CDX, FCI, auto-bridge, sfp-led, leds-lp5812) and + userspace tools (fmlib, fmc, libfci, libcli, dpa-app, cmm) for + NXP ASK data-plane acceleration on the LS1046A Gateway DK. +EOF + + cat > "${pkgdir}/DEBIAN/postinst" << EOF +#!/bin/bash +depmod -a ${kernel_ver} +systemctl daemon-reload || true +ldconfig || true +# Enable CMM service on OTA install (guarded by ConditionPathExists=/dev/cdx_ctrl at runtime) +if command -v systemctl >/dev/null 2>&1; then + systemctl enable cmm.service 2>/dev/null || true +fi +# Re-pin patched ASK libraries — vanilla Debian versions break CMM/CDX offloading +apt-mark hold libnetfilter-conntrack3 libnfnetlink0 iptables 2>/dev/null || true +EOF + chmod 755 "${pkgdir}/DEBIAN/postinst" + + cat > "${pkgdir}/DEBIAN/prerm" << 'EOF' +#!/bin/bash +systemctl stop cmm.service 2>/dev/null || true +EOF + chmod 755 "${pkgdir}/DEBIAN/prerm" + + cat > "${pkgdir}/DEBIAN/postrm" << EOF +#!/bin/bash +depmod -a ${kernel_ver} || true +ldconfig || true +systemctl daemon-reload || true +if [ "\$1" = "remove" ] || [ "\$1" = "purge" ]; then + apt-mark unhold libnetfilter-conntrack3 libnfnetlink0 iptables 2>/dev/null || true +fi +EOF + chmod 755 "${pkgdir}/DEBIAN/postrm" + + cat > "${pkgdir}/DEBIAN/conffiles" << 'CONFFILES' +/etc/cdx_cfg.xml +/etc/cdx_pcd.xml +/etc/cdx_sp.xml +/etc/config/fastforward +/etc/sysctl.d/99-ls1046a-conntrack.conf +CONFFILES + + # Build .deb once, install in chroot and save to output + local debfile="${pkgname}_${ask_version}_arm64.deb" + mkdir -p "${SRC}/output/debs" + run_host_command_logged dpkg-deb -b "${pkgdir}" "${SRC}/output/debs/${debfile}" \ + || exit_with_error "dpkg-deb failed for ${debfile}" + cp "${SRC}/output/debs/${debfile}" "${SDCARD}/root/" + chroot_sdcard "dpkg -i /root/${debfile}" || exit_with_error "dpkg -i failed for ${debfile}" + rm -f "${SDCARD}/root/${debfile}" + + rm -rf "${pkgdir}" + + display_alert "ASK extension" "ASK packaged and installed: ${debfile}" "info" +} + +# Build patched versions of system libraries +function build_ask_patched_libraries() { + # Install all build dependencies upfront + display_alert "ASK extension" "installing build deps for patched libraries" "info" + chroot_sdcard "DEBIAN_FRONTEND=noninteractive apt-get -y build-dep \ + libnetfilter-conntrack libnfnetlink iptables" + + # Staging dir for patched .debs (saved to output later) + mkdir -p "${SDCARD}/tmp/ask-patched-debs" + + # Rebuild each patched library in an isolated directory + rebuild_patched_deb "libnetfilter-conntrack" \ + "01-nxp-ask-comcerto-fp-extensions.patch" \ + "libnetfilter-conntrack3_*.deb libnetfilter-conntrack-dev_*.deb" + + rebuild_patched_deb "libnfnetlink" \ + "01-nxp-ask-nonblocking-heap-buffer.patch" \ + "libnfnetlink0_*.deb libnfnetlink-dev_*.deb" + + rebuild_patched_deb "iptables" \ + "001-qosmark-extensions.patch" \ + "libip4tc2_*.deb libip6tc2_*.deb libxtables12_*.deb iptables_*.deb" + + # Copy patched .debs to output for distribution + mkdir -p "${SRC}/output/debs" + cp "${SDCARD}"/tmp/ask-patched-debs/*.deb "${SRC}/output/debs/" 2>/dev/null || true + rm -rf "${SDCARD}/tmp/ask-patched-debs" +} + +# Helper: rebuild a Debian package with an ASK patch in an isolated chroot directory +# Usage: rebuild_patched_deb +function rebuild_patched_deb() { + local pkg="$1" patch="$2" debs="$3" + local workdir="/tmp/ask-rebuild-${pkg}" + + display_alert "ASK extension" "rebuilding ${pkg}" "info" + # Note: ${debs} is intentionally unquoted — it contains globs that must expand in the chroot + chroot_sdcard "set -e && \ + rm -rf '${workdir}' && mkdir -p '${workdir}' && cd '${workdir}' && \ + apt-get source '${pkg}' && \ + cd \$(ls -d ${pkg}-*/ | head -1) && \ + patch -p1 < '/tmp/ask-patches/${patch}' && \ + DEB_BUILD_OPTIONS=nocheck dpkg-buildpackage -b -uc -us && \ + cd '${workdir}' && dpkg -i ${debs} && \ + cp ${debs} /tmp/ask-patched-debs/ && \ + rm -rf '${workdir}'" \ + || exit_with_error "${pkg} rebuild failed" +} diff --git a/packages/bsp/gateway-dk/99-ls1046a-conntrack.conf b/packages/bsp/gateway-dk/99-ls1046a-conntrack.conf new file mode 100644 index 000000000000..a4b2123911da --- /dev/null +++ b/packages/bsp/gateway-dk/99-ls1046a-conntrack.conf @@ -0,0 +1,6 @@ +net.netfilter.nf_conntrack_acct=1 +net.netfilter.nf_conntrack_checksum=0 +net.netfilter.nf_conntrack_max=131072 +net.netfilter.nf_conntrack_tcp_timeout_established=7440 +net.netfilter.nf_conntrack_udp_timeout=60 +net.netfilter.nf_conntrack_udp_timeout_stream=180 diff --git a/packages/bsp/gateway-dk/gateway-dk-leds.service b/packages/bsp/gateway-dk/gateway-dk-leds.service new file mode 100644 index 000000000000..e688d2d1932d --- /dev/null +++ b/packages/bsp/gateway-dk/gateway-dk-leds.service @@ -0,0 +1,11 @@ +[Unit] +Description=Mono Gateway DK boot LED indicator +After=systemd-modules-load.service systemd-udev-settle.service + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/gateway-dk-leds.sh +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target diff --git a/packages/bsp/gateway-dk/gateway-dk-leds.sh b/packages/bsp/gateway-dk/gateway-dk-leds.sh new file mode 100644 index 000000000000..1aaae857a4bd --- /dev/null +++ b/packages/bsp/gateway-dk/gateway-dk-leds.sh @@ -0,0 +1,7 @@ +#!/bin/bash +set -e +# Mono Gateway DK — switch from U-Boot green LED to white (Linux booted) +GREEN="/sys/class/leds/status:green/brightness" +WHITE="/sys/class/leds/status:white/brightness" +[[ -w "$GREEN" ]] && echo 0 > "$GREEN" +[[ -w "$WHITE" ]] && echo 32 > "$WHITE" diff --git a/packages/bsp/gateway-dk/generate-fancontrol-conf b/packages/bsp/gateway-dk/generate-fancontrol-conf new file mode 100755 index 000000000000..1698fee25ab6 --- /dev/null +++ b/packages/bsp/gateway-dk/generate-fancontrol-conf @@ -0,0 +1,43 @@ +#!/bin/bash +set -e +# Generate /etc/fancontrol with correct hwmon numbers for Mono Gateway DK +# EMC2305 fan controller driven by cluster_thermal CPU temperature +# Retries for up to 30s in case hwmon devices aren't ready at boot + +# Remove stale config from previous boot (hwmon numbers may have changed) +rm -f /etc/fancontrol + +FAN_HWMON="" +TEMP_HWMON="" + +for attempt in $(seq 1 6); do + for h in /sys/class/hwmon/hwmon*; do + name=$(cat "$h/name" 2>/dev/null) + case "$name" in + emc2305) FAN_HWMON=$(basename "$h") ;; + cluster_thermal) TEMP_HWMON=$(basename "$h") ;; + esac + done + [ -n "$FAN_HWMON" ] && [ -n "$TEMP_HWMON" ] && break + sleep 5 +done + +if [ -z "$FAN_HWMON" ] || [ -z "$TEMP_HWMON" ]; then + echo "ERROR: Could not find emc2305 or cluster_thermal hwmon devices after 30s" >&2 + exit 1 +fi + +FAN_DEV=$(readlink -f "/sys/class/hwmon/$FAN_HWMON/device" | sed 's|/sys/||') +TEMP_DEV=$(readlink -f "/sys/class/hwmon/$TEMP_HWMON/device" | sed 's|/sys/||') + +cat > /etc/fancontrol << EOF +INTERVAL=10 +DEVPATH=${TEMP_HWMON}=${TEMP_DEV} ${FAN_HWMON}=${FAN_DEV} +DEVNAME=${TEMP_HWMON}=cluster_thermal ${FAN_HWMON}=emc2305 +FCTEMPS=${FAN_HWMON}/pwm1=${TEMP_HWMON}/temp1_input +FCFANS=${FAN_HWMON}/pwm1=${FAN_HWMON}/fan1_input +MINTEMP=${FAN_HWMON}/pwm1=40 +MAXTEMP=${FAN_HWMON}/pwm1=80 +MINSTART=${FAN_HWMON}/pwm1=51 +MINSTOP=${FAN_HWMON}/pwm1=34 +EOF diff --git a/packages/bsp/gateway-dk/generate-fancontrol-conf.service b/packages/bsp/gateway-dk/generate-fancontrol-conf.service new file mode 100644 index 000000000000..3180800b5a9a --- /dev/null +++ b/packages/bsp/gateway-dk/generate-fancontrol-conf.service @@ -0,0 +1,13 @@ +[Unit] +Description=Generate fancontrol configuration for Mono Gateway DK +DefaultDependencies=no +Before=fancontrol.service +After=systemd-udev-settle.service + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/generate-fancontrol-conf +RemainAfterExit=yes + +[Install] +WantedBy=fancontrol.service diff --git a/packages/bsp/gateway-dk/leds-lp5812.c b/packages/bsp/gateway-dk/leds-lp5812.c new file mode 100644 index 000000000000..d3657ba9d987 --- /dev/null +++ b/packages/bsp/gateway-dk/leds-lp5812.c @@ -0,0 +1,730 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * LP5812 LED driver + * + * Copyright (C) 2025 Texas Instruments + * + * Author: Jared Zhou + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "leds-lp5812.h" + +static const struct lp5812_mode_mapping chip_mode_map[] = { + {"direct_mode", 0, 0, 0, 0, 0, 0}, + {"tcm:1:0", 1, 0, 0, 0, 0, 0}, + {"tcm:1:1", 1, 1, 0, 0, 0, 0}, + {"tcm:1:2", 1, 2, 0, 0, 0, 0}, + {"tcm:1:3", 1, 3, 0, 0, 0, 0}, + {"tcm:2:0:1", 2, 0, 1, 0, 0, 0}, + {"tcm:2:0:2", 2, 0, 2, 0, 0, 0}, + {"tcm:2:0:3", 2, 0, 3, 0, 0, 0}, + {"tcm:2:1:2", 2, 1, 2, 0, 0, 0}, + {"tcm:2:1:3", 2, 1, 3, 0, 0, 0}, + {"tcm:2:2:3", 2, 2, 3, 0, 0, 0}, + {"tcm:3:0:1:2", 3, 0, 1, 2, 0, 0}, + {"tcm:3:0:1:3", 3, 0, 1, 3, 0, 0}, + {"tcm:3:0:2:3", 3, 0, 2, 3, 0, 0}, + {"tcm:4:0:1:2:3", 4, 0, 1, 2, 3, 0}, + {"mix:1:0:1", 5, 1, 0, 0, 0, 0}, + {"mix:1:0:2", 5, 2, 0, 0, 0, 0}, + {"mix:1:0:3", 5, 3, 0, 0, 0, 0}, + {"mix:1:1:0", 5, 0, 0, 0, 0, 1}, + {"mix:1:1:2", 5, 2, 0, 0, 0, 1}, + {"mix:1:1:3", 5, 3, 0, 0, 0, 1}, + {"mix:1:2:0", 5, 0, 0, 0, 0, 2}, + {"mix:1:2:1", 5, 1, 0, 0, 0, 2}, + {"mix:1:2:3", 5, 3, 0, 0, 0, 2}, + {"mix:1:3:0", 5, 0, 0, 0, 0, 3}, + {"mix:1:3:1", 5, 1, 0, 0, 0, 3}, + {"mix:1:3:2", 5, 2, 0, 0, 0, 3}, + {"mix:2:0:1:2", 6, 1, 2, 0, 0, 0}, + {"mix:2:0:1:3", 6, 1, 3, 0, 0, 0}, + {"mix:2:0:2:3", 6, 2, 3, 0, 0, 0}, + {"mix:2:1:0:2", 6, 0, 2, 0, 0, 1}, + {"mix:2:1:0:3", 6, 0, 3, 0, 0, 1}, + {"mix:2:1:2:3", 6, 2, 3, 0, 0, 1}, + {"mix:2:2:0:1", 6, 0, 1, 0, 0, 2}, + {"mix:2:2:0:3", 6, 0, 3, 0, 0, 2}, + {"mix:2:2:1:3", 6, 1, 3, 0, 0, 2}, + {"mix:2:3:0:1", 6, 0, 1, 0, 0, 3}, + {"mix:2:3:0:2", 6, 0, 2, 0, 0, 3}, + {"mix:2:3:1:2", 6, 1, 2, 0, 0, 3}, + {"mix:3:0:1:2:3", 7, 1, 2, 3, 0, 0}, + {"mix:3:1:0:2:3", 7, 0, 2, 3, 0, 1}, + {"mix:3:2:0:1:3", 7, 0, 1, 3, 0, 2}, + {"mix:3:3:0:1:2", 7, 0, 1, 2, 0, 3} +}; + +static int lp5812_write(struct lp5812_chip *chip, u16 reg, u8 val) +{ + struct device *dev = &chip->client->dev; + struct i2c_msg msg; + u8 buf[LP5812_DATA_LENGTH]; + u8 reg_addr_bit8_9; + int ret; + + /* Extract register address bits 9 and 8 for Address Byte 1 */ + reg_addr_bit8_9 = (reg >> LP5812_REG_ADDR_HIGH_SHIFT) & LP5812_REG_ADDR_BIT_8_9_MASK; + + /* Prepare payload: Address Byte 2 (bits [7:0]) and value to write */ + buf[LP5812_DATA_BYTE_0_IDX] = (u8)(reg & LP5812_REG_ADDR_LOW_MASK); + buf[LP5812_DATA_BYTE_1_IDX] = val; + + /* Construct I2C message for a write operation */ + msg.addr = (chip->client->addr << LP5812_CHIP_ADDR_SHIFT) | reg_addr_bit8_9; + msg.flags = 0; + msg.len = sizeof(buf); + msg.buf = buf; + + ret = i2c_transfer(chip->client->adapter, &msg, 1); + if (ret == 1) + return 0; + + dev_err(dev, "I2C write error, ret=%d\n", ret); + return ret < 0 ? ret : -EIO; +} + +static int lp5812_read(struct lp5812_chip *chip, u16 reg, u8 *val) +{ + struct device *dev = &chip->client->dev; + struct i2c_msg msgs[LP5812_READ_MSG_LENGTH]; + u8 ret_val; + u8 reg_addr_bit8_9; + u8 converted_reg; + int ret; + + /* Extract register address bits 9 and 8 for Address Byte 1 */ + reg_addr_bit8_9 = (reg >> LP5812_REG_ADDR_HIGH_SHIFT) & LP5812_REG_ADDR_BIT_8_9_MASK; + + /* Lower 8 bits go in Address Byte 2 */ + converted_reg = (u8)(reg & LP5812_REG_ADDR_LOW_MASK); + + /* Prepare I2C write message to set register address */ + msgs[LP5812_MSG_0_IDX].addr = + (chip->client->addr << LP5812_CHIP_ADDR_SHIFT) | reg_addr_bit8_9; + msgs[LP5812_MSG_0_IDX].flags = 0; + msgs[LP5812_MSG_0_IDX].len = 1; + msgs[LP5812_MSG_0_IDX].buf = &converted_reg; + + /* Prepare I2C read message to retrieve register value */ + msgs[LP5812_MSG_1_IDX].addr = + (chip->client->addr << LP5812_CHIP_ADDR_SHIFT) | reg_addr_bit8_9; + msgs[LP5812_MSG_1_IDX].flags = I2C_M_RD; + msgs[LP5812_MSG_1_IDX].len = 1; + msgs[LP5812_MSG_1_IDX].buf = &ret_val; + + ret = i2c_transfer(chip->client->adapter, msgs, LP5812_READ_MSG_LENGTH); + if (ret == LP5812_READ_MSG_LENGTH) { + *val = ret_val; + return 0; + } + + dev_err(dev, "I2C read error, ret=%d\n", ret); + *val = 0; + return ret < 0 ? ret : -EIO; +} + +static int lp5812_read_tsd_config_status(struct lp5812_chip *chip, u8 *reg_val) +{ + return lp5812_read(chip, chip->cfg->reg_tsd_config_status.addr, reg_val); +} + +static int lp5812_update_regs_config(struct lp5812_chip *chip) +{ + u8 reg_val; + int ret; + + ret = lp5812_write(chip, chip->cfg->reg_cmd_update.addr, LP5812_UPDATE_CMD_VAL); + if (ret) + return ret; + + ret = lp5812_read_tsd_config_status(chip, ®_val); + if (ret) + return ret; + + return reg_val & LP5812_CFG_ERR_STATUS_MASK; +} + +static ssize_t parse_drive_mode(struct lp5812_chip *chip, const char *str) +{ + int i; + + chip->u_drive_mode.s_drive_mode.mix_sel_led_0 = false; + chip->u_drive_mode.s_drive_mode.mix_sel_led_1 = false; + chip->u_drive_mode.s_drive_mode.mix_sel_led_2 = false; + chip->u_drive_mode.s_drive_mode.mix_sel_led_3 = false; + + if (sysfs_streq(str, LP5812_MODE_DIRECT_NAME)) { + chip->u_drive_mode.s_drive_mode.led_mode = LP5812_MODE_DIRECT_VALUE; + return 0; + } + + for (i = 0; i < ARRAY_SIZE(chip_mode_map); i++) { + if (sysfs_streq(str, chip_mode_map[i].mode_name)) { + chip->u_drive_mode.s_drive_mode.led_mode = chip_mode_map[i].mode; + chip->u_scan_order.s_scan_order.scan_order_0 = + chip_mode_map[i].scan_order_0; + chip->u_scan_order.s_scan_order.scan_order_1 = + chip_mode_map[i].scan_order_1; + chip->u_scan_order.s_scan_order.scan_order_2 = + chip_mode_map[i].scan_order_2; + chip->u_scan_order.s_scan_order.scan_order_3 = + chip_mode_map[i].scan_order_3; + + switch (chip_mode_map[i].selection_led) { + case LP5812_MODE_MIX_SELECT_LED_0: + chip->u_drive_mode.s_drive_mode.mix_sel_led_0 = true; + break; + case LP5812_MODE_MIX_SELECT_LED_1: + chip->u_drive_mode.s_drive_mode.mix_sel_led_1 = true; + break; + case LP5812_MODE_MIX_SELECT_LED_2: + chip->u_drive_mode.s_drive_mode.mix_sel_led_2 = true; + break; + case LP5812_MODE_MIX_SELECT_LED_3: + chip->u_drive_mode.s_drive_mode.mix_sel_led_3 = true; + break; + default: + return -EINVAL; + } + + return 0; + } + } + + return -EINVAL; +} + +static int lp5812_set_drive_mode_scan_order(struct lp5812_chip *chip) +{ + u8 val; + int ret; + + /* Set led mode */ + val = chip->u_drive_mode.drive_mode_val; + ret = lp5812_write(chip, chip->cfg->reg_dev_config_1.addr, val); + if (ret) + return ret; + + /* Setup scan order */ + val = chip->u_scan_order.scan_order_val; + ret = lp5812_write(chip, chip->cfg->reg_dev_config_2.addr, val); + + return ret; +} + +static int lp5812_set_led_mode(struct lp5812_chip *chip, int led_number, + enum control_mode mode) +{ + u8 reg_val; + u16 reg; + int ret; + + if (led_number < LP5812_NUMBER_LED_IN_REG) + reg = chip->cfg->reg_dev_config_3.addr; + else + reg = chip->cfg->reg_dev_config_4.addr; + + ret = lp5812_read(chip, reg, ®_val); + if (ret) + return ret; + + if (mode == LP5812_MODE_MANUAL) + reg_val &= ~(1 << (led_number % LP5812_NUMBER_LED_IN_REG)); + else + reg_val |= (1 << (led_number % LP5812_NUMBER_LED_IN_REG)); + + ret = lp5812_write(chip, reg, reg_val); + if (ret) + return ret; + + ret = lp5812_update_regs_config(chip); + + return ret; +} + +static int lp5812_manual_dc_pwm_control(struct lp5812_chip *chip, int led_number, + u8 val, enum dimming_type dimming_type) +{ + u16 led_base_reg; + int ret; + + if (dimming_type == LP5812_DIMMING_ANALOG) + led_base_reg = chip->cfg->reg_manual_dc_base.addr; + else + led_base_reg = chip->cfg->reg_manual_pwm_base.addr; + ret = lp5812_write(chip, led_base_reg + led_number, val); + + return ret; +} + +static int lp5812_auto_dc(struct lp5812_chip *chip, + int led_number, u8 val) +{ + return lp5812_write(chip, chip->cfg->reg_auto_dc_base.addr + led_number, val); +} + +static int lp5812_multicolor_brightness(struct lp5812_led *led) +{ + int ret, i; + struct lp5812_chip *chip = led->chip; + + guard(mutex)(&chip->lock); + for (i = 0; i < led->mc_cdev.num_colors; i++) { + ret = lp5812_manual_dc_pwm_control(chip, led->mc_cdev.subled_info[i].channel, + led->mc_cdev.subled_info[i].brightness, + LP5812_DIMMING_PWM); + if (ret) + return ret; + } + + return 0; +} + +static int lp5812_led_brightness(struct lp5812_led *led) +{ + struct lp5812_chip *chip = led->chip; + struct lp5812_led_config *led_cfg; + int ret; + + led_cfg = &chip->led_config[led->chan_nr]; + + guard(mutex)(&chip->lock); + ret = lp5812_manual_dc_pwm_control(chip, led_cfg->led_id[0], + led->brightness, LP5812_DIMMING_PWM); + + return ret; +} + +static int lp5812_set_brightness(struct led_classdev *cdev, + enum led_brightness brightness) +{ + struct lp5812_led *led = container_of(cdev, struct lp5812_led, cdev); + + led->brightness = (u8)brightness; + return lp5812_led_brightness(led); +} + +static int lp5812_set_mc_brightness(struct led_classdev *cdev, + enum led_brightness brightness) +{ + struct led_classdev_mc *mc_dev = lcdev_to_mccdev(cdev); + struct lp5812_led *led = container_of(mc_dev, struct lp5812_led, mc_cdev); + + led_mc_calc_color_components(&led->mc_cdev, brightness); + return lp5812_multicolor_brightness(led); +} + +static int lp5812_init_led(struct lp5812_led *led, struct lp5812_chip *chip, int chan) +{ + struct device *dev = &chip->client->dev; + struct mc_subled *mc_led_info; + struct led_classdev *led_cdev; + int i, ret; + + if (chip->led_config[chan].name) { + led->cdev.name = chip->led_config[chan].name; + } else { + led->cdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s:channel%d", + chip->label ? : chip->client->name, chan); + if (!led->cdev.name) + return -ENOMEM; + } + + if (!chip->led_config[chan].is_sc_led) { + mc_led_info = devm_kcalloc(dev, + chip->led_config[chan].num_colors, + sizeof(*mc_led_info), GFP_KERNEL); + if (!mc_led_info) + return -ENOMEM; + + led_cdev = &led->mc_cdev.led_cdev; + led_cdev->name = led->cdev.name; + led_cdev->brightness_set_blocking = lp5812_set_mc_brightness; + led->mc_cdev.num_colors = chip->led_config[chan].num_colors; + for (i = 0; i < led->mc_cdev.num_colors; i++) { + mc_led_info[i].color_index = + chip->led_config[chan].color_id[i]; + mc_led_info[i].channel = + chip->led_config[chan].led_id[i]; + } + + led->mc_cdev.subled_info = mc_led_info; + } else { + led->cdev.brightness_set_blocking = lp5812_set_brightness; + } + + led->chan_nr = chan; + + if (chip->led_config[chan].is_sc_led) { + ret = devm_led_classdev_register(dev, &led->cdev); + if (ret == 0) + led->cdev.dev->platform_data = led; + } else { + ret = devm_led_classdev_multicolor_register(dev, &led->mc_cdev); + if (ret == 0) + led->mc_cdev.led_cdev.dev->platform_data = led; + } + + return ret; +} + +static int lp5812_register_leds(struct lp5812_led *led, struct lp5812_chip *chip) +{ + struct lp5812_led *each; + int num_channels = chip->num_channels; + u8 reg_val; + u16 reg; + int ret, i, j; + + for (i = 0; i < num_channels; i++) { + each = led + i; + ret = lp5812_init_led(each, chip, i); + if (ret) + goto err_init_led; + + each->chip = chip; + + for (j = 0; j < chip->led_config[i].num_colors; j++) { + ret = lp5812_auto_dc(chip, chip->led_config[i].led_id[j], + chip->led_config[i].max_current[j]); + if (ret) + goto err_init_led; + + ret = lp5812_manual_dc_pwm_control(chip, chip->led_config[i].led_id[j], + chip->led_config[i].max_current[j], + LP5812_DIMMING_ANALOG); + if (ret) + goto err_init_led; + + ret = lp5812_set_led_mode(chip, chip->led_config[i].led_id[j], + LP5812_MODE_MANUAL); + if (ret) + goto err_init_led; + + reg = (chip->led_config[i].led_id[j] < LP5812_NUMBER_LED_IN_REG) ? + chip->cfg->reg_led_en_1.addr : + chip->cfg->reg_led_en_2.addr; + + ret = lp5812_read(chip, reg, ®_val); + if (ret) + goto err_init_led; + + reg_val |= (1 << (chip->led_config[i].led_id[j] % + LP5812_NUMBER_LED_IN_REG)); + + ret = lp5812_write(chip, reg, reg_val); + if (ret) + goto err_init_led; + } + } + + return 0; + +err_init_led: + return ret; +} + +static int lp5812_init_device(struct lp5812_chip *chip) +{ + int ret; + + usleep_range(LP5812_WAIT_DEVICE_STABLE_MIN, LP5812_WAIT_DEVICE_STABLE_MAX); + + ret = lp5812_write(chip, chip->cfg->reg_chip_en.addr, (u8)1); + if (ret) { + dev_err(&chip->client->dev, "lp5812_enable_disable failed\n"); + return ret; + } + + ret = lp5812_write(chip, chip->cfg->reg_dev_config_12.addr, LP5812_LSD_LOD_START_UP); + if (ret) { + dev_err(&chip->client->dev, "write 0x0B to DEV_CONFIG12 failed\n"); + return ret; + } + + ret = parse_drive_mode(chip, chip->scan_mode); + if (ret) + return ret; + + ret = lp5812_set_drive_mode_scan_order(chip); + if (ret) + return ret; + + ret = lp5812_update_regs_config(chip); + if (ret) { + dev_err(&chip->client->dev, "lp5812_update_regs_config failed\n"); + return ret; + } + + return 0; +} + +static void lp5812_deinit_device(struct lp5812_chip *chip) +{ + lp5812_write(chip, chip->cfg->reg_led_en_1.addr, 0); + lp5812_write(chip, chip->cfg->reg_led_en_2.addr, 0); + lp5812_write(chip, chip->cfg->reg_chip_en.addr, 0); +} + +static int lp5812_parse_led_channel(struct device_node *np, + struct lp5812_led_config *cfg, + int color_number) +{ + int color_id = 0, reg, ret; + u32 max_cur = 0; + + ret = of_property_read_u32(np, "reg", ®); + if (ret) + return ret; + + cfg->led_id[color_number] = reg; + + of_property_read_u32(np, "led-max-microamp", &max_cur); + cfg->max_current[color_number] = max_cur / 100; + + of_property_read_u32(np, "color", &color_id); + cfg->color_id[color_number] = color_id; + + return 0; +} + +static int lp5812_parse_led(struct device_node *np, + struct lp5812_led_config *cfg, + int led_index) +{ + int num_colors = 0, ret; + + of_property_read_string(np, "label", &cfg[led_index].name); + + ret = of_property_read_u32(np, "reg", &cfg[led_index].chan_nr); + if (ret) + return ret; + + for_each_available_child_of_node_scoped(np, child) { + ret = lp5812_parse_led_channel(child, &cfg[led_index], num_colors); + if (ret) + return ret; + num_colors++; + } + + if (num_colors == 0) { + ret = lp5812_parse_led_channel(np, &cfg[led_index], 0); + if (ret) + return ret; + num_colors = 1; + cfg[led_index].is_sc_led = true; + } else { + cfg[led_index].is_sc_led = false; + } + + cfg[led_index].num_colors = num_colors; + + return 0; +} + +static int lp5812_of_populate_pdata(struct device *dev, + struct device_node *np, + struct lp5812_chip *chip) +{ + struct lp5812_led_config *cfg; + int num_channels, i = 0, ret; + + num_channels = of_get_available_child_count(np); + if (num_channels == 0) { + dev_err(dev, "no LED channels\n"); + return -EINVAL; + } + + cfg = devm_kcalloc(dev, num_channels, sizeof(*cfg), GFP_KERNEL); + if (!cfg) + return -ENOMEM; + + chip->led_config = &cfg[0]; + chip->num_channels = num_channels; + + for_each_available_child_of_node_scoped(np, child) { + ret = lp5812_parse_led(child, cfg, i); + if (ret) + return -EINVAL; + i++; + } + + ret = of_property_read_string(np, "ti,scan-mode", &chip->scan_mode); + if (ret) + chip->scan_mode = LP5812_MODE_DIRECT_NAME; + + of_property_read_string(np, "label", &chip->label); + + return 0; +} + +static int lp5812_probe(struct i2c_client *client) +{ + struct lp5812_chip *chip; + struct device_node *np = dev_of_node(&client->dev); + struct lp5812_led *led; + int ret; + + if (!np) + return -EINVAL; + + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->cfg = i2c_get_match_data(client); + ret = lp5812_of_populate_pdata(&client->dev, np, chip); + if (ret) + return ret; + + led = devm_kcalloc(&client->dev, chip->num_channels, sizeof(*led), GFP_KERNEL); + if (!led) + return -ENOMEM; + + chip->client = client; + mutex_init(&chip->lock); + i2c_set_clientdata(client, led); + + ret = lp5812_init_device(chip); + if (ret) + return ret; + + ret = lp5812_register_leds(led, chip); + if (ret) + goto err_out; + + return 0; + +err_out: + lp5812_deinit_device(chip); + return ret; +} + +static void lp5812_remove(struct i2c_client *client) +{ + struct lp5812_led *led = i2c_get_clientdata(client); + + lp5812_deinit_device(led->chip); +} + +/* Chip specific configurations */ +static const struct lp5812_device_config lp5812_cfg = { + .reg_reset = { + .addr = LP5812_REG_RESET, + .val = LP5812_RESET + }, + .reg_chip_en = { + .addr = LP5812_REG_ENABLE, + .val = LP5812_ENABLE_DEFAULT + }, + .reg_dev_config_0 = { + .addr = LP5812_DEV_CONFIG0, + .val = 0 + }, + .reg_dev_config_1 = { + .addr = LP5812_DEV_CONFIG1, + .val = 0 + }, + .reg_dev_config_2 = { + .addr = LP5812_DEV_CONFIG2, + .val = 0 + }, + .reg_dev_config_3 = { + .addr = LP5812_DEV_CONFIG3, + .val = 0 + }, + .reg_dev_config_4 = { + .addr = LP5812_DEV_CONFIG4, + .val = 0 + }, + .reg_dev_config_5 = { + .addr = LP5812_DEV_CONFIG5, + .val = 0 + }, + .reg_dev_config_6 = { + .addr = LP5812_DEV_CONFIG6, + .val = 0 + }, + .reg_dev_config_7 = { + .addr = LP5812_DEV_CONFIG7, + .val = 0 + }, + .reg_dev_config_12 = { + .addr = LP5812_DEV_CONFIG12, + .val = LP5812_DEV_CONFIG12_DEFAULT + }, + .reg_cmd_update = { + .addr = LP5812_CMD_UPDATE, + .val = 0 + }, + .reg_tsd_config_status = { + .addr = LP5812_TSD_CONFIG_STATUS, + .val = 0 + }, + .reg_led_en_1 = { + .addr = LP5812_LED_EN_1, + .val = 0 + }, + .reg_led_en_2 = { + .addr = LP5812_LED_EN_2, + .val = 0 + }, + .reg_fault_clear = { + .addr = LP5812_FAULT_CLEAR, + .val = 0 + }, + .reg_manual_dc_base = { + .addr = LP5812_MANUAL_DC_BASE, + .val = 0 + }, + .reg_auto_dc_base = { + .addr = LP5812_AUTO_DC_BASE, + .val = 0 + }, + .reg_manual_pwm_base = { + .addr = LP5812_MANUAL_PWM_BASE, + .val = 0 + }, + .reg_lod_status_base = { + .addr = LP5812_LOD_STATUS, + .val = 0 + }, + .reg_lsd_status_base = { + .addr = LP5812_LSD_STATUS, + .val = 0 + } +}; + +static const struct of_device_id of_lp5812_match[] = { + { .compatible = "ti,lp5812", .data = &lp5812_cfg }, + {/* NULL */} +}; + +MODULE_DEVICE_TABLE(of, of_lp5812_match); + +static struct i2c_driver lp5812_driver = { + .driver = { + .name = "lp5812", + .of_match_table = of_lp5812_match, + }, + .probe = lp5812_probe, + .remove = lp5812_remove, +}; + +module_i2c_driver(lp5812_driver); + +MODULE_DESCRIPTION("Texas Instruments LP5812 LED Driver"); +MODULE_AUTHOR("Jared Zhou"); +MODULE_LICENSE("GPL"); diff --git a/packages/bsp/gateway-dk/leds-lp5812.h b/packages/bsp/gateway-dk/leds-lp5812.h new file mode 100644 index 000000000000..59af1ccfe41b --- /dev/null +++ b/packages/bsp/gateway-dk/leds-lp5812.h @@ -0,0 +1,197 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * LP5812 Driver Header + * + * Copyright (C) 2025 Texas Instruments + * + * Author: Jared Zhou + */ + +#ifndef _LP5812_H_ +#define _LP5812_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define LP5812_REG_ENABLE 0x0000 +#define LP5812_REG_RESET 0x0023 +#define LP5812_DEV_CONFIG0 0x0001 +#define LP5812_DEV_CONFIG1 0x0002 +#define LP5812_DEV_CONFIG2 0x0003 +#define LP5812_DEV_CONFIG3 0x0004 +#define LP5812_DEV_CONFIG4 0x0005 +#define LP5812_DEV_CONFIG5 0x0006 +#define LP5812_DEV_CONFIG6 0x0007 +#define LP5812_DEV_CONFIG7 0x0008 +#define LP5812_DEV_CONFIG8 0x0009 +#define LP5812_DEV_CONFIG9 0x000A +#define LP5812_DEV_CONFIG10 0x000B +#define LP5812_DEV_CONFIG11 0x000c +#define LP5812_DEV_CONFIG12 0x000D +#define LP5812_CMD_UPDATE 0x0010 +#define LP5812_LED_EN_1 0x0020 +#define LP5812_LED_EN_2 0x0021 +#define LP5812_FAULT_CLEAR 0x0022 +#define LP5812_MANUAL_DC_BASE 0x0030 +#define LP5812_AUTO_DC_BASE 0x0050 +#define LP5812_MANUAL_PWM_BASE 0x0040 + +#define LP5812_TSD_CONFIG_STATUS 0x0300 +#define LP5812_LOD_STATUS 0x0301 +#define LP5812_LSD_STATUS 0x0303 + +#define LP5812_ENABLE_DEFAULT 0x01 +#define FAULT_CLEAR_ALL 0x07 +#define TSD_CLEAR_VAL 0x04 +#define LSD_CLEAR_VAL 0x02 +#define LOD_CLEAR_VAL 0x01 +#define LP5812_RESET 0x66 +#define LP5812_DEV_CONFIG12_DEFAULT 0x08 + +#define LP5812_UPDATE_CMD_VAL 0x55 +#define LP5812_REG_ADDR_HIGH_SHIFT 8 +#define LP5812_REG_ADDR_BIT_8_9_MASK 0x03 +#define LP5812_REG_ADDR_LOW_MASK 0xFF +#define LP5812_CHIP_ADDR_SHIFT 0 /* no address shift for LP5810 */ +#define LP5812_DATA_LENGTH 2 +#define LP5812_DATA_BYTE_0_IDX 0 +#define LP5812_DATA_BYTE_1_IDX 1 + +#define LP5812_READ_MSG_LENGTH 2 +#define LP5812_MSG_0_IDX 0 +#define LP5812_MSG_1_IDX 1 +#define LP5812_CFG_ERR_STATUS_MASK 0x01 +#define LP5812_CFG_TSD_STATUS_SHIFT 1 +#define LP5812_CFG_TSD_STATUS_MASK 0x01 + +#define LP5812_FAULT_CLEAR_LOD 0 +#define LP5812_FAULT_CLEAR_LSD 1 +#define LP5812_FAULT_CLEAR_TSD 2 +#define LP5812_FAULT_CLEAR_ALL 3 +#define LP5812_NUMBER_LED_IN_REG 8 + +#define LP5812_WAIT_DEVICE_STABLE_MIN 1000 +#define LP5812_WAIT_DEVICE_STABLE_MAX 1100 + +#define LP5812_LSD_LOD_START_UP 0x0B +#define LP5812_MODE_NAME_MAX_LEN 20 +#define LP5812_MODE_DIRECT_NAME "direct_mode" +#define LP5812_MODE_DIRECT_VALUE 0 +#define LP5812_MODE_MIX_SELECT_LED_0 0 +#define LP5812_MODE_MIX_SELECT_LED_1 1 +#define LP5812_MODE_MIX_SELECT_LED_2 2 +#define LP5812_MODE_MIX_SELECT_LED_3 3 + +enum control_mode { + LP5812_MODE_MANUAL = 0, + LP5812_MODE_AUTONOMOUS +}; + +enum dimming_type { + LP5812_DIMMING_ANALOG, + LP5812_DIMMING_PWM +}; + +union u_scan_order { + struct { + u8 scan_order_0:2; + u8 scan_order_1:2; + u8 scan_order_2:2; + u8 scan_order_3:2; + } s_scan_order; + u8 scan_order_val; +}; + +union u_drive_mode { + struct { + u8 mix_sel_led_0:1; + u8 mix_sel_led_1:1; + u8 mix_sel_led_2:1; + u8 mix_sel_led_3:1; + u8 led_mode:3; + u8 pwm_fre:1; + } s_drive_mode; + u8 drive_mode_val; +}; + +struct lp5812_reg { + u16 addr; + union { + u8 val; + u8 mask; + u8 shift; + }; +}; + +struct lp5812_mode_mapping { + char mode_name[LP5812_MODE_NAME_MAX_LEN]; + u8 mode; + u8 scan_order_0; + u8 scan_order_1; + u8 scan_order_2; + u8 scan_order_3; + u8 selection_led; +}; + +struct lp5812_led_config { + bool is_sc_led; + const char *name; + u8 color_id[LED_COLOR_ID_MAX]; + u32 max_current[LED_COLOR_ID_MAX]; + int chan_nr; + int num_colors; + int led_id[LED_COLOR_ID_MAX]; +}; + +struct lp5812_chip { + u8 num_channels; + struct i2c_client *client; + struct mutex lock; /* Protects register access */ + struct lp5812_led_config *led_config; + const char *label; + const char *scan_mode; + const struct lp5812_device_config *cfg; + union u_scan_order u_scan_order; + union u_drive_mode u_drive_mode; +}; + +struct lp5812_led { + u8 brightness; + int chan_nr; + struct led_classdev cdev; + struct led_classdev_mc mc_cdev; + struct lp5812_chip *chip; +}; + +struct lp5812_device_config { + const struct lp5812_reg reg_reset; + const struct lp5812_reg reg_chip_en; + const struct lp5812_reg reg_dev_config_0; + const struct lp5812_reg reg_dev_config_1; + const struct lp5812_reg reg_dev_config_2; + const struct lp5812_reg reg_dev_config_3; + const struct lp5812_reg reg_dev_config_4; + const struct lp5812_reg reg_dev_config_5; + const struct lp5812_reg reg_dev_config_6; + const struct lp5812_reg reg_dev_config_7; + const struct lp5812_reg reg_dev_config_12; + const struct lp5812_reg reg_cmd_update; + + const struct lp5812_reg reg_led_en_1; + const struct lp5812_reg reg_led_en_2; + const struct lp5812_reg reg_fault_clear; + const struct lp5812_reg reg_manual_dc_base; + const struct lp5812_reg reg_auto_dc_base; + const struct lp5812_reg reg_manual_pwm_base; + const struct lp5812_reg reg_tsd_config_status; + const struct lp5812_reg reg_lod_status_base; + const struct lp5812_reg reg_lsd_status_base; +}; + +#endif /*_LP5812_H_*/ \ No newline at end of file diff --git a/packages/bsp/gateway-dk/leds-lp5812.mk b/packages/bsp/gateway-dk/leds-lp5812.mk new file mode 100644 index 000000000000..8e70bff1932b --- /dev/null +++ b/packages/bsp/gateway-dk/leds-lp5812.mk @@ -0,0 +1,12 @@ +obj-m := leds-lp5812.o + +ccflags-y := -I$(src) + +all: + $(MAKE) -C $(KERNEL_SRC) M=$(PWD) modules + +modules_install: + $(MAKE) -C $(KERNEL_SRC) M=$(PWD) modules_install + +clean: + $(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean diff --git a/packages/bsp/gateway-dk/sfp-led.c b/packages/bsp/gateway-dk/sfp-led.c new file mode 100644 index 000000000000..8dde4456f284 --- /dev/null +++ b/packages/bsp/gateway-dk/sfp-led.c @@ -0,0 +1,666 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * SFP LED Control Platform Driver (Passive Monitor) + * + * Controls SFP port LEDs based on module presence and link state. + * This driver passively monitors I2C and netdev state without interfering + * with the SFP subsystem or MAC driver. + * + * Design principle: + * This driver does NOT interact with the kernel's SFP state machine. + * This avoids conflicts with MAC drivers that use fixed-link configuration + * (like NXP DPAA SDK). + * + * Detection method: + * - Module presence: Probe I2C EEPROM at 0x50 + * - Link state: Check netdev operstate (for DAC) or I2C DDM (for fiber) + * - Activity: Poll netdev tx/rx packet counters + * + * LED behavior: + * + * State | Green (Link) | Orange (Activity) + * ---------------------------|--------------|------------------- + * No module | OFF | OFF + * Module present, no link | OFF | ON (solid) + * Module present, link up | ON | Blinks on traffic + * + * Module type detection: + * - Fiber SFP: Uses I2C DDM (A2h byte 110 LOS bit) for link detection + * - DAC cable: Uses netdev operstate (DAC has no DDM support) + * - Detection via A0h page bytes 3 and 8 copper compliance bits + * + * Device tree binding example: + * + * sfp0: sfp-0 { + * compatible = "sff,sfp"; + * i2c-bus = <&sfp0_i2c>; + * leds = <&led_sfp0_link>, <&led_sfp0_activity>; + * }; + * + * sfp-led-controller { + * compatible = "mono,sfp-led"; + * sfp-ports = <&sfp0>, <&sfp1>; + * }; + * + * // MAC node must reference SFP for netdev association + * &fman_mac { + * sfp = <&sfp0>; + * }; + * + * Copyright 2026 Mono Technologies Inc. + * Author: Tomaz Zaman + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "sfp-led" +#define SFP_LED_NAME_SIZE 64 + +/* Polling interval in milliseconds */ +#define SFP_LED_POLL_INTERVAL_MS 100 +#define SFP_LED_NETDEV_RETRY_MS 1000 +#define SFP_LED_MAX_NETDEV_RETRIES 30 + +/* SFP I2C addresses per SFP MSA */ +#define SFP_EEPROM_ADDR 0x50 /* A0h page - module ID/capabilities */ +#define SFP_DIAG_ADDR 0x51 /* A2h page - diagnostics/status */ + +/* SFP A2h page registers */ +#define SFP_STATUS_CTRL_REG 110 /* Status/Control register */ +#define SFP_STATUS_LOS BIT(1) /* RX Loss of Signal */ +#define SFP_STATUS_TX_FAULT BIT(2) /* TX Fault */ + +/* SFP A0h page - cable type detection (per SFP MSA) */ +#define SFP_PHYS_EXT_ID 1 /* Extended identifier */ +#define SFP_COMPLIANCE_3 3 /* 10G/1G Ethernet compliance */ +#define SFP_COMPLIANCE_8 8 /* SFP+ cable technology */ +#define SFP_8472_COMPLIANCE 94 /* SFF-8472 compliance (DDM support) */ + +/* Byte 3 bits - 1G Ethernet copper compliance */ +#define SFP_IF_1X_COPPER_PASSIVE BIT(0) +#define SFP_IF_1X_COPPER_ACTIVE BIT(1) + +/* Byte 8 bits - SFP+ cable technology */ +#define SFP_CT_PASSIVE BIT(2) /* Passive cable */ +#define SFP_CT_ACTIVE BIT(3) /* Active cable */ + +struct sfp_led_port { + struct sfp_led_priv *priv; + struct device_node *sfp_np; + struct i2c_adapter *i2c_adapter; /* I2C bus for module detection */ + struct net_device *netdev; + char netdev_name[IFNAMSIZ]; + + struct led_classdev *link_led; + struct led_classdev *activity_led; + + char link_led_name[SFP_LED_NAME_SIZE]; + char activity_led_name[SFP_LED_NAME_SIZE]; + + struct delayed_work poll_work; + int netdev_retries; + int debug_count; /* Rate limit debug output */ + + /* Cached state for change detection */ + bool last_module_present; + bool last_carrier; + bool is_dac; /* True if DAC cable (no DDM support) */ + u64 last_tx_packets; + u64 last_rx_packets; + bool activity_led_on; +}; + +struct sfp_led_priv { + struct device *dev; + int num_ports; + struct sfp_led_port *ports; +}; + +/* + * Find the netdev associated with an SFP by traversing device tree. + * + * DPAA device tree structure: + * fsldpaa/ethernet@8 (fsl,dpa-ethernet) -> fsl,fman-mac = <&enet6> + * fman0/ethernet@f0000 (enet6) -> sfp = <&sfp_xfi0> + */ +static struct net_device *sfp_led_find_netdev(struct device_node *sfp_np) +{ + struct net_device *dev, *found = NULL; + + if (!sfp_np) + return NULL; + + /* + * Use rtnl_trylock to avoid deadlock: this is called from a + * workqueue, and networking teardown can flush the system workqueue + * while holding rtnl_lock. If we can't get the lock, the caller + * will retry on the next poll cycle. + */ + if (!rtnl_trylock()) + return NULL; + + for_each_netdev(&init_net, dev) { + struct device *parent = dev->dev.parent; + struct device_node *dpaa_node, *mac_node, *sfp_ref; + + if (!parent || !parent->of_node) + continue; + + dpaa_node = parent->of_node; + + mac_node = of_parse_phandle(dpaa_node, "fsl,fman-mac", 0); + if (!mac_node) + continue; + + sfp_ref = of_parse_phandle(mac_node, "sfp", 0); + of_node_put(mac_node); + + if (sfp_ref == sfp_np) { + of_node_put(sfp_ref); + found = dev; + dev_hold(found); + break; + } + of_node_put(sfp_ref); + } + + rtnl_unlock(); + + return found; +} + +/* + * Detect SFP module presence by probing I2C EEPROM at address 0x50. + * All SFP/SFP+ modules have an EEPROM that responds to this address. + * Returns true if module is present, false otherwise. + */ +static bool sfp_led_i2c_module_present(struct sfp_led_port *port) +{ + union i2c_smbus_data data; + int ret; + + if (!port->i2c_adapter) + return false; + + /* + * Try to read byte 0 from SFP EEPROM (identifier byte). + * If the read succeeds, a module is present. + */ + ret = i2c_smbus_xfer(port->i2c_adapter, SFP_EEPROM_ADDR, + 0, I2C_SMBUS_READ, 0, + I2C_SMBUS_BYTE_DATA, &data); + + return ret >= 0; +} + +static bool sfp_led_module_present(struct sfp_led_port *port) +{ + return sfp_led_i2c_module_present(port); +} + +/* + * Detect if the SFP module is a DAC (Direct Attach Copper) cable. + * DAC cables don't have optical transceivers and don't support DDM. + * Detection via A0h page compliance bytes per SFP MSA: + * - Byte 3 bits 0-1: 1G copper passive/active + * - Byte 8 bits 2-3: SFP+ cable technology passive/active + * Returns true if DAC cable, false if fiber/optical module. + */ +static bool sfp_led_is_dac_cable(struct sfp_led_port *port) +{ + union i2c_smbus_data data; + int ret; + u8 byte3, byte8; + bool is_dac; + + if (!port->i2c_adapter) + return false; /* Can't detect, assume fiber */ + + /* Read byte 3 - 10G/1G Ethernet compliance */ + ret = i2c_smbus_xfer(port->i2c_adapter, SFP_EEPROM_ADDR, + 0, I2C_SMBUS_READ, SFP_COMPLIANCE_3, + I2C_SMBUS_BYTE_DATA, &data); + if (ret < 0) { + dev_warn(port->priv->dev, "%s: failed to read A0h byte 3: %d\n", + port->link_led_name, ret); + return false; + } + byte3 = data.byte; + + /* Read byte 8 - SFP+ cable technology */ + ret = i2c_smbus_xfer(port->i2c_adapter, SFP_EEPROM_ADDR, + 0, I2C_SMBUS_READ, SFP_COMPLIANCE_8, + I2C_SMBUS_BYTE_DATA, &data); + if (ret < 0) { + dev_warn(port->priv->dev, "%s: failed to read A0h byte 8: %d\n", + port->link_led_name, ret); + return false; + } + byte8 = data.byte; + + /* Check copper compliance bits */ + is_dac = (byte3 & (SFP_IF_1X_COPPER_PASSIVE | SFP_IF_1X_COPPER_ACTIVE)) || + (byte8 & (SFP_CT_PASSIVE | SFP_CT_ACTIVE)); + + dev_dbg(port->priv->dev, "%s: A0h byte3=0x%02x byte8=0x%02x -> %s\n", + port->link_led_name, byte3, byte8, + is_dac ? "DAC cable" : "fiber/optical"); + + return is_dac; +} + +/* + * Read LOS (Loss of Signal) status from SFP module via I2C. + * SFP MSA defines status register at A2h (0x51), byte 110. + * Returns true if signal is lost, false if signal is present. + */ +static bool sfp_led_i2c_los(struct sfp_led_port *port) +{ + union i2c_smbus_data data; + int ret; + if (!port->i2c_adapter) + return true; /* Assume no signal if can't check */ + + ret = i2c_smbus_xfer(port->i2c_adapter, SFP_DIAG_ADDR, + 0, I2C_SMBUS_READ, SFP_STATUS_CTRL_REG, + I2C_SMBUS_BYTE_DATA, &data); + + /* Debug: log every 50th read or on error */ + if (ret < 0) { + if (port->debug_count++ % 50 == 0) + dev_dbg(port->priv->dev, "%s: A2h read failed: %d (no DDM?)\n", + port->link_led_name, ret); + return true; /* Error reading - assume no signal */ + } + + /* Debug: log status byte periodically */ + if (port->debug_count++ % 50 == 0) + dev_dbg(port->priv->dev, "%s: A2h[110]=0x%02x LOS=%d\n", + port->link_led_name, data.byte, + (data.byte & SFP_STATUS_LOS) ? 1 : 0); + + return (data.byte & SFP_STATUS_LOS) != 0; +} + +/* + * Check if interface has operational link. + * For DAC cables with DPAA fixed-link, get_link() is unreliable. + * Use operstate which accurately reflects actual link status. + */ +static bool sfp_led_has_operational_link(struct net_device *netdev) +{ + /* + * operstate reflects actual link status: + * - IF_OPER_UP: interface is up and link is established + * - IF_OPER_DOWN: interface is down or no link + * This is what ethtool uses for "Link detected" field. + */ + return netdev->operstate == IF_OPER_UP; +} + +/* + * Check if we have signal/link. + * For fiber modules: I2C DDM status register (A2h byte 110 LOS bit) + * For DAC cables: operstate (DAC has no DDM support) + * Returns true if link/signal is present. + */ +static bool sfp_led_has_signal(struct sfp_led_port *port) +{ + /* + * DAC cables don't have optical transceivers and don't support DDM. + * The A2h page reads return 0xff which looks like LOS=1. + * For DAC, check operstate which accurately reflects link status, + * unlike get_link()/carrier which may be stale with fixed-link config. + */ + if (port->is_dac) { + if (port->netdev) + return sfp_led_has_operational_link(port->netdev); + return false; + } + + /* Fiber: Use I2C DDM status register (most fiber SFPs support DDM) */ + if (port->i2c_adapter) + return !sfp_led_i2c_los(port); + + /* Last resort: check operstate */ + if (port->netdev) + return sfp_led_has_operational_link(port->netdev); + + return false; +} + +static void sfp_led_set_link(struct sfp_led_port *port, bool on) +{ + if (!port->link_led) + return; + + led_set_brightness(port->link_led, + on ? port->link_led->max_brightness : LED_OFF); +} + +static void sfp_led_set_activity(struct sfp_led_port *port, bool on) +{ + if (!port->activity_led) + return; + + /* Don't override if user has configured a trigger */ + if (port->activity_led->trigger) + return; + + led_set_brightness(port->activity_led, + on ? port->activity_led->max_brightness : LED_OFF); +} + +static void sfp_led_poll_work_handler(struct work_struct *work) +{ + struct sfp_led_port *port = container_of(work, struct sfp_led_port, + poll_work.work); + struct net_device *netdev; + bool module_present, carrier; + struct rtnl_link_stats64 stats; + bool had_activity; + + /* Check module presence via I2C */ + module_present = sfp_led_module_present(port); + + /* Handle module state changes */ + if (module_present != port->last_module_present) { + port->last_module_present = module_present; + + if (!module_present) { + /* Module removed - turn off both LEDs and reset state */ + sfp_led_set_link(port, false); + sfp_led_set_activity(port, false); + port->last_carrier = false; + port->is_dac = false; + dev_dbg(port->priv->dev, "%s: module removed\n", + port->link_led_name); + } else { + /* Module inserted - detect cable type */ + port->is_dac = sfp_led_is_dac_cable(port); + /* Set initial state: module present, no link yet */ + sfp_led_set_link(port, false); + sfp_led_set_activity(port, true); + dev_dbg(port->priv->dev, "%s: module inserted (%s)\n", + port->link_led_name, + port->is_dac ? "DAC" : "fiber"); + } + } + + if (!module_present) + goto reschedule; + + /* Try to find netdev if we don't have one yet */ + netdev = READ_ONCE(port->netdev); + if (!netdev) { + netdev = sfp_led_find_netdev(port->sfp_np); + if (netdev) { + if (cmpxchg(&port->netdev, NULL, netdev) != NULL) { + dev_put(netdev); + } else { + strscpy(port->netdev_name, netdev->name, + sizeof(port->netdev_name)); + dev_dbg(port->priv->dev, "%s: found netdev %s\n", + port->link_led_name, netdev->name); + } + } else { + port->netdev_retries++; + if (port->netdev_retries < SFP_LED_MAX_NETDEV_RETRIES) { + /* Keep activity LED on to show module present */ + sfp_led_set_activity(port, true); + } + } + netdev = READ_ONCE(port->netdev); + } + + if (!netdev) { + /* No netdev yet - show module present only */ + sfp_led_set_link(port, false); + sfp_led_set_activity(port, true); + goto reschedule; + } + + /* Check signal/carrier state */ + carrier = sfp_led_has_signal(port); + + if (carrier != port->last_carrier) { + port->last_carrier = carrier; + sfp_led_set_link(port, carrier); + + if (carrier) { + dev_dbg(port->priv->dev, "%s: link up\n", + port->link_led_name); + /* Turn off activity LED and reset counters on link up */ + sfp_led_set_activity(port, false); + port->last_tx_packets = 0; + port->last_rx_packets = 0; + port->activity_led_on = false; + } else { + dev_dbg(port->priv->dev, "%s: link down\n", + port->link_led_name); + /* Module present but no link - solid activity LED */ + sfp_led_set_activity(port, true); + } + } + + if (!carrier) + goto reschedule; + + /* Monitor activity when link is up */ + if (!netif_running(netdev)) + goto reschedule; + + dev_get_stats(netdev, &stats); + + had_activity = (stats.tx_packets != port->last_tx_packets || + stats.rx_packets != port->last_rx_packets); + + if (had_activity) { + /* Toggle LED for visible blink */ + port->activity_led_on = !port->activity_led_on; + sfp_led_set_activity(port, port->activity_led_on); + port->last_tx_packets = stats.tx_packets; + port->last_rx_packets = stats.rx_packets; + } else if (port->activity_led_on) { + /* No activity - turn off */ + port->activity_led_on = false; + sfp_led_set_activity(port, false); + } + +reschedule: + schedule_delayed_work(&port->poll_work, + msecs_to_jiffies(SFP_LED_POLL_INTERVAL_MS)); +} + +static int sfp_led_register_port(struct sfp_led_priv *priv, + struct device_node *sfp_np, int index) +{ + struct sfp_led_port *port = &priv->ports[index]; + struct device_node *i2c_np; + + port->priv = priv; + port->sfp_np = sfp_np; + of_node_get(sfp_np); + + /* Get I2C adapter for module detection */ + i2c_np = of_parse_phandle(sfp_np, "i2c-bus", 0); + if (i2c_np) { + port->i2c_adapter = of_get_i2c_adapter_by_node(i2c_np); + of_node_put(i2c_np); + } + + if (IS_ERR_OR_NULL(port->i2c_adapter)) { + int ret = PTR_ERR_OR_ZERO(port->i2c_adapter); + + port->i2c_adapter = NULL; + if (ret != -EPROBE_DEFER) + dev_err(priv->dev, "port %d: i2c-bus not available\n", index); + of_node_put(sfp_np); + port->sfp_np = NULL; + return ret ? ret : -ENODEV; + } + + /* Get LEDs */ + port->link_led = of_led_get(sfp_np, 0); + if (IS_ERR(port->link_led)) { + dev_dbg(priv->dev, "port %d: link LED not in DT: %ld\n", + index, PTR_ERR(port->link_led)); + port->link_led = NULL; + } + + port->activity_led = of_led_get(sfp_np, 1); + if (IS_ERR(port->activity_led)) { + dev_dbg(priv->dev, "port %d: activity LED not in DT: %ld\n", + index, PTR_ERR(port->activity_led)); + port->activity_led = NULL; + } + + /* Set LED names for logging */ + if (port->link_led && port->link_led->name) + strscpy(port->link_led_name, port->link_led->name, + sizeof(port->link_led_name)); + else + snprintf(port->link_led_name, sizeof(port->link_led_name), + "sfp%d:link", index); + + if (port->activity_led && port->activity_led->name) + strscpy(port->activity_led_name, port->activity_led->name, + sizeof(port->activity_led_name)); + else + snprintf(port->activity_led_name, sizeof(port->activity_led_name), + "sfp%d:activity", index); + + /* Initialize work */ + INIT_DELAYED_WORK(&port->poll_work, sfp_led_poll_work_handler); + + /* Start polling */ + schedule_delayed_work(&port->poll_work, 0); + + dev_dbg(priv->dev, "registered port %d: %pOFn (link=%s, activity=%s)\n", + index, sfp_np, port->link_led_name, port->activity_led_name); + + return 0; +} + +static void sfp_led_cleanup_port(struct sfp_led_port *port) +{ + if (!port->sfp_np) + return; + + cancel_delayed_work_sync(&port->poll_work); + + sfp_led_set_link(port, false); + sfp_led_set_activity(port, false); + + if (port->activity_led) { + led_put(port->activity_led); + port->activity_led = NULL; + } + + if (port->link_led) { + led_put(port->link_led); + port->link_led = NULL; + } + + if (port->netdev) { + dev_put(port->netdev); + port->netdev = NULL; + } + + if (port->i2c_adapter) { + i2c_put_adapter(port->i2c_adapter); + port->i2c_adapter = NULL; + } + + of_node_put(port->sfp_np); + port->sfp_np = NULL; +} + +static int sfp_led_probe(struct platform_device *pdev) +{ + struct sfp_led_priv *priv; + struct device_node *np; + int count, i, registered = 0; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = &pdev->dev; + platform_set_drvdata(pdev, priv); + + count = of_count_phandle_with_args(pdev->dev.of_node, "sfp-ports", NULL); + if (count <= 0) { + dev_err(&pdev->dev, "no sfp-ports specified\n"); + return -ENODEV; + } + + priv->ports = devm_kcalloc(&pdev->dev, count, + sizeof(*priv->ports), GFP_KERNEL); + if (!priv->ports) + return -ENOMEM; + + priv->num_ports = count; + + for (i = 0; i < count; i++) { + np = of_parse_phandle(pdev->dev.of_node, "sfp-ports", i); + if (!np) { + dev_warn(&pdev->dev, "failed to parse sfp-ports[%d]\n", i); + continue; + } + + if (sfp_led_register_port(priv, np, i) == 0) + registered++; + + of_node_put(np); + } + + if (registered == 0) { + dev_err(&pdev->dev, "no SFP ports registered\n"); + return -ENODEV; + } + + dev_dbg(&pdev->dev, "loaded (passive monitor, %d ports)\n", registered); + return 0; +} + +static void sfp_led_remove(struct platform_device *pdev) +{ + struct sfp_led_priv *priv = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < priv->num_ports; i++) + sfp_led_cleanup_port(&priv->ports[i]); + + dev_dbg(&pdev->dev, "unloaded\n"); +} + +static const struct of_device_id sfp_led_of_match[] = { + { .compatible = "mono,sfp-led" }, + { } +}; +MODULE_DEVICE_TABLE(of, sfp_led_of_match); + +static struct platform_driver sfp_led_driver = { + .probe = sfp_led_probe, + .remove = sfp_led_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = sfp_led_of_match, + }, +}; +module_platform_driver(sfp_led_driver); + +MODULE_AUTHOR("Tomaz Zaman "); +MODULE_DESCRIPTION("SFP LED Control Platform Driver (Passive Monitor)"); +MODULE_LICENSE("GPL"); diff --git a/packages/bsp/gateway-dk/sfp-led.mk b/packages/bsp/gateway-dk/sfp-led.mk new file mode 100644 index 000000000000..415a22c91507 --- /dev/null +++ b/packages/bsp/gateway-dk/sfp-led.mk @@ -0,0 +1,10 @@ +obj-m := sfp-led.o + +all: + $(MAKE) -C $(KERNEL_SRC) M=$(PWD) modules + +modules_install: + $(MAKE) -C $(KERNEL_SRC) M=$(PWD) modules_install + +clean: + $(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean diff --git a/patch/kernel/archive/ls1046a-6.12/001-hwmon-ina2xx-Add-INA234-support.patch b/patch/kernel/archive/ls1046a-6.12/001-hwmon-ina2xx-Add-INA234-support.patch new file mode 100644 index 000000000000..b67b6930d314 --- /dev/null +++ b/patch/kernel/archive/ls1046a-6.12/001-hwmon-ina2xx-Add-INA234-support.patch @@ -0,0 +1,127 @@ +From: Tomaz Zaman +Date: Tue, 21 Oct 2025 12:00:00 +0000 +Subject: [PATCH] hwmon: ina2xx: Add INA234 support as INA226 variant + +Add support for the Texas Instruments INA234 power monitor. + +The INA234 is a 12-bit device with similar register layout to INA226. +The key difference is the bus voltage LSB: INA234 uses 3.125mV which +becomes 1.6mV effective LSB due to the 12-bit format (data in bits +[15:4] with bits [3:0] reserved). + +Datasheet: https://www.ti.com/product/ina234 + +Signed-off-by: Tomaz Zaman +--- + drivers/hwmon/ina2xx.c | 27 ++++++++++++++++++++------- + 1 file changed, 20 insertions(+), 7 deletions(-) + +diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c +index xxxxxxxx..xxxxxxxx 100644 +--- a/drivers/hwmon/ina2xx.c ++++ b/drivers/hwmon/ina2xx.c +@@ -125,7 +125,7 @@ + .writeable_reg = ina2xx_writeable_reg, + }; + +-enum ina2xx_ids { ina219, ina226 }; ++enum ina2xx_ids { ina219, ina226, ina234 }; + + struct ina2xx_config { + u16 config_default; +@@ -164,6 +164,14 @@ + .bus_voltage_lsb = 1250, + .power_lsb_factor = 25, + }, ++ [ina234] = { ++ .config_default = INA226_CONFIG_DEFAULT, ++ .calibration_value = 2048, ++ .shunt_div = 400, ++ .bus_voltage_shift = 4, ++ .bus_voltage_lsb = 25600, ++ .power_lsb_factor = 32, ++ }, + }; + + /* +@@ -633,12 +641,12 @@ + return 0444; + case hwmon_in_lcrit: + case hwmon_in_crit: +- if (chip == ina226) ++ if (chip == ina226 || chip == ina234) + return 0644; + break; + case hwmon_in_lcrit_alarm: + case hwmon_in_crit_alarm: +- if (chip == ina226) ++ if (chip == ina226 || chip == ina234) + return 0444; + break; + default: +@@ -651,12 +659,12 @@ + return 0444; + case hwmon_curr_lcrit: + case hwmon_curr_crit: +- if (chip == ina226) ++ if (chip == ina226 || chip == ina234) + return 0644; + break; + case hwmon_curr_lcrit_alarm: + case hwmon_curr_crit_alarm: +- if (chip == ina226) ++ if (chip == ina226 || chip == ina234) + return 0444; + break; + default: +@@ -668,11 +676,11 @@ + case hwmon_power_input: + return 0444; + case hwmon_power_crit: +- if (chip == ina226) ++ if (chip == ina226 || chip == ina234) + return 0644; + break; + case hwmon_power_crit_alarm: +- if (chip == ina226) ++ if (chip == ina226 || chip == ina234) + return 0444; + break; + default: +@@ -682,7 +690,7 @@ + case hwmon_chip: + switch (attr) { + case hwmon_chip_update_interval: +- if (chip == ina226) ++ if (chip == ina226 || chip == ina234) + return 0644; + break; + default: +@@ -802,7 +810,7 @@ + if (ret < 0) + return ret; + +- if (data->chip == ina226) { ++ if (data->chip == ina226 || data->chip == ina234) { + bool active_high = device_property_read_bool(dev, "ti,alert-polarity-active-high"); + + regmap_update_bits(regmap, INA226_MASK_ENABLE, +@@ -872,6 +880,7 @@ + { "ina226", ina226 }, + { "ina230", ina226 }, + { "ina231", ina226 }, ++ { "ina234", ina234 }, + { } + }; + MODULE_DEVICE_TABLE(i2c, ina2xx_id); +@@ -897,6 +906,10 @@ + .compatible = "ti,ina231", + .data = (void *)ina226 + }, ++ { ++ .compatible = "ti,ina234", ++ .data = (void *)ina234 ++ }, + { }, + }; + MODULE_DEVICE_TABLE(of, ina2xx_of_match); diff --git a/patch/kernel/archive/ls1046a-6.12/002-arm64-dts-Add-Mono-Gateway-DK-device-tree.patch b/patch/kernel/archive/ls1046a-6.12/002-arm64-dts-Add-Mono-Gateway-DK-device-tree.patch new file mode 100644 index 000000000000..0a9daed67903 --- /dev/null +++ b/patch/kernel/archive/ls1046a-6.12/002-arm64-dts-Add-Mono-Gateway-DK-device-tree.patch @@ -0,0 +1,1053 @@ +From: Tomaz Zaman +Date: Fri, 03 Apr 2026 12:00:00 +0000 +Subject: [PATCH] arm64: dts: freescale: Add Mono Gateway DK device tree + +Add device tree for the Mono Gateway Development Kit, a networking +gateway based on the NXP LS1046A SoC with 3x 1GbE SGMII, 2x 10GbE +SFP+, eMMC, QSPI NOR, EMC2305 fan controller, INA234 power monitors, +LP5812 LED controller, and TMP431 temperature sensors. + +Signed-off-by: Tomaz Zaman +--- + arch/arm64/boot/dts/freescale/Makefile | 1 + + arch/arm64/boot/dts/freescale/mono-gateway-dk.dts | 1024 ++++++++++++++++++++ + 2 files changed, 1025 insertions(+) + create mode 100644 arch/arm64/boot/dts/freescale/mono-gateway-dk.dts + +diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile +--- a/arch/arm64/boot/dts/freescale/Makefile ++++ b/arch/arm64/boot/dts/freescale/Makefile +@@ -34,6 +34,7 @@ + dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-rdb-usdpaa-shared.dtb + dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-tqmls1046a-mbls10xxa.dtb ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += mono-gateway-dk.dtb + DTC_FLAGS_fsl-ls1088a-qds := -Wno-interrupt_map + dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1088a-qds.dtb + DTC_FLAGS_fsl-ls1088a-rdb := -Wno-interrupt_map + +diff --git a/arch/arm64/boot/dts/freescale/mono-gateway-dk.dts b/arch/arm64/boot/dts/freescale/mono-gateway-dk.dts +new file mode 100644 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/mono-gateway-dk.dts +@@ -0,0 +1,1021 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Device Tree file for Mono Gateway DK (NXP LS1046A). ++ * ++ * Copyright 2026 Mono Technologies Inc. ++ * ++ * Author: Tomaz Zaman ++ */ ++ ++/dts-v1/; ++ ++#include ++#include ++#include "fsl-ls1046a.dtsi" ++#include "qoriq-qman-portals-sdk.dtsi" ++#include "qoriq-bman-portals-sdk.dtsi" ++ ++/ { ++ model = "Mono Gateway Development Kit"; ++ compatible = "mono,gateway-dk", "fsl,ls1046a"; ++ ++ aliases { ++ serial0 = &duart0; ++ serial1 = &duart1; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ /* SFP+ Port 0 LEDs - Activity/Link */ ++ led_sfp0_link: sfp0_link { ++ label = "sfp0:link"; ++ gpios = <&gpio2 17 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; ++ }; ++ ++ led_sfp0_activity: sfp0_activity { ++ label = "sfp0:activity"; ++ gpios = <&gpio2 18 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; ++ }; ++ ++ /* SFP+ Port 1 LEDs - Activity/Link */ ++ led_sfp1_link: sfp1_link { ++ label = "sfp1:link"; ++ gpios = <&gpio2 15 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; ++ }; ++ ++ led_sfp1_activity: sfp1_activity { ++ label = "sfp1:activity"; ++ gpios = <&gpio2 16 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; ++ }; ++ }; ++ ++ /* SFP 1 */ ++ sfp_xfi0: sfp-xfi0 { ++ compatible = "sff,sfp"; ++ i2c-bus = <&sfp0_i2c>; ++ tx-disable-gpios = <&gpio2 14 GPIO_ACTIVE_HIGH>; ++ mod-def0-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>; ++ los-gpios = <&gpio2 11 GPIO_ACTIVE_HIGH>; ++ maximum-power-milliwatt = <3000>; ++ leds = <&led_sfp0_link>, <&led_sfp0_activity>; ++ }; ++ ++ /* SFP 2 */ ++ sfp_xfi1: sfp-xfi1 { ++ compatible = "sff,sfp"; ++ i2c-bus = <&sfp1_i2c>; ++ tx-disable-gpios = <&gpio2 13 GPIO_ACTIVE_HIGH>; ++ mod-def0-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>; ++ los-gpios = <&gpio2 9 GPIO_ACTIVE_HIGH>; ++ maximum-power-milliwatt = <3000>; ++ leds = <&led_sfp1_link>, <&led_sfp1_activity>; ++ }; ++ ++ /* SFP LED Controller */ ++ sfp_led_controller: sfp-led-controller { ++ compatible = "mono,sfp-led"; ++ sfp-ports = <&sfp_xfi0>, <&sfp_xfi1>; ++ }; ++ ++ /* Boot memory regions for SDK DPAA driver */ ++ bootmem0@a0000000 { ++ reg = <0x00 0xa0000000 0x00 0x4000000 0x00 0xa4000000 0x00 0x6000000>; ++ }; ++ ++ bootmem1@aa000000 { ++ reg = <0x00 0xaa000000 0x00 0x4000000 0x00 0xae000000 0x00 0x6000000>; ++ }; ++ ++ cpus { ++ fman0-extended-args { ++ cell-index = <0x00>; ++ compatible = "fsl,fman-extended-args"; ++ total-fifo-size = <0x3e500>; ++ ++ /* Offline ports for CDX - cell-index overridden for SDK compatibility: ++ * fman0_oh_0x3 (port@83000) = cell-index 1 (SDK style) ++ * fman0_oh_0x4 (port@84000) = cell-index 2 (SDK style) ++ */ ++ fman0_oh_0x3-extended-args { ++ cell-index = <0x01>; /* matches port@83000 SDK cell-index */ ++ compatible = "fsl,fman-port-op-extended-args"; ++ fifo-size = <0x3200 0x00>; ++ buffer-layout = <0x60 0x40>; ++ }; ++ ++ fman0_oh_0x4-extended-args { ++ cell-index = <0x02>; /* matches port@84000 SDK cell-index */ ++ compatible = "fsl,fman-port-op-extended-args"; ++ fifo-size = <0x900 0x00>; ++ buffer-layout = <0x60 0x40>; ++ }; ++ ++ /* All 1G ports need extended-args (SDK driver requirement) */ ++ ++ /* MAC1 (ethernet@e0000) - cell-index 0 - disabled but needed */ ++ fman0_rx0-extended-args { ++ cell-index = <0x00>; ++ compatible = "fsl,fman-port-1g-rx-extended-args"; ++ fifo-size = <0x3200 0x00>; ++ buffer-layout = <0x60 0x40>; ++ vsp-window = <0x02 0x00>; ++ }; ++ ++ fman0_tx0-extended-args { ++ cell-index = <0x00>; ++ compatible = "fsl,fman-port-1g-tx-extended-args"; ++ fifo-size = <0x3200 0x00>; ++ buffer-layout = <0x60 0x40>; ++ }; ++ ++ /* MAC2 (ethernet@e2000) - cell-index 1 */ ++ fman0_rx1-extended-args { ++ cell-index = <0x01>; ++ compatible = "fsl,fman-port-1g-rx-extended-args"; ++ fifo-size = <0x3200 0x00>; ++ buffer-layout = <0x60 0x40>; ++ vsp-window = <0x02 0x00>; ++ }; ++ ++ fman0_tx1-extended-args { ++ cell-index = <0x01>; ++ compatible = "fsl,fman-port-1g-tx-extended-args"; ++ fifo-size = <0x3200 0x00>; ++ buffer-layout = <0x60 0x40>; ++ }; ++ ++ /* MAC3 (ethernet@e4000) - cell-index 2 - disabled but needed */ ++ fman0_rx2-extended-args { ++ cell-index = <0x02>; ++ compatible = "fsl,fman-port-1g-rx-extended-args"; ++ fifo-size = <0x3200 0x00>; ++ buffer-layout = <0x60 0x40>; ++ vsp-window = <0x02 0x00>; ++ }; ++ ++ fman0_tx2-extended-args { ++ cell-index = <0x02>; ++ compatible = "fsl,fman-port-1g-tx-extended-args"; ++ fifo-size = <0x3200 0x00>; ++ buffer-layout = <0x60 0x40>; ++ }; ++ ++ /* MAC4 (ethernet@e6000) - cell-index 3 - disabled but needed */ ++ fman0_rx3-extended-args { ++ cell-index = <0x03>; ++ compatible = "fsl,fman-port-1g-rx-extended-args"; ++ fifo-size = <0x3200 0x00>; ++ buffer-layout = <0x60 0x40>; ++ vsp-window = <0x02 0x00>; ++ }; ++ ++ fman0_tx3-extended-args { ++ cell-index = <0x03>; ++ compatible = "fsl,fman-port-1g-tx-extended-args"; ++ fifo-size = <0x3200 0x00>; ++ buffer-layout = <0x60 0x40>; ++ }; ++ ++ /* MAC5 (ethernet@e8000) - cell-index 4 */ ++ fman0_rx4-extended-args { ++ cell-index = <0x04>; ++ compatible = "fsl,fman-port-1g-rx-extended-args"; ++ fifo-size = <0x3200 0x00>; ++ buffer-layout = <0x60 0x40>; ++ vsp-window = <0x02 0x00>; ++ }; ++ ++ fman0_tx4-extended-args { ++ cell-index = <0x04>; ++ compatible = "fsl,fman-port-1g-tx-extended-args"; ++ fifo-size = <0x3200 0x00>; ++ buffer-layout = <0x60 0x40>; ++ }; ++ ++ /* MAC6 (ethernet@ea000) - cell-index 5 */ ++ fman0_rx5-extended-args { ++ cell-index = <0x05>; ++ compatible = "fsl,fman-port-1g-rx-extended-args"; ++ fifo-size = <0x3200 0x00>; ++ buffer-layout = <0x60 0x40>; ++ vsp-window = <0x02 0x00>; ++ }; ++ ++ fman0_tx5-extended-args { ++ cell-index = <0x05>; ++ compatible = "fsl,fman-port-1g-tx-extended-args"; ++ fifo-size = <0x3200 0x00>; ++ buffer-layout = <0x60 0x40>; ++ }; ++ ++ /* MAC9 (ethernet@f0000) - 10G cell-index 0 */ ++ fman0_rx6-extended-args { ++ cell-index = <0x00>; ++ compatible = "fsl,fman-port-10g-rx-extended-args"; ++ fifo-size = <0x6000 0x00>; ++ buffer-layout = <0x60 0x40>; ++ vsp-window = <0x02 0x00>; ++ }; ++ ++ fman0_tx6-extended-args { ++ cell-index = <0x00>; ++ compatible = "fsl,fman-port-10g-tx-extended-args"; ++ fifo-size = <0x4000 0x00>; ++ buffer-layout = <0x60 0x40>; ++ }; ++ ++ /* MAC10 (ethernet@f2000) - 10G cell-index 1 */ ++ fman0_rx7-extended-args { ++ cell-index = <0x01>; ++ compatible = "fsl,fman-port-10g-rx-extended-args"; ++ fifo-size = <0x6000 0x00>; ++ buffer-layout = <0x60 0x40>; ++ vsp-window = <0x02 0x00>; ++ }; ++ ++ fman0_tx7-extended-args { ++ cell-index = <0x01>; ++ compatible = "fsl,fman-port-10g-tx-extended-args"; ++ fifo-size = <0x4000 0x00>; ++ buffer-layout = <0x60 0x40>; ++ }; ++ }; ++ }; ++}; ++ ++&pcie3 { ++ status = "okay"; ++}; ++ ++&gpio2 { ++ 2R-enable { ++ gpio-hog; ++ gpios = <6 GPIO_ACTIVE_LOW>; ++ output-high; ++ line-name = "2r-enable"; ++ }; ++ ++ 3R-enable { ++ gpio-hog; ++ gpios = <2 GPIO_ACTIVE_LOW>; ++ output-low; ++ line-name = "3r-enable"; ++ }; ++ ++ uart-mux { ++ gpio-hog; ++ gpios = <26 GPIO_ACTIVE_HIGH>; ++ output-high; /* "output-high" for 2R, "output-low" for 3R */ ++ line-name = "uart-mux"; ++ }; ++}; ++ ++&duart0 { ++ status = "okay"; ++}; ++ ++&duart1 { ++ status = "okay"; ++ uart-has-rtscts; ++}; ++ ++&usb0 { ++ status = "okay"; ++ dr_mode = "host"; ++}; ++ ++&usb1 { ++ status = "disabled"; ++ disable-over-current; ++}; ++ ++&usb2 { ++ status = "disabled"; ++ disable-over-current; ++}; ++ ++&dspi { ++ status = "okay"; ++}; ++ ++&esdhc { ++ status = "okay"; ++ mmc-hs200-1_8v; ++ bus-width = <4>; ++}; ++ ++&i2c0 { ++ status = "okay"; ++ ++ /* Thermal sensors, retimer, clock generator, PWM fan */ ++ i2c-mux@70 { ++ compatible = "nxp,pca9545"; ++ reg = <0x70>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ i2c@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ ++ retimer: retimer@18 { ++ compatible = "ti,ds100df410"; ++ reg = <0x18>; ++ }; ++ }; ++ ++ i2c@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <1>; ++ ++ temp-sensor@4c { ++ compatible = "ti,tmp431"; ++ reg = <0x4c>; ++ }; ++ }; ++ ++ i2c@2 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <2>; ++ ++ temp-sensor@4c { ++ compatible = "ti,tmp431"; ++ reg = <0x4c>; ++ }; ++ }; ++ ++ i2c@3 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <3>; ++ ++ fan_controller: fan-controller@2e { ++ compatible = "microchip,emc2305"; ++ reg = <0x2e>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ #pwm-cells = <3>; ++ ++ fan0: fan@0 { ++ reg = <0>; ++ label = "System Fan 1"; ++ pwms = <&fan_controller 26000 1 1>; ++ #cooling-cells = <2>; ++ }; ++ ++ fan1: fan@1 { ++ reg = <1>; ++ label = "System Fan 2"; ++ pwms = <&fan_controller 26000 1 1>; ++ #cooling-cells = <2>; ++ }; ++ }; ++ }; ++ }; ++}; ++ ++&i2c1 { ++ status = "okay"; ++ ++ /* SFP+ modules */ ++ sfpmux: i2c-mux@70 { ++ compatible = "nxp,pca9545"; ++ reg = <0x70>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ sfp0_i2c: i2c@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ }; ++ ++ sfp1_i2c: i2c@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <1>; ++ }; ++ }; ++}; ++ ++&i2c2 { ++ status = "okay"; ++ ++ i2c-mux@70 { ++ compatible = "nxp,pca9545"; ++ reg = <0x70>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ i2c@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ ++ power_sensor@40 { ++ compatible = "ti,ina234"; ++ reg = <0x40>; ++ label = "USB Power Delivery"; ++ #io-channel-cells = <1>; ++ shunt-resistor = <1000>; ++ }; ++ power_sensor@41 { ++ compatible = "ti,ina234"; ++ reg = <0x41>; ++ label = "5V PSU"; ++ #io-channel-cells = <1>; ++ shunt-resistor = <1000>; ++ }; ++ power_sensor@42 { ++ compatible = "ti,ina234"; ++ reg = <0x42>; ++ label = "1V Core PSU"; ++ #io-channel-cells = <1>; ++ shunt-resistor = <1000>; ++ }; ++ power_sensor@43 { ++ compatible = "ti,ina234"; ++ reg = <0x43>; ++ label = "1.2V DDR PSU"; ++ #io-channel-cells = <1>; ++ shunt-resistor = <5000>; ++ }; ++ }; ++ ++ i2c@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <1>; ++ ++ power_sensor@40 { ++ compatible = "ti,ina234"; ++ reg = <0x40>; ++ label = "1.35V SerDes PSU"; ++ #io-channel-cells = <1>; ++ shunt-resistor = <5000>; ++ }; ++ power_sensor@41 { ++ compatible = "ti,ina234"; ++ reg = <0x41>; ++ label = "1.8V PSU"; ++ #io-channel-cells = <1>; ++ shunt-resistor = <5000>; ++ }; ++ power_sensor@42 { ++ compatible = "ti,ina234"; ++ reg = <0x42>; ++ label = "2.5V DDR PSU"; ++ #io-channel-cells = <1>; ++ shunt-resistor = <5000>; ++ }; ++ power_sensor@43 { ++ compatible = "ti,ina234"; ++ reg = <0x43>; ++ label = "3.3V PSU"; ++ #io-channel-cells = <1>; ++ shunt-resistor = <1000>; ++ }; ++ }; ++ ++ i2c@2 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <2>; ++ ++ rtc@53 { ++ compatible = "nxp,pcf2131"; ++ reg = <0x53>; ++ }; ++ ++ typec: hd3ss3220@47 { ++ compatible = "ti,hd3ss3220"; ++ reg = <0x47>; ++ }; ++ }; ++ ++ i2c@3 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <3>; ++ ++ lp5810@6c { ++ compatible = "ti,lp5812"; ++ reg = <0x6c>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ led@0 { ++ reg = <0>; ++ color = ; ++ label = "status:white"; ++ led-max-microamp = <25500>; ++ }; ++ ++ led@1 { ++ reg = <1>; ++ color = ; ++ label = "status:blue"; ++ led-max-microamp = <25500>; ++ }; ++ ++ led@2 { ++ reg = <2>; ++ color = ; ++ label = "status:green"; ++ led-max-microamp = <25500>; ++ }; ++ ++ led@3 { ++ reg = <3>; ++ color = ; ++ label = "status:red"; ++ led-max-microamp = <25500>; ++ }; ++ }; ++ }; ++ }; ++}; ++ ++&i2c3 { ++ status = "okay"; ++}; ++ ++&qspi { ++ status = "okay"; ++ ++ mt25qu512a0: flash@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "jedec,spi-nor"; ++ spi-max-frequency = <50000000>; ++ reg = <0>; ++ ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@flash { ++ label = "flash"; ++ reg = <0x0 0x4000000>; ++ }; ++ ++ partition@0 { ++ label = "rcw-bl2"; ++ reg = <0x0 0x100000>; ++ }; ++ ++ partition@100000 { ++ label = "uboot"; ++ reg = <0x100000 0x200000>; ++ }; ++ ++ partition@300000 { ++ label = "uboot-env"; ++ reg = <0x300000 0x100000>; ++ }; ++ ++ partition@400000 { ++ label = "fman-ucode"; ++ reg = <0x400000 0x100000>; ++ }; ++ ++ partition@500000 { ++ label = "recovery-dtb"; ++ reg = <0x500000 0x100000>; ++ }; ++ ++ partition@600000 { ++ label = "backup"; ++ reg = <0x600000 0x400000>; ++ }; ++ ++ partition@a00000 { ++ label = "kernel-initramfs"; ++ reg = <0xa00000 0x1600000>; ++ }; ++ ++ partition@2000000 { ++ label = "unallocated"; ++ reg = <0x2000000 0x2000000>; ++ }; ++ }; ++ }; ++}; ++ ++#include "fsl-ls1046-post.dtsi" ++ ++&bman_fbpr { ++ compatible = "fsl,bman-fbpr"; ++ alloc-ranges = <0 0 0x10000 0>; ++}; ++&qman_fqd { ++ compatible = "fsl,qman-fqd"; ++ alloc-ranges = <0 0 0x10000 0>; ++}; ++&qman_pfdr { ++ compatible = "fsl,qman-pfdr"; ++ alloc-ranges = <0 0 0x10000 0>; ++}; ++ ++&soc { ++ /delete-property/ dma-coherent; ++ ++ #include "qoriq-dpaa-eth.dtsi" ++ /* Note: We override cell-index values in &fman0 section to match ++ * SDK driver expectations (0-5 instead of mainline 2-7). ++ * Port@82000 with cell-index=0 becomes the HC port for PCD. ++ */ ++ ++ pcie@3400000 { ++ /delete-property/ iommu-map; ++ }; ++ ++ pcie@3500000 { ++ /delete-property/ iommu-map; ++ }; ++ ++ pcie@3600000 { ++ /delete-property/ iommu-map; ++ }; ++ ++ /delete-node/ iommu@9000000; ++}; ++ ++&fsldpaa { ++ ethernet@0 { ++ status = "disabled"; /* MAC1 - not on Mono Gateway DK */ ++ }; ++ ethernet@2 { ++ status = "disabled"; /* MAC3 - not on Mono Gateway DK */ ++ }; ++ ethernet@3 { ++ status = "disabled"; /* MAC4 - not on Mono Gateway DK */ ++ }; ++ ++ /* Enabled from qoriq-dpaa-eth.dtsi: ++ * ethernet@1 = enet1 = MAC2 ++ * ethernet@4 = enet4 = MAC5 ++ * ethernet@5 = enet5 = MAC6 ++ * ethernet@8 = enet6 = MAC9 (10G) ++ */ ++ ++ /* Add MAC10 - not in qoriq-dpaa-eth.dtsi */ ++ ethernet@9 { ++ compatible = "fsl,dpa-ethernet"; ++ fsl,fman-mac = <&enet7>; ++ dma-coherent; ++ }; ++}; ++ ++&fman0 { ++ compatible = "fsl,fman", "simple-bus"; ++ ++ /* Core FMan sub-modules */ ++ muram@0 { ++ compatible = "fsl,fman-muram"; ++ reg = <0x0 0x60000>; ++ }; ++ ++ bmi@80000 { ++ compatible = "fsl,fman-bmi"; ++ reg = <0x80000 0x400>; ++ }; ++ ++ qmi@80400 { ++ compatible = "fsl,fman-qmi"; ++ reg = <0x80400 0x400>; ++ }; ++ ++ /* PCD sub-modules required for FMC/CDX */ ++ cc { ++ compatible = "fsl,fman-cc"; ++ }; ++ ++ policer@c0000 { ++ compatible = "fsl,fman-policer"; ++ reg = <0xc0000 0x1000>; ++ }; ++ ++ keygen@c1000 { ++ compatible = "fsl,fman-keygen"; ++ reg = <0xc1000 0x1000>; ++ }; ++ ++ dma@c2000 { ++ compatible = "fsl,fman-dma"; ++ reg = <0xc2000 0x1000>; ++ }; ++ ++ fpm@c3000 { ++ compatible = "fsl,fman-fpm"; ++ reg = <0xc3000 0x1000>; ++ }; ++ ++ parser@c7000 { ++ compatible = "fsl,fman-parser"; ++ reg = <0xc7000 0x1000>; ++ }; ++ ++ vsps@dc000 { ++ compatible = "fsl,fman-vsps"; ++ reg = <0xdc000 0x1000>; ++ }; ++ ++ ethernet@e0000 { ++ status = "disabled"; ++ }; ++ ++ ethernet@e4000 { ++ status = "disabled"; ++ }; ++ ++ ethernet@e6000 { ++ status = "disabled"; ++ }; ++ ++ ethernet@e8000 { ++ phy-handle = <&sgmii_phy0>; ++ phy-connection-type = "sgmii"; ++ status = "okay"; ++ }; ++ ++ ethernet@ea000 { ++ phy-handle = <&sgmii_phy1>; ++ phy-connection-type = "sgmii"; ++ status = "okay"; ++ }; ++ ++ ethernet@e2000 { ++ phy-handle = <&sgmii_phy2>; ++ phy-connection-type = "sgmii"; ++ status = "okay"; ++ }; ++ ++ fm1_mac9: ethernet@f0000 { /* 10GEC1 */ ++ /delete-property/ managed; ++ sfp = <&sfp_xfi0>; ++ fixed-link = <0 1 10000 0 0>; ++ phy-connection-type = "xgmii"; ++ pcs-handle-names = "xfi"; /* Match enet7 for consistency */ ++ }; ++ ++ fm1_mac10: ethernet@f2000 { /* 10GEC2 */ ++ /delete-property/ managed; ++ sfp = <&sfp_xfi1>; ++ fixed-link = <0 1 10000 0 0>; ++ phy-connection-type = "xgmii"; ++ }; ++ ++ mdio@fc000 { ++ status = "disabled"; ++ }; ++ ++ mdio@fd000 { ++ sgmii_phy0: ethernet-phy@0 { ++ reg = <0x0>; ++ }; ++ ++ sgmii_phy1: ethernet-phy@1 { ++ reg = <0x1>; ++ }; ++ ++ sgmii_phy2: ethernet-phy@2 { ++ reg = <0x2>; ++ }; ++ }; ++ ++ /* DPA Offline port bindings - required for CDX. ++ * Use phandles fman0_oh_0x3 (port@83000) and fman0_oh_0x4 (port@84000). ++ * Cell-index overridden to SDK-style (1 and 2) in port nodes above. ++ */ ++ dpa-fman0-oh@2 { ++ compatible = "fsl,dpa-oh"; ++ fsl,qman-frame-queues-oh = <0x60 0x01 0x61 0x01>; ++ fsl,fman-oh-port = <&fman0_oh_0x3>; ++ }; ++ ++ dpa-fman0-oh@3 { ++ compatible = "fsl,dpa-oh"; ++ fsl,qman-frame-queues-oh = <0x62 0x01 0x63 0x01>; ++ fsl,fman-oh-port = <&fman0_oh_0x4>; ++ }; ++ ++ /* Override OH port cell-index values for SDK driver compatibility. ++ * SDK driver expects cell-index 0 for HC (Host Command/PCD) port. ++ * Mainline qoriq-fman3-0.dtsi uses cell-index 2-7, but SDK needs 0-5. ++ */ ++ port@82000 { ++ cell-index = <0>; /* HC port - required for PCD initialization */ ++ compatible = "fsl,fman-port-oh"; ++ }; ++ ++ port@83000 { ++ cell-index = <1>; ++ compatible = "fsl,fman-port-oh"; ++ }; ++ ++ port@84000 { ++ cell-index = <2>; ++ compatible = "fsl,fman-port-oh"; ++ }; ++ ++ port@85000 { ++ cell-index = <3>; ++ compatible = "fsl,fman-port-oh"; ++ }; ++ ++ port@86000 { ++ cell-index = <4>; ++ compatible = "fsl,fman-port-oh"; ++ }; ++ ++ port@87000 { ++ cell-index = <5>; ++ compatible = "fsl,fman-port-oh"; ++ }; ++}; ++ ++&clockgen { ++ dma-coherent; ++}; ++ ++&scfg { ++ dma-coherent; ++}; ++ ++&crypto { ++ dma-coherent; ++}; ++ ++&dcfg { ++ dma-coherent; ++}; ++ ++&ifc { ++ dma-coherent; ++}; ++ ++&qspi { ++ dma-coherent; ++}; ++ ++&esdhc { ++ dma-coherent; ++}; ++ ++&ddr { ++ dma-coherent; ++}; ++ ++&tmu { ++ dma-coherent; ++}; ++ ++&qman { ++ dma-coherent; ++}; ++ ++&bman { ++ dma-coherent; ++}; ++ ++&bportals { ++ dma-coherent; ++}; ++ ++&qportals { ++ dma-coherent; ++}; ++ ++&dspi { ++ dma-coherent; ++}; ++ ++&i2c0 { ++ dma-coherent; ++}; ++ ++&i2c1 { ++ dma-coherent; ++}; ++ ++&i2c2 { ++ dma-coherent; ++}; ++ ++&i2c3 { ++ dma-coherent; ++}; ++ ++&duart0 { ++ dma-coherent; ++}; ++ ++&duart1 { ++ dma-coherent; ++}; ++ ++&duart2 { ++ dma-coherent; ++}; ++ ++&duart3 { ++ dma-coherent; ++}; ++ ++&gpio0 { ++ dma-coherent; ++}; ++ ++&gpio1 { ++ dma-coherent; ++}; ++ ++&gpio2 { ++ dma-coherent; ++}; ++ ++&gpio3 { ++ dma-coherent; ++}; ++ ++&lpuart0 { ++ dma-coherent; ++}; ++ ++&lpuart1 { ++ dma-coherent; ++}; ++ ++&lpuart2 { ++ dma-coherent; ++}; ++ ++&lpuart3 { ++ dma-coherent; ++}; ++ ++&lpuart4 { ++ dma-coherent; ++}; ++ ++&lpuart5 { ++ dma-coherent; ++}; ++ ++&ftm_alarm0 { ++ dma-coherent; ++}; ++ ++&wdog0 { ++ dma-coherent; ++}; ++ ++&edma0 { ++ dma-coherent; ++}; ++ ++&sata { ++ dma-coherent; ++}; ++ ++&qdma { ++ dma-coherent; ++}; ++ ++&msi1 { ++ dma-coherent; ++}; ++ ++&msi2 { ++ dma-coherent; ++}; ++ ++&msi3 { ++ dma-coherent; ++}; ++ ++&fman0 { ++ dma-coherent; ++}; ++ ++&ptp_timer0 { ++ dma-coherent; ++}; ++ ++&fsldpaa { ++ dma-coherent; ++};