diff --git a/arch/arm/boot/dts/rk3506.dtsi b/arch/arm/boot/dts/rk3506.dtsi index 3f7562e65160..d32533dfdb3d 100644 --- a/arch/arm/boot/dts/rk3506.dtsi +++ b/arch/arm/boot/dts/rk3506.dtsi @@ -79,6 +79,9 @@ resets = <&cru SRST_A_MAC0>; reset-names = "stmmaceth"; + assigned-clocks = <&cru CLK_MAC0_PTP>; + assigned-clock-rates = <62500000>; + snps,mixed-burst; snps,tso; @@ -130,6 +133,9 @@ resets = <&cru SRST_A_MAC1>; reset-names = "stmmaceth"; + assigned-clocks = <&cru CLK_MAC1_PTP>; + assigned-clock-rates = <62500000>; + snps,mixed-burst; snps,tso; diff --git a/arch/arm/boot/dts/rk3506g-iotest-pwm-test.dtsi b/arch/arm/boot/dts/rk3506g-iotest-pwm-test.dtsi index 056729b46233..0434275de148 100644 --- a/arch/arm/boot/dts/rk3506g-iotest-pwm-test.dtsi +++ b/arch/arm/boot/dts/rk3506g-iotest-pwm-test.dtsi @@ -3,6 +3,7 @@ * Copyright (c) 2024 Rockchip Electronics Co., Ltd. */ +#ifndef IR_TRANSMIT_TEST / { pwm_rockchip_test: pwm-rockchip-test { compatible = "pwm-rockchip-test"; @@ -32,6 +33,7 @@ "pwm1_7"; }; }; +#endif /* use GPIO0_B0 ~ GPIO0_C3(rm_io8 ~ rm_io19) by default */ &pwm0_4ch_0 { @@ -159,3 +161,37 @@ assigned-clock-rates = <100000000>; }; #endif + +#ifdef IR_TRANSMIT_TEST +&pwm1_8ch_0 { + rockchip,pwm-ir-transmit; +}; + +&pwm1_8ch_1 { + rockchip,pwm-ir-transmit; +}; + +&pwm1_8ch_2 { + rockchip,pwm-ir-transmit; +}; + +&pwm1_8ch_3 { + rockchip,pwm-ir-transmit; +}; + +&pwm1_8ch_4 { + rockchip,pwm-ir-transmit; +}; + +&pwm1_8ch_5 { + rockchip,pwm-ir-transmit; +}; + +&pwm1_8ch_6 { + rockchip,pwm-ir-transmit; +}; + +&pwm1_8ch_7 { + rockchip,pwm-ir-transmit; +}; +#endif diff --git a/drivers/firmware/rockchip_sip.c b/drivers/firmware/rockchip_sip.c index 593e2f693464..bf214bcea209 100644 --- a/drivers/firmware/rockchip_sip.c +++ b/drivers/firmware/rockchip_sip.c @@ -366,13 +366,17 @@ EXPORT_SYMBOL_GPL(sip_hdcp_config); */ #ifdef CONFIG_ARM64 #define SIP_UARTDBG_FN SIP_UARTDBG_CFG64 +#define SIP_FIQ_DBG_STACK_SIZE IRQ_STACK_SIZE #else #define SIP_UARTDBG_FN SIP_UARTDBG_CFG +#define SIP_FIQ_DBG_STACK_SIZE SZ_8K + static int firmware_64_32bit; #endif static int fiq_sip_enabled; static int fiq_target_cpu; +static unsigned long fiq_stack_top; static phys_addr_t ft_fiq_mem_phy; static void __iomem *ft_fiq_mem_base; static sip_fiq_debugger_uart_irq_tf_cb_t sip_fiq_debugger_uart_irq_tf; @@ -481,13 +485,26 @@ int sip_fiq_debugger_uart_irq_tf_init(u32 irq_id, sip_fiq_debugger_uart_irq_tf_c { struct arm_smccc_res res; - fiq_target_cpu = 0; + /* Alloc a page for fiq_debugger's stack */ + if (fiq_stack_top == 0) { + fiq_stack_top = __get_free_pages(GFP_KERNEL | __GFP_ZERO, + get_order(SIP_FIQ_DBG_STACK_SIZE)); + if (fiq_stack_top) { + fiq_stack_top += SIP_FIQ_DBG_STACK_SIZE; + } else { + pr_err("%s: alloc stack failed\n", __func__); + return -ENOMEM; + } + } /* init fiq debugger callback */ sip_fiq_debugger_uart_irq_tf = callback_fn; - res = __invoke_sip_fn_smc(SIP_UARTDBG_FN, irq_id, - (unsigned long)sip_fiq_debugger_uart_irq_tf_cb, - UARTDBG_CFG_INIT); + arm_smccc_smc(SIP_UARTDBG_FN, + irq_id, + (unsigned long)sip_fiq_debugger_uart_irq_tf_cb, + UARTDBG_CFG_INIT, + fiq_stack_top, 0, 0, 0, &res); + if (IS_SIP_ERROR(res.a0)) { pr_err("%s error: %d\n", __func__, (int)res.a0); return res.a0; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 4b64d8854afc..2ea810647d04 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -5267,6 +5267,7 @@ static void vop2_crtc_atomic_disable(struct drm_crtc *crtc, vop2->active_display_mask &= ~BIT(vp->id); vcstate->splice_mode = false; vcstate->output_flags = 0; + vcstate->output_type = 0; vp->splice_mode_right = false; vp->loader_protect = false; splice_vp->splice_mode_right = false; diff --git a/drivers/media/i2c/imx415.c b/drivers/media/i2c/imx415.c index d2636434b8ab..027f9181aebd 100644 --- a/drivers/media/i2c/imx415.c +++ b/drivers/media/i2c/imx415.c @@ -247,6 +247,11 @@ struct imx415 { struct cam_sw_info *cam_sw_inf; int rhs1_old; int rhs2_old; + u32 cur_exposure[3]; + u32 cur_gain[3]; + u32 pclk; + u32 tline; + bool is_tline_init; }; static struct rkmodule_csi_dphy_param dcphy_param = { @@ -1626,6 +1631,123 @@ static void imx415_get_module_inf(struct imx415 *imx415, strlcpy(inf->base.lens, imx415->len_name, sizeof(inf->base.lens)); } +static void imx415_get_pclk_and_tline(struct imx415 *imx415) +{ + const struct imx415_mode *mode = imx415->cur_mode; + + imx415->pclk = (u32)div_u64((u64)mode->hts_def * mode->vts_def * + mode->max_fps.denominator, mode->max_fps.numerator); + imx415->tline = (u32)div_u64((u64)mode->hts_def * 1000000000, imx415->pclk); +} + +static void imx415_hdr_exposure_readback(struct imx415 *imx415) +{ + u32 shr, shr_l, shr_m, shr_h; + u32 rhs, rhs_l, rhs_m, rhs_h; + u32 gain, gain_l, gain_h; + int ret = 0; + + if (!imx415->is_tline_init) { + imx415_get_pclk_and_tline(imx415); + imx415->is_tline_init = true; + } + + ret = imx415_read_reg(imx415->client, IMX415_LF_EXPO_REG_L, + IMX415_REG_VALUE_08BIT, &shr_l); + ret |= imx415_read_reg(imx415->client, IMX415_LF_EXPO_REG_M, + IMX415_REG_VALUE_08BIT, &shr_m); + ret |= imx415_read_reg(imx415->client, IMX415_LF_EXPO_REG_H, + IMX415_REG_VALUE_08BIT, &shr_h); + if (!ret) { + shr = (shr_h << 16) | (shr_m << 8) | shr_l; + imx415->cur_exposure[0] = (imx415->cur_vts - shr) * imx415->tline; + } else { + dev_err(&imx415->client->dev, + "imx415 get exposure of long frame failed!\n"); + } + ret = imx415_read_reg(imx415->client, IMX415_LF_GAIN_REG_H, + IMX415_REG_VALUE_08BIT, &gain_h); + ret |= imx415_read_reg(imx415->client, IMX415_LF_GAIN_REG_L, + IMX415_REG_VALUE_08BIT, &gain_l); + if (!ret) { + gain = (gain_h << 8) | gain_l; + imx415->cur_gain[0] = gain * 300;//step=0.3db,factor=1000 + } else { + dev_err(&imx415->client->dev, + "imx415 get gain of long frame failed!\n"); + } + + ret = imx415_read_reg(imx415->client, IMX415_SF1_EXPO_REG_L, + IMX415_REG_VALUE_08BIT, &shr_l); + ret |= imx415_read_reg(imx415->client, IMX415_SF1_EXPO_REG_M, + IMX415_REG_VALUE_08BIT, &shr_m); + ret |= imx415_read_reg(imx415->client, IMX415_SF1_EXPO_REG_H, + IMX415_REG_VALUE_08BIT, &shr_h); + ret |= imx415_read_reg(imx415->client, IMX415_RHS1_REG_L, + IMX415_REG_VALUE_08BIT, &rhs_l); + ret |= imx415_read_reg(imx415->client, IMX415_RHS1_REG_M, + IMX415_REG_VALUE_08BIT, &rhs_m); + ret |= imx415_read_reg(imx415->client, IMX415_RHS1_REG_H, + IMX415_REG_VALUE_08BIT, &rhs_h); + if (!ret) { + shr = (shr_h << 16) | (shr_m << 8) | shr_l; + rhs = (rhs_h << 16) | (rhs_m << 8) | rhs_l; + imx415->cur_exposure[1] = (rhs - shr) * imx415->tline; + } else { + dev_err(&imx415->client->dev, + "imx415 get exposure of %s frame failed!\n", + imx415->cur_mode->hdr_mode == HDR_X2 ? + "short" : "middle"); + } + ret = imx415_read_reg(imx415->client, IMX415_SF1_GAIN_REG_H, + IMX415_REG_VALUE_08BIT, &gain_h); + ret |= imx415_read_reg(imx415->client, IMX415_SF1_GAIN_REG_L, + IMX415_REG_VALUE_08BIT, &gain_l); + if (!ret) { + gain = (gain_h << 8) | gain_l; + imx415->cur_gain[1] = gain * 300;//step=0.3db,factor=1000 + } else { + dev_err(&imx415->client->dev, + "imx415 get gain of %s frame failed!\n", + imx415->cur_mode->hdr_mode == HDR_X2 ? + "short" : "middle"); + } + + if (imx415->cur_mode->hdr_mode == HDR_X3) { + ret = imx415_read_reg(imx415->client, IMX415_SF2_EXPO_REG_L, + IMX415_REG_VALUE_08BIT, &shr_l); + ret |= imx415_read_reg(imx415->client, IMX415_SF2_EXPO_REG_M, + IMX415_REG_VALUE_08BIT, &shr_m); + ret |= imx415_read_reg(imx415->client, IMX415_SF2_EXPO_REG_H, + IMX415_REG_VALUE_08BIT, &shr_h); + ret |= imx415_read_reg(imx415->client, IMX415_RHS2_REG_L, + IMX415_REG_VALUE_08BIT, &rhs_l); + ret |= imx415_read_reg(imx415->client, IMX415_RHS2_REG_M, + IMX415_REG_VALUE_08BIT, &rhs_m); + ret |= imx415_read_reg(imx415->client, IMX415_RHS2_REG_H, + IMX415_REG_VALUE_08BIT, &rhs_h); + if (!ret) { + shr = (shr_h << 16) | (shr_m << 8) | shr_l; + rhs = (rhs_h << 16) | (rhs_m << 8) | rhs_l; + imx415->cur_exposure[2] = (rhs - shr) * imx415->tline; + } else { + dev_err(&imx415->client->dev, + "imx415 get exposure of short frame failed!\n"); + } + ret = imx415_read_reg(imx415->client, IMX415_SF2_GAIN_REG_H, + IMX415_REG_VALUE_08BIT, &gain_h); + ret |= imx415_read_reg(imx415->client, IMX415_SF2_GAIN_REG_L, + IMX415_REG_VALUE_08BIT, &gain_l); + if (!ret) { + gain = (gain_h << 8) | gain_l; + imx415->cur_gain[2] = gain * 300;//step=0.3db,factor=1000 + } else { + dev_err(&imx415->client->dev, + "imx415 get gain of short frame failed!\n"); + } + } +} + static int imx415_set_hdrae_3frame(struct imx415 *imx415, struct preisp_hdrae_exp_s *ae) { @@ -1877,6 +1999,7 @@ static int imx415_set_hdrae_3frame(struct imx415 *imx415, ret |= imx415_write_reg(client, IMX415_GROUP_HOLD_REG, IMX415_REG_VALUE_08BIT, IMX415_GROUP_HOLD_END); + imx415_hdr_exposure_readback(imx415); return ret; } @@ -2035,6 +2158,7 @@ static int imx415_set_hdrae(struct imx415 *imx415, ret |= imx415_write_reg(client, IMX415_GROUP_HOLD_REG, IMX415_REG_VALUE_08BIT, IMX415_GROUP_HOLD_END); + imx415_hdr_exposure_readback(imx415); return ret; } @@ -2060,6 +2184,9 @@ static long imx415_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) u64 pixel_rate = 0; struct rkmodule_csi_dphy_param *dphy_param; u8 lanes = imx415->bus_cfg.bus.mipi_csi2.num_data_lanes; + struct rkmodule_exp_delay *exp_delay; + struct rkmodule_exp_info *exp_info; + int idx_max = 0; switch (cmd) { case PREISP_CMD_SET_HDRAE_EXP: @@ -2152,6 +2279,30 @@ static long imx415_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) } else ret = -EINVAL; break; + case RKMODULE_GET_EXP_DELAY: + exp_delay = (struct rkmodule_exp_delay *)arg; + exp_delay->exp_delay = 2; + exp_delay->gain_delay = 2; + exp_delay->vts_delay = 1; + break; + case RKMODULE_GET_EXP_INFO: + exp_info = (struct rkmodule_exp_info *)arg; + if (imx415->cur_mode->hdr_mode == NO_HDR) + idx_max = 1; + else if (imx415->cur_mode->hdr_mode == HDR_X2) + idx_max = 2; + else + idx_max = 3; + for (i = 0; i < idx_max; i++) { + exp_info->exp[i] = imx415->cur_exposure[i]; + exp_info->gain[i] = imx415->cur_gain[i]; + } + exp_info->hts = imx415->cur_mode->hts_def; + exp_info->vts = imx415->cur_vts; + exp_info->pclk = imx415->pclk; + exp_info->gain_mode.gain_mode = RKMODULE_GAIN_MODE_DB; + exp_info->gain_mode.factor = 1000; + break; default: ret = -ENOIOCTLCMD; break; @@ -2174,6 +2325,8 @@ static long imx415_compat_ioctl32(struct v4l2_subdev *sd, u32 stream; u32 brl = 0; struct rkmodule_csi_dphy_param *dphy_param; + struct rkmodule_exp_delay *exp_delay; + struct rkmodule_exp_info *exp_info; switch (cmd) { case RKMODULE_GET_MODULE_INFO: @@ -2292,7 +2445,36 @@ static long imx415_compat_ioctl32(struct v4l2_subdev *sd, } kfree(dphy_param); break; + case RKMODULE_GET_EXP_DELAY: + exp_delay = kzalloc(sizeof(*exp_delay), GFP_KERNEL); + if (!exp_delay) { + ret = -ENOMEM; + return ret; + } + ret = imx415_ioctl(sd, cmd, exp_delay); + if (!ret) { + ret = copy_to_user(up, exp_delay, sizeof(*exp_delay)); + if (ret) + ret = -EFAULT; + } + kfree(exp_delay); + break; + case RKMODULE_GET_EXP_INFO: + exp_info = kzalloc(sizeof(*exp_info), GFP_KERNEL); + if (!exp_info) { + ret = -ENOMEM; + return ret; + } + + ret = imx415_ioctl(sd, cmd, exp_info); + if (!ret) { + ret = copy_to_user(up, exp_info, sizeof(*exp_info)); + if (ret) + ret = -EFAULT; + } + kfree(exp_info); + break; default: ret = -ENOIOCTLCMD; break; @@ -2302,7 +2484,6 @@ static long imx415_compat_ioctl32(struct v4l2_subdev *sd, } #endif - static int __imx415_start_stream(struct imx415 *imx415) { int ret; @@ -2315,6 +2496,7 @@ static int __imx415_start_stream(struct imx415 *imx415) if (ret) return ret; } + imx415_get_pclk_and_tline(imx415); /* In case these controls are set before streaming */ ret = __v4l2_ctrl_handler_setup(&imx415->ctrl_handler); @@ -2340,6 +2522,7 @@ static int __imx415_stop_stream(struct imx415 *imx415) imx415->has_init_exp = false; if (imx415->is_thunderboot) imx415->is_first_streamoff = true; + imx415->is_tline_init = false; return imx415_write_reg(imx415->client, IMX415_REG_CTRL_MODE, IMX415_REG_VALUE_08BIT, 1); } @@ -2697,6 +2880,48 @@ static const struct v4l2_subdev_ops imx415_subdev_ops = { .pad = &imx415_pad_ops, }; +static void imx415_exposure_readback(struct imx415 *imx415) +{ + u32 shr, shr_l, shr_m, shr_h; + int ret = 0; + + if (!imx415->is_tline_init) { + imx415_get_pclk_and_tline(imx415); + imx415->is_tline_init = true; + } + + ret = imx415_read_reg(imx415->client, IMX415_LF_EXPO_REG_L, + IMX415_REG_VALUE_08BIT, &shr_l); + ret |= imx415_read_reg(imx415->client, IMX415_LF_EXPO_REG_M, + IMX415_REG_VALUE_08BIT, &shr_m); + ret |= imx415_read_reg(imx415->client, IMX415_LF_EXPO_REG_H, + IMX415_REG_VALUE_08BIT, &shr_h); + if (!ret) { + shr = (shr_h << 16) | (shr_m << 8) | shr_l; + imx415->cur_exposure[0] = (imx415->cur_vts - shr) * imx415->tline; + } +} + +static void imx415_gain_readback(struct imx415 *imx415) +{ + int ret = 0; + u32 gain, gain_l, gain_h; + + if (!imx415->is_tline_init) { + imx415_get_pclk_and_tline(imx415); + imx415->is_tline_init = true; + } + + ret = imx415_read_reg(imx415->client, IMX415_LF_GAIN_REG_H, + IMX415_REG_VALUE_08BIT, + &gain_h); + ret |= imx415_read_reg(imx415->client, IMX415_LF_GAIN_REG_L, + IMX415_REG_VALUE_08BIT, + &gain_l); + gain = (gain_h << 8) | gain_l; + imx415->cur_gain[0] = gain * 300;//step=0.3db,factor=1000 +} + static int imx415_set_ctrl(struct v4l2_ctrl *ctrl) { struct imx415 *imx415 = container_of(ctrl->handler, @@ -2738,6 +2963,7 @@ static int imx415_set_ctrl(struct v4l2_ctrl *ctrl) ret |= imx415_write_reg(imx415->client, IMX415_LF_EXPO_REG_H, IMX415_REG_VALUE_08BIT, IMX415_FETCH_EXP_H(shr0)); + imx415_exposure_readback(imx415); dev_dbg(&client->dev, "set exposure(shr0) %d = cur_vts(%d) - val(%d)\n", shr0, imx415->cur_vts, ctrl->val); break; @@ -2750,6 +2976,7 @@ static int imx415_set_ctrl(struct v4l2_ctrl *ctrl) ret |= imx415_write_reg(imx415->client, IMX415_LF_GAIN_REG_L, IMX415_REG_VALUE_08BIT, IMX415_FETCH_GAIN_L(ctrl->val)); + imx415_gain_readback(imx415); dev_dbg(&client->dev, "set analog gain 0x%x\n", ctrl->val); break; @@ -2871,12 +3098,10 @@ static int imx415_initialize_controls(struct imx415 *imx415) V4L2_CID_EXPOSURE, IMX415_EXPOSURE_MIN, exposure_max, IMX415_EXPOSURE_STEP, mode->exp_def); - imx415->anal_a_gain = v4l2_ctrl_new_std(handler, &imx415_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, IMX415_GAIN_MIN, IMX415_GAIN_MAX, IMX415_GAIN_STEP, IMX415_GAIN_DEFAULT); - v4l2_ctrl_new_std(handler, &imx415_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0); v4l2_ctrl_new_std(handler, &imx415_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0); @@ -2889,6 +3114,7 @@ static int imx415_initialize_controls(struct imx415 *imx415) imx415->subdev.ctrl_handler = handler; imx415->has_init_exp = false; + imx415->is_tline_init = false; return 0; diff --git a/drivers/media/platform/rockchip/isp/isp_external.h b/drivers/media/platform/rockchip/isp/isp_external.h index 480329bb2c9c..e44b27fe7bb4 100644 --- a/drivers/media/platform/rockchip/isp/isp_external.h +++ b/drivers/media/platform/rockchip/isp/isp_external.h @@ -27,6 +27,9 @@ #define RKISP_VICAP_CMD_HW_LINK \ _IOW('V', BASE_VIDIOC_PRIVATE + 6, int) +#define RKISP_VICAP_CMD_SOF \ + _IOW('V', BASE_VIDIOC_PRIVATE + 7, struct rkisp_vicap_sof) + #define RKISP_VICAP_BUF_CNT 3 #define RKISP_VICAP_BUF_CNT_MAX 8 #define RKISP_RX_BUF_POOL_MAX (RKISP_VICAP_BUF_CNT_MAX * 3) @@ -90,4 +93,19 @@ struct rkisp_rx_buf { bool is_uncompact; }; +struct rkisp_vicap_sof { + u64 timestamp; + u32 sequence; + u32 exp[3]; + u32 gain[3]; + u32 hts; + u32 vts; + u32 pclk; + __u32 dcg_used; + __u32 dcg_val[3]; + struct rkmodule_dcg_ratio dcg_ratio; + struct rkmodule_gain_mode gain_mode; + bool is_exp_active; +}; + #endif diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index e5c77c2027c0..b5d1cfd2e3de 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -4238,8 +4238,19 @@ static int rockchip_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, { struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); struct rockchip_pin_bank *bank; + struct pin_desc *desc; + int mux, pin = offset % 32; + static unsigned long bitmap[BITS_TO_LONGS(2048)]; bank = pin_to_bank(info, offset); + mux = rockchip_get_mux(bank, pin); + desc = pin_desc_get(pctldev, offset); + if (offset < 2048 && !test_bit(offset, bitmap) && desc->mux_owner && mux) { + set_bit(offset, bitmap); + WARN(1, "pin %u already requested by %s; switch mux %d to GPIO\n", + offset, desc->mux_owner, mux); + } + return rockchip_set_mux(bank, offset - bank->pin_base, RK_FUNC_GPIO); } diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c index 246eb3bfa8b3..56c419d0c344 100644 --- a/drivers/pwm/pwm-rockchip.c +++ b/drivers/pwm/pwm-rockchip.c @@ -20,10 +20,13 @@ #include #include #include +#include #include "pwm-rockchip-irq-callbacks.h" #define PWM_MAX_CHANNEL_NUM 8 +#define PWM_IR_TRANSMIT_BUFFER_SIZE 7 + /* * regs for pwm v1-v3 */ @@ -101,6 +104,9 @@ #define CLK_PRESCALE(v) HIWORD_UPDATE(v, 0, 2) #define CLK_SCALE(v) HIWORD_UPDATE(v, 4, 12) #define CLK_SRC_SEL(v) HIWORD_UPDATE(v, 13, 14) +#define SRC_CLK_PWM 0 +#define SRC_CLK_PWM_OSC 1 +#define SRC_CLK_PWM_RC 2 #define CLK_GLOBAL_SEL(v) HIWORD_UPDATE(v, 15, 15) /* CTRL */ #define CTRL_V4 0xc @@ -220,6 +226,46 @@ #define GLOBAL_CTRL 0xc4 #define GLOBAL_PWM_EN(v) HIWORD_UPDATE(v, 0, 0) #define GLOBAL_PWM_UPDATE_EN(v) HIWORD_UPDATE(v, 1, 1) +/* IR_TRANS_ARBITER */ +#define IR_TRANS_ARBITER 0x180 +#define IR_TRANS_GRANT_SHIFT 0 +#define IR_TRANS_READ_LOCK_SHIFT 16 +/* IR_TRANS_CTRL0 */ +#define IR_TRANS_CTRL0 0x184 +#define IR_TRANS_OUT_ENABLE(v) HIWORD_UPDATE(v, 0, 0) +#define IR_TRANS_DUTY_POL(v) HIWORD_UPDATE(v, 1, 1) +#define IR_TRANS_INACTIVE_POL(v) HIWORD_UPDATE(v, 2, 2) +#define IR_TRANS_MODE(v) HIWORD_UPDATE(v, 3, 3) +#define IR_TRANS_FORMAT(v) HIWORD_UPDATE(v, 4, 7) +#define NEC_WITH_SIMPLE_REPEAT_CODE 0 +#define NEC_WITH_FULL_REPEAT_CODE 1 +#define TC9012 2 +#define SONY 3 +/* IR_TRANS_CTRL1 */ +#define IR_TRANS_CTRL1 0x188 +#define IR_TRANS_RPT(v) HIWORD_UPDATE(v, 0, 15) +/* IR_TRANS_PRE */ +#define IR_TRANS_PRE 0x18c +#define IR_TRANS_OUT_LOW_PRELOAD_SHIFT 0 +#define IR_TRANS_OUT_HIGH_PRELOAD_SHIFT 16 +/* IR_TRANS_SPRE */ +#define IR_TRANS_SPRE 0x190 +#define IR_TRANS_OUT_HIGH_SIMPLE_PRELOAD_SHIFT 0 +/* IR_TRANS_LD */ +#define IR_TRANS_LD 0x194 +#define IR_TRANS_OUT_DATA_LOW_PERIOD_SHIFT 0 +/* IR_TRANS_HD */ +#define IR_TRANS_HD 0x198 +#define IR_TRANS_OUT_HIGH_PERIOD_FOR_ZERO_SHIFT 0 +#define IR_TRANS_OUT_HIGH_PERIOD_FOR_ONE_SHIFT 16 +/* IR_TRANS_BURST_FRAME */ +#define IR_TRANS_BURST_FRAME 0x19c +#define IR_TRANS_OUT_FRAME_PERIOD_SHIFT 0 +#define IR_TRANS_OUT_FRAME_PERIOD_MASK (0x3ffff << IR_TRANS_OUT_FRAME_PERIOD_SHIFT) +#define IR_TRANS_OUT_BURST_PERIOD_SHIFT 20 +/* IR_TRANS_DATA_VALUE */ +#define IR_TRANS_DATA_VALUE 0x1a0 +#define IR_TRANS_OUT_VALUE_SHIFT 0 /* FREQ_ARBITER */ #define FREQ_ARBITER 0x1c0 #define FREQ_GRANT_SHIFT 0 @@ -264,6 +310,7 @@ struct rockchip_pwm_chip { const struct rockchip_pwm_biphasic_config *biphasic_config; struct resource *res; struct dentry *debugfs; + struct completion ir_trans_completion; void __iomem *base; unsigned long clk_rate; unsigned long is_clk_enabled; @@ -273,6 +320,7 @@ struct rockchip_pwm_chip { bool capture_en; bool wave_en; bool global_ctrl_grant; + bool ir_trans_support; bool freq_meter_support; bool counter_support; bool wave_support; @@ -322,6 +370,7 @@ struct rockchip_pwm_funcs { struct rockchip_pwm_biphasic_config *config); int (*get_biphasic_result)(struct pwm_chip *chip, struct pwm_device *pwm, unsigned long *biphasic_res); + int (*ir_transmit)(struct pwm_chip *chip, unsigned int *txbuf, unsigned int count); irqreturn_t (*irq_handler)(int irq, void *data); }; @@ -713,6 +762,13 @@ static irqreturn_t rockchip_pwm_irq_v4(int irq, void *data) ret = IRQ_HANDLED; } + if (val & IR_TRANS_END_INT) { + writel_relaxed(IR_TRANS_END_INT, pc->base + INTSTS); + complete(&pc->ir_trans_completion); + + ret = IRQ_HANDLED; + } + return ret; } @@ -1844,6 +1900,143 @@ int rockchip_pwm_get_biphasic_result(struct pwm_device *pwm, unsigned long *biph } EXPORT_SYMBOL_GPL(rockchip_pwm_get_biphasic_result); +#ifdef CONFIG_RC_CORE +static int rockchip_pwm_ir_transmit_v4(struct pwm_chip *chip, unsigned int *txbuf, + unsigned int count) +{ + struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip); + u32 arbiter; + u32 preload, spreload; + u32 low_period, high_period; + u32 tx_value; + u32 timeout_ms; + u32 val; + int ret = 0; + + if (count != PWM_IR_TRANSMIT_BUFFER_SIZE) { + dev_err(chip->dev, "Unsupported ir transmit buf size: %d\n", count); + return -EINVAL; + } + + ret = clk_enable(pc->clk); + if (ret) + return ret; + + arbiter = BIT(pc->channel_id) << IR_TRANS_READ_LOCK_SHIFT | + BIT(pc->channel_id) << IR_TRANS_GRANT_SHIFT; + writel_relaxed(arbiter, pc->base + IR_TRANS_ARBITER); + val = readl_relaxed(pc->base + IR_TRANS_ARBITER); + if (!(val & arbiter)) { + dev_err(chip->dev, "Failed to abtain ir transmit arbitration for PWM%d\n", + pc->channel_id); + ret = -EINVAL; + goto err_clk; + } + + reinit_completion(&pc->ir_trans_completion); + + /* + * Each value in the txbuf[] is in microseconds(us). + * txbuf[0]: the low duration of NEC leader code. + * txbuf[1]: the high duration of NEC leader code. + * txbuf[2]: the high duration of NEC repeat code. + * txbuf[3]: the low duration of NEC logic '0' and '1'. + * txbuf[4]: the high duration of NEC logic '0'. + * txbuf[5]: the high duration of NEC logic '1'. + * txbuf[6]: + * bit[31:24] bit[23:16] bit[15:8] bit[7:0] + * address code address inverted code command code command inverted code + */ + preload = txbuf[0] << IR_TRANS_OUT_LOW_PRELOAD_SHIFT | + txbuf[1] << IR_TRANS_OUT_HIGH_PRELOAD_SHIFT; + spreload = txbuf[2] << IR_TRANS_OUT_HIGH_SIMPLE_PRELOAD_SHIFT; + low_period = txbuf[3] << IR_TRANS_OUT_DATA_LOW_PERIOD_SHIFT; + high_period = txbuf[4] << IR_TRANS_OUT_HIGH_PERIOD_FOR_ZERO_SHIFT | + txbuf[5] << IR_TRANS_OUT_HIGH_PERIOD_FOR_ONE_SHIFT; + tx_value = txbuf[6] << IR_TRANS_OUT_VALUE_SHIFT; + + /* Set the dclk to 1M */ + writel_relaxed(CLK_SCALE(0x32), pc->base + CLK_CTRL); + writel_relaxed(PWM_CLK_EN(true), pc->base + ENABLE); + writel_relaxed(IR_TRANS_END_INT_EN(true), pc->base + INT_EN); + + writel_relaxed(preload, pc->base + IR_TRANS_PRE); + writel_relaxed(spreload, pc->base + IR_TRANS_SPRE); + writel_relaxed(low_period, pc->base + IR_TRANS_LD); + writel_relaxed(high_period, pc->base + IR_TRANS_HD); + writel_relaxed(tx_value, pc->base + IR_TRANS_DATA_VALUE); + + val = readl_relaxed(pc->base + IR_TRANS_BURST_FRAME); + timeout_ms = ((val & IR_TRANS_OUT_FRAME_PERIOD_MASK) >> + IR_TRANS_OUT_FRAME_PERIOD_SHIFT) / 1000; + + writel_relaxed(IR_TRANS_INACTIVE_POL(true) | IR_TRANS_OUT_ENABLE(true), + pc->base + IR_TRANS_CTRL0); + + ret = wait_for_completion_timeout(&pc->ir_trans_completion, + msecs_to_jiffies(timeout_ms * 3 / 2)); + if (!ret) { + dev_err(chip->dev, "Failed to wait for PWM%d ir transmit to complete\n", + pc->channel_id); + ret = -ETIMEDOUT; + } + + writel_relaxed(IR_TRANS_OUT_ENABLE(false), pc->base + IR_TRANS_CTRL0); + writel_relaxed(IR_TRANS_END_INT_EN(false), pc->base + INT_EN); + writel_relaxed(PWM_CLK_EN(false), pc->base + ENABLE); + writel_relaxed(0, pc->base + IR_TRANS_ARBITER); + +err_clk: + clk_disable(pc->clk); + + return ret ? ret : count; +} + +static int rockchip_pwm_ir_transmit(struct rc_dev *dev, unsigned int *txbuf, unsigned int count) +{ + struct rockchip_pwm_chip *pc = dev->priv; + struct pwm_chip *chip = &pc->chip; + struct pwm_state curstate; + int ret; + + if (!pc->data->funcs.ir_transmit) { + dev_err(chip->dev, "Unsupported ir transmit mode\n"); + return -EINVAL; + } + + pwm_get_state(&pc->chip.pwms[0], &curstate); + if (curstate.enabled) { + dev_err(chip->dev, "Failed to enable ir transmit mode because PWM%d is busy\n", + pc->channel_id); + return -EBUSY; + } + + ret = pinctrl_select_state(pc->pinctrl, pc->active_state); + if (ret) { + dev_err(chip->dev, "Failed to select pinctrl state\n"); + return ret; + } + + ret = clk_enable(pc->pclk); + if (ret) + return ret; + + ret = pc->data->funcs.ir_transmit(chip, txbuf, count); + if (ret < 0) + dev_err(chip->dev, "Failed to transmit ir buf\n"); + + clk_disable(pc->pclk); + + return ret; +} +#else +static int rockchip_pwm_ir_transmit_v4(struct pwm_chip *chip, unsigned int *txbuf, + unsigned int count) +{ + return count; +} +#endif + #ifdef CONFIG_DEBUG_FS static int rockchip_pwm_debugfs_show(struct seq_file *s, void *data) { @@ -2034,6 +2227,7 @@ static const struct rockchip_pwm_data pwm_data_v4 = { .set_wave = rockchip_pwm_set_wave_v4, .set_biphasic = rockchip_pwm_set_biphasic_v4, .get_biphasic_result = rockchip_pwm_get_biphasic_result_v4, + .ir_transmit = rockchip_pwm_ir_transmit_v4, .irq_handler = rockchip_pwm_irq_v4, }, }; @@ -2140,6 +2334,7 @@ static int rockchip_pwm_probe(struct platform_device *pdev) if (pc->main_version >= 4) { version = readl_relaxed(pc->base + pc->data->regs.version); pc->channel_id = (version & CHANNLE_INDEX_MASK) >> CHANNLE_INDEX_SHIFT; + pc->ir_trans_support = !!(version & IR_TRANS_SUPPORT); pc->freq_meter_support = !!(version & FREQ_METER_SUPPORT); pc->counter_support = !!(version & COUNTER_SUPPORT); pc->wave_support = !!(version & WAVE_SUPPORT); @@ -2218,6 +2413,27 @@ static int rockchip_pwm_probe(struct platform_device *pdev) } } +#ifdef CONFIG_RC_CORE + if (pc->ir_trans_support && + device_property_present(&pdev->dev, "rockchip,pwm-ir-transmit")) { + struct rc_dev *rcdev; + + init_completion(&pc->ir_trans_completion); + + rcdev = devm_rc_allocate_device(&pdev->dev, RC_DRIVER_IR_RAW_TX); + if (!rcdev) + goto err_pclk; + + rcdev->priv = pc; + rcdev->driver_name = "rockchip-pwm-ir-tx"; + rcdev->device_name = "Rockchip IR TX"; + rcdev->tx_ir = rockchip_pwm_ir_transmit; + ret = devm_rc_register_device(&pdev->dev, rcdev); + if (ret < 0) + goto err_pclk; + } +#endif + rockchip_pwm_debugfs_init(pc); /* Keep the PWM clk enabled if the PWM appears to be up and running. */ diff --git a/include/uapi/linux/rk-camera-module.h b/include/uapi/linux/rk-camera-module.h index ce66391852d7..3dbf6faca24d 100644 --- a/include/uapi/linux/rk-camera-module.h +++ b/include/uapi/linux/rk-camera-module.h @@ -198,6 +198,12 @@ #define RKCIS_CMD_SELECT_SETTING \ _IOW('V', BASE_VIDIOC_PRIVATE + 44, struct rk_sensor_setting) +#define RKMODULE_GET_EXP_DELAY \ + _IOR('V', BASE_VIDIOC_PRIVATE + 45, struct rkmodule_exp_delay) + +#define RKMODULE_GET_EXP_INFO \ + _IOR('V', BASE_VIDIOC_PRIVATE + 46, struct rkmodule_exp_info) + struct rkmodule_i2cdev_info { __u8 slave_addr; } __attribute__ ((packed)); @@ -856,4 +862,37 @@ struct rk_sensor_setting { __u32 mode; } __attribute__ ((packed)); +struct rkmodule_exp_delay { + __u32 exp_delay; + __u32 gain_delay; + __u32 vts_delay; + __u32 dcg_delay; + __u32 reserved[2]; +} __attribute__ ((packed)); + +enum rkmodule_gain_mode_e { + RKMODULE_GAIN_MODE_LINEAR, + RKMODULE_GAIN_MODE_DB, +}; + +struct rkmodule_gain_mode { + __u32 gain_mode; + __u32 factor; +} __attribute__ ((packed)); + +struct rkmodule_exp_info { + __u32 exp[3]; + __u32 gain[3]; + __u32 exp_reg[3]; + __u32 gain_reg[3]; + __u32 hts; + __u32 vts; + __u32 pclk; + __u32 dcg_used; + __u32 dcg_val[3]; + struct rkmodule_dcg_ratio dcg_ratio; + struct rkmodule_gain_mode gain_mode; + __u32 reserved[6]; +} __attribute__ ((packed)); + #endif /* _UAPI_RKMODULE_CAMERA_H */ diff --git a/include/uapi/linux/rkcif-config.h b/include/uapi/linux/rkcif-config.h index 434c54f40653..57c8b536caae 100644 --- a/include/uapi/linux/rkcif-config.h +++ b/include/uapi/linux/rkcif-config.h @@ -83,6 +83,9 @@ #define RKCIF_CMD_SET_SENSOR_FLIP_END \ _IOWR('V', BASE_VIDIOC_PRIVATE + 21, int) +#define RKCIF_CMD_SUPPORT_GET_EXP \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 22, int) + /* cif memory mode * 0: raw12/raw10/raw8 8bit memory compact * 1: raw12/raw10 16bit memory one pixel