diff --git a/arch/arm64/boot/dts/rockchip/rk3576-evb.dtsi b/arch/arm64/boot/dts/rockchip/rk3576-evb.dtsi index 5d9084586630..8748210d65f5 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576-evb.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3576-evb.dtsi @@ -116,6 +116,15 @@ rockchip,jack-det; }; + edp_sound: edp-sound { + status = "disabled"; + compatible = "rockchip,hdmi"; + rockchip,mclk-fs = <128>; + rockchip,card-name = "rockchip-edp"; + rockchip,cpu = <&sai6>; + rockchip,codec = <&edp 0>; + }; + hdmi_sound: hdmi-sound { compatible = "rockchip,hdmi"; rockchip,mclk-fs = <128>; diff --git a/arch/arm64/boot/dts/rockchip/rk3576-evb1-v10-rk628-hdmi2csi.dts b/arch/arm64/boot/dts/rockchip/rk3576-evb1-v10-rk628-hdmi2csi.dts index d70ebb39783f..87d0adf7ab70 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576-evb1-v10-rk628-hdmi2csi.dts +++ b/arch/arm64/boot/dts/rockchip/rk3576-evb1-v10-rk628-hdmi2csi.dts @@ -23,19 +23,16 @@ status = "okay"; }; - hdmiin-sound { - compatible = "simple-audio-card"; - simple-audio-card,format = "i2s"; - simple-audio-card,name = "rockchip,hdmiin"; - simple-audio-card,bitclock-master = <&dailink0_master>; - simple-audio-card,frame-master = <&dailink0_master>; + hdmiin_sound: hdmiin-sound { status = "okay"; - simple-audio-card,cpu { - sound-dai = <&sai4>; - }; - dailink0_master: simple-audio-card,codec { - sound-dai = <&rk628_dc>; - }; + compatible = "rockchip,hdmi"; + rockchip,mclk-fs = <128>; + rockchip,card-name = "rockchip,rk628hdmiin"; + rockchip,cpu = <&sai4>; + rockchip,codec = <&rk628_csi>; + rockchip,bitclock-master = <&rk628_csi>; + rockchip,frame-master = <&rk628_csi>; + rockchip,jack-det; }; }; @@ -96,6 +93,7 @@ plugin-det-gpios = <&gpio3 RK_PD5 GPIO_ACTIVE_LOW>; continues-clk = <1>; cec-enable; + #sound-dai-cells = <0>; rockchip,camera-module-index = <0>; rockchip,camera-module-facing = "back"; @@ -174,6 +172,7 @@ pinctrl-0 = <&sai4m2_lrck &sai4m2_sclk &sai4m2_sdi>; + rockchip,sai-rx-wait-time-ms = <50>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3576-pinctrl.dtsi b/arch/arm64/boot/dts/rockchip/rk3576-pinctrl.dtsi index 9850c6fde722..0b0851a7e4ea 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576-pinctrl.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3576-pinctrl.dtsi @@ -2541,56 +2541,56 @@ pwm0m0_ch0: pwm0m0-ch0 { rockchip,pins = /* pwm0_ch0_m0 */ - <0 RK_PC4 12 &pcfg_pull_none>; + <0 RK_PC4 12 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm0m0_ch1: pwm0m0-ch1 { rockchip,pins = /* pwm0_ch1_m0 */ - <0 RK_PC3 12 &pcfg_pull_none>; + <0 RK_PC3 12 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm0m1_ch0: pwm0m1-ch0 { rockchip,pins = /* pwm0_ch0_m1 */ - <1 RK_PC0 13 &pcfg_pull_none>; + <1 RK_PC0 13 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm0m1_ch1: pwm0m1-ch1 { rockchip,pins = /* pwm0_ch1_m1 */ - <4 RK_PC1 14 &pcfg_pull_none>; + <4 RK_PC1 14 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm0m2_ch0: pwm0m2-ch0 { rockchip,pins = /* pwm0_ch0_m2 */ - <2 RK_PC3 13 &pcfg_pull_none>; + <2 RK_PC3 13 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm0m2_ch1: pwm0m2-ch1 { rockchip,pins = /* pwm0_ch1_m2 */ - <2 RK_PC7 13 &pcfg_pull_none>; + <2 RK_PC7 13 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm0m3_ch0: pwm0m3-ch0 { rockchip,pins = /* pwm0_ch0_m3 */ - <3 RK_PB0 12 &pcfg_pull_none>; + <3 RK_PB0 12 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm0m3_ch1: pwm0m3-ch1 { rockchip,pins = /* pwm0_ch1_m3 */ - <3 RK_PB6 12 &pcfg_pull_none>; + <3 RK_PB6 12 &pcfg_pull_none_drv_level_2>; }; }; @@ -2769,224 +2769,224 @@ pwm2m0_ch0: pwm2m0-ch0 { rockchip,pins = /* pwm2_ch0_m0 */ - <0 RK_PD3 12 &pcfg_pull_none>; + <0 RK_PD3 12 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m0_ch1: pwm2m0-ch1 { rockchip,pins = /* pwm2_ch1_m0 */ - <1 RK_PB3 12 &pcfg_pull_none>; + <1 RK_PB3 12 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m0_ch2: pwm2m0-ch2 { rockchip,pins = /* pwm2_ch2_m0 */ - <2 RK_PA0 14 &pcfg_pull_none>; + <2 RK_PA0 14 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m0_ch3: pwm2m0-ch3 { rockchip,pins = /* pwm2_ch3_m0 */ - <2 RK_PA1 14 &pcfg_pull_none>; + <2 RK_PA1 14 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m0_ch4: pwm2m0-ch4 { rockchip,pins = /* pwm2_ch4_m0 */ - <2 RK_PA4 14 &pcfg_pull_none>; + <2 RK_PA4 14 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m0_ch5: pwm2m0-ch5 { rockchip,pins = /* pwm2_ch5_m0 */ - <4 RK_PA2 13 &pcfg_pull_none>; + <4 RK_PA2 13 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m0_ch6: pwm2m0-ch6 { rockchip,pins = /* pwm2_ch6_m0 */ - <4 RK_PA7 13 &pcfg_pull_none>; + <4 RK_PA7 13 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m0_ch7: pwm2m0-ch7 { rockchip,pins = /* pwm2_ch7_m0 */ - <4 RK_PB3 13 &pcfg_pull_none>; + <4 RK_PB3 13 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m1_ch0: pwm2m1-ch0 { rockchip,pins = /* pwm2_ch0_m1 */ - <4 RK_PC2 14 &pcfg_pull_none>; + <4 RK_PC2 14 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m1_ch1: pwm2m1-ch1 { rockchip,pins = /* pwm2_ch1_m1 */ - <4 RK_PC3 14 &pcfg_pull_none>; + <4 RK_PC3 14 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m1_ch2: pwm2m1-ch2 { rockchip,pins = /* pwm2_ch2_m1 */ - <4 RK_PC6 14 &pcfg_pull_none>; + <4 RK_PC6 14 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m1_ch3: pwm2m1-ch3 { rockchip,pins = /* pwm2_ch3_m1 */ - <4 RK_PC7 14 &pcfg_pull_none>; + <4 RK_PC7 14 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m1_ch4: pwm2m1-ch4 { rockchip,pins = /* pwm2_ch4_m1 */ - <4 RK_PA3 13 &pcfg_pull_none>; + <4 RK_PA3 13 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m1_ch5: pwm2m1-ch5 { rockchip,pins = /* pwm2_ch5_m1 */ - <4 RK_PC5 14 &pcfg_pull_none>; + <4 RK_PC5 14 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m1_ch6: pwm2m1-ch6 { rockchip,pins = /* pwm2_ch6_m1 */ - <4 RK_PC4 14 &pcfg_pull_none>; + <4 RK_PC4 14 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m1_ch7: pwm2m1-ch7 { rockchip,pins = /* pwm2_ch7_m1 */ - <1 RK_PB1 12 &pcfg_pull_none>; + <1 RK_PB1 12 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m2_ch0: pwm2m2-ch0 { rockchip,pins = /* pwm2_ch0_m2 */ - <2 RK_PD0 13 &pcfg_pull_none>; + <2 RK_PD0 13 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m2_ch1: pwm2m2-ch1 { rockchip,pins = /* pwm2_ch1_m2 */ - <2 RK_PD1 13 &pcfg_pull_none>; + <2 RK_PD1 13 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m2_ch2: pwm2m2-ch2 { rockchip,pins = /* pwm2_ch2_m2 */ - <2 RK_PD2 13 &pcfg_pull_none>; + <2 RK_PD2 13 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m2_ch3: pwm2m2-ch3 { rockchip,pins = /* pwm2_ch3_m2 */ - <2 RK_PD3 13 &pcfg_pull_none>; + <2 RK_PD3 13 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m2_ch4: pwm2m2-ch4 { rockchip,pins = /* pwm2_ch4_m2 */ - <2 RK_PD4 13 &pcfg_pull_none>; + <2 RK_PD4 13 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m2_ch5: pwm2m2-ch5 { rockchip,pins = /* pwm2_ch5_m2 */ - <2 RK_PD5 13 &pcfg_pull_none>; + <2 RK_PD5 13 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m2_ch6: pwm2m2-ch6 { rockchip,pins = /* pwm2_ch6_m2 */ - <2 RK_PD6 13 &pcfg_pull_none>; + <2 RK_PD6 13 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m2_ch7: pwm2m2-ch7 { rockchip,pins = /* pwm2_ch7_m2 */ - <2 RK_PD7 13 &pcfg_pull_none>; + <2 RK_PD7 13 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m3_ch0: pwm2m3-ch0 { rockchip,pins = /* pwm2_ch0_m3 */ - <3 RK_PC2 12 &pcfg_pull_none>; + <3 RK_PC2 12 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m3_ch1: pwm2m3-ch1 { rockchip,pins = /* pwm2_ch1_m3 */ - <3 RK_PC3 12 &pcfg_pull_none>; + <3 RK_PC3 12 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m3_ch2: pwm2m3-ch2 { rockchip,pins = /* pwm2_ch2_m3 */ - <3 RK_PC5 12 &pcfg_pull_none>; + <3 RK_PC5 12 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m3_ch3: pwm2m3-ch3 { rockchip,pins = /* pwm2_ch3_m3 */ - <3 RK_PD0 12 &pcfg_pull_none>; + <3 RK_PD0 12 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m3_ch4: pwm2m3-ch4 { rockchip,pins = /* pwm2_ch4_m3 */ - <3 RK_PD2 12 &pcfg_pull_none>; + <3 RK_PD2 12 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m3_ch5: pwm2m3-ch5 { rockchip,pins = /* pwm2_ch5_m3 */ - <3 RK_PD3 12 &pcfg_pull_none>; + <3 RK_PD3 12 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m3_ch6: pwm2m3-ch6 { rockchip,pins = /* pwm2_ch6_m3 */ - <3 RK_PD6 12 &pcfg_pull_none>; + <3 RK_PD6 12 &pcfg_pull_none_drv_level_2>; }; /omit-if-no-ref/ pwm2m3_ch7: pwm2m3-ch7 { rockchip,pins = /* pwm2_ch7_m3 */ - <3 RK_PD7 12 &pcfg_pull_none>; + <3 RK_PD7 12 &pcfg_pull_none_drv_level_2>; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3576.dtsi b/arch/arm64/boot/dts/rockchip/rk3576.dtsi index b3561c32e3d0..1ff0eace6c78 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3576.dtsi @@ -3158,6 +3158,7 @@ phy-names = "dp"; power-domains = <&power RK3576_PD_VO0>; rockchip,grf = <&vo0_grf>; + #sound-dai-cells = <1>; status = "disabled"; ports { diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index bcb551fc29b2..032aad4ce48f 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -600,7 +600,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, .ops = &rockchip_dp_audio_codec_ops, .spdif = 1, .i2s = 1, - .max_i2s_channels = 2, + .max_i2s_channels = 8, }; dp->audio_pdev = diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c index f9d9dba3a1e9..afdcd5ad6fd4 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c @@ -243,7 +243,6 @@ struct dw_mipi_dsi2 { struct clk *pclk; struct clk *sys_clk; bool phy_enabled; - bool phy_request_clkhs; struct phy *dcphy; union phy_configure_opts phy_opts; @@ -832,10 +831,9 @@ static void dw_mipi_dsi2_pre_enable(struct dw_mipi_dsi2 *dsi2) dw_mipi_dsi2_pre_enable(dsi2->slave); } -static void dw_mipi_dsi2_enable(struct dw_mipi_dsi2 *dsi2) +static void dw_mipi_dsi2_clk_management(struct dw_mipi_dsi2 *dsi2) { - u32 clk_type, mode; - int ret; + u32 clk_type; /* * initial deskew calibration is send after phy_power_on, @@ -848,7 +846,14 @@ static void dw_mipi_dsi2_enable(struct dw_mipi_dsi2 *dsi2) regmap_update_bits(dsi2->regmap, DSI2_PHY_CLK_CFG, CLK_TYPE_MASK, clk_type); +} +static void dw_mipi_dsi2_enable(struct dw_mipi_dsi2 *dsi2) +{ + u32 mode; + int ret; + + dw_mipi_dsi2_clk_management(dsi2); dw_mipi_dsi2_ipi_set(dsi2); if (dsi2->auto_calc_mode) { @@ -1633,18 +1638,9 @@ static ssize_t dw_mipi_dsi2_transfer(struct dw_mipi_dsi2 *dsi2, u32 val; u32 mode; - if (msg->flags & MIPI_DSI_MSG_USE_LPM) { - regmap_update_bits(dsi2->regmap, DSI2_PHY_CLK_CFG, - CLK_TYPE_MASK, dsi2->phy_request_clkhs ? - CONTIUOUS_CLK : NON_CONTINUOUS_CLK); - regmap_update_bits(dsi2->regmap, DSI2_DSI_VID_TX_CFG, - LPDT_DISPLAY_CMD_EN, LPDT_DISPLAY_CMD_EN); - } else { - regmap_update_bits(dsi2->regmap, DSI2_PHY_CLK_CFG, - CLK_TYPE_MASK, CONTIUOUS_CLK); - regmap_update_bits(dsi2->regmap, DSI2_DSI_VID_TX_CFG, - LPDT_DISPLAY_CMD_EN, 0); - } + dw_mipi_dsi2_clk_management(dsi2); + regmap_update_bits(dsi2->regmap, DSI2_DSI_VID_TX_CFG, LPDT_DISPLAY_CMD_EN, + msg->flags & MIPI_DSI_MSG_USE_LPM ? LPDT_DISPLAY_CMD_EN : 0); /* create a packet to the DSI protocol */ ret = mipi_dsi_create_packet(&packet, msg); @@ -1732,9 +1728,6 @@ static int dw_mipi_dsi2_probe(struct platform_device *pdev) dsi2->pdata = of_device_get_match_data(dev); platform_set_drvdata(pdev, dsi2); - if (device_property_read_bool(dev, "phy-request-clkhs")) - dsi2->phy_request_clkhs = true; - if (device_property_read_bool(dev, "auto-calculation-mode")) dsi2->auto_calc_mode = true; diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 223f77d167e1..cd647f28a73b 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -1830,8 +1830,14 @@ dw_hdmi_rockchip_mode_valid(struct dw_hdmi *dw_hdmi, void *data, hdmi = to_rockchip_hdmi(encoder); if (!hdmi->skip_check_420_mode) { + u32 max_tmds_clock = connector->display_info.max_tmds_clock; + + /* some sinks edid max_tmds_clocks are 0, we think it only support hdmi1.4 */ + if (!connector->display_info.max_tmds_clock) + max_tmds_clock = 340000; + /* edid isn't support yuv420 and max_tmds_clock is less than mode pixel clk */ - if (mode->clock < 600000 && connector->display_info.max_tmds_clock < mode->clock && + if (mode->clock < 600000 && max_tmds_clock < mode->clock && (!drm_mode_is_420(&connector->display_info, mode) || !connector->ycbcr_420_allowed)) return MODE_BAD; @@ -1846,7 +1852,7 @@ dw_hdmi_rockchip_mode_valid(struct dw_hdmi *dw_hdmi, void *data, * exceeds the max_tmds_clock of edid. */ if (drm_mode_is_420(&connector->display_info, mode) && - connector->display_info.max_tmds_clock < (mode->clock / 2) && + max_tmds_clock < (mode->clock / 2) && is_hdmi2_mode(mode)) return MODE_BAD; }; diff --git a/drivers/input/touchscreen/focaltech_touch_ft5726/focaltech_core.c b/drivers/input/touchscreen/focaltech_touch_ft5726/focaltech_core.c index 324100dc0d40..f17fec1df58c 100644 --- a/drivers/input/touchscreen/focaltech_touch_ft5726/focaltech_core.c +++ b/drivers/input/touchscreen/focaltech_touch_ft5726/focaltech_core.c @@ -1432,7 +1432,7 @@ static void fts_resume_work(struct work_struct *work) } #if defined(CONFIG_FB) -static int fb_notifier_callback(struct notifier_block *self, +static int fts_fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) { struct fb_event *evdata = data; @@ -1445,7 +1445,7 @@ static int fb_notifier_callback(struct notifier_block *self, return 0; } - if (!(event == FB_EARLY_EVENT_BLANK || event == FB_EVENT_BLANK)) { + if (event != FB_EVENT_BLANK) { FTS_INFO("event(%lu) do not need process\n", event); return 0; } @@ -1454,18 +1454,14 @@ static int fb_notifier_callback(struct notifier_block *self, FTS_INFO("FB event:%lu,blank:%d", event, *blank); switch (*blank) { case FB_BLANK_UNBLANK: - if (FB_EARLY_EVENT_BLANK == event) { - FTS_INFO("resume: event = %lu, not care\n", event); - } else if (FB_EVENT_BLANK == event) { + if (FB_EVENT_BLANK == event) { queue_work(fts_data->ts_workqueue, &fts_data->resume_work); } break; case FB_BLANK_POWERDOWN: - if (FB_EARLY_EVENT_BLANK == event) { + if (FB_EVENT_BLANK == event) { cancel_work_sync(&fts_data->resume_work); fts_ts_suspend(ts_data->dev); - } else if (FB_EVENT_BLANK == event) { - FTS_INFO("suspend: event = %lu, not care\n", event); } break; default: @@ -1766,7 +1762,7 @@ static int fts_ts_probe_entry(struct fts_ts_data *ts_data) #endif #if defined(CONFIG_FB) - ts_data->fb_notif.notifier_call = fb_notifier_callback; + ts_data->fb_notif.notifier_call = fts_fb_notifier_callback; ret = fb_register_client(&ts_data->fb_notif); if (ret) { FTS_ERROR("[FB]Unable to register fb_notifier: %d", ret); diff --git a/drivers/input/touchscreen/parade/pt_core.c b/drivers/input/touchscreen/parade/pt_core.c index b98996ec940b..97a7c452e3ab 100644 --- a/drivers/input/touchscreen/parade/pt_core.c +++ b/drivers/input/touchscreen/parade/pt_core.c @@ -12305,7 +12305,7 @@ static void pt_setup_early_suspend(struct pt_core_data *cd) } #elif defined(CONFIG_FB) /******************************************************************************* - * FUNCTION: fb_notifier_callback + * FUNCTION: pt_fb_notifier_callback * * SUMMARY: Call back function for FrameBuffer notifier to allow to call * resume/suspend attention list. @@ -12318,7 +12318,7 @@ static void pt_setup_early_suspend(struct pt_core_data *cd) * event - event type of fb notifier * *data - pointer to fb_event structure ******************************************************************************/ -static int fb_notifier_callback(struct notifier_block *self, +static int pt_fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) { struct pt_core_data *cd = @@ -12370,7 +12370,7 @@ static void pt_setup_fb_notifier(struct pt_core_data *cd) cd->fb_state = FB_ON; - cd->fb_notifier.notifier_call = fb_notifier_callback; + cd->fb_notifier.notifier_call = pt_fb_notifier_callback; rc = fb_register_client(&cd->fb_notifier); if (rc) diff --git a/drivers/media/i2c/rk628/rk628_bt1120_v4l2.c b/drivers/media/i2c/rk628/rk628_bt1120_v4l2.c index 5072cc41288a..67c350b811a5 100644 --- a/drivers/media/i2c/rk628/rk628_bt1120_v4l2.c +++ b/drivers/media/i2c/rk628/rk628_bt1120_v4l2.c @@ -251,7 +251,7 @@ static bool tx_5v_power_present(struct v4l2_subdev *sd) struct rk628_bt1120 *bt1120 = to_bt1120(sd); ret = rk628_hdmirx_tx_5v_power_detect(bt1120->plugin_det_gpio); - v4l2_dbg(1, debug, sd, "%s: %d\n", __func__, ret); + v4l2_dbg(2, debug, sd, "%s: %d\n", __func__, ret); return ret; } @@ -464,6 +464,7 @@ static void rk628_delayed_work_res_change(struct work_struct *work) bool plugin; mutex_lock(&bt1120->confctl_mutex); + rk628_set_bg_enable(bt1120->rk628, false); enable_stream(sd, false); bt1120->nosignal = true; bt1120->avi_rcv_rdy = false; @@ -513,7 +514,7 @@ static void rk628_hdmirx_hpd_ctrl(struct v4l2_subdev *sd, bool en) HOT_PLUG_DETECT_MASK, HOT_PLUG_DETECT(set_level)); if (bt1120->cec_enable && bt1120->cec) - rk628_hdmirx_cec_hpd(bt1120->cec, en); + rk628_hdmirx_cec_hpd(bt1120->cec, tx_5v_power_present(sd)); } static int rk628_bt1120_s_ctrl_detect_tx_5v(struct v4l2_subdev *sd) @@ -950,16 +951,23 @@ static void rk628_bt1120_clear_hdmirx_interrupts(struct v4l2_subdev *sd) { struct rk628_bt1120 *bt1120 = to_bt1120(sd); - /* clear interrupts */ - rk628_i2c_write(bt1120->rk628, HDMI_RX_MD_ICLR, 0xffffffff); - rk628_i2c_write(bt1120->rk628, HDMI_RX_PDEC_ICLR, 0xffffffff); if (bt1120->rk628->version >= RK628F_VERSION) rk628_i2c_write(bt1120->rk628, GRF_INTR0_CLR_EN, 0x02000200); else rk628_i2c_write(bt1120->rk628, GRF_INTR0_CLR_EN, 0x01000100); } -static int rk628_bt1120_isr(struct v4l2_subdev *sd, u32 status, bool *handled) +static int rk628_is_general_isr(struct rk628_bt1120 *bt1120, u32 md_ints, u32 pdec_ints) +{ + if (rk628_hdmirx_is_signal_change_ists(bt1120->rk628, md_ints, pdec_ints)) + return 1; + if ((pdec_ints & AVI_RCV_ISTS) && !bt1120->avi_rcv_rdy) + return 1; + + return 0; +} + +static int rk628_hdmirx_general_isr(struct v4l2_subdev *sd, u32 status, bool *handled) { struct rk628_bt1120 *bt1120 = to_bt1120(sd); u32 md_ints, pdec_ints, fifo_ints, hact, vact; @@ -972,11 +980,25 @@ static int rk628_bt1120_isr(struct v4l2_subdev *sd, u32 status, bool *handled) return -EINVAL; } + if (!bt1120->vid_ints_en) + return 0; + rk628_i2c_read(bt1120->rk628, GRF_INTR0_STATUS, &int0_status); + if (!(int0_status & (BIT(8) | BIT(9)))) + return 0; + v4l2_dbg(1, debug, sd, "%s: int0 status: 0x%x\n", __func__, int0_status); rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_ISTS, &md_ints); rk628_i2c_read(bt1120->rk628, HDMI_RX_PDEC_ISTS, &pdec_ints); + + /* clear interrupts */ + rk628_i2c_write(bt1120->rk628, HDMI_RX_MD_ICLR, 0xffffffff); + rk628_i2c_write(bt1120->rk628, HDMI_RX_PDEC_ICLR, 0xffffffff); + + if (!rk628_is_general_isr(bt1120, md_ints, pdec_ints)) + return 0; + if (bt1120->rk628->version >= RK628F_VERSION && rk628_hdmirx_is_signal_change_ists(bt1120->rk628, md_ints, pdec_ints)) rk628_set_bg_enable(bt1120->rk628, true); @@ -1003,37 +1025,34 @@ static int rk628_bt1120_isr(struct v4l2_subdev *sd, u32 status, bool *handled) } } } - if (bt1120->vid_ints_en) { - v4l2_dbg(1, debug, sd, "%s: md_ints: %#x, pdec_ints:%#x, plugin: %d\n", - __func__, md_ints, pdec_ints, plugin); + v4l2_dbg(1, debug, sd, "%s: md_ints: %#x, pdec_ints:%#x, plugin: %d\n", + __func__, md_ints, pdec_ints, plugin); - if (rk628_hdmirx_is_signal_change_ists(bt1120->rk628, md_ints, pdec_ints)) { + if (rk628_hdmirx_is_signal_change_ists(bt1120->rk628, md_ints, pdec_ints)) { + rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_HACT_PX, &hact); + rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_VAL, &vact); + v4l2_dbg(1, debug, sd, "%s: HACT:%#x, VACT:%#x\n", + __func__, hact, vact); - rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_HACT_PX, &hact); - rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_VAL, &vact); - v4l2_dbg(1, debug, sd, "%s: HACT:%#x, VACT:%#x\n", - __func__, hact, vact); - - rk628_bt1120_enable_interrupts(sd, false); - if (bt1120->rk628->version < RK628F_VERSION) { - enable_stream(sd, false); - bt1120->nosignal = true; - } - schedule_delayed_work(&bt1120->delayed_work_res_change, HZ / 2); - - v4l2_dbg(1, debug, sd, "%s: hact/vact change, md_ints: %#x\n", - __func__, (u32)(md_ints & (VACT_LIN_ISTS | HACT_PIX_ISTS))); - *handled = true; + rk628_bt1120_enable_interrupts(sd, false); + if (bt1120->rk628->version < RK628F_VERSION) { + enable_stream(sd, false); + bt1120->nosignal = true; } + schedule_delayed_work(&bt1120->delayed_work_res_change, HZ / 2); - if ((pdec_ints & AVI_RCV_ISTS) && plugin && !bt1120->avi_rcv_rdy) { - v4l2_dbg(1, debug, sd, "%s: AVI RCV INT!\n", __func__); - bt1120->avi_rcv_rdy = true; - /* After get the AVI_RCV interrupt state, disable interrupt. */ - rk628_i2c_write(bt1120->rk628, HDMI_RX_PDEC_IEN_CLR, AVI_RCV_ISTS); + v4l2_dbg(1, debug, sd, "%s: hact/vact change, md_ints: %#x\n", + __func__, (u32)(md_ints & (VACT_LIN_ISTS | HACT_PIX_ISTS))); + *handled = true; + } - *handled = true; - } + if ((pdec_ints & AVI_RCV_ISTS) && plugin && !bt1120->avi_rcv_rdy) { + v4l2_dbg(1, debug, sd, "%s: AVI RCV INT!\n", __func__); + bt1120->avi_rcv_rdy = true; + /* After get the AVI_RCV interrupt state, disable interrupt. */ + rk628_i2c_write(bt1120->rk628, HDMI_RX_PDEC_IEN_CLR, AVI_RCV_ISTS); + + *handled = true; } if (*handled != true) v4l2_dbg(1, debug, sd, "%s: unhandled interrupt!\n", __func__); @@ -1041,17 +1060,25 @@ static int rk628_bt1120_isr(struct v4l2_subdev *sd, u32 status, bool *handled) return 0; } +static int rk628_hdmirx_isr(struct v4l2_subdev *sd, u32 status, bool *handled) +{ + struct rk628_bt1120 *bt1120 = to_bt1120(sd); + + rk628_hdmirx_general_isr(sd, status, handled); + if (bt1120->cec_enable && bt1120->cec) + rk628_hdmirx_cec_irq(bt1120->rk628, bt1120->cec); + + rk628_bt1120_clear_hdmirx_interrupts(sd); + + return 0; +} + static irqreturn_t rk628_bt1120_irq_handler(int irq, void *dev_id) { struct rk628_bt1120 *bt1120 = dev_id; bool handled = true; - rk628_bt1120_isr(&bt1120->sd, 0, &handled); - - if (bt1120->cec_enable && bt1120->cec) - rk628_hdmirx_cec_irq(bt1120->rk628, bt1120->cec); - - rk628_bt1120_clear_hdmirx_interrupts(&bt1120->sd); + rk628_hdmirx_isr(&bt1120->sd, 0, &handled); return handled ? IRQ_HANDLED : IRQ_NONE; } @@ -1615,7 +1642,7 @@ static const struct v4l2_subdev_internal_ops bt1120_subdev_internal_ops = { #endif static const struct v4l2_subdev_core_ops rk628_bt1120_core_ops = { - .interrupt_service_routine = rk628_bt1120_isr, + .interrupt_service_routine = rk628_hdmirx_isr, .subscribe_event = rk628_bt1120_subscribe_event, .unsubscribe_event = v4l2_event_subdev_unsubscribe, .ioctl = rk628_bt1120_ioctl, @@ -2008,7 +2035,8 @@ static int rk628_bt1120_probe(struct i2c_client *client, bt1120->audio_info = rk628_hdmirx_audioinfo_alloc(dev, &bt1120->confctl_mutex, rk628, - bt1120->i2s_enable_default); + bt1120->i2s_enable_default, + NULL); if (!bt1120->audio_info) { v4l2_err(sd, "request audio info fail\n"); goto err_work_queues; diff --git a/drivers/media/i2c/rk628/rk628_csi_v4l2.c b/drivers/media/i2c/rk628/rk628_csi_v4l2.c index 5a81de8e14c6..2a53a1107c71 100644 --- a/drivers/media/i2c/rk628/rk628_csi_v4l2.c +++ b/drivers/media/i2c/rk628/rk628_csi_v4l2.c @@ -382,7 +382,7 @@ static bool tx_5v_power_present(struct v4l2_subdev *sd) struct rk628_csi *csi = to_csi(sd); ret = rk628_hdmirx_tx_5v_power_detect(csi->plugin_det_gpio); - v4l2_dbg(1, debug, sd, "%s: %d\n", __func__, ret); + v4l2_dbg(2, debug, sd, "%s: %d\n", __func__, ret); return ret; } @@ -494,6 +494,9 @@ static void rk628_hdmirx_config_all(struct v4l2_subdev *sd) } if (ret < 0 || rk628_hdmirx_scdc_ced_err(csi->rk628)) { + if (rk628_hdmirx_get_arc_enable(csi->audio_info)) + return; + rk628_hdmirx_plugout(sd); csi->lock_fail_time++; v4l2_dbg(1, debug, sd, "%s: lock fail time: %d\n", @@ -574,6 +577,7 @@ static void rk628_delayed_work_res_change(struct work_struct *work) bool plugin; mutex_lock(&csi->confctl_mutex); + rk628_set_bg_enable(csi->rk628, false); enable_stream(sd, false); csi->nosignal = true; csi->avi_rcv_rdy = false; @@ -623,7 +627,7 @@ static void rk628_hdmirx_hpd_ctrl(struct v4l2_subdev *sd, bool en) HOT_PLUG_DETECT_MASK, HOT_PLUG_DETECT(set_level)); if (csi->cec_enable && csi->cec) - rk628_hdmirx_cec_hpd(csi->cec, en); + rk628_hdmirx_cec_hpd(csi->cec, tx_5v_power_present(sd)); } @@ -1571,9 +1575,6 @@ static void rk628_csi_clear_hdmirx_interrupts(struct v4l2_subdev *sd) struct rk628_csi *csi = to_csi(sd); v4l2_dbg(2, debug, sd, "%s: clear hdmirx ints\n", __func__); - /* clear interrupts */ - rk628_i2c_write(csi->rk628, HDMI_RX_MD_ICLR, 0xffffffff); - rk628_i2c_write(csi->rk628, HDMI_RX_PDEC_ICLR, 0xffffffff); if (csi->rk628->version >= RK628F_VERSION) rk628_i2c_write(csi->rk628, GRF_INTR0_CLR_EN, 0x02000200); else @@ -1644,13 +1645,22 @@ static void rk628_csi_error_process(struct v4l2_subdev *sd) } } -static int rk628_csi_isr(struct v4l2_subdev *sd, u32 status, bool *handled) +static int rk628_is_general_isr(struct rk628_csi *csi, u32 md_ints, u32 pdec_ints) +{ + if (rk628_hdmirx_is_signal_change_ists(csi->rk628, md_ints, pdec_ints)) + return 1; + if ((pdec_ints & AVI_RCV_ISTS) && !csi->avi_rcv_rdy) + return 1; + + return 0; +} + +static int rk628_hdmirx_general_isr(struct v4l2_subdev *sd, u32 status, bool *handled) { struct rk628_csi *csi = to_csi(sd); u32 md_ints = 0x0, pdec_ints = 0x0, fifo_ints, hact, vact; bool plugin; void *audio_info = csi->audio_info; - u32 csi0_raw_ints = 0x0, csi1_raw_ints = 0x0; u32 int0_status; const struct v4l2_event evt_signal_lost = { .type = RK_HDMIRX_V4L2_EVENT_SIGNAL_LOST, @@ -1661,31 +1671,36 @@ static int rk628_csi_isr(struct v4l2_subdev *sd, u32 status, bool *handled) return -EINVAL; } + if (!csi->vid_ints_en) + return 0; + rk628_i2c_read(csi->rk628, GRF_INTR0_STATUS, &int0_status); + if (!(int0_status & (BIT(8) | BIT(9)))) + return 0; + + rk628_i2c_read(csi->rk628, HDMI_RX_MD_ISTS, &md_ints); + rk628_i2c_read(csi->rk628, HDMI_RX_PDEC_ISTS, &pdec_ints); + + /* clear interrupts */ + rk628_i2c_write(csi->rk628, HDMI_RX_MD_ICLR, 0xffffffff); + rk628_i2c_write(csi->rk628, HDMI_RX_PDEC_ICLR, 0xffffffff); + + if (!rk628_is_general_isr(csi, md_ints, pdec_ints)) + return 0; + v4l2_dbg(1, debug, sd, "%s: int0 status: 0x%x\n", __func__, int0_status); - if (int0_status & (BIT(8) | BIT(9))) { - rk628_i2c_read(csi->rk628, HDMI_RX_MD_ISTS, &md_ints); - rk628_i2c_read(csi->rk628, HDMI_RX_PDEC_ISTS, &pdec_ints); - if (csi->rk628->version >= RK628F_VERSION && - rk628_hdmirx_is_signal_change_ists(csi->rk628, md_ints, pdec_ints)) - rk628_set_bg_enable(csi->rk628, true); - } - if ((int0_status & (BIT(6) | BIT(7)))) { - rk628_i2c_read(csi->rk628, CSITX_ERR_INTR_RAW_STATUS_IMD, &csi0_raw_ints); - if (csi->rk628->version >= RK628F_VERSION) - rk628_i2c_read(csi->rk628, CSITX1_ERR_INTR_RAW_STATUS_IMD, &csi1_raw_ints); - rk628_csi_clear_csi_interrupts(sd); - } + if (csi->rk628->version >= RK628F_VERSION && + rk628_hdmirx_is_signal_change_ists(csi->rk628, md_ints, pdec_ints)) + rk628_set_bg_enable(csi->rk628, true); plugin = tx_5v_power_present(sd); if (!plugin) { rk628_csi_enable_interrupts(sd, false); - rk628_csi_enable_csi_interrupts(sd, false); return 0; } - if (csi->rk628->version < RK628F_VERSION && (int0_status & BIT(8))) { + if (csi->rk628->version < RK628F_VERSION) { if (rk628_audio_ctsnints_enabled(audio_info)) { if (pdec_ints & (ACR_N_CHG_ICLR | ACR_CTS_CHG_ICLR)) { rk628_csi_isr_ctsn(audio_info, pdec_ints); @@ -1701,41 +1716,77 @@ static int rk628_csi_isr(struct v4l2_subdev *sd, u32 status, bool *handled) } } } - if (csi->vid_ints_en && (int0_status & (BIT(8) | BIT(9)))) { - v4l2_dbg(1, debug, sd, "%s: md_ints: %#x, pdec_ints:%#x, plugin: %d\n", - __func__, md_ints, pdec_ints, plugin); - if (rk628_hdmirx_is_signal_change_ists(csi->rk628, md_ints, pdec_ints)) { - rk628_i2c_read(csi->rk628, HDMI_RX_MD_HACT_PX, &hact); - rk628_i2c_read(csi->rk628, HDMI_RX_MD_VAL, &vact); - v4l2_dbg(1, debug, sd, "%s: HACT:%#x, VACT:%#x\n", - __func__, hact, vact); + v4l2_dbg(1, debug, sd, "%s: md_ints: %#x, pdec_ints:%#x, plugin: %d\n", + __func__, md_ints, pdec_ints, plugin); - rk628_csi_enable_interrupts(sd, false); - if (csi->rk628->version < RK628F_VERSION) { - enable_stream(sd, false); - csi->nosignal = true; - } - v4l2_event_queue(sd->devnode, &evt_signal_lost); - schedule_delayed_work(&csi->delayed_work_res_change, msecs_to_jiffies(100)); + if (rk628_hdmirx_is_signal_change_ists(csi->rk628, md_ints, pdec_ints)) { + rk628_i2c_read(csi->rk628, HDMI_RX_MD_HACT_PX, &hact); + rk628_i2c_read(csi->rk628, HDMI_RX_MD_VAL, &vact); + v4l2_dbg(1, debug, sd, "%s: HACT:%#x, VACT:%#x\n", + __func__, hact, vact); - v4l2_dbg(1, debug, sd, "%s: hact/vact change, md_ints: %#x\n", - __func__, (u32)(md_ints & (VACT_LIN_ISTS | HACT_PIX_ISTS))); - *handled = true; + rk628_csi_enable_interrupts(sd, false); + if (csi->rk628->version < RK628F_VERSION) { + enable_stream(sd, false); + csi->nosignal = true; } + v4l2_event_queue(sd->devnode, &evt_signal_lost); + schedule_delayed_work(&csi->delayed_work_res_change, msecs_to_jiffies(100)); - if ((pdec_ints & AVI_RCV_ISTS) && plugin && !csi->avi_rcv_rdy) { - v4l2_dbg(1, debug, sd, "%s: AVI RCV INT!\n", __func__); - if (csi->plat_data->tx_mode == DSI_MODE) - enable_stream(sd, false); - csi->avi_rcv_rdy = true; - /* After get the AVI_RCV interrupt state, disable interrupt. */ - rk628_i2c_write(csi->rk628, HDMI_RX_PDEC_IEN_CLR, AVI_RCV_ISTS); - - *handled = true; - } + v4l2_dbg(1, debug, sd, "%s: hact/vact change, md_ints: %#x\n", + __func__, (u32)(md_ints & (VACT_LIN_ISTS | HACT_PIX_ISTS))); + *handled = true; } + if ((pdec_ints & AVI_RCV_ISTS) && plugin && !csi->avi_rcv_rdy) { + v4l2_dbg(1, debug, sd, "%s: AVI RCV INT!\n", __func__); + if (csi->plat_data->tx_mode == DSI_MODE) + enable_stream(sd, false); + csi->avi_rcv_rdy = true; + /* After get the AVI_RCV interrupt state, disable interrupt. */ + rk628_i2c_write(csi->rk628, HDMI_RX_PDEC_IEN_CLR, AVI_RCV_ISTS); + + *handled = true; + } + + if (*handled != true) + v4l2_dbg(1, debug, sd, "%s: unhandled interrupt!\n", __func__); + + return 0; +} + +static int rk628_hdmirx_isr(struct v4l2_subdev *sd, u32 status, bool *handled) +{ + struct rk628_csi *csi = to_csi(sd); + + rk628_hdmirx_general_isr(sd, status, handled); + if (csi->cec_enable && csi->cec) + rk628_hdmirx_cec_irq(csi->rk628, csi->cec); + + rk628_csi_clear_hdmirx_interrupts(sd); + + return 0; +} + +static int rk628_csi_isr(struct v4l2_subdev *sd, u32 status, bool *handled) +{ + struct rk628_csi *csi = to_csi(sd); + u32 int0_status; + u32 csi0_raw_ints = 0x0, csi1_raw_ints = 0x0; + + rk628_i2c_read(csi->rk628, GRF_INTR0_STATUS, &int0_status); + if (!(int0_status & (BIT(6) | BIT(7)))) + return 0; + + v4l2_dbg(1, debug, sd, "%s: int0 status: 0x%x\n", __func__, int0_status); + + rk628_i2c_read(csi->rk628, CSITX_ERR_INTR_RAW_STATUS_IMD, &csi0_raw_ints); + if (csi->rk628->version >= RK628F_VERSION) + rk628_i2c_read(csi->rk628, CSITX1_ERR_INTR_RAW_STATUS_IMD, &csi1_raw_ints); + + rk628_csi_clear_csi_interrupts(sd); + if (csi0_raw_ints || csi1_raw_ints) { v4l2_info(sd, "%s: csi interrupt: csi0_raw_ints: 0x%x, csi1_raw_ints: 0x%x!\n", @@ -1750,17 +1801,20 @@ static int rk628_csi_isr(struct v4l2_subdev *sd, u32 status, bool *handled) return 0; } +static int rk628_isr_process(struct v4l2_subdev *sd, u32 status, bool *handled) +{ + rk628_hdmirx_isr(sd, status, handled); + rk628_csi_isr(sd, status, handled); + + return 0; +} + static irqreturn_t rk628_csi_irq_handler(int irq, void *dev_id) { struct rk628_csi *csi = dev_id; bool handled = true; - rk628_csi_isr(&csi->sd, 0, &handled); - - if (csi->cec_enable && csi->cec) - rk628_hdmirx_cec_irq(csi->rk628, csi->cec); - - rk628_csi_clear_hdmirx_interrupts(&csi->sd); + rk628_isr_process(&csi->sd, 0, &handled); return handled ? IRQ_HANDLED : IRQ_NONE; } @@ -1792,6 +1846,8 @@ static int rk628_csi_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub); case RK_HDMIRX_V4L2_EVENT_SIGNAL_LOST: return v4l2_event_subscribe(fh, sub, 0, NULL); + case RK_HDMIRX_V4L2_EVENT_AUDIOINFO: + return v4l2_event_subscribe(fh, sub, 0, NULL); default: return -EINVAL; } @@ -2786,7 +2842,7 @@ static long rk628_csi_compat_ioctl32(struct v4l2_subdev *sd, #endif static const struct v4l2_subdev_core_ops rk628_csi_core_ops = { - .interrupt_service_routine = rk628_csi_isr, + .interrupt_service_routine = rk628_isr_process, .subscribe_event = rk628_csi_subscribe_event, .unsubscribe_event = v4l2_event_subdev_unsubscribe, .ioctl = rk628_csi_ioctl, @@ -2886,6 +2942,17 @@ static irqreturn_t plugin_detect_irq(int irq, void *dev_id) return IRQ_HANDLED; } +static void rk628_csi_audio_info_cb(struct rk628 *rk628, bool on) +{ + struct i2c_client *client = to_i2c_client(rk628->dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + const struct v4l2_event evt_audio_info = { + .type = RK_HDMIRX_V4L2_EVENT_AUDIOINFO, + }; + v4l2_event_queue(sd->devnode, &evt_audio_info); +} + static int rk628_csi_power_on(struct rk628_csi *csi) { clk_prepare_enable(csi->soc_24M); @@ -3132,12 +3199,48 @@ static ssize_t audio_present_show(struct device *dev, rk628_hdmirx_audio_present(csi->audio_info) : 0); } +static ssize_t arc_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct rk628_csi *csi = dev_get_drvdata(dev); + struct rk_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev); + + if (!hdmirx_dev) + return -EINVAL; + + return snprintf(buf, PAGE_SIZE, "%d\n", + rk628_hdmirx_get_arc_enable(csi->audio_info) ? 1 : 0); +} + +static ssize_t arc_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rk628_csi *csi = dev_get_drvdata(dev); + struct rk_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev); + bool enabled; + int ret; + + if (!hdmirx_dev) + return -EINVAL; + + ret = kstrtobool(buf, &enabled); + if (ret) + return ret; + + rk628_hdmirx_set_arc_enable(csi->audio_info, enabled); + + return count; +} + static DEVICE_ATTR_RO(audio_rate); static DEVICE_ATTR_RO(audio_present); +static DEVICE_ATTR_RW(arc_enable); static struct attribute *rk628_attrs[] = { &dev_attr_audio_rate.attr, &dev_attr_audio_present.attr, + &dev_attr_arc_enable.attr, NULL }; ATTRIBUTE_GROUPS(rk628); @@ -3372,7 +3475,8 @@ static int rk628_csi_probe(struct i2c_client *client, csi->audio_info = rk628_hdmirx_audioinfo_alloc(dev, &csi->confctl_mutex, rk628, - csi->i2s_enable_default); + csi->i2s_enable_default, + rk628_csi_audio_info_cb); if (!csi->audio_info) { err = -ENOMEM; v4l2_err(sd, "request audio info fail\n"); diff --git a/drivers/media/i2c/rk628/rk628_hdmirx.c b/drivers/media/i2c/rk628/rk628_hdmirx.c index ef69600a5340..5af2cc8223bb 100644 --- a/drivers/media/i2c/rk628/rk628_hdmirx.c +++ b/drivers/media/i2c/rk628/rk628_hdmirx.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "rk628.h" #include "rk628_combrxphy.h" @@ -19,6 +20,8 @@ #define INIT_FIFO_STATE 64 +#define DEFAULT_AUDIO_CLK 5644800 + struct rk628_audiostate { u32 hdmirx_aud_clkrate; u32 fs_audio; @@ -39,10 +42,21 @@ struct rk628_audioinfo { bool i2s_enabled_default; bool i2s_enabled; int debug; + bool sample_flat; bool fifo_ints_en; bool ctsn_ints_en; bool audio_present; + bool arc_en; + bool underflow; + bool overflow; + bool startthreshold; + int stablelimit; + int stablecount; struct device *dev; + struct platform_device *pdev; + hdmi_codec_plugged_cb plugged_cb; + rk628_audio_info_cb info_cb; + struct device *codec_dev; }; struct hdmirx_tmdsclk_cnt { @@ -296,6 +310,9 @@ static void rk628_hdmirx_audio_fifo_init(struct rk628_audioinfo *aif) rk628_i2c_write(aif->rk628, HDMI_RX_AUD_FIFO_CTRL, 0x10001); rk628_i2c_write(aif->rk628, HDMI_RX_AUD_FIFO_CTRL, 0x10000); aif->audio_state.pre_state = aif->audio_state.init_state = INIT_FIFO_STATE*4; + aif->underflow = false; + aif->overflow = false; + aif->startthreshold = false; } static void rk628_hdmirx_audio_fifo_initd(struct rk628_audioinfo *aif) @@ -360,6 +377,25 @@ static void rk628_hdmirx_audio_clk_inc_rate(struct rk628_audioinfo *aif, int dis aif->audio_state.hdmirx_aud_clkrate = hdmirx_aud_clkrate; } +static void rk628_hdmirx_audio_clk_ppm_inc(struct rk628_audioinfo *aif, int ppm) +{ + int delta, rate, inc; + + rate = aif->audio_state.hdmirx_aud_clkrate; + if (ppm < 0) { + ppm = -ppm; + inc = -1; + } else + inc = 1; + delta = div_u64(((uint64_t)rate * ppm + 500000), 1000000); + delta *= inc; + rate += delta; + dev_dbg(aif->dev, "%s: %u to %u(delta:%d)\n", + __func__, aif->audio_state.hdmirx_aud_clkrate, rate, delta); + rk628_clk_set_rate(aif->rk628, CGU_CLK_HDMIRX_AUD, rate); + aif->audio_state.hdmirx_aud_clkrate = rate; +} + static void rk628_hdmirx_audio_set_fs(struct rk628_audioinfo *aif, u32 fs_audio) { u32 hdmirx_aud_clkrate_t = fs_audio*128; @@ -403,6 +439,55 @@ static const char *audio_fifo_err(u32 fifo_status) return "underflow or overflow"; } +static int rk628_hdmirx_audio_clk_adjust(struct rk628_audioinfo *aif, + int total_offset, int single_offset) +{ + int shedule_time = 500; + int ppm = 10; + + if (total_offset > 16 && single_offset > 0) + rk628_hdmirx_audio_clk_ppm_inc(aif, ppm); + else if (total_offset < -16 && single_offset < 0) + rk628_hdmirx_audio_clk_ppm_inc(aif, -ppm); + if (total_offset >= 20) { + shedule_time = 200; + } else if (total_offset >= 50) { + shedule_time = 100; + dev_dbg(aif->dev, "%s: decrease shedule time to %d\n", __func__, shedule_time); + } else if (ppm >= 80) { + shedule_time = 50; + dev_dbg(aif->dev, "%s: decrease shedule time to %d\n", __func__, shedule_time); + } + if (!aif->audio_present) + shedule_time = 50; + return shedule_time; +} + +static void rk628_hdmirx_audio_state_change(struct rk628_audioinfo *aif, bool on) +{ + struct device *dev = aif->rk628->dev; + + if (on) { + if (aif->stablecount < aif->stablelimit) { + aif->stablecount++; + dev_info(dev, "wait for audio stable count %d\n", aif->stablecount); + return; + } + if (!aif->audio_present) { + aif->audio_present = true; + dev_info(dev, "audio on\n"); + rk628_hdmirx_audio_handle_plugged_change(aif, aif->audio_present); + } + } else { + if (aif->audio_present) { + aif->stablecount = 0; + aif->audio_present = false; + dev_info(dev, "audio off\n"); + rk628_hdmirx_audio_handle_plugged_change(aif, aif->audio_present); + } + } +} + static void rk628_csi_delayed_work_audio_v2(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); @@ -412,13 +497,13 @@ static void rk628_csi_delayed_work_audio_v2(struct work_struct *work) struct rk628 *rk628 = aif->rk628; u32 fs_audio, sample_flat; int init_state, pre_state, fifo_status, fifo_ints; + int single_offset, total_offset; unsigned long delay = 500; fs_audio = _rk628_hdmirx_audio_fs(aif); /* read fifo init status */ rk628_i2c_read(rk628, HDMI_RX_AUD_FIFO_ISTS, &fifo_ints); dev_dbg(rk628->dev, "%s: HDMI_RX_AUD_FIFO_ISTS:%#x\r\n", __func__, fifo_ints); - if (fifo_ints & (AFIF_UNDERFL_ISTS | AFIF_OVERFL_ISTS)) { dev_warn(rk628->dev, "%s: audio %s %#x, with fs %svalid %d\n", __func__, audio_fifo_err(fifo_ints), fifo_ints, @@ -426,7 +511,7 @@ static void rk628_csi_delayed_work_audio_v2(struct work_struct *work) if (is_validfs(fs_audio)) rk628_hdmirx_audio_set_fs(aif, fs_audio); rk628_hdmirx_audio_fifo_init(aif); - audio_state->pre_state = 0; + rk628_hdmirx_audio_state_change(aif, 0); goto exit; } @@ -434,9 +519,11 @@ static void rk628_csi_delayed_work_audio_v2(struct work_struct *work) init_state = audio_state->init_state; pre_state = audio_state->pre_state; rk628_i2c_read(rk628, HDMI_RX_AUD_FIFO_FILLSTS1, &fifo_status); + single_offset = fifo_status - pre_state; + total_offset = fifo_status - init_state; dev_dbg(rk628->dev, "%s: HDMI_RX_AUD_FIFO_FILLSTS1:%#x, single offset:%d, total offset:%d\n", - __func__, fifo_status, fifo_status - pre_state, fifo_status - init_state); + __func__, fifo_status, single_offset, total_offset); if (!is_validfs(fs_audio)) { dev_dbg(rk628->dev, "%s: no supported fs(%u), fifo_status %d\n", __func__, fs_audio, fifo_status); @@ -446,33 +533,26 @@ static void rk628_csi_delayed_work_audio_v2(struct work_struct *work) __func__, audio_state->fs_audio, fs_audio); rk628_hdmirx_audio_set_fs(aif, fs_audio); rk628_hdmirx_audio_fifo_init(aif); - audio_state->pre_state = 0; + rk628_hdmirx_audio_state_change(aif, 0); goto exit; } if (fifo_status != 0) { - if (!aif->audio_present) { - dev_info(rk628->dev, "audio on"); - aif->audio_present = true; - } - if (fifo_status - init_state > 16 && fifo_status - pre_state > 0) - rk628_hdmirx_audio_clk_inc_rate(aif, 10); - else if (fifo_status - init_state < -16 && fifo_status - pre_state < 0) - rk628_hdmirx_audio_clk_inc_rate(aif, -10); + rk628_hdmirx_audio_state_change(aif, 1); + delay = rk628_hdmirx_audio_clk_adjust(aif, total_offset, single_offset); } else { - if (aif->audio_present) { - dev_info(rk628->dev, "audio off"); - aif->audio_present = false; - } + rk628_hdmirx_audio_state_change(aif, 0); } audio_state->pre_state = fifo_status; - - rk628_i2c_read(rk628, HDMI_RX_AUD_SPARE, &sample_flat); - sample_flat = sample_flat & AUDS_MAS_SAMPLE_FLAT; - if (!sample_flat) - rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, SW_I2S_DATA_OEN_MASK, SW_I2S_DATA_OEN(0)); - else - rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, SW_I2S_DATA_OEN_MASK, SW_I2S_DATA_OEN(1)); - + if (aif->i2s_enabled) { + rk628_i2c_read(rk628, HDMI_RX_AUD_SPARE, &sample_flat); + sample_flat = !!(sample_flat & AUDS_MAS_SAMPLE_FLAT); + if (sample_flat != aif->sample_flat) { + dev_info(rk628->dev, "audio sample flat change to %d\n", sample_flat); + rk628_i2c_write(aif->rk628, HDMI_RX_AUD_SAO_CTRL, I2S_LPCM_BPCUV(0) | I2S_32_16(1) | + (sample_flat ? I2S_DATA_ENABLE_BITS(0xf) : I2S_DATA_ENABLE_BITS(0))); + aif->sample_flat = sample_flat; + } + } exit: schedule_delayed_work(&aif->delayed_work_audio, msecs_to_jiffies(delay)); } @@ -503,10 +583,19 @@ static void rk628_csi_delayed_work_audio(struct work_struct *work) rk628_i2c_read(aif->rk628, HDMI_RX_AUD_FIFO_FILLSTS1, &cur_state); dev_dbg(aif->dev, "%s: HDMI_RX_AUD_FIFO_FILLSTS1:%#x, single offset:%d, total offset:%d\n", __func__, cur_state, cur_state - pre_state, cur_state - init_state); - if (cur_state != 0) - aif->audio_present = true; - else - aif->audio_present = false; + if (cur_state != 0) { + if (!aif->audio_present) { + dev_dbg(aif->dev, "audio on\n"); + aif->audio_present = true; + rk628_hdmirx_audio_handle_plugged_change(aif, 1); + } + } else { + if (aif->audio_present) { + dev_dbg(aif->dev, "audio off\n"); + aif->audio_present = false; + rk628_hdmirx_audio_handle_plugged_change(aif, 0); + } + } if ((cur_state - init_state) > 16 && (cur_state - pre_state) > 0) rk628_hdmirx_audio_clk_inc_rate(aif, 10); @@ -545,23 +634,110 @@ static void rk628_csi_delayed_work_audio_rate_change(struct work_struct *work) if (is_validfs(fs_audio)) rk628_hdmirx_audio_set_fs(aif, fs_audio); rk628_i2c_read(aif->rk628, HDMI_RX_AUD_FIFO_FILLSTS1, &fifo_fillsts); - if (!fifo_fillsts) { + if (!fifo_fillsts) dev_dbg(aif->dev, "%s underflow after overflow\n", __func__); - rk628_hdmirx_audio_fifo_initd(aif); - } else { + else dev_dbg(aif->dev, "%s overflow after underflow\n", __func__); - rk628_hdmirx_audio_fifo_initd(aif); - } + rk628_hdmirx_audio_fifo_initd(aif); + aif->audio_present = false; + rk628_hdmirx_audio_handle_plugged_change(aif, 0); } mutex_unlock(aif->confctl_mutex); } +static int rk628_hdmirx_audio_hw_params(struct device *dev, void *data, + struct hdmi_codec_daifmt *daifmt, + struct hdmi_codec_params *params) +{ + dev_dbg(dev, "%s\n", __func__); + return 0; +} + +static int rk628_hdmirx_audio_startup(struct device *dev, void *data) +{ + struct rk628_audioinfo *aif = (struct rk628_audioinfo *)data; + + dev_info(dev, "%s: %d\n", __func__, aif->audio_present); + if (aif->audio_present) + return 0; + dev_err(dev, "%s: device is no connected\n", __func__); + return -ENODEV; +} + +static void rk628_hdmirx_audio_shutdown(struct device *dev, void *data) +{ + dev_dbg(dev, "%s\n", __func__); +} + +static int rk628_hdmirx_audio_get_dai_id(struct snd_soc_component *comment, + struct device_node *endpoint) +{ + dev_dbg(comment->dev, "%s\n", __func__); + return 0; +} + +void rk628_hdmirx_audio_handle_plugged_change(HAUDINFO info, bool plugged) +{ + struct rk628_audioinfo *aif = (struct rk628_audioinfo *)info; + + if (aif->plugged_cb && aif->codec_dev) + aif->plugged_cb(aif->codec_dev, plugged); + if (aif->info_cb) + aif->info_cb(aif->rk628, plugged); +} + +static int rk628_hdmirx_audio_hook_plugged_cb(struct device *dev, void *data, + hdmi_codec_plugged_cb fn, + struct device *codec_dev) +{ + struct rk628_audioinfo *aif = (struct rk628_audioinfo *)data; + + dev_dbg(dev, "%s\n", __func__); + if (aif->confctl_mutex) + mutex_lock(aif->confctl_mutex); + aif->plugged_cb = fn; + aif->codec_dev = codec_dev; + rk628_hdmirx_audio_handle_plugged_change(aif, aif->audio_present); + if (aif->confctl_mutex) + mutex_unlock(aif->confctl_mutex); + return 0; +} + +static const struct hdmi_codec_ops rk628_hdmirx_audio_codec_ops = { + .hw_params = rk628_hdmirx_audio_hw_params, + .audio_startup = rk628_hdmirx_audio_startup, + .audio_shutdown = rk628_hdmirx_audio_shutdown, + .get_dai_id = rk628_hdmirx_audio_get_dai_id, + .hook_plugged_cb = rk628_hdmirx_audio_hook_plugged_cb +}; + +static int rk628_hdmirx_register_audio_device(struct rk628_audioinfo *aif) +{ + struct hdmi_codec_pdata codec_data = { + .ops = &rk628_hdmirx_audio_codec_ops, + .spdif = 1, + .i2s = 1, + .max_i2s_channels = 8, + .data = aif, + }; + + aif->pdev = platform_device_register_data(aif->dev, + HDMI_CODEC_DRV_NAME, + PLATFORM_DEVID_AUTO, + &codec_data, + sizeof(codec_data)); + + return PTR_ERR_OR_ZERO(aif->pdev); +} + HAUDINFO rk628_hdmirx_audioinfo_alloc(struct device *dev, struct mutex *confctl_mutex, struct rk628 *rk628, - bool en) + bool en, + rk628_audio_info_cb info_cb) { struct rk628_audioinfo *aif; + int ret; aif = devm_kzalloc(dev, sizeof(*aif), GFP_KERNEL); if (!aif) @@ -577,6 +753,13 @@ HAUDINFO rk628_hdmirx_audioinfo_alloc(struct device *dev, aif->rk628 = rk628; aif->i2s_enabled_default = en; aif->dev = dev; + aif->audio_present = false; + aif->info_cb = info_cb; + ret = rk628_hdmirx_register_audio_device(aif); + if (ret) { + dev_err(dev, "register audio_driver failed!\n"); + return NULL; + } return aif; } EXPORT_SYMBOL(rk628_hdmirx_audioinfo_alloc); @@ -614,6 +797,8 @@ void rk628_hdmirx_audio_destroy(HAUDINFO info) rk628_hdmirx_audio_cancel_work_audio(aif, true); if (rk628->version < RK628F_VERSION) rk628_hdmirx_audio_cancel_work_rate_change(aif, true); + if (aif->pdev) + platform_device_unregister(aif->pdev); aif->confctl_mutex = NULL; aif->rk628 = NULL; } @@ -639,21 +824,42 @@ int rk628_hdmirx_audio_fs(HAUDINFO info) } EXPORT_SYMBOL(rk628_hdmirx_audio_fs); +bool rk628_hdmirx_get_arc_enable(HAUDINFO info) +{ + struct rk628_audioinfo *aif = (struct rk628_audioinfo *)info; + + if (!aif) + return false; + + return aif->arc_en; +} +EXPORT_SYMBOL(rk628_hdmirx_get_arc_enable); + +int rk628_hdmirx_set_arc_enable(HAUDINFO info, bool enabled) +{ + struct rk628_audioinfo *aif = (struct rk628_audioinfo *)info; + + if (!aif) + return false; + + return aif->arc_en = enabled; +} +EXPORT_SYMBOL(rk628_hdmirx_set_arc_enable); + void rk628_hdmirx_audio_i2s_ctrl(HAUDINFO info, bool enable) { struct rk628_audioinfo *aif = (struct rk628_audioinfo *)info; - if (enable == aif->i2s_enabled) + if (enable == aif->i2s_enabled || aif->i2s_enabled_default) return; - if (enable) { + if (enable && !aif->sample_flat) { rk628_i2c_write(aif->rk628, HDMI_RX_AUD_SAO_CTRL, - I2S_LPCM_BPCUV(0) | - I2S_32_16(1)); + I2S_LPCM_BPCUV(0) | I2S_32_16(1) | + I2S_DATA_ENABLE_BITS(0)); } else { rk628_i2c_write(aif->rk628, HDMI_RX_AUD_SAO_CTRL, - I2S_LPCM_BPCUV(0) | - I2S_32_16(1) | - I2S_ENABLE_BITS(0x3f)); + I2S_LPCM_BPCUV(0) | I2S_32_16(1) | + I2S_DATA_ENABLE_BITS(0xf)); } aif->i2s_enabled = enable; } @@ -674,14 +880,19 @@ void rk628_hdmirx_audio_setup(HAUDINFO info) aif->audio_state.init_state = INIT_FIFO_STATE*4; aif->audio_state.fifo_int = false; aif->audio_state.audio_enable = false; + aif->sample_flat = false; aif->fifo_ints_en = false; aif->ctsn_ints_en = false; aif->i2s_enabled = false; + aif->underflow = false; + aif->overflow = false; + aif->startthreshold = false; + aif->stablelimit = 0; if (rk628->version >= RK628F_VERSION) rk628_i2c_write(rk628, CRU_MODE_CON00, HIWORD_UPDATE(1, 4, 4)); - rk628_hdmirx_audio_clk_set_rate(aif, 5644800); + rk628_hdmirx_audio_clk_set_rate(aif, DEFAULT_AUDIO_CLK); /* manual aud CTS */ rk628_i2c_write(aif->rk628, HDMI_RX_AUDPLL_GEN_CTS, audio_pll_cts); /* manual aud N */ @@ -697,8 +908,8 @@ void rk628_hdmirx_audio_setup(HAUDINFO info) AFIF_TH_START_MASK | AFIF_TH_MAX_MASK | AFIF_TH_MIN_MASK, - AFIF_TH_START(64) | - AFIF_TH_MAX(8) | + AFIF_TH_START(INIT_FIFO_STATE) | + AFIF_TH_MAX(INIT_FIFO_STATE*2) | AFIF_TH_MIN(8)); /* AUTO_VMUTE */ @@ -709,8 +920,8 @@ void rk628_hdmirx_audio_setup(HAUDINFO info) AFIF_SUBPACKETS(1)); rk628_i2c_write(aif->rk628, HDMI_RX_AUD_SAO_CTRL, I2S_LPCM_BPCUV(0) | - I2S_32_16(1)| - (aif->i2s_enabled_default ? 0 : I2S_ENABLE_BITS(0x3f))); + I2S_32_16(1) | + (aif->i2s_enabled_default ? 0 : I2S_DATA_ENABLE_BITS(0xf))); aif->i2s_enabled = aif->i2s_enabled_default; rk628_i2c_write(aif->rk628, HDMI_RX_AUD_MUTE_CTRL, APPLY_INT_MUTE(0) | @@ -726,8 +937,6 @@ void rk628_hdmirx_audio_setup(HAUDINFO info) rk628_i2c_write(aif->rk628, HDMI_RX_AUD_CHEXTR_CTRL, AUD_LAYOUT_CTRL(1)); if (rk628->version >= RK628F_VERSION) { - rk628_i2c_update_bits(aif->rk628, HDMI_RX_DMI_DISABLE_IF, - AUD_ENABLE_MASK, AUD_ENABLE(1)); schedule_delayed_work(&aif->delayed_work_audio, msecs_to_jiffies(1000)); } else { aif->ctsn_ints_en = true; @@ -1027,6 +1236,17 @@ void rk628_hdmirx_cec_irq(struct rk628 *rk628, struct rk628_hdmirx_cec *cec) } EXPORT_SYMBOL(rk628_hdmirx_cec_irq); +static void rk628_delayed_work_cec(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct rk628_hdmirx_cec *cec = container_of(dwork, struct rk628_hdmirx_cec, + delayed_work_cec); + bool en = rk628_hdmirx_tx_5v_power_detect(cec->rk628->hdmirx_det_gpio); + + cec->cec_hpd = en; + cec_queue_pin_hpd_event(cec->adap, en, ktime_get()); +} + struct rk628_hdmirx_cec *rk628_hdmirx_cec_register(struct rk628 *rk628) { struct rk628_hdmirx_cec *cec; @@ -1068,6 +1288,8 @@ struct rk628_hdmirx_cec *rk628_hdmirx_cec_register(struct rk628 *rk628) /* override the module pointer */ cec->adap->owner = THIS_MODULE; + INIT_DELAYED_WORK(&cec->delayed_work_cec, rk628_delayed_work_cec); + ret = devm_add_action(cec->dev, rk628_hdmirx_cec_del, cec); if (ret) { cec_delete_adapter(cec->adap); @@ -1102,6 +1324,8 @@ struct rk628_hdmirx_cec *rk628_hdmirx_cec_register(struct rk628 *rk628) */ devm_remove_action(cec->dev, rk628_hdmirx_cec_del, cec); + schedule_delayed_work(&cec->delayed_work_cec, msecs_to_jiffies(10000)); + return cec; } EXPORT_SYMBOL(rk628_hdmirx_cec_register); @@ -1121,7 +1345,11 @@ void rk628_hdmirx_cec_hpd(struct rk628_hdmirx_cec *cec, bool en) if (!cec || !cec->adap) return; - cec_queue_pin_hpd_event(cec->adap, en, ktime_get()); + rk628_dbg(cec->rk628, "%s: cec_hpd:%d, en:%d\n", __func__, cec->cec_hpd, en); + if (cec->cec_hpd != en) { + cec->cec_hpd = en; + cec_queue_pin_hpd_event(cec->adap, en, ktime_get()); + } } EXPORT_SYMBOL(rk628_hdmirx_cec_hpd); @@ -1131,6 +1359,9 @@ void rk628_hdmirx_cec_state_reconfiguration(struct rk628 *rk628, unsigned int irqs; u32 val; + /* clk_hdmirx_cec = 32.768k */ + rk628_clk_set_rate(rk628, CGU_CLK_HDMIRX_CEC, 32768); + rk628_i2c_write(rk628, HDMI_RX_CEC_ADDR_L, cec->addresses & 0xff); rk628_i2c_write(rk628, HDMI_RX_CEC_ADDR_H, (cec->addresses >> 8) & 0xff); diff --git a/drivers/media/i2c/rk628/rk628_hdmirx.h b/drivers/media/i2c/rk628/rk628_hdmirx.h index 1f0a302a75a8..ed5c4c05ac01 100644 --- a/drivers/media/i2c/rk628/rk628_hdmirx.h +++ b/drivers/media/i2c/rk628/rk628_hdmirx.h @@ -188,6 +188,8 @@ #define HDMI_RX_AUD_SAO_CTRL (HDMI_RX_BASE + 0x0260) #define I2S_ENABLE_BITS_MASK GENMASK(10, 5) #define I2S_ENABLE_BITS(x) UPDATE(x, 10, 5) +#define I2S_CLK_ENABLE_BITS(x) UPDATE(x, 10, 9) +#define I2S_DATA_ENABLE_BITS(x) UPDATE(x, 8, 5) #define I2S_LPCM_BPCUV_MASK BIT(11) #define I2S_LPCM_BPCUV(x) UPDATE(x, 11, 11) #define I2S_32_16_MASK BIT(0) @@ -486,17 +488,21 @@ struct rk628_hdmirx_cec { unsigned int tx_status; bool tx_done; bool rx_done; + bool cec_hpd; struct cec_notifier *notify; + struct delayed_work delayed_work_cec; }; void rk628_hdmirx_set_hdcp(struct rk628 *rk628, struct rk628_hdcp *hdcp, bool en); void rk628_hdmirx_controller_setup(struct rk628 *rk628); typedef void *HAUDINFO; +typedef void (*rk628_audio_info_cb)(struct rk628 *rk628, bool on); HAUDINFO rk628_hdmirx_audioinfo_alloc(struct device *dev, struct mutex *confctl_mutex, struct rk628 *rk628, - bool en); + bool en, + rk628_audio_info_cb info_cb); void rk628_hdmirx_audio_destroy(HAUDINFO info); void rk628_hdmirx_audio_setup(HAUDINFO info); void rk628_hdmirx_audio_cancel_work_audio(HAUDINFO info, bool sync); @@ -504,6 +510,9 @@ void rk628_hdmirx_audio_cancel_work_rate_change(HAUDINFO info, bool sync); bool rk628_hdmirx_audio_present(HAUDINFO info); int rk628_hdmirx_audio_fs(HAUDINFO info); void rk628_hdmirx_audio_i2s_ctrl(HAUDINFO info, bool enable); +bool rk628_hdmirx_get_arc_enable(HAUDINFO info); +int rk628_hdmirx_set_arc_enable(HAUDINFO info, bool enabled); +void rk628_hdmirx_audio_handle_plugged_change(HAUDINFO info, bool plugged); /* for audio isr process */ bool rk628_audio_fifoints_enabled(HAUDINFO info); diff --git a/drivers/soc/rockchip/rockchip_csu.c b/drivers/soc/rockchip/rockchip_csu.c index 04a6a5b39715..a042b59bcc22 100644 --- a/drivers/soc/rockchip/rockchip_csu.c +++ b/drivers/soc/rockchip/rockchip_csu.c @@ -36,6 +36,21 @@ struct rockchip_csu { static struct rockchip_csu *rk_csu; static DEFINE_MUTEX(csu_lock); +static struct csu_bus *rockchip_csu_get_bus(unsigned int bus_id) +{ + int i; + + if (!rk_csu || !rk_csu->bus) + return NULL; + + for (i = 0; i < rk_csu->bus_cnt; i++) { + if (bus_id == rk_csu->bus[i].id) + return &rk_csu->bus[i]; + } + + return NULL; +} + static int rockchip_csu_sip_config(struct device *dev, u32 bus_id, u32 cfg, u32 enable_msk) { @@ -91,7 +106,7 @@ static int csu_disable(struct csu_clk *clk, bool disable) return 0; if (clk->bus_id >= rk_csu->bus_cnt) return 0; - bus = &rk_csu->bus[clk->bus_id]; + bus = rockchip_csu_get_bus(clk->bus_id); if (!bus) return 0; @@ -138,7 +153,7 @@ int rockchip_csu_set_div(struct csu_clk *clk, unsigned int div) return 0; if (clk->bus_id >= rk_csu->bus_cnt) return 0; - bus = &rk_csu->bus[clk->bus_id]; + bus = rockchip_csu_get_bus(clk->bus_id); if (!bus) return 0; diff --git a/drivers/video/rockchip/mpp/mpp_rkvdec2.c b/drivers/video/rockchip/mpp/mpp_rkvdec2.c index 1d8eae761489..f94b23e2401b 100644 --- a/drivers/video/rockchip/mpp/mpp_rkvdec2.c +++ b/drivers/video/rockchip/mpp/mpp_rkvdec2.c @@ -588,6 +588,7 @@ static int rkvdec2_isr(struct mpp_dev *mpp) struct rkvdec2_task *task = NULL; struct mpp_task *mpp_task = mpp->cur_task; struct rkvdec2_dev *dec = to_rkvdec2_dev(mpp); + struct rkvdec_link_info *link_info = mpp->var->hw_info->link_info; /* FIXME use a spin lock here */ if (!mpp_task) { @@ -601,8 +602,7 @@ static int rkvdec2_isr(struct mpp_dev *mpp) task->irq_status = mpp->irq_status; mpp_debug(DEBUG_IRQ_STATUS, "irq_status: %08x\n", task->irq_status); - err_mask = RKVDEC_COLMV_REF_ERR_STA | RKVDEC_BUF_EMPTY_STA | - RKVDEC_TIMEOUT_STA | RKVDEC_ERROR_STA; + err_mask = link_info->err_mask; if (err_mask & task->irq_status) { atomic_inc(&mpp->reset_request); if (mpp_debug_unlikely(DEBUG_DUMP_ERR_REG)) { diff --git a/drivers/video/rockchip/mpp/mpp_rkvdec2.h b/drivers/video/rockchip/mpp/mpp_rkvdec2.h index 90a795b39e84..1f91290ba604 100644 --- a/drivers/video/rockchip/mpp/mpp_rkvdec2.h +++ b/drivers/video/rockchip/mpp/mpp_rkvdec2.h @@ -67,10 +67,6 @@ #define RKVDEC_READY_STA BIT(2) #define RKVDEC_IRQ_RAW BIT(1) #define RKVDEC_IRQ BIT(0) -#define RKVDEC_INT_ERROR_MASK (RKVDEC_COLMV_REF_ERR_STA |\ - RKVDEC_BUF_EMPTY_STA |\ - RKVDEC_TIMEOUT_STA |\ - RKVDEC_ERROR_STA) #define RKVDEC_PERF_WORKING_CNT 0x41c /* perf sel reference register */ diff --git a/drivers/video/rockchip/mpp/mpp_rkvdec2_link.c b/drivers/video/rockchip/mpp/mpp_rkvdec2_link.c index 708708e7f350..2d154bab1bb4 100644 --- a/drivers/video/rockchip/mpp/mpp_rkvdec2_link.c +++ b/drivers/video/rockchip/mpp/mpp_rkvdec2_link.c @@ -79,6 +79,7 @@ struct rkvdec_link_info rkvdec_link_v2_hw_info = { }, .irq_base = 0x00, .next_addr_base = 0x1c, + .err_mask = 0xf0, }; /* vdpu34x link hw info for rk356x */ @@ -140,6 +141,7 @@ struct rkvdec_link_info rkvdec_link_rk356x_hw_info = { }, .irq_base = 0x00, .next_addr_base = 0x1c, + .err_mask = 0xf0, }; /* vdpu382 link hw info */ @@ -201,6 +203,7 @@ struct rkvdec_link_info rkvdec_link_vdpu382_hw_info = { }, .irq_base = 0x00, .next_addr_base = 0x1c, + .err_mask = 0xf0, }; /* vdpu383 link hw info */ @@ -1102,7 +1105,7 @@ static void rkvdec2_link_try_dequeue(struct mpp_dev *mpp) mpp_task->session->index, mpp_task->task_index, irq_status, timeout_flag, abort_flag); - if (irq_status & RKVDEC_INT_ERROR_MASK) { + if (irq_status & info->err_mask) { dev_err(mpp->dev, "session %d task %d irq_status %#08x timeout %u abort %u\n", mpp_task->session->index, mpp_task->task_index, @@ -1851,10 +1854,11 @@ irqreturn_t rkvdec2_soft_ccu_irq(int irq, void *param) { struct mpp_dev *mpp = param; u32 irq_status = mpp_read_relaxed(mpp, RKVDEC_REG_INT_EN); + struct rkvdec_link_info *link_info = mpp->var->hw_info->link_info; if (irq_status & RKVDEC_IRQ_RAW) { mpp_debug(DEBUG_IRQ_STATUS, "irq_status=%08x\n", irq_status); - if (irq_status & RKVDEC_INT_ERROR_MASK) { + if (irq_status & link_info->err_mask) { atomic_inc(&mpp->reset_request); atomic_inc(&mpp->queue->reset_request); } @@ -2214,7 +2218,7 @@ static int rkvdec2_hard_ccu_dequeue(struct mpp_taskqueue *queue, mpp_debug(DEBUG_IRQ_CHECK, "session %d task %d w:h[%d %d] err %d irq_status %#x timeout=%u abort=%u iova %08x next %08x ccu[%d %d]\n", mpp_task->session->index, mpp_task->task_index, task->width, - task->height, !!(irq_status & RKVDEC_INT_ERROR_MASK), irq_status, + task->height, !!(irq_status & hw->err_mask), irq_status, timeout_flag, abort_flag, (u32)task->table->iova, ((u32 *)task->table->vaddr)[hw->tb_reg_next], ccu_decoded_num, ccu_total_dec_num); @@ -2251,7 +2255,7 @@ static int rkvdec2_hard_ccu_dequeue(struct mpp_taskqueue *queue, list_del_init(&mpp_task->queue_link); /* Wake up the GET thread */ wake_up(&mpp_task->wait); - if ((irq_status & RKVDEC_INT_ERROR_MASK) || timeout_flag) { + if ((irq_status & hw->err_mask) || timeout_flag) { pr_err("session %d task %d irq_status %#x timeout=%u abort=%u\n", mpp_task->session->index, mpp_task->task_index, irq_status, timeout_flag, abort_flag);