diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 773770c47e37..dd68422c2aa1 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -108,6 +108,7 @@ config ARM select HAVE_KERNEL_XZ select HAVE_KPROBES if !XIP_KERNEL && !CPU_ENDIAN_BE32 && !CPU_V7M select HAVE_KRETPROBES if HAVE_KPROBES + select HAVE_LD_DEAD_CODE_DATA_ELIMINATION select HAVE_MOD_ARCH_SPECIFIC select HAVE_NMI select HAVE_OPTPROBES if !THUMB2_KERNEL diff --git a/arch/arm/boot/compressed/vmlinux.lds.S b/arch/arm/boot/compressed/vmlinux.lds.S index 3fcb3e62dc56..d411abd4310e 100644 --- a/arch/arm/boot/compressed/vmlinux.lds.S +++ b/arch/arm/boot/compressed/vmlinux.lds.S @@ -125,7 +125,7 @@ SECTIONS . = BSS_START; __bss_start = .; - .bss : { *(.bss) } + .bss : { *(.bss .bss.*) } _end = .; . = ALIGN(8); /* the stack must be 64-bit aligned */ diff --git a/arch/arm/configs/rk3506_defconfig b/arch/arm/configs/rk3506_defconfig index cb4c9dccbeb5..06dc4ccd234e 100644 --- a/arch/arm/configs/rk3506_defconfig +++ b/arch/arm/configs/rk3506_defconfig @@ -16,6 +16,7 @@ CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_LZ4 is not set # CONFIG_RD_ZSTD is not set CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_LD_DEAD_CODE_DATA_ELIMINATION=y # CONFIG_BUG is not set # CONFIG_ELF_CORE is not set # CONFIG_BASE_FULL is not set @@ -102,17 +103,23 @@ CONFIG_NETDEVICES=y # CONFIG_NET_VENDOR_AMAZON is not set # CONFIG_NET_VENDOR_AQUANTIA is not set # CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_ASIX is not set # CONFIG_NET_VENDOR_BROADCOM is not set # CONFIG_NET_VENDOR_CADENCE is not set # CONFIG_NET_VENDOR_CAVIUM is not set # CONFIG_NET_VENDOR_CIRRUS is not set # CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_NET_VENDOR_DAVICOM is not set +# CONFIG_NET_VENDOR_ENGLEDER is not set # CONFIG_NET_VENDOR_EZCHIP is not set # CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_FUNGIBLE is not set # CONFIG_NET_VENDOR_GOOGLE is not set # CONFIG_NET_VENDOR_HISILICON is not set # CONFIG_NET_VENDOR_HUAWEI is not set # CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_ADI is not set +# CONFIG_NET_VENDOR_LITEX is not set # CONFIG_NET_VENDOR_MARVELL is not set # CONFIG_NET_VENDOR_MELLANOX is not set # CONFIG_NET_VENDOR_MICREL is not set @@ -136,7 +143,9 @@ CONFIG_STMMAC_FULL=y # CONFIG_DWMAC_GENERIC is not set CONFIG_DWMAC_ROCKCHIP_TOOL=y # CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_VERTEXCOM is not set # CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WANGXUN is not set # CONFIG_NET_VENDOR_WIZNET is not set # CONFIG_NET_VENDOR_XILINX is not set CONFIG_MOTORCOMM_PHY=y diff --git a/arch/arm/include/asm/vmlinux.lds.h b/arch/arm/include/asm/vmlinux.lds.h index fad45c884e98..fa031135710f 100644 --- a/arch/arm/include/asm/vmlinux.lds.h +++ b/arch/arm/include/asm/vmlinux.lds.h @@ -42,7 +42,7 @@ #define PROC_INFO \ . = ALIGN(4); \ __proc_info_begin = .; \ - *(.proc.info.init) \ + KEEP(*(.proc.info.init)) \ __proc_info_end = .; #define IDMAP_TEXT \ diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index c39303e5c234..fe3a24fe6a00 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -1297,6 +1297,7 @@ vector_addrexcptn: .globl vector_fiq .section .vectors, "ax", %progbits + .reloc .text, R_ARM_NONE, . W(b) vector_rst W(b) vector_und ARM( .reloc ., R_ARM_LDR_PC_G0, .L__vector_swi ) @@ -1310,6 +1311,7 @@ THUMB( .reloc ., R_ARM_THM_PC12, .L__vector_swi ) #ifdef CONFIG_HARDEN_BRANCH_HISTORY .section .vectors.bhb.loop8, "ax", %progbits + .reloc .text, R_ARM_NONE, . W(b) vector_rst W(b) vector_bhb_loop8_und ARM( .reloc ., R_ARM_LDR_PC_G0, .L__vector_bhb_loop8_swi ) @@ -1322,6 +1324,7 @@ THUMB( .reloc ., R_ARM_THM_PC12, .L__vector_bhb_loop8_swi ) W(b) vector_bhb_loop8_fiq .section .vectors.bhb.bpiall, "ax", %progbits + .reloc .text, R_ARM_NONE, . W(b) vector_rst W(b) vector_bhb_bpiall_und ARM( .reloc ., R_ARM_LDR_PC_G0, .L__vector_bhb_bpiall_swi ) diff --git a/arch/arm/kernel/vmlinux-xip.lds.S b/arch/arm/kernel/vmlinux-xip.lds.S index 76678732c60d..8ab517f26c22 100644 --- a/arch/arm/kernel/vmlinux-xip.lds.S +++ b/arch/arm/kernel/vmlinux-xip.lds.S @@ -64,7 +64,7 @@ SECTIONS . = ALIGN(4); __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { __start___ex_table = .; - ARM_MMU_KEEP(*(__ex_table)) + ARM_MMU_KEEP(KEEP(*(__ex_table))) __stop___ex_table = .; } @@ -84,7 +84,7 @@ SECTIONS } .init.arch.info : { __arch_info_begin = .; - *(.arch.info.init) + KEEP(*(.arch.info.init)) __arch_info_end = .; } .init.tagtable : { diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index aa12b65a7fd6..392cb962a40c 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -75,7 +75,7 @@ SECTIONS . = ALIGN(4); __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { __start___ex_table = .; - ARM_MMU_KEEP(*(__ex_table)) + ARM_MMU_KEEP(KEEP(*(__ex_table))) __stop___ex_table = .; } @@ -100,7 +100,7 @@ SECTIONS } .init.arch.info : { __arch_info_begin = .; - *(.arch.info.init) + KEEP(*(.arch.info.init)) __arch_info_end = .; } .init.tagtable : { @@ -117,7 +117,7 @@ SECTIONS #endif .init.pv_table : { __pv_table_begin = .; - *(.pv_table) + KEEP(*(.pv_table)) __pv_table_end = .; } diff --git a/arch/arm64/configs/rockchip_linux_defconfig b/arch/arm64/configs/rockchip_linux_defconfig index f079f125c510..895097420356 100644 --- a/arch/arm64/configs/rockchip_linux_defconfig +++ b/arch/arm64/configs/rockchip_linux_defconfig @@ -132,6 +132,8 @@ CONFIG_PCIEPORTBUS=y CONFIG_PCIEASPM_POWERSAVE=y CONFIG_PCIEASPM_EXT=y # CONFIG_VGA_ARB is not set +CONFIG_HOTPLUG_PCI=y +CONFIG_HOTPLUG_PCI_GPIO=y CONFIG_PCIE_ROCKCHIP_HOST=y CONFIG_PCIE_DW_ROCKCHIP=y CONFIG_DEVTMPFS=y diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 9fdc68640d0a..f4340ad4a96d 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -54,6 +54,10 @@ KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_CFI), $(KBUILD_CFLAGS)) # disable LTO KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_LTO), $(KBUILD_CFLAGS)) +# The .data section would be renamed to .data.efistub, therefore, remove +# `-fdata-sections` flag from KBUILD_CFLAGS_KERNEL +KBUILD_CFLAGS_KERNEL := $(filter-out -fdata-sections, $(KBUILD_CFLAGS_KERNEL)) + GCOV_PROFILE := n # Sanitizer runtimes are unavailable and cannot be linked here. KASAN_SANITIZE := n diff --git a/drivers/gpu/drm/rockchip/rockchip_post_csc.c b/drivers/gpu/drm/rockchip/rockchip_post_csc.c index a57d562bf04f..7e8d183ebc2e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_post_csc.c +++ b/drivers/gpu/drm/rockchip/rockchip_post_csc.c @@ -207,6 +207,13 @@ static const struct rk_pq_csc_dc_coef rk_dc_csc_table_hdy_cb_cr_full_to_xv_yccsd /* xv_ycc BT.601 (i.e. SD) -> to BT.709 (i.e. HD) */ static const struct rk_pq_csc_coef rk_csc_table_xv_yccsdy_cb_cr_to_hdy_cb_cr = { + 1024, -118, -213, + 0, 1043, 117, + 0, 77, 1050 +}; + +/* xv_ycc BT.601 full(i.e. SD) -> to BT.709 full(i.e. HD) */ +static const struct rk_pq_csc_coef rk_csc_table_xv_yccsdy_cb_cr_full_to_hdy_cb_cr_full = { 1024, -121, -218, 0, 1043, 117, 0, 77, 1050 @@ -642,7 +649,7 @@ static const struct rk_csc_mode_coef g_mode_csc_coef[] = { }, { RK_PQ_CSC_YUV2YUV, "YUV L->YUV L", - &rk_csc_table_xv_yccsdy_cb_cr_to_hdy_cb_cr, + &rk_csc_table_identity_y_cb_cr_to_y_cb_cr, &rk_dc_csc_table_xv_yccsdy_cb_cr_to_hdy_cb_cr, { OPTM_CS_E_ITU_R_BT_709, OPTM_CS_E_ITU_R_BT_709, false, false @@ -690,7 +697,7 @@ static const struct rk_csc_mode_coef g_mode_csc_coef[] = { }, { RK_PQ_CSC_YUV2YUV_601_709_FULL, "YUV601 F->YUV709 F", - &rk_csc_table_xv_yccsdy_cb_cr_to_hdy_cb_cr, + &rk_csc_table_xv_yccsdy_cb_cr_full_to_hdy_cb_cr_full, &rk_dc_csc_table_hdy_cb_cr_full_to_xv_yccsdy_cb_cr_full, { OPTM_CS_E_XV_YCC_601, OPTM_CS_E_ITU_R_BT_709, true, true @@ -890,7 +897,7 @@ static const struct rk_csc_mode_coef g_mode_csc_coef[] = { }, { RK_PQ_CSC_YUV2YUV, "YUV 601 L->YUV 601 L", - &rk_csc_table_xv_yccsdy_cb_cr_to_hdy_cb_cr, + &rk_csc_table_identity_y_cb_cr_to_y_cb_cr, &rk_dc_csc_table_xv_yccsdy_cb_cr_to_hdy_cb_cr, { OPTM_CS_E_XV_YCC_601, OPTM_CS_E_XV_YCC_601, false, false @@ -922,7 +929,7 @@ static const struct rk_csc_mode_coef g_mode_csc_coef[] = { }, { RK_PQ_CSC_YUV2YUV, "YUV 2020 L->YUV 2020 L", - &rk_csc_table_xv_yccsdy_cb_cr_to_hdy_cb_cr, + &rk_csc_table_identity_y_cb_cr_to_y_cb_cr, &rk_dc_csc_table_xv_yccsdy_cb_cr_to_hdy_cb_cr, { OPTM_CS_E_XV_YCC_2020, OPTM_CS_E_XV_YCC_2020, false, false @@ -988,14 +995,26 @@ static const struct rk_csc_mode_coef g_mode_csc_coef[] = { static const struct rk_pq_csc_coef r2y_for_y2y = { 306, 601, 117, - -151, -296, 446, - 630, -527, -102, + -173, -339, 512, + 512, -429, -83, }; static const struct rk_pq_csc_coef y2r_for_y2y = { - 1024, -0, 1167, - 1024, -404, -594, - 1024, 2081, -1, + 1024, -1, 1436, + 1024, -353, -731, + 1024, 1814, 1, +}; + +static const struct rk_pq_csc_coef r2y_for_r2r = { + 1024, 0, 1612, + 1024, -192, -480, + 1024, 1900, -2, +}; + +static const struct rk_pq_csc_coef y2r_for_r2r = { + 218, 732, 74, + -117, -395, 512, + 512, -465, -47, }; static const struct rk_pq_csc_coef rgb_input_swap_matrix = { @@ -1124,7 +1143,7 @@ static void csc_matrix_ventor_multiply(struct rk_pq_csc_ventor *dst, m0->csc_coef22 * v0->csc_offset2; } -static void csc_matrix_element_left_shift(struct rk_pq_csc_coef *m, int n) +static void csc_matrix_element_right_shift(struct rk_pq_csc_coef *m, int n) { m->csc_coef00 = m->csc_coef00 >> n; m->csc_coef01 = m->csc_coef01 >> n; @@ -1137,6 +1156,30 @@ static void csc_matrix_element_left_shift(struct rk_pq_csc_coef *m, int n) m->csc_coef22 = m->csc_coef22 >> n; } +static inline s32 csc_simple_round(s32 x, s32 n) +{ + s32 value = 0; + + if (n == 0) + return x; + + value = (abs(x) + (1 << (n - 1))) >> (n); + return (((x) >= 0) ? value : -value); +} + +static void csc_matrix_element_right_shift_with_simple_round(struct rk_pq_csc_coef *m, int n) +{ + m->csc_coef00 = csc_simple_round(m->csc_coef00, n); + m->csc_coef01 = csc_simple_round(m->csc_coef01, n); + m->csc_coef02 = csc_simple_round(m->csc_coef02, n); + m->csc_coef10 = csc_simple_round(m->csc_coef10, n); + m->csc_coef11 = csc_simple_round(m->csc_coef11, n); + m->csc_coef12 = csc_simple_round(m->csc_coef12, n); + m->csc_coef20 = csc_simple_round(m->csc_coef20, n); + m->csc_coef21 = csc_simple_round(m->csc_coef21, n); + m->csc_coef22 = csc_simple_round(m->csc_coef22, n); +} + static struct rk_pq_csc_coef create_rgb_gain_matrix(s32 r_gain, s32 g_gain, s32 b_gain) { struct rk_pq_csc_coef m; @@ -1280,23 +1323,23 @@ static int csc_calc_adjust_output_coef(bool is_input_yuv, bool is_output_yuv, csc_matrix_multiply(&temp0, csc_mode_cfg->pst_csc_coef, &hue_matrix); /* * The value bits width is 32 bit, so every time 2 matirx multifly, - * left shift is necessary to avoid overflow. For enhancing the + * right shift is necessary to avoid overflow. For enhancing the * calculator precision, PQ_CALC_ENHANCE_BIT bits is reserved and - * left shift before get the final result. + * right shift before get the final result. */ - csc_matrix_element_left_shift(&temp0, PQ_CSC_PARAM_FIX_BIT_WIDTH - - PQ_CALC_ENHANCE_BIT); + csc_matrix_element_right_shift(&temp0, PQ_CSC_PARAM_FIX_BIT_WIDTH - + PQ_CALC_ENHANCE_BIT); csc_matrix_multiply(&temp1, &temp0, &saturation_matrix); - csc_matrix_element_left_shift(&temp1, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH); + csc_matrix_element_right_shift(&temp1, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH); csc_matrix_multiply(&temp0, &temp1, r2y_matrix); - csc_matrix_element_left_shift(&temp0, PQ_CSC_PARAM_FIX_BIT_WIDTH); + csc_matrix_element_right_shift(&temp0, PQ_CSC_PARAM_FIX_BIT_WIDTH); csc_matrix_multiply(&temp1, &temp0, &gain_matrix); - csc_matrix_element_left_shift(&temp1, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH); + csc_matrix_element_right_shift(&temp1, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH); csc_matrix_multiply(&temp0, &temp1, &contrast_matrix); - csc_matrix_element_left_shift(&temp0, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH); + csc_matrix_element_right_shift(&temp0, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH); csc_matrix_multiply(out_matrix, &temp0, y2r_matrix); - csc_matrix_element_left_shift(out_matrix, PQ_CSC_PARAM_FIX_BIT_WIDTH + - PQ_CALC_ENHANCE_BIT); + csc_matrix_element_right_shift_with_simple_round(out_matrix, + PQ_CSC_PARAM_FIX_BIT_WIDTH + PQ_CALC_ENHANCE_BIT); dc_in_ventor.csc_offset0 = dc_in_offset; dc_in_ventor.csc_offset1 = -PQ_CSC_DC_IN_OUT_DEFAULT; @@ -1311,15 +1354,15 @@ static int csc_calc_adjust_output_coef(bool is_input_yuv, bool is_output_yuv, * hue_matrix * saturation_matrix */ csc_matrix_multiply(&temp0, csc_mode_cfg->pst_csc_coef, &hue_matrix); - csc_matrix_element_left_shift(&temp0, PQ_CSC_PARAM_FIX_BIT_WIDTH - - PQ_CALC_ENHANCE_BIT); + csc_matrix_element_right_shift(&temp0, PQ_CSC_PARAM_FIX_BIT_WIDTH - + PQ_CALC_ENHANCE_BIT); csc_matrix_multiply(&temp1, &temp0, &saturation_matrix); - csc_matrix_element_left_shift(&temp1, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH); + csc_matrix_element_right_shift(&temp1, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH); csc_matrix_multiply(&temp0, &contrast_matrix, &temp1); - csc_matrix_element_left_shift(&temp0, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH); + csc_matrix_element_right_shift(&temp0, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH); csc_matrix_multiply(out_matrix, &gain_matrix, &temp0); - csc_matrix_element_left_shift(out_matrix, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH + - PQ_CALC_ENHANCE_BIT); + csc_matrix_element_right_shift(out_matrix, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH + + PQ_CALC_ENHANCE_BIT); dc_in_ventor.csc_offset0 = dc_in_offset; dc_in_ventor.csc_offset1 = -PQ_CSC_DC_IN_OUT_DEFAULT; @@ -1334,15 +1377,15 @@ static int csc_calc_adjust_output_coef(bool is_input_yuv, bool is_output_yuv, * gain_matrix * contrast_matrix */ csc_matrix_multiply(&temp0, csc_mode_cfg->pst_csc_coef, &gain_matrix); - csc_matrix_element_left_shift(&temp0, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH - - PQ_CALC_ENHANCE_BIT); + csc_matrix_element_right_shift(&temp0, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH - + PQ_CALC_ENHANCE_BIT); csc_matrix_multiply(&temp1, &temp0, &contrast_matrix); - csc_matrix_element_left_shift(&temp1, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH); + csc_matrix_element_right_shift(&temp1, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH); csc_matrix_multiply(&temp0, &saturation_matrix, &temp1); - csc_matrix_element_left_shift(&temp0, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH); + csc_matrix_element_right_shift(&temp0, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH); csc_matrix_multiply(out_matrix, &hue_matrix, &temp0); - csc_matrix_element_left_shift(out_matrix, PQ_CSC_PARAM_FIX_BIT_WIDTH + - PQ_CALC_ENHANCE_BIT); + csc_matrix_element_right_shift(out_matrix, PQ_CSC_PARAM_FIX_BIT_WIDTH + + PQ_CALC_ENHANCE_BIT); dc_in_ventor.csc_offset0 = dc_in_offset; dc_in_ventor.csc_offset1 = dc_in_offset; @@ -1356,35 +1399,21 @@ static int csc_calc_adjust_output_coef(bool is_input_yuv, bool is_output_yuv, * so output = T * gain_matrix * contrast_matrix * * N_y2r * hue_matrix * saturation_matrix * N_r2y */ - if (!color_info->in_full_range && color_info->out_full_range) { - r2y_matrix = &rk_csc_table_rgb_limit_to_hdy_cb_cr; - y2r_matrix = &rk_csc_table_hdy_cb_cr_limit_to_rgb_full; - } else if (color_info->in_full_range && !color_info->out_full_range) { - r2y_matrix = &rk_csc_table_rgb_to_hdy_cb_cr; - y2r_matrix = &rk_csc_table_hdy_cb_cr_limit_to_rgb_limit; - } else if (color_info->in_full_range && color_info->out_full_range) { - r2y_matrix = &rk_csc_table_rgb_to_hdy_cb_cr_full; - y2r_matrix = &rk_csc_table_hdy_cb_cr_to_rgb_full; - } else { - r2y_matrix = &rk_csc_table_rgb_limit_to_hdy_cb_cr; - y2r_matrix = &rk_csc_table_hdy_cb_cr_limit_to_rgb_limit; - } + r2y_matrix = &r2y_for_r2r; + y2r_matrix = &y2r_for_r2r; csc_matrix_multiply(&temp0, &contrast_matrix, y2r_matrix); - csc_matrix_element_left_shift(&temp0, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH - - PQ_CALC_ENHANCE_BIT); + csc_matrix_element_right_shift(&temp0, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH - + PQ_CALC_ENHANCE_BIT); csc_matrix_multiply(&temp1, &gain_matrix, &temp0); - csc_matrix_element_left_shift(&temp1, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH); + csc_matrix_element_right_shift(&temp1, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH); csc_matrix_multiply(&temp0, &temp1, &hue_matrix); - csc_matrix_element_left_shift(&temp0, PQ_CSC_PARAM_FIX_BIT_WIDTH); + csc_matrix_element_right_shift(&temp0, PQ_CSC_PARAM_FIX_BIT_WIDTH); csc_matrix_multiply(&temp1, &temp0, &saturation_matrix); - csc_matrix_element_left_shift(&temp1, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH); + csc_matrix_element_right_shift(&temp1, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH); csc_matrix_multiply(out_matrix, &temp1, r2y_matrix); - csc_matrix_element_left_shift(out_matrix, PQ_CSC_PARAM_FIX_BIT_WIDTH + - PQ_CALC_ENHANCE_BIT); - - if (color_info->in_full_range && color_info->out_full_range) - out_matrix->csc_coef00 += 1; + csc_matrix_element_right_shift_with_simple_round(out_matrix, + PQ_CSC_PARAM_FIX_BIT_WIDTH + PQ_CALC_ENHANCE_BIT); dc_in_ventor.csc_offset0 = dc_in_offset; dc_in_ventor.csc_offset1 = dc_in_offset; @@ -1522,9 +1551,9 @@ int rockchip_calc_post_csc(struct post_csc *csc_cfg, struct post_csc_coef *csc_s rockchip_swap_color_channel(convert_mode->is_input_yuv, convert_mode->is_output_yuv, csc_simple_coef, &out_matrix, &out_dc); - csc_simple_coef->csc_dc0 = pq_csc_simple_round(csc_simple_coef->csc_dc0, bit_num); - csc_simple_coef->csc_dc1 = pq_csc_simple_round(csc_simple_coef->csc_dc1, bit_num); - csc_simple_coef->csc_dc2 = pq_csc_simple_round(csc_simple_coef->csc_dc2, bit_num); + csc_simple_coef->csc_dc0 = csc_simple_round(csc_simple_coef->csc_dc0, bit_num); + csc_simple_coef->csc_dc1 = csc_simple_round(csc_simple_coef->csc_dc1, bit_num); + csc_simple_coef->csc_dc2 = csc_simple_round(csc_simple_coef->csc_dc2, bit_num); csc_simple_coef->range_type = csc_mode_cfg->st_csc_color_info.out_full_range; return ret; diff --git a/drivers/media/i2c/rk628/rk628_combtxphy.c b/drivers/media/i2c/rk628/rk628_combtxphy.c index dac86c39ab20..299b798eb2fe 100644 --- a/drivers/media/i2c/rk628/rk628_combtxphy.c +++ b/drivers/media/i2c/rk628/rk628_combtxphy.c @@ -246,10 +246,10 @@ EXPORT_SYMBOL(rk628_txphy_power_on); void rk628_txphy_power_off(struct rk628 *rk628) { - rk628_i2c_update_bits(rk628, COMBTXPHY_CON0, SW_TX_IDLE_MASK | SW_TX_PD_MASK | - SW_PD_PLL_MASK | SW_MODULEB_EN_MASK | - SW_MODULEA_EN_MASK, SW_TX_IDLE(0x3ff) | - SW_TX_PD(0x3ff) | SW_PD_PLL); + rk628_i2c_update_bits(rk628, COMBTXPHY_CON0, SW_TX_IDLE_MASK | SW_TX_PD_MASK | + SW_PD_PLL_MASK | SW_MODULEB_EN_MASK | SW_MODULEA_EN_MASK | + SW_GVI_LVDS_EN_MASK | SW_MIPI_DSI_EN_MASK, + SW_TX_IDLE(0x3ff) | SW_TX_PD(0x3ff) | SW_PD_PLL); } EXPORT_SYMBOL(rk628_txphy_power_off); diff --git a/drivers/media/i2c/rk628/rk628_csi_v4l2.c b/drivers/media/i2c/rk628/rk628_csi_v4l2.c index d5038ddf545b..e4be55fa5e28 100644 --- a/drivers/media/i2c/rk628/rk628_csi_v4l2.c +++ b/drivers/media/i2c/rk628/rk628_csi_v4l2.c @@ -494,6 +494,7 @@ static void rk628_hdmirx_plugout(struct v4l2_subdev *sd) rk628_hdmirx_hpd_ctrl(sd, false); rk628_hdmirx_inno_phy_power_off(sd); rk628_hdmirx_verisyno_phy_power_off(csi->rk628); + mipi_dphy_power_off(csi); } static void rk628_hdmirx_config_all(struct v4l2_subdev *sd) @@ -1458,9 +1459,6 @@ static void rk628_csi_initial_setup(struct v4l2_subdev *sd) } csi->rk628->dphy_lane_en = 0x1f; - if (csi->plat_data->tx_mode == CSI_MODE) - mipi_dphy_power_on(csi); - csi->txphy_pwron = true; if (tx_5v_power_present(sd)) schedule_delayed_work(&csi->delayed_work_enable_hotplug, msecs_to_jiffies(4000)); diff --git a/drivers/media/platform/rockchip/vpss/common.h b/drivers/media/platform/rockchip/vpss/common.h index 6e4d71b8c1c7..5d64bf0090df 100644 --- a/drivers/media/platform/rockchip/vpss/common.h +++ b/drivers/media/platform/rockchip/vpss/common.h @@ -90,6 +90,7 @@ static inline struct vb2_queue *to_vb2_queue(struct file *file) extern int rkvpss_debug; extern struct platform_driver rkvpss_plat_drv; +extern int rkvpss_cfginfo_num; void rkvpss_idx_write(struct rkvpss_device *dev, u32 reg, u32 val, int idx); void rkvpss_unite_write(struct rkvpss_device *dev, u32 reg, u32 val); diff --git a/drivers/media/platform/rockchip/vpss/dev.c b/drivers/media/platform/rockchip/vpss/dev.c index 971d4e209691..e93011d10fb3 100644 --- a/drivers/media/platform/rockchip/vpss/dev.c +++ b/drivers/media/platform/rockchip/vpss/dev.c @@ -24,7 +24,7 @@ int rkvpss_debug; module_param_named(debug, rkvpss_debug, int, 0644); -MODULE_PARM_DESC(debug, "Debug level (0-3)"); +MODULE_PARM_DESC(debug, "Debug level (0-6)"); static bool rkvpss_clk_dbg; module_param_named(clk_dbg, rkvpss_clk_dbg, bool, 0644); @@ -34,6 +34,30 @@ static char rkvpss_version[RKVPSS_VERNO_LEN]; module_param_string(version, rkvpss_version, RKVPSS_VERNO_LEN, 0444); MODULE_PARM_DESC(version, "version number"); +int rkvpss_cfginfo_num = 5; + +static int rkvpss_get_cfginfo_num(const char *val, const struct kernel_param *kp) +{ + int num, ret; + + ret = kstrtoint(val, 10, &num); + if (ret) + return ret; + if (num < 0 || num > 50) { + pr_info("rkvpss_cfginfo_num must be range of 0 to 50"); + return -EINVAL; + } + + return param_set_int(val, kp); +} + +static const struct kernel_param_ops cfginfo_num_ops = { + .set = rkvpss_get_cfginfo_num, + .get = param_get_int, +}; +module_param_cb(cfginfo_num, &cfginfo_num_ops, &rkvpss_cfginfo_num, 0644); +MODULE_PARM_DESC(cfginfo_num, "rkvpss offline cfginfo number"); + void rkvpss_set_clk_rate(struct clk *clk, unsigned long rate) { if (rkvpss_clk_dbg) @@ -323,6 +347,8 @@ static int rkvpss_plat_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); vpss_dev->is_probe_end = true; init_waitqueue_head(&vpss_dev->stop_done); + vpss_dev->is_suspend = false; + vpss_dev->is_idle = true; return 0; err_unreg_media_dev: @@ -351,7 +377,7 @@ static int rkvpss_plat_remove(struct platform_device *pdev) return 0; } -static int __maybe_unused rkvpss_runtime_suspend(struct device *dev) +static int __maybe_unused rkvpss_dev_runtime_suspend(struct device *dev) { struct rkvpss_device *vpss_dev = dev_get_drvdata(dev); int ret; @@ -362,7 +388,7 @@ static int __maybe_unused rkvpss_runtime_suspend(struct device *dev) return (ret > 0) ? 0 : ret; } -static int __maybe_unused rkvpss_runtime_resume(struct device *dev) +static int __maybe_unused rkvpss_dev_runtime_resume(struct device *dev) { struct rkvpss_device *vpss_dev = dev_get_drvdata(dev); int ret; @@ -373,9 +399,46 @@ static int __maybe_unused rkvpss_runtime_resume(struct device *dev) return (ret > 0) ? 0 : ret; } +static int rkvpss_pm_suspend(struct device *dev) +{ + struct rkvpss_device *vpss_dev = dev_get_drvdata(dev); + u32 ret; + + v4l2_dbg(4, rkvpss_debug, &vpss_dev->v4l2_dev, "%s enter\n", __func__); + if (vpss_dev->vpss_sdev.state == VPSS_STOP) + return 0; + + vpss_dev->is_suspend = true; + /* wait fe*/ + if (!vpss_dev->is_idle) { + ret = wait_for_completion_timeout(&vpss_dev->pm_suspend_wait_fe, + msecs_to_jiffies(200)); + if (!ret) + v4l2_info(&vpss_dev->v4l2_dev, "%s wait fe timeout\n", __func__); + } + v4l2_dbg(4, rkvpss_debug, &vpss_dev->v4l2_dev, "%s exit\n", __func__); + return 0; +} + +static int rkvpss_pm_resume(struct device *dev) +{ + struct rkvpss_device *vpss_dev = dev_get_drvdata(dev); + + v4l2_dbg(4, rkvpss_debug, &vpss_dev->v4l2_dev, "%s enter\n", __func__); + if (vpss_dev->vpss_sdev.state == VPSS_STOP) + return 0; + + vpss_dev->is_suspend = false; + v4l2_dbg(4, rkvpss_debug, &vpss_dev->v4l2_dev, "%s exit\n", __func__); + + return 0; +} + static const struct dev_pm_ops rkvpss_plat_pm_ops = { - SET_RUNTIME_PM_OPS(rkvpss_runtime_suspend, - rkvpss_runtime_resume, NULL) + .suspend = rkvpss_pm_suspend, + .resume = rkvpss_pm_resume, + SET_RUNTIME_PM_OPS(rkvpss_dev_runtime_suspend, + rkvpss_dev_runtime_resume, NULL) }; struct platform_driver rkvpss_plat_drv = { diff --git a/drivers/media/platform/rockchip/vpss/dev.h b/drivers/media/platform/rockchip/vpss/dev.h index be9830241462..eaebd3fbdab0 100644 --- a/drivers/media/platform/rockchip/vpss/dev.h +++ b/drivers/media/platform/rockchip/vpss/dev.h @@ -79,6 +79,9 @@ struct rkvpss_device { unsigned int irq_ends_mask; bool is_probe_end; + bool is_suspend; + bool is_idle; + struct completion pm_suspend_wait_fe; }; void rkvpss_pipeline_default_fmt(struct rkvpss_device *dev); diff --git a/drivers/media/platform/rockchip/vpss/hw.c b/drivers/media/platform/rockchip/vpss/hw.c index bd974b17cfeb..f5bd2c96d5e2 100644 --- a/drivers/media/platform/rockchip/vpss/hw.c +++ b/drivers/media/platform/rockchip/vpss/hw.c @@ -702,6 +702,107 @@ static const struct of_device_id rkvpss_hw_of_match[] = { {}, }; +void rkvpss_hw_reg_save(struct rkvpss_hw_dev *dev) +{ + void *buf = dev->sw_reg; + + dev_info(dev->dev, "%s\n", __func__); + memcpy_fromio(buf, dev->base_addr, RKVPSS_SW_REG_SIZE); +} + +void rkvpss_hw_reg_restore(struct rkvpss_hw_dev *dev) +{ + void __iomem *base = dev->base_addr; + void *reg_buf = dev->sw_reg; + u32 val, *reg, i; + + dev_info(dev->dev, "%s\n", __func__); + + /* cmsc */ + for (i = RKVPSS_CMSC_BASE; i <= RKVPSS_CMSC_WIN7_L3_SLP; i += 4) { + if (i == RKVPSS_CMSC_UPDATE) + continue; + reg = reg_buf + i; + writel(*reg, base + i); + } + val = RKVPSS_CMSC_GEN_UPD | RKVPSS_CMSC_UPDATE; + writel(val, base + RKVPSS_CMSC_UPDATE); + + /* crop1 */ + for (i = RKVPSS_CROP1_CTRL; i <= RKVPSS_CROP1_3_V_SIZE; i += 4) { + if (i == RKVPSS_CROP1_UPDATE) + continue; + reg = reg_buf + i; + writel(*reg, base + i); + } + val = RKVPSS_CROP_GEN_UPD | RKVPSS_CROP_FORCE_UPD; + writel(val, base + RKVPSS_CROP1_UPDATE); + writel(val, base + RKVPSS_CROP1_UPDATE); + + /* scale */ + for (i = RKVPSS_ZME_BASE; i <= RKVPSS_ZME_UV_YSCL_FACTOR; i += 4) { + if (i == RKVPSS_ZME_UPDATE) + continue; + reg = reg_buf + i; + writel(*reg, base + i); + } + val = RKVPSS_ZME_GEN_UPD | RKVPSS_ZME_FORCE_UPD; + writel(val, base + RKVPSS_ZME_UPDATE); + + for (i = RKVPSS_SCALE1_BASE; i <= RKVPSS_SCALE1_IN_CROP_OFFSET; i += 4) { + if (i == RKVPSS_SCALE1_UPDATE) + continue; + reg = reg_buf + i; + writel(*reg, base + i); + } + val = RKVPSS_SCL_GEN_UPD | RKVPSS_SCL_FORCE_UPD; + writel(val, base + RKVPSS_SCALE1_UPDATE); + + for (i = RKVPSS_SCALE2_BASE; i <= RKVPSS_SCALE2_IN_CROP_OFFSET; i += 4) { + if (i == RKVPSS_SCALE2_UPDATE) + continue; + reg = reg_buf + i; + writel(*reg, base + i); + } + val = RKVPSS_SCL_GEN_UPD | RKVPSS_SCL_FORCE_UPD; + writel(val, base + RKVPSS_SCALE2_UPDATE); + + for (i = RKVPSS_SCALE3_BASE; i <= RKVPSS_SCALE3_IN_CROP_OFFSET; i += 4) { + if (i == RKVPSS_SCALE3_UPDATE) + continue; + reg = reg_buf + i; + writel(*reg, base + i); + } + val = RKVPSS_SCL_GEN_UPD | RKVPSS_SCL_FORCE_UPD; + writel(val, base + RKVPSS_SCALE3_UPDATE); + + /* mi */ + for (i = RKVPSS_MI_BASE; i <= RKVPSS_MI_CHN3_WR_LINE_CNT; i += 4) { + if (i >= RKVPSS_MI_RD_CTRL && i <= RKVPSS_MI_RD_Y_HEIGHT_SHD) + continue; + if (i == RKVPSS_MI_WR_INIT) + continue; + reg = reg_buf + i; + writel(*reg, base + i); + } + val = RKVPSS_MI_FORCE_UPD; + writel(val, base + RKVPSS_MI_WR_INIT); + writel(val, base + RKVPSS_MI_WR_INIT); + + /* vpss ctrl */ + for (i = RKVPSS_VPSS_BASE; i <= RKVPSS_VPSS_Y2R_OFF2; i += 4) { + if (i == RKVPSS_VPSS_UPDATE || i == RKVPSS_VPSS_RESET) + continue; + reg = reg_buf + i; + writel(*reg, base + i); + } + val = RKVPSS_CFG_FORCE_UPD | RKVPSS_CFG_GEN_UPD | RKVPSS_MIR_GEN_UPD | + RKVPSS_ONLINE2_CHN_FORCE_UPD; + if (!dev->is_ofl_cmsc) + val |= RKVPSS_MIR_FORCE_UPD; + writel(val, base + RKVPSS_VPSS_UPDATE); +} + static int rkvpss_hw_probe(struct platform_device *pdev) { const struct of_device_id *match; @@ -721,6 +822,9 @@ static int rkvpss_hw_probe(struct platform_device *pdev) if (!hw_dev) return -ENOMEM; + hw_dev->sw_reg = devm_kzalloc(dev, RKVPSS_SW_REG_SIZE, GFP_KERNEL); + if (!hw_dev->sw_reg) + return -ENOMEM; dev_set_drvdata(dev, hw_dev); hw_dev->dev = dev; match_data = match->data; @@ -749,8 +853,8 @@ static int rkvpss_hw_probe(struct platform_device *pdev) irq = platform_get_irq_byname(pdev, match_data->irqs[i].name); if (irq < 0) { dev_err(dev, "no irq %s in dts\n", match_data->irqs[i].name); - ret = irq; - goto err; + ret = irq; + goto err; } ret = devm_request_irq(dev, irq, match_data->irqs[i].irq_hdl, @@ -798,6 +902,7 @@ static int rkvpss_hw_probe(struct platform_device *pdev) hw_dev->is_dma_contig = true; hw_dev->is_shutdown = false; hw_dev->is_mmu = is_iommu_enable(dev); + hw_dev->is_suspend = false; ret = of_reserved_mem_device_init(dev); if (ret) { is_mem_reserved = false; @@ -839,40 +944,72 @@ static void rkvpss_hw_shutdown(struct platform_device *pdev) } } -static int __maybe_unused rkvpss_runtime_suspend(struct device *dev) +static int __maybe_unused rkvpss_hw_runtime_suspend(struct device *dev) { struct rkvpss_hw_dev *hw_dev = dev_get_drvdata(dev); + u32 ret; + + if (rkvpss_debug >= 4) + dev_info(dev, "%s enter\n", __func__); + + if (dev->power.runtime_status) { + rkvpss_hw_write(hw_dev, RKVPSS_MI_IMSC, 0); + rkvpss_hw_write(hw_dev, RKVPSS_VPSS_IMSC, 0); + hw_dev->ofl_dev.mode_sel_en = true; + } else { + rkvpss_hw_reg_save(hw_dev); + hw_dev->is_suspend = true; + if (hw_dev->ofl_dev.pm_need_wait) { + ret = wait_for_completion_timeout(&hw_dev->ofl_dev.pm_cmpl, + msecs_to_jiffies(200)); + if (!ret) + dev_info(dev, "%s pm wait offline timeout\n", __func__); + } + } - rkvpss_hw_write(hw_dev, RKVPSS_MI_IMSC, 0); - rkvpss_hw_write(hw_dev, RKVPSS_VPSS_IMSC, 0); disable_sys_clk(hw_dev); - hw_dev->ofl_dev.mode_sel_en = true; + + if (rkvpss_debug >= 4) + dev_info(dev, "%s exit\n", __func__); + return 0; } -static int __maybe_unused rkvpss_runtime_resume(struct device *dev) +static int __maybe_unused rkvpss_hw_runtime_resume(struct device *dev) { struct rkvpss_hw_dev *hw_dev = dev_get_drvdata(dev); void __iomem *base = hw_dev->base_addr; int i; + if (rkvpss_debug >= 4) + dev_info(dev, "%s enter\n", __func__); + enable_sys_clk(hw_dev); rkvpss_soft_reset(hw_dev); - for (i = 0; i < hw_dev->dev_num; i++) { - void *buf = hw_dev->vpss[i]->sw_base_addr; + if (dev->power.runtime_status) { + for (i = 0; i < hw_dev->dev_num; i++) { + void *buf = hw_dev->vpss[i]->sw_base_addr; - memset(buf, 0, RKVPSS_SW_REG_SIZE_MAX); - memcpy_fromio(buf, base, RKVPSS_SW_REG_SIZE); + memset(buf, 0, RKVPSS_SW_REG_SIZE_MAX); + memcpy_fromio(buf, base, RKVPSS_SW_REG_SIZE); + } + } else { + rkvpss_hw_reg_restore(hw_dev); + hw_dev->is_suspend = false; } + + if (rkvpss_debug >= 4) + dev_info(dev, "%s exit\n", __func__); + return 0; } static const struct dev_pm_ops rkvpss_hw_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) - SET_RUNTIME_PM_OPS(rkvpss_runtime_suspend, - rkvpss_runtime_resume, NULL) + SET_RUNTIME_PM_OPS(rkvpss_hw_runtime_suspend, + rkvpss_hw_runtime_resume, NULL) }; static struct platform_driver rkvpss_hw_drv = { diff --git a/drivers/media/platform/rockchip/vpss/hw.h b/drivers/media/platform/rockchip/vpss/hw.h index 662f1763b17b..8fb8bff15ad8 100644 --- a/drivers/media/platform/rockchip/vpss/hw.h +++ b/drivers/media/platform/rockchip/vpss/hw.h @@ -33,6 +33,7 @@ struct rkvpss_hw_dev { struct rkvpss_device *vpss[VPSS_MAX_DEV]; struct rkvpss_offline_dev ofl_dev; struct list_head list; + void *sw_reg; int clk_rate_tbl_num; int clks_num; int dev_num; @@ -52,6 +53,7 @@ struct rkvpss_hw_dev { bool is_single; bool is_dma_contig; bool is_shutdown; + bool is_suspend; }; #define RKVPSS_ZME_TAP_COE(x, y) (((x) & 0x3ff) | (((y) & 0x3ff) << 16)) @@ -67,4 +69,6 @@ void rkvpss_hw_write(struct rkvpss_hw_dev *hw_dev, u32 reg, u32 val); u32 rkvpss_hw_read(struct rkvpss_hw_dev *hw_dev, u32 reg); void rkvpss_hw_set_bits(struct rkvpss_hw_dev *hw, u32 reg, u32 mask, u32 val); void rkvpss_hw_clear_bits(struct rkvpss_hw_dev *hw, u32 reg, u32 mask); +void rkvpss_hw_reg_save(struct rkvpss_hw_dev *dev); +void rkvpss_hw_reg_restore(struct rkvpss_hw_dev *dev); #endif diff --git a/drivers/media/platform/rockchip/vpss/stream.c b/drivers/media/platform/rockchip/vpss/stream.c index 97ccd297fa5b..2ebdbf3c7d09 100644 --- a/drivers/media/platform/rockchip/vpss/stream.c +++ b/drivers/media/platform/rockchip/vpss/stream.c @@ -779,8 +779,9 @@ static void rkvpss_buf_done_task(unsigned long arg) buf = list_first_entry(&local_list, struct rkvpss_buffer, queue); list_del(&buf->queue); v4l2_dbg(2, rkvpss_debug, &stream->dev->v4l2_dev, - "%s id:%d seq:%d buf:0x%x done\n", - node->vdev.name, stream->id, buf->vb.sequence, buf->dma[0]); + "%s stream:%d index:%d seq:%d buf:0x%x done\n", + node->vdev.name, stream->id, buf->vb.vb2_buf.index, + buf->vb.sequence, buf->dma[0]); vb2_buffer_done(&buf->vb.vb2_buf, stream->streaming ? VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR); } @@ -794,6 +795,9 @@ static void rkvpss_stream_buf_done(struct rkvpss_stream *stream, if (!stream || !buf) return; + v4l2_dbg(3, rkvpss_debug, &stream->dev->v4l2_dev, + "stream:%d\n", stream->id); + spin_lock_irqsave(&stream->vbq_lock, lock_flags); list_add_tail(&buf->queue, &stream->buf_done_list); spin_unlock_irqrestore(&stream->vbq_lock, lock_flags); @@ -807,6 +811,8 @@ static void rkvpss_frame_end(struct rkvpss_stream *stream) struct rkvpss_buffer *buf = NULL; unsigned long lock_flags = 0; + v4l2_dbg(3, rkvpss_debug, &dev->v4l2_dev, + "stream:%d\n", stream->id); spin_lock_irqsave(&stream->vbq_lock, lock_flags); if (stream->curr_buf) { buf = stream->curr_buf; @@ -906,8 +912,8 @@ static void rkvpss_buf_queue(struct vb2_buffer *vb) } v4l2_dbg(2, rkvpss_debug, &dev->v4l2_dev, - "%s stream:%d buf:0x%x\n", __func__, - stream->id, vpssbuf->dma[0]); + "%s stream:%d index:%d buf:0x%x\n", __func__, + stream->id, vb->index, vpssbuf->dma[0]); spin_lock_irqsave(&stream->vbq_lock, lock_flags); list_add_tail(&vpssbuf->queue, &stream->buf_queue); diff --git a/drivers/media/platform/rockchip/vpss/vpss.c b/drivers/media/platform/rockchip/vpss/vpss.c index 3dd809ea1448..ab5c74fc2c90 100644 --- a/drivers/media/platform/rockchip/vpss/vpss.c +++ b/drivers/media/platform/rockchip/vpss/vpss.c @@ -246,10 +246,11 @@ static int rkvpss_sof(struct rkvpss_subdev *sdev, struct rkisp_vpss_sof *info) sdev->frame_seq = info->seq; sdev->frame_timestamp = info->timestamp; dev->unite_index = info->unite_index; + dev->is_idle = false; v4l2_dbg(3, rkvpss_debug, &dev->v4l2_dev, - "%s unite_mode:%u, unite_indev:%u\n", __func__, - dev->unite_mode, dev->unite_index); + "%s unite_mode:%u, unite_indev:%u seq:%d\n", __func__, + dev->unite_mode, dev->unite_index, info->seq); rkvpss_cmsc_config(dev, !info->irq); for (i = 0; i < RKVPSS_OUTPUT_MAX; i++) { @@ -418,6 +419,10 @@ void rkvpss_check_idle(struct rkvpss_device *dev, u32 irq) dev->irq_ends = 0; rkvpss_end_notify_isp(dev); + dev->is_idle = true; + + if (dev->is_suspend) + complete(&dev->pm_suspend_wait_fe); } int rkvpss_register_subdev(struct rkvpss_device *dev, @@ -451,6 +456,7 @@ int rkvpss_register_subdev(struct rkvpss_device *dev, if (ret < 0) goto free_media; rkvpss_subdev_default_fmt(vpss_sdev); + init_completion(&dev->pm_suspend_wait_fe); return ret; free_media: media_entity_cleanup(&sd->entity); diff --git a/drivers/media/platform/rockchip/vpss/vpss_offline.c b/drivers/media/platform/rockchip/vpss/vpss_offline.c index 09f3e448e0af..a26cf8554c6b 100644 --- a/drivers/media/platform/rockchip/vpss/vpss_offline.c +++ b/drivers/media/platform/rockchip/vpss/vpss_offline.c @@ -148,7 +148,8 @@ static struct rkvpss_offline_buf *buf_add(struct file *file, int id, int fd, int buf->alloc = false; list_add_tail(&buf->list, &ofl->list); v4l2_dbg(1, rkvpss_debug, &ofl->v4l2_dev, - "%s file:%p dev_id:%d fd:%d dbuf:%p\n", __func__, file, id, fd, dbuf); + "%s file:%p dev_id:%d fd:%d dbuf:%p size:%d\n", __func__, + file, id, fd, dbuf, size); } else { dma_buf_put(dbuf); } @@ -417,6 +418,13 @@ static void poly_phase_scale(struct rkvpss_frame_cfg *frame_cfg, end: val = RKVPSS_ZME_GEN_UPD | RKVPSS_ZME_FORCE_UPD; rkvpss_hw_write(hw, RKVPSS_ZME_UPDATE, val); + + v4l2_dbg(3, rkvpss_debug, &ofl->v4l2_dev, + "%s unite:%d left:%d hw ctrl:0x%x y_src_size:0x%x y_dst_size:0x%x\n", + __func__, unite, left, + rkvpss_hw_read(hw, RKVPSS_ZME_CTRL), + rkvpss_hw_read(hw, RKVPSS_ZME_Y_SRC_SIZE), + rkvpss_hw_read(hw, RKVPSS_ZME_Y_DST_SIZE)); } static void bilinear_scale(struct rkvpss_frame_cfg *frame_cfg, @@ -537,6 +545,13 @@ end: rkvpss_hw_write(hw, reg_base, ctrl); val = RKVPSS_SCL_GEN_UPD | RKVPSS_SCL_FORCE_UPD; rkvpss_hw_write(hw, reg_base + 0x4, val); + + v4l2_dbg(3, rkvpss_debug, &ofl->v4l2_dev, + "%s unite:%d left:%d hw ch:%d ctrl:0x%x y_src_size:0x%x y_dst_size:0x%x\n", + __func__, unite, left, idx, + rkvpss_hw_read(hw, reg_base), + rkvpss_hw_read(hw, reg_base + 0x8), + rkvpss_hw_read(hw, reg_base + 0xc)); } static void scale_config(struct file *file, @@ -556,7 +571,7 @@ static void scale_config(struct file *file, } } -static void cmsc_config(struct rkvpss_offline_dev *ofl, +static int cmsc_config(struct rkvpss_offline_dev *ofl, struct rkvpss_frame_cfg *cfg, bool unite, bool left) { struct rkvpss_hw_dev *hw = ofl->hw; @@ -568,9 +583,10 @@ static void cmsc_config(struct rkvpss_offline_dev *ofl, u32 ch_win_mode[RKVPSS_OUTPUT_MAX]; u32 win_color[RKVPSS_CMSC_WIN_MAX]; u32 val, slope, hor, mask, mosaic_block = 0, ctrl = 0; + u32 hw_in_w, hw_in_h; if (!hw->is_ofl_cmsc) - return; + return 0; for (i = 0; i < RKVPSS_OUTPUT_MAX; i++) { if (!cfg->output[i].enable) @@ -597,14 +613,8 @@ static void cmsc_config(struct rkvpss_offline_dev *ofl, cfg->output[i].cmsc.win[j].cover_color_a = 15; win_color[j] |= RKVPSS_CMSC_WIN_ALPHA(cfg->output[i].cmsc.win[j].cover_color_a); } - for (k = 0; k < RKVPSS_CMSC_POINT_MAX; k++) { + for (k = 0; k < RKVPSS_CMSC_POINT_MAX; k++) tmp_cfg.win[j].point[k] = cmsc_cfg->win[j].point[k]; - v4l2_dbg(3, rkvpss_debug, &ofl->v4l2_dev, - "%s input params dev_id:%d, unite:%d left:%d ch:%d win:%d point:%d x:%u y:%u", - __func__, cfg->dev_id, unite, left, i, j, k, - tmp_cfg.win[j].point[k].x, - tmp_cfg.win[j].point[k].y); - } } } @@ -705,10 +715,23 @@ static void cmsc_config(struct rkvpss_offline_dev *ofl, } rkvpss_hw_write(hw, RKVPSS_CMSC_CHN0_WIN + i * 4, ch_win_en[i]); rkvpss_hw_write(hw, RKVPSS_CMSC_CHN0_MODE + i * 4, ch_win_mode[i]); + hw_in_w = rkvpss_hw_read(hw, RKVPSS_MI_RD_Y_WIDTH); + hw_in_h = rkvpss_hw_read(hw, RKVPSS_MI_RD_Y_HEIGHT); for (j = 0; j < RKVPSS_CMSC_WIN_MAX; j++) { if (!(ch_win_en[i] & BIT(j))) continue; for (k = 0; k < RKVPSS_CMSC_POINT_MAX; k++) { + if (tmp_cfg.win[j].point[k].x > hw_in_w || + tmp_cfg.win[j].point[k].y > hw_in_h) { + v4l2_err(&ofl->v4l2_dev, + "%s cmsc coordinate error dev_id:%d unite:%u left:%u ch:%d win:%d point:%d x:%u y:%u hw_in_w:%u hw_in_h:%u\n", + __func__, cfg->dev_id, unite, left, + i, j, k, + tmp_cfg.win[j].point[k].x, + tmp_cfg.win[j].point[k].y, + hw_in_w, hw_in_w); + return -EINVAL; + } val = RKVPSS_CMSC_WIN_VTX(tmp_cfg.win[j].point[k].x, tmp_cfg.win[j].point[k].y); rkvpss_hw_write(hw, RKVPSS_CMSC_WIN0_L0_VTX + k * 8 + j * 32, val); @@ -718,7 +741,7 @@ static void cmsc_config(struct rkvpss_offline_dev *ofl, &slope, &hor); val = RKVPSS_CMSC_WIN_SLP(slope, hor); rkvpss_hw_write(hw, RKVPSS_CMSC_WIN0_L0_SLP + k * 8 + j * 32, val); - v4l2_dbg(3, rkvpss_debug, &ofl->v4l2_dev, + v4l2_dbg(4, rkvpss_debug, &ofl->v4l2_dev, "%s dev_id:%d, unite:%d left:%d ch:%d win:%d point:%d x:%u y:%u", __func__, cfg->dev_id, unite, left, i, j, k, tmp_cfg.win[j].point[k].x, @@ -736,9 +759,11 @@ static void cmsc_config(struct rkvpss_offline_dev *ofl, val = RKVPSS_CMSC_GEN_UPD | RKVPSS_CMSC_FORCE_UPD; rkvpss_hw_write(hw, RKVPSS_CMSC_UPDATE, val); - v4l2_dbg(4, rkvpss_debug, &ofl->v4l2_dev, - "%s dev_id:%d, unite:%d left:%d ctrl:0x%x update_val:0x%x", + v4l2_dbg(3, rkvpss_debug, &ofl->v4l2_dev, + "%s dev_id:%d, unite:%d left:%d hw ctrl:0x%x update_val:0x%x", __func__, cfg->dev_id, unite, left, ctrl, val); + + return 0; } static void aspt_config(struct file *file, @@ -789,6 +814,14 @@ static void aspt_config(struct file *file, rkvpss_hw_write(hw, reg_base, RKVPSS_RATIO_EN); val = RKVPSS_RATIO_FORCE_UPD | RKVPSS_RATIO_GEN_UPD; rkvpss_hw_write(hw, reg_base + 0x4, val); + + v4l2_dbg(3, rkvpss_debug, &ofl->v4l2_dev, + "%s hw ch:%d ctrl:0x%x in_size:0x%x out_size:0x%x offset:0x%x\n", + __func__, i, + rkvpss_hw_read(hw, reg_base), + rkvpss_hw_read(hw, reg_base + 0x10), + rkvpss_hw_read(hw, reg_base + 0x14), + rkvpss_hw_read(hw, reg_base + 0x18)); } } @@ -821,14 +854,16 @@ static void add_cfginfo(struct rkvpss_offline_dev *ofl, struct rkvpss_frame_cfg list_for_each_entry(cfginfo, &ofl->cfginfo_list, list) { count++; } - if (count >= 5) { + while (count >= rkvpss_cfginfo_num && count != 0) { first_cfg = list_first_entry(&ofl->cfginfo_list, struct rkvpss_ofl_cfginfo, list); list_del_init(&first_cfg->list); kfree(first_cfg); - list_add_tail(&new_cfg->list, &ofl->cfginfo_list); - } else { - list_add_tail(&new_cfg->list, &ofl->cfginfo_list); + count--; } + if (rkvpss_cfginfo_num) + list_add_tail(&new_cfg->list, &ofl->cfginfo_list); + else + kfree(new_cfg); mutex_unlock(&ofl->ofl_lock); } @@ -1028,7 +1063,7 @@ static int read_config(struct file *file, struct rkvpss_frame_cfg *cfg, bool uni } v4l2_dbg(3, rkvpss_debug, &ofl->v4l2_dev, - "%s unite:%d left:%d width:%d height:%d y_base:0x%x\n", + "%s unite:%d left:%d hw width:%d height:%d y_base:0x%x\n", __func__, unite, left, rkvpss_hw_read(hw, RKVPSS_MI_RD_Y_WIDTH), rkvpss_hw_read(hw, RKVPSS_MI_RD_Y_HEIGHT), @@ -1144,13 +1179,17 @@ static void crop_config(struct file *file, struct rkvpss_frame_cfg *cfg, bool un rkvpss_hw_write(hw, RKVPSS_CROP0_CTRL, crop_en); rkvpss_hw_write(hw, RKVPSS_CROP0_UPDATE, RKVPSS_CROP_FORCE_UPD); - v4l2_dbg(3, rkvpss_debug, &ofl->v4l2_dev, - "%s unite:%d left:%d h_offs:%d v_offs:%d width:%d height:%d\n", - __func__, unite, left, - rkvpss_hw_read(hw, RKVPSS_CROP0_0_H_OFFS), - rkvpss_hw_read(hw, RKVPSS_CROP0_0_V_OFFS), - rkvpss_hw_read(hw, RKVPSS_CROP0_0_H_SIZE), - rkvpss_hw_read(hw, RKVPSS_CROP0_0_V_SIZE)); + for (i = 0; i < RKVPSS_OUTPUT_MAX; i++) { + if (!cfg->output[i].enable) + continue; + v4l2_dbg(3, rkvpss_debug, &ofl->v4l2_dev, + "%s unite:%d left:%d hw ch:%d h_offs:%d v_offs:%d width:%d height:%d\n", + __func__, unite, left, i, + rkvpss_hw_read(hw, RKVPSS_CROP0_0_H_OFFS + i * 0x10), + rkvpss_hw_read(hw, RKVPSS_CROP0_0_V_OFFS + i * 0x10), + rkvpss_hw_read(hw, RKVPSS_CROP0_0_H_SIZE + i * 0x10), + rkvpss_hw_read(hw, RKVPSS_CROP0_0_V_SIZE + i * 0x10)); + } } static int write_config(struct file *file, struct rkvpss_frame_cfg *cfg, bool unite, bool left) @@ -1375,7 +1414,7 @@ static int write_config(struct file *file, struct rkvpss_frame_cfg *cfg, bool un mi_update |= (RKVPSS_MI_CHN0_FORCE_UPD << i); v4l2_dbg(3, rkvpss_debug, &ofl->v4l2_dev, - "%s unite:%d left:%d ch:%d y_size:%d y_stride:%d y_pic_size:%d y_base:0x%x", + "%s unite:%d left:%d hw ch:%d y_size:%d y_stride:%d y_pic_size:%d y_base:0x%x", __func__, unite, left, i, rkvpss_hw_read(hw, RKVPSS_MI_CHN0_WR_Y_SIZE + i * 100), rkvpss_hw_read(hw, RKVPSS_MI_CHN0_WR_Y_STRIDE + i * 100), @@ -1505,22 +1544,22 @@ static void calc_unite_scl_params(struct file *file, struct rkvpss_frame_cfg *cf params->scl_in_crop_w_y = right_y_crop_total - params->quad_crop_w; params->scl_in_crop_w_c = right_c_crop_total - params->quad_crop_w; - if (rkvpss_debug >= 2) { + if (rkvpss_debug >= 4) { v4l2_info(&ofl->v4l2_dev, "%s dev_id:%d seq:%d ch:%d y_w_fac:%u c_w_fac:%u y_h_fac:%u c_h_fac:%u\n", __func__, cfg->dev_id, cfg->sequence, i, params->y_w_fac, params->c_w_fac, params->y_h_fac, params->c_h_fac); v4l2_info(&ofl->v4l2_dev, - "\t%s unite_right_enlarge:%u", - __func__, ofl->unite_right_enlarge); + "\t\t\t\t\t\t unite_right_enlarge:%u", + ofl->unite_right_enlarge); v4l2_info(&ofl->v4l2_dev, - "\t%s y_w_phase:%u c_w_phase:%u quad_crop_w:%u scl_in_crop_w_y:%u scl_in_crop_w_c:%u\n", - __func__, params->y_w_phase, params->c_w_phase, + "\t\t\t\t\t\t y_w_phase:%u c_w_phase:%u quad_crop_w:%u scl_in_crop_w_y:%u scl_in_crop_w_c:%u\n", + params->y_w_phase, params->c_w_phase, params->quad_crop_w, params->scl_in_crop_w_y, params->scl_in_crop_w_c); v4l2_info(&ofl->v4l2_dev, - "\t%s right_scl_need_size_y:%u right_scl_need_size_c:%u\n", - __func__, params->right_scl_need_size_y, + "\t\t\t\t\t\t right_scl_need_size_y:%u right_scl_need_size_c:%u\n", + params->right_scl_need_size_y, params->right_scl_need_size_c); } } @@ -1531,41 +1570,12 @@ static int rkvpss_ofl_run(struct file *file, struct rkvpss_frame_cfg *cfg, bool struct rkvpss_offline_dev *ofl = video_drvdata(file); struct rkvpss_hw_dev *hw = ofl->hw; u32 update, val, mask; - ktime_t t = 0; - s64 us = 0; int ret, i; - u64 ns; bool left_tmp; - if (rkvpss_debug >= 2) { - v4l2_info(&ofl->v4l2_dev, - "%s dev_id:%d seq:%d mirror:%d input:%dx%d buffd:%d format:%c%c%c%c\n", - __func__, cfg->dev_id, cfg->sequence, cfg->mirror, - cfg->input.width, cfg->input.height, cfg->input.buf_fd, - cfg->input.format, cfg->input.format >> 8, - cfg->input.format >> 16, cfg->input.format >> 24); - for (i = 0; i < RKVPSS_OUTPUT_MAX; i++) { - if (!cfg->output[i].enable) - continue; - v4l2_info(&ofl->v4l2_dev, - "\t\t\tch%d crop:(%d,%d)/%dx%d scl:%dx%d flip:%d buffd:%d format:%c%c%c%c\n", - i, cfg->output[i].crop_h_offs, cfg->output[i].crop_v_offs, - cfg->output[i].crop_width, cfg->output[i].crop_height, - cfg->output[i].scl_width, cfg->output[i].scl_height, - cfg->output[i].flip, cfg->output[i].buf_fd, - cfg->output[i].format, cfg->output[i].format >> 8, - cfg->output[i].format >> 16, cfg->output[i].format >> 24); - } - t = ktime_get(); - } - if (!unite || left) add_cfginfo(ofl, cfg); - ns = ktime_get_ns(); - ofl->dev_rate[cfg->dev_id].in_rate = ns - ofl->dev_rate[cfg->dev_id].in_timestamp; - ofl->dev_rate[cfg->dev_id].in_timestamp = ns; - init_completion(&ofl->cmpl); ofl->mode_sel_en = false; @@ -1581,7 +1591,9 @@ static int rkvpss_ofl_run(struct file *file, struct rkvpss_frame_cfg *cfg, bool else left_tmp = left; - cmsc_config(ofl, cfg, unite, left_tmp); + ret = cmsc_config(ofl, cfg, unite, left_tmp); + if (ret) + return ret; crop_config(file, cfg, unite, left_tmp); scale_config(file, cfg, unite, left_tmp); if (!unite) @@ -1614,20 +1626,6 @@ static int rkvpss_ofl_run(struct file *file, struct rkvpss_frame_cfg *cfg, bool rkvpss_hw_write(hw, RKVPSS_VPSS_UPDATE, update); rkvpss_hw_set_bits(hw, RKVPSS_VPSS_IMSC, 0, RKVPSS_ALL_FRM_END); - if (rkvpss_debug >=5) { - v4l2_info(&ofl->v4l2_dev, - "%s dev_id%d unite:%d left:%d\n", - __func__, cfg->dev_id, unite, left); - for (i = 0; i < 16128; i += 16) { - printk("%04x: %08x %08x %08x %08x\n", - i, - rkvpss_hw_read(hw, i), - rkvpss_hw_read(hw, i + 4), - rkvpss_hw_read(hw, i + 8), - rkvpss_hw_read(hw, i + 12)); - } - } - rkvpss_hw_write(hw, RKVPSS_MI_RD_START, RKVPSS_MI_RD_ST); ret = wait_for_completion_timeout(&ofl->cmpl, msecs_to_jiffies(500)); @@ -1638,19 +1636,6 @@ static int rkvpss_ofl_run(struct file *file, struct rkvpss_frame_cfg *cfg, bool ret = 0; } - if (rkvpss_debug >= 2) { - us = ktime_us_delta(ktime_get(), t); - v4l2_info(&ofl->v4l2_dev, - "%s end, time:%lldus\n", __func__, us); - } - - ns = ktime_get_ns(); - ofl->dev_rate[cfg->dev_id].out_rate = ns - ofl->dev_rate[cfg->dev_id].out_timestamp; - ofl->dev_rate[cfg->dev_id].out_timestamp = ns; - ofl->dev_rate[cfg->dev_id].sequence = cfg->sequence; - ofl->dev_rate[cfg->dev_id].delay = ofl->dev_rate[cfg->dev_id].out_timestamp - - ofl->dev_rate[cfg->dev_id].in_timestamp; - return ret; } @@ -1970,11 +1955,83 @@ static int rkvpss_prepare_run(struct file *file, struct rkvpss_frame_cfg *cfg) struct rkvpss_offline_dev *ofl = video_drvdata(file); int ret = 0; bool unite; + int i, j, k; + s64 us = 0; + u64 ns; + ktime_t t = 0; + + ns = ktime_get_ns(); + ofl->dev_rate[cfg->dev_id].in_rate = ns - ofl->dev_rate[cfg->dev_id].in_timestamp; + ofl->dev_rate[cfg->dev_id].in_timestamp = ns; ret = rkvpss_check_params(file, cfg, &unite); if (ret < 0) goto end; + /******** show cfg info ********/ + if (rkvpss_debug >= 2) { + t = ktime_get(); + + v4l2_info(&ofl->v4l2_dev, + "%s dev_id:%d seq:%d mirror:%d input:%dx%d buffd:%d format:%c%c%c%c stride:%d rotate:%d\n", + __func__, cfg->dev_id, cfg->sequence, cfg->mirror, + cfg->input.width, cfg->input.height, cfg->input.buf_fd, + cfg->input.format, cfg->input.format >> 8, + cfg->input.format >> 16, cfg->input.format >> 24, + cfg->input.stride, cfg->input.rotate); + for (i = 0; i < RKVPSS_OUTPUT_MAX; i++) { + v4l2_info(&ofl->v4l2_dev, + "\t\t\tch%d enable:%d crop:(%d,%d)/%dx%d scl:%dx%d flip:%d buffd:%d format:%c%c%c%c stride:%d\n", + i, cfg->output[i].enable, + cfg->output[i].crop_h_offs, cfg->output[i].crop_v_offs, + cfg->output[i].crop_width, cfg->output[i].crop_height, + cfg->output[i].scl_width, cfg->output[i].scl_height, + cfg->output[i].flip, cfg->output[i].buf_fd, + cfg->output[i].format, cfg->output[i].format >> 8, + cfg->output[i].format >> 16, cfg->output[i].format >> 24, + cfg->output[i].stride); + if (rkvpss_debug < 4) + break; + if (!cfg->output[i].enable) + continue; + v4l2_info(&ofl->v4l2_dev, + "\t\t\tcmsc mosaic_block:%d width_ro:%d height_ro:%d\n", + cfg->output[i].cmsc.mosaic_block, + cfg->output[i].cmsc.width_ro, + cfg->output[i].cmsc.height_ro); + for (j = 0; j < RKVPSS_CMSC_WIN_MAX; j++) { + if (!cfg->output[i].cmsc.win[j].win_en) + continue; + v4l2_info(&ofl->v4l2_dev, + "\t\t\t\twin:%d win_en:%u mode:%u color_y:%u color_u:%u color_v:%u color_a:%u\n", + j, + cfg->output[i].cmsc.win[j].win_en, + cfg->output[i].cmsc.win[j].mode, + cfg->output[i].cmsc.win[j].cover_color_y, + cfg->output[i].cmsc.win[j].cover_color_u, + cfg->output[i].cmsc.win[j].cover_color_v, + cfg->output[i].cmsc.win[j].cover_color_a); + for (k = 0; k < RKVPSS_CMSC_POINT_MAX; k++) { + v4l2_info(&ofl->v4l2_dev, + "\t\t\t\t\tpoint:%d x:%d y:%d\n", + k, + cfg->output[i].cmsc.win[j].point[k].x, + cfg->output[i].cmsc.win[j].point[k].y); + } + } + v4l2_info(&ofl->v4l2_dev, + "\t\t\taspt_en:%d w:%d h:%d h_offs:%d v_offs:%d color_y:%d color_u:%d color_v:%d\n", + cfg->output[i].aspt.enable, + cfg->output[i].aspt.width, + cfg->output[i].aspt.height, + cfg->output[i].aspt.h_offs, + cfg->output[i].aspt.v_offs, + cfg->output[i].aspt.color_y, + cfg->output[i].aspt.color_u, + cfg->output[i].aspt.color_v); + } + } + if (!unite) { ret = rkvpss_ofl_run(file, cfg, false, false); if (ret < 0) @@ -1992,6 +2049,19 @@ static int rkvpss_prepare_run(struct file *file, struct rkvpss_frame_cfg *cfg) } } + if (rkvpss_debug >= 2) { + us = ktime_us_delta(ktime_get(), t); + v4l2_info(&ofl->v4l2_dev, + "%s end, time:%lldus\n", __func__, us); + } + + ns = ktime_get_ns(); + ofl->dev_rate[cfg->dev_id].out_rate = ns - ofl->dev_rate[cfg->dev_id].out_timestamp; + ofl->dev_rate[cfg->dev_id].out_timestamp = ns; + ofl->dev_rate[cfg->dev_id].sequence = cfg->sequence; + ofl->dev_rate[cfg->dev_id].delay = ofl->dev_rate[cfg->dev_id].out_timestamp - + ofl->dev_rate[cfg->dev_id].in_timestamp; + end: return ret; } @@ -1999,11 +2069,16 @@ end: static long rkvpss_ofl_ioctl(struct file *file, void *fh, bool valid_prio, unsigned int cmd, void *arg) { + struct rkvpss_offline_dev *ofl = video_drvdata(file); long ret = 0; bool unite; - if (!arg) - return -EINVAL; + ofl->pm_need_wait = true; + + if (!arg) { + ret = -EINVAL; + goto out; + } switch (cmd) { case RKVPSS_CMD_MODULE_SEL: @@ -2028,6 +2103,12 @@ static long rkvpss_ofl_ioctl(struct file *file, void *fh, ret = -EFAULT; } +out: + /* notify hw suspend */ + if (ofl->hw->is_suspend) + complete(&ofl->pm_cmpl); + + ofl->pm_need_wait = false; return ret; } @@ -2131,6 +2212,8 @@ int rkvpss_register_offline(struct rkvpss_hw_dev *hw) INIT_LIST_HEAD(&ofl->cfginfo_list); mutex_init(&ofl->ofl_lock); rkvpss_offline_proc_init(ofl); + ofl->pm_need_wait = false; + init_completion(&ofl->pm_cmpl); return 0; unreg_v4l2: mutex_destroy(&ofl->apilock); diff --git a/drivers/media/platform/rockchip/vpss/vpss_offline.h b/drivers/media/platform/rockchip/vpss/vpss_offline.h index 8632e3f18b18..78b7434d6a9c 100644 --- a/drivers/media/platform/rockchip/vpss/vpss_offline.h +++ b/drivers/media/platform/rockchip/vpss/vpss_offline.h @@ -73,8 +73,10 @@ struct rkvpss_offline_dev { struct mutex ofl_lock; struct rkvpss_dev_rate dev_rate[DEV_NUM_MAX]; struct rkvpss_unite_scl_params unite_params[RKVPSS_OUTPUT_MAX]; + struct completion pm_cmpl; u32 unite_right_enlarge; bool mode_sel_en; + bool pm_need_wait; }; int rkvpss_register_offline(struct rkvpss_hw_dev *hw); diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index fedd5cf51802..c01dfedd7dd4 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -26,6 +26,7 @@ #include "pcie-designware.h" #include "../rockchip-pcie-dma.h" #include "pcie-dw-dmatest.h" +#include "../../hotplug/gpiophp.h" #define RK_PCIE_DBG 0 @@ -131,6 +132,9 @@ struct rk_pcie { bool is_signal_test; bool bifurcation; bool supports_clkreq; + bool slot_pluggable; + struct gpio_hotplug_slot hp_slot; + bool hp_no_link; struct regulator *vpcie3v3; struct irq_domain *irq_domain; raw_spinlock_t intx_lock; @@ -280,7 +284,7 @@ static int rk_pcie_establish_link(struct dw_pcie *pci) * we still need to reset link as we need to remove all resource info * from devices, for instance BAR, as it wasn't assigned by kernel. */ - if (dw_pcie_link_up(pci)) { + if (dw_pcie_link_up(pci) && !rk_pcie->hp_no_link) { dev_err(pci->dev, "link is already up\n"); return 0; } @@ -346,6 +350,8 @@ static int rk_pcie_establish_link(struct dw_pcie *pci) dev_info(pci->dev, "PCIe Link up, LTSSM is 0x%x\n", rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_LTSSM_STATUS)); rk_pcie_debug_dump(rk_pcie); + if (rk_pcie->slot_pluggable) + rk_pcie->hp_no_link = false; return 0; } } @@ -372,7 +378,12 @@ static int rk_pcie_establish_link(struct dw_pcie *pci) } } - return rk_pcie->is_signal_test == true ? 0 : -EINVAL; + if (rk_pcie->slot_pluggable) { + rk_pcie->hp_no_link = true; + return 0; + } else { + return rk_pcie->is_signal_test == true ? 0 : -EINVAL; + } } static bool rk_pcie_udma_enabled(struct rk_pcie *rk_pcie) @@ -1070,6 +1081,40 @@ remove: return -ENOMEM; } +static int rk_pcie_slot_enable(struct gpio_hotplug_slot *slot) +{ + struct rk_pcie *rk_pcie = container_of(slot, struct rk_pcie, hp_slot); + int ret; + + dev_info(rk_pcie->pci->dev, "%s\n", __func__); + rk_pcie->hp_no_link = true; + rk_pcie_enable_power(rk_pcie); + rk_pcie_fast_link_setup(rk_pcie); + ret = rk_pcie_establish_link(rk_pcie->pci); + if (ret) + dev_err(rk_pcie->pci->dev, "fail to enable slot\n"); + + return ret; +} + +static int rk_pcie_slot_disable(struct gpio_hotplug_slot *slot) +{ + struct rk_pcie *rk_pcie = container_of(slot, struct rk_pcie, hp_slot); + + dev_info(rk_pcie->pci->dev, "%s\n", __func__); + rk_pcie->hp_no_link = true; + rk_pcie_disable_ltssm(rk_pcie); + gpiod_set_value_cansleep(rk_pcie->rst_gpio, 0); + rk_pcie_disable_power(rk_pcie); + + return 0; +} + +static const struct gpio_hotplug_slot_plat_ops rk_pcie_gpio_hp_plat_ops = { + .enable = rk_pcie_slot_enable, + .disable = rk_pcie_slot_disable, +}; + static int rk_pcie_really_probe(void *p) { struct platform_device *pdev = p; @@ -1128,6 +1173,12 @@ static int rk_pcie_really_probe(void *p) rk_pcie->supports_clkreq = device_property_read_bool(dev, "supports-clkreq"); + if (device_property_read_bool(dev, "hotplug-gpios") || + device_property_read_bool(dev, "hotplug-gpio")) { + rk_pcie->slot_pluggable = true; + dev_info(dev, "support hotplug-gpios!\n"); + } + retry_regulator: /* DON'T MOVE ME: must be enable before phy init */ rk_pcie->vpcie3v3 = devm_regulator_get_optional(dev, "vpcie3v3"); @@ -1257,9 +1308,23 @@ retry_regulator: if (rk_pcie->is_signal_test == true) return 0; - if (ret) + if (ret && !rk_pcie->slot_pluggable) goto remove_rst_wq; + if (rk_pcie->slot_pluggable) { + rk_pcie->hp_slot.plat_ops = &rk_pcie_gpio_hp_plat_ops; + rk_pcie->hp_slot.np = rk_pcie->pci->dev->of_node; + rk_pcie->hp_slot.slot_nr = rk_pcie->pci->pp.bridge->busnr; + rk_pcie->hp_slot.pdev = pci_get_slot(rk_pcie->pci->pp.bridge->bus, PCI_DEVFN(0, 0)); + + ret = register_gpio_hotplug_slot(&rk_pcie->hp_slot); + if (ret < 0) + dev_warn(dev, "Failed to register ops for GPIO Hot-Plug controller: %d\n", + ret); + /* Set debounce to 200ms for safe if possible */ + gpiod_set_debounce(rk_pcie->hp_slot.gpiod, 200); + } + ret = rk_pcie_init_dma_trx(rk_pcie); if (ret) { dev_err(dev, "failed to add dma extension\n");