diff options
author | Dave Airlie <airlied@redhat.com> | 2016-07-02 01:51:46 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2016-07-02 01:51:46 -0400 |
commit | 583fa4e02775b26d76771d4e1ddc6f10ba005ef2 (patch) | |
tree | 06b297de8e9049d4e4c4e2025608143c8d7b71de | |
parent | 2a3467063ae3b17264578626dec2377dd48cd1c3 (diff) | |
parent | 2c348e5053281555604233a66a633f7165665156 (diff) |
Merge branch 'sti-drm-next-2016-06-30' of http://git.linaro.org/people/benjamin.gaignard/kernel into drm-next
This pull request include 3 minors fix and one feature evolution
around ASoC hdmi codec support.
* 'sti-drm-next-2016-06-30' of http://git.linaro.org/people/benjamin.gaignard/kernel:
drm: sti: Add ASoC generic hdmi codec support.
drm/sti: adjust delay for AWG
drm: sti: fix clocking issues in crtc
drm/sti: Use 64-bit timestamps
-rw-r--r-- | drivers/gpu/drm/sti/Kconfig | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_awg_utils.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_crtc.c | 59 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_hdmi.c | 294 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_hdmi.h | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_plane.c | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_plane.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_vtg.c | 2 |
8 files changed, 328 insertions, 63 deletions
diff --git a/drivers/gpu/drm/sti/Kconfig b/drivers/gpu/drm/sti/Kconfig index 5ad43a1bb260..494ab257f77c 100644 --- a/drivers/gpu/drm/sti/Kconfig +++ b/drivers/gpu/drm/sti/Kconfig | |||
@@ -7,5 +7,6 @@ config DRM_STI | |||
7 | select DRM_KMS_CMA_HELPER | 7 | select DRM_KMS_CMA_HELPER |
8 | select DRM_PANEL | 8 | select DRM_PANEL |
9 | select FW_LOADER | 9 | select FW_LOADER |
10 | select SND_SOC_HDMI_CODEC if SND_SOC | ||
10 | help | 11 | help |
11 | Choose this option to enable DRM on STM stiH41x chipset | 12 | Choose this option to enable DRM on STM stiH41x chipset |
diff --git a/drivers/gpu/drm/sti/sti_awg_utils.c b/drivers/gpu/drm/sti/sti_awg_utils.c index a516eb869f6f..2da7d6866d5d 100644 --- a/drivers/gpu/drm/sti/sti_awg_utils.c +++ b/drivers/gpu/drm/sti/sti_awg_utils.c | |||
@@ -6,6 +6,8 @@ | |||
6 | 6 | ||
7 | #include "sti_awg_utils.h" | 7 | #include "sti_awg_utils.h" |
8 | 8 | ||
9 | #define AWG_DELAY (-5) | ||
10 | |||
9 | #define AWG_OPCODE_OFFSET 10 | 11 | #define AWG_OPCODE_OFFSET 10 |
10 | #define AWG_MAX_ARG 0x3ff | 12 | #define AWG_MAX_ARG 0x3ff |
11 | 13 | ||
@@ -125,7 +127,7 @@ static int awg_generate_line_signal( | |||
125 | val = timing->blanking_level; | 127 | val = timing->blanking_level; |
126 | ret |= awg_generate_instr(RPLSET, val, 0, 0, fwparams); | 128 | ret |= awg_generate_instr(RPLSET, val, 0, 0, fwparams); |
127 | 129 | ||
128 | val = timing->trailing_pixels - 1; | 130 | val = timing->trailing_pixels - 1 + AWG_DELAY; |
129 | ret |= awg_generate_instr(SKIP, val, 0, 0, fwparams); | 131 | ret |= awg_generate_instr(SKIP, val, 0, 0, fwparams); |
130 | } | 132 | } |
131 | 133 | ||
diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c index 7fab3af7473b..c7d734dc3cf4 100644 --- a/drivers/gpu/drm/sti/sti_crtc.c +++ b/drivers/gpu/drm/sti/sti_crtc.c | |||
@@ -23,22 +23,11 @@ | |||
23 | static void sti_crtc_enable(struct drm_crtc *crtc) | 23 | static void sti_crtc_enable(struct drm_crtc *crtc) |
24 | { | 24 | { |
25 | struct sti_mixer *mixer = to_sti_mixer(crtc); | 25 | struct sti_mixer *mixer = to_sti_mixer(crtc); |
26 | struct device *dev = mixer->dev; | ||
27 | struct sti_compositor *compo = dev_get_drvdata(dev); | ||
28 | 26 | ||
29 | DRM_DEBUG_DRIVER("\n"); | 27 | DRM_DEBUG_DRIVER("\n"); |
30 | 28 | ||
31 | mixer->status = STI_MIXER_READY; | 29 | mixer->status = STI_MIXER_READY; |
32 | 30 | ||
33 | /* Prepare and enable the compo IP clock */ | ||
34 | if (mixer->id == STI_MIXER_MAIN) { | ||
35 | if (clk_prepare_enable(compo->clk_compo_main)) | ||
36 | DRM_INFO("Failed to prepare/enable compo_main clk\n"); | ||
37 | } else { | ||
38 | if (clk_prepare_enable(compo->clk_compo_aux)) | ||
39 | DRM_INFO("Failed to prepare/enable compo_aux clk\n"); | ||
40 | } | ||
41 | |||
42 | drm_crtc_vblank_on(crtc); | 31 | drm_crtc_vblank_on(crtc); |
43 | } | 32 | } |
44 | 33 | ||
@@ -57,9 +46,8 @@ sti_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode) | |||
57 | struct sti_mixer *mixer = to_sti_mixer(crtc); | 46 | struct sti_mixer *mixer = to_sti_mixer(crtc); |
58 | struct device *dev = mixer->dev; | 47 | struct device *dev = mixer->dev; |
59 | struct sti_compositor *compo = dev_get_drvdata(dev); | 48 | struct sti_compositor *compo = dev_get_drvdata(dev); |
60 | struct clk *clk; | 49 | struct clk *compo_clk, *pix_clk; |
61 | int rate = mode->clock * 1000; | 50 | int rate = mode->clock * 1000; |
62 | int res; | ||
63 | 51 | ||
64 | DRM_DEBUG_KMS("CRTC:%d (%s) mode:%d (%s)\n", | 52 | DRM_DEBUG_KMS("CRTC:%d (%s) mode:%d (%s)\n", |
65 | crtc->base.id, sti_mixer_to_str(mixer), | 53 | crtc->base.id, sti_mixer_to_str(mixer), |
@@ -74,32 +62,46 @@ sti_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode) | |||
74 | mode->vsync_start, mode->vsync_end, | 62 | mode->vsync_start, mode->vsync_end, |
75 | mode->vtotal, mode->type, mode->flags); | 63 | mode->vtotal, mode->type, mode->flags); |
76 | 64 | ||
77 | /* Set rate and prepare/enable pixel clock */ | 65 | if (mixer->id == STI_MIXER_MAIN) { |
78 | if (mixer->id == STI_MIXER_MAIN) | 66 | compo_clk = compo->clk_compo_main; |
79 | clk = compo->clk_pix_main; | 67 | pix_clk = compo->clk_pix_main; |
80 | else | 68 | } else { |
81 | clk = compo->clk_pix_aux; | 69 | compo_clk = compo->clk_compo_aux; |
70 | pix_clk = compo->clk_pix_aux; | ||
71 | } | ||
72 | |||
73 | /* Prepare and enable the compo IP clock */ | ||
74 | if (clk_prepare_enable(compo_clk)) { | ||
75 | DRM_INFO("Failed to prepare/enable compositor clk\n"); | ||
76 | goto compo_error; | ||
77 | } | ||
82 | 78 | ||
83 | res = clk_set_rate(clk, rate); | 79 | /* Set rate and prepare/enable pixel clock */ |
84 | if (res < 0) { | 80 | if (clk_set_rate(pix_clk, rate) < 0) { |
85 | DRM_ERROR("Cannot set rate (%dHz) for pix clk\n", rate); | 81 | DRM_ERROR("Cannot set rate (%dHz) for pix clk\n", rate); |
86 | return -EINVAL; | 82 | goto pix_error; |
87 | } | 83 | } |
88 | if (clk_prepare_enable(clk)) { | 84 | if (clk_prepare_enable(pix_clk)) { |
89 | DRM_ERROR("Failed to prepare/enable pix clk\n"); | 85 | DRM_ERROR("Failed to prepare/enable pix clk\n"); |
90 | return -EINVAL; | 86 | goto pix_error; |
91 | } | 87 | } |
92 | 88 | ||
93 | sti_vtg_set_config(mixer->id == STI_MIXER_MAIN ? | 89 | sti_vtg_set_config(mixer->id == STI_MIXER_MAIN ? |
94 | compo->vtg_main : compo->vtg_aux, &crtc->mode); | 90 | compo->vtg_main : compo->vtg_aux, &crtc->mode); |
95 | 91 | ||
96 | res = sti_mixer_active_video_area(mixer, &crtc->mode); | 92 | if (sti_mixer_active_video_area(mixer, &crtc->mode)) { |
97 | if (res) { | ||
98 | DRM_ERROR("Can't set active video area\n"); | 93 | DRM_ERROR("Can't set active video area\n"); |
99 | return -EINVAL; | 94 | goto mixer_error; |
100 | } | 95 | } |
101 | 96 | ||
102 | return res; | 97 | return 0; |
98 | |||
99 | mixer_error: | ||
100 | clk_disable_unprepare(pix_clk); | ||
101 | pix_error: | ||
102 | clk_disable_unprepare(compo_clk); | ||
103 | compo_error: | ||
104 | return -EINVAL; | ||
103 | } | 105 | } |
104 | 106 | ||
105 | static void sti_crtc_disable(struct drm_crtc *crtc) | 107 | static void sti_crtc_disable(struct drm_crtc *crtc) |
@@ -130,7 +132,6 @@ static void sti_crtc_disable(struct drm_crtc *crtc) | |||
130 | static void | 132 | static void |
131 | sti_crtc_mode_set_nofb(struct drm_crtc *crtc) | 133 | sti_crtc_mode_set_nofb(struct drm_crtc *crtc) |
132 | { | 134 | { |
133 | sti_crtc_enable(crtc); | ||
134 | sti_crtc_mode_set(crtc, &crtc->state->adjusted_mode); | 135 | sti_crtc_mode_set(crtc, &crtc->state->adjusted_mode); |
135 | } | 136 | } |
136 | 137 | ||
@@ -221,9 +222,7 @@ static void sti_crtc_atomic_flush(struct drm_crtc *crtc, | |||
221 | static const struct drm_crtc_helper_funcs sti_crtc_helper_funcs = { | 222 | static const struct drm_crtc_helper_funcs sti_crtc_helper_funcs = { |
222 | .enable = sti_crtc_enable, | 223 | .enable = sti_crtc_enable, |
223 | .disable = sti_crtc_disabling, | 224 | .disable = sti_crtc_disabling, |
224 | .mode_set = drm_helper_crtc_mode_set, | ||
225 | .mode_set_nofb = sti_crtc_mode_set_nofb, | 225 | .mode_set_nofb = sti_crtc_mode_set_nofb, |
226 | .mode_set_base = drm_helper_crtc_mode_set_base, | ||
227 | .atomic_begin = sti_crtc_atomic_begin, | 226 | .atomic_begin = sti_crtc_atomic_begin, |
228 | .atomic_flush = sti_crtc_atomic_flush, | 227 | .atomic_flush = sti_crtc_atomic_flush, |
229 | }; | 228 | }; |
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index 8d1402b245bf..927e2b2e5af2 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <drm/drm_crtc_helper.h> | 18 | #include <drm/drm_crtc_helper.h> |
19 | #include <drm/drm_edid.h> | 19 | #include <drm/drm_edid.h> |
20 | 20 | ||
21 | #include <sound/hdmi-codec.h> | ||
22 | |||
21 | #include "sti_hdmi.h" | 23 | #include "sti_hdmi.h" |
22 | #include "sti_hdmi_tx3g4c28phy.h" | 24 | #include "sti_hdmi_tx3g4c28phy.h" |
23 | #include "sti_hdmi_tx3g0c55phy.h" | 25 | #include "sti_hdmi_tx3g0c55phy.h" |
@@ -35,6 +37,8 @@ | |||
35 | #define HDMI_DFLT_CHL0_DAT 0x0110 | 37 | #define HDMI_DFLT_CHL0_DAT 0x0110 |
36 | #define HDMI_DFLT_CHL1_DAT 0x0114 | 38 | #define HDMI_DFLT_CHL1_DAT 0x0114 |
37 | #define HDMI_DFLT_CHL2_DAT 0x0118 | 39 | #define HDMI_DFLT_CHL2_DAT 0x0118 |
40 | #define HDMI_AUDIO_CFG 0x0200 | ||
41 | #define HDMI_SPDIF_FIFO_STATUS 0x0204 | ||
38 | #define HDMI_SW_DI_1_HEAD_WORD 0x0210 | 42 | #define HDMI_SW_DI_1_HEAD_WORD 0x0210 |
39 | #define HDMI_SW_DI_1_PKT_WORD0 0x0214 | 43 | #define HDMI_SW_DI_1_PKT_WORD0 0x0214 |
40 | #define HDMI_SW_DI_1_PKT_WORD1 0x0218 | 44 | #define HDMI_SW_DI_1_PKT_WORD1 0x0218 |
@@ -44,6 +48,9 @@ | |||
44 | #define HDMI_SW_DI_1_PKT_WORD5 0x0228 | 48 | #define HDMI_SW_DI_1_PKT_WORD5 0x0228 |
45 | #define HDMI_SW_DI_1_PKT_WORD6 0x022C | 49 | #define HDMI_SW_DI_1_PKT_WORD6 0x022C |
46 | #define HDMI_SW_DI_CFG 0x0230 | 50 | #define HDMI_SW_DI_CFG 0x0230 |
51 | #define HDMI_SAMPLE_FLAT_MASK 0x0244 | ||
52 | #define HDMI_AUDN 0x0400 | ||
53 | #define HDMI_AUD_CTS 0x0404 | ||
47 | #define HDMI_SW_DI_2_HEAD_WORD 0x0600 | 54 | #define HDMI_SW_DI_2_HEAD_WORD 0x0600 |
48 | #define HDMI_SW_DI_2_PKT_WORD0 0x0604 | 55 | #define HDMI_SW_DI_2_PKT_WORD0 0x0604 |
49 | #define HDMI_SW_DI_2_PKT_WORD1 0x0608 | 56 | #define HDMI_SW_DI_2_PKT_WORD1 0x0608 |
@@ -103,6 +110,7 @@ | |||
103 | #define HDMI_INT_DLL_LCK BIT(5) | 110 | #define HDMI_INT_DLL_LCK BIT(5) |
104 | #define HDMI_INT_NEW_FRAME BIT(6) | 111 | #define HDMI_INT_NEW_FRAME BIT(6) |
105 | #define HDMI_INT_GENCTRL_PKT BIT(7) | 112 | #define HDMI_INT_GENCTRL_PKT BIT(7) |
113 | #define HDMI_INT_AUDIO_FIFO_XRUN BIT(8) | ||
106 | #define HDMI_INT_SINK_TERM_PRESENT BIT(11) | 114 | #define HDMI_INT_SINK_TERM_PRESENT BIT(11) |
107 | 115 | ||
108 | #define HDMI_DEFAULT_INT (HDMI_INT_SINK_TERM_PRESENT \ | 116 | #define HDMI_DEFAULT_INT (HDMI_INT_SINK_TERM_PRESENT \ |
@@ -111,6 +119,7 @@ | |||
111 | | HDMI_INT_GLOBAL) | 119 | | HDMI_INT_GLOBAL) |
112 | 120 | ||
113 | #define HDMI_WORKING_INT (HDMI_INT_SINK_TERM_PRESENT \ | 121 | #define HDMI_WORKING_INT (HDMI_INT_SINK_TERM_PRESENT \ |
122 | | HDMI_INT_AUDIO_FIFO_XRUN \ | ||
114 | | HDMI_INT_GENCTRL_PKT \ | 123 | | HDMI_INT_GENCTRL_PKT \ |
115 | | HDMI_INT_NEW_FRAME \ | 124 | | HDMI_INT_NEW_FRAME \ |
116 | | HDMI_INT_DLL_LCK \ | 125 | | HDMI_INT_DLL_LCK \ |
@@ -121,6 +130,27 @@ | |||
121 | 130 | ||
122 | #define HDMI_STA_SW_RST BIT(1) | 131 | #define HDMI_STA_SW_RST BIT(1) |
123 | 132 | ||
133 | #define HDMI_AUD_CFG_8CH BIT(0) | ||
134 | #define HDMI_AUD_CFG_SPDIF_DIV_2 BIT(1) | ||
135 | #define HDMI_AUD_CFG_SPDIF_DIV_3 BIT(2) | ||
136 | #define HDMI_AUD_CFG_SPDIF_CLK_DIV_4 (BIT(1) | BIT(2)) | ||
137 | #define HDMI_AUD_CFG_CTS_CLK_256FS BIT(12) | ||
138 | #define HDMI_AUD_CFG_DTS_INVALID BIT(16) | ||
139 | #define HDMI_AUD_CFG_ONE_BIT_INVALID (BIT(18) | BIT(19) | BIT(20) | BIT(21)) | ||
140 | #define HDMI_AUD_CFG_CH12_VALID BIT(28) | ||
141 | #define HDMI_AUD_CFG_CH34_VALID BIT(29) | ||
142 | #define HDMI_AUD_CFG_CH56_VALID BIT(30) | ||
143 | #define HDMI_AUD_CFG_CH78_VALID BIT(31) | ||
144 | |||
145 | /* sample flat mask */ | ||
146 | #define HDMI_SAMPLE_FLAT_NO 0 | ||
147 | #define HDMI_SAMPLE_FLAT_SP0 BIT(0) | ||
148 | #define HDMI_SAMPLE_FLAT_SP1 BIT(1) | ||
149 | #define HDMI_SAMPLE_FLAT_SP2 BIT(2) | ||
150 | #define HDMI_SAMPLE_FLAT_SP3 BIT(3) | ||
151 | #define HDMI_SAMPLE_FLAT_ALL (HDMI_SAMPLE_FLAT_SP0 | HDMI_SAMPLE_FLAT_SP1 |\ | ||
152 | HDMI_SAMPLE_FLAT_SP2 | HDMI_SAMPLE_FLAT_SP3) | ||
153 | |||
124 | #define HDMI_INFOFRAME_HEADER_TYPE(x) (((x) & 0xff) << 0) | 154 | #define HDMI_INFOFRAME_HEADER_TYPE(x) (((x) & 0xff) << 0) |
125 | #define HDMI_INFOFRAME_HEADER_VERSION(x) (((x) & 0xff) << 8) | 155 | #define HDMI_INFOFRAME_HEADER_VERSION(x) (((x) & 0xff) << 8) |
126 | #define HDMI_INFOFRAME_HEADER_LEN(x) (((x) & 0x0f) << 16) | 156 | #define HDMI_INFOFRAME_HEADER_LEN(x) (((x) & 0x0f) << 16) |
@@ -171,6 +201,10 @@ static irqreturn_t hdmi_irq_thread(int irq, void *arg) | |||
171 | wake_up_interruptible(&hdmi->wait_event); | 201 | wake_up_interruptible(&hdmi->wait_event); |
172 | } | 202 | } |
173 | 203 | ||
204 | /* Audio FIFO underrun IRQ */ | ||
205 | if (hdmi->irq_status & HDMI_INT_AUDIO_FIFO_XRUN) | ||
206 | DRM_INFO("Warning: audio FIFO underrun occurs!"); | ||
207 | |||
174 | return IRQ_HANDLED; | 208 | return IRQ_HANDLED; |
175 | } | 209 | } |
176 | 210 | ||
@@ -441,26 +475,29 @@ static int hdmi_avi_infoframe_config(struct sti_hdmi *hdmi) | |||
441 | */ | 475 | */ |
442 | static int hdmi_audio_infoframe_config(struct sti_hdmi *hdmi) | 476 | static int hdmi_audio_infoframe_config(struct sti_hdmi *hdmi) |
443 | { | 477 | { |
444 | struct hdmi_audio_infoframe infofame; | 478 | struct hdmi_audio_params *audio = &hdmi->audio; |
445 | u8 buffer[HDMI_INFOFRAME_SIZE(AUDIO)]; | 479 | u8 buffer[HDMI_INFOFRAME_SIZE(AUDIO)]; |
446 | int ret; | 480 | int ret, val; |
447 | 481 | ||
448 | ret = hdmi_audio_infoframe_init(&infofame); | 482 | DRM_DEBUG_DRIVER("enter %s, AIF %s\n", __func__, |
449 | if (ret < 0) { | 483 | audio->enabled ? "enable" : "disable"); |
450 | DRM_ERROR("failed to setup audio infoframe: %d\n", ret); | 484 | if (audio->enabled) { |
451 | return ret; | 485 | /* set audio parameters stored*/ |
452 | } | 486 | ret = hdmi_audio_infoframe_pack(&audio->cea, buffer, |
453 | 487 | sizeof(buffer)); | |
454 | infofame.channels = 2; | 488 | if (ret < 0) { |
455 | 489 | DRM_ERROR("failed to pack audio infoframe: %d\n", ret); | |
456 | ret = hdmi_audio_infoframe_pack(&infofame, buffer, sizeof(buffer)); | 490 | return ret; |
457 | if (ret < 0) { | 491 | } |
458 | DRM_ERROR("failed to pack audio infoframe: %d\n", ret); | 492 | hdmi_infoframe_write_infopack(hdmi, buffer, ret); |
459 | return ret; | 493 | } else { |
494 | /*disable audio info frame transmission */ | ||
495 | val = hdmi_read(hdmi, HDMI_SW_DI_CFG); | ||
496 | val &= ~HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, | ||
497 | HDMI_IFRAME_SLOT_AUDIO); | ||
498 | hdmi_write(hdmi, val, HDMI_SW_DI_CFG); | ||
460 | } | 499 | } |
461 | 500 | ||
462 | hdmi_infoframe_write_infopack(hdmi, buffer, ret); | ||
463 | |||
464 | return 0; | 501 | return 0; |
465 | } | 502 | } |
466 | 503 | ||
@@ -650,6 +687,10 @@ static int hdmi_dbg_show(struct seq_file *s, void *data) | |||
650 | DBGFS_DUMP("", HDMI_SW_DI_CFG); | 687 | DBGFS_DUMP("", HDMI_SW_DI_CFG); |
651 | hdmi_dbg_sw_di_cfg(s, hdmi_read(hdmi, HDMI_SW_DI_CFG)); | 688 | hdmi_dbg_sw_di_cfg(s, hdmi_read(hdmi, HDMI_SW_DI_CFG)); |
652 | 689 | ||
690 | DBGFS_DUMP("\n", HDMI_AUDIO_CFG); | ||
691 | DBGFS_DUMP("\n", HDMI_SPDIF_FIFO_STATUS); | ||
692 | DBGFS_DUMP("\n", HDMI_AUDN); | ||
693 | |||
653 | seq_printf(s, "\n AVI Infoframe (Data Island slot N=%d):", | 694 | seq_printf(s, "\n AVI Infoframe (Data Island slot N=%d):", |
654 | HDMI_IFRAME_SLOT_AVI); | 695 | HDMI_IFRAME_SLOT_AVI); |
655 | DBGFS_DUMP_DI(HDMI_SW_DI_N_HEAD_WORD, HDMI_IFRAME_SLOT_AVI); | 696 | DBGFS_DUMP_DI(HDMI_SW_DI_N_HEAD_WORD, HDMI_IFRAME_SLOT_AVI); |
@@ -854,6 +895,7 @@ static int sti_hdmi_connector_get_modes(struct drm_connector *connector) | |||
854 | 895 | ||
855 | count = drm_add_edid_modes(connector, edid); | 896 | count = drm_add_edid_modes(connector, edid); |
856 | drm_mode_connector_update_edid_property(connector, edid); | 897 | drm_mode_connector_update_edid_property(connector, edid); |
898 | drm_edid_to_eld(connector, edid); | ||
857 | 899 | ||
858 | kfree(edid); | 900 | kfree(edid); |
859 | return count; | 901 | return count; |
@@ -1036,6 +1078,206 @@ static struct drm_encoder *sti_hdmi_find_encoder(struct drm_device *dev) | |||
1036 | return NULL; | 1078 | return NULL; |
1037 | } | 1079 | } |
1038 | 1080 | ||
1081 | /** | ||
1082 | * sti_hdmi_audio_get_non_coherent_n() - get N parameter for non-coherent | ||
1083 | * clocks. None-coherent clocks means that audio and TMDS clocks have not the | ||
1084 | * same source (drifts between clocks). In this case assumption is that CTS is | ||
1085 | * automatically calculated by hardware. | ||
1086 | * | ||
1087 | * @audio_fs: audio frame clock frequency in Hz | ||
1088 | * | ||
1089 | * Values computed are based on table described in HDMI specification 1.4b | ||
1090 | * | ||
1091 | * Returns n value. | ||
1092 | */ | ||
1093 | static int sti_hdmi_audio_get_non_coherent_n(unsigned int audio_fs) | ||
1094 | { | ||
1095 | unsigned int n; | ||
1096 | |||
1097 | switch (audio_fs) { | ||
1098 | case 32000: | ||
1099 | n = 4096; | ||
1100 | break; | ||
1101 | case 44100: | ||
1102 | n = 6272; | ||
1103 | break; | ||
1104 | case 48000: | ||
1105 | n = 6144; | ||
1106 | break; | ||
1107 | case 88200: | ||
1108 | n = 6272 * 2; | ||
1109 | break; | ||
1110 | case 96000: | ||
1111 | n = 6144 * 2; | ||
1112 | break; | ||
1113 | case 176400: | ||
1114 | n = 6272 * 4; | ||
1115 | break; | ||
1116 | case 192000: | ||
1117 | n = 6144 * 4; | ||
1118 | break; | ||
1119 | default: | ||
1120 | /* Not pre-defined, recommended value: 128 * fs / 1000 */ | ||
1121 | n = (audio_fs * 128) / 1000; | ||
1122 | } | ||
1123 | |||
1124 | return n; | ||
1125 | } | ||
1126 | |||
1127 | static int hdmi_audio_configure(struct sti_hdmi *hdmi, | ||
1128 | struct hdmi_audio_params *params) | ||
1129 | { | ||
1130 | int audio_cfg, n; | ||
1131 | struct hdmi_audio_infoframe *info = ¶ms->cea; | ||
1132 | |||
1133 | DRM_DEBUG_DRIVER("\n"); | ||
1134 | |||
1135 | if (!hdmi->enabled) | ||
1136 | return 0; | ||
1137 | |||
1138 | /* update N parameter */ | ||
1139 | n = sti_hdmi_audio_get_non_coherent_n(params->sample_rate); | ||
1140 | |||
1141 | DRM_DEBUG_DRIVER("Audio rate = %d Hz, TMDS clock = %d Hz, n = %d\n", | ||
1142 | params->sample_rate, hdmi->mode.clock * 1000, n); | ||
1143 | hdmi_write(hdmi, n, HDMI_AUDN); | ||
1144 | |||
1145 | /* update HDMI registers according to configuration */ | ||
1146 | audio_cfg = HDMI_AUD_CFG_SPDIF_DIV_2 | HDMI_AUD_CFG_DTS_INVALID | | ||
1147 | HDMI_AUD_CFG_ONE_BIT_INVALID; | ||
1148 | |||
1149 | switch (info->channels) { | ||
1150 | case 8: | ||
1151 | audio_cfg |= HDMI_AUD_CFG_CH78_VALID; | ||
1152 | case 6: | ||
1153 | audio_cfg |= HDMI_AUD_CFG_CH56_VALID; | ||
1154 | case 4: | ||
1155 | audio_cfg |= HDMI_AUD_CFG_CH34_VALID | HDMI_AUD_CFG_8CH; | ||
1156 | case 2: | ||
1157 | audio_cfg |= HDMI_AUD_CFG_CH12_VALID; | ||
1158 | break; | ||
1159 | default: | ||
1160 | DRM_ERROR("ERROR: Unsupported number of channels (%d)!\n", | ||
1161 | info->channels); | ||
1162 | return -EINVAL; | ||
1163 | } | ||
1164 | |||
1165 | hdmi_write(hdmi, audio_cfg, HDMI_AUDIO_CFG); | ||
1166 | |||
1167 | hdmi->audio = *params; | ||
1168 | |||
1169 | return hdmi_audio_infoframe_config(hdmi); | ||
1170 | } | ||
1171 | |||
1172 | static void hdmi_audio_shutdown(struct device *dev) | ||
1173 | { | ||
1174 | struct sti_hdmi *hdmi = dev_get_drvdata(dev); | ||
1175 | int audio_cfg; | ||
1176 | |||
1177 | DRM_DEBUG_DRIVER("\n"); | ||
1178 | |||
1179 | /* disable audio */ | ||
1180 | audio_cfg = HDMI_AUD_CFG_SPDIF_DIV_2 | HDMI_AUD_CFG_DTS_INVALID | | ||
1181 | HDMI_AUD_CFG_ONE_BIT_INVALID; | ||
1182 | hdmi_write(hdmi, audio_cfg, HDMI_AUDIO_CFG); | ||
1183 | |||
1184 | hdmi->audio.enabled = 0; | ||
1185 | hdmi_audio_infoframe_config(hdmi); | ||
1186 | } | ||
1187 | |||
1188 | static int hdmi_audio_hw_params(struct device *dev, | ||
1189 | struct hdmi_codec_daifmt *daifmt, | ||
1190 | struct hdmi_codec_params *params) | ||
1191 | { | ||
1192 | struct sti_hdmi *hdmi = dev_get_drvdata(dev); | ||
1193 | int ret; | ||
1194 | struct hdmi_audio_params audio = { | ||
1195 | .sample_width = params->sample_width, | ||
1196 | .sample_rate = params->sample_rate, | ||
1197 | .cea = params->cea, | ||
1198 | }; | ||
1199 | |||
1200 | DRM_DEBUG_DRIVER("\n"); | ||
1201 | |||
1202 | if (!hdmi->enabled) | ||
1203 | return 0; | ||
1204 | |||
1205 | if ((daifmt->fmt != HDMI_I2S) || daifmt->bit_clk_inv || | ||
1206 | daifmt->frame_clk_inv || daifmt->bit_clk_master || | ||
1207 | daifmt->frame_clk_master) { | ||
1208 | dev_err(dev, "%s: Bad flags %d %d %d %d\n", __func__, | ||
1209 | daifmt->bit_clk_inv, daifmt->frame_clk_inv, | ||
1210 | daifmt->bit_clk_master, | ||
1211 | daifmt->frame_clk_master); | ||
1212 | return -EINVAL; | ||
1213 | } | ||
1214 | |||
1215 | audio.enabled = 1; | ||
1216 | |||
1217 | ret = hdmi_audio_configure(hdmi, &audio); | ||
1218 | if (ret < 0) | ||
1219 | return ret; | ||
1220 | |||
1221 | return 0; | ||
1222 | } | ||
1223 | |||
1224 | static int hdmi_audio_digital_mute(struct device *dev, bool enable) | ||
1225 | { | ||
1226 | struct sti_hdmi *hdmi = dev_get_drvdata(dev); | ||
1227 | |||
1228 | DRM_DEBUG_DRIVER("%s\n", enable ? "enable" : "disable"); | ||
1229 | |||
1230 | if (enable) | ||
1231 | hdmi_write(hdmi, HDMI_SAMPLE_FLAT_ALL, HDMI_SAMPLE_FLAT_MASK); | ||
1232 | else | ||
1233 | hdmi_write(hdmi, HDMI_SAMPLE_FLAT_NO, HDMI_SAMPLE_FLAT_MASK); | ||
1234 | |||
1235 | return 0; | ||
1236 | } | ||
1237 | |||
1238 | static int hdmi_audio_get_eld(struct device *dev, uint8_t *buf, size_t len) | ||
1239 | { | ||
1240 | struct sti_hdmi *hdmi = dev_get_drvdata(dev); | ||
1241 | struct drm_connector *connector = hdmi->drm_connector; | ||
1242 | |||
1243 | DRM_DEBUG_DRIVER("\n"); | ||
1244 | memcpy(buf, connector->eld, min(sizeof(connector->eld), len)); | ||
1245 | |||
1246 | return 0; | ||
1247 | } | ||
1248 | |||
1249 | static const struct hdmi_codec_ops audio_codec_ops = { | ||
1250 | .hw_params = hdmi_audio_hw_params, | ||
1251 | .audio_shutdown = hdmi_audio_shutdown, | ||
1252 | .digital_mute = hdmi_audio_digital_mute, | ||
1253 | .get_eld = hdmi_audio_get_eld, | ||
1254 | }; | ||
1255 | |||
1256 | static int sti_hdmi_register_audio_driver(struct device *dev, | ||
1257 | struct sti_hdmi *hdmi) | ||
1258 | { | ||
1259 | struct hdmi_codec_pdata codec_data = { | ||
1260 | .ops = &audio_codec_ops, | ||
1261 | .max_i2s_channels = 8, | ||
1262 | .i2s = 1, | ||
1263 | }; | ||
1264 | |||
1265 | DRM_DEBUG_DRIVER("\n"); | ||
1266 | |||
1267 | hdmi->audio.enabled = 0; | ||
1268 | |||
1269 | hdmi->audio_pdev = platform_device_register_data( | ||
1270 | dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO, | ||
1271 | &codec_data, sizeof(codec_data)); | ||
1272 | |||
1273 | if (IS_ERR(hdmi->audio_pdev)) | ||
1274 | return PTR_ERR(hdmi->audio_pdev); | ||
1275 | |||
1276 | DRM_INFO("%s Driver bound %s\n", HDMI_CODEC_DRV_NAME, dev_name(dev)); | ||
1277 | |||
1278 | return 0; | ||
1279 | } | ||
1280 | |||
1039 | static int sti_hdmi_bind(struct device *dev, struct device *master, void *data) | 1281 | static int sti_hdmi_bind(struct device *dev, struct device *master, void *data) |
1040 | { | 1282 | { |
1041 | struct sti_hdmi *hdmi = dev_get_drvdata(dev); | 1283 | struct sti_hdmi *hdmi = dev_get_drvdata(dev); |
@@ -1082,12 +1324,27 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data) | |||
1082 | /* initialise property */ | 1324 | /* initialise property */ |
1083 | sti_hdmi_connector_init_property(drm_dev, drm_connector); | 1325 | sti_hdmi_connector_init_property(drm_dev, drm_connector); |
1084 | 1326 | ||
1327 | hdmi->drm_connector = drm_connector; | ||
1328 | |||
1085 | err = drm_mode_connector_attach_encoder(drm_connector, encoder); | 1329 | err = drm_mode_connector_attach_encoder(drm_connector, encoder); |
1086 | if (err) { | 1330 | if (err) { |
1087 | DRM_ERROR("Failed to attach a connector to a encoder\n"); | 1331 | DRM_ERROR("Failed to attach a connector to a encoder\n"); |
1088 | goto err_sysfs; | 1332 | goto err_sysfs; |
1089 | } | 1333 | } |
1090 | 1334 | ||
1335 | err = sti_hdmi_register_audio_driver(dev, hdmi); | ||
1336 | if (err) { | ||
1337 | DRM_ERROR("Failed to attach an audio codec\n"); | ||
1338 | goto err_sysfs; | ||
1339 | } | ||
1340 | |||
1341 | /* Initialize audio infoframe */ | ||
1342 | err = hdmi_audio_infoframe_init(&hdmi->audio.cea); | ||
1343 | if (err) { | ||
1344 | DRM_ERROR("Failed to init audio infoframe\n"); | ||
1345 | goto err_sysfs; | ||
1346 | } | ||
1347 | |||
1091 | /* Enable default interrupts */ | 1348 | /* Enable default interrupts */ |
1092 | hdmi_write(hdmi, HDMI_DEFAULT_INT, HDMI_INT_EN); | 1349 | hdmi_write(hdmi, HDMI_DEFAULT_INT, HDMI_INT_EN); |
1093 | 1350 | ||
@@ -1095,6 +1352,7 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data) | |||
1095 | 1352 | ||
1096 | err_sysfs: | 1353 | err_sysfs: |
1097 | drm_bridge_remove(bridge); | 1354 | drm_bridge_remove(bridge); |
1355 | hdmi->drm_connector = NULL; | ||
1098 | return -EINVAL; | 1356 | return -EINVAL; |
1099 | } | 1357 | } |
1100 | 1358 | ||
@@ -1244,6 +1502,8 @@ static int sti_hdmi_remove(struct platform_device *pdev) | |||
1244 | struct sti_hdmi *hdmi = dev_get_drvdata(&pdev->dev); | 1502 | struct sti_hdmi *hdmi = dev_get_drvdata(&pdev->dev); |
1245 | 1503 | ||
1246 | i2c_put_adapter(hdmi->ddc_adapt); | 1504 | i2c_put_adapter(hdmi->ddc_adapt); |
1505 | if (hdmi->audio_pdev) | ||
1506 | platform_device_unregister(hdmi->audio_pdev); | ||
1247 | component_del(&pdev->dev, &sti_hdmi_ops); | 1507 | component_del(&pdev->dev, &sti_hdmi_ops); |
1248 | 1508 | ||
1249 | return 0; | 1509 | return 0; |
diff --git a/drivers/gpu/drm/sti/sti_hdmi.h b/drivers/gpu/drm/sti/sti_hdmi.h index ef3a94583bbd..119bc3582ac7 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.h +++ b/drivers/gpu/drm/sti/sti_hdmi.h | |||
@@ -23,6 +23,13 @@ struct hdmi_phy_ops { | |||
23 | void (*stop)(struct sti_hdmi *hdmi); | 23 | void (*stop)(struct sti_hdmi *hdmi); |
24 | }; | 24 | }; |
25 | 25 | ||
26 | struct hdmi_audio_params { | ||
27 | bool enabled; | ||
28 | unsigned int sample_width; | ||
29 | unsigned int sample_rate; | ||
30 | struct hdmi_audio_infoframe cea; | ||
31 | }; | ||
32 | |||
26 | /* values for the framing mode property */ | 33 | /* values for the framing mode property */ |
27 | enum sti_hdmi_modes { | 34 | enum sti_hdmi_modes { |
28 | HDMI_MODE_HDMI, | 35 | HDMI_MODE_HDMI, |
@@ -67,6 +74,9 @@ static const struct drm_prop_enum_list colorspace_mode_names[] = { | |||
67 | * @ddc_adapt: i2c ddc adapter | 74 | * @ddc_adapt: i2c ddc adapter |
68 | * @colorspace: current colorspace selected | 75 | * @colorspace: current colorspace selected |
69 | * @hdmi_mode: select framing for HDMI or DVI | 76 | * @hdmi_mode: select framing for HDMI or DVI |
77 | * @audio_pdev: ASoC hdmi-codec platform device | ||
78 | * @audio: hdmi audio parameters. | ||
79 | * @drm_connector: hdmi connector | ||
70 | */ | 80 | */ |
71 | struct sti_hdmi { | 81 | struct sti_hdmi { |
72 | struct device dev; | 82 | struct device dev; |
@@ -89,6 +99,9 @@ struct sti_hdmi { | |||
89 | struct i2c_adapter *ddc_adapt; | 99 | struct i2c_adapter *ddc_adapt; |
90 | enum hdmi_colorspace colorspace; | 100 | enum hdmi_colorspace colorspace; |
91 | enum sti_hdmi_modes hdmi_mode; | 101 | enum sti_hdmi_modes hdmi_mode; |
102 | struct platform_device *audio_pdev; | ||
103 | struct hdmi_audio_params audio; | ||
104 | struct drm_connector *drm_connector; | ||
92 | }; | 105 | }; |
93 | 106 | ||
94 | u32 hdmi_read(struct sti_hdmi *hdmi, int offset); | 107 | u32 hdmi_read(struct sti_hdmi *hdmi, int offset); |
diff --git a/drivers/gpu/drm/sti/sti_plane.c b/drivers/gpu/drm/sti/sti_plane.c index 85cee9098439..0cf3335ef37c 100644 --- a/drivers/gpu/drm/sti/sti_plane.c +++ b/drivers/gpu/drm/sti/sti_plane.c | |||
@@ -45,25 +45,15 @@ const char *sti_plane_to_str(struct sti_plane *plane) | |||
45 | 45 | ||
46 | #define STI_FPS_INTERVAL_MS 3000 | 46 | #define STI_FPS_INTERVAL_MS 3000 |
47 | 47 | ||
48 | static int sti_plane_timespec_ms_diff(struct timespec lhs, struct timespec rhs) | ||
49 | { | ||
50 | struct timespec tmp_ts = timespec_sub(lhs, rhs); | ||
51 | u64 tmp_ns = (u64)timespec_to_ns(&tmp_ts); | ||
52 | |||
53 | do_div(tmp_ns, NSEC_PER_MSEC); | ||
54 | |||
55 | return (u32)tmp_ns; | ||
56 | } | ||
57 | |||
58 | void sti_plane_update_fps(struct sti_plane *plane, | 48 | void sti_plane_update_fps(struct sti_plane *plane, |
59 | bool new_frame, | 49 | bool new_frame, |
60 | bool new_field) | 50 | bool new_field) |
61 | { | 51 | { |
62 | struct timespec now; | 52 | ktime_t now; |
63 | struct sti_fps_info *fps; | 53 | struct sti_fps_info *fps; |
64 | int fpks, fipks, ms_since_last, num_frames, num_fields; | 54 | int fpks, fipks, ms_since_last, num_frames, num_fields; |
65 | 55 | ||
66 | getrawmonotonic(&now); | 56 | now = ktime_get(); |
67 | 57 | ||
68 | /* Compute number of frame updates */ | 58 | /* Compute number of frame updates */ |
69 | fps = &plane->fps_info; | 59 | fps = &plane->fps_info; |
@@ -76,7 +66,7 @@ void sti_plane_update_fps(struct sti_plane *plane, | |||
76 | return; | 66 | return; |
77 | 67 | ||
78 | fps->curr_frame_counter++; | 68 | fps->curr_frame_counter++; |
79 | ms_since_last = sti_plane_timespec_ms_diff(now, fps->last_timestamp); | 69 | ms_since_last = ktime_to_ms(ktime_sub(now, fps->last_timestamp)); |
80 | num_frames = fps->curr_frame_counter - fps->last_frame_counter; | 70 | num_frames = fps->curr_frame_counter - fps->last_frame_counter; |
81 | 71 | ||
82 | if (num_frames <= 0 || ms_since_last < STI_FPS_INTERVAL_MS) | 72 | if (num_frames <= 0 || ms_since_last < STI_FPS_INTERVAL_MS) |
diff --git a/drivers/gpu/drm/sti/sti_plane.h b/drivers/gpu/drm/sti/sti_plane.h index 39d39f5b7dd9..e0ea1dd3bb88 100644 --- a/drivers/gpu/drm/sti/sti_plane.h +++ b/drivers/gpu/drm/sti/sti_plane.h | |||
@@ -55,7 +55,7 @@ struct sti_fps_info { | |||
55 | unsigned int last_frame_counter; | 55 | unsigned int last_frame_counter; |
56 | unsigned int curr_field_counter; | 56 | unsigned int curr_field_counter; |
57 | unsigned int last_field_counter; | 57 | unsigned int last_field_counter; |
58 | struct timespec last_timestamp; | 58 | ktime_t last_timestamp; |
59 | char fps_str[FPS_LENGTH]; | 59 | char fps_str[FPS_LENGTH]; |
60 | char fips_str[FPS_LENGTH]; | 60 | char fips_str[FPS_LENGTH]; |
61 | }; | 61 | }; |
diff --git a/drivers/gpu/drm/sti/sti_vtg.c b/drivers/gpu/drm/sti/sti_vtg.c index 6bf4ce466d20..957ce712ea44 100644 --- a/drivers/gpu/drm/sti/sti_vtg.c +++ b/drivers/gpu/drm/sti/sti_vtg.c | |||
@@ -65,7 +65,7 @@ | |||
65 | #define HDMI_DELAY (5) | 65 | #define HDMI_DELAY (5) |
66 | 66 | ||
67 | /* Delay introduced by the DVO in nb of pixel */ | 67 | /* Delay introduced by the DVO in nb of pixel */ |
68 | #define DVO_DELAY (2) | 68 | #define DVO_DELAY (7) |
69 | 69 | ||
70 | /* delay introduced by the Arbitrary Waveform Generator in nb of pixels */ | 70 | /* delay introduced by the Arbitrary Waveform Generator in nb of pixels */ |
71 | #define AWG_DELAY_HD (-9) | 71 | #define AWG_DELAY_HD (-9) |