From ce0eedfcb226b8d3d0536362e0cc046634f63e3b Mon Sep 17 00:00:00 2001 From: "algea.cao" Date: Wed, 14 Jun 2017 18:10:07 +0800 Subject: [PATCH] drm/rockchip: support rk3328 linux drm cvbs This adds support for Rockchip CVBS found on rk3328 Linux. The CVBS driver is based on the DRM framework. NTSC(720x480i60hz) and PAL(720x576i50hz) modes are supported. it's worth noting that rk3328 CVBS dclk is base on hdmi clk,so hdmi should be enabled. Change-Id: I059808111bfa96724eb629b6fc37915a4852e234 Signed-off-by: algea.cao --- .../display/rockchip/rockchip_drm_tve.txt | 43 ++ drivers/gpu/drm/rockchip/Kconfig | 7 + drivers/gpu/drm/rockchip/Makefile | 1 + drivers/gpu/drm/rockchip/rockchip_drm_tve.c | 525 ++++++++++++++++++ drivers/gpu/drm/rockchip/rockchip_drm_tve.h | 163 ++++++ 5 files changed, 739 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/rockchip/rockchip_drm_tve.txt create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_tve.c create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_tve.h diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip_drm_tve.txt b/Documentation/devicetree/bindings/display/rockchip/rockchip_drm_tve.txt new file mode 100644 index 000000000000..e44cbe682171 --- /dev/null +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip_drm_tve.txt @@ -0,0 +1,43 @@ +Rockchip specific extensions to the TVE +================================ + +Required properties: +- compatible: "rockchip,rk3328-tve"; +- reg: Physical base address and length of the controller's registers. +- ports: contain a port node with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt +- rockchip,saturation: the value for TVE_COLOR_BUSRT_SAT(0x78) +- rockchip,brightcontrast: the value for TVE_BRIGHTNESS_CONTRAST(0x90) +- rockchip,adjtiming: the value for TVE_HOR_TIMING3(0x0c) +- rockchip,lumafilter0: the value for TVE_LUMA_FILTER1(0x14) +- rockchip,lumafilter1: the value for TVE_LUMA_FILTER2(0x18) +- rockchip,lumafilter2: the value for TVE_LUMA_FILTER3(0x1c) +- rockchip,daclevel: the value is used to adjust the voltage amplitude of the CVBS +- rockchip,dac1level: only for rv1108 rk322x and rk3328 + +Example: + tve: tve@ff373e00 { + compatible = "rockchip,rk3328-tve"; + reg = <0x0 0xff373e00 0x0 0x100>, + <0x0 0xff420000 0x0 0x10000>; + rockchip,saturation = <0x00376749>; + rockchip,brightcontrast = <0x0000a305>; + rockchip,adjtiming = <0xb6c00880>; + rockchip,lumafilter0 = <0x01ff0000>; + rockchip,lumafilter1 = <0xf40200fe>; + rockchip,lumafilter2 = <0xf332d70c>; + rockchip,daclevel = <0x22>; + rockchip,dac1level = <0x7>; + status = "disabled"; + + ports { + tve_in: port { + #address-cells = <1>; + #size-cells = <0>; + tve_in_vop: endpoint@0 { + reg = <0>; + remote-endpoint = <&vop_out_tve>; + }; + }; + }; + }; diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index 6dc71f538bb0..fd749154e6c7 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -81,3 +81,10 @@ config ROCKCHIP_LVDS Rockchip rk3288 SoC has LVDS TX Controller can be used, and it support LVDS, rgb, dual LVDS output mode. say Y to enable its driver. + +config ROCKCHIP_DRM_TVE + tristate "Rockchip TVE support" + depends on DRM_ROCKCHIP + help + Choose this option to enable support for Rockchip TVE controllers. + say Y to enable its driver. diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index a49a0189ef10..98f753458642 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o obj-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o obj-$(CONFIG_DRM_ROCKCHIP) += rockchip_vop_reg.o rockchipdrm.o +obj-$(CONFIG_ROCKCHIP_DRM_TVE) += rockchip_drm_tve.o diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_tve.c b/drivers/gpu/drm/rockchip/rockchip_drm_tve.c new file mode 100644 index 000000000000..62e9c0ba9289 --- /dev/null +++ b/drivers/gpu/drm/rockchip/rockchip_drm_tve.c @@ -0,0 +1,525 @@ +#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" + +static const struct drm_display_mode cvbs_mode[] = { + { DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER | + DRM_MODE_TYPE_PREFERRED, 13500, 720, 732, + 795, 864, 0, 576, 580, 586, 625, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), + .vrefresh = 50, 0, }, + { DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500, 720, 739, + 801, 858, 0, 480, 488, 494, 525, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), + .vrefresh = 60, 0, }, +}; + +#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 connector_to_tve(x) container_of(x, struct rockchip_tve, connector) +#define encoder_to_tve(x) container_of(x, struct rockchip_tve, encoder) + +static int +rockchip_tve_get_modes(struct drm_connector *connector) +{ + int count; + + 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]); + 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) +{ + int mode = tve->tv_format; + + dev_dbg(tve->dev, "tve set mode:%d\n", mode); + if (tve->inputformat == 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"); + 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"); + 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)); + } +} + +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 val; + + if (enable) { + dev_dbg(tve->dev, "dac enable\n"); + val = 0x70; + } else { + dev_dbg(tve->dev, "dac disable\n"); + val = v_CUR_REG(0x7) | m_DR_PWR_DOWN | m_BG_PWR_DOWN; + } + + if (tve->vdacbase) + tve_dac_writel(VDAC_VDAC1, 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; +} + +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; + } + dac_enable(tve, true); + tve_set_mode(tve); + 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 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]; + s->bus_format = MEDIA_BUS_FMT_YUV8_1X24; + + 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 = { + .dpms = drm_atomic_helper_connector_dpms, + .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_parse_dt(struct device_node *np, + struct rockchip_tve *tve) +{ + int ret; + u32 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; + tve->daclevel = val; + + ret = of_property_read_u32(np, "rockchip,dac1level", &val); + if ((val == 0) || (ret < 0)) + return -EINVAL; + tve->dac1level = val; + + return 0; +} + +static const struct of_device_id rockchip_tve_dt_ids[] = { + { + .compatible = "rockchip,rk3328-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; + 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; + } + + if (!strcmp(match->compatible, "rockchip,rk3328-tve")) { + tve->inputformat = INPUT_FORMAT_YUV; + } else { + dev_err(tve->dev, "It is not a valid tv encoder! "); + return -ENOMEM; + } + + ret = tve_parse_dt(np, tve); + if (ret) { + dev_err(tve->dev, "TVE parse dts error!"); + return -EINVAL; + } + + tve->enable = 0; + platform_set_drvdata(pdev, tve); + tve->dev = &pdev->dev; + 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, + "rk3328 tv encoder device map registers failed!"); + return PTR_ERR(tve->regbase); + } + + 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, + "rk3328 tv encoder device dac map registers failed!"); + return PTR_ERR(tve->vdacbase); + } + + dac_init(tve); + + mutex_init(&tve->suspend_lock); + + tve->tv_format = TVOUT_CVBS_PAL; + encoder = &tve->encoder; + encoder->possible_crtcs = 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"); + return ret; + } + + drm_encoder_helper_add(encoder, &rockchip_tve_encoder_helper_funcs); + + connector = &tve->connector; + connector->dpms = DRM_MODE_DPMS_OFF; + + 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_mode_connector_attach_encoder(connector, encoder); + if (ret < 0) { + dev_dbg(tve->dev, "failed to attach connector and encoder\n"); + goto err_free_connector; + } + + pm_runtime_enable(dev); + 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); + return ret; +} + +static void rockchip_tve_unbind(struct device *dev, struct device *master, + void *data) +{ + struct rockchip_tve *tve = dev_get_drvdata(dev); + + rockchip_tve_encoder_disable(&tve->encoder); + + drm_connector_cleanup(&tve->connector); + drm_encoder_cleanup(&tve->encoder); + + pm_runtime_disable(dev); +} + +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 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, + .driver = { + .name = "rockchip-tve", + .of_match_table = of_match_ptr(rockchip_tve_dt_ids), + }, +}; +module_platform_driver(rockchip_tve_driver); + +MODULE_AUTHOR("Algea Cao "); +MODULE_DESCRIPTION("ROCKCHIP TVE Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_tve.h b/drivers/gpu/drm/rockchip/rockchip_drm_tve.h new file mode 100644 index 000000000000..6b291f8962d8 --- /dev/null +++ b/drivers/gpu/drm/rockchip/rockchip_drm_tve.h @@ -0,0 +1,163 @@ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: + * algea cao + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 __ROCKCHIP_DRM_TVE_H__ +#define __ROCKCHIP_DRM_TVE_H__ + +#define TV_CTRL (0x00) + #define m_CVBS_MODE BIT(24) + #define m_CLK_UPSTREAM_EN (3 << 18) + #define m_TIMING_EN (3 << 16) + #define m_LUMA_FILTER_GAIN (3 << 9) + #define m_LUMA_FILTER_BW BIT(8) + #define m_CSC_PATH (3 << 1) + + #define v_CVBS_MODE(x) (((x) & 1) << 24) + #define v_CLK_UPSTREAM_EN(x) (((x) & 3) << 18) + #define v_TIMING_EN(x) (((x) & 3) << 16) + #define v_LUMA_FILTER_GAIN(x) (((x) & 3) << 9) + #define v_LUMA_FILTER_UPSAMPLE(x) (((x) & 1) << 8) + #define v_CSC_PATH(x) (((x) & 3) << 1) + +#define TV_SYNC_TIMING (0x04) +#define TV_ACT_TIMING (0x08) +#define TV_ADJ_TIMING (0x0c) +#define TV_FREQ_SC (0x10) +#define TV_LUMA_FILTER0 (0x14) +#define TV_LUMA_FILTER1 (0x18) +#define TV_LUMA_FILTER2 (0x1C) +#define TV_ACT_ST (0x34) +#define TV_ROUTING (0x38) + #define m_DAC_SENSE_EN BIT(27) + #define m_Y_IRE_7_5 BIT(19) + #define m_Y_AGC_PULSE_ON BIT(15) + #define m_Y_VIDEO_ON BIT(11) + #define m_Y_SYNC_ON BIT(7) + #define m_YPP_MODE BIT(3) + #define m_MONO_EN BIT(2) + #define m_PIC_MODE BIT(1) + + #define v_DAC_SENSE_EN(x) (((x) & 1) << 27) + #define v_Y_IRE_7_5(x) (((x) & 1) << 19) + #define v_Y_AGC_PULSE_ON(x) (((x) & 1) << 15) + #define v_Y_VIDEO_ON(x) (((x) & 1) << 11) + #define v_Y_SYNC_ON(x) (((x) & 1) << 7) + #define v_YPP_MODE(x) (((x) & 1) << 3) + #define v_MONO_EN(x) (((x) & 1) << 2) + #define v_PIC_MODE(x) (((x) & 1) << 1) + +#define TV_SYNC_ADJUST (0x50) +#define TV_STATUS (0x54) +#define TV_RESET (0x68) + #define m_RESET BIT(1) + #define v_RESET(x) (((x) & 1) << 1) +#define TV_SATURATION (0x78) +#define TV_BW_CTRL (0x8C) + #define m_CHROMA_BW (3 << 4) + #define m_COLOR_DIFF_BW (0xf) + + enum { + BP_FILTER_PASS = 0, + BP_FILTER_NTSC, + BP_FILTER_PAL, + }; + enum { + COLOR_DIFF_FILTER_OFF = 0, + COLOR_DIFF_FILTER_BW_0_6, + COLOR_DIFF_FILTER_BW_1_3, + COLOR_DIFF_FILTER_BW_2_0 + }; + + #define v_CHROMA_BW(x) ((3 & (x)) << 4) + #define v_COLOR_DIFF_BW(x) (0xF & (x)) + +#define TV_BRIGHTNESS_CONTRAST (0x90) + +#define m_EXTREF_EN BIT(0) +#define m_VBG_EN BIT(1) +#define m_DAC_EN BIT(2) +#define m_SENSE_EN BIT(3) +#define m_BIAS_EN (7 << 4) +#define m_DAC_GAIN (0x3f << 7) +#define v_DAC_GAIN(x) (((x) & 0x3f) << 7) + +#define VDAC_VDAC0 (0x00) + #define m_RST_ANA BIT(7) + #define m_RST_DIG BIT(6) + + #define v_RST_ANA(x) (((x) & 1) << 7) + #define v_RST_DIG(x) (((x) & 1) << 6) +#define VDAC_VDAC1 (0x280) + #define m_CUR_REG (0xf << 4) + #define m_DR_PWR_DOWN BIT(1) + #define m_BG_PWR_DOWN BIT(0) + + #define v_CUR_REG(x) (((x) & 0xf) << 4) + #define v_DR_PWR_DOWN(x) (((x) & 1) << 1) + #define v_BG_PWR_DOWN(x) (((x) & 1) << 0) +#define VDAC_VDAC2 (0x284) + #define m_CUR_CTR (0X3f) + + #define v_CUR_CTR(x) (((x) & 0x3f)) +#define VDAC_VDAC3 (0x288) + #define m_CAB_EN BIT(5) + #define m_CAB_REF BIT(4) + #define m_CAB_FLAG BIT(0) + + #define v_CAB_EN(x) (((x) & 1) << 5) + #define v_CAB_REF(x) (((x) & 1) << 4) + #define v_CAB_FLAG(x) (((x) & 1) << 0) + +enum { + TVOUT_CVBS_NTSC = 0, + TVOUT_CVBS_PAL, +}; + +enum { + INPUT_FORMAT_RGB = 0, + INPUT_FORMAT_YUV +}; + +#define grf_writel(offset, v) do { \ + writel_relaxed(v, RK_GRF_VIRT + (offset)); \ + dsb(sy); \ + } while (0) + +struct rockchip_tve { + struct device *dev; + struct drm_device *drm_dev; + struct drm_connector connector; + struct drm_encoder encoder; + + u32 tv_format; + void __iomem *regbase; + void __iomem *vdacbase; + struct clk *dac_clk; + u32 reg_phy_base; + u32 len; + int inputformat; + bool enable; + u32 test_mode; + u32 saturation; + u32 brightcontrast; + u32 adjtiming; + u32 lumafilter0; + u32 lumafilter1; + u32 lumafilter2; + u32 daclevel; + u32 dac1level; + struct mutex suspend_lock; /* mutex for tve resume operation*/ +}; + +#endif /* _ROCKCHIP_DRM_TVE_ */ -- 2.34.1