/* SPDX-License-Identifier: GPL-2.0 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rockchip_drm_drv.h" #include "rockchip_drm_tve.h" #include "rockchip_drm_vop.h" #define RK322X_VDAC_STANDARD 0x15 static const struct drm_display_mode cvbs_mode[] = { { DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500, 720, 753, 816, 864, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), 0, }, { DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500, 720, 753, 815, 858, 0, 480, 480, 486, 525, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), 0, }, }; struct env_config { u32 offset; u32 value; }; static struct env_config ntsc_bt656_config[] = { { BT656_DECODER_CROP, 0x00000000 }, { BT656_DECODER_SIZE, 0x01e002d0 }, { BT656_DECODER_HTOTAL_HS_END, 0x035a003e }, { BT656_DECODER_VACT_ST_HACT_ST, 0x00160069 }, { BT656_DECODER_VTOTAL_VS_END, 0x020d0003 }, { BT656_DECODER_VS_ST_END_F1, 0x01060109 }, { BT656_DECODER_DBG_REG, 0x024002d0 }, { BT656_DECODER_CTRL, 0x00000009 }, }; static struct env_config ntsc_tve_config[] = { { TVE_MODE_CTRL, 0x000af906 }, { TVE_HOR_TIMING1, 0x00c07a81 }, { TVE_HOR_TIMING2, 0x169810fc }, { TVE_HOR_TIMING3, 0x96b40000 }, { TVE_SUB_CAR_FRQ, 0x21f07bd7 }, { TVE_IMAGE_POSITION, 0x001500d6 }, { TVE_ROUTING, 0x10088880 }, { TVE_SYNC_ADJUST, 0x00000000 }, { TVE_STATUS, 0x00000000 }, { TVE_CTRL, 0x00000000 }, { TVE_INTR_STATUS, 0x00000000 }, { TVE_INTR_EN, 0x00000000 }, { TVE_INTR_CLR, 0x00000000 }, { TVE_COLOR_BUSRT_SAT, 0x0052543c }, { TVE_CHROMA_BANDWIDTH, 0x00000002 }, { TVE_BRIGHTNESS_CONTRAST, 0x00008300 }, { TVE_CLAMP, 0x00000000 }, }; static struct env_config pal_bt656_config[] = { { BT656_DECODER_CROP, 0x00000000 }, { BT656_DECODER_SIZE, 0x024002d0 }, { BT656_DECODER_HTOTAL_HS_END, 0x0360003f }, { BT656_DECODER_VACT_ST_HACT_ST, 0x0016006f }, { BT656_DECODER_VTOTAL_VS_END, 0x02710003 }, { BT656_DECODER_VS_ST_END_F1, 0x0138013b }, { BT656_DECODER_DBG_REG, 0x024002d0 }, { BT656_DECODER_CTRL, 0x00000009 }, }; static struct env_config pal_tve_config[] = { { TVE_MODE_CTRL, 0x010ab906 }, { TVE_HOR_TIMING1, 0x00c28381 }, { TVE_HOR_TIMING2, 0x267d111d }, { TVE_HOR_TIMING3, 0x66c00880 }, { TVE_SUB_CAR_FRQ, 0x2a098acb }, { TVE_IMAGE_POSITION, 0x001500f6 }, { TVE_ROUTING, 0x10008882 }, { TVE_SYNC_ADJUST, 0x00000000 }, { TVE_STATUS, 0x000000b0 }, { TVE_CTRL, 0x00000000 }, { TVE_INTR_STATUS, 0x00000000 }, { TVE_INTR_EN, 0x00000000 }, { TVE_INTR_CLR, 0x00000000 }, { TVE_COLOR_BUSRT_SAT, 0x00356245 }, { TVE_CHROMA_BANDWIDTH, 0x00000022 }, { TVE_BRIGHTNESS_CONTRAST, 0x0000aa00 }, { TVE_CLAMP, 0x00000000 }, }; #define BT656_ENV_CONFIG_SIZE (sizeof(ntsc_bt656_config) / sizeof(struct env_config)) #define TVE_ENV_CONFIG_SIZE (sizeof(ntsc_tve_config) / sizeof(struct env_config)) #define tve_writel(offset, v) writel_relaxed(v, tve->regbase + (offset)) #define tve_readl(offset) readl_relaxed(tve->regbase + (offset)) #define tve_dac_writel(offset, v) writel_relaxed(v, tve->vdacbase + (offset)) #define tve_dac_readl(offset) readl_relaxed(tve->vdacbase + (offset)) #define tve_dac_grf_writel(offset, v) regmap_write(tve->dac_grf, offset, v) #define tve_dac_grf_readl(offset, v) regmap_read(tve->dac_grf, offset, v) #define connector_to_tve(x) container_of(x, struct rockchip_tve, connector) #define encoder_to_tve(x) container_of(x, struct rockchip_tve, encoder) struct rockchip_tve_data { int input_format; int soc_type; }; static void tve_write_block(struct rockchip_tve *tve, struct env_config *config, int len) { int i; for (i = 0; i < len; i++) tve_writel(config[i].offset, config[i].value); } static int rockchip_tve_get_modes(struct drm_connector *connector) { int count; struct rockchip_tve *tve = connector_to_tve(connector); for (count = 0; count < ARRAY_SIZE(cvbs_mode); count++) { struct drm_display_mode *mode_ptr; mode_ptr = drm_mode_duplicate(connector->dev, &cvbs_mode[count]); if (tve->preferred_mode == count) mode_ptr->type |= DRM_MODE_TYPE_PREFERRED; drm_mode_probed_add(connector, mode_ptr); } return count; } static enum drm_mode_status rockchip_tve_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { return MODE_OK; } static struct drm_encoder *rockchip_tve_best_encoder(struct drm_connector *connector) { struct rockchip_tve *tve = connector_to_tve(connector); return &tve->encoder; } static void rockchip_encoder_destroy(struct drm_encoder *encoder) { drm_encoder_cleanup(encoder); } static enum drm_connector_status rockchip_tve_connector_detect(struct drm_connector *connector, bool force) { return connector_status_connected; } static void rockchip_tve_connector_destroy(struct drm_connector *connector) { drm_connector_cleanup(connector); } static void tve_set_mode(struct rockchip_tve *tve) { struct env_config *bt656_cfg, *tve_cfg; int mode = tve->tv_format; if (tve->soc_type == SOC_RK3528) { tve_writel(TVE_LUMA_FILTER1, tve->lumafilter0); tve_writel(TVE_LUMA_FILTER2, tve->lumafilter1); tve_writel(TVE_LUMA_FILTER3, tve->lumafilter2); tve_writel(TVE_LUMA_FILTER4, tve->lumafilter3); tve_writel(TVE_LUMA_FILTER5, tve->lumafilter4); tve_writel(TVE_LUMA_FILTER6, tve->lumafilter5); tve_writel(TVE_LUMA_FILTER7, tve->lumafilter6); tve_writel(TVE_LUMA_FILTER8, tve->lumafilter7); } else { dev_dbg(tve->dev, "tve set mode:%d\n", mode); if (tve->input_format == INPUT_FORMAT_RGB) tve_writel(TV_CTRL, v_CVBS_MODE(mode) | v_CLK_UPSTREAM_EN(2) | v_TIMING_EN(2) | v_LUMA_FILTER_GAIN(0) | v_LUMA_FILTER_UPSAMPLE(1) | v_CSC_PATH(0)); else tve_writel(TV_CTRL, v_CVBS_MODE(mode) | v_CLK_UPSTREAM_EN(2) | v_TIMING_EN(2) | v_LUMA_FILTER_GAIN(0) | v_LUMA_FILTER_UPSAMPLE(1) | v_CSC_PATH(3)); tve_writel(TV_LUMA_FILTER0, tve->lumafilter0); tve_writel(TV_LUMA_FILTER1, tve->lumafilter1); tve_writel(TV_LUMA_FILTER2, tve->lumafilter2); } if (mode == TVOUT_CVBS_NTSC) { dev_dbg(tve->dev, "NTSC MODE\n"); if (tve->soc_type == SOC_RK3528) { bt656_cfg = ntsc_bt656_config; tve_cfg = ntsc_tve_config; tve_write_block(tve, bt656_cfg, BT656_ENV_CONFIG_SIZE); tve_write_block(tve, tve_cfg, TVE_ENV_CONFIG_SIZE); } else { tve_writel(TV_ROUTING, v_DAC_SENSE_EN(0) | v_Y_IRE_7_5(1) | v_Y_AGC_PULSE_ON(0) | v_Y_VIDEO_ON(1) | v_YPP_MODE(1) | v_Y_SYNC_ON(1) | v_PIC_MODE(mode)); tve_writel(TV_BW_CTRL, v_CHROMA_BW(BP_FILTER_NTSC) | v_COLOR_DIFF_BW(COLOR_DIFF_FILTER_BW_1_3)); tve_writel(TV_SATURATION, 0x0042543C); if (tve->test_mode) tve_writel(TV_BRIGHTNESS_CONTRAST, 0x00008300); else tve_writel(TV_BRIGHTNESS_CONTRAST, 0x00007900); tve_writel(TV_FREQ_SC, 0x21F07BD7); tve_writel(TV_SYNC_TIMING, 0x00C07a81); tve_writel(TV_ADJ_TIMING, 0x96B40000 | 0x70); tve_writel(TV_ACT_ST, 0x001500D6); tve_writel(TV_ACT_TIMING, 0x069800FC | (1 << 12) | (1 << 28)); } } else if (mode == TVOUT_CVBS_PAL) { dev_dbg(tve->dev, "PAL MODE\n"); if (tve->soc_type == SOC_RK3528) { bt656_cfg = pal_bt656_config; tve_cfg = pal_tve_config; tve_write_block(tve, bt656_cfg, BT656_ENV_CONFIG_SIZE); tve_write_block(tve, tve_cfg, TVE_ENV_CONFIG_SIZE); } else { tve_writel(TV_ROUTING, v_DAC_SENSE_EN(0) | v_Y_IRE_7_5(0) | v_Y_AGC_PULSE_ON(0) | v_Y_VIDEO_ON(1) | v_YPP_MODE(1) | v_Y_SYNC_ON(1) | v_PIC_MODE(mode)); tve_writel(TV_BW_CTRL, v_CHROMA_BW(BP_FILTER_PAL) | v_COLOR_DIFF_BW(COLOR_DIFF_FILTER_BW_1_3)); tve_writel(TV_SATURATION, tve->saturation); tve_writel(TV_BRIGHTNESS_CONTRAST, tve->brightcontrast); tve_writel(TV_FREQ_SC, 0x2A098ACB); tve_writel(TV_SYNC_TIMING, 0x00C28381); tve_writel(TV_ADJ_TIMING, (0xc << 28) | 0x06c00800 | 0x80); tve_writel(TV_ACT_ST, 0x001500F6); tve_writel(TV_ACT_TIMING, 0x0694011D | (1 << 12) | (2 << 28)); tve_writel(TV_ADJ_TIMING, tve->adjtiming); tve_writel(TV_ACT_TIMING, 0x0694011D | (1 << 12) | (2 << 28)); } } if (tve->soc_type == SOC_RK3528) { u32 upsample_mode = 0; u32 mask = 0; u32 val = 0; bool upsample_en; upsample_en = tve->upsample_mode ? 1 : 0; if (upsample_en) upsample_mode = tve->upsample_mode - 1; mask = m_TVE_DCLK_POL | m_TVE_DCLK_EN | m_DCLK_UPSAMPLE_2X4X | m_DCLK_UPSAMPLE_EN | m_TVE_MODE | m_TVE_EN; val = v_TVE_DCLK_POL(0) | v_TVE_DCLK_EN(1) | v_DCLK_UPSAMPLE_2X4X(upsample_mode) | v_DCLK_UPSAMPLE_EN(upsample_en) | v_TVE_MODE(tve->tv_format) | v_TVE_EN(1); tve_dac_grf_writel(RK3528_VO_GRF_CVBS_CON, (mask << 16) | val); } } static void dac_init(struct rockchip_tve *tve) { tve_dac_writel(VDAC_VDAC1, v_CUR_REG(tve->dac1level) | m_DR_PWR_DOWN | m_BG_PWR_DOWN); tve_dac_writel(VDAC_VDAC2, v_CUR_CTR(tve->daclevel)); tve_dac_writel(VDAC_VDAC3, v_CAB_EN(0)); } static void dac_enable(struct rockchip_tve *tve, bool enable) { u32 mask = 0; u32 val = 0; u32 grfreg = 0; u32 offset = 0; if (enable) { dev_dbg(tve->dev, "dac enable\n"); if (tve->soc_type == SOC_RK3036) { mask = m_VBG_EN | m_DAC_EN | m_DAC_GAIN; val = m_VBG_EN | m_DAC_EN | v_DAC_GAIN(tve->daclevel); grfreg = RK3036_GRF_SOC_CON3; } else if (tve->soc_type == SOC_RK312X) { mask = m_VBG_EN | m_DAC_EN | m_DAC_GAIN; val = m_VBG_EN | m_DAC_EN | v_DAC_GAIN(tve->daclevel); grfreg = RK312X_GRF_TVE_CON; } else if (tve->soc_type == SOC_RK322X || tve->soc_type == SOC_RK3328) { val = v_CUR_REG(tve->dac1level) | v_DR_PWR_DOWN(0) | v_BG_PWR_DOWN(0); offset = VDAC_VDAC1; } else if (tve->soc_type == SOC_RK3528) { /* * Reset the vdac */ tve_dac_writel(VDAC_CLK_RST, v_ANALOG_RST(0) | v_DIGITAL_RST(0)); msleep(20); tve_dac_writel(VDAC_CLK_RST, v_ANALOG_RST(1) | v_DIGITAL_RST(1)); tve_dac_writel(VDAC_CURRENT_CTRL, v_OUT_CURRENT(tve->vdac_out_current)); val = v_REF_VOLTAGE(7) | v_DAC_PWN(1) | v_BIAS_PWN(1); offset = VDAC_PWM_REF_CTRL; } } else { dev_dbg(tve->dev, "dac disable\n"); if (tve->soc_type == SOC_RK312X) { mask = m_VBG_EN | m_DAC_EN; grfreg = RK312X_GRF_TVE_CON; } else if (tve->soc_type == SOC_RK3036) { mask = m_VBG_EN | m_DAC_EN; grfreg = RK3036_GRF_SOC_CON3; } else if (tve->soc_type == SOC_RK322X || tve->soc_type == SOC_RK3328) { val = v_CUR_REG(tve->dac1level) | m_DR_PWR_DOWN | m_BG_PWR_DOWN; offset = VDAC_VDAC1; } else if (tve->soc_type == SOC_RK3528) { val = v_DAC_PWN(0) | v_BIAS_PWN(0); offset = VDAC_PWM_REF_CTRL; } } if (grfreg) tve_dac_grf_writel(grfreg, (mask << 16) | val); else if (tve->vdacbase) tve_dac_writel(offset, val); } static int cvbs_set_disable(struct rockchip_tve *tve) { int ret = 0; dev_dbg(tve->dev, "%s\n", __func__); if (!tve->enable) return 0; ret = pm_runtime_put(tve->dev); if (ret < 0) { dev_err(tve->dev, "failed to put pm runtime: %d\n", ret); return ret; } dac_enable(tve, false); tve->enable = 0; return 0; } /* * RK3528 supports bt656 to cvbs, and the others support rgb to cvbs. * * ┌──────────┐ * │ rgb data ├─────────────────────────────────────┐ * └──────────┘ │ * ▼ * ┌────────────┐ ┌───────────────┐ ┌───────────────────┐ ┌──────┐ ┌────────┐ * │ bt656 data ├───►│ bt656 decoder ├───►│ cvbs(tve) encoder ├───►│ vdac ├───►│ screen │ * └────────────┘ └───────────────┘ └───────────────────┘ └──────┘ └────────┘ * */ static int cvbs_set_enable(struct rockchip_tve *tve) { int ret = 0; dev_dbg(tve->dev, "%s\n", __func__); if (tve->enable) return 0; ret = pm_runtime_get_sync(tve->dev); if (ret < 0) { dev_err(tve->dev, "failed to get pm runtime: %d\n", ret); return ret; } tve_set_mode(tve); msleep(1000); dac_enable(tve, true); tve->enable = 1; return 0; } static void rockchip_tve_encoder_enable(struct drm_encoder *encoder) { struct rockchip_tve *tve = encoder_to_tve(encoder); mutex_lock(&tve->suspend_lock); dev_dbg(tve->dev, "tve encoder enable\n"); cvbs_set_enable(tve); mutex_unlock(&tve->suspend_lock); } static void rockchip_tve_encoder_disable(struct drm_encoder *encoder) { struct rockchip_tve *tve = encoder_to_tve(encoder); mutex_lock(&tve->suspend_lock); dev_dbg(tve->dev, "tve encoder enable\n"); cvbs_set_disable(tve); mutex_unlock(&tve->suspend_lock); } static void rockchip_tve_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct rockchip_tve *tve = encoder_to_tve(encoder); dev_dbg(tve->dev, "encoder mode set:%s\n", adjusted_mode->name); if (adjusted_mode->vdisplay == 576) tve->tv_format = TVOUT_CVBS_PAL; else tve->tv_format = TVOUT_CVBS_NTSC; if (tve->enable) { dac_enable(tve, false); msleep(200); tve_set_mode(tve); dac_enable(tve, true); } } static bool rockchip_tve_encoder_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { return true; } static int rockchip_tve_encoder_atomic_check(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); struct rockchip_tve *tve = encoder_to_tve(encoder); struct drm_connector *connector = conn_state->connector; struct drm_display_info *info = &connector->display_info; s->output_mode = ROCKCHIP_OUT_MODE_P888; s->output_type = DRM_MODE_CONNECTOR_TV; if (info->num_bus_formats) s->bus_format = info->bus_formats[0]; else s->bus_format = MEDIA_BUS_FMT_YUV8_1X24; /* * For RK3528: * VOP -> BT656 output -> BT656 decoder -> TVE encoder -> CVBS output */ if (tve->soc_type == SOC_RK3528) s->output_if |= VOP_OUTPUT_IF_BT656; s->color_space = V4L2_COLORSPACE_SMPTE170M; s->tv_state = &conn_state->tv; return 0; } static const struct drm_connector_helper_funcs rockchip_tve_connector_helper_funcs = { .mode_valid = rockchip_tve_mode_valid, .get_modes = rockchip_tve_get_modes, .best_encoder = rockchip_tve_best_encoder, }; static const struct drm_encoder_funcs rockchip_tve_encoder_funcs = { .destroy = rockchip_encoder_destroy, }; static const struct drm_connector_funcs rockchip_tve_connector_funcs = { .detect = rockchip_tve_connector_detect, .fill_modes = drm_helper_probe_single_connector_modes, .destroy = rockchip_tve_connector_destroy, .reset = drm_atomic_helper_connector_reset, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; static const struct drm_encoder_helper_funcs rockchip_tve_encoder_helper_funcs = { .mode_fixup = rockchip_tve_encoder_mode_fixup, .mode_set = rockchip_tve_encoder_mode_set, .enable = rockchip_tve_encoder_enable, .disable = rockchip_tve_encoder_disable, .atomic_check = rockchip_tve_encoder_atomic_check, }; static int tve_read_otp_by_name(struct rockchip_tve *tve, char *name, u8 *val, u8 default_val) { struct nvmem_cell *cell; size_t len; unsigned char *efuse_buf; int ret = -EINVAL; *val = default_val; cell = nvmem_cell_get(tve->dev, name); if (!IS_ERR(cell)) { efuse_buf = nvmem_cell_read(cell, &len); nvmem_cell_put(cell); if (!IS_ERR(efuse_buf)) { *val = efuse_buf[0]; kfree(efuse_buf); return 0; } } dev_err(tve->dev, "failed to read %s from otp, use default\n", name); return ret; } static int tve_parse_dt(struct device_node *np, struct rockchip_tve *tve) { int ret, val; u8 out_current, version; ret = of_property_read_u32(np, "rockchip,tvemode", &val); if (ret < 0) { tve->preferred_mode = 0; } else if (val > 1) { dev_err(tve->dev, "tve mode value invalid\n"); return -EINVAL; } tve->preferred_mode = val; ret = of_property_read_u32(np, "rockchip,lumafilter0", &val); if (val == 0 || ret < 0) return -EINVAL; tve->lumafilter0 = val; ret = of_property_read_u32(np, "rockchip,lumafilter1", &val); if (val == 0 || ret < 0) return -EINVAL; tve->lumafilter1 = val; ret = of_property_read_u32(np, "rockchip,lumafilter2", &val); if (val == 0 || ret < 0) return -EINVAL; tve->lumafilter2 = val; ret = of_property_read_u32(np, "rockchip,lumafilter3", &val); if (val == 0 || ret < 0) return -EINVAL; tve->lumafilter3 = val; ret = of_property_read_u32(np, "rockchip,lumafilter4", &val); if (val == 0 || ret < 0) return -EINVAL; tve->lumafilter4 = val; ret = of_property_read_u32(np, "rockchip,lumafilter5", &val); if (val == 0 || ret < 0) return -EINVAL; tve->lumafilter5 = val; ret = of_property_read_u32(np, "rockchip,lumafilter6", &val); if (val == 0 || ret < 0) return -EINVAL; tve->lumafilter6 = val; ret = of_property_read_u32(np, "rockchip,lumafilter7", &val); if (val == 0 || ret < 0) return -EINVAL; tve->lumafilter7 = val; ret = of_property_read_u32(np, "rockchip,tve-upsample", &val); if (val > DCLK_UPSAMPLEx4 || ret < 0) return -EINVAL; tve->upsample_mode = val; /* * Read vdac output current from OTP if exists, and the default * current val is 0xd2. */ ret = tve_read_otp_by_name(tve, "out-current", &out_current, 0xd2); if (!ret) { if (out_current) { /* * If test version is 0x0, the value of vdac out current * needs to be reduced by one. */ ret = tve_read_otp_by_name(tve, "version", &version, 0x0); if (!ret) { if (version == 0x0) out_current -= 1; } } else { /* * If the current value read from OTP is 0, set it to default. */ out_current = 0xd2; } } tve->vdac_out_current = out_current; return 0; } static int tve_parse_dt_legacy(struct device_node *np, struct rockchip_tve *tve) { int ret, val; u32 getdac = 0; size_t len; struct nvmem_cell *cell; unsigned char *efuse_buf; ret = of_property_read_u32(np, "rockchip,tvemode", &val); if (ret < 0) { tve->preferred_mode = 0; } else if (val > 1) { dev_err(tve->dev, "tve mode value invalid\n"); return -EINVAL; } tve->preferred_mode = val; ret = of_property_read_u32(np, "rockchip,saturation", &val); if (val == 0 || ret < 0) return -EINVAL; tve->saturation = val; ret = of_property_read_u32(np, "rockchip,brightcontrast", &val); if (val == 0 || ret < 0) return -EINVAL; tve->brightcontrast = val; ret = of_property_read_u32(np, "rockchip,adjtiming", &val); if (val == 0 || ret < 0) return -EINVAL; tve->adjtiming = val; ret = of_property_read_u32(np, "rockchip,lumafilter0", &val); if (val == 0 || ret < 0) return -EINVAL; tve->lumafilter0 = val; ret = of_property_read_u32(np, "rockchip,lumafilter1", &val); if (val == 0 || ret < 0) return -EINVAL; tve->lumafilter1 = val; ret = of_property_read_u32(np, "rockchip,lumafilter2", &val); if (val == 0 || ret < 0) return -EINVAL; tve->lumafilter2 = val; ret = of_property_read_u32(np, "rockchip,daclevel", &val); if (val == 0 || ret < 0) { return -EINVAL; } else { tve->daclevel = val; if (tve->soc_type == SOC_RK322X || tve->soc_type == SOC_RK3328) { cell = nvmem_cell_get(tve->dev, "tve_dac_adj"); if (IS_ERR(cell)) { dev_dbg(tve->dev, "failed to get id cell: %ld\n", PTR_ERR(cell)); } else { efuse_buf = nvmem_cell_read(cell, &len); nvmem_cell_put(cell); if (IS_ERR(efuse_buf)) return PTR_ERR(efuse_buf); if (len == 1) getdac = efuse_buf[0]; kfree(efuse_buf); if (getdac > 0) { tve->daclevel = getdac + 5 + val - RK322X_VDAC_STANDARD; if (tve->daclevel > 0x3f) { dev_err(tve->dev, "rk322x daclevel error!\n"); tve->daclevel = val; } } } } } if (tve->soc_type == SOC_RK322X || tve->soc_type == SOC_RK3328) { ret = of_property_read_u32(np, "rockchip,dac1level", &val); if ((val == 0) || (ret < 0)) return -EINVAL; tve->dac1level = val; } return 0; } static bool tve_check_lumafilter(struct rockchip_tve *tve) { int lumafilter[8] = {INT_MAX}; /* * The default lumafilter value is 0. If lumafilter value * is equal to the dts value, uboot logo is enabled. */ if (tve->soc_type == SOC_RK3528) { lumafilter[0] = tve_readl(TVE_LUMA_FILTER1); lumafilter[1] = tve_readl(TVE_LUMA_FILTER2); lumafilter[2] = tve_readl(TVE_LUMA_FILTER3); lumafilter[3] = tve_readl(TVE_LUMA_FILTER4); lumafilter[4] = tve_readl(TVE_LUMA_FILTER5); lumafilter[5] = tve_readl(TVE_LUMA_FILTER6); lumafilter[6] = tve_readl(TVE_LUMA_FILTER7); lumafilter[7] = tve_readl(TVE_LUMA_FILTER8); if (lumafilter[0] == tve->lumafilter0 && lumafilter[1] == tve->lumafilter1 && lumafilter[2] == tve->lumafilter2 && lumafilter[3] == tve->lumafilter3 && lumafilter[4] == tve->lumafilter4 && lumafilter[5] == tve->lumafilter5 && lumafilter[6] == tve->lumafilter6 && lumafilter[7] == tve->lumafilter7) { return true; } } else { lumafilter[0] = tve_readl(TV_LUMA_FILTER0); lumafilter[1] = tve_readl(TV_LUMA_FILTER1); lumafilter[2] = tve_readl(TV_LUMA_FILTER2); if (lumafilter[0] == tve->lumafilter0 && lumafilter[1] == tve->lumafilter1 && lumafilter[2] == tve->lumafilter2) { return true; } } return false; } static void check_uboot_logo(struct rockchip_tve *tve) { int vdac; if (tve->soc_type == SOC_RK322X || tve->soc_type == SOC_RK3328) { vdac = tve_dac_readl(VDAC_VDAC1); /* Whether the dac power has been turned down. */ if (vdac & m_DR_PWR_DOWN) { tve->connector.dpms = DRM_MODE_DPMS_OFF; return; } } if (tve_check_lumafilter(tve)) { tve->connector.dpms = DRM_MODE_DPMS_ON; return; } if (tve->soc_type == SOC_RK322X || tve->soc_type == SOC_RK3328) dac_init(tve); tve->connector.dpms = DRM_MODE_DPMS_OFF; } static const struct rockchip_tve_data rk3036_tve = { .soc_type = SOC_RK3036, .input_format = INPUT_FORMAT_RGB, }; static const struct rockchip_tve_data rk312x_tve = { .soc_type = SOC_RK312X, .input_format = INPUT_FORMAT_RGB, }; static const struct rockchip_tve_data rk322x_tve = { .soc_type = SOC_RK322X, .input_format = INPUT_FORMAT_YUV, }; static const struct rockchip_tve_data rk3328_tve = { .soc_type = SOC_RK3328, .input_format = INPUT_FORMAT_YUV, }; static const struct rockchip_tve_data rk3528_tve = { .soc_type = SOC_RK3528, .input_format = INPUT_FORMAT_YUV, }; static const struct of_device_id rockchip_tve_dt_ids[] = { { .compatible = "rockchip,rk3036-tve", .data = &rk3036_tve }, { .compatible = "rockchip,rk312x-tve", .data = &rk312x_tve }, { .compatible = "rockchip,rk322x-tve", .data = &rk322x_tve }, { .compatible = "rockchip,rk3328-tve", .data = &rk3328_tve }, { .compatible = "rockchip,rk3528-tve", .data = &rk3528_tve }, {} }; MODULE_DEVICE_TABLE(of, rockchip_tve_dt_ids); static int rockchip_tve_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); struct drm_device *drm_dev = data; struct device_node *np = dev->of_node; const struct of_device_id *match; const struct rockchip_tve_data *tve_data; struct rockchip_tve *tve; struct resource *res; struct drm_encoder *encoder; struct drm_connector *connector; int ret; tve = devm_kzalloc(dev, sizeof(*tve), GFP_KERNEL); if (!tve) return -ENOMEM; match = of_match_node(rockchip_tve_dt_ids, np); if (!match) { dev_err(tve->dev, "tve can't match node\n"); return -EINVAL; } tve->dev = &pdev->dev; tve_data = of_device_get_match_data(dev); if (tve_data) { tve->soc_type = tve_data->soc_type; tve->input_format = tve_data->input_format; } if (tve->soc_type == SOC_RK3528) ret = tve_parse_dt(np, tve); else ret = tve_parse_dt_legacy(np, tve); if (ret) { dev_err(tve->dev, "TVE parse dts error!"); return -EINVAL; } tve->enable = 0; tve->drm_dev = drm_dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); tve->reg_phy_base = res->start; tve->len = resource_size(res); tve->regbase = devm_ioremap(tve->dev, res->start, tve->len); if (IS_ERR(tve->regbase)) { dev_err(tve->dev, "tv encoder device map registers failed!"); return PTR_ERR(tve->regbase); } if (tve->soc_type == SOC_RK322X || tve->soc_type == SOC_RK3328 || tve->soc_type == SOC_RK3528) { res = platform_get_resource(pdev, IORESOURCE_MEM, 1); tve->len = resource_size(res); tve->vdacbase = devm_ioremap(tve->dev, res->start, tve->len); if (IS_ERR(tve->vdacbase)) { dev_err(tve->dev, "tv encoder device dac map registers failed!"); return PTR_ERR(tve->vdacbase); } } if (tve->soc_type == SOC_RK3036) { tve->aclk = devm_clk_get(tve->dev, "aclk"); if (IS_ERR(tve->aclk)) { dev_err(tve->dev, "Unable to get tve aclk\n"); return PTR_ERR(tve->aclk); } ret = clk_prepare_enable(tve->aclk); if (ret) { dev_err(tve->dev, "Cannot enable tve aclk: %d\n", ret); return ret; } } else if (tve->soc_type == SOC_RK3528) { tve->hclk = devm_clk_get(tve->dev, "hclk"); if (IS_ERR(tve->hclk)) { dev_err(tve->dev, "Unable to get tve hclk\n"); return PTR_ERR(tve->hclk); } ret = clk_prepare_enable(tve->hclk); if (ret) { dev_err(tve->dev, "Cannot enable tve hclk: %d\n", ret); return ret; } tve->pclk_vdac = devm_clk_get(tve->dev, "pclk_vdac"); if (IS_ERR(tve->pclk_vdac)) { dev_err(tve->dev, "Unable to get vdac pclk\n"); return PTR_ERR(tve->pclk_vdac); } ret = clk_prepare_enable(tve->pclk_vdac); if (ret) { dev_err(tve->dev, "Cannot enable vdac pclk: %d\n", ret); return ret; } tve->dclk = devm_clk_get(tve->dev, "dclk"); if (IS_ERR(tve->dclk)) { dev_err(tve->dev, "Unable to get tve dclk\n"); return PTR_ERR(tve->dclk); } ret = clk_prepare_enable(tve->dclk); if (ret) { dev_err(tve->dev, "Cannot enable tve dclk: %d\n", ret); return ret; } if (tve->upsample_mode == DCLK_UPSAMPLEx4) { tve->dclk_4x = devm_clk_get(tve->dev, "dclk_4x"); if (IS_ERR(tve->dclk_4x)) { dev_err(tve->dev, "Unable to get tve dclk_4x\n"); return PTR_ERR(tve->dclk_4x); } ret = clk_prepare_enable(tve->dclk_4x); if (ret) { dev_err(tve->dev, "Cannot enable tve dclk_4x: %d\n", ret); return ret; } } } tve->dac_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf"); mutex_init(&tve->suspend_lock); check_uboot_logo(tve); tve->tv_format = TVOUT_CVBS_PAL; encoder = &tve->encoder; encoder->possible_crtcs = rockchip_drm_of_find_possible_crtcs(drm_dev, dev->of_node); dev_dbg(tve->dev, "possible_crtc:%d\n", encoder->possible_crtcs); ret = drm_encoder_init(drm_dev, encoder, &rockchip_tve_encoder_funcs, DRM_MODE_ENCODER_TVDAC, NULL); if (ret < 0) { dev_err(tve->dev, "failed to initialize encoder with drm\n"); goto err_disable_aclk; } drm_encoder_helper_add(encoder, &rockchip_tve_encoder_helper_funcs); connector = &tve->connector; connector->interlace_allowed = 1; ret = drm_connector_init(drm_dev, connector, &rockchip_tve_connector_funcs, DRM_MODE_CONNECTOR_TV); if (ret < 0) { dev_dbg(tve->dev, "failed to initialize connector with drm\n"); goto err_free_encoder; } drm_connector_helper_add(connector, &rockchip_tve_connector_helper_funcs); ret = drm_connector_attach_encoder(connector, encoder); if (ret < 0) { dev_dbg(tve->dev, "failed to attach connector and encoder\n"); goto err_free_connector; } tve->sub_dev.connector = &tve->connector; tve->sub_dev.of_node = tve->dev->of_node; rockchip_drm_register_sub_dev(&tve->sub_dev); pm_runtime_enable(dev); dev_set_drvdata(dev, tve); dev_dbg(tve->dev, "%s tv encoder probe ok\n", match->compatible); return 0; err_free_connector: drm_connector_cleanup(connector); err_free_encoder: drm_encoder_cleanup(encoder); err_disable_aclk: if (tve->soc_type == SOC_RK3036) clk_disable_unprepare(tve->aclk); return ret; } static void rockchip_tve_unbind(struct device *dev, struct device *master, void *data) { struct rockchip_tve *tve = dev_get_drvdata(dev); rockchip_drm_unregister_sub_dev(&tve->sub_dev); rockchip_tve_encoder_disable(&tve->encoder); drm_connector_cleanup(&tve->connector); drm_encoder_cleanup(&tve->encoder); pm_runtime_disable(dev); dev_set_drvdata(dev, NULL); } static const struct component_ops rockchip_tve_component_ops = { .bind = rockchip_tve_bind, .unbind = rockchip_tve_unbind, }; static int rockchip_tve_probe(struct platform_device *pdev) { component_add(&pdev->dev, &rockchip_tve_component_ops); return 0; } static void rockchip_tve_shutdown(struct platform_device *pdev) { struct rockchip_tve *tve = dev_get_drvdata(&pdev->dev); if (!tve) return; mutex_lock(&tve->suspend_lock); dev_dbg(tve->dev, "tve shutdown\n"); cvbs_set_disable(tve); mutex_unlock(&tve->suspend_lock); } static int rockchip_tve_remove(struct platform_device *pdev) { component_del(&pdev->dev, &rockchip_tve_component_ops); return 0; } struct platform_driver rockchip_tve_driver = { .probe = rockchip_tve_probe, .remove = rockchip_tve_remove, .shutdown = rockchip_tve_shutdown, .driver = { .name = "rockchip-tve", .of_match_table = of_match_ptr(rockchip_tve_dt_ids), }, }; MODULE_AUTHOR("Algea Cao "); MODULE_DESCRIPTION("ROCKCHIP TVE Driver"); MODULE_LICENSE("GPL v2");