From dbf24e0936ee5e9bca0777ef5bdff719873a31fd Mon Sep 17 00:00:00 2001 From: Evoke Zhang Date: Tue, 2 Jan 2018 11:27:09 +0800 Subject: [PATCH] vout_serve: add vout, vout2 support for g12a PD#156734: vout_serve: add vout, vout2 support for g12a Change-Id: I1cb45beca5325f9013901687d7d995bfb9a25766 Signed-off-by: Evoke Zhang --- MAINTAINERS | 16 + arch/arm64/boot/dts/amlogic/g12a_pxp.dts | 12 + arch/arm64/configs/meson64_defconfig | 1 + .../media/enhancement/amvecm/amdolby_vision.c | 46 +- drivers/amlogic/media/video_sink/video.c | 20 +- drivers/amlogic/media/vout/cvbs/cvbs_out.c | 62 +- .../media/vout/hdmitx/hdmi_tx_20/hdmi_tx_main.c | 55 +- drivers/amlogic/media/vout/lcd/lcd_common.h | 2 - .../amlogic/media/vout/lcd/lcd_tablet/lcd_tablet.c | 88 ++- drivers/amlogic/media/vout/lcd/lcd_tv/lcd_tv.c | 31 +- drivers/amlogic/media/vout/lcd/lcd_vout.c | 24 +- drivers/amlogic/media/vout/vout_serve/Kconfig | 7 + drivers/amlogic/media/vout/vout_serve/Makefile | 3 +- .../amlogic/media/vout/vout_serve/vout2_notify.c | 214 ++++++ .../amlogic/media/vout/vout_serve/vout2_serve.c | 821 +++++++++++++++++++++ drivers/amlogic/media/vout/vout_serve/vout_func.c | 549 ++++++++++++++ drivers/amlogic/media/vout/vout_serve/vout_func.h | 83 +++ .../amlogic/media/vout/vout_serve/vout_notify.c | 359 ++------- drivers/amlogic/media/vout/vout_serve/vout_serve.c | 148 +++- drivers/amlogic/media/vout/vout_serve/vout_serve.h | 27 - include/linux/amlogic/media/video_sink/video.h | 2 - include/linux/amlogic/media/vout/lcd/lcd_vout.h | 4 + include/linux/amlogic/media/vout/vinfo.h | 4 +- include/linux/amlogic/media/vout/vout_notify.h | 34 +- 24 files changed, 2146 insertions(+), 466 deletions(-) create mode 100644 drivers/amlogic/media/vout/vout_serve/vout2_notify.c create mode 100644 drivers/amlogic/media/vout/vout_serve/vout2_serve.c create mode 100644 drivers/amlogic/media/vout/vout_serve/vout_func.c create mode 100644 drivers/amlogic/media/vout/vout_serve/vout_func.h delete mode 100644 drivers/amlogic/media/vout/vout_serve/vout_serve.h diff --git a/MAINTAINERS b/MAINTAINERS index 33b8d8d..4a8a16b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14285,3 +14285,19 @@ M: Qiufang Dai F: drivers/amlogic/clk/g12a/g12a_clk_gpu.c F: drivers/amlogic/clk/g12a/g12a_clk_media.c +AMLOGIC VOUT_SERVE +M: Evoke Zhang +F: drivers/amlogic/media/vout/vout_serve/vout2_notify.c +F: drivers/amlogic/media/vout/vout_serve/vout2_serve.c +F: drivers/amlogic/media/vout/vout_serve/vout_func.c +F: drivers/amlogic/media/vout/vout_serve/vout_func.h + +AMLOGIC GPIO IRQ +M: Xingyu Chen +F: drivers/amlogic/irqchip/* +F: Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt + +AMLOGIC PINCTRL DRIVER +M: Xingyu Chen +F: drivers/amlogic/pinctrl/* +F: include/dt-bindings/gpio/* diff --git a/arch/arm64/boot/dts/amlogic/g12a_pxp.dts b/arch/arm64/boot/dts/amlogic/g12a_pxp.dts index 5e0ed41..953e9a2 100644 --- a/arch/arm64/boot/dts/amlogic/g12a_pxp.dts +++ b/arch/arm64/boot/dts/amlogic/g12a_pxp.dts @@ -56,6 +56,18 @@ }; }; + vout { + compatible = "amlogic, vout"; + dev_name = "vout"; + status = "okay"; + }; + + vout2 { + compatible = "amlogic, vout2"; + dev_name = "vout"; + status = "okay"; + }; + }; /* end of / */ &aobus{ diff --git a/arch/arm64/configs/meson64_defconfig b/arch/arm64/configs/meson64_defconfig index 755f8fb..d7449e4 100644 --- a/arch/arm64/configs/meson64_defconfig +++ b/arch/arm64/configs/meson64_defconfig @@ -279,6 +279,7 @@ CONFIG_AMLOGIC_BL_EXTERN_I2C_LP8556=y CONFIG_AMLOGIC_BL_EXTERN_MIPI_LT070ME05=y CONFIG_AMLOGIC_LOCAL_DIMMING=y CONFIG_AMLOGIC_VOUT_SERVE=y +CONFIG_AMLOGIC_VOUT2_SERVE=y CONFIG_AMLOGIC_MEDIA_FB=y CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE=y CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA=y diff --git a/drivers/amlogic/media/enhancement/amvecm/amdolby_vision.c b/drivers/amlogic/media/enhancement/amvecm/amdolby_vision.c index f7ebfb1..7f28d2b 100644 --- a/drivers/amlogic/media/enhancement/amvecm/amdolby_vision.c +++ b/drivers/amlogic/media/enhancement/amvecm/amdolby_vision.c @@ -1390,6 +1390,25 @@ void prepare_hdr10_param( } } +static inline void fresh_tx_hdr_pkt(struct vout_device_s *vdev) +{ + if (vdev) { + if (vdev->fresh_tx_hdr_pkt) + vdev->fresh_tx_hdr_pkt(&hdr10_data); + } +} + +static inline void fresh_tx_vsif_pkt(struct vout_device_s *vdev, + int dv_en, int dv_mode) +{ + int tmp = (dv_mode == DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL ? 1 : 0); + + if (vdev) { + if (vdev->fresh_tx_vsif_pkt) + vdev->fresh_tx_vsif_pkt(dv_en, tmp); + } +} + static bool send_hdmi_pkt( enum signal_format_e dst_format, const struct vinfo_s *vinfo) @@ -1507,12 +1526,8 @@ static bool send_hdmi_pkt( hdr10_data.max_frame_average = (p_hdr->max_frame_average_light_level_MSB << 8) | p_hdr->max_frame_average_light_level_LSB; - if (vdev) { - if (vdev->fresh_tx_hdr_pkt) - vdev->fresh_tx_hdr_pkt(&hdr10_data); - if (vdev->fresh_tx_vsif_pkt) - vdev->fresh_tx_vsif_pkt(0, 0); - } + fresh_tx_hdr_pkt(vdev); + fresh_tx_vsif_pkt(vdev, 0, 0); if (flag) { pr_dolby_dbg("Info frame for hdr10 changed:\n"); @@ -1553,15 +1568,8 @@ static bool send_hdmi_pkt( hdr10_data.luminance[1] = 0; hdr10_data.max_content = 0; hdr10_data.max_frame_average = 0; - if (vdev) { - if (vdev->fresh_tx_hdr_pkt) - vdev->fresh_tx_hdr_pkt(&hdr10_data); - if (vdev->fresh_tx_vsif_pkt) - vdev->fresh_tx_vsif_pkt( - 1, dolby_vision_mode == - DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL - ? 1 : 0); - } + fresh_tx_hdr_pkt(vdev); + fresh_tx_vsif_pkt(vdev, 1, dolby_vision_mode); } else { hdr10_data.features = (1 << 29) /* video available */ @@ -1581,12 +1589,8 @@ static bool send_hdmi_pkt( hdr10_data.luminance[1] = 0; hdr10_data.max_content = 0; hdr10_data.max_frame_average = 0; - if (vdev) { - if (vdev->fresh_tx_hdr_pkt) - vdev->fresh_tx_hdr_pkt(&hdr10_data); - if (vdev->fresh_tx_vsif_pkt) - vdev->fresh_tx_vsif_pkt(0, 0); - } + fresh_tx_hdr_pkt(vdev); + fresh_tx_vsif_pkt(vdev, 0, 0); } return flag; } diff --git a/drivers/amlogic/media/video_sink/video.c b/drivers/amlogic/media/video_sink/video.c index 1f5fcfb..703b2d5 100644 --- a/drivers/amlogic/media/video_sink/video.c +++ b/drivers/amlogic/media/video_sink/video.c @@ -8908,7 +8908,7 @@ static int __init video_early_init(void) /*(3<<9) | (1<<8) | (0)); // fclk_div7/1 = 364M*/ /*moved to vpu.c, default config by dts */ - if (/*get_logo_vmode()*/0 >= VMODE_MAX) {/*DEBUG_TMP*/ +#if 0 /* if (0 >= VMODE_MAX) //DEBUG_TMP */ #if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */ if (cpu_after_eq(MESON_CPU_MAJOR_ID_GXTVBB)) WRITE_VCBUS_REG_BITS(VPP_OFIFO_SIZE, 0xfff, @@ -8921,11 +8921,12 @@ static int __init video_early_init(void) VPP_OFIFO_SIZE_WID); #endif #endif /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */ - } else { +#else if (cpu_after_eq(MESON_CPU_MAJOR_ID_GXTVBB)) WRITE_VCBUS_REG_BITS(VPP_OFIFO_SIZE, 0xfff, VPP_OFIFO_SIZE_BIT, VPP_OFIFO_SIZE_WID); - } +#endif + #if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */ WRITE_VCBUS_REG(VPP_PREBLEND_VD1_H_START_END, 4096); WRITE_VCBUS_REG(VPP_BLEND_VD2_H_START_END, 4096); @@ -8940,23 +8941,20 @@ static int __init video_early_init(void) if (is_meson_gxbb_cpu()) SET_VCBUS_REG_MASK(VPP_MISC, VPP_OUT_SATURATE); - if (/*get_logo_vmode()*/0 >= VMODE_MAX) {/*DEBUG_TMP*/ +#if 0 /* if (0 >= VMODE_MAX) //DEBUG_TMP */ CLEAR_VCBUS_REG_MASK(VPP_VSC_PHASE_CTRL, VPP_PHASECTL_TYPE_INTERLACE); -#ifndef CONFIG_FB_AML_TCON SET_VCBUS_REG_MASK(VPP_MISC, VPP_OUT_SATURATE); -#endif WRITE_VCBUS_REG(VPP_HOLD_LINES + cur_dev->vpp_off, 0x08080808); - } +#endif + #ifdef CONFIG_SUPPORT_VIDEO_ON_VPP2 - if (/*get_logo_vmode()*/0 >= VMODE_MAX) {/*DEBUG_TMP*/ +#if 0 /* if (0 >= VMODE_MAX) //DEBUG_TMP */ CLEAR_VCBUS_REG_MASK(VPP2_VSC_PHASE_CTRL, VPP_PHASECTL_TYPE_INTERLACE); -#ifndef CONFIG_FB_AML_TCON SET_VCBUS_REG_MASK(VPP2_MISC, VPP_OUT_SATURATE); -#endif WRITE_VCBUS_REG(VPP2_HOLD_LINES, 0x08080808); - } +#endif #if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */ WRITE_VCBUS_REG_BITS(VPP2_OFIFO_SIZE, 0x800, VPP_OFIFO_SIZE_BIT, VPP_OFIFO_SIZE_WID); diff --git a/drivers/amlogic/media/vout/cvbs/cvbs_out.c b/drivers/amlogic/media/vout/cvbs/cvbs_out.c index 47fe2f4..b125c1e 100644 --- a/drivers/amlogic/media/vout/cvbs/cvbs_out.c +++ b/drivers/amlogic/media/vout/cvbs/cvbs_out.c @@ -583,6 +583,24 @@ static int cvbs_module_disable(enum vmode_e cur_vmod) return 0; } +static int cvbs_vout_state; +static int cvbs_vout_set_state(int index) +{ + cvbs_vout_state |= (1 << index); + return 0; +} + +static int cvbs_vout_clr_state(int index) +{ + cvbs_vout_state &= ~(1 << index); + return 0; +} + +static int cvbs_vout_get_state(void) +{ + return cvbs_vout_state; +} + #ifdef CONFIG_PM static int cvbs_suspend(void) { @@ -602,14 +620,40 @@ static int cvbs_resume(void) } #endif -static struct vout_server_s cvbs_server = { - .name = "vout_cvbs_server", +static struct vout_server_s cvbs_vout_server = { + .name = "cvbs_vout_server", + .op = { + .get_vinfo = cvbs_get_current_info, + .set_vmode = cvbs_set_current_vmode, + .validate_vmode = cvbs_validate_vmode, + .vmode_is_supported = cvbs_vmode_is_supported, + .disable = cvbs_module_disable, + .set_state = cvbs_vout_set_state, + .clr_state = cvbs_vout_clr_state, + .get_state = cvbs_vout_get_state, + .set_vframe_rate_hint = NULL, + .set_vframe_rate_end_hint = NULL, + .set_vframe_rate_policy = NULL, + .get_vframe_rate_policy = NULL, +#ifdef CONFIG_PM + .vout_suspend = cvbs_suspend, + .vout_resume = cvbs_resume, +#endif + }, +}; + +#ifdef CONFIG_AMLOGIC_VOUT2_SERVE +static struct vout_server_s cvbs_vout2_server = { + .name = "cvbs_vout2_server", .op = { .get_vinfo = cvbs_get_current_info, .set_vmode = cvbs_set_current_vmode, .validate_vmode = cvbs_validate_vmode, .vmode_is_supported = cvbs_vmode_is_supported, .disable = cvbs_module_disable, + .set_state = cvbs_vout_set_state, + .clr_state = cvbs_vout_clr_state, + .get_state = cvbs_vout_get_state, .set_vframe_rate_hint = NULL, .set_vframe_rate_end_hint = NULL, .set_vframe_rate_policy = NULL, @@ -620,16 +664,23 @@ static struct vout_server_s cvbs_server = { #endif }, }; +#endif static void cvbs_init_vout(void) { if (info->vinfo == NULL) info->vinfo = &cvbs_info[MODE_480CVBS]; - if (vout_register_server(&cvbs_server)) + if (vout_register_server(&cvbs_vout_server)) cvbs_log_err("register cvbs module server fail\n"); else cvbs_log_info("register cvbs module server ok\n"); +#ifdef CONFIG_AMLOGIC_VOUT2_SERVE + if (vout2_register_server(&cvbs_vout2_server)) + cvbs_log_err("register cvbs module vout2 server fail\n"); + else + cvbs_log_info("register cvbs module vout2 server ok\n"); +#endif } /* **************************************************** */ @@ -1292,7 +1343,10 @@ static int cvbsout_remove(struct platform_device *pdev) cdev_del(info->cdev); kfree(info); } - vout_unregister_server(&cvbs_server); + vout_unregister_server(&cvbs_vout_server); +#ifdef CONFIG_AMLOGIC_VOUT2_SERVE + vout2_unregister_server(&cvbs_vout2_server); +#endif cvbs_log_info("%s\n", __func__); return 0; } diff --git a/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_main.c b/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_main.c index 2937c13..6225cca 100644 --- a/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_main.c +++ b/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_main.c @@ -2447,14 +2447,35 @@ static int hdmitx_module_disable(enum vmode_e cur_vmod) return 0; } -static struct vout_server_s hdmitx_server = { - .name = "vout_hdmitx_server", +static int hdmitx_vout_state; +static int hdmitx_vout_set_state(int index) +{ + hdmitx_vout_state |= (1 << index); + return 0; +} + +static int hdmitx_vout_clr_state(int index) +{ + hdmitx_vout_state &= ~(1 << index); + return 0; +} + +static int hdmitx_vout_get_state(void) +{ + return hdmitx_vout_state; +} + +static struct vout_server_s hdmitx_vout_server = { + .name = "hdmitx_vout_server", .op = { .get_vinfo = hdmitx_get_current_vinfo, .set_vmode = hdmitx_set_current_vmode, .validate_vmode = hdmitx_validate_vmode, .vmode_is_supported = hdmitx_vmode_is_supported, .disable = hdmitx_module_disable, + .set_state = hdmitx_vout_set_state, + .clr_state = hdmitx_vout_clr_state, + .get_state = hdmitx_vout_get_state, #ifdef CONFIG_PM .vout_suspend = NULL, .vout_resume = NULL, @@ -2462,6 +2483,26 @@ static struct vout_server_s hdmitx_server = { }, }; +#ifdef CONFIG_AMLOGIC_VOUT2_SERVE +static struct vout_server_s hdmitx_vout2_server = { + .name = "hdmitx_vout2_server", + .op = { + .get_vinfo = hdmitx_get_current_vinfo, + .set_vmode = hdmitx_set_current_vmode, + .validate_vmode = hdmitx_validate_vmode, + .vmode_is_supported = hdmitx_vmode_is_supported, + .disable = hdmitx_module_disable, + .set_state = hdmitx_vout_set_state, + .clr_state = hdmitx_vout_clr_state, + .get_state = hdmitx_vout_get_state, +#ifdef CONFIG_PM + .vout_suspend = NULL, + .vout_resume = NULL, +#endif + }, +}; +#endif + #include #include @@ -3357,7 +3398,10 @@ static int amhdmitx_probe(struct platform_device *pdev) hdmitx_device.nb.notifier_call = hdmitx_reboot_notifier; register_reboot_notifier(&hdmitx_device.nb); - vout_register_server(&hdmitx_server); + vout_register_server(&hdmitx_vout_server); +#ifdef CONFIG_AMLOGIC_VOUT2_SERVE + vout2_register_server(&hdmitx_vout2_server); +#endif #ifdef CONFIG_AMLOGIC_SND_SOC aout_register_client(&hdmitx_notifier_nb_a); #else @@ -3390,7 +3434,10 @@ static int amhdmitx_remove(struct platform_device *pdev) hdmitx_device.HWOp.UnInit(&hdmitx_device); hdmitx_device.hpd_event = 0xff; kthread_stop(hdmitx_device.task); - vout_unregister_server(&hdmitx_server); + vout_unregister_server(&hdmitx_vout_server); +#ifdef CONFIG_AMLOGIC_VOUT2_SERVE + vout2_unregister_server(&hdmitx_vout2_server); +#endif #ifdef CONFIG_AMLOGIC_SND_SOC aout_unregister_client(&hdmitx_notifier_nb_a); #endif diff --git a/drivers/amlogic/media/vout/lcd/lcd_common.h b/drivers/amlogic/media/vout/lcd/lcd_common.h index 9a19c50..8576601 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_common.h +++ b/drivers/amlogic/media/vout/lcd/lcd_common.h @@ -62,13 +62,11 @@ extern int lcd_class_remove(void); #ifdef CONFIG_AMLOGIC_LCD_TV extern void lcd_vbyone_interrupt_enable(int flag); extern void lcd_tv_clk_update(struct lcd_config_s *pconf); -extern void lcd_tv_vout_server_init(void); extern int lcd_tv_probe(struct device *dev); extern int lcd_tv_remove(struct device *dev); #endif #ifdef CONFIG_AMLOGIC_LCD_TABLET extern void lcd_tablet_clk_update(struct lcd_config_s *pconf); -extern void lcd_tablet_vout_server_init(void); extern int lcd_tablet_probe(struct device *dev); extern int lcd_tablet_remove(struct device *dev); #endif diff --git a/drivers/amlogic/media/vout/lcd/lcd_tablet/lcd_tablet.c b/drivers/amlogic/media/vout/lcd/lcd_tablet/lcd_tablet.c index 9689b6a..d4df533 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_tablet/lcd_tablet.c +++ b/drivers/amlogic/media/vout/lcd/lcd_tablet/lcd_tablet.c @@ -49,6 +49,24 @@ * vout server api * ************************************************** */ +static struct vinfo_s *lcd_get_current_info(void) +{ + struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); + + return lcd_drv->lcd_info; +} + +static int lcd_vmode_is_supported(enum vmode_e mode) +{ + mode &= VMODE_MODE_BIT_MASK; + if (lcd_debug_print_flag) + LCDPR("%s vmode = %d\n", __func__, mode); + + if (mode == VMODE_LCD) + return true; + return false; +} + static enum vmode_e lcd_validate_vmode(char *mode) { if (mode == NULL) @@ -60,13 +78,6 @@ static enum vmode_e lcd_validate_vmode(char *mode) return VMODE_MAX; } -static struct vinfo_s *lcd_get_current_info(void) -{ - struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); - - return lcd_drv->lcd_info; -} - static int lcd_set_current_vmode(enum vmode_e mode) { int ret = 0; @@ -90,24 +101,31 @@ static int lcd_set_current_vmode(enum vmode_e mode) return ret; } -static int lcd_vmode_is_supported(enum vmode_e mode) +static int lcd_vout_disable(enum vmode_e cur_vmod) { - mode &= VMODE_MODE_BIT_MASK; - if (lcd_debug_print_flag) - LCDPR("%s vmode = %d\n", __func__, mode); + aml_lcd_notifier_call_chain(LCD_EVENT_IF_POWER_OFF, NULL); + LCDPR("%s finished\n", __func__); + return 0; +} - if (mode == VMODE_LCD) - return true; - return false; +static int lcd_vout_state; +static int lcd_vout_set_state(int index) +{ + lcd_vout_state |= (1 << index); + return 0; } -static int lcd_vout_disable(enum vmode_e cur_vmod) +static int lcd_vout_clr_state(int index) { - aml_lcd_notifier_call_chain(LCD_EVENT_IF_POWER_OFF, NULL); - LCDPR("%s finished\n", __func__); + lcd_vout_state &= ~(1 << index); return 0; } +static int lcd_vout_get_state(void) +{ + return lcd_vout_state; +} + #ifdef CONFIG_AML_VOUT_FRAMERATE_AUTOMATION struct lcd_vframe_match_s { int fps; @@ -343,6 +361,9 @@ static struct vout_server_s lcd_vout_server = { .validate_vmode = lcd_validate_vmode, .vmode_is_supported = lcd_vmode_is_supported, .disable = lcd_vout_disable, + .set_state = lcd_vout_set_state, + .clr_state = lcd_vout_clr_state, + .get_state = lcd_vout_get_state, .set_vframe_rate_hint = lcd_set_vframe_rate_hint, .set_vframe_rate_end_hint = lcd_set_vframe_rate_end_hint, .set_vframe_rate_policy = lcd_set_vframe_rate_policy, @@ -354,6 +375,30 @@ static struct vout_server_s lcd_vout_server = { }, }; +#ifdef CONFIG_AMLOGIC_VOUT2_SERVE +static struct vout_server_s lcd_vout2_server = { + .name = "lcd_vout2_server", + .op = { + .get_vinfo = lcd_get_current_info, + .set_vmode = lcd_set_current_vmode, + .validate_vmode = lcd_validate_vmode, + .vmode_is_supported = lcd_vmode_is_supported, + .disable = lcd_vout_disable, + .set_state = lcd_vout_set_state, + .clr_state = lcd_vout_clr_state, + .get_state = lcd_vout_get_state, + .set_vframe_rate_hint = lcd_set_vframe_rate_hint, + .set_vframe_rate_end_hint = lcd_set_vframe_rate_end_hint, + .set_vframe_rate_policy = lcd_set_vframe_rate_policy, + .get_vframe_rate_policy = lcd_get_vframe_rate_policy, +#ifdef CONFIG_PM + .vout_suspend = lcd_suspend, + .vout_resume = lcd_resume, +#endif + }, +}; +#endif + static void lcd_tablet_vinfo_update(void) { struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); @@ -430,10 +475,15 @@ static void lcd_tablet_vinfo_update_default(void) } } -void lcd_tablet_vout_server_init(void) +static void lcd_tablet_vout_server_init(void) { + struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); + lcd_tablet_vinfo_update_default(); - vout_register_server(&lcd_vout_server); + lcd_drv->vout_server = &lcd_vout_server; +#ifdef CONFIG_AMLOGIC_VOUT2_SERVE + lcd_drv->vout2_server = &lcd_vout2_server; +#endif } /* ************************************************** diff --git a/drivers/amlogic/media/vout/lcd/lcd_tv/lcd_tv.c b/drivers/amlogic/media/vout/lcd/lcd_tv/lcd_tv.c index 6889fc3..b308da8 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_tv/lcd_tv.c +++ b/drivers/amlogic/media/vout/lcd/lcd_tv/lcd_tv.c @@ -227,6 +227,7 @@ static void lcd_vmode_vinfo_update(enum vmode_e mode) lcd_drv->lcd_info->video_clk = pconf->lcd_timing.lcd_clk; lcd_drv->lcd_info->htotal = pconf->lcd_basic.h_period; lcd_drv->lcd_info->vtotal = pconf->lcd_basic.v_period; + lcd_drv->lcd_info->viu_mux = VIU_MUX_ENCL; lcd_hdr_vinfo_update(); } @@ -328,6 +329,24 @@ static int lcd_vout_disable(enum vmode_e cur_vmod) return 0; } +static int lcd_vout_state; +static int lcd_vout_set_state(int index) +{ + lcd_vout_state |= (1 << index); + return 0; +} + +static int lcd_vout_clr_state(int index) +{ + lcd_vout_state &= ~(1 << index); + return 0; +} + +static int lcd_vout_get_state(void) +{ + return lcd_vout_state; +} + #ifdef CONFIG_AML_VOUT_FRAMERATE_AUTOMATION struct lcd_vframe_match_s { int fps; @@ -572,6 +591,9 @@ static struct vout_server_s lcd_vout_server = { .validate_vmode = lcd_validate_vmode, .vmode_is_supported = lcd_vmode_is_supported, .disable = lcd_vout_disable, + .set_state = lcd_vout_set_state, + .clr_state = lcd_vout_clr_state, + .get_state = lcd_vout_get_state, .set_vframe_rate_hint = lcd_set_vframe_rate_hint, .set_vframe_rate_end_hint = lcd_set_vframe_rate_end_hint, .set_vframe_rate_policy = lcd_set_vframe_rate_policy, @@ -624,10 +646,15 @@ static void lcd_vinfo_update_default(void) } } -void lcd_tv_vout_server_init(void) +static void lcd_tv_vout_server_init(void) { + struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); + lcd_vinfo_update_default(); - vout_register_server(&lcd_vout_server); + lcd_drv->vout_server = &lcd_vout_server; +#ifdef CONFIG_AMLOGIC_VOUT2_SERVE + lcd_drv->vout2_server = NULL; +#endif } /* ************************************************** * diff --git a/drivers/amlogic/media/vout/lcd/lcd_vout.c b/drivers/amlogic/media/vout/lcd/lcd_vout.c index 07bd7d8..a41e8f22 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_vout.c +++ b/drivers/amlogic/media/vout/lcd/lcd_vout.c @@ -700,21 +700,17 @@ static void lcd_fops_remove(void) static void lcd_init_vout(void) { - switch (lcd_driver->lcd_mode) { -#ifdef CONFIG_AMLOGIC_LCD_TV - case LCD_MODE_TV: - lcd_tv_vout_server_init(); - break; -#endif -#ifdef CONFIG_AMLOGIC_LCD_TABLET - case LCD_MODE_TABLET: - lcd_tablet_vout_server_init(); - break; + if (lcd_driver->vout_server_init) + lcd_driver->vout_server_init(); + else + LCDERR("vout_server_init is null\n"); + + if (lcd_driver->vout_server) + vout_register_server(lcd_driver->vout_server); +#ifdef CONFIG_AMLOGIC_VOUT2_SERVE + if (lcd_driver->vout2_server) + vout2_register_server(lcd_driver->vout2_server); #endif - default: - LCDERR("invalid lcd mode: %d\n", lcd_driver->lcd_mode); - break; - } } static int lcd_mode_probe(struct device *dev) diff --git a/drivers/amlogic/media/vout/vout_serve/Kconfig b/drivers/amlogic/media/vout/vout_serve/Kconfig index a7180a7..b78c0fb 100644 --- a/drivers/amlogic/media/vout/vout_serve/Kconfig +++ b/drivers/amlogic/media/vout/vout_serve/Kconfig @@ -9,3 +9,10 @@ config AMLOGIC_VOUT_SERVE Amlogic Video output Server support. Provide display mode service for all of the display modules. +config AMLOGIC_VOUT2_SERVE + bool "Amlogic Vout2_Serve Module" + default n + help + Amlogic Video output2 Server support. + Provide 2nd display mode service for all of the display modules. + diff --git a/drivers/amlogic/media/vout/vout_serve/Makefile b/drivers/amlogic/media/vout/vout_serve/Makefile index e101d35..a67378b 100644 --- a/drivers/amlogic/media/vout/vout_serve/Makefile +++ b/drivers/amlogic/media/vout/vout_serve/Makefile @@ -1,2 +1,3 @@ -obj-$(CONFIG_AMLOGIC_VOUT_SERVE) += vout_notify.o vout_serve.o +obj-$(CONFIG_AMLOGIC_VOUT_SERVE) += vout_notify.o vout_serve.o vout_func.o +obj-$(CONFIG_AMLOGIC_VOUT2_SERVE) += vout2_notify.o vout2_serve.o diff --git a/drivers/amlogic/media/vout/vout_serve/vout2_notify.c b/drivers/amlogic/media/vout/vout_serve/vout2_notify.c new file mode 100644 index 0000000..2cf1a60 --- /dev/null +++ b/drivers/amlogic/media/vout/vout_serve/vout2_notify.c @@ -0,0 +1,214 @@ +/* + * drivers/amlogic/media/vout/vout_serve/vout2_notify.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +/* Linux Headers */ +#include +#include +#include +#include + +/* Amlogic Headers */ +#include + +/* Local Headers */ +#include "vout_func.h" + +static BLOCKING_NOTIFIER_HEAD(vout2_notifier_list); + +/** + * vout_register_client - register a client notifier + * @nb: notifier block to callback on events + */ +int vout2_register_client(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&vout2_notifier_list, nb); +} +EXPORT_SYMBOL(vout2_register_client); + +/** + * vout_unregister_client - unregister a client notifier + * @nb: notifier block to callback on events + */ +int vout2_unregister_client(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&vout2_notifier_list, nb); +} +EXPORT_SYMBOL(vout2_unregister_client); + +/** + * vout_notifier_call_chain - notify clients of fb_events + * + */ +int vout2_notifier_call_chain(unsigned long val, void *v) +{ + return blocking_notifier_call_chain(&vout2_notifier_list, val, v); +} +EXPORT_SYMBOL_GPL(vout2_notifier_call_chain); + +/* + *interface export to client who want to get current vinfo. + */ +struct vinfo_s *get_current_vinfo2(void) +{ + struct vinfo_s *vinfo = NULL; + struct vout_module_s *p_module = NULL; + + p_module = vout_func_get_vout2_module(); + if (!IS_ERR_OR_NULL(p_module->curr_vout_server)) { + if (p_module->curr_vout_server->op.get_vinfo) + vinfo = p_module->curr_vout_server->op.get_vinfo(); + } + if (vinfo == NULL) /* avoid crash mistake */ + vinfo = get_invalid_vinfo(2); + + return vinfo; +} +EXPORT_SYMBOL(get_current_vinfo2); + +/* + *interface export to client who want to get current vmode. + */ +enum vmode_e get_current_vmode2(void) +{ + const struct vinfo_s *vinfo; + struct vout_module_s *p_module = NULL; + enum vmode_e mode = VMODE_MAX; + + p_module = vout_func_get_vout2_module(); + if (!IS_ERR_OR_NULL(p_module->curr_vout_server)) { + if (p_module->curr_vout_server->op.get_vinfo) { + vinfo = p_module->curr_vout_server->op.get_vinfo(); + if (vinfo) + mode = vinfo->mode; + } + } + + return mode; +} +EXPORT_SYMBOL(get_current_vmode2); + +const char *get_name_by_vmode2(enum vmode_e mode) +{ + const char *str = NULL; + const struct vinfo_s *vinfo = NULL; + struct vout_module_s *p_module = NULL; + + p_module = vout_func_get_vout2_module(); + if (!IS_ERR_OR_NULL(p_module->curr_vout_server)) { + if (p_module->curr_vout_server->op.get_vinfo) + vinfo = p_module->curr_vout_server->op.get_vinfo(); + } + if (vinfo == NULL) + vinfo = get_invalid_vinfo(2); + str = vinfo->name; + + return str; +} +EXPORT_SYMBOL(get_name_by_vmode2); + +/* + * interface export to client who want to set current vmode. + */ +int set_current_vmode2(enum vmode_e mode) +{ + return vout_func_set_current_vmode(2, mode); +} +EXPORT_SYMBOL(set_current_vmode2); + +/* + *interface export to client who want to set current vmode. + */ +enum vmode_e validate_vmode2(char *name) +{ + return vout_func_validate_vmode(2, name); +} +EXPORT_SYMBOL(validate_vmode2); + +/* + *interface export to client who want to notify about source frame rate. + */ +int set_vframe2_rate_hint(int duration) +{ + return vout_func_set_vframe_rate_hint(2, duration); +} +EXPORT_SYMBOL(set_vframe2_rate_hint); + +/* + *interface export to client who want to notify about source frame rate end. + */ +int set_vframe2_rate_end_hint(void) +{ + return vout_func_set_vframe_rate_end_hint(2); +} +EXPORT_SYMBOL(set_vframe2_rate_end_hint); + +/* + *interface export to client who want to notify about source fr_policy. + */ +int set_vframe2_rate_policy(int policy) +{ + return vout_func_set_vframe_rate_policy(2, policy); +} +EXPORT_SYMBOL(set_vframe2_rate_policy); + +/* + *interface export to client who want to notify about source fr_policy. + */ +int get_vframe2_rate_policy(void) +{ + return vout_func_get_vframe_rate_policy(2); +} +EXPORT_SYMBOL(get_vframe2_rate_policy); + +int vout2_suspend(void) +{ + return vout_func_vout_suspend(2); +} +EXPORT_SYMBOL(vout2_suspend); + +int vout2_resume(void) +{ + return vout_func_vout_resume(2); +} +EXPORT_SYMBOL(vout2_resume); + +/* + *interface export to client who want to shutdown. + */ +int vout2_shutdown(void) +{ + return vout_func_vout_shutdown(2); +} +EXPORT_SYMBOL(vout2_shutdown); + +/* + *here we offer two functions to get and register vout module server + *vout module server will set and store tvmode attributes for vout encoder + *we can ensure TVMOD SET MODULE independent with these two function. + */ + +int vout2_register_server(struct vout_server_s *mem_server) +{ + return vout_func_vout_register_server(2, mem_server); +} +EXPORT_SYMBOL(vout2_register_server); + +int vout2_unregister_server(struct vout_server_s *mem_server) +{ + return vout_func_vout_unregister_server(2, mem_server); +} +EXPORT_SYMBOL(vout2_unregister_server); diff --git a/drivers/amlogic/media/vout/vout_serve/vout2_serve.c b/drivers/amlogic/media/vout/vout_serve/vout2_serve.c new file mode 100644 index 0000000..d14e242 --- /dev/null +++ b/drivers/amlogic/media/vout/vout_serve/vout2_serve.c @@ -0,0 +1,821 @@ +/* + * drivers/amlogic/media/vout/vout_serve/vout2_serve.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +/* Linux Headers */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Amlogic Headers */ +#include + +/* Local Headers */ +#include "vout_func.h" + +#ifdef CONFIG_AMLOGIC_LEGACY_EARLY_SUSPEND +#include +static struct early_suspend early_suspend; +static int early_suspend_flag; +#endif + +#define VOUT_CDEV_NAME "display2" +#define VOUT_CLASS_NAME "display2" +#define MAX_NUMBER_PARA 10 + +#define VMODE_NAME_LEN_MAX 64 +static struct class *vout2_class; +static DEFINE_MUTEX(vout2_serve_mutex); +static char vout2_mode[VMODE_NAME_LEN_MAX]; +static char local_name[VMODE_NAME_LEN_MAX] = {0}; + +static char vout2_axis[64]; + +static struct extcon_dev *vout2_excton_setmode; +static const unsigned int vout2_cable[] = { + EXTCON_TYPE_DISP, + EXTCON_NONE, +}; + +static struct vout_cdev_s *vout2_cdev; + +/* ********************************************************** + * null display support + * ********************************************************** + */ +static struct vinfo_s nulldisp_vinfo = { + .name = "null", + .mode = VMODE_NULL, + .width = 1920, + .height = 1080, + .field_height = 1080, + .aspect_ratio_num = 16, + .aspect_ratio_den = 9, + .sync_duration_num = 60, + .sync_duration_den = 1, + .video_clk = 148500000, + .htotal = 2200, + .vtotal = 1125, + .viu_color_fmt = COLOR_FMT_RGB444, + .viu_mux = VIU_MUX_MAX, + .vout_device = NULL, +}; + +static struct vinfo_s *nulldisp_get_current_info(void) +{ + return &nulldisp_vinfo; +} + +static int nulldisp_set_current_vmode(enum vmode_e mode) +{ + return 0; +} + +static enum vmode_e nulldisp_validate_vmode(char *name) +{ + if (strncmp(nulldisp_vinfo.name, name, + strlen(nulldisp_vinfo.name)) == 0) { + return nulldisp_vinfo.mode; + } + + return VMODE_MAX; +} + +static int nulldisp_vmode_is_supported(enum vmode_e mode) +{ + if (nulldisp_vinfo.mode == mode) + return true; + return false; +} + +static int nulldisp_disable(enum vmode_e cur_vmod) +{ + return 0; +} + +static int nulldisp_vout_state; +static int nulldisp_vout_set_state(int bit) +{ + nulldisp_vout_state |= (1 << bit); + return 0; +} + +static int nulldisp_vout_clr_state(int bit) +{ + nulldisp_vout_state &= ~(1 << bit); + return 0; +} + +static int nulldisp_vout_get_state(void) +{ + return nulldisp_vout_state; +} + +static struct vout_server_s nulldisp_vout2_server = { + .name = "nulldisp_vout2_server", + .op = { + .get_vinfo = nulldisp_get_current_info, + .set_vmode = nulldisp_set_current_vmode, + .validate_vmode = nulldisp_validate_vmode, + .vmode_is_supported = nulldisp_vmode_is_supported, + .disable = nulldisp_disable, + .set_state = nulldisp_vout_set_state, + .clr_state = nulldisp_vout_clr_state, + .get_state = nulldisp_vout_get_state, + }, +}; + +/* ********************************************************** */ + +char *get_vout2_mode_internal(void) +{ + return vout2_mode; +} +EXPORT_SYMBOL(get_vout2_mode_internal); + +static int set_vout2_mode(char *name) +{ + enum vmode_e mode; + int ret = 0; + + VOUTPR("vout2: vmode set to %s\n", name); + + if (strcmp(name, local_name) == 0) { + VOUTPR("vout2: don't set the same mode as current\n"); + return -1; + } + + mode = validate_vmode2(name); + if (mode == VMODE_MAX) { + VOUTERR("vout2: no matched vout2 mode\n"); + return -1; + } + memset(local_name, 0, sizeof(local_name)); + snprintf(local_name, VMODE_NAME_LEN_MAX, "%s", name); + + extcon_set_state_sync(vout2_excton_setmode, EXTCON_TYPE_DISP, 1); + + vout2_notifier_call_chain(VOUT_EVENT_MODE_CHANGE_PRE, &mode); + ret = set_current_vmode2(mode); + if (ret) { + VOUTERR("vout2: new mode %s set error\n", name); + } else { + snprintf(vout2_mode, VMODE_NAME_LEN_MAX, "%s", name); + VOUTPR("vout2: new mode %s set ok\n", vout2_mode); + } + vout2_notifier_call_chain(VOUT_EVENT_MODE_CHANGE, &mode); + + extcon_set_state_sync(vout2_excton_setmode, EXTCON_TYPE_DISP, 0); + + return ret; +} + +static int set_vout2_init_mode(void) +{ + enum vmode_e vmode = VMODE_NULL; + int ret = 0; + + ret = set_current_vmode2(vmode); + if (ret) { + VOUTERR("vout2: init mode null set error\n"); + } else { + snprintf(vout2_mode, VMODE_NAME_LEN_MAX, "null"); + VOUTPR("vout2: init mode %s set ok\n", vout2_mode); + } + + return ret; +} + +static int parse_para(const char *para, int para_num, int *result) +{ + char *token = NULL; + char *params, *params_base; + int *out = result; + int len = 0, count = 0; + int res = 0; + int ret = 0; + + if (!para) + return 0; + + params = kstrdup(para, GFP_KERNEL); + params_base = params; + token = params; + len = strlen(token); + do { + token = strsep(¶ms, " "); + while (token && (isspace(*token) + || !isgraph(*token)) && len) { + token++; + len--; + } + if ((!token) || (*token == '\n') || (len == 0)) + break; + ret = kstrtoint(token, 0, &res); + if (ret < 0) + break; + len = strlen(token); + *out++ = res; + count++; + } while ((token) && (count < para_num) && (len > 0)); + + kfree(params_base); + return count; +} + +#define OSD_COUNT 2 +static void set_vout2_axis(char *para) +{ + static struct disp_rect_s disp_rect[OSD_COUNT]; + /* char count = OSD_COUNT * 4; */ + int *pt = &disp_rect[0].x; + int parsed[MAX_NUMBER_PARA] = {}; + + /* parse window para */ + if (parse_para(para, 8, parsed) >= 4) + memcpy(pt, parsed, sizeof(struct disp_rect_s) * OSD_COUNT); + /* if ((count >= 4) && (count < 8)) + * disp_rect[1] = disp_rect[0]; + */ + + VOUTPR("vout2: osd0=> x:%d,y:%d,w:%d,h:%d\n" + "osd1=> x:%d,y:%d,w:%d,h:%d\n", + *pt, *(pt + 1), *(pt + 2), *(pt + 3), + *(pt + 4), *(pt + 5), *(pt + 6), *(pt + 7)); + vout2_notifier_call_chain(VOUT_EVENT_OSD_DISP_AXIS, &disp_rect[0]); +} + +static ssize_t vout2_mode_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + int ret = 0; + + ret = snprintf(buf, VMODE_NAME_LEN_MAX, "%s\n", vout2_mode); + + return ret; +} + +static ssize_t vout2_mode_store(struct class *class, + struct class_attribute *attr, const char *buf, size_t count) +{ + char mode[64]; + + mutex_lock(&vout2_serve_mutex); + snprintf(mode, VMODE_NAME_LEN_MAX, "%s", buf); + set_vout2_mode(mode); + mutex_unlock(&vout2_serve_mutex); + return count; +} + +static ssize_t vout2_axis_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + int ret = 0; + + ret = snprintf(buf, 64, "%s\n", vout2_axis); + return ret; +} + +static ssize_t vout2_axis_store(struct class *class, + struct class_attribute *attr, const char *buf, size_t count) +{ + mutex_lock(&vout2_serve_mutex); + snprintf(vout2_axis, 64, "%s", buf); + set_vout2_axis(vout2_axis); + mutex_unlock(&vout2_serve_mutex); + return count; +} + +static ssize_t vout2_fr_policy_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + int policy; + int ret = 0; + + policy = get_vframe2_rate_policy(); + ret = sprintf(buf, "%d\n", policy); + + return ret; +} + +static ssize_t vout2_fr_policy_store(struct class *class, + struct class_attribute *attr, const char *buf, size_t count) +{ + int policy; + int ret = 0; + + mutex_lock(&vout2_serve_mutex); + ret = kstrtoint(buf, 10, &policy); + if (ret) { + pr_info("%s: invalid data\n", __func__); + mutex_unlock(&vout2_serve_mutex); + return -EINVAL; + } + ret = set_vframe2_rate_policy(policy); + if (ret) + pr_info("%s: %d failed\n", __func__, policy); + mutex_unlock(&vout2_serve_mutex); + + return count; +} + +static ssize_t vout2_vinfo_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + const struct vinfo_s *info = NULL; + ssize_t len = 0; + + info = get_current_vinfo2(); + if (info == NULL) + return sprintf(buf, "current vinfo2 is null\n"); + + len = sprintf(buf, "current vinfo2:\n" + " name: %s\n" + " mode: %d\n" + " width: %d\n" + " height: %d\n" + " field_height: %d\n" + " aspect_ratio_num: %d\n" + " aspect_ratio_den: %d\n" + " sync_duration_num: %d\n" + " sync_duration_den: %d\n" + " screen_real_width: %d\n" + " screen_real_height: %d\n" + " htotal: %d\n" + " vtotal: %d\n" + " video_clk: %d\n" + " viu_color_fmt: %d\n" + " viu_mux: %d\n\n", + info->name, info->mode, + info->width, info->height, info->field_height, + info->aspect_ratio_num, info->aspect_ratio_den, + info->sync_duration_num, info->sync_duration_den, + info->screen_real_width, info->screen_real_height, + info->htotal, info->vtotal, + info->video_clk, info->viu_color_fmt, info->viu_mux); + len += sprintf(buf+len, "master_display_info:\n" + " present_flag %d\n" + " features 0x%x\n" + " primaries 0x%x, 0x%x\n" + " 0x%x, 0x%x\n" + " 0x%x, 0x%x\n" + " white_point 0x%x, 0x%x\n" + " luminance %d, %d\n\n", + info->master_display_info.present_flag, + info->master_display_info.features, + info->master_display_info.primaries[0][0], + info->master_display_info.primaries[0][1], + info->master_display_info.primaries[1][0], + info->master_display_info.primaries[1][1], + info->master_display_info.primaries[2][0], + info->master_display_info.primaries[2][1], + info->master_display_info.white_point[0], + info->master_display_info.white_point[1], + info->master_display_info.luminance[0], + info->master_display_info.luminance[1]); + len += sprintf(buf+len, "hdr_info:\n" + " hdr_support %d\n" + " lumi_max %d\n" + " lumi_avg %d\n" + " lumi_min %d\n", + info->hdr_info.hdr_support, + info->hdr_info.lumi_max, + info->hdr_info.lumi_avg, + info->hdr_info.lumi_min); + return len; +} + +static struct class_attribute vout2_class_attrs[] = { + __ATTR(mode, 0644, vout2_mode_show, vout2_mode_store), + __ATTR(axis, 0644, vout2_axis_show, vout2_axis_store), + __ATTR(fr_policy, 0644, + vout2_fr_policy_show, vout2_fr_policy_store), + __ATTR(vinfo, 0444, vout2_vinfo_show, NULL), +}; + +static int vout2_attr_create(void) +{ + int i; + int ret = 0; + + /* create vout class */ + vout2_class = class_create(THIS_MODULE, VOUT_CLASS_NAME); + if (IS_ERR(vout2_class)) { + VOUTERR("vout2: create vout2 class fail\n"); + return -1; + } + + /* create vout class attr files */ + for (i = 0; i < ARRAY_SIZE(vout2_class_attrs); i++) { + if (class_create_file(vout2_class, &vout2_class_attrs[i])) { + VOUTERR("vout2: create vout2 attribute %s fail\n", + vout2_class_attrs[i].attr.name); + } + } + + VOUTPR("vout2: create vout2 attribute OK\n"); + + return ret; +} + +static int vout2_attr_remove(void) +{ + int i; + + if (vout2_class == NULL) + return 0; + + for (i = 0; i < ARRAY_SIZE(vout2_class_attrs); i++) + class_remove_file(vout2_class, &vout2_class_attrs[i]); + + class_destroy(vout2_class); + vout2_class = NULL; + + return 0; +} + +/* ************************************************************* */ +/* vout2 ioctl */ +/* ************************************************************* */ +static int vout2_io_open(struct inode *inode, struct file *file) +{ + struct vout_cdev_s *vcdev; + + VOUTPR("%s\n", __func__); + vcdev = container_of(inode->i_cdev, struct vout_cdev_s, cdev); + file->private_data = vcdev; + return 0; +} + +static int vout2_io_release(struct inode *inode, struct file *file) +{ + VOUTPR("%s\n", __func__); + file->private_data = NULL; + return 0; +} + +static long vout2_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + void __user *argp; + int mcd_nr; + struct vinfo_s *info = NULL; + struct vinfo_base_s baseinfo; + + mcd_nr = _IOC_NR(cmd); + VOUTPR("%s: cmd_dir = 0x%x, cmd_nr = 0x%x\n", + __func__, _IOC_DIR(cmd), mcd_nr); + + argp = (void __user *)arg; + switch (mcd_nr) { + case VOUT_IOC_NR_GET_VINFO: + info = get_current_vinfo2(); + if (info == NULL) + ret = -EFAULT; + else if (info->mode == VMODE_INIT_NULL) + ret = -EFAULT; + else { + baseinfo.mode = info->mode; + baseinfo.width = info->width; + baseinfo.height = info->height; + baseinfo.field_height = info->field_height; + baseinfo.aspect_ratio_num = info->aspect_ratio_num; + baseinfo.aspect_ratio_den = info->aspect_ratio_den; + baseinfo.sync_duration_num = info->sync_duration_num; + baseinfo.sync_duration_den = info->sync_duration_den; + baseinfo.screen_real_width = info->screen_real_width; + baseinfo.screen_real_height = info->screen_real_height; + baseinfo.video_clk = info->video_clk; + baseinfo.viu_color_fmt = info->viu_color_fmt; + baseinfo.hdr_info = info->hdr_info; + if (copy_to_user(argp, &baseinfo, + sizeof(struct vinfo_base_s))) + ret = -EFAULT; + } + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +#ifdef CONFIG_COMPAT +static long vout2_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + unsigned long ret; + + arg = (unsigned long)compat_ptr(arg); + ret = vout2_ioctl(file, cmd, arg); + return ret; +} +#endif + +static const struct file_operations vout2_fops = { + .owner = THIS_MODULE, + .open = vout2_io_open, + .release = vout2_io_release, + .unlocked_ioctl = vout2_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = vout2_compat_ioctl, +#endif +}; + +static int vout2_fops_create(void) +{ + int ret = 0; + + vout2_cdev = kmalloc(sizeof(struct vout_cdev_s), GFP_KERNEL); + if (!vout2_cdev) { + VOUTERR("vout2: failed to allocate vout2_cdev\n"); + return -1; + } + + ret = alloc_chrdev_region(&vout2_cdev->devno, 0, 1, VOUT_CDEV_NAME); + if (ret < 0) { + VOUTERR("vout2: failed to alloc vout2 devno\n"); + goto vout2_fops_err1; + } + + cdev_init(&vout2_cdev->cdev, &vout2_fops); + vout2_cdev->cdev.owner = THIS_MODULE; + ret = cdev_add(&vout2_cdev->cdev, vout2_cdev->devno, 1); + if (ret) { + VOUTERR("vout2: failed to add vout2 cdev\n"); + goto vout2_fops_err2; + } + + vout2_cdev->dev = device_create(vout2_class, NULL, vout2_cdev->devno, + NULL, VOUT_CDEV_NAME); + if (IS_ERR(vout2_cdev->dev)) { + ret = PTR_ERR(vout2_cdev->dev); + VOUTERR("vout2: failed to create vout2 device: %d\n", ret); + goto vout2_fops_err3; + } + + VOUTPR("vout2: %s OK\n", __func__); + return 0; + +vout2_fops_err3: + cdev_del(&vout2_cdev->cdev); +vout2_fops_err2: + unregister_chrdev_region(vout2_cdev->devno, 1); +vout2_fops_err1: + kfree(vout2_cdev); + vout2_cdev = NULL; + return -1; +} + +static void vout2_fops_remove(void) +{ + cdev_del(&vout2_cdev->cdev); + unregister_chrdev_region(vout2_cdev->devno, 1); + kfree(vout2_cdev); + vout2_cdev = NULL; +} +/* ************************************************************* */ + +#ifdef CONFIG_PM +static int aml_vout2_suspend(struct platform_device *pdev, pm_message_t state) +{ +#ifdef CONFIG_AMLOGIC_LEGACY_EARLY_SUSPEND + + if (early_suspend_flag) + return 0; + +#endif + vout2_suspend(); + return 0; +} + +static int aml_vout2_resume(struct platform_device *pdev) +{ +#ifdef CONFIG_AMLOGIC_LEGACY_EARLY_SUSPEND + + if (early_suspend_flag) + return 0; + +#endif + vout2_resume(); + return 0; +} +#endif + +#ifdef CONFIG_HIBERNATION +static int aml_vout2_freeze(struct device *dev) +{ + return 0; +} + +static int aml_vout2_thaw(struct device *dev) +{ + return 0; +} + +static int aml_vout2_restore(struct device *dev) +{ + enum vmode_e mode; + + mode = get_current_vmode2(); + vout2_notifier_call_chain(VOUT_EVENT_MODE_CHANGE, &mode); + + return 0; +} +static int aml_vout2_pm_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + + return aml_vout2_suspend(pdev, PMSG_SUSPEND); +} +static int aml_vout2_pm_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + + return aml_vout2_resume(pdev); +} +#endif + +#ifdef CONFIG_AMLOGIC_LEGACY_EARLY_SUSPEND +static void aml_vout2_early_suspend(struct early_suspend *h) +{ + if (early_suspend_flag) + return; + + vout2_suspend(); + early_suspend_flag = 1; +} + +static void aml_vout2_late_resume(struct early_suspend *h) +{ + if (!early_suspend_flag) + return; + + early_suspend_flag = 0; + vout2_resume(); +} +#endif + +static void aml_vout2_extcon_register(struct platform_device *pdev) +{ + struct extcon_dev *edev; + int ret; + + /*set display mode*/ + edev = extcon_dev_allocate(vout2_cable); + if (IS_ERR(edev)) { + VOUTERR("failed to allocate vout2 extcon setmode\n"); + return; + } + + edev->dev.parent = &pdev->dev; + edev->name = "vout2_excton_setmode"; + dev_set_name(&edev->dev, "setmode2"); + ret = extcon_dev_register(edev); + if (ret) { + VOUTERR("failed to register vout2 extcon setmode\n"); + return; + } + vout2_excton_setmode = edev; +} + +static void aml_vout2_extcon_free(void) +{ + extcon_dev_free(vout2_excton_setmode); + vout2_excton_setmode = NULL; +} + +/***************************************************************** + ** + ** vout driver interface + ** + ******************************************************************/ +static int aml_vout2_probe(struct platform_device *pdev) +{ + int ret = -1; + +#ifdef CONFIG_AMLOGIC_LEGACY_EARLY_SUSPEND + early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN; + early_suspend.suspend = aml_vout2_early_suspend; + early_suspend.resume = aml_vout2_late_resume; + register_early_suspend(&early_suspend); +#endif + + vout2_class = NULL; + ret = vout2_attr_create(); + ret = vout2_fops_create(); + + vout2_register_server(&nulldisp_vout2_server); + set_vout2_init_mode(); + + aml_vout2_extcon_register(pdev); + + VOUTPR("vout2: %s OK\n", __func__); + return ret; +} + +static int aml_vout2_remove(struct platform_device *pdev) +{ +#ifdef CONFIG_AMLOGIC_LEGACY_EARLY_SUSPEND + unregister_early_suspend(&early_suspend); +#endif + + aml_vout2_extcon_free(); + vout2_attr_remove(); + vout2_fops_remove(); + vout2_unregister_server(&nulldisp_vout2_server); + + return 0; +} + +static void aml_vout2_shutdown(struct platform_device *pdev) +{ + VOUTPR("vout2: %s\n", __func__); + vout2_shutdown(); +} + +static const struct of_device_id aml_vout2_dt_match[] = { + { .compatible = "amlogic, vout2",}, + { }, +}; + +#ifdef CONFIG_HIBERNATION +const struct dev_pm_ops vout2_pm = { + .freeze = aml_vout2_freeze, + .thaw = aml_vout2_thaw, + .restore = aml_vout2_restore, + .suspend = aml_vout2_pm_suspend, + .resume = aml_vout2_pm_resume, +}; +#endif + +static struct platform_driver vout2_driver = { + .probe = aml_vout2_probe, + .remove = aml_vout2_remove, + .shutdown = aml_vout2_shutdown, +#ifdef CONFIG_PM + .suspend = aml_vout2_suspend, + .resume = aml_vout2_resume, +#endif + .driver = { + .name = "vout2", + .of_match_table = aml_vout2_dt_match, +#ifdef CONFIG_HIBERNATION + .pm = &vout2_pm, +#endif + }, +}; + +static int __init vout2_init_module(void) +{ + int ret = 0; + + if (platform_driver_register(&vout2_driver)) { + VOUTERR("vout2: failed to register VOUT2 driver\n"); + ret = -ENODEV; + } + + return ret; +} + +static __exit void vout2_exit_module(void) +{ + platform_driver_unregister(&vout2_driver); +} + +module_init(vout2_init_module); +module_exit(vout2_exit_module); + +MODULE_AUTHOR("Platform-BJ "); +MODULE_DESCRIPTION("VOUT2 Server Module"); +MODULE_LICENSE("GPL"); diff --git a/drivers/amlogic/media/vout/vout_serve/vout_func.c b/drivers/amlogic/media/vout/vout_serve/vout_func.c new file mode 100644 index 0000000..425d4c5 --- /dev/null +++ b/drivers/amlogic/media/vout/vout_serve/vout_func.c @@ -0,0 +1,549 @@ +/* + * drivers/amlogic/media/vout/vout_serve/vout_func.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +/* Linux Headers */ +#include +#include +#include +#include + +/* Amlogic Headers */ +#include +#include + +/* Local Headers */ +#include "vout_func.h" + +static DEFINE_MUTEX(vout_mutex); + +static struct vout_module_s vout_module = { + .vout_server_list = { + &vout_module.vout_server_list, + &vout_module.vout_server_list + }, + .curr_vout_server = NULL, +}; + +#ifdef CONFIG_AMLOGIC_VOUT2_SERVE +static struct vout_module_s vout2_module = { + .vout_server_list = { + &vout2_module.vout_server_list, + &vout2_module.vout_server_list + }, + .curr_vout_server = NULL, +}; +#endif + +static struct vinfo_s invalid_vinfo = { + .name = "invalid", + .mode = VMODE_INIT_NULL, + .width = 1920, + .height = 1080, + .field_height = 1080, + .aspect_ratio_num = 16, + .aspect_ratio_den = 9, + .sync_duration_num = 60, + .sync_duration_den = 1, + .video_clk = 148500000, + .htotal = 2200, + .vtotal = 1125, + .viu_color_fmt = COLOR_FMT_RGB444, + .viu_mux = VIU_MUX_MAX, + .vout_device = NULL, +}; + +struct vinfo_s *get_invalid_vinfo(int index) +{ + VOUTERR("invalid vinfo%d. current vmode is not supported\n", index); + return &invalid_vinfo; +} +EXPORT_SYMBOL(get_invalid_vinfo); + +struct vout_module_s *vout_func_get_vout_module(void) +{ + return &vout_module; +} +EXPORT_SYMBOL(vout_func_get_vout_module); + +#ifdef CONFIG_AMLOGIC_VOUT2_SERVE +struct vout_module_s *vout_func_get_vout2_module(void) +{ + return &vout2_module; +} +EXPORT_SYMBOL(vout_func_get_vout2_module); +#endif + +static unsigned int vout_func_vcbus_read(unsigned int _reg) +{ + return aml_read_vcbus(_reg); +}; + +static void vout_func_vcbus_write(unsigned int _reg, unsigned int _value) +{ + aml_write_vcbus(_reg, _value); +}; + +static void vout_func_vcbus_setb(unsigned int _reg, unsigned int _value, + unsigned int _start, unsigned int _len) +{ + vout_func_vcbus_write(_reg, ((vout_func_vcbus_read(_reg) & + ~(((1L << (_len))-1) << (_start))) | + (((_value)&((1L<<(_len))-1)) << (_start)))); +} + +static inline int vout_func_check_state(int index, unsigned int state, + struct vout_server_s *p_server) +{ + if (state & ~(1 << index)) { + /*VOUTERR("vout%d: server %s is actived by another vout\n", + * index, p_server->name); + */ + return -1; + } + + return 0; +} + +static void vout_func_update_viu(int index, struct vout_server_s *p_server) +{ + struct vinfo_s *vinfo = NULL; + unsigned int post_reg = VPP_POSTBLEND_H_SIZE; + unsigned int bit = 0, mux = 3; + + return; + if (p_server->op.get_vinfo) + vinfo = p_server->op.get_vinfo(); + else + vinfo = get_invalid_vinfo(index); + + switch (index) { + case 1: + post_reg = VPP_POSTBLEND_H_SIZE; + bit = 0; + break; + case 2: + post_reg = VPP2_POSTBLEND_H_SIZE; + bit = 2; + break; + default: + break; + } + + mux = vinfo->viu_mux; + + vout_func_vcbus_write(post_reg, vinfo->width); + vout_func_vcbus_setb(VPU_VIU_VENC_MUX_CTRL, mux, bit, 2); +} + +/* + * interface export to client who want to set current vmode. + */ +int vout_func_set_current_vmode(int index, enum vmode_e mode) +{ + int ret = -1; + struct vout_server_s *p_server; + struct vout_module_s *p_module = NULL; + int state; + + mutex_lock(&vout_mutex); + + if (index == 1) + p_module = &vout_module; +#ifdef CONFIG_AMLOGIC_VOUT2_SERVE + else if (index == 2) + p_module = &vout2_module; +#endif + + list_for_each_entry(p_server, &p_module->vout_server_list, list) { + if (p_server->op.vmode_is_supported == NULL) { + p_server->op.disable(mode); + continue; + } + + if (p_server->op.vmode_is_supported(mode) == true) { + p_module->curr_vout_server = p_server; + ret = p_server->op.set_vmode(mode); + if (p_server->op.set_state) + p_server->op.set_state(index); + vout_func_update_viu(index, p_server); + } else { + if (p_server->op.get_state) { + state = p_server->op.get_state(); + if (state & (1 << index)) + p_server->op.disable(mode); + } + if (p_server->op.clr_state) + p_server->op.clr_state(index); + } + } + + mutex_unlock(&vout_mutex); + + return ret; +} +EXPORT_SYMBOL(vout_func_set_current_vmode); + +/* + *interface export to client who want to set current vmode. + */ +enum vmode_e vout_func_validate_vmode(int index, char *name) +{ + enum vmode_e ret = VMODE_MAX; + struct vout_server_s *p_server; + struct vout_module_s *p_module = NULL; + int state; + + mutex_lock(&vout_mutex); + + if (index == 1) + p_module = &vout_module; +#ifdef CONFIG_AMLOGIC_VOUT2_SERVE + else if (index == 2) + p_module = &vout2_module; +#endif + + list_for_each_entry(p_server, &p_module->vout_server_list, list) { + /* check state for another vout */ + if (p_server->op.get_state) { + state = p_server->op.get_state(); + if (vout_func_check_state(index, state, p_server)) + continue; + } + if (p_server->op.validate_vmode) { + ret = p_server->op.validate_vmode(name); + if (ret != VMODE_MAX) /* valid vmode find. */ + break; + } + } + mutex_unlock(&vout_mutex); + + return ret; +} +EXPORT_SYMBOL(vout_func_validate_vmode); + +int vout_func_set_vframe_rate_hint(int index, int duration) +{ + int ret = -1; + struct vout_server_s *p_server = NULL; + + mutex_lock(&vout_mutex); + + if (index == 1) + p_server = vout_module.curr_vout_server; +#ifdef CONFIG_AMLOGIC_VOUT2_SERVE + else if (index == 2) + p_server = vout2_module.curr_vout_server; +#endif + + if (!IS_ERR_OR_NULL(p_server)) { + if (p_server->op.set_vframe_rate_hint) + ret = p_server->op.set_vframe_rate_hint(duration); + } + + mutex_unlock(&vout_mutex); + return ret; +} +EXPORT_SYMBOL(vout_func_set_vframe_rate_hint); + +/* + *interface export to client who want to notify about source frame rate end. + */ +int vout_func_set_vframe_rate_end_hint(int index) +{ + int ret = -1; + struct vout_server_s *p_server = NULL; + + mutex_lock(&vout_mutex); + + if (index == 1) + p_server = vout_module.curr_vout_server; +#ifdef CONFIG_AMLOGIC_VOUT2_SERVE + else if (index == 2) + p_server = vout2_module.curr_vout_server; +#endif + + if (!IS_ERR_OR_NULL(p_server)) { + if (p_server->op.set_vframe_rate_end_hint) + ret = p_server->op.set_vframe_rate_end_hint(); + } + + mutex_unlock(&vout_mutex); + return ret; +} +EXPORT_SYMBOL(vout_func_set_vframe_rate_end_hint); + +/* + *interface export to client who want to notify about source fr_policy. + */ +int vout_func_set_vframe_rate_policy(int index, int policy) +{ + int ret = -1; + struct vout_server_s *p_server = NULL; + + mutex_lock(&vout_mutex); + + if (index == 1) + p_server = vout_module.curr_vout_server; +#ifdef CONFIG_AMLOGIC_VOUT2_SERVE + else if (index == 2) + p_server = vout2_module.curr_vout_server; +#endif + + if (!IS_ERR_OR_NULL(p_server)) { + if (p_server->op.set_vframe_rate_policy) + ret = p_server->op.set_vframe_rate_policy(policy); + } + + mutex_unlock(&vout_mutex); + return ret; +} +EXPORT_SYMBOL(vout_func_set_vframe_rate_policy); + +/* + *interface export to client who want to notify about source fr_policy. + */ +int vout_func_get_vframe_rate_policy(int index) +{ + int ret = -1; + struct vout_server_s *p_server = NULL; + + mutex_lock(&vout_mutex); + + if (index == 1) + p_server = vout_module.curr_vout_server; +#ifdef CONFIG_AMLOGIC_VOUT2_SERVE + else if (index == 2) + p_server = vout2_module.curr_vout_server; +#endif + + if (!IS_ERR_OR_NULL(p_server)) { + if (p_server->op.get_vframe_rate_policy) + ret = p_server->op.get_vframe_rate_policy(); + } + + mutex_unlock(&vout_mutex); + return ret; +} +EXPORT_SYMBOL(vout_func_get_vframe_rate_policy); + +int vout_func_vout_suspend(int index) +{ + int ret = 0; + struct vout_server_s *p_server = NULL; + + mutex_lock(&vout_mutex); + + if (index == 1) + p_server = vout_module.curr_vout_server; + else if (index == 2) + p_server = vout2_module.curr_vout_server; + + if (!IS_ERR_OR_NULL(p_server)) { + if (p_server->op.vout_suspend) + ret = p_server->op.vout_suspend(); + } + + mutex_unlock(&vout_mutex); + return ret; +} +EXPORT_SYMBOL(vout_func_vout_suspend); + +int vout_func_vout_resume(int index) +{ + struct vout_server_s *p_server = NULL; + + mutex_lock(&vout_mutex); + + if (index == 1) + p_server = vout_module.curr_vout_server; +#ifdef CONFIG_AMLOGIC_VOUT2_SERVE + else if (index == 2) + p_server = vout2_module.curr_vout_server; +#endif + + if (!IS_ERR_OR_NULL(p_server)) { + if (p_server->op.vout_resume) { + /* ignore error when resume. */ + p_server->op.vout_resume(); + } + } + + mutex_unlock(&vout_mutex); + return 0; +} +EXPORT_SYMBOL(vout_func_vout_resume); + +/* + *interface export to client who want to shutdown. + */ +int vout_func_vout_shutdown(int index) +{ + int ret = -1; + struct vout_server_s *p_server; + struct vout_module_s *p_module = NULL; + + if (index == 1) + p_module = &vout_module; +#ifdef CONFIG_AMLOGIC_VOUT2_SERVE + else if (index == 2) + p_module = &vout2_module; +#endif + + list_for_each_entry(p_server, &p_module->vout_server_list, list) { + if (p_server->op.vout_shutdown) + ret = p_server->op.vout_shutdown(); + } + + return ret; +} +EXPORT_SYMBOL(vout_func_vout_shutdown); + +/* + *here we offer two functions to get and register vout module server + *vout module server will set and store tvmode attributes for vout encoder + *we can ensure TVMOD SET MODULE independent with these two function. + */ + +int vout_func_vout_register_server(int index, + struct vout_server_s *mem_server) +{ + struct list_head *p_iter; + struct vout_server_s *p_server; + struct vout_module_s *p_module = NULL; + + if (mem_server == NULL) { + VOUTERR("vout%d: server is NULL\n", index); + return -1; + } + if (mem_server->name == NULL) { + VOUTERR("vout%d: server name is NULL\n", index); + return -1; + } + VOUTPR("vout%d: register server: %s\n", index, mem_server->name); + + mutex_lock(&vout_mutex); + + if (index == 1) + p_module = &vout_module; +#ifdef CONFIG_AMLOGIC_VOUT2_SERVE + else if (index == 2) + p_module = &vout2_module; +#endif + + list_for_each(p_iter, &p_module->vout_server_list) { + p_server = list_entry(p_iter, struct vout_server_s, list); + + if (p_server->name && + (strcmp(p_server->name, mem_server->name) == 0)) { + VOUTPR("vout%d: server %s is already registered\n", + index, mem_server->name); + /* vout server already registered. */ + mutex_unlock(&vout_mutex); + return -1; + } + } + list_add(&mem_server->list, &p_module->vout_server_list); + mutex_unlock(&vout_mutex); + return 0; +} +EXPORT_SYMBOL(vout_func_vout_register_server); + +int vout_func_vout_unregister_server(int index, + struct vout_server_s *mem_server) +{ + struct vout_server_s *p_server; + struct vout_module_s *p_module = NULL; + + if (mem_server == NULL) { + VOUTERR("vout%d: server is NULL\n", index); + return -1; + } + VOUTPR("vout%d: unregister server: %s\n", index, mem_server->name); + + mutex_lock(&vout_mutex); + + if (index == 1) + p_module = &vout_module; +#ifdef CONFIG_AMLOGIC_VOUT2_SERVE + else if (index == 2) + p_module = &vout2_module; +#endif + + list_for_each_entry(p_server, &p_module->vout_server_list, list) { + if (p_server->name && mem_server->name && + (strcmp(p_server->name, mem_server->name) == 0)) { + /* + * We will not move current vout server pointer + * automatically if current vout server pointer + * is the one which will be deleted next. + * So you should change current vout server + * first then remove it + */ + if (p_module->curr_vout_server == p_server) + p_module->curr_vout_server = NULL; + + list_del(&mem_server->list); + mutex_unlock(&vout_mutex); + return 0; + } + } + mutex_unlock(&vout_mutex); + return 0; +} +EXPORT_SYMBOL(vout_func_vout_unregister_server); + +/* fps = 9600/duration/100 hz */ +static int vsource_fps_table[][2] = { + /* duration fps */ + {1600, 6000,}, + {1601, 5994,}, + {1602, 5994,}, + {1920, 5000,}, + {3200, 3000,}, + {3203, 2997,}, + {3840, 2500,}, + {4000, 2400,}, + {4004, 2397,}, +}; + +int vout_get_vsource_fps(int duration) +{ + int i; + int fps = 6000; + + for (i = 0; i < 9; i++) { + if (duration == vsource_fps_table[i][0]) { + fps = vsource_fps_table[i][1]; + break; + } + } + + return fps; +} +EXPORT_SYMBOL(vout_get_vsource_fps); + +int vout_get_hpd_state(void) +{ + int ret = 0; + +#ifdef CONFIG_AMLOGIC_HDMITX + ret = get_hpd_state(); +#endif + + return ret; +} +EXPORT_SYMBOL(vout_get_hpd_state); diff --git a/drivers/amlogic/media/vout/vout_serve/vout_func.h b/drivers/amlogic/media/vout/vout_serve/vout_func.h new file mode 100644 index 0000000..fc97b08 --- /dev/null +++ b/drivers/amlogic/media/vout/vout_serve/vout_func.h @@ -0,0 +1,83 @@ +/* + * drivers/amlogic/media/vout/vout_serve/vout_func.h + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#ifndef _VOUT_FUNC_H_ +#define _VOUT_FUNC_H_ +#include +#include + +#define VOUTPR(fmt, args...) pr_info("vout: "fmt"", ## args) +#define VOUTERR(fmt, args...) pr_err("vout: error: "fmt"", ## args) + +/* [ 3: 2] cntl_viu2_sel_venc: + * 0=No connection, 1=ENCI, 2=ENCP, 3=ENCT. + * [ 1: 0] cntl_viu1_sel_venc: + * 0=No connection, 1=ENCI, 2=ENCP, 3=ENCT. + */ +#define VPU_VIU_VENC_MUX_CTRL 0x271a +#define VPP_POSTBLEND_H_SIZE 0x1d21 +#define VPP2_POSTBLEND_H_SIZE 0x1921 + +struct vout_cdev_s { + dev_t devno; + struct cdev cdev; + struct device *dev; +}; + +#ifdef CONFIG_AMLOGIC_HDMITX +extern int get_hpd_state(void); +#endif +extern int vout_get_hpd_state(void); + +extern struct vinfo_s *get_invalid_vinfo(int index); +extern struct vout_module_s *vout_func_get_vout_module(void); +#ifdef CONFIG_AMLOGIC_VOUT2_SERVE +extern struct vout_module_s *vout_func_get_vout2_module(void); +#endif + +extern int vout_func_set_current_vmode(int index, enum vmode_e mode); +extern enum vmode_e vout_func_validate_vmode(int index, char *name); +extern int vout_func_set_vframe_rate_hint(int index, int duration); +extern int vout_func_set_vframe_rate_end_hint(int index); +extern int vout_func_set_vframe_rate_policy(int index, int policy); +extern int vout_func_get_vframe_rate_policy(int index); +extern int vout_func_vout_suspend(int index); +extern int vout_func_vout_resume(int index); +extern int vout_func_vout_shutdown(int index); +extern int vout_func_vout_register_server(int index, + struct vout_server_s *mem_server); +extern int vout_func_vout_unregister_server(int index, + struct vout_server_s *mem_server); + + +extern int set_current_vmode(enum vmode_e); +extern enum vmode_e validate_vmode(char *p); + +extern int vout_suspend(void); +extern int vout_resume(void); +extern int vout_shutdown(void); + +#ifdef CONFIG_AMLOGIC_VOUT2_SERVE +extern int set_current_vmode2(enum vmode_e); +extern enum vmode_e validate_vmode2(char *p); + +extern int vout2_suspend(void); +extern int vout2_resume(void); +extern int vout2_shutdown(void); +#endif + +#endif diff --git a/drivers/amlogic/media/vout/vout_serve/vout_notify.c b/drivers/amlogic/media/vout/vout_serve/vout_notify.c index 6bd26c7..f63eb77 100644 --- a/drivers/amlogic/media/vout/vout_serve/vout_notify.c +++ b/drivers/amlogic/media/vout/vout_serve/vout_notify.c @@ -19,23 +19,15 @@ #include #include #include +#include /* Amlogic Headers */ #include /* Local Headers */ -#include "vout_serve.h" +#include "vout_func.h" static BLOCKING_NOTIFIER_HEAD(vout_notifier_list); -static DEFINE_MUTEX(vout_mutex); - -static struct vout_module_s vout_module = { - .vout_server_list = { - &vout_module.vout_server_list, - &vout_module.vout_server_list - }, - .curr_vout_server = NULL, -}; /** * vout_register_client - register a client notifier @@ -67,43 +59,23 @@ int vout_notifier_call_chain(unsigned long val, void *v) } EXPORT_SYMBOL_GPL(vout_notifier_call_chain); -static struct vinfo_s vinfo_invalid = { - .name = "invalid", - .mode = VMODE_INIT_NULL, - .width = 1920, - .height = 1080, - .field_height = 1080, - .aspect_ratio_num = 16, - .aspect_ratio_den = 9, - .sync_duration_num = 60, - .sync_duration_den = 1, - .video_clk = 148500000, - .viu_color_fmt = COLOR_FMT_RGB444, - .viu_mux = VIU_MUX_MAX, - .vout_device = NULL, -}; - -static struct vinfo_s *get_invalid_vinfo(void) -{ - VOUTERR("invalid vinfo. current vmode is not supported\n"); - return &vinfo_invalid; -} - /* *interface export to client who want to get current vinfo. */ struct vinfo_s *get_current_vinfo(void) { - struct vinfo_s *info = NULL; + struct vinfo_s *vinfo = NULL; + struct vout_module_s *p_module = NULL; - if (vout_module.curr_vout_server) { - if (vout_module.curr_vout_server->op.get_vinfo) - info = vout_module.curr_vout_server->op.get_vinfo(); + p_module = vout_func_get_vout_module(); + if (!IS_ERR_OR_NULL(p_module->curr_vout_server)) { + if (p_module->curr_vout_server->op.get_vinfo) + vinfo = p_module->curr_vout_server->op.get_vinfo(); } - if (info == NULL) /* avoid crash mistake */ - info = get_invalid_vinfo(); + if (vinfo == NULL) /* avoid crash mistake */ + vinfo = get_invalid_vinfo(1); - return info; + return vinfo; } EXPORT_SYMBOL(get_current_vinfo); @@ -112,13 +84,16 @@ EXPORT_SYMBOL(get_current_vinfo); */ enum vmode_e get_current_vmode(void) { - const struct vinfo_s *info; + const struct vinfo_s *vinfo; + struct vout_module_s *p_module = NULL; enum vmode_e mode = VMODE_MAX; - if (vout_module.curr_vout_server) { - if (vout_module.curr_vout_server->op.get_vinfo) { - info = vout_module.curr_vout_server->op.get_vinfo(); - mode = info->mode; + p_module = vout_func_get_vout_module(); + if (!IS_ERR_OR_NULL(p_module->curr_vout_server)) { + if (p_module->curr_vout_server->op.get_vinfo) { + vinfo = p_module->curr_vout_server->op.get_vinfo(); + if (vinfo) + mode = vinfo->mode; } } @@ -129,123 +104,46 @@ EXPORT_SYMBOL(get_current_vmode); const char *get_name_by_vmode(enum vmode_e mode) { const char *str = NULL; - const struct vinfo_s *info = NULL; + const struct vinfo_s *vinfo = NULL; + struct vout_module_s *p_module = NULL; - if (vout_module.curr_vout_server) { - if (vout_module.curr_vout_server->op.get_vinfo) { - info = vout_module.curr_vout_server->op.get_vinfo(); - str = info->name; - } + p_module = vout_func_get_vout_module(); + if (!IS_ERR_OR_NULL(p_module->curr_vout_server)) { + if (p_module->curr_vout_server->op.get_vinfo) + vinfo = p_module->curr_vout_server->op.get_vinfo(); } - if (info == NULL) - info = get_invalid_vinfo(); - str = info->name; + if (vinfo == NULL) + vinfo = get_invalid_vinfo(1); + str = vinfo->name; return str; } EXPORT_SYMBOL(get_name_by_vmode); -/* fps = 9600/duration/100 hz */ -static int vsource_fps_table[][2] = { - /* duration fps */ - {1600, 6000,}, - {1601, 5994,}, - {1602, 5994,}, - {1920, 5000,}, - {3200, 3000,}, - {3203, 2997,}, - {3840, 2500,}, - {4000, 2400,}, - {4004, 2397,}, -}; - -int get_vsource_fps(int duration) +/* + * interface export to client who want to set current vmode. + */ +int set_current_vmode(enum vmode_e mode) { - int i; - int fps = 6000; - - for (i = 0; i < 9; i++) { - if (duration == vsource_fps_table[i][0]) { - fps = vsource_fps_table[i][1]; - break; - } - } - - return fps; + return vout_func_set_current_vmode(1, mode); } +EXPORT_SYMBOL(set_current_vmode); -static struct vframe_match_s vframe_match_table_1[] = { - {5000, 5000, 50, 1}, - {2500, 5000, 50, 1}, - {6000, 6000, 60, 1}, - {3000, 6000, 60, 1}, - {2400, 6000, 60, 1}, - {2397, 5994, 5994, 100}, - {2997, 5994, 5994, 100}, - {5994, 5994, 5994, 100}, - {0, 6000, 60, 1}, -}; - -static struct vframe_match_s vframe_match_table_2[] = { - {5000, 5000, 50, 1}, - {2500, 5000, 50, 1}, - {6000, 6000, 60, 1}, - {3000, 6000, 60, 1}, - {2400, 4800, 48, 1}, - {2397, 5994, 5994, 100}, - {2997, 5994, 5994, 100}, - {5994, 5994, 5994, 100}, - {0, 6000, 60, 1}, -}; - -struct vframe_match_s *get_vframe_match(int duration, int fr_policy) +/* + *interface export to client who want to set current vmode. + */ +enum vmode_e validate_vmode(char *name) { - int i, n, fps; - struct vframe_match_s *vtable; - - fps = get_vsource_fps(duration); - - switch (fr_policy) { - case 1: - vtable = vframe_match_table_1; - n = ARRAY_SIZE(vframe_match_table_1); - break; - case 2: - vtable = vframe_match_table_2; - n = ARRAY_SIZE(vframe_match_table_2); - break; - default: - VOUTPR("%s: fr_auto_policy = %d, disabled\n", - __func__, fr_policy); - return 0; - } - for (i = 0; i < n; i++) { - if (fps == vtable[i].fps) - break; - } - VOUTPR("%s: policy = %d, duration = %d, fps = %d, frame_rate = %d\n", - __func__, fr_policy, duration, fps, vtable[i].frame_rate); - - return &vtable[i]; + return vout_func_validate_vmode(1, name); } -EXPORT_SYMBOL(get_vframe_match); +EXPORT_SYMBOL(validate_vmode); /* *interface export to client who want to notify about source frame rate. */ int set_vframe_rate_hint(int duration) { - int r = -1; - struct vout_server_s *p_server = vout_module.curr_vout_server; - - if (p_server) { - if ((p_server->op.set_vframe_rate_hint != NULL) && - (p_server->op.set_vframe_rate_hint(duration) == 0)) { - return 0; - } - } - - return r; + return vout_func_set_vframe_rate_hint(1, duration); } EXPORT_SYMBOL(set_vframe_rate_hint); @@ -254,17 +152,7 @@ EXPORT_SYMBOL(set_vframe_rate_hint); */ int set_vframe_rate_end_hint(void) { - int ret = -1; - struct vout_server_s *p_server = vout_module.curr_vout_server; - - if (p_server) { - if ((p_server->op.set_vframe_rate_end_hint != NULL) && - (p_server->op.set_vframe_rate_end_hint() == 0)) { - return 0; - } - } - - return ret; + return vout_func_set_vframe_rate_end_hint(1); } EXPORT_SYMBOL(set_vframe_rate_end_hint); @@ -273,17 +161,7 @@ EXPORT_SYMBOL(set_vframe_rate_end_hint); */ int set_vframe_rate_policy(int policy) { - int ret = -1; - struct vout_server_s *p_server = vout_module.curr_vout_server; - - if (p_server) { - if ((p_server->op.set_vframe_rate_policy != NULL) && - (p_server->op.set_vframe_rate_policy(policy) == 0)) { - return 0; - } - } - - return ret; + return vout_func_set_vframe_rate_policy(1, policy); } EXPORT_SYMBOL(set_vframe_rate_policy); @@ -292,17 +170,7 @@ EXPORT_SYMBOL(set_vframe_rate_policy); */ int get_vframe_rate_policy(void) { - int ret = -1; - struct vout_server_s *p_server = vout_module.curr_vout_server; - - if (p_server) { - if (p_server->op.get_vframe_rate_policy != NULL) { - ret = p_server->op.get_vframe_rate_policy(); - return ret; - } - } - - return ret; + return vout_func_get_vframe_rate_policy(1); } EXPORT_SYMBOL(get_vframe_rate_policy); @@ -317,7 +185,6 @@ void wakeup_early_suspend_proc(void) int vout_suspend(void) { int ret = 0; - struct vout_server_s *p_server = vout_module.curr_vout_server; #ifdef CONFIG_SCREEN_ON_EARLY wake_up_flag = 0; @@ -332,101 +199,23 @@ int vout_suspend(void) wake_up_flag = 0; #endif - mutex_lock(&vout_mutex); - - if (p_server) { - if (p_server->op.vout_suspend) - ret = p_server->op.vout_suspend(); - } - - mutex_unlock(&vout_mutex); + ret = vout_func_vout_suspend(1); return ret; } EXPORT_SYMBOL(vout_suspend); int vout_resume(void) { - struct vout_server_s *p_server = vout_module.curr_vout_server; - - mutex_lock(&vout_mutex); - - if (p_server) { - if (p_server->op.vout_resume) { - /* ignore error when resume. */ - p_server->op.vout_resume(); - } - } - - mutex_unlock(&vout_mutex); - return 0; + return vout_func_vout_resume(1); } EXPORT_SYMBOL(vout_resume); /* - * interface export to client who want to set current vmode. - */ -int set_current_vmode(enum vmode_e mode) -{ - int ret = -1; - struct vout_server_s *p_server; - - mutex_lock(&vout_mutex); - list_for_each_entry(p_server, &vout_module.vout_server_list, list) { - if (p_server->op.vmode_is_supported == NULL) { - p_server->op.disable(mode); - continue; - } - - if (p_server->op.vmode_is_supported(mode) == true) { - vout_module.curr_vout_server = p_server; - ret = p_server->op.set_vmode(mode); - /* break; do not exit , should disable other modules */ - } else - p_server->op.disable(mode); - } - - mutex_unlock(&vout_mutex); - - return ret; -} -EXPORT_SYMBOL(set_current_vmode); - -/* - *interface export to client who want to set current vmode. - */ -enum vmode_e validate_vmode(char *name) -{ - enum vmode_e ret = VMODE_MAX; - struct vout_server_s *p_server; - - mutex_lock(&vout_mutex); - list_for_each_entry(p_server, &vout_module.vout_server_list, list) { - if (p_server->op.validate_vmode) - ret = p_server->op.validate_vmode(name); - - if (ret != VMODE_MAX) /* valid vmode find. */ - break; - } - mutex_unlock(&vout_mutex); - - return ret; -} -EXPORT_SYMBOL(validate_vmode); - -/* *interface export to client who want to shutdown. */ int vout_shutdown(void) { - int ret = -1; - struct vout_server_s *p_server; - - list_for_each_entry(p_server, &vout_module.vout_server_list, list) { - if (p_server->op.vout_shutdown) - ret = p_server->op.vout_shutdown(); - } - - return ret; + return vout_func_vout_shutdown(1); } EXPORT_SYMBOL(vout_shutdown); @@ -436,64 +225,14 @@ EXPORT_SYMBOL(vout_shutdown); *we can ensure TVMOD SET MODULE independent with these two function. */ - int vout_register_server(struct vout_server_s *mem_server) { - struct list_head *p_iter; - struct vout_server_s *p_server; - - if (mem_server == NULL) { - VOUTERR("%s: server is NULL\n", __func__); - return -1; - } - VOUTPR("%s\n", __func__); - - mutex_lock(&vout_mutex); - list_for_each(p_iter, &vout_module.vout_server_list) { - p_server = list_entry(p_iter, struct vout_server_s, list); - - if (p_server->name && mem_server->name && - strcmp(p_server->name, mem_server->name) == 0) { - /* vout server already registered. */ - mutex_unlock(&vout_mutex); - return -1; - } - } - list_add(&mem_server->list, &vout_module.vout_server_list); - mutex_unlock(&vout_mutex); - return 0; + return vout_func_vout_register_server(1, mem_server); } EXPORT_SYMBOL(vout_register_server); int vout_unregister_server(struct vout_server_s *mem_server) { - struct vout_server_s *p_server; - - if (mem_server == NULL) { - VOUTERR("%s: server is NULL\n", __func__); - return -1; - } - - mutex_lock(&vout_mutex); - list_for_each_entry(p_server, &vout_module.vout_server_list, list) { - if (p_server->name && mem_server->name && - strcmp(p_server->name, mem_server->name) == 0) { - /* - * We will not move current vout server pointer - * automatically if current vout server pointer - * is the one which will be deleted next. - * So you should change current vout server - * first then remove it - */ - if (vout_module.curr_vout_server == p_server) - vout_module.curr_vout_server = NULL; - - list_del(&mem_server->list); - mutex_unlock(&vout_mutex); - return 0; - } - } - mutex_unlock(&vout_mutex); - return 0; + return vout_func_vout_unregister_server(1, mem_server); } EXPORT_SYMBOL(vout_unregister_server); diff --git a/drivers/amlogic/media/vout/vout_serve/vout_serve.c b/drivers/amlogic/media/vout/vout_serve/vout_serve.c index 27c7648..04ed883 100644 --- a/drivers/amlogic/media/vout/vout_serve/vout_serve.c +++ b/drivers/amlogic/media/vout/vout_serve/vout_serve.c @@ -38,12 +38,9 @@ /* Amlogic Headers */ #include -#ifdef CONFIG_AMLOGIC_HDMITX -#include -#endif /* Local Headers */ -#include "vout_serve.h" +#include "vout_func.h" #ifdef CONFIG_AMLOGIC_LEGACY_EARLY_SUSPEND #include @@ -60,7 +57,7 @@ static int early_resume_flag; #define VMODE_NAME_LEN_MAX 64 static struct class *vout_class; -static DEFINE_MUTEX(vout_mutex); +static DEFINE_MUTEX(vout_serve_mutex); static char vout_mode_uboot[VMODE_NAME_LEN_MAX] __nosavedata; static char vout_mode[VMODE_NAME_LEN_MAX] __nosavedata; static char local_name[VMODE_NAME_LEN_MAX] = {0}; @@ -87,13 +84,95 @@ static const unsigned int vout_cable[] = { EXTCON_NONE, }; -struct vout_cdev_s { - dev_t devno; - struct cdev cdev; - struct device *dev; +static struct vout_cdev_s *vout_cdev; + +/* ********************************************************** + * null display support + * ********************************************************** + */ +static struct vinfo_s nulldisp_vinfo = { + .name = "null", + .mode = VMODE_NULL, + .width = 1920, + .height = 1080, + .field_height = 1080, + .aspect_ratio_num = 16, + .aspect_ratio_den = 9, + .sync_duration_num = 60, + .sync_duration_den = 1, + .video_clk = 148500000, + .htotal = 2200, + .vtotal = 1125, + .viu_color_fmt = COLOR_FMT_RGB444, + .viu_mux = VIU_MUX_MAX, + .vout_device = NULL, }; -static struct vout_cdev_s *vout_cdev; +static struct vinfo_s *nulldisp_get_current_info(void) +{ + return &nulldisp_vinfo; +} + +static int nulldisp_set_current_vmode(enum vmode_e mode) +{ + return 0; +} + +static enum vmode_e nulldisp_validate_vmode(char *name) +{ + if (strncmp(nulldisp_vinfo.name, name, + strlen(nulldisp_vinfo.name)) == 0) { + return nulldisp_vinfo.mode; + } + + return VMODE_MAX; +} + +static int nulldisp_vmode_is_supported(enum vmode_e mode) +{ + if (nulldisp_vinfo.mode == mode) + return true; + return false; +} + +static int nulldisp_disable(enum vmode_e cur_vmod) +{ + return 0; +} + +static int nulldisp_vout_state; +static int nulldisp_vout_set_state(int bit) +{ + nulldisp_vout_state |= (1 << bit); + return 0; +} + +static int nulldisp_vout_clr_state(int bit) +{ + nulldisp_vout_state &= ~(1 << bit); + return 0; +} + +static int nulldisp_vout_get_state(void) +{ + return nulldisp_vout_state; +} + +static struct vout_server_s nulldisp_vout_server = { + .name = "nulldisp_vout_server", + .op = { + .get_vinfo = nulldisp_get_current_info, + .set_vmode = nulldisp_set_current_vmode, + .validate_vmode = nulldisp_validate_vmode, + .vmode_is_supported = nulldisp_vmode_is_supported, + .disable = nulldisp_disable, + .set_state = nulldisp_vout_set_state, + .clr_state = nulldisp_vout_clr_state, + .get_state = nulldisp_vout_get_state, + }, +}; + +/* ********************************************************** */ char *get_vout_mode_internal(void) { @@ -249,11 +328,11 @@ static ssize_t vout_mode_store(struct class *class, { char mode[64]; - mutex_lock(&vout_mutex); + mutex_lock(&vout_serve_mutex); tvout_monitor_flag = 0; snprintf(mode, VMODE_NAME_LEN_MAX, "%s", buf); set_vout_mode(mode); - mutex_unlock(&vout_mutex); + mutex_unlock(&vout_serve_mutex); return count; } @@ -269,10 +348,10 @@ static ssize_t vout_axis_show(struct class *class, static ssize_t vout_axis_store(struct class *class, struct class_attribute *attr, const char *buf, size_t count) { - mutex_lock(&vout_mutex); + mutex_lock(&vout_serve_mutex); snprintf(vout_axis, 64, "%s", buf); set_vout_axis(vout_axis); - mutex_unlock(&vout_mutex); + mutex_unlock(&vout_serve_mutex); return count; } @@ -294,17 +373,17 @@ static ssize_t vout_fr_policy_store(struct class *class, int policy; int ret = 0; - mutex_lock(&vout_mutex); + mutex_lock(&vout_serve_mutex); ret = kstrtoint(buf, 10, &policy); if (ret) { pr_info("%s: invalid data\n", __func__); - mutex_unlock(&vout_mutex); + mutex_unlock(&vout_serve_mutex); return -EINVAL; } ret = set_vframe_rate_policy(policy); if (ret) pr_info("%s: %d failed\n", __func__, policy); - mutex_unlock(&vout_mutex); + mutex_unlock(&vout_serve_mutex); return count; } @@ -398,11 +477,13 @@ static int vout_attr_create(void) /* create vout class attr files */ for (i = 0; i < ARRAY_SIZE(vout_class_attrs); i++) { if (class_create_file(vout_class, &vout_class_attrs[i])) { - VOUTERR("create attribute %s fail\n", + VOUTERR("create vout attribute %s fail\n", vout_class_attrs[i].attr.name); } } + VOUTPR("create vout attribute OK\n"); + return ret; } @@ -523,7 +604,7 @@ static int vout_fops_create(void) ret = alloc_chrdev_region(&vout_cdev->devno, 0, 1, VOUT_CDEV_NAME); if (ret < 0) { - VOUTERR("failed to alloc devno\n"); + VOUTERR("failed to alloc vout devno\n"); goto vout_fops_err1; } @@ -531,7 +612,7 @@ static int vout_fops_create(void) vout_cdev->cdev.owner = THIS_MODULE; ret = cdev_add(&vout_cdev->cdev, vout_cdev->devno, 1); if (ret) { - VOUTERR("failed to add cdev\n"); + VOUTERR("failed to add vout cdev\n"); goto vout_fops_err2; } @@ -539,7 +620,7 @@ static int vout_fops_create(void) NULL, VOUT_CDEV_NAME); if (IS_ERR(vout_cdev->dev)) { ret = PTR_ERR(vout_cdev->dev); - VOUTERR("failed to create device: %d\n", ret); + VOUTERR("failed to create vout device: %d\n", ret); goto vout_fops_err3; } @@ -677,9 +758,7 @@ static int refresh_tvout_mode(void) if (tvout_monitor_flag == 0) return 0; -#ifdef CONFIG_AMLOGIC_HDMITX - hpd_state = get_hpd_state(); -#endif + hpd_state = vout_get_hpd_state(); if (hpd_state) { cur_vmode = validate_vmode(hdmimode); cur_mode_str = hdmimode; @@ -714,9 +793,9 @@ static void aml_tvout_mode_work(struct work_struct *work) return; } - mutex_lock(&vout_mutex); + mutex_lock(&vout_serve_mutex); refresh_tvout_mode(); - mutex_unlock(&vout_mutex); + mutex_unlock(&vout_serve_mutex); if (tvout_monitor_flag) schedule_delayed_work(&tvout_mode_work, 1*HZ/2); @@ -734,9 +813,9 @@ static void aml_tvout_mode_monitor(void) tvout_monitor_flag = 1; INIT_DELAYED_WORK(&tvout_mode_work, aml_tvout_mode_work); - mutex_lock(&vout_mutex); + mutex_lock(&vout_serve_mutex); refresh_tvout_mode(); - mutex_unlock(&vout_mutex); + mutex_unlock(&vout_serve_mutex); schedule_delayed_work(&tvout_mode_work, 1*HZ/2); } @@ -749,7 +828,7 @@ static void aml_vout_extcon_register(struct platform_device *pdev) /*set display mode*/ edev = extcon_dev_allocate(vout_cable); if (IS_ERR(edev)) { - VOUTERR("failed to allocate extcon setmode\n"); + VOUTERR("failed to allocate vout extcon setmode\n"); return; } @@ -758,7 +837,7 @@ static void aml_vout_extcon_register(struct platform_device *pdev) dev_set_name(&edev->dev, "setmode"); ret = extcon_dev_register(edev); if (ret) { - VOUTERR("failed to register extcon setmode\n"); + VOUTERR("failed to register vout extcon setmode\n"); return; } vout_excton_setmode = edev; @@ -786,16 +865,12 @@ static int aml_vout_probe(struct platform_device *pdev) register_early_suspend(&early_suspend); #endif - set_vout_init_mode(); - vout_class = NULL; ret = vout_attr_create(); ret = vout_fops_create(); - if (ret == 0) - VOUTPR("create vout attribute OK\n"); - else - VOUTERR("create vout attribute FAILED\n"); + vout_register_server(&nulldisp_vout_server); + set_vout_init_mode(); aml_vout_extcon_register(pdev); aml_tvout_mode_monitor(); @@ -813,6 +888,7 @@ static int aml_vout_remove(struct platform_device *pdev) aml_vout_extcon_free(); vout_attr_remove(); vout_fops_remove(); + vout_unregister_server(&nulldisp_vout_server); return 0; } diff --git a/drivers/amlogic/media/vout/vout_serve/vout_serve.h b/drivers/amlogic/media/vout/vout_serve/vout_serve.h deleted file mode 100644 index 9e5595b..0000000 --- a/drivers/amlogic/media/vout/vout_serve/vout_serve.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * drivers/amlogic/media/vout/vout_serve/vout_serve.h - * - * Copyright (C) 2017 Amlogic, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - */ - -#ifndef _VOUT_SERVE_H_ -#define _VOUT_SERVE_H_ - -#include -#include - -#define VOUTPR(fmt, args...) pr_info("vout: "fmt"", ## args) -#define VOUTERR(fmt, args...) pr_err("vout: error: "fmt"", ## args) - -#endif diff --git a/include/linux/amlogic/media/video_sink/video.h b/include/linux/amlogic/media/video_sink/video.h index 1011c90..6bca070 100644 --- a/include/linux/amlogic/media/video_sink/video.h +++ b/include/linux/amlogic/media/video_sink/video.h @@ -263,8 +263,6 @@ int get_video0_frame_info(struct vframe_s *vf); #define AMVIDEO_UPDATE_OSD_MODE 0x00000001 -extern enum vmode_e get_logo_vmode(void); - int query_video_status(int type, int *value); int get_video0_frame_info(struct vframe_s *vf); int amvideo_notifier_call_chain(unsigned long val, void *v); diff --git a/include/linux/amlogic/media/vout/lcd/lcd_vout.h b/include/linux/amlogic/media/vout/lcd/lcd_vout.h index 410f079..0d55a59 100644 --- a/include/linux/amlogic/media/vout/lcd/lcd_vout.h +++ b/include/linux/amlogic/media/vout/lcd/lcd_vout.h @@ -425,6 +425,10 @@ struct aml_lcd_drv_s { struct lcd_config_s *lcd_config; struct vinfo_s *lcd_info; struct class *lcd_debug_class; + struct vout_server_s *vout_server; +#ifdef CONFIG_AMLOGIC_VOUT2_SERVE + struct vout_server_s *vout2_server; +#endif int fr_auto_policy; struct lcd_duration_s std_duration; diff --git a/include/linux/amlogic/media/vout/vinfo.h b/include/linux/amlogic/media/vout/vinfo.h index 0d2536a..c4ce992 100644 --- a/include/linux/amlogic/media/vout/vinfo.h +++ b/include/linux/amlogic/media/vout/vinfo.h @@ -35,9 +35,9 @@ enum vmode_e { }; enum viu_mux_e { - VIU_MUX_ENCI = 0, + VIU_MUX_ENCL = 0, + VIU_MUX_ENCI, VIU_MUX_ENCP, - VIU_MUX_ENCL, VIU_MUX_MAX, }; diff --git a/include/linux/amlogic/media/vout/vout_notify.h b/include/linux/amlogic/media/vout/vout_notify.h index eea99e0..cecb5bb 100644 --- a/include/linux/amlogic/media/vout/vout_notify.h +++ b/include/linux/amlogic/media/vout/vout_notify.h @@ -39,6 +39,9 @@ struct vout_op_s { enum vmode_e (*validate_vmode)(char *); int (*vmode_is_supported)(enum vmode_e); int (*disable)(enum vmode_e); + int (*set_state)(int); + int (*clr_state)(int); + int (*get_state)(void); int (*set_vframe_rate_hint)(int); int (*set_vframe_rate_end_hint)(void); int (*set_vframe_rate_policy)(int); @@ -61,27 +64,40 @@ struct vout_module_s { extern int vout_register_client(struct notifier_block *p); extern int vout_unregister_client(struct notifier_block *p); +extern int vout_notifier_call_chain(unsigned int long, void *p); extern int vout_register_server(struct vout_server_s *p); extern int vout_unregister_server(struct vout_server_s *p); -extern int vout_notifier_call_chain(unsigned int long, void *p); extern struct vinfo_s *get_current_vinfo(void); extern enum vmode_e get_current_vmode(void); -extern int set_current_vmode(enum vmode_e); -extern enum vmode_e validate_vmode(char *p); -extern int get_vsource_fps(int duration); extern int set_vframe_rate_hint(int duration); extern int set_vframe_rate_end_hint(void); extern int set_vframe_rate_policy(int pol); extern int get_vframe_rate_policy(void); +#ifdef CONFIG_AMLOGIC_VOUT2_SERVE +extern int vout2_register_client(struct notifier_block *p); +extern int vout2_unregister_client(struct notifier_block *p); +extern int vout2_notifier_call_chain(unsigned int long, void *p); +extern int vout2_register_server(struct vout_server_s *p); +extern int vout2_unregister_server(struct vout_server_s *p); + +extern struct vinfo_s *get_current_vinfo2(void); +extern enum vmode_e get_current_vmode2(void); +extern int set_vframe2_rate_hint(int duration); +extern int set_vframe2_rate_end_hint(void); +extern int set_vframe2_rate_policy(int pol); +extern int get_vframe2_rate_policy(void); + +#endif + +extern int vout_get_vsource_fps(int duration); + /* vdac ctrl,adc/dac ref signal,cvbs out signal * module index: atv demod:0x01; dtv demod:0x02; tvafe:0x4; dac:0x8 */ extern void vdac_enable(bool on, unsigned int module_sel); -extern int vout_suspend(void); -extern int vout_resume(void); -extern int vout_shutdown(void); + #define VOUT_EVENT_MODE_CHANGE_PRE 0x00010000 #define VOUT_EVENT_MODE_CHANGE 0x00020000 @@ -100,11 +116,7 @@ extern int vout_shutdown(void); _IOW(VOUT_IOC_TYPE, VOUT_IOC_NR_SET_VINFO, struct vinfo_base_s) /* ******************************** */ -extern void update_vout_mode(char *name); - extern char *get_vout_mode_internal(void); extern char *get_vout_mode_uboot(void); -extern enum vmode_e get_logo_vmode(void); - #endif /* _VOUT_NOTIFY_H_ */ -- 2.7.4