diff --git a/target/linux/bcm27xx/bcm2708/config-6.6 b/target/linux/bcm27xx/bcm2708/config-6.6 index a50596e45e62..4872e44642f8 100644 --- a/target/linux/bcm27xx/bcm2708/config-6.6 +++ b/target/linux/bcm27xx/bcm2708/config-6.6 @@ -160,6 +160,7 @@ CONFIG_FIX_EARLYCON_MEM=y CONFIG_FONT_8x16=y CONFIG_FONT_8x8=y CONFIG_FONT_SUPPORT=y +CONFIG_FORCE_NR_CPUS=y CONFIG_FRAMEBUFFER_CONSOLE=y # CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y diff --git a/target/linux/bcm27xx/bcm2711/config-6.6 b/target/linux/bcm27xx/bcm2711/config-6.6 index 33458c27d725..270763549a19 100644 --- a/target/linux/bcm27xx/bcm2711/config-6.6 +++ b/target/linux/bcm27xx/bcm2711/config-6.6 @@ -176,6 +176,7 @@ CONFIG_DMA_BCM2835=y CONFIG_DMA_CMA=y CONFIG_DMA_DIRECT_REMAP=y CONFIG_DMA_ENGINE=y +# CONFIG_DMA_NUMA_CMA is not set CONFIG_DMA_OF=y CONFIG_DMA_SHARED_BUFFER=y CONFIG_DMA_VIRTUAL_CHANNELS=y @@ -221,6 +222,8 @@ CONFIG_FW_LOADER_SYSFS=y CONFIG_GCC10_NO_ARRAY_BOUNDS=y CONFIG_GCC_SUPPORTS_DYNAMIC_FTRACE_WITH_ARGS=y CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_ARCH_NUMA=y +CONFIG_GENERIC_ARCH_NUMA_EMULATION=y CONFIG_GENERIC_ARCH_TOPOLOGY=y CONFIG_GENERIC_BUG=y CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y @@ -331,6 +334,8 @@ CONFIG_MODULES_USE_ELF_RELA=y # CONFIG_MTD is not set CONFIG_MUTEX_SPIN_ON_OWNER=y CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y +CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y CONFIG_NEED_SG_DMA_LENGTH=y CONFIG_NET_EGRESS=y CONFIG_NET_FLOW_LIMIT=y @@ -340,11 +345,15 @@ CONFIG_NET_SELFTESTS=y CONFIG_NET_XGRESS=y CONFIG_NLS=y CONFIG_NLS_ASCII=y +CONFIG_NODES_SHIFT=4 CONFIG_NOP_USB_XCEIV=y CONFIG_NO_HZ=y CONFIG_NO_HZ_COMMON=y CONFIG_NO_HZ_IDLE=y CONFIG_NR_CPUS=4 +CONFIG_NUMA=y +# CONFIG_NUMA_BALANCING is not set +CONFIG_NUMA_EMULATION=y CONFIG_NVMEM=y CONFIG_NVMEM_LAYOUTS=y CONFIG_NVMEM_RASPBERRYPI_OTP=y @@ -358,6 +367,7 @@ CONFIG_OF_GPIO=y CONFIG_OF_IRQ=y CONFIG_OF_KOBJ=y CONFIG_OF_MDIO=y +CONFIG_OF_NUMA=y CONFIG_OF_OVERLAY=y CONFIG_OF_RESOLVE=y CONFIG_PADATA=y @@ -485,6 +495,7 @@ CONFIG_USB_UAS=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_PCI=y CONFIG_USB_XHCI_PLATFORM=y +CONFIG_USE_PERCPU_NUMA_NODE_ID=y CONFIG_VCHIQ_CDEV=y CONFIG_VIDEO_CMDLINE=y CONFIG_VIDEO_DEV=y diff --git a/target/linux/bcm27xx/bcm2712/config-6.6 b/target/linux/bcm27xx/bcm2712/config-6.6 index 734b19612bca..a5eb6c4d0e1f 100644 --- a/target/linux/bcm27xx/bcm2712/config-6.6 +++ b/target/linux/bcm27xx/bcm2712/config-6.6 @@ -218,6 +218,7 @@ CONFIG_DMA_BCM2835=y CONFIG_DMA_CMA=y CONFIG_DMA_DIRECT_REMAP=y CONFIG_DMA_ENGINE=y +# CONFIG_DMA_NUMA_CMA is not set CONFIG_DMA_OF=y CONFIG_DMA_OPS=y CONFIG_DMA_SHARED_BUFFER=y @@ -264,6 +265,8 @@ CONFIG_FW_LOADER_SYSFS=y CONFIG_GCC10_NO_ARRAY_BOUNDS=y CONFIG_GCC_SUPPORTS_DYNAMIC_FTRACE_WITH_ARGS=y CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_ARCH_NUMA=y +CONFIG_GENERIC_ARCH_NUMA_EMULATION=y CONFIG_GENERIC_ARCH_TOPOLOGY=y CONFIG_GENERIC_BUG=y CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y @@ -409,6 +412,8 @@ CONFIG_MMU_LAZY_TLB_REFCOUNT=y CONFIG_MODULES_USE_ELF_RELA=y CONFIG_MUTEX_SPIN_ON_OWNER=y CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y +CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y CONFIG_NEED_SG_DMA_FLAGS=y CONFIG_NEED_SG_DMA_LENGTH=y CONFIG_NET_EGRESS=y @@ -419,11 +424,15 @@ CONFIG_NET_SELFTESTS=y CONFIG_NET_XGRESS=y CONFIG_NLS=y CONFIG_NLS_ASCII=y +CONFIG_NODES_SHIFT=4 CONFIG_NOP_USB_XCEIV=y CONFIG_NO_HZ=y CONFIG_NO_HZ_COMMON=y CONFIG_NO_HZ_IDLE=y CONFIG_NR_CPUS=4 +CONFIG_NUMA=y +# CONFIG_NUMA_BALANCING is not set +CONFIG_NUMA_EMULATION=y CONFIG_NVMEM=y CONFIG_NVMEM_LAYOUTS=y CONFIG_NVMEM_RASPBERRYPI_OTP=y @@ -441,6 +450,7 @@ CONFIG_OF_IOMMU=y CONFIG_OF_IRQ=y CONFIG_OF_KOBJ=y CONFIG_OF_MDIO=y +CONFIG_OF_NUMA=y CONFIG_OF_OVERLAY=y CONFIG_OF_RESOLVE=y CONFIG_PADATA=y @@ -610,6 +620,7 @@ CONFIG_USB_UAS=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_PCI=y CONFIG_USB_XHCI_PLATFORM=y +CONFIG_USE_PERCPU_NUMA_NODE_ID=y CONFIG_VCHIQ_CDEV=y CONFIG_VIDEO_CMDLINE=y CONFIG_VIDEO_DEV=y diff --git a/target/linux/bcm27xx/modules/sound.mk b/target/linux/bcm27xx/modules/sound.mk index e61f07852b6a..989828e97ee9 100644 --- a/target/linux/bcm27xx/modules/sound.mk +++ b/target/linux/bcm27xx/modules/sound.mk @@ -45,7 +45,8 @@ $(eval $(call KernelPackage,sound-soc-bcm2835-i2s)) define KernelPackage/sound-soc-rpi-simple-soundcard TITLE:=Support for Raspberry Pi simple soundcards KCONFIG:= \ - CONFIG_SND_RPI_SIMPLE_SOUNDCARD + CONFIG_SND_RPI_SIMPLE_SOUNDCARD \ + CONFIG_SND_BCM2708_SOC_HIFIBERRY_ADC8X FILES:= \ $(LINUX_DIR)/sound/soc/bcm/snd-soc-rpi-simple-soundcard.ko AUTOLOAD:=$(call AutoLoad,68,snd-soc-rpi-simple-soundcard) @@ -526,6 +527,32 @@ endef $(eval $(call KernelPackage,sound-soc-googlevoicehat)) +define KernelPackage/sound-soc-hifiberry-adc + TITLE:=Support for HifiBerry ADC + KCONFIG:= \ + CONFIG_SND_BCM2708_SOC_HIFIBERRY_ADC \ + CONFIG_SND_RPI_HIFIBERRY_ADC \ + CONFIG_SND_SOC_PCM186X_I2C + FILES:= \ + $(LINUX_DIR)/sound/soc/bcm/snd-soc-hifiberry-adc.ko \ + $(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm186x.ko \ + $(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm186x-i2c.ko + AUTOLOAD:=$(call AutoLoad,68,snd-soc-pcm186x snd-soc-pcm186x-i2c \ + snd-soc-hifiberry-adc) + DEPENDS:= \ + kmod-sound-soc-bcm2835-i2s \ + +kmod-i2c-bcm2835 \ + +kmod-regmap-i2c + $(call AddDepends/sound) +endef + +define KernelPackage/sound-soc-hifiberry-adc/description + This package contains support for HifiBerry ADC +endef + +$(eval $(call KernelPackage,sound-soc-hifiberry-adc)) + + define KernelPackage/sound-soc-hifiberry-dac TITLE:=Support for HifiBerry DAC KCONFIG:= \ diff --git a/target/linux/bcm27xx/patches-6.6/950-0635-drm-vc4-Assign-LBM-memory-during-atomic_flush.patch b/target/linux/bcm27xx/patches-6.6/950-0635-drm-vc4-Assign-LBM-memory-during-atomic_flush.patch deleted file mode 100644 index ccdae3dbe06f..000000000000 --- a/target/linux/bcm27xx/patches-6.6/950-0635-drm-vc4-Assign-LBM-memory-during-atomic_flush.patch +++ /dev/null @@ -1,240 +0,0 @@ -From c7b98a63328a749d44b7580ee9baafc5d417e48f Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Thu, 31 Aug 2023 11:45:38 +0100 -Subject: [PATCH 0635/1085] drm/vc4: Assign LBM memory during atomic_flush. - -Avoid double buffering LBM allocations by making the -allocation a single alloc per crtc at atomic_flush. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/tests/vc4_test_lbm_size.c | 2 +- - drivers/gpu/drm/vc4/vc4_drv.h | 8 ++-- - drivers/gpu/drm/vc4/vc4_hvs.c | 47 ++++++++++++++++++- - drivers/gpu/drm/vc4/vc4_plane.c | 38 +++------------ - 4 files changed, 58 insertions(+), 37 deletions(-) - ---- a/drivers/gpu/drm/vc4/tests/vc4_test_lbm_size.c -+++ b/drivers/gpu/drm/vc4/tests/vc4_test_lbm_size.c -@@ -248,7 +248,7 @@ static void drm_vc4_test_vc4_lbm_size(st - ret = drm_atomic_check_only(state); - KUNIT_ASSERT_EQ(test, ret, 0); - -- KUNIT_EXPECT_EQ(test, vc4_plane_state->lbm.size, params->expected_lbm_size); -+ KUNIT_EXPECT_EQ(test, vc4_plane_state->lbm_size, params->expected_lbm_size); - - for (i = 0; i < 2; i++) { - KUNIT_EXPECT_EQ(test, ---- a/drivers/gpu/drm/vc4/vc4_drv.h -+++ b/drivers/gpu/drm/vc4/vc4_drv.h -@@ -417,6 +417,8 @@ struct vc4_plane_state { - u32 dlist_size; /* Number of dwords allocated for the display list */ - u32 dlist_count; /* Number of used dwords in the display list. */ - -+ u32 lbm_size; /* LBM requirements for this plane */ -+ - /* Offset in the dlist to various words, for pageflip or - * cursor updates. - */ -@@ -442,9 +444,6 @@ struct vc4_plane_state { - bool is_unity; - bool is_yuv; - -- /* Our allocation in LBM for temporary storage during scaling. */ -- struct drm_mm_node lbm; -- - /* Our allocation in UPM for prefetching. */ - struct drm_mm_node upm[DRM_FORMAT_MAX_PLANES]; - -@@ -635,6 +634,9 @@ struct vc4_crtc { - * access to that value. - */ - unsigned int current_hvs_channel; -+ -+ /* @lbm: Our allocation in LBM for temporary storage during scaling. */ -+ struct drm_mm_node lbm; - }; - - #define to_vc4_crtc(_crtc) \ ---- a/drivers/gpu/drm/vc4/vc4_hvs.c -+++ b/drivers/gpu/drm/vc4/vc4_hvs.c -@@ -1103,6 +1103,7 @@ int vc4_hvs_atomic_check(struct drm_crtc - struct drm_plane *plane; - const struct drm_plane_state *plane_state; - u32 dlist_count = 0; -+ u32 lbm_count = 0; - - /* The pixelvalve can only feed one encoder (and encoders are - * 1:1 with connectors.) -@@ -1111,6 +1112,8 @@ int vc4_hvs_atomic_check(struct drm_crtc - return -EINVAL; - - drm_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) { -+ const struct vc4_plane_state *vc4_plane_state = -+ to_vc4_plane_state(plane_state); - u32 plane_dlist_count = vc4_plane_dlist_size(plane_state); - - drm_dbg_driver(dev, "[CRTC:%d:%s] Found [PLANE:%d:%s] with DLIST size: %u\n", -@@ -1119,6 +1122,7 @@ int vc4_hvs_atomic_check(struct drm_crtc - plane_dlist_count); - - dlist_count += plane_dlist_count; -+ lbm_count += vc4_plane_state->lbm_size; - } - - dlist_count++; /* Account for SCALER_CTL0_END. */ -@@ -1132,6 +1136,8 @@ int vc4_hvs_atomic_check(struct drm_crtc - - vc4_state->mm = alloc; - -+ /* FIXME: Check total lbm allocation here */ -+ - return vc4_hvs_gamma_check(crtc, state); - } - -@@ -1246,7 +1252,10 @@ void vc4_hvs_atomic_flush(struct drm_crt - bool debug_dump_regs = false; - bool enable_bg_fill = false; - u32 __iomem *dlist_start, *dlist_next; -+ unsigned long irqflags; - unsigned int zpos = 0; -+ u32 lbm_offset = 0; -+ u32 lbm_size = 0; - bool found = false; - int idx; - -@@ -1265,6 +1274,35 @@ void vc4_hvs_atomic_flush(struct drm_crt - vc4_hvs_dump_state(hvs); - } - -+ drm_atomic_crtc_for_each_plane(plane, crtc) { -+ vc4_plane_state = to_vc4_plane_state(plane->state); -+ lbm_size += vc4_plane_state->lbm_size; -+ } -+ -+ if (drm_mm_node_allocated(&vc4_crtc->lbm)) { -+ spin_lock_irqsave(&vc4_crtc->irq_lock, irqflags); -+ drm_mm_remove_node(&vc4_crtc->lbm); -+ spin_unlock_irqrestore(&vc4_crtc->irq_lock, irqflags); -+ } -+ -+ if (lbm_size) { -+ int ret; -+ -+ spin_lock_irqsave(&vc4_crtc->irq_lock, irqflags); -+ ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm, -+ &vc4_crtc->lbm, -+ lbm_size, 1, -+ 0, 0); -+ spin_unlock_irqrestore(&vc4_crtc->irq_lock, irqflags); -+ -+ if (ret) { -+ pr_err("Failed to allocate LBM ret %d\n", ret); -+ return; -+ } -+ } -+ -+ lbm_offset = vc4_crtc->lbm.start; -+ - dlist_start = vc4->hvs->dlist + vc4_state->mm->mm_node.start; - dlist_next = dlist_start; - -@@ -1276,6 +1314,8 @@ void vc4_hvs_atomic_flush(struct drm_crt - if (plane->state->normalized_zpos != zpos) - continue; - -+ vc4_plane_state = to_vc4_plane_state(plane->state); -+ - /* Is this the first active plane? */ - if (dlist_next == dlist_start) { - /* We need to enable background fill when a plane -@@ -1286,10 +1326,15 @@ void vc4_hvs_atomic_flush(struct drm_crt - * already needs it or all planes on top blend from - * the first or a lower plane. - */ -- vc4_plane_state = to_vc4_plane_state(plane->state); - enable_bg_fill = vc4_plane_state->needs_bg_fill; - } - -+ if (vc4_plane_state->lbm_size) { -+ vc4_plane_state->dlist[vc4_plane_state->lbm_offset] = -+ lbm_offset; -+ lbm_offset += vc4_plane_state->lbm_size; -+ } -+ - dlist_next += vc4_plane_write_dlist(plane, dlist_next); - - found = true; ---- a/drivers/gpu/drm/vc4/vc4_plane.c -+++ b/drivers/gpu/drm/vc4/vc4_plane.c -@@ -288,7 +288,6 @@ struct drm_plane_state *vc4_plane_duplic - if (!vc4_state) - return NULL; - -- memset(&vc4_state->lbm, 0, sizeof(vc4_state->lbm)); - memset(&vc4_state->upm, 0, sizeof(vc4_state->upm)); - - for (i = 0; i < DRM_FORMAT_MAX_PLANES; i++) -@@ -320,14 +319,6 @@ void vc4_plane_destroy_state(struct drm_ - struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); - unsigned int i; - -- if (drm_mm_node_allocated(&vc4_state->lbm)) { -- unsigned long irqflags; -- -- spin_lock_irqsave(&hvs->mm_lock, irqflags); -- drm_mm_remove_node(&vc4_state->lbm); -- spin_unlock_irqrestore(&hvs->mm_lock, irqflags); -- } -- - for (i = 0; i < DRM_FORMAT_MAX_PLANES; i++) { - unsigned long irqflags; - -@@ -903,12 +894,13 @@ static int vc4_plane_allocate_lbm(struct - struct vc4_dev *vc4 = to_vc4_dev(drm); - struct drm_plane *plane = state->plane; - struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); -- unsigned long irqflags; - u32 lbm_size; - - lbm_size = vc4_lbm_size(state); -- if (!lbm_size) -+ if (!lbm_size) { -+ vc4_state->lbm_size = 0; - return 0; -+ } - - /* - * NOTE: BCM2712 doesn't need to be aligned, since the size -@@ -925,28 +917,10 @@ static int vc4_plane_allocate_lbm(struct - if (WARN_ON(!vc4_state->lbm_offset)) - return -EINVAL; - -- /* Allocate the LBM memory that the HVS will use for temporary -- * storage due to our scaling/format conversion. -+ /* FIXME: Add loop here that ensures that the total LBM assigned in this -+ * state is less than the total lbm size - */ -- if (!drm_mm_node_allocated(&vc4_state->lbm)) { -- int ret; -- -- spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags); -- ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm, -- &vc4_state->lbm, -- lbm_size, 1, -- 0, 0); -- spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags); -- -- if (ret) { -- drm_err(drm, "Failed to allocate LBM entry: %d\n", ret); -- return ret; -- } -- } else { -- WARN_ON_ONCE(lbm_size != vc4_state->lbm.size); -- } -- -- vc4_state->dlist[vc4_state->lbm_offset] = vc4_state->lbm.start; -+ vc4_state->lbm_size = lbm_size; - - return 0; - } diff --git a/target/linux/bcm27xx/patches-6.6/950-0655-vc4-drm-Remove-the-clear-of-SCALER_DISPBKGND_FILL.patch b/target/linux/bcm27xx/patches-6.6/950-0655-vc4-drm-Remove-the-clear-of-SCALER_DISPBKGND_FILL.patch index 67d8ae272651..fa57c12cf628 100644 --- a/target/linux/bcm27xx/patches-6.6/950-0655-vc4-drm-Remove-the-clear-of-SCALER_DISPBKGND_FILL.patch +++ b/target/linux/bcm27xx/patches-6.6/950-0655-vc4-drm-Remove-the-clear-of-SCALER_DISPBKGND_FILL.patch @@ -25,7 +25,7 @@ Signed-off-by: Dom Cobley --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c -@@ -1349,27 +1349,25 @@ void vc4_hvs_atomic_flush(struct drm_crt +@@ -1304,27 +1304,25 @@ void vc4_hvs_atomic_flush(struct drm_crt WARN_ON(!vc4_state->mm); WARN_ON_ONCE(dlist_next - dlist_start != vc4_state->mm->mm_node.size); diff --git a/target/linux/bcm27xx/patches-6.6/950-0675-drm-vc4-Correct-address-offset-for-planes-with-src_-.patch b/target/linux/bcm27xx/patches-6.6/950-0675-drm-vc4-Correct-address-offset-for-planes-with-src_-.patch index 9eb1ddad9396..30c6271bc6f1 100644 --- a/target/linux/bcm27xx/patches-6.6/950-0675-drm-vc4-Correct-address-offset-for-planes-with-src_-.patch +++ b/target/linux/bcm27xx/patches-6.6/950-0675-drm-vc4-Correct-address-offset-for-planes-with-src_-.patch @@ -22,7 +22,7 @@ Signed-off-by: Dave Stevenson --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c -@@ -1447,9 +1447,9 @@ static int vc4_plane_mode_set(struct drm +@@ -1473,9 +1473,9 @@ static int vc4_plane_mode_set(struct drm vc4_state->ptr0_offset[0] = vc4_state->dlist_count; for (i = 0; i < num_planes; i++) { @@ -34,7 +34,7 @@ Signed-off-by: Dave Stevenson } /* Pointer Context Word 0/1/2: Written by the HVS */ -@@ -1842,9 +1842,8 @@ static int vc6_plane_mode_set(struct drm +@@ -1868,9 +1868,8 @@ static int vc6_plane_mode_set(struct drm * TODO: This only covers Raster Scan Order planes */ for (i = 0; i < num_planes; i++) { diff --git a/target/linux/bcm27xx/patches-6.6/950-0711-drm-vc4-Add-hvs_dlist_allocs-debugfs-function.patch b/target/linux/bcm27xx/patches-6.6/950-0711-drm-vc4-Add-hvs_dlist_allocs-debugfs-function.patch index c04a5bb0e6d4..e8e93d5e80a8 100644 --- a/target/linux/bcm27xx/patches-6.6/950-0711-drm-vc4-Add-hvs_dlist_allocs-debugfs-function.patch +++ b/target/linux/bcm27xx/patches-6.6/950-0711-drm-vc4-Add-hvs_dlist_allocs-debugfs-function.patch @@ -50,7 +50,7 @@ Signed-off-by: Dave Stevenson /* The filter kernel is composed of dwords each containing 3 9-bit * signed integers packed next to each other. */ -@@ -1596,6 +1626,8 @@ int vc4_hvs_debugfs_init(struct drm_mino +@@ -1551,6 +1581,8 @@ int vc4_hvs_debugfs_init(struct drm_mino drm_debugfs_add_file(drm, "hvs_underrun", vc4_hvs_debugfs_underrun, NULL); diff --git a/target/linux/bcm27xx/patches-6.6/950-0738-drm-vc4-Drop-planes-that-are-completely-off-screen.patch b/target/linux/bcm27xx/patches-6.6/950-0738-drm-vc4-Drop-planes-that-are-completely-off-screen.patch index 321be130dc51..b8aa8dccfd59 100644 --- a/target/linux/bcm27xx/patches-6.6/950-0738-drm-vc4-Drop-planes-that-are-completely-off-screen.patch +++ b/target/linux/bcm27xx/patches-6.6/950-0738-drm-vc4-Drop-planes-that-are-completely-off-screen.patch @@ -25,7 +25,7 @@ Signed-off-by: Dave Stevenson --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c -@@ -1108,6 +1108,12 @@ static int vc4_plane_mode_set(struct drm +@@ -1134,6 +1134,12 @@ static int vc4_plane_mode_set(struct drm width = vc4_state->src_w[0] >> 16; height = vc4_state->src_h[0] >> 16; @@ -38,7 +38,7 @@ Signed-off-by: Dave Stevenson /* SCL1 is used for Cb/Cr scaling of planar formats. For RGB * and 4:4:4, scl1 should be set to scl0 so both channels of * the scaler do the same thing. For YUV, the Y plane needs -@@ -1623,6 +1629,12 @@ static int vc6_plane_mode_set(struct drm +@@ -1649,6 +1655,12 @@ static int vc6_plane_mode_set(struct drm width = vc4_state->src_w[0] >> 16; height = vc4_state->src_h[0] >> 16; @@ -51,7 +51,7 @@ Signed-off-by: Dave Stevenson /* SCL1 is used for Cb/Cr scaling of planar formats. For RGB * and 4:4:4, scl1 should be set to scl0 so both channels of * the scaler do the same thing. For YUV, the Y plane needs -@@ -1994,6 +2006,9 @@ int vc4_plane_atomic_check(struct drm_pl +@@ -2020,6 +2032,9 @@ int vc4_plane_atomic_check(struct drm_pl if (ret) return ret; diff --git a/target/linux/bcm27xx/patches-6.6/950-0740-drm-vc4-Free-the-dlist-alloc-immediately-if-it-never.patch b/target/linux/bcm27xx/patches-6.6/950-0740-drm-vc4-Free-the-dlist-alloc-immediately-if-it-never.patch index 3782d53e346b..dced86878d1e 100644 --- a/target/linux/bcm27xx/patches-6.6/950-0740-drm-vc4-Free-the-dlist-alloc-immediately-if-it-never.patch +++ b/target/linux/bcm27xx/patches-6.6/950-0740-drm-vc4-Free-the-dlist-alloc-immediately-if-it-never.patch @@ -23,7 +23,7 @@ Signed-off-by: Dave Stevenson --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h -@@ -667,6 +667,7 @@ struct vc4_hvs_dlist_allocation { +@@ -665,6 +665,7 @@ struct vc4_hvs_dlist_allocation { struct drm_mm_node mm_node; unsigned int channel; u8 target_frame_count; @@ -46,7 +46,7 @@ Signed-off-by: Dave Stevenson spin_lock_irqsave(&hvs->mm_lock, flags); vc4_hvs_free_dlist_entry_locked(hvs, alloc); spin_unlock_irqrestore(&hvs->mm_lock, flags); -@@ -1201,6 +1204,7 @@ static void vc4_hvs_install_dlist(struct +@@ -1195,6 +1198,7 @@ static void vc4_hvs_install_dlist(struct return; WARN_ON(!vc4_state->mm); diff --git a/target/linux/bcm27xx/patches-6.6/950-0763-drm-vc4-Mop-and-moplet-have-different-register-offse.patch b/target/linux/bcm27xx/patches-6.6/950-0763-drm-vc4-Mop-and-moplet-have-different-register-offse.patch index ccf84b313c99..2340240218e2 100644 --- a/target/linux/bcm27xx/patches-6.6/950-0763-drm-vc4-Mop-and-moplet-have-different-register-offse.patch +++ b/target/linux/bcm27xx/patches-6.6/950-0763-drm-vc4-Mop-and-moplet-have-different-register-offse.patch @@ -17,7 +17,7 @@ Signed-off-by: Dave Stevenson --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h -@@ -549,6 +549,7 @@ struct vc4_crtc_data { +@@ -550,6 +550,7 @@ struct vc4_crtc_data { struct vc4_txp_data { struct vc4_crtc_data base; enum vc4_encoder_type encoder_type; diff --git a/target/linux/bcm27xx/patches-6.6/950-0829-vc4-hvs-Add-support-for-D0-register-changes.patch b/target/linux/bcm27xx/patches-6.6/950-0829-vc4-hvs-Add-support-for-D0-register-changes.patch index 1bc75773b798..3d13a6a09c39 100644 --- a/target/linux/bcm27xx/patches-6.6/950-0829-vc4-hvs-Add-support-for-D0-register-changes.patch +++ b/target/linux/bcm27xx/patches-6.6/950-0829-vc4-hvs-Add-support-for-D0-register-changes.patch @@ -54,7 +54,7 @@ Signed-off-by: Dom Cobley unsigned int irq; -@@ -714,6 +715,12 @@ struct vc4_crtc_state { +@@ -712,6 +713,12 @@ struct vc4_crtc_state { writel(val, hvs->regs + (offset)); \ } while (0) @@ -244,7 +244,7 @@ Signed-off-by: Dom Cobley out: drm_dev_exit(idx); -@@ -1227,8 +1286,8 @@ static void vc4_hvs_install_dlist(struct +@@ -1221,8 +1280,8 @@ static void vc4_hvs_install_dlist(struct if (vc4->gen >= VC4_GEN_6) HVS_WRITE(SCALER6_DISPX_LPTRS(vc4_state->assigned_channel), @@ -255,7 +255,7 @@ Signed-off-by: Dom Cobley else HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel), vc4_state->mm->mm_node.start); -@@ -1427,11 +1486,11 @@ void vc4_hvs_atomic_flush(struct drm_crt +@@ -1382,11 +1441,11 @@ void vc4_hvs_atomic_flush(struct drm_crt if (enable_bg_fill) HVS_WRITE(SCALER6_DISPX_CTRL1(channel), HVS_READ(SCALER6_DISPX_CTRL1(channel)) | @@ -269,7 +269,7 @@ Signed-off-by: Dom Cobley } else { /* we can actually run with a lower core clock when background * fill is enabled on VC4_GEN_5 so leave it enabled always. -@@ -1701,7 +1760,7 @@ struct vc4_hvs *__vc4_hvs_alloc(struct v +@@ -1656,7 +1715,7 @@ struct vc4_hvs *__vc4_hvs_alloc(struct v * access a register. Use a plausible size then. */ if (!kunit_get_current_test()) @@ -278,7 +278,7 @@ Signed-off-by: Dom Cobley else dlist_size = 4096; -@@ -1935,14 +1994,17 @@ static int vc6_hvs_hw_init(struct vc4_hv +@@ -1890,14 +1949,17 @@ static int vc6_hvs_hw_init(struct vc4_hv const struct vc6_csc_coeff_entry *coeffs; unsigned int i; @@ -300,7 +300,7 @@ Signed-off-by: Dom Cobley for (i = 0; i < 6; i++) { coeffs = &csc_coeffs[i / 3][i % 3]; -@@ -2041,21 +2103,21 @@ static int vc4_hvs_cob_init(struct vc4_h +@@ -1996,21 +2058,21 @@ static int vc4_hvs_cob_init(struct vc4_h reg = 0; top = 3840; @@ -325,7 +325,7 @@ Signed-off-by: Dom Cobley VC4_SET_FIELD(top, SCALER6_DISPX_COB_TOP) | VC4_SET_FIELD(base, SCALER6_DISPX_COB_BASE)); break; -@@ -2086,7 +2148,10 @@ static int vc4_hvs_bind(struct device *d +@@ -2041,7 +2103,10 @@ static int vc4_hvs_bind(struct device *d hvs->regset.base = hvs->regs; @@ -337,7 +337,7 @@ Signed-off-by: Dom Cobley hvs->regset.regs = vc6_hvs_regs; hvs->regset.nregs = ARRAY_SIZE(vc6_hvs_regs); } else { -@@ -2253,6 +2318,7 @@ static void vc4_hvs_dev_remove(struct pl +@@ -2208,6 +2273,7 @@ static void vc4_hvs_dev_remove(struct pl static const struct of_device_id vc4_hvs_dt_match[] = { { .compatible = "brcm,bcm2711-hvs" }, { .compatible = "brcm,bcm2712-hvs" }, diff --git a/target/linux/bcm27xx/patches-6.6/950-0830-vc4-hvs-Updates-to-support-D0-alpha-and-csc-changes.patch b/target/linux/bcm27xx/patches-6.6/950-0830-vc4-hvs-Updates-to-support-D0-alpha-and-csc-changes.patch index 0a38601048fe..d88e6a744cda 100644 --- a/target/linux/bcm27xx/patches-6.6/950-0830-vc4-hvs-Updates-to-support-D0-alpha-and-csc-changes.patch +++ b/target/linux/bcm27xx/patches-6.6/950-0830-vc4-hvs-Updates-to-support-D0-alpha-and-csc-changes.patch @@ -16,7 +16,7 @@ Signed-off-by: Dom Cobley --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c -@@ -1933,6 +1933,17 @@ static int vc4_hvs_hw_init(struct vc4_hv +@@ -1888,6 +1888,17 @@ static int vc4_hvs_hw_init(struct vc4_hv #define CFC1_N_MA_CSC_COEFF_C23(x) (0xa03c + ((x) * 0x3000)) #define CFC1_N_MA_CSC_COEFF_C24(x) (0xa040 + ((x) * 0x3000)) @@ -34,7 +34,7 @@ Signed-off-by: Dom Cobley /* 4 S2.22 multiplication factors, and 1 S9.15 addititive element for each of 3 * output components */ -@@ -2003,31 +2014,43 @@ static int vc6_hvs_hw_init(struct vc4_hv +@@ -1958,31 +1969,43 @@ static int vc6_hvs_hw_init(struct vc4_hv HVS_WRITE(SCALER6(PRI_MAP0), 0xffffffff); HVS_WRITE(SCALER6(PRI_MAP1), 0xffffffff); @@ -104,7 +104,7 @@ Signed-off-by: Dom Cobley return 0; --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c -@@ -1054,6 +1054,12 @@ static u32 vc4_hvs5_get_alpha_blend_mode +@@ -1080,6 +1080,12 @@ static u32 vc4_hvs5_get_alpha_blend_mode WARN_ON_ONCE(vc4->gen != VC4_GEN_5 && vc4->gen != VC4_GEN_6); @@ -117,7 +117,7 @@ Signed-off-by: Dom Cobley if (!state->fb->format->has_alpha) return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_FIXED, SCALER5_CTL2_ALPHA_MODE); -@@ -1569,14 +1575,13 @@ static int vc4_plane_mode_set(struct drm +@@ -1595,14 +1601,13 @@ static int vc4_plane_mode_set(struct drm static u32 vc6_plane_get_csc_mode(struct vc4_plane_state *vc4_state) { struct drm_plane_state *state = &vc4_state->base; @@ -133,7 +133,7 @@ Signed-off-by: Dom Cobley /* CSC pre-loaded with: * 0 = BT601 limited range * 1 = BT709 limited range -@@ -1590,8 +1595,15 @@ static u32 vc6_plane_get_csc_mode(struct +@@ -1616,8 +1621,15 @@ static u32 vc6_plane_get_csc_mode(struct if (color_range > DRM_COLOR_YCBCR_FULL_RANGE) color_range = DRM_COLOR_YCBCR_LIMITED_RANGE; diff --git a/target/linux/bcm27xx/patches-6.6/950-0833-drm-vc4-Add-2712-support-to-vc4_plane_async_set_fb.patch b/target/linux/bcm27xx/patches-6.6/950-0833-drm-vc4-Add-2712-support-to-vc4_plane_async_set_fb.patch index 46a66f4c59de..423e5b63c941 100644 --- a/target/linux/bcm27xx/patches-6.6/950-0833-drm-vc4-Add-2712-support-to-vc4_plane_async_set_fb.patch +++ b/target/linux/bcm27xx/patches-6.6/950-0833-drm-vc4-Add-2712-support-to-vc4_plane_async_set_fb.patch @@ -17,7 +17,7 @@ Signed-off-by: Dave Stevenson --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c -@@ -1877,7 +1877,7 @@ static int vc6_plane_mode_set(struct drm +@@ -1903,7 +1903,7 @@ static int vc6_plane_mode_set(struct drm * The UPM buffer will be allocated in * vc6_plane_allocate_upm(). */ @@ -26,7 +26,7 @@ Signed-off-by: Dave Stevenson SCALER6_PTR0_UPPER_ADDR)); /* Pointer Word 1 */ -@@ -2079,7 +2079,8 @@ void vc4_plane_async_set_fb(struct drm_p +@@ -2105,7 +2105,8 @@ void vc4_plane_async_set_fb(struct drm_p { struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state); struct drm_gem_dma_object *bo = drm_fb_dma_get_gem_obj(fb, 0); @@ -36,7 +36,7 @@ Signed-off-by: Dave Stevenson int idx; if (!drm_dev_enter(plane->dev, &idx)) -@@ -2089,19 +2090,38 @@ void vc4_plane_async_set_fb(struct drm_p +@@ -2115,19 +2116,38 @@ void vc4_plane_async_set_fb(struct drm_p * because this is only called on the primary plane. */ WARN_ON_ONCE(plane->state->crtc_x < 0 || plane->state->crtc_y < 0); diff --git a/target/linux/bcm27xx/patches-6.6/950-0834-drm-vc4-Fix-atomic_async_check-to-call-the-right-mod.patch b/target/linux/bcm27xx/patches-6.6/950-0834-drm-vc4-Fix-atomic_async_check-to-call-the-right-mod.patch index 07a36b16928c..49d2129c8419 100644 --- a/target/linux/bcm27xx/patches-6.6/950-0834-drm-vc4-Fix-atomic_async_check-to-call-the-right-mod.patch +++ b/target/linux/bcm27xx/patches-6.6/950-0834-drm-vc4-Fix-atomic_async_check-to-call-the-right-mod.patch @@ -19,7 +19,7 @@ Signed-off-by: Dave Stevenson --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c -@@ -2205,11 +2205,15 @@ static int vc4_plane_atomic_async_check( +@@ -2231,11 +2231,15 @@ static int vc4_plane_atomic_async_check( { struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); diff --git a/target/linux/bcm27xx/patches-6.6/950-0884-drm-vc4-Drop-planes-that-have-0-destination-size.patch b/target/linux/bcm27xx/patches-6.6/950-0884-drm-vc4-Drop-planes-that-have-0-destination-size.patch index 3e4bed22d4a4..3796a923a8e6 100644 --- a/target/linux/bcm27xx/patches-6.6/950-0884-drm-vc4-Drop-planes-that-have-0-destination-size.patch +++ b/target/linux/bcm27xx/patches-6.6/950-0884-drm-vc4-Drop-planes-that-have-0-destination-size.patch @@ -16,7 +16,7 @@ Signed-off-by: Dave Stevenson --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c -@@ -1114,7 +1114,7 @@ static int vc4_plane_mode_set(struct drm +@@ -1140,7 +1140,7 @@ static int vc4_plane_mode_set(struct drm width = vc4_state->src_w[0] >> 16; height = vc4_state->src_h[0] >> 16; @@ -25,7 +25,7 @@ Signed-off-by: Dave Stevenson /* 0 source size probably means the plane is offscreen */ vc4_state->dlist_initialized = 1; return 0; -@@ -1641,8 +1641,10 @@ static int vc6_plane_mode_set(struct drm +@@ -1667,8 +1667,10 @@ static int vc6_plane_mode_set(struct drm width = vc4_state->src_w[0] >> 16; height = vc4_state->src_h[0] >> 16; @@ -38,7 +38,7 @@ Signed-off-by: Dave Stevenson vc4_state->dlist_initialized = 1; return 0; } -@@ -2018,7 +2020,8 @@ int vc4_plane_atomic_check(struct drm_pl +@@ -2044,7 +2046,8 @@ int vc4_plane_atomic_check(struct drm_pl if (ret) return ret; diff --git a/target/linux/bcm27xx/patches-6.6/950-0885-vc4-hvs-Support-fixed-alpha-correctly-on-2712D0.patch b/target/linux/bcm27xx/patches-6.6/950-0885-vc4-hvs-Support-fixed-alpha-correctly-on-2712D0.patch index 0100b20df538..3147ac297f26 100644 --- a/target/linux/bcm27xx/patches-6.6/950-0885-vc4-hvs-Support-fixed-alpha-correctly-on-2712D0.patch +++ b/target/linux/bcm27xx/patches-6.6/950-0885-vc4-hvs-Support-fixed-alpha-correctly-on-2712D0.patch @@ -16,7 +16,7 @@ Signed-off-by: Dom Cobley --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c -@@ -1079,6 +1079,21 @@ static u32 vc4_hvs5_get_alpha_blend_mode +@@ -1105,6 +1105,21 @@ static u32 vc4_hvs5_get_alpha_blend_mode } } @@ -38,7 +38,7 @@ Signed-off-by: Dom Cobley /* Writes out a full display list for an active plane to the plane's * private dlist state. */ -@@ -1824,7 +1839,7 @@ static int vc6_plane_mode_set(struct drm +@@ -1850,7 +1865,7 @@ static int vc6_plane_mode_set(struct drm vc4_dlist_write(vc4_state, SCALER6_CTL0_VALID | VC4_SET_FIELD(tiling, SCALER6_CTL0_ADDR_MODE) | diff --git a/target/linux/bcm27xx/patches-6.6/950-0902-vc4-hvs-Fix-lbm-size-calculation-for-yuv.patch b/target/linux/bcm27xx/patches-6.6/950-0902-vc4-hvs-Fix-lbm-size-calculation-for-yuv.patch index 12f762ac91f8..80724fd6ef19 100644 --- a/target/linux/bcm27xx/patches-6.6/950-0902-vc4-hvs-Fix-lbm-size-calculation-for-yuv.patch +++ b/target/linux/bcm27xx/patches-6.6/950-0902-vc4-hvs-Fix-lbm-size-calculation-for-yuv.patch @@ -18,7 +18,7 @@ Signed-off-by: Dom Cobley --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c -@@ -733,7 +733,7 @@ static unsigned int vc4_lbm_channel_size +@@ -742,7 +742,7 @@ static unsigned int vc4_lbm_channel_size if (!components) return 0; diff --git a/target/linux/bcm27xx/patches-6.6/950-0989-drm-vc4-Enable-bg_fill-if-there-are-no-planes-enable.patch b/target/linux/bcm27xx/patches-6.6/950-0989-drm-vc4-Enable-bg_fill-if-there-are-no-planes-enable.patch index addbb3691f08..10d7f571194f 100644 --- a/target/linux/bcm27xx/patches-6.6/950-0989-drm-vc4-Enable-bg_fill-if-there-are-no-planes-enable.patch +++ b/target/linux/bcm27xx/patches-6.6/950-0989-drm-vc4-Enable-bg_fill-if-there-are-no-planes-enable.patch @@ -19,12 +19,12 @@ Signed-off-by: Dave Stevenson --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c -@@ -1406,7 +1406,7 @@ void vc4_hvs_atomic_flush(struct drm_crt +@@ -1400,7 +1400,7 @@ void vc4_hvs_atomic_flush(struct drm_crt struct drm_plane *plane; struct vc4_plane_state *vc4_plane_state; bool debug_dump_regs = false; - bool enable_bg_fill = false; + bool enable_bg_fill = true; u32 __iomem *dlist_start, *dlist_next; - unsigned long irqflags; unsigned int zpos = 0; + bool found = false; diff --git a/target/linux/bcm27xx/patches-6.6/950-1065-drm-vc4-Add-option-to-call-from-crtc-to-encoder-on-v.patch b/target/linux/bcm27xx/patches-6.6/950-1065-drm-vc4-Add-option-to-call-from-crtc-to-encoder-on-v.patch index 8137b10592d3..d806631555f7 100644 --- a/target/linux/bcm27xx/patches-6.6/950-1065-drm-vc4-Add-option-to-call-from-crtc-to-encoder-on-v.patch +++ b/target/linux/bcm27xx/patches-6.6/950-1065-drm-vc4-Add-option-to-call-from-crtc-to-encoder-on-v.patch @@ -50,7 +50,7 @@ Signed-off-by: Dave Stevenson } --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h -@@ -503,6 +503,7 @@ struct vc4_encoder { +@@ -504,6 +504,7 @@ struct vc4_encoder { void (*post_crtc_disable)(struct drm_encoder *encoder, struct drm_atomic_state *state); void (*post_crtc_powerdown)(struct drm_encoder *encoder, struct drm_atomic_state *state); diff --git a/target/linux/bcm27xx/patches-6.6/950-1115-mmc-sd-halt-CQHCI-before-issuing-a-cache-flush-comma.patch b/target/linux/bcm27xx/patches-6.6/950-1115-mmc-sd-halt-CQHCI-before-issuing-a-cache-flush-comma.patch deleted file mode 100644 index 3f01a7ba09cb..000000000000 --- a/target/linux/bcm27xx/patches-6.6/950-1115-mmc-sd-halt-CQHCI-before-issuing-a-cache-flush-comma.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 8e40644b272a4ddc9d3b58b4373dffcef02d1b63 Mon Sep 17 00:00:00 2001 -From: Jonathan Bell -Date: Tue, 4 Jun 2024 13:21:47 +0100 -Subject: [PATCH 1115/1135] mmc: sd: halt CQHCI before issuing a cache flush - command - -SD cards perform cache flushes by a CMD49 extension register write - -which needs to be started from the SDHCI command/argument registers and -not a CQHCI slot. - -Host access to SD/CQ registers should be exclusive to one or the other, -so issue a halt before doing the command. - -Signed-off-by: Jonathan Bell ---- - drivers/mmc/core/sd.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - ---- a/drivers/mmc/core/sd.c -+++ b/drivers/mmc/core/sd.c -@@ -1265,6 +1265,14 @@ static int sd_flush_cache(struct mmc_hos - reg_buf = card->ext_reg_buf; - - /* -+ * Flushing requires sending CMD49 (adtc), which can't be done as a DCMD -+ * and conflicts with CQHCI - temporarily turn CQE off to use the SDHCI -+ * command/argument registers. -+ */ -+ if (host->cqe_on) -+ host->cqe_ops->cqe_off(host); -+ -+ /* - * Set Flush Cache at bit 0 in the performance enhancement register at - * 261 bytes offset. - */ diff --git a/target/linux/bcm27xx/patches-6.6/950-1168-fixup-mmc-restrict-posted-write-counts-for-SD-cards-.patch b/target/linux/bcm27xx/patches-6.6/950-1168-fixup-mmc-restrict-posted-write-counts-for-SD-cards-.patch index 4f1d02c74dac..b4f30b4b3c46 100644 --- a/target/linux/bcm27xx/patches-6.6/950-1168-fixup-mmc-restrict-posted-write-counts-for-SD-cards-.patch +++ b/target/linux/bcm27xx/patches-6.6/950-1168-fixup-mmc-restrict-posted-write-counts-for-SD-cards-.patch @@ -60,7 +60,7 @@ Signed-off-by: Jonathan Bell } card->ext_perf.fno = fno; -@@ -1383,6 +1384,7 @@ retry: +@@ -1375,6 +1376,7 @@ retry: card->ocr = ocr; card->type = MMC_TYPE_SD; diff --git a/target/linux/bcm27xx/patches-6.6/950-1199-drm-vc4-Disable-the-2pixel-clock-odd-timings-workaro.patch b/target/linux/bcm27xx/patches-6.6/950-1199-drm-vc4-Disable-the-2pixel-clock-odd-timings-workaro.patch index 78806c2b155b..ea64afd5f9fd 100644 --- a/target/linux/bcm27xx/patches-6.6/950-1199-drm-vc4-Disable-the-2pixel-clock-odd-timings-workaro.patch +++ b/target/linux/bcm27xx/patches-6.6/950-1199-drm-vc4-Disable-the-2pixel-clock-odd-timings-workaro.patch @@ -135,7 +135,7 @@ Signed-off-by: Dave Stevenson }, --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h -@@ -569,6 +569,8 @@ struct vc4_pv_data { +@@ -570,6 +570,8 @@ struct vc4_pv_data { /* Number of pixels output per clock period */ u8 pixels_per_clock; diff --git a/target/linux/bcm27xx/patches-6.6/950-1218-Bluetooth-hci_sync-Fix-crash-on-NULL-parent.patch b/target/linux/bcm27xx/patches-6.6/950-1218-Bluetooth-hci_sync-Fix-crash-on-NULL-parent.patch new file mode 100644 index 000000000000..272f711e632d --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1218-Bluetooth-hci_sync-Fix-crash-on-NULL-parent.patch @@ -0,0 +1,27 @@ +From ad2babc6596ba4f500454a4eaa607f3b49fcbcbe Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 7 Aug 2024 17:41:31 +0100 +Subject: [PATCH 1218/1350] Bluetooth: hci_sync: Fix crash on NULL parent + +Although later functions can handle a NULL fwnode, fwnode can't handle +being passed a NULL pointer. + +See: https://github.com/raspberrypi/linux/issues/6305 + +Signed-off-by: Phil Elwell +--- + net/bluetooth/hci_sync.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/net/bluetooth/hci_sync.c ++++ b/net/bluetooth/hci_sync.c +@@ -4861,7 +4861,8 @@ static const struct { + */ + static int hci_dev_setup_sync(struct hci_dev *hdev) + { +- struct fwnode_handle *fwnode = dev_fwnode(hdev->dev.parent); ++ struct fwnode_handle *fwnode = ++ hdev->dev.parent ? dev_fwnode(hdev->dev.parent) : NULL; + int ret = 0; + bool invalid_bdaddr; + size_t i; diff --git a/target/linux/bcm27xx/patches-6.6/950-1219-overlays-add-overlay-for-generic-I2S-clock-master-DA.patch b/target/linux/bcm27xx/patches-6.6/950-1219-overlays-add-overlay-for-generic-I2S-clock-master-DA.patch new file mode 100644 index 000000000000..8fbde277ef7c --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1219-overlays-add-overlay-for-generic-I2S-clock-master-DA.patch @@ -0,0 +1,96 @@ +From 209e8a3e6646f25abb352fd5a8a4c2e855b1e952 Mon Sep 17 00:00:00 2001 +From: Adrian Figueroa +Date: Wed, 14 Aug 2024 20:00:12 +0200 +Subject: [PATCH 1219/1350] overlays: add overlay for generic I2S clock-master + DAC + +Adds an overlay for supporting a generic I2S DAC that +acts as the clock master on the bus. +The data format is 32 bit stereo. + +Signed-off-by: Adrian Figueroa +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 6 +++ + .../dts/overlays/i2s-master-dac-overlay.dts | 50 +++++++++++++++++++ + 3 files changed, 57 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/i2s-master-dac-overlay.dts + +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -125,6 +125,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + i2c6.dtbo \ + i2s-dac.dtbo \ + i2s-gpio28-31.dtbo \ ++ i2s-master-dac.dtbo \ + ilitek251x.dtbo \ + imx219.dtbo \ + imx258.dtbo \ +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -2633,6 +2633,12 @@ Load: dtoverlay=i2s-gpio28-31 + Params: + + ++Name: i2s-master-dac ++Info: Configures a generic I2S DAC soundcard that acts as a clock master. ++Load: dtoverlay=i2s-master-dac ++Params: ++ ++ + Name: ilitek251x + Info: Enables I2C connected Ilitek 251x multiple touch controller using + GPIO 4 (pin 7 on GPIO header) for interrupt. +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/i2s-master-dac-overlay.dts +@@ -0,0 +1,50 @@ ++// Definitions for a generic I2S DAC that acts as clock master on the bus. ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&i2s_clk_consumer>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target-path = "/"; ++ __overlay__ { ++ codec_bare: codec_bare { ++ compatible = "linux,spdif-dit"; ++ #sound-dai-cells = <0>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&sound>; ++ __overlay__ { ++ compatible = "simple-audio-card"; ++ i2s-controller = <&i2s_clk_consumer>; ++ status = "okay"; ++ ++ simple-audio-card,name = "i2s-master-dac"; ++ simple-audio-card,format = "i2s"; ++ ++ simple-audio-card,bitclock-master = <&snd_codec>; ++ simple-audio-card,frame-master = <&snd_codec>; ++ ++ simple-audio-card,cpu { ++ sound-dai = <&i2s_clk_consumer>; ++ dai-tdm-slot-num = <2>; ++ dai-tdm-slot-width = <32>; ++ }; ++ ++ snd_codec: simple-audio-card,codec { ++ sound-dai = <&codec_bare>; ++ }; ++ }; ++ }; ++}; diff --git a/target/linux/bcm27xx/patches-6.6/950-1220-ASoC-DACplusADCPro-put-ADC-control-definitions-in-he.patch b/target/linux/bcm27xx/patches-6.6/950-1220-ASoC-DACplusADCPro-put-ADC-control-definitions-in-he.patch new file mode 100644 index 000000000000..6de452829c01 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1220-ASoC-DACplusADCPro-put-ADC-control-definitions-in-he.patch @@ -0,0 +1,275 @@ +From 15ca476264094b25d0a210109a061192a468117b Mon Sep 17 00:00:00 2001 +From: j-schambacher +Date: Thu, 15 Aug 2024 16:08:14 +0200 +Subject: [PATCH 1220/1350] ASoC: DACplusADCPro - put ADC control definitions + in header file + +For easier maintenance all ADC ALSA-Kcontrols and the respective +definitions are placed into a new header file that is included +by the existing DAC+ADC Pro driver and a new, soon to be +released ADC only board driver using the same controls. + +Signed-off-by: j-schambacher +--- + sound/soc/bcm/hifiberry_adc_controls.h | 128 ++++++++++++++++++++++++ + sound/soc/bcm/hifiberry_dacplusadcpro.c | 110 +------------------- + 2 files changed, 129 insertions(+), 109 deletions(-) + create mode 100644 sound/soc/bcm/hifiberry_adc_controls.h + +--- /dev/null ++++ b/sound/soc/bcm/hifiberry_adc_controls.h +@@ -0,0 +1,128 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * ALSA mixer/Kcontrol definitions common to HiFiBerry ADCs ++ * ++ * used by DAC+ADC Pro (hifiberry_dacplusadcpro.c), ++ * ADC (hifiberry_adc.c) ++ * ++ * Author: Joerg Schambacher ++ * Copyright 2024 ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ */ ++ ++static const unsigned int pcm186x_adc_input_channel_sel_value[] = { ++ 0x00, 0x01, 0x02, 0x03, 0x10 ++}; ++ ++static const char * const pcm186x_adcl_input_channel_sel_text[] = { ++ "No Select", ++ "VINL1[SE]", /* Default for ADCL */ ++ "VINL2[SE]", ++ "VINL2[SE] + VINL1[SE]", ++ "{VIN1P, VIN1M}[DIFF]" ++}; ++ ++static const char * const pcm186x_adcr_input_channel_sel_text[] = { ++ "No Select", ++ "VINR1[SE]", /* Default for ADCR */ ++ "VINR2[SE]", ++ "VINR2[SE] + VINR1[SE]", ++ "{VIN2P, VIN2M}[DIFF]" ++}; ++ ++static const struct soc_enum pcm186x_adc_input_channel_sel[] = { ++ SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_L, 0, ++ PCM186X_ADC_INPUT_SEL_MASK, ++ ARRAY_SIZE(pcm186x_adcl_input_channel_sel_text), ++ pcm186x_adcl_input_channel_sel_text, ++ pcm186x_adc_input_channel_sel_value), ++ SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_R, 0, ++ PCM186X_ADC_INPUT_SEL_MASK, ++ ARRAY_SIZE(pcm186x_adcr_input_channel_sel_text), ++ pcm186x_adcr_input_channel_sel_text, ++ pcm186x_adc_input_channel_sel_value), ++}; ++ ++static const unsigned int pcm186x_mic_bias_sel_value[] = { ++ 0x00, 0x01, 0x11 ++}; ++ ++static const char * const pcm186x_mic_bias_sel_text[] = { ++ "Mic Bias off", ++ "Mic Bias on", ++ "Mic Bias with Bypass Resistor" ++}; ++ ++static const struct soc_enum pcm186x_mic_bias_sel[] = { ++ SOC_VALUE_ENUM_SINGLE(PCM186X_MIC_BIAS_CTRL, 0, ++ GENMASK(4, 0), ++ ARRAY_SIZE(pcm186x_mic_bias_sel_text), ++ pcm186x_mic_bias_sel_text, ++ pcm186x_mic_bias_sel_value), ++}; ++ ++static const unsigned int pcm186x_gain_sel_value[] = { ++ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, ++ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, ++ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, ++ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, ++ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, ++ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, ++ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, ++ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, ++ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, ++ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, ++ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, ++ 0x50 ++}; ++ ++static const char * const pcm186x_gain_sel_text[] = { ++ "-12.0dB", "-11.5dB", "-11.0dB", "-10.5dB", "-10.0dB", "-9.5dB", ++ "-9.0dB", "-8.5dB", "-8.0dB", "-7.5dB", "-7.0dB", "-6.5dB", ++ "-6.0dB", "-5.5dB", "-5.0dB", "-4.5dB", "-4.0dB", "-3.5dB", ++ "-3.0dB", "-2.5dB", "-2.0dB", "-1.5dB", "-1.0dB", "-0.5dB", ++ "0.0dB", "0.5dB", "1.0dB", "1.5dB", "2.0dB", "2.5dB", ++ "3.0dB", "3.5dB", "4.0dB", "4.5dB", "5.0dB", "5.5dB", ++ "6.0dB", "6.5dB", "7.0dB", "7.5dB", "8.0dB", "8.5dB", ++ "9.0dB", "9.5dB", "10.0dB", "10.5dB", "11.0dB", "11.5dB", ++ "12.0dB", "12.5dB", "13.0dB", "13.5dB", "14.0dB", "14.5dB", ++ "15.0dB", "15.5dB", "16.0dB", "16.5dB", "17.0dB", "17.5dB", ++ "18.0dB", "18.5dB", "19.0dB", "19.5dB", "20.0dB", "20.5dB", ++ "21.0dB", "21.5dB", "22.0dB", "22.5dB", "23.0dB", "23.5dB", ++ "24.0dB", "24.5dB", "25.0dB", "25.5dB", "26.0dB", "26.5dB", ++ "27.0dB", "27.5dB", "28.0dB", "28.5dB", "29.0dB", "29.5dB", ++ "30.0dB", "30.5dB", "31.0dB", "31.5dB", "32.0dB", "32.5dB", ++ "33.0dB", "33.5dB", "34.0dB", "34.5dB", "35.0dB", "35.5dB", ++ "36.0dB", "36.5dB", "37.0dB", "37.5dB", "38.0dB", "38.5dB", ++ "39.0dB", "39.5dB", "40.0dB"}; ++ ++static const struct soc_enum pcm186x_gain_sel[] = { ++ SOC_VALUE_ENUM_SINGLE(PCM186X_PGA_VAL_CH1_L, 0, ++ 0xff, ++ ARRAY_SIZE(pcm186x_gain_sel_text), ++ pcm186x_gain_sel_text, ++ pcm186x_gain_sel_value), ++ SOC_VALUE_ENUM_SINGLE(PCM186X_PGA_VAL_CH1_R, 0, ++ 0xff, ++ ARRAY_SIZE(pcm186x_gain_sel_text), ++ pcm186x_gain_sel_text, ++ pcm186x_gain_sel_value), ++}; ++ ++static const struct snd_kcontrol_new pcm1863_snd_controls_card[] = { ++ SOC_ENUM("ADC Left Input", pcm186x_adc_input_channel_sel[0]), ++ SOC_ENUM("ADC Right Input", pcm186x_adc_input_channel_sel[1]), ++ SOC_ENUM("ADC Mic Bias", pcm186x_mic_bias_sel), ++ SOC_ENUM("PGA Gain Left", pcm186x_gain_sel[0]), ++ SOC_ENUM("PGA Gain Right", pcm186x_gain_sel[1]), ++}; +--- a/sound/soc/bcm/hifiberry_dacplusadcpro.c ++++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c +@@ -37,6 +37,7 @@ + + #include "../codecs/pcm512x.h" + #include "../codecs/pcm186x.h" ++#include "hifiberry_adc_controls.h" + + #define HIFIBERRY_DACPRO_NOCLOCK 0 + #define HIFIBERRY_DACPRO_CLK44EN 1 +@@ -57,115 +58,6 @@ static bool snd_rpi_hifiberry_is_dacpro; + static bool digital_gain_0db_limit = true; + static bool leds_off; + +-static const unsigned int pcm186x_adc_input_channel_sel_value[] = { +- 0x00, 0x01, 0x02, 0x03, 0x10 +-}; +- +-static const char * const pcm186x_adcl_input_channel_sel_text[] = { +- "No Select", +- "VINL1[SE]", /* Default for ADCL */ +- "VINL2[SE]", +- "VINL2[SE] + VINL1[SE]", +- "{VIN1P, VIN1M}[DIFF]" +-}; +- +-static const char * const pcm186x_adcr_input_channel_sel_text[] = { +- "No Select", +- "VINR1[SE]", /* Default for ADCR */ +- "VINR2[SE]", +- "VINR2[SE] + VINR1[SE]", +- "{VIN2P, VIN2M}[DIFF]" +-}; +- +-static const struct soc_enum pcm186x_adc_input_channel_sel[] = { +- SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_L, 0, +- PCM186X_ADC_INPUT_SEL_MASK, +- ARRAY_SIZE(pcm186x_adcl_input_channel_sel_text), +- pcm186x_adcl_input_channel_sel_text, +- pcm186x_adc_input_channel_sel_value), +- SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_R, 0, +- PCM186X_ADC_INPUT_SEL_MASK, +- ARRAY_SIZE(pcm186x_adcr_input_channel_sel_text), +- pcm186x_adcr_input_channel_sel_text, +- pcm186x_adc_input_channel_sel_value), +-}; +- +-static const unsigned int pcm186x_mic_bias_sel_value[] = { +- 0x00, 0x01, 0x11 +-}; +- +-static const char * const pcm186x_mic_bias_sel_text[] = { +- "Mic Bias off", +- "Mic Bias on", +- "Mic Bias with Bypass Resistor" +-}; +- +-static const struct soc_enum pcm186x_mic_bias_sel[] = { +- SOC_VALUE_ENUM_SINGLE(PCM186X_MIC_BIAS_CTRL, 0, +- GENMASK(4, 0), +- ARRAY_SIZE(pcm186x_mic_bias_sel_text), +- pcm186x_mic_bias_sel_text, +- pcm186x_mic_bias_sel_value), +-}; +- +-static const unsigned int pcm186x_gain_sel_value[] = { +- 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, +- 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, +- 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, +- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, +- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, +- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, +- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, +- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, +- 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, +- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, +- 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, +- 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, +- 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, +- 0x50 +-}; +- +-static const char * const pcm186x_gain_sel_text[] = { +- "-12.0dB", "-11.5dB", "-11.0dB", "-10.5dB", "-10.0dB", "-9.5dB", +- "-9.0dB", "-8.5dB", "-8.0dB", "-7.5dB", "-7.0dB", "-6.5dB", +- "-6.0dB", "-5.5dB", "-5.0dB", "-4.5dB", "-4.0dB", "-3.5dB", +- "-3.0dB", "-2.5dB", "-2.0dB", "-1.5dB", "-1.0dB", "-0.5dB", +- "0.0dB", "0.5dB", "1.0dB", "1.5dB", "2.0dB", "2.5dB", +- "3.0dB", "3.5dB", "4.0dB", "4.5dB", "5.0dB", "5.5dB", +- "6.0dB", "6.5dB", "7.0dB", "7.5dB", "8.0dB", "8.5dB", +- "9.0dB", "9.5dB", "10.0dB", "10.5dB", "11.0dB", "11.5dB", +- "12.0dB", "12.5dB", "13.0dB", "13.5dB", "14.0dB", "14.5dB", +- "15.0dB", "15.5dB", "16.0dB", "16.5dB", "17.0dB", "17.5dB", +- "18.0dB", "18.5dB", "19.0dB", "19.5dB", "20.0dB", "20.5dB", +- "21.0dB", "21.5dB", "22.0dB", "22.5dB", "23.0dB", "23.5dB", +- "24.0dB", "24.5dB", "25.0dB", "25.5dB", "26.0dB", "26.5dB", +- "27.0dB", "27.5dB", "28.0dB", "28.5dB", "29.0dB", "29.5dB", +- "30.0dB", "30.5dB", "31.0dB", "31.5dB", "32.0dB", "32.5dB", +- "33.0dB", "33.5dB", "34.0dB", "34.5dB", "35.0dB", "35.5dB", +- "36.0dB", "36.5dB", "37.0dB", "37.5dB", "38.0dB", "38.5dB", +- "39.0dB", "39.5dB", "40.0dB"}; +- +-static const struct soc_enum pcm186x_gain_sel[] = { +- SOC_VALUE_ENUM_SINGLE(PCM186X_PGA_VAL_CH1_L, 0, +- 0xff, +- ARRAY_SIZE(pcm186x_gain_sel_text), +- pcm186x_gain_sel_text, +- pcm186x_gain_sel_value), +- SOC_VALUE_ENUM_SINGLE(PCM186X_PGA_VAL_CH1_R, 0, +- 0xff, +- ARRAY_SIZE(pcm186x_gain_sel_text), +- pcm186x_gain_sel_text, +- pcm186x_gain_sel_value), +-}; +- +-static const struct snd_kcontrol_new pcm1863_snd_controls_card[] = { +- SOC_ENUM("ADC Left Input", pcm186x_adc_input_channel_sel[0]), +- SOC_ENUM("ADC Right Input", pcm186x_adc_input_channel_sel[1]), +- SOC_ENUM("ADC Mic Bias", pcm186x_mic_bias_sel), +- SOC_ENUM("PGA Gain Left", pcm186x_gain_sel[0]), +- SOC_ENUM("PGA Gain Right", pcm186x_gain_sel[1]), +-}; +- + static int pcm1863_add_controls(struct snd_soc_component *component) + { + snd_soc_add_component_controls(component, diff --git a/target/linux/bcm27xx/patches-6.6/950-1222-drm-rp1-rp1-dsi-Add-DRM_FORMAT_ARGB8888-and-DRM_FORM.patch b/target/linux/bcm27xx/patches-6.6/950-1222-drm-rp1-rp1-dsi-Add-DRM_FORMAT_ARGB8888-and-DRM_FORM.patch new file mode 100644 index 000000000000..3f4be4c11112 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1222-drm-rp1-rp1-dsi-Add-DRM_FORMAT_ARGB8888-and-DRM_FORM.patch @@ -0,0 +1,48 @@ +From 9c5d91f6b938c23065ddc21c8654c5e222c35687 Mon Sep 17 00:00:00 2001 +From: Jan Kehren +Date: Fri, 16 Aug 2024 13:47:50 +0000 +Subject: [PATCH 1222/1350] drm: rp1: rp1-dsi: Add DRM_FORMAT_ARGB8888 and + DRM_FORMAT_ABGR8888 + +Android requires this. +As the underlying hardware doesn't support alpha blending, +we ignore the alpha value. + +Signed-off-by: Jan Kehren +--- + drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c | 2 ++ + drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dma.c | 12 ++++++++++++ + 2 files changed, 14 insertions(+) + +--- a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c ++++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c +@@ -229,6 +229,8 @@ static const struct drm_mode_config_func + static const u32 rp1dsi_formats[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, ++ DRM_FORMAT_ARGB8888, ++ DRM_FORMAT_ABGR8888, + DRM_FORMAT_RGB888, + DRM_FORMAT_BGR888, + DRM_FORMAT_RGB565 +--- a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dma.c ++++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dma.c +@@ -247,6 +247,18 @@ static const struct rp1dsi_ipixfmt my_fo + .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 3), + }, + { ++ .format = DRM_FORMAT_ARGB8888, ++ .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = ISHIFT_RGB(23, 15, 7), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 3), ++ }, ++ { ++ .format = DRM_FORMAT_ABGR8888, ++ .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = ISHIFT_RGB(7, 15, 23), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 3), ++ }, ++ { + .format = DRM_FORMAT_RGB888, + .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), + .shift = ISHIFT_RGB(23, 15, 7), diff --git a/target/linux/bcm27xx/patches-6.6/950-1223-drm-rp1-rp1-dpi-Add-DRM_FORMAT_ARGB8888-and-DRM_FORM.patch b/target/linux/bcm27xx/patches-6.6/950-1223-drm-rp1-rp1-dpi-Add-DRM_FORMAT_ARGB8888-and-DRM_FORM.patch new file mode 100644 index 000000000000..a24a0e942073 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1223-drm-rp1-rp1-dpi-Add-DRM_FORMAT_ARGB8888-and-DRM_FORM.patch @@ -0,0 +1,48 @@ +From 9f0523de1b7ef122fae527326372a4ab5aa42fa6 Mon Sep 17 00:00:00 2001 +From: Jan Kehren +Date: Tue, 20 Aug 2024 08:08:50 +0000 +Subject: [PATCH 1223/1350] drm: rp1: rp1-dpi: Add DRM_FORMAT_ARGB8888 and + DRM_FORMAT_ABGR8888 + +Android requires this. +As the underlying hardware doesn't support alpha blending, +we ignore the alpha value. + +Signed-off-by: Jan Kehren +--- + drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c | 2 ++ + drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c | 12 ++++++++++++ + 2 files changed, 14 insertions(+) + +--- a/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c ++++ b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c +@@ -260,6 +260,8 @@ static struct drm_driver rp1dpi_driver = + static const u32 rp1dpi_formats[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, ++ DRM_FORMAT_ARGB8888, ++ DRM_FORMAT_ABGR8888, + DRM_FORMAT_RGB888, + DRM_FORMAT_BGR888, + DRM_FORMAT_RGB565 +--- a/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c ++++ b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c +@@ -258,6 +258,18 @@ static const struct rp1dpi_ipixfmt my_fo + .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 3), + }, + { ++ .format = DRM_FORMAT_ARGB8888, ++ .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = ISHIFT_RGB(23, 15, 7), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 3), ++ }, ++ { ++ .format = DRM_FORMAT_ABGR8888, ++ .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = ISHIFT_RGB(7, 15, 23), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 3), ++ }, ++ { + .format = DRM_FORMAT_RGB888, + .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), + .shift = ISHIFT_RGB(23, 15, 7), diff --git a/target/linux/bcm27xx/patches-6.6/950-1224-drm-rp1-rp1-vec-Add-DRM_FORMAT_ARGB8888-and-DRM_FORM.patch b/target/linux/bcm27xx/patches-6.6/950-1224-drm-rp1-rp1-vec-Add-DRM_FORMAT_ARGB8888-and-DRM_FORM.patch new file mode 100644 index 000000000000..4c671cb66421 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1224-drm-rp1-rp1-vec-Add-DRM_FORMAT_ARGB8888-and-DRM_FORM.patch @@ -0,0 +1,48 @@ +From 29f7f01091f9aaa6b0c45f5c2e3db1792d381e9d Mon Sep 17 00:00:00 2001 +From: Jan Kehren +Date: Tue, 20 Aug 2024 08:16:06 +0000 +Subject: [PATCH 1224/1350] drm: rp1: rp1-vec: Add DRM_FORMAT_ARGB8888 and + DRM_FORMAT_ABGR8888 + +Android requires this. +As the underlying hardware doesn't support alpha blending, +we ignore the alpha value. + +Signed-off-by: Jan Kehren +--- + drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c | 2 ++ + drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c | 12 ++++++++++++ + 2 files changed, 14 insertions(+) + +--- a/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c ++++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c +@@ -420,6 +420,8 @@ static const struct drm_mode_config_func + static const u32 rp1vec_formats[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, ++ DRM_FORMAT_ARGB8888, ++ DRM_FORMAT_ABGR8888, + DRM_FORMAT_RGB888, + DRM_FORMAT_BGR888, + DRM_FORMAT_RGB565 +--- a/drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c ++++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c +@@ -63,6 +63,18 @@ static const struct rp1vec_ipixfmt my_fo + .rgbsz = BITS(VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1, 3), + }, + { ++ .format = DRM_FORMAT_ARGB8888, ++ .mask = MASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = SHIFT_RGB(23, 15, 7), ++ .rgbsz = BITS(VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1, 3), ++ }, ++ { ++ .format = DRM_FORMAT_ABGR8888, ++ .mask = MASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = SHIFT_RGB(7, 15, 23), ++ .rgbsz = BITS(VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1, 3), ++ }, ++ { + .format = DRM_FORMAT_RGB888, + .mask = MASK_RGB(0x3fc, 0x3fc, 0x3fc), + .shift = SHIFT_RGB(23, 15, 7), diff --git a/target/linux/bcm27xx/patches-6.6/950-1225-drm-vc4-Add-a-delay-after-disabling-hdmi-phy-output.patch b/target/linux/bcm27xx/patches-6.6/950-1225-drm-vc4-Add-a-delay-after-disabling-hdmi-phy-output.patch new file mode 100644 index 000000000000..b00330b6a241 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1225-drm-vc4-Add-a-delay-after-disabling-hdmi-phy-output.patch @@ -0,0 +1,34 @@ +From d984fd8907736d37656c558e213cfe087e43a7ce Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Mon, 12 Aug 2024 13:31:58 +0100 +Subject: [PATCH 1225/1350] drm/vc4: Add a delay after disabling hdmi phy + output + +There appears to be a requirement for some devices +(I'm testing with a 8K VRROOM 40Gbps HDMI switch) +for a measable delay between removing the hdmi phy output from +the old mode, to enabling the hdmi phy output for the new mode. + +Without the delay, a mode switch has a small change of getting a permanent +'no signal', which requires a subsequent mode switch or a unplug/replug +to redetect. + +Switching between 4kp24/25/30 modes fails about 5% of time in my testing. + +Add a delay to make it impossible to switch faster than this. + +Signed-off-by: Dom Cobley +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -668,6 +668,7 @@ static void vc4_crtc_atomic_disable(stru + * someone was waiting it. + */ + vc4_crtc_send_vblank(crtc); ++ msleep(20); + } + + static void vc4_crtc_atomic_enable(struct drm_crtc *crtc, diff --git a/target/linux/bcm27xx/patches-6.6/950-1226-drm-vc4-Implement-vc6_hdmi_phy_disable.patch b/target/linux/bcm27xx/patches-6.6/950-1226-drm-vc4-Implement-vc6_hdmi_phy_disable.patch new file mode 100644 index 000000000000..527e815a86fd --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1226-drm-vc4-Implement-vc6_hdmi_phy_disable.patch @@ -0,0 +1,25 @@ +From aa54ce17dc3a19eaf26f9c17c05a18aabcac90b0 Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Tue, 13 Aug 2024 16:13:16 +0100 +Subject: [PATCH 1226/1350] drm/vc4: Implement vc6_hdmi_phy_disable + +The body of this function was missing so we don't reset the phy +when disabling it. + +Signed-off-by: Dom Cobley +--- + drivers/gpu/drm/vc4/vc4_hdmi_phy.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c +@@ -1197,4 +1197,9 @@ void vc6_hdmi_phy_init(struct vc4_hdmi * + + void vc6_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi) + { ++ unsigned long flags; ++ ++ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); ++ vc6_hdmi_reset_phy(vc4_hdmi); ++ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + } diff --git a/target/linux/bcm27xx/patches-6.6/950-1227-drm-vc4-Also-power-down-the-PLL-core-when-resetting-.patch b/target/linux/bcm27xx/patches-6.6/950-1227-drm-vc4-Also-power-down-the-PLL-core-when-resetting-.patch new file mode 100644 index 000000000000..67df065766aa --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1227-drm-vc4-Also-power-down-the-PLL-core-when-resetting-.patch @@ -0,0 +1,35 @@ +From 3d21dabd055ca064880e775892a10c5e69fdf5e9 Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Tue, 13 Aug 2024 17:18:51 +0100 +Subject: [PATCH 1227/1350] drm/vc4: Also power down the PLL core when + resetting PHY + +The current reset code doesn't actually stop the hdmi output. +That makes it difficult for displays to handle a mode set. + +Powering down the PLL does actually remove the hdmi signal +and makes mode sets more reliable + +Signed-off-by: Dom Cobley +--- + drivers/gpu/drm/vc4/vc4_hdmi_phy.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c +@@ -137,6 +137,7 @@ + #define VC6_HDMI_TX_PHY_PLL_REFCLK_REFCLK_SEL_CMOS BIT(13) + #define VC6_HDMI_TX_PHY_PLL_REFCLK_REFFRQ_MASK VC4_MASK(9, 0) + ++#define VC6_HDMI_TX_PHY_PLL_POST_KDIV_BYPASS_EN BIT(4) + #define VC6_HDMI_TX_PHY_PLL_POST_KDIV_CLK0_SEL_MASK VC4_MASK(3, 2) + #define VC6_HDMI_TX_PHY_PLL_POST_KDIV_KDIV_MASK VC4_MASK(1, 0) + +@@ -947,6 +948,7 @@ static void vc6_hdmi_reset_phy(struct vc + + HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0); + HDMI_WRITE(HDMI_TX_PHY_POWERUP_CTL, 0); ++ HDMI_WRITE(HDMI_TX_PHY_PLL_POST_KDIV, VC6_HDMI_TX_PHY_PLL_POST_KDIV_BYPASS_EN); + } + + void vc6_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, diff --git a/target/linux/bcm27xx/patches-6.6/950-1228-ASoC-add-driver-for-new-HiFiBerry-ADC-only-board-s.patch b/target/linux/bcm27xx/patches-6.6/950-1228-ASoC-add-driver-for-new-HiFiBerry-ADC-only-board-s.patch new file mode 100644 index 000000000000..099d37e3ddd0 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1228-ASoC-add-driver-for-new-HiFiBerry-ADC-only-board-s.patch @@ -0,0 +1,228 @@ +From 784ef64631be19ef45a597e618c04a0f8b041307 Mon Sep 17 00:00:00 2001 +From: j-schambacher +Date: Tue, 20 Aug 2024 10:08:27 +0200 +Subject: [PATCH 1228/1350] ASoC: add driver for new HiFiBerry ADC only + board(s) + +Adds the driver for the soon to be released first ADC only board. +It includes the same ADC controls as used by the DAC+ADC Pro driver. + +Signed-off-by: j-schambacher +--- + sound/soc/bcm/Kconfig | 7 ++ + sound/soc/bcm/Makefile | 2 + + sound/soc/bcm/hifiberry_adc.c | 174 ++++++++++++++++++++++++++++++++++ + 3 files changed, 183 insertions(+) + create mode 100644 sound/soc/bcm/hifiberry_adc.c + +--- a/sound/soc/bcm/Kconfig ++++ b/sound/soc/bcm/Kconfig +@@ -39,6 +39,13 @@ config SND_BCM2708_SOC_GOOGLEVOICEHAT_SO + help + Say Y or M if you want to add support for voiceHAT soundcard. + ++config SND_BCM2708_SOC_HIFIBERRY_ADC ++ tristate "Support for HifiBerry ADC" ++ select SND_SOC_PCM186X_I2C ++ select SND_RPI_HIFIBERRY_ADC ++ help ++ Say Y or M if you want to add support for HifiBerry ADC. ++ + config SND_BCM2708_SOC_HIFIBERRY_DAC + tristate "Support for HifiBerry DAC and DAC8X" + select SND_SOC_PCM5102A +--- a/sound/soc/bcm/Makefile ++++ b/sound/soc/bcm/Makefile +@@ -18,6 +18,7 @@ obj-$(CONFIG_SND_BCM63XX_I2S_WHISTLER) + + snd-soc-googlevoicehat-codec-objs := googlevoicehat-codec.o + + # BCM2708 Machine Support ++snd-soc-hifiberry-adc-objs := hifiberry_adc.o + snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o + snd-soc-hifiberry-dacplushd-objs := hifiberry_dacplushd.o + snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o +@@ -51,6 +52,7 @@ snd-soc-chipdip-dac-objs := chipdip-dac. + snd-soc-dacberry400-objs := dacberry400.o + + obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o ++obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_ADC) += snd-soc-hifiberry-adc.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD) += snd-soc-hifiberry-dacplushd.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o +--- /dev/null ++++ b/sound/soc/bcm/hifiberry_adc.c +@@ -0,0 +1,174 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * ASoC Driver for HiFiBerry ADC ++ * ++ * Author: Joerg Schambacher ++ * Copyright 2024 ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../codecs/pcm186x.h" ++#include "hifiberry_adc_controls.h" ++ ++static bool leds_off; ++ ++static int pcm1863_add_controls(struct snd_soc_component *component) ++{ ++ snd_soc_add_component_controls(component, ++ pcm1863_snd_controls_card, ++ ARRAY_SIZE(pcm1863_snd_controls_card)); ++ return 0; ++} ++ ++static int snd_rpi_hifiberry_adc_init(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); ++ struct snd_soc_component *adc = codec_dai->component; ++ int ret; ++ ++ ret = pcm1863_add_controls(adc); ++ if (ret < 0) ++ dev_warn(rtd->dev, "Failed to add pcm1863 controls: %d\n", ++ ret); ++ ++ codec_dai->driver->capture.rates = ++ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | ++ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | ++ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000; ++ ++ /* set GPIO2 to output, GPIO3 input */ ++ snd_soc_component_write(adc, PCM186X_GPIO3_2_CTRL, 0x00); ++ snd_soc_component_write(adc, PCM186X_GPIO3_2_DIR_CTRL, 0x04); ++ if (leds_off) ++ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x00); ++ else ++ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40); ++ ++ return 0; ++} ++ ++static int snd_rpi_hifiberry_adc_hw_params( ++ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) ++{ ++ int ret = 0; ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ int channels = params_channels(params); ++ int width = snd_pcm_format_width(params_format(params)); ++ ++ /* Using powers of 2 allows for an integer clock divisor */ ++ width = width <= 16 ? 16 : 32; ++ ++ ret = snd_soc_dai_set_bclk_ratio(asoc_rtd_to_cpu(rtd, 0), channels * width); ++ return ret; ++} ++ ++/* machine stream operations */ ++static const struct snd_soc_ops snd_rpi_hifiberry_adc_ops = { ++ .hw_params = snd_rpi_hifiberry_adc_hw_params, ++}; ++ ++SND_SOC_DAILINK_DEFS(hifi, ++ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")), ++ DAILINK_COMP_ARRAY(COMP_CODEC("pcm186x.1-004a", "pcm1863-aif")), ++ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0"))); ++ ++static struct snd_soc_dai_link snd_rpi_hifiberry_adc_dai[] = { ++{ ++ .name = "HiFiBerry ADC", ++ .stream_name = "HiFiBerry ADC HiFi", ++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | ++ SND_SOC_DAIFMT_CBS_CFS, ++ .ops = &snd_rpi_hifiberry_adc_ops, ++ .init = snd_rpi_hifiberry_adc_init, ++ SND_SOC_DAILINK_REG(hifi), ++}, ++}; ++ ++/* audio machine driver */ ++static struct snd_soc_card snd_rpi_hifiberry_adc = { ++ .name = "snd_rpi_hifiberry_adc", ++ .driver_name = "HifiberryAdc", ++ .owner = THIS_MODULE, ++ .dai_link = snd_rpi_hifiberry_adc_dai, ++ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_adc_dai), ++}; ++ ++static int snd_rpi_hifiberry_adc_probe(struct platform_device *pdev) ++{ ++ int ret = 0, i = 0; ++ struct snd_soc_card *card = &snd_rpi_hifiberry_adc; ++ ++ snd_rpi_hifiberry_adc.dev = &pdev->dev; ++ if (pdev->dev.of_node) { ++ struct device_node *i2s_node; ++ struct snd_soc_dai_link *dai; ++ ++ dai = &snd_rpi_hifiberry_adc_dai[0]; ++ i2s_node = of_parse_phandle(pdev->dev.of_node, ++ "i2s-controller", 0); ++ if (i2s_node) { ++ for (i = 0; i < card->num_links; i++) { ++ dai->cpus->dai_name = NULL; ++ dai->cpus->of_node = i2s_node; ++ dai->platforms->name = NULL; ++ dai->platforms->of_node = i2s_node; ++ } ++ } ++ } ++ leds_off = of_property_read_bool(pdev->dev.of_node, ++ "hifiberry-adc,leds_off"); ++ ret = snd_soc_register_card(&snd_rpi_hifiberry_adc); ++ if (ret && ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, ++ "snd_soc_register_card() failed: %d\n", ret); ++ ++ return ret; ++} ++ ++static const struct of_device_id snd_rpi_hifiberry_adc_of_match[] = { ++ { .compatible = "hifiberry,hifiberry-adc", }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_adc_of_match); ++ ++static struct platform_driver snd_rpi_hifiberry_adc_driver = { ++ .driver = { ++ .name = "snd-rpi-hifiberry-adc", ++ .owner = THIS_MODULE, ++ .of_match_table = snd_rpi_hifiberry_adc_of_match, ++ }, ++ .probe = snd_rpi_hifiberry_adc_probe, ++}; ++ ++module_platform_driver(snd_rpi_hifiberry_adc_driver); ++ ++MODULE_AUTHOR("Joerg Schambacher "); ++MODULE_DESCRIPTION("ASoC Driver for HiFiBerry ADC"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/bcm27xx/patches-6.6/950-1229-overlays-Add-overlay-for-Hifiberry-ADC.patch b/target/linux/bcm27xx/patches-6.6/950-1229-overlays-Add-overlay-for-Hifiberry-ADC.patch new file mode 100644 index 000000000000..b1e763168324 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1229-overlays-Add-overlay-for-Hifiberry-ADC.patch @@ -0,0 +1,100 @@ +From 2f656dc533b65ae7f23527c3dc176efa92add105 Mon Sep 17 00:00:00 2001 +From: j-schambacher +Date: Tue, 20 Aug 2024 10:24:10 +0200 +Subject: [PATCH 1229/1350] overlays: Add overlay for Hifiberry ADC + +Adds the DT overlay for the HiFiBerry ADC. + +Signed-off-by: j-schambacher +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 7 +++ + .../dts/overlays/hifiberry-adc-overlay.dts | 45 +++++++++++++++++++ + sound/soc/bcm/Kconfig | 1 + + 4 files changed, 54 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/hifiberry-adc-overlay.dts + +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -85,6 +85,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + hd44780-i2c-lcd.dtbo \ + hd44780-lcd.dtbo \ + hdmi-backlight-hwhack-gpio.dtbo \ ++ hifiberry-adc.dtbo \ + hifiberry-amp.dtbo \ + hifiberry-amp100.dtbo \ + hifiberry-amp3.dtbo \ +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -1771,6 +1771,13 @@ Params: gpio_pin GPIO pin + expects a high to switch it on. + + ++Name: hifiberry-adc ++Info: Configures the HifiBerry ADC audio card ++Load: dtoverlay=hifiberry-adc,= ++Params: leds_off If set to 'true' the onboard indicator LED ++ is switched off at all times. ++ ++ + Name: hifiberry-amp + Info: Configures the HifiBerry Amp and Amp+ audio cards + Load: dtoverlay=hifiberry-amp +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/hifiberry-adc-overlay.dts +@@ -0,0 +1,45 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Definitions for HiFiBerry ADC, no onboard clocks ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&i2s_clk_producer>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&i2c1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ hb_adc: pcm186x@4a { ++ #sound-dai-cells = <0>; ++ compatible = "ti,pcm1863"; ++ reg = <0x4a>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&sound>; ++ hifiberry_adc: __overlay__ { ++ compatible = "hifiberry,hifiberry-adc"; ++ audio-codec = <&hb_adc>; ++ i2s-controller = <&i2s_clk_producer>; ++ status = "okay"; ++ }; ++ }; ++ ++ __overrides__ { ++ leds_off = <&hifiberry_adc>,"hifiberry-adc,leds_off?"; ++ }; ++}; +--- a/sound/soc/bcm/Kconfig ++++ b/sound/soc/bcm/Kconfig +@@ -45,6 +45,7 @@ config SND_BCM2708_SOC_HIFIBERRY_ADC + select SND_RPI_HIFIBERRY_ADC + help + Say Y or M if you want to add support for HifiBerry ADC. ++ Use this module for HiFiBerry's ADC-only sound cards + + config SND_BCM2708_SOC_HIFIBERRY_DAC + tristate "Support for HifiBerry DAC and DAC8X" diff --git a/target/linux/bcm27xx/patches-6.6/950-0320-spi-spidev-Restore-loading-from-Device-Tree.patch b/target/linux/bcm27xx/patches-6.6/950-1232-spi-spidev-Restore-loading-from-Device-Tree.patch similarity index 60% rename from target/linux/bcm27xx/patches-6.6/950-0320-spi-spidev-Restore-loading-from-Device-Tree.patch rename to target/linux/bcm27xx/patches-6.6/950-1232-spi-spidev-Restore-loading-from-Device-Tree.patch index da1bbb788661..8384559dad27 100644 --- a/target/linux/bcm27xx/patches-6.6/950-0320-spi-spidev-Restore-loading-from-Device-Tree.patch +++ b/target/linux/bcm27xx/patches-6.6/950-1232-spi-spidev-Restore-loading-from-Device-Tree.patch @@ -1,7 +1,7 @@ -From 2f223e0e4931486fbc32df3c89bc16ff1ca434bf Mon Sep 17 00:00:00 2001 +From ba0f2212e0e100ee16bdde76b7efca6bb8ee9446 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 29 Nov 2021 12:14:49 +0000 -Subject: [PATCH 0320/1085] spi: spidev: Restore loading from Device Tree +Subject: [PATCH 1232/1350] spi: spidev: Restore loading from Device Tree As happens occasionally, an upstream change has once again prevented spidev from being loaded via Device Tree. We now need "spidev" to be @@ -15,11 +15,11 @@ Signed-off-by: Phil Elwell --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c -@@ -699,6 +699,7 @@ static const struct file_operations spid - static struct class *spidev_class; - - static const struct spi_device_id spidev_spi_ids[] = { +@@ -711,6 +711,7 @@ static const struct spi_device_id spidev + { .name = "spi-authenta" }, + { .name = "em3581" }, + { .name = "si3210" }, + { .name = "spidev" }, - { .name = "bh2228fv" }, - { .name = "dh2228fv" }, - { .name = "jg10309-01" }, + {}, + }; + MODULE_DEVICE_TABLE(spi, spidev_spi_ids); diff --git a/target/linux/bcm27xx/patches-6.6/950-1233-drivers-drm-rp1-dsi-Implement-more-DSI-options-and-f.patch b/target/linux/bcm27xx/patches-6.6/950-1233-drivers-drm-rp1-dsi-Implement-more-DSI-options-and-f.patch new file mode 100644 index 000000000000..e906ad80272e --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1233-drivers-drm-rp1-dsi-Implement-more-DSI-options-and-f.patch @@ -0,0 +1,242 @@ +From e596d70725ca70113d39d9366d7b4d3e492f6449 Mon Sep 17 00:00:00 2001 +From: Nick Hollinghurst +Date: Wed, 31 Jul 2024 19:05:29 +0100 +Subject: [PATCH 1233/1350] drivers: drm: rp1-dsi: Implement more DSI options + and flags + +Now implementing: +- Per-command selection of LP or HS for commands (previously LP) +- EoTp transmission option (previously EoTp was always disabled) +- Non-continuous clock option (previously always continuous) +- Per-command enabling of ACK request (in command mode only) + +Make a plausible (and possibly correct) attempt to measure the +longest LP command that will fit into vertical blanking lines. + +DON'T set both "Burst Mode" and "Sync Events" flags together. +This is redundant in the standard IP; in this RP1 variant it +would enable Sync Pulses but may break with some video timings. + +Signed-off-by: Nick Hollinghurst +--- + drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c | 5 +- + drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h | 3 +- + drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c | 106 +++++++++++++++++----- + 3 files changed, 91 insertions(+), 23 deletions(-) + +--- a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c ++++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c +@@ -396,7 +396,10 @@ ssize_t rp1dsi_host_transfer(struct mipi + return ret; + } + +- rp1dsi_dsi_send(dsi, *(u32 *)(&packet.header), packet.payload_length, packet.payload); ++ rp1dsi_dsi_send(dsi, *(u32 *)(&packet.header), ++ packet.payload_length, packet.payload, ++ !!(msg->flags & MIPI_DSI_MSG_USE_LPM), ++ !!(msg->flags & MIPI_DSI_MSG_REQ_ACK)); + + /* Optional read back */ + if (msg->rx_len && msg->rx_buf) +--- a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h ++++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h +@@ -86,7 +86,8 @@ void rp1dsi_mipicfg_setup(struct rp1_dsi + /* Functions to control the SNPS D-PHY and DSI block setup */ + + void rp1dsi_dsi_setup(struct rp1_dsi *dsi, struct drm_display_mode const *mode); +-void rp1dsi_dsi_send(struct rp1_dsi *dsi, u32 header, int len, const u8 *buf); ++void rp1dsi_dsi_send(struct rp1_dsi *dsi, u32 header, int len, const u8 *buf, ++ bool use_lpm, bool req_ack); + int rp1dsi_dsi_recv(struct rp1_dsi *dsi, int len, u8 *buf); + void rp1dsi_dsi_set_cmdmode(struct rp1_dsi *dsi, int cmd_mode); + void rp1dsi_dsi_stop(struct rp1_dsi *dsi); +--- a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c ++++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c +@@ -103,6 +103,24 @@ + + /* And some bitfield definitions */ + ++#define DSI_PCKHDL_EOTP_TX_EN BIT(0) ++#define DSI_PCKHDL_BTA_EN BIT(2) ++ ++#define DSI_VID_MODE_LP_CMD_EN BIT(15) ++#define DSI_VID_MODE_FRAME_BTA_ACK_EN BIT(14) ++#define DSI_VID_MODE_LP_HFP_EN BIT(13) ++#define DSI_VID_MODE_LP_HBP_EN BIT(12) ++#define DSI_VID_MODE_LP_VACT_EN BIT(11) ++#define DSI_VID_MODE_LP_VFP_EN BIT(10) ++#define DSI_VID_MODE_LP_VBP_EN BIT(9) ++#define DSI_VID_MODE_LP_VSA_EN BIT(8) ++#define DSI_VID_MODE_SYNC_PULSES 0 ++#define DSI_VID_MODE_SYNC_EVENTS 1 ++#define DSI_VID_MODE_BURST 2 ++ ++#define DSI_CMD_MODE_ALL_LP 0x10f7f00 ++#define DSI_CMD_MODE_ACK_RQST_EN BIT(1) ++ + #define DPHY_PWR_UP_SHUTDOWNZ_LSB 0 + #define DPHY_PWR_UP_SHUTDOWNZ_BITS BIT(DPHY_PWR_UP_SHUTDOWNZ_LSB) + +@@ -1252,8 +1270,8 @@ static u32 dphy_configure_pll(struct rp1 + vco_freq, actual_vco_freq, m, refclk, n, + hsfreq_table[dsi->hsfreq_index].hsfreqrange); + } else { +- drm_warn(dsi->drm, +- "rp1dsi: Error configuring DPHY PLL %uHz\n", vco_freq); ++ drm_err(dsi->drm, ++ "rp1dsi: Error configuring DPHY PLL %uHz\n", vco_freq); + } + + return actual_vco_freq; +@@ -1321,7 +1339,7 @@ static void rp1dsi_dpiclk_start(struct r + clk_set_rate(dsi->clocks[RP1DSI_CLOCK_DPI], (4 * lanes * byte_clock) / (bpp >> 1)); + clk_prepare_enable(dsi->clocks[RP1DSI_CLOCK_DPI]); + drm_info(dsi->drm, +- "rp1dsi: Nominal Byte clock %u DPI clock %lu (parent rate %lu)", ++ "rp1dsi: Nominal Byte clock %u DPI clock %lu (parent rate %lu)\n", + byte_clock, + clk_get_rate(dsi->clocks[RP1DSI_CLOCK_DPI]), + clk_get_rate(clk_get_parent(dsi->clocks[RP1DSI_CLOCK_DPI]))); +@@ -1365,7 +1383,8 @@ static u32 get_colorcode(enum mipi_dsi_p + + void rp1dsi_dsi_setup(struct rp1_dsi *dsi, struct drm_display_mode const *mode) + { +- u32 timeout, mask, vid_mode_cfg; ++ int cmdtim; ++ u32 timeout, mask, clkdiv; + unsigned int bpp = mipi_dsi_pixel_format_to_bpp(dsi->display_format); + u32 byte_clock = clamp((bpp * 125 * min(mode->clock, RP1DSI_DPI_MAX_KHZ)) / dsi->lanes, + RP1DSI_BYTE_CLK_MIN, RP1DSI_BYTE_CLK_MAX); +@@ -1374,19 +1393,31 @@ void rp1dsi_dsi_setup(struct rp1_dsi *ds + DSI_WRITE(DSI_DPI_CFG_POL, 0); + DSI_WRITE(DSI_GEN_VCID, dsi->vc); + DSI_WRITE(DSI_DPI_COLOR_CODING, get_colorcode(dsi->display_format)); +- /* a conservative guess (LP escape is slow!) */ +- DSI_WRITE(DSI_DPI_LP_CMD_TIM, 0x00100000); + +- /* Drop to LP where possible; use LP Escape for all commands */ +- vid_mode_cfg = 0xbf00; +- if (!(dsi->display_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)) +- vid_mode_cfg |= 0x01; +- else if (8 * dsi->lanes > bpp) +- vid_mode_cfg &= ~0x400; /* PULSE && inexact DPICLK => fix HBP time */ ++ /* ++ * Flags to configure use of LP, EoTp, Burst Mode, Sync Events/Pulses. ++ * Note that Burst Mode implies Sync Events; the two flags need not be ++ * set concurrently, and in this RP1 variant *should not* both be set: ++ * doing so would (counter-intuitively) enable Sync Pulses and may fail ++ * if there is not sufficient time to return to LP11 state during HBP. ++ */ ++ mask = DSI_VID_MODE_LP_HFP_EN | DSI_VID_MODE_LP_HBP_EN | ++ DSI_VID_MODE_LP_VACT_EN | DSI_VID_MODE_LP_VFP_EN | ++ DSI_VID_MODE_LP_VBP_EN | DSI_VID_MODE_LP_VSA_EN; ++ if (dsi->display_flags & MIPI_DSI_MODE_LPM) ++ mask |= DSI_VID_MODE_LP_CMD_EN; + if (dsi->display_flags & MIPI_DSI_MODE_VIDEO_BURST) +- vid_mode_cfg |= 0x02; +- DSI_WRITE(DSI_VID_MODE_CFG, vid_mode_cfg); +- DSI_WRITE(DSI_CMD_MODE_CFG, 0x10F7F00); ++ mask |= DSI_VID_MODE_BURST; ++ else if (!(dsi->display_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)) ++ mask |= DSI_VID_MODE_SYNC_EVENTS; ++ else if (8 * dsi->lanes > bpp) ++ mask &= ~DSI_VID_MODE_LP_HBP_EN; /* PULSE && inexact DPICLK => fix HBP time */ ++ DSI_WRITE(DSI_VID_MODE_CFG, mask); ++ DSI_WRITE(DSI_CMD_MODE_CFG, ++ (dsi->display_flags & MIPI_DSI_MODE_LPM) ? DSI_CMD_MODE_ALL_LP : 0); ++ DSI_WRITE(DSI_PCKHDL_CFG, ++ DSI_PCKHDL_BTA_EN | ++ ((dsi->display_flags & MIPI_DSI_MODE_NO_EOT_PACKET) ? 0 : DSI_PCKHDL_EOTP_TX_EN)); + + /* Select Command Mode */ + DSI_WRITE(DSI_MODE_CFG, 1); +@@ -1397,9 +1428,9 @@ void rp1dsi_dsi_setup(struct rp1_dsi *ds + timeout = 0; + DSI_WRITE(DSI_TO_CNT_CFG, (timeout << 16) | RP1DSI_LPRX_TO_VAL); + DSI_WRITE(DSI_BTA_TO_CNT, RP1DSI_BTA_TO_VAL); ++ clkdiv = max(2u, 1u + byte_clock / RP1DSI_ESC_CLK_MAX); /* byte clocks per escape clock */ + DSI_WRITE(DSI_CLKMGR_CFG, +- (RP1DSI_TO_CLK_DIV << 8) | +- max(2u, 1u + byte_clock / RP1DSI_ESC_CLK_MAX)); ++ (RP1DSI_TO_CLK_DIV << 8) | clkdiv); + + /* Configure video timings */ + DSI_WRITE(DSI_VID_PKT_SIZE, mode->hdisplay); +@@ -1425,6 +1456,18 @@ void rp1dsi_dsi_setup(struct rp1_dsi *ds + (hsfreq_table[dsi->hsfreq_index].data_lp2hs << DSI_PHY_TMR_LP2HS_LSB) | + (hsfreq_table[dsi->hsfreq_index].data_hs2lp << DSI_PHY_TMR_HS2LP_LSB)); + ++ /* Estimate how many LP bytes can be sent during vertical blanking (Databook 3.6.2.1) */ ++ cmdtim = mode->htotal; ++ if (dsi->display_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) ++ cmdtim -= mode->hsync_end - mode->hsync_start; ++ cmdtim = (bpp * cmdtim - 64) / (8 * dsi->lanes); /* byte clocks after HSS and EoTp */ ++ cmdtim -= hsfreq_table[dsi->hsfreq_index].data_hs2lp; ++ cmdtim -= hsfreq_table[dsi->hsfreq_index].data_lp2hs; ++ cmdtim = (cmdtim / clkdiv) - 24; /* escape clocks for commands */ ++ cmdtim = max(0, cmdtim >> 4); /* bytes (at 2 clocks per bit) */ ++ drm_info(dsi->drm, "rp1dsi: Command time (outvact): %d\n", cmdtim); ++ DSI_WRITE(DSI_DPI_LP_CMD_TIM, cmdtim << 16); ++ + /* Wait for PLL lock */ + for (timeout = (1 << 14); timeout != 0; --timeout) { + usleep_range(10, 50); +@@ -1434,9 +1477,9 @@ void rp1dsi_dsi_setup(struct rp1_dsi *ds + if (timeout == 0) + drm_err(dsi->drm, "RP1DSI: Time out waiting for PLL\n"); + +- DSI_WRITE(DSI_LPCLK_CTRL, 0x1); /* configure the requesthsclk */ ++ DSI_WRITE(DSI_LPCLK_CTRL, ++ (dsi->display_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) ? 0x3 : 0x1); + DSI_WRITE(DSI_PHY_TST_CTRL0, 0x2); +- DSI_WRITE(DSI_PCKHDL_CFG, 1 << 2); /* allow bus turnaround */ + DSI_WRITE(DSI_PWR_UP, 0x1); /* power up */ + + /* Now it should be safe to start the external DPI clock divider */ +@@ -1460,7 +1503,8 @@ void rp1dsi_dsi_setup(struct rp1_dsi *ds + mask, DSI_READ(DSI_PHY_STATUS)); + } + +-void rp1dsi_dsi_send(struct rp1_dsi *dsi, u32 hdr, int len, const u8 *buf) ++void rp1dsi_dsi_send(struct rp1_dsi *dsi, u32 hdr, int len, const u8 *buf, ++ bool use_lpm, bool req_ack) + { + u32 val; + +@@ -1471,6 +1515,24 @@ void rp1dsi_dsi_send(struct rp1_dsi *dsi + usleep_range(100, 150); + } + ++ /* ++ * Update global configuration flags for LP/HS and ACK options. ++ * XXX It's not clear if having empty FIFOs (checked above and below) guarantees that ++ * the last command has completed and been ACKed, or how closely these control registers ++ * align with command/payload FIFO writes (as each is an independent clock-crossing)? ++ */ ++ val = DSI_READ(DSI_VID_MODE_CFG); ++ if (use_lpm) ++ val |= DSI_VID_MODE_LP_CMD_EN; ++ else ++ val &= ~DSI_VID_MODE_LP_CMD_EN; ++ DSI_WRITE(DSI_VID_MODE_CFG, val); ++ val = (use_lpm) ? DSI_CMD_MODE_ALL_LP : 0; ++ if (req_ack) ++ val |= DSI_CMD_MODE_ACK_RQST_EN; ++ DSI_WRITE(DSI_CMD_MODE_CFG, val); ++ (void)DSI_READ(DSI_CMD_MODE_CFG); ++ + /* Write payload (in 32-bit words) and header */ + for (; len > 0; len -= 4) { + val = *buf++; +@@ -1504,8 +1566,10 @@ int rp1dsi_dsi_recv(struct rp1_dsi *dsi, + break; + usleep_range(100, 150); + } +- if (i == 0) ++ if (!i) { ++ drm_warn(dsi->drm, "Receive failed\n"); + return -EIO; ++ } + + for (i = 0; i < len; i += 4) { + /* Read fifo must not be empty before all bytes are read */ diff --git a/target/linux/bcm27xx/patches-6.6/950-1234-rtc-pcf8523-Fix-oscillator-stop-bit-handling-reading.patch b/target/linux/bcm27xx/patches-6.6/950-1234-rtc-pcf8523-Fix-oscillator-stop-bit-handling-reading.patch new file mode 100644 index 000000000000..8b634117d2a2 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1234-rtc-pcf8523-Fix-oscillator-stop-bit-handling-reading.patch @@ -0,0 +1,53 @@ +From 8beb6891489c3c99618a7390578109aadfdf8901 Mon Sep 17 00:00:00 2001 +From: Axel <48924884+Paladinking@users.noreply.github.com> +Date: Wed, 28 Aug 2024 09:46:13 +0200 +Subject: [PATCH 1234/1350] rtc: pcf8523: Fix oscillator stop bit handling + reading from Control_1 + +The check if the oscillator stop bit is set was reading from Control_1 +register instead of the Seconds register. +This caused the Seconds register to be incorrectly changed if bit 7 of +Control_1 happens to be set. + +Signed-off-by: Axel Hammarberg +--- + drivers/rtc/rtc-pcf8523.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/drivers/rtc/rtc-pcf8523.c ++++ b/drivers/rtc/rtc-pcf8523.c +@@ -108,10 +108,10 @@ static int pcf8523_rtc_read_time(struct + if (err < 0) + return err; + +- if ((regs[0] & PCF8523_CONTROL1_STOP) || (regs[3] & PCF8523_SECONDS_OS)) ++ if (regs[PCF8523_REG_CONTROL1] & PCF8523_CONTROL1_STOP) + return -EINVAL; + +- if (regs[0] & PCF8523_SECONDS_OS) { ++ if (regs[PCF8523_REG_SECONDS] & PCF8523_SECONDS_OS) { + /* + * If the oscillator was stopped, try to clear the flag. Upon + * power-up the flag is always set, but if we cannot clear it +@@ -120,10 +120,10 @@ static int pcf8523_rtc_read_time(struct + * that the clock cannot be assumed to be correct. + */ + +- regs[0] &= ~PCF8523_SECONDS_OS; ++ regs[PCF8523_REG_SECONDS] &= ~PCF8523_SECONDS_OS; + + err = regmap_write(pcf8523->regmap, PCF8523_REG_SECONDS, +- regs[0]); ++ regs[PCF8523_REG_SECONDS]); + if (err < 0) + return err; + +@@ -135,7 +135,7 @@ static int pcf8523_rtc_read_time(struct + if (value & PCF8523_SECONDS_OS) + return -EAGAIN; + +- regs[0] = value; ++ regs[PCF8523_REG_SECONDS] = value; + } + + tm->tm_sec = bcd2bin(regs[3] & 0x7f); diff --git a/target/linux/bcm27xx/patches-6.6/950-1235-drivers-media-pci-Update-Hailo-accelerator-device-dr.patch b/target/linux/bcm27xx/patches-6.6/950-1235-drivers-media-pci-Update-Hailo-accelerator-device-dr.patch new file mode 100644 index 000000000000..5f8cf8df017a --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1235-drivers-media-pci-Update-Hailo-accelerator-device-dr.patch @@ -0,0 +1,3352 @@ +From a44f17d8193b69aedb1beebf5ad885a88b1c6615 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Fri, 2 Aug 2024 11:01:24 +0100 +Subject: [PATCH 1235/1350] drivers: media: pci: Update Hailo accelerator + device driver to v4.18.0 + +Sourced from https://github.com/hailo-ai/hailort-drivers/ + +Signed-off-by: Naushir Patuck +--- + drivers/media/pci/hailo/Makefile | 2 + + drivers/media/pci/hailo/common/fw_operation.c | 2 +- + drivers/media/pci/hailo/common/fw_operation.h | 2 +- + .../media/pci/hailo/common/fw_validation.c | 10 +- + .../media/pci/hailo/common/fw_validation.h | 5 +- + .../pci/hailo/common/hailo_ioctl_common.h | 240 +++++++---- + .../media/pci/hailo/common/hailo_resource.c | 2 +- + .../media/pci/hailo/common/hailo_resource.h | 2 +- + drivers/media/pci/hailo/common/pcie_common.c | 367 +++++++++++++---- + drivers/media/pci/hailo/common/pcie_common.h | 42 +- + drivers/media/pci/hailo/common/utils.h | 24 +- + drivers/media/pci/hailo/common/vdma_common.c | 371 +++++++++++++----- + drivers/media/pci/hailo/common/vdma_common.h | 34 +- + drivers/media/pci/hailo/src/fops.c | 104 +++-- + drivers/media/pci/hailo/src/fops.h | 1 + + drivers/media/pci/hailo/src/pci_soc_ioctl.c | 155 ++++++++ + drivers/media/pci/hailo/src/pci_soc_ioctl.h | 19 + + drivers/media/pci/hailo/src/pcie.c | 93 ++++- + drivers/media/pci/hailo/src/pcie.h | 2 + + drivers/media/pci/hailo/src/sysfs.c | 9 + + drivers/media/pci/hailo/src/utils.c | 1 - + .../pci/hailo/utils/integrated_nnc_utils.c | 101 +++++ + .../pci/hailo/utils/integrated_nnc_utils.h | 30 ++ + drivers/media/pci/hailo/vdma/ioctl.c | 53 ++- + drivers/media/pci/hailo/vdma/ioctl.h | 6 +- + drivers/media/pci/hailo/vdma/memory.c | 148 ++++++- + drivers/media/pci/hailo/vdma/memory.h | 4 +- + drivers/media/pci/hailo/vdma/vdma.c | 80 ++-- + drivers/media/pci/hailo/vdma/vdma.h | 30 +- + 29 files changed, 1536 insertions(+), 403 deletions(-) + create mode 100755 drivers/media/pci/hailo/src/pci_soc_ioctl.c + create mode 100755 drivers/media/pci/hailo/src/pci_soc_ioctl.h + create mode 100755 drivers/media/pci/hailo/utils/integrated_nnc_utils.c + create mode 100755 drivers/media/pci/hailo/utils/integrated_nnc_utils.h + +--- a/drivers/media/pci/hailo/Makefile ++++ b/drivers/media/pci/hailo/Makefile +@@ -10,6 +10,7 @@ hailo_pci-objs += src/pcie.o + hailo_pci-objs += src/fops.o + hailo_pci-objs += src/utils.o + hailo_pci-objs += src/sysfs.o ++hailo_pci-objs += src/pci_soc_ioctl.o + + hailo_pci-objs += $(COMMON_SRC_DIRECTORY)/fw_validation.o + hailo_pci-objs += $(COMMON_SRC_DIRECTORY)/fw_operation.o +@@ -18,6 +19,7 @@ hailo_pci-objs += $(COMMON_SRC_DIRECTORY + hailo_pci-objs += $(COMMON_SRC_DIRECTORY)/hailo_resource.o + + hailo_pci-objs += $(UTILS_SRC_DIRECTORY)/logs.o ++hailo_pci-objs += $(UTILS_SRC_DIRECTORY)/integrated_nnc_utils.o + + hailo_pci-objs += $(VDMA_SRC_DIRECTORY)/vdma.o + hailo_pci-objs += $(VDMA_SRC_DIRECTORY)/memory.o +--- a/drivers/media/pci/hailo/common/fw_operation.c ++++ b/drivers/media/pci/hailo/common/fw_operation.c +@@ -1,4 +1,4 @@ +-// SPDX-License-Identifier: GPL-2.0 ++// SPDX-License-Identifier: MIT + /** + * Copyright (c) 2022 Hailo Technologies Ltd. All rights reserved. + **/ +--- a/drivers/media/pci/hailo/common/fw_operation.h ++++ b/drivers/media/pci/hailo/common/fw_operation.h +@@ -1,4 +1,4 @@ +-// SPDX-License-Identifier: GPL-2.0 ++// SPDX-License-Identifier: MIT + /** + * Copyright (c) 2022 Hailo Technologies Ltd. All rights reserved. + **/ +--- a/drivers/media/pci/hailo/common/fw_validation.c ++++ b/drivers/media/pci/hailo/common/fw_validation.c +@@ -1,4 +1,4 @@ +-// SPDX-License-Identifier: GPL-2.0 ++// SPDX-License-Identifier: MIT + /** + * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. + **/ +@@ -28,16 +28,18 @@ int FW_VALIDATION__validate_fw_header(ui + firmware_header_t *firmware_header = NULL; + u32 consumed_firmware_offset = *outer_consumed_firmware_offset; + u32 expected_firmware_magic = 0; +- ++ + firmware_header = (firmware_header_t *) (firmware_base_address + consumed_firmware_offset); + CONSUME_FIRMWARE(sizeof(firmware_header_t), -EINVAL); + + switch (board_type) { + case HAILO_BOARD_TYPE_HAILO8: +- expected_firmware_magic = FIRMWARE_HEADER_MAGIC_HAILO8; ++ expected_firmware_magic = FIRMWARE_HEADER_MAGIC_HAILO8; + break; ++ case HAILO_BOARD_TYPE_HAILO10H_LEGACY: + case HAILO_BOARD_TYPE_HAILO15: +- expected_firmware_magic = FIRMWARE_HEADER_MAGIC_HAILO15; ++ case HAILO_BOARD_TYPE_HAILO10H: ++ expected_firmware_magic = FIRMWARE_HEADER_MAGIC_HAILO15; + break; + case HAILO_BOARD_TYPE_PLUTO: + expected_firmware_magic = FIRMWARE_HEADER_MAGIC_PLUTO; +--- a/drivers/media/pci/hailo/common/fw_validation.h ++++ b/drivers/media/pci/hailo/common/fw_validation.h +@@ -1,4 +1,4 @@ +-// SPDX-License-Identifier: GPL-2.0 ++// SPDX-License-Identifier: MIT + /** + * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. + **/ +@@ -11,8 +11,7 @@ + + #define FIRMWARE_HEADER_MAGIC_HAILO8 (0x1DD89DE0) + #define FIRMWARE_HEADER_MAGIC_HAILO15 (0xE905DAAB) +-// TODO - HRT-11344 : change fw magic to pluto specific +-#define FIRMWARE_HEADER_MAGIC_PLUTO (0xE905DAAB) ++#define FIRMWARE_HEADER_MAGIC_PLUTO (0xF94739AB) + + #ifndef HAILO_EMULATOR + #define FIRMWARE_WAIT_TIMEOUT_MS (5000) +--- a/drivers/media/pci/hailo/common/hailo_ioctl_common.h ++++ b/drivers/media/pci/hailo/common/hailo_ioctl_common.h +@@ -6,6 +6,14 @@ + #ifndef _HAILO_IOCTL_COMMON_H_ + #define _HAILO_IOCTL_COMMON_H_ + ++#define HAILO_DRV_VER_MAJOR 4 ++#define HAILO_DRV_VER_MINOR 18 ++#define HAILO_DRV_VER_REVISION 0 ++ ++#define _STRINGIFY_EXPANDED( x ) #x ++#define _STRINGIFY_NUMBER( x ) _STRINGIFY_EXPANDED(x) ++#define HAILO_DRV_VER _STRINGIFY_NUMBER(HAILO_DRV_VER_MAJOR) "." _STRINGIFY_NUMBER(HAILO_DRV_VER_MINOR) "." _STRINGIFY_NUMBER(HAILO_DRV_VER_REVISION) ++ + + // This value is not easily changeable. + // For example: the channel interrupts ioctls assume we have up to 32 channels +@@ -23,14 +31,17 @@ + #define INVALID_DRIVER_HANDLE_VALUE ((uintptr_t)-1) + + // Used by windows and unix driver to raise the right CPU control handle to the FW. The same as in pcie_service FW +-#define FW_ACCESS_CORE_CPU_CONTROL_SHIFT (1) +-#define FW_ACCESS_CORE_CPU_CONTROL_MASK (1 << FW_ACCESS_CORE_CPU_CONTROL_SHIFT) +-#define FW_ACCESS_CONTROL_INTERRUPT_SHIFT (0) +-#define FW_ACCESS_APP_CPU_CONTROL_MASK (1 << FW_ACCESS_CONTROL_INTERRUPT_SHIFT) +-#define FW_ACCESS_DRIVER_SHUTDOWN_SHIFT (2) +-#define FW_ACCESS_DRIVER_SHUTDOWN_MASK (1 << FW_ACCESS_DRIVER_SHUTDOWN_SHIFT) ++#define FW_ACCESS_CORE_CPU_CONTROL_SHIFT (1) ++#define FW_ACCESS_CORE_CPU_CONTROL_MASK (1 << FW_ACCESS_CORE_CPU_CONTROL_SHIFT) ++#define FW_ACCESS_CONTROL_INTERRUPT_SHIFT (0) ++#define FW_ACCESS_APP_CPU_CONTROL_MASK (1 << FW_ACCESS_CONTROL_INTERRUPT_SHIFT) ++#define FW_ACCESS_DRIVER_SHUTDOWN_SHIFT (2) ++#define FW_ACCESS_DRIVER_SHUTDOWN_MASK (1 << FW_ACCESS_DRIVER_SHUTDOWN_SHIFT) ++#define FW_ACCESS_SOC_CONNECT_SHIFT (3) ++#define FW_ACCESS_SOC_CONNECT_MASK (1 << FW_ACCESS_SOC_CONNECT_SHIFT) ++ ++#define INVALID_VDMA_CHANNEL (0xff) + +-#define INVALID_VDMA_CHANNEL (0xff) + + #if !defined(__cplusplus) && defined(NTDDI_VERSION) + #include +@@ -53,14 +64,23 @@ typedef uint8_t bool; + #define INT_MAX 0x7FFFFFFF + #endif // !defined(INT_MAX) + ++#if !defined(ECONNRESET) ++#define ECONNRESET 104 /* Connection reset by peer */ ++#endif // !defined(ECONNRESET) + + // {d88d31f1-fede-4e71-ac2a-6ce0018c1501} +-DEFINE_GUID (GUID_DEVINTERFACE_HailoKM, ++DEFINE_GUID (GUID_DEVINTERFACE_HailoKM_NNC, + 0xd88d31f1,0xfede,0x4e71,0xac,0x2a,0x6c,0xe0,0x01,0x8c,0x15,0x01); + +-#define HAILO_GENERAL_IOCTL_MAGIC 0 +-#define HAILO_VDMA_IOCTL_MAGIC 1 +-#define HAILO_NON_LINUX_IOCTL_MAGIC 2 ++// {7f16047d-64b8-207a-0092-e970893970a2} ++DEFINE_GUID (GUID_DEVINTERFACE_HailoKM_SOC, ++ 0x7f16047d,0x64b8,0x207a,0x00,0x92,0xe9,0x70,0x89,0x39,0x70,0xa2); ++ ++#define HAILO_GENERAL_IOCTL_MAGIC 0 ++#define HAILO_VDMA_IOCTL_MAGIC 1 ++#define HAILO_SOC_IOCTL_MAGIC 2 ++#define HAILO_PCI_EP_IOCTL_MAGIC 3 ++#define HAILO_NNC_IOCTL_MAGIC 4 + + #define HAILO_IOCTL_COMPATIBLE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS) + +@@ -114,9 +134,11 @@ static ULONG FORCEINLINE _IOC_(ULONG nr, + #define _IOWR_ _IOWR + #define _IO_ _IO + +-#define HAILO_GENERAL_IOCTL_MAGIC 'g' +-#define HAILO_VDMA_IOCTL_MAGIC 'v' +-#define HAILO_NON_LINUX_IOCTL_MAGIC 'w' ++#define HAILO_GENERAL_IOCTL_MAGIC 'g' ++#define HAILO_VDMA_IOCTL_MAGIC 'v' ++#define HAILO_SOC_IOCTL_MAGIC 's' ++#define HAILO_NNC_IOCTL_MAGIC 'n' ++#define HAILO_PCI_EP_IOCTL_MAGIC 'p' + + #elif defined(__QNX__) // #ifdef _MSC_VER + #include +@@ -132,7 +154,6 @@ static ULONG FORCEINLINE _IOC_(ULONG nr, + #define _IO_ __DION + #define HAILO_GENERAL_IOCTL_MAGIC _DCMD_ALL + #define HAILO_VDMA_IOCTL_MAGIC _DCMD_MISC +-#define HAILO_NON_LINUX_IOCTL_MAGIC _DCMD_PROC + + #else // #ifdef _MSC_VER + #error "unsupported platform!" +@@ -161,6 +182,16 @@ enum hailo_dma_data_direction { + HAILO_DMA_MAX_ENUM = INT_MAX, + }; + ++// Enum that states what type of buffer we are working with in the driver ++// TODO: HRT-13580 - Add specific type for user allocated and for driver allocated ++enum hailo_dma_buffer_type { ++ HAILO_DMA_USER_PTR_BUFFER = 0, ++ HAILO_DMA_DMABUF_BUFFER = 1, ++ ++ /** Max enum value to maintain ABI Integrity */ ++ HAILO_DMA_BUFFER_MAX_ENUM = INT_MAX, ++}; ++ + // Enum that determines if buffer should be allocated from user space or from driver + enum hailo_allocation_mode { + HAILO_ALLOCATION_MODE_USERSPACE = 0, +@@ -170,10 +201,19 @@ enum hailo_allocation_mode { + HAILO_ALLOCATION_MODE_MAX_ENUM = INT_MAX, + }; + ++enum hailo_vdma_interrupts_domain { ++ HAILO_VDMA_INTERRUPTS_DOMAIN_NONE = 0, ++ HAILO_VDMA_INTERRUPTS_DOMAIN_DEVICE = (1 << 0), ++ HAILO_VDMA_INTERRUPTS_DOMAIN_HOST = (1 << 1), ++ ++ /** Max enum value to maintain ABI Integrity */ ++ HAILO_VDMA_INTERRUPTS_DOMAIN_MAX_ENUM = INT_MAX, ++}; ++ + /* structure used in ioctl HAILO_VDMA_BUFFER_MAP */ + struct hailo_vdma_buffer_map_params { + #if defined(__linux__) || defined(_MSC_VER) +- void* user_address; // in ++ uintptr_t user_address; // in + #elif defined(__QNX__) + shm_handle_t shared_memory_handle; // in + #else +@@ -181,6 +221,7 @@ struct hailo_vdma_buffer_map_params { + #endif // __linux__ + size_t size; // in + enum hailo_dma_data_direction data_direction; // in ++ enum hailo_dma_buffer_type buffer_type; // in + uintptr_t allocated_buffer_handle; // in + size_t mapped_handle; // out + }; +@@ -204,31 +245,27 @@ struct hailo_desc_list_release_params { + uintptr_t desc_handle; // in + }; + +-/* structure used in ioctl HAILO_NON_LINUX_DESC_LIST_MMAP */ +-struct hailo_non_linux_desc_list_mmap_params { +- uintptr_t desc_handle; // in +- size_t size; // in +- void* user_address; // out +-}; +- + /* structure used in ioctl HAILO_DESC_LIST_BIND_VDMA_BUFFER */ +-struct hailo_desc_list_bind_vdma_buffer_params { ++struct hailo_desc_list_program_params { + size_t buffer_handle; // in + size_t buffer_size; // in + size_t buffer_offset; // in + uintptr_t desc_handle; // in + uint8_t channel_index; // in + uint32_t starting_desc; // in ++ bool should_bind; // in ++ enum hailo_vdma_interrupts_domain last_interrupts_domain; // in ++ bool is_debug; // in + }; + +-/* structure used in ioctl HAILO_VDMA_INTERRUPTS_ENABLE */ +-struct hailo_vdma_interrupts_enable_params { ++/* structure used in ioctl HAILO_VDMA_ENABLE_CHANNELS */ ++struct hailo_vdma_enable_channels_params { + uint32_t channels_bitmap_per_engine[MAX_VDMA_ENGINES]; // in + bool enable_timestamps_measure; // in + }; + +-/* structure used in ioctl HAILO_VDMA_INTERRUPTS_DISABLE */ +-struct hailo_vdma_interrupts_disable_params { ++/* structure used in ioctl HAILO_VDMA_DISABLE_CHANNELS */ ++struct hailo_vdma_disable_channels_params { + uint32_t channels_bitmap_per_engine[MAX_VDMA_ENGINES]; // in + }; + +@@ -237,7 +274,7 @@ struct hailo_vdma_interrupts_channel_dat + uint8_t engine_index; + uint8_t channel_index; + bool is_active; // If not activate, num_processed is ignored. +- uint16_t host_num_processed; ++ uint8_t transfers_completed; // Number of transfers completed. + uint8_t host_error; // Channel errors bits on source side + uint8_t device_error; // Channel errors bits on dest side + bool validation_success; // If the validation of the channel was successful +@@ -312,6 +349,10 @@ enum hailo_transfer_memory_type { + HAILO_TRANSFER_MEMORY_DMA_ENGINE1, + HAILO_TRANSFER_MEMORY_DMA_ENGINE2, + ++ // PCIe EP driver memories ++ HAILO_TRANSFER_MEMORY_PCIE_EP_CONFIG = 0x400, ++ HAILO_TRANSFER_MEMORY_PCIE_EP_BRIDGE, ++ + /** Max enum value to maintain ABI Integrity */ + HAILO_TRANSFER_MEMORY_MAX_ENUM = INT_MAX, + }; +@@ -352,15 +393,26 @@ enum hailo_board_type { + HAILO_BOARD_TYPE_HAILO8 = 0, + HAILO_BOARD_TYPE_HAILO15, + HAILO_BOARD_TYPE_PLUTO, ++ HAILO_BOARD_TYPE_HAILO10H, ++ HAILO_BOARD_TYPE_HAILO10H_LEGACY, + HAILO_BOARD_TYPE_COUNT, + + /** Max enum value to maintain ABI Integrity */ + HAILO_BOARD_TYPE_MAX_ENUM = INT_MAX + }; + ++enum hailo_accelerator_type { ++ HAILO_ACCELERATOR_TYPE_NNC, ++ HAILO_ACCELERATOR_TYPE_SOC, ++ ++ /** Max enum value to maintain ABI Integrity */ ++ HAILO_ACCELERATOR_TYPE_MAX_ENUM = INT_MAX ++}; ++ + enum hailo_dma_type { + HAILO_DMA_TYPE_PCIE, + HAILO_DMA_TYPE_DRAM, ++ HAILO_DMA_TYPE_PCI_EP, + + /** Max enum value to maintain ABI Integrity */ + HAILO_DMA_TYPE_MAX_ENUM = INT_MAX, +@@ -428,15 +480,6 @@ struct hailo_vdma_transfer_buffer { + uint32_t size; // in + }; + +-enum hailo_vdma_interrupts_domain { +- HAILO_VDMA_INTERRUPTS_DOMAIN_NONE = 0, +- HAILO_VDMA_INTERRUPTS_DOMAIN_DEVICE = (1 << 0), +- HAILO_VDMA_INTERRUPTS_DOMAIN_HOST = (1 << 1), +- +- /** Max enum value to maintain ABI Integrity */ +- HAILO_VDMA_INTERRUPTS_DOMAIN_MAX_ENUM = INT_MAX, +-}; +- + // We allow maximum 2 buffers per transfer since we may have an extra buffer + // to make sure each buffer is aligned to page size. + #define HAILO_MAX_BUFFERS_PER_SINGLE_TRANSFER (2) +@@ -460,6 +503,35 @@ struct hailo_vdma_launch_transfer_params + // more info (e.g desc complete status) + + uint32_t descs_programed; // out, amount of descriptors programed. ++ int launch_transfer_status; // out, status of the launch transfer call. (only used in case of error) ++}; ++ ++/* structure used in ioctl HAILO_SOC_CONNECT */ ++struct hailo_soc_connect_params { ++ uint8_t input_channel_index; // out ++ uint8_t output_channel_index; // out ++ uintptr_t input_desc_handle; // in ++ uintptr_t output_desc_handle; // in ++}; ++ ++/* structure used in ioctl HAILO_SOC_CLOSE */ ++struct hailo_soc_close_params { ++ uint8_t input_channel_index; // in ++ uint8_t output_channel_index; // in ++}; ++ ++/* structure used in ioctl HAILO_PCI_EP_ACCEPT */ ++struct hailo_pci_ep_accept_params { ++ uint8_t input_channel_index; // out ++ uint8_t output_channel_index; // out ++ uintptr_t input_desc_handle; // in ++ uintptr_t output_desc_handle; // in ++}; ++ ++/* structure used in ioctl HAILO_PCI_EP_CLOSE */ ++struct hailo_pci_ep_close_params { ++ uint8_t input_channel_index; // in ++ uint8_t output_channel_index; // in + }; + + #ifdef _MSC_VER +@@ -469,8 +541,8 @@ struct tCompatibleHailoIoctlData + ULONG_PTR Value; + union { + struct hailo_memory_transfer_params MemoryTransfer; +- struct hailo_vdma_interrupts_enable_params VdmaInterruptsEnable; +- struct hailo_vdma_interrupts_disable_params VdmaInterruptsDisable; ++ struct hailo_vdma_enable_channels_params VdmaEnableChannels; ++ struct hailo_vdma_disable_channels_params VdmaDisableChannels; + struct hailo_vdma_interrupts_read_timestamp_params VdmaInterruptsReadTimestamps; + struct hailo_vdma_interrupts_wait_params VdmaInterruptsWait; + struct hailo_vdma_buffer_sync_params VdmaBufferSync; +@@ -479,14 +551,17 @@ struct tCompatibleHailoIoctlData + struct hailo_vdma_buffer_unmap_params VdmaBufferUnmap; + struct hailo_desc_list_create_params DescListCreate; + struct hailo_desc_list_release_params DescListReleaseParam; +- struct hailo_desc_list_bind_vdma_buffer_params DescListBind; ++ struct hailo_desc_list_program_params DescListProgram; + struct hailo_d2h_notification D2HNotification; + struct hailo_device_properties DeviceProperties; + struct hailo_driver_info DriverInfo; +- struct hailo_non_linux_desc_list_mmap_params DescListMmap; + struct hailo_read_log_params ReadLog; + struct hailo_mark_as_in_use_params MarkAsInUse; + struct hailo_vdma_launch_transfer_params LaunchTransfer; ++ struct hailo_soc_connect_params ConnectParams; ++ struct hailo_soc_close_params SocCloseParams; ++ struct hailo_pci_ep_accept_params AcceptParams; ++ struct hailo_pci_ep_close_params PciEpCloseParams; + } Buffer; + }; + #endif // _MSC_VER +@@ -495,30 +570,20 @@ struct tCompatibleHailoIoctlData + + enum hailo_general_ioctl_code { + HAILO_MEMORY_TRANSFER_CODE, +- HAILO_FW_CONTROL_CODE, +- HAILO_READ_NOTIFICATION_CODE, +- HAILO_DISABLE_NOTIFICATION_CODE, + HAILO_QUERY_DEVICE_PROPERTIES_CODE, + HAILO_QUERY_DRIVER_INFO_CODE, +- HAILO_READ_LOG_CODE, +- HAILO_RESET_NN_CORE_CODE, + + // Must be last + HAILO_GENERAL_IOCTL_MAX_NR, + }; + + #define HAILO_MEMORY_TRANSFER _IOWR_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_MEMORY_TRANSFER_CODE, struct hailo_memory_transfer_params) +-#define HAILO_FW_CONTROL _IOWR_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_FW_CONTROL_CODE, struct hailo_fw_control) +-#define HAILO_READ_NOTIFICATION _IOW_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_READ_NOTIFICATION_CODE, struct hailo_d2h_notification) +-#define HAILO_DISABLE_NOTIFICATION _IO_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_DISABLE_NOTIFICATION_CODE) + #define HAILO_QUERY_DEVICE_PROPERTIES _IOW_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_QUERY_DEVICE_PROPERTIES_CODE, struct hailo_device_properties) + #define HAILO_QUERY_DRIVER_INFO _IOW_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_QUERY_DRIVER_INFO_CODE, struct hailo_driver_info) +-#define HAILO_READ_LOG _IOWR_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_READ_LOG_CODE, struct hailo_read_log_params) +-#define HAILO_RESET_NN_CORE _IO_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_RESET_NN_CORE_CODE) + + enum hailo_vdma_ioctl_code { +- HAILO_VDMA_INTERRUPTS_ENABLE_CODE, +- HAILO_VDMA_INTERRUPTS_DISABLE_CODE, ++ HAILO_VDMA_ENABLE_CHANNELS_CODE, ++ HAILO_VDMA_DISABLE_CHANNELS_CODE, + HAILO_VDMA_INTERRUPTS_WAIT_CODE, + HAILO_VDMA_INTERRUPTS_READ_TIMESTAMPS_CODE, + HAILO_VDMA_BUFFER_MAP_CODE, +@@ -526,7 +591,7 @@ enum hailo_vdma_ioctl_code { + HAILO_VDMA_BUFFER_SYNC_CODE, + HAILO_DESC_LIST_CREATE_CODE, + HAILO_DESC_LIST_RELEASE_CODE, +- HAILO_DESC_LIST_BIND_VDMA_BUFFER_CODE, ++ HAILO_DESC_LIST_PROGRAM_CODE, + HAILO_VDMA_LOW_MEMORY_BUFFER_ALLOC_CODE, + HAILO_VDMA_LOW_MEMORY_BUFFER_FREE_CODE, + HAILO_MARK_AS_IN_USE_CODE, +@@ -538,38 +603,67 @@ enum hailo_vdma_ioctl_code { + HAILO_VDMA_IOCTL_MAX_NR, + }; + +-#define HAILO_VDMA_INTERRUPTS_ENABLE _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_INTERRUPTS_ENABLE_CODE, struct hailo_vdma_interrupts_enable_params) +-#define HAILO_VDMA_INTERRUPTS_DISABLE _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_INTERRUPTS_DISABLE_CODE, struct hailo_vdma_interrupts_disable_params) ++#define HAILO_VDMA_ENABLE_CHANNELS _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_ENABLE_CHANNELS_CODE, struct hailo_vdma_enable_channels_params) ++#define HAILO_VDMA_DISABLE_CHANNELS _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_DISABLE_CHANNELS_CODE, struct hailo_vdma_disable_channels_params) + #define HAILO_VDMA_INTERRUPTS_WAIT _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_INTERRUPTS_WAIT_CODE, struct hailo_vdma_interrupts_wait_params) + #define HAILO_VDMA_INTERRUPTS_READ_TIMESTAMPS _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_INTERRUPTS_READ_TIMESTAMPS_CODE, struct hailo_vdma_interrupts_read_timestamp_params) + +-#define HAILO_VDMA_BUFFER_MAP _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_BUFFER_MAP_CODE, struct hailo_vdma_buffer_map_params) +-#define HAILO_VDMA_BUFFER_UNMAP _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_BUFFER_UNMAP_CODE, struct hailo_vdma_buffer_unmap_params) +-#define HAILO_VDMA_BUFFER_SYNC _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_BUFFER_SYNC_CODE, struct hailo_vdma_buffer_sync_params) ++#define HAILO_VDMA_BUFFER_MAP _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_BUFFER_MAP_CODE, struct hailo_vdma_buffer_map_params) ++#define HAILO_VDMA_BUFFER_UNMAP _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_BUFFER_UNMAP_CODE, struct hailo_vdma_buffer_unmap_params) ++#define HAILO_VDMA_BUFFER_SYNC _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_BUFFER_SYNC_CODE, struct hailo_vdma_buffer_sync_params) ++ ++#define HAILO_DESC_LIST_CREATE _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_DESC_LIST_CREATE_CODE, struct hailo_desc_list_create_params) ++#define HAILO_DESC_LIST_RELEASE _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_DESC_LIST_RELEASE_CODE, struct hailo_desc_list_release_params) ++#define HAILO_DESC_LIST_PROGRAM _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_DESC_LIST_PROGRAM_CODE, struct hailo_desc_list_program_params) + +-#define HAILO_DESC_LIST_CREATE _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_DESC_LIST_CREATE_CODE, struct hailo_desc_list_create_params) +-#define HAILO_DESC_LIST_RELEASE _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_DESC_LIST_RELEASE_CODE, struct hailo_desc_list_release_params) +-#define HAILO_DESC_LIST_BIND_VDMA_BUFFER _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_DESC_LIST_BIND_VDMA_BUFFER_CODE, struct hailo_desc_list_bind_vdma_buffer_params) ++#define HAILO_VDMA_LOW_MEMORY_BUFFER_ALLOC _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_LOW_MEMORY_BUFFER_ALLOC_CODE, struct hailo_allocate_low_memory_buffer_params) ++#define HAILO_VDMA_LOW_MEMORY_BUFFER_FREE _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_LOW_MEMORY_BUFFER_FREE_CODE, struct hailo_free_low_memory_buffer_params) + +-#define HAILO_VDMA_LOW_MEMORY_BUFFER_ALLOC _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_LOW_MEMORY_BUFFER_ALLOC_CODE, struct hailo_allocate_low_memory_buffer_params) +-#define HAILO_VDMA_LOW_MEMORY_BUFFER_FREE _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_LOW_MEMORY_BUFFER_FREE_CODE, struct hailo_free_low_memory_buffer_params) ++#define HAILO_MARK_AS_IN_USE _IOW_(HAILO_VDMA_IOCTL_MAGIC, HAILO_MARK_AS_IN_USE_CODE, struct hailo_mark_as_in_use_params) + +-#define HAILO_MARK_AS_IN_USE _IOW_(HAILO_VDMA_IOCTL_MAGIC, HAILO_MARK_AS_IN_USE_CODE, struct hailo_mark_as_in_use_params) ++#define HAILO_VDMA_CONTINUOUS_BUFFER_ALLOC _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CONTINUOUS_BUFFER_ALLOC_CODE, struct hailo_allocate_continuous_buffer_params) ++#define HAILO_VDMA_CONTINUOUS_BUFFER_FREE _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CONTINUOUS_BUFFER_FREE_CODE, struct hailo_free_continuous_buffer_params) + +-#define HAILO_VDMA_CONTINUOUS_BUFFER_ALLOC _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CONTINUOUS_BUFFER_ALLOC_CODE, struct hailo_allocate_continuous_buffer_params) +-#define HAILO_VDMA_CONTINUOUS_BUFFER_FREE _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CONTINUOUS_BUFFER_FREE_CODE, struct hailo_free_continuous_buffer_params) ++#define HAILO_VDMA_LAUNCH_TRANSFER _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_LAUNCH_TRANSFER_CODE, struct hailo_vdma_launch_transfer_params) + +-#define HAILO_VDMA_LAUNCH_TRANSFER _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_LAUNCH_TRANSFER_CODE, struct hailo_vdma_launch_transfer_params) ++enum hailo_nnc_ioctl_code { ++ HAILO_FW_CONTROL_CODE, ++ HAILO_READ_NOTIFICATION_CODE, ++ HAILO_DISABLE_NOTIFICATION_CODE, ++ HAILO_READ_LOG_CODE, ++ HAILO_RESET_NN_CORE_CODE, + ++ // Must be last ++ HAILO_NNC_IOCTL_MAX_NR ++}; + +-enum hailo_non_linux_ioctl_code { +- HAILO_NON_LINUX_DESC_LIST_MMAP_CODE, ++#define HAILO_FW_CONTROL _IOWR_(HAILO_NNC_IOCTL_MAGIC, HAILO_FW_CONTROL_CODE, struct hailo_fw_control) ++#define HAILO_READ_NOTIFICATION _IOW_(HAILO_NNC_IOCTL_MAGIC, HAILO_READ_NOTIFICATION_CODE, struct hailo_d2h_notification) ++#define HAILO_DISABLE_NOTIFICATION _IO_(HAILO_NNC_IOCTL_MAGIC, HAILO_DISABLE_NOTIFICATION_CODE) ++#define HAILO_READ_LOG _IOWR_(HAILO_NNC_IOCTL_MAGIC, HAILO_READ_LOG_CODE, struct hailo_read_log_params) ++#define HAILO_RESET_NN_CORE _IO_(HAILO_NNC_IOCTL_MAGIC, HAILO_RESET_NN_CORE_CODE) ++ ++enum hailo_soc_ioctl_code { ++ HAILO_SOC_IOCTL_CONNECT_CODE, ++ HAILO_SOC_IOCTL_CLOSE_CODE, + + // Must be last +- HAILO_NON_LINUX_IOCTL_MAX_NR, ++ HAILO_SOC_IOCTL_MAX_NR, + }; + +-#define HAILO_NON_LINUX_DESC_LIST_MMAP _IOWR_(HAILO_NON_LINUX_IOCTL_MAGIC, HAILO_NON_LINUX_DESC_LIST_MMAP_CODE, struct hailo_non_linux_desc_list_mmap_params) ++#define HAILO_SOC_CONNECT _IOWR_(HAILO_SOC_IOCTL_MAGIC, HAILO_SOC_IOCTL_CONNECT_CODE, struct hailo_soc_connect_params) ++#define HAILO_SOC_CLOSE _IOR_(HAILO_SOC_IOCTL_MAGIC, HAILO_SOC_IOCTL_CLOSE_CODE, struct hailo_soc_close_params) ++ ++ ++enum hailo_pci_ep_ioctl_code { ++ HAILO_PCI_EP_ACCEPT_CODE, ++ HAILO_PCI_EP_CLOSE_CODE, ++ ++ // Must be last ++ HAILO_PCI_EP_IOCTL_MAX_NR, ++}; + ++#define HAILO_PCI_EP_ACCEPT _IOWR_(HAILO_PCI_EP_IOCTL_MAGIC, HAILO_PCI_EP_ACCEPT_CODE, struct hailo_pci_ep_accept_params) ++#define HAILO_PCI_EP_CLOSE _IOR_(HAILO_PCI_EP_IOCTL_MAGIC, HAILO_PCI_EP_CLOSE_CODE, struct hailo_pci_ep_close_params) + + #endif /* _HAILO_IOCTL_COMMON_H_ */ +--- a/drivers/media/pci/hailo/common/hailo_resource.c ++++ b/drivers/media/pci/hailo/common/hailo_resource.c +@@ -1,4 +1,4 @@ +-// SPDX-License-Identifier: GPL-2.0 ++// SPDX-License-Identifier: MIT + /** + * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. + **/ +--- a/drivers/media/pci/hailo/common/hailo_resource.h ++++ b/drivers/media/pci/hailo/common/hailo_resource.h +@@ -1,4 +1,4 @@ +-// SPDX-License-Identifier: GPL-2.0 ++// SPDX-License-Identifier: MIT + /** + * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. + **/ +--- a/drivers/media/pci/hailo/common/pcie_common.c ++++ b/drivers/media/pci/hailo/common/pcie_common.c +@@ -1,4 +1,4 @@ +-// SPDX-License-Identifier: GPL-2.0 ++// SPDX-License-Identifier: MIT + /** + * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. + **/ +@@ -10,6 +10,8 @@ + #include + #include + #include ++#include ++#include + + + #define BSC_IMASK_HOST (0x0188) +@@ -19,14 +21,13 @@ + + #define PO2_ROUND_UP(size, alignment) ((size + alignment-1) & ~(alignment-1)) + +-#define ATR0_PARAM (0x17) +-#define ATR0_SRC_ADDR (0x0) +-#define ATR0_TRSL_ADDR2 (0x0) +-#define ATR0_TRSL_PARAM (6) ++#define ATR_PARAM (0x17) ++#define ATR_SRC_ADDR (0x0) ++#define ATR_TRSL_PARAM (6) ++#define ATR_TABLE_SIZE (0x1000u) ++#define ATR_TABLE_SIZE_MASK (0x1000u - 1) + + #define ATR0_PCIE_BRIDGE_OFFSET (0x700) +-#define ATR0_TABLE_SIZE (0x1000u) +-#define ATR0_TABLE_SIZE_MASK (0x1000u - 1) + + #define MAXIMUM_APP_FIRMWARE_CODE_SIZE (0x40000) + #define MAXIMUM_CORE_FIRMWARE_CODE_SIZE (0x20000) +@@ -45,8 +46,13 @@ + #define HAILO_PCIE_HOST_DMA_DATA_ID (0) + #define HAILO_PCIE_DMA_DEVICE_INTERRUPTS_BITMASK (1 << 4) + #define HAILO_PCIE_DMA_HOST_INTERRUPTS_BITMASK (1 << 5) ++#define HAILO_PCIE_DMA_SRC_CHANNELS_BITMASK (0x0000FFFF) + +-typedef u32 hailo_ptr_t; ++#define HAILO_PCIE_MAX_ATR_TABLE_INDEX (3) ++ ++#define MAX_FILES_PER_STAGE (4) ++ ++#define BOOT_STATUS_UNINITIALIZED (0x1) + + struct hailo_fw_addresses { + u32 boot_fw_header; +@@ -58,14 +64,11 @@ struct hailo_fw_addresses { + u32 core_fw_header; + u32 atr0_trsl_addr1; + u32 raise_ready_offset; ++ u32 boot_status; + }; + +-struct hailo_atr_config { +- u32 atr_param; +- u32 atr_src; +- u32 atr_trsl_addr_1; +- u32 atr_trsl_addr_2; +- u32 atr_trsl_param; ++struct loading_stage { ++ const struct hailo_file_batch *batch; + }; + + struct hailo_board_compatibility { +@@ -73,6 +76,69 @@ struct hailo_board_compatibility { + const char *fw_filename; + const struct hailo_config_constants board_cfg; + const struct hailo_config_constants fw_cfg; ++ const struct loading_stage stages[MAX_LOADING_STAGES]; ++}; ++ ++static const struct hailo_file_batch hailo10h_files_stg1[] = { ++ { ++ .filename = "hailo/hailo10h/customer_certificate.bin", ++ .address = 0xA0000, ++ .max_size = 0x8004, ++ .is_mandatory = true, ++ .has_header = false ++ }, ++ { ++ .filename = "hailo/hailo10h/u-boot.dtb.signed", ++ .address = 0xA8004, ++ .max_size = 0x20000, ++ .is_mandatory = true, ++ .has_header = false ++ }, ++ { ++ .filename = "hailo/hailo10h/scu_fw.bin", ++ .address = 0x20000, ++ .max_size = 0x40000, ++ .is_mandatory = true, ++ .has_header = true ++ }, ++ { ++ .filename = NULL, ++ .address = 0x00, ++ .max_size = 0x00, ++ .is_mandatory = false, ++ .has_header = false ++ } ++}; ++ ++static const struct hailo_file_batch hailo10h_files_stg2[] = { ++ { ++ .filename = "hailo/hailo10h/u-boot-spl.bin", ++ .address = 0x85000000, ++ .max_size = 0x1000000, ++ .is_mandatory = true, ++ .has_header = false ++ }, ++ { ++ .filename = "hailo/hailo10h/u-boot-tfa.itb", ++ .address = 0x86000000, ++ .max_size = 0x1000000, ++ .is_mandatory = true, ++ .has_header = false ++ }, ++ { ++ .filename = "hailo/hailo10h/fitImage", ++ .address = 0x87000000, ++ .max_size = 0x1000000, ++ .is_mandatory = true, ++ .has_header = false ++ }, ++ { ++ .filename = "hailo/hailo10h/core-image-minimal-hailo10-m2.ext4.gz", ++ .address = 0x88000000, ++ .max_size = 0x20000000, // Max size 512MB ++ .is_mandatory = true, ++ .has_header = false ++ }, + }; + + static const struct hailo_board_compatibility compat[HAILO_BOARD_TYPE_COUNT] = { +@@ -87,6 +153,7 @@ static const struct hailo_board_compatib + .core_fw_header = 0xA0000, + .atr0_trsl_addr1 = 0x60000000, + .raise_ready_offset = 0x1684, ++ .boot_status = 0xe0000, + }, + .fw_filename = "hailo/hailo8_fw.bin", + .board_cfg = { +@@ -100,7 +167,7 @@ static const struct hailo_board_compatib + .max_size = PCIE_HAILO8_FW_CFG_MAX_SIZE, + }, + }, +- [HAILO_BOARD_TYPE_HAILO15] = { ++ [HAILO_BOARD_TYPE_HAILO10H_LEGACY] = { + .fw_addresses = { + .boot_fw_header = 0x88000, + .boot_fw_trigger = 0x88c98, +@@ -111,6 +178,7 @@ static const struct hailo_board_compatib + .core_fw_header = 0xC0000, + .atr0_trsl_addr1 = 0x000BE000, + .raise_ready_offset = 0x1754, ++ .boot_status = 0x80000, + }, + .fw_filename = "hailo/hailo15_fw.bin", + .board_cfg = { +@@ -124,6 +192,39 @@ static const struct hailo_board_compatib + .max_size = 0, + }, + }, ++ [HAILO_BOARD_TYPE_HAILO10H] = { ++ .fw_addresses = { ++ .boot_fw_header = 0x88000, ++ .boot_fw_trigger = 0x88c98, ++ .boot_key_cert = 0x88018, ++ .boot_cont_cert = 0x886a8, ++ .app_fw_code_ram_base = 0x20000, ++ .core_code_ram_base = 0, ++ .core_fw_header = 0, ++ .atr0_trsl_addr1 = 0x000BE000, ++ .raise_ready_offset = 0x1754, ++ .boot_status = 0x80000, ++ }, ++ .fw_filename = NULL, ++ .board_cfg = { ++ .filename = NULL, ++ .address = 0, ++ .max_size = 0, ++ }, ++ .fw_cfg = { ++ .filename = NULL, ++ .address = 0, ++ .max_size = 0, ++ }, ++ .stages = { ++ { ++ .batch = hailo10h_files_stg1, ++ }, ++ { ++ .batch = hailo10h_files_stg2, ++ }, ++ }, ++ }, + // HRT-11344 : none of these matter except raise_ready_offset seeing as we load fw seperately - not through driver + // After implementing bootloader put correct values here + [HAILO_BOARD_TYPE_PLUTO] = { +@@ -138,6 +239,7 @@ static const struct hailo_board_compatib + .atr0_trsl_addr1 = 0x000BE000, + // NOTE: After they update hw consts - check register fw_access_interrupt_w1s of pcie_config + .raise_ready_offset = 0x174c, ++ .boot_status = 0x80000, + }, + .fw_filename = "hailo/pluto_fw.bin", + .board_cfg = { +@@ -225,7 +327,7 @@ int hailo_pcie_read_firmware_control(str + // Copy response buffer + hailo_resource_read_buffer(&resources->fw_access, PCIE_REQUEST_SIZE_OFFSET + (size_t)response_header_size, + command->buffer_len, &command->buffer); +- ++ + return 0; + } + +@@ -253,93 +355,111 @@ int hailo_pcie_read_firmware_notificatio + return hailo_read_firmware_notification(¬ification_resource, notification); + } + +-static void write_atr_table(struct hailo_pcie_resources *resources, +- struct hailo_atr_config *atr) ++int hailo_pcie_configure_atr_table(struct hailo_resource *bridge_config, u64 trsl_addr, u32 atr_index) + { +- hailo_resource_write_buffer(&resources->config, ATR0_PCIE_BRIDGE_OFFSET, +- sizeof(*atr), (void*)atr); +-} ++ size_t offset = 0; ++ struct hailo_atr_config atr = { ++ .atr_param = (ATR_PARAM | (atr_index << 12)), ++ .atr_src = ATR_SRC_ADDR, ++ .atr_trsl_addr_1 = (u32)(trsl_addr & 0xFFFFFFFF), ++ .atr_trsl_addr_2 = (u32)(trsl_addr >> 32), ++ .atr_trsl_param = ATR_TRSL_PARAM ++ }; + +-static void read_atr_table(struct hailo_pcie_resources *resources, +- struct hailo_atr_config *atr) +-{ +- hailo_resource_read_buffer(&resources->config, ATR0_PCIE_BRIDGE_OFFSET, +- sizeof(*atr), (void*)atr); ++ BUG_ON(HAILO_PCIE_MAX_ATR_TABLE_INDEX < atr_index); ++ offset = ATR0_PCIE_BRIDGE_OFFSET + (atr_index * 0x20); ++ ++ return hailo_resource_write_buffer(bridge_config, offset, sizeof(atr), (void*)&atr); + } + +-static void configure_atr_table(struct hailo_pcie_resources *resources, +- hailo_ptr_t base_address) ++void hailo_pcie_read_atr_table(struct hailo_resource *bridge_config, struct hailo_atr_config *atr, u32 atr_index) + { +- struct hailo_atr_config atr = { +- .atr_param = ATR0_PARAM, +- .atr_src = ATR0_SRC_ADDR, +- .atr_trsl_addr_1 = (u32)base_address, +- .atr_trsl_addr_2 = ATR0_TRSL_ADDR2, +- .atr_trsl_param = ATR0_TRSL_PARAM +- }; +- write_atr_table(resources, &atr); ++ size_t offset = 0; ++ ++ BUG_ON(HAILO_PCIE_MAX_ATR_TABLE_INDEX < atr_index); ++ offset = ATR0_PCIE_BRIDGE_OFFSET + (atr_index * 0x20); ++ ++ hailo_resource_read_buffer(bridge_config, offset, sizeof(*atr), (void*)atr); + } + + static void write_memory_chunk(struct hailo_pcie_resources *resources, + hailo_ptr_t dest, u32 dest_offset, const void *src, u32 len) + { ++ u32 ATR_INDEX = 0; + BUG_ON(dest_offset + len > (u32)resources->fw_access.size); + +- configure_atr_table(resources, dest); ++ (void)hailo_pcie_configure_atr_table(&resources->config, (u64)dest, ATR_INDEX); + (void)hailo_resource_write_buffer(&resources->fw_access, dest_offset, len, src); + } + + static void read_memory_chunk( + struct hailo_pcie_resources *resources, hailo_ptr_t src, u32 src_offset, void *dest, u32 len) + { ++ u32 ATR_INDEX = 0; + BUG_ON(src_offset + len > (u32)resources->fw_access.size); + +- configure_atr_table(resources, src); ++ (void)hailo_pcie_configure_atr_table(&resources->config, (u64)src, ATR_INDEX); + (void)hailo_resource_read_buffer(&resources->fw_access, src_offset, len, dest); + } + + // Note: this function modify the device ATR table (that is also used by the firmware for control and vdma). + // Use with caution, and restore the original atr if needed. +-static void write_memory(struct hailo_pcie_resources *resources, hailo_ptr_t dest, const void *src, u32 len) ++void write_memory(struct hailo_pcie_resources *resources, hailo_ptr_t dest, const void *src, u32 len) + { +- hailo_ptr_t base_address = dest & ~ATR0_TABLE_SIZE_MASK; ++ struct hailo_atr_config previous_atr = {0}; ++ hailo_ptr_t base_address = (dest & ~ATR_TABLE_SIZE_MASK); + u32 chunk_len = 0; + u32 offset = 0; ++ u32 ATR_INDEX = 0; ++ ++ // Store previous ATR (Read/write modify the ATR). ++ hailo_pcie_read_atr_table(&resources->config, &previous_atr, ATR_INDEX); + + if (base_address != dest) { + // Data is not aligned, write the first chunk +- chunk_len = min(base_address + ATR0_TABLE_SIZE - dest, len); ++ chunk_len = min(base_address + ATR_TABLE_SIZE - dest, len); + write_memory_chunk(resources, base_address, dest - base_address, src, chunk_len); + offset += chunk_len; + } + + while (offset < len) { +- chunk_len = min(len - offset, ATR0_TABLE_SIZE); ++ chunk_len = min(len - offset, ATR_TABLE_SIZE); + write_memory_chunk(resources, dest + offset, 0, (const u8*)src + offset, chunk_len); + offset += chunk_len; + } ++ ++ (void)hailo_pcie_configure_atr_table(&resources->config, ++ (((u64)(previous_atr.atr_trsl_addr_2) << 32) | previous_atr.atr_trsl_addr_1), ATR_INDEX); + } + + // Note: this function modify the device ATR table (that is also used by the firmware for control and vdma). + // Use with caution, and restore the original atr if needed. + static void read_memory(struct hailo_pcie_resources *resources, hailo_ptr_t src, void *dest, u32 len) + { +- hailo_ptr_t base_address = src & ~ATR0_TABLE_SIZE_MASK; ++ struct hailo_atr_config previous_atr = {0}; ++ hailo_ptr_t base_address = (src & ~ATR_TABLE_SIZE_MASK); + u32 chunk_len = 0; + u32 offset = 0; ++ u32 ATR_INDEX = 0; ++ ++ // Store previous ATR (Read/write modify the ATR). ++ hailo_pcie_read_atr_table(&resources->config, &previous_atr, ATR_INDEX); + + if (base_address != src) { + // Data is not aligned, write the first chunk +- chunk_len = min(base_address + ATR0_TABLE_SIZE - src, len); ++ chunk_len = min(base_address + ATR_TABLE_SIZE - src, len); + read_memory_chunk(resources, base_address, src - base_address, dest, chunk_len); + offset += chunk_len; + } + + while (offset < len) { +- chunk_len = min(len - offset, ATR0_TABLE_SIZE); ++ chunk_len = min(len - offset, ATR_TABLE_SIZE); + read_memory_chunk(resources, src + offset, 0, (u8*)dest + offset, chunk_len); + offset += chunk_len; + } ++ ++ (void)hailo_pcie_configure_atr_table(&resources->config, ++ (((u64)(previous_atr.atr_trsl_addr_2) << 32) | previous_atr.atr_trsl_addr_1), ATR_INDEX); + } + + static void hailo_write_app_firmware(struct hailo_pcie_resources *resources, firmware_header_t *fw_header, +@@ -367,7 +487,7 @@ static void hailo_write_core_firmware(st + write_memory(resources, fw_addresses->core_fw_header, fw_header, sizeof(firmware_header_t)); + } + +-static void hailo_trigger_firmware_boot(struct hailo_pcie_resources *resources) ++void hailo_trigger_firmware_boot(struct hailo_pcie_resources *resources) + { + const struct hailo_fw_addresses *fw_addresses = &(compat[resources->board_type].fw_addresses); + u32 pcie_finished = 1; +@@ -376,6 +496,17 @@ static void hailo_trigger_firmware_boot( + (void*)&pcie_finished, sizeof(pcie_finished)); + } + ++u32 hailo_get_boot_status(struct hailo_pcie_resources *resources) ++{ ++ u32 boot_status = 0; ++ const struct hailo_fw_addresses *fw_addresses = &(compat[resources->board_type].fw_addresses); ++ ++ read_memory(resources, fw_addresses->boot_status, ++ &boot_status, sizeof(boot_status)); ++ ++ return boot_status; ++} ++ + /** + * Validates the FW headers. + * @param[in] address Address of the firmware. +@@ -408,11 +539,14 @@ static int FW_VALIDATION__validate_fw_he + goto exit; + } + +- err = FW_VALIDATION__validate_fw_header(firmware_base_address, firmware_size, MAXIMUM_CORE_FIRMWARE_CODE_SIZE, +- &consumed_firmware_offset, &core_firmware_header, board_type); +- if (0 != err) { +- err = -EINVAL; +- goto exit; ++ // Not validating with HAILO10H since core firmware doesn't loaded over pcie ++ if (HAILO_BOARD_TYPE_HAILO10H != board_type) { ++ err = FW_VALIDATION__validate_fw_header(firmware_base_address, firmware_size, MAXIMUM_CORE_FIRMWARE_CODE_SIZE, ++ &consumed_firmware_offset, &core_firmware_header, board_type); ++ if (0 != err) { ++ err = -EINVAL; ++ goto exit; ++ } + } + + if (consumed_firmware_offset != firmware_size) { +@@ -437,6 +571,70 @@ exit: + return err; + } + ++static int write_single_file(struct hailo_pcie_resources *resources, const struct hailo_file_batch *files_batch, struct device *dev) ++{ ++ const struct firmware *firmware = NULL; ++ firmware_header_t *app_firmware_header = NULL; ++ secure_boot_certificate_t *firmware_cert = NULL; ++ firmware_header_t *core_firmware_header = NULL; ++ int err = 0; ++ ++ err = request_firmware_direct(&firmware, files_batch->filename, dev); ++ if (err < 0) { ++ return err; ++ } ++ ++ if (firmware->size > files_batch->max_size) { ++ release_firmware(firmware); ++ return -EFBIG; ++ } ++ ++ if (files_batch->has_header) { ++ err = FW_VALIDATION__validate_fw_headers((uintptr_t)firmware->data, firmware->size, ++ &app_firmware_header, &core_firmware_header, &firmware_cert, resources->board_type); ++ if (err < 0) { ++ release_firmware(firmware); ++ return err; ++ } ++ ++ hailo_write_app_firmware(resources, app_firmware_header, firmware_cert); ++ } else { ++ write_memory(resources, files_batch->address, (void*)firmware->data, firmware->size); ++ } ++ ++ release_firmware(firmware); ++ ++ return 0; ++} ++ ++int hailo_pcie_write_firmware_batch(struct device *dev, struct hailo_pcie_resources *resources, u32 stage) ++{ ++ const struct hailo_file_batch *files_batch = compat[resources->board_type].stages[stage].batch; ++ int file_index = 0; ++ int err = 0; ++ ++ for (file_index = 0; file_index < MAX_FILES_PER_STAGE; file_index++) ++ { ++ if (NULL == files_batch[file_index].filename) { ++ break; ++ } ++ ++ dev_notice(dev, "Writing file %s\n", files_batch[file_index].filename); ++ ++ err = write_single_file(resources, &files_batch[file_index], dev); ++ if (err < 0) { ++ pr_warn("Failed to write file %s\n", files_batch[file_index].filename); ++ if (files_batch[file_index].is_mandatory) { ++ return err; ++ } ++ } ++ ++ dev_notice(dev, "File %s written successfully\n", files_batch[file_index].filename); ++ } ++ ++ return 0; ++} ++ + int hailo_pcie_write_firmware(struct hailo_pcie_resources *resources, const void *fw_data, size_t fw_size) + { + firmware_header_t *app_firmware_header = NULL; +@@ -457,10 +655,25 @@ int hailo_pcie_write_firmware(struct hai + return 0; + } + ++// TODO: HRT-14147 - remove this function ++bool hailo_pcie_is_device_ready_for_boot(struct hailo_pcie_resources *resources) ++{ ++ return hailo_get_boot_status(resources) == BOOT_STATUS_UNINITIALIZED; ++} ++ + bool hailo_pcie_is_firmware_loaded(struct hailo_pcie_resources *resources) + { +- u32 offset = ATR0_PCIE_BRIDGE_OFFSET + offsetof(struct hailo_atr_config, atr_trsl_addr_1); +- u32 atr_value = hailo_resource_read32(&resources->config, offset); ++ u32 offset; ++ u32 atr_value; ++ ++ // TODO: HRT-14147 ++ if (HAILO_BOARD_TYPE_HAILO10H == resources->board_type) { ++ return !hailo_pcie_is_device_ready_for_boot(resources); ++ } ++ ++ offset = ATR0_PCIE_BRIDGE_OFFSET + offsetof(struct hailo_atr_config, atr_trsl_addr_1); ++ atr_value = hailo_resource_read32(&resources->config, offset); ++ + return atr_value == compat[resources->board_type].fw_addresses.atr0_trsl_addr1; + } + +@@ -516,7 +729,7 @@ void hailo_pcie_update_channel_interrupt + for (i = 0; i < MAX_VDMA_CHANNELS_PER_ENGINE; ++i) { + if (hailo_test_bit(i, &channels_bitmap)) { + // based on 18.5.2 "vDMA Interrupt Registers" in PLDA documentation +- u32 offset = (i < VDMA_DEST_CHANNELS_START) ? 0 : 8; ++ u32 offset = (i & 16) ? 8 : 0; + hailo_set_bit((((int)i*8) / MAX_VDMA_CHANNELS_PER_ENGINE) + offset, &mask); + } + } +@@ -531,7 +744,8 @@ void hailo_pcie_enable_interrupts(struct + hailo_resource_write32(&resources->config, BCS_DESTINATION_INTERRUPT_PER_CHANNEL, 0xFFFFFFFF); + hailo_resource_write32(&resources->config, BCS_SOURCE_INTERRUPT_PER_CHANNEL, 0xFFFFFFFF); + +- mask |= BCS_ISTATUS_HOST_FW_IRQ_CONTROL_MASK | BCS_ISTATUS_HOST_FW_IRQ_NOTIFICATION | BCS_ISTATUS_HOST_DRIVER_DOWN; ++ mask |= (BCS_ISTATUS_HOST_FW_IRQ_CONTROL_MASK | BCS_ISTATUS_HOST_FW_IRQ_NOTIFICATION | ++ BCS_ISTATUS_HOST_DRIVER_DOWN | BCS_ISTATUS_SOC_CONNECT_ACCEPTED); + hailo_resource_write32(&resources->config, BSC_IMASK_HOST, mask); + } + +@@ -569,16 +783,10 @@ long hailo_pcie_read_firmware_log(struct + static int direct_memory_transfer(struct hailo_pcie_resources *resources, + struct hailo_memory_transfer_params *params) + { +- int err = -EINVAL; +- struct hailo_atr_config previous_atr = {0}; +- + if (params->address > U32_MAX) { + return -EFAULT; + } + +- // Store previous ATR (Read/write modify the ATR). +- read_atr_table(resources, &previous_atr); +- + switch (params->transfer_direction) { + case TRANSFER_READ: + read_memory(resources, (u32)params->address, params->buffer, (u32)params->count); +@@ -587,14 +795,10 @@ static int direct_memory_transfer(struct + write_memory(resources, (u32)params->address, params->buffer, (u32)params->count); + break; + default: +- err = -EINVAL; +- goto restore_atr; ++ return -EINVAL; + } + +- err = 0; +-restore_atr: +- write_atr_table(resources, &previous_atr); +- return err; ++ return 0; + } + + int hailo_pcie_memory_transfer(struct hailo_pcie_resources *resources, struct hailo_memory_transfer_params *params) +@@ -623,6 +827,24 @@ bool hailo_pcie_is_device_connected(stru + return PCI_VENDOR_ID_HAILO == hailo_resource_read16(&resources->config, PCIE_CONFIG_VENDOR_OFFSET); + } + ++int hailo_set_device_type(struct hailo_pcie_resources *resources) ++{ ++ switch(resources->board_type) { ++ case HAILO_BOARD_TYPE_HAILO8: ++ case HAILO_BOARD_TYPE_HAILO10H_LEGACY: ++ case HAILO_BOARD_TYPE_PLUTO: ++ resources->accelerator_type = HAILO_ACCELERATOR_TYPE_NNC; ++ break; ++ case HAILO_BOARD_TYPE_HAILO10H: ++ resources->accelerator_type = HAILO_ACCELERATOR_TYPE_SOC; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ + // On PCIe, just return the address + static u64 encode_dma_address(dma_addr_t dma_address, u8 channel_id) + { +@@ -637,5 +859,14 @@ struct hailo_vdma_hw hailo_pcie_vdma_hw + .ddr_data_id = HAILO_PCIE_HOST_DMA_DATA_ID, + .device_interrupts_bitmask = HAILO_PCIE_DMA_DEVICE_INTERRUPTS_BITMASK, + .host_interrupts_bitmask = HAILO_PCIE_DMA_HOST_INTERRUPTS_BITMASK, ++ .src_channels_bitmask = HAILO_PCIE_DMA_SRC_CHANNELS_BITMASK, ++}; + +-}; +\ No newline at end of file ++void hailo_soc_write_soc_connect(struct hailo_pcie_resources *resources) ++{ ++ const struct hailo_fw_addresses *fw_addresses = &(compat[resources->board_type].fw_addresses); ++ const u32 soc_connect_value = FW_ACCESS_SOC_CONNECT_MASK; ++ ++ // Write shutdown flag to FW ++ hailo_resource_write32(&resources->fw_access, fw_addresses->raise_ready_offset, soc_connect_value); ++} +\ No newline at end of file +--- a/drivers/media/pci/hailo/common/pcie_common.h ++++ b/drivers/media/pci/hailo/common/pcie_common.h +@@ -1,4 +1,4 @@ +-// SPDX-License-Identifier: GPL-2.0 ++// SPDX-License-Identifier: MIT + /** + * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. + **/ +@@ -14,11 +14,13 @@ + #include "vdma_common.h" + + #include ++#include + + + #define BCS_ISTATUS_HOST_FW_IRQ_CONTROL_MASK (0x04000000) + #define BCS_ISTATUS_HOST_FW_IRQ_NOTIFICATION (0x02000000) + #define BCS_ISTATUS_HOST_DRIVER_DOWN (0x08000000) ++#define BCS_ISTATUS_SOC_CONNECT_ACCEPTED (0x10000000) + #define BCS_ISTATUS_HOST_VDMA_SRC_IRQ_MASK (0x000000FF) + #define BCS_ISTATUS_HOST_VDMA_DEST_IRQ_MASK (0x0000FF00) + +@@ -40,17 +42,35 @@ + #define PCI_DEVICE_ID_HAILO_HAILO15 0x45C4 + #define PCI_DEVICE_ID_HAILO_PLUTO 0x43a2 + ++typedef u32 hailo_ptr_t; ++ + struct hailo_pcie_resources { + struct hailo_resource config; // BAR0 + struct hailo_resource vdma_registers; // BAR2 + struct hailo_resource fw_access; // BAR4 + enum hailo_board_type board_type; ++ enum hailo_accelerator_type accelerator_type; ++}; ++ ++struct hailo_atr_config { ++ u32 atr_param; ++ u32 atr_src; ++ u32 atr_trsl_addr_1; ++ u32 atr_trsl_addr_2; ++ u32 atr_trsl_param; ++}; ++ ++enum loading_stages { ++ FIRST_STAGE = 0, ++ SECOND_STAGE = 1, ++ MAX_LOADING_STAGES = 2 + }; + + enum hailo_pcie_interrupt_masks { + FW_CONTROL = BCS_ISTATUS_HOST_FW_IRQ_CONTROL_MASK, + FW_NOTIFICATION = BCS_ISTATUS_HOST_FW_IRQ_NOTIFICATION, + DRIVER_DOWN = BCS_ISTATUS_HOST_DRIVER_DOWN, ++ SOC_CONNECT_ACCEPTED = BCS_ISTATUS_SOC_CONNECT_ACCEPTED, + VDMA_SRC_IRQ_MASK = BCS_ISTATUS_HOST_VDMA_SRC_IRQ_MASK, + VDMA_DEST_IRQ_MASK = BCS_ISTATUS_HOST_VDMA_DEST_IRQ_MASK + }; +@@ -66,6 +86,14 @@ struct hailo_config_constants { + size_t max_size; + }; + ++struct hailo_file_batch { ++ const char *filename; ++ u32 address; ++ size_t max_size; ++ bool is_mandatory; ++ bool has_header; ++}; ++ + // TODO: HRT-6144 - Align Windows/Linux to QNX + #ifdef __QNX__ + enum hailo_bar_index { +@@ -103,6 +131,7 @@ int hailo_pcie_write_firmware_control(st + int hailo_pcie_read_firmware_control(struct hailo_pcie_resources *resources, struct hailo_fw_control *command); + + int hailo_pcie_write_firmware(struct hailo_pcie_resources *resources, const void *fw_data, size_t fw_size); ++int hailo_pcie_write_firmware_batch(struct device *dev, struct hailo_pcie_resources *resources, u32 stage); + bool hailo_pcie_is_firmware_loaded(struct hailo_pcie_resources *resources); + bool hailo_pcie_wait_for_firmware(struct hailo_pcie_resources *resources); + +@@ -120,6 +149,17 @@ int hailo_pcie_memory_transfer(struct ha + + bool hailo_pcie_is_device_connected(struct hailo_pcie_resources *resources); + void hailo_pcie_write_firmware_driver_shutdown(struct hailo_pcie_resources *resources); ++void write_memory(struct hailo_pcie_resources *resources, hailo_ptr_t dest, const void *src, u32 len); ++void hailo_trigger_firmware_boot(struct hailo_pcie_resources *resources); ++ ++int hailo_set_device_type(struct hailo_pcie_resources *resources); ++ ++u32 hailo_get_boot_status(struct hailo_pcie_resources *resources); ++ ++int hailo_pcie_configure_atr_table(struct hailo_resource *bridge_config, u64 trsl_addr, u32 atr_index); ++void hailo_pcie_read_atr_table(struct hailo_resource *bridge_config, struct hailo_atr_config *atr, u32 atr_index); ++ ++void hailo_soc_write_soc_connect(struct hailo_pcie_resources *resources); + + #ifdef __cplusplus + } +--- a/drivers/media/pci/hailo/common/utils.h ++++ b/drivers/media/pci/hailo/common/utils.h +@@ -1,4 +1,4 @@ +-// SPDX-License-Identifier: GPL-2.0 ++// SPDX-License-Identifier: MIT + /** + * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. + **/ +@@ -11,6 +11,12 @@ + #define hailo_clear_bit(bit, pval) { *(pval) &= ~(1 << bit); } + #define hailo_test_bit(pos,var_addr) ((*var_addr) & (1<<(pos))) + ++#define READ_BITS_AT_OFFSET(amount_bits, offset, initial_value) \ ++ (((initial_value) >> (offset)) & ((1 << (amount_bits)) - 1)) ++#define WRITE_BITS_AT_OFFSET(amount_bits, offset, initial_value, value) \ ++ (((initial_value) & ~(((1 << (amount_bits)) - 1) << (offset))) | \ ++ (((value) & ((1 << (amount_bits)) - 1)) << (offset))) ++ + #ifdef __cplusplus + extern "C" + { +@@ -28,6 +34,22 @@ static inline void hailo_set_bit(int nr, + *p |= mask; + } + ++static inline uint8_t ceil_log2(uint32_t n) ++{ ++ uint8_t result = 0; ++ ++ if (n <= 1) { ++ return 0; ++ } ++ ++ while (n > 1) { ++ result++; ++ n = (n + 1) >> 1; ++ } ++ ++ return result; ++} ++ + #ifndef DIV_ROUND_UP + #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) + #endif +--- a/drivers/media/pci/hailo/common/vdma_common.c ++++ b/drivers/media/pci/hailo/common/vdma_common.c +@@ -1,4 +1,4 @@ +-// SPDX-License-Identifier: GPL-2.0 ++// SPDX-License-Identifier: MIT + /** + * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. + **/ +@@ -17,25 +17,37 @@ + + + #define CHANNEL_BASE_OFFSET(channel_index) ((channel_index) << 5) +-#define CHANNEL_HOST_OFFSET(channel_index) CHANNEL_BASE_OFFSET(channel_index) + \ +- (channel_index < VDMA_DEST_CHANNELS_START ? 0 : 0x10) +-#define CHANNEL_DEVICE_OFFSET(channel_index) CHANNEL_BASE_OFFSET(channel_index) + \ +- (channel_index < VDMA_DEST_CHANNELS_START ? 0x10 : 0) + + #define CHANNEL_CONTROL_OFFSET (0x0) ++#define CHANNEL_DEPTH_ID_OFFSET (0x1) + #define CHANNEL_NUM_AVAIL_OFFSET (0x2) + #define CHANNEL_NUM_PROC_OFFSET (0x4) + #define CHANNEL_ERROR_OFFSET (0x8) ++#define CHANNEL_DEST_REGS_OFFSET (0x10) + + #define VDMA_CHANNEL_CONTROL_START (0x1) + #define VDMA_CHANNEL_CONTROL_ABORT (0b00) + #define VDMA_CHANNEL_CONTROL_ABORT_PAUSE (0b10) + #define VDMA_CHANNEL_CONTROL_START_ABORT_PAUSE_RESUME_BITMASK (0x3) + #define VDMA_CHANNEL_CONTROL_START_ABORT_BITMASK (0x1) ++#define VDMA_CHANNEL_CONTROL_MASK (0xFC) ++#define VDMA_CHANNEL_CONTROL_START_RESUME (0b01) ++#define VDMA_CHANNEL_CONTROL_START_PAUSE (0b11) ++#define VDMA_CHANNEL_CONTROL_ABORT (0b00) ++#define VDMA_CHANNEL_CONTROL_ABORT_PAUSE (0b10) ++#define VDMA_CHANNEL_CONTROL_START_ABORT_PAUSE_RESUME_BITMASK (0x3) ++#define VDMA_CHANNEL_DESC_DEPTH_WIDTH (4) ++#define VDMA_CHANNEL_DESC_DEPTH_SHIFT (11) ++#define VDMA_CHANNEL_DATA_ID_SHIFT (8) ++#define VDMA_CHANNEL__MAX_CHECKS_CHANNEL_IS_IDLE (10000) ++#define VDMA_CHANNEL__ADDRESS_L_OFFSET (0x0A) ++#define VDMA_CHANNEL__ALIGNED_ADDRESS_L_OFFSET (0x8) ++#define VDMA_CHANNEL__ADDRESS_H_OFFSET (0x0C) + + #define DESCRIPTOR_PAGE_SIZE_SHIFT (8) + #define DESCRIPTOR_DESC_CONTROL (0x2) + #define DESCRIPTOR_ADDR_L_MASK (0xFFFFFFC0) ++#define DESCRIPTOR_LIST_MAX_DEPTH (16) + + #define DESCRIPTOR_DESC_STATUS_DONE_BIT (0x0) + #define DESCRIPTOR_DESC_STATUS_ERROR_BIT (0x1) +@@ -46,10 +58,14 @@ + #define DESC_REQUEST_IRQ_PROCESSED (1 << 2) + #define DESC_REQUEST_IRQ_ERR (1 << 3) + ++#define VDMA_CHANNEL_NUM_PROCESSED_WIDTH (16) ++#define VDMA_CHANNEL_NUM_PROCESSED_MASK ((1 << VDMA_CHANNEL_NUM_PROCESSED_WIDTH) - 1) ++#define VDMA_CHANNEL_NUM_ONGOING_MASK VDMA_CHANNEL_NUM_PROCESSED_MASK + + #define DWORD_SIZE (4) + #define WORD_SIZE (2) + #define BYTE_SIZE (1) ++#define BITS_IN_BYTE (8) + + #define TIMESTAMPS_CIRC_SPACE(timestamp_list) \ + CIRC_SPACE((timestamp_list).head, (timestamp_list).tail, CHANNEL_IRQ_TIMESTAMPS_SIZE) +@@ -146,18 +162,7 @@ void hailo_vdma_program_descriptor(struc + + static u8 get_channel_id(u8 channel_index) + { +- if (channel_index < VDMA_DEST_CHANNELS_START) { +- // H2D channel +- return channel_index; +- } +- else if ((channel_index >= VDMA_DEST_CHANNELS_START) && +- (channel_index < MAX_VDMA_CHANNELS_PER_ENGINE)) { +- // D2H channel +- return channel_index - VDMA_DEST_CHANNELS_START; +- } +- else { +- return INVALID_VDMA_CHANNEL; +- } ++ return (channel_index < MAX_VDMA_CHANNELS_PER_ENGINE) ? (channel_index & 0xF) : INVALID_VDMA_CHANNEL; + } + + static int program_descriptors_in_chunk( +@@ -198,12 +203,36 @@ static int program_descriptors_in_chunk( + return (int)desc_per_chunk; + } + +-int hailo_vdma_program_descriptors_list( ++static unsigned long get_interrupts_bitmask(struct hailo_vdma_hw *vdma_hw, ++ enum hailo_vdma_interrupts_domain interrupts_domain, bool is_debug) ++{ ++ unsigned long bitmask = 0; ++ ++ if (0 != (HAILO_VDMA_INTERRUPTS_DOMAIN_DEVICE & interrupts_domain)) { ++ bitmask |= vdma_hw->device_interrupts_bitmask; ++ } ++ if (0 != (HAILO_VDMA_INTERRUPTS_DOMAIN_HOST & interrupts_domain)) { ++ bitmask |= vdma_hw->host_interrupts_bitmask; ++ } ++ ++ if (bitmask != 0) { ++ bitmask |= DESC_REQUEST_IRQ_PROCESSED | DESC_REQUEST_IRQ_ERR; ++ if (is_debug) { ++ bitmask |= DESC_STATUS_REQ | DESC_STATUS_REQ_ERR; ++ } ++ } ++ ++ return bitmask; ++} ++ ++static int bind_and_program_descriptors_list( + struct hailo_vdma_hw *vdma_hw, + struct hailo_vdma_descriptors_list *desc_list, + u32 starting_desc, + struct hailo_vdma_mapped_transfer_buffer *buffer, +- u8 channel_index) ++ u8 channel_index, ++ enum hailo_vdma_interrupts_domain last_desc_interrupts, ++ bool is_debug) + { + const u8 channel_id = get_channel_id(channel_index); + int desc_programmed = 0; +@@ -260,9 +289,49 @@ int hailo_vdma_program_descriptors_list( + return -EFAULT; + } + ++ desc_list->desc_list[(starting_desc - 1) % desc_list->desc_count].PageSize_DescControl |= ++ get_interrupts_bitmask(vdma_hw, last_desc_interrupts, is_debug); ++ + return desc_programmed; + } + ++static int program_last_desc( ++ struct hailo_vdma_hw *vdma_hw, ++ struct hailo_vdma_descriptors_list *desc_list, ++ u32 starting_desc, ++ struct hailo_vdma_mapped_transfer_buffer *transfer_buffer, ++ enum hailo_vdma_interrupts_domain last_desc_interrupts, ++ bool is_debug) ++{ ++ u8 control = (u8)(DESCRIPTOR_DESC_CONTROL | get_interrupts_bitmask(vdma_hw, last_desc_interrupts, is_debug)); ++ u32 total_descs = DIV_ROUND_UP(transfer_buffer->size, desc_list->desc_page_size); ++ u32 last_desc = (starting_desc + total_descs - 1) % desc_list->desc_count; ++ u32 last_desc_size = transfer_buffer->size - (total_descs - 1) * desc_list->desc_page_size; ++ ++ // Configure only last descriptor with residue size ++ desc_list->desc_list[last_desc].PageSize_DescControl = (u32) ++ ((last_desc_size << DESCRIPTOR_PAGE_SIZE_SHIFT) + control); ++ return (int)total_descs; ++} ++ ++int hailo_vdma_program_descriptors_list( ++ struct hailo_vdma_hw *vdma_hw, ++ struct hailo_vdma_descriptors_list *desc_list, ++ u32 starting_desc, ++ struct hailo_vdma_mapped_transfer_buffer *buffer, ++ bool should_bind, ++ u8 channel_index, ++ enum hailo_vdma_interrupts_domain last_desc_interrupts, ++ bool is_debug) ++{ ++ return should_bind ? ++ bind_and_program_descriptors_list(vdma_hw, desc_list, starting_desc, ++ buffer, channel_index, last_desc_interrupts, is_debug) : ++ program_last_desc(vdma_hw, desc_list, starting_desc, buffer, ++ last_desc_interrupts, is_debug); ++} ++ ++ + static bool channel_control_reg_is_active(u8 control) + { + return (control & VDMA_CHANNEL_CONTROL_START_ABORT_BITMASK) == VDMA_CHANNEL_CONTROL_START; +@@ -270,12 +339,12 @@ static bool channel_control_reg_is_activ + + static int validate_channel_state(struct hailo_vdma_channel *channel) + { +- const u8 control = ioread8(channel->host_regs + CHANNEL_CONTROL_OFFSET); +- const u16 hw_num_avail = ioread16(channel->host_regs + CHANNEL_NUM_AVAIL_OFFSET); ++ u32 host_regs_value = ioread32(channel->host_regs); ++ const u8 control = READ_BITS_AT_OFFSET(BYTE_SIZE * BITS_IN_BYTE, CHANNEL_CONTROL_OFFSET * BITS_IN_BYTE, host_regs_value); ++ const u16 hw_num_avail = READ_BITS_AT_OFFSET(WORD_SIZE * BITS_IN_BYTE, CHANNEL_NUM_AVAIL_OFFSET * BITS_IN_BYTE, host_regs_value); + + if (!channel_control_reg_is_active(control)) { +- pr_err("Channel %d is not active\n", channel->index); +- return -EBUSY; ++ return -ECONNRESET; + } + + if (hw_num_avail != channel->state.num_avail) { +@@ -287,51 +356,16 @@ static int validate_channel_state(struct + return 0; + } + +-static unsigned long get_interrupts_bitmask(struct hailo_vdma_hw *vdma_hw, +- enum hailo_vdma_interrupts_domain interrupts_domain, bool is_debug) +-{ +- unsigned long bitmask = 0; +- +- if (0 != (HAILO_VDMA_INTERRUPTS_DOMAIN_DEVICE & interrupts_domain)) { +- bitmask |= vdma_hw->device_interrupts_bitmask; +- } +- if (0 != (HAILO_VDMA_INTERRUPTS_DOMAIN_HOST & interrupts_domain)) { +- bitmask |= vdma_hw->host_interrupts_bitmask; +- } +- +- if (bitmask != 0) { +- bitmask |= DESC_REQUEST_IRQ_PROCESSED | DESC_REQUEST_IRQ_ERR; +- if (is_debug) { +- bitmask |= DESC_STATUS_REQ | DESC_STATUS_REQ_ERR; +- } +- } +- +- return bitmask; +-} +- + static void set_num_avail(u8 __iomem *host_regs, u16 num_avail) + { +- iowrite16(num_avail, host_regs + CHANNEL_NUM_AVAIL_OFFSET); ++ u32 host_regs_val = ioread32(host_regs); ++ iowrite32(WRITE_BITS_AT_OFFSET(WORD_SIZE * BITS_IN_BYTE, CHANNEL_NUM_AVAIL_OFFSET * BITS_IN_BYTE, host_regs_val, num_avail), ++ host_regs); + } + + static u16 get_num_proc(u8 __iomem *host_regs) + { +- return ioread16(host_regs + CHANNEL_NUM_PROC_OFFSET); +-} +- +-static int program_last_desc( +- struct hailo_vdma_descriptors_list *desc_list, +- u32 starting_desc, +- struct hailo_vdma_mapped_transfer_buffer *transfer_buffer) +-{ +- u32 total_descs = DIV_ROUND_UP(transfer_buffer->size, desc_list->desc_page_size); +- u32 last_desc = (starting_desc + total_descs - 1) % desc_list->desc_count; +- u32 last_desc_size = transfer_buffer->size - (total_descs - 1) * desc_list->desc_page_size; +- +- // Configure only last descriptor with residue size +- desc_list->desc_list[last_desc].PageSize_DescControl = (u32) +- ((last_desc_size << DESCRIPTOR_PAGE_SIZE_SHIFT) + DESCRIPTOR_DESC_CONTROL); +- return (int)total_descs; ++ return READ_BITS_AT_OFFSET(WORD_SIZE * BITS_IN_BYTE, 0, ioread32(host_regs + CHANNEL_NUM_PROC_OFFSET)); + } + + int hailo_vdma_launch_transfer( +@@ -365,6 +399,11 @@ int hailo_vdma_launch_transfer( + return -EINVAL; + } + ++ ret = validate_channel_state(channel); ++ if (ret < 0) { ++ return ret; ++ } ++ + if (channel->state.num_avail != (u16)starting_desc) { + pr_err("Channel %d state out of sync. num available is %d, expected %d\n", + channel->index, channel->state.num_avail, (u16)starting_desc); +@@ -376,25 +415,17 @@ int hailo_vdma_launch_transfer( + return -EINVAL; + } + +- if (is_debug) { +- ret = validate_channel_state(channel); +- if (ret < 0) { +- return ret; +- } +- } +- + BUILD_BUG_ON_MSG((HAILO_MAX_BUFFERS_PER_SINGLE_TRANSFER + 1) != ARRAY_SIZE(ongoing_transfer.dirty_descs), + "Unexpected amount of dirty descriptors"); + ongoing_transfer.dirty_descs_count = buffers_count + 1; + ongoing_transfer.dirty_descs[0] = (u16)starting_desc; + + for (i = 0; i < buffers_count; i++) { +- ret = should_bind ? +- hailo_vdma_program_descriptors_list(vdma_hw, desc_list, starting_desc, &buffers[i], channel->index) : +- program_last_desc(desc_list, starting_desc, &buffers[i]); +- if (ret < 0) { +- return ret; +- } ++ ret = hailo_vdma_program_descriptors_list(vdma_hw, desc_list, ++ starting_desc, &buffers[i], should_bind, channel->index, ++ (i == (buffers_count - 1) ? last_desc_interrupts : HAILO_VDMA_INTERRUPTS_DOMAIN_NONE), ++ is_debug); ++ + total_descs += ret; + last_desc = (starting_desc + ret - 1) % desc_list->desc_count; + starting_desc = (starting_desc + ret) % desc_list->desc_count; +@@ -406,8 +437,6 @@ int hailo_vdma_launch_transfer( + + desc_list->desc_list[first_desc].PageSize_DescControl |= + get_interrupts_bitmask(vdma_hw, first_interrupts_domain, is_debug); +- desc_list->desc_list[last_desc].PageSize_DescControl |= +- get_interrupts_bitmask(vdma_hw, last_desc_interrupts, is_debug); + + ongoing_transfer.last_desc = (u16)last_desc; + ongoing_transfer.is_debug = is_debug; +@@ -477,8 +506,21 @@ static void channel_state_init(struct ha + state->desc_count_mask = U32_MAX; + } + ++static u8 __iomem *get_channel_regs(u8 __iomem *regs_base, u8 channel_index, bool is_host_side, u32 src_channels_bitmask) ++{ ++ // Check if getting host side regs or device side ++ u8 __iomem *channel_regs_base = regs_base + CHANNEL_BASE_OFFSET(channel_index); ++ if (is_host_side) { ++ return hailo_test_bit(channel_index, &src_channels_bitmask) ? channel_regs_base : ++ (channel_regs_base + CHANNEL_DEST_REGS_OFFSET); ++ } else { ++ return hailo_test_bit(channel_index, &src_channels_bitmask) ? (channel_regs_base + CHANNEL_DEST_REGS_OFFSET) : ++ channel_regs_base; ++ } ++} ++ + void hailo_vdma_engine_init(struct hailo_vdma_engine *engine, u8 engine_index, +- const struct hailo_resource *channel_registers) ++ const struct hailo_resource *channel_registers, u32 src_channels_bitmask) + { + u8 channel_index = 0; + struct hailo_vdma_channel *channel; +@@ -489,8 +531,8 @@ void hailo_vdma_engine_init(struct hailo + + for_each_vdma_channel(engine, channel, channel_index) { + u8 __iomem *regs_base = (u8 __iomem *)channel_registers->address; +- channel->host_regs = regs_base + CHANNEL_HOST_OFFSET(channel_index); +- channel->device_regs = regs_base + CHANNEL_DEVICE_OFFSET(channel_index); ++ channel->host_regs = get_channel_regs(regs_base, channel_index, true, src_channels_bitmask); ++ channel->device_regs = get_channel_regs(regs_base, channel_index, false, src_channels_bitmask); + channel->index = channel_index; + channel->timestamp_measure_enabled = false; + +@@ -502,7 +544,15 @@ void hailo_vdma_engine_init(struct hailo + } + } + +-void hailo_vdma_engine_enable_channel_interrupts(struct hailo_vdma_engine *engine, u32 bitmap, ++/** ++ * Enables the given channels bitmap in the given engine. Allows launching transfer ++ * and reading interrupts from the channels. ++ * ++ * @param engine - dma engine. ++ * @param bitmap - channels bitmap to enable. ++ * @param measure_timestamp - if set, allow interrupts timestamp measure. ++ */ ++void hailo_vdma_engine_enable_channels(struct hailo_vdma_engine *engine, u32 bitmap, + bool measure_timestamp) + { + struct hailo_vdma_channel *channel = NULL; +@@ -518,7 +568,14 @@ void hailo_vdma_engine_enable_channel_in + engine->enabled_channels |= bitmap; + } + +-void hailo_vdma_engine_disable_channel_interrupts(struct hailo_vdma_engine *engine, u32 bitmap) ++/** ++ * Disables the given channels bitmap in the given engine. ++ * ++ * @param engine - dma engine. ++ * @param bitmap - channels bitmap to enable. ++ * @param measure_timestamp - if set, allow interrupts timestamp measure. ++ */ ++void hailo_vdma_engine_disable_channels(struct hailo_vdma_engine *engine, u32 bitmap) + { + struct hailo_vdma_channel *channel = NULL; + u8 channel_index = 0; +@@ -582,11 +639,11 @@ void hailo_vdma_engine_set_channel_inter + } + + static void fill_channel_irq_data(struct hailo_vdma_interrupts_channel_data *irq_data, +- struct hailo_vdma_engine *engine, struct hailo_vdma_channel *channel, u16 num_proc, ++ struct hailo_vdma_engine *engine, struct hailo_vdma_channel *channel, u8 transfers_completed, + bool validation_success) + { +- u8 host_control = ioread8(channel->host_regs + CHANNEL_CONTROL_OFFSET); +- u8 device_control = ioread8(channel->device_regs + CHANNEL_CONTROL_OFFSET); ++ u8 host_control = READ_BITS_AT_OFFSET(BYTE_SIZE * BITS_IN_BYTE, CHANNEL_CONTROL_OFFSET * BITS_IN_BYTE, ioread32(channel->host_regs)); ++ u8 device_control = READ_BITS_AT_OFFSET(BYTE_SIZE * BITS_IN_BYTE, CHANNEL_CONTROL_OFFSET * BITS_IN_BYTE, ioread32(channel->device_regs)); + + irq_data->engine_index = engine->index; + irq_data->channel_index = channel->index; +@@ -594,9 +651,9 @@ static void fill_channel_irq_data(struct + irq_data->is_active = channel_control_reg_is_active(host_control) && + channel_control_reg_is_active(device_control); + +- irq_data->host_num_processed = num_proc; +- irq_data->host_error = ioread8(channel->host_regs + CHANNEL_ERROR_OFFSET); +- irq_data->device_error = ioread8(channel->device_regs + CHANNEL_ERROR_OFFSET); ++ irq_data->transfers_completed = transfers_completed; ++ irq_data->host_error = READ_BITS_AT_OFFSET(BYTE_SIZE * BITS_IN_BYTE, 0, ioread32(channel->host_regs + CHANNEL_ERROR_OFFSET)); ++ irq_data->device_error = READ_BITS_AT_OFFSET(BYTE_SIZE * BITS_IN_BYTE, 0, ioread32(channel->device_regs + CHANNEL_ERROR_OFFSET)); + irq_data->validation_success = validation_success; + } + +@@ -635,7 +692,12 @@ int hailo_vdma_engine_fill_irq_data(stru + bool validation_success = true; + + for_each_vdma_channel(engine, channel, channel_index) { ++ u8 transfers_completed = 0; + u16 hw_num_proc = U16_MAX; ++ ++ BUILD_BUG_ON_MSG(HAILO_VDMA_MAX_ONGOING_TRANSFERS >= U8_MAX, ++ "HAILO_VDMA_MAX_ONGOING_TRANSFERS must be less than U8_MAX to use transfers_completed as u8"); ++ + if (!hailo_test_bit(channel->index, &irq_channels_bitmap)) { + continue; + } +@@ -673,12 +735,143 @@ int hailo_vdma_engine_fill_irq_data(stru + channel->state.num_proc = (u16)((cur_transfer->last_desc + 1) & channel->state.desc_count_mask); + + ongoing_transfer_pop(channel, NULL); ++ transfers_completed++; + } + + fill_channel_irq_data(&irq_data->irq_data[irq_data->channels_count], +- engine, channel, hw_num_proc, validation_success); ++ engine, channel, transfers_completed, validation_success); + irq_data->channels_count++; + } + + return 0; ++} ++ ++// For all these functions - best way to optimize might be to not call the function when need to pause and then abort, ++// Rather read value once and maybe save ++// This function reads and writes the register - should try to make more optimized in future ++static void start_vdma_control_register(u8 __iomem *host_regs) ++{ ++ u32 host_regs_value = ioread32(host_regs); ++ iowrite32(WRITE_BITS_AT_OFFSET(BYTE_SIZE * BITS_IN_BYTE, CHANNEL_CONTROL_OFFSET * BITS_IN_BYTE, host_regs_value, ++ VDMA_CHANNEL_CONTROL_START_RESUME), host_regs); ++} ++ ++static void hailo_vdma_channel_pause(u8 __iomem *host_regs) ++{ ++ u32 host_regs_value = ioread32(host_regs); ++ iowrite32(WRITE_BITS_AT_OFFSET(BYTE_SIZE * BITS_IN_BYTE, CHANNEL_CONTROL_OFFSET * BITS_IN_BYTE, host_regs_value, ++ VDMA_CHANNEL_CONTROL_START_PAUSE), host_regs); ++} ++ ++// This function reads and writes the register - should try to make more optimized in future ++static void hailo_vdma_channel_abort(u8 __iomem *host_regs) ++{ ++ u32 host_regs_value = ioread32(host_regs); ++ iowrite32(WRITE_BITS_AT_OFFSET(BYTE_SIZE * BITS_IN_BYTE, CHANNEL_CONTROL_OFFSET * BITS_IN_BYTE, host_regs_value, ++ VDMA_CHANNEL_CONTROL_ABORT), host_regs); ++} ++ ++int hailo_vdma_start_channel(u8 __iomem *host_regs, uint64_t desc_dma_address, uint8_t desc_depth, ++ uint8_t data_id) ++{ ++ u16 dma_address_l = 0; ++ u32 dma_address_h = 0; ++ u32 desc_depth_data_id = 0; ++ ++ if (((desc_dma_address & 0xFFFF) != 0) || ++ (desc_depth > DESCRIPTOR_LIST_MAX_DEPTH)) { ++ return -EINVAL; ++ } ++ ++ // According to spec, depth 16 is equivalent to depth 0. ++ if (DESCRIPTOR_LIST_MAX_DEPTH == desc_depth) { ++ desc_depth = 0; ++ } ++ ++ // Stop old channel state ++ hailo_vdma_stop_channel(host_regs); ++ ++ // Configure address, depth and id ++ dma_address_l = (uint16_t)((desc_dma_address >> 16) & 0xFFFF); ++ iowrite32(WRITE_BITS_AT_OFFSET(WORD_SIZE * BITS_IN_BYTE, (VDMA_CHANNEL__ADDRESS_L_OFFSET - ++ VDMA_CHANNEL__ALIGNED_ADDRESS_L_OFFSET) * BITS_IN_BYTE, ioread32(host_regs + ++ VDMA_CHANNEL__ALIGNED_ADDRESS_L_OFFSET), dma_address_l), host_regs + VDMA_CHANNEL__ALIGNED_ADDRESS_L_OFFSET); ++ ++ dma_address_h = (uint32_t)(desc_dma_address >> 32); ++ iowrite32(dma_address_h, host_regs + VDMA_CHANNEL__ADDRESS_H_OFFSET); ++ ++ desc_depth_data_id = (uint32_t)(desc_depth << VDMA_CHANNEL_DESC_DEPTH_SHIFT) | ++ (data_id << VDMA_CHANNEL_DATA_ID_SHIFT); ++ iowrite32(desc_depth_data_id, host_regs); ++ ++ start_vdma_control_register(host_regs); ++ ++ return 0; ++} ++ ++static bool hailo_vdma_channel_is_idle(u8 __iomem *host_regs, size_t host_side_max_desc_count) ++{ ++ // Num processed and ongoing are next to each other in the memory. ++ // Reading them both in order to save BAR reads. ++ u32 host_side_num_processed_ongoing = ioread32(host_regs + CHANNEL_NUM_PROC_OFFSET); ++ u16 host_side_num_processed = (host_side_num_processed_ongoing & VDMA_CHANNEL_NUM_PROCESSED_MASK); ++ u16 host_side_num_ongoing = (host_side_num_processed_ongoing >> VDMA_CHANNEL_NUM_PROCESSED_WIDTH) & ++ VDMA_CHANNEL_NUM_ONGOING_MASK; ++ ++ if ((host_side_num_processed % host_side_max_desc_count) == (host_side_num_ongoing % host_side_max_desc_count)) { ++ return true; ++ } ++ ++ return false; ++} ++ ++static int hailo_vdma_wait_until_channel_idle(u8 __iomem *host_regs) ++{ ++ bool is_idle = false; ++ uint32_t check_counter = 0; ++ ++ u8 depth = (uint8_t)(READ_BITS_AT_OFFSET(VDMA_CHANNEL_DESC_DEPTH_WIDTH, VDMA_CHANNEL_DESC_DEPTH_SHIFT, ++ ioread32(host_regs))); ++ size_t host_side_max_desc_count = (size_t)(1 << depth); ++ ++ for (check_counter = 0; check_counter < VDMA_CHANNEL__MAX_CHECKS_CHANNEL_IS_IDLE; check_counter++) { ++ is_idle = hailo_vdma_channel_is_idle(host_regs, host_side_max_desc_count); ++ if (is_idle) { ++ return 0; ++ } ++ } ++ ++ return -ETIMEDOUT; ++} ++ ++void hailo_vdma_stop_channel(u8 __iomem *host_regs) ++{ ++ int err = 0; ++ u8 host_side_channel_regs = READ_BITS_AT_OFFSET(BYTE_SIZE * BITS_IN_BYTE, CHANNEL_CONTROL_OFFSET * BITS_IN_BYTE, ioread32(host_regs)); ++ ++ if ((host_side_channel_regs & VDMA_CHANNEL_CONTROL_START_ABORT_PAUSE_RESUME_BITMASK) == VDMA_CHANNEL_CONTROL_ABORT_PAUSE) { ++ // The channel is aborted (we set the channel to VDMA_CHANNEL_CONTROL_ABORT_PAUSE at the end of this function) ++ return; ++ } ++ ++ // Pause the channel ++ // The channel is paused to allow for "all transfers from fetched descriptors..." to be "...completed" ++ // (from PLDA PCIe refernce manual, "9.2.5 Starting a Channel and Transferring Data") ++ hailo_vdma_channel_pause(host_regs); ++ ++ // Even if channel is stuck and not idle, force abort and return error in the end ++ err = hailo_vdma_wait_until_channel_idle(host_regs); ++ // Success oriented - if error occured print error but still abort channel ++ if (err < 0) { ++ pr_err("Timeout occured while waiting for channel to become idle\n"); ++ } ++ ++ // Abort the channel (even of hailo_vdma_wait_until_channel_idle function fails) ++ hailo_vdma_channel_abort(host_regs); ++} ++ ++bool hailo_check_channel_index(u8 channel_index, u32 src_channels_bitmask, bool is_input_channel) ++{ ++ return is_input_channel ? hailo_test_bit(channel_index, &src_channels_bitmask) : ++ (!hailo_test_bit(channel_index, &src_channels_bitmask)); + } +\ No newline at end of file +--- a/drivers/media/pci/hailo/common/vdma_common.h ++++ b/drivers/media/pci/hailo/common/vdma_common.h +@@ -1,4 +1,4 @@ +-// SPDX-License-Identifier: GPL-2.0 ++// SPDX-License-Identifier: MIT + /** + * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. + **/ +@@ -30,8 +30,8 @@ struct hailo_vdma_descriptor { + + struct hailo_vdma_descriptors_list { + struct hailo_vdma_descriptor *desc_list; +- u32 desc_count; // Must be power of 2 if is_circular is set. +- u16 desc_page_size; ++ u32 desc_count; // Must be power of 2 if is_circular is set. ++ u16 desc_page_size; + bool is_circular; + }; + +@@ -127,6 +127,9 @@ struct hailo_vdma_hw { + // Bitmask needed to set on each descriptor to enable interrupts (either host/device). + unsigned long host_interrupts_bitmask; + unsigned long device_interrupts_bitmask; ++ ++ // Bitmask for each vdma hw, which channels are src side by index (on pcie/dram - 0x0000FFFF, pci ep - 0xFFFF0000) ++ u32 src_channels_bitmask; + }; + + #define _for_each_element_array(array, size, element, index) \ +@@ -147,7 +150,11 @@ void hailo_vdma_program_descriptor(struc + * @param starting_desc index of the first descriptor to program. If the list + * is circular, this function may wrap around the list. + * @param buffer buffer to program to the descriptors list. ++ * @param should_bind If false, assumes the buffer was already bound to the ++ * desc list. Used for optimization. + * @param channel_index channel index of the channel attached. ++ * @param last_desc_interrupts - interrupts settings on last descriptor. ++ * @param is_debug program descriptors for debug run. + * + * @return On success - the amount of descriptors programmed, negative value on error. + */ +@@ -156,7 +163,10 @@ int hailo_vdma_program_descriptors_list( + struct hailo_vdma_descriptors_list *desc_list, + u32 starting_desc, + struct hailo_vdma_mapped_transfer_buffer *buffer, +- u8 channel_index); ++ bool should_bind, ++ u8 channel_index, ++ enum hailo_vdma_interrupts_domain last_desc_interrupts, ++ bool is_debug); + + /** + * Launch a transfer on some vdma channel. Includes: +@@ -191,14 +201,12 @@ int hailo_vdma_launch_transfer( + bool is_debug); + + void hailo_vdma_engine_init(struct hailo_vdma_engine *engine, u8 engine_index, +- const struct hailo_resource *channel_registers); ++ const struct hailo_resource *channel_registers, u32 src_channels_bitmask); + +-// enable/disable channels interrupt (does not update interrupts mask because the +-// implementation is different between PCIe and DRAM DMA. To support it we +-// can add some ops struct to the engine). +-void hailo_vdma_engine_enable_channel_interrupts(struct hailo_vdma_engine *engine, u32 bitmap, ++void hailo_vdma_engine_enable_channels(struct hailo_vdma_engine *engine, u32 bitmap, + bool measure_timestamp); +-void hailo_vdma_engine_disable_channel_interrupts(struct hailo_vdma_engine *engine, u32 bitmap); ++ ++void hailo_vdma_engine_disable_channels(struct hailo_vdma_engine *engine, u32 bitmap); + + void hailo_vdma_engine_push_timestamps(struct hailo_vdma_engine *engine, u32 bitmap); + int hailo_vdma_engine_read_timestamps(struct hailo_vdma_engine *engine, +@@ -237,6 +245,12 @@ int hailo_vdma_engine_fill_irq_data(stru + struct hailo_vdma_engine *engine, u32 irq_channels_bitmap, + transfer_done_cb_t transfer_done, void *transfer_done_opaque); + ++int hailo_vdma_start_channel(u8 __iomem *host_regs, uint64_t desc_dma_address, uint8_t desc_depth, uint8_t data_id); ++ ++void hailo_vdma_stop_channel(u8 __iomem *host_regs); ++ ++bool hailo_check_channel_index(u8 channel_index, u32 src_channels_bitmask, bool is_input_channel); ++ + #ifdef __cplusplus + } + #endif +--- a/drivers/media/pci/hailo/src/fops.c ++++ b/drivers/media/pci/hailo/src/fops.c +@@ -19,7 +19,6 @@ + #include + #endif + +-#include "hailo_pcie_version.h" + #include "utils.h" + #include "fops.h" + #include "vdma_common.h" +@@ -27,6 +26,7 @@ + #include "vdma/memory.h" + #include "vdma/ioctl.h" + #include "utils/compact.h" ++#include "pci_soc_ioctl.h" + + + #if LINUX_VERSION_CODE >= KERNEL_VERSION( 4, 13, 0 ) +@@ -210,69 +210,66 @@ l_exit: + + int hailo_pcie_fops_release(struct inode *inode, struct file *filp) + { +- struct hailo_pcie_board *pBoard = (struct hailo_pcie_board *)filp->private_data; ++ struct hailo_pcie_board *board = (struct hailo_pcie_board *)filp->private_data; + struct hailo_file_context *context = NULL; + + u32 major = MAJOR(inode->i_rdev); + u32 minor = MINOR(inode->i_rdev); + +- if (pBoard) { +- hailo_info(pBoard, "(%d: %d-%d): fops_release\n", current->tgid, major, minor); ++ if (board) { ++ hailo_info(board, "(%d: %d-%d): fops_release\n", current->tgid, major, minor); + +- if (down_interruptible(&pBoard->mutex)) { +- hailo_err(pBoard, "fops_release down_interruptible failed"); +- return -ERESTARTSYS; +- } + +- context = find_file_context(pBoard, filp); ++ down(&board->mutex); ++ ++ context = find_file_context(board, filp); + if (NULL == context) { +- hailo_err(pBoard, "Invalid driver state, file context does not exist\n"); +- up(&pBoard->mutex); ++ hailo_err(board, "Invalid driver state, file context does not exist\n"); ++ up(&board->mutex); + return -EINVAL; + } + + if (false == context->is_valid) { + // File context is invalid, but open. It's OK to continue finalize and release it. +- hailo_err(pBoard, "Invalid file context\n"); ++ hailo_err(board, "Invalid file context\n"); + } + +- hailo_pcie_clear_notification_wait_list(pBoard, filp); ++ hailo_pcie_clear_notification_wait_list(board, filp); + +- if (filp == pBoard->vdma.used_by_filp) { +- if (hailo_pcie_driver_down(pBoard)) { +- hailo_err(pBoard, "Failed sending FW shutdown event"); ++ if (filp == board->vdma.used_by_filp) { ++ if (hailo_pcie_driver_down(board)) { ++ hailo_err(board, "Failed sending FW shutdown event"); + } + } + +- hailo_vdma_file_context_finalize(&context->vdma_context, &pBoard->vdma, filp); ++ hailo_vdma_file_context_finalize(&context->vdma_context, &board->vdma, filp); + release_file_context(context); + +- if (atomic_dec_and_test(&pBoard->ref_count)) { ++ if (atomic_dec_and_test(&board->ref_count)) { + // Disable interrupts +- hailo_disable_interrupts(pBoard); ++ hailo_disable_interrupts(board); + + if (power_mode_enabled()) { +- if (pBoard->pDev && pci_set_power_state(pBoard->pDev, PCI_D3hot) < 0) { +- hailo_err(pBoard, "Failed setting power state to D3hot"); ++ if (board->pDev && pci_set_power_state(board->pDev, PCI_D3hot) < 0) { ++ hailo_err(board, "Failed setting power state to D3hot"); + } + } + + // deallocate board if already removed +- if (!pBoard->pDev) { +- hailo_dbg(pBoard, "fops_close, freed board\n"); +- up(&pBoard->mutex); +- kfree(pBoard); +- pBoard = NULL; ++ if (!board->pDev) { ++ hailo_dbg(board, "fops_release, freed board\n"); ++ up(&board->mutex); ++ kfree(board); ++ board = NULL; + } else { +- +- hailo_dbg(pBoard, "fops_close, released resources for board\n"); +- up(&pBoard->mutex); ++ hailo_dbg(board, "fops_release, released resources for board\n"); ++ up(&board->mutex); + } + } else { +- up(&pBoard->mutex); ++ up(&board->mutex); + } + +- hailo_dbg(pBoard, "(%d: %d-%d): fops_close: SUCCESS on /dev/hailo%d\n", current->tgid, ++ hailo_dbg(board, "(%d: %d-%d): fops_release: SUCCESS on /dev/hailo%d\n", current->tgid, + major, minor, minor); + } + +@@ -394,6 +391,10 @@ irqreturn_t hailo_irqhandler(int irq, vo + } + } + ++ if (irq_source.interrupt_bitmask & SOC_CONNECT_ACCEPTED) { ++ complete_all(&board->soc_connect_accepted); ++ } ++ + if (0 != irq_source.vdma_channels_bitmap) { + hailo_vdma_irq_handler(&board->vdma, DEFAULT_VDMA_ENGINE_INDEX, + irq_source.vdma_channels_bitmap); +@@ -602,26 +603,35 @@ static long hailo_query_driver_info(stru + return 0; + } + +-static long hailo_general_ioctl(struct hailo_file_context *context, struct hailo_pcie_board *board, +- unsigned int cmd, unsigned long arg, struct file *filp, bool *should_up_board_mutex) ++static long hailo_general_ioctl(struct hailo_pcie_board *board, unsigned int cmd, unsigned long arg) + { + switch (cmd) { + case HAILO_MEMORY_TRANSFER: + return hailo_memory_transfer_ioctl(board, arg); ++ case HAILO_QUERY_DEVICE_PROPERTIES: ++ return hailo_query_device_properties(board, arg); ++ case HAILO_QUERY_DRIVER_INFO: ++ return hailo_query_driver_info(board, arg); ++ default: ++ hailo_err(board, "Invalid general ioctl code 0x%x (nr: %d)\n", cmd, _IOC_NR(cmd)); ++ return -ENOTTY; ++ } ++} ++ ++static long hailo_nnc_ioctl(struct hailo_pcie_board *board, unsigned int cmd, unsigned long arg, ++ struct file *filp, bool *should_up_board_mutex) ++{ ++ switch (cmd) { + case HAILO_FW_CONTROL: + return hailo_fw_control(board, arg, should_up_board_mutex); + case HAILO_READ_NOTIFICATION: + return hailo_read_notification_ioctl(board, arg, filp, should_up_board_mutex); + case HAILO_DISABLE_NOTIFICATION: + return hailo_disable_notification(board, filp); +- case HAILO_QUERY_DEVICE_PROPERTIES: +- return hailo_query_device_properties(board, arg); +- case HAILO_QUERY_DRIVER_INFO: +- return hailo_query_driver_info(board, arg); + case HAILO_READ_LOG: + return hailo_read_log_ioctl(board, arg); + default: +- hailo_err(board, "Invalid general ioctl code 0x%x (nr: %d)\n", cmd, _IOC_NR(cmd)); ++ hailo_err(board, "Invalid nnc ioctl code 0x%x (nr: %d)\n", cmd, _IOC_NR(cmd)); + return -ENOTTY; + } + } +@@ -673,12 +683,28 @@ long hailo_pcie_fops_unlockedioctl(struc + + switch (_IOC_TYPE(cmd)) { + case HAILO_GENERAL_IOCTL_MAGIC: +- err = hailo_general_ioctl(context, board, cmd, arg, filp, &should_up_board_mutex); ++ err = hailo_general_ioctl(board, cmd, arg); + break; + case HAILO_VDMA_IOCTL_MAGIC: + err = hailo_vdma_ioctl(&context->vdma_context, &board->vdma, cmd, arg, filp, &board->mutex, + &should_up_board_mutex); + break; ++ case HAILO_SOC_IOCTL_MAGIC: ++ if (HAILO_ACCELERATOR_TYPE_SOC != board->pcie_resources.accelerator_type) { ++ hailo_err(board, "Ioctl %d is not supported on this accelerator type\n", _IOC_TYPE(cmd)); ++ err = -EINVAL; ++ } else { ++ err = hailo_soc_ioctl(board, &context->vdma_context, &board->vdma, cmd, arg); ++ } ++ break; ++ case HAILO_NNC_IOCTL_MAGIC: ++ if (HAILO_ACCELERATOR_TYPE_NNC != board->pcie_resources.accelerator_type) { ++ hailo_err(board, "Ioctl %d is not supported on this accelerator type\n", _IOC_TYPE(cmd)); ++ err = -EINVAL; ++ } else { ++ err = hailo_nnc_ioctl(board, cmd, arg, filp, &should_up_board_mutex); ++ } ++ break; + default: + hailo_err(board, "Invalid ioctl type %d\n", _IOC_TYPE(cmd)); + err = -ENOTTY; +--- a/drivers/media/pci/hailo/src/fops.h ++++ b/drivers/media/pci/hailo/src/fops.h +@@ -11,6 +11,7 @@ int hailo_pcie_fops_release(struct inode + long hailo_pcie_fops_unlockedioctl(struct file* filp, unsigned int cmd, unsigned long arg); + int hailo_pcie_fops_mmap(struct file* filp, struct vm_area_struct *vma); + int hailo_pcie_driver_down(struct hailo_pcie_board *board); ++void hailo_pcie_ep_init(struct hailo_pcie_board *board); + + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) + irqreturn_t hailo_irqhandler(int irq, void* dev_id, struct pt_regs *regs); +--- /dev/null ++++ b/drivers/media/pci/hailo/src/pci_soc_ioctl.c +@@ -0,0 +1,155 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2024 Hailo Technologies Ltd. All rights reserved. ++ **/ ++#include "pci_soc_ioctl.h" ++ ++#include "utils.h" ++#include "vdma_common.h" ++#include "utils/logs.h" ++#include "vdma/memory.h" ++ ++#define PCI_SOC_VDMA_ENGINE_INDEX (0) ++#define PCI_SOC_WAIT_FOR_CONNECT_TIMEOUT_MS (10000) ++ ++long hailo_soc_ioctl(struct hailo_pcie_board *board, struct hailo_vdma_file_context *context, ++ struct hailo_vdma_controller *controller, unsigned int cmd, unsigned long arg) ++{ ++ switch (cmd) { ++ case HAILO_SOC_CONNECT: ++ return hailo_soc_connect_ioctl(board, context, controller, arg); ++ case HAILO_SOC_CLOSE: ++ return hailo_soc_close_ioctl(board, controller, arg); ++ default: ++ hailo_err(board, "Invalid pcie EP ioctl code 0x%x (nr: %d)\n", cmd, _IOC_NR(cmd)); ++ return -ENOTTY; ++ } ++} ++ ++long hailo_soc_connect_ioctl(struct hailo_pcie_board *board, struct hailo_vdma_file_context *context, ++ struct hailo_vdma_controller *controller, unsigned long arg) ++{ ++ struct hailo_soc_connect_params params; ++ struct hailo_vdma_channel *input_channel = NULL; ++ struct hailo_vdma_channel *output_channel = NULL; ++ struct hailo_vdma_engine *vdma_engine = NULL; ++ struct hailo_descriptors_list_buffer *input_descriptors_buffer = NULL; ++ struct hailo_descriptors_list_buffer *output_descriptors_buffer = NULL; ++ uint8_t depth = 0; ++ int err = 0; ++ long completion_result = 0; ++ ++ if (copy_from_user(¶ms, (void *)arg, sizeof(params))) { ++ hailo_err(board, "copy_from_user fail\n"); ++ return -ENOMEM; ++ } ++ ++ // TODO: have pci_ep choose the channel indexes the soc will use - for now use 0 and 16 ++ params.input_channel_index = 0; ++ params.output_channel_index = 16; ++ ++ reinit_completion(&board->soc_connect_accepted); ++ hailo_soc_write_soc_connect(&board->pcie_resources); ++ ++ // Wait for completion ++ completion_result = wait_for_completion_interruptible_timeout(&board->soc_connect_accepted, ++ msecs_to_jiffies(PCI_SOC_WAIT_FOR_CONNECT_TIMEOUT_MS)); ++ if (0 > completion_result) { ++ if (0 == completion_result) { ++ hailo_err(board, "Timeout waiting for connect to be accepted (timeout_ms=%d)\n", PCI_SOC_WAIT_FOR_CONNECT_TIMEOUT_MS); ++ return -ETIMEDOUT; ++ } else { ++ hailo_info(board, "soc connect failed with err=%ld (process was interrupted or killed)\n", ++ completion_result); ++ return -EINTR; ++ } ++ } ++ ++ vdma_engine = &controller->vdma_engines[PCI_SOC_VDMA_ENGINE_INDEX]; ++ input_channel = &vdma_engine->channels[params.input_channel_index]; ++ output_channel = &vdma_engine->channels[params.output_channel_index]; ++ ++ input_descriptors_buffer = hailo_vdma_find_descriptors_buffer(context, params.input_desc_handle); ++ output_descriptors_buffer = hailo_vdma_find_descriptors_buffer(context, params.output_desc_handle); ++ if (NULL == input_descriptors_buffer || NULL == output_descriptors_buffer) { ++ hailo_dev_err(&board->pDev->dev, "input / output descriptors buffer not found \n"); ++ return -EINVAL; ++ } ++ ++ // Make sure channels that we are accepting are not already enabled ++ if (0 != (vdma_engine->enabled_channels & params.input_channel_index) || ++ 0 != (vdma_engine->enabled_channels & params.output_channel_index)) { ++ hailo_dev_err(&board->pDev->dev, "Trying to accept already enabled channels\n"); ++ return -EINVAL; ++ } ++ ++ if (!is_powerof2((size_t)input_descriptors_buffer->desc_list.desc_count) || ++ !is_powerof2((size_t)output_descriptors_buffer->desc_list.desc_count)) { ++ hailo_dev_err(&board->pDev->dev, "Invalid desc list size\n"); ++ return -EINVAL; ++ } ++ ++ // configure and start input channel ++ depth = ceil_log2(input_descriptors_buffer->desc_list.desc_count); ++ // DMA Direction is only to get channel index - so ++ err = hailo_vdma_start_channel(input_channel->host_regs, input_descriptors_buffer->dma_address, depth, ++ board->vdma.hw->ddr_data_id); ++ if (err < 0) { ++ hailo_dev_err(&board->pDev->dev, "Error starting vdma input channel index %u\n", params.input_channel_index); ++ return -EINVAL; ++ } ++ ++ // configure and start output channel ++ depth = ceil_log2(output_descriptors_buffer->desc_list.desc_count); ++ // DMA Direction is only to get channel index - so ++ err = hailo_vdma_start_channel(output_channel->host_regs, output_descriptors_buffer->dma_address, depth, ++ board->vdma.hw->ddr_data_id); ++ if (err < 0) { ++ hailo_dev_err(&board->pDev->dev, "Error starting vdma output channel index %u\n", params.output_channel_index); ++ // Close input channel ++ hailo_vdma_stop_channel(input_channel->host_regs); ++ return -EINVAL; ++ } ++ ++ if (copy_to_user((void *)arg, ¶ms, sizeof(params))) { ++ hailo_dev_err(&board->pDev->dev, "copy_to_user fail\n"); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++long hailo_soc_close_ioctl(struct hailo_pcie_board *board, struct hailo_vdma_controller *controller, unsigned long arg) ++{ ++ struct hailo_soc_close_params params; ++ struct hailo_vdma_channel *input_channel = NULL; ++ struct hailo_vdma_channel *output_channel = NULL; ++ struct hailo_vdma_engine *vdma_engine = NULL; ++ ++ if (copy_from_user(¶ms, (void *)arg, sizeof(params))) { ++ hailo_dev_err(&board->pDev->dev, "copy_from_user fail\n"); ++ return -ENOMEM; ++ } ++ ++ vdma_engine = &controller->vdma_engines[PCI_SOC_VDMA_ENGINE_INDEX]; ++ ++ if (!hailo_check_channel_index(params.input_channel_index, controller->hw->src_channels_bitmask, true)) { ++ hailo_dev_err(&board->pDev->dev, "Invalid input channel index %u\n", params.input_channel_index); ++ return -EINVAL; ++ } ++ ++ if (!hailo_check_channel_index(params.output_channel_index, controller->hw->src_channels_bitmask, false)) { ++ hailo_dev_err(&board->pDev->dev, "Invalid output channel index %u\n", params.output_channel_index); ++ return -EINVAL; ++ } ++ ++ input_channel = &vdma_engine->channels[params.input_channel_index]; ++ output_channel = &vdma_engine->channels[params.output_channel_index]; ++ ++ // Close channels ++ hailo_vdma_stop_channel(input_channel->host_regs); ++ hailo_vdma_stop_channel(output_channel->host_regs); ++ ++ hailo_pcie_write_firmware_driver_shutdown(&board->pcie_resources); ++ return 0; ++} +\ No newline at end of file +--- /dev/null ++++ b/drivers/media/pci/hailo/src/pci_soc_ioctl.h +@@ -0,0 +1,19 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2024 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#ifndef _HAILO_PCI_SOC_IOCTL_H_ ++#define _HAILO_PCI_SOC_IOCTL_H_ ++ ++#include "vdma/ioctl.h" ++#include "pcie.h" ++ ++ ++long hailo_soc_ioctl(struct hailo_pcie_board *board, struct hailo_vdma_file_context *context, ++ struct hailo_vdma_controller *controller, unsigned int cmd, unsigned long arg); ++long hailo_soc_connect_ioctl(struct hailo_pcie_board *board, struct hailo_vdma_file_context *context, ++ struct hailo_vdma_controller *controller, unsigned long arg); ++long hailo_soc_close_ioctl(struct hailo_pcie_board *board, struct hailo_vdma_controller *controller, unsigned long arg); ++ ++#endif // _HAILO_PCI_SOC_IOCTL_H_ +\ No newline at end of file +--- a/drivers/media/pci/hailo/src/pcie.c ++++ b/drivers/media/pci/hailo/src/pcie.c +@@ -20,7 +20,6 @@ + + #define KERNEL_CODE 1 + +-#include "hailo_pcie_version.h" + #include "hailo_ioctl_common.h" + #include "pcie.h" + #include "fops.h" +@@ -45,6 +44,7 @@ enum hailo_allocate_driver_buffer_driver + static int force_desc_page_size = 0; + static bool g_is_power_mode_enabled = true; + static int force_allocation_from_driver = HAILO_NO_FORCE_BUFFER; ++static bool force_hailo15_legacy_mode = false; + + #define DEVICE_NODE_NAME "hailo" + static int char_major = 0; +@@ -322,7 +322,7 @@ static int hailo_write_config(struct hai + + static bool wait_for_firmware_completion(struct completion *fw_load_completion) + { +- return (0 != wait_for_completion_timeout(fw_load_completion, FIRMWARE_WAIT_TIMEOUT_MS)); ++ return (0 != wait_for_completion_timeout(fw_load_completion, msecs_to_jiffies(FIRMWARE_WAIT_TIMEOUT_MS))); + } + + static int hailo_load_firmware(struct hailo_pcie_resources *resources, +@@ -330,6 +330,7 @@ static int hailo_load_firmware(struct ha + { + const struct firmware *firmware = NULL; + int err = 0; ++ u32 boot_status = 0; + + if (hailo_pcie_is_firmware_loaded(resources)) { + hailo_dev_warn(dev, "Firmware was already loaded\n"); +@@ -368,7 +369,8 @@ static int hailo_load_firmware(struct ha + release_firmware(firmware); + + if (!wait_for_firmware_completion(fw_load_completion)) { +- hailo_dev_err(dev, "Timeout waiting for firmware..\n"); ++ boot_status = hailo_get_boot_status(resources); ++ hailo_dev_err(dev, "Timeout waiting for firmware file, boot status %u\n", boot_status); + return -ETIMEDOUT; + } + +@@ -376,6 +378,55 @@ static int hailo_load_firmware(struct ha + return 0; + } + ++static int hailo_load_firmware_batch(struct hailo_pcie_resources *resources, ++ struct device *dev, struct completion *fw_load_completion) ++{ ++ u32 boot_status = 0; ++ u32 pcie_finished = 1; ++ int err = 0; ++ ++ if (hailo_pcie_is_firmware_loaded(resources)) { ++ hailo_dev_warn(dev, "Firmware batch was already loaded\n"); ++ return 0; ++ } ++ ++ init_completion(fw_load_completion); ++ ++ err = hailo_pcie_write_firmware_batch(dev, resources, FIRST_STAGE); ++ if (err < 0) { ++ hailo_dev_err(dev, "Failed writing firmware files. err %d\n", err); ++ return err; ++ } ++ ++ hailo_trigger_firmware_boot(resources); ++ ++ if (!wait_for_firmware_completion(fw_load_completion)) { ++ boot_status = hailo_get_boot_status(resources); ++ hailo_dev_err(dev, "Timeout waiting for firmware file, boot status %u\n", boot_status); ++ return -ETIMEDOUT; ++ } ++ reinit_completion(fw_load_completion); ++ ++ err = hailo_pcie_write_firmware_batch(dev, resources, SECOND_STAGE); ++ if (err < 0) { ++ hailo_dev_err(dev, "Failed writing firmware files. err %d\n", err); ++ return err; ++ } ++ ++ // TODO: HRT-13838 - Remove, move address to compat, make write_memory static ++ write_memory(resources, 0x84000000, (void*)&pcie_finished, sizeof(pcie_finished)); ++ ++ if (!wait_for_firmware_completion(fw_load_completion)) { ++ boot_status = hailo_get_boot_status(resources); ++ hailo_dev_err(dev, "Timeout waiting for firmware file, boot status %u\n", boot_status); ++ return -ETIMEDOUT; ++ } ++ ++ hailo_dev_notice(dev, "Firmware Batch loaded successfully\n"); ++ ++ return 0; ++} ++ + static int hailo_activate_board(struct hailo_pcie_board *board) + { + int err = 0; +@@ -388,8 +439,21 @@ static int hailo_activate_board(struct h + return err; + } + +- err = hailo_load_firmware(&board->pcie_resources, &board->pDev->dev, +- &board->fw_loaded_completion); ++ switch (board->pcie_resources.board_type) { ++ case HAILO_BOARD_TYPE_HAILO10H: ++ err = hailo_load_firmware_batch(&board->pcie_resources, &board->pDev->dev, ++ &board->fw_loaded_completion); ++ break; ++ case HAILO_BOARD_TYPE_HAILO10H_LEGACY: ++ case HAILO_BOARD_TYPE_PLUTO: ++ case HAILO_BOARD_TYPE_HAILO8: ++ err = hailo_load_firmware(&board->pcie_resources, &board->pDev->dev, ++ &board->fw_loaded_completion); ++ break; ++ default: ++ hailo_err(board, "Invalid board type"); ++ err = -EINVAL; ++ } + if (err < 0) { + hailo_err(board, "Firmware load failed\n"); + hailo_disable_interrupts(board); +@@ -513,8 +577,23 @@ static int pcie_resources_init(struct pc + goto failure_release_vdma_regs; + } + ++ ++ // There is no HAILO15 as mercury through pcie unless it's legacy mode (H15 as accelerator) or HAILO-10H ++ if (HAILO_BOARD_TYPE_HAILO15 == board_type){ ++ if (true == force_hailo15_legacy_mode) { ++ board_type = HAILO_BOARD_TYPE_HAILO10H_LEGACY; ++ } else { ++ board_type = HAILO_BOARD_TYPE_HAILO10H; ++ } ++ } ++ + resources->board_type = board_type; + ++ err = hailo_set_device_type(resources); ++ if (err < 0) { ++ goto failure_release_fw_access; ++ } ++ + if (!hailo_pcie_is_device_connected(resources)) { + pci_err(pdev, "Probing: Failed reading device BARs, device may be disconnected\n"); + err = -ENODEV; +@@ -676,6 +755,7 @@ static int hailo_pcie_probe(struct pci_d + + pBoard->interrupts_enabled = false; + init_completion(&pBoard->fw_loaded_completion); ++ init_completion(&pBoard->soc_connect_accepted); + + sema_init(&pBoard->mutex, 1); + atomic_set(&pBoard->ref_count, 0); +@@ -1005,6 +1085,9 @@ MODULE_PARM_DESC(force_allocation_from_d + module_param(force_desc_page_size, int, S_IRUGO); + MODULE_PARM_DESC(force_desc_page_size, "Determines the maximum DMA descriptor page size (must be a power of 2)"); + ++module_param(force_hailo15_legacy_mode, bool, S_IRUGO); ++MODULE_PARM_DESC(force_hailo15_legacy_mode, "Forces work with Hailo15 in legacy mode(relevant for emulators)"); ++ + MODULE_AUTHOR("Hailo Technologies Ltd."); + MODULE_DESCRIPTION("Hailo PCIe driver"); + MODULE_LICENSE("GPL v2"); +--- a/drivers/media/pci/hailo/src/pcie.h ++++ b/drivers/media/pci/hailo/src/pcie.h +@@ -70,6 +70,8 @@ struct hailo_pcie_board { + enum hailo_allocation_mode allocation_mode; + struct completion fw_loaded_completion; + bool interrupts_enabled; ++ // Only needed in accelerator type soc ++ struct completion soc_connect_accepted; + }; + + bool power_mode_enabled(void); +--- a/drivers/media/pci/hailo/src/sysfs.c ++++ b/drivers/media/pci/hailo/src/sysfs.c +@@ -26,9 +26,18 @@ static ssize_t device_id_show(struct dev + } + static DEVICE_ATTR_RO(device_id); + ++static ssize_t accelerator_type_show(struct device *dev, struct device_attribute *_attr, ++ char *buf) ++{ ++ struct hailo_pcie_board *board = (struct hailo_pcie_board *)dev_get_drvdata(dev); ++ return sprintf(buf, "%d", board->pcie_resources.accelerator_type); ++} ++static DEVICE_ATTR_RO(accelerator_type); ++ + static struct attribute *hailo_dev_attrs[] = { + &dev_attr_board_location.attr, + &dev_attr_device_id.attr, ++ &dev_attr_accelerator_type.attr, + NULL + }; + +--- a/drivers/media/pci/hailo/src/utils.c ++++ b/drivers/media/pci/hailo/src/utils.c +@@ -8,7 +8,6 @@ + #include + #include + +-#include "hailo_pcie_version.h" + #include "pcie.h" + #include "utils.h" + #include "utils/logs.h" +--- /dev/null ++++ b/drivers/media/pci/hailo/utils/integrated_nnc_utils.c +@@ -0,0 +1,101 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#include "integrated_nnc_utils.h" ++#include "utils/logs.h" ++ ++#include ++#include ++#include ++#include ++ ++int hailo_ioremap_resource(struct platform_device *pdev, struct hailo_resource *resource, ++ const char *name) ++{ ++ void __iomem *address; ++ struct resource *platform_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); ++ if (NULL == platform_resource) { ++ return -ENOENT; ++ } ++ ++ address = devm_ioremap_resource(&pdev->dev, platform_resource); ++ if (IS_ERR(address)) { ++ return PTR_ERR(address); ++ } ++ ++ resource->address = (uintptr_t)address; ++ resource->size = resource_size(platform_resource); ++ ++ hailo_dev_dbg(&pdev->dev, "resource[%s]: remap %pr of %zx bytes to virtual start address %lx\n", ++ platform_resource->name, platform_resource, resource->size, (uintptr_t)address); ++ ++ return 0; ++} ++ ++// TODO: HRT-8475 - change to name instead of index ++int hailo_ioremap_shmem(struct platform_device *pdev, int index, struct hailo_resource *resource) ++{ ++ int ret; ++ struct resource res; ++ struct device_node *shmem; ++ void __iomem * remap_ptr; ++ ++ shmem = of_parse_phandle(pdev->dev.of_node, "shmem", index); ++ ret = of_address_to_resource(shmem, 0, &res); ++ if (ret) { ++ hailo_dev_err(&pdev->dev, "hailo_ioremap_shmem, failed to get memory (index: %d)\n", index); ++ return ret; ++ } ++ of_node_put(shmem); ++ ++ remap_ptr = devm_ioremap(&pdev->dev, res.start, resource_size(&res)); ++ if (!remap_ptr) { ++ hailo_dev_err(&pdev->dev, "hailo_ioremap_shmem, failed to ioremap shmem (index: %d)\n", index); ++ return -EADDRNOTAVAIL; ++ } ++ ++ resource->address = (uintptr_t)remap_ptr; ++ resource->size = resource_size(&res); ++ ++ return 0; ++} ++ ++int direct_memory_transfer(struct platform_device *pdev, struct hailo_memory_transfer_params *params) ++{ ++ int err = -EINVAL; ++ void __iomem *mem = ioremap(params->address, params->count); ++ if (NULL == mem) { ++ hailo_dev_err(&pdev->dev, "Failed ioremap %llu %zu\n", params->address, params->count); ++ return -ENOMEM; ++ } ++ ++ switch (params->transfer_direction) { ++ case TRANSFER_READ: ++ memcpy_fromio(params->buffer, mem, params->count); ++ err = 0; ++ break; ++ case TRANSFER_WRITE: ++ memcpy_toio(mem, params->buffer, params->count); ++ err = 0; ++ break; ++ default: ++ hailo_dev_err(&pdev->dev, "Invalid transfer direction %d\n", (int)params->transfer_direction); ++ err = -EINVAL; ++ } ++ ++ iounmap(mem); ++ return err; ++} ++ ++int hailo_get_resource_physical_addr(struct platform_device *pdev, const char *name, u64 *address) ++{ ++ struct resource *platform_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); ++ if (NULL == platform_resource) { ++ return -ENOENT; ++ } ++ ++ *address = (u64)(platform_resource->start); ++ return 0; ++} +\ No newline at end of file +--- /dev/null ++++ b/drivers/media/pci/hailo/utils/integrated_nnc_utils.h +@@ -0,0 +1,30 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#ifndef _INTEGRATED_NNC_UTILS_H_ ++#define _INTEGRATED_NNC_UTILS_H_ ++ ++#include ++#include "hailo_resource.h" ++ ++#define HAILO15_CORE_CONTROL_MAILBOX_INDEX (0) ++#define HAILO15_CORE_NOTIFICATION_MAILBOX_INDEX (1) ++#define HAILO15_CORE_DRIVER_DOWN_MAILBOX_INDEX (2) ++ ++#define HAILO15_CORE_CONTROL_MAILBOX_TX_SHMEM_INDEX (0) ++#define HAILO15_CORE_CONTROL_MAILBOX_RX_SHMEM_INDEX (1) ++#define HAILO15_CORE_NOTIFICATION_MAILBOX_RX_SHMEM_INDEX (2) ++ ++int hailo_ioremap_resource(struct platform_device *pdev, struct hailo_resource *resource, ++ const char *name); ++ ++// TODO: HRT-8475 - change to name instead of index ++int hailo_ioremap_shmem(struct platform_device *pdev, int index, struct hailo_resource *resource); ++ ++int direct_memory_transfer(struct platform_device *pDev, struct hailo_memory_transfer_params *params); ++ ++int hailo_get_resource_physical_addr(struct platform_device *pdev, const char *name, u64 *address); ++ ++#endif /* _INTEGRATED_NNC_UTILS_H_ */ +--- a/drivers/media/pci/hailo/vdma/ioctl.c ++++ b/drivers/media/pci/hailo/vdma/ioctl.c +@@ -12,9 +12,9 @@ + #include + + +-long hailo_vdma_interrupts_enable_ioctl(struct hailo_vdma_controller *controller, unsigned long arg) ++long hailo_vdma_enable_channels_ioctl(struct hailo_vdma_controller *controller, unsigned long arg) + { +- struct hailo_vdma_interrupts_enable_params input; ++ struct hailo_vdma_enable_channels_params input; + struct hailo_vdma_engine *engine = NULL; + u8 engine_index = 0; + u32 channels_bitmap = 0; +@@ -35,7 +35,7 @@ long hailo_vdma_interrupts_enable_ioctl( + + for_each_vdma_engine(controller, engine, engine_index) { + channels_bitmap = input.channels_bitmap_per_engine[engine_index]; +- hailo_vdma_engine_enable_channel_interrupts(engine, channels_bitmap, ++ hailo_vdma_engine_enable_channels(engine, channels_bitmap, + input.enable_timestamps_measure); + hailo_vdma_update_interrupts_mask(controller, engine_index); + hailo_dev_info(controller->dev, "Enabled interrupts for engine %u, channels bitmap 0x%x\n", +@@ -45,12 +45,13 @@ long hailo_vdma_interrupts_enable_ioctl( + return 0; + } + +-long hailo_vdma_interrupts_disable_ioctl(struct hailo_vdma_controller *controller, unsigned long arg) ++long hailo_vdma_disable_channels_ioctl(struct hailo_vdma_controller *controller, unsigned long arg) + { +- struct hailo_vdma_interrupts_disable_params input; ++ struct hailo_vdma_disable_channels_params input; + struct hailo_vdma_engine *engine = NULL; + u8 engine_index = 0; + u32 channels_bitmap = 0; ++ unsigned long irq_saved_flags = 0; + + if (copy_from_user(&input, (void*)arg, sizeof(input))) { + hailo_dev_err(controller->dev, "copy_from_user fail\n"); +@@ -61,15 +62,21 @@ long hailo_vdma_interrupts_disable_ioctl + for_each_vdma_engine(controller, engine, engine_index) { + channels_bitmap = input.channels_bitmap_per_engine[engine_index]; + if (channels_bitmap != (channels_bitmap & engine->enabled_channels)) { +- hailo_dev_err(controller->dev, "Trying to disable channels that were not enabled\n"); +- return -EINVAL; ++ hailo_dev_warn(controller->dev, "Trying to disable channels that were not enabled\n"); + } + } + + for_each_vdma_engine(controller, engine, engine_index) { + channels_bitmap = input.channels_bitmap_per_engine[engine_index]; +- hailo_vdma_engine_interrupts_disable(controller, engine, engine_index, +- channels_bitmap); ++ hailo_vdma_engine_disable_channels(engine, channels_bitmap); ++ hailo_vdma_update_interrupts_mask(controller, engine_index); ++ ++ spin_lock_irqsave(&controller->interrupts_lock, irq_saved_flags); ++ hailo_vdma_engine_clear_channel_interrupts(engine, channels_bitmap); ++ spin_unlock_irqrestore(&controller->interrupts_lock, irq_saved_flags); ++ ++ hailo_dev_info(controller->dev, "Disabled channels for engine %u, bitmap 0x%x\n", ++ engine_index, channels_bitmap); + } + + // Wake up threads waiting +@@ -197,7 +204,7 @@ long hailo_vdma_buffer_map_ioctl(struct + return -EFAULT; + } + +- hailo_dev_info(controller->dev, "address %px tgid %d size: %zu\n", ++ hailo_dev_info(controller->dev, "address %lx tgid %d size: %zu\n", + buf_info.user_address, current->tgid, buf_info.size); + + direction = get_dma_direction(buf_info.data_direction); +@@ -209,10 +216,9 @@ long hailo_vdma_buffer_map_ioctl(struct + low_memory_buffer = hailo_vdma_find_low_memory_buffer(context, buf_info.allocated_buffer_handle); + + mapped_buffer = hailo_vdma_buffer_map(controller->dev, +- buf_info.user_address, buf_info.size, direction, low_memory_buffer); ++ buf_info.user_address, buf_info.size, direction, buf_info.buffer_type, low_memory_buffer); + if (IS_ERR(mapped_buffer)) { +- hailo_dev_err(controller->dev, "failed map buffer %px\n", +- buf_info.user_address); ++ hailo_dev_err(controller->dev, "failed map buffer %lx\n", buf_info.user_address); + return PTR_ERR(mapped_buffer); + } + +@@ -225,7 +231,7 @@ long hailo_vdma_buffer_map_ioctl(struct + } + + list_add(&mapped_buffer->mapped_user_buffer_list, &context->mapped_user_buffer_list); +- hailo_dev_info(controller->dev, "buffer %px (handle %zu) is mapped\n", ++ hailo_dev_info(controller->dev, "buffer %lx (handle %zu) is mapped\n", + buf_info.user_address, buf_info.mapped_handle); + return 0; + } +@@ -374,10 +380,10 @@ long hailo_desc_list_release_ioctl(struc + return 0; + } + +-long hailo_desc_list_bind_vdma_buffer(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, ++long hailo_desc_list_program_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, + unsigned long arg) + { +- struct hailo_desc_list_bind_vdma_buffer_params configure_info; ++ struct hailo_desc_list_program_params configure_info; + struct hailo_vdma_buffer *mapped_buffer = NULL; + struct hailo_descriptors_list_buffer *descriptors_buffer = NULL; + struct hailo_vdma_mapped_transfer_buffer transfer_buffer = {0}; +@@ -410,7 +416,10 @@ long hailo_desc_list_bind_vdma_buffer(st + &descriptors_buffer->desc_list, + configure_info.starting_desc, + &transfer_buffer, +- configure_info.channel_index ++ configure_info.should_bind, ++ configure_info.channel_index, ++ configure_info.last_interrupts_domain, ++ configure_info.is_debug + ); + } + +@@ -683,11 +692,19 @@ long hailo_vdma_launch_transfer_ioctl(st + params.is_debug + ); + if (ret < 0) { +- hailo_dev_err(controller->dev, "Failed launch transfer %d\n", ret); ++ params.launch_transfer_status = ret; ++ if (-ECONNRESET != ret) { ++ hailo_dev_err(controller->dev, "Failed launch transfer %d\n", ret); ++ } ++ // Still need to copy fail status back to userspace - success oriented ++ if (copy_to_user((void __user*)arg, ¶ms, sizeof(params))) { ++ hailo_dev_err(controller->dev, "copy_to_user fail\n"); ++ } + return ret; + } + + params.descs_programed = ret; ++ params.launch_transfer_status = 0; + + if (copy_to_user((void __user*)arg, ¶ms, sizeof(params))) { + hailo_dev_err(controller->dev, "copy_to_user fail\n"); +--- a/drivers/media/pci/hailo/vdma/ioctl.h ++++ b/drivers/media/pci/hailo/vdma/ioctl.h +@@ -8,8 +8,8 @@ + + #include "vdma/vdma.h" + +-long hailo_vdma_interrupts_enable_ioctl(struct hailo_vdma_controller *controller, unsigned long arg); +-long hailo_vdma_interrupts_disable_ioctl(struct hailo_vdma_controller *controller, unsigned long arg); ++long hailo_vdma_enable_channels_ioctl(struct hailo_vdma_controller *controller, unsigned long arg); ++long hailo_vdma_disable_channels_ioctl(struct hailo_vdma_controller *controller, unsigned long arg); + long hailo_vdma_interrupts_wait_ioctl(struct hailo_vdma_controller *controller, unsigned long arg, + struct semaphore *mutex, bool *should_up_board_mutex); + +@@ -19,7 +19,7 @@ long hailo_vdma_buffer_sync_ioctl(struct + + long hailo_desc_list_create_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, unsigned long arg); + long hailo_desc_list_release_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, unsigned long arg); +-long hailo_desc_list_bind_vdma_buffer(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, unsigned long arg); ++long hailo_desc_list_program_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, unsigned long arg); + + long hailo_vdma_low_memory_buffer_alloc_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, unsigned long arg); + long hailo_vdma_low_memory_buffer_free_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, unsigned long arg); +--- a/drivers/media/pci/hailo/vdma/memory.c ++++ b/drivers/media/pci/hailo/vdma/memory.c +@@ -11,27 +11,107 @@ + #include + #include + #include ++#include + + + #define SGL_MAX_SEGMENT_SIZE (0x10000) + // See linux/mm.h + #define MMIO_AND_NO_PAGES_VMA_MASK (VM_IO | VM_PFNMAP) + +-static int map_mmio_address(void __user* user_address, u32 size, struct vm_area_struct *vma, ++static int map_mmio_address(uintptr_t user_address, u32 size, struct vm_area_struct *vma, + struct sg_table *sgt); +-static int prepare_sg_table(struct sg_table *sg_table, void __user* user_address, u32 size, ++static int prepare_sg_table(struct sg_table *sg_table, uintptr_t user_address, u32 size, + struct hailo_vdma_low_memory_buffer *low_mem_driver_allocated_buffer); + static void clear_sg_table(struct sg_table *sgt); + ++#if LINUX_VERSION_CODE >= KERNEL_VERSION( 3, 3, 0 ) ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0) ++// Import DMA_BUF namespace for needed kernels ++MODULE_IMPORT_NS(DMA_BUF); ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0) */ ++ ++static int hailo_map_dmabuf(struct device *dev, int dmabuf_fd, enum dma_data_direction direction, struct sg_table *sgt, ++ struct hailo_dmabuf_info *dmabuf_info) ++{ ++ int ret = -EINVAL; ++ struct dma_buf *dmabuf = NULL; ++ struct dma_buf_attachment *dmabuf_attachment = NULL; ++ struct sg_table *res_sgt = NULL; ++ ++ dmabuf = dma_buf_get(dmabuf_fd); ++ if (IS_ERR(dmabuf)) { ++ dev_err(dev, "dma_buf_get failed, err=%ld\n", PTR_ERR(dmabuf)); ++ ret = -EINVAL; ++ goto cleanup; ++ } ++ ++ dmabuf_attachment = dma_buf_attach(dmabuf, dev); ++ if (IS_ERR(dmabuf_attachment)) { ++ dev_err(dev, "dma_buf_attach failed, err=%ld\n", PTR_ERR(dmabuf_attachment)); ++ ret = -EINVAL; ++ goto l_buf_get; ++ } ++ ++ res_sgt = dma_buf_map_attachment(dmabuf_attachment, direction); ++ if (IS_ERR(res_sgt)) { ++ dev_err(dev, "dma_buf_map_attachment failed, err=%ld\n", PTR_ERR(res_sgt)); ++ goto l_buf_attach; ++ } ++ ++ *sgt = *res_sgt; ++ ++ dmabuf_info->dmabuf = dmabuf; ++ dmabuf_info->dmabuf_attachment = dmabuf_attachment; ++ dmabuf_info->dmabuf_sg_table = res_sgt; ++ return 0; ++ ++l_buf_attach: ++ dma_buf_detach(dmabuf, dmabuf_attachment); ++l_buf_get: ++ dma_buf_put(dmabuf); ++cleanup: ++ return ret; ++} ++ ++static void hailo_unmap_dmabuf(struct hailo_vdma_buffer *vdma_buffer) ++{ ++ dma_buf_unmap_attachment(vdma_buffer->dmabuf_info.dmabuf_attachment, vdma_buffer->dmabuf_info.dmabuf_sg_table, vdma_buffer->data_direction); ++ dma_buf_detach(vdma_buffer->dmabuf_info.dmabuf, vdma_buffer->dmabuf_info.dmabuf_attachment); ++ dma_buf_put(vdma_buffer->dmabuf_info.dmabuf); ++} ++ ++#else /* LINUX_VERSION_CODE >= KERNEL_VERSION( 3, 3, 0 ) */ ++ ++static int hailo_map_dmabuf(struct device *dev, int dmabuf_fd, enum dma_data_direction direction, struct sg_table *sgt, ++ struct hailo_dmabuf_info *dmabuf_info) ++{ ++ (void) dmabuf_fd; ++ (void) direction; ++ (void) sgt; ++ (void) mapped_buffer; ++ dev_err(dev, "dmabuf not supported in kernel versions lower than 3.3.0\n"); ++ return -EINVAL; ++} ++ ++static void hailo_unmap_dmabuf(struct hailo_vdma_buffer *vdma_buffer) ++{ ++ dev_err(vdma_buffer->device, "dmabuf not supported in kernel versions lower than 3.3.0\n"); ++ return -EINVAL; ++} ++ ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION( 3, 3, 0 ) */ ++ + struct hailo_vdma_buffer *hailo_vdma_buffer_map(struct device *dev, +- void __user *user_address, size_t size, enum dma_data_direction direction, +- struct hailo_vdma_low_memory_buffer *low_mem_driver_allocated_buffer) ++ uintptr_t user_address, size_t size, enum dma_data_direction direction, ++ enum hailo_dma_buffer_type buffer_type, struct hailo_vdma_low_memory_buffer *low_mem_driver_allocated_buffer) + { + int ret = -EINVAL; + struct hailo_vdma_buffer *mapped_buffer = NULL; + struct sg_table sgt = {0}; + struct vm_area_struct *vma = NULL; + bool is_mmio = false; ++ struct hailo_dmabuf_info dmabuf_info = {0}; + + mapped_buffer = kzalloc(sizeof(*mapped_buffer), GFP_KERNEL); + if (NULL == mapped_buffer) { +@@ -40,17 +120,19 @@ struct hailo_vdma_buffer *hailo_vdma_buf + goto cleanup; + } + +- if (IS_ENABLED(HAILO_SUPPORT_MMIO_DMA_MAPPING)) { +- vma = find_vma(current->mm, (uintptr_t)user_address); ++ if (IS_ENABLED(HAILO_SUPPORT_MMIO_DMA_MAPPING) && (HAILO_DMA_DMABUF_BUFFER != buffer_type)) { ++ vma = find_vma(current->mm, user_address); + if (NULL == vma) { +- dev_err(dev, "no vma for virt_addr/size = 0x%08lx/0x%08zx\n", (uintptr_t)user_address, size); ++ dev_err(dev, "no vma for virt_addr/size = 0x%08lx/0x%08zx\n", user_address, size); + ret = -EFAULT; + goto cleanup; + } + } + ++ // TODO: is MMIO DMA MAPPINGS STILL needed after dmabuf + if (IS_ENABLED(HAILO_SUPPORT_MMIO_DMA_MAPPING) && +- (MMIO_AND_NO_PAGES_VMA_MASK == (vma->vm_flags & MMIO_AND_NO_PAGES_VMA_MASK))) { ++ (MMIO_AND_NO_PAGES_VMA_MASK == (vma->vm_flags & MMIO_AND_NO_PAGES_VMA_MASK)) && ++ (HAILO_DMA_DMABUF_BUFFER != buffer_type)) { + // user_address represents memory mapped I/O and isn't backed by 'struct page' (only by pure pfn) + if (NULL != low_mem_driver_allocated_buffer) { + // low_mem_driver_allocated_buffer are backed by regular 'struct page' addresses, just in low memory +@@ -66,6 +148,14 @@ struct hailo_vdma_buffer *hailo_vdma_buf + } + + is_mmio = true; ++ ++ } else if (HAILO_DMA_DMABUF_BUFFER == buffer_type) { ++ // Content user_address in case of dmabuf is fd - for now ++ ret = hailo_map_dmabuf(dev, user_address, direction, &sgt, &dmabuf_info); ++ if (ret < 0) { ++ dev_err(dev, "Failed mapping dmabuf\n"); ++ goto cleanup; ++ } + } else { + // user_address is a standard 'struct page' backed memory address + ret = prepare_sg_table(&sgt, user_address, size, low_mem_driver_allocated_buffer); +@@ -88,6 +178,7 @@ struct hailo_vdma_buffer *hailo_vdma_buf + mapped_buffer->data_direction = direction; + mapped_buffer->sg_table = sgt; + mapped_buffer->is_mmio = is_mmio; ++ mapped_buffer->dmabuf_info = dmabuf_info; + + return mapped_buffer; + +@@ -103,11 +194,16 @@ static void unmap_buffer(struct kref *kr + { + struct hailo_vdma_buffer *buf = container_of(kref, struct hailo_vdma_buffer, kref); + +- if (!buf->is_mmio) { +- dma_unmap_sg(buf->device, buf->sg_table.sgl, buf->sg_table.orig_nents, buf->data_direction); +- } ++ // If dmabuf - unmap and detatch dmabuf ++ if (NULL != buf->dmabuf_info.dmabuf) { ++ hailo_unmap_dmabuf(buf); ++ } else { ++ if (!buf->is_mmio) { ++ dma_unmap_sg(buf->device, buf->sg_table.sgl, buf->sg_table.orig_nents, buf->data_direction); ++ } + +- clear_sg_table(&buf->sg_table); ++ clear_sg_table(&buf->sg_table); ++ } + kfree(buf); + } + +@@ -164,8 +260,9 @@ void hailo_vdma_buffer_sync(struct hailo + struct hailo_vdma_buffer *mapped_buffer, enum hailo_vdma_buffer_sync_type sync_type, + size_t offset, size_t size) + { +- if (IS_ENABLED(HAILO_SUPPORT_MMIO_DMA_MAPPING) && mapped_buffer->is_mmio) { +- // MMIO buffers don't need to be sync'd ++ if ((IS_ENABLED(HAILO_SUPPORT_MMIO_DMA_MAPPING) && mapped_buffer->is_mmio) || ++ (NULL != mapped_buffer->dmabuf_info.dmabuf)) { ++ // MMIO buffers and dmabufs don't need to be sync'd + return; + } + +@@ -404,7 +501,8 @@ void hailo_vdma_clear_continuous_buffer_ + + // Assumes the provided user_address belongs to the vma and that MMIO_AND_NO_PAGES_VMA_MASK bits are set under + // vma->vm_flags. This is validated in hailo_vdma_buffer_map, and won't be checked here +-static int map_mmio_address(void __user* user_address, u32 size, struct vm_area_struct *vma, ++#if defined(HAILO_SUPPORT_MMIO_DMA_MAPPING) ++static int map_mmio_address(uintptr_t user_address, u32 size, struct vm_area_struct *vma, + struct sg_table *sgt) + { + int ret = -EINVAL; +@@ -413,7 +511,7 @@ static int map_mmio_address(void __user* + unsigned long next_pfn = 0; + phys_addr_t phys_addr = 0; + dma_addr_t mmio_dma_address = 0; +- const uintptr_t virt_addr = (uintptr_t)user_address; ++ const uintptr_t virt_addr = user_address; + const u32 vma_size = vma->vm_end - vma->vm_start + 1; + const uintptr_t num_pages = PFN_UP(virt_addr + size) - PFN_DOWN(virt_addr); + +@@ -462,8 +560,21 @@ static int map_mmio_address(void __user* + + return 0; + } ++#else /* defined(HAILO_SUPPORT_MMIO_DMA_MAPPING) */ ++static int map_mmio_address(uintptr_t user_address, u32 size, struct vm_area_struct *vma, ++ struct sg_table *sgt) ++{ ++ (void) user_address; ++ (void) size; ++ (void) vma; ++ (void) sgt; ++ pr_err("MMIO DMA MAPPINGS are not supported in this kernel version\n"); ++ return -EINVAL; ++} ++#endif /* defined(HAILO_SUPPORT_MMIO_DMA_MAPPING) */ ++ + +-static int prepare_sg_table(struct sg_table *sg_table, void __user *user_address, u32 size, ++static int prepare_sg_table(struct sg_table *sg_table, uintptr_t user_address, u32 size, + struct hailo_vdma_low_memory_buffer *low_mem_driver_allocated_buffer) + { + int ret = -EINVAL; +@@ -482,8 +593,7 @@ static int prepare_sg_table(struct sg_ta + // Check whether mapping user allocated buffer or driver allocated low memory buffer + if (NULL == low_mem_driver_allocated_buffer) { + mmap_read_lock(current->mm); +- pinned_pages = get_user_pages_compact((unsigned long)user_address, +- npages, FOLL_WRITE | FOLL_FORCE, pages); ++ pinned_pages = get_user_pages_compact(user_address, npages, FOLL_WRITE | FOLL_FORCE, pages); + mmap_read_unlock(current->mm); + + if (pinned_pages < 0) { +--- a/drivers/media/pci/hailo/vdma/memory.h ++++ b/drivers/media/pci/hailo/vdma/memory.h +@@ -11,8 +11,8 @@ + + #include "vdma/vdma.h" + +-struct hailo_vdma_buffer *hailo_vdma_buffer_map(struct device *dev, +- void __user *user_address, size_t size, enum dma_data_direction direction, ++struct hailo_vdma_buffer *hailo_vdma_buffer_map(struct device *dev, uintptr_t user_address, size_t size, ++ enum dma_data_direction direction, enum hailo_dma_buffer_type buffer_type, + struct hailo_vdma_low_memory_buffer *low_mem_driver_allocated_buffer); + void hailo_vdma_buffer_get(struct hailo_vdma_buffer *buf); + void hailo_vdma_buffer_put(struct hailo_vdma_buffer *buf); +--- a/drivers/media/pci/hailo/vdma/vdma.c ++++ b/drivers/media/pci/hailo/vdma/vdma.c +@@ -21,7 +21,7 @@ + + + static struct hailo_vdma_engine* init_vdma_engines(struct device *dev, +- struct hailo_resource *channel_registers_per_engine, size_t engines_count) ++ struct hailo_resource *channel_registers_per_engine, size_t engines_count, u32 src_channels_bitmask) + { + struct hailo_vdma_engine *engines = NULL; + u8 i = 0; +@@ -33,7 +33,7 @@ static struct hailo_vdma_engine* init_vd + } + + for (i = 0; i < engines_count; i++) { +- hailo_vdma_engine_init(&engines[i], i, &channel_registers_per_engine[i]); ++ hailo_vdma_engine_init(&engines[i], i, &channel_registers_per_engine[i], src_channels_bitmask); + } + + return engines; +@@ -72,7 +72,8 @@ int hailo_vdma_controller_init(struct ha + controller->dev = dev; + + controller->vdma_engines_count = engines_count; +- controller->vdma_engines = init_vdma_engines(dev, channel_registers_per_engine, engines_count); ++ controller->vdma_engines = init_vdma_engines(dev, channel_registers_per_engine, engines_count, ++ vdma_hw->src_channels_bitmask); + if (IS_ERR(controller->vdma_engines)) { + dev_err(dev, "Failed initialized vdma engines\n"); + return PTR_ERR(controller->vdma_engines); +@@ -113,36 +114,27 @@ void hailo_vdma_update_interrupts_mask(s + controller->ops->update_channel_interrupts(controller, engine_index, engine->enabled_channels); + } + +-void hailo_vdma_engine_interrupts_disable(struct hailo_vdma_controller *controller, +- struct hailo_vdma_engine *engine, u8 engine_index, u32 channels_bitmap) +-{ +- unsigned long irq_saved_flags = 0; +- // In case of FLR, the vdma registers will be NULL +- const bool is_device_up = (NULL != controller->dev); +- +- hailo_vdma_engine_disable_channel_interrupts(engine, channels_bitmap); +- if (is_device_up) { +- hailo_vdma_update_interrupts_mask(controller, engine_index); +- } +- +- spin_lock_irqsave(&controller->interrupts_lock, irq_saved_flags); +- hailo_vdma_engine_clear_channel_interrupts(engine, channels_bitmap); +- spin_unlock_irqrestore(&controller->interrupts_lock, irq_saved_flags); +- +- hailo_dev_info(controller->dev, "Disabled interrupts for engine %u, channels bitmap 0x%x\n", +- engine_index, channels_bitmap); +-} +- + void hailo_vdma_file_context_finalize(struct hailo_vdma_file_context *context, + struct hailo_vdma_controller *controller, struct file *filp) + { + size_t engine_index = 0; + struct hailo_vdma_engine *engine = NULL; + const u32 channels_bitmap = 0xFFFFFFFF; // disable all channel interrupts ++ unsigned long irq_saved_flags = 0; ++ // In case of FLR, the vdma registers will be NULL ++ const bool is_device_up = (NULL != controller->dev); + + if (filp == controller->used_by_filp) { + for_each_vdma_engine(controller, engine, engine_index) { +- hailo_vdma_engine_interrupts_disable(controller, engine, engine_index, channels_bitmap); ++ hailo_vdma_engine_disable_channels(engine, channels_bitmap); ++ ++ if (is_device_up) { ++ hailo_vdma_update_interrupts_mask(controller, engine_index); ++ } ++ ++ spin_lock_irqsave(&controller->interrupts_lock, irq_saved_flags); ++ hailo_vdma_engine_clear_channel_interrupts(engine, channels_bitmap); ++ spin_unlock_irqrestore(&controller->interrupts_lock, irq_saved_flags); + } + } + +@@ -178,10 +170,10 @@ long hailo_vdma_ioctl(struct hailo_vdma_ + unsigned int cmd, unsigned long arg, struct file *filp, struct semaphore *mutex, bool *should_up_board_mutex) + { + switch (cmd) { +- case HAILO_VDMA_INTERRUPTS_ENABLE: +- return hailo_vdma_interrupts_enable_ioctl(controller, arg); +- case HAILO_VDMA_INTERRUPTS_DISABLE: +- return hailo_vdma_interrupts_disable_ioctl(controller, arg); ++ case HAILO_VDMA_ENABLE_CHANNELS: ++ return hailo_vdma_enable_channels_ioctl(controller, arg); ++ case HAILO_VDMA_DISABLE_CHANNELS: ++ return hailo_vdma_disable_channels_ioctl(controller, arg); + case HAILO_VDMA_INTERRUPTS_WAIT: + return hailo_vdma_interrupts_wait_ioctl(controller, arg, mutex, should_up_board_mutex); + case HAILO_VDMA_INTERRUPTS_READ_TIMESTAMPS: +@@ -196,8 +188,8 @@ long hailo_vdma_ioctl(struct hailo_vdma_ + return hailo_desc_list_create_ioctl(context, controller, arg); + case HAILO_DESC_LIST_RELEASE: + return hailo_desc_list_release_ioctl(context, controller, arg); +- case HAILO_DESC_LIST_BIND_VDMA_BUFFER: +- return hailo_desc_list_bind_vdma_buffer(context, controller, arg); ++ case HAILO_DESC_LIST_PROGRAM: ++ return hailo_desc_list_program_ioctl(context, controller, arg); + case HAILO_VDMA_LOW_MEMORY_BUFFER_ALLOC: + return hailo_vdma_low_memory_buffer_alloc_ioctl(context, controller, arg); + case HAILO_VDMA_LOW_MEMORY_BUFFER_FREE: +@@ -216,28 +208,6 @@ long hailo_vdma_ioctl(struct hailo_vdma_ + } + } + +-static int desc_list_mmap(struct hailo_vdma_controller *controller, +- struct hailo_descriptors_list_buffer *vdma_descriptors_buffer, struct vm_area_struct *vma) +-{ +- int err = 0; +- unsigned long vsize = vma->vm_end - vma->vm_start; +- +- if (vsize > vdma_descriptors_buffer->buffer_size) { +- hailo_dev_err(controller->dev, "Requested size to map (%lx) is larger than the descriptor list size(%x)\n", +- vsize, vdma_descriptors_buffer->buffer_size); +- return -EINVAL; +- } +- +- err = dma_mmap_coherent(controller->dev, vma, vdma_descriptors_buffer->kernel_address, +- vdma_descriptors_buffer->dma_address, vsize); +- if (err != 0) { +- hailo_dev_err(controller->dev, " Failed mmap descriptors %d\n", err); +- return err; +- } +- +- return 0; +-} +- + static int low_memory_buffer_mmap(struct hailo_vdma_controller *controller, + struct hailo_vdma_low_memory_buffer *vdma_buffer, struct vm_area_struct *vma) + { +@@ -300,15 +270,11 @@ static int continuous_buffer_mmap(struct + int hailo_vdma_mmap(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, + struct vm_area_struct *vma, uintptr_t vdma_handle) + { +- struct hailo_descriptors_list_buffer *vdma_descriptors_buffer = NULL; + struct hailo_vdma_low_memory_buffer *low_memory_buffer = NULL; + struct hailo_vdma_continuous_buffer *continuous_buffer = NULL; + + hailo_dev_info(controller->dev, "Map vdma_handle %llu\n", (u64)vdma_handle); +- if (NULL != (vdma_descriptors_buffer = hailo_vdma_find_descriptors_buffer(context, vdma_handle))) { +- return desc_list_mmap(controller, vdma_descriptors_buffer, vma); +- } +- else if (NULL != (low_memory_buffer = hailo_vdma_find_low_memory_buffer(context, vdma_handle))) { ++ if (NULL != (low_memory_buffer = hailo_vdma_find_low_memory_buffer(context, vdma_handle))) { + return low_memory_buffer_mmap(controller, low_memory_buffer, vma); + } + else if (NULL != (continuous_buffer = hailo_vdma_find_continuous_buffer(context, vdma_handle))) { +--- a/drivers/media/pci/hailo/vdma/vdma.h ++++ b/drivers/media/pci/hailo/vdma/vdma.h +@@ -16,6 +16,8 @@ + #include + #include + #include ++#include ++#include + + #define VDMA_CHANNEL_CONTROL_REG_OFFSET(channel_index, direction) (((direction) == DMA_TO_DEVICE) ? \ + (((channel_index) << 5) + 0x0) : (((channel_index) << 5) + 0x10)) +@@ -28,6 +30,22 @@ + ((u8*)((vdma_registers)->address) + VDMA_CHANNEL_NUM_PROC_OFFSET(channel_index, direction)) + + ++// dmabuf is supported from linux kernel version 3.3 ++#if LINUX_VERSION_CODE < KERNEL_VERSION( 3, 3, 0 ) ++// Make dummy struct with one byte (C standards does not allow empty struct) - in order to not have to ifdef everywhere ++struct hailo_dmabuf_info { ++ uint8_t dummy; ++}; ++#else ++// dmabuf_sg_table is needed because in dma_buf_unmap_attachment() the sg_table's address has to match the ++// The one returned from dma_buf_map_attachment() - otherwise we would need to malloc each time ++struct hailo_dmabuf_info { ++ struct dma_buf *dmabuf; ++ struct dma_buf_attachment *dmabuf_attachment; ++ struct sg_table *dmabuf_sg_table; ++}; ++#endif // LINUX_VERSION_CODE < KERNEL_VERSION( 3, 3, 0 ) ++ + struct hailo_vdma_buffer { + struct list_head mapped_user_buffer_list; + size_t handle; +@@ -35,7 +53,7 @@ struct hailo_vdma_buffer { + struct kref kref; + struct device *device; + +- void __user *user_address; ++ uintptr_t user_address; + u32 size; + enum dma_data_direction data_direction; + struct sg_table sg_table; +@@ -44,7 +62,10 @@ struct hailo_vdma_buffer { + // 'struct page' (only by pure pfn). On this case, accessing to the page, + // or calling APIs that access the page (e.g. dma_sync_sg_for_cpu) is not + // allowed. +- bool is_mmio; ++ bool is_mmio; ++ ++ // Relevant paramaters that need to be saved in case of dmabuf - otherwise struct pointers will be NULL ++ struct hailo_dmabuf_info dmabuf_info; + }; + + // Continuous buffer that holds a descriptor list. +@@ -53,7 +74,7 @@ struct hailo_descriptors_list_buffer { + uintptr_t handle; + void *kernel_address; + dma_addr_t dma_address; +- u32 buffer_size; ++ u32 buffer_size; + struct hailo_vdma_descriptors_list desc_list; + }; + +@@ -120,9 +141,6 @@ int hailo_vdma_controller_init(struct ha + void hailo_vdma_update_interrupts_mask(struct hailo_vdma_controller *controller, + size_t engine_index); + +-void hailo_vdma_engine_interrupts_disable(struct hailo_vdma_controller *controller, +- struct hailo_vdma_engine *engine, u8 engine_index, u32 channels_bitmap); +- + void hailo_vdma_file_context_init(struct hailo_vdma_file_context *context); + void hailo_vdma_file_context_finalize(struct hailo_vdma_file_context *context, + struct hailo_vdma_controller *controller, struct file *filp); diff --git a/target/linux/bcm27xx/patches-6.6/950-1236-media-rpivid-Make-SPS-PPS-optional-in-a-request.patch b/target/linux/bcm27xx/patches-6.6/950-1236-media-rpivid-Make-SPS-PPS-optional-in-a-request.patch new file mode 100644 index 000000000000..26edb5558a3a --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1236-media-rpivid-Make-SPS-PPS-optional-in-a-request.patch @@ -0,0 +1,80 @@ +From cf64a1dfecc2dc418efdd61701c1a4b185ab4761 Mon Sep 17 00:00:00 2001 +From: John Cox +Date: Fri, 23 Aug 2024 16:48:38 +0100 +Subject: [PATCH 1236/1350] media/rpivid: Make SPS / PPS optional in a request + +SPS & PPS are optional in requests. Fix. The framework keeps the last +value so this is mostly a matter of changing .required to false when +requesting the controls. Check that SPS has ever been set on frame +start, PPS is valid if all zeros so is at best tricky to check. + +Signed-off-by: John Cox +--- + drivers/staging/media/rpivid/rpivid.c | 4 ++-- + drivers/staging/media/rpivid/rpivid_h265.c | 6 ++++++ + drivers/staging/media/rpivid/rpivid_video.c | 5 ----- + drivers/staging/media/rpivid/rpivid_video.h | 5 +++++ + 4 files changed, 13 insertions(+), 7 deletions(-) + +--- a/drivers/staging/media/rpivid/rpivid.c ++++ b/drivers/staging/media/rpivid/rpivid.c +@@ -40,14 +40,14 @@ static const struct rpivid_control rpivi + .id = V4L2_CID_STATELESS_HEVC_SPS, + .ops = &rpivid_hevc_sps_ctrl_ops, + }, +- .required = true, ++ .required = false, + }, + { + .cfg = { + .id = V4L2_CID_STATELESS_HEVC_PPS, + .ops = &rpivid_hevc_pps_ctrl_ops, + }, +- .required = true, ++ .required = false, + }, + { + .cfg = { +--- a/drivers/staging/media/rpivid/rpivid_h265.c ++++ b/drivers/staging/media/rpivid/rpivid_h265.c +@@ -1726,6 +1726,12 @@ static void rpivid_h265_setup(struct rpi + unsigned int ctb_size_y; + bool sps_changed = false; + ++ if (!is_sps_set(run->h265.sps)) { ++ v4l2_warn(&dev->v4l2_dev, "SPS never set\n"); ++ goto fail; ++ } ++ // Can't check for PPS easily as all 0's looks valid to me ++ + if (memcmp(&s->sps, run->h265.sps, sizeof(s->sps)) != 0) { + /* SPS changed */ + v4l2_info(&dev->v4l2_dev, "SPS changed\n"); +--- a/drivers/staging/media/rpivid/rpivid_video.c ++++ b/drivers/staging/media/rpivid/rpivid_video.c +@@ -257,11 +257,6 @@ static int rpivid_hevc_validate_sps(cons + return 1; + } + +-static inline int is_sps_set(const struct v4l2_ctrl_hevc_sps * const sps) +-{ +- return sps && sps->pic_width_in_luma_samples != 0; +-} +- + static u32 pixelformat_from_sps(const struct v4l2_ctrl_hevc_sps * const sps, + const int index) + { +--- a/drivers/staging/media/rpivid/rpivid_video.h ++++ b/drivers/staging/media/rpivid/rpivid_video.h +@@ -20,6 +20,11 @@ struct rpivid_format { + unsigned int capabilities; + }; + ++static inline int is_sps_set(const struct v4l2_ctrl_hevc_sps * const sps) ++{ ++ return sps && sps->pic_width_in_luma_samples != 0; ++} ++ + extern const struct v4l2_ioctl_ops rpivid_ioctl_ops; + + int rpivid_queue_init(void *priv, struct vb2_queue *src_vq, diff --git a/target/linux/bcm27xx/patches-6.6/950-1238-piscreen-overlay-Add-invert-x-y-and-swapxy.patch b/target/linux/bcm27xx/patches-6.6/950-1238-piscreen-overlay-Add-invert-x-y-and-swapxy.patch new file mode 100644 index 000000000000..0eeb8ae0d71a --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1238-piscreen-overlay-Add-invert-x-y-and-swapxy.patch @@ -0,0 +1,37 @@ +From 31be188fb945560c193020b19773625421847112 Mon Sep 17 00:00:00 2001 +From: Satadru Pramanik +Date: Wed, 4 Sep 2024 08:40:42 -0400 +Subject: [PATCH 1238/1350] piscreen-overlay: Add invert[x,y] and swapxy + +Signed-off-by: Satadru Pramanik +--- + arch/arm/boot/dts/overlays/README | 6 ++++++ + arch/arm/boot/dts/overlays/piscreen-overlay.dts | 3 +++ + 2 files changed, 9 insertions(+) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -3694,6 +3694,12 @@ Params: speed Display + drm Select the DRM/KMS driver instead of the FBTFT + one + ++ invx Touchscreen inverted x axis ++ ++ invy Touchscreen inverted y axis ++ ++ swapxy Touchscreen swapped x y axis ++ + + Name: piscreen2r + Info: PiScreen 2 with resistive TP display by OzzMaker.com +--- a/arch/arm/boot/dts/overlays/piscreen-overlay.dts ++++ b/arch/arm/boot/dts/overlays/piscreen-overlay.dts +@@ -103,5 +103,8 @@ + xohms = <&piscreen_ts>,"ti,x-plate-ohms;0"; + drm = <&piscreen>,"compatible=waveshare,rpi-lcd-35", + <&piscreen>,"reset-gpios:8=",; ++ invx = <&piscreen_ts>,"touchscreen-inverted-x?"; ++ invy = <&piscreen_ts>,"touchscreen-inverted-y?"; ++ swapxy = <&piscreen_ts>,"touchscreen-swapped-x-y!"; + }; + }; diff --git a/target/linux/bcm27xx/patches-6.6/950-1239-drivers-gpu-drm-panel-Added-waveshare-5.0inch-6.25in.patch b/target/linux/bcm27xx/patches-6.6/950-1239-drivers-gpu-drm-panel-Added-waveshare-5.0inch-6.25in.patch new file mode 100644 index 000000000000..96e3b478d4e5 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1239-drivers-gpu-drm-panel-Added-waveshare-5.0inch-6.25in.patch @@ -0,0 +1,82 @@ +From f955b7838f9ce72e48b29e58d65e0642d097c8b3 Mon Sep 17 00:00:00 2001 +From: eng33 +Date: Wed, 4 Sep 2024 10:48:22 +0800 +Subject: [PATCH 1239/1350] drivers:gpu:drm:panel: Added waveshare 5.0inch, + 6.25inch, and 8.8inch dsi screen devices + +Signed-off-by: eng33 +--- + drivers/gpu/drm/panel/panel-waveshare-dsi.c | 55 +++++++++++++++++++++ + 1 file changed, 55 insertions(+) + +--- a/drivers/gpu/drm/panel/panel-waveshare-dsi.c ++++ b/drivers/gpu/drm/panel/panel-waveshare-dsi.c +@@ -150,6 +150,51 @@ static const struct drm_display_mode ws_ + .vtotal = 720 + 8 + 4 + 16, + }; + ++/* 5.0inch 720x1280 ++ * https://www.waveshare.com/5inch-dsi-lcd-d.htm ++ */ ++static const struct drm_display_mode ws_panel_5_0_mode = { ++ .clock = 83333, ++ .hdisplay = 720, ++ .hsync_start = 720 + 100, ++ .hsync_end = 720 + 100 + 80, ++ .htotal = 720 + 100 + 80 + 100, ++ .vdisplay = 1280, ++ .vsync_start = 1280 + 20, ++ .vsync_end = 1280 + 20 + 20, ++ .vtotal = 1280 + 20 + 20 + 20, ++}; ++ ++/* 6.25inch 720x1560 ++ * https://www.waveshare.com/6.25inch-dsi-lcd.htm ++ */ ++static const struct drm_display_mode ws_panel_6_25_mode = { ++ .clock = 83333, ++ .hdisplay = 720, ++ .hsync_start = 720 + 50, ++ .hsync_end = 720 + 50 + 50, ++ .htotal = 720 + 50 + 50 + 50, ++ .vdisplay = 1560, ++ .vsync_start = 1560 + 20, ++ .vsync_end = 1560 + 20 + 20, ++ .vtotal = 1560 + 20 + 20 + 20, ++}; ++ ++/* 8.8inch 480x1920 ++ * https://www.waveshare.com/8.8inch-dsi-lcd.htm ++ */ ++static const struct drm_display_mode ws_panel_8_8_mode = { ++ .clock = 83333, ++ .hdisplay = 480, ++ .hsync_start = 480 + 50, ++ .hsync_end = 480 + 50 + 50, ++ .htotal = 480 + 50 + 50 + 50, ++ .vdisplay = 1920, ++ .vsync_start = 1920 + 20, ++ .vsync_end = 1920 + 20 + 20, ++ .vtotal = 1920 + 20 + 20 + 20, ++}; ++ + static struct ws_panel *panel_to_ts(struct drm_panel *panel) + { + return container_of(panel, struct ws_panel, base); +@@ -413,6 +458,16 @@ static const struct of_device_id ws_pane + .compatible = "waveshare,4inch-panel", + .data = &ws_panel_4_mode, + }, { ++ .compatible = "waveshare,5.0inch-panel", ++ .data = &ws_panel_5_0_mode, ++ }, { ++ .compatible = "waveshare,6.25inch-panel", ++ .data = &ws_panel_6_25_mode, ++ }, { ++ .compatible = "waveshare,8.8inch-panel", ++ .data = &ws_panel_8_8_mode, ++ }, { ++ }, { + /* sentinel */ + } + }; diff --git a/target/linux/bcm27xx/patches-6.6/950-1240-arch-arm-boot-dts-overlays-Added-waveshare-5.0inch-6.patch b/target/linux/bcm27xx/patches-6.6/950-1240-arch-arm-boot-dts-overlays-Added-waveshare-5.0inch-6.patch new file mode 100644 index 000000000000..11f504a18790 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1240-arch-arm-boot-dts-overlays-Added-waveshare-5.0inch-6.patch @@ -0,0 +1,27 @@ +From 769cd349d65fb29aaa8f443f9c7a701205b0409c Mon Sep 17 00:00:00 2001 +From: eng33 +Date: Wed, 4 Sep 2024 10:56:13 +0800 +Subject: [PATCH 1240/1350] arch:arm:boot:dts:overlays: Added waveshare + 5.0inch, 6.25inch, and 8.8inch dsi screen dts + +Signed-off-by: eng33 +--- + .../dts/overlays/vc4-kms-dsi-waveshare-panel-overlay.dts | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-panel-overlay.dts ++++ b/arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-panel-overlay.dts +@@ -113,6 +113,13 @@ + 4_0_inchC = <&panel>, "compatible=waveshare,4inch-panel", + <&touch>, "touchscreen-size-x:0=720", + <&touch>, "touchscreen-size-y:0=720"; ++ 5_0_inch = <&panel>, "compatible=waveshare,5.0inch-panel", ++ <&touch>, "touchscreen-inverted-x?", ++ <&touch>, "touchscreen-inverted-y?"; ++ 6_25_inch = <&panel>, "compatible=waveshare,6.25inch-panel", ++ <&touch>, "touchscreen-inverted-x?", ++ <&touch>, "touchscreen-inverted-y?"; ++ 8_8_inch = <&panel>, "compatible=waveshare,8.8inch-panel"; + i2c1 = <&i2c_frag>, "target:0=",<&i2c1>, + <0>, "-3-4+5"; + disable_touch = <&touch>, "status=disabled"; diff --git a/target/linux/bcm27xx/patches-6.6/950-1241-arch-arm-boot-dts-overlays-Added-waveshare-5.0inch-6.patch b/target/linux/bcm27xx/patches-6.6/950-1241-arch-arm-boot-dts-overlays-Added-waveshare-5.0inch-6.patch new file mode 100644 index 000000000000..0d5921245391 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1241-arch-arm-boot-dts-overlays-Added-waveshare-5.0inch-6.patch @@ -0,0 +1,23 @@ +From 3d39588b52abb06ed2b4b0d2db026133a920758b Mon Sep 17 00:00:00 2001 +From: eng33 +Date: Thu, 5 Sep 2024 17:19:56 +0800 +Subject: [PATCH 1241/1350] arch:arm:boot:dts:overlays: Added waveshare + 5.0inch, 6.25inch, and 8.8inch dsi screen description + +Signed-off-by: eng33 +--- + arch/arm/boot/dts/overlays/README | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -5233,6 +5233,9 @@ Params: 2_8_inch 2.8" 480 + 3_4_inch 3.4" 800x800 round + 4_0_inch 4.0" 480x800 + 4_0_inchC 4.0" 720x720 ++ 5_0_inch 5.0" 720x1280 ++ 6_25_inch 6.25" 720x1560 ++ 8_8_inch 8.8" 480x1920 + 7_0_inchC 7.0" C 1024x600 + 7_9_inch 7.9" 400x1280 + 8_0_inch 8.0" 1280x800 diff --git a/target/linux/bcm27xx/patches-6.6/950-1242-spi-rp2040-gpio-bridge-Add-debugfs-progress-indicato.patch b/target/linux/bcm27xx/patches-6.6/950-1242-spi-rp2040-gpio-bridge-Add-debugfs-progress-indicato.patch new file mode 100644 index 000000000000..4d7bc4d03877 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1242-spi-rp2040-gpio-bridge-Add-debugfs-progress-indicato.patch @@ -0,0 +1,89 @@ +From 4d219b15a7a01a14c1be1eeee9a939732130d30a Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Tue, 13 Aug 2024 13:45:54 +0100 +Subject: [PATCH 1242/1350] spi: rp2040-gpio-bridge: Add debugfs progress + indicator + +Useful for tracking upload progress via userspace. + +Signed-off-by: Naushir Patuck +--- + drivers/spi/spi-rp2040-gpio-bridge.c | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +--- a/drivers/spi/spi-rp2040-gpio-bridge.c ++++ b/drivers/spi/spi-rp2040-gpio-bridge.c +@@ -6,6 +6,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -91,6 +92,9 @@ enum rp2040_gbdg_fixed_size_commands { + struct rp2040_gbdg { + struct spi_controller *controller; + ++ struct dentry *debugfs; ++ size_t transfer_progress; ++ + struct i2c_client *client; + struct crypto_shash *shash; + struct shash_desc *shash_desc; +@@ -702,6 +706,7 @@ static int rp2040_gbdg_transfer_cached(s + return 0; + } + ++ priv_data->transfer_progress = 0; + while (length) { + unsigned int xfer = min(length, RP2040_GBDG_BLOCK_SIZE); + +@@ -710,7 +715,9 @@ static int rp2040_gbdg_transfer_cached(s + return ret; + length -= xfer; + data += xfer; ++ priv_data->transfer_progress += xfer; + } ++ priv_data->transfer_progress = 0; + + return 0; + } +@@ -1016,6 +1023,16 @@ static int rp2040_gbdg_power_on(struct r + return 0; + } + ++static int transfer_progress_show(struct seq_file *s, void *data) ++{ ++ struct rp2040_gbdg *rp2040_gbdg = s->private; ++ ++ seq_printf(s, "%zu\n", rp2040_gbdg->transfer_progress); ++ return 0; ++} ++ ++DEFINE_SHOW_ATTRIBUTE(transfer_progress); ++ + static int rp2040_gbdg_probe(struct i2c_client *client) + { + struct rp2040_gbdg_device_info info; +@@ -1023,6 +1040,7 @@ static int rp2040_gbdg_probe(struct i2c_ + struct device *dev = &client->dev; + struct rp2040_gbdg *rp2040_gbdg; + struct device_node *np; ++ char debugfs_name[128]; + int ret; + + np = dev->of_node; +@@ -1136,6 +1154,12 @@ static int rp2040_gbdg_probe(struct i2c_ + + rp2040_gbdg_parse_dt(rp2040_gbdg); + ++ snprintf(debugfs_name, sizeof(debugfs_name), "rp2040-spi:%s", ++ dev_name(dev)); ++ rp2040_gbdg->debugfs = debugfs_create_dir(debugfs_name, NULL); ++ debugfs_create_file("transfer_progress", 0444, rp2040_gbdg->debugfs, ++ rp2040_gbdg, &transfer_progress_fops); ++ + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + diff --git a/target/linux/bcm27xx/patches-6.6/950-1243-media-dt-bindings-i2c-Add-Sony-IMX500.patch b/target/linux/bcm27xx/patches-6.6/950-1243-media-dt-bindings-i2c-Add-Sony-IMX500.patch new file mode 100644 index 000000000000..82e58c12bc58 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1243-media-dt-bindings-i2c-Add-Sony-IMX500.patch @@ -0,0 +1,166 @@ +From 30921ddfa24a5325d0f4980c72f98d20bace87a2 Mon Sep 17 00:00:00 2001 +From: Richard Oliver +Date: Fri, 24 May 2024 11:43:07 +0100 +Subject: [PATCH 1243/1350] media: dt-bindings: i2c: Add Sony IMX500 + +Add YAML device tree binding for the Sony IMX500 CMOS image sensor / +CNN inference engine. Also, add a MAINTAINERS entry. + +Signed-off-by: Richard Oliver +--- + .../bindings/media/i2c/sony,imx500.yaml | 132 ++++++++++++++++++ + MAINTAINERS | 7 + + 2 files changed, 139 insertions(+) + create mode 100644 Documentation/devicetree/bindings/media/i2c/sony,imx500.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/media/i2c/sony,imx500.yaml +@@ -0,0 +1,132 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/media/i2c/sony,imx500.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Sony CMOS Digital Image Sensor and CNN ++ ++maintainers: ++ - Raspberry Pi ++ ++description: |- ++ The Sony IMX500 is a stacked 1/2.3-inch CMOS digital image sensor and inbuilt ++ AI processor with an active array CNN (Convolutional Neural Network) inference ++ engine. The native sensor size is 4056H x 3040V, and the module also contains ++ an in-built ISP for the CNN. The module is programmable through an I2C ++ interface with firmware and neural network uploads being made over SPI. The ++ default I2C address is 0x1A, with an address of 0x10 being selectable via ++ SLASEL. The module also has a second I2C interface available with a fixed ++ address of 0x36. Image data is sent through MIPI CSI-2, which is configured ++ as either 2 or 4 data lanes. ++ ++properties: ++ compatible: ++ const: sony,imx500 ++ ++ reg: ++ description: I2C device address ++ maxItems: 1 ++ ++ clocks: ++ maxItems: 1 ++ ++ clock-names: ++ description: |- ++ Input clock (12 to 27 MHz) ++ items: ++ - const: inck ++ ++ interrupts: ++ maxItems: 1 ++ ++ vana-supply: ++ description: Supply voltage (analog) - 2.7 V ++ ++ vdig-supply: ++ description: Supply voltage (digital) - 0.84 V ++ ++ vif-supply: ++ description: Supply voltage (interface) - 1.8 V ++ ++ reset-gpios: ++ description: |- ++ Sensor reset (XCLR) GPIO ++ ++ Chip clear in lieu of built-in power on reset. To be set 'High' after ++ power supplies are brought up and INCK supplied. ++ ++ port: ++ $ref: /schemas/graph.yaml#/$defs/port-base ++ additionalProperties: false ++ description: | ++ Video output port ++ ++ properties: ++ endpoint: ++ $ref: /schemas/media/video-interfaces.yaml# ++ type: object ++ unevaluatedProperties: false ++ properties: ++ data-lanes: ++ items: ++ - const: 2 ++ - const: 4 ++ clock-noncontinuous: true ++ link-frequencies: true ++ required: ++ - link-frequencies ++ - data-lanes ++ ++ spi: ++ $ref: /schemas/types.yaml#/definitions/phandle ++ description: |- ++ SPI peripheral ++ ++ Optional SPI peripheral for uploading firmware and network weights to AI ++ processor. ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - clock-names ++ - vana-supply ++ - vdig-supply ++ - vif-supply ++ - port ++ ++examples: ++ - | ++ #include ++ ++ i2c { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ imx500: sensor@1a { ++ compatible = "sony,imx500"; ++ reg = <0x1a>; ++ ++ clocks = <&imx500_clk>; ++ clock-names = "inck"; ++ ++ vana-supply = <&imx500_vana>; /* 2.7 +/- 0.1 V */ ++ vdig-supply = <&imx500_vdig>; /* 0.84 +/- 0.04 V */ ++ vif-supply = <&imx500_vif>; /* 1.8 +/- 0.1 V */ ++ ++ reset-gpios = <&gpio_sensor 0 GPIO_ACTIVE_LOW>; ++ ++ port { ++ imx500_0: endpoint { ++ remote-endpoint = <&csi1_ep>; ++ data-lanes = <1 2>; ++ clock-noncontinuous; ++ link-frequencies = /bits/ 64 <499500000>; ++ }; ++ }; ++ }; ++ }; ++ ++... ++ +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -20127,6 +20127,13 @@ F: Documentation/devicetree/bindings/med + F: Documentation/devicetree/bindings/media/i2c/imx477.yaml + F: drivers/media/i2c/imx477.c + ++SONY IMX500 SENSOR DRIVER ++M: Raspberry Pi Kernel Maintenance ++L: linux-media@vger.kernel.org ++S: Maintained ++T: git git://linuxtv.org/media_tree.git ++F: Documentation/devicetree/bindings/media/i2c/sony,imx500.yaml ++ + SONY IMX519 SENSOR DRIVER + M: Arducam Kernel Maintenance + L: linux-media@vger.kernel.org diff --git a/target/linux/bcm27xx/patches-6.6/950-1244-media-i2c-Add-driver-for-Sony-IMX500-sensor.patch b/target/linux/bcm27xx/patches-6.6/950-1244-media-i2c-Add-driver-for-Sony-IMX500-sensor.patch new file mode 100644 index 000000000000..331e5863a645 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1244-media-i2c-Add-driver-for-Sony-IMX500-sensor.patch @@ -0,0 +1,1675 @@ +From f9b1e0ffdd9b5134d9356d7e09e9c1a065fdfa13 Mon Sep 17 00:00:00 2001 +From: Richard Oliver +Date: Thu, 27 Jun 2024 10:11:44 +0100 +Subject: [PATCH 1244/1350] media: i2c: Add driver for Sony IMX500 sensor + +The Sony IMX500 is a stacked 1/2.3-inch CMOS digital image sensor and +inbuilt AI processor with an active array CNN (Convolutional Neural +Network) inference engine. The native sensor size is 4056H x 3040V, and +the module also contains an in-built ISP for the CNN. The module is +programmable through an I2C interface with firmware and neural network +uploads being made over SPI. This driver supports imaging only. + +Signed-off-by: Richard Oliver +--- + MAINTAINERS | 1 + + drivers/media/i2c/Kconfig | 12 + + drivers/media/i2c/Makefile | 1 + + drivers/media/i2c/imx500.c | 1610 ++++++++++++++++++++++++++++++++++++ + 4 files changed, 1624 insertions(+) + create mode 100644 drivers/media/i2c/imx500.c + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -20133,6 +20133,7 @@ L: linux-media@vger.kernel.org + S: Maintained + T: git git://linuxtv.org/media_tree.git + F: Documentation/devicetree/bindings/media/i2c/sony,imx500.yaml ++F: drivers/media/i2c/imx500.c + + SONY IMX519 SENSOR DRIVER + M: Arducam Kernel Maintenance +--- a/drivers/media/i2c/Kconfig ++++ b/drivers/media/i2c/Kconfig +@@ -236,6 +236,18 @@ config VIDEO_IMX477 + To compile this driver as a module, choose M here: the + module will be called imx477. + ++config VIDEO_IMX500 ++ tristate "Sony IMX500 sensor support" ++ depends on I2C && VIDEO_DEV ++ select VIDEO_V4L2_SUBDEV_API ++ select V4L2_CCI_I2C ++ help ++ This is a Video4Linux2 sensor driver for the Sony ++ IMX500 camera. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called IMX500. ++ + config VIDEO_IMX519 + tristate "Arducam IMX519 sensor support" + depends on I2C && VIDEO_DEV +--- a/drivers/media/i2c/Makefile ++++ b/drivers/media/i2c/Makefile +@@ -58,6 +58,7 @@ obj-$(CONFIG_VIDEO_IMX355) += imx355.o + obj-$(CONFIG_VIDEO_IMX412) += imx412.o + obj-$(CONFIG_VIDEO_IMX415) += imx415.o + obj-$(CONFIG_VIDEO_IMX477) += imx477.o ++obj-$(CONFIG_VIDEO_IMX500) += imx500.o + obj-$(CONFIG_VIDEO_IMX519) += imx519.o + obj-$(CONFIG_VIDEO_IMX708) += imx708.o + obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o +--- /dev/null ++++ b/drivers/media/i2c/imx500.c +@@ -0,0 +1,1610 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * A V4L2 driver for Sony IMX500 cameras. ++ * Copyright (C) 2024, Raspberry Pi Ltd ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Chip ID */ ++#define IMX500_REG_CHIP_ID CCI_REG16(0x0016) ++#define IMX500_CHIP_ID 0x0500 ++ ++#define IMX500_REG_MODE_SELECT CCI_REG8(0x0100) ++#define IMX500_MODE_STANDBY 0x00 ++#define IMX500_MODE_STREAMING 0x01 ++ ++#define IMX500_REG_IMAGE_ONLY_MODE CCI_REG8(0xa700) ++#define IMX500_IMAGE_ONLY_FALSE 0x00 ++#define IMX500_IMAGE_ONLY_TRUE 0x01 ++ ++#define IMX500_REG_ORIENTATION CCI_REG8(0x101) ++ ++#define IMX500_XCLK_FREQ 24000000 ++ ++#define IMX500_DEFAULT_LINK_FREQ 444000000 ++ ++#define IMX500_PIXEL_RATE 744000000 ++ ++/* V_TIMING internal */ ++#define IMX500_REG_FRAME_LENGTH CCI_REG16(0x0340) ++#define IMX500_FRAME_LENGTH_MAX 0xffdc ++#define IMX500_VBLANK_MIN 4 ++ ++/* H_TIMING internal */ ++#define IMX500_REG_LINE_LENGTH CCI_REG16(0x0342) ++#define IMX500_LINE_LENGTH_MAX 0xfff0 ++ ++/* Long exposure multiplier */ ++#define IMX500_LONG_EXP_SHIFT_MAX 7 ++#define IMX500_LONG_EXP_SHIFT_REG CCI_REG8(0x3210) ++ ++/* Exposure control */ ++#define IMX500_REG_EXPOSURE CCI_REG16(0x0202) ++#define IMX500_EXPOSURE_OFFSET 22 ++#define IMX500_EXPOSURE_MIN 8 ++#define IMX500_EXPOSURE_STEP 1 ++#define IMX500_EXPOSURE_DEFAULT 0x640 ++#define IMX500_EXPOSURE_MAX (IMX500_FRAME_LENGTH_MAX - IMX500_EXPOSURE_OFFSET) ++ ++/* Analog gain control */ ++#define IMX500_REG_ANALOG_GAIN CCI_REG16(0x0204) ++#define IMX500_ANA_GAIN_MIN 0 ++#define IMX500_ANA_GAIN_MAX 978 ++#define IMX500_ANA_GAIN_STEP 1 ++#define IMX500_ANA_GAIN_DEFAULT 0x0 ++ ++/* Colour balance controls */ ++#define IMX500_REG_COLOUR_BALANCE_R CCI_REG16(0xd804) ++#define IMX500_REG_COLOUR_BALANCE_GR CCI_REG16(0xd806) ++#define IMX500_REG_COLOUR_BALANCE_GB CCI_REG16(0xd808) ++#define IMX500_REG_COLOUR_BALANCE_B CCI_REG16(0xd80a) ++#define IMX500_COLOUR_BALANCE_MIN 0x0001 ++#define IMX500_COLOUR_BALANCE_MAX 0x0fff ++#define IMX500_COLOUR_BALANCE_STEP 0x0001 ++#define IMX500_COLOUR_BALANCE_DEFAULT 0x0100 ++ ++/* Embedded sizes */ ++#define IMX500_MAX_EMBEDDED_SIZE \ ++ (2 * ((((IMX500_PIXEL_ARRAY_WIDTH * 10) >> 3) + 15) & ~15)) ++ ++/* IMX500 native and active pixel array size. */ ++#define IMX500_NATIVE_WIDTH 4072U ++#define IMX500_NATIVE_HEIGHT 3176U ++#define IMX500_PIXEL_ARRAY_LEFT 8U ++#define IMX500_PIXEL_ARRAY_TOP 16U ++#define IMX500_PIXEL_ARRAY_WIDTH 4056U ++#define IMX500_PIXEL_ARRAY_HEIGHT 3040U ++ ++#define NUM_PADS 1 ++ ++/* regulator supplies */ ++static const char *const imx500_supply_name[] = { ++ /* Supplies can be enabled in any order */ ++ "vana", /* Analog (2.7V) supply */ ++ "vdig", /* Digital Core (0.84V) supply */ ++ "vif", /* Interface (1.8V) supply */ ++}; ++ ++#define IMX500_NUM_SUPPLIES ARRAY_SIZE(imx500_supply_name) ++ ++struct imx500_reg_list { ++ unsigned int num_of_regs; ++ const struct cci_reg_sequence *regs; ++}; ++ ++/* Mode : resolution and related config&values */ ++struct imx500_mode { ++ /* Frame width */ ++ unsigned int width; ++ ++ /* Frame height */ ++ unsigned int height; ++ ++ /* H-timing in pixels */ ++ unsigned int line_length_pix; ++ ++ /* Analog crop rectangle. */ ++ struct v4l2_rect crop; ++ ++ /* Default framerate. */ ++ unsigned int framerate_default; ++ ++ /* Default register values */ ++ struct imx500_reg_list reg_list; ++}; ++ ++static const struct cci_reg_sequence mode_common_regs[] = { ++ { CCI_REG8(0x0305), 0x02 }, ++ { CCI_REG8(0x0306), 0x00 }, ++ { CCI_REG8(0x030d), 0x02 }, ++ { CCI_REG8(0x030e), 0x00 }, ++ { CCI_REG8(0x0106), 0x01 }, /* FAST_STANDBY_CTL */ ++ { CCI_REG8(0x0136), 0x1b }, /* EXCLK_FREQ */ ++ { CCI_REG8(0x0137), 0x00 }, ++ { CCI_REG8(0x0138), 0x01 }, /* TEMP_SENS_CTL */ ++ { CCI_REG8(0x0112), 0x0a }, ++ { CCI_REG8(0x0113), 0x0a }, ++ { CCI_REG8(0x0114), 0x01 }, /* CSI_LANE_MODE */ ++}; ++ ++/* 12 mpix 15fps */ ++static const struct cci_reg_sequence mode_4056x3040_regs[] = { ++ { CCI_REG8(0x0340), 0x12 }, ++ { CCI_REG8(0x0341), 0x42 }, ++ { CCI_REG8(0x0342), 0x45 }, ++ { CCI_REG8(0x0343), 0xec }, ++ { CCI_REG8(0x3210), 0x00 }, ++ { CCI_REG8(0x0344), 0x00 }, ++ { CCI_REG8(0x0345), 0x00 }, ++ { CCI_REG8(0x0346), 0x00 }, ++ { CCI_REG8(0x0347), 0x00 }, ++ { CCI_REG8(0x0348), 0x0f }, ++ { CCI_REG8(0x0349), 0xd7 }, ++ { CCI_REG8(0x0350), 0x00 }, ++ { CCI_REG8(0x034a), 0x0b }, ++ { CCI_REG8(0x034b), 0xdf }, ++ { CCI_REG8(0x3f58), 0x01 }, ++ { CCI_REG8(0x0381), 0x01 }, ++ { CCI_REG8(0x0383), 0x01 }, ++ { CCI_REG8(0x0385), 0x01 }, ++ { CCI_REG8(0x0387), 0x01 }, ++ { CCI_REG8(0x0900), 0x00 }, ++ { CCI_REG8(0x0901), 0x11 }, ++ { CCI_REG8(0x0902), 0x00 }, ++ { CCI_REG8(0x3241), 0x11 }, ++ { CCI_REG8(0x3242), 0x01 }, ++ { CCI_REG8(0x3250), 0x00 }, ++ { CCI_REG8(0x3f0f), 0x00 }, ++ { CCI_REG8(0x3f40), 0x00 }, ++ { CCI_REG8(0x3f41), 0x00 }, ++ { CCI_REG8(0x3f42), 0x00 }, ++ { CCI_REG8(0x3f43), 0x00 }, ++ { CCI_REG8(0xb34e), 0x00 }, ++ { CCI_REG8(0xb351), 0x20 }, ++ { CCI_REG8(0xb35c), 0x00 }, ++ { CCI_REG8(0xb35e), 0x08 }, ++ { CCI_REG8(0x0401), 0x00 }, ++ { CCI_REG8(0x0404), 0x00 }, ++ { CCI_REG8(0x0405), 0x10 }, ++ { CCI_REG8(0x0408), 0x00 }, ++ { CCI_REG8(0x0409), 0x00 }, ++ { CCI_REG8(0x040a), 0x00 }, ++ { CCI_REG8(0x040b), 0x00 }, ++ { CCI_REG8(0x040c), 0x0f }, ++ { CCI_REG8(0x040d), 0xd8 }, ++ { CCI_REG8(0x040e), 0x0b }, ++ { CCI_REG8(0x040f), 0xe0 }, ++ { CCI_REG8(0x034c), 0x0f }, ++ { CCI_REG8(0x034d), 0xd8 }, ++ { CCI_REG8(0x034e), 0x0b }, ++ { CCI_REG8(0x034f), 0xe0 }, ++ { CCI_REG8(0x0301), 0x05 }, ++ { CCI_REG8(0x0303), 0x02 }, ++ { CCI_REG8(0x0307), 0x9b }, ++ { CCI_REG8(0x0309), 0x0a }, ++ { CCI_REG8(0x030b), 0x01 }, ++ { CCI_REG8(0x030f), 0x4a }, ++ { CCI_REG8(0x0310), 0x01 }, ++ { CCI_REG8(0x0820), 0x07 }, ++ { CCI_REG8(0x0821), 0xce }, ++ { CCI_REG8(0x0822), 0x00 }, ++ { CCI_REG8(0x0823), 0x00 }, ++ { CCI_REG8(0x3e20), 0x01 }, ++ { CCI_REG8(0x3e35), 0x01 }, ++ { CCI_REG8(0x3e36), 0x01 }, ++ { CCI_REG8(0x3e37), 0x00 }, ++ { CCI_REG8(0x3e3a), 0x01 }, ++ { CCI_REG8(0x3e3b), 0x00 }, ++ { CCI_REG8(0x00e3), 0x00 }, ++ { CCI_REG8(0x00e4), 0x00 }, ++ { CCI_REG8(0x00e6), 0x00 }, ++ { CCI_REG8(0x00e7), 0x00 }, ++ { CCI_REG8(0x00e8), 0x00 }, ++ { CCI_REG8(0x00e9), 0x00 }, ++ { CCI_REG8(0x3f50), 0x00 }, ++ { CCI_REG8(0x3f56), 0x02 }, ++ { CCI_REG8(0x3f57), 0x42 }, ++ { CCI_REG8(0x3606), 0x01 }, ++ { CCI_REG8(0x3607), 0x01 }, ++ { CCI_REG8(0x3f26), 0x00 }, ++ { CCI_REG8(0x3f4a), 0x00 }, ++ { CCI_REG8(0x3f4b), 0x00 }, ++ { CCI_REG8(0x4bc0), 0x16 }, ++ { CCI_REG8(0x7ba8), 0x00 }, ++ { CCI_REG8(0x7ba9), 0x00 }, ++ { CCI_REG8(0x886b), 0x00 }, ++ { CCI_REG8(0x579a), 0x00 }, ++ { CCI_REG8(0x579b), 0x0a }, ++ { CCI_REG8(0x579c), 0x01 }, ++ { CCI_REG8(0x579d), 0x2a }, ++ { CCI_REG8(0x57ac), 0x00 }, ++ { CCI_REG8(0x57ad), 0x00 }, ++ { CCI_REG8(0x57ae), 0x00 }, ++ { CCI_REG8(0x57af), 0x81 }, ++ { CCI_REG8(0x57be), 0x00 }, ++ { CCI_REG8(0x57bf), 0x00 }, ++ { CCI_REG8(0x57c0), 0x00 }, ++ { CCI_REG8(0x57c1), 0x81 }, ++ { CCI_REG8(0x57d0), 0x00 }, ++ { CCI_REG8(0x57d1), 0x00 }, ++ { CCI_REG8(0x57d2), 0x00 }, ++ { CCI_REG8(0x57d3), 0x81 }, ++ { CCI_REG8(0x5324), 0x00 }, ++ { CCI_REG8(0x5325), 0x26 }, ++ { CCI_REG8(0x5326), 0x00 }, ++ { CCI_REG8(0x5327), 0x6b }, ++ { CCI_REG8(0xbca7), 0x00 }, ++ { CCI_REG8(0x5fcc), 0x28 }, ++ { CCI_REG8(0x5fd7), 0x2d }, ++ { CCI_REG8(0x5fe2), 0x2d }, ++ { CCI_REG8(0x5fed), 0x2d }, ++ { CCI_REG8(0x5ff8), 0x2d }, ++ { CCI_REG8(0x6003), 0x2d }, ++ { CCI_REG8(0x5d0b), 0x01 }, ++ { CCI_REG8(0x6f6d), 0x00 }, ++ { CCI_REG8(0x61c9), 0x00 }, ++ { CCI_REG8(0x5352), 0x00 }, ++ { CCI_REG8(0x5353), 0x49 }, ++ { CCI_REG8(0x5356), 0x00 }, ++ { CCI_REG8(0x5357), 0x30 }, ++ { CCI_REG8(0x5358), 0x00 }, ++ { CCI_REG8(0x5359), 0x3b }, ++ { CCI_REG8(0x535c), 0x00 }, ++ { CCI_REG8(0x535d), 0xb0 }, ++ { CCI_REG8(0x6187), 0x18 }, ++ { CCI_REG8(0x6189), 0x18 }, ++ { CCI_REG8(0x618b), 0x18 }, ++ { CCI_REG8(0x618d), 0x1d }, ++ { CCI_REG8(0x618f), 0x1d }, ++ { CCI_REG8(0x5414), 0x01 }, ++ { CCI_REG8(0x5415), 0x0c }, ++ { CCI_REG8(0xbca8), 0x0a }, ++ { CCI_REG8(0x5fcf), 0x1e }, ++ { CCI_REG8(0x5fda), 0x1e }, ++ { CCI_REG8(0x5fe5), 0x1e }, ++ { CCI_REG8(0x5ff0), 0x1e }, ++ { CCI_REG8(0x5ffb), 0x1e }, ++ { CCI_REG8(0x6006), 0x1e }, ++ { CCI_REG8(0x616e), 0x04 }, ++ { CCI_REG8(0x616f), 0x04 }, ++ { CCI_REG8(0x6170), 0x04 }, ++ { CCI_REG8(0x6171), 0x06 }, ++ { CCI_REG8(0x6172), 0x06 }, ++ { CCI_REG8(0x6173), 0x0c }, ++ { CCI_REG8(0x6174), 0x0c }, ++ { CCI_REG8(0x6175), 0x0c }, ++ { CCI_REG8(0x6176), 0x00 }, ++ { CCI_REG8(0x6177), 0x10 }, ++ { CCI_REG8(0x6178), 0x00 }, ++ { CCI_REG8(0x6179), 0x1a }, ++ { CCI_REG8(0x617a), 0x00 }, ++ { CCI_REG8(0x617b), 0x1a }, ++ { CCI_REG8(0x617c), 0x00 }, ++ { CCI_REG8(0x617d), 0x27 }, ++ { CCI_REG8(0x617e), 0x00 }, ++ { CCI_REG8(0x617f), 0x27 }, ++ { CCI_REG8(0x6180), 0x00 }, ++ { CCI_REG8(0x6181), 0x44 }, ++ { CCI_REG8(0x6182), 0x00 }, ++ { CCI_REG8(0x6183), 0x44 }, ++ { CCI_REG8(0x6184), 0x00 }, ++ { CCI_REG8(0x6185), 0x44 }, ++ { CCI_REG8(0x5dfc), 0x0a }, ++ { CCI_REG8(0x5e00), 0x0a }, ++ { CCI_REG8(0x5e04), 0x0a }, ++ { CCI_REG8(0x5e08), 0x0a }, ++ { CCI_REG8(0x5dfd), 0x0a }, ++ { CCI_REG8(0x5e01), 0x0a }, ++ { CCI_REG8(0x5e05), 0x0a }, ++ { CCI_REG8(0x5e09), 0x0a }, ++ { CCI_REG8(0x5dfe), 0x0a }, ++ { CCI_REG8(0x5e02), 0x0a }, ++ { CCI_REG8(0x5e06), 0x0a }, ++ { CCI_REG8(0x5e0a), 0x0a }, ++ { CCI_REG8(0x5dff), 0x0a }, ++ { CCI_REG8(0x5e03), 0x0a }, ++ { CCI_REG8(0x5e07), 0x0a }, ++ { CCI_REG8(0x5e0b), 0x0a }, ++ { CCI_REG8(0x5dec), 0x12 }, ++ { CCI_REG8(0x5df0), 0x12 }, ++ { CCI_REG8(0x5df4), 0x21 }, ++ { CCI_REG8(0x5df8), 0x31 }, ++ { CCI_REG8(0x5ded), 0x12 }, ++ { CCI_REG8(0x5df1), 0x12 }, ++ { CCI_REG8(0x5df5), 0x21 }, ++ { CCI_REG8(0x5df9), 0x31 }, ++ { CCI_REG8(0x5dee), 0x12 }, ++ { CCI_REG8(0x5df2), 0x12 }, ++ { CCI_REG8(0x5df6), 0x21 }, ++ { CCI_REG8(0x5dfa), 0x31 }, ++ { CCI_REG8(0x5def), 0x12 }, ++ { CCI_REG8(0x5df3), 0x12 }, ++ { CCI_REG8(0x5df7), 0x21 }, ++ { CCI_REG8(0x5dfb), 0x31 }, ++ { CCI_REG8(0x5ddc), 0x0d }, ++ { CCI_REG8(0x5de0), 0x0d }, ++ { CCI_REG8(0x5de4), 0x0d }, ++ { CCI_REG8(0x5de8), 0x0d }, ++ { CCI_REG8(0x5ddd), 0x0d }, ++ { CCI_REG8(0x5de1), 0x0d }, ++ { CCI_REG8(0x5de5), 0x0d }, ++ { CCI_REG8(0x5de9), 0x0d }, ++ { CCI_REG8(0x5dde), 0x0d }, ++ { CCI_REG8(0x5de2), 0x0d }, ++ { CCI_REG8(0x5de6), 0x0d }, ++ { CCI_REG8(0x5dea), 0x0d }, ++ { CCI_REG8(0x5ddf), 0x0d }, ++ { CCI_REG8(0x5de3), 0x0d }, ++ { CCI_REG8(0x5de7), 0x0d }, ++ { CCI_REG8(0x5deb), 0x0d }, ++ { CCI_REG8(0x5dcc), 0x55 }, ++ { CCI_REG8(0x5dd0), 0x50 }, ++ { CCI_REG8(0x5dd4), 0x4b }, ++ { CCI_REG8(0x5dd8), 0x4b }, ++ { CCI_REG8(0x5dcd), 0x55 }, ++ { CCI_REG8(0x5dd1), 0x50 }, ++ { CCI_REG8(0x5dd5), 0x4b }, ++ { CCI_REG8(0x5dd9), 0x4b }, ++ { CCI_REG8(0x5dce), 0x55 }, ++ { CCI_REG8(0x5dd2), 0x50 }, ++ { CCI_REG8(0x5dd6), 0x4b }, ++ { CCI_REG8(0x5dda), 0x4b }, ++ { CCI_REG8(0x5dcf), 0x55 }, ++ { CCI_REG8(0x5dd3), 0x50 }, ++ { CCI_REG8(0x5dd7), 0x4b }, ++ { CCI_REG8(0x5ddb), 0x4b }, ++ { CCI_REG8(0x0202), 0x12 }, ++ { CCI_REG8(0x0203), 0x2c }, ++ { CCI_REG8(0x0204), 0x00 }, ++ { CCI_REG8(0x0205), 0x00 }, ++ { CCI_REG8(0x020e), 0x01 }, ++ { CCI_REG8(0x020f), 0x00 }, ++ { CCI_REG8(0x0210), 0x01 }, ++ { CCI_REG8(0x0211), 0x00 }, ++ { CCI_REG8(0x0212), 0x01 }, ++ { CCI_REG8(0x0213), 0x00 }, ++ { CCI_REG8(0x0214), 0x01 }, ++ { CCI_REG8(0x0215), 0x00 }, ++}; ++ ++/* 2x2 binned. 56fps */ ++static const struct cci_reg_sequence mode_2028x1520_regs[] = { ++ { CCI_REG8(0x0112), 0x0a }, ++ { CCI_REG8(0x0113), 0x0a }, ++ { CCI_REG8(0x0114), 0x01 }, ++ { CCI_REG8(0x0342), 0x24 }, ++ { CCI_REG8(0x0343), 0xb6 }, ++ { CCI_REG8(0x0340), 0x0b }, ++ { CCI_REG8(0x0341), 0x9c }, ++ { CCI_REG8(0x3210), 0x00 }, ++ { CCI_REG8(0x0344), 0x00 }, ++ { CCI_REG8(0x0345), 0x00 }, ++ { CCI_REG8(0x0346), 0x00 }, ++ { CCI_REG8(0x0347), 0x00 }, ++ { CCI_REG8(0x0348), 0x0f }, ++ { CCI_REG8(0x0349), 0xd7 }, ++ { CCI_REG8(0x0350), 0x00 }, ++ { CCI_REG8(0x034a), 0x0b }, ++ { CCI_REG8(0x034b), 0xdf }, ++ { CCI_REG8(0x3f58), 0x01 }, ++ { CCI_REG8(0x0381), 0x01 }, ++ { CCI_REG8(0x0383), 0x01 }, ++ { CCI_REG8(0x0385), 0x01 }, ++ { CCI_REG8(0x0387), 0x01 }, ++ { CCI_REG8(0x0900), 0x01 }, ++ { CCI_REG8(0x0901), 0x22 }, ++ { CCI_REG8(0x0902), 0x02 }, ++ { CCI_REG8(0x3241), 0x11 }, ++ { CCI_REG8(0x3242), 0x01 }, ++ { CCI_REG8(0x3250), 0x03 }, ++ { CCI_REG8(0x3f0f), 0x00 }, ++ { CCI_REG8(0x3f40), 0x00 }, ++ { CCI_REG8(0x3f41), 0x00 }, ++ { CCI_REG8(0x3f42), 0x00 }, ++ { CCI_REG8(0x3f43), 0x00 }, ++ { CCI_REG8(0xb34e), 0x00 }, ++ { CCI_REG8(0xb351), 0x20 }, ++ { CCI_REG8(0xb35c), 0x00 }, ++ { CCI_REG8(0xb35e), 0x08 }, ++ { CCI_REG8(0x0401), 0x00 }, ++ { CCI_REG8(0x0404), 0x00 }, ++ { CCI_REG8(0x0405), 0x10 }, ++ { CCI_REG8(0x0408), 0x00 }, ++ { CCI_REG8(0x0409), 0x00 }, ++ { CCI_REG8(0x040a), 0x00 }, ++ { CCI_REG8(0x040b), 0x00 }, ++ { CCI_REG8(0x040c), 0x07 }, ++ { CCI_REG8(0x040d), 0xec }, ++ { CCI_REG8(0x040e), 0x05 }, ++ { CCI_REG8(0x040f), 0xf0 }, ++ { CCI_REG8(0x034c), 0x07 }, ++ { CCI_REG8(0x034d), 0xec }, ++ { CCI_REG8(0x034e), 0x05 }, ++ { CCI_REG8(0x034f), 0xf0 }, ++ { CCI_REG8(0x0301), 0x05 }, ++ { CCI_REG8(0x0303), 0x02 }, ++ { CCI_REG8(0x0307), 0x9b }, ++ { CCI_REG8(0x0309), 0x0a }, ++ { CCI_REG8(0x030b), 0x01 }, ++ { CCI_REG8(0x030f), 0x4a }, ++ { CCI_REG8(0x0310), 0x01 }, ++ { CCI_REG8(0x0820), 0x07 }, ++ { CCI_REG8(0x0821), 0xce }, ++ { CCI_REG8(0x0822), 0x00 }, ++ { CCI_REG8(0x0823), 0x00 }, ++ { CCI_REG8(0x3e20), 0x01 }, ++ { CCI_REG8(0x3e35), 0x01 }, ++ { CCI_REG8(0x3e36), 0x01 }, ++ { CCI_REG8(0x3e37), 0x00 }, ++ { CCI_REG8(0x3e3a), 0x01 }, ++ { CCI_REG8(0x3e3b), 0x00 }, ++ { CCI_REG8(0x00e3), 0x00 }, ++ { CCI_REG8(0x00e4), 0x00 }, ++ { CCI_REG8(0x00e6), 0x00 }, ++ { CCI_REG8(0x00e7), 0x00 }, ++ { CCI_REG8(0x00e8), 0x00 }, ++ { CCI_REG8(0x00e9), 0x00 }, ++ { CCI_REG8(0x3f50), 0x00 }, ++ { CCI_REG8(0x3f56), 0x01 }, ++ { CCI_REG8(0x3f57), 0x30 }, ++ { CCI_REG8(0x3606), 0x01 }, ++ { CCI_REG8(0x3607), 0x01 }, ++ { CCI_REG8(0x3f26), 0x00 }, ++ { CCI_REG8(0x3f4a), 0x00 }, ++ { CCI_REG8(0x3f4b), 0x00 }, ++ { CCI_REG8(0x4bc0), 0x16 }, ++ { CCI_REG8(0x7ba8), 0x00 }, ++ { CCI_REG8(0x7ba9), 0x00 }, ++ { CCI_REG8(0x886b), 0x00 }, ++ { CCI_REG8(0x579a), 0x00 }, ++ { CCI_REG8(0x579b), 0x0a }, ++ { CCI_REG8(0x579c), 0x01 }, ++ { CCI_REG8(0x579d), 0x2a }, ++ { CCI_REG8(0x57ac), 0x00 }, ++ { CCI_REG8(0x57ad), 0x00 }, ++ { CCI_REG8(0x57ae), 0x00 }, ++ { CCI_REG8(0x57af), 0x81 }, ++ { CCI_REG8(0x57be), 0x00 }, ++ { CCI_REG8(0x57bf), 0x00 }, ++ { CCI_REG8(0x57c0), 0x00 }, ++ { CCI_REG8(0x57c1), 0x81 }, ++ { CCI_REG8(0x57d0), 0x00 }, ++ { CCI_REG8(0x57d1), 0x00 }, ++ { CCI_REG8(0x57d2), 0x00 }, ++ { CCI_REG8(0x57d3), 0x81 }, ++ { CCI_REG8(0x5324), 0x00 }, ++ { CCI_REG8(0x5325), 0x31 }, ++ { CCI_REG8(0x5326), 0x00 }, ++ { CCI_REG8(0x5327), 0x60 }, ++ { CCI_REG8(0xbca7), 0x08 }, ++ { CCI_REG8(0x5fcc), 0x1e }, ++ { CCI_REG8(0x5fd7), 0x1e }, ++ { CCI_REG8(0x5fe2), 0x1e }, ++ { CCI_REG8(0x5fed), 0x1e }, ++ { CCI_REG8(0x5ff8), 0x1e }, ++ { CCI_REG8(0x6003), 0x1e }, ++ { CCI_REG8(0x5d0b), 0x02 }, ++ { CCI_REG8(0x6f6d), 0x01 }, ++ { CCI_REG8(0x61c9), 0x68 }, ++ { CCI_REG8(0x5352), 0x00 }, ++ { CCI_REG8(0x5353), 0x3f }, ++ { CCI_REG8(0x5356), 0x00 }, ++ { CCI_REG8(0x5357), 0x1c }, ++ { CCI_REG8(0x5358), 0x00 }, ++ { CCI_REG8(0x5359), 0x3d }, ++ { CCI_REG8(0x535c), 0x00 }, ++ { CCI_REG8(0x535d), 0xa6 }, ++ { CCI_REG8(0x6187), 0x1d }, ++ { CCI_REG8(0x6189), 0x1d }, ++ { CCI_REG8(0x618b), 0x1d }, ++ { CCI_REG8(0x618d), 0x23 }, ++ { CCI_REG8(0x618f), 0x23 }, ++ { CCI_REG8(0x5414), 0x01 }, ++ { CCI_REG8(0x5415), 0x12 }, ++ { CCI_REG8(0xbca8), 0x00 }, ++ { CCI_REG8(0x5fcf), 0x28 }, ++ { CCI_REG8(0x5fda), 0x2d }, ++ { CCI_REG8(0x5fe5), 0x2d }, ++ { CCI_REG8(0x5ff0), 0x2d }, ++ { CCI_REG8(0x5ffb), 0x2d }, ++ { CCI_REG8(0x6006), 0x2d }, ++ { CCI_REG8(0x616e), 0x04 }, ++ { CCI_REG8(0x616f), 0x04 }, ++ { CCI_REG8(0x6170), 0x04 }, ++ { CCI_REG8(0x6171), 0x06 }, ++ { CCI_REG8(0x6172), 0x06 }, ++ { CCI_REG8(0x6173), 0x0c }, ++ { CCI_REG8(0x6174), 0x0c }, ++ { CCI_REG8(0x6175), 0x0c }, ++ { CCI_REG8(0x6176), 0x00 }, ++ { CCI_REG8(0x6177), 0x10 }, ++ { CCI_REG8(0x6178), 0x00 }, ++ { CCI_REG8(0x6179), 0x1a }, ++ { CCI_REG8(0x617a), 0x00 }, ++ { CCI_REG8(0x617b), 0x1a }, ++ { CCI_REG8(0x617c), 0x00 }, ++ { CCI_REG8(0x617d), 0x27 }, ++ { CCI_REG8(0x617e), 0x00 }, ++ { CCI_REG8(0x617f), 0x27 }, ++ { CCI_REG8(0x6180), 0x00 }, ++ { CCI_REG8(0x6181), 0x44 }, ++ { CCI_REG8(0x6182), 0x00 }, ++ { CCI_REG8(0x6183), 0x44 }, ++ { CCI_REG8(0x6184), 0x00 }, ++ { CCI_REG8(0x6185), 0x44 }, ++ { CCI_REG8(0x5dfc), 0x0a }, ++ { CCI_REG8(0x5e00), 0x0a }, ++ { CCI_REG8(0x5e04), 0x0a }, ++ { CCI_REG8(0x5e08), 0x0a }, ++ { CCI_REG8(0x5dfd), 0x0a }, ++ { CCI_REG8(0x5e01), 0x0a }, ++ { CCI_REG8(0x5e05), 0x0a }, ++ { CCI_REG8(0x5e09), 0x0a }, ++ { CCI_REG8(0x5dfe), 0x0a }, ++ { CCI_REG8(0x5e02), 0x0a }, ++ { CCI_REG8(0x5e06), 0x0a }, ++ { CCI_REG8(0x5e0a), 0x0a }, ++ { CCI_REG8(0x5dff), 0x0a }, ++ { CCI_REG8(0x5e03), 0x0a }, ++ { CCI_REG8(0x5e07), 0x0a }, ++ { CCI_REG8(0x5e0b), 0x0a }, ++ { CCI_REG8(0x5dec), 0x12 }, ++ { CCI_REG8(0x5df0), 0x12 }, ++ { CCI_REG8(0x5df4), 0x21 }, ++ { CCI_REG8(0x5df8), 0x31 }, ++ { CCI_REG8(0x5ded), 0x12 }, ++ { CCI_REG8(0x5df1), 0x12 }, ++ { CCI_REG8(0x5df5), 0x21 }, ++ { CCI_REG8(0x5df9), 0x31 }, ++ { CCI_REG8(0x5dee), 0x12 }, ++ { CCI_REG8(0x5df2), 0x12 }, ++ { CCI_REG8(0x5df6), 0x21 }, ++ { CCI_REG8(0x5dfa), 0x31 }, ++ { CCI_REG8(0x5def), 0x12 }, ++ { CCI_REG8(0x5df3), 0x12 }, ++ { CCI_REG8(0x5df7), 0x21 }, ++ { CCI_REG8(0x5dfb), 0x31 }, ++ { CCI_REG8(0x5ddc), 0x0d }, ++ { CCI_REG8(0x5de0), 0x0d }, ++ { CCI_REG8(0x5de4), 0x0d }, ++ { CCI_REG8(0x5de8), 0x0d }, ++ { CCI_REG8(0x5ddd), 0x0d }, ++ { CCI_REG8(0x5de1), 0x0d }, ++ { CCI_REG8(0x5de5), 0x0d }, ++ { CCI_REG8(0x5de9), 0x0d }, ++ { CCI_REG8(0x5dde), 0x0d }, ++ { CCI_REG8(0x5de2), 0x0d }, ++ { CCI_REG8(0x5de6), 0x0d }, ++ { CCI_REG8(0x5dea), 0x0d }, ++ { CCI_REG8(0x5ddf), 0x0d }, ++ { CCI_REG8(0x5de3), 0x0d }, ++ { CCI_REG8(0x5de7), 0x0d }, ++ { CCI_REG8(0x5deb), 0x0d }, ++ { CCI_REG8(0x5dcc), 0x55 }, ++ { CCI_REG8(0x5dd0), 0x50 }, ++ { CCI_REG8(0x5dd4), 0x4b }, ++ { CCI_REG8(0x5dd8), 0x4b }, ++ { CCI_REG8(0x5dcd), 0x55 }, ++ { CCI_REG8(0x5dd1), 0x50 }, ++ { CCI_REG8(0x5dd5), 0x4b }, ++ { CCI_REG8(0x5dd9), 0x4b }, ++ { CCI_REG8(0x5dce), 0x55 }, ++ { CCI_REG8(0x5dd2), 0x50 }, ++ { CCI_REG8(0x5dd6), 0x4b }, ++ { CCI_REG8(0x5dda), 0x4b }, ++ { CCI_REG8(0x5dcf), 0x55 }, ++ { CCI_REG8(0x5dd3), 0x50 }, ++ { CCI_REG8(0x5dd7), 0x4b }, ++ { CCI_REG8(0x5ddb), 0x4b }, ++ { CCI_REG8(0x0202), 0x0b }, ++ { CCI_REG8(0x0203), 0x86 }, ++ { CCI_REG8(0x0204), 0x00 }, ++ { CCI_REG8(0x0205), 0x00 }, ++ { CCI_REG8(0x020e), 0x01 }, ++ { CCI_REG8(0x020f), 0x00 }, ++ { CCI_REG8(0x0210), 0x01 }, ++ { CCI_REG8(0x0211), 0x00 }, ++ { CCI_REG8(0x0212), 0x01 }, ++ { CCI_REG8(0x0213), 0x00 }, ++ { CCI_REG8(0x0214), 0x01 }, ++ { CCI_REG8(0x0215), 0x00 }, ++}; ++ ++/* Mode configs */ ++static const struct imx500_mode imx500_supported_modes[] = { ++ { ++ /* 12MPix 10fps mode */ ++ .width = 4056, ++ .height = 3040, ++ .line_length_pix = 17900, ++ .crop = { ++ .left = IMX500_PIXEL_ARRAY_LEFT, ++ .top = IMX500_PIXEL_ARRAY_TOP, ++ .width = 4056, ++ .height = 3040, ++ }, ++ .framerate_default = 10, ++ .reg_list = { ++ .num_of_regs = ARRAY_SIZE(mode_4056x3040_regs), ++ .regs = mode_4056x3040_regs, ++ }, ++ }, ++ { ++ /* 2x2 binned 40fps mode */ ++ .width = 2028, ++ .height = 1520, ++ .line_length_pix = 9398, ++ .crop = { ++ .left = IMX500_PIXEL_ARRAY_LEFT, ++ .top = IMX500_PIXEL_ARRAY_TOP, ++ .width = 4056, ++ .height = 3040, ++ }, ++ .framerate_default = 40, ++ .reg_list = { ++ .num_of_regs = ARRAY_SIZE(mode_2028x1520_regs), ++ .regs = mode_2028x1520_regs, ++ }, ++ }, ++}; ++ ++/* ++ * The supported formats. ++ * This table MUST contain 4 entries per format, to cover the various flip ++ * combinations in the order ++ * - no flip ++ * - h flip ++ * - v flip ++ * - h&v flips ++ */ ++static const u32 codes[] = { ++ /* 10-bit modes. */ ++ MEDIA_BUS_FMT_SRGGB10_1X10, ++ MEDIA_BUS_FMT_SGRBG10_1X10, ++ MEDIA_BUS_FMT_SGBRG10_1X10, ++ MEDIA_BUS_FMT_SBGGR10_1X10, ++}; ++ ++struct imx500 { ++ struct v4l2_subdev sd; ++ struct media_pad pad; ++ struct regmap *regmap; ++ ++ unsigned int fmt_code; ++ ++ struct clk *xclk; ++ u32 xclk_freq; ++ ++ struct gpio_desc *reset_gpio; ++ struct regulator_bulk_data supplies[IMX500_NUM_SUPPLIES]; ++ ++ struct v4l2_ctrl_handler ctrl_handler; ++ /* V4L2 Controls */ ++ struct v4l2_ctrl *pixel_rate; ++ struct v4l2_ctrl *link_freq; ++ struct v4l2_ctrl *exposure; ++ struct v4l2_ctrl *vflip; ++ struct v4l2_ctrl *hflip; ++ struct v4l2_ctrl *vblank; ++ struct v4l2_ctrl *hblank; ++ ++ /* Current mode */ ++ const struct imx500_mode *mode; ++ ++ /* ++ * Mutex for serialized access: ++ * Protect sensor module set pad format and start/stop streaming safely. ++ */ ++ struct mutex mutex; ++ ++ /* Streaming on/off */ ++ bool streaming; ++ ++ /* Rewrite common registers on stream on? */ ++ bool common_regs_written; ++ ++ /* Current long exposure factor in use. Set through V4L2_CID_VBLANK */ ++ unsigned int long_exp_shift; ++}; ++ ++static inline struct imx500 *to_imx500(struct v4l2_subdev *_sd) ++{ ++ return container_of(_sd, struct imx500, sd); ++} ++ ++/* Get bayer order based on flip setting. */ ++static u32 imx500_get_format_code(struct imx500 *imx500) ++{ ++ unsigned int i; ++ ++ lockdep_assert_held(&imx500->mutex); ++ ++ i = (imx500->vflip->val ? 2 : 0) | (imx500->hflip->val ? 1 : 0); ++ ++ return codes[i]; ++} ++ ++static void imx500_set_default_format(struct imx500 *imx500) ++{ ++ /* Set default mode to max resolution */ ++ imx500->mode = &imx500_supported_modes[0]; ++ imx500->fmt_code = MEDIA_BUS_FMT_SRGGB10_1X10; ++} ++ ++static void imx500_adjust_exposure_range(struct imx500 *imx500) ++{ ++ int exposure_max, exposure_def; ++ ++ /* Honour the VBLANK limits when setting exposure. */ ++ exposure_max = imx500->mode->height + imx500->vblank->val - ++ IMX500_EXPOSURE_OFFSET; ++ exposure_def = min(exposure_max, imx500->exposure->val); ++ __v4l2_ctrl_modify_range(imx500->exposure, imx500->exposure->minimum, ++ exposure_max, imx500->exposure->step, ++ exposure_def); ++} ++ ++static int imx500_set_frame_length(struct imx500 *imx500, unsigned int val) ++{ ++ int ret = 0; ++ ++ imx500->long_exp_shift = 0; ++ ++ while (val > IMX500_FRAME_LENGTH_MAX) { ++ imx500->long_exp_shift++; ++ val >>= 1; ++ } ++ ++ ret = cci_write(imx500->regmap, IMX500_REG_FRAME_LENGTH, val, NULL); ++ if (ret) ++ return ret; ++ ++ return cci_write(imx500->regmap, IMX500_LONG_EXP_SHIFT_REG, ++ imx500->long_exp_shift, NULL); ++} ++ ++static int imx500_set_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct imx500 *imx500 = ++ container_of(ctrl->handler, struct imx500, ctrl_handler); ++ struct i2c_client *client = v4l2_get_subdevdata(&imx500->sd); ++ int ret = 0; ++ ++ /* ++ * The VBLANK control may change the limits of usable exposure, so check ++ * and adjust if necessary. ++ */ ++ if (ctrl->id == V4L2_CID_VBLANK) ++ imx500_adjust_exposure_range(imx500); ++ ++ /* ++ * Applying V4L2 control value only happens ++ * when power is up for streaming ++ */ ++ if (pm_runtime_get_if_in_use(&client->dev) == 0) ++ return 0; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_ANALOGUE_GAIN: ++ ret = cci_write(imx500->regmap, IMX500_REG_ANALOG_GAIN, ++ ctrl->val, NULL); ++ break; ++ case V4L2_CID_EXPOSURE: ++ ret = cci_write(imx500->regmap, IMX500_REG_EXPOSURE, ++ ctrl->val >> imx500->long_exp_shift, NULL); ++ break; ++ case V4L2_CID_HFLIP: ++ case V4L2_CID_VFLIP: ++ ret = cci_write(imx500->regmap, IMX500_REG_ORIENTATION, ++ imx500->hflip->val | imx500->vflip->val << 1, ++ NULL); ++ break; ++ case V4L2_CID_VBLANK: ++ ret = imx500_set_frame_length(imx500, ++ imx500->mode->height + ctrl->val); ++ break; ++ case V4L2_CID_HBLANK: ++ ret = cci_write(imx500->regmap, IMX500_REG_LINE_LENGTH, ++ imx500->mode->width + ctrl->val, NULL); ++ break; ++ case V4L2_CID_NOTIFY_GAINS: ++ ret = cci_write(imx500->regmap, IMX500_REG_COLOUR_BALANCE_B, ++ ctrl->p_new.p_u32[0], NULL); ++ cci_write(imx500->regmap, IMX500_REG_COLOUR_BALANCE_GB, ++ ctrl->p_new.p_u32[1], &ret); ++ cci_write(imx500->regmap, IMX500_REG_COLOUR_BALANCE_GR, ++ ctrl->p_new.p_u32[2], &ret); ++ cci_write(imx500->regmap, IMX500_REG_COLOUR_BALANCE_R, ++ ctrl->p_new.p_u32[3], &ret); ++ break; ++ default: ++ dev_info(&client->dev, ++ "ctrl(id:0x%x,val:0x%x) is not handled\n", ctrl->id, ++ ctrl->val); ++ ret = -EINVAL; ++ break; ++ } ++ ++ pm_runtime_mark_last_busy(&client->dev); ++ pm_runtime_put_autosuspend(&client->dev); ++ ++ return ret; ++} ++ ++static const struct v4l2_ctrl_ops imx500_ctrl_ops = { ++ .s_ctrl = imx500_set_ctrl, ++}; ++ ++static const struct v4l2_ctrl_config imx500_notify_gains_ctrl = { ++ .ops = &imx500_ctrl_ops, ++ .id = V4L2_CID_NOTIFY_GAINS, ++ .type = V4L2_CTRL_TYPE_U32, ++ .min = IMX500_COLOUR_BALANCE_MIN, ++ .max = IMX500_COLOUR_BALANCE_MAX, ++ .step = IMX500_COLOUR_BALANCE_STEP, ++ .def = IMX500_COLOUR_BALANCE_DEFAULT, ++ .dims = { 4 }, ++ .elem_size = sizeof(u32), ++}; ++ ++static int imx500_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ struct imx500 *imx500 = to_imx500(sd); ++ ++ if (code->pad >= NUM_PADS) ++ return -EINVAL; ++ ++ if (code->index != 0) ++ return -EINVAL; ++ ++ code->code = imx500_get_format_code(imx500); ++ ++ return 0; ++} ++ ++static int imx500_enum_frame_size(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_frame_size_enum *fse) ++{ ++ struct imx500 *imx500 = to_imx500(sd); ++ ++ if (fse->pad >= NUM_PADS) ++ return -EINVAL; ++ ++ const struct imx500_mode *mode_list = imx500_supported_modes; ++ unsigned int num_modes = ARRAY_SIZE(imx500_supported_modes); ++ ++ if (fse->index >= num_modes) ++ return -EINVAL; ++ ++ if (fse->code != imx500_get_format_code(imx500)) ++ return -EINVAL; ++ ++ fse->min_width = mode_list[fse->index].width; ++ fse->max_width = fse->min_width; ++ fse->min_height = mode_list[fse->index].height; ++ fse->max_height = fse->min_height; ++ ++ return 0; ++} ++ ++static void imx500_update_image_pad_format(struct imx500 *imx500, ++ const struct imx500_mode *mode, ++ struct v4l2_subdev_format *fmt) ++{ ++ fmt->format.width = mode->width; ++ fmt->format.height = mode->height; ++ fmt->format.field = V4L2_FIELD_NONE; ++ fmt->format.colorspace = V4L2_COLORSPACE_RAW; ++ fmt->format.ycbcr_enc = ++ V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->format.colorspace); ++ fmt->format.quantization = V4L2_MAP_QUANTIZATION_DEFAULT( ++ true, fmt->format.colorspace, fmt->format.ycbcr_enc); ++ fmt->format.xfer_func = ++ V4L2_MAP_XFER_FUNC_DEFAULT(fmt->format.colorspace); ++} ++ ++static int imx500_get_pad_format(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_format *fmt) ++{ ++ struct imx500 *imx500 = to_imx500(sd); ++ ++ if (fmt->pad >= NUM_PADS) ++ return -EINVAL; ++ ++ mutex_lock(&imx500->mutex); ++ ++ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { ++ struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_get_try_format( ++ &imx500->sd, sd_state, fmt->pad); ++ /* update the code which could change due to vflip or hflip */ ++ try_fmt->code = imx500_get_format_code(imx500); ++ fmt->format = *try_fmt; ++ } else { ++ imx500_update_image_pad_format(imx500, imx500->mode, fmt); ++ fmt->format.code = imx500_get_format_code(imx500); ++ } ++ ++ mutex_unlock(&imx500->mutex); ++ return 0; ++} ++ ++static unsigned int imx500_get_frame_length(const struct imx500_mode *mode, ++ unsigned int framerate_default) ++{ ++ u64 frame_length; ++ ++ frame_length = IMX500_PIXEL_RATE; ++ do_div(frame_length, (u64)framerate_default * mode->line_length_pix); ++ ++ if (WARN_ON(frame_length > IMX500_FRAME_LENGTH_MAX)) ++ frame_length = IMX500_FRAME_LENGTH_MAX; ++ ++ return max_t(unsigned int, frame_length, mode->height); ++} ++ ++static void imx500_set_framing_limits(struct imx500 *imx500) ++{ ++ unsigned int frm_length_default, hblank_min; ++ const struct imx500_mode *mode = imx500->mode; ++ ++ frm_length_default = ++ imx500_get_frame_length(mode, mode->framerate_default); ++ ++ /* Default to no long exposure multiplier. */ ++ imx500->long_exp_shift = 0; ++ ++ /* Update limits and set FPS to default */ ++ __v4l2_ctrl_modify_range( ++ imx500->vblank, 1, ++ ((1 << IMX500_LONG_EXP_SHIFT_MAX) * IMX500_FRAME_LENGTH_MAX) - ++ mode->height, ++ IMX500_VBLANK_MIN, frm_length_default - mode->height); ++ ++ /* Setting this will adjust the exposure limits as well. */ ++ __v4l2_ctrl_s_ctrl(imx500->vblank, frm_length_default - mode->height); ++ ++ hblank_min = mode->line_length_pix - mode->width; ++ __v4l2_ctrl_modify_range(imx500->hblank, hblank_min, hblank_min, 1, ++ hblank_min); ++ __v4l2_ctrl_s_ctrl(imx500->hblank, hblank_min); ++} ++ ++static int imx500_set_pad_format(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_format *fmt) ++{ ++ struct v4l2_mbus_framefmt *framefmt; ++ const struct imx500_mode *mode; ++ struct imx500 *imx500 = to_imx500(sd); ++ ++ if (fmt->pad >= NUM_PADS) ++ return -EINVAL; ++ ++ mutex_lock(&imx500->mutex); ++ ++ const struct imx500_mode *mode_list = imx500_supported_modes; ++ unsigned int num_modes = ARRAY_SIZE(imx500_supported_modes); ++ ++ /* Bayer order varies with flips */ ++ fmt->format.code = imx500_get_format_code(imx500); ++ ++ mode = v4l2_find_nearest_size(mode_list, num_modes, width, height, ++ fmt->format.width, fmt->format.height); ++ imx500_update_image_pad_format(imx500, mode, fmt); ++ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { ++ framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); ++ *framefmt = fmt->format; ++ } else if (imx500->mode != mode) { ++ imx500->mode = mode; ++ imx500->fmt_code = fmt->format.code; ++ imx500_set_framing_limits(imx500); ++ } ++ ++ mutex_unlock(&imx500->mutex); ++ ++ return 0; ++} ++ ++static const struct v4l2_rect * ++__imx500_get_pad_crop(struct imx500 *imx500, struct v4l2_subdev_state *sd_state, ++ unsigned int pad, enum v4l2_subdev_format_whence which) ++{ ++ switch (which) { ++ case V4L2_SUBDEV_FORMAT_TRY: ++ return v4l2_subdev_get_try_crop(&imx500->sd, sd_state, pad); ++ case V4L2_SUBDEV_FORMAT_ACTIVE: ++ return &imx500->mode->crop; ++ } ++ ++ return NULL; ++} ++ ++static int imx500_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_selection *sel) ++{ ++ switch (sel->target) { ++ case V4L2_SEL_TGT_CROP: { ++ struct imx500 *imx500 = to_imx500(sd); ++ ++ mutex_lock(&imx500->mutex); ++ sel->r = *__imx500_get_pad_crop(imx500, sd_state, sel->pad, ++ sel->which); ++ mutex_unlock(&imx500->mutex); ++ ++ return 0; ++ } ++ ++ case V4L2_SEL_TGT_NATIVE_SIZE: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = IMX500_NATIVE_WIDTH; ++ sel->r.height = IMX500_NATIVE_HEIGHT; ++ ++ return 0; ++ ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ sel->r.left = IMX500_PIXEL_ARRAY_LEFT; ++ sel->r.top = IMX500_PIXEL_ARRAY_TOP; ++ sel->r.width = IMX500_PIXEL_ARRAY_WIDTH; ++ sel->r.height = IMX500_PIXEL_ARRAY_HEIGHT; ++ ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++/* Start streaming */ ++static int imx500_start_streaming(struct imx500 *imx500) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&imx500->sd); ++ const struct imx500_reg_list *reg_list; ++ int ret; ++ ++ ret = pm_runtime_resume_and_get(&client->dev); ++ if (ret < 0) ++ return ret; ++ ++ ret = cci_write(imx500->regmap, IMX500_REG_IMAGE_ONLY_MODE, ++ IMX500_IMAGE_ONLY_TRUE, ++ NULL); ++ if (ret) { ++ dev_err(&client->dev, "%s failed to set image mode\n", ++ __func__); ++ return ret; ++ } ++ ++ if (!imx500->common_regs_written) { ++ ret = cci_multi_reg_write(imx500->regmap, mode_common_regs, ++ ARRAY_SIZE(mode_common_regs), NULL); ++ ++ if (ret) { ++ dev_err(&client->dev, ++ "%s failed to set common settings\n", __func__); ++ return ret; ++ } ++ ++ imx500->common_regs_written = true; ++ } ++ ++ /* Apply default values of current mode */ ++ reg_list = &imx500->mode->reg_list; ++ ret = cci_multi_reg_write(imx500->regmap, reg_list->regs, ++ reg_list->num_of_regs, NULL); ++ if (ret) { ++ dev_err(&client->dev, "%s failed to set mode\n", __func__); ++ return ret; ++ } ++ ++ /* Apply customized values from user */ ++ ret = __v4l2_ctrl_handler_setup(imx500->sd.ctrl_handler); ++ ++ /* Disable any sensor startup frame drops. This must be written here! */ ++ cci_write(imx500->regmap, CCI_REG8(0xD405), 0, &ret); ++ ++ /* set stream on register */ ++ cci_write(imx500->regmap, IMX500_REG_MODE_SELECT, IMX500_MODE_STREAMING, ++ &ret); ++ ++ return ret; ++} ++ ++/* Stop streaming */ ++static void imx500_stop_streaming(struct imx500 *imx500) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&imx500->sd); ++ int ret; ++ ++ /* set stream off register */ ++ ret = cci_write(imx500->regmap, IMX500_REG_MODE_SELECT, ++ IMX500_MODE_STANDBY, NULL); ++ if (ret) ++ dev_err(&client->dev, "%s failed to set stream\n", __func__); ++ ++ pm_runtime_mark_last_busy(&client->dev); ++ pm_runtime_put_autosuspend(&client->dev); ++} ++ ++static int imx500_set_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct imx500 *imx500 = to_imx500(sd); ++ int ret = 0; ++ ++ mutex_lock(&imx500->mutex); ++ if (imx500->streaming == enable) { ++ mutex_unlock(&imx500->mutex); ++ return 0; ++ } ++ ++ if (enable) { ++ /* ++ * Apply default & customized values ++ * and then start streaming. ++ */ ++ ret = imx500_start_streaming(imx500); ++ if (ret) ++ goto err_start_streaming; ++ } else { ++ imx500_stop_streaming(imx500); ++ } ++ ++ imx500->streaming = enable; ++ ++ /* vflip and hflip cannot change during streaming */ ++ __v4l2_ctrl_grab(imx500->vflip, enable); ++ __v4l2_ctrl_grab(imx500->hflip, enable); ++ ++ mutex_unlock(&imx500->mutex); ++ ++ return ret; ++ ++err_start_streaming: ++ mutex_unlock(&imx500->mutex); ++ ++ return ret; ++} ++ ++/* Power/clock management functions */ ++static int imx500_power_on(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct imx500 *imx500 = to_imx500(sd); ++ int ret; ++ ++ ret = regulator_bulk_enable(IMX500_NUM_SUPPLIES, imx500->supplies); ++ if (ret) { ++ dev_err(&client->dev, "%s: failed to enable regulators\n", ++ __func__); ++ return ret; ++ } ++ ++ /* T4 - 1us ++ * Ambiguous: Regulators rising to INCK start is specified by the datasheet ++ * but also "Presence of INCK during Power off is acceptable" ++ */ ++ udelay(2); ++ ++ ret = clk_prepare_enable(imx500->xclk); ++ if (ret) { ++ dev_err(&client->dev, "%s: failed to enable clock\n", __func__); ++ goto reg_off; ++ } ++ ++ /* T5 - 0ms ++ * Ambiguous: Regulators rising to XCLR rising is specified by the datasheet ++ * as 0ms but also "XCLR pin should be set to 'High' after INCK supplied.". ++ * T4 and T5 are shown as overlapping. ++ */ ++ gpiod_set_value_cansleep(imx500->reset_gpio, 1); ++ ++ /* T7 - 9ms ++ * "INCK start and CXLR rising till Send Streaming Command wait time" ++ */ ++ usleep_range(9000, 12000); ++ ++ return 0; ++ ++reg_off: ++ regulator_bulk_disable(IMX500_NUM_SUPPLIES, imx500->supplies); ++ return ret; ++} ++ ++static int imx500_power_off(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct imx500 *imx500 = to_imx500(sd); ++ ++ /* Datasheet specifies power down sequence as INCK disable, XCLR low, ++ * regulator disable. T1 (XCLR neg-edge to regulator disable) is specified ++ * as 0us. ++ * ++ * Note, this is not the reverse order of power up. ++ */ ++ clk_disable_unprepare(imx500->xclk); ++ gpiod_set_value_cansleep(imx500->reset_gpio, 0); ++ regulator_bulk_disable(IMX500_NUM_SUPPLIES, imx500->supplies); ++ ++ /* Force reprogramming of the common registers when powered up again. */ ++ imx500->common_regs_written = false; ++ ++ return 0; ++} ++ ++static int imx500_get_regulators(struct imx500 *imx500) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&imx500->sd); ++ unsigned int i; ++ ++ for (i = 0; i < IMX500_NUM_SUPPLIES; i++) ++ imx500->supplies[i].supply = imx500_supply_name[i]; ++ ++ return devm_regulator_bulk_get(&client->dev, IMX500_NUM_SUPPLIES, ++ imx500->supplies); ++} ++ ++/* Verify chip ID */ ++static int imx500_identify_module(struct imx500 *imx500) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&imx500->sd); ++ int ret; ++ u64 val; ++ ++ ret = cci_read(imx500->regmap, IMX500_REG_CHIP_ID, &val, NULL); ++ if (ret) { ++ dev_err(&client->dev, ++ "failed to read chip id %x, with error %d\n", ++ IMX500_CHIP_ID, ret); ++ return ret; ++ } ++ ++ if (val != IMX500_CHIP_ID) { ++ dev_err(&client->dev, "chip id mismatch: %x!=%llx\n", ++ IMX500_CHIP_ID, val); ++ return -EIO; ++ } ++ ++ dev_info(&client->dev, "Device found is imx%llx\n", val); ++ ++ return 0; ++} ++ ++static const struct v4l2_subdev_core_ops imx500_core_ops = { ++ .subscribe_event = v4l2_ctrl_subdev_subscribe_event, ++ .unsubscribe_event = v4l2_event_subdev_unsubscribe, ++}; ++ ++static const struct v4l2_subdev_video_ops imx500_video_ops = { ++ .s_stream = imx500_set_stream, ++}; ++ ++static const struct v4l2_subdev_pad_ops imx500_pad_ops = { ++ .enum_mbus_code = imx500_enum_mbus_code, ++ .get_fmt = imx500_get_pad_format, ++ .set_fmt = imx500_set_pad_format, ++ .get_selection = imx500_get_selection, ++ .enum_frame_size = imx500_enum_frame_size, ++}; ++ ++static const struct v4l2_subdev_ops imx500_subdev_ops = { ++ .core = &imx500_core_ops, ++ .video = &imx500_video_ops, ++ .pad = &imx500_pad_ops, ++}; ++ ++static const s64 imx500_link_freq_menu[] = { ++ IMX500_DEFAULT_LINK_FREQ, ++}; ++ ++/* Initialize control handlers */ ++static int imx500_init_controls(struct imx500 *imx500) ++{ ++ struct v4l2_ctrl_handler *ctrl_hdlr; ++ struct i2c_client *client = v4l2_get_subdevdata(&imx500->sd); ++ struct v4l2_fwnode_device_properties props; ++ int ret; ++ ++ ctrl_hdlr = &imx500->ctrl_handler; ++ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 16); ++ if (ret) ++ return ret; ++ ++ mutex_init(&imx500->mutex); ++ ctrl_hdlr->lock = &imx500->mutex; ++ ++ /* By default, PIXEL_RATE is read only */ ++ imx500->pixel_rate = v4l2_ctrl_new_std( ++ ctrl_hdlr, &imx500_ctrl_ops, V4L2_CID_PIXEL_RATE, ++ IMX500_PIXEL_RATE, IMX500_PIXEL_RATE, 1, IMX500_PIXEL_RATE); ++ ++ /* LINK_FREQ is also read only */ ++ imx500->link_freq = ++ v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx500_ctrl_ops, ++ V4L2_CID_LINK_FREQ, ++ ARRAY_SIZE(imx500_link_freq_menu) - 1, 0, ++ imx500_link_freq_menu); ++ if (imx500->link_freq) ++ imx500->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ ++ /* ++ * Create the controls here, but mode specific limits are setup ++ * in the imx500_set_framing_limits() call below. ++ */ ++ imx500->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx500_ctrl_ops, ++ V4L2_CID_VBLANK, 0, 0xffff, 1, 0); ++ imx500->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx500_ctrl_ops, ++ V4L2_CID_HBLANK, 0, 0xffff, 1, 0); ++ ++ imx500->exposure = v4l2_ctrl_new_std( ++ ctrl_hdlr, &imx500_ctrl_ops, V4L2_CID_EXPOSURE, ++ IMX500_EXPOSURE_MIN, IMX500_EXPOSURE_MAX, IMX500_EXPOSURE_STEP, ++ IMX500_EXPOSURE_DEFAULT); ++ ++ v4l2_ctrl_new_std(ctrl_hdlr, &imx500_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, ++ IMX500_ANA_GAIN_MIN, IMX500_ANA_GAIN_MAX, ++ IMX500_ANA_GAIN_STEP, IMX500_ANA_GAIN_DEFAULT); ++ ++ imx500->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx500_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ if (imx500->hflip) ++ imx500->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; ++ ++ imx500->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx500_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ if (imx500->vflip) ++ imx500->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; ++ ++ v4l2_ctrl_new_custom(ctrl_hdlr, &imx500_notify_gains_ctrl, NULL); ++ ++ if (ctrl_hdlr->error) { ++ ret = ctrl_hdlr->error; ++ dev_err(&client->dev, "%s control init failed (%d)\n", __func__, ++ ret); ++ goto error; ++ } ++ ++ ret = v4l2_fwnode_device_parse(&client->dev, &props); ++ if (ret) ++ goto error; ++ ++ ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx500_ctrl_ops, ++ &props); ++ if (ret) ++ goto error; ++ ++ imx500->sd.ctrl_handler = ctrl_hdlr; ++ ++ /* Setup exposure and frame/line length limits. */ ++ imx500_set_framing_limits(imx500); ++ ++ return 0; ++ ++error: ++ v4l2_ctrl_handler_free(ctrl_hdlr); ++ mutex_destroy(&imx500->mutex); ++ ++ return ret; ++} ++ ++static void imx500_free_controls(struct imx500 *imx500) ++{ ++ v4l2_ctrl_handler_free(imx500->sd.ctrl_handler); ++ mutex_destroy(&imx500->mutex); ++} ++ ++static int imx500_check_hwcfg(struct device *dev) ++{ ++ struct fwnode_handle *endpoint; ++ struct v4l2_fwnode_endpoint ep_cfg = { .bus_type = ++ V4L2_MBUS_CSI2_DPHY }; ++ int ret = -EINVAL; ++ ++ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); ++ if (!endpoint) { ++ dev_err(dev, "endpoint node not found\n"); ++ return -EINVAL; ++ } ++ ++ if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg)) { ++ dev_err(dev, "could not parse endpoint\n"); ++ goto error_out; ++ } ++ ++ /* Check the number of MIPI CSI2 data lanes */ ++ if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2) { ++ dev_err(dev, "only 2 data lanes are currently supported\n"); ++ goto error_out; ++ } ++ ++ /* Check the link frequency set in device tree */ ++ if (!ep_cfg.nr_of_link_frequencies) { ++ dev_err(dev, "link-frequency property not found in DT\n"); ++ goto error_out; ++ } ++ ++ if (ep_cfg.nr_of_link_frequencies != 1 || ++ ep_cfg.link_frequencies[0] != IMX500_DEFAULT_LINK_FREQ) { ++ dev_err(dev, "Link frequency not supported: %lld\n", ++ ep_cfg.link_frequencies[0]); ++ goto error_out; ++ } ++ ++ ret = 0; ++ ++error_out: ++ v4l2_fwnode_endpoint_free(&ep_cfg); ++ fwnode_handle_put(endpoint); ++ ++ return ret; ++} ++ ++static int imx500_probe(struct i2c_client *client) ++{ ++ struct device *dev = &client->dev; ++ struct imx500 *imx500; ++ int ret; ++ ++ imx500 = devm_kzalloc(&client->dev, sizeof(*imx500), GFP_KERNEL); ++ if (!imx500) ++ return -ENOMEM; ++ ++ imx500->regmap = devm_cci_regmap_init_i2c(client, 16); ++ if (IS_ERR(imx500->regmap)) ++ return dev_err_probe(dev, PTR_ERR(imx500->regmap), ++ "failed to initialise CCI\n"); ++ ++ v4l2_i2c_subdev_init(&imx500->sd, client, &imx500_subdev_ops); ++ ++ /* Check the hardware configuration in device tree */ ++ if (imx500_check_hwcfg(dev)) ++ return -EINVAL; ++ ++ /* Get system clock (xclk) */ ++ imx500->xclk = devm_clk_get(dev, NULL); ++ if (IS_ERR(imx500->xclk)) ++ return dev_err_probe(dev, PTR_ERR(imx500->xclk), ++ "failed to get xclk\n"); ++ ++ imx500->xclk_freq = clk_get_rate(imx500->xclk); ++ if (imx500->xclk_freq != IMX500_XCLK_FREQ) { ++ dev_err(dev, "xclk frequency not supported: %d Hz\n", ++ imx500->xclk_freq); ++ return -EINVAL; ++ } ++ ++ ret = imx500_get_regulators(imx500); ++ if (ret) { ++ dev_err(dev, "failed to get regulators\n"); ++ return ret; ++ } ++ ++ imx500->reset_gpio = ++ devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); ++ ++ /* ++ * The sensor must be powered for imx500_identify_module() ++ * to be able to read the CHIP_ID register ++ */ ++ ret = imx500_power_on(dev); ++ if (ret) ++ return ret; ++ ++ pm_runtime_set_active(dev); ++ pm_runtime_get_noresume(dev); ++ pm_runtime_enable(dev); ++ pm_runtime_set_autosuspend_delay(dev, 5000); ++ pm_runtime_use_autosuspend(dev); ++ ++ ret = imx500_identify_module(imx500); ++ if (ret) ++ goto error_power_off; ++ ++ /* Initialize default format */ ++ imx500_set_default_format(imx500); ++ ++ /* This needs the pm runtime to be registered. */ ++ ret = imx500_init_controls(imx500); ++ if (ret) ++ goto error_power_off; ++ ++ /* Initialize subdev */ ++ imx500->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | ++ V4L2_SUBDEV_FL_HAS_EVENTS; ++ imx500->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ++ /* Initialize source pads */ ++ imx500->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ++ ret = media_entity_pads_init(&imx500->sd.entity, NUM_PADS, ++ &imx500->pad); ++ if (ret) { ++ dev_err(dev, "failed to init entity pads: %d\n", ret); ++ goto error_handler_free; ++ } ++ ++ ret = v4l2_async_register_subdev_sensor(&imx500->sd); ++ if (ret < 0) { ++ dev_err(dev, "failed to register sensor sub-device: %d\n", ret); ++ goto error_media_entity; ++ } ++ ++ pm_runtime_mark_last_busy(&client->dev); ++ pm_runtime_put_autosuspend(&client->dev); ++ ++ return 0; ++ ++error_media_entity: ++ media_entity_cleanup(&imx500->sd.entity); ++ ++error_handler_free: ++ imx500_free_controls(imx500); ++ ++error_power_off: ++ pm_runtime_disable(&client->dev); ++ pm_runtime_put_noidle(&client->dev); ++ imx500_power_off(&client->dev); ++ ++ return ret; ++} ++ ++static void imx500_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct imx500 *imx500 = to_imx500(sd); ++ ++ v4l2_async_unregister_subdev(sd); ++ media_entity_cleanup(&sd->entity); ++ imx500_free_controls(imx500); ++ ++ pm_runtime_disable(&client->dev); ++ if (!pm_runtime_status_suspended(&client->dev)) ++ imx500_power_off(&client->dev); ++ pm_runtime_set_suspended(&client->dev); ++} ++ ++static const struct of_device_id imx500_dt_ids[] = { ++ { .compatible = "sony,imx500" }, ++ { /* sentinel */ } ++}; ++ ++MODULE_DEVICE_TABLE(of, imx500_dt_ids); ++ ++static const struct dev_pm_ops imx500_pm_ops = { SET_RUNTIME_PM_OPS( ++ imx500_power_off, imx500_power_on, NULL) }; ++ ++static struct i2c_driver imx500_i2c_driver = { ++ .driver = { ++ .name = "imx500", ++ .of_match_table = imx500_dt_ids, ++ .pm = &imx500_pm_ops, ++ }, ++ .probe = imx500_probe, ++ .remove = imx500_remove, ++}; ++ ++module_i2c_driver(imx500_i2c_driver); ++ ++MODULE_AUTHOR("Naushir Patuck "); ++MODULE_DESCRIPTION("Sony IMX500 sensor driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/bcm27xx/patches-6.6/950-1245-lib-earlycpio-export-symbol-find_cpio_data.patch b/target/linux/bcm27xx/patches-6.6/950-1245-lib-earlycpio-export-symbol-find_cpio_data.patch new file mode 100644 index 000000000000..f749e848484b --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1245-lib-earlycpio-export-symbol-find_cpio_data.patch @@ -0,0 +1,20 @@ +From a32f7dae82774d6064181dcc989c1c1349c4e47e Mon Sep 17 00:00:00 2001 +From: Richard Oliver +Date: Thu, 20 Jun 2024 09:58:32 +0100 +Subject: [PATCH 1245/1350] lib: earlycpio: export symbol find_cpio_data() + +Add EXPORT_SYMBOL_GPL() for find_cpio_data() so that loadable modules +may also parse uncompressed cpio. + +Signed-off-by: Richard Oliver +--- + lib/earlycpio.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/lib/earlycpio.c ++++ b/lib/earlycpio.c +@@ -139,3 +139,4 @@ struct cpio_data find_cpio_data(const ch + quit: + return cd; + } ++EXPORT_SYMBOL_GPL(find_cpio_data); diff --git a/target/linux/bcm27xx/patches-6.6/950-1246-media-i2c-imx500-Inbuilt-AI-processor-support.patch b/target/linux/bcm27xx/patches-6.6/950-1246-media-i2c-imx500-Inbuilt-AI-processor-support.patch new file mode 100644 index 000000000000..9a0642b375e8 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1246-media-i2c-imx500-Inbuilt-AI-processor-support.patch @@ -0,0 +1,1631 @@ +From 97f4ec49828877642e4a87f9c2f47c7a9dd10b90 Mon Sep 17 00:00:00 2001 +From: Richard Oliver +Date: Wed, 24 Jul 2024 13:06:16 +0100 +Subject: [PATCH 1246/1350] media: i2c: imx500: Inbuilt AI processor support + +Add support for the IMX500's inbuilt AI processor. The IMX500 program +loader, AI processor firmware, DNN weights are accessed via the kernel's +firmware interface on 'open' and are transferred to the IMX500 over SPI. + +Signed-off-by: Richard Oliver +--- + drivers/media/i2c/imx500.c | 1322 +++++++++++++++++++++++++++- + include/uapi/linux/v4l2-controls.h | 6 + + 2 files changed, 1290 insertions(+), 38 deletions(-) + +--- a/drivers/media/i2c/imx500.c ++++ b/drivers/media/i2c/imx500.c +@@ -5,9 +5,14 @@ + */ + #include + #include ++#include + #include ++#include ++#include + #include + #include ++#include ++#include + #include + #include + #include +@@ -67,6 +72,138 @@ + #define IMX500_ANA_GAIN_STEP 1 + #define IMX500_ANA_GAIN_DEFAULT 0x0 + ++/* Inference windows */ ++#define IMX500_REG_DWP_AP_VC_VOFF CCI_REG16(0xD500) ++#define IMX500_REG_DWP_AP_VC_HOFF CCI_REG16(0xD502) ++#define IMX500_REG_DWP_AP_VC_VSIZE CCI_REG16(0xD504) ++#define IMX500_REG_DWP_AP_VC_HSIZE CCI_REG16(0xD506) ++ ++#define IMX500_REG_DD_CH06_X_OUT_SIZE \ ++ CCI_REG16(0x3054) /* Output pixel count for KPI */ ++#define IMX500_REG_DD_CH07_X_OUT_SIZE \ ++ CCI_REG16(0x3056) /* Output pixel count for Input Tensor */ ++#define IMX500_REG_DD_CH08_X_OUT_SIZE \ ++ CCI_REG16(0x3058) /* Output pixel count for Output Tensor */ ++#define IMX500_REG_DD_CH09_X_OUT_SIZE \ ++ CCI_REG16(0x305A) /* Output pixel count for PQ Settings */ ++ ++#define IMX500_REG_DD_CH06_Y_OUT_SIZE \ ++ CCI_REG16(0x305C) /* Output line count for KPI */ ++#define IMX500_REG_DD_CH07_Y_OUT_SIZE \ ++ CCI_REG16(0x305E) /* Output line count for Input Tensor */ ++#define IMX500_REG_DD_CH08_Y_OUT_SIZE \ ++ CCI_REG16(0x3060) /* Output line count for Output Tensor */ ++#define IMX500_REG_DD_CH09_Y_OUT_SIZE \ ++ CCI_REG16(0x3062) /* Output line count for PQ Settings */ ++ ++#define IMX500_REG_DD_CH06_VCID \ ++ CCI_REG8(0x3064) /* Virtual channel ID for KPI */ ++#define IMX500_REG_DD_CH07_VCID \ ++ CCI_REG8(0x3065) /* Virtual channel ID for Input Tensor */ ++#define IMX500_REG_DD_CH08_VCID \ ++ CCI_REG8(0x3066) /* Virtual channel ID for Output Tensor */ ++#define IMX500_REG_DD_CH09_VCID \ ++ CCI_REG8(0x3067) /* Virtual channel ID for PQ Settings */ ++ ++#define IMX500_REG_DD_CH06_DT CCI_REG8(0x3068) /* Data Type for KPI */ ++#define IMX500_REG_DD_CH07_DT CCI_REG8(0x3069) /* Data Type for Input Tensor */ ++#define IMX500_REG_DD_CH08_DT CCI_REG8(0x306A) /* Data Type for Output Tensor */ ++#define IMX500_REG_DD_CH09_DT CCI_REG8(0x306B) /* Data Type for PQ Settings */ ++ ++#define IMX500_REG_DD_CH06_PACKING \ ++ CCI_REG8(0x306C) /* Pixel/byte packing for KPI */ ++#define IMX500_REG_DD_CH07_PACKING \ ++ CCI_REG8(0x306D) /* Pixel/byte packing for Input Tensor */ ++#define IMX500_REG_DD_CH08_PACKING \ ++ CCI_REG8(0x306E) /* Pixel/byte packing for Output Tensor */ ++#define IMX500_REG_DD_CH09_PACKING \ ++ CCI_REG8(0x306F) /* Pixel/byte packing for PQ Settings */ ++#define IMX500_DD_PACKING_8BPP 2 /* 8 bits/pixel */ ++#define IMX500_DD_PACKING_10BPP 3 /* 10 bits/pixel */ ++ ++/* Interrupt command (start processing command inside IMX500 CPU) */ ++#define IMX500_REG_DD_CMD_INT CCI_REG8(0x3080) ++#define IMX500_DD_CMD_INT_ST_TRANS 0 ++#define IMX500_DD_CMD_INT_UPDATE 1 ++#define IMX500_DD_CMD_INT_FLASH_ERASE 2 ++ ++/* State transition command type */ ++#define IMX500_REG_DD_ST_TRANS_CMD CCI_REG8(0xD000) ++#define IMX500_DD_ST_TRANS_CMD_LOADER_FW 0 ++#define IMX500_DD_ST_TRANS_CMD_MAIN_FW 1 ++#define IMX500_DD_ST_TRANS_CMD_NW_WEIGHTS 2 ++#define IMX500_DD_ST_TRANS_CMD_CLEAR_WEIGHTS 3 ++ ++/* Network weights update command */ ++#define IMX500_REG_DD_UPDATE_CMD CCI_REG8(0xD001) ++#define IMX500_DD_UPDATE_CMD_SRAM 0 ++#define IMX500_DD_UPDATE_CMD_FLASH 1 ++ ++/* Transfer source when loading into RAM */ ++#define IMX500_REG_DD_LOAD_MODE CCI_REG8(0xD002) ++#define IMX500_DD_LOAD_MODE_AP 0 ++#define IMX500_DD_LOAD_MODE_FLASH 1 ++ ++/* Image type to transfer */ ++#define IMX500_REG_DD_IMAGE_TYPE CCI_REG8(0xD003) ++#define IMX500_DD_IMAGE_TYPE_LOADER_FW 0 ++#define IMX500_DD_IMAGE_TYPE_MAIN_FW 1 ++#define IMX500_DD_IMAGE_TYPE_NETWORK_WEIGHTS 2 ++ ++/* Number of divisions of download image file */ ++#define IMX500_REG_DD_DOWNLOAD_DIV_NUM CCI_REG8(0xD004) ++ ++#define IMX500_REG_DD_FLASH_TYPE CCI_REG8(0xD005) ++ ++/* total size of download file (4-byte) */ ++#define IMX500_REG_DD_DOWNLOAD_FILE_SIZE CCI_REG32(0xD008) ++ ++/* Status notification (4-byte) */ ++#define IMX500_REG_DD_REF_STS CCI_REG32(0xD010) ++#define IMX500_DD_REF_STS_FATAL 0xFF ++#define IMX500_DD_REF_STS_DETECT_CNT 0xFF00 ++#define IMX500_DD_REF_STS_ERR_CNT 0xFF0000 ++#define IMX500_DD_REF_CMD_REPLY_CNT 0xFF000000 ++ ++/* Command reply status */ ++#define IMX500_REG_DD_CMD_REPLY_STS CCI_REG8(0xD014) ++#define IMX500_DD_CMD_REPLY_STS_TRANS_READY 0x00 ++#define IMX500_DD_CMD_REPLY_STS_TRANS_DONE 0x01 ++#define IMX500_DD_CMD_REPLY_STS_UPDATE_READY 0x10 ++#define IMX500_DD_CMD_REPLY_STS_UPDATE_DONE 0x11 ++#define IMX500_DD_CMD_REPLY_STS_UPDATE_CANCEL_DONE 0x12 ++#define IMX500_DD_CMD_REPLY_STS_STATUS_ERROR 0xFF ++#define IMX500_DD_CMD_REPLY_STS_MAC_AUTH_ERROR 0xFE ++#define IMX500_DD_CMD_REPLY_STS_TIMEOUT_ERROR 0xFD ++#define IMX500_DD_CMD_REPLY_STS_PARAMETER_ERROR 0xFC ++#define IMX500_DD_CMD_REPLY_STS_INTERNAL_ERROR 0xFB ++#define IMX500_DD_CMD_REPLY_STS_PACKET_FMT_ERROR 0xFA ++ ++/* Download status */ ++#define IMX500_REG_DD_DOWNLOAD_STS CCI_REG8(0xD015) ++#define IMX500_DD_DOWNLOAD_STS_READY 0 ++#define IMX500_DD_DOWNLOAD_STS_DOWNLOADING 1 ++ ++/* Update cancel */ ++#define IMX500_REG_DD_UPDATE_CANCEL CCI_REG8(0xD016) ++#define IMX500_DD_UPDATE_CANCEL_NOT_CANCEL 0 ++#define IMX500_DD_UPDATE_CANCEL_DO_CANCEL 1 ++ ++/* Notify error status */ ++#define IMX500_REG_DD_ERR_STS CCI_REG8(0xD020) ++#define IMX500_DD_ERR_STS_STATUS_ERROR_BIT 0x1 ++#define IMX500_DD_ERR_STS_INTERNAL_ERROR_BIT 0x2 ++#define IMX500_DD_ERR_STS_PARAMETER_ERROR_BIT 0x4 ++ ++/* System state */ ++#define IMX500_REG_DD_SYS_STATE CCI_REG8(0xD02A) ++#define IMX500_DD_SYS_STATE_STANDBY_NO_NETWORK 0 ++#define IMX500_DD_SYS_STATE_STEAMING_NO_NETWORK 1 ++#define IMX500_DD_SYS_STATE_STANDBY_WITH_NETWORK 2 ++#define IMX500_DD_SYS_STATE_STREAMING_WITH_NETWORK 3 ++ ++#define IMX500_REG_MAIN_FW_VERSION CCI_REG32(0xD07C) ++ + /* Colour balance controls */ + #define IMX500_REG_COLOUR_BALANCE_R CCI_REG16(0xd804) + #define IMX500_REG_COLOUR_BALANCE_GR CCI_REG16(0xd806) +@@ -81,6 +218,11 @@ + #define IMX500_MAX_EMBEDDED_SIZE \ + (2 * ((((IMX500_PIXEL_ARRAY_WIDTH * 10) >> 3) + 15) & ~15)) + ++/* Inference sizes */ ++#define IMX500_INFERENCE_LINE_WIDTH 2560 ++#define IMX500_NUM_KPI_LINES 1 ++#define IMX500_NUM_PQ_LINES 1 ++ + /* IMX500 native and active pixel array size. */ + #define IMX500_NATIVE_WIDTH 4072U + #define IMX500_NATIVE_HEIGHT 3176U +@@ -89,7 +231,12 @@ + #define IMX500_PIXEL_ARRAY_WIDTH 4056U + #define IMX500_PIXEL_ARRAY_HEIGHT 3040U + +-#define NUM_PADS 1 ++enum pad_types { IMAGE_PAD, METADATA_PAD, NUM_PADS }; ++ ++#define V4L2_CID_USER_IMX500_INFERENCE_WINDOW (V4L2_CID_USER_IMX500_BASE + 0) ++#define V4L2_CID_USER_IMX500_NETWORK_FW_FD (V4L2_CID_USER_IMX500_BASE + 1) ++ ++#define ONE_MIB (1024 * 1024) + + /* regulator supplies */ + static const char *const imx500_supply_name[] = { +@@ -101,6 +248,13 @@ static const char *const imx500_supply_n + + #define IMX500_NUM_SUPPLIES ARRAY_SIZE(imx500_supply_name) + ++enum imx500_image_type { ++ TYPE_LOADER = 0, ++ TYPE_MAIN = 1, ++ TYPE_NW_WEIGHTS = 2, ++ TYPE_MAX ++}; ++ + struct imx500_reg_list { + unsigned int num_of_regs; + const struct cci_reg_sequence *regs; +@@ -135,10 +289,19 @@ static const struct cci_reg_sequence mod + { CCI_REG8(0x0106), 0x01 }, /* FAST_STANDBY_CTL */ + { CCI_REG8(0x0136), 0x1b }, /* EXCLK_FREQ */ + { CCI_REG8(0x0137), 0x00 }, +- { CCI_REG8(0x0138), 0x01 }, /* TEMP_SENS_CTL */ + { CCI_REG8(0x0112), 0x0a }, + { CCI_REG8(0x0113), 0x0a }, + { CCI_REG8(0x0114), 0x01 }, /* CSI_LANE_MODE */ ++ { CCI_REG16(0x3054), IMX500_INFERENCE_LINE_WIDTH }, ++ { CCI_REG16(0x3056), IMX500_INFERENCE_LINE_WIDTH }, ++ { CCI_REG16(0x3058), IMX500_INFERENCE_LINE_WIDTH }, ++ { CCI_REG16(0x305A), IMX500_INFERENCE_LINE_WIDTH }, /* X_OUT */ ++ { CCI_REG16(0x305C), IMX500_NUM_KPI_LINES }, /* KPI Y_OUT */ ++ { CCI_REG16(0x3062), IMX500_NUM_PQ_LINES }, /* PQ Y_OUT */ ++ { CCI_REG8(0x3068), 0x30 }, ++ { CCI_REG8(0x3069), 0x31 }, ++ { CCI_REG8(0x306A), 0x32 }, ++ { CCI_REG8(0x306B), 0x33 }, /* Data Types */ + }; + + /* 12 mpix 15fps */ +@@ -624,6 +787,111 @@ static const struct cci_reg_sequence mod + { CCI_REG8(0x0215), 0x00 }, + }; + ++static const struct cci_reg_sequence metadata_output[] = { ++ { CCI_REG8(0x3050), 1 }, /* MIPI Output enabled */ ++ { CCI_REG8(0x3051), 1 }, /* MIPI output frame includes pixels data */ ++ { CCI_REG8(0x3052), 1 }, /* MIPI output frame includes meta data */ ++ { IMX500_REG_DD_CH06_VCID, 0 }, ++ { IMX500_REG_DD_CH07_VCID, 0 }, ++ { IMX500_REG_DD_CH08_VCID, 0 }, ++ { IMX500_REG_DD_CH09_VCID, 0 }, ++ { IMX500_REG_DD_CH06_DT, ++ 0x12 }, /* KPI - User Defined 8-bit Data Type 1 */ ++ { IMX500_REG_DD_CH07_DT, 0x12 }, /* Input Tensor - U.D. 8-bit type 2 */ ++ { IMX500_REG_DD_CH08_DT, 0x12 }, /* Output Tensor - U.D. 8-bit type 3 */ ++ { IMX500_REG_DD_CH09_DT, 0x12 }, /* PQ - U.D. 8-bit type 4 */ ++ { IMX500_REG_DD_CH06_PACKING, IMX500_DD_PACKING_8BPP }, ++ { IMX500_REG_DD_CH07_PACKING, IMX500_DD_PACKING_8BPP }, ++ { IMX500_REG_DD_CH08_PACKING, IMX500_DD_PACKING_8BPP }, ++ { IMX500_REG_DD_CH09_PACKING, IMX500_DD_PACKING_8BPP }, ++}; ++ ++static const struct cci_reg_sequence dnn_regs[] = { ++ { CCI_REG8(0xd960), 0x52 }, ++ { CCI_REG8(0xd961), 0x52 }, ++ { CCI_REG8(0xd962), 0x52 }, ++ { CCI_REG8(0xd963), 0x52 }, ++ { CCI_REG8(0xd96c), 0x44 }, ++ { CCI_REG8(0xd96d), 0x44 }, ++ { CCI_REG8(0xd96e), 0x44 }, ++ { CCI_REG8(0xd96f), 0x44 }, ++ { CCI_REG8(0xd600), 0x20 }, ++ /* Black level */ ++ { CCI_REG16(0xd80c), 0x100 }, ++ { CCI_REG16(0xd80e), 0x100 }, ++ { CCI_REG16(0xd810), 0x100 }, ++ { CCI_REG16(0xd812), 0x100 }, ++ /* Gamma */ ++ { CCI_REG8(0xd814), 1 }, ++ { CCI_REG32(0xd850), 0x10000 }, ++ { CCI_REG32(0xd854), 0x40002 }, ++ { CCI_REG32(0xd858), 0x60005 }, ++ { CCI_REG32(0xd85c), 0x90008 }, ++ { CCI_REG32(0xd860), 0xc000a }, ++ { CCI_REG32(0xd864), 0x12000f }, ++ { CCI_REG32(0xd868), 0x1c0014 }, ++ { CCI_REG32(0xd86c), 0x2a0024 }, ++ { CCI_REG32(0xd870), 0x360030 }, ++ { CCI_REG32(0xd874), 0x46003c }, ++ { CCI_REG32(0xd878), 0x5a0051 }, ++ { CCI_REG32(0xd87c), 0x750064 }, ++ { CCI_REG32(0xd880), 0x920084 }, ++ { CCI_REG32(0xd884), 0xa9009e }, ++ { CCI_REG32(0xd888), 0xba00b2 }, ++ { CCI_REG32(0xd88c), 0xc700c1 }, ++ { CCI_REG32(0xd890), 0xd100cd }, ++ { CCI_REG32(0xd894), 0xde00d6 }, ++ { CCI_REG32(0xd898), 0xe900e4 }, ++ { CCI_REG32(0xd89c), 0xf300ee }, ++ { CCI_REG32(0xd8a0), 0xfb00f7 }, ++ { CCI_REG16(0xd8a4), 0xff }, ++ { CCI_REG32(0xd8a8), 0x10000 }, ++ { CCI_REG32(0xd8ac), 0x40002 }, ++ { CCI_REG32(0xd8b0), 0x60005 }, ++ { CCI_REG32(0xd8b4), 0x90008 }, ++ { CCI_REG32(0xd8b8), 0xc000a }, ++ { CCI_REG32(0xd8bc), 0x12000f }, ++ { CCI_REG32(0xd8c0), 0x1c0014 }, ++ { CCI_REG32(0xd8c4), 0x2a0024 }, ++ { CCI_REG32(0xd8c8), 0x360030 }, ++ { CCI_REG32(0xd8cc), 0x46003c }, ++ { CCI_REG32(0xd8d0), 0x5a0051 }, ++ { CCI_REG32(0xd8d4), 0x750064 }, ++ { CCI_REG32(0xd8d8), 0x920084 }, ++ { CCI_REG32(0xd8dc), 0xa9009e }, ++ { CCI_REG32(0xd8e0), 0xba00b2 }, ++ { CCI_REG32(0xd8e4), 0xc700c1 }, ++ { CCI_REG32(0xd8e8), 0xd100cd }, ++ { CCI_REG32(0xd8ec), 0xde00d6 }, ++ { CCI_REG32(0xd8f0), 0xe900e4 }, ++ { CCI_REG32(0xd8f4), 0xf300ee }, ++ { CCI_REG32(0xd8f8), 0xfb00f7 }, ++ { CCI_REG16(0xd8fc), 0xff }, ++ { CCI_REG32(0xd900), 0x10000 }, ++ { CCI_REG32(0xd904), 0x40002 }, ++ { CCI_REG32(0xd908), 0x60005 }, ++ { CCI_REG32(0xd90c), 0x90008 }, ++ { CCI_REG32(0xd910), 0xc000a }, ++ { CCI_REG32(0xd914), 0x12000f }, ++ { CCI_REG32(0xd918), 0x1c0014 }, ++ { CCI_REG32(0xd91c), 0x2a0024 }, ++ { CCI_REG32(0xd920), 0x360030 }, ++ { CCI_REG32(0xd924), 0x46003c }, ++ { CCI_REG32(0xd928), 0x5a0051 }, ++ { CCI_REG32(0xd92c), 0x750064 }, ++ { CCI_REG32(0xd930), 0x920084 }, ++ { CCI_REG32(0xd934), 0xa9009e }, ++ { CCI_REG32(0xd938), 0xba00b2 }, ++ { CCI_REG32(0xd93c), 0xc700c1 }, ++ { CCI_REG32(0xd940), 0xd100cd }, ++ { CCI_REG32(0xd944), 0xde00d6 }, ++ { CCI_REG32(0xd948), 0xe900e4 }, ++ { CCI_REG32(0xd94c), 0xf300ee }, ++ { CCI_REG32(0xd950), 0xfb00f7 }, ++ { CCI_REG16(0xd954), 0xff }, ++ { CCI_REG8(0xd826), 1 }, ++}; ++ + /* Mode configs */ + static const struct imx500_mode imx500_supported_modes[] = { + { +@@ -679,9 +947,17 @@ static const u32 codes[] = { + MEDIA_BUS_FMT_SBGGR10_1X10, + }; + ++enum imx500_state { ++ IMX500_STATE_RESET = 0, ++ IMX500_STATE_PROGRAM_EMPTY, ++ IMX500_STATE_WITHOUT_NETWORK, ++ IMX500_STATE_WITH_NETWORK, ++}; ++ + struct imx500 { ++ struct dentry *debugfs; + struct v4l2_subdev sd; +- struct media_pad pad; ++ struct media_pad pad[NUM_PADS]; + struct regmap *regmap; + + unsigned int fmt_code; +@@ -701,6 +977,9 @@ struct imx500 { + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *hblank; ++ struct v4l2_ctrl *network_fw_ctrl; ++ ++ struct v4l2_rect inference_window; + + /* Current mode */ + const struct imx500_mode *mode; +@@ -717,8 +996,24 @@ struct imx500 { + /* Rewrite common registers on stream on? */ + bool common_regs_written; + ++ bool loader_and_main_written; ++ bool network_written; ++ + /* Current long exposure factor in use. Set through V4L2_CID_VBLANK */ + unsigned int long_exp_shift; ++ ++ struct spi_device *spi_device; ++ ++ const struct firmware *fw_loader; ++ const struct firmware *fw_main; ++ const u8 *fw_network; ++ size_t fw_network_size; ++ size_t fw_progress; ++ unsigned int fw_stage; ++ ++ enum imx500_state fsm_state; ++ ++ u32 num_inference_lines; + }; + + static inline struct imx500 *to_imx500(struct v4l2_subdev *_sd) +@@ -726,6 +1021,188 @@ static inline struct imx500 *to_imx500(s + return container_of(_sd, struct imx500, sd); + } + ++static bool validate_normalization_yuv(u16 reg, uint8_t size, ++ uint32_t value) ++{ ++ /* Some regs are 9-bit, some 8-bit, some 1-bit */ ++ switch (reg) { ++ case 0xD62A: ++ case 0xD632: ++ case 0xD63A: ++ case 0xD644: ++ case 0xD648: ++ case 0xD64C: ++ case 0xD650: ++ case 0xD654: ++ case 0xD658: ++ return size == 2 && !(value & ~0x1FF); ++ case 0xD600: ++ case 0xD601: ++ case 0xD602: ++ return size == 1 && !(value & ~0xFF); ++ case 0xD629: ++ case 0xD630: ++ case 0xD638: ++ case 0xD643: ++ case 0xD647: ++ case 0xD64B: ++ case 0xD64F: ++ case 0xD653: ++ case 0xD657: ++ return size == 1 && !(value & ~0x01); ++ default: ++ return false; ++ } ++} ++ ++/* Common function as bayer rgb + normalization use the same repeating register ++ * layout ++ */ ++static bool validate_bit_pattern(u8 offset, uint8_t size, uint32_t value) ++{ ++ /* There are no odd register addresses */ ++ if (offset & 1) ++ return false; ++ ++ /* Valid register sizes/patterns repeat every 4 */ ++ offset = (offset >> 1) & 3; ++ ++ if (offset == 1) ++ return size == 1 && !(value & ~1); ++ else ++ return size == 2 && !(value & ~0x1FF); ++} ++ ++static bool validate_bayer_rgb_normalization(u16 reg, uint8_t size, ++ uint32_t value) ++{ ++ if (reg < 0xD684 || reg >= 0xD6E4) ++ return false; ++ return validate_bit_pattern(reg - 0xD684, size, value); ++} ++ ++static bool validate_normalization_registers(u16 reg, uint8_t size, ++ uint32_t value) ++{ ++ if (reg < 0xD708 || reg >= 0xD750) ++ return false; ++ return validate_bit_pattern(reg - 0xD708, size, value); ++} ++ ++static bool validate_image_format_selection(u16 reg, uint8_t size, ++ uint32_t value) ++{ ++ if (size != 1 || value > 5) ++ return false; ++ if (reg < 0xD750 || reg > 0xd752) ++ return false; ++ return true; ++} ++ ++static bool validate_yc_conversion_factor(u16 reg, uint8_t size, ++ uint32_t value) ++{ ++ static const u32 allowed[9] = { ++ 0x0FFF0FFF, 0x0FFF1FFF, 0x0FFF0FFF, 0x0FFF1FFF, 0x0FFF0FFF, ++ 0x0FFF1FFF, 0x01FF01FF, 0x01FF01FF, 0x01FF01FF, ++ }; ++ ++ if (size > 4 || size & 1 || reg & 1 || reg < 0x76C || reg > 0xD7FA) ++ return false; ++ ++ if (size == 2) { ++ if (reg & 2) ++ reg -= 2; ++ else ++ value <<= 16; ++ } ++ ++ /* High registers (clip values) are all 2x 9-bit */ ++ if (reg >= 0xD7D8) ++ return !(value & ~0x01FF01FF); ++ ++ /* Early registers follow a repeating pattern */ ++ reg -= 0xD76C; ++ reg >>= 2; ++ return !(value & ~allowed[reg % sizeof(allowed)]); ++} ++ ++static bool validate_dnn_output_setting(u16 reg, uint8_t size, ++ uint32_t value) ++{ ++ /* Only Y_OUT_SIZE for Input Tensor / Output Tensor is configurable from ++ * userspace ++ */ ++ return (size == 2) && (value < 2046) && ++ ((reg == CCI_REG_ADDR(IMX500_REG_DD_CH07_Y_OUT_SIZE)) || ++ (reg == CCI_REG_ADDR(IMX500_REG_DD_CH08_Y_OUT_SIZE))); ++} ++ ++static bool __must_check ++imx500_validate_inference_register(const struct cci_reg_sequence *reg) ++{ ++ unsigned int i; ++ ++ static bool (*const checks[])(uint16_t, uint8_t, uint32_t) = { ++ validate_normalization_yuv, ++ validate_bayer_rgb_normalization, ++ validate_normalization_registers, ++ validate_image_format_selection, ++ validate_yc_conversion_factor, ++ validate_dnn_output_setting, ++ }; ++ ++ if (!reg) ++ return false; ++ ++ for (i = 0; i < ARRAY_SIZE(checks); i++) { ++ if (checks[i](CCI_REG_ADDR(reg->reg), ++ CCI_REG_WIDTH_BYTES(reg->reg), reg->val)) ++ return true; ++ } ++ ++ return false; ++} ++ ++static int imx500_set_inference_window(struct imx500 *imx500) ++{ ++ u16 left, top, width, height; ++ ++ if (!imx500->inference_window.width || ++ !imx500->inference_window.height) { ++ width = 4056; ++ height = 3040; ++ left = 0; ++ top = 0; ++ } else { ++ width = min_t(u16, imx500->inference_window.width, 4056); ++ height = min_t(u16, imx500->inference_window.height, 3040); ++ left = min_t(u16, imx500->inference_window.left, 4056); ++ top = min_t(u16, imx500->inference_window.top, 3040); ++ } ++ ++ const struct cci_reg_sequence window_regs[] = { ++ { IMX500_REG_DWP_AP_VC_HOFF, left }, ++ { IMX500_REG_DWP_AP_VC_VOFF, top }, ++ { IMX500_REG_DWP_AP_VC_HSIZE, width }, ++ { IMX500_REG_DWP_AP_VC_VSIZE, height }, ++ }; ++ ++ return cci_multi_reg_write(imx500->regmap, window_regs, ++ ARRAY_SIZE(window_regs), NULL); ++} ++ ++static int imx500_reg_val_write_cbk(void *arg, ++ const struct cci_reg_sequence *reg) ++{ ++ struct imx500 *imx500 = arg; ++ ++ if (!imx500_validate_inference_register(reg)) ++ return -EINVAL; ++ ++ return cci_write(imx500->regmap, reg->reg, reg->val, NULL); ++} ++ + /* Get bayer order based on flip setting. */ + static u32 imx500_get_format_code(struct imx500 *imx500) + { +@@ -745,6 +1222,144 @@ static void imx500_set_default_format(st + imx500->fmt_code = MEDIA_BUS_FMT_SRGGB10_1X10; + } + ++/* -1 on fail, block size on success */ ++static int imx500_validate_fw_block(const char *data, size_t maxlen) ++{ ++ const size_t header_size = 32; ++ static const char header_id[] = { '9', '4', '6', '4' }; ++ ++ const size_t footer_size = 64; ++ static const char footer_id[] = { '3', '6', '9', '5' }; ++ ++ u32 data_size; ++ ++ const char *end = data + maxlen; ++ ++ if (!data) ++ return -1; ++ ++ if (maxlen < header_size) ++ return -1; ++ ++ if (memcmp(data, &header_id, sizeof(header_id))) ++ return -1; ++ ++ /* data_size is size of header + body */ ++ memcpy(&data_size, data + sizeof(header_id), sizeof(data_size)); ++ data_size = ___constant_swab32(data_size); ++ ++ if (end - data_size - footer_size < data) ++ return -1; ++ if (memcmp(data + data_size + footer_size - sizeof(footer_id), ++ &footer_id, sizeof(footer_id))) ++ return -1; ++ ++ return data_size + footer_size; ++} ++ ++/* Parse fw block by block, returning total valid fw size */ ++static size_t imx500_valid_fw_bytes(const u8 *fw, ++ const size_t fw_size) ++{ ++ int i; ++ size_t bytes = 0; ++ ++ const u8 *data = fw; ++ size_t size = fw_size; ++ ++ while ((i = imx500_validate_fw_block(data, size)) > 0) { ++ bytes += i; ++ data += i; ++ size -= i; ++ } ++ ++ return bytes; ++} ++ ++static int imx500_iterate_nw_regs( ++ const u8 *fw, size_t fw_size, void *arg, ++ int (*cbk)(void *arg, const struct cci_reg_sequence *reg)) ++{ ++ struct cpio_data cd = { NULL, 0, "" }; ++ const u8 *read_pos; ++ size_t entries; ++ size_t size; ++ ++ if (!fw || !cbk) ++ return -EINVAL; ++ ++ size = imx500_valid_fw_bytes(fw, fw_size); ++ cd = find_cpio_data("imx500_regs", (void *)(fw + size), ++ fw_size - size, NULL); ++ if (!cd.data || cd.size % 7) ++ return -EINVAL; ++ ++ read_pos = cd.data; ++ entries = cd.size / 7; ++ ++ while (entries--) { ++ struct cci_reg_sequence reg = { 0, 0 }; ++ u16 addr; ++ u8 len; ++ u32 val; ++ int ret; ++ ++ memcpy(&addr, read_pos, sizeof(addr)); ++ read_pos += sizeof(addr); ++ memcpy(&len, read_pos, sizeof(len)); ++ read_pos += sizeof(len); ++ memcpy(&val, read_pos, sizeof(val)); ++ read_pos += sizeof(val); ++ ++ reg.reg = ((len << CCI_REG_WIDTH_SHIFT) | addr); ++ reg.val = val; ++ ++ ret = cbk(arg, ®); ++ if (ret) ++ return ret; ++ } ++ return 0; ++} ++ ++static int imx500_reg_tensor_lines_cbk(void *arg, ++ const struct cci_reg_sequence *reg) ++{ ++ u16 *tensor_lines = arg; ++ ++ if (reg->val < 2046) { ++ switch (reg->reg) { ++ case IMX500_REG_DD_CH07_Y_OUT_SIZE: ++ tensor_lines[0] = reg->val; ++ break; ++ case IMX500_REG_DD_CH08_Y_OUT_SIZE: ++ tensor_lines[1] = reg->val; ++ break; ++ } ++ } ++ ++ return 0; ++} ++ ++static void imx500_calc_inference_lines(struct imx500 *imx500) ++{ ++ u16 tensor_lines[2] = { 0, 0 }; ++ ++ if (!imx500->fw_network) { ++ imx500->num_inference_lines = 0; ++ return; ++ } ++ ++ imx500_iterate_nw_regs(imx500->fw_network, imx500->fw_network_size, ++ tensor_lines, imx500_reg_tensor_lines_cbk); ++ ++ /* Full-res mode, embedded lines are actually slightly shorter than inference ++ * lines 2544 vs 2560 (over-allocate with inf. width) ++ */ ++ imx500->num_inference_lines = IMX500_NUM_KPI_LINES + ++ IMX500_NUM_PQ_LINES + tensor_lines[0] + ++ tensor_lines[1]; ++} ++ + static void imx500_adjust_exposure_range(struct imx500 *imx500) + { + int exposure_max, exposure_def; +@@ -777,6 +1392,99 @@ static int imx500_set_frame_length(struc + imx500->long_exp_shift, NULL); + } + ++/* reg is both input and output: ++ * reg->val is the value we're polling until we're NEQ to ++ * It is then populated with the updated value. ++ */ ++static int __must_check imx500_poll_status_reg(struct imx500 *state, ++ struct cci_reg_sequence *reg, ++ u8 timeout) ++{ ++ u64 read_value; ++ int ret; ++ ++ while (timeout) { ++ ret = cci_read(state->regmap, reg->reg, &read_value, NULL); ++ if (ret) ++ return ret; ++ ++ if (read_value != reg->val) { ++ reg->val = read_value; ++ return 0; ++ } ++ ++ timeout--; ++ mdelay(50); ++ } ++ return -EAGAIN; ++} ++ ++static int imx500_prepare_poll_cmd_reply_sts(struct imx500 *imx500, ++ struct cci_reg_sequence *cmd_reply) ++{ ++ /* Perform single-byte read of 4-byte IMX500_REG_DD_REF_STS register to ++ * target CMD_REPLY_STS_CNT sub-register ++ */ ++ cmd_reply->reg = CCI_REG8(CCI_REG_ADDR(IMX500_REG_DD_REF_STS)); ++ ++ return cci_read(imx500->regmap, cmd_reply->reg, &cmd_reply->val, NULL); ++} ++ ++static int imx500_clear_weights(struct imx500 *imx500) ++{ ++ struct cci_reg_sequence cmd_reply_sts_cnt_reg; ++ u64 imx500_fsm_state; ++ u64 cmd_reply; ++ int ret; ++ ++ static const struct cci_reg_sequence request_clear[] = { ++ { IMX500_REG_DD_ST_TRANS_CMD, ++ IMX500_DD_ST_TRANS_CMD_CLEAR_WEIGHTS }, ++ { IMX500_REG_DD_CMD_INT, IMX500_DD_CMD_INT_ST_TRANS }, ++ }; ++ ++ if (imx500->fsm_state != IMX500_STATE_WITH_NETWORK) ++ return -EINVAL; ++ ++ ret = cci_read(imx500->regmap, IMX500_REG_DD_SYS_STATE, ++ &imx500_fsm_state, NULL); ++ if (ret || imx500_fsm_state != IMX500_DD_SYS_STATE_STANDBY_WITH_NETWORK) ++ return ret ? ret : -EREMOTEIO; ++ ++ ret = imx500_prepare_poll_cmd_reply_sts(imx500, &cmd_reply_sts_cnt_reg); ++ if (ret) ++ return ret; ++ ++ ret = cci_multi_reg_write(imx500->regmap, request_clear, ++ ARRAY_SIZE(request_clear), NULL); ++ if (ret) ++ return ret; ++ ++ ret = imx500_poll_status_reg(imx500, &cmd_reply_sts_cnt_reg, 5); ++ if (ret) ++ return ret; ++ ++ ret = cci_read(imx500->regmap, IMX500_REG_DD_CMD_REPLY_STS, &cmd_reply, ++ NULL); ++ if (ret || cmd_reply != IMX500_DD_CMD_REPLY_STS_TRANS_DONE) ++ return ret ? ret : -EREMOTEIO; ++ ++ imx500->fsm_state = IMX500_STATE_WITHOUT_NETWORK; ++ imx500->network_written = false; ++ return 0; ++} ++ ++static void imx500_clear_fw_network(struct imx500 *imx500) ++{ ++ /* Remove any previous firmware blob. */ ++ if (imx500->fw_network) ++ vfree(imx500->fw_network); ++ ++ imx500->fw_network = NULL; ++ imx500->network_written = false; ++ imx500->fw_progress = 0; ++} ++ + static int imx500_set_ctrl(struct v4l2_ctrl *ctrl) + { + struct imx500 *imx500 = +@@ -784,6 +1492,53 @@ static int imx500_set_ctrl(struct v4l2_c + struct i2c_client *client = v4l2_get_subdevdata(&imx500->sd); + int ret = 0; + ++ if (ctrl->id == V4L2_CID_USER_IMX500_NETWORK_FW_FD) { ++ /* Reset state of the control. */ ++ if (ctrl->val < 0) { ++ return 0; ++ } else if (ctrl->val == S32_MAX) { ++ ctrl->val = -1; ++ if (pm_runtime_get_if_in_use(&client->dev) == 0) ++ return 0; ++ ++ if (imx500->network_written) ++ ret = imx500_clear_weights(imx500); ++ imx500_clear_fw_network(imx500); ++ ++ pm_runtime_mark_last_busy(&client->dev); ++ pm_runtime_put_autosuspend(&client->dev); ++ ++ return ret; ++ } ++ ++ imx500_clear_fw_network(imx500); ++ ret = kernel_read_file_from_fd(ctrl->val, 0, ++ (void **)&imx500->fw_network, INT_MAX, ++ &imx500->fw_network_size, ++ 1); ++ /* ++ * Back to reset state, the FD cannot be considered valid after ++ * this IOCTL completes. ++ */ ++ ctrl->val = -1; ++ ++ if (ret < 0) { ++ dev_err(&client->dev, "%s failed to read fw image: %d\n", ++ __func__, ret); ++ imx500_clear_fw_network(imx500); ++ return ret; ++ } ++ if (ret != imx500->fw_network_size) { ++ dev_err(&client->dev, "%s read fw image size mismatich: got %u, expected %zu\n", ++ __func__, ret, imx500->fw_network_size); ++ imx500_clear_fw_network(imx500); ++ return -EIO; ++ } ++ ++ imx500_calc_inference_lines(imx500); ++ return 0; ++ } ++ + /* + * The VBLANK control may change the limits of usable exposure, so check + * and adjust if necessary. +@@ -831,6 +1586,11 @@ static int imx500_set_ctrl(struct v4l2_c + cci_write(imx500->regmap, IMX500_REG_COLOUR_BALANCE_R, + ctrl->p_new.p_u32[3], &ret); + break; ++ case V4L2_CID_USER_IMX500_INFERENCE_WINDOW: ++ memcpy(&imx500->inference_window, ctrl->p_new.p_u32, ++ sizeof(struct v4l2_rect)); ++ ret = imx500_set_inference_window(imx500); ++ break; + default: + dev_info(&client->dev, + "ctrl(id:0x%x,val:0x%x) is not handled\n", ctrl->id, +@@ -870,10 +1630,17 @@ static int imx500_enum_mbus_code(struct + if (code->pad >= NUM_PADS) + return -EINVAL; + +- if (code->index != 0) +- return -EINVAL; ++ if (code->pad == IMAGE_PAD) { ++ if (code->index != 0) ++ return -EINVAL; + +- code->code = imx500_get_format_code(imx500); ++ code->code = imx500_get_format_code(imx500); ++ } else { ++ if (code->index > 0) ++ return -EINVAL; ++ ++ code->code = MEDIA_BUS_FMT_SENSOR_DATA; ++ } + + return 0; + } +@@ -887,19 +1654,31 @@ static int imx500_enum_frame_size(struct + if (fse->pad >= NUM_PADS) + return -EINVAL; + +- const struct imx500_mode *mode_list = imx500_supported_modes; +- unsigned int num_modes = ARRAY_SIZE(imx500_supported_modes); +- +- if (fse->index >= num_modes) +- return -EINVAL; +- +- if (fse->code != imx500_get_format_code(imx500)) +- return -EINVAL; ++ if (fse->pad == IMAGE_PAD) { ++ const struct imx500_mode *mode_list = imx500_supported_modes; ++ unsigned int num_modes = ARRAY_SIZE(imx500_supported_modes); ++ ++ if (fse->index >= num_modes) ++ return -EINVAL; ++ ++ if (fse->code != imx500_get_format_code(imx500)) ++ return -EINVAL; ++ ++ fse->min_width = mode_list[fse->index].width; ++ fse->max_width = fse->min_width; ++ fse->min_height = mode_list[fse->index].height; ++ fse->max_height = fse->min_height; ++ } else { ++ if (fse->code != MEDIA_BUS_FMT_SENSOR_DATA || fse->index > 0) ++ return -EINVAL; + +- fse->min_width = mode_list[fse->index].width; +- fse->max_width = fse->min_width; +- fse->min_height = mode_list[fse->index].height; +- fse->max_height = fse->min_height; ++ fse->min_width = IMX500_MAX_EMBEDDED_SIZE + ++ imx500->num_inference_lines * ++ IMX500_INFERENCE_LINE_WIDTH; ++ fse->max_width = fse->min_width; ++ fse->min_height = 1; ++ fse->max_height = fse->min_height; ++ } + + return 0; + } +@@ -920,6 +1699,17 @@ static void imx500_update_image_pad_form + V4L2_MAP_XFER_FUNC_DEFAULT(fmt->format.colorspace); + } + ++static void imx500_update_metadata_pad_format(const struct imx500 *imx500, ++ struct v4l2_subdev_format *fmt) ++{ ++ fmt->format.width = ++ IMX500_MAX_EMBEDDED_SIZE + ++ imx500->num_inference_lines * IMX500_INFERENCE_LINE_WIDTH; ++ fmt->format.height = 1; ++ fmt->format.code = MEDIA_BUS_FMT_SENSOR_DATA; ++ fmt->format.field = V4L2_FIELD_NONE; ++} ++ + static int imx500_get_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +@@ -935,11 +1725,18 @@ static int imx500_get_pad_format(struct + struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_get_try_format( + &imx500->sd, sd_state, fmt->pad); + /* update the code which could change due to vflip or hflip */ +- try_fmt->code = imx500_get_format_code(imx500); ++ try_fmt->code = fmt->pad == IMAGE_PAD ? ++ imx500_get_format_code(imx500) : ++ MEDIA_BUS_FMT_SENSOR_DATA; + fmt->format = *try_fmt; + } else { +- imx500_update_image_pad_format(imx500, imx500->mode, fmt); +- fmt->format.code = imx500_get_format_code(imx500); ++ if (fmt->pad == IMAGE_PAD) { ++ imx500_update_image_pad_format(imx500, imx500->mode, ++ fmt); ++ fmt->format.code = imx500_get_format_code(imx500); ++ } else { ++ imx500_update_metadata_pad_format(imx500, fmt); ++ } + } + + mutex_unlock(&imx500->mutex); +@@ -1000,22 +1797,35 @@ static int imx500_set_pad_format(struct + + mutex_lock(&imx500->mutex); + +- const struct imx500_mode *mode_list = imx500_supported_modes; +- unsigned int num_modes = ARRAY_SIZE(imx500_supported_modes); ++ if (fmt->pad == IMAGE_PAD) { ++ const struct imx500_mode *mode_list = imx500_supported_modes; ++ unsigned int num_modes = ARRAY_SIZE(imx500_supported_modes); + +- /* Bayer order varies with flips */ +- fmt->format.code = imx500_get_format_code(imx500); ++ /* Bayer order varies with flips */ ++ fmt->format.code = imx500_get_format_code(imx500); + +- mode = v4l2_find_nearest_size(mode_list, num_modes, width, height, +- fmt->format.width, fmt->format.height); +- imx500_update_image_pad_format(imx500, mode, fmt); +- if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { +- framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); +- *framefmt = fmt->format; +- } else if (imx500->mode != mode) { +- imx500->mode = mode; +- imx500->fmt_code = fmt->format.code; +- imx500_set_framing_limits(imx500); ++ mode = v4l2_find_nearest_size(mode_list, num_modes, width, ++ height, fmt->format.width, ++ fmt->format.height); ++ imx500_update_image_pad_format(imx500, mode, fmt); ++ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { ++ framefmt = v4l2_subdev_get_try_format(sd, sd_state, ++ fmt->pad); ++ *framefmt = fmt->format; ++ } else if (imx500->mode != mode) { ++ imx500->mode = mode; ++ imx500->fmt_code = fmt->format.code; ++ imx500_set_framing_limits(imx500); ++ } ++ } else { ++ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { ++ framefmt = v4l2_subdev_get_try_format(sd, sd_state, ++ fmt->pad); ++ *framefmt = fmt->format; ++ } else { ++ /* Only one embedded data mode is supported */ ++ imx500_update_metadata_pad_format(imx500, fmt); ++ } + } + + mutex_unlock(&imx500->mutex); +@@ -1074,6 +1884,243 @@ static int imx500_get_selection(struct v + return -EINVAL; + } + ++static int __must_check imx500_spi_write(struct imx500 *state, const u8 *data, ++ size_t size) ++{ ++ if (size % 4 || size > ONE_MIB) ++ return -EINVAL; ++ ++ if (!state->spi_device) ++ return -ENODEV; ++ ++ return spi_write(state->spi_device, data, size); ++} ++ ++/* Moves the IMX500 internal state machine between states or updates. ++ * ++ * Prerequisites: Sensor is powered on and not currently streaming ++ */ ++static int imx500_state_transition(struct imx500 *imx500, const u8 *fw, ++ size_t fw_size, enum imx500_image_type type, ++ bool update) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&imx500->sd); ++ struct cci_reg_sequence cmd_reply_sts_cnt_reg; ++ size_t valid_size; ++ int ret; ++ u64 tmp; ++ ++ if (!imx500 || !fw || type >= TYPE_MAX) ++ return -EINVAL; ++ ++ if (!update && (int)type != (int)imx500->fsm_state) ++ return -EINVAL; ++ ++ /* Validate firmware */ ++ valid_size = imx500_valid_fw_bytes(fw, fw_size); ++ if (!valid_size) ++ return -EINVAL; ++ ++ ret = imx500_prepare_poll_cmd_reply_sts(imx500, &cmd_reply_sts_cnt_reg); ++ if (ret) ++ return ret; ++ ++ struct cci_reg_sequence common_regs[] = { ++ { IMX500_REG_DD_FLASH_TYPE, 0x02 }, ++ { IMX500_REG_DD_LOAD_MODE, IMX500_DD_LOAD_MODE_AP }, ++ { IMX500_REG_DD_IMAGE_TYPE, type }, ++ { IMX500_REG_DD_DOWNLOAD_DIV_NUM, (valid_size - 1) / ONE_MIB }, ++ { IMX500_REG_DD_DOWNLOAD_FILE_SIZE, valid_size }, ++ }; ++ ++ struct cci_reg_sequence state_transition_regs[] = { ++ { IMX500_REG_DD_ST_TRANS_CMD, type }, ++ { IMX500_REG_DD_CMD_INT, IMX500_DD_CMD_INT_ST_TRANS }, ++ }; ++ ++ struct cci_reg_sequence update_regs[] = { ++ { IMX500_REG_DD_UPDATE_CMD, IMX500_DD_UPDATE_CMD_SRAM }, ++ { IMX500_REG_DD_CMD_INT, IMX500_DD_CMD_INT_UPDATE }, ++ }; ++ ++ ret = cci_multi_reg_write(imx500->regmap, common_regs, ++ ARRAY_SIZE(common_regs), NULL); ++ ++ cci_multi_reg_write(imx500->regmap, ++ update ? update_regs : state_transition_regs, 2, ++ &ret); ++ if (ret) ++ return ret; ++ ++ /* Poll CMD_REPLY_STS_CNT until a response is available */ ++ ret = imx500_poll_status_reg(imx500, &cmd_reply_sts_cnt_reg, 5); ++ if (ret) { ++ dev_err(&client->dev, "DD_REF_STS register did not update\n"); ++ return ret; ++ } ++ ++ /* Read response to state transition / update request */ ++ ret = cci_read(imx500->regmap, IMX500_REG_DD_CMD_REPLY_STS, &tmp, NULL); ++ if (ret || tmp != (update ? IMX500_DD_CMD_REPLY_STS_UPDATE_READY : ++ IMX500_DD_CMD_REPLY_STS_TRANS_READY)) ++ return ret ? ret : -EBUSY; ++ ++ imx500->fw_stage = type; ++ imx500->fw_progress = 0; ++ ++ for (size_t i = 0; i <= valid_size / ONE_MIB; i++) { ++ const u8 *data = fw + (i * ONE_MIB); ++ size_t size = valid_size - (i * ONE_MIB); ++ struct cci_reg_sequence download_sts_reg = { ++ IMX500_REG_DD_DOWNLOAD_STS, ++ IMX500_DD_DOWNLOAD_STS_DOWNLOADING, ++ }; ++ ++ /* Calculate SPI xfer size avoiding 0-sized TXNs */ ++ size = min_t(size_t, size, ONE_MIB); ++ if (!size) ++ break; ++ ++ /* Poll until device is ready for download */ ++ ret = imx500_poll_status_reg(imx500, &download_sts_reg, 100); ++ if (ret) { ++ dev_err(&client->dev, ++ "DD_DOWNLOAD_STS was never ready\n"); ++ return ret; ++ } ++ ++ /* Do SPI transfer */ ++ ret = imx500_spi_write(imx500, data, size); ++ imx500->fw_progress += size; ++ ++ if (ret < 0) ++ return ret; ++ } ++ ++ /* Poll until another response is available */ ++ ret = imx500_poll_status_reg(imx500, &cmd_reply_sts_cnt_reg, 5); ++ if (ret) { ++ dev_err(&client->dev, ++ "DD_REF_STS register did not update after SPI write(s)\n"); ++ return ret; ++ } ++ ++ /* Verify that state transition / update completed successfully */ ++ ret = cci_read(imx500->regmap, IMX500_REG_DD_CMD_REPLY_STS, &tmp, NULL); ++ if (ret || tmp != (update ? IMX500_DD_CMD_REPLY_STS_UPDATE_DONE : ++ IMX500_DD_CMD_REPLY_STS_TRANS_DONE)) ++ return ret ? ret : -EREMOTEIO; ++ ++ if (!update && imx500->fsm_state < IMX500_STATE_WITH_NETWORK) ++ imx500->fsm_state++; ++ ++ imx500->fw_progress = fw_size; ++ ++ return 0; ++} ++ ++static int imx500_transition_to_standby_wo_network(struct imx500 *imx500) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&imx500->sd); ++ const struct firmware *firmware; ++ u64 fw_ver; ++ int ret; ++ ++ firmware = imx500->fw_loader; ++ ret = imx500_state_transition(imx500, firmware->data, firmware->size, ++ TYPE_LOADER, false); ++ if (ret) { ++ dev_err(&client->dev, "%s: failed to load loader firmware\n", ++ __func__); ++ return ret; ++ } ++ ++ firmware = imx500->fw_main; ++ ret = imx500_state_transition(imx500, firmware->data, firmware->size, ++ TYPE_MAIN, false); ++ if (ret) { ++ dev_err(&client->dev, "%s: failed to load main firmware\n", ++ __func__); ++ return ret; ++ } ++ ++ ret = cci_read(imx500->regmap, IMX500_REG_MAIN_FW_VERSION, &fw_ver, ++ NULL); ++ if (ret) { ++ dev_err(&client->dev, ++ "%s: could not read main firmware version\n", __func__); ++ return ret; ++ } ++ ++ dev_info(&client->dev, ++ "main firmware version: %llu%llu.%llu%llu.%llu%llu\n", ++ (fw_ver >> 20) & 0xF, (fw_ver >> 16) & 0xF, ++ (fw_ver >> 12) & 0xF, (fw_ver >> 8) & 0xF, (fw_ver >> 4) & 0xF, ++ fw_ver & 0xF); ++ ++ ret = cci_multi_reg_write(imx500->regmap, metadata_output, ++ ARRAY_SIZE(metadata_output), NULL); ++ if (ret) { ++ dev_err(&client->dev, ++ "%s: failed to configure MIPI output for DNN\n", ++ __func__); ++ return ret; ++ } ++ ++ ret = cci_multi_reg_write(imx500->regmap, dnn_regs, ++ ARRAY_SIZE(dnn_regs), NULL); ++ if (ret) { ++ dev_err(&client->dev, "%s: unable to write DNN regs\n", ++ __func__); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int imx500_transition_to_network(struct imx500 *imx500) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&imx500->sd); ++ u64 imx500_fsm_state; ++ int ret; ++ ++ ret = imx500_iterate_nw_regs(imx500->fw_network, ++ imx500->fw_network_size, imx500, ++ imx500_reg_val_write_cbk); ++ if (ret) { ++ dev_err(&client->dev, ++ "%s: unable to apply register writes from firmware\n", ++ __func__); ++ return ret; ++ } ++ ++ /* Read IMX500 state to determine whether transition or update is required */ ++ ret = cci_read(imx500->regmap, IMX500_REG_DD_SYS_STATE, ++ &imx500_fsm_state, NULL); ++ if (ret || imx500_fsm_state & 1) ++ return ret ? ret : -EREMOTEIO; ++ ++ ret = imx500_state_transition( ++ imx500, imx500->fw_network, imx500->fw_network_size, ++ TYPE_NW_WEIGHTS, ++ imx500_fsm_state == IMX500_DD_SYS_STATE_STANDBY_WITH_NETWORK); ++ if (ret) { ++ dev_err(&client->dev, "%s: failed to load network weights\n", ++ __func__); ++ return ret; ++ } ++ ++ /* Select network 0 */ ++ ret = cci_write(imx500->regmap, CCI_REG8(0xD701), 0, NULL); ++ if (ret) { ++ dev_err(&client->dev, "%s: failed to select network 0\n", ++ __func__); ++ return ret; ++ } ++ ++ return ret; ++} ++ + /* Start streaming */ + static int imx500_start_streaming(struct imx500 *imx500) + { +@@ -1086,7 +2133,8 @@ static int imx500_start_streaming(struct + return ret; + + ret = cci_write(imx500->regmap, IMX500_REG_IMAGE_ONLY_MODE, +- IMX500_IMAGE_ONLY_TRUE, ++ imx500->fw_network ? IMX500_IMAGE_ONLY_FALSE : ++ IMX500_IMAGE_ONLY_TRUE, + NULL); + if (ret) { + dev_err(&client->dev, "%s failed to set image mode\n", +@@ -1094,6 +2142,30 @@ static int imx500_start_streaming(struct + return ret; + } + ++ /* Acquire loader and main firmware if needed */ ++ if (imx500->fw_network) { ++ if (!imx500->fw_loader) { ++ ret = request_firmware(&imx500->fw_loader, ++ "imx500_loader.fpk", ++ &client->dev); ++ if (ret) { ++ dev_err(&client->dev, ++ "Unable to acquire firmware loader\n"); ++ return ret; ++ } ++ } ++ if (!imx500->fw_main) { ++ ret = request_firmware(&imx500->fw_main, ++ "imx500_firmware.fpk", ++ &client->dev); ++ if (ret) { ++ dev_err(&client->dev, ++ "Unable to acquire main firmware\n"); ++ return ret; ++ } ++ } ++ } ++ + if (!imx500->common_regs_written) { + ret = cci_multi_reg_write(imx500->regmap, mode_common_regs, + ARRAY_SIZE(mode_common_regs), NULL); +@@ -1107,6 +2179,38 @@ static int imx500_start_streaming(struct + imx500->common_regs_written = true; + } + ++ if (imx500->fw_network && !imx500->loader_and_main_written) { ++ ret = imx500_transition_to_standby_wo_network(imx500); ++ if (ret) { ++ dev_err(&client->dev, ++ "%s failed to transition from program empty state\n", ++ __func__); ++ return ret; ++ } ++ imx500->loader_and_main_written = true; ++ } ++ ++ if (imx500->fw_network && !imx500->network_written) { ++ ret = imx500_transition_to_network(imx500); ++ if (ret) { ++ dev_err(&client->dev, ++ "%s failed to transition to network loaded\n", ++ __func__); ++ return ret; ++ } ++ imx500->network_written = true; ++ } ++ ++ /* Enable DNN */ ++ if (imx500->fw_network) { ++ ret = cci_write(imx500->regmap, CCI_REG8(0xD100), 4, NULL); ++ if (ret) { ++ dev_err(&client->dev, "%s failed to enable DNN\n", ++ __func__); ++ return ret; ++ } ++ } ++ + /* Apply default values of current mode */ + reg_list = &imx500->mode->reg_list; + ret = cci_multi_reg_write(imx500->regmap, reg_list->regs, +@@ -1141,6 +2245,11 @@ static void imx500_stop_streaming(struct + if (ret) + dev_err(&client->dev, "%s failed to set stream\n", __func__); + ++ /* Disable DNN */ ++ ret = cci_write(imx500->regmap, CCI_REG8(0xD100), 0, NULL); ++ if (ret) ++ dev_err(&client->dev, "%s failed to disable DNN\n", __func__); ++ + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); + } +@@ -1173,6 +2282,7 @@ static int imx500_set_stream(struct v4l2 + /* vflip and hflip cannot change during streaming */ + __v4l2_ctrl_grab(imx500->vflip, enable); + __v4l2_ctrl_grab(imx500->hflip, enable); ++ __v4l2_ctrl_grab(imx500->network_fw_ctrl, enable); + + mutex_unlock(&imx500->mutex); + +@@ -1247,7 +2357,10 @@ static int imx500_power_off(struct devic + regulator_bulk_disable(IMX500_NUM_SUPPLIES, imx500->supplies); + + /* Force reprogramming of the common registers when powered up again. */ ++ imx500->fsm_state = IMX500_STATE_RESET; + imx500->common_regs_written = false; ++ imx500->loader_and_main_written = false; ++ imx500_clear_fw_network(imx500); + + return 0; + } +@@ -1317,6 +2430,36 @@ static const s64 imx500_link_freq_menu[] + IMX500_DEFAULT_LINK_FREQ, + }; + ++/* Custom control for inference window */ ++static const struct v4l2_ctrl_config inf_window_ctrl = { ++ .name = "IMX500 Inference Windows", ++ .id = V4L2_CID_USER_IMX500_INFERENCE_WINDOW, ++ .dims[0] = 4, ++ .ops = &imx500_ctrl_ops, ++ .type = V4L2_CTRL_TYPE_U32, ++ .elem_size = sizeof(u32), ++ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE | ++ V4L2_CTRL_FLAG_HAS_PAYLOAD, ++ .def = 0, ++ .min = 0x00, ++ .max = 4032, ++ .step = 1, ++}; ++ ++/* Custom control for network firmware file FD */ ++static const struct v4l2_ctrl_config network_fw_fd = { ++ .name = "IMX500 Network Firmware File FD", ++ .id = V4L2_CID_USER_IMX500_NETWORK_FW_FD, ++ .ops = &imx500_ctrl_ops, ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE | ++ V4L2_CTRL_FLAG_WRITE_ONLY, ++ .min = -1, ++ .max = S32_MAX, ++ .step = 1, ++ .def = -1, ++}; ++ + /* Initialize control handlers */ + static int imx500_init_controls(struct imx500 *imx500) + { +@@ -1376,6 +2519,9 @@ static int imx500_init_controls(struct i + imx500->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + + v4l2_ctrl_new_custom(ctrl_hdlr, &imx500_notify_gains_ctrl, NULL); ++ v4l2_ctrl_new_custom(ctrl_hdlr, &inf_window_ctrl, NULL); ++ imx500->network_fw_ctrl = ++ v4l2_ctrl_new_custom(ctrl_hdlr, &network_fw_fd, NULL); + + if (ctrl_hdlr->error) { + ret = ctrl_hdlr->error; +@@ -1459,12 +2605,35 @@ error_out: + return ret; + } + ++static int fw_progress_show(struct seq_file *s, void *data) ++{ ++ struct imx500 *imx500 = s->private; ++ ++ seq_printf(s, "%d %zu %zu\n", imx500->fw_stage, imx500->fw_progress, ++ imx500->fw_network_size); ++ return 0; ++} ++DEFINE_SHOW_ATTRIBUTE(fw_progress); ++ + static int imx500_probe(struct i2c_client *client) + { + struct device *dev = &client->dev; ++ struct spi_device *spi = NULL; ++ char debugfs_name[128]; + struct imx500 *imx500; + int ret; + ++ struct device_node *spi_node = of_parse_phandle(dev->of_node, "spi", 0); ++ ++ if (spi_node) { ++ struct device *tmp = ++ bus_find_device_by_of_node(&spi_bus_type, spi_node); ++ of_node_put(spi_node); ++ spi = tmp ? to_spi_device(tmp) : NULL; ++ if (!spi) ++ return -EPROBE_DEFER; ++ } ++ + imx500 = devm_kzalloc(&client->dev, sizeof(*imx500), GFP_KERNEL); + if (!imx500) + return -ENOMEM; +@@ -1474,6 +2643,8 @@ static int imx500_probe(struct i2c_clien + return dev_err_probe(dev, PTR_ERR(imx500->regmap), + "failed to initialise CCI\n"); + ++ imx500->spi_device = spi; ++ + v4l2_i2c_subdev_init(&imx500->sd, client, &imx500_subdev_ops); + + /* Check the hardware configuration in device tree */ +@@ -1534,10 +2705,10 @@ static int imx500_probe(struct i2c_clien + imx500->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + /* Initialize source pads */ +- imx500->pad.flags = MEDIA_PAD_FL_SOURCE; ++ imx500->pad[IMAGE_PAD].flags = MEDIA_PAD_FL_SOURCE; ++ imx500->pad[METADATA_PAD].flags = MEDIA_PAD_FL_SOURCE; + +- ret = media_entity_pads_init(&imx500->sd.entity, NUM_PADS, +- &imx500->pad); ++ ret = media_entity_pads_init(&imx500->sd.entity, NUM_PADS, imx500->pad); + if (ret) { + dev_err(dev, "failed to init entity pads: %d\n", ret); + goto error_handler_free; +@@ -1549,6 +2720,12 @@ static int imx500_probe(struct i2c_clien + goto error_media_entity; + } + ++ snprintf(debugfs_name, sizeof(debugfs_name), "imx500-fw:%s", ++ dev_name(dev)); ++ imx500->debugfs = debugfs_create_dir(debugfs_name, NULL); ++ debugfs_create_file("fw_progress", 0444, imx500->debugfs, imx500, ++ &fw_progress_fops); ++ + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); + +@@ -1573,10 +2750,23 @@ static void imx500_remove(struct i2c_cli + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx500 *imx500 = to_imx500(sd); + ++ if (imx500->spi_device) ++ put_device(&imx500->spi_device->dev); ++ + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + imx500_free_controls(imx500); + ++ if (imx500->fw_loader) ++ release_firmware(imx500->fw_loader); ++ ++ if (imx500->fw_main) ++ release_firmware(imx500->fw_main); ++ ++ imx500->fw_loader = NULL; ++ imx500->fw_main = NULL; ++ imx500_clear_fw_network(imx500); ++ + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + imx500_power_off(&client->dev); +@@ -1603,7 +2793,63 @@ static struct i2c_driver imx500_i2c_driv + .remove = imx500_remove, + }; + +-module_i2c_driver(imx500_i2c_driver); ++static int imx500_spi_probe(struct spi_device *spi) ++{ ++ int result; ++ ++ spi->bits_per_word = 8; ++ spi->max_speed_hz = 35000000; ++ spi->mode = SPI_MODE_3; ++ ++ result = spi_setup(spi); ++ if (result < 0) ++ return dev_err_probe(&spi->dev, result, "spi_setup() failed"); ++ ++ return 0; ++} ++ ++static void imx500_spi_remove(struct spi_device *spi) ++{ ++} ++ ++static const struct spi_device_id imx500_spi_id[] = { ++ { "imx500", 0 }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(spi, imx500_spi_id); ++ ++static struct spi_driver imx500_spi_driver = { ++ .driver = { ++ .name = "imx500", ++ .of_match_table = imx500_dt_ids, ++ }, ++ .probe = imx500_spi_probe, ++ .remove = imx500_spi_remove, ++ .id_table = imx500_spi_id, ++}; ++ ++static int __init imx500_driver_init(void) ++{ ++ int ret; ++ ++ ret = spi_register_driver(&imx500_spi_driver); ++ if (ret) ++ return ret; ++ ++ ret = i2c_add_driver(&imx500_i2c_driver); ++ if (ret) ++ spi_unregister_driver(&imx500_spi_driver); ++ ++ return ret; ++} ++module_init(imx500_driver_init); ++ ++static void __exit imx500_driver_exit(void) ++{ ++ i2c_del_driver(&imx500_i2c_driver); ++ spi_unregister_driver(&imx500_spi_driver); ++} ++module_exit(imx500_driver_exit); + + MODULE_AUTHOR("Naushir Patuck "); + MODULE_DESCRIPTION("Sony IMX500 sensor driver"); +--- a/include/uapi/linux/v4l2-controls.h ++++ b/include/uapi/linux/v4l2-controls.h +@@ -207,6 +207,12 @@ enum v4l2_colorfx { + * We reserve 16 controls for this driver. */ + #define V4L2_CID_USER_BCM2835_ISP_BASE (V4L2_CID_USER_BASE + 0x10e0) + ++/* ++ * The base for IMX500 driver controls. ++ * We reserve 16 controls for this driver. ++ */ ++#define V4L2_CID_USER_IMX500_BASE (V4L2_CID_USER_BASE + 0x2000) ++ + /* MPEG-class control IDs */ + /* The MPEG controls are applicable to all codec controls + * and the 'MPEG' part of the define is historical */ diff --git a/target/linux/bcm27xx/patches-6.6/950-1247-dts-bcm-283x-2712-clocks-as-simple-bus.patch b/target/linux/bcm27xx/patches-6.6/950-1247-dts-bcm-283x-2712-clocks-as-simple-bus.patch new file mode 100644 index 000000000000..ec77dd17c18b --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1247-dts-bcm-283x-2712-clocks-as-simple-bus.patch @@ -0,0 +1,41 @@ +From 15cc525406cf311399d182ffcc18711651b7c8b2 Mon Sep 17 00:00:00 2001 +From: Richard Oliver +Date: Fri, 12 Jul 2024 13:32:30 +0100 +Subject: [PATCH 1247/1350] dts: bcm{283x,2712}: /clocks as "simple-bus" + +Make /clocks node compatible with "simple-bus" to ensure that all children +(not just those that are "fixed-clock" compatible) are automatically +probed. + +Signed-off-by: Richard Oliver +--- + arch/arm/boot/dts/broadcom/bcm283x.dtsi | 4 ++++ + arch/arm64/boot/dts/broadcom/bcm2712.dtsi | 4 ++++ + 2 files changed, 8 insertions(+) + +--- a/arch/arm/boot/dts/broadcom/bcm283x.dtsi ++++ b/arch/arm/boot/dts/broadcom/bcm283x.dtsi +@@ -478,6 +478,10 @@ + }; + + clocks { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ + /* The oscillator is the root of the clock tree. */ + clk_osc: clk-osc { + compatible = "fixed-clock"; +--- a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi ++++ b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi +@@ -1258,6 +1258,10 @@ + }; + + clocks { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ + /* The oscillator is the root of the clock tree. */ + clk_osc: clk-osc { + compatible = "fixed-clock"; diff --git a/target/linux/bcm27xx/patches-6.6/950-1248-dts-Add-AI-Camera-support.patch b/target/linux/bcm27xx/patches-6.6/950-1248-dts-Add-AI-Camera-support.patch new file mode 100644 index 000000000000..4a451480b039 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1248-dts-Add-AI-Camera-support.patch @@ -0,0 +1,389 @@ +From 4113b1097fe40ff3a64ee7a9ade7c258e9ecdb5b Mon Sep 17 00:00:00 2001 +From: Richard Oliver +Date: Mon, 3 Jun 2024 14:10:27 +0100 +Subject: [PATCH 1248/1350] dts: Add 'AI Camera' support + +The AI Camera combines an IMX500 and a RP2040 GPIO bridge on a single +module. The Raspberry Pi camera regulator is used for both IMX500 and +RP2040. SPI, clocks, and reset (required by IMX500) are provided by the +RP2040 GPIO bridge. + +Signed-off-by: Richard Oliver +--- + arch/arm/boot/dts/overlays/Makefile | 2 + + arch/arm/boot/dts/overlays/README | 21 +++ + arch/arm/boot/dts/overlays/imx500-overlay.dts | 119 +++++++++++++++++ + .../boot/dts/overlays/imx500-pi5-overlay.dts | 124 ++++++++++++++++++ + arch/arm/boot/dts/overlays/imx500.dtsi | 28 ++++ + arch/arm/boot/dts/overlays/overlay_map.dts | 10 ++ + .../dts/overlays/rpi-rp2040-gpio-bridge.dtsi | 21 +++ + 7 files changed, 325 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/imx500-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/imx500-pi5-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/imx500.dtsi + create mode 100644 arch/arm/boot/dts/overlays/rpi-rp2040-gpio-bridge.dtsi + +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -136,6 +136,8 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + imx378.dtbo \ + imx462.dtbo \ + imx477.dtbo \ ++ imx500.dtbo \ ++ imx500-pi5.dtbo \ + imx519.dtbo \ + imx708.dtbo \ + interludeaudio-analog.dtbo \ +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -2818,6 +2818,27 @@ Params: rotation Mounting + sync-sink Configure as vsync sink + + ++Name: imx500 ++Info: Sony IMX500 camera module. ++ Uses Unicam 1, which is the standard camera connector on most Pi ++ variants. ++Load: dtoverlay=imx500,= ++Params: rotation Mounting rotation of the camera sensor (0 or ++ 180, default 0) ++ orientation Sensor orientation (0 = front, 1 = rear, ++ 2 = external, default external) ++ media-controller Configure use of Media Controller API for ++ configuring the sensor (default on) ++ cam0 Adopt the default configuration for CAM0 on a ++ Compute Module (CSI0, i2c_vc, and cam0_reg). ++ bypass-cache Do save blocks of data to flash when using ++ rp2040-gpio-bridge for SPI transfers. ++ ++ ++Name: imx500-pi5 ++Info: See imx500 (this is the Pi 5 version) ++ ++ + Name: imx519 + Info: Sony IMX519 camera module. + Uses Unicam 1, which is the standard camera connector on most Pi +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/imx500-overlay.dts +@@ -0,0 +1,119 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++// Definitions for IMX500 camera module on VC I2C bus ++/dts-v1/; ++/plugin/; ++ ++#include ++ ++/{ ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&i2c0if>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&i2c0mux>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ reg_frag: fragment@2 { ++ target = <&cam1_reg>; ++ cam_reg: __overlay__ { ++ startup-delay-us = <300000>; ++ }; ++ }; ++ ++ i2c_frag: fragment@100 { ++ target = <&i2c_csi_dsi>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ #include "imx500.dtsi" ++ #include "rpi-rp2040-gpio-bridge.dtsi" ++ }; ++ }; ++ ++ csi_frag: fragment@101 { ++ target = <&csi1>; ++ csi: __overlay__ { ++ status = "okay"; ++ brcm,media-controller; ++ ++ port { ++ csi_ep: endpoint { ++ remote-endpoint = <&cam_endpoint>; ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ clock-noncontinuous; ++ }; ++ }; ++ }; ++ }; ++ ++ spi_frag: fragment@102 { ++ target = <&spi_bridgedev0>; ++ __overlay__ { ++ compatible = "sony,imx500"; ++ }; ++ }; ++ ++ chosen_frag: fragment@103 { ++ target = <&chosen>; ++ __overlay__ { ++ core_freq_fixed; ++ }; ++ }; ++ ++ clocks_frag: fragment@104 { ++ target-path = "/clocks"; ++ __overlay__ { ++ clk_aicam: clk-aicam { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <24000000>; ++ }; ++ ++ clk_aicam_gated: clk-aicam-gated { ++ compatible = "gpio-gate-clock"; ++ clocks = <&clk_aicam>; ++ #clock-cells = <0>; ++ enable-gpios = <&spi_bridge 21 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ rotation = <&cam_node>,"rotation:0"; ++ orientation = <&cam_node>,"orientation:0"; ++ media-controller = <&csi>,"brcm,media-controller?"; ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, ++ <&csi_frag>, "target:0=",<&csi0>, ++ <&spi_bridge>, "power-supply:0=",<&cam0_reg>, ++ <®_frag>, "target:0=",<&cam0_reg>, ++ <&cam_node>, "VANA-supply:0=",<&cam0_reg>; ++ bypass-cache = <&spi_bridge>,"bypass-cache?"; ++ }; ++}; ++ ++&cam_node { ++ status = "okay"; ++ reset-gpios = <&spi_bridge 20 GPIO_ACTIVE_HIGH>; ++ clocks = <&clk_aicam_gated>; ++ spi = <&spi_bridgedev0>; ++}; ++ ++&spi_bridge { ++ status = "okay"; ++}; ++ ++&cam_endpoint { ++ remote-endpoint = <&csi_ep>; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/imx500-pi5-overlay.dts +@@ -0,0 +1,124 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++// Definitions for IMX500 camera module on VC I2C bus ++/dts-v1/; ++/plugin/; ++ ++#include ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&i2c0if>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&i2c0mux>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ reg_frag: fragment@2 { ++ target = <&cam1_reg>; ++ cam_reg: __overlay__ { ++ startup-delay-us = <300000>; ++ }; ++ }; ++ ++ i2c_frag: fragment@100 { ++ target = <&i2c_csi_dsi>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ #include "imx500.dtsi" ++ #include "rpi-rp2040-gpio-bridge.dtsi" ++ }; ++ }; ++ ++ csi_frag: fragment@101 { ++ target = <&csi1>; ++ csi: __overlay__ { ++ status = "okay"; ++ brcm,media-controller; ++ ++ port { ++ csi_ep: endpoint { ++ remote-endpoint = <&cam_endpoint>; ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ clock-noncontinuous; ++ }; ++ }; ++ }; ++ }; ++ ++ spi_frag: fragment@102 { ++ target = <&spi_bridge>; ++ spi_frag_overlay: __overlay__ { ++ fast_xfer_requires_i2c_lock = <1>; ++ fast_xfer_recv_gpio_base = <11>; ++ fast_xfer-gpios = <&rp1_gpio 40 0>, // CD1_SDA (used as data) ++ <&rp1_gpio 48 0>; // CD1_IO1_MICDAT1 (clock) ++ }; ++ }; ++ ++ spi_bridge_frag: fragment@103 { ++ target = <&spi_bridgedev0>; ++ __overlay__ { ++ compatible = "sony,imx500"; ++ }; ++ }; ++ ++ clocks_frag: fragment@104 { ++ target-path = "/clocks"; ++ __overlay__ { ++ clk_aicam: clk-aicam { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <24000000>; ++ }; ++ ++ clk_aicam_gated: clk-aicam-gated { ++ compatible = "gpio-gate-clock"; ++ clocks = <&clk_aicam>; ++ #clock-cells = <0>; ++ enable-gpios = <&spi_bridge 21 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ rotation = <&cam_node>,"rotation:0"; ++ orientation = <&cam_node>,"orientation:0"; ++ media-controller = <&csi>,"brcm,media-controller?"; ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, ++ <&csi_frag>, "target:0=",<&csi0>, ++ <&spi_frag_overlay>, "fast_xfer-gpios:4=38", // CD0_SDA (data) ++ <&spi_frag_overlay>, "fast_xfer-gpios:16=35", // CD0_IO1_MICDAT0 (clock) ++ <&spi_bridge>, "power-supply:0=",<&cam0_reg>, ++ <®_frag>, "target:0=",<&cam0_reg>, ++ <&cam_node>, "VANA-supply:0=",<&cam0_reg>; ++ bypass-cache = <&spi_bridge>,"bypass-cache?"; ++ }; ++}; ++ ++&cam_node { ++ status = "okay"; ++ reset-gpios = <&spi_bridge 20 GPIO_ACTIVE_HIGH>; ++ clocks = <&clk_aicam_gated>; ++ spi = <&spi_bridgedev0>; ++}; ++ ++&spi_bridge { ++ status = "okay"; ++}; ++ ++&cam_endpoint { ++ remote-endpoint = <&csi_ep>; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/imx500.dtsi +@@ -0,0 +1,28 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++cam_node: imx500@1a { ++ reg = <0x1a>; ++ compatible = "sony,imx500"; ++ status = "disabled"; ++ ++ clocks = <&cam1_clk>; ++ clock-names = "inck"; ++ ++ vana-supply = <&cam1_reg>; /* 2.7v */ ++ vdig-supply = <&cam_dummy_reg>; /* 0.84v */ ++ vif-supply = <&cam_dummy_reg>; /* 1.8v */ ++ ++ reset-gpios = <&gpio 255 GPIO_ACTIVE_HIGH>; ++ ++ rotation = <0>; ++ orientation = <2>; ++ ++ port { ++ cam_endpoint: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ clock-noncontinuous; ++ link-frequencies = ++ /bits/ 64 <444000000>; ++ }; ++ }; ++}; +--- a/arch/arm/boot/dts/overlays/overlay_map.dts ++++ b/arch/arm/boot/dts/overlays/overlay_map.dts +@@ -118,6 +118,16 @@ + bcm2711; + }; + ++ imx500 { ++ bcm2835; ++ bcm2711; ++ bcm2712 = "imx500-pi5"; ++ }; ++ ++ imx500-pi5 { ++ bcm2712; ++ }; ++ + lirc-rpi { + deprecated = "use gpio-ir"; + }; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/rpi-rp2040-gpio-bridge.dtsi +@@ -0,0 +1,21 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++spi_bridge: spi@40 { ++ reg = <0x40>; ++ compatible = "raspberrypi,rp2040-gpio-bridge"; ++ status = "disabled"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ power-supply = <&cam1_reg>; ++ ++ #gpio-cells = <2>; ++ gpio-controller; ++ ++ spi_bridgedev0: spidev@0{ ++ compatible = "spidev"; ++ reg = <0>; /* CE0 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <35000000>; ++ }; ++}; diff --git a/target/linux/bcm27xx/patches-6.6/950-1250-media-i2c-imx500-Enable-LED-during-SPI-transfers.patch b/target/linux/bcm27xx/patches-6.6/950-1250-media-i2c-imx500-Enable-LED-during-SPI-transfers.patch new file mode 100644 index 000000000000..cd7da629c09b --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1250-media-i2c-imx500-Enable-LED-during-SPI-transfers.patch @@ -0,0 +1,66 @@ +From 62faabb61ae152e8289a00ffb3445f4c47777b33 Mon Sep 17 00:00:00 2001 +From: Richard Oliver +Date: Mon, 3 Jun 2024 16:02:41 +0100 +Subject: [PATCH 1250/1350] media: i2c: imx500: Enable LED during SPI transfers + +The Raspberry Pi 'AI Camera' is equipped with an LED. Enable this LED +during SPI transfers to indicate to the end-user that progress is being +made during large tramsfers. + +Signed-off-by: Richard Oliver +--- + arch/arm/boot/dts/overlays/imx500-overlay.dts | 1 + + arch/arm/boot/dts/overlays/imx500-pi5-overlay.dts | 1 + + drivers/media/i2c/imx500.c | 6 ++++++ + 3 files changed, 8 insertions(+) + +--- a/arch/arm/boot/dts/overlays/imx500-overlay.dts ++++ b/arch/arm/boot/dts/overlays/imx500-overlay.dts +@@ -105,6 +105,7 @@ + + &cam_node { + status = "okay"; ++ led-gpios = <&spi_bridge 19 GPIO_ACTIVE_HIGH>; + reset-gpios = <&spi_bridge 20 GPIO_ACTIVE_HIGH>; + clocks = <&clk_aicam_gated>; + spi = <&spi_bridgedev0>; +--- a/arch/arm/boot/dts/overlays/imx500-pi5-overlay.dts ++++ b/arch/arm/boot/dts/overlays/imx500-pi5-overlay.dts +@@ -110,6 +110,7 @@ + + &cam_node { + status = "okay"; ++ led-gpios = <&spi_bridge 19 GPIO_ACTIVE_HIGH>; + reset-gpios = <&spi_bridge 20 GPIO_ACTIVE_HIGH>; + clocks = <&clk_aicam_gated>; + spi = <&spi_bridgedev0>; +--- a/drivers/media/i2c/imx500.c ++++ b/drivers/media/i2c/imx500.c +@@ -965,6 +965,7 @@ struct imx500 { + struct clk *xclk; + u32 xclk_freq; + ++ struct gpio_desc *led_gpio; + struct gpio_desc *reset_gpio; + struct regulator_bulk_data supplies[IMX500_NUM_SUPPLIES]; + +@@ -1990,7 +1991,10 @@ static int imx500_state_transition(struc + } + + /* Do SPI transfer */ ++ gpiod_set_value_cansleep(imx500->led_gpio, 1); + ret = imx500_spi_write(imx500, data, size); ++ gpiod_set_value_cansleep(imx500->led_gpio, 0); ++ + imx500->fw_progress += size; + + if (ret < 0) +@@ -2670,6 +2674,8 @@ static int imx500_probe(struct i2c_clien + return ret; + } + ++ imx500->led_gpio = devm_gpiod_get_optional(dev, "led", GPIOD_OUT_LOW); ++ + imx500->reset_gpio = + devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + diff --git a/target/linux/bcm27xx/patches-6.6/950-1251-spi-rp2040-gpio-bridge-add-missing-MD5-dependency.patch b/target/linux/bcm27xx/patches-6.6/950-1251-spi-rp2040-gpio-bridge-add-missing-MD5-dependency.patch new file mode 100644 index 000000000000..f6a27b815f64 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1251-spi-rp2040-gpio-bridge-add-missing-MD5-dependency.patch @@ -0,0 +1,24 @@ +From cc50cdbcf3e8f065bd7798a92689f54578b4169f Mon Sep 17 00:00:00 2001 +From: Richard Oliver +Date: Wed, 24 Jul 2024 15:48:22 +0100 +Subject: [PATCH 1251/1350] spi: rp2040-gpio-bridge: add missing MD5 dependency + +rp2040-gpio-bridge relies on the md5 crypto driver. This dependency +cannot be determined automatically as rp2040-gpio-bridge does not +use any of md5's symbols directly. + +Declare a soft 'pre' dependency on md5 to ensure that it is included and +loaded before rp2040-gpio-bridge. + +Signed-off-by: Richard Oliver +--- + drivers/spi/spi-rp2040-gpio-bridge.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/spi/spi-rp2040-gpio-bridge.c ++++ b/drivers/spi/spi-rp2040-gpio-bridge.c +@@ -1241,3 +1241,4 @@ module_i2c_driver(rp2040_gbdg_driver); + MODULE_AUTHOR("Richard Oliver "); + MODULE_DESCRIPTION("Raspberry Pi RP2040 GPIO Bridge"); + MODULE_LICENSE("GPL"); ++MODULE_SOFTDEP("pre: md5"); diff --git a/target/linux/bcm27xx/patches-6.6/950-1252-drivers-drm-rp1-vec-Increase-width-limit-for-PAL-16-.patch b/target/linux/bcm27xx/patches-6.6/950-1252-drivers-drm-rp1-vec-Increase-width-limit-for-PAL-16-.patch new file mode 100644 index 000000000000..d22b3c025db6 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1252-drivers-drm-rp1-vec-Increase-width-limit-for-PAL-16-.patch @@ -0,0 +1,50 @@ +From eab19e7bde679f56241db0c51f94f056fcffd6a9 Mon Sep 17 00:00:00 2001 +From: Nick Hollinghurst +Date: Wed, 4 Sep 2024 19:28:50 +0100 +Subject: [PATCH 1252/1350] drivers: drm: rp1-vec: Increase width limit, for + PAL 16:9 @ 18MHz + +There was no technical reason for the DRM mode's width limit of 848; +increase it to 960 (720*18MHz/13.5MHz) to support ~square pixels on +16:9 screens. Tweak the PAL active window to start slightly earlier. +(The maximum number of visible columns at 18MHz is about 942.) + +Signed-off-by: Nick Hollinghurst +--- + drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c | 4 ++-- + drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c ++++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c +@@ -508,8 +508,8 @@ static int rp1vec_platform_probe(struct + + vec->drm.mode_config.min_width = 256; + vec->drm.mode_config.min_height = 128; +- vec->drm.mode_config.max_width = 848; /* for System E */ +- vec->drm.mode_config.max_height = 738; /* for System E */ ++ vec->drm.mode_config.max_width = 960; /* for "widescreen" @ 18MHz */ ++ vec->drm.mode_config.max_height = 738; /* for System E only */ + vec->drm.mode_config.preferred_depth = 32; + vec->drm.mode_config.prefer_shadow = 0; + vec->drm.mode_config.quirk_addfb_prefer_host_byte_order = true; +--- a/drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c ++++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c +@@ -195,7 +195,7 @@ static const struct rp1vec_hwmode rp1vec + .misc = 0x00091c01, /* 5-tap FIR, SEQ_EN, 8 fld sync, PAL */ + .nco_freq = 0x0a8262b2cc48c1d1, + .timing_regs = { +- 0x046e0cee, 0x0d8001fb, 0x025c034f, 0x00fd0b84, ++ 0x04660cee, 0x0d8001fb, 0x025c034f, 0x00fd0b84, + 0x026c0270, 0x00000004, 0x00050009, 0x00070135, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00170136, 0x00000000, +@@ -218,7 +218,7 @@ static const struct rp1vec_hwmode rp1vec + .misc = 0x0009dc03, /* 5-tap FIR, SEQ_EN, 4 flds, 8 fld sync, ilace, PAL */ + .nco_freq = 0x0a8262b2cc48c1d1, + .timing_regs = { +- 0x046e0cee, 0x0d8001fb, 0x025c034f, 0x00fd0b84, ++ 0x04660cee, 0x0d8001fb, 0x025c034f, 0x00fd0b84, + 0x026c0270, 0x00000004, 0x00050009, 0x00070135, + 0x013f026d, 0x00060136, 0x0140026e, 0x0150026e, + 0x00180136, 0x026f0017, diff --git a/target/linux/bcm27xx/patches-6.6/950-0058-Revert-Bluetooth-Always-request-for-user-confirmatio.patch b/target/linux/bcm27xx/patches-6.6/950-1255-Revert-Bluetooth-Always-request-for-user-confirmatio.patch similarity index 86% rename from target/linux/bcm27xx/patches-6.6/950-0058-Revert-Bluetooth-Always-request-for-user-confirmatio.patch rename to target/linux/bcm27xx/patches-6.6/950-1255-Revert-Bluetooth-Always-request-for-user-confirmatio.patch index 5e3446d6f130..e549f27d7b34 100644 --- a/target/linux/bcm27xx/patches-6.6/950-0058-Revert-Bluetooth-Always-request-for-user-confirmatio.patch +++ b/target/linux/bcm27xx/patches-6.6/950-1255-Revert-Bluetooth-Always-request-for-user-confirmatio.patch @@ -1,7 +1,7 @@ -From eaeca896d077e9e42866f7f7caae7b62211a0d0d Mon Sep 17 00:00:00 2001 +From d6a12dd8f4e9362f7dd355969dd046adc44b1f47 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 1 Mar 2021 09:12:44 +0000 -Subject: [PATCH 0058/1085] Revert "Bluetooth: Always request for user +Subject: [PATCH 1255/1350] Revert "Bluetooth: Always request for user confirmation for Just Works (LE SC)" This reverts commit ffee202a78c2980688bc5d2f7d56480e69a5e0c9. @@ -24,7 +24,7 @@ Signed-off-by: Phil Elwell --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c -@@ -2215,7 +2215,7 @@ mackey_and_ltk: +@@ -2208,7 +2208,7 @@ mackey_and_ltk: if (err) return SMP_UNSPECIFIED; @@ -33,7 +33,7 @@ Signed-off-by: Phil Elwell if (test_bit(SMP_FLAG_INITIATOR, &smp->flags)) { sc_dhkey_check(smp); SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK); -@@ -2230,9 +2230,6 @@ mackey_and_ltk: +@@ -2223,9 +2223,6 @@ mackey_and_ltk: confirm_hint = 0; confirm: diff --git a/target/linux/bcm27xx/patches-6.6/950-1256-media-i2c-ov5647-Add-control-of-V4L2_CID_HBLANK.patch b/target/linux/bcm27xx/patches-6.6/950-1256-media-i2c-ov5647-Add-control-of-V4L2_CID_HBLANK.patch new file mode 100644 index 000000000000..89c690ca5bf7 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1256-media-i2c-ov5647-Add-control-of-V4L2_CID_HBLANK.patch @@ -0,0 +1,126 @@ +From e4c2a7731efcd7abe7554debef783b5358712d6d Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 9 Sep 2024 16:41:12 +0100 +Subject: [PATCH 1256/1350] media: i2c: ov5647: Add control of V4L2_CID_HBLANK + +The driver did expose V4L2_CID_HBLANK, but as a READ_ONLY control. + +The sensor only uses the HTS register to control the line length, +so convert this control to read/write, with the appropriate ranges. +Adopt the old fixed values as the minimum values permitted in each +mode to avoid issues of it not streaming. + +This should allow exposure times up to ~3 seconds (up from ~1sec). + +Signed-off-by: Dave Stevenson +--- + drivers/media/i2c/ov5647.c | 26 +++++++++++++------------- + 1 file changed, 13 insertions(+), 13 deletions(-) + +--- a/drivers/media/i2c/ov5647.c ++++ b/drivers/media/i2c/ov5647.c +@@ -53,6 +53,8 @@ + #define OV5647_REG_AEC_AGC 0x3503 + #define OV5647_REG_GAIN_HI 0x350a + #define OV5647_REG_GAIN_LO 0x350b ++#define OV5647_REG_HTS_HI 0x380c ++#define OV5647_REG_HTS_LO 0x380d + #define OV5647_REG_VTS_HI 0x380e + #define OV5647_REG_VTS_LO 0x380f + #define OV5647_REG_VFLIP 0x3820 +@@ -79,6 +81,8 @@ + #define OV5647_VBLANK_MIN 24 + #define OV5647_VTS_MAX 32767 + ++#define OV5647_HTS_MAX 0x1fff ++ + #define OV5647_EXPOSURE_MIN 4 + #define OV5647_EXPOSURE_STEP 1 + #define OV5647_EXPOSURE_DEFAULT 1000 +@@ -188,8 +192,6 @@ static struct regval_list ov5647_2592x19 + {0x3a19, 0xf8}, + {0x3c01, 0x80}, + {0x3b07, 0x0c}, +- {0x380c, 0x0b}, +- {0x380d, 0x1c}, + {0x3814, 0x11}, + {0x3815, 0x11}, + {0x3708, 0x64}, +@@ -277,8 +279,6 @@ static struct regval_list ov5647_1080p30 + {0x3a19, 0xf8}, + {0x3c01, 0x80}, + {0x3b07, 0x0c}, +- {0x380c, 0x09}, +- {0x380d, 0x70}, + {0x3814, 0x11}, + {0x3815, 0x11}, + {0x3708, 0x64}, +@@ -376,8 +376,6 @@ static struct regval_list ov5647_2x2binn + {0x3809, 0x10}, + {0x380a, 0x03}, + {0x380b, 0xcc}, +- {0x380c, 0x07}, +- {0x380d, 0x68}, + {0x3811, 0x0c}, + {0x3813, 0x06}, + {0x3814, 0x31}, +@@ -451,8 +449,6 @@ static struct regval_list ov5647_640x480 + {0x3a19, 0xf8}, + {0x3c01, 0x80}, + {0x3b07, 0x0c}, +- {0x380c, 0x07}, +- {0x380d, 0x3c}, + {0x3814, 0x35}, + {0x3815, 0x35}, + {0x3708, 0x64}, +@@ -1079,7 +1075,8 @@ static int ov5647_set_pad_fmt(struct v4l + mode->pixel_rate, 1, mode->pixel_rate); + + hblank = mode->hts - mode->format.width; +- __v4l2_ctrl_modify_range(sensor->hblank, hblank, hblank, 1, ++ __v4l2_ctrl_modify_range(sensor->hblank, hblank, ++ OV5647_HTS_MAX - mode->format.width, 1, + hblank); + + vblank = mode->vts - mode->format.height; +@@ -1343,6 +1340,10 @@ static int ov5647_s_ctrl(struct v4l2_ctr + ret = ov5647_write16(sd, OV5647_REG_VTS_HI, + sensor->mode->format.height + ctrl->val); + break; ++ case V4L2_CID_HBLANK: ++ ret = ov5647_write16(sd, OV5647_REG_HTS_HI, ++ sensor->mode->format.width + ctrl->val); ++ break; + case V4L2_CID_TEST_PATTERN: + ret = ov5647_write(sd, OV5647_REG_ISPCTRL3D, + ov5647_test_pattern_val[ctrl->val]); +@@ -1350,7 +1351,6 @@ static int ov5647_s_ctrl(struct v4l2_ctr + + /* Read-only, but we adjust it based on mode. */ + case V4L2_CID_PIXEL_RATE: +- case V4L2_CID_HBLANK: + /* Read-only, but we adjust it based on mode. */ + break; + +@@ -1427,10 +1427,11 @@ static int ov5647_init_controls(struct o + sensor->mode->pixel_rate, 1, + sensor->mode->pixel_rate); + +- /* By default, HBLANK is read only, but it does change per mode. */ + hblank = sensor->mode->hts - sensor->mode->format.width; + sensor->hblank = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops, +- V4L2_CID_HBLANK, hblank, hblank, 1, ++ V4L2_CID_HBLANK, hblank, ++ OV5647_HTS_MAX - ++ sensor->mode->format.width, 1, + hblank); + + sensor->vblank = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops, +@@ -1464,7 +1465,6 @@ static int ov5647_init_controls(struct o + goto handler_free; + + sensor->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY; +- sensor->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + sensor->sd.ctrl_handler = &sensor->ctrls; + + return 0; diff --git a/target/linux/bcm27xx/patches-6.6/950-1257-drm-vc4-Add-support-for-per-plane-scaling-filter-sel.patch b/target/linux/bcm27xx/patches-6.6/950-1257-drm-vc4-Add-support-for-per-plane-scaling-filter-sel.patch new file mode 100644 index 000000000000..5b3ae3c91011 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1257-drm-vc4-Add-support-for-per-plane-scaling-filter-sel.patch @@ -0,0 +1,170 @@ +From d6a3a3f106010d9576a700148220842cac4c5739 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 25 Jul 2024 15:42:41 +0100 +Subject: [PATCH 1257/1350] drm/vc4: Add support for per plane scaling filter + selection + +Seeing as the HVS can be configured with regard the scaling filter, +and DRM now supports selecting scaling filters at a per CRTC or +per plane level, we can implement it. + +Default remains as the Mitchell/Netravali filter, but nearest +neighbour is now also implemented. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_drv.h | 1 + + drivers/gpu/drm/vc4/vc4_hvs.c | 14 ++++++++-- + drivers/gpu/drm/vc4/vc4_plane.c | 48 ++++++++++++++++++++++++++------- + 3 files changed, 52 insertions(+), 11 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -358,6 +358,7 @@ struct vc4_hvs { + struct work_struct free_dlist_work; + + struct drm_mm_node mitchell_netravali_filter; ++ struct drm_mm_node nearest_neighbour_filter; + + struct debugfs_regset32 regset; + +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -469,6 +469,9 @@ static int vc4_hvs_debugfs_dlist_allocs( + static const u32 mitchell_netravali_1_3_1_3_kernel[] = + VC4_LINEAR_PHASE_KERNEL(0, -2, -6, -8, -10, -8, -3, 2, 18, + 50, 82, 119, 155, 187, 213, 227); ++static const u32 nearest_neighbour_kernel[] = ++ VC4_LINEAR_PHASE_KERNEL(0, 0, 0, 0, 0, 0, 0, 0, ++ 1, 1, 1, 1, 255, 255, 255, 255); + + static int vc4_hvs_upload_linear_kernel(struct vc4_hvs *hvs, + struct drm_mm_node *space, +@@ -2255,14 +2258,19 @@ static int vc4_hvs_bind(struct device *d + if (ret) + return ret; + +- /* Upload filter kernels. We only have the one for now, so we +- * keep it around for the lifetime of the driver. ++ /* Upload filter kernels. We only have the two for now, so we ++ * keep them around for the lifetime of the driver. + */ + ret = vc4_hvs_upload_linear_kernel(hvs, + &hvs->mitchell_netravali_filter, + mitchell_netravali_1_3_1_3_kernel); + if (ret) + return ret; ++ ret = vc4_hvs_upload_linear_kernel(hvs, ++ &hvs->nearest_neighbour_filter, ++ nearest_neighbour_kernel); ++ if (ret) ++ return ret; + + ret = vc4_hvs_cob_init(hvs); + if (ret) +@@ -2288,6 +2296,8 @@ static void vc4_hvs_unbind(struct device + + if (drm_mm_node_allocated(&vc4->hvs->mitchell_netravali_filter)) + drm_mm_remove_node(&vc4->hvs->mitchell_netravali_filter); ++ if (drm_mm_node_allocated(&vc4->hvs->nearest_neighbour_filter)) ++ drm_mm_remove_node(&vc4->hvs->nearest_neighbour_filter); + + drm_mm_for_each_node_safe(node, next, &vc4->hvs->dlist_mm) + drm_mm_remove_node(node); +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -582,7 +582,9 @@ static void vc4_write_tpz(struct vc4_pla + /* phase magnitude bits */ + #define PHASE_BITS 6 + +-static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst, u32 xy, int channel, int chroma_offset) ++static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst, ++ u32 xy, int channel, int chroma_offset, ++ bool no_interpolate) + { + struct vc4_dev *vc4 = to_vc4_dev(vc4_state->base.plane->dev); + u32 scale = src / dst; +@@ -621,6 +623,7 @@ static void vc4_write_ppf(struct vc4_pla + phase &= SCALER_PPF_IPHASE_MASK; + + vc4_dlist_write(vc4_state, ++ no_interpolate ? SCALER_PPF_NOINTERP : 0 | + SCALER_PPF_AGC | + VC4_SET_FIELD(scale, SCALER_PPF_SCALE) | + /* +@@ -815,15 +818,17 @@ static void vc4_write_scaling_parameters + /* Ch0 H-PPF Word 0: Scaling Parameters */ + if (vc4_state->x_scaling[channel] == VC4_SCALING_PPF) { + vc4_write_ppf(vc4_state, +- vc4_state->src_w[channel], vc4_state->crtc_w, vc4_state->src_x, channel, +- state->chroma_siting_h); ++ vc4_state->src_w[channel], vc4_state->crtc_w, vc4_state->src_x, ++ channel, state->chroma_siting_h, ++ state->scaling_filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR); + } + + /* Ch0 V-PPF Words 0-1: Scaling Parameters, Context */ + if (vc4_state->y_scaling[channel] == VC4_SCALING_PPF) { + vc4_write_ppf(vc4_state, +- vc4_state->src_h[channel], vc4_state->crtc_h, vc4_state->src_y, channel, +- state->chroma_siting_v); ++ vc4_state->src_h[channel], vc4_state->crtc_h, vc4_state->src_y, ++ channel, state->chroma_siting_v, ++ state->scaling_filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR); + vc4_dlist_write(vc4_state, 0xc0c0c0c0); + } + +@@ -1573,7 +1578,18 @@ static int vc4_plane_mode_set(struct drm + vc4_state->y_scaling[0] == VC4_SCALING_PPF || + vc4_state->x_scaling[1] == VC4_SCALING_PPF || + vc4_state->y_scaling[1] == VC4_SCALING_PPF) { +- u32 kernel = VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start, ++ struct drm_mm_node *filter; ++ ++ switch (state->scaling_filter) { ++ case DRM_SCALING_FILTER_DEFAULT: ++ default: ++ filter = &vc4->hvs->mitchell_netravali_filter; ++ break; ++ case DRM_SCALING_FILTER_NEAREST_NEIGHBOR: ++ filter = &vc4->hvs->nearest_neighbour_filter; ++ break; ++ } ++ u32 kernel = VC4_SET_FIELD(filter->start, + SCALER_PPF_KERNEL_OFFSET); + + /* HPPF plane 0 */ +@@ -1984,9 +2000,19 @@ static int vc6_plane_mode_set(struct drm + vc4_state->y_scaling[0] == VC4_SCALING_PPF || + vc4_state->x_scaling[1] == VC4_SCALING_PPF || + vc4_state->y_scaling[1] == VC4_SCALING_PPF) { +- u32 kernel = +- VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start, +- SCALER_PPF_KERNEL_OFFSET); ++ struct drm_mm_node *filter; ++ ++ switch (state->scaling_filter) { ++ case DRM_SCALING_FILTER_DEFAULT: ++ default: ++ filter = &vc4->hvs->mitchell_netravali_filter; ++ break; ++ case DRM_SCALING_FILTER_NEAREST_NEIGHBOR: ++ filter = &vc4->hvs->nearest_neighbour_filter; ++ break; ++ } ++ u32 kernel = VC4_SET_FIELD(filter->start, ++ SCALER_PPF_KERNEL_OFFSET); + + /* HPPF plane 0 */ + vc4_dlist_write(vc4_state, kernel); +@@ -2468,6 +2494,10 @@ struct drm_plane *vc4_plane_init(struct + DRM_COLOR_YCBCR_BT709, + DRM_COLOR_YCBCR_LIMITED_RANGE); + ++ drm_plane_create_scaling_filter_property(plane, ++ BIT(DRM_SCALING_FILTER_DEFAULT) | ++ BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR)); ++ + drm_plane_create_chroma_siting_properties(plane, 0, 0); + + if (type == DRM_PLANE_TYPE_PRIMARY) diff --git a/target/linux/bcm27xx/patches-6.6/950-1258-drm-panel-waveshare-Remove-duplicated-sentinel-on-co.patch b/target/linux/bcm27xx/patches-6.6/950-1258-drm-panel-waveshare-Remove-duplicated-sentinel-on-co.patch new file mode 100644 index 000000000000..215cc3cf7684 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1258-drm-panel-waveshare-Remove-duplicated-sentinel-on-co.patch @@ -0,0 +1,37 @@ +From 7a3d1c22ecbdac458883991beae0461137cbfc8a Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 12 Sep 2024 18:04:58 +0100 +Subject: [PATCH 1258/1350] drm: panel: waveshare: Remove duplicated sentinel + on compatible list + +Remove the duplicated sentinel that got added, otherwise we have +an extra blank compatible string match in the module, and that matches +everything. + +$ modinfo panel_waveshare_dsi +filename: /lib/modules/6.6.50-v8+/kernel/drivers/gpu/drm/panel/panel-waveshare-dsi.ko.xz +license: GPL +description: Waveshare DSI panel driver +author: Dave Stevenson +srcversion: E767180DABD8B00B45571AF +alias: of:N*T*C* +alias: of:N*T* +alias: of:N*T*Cwaveshare,8.8inch-panelC* +alias: of:N*T*Cwaveshare,8.8inch-panel + +Fixes: f955b7838f9c ("drivers:gpu:drm:panel: Added waveshare 5.0inch, 6.25inch, and 8.8inch dsi screen devices") +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/panel/panel-waveshare-dsi.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/gpu/drm/panel/panel-waveshare-dsi.c ++++ b/drivers/gpu/drm/panel/panel-waveshare-dsi.c +@@ -467,7 +467,6 @@ static const struct of_device_id ws_pane + .compatible = "waveshare,8.8inch-panel", + .data = &ws_panel_8_8_mode, + }, { +- }, { + /* sentinel */ + } + }; diff --git a/target/linux/bcm27xx/patches-6.6/950-1019-drivers-mmc-disable-write-caching-on-Samsung-2023-mo.patch b/target/linux/bcm27xx/patches-6.6/950-1260-drivers-mmc-disable-write-caching-on-Samsung-2023-mo.patch similarity index 92% rename from target/linux/bcm27xx/patches-6.6/950-1019-drivers-mmc-disable-write-caching-on-Samsung-2023-mo.patch rename to target/linux/bcm27xx/patches-6.6/950-1260-drivers-mmc-disable-write-caching-on-Samsung-2023-mo.patch index 73a6b708567b..35607aacafba 100644 --- a/target/linux/bcm27xx/patches-6.6/950-1019-drivers-mmc-disable-write-caching-on-Samsung-2023-mo.patch +++ b/target/linux/bcm27xx/patches-6.6/950-1260-drivers-mmc-disable-write-caching-on-Samsung-2023-mo.patch @@ -1,7 +1,7 @@ -From 43730828eca754b4b527d79fc5a1d3ff50c50481 Mon Sep 17 00:00:00 2001 +From c9b61d1d83073761871c7acba332216494e6f0bb Mon Sep 17 00:00:00 2001 From: Jonathan Bell Date: Mon, 8 Apr 2024 16:09:52 +0100 -Subject: [PATCH 1019/1085] drivers: mmc: disable write-caching on Samsung 2023 +Subject: [PATCH 1260/1350] drivers: mmc: disable write-caching on Samsung 2023 model year SD cards Samsung EVO Plus, Pro Plus and Evo Ultimate cards of this era appear to diff --git a/target/linux/bcm27xx/patches-6.6/950-1261-mm-vmscan-Maintain-TLB-coherency-in-LRU-code.patch b/target/linux/bcm27xx/patches-6.6/950-1261-mm-vmscan-Maintain-TLB-coherency-in-LRU-code.patch new file mode 100644 index 000000000000..70ece97505c7 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1261-mm-vmscan-Maintain-TLB-coherency-in-LRU-code.patch @@ -0,0 +1,27 @@ +From 536f2097dc397e4ebd0566e8f00219c02d7c8073 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 12 Sep 2024 10:06:50 +0100 +Subject: [PATCH 1261/1350] mm/vmscan: Maintain TLB coherency in LRU code + +As a workaround (and possibly a fix) for CPU spins observed on BCM2837, +use ptep_clear_flush_young instead of ptep_test_and_clear_young inside +lru_gen_look_around in order to expose PTE changes to the MMU. Note that +on architectures that don't require an explicit flush, +ptep_clear_flush_young just calls ptep_test_and_clear_young. + +Signed-off-by: Phil Elwell +--- + mm/vmscan.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -4716,7 +4716,7 @@ void lru_gen_look_around(struct page_vma + if (!folio) + continue; + +- if (!ptep_test_and_clear_young(vma, addr, pte + i)) ++ if (!ptep_clear_flush_young(vma, addr, pte + i)) + VM_WARN_ON_ONCE(true); + + young++; diff --git a/target/linux/bcm27xx/patches-6.6/950-1262-drm-panel-ili9881-Correct-symmetry-on-enable-disable.patch b/target/linux/bcm27xx/patches-6.6/950-1262-drm-panel-ili9881-Correct-symmetry-on-enable-disable.patch new file mode 100644 index 000000000000..d10eee3c0bdc --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1262-drm-panel-ili9881-Correct-symmetry-on-enable-disable.patch @@ -0,0 +1,35 @@ +From c763cf351ea25b7fb31f2d388dab0838565d1b75 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 13 Sep 2024 14:44:08 +0100 +Subject: [PATCH 1262/1350] drm: panel: ili9881: Correct symmetry on + enable/disable return codes + +ili9881c_enable is always returning 0. + +ili9881c_disable was returning the error code from +mipi_dsi_dcs_set_display_off. +If non-zero, the drm_panel framework will leave the panel marked as +enabled, and not run the enable hook next time around. That isn't +helpful, particularly as we're expecting unprepare to disable +resets and regulators. + +Change ili9881c_disable to match enable in always returning 0. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/panel/panel-ilitek-ili9881c.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c ++++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c +@@ -1745,7 +1745,9 @@ static int ili9881c_disable(struct drm_p + { + struct ili9881c *ctx = panel_to_ili9881c(panel); + +- return mipi_dsi_dcs_set_display_off(ctx->dsi); ++ mipi_dsi_dcs_set_display_off(ctx->dsi); ++ ++ return 0; + } + + static int ili9881c_unprepare(struct drm_panel *panel) diff --git a/target/linux/bcm27xx/patches-6.6/950-1263-dtoverlays-adds-the-definitions-for-the-HiFiBerry-8-.patch b/target/linux/bcm27xx/patches-6.6/950-1263-dtoverlays-adds-the-definitions-for-the-HiFiBerry-8-.patch new file mode 100644 index 000000000000..0dff678d934f --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1263-dtoverlays-adds-the-definitions-for-the-HiFiBerry-8-.patch @@ -0,0 +1,113 @@ +From 77773aec03f65758c760ec5b43a79ad6edeb211b Mon Sep 17 00:00:00 2001 +From: j-schambacher +Date: Thu, 12 Sep 2024 16:44:12 +0200 +Subject: [PATCH 1263/1350] dtoverlays: adds the definitions for the HiFiBerry + 8-channel ADC + +Additions and changes for the 8 channel ADC card. This card uses only +HW-controlled devices which allows the uses of the 'dummy-dai'. +It will run only on a PI5 as it requires the designware I2S0 module. + +The necessary output lanes I2S0_DI[0..3] are claimed from within the +DT overlay. + +Signed-off-by: j-schambacher +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 6 +++ + .../dts/overlays/hifiberry-adc8x-overlay.dts | 50 +++++++++++++++++++ + arch/arm/boot/dts/overlays/overlay_map.dts | 4 ++ + 4 files changed, 61 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/hifiberry-adc8x-overlay.dts + +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -86,6 +86,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + hd44780-lcd.dtbo \ + hdmi-backlight-hwhack-gpio.dtbo \ + hifiberry-adc.dtbo \ ++ hifiberry-adc8x.dtbo \ + hifiberry-amp.dtbo \ + hifiberry-amp100.dtbo \ + hifiberry-amp3.dtbo \ +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -1778,6 +1778,12 @@ Params: leds_off If set t + is switched off at all times. + + ++Name: hifiberry-adc8x ++Info: Configures the HifiBerry ADC8X audio card (only on Pi5) ++Load: dtoverlay=hifiberry-adc8x ++Params: ++ ++ + Name: hifiberry-amp + Info: Configures the HifiBerry Amp and Amp+ audio cards + Load: dtoverlay=hifiberry-amp +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/hifiberry-adc8x-overlay.dts +@@ -0,0 +1,50 @@ ++// Definitions for HiFiBerry ADC8x ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&gpio>; ++ __overlay__ { ++ rp1_i2s0_adc8x: rp1_i2s0_adc8x { ++ function = "i2s0"; ++ pins = "gpio18", "gpio19", "gpio20", ++ "gpio22", "gpio24", "gpio26"; ++ bias-disable; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&i2s_clk_producer>; ++ __overlay__ { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&rp1_i2s0_adc8x>; ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@2 { ++ target-path = "/"; ++ __overlay__ { ++ dummy-codec { ++ #sound-dai-cells = <0>; ++ compatible = "snd-soc-dummy"; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&sound>; ++ __overlay__ { ++ compatible = "hifiberry,hifiberry-adc8x"; ++ i2s-controller = <&i2s_clk_producer>; ++ status = "okay"; ++ }; ++ }; ++ ++}; +--- a/arch/arm/boot/dts/overlays/overlay_map.dts ++++ b/arch/arm/boot/dts/overlays/overlay_map.dts +@@ -48,6 +48,10 @@ + bcm2712; + }; + ++ hifiberry-adc8x { ++ bcm2712; ++ }; ++ + hifiberry-dac8x { + bcm2712; + }; diff --git a/target/linux/bcm27xx/patches-6.6/950-1264-ASoC-add-HiFiBerry-ADC8x-8-channel-ADC-to-simple-car.patch b/target/linux/bcm27xx/patches-6.6/950-1264-ASoC-add-HiFiBerry-ADC8x-8-channel-ADC-to-simple-car.patch new file mode 100644 index 000000000000..87d523e2a6b2 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1264-ASoC-add-HiFiBerry-ADC8x-8-channel-ADC-to-simple-car.patch @@ -0,0 +1,88 @@ +From 4d2eaa194d77588fa42567ba174c3c14c5798027 Mon Sep 17 00:00:00 2001 +From: j-schambacher +Date: Thu, 12 Sep 2024 17:42:13 +0200 +Subject: [PATCH 1264/1350] ASoC: add HiFiBerry ADC8x 8-channel ADC to + simple-card-driver + +Definitions for the 8 channel ADC card. The card uses only +HW-controlled devices which allows the uses of the 'dummy-dai'. +It will run only on a PI5 as it requires the designware I2S0 module. + +The necessary output lanes I2S0_DI[0..3] are claimed from within the +DT overlay. + +Signed-off-by: j-schambacher +--- + sound/soc/bcm/Kconfig | 7 ++++++ + sound/soc/bcm/rpi-simple-soundcard.c | 37 ++++++++++++++++++++++++++++ + 2 files changed, 44 insertions(+) + +--- a/sound/soc/bcm/Kconfig ++++ b/sound/soc/bcm/Kconfig +@@ -47,6 +47,13 @@ config SND_BCM2708_SOC_HIFIBERRY_ADC + Say Y or M if you want to add support for HifiBerry ADC. + Use this module for HiFiBerry's ADC-only sound cards + ++config SND_BCM2708_SOC_HIFIBERRY_ADC8X ++ tristate "Support for HifiBerry ADC8X" ++ select SND_RPI_SIMPLE_SOUNDCARD ++ help ++ Say Y or M if you want to add support for HifiBerry ADC8X. ++ Note: ADC8X only works on PI5 ++ + config SND_BCM2708_SOC_HIFIBERRY_DAC + tristate "Support for HifiBerry DAC and DAC8X" + select SND_SOC_PCM5102A +--- a/sound/soc/bcm/rpi-simple-soundcard.c ++++ b/sound/soc/bcm/rpi-simple-soundcard.c +@@ -254,6 +254,41 @@ static struct snd_rpi_simple_drvdata drv + .dai = snd_hifiberrydacplusdsp_soundcard_dai, + }; + ++SND_SOC_DAILINK_DEFS(hifiberry_adc, ++ DAILINK_COMP_ARRAY(COMP_EMPTY()), ++ DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), ++ DAILINK_COMP_ARRAY(COMP_EMPTY())); ++ ++static int hifiberry_adc8x_init(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); ++ ++ /* set limits of 8 channels and 192ksps sample rate ++ */ ++ codec_dai->driver->capture.channels_max = 8; ++ codec_dai->driver->capture.rates = SNDRV_PCM_RATE_8000_192000; ++ ++ return 0; ++} ++ ++static struct snd_soc_dai_link snd_hifiberry_adc8x_dai[] = { ++ { ++ .name = "HifiBerry ADC8x", ++ .stream_name = "HifiBerry ADC8x HiFi", ++ .dai_fmt = SND_SOC_DAIFMT_I2S | ++ SND_SOC_DAIFMT_NB_NF | ++ SND_SOC_DAIFMT_CBS_CFS, ++ .init = hifiberry_adc8x_init, ++ SND_SOC_DAILINK_REG(hifiberry_adc), ++ }, ++}; ++ ++static struct snd_rpi_simple_drvdata drvdata_hifiberry_adc8x = { ++ .card_name = "snd_rpi_hifiberry_adc8x", ++ .dai = snd_hifiberry_adc8x_dai, ++ .fixed_bclk_ratio = 64, ++}; ++ + SND_SOC_DAILINK_DEFS(hifiberry_amp, + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_CODEC("tas5713.1-001b", "tas5713-hifi")), +@@ -445,6 +480,8 @@ static const struct of_device_id snd_rpi + .data = (void *) &drvdata_googlevoicehat }, + { .compatible = "hifiberrydacplusdsp,hifiberrydacplusdsp-soundcard", + .data = (void *) &drvdata_hifiberrydacplusdsp }, ++ { .compatible = "hifiberry,hifiberry-adc8x", ++ .data = (void *) &drvdata_hifiberry_adc8x }, + { .compatible = "hifiberry,hifiberry-amp", + .data = (void *) &drvdata_hifiberry_amp }, + { .compatible = "hifiberry,hifiberry-amp3", diff --git a/target/linux/bcm27xx/patches-6.6/950-1265-vc04_services-codec-Allocate-the-max-number-of-buffe.patch b/target/linux/bcm27xx/patches-6.6/950-1265-vc04_services-codec-Allocate-the-max-number-of-buffe.patch new file mode 100644 index 000000000000..aa4c7594af0c --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1265-vc04_services-codec-Allocate-the-max-number-of-buffe.patch @@ -0,0 +1,35 @@ +From 8c9ca647449ba9df7e3b300c480242f9b5bdd867 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 10 Sep 2024 16:58:56 +0100 +Subject: [PATCH 1265/1350] vc04_services: codec: Allocate the max number of + buffers on the VPU + +The VPU's API can't match the use of VIDIOC_CREATE_BUFS to add buffers +to the internal pool whilst a port is enabled, therefore allocate +the maximum number of buffers possible in V4L2 to avoid the issue. +As these are only buffer headers, the overhead is relatively small. + +Signed-off-by: Dave Stevenson +--- + .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -2871,8 +2871,14 @@ static int bcm2835_codec_queue_setup(str + + if (*nbuffers < port->minimum_buffer.num) + *nbuffers = port->minimum_buffer.num; +- /* Add one buffer to take an EOS */ +- port->current_buffer.num = *nbuffers + 1; ++ ++ /* ++ * The VPU uses this number to allocate a pool of headers at port_enable. ++ * We can't increase it later, so use of CREATE_BUFS is going to result ++ * in bad things happening. Adopt worst-case allocation, and add one ++ * buffer to take an EOS ++ */ ++ port->current_buffer.num = VB2_MAX_FRAME + 1; + + return 0; + } diff --git a/target/linux/bcm27xx/patches-6.6/950-1266-drm-vc4-Fix-interpolate-bit-for-nearest-neighbour-fi.patch b/target/linux/bcm27xx/patches-6.6/950-1266-drm-vc4-Fix-interpolate-bit-for-nearest-neighbour-fi.patch new file mode 100644 index 000000000000..7fd30b65502e --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1266-drm-vc4-Fix-interpolate-bit-for-nearest-neighbour-fi.patch @@ -0,0 +1,26 @@ +From c1321370c9af9681e0604c4d3363cf362fb48598 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 16 Sep 2024 15:56:51 +0100 +Subject: [PATCH 1266/1350] drm: vc4: Fix interpolate bit for nearest neighbour + filter + +Operator precedence resulted in the wrong value being written +for nearest neighbour mode. Correct it. + +Fixes: d6a3a3f10601 ("drm/vc4: Add support for per plane scaling filter selection") +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_plane.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -623,7 +623,7 @@ static void vc4_write_ppf(struct vc4_pla + phase &= SCALER_PPF_IPHASE_MASK; + + vc4_dlist_write(vc4_state, +- no_interpolate ? SCALER_PPF_NOINTERP : 0 | ++ (no_interpolate ? SCALER_PPF_NOINTERP : 0) | + SCALER_PPF_AGC | + VC4_SET_FIELD(scale, SCALER_PPF_SCALE) | + /* diff --git a/target/linux/bcm27xx/patches-6.6/950-1267-dts-rp1-Disable-DMA-usage-for-UART0.patch b/target/linux/bcm27xx/patches-6.6/950-1267-dts-rp1-Disable-DMA-usage-for-UART0.patch new file mode 100644 index 000000000000..c809c4f10b60 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1267-dts-rp1-Disable-DMA-usage-for-UART0.patch @@ -0,0 +1,34 @@ +From cc63d552b9aab92fb581dfb08267d5af697f477b Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 18 Sep 2024 16:45:24 +0100 +Subject: [PATCH 1267/1350] dts: rp1: Disable DMA usage for UART0 + +Some recent DMA changes have led to data loss in UART0 on Pi 5. It also +seems that even prior to these changes there was a problem with aborted +transfers. + +As this is the only RP1 UART configured for DMA, it is better to remove +the DMA usage until it is shown to be reliable. + +Link: https://github.com/raspberrypi/linux/issues/6365 + +Signed-off-by: Phil Elwell +--- + arch/arm64/boot/dts/broadcom/rp1.dtsi | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/arch/arm64/boot/dts/broadcom/rp1.dtsi ++++ b/arch/arm64/boot/dts/broadcom/rp1.dtsi +@@ -55,9 +55,9 @@ + interrupts = ; + clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>; + clock-names = "uartclk", "apb_pclk"; +- dmas = <&rp1_dma RP1_DMA_UART0_TX>, +- <&rp1_dma RP1_DMA_UART0_RX>; +- dma-names = "tx", "rx"; ++ // dmas = <&rp1_dma RP1_DMA_UART0_TX>, ++ // <&rp1_dma RP1_DMA_UART0_RX>; ++ // dma-names = "tx", "rx"; + pinctrl-names = "default"; + arm,primecell-periphid = <0x00541011>; + uart-has-rtscts; diff --git a/target/linux/bcm27xx/patches-6.6/950-1269-drivers-media-imx500-Fixes-for-vblank-control.patch b/target/linux/bcm27xx/patches-6.6/950-1269-drivers-media-imx500-Fixes-for-vblank-control.patch new file mode 100644 index 000000000000..9b47eedca51d --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1269-drivers-media-imx500-Fixes-for-vblank-control.patch @@ -0,0 +1,50 @@ +From f6c0447dfb915538a0d5fa966fc26ca022cf49c8 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Fri, 20 Sep 2024 08:25:58 +0100 +Subject: [PATCH 1269/1350] drivers: media: imx500: Fixes for vblank control + +Reduce the default/max framerate of the 2x2 binned mode to 30fps. +The current limit of 50fps can cause the sensor to produce corrupt +frames and cause missing framing events. + +Also fixup the vblank control min/max/default/step paramters when +setting up. + +Signed-off-by: Naushir Patuck +--- + drivers/media/i2c/imx500.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/media/i2c/imx500.c ++++ b/drivers/media/i2c/imx500.c +@@ -47,7 +47,7 @@ + /* V_TIMING internal */ + #define IMX500_REG_FRAME_LENGTH CCI_REG16(0x0340) + #define IMX500_FRAME_LENGTH_MAX 0xffdc +-#define IMX500_VBLANK_MIN 4 ++#define IMX500_VBLANK_MIN 1117 + + /* H_TIMING internal */ + #define IMX500_REG_LINE_LENGTH CCI_REG16(0x0342) +@@ -922,7 +922,7 @@ static const struct imx500_mode imx500_s + .width = 4056, + .height = 3040, + }, +- .framerate_default = 40, ++ .framerate_default = 30, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_2028x1520_regs), + .regs = mode_2028x1520_regs, +@@ -1771,10 +1771,10 @@ static void imx500_set_framing_limits(st + + /* Update limits and set FPS to default */ + __v4l2_ctrl_modify_range( +- imx500->vblank, 1, ++ imx500->vblank, IMX500_VBLANK_MIN, + ((1 << IMX500_LONG_EXP_SHIFT_MAX) * IMX500_FRAME_LENGTH_MAX) - + mode->height, +- IMX500_VBLANK_MIN, frm_length_default - mode->height); ++ 1, frm_length_default - mode->height); + + /* Setting this will adjust the exposure limits as well. */ + __v4l2_ctrl_s_ctrl(imx500->vblank, frm_length_default - mode->height); diff --git a/target/linux/bcm27xx/patches-6.6/950-1270-drm-bridge-Document-bridge-init-order-with-pre_enabl.patch b/target/linux/bcm27xx/patches-6.6/950-1270-drm-bridge-Document-bridge-init-order-with-pre_enabl.patch new file mode 100644 index 000000000000..14f9dd8d8472 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1270-drm-bridge-Document-bridge-init-order-with-pre_enabl.patch @@ -0,0 +1,56 @@ +From d62184f6b06627b4fe922b08132e38c181d389a0 Mon Sep 17 00:00:00 2001 +From: Jagan Teki +Date: Tue, 28 Mar 2023 22:37:52 +0530 +Subject: [PATCH 1270/1350] drm/bridge: Document bridge init order with + pre_enable_prev_first +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Upstream commit 113cc3ad8566e06d6c8ef4fc0075a938dedefab5 + +In order to satisfy the MIPI DSI initialization sequence the bridge +init order has been altered with the help of pre_enable_prev_first +in pre_enable and post_disable bridge operations. + +Document the affected bridge init order with an example on the +bridge operations helpers. + +Signed-off-by: Jagan Teki +Reviewed-by: Dave Stevenson +Signed-off-by: Robert Foss +Link: https://patchwork.freedesktop.org/patch/msgid/20230328170752.1102347-2-jagan@amarulasolutions.com +--- + drivers/gpu/drm/drm_bridge.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +--- a/drivers/gpu/drm/drm_bridge.c ++++ b/drivers/gpu/drm/drm_bridge.c +@@ -657,6 +657,13 @@ static void drm_atomic_bridge_call_post_ + * bridge will be called before the previous one to reverse the @pre_enable + * calling direction. + * ++ * Example: ++ * Bridge A ---> Bridge B ---> Bridge C ---> Bridge D ---> Bridge E ++ * ++ * With pre_enable_prev_first flag enable in Bridge B, D, E then the resulting ++ * @post_disable order would be, ++ * Bridge B, Bridge A, Bridge E, Bridge D, Bridge C. ++ * + * Note: the bridge passed should be the one closest to the encoder + */ + void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, +@@ -753,6 +760,13 @@ static void drm_atomic_bridge_call_pre_e + * If a bridge sets @pre_enable_prev_first, then the pre_enable for the + * prev bridge will be called before pre_enable of this bridge. + * ++ * Example: ++ * Bridge A ---> Bridge B ---> Bridge C ---> Bridge D ---> Bridge E ++ * ++ * With pre_enable_prev_first flag enable in Bridge B, D, E then the resulting ++ * @pre_enable order would be, ++ * Bridge C, Bridge D, Bridge E, Bridge A, Bridge B. ++ * + * Note: the bridge passed should be the one closest to the encoder + */ + void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, diff --git a/target/linux/bcm27xx/patches-6.6/950-1271-drm-vc4-dsi-Don-t-reset-the-host-until-post_disable.patch b/target/linux/bcm27xx/patches-6.6/950-1271-drm-vc4-dsi-Don-t-reset-the-host-until-post_disable.patch new file mode 100644 index 000000000000..11094eb801cd --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1271-drm-vc4-dsi-Don-t-reset-the-host-until-post_disable.patch @@ -0,0 +1,50 @@ +From ef34d0100e0f2f137ad0e6af333aad4e0d5c3319 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 2 May 2024 12:03:58 +0100 +Subject: [PATCH 1271/1350] drm/vc4: dsi: Don't reset the host until + post_disable + +Some DSI peripheral drivers wish to send commands in the +post_disable or panel unprepare callback. These are called +after the DSI host's disable call, but before the host's +post_disable if pre_enable_prev_first is set. + +Don't reset the block until post_disable to allow these +commands to be sent. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_dsi.c | 15 +++++++-------- + 1 file changed, 7 insertions(+), 8 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_dsi.c ++++ b/drivers/gpu/drm/vc4/vc4_dsi.c +@@ -818,6 +818,13 @@ static void vc4_dsi_bridge_disable(struc + disp0_ctrl = DSI_PORT_READ(DISP0_CTRL); + disp0_ctrl &= ~DSI_DISP0_ENABLE; + DSI_PORT_WRITE(DISP0_CTRL, disp0_ctrl); ++} ++ ++static void vc4_dsi_bridge_post_disable(struct drm_bridge *bridge, ++ struct drm_bridge_state *state) ++{ ++ struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge); ++ struct device *dev = &dsi->pdev->dev; + + /* Reset the DSI and all its fifos. */ + DSI_PORT_WRITE(CTRL, DSI_CTRL_SOFT_RESET_CFG | +@@ -828,14 +835,6 @@ static void vc4_dsi_bridge_disable(struc + DSI_PORT_BIT(PHY_AFEC0_PD) | + DSI_PORT_BIT(AFEC0_PD_ALL_LANES)); + +-} +- +-static void vc4_dsi_bridge_post_disable(struct drm_bridge *bridge, +- struct drm_bridge_state *state) +-{ +- struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge); +- struct device *dev = &dsi->pdev->dev; +- + clk_disable_unprepare(dsi->pll_phy_clock); + clk_disable_unprepare(dsi->escape_clock); + clk_disable_unprepare(dsi->pixel_clock); diff --git a/target/linux/bcm27xx/patches-6.6/950-1272-drm-vc4-dsi-enable-video-and-then-retry-failed-trans.patch b/target/linux/bcm27xx/patches-6.6/950-1272-drm-vc4-dsi-enable-video-and-then-retry-failed-trans.patch new file mode 100644 index 000000000000..e39e3b58655b --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1272-drm-vc4-dsi-enable-video-and-then-retry-failed-trans.patch @@ -0,0 +1,111 @@ +From 6da70162dd1e729c04e2dc25472b39390868af79 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 20 Sep 2024 12:05:18 +0100 +Subject: [PATCH 1272/1350] drm: vc4: dsi: enable video and then retry failed + transfers + +The DSI block appears to be able to come up stuck in a condition where +it leaves the lanes in HS mode or just jabbering. This stops LP +transfers from completing as there is no LP time available. This is +signalled via the LP1 contention error. + +Enabling video briefly clears that condition, so if we detect the +error condition, enable video mode and then retry. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_dsi.c | 54 +++++++++++++++++++++++++++++------ + 1 file changed, 46 insertions(+), 8 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_dsi.c ++++ b/drivers/gpu/drm/vc4/vc4_dsi.c +@@ -286,6 +286,8 @@ + DSI1_INT_PR_TO) + + #define DSI0_STAT 0x2c ++# define DSI0_STAT_ERR_CONT_LP1 BIT(6) ++# define DSI0_STAT_ERR_CONT_LP0 BIT(5) + #define DSI0_HSTX_TO_CNT 0x30 + #define DSI0_LPRX_TO_CNT 0x34 + #define DSI0_TA_TO_CNT 0x38 +@@ -1203,10 +1205,9 @@ static int vc4_dsi_bridge_attach(struct + &dsi->bridge, flags); + } + +-static ssize_t vc4_dsi_host_transfer(struct mipi_dsi_host *host, +- const struct mipi_dsi_msg *msg) ++static ssize_t vc4_dsi_transfer(struct vc4_dsi *dsi, ++ const struct mipi_dsi_msg *msg, bool log_error) + { +- struct vc4_dsi *dsi = host_to_dsi(host); + struct mipi_dsi_packet packet; + u32 pkth = 0, pktc = 0; + int i, ret; +@@ -1315,10 +1316,12 @@ static ssize_t vc4_dsi_host_transfer(str + DSI_PORT_WRITE(TXPKT1C, pktc); + + if (!wait_for_completion_timeout(&dsi->xfer_completion, +- msecs_to_jiffies(1000))) { +- dev_err(&dsi->pdev->dev, "transfer interrupt wait timeout"); +- dev_err(&dsi->pdev->dev, "instat: 0x%08x\n", +- DSI_PORT_READ(INT_STAT)); ++ msecs_to_jiffies(500))) { ++ if (log_error) { ++ dev_err(&dsi->pdev->dev, "transfer interrupt wait timeout"); ++ dev_err(&dsi->pdev->dev, "instat: 0x%08x, stat: 0x%08x\n", ++ DSI_PORT_READ(INT_STAT), DSI_PORT_READ(INT_STAT)); ++ } + ret = -ETIMEDOUT; + } else { + ret = dsi->xfer_result; +@@ -1361,7 +1364,8 @@ static ssize_t vc4_dsi_host_transfer(str + return ret; + + reset_fifo_and_return: +- DRM_ERROR("DSI transfer failed, resetting: %d\n", ret); ++ if (log_error) ++ DRM_ERROR("DSI transfer failed, resetting: %d\n", ret); + + DSI_PORT_WRITE(TXPKT1C, DSI_PORT_READ(TXPKT1C) & ~DSI_TXPKT1C_CMD_EN); + udelay(1); +@@ -1374,6 +1378,40 @@ reset_fifo_and_return: + return ret; + } + ++static ssize_t vc4_dsi_host_transfer(struct mipi_dsi_host *host, ++ const struct mipi_dsi_msg *msg) ++{ ++ struct vc4_dsi *dsi = host_to_dsi(host); ++ u32 stat, disp0_ctrl; ++ int ret; ++ ++ ret = vc4_dsi_transfer(dsi, msg, false); ++ ++ if (ret == -ETIMEDOUT) { ++ stat = DSI_PORT_READ(STAT); ++ disp0_ctrl = DSI_PORT_READ(DISP0_CTRL); ++ ++ DSI_PORT_WRITE(STAT, DSI_PORT_BIT(STAT_ERR_CONT_LP1)); ++ if (!(disp0_ctrl & DSI_DISP0_ENABLE)) { ++ /* If video mode not enabled, then try recovering by ++ * enabling it briefly to clear FIFOs and the state. ++ */ ++ disp0_ctrl |= DSI_DISP0_ENABLE; ++ DSI_PORT_WRITE(DISP0_CTRL, disp0_ctrl); ++ msleep(30); ++ disp0_ctrl &= ~DSI_DISP0_ENABLE; ++ DSI_PORT_WRITE(DISP0_CTRL, disp0_ctrl); ++ msleep(30); ++ ++ ret = vc4_dsi_transfer(dsi, msg, true); ++ } else { ++ DRM_ERROR("DSI transfer failed whilst in HS mode stat: 0x%08x\n", ++ stat); ++ } ++ } ++ return ret; ++} ++ + static const struct component_ops vc4_dsi_ops; + static int vc4_dsi_host_attach(struct mipi_dsi_host *host, + struct mipi_dsi_device *device) diff --git a/target/linux/bcm27xx/patches-6.6/950-1273-drm-panel-ili9881-Add-option-to-reconfigure-setup-co.patch b/target/linux/bcm27xx/patches-6.6/950-1273-drm-panel-ili9881-Add-option-to-reconfigure-setup-co.patch new file mode 100644 index 000000000000..16329253b947 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1273-drm-panel-ili9881-Add-option-to-reconfigure-setup-co.patch @@ -0,0 +1,102 @@ +From d644270369cc6bf39012cce735dde6b86ad01424 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 18 Sep 2024 16:09:28 +0100 +Subject: [PATCH 1273/1350] drm: panel: ili9881: Add option to reconfigure + setup commands + +The driver is typically asking for LP commands, but then tries +to send set_display_[on|off] from enable/disable when the host +will be in HS mode. +It also sends shutdown commands just before it asserts reset and +disables the regulator, which is rather redundant. + +Add an option to configure these two choices from the panel_desc. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/panel/panel-ilitek-ili9881c.c | 32 ++++++++++++++++--- + 1 file changed, 28 insertions(+), 4 deletions(-) + +--- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c ++++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c +@@ -40,12 +40,19 @@ struct ili9881c_instr { + } arg; + }; + ++enum ili9881_desc_flags { ++ ILI9881_FLAGS_NO_SHUTDOWN_CMDS = BIT(0), ++ ILI9881_FLAGS_PANEL_ON_IN_PREPARE = BIT(1), ++ ILI9881_FLAGS_MAX = BIT(31), ++}; ++ + struct ili9881c_desc { + const struct ili9881c_instr *init; + const size_t init_length; + const struct drm_display_mode *mode; + const unsigned long mode_flags; + unsigned int lanes; ++ enum ili9881_desc_flags flags; + }; + + struct ili9881c { +@@ -1727,6 +1734,12 @@ static int ili9881c_prepare(struct drm_p + if (ret) + return ret; + ++ if (ctx->desc->flags & ILI9881_FLAGS_PANEL_ON_IN_PREPARE) { ++ msleep(120); ++ ++ ret = mipi_dsi_dcs_set_display_on(ctx->dsi); ++ } ++ + return 0; + } + +@@ -1734,9 +1747,11 @@ static int ili9881c_enable(struct drm_pa + { + struct ili9881c *ctx = panel_to_ili9881c(panel); + +- msleep(120); ++ if (!(ctx->desc->flags & ILI9881_FLAGS_PANEL_ON_IN_PREPARE)) { ++ msleep(120); + +- mipi_dsi_dcs_set_display_on(ctx->dsi); ++ mipi_dsi_dcs_set_display_on(ctx->dsi); ++ } + + return 0; + } +@@ -1745,7 +1760,8 @@ static int ili9881c_disable(struct drm_p + { + struct ili9881c *ctx = panel_to_ili9881c(panel); + +- mipi_dsi_dcs_set_display_off(ctx->dsi); ++ if (!(ctx->desc->flags & ILI9881_FLAGS_PANEL_ON_IN_PREPARE)) ++ mipi_dsi_dcs_set_display_off(ctx->dsi); + + return 0; + } +@@ -1754,7 +1770,13 @@ static int ili9881c_unprepare(struct drm + { + struct ili9881c *ctx = panel_to_ili9881c(panel); + +- mipi_dsi_dcs_enter_sleep_mode(ctx->dsi); ++ if (!(ctx->desc->flags & ILI9881_FLAGS_NO_SHUTDOWN_CMDS)) { ++ if (ctx->desc->flags & ILI9881_FLAGS_PANEL_ON_IN_PREPARE) ++ mipi_dsi_dcs_set_display_off(ctx->dsi); ++ ++ mipi_dsi_dcs_enter_sleep_mode(ctx->dsi); ++ } ++ + regulator_disable(ctx->power); + gpiod_set_value_cansleep(ctx->reset, 1); + +@@ -2066,6 +2088,8 @@ static const struct ili9881c_desc rpi_7i + .mode = &rpi_7inch_default_mode, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM, + .lanes = 2, ++ .flags = ILI9881_FLAGS_NO_SHUTDOWN_CMDS | ++ ILI9881_FLAGS_PANEL_ON_IN_PREPARE, + }; + + static const struct of_device_id ili9881c_of_match[] = { diff --git a/target/linux/bcm27xx/patches-6.6/950-1274-regulator-rpi-panel-Remove-the-ID-read.patch b/target/linux/bcm27xx/patches-6.6/950-1274-regulator-rpi-panel-Remove-the-ID-read.patch new file mode 100644 index 000000000000..8336b7ae1ae6 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1274-regulator-rpi-panel-Remove-the-ID-read.patch @@ -0,0 +1,90 @@ +From b510e5cbbf8b8e2da3198cf931452290629876b7 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 20 Sep 2024 18:32:11 +0100 +Subject: [PATCH 1274/1350] regulator/rpi-panel: Remove the ID read + +Reading from the Atmel has always been troublesome due to +clock stretching, and the driver does nothing with it anyway. + +Remove the read and assume that if the overlay has been +configured (most likely through the firmware autodetection) +that the hardware is present. + +Signed-off-by: Dave Stevenson +--- + .../regulator/rpi-panel-attiny-regulator.c | 50 ------------------- + 1 file changed, 50 deletions(-) + +--- a/drivers/regulator/rpi-panel-attiny-regulator.c ++++ b/drivers/regulator/rpi-panel-attiny-regulator.c +@@ -229,39 +229,6 @@ static void attiny_gpio_set(struct gpio_ + mutex_unlock(&state->lock); + } + +-static int attiny_i2c_read(struct i2c_client *client, u8 reg, unsigned int *buf) +-{ +- struct i2c_msg msgs[1]; +- u8 addr_buf[1] = { reg }; +- u8 data_buf[1] = { 0, }; +- int ret; +- +- /* Write register address */ +- msgs[0].addr = client->addr; +- msgs[0].flags = 0; +- msgs[0].len = ARRAY_SIZE(addr_buf); +- msgs[0].buf = addr_buf; +- +- ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); +- if (ret != ARRAY_SIZE(msgs)) +- return -EIO; +- +- usleep_range(5000, 10000); +- +- /* Read data from register */ +- msgs[0].addr = client->addr; +- msgs[0].flags = I2C_M_RD; +- msgs[0].len = 1; +- msgs[0].buf = data_buf; +- +- ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); +- if (ret != ARRAY_SIZE(msgs)) +- return -EIO; +- +- *buf = data_buf[0]; +- return 0; +-} +- + /* + * I2C driver interface functions + */ +@@ -273,7 +240,6 @@ static int attiny_i2c_probe(struct i2c_c + struct regulator_dev *rdev; + struct attiny_lcd *state; + struct regmap *regmap; +- unsigned int data; + int ret; + + state = devm_kzalloc(&i2c->dev, sizeof(*state), GFP_KERNEL); +@@ -291,22 +257,6 @@ static int attiny_i2c_probe(struct i2c_c + goto error; + } + +- ret = attiny_i2c_read(i2c, REG_ID, &data); +- if (ret < 0) { +- dev_err(&i2c->dev, "Failed to read REG_ID reg: %d\n", ret); +- goto error; +- } +- +- switch (data) { +- case 0xde: /* ver 1 */ +- case 0xc3: /* ver 2 */ +- break; +- default: +- dev_err(&i2c->dev, "Unknown Atmel firmware revision: 0x%02x\n", data); +- ret = -ENODEV; +- goto error; +- } +- + regmap_write(regmap, REG_POWERON, 0); + msleep(30); + regmap_write(regmap, REG_PWM, 0); diff --git a/target/linux/bcm27xx/patches-6.6/950-1275-drivers-mfd-sensehat-Add-Raspberry-Pi-Sense-HAT-to-s.patch b/target/linux/bcm27xx/patches-6.6/950-1275-drivers-mfd-sensehat-Add-Raspberry-Pi-Sense-HAT-to-s.patch new file mode 100644 index 000000000000..f89dfa8ffd42 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1275-drivers-mfd-sensehat-Add-Raspberry-Pi-Sense-HAT-to-s.patch @@ -0,0 +1,29 @@ +From 2f9fad762e8ed78aa4220d582b4d1856808f4a7a Mon Sep 17 00:00:00 2001 +From: Charles Mirabile +Date: Tue, 19 Apr 2022 16:51:53 -0400 +Subject: [PATCH 1275/1350] drivers/mfd: sensehat: Add Raspberry Pi Sense HAT + to simple_mfd_i2c + +This patch adds the compatible string for the Sense HAT device to +the list of compatible strings in the simple_mfd_i2c driver so that +it can match against the device and load its children and their drivers + +Co-developed-by: Mwesigwa Guma +Signed-off-by: Mwesigwa Guma +Co-developed-by: Joel Savitz +Signed-off-by: Joel Savitz +Signed-off-by: Charles Mirabile +--- + drivers/mfd/simple-mfd-i2c.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/mfd/simple-mfd-i2c.c ++++ b/drivers/mfd/simple-mfd-i2c.c +@@ -98,6 +98,7 @@ static const struct of_device_id simple_ + { .compatible = "maxim,max5970", .data = &maxim_max5970}, + { .compatible = "maxim,max5978", .data = &maxim_max5970}, + { .compatible = "raspberrypi,poe-core", &rpi_poe_core }, ++ { .compatible = "raspberrypi,sensehat" }, + {} + }; + MODULE_DEVICE_TABLE(of, simple_mfd_i2c_of_match); diff --git a/target/linux/bcm27xx/patches-6.6/950-1281-dtoverlays-Correct-pinctrl-assignment-on-mcp23017.patch b/target/linux/bcm27xx/patches-6.6/950-1281-dtoverlays-Correct-pinctrl-assignment-on-mcp23017.patch new file mode 100644 index 000000000000..ce0dd744a123 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1281-dtoverlays-Correct-pinctrl-assignment-on-mcp23017.patch @@ -0,0 +1,24 @@ +From 78518a36d7c87bafdbb06478e6b54be5df4b355b Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 23 Sep 2024 17:49:00 +0100 +Subject: [PATCH 1281/1350] dtoverlays: Correct pinctrl assignment on mcp23017 + +The pinctrl definition used "pinctrl-name" which is missing +an "s" from the end. + +Signed-off-by: Dave Stevenson +--- + arch/arm/boot/dts/overlays/mcp23017-overlay.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/overlays/mcp23017-overlay.dts ++++ b/arch/arm/boot/dts/overlays/mcp23017-overlay.dts +@@ -34,7 +34,7 @@ + target = <&mcp23017>; + mcp23017_irq: __overlay__ { + #interrupt-cells=<2>; +- pinctrl-name = "default"; ++ pinctrl-names = "default"; + pinctrl-0 = <&mcp23017_pins>; + interrupt-parent = <&gpio>; + interrupts = <4 2>; diff --git a/target/linux/bcm27xx/patches-6.6/950-1282-tty-serial-pl011-Also-unregister-pl011_axi_platform_.patch b/target/linux/bcm27xx/patches-6.6/950-1282-tty-serial-pl011-Also-unregister-pl011_axi_platform_.patch new file mode 100644 index 000000000000..3a5f9f15c38f --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1282-tty-serial-pl011-Also-unregister-pl011_axi_platform_.patch @@ -0,0 +1,22 @@ +From 0fb3c83a9fa3011cb735ec011b7582d4749957b2 Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Fri, 20 Sep 2024 12:21:27 +0100 +Subject: [PATCH 1282/1350] tty/serial: pl011: Also unregister + pl011_axi_platform_driver + +See: https://github.com/raspberrypi/linux/issues/6379 +Signed-off-by: Dom Cobley +--- + drivers/tty/serial/amba-pl011.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/tty/serial/amba-pl011.c ++++ b/drivers/tty/serial/amba-pl011.c +@@ -3122,6 +3122,7 @@ static int __init pl011_init(void) + static void __exit pl011_exit(void) + { + platform_driver_unregister(&arm_sbsa_uart_platform_driver); ++ platform_driver_unregister(&pl011_axi_platform_driver); + amba_driver_unregister(&pl011_driver); + } + diff --git a/target/linux/bcm27xx/patches-6.6/950-1283-overlays-wm8960-soundcard-Fix-clock-declaration.patch b/target/linux/bcm27xx/patches-6.6/950-1283-overlays-wm8960-soundcard-Fix-clock-declaration.patch new file mode 100644 index 000000000000..7a64d151c65f --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1283-overlays-wm8960-soundcard-Fix-clock-declaration.patch @@ -0,0 +1,62 @@ +From 409a0e2fd41da7a4b04672136aa7d749988faf61 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 25 Sep 2024 16:41:55 +0100 +Subject: [PATCH 1283/1350] overlays: wm8960-soundcard: Fix clock declaration + +How did this ever work? The static-clock declaration is fine, but the +reference to it is attached to part of the simple-audio-card node, +rather than the instantiation of the codec driver (a subnode of the +I2C controller). + +Move the clock reference where it should be, and fix a few minor +cosmetic issues at the same time. + +Signed-off-by: Phil Elwell +--- + .../arm/boot/dts/overlays/wm8960-soundcard-overlay.dts | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/arch/arm/boot/dts/overlays/wm8960-soundcard-overlay.dts ++++ b/arch/arm/boot/dts/overlays/wm8960-soundcard-overlay.dts +@@ -13,7 +13,7 @@ + }; + + fragment@1 { +- target-path="/"; ++ target-path = "/"; + __overlay__ { + wm8960_mclk: wm8960_mclk { + compatible = "fixed-clock"; +@@ -29,17 +29,18 @@ + #size-cells = <0>; + status = "okay"; + +- wm8960: wm8960 { ++ wm8960: wm8960@1a { + compatible = "wlf,wm8960"; + reg = <0x1a>; + #sound-dai-cells = <0>; + AVDD-supply = <&vdd_5v0_reg>; + DVDD-supply = <&vdd_3v3_reg>; ++ clocks = <&wm8960_mclk>; ++ clock-names = "mclk"; + }; + }; + }; + +- + fragment@3 { + target = <&sound>; + slave_overlay: __overlay__ { +@@ -67,10 +68,9 @@ + simple-audio-card,cpu { + sound-dai = <&i2s_clk_producer>; + }; ++ + dailink0_slave: simple-audio-card,codec { + sound-dai = <&wm8960>; +- clocks = <&wm8960_mclk>; +- clock-names = "mclk"; + }; + }; + }; diff --git a/target/linux/bcm27xx/patches-6.6/950-1284-googlevoicehat-Fix-playback-muting-when-recording-is.patch b/target/linux/bcm27xx/patches-6.6/950-1284-googlevoicehat-Fix-playback-muting-when-recording-is.patch new file mode 100644 index 000000000000..3ecccd622ec3 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1284-googlevoicehat-Fix-playback-muting-when-recording-is.patch @@ -0,0 +1,44 @@ +From d52d2bd85ad4d1cfc37a87a6b7bfcc37207c6025 Mon Sep 17 00:00:00 2001 +From: Ali Tekin <140681099+alitekin-saha@users.noreply.github.com> +Date: Thu, 26 Sep 2024 10:51:13 +0300 +Subject: [PATCH 1284/1350] googlevoicehat: Fix playback muting when recording + is stopped + +Fixed audio amplifier control logic in the voicehat trigger function +Resolves improper handling of the SDMODE pin, which caused issues when the microphone and speaker were used simultaneously. The playback stream check is now correctly based on `substream->stream == SNDRV_PCM_STREAM_PLAYBACK`, ensuring proper control of the audio amplifier. + +Signed-off-by: Ali Tekin +--- + sound/soc/bcm/googlevoicehat-codec.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +--- a/sound/soc/bcm/googlevoicehat-codec.c ++++ b/sound/soc/bcm/googlevoicehat-codec.c +@@ -95,8 +95,7 @@ static int voicehat_daiops_trigger(struc + struct snd_soc_dai *dai) + { + struct snd_soc_component *component = dai->component; +- struct voicehat_priv *voicehat = +- snd_soc_component_get_drvdata(component); ++ struct voicehat_priv *voicehat = snd_soc_component_get_drvdata(component); + + if (voicehat->sdmode_delay_jiffies == 0) + return 0; +@@ -109,7 +108,7 @@ static int voicehat_daiops_trigger(struc + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: +- if (dai->stream[SNDRV_PCM_STREAM_PLAYBACK].active) { ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + dev_info(dai->dev, "Enabling audio amp...\n"); + queue_delayed_work( + system_power_efficient_wq, +@@ -120,7 +119,7 @@ static int voicehat_daiops_trigger(struc + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: +- if (dai->stream[SNDRV_PCM_STREAM_PLAYBACK].active) { ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + cancel_delayed_work(&voicehat->enable_sdmode_work); + dev_info(dai->dev, "Disabling audio amp...\n"); + gpiod_set_value(voicehat->sdmode_gpio, 0); diff --git a/target/linux/bcm27xx/patches-6.6/950-1285-ASoC-bcm2835-i2s-Set-the-PERIOD_BYTES-min-to-256.patch b/target/linux/bcm27xx/patches-6.6/950-1285-ASoC-bcm2835-i2s-Set-the-PERIOD_BYTES-min-to-256.patch new file mode 100644 index 000000000000..5f148f4af3ae --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1285-ASoC-bcm2835-i2s-Set-the-PERIOD_BYTES-min-to-256.patch @@ -0,0 +1,48 @@ +From a382d82b99a078f2ce65e78df9ba6db0d01c8ca3 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 24 Sep 2024 20:34:54 +0100 +Subject: [PATCH 1285/1350] ASoC: bcm2835-i2s: Set the PERIOD_BYTES min to 256 + +Commit [1] set the minimum PERIOD_BYTES value to the product of the DMA +burst size and 8. For the I2S interface on BCM2835 that equates to 16 +where it used to be 256. ffmpeg uses the minimum value as its preferred +value, leading to many, many very small periods, which affects +performance and leads to complaints about DTS timestamps. + +Restore the previous behaviour and performance by making the bcm2835-i2s +driver set a minimum PERIOD_BYTES value of 256. + +Link: https://github.com/raspberrypi/linux/issues/5709 + +[1] 300689fb04b3 ("ASoC: soc-generic-dmaengine-pcm: set +period_bytes_min based on maxburst") + +Signed-off-by: Phil Elwell +--- + sound/soc/bcm/bcm2835-i2s.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/sound/soc/bcm/bcm2835-i2s.c ++++ b/sound/soc/bcm/bcm2835-i2s.c +@@ -619,6 +619,10 @@ static int bcm2835_i2s_prepare(struct sn + struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); + uint32_t cs_reg; + ++ snd_pcm_hw_constraint_minmax(substream->runtime, ++ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 256, ++ ~0); ++ + /* + * Clear both FIFOs if the one that should be started + * is not empty at the moment. This should only happen +@@ -700,6 +704,10 @@ static int bcm2835_i2s_startup(struct sn + /* Should this still be running stop it */ + bcm2835_i2s_stop_clock(dev); + ++ snd_pcm_hw_constraint_minmax(substream->runtime, ++ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, ++ 256, ~0); ++ + /* Enable PCM block */ + regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, + BCM2835_I2S_EN, BCM2835_I2S_EN); diff --git a/target/linux/bcm27xx/patches-6.6/950-1286-clk-clk-rp1-Don-t-crash-on-duplicate-clocks.patch b/target/linux/bcm27xx/patches-6.6/950-1286-clk-clk-rp1-Don-t-crash-on-duplicate-clocks.patch new file mode 100644 index 000000000000..88a8774da040 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1286-clk-clk-rp1-Don-t-crash-on-duplicate-clocks.patch @@ -0,0 +1,30 @@ +From d290bef1f99e24cd590c64db149d007c6a631b65 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 16 Sep 2024 11:48:08 +0100 +Subject: [PATCH 1286/1350] clk: clk-rp1: Don't crash on duplicate clocks + +When using DTBs that don't match the kernel version, it's possible for +clock registration to fail. Handle that failure, in the hope that the +system can continue to boot, with a suitable error message. + +Link: https://github.com/raspberrypi/linux/issues/6321 + +Signed-off-by: Phil Elwell +--- + drivers/clk/clk-rp1.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/clk/clk-rp1.c ++++ b/drivers/clk/clk-rp1.c +@@ -2454,6 +2454,11 @@ static int rp1_clk_probe(struct platform + desc = &clk_desc_array[i]; + if (desc->clk_register && desc->data) { + hws[i] = desc->clk_register(clockman, desc->data); ++ if (IS_ERR_OR_NULL(hws[i])) { ++ pr_err("Failed to register RP1 clock '%s' (%ld) - wrong dtbs?\n", *(char **)desc->data, PTR_ERR(hws[i])); ++ hws[i] = NULL; ++ continue; ++ } + if (!strcmp(clk_hw_get_name(hws[i]), "clk_i2s")) { + clk_i2s = hws[i]; + clk_xosc = clk_hw_get_parent_by_index(clk_i2s, 0); diff --git a/target/linux/bcm27xx/patches-6.6/950-1287-drivers-media-imx500-Simplify-the-vblank-control-ini.patch b/target/linux/bcm27xx/patches-6.6/950-1287-drivers-media-imx500-Simplify-the-vblank-control-ini.patch new file mode 100644 index 000000000000..b4bb7d87da4f --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1287-drivers-media-imx500-Simplify-the-vblank-control-ini.patch @@ -0,0 +1,98 @@ +From 0094eba3f2a4338cfa6854b0b5104d02ba0fa01f Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Thu, 26 Sep 2024 13:12:23 +0100 +Subject: [PATCH 1287/1350] drivers: media: imx500: Simplify the vblank control + init + +Set the VBLANK control minimum and default values to IMX500_VBLANK_MIN +unconditionally everywhere. + +Remove the mode specific framerate_default parameter, it is now unused. + +Signed-off-by: Naushir Patuck +--- + drivers/media/i2c/imx500.c | 32 +++++--------------------------- + 1 file changed, 5 insertions(+), 27 deletions(-) + +--- a/drivers/media/i2c/imx500.c ++++ b/drivers/media/i2c/imx500.c +@@ -274,9 +274,6 @@ struct imx500_mode { + /* Analog crop rectangle. */ + struct v4l2_rect crop; + +- /* Default framerate. */ +- unsigned int framerate_default; +- + /* Default register values */ + struct imx500_reg_list reg_list; + }; +@@ -905,7 +902,6 @@ static const struct imx500_mode imx500_s + .width = 4056, + .height = 3040, + }, +- .framerate_default = 10, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_4056x3040_regs), + .regs = mode_4056x3040_regs, +@@ -922,7 +918,6 @@ static const struct imx500_mode imx500_s + .width = 4056, + .height = 3040, + }, +- .framerate_default = 30, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_2028x1520_regs), + .regs = mode_2028x1520_regs, +@@ -1744,28 +1739,11 @@ static int imx500_get_pad_format(struct + return 0; + } + +-static unsigned int imx500_get_frame_length(const struct imx500_mode *mode, +- unsigned int framerate_default) +-{ +- u64 frame_length; +- +- frame_length = IMX500_PIXEL_RATE; +- do_div(frame_length, (u64)framerate_default * mode->line_length_pix); +- +- if (WARN_ON(frame_length > IMX500_FRAME_LENGTH_MAX)) +- frame_length = IMX500_FRAME_LENGTH_MAX; +- +- return max_t(unsigned int, frame_length, mode->height); +-} +- + static void imx500_set_framing_limits(struct imx500 *imx500) + { +- unsigned int frm_length_default, hblank_min; ++ unsigned int hblank_min; + const struct imx500_mode *mode = imx500->mode; + +- frm_length_default = +- imx500_get_frame_length(mode, mode->framerate_default); +- + /* Default to no long exposure multiplier. */ + imx500->long_exp_shift = 0; + +@@ -1773,11 +1751,10 @@ static void imx500_set_framing_limits(st + __v4l2_ctrl_modify_range( + imx500->vblank, IMX500_VBLANK_MIN, + ((1 << IMX500_LONG_EXP_SHIFT_MAX) * IMX500_FRAME_LENGTH_MAX) - +- mode->height, +- 1, frm_length_default - mode->height); ++ mode->height, 1, IMX500_VBLANK_MIN); + + /* Setting this will adjust the exposure limits as well. */ +- __v4l2_ctrl_s_ctrl(imx500->vblank, frm_length_default - mode->height); ++ __v4l2_ctrl_s_ctrl(imx500->vblank, IMX500_VBLANK_MIN); + + hblank_min = mode->line_length_pix - mode->width; + __v4l2_ctrl_modify_range(imx500->hblank, hblank_min, hblank_min, 1, +@@ -2499,7 +2476,8 @@ static int imx500_init_controls(struct i + * in the imx500_set_framing_limits() call below. + */ + imx500->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx500_ctrl_ops, +- V4L2_CID_VBLANK, 0, 0xffff, 1, 0); ++ V4L2_CID_VBLANK, IMX500_VBLANK_MIN, ++ 0xffff, 1, IMX500_VBLANK_MIN); + imx500->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx500_ctrl_ops, + V4L2_CID_HBLANK, 0, 0xffff, 1, 0); + diff --git a/target/linux/bcm27xx/patches-6.6/950-1288-dts-overlay_map-ramoops-pi4-works-on-Pi-5.patch b/target/linux/bcm27xx/patches-6.6/950-1288-dts-overlay_map-ramoops-pi4-works-on-Pi-5.patch new file mode 100644 index 000000000000..43011bae3967 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1288-dts-overlay_map-ramoops-pi4-works-on-Pi-5.patch @@ -0,0 +1,28 @@ +From 9557336c4fc4ac4606ac9e78c239aa689c26e870 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 26 Sep 2024 17:46:25 +0100 +Subject: [PATCH 1288/1350] dts: overlay_map: ramoops-pi4 works on Pi 5 + +Add the necessary overlay_map entries so that ramoops-pi4 is loaded +with dtoverlay=ramoops on Pi 5. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/overlay_map.dts | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/arch/arm/boot/dts/overlays/overlay_map.dts ++++ b/arch/arm/boot/dts/overlays/overlay_map.dts +@@ -247,10 +247,12 @@ + ramoops { + bcm2835; + bcm2711 = "ramoops-pi4"; ++ bcm2712 = "ramoops-pi4"; + }; + + ramoops-pi4 { + bcm2711; ++ bcm2712; + }; + + rpi-cirrus-wm5102 { diff --git a/target/linux/bcm27xx/patches-6.6/950-1289-dts-align-PCI-BAR-allocation-on-bcm2711-and-bcm2712-.patch b/target/linux/bcm27xx/patches-6.6/950-1289-dts-align-PCI-BAR-allocation-on-bcm2711-and-bcm2712-.patch new file mode 100644 index 000000000000..c54f221a4fdc --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1289-dts-align-PCI-BAR-allocation-on-bcm2711-and-bcm2712-.patch @@ -0,0 +1,109 @@ +From 2b5de12af9bb390239d5f3385c49e0c34f335de8 Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Fri, 27 Sep 2024 10:59:02 +0100 +Subject: [PATCH 1289/1350] dts: align PCI BAR allocation on bcm2711 and + bcm2712 to start at 2GB + +Fold the Pi 5 mmio-hi compatibility option into the base DTB, and +shuffle the single MMIO window on bcm2711 to match. + +Certain devices cannot handle low addresses, e.g. by failing to +enumerate or failing to route the traffic appropriately. + +Link: https://github.com/raspberrypi/linux/issues/6134 +Link: https://github.com/raspberrypi/linux/issues/6278 + +Signed-off-by: Jonathan Bell +--- + .../arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi | 6 +++--- + arch/arm/boot/dts/overlays/README | 2 -- + .../overlays/pciex1-compat-pi5-overlay.dts | 20 ------------------- + arch/arm64/boot/dts/broadcom/bcm2712.dtsi | 10 ++++++---- + 4 files changed, 9 insertions(+), 29 deletions(-) + +--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi ++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi +@@ -123,7 +123,7 @@ + + ranges = <0x0 0x7c000000 0x0 0xfc000000 0x0 0x03800000>, + <0x0 0x40000000 0x0 0xff800000 0x0 0x00800000>, +- <0x6 0x00000000 0x6 0x00000000 0x0 0x40000000>, ++ <0x6 0x00000000 0x6 0x00000000 0x0 0x80000000>, + <0x0 0x00000000 0x0 0x00000000 0x0 0xfc000000>; + dma-ranges = <0x4 0x7c000000 0x0 0xfc000000 0x0 0x03800000>, + <0x0 0x00000000 0x0 0x00000000 0x4 0x00000000>; +@@ -167,8 +167,8 @@ + + &pcie0 { + reg = <0x0 0x7d500000 0x0 0x9310>; +- ranges = <0x02000000 0x0 0xc0000000 0x6 0x00000000 +- 0x0 0x40000000>; ++ ranges = <0x02000000 0x0 0x80000000 0x6 0x00000000 ++ 0x0 0x80000000>; + }; + + &genet { +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -3617,8 +3617,6 @@ Params: l1ss Enable A + the MSI-MIP peripheral. Use if a) more than 8 + interrupt vectors are required or b) the EP + requires DMA and MSI addresses to be 32bit. +- mmio-hi Move the start of outbound 32bit addresses to +- 2GB and expand 64bit outbound space to 14GB. + + + [ The pcf2127-rtc overlay has been deleted. See i2c-rtc. ] +--- a/arch/arm/boot/dts/overlays/pciex1-compat-pi5-overlay.dts ++++ b/arch/arm/boot/dts/overlays/pciex1-compat-pi5-overlay.dts +@@ -32,29 +32,9 @@ + }; + }; + +- /* +- * Shift the start of the 32bit outbound window to 2GB, +- * so there are no BARs starting at 0x0. Expand the 64bit +- * outbound window to use the spare 2GB. +- */ +- fragment@3 { +- target = <&pciex1>; +- __dormant__ { +- #address-cells = <3>; +- #size-cells = <2>; +- ranges = <0x02000000 0x00 0x80000000 +- 0x1b 0x80000000 +- 0x00 0x7ffffffc>, +- <0x43000000 0x04 0x00000000 +- 0x18 0x00000000 +- 0x03 0x80000000>; +- }; +- }; +- + __overrides__ { + l1ss = <0>, "+0"; + no-l0s = <0>, "+1"; + no-mip = <0>, "+2"; +- mmio-hi = <0>, "+3"; + }; + }; +--- a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi ++++ b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi +@@ -1052,12 +1052,14 @@ + msi-controller; + msi-parent = <&mip1>; + +- ranges = <0x02000000 0x00 0x00000000 +- 0x1b 0x00000000 +- 0x00 0xfffffffc>, ++ // 2GB, 32-bit, non-prefetchable at PCIe 00_80000000 ++ ranges = <0x02000000 0x00 0x80000000 ++ 0x1b 0x80000000 ++ 0x00 0x80000000>, ++ // 14GB, 64-bit, prefetchable at PCIe 04_00000000 + <0x43000000 0x04 0x00000000 + 0x18 0x00000000 +- 0x03 0x00000000>; ++ 0x03 0x80000000>; + + dma-ranges = <0x03000000 0x10 0x00000000 + 0x00 0x00000000 diff --git a/target/linux/bcm27xx/patches-6.6/950-1290-overlays-Add-Pineboards-HatDrive-POE-6257.patch b/target/linux/bcm27xx/patches-6.6/950-1290-overlays-Add-Pineboards-HatDrive-POE-6257.patch new file mode 100644 index 000000000000..583602d0e0c1 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1290-overlays-Add-Pineboards-HatDrive-POE-6257.patch @@ -0,0 +1,61 @@ +From 35b3f98bb2bfb80a718c52ba49c167da6c78d2ea Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Micha=C5=82=20Gapi=C5=84ski?= + +Date: Mon, 30 Sep 2024 16:47:20 +0200 +Subject: [PATCH 1290/1350] overlays: Add Pineboards HatDrive! POE+ (#6257) + +overlays: Add Pineboards HatDrive! POE+ +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 6 ++++++ + .../pineboards-hatdrive-poe-plus-overlay.dts | 19 +++++++++++++++++++ + 3 files changed, 26 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/pineboards-hatdrive-poe-plus-overlay.dts + +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -204,6 +204,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + pifi-mini-210.dtbo \ + piglow.dtbo \ + pineboards-hat-ai.dtbo \ ++ pineboards-hatdrive-poe-plus.dtbo \ + piscreen.dtbo \ + piscreen2r.dtbo \ + pisound.dtbo \ +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -3703,6 +3703,12 @@ Load: dtoverlay=pineboards-hat-ai + Params: + + ++Name: pineboards-hatdrive-poe-plus ++Info: Configures the Pineboards HatDrive! PoE+ ++Load: dtoverlay=pineboards-hatdrive-poe-plus ++Params: ++ ++ + Name: piscreen + Info: PiScreen display by OzzMaker.com + Load: dtoverlay=piscreen,= +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/pineboards-hatdrive-poe-plus-overlay.dts +@@ -0,0 +1,19 @@ ++/* ++ * Device Tree overlay for Pineboards HatDrive! PoE+. ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target-path = "/chosen"; ++ __overlay__ { ++ power: power { ++ hat_current_supply = <5000>; ++ }; ++ }; ++ }; ++}; diff --git a/target/linux/bcm27xx/patches-6.6/950-1296-dtoverlays-Correct-vc4-kms-dpi-generic-for-width-hei.patch b/target/linux/bcm27xx/patches-6.6/950-1296-dtoverlays-Correct-vc4-kms-dpi-generic-for-width-hei.patch new file mode 100644 index 000000000000..f56147c8f7ef --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1296-dtoverlays-Correct-vc4-kms-dpi-generic-for-width-hei.patch @@ -0,0 +1,31 @@ +From 50a6e5cf28a24e7f4192ad6f70f472eca2097cc6 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 2 Oct 2024 16:36:45 +0100 +Subject: [PATCH 1296/1350] dtoverlays: Correct vc4-kms-dpi-generic for + [width|height]-mm + +These two overrides were updating the &panel node from +vc4-kms-dpi.dtsi, when fragment0 from the vc4-kms-dpi-generic +was also updating the same node. Application order meant that +the override value was overwritten. + +Correct the target. + +Signed-off-by: Dave Stevenson +--- + arch/arm/boot/dts/overlays/vc4-kms-dpi-generic-overlay.dts | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/arch/arm/boot/dts/overlays/vc4-kms-dpi-generic-overlay.dts ++++ b/arch/arm/boot/dts/overlays/vc4-kms-dpi-generic-overlay.dts +@@ -60,8 +60,8 @@ + de-invert = <&timing>, "de-active:0=0"; + pixclk-invert = <&timing>, "pixelclk-active:0=0"; + +- width-mm = <&panel>, "width-mm:0"; +- height-mm = <&panel>, "height-mm:0"; ++ width-mm = <&panel_generic>, "width-mm:0"; ++ height-mm = <&panel_generic>, "height-mm:0"; + + rgb565 = <&panel_generic>, "bus-format:0=0x1017", + <&dpi_node_generic>, "pinctrl-0:0=",<&dpi_16bit_gpio0>; diff --git a/target/linux/bcm27xx/patches-6.6/950-1297-dts-bcm2712-rpi-Add-four-missing-GPIOs-to-2712D0.patch b/target/linux/bcm27xx/patches-6.6/950-1297-dts-bcm2712-rpi-Add-four-missing-GPIOs-to-2712D0.patch new file mode 100644 index 000000000000..2ccd898f847a --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1297-dts-bcm2712-rpi-Add-four-missing-GPIOs-to-2712D0.patch @@ -0,0 +1,32 @@ +From e044f6af1b2b41bc2212551b4fd6353469cb7263 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 12 Sep 2024 16:29:57 +0100 +Subject: [PATCH 1297/1350] dts: bcm2712-rpi: Add four missing GPIOs to 2712D0 + +It's useful for gpioinfo and pinctrl to distinguish between unused and +absent GPIOs. We use "-" for the former and "" for the latter. +With this convention, gpioinfo shows absent GPIOs as "unnamed", while +pinctrl omits them altogether. + +Signed-off-by: Phil Elwell +--- + arch/arm64/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/arch/arm64/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts ++++ b/arch/arm64/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts +@@ -15,10 +15,10 @@ + "", // GPIO_007 + "", // GPIO_008 + "", // GPIO_009 +- "", // GPIO_010 +- "", // GPIO_011 +- "", // GPIO_012 +- "", // GPIO_013 ++ "-", // GPIO_010 ++ "-", // GPIO_011 ++ "-", // GPIO_012 ++ "-", // GPIO_013 + "PCIE_SDA", // GPIO_014 + "PCIE_SCL", // GPIO_015 + "", // GPIO_016 diff --git a/target/linux/bcm27xx/patches-6.6/950-1298-arm64-dts-Add-preliminary-bcm2712-rpi-500-dts.patch b/target/linux/bcm27xx/patches-6.6/950-1298-arm64-dts-Add-preliminary-bcm2712-rpi-500-dts.patch new file mode 100644 index 000000000000..6d961a760ee9 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1298-arm64-dts-Add-preliminary-bcm2712-rpi-500-dts.patch @@ -0,0 +1,169 @@ +From 3be1a52ad9e3ae7b0e16eb20c77d9df60e29f139 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 10 Sep 2024 14:07:16 +0100 +Subject: [PATCH 1298/1350] arm64: dts: Add preliminary bcm2712-rpi-500 dts + +Add the first DTS file for Pi 500. + +Signed-off-by: Phil Elwell +--- + arch/arm64/boot/dts/broadcom/Makefile | 1 + + .../boot/dts/broadcom/bcm2712-rpi-500.dts | 142 ++++++++++++++++++ + 2 files changed, 143 insertions(+) + create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-500.dts + +--- a/arch/arm64/boot/dts/broadcom/Makefile ++++ b/arch/arm64/boot/dts/broadcom/Makefile +@@ -22,6 +22,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rp + dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-cm4s.dtb + dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-5-b.dtb + dtb-$(CONFIG_ARCH_BCM2835) += bcm2712d0-rpi-5-b.dtb ++dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-500.dtb + dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-cm5-cm5io.dtb + dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-cm5-cm4io.dtb + dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-cm5l-cm5io.dtb +--- /dev/null ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-500.dts +@@ -0,0 +1,142 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include "bcm2712d0-rpi-5-b.dts" ++ ++/ { ++ compatible = "raspberrypi,500", "brcm,bcm2712"; ++ model = "Raspberry Pi 500"; ++}; ++ ++&pwr_key { ++ debounce-interval = <400>; ++}; ++ ++&gio { ++ gpio-line-names = ++ "", // GPIO_000 ++ "2712_BOOT_CS_N", // GPIO_001 ++ "2712_BOOT_MISO", // GPIO_002 ++ "2712_BOOT_MOSI", // GPIO_003 ++ "2712_BOOT_SCLK", // GPIO_004 ++ "", // GPIO_005 ++ "", // GPIO_006 ++ "", // GPIO_007 ++ "", // GPIO_008 ++ "", // GPIO_009 ++ "-", // GPIO_010 ++ "-", // GPIO_011 ++ "-", // GPIO_012 ++ "-", // GPIO_013 ++ "M2_DET_WAKE", // GPIO_014 ++ "M2_PWR_EN", // GPIO_015 ++ "", // GPIO_016 ++ "", // GPIO_017 ++ "KEYB_BOOTSEL", // GPIO_018 ++ "-", // GPIO_019 ++ "PWR_GPIO", // GPIO_020 ++ "KEYB_RUN", // GPIO_021 ++ "-", // GPIO_022 ++ "-", // GPIO_023 ++ "BT_RTS", // GPIO_024 ++ "BT_CTS", // GPIO_025 ++ "BT_TXD", // GPIO_026 ++ "BT_RXD", // GPIO_027 ++ "WL_ON", // GPIO_028 ++ "BT_ON", // GPIO_029 ++ "WIFI_SDIO_CLK", // GPIO_030 ++ "WIFI_SDIO_CMD", // GPIO_031 ++ "WIFI_SDIO_D0", // GPIO_032 ++ "WIFI_SDIO_D1", // GPIO_033 ++ "WIFI_SDIO_D2", // GPIO_034 ++ "WIFI_SDIO_D3"; // GPIO_035 ++}; ++ ++&gio_aon { ++ gpio-line-names = ++ "RP1_SDA", // AON_GPIO_00 ++ "RP1_SCL", // AON_GPIO_01 ++ "RP1_RUN", // AON_GPIO_02 ++ "SD_IOVDD_SEL", // AON_GPIO_03 ++ "SD_PWR_ON", // AON_GPIO_04 ++ "SD_CDET_N", // AON_GPIO_05 ++ "SD_FLG_N", // AON_GPIO_06 ++ "", // AON_GPIO_07 ++ "2712_WAKE", // AON_GPIO_08 ++ "2712_STAT_LED", // AON_GPIO_09 ++ "", // AON_GPIO_10 ++ "", // AON_GPIO_11 ++ "PMIC_INT", // AON_GPIO_12 ++ "UART_TX_FS", // AON_GPIO_13 ++ "UART_RX_FS", // AON_GPIO_14 ++ "", // AON_GPIO_15 ++ "", // AON_GPIO_16 ++ ++ // Pad bank0 out to 32 entries ++ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ++ ++ "HDMI0_SCL", // AON_SGPIO_00 ++ "HDMI0_SDA", // AON_SGPIO_01 ++ "HDMI1_SCL", // AON_SGPIO_02 ++ "HDMI1_SDA", // AON_SGPIO_03 ++ "PMIC_SCL", // AON_SGPIO_04 ++ "PMIC_SDA"; // AON_SGPIO_05 ++}; ++ ++&rp1_gpio { ++ gpio-line-names = ++ "ID_SDA", // GPIO0 ++ "ID_SCL", // GPIO1 ++ "GPIO2", // GPIO2 ++ "GPIO3", // GPIO3 ++ "GPIO4", // GPIO4 ++ "GPIO5", // GPIO5 ++ "GPIO6", // GPIO6 ++ "GPIO7", // GPIO7 ++ "GPIO8", // GPIO8 ++ "GPIO9", // GPIO9 ++ "GPIO10", // GPIO10 ++ "GPIO11", // GPIO11 ++ "GPIO12", // GPIO12 ++ "GPIO13", // GPIO13 ++ "GPIO14", // GPIO14 ++ "GPIO15", // GPIO15 ++ "GPIO16", // GPIO16 ++ "GPIO17", // GPIO17 ++ "GPIO18", // GPIO18 ++ "GPIO19", // GPIO19 ++ "GPIO20", // GPIO20 ++ "GPIO21", // GPIO21 ++ "GPIO22", // GPIO22 ++ "GPIO23", // GPIO23 ++ "GPIO24", // GPIO24 ++ "GPIO25", // GPIO25 ++ "GPIO26", // GPIO26 ++ "GPIO27", // GPIO27 ++ ++ "PCIE_RP1_WAKE", // GPIO28 ++ "-", // GPIO29 ++ "HOST_SDA", // GPIO30 ++ "HOST_SCL", // GPIO31 ++ "ETH_RST_N", // GPIO32 ++ "PCIE_DET_WAKE", // GPIO33 ++ ++ "-", // GPIO34 ++ "-", // GPIO35 ++ "RP1_PCIE_CLKREQ_N", // GPIO36 ++ "-", // GPIO37 ++ "-", // GPIO38 ++ "-", // GPIO39 ++ "CD1_SDA", // GPIO40 ++ "CD1_SCL", // GPIO41 ++ "USB_VBUS_EN", // GPIO42 ++ "USB_OC_N", // GPIO43 ++ "RP1_STAT_LED", // GPIO44 ++ "-", // GPIO45 ++ "-", // GPIO46 ++ "HOST_WAKE", // GPIO47 ++ "-", // GPIO48 ++ "EN_MAX_USB_CUR", // GPIO49 ++ "-", // GPIO50 ++ "-", // GPIO51 ++ "-", // GPIO52 ++ "-"; // GPIO53 ++}; diff --git a/target/linux/bcm27xx/patches-6.6/950-1301-dts-2712-Reduce-default-cma-usage-on-Pi5.patch b/target/linux/bcm27xx/patches-6.6/950-1301-dts-2712-Reduce-default-cma-usage-on-Pi5.patch new file mode 100644 index 000000000000..bb26a8934564 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1301-dts-2712-Reduce-default-cma-usage-on-Pi5.patch @@ -0,0 +1,30 @@ +From 3edaa3875fbeb0b2effd77c62baabf2933efc6ef Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Fri, 13 Sep 2024 17:23:58 +0100 +Subject: [PATCH 1301/1350] dts: 2712: Reduce default cma usage on Pi5 + +Significant cma shouldn't really be needed on Pi5 as the hardware +blocks support iommu and can access system memory. + +We've migrated codec and camera support to system memory, and 3d +has always (even on Pi4) used system memory. + +A large cma block causes issues with enabling NUMA on a low +memory (2G) Pi5, as cma cannot span numa regions. + +Signed-off-by: Dom Cobley +--- + arch/arm/boot/dts/overlays/vc4-kms-v3d-pi5-overlay.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-pi5-overlay.dts ++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-pi5-overlay.dts +@@ -3,7 +3,7 @@ + #include "cma-overlay.dts" + + &frag0 { +- size = <((320-4)*1024*1024)>; ++ size = <(64*1024*1024)>; + }; + + / { diff --git a/target/linux/bcm27xx/patches-6.6/950-1305-dts-bcm2712d0-Add-non-d0-vc6-compatible-string.patch b/target/linux/bcm27xx/patches-6.6/950-1305-dts-bcm2712d0-Add-non-d0-vc6-compatible-string.patch new file mode 100644 index 000000000000..4660c8f43576 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1305-dts-bcm2712d0-Add-non-d0-vc6-compatible-string.patch @@ -0,0 +1,39 @@ +From d69bca1f0425be1a42f7ad1e3cff5313ba7c122a Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 9 Oct 2024 15:13:14 +0100 +Subject: [PATCH 1305/1350] dts: bcm2712d0: Add non-d0 vc6 compatible string + +Although the VC4/VC6 driver requires a special compatible string for the +"d0" stepping, the removal of the old compatible string upsets Mesa. + +Satisfy both requirements by adding the old "brcm,bcm2712-vc6" string +as a fallback. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/bcm2712d0-overlay.dts | 2 +- + arch/arm64/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/arch/arm/boot/dts/overlays/bcm2712d0-overlay.dts ++++ b/arch/arm/boot/dts/overlays/bcm2712d0-overlay.dts +@@ -41,7 +41,7 @@ + fragment@4 { + target = <&vc4>; + __overlay__ { +- compatible = "brcm,bcm2712d0-vc6"; ++ compatible = "brcm,bcm2712d0-vc6", "brcm,bcm2712-vc6"; + }; + }; + +--- a/arch/arm64/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts ++++ b/arch/arm64/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts +@@ -87,7 +87,7 @@ + }; + + &vc4 { +- compatible = "brcm,bcm2712d0-vc6"; ++ compatible = "brcm,bcm2712d0-vc6", "brcm,bcm2712-vc6"; + }; + + &uart10 { diff --git a/target/linux/bcm27xx/patches-6.6/950-1312-Reapply-dtoverlays-Convert-SenseHAT-overlays-to-use-.patch b/target/linux/bcm27xx/patches-6.6/950-1312-Reapply-dtoverlays-Convert-SenseHAT-overlays-to-use-.patch new file mode 100644 index 000000000000..9501067d68f8 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1312-Reapply-dtoverlays-Convert-SenseHAT-overlays-to-use-.patch @@ -0,0 +1,100 @@ +From 9a86952570b925e68dfd30a12642000353242745 Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Thu, 10 Oct 2024 17:16:08 +0100 +Subject: [PATCH 1312/1350] Reapply "dtoverlays: Convert SenseHAT overlays to + use MFD and upstream drivers" + +This reverts commit 82a50e430ef1d6eb37d78e25aa572c1f6ea56160. +--- + .../boot/dts/overlays/rpi-sense-overlay.dts | 28 +++++++++++++++++-- + .../dts/overlays/rpi-sense-v2-overlay.dts | 28 +++++++++++++++++-- + 2 files changed, 50 insertions(+), 6 deletions(-) + +--- a/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts ++++ b/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts +@@ -12,11 +12,23 @@ + #size-cells = <0>; + status = "okay"; + +- rpi-sense@46 { +- compatible = "rpi,rpi-sense"; ++ sensehat@46 { ++ compatible = "raspberrypi,sensehat"; + reg = <0x46>; +- keys-int-gpios = <&gpio 23 1>; ++ interrupt-parent = <&gpio>; + status = "okay"; ++ ++ display { ++ compatible = "raspberrypi,rpi-sense-fb"; ++ status = "okay"; ++ }; ++ joystick { ++ compatible = "raspberrypi,sensehat-joystick"; ++ interrupts = <23 1>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sensehat_pins>; ++ status = "okay"; ++ }; + }; + + lsm9ds1-magn@1c { +@@ -44,4 +56,14 @@ + }; + }; + }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ sensehat_pins: sensehat_pins { ++ brcm,pins = <23>; ++ brcm,function = <0>; ++ }; ++ }; ++ }; + }; +--- a/arch/arm/boot/dts/overlays/rpi-sense-v2-overlay.dts ++++ b/arch/arm/boot/dts/overlays/rpi-sense-v2-overlay.dts +@@ -12,11 +12,23 @@ + #size-cells = <0>; + status = "okay"; + +- rpi-sense@46 { +- compatible = "rpi,rpi-sense"; ++ sensehat@46 { ++ compatible = "raspberrypi,sensehat"; + reg = <0x46>; +- keys-int-gpios = <&gpio 23 1>; ++ interrupt-parent = <&gpio>; + status = "okay"; ++ ++ display { ++ compatible = "raspberrypi,rpi-sense-fb"; ++ status = "okay"; ++ }; ++ joystick { ++ compatible = "raspberrypi,sensehat-joystick"; ++ interrupts = <23 1>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sensehat_pins>; ++ status = "okay"; ++ }; + }; + + lsm9ds1-magn@1c { +@@ -44,4 +56,14 @@ + }; + }; + }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ sensehat_pins: sensehat_pins { ++ brcm,pins = <23>; ++ brcm,function = <0>; ++ }; ++ }; ++ }; + }; diff --git a/target/linux/bcm27xx/patches-6.6/950-1313-Reapply-drivers-Remove-downstream-SenseHAT-core-and-.patch b/target/linux/bcm27xx/patches-6.6/950-1313-Reapply-drivers-Remove-downstream-SenseHAT-core-and-.patch new file mode 100644 index 000000000000..714123d3ded3 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1313-Reapply-drivers-Remove-downstream-SenseHAT-core-and-.patch @@ -0,0 +1,608 @@ +From 9fb57f6b8920a8aceb74ceb3e171a7e5769205a5 Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Thu, 10 Oct 2024 17:18:39 +0100 +Subject: [PATCH 1313/1350] Reapply "drivers: Remove downstream SenseHAT core + and joystick drivers" + +This reverts commit e6493e2d6a1f572fbb4a1d724e54715cb748b424. +--- + drivers/input/joystick/Kconfig | 8 -- + drivers/input/joystick/Makefile | 1 - + drivers/input/joystick/rpisense-js.c | 153 --------------------- + drivers/mfd/Kconfig | 8 -- + drivers/mfd/Makefile | 1 - + drivers/mfd/rpisense-core.c | 163 ----------------------- + drivers/video/fbdev/Kconfig | 4 +- + drivers/video/fbdev/rpisense-fb.c | 53 ++++---- + include/linux/mfd/rpisense/core.h | 47 ------- + include/linux/mfd/rpisense/framebuffer.h | 5 +- + 10 files changed, 32 insertions(+), 411 deletions(-) + delete mode 100644 drivers/input/joystick/rpisense-js.c + delete mode 100644 drivers/mfd/rpisense-core.c + delete mode 100644 include/linux/mfd/rpisense/core.h + +--- a/drivers/input/joystick/Kconfig ++++ b/drivers/input/joystick/Kconfig +@@ -412,12 +412,4 @@ config JOYSTICK_SENSEHAT + To compile this driver as a module, choose M here: the + module will be called sensehat_joystick. + +-config JOYSTICK_RPISENSE +- tristate "Raspberry Pi Sense HAT joystick" +- depends on GPIOLIB && INPUT +- select MFD_RPISENSE_CORE +- +- help +- This is the joystick driver for the Raspberry Pi Sense HAT +- + endif +--- a/drivers/input/joystick/Makefile ++++ b/drivers/input/joystick/Makefile +@@ -40,4 +40,3 @@ obj-$(CONFIG_JOYSTICK_WARRIOR) += warri + obj-$(CONFIG_JOYSTICK_WALKERA0701) += walkera0701.o + obj-$(CONFIG_JOYSTICK_XPAD) += xpad.o + obj-$(CONFIG_JOYSTICK_ZHENHUA) += zhenhua.o +-obj-$(CONFIG_JOYSTICK_RPISENSE) += rpisense-js.o +--- a/drivers/input/joystick/rpisense-js.c ++++ /dev/null +@@ -1,153 +0,0 @@ +-/* +- * Raspberry Pi Sense HAT joystick driver +- * http://raspberrypi.org +- * +- * Copyright (C) 2015 Raspberry Pi +- * +- * Author: Serge Schneider +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License as published by the +- * Free Software Foundation; either version 2 of the License, or (at your +- * option) any later version. +- * +- */ +- +-#include +- +-#include +-#include +- +-static struct rpisense *rpisense; +-static unsigned char keymap[5] = {KEY_DOWN, KEY_RIGHT, KEY_UP, KEY_ENTER, KEY_LEFT,}; +- +-static void keys_work_fn(struct work_struct *work) +-{ +- int i; +- static s32 prev_keys; +- struct rpisense_js *rpisense_js = &rpisense->joystick; +- s32 keys = rpisense_reg_read(rpisense, RPISENSE_KEYS); +- s32 changes = keys ^ prev_keys; +- +- prev_keys = keys; +- for (i = 0; i < 5; i++) { +- if (changes & 1) { +- input_report_key(rpisense_js->keys_dev, +- keymap[i], keys & 1); +- } +- changes >>= 1; +- keys >>= 1; +- } +- input_sync(rpisense_js->keys_dev); +-} +- +-static irqreturn_t keys_irq_handler(int irq, void *pdev) +-{ +- struct rpisense_js *rpisense_js = &rpisense->joystick; +- +- schedule_work(&rpisense_js->keys_work_s); +- return IRQ_HANDLED; +-} +- +-static int rpisense_js_probe(struct platform_device *pdev) +-{ +- int ret; +- int i; +- struct rpisense_js *rpisense_js; +- +- rpisense = rpisense_get_dev(); +- rpisense_js = &rpisense->joystick; +- +- INIT_WORK(&rpisense_js->keys_work_s, keys_work_fn); +- +- rpisense_js->keys_dev = input_allocate_device(); +- if (!rpisense_js->keys_dev) { +- dev_err(&pdev->dev, "Could not allocate input device.\n"); +- return -ENOMEM; +- } +- +- rpisense_js->keys_dev->evbit[0] = BIT_MASK(EV_KEY); +- for (i = 0; i < ARRAY_SIZE(keymap); i++) { +- set_bit(keymap[i], +- rpisense_js->keys_dev->keybit); +- } +- +- rpisense_js->keys_dev->name = "Raspberry Pi Sense HAT Joystick"; +- rpisense_js->keys_dev->phys = "rpi-sense-joy/input0"; +- rpisense_js->keys_dev->id.bustype = BUS_I2C; +- rpisense_js->keys_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); +- rpisense_js->keys_dev->keycode = keymap; +- rpisense_js->keys_dev->keycodesize = sizeof(unsigned char); +- rpisense_js->keys_dev->keycodemax = ARRAY_SIZE(keymap); +- +- ret = input_register_device(rpisense_js->keys_dev); +- if (ret) { +- dev_err(&pdev->dev, "Could not register input device.\n"); +- goto err_keys_alloc; +- } +- +- ret = gpiod_direction_input(rpisense_js->keys_desc); +- if (ret) { +- dev_err(&pdev->dev, "Could not set keys-int direction.\n"); +- goto err_keys_reg; +- } +- +- rpisense_js->keys_irq = gpiod_to_irq(rpisense_js->keys_desc); +- if (rpisense_js->keys_irq < 0) { +- dev_err(&pdev->dev, "Could not determine keys-int IRQ.\n"); +- ret = rpisense_js->keys_irq; +- goto err_keys_reg; +- } +- +- ret = devm_request_irq(&pdev->dev, rpisense_js->keys_irq, +- keys_irq_handler, IRQF_TRIGGER_RISING, +- "keys", &pdev->dev); +- if (ret) { +- dev_err(&pdev->dev, "IRQ request failed.\n"); +- goto err_keys_reg; +- } +- return 0; +-err_keys_reg: +- input_unregister_device(rpisense_js->keys_dev); +-err_keys_alloc: +- input_free_device(rpisense_js->keys_dev); +- return ret; +-} +- +-static int rpisense_js_remove(struct platform_device *pdev) +-{ +- struct rpisense_js *rpisense_js = &rpisense->joystick; +- +- input_unregister_device(rpisense_js->keys_dev); +- input_free_device(rpisense_js->keys_dev); +- return 0; +-} +- +-#ifdef CONFIG_OF +-static const struct of_device_id rpisense_js_id[] = { +- { .compatible = "rpi,rpi-sense-js" }, +- { }, +-}; +-MODULE_DEVICE_TABLE(of, rpisense_js_id); +-#endif +- +-static struct platform_device_id rpisense_js_device_id[] = { +- { .name = "rpi-sense-js" }, +- { }, +-}; +-MODULE_DEVICE_TABLE(platform, rpisense_js_device_id); +- +-static struct platform_driver rpisense_js_driver = { +- .probe = rpisense_js_probe, +- .remove = rpisense_js_remove, +- .driver = { +- .name = "rpi-sense-js", +- .owner = THIS_MODULE, +- }, +-}; +- +-module_platform_driver(rpisense_js_driver); +- +-MODULE_DESCRIPTION("Raspberry Pi Sense HAT joystick driver"); +-MODULE_AUTHOR("Serge Schneider "); +-MODULE_LICENSE("GPL"); +--- a/drivers/mfd/Kconfig ++++ b/drivers/mfd/Kconfig +@@ -11,14 +11,6 @@ config MFD_CORE + select IRQ_DOMAIN + default n + +-config MFD_RPISENSE_CORE +- tristate "Raspberry Pi Sense HAT core functions" +- depends on I2C +- select MFD_CORE +- help +- This is the core driver for the Raspberry Pi Sense HAT. This provides +- the necessary functions to communicate with the hardware. +- + config MFD_CS5535 + tristate "AMD CS5535 and CS5536 southbridge core functions" + select MFD_CORE +--- a/drivers/mfd/Makefile ++++ b/drivers/mfd/Makefile +@@ -268,7 +268,6 @@ obj-$(CONFIG_MFD_STMFX) += stmfx.o + obj-$(CONFIG_MFD_KHADAS_MCU) += khadas-mcu.o + obj-$(CONFIG_MFD_ACER_A500_EC) += acer-ec-a500.o + obj-$(CONFIG_MFD_QCOM_PM8008) += qcom-pm8008.o +-obj-$(CONFIG_MFD_RPISENSE_CORE) += rpisense-core.o + + obj-$(CONFIG_SGI_MFD_IOC3) += ioc3.o + obj-$(CONFIG_MFD_SIMPLE_MFD_I2C) += simple-mfd-i2c.o +--- a/drivers/mfd/rpisense-core.c ++++ /dev/null +@@ -1,163 +0,0 @@ +-/* +- * Raspberry Pi Sense HAT core driver +- * http://raspberrypi.org +- * +- * Copyright (C) 2015 Raspberry Pi +- * +- * Author: Serge Schneider +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License as published by the +- * Free Software Foundation; either version 2 of the License, or (at your +- * option) any later version. +- * +- * This driver is based on wm8350 implementation. +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-static struct rpisense *rpisense; +- +-static void rpisense_client_dev_register(struct rpisense *rpisense, +- const char *name, +- struct platform_device **pdev) +-{ +- int ret; +- +- *pdev = platform_device_alloc(name, -1); +- if (*pdev == NULL) { +- dev_err(rpisense->dev, "Failed to allocate %s\n", name); +- return; +- } +- +- (*pdev)->dev.parent = rpisense->dev; +- platform_set_drvdata(*pdev, rpisense); +- ret = platform_device_add(*pdev); +- if (ret != 0) { +- dev_err(rpisense->dev, "Failed to register %s: %d\n", +- name, ret); +- platform_device_put(*pdev); +- *pdev = NULL; +- } +-} +- +-static int rpisense_probe(struct i2c_client *i2c) +-{ +- int ret; +- struct rpisense_js *rpisense_js; +- +- rpisense = devm_kzalloc(&i2c->dev, sizeof(struct rpisense), GFP_KERNEL); +- if (rpisense == NULL) +- return -ENOMEM; +- +- i2c_set_clientdata(i2c, rpisense); +- rpisense->dev = &i2c->dev; +- rpisense->i2c_client = i2c; +- +- ret = rpisense_reg_read(rpisense, RPISENSE_WAI); +- if (ret > 0) { +- if (ret != 's') +- return -EINVAL; +- } else { +- return ret; +- } +- ret = rpisense_reg_read(rpisense, RPISENSE_VER); +- if (ret < 0) +- return ret; +- +- dev_info(rpisense->dev, +- "Raspberry Pi Sense HAT firmware version %i\n", ret); +- +- rpisense_js = &rpisense->joystick; +- rpisense_js->keys_desc = devm_gpiod_get(&i2c->dev, +- "keys-int", GPIOD_IN); +- if (IS_ERR(rpisense_js->keys_desc)) { +- dev_warn(&i2c->dev, "Failed to get keys-int descriptor.\n"); +- rpisense_js->keys_desc = gpio_to_desc(23); +- if (rpisense_js->keys_desc == NULL) { +- dev_err(&i2c->dev, "GPIO23 fallback failed.\n"); +- return PTR_ERR(rpisense_js->keys_desc); +- } +- } +- rpisense_client_dev_register(rpisense, "rpi-sense-js", +- &(rpisense->joystick.pdev)); +- rpisense_client_dev_register(rpisense, "rpi-sense-fb", +- &(rpisense->framebuffer.pdev)); +- +- return 0; +-} +- +-static void rpisense_remove(struct i2c_client *i2c) +-{ +- struct rpisense *rpisense = i2c_get_clientdata(i2c); +- +- platform_device_unregister(rpisense->joystick.pdev); +-} +- +-struct rpisense *rpisense_get_dev(void) +-{ +- return rpisense; +-} +-EXPORT_SYMBOL_GPL(rpisense_get_dev); +- +-s32 rpisense_reg_read(struct rpisense *rpisense, int reg) +-{ +- int ret = i2c_smbus_read_byte_data(rpisense->i2c_client, reg); +- +- if (ret < 0) +- dev_err(rpisense->dev, "Read from reg %d failed\n", reg); +- /* Due to the BCM270x I2C clock stretching bug, some values +- * may have MSB set. Clear it to avoid incorrect values. +- * */ +- return ret & 0x7F; +-} +-EXPORT_SYMBOL_GPL(rpisense_reg_read); +- +-int rpisense_block_write(struct rpisense *rpisense, const char *buf, int count) +-{ +- int ret = i2c_master_send(rpisense->i2c_client, buf, count); +- +- if (ret < 0) +- dev_err(rpisense->dev, "Block write failed\n"); +- return ret; +-} +-EXPORT_SYMBOL_GPL(rpisense_block_write); +- +-static const struct i2c_device_id rpisense_i2c_id[] = { +- { "rpi-sense", 0 }, +- { } +-}; +-MODULE_DEVICE_TABLE(i2c, rpisense_i2c_id); +- +-#ifdef CONFIG_OF +-static const struct of_device_id rpisense_core_id[] = { +- { .compatible = "rpi,rpi-sense" }, +- { }, +-}; +-MODULE_DEVICE_TABLE(of, rpisense_core_id); +-#endif +- +- +-static struct i2c_driver rpisense_driver = { +- .driver = { +- .name = "rpi-sense", +- .owner = THIS_MODULE, +- }, +- .probe = rpisense_probe, +- .remove = rpisense_remove, +- .id_table = rpisense_i2c_id, +-}; +- +-module_i2c_driver(rpisense_driver); +- +-MODULE_DESCRIPTION("Raspberry Pi Sense HAT core driver"); +-MODULE_AUTHOR("Serge Schneider "); +-MODULE_LICENSE("GPL"); +- +--- a/drivers/video/fbdev/Kconfig ++++ b/drivers/video/fbdev/Kconfig +@@ -1967,8 +1967,8 @@ config FB_SM712 + + config FB_RPISENSE + tristate "Raspberry Pi Sense HAT framebuffer" +- depends on FB +- select MFD_RPISENSE_CORE ++ depends on FB && I2C ++ select MFD_SIMPLE_MFD_I2C + select FB_SYS_FOPS + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA +--- a/drivers/video/fbdev/rpisense-fb.c ++++ b/drivers/video/fbdev/rpisense-fb.c +@@ -23,16 +23,14 @@ + #include + #include + #include ++#include + + #include +-#include + + static bool lowlight; + module_param(lowlight, bool, 0); + MODULE_PARM_DESC(lowlight, "Reduce LED matrix brightness to one third"); + +-static struct rpisense *rpisense; +- + struct rpisense_fb_param { + char __iomem *vmem; + u8 *vmem_work; +@@ -116,26 +114,26 @@ static void rpisense_fb_imageblit(struct + } + + static void rpisense_fb_deferred_io(struct fb_info *info, +- struct list_head *pagelist) ++ struct list_head *pagelist) + { + int i; + int j; + u8 *vmem_work = rpisense_fb_param.vmem_work; + u16 *mem = (u16 *)rpisense_fb_param.vmem; + u8 *gamma = rpisense_fb_param.gamma; ++ struct rpisense_fb *rpisense_fb = info->par; + +- vmem_work[0] = 0; + for (j = 0; j < 8; j++) { + for (i = 0; i < 8; i++) { +- vmem_work[(j * 24) + i + 1] = ++ vmem_work[(j * 24) + i] = + gamma[(mem[(j * 8) + i] >> 11) & 0x1F]; +- vmem_work[(j * 24) + (i + 8) + 1] = ++ vmem_work[(j * 24) + (i + 8)] = + gamma[(mem[(j * 8) + i] >> 6) & 0x1F]; +- vmem_work[(j * 24) + (i + 16) + 1] = ++ vmem_work[(j * 24) + (i + 16)] = + gamma[(mem[(j * 8) + i]) & 0x1F]; + } + } +- rpisense_block_write(rpisense, vmem_work, 193); ++ regmap_bulk_write(rpisense_fb->regmap, 0, vmem_work, 192); + } + + static struct fb_deferred_io rpisense_fb_defio = { +@@ -200,8 +198,22 @@ static int rpisense_fb_probe(struct plat + int ret = -ENOMEM; + struct rpisense_fb *rpisense_fb; + +- rpisense = rpisense_get_dev(); +- rpisense_fb = &rpisense->framebuffer; ++ info = framebuffer_alloc(sizeof(*rpisense_fb), &pdev->dev); ++ if (!info) { ++ dev_err(&pdev->dev, "Could not allocate framebuffer.\n"); ++ goto err_malloc; ++ } ++ ++ rpisense_fb = info->par; ++ platform_set_drvdata(pdev, rpisense_fb); ++ ++ rpisense_fb->pdev = pdev; ++ rpisense_fb->regmap = dev_get_regmap(pdev->dev.parent, NULL); ++ if (!rpisense_fb->regmap) { ++ dev_err(&pdev->dev, ++ "unable to get sensehat regmap"); ++ return -ENODEV; ++ } + + rpisense_fb_param.vmem = vzalloc(rpisense_fb_param.vmemsize); + if (!rpisense_fb_param.vmem) +@@ -211,12 +223,6 @@ static int rpisense_fb_probe(struct plat + if (!rpisense_fb_param.vmem_work) + goto err_malloc; + +- info = framebuffer_alloc(0, &pdev->dev); +- if (!info) { +- dev_err(&pdev->dev, "Could not allocate framebuffer.\n"); +- goto err_malloc; +- } +- rpisense_fb->info = info; + + rpisense_fb_fix.smem_start = (unsigned long)rpisense_fb_param.vmem; + rpisense_fb_fix.smem_len = rpisense_fb_param.vmemsize; +@@ -253,7 +259,7 @@ err_malloc: + + static int rpisense_fb_remove(struct platform_device *pdev) + { +- struct rpisense_fb *rpisense_fb = &rpisense->framebuffer; ++ struct rpisense_fb *rpisense_fb = platform_get_drvdata(pdev); + struct fb_info *info = rpisense_fb->info; + + if (info) { +@@ -266,19 +272,11 @@ static int rpisense_fb_remove(struct pla + return 0; + } + +-#ifdef CONFIG_OF + static const struct of_device_id rpisense_fb_id[] = { +- { .compatible = "rpi,rpi-sense-fb" }, ++ { .compatible = "raspberrypi,rpi-sense-fb" }, + { }, + }; + MODULE_DEVICE_TABLE(of, rpisense_fb_id); +-#endif +- +-static struct platform_device_id rpisense_fb_device_id[] = { +- { .name = "rpi-sense-fb" }, +- { }, +-}; +-MODULE_DEVICE_TABLE(platform, rpisense_fb_device_id); + + static struct platform_driver rpisense_fb_driver = { + .probe = rpisense_fb_probe, +@@ -286,6 +284,7 @@ static struct platform_driver rpisense_f + .driver = { + .name = "rpi-sense-fb", + .owner = THIS_MODULE, ++ .of_match_table = rpisense_fb_id, + }, + }; + +--- a/include/linux/mfd/rpisense/core.h ++++ /dev/null +@@ -1,47 +0,0 @@ +-/* +- * Raspberry Pi Sense HAT core driver +- * http://raspberrypi.org +- * +- * Copyright (C) 2015 Raspberry Pi +- * +- * Author: Serge Schneider +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License as published by the +- * Free Software Foundation; either version 2 of the License, or (at your +- * option) any later version. +- * +- */ +- +-#ifndef __LINUX_MFD_RPISENSE_CORE_H_ +-#define __LINUX_MFD_RPISENSE_CORE_H_ +- +-#include +-#include +- +-/* +- * Register values. +- */ +-#define RPISENSE_FB 0x00 +-#define RPISENSE_WAI 0xF0 +-#define RPISENSE_VER 0xF1 +-#define RPISENSE_KEYS 0xF2 +-#define RPISENSE_EE_WP 0xF3 +- +-#define RPISENSE_ID 's' +- +-struct rpisense { +- struct device *dev; +- struct i2c_client *i2c_client; +- +- /* Client devices */ +- struct rpisense_js joystick; +- struct rpisense_fb framebuffer; +-}; +- +-struct rpisense *rpisense_get_dev(void); +-s32 rpisense_reg_read(struct rpisense *rpisense, int reg); +-int rpisense_reg_write(struct rpisense *rpisense, int reg, u16 val); +-int rpisense_block_write(struct rpisense *rpisense, const char *buf, int count); +- +-#endif +--- a/include/linux/mfd/rpisense/framebuffer.h ++++ b/include/linux/mfd/rpisense/framebuffer.h +@@ -16,6 +16,8 @@ + #ifndef __LINUX_RPISENSE_FB_H_ + #define __LINUX_RPISENSE_FB_H_ + ++#include ++ + #define SENSEFB_FBIO_IOC_MAGIC 0xF1 + + #define SENSEFB_FBIOGET_GAMMA _IO(SENSEFB_FBIO_IOC_MAGIC, 0) +@@ -25,8 +27,9 @@ + struct rpisense; + + struct rpisense_fb { +- struct platform_device *pdev; + struct fb_info *info; ++ struct platform_device *pdev; ++ struct regmap *regmap; + }; + + #endif diff --git a/target/linux/bcm27xx/patches-6.6/950-1315-Reapply-Input-sensehat-joystick-Revert-to-downstream.patch b/target/linux/bcm27xx/patches-6.6/950-1315-Reapply-Input-sensehat-joystick-Revert-to-downstream.patch new file mode 100644 index 000000000000..87d84a9fac39 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1315-Reapply-Input-sensehat-joystick-Revert-to-downstream.patch @@ -0,0 +1,22 @@ +From 3a7ab92b9be0f8849941ed66049b9c3744cbd5aa Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Thu, 10 Oct 2024 17:18:57 +0100 +Subject: [PATCH 1315/1350] Reapply "Input: sensehat-joystick : Revert to + downstream keymap" + +This reverts commit bdb00151ff537c119cea7125e665a9bee1f76c58. +--- + drivers/input/joystick/sensehat-joystick.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/input/joystick/sensehat-joystick.c ++++ b/drivers/input/joystick/sensehat-joystick.c +@@ -28,7 +28,7 @@ struct sensehat_joystick { + }; + + static const unsigned int keymap[] = { +- BTN_DPAD_DOWN, BTN_DPAD_RIGHT, BTN_DPAD_UP, BTN_SELECT, BTN_DPAD_LEFT, ++ KEY_DOWN, KEY_RIGHT, KEY_UP, KEY_ENTER, KEY_LEFT + }; + + static irqreturn_t sensehat_joystick_report(int irq, void *cookie) diff --git a/target/linux/bcm27xx/patches-6.6/950-1316-Reapply-dtoverlays-Add-Sense-Hat-to-hat_map.patch b/target/linux/bcm27xx/patches-6.6/950-1316-Reapply-dtoverlays-Add-Sense-Hat-to-hat_map.patch new file mode 100644 index 000000000000..c4a2ee2ecea6 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1316-Reapply-dtoverlays-Add-Sense-Hat-to-hat_map.patch @@ -0,0 +1,27 @@ +From 2132f8aad4e978a9789a84f667567ce2bc93cb3c Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Thu, 10 Oct 2024 17:19:06 +0100 +Subject: [PATCH 1316/1350] Reapply "dtoverlays: Add Sense Hat to hat_map" + +This reverts commit 14fc8b7994220e9b3d85c07b53c5704d5e082944. +--- + arch/arm/boot/dts/overlays/hat_map.dts | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/arch/arm/boot/dts/overlays/hat_map.dts ++++ b/arch/arm/boot/dts/overlays/hat_map.dts +@@ -95,4 +95,14 @@ + uuid = [ 1c955808 681f 4bbc a2ef b7ea47cd388e ]; + overlay = "recalboxrgbdual"; + }; ++ ++ sensehat-v1 { ++ uuid = [ 5d960035 8e87 428f 95d8 59852d697754 ]; ++ overlay = "rpi-sense"; ++ }; ++ ++ sensehat-v2 { ++ uuid = [ 1aa9c428 72eb 48da 9306 8c3706ed3653 ]; ++ overlay = "rpi-sense-v2"; ++ }; + }; diff --git a/target/linux/bcm27xx/patches-6.6/950-1317-overlays-hat_map-Add-Sense-and-Hailo-AI-HATs.patch b/target/linux/bcm27xx/patches-6.6/950-1317-overlays-hat_map-Add-Sense-and-Hailo-AI-HATs.patch new file mode 100644 index 000000000000..041447eaaacf --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1317-overlays-hat_map-Add-Sense-and-Hailo-AI-HATs.patch @@ -0,0 +1,54 @@ +From e53eefbc711622f0702e887f88d69f867aa0bf1a Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 1 Oct 2024 12:14:57 +0100 +Subject: [PATCH 1317/1350] overlays: hat_map: Add Sense and Hailo AI HATs + +Add mappings to overlays for the Sense HATs and the Hailo AI HATs. Note +that mapping by product names (and not UUIDs) as used here requires an +updated firmware. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/hat_map.dts | 20 ++++++++++++++++++-- + 1 file changed, 18 insertions(+), 2 deletions(-) + +--- a/arch/arm/boot/dts/overlays/hat_map.dts ++++ b/arch/arm/boot/dts/overlays/hat_map.dts +@@ -1,6 +1,18 @@ + /dts-v1/; + + / { ++ hailo-8 { ++ product = "Raspberry Pi AI Hat, Model Hailo-8"; ++ vendor = "Hailo Technologies"; ++ overlay = "none,pciex1,pciex1_gen=3"; ++ }; ++ ++ hailo-8l { ++ product = "Raspberry Pi AI Hat, Model Hailo-8L"; ++ vendor = "Hailo Technologies"; ++ overlay = "none,pciex1,pciex1_gen=3"; ++ }; ++ + hifiberry-amp100-1 { + uuid = [ 5eb863b8 12f9 41ad 978f 4cee1b3eca62 ]; + overlay = "hifiberry-amp100"; +@@ -97,12 +109,16 @@ + }; + + sensehat-v1 { +- uuid = [ 5d960035 8e87 428f 95d8 59852d697754 ]; ++ product = "Sense HAT"; ++ vendor = "Raspberry Pi"; ++ pver = < 0x0001 >; + overlay = "rpi-sense"; + }; + + sensehat-v2 { +- uuid = [ 1aa9c428 72eb 48da 9306 8c3706ed3653 ]; ++ product = "Sense HAT"; ++ vendor = "Raspberry Pi"; ++ pver = < 0x0002 >; + overlay = "rpi-sense-v2"; + }; + }; diff --git a/target/linux/bcm27xx/patches-6.6/950-1318-drivers-media-imx500-Enable-LS-correction.patch b/target/linux/bcm27xx/patches-6.6/950-1318-drivers-media-imx500-Enable-LS-correction.patch new file mode 100644 index 000000000000..6d3233c80b2b --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1318-drivers-media-imx500-Enable-LS-correction.patch @@ -0,0 +1,408 @@ +From e2cafea49115af21f84e315e228121ec10dd4cb3 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Fri, 11 Oct 2024 12:32:46 +0100 +Subject: [PATCH 1318/1350] drivers: media: imx500: Enable LS correction + +This correction is calibrated to approx 5000K. + +Signed-off-by: Naushir Patuck +--- + drivers/media/i2c/imx500.c | 387 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 387 insertions(+) + +--- a/drivers/media/i2c/imx500.c ++++ b/drivers/media/i2c/imx500.c +@@ -887,6 +887,393 @@ static const struct cci_reg_sequence dnn + { CCI_REG32(0xd950), 0xfb00f7 }, + { CCI_REG16(0xd954), 0xff }, + { CCI_REG8(0xd826), 1 }, ++ /* LSC */ ++ { CCI_REG32(0xe000), 0x2e502a0 }, ++ { CCI_REG32(0xe004), 0x2c80283 }, ++ { CCI_REG32(0xe008), 0x2700233 }, ++ { CCI_REG32(0xe00c), 0x22d01f6 }, ++ { CCI_REG32(0xe010), 0x1f401c3 }, ++ { CCI_REG32(0xe014), 0x1c5019c }, ++ { CCI_REG32(0xe018), 0x1bb0192 }, ++ { CCI_REG32(0xe01c), 0x1ba0192 }, ++ { CCI_REG32(0xe020), 0x1b90192 }, ++ { CCI_REG32(0xe024), 0x1ba0192 }, ++ { CCI_REG32(0xe028), 0x1ca019f }, ++ { CCI_REG32(0xe02c), 0x1fb01c8 }, ++ { CCI_REG32(0xe030), 0x23601fb }, ++ { CCI_REG32(0xe034), 0x27a0239 }, ++ { CCI_REG32(0xe038), 0x2d5028a }, ++ { CCI_REG32(0xe03c), 0x2f302a8 }, ++ { CCI_REG32(0xe040), 0x2c60283 }, ++ { CCI_REG32(0xe044), 0x27c0240 }, ++ { CCI_REG32(0xe048), 0x22d01f6 }, ++ { CCI_REG32(0xe04c), 0x1fd01cd }, ++ { CCI_REG32(0xe050), 0x1c4019c }, ++ { CCI_REG32(0xe054), 0x19c017b }, ++ { CCI_REG32(0xe058), 0x1810165 }, ++ { CCI_REG32(0xe05c), 0x175015c }, ++ { CCI_REG32(0xe060), 0x175015c }, ++ { CCI_REG32(0xe064), 0x1840167 }, ++ { CCI_REG32(0xe068), 0x1a0017e }, ++ { CCI_REG32(0xe06c), 0x1cc01a1 }, ++ { CCI_REG32(0xe070), 0x20501d1 }, ++ { CCI_REG32(0xe074), 0x23601fc }, ++ { CCI_REG32(0xe078), 0x2890246 }, ++ { CCI_REG32(0xe07c), 0x2d3028a }, ++ { CCI_REG32(0xe080), 0x2800243 }, ++ { CCI_REG32(0xe084), 0x245020e }, ++ { CCI_REG32(0xe088), 0x1ff01ce }, ++ { CCI_REG32(0xe08c), 0x1c4019c }, ++ { CCI_REG32(0xe090), 0x19a017b }, ++ { CCI_REG32(0xe094), 0x1650150 }, ++ { CCI_REG32(0xe098), 0x14a013a }, ++ { CCI_REG32(0xe09c), 0x13f0131 }, ++ { CCI_REG32(0xe0a0), 0x1400131 }, ++ { CCI_REG32(0xe0a4), 0x14d013c }, ++ { CCI_REG32(0xe0a8), 0x16a0154 }, ++ { CCI_REG32(0xe0ac), 0x1a1017e }, ++ { CCI_REG32(0xe0b0), 0x1cc01a1 }, ++ { CCI_REG32(0xe0b4), 0x20801d3 }, ++ { CCI_REG32(0xe0b8), 0x2510214 }, ++ { CCI_REG32(0xe0bc), 0x28b0249 }, ++ { CCI_REG32(0xe0c0), 0x2640229 }, ++ { CCI_REG32(0xe0c4), 0x22101ed }, ++ { CCI_REG32(0xe0c8), 0x1dc01b0 }, ++ { CCI_REG32(0xe0cc), 0x19c017c }, ++ { CCI_REG32(0xe0d0), 0x1650150 }, ++ { CCI_REG32(0xe0d4), 0x148013a }, ++ { CCI_REG32(0xe0d8), 0x123011c }, ++ { CCI_REG32(0xe0dc), 0x1190113 }, ++ { CCI_REG32(0xe0e0), 0x1190113 }, ++ { CCI_REG32(0xe0e4), 0x1280120 }, ++ { CCI_REG32(0xe0e8), 0x14c013c }, ++ { CCI_REG32(0xe0ec), 0x16b0154 }, ++ { CCI_REG32(0xe0f0), 0x1a30181 }, ++ { CCI_REG32(0xe0f4), 0x1e601b6 }, ++ { CCI_REG32(0xe0f8), 0x22c01f3 }, ++ { CCI_REG32(0xe0fc), 0x2700230 }, ++ { CCI_REG32(0xe100), 0x257021d }, ++ { CCI_REG32(0xe104), 0x20901d8 }, ++ { CCI_REG32(0xe108), 0x1c4019d }, ++ { CCI_REG32(0xe10c), 0x1820167 }, ++ { CCI_REG32(0xe110), 0x14b013b }, ++ { CCI_REG32(0xe114), 0x124011c }, ++ { CCI_REG32(0xe118), 0x1170113 }, ++ { CCI_REG32(0xe11c), 0x1010101 }, ++ { CCI_REG32(0xe120), 0x1030102 }, ++ { CCI_REG32(0xe124), 0x1190113 }, ++ { CCI_REG32(0xe128), 0x1280120 }, ++ { CCI_REG32(0xe12c), 0x14f013f }, ++ { CCI_REG32(0xe130), 0x189016c }, ++ { CCI_REG32(0xe134), 0x1ce01a3 }, ++ { CCI_REG32(0xe138), 0x21601df }, ++ { CCI_REG32(0xe13c), 0x2630224 }, ++ { CCI_REG32(0xe140), 0x257021d }, ++ { CCI_REG32(0xe144), 0x20101d0 }, ++ { CCI_REG32(0xe148), 0x1ba0194 }, ++ { CCI_REG32(0xe14c), 0x176015d }, ++ { CCI_REG32(0xe150), 0x13e0132 }, ++ { CCI_REG32(0xe154), 0x1190114 }, ++ { CCI_REG32(0xe158), 0x1010101 }, ++ { CCI_REG32(0xe15c), 0x1000100 }, ++ { CCI_REG32(0xe160), 0x1010100 }, ++ { CCI_REG32(0xe164), 0x1040103 }, ++ { CCI_REG32(0xe168), 0x11d0118 }, ++ { CCI_REG32(0xe16c), 0x1450136 }, ++ { CCI_REG32(0xe170), 0x17d0163 }, ++ { CCI_REG32(0xe174), 0x1c4019a }, ++ { CCI_REG32(0xe178), 0x20d01d6 }, ++ { CCI_REG32(0xe17c), 0x2630224 }, ++ { CCI_REG32(0xe180), 0x257021d }, ++ { CCI_REG32(0xe184), 0x20001d0 }, ++ { CCI_REG32(0xe188), 0x1b90194 }, ++ { CCI_REG32(0xe18c), 0x175015d }, ++ { CCI_REG32(0xe190), 0x13e0132 }, ++ { CCI_REG32(0xe194), 0x1180114 }, ++ { CCI_REG32(0xe198), 0x1040103 }, ++ { CCI_REG32(0xe19c), 0x1000100 }, ++ { CCI_REG32(0xe1a0), 0x1030102 }, ++ { CCI_REG32(0xe1a4), 0x1050103 }, ++ { CCI_REG32(0xe1a8), 0x11d0118 }, ++ { CCI_REG32(0xe1ac), 0x1450136 }, ++ { CCI_REG32(0xe1b0), 0x17d0163 }, ++ { CCI_REG32(0xe1b4), 0x1c4019a }, ++ { CCI_REG32(0xe1b8), 0x20d01d6 }, ++ { CCI_REG32(0xe1bc), 0x2640224 }, ++ { CCI_REG32(0xe1c0), 0x258021f }, ++ { CCI_REG32(0xe1c4), 0x20e01db }, ++ { CCI_REG32(0xe1c8), 0x1c7019f }, ++ { CCI_REG32(0xe1cc), 0x1840169 }, ++ { CCI_REG32(0xe1d0), 0x14d013e }, ++ { CCI_REG32(0xe1d4), 0x1290120 }, ++ { CCI_REG32(0xe1d8), 0x1180114 }, ++ { CCI_REG32(0xe1dc), 0x1050103 }, ++ { CCI_REG32(0xe1e0), 0x1050103 }, ++ { CCI_REG32(0xe1e4), 0x11e0117 }, ++ { CCI_REG32(0xe1e8), 0x12c0123 }, ++ { CCI_REG32(0xe1ec), 0x1530142 }, ++ { CCI_REG32(0xe1f0), 0x18d016f }, ++ { CCI_REG32(0xe1f4), 0x1d201a6 }, ++ { CCI_REG32(0xe1f8), 0x21a01e2 }, ++ { CCI_REG32(0xe1fc), 0x2640225 }, ++ { CCI_REG32(0xe200), 0x269022d }, ++ { CCI_REG32(0xe204), 0x22601f1 }, ++ { CCI_REG32(0xe208), 0x1e101b4 }, ++ { CCI_REG32(0xe20c), 0x1a10181 }, ++ { CCI_REG32(0xe210), 0x16c0156 }, ++ { CCI_REG32(0xe214), 0x14d013e }, ++ { CCI_REG32(0xe218), 0x1290120 }, ++ { CCI_REG32(0xe21c), 0x11f0118 }, ++ { CCI_REG32(0xe220), 0x11f0118 }, ++ { CCI_REG32(0xe224), 0x12b0123 }, ++ { CCI_REG32(0xe228), 0x1530142 }, ++ { CCI_REG32(0xe22c), 0x172015a }, ++ { CCI_REG32(0xe230), 0x1aa0187 }, ++ { CCI_REG32(0xe234), 0x1ec01bb }, ++ { CCI_REG32(0xe238), 0x23301f8 }, ++ { CCI_REG32(0xe23c), 0x2750233 }, ++ { CCI_REG32(0xe240), 0x28b024c }, ++ { CCI_REG32(0xe244), 0x24f0216 }, ++ { CCI_REG32(0xe248), 0x20701d4 }, ++ { CCI_REG32(0xe24c), 0x1ce01a4 }, ++ { CCI_REG32(0xe250), 0x1a10181 }, ++ { CCI_REG32(0xe254), 0x16c0156 }, ++ { CCI_REG32(0xe258), 0x1520141 }, ++ { CCI_REG32(0xe25c), 0x1480138 }, ++ { CCI_REG32(0xe260), 0x1480138 }, ++ { CCI_REG32(0xe264), 0x1550143 }, ++ { CCI_REG32(0xe268), 0x172015a }, ++ { CCI_REG32(0xe26c), 0x1aa0187 }, ++ { CCI_REG32(0xe270), 0x1d701a9 }, ++ { CCI_REG32(0xe274), 0x21201db }, ++ { CCI_REG32(0xe278), 0x25d021d }, ++ { CCI_REG32(0xe27c), 0x2990254 }, ++ { CCI_REG32(0xe280), 0x2d70291 }, ++ { CCI_REG32(0xe284), 0x28c024c }, ++ { CCI_REG32(0xe288), 0x2390201 }, ++ { CCI_REG32(0xe28c), 0x20701d4 }, ++ { CCI_REG32(0xe290), 0x1ce01a4 }, ++ { CCI_REG32(0xe294), 0x1a70184 }, ++ { CCI_REG32(0xe298), 0x18c016e }, ++ { CCI_REG32(0xe29c), 0x1810164 }, ++ { CCI_REG32(0xe2a0), 0x1810164 }, ++ { CCI_REG32(0xe2a4), 0x1900170 }, ++ { CCI_REG32(0xe2a8), 0x1ad0188 }, ++ { CCI_REG32(0xe2ac), 0x1d601a9 }, ++ { CCI_REG32(0xe2b0), 0x21201da }, ++ { CCI_REG32(0xe2b4), 0x2450207 }, ++ { CCI_REG32(0xe2b8), 0x29a0254 }, ++ { CCI_REG32(0xe2bc), 0x2ea029d }, ++ { CCI_REG32(0xe2c0), 0x2f602ae }, ++ { CCI_REG32(0xe2c4), 0x2d80291 }, ++ { CCI_REG32(0xe2c8), 0x280023f }, ++ { CCI_REG32(0xe2cc), 0x2390200 }, ++ { CCI_REG32(0xe2d0), 0x1fe01cc }, ++ { CCI_REG32(0xe2d4), 0x1d201a4 }, ++ { CCI_REG32(0xe2d8), 0x1c6019b }, ++ { CCI_REG32(0xe2dc), 0x1c6019b }, ++ { CCI_REG32(0xe2e0), 0x1c6019b }, ++ { CCI_REG32(0xe2e4), 0x1c8019b }, ++ { CCI_REG32(0xe2e8), 0x1d701a9 }, ++ { CCI_REG32(0xe2ec), 0x20801d1 }, ++ { CCI_REG32(0xe2f0), 0x2450206 }, ++ { CCI_REG32(0xe2f4), 0x28e0248 }, ++ { CCI_REG32(0xe2f8), 0x2ec029d }, ++ { CCI_REG32(0xe2fc), 0x30902b9 }, ++ { CCI_REG32(0xe300), 0x2a002a4 }, ++ { CCI_REG32(0xe304), 0x2830286 }, ++ { CCI_REG32(0xe308), 0x2330234 }, ++ { CCI_REG32(0xe30c), 0x1f601f7 }, ++ { CCI_REG32(0xe310), 0x1c301c4 }, ++ { CCI_REG32(0xe314), 0x19c019c }, ++ { CCI_REG32(0xe318), 0x1920193 }, ++ { CCI_REG32(0xe31c), 0x1920193 }, ++ { CCI_REG32(0xe320), 0x1920192 }, ++ { CCI_REG32(0xe324), 0x1920193 }, ++ { CCI_REG32(0xe328), 0x19f01a1 }, ++ { CCI_REG32(0xe32c), 0x1c801ca }, ++ { CCI_REG32(0xe330), 0x1fb01fe }, ++ { CCI_REG32(0xe334), 0x239023e }, ++ { CCI_REG32(0xe338), 0x28a0292 }, ++ { CCI_REG32(0xe33c), 0x2a802b0 }, ++ { CCI_REG32(0xe340), 0x2830287 }, ++ { CCI_REG32(0xe344), 0x2400242 }, ++ { CCI_REG32(0xe348), 0x1f601f8 }, ++ { CCI_REG32(0xe34c), 0x1cd01ce }, ++ { CCI_REG32(0xe350), 0x19c019d }, ++ { CCI_REG32(0xe354), 0x17b017d }, ++ { CCI_REG32(0xe358), 0x1650166 }, ++ { CCI_REG32(0xe35c), 0x15c015d }, ++ { CCI_REG32(0xe360), 0x15c015d }, ++ { CCI_REG32(0xe364), 0x1670168 }, ++ { CCI_REG32(0xe368), 0x17e0180 }, ++ { CCI_REG32(0xe36c), 0x1a101a3 }, ++ { CCI_REG32(0xe370), 0x1d101d3 }, ++ { CCI_REG32(0xe374), 0x1fc0200 }, ++ { CCI_REG32(0xe378), 0x246024c }, ++ { CCI_REG32(0xe37c), 0x28a0291 }, ++ { CCI_REG32(0xe380), 0x2430245 }, ++ { CCI_REG32(0xe384), 0x20e0211 }, ++ { CCI_REG32(0xe388), 0x1ce01d0 }, ++ { CCI_REG32(0xe38c), 0x19c019e }, ++ { CCI_REG32(0xe390), 0x17b017c }, ++ { CCI_REG32(0xe394), 0x1500152 }, ++ { CCI_REG32(0xe398), 0x13a013c }, ++ { CCI_REG32(0xe39c), 0x1310134 }, ++ { CCI_REG32(0xe3a0), 0x1310134 }, ++ { CCI_REG32(0xe3a4), 0x13c013f }, ++ { CCI_REG32(0xe3a8), 0x1540156 }, ++ { CCI_REG32(0xe3ac), 0x17e0180 }, ++ { CCI_REG32(0xe3b0), 0x1a101a4 }, ++ { CCI_REG32(0xe3b4), 0x1d301d8 }, ++ { CCI_REG32(0xe3b8), 0x2140219 }, ++ { CCI_REG32(0xe3bc), 0x249024e }, ++ { CCI_REG32(0xe3c0), 0x229022b }, ++ { CCI_REG32(0xe3c4), 0x1ed01ef }, ++ { CCI_REG32(0xe3c8), 0x1b001b2 }, ++ { CCI_REG32(0xe3cc), 0x17c017e }, ++ { CCI_REG32(0xe3d0), 0x1500151 }, ++ { CCI_REG32(0xe3d4), 0x13a013c }, ++ { CCI_REG32(0xe3d8), 0x11c011f }, ++ { CCI_REG32(0xe3dc), 0x1130117 }, ++ { CCI_REG32(0xe3e0), 0x1130117 }, ++ { CCI_REG32(0xe3e4), 0x1200123 }, ++ { CCI_REG32(0xe3e8), 0x13c013f }, ++ { CCI_REG32(0xe3ec), 0x1540156 }, ++ { CCI_REG32(0xe3f0), 0x1810183 }, ++ { CCI_REG32(0xe3f4), 0x1b601ba }, ++ { CCI_REG32(0xe3f8), 0x1f301f6 }, ++ { CCI_REG32(0xe3fc), 0x2300234 }, ++ { CCI_REG32(0xe400), 0x21d0221 }, ++ { CCI_REG32(0xe404), 0x1d801db }, ++ { CCI_REG32(0xe408), 0x19d019f }, ++ { CCI_REG32(0xe40c), 0x1670169 }, ++ { CCI_REG32(0xe410), 0x13b013d }, ++ { CCI_REG32(0xe414), 0x11c011f }, ++ { CCI_REG32(0xe418), 0x1130117 }, ++ { CCI_REG32(0xe41c), 0x1010106 }, ++ { CCI_REG32(0xe420), 0x1020108 }, ++ { CCI_REG32(0xe424), 0x1130117 }, ++ { CCI_REG32(0xe428), 0x1200123 }, ++ { CCI_REG32(0xe42c), 0x13f0142 }, ++ { CCI_REG32(0xe430), 0x16c016f }, ++ { CCI_REG32(0xe434), 0x1a301a6 }, ++ { CCI_REG32(0xe438), 0x1df01e2 }, ++ { CCI_REG32(0xe43c), 0x2240228 }, ++ { CCI_REG32(0xe440), 0x21d0220 }, ++ { CCI_REG32(0xe444), 0x1d001d3 }, ++ { CCI_REG32(0xe448), 0x1940196 }, ++ { CCI_REG32(0xe44c), 0x15d0160 }, ++ { CCI_REG32(0xe450), 0x1320135 }, ++ { CCI_REG32(0xe454), 0x1140118 }, ++ { CCI_REG32(0xe458), 0x1010106 }, ++ { CCI_REG32(0xe45c), 0x1000106 }, ++ { CCI_REG32(0xe460), 0x1000106 }, ++ { CCI_REG32(0xe464), 0x1030109 }, ++ { CCI_REG32(0xe468), 0x118011b }, ++ { CCI_REG32(0xe46c), 0x136013a }, ++ { CCI_REG32(0xe470), 0x1630165 }, ++ { CCI_REG32(0xe474), 0x19a019c }, ++ { CCI_REG32(0xe478), 0x1d601d9 }, ++ { CCI_REG32(0xe47c), 0x2240227 }, ++ { CCI_REG32(0xe480), 0x21d0220 }, ++ { CCI_REG32(0xe484), 0x1d001d3 }, ++ { CCI_REG32(0xe488), 0x1940196 }, ++ { CCI_REG32(0xe48c), 0x15d0160 }, ++ { CCI_REG32(0xe490), 0x1320135 }, ++ { CCI_REG32(0xe494), 0x1140118 }, ++ { CCI_REG32(0xe498), 0x1030109 }, ++ { CCI_REG32(0xe49c), 0x1000106 }, ++ { CCI_REG32(0xe4a0), 0x1020108 }, ++ { CCI_REG32(0xe4a4), 0x1030109 }, ++ { CCI_REG32(0xe4a8), 0x118011b }, ++ { CCI_REG32(0xe4ac), 0x1360139 }, ++ { CCI_REG32(0xe4b0), 0x1630165 }, ++ { CCI_REG32(0xe4b4), 0x19a019c }, ++ { CCI_REG32(0xe4b8), 0x1d601d9 }, ++ { CCI_REG32(0xe4bc), 0x2240227 }, ++ { CCI_REG32(0xe4c0), 0x21f0221 }, ++ { CCI_REG32(0xe4c4), 0x1db01de }, ++ { CCI_REG32(0xe4c8), 0x19f01a2 }, ++ { CCI_REG32(0xe4cc), 0x169016c }, ++ { CCI_REG32(0xe4d0), 0x13e0141 }, ++ { CCI_REG32(0xe4d4), 0x1200124 }, ++ { CCI_REG32(0xe4d8), 0x1140119 }, ++ { CCI_REG32(0xe4dc), 0x1030109 }, ++ { CCI_REG32(0xe4e0), 0x1030109 }, ++ { CCI_REG32(0xe4e4), 0x117011c }, ++ { CCI_REG32(0xe4e8), 0x1230126 }, ++ { CCI_REG32(0xe4ec), 0x1420145 }, ++ { CCI_REG32(0xe4f0), 0x16f0171 }, ++ { CCI_REG32(0xe4f4), 0x1a601a8 }, ++ { CCI_REG32(0xe4f8), 0x1e201e4 }, ++ { CCI_REG32(0xe4fc), 0x2250227 }, ++ { CCI_REG32(0xe500), 0x22d0231 }, ++ { CCI_REG32(0xe504), 0x1f101f4 }, ++ { CCI_REG32(0xe508), 0x1b401b7 }, ++ { CCI_REG32(0xe50c), 0x1810183 }, ++ { CCI_REG32(0xe510), 0x1560159 }, ++ { CCI_REG32(0xe514), 0x13e0141 }, ++ { CCI_REG32(0xe518), 0x1200124 }, ++ { CCI_REG32(0xe51c), 0x118011c }, ++ { CCI_REG32(0xe520), 0x118011c }, ++ { CCI_REG32(0xe524), 0x1230126 }, ++ { CCI_REG32(0xe528), 0x1420145 }, ++ { CCI_REG32(0xe52c), 0x15a015c }, ++ { CCI_REG32(0xe530), 0x1870188 }, ++ { CCI_REG32(0xe534), 0x1bb01bd }, ++ { CCI_REG32(0xe538), 0x1f801fb }, ++ { CCI_REG32(0xe53c), 0x2330236 }, ++ { CCI_REG32(0xe540), 0x24c0250 }, ++ { CCI_REG32(0xe544), 0x2160219 }, ++ { CCI_REG32(0xe548), 0x1d401d7 }, ++ { CCI_REG32(0xe54c), 0x1a401a6 }, ++ { CCI_REG32(0xe550), 0x1810183 }, ++ { CCI_REG32(0xe554), 0x1560158 }, ++ { CCI_REG32(0xe558), 0x1410144 }, ++ { CCI_REG32(0xe55c), 0x138013b }, ++ { CCI_REG32(0xe560), 0x138013b }, ++ { CCI_REG32(0xe564), 0x1430146 }, ++ { CCI_REG32(0xe568), 0x15a015c }, ++ { CCI_REG32(0xe56c), 0x1870188 }, ++ { CCI_REG32(0xe570), 0x1a901ab }, ++ { CCI_REG32(0xe574), 0x1db01dd }, ++ { CCI_REG32(0xe578), 0x21d0221 }, ++ { CCI_REG32(0xe57c), 0x2540259 }, ++ { CCI_REG32(0xe580), 0x2910296 }, ++ { CCI_REG32(0xe584), 0x24c0251 }, ++ { CCI_REG32(0xe588), 0x2010204 }, ++ { CCI_REG32(0xe58c), 0x1d401d6 }, ++ { CCI_REG32(0xe590), 0x1a401a5 }, ++ { CCI_REG32(0xe594), 0x1840186 }, ++ { CCI_REG32(0xe598), 0x16e0170 }, ++ { CCI_REG32(0xe59c), 0x1640167 }, ++ { CCI_REG32(0xe5a0), 0x1640167 }, ++ { CCI_REG32(0xe5a4), 0x1700173 }, ++ { CCI_REG32(0xe5a8), 0x188018a }, ++ { CCI_REG32(0xe5ac), 0x1a901ab }, ++ { CCI_REG32(0xe5b0), 0x1da01dd }, ++ { CCI_REG32(0xe5b4), 0x207020a }, ++ { CCI_REG32(0xe5b8), 0x2540259 }, ++ { CCI_REG32(0xe5bc), 0x29d02a3 }, ++ { CCI_REG32(0xe5c0), 0x2ae02b4 }, ++ { CCI_REG32(0xe5c4), 0x2910297 }, ++ { CCI_REG32(0xe5c8), 0x23f0243 }, ++ { CCI_REG32(0xe5cc), 0x2000201 }, ++ { CCI_REG32(0xe5d0), 0x1cc01cd }, ++ { CCI_REG32(0xe5d4), 0x1a401a6 }, ++ { CCI_REG32(0xe5d8), 0x19b019d }, ++ { CCI_REG32(0xe5dc), 0x19b019d }, ++ { CCI_REG32(0xe5e0), 0x19b019d }, ++ { CCI_REG32(0xe5e4), 0x19b019e }, ++ { CCI_REG32(0xe5e8), 0x1a901ab }, ++ { CCI_REG32(0xe5ec), 0x1d101d3 }, ++ { CCI_REG32(0xe5f0), 0x2060209 }, ++ { CCI_REG32(0xe5f4), 0x248024b }, ++ { CCI_REG32(0xe5f8), 0x29d02a3 }, ++ { CCI_REG32(0xe5fc), 0x2b902c0 }, ++ { CCI_REG8(0xd822), 0x01 }, ++ { CCI_REG8(0xd823), 0x0f }, + }; + + /* Mode configs */ diff --git a/target/linux/bcm27xx/patches-6.6/950-1319-dts-bcm2712-rpi-500-Add-USER_LED-GPIO-name.patch b/target/linux/bcm27xx/patches-6.6/950-1319-dts-bcm2712-rpi-500-Add-USER_LED-GPIO-name.patch new file mode 100644 index 000000000000..0dabf4bf022a --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1319-dts-bcm2712-rpi-500-Add-USER_LED-GPIO-name.patch @@ -0,0 +1,23 @@ +From 0985b32279d47e7ea01152233d26eedcdf721d09 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 11 Oct 2024 14:24:51 +0100 +Subject: [PATCH 1319/1350] dts: bcm2712-rpi-500: Add USER_LED GPIO name + +The USER_LED signal was missing from the initial DTS. + +Signed-off-by: Phil Elwell +--- + arch/arm64/boot/dts/broadcom/bcm2712-rpi-500.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-500.dts ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-500.dts +@@ -35,7 +35,7 @@ + "PWR_GPIO", // GPIO_020 + "KEYB_RUN", // GPIO_021 + "-", // GPIO_022 +- "-", // GPIO_023 ++ "USER_LED", // GPIO_023 + "BT_RTS", // GPIO_024 + "BT_CTS", // GPIO_025 + "BT_TXD", // GPIO_026 diff --git a/target/linux/bcm27xx/patches-6.6/950-1321-dtoverlays-Fix-up-imx500-overlays-to-have-unique-clo.patch b/target/linux/bcm27xx/patches-6.6/950-1321-dtoverlays-Fix-up-imx500-overlays-to-have-unique-clo.patch new file mode 100644 index 000000000000..b8e67c649fda --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1321-dtoverlays-Fix-up-imx500-overlays-to-have-unique-clo.patch @@ -0,0 +1,86 @@ +From 239df148741e35d5b54749a624f96dfcacc7c57e Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 14 Oct 2024 15:37:57 +0100 +Subject: [PATCH 1321/1350] dtoverlays: Fix up imx500 overlays to have unique + clock nodes + +The overlay was creating DT nodes /clocks/clk-aicam and +/clocks/clk-aicam-gated for both cam0 and cam1, which resulted +in one failing. + +The clock infrastructure creates the clock name from the node name +without any @N reg extension, so we can't just use that. The nodes +therefore have to be renamed. + +Signed-off-by: Dave Stevenson +--- + arch/arm/boot/dts/overlays/imx500-overlay.dts | 10 ++++++---- + arch/arm/boot/dts/overlays/imx500-pi5-overlay.dts | 10 ++++++---- + 2 files changed, 12 insertions(+), 8 deletions(-) + +--- a/arch/arm/boot/dts/overlays/imx500-overlay.dts ++++ b/arch/arm/boot/dts/overlays/imx500-overlay.dts +@@ -72,16 +72,16 @@ + }; + }; + +- clocks_frag: fragment@104 { ++ fragment@104 { + target-path = "/clocks"; + __overlay__ { +- clk_aicam: clk-aicam { ++ clk_aicam: clk-aicam1 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; + +- clk_aicam_gated: clk-aicam-gated { ++ clk_aicam_gated: clk-aicam-gated1 { + compatible = "gpio-gate-clock"; + clocks = <&clk_aicam>; + #clock-cells = <0>; +@@ -98,7 +98,9 @@ + <&csi_frag>, "target:0=",<&csi0>, + <&spi_bridge>, "power-supply:0=",<&cam0_reg>, + <®_frag>, "target:0=",<&cam0_reg>, +- <&cam_node>, "VANA-supply:0=",<&cam0_reg>; ++ <&cam_node>, "VANA-supply:0=",<&cam0_reg>, ++ <&clk_aicam>,"name=clk-aicam0", ++ <&clk_aicam_gated>,"name=clk-aicam-gated0"; + bypass-cache = <&spi_bridge>,"bypass-cache?"; + }; + }; +--- a/arch/arm/boot/dts/overlays/imx500-pi5-overlay.dts ++++ b/arch/arm/boot/dts/overlays/imx500-pi5-overlay.dts +@@ -75,16 +75,16 @@ + }; + }; + +- clocks_frag: fragment@104 { ++ fragment@104 { + target-path = "/clocks"; + __overlay__ { +- clk_aicam: clk-aicam { ++ clk_aicam: clk-aicam1 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; + +- clk_aicam_gated: clk-aicam-gated { ++ clk_aicam_gated: clk-aicam-gated1 { + compatible = "gpio-gate-clock"; + clocks = <&clk_aicam>; + #clock-cells = <0>; +@@ -103,7 +103,9 @@ + <&spi_frag_overlay>, "fast_xfer-gpios:16=35", // CD0_IO1_MICDAT0 (clock) + <&spi_bridge>, "power-supply:0=",<&cam0_reg>, + <®_frag>, "target:0=",<&cam0_reg>, +- <&cam_node>, "VANA-supply:0=",<&cam0_reg>; ++ <&cam_node>, "VANA-supply:0=",<&cam0_reg>, ++ <&clk_aicam>,"name=clk-aicam0", ++ <&clk_aicam_gated>,"name=clk-aicam-gated0"; + bypass-cache = <&spi_bridge>,"bypass-cache?"; + }; + }; diff --git a/target/linux/bcm27xx/patches-6.6/950-1322-dtoverlays-Add-an-overlay-for-Waveshare-s-800x480-4..patch b/target/linux/bcm27xx/patches-6.6/950-1322-dtoverlays-Add-an-overlay-for-Waveshare-s-800x480-4..patch new file mode 100644 index 000000000000..4a6679810142 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1322-dtoverlays-Add-an-overlay-for-Waveshare-s-800x480-4..patch @@ -0,0 +1,177 @@ +From 6f2d1b4c3132206de40247b604638a51277131fb Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 14 Oct 2024 18:53:43 +0100 +Subject: [PATCH 1322/1350] dtoverlays: Add an overlay for Waveshare's 800x480 + 4.3" DSI screen + +It tried to be a clone of the Pi 7" display, but isn't, and gives +corrupt images with the current timings. + +Add a new overlay for it. + +Signed-off-by: Dave Stevenson +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 17 +++ + .../vc4-kms-dsi-waveshare-800x480-overlay.dts | 119 ++++++++++++++++++ + 3 files changed, 137 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-800x480-overlay.dts + +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -319,6 +319,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + vc4-kms-dsi-ili9881-7inch.dtbo \ + vc4-kms-dsi-lt070me05000.dtbo \ + vc4-kms-dsi-lt070me05000-v2.dtbo \ ++ vc4-kms-dsi-waveshare-800x480.dtbo \ + vc4-kms-dsi-waveshare-panel.dtbo \ + vc4-kms-kippah-7inch.dtbo \ + vc4-kms-v3d.dtbo \ +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -5248,6 +5248,23 @@ Load: dtoverlay=vc4-kms-dsi-lt070me050 + Params: + + ++Name: vc4-kms-dsi-waveshare-800x480 ++Info: Enable the Waveshare 4.3" 800x480 DSI screen. ++ It tries to look like the Pi 7" display, but won't accept some of the ++ timings. ++ Includes the edt-ft5406 for the touchscreen element. ++ Requires vc4-kms-v3d to be loaded. ++Load: dtoverlay=vc4-kms-dsi-waveshare-800x480,= ++Params: sizex Touchscreen size x (default 800) ++ sizey Touchscreen size y (default 480) ++ invx Touchscreen inverted x axis ++ invy Touchscreen inverted y axis ++ swapxy Touchscreen swapped x y axis ++ disable_touch Disables the touch screen overlay driver ++ dsi0 Use DSI0 and i2c_csi_dsi0 (rather than ++ the default DSI1 and i2c_csi_dsi). ++ ++ + Name: vc4-kms-dsi-waveshare-panel + Info: Enable a Waveshare DSI touchscreen + Includes the Goodix driver for the touchscreen element. +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-800x480-overlay.dts +@@ -0,0 +1,119 @@ ++/* ++ * Device Tree overlay for Waveshare 4.3" 800x480 panel. ++ * It tries to look like a Pi 7" panel, but fails with some of the timing ++ * options. ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++#include "edt-ft5406.dtsi" ++ ++/ { ++ /* No compatible as it will have come from edt-ft5406.dtsi */ ++ ++ dsi_frag: fragment@0 { ++ target = <&dsi1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ port { ++ dsi_out: endpoint { ++ remote-endpoint = <&panel_dsi_port>; ++ }; ++ }; ++ ++ panel: panel-dsi-generic@0 { ++ // See panel-dsi.yaml binding ++ compatible = "waveshare,4-3-inch-dsi","panel-dsi"; ++ reg = <0>; ++ power-supply = <®_display>; ++ backlight = <®_display>; ++ dsi-color-format = "RGB888"; ++ mode = "MODE_VIDEO"; ++ width-mm = <0>; ++ height-mm = <0>; ++ ++ port { ++ panel_dsi_port: endpoint { ++ data-lanes = <1>; ++ remote-endpoint = <&dsi_out>; ++ }; ++ }; ++ ++ timing: panel-timing { ++ clock-frequency = <27777000>; ++ hactive = <800>; ++ vactive = <480>; ++ hfront-porch = <59>; ++ hsync-len = <2>; ++ hback-porch = <45>; ++ vfront-porch = <7>; ++ vsync-len = <2>; ++ vback-porch = <22>; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target-path = "/"; ++ __overlay__ { ++ reg_bridge: reg_bridge@1 { ++ reg = <1>; ++ compatible = "regulator-fixed"; ++ regulator-name = "bridge_reg"; ++ gpio = <®_display 0 0>; ++ vin-supply = <®_display>; ++ enable-active-high; ++ }; ++ }; ++ }; ++ ++ i2c_frag: fragment@2 { ++ target = <&i2c_csi_dsi>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ reg_display: reg_display@45 { ++ compatible = "raspberrypi,7inch-touchscreen-panel-regulator"; ++ reg = <0x45>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&i2c0if>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@4 { ++ target = <&i2c0mux>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ fragment@5 { ++ target = <&ft5406>; ++ __overlay__ { ++ vcc-supply = <®_display>; ++ reset-gpio = <®_display 1 1>; ++ }; ++ }; ++ ++ __overrides__ { ++ dsi0 = <&dsi_frag>, "target:0=",<&dsi0>, ++ <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, ++ <&ts_i2c_frag>, "target:0=",<&i2c_csi_dsi0>, ++ <®_bridge>, "reg:0=0", ++ <®_bridge>, "regulator-name=bridge_reg_0"; ++ disable_touch = <&ft5406>, "status=disabled"; ++ }; ++}; diff --git a/target/linux/bcm27xx/patches-6.6/950-1323-drm-vc4-Remove-request-for-min-clocks-when-hdmi-outp.patch b/target/linux/bcm27xx/patches-6.6/950-1323-drm-vc4-Remove-request-for-min-clocks-when-hdmi-outp.patch new file mode 100644 index 000000000000..9f4cf9d0336d --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1323-drm-vc4-Remove-request-for-min-clocks-when-hdmi-outp.patch @@ -0,0 +1,74 @@ +From 18d185166ca00c9280505ad41fbe036efbb52e67 Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Mon, 14 Oct 2024 18:55:00 +0100 +Subject: [PATCH 1323/1350] drm/vc4: Remove request for min clocks when hdmi + output is disabled + +Currently, booting with no hdmi connected has: +pi@pi4:~ $ vcgencmd measure_clock hdmi pixel +frequency(9)=120010256 +frequency(29)=74988280 + +After connecting hdmi we get: +pi@pi4:~ $ vcgencmd measure_clock hdmi pixel +frequency(9)=300005856 +frequency(29)=149989744 + +and that persists after disconnecting hdmi + +I can measure this on a power supply as 10mA@5.2V (52mW). + +We should always remove clk_set_min_rate requests +when we no longer need them. + +Signed-off-by: Dom Cobley +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 4 ++++ + drivers/gpu/drm/vc4/vc4_hvs.c | 3 +++ + drivers/gpu/drm/vc4/vc4_v3d.c | 2 ++ + 3 files changed, 9 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -1224,6 +1224,8 @@ static void vc4_hdmi_encoder_post_crtc_p + if (vc4_hdmi->variant->phy_disable) + vc4_hdmi->variant->phy_disable(vc4_hdmi); + ++ /* we no longer require a minimum clock rate */ ++ clk_set_min_rate(vc4_hdmi->pixel_bvb_clock, 0); + clk_disable_unprepare(vc4_hdmi->pixel_bvb_clock); + clk_disable_unprepare(vc4_hdmi->pixel_clock); + +@@ -3724,6 +3726,8 @@ static int vc4_hdmi_runtime_suspend(stru + struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); + + clk_disable_unprepare(vc4_hdmi->audio_clock); ++ /* we no longer require a minimum clock rate */ ++ clk_set_min_rate(vc4_hdmi->hsm_clock, 0); + clk_disable_unprepare(vc4_hdmi->hsm_clock); + + return 0; +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -2308,7 +2308,10 @@ static void vc4_hvs_unbind(struct device + drm_mm_remove_node(node); + drm_mm_takedown(&vc4->hvs->lbm_mm); + ++ /* we no longer require a minimum clock rate */ ++ clk_set_min_rate(hvs->disp_clk, 0); + clk_disable_unprepare(hvs->disp_clk); ++ clk_set_min_rate(hvs->core_clk, 0); + clk_disable_unprepare(hvs->core_clk); + + vc4->hvs = NULL; +--- a/drivers/gpu/drm/vc4/vc4_v3d.c ++++ b/drivers/gpu/drm/vc4/vc4_v3d.c +@@ -376,6 +376,8 @@ static int vc4_v3d_runtime_suspend(struc + + vc4_irq_disable(&vc4->base); + ++ /* we no longer require a minimum clock rate */ ++ clk_set_min_rate(v3d->clk, 0); + clk_disable_unprepare(v3d->clk); + + return 0; diff --git a/target/linux/bcm27xx/patches-6.6/950-1324-dts-bcm2712-rpi-Add-aliases-for-the-CSI-DSI-I2Cs.patch b/target/linux/bcm27xx/patches-6.6/950-1324-dts-bcm2712-rpi-Add-aliases-for-the-CSI-DSI-I2Cs.patch new file mode 100644 index 000000000000..8781590f2e6e --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1324-dts-bcm2712-rpi-Add-aliases-for-the-CSI-DSI-I2Cs.patch @@ -0,0 +1,71 @@ +From 36faab69e8eebfb7f587bddef96040c59d3daa7c Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 16 Oct 2024 11:31:04 +0100 +Subject: [PATCH 1324/1350] dts: bcm2712-rpi: Add aliases for the CSI/DSI I2Cs + +Older Pis arrange that the camera I2C ports appear as /dev/i2c-10. Add +aliases so that on the Pi 5 family, i2c_csi_dsi0 becomes i2c-10 and +i2c_csi_dsi1 becomes i2c-11. Only the I2C buses that appear on the +40-pin header, i.e. I2C0 to I2C3, get a low bus number. + +Also add hints for our udev rules about which symlinks to create for +backwards-compatibility with the previous bus numbers. Note that +lower numbers have priority, so i2c-0 on CM5 masks i2c-11, forcing +i2c-11 to be a symlink to i2c-0, not vice versa. + +Signed-off-by: Phil Elwell +--- + arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts | 2 ++ + arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi | 2 ++ + arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi | 7 +++---- + 3 files changed, 7 insertions(+), 4 deletions(-) + +--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts +@@ -255,12 +255,14 @@ i2c_csi_dsi0: &i2c6 { // Note: This is f + pinctrl-0 = <&rp1_i2c6_38_39>; + pinctrl-names = "default"; + clock-frequency = <100000>; ++ symlink = "i2c-6"; + }; + + i2c_csi_dsi1: &i2c4 { // Note: This is for MIPI1 connector only + pinctrl-0 = <&rp1_i2c4_40_41>; + pinctrl-names = "default"; + clock-frequency = <100000>; ++ symlink = "i2c-4"; + }; + + i2c_csi_dsi: &i2c_csi_dsi1 { }; // An alias for compatibility +--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi +@@ -238,9 +238,11 @@ i2c_csi_dsi0: &i2c6 { // Note: This is f + pinctrl-0 = <&rp1_i2c6_38_39>; + pinctrl-names = "default"; + clock-frequency = <100000>; ++ symlink = "i2c-6"; + }; + + i2c_csi_dsi1: &i2c0 { // Note: This is for MIPI1 connector ++ symlink = "i2c-11"; + }; + + i2c_csi_dsi: &i2c_csi_dsi1 { }; // An alias for compatibility +--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi +@@ -117,12 +117,11 @@ + i2c = &i2c_arm; + i2c0 = &i2c0; + i2c1 = &i2c1; +- i2c10 = &i2c_rp1boot; + i2c2 = &i2c2; + i2c3 = &i2c3; +- i2c4 = &i2c4; +- i2c5 = &i2c5; +- i2c6 = &i2c6; ++ i2c10 = &i2c_csi_dsi0; ++ i2c11 = &i2c_csi_dsi1; ++ i2c12 = &i2c_rp1boot; + mailbox = &mailbox; + mmc0 = &sdio1; + serial0 = &uart0; diff --git a/target/linux/bcm27xx/patches-6.6/950-1325-NotForUpstream-media-video-mux-Propagate-controls-to.patch b/target/linux/bcm27xx/patches-6.6/950-1325-NotForUpstream-media-video-mux-Propagate-controls-to.patch new file mode 100644 index 000000000000..c40c3d27c144 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1325-NotForUpstream-media-video-mux-Propagate-controls-to.patch @@ -0,0 +1,51 @@ +From e03a63b8d4a60ee49e3277ac7f7ea4c2998e7938 Mon Sep 17 00:00:00 2001 +From: Kieran Bingham +Date: Thu, 10 Oct 2024 14:52:52 +0100 +Subject: [PATCH 1325/1350] NotForUpstream: media: video-mux: Propagate + controls to source + +The i.MX8MP makes calls on it's source device to determine +the link-frequency that should be configured on the CSI2 receiver. + +When the source is behind a video mux, we need to pass this call through +to the connected device. + +Map the control handler of the source device to the video-mux, +essentially proxying all controls on the mux to the device which has +it's link enabled. + +Signed-off-by: Kieran Bingham +--- + drivers/media/platform/video-mux.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/drivers/media/platform/video-mux.c ++++ b/drivers/media/platform/video-mux.c +@@ -69,6 +69,7 @@ static int video_mux_link_setup(struct m + const struct media_pad *remote, u32 flags) + { + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); ++ struct v4l2_subdev *source_sd; + struct video_mux *vmux = v4l2_subdev_to_video_mux(sd); + u16 source_pad = entity->num_pads - 1; + int ret = 0; +@@ -111,6 +112,10 @@ static int video_mux_link_setup(struct m + *source_mbusformat = *v4l2_subdev_get_pad_format(sd, sd_state, + vmux->active); + v4l2_subdev_unlock_state(sd_state); ++ ++ source_sd = media_entity_to_v4l2_subdev(remote->entity); ++ vmux->subdev.ctrl_handler = source_sd->ctrl_handler; ++ + } else { + if (vmux->active != local->index) + goto out; +@@ -118,6 +123,8 @@ static int video_mux_link_setup(struct m + dev_dbg(sd->dev, "going inactive\n"); + mux_control_deselect(vmux->mux); + vmux->active = -1; ++ ++ vmux->subdev.ctrl_handler = NULL; + } + + out: diff --git a/target/linux/bcm27xx/patches-6.6/950-1326-media-platform-video-mux-Fix-mutex-locking.patch b/target/linux/bcm27xx/patches-6.6/950-1326-media-platform-video-mux-Fix-mutex-locking.patch new file mode 100644 index 000000000000..12b08b8188f2 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1326-media-platform-video-mux-Fix-mutex-locking.patch @@ -0,0 +1,59 @@ +From cc0c868b51941f0ff2676970b70d388f1722e7fe Mon Sep 17 00:00:00 2001 +From: Paul Elder +Date: Thu, 10 Oct 2024 14:52:53 +0100 +Subject: [PATCH 1326/1350] media: platform: video-mux: Fix mutex locking + +The current order of locking between the driver mutex and the v4l2 +subdev state lock causes a circuluar locking dependency when trying to +set up a link. Fix this. + +Signed-off-by: Paul Elder +Reviewed-by: Laurent Pinchart +Signed-off-by: Kieran Bingham +--- + drivers/media/platform/video-mux.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/media/platform/video-mux.c ++++ b/drivers/media/platform/video-mux.c +@@ -70,6 +70,7 @@ static int video_mux_link_setup(struct m + { + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); + struct v4l2_subdev *source_sd; ++ struct v4l2_subdev_state *sd_state; + struct video_mux *vmux = v4l2_subdev_to_video_mux(sd); + u16 source_pad = entity->num_pads - 1; + int ret = 0; +@@ -85,10 +86,10 @@ static int video_mux_link_setup(struct m + remote->entity->name, remote->index, local->entity->name, + local->index, flags & MEDIA_LNK_FL_ENABLED); + ++ sd_state = v4l2_subdev_lock_and_get_active_state(sd); + mutex_lock(&vmux->lock); + + if (flags & MEDIA_LNK_FL_ENABLED) { +- struct v4l2_subdev_state *sd_state; + struct v4l2_mbus_framefmt *source_mbusformat; + + if (vmux->active == local->index) +@@ -106,12 +107,10 @@ static int video_mux_link_setup(struct m + vmux->active = local->index; + + /* Propagate the active format to the source */ +- sd_state = v4l2_subdev_lock_and_get_active_state(sd); + source_mbusformat = v4l2_subdev_get_pad_format(sd, sd_state, + source_pad); + *source_mbusformat = *v4l2_subdev_get_pad_format(sd, sd_state, + vmux->active); +- v4l2_subdev_unlock_state(sd_state); + + source_sd = media_entity_to_v4l2_subdev(remote->entity); + vmux->subdev.ctrl_handler = source_sd->ctrl_handler; +@@ -129,6 +128,7 @@ static int video_mux_link_setup(struct m + + out: + mutex_unlock(&vmux->lock); ++ v4l2_subdev_unlock_state(sd_state); + return ret; + } + diff --git a/target/linux/bcm27xx/patches-6.6/950-1327-media-i2c-ov5647-Tidy-up-mode-registers-to-make-the-.patch b/target/linux/bcm27xx/patches-6.6/950-1327-media-i2c-ov5647-Tidy-up-mode-registers-to-make-the-.patch new file mode 100644 index 000000000000..3f0a34e46462 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1327-media-i2c-ov5647-Tidy-up-mode-registers-to-make-the-.patch @@ -0,0 +1,94 @@ +From 664e835fd4886332ec3b3813de47102fe45e4fc3 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 15 Oct 2024 16:05:57 +0100 +Subject: [PATCH 1327/1350] media: i2c: ov5647: Tidy up mode registers to make + the order common + +To make comparisons of the mode registers easier, put the registers +for the binned and VGA modes in the same order as the others. + +Signed-off-by: Dave Stevenson +--- + drivers/media/i2c/ov5647.c | 33 ++++++++++++++------------------- + 1 file changed, 14 insertions(+), 19 deletions(-) + +--- a/drivers/media/i2c/ov5647.c ++++ b/drivers/media/i2c/ov5647.c +@@ -344,6 +344,8 @@ static struct regval_list ov5647_2x2binn + {0x3036, 0x62}, + {0x303c, 0x11}, + {0x3106, 0xf5}, ++ {0x3821, 0x01}, ++ {0x3820, 0x41}, + {0x3827, 0xec}, + {0x370c, 0x03}, + {0x3612, 0x59}, +@@ -416,8 +418,6 @@ static struct regval_list ov5647_2x2binn + {0x4837, 0x16}, + {0x4800, 0x24}, + {0x3503, 0x03}, +- {0x3820, 0x41}, +- {0x3821, 0x01}, + {0x350a, 0x00}, + {0x350b, 0x10}, + {0x3500, 0x00}, +@@ -430,20 +430,27 @@ static struct regval_list ov5647_2x2binn + static struct regval_list ov5647_640x480_10bpp[] = { + {0x0100, 0x00}, + {0x0103, 0x01}, +- {0x3035, 0x11}, ++ {0x3034, 0x1a}, ++ {0x3035, 0x21}, + {0x3036, 0x46}, + {0x303c, 0x11}, ++ {0x3106, 0xf5}, + {0x3821, 0x01}, + {0x3820, 0x41}, ++ {0x3827, 0xec}, + {0x370c, 0x03}, + {0x3612, 0x59}, + {0x3618, 0x00}, + {0x5000, 0x06}, + {0x5003, 0x08}, + {0x5a00, 0x08}, +- {0x3000, 0xff}, +- {0x3001, 0xff}, +- {0x3002, 0xff}, ++ {0x3000, 0x00}, ++ {0x3001, 0x00}, ++ {0x3002, 0x00}, ++ {0x3016, 0x08}, ++ {0x3017, 0xe0}, ++ {0x3018, 0x44}, ++ {0x301c, 0xf8}, + {0x301d, 0xf0}, + {0x3a18, 0x00}, + {0x3a19, 0xf8}, +@@ -469,6 +476,7 @@ static struct regval_list ov5647_640x480 + {0x3632, 0xe2}, + {0x3633, 0x23}, + {0x3634, 0x44}, ++ {0x3636, 0x06}, + {0x3620, 0x64}, + {0x3621, 0xe0}, + {0x3600, 0x37}, +@@ -497,19 +505,6 @@ static struct regval_list ov5647_640x480 + {0x4001, 0x02}, + {0x4004, 0x02}, + {0x4000, 0x09}, +- {0x3000, 0x00}, +- {0x3001, 0x00}, +- {0x3002, 0x00}, +- {0x3017, 0xe0}, +- {0x301c, 0xfc}, +- {0x3636, 0x06}, +- {0x3016, 0x08}, +- {0x3827, 0xec}, +- {0x3018, 0x44}, +- {0x3035, 0x21}, +- {0x3106, 0xf5}, +- {0x3034, 0x1a}, +- {0x301c, 0xf8}, + {0x4800, 0x34}, + {0x3503, 0x03}, + {0x0100, 0x01}, diff --git a/target/linux/bcm27xx/patches-6.6/950-1328-media-i2c-ov5647-Separate-out-the-common-registers.patch b/target/linux/bcm27xx/patches-6.6/950-1328-media-i2c-ov5647-Separate-out-the-common-registers.patch new file mode 100644 index 000000000000..7f979e35e3a4 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1328-media-i2c-ov5647-Separate-out-the-common-registers.patch @@ -0,0 +1,392 @@ +From aef1e51838641a602e0ab60523283f8a6e36a725 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 15 Oct 2024 17:02:39 +0100 +Subject: [PATCH 1328/1350] media: i2c: ov5647: Separate out the common + registers. + +There are many registers in common between all the modes. +Pull those out into one common table. + +Signed-off-by: Dave Stevenson +--- + drivers/media/i2c/ov5647.c | 243 ++++++++----------------------------- + 1 file changed, 50 insertions(+), 193 deletions(-) + +--- a/drivers/media/i2c/ov5647.c ++++ b/drivers/media/i2c/ov5647.c +@@ -162,22 +162,16 @@ static const struct regval_list sensor_o + {0x3002, 0xe4}, + }; + +-static struct regval_list ov5647_2592x1944_10bpp[] = { ++static struct regval_list ov5647_common_regs[] = { + {0x0100, 0x00}, + {0x0103, 0x01}, + {0x3034, 0x1a}, + {0x3035, 0x21}, +- {0x3036, 0x69}, + {0x303c, 0x11}, + {0x3106, 0xf5}, +- {0x3821, 0x00}, +- {0x3820, 0x00}, + {0x3827, 0xec}, + {0x370c, 0x03}, +- {0x3612, 0x5b}, +- {0x3618, 0x04}, + {0x5000, 0x06}, +- {0x5002, 0x41}, + {0x5003, 0x08}, + {0x5a00, 0x08}, + {0x3000, 0x00}, +@@ -192,24 +186,6 @@ static struct regval_list ov5647_2592x19 + {0x3a19, 0xf8}, + {0x3c01, 0x80}, + {0x3b07, 0x0c}, +- {0x3814, 0x11}, +- {0x3815, 0x11}, +- {0x3708, 0x64}, +- {0x3709, 0x12}, +- {0x3808, 0x0a}, +- {0x3809, 0x20}, +- {0x380a, 0x07}, +- {0x380b, 0x98}, +- {0x3800, 0x00}, +- {0x3801, 0x00}, +- {0x3802, 0x00}, +- {0x3803, 0x00}, +- {0x3804, 0x0a}, +- {0x3805, 0x3f}, +- {0x3806, 0x07}, +- {0x3807, 0xa3}, +- {0x3811, 0x10}, +- {0x3813, 0x06}, + {0x3630, 0x2e}, + {0x3632, 0xe2}, + {0x3633, 0x23}, +@@ -229,11 +205,6 @@ static struct regval_list ov5647_2592x19 + {0x3f06, 0x10}, + {0x3f01, 0x0a}, + {0x3a08, 0x01}, +- {0x3a09, 0x28}, +- {0x3a0a, 0x00}, +- {0x3a0b, 0xf6}, +- {0x3a0d, 0x08}, +- {0x3a0e, 0x06}, + {0x3a0f, 0x58}, + {0x3a10, 0x50}, + {0x3a1b, 0x58}, +@@ -241,52 +212,57 @@ static struct regval_list ov5647_2592x19 + {0x3a11, 0x60}, + {0x3a1f, 0x28}, + {0x4001, 0x02}, +- {0x4004, 0x04}, + {0x4000, 0x09}, ++ {0x3503, 0x03}, ++}; ++ ++static struct regval_list ov5647_2592x1944_10bpp[] = { ++ {0x3036, 0x69}, ++ {0x3821, 0x00}, ++ {0x3820, 0x00}, ++ {0x3612, 0x5b}, ++ {0x3618, 0x04}, ++ {0x5002, 0x41}, ++ {0x3814, 0x11}, ++ {0x3815, 0x11}, ++ {0x3708, 0x64}, ++ {0x3709, 0x12}, ++ {0x3800, 0x00}, ++ {0x3801, 0x00}, ++ {0x3802, 0x00}, ++ {0x3803, 0x00}, ++ {0x3804, 0x0a}, ++ {0x3805, 0x3f}, ++ {0x3806, 0x07}, ++ {0x3807, 0xa3}, ++ {0x3808, 0x0a}, ++ {0x3809, 0x20}, ++ {0x380a, 0x07}, ++ {0x380b, 0x98}, ++ {0x3811, 0x10}, ++ {0x3813, 0x06}, ++ {0x3a09, 0x28}, ++ {0x3a0a, 0x00}, ++ {0x3a0b, 0xf6}, ++ {0x3a0d, 0x08}, ++ {0x3a0e, 0x06}, ++ {0x4004, 0x04}, + {0x4837, 0x19}, + {0x4800, 0x24}, +- {0x3503, 0x03}, + {0x0100, 0x01}, + }; + + static struct regval_list ov5647_1080p30_10bpp[] = { +- {0x0100, 0x00}, +- {0x0103, 0x01}, +- {0x3034, 0x1a}, +- {0x3035, 0x21}, + {0x3036, 0x62}, +- {0x303c, 0x11}, +- {0x3106, 0xf5}, + {0x3821, 0x00}, + {0x3820, 0x00}, +- {0x3827, 0xec}, +- {0x370c, 0x03}, + {0x3612, 0x5b}, + {0x3618, 0x04}, +- {0x5000, 0x06}, + {0x5002, 0x41}, +- {0x5003, 0x08}, +- {0x5a00, 0x08}, +- {0x3000, 0x00}, +- {0x3001, 0x00}, +- {0x3002, 0x00}, +- {0x3016, 0x08}, +- {0x3017, 0xe0}, +- {0x3018, 0x44}, +- {0x301c, 0xf8}, +- {0x301d, 0xf0}, +- {0x3a18, 0x00}, +- {0x3a19, 0xf8}, +- {0x3c01, 0x80}, +- {0x3b07, 0x0c}, + {0x3814, 0x11}, + {0x3815, 0x11}, + {0x3708, 0x64}, + {0x3709, 0x12}, +- {0x3808, 0x07}, +- {0x3809, 0x80}, +- {0x380a, 0x04}, +- {0x380b, 0x38}, + {0x3800, 0x01}, + {0x3801, 0x5c}, + {0x3802, 0x01}, +@@ -295,77 +271,30 @@ static struct regval_list ov5647_1080p30 + {0x3805, 0xe3}, + {0x3806, 0x05}, + {0x3807, 0xf1}, ++ {0x3808, 0x07}, ++ {0x3809, 0x80}, ++ {0x380a, 0x04}, ++ {0x380b, 0x38}, + {0x3811, 0x04}, + {0x3813, 0x02}, +- {0x3630, 0x2e}, +- {0x3632, 0xe2}, +- {0x3633, 0x23}, +- {0x3634, 0x44}, +- {0x3636, 0x06}, +- {0x3620, 0x64}, +- {0x3621, 0xe0}, +- {0x3600, 0x37}, +- {0x3704, 0xa0}, +- {0x3703, 0x5a}, +- {0x3715, 0x78}, +- {0x3717, 0x01}, +- {0x3731, 0x02}, +- {0x370b, 0x60}, +- {0x3705, 0x1a}, +- {0x3f05, 0x02}, +- {0x3f06, 0x10}, +- {0x3f01, 0x0a}, +- {0x3a08, 0x01}, + {0x3a09, 0x4b}, + {0x3a0a, 0x01}, + {0x3a0b, 0x13}, + {0x3a0d, 0x04}, + {0x3a0e, 0x03}, +- {0x3a0f, 0x58}, +- {0x3a10, 0x50}, +- {0x3a1b, 0x58}, +- {0x3a1e, 0x50}, +- {0x3a11, 0x60}, +- {0x3a1f, 0x28}, +- {0x4001, 0x02}, + {0x4004, 0x04}, +- {0x4000, 0x09}, + {0x4837, 0x19}, + {0x4800, 0x34}, +- {0x3503, 0x03}, + {0x0100, 0x01}, + }; + + static struct regval_list ov5647_2x2binned_10bpp[] = { +- {0x0100, 0x00}, +- {0x0103, 0x01}, +- {0x3034, 0x1a}, +- {0x3035, 0x21}, + {0x3036, 0x62}, +- {0x303c, 0x11}, +- {0x3106, 0xf5}, + {0x3821, 0x01}, + {0x3820, 0x41}, +- {0x3827, 0xec}, +- {0x370c, 0x03}, + {0x3612, 0x59}, + {0x3618, 0x00}, +- {0x5000, 0x06}, + {0x5002, 0x41}, +- {0x5003, 0x08}, +- {0x5a00, 0x08}, +- {0x3000, 0x00}, +- {0x3001, 0x00}, +- {0x3002, 0x00}, +- {0x3016, 0x08}, +- {0x3017, 0xe0}, +- {0x3018, 0x44}, +- {0x301c, 0xf8}, +- {0x301d, 0xf0}, +- {0x3a18, 0x00}, +- {0x3a19, 0xf8}, +- {0x3c01, 0x80}, +- {0x3b07, 0x0c}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, +@@ -382,42 +311,14 @@ static struct regval_list ov5647_2x2binn + {0x3813, 0x06}, + {0x3814, 0x31}, + {0x3815, 0x31}, +- {0x3630, 0x2e}, +- {0x3632, 0xe2}, +- {0x3633, 0x23}, +- {0x3634, 0x44}, +- {0x3636, 0x06}, +- {0x3620, 0x64}, +- {0x3621, 0xe0}, +- {0x3600, 0x37}, +- {0x3704, 0xa0}, +- {0x3703, 0x5a}, +- {0x3715, 0x78}, +- {0x3717, 0x01}, +- {0x3731, 0x02}, +- {0x370b, 0x60}, +- {0x3705, 0x1a}, +- {0x3f05, 0x02}, +- {0x3f06, 0x10}, +- {0x3f01, 0x0a}, +- {0x3a08, 0x01}, + {0x3a09, 0x28}, + {0x3a0a, 0x00}, + {0x3a0b, 0xf6}, + {0x3a0d, 0x08}, + {0x3a0e, 0x06}, +- {0x3a0f, 0x58}, +- {0x3a10, 0x50}, +- {0x3a1b, 0x58}, +- {0x3a1e, 0x50}, +- {0x3a11, 0x60}, +- {0x3a1f, 0x28}, +- {0x4001, 0x02}, + {0x4004, 0x04}, +- {0x4000, 0x09}, + {0x4837, 0x16}, + {0x4800, 0x24}, +- {0x3503, 0x03}, + {0x350a, 0x00}, + {0x350b, 0x10}, + {0x3500, 0x00}, +@@ -428,42 +329,15 @@ static struct regval_list ov5647_2x2binn + }; + + static struct regval_list ov5647_640x480_10bpp[] = { +- {0x0100, 0x00}, +- {0x0103, 0x01}, +- {0x3034, 0x1a}, +- {0x3035, 0x21}, + {0x3036, 0x46}, +- {0x303c, 0x11}, +- {0x3106, 0xf5}, + {0x3821, 0x01}, + {0x3820, 0x41}, +- {0x3827, 0xec}, +- {0x370c, 0x03}, + {0x3612, 0x59}, + {0x3618, 0x00}, +- {0x5000, 0x06}, +- {0x5003, 0x08}, +- {0x5a00, 0x08}, +- {0x3000, 0x00}, +- {0x3001, 0x00}, +- {0x3002, 0x00}, +- {0x3016, 0x08}, +- {0x3017, 0xe0}, +- {0x3018, 0x44}, +- {0x301c, 0xf8}, +- {0x301d, 0xf0}, +- {0x3a18, 0x00}, +- {0x3a19, 0xf8}, +- {0x3c01, 0x80}, +- {0x3b07, 0x0c}, + {0x3814, 0x35}, + {0x3815, 0x35}, + {0x3708, 0x64}, + {0x3709, 0x52}, +- {0x3808, 0x02}, +- {0x3809, 0x80}, +- {0x380a, 0x01}, +- {0x380b, 0xe0}, + {0x3800, 0x00}, + {0x3801, 0x10}, + {0x3802, 0x00}, +@@ -472,41 +346,17 @@ static struct regval_list ov5647_640x480 + {0x3805, 0x2f}, + {0x3806, 0x07}, + {0x3807, 0x9f}, +- {0x3630, 0x2e}, +- {0x3632, 0xe2}, +- {0x3633, 0x23}, +- {0x3634, 0x44}, +- {0x3636, 0x06}, +- {0x3620, 0x64}, +- {0x3621, 0xe0}, +- {0x3600, 0x37}, +- {0x3704, 0xa0}, +- {0x3703, 0x5a}, +- {0x3715, 0x78}, +- {0x3717, 0x01}, +- {0x3731, 0x02}, +- {0x370b, 0x60}, +- {0x3705, 0x1a}, +- {0x3f05, 0x02}, +- {0x3f06, 0x10}, +- {0x3f01, 0x0a}, +- {0x3a08, 0x01}, ++ {0x3808, 0x02}, ++ {0x3809, 0x80}, ++ {0x380a, 0x01}, ++ {0x380b, 0xe0}, + {0x3a09, 0x2e}, + {0x3a0a, 0x00}, + {0x3a0b, 0xfb}, + {0x3a0d, 0x02}, + {0x3a0e, 0x01}, +- {0x3a0f, 0x58}, +- {0x3a10, 0x50}, +- {0x3a1b, 0x58}, +- {0x3a1e, 0x50}, +- {0x3a11, 0x60}, +- {0x3a1f, 0x28}, +- {0x4001, 0x02}, + {0x4004, 0x02}, +- {0x4000, 0x09}, + {0x4800, 0x34}, +- {0x3503, 0x03}, + {0x0100, 0x01}, + }; + +@@ -715,6 +565,13 @@ static int ov5647_set_mode(struct v4l2_s + if (ret < 0) + return ret; + ++ ret = ov5647_write_array(sd, ov5647_common_regs, ++ ARRAY_SIZE(ov5647_common_regs)); ++ if (ret < 0) { ++ dev_err(&client->dev, "write sensor common regs error\n"); ++ return ret; ++ } ++ + ret = ov5647_write_array(sd, sensor->mode->reg_list, + sensor->mode->num_regs); + if (ret < 0) { diff --git a/target/linux/bcm27xx/patches-6.6/950-1329-media-i2c-ov5647-Use-the-same-PLL-config-for-full-10.patch b/target/linux/bcm27xx/patches-6.6/950-1329-media-i2c-ov5647-Use-the-same-PLL-config-for-full-10.patch new file mode 100644 index 000000000000..c272951c6ff3 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1329-media-i2c-ov5647-Use-the-same-PLL-config-for-full-10.patch @@ -0,0 +1,53 @@ +From 35e5c3d706cbe686e3468d9f24ae999212553893 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 15 Oct 2024 19:36:13 +0100 +Subject: [PATCH 1329/1350] media: i2c: ov5647: Use the same PLL config for + full, 1080p, and binned modes + +In order to simplify the driver slightly, use the same PLL +configuration, and hence pixel rate and link frequency (to be +added) for the full, 1080p, and binned modes. + +Signed-off-by: Dave Stevenson +--- + drivers/media/i2c/ov5647.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/media/i2c/ov5647.c ++++ b/drivers/media/i2c/ov5647.c +@@ -253,7 +253,7 @@ static struct regval_list ov5647_2592x19 + }; + + static struct regval_list ov5647_1080p30_10bpp[] = { +- {0x3036, 0x62}, ++ {0x3036, 0x69}, + {0x3821, 0x00}, + {0x3820, 0x00}, + {0x3612, 0x5b}, +@@ -289,7 +289,7 @@ static struct regval_list ov5647_1080p30 + }; + + static struct regval_list ov5647_2x2binned_10bpp[] = { +- {0x3036, 0x62}, ++ {0x3036, 0x69}, + {0x3821, 0x01}, + {0x3820, 0x41}, + {0x3612, 0x59}, +@@ -397,7 +397,7 @@ static const struct ov5647_mode ov5647_m + .width = 1928, + .height = 1080, + }, +- .pixel_rate = 81666700, ++ .pixel_rate = 87500000, + .hts = 2416, + .vts = 0x450, + .reg_list = ov5647_1080p30_10bpp, +@@ -418,7 +418,7 @@ static const struct ov5647_mode ov5647_m + .width = 2592, + .height = 1944, + }, +- .pixel_rate = 81666700, ++ .pixel_rate = 87500000, + .hts = 1896, + .vts = 0x59b, + .reg_list = ov5647_2x2binned_10bpp, diff --git a/target/linux/bcm27xx/patches-6.6/950-1330-media-i2c-ov5647-Add-V4L2_CID_LINK_FREQUENCY-control.patch b/target/linux/bcm27xx/patches-6.6/950-1330-media-i2c-ov5647-Add-V4L2_CID_LINK_FREQUENCY-control.patch new file mode 100644 index 000000000000..efe47592d7c6 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1330-media-i2c-ov5647-Add-V4L2_CID_LINK_FREQUENCY-control.patch @@ -0,0 +1,111 @@ +From 84ab77459e61c648299d32464127b89ca65de40a Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 15 Oct 2024 19:46:01 +0100 +Subject: [PATCH 1330/1350] media: i2c: ov5647: Add V4L2_CID_LINK_FREQUENCY + control + +The link frequency can vary between modes, so add it as a +control. + +Signed-off-by: Dave Stevenson +--- + drivers/media/i2c/ov5647.c | 25 ++++++++++++++++++++++++- + 1 file changed, 24 insertions(+), 1 deletion(-) + +--- a/drivers/media/i2c/ov5647.c ++++ b/drivers/media/i2c/ov5647.c +@@ -97,6 +97,13 @@ static const char * const ov5647_supply_ + + #define OV5647_NUM_SUPPLIES ARRAY_SIZE(ov5647_supply_names) + ++#define FREQ_INDEX_FULL 0 ++#define FREQ_INDEX_VGA 1 ++static const s64 ov5647_link_freqs[] = { ++ [FREQ_INDEX_FULL] = 218500000, ++ [FREQ_INDEX_VGA] = 208333000, ++}; ++ + struct regval_list { + u16 addr; + u8 data; +@@ -106,6 +113,7 @@ struct ov5647_mode { + struct v4l2_mbus_framefmt format; + struct v4l2_rect crop; + u64 pixel_rate; ++ unsigned int link_freq_index; + int hts; + int vts; + const struct regval_list *reg_list; +@@ -128,6 +136,7 @@ struct ov5647 { + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; ++ struct v4l2_ctrl *link_freq; + bool streaming; + }; + +@@ -377,6 +386,7 @@ static const struct ov5647_mode ov5647_m + .height = 1944 + }, + .pixel_rate = 87500000, ++ .link_freq_index = FREQ_INDEX_FULL, + .hts = 2844, + .vts = 0x7b0, + .reg_list = ov5647_2592x1944_10bpp, +@@ -398,6 +408,7 @@ static const struct ov5647_mode ov5647_m + .height = 1080, + }, + .pixel_rate = 87500000, ++ .link_freq_index = FREQ_INDEX_FULL, + .hts = 2416, + .vts = 0x450, + .reg_list = ov5647_1080p30_10bpp, +@@ -419,6 +430,7 @@ static const struct ov5647_mode ov5647_m + .height = 1944, + }, + .pixel_rate = 87500000, ++ .link_freq_index = FREQ_INDEX_FULL, + .hts = 1896, + .vts = 0x59b, + .reg_list = ov5647_2x2binned_10bpp, +@@ -440,6 +452,7 @@ static const struct ov5647_mode ov5647_m + .height = 1920, + }, + .pixel_rate = 55000000, ++ .link_freq_index = FREQ_INDEX_VGA, + .hts = 1852, + .vts = 0x1f8, + .reg_list = ov5647_640x480_10bpp, +@@ -943,6 +956,8 @@ static int ov5647_set_pad_fmt(struct v4l + sensor->exposure->minimum, + exposure_max, sensor->exposure->step, + exposure_def); ++ ++ __v4l2_ctrl_s_ctrl(sensor->link_freq, mode->link_freq_index); + } + *fmt = mode->format; + /* The code we pass back must reflect the current h/vflips. */ +@@ -1248,7 +1263,7 @@ static int ov5647_init_controls(struct o + int hblank, exposure_max, exposure_def; + struct v4l2_fwnode_device_properties props; + +- v4l2_ctrl_handler_init(&sensor->ctrls, 9); ++ v4l2_ctrl_handler_init(&sensor->ctrls, 10); + + v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 0); +@@ -1308,6 +1323,14 @@ static int ov5647_init_controls(struct o + if (sensor->vflip) + sensor->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + ++ sensor->link_freq = ++ v4l2_ctrl_new_int_menu(&sensor->ctrls, &ov5647_ctrl_ops, ++ V4L2_CID_LINK_FREQ, ++ ARRAY_SIZE(ov5647_link_freqs) - 1, 0, ++ ov5647_link_freqs); ++ if (sensor->link_freq) ++ sensor->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ + v4l2_fwnode_device_parse(dev, &props); + + v4l2_ctrl_new_fwnode_properties(&sensor->ctrls, &ov5647_ctrl_ops, diff --git a/target/linux/bcm27xx/patches-6.6/950-1331-mmc-don-t-reference-requests-after-finishing-them.patch b/target/linux/bcm27xx/patches-6.6/950-1331-mmc-don-t-reference-requests-after-finishing-them.patch new file mode 100644 index 000000000000..c7d411f0e3d0 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1331-mmc-don-t-reference-requests-after-finishing-them.patch @@ -0,0 +1,71 @@ +From b80d5d1d5148a89121e3759bb4caa27e7ee1cf05 Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Tue, 15 Oct 2024 11:22:53 +0100 +Subject: [PATCH 1331/1350] mmc: don't reference requests after finishing them + +Posted write tracking introduced in the commit below raced with re-use +of the requests between completion and submission, potentially causing +underflow of the pending write count. + +Fixes: e6c1e862b2b8 ("mmc: restrict posted write counts for SD cards in CQ mode") + +Signed-off-by: Jonathan Bell +--- + drivers/mmc/core/block.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +--- a/drivers/mmc/core/block.c ++++ b/drivers/mmc/core/block.c +@@ -1524,6 +1524,7 @@ static void mmc_blk_cqe_complete_rq(stru + struct request_queue *q = req->q; + struct mmc_host *host = mq->card->host; + enum mmc_issue_type issue_type = mmc_issue_type(mq, req); ++ bool write = req_op(req) == REQ_OP_WRITE; + unsigned long flags; + bool put_card; + int err; +@@ -1555,7 +1556,7 @@ static void mmc_blk_cqe_complete_rq(stru + + spin_lock_irqsave(&mq->lock, flags); + +- if (req_op(req) == REQ_OP_WRITE) ++ if (write) + mq->pending_writes--; + mq->in_flight[issue_type] -= 1; + +@@ -2170,15 +2171,16 @@ static void mmc_blk_mq_poll_completion(s + } + + static void mmc_blk_mq_dec_in_flight(struct mmc_queue *mq, enum mmc_issue_type issue_type, +- struct request *req) ++ bool write) + { + unsigned long flags; + bool put_card; + + spin_lock_irqsave(&mq->lock, flags); + +- if (req_op(req) == REQ_OP_WRITE) ++ if (write) + mq->pending_writes--; ++ + mq->in_flight[issue_type] -= 1; + + put_card = (mmc_tot_in_flight(mq) == 0); +@@ -2193,6 +2195,7 @@ static void mmc_blk_mq_post_req(struct m + bool can_sleep) + { + enum mmc_issue_type issue_type = mmc_issue_type(mq, req); ++ bool write = req_op(req) == REQ_OP_WRITE; + struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req); + struct mmc_request *mrq = &mqrq->brq.mrq; + struct mmc_host *host = mq->card->host; +@@ -2212,7 +2215,7 @@ static void mmc_blk_mq_post_req(struct m + blk_mq_complete_request(req); + } + +- mmc_blk_mq_dec_in_flight(mq, issue_type, req); ++ mmc_blk_mq_dec_in_flight(mq, issue_type, write); + } + + void mmc_blk_mq_recovery(struct mmc_queue *mq) diff --git a/target/linux/bcm27xx/patches-6.6/950-1333-mmc-quirks-disable-cache-on-more-known-bad-Sandisk-c.patch b/target/linux/bcm27xx/patches-6.6/950-1333-mmc-quirks-disable-cache-on-more-known-bad-Sandisk-c.patch new file mode 100644 index 000000000000..109c502e13f6 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1333-mmc-quirks-disable-cache-on-more-known-bad-Sandisk-c.patch @@ -0,0 +1,35 @@ +From 4d702b5c68d6449d81281677f71de557f64cdce5 Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Tue, 15 Oct 2024 14:35:42 +0100 +Subject: [PATCH 1333/1350] mmc: quirks: disable cache on more known-bad + Sandisk card date ranges + +Cards with manufacture dates in 2019 and 2020 have been seen in the wild +that hang indefinitely if issued a cache flush command in CQ mode. + +Signed-off-by: Jonathan Bell +--- + drivers/mmc/core/quirks.h | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/drivers/mmc/core/quirks.h ++++ b/drivers/mmc/core/quirks.h +@@ -33,6 +33,18 @@ static const struct mmc_fixup __maybe_un + 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd, + MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY), + ++ /* ++ * Early Sandisk Extreme and Extreme Pro A2 cards never finish SD cache ++ * flush in CQ mode. Latest card date this was seen on is 10/2020. ++ */ ++ _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_SANDISK_SD, 0x5344, 2019, CID_MONTH_ANY, ++ 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd, ++ MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY), ++ ++ _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_SANDISK_SD, 0x5344, 2020, CID_MONTH_ANY, ++ 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd, ++ MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY), ++ + END_FIXUP + }; + diff --git a/target/linux/bcm27xx/patches-6.6/950-1334-mmc-block-disable-CQ-on-SD-cards-when-doing-non-Disc.patch b/target/linux/bcm27xx/patches-6.6/950-1334-mmc-block-disable-CQ-on-SD-cards-when-doing-non-Disc.patch new file mode 100644 index 000000000000..72a87e5978c6 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1334-mmc-block-disable-CQ-on-SD-cards-when-doing-non-Disc.patch @@ -0,0 +1,55 @@ +From 73ddacb555c5ef1f063f44b4ec3268da899ff8b5 Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Fri, 18 Oct 2024 13:11:11 +0100 +Subject: [PATCH 1334/1350] mmc: block: disable CQ on SD cards when doing + non-Discard erase + +Only CMD38 with Arg=0x1 (Discard) is supported when in CQ mode, so +turn it off before issuing a non-discard erase op. + +Signed-off-by: Jonathan Bell +--- + drivers/mmc/core/block.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +--- a/drivers/mmc/core/block.c ++++ b/drivers/mmc/core/block.c +@@ -1177,12 +1177,26 @@ static void mmc_blk_issue_erase_rq(struc + unsigned int from, nr; + int err = 0; + blk_status_t status = BLK_STS_OK; ++ bool restart_cmdq = false; + + if (!mmc_can_erase(card)) { + status = BLK_STS_NOTSUPP; + goto fail; + } + ++ /* ++ * Only Discard ops are supported with SD cards in CQ mode ++ * (SD Physical Spec v9.00 4.19.2) ++ */ ++ if (mmc_card_sd(card) && card->ext_csd.cmdq_en && erase_arg != SD_DISCARD_ARG) { ++ restart_cmdq = true; ++ err = mmc_sd_cmdq_disable(card); ++ if (err) { ++ status = BLK_STS_IOERR; ++ goto fail; ++ } ++ } ++ + from = blk_rq_pos(req); + nr = blk_rq_sectors(req); + +@@ -1203,6 +1217,11 @@ static void mmc_blk_issue_erase_rq(struc + status = BLK_STS_IOERR; + else + mmc_blk_reset_success(md, type); ++ ++ if (restart_cmdq) ++ err = mmc_sd_cmdq_enable(card); ++ if (err) ++ status = BLK_STS_IOERR; + fail: + blk_mq_end_request(req, status); + } diff --git a/target/linux/bcm27xx/patches-6.6/950-1208-DTS-bcm2712-enable-SD-slot-CQE-by-default-on-Pi-5.patch b/target/linux/bcm27xx/patches-6.6/950-1335-DTS-bcm2712-re-enable-SD-slot-CQE-by-default-on-Pi-5.patch similarity index 77% rename from target/linux/bcm27xx/patches-6.6/950-1208-DTS-bcm2712-enable-SD-slot-CQE-by-default-on-Pi-5.patch rename to target/linux/bcm27xx/patches-6.6/950-1335-DTS-bcm2712-re-enable-SD-slot-CQE-by-default-on-Pi-5.patch index 16e760349817..e6260e7249c0 100644 --- a/target/linux/bcm27xx/patches-6.6/950-1208-DTS-bcm2712-enable-SD-slot-CQE-by-default-on-Pi-5.patch +++ b/target/linux/bcm27xx/patches-6.6/950-1335-DTS-bcm2712-re-enable-SD-slot-CQE-by-default-on-Pi-5.patch @@ -1,10 +1,10 @@ -From 216df57950849f905c398904e7d6cbdf278b5717 Mon Sep 17 00:00:00 2001 +From 48a15bc46004025776880a091d47a22e03449acc Mon Sep 17 00:00:00 2001 From: Jonathan Bell -Date: Mon, 5 Aug 2024 11:28:36 +0100 -Subject: [PATCH 1208/1215] DTS: bcm2712: enable SD slot CQE by default on Pi 5 +Date: Fri, 18 Oct 2024 14:06:01 +0100 +Subject: [PATCH 1335/1350] DTS: bcm2712; re-enable SD slot CQE by default on + Pi 5 -The corresponding driver implementation has seen sufficient testing, -so enable by default. Retain the dtparam so it can be turned off for test. +This reverts commit 1b92c9369569137d8f2b8bf82884a05999e1f73b. Signed-off-by: Jonathan Bell --- @@ -29,7 +29,7 @@ Signed-off-by: Jonathan Bell requests 50MHz --- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts +++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts -@@ -363,6 +363,7 @@ dpi_16bit_gpio2: &rp1_dpi_16bit_g +@@ -365,6 +365,7 @@ dpi_16bit_gpio2: &rp1_dpi_16bit_g sd-uhs-sdr50; sd-uhs-ddr50; sd-uhs-sdr104; diff --git a/target/linux/bcm27xx/patches-6.6/950-1336-mmc-quirks-add-MMC_QUIRK_BROKEN_ERASE-for-Phison-Int.patch b/target/linux/bcm27xx/patches-6.6/950-1336-mmc-quirks-add-MMC_QUIRK_BROKEN_ERASE-for-Phison-Int.patch new file mode 100644 index 000000000000..ba61b15ea157 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1336-mmc-quirks-add-MMC_QUIRK_BROKEN_ERASE-for-Phison-Int.patch @@ -0,0 +1,33 @@ +From 527d6f5a7861e24c60d41e9706ec4589165321d1 Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Fri, 18 Oct 2024 16:01:28 +0100 +Subject: [PATCH 1336/1350] mmc: quirks: add MMC_QUIRK_BROKEN_ERASE for + Phison/Integral cards + +Recent Integral cards end up with corrupt sectors after a flash erase. +This covers sizes for the A2 range, which can't be differentiated from +the A1 range which might not have the same issue. + +Signed-off-by: Jonathan Bell +--- + drivers/mmc/core/quirks.h | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/drivers/mmc/core/quirks.h ++++ b/drivers/mmc/core/quirks.h +@@ -162,6 +162,15 @@ static const struct mmc_fixup __maybe_un + MMC_FIXUP("SD32G", 0x41, 0x3432, add_quirk, MMC_QUIRK_ERASE_BROKEN), + MMC_FIXUP("SD64G", 0x41, 0x3432, add_quirk, MMC_QUIRK_ERASE_BROKEN), + ++ /* ++ * Larger Integral SD cards using rebranded Phison controllers trash ++ * nearby flash blocks after erases. ++ */ ++ MMC_FIXUP("SD64G", 0x27, 0x5048, add_quirk, MMC_QUIRK_ERASE_BROKEN), ++ MMC_FIXUP("SD128", 0x27, 0x5048, add_quirk, MMC_QUIRK_ERASE_BROKEN), ++ MMC_FIXUP("SD256", 0x27, 0x5048, add_quirk, MMC_QUIRK_ERASE_BROKEN), ++ MMC_FIXUP("SD512", 0x27, 0x5048, add_quirk, MMC_QUIRK_ERASE_BROKEN), ++ + END_FIXUP + }; + diff --git a/target/linux/bcm27xx/patches-6.6/950-1337-Input-matrix_keypad-avoid-repeatedly-converting-GPIO.patch b/target/linux/bcm27xx/patches-6.6/950-1337-Input-matrix_keypad-avoid-repeatedly-converting-GPIO.patch new file mode 100644 index 000000000000..d9a7a10cd445 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1337-Input-matrix_keypad-avoid-repeatedly-converting-GPIO.patch @@ -0,0 +1,155 @@ +From 25b2b36dea57fd86b63df2e253b376532d314a30 Mon Sep 17 00:00:00 2001 +From: Dmitry Torokhov +Date: Sat, 20 Jan 2024 21:32:28 -0800 +Subject: [PATCH 1337/1350] Input: matrix_keypad - avoid repeatedly converting + GPIO to IRQ + +commit a96fb711c6be76bcfbcf594a865002fa7c0eb525 upstream. + +There is no need to do conversion from GPIOs to interrupt numbers. +Convert row GPIOs to interrupt numbers once in probe() and use +this information when the driver needs to enable or disable given +interrupt line. + +Link: https://lore.kernel.org/r/20240121053232.276968-1-dmitry.torokhov@gmail.com +Signed-off-by: Dmitry Torokhov +--- + drivers/input/keyboard/matrix_keypad.c | 48 ++++++++++++++------------ + 1 file changed, 25 insertions(+), 23 deletions(-) + +--- a/drivers/input/keyboard/matrix_keypad.c ++++ b/drivers/input/keyboard/matrix_keypad.c +@@ -27,6 +27,7 @@ struct matrix_keypad { + const struct matrix_keypad_platform_data *pdata; + struct input_dev *input_dev; + unsigned int row_shift; ++ unsigned int row_irqs[MATRIX_MAX_ROWS]; + + DECLARE_BITMAP(disabled_gpios, MATRIX_MAX_ROWS); + +@@ -92,7 +93,7 @@ static void enable_row_irqs(struct matri + enable_irq(pdata->clustered_irq); + else { + for (i = 0; i < pdata->num_row_gpios; i++) +- enable_irq(gpio_to_irq(pdata->row_gpios[i])); ++ enable_irq(keypad->row_irqs[i]); + } + } + +@@ -105,7 +106,7 @@ static void disable_row_irqs(struct matr + disable_irq_nosync(pdata->clustered_irq); + else { + for (i = 0; i < pdata->num_row_gpios; i++) +- disable_irq_nosync(gpio_to_irq(pdata->row_gpios[i])); ++ disable_irq_nosync(keypad->row_irqs[i]); + } + } + +@@ -233,7 +234,6 @@ static void matrix_keypad_stop(struct in + static void matrix_keypad_enable_wakeup(struct matrix_keypad *keypad) + { + const struct matrix_keypad_platform_data *pdata = keypad->pdata; +- unsigned int gpio; + int i; + + if (pdata->clustered_irq > 0) { +@@ -241,21 +241,16 @@ static void matrix_keypad_enable_wakeup( + keypad->gpio_all_disabled = true; + } else { + +- for (i = 0; i < pdata->num_row_gpios; i++) { +- if (!test_bit(i, keypad->disabled_gpios)) { +- gpio = pdata->row_gpios[i]; +- +- if (enable_irq_wake(gpio_to_irq(gpio)) == 0) ++ for (i = 0; i < pdata->num_row_gpios; i++) ++ if (!test_bit(i, keypad->disabled_gpios)) ++ if (enable_irq_wake(keypad->row_irqs[i]) == 0) + __set_bit(i, keypad->disabled_gpios); +- } +- } + } + } + + static void matrix_keypad_disable_wakeup(struct matrix_keypad *keypad) + { + const struct matrix_keypad_platform_data *pdata = keypad->pdata; +- unsigned int gpio; + int i; + + if (pdata->clustered_irq > 0) { +@@ -264,12 +259,9 @@ static void matrix_keypad_disable_wakeup + keypad->gpio_all_disabled = false; + } + } else { +- for (i = 0; i < pdata->num_row_gpios; i++) { +- if (test_and_clear_bit(i, keypad->disabled_gpios)) { +- gpio = pdata->row_gpios[i]; +- disable_irq_wake(gpio_to_irq(gpio)); +- } +- } ++ for (i = 0; i < pdata->num_row_gpios; i++) ++ if (test_and_clear_bit(i, keypad->disabled_gpios)) ++ disable_irq_wake(keypad->row_irqs[i]); + } + } + +@@ -306,7 +298,7 @@ static int matrix_keypad_init_gpio(struc + struct matrix_keypad *keypad) + { + const struct matrix_keypad_platform_data *pdata = keypad->pdata; +- int i, err; ++ int i, irq, err; + + /* initialized strobe lines as outputs, activated */ + for (i = 0; i < pdata->num_col_gpios; i++) { +@@ -345,11 +337,19 @@ static int matrix_keypad_init_gpio(struc + } + } else { + for (i = 0; i < pdata->num_row_gpios; i++) { +- err = request_any_context_irq( +- gpio_to_irq(pdata->row_gpios[i]), ++ irq = gpio_to_irq(pdata->row_gpios[i]); ++ if (irq < 0) { ++ err = irq; ++ dev_err(&pdev->dev, ++ "Unable to convert GPIO line %i to irq: %d\n", ++ pdata->row_gpios[i], err); ++ goto err_free_irqs; ++ } ++ ++ err = request_any_context_irq(irq, + matrix_keypad_interrupt, + IRQF_TRIGGER_RISING | +- IRQF_TRIGGER_FALLING, ++ IRQF_TRIGGER_FALLING, + "matrix-keypad", keypad); + if (err < 0) { + dev_err(&pdev->dev, +@@ -357,6 +357,8 @@ static int matrix_keypad_init_gpio(struc + pdata->row_gpios[i]); + goto err_free_irqs; + } ++ ++ keypad->row_irqs[i] = irq; + } + } + +@@ -366,7 +368,7 @@ static int matrix_keypad_init_gpio(struc + + err_free_irqs: + while (--i >= 0) +- free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad); ++ free_irq(keypad->row_irqs[i], keypad); + i = pdata->num_row_gpios; + err_free_rows: + while (--i >= 0) +@@ -388,7 +390,7 @@ static void matrix_keypad_free_gpio(stru + free_irq(pdata->clustered_irq, keypad); + } else { + for (i = 0; i < pdata->num_row_gpios; i++) +- free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad); ++ free_irq(keypad->row_irqs[i], keypad); + } + + for (i = 0; i < pdata->num_row_gpios; i++) diff --git a/target/linux/bcm27xx/patches-6.6/950-1338-numa-Add-simple-generic-NUMA-emulation.patch b/target/linux/bcm27xx/patches-6.6/950-1338-numa-Add-simple-generic-NUMA-emulation.patch new file mode 100644 index 000000000000..afb1bf7c9ab1 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1338-numa-Add-simple-generic-NUMA-emulation.patch @@ -0,0 +1,182 @@ +From b1a0f9c705912ec0434645f2d2bcf914c635564d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ma=C3=ADra=20Canal?= +Date: Fri, 17 May 2024 11:40:23 -0300 +Subject: [PATCH 1338/1350] numa: Add simple generic NUMA emulation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add some common code for splitting the memory into N emulated NUMA memory +nodes. + +Individual architecture can then enable selecting this option and use the +existing numa=fake= kernel argument to enable it. + +Memory is always split into equally sized chunks. + +Signed-off-by: Maíra Canal +Co-developed-by: Tvrtko Ursulin +Signed-off-by: Tvrtko Ursulin +Cc: Catalin Marinas +Cc: Will Deacon +Cc: Greg Kroah-Hartman +Cc: “Rafael J. Wysocki" +--- + drivers/base/Kconfig | 7 ++++ + drivers/base/Makefile | 1 + + drivers/base/arch_numa.c | 6 ++++ + drivers/base/numa_emulation.c | 67 +++++++++++++++++++++++++++++++++++ + drivers/base/numa_emulation.h | 21 +++++++++++ + 5 files changed, 102 insertions(+) + create mode 100644 drivers/base/numa_emulation.c + create mode 100644 drivers/base/numa_emulation.h + +--- a/drivers/base/Kconfig ++++ b/drivers/base/Kconfig +@@ -230,6 +230,13 @@ config GENERIC_ARCH_NUMA + Enable support for generic NUMA implementation. Currently, RISC-V + and ARM64 use it. + ++config GENERIC_ARCH_NUMA_EMULATION ++ bool ++ depends on GENERIC_ARCH_NUMA ++ help ++ Enable NUMA emulation. Note that NUMA emulation will only be used if ++ the machine has no NUMA node. ++ + config FW_DEVLINK_SYNC_STATE_TIMEOUT + bool "sync_state() behavior defaults to timeout instead of strict" + help +--- a/drivers/base/Makefile ++++ b/drivers/base/Makefile +@@ -25,6 +25,7 @@ obj-$(CONFIG_DEV_COREDUMP) += devcoredum + obj-$(CONFIG_GENERIC_MSI_IRQ) += platform-msi.o + obj-$(CONFIG_GENERIC_ARCH_TOPOLOGY) += arch_topology.o + obj-$(CONFIG_GENERIC_ARCH_NUMA) += arch_numa.o ++obj-$(CONFIG_GENERIC_ARCH_NUMA_EMULATION) += numa_emulation.o + obj-$(CONFIG_ACPI) += physical_location.o + + obj-y += test/ +--- a/drivers/base/arch_numa.c ++++ b/drivers/base/arch_numa.c +@@ -15,6 +15,8 @@ + + #include + ++#include "numa_emulation.h" ++ + struct pglist_data *node_data[MAX_NUMNODES] __read_mostly; + EXPORT_SYMBOL(node_data); + nodemask_t numa_nodes_parsed __initdata; +@@ -30,6 +32,8 @@ static __init int numa_parse_early_param + return -EINVAL; + if (str_has_prefix(opt, "off")) + numa_off = true; ++ if (str_has_prefix(opt, "fake=")) ++ return numa_emu_cmdline(opt + 5); + + return 0; + } +@@ -471,6 +475,8 @@ void __init arch_numa_init(void) + return; + if (acpi_disabled && !numa_init(of_numa_init)) + return; ++ if (!numa_init(numa_emu_init)) ++ return; + } + + numa_init(dummy_numa_init); +--- /dev/null ++++ b/drivers/base/numa_emulation.c +@@ -0,0 +1,67 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Simple NUMA emulation. ++ * ++ * Copyright © 2024 Raspberry Pi Ltd ++ * ++ * Author: Maíra Canal ++ * Author: Tvrtko Ursulin ++ */ ++#include ++ ++#include "numa_emulation.h" ++ ++static unsigned int emu_nodes; ++ ++int __init numa_emu_cmdline(char *str) ++{ ++ int ret; ++ ++ ret = kstrtouint(str, 10, &emu_nodes); ++ if (ret) ++ return ret; ++ ++ if (emu_nodes > MAX_NUMNODES) { ++ pr_notice("numa=fake=%u too large, reducing to %u\n", ++ emu_nodes, MAX_NUMNODES); ++ emu_nodes = MAX_NUMNODES; ++ } ++ ++ return 0; ++} ++ ++int __init numa_emu_init(void) ++{ ++ phys_addr_t start, end; ++ unsigned long size; ++ unsigned int i; ++ int ret; ++ ++ if (!emu_nodes) ++ return -EINVAL; ++ ++ start = memblock_start_of_DRAM(); ++ end = memblock_end_of_DRAM() - 1; ++ ++ size = DIV_ROUND_DOWN_ULL(end - start + 1, emu_nodes); ++ size = PAGE_ALIGN_DOWN(size); ++ ++ for (i = 0; i < emu_nodes; i++) { ++ u64 s, e; ++ ++ s = start + i * size; ++ e = s + size - 1; ++ ++ if (i == (emu_nodes - 1) && e != end) ++ e = end; ++ ++ pr_info("Faking a node at [mem %pap-%pap]\n", &s, &e); ++ ret = numa_add_memblk(i, s, e + 1); ++ if (ret) { ++ pr_err("Failed to add fake NUMA node %d!\n", i); ++ break; ++ } ++ } ++ ++ return ret; ++} +--- /dev/null ++++ b/drivers/base/numa_emulation.h +@@ -0,0 +1,21 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * NUMA emulation header ++ * ++ * Copyright © 2024 Raspberry Pi Ltd ++ */ ++ ++#ifdef CONFIG_GENERIC_ARCH_NUMA_EMULATION ++int numa_emu_cmdline(char *str); ++int __init numa_emu_init(void); ++#else ++static inline int numa_emu_cmdline(char *str) ++{ ++ return -EINVAL; ++} ++ ++static int __init numa_emu_init(void) ++{ ++ return -EOPNOTSUPP; ++} ++#endif /* CONFIG_NUMA_EMU */ diff --git a/target/linux/bcm27xx/patches-6.6/950-1339-arm64-numa-Add-NUMA-emulation-for-ARM64.patch b/target/linux/bcm27xx/patches-6.6/950-1339-arm64-numa-Add-NUMA-emulation-for-ARM64.patch new file mode 100644 index 000000000000..169706de8c8d --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1339-arm64-numa-Add-NUMA-emulation-for-ARM64.patch @@ -0,0 +1,39 @@ +From 462346142b26dd1fd8f55655959e38b385acb1c1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ma=C3=ADra=20Canal?= +Date: Fri, 17 May 2024 11:40:34 -0300 +Subject: [PATCH 1339/1350] arm64/numa: Add NUMA emulation for ARM64 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Allow selecting NUMA emulation on arm64. + +Signed-off-by: Maíra Canal +Signed-off-by: Tvrtko Ursulin +Cc: Catalin Marinas +Cc: Will Deacon +Cc: Greg Kroah-Hartman +Cc: “Rafael J. Wysocki" +--- + arch/arm64/Kconfig | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/arch/arm64/Kconfig ++++ b/arch/arm64/Kconfig +@@ -1500,6 +1500,16 @@ config NODES_SHIFT + Specify the maximum number of NUMA Nodes available on the target + system. Increases memory reserved to accommodate various tables. + ++config NUMA_EMULATION ++ bool "NUMA emulation" ++ depends on NUMA ++ select GENERIC_ARCH_NUMA_EMULATION ++ help ++ Enable NUMA emulation support. A flat machine will be split into ++ virtual nodes when booted with "numa=fake=N", where N is the number ++ of nodes, the system RAM will be split into N equal chunks, and ++ assigned to each node. ++ + source "kernel/Kconfig.hz" + + config ARCH_SPARSEMEM_ENABLE diff --git a/target/linux/bcm27xx/patches-6.6/950-1340-mm-numa-Allow-override-of-kernel-s-default-NUMA-poli.patch b/target/linux/bcm27xx/patches-6.6/950-1340-mm-numa-Allow-override-of-kernel-s-default-NUMA-poli.patch new file mode 100644 index 000000000000..f0de0ce9d59b --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1340-mm-numa-Allow-override-of-kernel-s-default-NUMA-poli.patch @@ -0,0 +1,115 @@ +From 4bbdd9335a4784743a5ac30697f24972219559c2 Mon Sep 17 00:00:00 2001 +From: Tvrtko Ursulin +Date: Wed, 22 May 2024 17:12:16 +0100 +Subject: [PATCH 1340/1350] mm/numa: Allow override of kernel's default NUMA + policy + +Add numa_policy kernel argument to allow overriding the kernel's default +NUMA policy at boot time. + +Syntax identical to what tmpfs accepts as it's mpol argument is accepted. + +Some examples: + + numa_policy=interleave + numa_policy=interleave=skip-interleave + numa_policy=bind:0-3,5,7,9-15 + numa_policy=bind=static:1-2 + +Signed-off-by: Tvrtko Ursulin +--- + mm/mempolicy.c | 49 ++++++++++++++++++++++++++++++++++++++++++------- + 1 file changed, 42 insertions(+), 7 deletions(-) + +--- a/mm/mempolicy.c ++++ b/mm/mempolicy.c +@@ -2974,7 +2974,9 @@ void __init numa_policy_init(void) + /* Reset policy of current process to default */ + void numa_default_policy(void) + { +- do_set_mempolicy(MPOL_DEFAULT, 0, NULL); ++ struct mempolicy *pol = &default_policy; ++ ++ do_set_mempolicy(pol->mode, pol->flags, &pol->nodes); + } + + /* +@@ -2992,7 +2994,6 @@ static const char * const policy_modes[] + }; + + +-#ifdef CONFIG_TMPFS + /** + * mpol_parse_str - parse string to mempolicy, for tmpfs mpol mount option. + * @str: string containing mempolicy to parse +@@ -3005,13 +3006,18 @@ static const char * const policy_modes[] + */ + int mpol_parse_str(char *str, struct mempolicy **mpol) + { +- struct mempolicy *new = NULL; ++ struct mempolicy *new; + unsigned short mode_flags; + nodemask_t nodes; + char *nodelist = strchr(str, ':'); + char *flags = strchr(str, '='); + int err = 1, mode; + ++ if (*mpol) ++ new = *mpol; ++ else ++ new = NULL; ++ + if (flags) + *flags++ = '\0'; /* terminate mode string */ + +@@ -3090,9 +3096,16 @@ int mpol_parse_str(char *str, struct mem + goto out; + } + +- new = mpol_new(mode, mode_flags, &nodes); +- if (IS_ERR(new)) +- goto out; ++ if (!new) { ++ new = mpol_new(mode, mode_flags, &nodes); ++ if (IS_ERR(new)) ++ goto out; ++ } else { ++ atomic_set(&new->refcnt, 1); ++ new->mode = mode; ++ new->flags = mode_flags; ++ new->home_node = NUMA_NO_NODE; ++ } + + /* + * Save nodes for mpol_to_str() to show the tmpfs mount options +@@ -3125,7 +3138,29 @@ out: + *mpol = new; + return err; + } +-#endif /* CONFIG_TMPFS */ ++ ++static int __init setup_numapolicy(char *str) ++{ ++ struct mempolicy pol = { }, *ppol = &pol; ++ char buf[128]; ++ int ret; ++ ++ if (str) ++ ret = mpol_parse_str(str, &ppol); ++ else ++ ret = -EINVAL; ++ ++ if (!ret) { ++ default_policy = pol; ++ mpol_to_str(buf, sizeof(buf), &pol); ++ pr_info("NUMA default policy overridden to '%s'\n", buf); ++ } else { ++ pr_warn("Unable to parse numa_policy=\n"); ++ } ++ ++ return ret == 0; ++} ++__setup("numa_policy=", setup_numapolicy); + + /** + * mpol_to_str - format a mempolicy structure for printing diff --git a/target/linux/bcm27xx/patches-6.6/950-1341-dma-buf-system_heap-Allow-specifying-maximum-allocat.patch b/target/linux/bcm27xx/patches-6.6/950-1341-dma-buf-system_heap-Allow-specifying-maximum-allocat.patch new file mode 100644 index 000000000000..db2268ea26be --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1341-dma-buf-system_heap-Allow-specifying-maximum-allocat.patch @@ -0,0 +1,46 @@ +From 56fda5adce0c9b4dc8ff2c7be9a704599e685001 Mon Sep 17 00:00:00 2001 +From: Tvrtko Ursulin +Date: Wed, 17 Jul 2024 09:33:21 +0100 +Subject: [PATCH 1341/1350] dma-buf: system_heap: Allow specifying maximum + allocation order + +system_heap.max_order= + +Signed-off-by: Tvrtko Ursulin +--- + drivers/dma-buf/heaps/system_heap.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +--- a/drivers/dma-buf/heaps/system_heap.c ++++ b/drivers/dma-buf/heaps/system_heap.c +@@ -54,6 +54,11 @@ static gfp_t order_flags[] = {HIGH_ORDER + static const unsigned int orders[] = {8, 4, 0}; + #define NUM_ORDERS ARRAY_SIZE(orders) + ++static unsigned int module_max_order = orders[0]; ++ ++module_param_named(max_order, module_max_order, uint, 0400); ++MODULE_PARM_DESC(max_order, "Maximum allocation order override."); ++ + static struct sg_table *dup_sg_table(struct sg_table *table) + { + struct sg_table *new_table; +@@ -339,7 +344,7 @@ static struct dma_buf *system_heap_alloc + struct system_heap_buffer *buffer; + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + unsigned long size_remaining = len; +- unsigned int max_order = orders[0]; ++ unsigned int max_order = module_max_order; + struct dma_buf *dmabuf; + struct sg_table *table; + struct scatterlist *sg; +@@ -433,6 +438,9 @@ static int system_heap_create(void) + if (IS_ERR(sys_heap)) + return PTR_ERR(sys_heap); + ++ if (module_max_order > orders[0]) ++ module_max_order = orders[0]; ++ + return 0; + } + module_init(system_heap_create); diff --git a/target/linux/bcm27xx/patches-6.6/950-1342-numa-emulation-Check-emulated-zones-around-the-CMA-w.patch b/target/linux/bcm27xx/patches-6.6/950-1342-numa-emulation-Check-emulated-zones-around-the-CMA-w.patch new file mode 100644 index 000000000000..cc459b6a569f --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1342-numa-emulation-Check-emulated-zones-around-the-CMA-w.patch @@ -0,0 +1,95 @@ +From a27d76f4517d56a6471def2f76687e83fd2a7923 Mon Sep 17 00:00:00 2001 +From: Tvrtko Ursulin +Date: Mon, 29 Jul 2024 16:53:18 +0100 +Subject: [PATCH 1342/1350] numa/emulation: Check emulated zones around the CMA + window + +... Make sure CMA zones do not straddle the emulated NUMA nodes ... + +Signed-off-by: Tvrtko Ursulin +--- + drivers/base/numa_emulation.c | 5 +++++ + include/linux/cma.h | 10 ++++++++++ + mm/cma.c | 36 +++++++++++++++++++++++++++++++++++ + 3 files changed, 51 insertions(+) + +--- a/drivers/base/numa_emulation.c ++++ b/drivers/base/numa_emulation.c +@@ -7,6 +7,7 @@ + * Author: Maíra Canal + * Author: Tvrtko Ursulin + */ ++#include + #include + + #include "numa_emulation.h" +@@ -55,6 +56,10 @@ int __init numa_emu_init(void) + if (i == (emu_nodes - 1) && e != end) + e = end; + ++ ret = cma_check_range(&s, &e); ++ if (ret) ++ return ret; ++ + pr_info("Faking a node at [mem %pap-%pap]\n", &s, &e); + ret = numa_add_memblk(i, s, e + 1); + if (ret) { +--- a/include/linux/cma.h ++++ b/include/linux/cma.h +@@ -56,4 +56,14 @@ extern bool cma_release(struct cma *cma, + extern int cma_for_each_area(int (*it)(struct cma *cma, void *data), void *data); + + extern void cma_reserve_pages_on_error(struct cma *cma); ++ ++#ifdef CONFIG_CMA ++extern int cma_check_range(u64 *start, u64 *end); ++#else ++static inline int cma_check_range(u64 *start, u64 *end) ++{ ++ return 0; ++} ++#endif ++ + #endif +--- a/mm/cma.c ++++ b/mm/cma.c +@@ -587,3 +587,39 @@ int cma_for_each_area(int (*it)(struct c + + return 0; + } ++ ++struct cma_check_range_data { ++ u64 start, end; ++}; ++ ++static int check_range(struct cma *cma_, void *data) ++{ ++ struct cma_check_range_data *range = data; ++ struct cma_check_range_data cma; ++ bool starts_in_range; ++ bool ends_in_range; ++ ++ cma.start = cma_get_base(cma_); ++ cma.end = cma.start + cma_get_size(cma_) - 1; ++ ++ starts_in_range = cma.start >= range->start && cma.start <= range->end; ++ ends_in_range = cma.end >= range->start && cma.end <= range->end; ++ ++ if (starts_in_range == ends_in_range) ++ return 0; ++ ++ pr_notice("CMA %s [%llx-%llx] straddles range [%llx-%llx]\n", ++ cma_->name, cma.start, cma.end, range->start, range->end); ++ ++ return -EINVAL; ++} ++ ++int cma_check_range(u64 *start, u64 *end) ++{ ++ struct cma_check_range_data range = { ++ .start = *start, ++ .end = *end, ++ }; ++ ++ return cma_for_each_area(check_range, &range); ++} diff --git a/target/linux/bcm27xx/patches-6.6/950-1344-dts-Move-some-common-rpi-settings-into-rpi-files.patch b/target/linux/bcm27xx/patches-6.6/950-1344-dts-Move-some-common-rpi-settings-into-rpi-files.patch new file mode 100644 index 000000000000..26c052c2230d --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1344-dts-Move-some-common-rpi-settings-into-rpi-files.patch @@ -0,0 +1,97 @@ +From aece59283a161dfad67c700c2ae97f9dd996eb2f Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 23 Jul 2024 15:55:54 +0100 +Subject: [PATCH 1344/1350] dts: Move some common rpi settings into rpi files + +Most 2711 devices and all 2712 device share common bootargs (command +lines). Make the common values shared defaults, overriding them were +necessary. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/broadcom/bcm2711-rpi-4-b.dts | 4 ---- + arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4.dts | 4 ---- + arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi | 1 + + arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts | 5 ----- + arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi | 5 ----- + arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi | 5 +++++ + 6 files changed, 6 insertions(+), 18 deletions(-) + +--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-4-b.dts ++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-4-b.dts +@@ -265,10 +265,6 @@ + #include "bcm283x-rpi-i2c0mux_0_44.dtsi" + + / { +- chosen { +- bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0"; +- }; +- + /delete-node/ wifi-pwrseq; + }; + +--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4.dts ++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4.dts +@@ -274,10 +274,6 @@ + #include "bcm283x-rpi-i2c0mux_0_44.dtsi" + + / { +- chosen { +- bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0"; +- }; +- + /delete-node/ wifi-pwrseq; + }; + +--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi ++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi +@@ -3,6 +3,7 @@ + + / { + chosen: chosen { ++ bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0"; + }; + + __overrides__ { +--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts +@@ -432,11 +432,6 @@ dpi_16bit_gpio2: &rp1_dpi_16bit_g + }; + + / { +- chosen: chosen { +- bootargs = "reboot=w coherent_pool=1M 8250.nr_uarts=1 pci=pcie_bus_safe"; +- stdout-path = "serial10:115200n8"; +- }; +- + fan: cooling_fan { + status = "disabled"; + compatible = "pwm-fan"; +--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi +@@ -422,11 +422,6 @@ dpi_16bit_gpio2: &rp1_dpi_16bit_g + }; + + / { +- chosen: chosen { +- bootargs = "reboot=w coherent_pool=1M 8250.nr_uarts=1 pci=pcie_bus_safe"; +- stdout-path = "serial10:115200n8"; +- }; +- + fan: cooling_fan { + status = "disabled"; + compatible = "pwm-fan"; +--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi +@@ -98,6 +98,11 @@ + }; + + / { ++ chosen: chosen { ++ bootargs = "reboot=w coherent_pool=1M 8250.nr_uarts=1 pci=pcie_bus_safe"; ++ stdout-path = "serial10:115200n8"; ++ }; ++ + aliases: aliases { + blconfig = &blconfig; + blpubkey = &blpubkey; diff --git a/target/linux/bcm27xx/patches-6.6/950-1345-dts-Set-preferred-numa-options-in-bootargs.patch b/target/linux/bcm27xx/patches-6.6/950-1345-dts-Set-preferred-numa-options-in-bootargs.patch new file mode 100644 index 000000000000..727c1a3678bd --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1345-dts-Set-preferred-numa-options-in-bootargs.patch @@ -0,0 +1,52 @@ +From dd44b93200c412c4c043392243c417f2d70082b3 Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Thu, 18 Jul 2024 20:22:18 +0100 +Subject: [PATCH 1345/1350] dts: Set preferred numa options in bootargs + +The default cmdline adjustment is now numa_policy=interleave for 2711 and 2712, +and additionally system_heap.max_order=0 iommu_dma_numa_policy=interleave for +just 2712 (due to its better iommu support). + +The key setting numa=fake= is not set here, so we will boot with a single +numa region and behaviour should be pretty much unchanged from before this PR. + +Signed-off-by: Dom Cobley +--- + arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4s.dts | 2 +- + arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi | 2 +- + arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi | 2 +- + 3 files changed, 3 insertions(+), 3 deletions(-) + +--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4s.dts ++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4s.dts +@@ -148,7 +148,7 @@ + + / { + chosen { +- bootargs = "coherent_pool=1M snd_bcm2835.enable_headphones=0"; ++ bootargs = "coherent_pool=1M snd_bcm2835.enable_headphones=0 numa_policy=interleave"; + }; + + aliases { +--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi ++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi +@@ -3,7 +3,7 @@ + + / { + chosen: chosen { +- bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0"; ++ bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0 numa_policy=interleave"; + }; + + __overrides__ { +--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi +@@ -99,7 +99,7 @@ + + / { + chosen: chosen { +- bootargs = "reboot=w coherent_pool=1M 8250.nr_uarts=1 pci=pcie_bus_safe"; ++ bootargs = "reboot=w coherent_pool=1M 8250.nr_uarts=1 pci=pcie_bus_safe numa_policy=interleave iommu_dma_numa_policy=interleave system_heap.max_order=0"; + stdout-path = "serial10:115200n8"; + }; + diff --git a/target/linux/bcm27xx/patches-6.6/950-1346-drm-vc4-Do-not-include-writeback-conn-load-in-load-t.patch b/target/linux/bcm27xx/patches-6.6/950-1346-drm-vc4-Do-not-include-writeback-conn-load-in-load-t.patch new file mode 100644 index 000000000000..1a7c5f64432f --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1346-drm-vc4-Do-not-include-writeback-conn-load-in-load-t.patch @@ -0,0 +1,48 @@ +From a2c8327a1b534574d51f5ea42009876e0008efd2 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 9 Sep 2024 17:28:00 +0100 +Subject: [PATCH 1346/1350] drm/vc4: Do not include writeback conn load in load + tracker + +The transposer/writeback connector should be running with a +lower priority, so shouldn't be factored into the load +calculations. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_kms.c | 17 +++++++++++++---- + 1 file changed, 13 insertions(+), 4 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_kms.c +@@ -674,17 +674,26 @@ static int vc4_load_tracker_atomic_check + for_each_oldnew_plane_in_state(state, plane, old_plane_state, + new_plane_state, i) { + struct vc4_plane_state *vc4_plane_state; ++ struct vc4_crtc *vc4_crtc; + + if (old_plane_state->fb && old_plane_state->crtc) { + vc4_plane_state = to_vc4_plane_state(old_plane_state); +- load_state->membus_load -= vc4_plane_state->membus_load; +- load_state->hvs_load -= vc4_plane_state->hvs_load; ++ vc4_crtc = to_vc4_crtc(old_plane_state->crtc); ++ ++ if (!vc4_crtc->feeds_txp) { ++ load_state->membus_load -= vc4_plane_state->membus_load; ++ load_state->hvs_load -= vc4_plane_state->hvs_load; ++ } + } + + if (new_plane_state->fb && new_plane_state->crtc) { + vc4_plane_state = to_vc4_plane_state(new_plane_state); +- load_state->membus_load += vc4_plane_state->membus_load; +- load_state->hvs_load += vc4_plane_state->hvs_load; ++ vc4_crtc = to_vc4_crtc(new_plane_state->crtc); ++ ++ if (!vc4_crtc->feeds_txp) { ++ load_state->membus_load += vc4_plane_state->membus_load; ++ load_state->hvs_load += vc4_plane_state->hvs_load; ++ } + } + } + diff --git a/target/linux/bcm27xx/patches-6.6/950-1347-drm-vc4-Drop-panic-priority-for-writeback-connector.patch b/target/linux/bcm27xx/patches-6.6/950-1347-drm-vc4-Drop-panic-priority-for-writeback-connector.patch new file mode 100644 index 000000000000..91187d20cb31 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1347-drm-vc4-Drop-panic-priority-for-writeback-connector.patch @@ -0,0 +1,54 @@ +From 2e85eb0e4950c5ad27df5a3ba54300e89694eba4 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 9 Sep 2024 17:38:45 +0100 +Subject: [PATCH 1347/1350] drm/vc4: Drop panic priority for writeback + connector + +As the writeback connector doesn't have the same realtime +constraints of a live display, drop the panic priority for it. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_kms.c | 21 ++++++++++++++------- + 1 file changed, 14 insertions(+), 7 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_kms.c +@@ -224,7 +224,7 @@ static void vc4_hvs_pv_muxing_commit(str + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state); + u32 dispctrl; +- u32 dsp3_mux; ++ u32 dsp3_mux_pri; + + if (!crtc_state->active) + continue; +@@ -241,15 +241,22 @@ static void vc4_hvs_pv_muxing_commit(str + * enabled. In this case, FIFO 2 is directly accessed by the + * TXP IP, and we need to disable the FIFO2 -> pixelvalve1 + * route. ++ * ++ * TXP can also run with a lower panic level than a live display, ++ * as it doesn't have the same real-time constraint. + */ +- if (vc4_crtc->feeds_txp) +- dsp3_mux = VC4_SET_FIELD(3, SCALER_DISPCTRL_DSP3_MUX); +- else +- dsp3_mux = VC4_SET_FIELD(2, SCALER_DISPCTRL_DSP3_MUX); ++ if (vc4_crtc->feeds_txp) { ++ dsp3_mux_pri = VC4_SET_FIELD(3, SCALER_DISPCTRL_DSP3_MUX); ++ dsp3_mux_pri |= VC4_SET_FIELD(0, SCALER_DISPCTRL_PANIC2); ++ } else { ++ dsp3_mux_pri = VC4_SET_FIELD(2, SCALER_DISPCTRL_DSP3_MUX); ++ dsp3_mux_pri |= VC4_SET_FIELD(2, SCALER_DISPCTRL_PANIC2); ++ } + + dispctrl = HVS_READ(SCALER_DISPCTRL) & +- ~SCALER_DISPCTRL_DSP3_MUX_MASK; +- HVS_WRITE(SCALER_DISPCTRL, dispctrl | dsp3_mux); ++ ~(SCALER_DISPCTRL_DSP3_MUX_MASK | ++ SCALER_DISPCTRL_PANIC2_MASK); ++ HVS_WRITE(SCALER_DISPCTRL, dispctrl | dsp3_mux_pri); + } + } + diff --git a/target/linux/bcm27xx/patches-6.6/950-1348-dts-Simplify-bootargs.patch b/target/linux/bcm27xx/patches-6.6/950-1348-dts-Simplify-bootargs.patch new file mode 100644 index 000000000000..f6de5994d637 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1348-dts-Simplify-bootargs.patch @@ -0,0 +1,112 @@ +From 8334494807ff5de7e500cb22e078c08754341c26 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 25 Oct 2024 10:36:20 +0100 +Subject: [PATCH 1348/1350] dts: Simplify bootargs + +Reduce the number of different places that bootargs is set in Pi dts +files. The variants are all combinations of with/without Bluetooth +and with/without NUMA support (2711). + +This is effectively a cosmetic change - the resulting dtbs are +unchanged. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/broadcom/bcm2708-rpi-bt.dtsi | 4 ++++ + arch/arm/boot/dts/broadcom/bcm2708-rpi-zero-w.dts | 4 ---- + arch/arm/boot/dts/broadcom/bcm2710-rpi-3-b-plus.dts | 4 ---- + arch/arm/boot/dts/broadcom/bcm2710-rpi-3-b.dts | 4 ---- + arch/arm/boot/dts/broadcom/bcm2710-rpi-zero-2-w.dts | 4 ---- + arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi | 2 +- + arch/arm/boot/dts/broadcom/bcm271x-rpi-bt.dtsi | 4 ++++ + 7 files changed, 9 insertions(+), 17 deletions(-) + +--- a/arch/arm/boot/dts/broadcom/bcm2708-rpi-bt.dtsi ++++ b/arch/arm/boot/dts/broadcom/bcm2708-rpi-bt.dtsi +@@ -23,6 +23,10 @@ + }; + + / { ++ chosen { ++ bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0"; ++ }; ++ + aliases { + bluetooth = &bt; + }; +--- a/arch/arm/boot/dts/broadcom/bcm2708-rpi-zero-w.dts ++++ b/arch/arm/boot/dts/broadcom/bcm2708-rpi-zero-w.dts +@@ -11,10 +11,6 @@ + compatible = "raspberrypi,model-zero-w", "brcm,bcm2835"; + model = "Raspberry Pi Zero W"; + +- chosen { +- bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0"; +- }; +- + aliases { + serial0 = &uart1; + serial1 = &uart0; +--- a/arch/arm/boot/dts/broadcom/bcm2710-rpi-3-b-plus.dts ++++ b/arch/arm/boot/dts/broadcom/bcm2710-rpi-3-b-plus.dts +@@ -12,10 +12,6 @@ + compatible = "raspberrypi,3-model-b-plus", "brcm,bcm2837"; + model = "Raspberry Pi 3 Model B+"; + +- chosen { +- bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0"; +- }; +- + aliases { + serial0 = &uart1; + serial1 = &uart0; +--- a/arch/arm/boot/dts/broadcom/bcm2710-rpi-3-b.dts ++++ b/arch/arm/boot/dts/broadcom/bcm2710-rpi-3-b.dts +@@ -12,10 +12,6 @@ + compatible = "raspberrypi,3-model-b", "brcm,bcm2837"; + model = "Raspberry Pi 3 Model B"; + +- chosen { +- bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0"; +- }; +- + aliases { + serial0 = &uart1; + serial1 = &uart0; +--- a/arch/arm/boot/dts/broadcom/bcm2710-rpi-zero-2-w.dts ++++ b/arch/arm/boot/dts/broadcom/bcm2710-rpi-zero-2-w.dts +@@ -11,10 +11,6 @@ + compatible = "raspberrypi,model-zero-2-w", "brcm,bcm2837"; + model = "Raspberry Pi Zero 2 W"; + +- chosen { +- bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0"; +- }; +- + aliases { + serial0 = &uart1; + serial1 = &uart0; +--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi ++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi +@@ -2,7 +2,7 @@ + #include "bcm270x-rpi.dtsi" + + / { +- chosen: chosen { ++ chosen { + bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0 numa_policy=interleave"; + }; + +--- a/arch/arm/boot/dts/broadcom/bcm271x-rpi-bt.dtsi ++++ b/arch/arm/boot/dts/broadcom/bcm271x-rpi-bt.dtsi +@@ -23,6 +23,10 @@ + }; + + / { ++ chosen { ++ bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0"; ++ }; ++ + aliases { + bluetooth = &bt; + }; diff --git a/target/linux/bcm27xx/patches-6.6/950-1349-cgroup-Use-kernel-command-line-to-disable-memory-cgr.patch b/target/linux/bcm27xx/patches-6.6/950-1349-cgroup-Use-kernel-command-line-to-disable-memory-cgr.patch new file mode 100644 index 000000000000..46e0aeaf4ce6 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1349-cgroup-Use-kernel-command-line-to-disable-memory-cgr.patch @@ -0,0 +1,193 @@ +From 86099deff5abf5f63643eecaedb4c11ae77474ce Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ma=C3=ADra=20Canal?= +Date: Thu, 24 Oct 2024 08:03:19 -0300 +Subject: [PATCH 1349/1350] cgroup: Use kernel command line to disable memory + cgroup +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Commit 94a23e978235 ("cgroup: Disable cgroup "memory" by default") +disabled the memory cgroup by default when initing the cgroups. However, +it's possible to disable the memory cgroup by a kernel command line. +Hard-coding such a feature can be problematic as some memory management +features depend on the order that things are set. + +For example, it is possible to see a NULL pointer dereference caused by +commit 94a23e978235cd35f38075072b34152b2b667e6e. The NULL pointer +dereference is triggered by the memory shrinker and ends up in a kernel +crash. + +[ 50.028629] ================================================================== +[ 50.028645] BUG: KASAN: null-ptr-deref in do_shrink_slab+0x1fc/0x978 +[ 50.028663] Write of size 8 at addr 0000000000000000 by task gfxrecon-replay/1965 + +[ 50.028676] CPU: 3 UID: 1000 PID: 1965 Comm: gfxrecon-replay Tainted: G C 6.12.0-rc4-v8-thp-kasan+ #85 +[ 50.028685] Tainted: [C]=CRAP +[ 50.028689] Hardware name: Raspberry Pi 5 Model B Rev 1.0 (DT) +[ 50.028694] Call trace: +[ 50.028697] dump_backtrace+0xfc/0x120 +[ 50.028706] show_stack+0x24/0x38 +[ 50.028711] dump_stack_lvl+0x40/0x88 +[ 50.028720] print_report+0xe4/0x708 +[ 50.028728] kasan_report+0xcc/0x130 +[ 50.028733] kasan_check_range+0x254/0x298 +[ 50.028738] __kasan_check_write+0x20/0x30 +[ 50.028745] do_shrink_slab+0x1fc/0x978 +[ 50.028751] shrink_slab+0x318/0xc38 +[ 50.028756] shrink_one+0x254/0x6d8 +[ 50.028762] shrink_node+0x26b4/0x2848 +[ 50.028767] do_try_to_free_pages+0x3e4/0x1190 +[ 50.028773] try_to_free_pages+0x5a4/0xb40 +[ 50.028778] __alloc_pages_direct_reclaim+0x144/0x298 +[ 50.028787] __alloc_pages_slowpath+0x5c4/0xc70 +[ 50.028793] __alloc_pages_noprof+0x4a8/0x6a8 +[ 50.028800] __folio_alloc_noprof+0x24/0xa8 +[ 50.028806] shmem_alloc_and_add_folio+0x2ec/0xce0 +[ 50.028812] shmem_get_folio_gfp+0x380/0xc20 +[ 50.028818] shmem_read_folio_gfp+0xe0/0x160 +[ 50.028824] drm_gem_get_pages+0x238/0x620 [drm] +[ 50.029039] drm_gem_shmem_get_pages_sgt+0xd8/0x4b8 [drm_shmem_helper] +[ 50.029053] v3d_bo_create_finish+0x58/0x1e0 [v3d] +[ 50.029083] v3d_create_bo_ioctl+0xac/0x210 [v3d] +[ 50.029105] drm_ioctl_kernel+0x1d8/0x2b8 [drm] +[ 50.029220] drm_ioctl+0x4b4/0x920 [drm] +[ 50.029330] __arm64_sys_ioctl+0x11c/0x160 +[ 50.029337] invoke_syscall+0x88/0x268 +[ 50.029345] el0_svc_common+0x160/0x1d8 +[ 50.029351] do_el0_svc+0x50/0x68 +[ 50.029358] el0_svc+0x34/0x80 +[ 50.029364] el0t_64_sync_handler+0x84/0x100 +[ 50.029371] el0t_64_sync+0x190/0x198 +[ 50.029376] ================================================================== + +This happens because the memory shrinker is unaware that we are +artificially disabling the memory cgroups and therefore it doesn't +allocate `nr_deferred` (as it would if we used the kernel command line). + +To avoid such an issue, revert the artificial disablement and disable it +through the command line. If a user wants to enable the feature, it can +use the `cgroup_enable=` command line. + +Signed-off-by: Maíra Canal +--- + arch/arm/boot/dts/broadcom/bcm2708-rpi-bt.dtsi | 2 +- + arch/arm/boot/dts/broadcom/bcm270x.dtsi | 2 +- + arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4s.dts | 2 +- + arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi | 2 +- + arch/arm/boot/dts/broadcom/bcm271x-rpi-bt.dtsi | 2 +- + arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi | 2 +- + kernel/cgroup/cgroup.c | 15 +-------------- + 7 files changed, 7 insertions(+), 20 deletions(-) + +--- a/arch/arm/boot/dts/broadcom/bcm2708-rpi-bt.dtsi ++++ b/arch/arm/boot/dts/broadcom/bcm2708-rpi-bt.dtsi +@@ -24,7 +24,7 @@ + + / { + chosen { +- bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0"; ++ bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0 cgroup_disable=memory"; + }; + + aliases { +--- a/arch/arm/boot/dts/broadcom/bcm270x.dtsi ++++ b/arch/arm/boot/dts/broadcom/bcm270x.dtsi +@@ -4,7 +4,7 @@ + / { + chosen: chosen { + // Disable audio by default +- bootargs = "coherent_pool=1M snd_bcm2835.enable_headphones=0"; ++ bootargs = "coherent_pool=1M snd_bcm2835.enable_headphones=0 cgroup_disable=memory"; + stdout-path = "serial0:115200n8"; + }; + +--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4s.dts ++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4s.dts +@@ -148,7 +148,7 @@ + + / { + chosen { +- bootargs = "coherent_pool=1M snd_bcm2835.enable_headphones=0 numa_policy=interleave"; ++ bootargs = "coherent_pool=1M snd_bcm2835.enable_headphones=0 cgroup_disable=memory numa_policy=interleave"; + }; + + aliases { +--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi ++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi +@@ -3,7 +3,7 @@ + + / { + chosen { +- bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0 numa_policy=interleave"; ++ bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0 cgroup_disable=memory numa_policy=interleave"; + }; + + __overrides__ { +--- a/arch/arm/boot/dts/broadcom/bcm271x-rpi-bt.dtsi ++++ b/arch/arm/boot/dts/broadcom/bcm271x-rpi-bt.dtsi +@@ -24,7 +24,7 @@ + + / { + chosen { +- bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0"; ++ bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0 cgroup_disable=memory"; + }; + + aliases { +--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi +@@ -99,7 +99,7 @@ + + / { + chosen: chosen { +- bootargs = "reboot=w coherent_pool=1M 8250.nr_uarts=1 pci=pcie_bus_safe numa_policy=interleave iommu_dma_numa_policy=interleave system_heap.max_order=0"; ++ bootargs = "reboot=w coherent_pool=1M 8250.nr_uarts=1 pci=pcie_bus_safe cgroup_disable=memory numa_policy=interleave iommu_dma_numa_policy=interleave system_heap.max_order=0"; + stdout-path = "serial10:115200n8"; + }; + +--- a/kernel/cgroup/cgroup.c ++++ b/kernel/cgroup/cgroup.c +@@ -6060,9 +6060,6 @@ int __init cgroup_init_early(void) + return 0; + } + +-static u16 cgroup_enable_mask __initdata; +-static int __init cgroup_disable(char *str); +- + /** + * cgroup_init - cgroup initialization + * +@@ -6096,12 +6093,6 @@ int __init cgroup_init(void) + + cgroup_unlock(); + +- /* +- * Apply an implicit disable, knowing that an explicit enable will +- * prevent if from doing anything. +- */ +- cgroup_disable("memory"); +- + for_each_subsys(ss, ssid) { + if (ss->early_init) { + struct cgroup_subsys_state *css = +@@ -6742,10 +6733,6 @@ static int __init cgroup_disable(char *s + strcmp(token, ss->legacy_name)) + continue; + +- /* An explicit cgroup_enable overrides a disable */ +- if (cgroup_enable_mask & (1 << i)) +- continue; +- + static_branch_disable(cgroup_subsys_enabled_key[i]); + pr_info("Disabling %s control group subsystem\n", + ss->name); +@@ -6779,7 +6766,7 @@ static int __init cgroup_enable(char *st + strcmp(token, ss->legacy_name)) + continue; + +- cgroup_enable_mask |= 1 << i; ++ cgroup_feature_disable_mask &= ~(1 << i); + static_branch_enable(cgroup_subsys_enabled_key[i]); + pr_info("Enabling %s control group subsystem\n", + ss->name); diff --git a/target/linux/bcm27xx/patches-6.6/950-1350-arm64-dts-Sort-out-CM5-and-I-O-board-I2C-ports.patch b/target/linux/bcm27xx/patches-6.6/950-1350-arm64-dts-Sort-out-CM5-and-I-O-board-I2C-ports.patch new file mode 100644 index 000000000000..8ee3b7546435 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1350-arm64-dts-Sort-out-CM5-and-I-O-board-I2C-ports.patch @@ -0,0 +1,185 @@ +From 4622323f5c9e540f3356f2229c4d551b31cc234d Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 24 Oct 2024 15:38:36 +0100 +Subject: [PATCH 1350/1350] arm64: dts: Sort out CM5 and I/O board I2C ports + +There is a difference in I2C usage between CM4IO and CM5IO. Present a +simple, consistent view of the world by moving the assignment of the +bus IDs into carrier-specific files. + +CM5 has reduced connectivity on CM4IO - the DPHYs are connected to +CAM1 and DISP1. Keep i2c-10 for use with that pair, as is the case for +CM4 on CM4IO. + +Fixes: 36faab69e8ee ("dts: bcm2712-rpi: Add aliases for the CSI/DSI I2Cs") +See: https://github.com/raspberrypi/linux/pull/6421 + +Signed-off-by: Phil Elwell +--- + .../boot/dts/broadcom/bcm2712-rpi-cm4io.dtsi | 28 +++++++++++++++++++ + .../dts/broadcom/bcm2712-rpi-cm5-cm4io.dts | 17 +---------- + .../dts/broadcom/bcm2712-rpi-cm5-cm5io.dts | 7 +---- + .../boot/dts/broadcom/bcm2712-rpi-cm5.dtsi | 13 --------- + .../boot/dts/broadcom/bcm2712-rpi-cm5io.dtsi | 14 ++++++++++ + .../dts/broadcom/bcm2712-rpi-cm5l-cm4io.dts | 17 +---------- + .../dts/broadcom/bcm2712-rpi-cm5l-cm5io.dts | 7 +---- + .../boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi | 4 --- + 8 files changed, 46 insertions(+), 61 deletions(-) + create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm4io.dtsi + create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5io.dtsi + +--- /dev/null ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm4io.dtsi +@@ -0,0 +1,28 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++i2c_csi_dsi0: &i2c0 { // Note: For CAM0 and DISP0 connectors ++}; ++ ++i2c_csi_dsi1: &i2c6 { // Note: For CAM1, DISP1, on-board RTC, and fan controller ++ pinctrl-0 = <&rp1_i2c6_38_39>; ++ pinctrl-names = "default"; ++ clock-frequency = <100000>; ++ symlink = "i2c-6"; ++}; ++ ++i2c_csi_dsi: &i2c_csi_dsi1 { }; // The connector that needs no jumper to enable ++ ++&aliases { ++ /delete-property/ i2c11; ++ i2c10 = &i2c_csi_dsi; ++}; ++ ++// The RP1 USB3 interfaces are not usable on CM4IO ++ ++&rp1_usb0 { ++ status = "disabled"; ++}; ++ ++&rp1_usb1 { ++ status = "disabled"; ++}; +--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm4io.dts ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm4io.dts +@@ -2,19 +2,4 @@ + /dts-v1/; + + #include "bcm2712-rpi-cm5.dtsi" +- +-// The RP1 USB3 interfaces are not usable on CM4IO +- +-&rp1_usb0 { +- status = "disabled"; +-}; +- +-&rp1_usb1 { +- status = "disabled"; +-}; +- +-/ { +- __overrides__ { +- i2c_csi_dsi = <&i2c_csi_dsi>, "status"; +- }; +-}; ++#include "bcm2712-rpi-cm4io.dtsi" +--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm5io.dts ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm5io.dts +@@ -2,9 +2,4 @@ + /dts-v1/; + + #include "bcm2712-rpi-cm5.dtsi" +- +-/ { +- __overrides__ { +- i2c_csi_dsi = <&i2c_csi_dsi>, "status"; +- }; +-}; ++#include "bcm2712-rpi-cm5io.dtsi" +--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi +@@ -234,19 +234,6 @@ aux: &dummy {}; + + #include "bcm2712-rpi.dtsi" + +-i2c_csi_dsi0: &i2c6 { // Note: This is for MIPI0 connector only +- pinctrl-0 = <&rp1_i2c6_38_39>; +- pinctrl-names = "default"; +- clock-frequency = <100000>; +- symlink = "i2c-6"; +-}; +- +-i2c_csi_dsi1: &i2c0 { // Note: This is for MIPI1 connector +- symlink = "i2c-11"; +-}; +- +-i2c_csi_dsi: &i2c_csi_dsi1 { }; // An alias for compatibility +- + cam1_reg: &cam0_reg { // Shares CAM_GPIO with cam0_reg + }; + +--- /dev/null ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5io.dtsi +@@ -0,0 +1,14 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++i2c_csi_dsi1: &i2c0 { // Note: This is for CAM/DISP 1 connector ++ symlink = "i2c-11"; ++}; ++ ++i2c_csi_dsi0: &i2c6 { // Note: This is for CAM/DISP 0 connector ++ pinctrl-0 = <&rp1_i2c6_38_39>; ++ pinctrl-names = "default"; ++ clock-frequency = <100000>; ++ symlink = "i2c-6"; ++}; ++ ++i2c_csi_dsi: &i2c_csi_dsi0 { }; // The connector that needs no jumper to enable +--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm4io.dts ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm4io.dts +@@ -2,19 +2,4 @@ + /dts-v1/; + + #include "bcm2712-rpi-cm5l.dtsi" +- +-// The RP1 USB3 interfaces are not usable on CM4IO +- +-&rp1_usb0 { +- status = "disabled"; +-}; +- +-&rp1_usb1 { +- status = "disabled"; +-}; +- +-/ { +- __overrides__ { +- i2c_csi_dsi = <&i2c_csi_dsi>, "status"; +- }; +-}; ++#include "bcm2712-rpi-cm4io.dtsi" +--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm5io.dts ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm5io.dts +@@ -2,9 +2,4 @@ + /dts-v1/; + + #include "bcm2712-rpi-cm5l.dtsi" +- +-/ { +- __overrides__ { +- i2c_csi_dsi = <&i2c_csi_dsi>, "status"; +- }; +-}; ++#include "bcm2712-rpi-cm5io.dtsi" +--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi +@@ -5,10 +5,6 @@ + + / { + model = "Raspberry Pi Compute Module 5 Lite"; +- +- __overrides__ { +- i2c_csi_dsi = <&i2c_csi_dsi>, "status"; +- }; + }; + + &sd_io_1v8_reg {