From 22b792ff38ac07b40d4f6b9918828126503a6364 Mon Sep 17 00:00:00 2001 From: Hao Yao Date: Fri, 27 Sep 2024 16:58:48 +0800 Subject: [PATCH] ARL platform PV release candidate on 2024-09-27 Signed-off-by: Hao Yao --- .github/workflows/test.yml | 76 +- Makefile | 7 +- README.md | 19 +- dkms.conf | 64 +- drivers/media/i2c/ov01a1s.c | 216 +-- drivers/media/i2c/ov05c10.c | 27 +- drivers/media/pci/intel/Makefile | 13 - drivers/media/pci/intel/ipu-isys-video.c | 20 - drivers/media/pci/intel/ipu.c | 5 +- drivers/media/pci/intel/ipu6/Makefile | 22 +- drivers/media/pci/intel/ipu6/ipu-platform.h | 2 +- drivers/media/pci/intel/ipu6/psys/Makefile | 28 + .../pci/intel/{ => ipu6/psys}/ipu-fw-psys.c | 201 +++ .../pci/intel/{ => ipu6/psys}/ipu-fw-psys.h | 0 .../intel/ipu6/{ => psys}/ipu-fw-resources.c | 0 .../intel/ipu6/{ => psys}/ipu-platform-psys.h | 0 .../ipu6/{ => psys}/ipu-platform-resources.h | 0 .../intel/{ => ipu6/psys}/ipu-psys-compat32.c | 0 .../pci/intel/{ => ipu6/psys}/ipu-psys.c | 699 +++++++++- .../pci/intel/{ => ipu6/psys}/ipu-psys.h | 137 +- .../pci/intel/ipu6/{ => psys}/ipu-resources.c | 43 + .../intel/ipu6/{ => psys}/ipu6-fw-resources.c | 69 + .../intel/ipu6/{ => psys}/ipu6-l-scheduler.c | 98 ++ .../ipu6/{ => psys}/ipu6-platform-resources.h | 0 .../pci/intel/ipu6/{ => psys}/ipu6-ppg.c | 369 +++++ .../pci/intel/ipu6/{ => psys}/ipu6-ppg.h | 0 .../pci/intel/ipu6/{ => psys}/ipu6-psys-gpc.c | 0 .../pci/intel/ipu6/{ => psys}/ipu6-psys.c | 290 ++++ .../ipu6/{ => psys}/ipu6ep-fw-resources.c | 0 .../{ => psys}/ipu6ep-platform-resources.h | 0 .../ipu6/{ => psys}/ipu6se-fw-resources.c | 20 + .../{ => psys}/ipu6se-platform-resources.h | 0 ...dule-parameter-to-set-isys-psys-freq.patch | 64 + ...-disable-ATS-when-CPU-is-not-Metero-.patch | 39 + .../0001-workaround-patch-to-build-psys.patch | 22 + ...0001-v6.10-IPU6-headers-used-by-PSYS.patch | 1198 +++++++++++++++++ 36 files changed, 3521 insertions(+), 227 deletions(-) delete mode 100644 drivers/media/pci/intel/Makefile create mode 100644 drivers/media/pci/intel/ipu6/psys/Makefile rename drivers/media/pci/intel/{ => ipu6/psys}/ipu-fw-psys.c (68%) rename drivers/media/pci/intel/{ => ipu6/psys}/ipu-fw-psys.h (100%) rename drivers/media/pci/intel/ipu6/{ => psys}/ipu-fw-resources.c (100%) rename drivers/media/pci/intel/ipu6/{ => psys}/ipu-platform-psys.h (100%) rename drivers/media/pci/intel/ipu6/{ => psys}/ipu-platform-resources.h (100%) rename drivers/media/pci/intel/{ => ipu6/psys}/ipu-psys-compat32.c (100%) rename drivers/media/pci/intel/{ => ipu6/psys}/ipu-psys.c (72%) rename drivers/media/pci/intel/{ => ipu6/psys}/ipu-psys.h (58%) rename drivers/media/pci/intel/ipu6/{ => psys}/ipu-resources.c (94%) rename drivers/media/pci/intel/ipu6/{ => psys}/ipu6-fw-resources.c (87%) rename drivers/media/pci/intel/ipu6/{ => psys}/ipu6-l-scheduler.c (85%) rename drivers/media/pci/intel/ipu6/{ => psys}/ipu6-platform-resources.h (100%) rename drivers/media/pci/intel/ipu6/{ => psys}/ipu6-ppg.c (59%) rename drivers/media/pci/intel/ipu6/{ => psys}/ipu6-ppg.h (100%) rename drivers/media/pci/intel/ipu6/{ => psys}/ipu6-psys-gpc.c (100%) rename drivers/media/pci/intel/ipu6/{ => psys}/ipu6-psys.c (75%) rename drivers/media/pci/intel/ipu6/{ => psys}/ipu6ep-fw-resources.c (100%) rename drivers/media/pci/intel/ipu6/{ => psys}/ipu6ep-platform-resources.h (100%) rename drivers/media/pci/intel/ipu6/{ => psys}/ipu6se-fw-resources.c (90%) rename drivers/media/pci/intel/ipu6/{ => psys}/ipu6se-platform-resources.h (100%) create mode 100644 patch/v6.10/0002-use-module-parameter-to-set-isys-psys-freq.patch create mode 100644 patch/v6.10/0003-media-ipu6-Don-t-disable-ATS-when-CPU-is-not-Metero-.patch create mode 100644 patch/v6.10/in-tree-build/0001-workaround-patch-to-build-psys.patch create mode 100644 patches/0001-v6.10-IPU6-headers-used-by-PSYS.patch diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e3474a3de224..70d4425b8db0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -80,6 +80,64 @@ jobs: exit 1 fi echo "#### Successful builds for kernels: ${succeeded}"; + Ubuntu-2404-dkms: + runs-on: ubuntu-latest + container: ubuntu:24.04 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Prepare environment + shell: bash + run: | + sed -i 's/noble noble-updates noble-backports/noble noble-updates noble-backports noble-proposed/' /etc/apt/sources.list.d/ubuntu.sources + apt-get update --quiet; + apt-get install --yes --no-install-recommends dkms gpg-agent kmod software-properties-common sudo + + - name: Download header files + shell: bash + run: | + # latest generic kernel headers + apt-get install --yes linux-headers-generic linux-headers-generic-hwe-24.04-edge + # latest oem kernel + apt-get install --yes linux-headers-oem-24.04 linux-headers-oem-24.04a linux-headers-oem-24.04b + + - name: Register with dkms + shell: bash + run: | + dkms add . + + - name: Compile driver + shell: bash + run: | + # run dkms build and all available kernel headers + failed="" + succeeded="" + for kver in /lib/modules/*/build; do + # skip the kernel headers from the azure kernel. These kernel headers + # are preinstalled and of no interest + if [[ "$kver" == *"azure"* ]]; then + echo "Skipping $kver - This is the kernel of the github runner."; + continue; + fi; + test -d $kver || continue + kver=${kver%/build} + kver=${kver##*/} + echo "=== Testing ${kver} ==="; + echo "running: dkms build -m ipu6-drivers/0.0.0 -k ${kver}"; + ret=$(sudo dkms build -m ipu6-drivers/0.0.0 -k ${kver} >&2; echo $?); + if [ ${ret} -eq 0 ]; then + succeeded="${succeeded} ${kver}" + else + echo "#### Skipped unexpected failure ${kver}"; + failed="${failed} ${kver}"; + fi; + done + if [ "x${failed}" != "x" ]; then + echo "#### Failed kernels: ${failed}"; + exit 1 + fi + echo "#### Successful builds for kernels: ${succeeded}"; Ubuntu-rolling-dkms: runs-on: ubuntu-latest @@ -112,8 +170,8 @@ jobs: # Add unstable kernel ppa add-apt-repository ppa:canonical-kernel-team/unstable apt-get update --quiet; - # latest and wip generic kernel headers - apt-get install --yes linux-headers-generic linux-headers-generic-wip + # latest generic kernel headers + apt-get install --yes linux-headers-generic # latest oem kernel apt-get install --yes linux-headers-oem-22.04 @@ -160,18 +218,6 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Checkout ivsc-driver repo - uses: actions/checkout@v4 - with: - repository: intel/ivsc-driver - path: ivsc-driver - - - name: Merge with ivsc-driver - shell: bash - run: | - cp -r ivsc-driver/backport-include ivsc-driver/drivers ivsc-driver/include . - rm -rf ivsc-driver - - name: Prepare environment shell: bash run: | @@ -211,6 +257,8 @@ jobs: ret=$(sudo dkms build -m ipu6-drivers/0.0.0 -k ${kver} >&2; echo $?); if [ ${ret} -eq 0 ]; then succeeded="${succeeded} ${kver}" + elif [ ${ret} -eq 77 ]; then + echo "#### Config of ${kver} doesn't support"; else echo "#### Skipped unexpected failure ${kver}"; failed="${failed} ${kver}"; diff --git a/Makefile b/Makefile index b268b643cce9..49b27300a7fc 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,7 @@ KV_IVSC := 6.6.0 KV_IPU_BRIDGE := 6.6.0 KV_OV2740 := 6.8.0 KV_OV05C10 := 6.8.0 +KV_IPU6_ISYS := 6.10.0 KERNEL_SRC ?= /lib/modules/$(KERNELRELEASE)/build MODSRC := $(shell pwd) @@ -74,7 +75,11 @@ export CONFIG_IPU_ISYS_BRIDGE = y export CONFIG_IPU_BRIDGE = n endif export EXTERNAL_BUILD = 1 -obj-y += drivers/media/pci/intel/ +ifeq ($(call version_lt,$(KERNEL_VERSION),$(KV_IPU6_ISYS)),true) +obj-y += drivers/media/pci/intel/ipu6/ +else +obj-y += drivers/media/pci/intel/ipu6/psys/ +endif export CONFIG_VIDEO_HM11B1 = m export CONFIG_VIDEO_OV01A1S = m diff --git a/README.md b/README.md index 0867b4a59361..638aa8f3dba0 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Three ways are available: 3. and build with dkms ### 1. Build with kernel source tree -- Tested with kernel v6.8 +- Tested with kernel v6.10 - Check out kernel - Apply patches: ```sh @@ -47,10 +47,23 @@ Three ways are available: # For kernel version v6.8 patch/v6.8/*.patch + + # For kernel version v6.10 + patch/v6.10/in-tree-build/*.patch + patch/v6.10/*.patch ``` - For kernel v6.8. patch/v6.8/0002-media-Add-IPU6-and-supported-sensors-config.patch will change the related Kconfig & Makefile. +- For kernel v6.10. patch/v6.10/in-tree-build/0001-workaround-patch-to-build-psys.patch will change the Makefile to build IPU6 PSYS driver. - For latest linux-firmware repo, apply patch/linux-firmware/0001-Add-symbolic-link-for-Intel-IPU6-firmwares.patch to it to make driver work. -- Copy `drivers` and `include` folders to kernel source **(except Kconfig & Makefile at drivers/media/pci/intel and drivers/media/i2c as they are modified by patches in previous step. You can delete them before you copy folders.)**. +- For kernel v6.10 and above, copy only drivers you need to kernel source: +```sh +# Out-Of-Tree IPU6 PSYS driver +cp -r drivers/media/pci/intel/ipu6/psys /drivers/media/pci/intel/ipu6/ +cp include/uapi/linux/ipu-psys.h /include/uapi/linux/ +# Out-Of-Tree I2C sensor drivers +cp -r drivers/media/i2c /drivers/media/i2c +``` +- For kernel version less than v6.10, copy `drivers` and `include` folders to kernel source **(except Kconfig & Makefile at drivers/media/pci/intel and drivers/media/i2c as they are modified by patches in previous step. You can delete them before you copy folders.)**. - Enable the following settings in .config ```conf @@ -87,6 +100,8 @@ Three ways are available: ``` ### 2. Build outside kernel source tree - Requires kernel header installed on build machine +- For kernel >= v6.10, need to patch this repo by ipu6-drivers/patches/*.patch (which can be automatically applied if you use DKMS build). +- For kernel >= v6.10, need to patch your kernel by patch/v6.10/*.patch. - For kernel >= v6.8, still need to patch kernel by patch/v6.8/0004 & 0005 to make upstream iVSC driver work correctly. For kernel <= v6.6, requires iVSC out-of-tree driver be built together. - To prepare out-of-tree iVSC driver under kernel <= v6.6: ```sh diff --git a/dkms.conf b/dkms.conf index 635f518d4eb9..81bfc32e3cf8 100644 --- a/dkms.conf +++ b/dkms.conf @@ -4,6 +4,7 @@ PACKAGE_VERSION=0.0.0 MAKE="make KERNELRELEASE=$kernelver KERNEL_SRC=$kernel_source_dir" CLEAN="make KERNELRELEASE=$kernelver KERNEL_SRC=$kernel_source_dir clean" AUTOINSTALL="yes" +BUILD_EXCLUSIVE_CONFIG="CONFIG_VIDEO_V4L2_I2C" version_lt() { IFS='.' read -r i j k <<< "$1" @@ -33,61 +34,68 @@ KERNEL_VERSION=$(echo ${kernelver} | sed 's/[^0-9.]*\([0-9.]*\).*/\1/') KV_IVSC=6.6.0 KV_OV2740=6.8.0 KV_OV05C10=6.8.0 +KV_IPU6_ISYS=6.10.0 -BUILT_MODULE_NAME[0]="intel-ipu6" -BUILT_MODULE_LOCATION[0]="drivers/media/pci/intel/ipu6" +BUILT_MODULE_NAME[0]="hm11b1" +BUILT_MODULE_LOCATION[0]="drivers/media/i2c" DEST_MODULE_LOCATION[0]="/updates" -BUILT_MODULE_NAME[1]="intel-ipu6-isys" -BUILT_MODULE_LOCATION[1]="drivers/media/pci/intel/ipu6" +BUILT_MODULE_NAME[1]="ov01a1s" +BUILT_MODULE_LOCATION[1]="drivers/media/i2c" DEST_MODULE_LOCATION[1]="/updates" -BUILT_MODULE_NAME[2]="intel-ipu6-psys" -BUILT_MODULE_LOCATION[2]="drivers/media/pci/intel/ipu6" +BUILT_MODULE_NAME[2]="ov01a10" +BUILT_MODULE_LOCATION[2]="drivers/media/i2c" DEST_MODULE_LOCATION[2]="/updates" -BUILT_MODULE_NAME[3]="hm11b1" +BUILT_MODULE_NAME[3]="ov02c10" BUILT_MODULE_LOCATION[3]="drivers/media/i2c" DEST_MODULE_LOCATION[3]="/updates" -BUILT_MODULE_NAME[4]="ov01a1s" +BUILT_MODULE_NAME[4]="ov02e10" BUILT_MODULE_LOCATION[4]="drivers/media/i2c" DEST_MODULE_LOCATION[4]="/updates" -BUILT_MODULE_NAME[5]="ov01a10" +BUILT_MODULE_NAME[5]="hm2170" BUILT_MODULE_LOCATION[5]="drivers/media/i2c" DEST_MODULE_LOCATION[5]="/updates" -BUILT_MODULE_NAME[6]="ov02c10" +BUILT_MODULE_NAME[6]="hm2172" BUILT_MODULE_LOCATION[6]="drivers/media/i2c" DEST_MODULE_LOCATION[6]="/updates" -BUILT_MODULE_NAME[7]="ov02e10" +BUILT_MODULE_NAME[7]="hi556" BUILT_MODULE_LOCATION[7]="drivers/media/i2c" DEST_MODULE_LOCATION[7]="/updates" -BUILT_MODULE_NAME[8]="hm2170" -BUILT_MODULE_LOCATION[8]="drivers/media/i2c" -DEST_MODULE_LOCATION[8]="/updates" +if ! version_lt ${KERNEL_VERSION} ${KV_OV05C10}; then + BUILD_EXCLUSIVE_CONFIG="CONFIG_VIDEO_V4L2_I2C CONFIG_V4L2_CCI_I2C" + BUILT_MODULE_NAME[8]="ov05c10" + BUILT_MODULE_LOCATION[8]="drivers/media/i2c" + DEST_MODULE_LOCATION[8]="/updates" +fi -BUILT_MODULE_NAME[9]="hm2172" -BUILT_MODULE_LOCATION[9]="drivers/media/i2c" -DEST_MODULE_LOCATION[9]="/updates" +if version_lt ${KERNEL_VERSION} ${KV_OV2740}; then + BUILT_MODULE_NAME[8]="ov2740" + BUILT_MODULE_LOCATION[8]="drivers/media/i2c" + DEST_MODULE_LOCATION[8]="/updates" +fi -BUILT_MODULE_NAME[10]="hi556" -BUILT_MODULE_LOCATION[10]="drivers/media/i2c" -DEST_MODULE_LOCATION[10]="/updates" +if ! version_lt ${KERNEL_VERSION} ${KV_IPU6_ISYS}; then + PATCH[0]="0001-v6.10-IPU6-headers-used-by-PSYS.patch" +fi +BUILT_MODULE_NAME[9]="intel-ipu6-psys" +BUILT_MODULE_LOCATION[9]="drivers/media/pci/intel/ipu6/psys" +DEST_MODULE_LOCATION[9]="/updates" -if ! version_lt ${KERNEL_VERSION} ${KV_OV05C10}; then - BUILT_MODULE_NAME[11]="ov05c10" - BUILT_MODULE_LOCATION[11]="drivers/media/i2c" - DEST_MODULE_LOCATION[11]="/updates" -fi +if version_lt ${KERNEL_VERSION} ${KV_IPU6_ISYS}; then + BUILT_MODULE_NAME[10]="intel-ipu6" + BUILT_MODULE_LOCATION[10]="drivers/media/pci/intel/ipu6" + DEST_MODULE_LOCATION[10]="/updates" -if version_lt ${KERNEL_VERSION} ${KV_OV2740}; then - BUILT_MODULE_NAME[11]="ov2740" - BUILT_MODULE_LOCATION[11]="drivers/media/i2c" + BUILT_MODULE_NAME[11]="intel-ipu6-isys" + BUILT_MODULE_LOCATION[11]="drivers/media/pci/intel/ipu6" DEST_MODULE_LOCATION[11]="/updates" fi diff --git a/drivers/media/i2c/ov01a1s.c b/drivers/media/i2c/ov01a1s.c index f7cf2218cd0a..18704abf5579 100644 --- a/drivers/media/i2c/ov01a1s.c +++ b/drivers/media/i2c/ov01a1s.c @@ -18,8 +18,16 @@ #include "power_ctrl_logic.h" #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0) && \ - IS_ENABLED(CONFIG_INTEL_VSC) +IS_ENABLED(CONFIG_INTEL_VSC) #include + +static const struct acpi_device_id cvfd_ids[] = { + { "INTC1059", 0 }, + { "INTC1095", 0 }, + { "INTC100A", 0 }, + { "INTC10CF", 0 }, + { } +}; #endif #define OV01A1S_LINK_FREQ_400MHZ 400000000ULL @@ -304,7 +312,7 @@ struct ov01a1s { struct v4l2_ctrl *hblank; struct v4l2_ctrl *exposure; #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0) && \ - IS_ENABLED(CONFIG_INTEL_VSC) +IS_ENABLED(CONFIG_INTEL_VSC) struct v4l2_ctrl *privacy_status; /* VSC settings */ @@ -338,7 +346,7 @@ struct ov01a1s { OV01A1S_USE_INT3472 = 1, #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0) && \ - IS_ENABLED(CONFIG_INTEL_VSC) +IS_ENABLED(CONFIG_INTEL_VSC) OV01A1S_USE_INTEL_VSC = 2, #endif } power_type; @@ -352,7 +360,8 @@ static inline struct ov01a1s *to_ov01a1s(struct v4l2_subdev *subdev) return container_of(subdev, struct ov01a1s, sd); } -static int ov01a1s_read_reg(struct ov01a1s *ov01a1s, u16 reg, u16 len, u32 *val) +static int ov01a1s_read_reg(struct ov01a1s *ov01a1s, u16 reg, u16 len, + u32 *val) { struct i2c_client *client = ov01a1s->client; struct i2c_msg msgs[2]; @@ -430,23 +439,27 @@ static int ov01a1s_update_digital_gain(struct ov01a1s *ov01a1s, u32 d_gain) ret = ov01a1s_write_reg(ov01a1s, OV01A1S_REG_DIGILAL_GAIN_B, 3, real); if (ret) { - dev_err(&client->dev, "failed to set OV01A1S_REG_DIGITAL_GAIN_B"); + dev_err(&client->dev, + "failed to set OV01A1S_REG_DIGITAL_GAIN_B"); return ret; } ret = ov01a1s_write_reg(ov01a1s, OV01A1S_REG_DIGITAL_GAIN_GB, 3, real); if (ret) { - dev_err(&client->dev, "failed to set OV01A1S_REG_DIGITAL_GAIN_GB"); + dev_err(&client->dev, + "failed to set OV01A1S_REG_DIGITAL_GAIN_GB"); return ret; } ret = ov01a1s_write_reg(ov01a1s, OV01A1S_REG_DIGITAL_GAIN_GR, 3, real); if (ret) { - dev_err(&client->dev, "failed to set OV01A1S_REG_DIGITAL_GAIN_GR"); + dev_err(&client->dev, + "failed to set OV01A1S_REG_DIGITAL_GAIN_GR"); return ret; } ret = ov01a1s_write_reg(ov01a1s, OV01A1S_REG_DIGITAL_GAIN_R, 3, real); if (ret) { - dev_err(&client->dev, "failed to set OV01A1S_REG_DIGITAL_GAIN_R"); + dev_err(&client->dev, + "failed to set OV01A1S_REG_DIGITAL_GAIN_R"); return ret; } return ret; @@ -509,7 +522,7 @@ static int ov01a1s_set_ctrl(struct v4l2_ctrl *ctrl) break; #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0) && \ - IS_ENABLED(CONFIG_INTEL_VSC) +IS_ENABLED(CONFIG_INTEL_VSC) case V4L2_CID_PRIVACY: dev_dbg(&client->dev, "set privacy to %d", ctrl->val); break; @@ -540,7 +553,7 @@ static int ov01a1s_init_controls(struct ov01a1s *ov01a1s) ctrl_hdlr = &ov01a1s->ctrl_handler; #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0) && \ - IS_ENABLED(CONFIG_INTEL_VSC) +IS_ENABLED(CONFIG_INTEL_VSC) ret = v4l2_ctrl_handler_init(ctrl_hdlr, 9); #else ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8); @@ -578,11 +591,12 @@ static int ov01a1s_init_controls(struct ov01a1s *ov01a1s) if (ov01a1s->hblank) ov01a1s->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0) && \ - IS_ENABLED(CONFIG_INTEL_VSC) +IS_ENABLED(CONFIG_INTEL_VSC) ov01a1s->privacy_status = v4l2_ctrl_new_std(ctrl_hdlr, &ov01a1s_ctrl_ops, V4L2_CID_PRIVACY, - 0, 1, 1, 0); + 0, 1, 1, + !(ov01a1s->status.status)); #endif v4l2_ctrl_new_std(ctrl_hdlr, &ov01a1s_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, @@ -620,9 +634,9 @@ static void ov01a1s_update_pad_format(const struct ov01a1s_mode *mode, } #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0) && \ - IS_ENABLED(CONFIG_INTEL_VSC) +IS_ENABLED(CONFIG_INTEL_VSC) static void ov01a1s_vsc_privacy_callback(void *handle, - enum vsc_privacy_status status) + enum vsc_privacy_status status) { struct ov01a1s *ov01a1s = handle; @@ -716,6 +730,14 @@ static int ov01a1s_power_off(struct device *dev) struct ov01a1s *ov01a1s = to_ov01a1s(sd); int ret = 0; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0) && \ +IS_ENABLED(CONFIG_INTEL_VSC) + if (ov01a1s->power_type == OV01A1S_USE_INTEL_VSC) { + ret = vsc_release_camera_sensor(&ov01a1s->status); + if (ret && ret != -EAGAIN) + dev_err(dev, "Release VSC failed"); + } +#endif #if IS_ENABLED(CONFIG_INTEL_SKL_INT3472) if (ov01a1s->power_type == OV01A1S_USE_INT3472) { gpiod_set_value_cansleep(ov01a1s->reset_gpio, 1); @@ -729,14 +751,6 @@ static int ov01a1s_power_off(struct device *dev) if (ov01a1s->power_type == OV01A1S_USE_INT3472) ret = power_ctrl_logic_set_power(0); #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0) && \ - IS_ENABLED(CONFIG_INTEL_VSC) - if (ov01a1s->power_type == OV01A1S_USE_INTEL_VSC) { - ret = vsc_release_camera_sensor(&ov01a1s->status); - if (ret && ret != -EAGAIN) - dev_err(dev, "Release VSC failed"); - } -#endif return ret; } @@ -747,6 +761,28 @@ static int ov01a1s_power_on(struct device *dev) struct ov01a1s *ov01a1s = to_ov01a1s(sd); int ret = 0; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0) && \ +IS_ENABLED(CONFIG_INTEL_VSC) + if (ov01a1s->power_type == OV01A1S_USE_INTEL_VSC) { + ov01a1s->conf.lane_num = OV01A1S_DATA_LANES; + /* frequency unit 100k */ + ov01a1s->conf.freq = OV01A1S_LINK_FREQ_400MHZ / 100000; + ret = vsc_acquire_camera_sensor(&ov01a1s->conf, + ov01a1s_vsc_privacy_callback, + ov01a1s, &ov01a1s->status); + if (ret == -EAGAIN) + return -EPROBE_DEFER; + if (ret) { + dev_err(dev, "Acquire VSC failed"); + return ret; + } + if (ov01a1s->privacy_status) + __v4l2_ctrl_s_ctrl(ov01a1s->privacy_status, + !(ov01a1s->status.status)); + + return ret; + } +#endif #if IS_ENABLED(CONFIG_INTEL_SKL_INT3472) if (ov01a1s->power_type == OV01A1S_USE_INT3472) { ret = clk_prepare_enable(ov01a1s->clk); @@ -764,20 +800,6 @@ static int ov01a1s_power_on(struct device *dev) if (ov01a1s->power_type == OV01A1S_USE_INT3472) ret = power_ctrl_logic_set_power(1); #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0) && \ - IS_ENABLED(CONFIG_INTEL_VSC) - if (ov01a1s->power_type == OV01A1S_USE_INTEL_VSC) { - ret = vsc_acquire_camera_sensor(&ov01a1s->conf, - ov01a1s_vsc_privacy_callback, - ov01a1s, &ov01a1s->status); - if (ret && ret != -EAGAIN) { - dev_err(dev, "Acquire VSC failed"); - return ret; - } - __v4l2_ctrl_s_ctrl(ov01a1s->privacy_status, - !(ov01a1s->status.status)); - } -#endif return ret; } @@ -1082,77 +1104,70 @@ static void ov01a1s_remove(struct i2c_client *client) #endif } -#if IS_ENABLED(CONFIG_INTEL_SKL_INT3472) -static int ov01a1s_parse_gpio(struct ov01a1s *ov01a1s) +/* This function tries to get power control resources */ +static int ov01a1s_get_pm_resources(struct device *dev) { - struct device *dev = &ov01a1s->client->dev; - - ov01a1s->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(ov01a1s->reset_gpio)) { - dev_warn(dev, "error while getting reset gpio: %ld\n", - PTR_ERR(ov01a1s->reset_gpio)); - ov01a1s->reset_gpio = NULL; - return -EPROBE_DEFER; - } + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov01a1s *ov01a1s = to_ov01a1s(sd); + int ret; - /* For optional, don't return or print warn if can't get it */ - ov01a1s->powerdown_gpio = - devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_LOW); - if (IS_ERR(ov01a1s->powerdown_gpio)) { - dev_dbg(dev, "no powerdown gpio: %ld\n", - PTR_ERR(ov01a1s->powerdown_gpio)); - ov01a1s->powerdown_gpio = NULL; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0) && \ +IS_ENABLED(CONFIG_INTEL_VSC) + acpi_handle handle = ACPI_HANDLE(dev); + struct acpi_handle_list deps; + acpi_status status; + int i = 0; + + if (!acpi_has_method(handle, "_DEP")) + return false; + + status = acpi_evaluate_reference(handle, "_DEP", NULL, &deps); + if (ACPI_FAILURE(status)) { + acpi_handle_debug(handle, "Failed to evaluate _DEP.\n"); + return false; } + for (i = 0; i < deps.count; i++) { + struct acpi_device *dep = NULL; - ov01a1s->avdd = devm_regulator_get_optional(dev, "avdd"); - if (IS_ERR(ov01a1s->avdd)) { - dev_dbg(dev, "no regulator avdd: %ld\n", - PTR_ERR(ov01a1s->avdd)); - ov01a1s->avdd = NULL; - } + if (deps.handles[i]) +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0) + acpi_bus_get_device(deps.handles[i], &dep); +#else + dep = acpi_fetch_acpi_dev(deps.handles[i]); +#endif - ov01a1s->clk = devm_clk_get_optional(dev, "clk"); - if (IS_ERR(ov01a1s->clk)) { - dev_dbg(dev, "no clk: %ld\n", PTR_ERR(ov01a1s->clk)); - ov01a1s->clk = NULL; + if (dep && !acpi_match_device_ids(dep, cvfd_ids)) { + ov01a1s->power_type = OV01A1S_USE_INTEL_VSC; + return 0; + } } - - return 0; -} #endif +#if IS_ENABLED(CONFIG_INTEL_SKL_INT3472) + ov01a1s->reset_gpio = + devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(ov01a1s->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(ov01a1s->reset_gpio), + "failed to get reset gpio\n"); -static int ov01a1s_parse_power(struct ov01a1s *ov01a1s) -{ - int ret = 0; + ov01a1s->clk = devm_clk_get_optional(dev, NULL); + if (IS_ERR(ov01a1s->clk)) + return dev_err_probe(dev, PTR_ERR(ov01a1s->clk), + "failed to get imaging clock\n"); -#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0) && \ - IS_ENABLED(CONFIG_INTEL_VSC) - ov01a1s->conf.lane_num = OV01A1S_DATA_LANES; - /* frequency unit 100k */ - ov01a1s->conf.freq = OV01A1S_LINK_FREQ_400MHZ / 100000; - ret = vsc_acquire_camera_sensor(&ov01a1s->conf, NULL, NULL, &ov01a1s->status); - if (!ret) { - ov01a1s->power_type = OV01A1S_USE_INTEL_VSC; - return 0; - } else if (ret != -EAGAIN) { - return ret; + ov01a1s->avdd = devm_regulator_get_optional(dev, "avdd"); + if (IS_ERR(ov01a1s->avdd)) { + ret = PTR_ERR(ov01a1s->avdd); + ov01a1s->avdd = NULL; + if (ret != -ENODEV) + return dev_err_probe(dev, ret, + "failed to get avdd regulator\n"); } #endif -#if IS_ENABLED(CONFIG_INTEL_SKL_INT3472) - ret = ov01a1s_parse_gpio(ov01a1s); -#elif IS_ENABLED(CONFIG_POWER_CTRL_LOGIC) - ret = power_ctrl_logic_set_power(1); -#endif #if IS_ENABLED(CONFIG_INTEL_SKL_INT3472) || IS_ENABLED(CONFIG_POWER_CTRL_LOGIC) - if (!ret) { - ov01a1s->power_type = OV01A1S_USE_INT3472; - return 0; - } + ov01a1s->power_type = OV01A1S_USE_INT3472; #endif - if (ret == -EAGAIN) - return -EPROBE_DEFER; - return ret; + return 0; } static int ov01a1s_probe(struct i2c_client *client) @@ -1172,16 +1187,15 @@ static int ov01a1s_probe(struct i2c_client *client) return -ENOMEM; ov01a1s->client = client; - ret = ov01a1s_parse_power(ov01a1s); - if (ret) + v4l2_i2c_subdev_init(&ov01a1s->sd, client, &ov01a1s_subdev_ops); + ov01a1s_get_pm_resources(&client->dev); + + ret = ov01a1s_power_on(&client->dev); + if (ret) { + dev_err_probe(&client->dev, ret, "failed to power on\n"); return ret; + } - v4l2_i2c_subdev_init(&ov01a1s->sd, client, &ov01a1s_subdev_ops); -#if IS_ENABLED(CONFIG_INTEL_SKL_INT3472) - /* In other cases, power is up in ov01a1s_parse_power */ - if (ov01a1s->power_type == OV01A1S_USE_INT3472) - ov01a1s_power_on(&client->dev); -#endif ret = ov01a1s_identify_module(ov01a1s); if (ret) { dev_err(&client->dev, "failed to find sensor: %d", ret); diff --git a/drivers/media/i2c/ov05c10.c b/drivers/media/i2c/ov05c10.c index bce60998cd41..ea3fa41db89f 100644 --- a/drivers/media/i2c/ov05c10.c +++ b/drivers/media/i2c/ov05c10.c @@ -1,9 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2024 Intel Corporation. -#include #include #include +#include #include #include #include @@ -46,7 +46,7 @@ #define OV05C10_DGTL_GAIN_DEFAULT 0x40 #define OV05C10_VTS_MAX 0xffff -#define OV05C10_PPL 3234 +#define OV05C10_PPL 3236 #define OV05C10_DEFAULT_VTS 1860 #define PIXEL_RATE 192000000ULL #define OV05C10_NATIVE_WIDTH 2888 @@ -300,17 +300,16 @@ struct ov05c10 { struct clk *img_clk; struct regulator *avdd; struct gpio_desc *reset; - struct gpio_desc *pwdn_gpio; }; -static int ov05c10_test_pattern(struct ov05c10 *ov05c10, u32 pattern_menu) +static int ov05c10_test_pattern(struct ov05c10 *ov05c10, u32 pattern) { int ret; ret = cci_write(ov05c10->regmap, REG_PAGE_FLAG, 0x04, NULL); if (ret) return ret; - if (pattern_menu) + if (pattern) return cci_multi_reg_write(ov05c10->regmap, ov05c10_test_enable, ARRAY_SIZE(ov05c10_test_enable), @@ -330,6 +329,7 @@ static int ov05c10_set_ctrl(struct v4l2_ctrl *ctrl) struct v4l2_subdev_state *state; const struct v4l2_mbus_framefmt *format; s64 exposure_max; + u64 vts; int ret; state = v4l2_subdev_get_locked_active_state(&ov05c10->sd); @@ -344,6 +344,16 @@ static int ov05c10_set_ctrl(struct v4l2_ctrl *ctrl) ov05c10->exposure->minimum, exposure_max, ov05c10->exposure->step, ov05c10->cur_mode->height - OV05C10_EXPOSURE_MARGIN); + + /* + * REG_TIMING_VTS is read-only and increased by writing to + * REG_DUMMY_LINE in ov05c10. The calculation formula is + * required VTS = dummyline + current VTS. + * Here get the current VTS and calculate the required dummyline. + */ + cci_read(ov05c10->regmap, REG_TIMING_VTS, &vts, NULL); + ctrl->val += format->height; + ctrl->val = (ctrl->val > vts) ? ctrl->val - vts : 0; } /* V4L2 controls values will be applied only when power is already up */ if (!pm_runtime_get_if_in_use(&client->dev)) @@ -369,8 +379,6 @@ static int ov05c10_set_ctrl(struct v4l2_ctrl *ctrl) ctrl->val, NULL); break; case V4L2_CID_VBLANK: - ctrl->val = ctrl->val - - (OV05C10_DEFAULT_VTS - ov05c10->cur_mode->height); ret = cci_write(ov05c10->regmap, REG_DUMMY_LINE, ctrl->val, NULL); break; @@ -936,10 +944,9 @@ static int ov05c10_probe(struct i2c_client *client) * Device is already turned on by i2c-core with ACPI domain PM. * Enable runtime PM and turn off the device. */ - pm_runtime_set_active(&client->dev); + if (full_power) + pm_runtime_set_active(&client->dev); pm_runtime_enable(&client->dev); - pm_runtime_set_autosuspend_delay(&client->dev, 1000); - pm_runtime_use_autosuspend(&client->dev); pm_runtime_idle(&client->dev); ret = v4l2_async_register_subdev_sensor(&ov05c10->sd); if (ret < 0) { diff --git a/drivers/media/pci/intel/Makefile b/drivers/media/pci/intel/Makefile deleted file mode 100644 index 19fe3aab1a18..000000000000 --- a/drivers/media/pci/intel/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Copyright (c) 2010 - 2020 Intel Corporation. - -# force check the compile warning to make sure zero warnings -# note we may have build issue when gcc upgraded. -subdir-ccflags-y := -Wall -Wextra -subdir-ccflags-y += $(call cc-disable-warning, unused-parameter) -subdir-ccflags-y += $(call cc-disable-warning, implicit-fallthrough) -subdir-ccflags-y += $(call cc-disable-warning, missing-field-initializers) -subdir-ccflags-y += $(call cc-disable-warning, type-limits) -subdir-ccflags-$(CONFIG_VIDEO_INTEL_IPU_WERROR) += -Werror - -obj-$(CONFIG_VIDEO_INTEL_IPU6) += ipu6/ diff --git a/drivers/media/pci/intel/ipu-isys-video.c b/drivers/media/pci/intel/ipu-isys-video.c index 92b369d7df9e..3e2b31fa2c2a 100644 --- a/drivers/media/pci/intel/ipu-isys-video.c +++ b/drivers/media/pci/intel/ipu-isys-video.c @@ -1788,23 +1788,6 @@ int ipu_isys_video_set_streaming(struct ipu_isys_video *av, return rval; } -#ifdef CONFIG_COMPAT -static long ipu_isys_compat_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - long ret = -ENOIOCTLCMD; - void __user *up = compat_ptr(arg); - - /* - * at present, there is not any private IOCTL need to compat handle - */ - if (file->f_op->unlocked_ioctl) - ret = file->f_op->unlocked_ioctl(file, cmd, (unsigned long)up); - - return ret; -} -#endif - static const struct v4l2_ioctl_ops ioctl_ops_mplane = { .vidioc_querycap = ipu_isys_vidioc_querycap, #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0) @@ -1838,9 +1821,6 @@ static const struct v4l2_file_operations isys_fops = { .owner = THIS_MODULE, .poll = vb2_fop_poll, .unlocked_ioctl = video_ioctl2, -#ifdef CONFIG_COMPAT - .compat_ioctl32 = ipu_isys_compat_ioctl, -#endif .mmap = vb2_fop_mmap, .open = video_open, .release = video_release, diff --git a/drivers/media/pci/intel/ipu.c b/drivers/media/pci/intel/ipu.c index eb5d46a47920..65cb6213d474 100644 --- a/drivers/media/pci/intel/ipu.c +++ b/drivers/media/pci/intel/ipu.c @@ -374,8 +374,9 @@ static int ipu_pci_config_setup(struct pci_dev *dev) pci_write_config_word(dev, PCI_COMMAND, pci_command); /* disable IPU6 PCI ATS on mtl ES2 */ - if (ipu_ver == IPU_VER_6EP_MTL && boot_cpu_data.x86_stepping == 0x2 && - pci_ats_supported(dev)) + if ((boot_cpu_data.x86_model == 0xac || + boot_cpu_data.x86_model == 0xaa) && + boot_cpu_data.x86_stepping == 0x2 && pci_ats_supported(dev)) pci_disable_ats(dev); /* no msi pci capability for IPU6EP */ diff --git a/drivers/media/pci/intel/ipu6/Makefile b/drivers/media/pci/intel/ipu6/Makefile index 23f8cdba47ae..1a3212fbac26 100644 --- a/drivers/media/pci/intel/ipu6/Makefile +++ b/drivers/media/pci/intel/ipu6/Makefile @@ -5,7 +5,7 @@ ifneq ($(EXTERNAL_BUILD), 1) srcpath := $(srctree) endif -ccflags-y += -DIPU_TPG_FRAME_SYNC -DIPU_PSYS_GPC \ +ccflags-y += -DIPU_TPG_FRAME_SYNC \ -DIPU_ISYS_GPC intel-ipu6-objs += ../ipu.o \ @@ -38,25 +38,9 @@ intel-ipu6-isys-objs += ../ipu-isys.o \ obj-$(CONFIG_VIDEO_INTEL_IPU6) += intel-ipu6-isys.o -intel-ipu6-psys-objs += ../ipu-psys.o \ - ipu6-psys.o \ - ipu-resources.o \ - ipu6-psys-gpc.o \ - ipu6-l-scheduler.o \ - ipu6-ppg.o - -intel-ipu6-psys-objs += ipu-fw-resources.o \ - ipu6-fw-resources.o \ - ipu6se-fw-resources.o \ - ipu6ep-fw-resources.o \ - ../ipu-fw-psys.o - -ifeq ($(CONFIG_COMPAT),y) -intel-ipu6-psys-objs += ../ipu-psys-compat32.o -endif - -obj-$(CONFIG_VIDEO_INTEL_IPU6) += intel-ipu6-psys.o +obj-$(CONFIG_VIDEO_INTEL_IPU6) += psys/ ccflags-y += -I$(srcpath)/$(src)/../../../../../include/ +ccflags-y += -I$(srcpath)/$(src)/psys/ ccflags-y += -I$(srcpath)/$(src)/../ ccflags-y += -I$(srcpath)/$(src)/ diff --git a/drivers/media/pci/intel/ipu6/ipu-platform.h b/drivers/media/pci/intel/ipu6/ipu-platform.h index 826fe5febf5e..d5ddbd9936cd 100644 --- a/drivers/media/pci/intel/ipu6/ipu-platform.h +++ b/drivers/media/pci/intel/ipu6/ipu-platform.h @@ -27,7 +27,7 @@ * that the software components which uses IPU driver can get the hw stepping * information. */ -#define IPU_MEDIA_DEV_MODEL_NAME "ipu6" +#define IPU_MEDIA_DEV_MODEL_NAME "ipu6-downstream" #define IPU6SE_ISYS_NUM_STREAMS IPU6SE_NONSECURE_STREAM_ID_MAX #define IPU6_ISYS_NUM_STREAMS IPU6_NONSECURE_STREAM_ID_MAX diff --git a/drivers/media/pci/intel/ipu6/psys/Makefile b/drivers/media/pci/intel/ipu6/psys/Makefile new file mode 100644 index 000000000000..fa638fcdfa27 --- /dev/null +++ b/drivers/media/pci/intel/ipu6/psys/Makefile @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0-only + +is_kernel_lt_6_10 = $(shell if [ $$(printf "6.10\n$(KERNELVERSION)" | sort -V | head -n1) != "6.10" ]; then echo 1; fi) +ifeq ($(is_kernel_lt_6_10), 1) +ifneq ($(EXTERNAL_BUILD), 1) +src := $(srctree)/$(src) +endif +endif + +intel-ipu6-psys-objs += ipu-psys.o \ + ipu6-psys.o \ + ipu-resources.o \ + ipu6-l-scheduler.o \ + ipu6-ppg.o + +intel-ipu6-psys-objs += ipu-fw-resources.o \ + ipu6-fw-resources.o \ + ipu6se-fw-resources.o \ + ipu6ep-fw-resources.o \ + ipu-fw-psys.o + +obj-$(CONFIG_VIDEO_INTEL_IPU6) += intel-ipu6-psys.o + +ifeq ($(is_kernel_lt_6_10), 1) +ccflags-y += -I$(src)/../ipu6/ +endif +ccflags-y += -I$(src)/../ +ccflags-y += -I$(src)/../../ diff --git a/drivers/media/pci/intel/ipu-fw-psys.c b/drivers/media/pci/intel/ipu6/psys/ipu-fw-psys.c similarity index 68% rename from drivers/media/pci/intel/ipu-fw-psys.c rename to drivers/media/pci/intel/ipu6/psys/ipu-fw-psys.c index ca7fe2a9b100..f2f6cefeea70 100644 --- a/drivers/media/pci/intel/ipu-fw-psys.c +++ b/drivers/media/pci/intel/ipu6/psys/ipu-fw-psys.c @@ -5,7 +5,12 @@ #include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) #include "ipu-fw-com.h" +#else +#include "ipu6-fw-com.h" +#endif #include "ipu-fw-psys.h" #include "ipu-psys.h" @@ -15,6 +20,7 @@ int ipu_fw_psys_pg_start(struct ipu_psys_kcmd *kcmd) return 0; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) int ipu_fw_psys_pg_disown(struct ipu_psys_kcmd *kcmd) { struct ipu_fw_psys_cmd *psys_cmd; @@ -123,12 +129,125 @@ int ipu_fw_psys_rcv_event(struct ipu_psys *psys, ipu_recv_put_token(psys->fwcom, 0); return 1; } +#else +int ipu_fw_psys_pg_disown(struct ipu_psys_kcmd *kcmd) +{ + struct ipu_fw_psys_cmd *psys_cmd; + struct device *dev = &kcmd->fh->psys->adev->auxdev.dev; + int ret = 0; + + psys_cmd = ipu6_send_get_token(kcmd->fh->psys->fwcom, 0); + if (!psys_cmd) { + dev_err(dev, "%s failed to get token!\n", __func__); + kcmd->pg_user = NULL; + ret = -ENODATA; + goto out; + } + psys_cmd->command = IPU_FW_PSYS_PROCESS_GROUP_CMD_START; + psys_cmd->msg = 0; + psys_cmd->context_handle = kcmd->kpg->pg->ipu_virtual_address; + ipu6_send_put_token(kcmd->fh->psys->fwcom, 0); + +out: + return ret; +} + +int ipu_fw_psys_ppg_suspend(struct ipu_psys_kcmd *kcmd) +{ + struct device *dev = &kcmd->fh->psys->adev->auxdev.dev; + struct ipu_fw_psys_cmd *psys_cmd; + int ret = 0; + + /* ppg suspend cmd uses QUEUE_DEVICE_ID instead of QUEUE_COMMAND_ID */ + psys_cmd = ipu6_send_get_token(kcmd->fh->psys->fwcom, 1); + if (!psys_cmd) { + dev_err(dev, "%s failed to get token!\n", __func__); + kcmd->pg_user = NULL; + ret = -ENODATA; + goto out; + } + psys_cmd->command = IPU_FW_PSYS_PROCESS_GROUP_CMD_SUSPEND; + psys_cmd->msg = 0; + psys_cmd->context_handle = kcmd->kpg->pg->ipu_virtual_address; + ipu6_send_put_token(kcmd->fh->psys->fwcom, 1); + +out: + return ret; +} + +int ipu_fw_psys_ppg_resume(struct ipu_psys_kcmd *kcmd) +{ + struct device *dev = &kcmd->fh->psys->adev->auxdev.dev; + struct ipu_fw_psys_cmd *psys_cmd; + int ret = 0; + + psys_cmd = ipu6_send_get_token(kcmd->fh->psys->fwcom, 0); + if (!psys_cmd) { + dev_err(dev, "%s failed to get token!\n", __func__); + kcmd->pg_user = NULL; + ret = -ENODATA; + goto out; + } + psys_cmd->command = IPU_FW_PSYS_PROCESS_GROUP_CMD_RESUME; + psys_cmd->msg = 0; + psys_cmd->context_handle = kcmd->kpg->pg->ipu_virtual_address; + ipu6_send_put_token(kcmd->fh->psys->fwcom, 0); + +out: + return ret; +} + +int ipu_fw_psys_pg_abort(struct ipu_psys_kcmd *kcmd) +{ + struct device *dev = &kcmd->fh->psys->adev->auxdev.dev; + struct ipu_fw_psys_cmd *psys_cmd; + int ret = 0; + + psys_cmd = ipu6_send_get_token(kcmd->fh->psys->fwcom, 0); + if (!psys_cmd) { + dev_err(dev, "%s failed to get token!\n", __func__); + kcmd->pg_user = NULL; + ret = -ENODATA; + goto out; + } + psys_cmd->command = IPU_FW_PSYS_PROCESS_GROUP_CMD_STOP; + psys_cmd->msg = 0; + psys_cmd->context_handle = kcmd->kpg->pg->ipu_virtual_address; + ipu6_send_put_token(kcmd->fh->psys->fwcom, 0); + +out: + return ret; +} + +int ipu_fw_psys_pg_submit(struct ipu_psys_kcmd *kcmd) +{ + kcmd->kpg->pg->state = IPU_FW_PSYS_PROCESS_GROUP_BLOCKED; + return 0; +} + +int ipu_fw_psys_rcv_event(struct ipu_psys *psys, + struct ipu_fw_psys_event *event) +{ + void *rcv; + + rcv = ipu6_recv_get_token(psys->fwcom, 0); + if (!rcv) + return 0; + + memcpy(event, rcv, sizeof(*event)); + ipu6_recv_put_token(psys->fwcom, 0); + return 1; +} +#endif int ipu_fw_psys_terminal_set(struct ipu_fw_psys_terminal *terminal, int terminal_idx, struct ipu_psys_kcmd *kcmd, u32 buffer, unsigned int size) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &kcmd->fh->psys->adev->auxdev.dev; +#endif u32 type; u32 buffer_state; @@ -155,8 +274,12 @@ int ipu_fw_psys_terminal_set(struct ipu_fw_psys_terminal *terminal, buffer_state = IPU_FW_PSYS_BUFFER_EMPTY; break; default: +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_err(&kcmd->fh->psys->adev->dev, "unknown terminal type: 0x%x\n", type); +#else + dev_err(dev, "unknown terminal type: 0x%x\n", type); +#endif return -EAGAIN; } @@ -243,10 +366,18 @@ int ipu_fw_psys_ppg_set_buffer_set(struct ipu_psys_kcmd *kcmd, struct ipu_fw_psys_terminal *terminal, int terminal_idx, u32 buffer) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) u32 type; u32 buffer_state; u32 *buffer_ptr; struct ipu_fw_psys_buffer_set *buf_set = kcmd->kbuf_set->buf_set; +#else + struct device *dev = &kcmd->fh->psys->adev->auxdev.dev; + struct ipu_fw_psys_buffer_set *buf_set = kcmd->kbuf_set->buf_set; + u32 buffer_state; + u32 *buffer_ptr; + u32 type; +#endif type = terminal->terminal_type; @@ -271,8 +402,12 @@ int ipu_fw_psys_ppg_set_buffer_set(struct ipu_psys_kcmd *kcmd, buffer_state = IPU_FW_PSYS_BUFFER_EMPTY; break; default: +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_err(&kcmd->fh->psys->adev->dev, "unknown terminal type: 0x%x\n", type); +#else + dev_err(dev, "unknown terminal type: 0x%x\n", type); +#endif return -EAGAIN; } @@ -347,12 +482,19 @@ ipu_fw_psys_ppg_create_buffer_set(struct ipu_psys_kcmd *kcmd, int ipu_fw_psys_ppg_enqueue_bufs(struct ipu_psys_kcmd *kcmd) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &kcmd->fh->psys->adev->auxdev.dev; +#endif struct ipu_fw_psys_cmd *psys_cmd; unsigned int queue_id; int ret = 0; unsigned int size; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) if (ipu_ver == IPU_VER_6SE) +#else + if (ipu_ver == IPU6_VER_6SE) +#endif size = IPU6SE_FW_PSYS_N_PSYS_CMD_QUEUE_ID; else size = IPU6_FW_PSYS_N_PSYS_CMD_QUEUE_ID; @@ -361,6 +503,7 @@ int ipu_fw_psys_ppg_enqueue_bufs(struct ipu_psys_kcmd *kcmd) if (queue_id >= size) return -EINVAL; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) psys_cmd = ipu_send_get_token(kcmd->fh->psys->fwcom, queue_id); if (!psys_cmd) { dev_err(&kcmd->fh->psys->adev->dev, @@ -368,12 +511,24 @@ int ipu_fw_psys_ppg_enqueue_bufs(struct ipu_psys_kcmd *kcmd) kcmd->pg_user = NULL; return -ENODATA; } +#else + psys_cmd = ipu6_send_get_token(kcmd->fh->psys->fwcom, queue_id); + if (!psys_cmd) { + dev_err(dev, "%s failed to get token!\n", __func__); + kcmd->pg_user = NULL; + return -ENODATA; + } +#endif psys_cmd->command = IPU_FW_PSYS_PROCESS_GROUP_CMD_RUN; psys_cmd->msg = 0; psys_cmd->context_handle = kcmd->kbuf_set->buf_set->ipu_virtual_address; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) ipu_send_put_token(kcmd->fh->psys->fwcom, queue_id); +#else + ipu6_send_put_token(kcmd->fh->psys->fwcom, queue_id); +#endif return ret; } @@ -388,6 +543,7 @@ void ipu_fw_psys_ppg_set_base_queue_id(struct ipu_psys_kcmd *kcmd, u8 queue_id) kcmd->kpg->pg->base_queue_id = queue_id; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) int ipu_fw_psys_open(struct ipu_psys *psys) { int retry = IPU_PSYS_OPEN_RETRY, retval; @@ -428,3 +584,48 @@ int ipu_fw_psys_close(struct ipu_psys *psys) } return retval; } +#else +int ipu_fw_psys_open(struct ipu_psys *psys) +{ + struct device *dev = &psys->adev->auxdev.dev; + int retry = IPU_PSYS_OPEN_RETRY, retval; + + retval = ipu6_fw_com_open(psys->fwcom); + if (retval) { + dev_err(dev, "fw com open failed.\n"); + return retval; + } + + do { + usleep_range(IPU_PSYS_OPEN_TIMEOUT_US, + IPU_PSYS_OPEN_TIMEOUT_US + 10); + retval = ipu6_fw_com_ready(psys->fwcom); + if (retval) { + dev_dbg(dev, "psys port open ready!\n"); + break; + } + retry--; + } while (retry > 0); + + if (!retry) { + dev_err(dev, "psys port open ready failed\n"); + ipu6_fw_com_close(psys->fwcom); + return -EIO; + } + + return 0; +} + +int ipu_fw_psys_close(struct ipu_psys *psys) +{ + struct device *dev = &psys->adev->auxdev.dev; + int retval; + + retval = ipu6_fw_com_close(psys->fwcom); + if (retval) { + dev_err(dev, "fw com close failed.\n"); + return retval; + } + return retval; +} +#endif diff --git a/drivers/media/pci/intel/ipu-fw-psys.h b/drivers/media/pci/intel/ipu6/psys/ipu-fw-psys.h similarity index 100% rename from drivers/media/pci/intel/ipu-fw-psys.h rename to drivers/media/pci/intel/ipu6/psys/ipu-fw-psys.h diff --git a/drivers/media/pci/intel/ipu6/ipu-fw-resources.c b/drivers/media/pci/intel/ipu6/psys/ipu-fw-resources.c similarity index 100% rename from drivers/media/pci/intel/ipu6/ipu-fw-resources.c rename to drivers/media/pci/intel/ipu6/psys/ipu-fw-resources.c diff --git a/drivers/media/pci/intel/ipu6/ipu-platform-psys.h b/drivers/media/pci/intel/ipu6/psys/ipu-platform-psys.h similarity index 100% rename from drivers/media/pci/intel/ipu6/ipu-platform-psys.h rename to drivers/media/pci/intel/ipu6/psys/ipu-platform-psys.h diff --git a/drivers/media/pci/intel/ipu6/ipu-platform-resources.h b/drivers/media/pci/intel/ipu6/psys/ipu-platform-resources.h similarity index 100% rename from drivers/media/pci/intel/ipu6/ipu-platform-resources.h rename to drivers/media/pci/intel/ipu6/psys/ipu-platform-resources.h diff --git a/drivers/media/pci/intel/ipu-psys-compat32.c b/drivers/media/pci/intel/ipu6/psys/ipu-psys-compat32.c similarity index 100% rename from drivers/media/pci/intel/ipu-psys-compat32.c rename to drivers/media/pci/intel/ipu6/psys/ipu-psys-compat32.c diff --git a/drivers/media/pci/intel/ipu-psys.c b/drivers/media/pci/intel/ipu6/psys/ipu-psys.c similarity index 72% rename from drivers/media/pci/intel/ipu-psys.c rename to drivers/media/pci/intel/ipu6/psys/ipu-psys.c index dc2d689175db..335863112888 100644 --- a/drivers/media/pci/intel/ipu-psys.c +++ b/drivers/media/pci/intel/ipu6/psys/ipu-psys.c @@ -30,6 +30,7 @@ #include +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) #include "ipu.h" #include "ipu-mmu.h" #include "ipu-bus.h" @@ -41,11 +42,26 @@ #include "ipu-platform-psys.h" #include "ipu-platform-regs.h" #include "ipu-fw-com.h" +#else +#include "ipu6.h" +#include "ipu6-mmu.h" +#include "ipu6-bus.h" +#include "ipu6-buttress.h" +#include "ipu6-cpd.h" +#include "ipu-fw-psys.h" +#include "ipu-psys.h" +#include "ipu6-platform-regs.h" +#include "ipu6-fw-com.h" +#endif static bool async_fw_init; module_param(async_fw_init, bool, 0664); MODULE_PARM_DESC(async_fw_init, "Enable asynchronous firmware initialization"); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) +#define SYSCOM_BUTTRESS_FW_PARAMS_PSYS_OFFSET 7 + +#endif #define IPU_PSYS_NUM_DEVICES 4 #define IPU_PSYS_MAX_NUM_DESCS 1024 @@ -64,12 +80,54 @@ static struct fw_init_task { struct ipu_psys *psys; } fw_init_task; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) static void ipu_psys_remove(struct ipu_bus_device *adev); +#else +static void ipu6_psys_remove(struct auxiliary_device *auxdev); +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) static struct bus_type ipu_psys_bus = { .name = IPU_PSYS_NAME, }; +#else +static const struct bus_type ipu6_psys_bus = { + .name = "intel-ipu6-psys", +}; +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) +#define PKG_DIR_ENT_LEN_FOR_PSYS 2 +#define PKG_DIR_SIZE_MASK_FOR_PSYS GENMASK(23, 0) +enum ipu6_version ipu_ver; + +static u32 ipu6_cpd_pkg_dir_get_address(const u64 *pkg_dir, int pkg_dir_idx) +{ + return pkg_dir[++pkg_dir_idx * PKG_DIR_ENT_LEN_FOR_PSYS]; +} + +static u32 ipu6_cpd_pkg_dir_get_num_entries(const u64 *pkg_dir) +{ + return pkg_dir[1]; +} + +static u32 ipu6_cpd_pkg_dir_get_size(const u64 *pkg_dir, int pkg_dir_idx) +{ + return pkg_dir[++pkg_dir_idx * PKG_DIR_ENT_LEN_FOR_PSYS + 1] & + PKG_DIR_SIZE_MASK_FOR_PSYS; +} + +#define PKG_DIR_ID_SHIFT 48 +#define PKG_DIR_ID_MASK 0x7f + +static u32 ipu6_cpd_pkg_dir_get_type(const u64 *pkg_dir, int pkg_dir_idx) +{ + return pkg_dir[++pkg_dir_idx * PKG_DIR_ENT_LEN_FOR_PSYS + 1] >> + PKG_DIR_ID_SHIFT & PKG_DIR_ID_MASK; +} + +#endif /* * These are some trivial wrappers that save us from open-coding some * common patterns and also that's were we have some checking (for the @@ -147,6 +205,9 @@ static struct ipu_psys_desc *ipu_psys_desc_alloc(int fd) struct ipu_psys_pg *__get_pg_buf(struct ipu_psys *psys, size_t pg_size) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; +#endif struct ipu_psys_pg *kpg; unsigned long flags; @@ -164,8 +225,13 @@ struct ipu_psys_pg *__get_pg_buf(struct ipu_psys *psys, size_t pg_size) if (!kpg) return NULL; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) kpg->pg = dma_alloc_attrs(&psys->adev->dev, pg_size, &kpg->pg_dma_addr, GFP_KERNEL, 0); +#else + kpg->pg = dma_alloc_attrs(dev, pg_size, &kpg->pg_dma_addr, + GFP_KERNEL, 0); +#endif if (!kpg->pg) { kfree(kpg); return NULL; @@ -258,6 +324,7 @@ ipu_psys_lookup_kbuffer_by_kaddr(struct ipu_psys_fh *fh, void *kaddr) return NULL; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) static int ipu_psys_get_userpages(struct ipu_dma_buf_attach *attach) { struct vm_area_struct *vma; @@ -405,6 +472,88 @@ static void ipu_psys_put_userpages(struct ipu_dma_buf_attach *attach) kfree(attach->sgt); attach->sgt = NULL; } +#else +static int ipu_psys_get_userpages(struct ipu_dma_buf_attach *attach) +{ + struct vm_area_struct *vma; + unsigned long start, end; + int npages, array_size; + struct page **pages; + struct sg_table *sgt; + int ret = -ENOMEM; + int nr = 0; + u32 flags; + + start = attach->userptr; + end = PAGE_ALIGN(start + attach->len); + npages = (end - (start & PAGE_MASK)) >> PAGE_SHIFT; + array_size = npages * sizeof(struct page *); + + sgt = kzalloc(sizeof(*sgt), GFP_KERNEL); + if (!sgt) + return -ENOMEM; + + WARN_ON_ONCE(attach->npages); + + pages = kvzalloc(array_size, GFP_KERNEL); + if (!pages) + goto free_sgt; + + mmap_read_lock(current->mm); + vma = vma_lookup(current->mm, start); + if (unlikely(!vma)) { + ret = -EFAULT; + goto error_up_read; + } + mmap_read_unlock(current->mm); + + flags = FOLL_WRITE | FOLL_FORCE | FOLL_LONGTERM; + nr = pin_user_pages_fast(start & PAGE_MASK, npages, + flags, pages); + if (nr < npages) + goto error; + + attach->pages = pages; + attach->npages = npages; + + ret = sg_alloc_table_from_pages(sgt, pages, npages, + start & ~PAGE_MASK, attach->len, + GFP_KERNEL); + if (ret < 0) + goto error; + + attach->sgt = sgt; + + return 0; + +error_up_read: + mmap_read_unlock(current->mm); +error: + if (nr) + unpin_user_pages(pages, nr); + kvfree(pages); +free_sgt: + kfree(sgt); + + pr_err("failed to get userpages:%d\n", ret); + + return ret; +} + +static void ipu_psys_put_userpages(struct ipu_dma_buf_attach *attach) +{ + if (!attach || !attach->userptr || !attach->sgt) + return; + + unpin_user_pages(attach->pages, attach->npages); + + kvfree(attach->pages); + + sg_free_table(attach->sgt); + kfree(attach->sgt); + attach->sgt = NULL; +} +#endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) static int ipu_dma_buf_attach(struct dma_buf *dbuf, @@ -672,7 +821,11 @@ static void ipu_dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr) } #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) struct dma_buf_ops ipu_dma_buf_ops = { +#else +static const struct dma_buf_ops ipu_dma_buf_ops = { +#endif .attach = ipu_dma_buf_attach, .detach = ipu_dma_buf_detach, .map_dma_buf = ipu_dma_buf_map, @@ -694,13 +847,17 @@ struct dma_buf_ops ipu_dma_buf_ops = { static int ipu_psys_open(struct inode *inode, struct file *file) { struct ipu_psys *psys = inode_to_ipu_psys(inode); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) struct ipu_device *isp = psys->adev->isp; +#endif struct ipu_psys_fh *fh; int rval; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) if (isp->flr_done) return -EIO; +#endif fh = kzalloc(sizeof(*fh), GFP_KERNEL); if (!fh) return -ENOMEM; @@ -793,12 +950,19 @@ static void __ipu_psys_unmapbuf(struct ipu_psys_fh *fh, static int ipu_psys_unmapbuf_locked(int fd, struct ipu_psys_fh *fh) { struct ipu_psys *psys = fh->psys; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; +#endif struct ipu_psys_kbuffer *kbuf; struct ipu_psys_desc *desc; desc = psys_desc_lookup(fh, fd); if (WARN_ON_ONCE(!desc)) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_err(&psys->adev->dev, "descriptor not found: %d\n", fd); +#else + dev_err(dev, "descriptor not found: %d\n", fd); +#endif return -EINVAL; } @@ -808,7 +972,11 @@ static int ipu_psys_unmapbuf_locked(int fd, struct ipu_psys_fh *fh) kfree(desc); if (WARN_ON_ONCE(!kbuf || !kbuf->dbuf)) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_err(&psys->adev->dev, +#else + dev_err(dev, +#endif "descriptor with no buffer: %d\n", fd); return -EINVAL; } @@ -891,13 +1059,20 @@ static int ipu_psys_getbuf(struct ipu_psys_buffer *buf, struct ipu_psys_fh *fh) { struct ipu_psys_kbuffer *kbuf; struct ipu_psys *psys = fh->psys; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; +#endif struct ipu_psys_desc *desc; DEFINE_DMA_BUF_EXPORT_INFO(exp_info); struct dma_buf *dbuf; int ret; if (!buf->base.userptr) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_err(&psys->adev->dev, "Buffer allocation not supported\n"); +#else + dev_err(dev, "Buffer allocation not supported\n"); +#endif return -EINVAL; } @@ -944,7 +1119,11 @@ static int ipu_psys_getbuf(struct ipu_psys_buffer *buf, struct ipu_psys_fh *fh) ipu_buffer_add(fh, kbuf); mutex_unlock(&fh->mutex); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "IOC_GETBUF: userptr %p size %llu to fd %d", +#else + dev_dbg(dev, "IOC_GETBUF: userptr %llu size %llu to fd %d", +#endif buf->base.userptr, buf->len, buf->base.fd); return 0; @@ -974,6 +1153,9 @@ static void ipu_psys_kbuffer_lru(struct ipu_psys_fh *fh, struct ipu_psys_kbuffer *ipu_psys_mapbuf_locked(int fd, struct ipu_psys_fh *fh) { struct ipu_psys *psys = fh->psys; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; +#endif struct ipu_psys_kbuffer *kbuf; struct ipu_psys_desc *desc; struct dma_buf *dbuf; @@ -1025,7 +1207,11 @@ struct ipu_psys_kbuffer *ipu_psys_mapbuf_locked(int fd, struct ipu_psys_fh *fh) desc->kbuf = kbuf; if (kbuf->sgt) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "fd %d has been mapped!\n", fd); +#else + dev_dbg(dev, "fd %d has been mapped!\n", fd); +#endif dma_buf_put(dbuf); goto mapbuf_end; } @@ -1035,11 +1221,19 @@ struct ipu_psys_kbuffer *ipu_psys_mapbuf_locked(int fd, struct ipu_psys_fh *fh) if (kbuf->len == 0) kbuf->len = kbuf->dbuf->size; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) kbuf->db_attach = dma_buf_attach(kbuf->dbuf, &psys->adev->dev); if (IS_ERR(kbuf->db_attach)) { dev_dbg(&psys->adev->dev, "dma buf attach failed\n"); goto kbuf_map_fail; } +#else + kbuf->db_attach = dma_buf_attach(kbuf->dbuf, dev); + if (IS_ERR(kbuf->db_attach)) { + dev_dbg(dev, "dma buf attach failed\n"); + goto kbuf_map_fail; + } +#endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 255) kbuf->sgt = dma_buf_map_attachment_unlocked(kbuf->db_attach, @@ -1049,16 +1243,28 @@ struct ipu_psys_kbuffer *ipu_psys_mapbuf_locked(int fd, struct ipu_psys_fh *fh) #endif if (IS_ERR_OR_NULL(kbuf->sgt)) { kbuf->sgt = NULL; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "dma buf map attachment failed\n"); +#else + dev_dbg(dev, "dma buf map attachment failed\n"); +#endif goto kbuf_map_fail; } kbuf->dma_addr = sg_dma_address(kbuf->sgt->sgl); + /* no need vmap for imported dmabufs */ + if (!kbuf->userptr) + goto mapbuf_end; + #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) && LINUX_VERSION_CODE != KERNEL_VERSION(5, 10, 46) #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 255) if (dma_buf_vmap_unlocked(kbuf->dbuf, &dmap)) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "dma buf vmap failed\n"); +#else + dev_dbg(dev, "dma buf vmap failed\n"); +#endif goto kbuf_map_fail; } #else @@ -1076,7 +1282,11 @@ struct ipu_psys_kbuffer *ipu_psys_mapbuf_locked(int fd, struct ipu_psys_fh *fh) } #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "%s kbuf %p fd %d with len %llu mapped\n", +#else + dev_dbg(dev, "%s kbuf %p fd %d with len %llu mapped\n", +#endif __func__, kbuf, fd, kbuf->len); mapbuf_end: @@ -1108,7 +1318,11 @@ static long ipu_psys_mapbuf(int fd, struct ipu_psys_fh *fh) kbuf = ipu_psys_mapbuf_locked(fd, fh); mutex_unlock(&fh->mutex); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&fh->psys->adev->dev, "IOC_MAPBUF\n"); +#else + dev_dbg(&fh->psys->adev->auxdev.dev, "IOC_MAPBUF\n"); +#endif return kbuf ? 0 : -EINVAL; } @@ -1121,11 +1335,16 @@ static long ipu_psys_unmapbuf(int fd, struct ipu_psys_fh *fh) ret = ipu_psys_unmapbuf_locked(fd, fh); mutex_unlock(&fh->mutex); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&fh->psys->adev->dev, "IOC_UNMAPBUF\n"); +#else + dev_dbg(&fh->psys->adev->auxdev.dev, "IOC_UNMAPBUF\n"); +#endif return ret; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) static unsigned int ipu_psys_poll(struct file *file, struct poll_table_struct *wait) { @@ -1144,21 +1363,54 @@ static unsigned int ipu_psys_poll(struct file *file, return res; } +#else +static __poll_t ipu_psys_poll(struct file *file, + struct poll_table_struct *wait) +{ + struct ipu_psys_fh *fh = file->private_data; + struct ipu_psys *psys = fh->psys; + struct device *dev = &psys->adev->auxdev.dev; + __poll_t ret = 0; + + dev_dbg(dev, "ipu psys poll\n"); + + poll_wait(file, &fh->wait, wait); + + if (ipu_get_completed_kcmd(fh)) + ret = POLLIN; + + dev_dbg(dev, "ipu psys poll ret %u\n", ret); + + return ret; +} +#endif static long ipu_get_manifest(struct ipu_psys_manifest *manifest, struct ipu_psys_fh *fh) { struct ipu_psys *psys = fh->psys; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) struct ipu_device *isp = psys->adev->isp; struct ipu_cpd_client_pkg_hdr *client_pkg; +#else + struct device *dev = &psys->adev->auxdev.dev; + struct ipu6_bus_device *adev = psys->adev; + struct ipu6_device *isp = adev->isp; + struct ipu6_cpd_client_pkg_hdr *client_pkg; +#endif u32 entries; void *host_fw_data; dma_addr_t dma_fw_data; u32 client_pkg_offset; host_fw_data = (void *)isp->cpd_fw->data; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dma_fw_data = sg_dma_address(psys->fw_sgt.sgl); +#else + dma_fw_data = sg_dma_address(adev->fw_sgt.sgl); +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) entries = ipu_cpd_pkg_dir_get_num_entries(psys->pkg_dir); if (!manifest || manifest->index > entries - 1) { dev_err(&psys->adev->dev, "invalid argument\n"); @@ -1174,6 +1426,23 @@ static long ipu_get_manifest(struct ipu_psys_manifest *manifest, client_pkg_offset = ipu_cpd_pkg_dir_get_address(psys->pkg_dir, manifest->index); +#else + entries = ipu6_cpd_pkg_dir_get_num_entries(adev->pkg_dir); + if (!manifest || manifest->index > entries - 1) { + dev_err(dev, "invalid argument\n"); + return -EINVAL; + } + + if (!ipu6_cpd_pkg_dir_get_size(adev->pkg_dir, manifest->index) || + ipu6_cpd_pkg_dir_get_type(adev->pkg_dir, manifest->index) < + IPU6_CPD_PKG_DIR_CLIENT_PG_TYPE) { + dev_dbg(dev, "invalid pkg dir entry\n"); + return -ENOENT; + } + + client_pkg_offset = ipu6_cpd_pkg_dir_get_address(adev->pkg_dir, + manifest->index); +#endif client_pkg_offset -= dma_fw_data; client_pkg = host_fw_data + client_pkg_offset; @@ -1261,9 +1530,6 @@ static const struct file_operations ipu_psys_fops = { .open = ipu_psys_open, .release = ipu_psys_release, .unlocked_ioctl = ipu_psys_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = ipu_psys_compat_ioctl32, -#endif .poll = ipu_psys_poll, .owner = THIS_MODULE, }; @@ -1275,8 +1541,13 @@ static void ipu_psys_dev_release(struct device *dev) #ifdef CONFIG_PM static int psys_runtime_pm_resume(struct device *dev) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) struct ipu_bus_device *adev = to_ipu_bus_device(dev); struct ipu_psys *psys = ipu_bus_get_drvdata(adev); +#else + struct ipu6_bus_device *adev = to_ipu6_bus_device(dev); + struct ipu_psys *psys = ipu6_bus_get_drvdata(adev); +#endif unsigned long flags; int retval; @@ -1290,7 +1561,11 @@ static int psys_runtime_pm_resume(struct device *dev) } spin_unlock_irqrestore(&psys->ready_lock, flags); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) retval = ipu_mmu_hw_init(adev->mmu); +#else + retval = ipu6_mmu_hw_init(adev->mmu); +#endif if (retval) return retval; @@ -1301,7 +1576,11 @@ static int psys_runtime_pm_resume(struct device *dev) return 0; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) if (!ipu_buttress_auth_done(adev->isp)) { +#else + if (!ipu6_buttress_auth_done(adev->isp)) { +#endif dev_dbg(dev, "%s: not yet authenticated, skipping\n", __func__); return 0; } @@ -1309,17 +1588,31 @@ static int psys_runtime_pm_resume(struct device *dev) ipu_psys_setup_hw(psys); ipu_psys_subdomains_power(psys, 1); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) ipu_trace_restore(&psys->adev->dev); +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) ipu_configure_spc(adev->isp, &psys->pdata->ipdata->hw_variant, IPU_CPD_PKG_DIR_PSYS_SERVER_IDX, psys->pdata->base, psys->pkg_dir, psys->pkg_dir_dma_addr); +#else + ipu6_configure_spc(adev->isp, + &psys->pdata->ipdata->hw_variant, + IPU6_CPD_PKG_DIR_PSYS_SERVER_IDX, + psys->pdata->base, adev->pkg_dir, + adev->pkg_dir_dma_addr); +#endif retval = ipu_fw_psys_open(psys); if (retval) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_err(&psys->adev->dev, "Failed to open abi.\n"); +#else + dev_err(dev, "Failed to open abi.\n"); +#endif return retval; } @@ -1332,8 +1625,13 @@ static int psys_runtime_pm_resume(struct device *dev) static int psys_runtime_pm_suspend(struct device *dev) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) struct ipu_bus_device *adev = to_ipu_bus_device(dev); struct ipu_psys *psys = ipu_bus_get_drvdata(adev); +#else + struct ipu6_bus_device *adev = to_ipu6_bus_device(dev); + struct ipu_psys *psys = ipu6_bus_get_drvdata(adev); +#endif unsigned long flags; int rval; @@ -1358,7 +1656,11 @@ static int psys_runtime_pm_suspend(struct device *dev) ipu_psys_subdomains_power(psys, 0); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) ipu_mmu_hw_cleanup(adev->mmu); +#else + ipu6_mmu_hw_cleanup(adev->mmu); +#endif return 0; } @@ -1389,6 +1691,7 @@ static const struct dev_pm_ops psys_pm_ops = { #define PSYS_PM_OPS NULL #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) static int cpd_fw_reload(struct ipu_device *isp) { struct ipu_psys *psys = ipu_bus_get_drvdata(isp->psys); @@ -1465,7 +1768,9 @@ static int cpd_fw_reload(struct ipu_device *isp) return rval; } +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) #ifdef CONFIG_DEBUG_FS static int ipu_psys_icache_prefetch_sp_get(void *data, u64 *val) { @@ -1536,17 +1841,13 @@ static int ipu_psys_init_debugfs(struct ipu_psys *psys) psys->debugfsdir = dir; -#ifdef IPU_PSYS_GPC - if (ipu_psys_gpc_init_debugfs(psys)) - return -ENOMEM; -#endif - return 0; err: debugfs_remove_recursive(dir); return -ENOMEM; } #endif +#endif static int ipu_psys_sched_cmd(void *ptr) { @@ -1574,6 +1875,7 @@ static int ipu_psys_sched_cmd(void *ptr) return 0; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) static void start_sp(struct ipu_bus_device *adev) { struct ipu_psys *psys = ipu_bus_get_drvdata(adev); @@ -1601,7 +1903,37 @@ static int query_sp(struct ipu_bus_device *adev) return val == IPU_PSYS_SPC_STATUS_READY; } +#else +static void start_sp(struct ipu6_bus_device *adev) +{ + struct ipu_psys *psys = ipu6_bus_get_drvdata(adev); + void __iomem *spc_regs_base = psys->pdata->base + + psys->pdata->ipdata->hw_variant.spc_offset; + u32 val = 0; + val |= IPU6_PSYS_SPC_STATUS_START | + IPU6_PSYS_SPC_STATUS_RUN | + IPU6_PSYS_SPC_STATUS_CTRL_ICACHE_INVALIDATE; + val |= psys->icache_prefetch_sp ? + IPU6_PSYS_SPC_STATUS_ICACHE_PREFETCH : 0; + writel(val, spc_regs_base + IPU6_PSYS_REG_SPC_STATUS_CTRL); +} + +static int query_sp(struct ipu6_bus_device *adev) +{ + struct ipu_psys *psys = ipu6_bus_get_drvdata(adev); + void __iomem *spc_regs_base = psys->pdata->base + + psys->pdata->ipdata->hw_variant.spc_offset; + u32 val = readl(spc_regs_base + IPU6_PSYS_REG_SPC_STATUS_CTRL); + + /* return true when READY == 1, START == 0 */ + val &= IPU6_PSYS_SPC_STATUS_READY | IPU6_PSYS_SPC_STATUS_START; + + return val == IPU6_PSYS_SPC_STATUS_READY; +} +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) static int ipu_psys_fw_init(struct ipu_psys *psys) { unsigned int size; @@ -1672,7 +2004,84 @@ static void run_fw_init_work(struct work_struct *work) dev_info(&psys->adev->dev, "FW init done\n"); } } +#else +static int ipu_psys_fw_init(struct ipu_psys *psys) +{ + struct ipu6_fw_syscom_queue_config *queue_cfg; + struct device *dev = &psys->adev->auxdev.dev; + unsigned int size; + struct ipu6_fw_syscom_queue_config fw_psys_event_queue_cfg[] = { + { + IPU_FW_PSYS_EVENT_QUEUE_SIZE, + sizeof(struct ipu_fw_psys_event) + } + }; + struct ipu_fw_psys_srv_init server_init = { + .ddr_pkg_dir_address = 0, + .host_ddr_pkg_dir = NULL, + .pkg_dir_size = 0, + .icache_prefetch_sp = psys->icache_prefetch_sp, + .icache_prefetch_isp = psys->icache_prefetch_isp, + }; + struct ipu6_fw_com_cfg fwcom = { + .num_output_queues = IPU_FW_PSYS_N_PSYS_EVENT_QUEUE_ID, + .output = fw_psys_event_queue_cfg, + .specific_addr = &server_init, + .specific_size = sizeof(server_init), + .cell_start = start_sp, + .cell_ready = query_sp, + .buttress_boot_offset = SYSCOM_BUTTRESS_FW_PARAMS_PSYS_OFFSET, + }; + int i; + size = IPU6SE_FW_PSYS_N_PSYS_CMD_QUEUE_ID; + if (ipu_ver == IPU6_VER_6 || ipu_ver == IPU6_VER_6EP || + ipu_ver == IPU6_VER_6EP_MTL) + size = IPU6_FW_PSYS_N_PSYS_CMD_QUEUE_ID; + + queue_cfg = devm_kzalloc(dev, sizeof(*queue_cfg) * size, + GFP_KERNEL); + if (!queue_cfg) + return -ENOMEM; + + for (i = 0; i < size; i++) { + queue_cfg[i].queue_size = IPU_FW_PSYS_CMD_QUEUE_SIZE; + queue_cfg[i].token_size = sizeof(struct ipu_fw_psys_cmd); + } + + fwcom.input = queue_cfg; + fwcom.num_input_queues = size; + fwcom.dmem_addr = psys->pdata->ipdata->hw_variant.dmem_offset; + + psys->fwcom = ipu6_fw_com_prepare(&fwcom, psys->adev, + psys->pdata->base); + if (!psys->fwcom) { + dev_err(dev, "psys fw com prepare failed\n"); + return -EIO; + } + + return 0; +} + +static void run_fw_init_work(struct work_struct *work) +{ + struct fw_init_task *task = (struct fw_init_task *)work; + struct ipu_psys *psys = task->psys; + struct device *dev = &psys->adev->auxdev.dev; + int rval; + + rval = ipu_psys_fw_init(psys); + + if (rval) { + dev_err(dev, "FW init failed(%d)\n", rval); + ipu6_psys_remove(&psys->adev->auxdev); + } else { + dev_info(dev, "FW init done\n"); + } +} +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) static int ipu_psys_probe(struct ipu_bus_device *adev) { struct ipu_device *isp = adev->isp; @@ -1854,16 +2263,214 @@ static int ipu_psys_probe(struct ipu_bus_device *adev) return rval; } +#else +static int ipu6_psys_probe(struct auxiliary_device *auxdev, + const struct auxiliary_device_id *auxdev_id) +{ + struct ipu6_bus_device *adev = auxdev_to_adev(auxdev); + struct device *dev = &auxdev->dev; + struct ipu_psys_pg *kpg, *kpg0; + struct ipu_psys *psys; + unsigned int minor; + int i, rval = -E2BIG; + + if (!adev->isp->bus_ready_to_probe) + return -EPROBE_DEFER; + + if (!adev->pkg_dir) + return -EPROBE_DEFER; + + ipu_ver = adev->isp->hw_ver; + + rval = alloc_chrdev_region(&ipu_psys_dev_t, 0, + IPU_PSYS_NUM_DEVICES, IPU6_PSYS_NAME); + if (rval) { + dev_err(dev, "can't alloc psys chrdev region (%d)\n", + rval); + return rval; + } + + rval = ipu6_mmu_hw_init(adev->mmu); + if (rval) + goto out_unregister_chr_region; + + mutex_lock(&ipu_psys_mutex); + + minor = find_next_zero_bit(ipu_psys_devices, IPU_PSYS_NUM_DEVICES, 0); + if (minor == IPU_PSYS_NUM_DEVICES) { + dev_err(dev, "too many devices\n"); + goto out_unlock; + } + + psys = devm_kzalloc(dev, sizeof(*psys), GFP_KERNEL); + if (!psys) { + rval = -ENOMEM; + goto out_unlock; + } + + adev->auxdrv_data = + (const struct ipu6_auxdrv_data *)auxdev_id->driver_data; + adev->auxdrv = to_auxiliary_drv(dev->driver); + + psys->adev = adev; + psys->pdata = adev->pdata; + psys->icache_prefetch_sp = 0; + + psys->power_gating = 0; + + cdev_init(&psys->cdev, &ipu_psys_fops); + psys->cdev.owner = ipu_psys_fops.owner; + + rval = cdev_add(&psys->cdev, MKDEV(MAJOR(ipu_psys_dev_t), minor), 1); + if (rval) { + dev_err(dev, "cdev_add failed (%d)\n", rval); + goto out_unlock; + } + + set_bit(minor, ipu_psys_devices); + + spin_lock_init(&psys->ready_lock); + spin_lock_init(&psys->pgs_lock); + psys->ready = 0; + psys->timeout = IPU_PSYS_CMD_TIMEOUT_MS; + + mutex_init(&psys->mutex); + INIT_LIST_HEAD(&psys->fhs); + INIT_LIST_HEAD(&psys->pgs); + INIT_LIST_HEAD(&psys->started_kcmds_list); + + init_waitqueue_head(&psys->sched_cmd_wq); + atomic_set(&psys->wakeup_count, 0); + /* + * Create a thread to schedule commands sent to IPU firmware. + * The thread reduces the coupling between the command scheduler + * and queueing commands from the user to driver. + */ + psys->sched_cmd_thread = kthread_run(ipu_psys_sched_cmd, psys, + "psys_sched_cmd"); + + if (IS_ERR(psys->sched_cmd_thread)) { + psys->sched_cmd_thread = NULL; + mutex_destroy(&psys->mutex); + goto out_unlock; + } + + dev_set_drvdata(dev, psys); + + rval = ipu_psys_resource_pool_init(&psys->resource_pool_running); + if (rval < 0) { + dev_err(&psys->dev, + "unable to alloc process group resources\n"); + goto out_mutex_destroy; + } + + ipu6_psys_hw_res_variant_init(); + + /* allocate and map memory for process groups */ + for (i = 0; i < IPU_PSYS_PG_POOL_SIZE; i++) { + kpg = kzalloc(sizeof(*kpg), GFP_KERNEL); + if (!kpg) + goto out_free_pgs; + kpg->pg = dma_alloc_attrs(dev, IPU_PSYS_PG_MAX_SIZE, + &kpg->pg_dma_addr, + GFP_KERNEL, 0); + if (!kpg->pg) { + kfree(kpg); + goto out_free_pgs; + } + kpg->size = IPU_PSYS_PG_MAX_SIZE; + list_add(&kpg->list, &psys->pgs); + } + + psys->caps.pg_count = ipu6_cpd_pkg_dir_get_num_entries(adev->pkg_dir); + + dev_info(dev, "pkg_dir entry count:%d\n", psys->caps.pg_count); + if (async_fw_init) { + INIT_DELAYED_WORK((struct delayed_work *)&fw_init_task, + run_fw_init_work); + fw_init_task.psys = psys; + schedule_delayed_work((struct delayed_work *)&fw_init_task, 0); + } else { + rval = ipu_psys_fw_init(psys); + } + + if (rval) { + dev_err(dev, "FW init failed(%d)\n", rval); + goto out_free_pgs; + } + + psys->dev.bus = &ipu6_psys_bus; + psys->dev.parent = dev; + psys->dev.devt = MKDEV(MAJOR(ipu_psys_dev_t), minor); + psys->dev.release = ipu_psys_dev_release; + dev_set_name(&psys->dev, "ipu-psys%d", minor); + rval = device_register(&psys->dev); + if (rval < 0) { + dev_err(dev, "psys device_register failed\n"); + goto out_release_fw_com; + } + + /* Add the hw stepping information to caps */ + strscpy(psys->caps.dev_model, IPU6_MEDIA_DEV_MODEL_NAME, + sizeof(psys->caps.dev_model)); + + mutex_unlock(&ipu_psys_mutex); + + dev_info(dev, "psys probe minor: %d\n", minor); + + ipu6_mmu_hw_cleanup(adev->mmu); + + return 0; + +out_release_fw_com: + ipu6_fw_com_release(psys->fwcom, 1); +out_free_pgs: + list_for_each_entry_safe(kpg, kpg0, &psys->pgs, list) { + dma_free_attrs(dev, kpg->size, kpg->pg, kpg->pg_dma_addr, 0); + kfree(kpg); + } + + ipu_psys_resource_pool_cleanup(&psys->resource_pool_running); +out_mutex_destroy: + mutex_destroy(&psys->mutex); + cdev_del(&psys->cdev); + if (psys->sched_cmd_thread) { + kthread_stop(psys->sched_cmd_thread); + psys->sched_cmd_thread = NULL; + } +out_unlock: + /* Safe to call even if the init is not called */ + mutex_unlock(&ipu_psys_mutex); + ipu6_mmu_hw_cleanup(adev->mmu); + +out_unregister_chr_region: + unregister_chrdev_region(ipu_psys_dev_t, IPU_PSYS_NUM_DEVICES); + + return rval; +} +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) static void ipu_psys_remove(struct ipu_bus_device *adev) { struct ipu_device *isp = adev->isp; struct ipu_psys *psys = ipu_bus_get_drvdata(adev); +#else +static void ipu6_psys_remove(struct auxiliary_device *auxdev) +{ + struct device *dev = &auxdev->dev; + struct ipu_psys *psys = dev_get_drvdata(&auxdev->dev); +#endif struct ipu_psys_pg *kpg, *kpg0; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + unregister_chrdev_region(ipu_psys_dev_t, IPU_PSYS_NUM_DEVICES); +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) #ifdef CONFIG_DEBUG_FS if (isp->ipu_dir) debugfs_remove_recursive(psys->debugfsdir); +#endif #endif if (psys->sched_cmd_thread) { @@ -1874,18 +2481,29 @@ static void ipu_psys_remove(struct ipu_bus_device *adev) mutex_lock(&ipu_psys_mutex); list_for_each_entry_safe(kpg, kpg0, &psys->pgs, list) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dma_free_attrs(&adev->dev, kpg->size, kpg->pg, kpg->pg_dma_addr, 0); +#else + dma_free_attrs(dev, kpg->size, kpg->pg, kpg->pg_dma_addr, 0); +#endif kfree(kpg); } +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) if (psys->fwcom && ipu_fw_com_release(psys->fwcom, 1)) dev_err(&adev->dev, "fw com release failed.\n"); +#else + if (psys->fwcom && ipu6_fw_com_release(psys->fwcom, 1)) + dev_err(dev, "fw com release failed.\n"); +#endif kfree(psys->server_init); kfree(psys->syscom_config); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) ipu_trace_uninit(&adev->dev); +#endif ipu_psys_resource_pool_cleanup(&psys->resource_pool_running); @@ -1898,9 +2516,14 @@ static void ipu_psys_remove(struct ipu_bus_device *adev) mutex_destroy(&psys->mutex); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_info(&adev->dev, "removed\n"); +#else + dev_info(dev, "removed\n"); +#endif } +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) static irqreturn_t psys_isr_threaded(struct ipu_bus_device *adev) { struct ipu_psys *psys = ipu_bus_get_drvdata(adev); @@ -1930,7 +2553,38 @@ static irqreturn_t psys_isr_threaded(struct ipu_bus_device *adev) return status ? IRQ_HANDLED : IRQ_NONE; } +#else +static irqreturn_t psys_isr_threaded(struct ipu6_bus_device *adev) +{ + struct ipu_psys *psys = ipu6_bus_get_drvdata(adev); + struct device *dev = &psys->adev->auxdev.dev; + void __iomem *base = psys->pdata->base; + u32 status; + int r; + + mutex_lock(&psys->mutex); + r = pm_runtime_get_if_in_use(dev); + if (!r || WARN_ON_ONCE(r < 0)) { + mutex_unlock(&psys->mutex); + return IRQ_NONE; + } + + status = readl(base + IPU6_REG_PSYS_GPDEV_IRQ_STATUS); + writel(status, base + IPU6_REG_PSYS_GPDEV_IRQ_CLEAR); + + if (status & IPU6_PSYS_GPDEV_IRQ_FWIRQ(IPU6_PSYS_GPDEV_FWIRQ0)) { + writel(0, base + IPU6_REG_PSYS_GPDEV_FWIRQ(0)); + ipu_psys_handle_events(psys); + } + + pm_runtime_put(dev); + mutex_unlock(&psys->mutex); + return status ? IRQ_HANDLED : IRQ_NONE; +} +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) static struct ipu_bus_driver ipu_psys_driver = { .probe = ipu_psys_probe, .remove = ipu_psys_remove, @@ -1989,6 +2643,32 @@ MODULE_DEVICE_TABLE(pci, ipu_pci_tbl); module_init(ipu_psys_init); module_exit(ipu_psys_exit); +#else +static const struct ipu6_auxdrv_data ipu6_psys_auxdrv_data = { + .isr_threaded = psys_isr_threaded, + .wake_isr_thread = true, +}; + +static const struct auxiliary_device_id ipu6_psys_id_table[] = { + { + .name = "intel_ipu6.psys", + .driver_data = (kernel_ulong_t)&ipu6_psys_auxdrv_data, + }, + { } +}; +MODULE_DEVICE_TABLE(auxiliary, ipu6_psys_id_table); + +static struct auxiliary_driver ipu6_psys_aux_driver = { + .name = IPU6_PSYS_NAME, + .probe = ipu6_psys_probe, + .remove = ipu6_psys_remove, + .id_table = ipu6_psys_id_table, + .driver = { + .pm = &psys_pm_ops, + }, +}; +module_auxiliary_driver(ipu6_psys_aux_driver); +#endif MODULE_AUTHOR("Antti Laakso "); MODULE_AUTHOR("Bin Han "); @@ -2003,3 +2683,6 @@ MODULE_DESCRIPTION("Intel ipu processing system driver"); #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0) || IS_ENABLED(CONFIG_DRM_I915_HAS_SRIOV) MODULE_IMPORT_NS(DMA_BUF); #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) +MODULE_IMPORT_NS(INTEL_IPU6); +#endif diff --git a/drivers/media/pci/intel/ipu-psys.h b/drivers/media/pci/intel/ipu6/psys/ipu-psys.h similarity index 58% rename from drivers/media/pci/intel/ipu-psys.h rename to drivers/media/pci/intel/ipu6/psys/ipu-psys.h index ca6a817428aa..7ffa9ff37eea 100644 --- a/drivers/media/pci/intel/ipu-psys.h +++ b/drivers/media/pci/intel/ipu6/psys/ipu-psys.h @@ -7,11 +7,116 @@ #include #include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) #include "ipu.h" #include "ipu-pdata.h" +#else +#include "ipu6.h" +#include "ipu6-bus.h" +#endif #include "ipu-fw-psys.h" #include "ipu-platform-psys.h" +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) +/* PSYS Info bits*/ +#define IPU_REG_PSYS_INFO_SEG_CMEM_MASTER(a) (0x2c + ((a) * 12)) +#define IPU_REG_PSYS_INFO_SEG_XMEM_MASTER(a) (0x5c + ((a) * 12)) + +#define IPU_PSYS_REG_SPC_STATUS_CTRL 0x0 +#define IPU_PSYS_REG_SPC_START_PC 0x4 +#define IPU_PSYS_REG_SPC_ICACHE_BASE 0x10 +#define IPU_REG_PSYS_INFO_SEG_0_CONFIG_ICACHE_MASTER 0x14 + +#define IPU_PSYS_SPC_STATUS_START BIT(1) +#define IPU_PSYS_SPC_STATUS_RUN BIT(3) +#define IPU_PSYS_SPC_STATUS_READY BIT(5) +#define IPU_PSYS_SPC_STATUS_CTRL_ICACHE_INVALIDATE BIT(12) +#define IPU_PSYS_SPC_STATUS_ICACHE_PREFETCH BIT(13) + +#define IPU_PSYS_REG_SPP0_STATUS_CTRL 0x20000 + +#define IPU_INFO_ENABLE_SNOOP BIT(0) +#define IPU_INFO_DEC_FORCE_FLUSH BIT(1) +#define IPU_INFO_DEC_PASS_THRU BIT(2) +#define IPU_INFO_ZLW BIT(3) +#define IPU_INFO_STREAM_ID_SET(id) (((id) & 0x1f) << 4) +#define IPU_INFO_REQUEST_DESTINATION_IOSF BIT(9) +#define IPU_INFO_IMR_BASE BIT(10) +#define IPU_INFO_IMR_DESTINED BIT(11) + +#define IPU_INFO_REQUEST_DESTINATION_PRIMARY IPU_INFO_REQUEST_DESTINATION_IOSF + +#define IPU_REG_DMA_TOP_AB_GROUP1_BASE_ADDR 0x1ae000 +#define IPU_REG_DMA_TOP_AB_GROUP2_BASE_ADDR 0x1af000 +#define IPU_REG_DMA_TOP_AB_RING_MIN_OFFSET(n) (0x4 + (n) * 0xc) +#define IPU_REG_DMA_TOP_AB_RING_MAX_OFFSET(n) (0x8 + (n) * 0xc) +#define IPU_REG_DMA_TOP_AB_RING_ACCESS_OFFSET(n) (0xc + (n) * 0xc) + +enum ipu_device_ab_group1_target_id { + IPU_DEVICE_AB_GROUP1_TARGET_ID_R0_SPC_DMEM, + IPU_DEVICE_AB_GROUP1_TARGET_ID_R1_SPC_DMEM, + IPU_DEVICE_AB_GROUP1_TARGET_ID_R2_SPC_DMEM, + IPU_DEVICE_AB_GROUP1_TARGET_ID_R3_SPC_STATUS_REG, + IPU_DEVICE_AB_GROUP1_TARGET_ID_R4_SPC_MASTER_BASE_ADDR, + IPU_DEVICE_AB_GROUP1_TARGET_ID_R5_SPC_PC_STALL, + IPU_DEVICE_AB_GROUP1_TARGET_ID_R6_SPC_EQ, + IPU_DEVICE_AB_GROUP1_TARGET_ID_R7_SPC_RESERVED, + IPU_DEVICE_AB_GROUP1_TARGET_ID_R8_SPC_RESERVED, + IPU_DEVICE_AB_GROUP1_TARGET_ID_R9_SPP0, + IPU_DEVICE_AB_GROUP1_TARGET_ID_R10_SPP1, + IPU_DEVICE_AB_GROUP1_TARGET_ID_R11_CENTRAL_R1, + IPU_DEVICE_AB_GROUP1_TARGET_ID_R12_IRQ, + IPU_DEVICE_AB_GROUP1_TARGET_ID_R13_CENTRAL_R2, + IPU_DEVICE_AB_GROUP1_TARGET_ID_R14_DMA, + IPU_DEVICE_AB_GROUP1_TARGET_ID_R15_DMA, + IPU_DEVICE_AB_GROUP1_TARGET_ID_R16_GP, + IPU_DEVICE_AB_GROUP1_TARGET_ID_R17_ZLW_INSERTER, + IPU_DEVICE_AB_GROUP1_TARGET_ID_R18_AB, +}; + +/* IRQ-related registers in PSYS */ +#define IPU_REG_PSYS_GPDEV_IRQ_EDGE 0x1aa200 +#define IPU_REG_PSYS_GPDEV_IRQ_MASK 0x1aa204 +#define IPU_REG_PSYS_GPDEV_IRQ_STATUS 0x1aa208 +#define IPU_REG_PSYS_GPDEV_IRQ_CLEAR 0x1aa20c +#define IPU_REG_PSYS_GPDEV_IRQ_ENABLE 0x1aa210 +#define IPU_REG_PSYS_GPDEV_IRQ_LEVEL_NOT_PULSE 0x1aa214 +/* There are 8 FW interrupts, n = 0..7 */ +#define IPU_PSYS_GPDEV_FWIRQ0 5 +#define IPU_PSYS_GPDEV_FWIRQ1 6 +#define IPU_PSYS_GPDEV_FWIRQ2 7 +#define IPU_PSYS_GPDEV_FWIRQ3 8 +#define IPU_PSYS_GPDEV_FWIRQ4 9 +#define IPU_PSYS_GPDEV_FWIRQ5 10 +#define IPU_PSYS_GPDEV_FWIRQ6 11 +#define IPU_PSYS_GPDEV_FWIRQ7 12 +#define IPU_PSYS_GPDEV_IRQ_FWIRQ(n) (1 << (n)) +#define IPU_REG_PSYS_GPDEV_FWIRQ(n) (4 * (n) + 0x1aa100) + +/* + * psys subdomains power request regs + */ +enum ipu_device_buttress_psys_domain_pos { + IPU_PSYS_SUBDOMAIN_ISA = 0, + IPU_PSYS_SUBDOMAIN_PSA = 1, + IPU_PSYS_SUBDOMAIN_BB = 2, + IPU_PSYS_SUBDOMAIN_IDSP1 = 3, /* only in IPU6M */ + IPU_PSYS_SUBDOMAIN_IDSP2 = 4, /* only in IPU6M */ +}; + +#define IPU_PSYS_SUBDOMAINS_POWER_MASK (BIT(IPU_PSYS_SUBDOMAIN_ISA) | \ + BIT(IPU_PSYS_SUBDOMAIN_PSA) | \ + BIT(IPU_PSYS_SUBDOMAIN_BB)) + +#define IPU_PSYS_SUBDOMAINS_POWER_REQ 0xa0 +#define IPU_PSYS_SUBDOMAINS_POWER_STATUS 0xa4 + +#define IPU_PSYS_CMD_TIMEOUT_MS 2000 +#define IPU_PSYS_OPEN_TIMEOUT_US 50 +#define IPU_PSYS_OPEN_RETRY (10000 / IPU_PSYS_OPEN_TIMEOUT_US) +#endif + #define IPU_PSYS_PG_POOL_SIZE 16 #define IPU_PSYS_PG_MAX_SIZE 8192 #define IPU_MAX_PSYS_CMD_BUFFERS 32 @@ -21,6 +126,10 @@ #define IPU_PSYS_CLOSE_TIMEOUT (100000 / IPU_PSYS_CLOSE_TIMEOUT_US) #define IPU_MAX_RESOURCES 128 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) +extern enum ipu6_version ipu_ver; + +#endif /* Opaque structure. Do not access fields. */ struct ipu_resource { u32 id; @@ -90,16 +199,23 @@ struct ipu_psys { struct list_head fhs; struct list_head pgs; struct list_head started_kcmds_list; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) struct ipu_psys_pdata *pdata; struct ipu_bus_device *adev; +#else + struct ipu6_psys_pdata *pdata; + struct ipu6_bus_device *adev; +#endif struct ia_css_syscom_context *dev_ctx; struct ia_css_syscom_config *syscom_config; struct ia_css_psys_server_init *server_init; struct task_struct *sched_cmd_thread; wait_queue_head_t sched_cmd_wq; atomic_t wakeup_count; /* Psys schedule thread wakeup count */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) #ifdef CONFIG_DEBUG_FS struct dentry *debugfsdir; +#endif #endif /* Resources needed to be managed for process groups */ @@ -144,6 +260,13 @@ struct ipu_psys_pg { struct ipu_psys_resource_alloc resource_alloc; }; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) +struct ipu6_psys_constraint { + struct list_head list; + unsigned int min_freq; +}; +#endif + struct ipu_psys_kcmd { struct ipu_psys_fh *fh; struct list_head list; @@ -163,7 +286,11 @@ struct ipu_psys_kcmd { u32 terminal_enable_bitmap[4]; u32 routing_enable_bitmap[4]; u32 rbm[5]; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) struct ipu_buttress_constraint constraint; +#else + struct ipu6_psys_constraint constraint; +#endif struct ipu_psys_event ev; struct timer_list watchdog; }; @@ -173,7 +300,9 @@ struct ipu_dma_buf_attach { u64 len; void *userptr; struct sg_table *sgt; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) bool vma_is_io; +#endif struct page **pages; size_t npages; }; @@ -202,11 +331,6 @@ struct ipu_psys_desc { #define inode_to_ipu_psys(inode) \ container_of((inode)->i_cdev, struct ipu_psys, cdev) -#ifdef CONFIG_COMPAT -long ipu_psys_compat_ioctl32(struct file *file, unsigned int cmd, - unsigned long arg); -#endif - void ipu_psys_setup_hw(struct ipu_psys *psys); void ipu_psys_subdomains_power(struct ipu_psys *psys, bool on); void ipu_psys_handle_events(struct ipu_psys *psys); @@ -219,9 +343,6 @@ struct ipu_psys_kbuffer * ipu_psys_mapbuf_locked(int fd, struct ipu_psys_fh *fh); struct ipu_psys_kbuffer * ipu_psys_lookup_kbuffer_by_kaddr(struct ipu_psys_fh *fh, void *kaddr); -#ifdef IPU_PSYS_GPC -int ipu_psys_gpc_init_debugfs(struct ipu_psys *psys); -#endif int ipu_psys_resource_pool_init(struct ipu_psys_resource_pool *pool); void ipu_psys_resource_pool_cleanup(struct ipu_psys_resource_pool *pool); struct ipu_psys_kcmd *ipu_get_completed_kcmd(struct ipu_psys_fh *fh); diff --git a/drivers/media/pci/intel/ipu6/ipu-resources.c b/drivers/media/pci/intel/ipu6/psys/ipu-resources.c similarity index 94% rename from drivers/media/pci/intel/ipu6/ipu-resources.c rename to drivers/media/pci/intel/ipu6/psys/ipu-resources.c index b607b0716f56..126f01ea8db6 100644 --- a/drivers/media/pci/intel/ipu6/ipu-resources.c +++ b/drivers/media/pci/intel/ipu6/psys/ipu-resources.c @@ -13,6 +13,7 @@ #include "ipu-psys.h" struct ipu6_psys_hw_res_variant hw_var; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) void ipu6_psys_hw_res_variant_init(void) { if (ipu_ver == IPU_VER_6SE) { @@ -45,6 +46,40 @@ static const struct ipu_fw_resource_definitions *get_res(void) return ipu6_res_defs; } +#else +void ipu6_psys_hw_res_variant_init(void) +{ + if (ipu_ver == IPU6_VER_6SE) { + hw_var.queue_num = IPU6SE_FW_PSYS_N_PSYS_CMD_QUEUE_ID; + hw_var.cell_num = IPU6SE_FW_PSYS_N_CELL_ID; + } else if (ipu_ver == IPU6_VER_6) { + hw_var.queue_num = IPU6_FW_PSYS_N_PSYS_CMD_QUEUE_ID; + hw_var.cell_num = IPU6_FW_PSYS_N_CELL_ID; + } else if (ipu_ver == IPU6_VER_6EP || ipu_ver == IPU6_VER_6EP_MTL) { + hw_var.queue_num = IPU6_FW_PSYS_N_PSYS_CMD_QUEUE_ID; + hw_var.cell_num = IPU6EP_FW_PSYS_N_CELL_ID; + } else { + WARN(1, "ipu6 psys res var is not initialised correctly."); + } + + hw_var.set_proc_dev_chn = ipu6_fw_psys_set_proc_dev_chn; + hw_var.set_proc_dfm_bitmap = ipu6_fw_psys_set_proc_dfm_bitmap; + hw_var.set_proc_ext_mem = ipu6_fw_psys_set_process_ext_mem; + hw_var.get_pgm_by_proc = + ipu6_fw_psys_get_program_manifest_by_process; +} + +static const struct ipu_fw_resource_definitions *get_res(void) +{ + if (ipu_ver == IPU6_VER_6SE) + return ipu6se_res_defs; + + if (ipu_ver == IPU6_VER_6EP || ipu_ver == IPU6_VER_6EP_MTL) + return ipu6ep_res_defs; + + return ipu6_res_defs; +} +#endif static int ipu_resource_init(struct ipu_resource *res, u32 id, int elements) { @@ -171,7 +206,11 @@ int ipu_psys_resource_pool_init(struct ipu_psys_resource_pool *pool) } spin_lock(&pool->queues_lock); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) if (ipu_ver == IPU_VER_6SE) +#else + if (ipu_ver == IPU6_VER_6SE) +#endif bitmap_zero(pool->cmd_queues, IPU6SE_FW_PSYS_N_PSYS_CMD_QUEUE_ID); else @@ -380,7 +419,11 @@ int ipu_psys_allocate_cmd_queue_resource(struct ipu_psys_resource_pool *pool) size = IPU6_FW_PSYS_N_PSYS_CMD_QUEUE_ID; start = IPU6_FW_PSYS_CMD_QUEUE_PPG0_COMMAND_ID; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) if (ipu_ver == IPU_VER_6SE) { +#else + if (ipu_ver == IPU6_VER_6SE) { +#endif size = IPU6SE_FW_PSYS_N_PSYS_CMD_QUEUE_ID; start = IPU6SE_FW_PSYS_CMD_QUEUE_PPG0_COMMAND_ID; } diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-resources.c b/drivers/media/pci/intel/ipu6/psys/ipu6-fw-resources.c similarity index 87% rename from drivers/media/pci/intel/ipu6/ipu6-fw-resources.c rename to drivers/media/pci/intel/ipu6/psys/ipu6-fw-resources.c index fa89a4a7ba7e..c809b53fc301 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-fw-resources.c +++ b/drivers/media/pci/intel/ipu6/psys/ipu6-fw-resources.c @@ -539,6 +539,7 @@ int ipu6_fw_psys_get_program_manifest_by_process( return 0; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) #if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) || \ (defined(CONFIG_DYNAMIC_DEBUG_CORE) && defined(DYNAMIC_DEBUG_MODULE)) void ipu6_fw_psys_pg_dump(struct ipu_psys *psys, @@ -607,3 +608,71 @@ void ipu6_fw_psys_pg_dump(struct ipu_psys *psys, WARN(1, "%s ipu_ver:[%u] is unsupported!\n", __func__, ipu_ver); } #endif +#else +#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) || \ + (defined(CONFIG_DYNAMIC_DEBUG_CORE) && defined(DYNAMIC_DEBUG_MODULE)) +void ipu6_fw_psys_pg_dump(struct ipu_psys *psys, + struct ipu_psys_kcmd *kcmd, const char *note) +{ + struct ipu_fw_psys_process_group *pg = kcmd->kpg->pg; + struct device *dev = &psys->adev->auxdev.dev; + u32 pgid = pg->ID; + u8 processes = pg->process_count; + u16 *process_offset_table = (u16 *)((char *)pg + pg->processes_offset); + unsigned int p, chn, mem, mem_id; + unsigned int mem_type, max_mem_id, dev_chn; + + if (ipu_ver == IPU6_VER_6SE) { + mem_type = IPU6SE_FW_PSYS_N_DATA_MEM_TYPE_ID; + max_mem_id = IPU6SE_FW_PSYS_N_MEM_ID; + dev_chn = IPU6SE_FW_PSYS_N_DEV_CHN_ID; + } else if (ipu_ver == IPU6_VER_6 || ipu_ver == IPU6_VER_6EP || + ipu_ver == IPU6_VER_6EP_MTL) { + mem_type = IPU6_FW_PSYS_N_DATA_MEM_TYPE_ID; + max_mem_id = IPU6_FW_PSYS_N_MEM_ID; + dev_chn = IPU6_FW_PSYS_N_DEV_CHN_ID; + } else { + WARN(1, "%s ipu_ver:[%u] is unsupported!\n", __func__, ipu_ver); + return; + } + + dev_dbg(dev, "%s %s pgid %i has %i processes:\n", + __func__, note, pgid, processes); + + for (p = 0; p < processes; p++) { + struct ipu_fw_psys_process *process = + (struct ipu_fw_psys_process *) + ((char *)pg + process_offset_table[p]); + struct ipu6_fw_psys_process_ext *pm_ext = + (struct ipu6_fw_psys_process_ext *)((u8 *)process + + process->process_extension_offset); + dev_dbg(dev, "\t process %i size=%u", p, process->size); + if (!process->process_extension_offset) + continue; + + for (mem = 0; mem < mem_type; mem++) { + mem_id = pm_ext->ext_mem_id[mem]; + if (mem_id != max_mem_id) + dev_dbg(dev, "\t mem type %u id %d offset=0x%x", + mem, mem_id, + pm_ext->ext_mem_offset[mem]); + } + for (chn = 0; chn < dev_chn; chn++) { + if (pm_ext->dev_chn_offset[chn] != (u16)(-1)) + dev_dbg(dev, "\t dev_chn[%u]=0x%x\n", + chn, pm_ext->dev_chn_offset[chn]); + } + } +} +#else +void ipu6_fw_psys_pg_dump(struct ipu_psys *psys, + struct ipu_psys_kcmd *kcmd, const char *note) +{ + if (ipu_ver == IPU6_VER_6SE || ipu_ver == IPU6_VER_6 || + ipu_ver == IPU6_VER_6EP || ipu_ver == IPU6_VER_6EP_MTL) + return; + + WARN(1, "%s ipu_ver:[%u] is unsupported!\n", __func__, ipu_ver); +} +#endif +#endif diff --git a/drivers/media/pci/intel/ipu6/ipu6-l-scheduler.c b/drivers/media/pci/intel/ipu6/psys/ipu6-l-scheduler.c similarity index 85% rename from drivers/media/pci/intel/ipu6/ipu6-l-scheduler.c rename to drivers/media/pci/intel/ipu6/psys/ipu6-l-scheduler.c index 0d5f84a1ee31..d135ee09a01a 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-l-scheduler.c +++ b/drivers/media/pci/intel/ipu6/psys/ipu6-l-scheduler.c @@ -50,14 +50,23 @@ void ipu_psys_scheduler_remove_kppg(struct ipu_psys_ppg *kppg, struct sched_list *sc_list = get_sc_list(type); struct ipu_psys_ppg *tmp0, *tmp1; struct ipu_psys *psys = kppg->fh->psys; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; +#endif mutex_lock(&sc_list->lock); list_for_each_entry_safe(tmp0, tmp1, &sc_list->list, sched_list) { if (tmp0 == kppg) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "remove from %s list, kppg(%d 0x%p) state %d\n", type == SCHED_START_LIST ? "start" : "stop", kppg->kpg->pg->ID, kppg, kppg->state); +#else + dev_dbg(dev, "remove from %s list, kppg(%d 0x%p) state %d\n", + type == SCHED_START_LIST ? "start" : "stop", + kppg->kpg->pg->ID, kppg, kppg->state); +#endif list_del_init(&kppg->sched_list); } } @@ -70,9 +79,16 @@ void ipu_psys_scheduler_add_kppg(struct ipu_psys_ppg *kppg, int cur_pri = kppg->pri_base + kppg->pri_dynamic; struct sched_list *sc_list = get_sc_list(type); struct ipu_psys *psys = kppg->fh->psys; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; +#endif struct ipu_psys_ppg *tmp0, *tmp1; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, +#else + dev_dbg(dev, +#endif "add to %s list, kppg(%d 0x%p) state %d prio(%d %d) fh 0x%p\n", type == SCHED_START_LIST ? "start" : "stop", kppg->kpg->pg->ID, kppg, kppg->state, @@ -85,14 +101,22 @@ void ipu_psys_scheduler_add_kppg(struct ipu_psys_ppg *kppg, } if (is_kppg_in_list(kppg, &sc_list->list)) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "kppg already in list\n"); +#else + dev_dbg(dev, "kppg already in list\n"); +#endif goto out; } list_for_each_entry_safe(tmp0, tmp1, &sc_list->list, sched_list) { int tmp_pri = tmp0->pri_base + tmp0->pri_dynamic; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, +#else + dev_dbg(dev, +#endif "found kppg(%d 0x%p), state %d pri(%d %d) fh 0x%p\n", tmp0->kpg->pg->ID, tmp0, tmp0->state, tmp0->pri_base, tmp0->pri_dynamic, tmp0->fh); @@ -115,6 +139,9 @@ static int ipu_psys_detect_resource_contention(struct ipu_psys_ppg *kppg) { struct ipu_psys_resource_pool *try_res_pool; struct ipu_psys *psys = kppg->fh->psys; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; +#endif int ret = 0; int state; @@ -131,14 +158,22 @@ static int ipu_psys_detect_resource_contention(struct ipu_psys_ppg *kppg) ret = ipu_psys_resource_pool_init(try_res_pool); if (ret < 0) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_err(&psys->adev->dev, "unable to alloc pg resources\n"); +#else + dev_err(dev, "unable to alloc pg resources\n"); +#endif WARN_ON(1); goto exit; } ipu_psys_resource_copy(&psys->resource_pool_running, try_res_pool); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) ret = ipu_psys_try_allocate_resources(&psys->adev->dev, kppg->kpg->pg, +#else + ret = ipu_psys_try_allocate_resources(dev, kppg->kpg->pg, +#endif kppg->manifest, try_res_pool); @@ -202,13 +237,20 @@ static void ipu_psys_scheduler_update_start_ppg_priority(void) static bool ipu_psys_scheduler_switch_ppg(struct ipu_psys *psys) { struct sched_list *sc_list = get_sc_list(SCHED_STOP_LIST); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; +#endif struct ipu_psys_ppg *kppg; bool resched = false; mutex_lock(&sc_list->lock); if (list_empty(&sc_list->list)) { /* some ppgs are RESUMING/STARTING */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "no candidated stop ppg\n"); +#else + dev_dbg(dev, "no candidated stop ppg\n"); +#endif mutex_unlock(&sc_list->lock); return false; } @@ -218,7 +260,11 @@ static bool ipu_psys_scheduler_switch_ppg(struct ipu_psys *psys) mutex_lock(&kppg->mutex); if (!(kppg->state & PPG_STATE_STOP)) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "s_change:%s: %p %d -> %d\n", +#else + dev_dbg(dev, "s_change:%s: %p %d -> %d\n", +#endif __func__, kppg, kppg->state, PPG_STATE_SUSPEND); kppg->state = PPG_STATE_SUSPEND; resched = true; @@ -237,6 +283,9 @@ static bool ipu_psys_scheduler_switch_ppg(struct ipu_psys *psys) static bool ipu_psys_scheduler_ppg_start(struct ipu_psys *psys) { struct sched_list *sc_list = get_sc_list(SCHED_START_LIST); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; +#endif struct ipu_psys_ppg *kppg, *kppg0; bool stopping_existed = false; int ret; @@ -245,7 +294,11 @@ static bool ipu_psys_scheduler_ppg_start(struct ipu_psys *psys) mutex_lock(&sc_list->lock); if (list_empty(&sc_list->list)) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "no ppg to start\n"); +#else + dev_dbg(dev, "no ppg to start\n"); +#endif mutex_unlock(&sc_list->lock); return false; } @@ -256,8 +309,12 @@ static bool ipu_psys_scheduler_ppg_start(struct ipu_psys *psys) ret = ipu_psys_detect_resource_contention(kppg); if (ret < 0) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "ppg %d resource detect failed(%d)\n", +#else + dev_dbg(dev, "ppg %d resource detect failed(%d)\n", +#endif kppg->kpg->pg->ID, ret); /* * switch out other ppg in 2 cases: @@ -269,11 +326,19 @@ static bool ipu_psys_scheduler_ppg_start(struct ipu_psys *psys) ipu_psys_scheduler_switch_ppg(psys)) { return true; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "ppg is suspending/stopping\n"); +#else + dev_dbg(dev, "ppg is suspending/stopping\n"); +#endif } else { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_err(&psys->adev->dev, "detect resource error %d\n", ret); +#else + dev_err(dev, "detect resource error %d\n", ret); +#endif } } else { kppg->pri_dynamic = 0; @@ -367,6 +432,9 @@ static void ipu_psys_update_ppg_state_by_kcmd(struct ipu_psys *psys, struct ipu_psys_ppg *kppg, struct ipu_psys_kcmd *kcmd) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; +#endif int old_ppg_state = kppg->state; /* @@ -397,13 +465,21 @@ static void ipu_psys_update_ppg_state_by_kcmd(struct ipu_psys *psys, else if (kcmd->state == KCMD_STATE_PPG_STOP) ipu_psys_kcmd_complete(kppg, kcmd, 0); else if (kcmd->state == KCMD_STATE_PPG_ENQUEUE) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_err(&psys->adev->dev, "ppg %p stopped!\n", kppg); +#else + dev_err(dev, "ppg %p stopped!\n", kppg); +#endif ipu_psys_kcmd_complete(kppg, kcmd, -EIO); } } if (old_ppg_state != kppg->state) +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "s_change:%s: %p %d -> %d\n", +#else + dev_dbg(dev, "s_change:%s: %p %d -> %d\n", +#endif __func__, kppg, old_ppg_state, kppg->state); } @@ -507,9 +583,17 @@ static bool has_pending_kcmd(struct ipu_psys *psys) static bool ipu_psys_scheduler_exit_power_gating(struct ipu_psys *psys) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; + +#endif /* Assume power gating process can be aborted directly during START */ if (psys->power_gating == PSYS_POWER_GATED) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "powergating: exit ---\n"); +#else + dev_dbg(dev, "powergating: exit ---\n"); +#endif ipu_psys_exit_power_gating(psys); } psys->power_gating = PSYS_POWER_NORMAL; @@ -518,6 +602,9 @@ static bool ipu_psys_scheduler_exit_power_gating(struct ipu_psys *psys) static bool ipu_psys_scheduler_enter_power_gating(struct ipu_psys *psys) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; +#endif struct ipu_psys_scheduler *sched; struct ipu_psys_ppg *kppg, *tmp; struct ipu_psys_fh *fh; @@ -528,7 +615,11 @@ static bool ipu_psys_scheduler_enter_power_gating(struct ipu_psys *psys) if (psys->power_gating == PSYS_POWER_NORMAL && is_ready_to_enter_power_gating(psys)) { /* Enter power gating */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "powergating: enter +++\n"); +#else + dev_dbg(dev, "powergating: enter +++\n"); +#endif psys->power_gating = PSYS_POWER_GATING; } @@ -575,6 +666,9 @@ static bool ipu_psys_scheduler_enter_power_gating(struct ipu_psys *psys) void ipu_psys_run_next(struct ipu_psys *psys) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; +#endif /* Wake up scheduler due to unfinished work */ bool need_trigger = false; /* Wait FW callback if there are stopping/suspending/running ppg */ @@ -608,7 +702,11 @@ void ipu_psys_run_next(struct ipu_psys *psys) } if (need_trigger && !wait_fw_finish) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "scheduler: wake up\n"); +#else + dev_dbg(dev, "scheduler: wake up\n"); +#endif atomic_set(&psys->wakeup_count, 1); wake_up_interruptible(&psys->sched_cmd_wq); } diff --git a/drivers/media/pci/intel/ipu6/ipu6-platform-resources.h b/drivers/media/pci/intel/ipu6/psys/ipu6-platform-resources.h similarity index 100% rename from drivers/media/pci/intel/ipu6/ipu6-platform-resources.h rename to drivers/media/pci/intel/ipu6/psys/ipu6-platform-resources.h diff --git a/drivers/media/pci/intel/ipu6/ipu6-ppg.c b/drivers/media/pci/intel/ipu6/psys/ipu6-ppg.c similarity index 59% rename from drivers/media/pci/intel/ipu6/ipu6-ppg.c rename to drivers/media/pci/intel/ipu6/psys/ipu6-ppg.c index 309171bb35c2..9038f69cd10f 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-ppg.c +++ b/drivers/media/pci/intel/ipu6/psys/ipu6-ppg.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2020 - 2024 Intel Corporation +#include #include #include @@ -48,6 +49,9 @@ struct ipu_psys_kcmd *ipu_psys_ppg_get_stop_kcmd(struct ipu_psys_ppg *kppg) static struct ipu_psys_buffer_set * __get_buf_set(struct ipu_psys_fh *fh, size_t buf_set_size) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &fh->psys->adev->auxdev.dev; +#endif struct ipu_psys_buffer_set *kbuf_set; struct ipu_psys_scheduler *sched = &fh->sched; @@ -67,9 +71,14 @@ __get_buf_set(struct ipu_psys_fh *fh, size_t buf_set_size) if (!kbuf_set) return NULL; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) kbuf_set->kaddr = dma_alloc_attrs(&fh->psys->adev->dev, buf_set_size, &kbuf_set->dma_addr, GFP_KERNEL, 0); +#else + kbuf_set->kaddr = dma_alloc_attrs(dev, buf_set_size, + &kbuf_set->dma_addr, GFP_KERNEL, 0); +#endif if (!kbuf_set->kaddr) { kfree(kbuf_set); return NULL; @@ -90,6 +99,9 @@ ipu_psys_create_buffer_set(struct ipu_psys_kcmd *kcmd, { struct ipu_psys_fh *fh = kcmd->fh; struct ipu_psys *psys = fh->psys; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; +#endif struct ipu_psys_buffer_set *kbuf_set; size_t buf_set_size; u32 *keb; @@ -98,7 +110,11 @@ ipu_psys_create_buffer_set(struct ipu_psys_kcmd *kcmd, kbuf_set = __get_buf_set(fh, buf_set_size); if (!kbuf_set) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_err(&psys->adev->dev, "failed to create buffer set\n"); +#else + dev_err(dev, "failed to create buffer set\n"); +#endif return NULL; } @@ -115,6 +131,7 @@ ipu_psys_create_buffer_set(struct ipu_psys_kcmd *kcmd, return kbuf_set; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) int ipu_psys_ppg_get_bufset(struct ipu_psys_kcmd *kcmd, struct ipu_psys_ppg *kppg) { @@ -432,6 +449,325 @@ int ipu_psys_ppg_suspend(struct ipu_psys_ppg *kppg) return ret; } +#else +int ipu_psys_ppg_get_bufset(struct ipu_psys_kcmd *kcmd, + struct ipu_psys_ppg *kppg) +{ + struct ipu_psys *psys = kppg->fh->psys; + struct device *dev = &psys->adev->auxdev.dev; + struct ipu_psys_buffer_set *kbuf_set; + unsigned int i; + int ret; + + kbuf_set = ipu_psys_create_buffer_set(kcmd, kppg); + if (!kbuf_set) { + ret = -EINVAL; + goto error; + } + kcmd->kbuf_set = kbuf_set; + kbuf_set->kcmd = kcmd; + + for (i = 0; i < kcmd->nbuffers; i++) { + struct ipu_fw_psys_terminal *terminal; + u32 buffer; + + terminal = ipu_fw_psys_pg_get_terminal(kcmd, i); + if (!terminal) + continue; + + buffer = (u32)kcmd->kbufs[i]->dma_addr + + kcmd->buffers[i].data_offset; + + ret = ipu_fw_psys_ppg_set_buffer_set(kcmd, terminal, i, buffer); + if (ret) { + dev_err(dev, "Unable to set bufset\n"); + goto error; + } + } + + return 0; + +error: + dev_err(dev, "failed to get buffer set\n"); + return ret; +} + +void ipu_psys_ppg_complete(struct ipu_psys *psys, struct ipu_psys_ppg *kppg) +{ + struct device *dev; + u8 queue_id; + int old_ppg_state; + + if (!psys || !kppg) + return; + + dev = &psys->adev->auxdev.dev; + + mutex_lock(&kppg->mutex); + old_ppg_state = kppg->state; + if (kppg->state == PPG_STATE_STOPPING) { + struct ipu_psys_kcmd tmp_kcmd = { + .kpg = kppg->kpg, + }; + + kppg->state = PPG_STATE_STOPPED; + ipu_psys_free_resources(&kppg->kpg->resource_alloc, + &psys->resource_pool_running); + queue_id = ipu_fw_psys_ppg_get_base_queue_id(&tmp_kcmd); + ipu_psys_free_cmd_queue_resource(&psys->resource_pool_running, queue_id); + pm_runtime_put(dev); + } else { + if (kppg->state == PPG_STATE_SUSPENDING) { + kppg->state = PPG_STATE_SUSPENDED; + ipu_psys_free_resources(&kppg->kpg->resource_alloc, + &psys->resource_pool_running); + } else if (kppg->state == PPG_STATE_STARTED || + kppg->state == PPG_STATE_RESUMED) { + kppg->state = PPG_STATE_RUNNING; + } + + /* Kick l-scheduler thread for FW callback, + * also for checking if need to enter power gating + */ + atomic_set(&psys->wakeup_count, 1); + wake_up_interruptible(&psys->sched_cmd_wq); + } + if (old_ppg_state != kppg->state) + dev_dbg(dev, "s_change:%s: %p %d -> %d\n", __func__, kppg, + old_ppg_state, kppg->state); + + mutex_unlock(&kppg->mutex); +} + +int ipu_psys_ppg_start(struct ipu_psys_ppg *kppg) +{ + struct ipu_psys *psys = kppg->fh->psys; + struct device *dev = &psys->adev->auxdev.dev; + struct ipu_psys_kcmd *kcmd = ipu_psys_ppg_get_kcmd(kppg, + KCMD_STATE_PPG_START); + unsigned int i; + int ret; + + if (!kcmd) { + dev_err(dev, "failed to find start kcmd!\n"); + return -EINVAL; + } + + dev_dbg(dev, "start ppg id %d, addr 0x%p\n", + ipu_fw_psys_pg_get_id(kcmd), kppg); + + kppg->state = PPG_STATE_STARTING; + for (i = 0; i < kcmd->nbuffers; i++) { + struct ipu_fw_psys_terminal *terminal; + + terminal = ipu_fw_psys_pg_get_terminal(kcmd, i); + if (!terminal) + continue; + + ret = ipu_fw_psys_terminal_set(terminal, i, kcmd, 0, + kcmd->buffers[i].len); + if (ret) { + dev_err(dev, "Unable to set terminal\n"); + return ret; + } + } + + ret = ipu_fw_psys_pg_submit(kcmd); + if (ret) { + dev_err(dev, "failed to submit kcmd!\n"); + return ret; + } + + ret = ipu_psys_allocate_resources(dev, kcmd->kpg->pg, kcmd->pg_manifest, + &kcmd->kpg->resource_alloc, + &psys->resource_pool_running); + if (ret) { + dev_err(dev, "alloc resources failed!\n"); + return ret; + } + + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + dev_err(dev, "failed to power on psys\n"); + goto error; + } + + ret = ipu_psys_kcmd_start(psys, kcmd); + if (ret) { + ipu_psys_kcmd_complete(kppg, kcmd, -EIO); + goto error; + } + + dev_dbg(dev, "s_change:%s: %p %d -> %d\n", + __func__, kppg, kppg->state, PPG_STATE_STARTED); + kppg->state = PPG_STATE_STARTED; + ipu_psys_kcmd_complete(kppg, kcmd, 0); + + return 0; + +error: + pm_runtime_put_noidle(dev); + ipu_psys_reset_process_cell(dev, kcmd->kpg->pg, kcmd->pg_manifest, + kcmd->kpg->pg->process_count); + ipu_psys_free_resources(&kppg->kpg->resource_alloc, + &psys->resource_pool_running); + + dev_err(dev, "failed to start ppg\n"); + return ret; +} + +int ipu_psys_ppg_resume(struct ipu_psys_ppg *kppg) +{ + struct ipu_psys *psys = kppg->fh->psys; + struct device *dev = &psys->adev->auxdev.dev; + struct ipu_psys_kcmd tmp_kcmd = { + .kpg = kppg->kpg, + .fh = kppg->fh, + }; + int ret; + + dev_dbg(dev, "resume ppg id %d, addr 0x%p\n", + ipu_fw_psys_pg_get_id(&tmp_kcmd), kppg); + + kppg->state = PPG_STATE_RESUMING; + if (enable_suspend_resume) { + ret = ipu_psys_allocate_resources(dev, kppg->kpg->pg, + kppg->manifest, + &kppg->kpg->resource_alloc, + &psys->resource_pool_running); + if (ret) { + dev_err(dev, "failed to allocate res\n"); + return -EIO; + } + + ret = ipu_fw_psys_ppg_resume(&tmp_kcmd); + if (ret) { + dev_err(dev, "failed to resume ppg\n"); + goto error; + } + } else { + kppg->kpg->pg->state = IPU_FW_PSYS_PROCESS_GROUP_READY; + ret = ipu_fw_psys_pg_submit(&tmp_kcmd); + if (ret) { + dev_err(dev, "failed to submit kcmd!\n"); + return ret; + } + + ret = ipu_psys_allocate_resources(dev, kppg->kpg->pg, + kppg->manifest, + &kppg->kpg->resource_alloc, + &psys->resource_pool_running); + if (ret) { + dev_err(dev, "failed to allocate res\n"); + return ret; + } + + ret = ipu_psys_kcmd_start(psys, &tmp_kcmd); + if (ret) { + dev_err(dev, "failed to start kcmd!\n"); + goto error; + } + } + dev_dbg(dev, "s_change:%s: %p %d -> %d\n", + __func__, kppg, kppg->state, PPG_STATE_RESUMED); + kppg->state = PPG_STATE_RESUMED; + + return 0; + +error: + ipu_psys_reset_process_cell(dev, kppg->kpg->pg, kppg->manifest, + kppg->kpg->pg->process_count); + ipu_psys_free_resources(&kppg->kpg->resource_alloc, + &psys->resource_pool_running); + + return ret; +} + +int ipu_psys_ppg_stop(struct ipu_psys_ppg *kppg) +{ + struct ipu_psys_kcmd *kcmd = ipu_psys_ppg_get_kcmd(kppg, + KCMD_STATE_PPG_STOP); + struct ipu_psys *psys = kppg->fh->psys; + struct device *dev = &psys->adev->auxdev.dev; + struct ipu_psys_kcmd kcmd_temp; + int ppg_id, ret = 0; + + if (kcmd) { + list_move_tail(&kcmd->list, &kppg->kcmds_processing_list); + } else { + dev_dbg(dev, "Exceptional stop happened!\n"); + kcmd_temp.kpg = kppg->kpg; + kcmd_temp.fh = kppg->fh; + kcmd = &kcmd_temp; + /* delete kppg in stop list to avoid this ppg resuming */ + ipu_psys_scheduler_remove_kppg(kppg, SCHED_STOP_LIST); + } + + ppg_id = ipu_fw_psys_pg_get_id(kcmd); + dev_dbg(dev, "stop ppg(%d, addr 0x%p)\n", ppg_id, kppg); + + if (kppg->state & PPG_STATE_SUSPENDED) { + if (enable_suspend_resume) { + dev_dbg(dev, "need resume before stop!\n"); + kcmd_temp.kpg = kppg->kpg; + kcmd_temp.fh = kppg->fh; + ret = ipu_fw_psys_ppg_resume(&kcmd_temp); + if (ret) + dev_err(dev, "ppg(%d) failed to resume\n", + ppg_id); + } else if (kcmd != &kcmd_temp) { + u8 queue_id = ipu_fw_psys_ppg_get_base_queue_id(kcmd); + + ipu_psys_free_cmd_queue_resource(&psys->resource_pool_running, + queue_id); + ipu_psys_kcmd_complete(kppg, kcmd, 0); + dev_dbg(dev, "s_change:%s %p %d -> %d\n", __func__, + kppg, kppg->state, PPG_STATE_STOPPED); + pm_runtime_put(dev); + kppg->state = PPG_STATE_STOPPED; + + return 0; + } else { + return 0; + } + } + dev_dbg(dev, "s_change:%s %p %d -> %d\n", __func__, kppg, kppg->state, + PPG_STATE_STOPPING); + kppg->state = PPG_STATE_STOPPING; + ret = ipu_fw_psys_pg_abort(kcmd); + if (ret) + dev_err(dev, "ppg(%d) failed to abort\n", ppg_id); + + return ret; +} + +int ipu_psys_ppg_suspend(struct ipu_psys_ppg *kppg) +{ + struct ipu_psys *psys = kppg->fh->psys; + struct device *dev = &psys->adev->auxdev.dev; + struct ipu_psys_kcmd tmp_kcmd = { + .kpg = kppg->kpg, + .fh = kppg->fh, + }; + int ppg_id = ipu_fw_psys_pg_get_id(&tmp_kcmd); + int ret = 0; + + dev_dbg(dev, "suspend ppg(%d, addr 0x%p)\n", ppg_id, kppg); + + dev_dbg(dev, "s_change:%s %p %d -> %d\n", __func__, kppg, kppg->state, + PPG_STATE_SUSPENDING); + kppg->state = PPG_STATE_SUSPENDING; + if (enable_suspend_resume) + ret = ipu_fw_psys_ppg_suspend(&tmp_kcmd); + else + ret = ipu_fw_psys_pg_abort(&tmp_kcmd); + if (ret) + dev_err(dev, "failed to %s ppg(%d)\n", + enable_suspend_resume ? "suspend" : "stop", ret); + + return ret; +} +#endif static bool ipu_psys_ppg_is_bufset_existing(struct ipu_psys_ppg *kppg) { @@ -448,6 +784,9 @@ bool ipu_psys_ppg_enqueue_bufsets(struct ipu_psys_ppg *kppg) { struct ipu_psys_kcmd *kcmd, *kcmd0; struct ipu_psys *psys = kppg->fh->psys; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; +#endif bool need_resume = false; mutex_lock(&kppg->mutex); @@ -466,14 +805,22 @@ bool ipu_psys_ppg_enqueue_bufsets(struct ipu_psys_ppg *kppg) ret = ipu_fw_psys_ppg_enqueue_bufs(kcmd); if (ret) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_err(&psys->adev->dev, +#else + dev_err(dev, +#endif "kppg 0x%p fail to qbufset %d", kppg, ret); break; } list_move_tail(&kcmd->list, &kppg->kcmds_processing_list); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, +#else + dev_dbg(dev, +#endif "kppg %d %p queue kcmd 0x%p fh 0x%p\n", ipu_fw_psys_pg_get_id(kcmd), kppg, kcmd, kcmd->fh); @@ -487,6 +834,9 @@ bool ipu_psys_ppg_enqueue_bufsets(struct ipu_psys_ppg *kppg) void ipu_psys_enter_power_gating(struct ipu_psys *psys) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; +#endif struct ipu_psys_scheduler *sched; struct ipu_psys_ppg *kppg, *tmp; struct ipu_psys_fh *fh; @@ -511,6 +861,7 @@ void ipu_psys_enter_power_gating(struct ipu_psys *psys) continue; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) ret = pm_runtime_put(&psys->adev->dev); if (ret < 0) { dev_err(&psys->adev->dev, @@ -518,6 +869,13 @@ void ipu_psys_enter_power_gating(struct ipu_psys *psys) pm_runtime_get_sync(&psys->adev->dev); } +#else + ret = pm_runtime_put(dev); + if (ret < 0) { + dev_err(dev, "failed to power gating off\n"); + pm_runtime_get_sync(dev); + } +#endif mutex_unlock(&kppg->mutex); } mutex_unlock(&fh->mutex); @@ -526,6 +884,9 @@ void ipu_psys_enter_power_gating(struct ipu_psys *psys) void ipu_psys_exit_power_gating(struct ipu_psys *psys) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; +#endif struct ipu_psys_scheduler *sched; struct ipu_psys_ppg *kppg, *tmp; struct ipu_psys_fh *fh; @@ -547,12 +908,20 @@ void ipu_psys_exit_power_gating(struct ipu_psys *psys) continue; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) ret = pm_runtime_get_sync(&psys->adev->dev); if (ret < 0) { dev_err(&psys->adev->dev, "failed to power gating\n"); pm_runtime_put_noidle(&psys->adev->dev); } +#else + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + dev_err(dev, "failed to power gating\n"); + pm_runtime_put_noidle(dev); + } +#endif mutex_unlock(&kppg->mutex); } mutex_unlock(&fh->mutex); diff --git a/drivers/media/pci/intel/ipu6/ipu6-ppg.h b/drivers/media/pci/intel/ipu6/psys/ipu6-ppg.h similarity index 100% rename from drivers/media/pci/intel/ipu6/ipu6-ppg.h rename to drivers/media/pci/intel/ipu6/psys/ipu6-ppg.h diff --git a/drivers/media/pci/intel/ipu6/ipu6-psys-gpc.c b/drivers/media/pci/intel/ipu6/psys/ipu6-psys-gpc.c similarity index 100% rename from drivers/media/pci/intel/ipu6/ipu6-psys-gpc.c rename to drivers/media/pci/intel/ipu6/psys/ipu6-psys-gpc.c diff --git a/drivers/media/pci/intel/ipu6/ipu6-psys.c b/drivers/media/pci/intel/ipu6/psys/ipu6-psys.c similarity index 75% rename from drivers/media/pci/intel/ipu6/ipu6-psys.c rename to drivers/media/pci/intel/ipu6/psys/ipu6-psys.c index ac5dae41dac4..53c845ba354f 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-psys.c +++ b/drivers/media/pci/intel/ipu6/psys/ipu6-psys.c @@ -18,11 +18,19 @@ #include #include +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) #include "ipu.h" #include "ipu-psys.h" #include "ipu6-ppg.h" #include "ipu-platform-regs.h" #include "ipu-trace.h" +#else +#include "ipu6.h" +#include "ipu-psys.h" +#include "ipu6-ppg.h" +#include "ipu6-platform-regs.h" +#include "ipu6-platform-buttress-regs.h" +#endif MODULE_IMPORT_NS(DMA_BUF); @@ -35,6 +43,7 @@ bool enable_power_gating = true; module_param(enable_power_gating, bool, 0664); MODULE_PARM_DESC(enable_power_gating, "enable power gating"); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) struct ipu_trace_block psys_trace_blocks[] = { { .offset = IPU_TRACE_REG_PS_TRACE_UNIT_BASE, @@ -68,7 +77,9 @@ struct ipu_trace_block psys_trace_blocks[] = { .type = IPU_TRACE_BLOCK_END, } }; +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) static void ipu6_set_sp_info_bits(void *base) { int i; @@ -83,16 +94,39 @@ static void ipu6_set_sp_info_bits(void *base) writel(IPU_INFO_REQUEST_DESTINATION_IOSF, base + IPU_REG_PSYS_INFO_SEG_XMEM_MASTER(i)); } +#else +static void ipu6_set_sp_info_bits(void __iomem *base) +{ + int i; + + writel(IPU6_INFO_REQUEST_DESTINATION_IOSF, + base + IPU6_REG_PSYS_INFO_SEG_0_CONFIG_ICACHE_MASTER); + + for (i = 0; i < 4; i++) + writel(IPU6_INFO_REQUEST_DESTINATION_IOSF, + base + IPU_REG_PSYS_INFO_SEG_CMEM_MASTER(i)); + for (i = 0; i < 4; i++) + writel(IPU6_INFO_REQUEST_DESTINATION_IOSF, + base + IPU_REG_PSYS_INFO_SEG_XMEM_MASTER(i)); +} +#endif #define PSYS_SUBDOMAINS_STATUS_WAIT_COUNT 1000 void ipu_psys_subdomains_power(struct ipu_psys *psys, bool on) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; +#endif unsigned int i; u32 val; /* power domain req */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "power %s psys sub-domains", on ? "UP" : "DOWN"); +#else + dev_dbg(dev, "power %s psys sub-domains", on ? "UP" : "DOWN"); +#endif if (on) writel(IPU_PSYS_SUBDOMAINS_POWER_MASK, psys->adev->isp->base + IPU_PSYS_SUBDOMAINS_POWER_REQ); @@ -106,8 +140,12 @@ void ipu_psys_subdomains_power(struct ipu_psys *psys, bool on) val = readl(psys->adev->isp->base + IPU_PSYS_SUBDOMAINS_POWER_STATUS); if (!(val & BIT(31))) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "PS sub-domains req done with status 0x%x", +#else + dev_dbg(dev, "PS sub-domains req done with status 0x%x", +#endif val); break; } @@ -115,7 +153,11 @@ void ipu_psys_subdomains_power(struct ipu_psys *psys, bool on) } while (i < PSYS_SUBDOMAINS_STATUS_WAIT_COUNT); if (i == PSYS_SUBDOMAINS_STATUS_WAIT_COUNT) +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_warn(&psys->adev->dev, "Psys sub-domains %s req timeout!", +#else + dev_warn(dev, "Psys sub-domains %s req timeout!", +#endif on ? "UP" : "DOWN"); } @@ -124,7 +166,11 @@ void ipu_psys_setup_hw(struct ipu_psys *psys) void __iomem *base = psys->pdata->base; void __iomem *spc_regs_base = base + psys->pdata->ipdata->hw_variant.spc_offset; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) void *psys_iommu0_ctrl; +#else + void __iomem *psys_iommu0_ctrl; +#endif u32 irqs; const u8 r3 = IPU_DEVICE_AB_GROUP1_TARGET_ID_R3_SPC_STATUS_REG; const u8 r4 = IPU_DEVICE_AB_GROUP1_TARGET_ID_R4_SPC_MASTER_BASE_ADDR; @@ -144,7 +190,11 @@ void ipu_psys_setup_hw(struct ipu_psys *psys) } psys_iommu0_ctrl = base + psys->pdata->ipdata->hw_variant.mmu_hw[0].offset + +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) IPU_MMU_INFO_OFFSET; +#else + IPU6_MMU_INFO_OFFSET; +#endif writel(IPU_INFO_REQUEST_DESTINATION_IOSF, psys_iommu0_ctrl); ipu6_set_sp_info_bits(spc_regs_base + IPU_PSYS_REG_SPC_STATUS_CTRL); @@ -152,7 +202,11 @@ void ipu_psys_setup_hw(struct ipu_psys *psys) /* Enable FW interrupt #0 */ writel(0, base + IPU_REG_PSYS_GPDEV_FWIRQ(0)); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) irqs = IPU_PSYS_GPDEV_IRQ_FWIRQ(IPU_PSYS_GPDEV_FWIRQ0); +#else + irqs = IPU6_PSYS_GPDEV_IRQ_FWIRQ(IPU_PSYS_GPDEV_FWIRQ0); +#endif writel(irqs, base + IPU_REG_PSYS_GPDEV_IRQ_EDGE); writel(irqs, base + IPU_REG_PSYS_GPDEV_IRQ_LEVEL_NOT_PULSE); writel(0xffffffff, base + IPU_REG_PSYS_GPDEV_IRQ_CLEAR); @@ -221,6 +275,9 @@ static struct ipu_psys_kcmd *ipu_psys_copy_cmd(struct ipu_psys_command *cmd, struct ipu_psys_fh *fh) { struct ipu_psys *psys = fh->psys; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; +#endif struct ipu_psys_kcmd *kcmd; struct ipu_psys_kbuffer *kpgbuf; unsigned int i; @@ -246,7 +303,11 @@ static struct ipu_psys_kcmd *ipu_psys_copy_cmd(struct ipu_psys_command *cmd, fd = cmd->pg; kpgbuf = ipu_psys_lookup_kbuffer(fh, fd); if (!kpgbuf || !kpgbuf->sgt) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_err(&psys->adev->dev, "%s kbuf %p with fd %d not found.\n", +#else + dev_err(dev, "%s kbuf %p with fd %d not found.\n", +#endif __func__, kpgbuf, fd); mutex_unlock(&fh->mutex); goto error; @@ -255,7 +316,11 @@ static struct ipu_psys_kcmd *ipu_psys_copy_cmd(struct ipu_psys_command *cmd, /* check and remap if possibe */ kpgbuf = ipu_psys_mapbuf_locked(fd, fh); if (!kpgbuf || !kpgbuf->sgt) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_err(&psys->adev->dev, "%s remap failed\n", __func__); +#else + dev_err(dev, "%s remap failed\n", __func__); +#endif mutex_unlock(&fh->mutex); goto error; } @@ -328,8 +393,12 @@ static struct ipu_psys_kcmd *ipu_psys_copy_cmd(struct ipu_psys_command *cmd, continue; } if (kcmd->state == KCMD_STATE_PPG_START) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_err(&psys->adev->dev, "err: all buffer.flags&DMA_HANDLE must 0\n"); +#else + dev_err(dev, "buffer.flags & DMA_HANDLE must be 0\n"); +#endif goto error; } @@ -337,7 +406,11 @@ static struct ipu_psys_kcmd *ipu_psys_copy_cmd(struct ipu_psys_command *cmd, fd = kcmd->buffers[i].base.fd; kpgbuf = ipu_psys_lookup_kbuffer(fh, fd); if (!kpgbuf || !kpgbuf->sgt) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_err(&psys->adev->dev, +#else + dev_err(dev, +#endif "%s kcmd->buffers[%d] %p fd %d not found.\n", __func__, i, kpgbuf, fd); mutex_unlock(&fh->mutex); @@ -346,7 +419,11 @@ static struct ipu_psys_kcmd *ipu_psys_copy_cmd(struct ipu_psys_command *cmd, kpgbuf = ipu_psys_mapbuf_locked(fd, fh); if (!kpgbuf || !kpgbuf->sgt) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_err(&psys->adev->dev, "%s remap failed\n", +#else + dev_err(dev, "%s remap failed\n", +#endif __func__); mutex_unlock(&fh->mutex); goto error; @@ -364,10 +441,16 @@ static struct ipu_psys_kcmd *ipu_psys_copy_cmd(struct ipu_psys_command *cmd, continue; prevfd = kcmd->buffers[i].base.fd; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dma_sync_sg_for_device(&psys->adev->dev, kcmd->kbufs[i]->sgt->sgl, kcmd->kbufs[i]->sgt->orig_nents, DMA_BIDIRECTIONAL); +#else + dma_sync_sg_for_device(dev, kcmd->kbufs[i]->sgt->sgl, + kcmd->kbufs[i]->sgt->orig_nents, + DMA_BIDIRECTIONAL); +#endif } if (kcmd->state != KCMD_STATE_PPG_START) @@ -377,7 +460,11 @@ static struct ipu_psys_kcmd *ipu_psys_copy_cmd(struct ipu_psys_command *cmd, error: ipu_psys_kcmd_free(kcmd); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "failed to copy cmd\n"); +#else + dev_dbg(dev, "failed to copy cmd\n"); +#endif return NULL; } @@ -432,6 +519,78 @@ static struct ipu_psys_ppg *ipu_psys_lookup_ppg(struct ipu_psys *psys, return NULL; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) +#define BUTTRESS_FREQ_CTL_QOS_FLOOR_SHIFT 8 +static void ipu_buttress_set_psys_ratio(struct ipu6_device *isp, + unsigned int psys_divisor, + unsigned int psys_qos_floor) +{ + struct ipu6_buttress_ctrl *ctrl = isp->psys->ctrl; + + mutex_lock(&isp->buttress.power_mutex); + + if (ctrl->ratio == psys_divisor && ctrl->qos_floor == psys_qos_floor) + goto out_mutex_unlock; + + ctrl->ratio = psys_divisor; + ctrl->qos_floor = psys_qos_floor; + + if (ctrl->started) { + /* + * According to documentation driver initiates DVFS + * transition by writing wanted ratio, floor ratio and start + * bit. No need to stop PS first + */ + writel(BUTTRESS_FREQ_CTL_START | + ctrl->qos_floor << BUTTRESS_FREQ_CTL_QOS_FLOOR_SHIFT | + psys_divisor, isp->base + BUTTRESS_REG_PS_FREQ_CTL); + } + +out_mutex_unlock: + mutex_unlock(&isp->buttress.power_mutex); +} + +static void ipu_buttress_set_psys_freq(struct ipu6_device *isp, + unsigned int freq) +{ + unsigned int psys_ratio = freq / BUTTRESS_PS_FREQ_STEP; + + dev_dbg(&isp->psys->auxdev.dev, "freq:%u\n", freq); + + ipu_buttress_set_psys_ratio(isp, psys_ratio, psys_ratio); +} + +static void +ipu_buttress_add_psys_constraint(struct ipu6_device *isp, + struct ipu6_psys_constraint *constraint) +{ + struct ipu6_buttress *b = &isp->buttress; + + mutex_lock(&b->cons_mutex); + list_add(&constraint->list, &b->constraints); + mutex_unlock(&b->cons_mutex); +} + +static void +ipu_buttress_remove_psys_constraint(struct ipu6_device *isp, + struct ipu6_psys_constraint *constraint) +{ + struct ipu6_buttress *b = &isp->buttress; + struct ipu6_psys_constraint *c; + unsigned int min_freq = 0; + + mutex_lock(&b->cons_mutex); + list_del(&constraint->list); + + list_for_each_entry(c, &b->constraints, list) + if (c->min_freq > min_freq) + min_freq = c->min_freq; + + ipu_buttress_set_psys_freq(isp, min_freq); + mutex_unlock(&b->cons_mutex); +} +#endif + /* * Move kcmd into completed state (due to running finished or failure). * Fill up the event struct and notify waiters. @@ -441,6 +600,9 @@ void ipu_psys_kcmd_complete(struct ipu_psys_ppg *kppg, { struct ipu_psys_fh *fh = kcmd->fh; struct ipu_psys *psys = fh->psys; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; +#endif kcmd->ev.type = IPU_PSYS_EVENT_TYPE_CMD_COMPLETE; kcmd->ev.user_token = kcmd->user_token; @@ -461,7 +623,11 @@ void ipu_psys_kcmd_complete(struct ipu_psys_ppg *kppg, memcpy(kcmd->pg_user, kcmd->kpg->pg, kcmd->kpg->pg_size); else +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "Skipping unmapped buffer\n"); +#else + dev_dbg(dev, "Skipping unmapped buffer\n"); +#endif } kcmd->state = KCMD_STATE_PPG_COMPLETE; @@ -478,17 +644,26 @@ void ipu_psys_kcmd_complete(struct ipu_psys_ppg *kppg, */ int ipu_psys_kcmd_start(struct ipu_psys *psys, struct ipu_psys_kcmd *kcmd) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; +#endif int ret; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) if (psys->adev->isp->flr_done) return -EIO; +#endif if (early_pg_transfer && kcmd->pg_user && kcmd->kpg->pg) memcpy(kcmd->pg_user, kcmd->kpg->pg, kcmd->kpg->pg_size); ret = ipu_fw_psys_pg_start(kcmd); if (ret) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_err(&psys->adev->dev, "failed to start kcmd!\n"); +#else + dev_err(dev, "failed to start kcmd!\n"); +#endif return ret; } @@ -496,7 +671,11 @@ int ipu_psys_kcmd_start(struct ipu_psys *psys, struct ipu_psys_kcmd *kcmd) ret = ipu_fw_psys_pg_disown(kcmd); if (ret) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_err(&psys->adev->dev, "failed to start kcmd!\n"); +#else + dev_err(dev, "failed to start kcmd!\n"); +#endif return ret; } @@ -508,6 +687,9 @@ static int ipu_psys_kcmd_send_to_ppg_start(struct ipu_psys_kcmd *kcmd) struct ipu_psys_fh *fh = kcmd->fh; struct ipu_psys_scheduler *sched = &fh->sched; struct ipu_psys *psys = fh->psys; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; +#endif struct ipu_psys_ppg *kppg; struct ipu_psys_resource_pool *rpr; int queue_id; @@ -542,7 +724,11 @@ static int ipu_psys_kcmd_send_to_ppg_start(struct ipu_psys_kcmd *kcmd) queue_id = ipu_psys_allocate_cmd_queue_resource(rpr); if (queue_id == -ENOSPC) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_err(&psys->adev->dev, "no available queue\n"); +#else + dev_err(dev, "no available queue\n"); +#endif kfree(kppg->manifest); kfree(kppg); mutex_unlock(&psys->mutex); @@ -574,8 +760,12 @@ static int ipu_psys_kcmd_send_to_ppg_start(struct ipu_psys_kcmd *kcmd) list_add(&kcmd->list, &kppg->kcmds_new_list); mutex_unlock(&kppg->mutex); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "START ppg(%d, 0x%p) kcmd 0x%p, queue %d\n", +#else + dev_dbg(dev, "START ppg(%d, 0x%p) kcmd 0x%p, queue %d\n", +#endif ipu_fw_psys_pg_get_id(kcmd), kppg, kcmd, queue_id); /* Kick l-scheduler thread */ @@ -589,6 +779,9 @@ static int ipu_psys_kcmd_send_to_ppg(struct ipu_psys_kcmd *kcmd) { struct ipu_psys_fh *fh = kcmd->fh; struct ipu_psys *psys = fh->psys; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; +#endif struct ipu_psys_ppg *kppg; struct ipu_psys_resource_pool *rpr; unsigned long flags; @@ -604,13 +797,21 @@ static int ipu_psys_kcmd_send_to_ppg(struct ipu_psys_kcmd *kcmd) kcmd->kpg->pg_size = 0; spin_unlock_irqrestore(&psys->pgs_lock, flags); if (!kppg) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_err(&psys->adev->dev, "token not match\n"); +#else + dev_err(dev, "token not match\n"); +#endif return -EINVAL; } kcmd->kpg = kppg->kpg; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "%s ppg(%d, 0x%p) kcmd %p\n", +#else + dev_dbg(dev, "%s ppg(%d, 0x%p) kcmd %p\n", +#endif (kcmd->state == KCMD_STATE_PPG_STOP) ? "STOP" : "ENQUEUE", ipu_fw_psys_pg_get_id(kcmd), kppg, kcmd); @@ -618,12 +819,20 @@ static int ipu_psys_kcmd_send_to_ppg(struct ipu_psys_kcmd *kcmd) if (kcmd->state == KCMD_STATE_PPG_STOP) { mutex_lock(&kppg->mutex); if (kppg->state == PPG_STATE_STOPPED) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "kppg 0x%p stopped!\n", kppg); +#else + dev_dbg(dev, "kppg 0x%p stopped!\n", kppg); +#endif id = ipu_fw_psys_ppg_get_base_queue_id(kcmd); ipu_psys_free_cmd_queue_resource(rpr, id); ipu_psys_kcmd_complete(kppg, kcmd, 0); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) pm_runtime_put(&psys->adev->dev); +#else + pm_runtime_put(dev); +#endif resche = false; } else { list_add(&kcmd->list, &kppg->kcmds_new_list); @@ -652,12 +861,17 @@ static int ipu_psys_kcmd_send_to_ppg(struct ipu_psys_kcmd *kcmd) int ipu_psys_kcmd_new(struct ipu_psys_command *cmd, struct ipu_psys_fh *fh) { struct ipu_psys *psys = fh->psys; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; +#endif struct ipu_psys_kcmd *kcmd; size_t pg_size; int ret; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) if (psys->adev->isp->flr_done) return -EIO; +#endif kcmd = ipu_psys_copy_cmd(cmd, fh); if (!kcmd) @@ -665,15 +879,24 @@ int ipu_psys_kcmd_new(struct ipu_psys_command *cmd, struct ipu_psys_fh *fh) pg_size = ipu_fw_psys_pg_get_size(kcmd); if (pg_size > kcmd->kpg->pg_size) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "pg size mismatch %lu %lu\n", pg_size, kcmd->kpg->pg_size); +#else + dev_dbg(dev, "pg size mismatch %lu %lu\n", pg_size, + kcmd->kpg->pg_size); +#endif ret = -EINVAL; goto error; } if (ipu_fw_psys_pg_get_protocol(kcmd) != IPU_FW_PSYS_PROCESS_GROUP_PROTOCOL_PPG) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_err(&psys->adev->dev, "No support legacy pg now\n"); +#else + dev_err(dev, "No support legacy pg now\n"); +#endif ret = -EINVAL; goto error; } @@ -688,8 +911,12 @@ int ipu_psys_kcmd_new(struct ipu_psys_command *cmd, struct ipu_psys_fh *fh) if (ret) goto error; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "IOC_QCMD: user_token:%llx issue_id:0x%llx pri:%d\n", +#else + dev_dbg(dev, "IOC_QCMD: user_token:%llx issue_id:0x%llx pri:%d\n", +#endif cmd->user_token, cmd->issue_id, cmd->priority); return 0; @@ -736,6 +963,9 @@ static bool ipu_psys_kcmd_is_valid(struct ipu_psys *psys, void ipu_psys_handle_events(struct ipu_psys *psys) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; +#endif struct ipu_psys_kcmd *kcmd; struct ipu_fw_psys_event event; struct ipu_psys_ppg *kppg; @@ -752,8 +982,13 @@ void ipu_psys_handle_events(struct ipu_psys *psys) if (!event.context_handle) break; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "ppg event: 0x%x, %d, status %d\n", event.context_handle, event.command, event.status); +#else + dev_dbg(dev, "ppg event: 0x%x, %d, status %d\n", + event.context_handle, event.command, event.status); +#endif error = false; /* @@ -800,18 +1035,30 @@ void ipu_psys_handle_events(struct ipu_psys *psys) mutex_unlock(&kppg->mutex); } } else { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_err(&psys->adev->dev, "invalid event\n"); +#else + dev_err(dev, "invalid event\n"); +#endif continue; } if (error || !kppg) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_err(&psys->adev->dev, "event error, command %d\n", cmd); +#else + dev_err(dev, "event error, command %d\n", cmd); +#endif break; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "event to kppg 0x%p, kcmd 0x%p\n", kppg, kcmd); +#else + dev_dbg(dev, "event to kppg 0x%p, kcmd 0x%p\n", kppg, kcmd); +#endif ipu_psys_ppg_complete(psys, kppg); @@ -829,6 +1076,9 @@ void ipu_psys_handle_events(struct ipu_psys *psys) int ipu_psys_fh_init(struct ipu_psys_fh *fh) { struct ipu_psys *psys = fh->psys; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; +#endif struct ipu_psys_buffer_set *kbuf_set, *kbuf_set_tmp; struct ipu_psys_scheduler *sched = &fh->sched; int i; @@ -842,11 +1092,18 @@ int ipu_psys_fh_init(struct ipu_psys_fh *fh) kbuf_set = kzalloc(sizeof(*kbuf_set), GFP_KERNEL); if (!kbuf_set) goto out_free_buf_sets; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) kbuf_set->kaddr = dma_alloc_attrs(&psys->adev->dev, IPU_PSYS_BUF_SET_MAX_SIZE, &kbuf_set->dma_addr, GFP_KERNEL, 0); +#else + kbuf_set->kaddr = dma_alloc_attrs(dev, + IPU_PSYS_BUF_SET_MAX_SIZE, + &kbuf_set->dma_addr, + GFP_KERNEL, 0); +#endif if (!kbuf_set->kaddr) { kfree(kbuf_set); goto out_free_buf_sets; @@ -860,8 +1117,12 @@ int ipu_psys_fh_init(struct ipu_psys_fh *fh) out_free_buf_sets: list_for_each_entry_safe(kbuf_set, kbuf_set_tmp, &sched->buf_sets, list) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dma_free_attrs(&psys->adev->dev, kbuf_set->size, kbuf_set->kaddr, +#else + dma_free_attrs(dev, kbuf_set->size, kbuf_set->kaddr, +#endif kbuf_set->dma_addr, 0); list_del(&kbuf_set->list); kfree(kbuf_set); @@ -874,6 +1135,9 @@ int ipu_psys_fh_init(struct ipu_psys_fh *fh) int ipu_psys_fh_deinit(struct ipu_psys_fh *fh) { struct ipu_psys *psys = fh->psys; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; +#endif struct ipu_psys_ppg *kppg, *kppg0; struct ipu_psys_kcmd *kcmd, *kcmd0; struct ipu_psys_buffer_set *kbuf_set, *kbuf_set0; @@ -901,12 +1165,20 @@ int ipu_psys_fh_deinit(struct ipu_psys_fh *fh) ipu_psys_ppg_stop(kppg); ipu_psys_free_resources(alloc, rpr); ipu_psys_free_cmd_queue_resource(rpr, id); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, +#else + dev_dbg(dev, +#endif "s_change:%s %p %d -> %d\n", __func__, kppg, kppg->state, PPG_STATE_STOPPED); kppg->state = PPG_STATE_STOPPED; if (psys->power_gating != PSYS_POWER_GATED) +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) pm_runtime_put(&psys->adev->dev); +#else + pm_runtime_put(dev); +#endif } list_del(&kppg->list); mutex_unlock(&kppg->mutex); @@ -950,8 +1222,12 @@ int ipu_psys_fh_deinit(struct ipu_psys_fh *fh) mutex_lock(&sched->bs_mutex); list_for_each_entry_safe(kbuf_set, kbuf_set0, &sched->buf_sets, list) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dma_free_attrs(&psys->adev->dev, kbuf_set->size, kbuf_set->kaddr, +#else + dma_free_attrs(dev, kbuf_set->size, kbuf_set->kaddr, +#endif kbuf_set->dma_addr, 0); list_del(&kbuf_set->list); kfree(kbuf_set); @@ -965,6 +1241,9 @@ int ipu_psys_fh_deinit(struct ipu_psys_fh *fh) struct ipu_psys_kcmd *ipu_get_completed_kcmd(struct ipu_psys_fh *fh) { struct ipu_psys_scheduler *sched = &fh->sched; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &fh->psys->adev->auxdev.dev; +#endif struct ipu_psys_kcmd *kcmd; struct ipu_psys_ppg *kppg; @@ -985,8 +1264,12 @@ struct ipu_psys_kcmd *ipu_get_completed_kcmd(struct ipu_psys_fh *fh) struct ipu_psys_kcmd, list); mutex_unlock(&fh->mutex); mutex_unlock(&kppg->mutex); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&fh->psys->adev->dev, "get completed kcmd 0x%p\n", kcmd); +#else + dev_dbg(dev, "get completed kcmd 0x%p\n", kcmd); +#endif return kcmd; } mutex_unlock(&fh->mutex); @@ -998,10 +1281,17 @@ long ipu_ioctl_dqevent(struct ipu_psys_event *event, struct ipu_psys_fh *fh, unsigned int f_flags) { struct ipu_psys *psys = fh->psys; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0) + struct device *dev = &psys->adev->auxdev.dev; +#endif struct ipu_psys_kcmd *kcmd = NULL; int rval; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) dev_dbg(&psys->adev->dev, "IOC_DQEVENT\n"); +#else + dev_dbg(dev, "IOC_DQEVENT\n"); +#endif if (!(f_flags & O_NONBLOCK)) { rval = wait_event_interruptible(fh->wait, diff --git a/drivers/media/pci/intel/ipu6/ipu6ep-fw-resources.c b/drivers/media/pci/intel/ipu6/psys/ipu6ep-fw-resources.c similarity index 100% rename from drivers/media/pci/intel/ipu6/ipu6ep-fw-resources.c rename to drivers/media/pci/intel/ipu6/psys/ipu6ep-fw-resources.c diff --git a/drivers/media/pci/intel/ipu6/ipu6ep-platform-resources.h b/drivers/media/pci/intel/ipu6/psys/ipu6ep-platform-resources.h similarity index 100% rename from drivers/media/pci/intel/ipu6/ipu6ep-platform-resources.h rename to drivers/media/pci/intel/ipu6/psys/ipu6ep-platform-resources.h diff --git a/drivers/media/pci/intel/ipu6/ipu6se-fw-resources.c b/drivers/media/pci/intel/ipu6/psys/ipu6se-fw-resources.c similarity index 90% rename from drivers/media/pci/intel/ipu6/ipu6se-fw-resources.c rename to drivers/media/pci/intel/ipu6/psys/ipu6se-fw-resources.c index 806ef7058930..19cb7107f231 100644 --- a/drivers/media/pci/intel/ipu6/ipu6se-fw-resources.c +++ b/drivers/media/pci/intel/ipu6/psys/ipu6se-fw-resources.c @@ -18,7 +18,11 @@ /* * Cell types by cell IDs */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) const u8 ipu6se_fw_psys_cell_types[IPU6SE_FW_PSYS_N_CELL_ID] = { +#else +static const u8 ipu6se_fw_psys_cell_types[IPU6SE_FW_PSYS_N_CELL_ID] = { +#endif IPU6SE_FW_PSYS_SP_CTRL_TYPE_ID, IPU6SE_FW_PSYS_ACC_ISA_TYPE_ID, /* IPU6SE_FW_PSYS_ISA_ICA_ID */ IPU6SE_FW_PSYS_ACC_ISA_TYPE_ID, /* IPU6SE_FW_PSYS_ISA_LSC_ID */ @@ -35,26 +39,42 @@ const u8 ipu6se_fw_psys_cell_types[IPU6SE_FW_PSYS_N_CELL_ID] = { IPU6SE_FW_PSYS_ACC_ISA_TYPE_ID /* PAF */ }; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) const u16 ipu6se_fw_num_dev_channels[IPU6SE_FW_PSYS_N_DEV_CHN_ID] = { +#else +static const u16 ipu6se_fw_num_dev_channels[IPU6SE_FW_PSYS_N_DEV_CHN_ID] = { +#endif IPU6SE_FW_PSYS_DEV_CHN_DMA_EXT0_MAX_SIZE, IPU6SE_FW_PSYS_DEV_CHN_DMA_EXT1_READ_MAX_SIZE, IPU6SE_FW_PSYS_DEV_CHN_DMA_EXT1_WRITE_MAX_SIZE, IPU6SE_FW_PSYS_DEV_CHN_DMA_ISA_MAX_SIZE, }; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) const u16 ipu6se_fw_psys_mem_size[IPU6SE_FW_PSYS_N_MEM_ID] = { +#else +static const u16 ipu6se_fw_psys_mem_size[IPU6SE_FW_PSYS_N_MEM_ID] = { +#endif IPU6SE_FW_PSYS_TRANSFER_VMEM0_MAX_SIZE, IPU6SE_FW_PSYS_LB_VMEM_MAX_SIZE, IPU6SE_FW_PSYS_DMEM0_MAX_SIZE, IPU6SE_FW_PSYS_DMEM1_MAX_SIZE }; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) const u16 ipu6se_fw_psys_dfms[IPU6SE_FW_PSYS_N_DEV_DFM_ID] = { +#else +static const u16 ipu6se_fw_psys_dfms[IPU6SE_FW_PSYS_N_DEV_DFM_ID] = { +#endif IPU6SE_FW_PSYS_DEV_DFM_ISL_FULL_PORT_ID_MAX_SIZE, IPU6SE_FW_PSYS_DEV_DFM_ISL_EMPTY_PORT_ID_MAX_SIZE }; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) const u8 +#else +static const u8 +#endif ipu6se_fw_psys_c_mem[IPU6SE_FW_PSYS_N_CELL_ID][IPU6SE_FW_PSYS_N_MEM_TYPE_ID] = { { /* IPU6SE_FW_PSYS_SP0_ID */ IPU6SE_FW_PSYS_N_MEM_ID, diff --git a/drivers/media/pci/intel/ipu6/ipu6se-platform-resources.h b/drivers/media/pci/intel/ipu6/psys/ipu6se-platform-resources.h similarity index 100% rename from drivers/media/pci/intel/ipu6/ipu6se-platform-resources.h rename to drivers/media/pci/intel/ipu6/psys/ipu6se-platform-resources.h diff --git a/patch/v6.10/0002-use-module-parameter-to-set-isys-psys-freq.patch b/patch/v6.10/0002-use-module-parameter-to-set-isys-psys-freq.patch new file mode 100644 index 000000000000..f39be8a330a0 --- /dev/null +++ b/patch/v6.10/0002-use-module-parameter-to-set-isys-psys-freq.patch @@ -0,0 +1,64 @@ +From c1eb35f7316fc54b67442dfe6880f57f93728a3c Mon Sep 17 00:00:00 2001 +From: Dongcheng Yan +Date: Tue, 30 Jul 2024 11:03:10 +0800 +Subject: [PATCH 2/3] use module parameter to set isys/psys freq + +Signed-off-by: Hongju Wang +Signed-off-by: Dongcheng Yan +--- + drivers/media/pci/intel/ipu6/ipu6.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c +index bbd646378ab3..5a683dbdf03a 100644 +--- a/drivers/media/pci/intel/ipu6/ipu6.c ++++ b/drivers/media/pci/intel/ipu6/ipu6.c +@@ -33,6 +33,14 @@ + #include "ipu6-platform-isys-csi2-reg.h" + #include "ipu6-platform-regs.h" + ++static unsigned int isys_freq_override; ++module_param(isys_freq_override, uint, 0660); ++MODULE_PARM_DESC(isys_freq_override, "Override ISYS freq(mhz)"); ++ ++static unsigned int psys_freq_override; ++module_param(psys_freq_override, uint, 0660); ++MODULE_PARM_DESC(psys_freq_override, "Override PSYS freq(mhz)"); ++ + #define IPU6_PCI_BAR 0 + + struct ipu6_cell_program { +@@ -387,6 +395,14 @@ ipu6_isys_init(struct pci_dev *pdev, struct device *parent, + pdata->base = base; + pdata->ipdata = ipdata; + ++ /* Override the isys freq */ ++ if (isys_freq_override >= BUTTRESS_MIN_FORCE_IS_FREQ && ++ isys_freq_override <= BUTTRESS_MAX_FORCE_IS_FREQ) { ++ ctrl->ratio = isys_freq_override / BUTTRESS_IS_FREQ_STEP; ++ dev_dbg(&pdev->dev, "Override the isys freq:%u(mhz)\n", ++ isys_freq_override); ++ } ++ + isys_adev = ipu6_bus_initialize_device(pdev, parent, pdata, ctrl, + IPU6_ISYS_NAME); + if (IS_ERR(isys_adev)) { +@@ -433,6 +449,15 @@ ipu6_psys_init(struct pci_dev *pdev, struct device *parent, + pdata->base = base; + pdata->ipdata = ipdata; + ++ /* Override the psys freq */ ++ if (psys_freq_override >= BUTTRESS_MIN_FORCE_PS_FREQ && ++ psys_freq_override <= BUTTRESS_MAX_FORCE_PS_FREQ) { ++ ctrl->ratio = psys_freq_override / BUTTRESS_PS_FREQ_STEP; ++ ctrl->qos_floor = psys_freq_override; ++ dev_dbg(&pdev->dev, "Override the psys freq:%u(mhz)\n", ++ psys_freq_override); ++ } ++ + psys_adev = ipu6_bus_initialize_device(pdev, parent, pdata, ctrl, + IPU6_PSYS_NAME); + if (IS_ERR(psys_adev)) { +-- +2.43.0 + diff --git a/patch/v6.10/0003-media-ipu6-Don-t-disable-ATS-when-CPU-is-not-Metero-.patch b/patch/v6.10/0003-media-ipu6-Don-t-disable-ATS-when-CPU-is-not-Metero-.patch new file mode 100644 index 000000000000..45583000ab10 --- /dev/null +++ b/patch/v6.10/0003-media-ipu6-Don-t-disable-ATS-when-CPU-is-not-Metero-.patch @@ -0,0 +1,39 @@ +From c2bad048dcd547c41edb1858259fb672c0db98d4 Mon Sep 17 00:00:00 2001 +From: Hao Yao +Date: Wed, 18 Sep 2024 14:47:40 +0800 +Subject: [PATCH 3/3] media: ipu6: Don't disable ATS when CPU is not Metero + Lake + +Signed-off-by: Hao Yao +--- + drivers/media/pci/intel/ipu6/ipu6.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c +index 5a683dbdf03a..00ae55816f9d 100644 +--- a/drivers/media/pci/intel/ipu6/ipu6.c ++++ b/drivers/media/pci/intel/ipu6/ipu6.c +@@ -3,6 +3,8 @@ + * Copyright (C) 2013--2024 Intel Corporation + */ + ++#include ++ + #include + #include + #include +@@ -493,8 +495,9 @@ static int ipu6_pci_config_setup(struct pci_dev *dev, u8 hw_ver) + int ret; + + /* disable IPU6 PCI ATS on mtl ES2 */ +- if (is_ipu6ep_mtl(hw_ver) && boot_cpu_data.x86_stepping == 0x2 && +- pci_ats_supported(dev)) ++ if ((boot_cpu_data.x86_vfm == INTEL_METEORLAKE || ++ boot_cpu_data.x86_vfm == INTEL_METEORLAKE_L) && ++ boot_cpu_data.x86_stepping == 0x2 && pci_ats_supported(dev)) + pci_disable_ats(dev); + + /* No PCI msi capability for IPU6EP */ +-- +2.43.0 + diff --git a/patch/v6.10/in-tree-build/0001-workaround-patch-to-build-psys.patch b/patch/v6.10/in-tree-build/0001-workaround-patch-to-build-psys.patch new file mode 100644 index 000000000000..24281b2785c9 --- /dev/null +++ b/patch/v6.10/in-tree-build/0001-workaround-patch-to-build-psys.patch @@ -0,0 +1,22 @@ +From 77c296a250c8741de81f5799bfcdd62a465cce65 Mon Sep 17 00:00:00 2001 +From: Dongcheng Yan +Date: Fri, 13 Sep 2024 18:02:37 +0800 +Subject: [PATCH 1/3] workaround patch to build psys + +Signed-off-by: Dongcheng Yan +--- + drivers/media/pci/intel/ipu6/Makefile | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/media/pci/intel/ipu6/Makefile b/drivers/media/pci/intel/ipu6/Makefile +index a821b0a1567f..8a4f4cd7610d 100644 +--- a/drivers/media/pci/intel/ipu6/Makefile ++++ b/drivers/media/pci/intel/ipu6/Makefile +@@ -21,3 +21,4 @@ intel-ipu6-isys-y := ipu6-isys.o \ + ipu6-isys-dwc-phy.o + + obj-$(CONFIG_VIDEO_INTEL_IPU6) += intel-ipu6-isys.o ++obj-$(CONFIG_VIDEO_INTEL_IPU6) += psys/ +-- +2.43.0 + diff --git a/patches/0001-v6.10-IPU6-headers-used-by-PSYS.patch b/patches/0001-v6.10-IPU6-headers-used-by-PSYS.patch new file mode 100644 index 000000000000..00fb961d2717 --- /dev/null +++ b/patches/0001-v6.10-IPU6-headers-used-by-PSYS.patch @@ -0,0 +1,1198 @@ +From cec333719e0f91769395e20ddc166b971327c97c Mon Sep 17 00:00:00 2001 +From: Hao Yao +Date: Sun, 29 Sep 2024 15:34:50 +0800 +Subject: [PATCH] v6.10 IPU6 headers used by PSYS + +Signed-off-by: Hao Yao +--- + drivers/media/pci/intel/ipu6/ipu6-bus.h | 58 +++ + drivers/media/pci/intel/ipu6/ipu6-buttress.h | 92 +++++ + drivers/media/pci/intel/ipu6/ipu6-cpd.h | 105 ++++++ + drivers/media/pci/intel/ipu6/ipu6-fw-com.h | 47 +++ + drivers/media/pci/intel/ipu6/ipu6-mmu.h | 73 ++++ + .../intel/ipu6/ipu6-platform-buttress-regs.h | 226 ++++++++++++ + .../media/pci/intel/ipu6/ipu6-platform-regs.h | 179 +++++++++ + drivers/media/pci/intel/ipu6/ipu6.h | 342 ++++++++++++++++++ + 8 files changed, 1122 insertions(+) + create mode 100644 drivers/media/pci/intel/ipu6/ipu6-bus.h + create mode 100644 drivers/media/pci/intel/ipu6/ipu6-buttress.h + create mode 100644 drivers/media/pci/intel/ipu6/ipu6-cpd.h + create mode 100644 drivers/media/pci/intel/ipu6/ipu6-fw-com.h + create mode 100644 drivers/media/pci/intel/ipu6/ipu6-mmu.h + create mode 100644 drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h + create mode 100644 drivers/media/pci/intel/ipu6/ipu6-platform-regs.h + create mode 100644 drivers/media/pci/intel/ipu6/ipu6.h + +diff --git a/drivers/media/pci/intel/ipu6/ipu6-bus.h b/drivers/media/pci/intel/ipu6/ipu6-bus.h +new file mode 100644 +index 000000000..b26c6aee1 +--- /dev/null ++++ b/drivers/media/pci/intel/ipu6/ipu6-bus.h +@@ -0,0 +1,58 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* Copyright (C) 2013 - 2024 Intel Corporation */ ++ ++#ifndef IPU6_BUS_H ++#define IPU6_BUS_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct firmware; ++struct pci_dev; ++ ++#define IPU6_BUS_NAME IPU6_NAME "-bus" ++ ++struct ipu6_buttress_ctrl; ++ ++struct ipu6_bus_device { ++ struct auxiliary_device auxdev; ++ struct auxiliary_driver *auxdrv; ++ const struct ipu6_auxdrv_data *auxdrv_data; ++ struct list_head list; ++ void *pdata; ++ struct ipu6_mmu *mmu; ++ struct ipu6_device *isp; ++ struct ipu6_buttress_ctrl *ctrl; ++ u64 dma_mask; ++ const struct firmware *fw; ++ struct sg_table fw_sgt; ++ u64 *pkg_dir; ++ dma_addr_t pkg_dir_dma_addr; ++ unsigned int pkg_dir_size; ++}; ++ ++struct ipu6_auxdrv_data { ++ irqreturn_t (*isr)(struct ipu6_bus_device *adev); ++ irqreturn_t (*isr_threaded)(struct ipu6_bus_device *adev); ++ bool wake_isr_thread; ++}; ++ ++#define to_ipu6_bus_device(_dev) \ ++ container_of(to_auxiliary_dev(_dev), struct ipu6_bus_device, auxdev) ++#define auxdev_to_adev(_auxdev) \ ++ container_of(_auxdev, struct ipu6_bus_device, auxdev) ++#define ipu6_bus_get_drvdata(adev) dev_get_drvdata(&(adev)->auxdev.dev) ++ ++struct ipu6_bus_device * ++ipu6_bus_initialize_device(struct pci_dev *pdev, struct device *parent, ++ void *pdata, struct ipu6_buttress_ctrl *ctrl, ++ char *name); ++int ipu6_bus_add_device(struct ipu6_bus_device *adev); ++void ipu6_bus_del_devices(struct pci_dev *pdev); ++ ++#endif +diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.h b/drivers/media/pci/intel/ipu6/ipu6-buttress.h +new file mode 100644 +index 000000000..9b6f56958 +--- /dev/null ++++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.h +@@ -0,0 +1,92 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* Copyright (C) 2013--2024 Intel Corporation */ ++ ++#ifndef IPU6_BUTTRESS_H ++#define IPU6_BUTTRESS_H ++ ++#include ++#include ++#include ++#include ++ ++struct device; ++struct firmware; ++struct ipu6_device; ++struct ipu6_bus_device; ++ ++#define BUTTRESS_PS_FREQ_STEP 25U ++#define BUTTRESS_MIN_FORCE_PS_FREQ (BUTTRESS_PS_FREQ_STEP * 8) ++#define BUTTRESS_MAX_FORCE_PS_FREQ (BUTTRESS_PS_FREQ_STEP * 32) ++ ++#define BUTTRESS_IS_FREQ_STEP 25U ++#define BUTTRESS_MIN_FORCE_IS_FREQ (BUTTRESS_IS_FREQ_STEP * 8) ++#define BUTTRESS_MAX_FORCE_IS_FREQ (BUTTRESS_IS_FREQ_STEP * 22) ++ ++struct ipu6_buttress_ctrl { ++ u32 freq_ctl, pwr_sts_shift, pwr_sts_mask, pwr_sts_on, pwr_sts_off; ++ unsigned int ratio; ++ unsigned int qos_floor; ++ bool started; ++}; ++ ++struct ipu6_buttress_ipc { ++ struct completion send_complete; ++ struct completion recv_complete; ++ u32 nack; ++ u32 nack_mask; ++ u32 recv_data; ++ u32 csr_out; ++ u32 csr_in; ++ u32 db0_in; ++ u32 db0_out; ++ u32 data0_out; ++ u32 data0_in; ++}; ++ ++struct ipu6_buttress { ++ struct mutex power_mutex, auth_mutex, cons_mutex, ipc_mutex; ++ struct ipu6_buttress_ipc cse; ++ struct ipu6_buttress_ipc ish; ++ struct list_head constraints; ++ u32 wdt_cached_value; ++ bool force_suspend; ++ u32 ref_clk; ++}; ++ ++enum ipu6_buttress_ipc_domain { ++ IPU6_BUTTRESS_IPC_CSE, ++ IPU6_BUTTRESS_IPC_ISH, ++}; ++ ++struct ipu6_ipc_buttress_bulk_msg { ++ u32 cmd; ++ u32 expected_resp; ++ bool require_resp; ++ u8 cmd_size; ++}; ++ ++int ipu6_buttress_ipc_reset(struct ipu6_device *isp, ++ struct ipu6_buttress_ipc *ipc); ++int ipu6_buttress_map_fw_image(struct ipu6_bus_device *sys, ++ const struct firmware *fw, ++ struct sg_table *sgt); ++void ipu6_buttress_unmap_fw_image(struct ipu6_bus_device *sys, ++ struct sg_table *sgt); ++int ipu6_buttress_power(struct device *dev, struct ipu6_buttress_ctrl *ctrl, ++ bool on); ++bool ipu6_buttress_get_secure_mode(struct ipu6_device *isp); ++int ipu6_buttress_authenticate(struct ipu6_device *isp); ++int ipu6_buttress_reset_authentication(struct ipu6_device *isp); ++bool ipu6_buttress_auth_done(struct ipu6_device *isp); ++int ipu6_buttress_start_tsc_sync(struct ipu6_device *isp); ++void ipu6_buttress_tsc_read(struct ipu6_device *isp, u64 *val); ++u64 ipu6_buttress_tsc_ticks_to_ns(u64 ticks, const struct ipu6_device *isp); ++ ++irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr); ++irqreturn_t ipu6_buttress_isr_threaded(int irq, void *isp_ptr); ++int ipu6_buttress_init(struct ipu6_device *isp); ++void ipu6_buttress_exit(struct ipu6_device *isp); ++void ipu6_buttress_csi_port_config(struct ipu6_device *isp, ++ u32 legacy, u32 combo); ++void ipu6_buttress_restore(struct ipu6_device *isp); ++#endif /* IPU6_BUTTRESS_H */ +diff --git a/drivers/media/pci/intel/ipu6/ipu6-cpd.h b/drivers/media/pci/intel/ipu6/ipu6-cpd.h +new file mode 100644 +index 000000000..e0e4fdeca +--- /dev/null ++++ b/drivers/media/pci/intel/ipu6/ipu6-cpd.h +@@ -0,0 +1,105 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* Copyright (C) 2015--2024 Intel Corporation */ ++ ++#ifndef IPU6_CPD_H ++#define IPU6_CPD_H ++ ++struct ipu6_device; ++struct ipu6_bus_device; ++ ++#define IPU6_CPD_SIZE_OF_FW_ARCH_VERSION 7 ++#define IPU6_CPD_SIZE_OF_SYSTEM_VERSION 11 ++#define IPU6_CPD_SIZE_OF_COMPONENT_NAME 12 ++ ++#define IPU6_CPD_METADATA_EXTN_TYPE_IUNIT 0x10 ++ ++#define IPU6_CPD_METADATA_IMAGE_TYPE_RESERVED 0 ++#define IPU6_CPD_METADATA_IMAGE_TYPE_BOOTLOADER 1 ++#define IPU6_CPD_METADATA_IMAGE_TYPE_MAIN_FIRMWARE 2 ++ ++#define IPU6_CPD_PKG_DIR_PSYS_SERVER_IDX 0 ++#define IPU6_CPD_PKG_DIR_ISYS_SERVER_IDX 1 ++ ++#define IPU6_CPD_PKG_DIR_CLIENT_PG_TYPE 3 ++ ++#define IPU6_CPD_METADATA_HASH_KEY_SIZE 48 ++#define IPU6SE_CPD_METADATA_HASH_KEY_SIZE 32 ++ ++struct ipu6_cpd_module_data_hdr { ++ u32 hdr_len; ++ u32 endian; ++ u32 fw_pkg_date; ++ u32 hive_sdk_date; ++ u32 compiler_date; ++ u32 target_platform_type; ++ u8 sys_ver[IPU6_CPD_SIZE_OF_SYSTEM_VERSION]; ++ u8 fw_arch_ver[IPU6_CPD_SIZE_OF_FW_ARCH_VERSION]; ++ u8 rsvd[2]; ++} __packed; ++ ++/* ++ * ipu6_cpd_hdr structure updated as the chksum and ++ * sub_partition_name is unused on host side ++ * CSE layout version 1.6 for IPU6SE (hdr_len = 0x10) ++ * CSE layout version 1.7 for IPU6 (hdr_len = 0x14) ++ */ ++struct ipu6_cpd_hdr { ++ u32 hdr_mark; ++ u32 ent_cnt; ++ u8 hdr_ver; ++ u8 ent_ver; ++ u8 hdr_len; ++} __packed; ++ ++struct ipu6_cpd_ent { ++ u8 name[IPU6_CPD_SIZE_OF_COMPONENT_NAME]; ++ u32 offset; ++ u32 len; ++ u8 rsvd[4]; ++} __packed; ++ ++struct ipu6_cpd_metadata_cmpnt_hdr { ++ u32 id; ++ u32 size; ++ u32 ver; ++} __packed; ++ ++struct ipu6_cpd_metadata_cmpnt { ++ struct ipu6_cpd_metadata_cmpnt_hdr hdr; ++ u8 sha2_hash[IPU6_CPD_METADATA_HASH_KEY_SIZE]; ++ u32 entry_point; ++ u32 icache_base_offs; ++ u8 attrs[16]; ++} __packed; ++ ++struct ipu6se_cpd_metadata_cmpnt { ++ struct ipu6_cpd_metadata_cmpnt_hdr hdr; ++ u8 sha2_hash[IPU6SE_CPD_METADATA_HASH_KEY_SIZE]; ++ u32 entry_point; ++ u32 icache_base_offs; ++ u8 attrs[16]; ++} __packed; ++ ++struct ipu6_cpd_metadata_extn { ++ u32 extn_type; ++ u32 len; ++ u32 img_type; ++ u8 rsvd[16]; ++} __packed; ++ ++struct ipu6_cpd_client_pkg_hdr { ++ u32 prog_list_offs; ++ u32 prog_list_size; ++ u32 prog_desc_offs; ++ u32 prog_desc_size; ++ u32 pg_manifest_offs; ++ u32 pg_manifest_size; ++ u32 prog_bin_offs; ++ u32 prog_bin_size; ++} __packed; ++ ++int ipu6_cpd_create_pkg_dir(struct ipu6_bus_device *adev, const void *src); ++void ipu6_cpd_free_pkg_dir(struct ipu6_bus_device *adev); ++int ipu6_cpd_validate_cpd_file(struct ipu6_device *isp, const void *cpd_file, ++ unsigned long cpd_file_size); ++#endif /* IPU6_CPD_H */ +diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-com.h b/drivers/media/pci/intel/ipu6/ipu6-fw-com.h +new file mode 100644 +index 000000000..b02285a3e +--- /dev/null ++++ b/drivers/media/pci/intel/ipu6/ipu6-fw-com.h +@@ -0,0 +1,47 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* Copyright (C) 2013--2024 Intel Corporation */ ++ ++#ifndef IPU6_FW_COM_H ++#define IPU6_FW_COM_H ++ ++struct ipu6_fw_com_context; ++struct ipu6_bus_device; ++ ++struct ipu6_fw_syscom_queue_config { ++ unsigned int queue_size; /* tokens per queue */ ++ unsigned int token_size; /* bytes per token */ ++}; ++ ++#define SYSCOM_BUTTRESS_FW_PARAMS_ISYS_OFFSET 0 ++ ++struct ipu6_fw_com_cfg { ++ unsigned int num_input_queues; ++ unsigned int num_output_queues; ++ struct ipu6_fw_syscom_queue_config *input; ++ struct ipu6_fw_syscom_queue_config *output; ++ ++ unsigned int dmem_addr; ++ ++ /* firmware-specific configuration data */ ++ void *specific_addr; ++ unsigned int specific_size; ++ int (*cell_ready)(struct ipu6_bus_device *adev); ++ void (*cell_start)(struct ipu6_bus_device *adev); ++ ++ unsigned int buttress_boot_offset; ++}; ++ ++void *ipu6_fw_com_prepare(struct ipu6_fw_com_cfg *cfg, ++ struct ipu6_bus_device *adev, void __iomem *base); ++ ++int ipu6_fw_com_open(struct ipu6_fw_com_context *ctx); ++bool ipu6_fw_com_ready(struct ipu6_fw_com_context *ctx); ++int ipu6_fw_com_close(struct ipu6_fw_com_context *ctx); ++int ipu6_fw_com_release(struct ipu6_fw_com_context *ctx, unsigned int force); ++ ++void *ipu6_recv_get_token(struct ipu6_fw_com_context *ctx, int q_nbr); ++void ipu6_recv_put_token(struct ipu6_fw_com_context *ctx, int q_nbr); ++void *ipu6_send_get_token(struct ipu6_fw_com_context *ctx, int q_nbr); ++void ipu6_send_put_token(struct ipu6_fw_com_context *ctx, int q_nbr); ++ ++#endif +diff --git a/drivers/media/pci/intel/ipu6/ipu6-mmu.h b/drivers/media/pci/intel/ipu6/ipu6-mmu.h +new file mode 100644 +index 000000000..21cdb0f14 +--- /dev/null ++++ b/drivers/media/pci/intel/ipu6/ipu6-mmu.h +@@ -0,0 +1,73 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* Copyright (C) 2013--2024 Intel Corporation */ ++ ++#ifndef IPU6_MMU_H ++#define IPU6_MMU_H ++ ++#define ISYS_MMID 1 ++#define PSYS_MMID 0 ++ ++#include ++#include ++#include ++ ++struct device; ++struct page; ++struct ipu6_hw_variants; ++ ++struct ipu6_mmu_info { ++ struct device *dev; ++ ++ u32 *l1_pt; ++ u32 l1_pt_dma; ++ u32 **l2_pts; ++ ++ u32 *dummy_l2_pt; ++ u32 dummy_l2_pteval; ++ void *dummy_page; ++ u32 dummy_page_pteval; ++ ++ dma_addr_t aperture_start; ++ dma_addr_t aperture_end; ++ unsigned long pgsize_bitmap; ++ ++ spinlock_t lock; /* Serialize access to users */ ++ struct ipu6_dma_mapping *dmap; ++}; ++ ++struct ipu6_mmu { ++ struct list_head node; ++ ++ struct ipu6_mmu_hw *mmu_hw; ++ unsigned int nr_mmus; ++ unsigned int mmid; ++ ++ phys_addr_t pgtbl; ++ struct device *dev; ++ ++ struct ipu6_dma_mapping *dmap; ++ struct list_head vma_list; ++ ++ struct page *trash_page; ++ dma_addr_t pci_trash_page; /* IOVA from PCI DMA services (parent) */ ++ dma_addr_t iova_trash_page; /* IOVA for IPU6 child nodes to use */ ++ ++ bool ready; ++ spinlock_t ready_lock; /* Serialize access to bool ready */ ++ ++ void (*tlb_invalidate)(struct ipu6_mmu *mmu); ++}; ++ ++struct ipu6_mmu *ipu6_mmu_init(struct device *dev, ++ void __iomem *base, int mmid, ++ const struct ipu6_hw_variants *hw); ++void ipu6_mmu_cleanup(struct ipu6_mmu *mmu); ++int ipu6_mmu_hw_init(struct ipu6_mmu *mmu); ++void ipu6_mmu_hw_cleanup(struct ipu6_mmu *mmu); ++int ipu6_mmu_map(struct ipu6_mmu_info *mmu_info, unsigned long iova, ++ phys_addr_t paddr, size_t size); ++size_t ipu6_mmu_unmap(struct ipu6_mmu_info *mmu_info, unsigned long iova, ++ size_t size); ++phys_addr_t ipu6_mmu_iova_to_phys(struct ipu6_mmu_info *mmu_info, ++ dma_addr_t iova); ++#endif +diff --git a/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h b/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h +new file mode 100644 +index 000000000..20f27011d +--- /dev/null ++++ b/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h +@@ -0,0 +1,226 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* Copyright (C) 2023--2024 Intel Corporation */ ++ ++#ifndef IPU6_PLATFORM_BUTTRESS_REGS_H ++#define IPU6_PLATFORM_BUTTRESS_REGS_H ++ ++#include ++ ++/* IS_WORKPOINT_REQ */ ++#define IPU6_BUTTRESS_REG_IS_FREQ_CTL 0x34 ++/* PS_WORKPOINT_REQ */ ++#define IPU6_BUTTRESS_REG_PS_FREQ_CTL 0x38 ++ ++/* should be tuned for real silicon */ ++#define IPU6_IS_FREQ_CTL_DEFAULT_RATIO 0x08 ++#define IPU6SE_IS_FREQ_CTL_DEFAULT_RATIO 0x0a ++#define IPU6_PS_FREQ_CTL_DEFAULT_RATIO 0x0d ++ ++#define IPU6_IS_FREQ_CTL_DEFAULT_QOS_FLOOR_RATIO 0x10 ++#define IPU6_PS_FREQ_CTL_DEFAULT_QOS_FLOOR_RATIO 0x0708 ++ ++#define IPU6_BUTTRESS_PWR_STATE_IS_PWR_SHIFT 3 ++#define IPU6_BUTTRESS_PWR_STATE_IS_PWR_MASK GENMASK(4, 3) ++ ++#define IPU6_BUTTRESS_PWR_STATE_PS_PWR_SHIFT 6 ++#define IPU6_BUTTRESS_PWR_STATE_PS_PWR_MASK GENMASK(7, 6) ++ ++#define IPU6_BUTTRESS_PWR_STATE_DN_DONE 0x0 ++#define IPU6_BUTTRESS_PWR_STATE_UP_PROCESS 0x1 ++#define IPU6_BUTTRESS_PWR_STATE_DN_PROCESS 0x2 ++#define IPU6_BUTTRESS_PWR_STATE_UP_DONE 0x3 ++ ++#define IPU6_BUTTRESS_REG_FPGA_SUPPORT_0 0x270 ++#define IPU6_BUTTRESS_REG_FPGA_SUPPORT_1 0x274 ++#define IPU6_BUTTRESS_REG_FPGA_SUPPORT_2 0x278 ++#define IPU6_BUTTRESS_REG_FPGA_SUPPORT_3 0x27c ++#define IPU6_BUTTRESS_REG_FPGA_SUPPORT_4 0x280 ++#define IPU6_BUTTRESS_REG_FPGA_SUPPORT_5 0x284 ++#define IPU6_BUTTRESS_REG_FPGA_SUPPORT_6 0x288 ++#define IPU6_BUTTRESS_REG_FPGA_SUPPORT_7 0x28c ++ ++#define BUTTRESS_REG_WDT 0x8 ++#define BUTTRESS_REG_BTRS_CTRL 0xc ++#define BUTTRESS_REG_BTRS_CTRL_STALL_MODE_VC0 BIT(0) ++#define BUTTRESS_REG_BTRS_CTRL_STALL_MODE_VC1 BIT(1) ++#define BUTTRESS_REG_BTRS_CTRL_REF_CLK_IND GENMASK(9, 8) ++ ++#define BUTTRESS_REG_FW_RESET_CTL 0x30 ++#define BUTTRESS_FW_RESET_CTL_START BIT(0) ++#define BUTTRESS_FW_RESET_CTL_DONE BIT(1) ++ ++#define BUTTRESS_REG_IS_FREQ_CTL 0x34 ++#define BUTTRESS_REG_PS_FREQ_CTL 0x38 ++ ++#define BUTTRESS_FREQ_CTL_START BIT(31) ++#define BUTTRESS_FREQ_CTL_ICCMAX_LEVEL GENMASK(19, 16) ++#define BUTTRESS_FREQ_CTL_QOS_FLOOR_MASK GENMASK(15, 8) ++#define BUTTRESS_FREQ_CTL_RATIO_MASK GENMASK(7, 0) ++ ++#define BUTTRESS_REG_PWR_STATE 0x5c ++ ++#define BUTTRESS_PWR_STATE_RESET 0x0 ++#define BUTTRESS_PWR_STATE_PWR_ON_DONE 0x1 ++#define BUTTRESS_PWR_STATE_PWR_RDY 0x3 ++#define BUTTRESS_PWR_STATE_PWR_IDLE 0x4 ++ ++#define BUTTRESS_PWR_STATE_HH_STATUS_MASK GENMASK(12, 11) ++ ++enum { ++ BUTTRESS_PWR_STATE_HH_STATE_IDLE, ++ BUTTRESS_PWR_STATE_HH_STATE_IN_PRGS, ++ BUTTRESS_PWR_STATE_HH_STATE_DONE, ++ BUTTRESS_PWR_STATE_HH_STATE_ERR, ++}; ++ ++#define BUTTRESS_PWR_STATE_IS_PWR_FSM_MASK GENMASK(23, 19) ++ ++#define BUTTRESS_PWR_STATE_IS_PWR_FSM_IDLE 0x0 ++#define BUTTRESS_PWR_STATE_IS_PWR_FSM_WAIT_4_PLL_CMP 0x1 ++#define BUTTRESS_PWR_STATE_IS_PWR_FSM_WAIT_4_CLKACK 0x2 ++#define BUTTRESS_PWR_STATE_IS_PWR_FSM_WAIT_4_PG_ACK 0x3 ++#define BUTTRESS_PWR_STATE_IS_PWR_FSM_RST_ASSRT_CYCLES 0x4 ++#define BUTTRESS_PWR_STATE_IS_PWR_FSM_STOP_CLK_CYCLES1 0x5 ++#define BUTTRESS_PWR_STATE_IS_PWR_FSM_STOP_CLK_CYCLES2 0x6 ++#define BUTTRESS_PWR_STATE_IS_PWR_FSM_RST_DEASSRT_CYCLES 0x7 ++#define BUTTRESS_PWR_STATE_IS_PWR_FSM_WAIT_4_FUSE_WR_CMP 0x8 ++#define BUTTRESS_PWR_STATE_IS_PWR_FSM_BRK_POINT 0x9 ++#define BUTTRESS_PWR_STATE_IS_PWR_FSM_IS_RDY 0xa ++#define BUTTRESS_PWR_STATE_IS_PWR_FSM_HALT_HALTED 0xb ++#define BUTTRESS_PWR_STATE_IS_PWR_FSM_RST_DURATION_CNT3 0xc ++#define BUTTRESS_PWR_STATE_IS_PWR_FSM_WAIT_4_CLKACK_PD 0xd ++#define BUTTRESS_PWR_STATE_IS_PWR_FSM_PD_BRK_POINT 0xe ++#define BUTTRESS_PWR_STATE_IS_PWR_FSM_WAIT_4_PD_PG_ACK0 0xf ++ ++#define BUTTRESS_PWR_STATE_PS_PWR_FSM_MASK GENMASK(28, 24) ++ ++#define BUTTRESS_PWR_STATE_PS_PWR_FSM_IDLE 0x0 ++#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_PU_PLL_IP_RDY 0x1 ++#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_RO_PRE_CNT_EXH 0x2 ++#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_PU_VGI_PWRGOOD 0x3 ++#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_RO_POST_CNT_EXH 0x4 ++#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WR_PLL_RATIO 0x5 ++#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_PU_PLL_CMP 0x6 ++#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_PU_CLKACK 0x7 ++#define BUTTRESS_PWR_STATE_PS_PWR_FSM_RST_ASSRT_CYCLES 0x8 ++#define BUTTRESS_PWR_STATE_PS_PWR_FSM_STOP_CLK_CYCLES1 0x9 ++#define BUTTRESS_PWR_STATE_PS_PWR_FSM_STOP_CLK_CYCLES2 0xa ++#define BUTTRESS_PWR_STATE_PS_PWR_FSM_RST_DEASSRT_CYCLES 0xb ++#define BUTTRESS_PWR_STATE_PS_PWR_FSM_PU_BRK_PNT 0xc ++#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_FUSE_ACCPT 0xd ++#define BUTTRESS_PWR_STATE_PS_PWR_FSM_PS_PWR_UP 0xf ++#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_4_HALTED 0x10 ++#define BUTTRESS_PWR_STATE_PS_PWR_FSM_RESET_CNT3 0x11 ++#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_PD_CLKACK 0x12 ++#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_PD_OFF_IND 0x13 ++#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_DVFS_PH4 0x14 ++#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_DVFS_PLL_CMP 0x15 ++#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_DVFS_CLKACK 0x16 ++ ++#define BUTTRESS_REG_SECURITY_CTL 0x300 ++#define BUTTRESS_REG_SKU 0x314 ++#define BUTTRESS_REG_SECURITY_TOUCH 0x318 ++#define BUTTRESS_REG_CAMERA_MASK 0x84 ++ ++#define BUTTRESS_SECURITY_CTL_FW_SECURE_MODE BIT(16) ++#define BUTTRESS_SECURITY_CTL_FW_SETUP_MASK GENMASK(4, 0) ++ ++#define BUTTRESS_SECURITY_CTL_FW_SETUP_DONE BIT(0) ++#define BUTTRESS_SECURITY_CTL_AUTH_DONE BIT(1) ++#define BUTTRESS_SECURITY_CTL_AUTH_FAILED BIT(3) ++ ++#define BUTTRESS_REG_FW_SOURCE_BASE_LO 0x78 ++#define BUTTRESS_REG_FW_SOURCE_BASE_HI 0x7C ++#define BUTTRESS_REG_FW_SOURCE_SIZE 0x80 ++ ++#define BUTTRESS_REG_ISR_STATUS 0x90 ++#define BUTTRESS_REG_ISR_ENABLED_STATUS 0x94 ++#define BUTTRESS_REG_ISR_ENABLE 0x98 ++#define BUTTRESS_REG_ISR_CLEAR 0x9C ++ ++#define BUTTRESS_ISR_IS_IRQ BIT(0) ++#define BUTTRESS_ISR_PS_IRQ BIT(1) ++#define BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE BIT(2) ++#define BUTTRESS_ISR_IPC_EXEC_DONE_BY_ISH BIT(3) ++#define BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING BIT(4) ++#define BUTTRESS_ISR_IPC_FROM_ISH_IS_WAITING BIT(5) ++#define BUTTRESS_ISR_CSE_CSR_SET BIT(6) ++#define BUTTRESS_ISR_ISH_CSR_SET BIT(7) ++#define BUTTRESS_ISR_SPURIOUS_CMP BIT(8) ++#define BUTTRESS_ISR_WATCHDOG_EXPIRED BIT(9) ++#define BUTTRESS_ISR_PUNIT_2_IUNIT_IRQ BIT(10) ++#define BUTTRESS_ISR_SAI_VIOLATION BIT(11) ++#define BUTTRESS_ISR_HW_ASSERTION BIT(12) ++#define BUTTRESS_ISR_IS_CORRECTABLE_MEM_ERR BIT(13) ++#define BUTTRESS_ISR_IS_FATAL_MEM_ERR BIT(14) ++#define BUTTRESS_ISR_IS_NON_FATAL_MEM_ERR BIT(15) ++#define BUTTRESS_ISR_PS_CORRECTABLE_MEM_ERR BIT(16) ++#define BUTTRESS_ISR_PS_FATAL_MEM_ERR BIT(17) ++#define BUTTRESS_ISR_PS_NON_FATAL_MEM_ERR BIT(18) ++#define BUTTRESS_ISR_PS_FAST_THROTTLE BIT(19) ++#define BUTTRESS_ISR_UFI_ERROR BIT(20) ++ ++#define BUTTRESS_REG_IU2CSEDB0 0x100 ++ ++#define BUTTRESS_IU2CSEDB0_BUSY BIT(31) ++#define BUTTRESS_IU2CSEDB0_IPC_CLIENT_ID_VAL 2 ++ ++#define BUTTRESS_REG_IU2CSEDATA0 0x104 ++ ++#define BUTTRESS_IU2CSEDATA0_IPC_BOOT_LOAD 1 ++#define BUTTRESS_IU2CSEDATA0_IPC_AUTH_RUN 2 ++#define BUTTRESS_IU2CSEDATA0_IPC_AUTH_REPLACE 3 ++#define BUTTRESS_IU2CSEDATA0_IPC_UPDATE_SECURE_TOUCH 16 ++ ++#define BUTTRESS_CSE2IUDATA0_IPC_BOOT_LOAD_DONE BIT(0) ++#define BUTTRESS_CSE2IUDATA0_IPC_AUTH_RUN_DONE BIT(1) ++#define BUTTRESS_CSE2IUDATA0_IPC_AUTH_REPLACE_DONE BIT(2) ++#define BUTTRESS_CSE2IUDATA0_IPC_UPDATE_SECURE_TOUCH_DONE BIT(4) ++ ++#define BUTTRESS_REG_IU2CSECSR 0x108 ++ ++#define BUTTRESS_IU2CSECSR_IPC_PEER_COMP_ACTIONS_RST_PHASE1 BIT(0) ++#define BUTTRESS_IU2CSECSR_IPC_PEER_COMP_ACTIONS_RST_PHASE2 BIT(1) ++#define BUTTRESS_IU2CSECSR_IPC_PEER_QUERIED_IP_COMP_ACTIONS_RST_PHASE BIT(2) ++#define BUTTRESS_IU2CSECSR_IPC_PEER_ASSERTED_REG_VALID_REQ BIT(3) ++#define BUTTRESS_IU2CSECSR_IPC_PEER_ACKED_REG_VALID BIT(4) ++#define BUTTRESS_IU2CSECSR_IPC_PEER_DEASSERTED_REG_VALID_REQ BIT(5) ++ ++#define BUTTRESS_REG_CSE2IUDB0 0x304 ++#define BUTTRESS_REG_CSE2IUCSR 0x30C ++#define BUTTRESS_REG_CSE2IUDATA0 0x308 ++ ++/* 0x20 == NACK, 0xf == unknown command */ ++#define BUTTRESS_CSE2IUDATA0_IPC_NACK 0xf20 ++#define BUTTRESS_CSE2IUDATA0_IPC_NACK_MASK GENMASK(15, 0) ++ ++#define BUTTRESS_REG_ISH2IUCSR 0x50 ++#define BUTTRESS_REG_ISH2IUDB0 0x54 ++#define BUTTRESS_REG_ISH2IUDATA0 0x58 ++ ++#define BUTTRESS_REG_IU2ISHDB0 0x10C ++#define BUTTRESS_REG_IU2ISHDATA0 0x110 ++#define BUTTRESS_REG_IU2ISHDATA1 0x114 ++#define BUTTRESS_REG_IU2ISHCSR 0x118 ++ ++#define BUTTRESS_REG_FABRIC_CMD 0x88 ++ ++#define BUTTRESS_FABRIC_CMD_START_TSC_SYNC BIT(0) ++#define BUTTRESS_FABRIC_CMD_IS_DRAIN BIT(4) ++ ++#define BUTTRESS_REG_TSW_CTL 0x120 ++#define BUTTRESS_TSW_CTL_SOFT_RESET BIT(8) ++ ++#define BUTTRESS_REG_TSC_LO 0x164 ++#define BUTTRESS_REG_TSC_HI 0x168 ++ ++#define BUTTRESS_IRQS (BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING | \ ++ BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE | \ ++ BUTTRESS_ISR_IS_IRQ | BUTTRESS_ISR_PS_IRQ) ++ ++#define BUTTRESS_EVENT (BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING | \ ++ BUTTRESS_ISR_IPC_FROM_ISH_IS_WAITING | \ ++ BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE | \ ++ BUTTRESS_ISR_IPC_EXEC_DONE_BY_ISH | \ ++ BUTTRESS_ISR_SAI_VIOLATION) ++#endif /* IPU6_PLATFORM_BUTTRESS_REGS_H */ +diff --git a/drivers/media/pci/intel/ipu6/ipu6-platform-regs.h b/drivers/media/pci/intel/ipu6/ipu6-platform-regs.h +new file mode 100644 +index 000000000..b883385ad +--- /dev/null ++++ b/drivers/media/pci/intel/ipu6/ipu6-platform-regs.h +@@ -0,0 +1,179 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* Copyright (C) 2018 - 2024 Intel Corporation */ ++ ++#ifndef IPU6_PLATFORM_REGS_H ++#define IPU6_PLATFORM_REGS_H ++ ++#include ++ ++/* ++ * IPU6 uses uniform address within IPU6, therefore all subsystem registers ++ * locates in one single space starts from 0 but in different sctions with ++ * different addresses, the subsystem offsets are defined to 0 as the ++ * register definition will have the address offset to 0. ++ */ ++#define IPU6_UNIFIED_OFFSET 0 ++ ++#define IPU6_ISYS_IOMMU0_OFFSET 0x2e0000 ++#define IPU6_ISYS_IOMMU1_OFFSET 0x2e0500 ++#define IPU6_ISYS_IOMMUI_OFFSET 0x2e0a00 ++ ++#define IPU6_PSYS_IOMMU0_OFFSET 0x1b0000 ++#define IPU6_PSYS_IOMMU1_OFFSET 0x1b0700 ++#define IPU6_PSYS_IOMMU1R_OFFSET 0x1b0e00 ++#define IPU6_PSYS_IOMMUI_OFFSET 0x1b1500 ++ ++/* the offset from IOMMU base register */ ++#define IPU6_MMU_L1_STREAM_ID_REG_OFFSET 0x0c ++#define IPU6_MMU_L2_STREAM_ID_REG_OFFSET 0x4c ++#define IPU6_PSYS_MMU1W_L2_STREAM_ID_REG_OFFSET 0x8c ++ ++#define IPU6_MMU_INFO_OFFSET 0x8 ++ ++#define IPU6_ISYS_SPC_OFFSET 0x210000 ++ ++#define IPU6SE_PSYS_SPC_OFFSET 0x110000 ++#define IPU6_PSYS_SPC_OFFSET 0x118000 ++ ++#define IPU6_ISYS_DMEM_OFFSET 0x200000 ++#define IPU6_PSYS_DMEM_OFFSET 0x100000 ++ ++#define IPU6_REG_ISYS_UNISPART_IRQ_EDGE 0x27c000 ++#define IPU6_REG_ISYS_UNISPART_IRQ_MASK 0x27c004 ++#define IPU6_REG_ISYS_UNISPART_IRQ_STATUS 0x27c008 ++#define IPU6_REG_ISYS_UNISPART_IRQ_CLEAR 0x27c00c ++#define IPU6_REG_ISYS_UNISPART_IRQ_ENABLE 0x27c010 ++#define IPU6_REG_ISYS_UNISPART_IRQ_LEVEL_NOT_PULSE 0x27c014 ++#define IPU6_REG_ISYS_UNISPART_SW_IRQ_REG 0x27c414 ++#define IPU6_REG_ISYS_UNISPART_SW_IRQ_MUX_REG 0x27c418 ++#define IPU6_ISYS_UNISPART_IRQ_CSI0 BIT(2) ++#define IPU6_ISYS_UNISPART_IRQ_CSI1 BIT(3) ++#define IPU6_ISYS_UNISPART_IRQ_SW BIT(22) ++ ++#define IPU6_REG_ISYS_ISL_TOP_IRQ_EDGE 0x2b0200 ++#define IPU6_REG_ISYS_ISL_TOP_IRQ_MASK 0x2b0204 ++#define IPU6_REG_ISYS_ISL_TOP_IRQ_STATUS 0x2b0208 ++#define IPU6_REG_ISYS_ISL_TOP_IRQ_CLEAR 0x2b020c ++#define IPU6_REG_ISYS_ISL_TOP_IRQ_ENABLE 0x2b0210 ++#define IPU6_REG_ISYS_ISL_TOP_IRQ_LEVEL_NOT_PULSE 0x2b0214 ++ ++#define IPU6_REG_ISYS_CMPR_TOP_IRQ_EDGE 0x2d2100 ++#define IPU6_REG_ISYS_CMPR_TOP_IRQ_MASK 0x2d2104 ++#define IPU6_REG_ISYS_CMPR_TOP_IRQ_STATUS 0x2d2108 ++#define IPU6_REG_ISYS_CMPR_TOP_IRQ_CLEAR 0x2d210c ++#define IPU6_REG_ISYS_CMPR_TOP_IRQ_ENABLE 0x2d2110 ++#define IPU6_REG_ISYS_CMPR_TOP_IRQ_LEVEL_NOT_PULSE 0x2d2114 ++ ++/* CDC Burst collector thresholds for isys - 3 FIFOs i = 0..2 */ ++#define IPU6_REG_ISYS_CDC_THRESHOLD(i) (0x27c400 + ((i) * 4)) ++ ++#define IPU6_CSI_IRQ_NUM_PER_PIPE 4 ++#define IPU6SE_ISYS_CSI_PORT_NUM 4 ++#define IPU6_ISYS_CSI_PORT_NUM 8 ++ ++#define IPU6_ISYS_CSI_PORT_IRQ(irq_num) BIT(irq_num) ++ ++/* PKG DIR OFFSET in IMR in secure mode */ ++#define IPU6_PKG_DIR_IMR_OFFSET 0x40 ++ ++#define IPU6_ISYS_REG_SPC_STATUS_CTRL 0x0 ++ ++#define IPU6_ISYS_SPC_STATUS_START BIT(1) ++#define IPU6_ISYS_SPC_STATUS_RUN BIT(3) ++#define IPU6_ISYS_SPC_STATUS_READY BIT(5) ++#define IPU6_ISYS_SPC_STATUS_CTRL_ICACHE_INVALIDATE BIT(12) ++#define IPU6_ISYS_SPC_STATUS_ICACHE_PREFETCH BIT(13) ++ ++#define IPU6_PSYS_REG_SPC_STATUS_CTRL 0x0 ++#define IPU6_PSYS_REG_SPC_START_PC 0x4 ++#define IPU6_PSYS_REG_SPC_ICACHE_BASE 0x10 ++#define IPU6_REG_PSYS_INFO_SEG_0_CONFIG_ICACHE_MASTER 0x14 ++ ++#define IPU6_PSYS_SPC_STATUS_START BIT(1) ++#define IPU6_PSYS_SPC_STATUS_RUN BIT(3) ++#define IPU6_PSYS_SPC_STATUS_READY BIT(5) ++#define IPU6_PSYS_SPC_STATUS_CTRL_ICACHE_INVALIDATE BIT(12) ++#define IPU6_PSYS_SPC_STATUS_ICACHE_PREFETCH BIT(13) ++ ++#define IPU6_PSYS_REG_SPP0_STATUS_CTRL 0x20000 ++ ++#define IPU6_INFO_ENABLE_SNOOP BIT(0) ++#define IPU6_INFO_DEC_FORCE_FLUSH BIT(1) ++#define IPU6_INFO_DEC_PASS_THROUGH BIT(2) ++#define IPU6_INFO_ZLW BIT(3) ++#define IPU6_INFO_REQUEST_DESTINATION_IOSF BIT(9) ++#define IPU6_INFO_IMR_BASE BIT(10) ++#define IPU6_INFO_IMR_DESTINED BIT(11) ++ ++#define IPU6_INFO_REQUEST_DESTINATION_PRIMARY IPU6_INFO_REQUEST_DESTINATION_IOSF ++ ++/* ++ * s2m_pixel_soc_pixel_remapping is dedicated for the enabling of the ++ * pixel s2m remp ability.Remap here means that s2m rearange the order ++ * of the pixels in each 4 pixels group. ++ * For examle, mirroring remping means that if input's 4 first pixels ++ * are 1 2 3 4 then in output we should see 4 3 2 1 in this 4 first pixels. ++ * 0xE4 is from s2m MAS document. It means no remapping. ++ */ ++#define S2M_PIXEL_SOC_PIXEL_REMAPPING_FLAG_NO_REMAPPING 0xe4 ++/* ++ * csi_be_soc_pixel_remapping is for the enabling of the pixel remapping. ++ * This remapping is exactly like the stream2mmio remapping. ++ */ ++#define CSI_BE_SOC_PIXEL_REMAPPING_FLAG_NO_REMAPPING 0xe4 ++ ++#define IPU6_REG_DMA_TOP_AB_GROUP1_BASE_ADDR 0x1ae000 ++#define IPU6_REG_DMA_TOP_AB_GROUP2_BASE_ADDR 0x1af000 ++#define IPU6_REG_DMA_TOP_AB_RING_MIN_OFFSET(n) (0x4 + (n) * 0xc) ++#define IPU6_REG_DMA_TOP_AB_RING_MAX_OFFSET(n) (0x8 + (n) * 0xc) ++#define IPU6_REG_DMA_TOP_AB_RING_ACCESS_OFFSET(n) (0xc + (n) * 0xc) ++ ++enum ipu6_device_ab_group1_target_id { ++ IPU6_DEVICE_AB_GROUP1_TARGET_ID_R0_SPC_DMEM, ++ IPU6_DEVICE_AB_GROUP1_TARGET_ID_R1_SPC_DMEM, ++ IPU6_DEVICE_AB_GROUP1_TARGET_ID_R2_SPC_DMEM, ++ IPU6_DEVICE_AB_GROUP1_TARGET_ID_R3_SPC_STATUS_REG, ++ IPU6_DEVICE_AB_GROUP1_TARGET_ID_R4_SPC_MASTER_BASE_ADDR, ++ IPU6_DEVICE_AB_GROUP1_TARGET_ID_R5_SPC_PC_STALL, ++ IPU6_DEVICE_AB_GROUP1_TARGET_ID_R6_SPC_EQ, ++ IPU6_DEVICE_AB_GROUP1_TARGET_ID_R7_SPC_RESERVED, ++ IPU6_DEVICE_AB_GROUP1_TARGET_ID_R8_SPC_RESERVED, ++ IPU6_DEVICE_AB_GROUP1_TARGET_ID_R9_SPP0, ++ IPU6_DEVICE_AB_GROUP1_TARGET_ID_R10_SPP1, ++ IPU6_DEVICE_AB_GROUP1_TARGET_ID_R11_CENTRAL_R1, ++ IPU6_DEVICE_AB_GROUP1_TARGET_ID_R12_IRQ, ++ IPU6_DEVICE_AB_GROUP1_TARGET_ID_R13_CENTRAL_R2, ++ IPU6_DEVICE_AB_GROUP1_TARGET_ID_R14_DMA, ++ IPU6_DEVICE_AB_GROUP1_TARGET_ID_R15_DMA, ++ IPU6_DEVICE_AB_GROUP1_TARGET_ID_R16_GP, ++ IPU6_DEVICE_AB_GROUP1_TARGET_ID_R17_ZLW_INSERTER, ++ IPU6_DEVICE_AB_GROUP1_TARGET_ID_R18_AB, ++}; ++ ++enum nci_ab_access_mode { ++ NCI_AB_ACCESS_MODE_RW, /* read & write */ ++ NCI_AB_ACCESS_MODE_RO, /* read only */ ++ NCI_AB_ACCESS_MODE_WO, /* write only */ ++ NCI_AB_ACCESS_MODE_NA, /* No access at all */ ++}; ++ ++/* IRQ-related registers in PSYS */ ++#define IPU6_REG_PSYS_GPDEV_IRQ_EDGE 0x1aa200 ++#define IPU6_REG_PSYS_GPDEV_IRQ_MASK 0x1aa204 ++#define IPU6_REG_PSYS_GPDEV_IRQ_STATUS 0x1aa208 ++#define IPU6_REG_PSYS_GPDEV_IRQ_CLEAR 0x1aa20c ++#define IPU6_REG_PSYS_GPDEV_IRQ_ENABLE 0x1aa210 ++#define IPU6_REG_PSYS_GPDEV_IRQ_LEVEL_NOT_PULSE 0x1aa214 ++/* There are 8 FW interrupts, n = 0..7 */ ++#define IPU6_PSYS_GPDEV_FWIRQ0 5 ++#define IPU6_PSYS_GPDEV_FWIRQ1 6 ++#define IPU6_PSYS_GPDEV_FWIRQ2 7 ++#define IPU6_PSYS_GPDEV_FWIRQ3 8 ++#define IPU6_PSYS_GPDEV_FWIRQ4 9 ++#define IPU6_PSYS_GPDEV_FWIRQ5 10 ++#define IPU6_PSYS_GPDEV_FWIRQ6 11 ++#define IPU6_PSYS_GPDEV_FWIRQ7 12 ++#define IPU6_PSYS_GPDEV_IRQ_FWIRQ(n) BIT(n) ++#define IPU6_REG_PSYS_GPDEV_FWIRQ(n) (4 * (n) + 0x1aa100) ++ ++#endif /* IPU6_PLATFORM_REGS_H */ +diff --git a/drivers/media/pci/intel/ipu6/ipu6.h b/drivers/media/pci/intel/ipu6/ipu6.h +new file mode 100644 +index 000000000..92e3c3414 +--- /dev/null ++++ b/drivers/media/pci/intel/ipu6/ipu6.h +@@ -0,0 +1,342 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* Copyright (C) 2013 - 2024 Intel Corporation */ ++ ++#ifndef IPU6_H ++#define IPU6_H ++ ++#include ++#include ++#include ++ ++#include "ipu6-buttress.h" ++ ++struct firmware; ++struct pci_dev; ++struct ipu6_bus_device; ++ ++#define IPU6_NAME "intel-ipu6" ++#define IPU6_MEDIA_DEV_MODEL_NAME "ipu6" ++ ++#define IPU6SE_FIRMWARE_NAME "intel/ipu/ipu6se_fw.bin" ++#define IPU6EP_FIRMWARE_NAME "intel/ipu/ipu6ep_fw.bin" ++#define IPU6_FIRMWARE_NAME "intel/ipu/ipu6_fw.bin" ++#define IPU6EPMTL_FIRMWARE_NAME "intel/ipu/ipu6epmtl_fw.bin" ++#define IPU6EPADLN_FIRMWARE_NAME "intel/ipu/ipu6epadln_fw.bin" ++ ++enum ipu6_version { ++ IPU6_VER_INVALID = 0, ++ IPU6_VER_6 = 1, ++ IPU6_VER_6SE = 3, ++ IPU6_VER_6EP = 5, ++ IPU6_VER_6EP_MTL = 6, ++}; ++ ++/* ++ * IPU6 - TGL ++ * IPU6SE - JSL ++ * IPU6EP - ADL/RPL ++ * IPU6EP_MTL - MTL ++ */ ++static inline bool is_ipu6se(u8 hw_ver) ++{ ++ return hw_ver == IPU6_VER_6SE; ++} ++ ++static inline bool is_ipu6ep(u8 hw_ver) ++{ ++ return hw_ver == IPU6_VER_6EP; ++} ++ ++static inline bool is_ipu6ep_mtl(u8 hw_ver) ++{ ++ return hw_ver == IPU6_VER_6EP_MTL; ++} ++ ++static inline bool is_ipu6_tgl(u8 hw_ver) ++{ ++ return hw_ver == IPU6_VER_6; ++} ++ ++/* ++ * ISYS DMA can overshoot. For higher resolutions over allocation is one line ++ * but it must be at minimum 1024 bytes. Value could be different in ++ * different versions / generations thus provide it via platform data. ++ */ ++#define IPU6_ISYS_OVERALLOC_MIN 1024 ++ ++/* Physical pages in GDA is 128, page size is 2K for IPU6, 1K for others */ ++#define IPU6_DEVICE_GDA_NR_PAGES 128 ++ ++/* Virtualization factor to calculate the available virtual pages */ ++#define IPU6_DEVICE_GDA_VIRT_FACTOR 32 ++ ++struct ipu6_device { ++ struct pci_dev *pdev; ++ struct list_head devices; ++ struct ipu6_bus_device *isys; ++ struct ipu6_bus_device *psys; ++ struct ipu6_buttress buttress; ++ ++ const struct firmware *cpd_fw; ++ const char *cpd_fw_name; ++ u32 cpd_metadata_cmpnt_size; ++ ++ void __iomem *base; ++ bool need_ipc_reset; ++ bool secure_mode; ++ u8 hw_ver; ++ bool bus_ready_to_probe; ++}; ++ ++#define IPU6_ISYS_NAME "isys" ++#define IPU6_PSYS_NAME "psys" ++ ++#define IPU6_MMU_MAX_DEVICES 4 ++#define IPU6_MMU_ADDR_BITS 32 ++/* The firmware is accessible within the first 2 GiB only in non-secure mode. */ ++#define IPU6_MMU_ADDR_BITS_NON_SECURE 31 ++ ++#define IPU6_MMU_MAX_TLB_L1_STREAMS 32 ++#define IPU6_MMU_MAX_TLB_L2_STREAMS 32 ++#define IPU6_MAX_LI_BLOCK_ADDR 128 ++#define IPU6_MAX_L2_BLOCK_ADDR 64 ++ ++#define IPU6SE_ISYS_NUM_STREAMS IPU6SE_NONSECURE_STREAM_ID_MAX ++#define IPU6_ISYS_NUM_STREAMS IPU6_NONSECURE_STREAM_ID_MAX ++ ++/* ++ * To maximize the IOSF utlization, IPU6 need to send requests in bursts. ++ * At the DMA interface with the buttress, there are CDC FIFOs with burst ++ * collection capability. CDC FIFO burst collectors have a configurable ++ * threshold and is configured based on the outcome of performance measurements. ++ * ++ * isys has 3 ports with IOSF interface for VC0, VC1 and VC2 ++ * psys has 4 ports with IOSF interface for VC0, VC1w, VC1r and VC2 ++ * ++ * Threshold values are pre-defined and are arrived at after performance ++ * evaluations on a type of IPU6 ++ */ ++#define IPU6_MAX_VC_IOSF_PORTS 4 ++ ++/* ++ * IPU6 must configure correct arbitration mechanism related to the IOSF VC ++ * requests. There are two options per VC0 and VC1 - > 0 means rearbitrate on ++ * stall and 1 means stall until the request is completed. ++ */ ++#define IPU6_BTRS_ARB_MODE_TYPE_REARB 0 ++#define IPU6_BTRS_ARB_MODE_TYPE_STALL 1 ++ ++/* Currently chosen arbitration mechanism for VC0 */ ++#define IPU6_BTRS_ARB_STALL_MODE_VC0 \ ++ IPU6_BTRS_ARB_MODE_TYPE_REARB ++ ++/* Currently chosen arbitration mechanism for VC1 */ ++#define IPU6_BTRS_ARB_STALL_MODE_VC1 \ ++ IPU6_BTRS_ARB_MODE_TYPE_REARB ++ ++/* ++ * MMU Invalidation HW bug workaround by ZLW mechanism ++ * ++ * Old IPU6 MMUV2 has a bug in the invalidation mechanism which might result in ++ * wrong translation or replication of the translation. This will cause data ++ * corruption. So we cannot directly use the MMU V2 invalidation registers ++ * to invalidate the MMU. Instead, whenever an invalidate is called, we need to ++ * clear the TLB by evicting all the valid translations by filling it with trash ++ * buffer (which is guaranteed not to be used by any other processes). ZLW is ++ * used to fill the L1 and L2 caches with the trash buffer translations. ZLW ++ * or Zero length write, is pre-fetch mechanism to pre-fetch the pages in ++ * advance to the L1 and L2 caches without triggering any memory operations. ++ * ++ * In MMU V2, L1 -> 16 streams and 64 blocks, maximum 16 blocks per stream ++ * One L1 block has 16 entries, hence points to 16 * 4K pages ++ * L2 -> 16 streams and 32 blocks. 2 blocks per streams ++ * One L2 block maps to 1024 L1 entries, hence points to 4MB address range ++ * 2 blocks per L2 stream means, 1 stream points to 8MB range ++ * ++ * As we need to clear the caches and 8MB being the biggest cache size, we need ++ * to have trash buffer which points to 8MB address range. As these trash ++ * buffers are not used for any memory transactions, we need only the least ++ * amount of physical memory. So we reserve 8MB IOVA address range but only ++ * one page is reserved from physical memory. Each of this 8MB IOVA address ++ * range is then mapped to the same physical memory page. ++ */ ++/* One L2 entry maps 1024 L1 entries and one L1 entry per page */ ++#define IPU6_MMUV2_L2_RANGE (1024 * PAGE_SIZE) ++/* Max L2 blocks per stream */ ++#define IPU6_MMUV2_MAX_L2_BLOCKS 2 ++/* Max L1 blocks per stream */ ++#define IPU6_MMUV2_MAX_L1_BLOCKS 16 ++#define IPU6_MMUV2_TRASH_RANGE (IPU6_MMUV2_L2_RANGE * IPU6_MMUV2_MAX_L2_BLOCKS) ++/* Entries per L1 block */ ++#define MMUV2_ENTRIES_PER_L1_BLOCK 16 ++#define MMUV2_TRASH_L1_BLOCK_OFFSET (MMUV2_ENTRIES_PER_L1_BLOCK * PAGE_SIZE) ++#define MMUV2_TRASH_L2_BLOCK_OFFSET IPU6_MMUV2_L2_RANGE ++ ++/* ++ * In some of the IPU6 MMUs, there is provision to configure L1 and L2 page ++ * table caches. Both these L1 and L2 caches are divided into multiple sections ++ * called streams. There is maximum 16 streams for both caches. Each of these ++ * sections are subdivided into multiple blocks. When nr_l1streams = 0 and ++ * nr_l2streams = 0, means the MMU is of type MMU_V1 and do not support ++ * L1/L2 page table caches. ++ * ++ * L1 stream per block sizes are configurable and varies per usecase. ++ * L2 has constant block sizes - 2 blocks per stream. ++ * ++ * MMU1 support pre-fetching of the pages to have less cache lookup misses. To ++ * enable the pre-fetching, MMU1 AT (Address Translator) device registers ++ * need to be configured. ++ * ++ * There are four types of memory accesses which requires ZLW configuration. ++ * ZLW(Zero Length Write) is a mechanism to enable VT-d pre-fetching on IOMMU. ++ * ++ * 1. Sequential Access or 1D mode ++ * Set ZLW_EN -> 1 ++ * set ZLW_PAGE_CROSS_1D -> 1 ++ * Set ZLW_N to "N" pages so that ZLW will be inserte N pages ahead where ++ * N is pre-defined and hardcoded in the platform data ++ * Set ZLW_2D -> 0 ++ * ++ * 2. ZLW 2D mode ++ * Set ZLW_EN -> 1 ++ * set ZLW_PAGE_CROSS_1D -> 1, ++ * Set ZLW_N -> 0 ++ * Set ZLW_2D -> 1 ++ * ++ * 3. ZLW Enable (no 1D or 2D mode) ++ * Set ZLW_EN -> 1 ++ * set ZLW_PAGE_CROSS_1D -> 0, ++ * Set ZLW_N -> 0 ++ * Set ZLW_2D -> 0 ++ * ++ * 4. ZLW disable ++ * Set ZLW_EN -> 0 ++ * set ZLW_PAGE_CROSS_1D -> 0, ++ * Set ZLW_N -> 0 ++ * Set ZLW_2D -> 0 ++ * ++ * To configure the ZLW for the above memory access, four registers are ++ * available. Hence to track these four settings, we have the following entries ++ * in the struct ipu6_mmu_hw. Each of these entries are per stream and ++ * available only for the L1 streams. ++ * ++ * a. l1_zlw_en -> To track zlw enabled per stream (ZLW_EN) ++ * b. l1_zlw_1d_mode -> Track 1D mode per stream. ZLW inserted at page boundary ++ * c. l1_ins_zlw_ahead_pages -> to track how advance the ZLW need to be inserted ++ * Insert ZLW request N pages ahead address. ++ * d. l1_zlw_2d_mode -> To track 2D mode per stream (ZLW_2D) ++ * ++ * ++ * Currently L1/L2 streams, blocks, AT ZLW configurations etc. are pre-defined ++ * as per the usecase specific calculations. Any change to this pre-defined ++ * table has to happen in sync with IPU6 FW. ++ */ ++struct ipu6_mmu_hw { ++ union { ++ unsigned long offset; ++ void __iomem *base; ++ }; ++ u32 info_bits; ++ u8 nr_l1streams; ++ /* ++ * L1 has variable blocks per stream - total of 64 blocks and maximum of ++ * 16 blocks per stream. Configurable by using the block start address ++ * per stream. Block start address is calculated from the block size ++ */ ++ u8 l1_block_sz[IPU6_MMU_MAX_TLB_L1_STREAMS]; ++ /* Is ZLW is enabled in each stream */ ++ bool l1_zlw_en[IPU6_MMU_MAX_TLB_L1_STREAMS]; ++ bool l1_zlw_1d_mode[IPU6_MMU_MAX_TLB_L1_STREAMS]; ++ u8 l1_ins_zlw_ahead_pages[IPU6_MMU_MAX_TLB_L1_STREAMS]; ++ bool l1_zlw_2d_mode[IPU6_MMU_MAX_TLB_L1_STREAMS]; ++ ++ u32 l1_stream_id_reg_offset; ++ u32 l2_stream_id_reg_offset; ++ ++ u8 nr_l2streams; ++ /* ++ * L2 has fixed 2 blocks per stream. Block address is calculated ++ * from the block size ++ */ ++ u8 l2_block_sz[IPU6_MMU_MAX_TLB_L2_STREAMS]; ++ /* flag to track if WA is needed for successive invalidate HW bug */ ++ bool insert_read_before_invalidate; ++}; ++ ++struct ipu6_mmu_pdata { ++ u32 nr_mmus; ++ struct ipu6_mmu_hw mmu_hw[IPU6_MMU_MAX_DEVICES]; ++ int mmid; ++}; ++ ++struct ipu6_isys_csi2_pdata { ++ void __iomem *base; ++}; ++ ++struct ipu6_isys_internal_csi2_pdata { ++ u32 nports; ++ u32 irq_mask; ++ u32 ctrl0_irq_edge; ++ u32 ctrl0_irq_clear; ++ u32 ctrl0_irq_mask; ++ u32 ctrl0_irq_enable; ++ u32 ctrl0_irq_lnp; ++ u32 ctrl0_irq_status; ++ u32 fw_access_port_ofs; ++}; ++ ++struct ipu6_isys_internal_tpg_pdata { ++ u32 ntpgs; ++ u32 *offsets; ++ u32 *sels; ++}; ++ ++struct ipu6_hw_variants { ++ unsigned long offset; ++ u32 nr_mmus; ++ struct ipu6_mmu_hw mmu_hw[IPU6_MMU_MAX_DEVICES]; ++ u8 cdc_fifos; ++ u8 cdc_fifo_threshold[IPU6_MAX_VC_IOSF_PORTS]; ++ u32 dmem_offset; ++ u32 spc_offset; ++}; ++ ++struct ipu6_isys_internal_pdata { ++ struct ipu6_isys_internal_csi2_pdata csi2; ++ struct ipu6_hw_variants hw_variant; ++ u32 num_parallel_streams; ++ u32 isys_dma_overshoot; ++ u32 sram_gran_shift; ++ u32 sram_gran_size; ++ u32 max_sram_size; ++ u32 max_streams; ++ u32 max_send_queues; ++ u32 max_sram_blocks; ++ u32 max_devq_size; ++ u32 sensor_type_start; ++ u32 sensor_type_end; ++ u32 ltr; ++ u32 memopen_threshold; ++ bool enhanced_iwake; ++}; ++ ++struct ipu6_isys_pdata { ++ void __iomem *base; ++ const struct ipu6_isys_internal_pdata *ipdata; ++}; ++ ++struct ipu6_psys_internal_pdata { ++ struct ipu6_hw_variants hw_variant; ++}; ++ ++struct ipu6_psys_pdata { ++ void __iomem *base; ++ const struct ipu6_psys_internal_pdata *ipdata; ++}; ++ ++int ipu6_fw_authenticate(void *data, u64 val); ++void ipu6_configure_spc(struct ipu6_device *isp, ++ const struct ipu6_hw_variants *hw_variant, ++ int pkg_dir_idx, void __iomem *base, u64 *pkg_dir, ++ dma_addr_t pkg_dir_dma_addr); ++#endif /* IPU6_H */ +-- +2.43.0 +