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

Reply via email to