diff options
author | Dave Airlie <airlied@redhat.com> | 2017-01-31 17:26:33 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2017-01-31 17:29:04 -0500 |
commit | 3a5e6bb9c660173cf6a1a3f29b0501553cd4db2f (patch) | |
tree | a9b28f2391cc11fb4a3f50e261b870f50c53a6f8 | |
parent | 2643105558099a4703f8209f2cad768673aff12d (diff) | |
parent | 098988cbe5849e3e125b0bc02a6545a1dc414ab1 (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.txt | 15 | ||||
-rw-r--r-- | drivers/gpu/drm/zte/Kconfig | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/zte/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/zte/zx_drm_drv.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/zte/zx_drm_drv.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/zte/zx_hdmi.c | 160 | ||||
-rw-r--r-- | drivers/gpu/drm/zte/zx_hdmi_regs.h | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/zte/zx_plane.c | 328 | ||||
-rw-r--r-- | drivers/gpu/drm/zte/zx_plane.h | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/zte/zx_plane_regs.h | 51 | ||||
-rw-r--r-- | drivers/gpu/drm/zte/zx_tvenc.c | 407 | ||||
-rw-r--r-- | drivers/gpu/drm/zte/zx_tvenc_regs.h | 31 | ||||
-rw-r--r-- | drivers/gpu/drm/zte/zx_vou.c | 356 | ||||
-rw-r--r-- | drivers/gpu/drm/zte/zx_vou.h | 48 | ||||
-rw-r--r-- | drivers/gpu/drm/zte/zx_vou_regs.h | 51 |
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 | |||
54 | Required 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 | |||
52 | Example: | 61 | Example: |
53 | 62 | ||
54 | vou: vou@1440000 { | 63 | vou: 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 | ||
7 | obj-$(CONFIG_DRM_ZTE) += zxdrm.o | 8 | obj-$(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 = { | |||
247 | static struct platform_driver *drivers[] = { | 247 | static 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 | ||
14 | extern struct platform_driver zx_crtc_driver; | 14 | extern struct platform_driver zx_crtc_driver; |
15 | extern struct platform_driver zx_hdmi_driver; | 15 | extern struct platform_driver zx_hdmi_driver; |
16 | extern struct platform_driver zx_tvenc_driver; | ||
16 | 17 | ||
17 | static inline u32 zx_readl(void __iomem *reg) | 18 | static 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 | ||
56 | static 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 | |||
63 | static inline u8 hdmi_readb(struct zx_hdmi *hdmi, u16 offset) | 59 | static 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 | ||
244 | static void zx_hdmi_encoder_disable(struct drm_encoder *encoder) | 240 | static 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 | ||
365 | static 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 | |||
375 | static 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 | |||
383 | static 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 | |||
395 | static 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 = ¶ms->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 | |||
447 | static 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 | |||
461 | static 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 | |||
472 | static 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 | |||
480 | static struct hdmi_codec_pdata zx_hdmi_codec_pdata = { | ||
481 | .ops = &zx_hdmi_codec_ops, | ||
482 | .spdif = 1, | ||
483 | }; | ||
484 | |||
485 | static 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 | |||
369 | static int zx_hdmi_i2c_read(struct zx_hdmi *hdmi, struct i2c_msg *msg) | 501 | static 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 | ||
595 | static const struct component_ops zx_hdmi_component_ops = { | 735 | static 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 | ||
24 | struct 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 | |||
34 | static const uint32_t gl_formats[] = { | 24 | static 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 | ||
33 | static 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 | |||
51 | static 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 | |||
87 | static 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 | |||
110 | static 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 | |||
117 | static inline void zx_vl_rsz_set_update(struct zx_plane *zplane) | ||
118 | { | ||
119 | zx_writel(zplane->rsz + RSZ_VL_ENABLE_CFG, 1); | ||
120 | } | ||
121 | |||
122 | static 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 | |||
141 | static 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 | |||
156 | static 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 | |||
190 | static 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 | |||
270 | static 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 | |||
282 | static 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 | |||
43 | static int zx_gl_plane_atomic_check(struct drm_plane *plane, | 288 | static 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 | ||
110 | void 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 | |||
118 | static void zx_gl_rsz_setup(struct zx_plane *zplane, u32 src_w, u32 src_h, | 355 | static 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 | ||
213 | static const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs = { | 452 | static 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 | ||
218 | static void zx_plane_destroy(struct drm_plane *plane) | 458 | static 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 | ||
473 | void 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 | |||
233 | static void zx_plane_hbsc_init(struct zx_plane *zplane) | 495 | static 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 | ||
251 | struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev, | 513 | int 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 | ||
14 | struct zx_layer_data { | 14 | struct 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 | ||
21 | struct 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); | 26 | int zx_plane_init(struct drm_device *drm, struct zx_plane *zplane, |
27 | enum drm_plane_type type); | ||
24 | void zx_plane_set_update(struct drm_plane *plane); | 28 | void 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 | |||
24 | struct zx_tvenc_pwrctrl { | ||
25 | struct regmap *regmap; | ||
26 | u32 reg; | ||
27 | u32 mask; | ||
28 | }; | ||
29 | |||
30 | struct 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 | |||
41 | struct 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 | |||
67 | static 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 | |||
98 | static 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 | |||
129 | static const struct zx_tvenc_mode *tvenc_modes[] = { | ||
130 | &tvenc_mode_pal, | ||
131 | &tvenc_mode_ntsc, | ||
132 | }; | ||
133 | |||
134 | static const struct zx_tvenc_mode * | ||
135 | zx_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 | |||
149 | static 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 | |||
190 | static 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 | |||
204 | static 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 | |||
217 | static 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 | |||
223 | static const struct drm_encoder_funcs zx_tvenc_encoder_funcs = { | ||
224 | .destroy = drm_encoder_cleanup, | ||
225 | }; | ||
226 | |||
227 | static 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 | |||
250 | static enum drm_mode_status | ||
251 | zx_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 | |||
266 | static 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 | |||
271 | static 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 | |||
280 | static 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 | |||
306 | static 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 | |||
329 | out: | ||
330 | of_node_put(out_args.np); | ||
331 | return ret; | ||
332 | } | ||
333 | |||
334 | static 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 | |||
372 | static void zx_tvenc_unbind(struct device *dev, struct device *master, | ||
373 | void *data) | ||
374 | { | ||
375 | /* Nothing to do */ | ||
376 | } | ||
377 | |||
378 | static const struct component_ops zx_tvenc_component_ops = { | ||
379 | .bind = zx_tvenc_bind, | ||
380 | .unbind = zx_tvenc_unbind, | ||
381 | }; | ||
382 | |||
383 | static int zx_tvenc_probe(struct platform_device *pdev) | ||
384 | { | ||
385 | return component_add(&pdev->dev, &zx_tvenc_component_ops); | ||
386 | } | ||
387 | |||
388 | static int zx_tvenc_remove(struct platform_device *pdev) | ||
389 | { | ||
390 | component_del(&pdev->dev, &zx_tvenc_component_ops); | ||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static const struct of_device_id zx_tvenc_of_match[] = { | ||
395 | { .compatible = "zte,zx296718-tvenc", }, | ||
396 | { /* end */ }, | ||
397 | }; | ||
398 | MODULE_DEVICE_TABLE(of, zx_tvenc_of_match); | ||
399 | |||
400 | struct 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 | ||
71 | static const struct zx_crtc_bits main_crtc_bits = { | 84 | static 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 | ||
79 | static const struct zx_crtc_bits aux_crtc_bits = { | 102 | static 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 | ||
87 | struct zx_crtc { | 120 | struct 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 | ||
133 | struct vou_layer_bits { | ||
134 | u32 enable; | ||
135 | u32 chnsel; | ||
136 | u32 clksel; | ||
137 | }; | ||
138 | |||
139 | static 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 | |||
151 | static 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 | |||
100 | struct zx_vou_hw { | 167 | struct 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 | ||
182 | enum 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 | |||
189 | struct 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 | |||
196 | static 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 | |||
115 | static inline struct zx_vou_hw *crtc_to_vou(struct drm_crtc *crtc) | 209 | static 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 | ||
122 | void vou_inf_enable(const struct vou_inf *inf, struct drm_crtc *crtc) | 216 | void 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 | |||
225 | void 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 | ||
149 | void vou_inf_disable(const struct vou_inf *inf, struct drm_crtc *crtc) | 253 | void 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 | ||
265 | void 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 | |||
160 | static inline void vou_chn_set_update(struct zx_crtc *zcrtc) | 323 | static 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) | |||
165 | static void zx_crtc_enable(struct drm_crtc *crtc) | 328 | static 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 | ||
594 | void 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 | |||
614 | void 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 | |||
624 | static 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 | |||
655 | static 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 | |||
396 | static irqreturn_t vou_irq_handler(int irq, void *dev_id) | 666 | static 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 | ||
452 | static void vou_hw_init(struct zx_vou_hw *vou) | 718 | static 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 | ||
605 | disable_ppu_clk: | 863 | disable_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 | ||
26 | enum vou_inf_data_sel { | 26 | enum 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 | ||
33 | struct vou_inf { | 34 | void 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; | 36 | void vou_inf_enable(enum vou_inf_id id, struct drm_crtc *crtc); |
36 | u32 clocks_en_bits; | 37 | void vou_inf_disable(enum vou_inf_id id, struct drm_crtc *crtc); |
37 | u32 clocks_sel_bits; | 38 | |
39 | enum 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 | |||
49 | enum 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 | ||
40 | void vou_inf_enable(const struct vou_inf *inf, struct drm_crtc *crtc); | 56 | struct vou_div_config { |
41 | void 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 | |||
61 | void zx_vou_config_dividers(struct drm_crtc *crtc, | ||
62 | struct vou_div_config *configs, int num); | ||
42 | 63 | ||
43 | int zx_vou_enable_vblank(struct drm_device *drm, unsigned int pipe); | 64 | int zx_vou_enable_vblank(struct drm_device *drm, unsigned int pipe); |
44 | void zx_vou_disable_vblank(struct drm_device *drm, unsigned int pipe); | 65 | void zx_vou_disable_vblank(struct drm_device *drm, unsigned int pipe); |
45 | 66 | ||
67 | void zx_vou_layer_enable(struct drm_plane *plane); | ||
68 | void 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 |