Add the BPF-side header panel-bpf-mipi-dsi.h and a standalone Makefile for building panel BPF programs. The header provides section name macros (PANEL_BPF_MIPI_DSI_PREPARE, etc.), the PANEL_BPF_MIPI_DSI_OPS() struct_ops declaration macro, extern declarations for all the kfuncs, and some convenience macros.
The Makefile follows the same pattern as drivers/hid/bpf/progs/. It generates vmlinux.h from BTF, bootstraps bpftool and libbpf from the kernel tools/ directory, then compiles every *.bpf.c file into a stripped .bpf.o object. The resulting objects are userspace artifacts loaded at runtime. Signed-off-by: Maxime Ripard <[email protected]> --- drivers/gpu/drm/panel/bpf/progs/Makefile | 93 +++++++++++++++++++++ .../gpu/drm/panel/bpf/progs/panel-bpf-mipi-dsi.h | 95 ++++++++++++++++++++++ include/drm/drm_panel_dsi_bpf.h | 50 ------------ 3 files changed, 188 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/panel/bpf/progs/Makefile b/drivers/gpu/drm/panel/bpf/progs/Makefile new file mode 100644 index 000000000000..74190ee618ab --- /dev/null +++ b/drivers/gpu/drm/panel/bpf/progs/Makefile @@ -0,0 +1,93 @@ +# SPDX-License-Identifier: GPL-2.0 +OUTPUT := .output +abs_out := $(abspath $(OUTPUT)) + +CLANG ?= clang +LLC ?= llc +LLVM_STRIP ?= llvm-strip + +TOOLS_PATH := $(abspath ../../../../../../tools) +BPFTOOL_SRC := $(TOOLS_PATH)/bpf/bpftool +BPFTOOL_OUTPUT := $(abs_out)/bpftool +DEFAULT_BPFTOOL := $(BPFTOOL_OUTPUT)/bootstrap/bpftool +BPFTOOL ?= $(DEFAULT_BPFTOOL) + +LIBBPF_SRC := $(TOOLS_PATH)/lib/bpf +LIBBPF_OUTPUT := $(abs_out)/libbpf +LIBBPF_DESTDIR := $(LIBBPF_OUTPUT) +LIBBPF_INCLUDE := $(LIBBPF_DESTDIR)/include +BPFOBJ := $(LIBBPF_OUTPUT)/libbpf.a + +INCLUDES := -I$(OUTPUT) -I$(LIBBPF_INCLUDE) -I$(TOOLS_PATH)/include/uapi +CFLAGS := -g -Wall + +VMLINUX_BTF_PATHS ?= $(if $(O),$(O)/vmlinux) \ + $(if $(KBUILD_OUTPUT),$(KBUILD_OUTPUT)/vmlinux) \ + ../../../../../../vmlinux \ + /sys/kernel/btf/vmlinux \ + /boot/vmlinux-$(shell uname -r) +VMLINUX_BTF ?= $(abspath $(firstword $(wildcard $(VMLINUX_BTF_PATHS)))) +ifeq ($(VMLINUX_BTF),) +$(error Cannot find a vmlinux for VMLINUX_BTF at any of "$(VMLINUX_BTF_PATHS)") +endif + +ifeq ($(V),1) +Q = +msg = +else +Q = @ +msg = @printf ' %-8s %s%s\n' "$(1)" "$(notdir $(2))" "$(if $(3), $(3))"; +MAKEFLAGS += --no-print-directory +submake_extras := feature_display=0 +endif + +.DELETE_ON_ERROR: + +.PHONY: all clean + +SOURCES = $(wildcard *.bpf.c) +TARGETS = $(SOURCES:.bpf.c=.bpf.o) + +all: $(TARGETS) + +clean: + $(call msg,CLEAN) + $(Q)rm -rf $(OUTPUT) $(TARGETS) + +%.bpf.o: %.bpf.c vmlinux.h $(BPFOBJ) | $(OUTPUT) + $(call msg,BPF,$@) + $(Q)$(CLANG) -g -O2 --target=bpf -Wall -Werror $(INCLUDES) \ + -Wno-microsoft-anon-tag \ + -fms-extensions \ + -c $(filter %.c,$^) -o $@ && \ + $(LLVM_STRIP) -g $@ + +vmlinux.h: $(VMLINUX_BTF) $(BPFTOOL) | $(INCLUDE_DIR) +ifeq ($(VMLINUX_H),) + $(call msg,GEN,,$@) + $(Q)$(BPFTOOL) btf dump file $(VMLINUX_BTF) format c > $@ +else + $(call msg,CP,,$@) + $(Q)cp "$(VMLINUX_H)" $@ +endif + +$(OUTPUT) $(LIBBPF_OUTPUT) $(BPFTOOL_OUTPUT): + $(call msg,MKDIR,$@) + $(Q)mkdir -p $@ + +$(BPFOBJ): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(LIBBPF_OUTPUT) + $(Q)$(MAKE) $(submake_extras) -C $(LIBBPF_SRC) \ + OUTPUT=$(abspath $(dir $@))/ prefix= \ + DESTDIR=$(LIBBPF_DESTDIR) $(abspath $@) install_headers + +ifeq ($(CROSS_COMPILE),) +$(DEFAULT_BPFTOOL): $(BPFOBJ) | $(BPFTOOL_OUTPUT) + $(Q)$(MAKE) $(submake_extras) -C $(BPFTOOL_SRC) \ + OUTPUT=$(BPFTOOL_OUTPUT)/ \ + LIBBPF_BOOTSTRAP_OUTPUT=$(LIBBPF_OUTPUT)/ \ + LIBBPF_BOOTSTRAP_DESTDIR=$(LIBBPF_DESTDIR)/ bootstrap +else +$(DEFAULT_BPFTOOL): | $(BPFTOOL_OUTPUT) + $(Q)$(MAKE) $(submake_extras) -C $(BPFTOOL_SRC) \ + OUTPUT=$(BPFTOOL_OUTPUT)/ bootstrap +endif diff --git a/drivers/gpu/drm/panel/bpf/progs/panel-bpf-mipi-dsi.h b/drivers/gpu/drm/panel/bpf/progs/panel-bpf-mipi-dsi.h new file mode 100644 index 000000000000..e2b03afef2c8 --- /dev/null +++ b/drivers/gpu/drm/panel/bpf/progs/panel-bpf-mipi-dsi.h @@ -0,0 +1,95 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef ____PANEL_BPF_MIPI_DSI_BPF__H +#define ____PANEL_BPF_MIPI_DSI_BPF__H + +#define PANEL_BPF_MIPI_DSI_PREPARE "struct_ops.s/panel_prepare" +#define PANEL_BPF_MIPI_DSI_UNPREPARE "struct_ops.s/panel_unprepare" +#define PANEL_BPF_MIPI_DSI_ENABLE "struct_ops.s/panel_enable" +#define PANEL_BPF_MIPI_DSI_DISABLE "struct_ops.s/panel_disable" + +#define PANEL_BPF_MIPI_DSI_OPS(name) SEC(".struct_ops") \ + struct drm_panel_dsi_bpf_ops name + +/* Mode flags — kernel #defines not exported through BTF */ +#define MIPI_DSI_MODE_VIDEO (1 << 0) +#define MIPI_DSI_MODE_VIDEO_BURST (1 << 1) +#define MIPI_DSI_MODE_VIDEO_SYNC_PULSE (1 << 2) +#define MIPI_DSI_MODE_NO_EOT_PACKET (1 << 9) +#define MIPI_DSI_CLOCK_NON_CONTINUOUS (1 << 10) +#define MIPI_DSI_MODE_LPM (1 << 11) + +extern int panel_bpf_mipi_dsi_regulator_enable_and_wait(struct panel_bpf_mipi_dsi_ctx *ctx, + enum panel_bpf_mipi_dsi_supply supply, + __u32 settle_ms) __ksym; +extern int panel_bpf_mipi_dsi_regulator_disable(struct panel_bpf_mipi_dsi_ctx *ctx, + enum panel_bpf_mipi_dsi_supply supply) __ksym; +extern void panel_bpf_mipi_dsi_gpio_cycle_and_wait(struct panel_bpf_mipi_dsi_ctx *ctx, + enum panel_bpf_mipi_dsi_gpio gpio, + __u32 assert_ms, + __u32 settle_ms) __ksym; +extern void panel_bpf_mipi_dsi_gpio_enable(struct panel_bpf_mipi_dsi_ctx *ctx, + enum panel_bpf_mipi_dsi_gpio gpio) __ksym; +extern void panel_bpf_mipi_dsi_gpio_disable(struct panel_bpf_mipi_dsi_ctx *ctx, + enum panel_bpf_mipi_dsi_gpio gpio) __ksym; +extern int panel_bpf_mipi_dsi_dcs_write_and_wait(struct panel_bpf_mipi_dsi_ctx *ctx, + __u8 cmd, const __u8 *data, + __u32 data__sz, + __u32 settle_ms) __ksym; +extern int panel_bpf_mipi_dsi_generic_write_and_wait(struct panel_bpf_mipi_dsi_ctx *ctx, + const __u8 *data, + __u32 data__sz, + __u32 settle_ms) __ksym; +extern int panel_bpf_mipi_dsi_dcs_read(struct panel_bpf_mipi_dsi_ctx *ctx, + __u8 cmd, __u8 *data, + __u32 data__sz) __ksym; + +/* + * Convenience macros + * + * These wrap the _and_wait kfuncs with settle_ms = 0 for the common + * case where no post-operation delay is needed. + */ + +/* Enable a supply without a post-enable delay. */ +#define panel_bpf_mipi_dsi_regulator_enable(ctx, supply) \ + panel_bpf_mipi_dsi_regulator_enable_and_wait((ctx), (supply), 0) + +/* Send a DCS command without a post-send delay. */ +#define panel_bpf_mipi_dsi_dcs_write(ctx, cmd, data, data__sz) \ + panel_bpf_mipi_dsi_dcs_write_and_wait((ctx), (cmd), (data), (data__sz), 0) + +/* Send a generic DSI write without a post-send delay. */ +#define panel_bpf_mipi_dsi_generic_write(ctx, data, data__sz) \ + panel_bpf_mipi_dsi_generic_write_and_wait((ctx), (data), (data__sz), 0) + +/* Send a DCS command with a single byte payload. */ +#define panel_bpf_mipi_dsi_dcs_write_byte(ctx, cmd, val) \ + do { \ + const __u8 _v = (val); \ + panel_bpf_mipi_dsi_dcs_write((ctx), (cmd), &_v, 1); \ + } while (0) + +/* + * Standard DCS command helpers + * + * exit_sleep_mode and enter_sleep_mode include the 120ms delay + * required by the MIPI DCS specification before the next command. + */ + +/* Send MIPI_DCS_EXIT_SLEEP_MODE with a 120ms settling delay. */ +#define panel_bpf_mipi_dsi_exit_sleep_mode(ctx) \ + panel_bpf_mipi_dsi_dcs_write_and_wait((ctx), MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0, 120) + +/* Send MIPI_DCS_ENTER_SLEEP_MODE with a 120ms settling delay. */ +#define panel_bpf_mipi_dsi_enter_sleep_mode(ctx) \ + panel_bpf_mipi_dsi_dcs_write_and_wait((ctx), MIPI_DCS_ENTER_SLEEP_MODE, NULL, 0, 120) + +/* Send MIPI_DCS_SET_DISPLAY_ON. */ +#define panel_bpf_mipi_dsi_set_display_on(ctx) \ + panel_bpf_mipi_dsi_dcs_write((ctx), MIPI_DCS_SET_DISPLAY_ON, NULL, 0) + +/* Send MIPI_DCS_SET_DISPLAY_OFF. */ +#define panel_bpf_mipi_dsi_set_display_off(ctx) \ + panel_bpf_mipi_dsi_dcs_write((ctx), MIPI_DCS_SET_DISPLAY_OFF, NULL, 0) + +#endif /* ____PANEL_BPF_MIPI_DSI_BPF__H */ diff --git a/include/drm/drm_panel_dsi_bpf.h b/include/drm/drm_panel_dsi_bpf.h deleted file mode 100644 index 02d4707fd0a0..000000000000 --- a/include/drm/drm_panel_dsi_bpf.h +++ /dev/null @@ -1,50 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __DRM_PANEL_DSI_BPF_H__ -#define __DRM_PANEL_DSI_BPF_H__ - -#include <linux/bpf.h> - -struct mipi_dsi_device; -struct drm_panel; - -#define DSI_BPF_PANEL_ID_LEN 64 - -/** - * struct dsi_bpf_ctx - Context passed to BPF panel programs - * @panel: The drm_panel this callback operates on (private) - */ -struct dsi_bpf_ctx { - struct drm_panel *panel; -}; - -/** - * struct drm_panel_dsi_bpf_ops - BPF struct_ops for MIPI-DSI panels - * @panel_id: Device identifier for matching. On DT systems this holds - * the panel's compatible string. Firmware-agnostic to allow future - * ACPI support. Written before load, immutable after. - * @panel_prepare: Called to power on the panel and send init commands. - * Must enable regulators, toggle GPIOs, and send the DSI init - * sequence. Sleepable. - * @panel_unprepare: Called to power off the panel. Must send shutdown - * commands, assert reset, and disable regulators. Sleepable. - * @panel_enable: Optional. Called after video stream starts, for panels - * that need post-video-start DSI commands. Sleepable. - * @panel_disable: Optional. Called before video stream stops. Sleepable. - * @set_brightness: Optional. Called to set backlight brightness via DSI - * commands. Sleepable. - */ -struct drm_panel_dsi_bpf_ops { - char panel_id[DSI_BPF_PANEL_ID_LEN]; - - /* private: internal bookkeeping */ - struct drm_panel *panel; - - /* public: */ - int (*panel_prepare)(struct dsi_bpf_ctx *ctx); - int (*panel_unprepare)(struct dsi_bpf_ctx *ctx); - int (*panel_enable)(struct dsi_bpf_ctx *ctx); - int (*panel_disable)(struct dsi_bpf_ctx *ctx); - int (*set_brightness)(struct dsi_bpf_ctx *ctx, u32 brightness); -}; - -#endif /* __DRM_PANEL_DSI_BPF_H__ */ -- 2.55.0
