aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2017-01-31 17:26:33 -0500
committerDave Airlie <airlied@redhat.com>2017-01-31 17:29:04 -0500
commit3a5e6bb9c660173cf6a1a3f29b0501553cd4db2f (patch)
treea9b28f2391cc11fb4a3f50e261b870f50c53a6f8
parent2643105558099a4703f8209f2cad768673aff12d (diff)
parent098988cbe5849e3e125b0bc02a6545a1dc414ab1 (diff)
Merge tag 'zxdrm-4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux into drm-next
ZTE DRM driver updates for 4.11: - Add missing selection of VIDEOMODE_HELPERS in Kconfig, since ZTE DRM driver uses drm_display_mode_to_videomode(). - Enable HDMI audio support through SPDIF interface based on generic hdmi-audio-codec driver. - Enable VOU VL (Video Layer) to support overlay plane with scaling function. - Refine zx_vou driver a bit and then add TV Encoder output device support. [airlied: fixup plane format change] * tag 'zxdrm-4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux: drm: zte: add tvenc driver support dt: add bindings for ZTE tvenc device drm: zte: add function to configure vou_ctrl dividers drm: zte: move struct vou_inf into zx_vou driver drm: zte: add interlace mode support drm: zte: add overlay plane support drm: zte: add .atomic_disable hook to disable graphic layer drm: zte: make zx_plane accessible from zx_vou driver drm: zte: support hdmi audio through spdif drm: zte: select VIDEOMODE_HELPERS in Kconfig
-rw-r--r--Documentation/devicetree/bindings/display/zte,vou.txt15
-rw-r--r--drivers/gpu/drm/zte/Kconfig2
-rw-r--r--drivers/gpu/drm/zte/Makefile1
-rw-r--r--drivers/gpu/drm/zte/zx_drm_drv.c1
-rw-r--r--drivers/gpu/drm/zte/zx_drm_drv.h1
-rw-r--r--drivers/gpu/drm/zte/zx_hdmi.c160
-rw-r--r--drivers/gpu/drm/zte/zx_hdmi_regs.h14
-rw-r--r--drivers/gpu/drm/zte/zx_plane.c328
-rw-r--r--drivers/gpu/drm/zte/zx_plane.h12
-rw-r--r--drivers/gpu/drm/zte/zx_plane_regs.h51
-rw-r--r--drivers/gpu/drm/zte/zx_tvenc.c407
-rw-r--r--drivers/gpu/drm/zte/zx_tvenc_regs.h31
-rw-r--r--drivers/gpu/drm/zte/zx_vou.c356
-rw-r--r--drivers/gpu/drm/zte/zx_vou.h48
-rw-r--r--drivers/gpu/drm/zte/zx_vou_regs.h51
15 files changed, 1365 insertions, 113 deletions
diff --git a/Documentation/devicetree/bindings/display/zte,vou.txt b/Documentation/devicetree/bindings/display/zte,vou.txt
index 740e5bd2e4f7..9c356284232b 100644
--- a/Documentation/devicetree/bindings/display/zte,vou.txt
+++ b/Documentation/devicetree/bindings/display/zte,vou.txt
@@ -49,6 +49,15 @@ Required properties:
49 "osc_clk" 49 "osc_clk"
50 "xclk" 50 "xclk"
51 51
52* TV Encoder output device
53
54Required properties:
55 - compatible: should be "zte,zx296718-tvenc"
56 - reg: Physical base address and length of the TVENC device IO region
57 - zte,tvenc-power-control: the phandle to SYSCTRL block followed by two
58 integer cells. The first cell is the offset of SYSCTRL register used
59 to control TV Encoder DAC power, and the second cell is the bit mask.
60
52Example: 61Example:
53 62
54vou: vou@1440000 { 63vou: vou@1440000 {
@@ -81,4 +90,10 @@ vou: vou@1440000 {
81 <&topcrm HDMI_XCLK>; 90 <&topcrm HDMI_XCLK>;
82 clock-names = "osc_cec", "osc_clk", "xclk"; 91 clock-names = "osc_cec", "osc_clk", "xclk";
83 }; 92 };
93
94 tvenc: tvenc@2000 {
95 compatible = "zte,zx296718-tvenc";
96 reg = <0x2000 0x1000>;
97 zte,tvenc-power-control = <&sysctrl 0x170 0x10>;
98 };
84}; 99};
diff --git a/drivers/gpu/drm/zte/Kconfig b/drivers/gpu/drm/zte/Kconfig
index 4065b2840f1c..5b36421ef3e5 100644
--- a/drivers/gpu/drm/zte/Kconfig
+++ b/drivers/gpu/drm/zte/Kconfig
@@ -4,5 +4,7 @@ config DRM_ZTE
4 select DRM_KMS_CMA_HELPER 4 select DRM_KMS_CMA_HELPER
5 select DRM_KMS_FB_HELPER 5 select DRM_KMS_FB_HELPER
6 select DRM_KMS_HELPER 6 select DRM_KMS_HELPER
7 select SND_SOC_HDMI_CODEC if SND_SOC
8 select VIDEOMODE_HELPERS
7 help 9 help
8 Choose this option to enable DRM on ZTE ZX SoCs. 10 Choose this option to enable DRM on ZTE ZX SoCs.
diff --git a/drivers/gpu/drm/zte/Makefile b/drivers/gpu/drm/zte/Makefile
index 699180bfd57c..01352b56c418 100644
--- a/drivers/gpu/drm/zte/Makefile
+++ b/drivers/gpu/drm/zte/Makefile
@@ -2,6 +2,7 @@ zxdrm-y := \
2 zx_drm_drv.o \ 2 zx_drm_drv.o \
3 zx_hdmi.o \ 3 zx_hdmi.o \
4 zx_plane.o \ 4 zx_plane.o \
5 zx_tvenc.o \
5 zx_vou.o 6 zx_vou.o
6 7
7obj-$(CONFIG_DRM_ZTE) += zxdrm.o 8obj-$(CONFIG_DRM_ZTE) += zxdrm.o
diff --git a/drivers/gpu/drm/zte/zx_drm_drv.c b/drivers/gpu/drm/zte/zx_drm_drv.c
index 3e76f72c92ff..13081fed902d 100644
--- a/drivers/gpu/drm/zte/zx_drm_drv.c
+++ b/drivers/gpu/drm/zte/zx_drm_drv.c
@@ -247,6 +247,7 @@ static struct platform_driver zx_drm_platform_driver = {
247static struct platform_driver *drivers[] = { 247static struct platform_driver *drivers[] = {
248 &zx_crtc_driver, 248 &zx_crtc_driver,
249 &zx_hdmi_driver, 249 &zx_hdmi_driver,
250 &zx_tvenc_driver,
250 &zx_drm_platform_driver, 251 &zx_drm_platform_driver,
251}; 252};
252 253
diff --git a/drivers/gpu/drm/zte/zx_drm_drv.h b/drivers/gpu/drm/zte/zx_drm_drv.h
index e65cd18a6cba..5ca035b079c7 100644
--- a/drivers/gpu/drm/zte/zx_drm_drv.h
+++ b/drivers/gpu/drm/zte/zx_drm_drv.h
@@ -13,6 +13,7 @@
13 13
14extern struct platform_driver zx_crtc_driver; 14extern struct platform_driver zx_crtc_driver;
15extern struct platform_driver zx_hdmi_driver; 15extern struct platform_driver zx_hdmi_driver;
16extern struct platform_driver zx_tvenc_driver;
16 17
17static inline u32 zx_readl(void __iomem *reg) 18static inline u32 zx_readl(void __iomem *reg)
18{ 19{
diff --git a/drivers/gpu/drm/zte/zx_hdmi.c b/drivers/gpu/drm/zte/zx_hdmi.c
index 6bf6c364811e..c47b9cbfe270 100644
--- a/drivers/gpu/drm/zte/zx_hdmi.c
+++ b/drivers/gpu/drm/zte/zx_hdmi.c
@@ -25,6 +25,8 @@
25#include <drm/drm_of.h> 25#include <drm/drm_of.h>
26#include <drm/drmP.h> 26#include <drm/drmP.h>
27 27
28#include <sound/hdmi-codec.h>
29
28#include "zx_hdmi_regs.h" 30#include "zx_hdmi_regs.h"
29#include "zx_vou.h" 31#include "zx_vou.h"
30 32
@@ -49,17 +51,11 @@ struct zx_hdmi {
49 bool sink_is_hdmi; 51 bool sink_is_hdmi;
50 bool sink_has_audio; 52 bool sink_has_audio;
51 const struct vou_inf *inf; 53 const struct vou_inf *inf;
54 struct platform_device *audio_pdev;
52}; 55};
53 56
54#define to_zx_hdmi(x) container_of(x, struct zx_hdmi, x) 57#define to_zx_hdmi(x) container_of(x, struct zx_hdmi, x)
55 58
56static const struct vou_inf vou_inf_hdmi = {
57 .id = VOU_HDMI,
58 .data_sel = VOU_YUV444,
59 .clocks_en_bits = BIT(24) | BIT(18) | BIT(6),
60 .clocks_sel_bits = BIT(13) | BIT(2),
61};
62
63static inline u8 hdmi_readb(struct zx_hdmi *hdmi, u16 offset) 59static inline u8 hdmi_readb(struct zx_hdmi *hdmi, u16 offset)
64{ 60{
65 return readl_relaxed(hdmi->mmio + offset * 4); 61 return readl_relaxed(hdmi->mmio + offset * 4);
@@ -238,14 +234,14 @@ static void zx_hdmi_encoder_enable(struct drm_encoder *encoder)
238 234
239 zx_hdmi_hw_enable(hdmi); 235 zx_hdmi_hw_enable(hdmi);
240 236
241 vou_inf_enable(hdmi->inf, encoder->crtc); 237 vou_inf_enable(VOU_HDMI, encoder->crtc);
242} 238}
243 239
244static void zx_hdmi_encoder_disable(struct drm_encoder *encoder) 240static void zx_hdmi_encoder_disable(struct drm_encoder *encoder)
245{ 241{
246 struct zx_hdmi *hdmi = to_zx_hdmi(encoder); 242 struct zx_hdmi *hdmi = to_zx_hdmi(encoder);
247 243
248 vou_inf_disable(hdmi->inf, encoder->crtc); 244 vou_inf_disable(VOU_HDMI, encoder->crtc);
249 245
250 zx_hdmi_hw_disable(hdmi); 246 zx_hdmi_hw_disable(hdmi);
251 247
@@ -366,6 +362,142 @@ static irqreturn_t zx_hdmi_irq_handler(int irq, void *dev_id)
366 return IRQ_NONE; 362 return IRQ_NONE;
367} 363}
368 364
365static int zx_hdmi_audio_startup(struct device *dev, void *data)
366{
367 struct zx_hdmi *hdmi = dev_get_drvdata(dev);
368 struct drm_encoder *encoder = &hdmi->encoder;
369
370 vou_inf_hdmi_audio_sel(encoder->crtc, VOU_HDMI_AUD_SPDIF);
371
372 return 0;
373}
374
375static void zx_hdmi_audio_shutdown(struct device *dev, void *data)
376{
377 struct zx_hdmi *hdmi = dev_get_drvdata(dev);
378
379 /* Disable audio input */
380 hdmi_writeb_mask(hdmi, AUD_EN, AUD_IN_EN, 0);
381}
382
383static inline int zx_hdmi_audio_get_n(unsigned int fs)
384{
385 unsigned int n;
386
387 if (fs && (fs % 44100) == 0)
388 n = 6272 * (fs / 44100);
389 else
390 n = fs * 128 / 1000;
391
392 return n;
393}
394
395static int zx_hdmi_audio_hw_params(struct device *dev,
396 void *data,
397 struct hdmi_codec_daifmt *daifmt,
398 struct hdmi_codec_params *params)
399{
400 struct zx_hdmi *hdmi = dev_get_drvdata(dev);
401 struct hdmi_audio_infoframe *cea = &params->cea;
402 union hdmi_infoframe frame;
403 int n;
404
405 /* We only support spdif for now */
406 if (daifmt->fmt != HDMI_SPDIF) {
407 DRM_DEV_ERROR(hdmi->dev, "invalid daifmt %d\n", daifmt->fmt);
408 return -EINVAL;
409 }
410
411 switch (params->sample_width) {
412 case 16:
413 hdmi_writeb_mask(hdmi, TPI_AUD_CONFIG, SPDIF_SAMPLE_SIZE_MASK,
414 SPDIF_SAMPLE_SIZE_16BIT);
415 break;
416 case 20:
417 hdmi_writeb_mask(hdmi, TPI_AUD_CONFIG, SPDIF_SAMPLE_SIZE_MASK,
418 SPDIF_SAMPLE_SIZE_20BIT);
419 break;
420 case 24:
421 hdmi_writeb_mask(hdmi, TPI_AUD_CONFIG, SPDIF_SAMPLE_SIZE_MASK,
422 SPDIF_SAMPLE_SIZE_24BIT);
423 break;
424 default:
425 DRM_DEV_ERROR(hdmi->dev, "invalid sample width %d\n",
426 params->sample_width);
427 return -EINVAL;
428 }
429
430 /* CTS is calculated by hardware, and we only need to take care of N */
431 n = zx_hdmi_audio_get_n(params->sample_rate);
432 hdmi_writeb(hdmi, N_SVAL1, n & 0xff);
433 hdmi_writeb(hdmi, N_SVAL2, (n >> 8) & 0xff);
434 hdmi_writeb(hdmi, N_SVAL3, (n >> 16) & 0xf);
435
436 /* Enable spdif mode */
437 hdmi_writeb_mask(hdmi, AUD_MODE, SPDIF_EN, SPDIF_EN);
438
439 /* Enable audio input */
440 hdmi_writeb_mask(hdmi, AUD_EN, AUD_IN_EN, AUD_IN_EN);
441
442 memcpy(&frame.audio, cea, sizeof(*cea));
443
444 return zx_hdmi_infoframe_trans(hdmi, &frame, FSEL_AUDIO);
445}
446
447static int zx_hdmi_audio_digital_mute(struct device *dev, void *data,
448 bool enable)
449{
450 struct zx_hdmi *hdmi = dev_get_drvdata(dev);
451
452 if (enable)
453 hdmi_writeb_mask(hdmi, TPI_AUD_CONFIG, TPI_AUD_MUTE,
454 TPI_AUD_MUTE);
455 else
456 hdmi_writeb_mask(hdmi, TPI_AUD_CONFIG, TPI_AUD_MUTE, 0);
457
458 return 0;
459}
460
461static int zx_hdmi_audio_get_eld(struct device *dev, void *data,
462 uint8_t *buf, size_t len)
463{
464 struct zx_hdmi *hdmi = dev_get_drvdata(dev);
465 struct drm_connector *connector = &hdmi->connector;
466
467 memcpy(buf, connector->eld, min(sizeof(connector->eld), len));
468
469 return 0;
470}
471
472static const struct hdmi_codec_ops zx_hdmi_codec_ops = {
473 .audio_startup = zx_hdmi_audio_startup,
474 .hw_params = zx_hdmi_audio_hw_params,
475 .audio_shutdown = zx_hdmi_audio_shutdown,
476 .digital_mute = zx_hdmi_audio_digital_mute,
477 .get_eld = zx_hdmi_audio_get_eld,
478};
479
480static struct hdmi_codec_pdata zx_hdmi_codec_pdata = {
481 .ops = &zx_hdmi_codec_ops,
482 .spdif = 1,
483};
484
485static int zx_hdmi_audio_register(struct zx_hdmi *hdmi)
486{
487 struct platform_device *pdev;
488
489 pdev = platform_device_register_data(hdmi->dev, HDMI_CODEC_DRV_NAME,
490 PLATFORM_DEVID_AUTO,
491 &zx_hdmi_codec_pdata,
492 sizeof(zx_hdmi_codec_pdata));
493 if (IS_ERR(pdev))
494 return PTR_ERR(pdev);
495
496 hdmi->audio_pdev = pdev;
497
498 return 0;
499}
500
369static int zx_hdmi_i2c_read(struct zx_hdmi *hdmi, struct i2c_msg *msg) 501static int zx_hdmi_i2c_read(struct zx_hdmi *hdmi, struct i2c_msg *msg)
370{ 502{
371 int len = msg->len; 503 int len = msg->len;
@@ -523,7 +655,6 @@ static int zx_hdmi_bind(struct device *dev, struct device *master, void *data)
523 655
524 hdmi->dev = dev; 656 hdmi->dev = dev;
525 hdmi->drm = drm; 657 hdmi->drm = drm;
526 hdmi->inf = &vou_inf_hdmi;
527 658
528 dev_set_drvdata(dev, hdmi); 659 dev_set_drvdata(dev, hdmi);
529 660
@@ -566,6 +697,12 @@ static int zx_hdmi_bind(struct device *dev, struct device *master, void *data)
566 return ret; 697 return ret;
567 } 698 }
568 699
700 ret = zx_hdmi_audio_register(hdmi);
701 if (ret) {
702 DRM_DEV_ERROR(dev, "failed to register audio: %d\n", ret);
703 return ret;
704 }
705
569 ret = zx_hdmi_register(drm, hdmi); 706 ret = zx_hdmi_register(drm, hdmi);
570 if (ret) { 707 if (ret) {
571 DRM_DEV_ERROR(dev, "failed to register hdmi: %d\n", ret); 708 DRM_DEV_ERROR(dev, "failed to register hdmi: %d\n", ret);
@@ -590,6 +727,9 @@ static void zx_hdmi_unbind(struct device *dev, struct device *master,
590 727
591 hdmi->connector.funcs->destroy(&hdmi->connector); 728 hdmi->connector.funcs->destroy(&hdmi->connector);
592 hdmi->encoder.funcs->destroy(&hdmi->encoder); 729 hdmi->encoder.funcs->destroy(&hdmi->encoder);
730
731 if (hdmi->audio_pdev)
732 platform_device_unregister(hdmi->audio_pdev);
593} 733}
594 734
595static const struct component_ops zx_hdmi_component_ops = { 735static const struct component_ops zx_hdmi_component_ops = {
diff --git a/drivers/gpu/drm/zte/zx_hdmi_regs.h b/drivers/gpu/drm/zte/zx_hdmi_regs.h
index de911f66b658..c6d5d8211725 100644
--- a/drivers/gpu/drm/zte/zx_hdmi_regs.h
+++ b/drivers/gpu/drm/zte/zx_hdmi_regs.h
@@ -52,5 +52,19 @@
52#define TPI_INFO_TRANS_RPT BIT(6) 52#define TPI_INFO_TRANS_RPT BIT(6)
53#define TPI_DDC_MASTER_EN 0x06f8 53#define TPI_DDC_MASTER_EN 0x06f8
54#define HW_DDC_MASTER BIT(7) 54#define HW_DDC_MASTER BIT(7)
55#define N_SVAL1 0xa03
56#define N_SVAL2 0xa04
57#define N_SVAL3 0xa05
58#define AUD_EN 0xa13
59#define AUD_IN_EN BIT(0)
60#define AUD_MODE 0xa14
61#define SPDIF_EN BIT(1)
62#define TPI_AUD_CONFIG 0xa62
63#define SPDIF_SAMPLE_SIZE_SHIFT 6
64#define SPDIF_SAMPLE_SIZE_MASK (0x3 << SPDIF_SAMPLE_SIZE_SHIFT)
65#define SPDIF_SAMPLE_SIZE_16BIT (0x1 << SPDIF_SAMPLE_SIZE_SHIFT)
66#define SPDIF_SAMPLE_SIZE_20BIT (0x2 << SPDIF_SAMPLE_SIZE_SHIFT)
67#define SPDIF_SAMPLE_SIZE_24BIT (0x3 << SPDIF_SAMPLE_SIZE_SHIFT)
68#define TPI_AUD_MUTE BIT(4)
55 69
56#endif /* __ZX_HDMI_REGS_H__ */ 70#endif /* __ZX_HDMI_REGS_H__ */
diff --git a/drivers/gpu/drm/zte/zx_plane.c b/drivers/gpu/drm/zte/zx_plane.c
index b634b090cdc1..1d08ba381098 100644
--- a/drivers/gpu/drm/zte/zx_plane.c
+++ b/drivers/gpu/drm/zte/zx_plane.c
@@ -21,16 +21,6 @@
21#include "zx_plane_regs.h" 21#include "zx_plane_regs.h"
22#include "zx_vou.h" 22#include "zx_vou.h"
23 23
24struct zx_plane {
25 struct drm_plane plane;
26 void __iomem *layer;
27 void __iomem *csc;
28 void __iomem *hbsc;
29 void __iomem *rsz;
30};
31
32#define to_zx_plane(plane) container_of(plane, struct zx_plane, plane)
33
34static const uint32_t gl_formats[] = { 24static const uint32_t gl_formats[] = {
35 DRM_FORMAT_ARGB8888, 25 DRM_FORMAT_ARGB8888,
36 DRM_FORMAT_XRGB8888, 26 DRM_FORMAT_XRGB8888,
@@ -40,6 +30,261 @@ static const uint32_t gl_formats[] = {
40 DRM_FORMAT_ARGB4444, 30 DRM_FORMAT_ARGB4444,
41}; 31};
42 32
33static const uint32_t vl_formats[] = {
34 DRM_FORMAT_NV12, /* Semi-planar YUV420 */
35 DRM_FORMAT_YUV420, /* Planar YUV420 */
36 DRM_FORMAT_YUYV, /* Packed YUV422 */
37 DRM_FORMAT_YVYU,
38 DRM_FORMAT_UYVY,
39 DRM_FORMAT_VYUY,
40 DRM_FORMAT_YUV444, /* YUV444 8bit */
41 /*
42 * TODO: add formats below that HW supports:
43 * - YUV420 P010
44 * - YUV420 Hantro
45 * - YUV444 10bit
46 */
47};
48
49#define FRAC_16_16(mult, div) (((mult) << 16) / (div))
50
51static int zx_vl_plane_atomic_check(struct drm_plane *plane,
52 struct drm_plane_state *plane_state)
53{
54 struct drm_framebuffer *fb = plane_state->fb;
55 struct drm_crtc *crtc = plane_state->crtc;
56 struct drm_crtc_state *crtc_state;
57 struct drm_rect clip;
58 int min_scale = FRAC_16_16(1, 8);
59 int max_scale = FRAC_16_16(8, 1);
60
61 if (!crtc || !fb)
62 return 0;
63
64 crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state,
65 crtc);
66 if (WARN_ON(!crtc_state))
67 return -EINVAL;
68
69 /* nothing to check when disabling or disabled */
70 if (!crtc_state->enable)
71 return 0;
72
73 /* plane must be enabled */
74 if (!plane_state->crtc)
75 return -EINVAL;
76
77 clip.x1 = 0;
78 clip.y1 = 0;
79 clip.x2 = crtc_state->adjusted_mode.hdisplay;
80 clip.y2 = crtc_state->adjusted_mode.vdisplay;
81
82 return drm_plane_helper_check_state(plane_state, &clip,
83 min_scale, max_scale,
84 true, true);
85}
86
87static int zx_vl_get_fmt(uint32_t format)
88{
89 switch (format) {
90 case DRM_FORMAT_NV12:
91 return VL_FMT_YUV420;
92 case DRM_FORMAT_YUV420:
93 return VL_YUV420_PLANAR | VL_FMT_YUV420;
94 case DRM_FORMAT_YUYV:
95 return VL_YUV422_YUYV | VL_FMT_YUV422;
96 case DRM_FORMAT_YVYU:
97 return VL_YUV422_YVYU | VL_FMT_YUV422;
98 case DRM_FORMAT_UYVY:
99 return VL_YUV422_UYVY | VL_FMT_YUV422;
100 case DRM_FORMAT_VYUY:
101 return VL_YUV422_VYUY | VL_FMT_YUV422;
102 case DRM_FORMAT_YUV444:
103 return VL_FMT_YUV444_8BIT;
104 default:
105 WARN_ONCE(1, "invalid pixel format %d\n", format);
106 return -EINVAL;
107 }
108}
109
110static inline void zx_vl_set_update(struct zx_plane *zplane)
111{
112 void __iomem *layer = zplane->layer;
113
114 zx_writel_mask(layer + VL_CTRL0, VL_UPDATE, VL_UPDATE);
115}
116
117static inline void zx_vl_rsz_set_update(struct zx_plane *zplane)
118{
119 zx_writel(zplane->rsz + RSZ_VL_ENABLE_CFG, 1);
120}
121
122static int zx_vl_rsz_get_fmt(uint32_t format)
123{
124 switch (format) {
125 case DRM_FORMAT_NV12:
126 case DRM_FORMAT_YUV420:
127 return RSZ_VL_FMT_YCBCR420;
128 case DRM_FORMAT_YUYV:
129 case DRM_FORMAT_YVYU:
130 case DRM_FORMAT_UYVY:
131 case DRM_FORMAT_VYUY:
132 return RSZ_VL_FMT_YCBCR422;
133 case DRM_FORMAT_YUV444:
134 return RSZ_VL_FMT_YCBCR444;
135 default:
136 WARN_ONCE(1, "invalid pixel format %d\n", format);
137 return -EINVAL;
138 }
139}
140
141static inline u32 rsz_step_value(u32 src, u32 dst)
142{
143 u32 val = 0;
144
145 if (src == dst)
146 val = 0;
147 else if (src < dst)
148 val = RSZ_PARA_STEP((src << 16) / dst);
149 else if (src > dst)
150 val = RSZ_DATA_STEP(src / dst) |
151 RSZ_PARA_STEP(((src << 16) / dst) & 0xffff);
152
153 return val;
154}
155
156static void zx_vl_rsz_setup(struct zx_plane *zplane, uint32_t format,
157 u32 src_w, u32 src_h, u32 dst_w, u32 dst_h)
158{
159 void __iomem *rsz = zplane->rsz;
160 u32 src_chroma_w = src_w;
161 u32 src_chroma_h = src_h;
162 u32 fmt;
163
164 /* Set up source and destination resolution */
165 zx_writel(rsz + RSZ_SRC_CFG, RSZ_VER(src_h - 1) | RSZ_HOR(src_w - 1));
166 zx_writel(rsz + RSZ_DEST_CFG, RSZ_VER(dst_h - 1) | RSZ_HOR(dst_w - 1));
167
168 /* Configure data format for VL RSZ */
169 fmt = zx_vl_rsz_get_fmt(format);
170 if (fmt >= 0)
171 zx_writel_mask(rsz + RSZ_VL_CTRL_CFG, RSZ_VL_FMT_MASK, fmt);
172
173 /* Calculate Chroma height and width */
174 if (fmt == RSZ_VL_FMT_YCBCR420) {
175 src_chroma_w = src_w >> 1;
176 src_chroma_h = src_h >> 1;
177 } else if (fmt == RSZ_VL_FMT_YCBCR422) {
178 src_chroma_w = src_w >> 1;
179 }
180
181 /* Set up Luma and Chroma step registers */
182 zx_writel(rsz + RSZ_VL_LUMA_HOR, rsz_step_value(src_w, dst_w));
183 zx_writel(rsz + RSZ_VL_LUMA_VER, rsz_step_value(src_h, dst_h));
184 zx_writel(rsz + RSZ_VL_CHROMA_HOR, rsz_step_value(src_chroma_w, dst_w));
185 zx_writel(rsz + RSZ_VL_CHROMA_VER, rsz_step_value(src_chroma_h, dst_h));
186
187 zx_vl_rsz_set_update(zplane);
188}
189
190static void zx_vl_plane_atomic_update(struct drm_plane *plane,
191 struct drm_plane_state *old_state)
192{
193 struct zx_plane *zplane = to_zx_plane(plane);
194 struct drm_plane_state *state = plane->state;
195 struct drm_framebuffer *fb = state->fb;
196 struct drm_rect *src = &state->src;
197 struct drm_rect *dst = &state->dst;
198 struct drm_gem_cma_object *cma_obj;
199 void __iomem *layer = zplane->layer;
200 void __iomem *hbsc = zplane->hbsc;
201 void __iomem *paddr_reg;
202 dma_addr_t paddr;
203 u32 src_x, src_y, src_w, src_h;
204 u32 dst_x, dst_y, dst_w, dst_h;
205 uint32_t format;
206 u32 fmt;
207 int num_planes;
208 int i;
209
210 if (!fb)
211 return;
212
213 format = fb->format->format;
214
215 src_x = src->x1 >> 16;
216 src_y = src->y1 >> 16;
217 src_w = drm_rect_width(src) >> 16;
218 src_h = drm_rect_height(src) >> 16;
219
220 dst_x = dst->x1;
221 dst_y = dst->y1;
222 dst_w = drm_rect_width(dst);
223 dst_h = drm_rect_height(dst);
224
225 /* Set up data address registers for Y, Cb and Cr planes */
226 num_planes = drm_format_num_planes(format);
227 paddr_reg = layer + VL_Y;
228 for (i = 0; i < num_planes; i++) {
229 cma_obj = drm_fb_cma_get_gem_obj(fb, i);
230 paddr = cma_obj->paddr + fb->offsets[i];
231 paddr += src_y * fb->pitches[i];
232 paddr += src_x * drm_format_plane_cpp(format, i);
233 zx_writel(paddr_reg, paddr);
234 paddr_reg += 4;
235 }
236
237 /* Set up source height/width register */
238 zx_writel(layer + VL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h));
239
240 /* Set up start position register */
241 zx_writel(layer + VL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y));
242
243 /* Set up end position register */
244 zx_writel(layer + VL_POS_END,
245 GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h));
246
247 /* Strides of Cb and Cr planes should be identical */
248 zx_writel(layer + VL_STRIDE, LUMA_STRIDE(fb->pitches[0]) |
249 CHROMA_STRIDE(fb->pitches[1]));
250
251 /* Set up video layer data format */
252 fmt = zx_vl_get_fmt(format);
253 if (fmt >= 0)
254 zx_writel(layer + VL_CTRL1, fmt);
255
256 /* Always use scaler since it exists (set for not bypass) */
257 zx_writel_mask(layer + VL_CTRL2, VL_SCALER_BYPASS_MODE,
258 VL_SCALER_BYPASS_MODE);
259
260 zx_vl_rsz_setup(zplane, format, src_w, src_h, dst_w, dst_h);
261
262 /* Enable HBSC block */
263 zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN);
264
265 zx_vou_layer_enable(plane);
266
267 zx_vl_set_update(zplane);
268}
269
270static void zx_plane_atomic_disable(struct drm_plane *plane,
271 struct drm_plane_state *old_state)
272{
273 struct zx_plane *zplane = to_zx_plane(plane);
274 void __iomem *hbsc = zplane->hbsc;
275
276 zx_vou_layer_disable(plane);
277
278 /* Disable HBSC block */
279 zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, 0);
280}
281
282static const struct drm_plane_helper_funcs zx_vl_plane_helper_funcs = {
283 .atomic_check = zx_vl_plane_atomic_check,
284 .atomic_update = zx_vl_plane_atomic_update,
285 .atomic_disable = zx_plane_atomic_disable,
286};
287
43static int zx_gl_plane_atomic_check(struct drm_plane *plane, 288static int zx_gl_plane_atomic_check(struct drm_plane *plane,
44 struct drm_plane_state *plane_state) 289 struct drm_plane_state *plane_state)
45{ 290{
@@ -107,14 +352,6 @@ static inline void zx_gl_rsz_set_update(struct zx_plane *zplane)
107 zx_writel(zplane->rsz + RSZ_ENABLE_CFG, 1); 352 zx_writel(zplane->rsz + RSZ_ENABLE_CFG, 1);
108} 353}
109 354
110void zx_plane_set_update(struct drm_plane *plane)
111{
112 struct zx_plane *zplane = to_zx_plane(plane);
113
114 zx_gl_rsz_set_update(zplane);
115 zx_gl_set_update(zplane);
116}
117
118static void zx_gl_rsz_setup(struct zx_plane *zplane, u32 src_w, u32 src_h, 355static void zx_gl_rsz_setup(struct zx_plane *zplane, u32 src_w, u32 src_h,
119 u32 dst_w, u32 dst_h) 356 u32 dst_w, u32 dst_h)
120{ 357{
@@ -207,12 +444,15 @@ static void zx_gl_plane_atomic_update(struct drm_plane *plane,
207 /* Enable HBSC block */ 444 /* Enable HBSC block */
208 zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN); 445 zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN);
209 446
447 zx_vou_layer_enable(plane);
448
210 zx_gl_set_update(zplane); 449 zx_gl_set_update(zplane);
211} 450}
212 451
213static const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs = { 452static const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs = {
214 .atomic_check = zx_gl_plane_atomic_check, 453 .atomic_check = zx_gl_plane_atomic_check,
215 .atomic_update = zx_gl_plane_atomic_update, 454 .atomic_update = zx_gl_plane_atomic_update,
455 .atomic_disable = zx_plane_atomic_disable,
216}; 456};
217 457
218static void zx_plane_destroy(struct drm_plane *plane) 458static void zx_plane_destroy(struct drm_plane *plane)
@@ -230,6 +470,28 @@ static const struct drm_plane_funcs zx_plane_funcs = {
230 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 470 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
231}; 471};
232 472
473void zx_plane_set_update(struct drm_plane *plane)
474{
475 struct zx_plane *zplane = to_zx_plane(plane);
476
477 /* Do nothing if the plane is not enabled */
478 if (!plane->state->crtc)
479 return;
480
481 switch (plane->type) {
482 case DRM_PLANE_TYPE_PRIMARY:
483 zx_gl_rsz_set_update(zplane);
484 zx_gl_set_update(zplane);
485 break;
486 case DRM_PLANE_TYPE_OVERLAY:
487 zx_vl_rsz_set_update(zplane);
488 zx_vl_set_update(zplane);
489 break;
490 default:
491 WARN_ONCE(1, "unsupported plane type %d\n", plane->type);
492 }
493}
494
233static void zx_plane_hbsc_init(struct zx_plane *zplane) 495static void zx_plane_hbsc_init(struct zx_plane *zplane)
234{ 496{
235 void __iomem *hbsc = zplane->hbsc; 497 void __iomem *hbsc = zplane->hbsc;
@@ -248,28 +510,16 @@ static void zx_plane_hbsc_init(struct zx_plane *zplane)
248 zx_writel(hbsc + HBSC_THRESHOLD_COL3, (0x3c0 << 16) | 0x40); 510 zx_writel(hbsc + HBSC_THRESHOLD_COL3, (0x3c0 << 16) | 0x40);
249} 511}
250 512
251struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev, 513int zx_plane_init(struct drm_device *drm, struct zx_plane *zplane,
252 struct zx_layer_data *data, 514 enum drm_plane_type type)
253 enum drm_plane_type type)
254{ 515{
255 const struct drm_plane_helper_funcs *helper; 516 const struct drm_plane_helper_funcs *helper;
256 struct zx_plane *zplane; 517 struct drm_plane *plane = &zplane->plane;
257 struct drm_plane *plane; 518 struct device *dev = zplane->dev;
258 const uint32_t *formats; 519 const uint32_t *formats;
259 unsigned int format_count; 520 unsigned int format_count;
260 int ret; 521 int ret;
261 522
262 zplane = devm_kzalloc(dev, sizeof(*zplane), GFP_KERNEL);
263 if (!zplane)
264 return ERR_PTR(-ENOMEM);
265
266 plane = &zplane->plane;
267
268 zplane->layer = data->layer;
269 zplane->hbsc = data->hbsc;
270 zplane->csc = data->csc;
271 zplane->rsz = data->rsz;
272
273 zx_plane_hbsc_init(zplane); 523 zx_plane_hbsc_init(zplane);
274 524
275 switch (type) { 525 switch (type) {
@@ -279,10 +529,12 @@ struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev,
279 format_count = ARRAY_SIZE(gl_formats); 529 format_count = ARRAY_SIZE(gl_formats);
280 break; 530 break;
281 case DRM_PLANE_TYPE_OVERLAY: 531 case DRM_PLANE_TYPE_OVERLAY:
282 /* TODO: add video layer (vl) support */ 532 helper = &zx_vl_plane_helper_funcs;
533 formats = vl_formats;
534 format_count = ARRAY_SIZE(vl_formats);
283 break; 535 break;
284 default: 536 default:
285 return ERR_PTR(-ENODEV); 537 return -ENODEV;
286 } 538 }
287 539
288 ret = drm_universal_plane_init(drm, plane, VOU_CRTC_MASK, 540 ret = drm_universal_plane_init(drm, plane, VOU_CRTC_MASK,
@@ -290,10 +542,10 @@ struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev,
290 type, NULL); 542 type, NULL);
291 if (ret) { 543 if (ret) {
292 DRM_DEV_ERROR(dev, "failed to init universal plane: %d\n", ret); 544 DRM_DEV_ERROR(dev, "failed to init universal plane: %d\n", ret);
293 return ERR_PTR(ret); 545 return ret;
294 } 546 }
295 547
296 drm_plane_helper_add(plane, helper); 548 drm_plane_helper_add(plane, helper);
297 549
298 return plane; 550 return 0;
299} 551}
diff --git a/drivers/gpu/drm/zte/zx_plane.h b/drivers/gpu/drm/zte/zx_plane.h
index 2b82cd558d9d..933611ddffd0 100644
--- a/drivers/gpu/drm/zte/zx_plane.h
+++ b/drivers/gpu/drm/zte/zx_plane.h
@@ -11,16 +11,20 @@
11#ifndef __ZX_PLANE_H__ 11#ifndef __ZX_PLANE_H__
12#define __ZX_PLANE_H__ 12#define __ZX_PLANE_H__
13 13
14struct zx_layer_data { 14struct zx_plane {
15 struct drm_plane plane;
16 struct device *dev;
15 void __iomem *layer; 17 void __iomem *layer;
16 void __iomem *csc; 18 void __iomem *csc;
17 void __iomem *hbsc; 19 void __iomem *hbsc;
18 void __iomem *rsz; 20 void __iomem *rsz;
21 const struct vou_layer_bits *bits;
19}; 22};
20 23
21struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev, 24#define to_zx_plane(plane) container_of(plane, struct zx_plane, plane)
22 struct zx_layer_data *data, 25
23 enum drm_plane_type type); 26int zx_plane_init(struct drm_device *drm, struct zx_plane *zplane,
27 enum drm_plane_type type);
24void zx_plane_set_update(struct drm_plane *plane); 28void zx_plane_set_update(struct drm_plane *plane);
25 29
26#endif /* __ZX_PLANE_H__ */ 30#endif /* __ZX_PLANE_H__ */
diff --git a/drivers/gpu/drm/zte/zx_plane_regs.h b/drivers/gpu/drm/zte/zx_plane_regs.h
index 3dde6716a558..65f271aeabed 100644
--- a/drivers/gpu/drm/zte/zx_plane_regs.h
+++ b/drivers/gpu/drm/zte/zx_plane_regs.h
@@ -46,6 +46,37 @@
46#define GL_POS_X(x) (((x) << GL_POS_X_SHIFT) & GL_POS_X_MASK) 46#define GL_POS_X(x) (((x) << GL_POS_X_SHIFT) & GL_POS_X_MASK)
47#define GL_POS_Y(x) (((x) << GL_POS_Y_SHIFT) & GL_POS_Y_MASK) 47#define GL_POS_Y(x) (((x) << GL_POS_Y_SHIFT) & GL_POS_Y_MASK)
48 48
49/* VL registers */
50#define VL_CTRL0 0x00
51#define VL_UPDATE BIT(3)
52#define VL_CTRL1 0x04
53#define VL_YUV420_PLANAR BIT(5)
54#define VL_YUV422_SHIFT 3
55#define VL_YUV422_YUYV (0 << VL_YUV422_SHIFT)
56#define VL_YUV422_YVYU (1 << VL_YUV422_SHIFT)
57#define VL_YUV422_UYVY (2 << VL_YUV422_SHIFT)
58#define VL_YUV422_VYUY (3 << VL_YUV422_SHIFT)
59#define VL_FMT_YUV420 0
60#define VL_FMT_YUV422 1
61#define VL_FMT_YUV420_P010 2
62#define VL_FMT_YUV420_HANTRO 3
63#define VL_FMT_YUV444_8BIT 4
64#define VL_FMT_YUV444_10BIT 5
65#define VL_CTRL2 0x08
66#define VL_SCALER_BYPASS_MODE BIT(0)
67#define VL_STRIDE 0x0c
68#define LUMA_STRIDE_SHIFT 16
69#define LUMA_STRIDE_MASK (0xffff << LUMA_STRIDE_SHIFT)
70#define CHROMA_STRIDE_SHIFT 0
71#define CHROMA_STRIDE_MASK (0xffff << CHROMA_STRIDE_SHIFT)
72#define VL_SRC_SIZE 0x10
73#define VL_Y 0x14
74#define VL_POS_START 0x30
75#define VL_POS_END 0x34
76
77#define LUMA_STRIDE(x) (((x) << LUMA_STRIDE_SHIFT) & LUMA_STRIDE_MASK)
78#define CHROMA_STRIDE(x) (((x) << CHROMA_STRIDE_SHIFT) & CHROMA_STRIDE_MASK)
79
49/* CSC registers */ 80/* CSC registers */
50#define CSC_CTRL0 0x30 81#define CSC_CTRL0 0x30
51#define CSC_COV_MODE_SHIFT 16 82#define CSC_COV_MODE_SHIFT 16
@@ -69,6 +100,18 @@
69#define RSZ_DEST_CFG 0x04 100#define RSZ_DEST_CFG 0x04
70#define RSZ_ENABLE_CFG 0x14 101#define RSZ_ENABLE_CFG 0x14
71 102
103#define RSZ_VL_LUMA_HOR 0x08
104#define RSZ_VL_LUMA_VER 0x0c
105#define RSZ_VL_CHROMA_HOR 0x10
106#define RSZ_VL_CHROMA_VER 0x14
107#define RSZ_VL_CTRL_CFG 0x18
108#define RSZ_VL_FMT_SHIFT 3
109#define RSZ_VL_FMT_MASK (0x3 << RSZ_VL_FMT_SHIFT)
110#define RSZ_VL_FMT_YCBCR420 (0x0 << RSZ_VL_FMT_SHIFT)
111#define RSZ_VL_FMT_YCBCR422 (0x1 << RSZ_VL_FMT_SHIFT)
112#define RSZ_VL_FMT_YCBCR444 (0x2 << RSZ_VL_FMT_SHIFT)
113#define RSZ_VL_ENABLE_CFG 0x1c
114
72#define RSZ_VER_SHIFT 16 115#define RSZ_VER_SHIFT 16
73#define RSZ_VER_MASK (0xffff << RSZ_VER_SHIFT) 116#define RSZ_VER_MASK (0xffff << RSZ_VER_SHIFT)
74#define RSZ_HOR_SHIFT 0 117#define RSZ_HOR_SHIFT 0
@@ -77,6 +120,14 @@
77#define RSZ_VER(x) (((x) << RSZ_VER_SHIFT) & RSZ_VER_MASK) 120#define RSZ_VER(x) (((x) << RSZ_VER_SHIFT) & RSZ_VER_MASK)
78#define RSZ_HOR(x) (((x) << RSZ_HOR_SHIFT) & RSZ_HOR_MASK) 121#define RSZ_HOR(x) (((x) << RSZ_HOR_SHIFT) & RSZ_HOR_MASK)
79 122
123#define RSZ_DATA_STEP_SHIFT 16
124#define RSZ_DATA_STEP_MASK (0xffff << RSZ_DATA_STEP_SHIFT)
125#define RSZ_PARA_STEP_SHIFT 0
126#define RSZ_PARA_STEP_MASK (0xffff << RSZ_PARA_STEP_SHIFT)
127
128#define RSZ_DATA_STEP(x) (((x) << RSZ_DATA_STEP_SHIFT) & RSZ_DATA_STEP_MASK)
129#define RSZ_PARA_STEP(x) (((x) << RSZ_PARA_STEP_SHIFT) & RSZ_PARA_STEP_MASK)
130
80/* HBSC registers */ 131/* HBSC registers */
81#define HBSC_SATURATION 0x00 132#define HBSC_SATURATION 0x00
82#define HBSC_HUE 0x04 133#define HBSC_HUE 0x04
diff --git a/drivers/gpu/drm/zte/zx_tvenc.c b/drivers/gpu/drm/zte/zx_tvenc.c
new file mode 100644
index 000000000000..b56dc69843fc
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_tvenc.c
@@ -0,0 +1,407 @@
1/*
2 * Copyright 2017 Linaro Ltd.
3 * Copyright 2017 ZTE Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 */
10
11#include <linux/clk.h>
12#include <linux/component.h>
13#include <linux/mfd/syscon.h>
14#include <linux/regmap.h>
15
16#include <drm/drm_atomic_helper.h>
17#include <drm/drm_crtc_helper.h>
18#include <drm/drmP.h>
19
20#include "zx_drm_drv.h"
21#include "zx_tvenc_regs.h"
22#include "zx_vou.h"
23
24struct zx_tvenc_pwrctrl {
25 struct regmap *regmap;
26 u32 reg;
27 u32 mask;
28};
29
30struct zx_tvenc {
31 struct drm_connector connector;
32 struct drm_encoder encoder;
33 struct device *dev;
34 void __iomem *mmio;
35 const struct vou_inf *inf;
36 struct zx_tvenc_pwrctrl pwrctrl;
37};
38
39#define to_zx_tvenc(x) container_of(x, struct zx_tvenc, x)
40
41struct zx_tvenc_mode {
42 struct drm_display_mode mode;
43 u32 video_info;
44 u32 video_res;
45 u32 field1_param;
46 u32 field2_param;
47 u32 burst_line_odd1;
48 u32 burst_line_even1;
49 u32 burst_line_odd2;
50 u32 burst_line_even2;
51 u32 line_timing_param;
52 u32 weight_value;
53 u32 blank_black_level;
54 u32 burst_level;
55 u32 control_param;
56 u32 sub_carrier_phase1;
57 u32 phase_line_incr_cvbs;
58};
59
60/*
61 * The CRM cannot directly provide a suitable frequency, and we have to
62 * ask a multiplied rate from CRM and use the divider in VOU to get the
63 * desired one.
64 */
65#define TVENC_CLOCK_MULTIPLIER 4
66
67static const struct zx_tvenc_mode tvenc_mode_pal = {
68 .mode = {
69 .clock = 13500 * TVENC_CLOCK_MULTIPLIER,
70 .hdisplay = 720,
71 .hsync_start = 720 + 12,
72 .hsync_end = 720 + 12 + 2,
73 .htotal = 720 + 12 + 2 + 130,
74 .vdisplay = 576,
75 .vsync_start = 576 + 2,
76 .vsync_end = 576 + 2 + 2,
77 .vtotal = 576 + 2 + 2 + 20,
78 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
79 DRM_MODE_FLAG_INTERLACE,
80 },
81 .video_info = 0x00040040,
82 .video_res = 0x05a9c760,
83 .field1_param = 0x0004d416,
84 .field2_param = 0x0009b94f,
85 .burst_line_odd1 = 0x0004d406,
86 .burst_line_even1 = 0x0009b53e,
87 .burst_line_odd2 = 0x0004d805,
88 .burst_line_even2 = 0x0009b93f,
89 .line_timing_param = 0x06a96fdf,
90 .weight_value = 0x00c188a0,
91 .blank_black_level = 0x0000fcfc,
92 .burst_level = 0x00001595,
93 .control_param = 0x00000001,
94 .sub_carrier_phase1 = 0x1504c566,
95 .phase_line_incr_cvbs = 0xc068db8c,
96};
97
98static const struct zx_tvenc_mode tvenc_mode_ntsc = {
99 .mode = {
100 .clock = 13500 * TVENC_CLOCK_MULTIPLIER,
101 .hdisplay = 720,
102 .hsync_start = 720 + 16,
103 .hsync_end = 720 + 16 + 2,
104 .htotal = 720 + 16 + 2 + 120,
105 .vdisplay = 480,
106 .vsync_start = 480 + 3,
107 .vsync_end = 480 + 3 + 2,
108 .vtotal = 480 + 3 + 2 + 17,
109 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
110 DRM_MODE_FLAG_INTERLACE,
111 },
112 .video_info = 0x00040080,
113 .video_res = 0x05a8375a,
114 .field1_param = 0x00041817,
115 .field2_param = 0x0008351e,
116 .burst_line_odd1 = 0x00041006,
117 .burst_line_even1 = 0x0008290d,
118 .burst_line_odd2 = 0x00000000,
119 .burst_line_even2 = 0x00000000,
120 .line_timing_param = 0x06a8ef9e,
121 .weight_value = 0x00b68197,
122 .blank_black_level = 0x0000f0f0,
123 .burst_level = 0x0000009c,
124 .control_param = 0x00000001,
125 .sub_carrier_phase1 = 0x10f83e10,
126 .phase_line_incr_cvbs = 0x80000000,
127};
128
129static const struct zx_tvenc_mode *tvenc_modes[] = {
130 &tvenc_mode_pal,
131 &tvenc_mode_ntsc,
132};
133
134static const struct zx_tvenc_mode *
135zx_tvenc_find_zmode(struct drm_display_mode *mode)
136{
137 int i;
138
139 for (i = 0; i < ARRAY_SIZE(tvenc_modes); i++) {
140 const struct zx_tvenc_mode *zmode = tvenc_modes[i];
141
142 if (drm_mode_equal(mode, &zmode->mode))
143 return zmode;
144 }
145
146 return NULL;
147}
148
149static void zx_tvenc_encoder_mode_set(struct drm_encoder *encoder,
150 struct drm_display_mode *mode,
151 struct drm_display_mode *adj_mode)
152{
153 struct zx_tvenc *tvenc = to_zx_tvenc(encoder);
154 const struct zx_tvenc_mode *zmode;
155 struct vou_div_config configs[] = {
156 { VOU_DIV_INF, VOU_DIV_4 },
157 { VOU_DIV_TVENC, VOU_DIV_1 },
158 { VOU_DIV_LAYER, VOU_DIV_2 },
159 };
160
161 zx_vou_config_dividers(encoder->crtc, configs, ARRAY_SIZE(configs));
162
163 zmode = zx_tvenc_find_zmode(mode);
164 if (!zmode) {
165 DRM_DEV_ERROR(tvenc->dev, "failed to find zmode\n");
166 return;
167 }
168
169 zx_writel(tvenc->mmio + VENC_VIDEO_INFO, zmode->video_info);
170 zx_writel(tvenc->mmio + VENC_VIDEO_RES, zmode->video_res);
171 zx_writel(tvenc->mmio + VENC_FIELD1_PARAM, zmode->field1_param);
172 zx_writel(tvenc->mmio + VENC_FIELD2_PARAM, zmode->field2_param);
173 zx_writel(tvenc->mmio + VENC_LINE_O_1, zmode->burst_line_odd1);
174 zx_writel(tvenc->mmio + VENC_LINE_E_1, zmode->burst_line_even1);
175 zx_writel(tvenc->mmio + VENC_LINE_O_2, zmode->burst_line_odd2);
176 zx_writel(tvenc->mmio + VENC_LINE_E_2, zmode->burst_line_even2);
177 zx_writel(tvenc->mmio + VENC_LINE_TIMING_PARAM,
178 zmode->line_timing_param);
179 zx_writel(tvenc->mmio + VENC_WEIGHT_VALUE, zmode->weight_value);
180 zx_writel(tvenc->mmio + VENC_BLANK_BLACK_LEVEL,
181 zmode->blank_black_level);
182 zx_writel(tvenc->mmio + VENC_BURST_LEVEL, zmode->burst_level);
183 zx_writel(tvenc->mmio + VENC_CONTROL_PARAM, zmode->control_param);
184 zx_writel(tvenc->mmio + VENC_SUB_CARRIER_PHASE1,
185 zmode->sub_carrier_phase1);
186 zx_writel(tvenc->mmio + VENC_PHASE_LINE_INCR_CVBS,
187 zmode->phase_line_incr_cvbs);
188}
189
190static void zx_tvenc_encoder_enable(struct drm_encoder *encoder)
191{
192 struct zx_tvenc *tvenc = to_zx_tvenc(encoder);
193 struct zx_tvenc_pwrctrl *pwrctrl = &tvenc->pwrctrl;
194
195 /* Set bit to power up TVENC DAC */
196 regmap_update_bits(pwrctrl->regmap, pwrctrl->reg, pwrctrl->mask,
197 pwrctrl->mask);
198
199 vou_inf_enable(VOU_TV_ENC, encoder->crtc);
200
201 zx_writel(tvenc->mmio + VENC_ENABLE, 1);
202}
203
204static void zx_tvenc_encoder_disable(struct drm_encoder *encoder)
205{
206 struct zx_tvenc *tvenc = to_zx_tvenc(encoder);
207 struct zx_tvenc_pwrctrl *pwrctrl = &tvenc->pwrctrl;
208
209 zx_writel(tvenc->mmio + VENC_ENABLE, 0);
210
211 vou_inf_disable(VOU_TV_ENC, encoder->crtc);
212
213 /* Clear bit to power down TVENC DAC */
214 regmap_update_bits(pwrctrl->regmap, pwrctrl->reg, pwrctrl->mask, 0);
215}
216
217static const struct drm_encoder_helper_funcs zx_tvenc_encoder_helper_funcs = {
218 .enable = zx_tvenc_encoder_enable,
219 .disable = zx_tvenc_encoder_disable,
220 .mode_set = zx_tvenc_encoder_mode_set,
221};
222
223static const struct drm_encoder_funcs zx_tvenc_encoder_funcs = {
224 .destroy = drm_encoder_cleanup,
225};
226
227static int zx_tvenc_connector_get_modes(struct drm_connector *connector)
228{
229 struct zx_tvenc *tvenc = to_zx_tvenc(connector);
230 struct device *dev = tvenc->dev;
231 int i;
232
233 for (i = 0; i < ARRAY_SIZE(tvenc_modes); i++) {
234 const struct zx_tvenc_mode *zmode = tvenc_modes[i];
235 struct drm_display_mode *mode;
236
237 mode = drm_mode_duplicate(connector->dev, &zmode->mode);
238 if (!mode) {
239 DRM_DEV_ERROR(dev, "failed to duplicate drm mode\n");
240 continue;
241 }
242
243 drm_mode_set_name(mode);
244 drm_mode_probed_add(connector, mode);
245 }
246
247 return i;
248}
249
250static enum drm_mode_status
251zx_tvenc_connector_mode_valid(struct drm_connector *connector,
252 struct drm_display_mode *mode)
253{
254 struct zx_tvenc *tvenc = to_zx_tvenc(connector);
255 const struct zx_tvenc_mode *zmode;
256
257 zmode = zx_tvenc_find_zmode(mode);
258 if (!zmode) {
259 DRM_DEV_ERROR(tvenc->dev, "unsupported mode: %s\n", mode->name);
260 return MODE_NOMODE;
261 }
262
263 return MODE_OK;
264}
265
266static struct drm_connector_helper_funcs zx_tvenc_connector_helper_funcs = {
267 .get_modes = zx_tvenc_connector_get_modes,
268 .mode_valid = zx_tvenc_connector_mode_valid,
269};
270
271static const struct drm_connector_funcs zx_tvenc_connector_funcs = {
272 .dpms = drm_atomic_helper_connector_dpms,
273 .fill_modes = drm_helper_probe_single_connector_modes,
274 .destroy = drm_connector_cleanup,
275 .reset = drm_atomic_helper_connector_reset,
276 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
277 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
278};
279
280static int zx_tvenc_register(struct drm_device *drm, struct zx_tvenc *tvenc)
281{
282 struct drm_encoder *encoder = &tvenc->encoder;
283 struct drm_connector *connector = &tvenc->connector;
284
285 /*
286 * The tvenc is designed to use aux channel, as there is a deflicker
287 * block for the channel.
288 */
289 encoder->possible_crtcs = BIT(1);
290
291 drm_encoder_init(drm, encoder, &zx_tvenc_encoder_funcs,
292 DRM_MODE_ENCODER_TVDAC, NULL);
293 drm_encoder_helper_add(encoder, &zx_tvenc_encoder_helper_funcs);
294
295 connector->interlace_allowed = true;
296
297 drm_connector_init(drm, connector, &zx_tvenc_connector_funcs,
298 DRM_MODE_CONNECTOR_Composite);
299 drm_connector_helper_add(connector, &zx_tvenc_connector_helper_funcs);
300
301 drm_mode_connector_attach_encoder(connector, encoder);
302
303 return 0;
304}
305
306static int zx_tvenc_pwrctrl_init(struct zx_tvenc *tvenc)
307{
308 struct zx_tvenc_pwrctrl *pwrctrl = &tvenc->pwrctrl;
309 struct device *dev = tvenc->dev;
310 struct of_phandle_args out_args;
311 struct regmap *regmap;
312 int ret;
313
314 ret = of_parse_phandle_with_fixed_args(dev->of_node,
315 "zte,tvenc-power-control", 2, 0, &out_args);
316 if (ret)
317 return ret;
318
319 regmap = syscon_node_to_regmap(out_args.np);
320 if (IS_ERR(regmap)) {
321 ret = PTR_ERR(regmap);
322 goto out;
323 }
324
325 pwrctrl->regmap = regmap;
326 pwrctrl->reg = out_args.args[0];
327 pwrctrl->mask = out_args.args[1];
328
329out:
330 of_node_put(out_args.np);
331 return ret;
332}
333
334static int zx_tvenc_bind(struct device *dev, struct device *master, void *data)
335{
336 struct platform_device *pdev = to_platform_device(dev);
337 struct drm_device *drm = data;
338 struct resource *res;
339 struct zx_tvenc *tvenc;
340 int ret;
341
342 tvenc = devm_kzalloc(dev, sizeof(*tvenc), GFP_KERNEL);
343 if (!tvenc)
344 return -ENOMEM;
345
346 tvenc->dev = dev;
347 dev_set_drvdata(dev, tvenc);
348
349 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
350 tvenc->mmio = devm_ioremap_resource(dev, res);
351 if (IS_ERR(tvenc->mmio)) {
352 ret = PTR_ERR(tvenc->mmio);
353 DRM_DEV_ERROR(dev, "failed to remap tvenc region: %d\n", ret);
354 return ret;
355 }
356
357 ret = zx_tvenc_pwrctrl_init(tvenc);
358 if (ret) {
359 DRM_DEV_ERROR(dev, "failed to init power control: %d\n", ret);
360 return ret;
361 }
362
363 ret = zx_tvenc_register(drm, tvenc);
364 if (ret) {
365 DRM_DEV_ERROR(dev, "failed to register tvenc: %d\n", ret);
366 return ret;
367 }
368
369 return 0;
370}
371
372static void zx_tvenc_unbind(struct device *dev, struct device *master,
373 void *data)
374{
375 /* Nothing to do */
376}
377
378static const struct component_ops zx_tvenc_component_ops = {
379 .bind = zx_tvenc_bind,
380 .unbind = zx_tvenc_unbind,
381};
382
383static int zx_tvenc_probe(struct platform_device *pdev)
384{
385 return component_add(&pdev->dev, &zx_tvenc_component_ops);
386}
387
388static int zx_tvenc_remove(struct platform_device *pdev)
389{
390 component_del(&pdev->dev, &zx_tvenc_component_ops);
391 return 0;
392}
393
394static const struct of_device_id zx_tvenc_of_match[] = {
395 { .compatible = "zte,zx296718-tvenc", },
396 { /* end */ },
397};
398MODULE_DEVICE_TABLE(of, zx_tvenc_of_match);
399
400struct platform_driver zx_tvenc_driver = {
401 .probe = zx_tvenc_probe,
402 .remove = zx_tvenc_remove,
403 .driver = {
404 .name = "zx-tvenc",
405 .of_match_table = zx_tvenc_of_match,
406 },
407};
diff --git a/drivers/gpu/drm/zte/zx_tvenc_regs.h b/drivers/gpu/drm/zte/zx_tvenc_regs.h
new file mode 100644
index 000000000000..bd91f5dcc1f3
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_tvenc_regs.h
@@ -0,0 +1,31 @@
1/*
2 * Copyright 2017 Linaro Ltd.
3 * Copyright 2017 ZTE Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 */
10
11#ifndef __ZX_TVENC_REGS_H__
12#define __ZX_TVENC_REGS_H__
13
14#define VENC_VIDEO_INFO 0x04
15#define VENC_VIDEO_RES 0x08
16#define VENC_FIELD1_PARAM 0x10
17#define VENC_FIELD2_PARAM 0x14
18#define VENC_LINE_O_1 0x18
19#define VENC_LINE_E_1 0x1c
20#define VENC_LINE_O_2 0x20
21#define VENC_LINE_E_2 0x24
22#define VENC_LINE_TIMING_PARAM 0x28
23#define VENC_WEIGHT_VALUE 0x2c
24#define VENC_BLANK_BLACK_LEVEL 0x30
25#define VENC_BURST_LEVEL 0x34
26#define VENC_CONTROL_PARAM 0x3c
27#define VENC_SUB_CARRIER_PHASE1 0x40
28#define VENC_PHASE_LINE_INCR_CVBS 0x48
29#define VENC_ENABLE 0xa8
30
31#endif /* __ZX_TVENC_REGS_H__ */
diff --git a/drivers/gpu/drm/zte/zx_vou.c b/drivers/gpu/drm/zte/zx_vou.c
index a86e3a5852a2..cf92d675feaa 100644
--- a/drivers/gpu/drm/zte/zx_vou.c
+++ b/drivers/gpu/drm/zte/zx_vou.c
@@ -40,6 +40,7 @@ struct zx_crtc_regs {
40 u32 fir_active; 40 u32 fir_active;
41 u32 fir_htiming; 41 u32 fir_htiming;
42 u32 fir_vtiming; 42 u32 fir_vtiming;
43 u32 sec_vtiming;
43 u32 timing_shift; 44 u32 timing_shift;
44 u32 timing_pi_shift; 45 u32 timing_pi_shift;
45}; 46};
@@ -48,6 +49,7 @@ static const struct zx_crtc_regs main_crtc_regs = {
48 .fir_active = FIR_MAIN_ACTIVE, 49 .fir_active = FIR_MAIN_ACTIVE,
49 .fir_htiming = FIR_MAIN_H_TIMING, 50 .fir_htiming = FIR_MAIN_H_TIMING,
50 .fir_vtiming = FIR_MAIN_V_TIMING, 51 .fir_vtiming = FIR_MAIN_V_TIMING,
52 .sec_vtiming = SEC_MAIN_V_TIMING,
51 .timing_shift = TIMING_MAIN_SHIFT, 53 .timing_shift = TIMING_MAIN_SHIFT,
52 .timing_pi_shift = TIMING_MAIN_PI_SHIFT, 54 .timing_pi_shift = TIMING_MAIN_PI_SHIFT,
53}; 55};
@@ -56,6 +58,7 @@ static const struct zx_crtc_regs aux_crtc_regs = {
56 .fir_active = FIR_AUX_ACTIVE, 58 .fir_active = FIR_AUX_ACTIVE,
57 .fir_htiming = FIR_AUX_H_TIMING, 59 .fir_htiming = FIR_AUX_H_TIMING,
58 .fir_vtiming = FIR_AUX_V_TIMING, 60 .fir_vtiming = FIR_AUX_V_TIMING,
61 .sec_vtiming = SEC_AUX_V_TIMING,
59 .timing_shift = TIMING_AUX_SHIFT, 62 .timing_shift = TIMING_AUX_SHIFT,
60 .timing_pi_shift = TIMING_AUX_PI_SHIFT, 63 .timing_pi_shift = TIMING_AUX_PI_SHIFT,
61}; 64};
@@ -65,7 +68,17 @@ struct zx_crtc_bits {
65 u32 polarity_shift; 68 u32 polarity_shift;
66 u32 int_frame_mask; 69 u32 int_frame_mask;
67 u32 tc_enable; 70 u32 tc_enable;
68 u32 gl_enable; 71 u32 sec_vactive_shift;
72 u32 sec_vactive_mask;
73 u32 interlace_select;
74 u32 pi_enable;
75 u32 div_vga_shift;
76 u32 div_pic_shift;
77 u32 div_tvenc_shift;
78 u32 div_hdmi_pnx_shift;
79 u32 div_hdmi_shift;
80 u32 div_inf_shift;
81 u32 div_layer_shift;
69}; 82};
70 83
71static const struct zx_crtc_bits main_crtc_bits = { 84static const struct zx_crtc_bits main_crtc_bits = {
@@ -73,7 +86,17 @@ static const struct zx_crtc_bits main_crtc_bits = {
73 .polarity_shift = MAIN_POL_SHIFT, 86 .polarity_shift = MAIN_POL_SHIFT,
74 .int_frame_mask = TIMING_INT_MAIN_FRAME, 87 .int_frame_mask = TIMING_INT_MAIN_FRAME,
75 .tc_enable = MAIN_TC_EN, 88 .tc_enable = MAIN_TC_EN,
76 .gl_enable = OSD_CTRL0_GL0_EN, 89 .sec_vactive_shift = SEC_VACT_MAIN_SHIFT,
90 .sec_vactive_mask = SEC_VACT_MAIN_MASK,
91 .interlace_select = MAIN_INTERLACE_SEL,
92 .pi_enable = MAIN_PI_EN,
93 .div_vga_shift = VGA_MAIN_DIV_SHIFT,
94 .div_pic_shift = PIC_MAIN_DIV_SHIFT,
95 .div_tvenc_shift = TVENC_MAIN_DIV_SHIFT,
96 .div_hdmi_pnx_shift = HDMI_MAIN_PNX_DIV_SHIFT,
97 .div_hdmi_shift = HDMI_MAIN_DIV_SHIFT,
98 .div_inf_shift = INF_MAIN_DIV_SHIFT,
99 .div_layer_shift = LAYER_MAIN_DIV_SHIFT,
77}; 100};
78 101
79static const struct zx_crtc_bits aux_crtc_bits = { 102static const struct zx_crtc_bits aux_crtc_bits = {
@@ -81,7 +104,17 @@ static const struct zx_crtc_bits aux_crtc_bits = {
81 .polarity_shift = AUX_POL_SHIFT, 104 .polarity_shift = AUX_POL_SHIFT,
82 .int_frame_mask = TIMING_INT_AUX_FRAME, 105 .int_frame_mask = TIMING_INT_AUX_FRAME,
83 .tc_enable = AUX_TC_EN, 106 .tc_enable = AUX_TC_EN,
84 .gl_enable = OSD_CTRL0_GL1_EN, 107 .sec_vactive_shift = SEC_VACT_AUX_SHIFT,
108 .sec_vactive_mask = SEC_VACT_AUX_MASK,
109 .interlace_select = AUX_INTERLACE_SEL,
110 .pi_enable = AUX_PI_EN,
111 .div_vga_shift = VGA_AUX_DIV_SHIFT,
112 .div_pic_shift = PIC_AUX_DIV_SHIFT,
113 .div_tvenc_shift = TVENC_AUX_DIV_SHIFT,
114 .div_hdmi_pnx_shift = HDMI_AUX_PNX_DIV_SHIFT,
115 .div_hdmi_shift = HDMI_AUX_DIV_SHIFT,
116 .div_inf_shift = INF_AUX_DIV_SHIFT,
117 .div_layer_shift = LAYER_AUX_DIV_SHIFT,
85}; 118};
86 119
87struct zx_crtc { 120struct zx_crtc {
@@ -97,6 +130,40 @@ struct zx_crtc {
97 130
98#define to_zx_crtc(x) container_of(x, struct zx_crtc, crtc) 131#define to_zx_crtc(x) container_of(x, struct zx_crtc, crtc)
99 132
133struct vou_layer_bits {
134 u32 enable;
135 u32 chnsel;
136 u32 clksel;
137};
138
139static const struct vou_layer_bits zx_gl_bits[GL_NUM] = {
140 {
141 .enable = OSD_CTRL0_GL0_EN,
142 .chnsel = OSD_CTRL0_GL0_SEL,
143 .clksel = VOU_CLK_GL0_SEL,
144 }, {
145 .enable = OSD_CTRL0_GL1_EN,
146 .chnsel = OSD_CTRL0_GL1_SEL,
147 .clksel = VOU_CLK_GL1_SEL,
148 },
149};
150
151static const struct vou_layer_bits zx_vl_bits[VL_NUM] = {
152 {
153 .enable = OSD_CTRL0_VL0_EN,
154 .chnsel = OSD_CTRL0_VL0_SEL,
155 .clksel = VOU_CLK_VL0_SEL,
156 }, {
157 .enable = OSD_CTRL0_VL1_EN,
158 .chnsel = OSD_CTRL0_VL1_SEL,
159 .clksel = VOU_CLK_VL1_SEL,
160 }, {
161 .enable = OSD_CTRL0_VL2_EN,
162 .chnsel = OSD_CTRL0_VL2_SEL,
163 .clksel = VOU_CLK_VL2_SEL,
164 },
165};
166
100struct zx_vou_hw { 167struct zx_vou_hw {
101 struct device *dev; 168 struct device *dev;
102 void __iomem *osd; 169 void __iomem *osd;
@@ -112,6 +179,33 @@ struct zx_vou_hw {
112 struct zx_crtc *aux_crtc; 179 struct zx_crtc *aux_crtc;
113}; 180};
114 181
182enum vou_inf_data_sel {
183 VOU_YUV444 = 0,
184 VOU_RGB_101010 = 1,
185 VOU_RGB_888 = 2,
186 VOU_RGB_666 = 3,
187};
188
189struct vou_inf {
190 enum vou_inf_id id;
191 enum vou_inf_data_sel data_sel;
192 u32 clocks_en_bits;
193 u32 clocks_sel_bits;
194};
195
196static struct vou_inf vou_infs[] = {
197 [VOU_HDMI] = {
198 .data_sel = VOU_YUV444,
199 .clocks_en_bits = BIT(24) | BIT(18) | BIT(6),
200 .clocks_sel_bits = BIT(13) | BIT(2),
201 },
202 [VOU_TV_ENC] = {
203 .data_sel = VOU_YUV444,
204 .clocks_en_bits = BIT(15),
205 .clocks_sel_bits = BIT(11) | BIT(0),
206 },
207};
208
115static inline struct zx_vou_hw *crtc_to_vou(struct drm_crtc *crtc) 209static inline struct zx_vou_hw *crtc_to_vou(struct drm_crtc *crtc)
116{ 210{
117 struct zx_crtc *zcrtc = to_zx_crtc(crtc); 211 struct zx_crtc *zcrtc = to_zx_crtc(crtc);
@@ -119,20 +213,30 @@ static inline struct zx_vou_hw *crtc_to_vou(struct drm_crtc *crtc)
119 return zcrtc->vou; 213 return zcrtc->vou;
120} 214}
121 215
122void vou_inf_enable(const struct vou_inf *inf, struct drm_crtc *crtc) 216void vou_inf_hdmi_audio_sel(struct drm_crtc *crtc,
217 enum vou_inf_hdmi_audio aud)
123{ 218{
124 struct zx_crtc *zcrtc = to_zx_crtc(crtc); 219 struct zx_crtc *zcrtc = to_zx_crtc(crtc);
125 struct zx_vou_hw *vou = zcrtc->vou; 220 struct zx_vou_hw *vou = zcrtc->vou;
221
222 zx_writel_mask(vou->vouctl + VOU_INF_HDMI_CTRL, VOU_HDMI_AUD_MASK, aud);
223}
224
225void vou_inf_enable(enum vou_inf_id id, struct drm_crtc *crtc)
226{
227 struct zx_crtc *zcrtc = to_zx_crtc(crtc);
228 struct zx_vou_hw *vou = zcrtc->vou;
229 struct vou_inf *inf = &vou_infs[id];
126 bool is_main = zcrtc->chn_type == VOU_CHN_MAIN; 230 bool is_main = zcrtc->chn_type == VOU_CHN_MAIN;
127 u32 data_sel_shift = inf->id << 1; 231 u32 data_sel_shift = id << 1;
128 232
129 /* Select data format */ 233 /* Select data format */
130 zx_writel_mask(vou->vouctl + VOU_INF_DATA_SEL, 0x3 << data_sel_shift, 234 zx_writel_mask(vou->vouctl + VOU_INF_DATA_SEL, 0x3 << data_sel_shift,
131 inf->data_sel << data_sel_shift); 235 inf->data_sel << data_sel_shift);
132 236
133 /* Select channel */ 237 /* Select channel */
134 zx_writel_mask(vou->vouctl + VOU_INF_CH_SEL, 0x1 << inf->id, 238 zx_writel_mask(vou->vouctl + VOU_INF_CH_SEL, 0x1 << id,
135 zcrtc->chn_type << inf->id); 239 zcrtc->chn_type << id);
136 240
137 /* Select interface clocks */ 241 /* Select interface clocks */
138 zx_writel_mask(vou->vouctl + VOU_CLK_SEL, inf->clocks_sel_bits, 242 zx_writel_mask(vou->vouctl + VOU_CLK_SEL, inf->clocks_sel_bits,
@@ -143,20 +247,79 @@ void vou_inf_enable(const struct vou_inf *inf, struct drm_crtc *crtc)
143 inf->clocks_en_bits); 247 inf->clocks_en_bits);
144 248
145 /* Enable the device */ 249 /* Enable the device */
146 zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << inf->id, 1 << inf->id); 250 zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << id, 1 << id);
147} 251}
148 252
149void vou_inf_disable(const struct vou_inf *inf, struct drm_crtc *crtc) 253void vou_inf_disable(enum vou_inf_id id, struct drm_crtc *crtc)
150{ 254{
151 struct zx_vou_hw *vou = crtc_to_vou(crtc); 255 struct zx_vou_hw *vou = crtc_to_vou(crtc);
256 struct vou_inf *inf = &vou_infs[id];
152 257
153 /* Disable the device */ 258 /* Disable the device */
154 zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << inf->id, 0); 259 zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << id, 0);
155 260
156 /* Disable interface clocks */ 261 /* Disable interface clocks */
157 zx_writel_mask(vou->vouctl + VOU_CLK_EN, inf->clocks_en_bits, 0); 262 zx_writel_mask(vou->vouctl + VOU_CLK_EN, inf->clocks_en_bits, 0);
158} 263}
159 264
265void zx_vou_config_dividers(struct drm_crtc *crtc,
266 struct vou_div_config *configs, int num)
267{
268 struct zx_crtc *zcrtc = to_zx_crtc(crtc);
269 struct zx_vou_hw *vou = zcrtc->vou;
270 const struct zx_crtc_bits *bits = zcrtc->bits;
271 int i;
272
273 /* Clear update flag bit */
274 zx_writel_mask(vou->vouctl + VOU_DIV_PARA, DIV_PARA_UPDATE, 0);
275
276 for (i = 0; i < num; i++) {
277 struct vou_div_config *cfg = configs + i;
278 u32 reg, shift;
279
280 switch (cfg->id) {
281 case VOU_DIV_VGA:
282 reg = VOU_CLK_SEL;
283 shift = bits->div_vga_shift;
284 break;
285 case VOU_DIV_PIC:
286 reg = VOU_CLK_SEL;
287 shift = bits->div_pic_shift;
288 break;
289 case VOU_DIV_TVENC:
290 reg = VOU_DIV_PARA;
291 shift = bits->div_tvenc_shift;
292 break;
293 case VOU_DIV_HDMI_PNX:
294 reg = VOU_DIV_PARA;
295 shift = bits->div_hdmi_pnx_shift;
296 break;
297 case VOU_DIV_HDMI:
298 reg = VOU_DIV_PARA;
299 shift = bits->div_hdmi_shift;
300 break;
301 case VOU_DIV_INF:
302 reg = VOU_DIV_PARA;
303 shift = bits->div_inf_shift;
304 break;
305 case VOU_DIV_LAYER:
306 reg = VOU_DIV_PARA;
307 shift = bits->div_layer_shift;
308 break;
309 default:
310 continue;
311 }
312
313 /* Each divider occupies 3 bits */
314 zx_writel_mask(vou->vouctl + reg, 0x7 << shift,
315 cfg->val << shift);
316 }
317
318 /* Set update flag bit to get dividers effected */
319 zx_writel_mask(vou->vouctl + VOU_DIV_PARA, DIV_PARA_UPDATE,
320 DIV_PARA_UPDATE);
321}
322
160static inline void vou_chn_set_update(struct zx_crtc *zcrtc) 323static inline void vou_chn_set_update(struct zx_crtc *zcrtc)
161{ 324{
162 zx_writel(zcrtc->chnreg + CHN_UPDATE, 1); 325 zx_writel(zcrtc->chnreg + CHN_UPDATE, 1);
@@ -165,11 +328,13 @@ static inline void vou_chn_set_update(struct zx_crtc *zcrtc)
165static void zx_crtc_enable(struct drm_crtc *crtc) 328static void zx_crtc_enable(struct drm_crtc *crtc)
166{ 329{
167 struct drm_display_mode *mode = &crtc->state->adjusted_mode; 330 struct drm_display_mode *mode = &crtc->state->adjusted_mode;
331 bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE;
168 struct zx_crtc *zcrtc = to_zx_crtc(crtc); 332 struct zx_crtc *zcrtc = to_zx_crtc(crtc);
169 struct zx_vou_hw *vou = zcrtc->vou; 333 struct zx_vou_hw *vou = zcrtc->vou;
170 const struct zx_crtc_regs *regs = zcrtc->regs; 334 const struct zx_crtc_regs *regs = zcrtc->regs;
171 const struct zx_crtc_bits *bits = zcrtc->bits; 335 const struct zx_crtc_bits *bits = zcrtc->bits;
172 struct videomode vm; 336 struct videomode vm;
337 u32 scan_mask;
173 u32 pol = 0; 338 u32 pol = 0;
174 u32 val; 339 u32 val;
175 int ret; 340 int ret;
@@ -177,7 +342,7 @@ static void zx_crtc_enable(struct drm_crtc *crtc)
177 drm_display_mode_to_videomode(mode, &vm); 342 drm_display_mode_to_videomode(mode, &vm);
178 343
179 /* Set up timing parameters */ 344 /* Set up timing parameters */
180 val = V_ACTIVE(vm.vactive - 1); 345 val = V_ACTIVE((interlaced ? vm.vactive / 2 : vm.vactive) - 1);
181 val |= H_ACTIVE(vm.hactive - 1); 346 val |= H_ACTIVE(vm.hactive - 1);
182 zx_writel(vou->timing + regs->fir_active, val); 347 zx_writel(vou->timing + regs->fir_active, val);
183 348
@@ -191,6 +356,25 @@ static void zx_crtc_enable(struct drm_crtc *crtc)
191 val |= FRONT_PORCH(vm.vfront_porch - 1); 356 val |= FRONT_PORCH(vm.vfront_porch - 1);
192 zx_writel(vou->timing + regs->fir_vtiming, val); 357 zx_writel(vou->timing + regs->fir_vtiming, val);
193 358
359 if (interlaced) {
360 u32 shift = bits->sec_vactive_shift;
361 u32 mask = bits->sec_vactive_mask;
362
363 val = zx_readl(vou->timing + SEC_V_ACTIVE);
364 val &= ~mask;
365 val |= ((vm.vactive / 2 - 1) << shift) & mask;
366 zx_writel(vou->timing + SEC_V_ACTIVE, val);
367
368 val = SYNC_WIDE(vm.vsync_len - 1);
369 /*
370 * The vback_porch for the second field needs to shift one on
371 * the value for the first field.
372 */
373 val |= BACK_PORCH(vm.vback_porch);
374 val |= FRONT_PORCH(vm.vfront_porch - 1);
375 zx_writel(vou->timing + regs->sec_vtiming, val);
376 }
377
194 /* Set up polarities */ 378 /* Set up polarities */
195 if (vm.flags & DISPLAY_FLAGS_VSYNC_LOW) 379 if (vm.flags & DISPLAY_FLAGS_VSYNC_LOW)
196 pol |= 1 << POL_VSYNC_SHIFT; 380 pol |= 1 << POL_VSYNC_SHIFT;
@@ -201,9 +385,17 @@ static void zx_crtc_enable(struct drm_crtc *crtc)
201 pol << bits->polarity_shift); 385 pol << bits->polarity_shift);
202 386
203 /* Setup SHIFT register by following what ZTE BSP does */ 387 /* Setup SHIFT register by following what ZTE BSP does */
204 zx_writel(vou->timing + regs->timing_shift, H_SHIFT_VAL); 388 val = H_SHIFT_VAL;
389 if (interlaced)
390 val |= V_SHIFT_VAL << 16;
391 zx_writel(vou->timing + regs->timing_shift, val);
205 zx_writel(vou->timing + regs->timing_pi_shift, H_PI_SHIFT_VAL); 392 zx_writel(vou->timing + regs->timing_pi_shift, H_PI_SHIFT_VAL);
206 393
394 /* Progressive or interlace scan select */
395 scan_mask = bits->interlace_select | bits->pi_enable;
396 zx_writel_mask(vou->timing + SCAN_CTRL, scan_mask,
397 interlaced ? scan_mask : 0);
398
207 /* Enable TIMING_CTRL */ 399 /* Enable TIMING_CTRL */
208 zx_writel_mask(vou->timing + TIMING_TC_ENABLE, bits->tc_enable, 400 zx_writel_mask(vou->timing + TIMING_TC_ENABLE, bits->tc_enable,
209 bits->tc_enable); 401 bits->tc_enable);
@@ -214,16 +406,16 @@ static void zx_crtc_enable(struct drm_crtc *crtc)
214 zx_writel_mask(zcrtc->chnreg + CHN_CTRL1, CHN_SCREEN_H_MASK, 406 zx_writel_mask(zcrtc->chnreg + CHN_CTRL1, CHN_SCREEN_H_MASK,
215 vm.vactive << CHN_SCREEN_H_SHIFT); 407 vm.vactive << CHN_SCREEN_H_SHIFT);
216 408
409 /* Configure channel interlace buffer control */
410 zx_writel_mask(zcrtc->chnreg + CHN_INTERLACE_BUF_CTRL, CHN_INTERLACE_EN,
411 interlaced ? CHN_INTERLACE_EN : 0);
412
217 /* Update channel */ 413 /* Update channel */
218 vou_chn_set_update(zcrtc); 414 vou_chn_set_update(zcrtc);
219 415
220 /* Enable channel */ 416 /* Enable channel */
221 zx_writel_mask(zcrtc->chnreg + CHN_CTRL0, CHN_ENABLE, CHN_ENABLE); 417 zx_writel_mask(zcrtc->chnreg + CHN_CTRL0, CHN_ENABLE, CHN_ENABLE);
222 418
223 /* Enable Graphic Layer */
224 zx_writel_mask(vou->osd + OSD_CTRL0, bits->gl_enable,
225 bits->gl_enable);
226
227 drm_crtc_vblank_on(crtc); 419 drm_crtc_vblank_on(crtc);
228 420
229 ret = clk_set_rate(zcrtc->pixclk, mode->clock * 1000); 421 ret = clk_set_rate(zcrtc->pixclk, mode->clock * 1000);
@@ -247,9 +439,6 @@ static void zx_crtc_disable(struct drm_crtc *crtc)
247 439
248 drm_crtc_vblank_off(crtc); 440 drm_crtc_vblank_off(crtc);
249 441
250 /* Disable Graphic Layer */
251 zx_writel_mask(vou->osd + OSD_CTRL0, bits->gl_enable, 0);
252
253 /* Disable channel */ 442 /* Disable channel */
254 zx_writel_mask(zcrtc->chnreg + CHN_CTRL0, CHN_ENABLE, 0); 443 zx_writel_mask(zcrtc->chnreg + CHN_CTRL0, CHN_ENABLE, 0);
255 444
@@ -294,7 +483,7 @@ static int zx_crtc_init(struct drm_device *drm, struct zx_vou_hw *vou,
294 enum vou_chn_type chn_type) 483 enum vou_chn_type chn_type)
295{ 484{
296 struct device *dev = vou->dev; 485 struct device *dev = vou->dev;
297 struct zx_layer_data data; 486 struct zx_plane *zplane;
298 struct zx_crtc *zcrtc; 487 struct zx_crtc *zcrtc;
299 int ret; 488 int ret;
300 489
@@ -305,19 +494,27 @@ static int zx_crtc_init(struct drm_device *drm, struct zx_vou_hw *vou,
305 zcrtc->vou = vou; 494 zcrtc->vou = vou;
306 zcrtc->chn_type = chn_type; 495 zcrtc->chn_type = chn_type;
307 496
497 zplane = devm_kzalloc(dev, sizeof(*zplane), GFP_KERNEL);
498 if (!zplane)
499 return -ENOMEM;
500
501 zplane->dev = dev;
502
308 if (chn_type == VOU_CHN_MAIN) { 503 if (chn_type == VOU_CHN_MAIN) {
309 data.layer = vou->osd + MAIN_GL_OFFSET; 504 zplane->layer = vou->osd + MAIN_GL_OFFSET;
310 data.csc = vou->osd + MAIN_CSC_OFFSET; 505 zplane->csc = vou->osd + MAIN_CSC_OFFSET;
311 data.hbsc = vou->osd + MAIN_HBSC_OFFSET; 506 zplane->hbsc = vou->osd + MAIN_HBSC_OFFSET;
312 data.rsz = vou->otfppu + MAIN_RSZ_OFFSET; 507 zplane->rsz = vou->otfppu + MAIN_RSZ_OFFSET;
508 zplane->bits = &zx_gl_bits[0];
313 zcrtc->chnreg = vou->osd + OSD_MAIN_CHN; 509 zcrtc->chnreg = vou->osd + OSD_MAIN_CHN;
314 zcrtc->regs = &main_crtc_regs; 510 zcrtc->regs = &main_crtc_regs;
315 zcrtc->bits = &main_crtc_bits; 511 zcrtc->bits = &main_crtc_bits;
316 } else { 512 } else {
317 data.layer = vou->osd + AUX_GL_OFFSET; 513 zplane->layer = vou->osd + AUX_GL_OFFSET;
318 data.csc = vou->osd + AUX_CSC_OFFSET; 514 zplane->csc = vou->osd + AUX_CSC_OFFSET;
319 data.hbsc = vou->osd + AUX_HBSC_OFFSET; 515 zplane->hbsc = vou->osd + AUX_HBSC_OFFSET;
320 data.rsz = vou->otfppu + AUX_RSZ_OFFSET; 516 zplane->rsz = vou->otfppu + AUX_RSZ_OFFSET;
517 zplane->bits = &zx_gl_bits[1];
321 zcrtc->chnreg = vou->osd + OSD_AUX_CHN; 518 zcrtc->chnreg = vou->osd + OSD_AUX_CHN;
322 zcrtc->regs = &aux_crtc_regs; 519 zcrtc->regs = &aux_crtc_regs;
323 zcrtc->bits = &aux_crtc_bits; 520 zcrtc->bits = &aux_crtc_bits;
@@ -331,13 +528,14 @@ static int zx_crtc_init(struct drm_device *drm, struct zx_vou_hw *vou,
331 return ret; 528 return ret;
332 } 529 }
333 530
334 zcrtc->primary = zx_plane_init(drm, dev, &data, DRM_PLANE_TYPE_PRIMARY); 531 ret = zx_plane_init(drm, zplane, DRM_PLANE_TYPE_PRIMARY);
335 if (IS_ERR(zcrtc->primary)) { 532 if (ret) {
336 ret = PTR_ERR(zcrtc->primary);
337 DRM_DEV_ERROR(dev, "failed to init primary plane: %d\n", ret); 533 DRM_DEV_ERROR(dev, "failed to init primary plane: %d\n", ret);
338 return ret; 534 return ret;
339 } 535 }
340 536
537 zcrtc->primary = &zplane->plane;
538
341 ret = drm_crtc_init_with_planes(drm, &zcrtc->crtc, zcrtc->primary, NULL, 539 ret = drm_crtc_init_with_planes(drm, &zcrtc->crtc, zcrtc->primary, NULL,
342 &zx_crtc_funcs, NULL); 540 &zx_crtc_funcs, NULL);
343 if (ret) { 541 if (ret) {
@@ -393,6 +591,78 @@ void zx_vou_disable_vblank(struct drm_device *drm, unsigned int pipe)
393 zcrtc->bits->int_frame_mask, 0); 591 zcrtc->bits->int_frame_mask, 0);
394} 592}
395 593
594void zx_vou_layer_enable(struct drm_plane *plane)
595{
596 struct zx_crtc *zcrtc = to_zx_crtc(plane->state->crtc);
597 struct zx_vou_hw *vou = zcrtc->vou;
598 struct zx_plane *zplane = to_zx_plane(plane);
599 const struct vou_layer_bits *bits = zplane->bits;
600
601 if (zcrtc->chn_type == VOU_CHN_MAIN) {
602 zx_writel_mask(vou->osd + OSD_CTRL0, bits->chnsel, 0);
603 zx_writel_mask(vou->vouctl + VOU_CLK_SEL, bits->clksel, 0);
604 } else {
605 zx_writel_mask(vou->osd + OSD_CTRL0, bits->chnsel,
606 bits->chnsel);
607 zx_writel_mask(vou->vouctl + VOU_CLK_SEL, bits->clksel,
608 bits->clksel);
609 }
610
611 zx_writel_mask(vou->osd + OSD_CTRL0, bits->enable, bits->enable);
612}
613
614void zx_vou_layer_disable(struct drm_plane *plane)
615{
616 struct zx_crtc *zcrtc = to_zx_crtc(plane->crtc);
617 struct zx_vou_hw *vou = zcrtc->vou;
618 struct zx_plane *zplane = to_zx_plane(plane);
619 const struct vou_layer_bits *bits = zplane->bits;
620
621 zx_writel_mask(vou->osd + OSD_CTRL0, bits->enable, 0);
622}
623
624static void zx_overlay_init(struct drm_device *drm, struct zx_vou_hw *vou)
625{
626 struct device *dev = vou->dev;
627 struct zx_plane *zplane;
628 int i;
629 int ret;
630
631 /*
632 * VL0 has some quirks on scaling support which need special handling.
633 * Let's leave it out for now.
634 */
635 for (i = 1; i < VL_NUM; i++) {
636 zplane = devm_kzalloc(dev, sizeof(*zplane), GFP_KERNEL);
637 if (!zplane) {
638 DRM_DEV_ERROR(dev, "failed to allocate zplane %d\n", i);
639 return;
640 }
641
642 zplane->layer = vou->osd + OSD_VL_OFFSET(i);
643 zplane->hbsc = vou->osd + HBSC_VL_OFFSET(i);
644 zplane->rsz = vou->otfppu + RSZ_VL_OFFSET(i);
645 zplane->bits = &zx_vl_bits[i];
646
647 ret = zx_plane_init(drm, zplane, DRM_PLANE_TYPE_OVERLAY);
648 if (ret) {
649 DRM_DEV_ERROR(dev, "failed to init overlay %d\n", i);
650 continue;
651 }
652 }
653}
654
655static inline void zx_osd_int_update(struct zx_crtc *zcrtc)
656{
657 struct drm_crtc *crtc = &zcrtc->crtc;
658 struct drm_plane *plane;
659
660 vou_chn_set_update(zcrtc);
661
662 drm_for_each_plane_mask(plane, crtc->dev, crtc->state->plane_mask)
663 zx_plane_set_update(plane);
664}
665
396static irqreturn_t vou_irq_handler(int irq, void *dev_id) 666static irqreturn_t vou_irq_handler(int irq, void *dev_id)
397{ 667{
398 struct zx_vou_hw *vou = dev_id; 668 struct zx_vou_hw *vou = dev_id;
@@ -412,15 +682,11 @@ static irqreturn_t vou_irq_handler(int irq, void *dev_id)
412 state = zx_readl(vou->osd + OSD_INT_STA); 682 state = zx_readl(vou->osd + OSD_INT_STA);
413 zx_writel(vou->osd + OSD_INT_CLRSTA, state); 683 zx_writel(vou->osd + OSD_INT_CLRSTA, state);
414 684
415 if (state & OSD_INT_MAIN_UPT) { 685 if (state & OSD_INT_MAIN_UPT)
416 vou_chn_set_update(vou->main_crtc); 686 zx_osd_int_update(vou->main_crtc);
417 zx_plane_set_update(vou->main_crtc->primary);
418 }
419 687
420 if (state & OSD_INT_AUX_UPT) { 688 if (state & OSD_INT_AUX_UPT)
421 vou_chn_set_update(vou->aux_crtc); 689 zx_osd_int_update(vou->aux_crtc);
422 zx_plane_set_update(vou->aux_crtc->primary);
423 }
424 690
425 if (state & OSD_INT_ERROR) 691 if (state & OSD_INT_ERROR)
426 DRM_DEV_ERROR(vou->dev, "OSD ERROR: 0x%08x!\n", state); 692 DRM_DEV_ERROR(vou->dev, "OSD ERROR: 0x%08x!\n", state);
@@ -451,19 +717,9 @@ static void vou_dtrc_init(struct zx_vou_hw *vou)
451 717
452static void vou_hw_init(struct zx_vou_hw *vou) 718static void vou_hw_init(struct zx_vou_hw *vou)
453{ 719{
454 /* Set GL0 to main channel and GL1 to aux channel */
455 zx_writel_mask(vou->osd + OSD_CTRL0, OSD_CTRL0_GL0_SEL, 0);
456 zx_writel_mask(vou->osd + OSD_CTRL0, OSD_CTRL0_GL1_SEL,
457 OSD_CTRL0_GL1_SEL);
458
459 /* Release reset for all VOU modules */ 720 /* Release reset for all VOU modules */
460 zx_writel(vou->vouctl + VOU_SOFT_RST, ~0); 721 zx_writel(vou->vouctl + VOU_SOFT_RST, ~0);
461 722
462 /* Select main clock for GL0 and aux clock for GL1 module */
463 zx_writel_mask(vou->vouctl + VOU_CLK_SEL, VOU_CLK_GL0_SEL, 0);
464 zx_writel_mask(vou->vouctl + VOU_CLK_SEL, VOU_CLK_GL1_SEL,
465 VOU_CLK_GL1_SEL);
466
467 /* Enable clock auto-gating for all VOU modules */ 723 /* Enable clock auto-gating for all VOU modules */
468 zx_writel(vou->vouctl + VOU_CLK_REQEN, ~0); 724 zx_writel(vou->vouctl + VOU_CLK_REQEN, ~0);
469 725
@@ -600,6 +856,8 @@ static int zx_crtc_bind(struct device *dev, struct device *master, void *data)
600 goto disable_ppu_clk; 856 goto disable_ppu_clk;
601 } 857 }
602 858
859 zx_overlay_init(drm, vou);
860
603 return 0; 861 return 0;
604 862
605disable_ppu_clk: 863disable_ppu_clk:
diff --git a/drivers/gpu/drm/zte/zx_vou.h b/drivers/gpu/drm/zte/zx_vou.h
index 349e06cd86f4..57e3c31ee6a5 100644
--- a/drivers/gpu/drm/zte/zx_vou.h
+++ b/drivers/gpu/drm/zte/zx_vou.h
@@ -23,24 +23,48 @@ enum vou_inf_id {
23 VOU_VGA = 5, 23 VOU_VGA = 5,
24}; 24};
25 25
26enum vou_inf_data_sel { 26enum vou_inf_hdmi_audio {
27 VOU_YUV444 = 0, 27 VOU_HDMI_AUD_SPDIF = BIT(0),
28 VOU_RGB_101010 = 1, 28 VOU_HDMI_AUD_I2S = BIT(1),
29 VOU_RGB_888 = 2, 29 VOU_HDMI_AUD_DSD = BIT(2),
30 VOU_RGB_666 = 3, 30 VOU_HDMI_AUD_HBR = BIT(3),
31 VOU_HDMI_AUD_PARALLEL = BIT(4),
31}; 32};
32 33
33struct vou_inf { 34void vou_inf_hdmi_audio_sel(struct drm_crtc *crtc,
34 enum vou_inf_id id; 35 enum vou_inf_hdmi_audio aud);
35 enum vou_inf_data_sel data_sel; 36void vou_inf_enable(enum vou_inf_id id, struct drm_crtc *crtc);
36 u32 clocks_en_bits; 37void vou_inf_disable(enum vou_inf_id id, struct drm_crtc *crtc);
37 u32 clocks_sel_bits; 38
39enum vou_div_id {
40 VOU_DIV_VGA,
41 VOU_DIV_PIC,
42 VOU_DIV_TVENC,
43 VOU_DIV_HDMI_PNX,
44 VOU_DIV_HDMI,
45 VOU_DIV_INF,
46 VOU_DIV_LAYER,
47};
48
49enum vou_div_val {
50 VOU_DIV_1 = 0,
51 VOU_DIV_2 = 1,
52 VOU_DIV_4 = 3,
53 VOU_DIV_8 = 7,
38}; 54};
39 55
40void vou_inf_enable(const struct vou_inf *inf, struct drm_crtc *crtc); 56struct vou_div_config {
41void vou_inf_disable(const struct vou_inf *inf, struct drm_crtc *crtc); 57 enum vou_div_id id;
58 enum vou_div_val val;
59};
60
61void zx_vou_config_dividers(struct drm_crtc *crtc,
62 struct vou_div_config *configs, int num);
42 63
43int zx_vou_enable_vblank(struct drm_device *drm, unsigned int pipe); 64int zx_vou_enable_vblank(struct drm_device *drm, unsigned int pipe);
44void zx_vou_disable_vblank(struct drm_device *drm, unsigned int pipe); 65void zx_vou_disable_vblank(struct drm_device *drm, unsigned int pipe);
45 66
67void zx_vou_layer_enable(struct drm_plane *plane);
68void zx_vou_layer_disable(struct drm_plane *plane);
69
46#endif /* __ZX_VOU_H__ */ 70#endif /* __ZX_VOU_H__ */
diff --git a/drivers/gpu/drm/zte/zx_vou_regs.h b/drivers/gpu/drm/zte/zx_vou_regs.h
index f44e7a4ae441..c066ef123434 100644
--- a/drivers/gpu/drm/zte/zx_vou_regs.h
+++ b/drivers/gpu/drm/zte/zx_vou_regs.h
@@ -22,6 +22,15 @@
22#define AUX_HBSC_OFFSET 0x860 22#define AUX_HBSC_OFFSET 0x860
23#define AUX_RSZ_OFFSET 0x800 23#define AUX_RSZ_OFFSET 0x800
24 24
25#define OSD_VL0_OFFSET 0x040
26#define OSD_VL_OFFSET(i) (OSD_VL0_OFFSET + 0x050 * (i))
27
28#define HBSC_VL0_OFFSET 0x760
29#define HBSC_VL_OFFSET(i) (HBSC_VL0_OFFSET + 0x040 * (i))
30
31#define RSZ_VL1_U0 0xa00
32#define RSZ_VL_OFFSET(i) (RSZ_VL1_U0 + 0x200 * (i))
33
25/* OSD (GPC_GLOBAL) registers */ 34/* OSD (GPC_GLOBAL) registers */
26#define OSD_INT_STA 0x04 35#define OSD_INT_STA 0x04
27#define OSD_INT_CLRSTA 0x08 36#define OSD_INT_CLRSTA 0x08
@@ -42,6 +51,12 @@
42) 51)
43#define OSD_INT_ENABLE (OSD_INT_ERROR | OSD_INT_AUX_UPT | OSD_INT_MAIN_UPT) 52#define OSD_INT_ENABLE (OSD_INT_ERROR | OSD_INT_AUX_UPT | OSD_INT_MAIN_UPT)
44#define OSD_CTRL0 0x10 53#define OSD_CTRL0 0x10
54#define OSD_CTRL0_VL0_EN BIT(13)
55#define OSD_CTRL0_VL0_SEL BIT(12)
56#define OSD_CTRL0_VL1_EN BIT(11)
57#define OSD_CTRL0_VL1_SEL BIT(10)
58#define OSD_CTRL0_VL2_EN BIT(9)
59#define OSD_CTRL0_VL2_SEL BIT(8)
45#define OSD_CTRL0_GL0_EN BIT(7) 60#define OSD_CTRL0_GL0_EN BIT(7)
46#define OSD_CTRL0_GL0_SEL BIT(6) 61#define OSD_CTRL0_GL0_SEL BIT(6)
47#define OSD_CTRL0_GL1_EN BIT(5) 62#define OSD_CTRL0_GL1_EN BIT(5)
@@ -60,6 +75,8 @@
60#define CHN_SCREEN_H_SHIFT 5 75#define CHN_SCREEN_H_SHIFT 5
61#define CHN_SCREEN_H_MASK (0x1fff << CHN_SCREEN_H_SHIFT) 76#define CHN_SCREEN_H_MASK (0x1fff << CHN_SCREEN_H_SHIFT)
62#define CHN_UPDATE 0x08 77#define CHN_UPDATE 0x08
78#define CHN_INTERLACE_BUF_CTRL 0x24
79#define CHN_INTERLACE_EN BIT(2)
63 80
64/* TIMING_CTRL registers */ 81/* TIMING_CTRL registers */
65#define TIMING_TC_ENABLE 0x04 82#define TIMING_TC_ENABLE 0x04
@@ -102,6 +119,19 @@
102#define TIMING_MAIN_SHIFT 0x2c 119#define TIMING_MAIN_SHIFT 0x2c
103#define TIMING_AUX_SHIFT 0x30 120#define TIMING_AUX_SHIFT 0x30
104#define H_SHIFT_VAL 0x0048 121#define H_SHIFT_VAL 0x0048
122#define V_SHIFT_VAL 0x0001
123#define SCAN_CTRL 0x34
124#define AUX_PI_EN BIT(19)
125#define MAIN_PI_EN BIT(18)
126#define AUX_INTERLACE_SEL BIT(1)
127#define MAIN_INTERLACE_SEL BIT(0)
128#define SEC_V_ACTIVE 0x38
129#define SEC_VACT_MAIN_SHIFT 0
130#define SEC_VACT_MAIN_MASK (0xffff << SEC_VACT_MAIN_SHIFT)
131#define SEC_VACT_AUX_SHIFT 16
132#define SEC_VACT_AUX_MASK (0xffff << SEC_VACT_AUX_SHIFT)
133#define SEC_MAIN_V_TIMING 0x3c
134#define SEC_AUX_V_TIMING 0x40
105#define TIMING_MAIN_PI_SHIFT 0x68 135#define TIMING_MAIN_PI_SHIFT 0x68
106#define TIMING_AUX_PI_SHIFT 0x6c 136#define TIMING_AUX_PI_SHIFT 0x6c
107#define H_PI_SHIFT_VAL 0x000f 137#define H_PI_SHIFT_VAL 0x000f
@@ -146,10 +176,31 @@
146#define VOU_INF_DATA_SEL 0x08 176#define VOU_INF_DATA_SEL 0x08
147#define VOU_SOFT_RST 0x14 177#define VOU_SOFT_RST 0x14
148#define VOU_CLK_SEL 0x18 178#define VOU_CLK_SEL 0x18
179#define VGA_AUX_DIV_SHIFT 29
180#define VGA_MAIN_DIV_SHIFT 26
181#define PIC_MAIN_DIV_SHIFT 23
182#define PIC_AUX_DIV_SHIFT 20
183#define VOU_CLK_VL2_SEL BIT(8)
184#define VOU_CLK_VL1_SEL BIT(7)
185#define VOU_CLK_VL0_SEL BIT(6)
149#define VOU_CLK_GL1_SEL BIT(5) 186#define VOU_CLK_GL1_SEL BIT(5)
150#define VOU_CLK_GL0_SEL BIT(4) 187#define VOU_CLK_GL0_SEL BIT(4)
188#define VOU_DIV_PARA 0x1c
189#define DIV_PARA_UPDATE BIT(31)
190#define TVENC_AUX_DIV_SHIFT 28
191#define HDMI_AUX_PNX_DIV_SHIFT 25
192#define HDMI_MAIN_PNX_DIV_SHIFT 22
193#define HDMI_AUX_DIV_SHIFT 19
194#define HDMI_MAIN_DIV_SHIFT 16
195#define TVENC_MAIN_DIV_SHIFT 13
196#define INF_AUX_DIV_SHIFT 9
197#define INF_MAIN_DIV_SHIFT 6
198#define LAYER_AUX_DIV_SHIFT 3
199#define LAYER_MAIN_DIV_SHIFT 0
151#define VOU_CLK_REQEN 0x20 200#define VOU_CLK_REQEN 0x20
152#define VOU_CLK_EN 0x24 201#define VOU_CLK_EN 0x24
202#define VOU_INF_HDMI_CTRL 0x30
203#define VOU_HDMI_AUD_MASK 0x1f
153 204
154/* OTFPPU_CTRL registers */ 205/* OTFPPU_CTRL registers */
155#define OTFPPU_RSZ_DATA_SOURCE 0x04 206#define OTFPPU_RSZ_DATA_SOURCE 0x04