aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2016-03-16 18:27:51 -0400
committerDave Airlie <airlied@redhat.com>2016-03-16 18:27:51 -0400
commitcf481068cdd430a22425d7712c8deeb25efdedc1 (patch)
tree7ddf5043cb06c12327ae8b5529356ff45e83e5e8 /drivers/gpu
parent9f443bf53b5699835e0132d62d1e6c99a1eaeee8 (diff)
parent52807ae90e76b69fd01688d6031190271536d29f (diff)
Merge branch '2016-02-26-st-drm-next' of http://git.linaro.org/people/benjamin.gaignard/kernel into drm-next
Here are sti patches for drm-next. It brings: - The support of the atomic_check for the planes and minor fixes for planes - The support of the vendor specific infoframe for HDMI and the support of 2 HDMI properties related to the connector - The support of the DVO solving panel detection issue and timing issue. - The support of debugfs for connectors, encoders, crtcs and planes. * '2016-02-26-st-drm-next' of http://git.linaro.org/people/benjamin.gaignard/kernel: (36 commits) drm/sti: use u32 to store DMA addresses drm: sti: remove sti_gem_prime_export hack drm/sti: add debugfs fps_show/fps_get mechanism for planes drm/sti: add debugfs entries for TVOUT encoders drm/sti: add debugfs entries for MIXER crtc drm/sti: add debugfs entries for VID plane drm/sti: add debugfs entries for HQVDP plane drm/sti: add debugfs entries for GDP planes drm/sti: add debugfs entries for CURSOR plane drm/sti: add debugfs entries for HDA connector drm/sti: add debugfs entries for DVO connector drm/sti: add debugfs entries for HDMI connector drm/sti: add hdmi_mode property for HDMI connector drm/sti: add colorspace property to the HDMI connector drm/sti: add HDMI vendor specific infoframe drm/sti: reset infoframe transmission when HDMI is stopped drm/sti: HDMI infoframe transmission mode not take into account drm/sti: reset HD DACS when HDA connector is created drm/sti: fix dvo data_enable signal drm/sti: adjust delay for DVO ...
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/sti/sti_awg_utils.c78
-rw-r--r--drivers/gpu/drm/sti/sti_compositor.c4
-rw-r--r--drivers/gpu/drm/sti/sti_crtc.c9
-rw-r--r--drivers/gpu/drm/sti/sti_cursor.c184
-rw-r--r--drivers/gpu/drm/sti/sti_drv.c141
-rw-r--r--drivers/gpu/drm/sti/sti_dvo.c78
-rw-r--r--drivers/gpu/drm/sti/sti_gdp.c476
-rw-r--r--drivers/gpu/drm/sti/sti_hda.c108
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi.c400
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi.h31
-rw-r--r--drivers/gpu/drm/sti/sti_hqvdp.c447
-rw-r--r--drivers/gpu/drm/sti/sti_mixer.c146
-rw-r--r--drivers/gpu/drm/sti/sti_mixer.h4
-rw-r--r--drivers/gpu/drm/sti/sti_plane.c63
-rw-r--r--drivers/gpu/drm/sti/sti_plane.h17
-rw-r--r--drivers/gpu/drm/sti/sti_tvout.c295
-rw-r--r--drivers/gpu/drm/sti/sti_vid.c125
-rw-r--r--drivers/gpu/drm/sti/sti_vid.h4
-rw-r--r--drivers/gpu/drm/sti/sti_vtg.c200
-rw-r--r--drivers/gpu/drm/sti/sti_vtg.h5
20 files changed, 2399 insertions, 416 deletions
diff --git a/drivers/gpu/drm/sti/sti_awg_utils.c b/drivers/gpu/drm/sti/sti_awg_utils.c
index 00d0698be9d3..a516eb869f6f 100644
--- a/drivers/gpu/drm/sti/sti_awg_utils.c
+++ b/drivers/gpu/drm/sti/sti_awg_utils.c
@@ -7,6 +7,7 @@
7#include "sti_awg_utils.h" 7#include "sti_awg_utils.h"
8 8
9#define AWG_OPCODE_OFFSET 10 9#define AWG_OPCODE_OFFSET 10
10#define AWG_MAX_ARG 0x3ff
10 11
11enum opcode { 12enum opcode {
12 SET, 13 SET,
@@ -34,6 +35,8 @@ static int awg_generate_instr(enum opcode opcode,
34 /* skip, repeat and replay arg should not exceed 1023. 35 /* skip, repeat and replay arg should not exceed 1023.
35 * If user wants to exceed this value, the instruction should be 36 * If user wants to exceed this value, the instruction should be
36 * duplicate and arg should be adjust for each duplicated instruction. 37 * duplicate and arg should be adjust for each duplicated instruction.
38 *
39 * mux_sel is used in case of SAV/EAV synchronization.
37 */ 40 */
38 41
39 while (arg_tmp > 0) { 42 while (arg_tmp > 0) {
@@ -65,7 +68,7 @@ static int awg_generate_instr(enum opcode opcode,
65 68
66 mux = 0; 69 mux = 0;
67 data_enable = 0; 70 data_enable = 0;
68 arg &= (0x3ff); 71 arg &= AWG_MAX_ARG;
69 break; 72 break;
70 case REPEAT: 73 case REPEAT:
71 case REPLAY: 74 case REPLAY:
@@ -76,13 +79,13 @@ static int awg_generate_instr(enum opcode opcode,
76 79
77 mux = 0; 80 mux = 0;
78 data_enable = 0; 81 data_enable = 0;
79 arg &= (0x3ff); 82 arg &= AWG_MAX_ARG;
80 break; 83 break;
81 case JUMP: 84 case JUMP:
82 mux = 0; 85 mux = 0;
83 data_enable = 0; 86 data_enable = 0;
84 arg |= 0x40; /* for jump instruction 7th bit is 1 */ 87 arg |= 0x40; /* for jump instruction 7th bit is 1 */
85 arg &= 0x3ff; 88 arg &= AWG_MAX_ARG;
86 break; 89 break;
87 case STOP: 90 case STOP:
88 arg = 0; 91 arg = 0;
@@ -110,68 +113,75 @@ static int awg_generate_instr(enum opcode opcode,
110 return 0; 113 return 0;
111} 114}
112 115
113int sti_awg_generate_code_data_enable_mode( 116static int awg_generate_line_signal(
114 struct awg_code_generation_params *fwparams, 117 struct awg_code_generation_params *fwparams,
115 struct awg_timing *timing) 118 struct awg_timing *timing)
116{ 119{
117 long int val; 120 long int val;
118 long int data_en;
119 int ret = 0; 121 int ret = 0;
120 122
121 if (timing->trailing_lines > 0) {
122 /* skip trailing lines */
123 val = timing->blanking_level;
124 data_en = 0;
125 ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams);
126
127 val = timing->trailing_lines - 1;
128 data_en = 0;
129 ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams);
130 }
131
132 if (timing->trailing_pixels > 0) { 123 if (timing->trailing_pixels > 0) {
133 /* skip trailing pixel */ 124 /* skip trailing pixel */
134 val = timing->blanking_level; 125 val = timing->blanking_level;
135 data_en = 0; 126 ret |= awg_generate_instr(RPLSET, val, 0, 0, fwparams);
136 ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams);
137 127
138 val = timing->trailing_pixels - 1; 128 val = timing->trailing_pixels - 1;
139 data_en = 0; 129 ret |= awg_generate_instr(SKIP, val, 0, 0, fwparams);
140 ret |= awg_generate_instr(SKIP, val, 0, data_en, fwparams);
141 } 130 }
142 131
143 /* set DE signal high */ 132 /* set DE signal high */
144 val = timing->blanking_level; 133 val = timing->blanking_level;
145 data_en = 1;
146 ret |= awg_generate_instr((timing->trailing_pixels > 0) ? SET : RPLSET, 134 ret |= awg_generate_instr((timing->trailing_pixels > 0) ? SET : RPLSET,
147 val, 0, data_en, fwparams); 135 val, 0, 1, fwparams);
148 136
149 if (timing->blanking_pixels > 0) { 137 if (timing->blanking_pixels > 0) {
150 /* skip the number of active pixel */ 138 /* skip the number of active pixel */
151 val = timing->active_pixels - 1; 139 val = timing->active_pixels - 1;
152 data_en = 1; 140 ret |= awg_generate_instr(SKIP, val, 0, 1, fwparams);
153 ret |= awg_generate_instr(SKIP, val, 0, data_en, fwparams);
154 141
155 /* set DE signal low */ 142 /* set DE signal low */
156 val = timing->blanking_level; 143 val = timing->blanking_level;
157 data_en = 0; 144 ret |= awg_generate_instr(SET, val, 0, 0, fwparams);
158 ret |= awg_generate_instr(SET, val, 0, data_en, fwparams); 145 }
146
147 return ret;
148}
149
150int sti_awg_generate_code_data_enable_mode(
151 struct awg_code_generation_params *fwparams,
152 struct awg_timing *timing)
153{
154 long int val, tmp_val;
155 int ret = 0;
156
157 if (timing->trailing_lines > 0) {
158 /* skip trailing lines */
159 val = timing->blanking_level;
160 ret |= awg_generate_instr(RPLSET, val, 0, 0, fwparams);
161
162 val = timing->trailing_lines - 1;
163 ret |= awg_generate_instr(REPLAY, val, 0, 0, fwparams);
159 } 164 }
160 165
161 /* replay the sequence as many active lines defined */ 166 tmp_val = timing->active_lines - 1;
162 val = timing->active_lines - 1; 167
163 data_en = 0; 168 while (tmp_val > 0) {
164 ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams); 169 /* generate DE signal for each line */
170 ret |= awg_generate_line_signal(fwparams, timing);
171 /* replay the sequence as many active lines defined */
172 ret |= awg_generate_instr(REPLAY,
173 min_t(int, AWG_MAX_ARG, tmp_val),
174 0, 0, fwparams);
175 tmp_val -= AWG_MAX_ARG;
176 }
165 177
166 if (timing->blanking_lines > 0) { 178 if (timing->blanking_lines > 0) {
167 /* skip blanking lines */ 179 /* skip blanking lines */
168 val = timing->blanking_level; 180 val = timing->blanking_level;
169 data_en = 0; 181 ret |= awg_generate_instr(RPLSET, val, 0, 0, fwparams);
170 ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams);
171 182
172 val = timing->blanking_lines - 1; 183 val = timing->blanking_lines - 1;
173 data_en = 0; 184 ret |= awg_generate_instr(REPLAY, val, 0, 0, fwparams);
174 ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams);
175 } 185 }
176 186
177 return ret; 187 return ret;
diff --git a/drivers/gpu/drm/sti/sti_compositor.c b/drivers/gpu/drm/sti/sti_compositor.c
index afed2171beb9..3d2fa3ab33df 100644
--- a/drivers/gpu/drm/sti/sti_compositor.c
+++ b/drivers/gpu/drm/sti/sti_compositor.c
@@ -75,13 +75,13 @@ static int sti_compositor_bind(struct device *dev,
75 switch (desc[i].type) { 75 switch (desc[i].type) {
76 case STI_VID_SUBDEV: 76 case STI_VID_SUBDEV:
77 compo->vid[vid_id++] = 77 compo->vid[vid_id++] =
78 sti_vid_create(compo->dev, desc[i].id, 78 sti_vid_create(compo->dev, drm_dev, desc[i].id,
79 compo->regs + desc[i].offset); 79 compo->regs + desc[i].offset);
80 break; 80 break;
81 case STI_MIXER_MAIN_SUBDEV: 81 case STI_MIXER_MAIN_SUBDEV:
82 case STI_MIXER_AUX_SUBDEV: 82 case STI_MIXER_AUX_SUBDEV:
83 compo->mixer[mixer_id++] = 83 compo->mixer[mixer_id++] =
84 sti_mixer_create(compo->dev, desc[i].id, 84 sti_mixer_create(compo->dev, drm_dev, desc[i].id,
85 compo->regs + desc[i].offset); 85 compo->regs + desc[i].offset);
86 break; 86 break;
87 case STI_GPD_SUBDEV: 87 case STI_GPD_SUBDEV:
diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c
index e04deedabd4a..fa47f63b5316 100644
--- a/drivers/gpu/drm/sti/sti_crtc.c
+++ b/drivers/gpu/drm/sti/sti_crtc.c
@@ -51,6 +51,15 @@ static void sti_crtc_disabling(struct drm_crtc *crtc)
51 mixer->status = STI_MIXER_DISABLING; 51 mixer->status = STI_MIXER_DISABLING;
52} 52}
53 53
54static bool sti_crtc_mode_fixup(struct drm_crtc *crtc,
55 const struct drm_display_mode *mode,
56 struct drm_display_mode *adjusted_mode)
57{
58 /* accept the provided drm_display_mode, do not fix it up */
59 drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
60 return true;
61}
62
54static int 63static int
55sti_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode) 64sti_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode)
56{ 65{
diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c
index 807863106b8d..82b5711fefef 100644
--- a/drivers/gpu/drm/sti/sti_cursor.c
+++ b/drivers/gpu/drm/sti/sti_cursor.c
@@ -5,12 +5,10 @@
5 * for STMicroelectronics. 5 * for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2 6 * License terms: GNU General Public License (GPL), version 2
7 */ 7 */
8#include <drm/drmP.h>
9 8
10#include <drm/drm_atomic_helper.h> 9#include <drm/drm_atomic.h>
11#include <drm/drm_fb_cma_helper.h> 10#include <drm/drm_fb_cma_helper.h>
12#include <drm/drm_gem_cma_helper.h> 11#include <drm/drm_gem_cma_helper.h>
13#include <drm/drm_plane_helper.h>
14 12
15#include "sti_compositor.h" 13#include "sti_compositor.h"
16#include "sti_cursor.h" 14#include "sti_cursor.h"
@@ -74,6 +72,82 @@ static const uint32_t cursor_supported_formats[] = {
74 72
75#define to_sti_cursor(x) container_of(x, struct sti_cursor, plane) 73#define to_sti_cursor(x) container_of(x, struct sti_cursor, plane)
76 74
75#define DBGFS_DUMP(reg) seq_printf(s, "\n %-25s 0x%08X", #reg, \
76 readl(cursor->regs + reg))
77
78static void cursor_dbg_vpo(struct seq_file *s, u32 val)
79{
80 seq_printf(s, "\txdo:%4d\tydo:%4d", val & 0x0FFF, (val >> 16) & 0x0FFF);
81}
82
83static void cursor_dbg_size(struct seq_file *s, u32 val)
84{
85 seq_printf(s, "\t%d x %d", val & 0x07FF, (val >> 16) & 0x07FF);
86}
87
88static void cursor_dbg_pml(struct seq_file *s,
89 struct sti_cursor *cursor, u32 val)
90{
91 if (cursor->pixmap.paddr == val)
92 seq_printf(s, "\tVirt @: %p", cursor->pixmap.base);
93}
94
95static void cursor_dbg_cml(struct seq_file *s,
96 struct sti_cursor *cursor, u32 val)
97{
98 if (cursor->clut_paddr == val)
99 seq_printf(s, "\tVirt @: %p", cursor->clut);
100}
101
102static int cursor_dbg_show(struct seq_file *s, void *data)
103{
104 struct drm_info_node *node = s->private;
105 struct sti_cursor *cursor = (struct sti_cursor *)node->info_ent->data;
106 struct drm_device *dev = node->minor->dev;
107 int ret;
108
109 ret = mutex_lock_interruptible(&dev->struct_mutex);
110 if (ret)
111 return ret;
112
113 seq_printf(s, "%s: (vaddr = 0x%p)",
114 sti_plane_to_str(&cursor->plane), cursor->regs);
115
116 DBGFS_DUMP(CUR_CTL);
117 DBGFS_DUMP(CUR_VPO);
118 cursor_dbg_vpo(s, readl(cursor->regs + CUR_VPO));
119 DBGFS_DUMP(CUR_PML);
120 cursor_dbg_pml(s, cursor, readl(cursor->regs + CUR_PML));
121 DBGFS_DUMP(CUR_PMP);
122 DBGFS_DUMP(CUR_SIZE);
123 cursor_dbg_size(s, readl(cursor->regs + CUR_SIZE));
124 DBGFS_DUMP(CUR_CML);
125 cursor_dbg_cml(s, cursor, readl(cursor->regs + CUR_CML));
126 DBGFS_DUMP(CUR_AWS);
127 DBGFS_DUMP(CUR_AWE);
128 seq_puts(s, "\n");
129
130 mutex_unlock(&dev->struct_mutex);
131 return 0;
132}
133
134static struct drm_info_list cursor_debugfs_files[] = {
135 { "cursor", cursor_dbg_show, 0, NULL },
136};
137
138static int cursor_debugfs_init(struct sti_cursor *cursor,
139 struct drm_minor *minor)
140{
141 unsigned int i;
142
143 for (i = 0; i < ARRAY_SIZE(cursor_debugfs_files); i++)
144 cursor_debugfs_files[i].data = cursor;
145
146 return drm_debugfs_create_files(cursor_debugfs_files,
147 ARRAY_SIZE(cursor_debugfs_files),
148 minor->debugfs_root, minor);
149}
150
77static void sti_cursor_argb8888_to_clut8(struct sti_cursor *cursor, u32 *src) 151static void sti_cursor_argb8888_to_clut8(struct sti_cursor *cursor, u32 *src)
78{ 152{
79 u8 *dst = cursor->pixmap.base; 153 u8 *dst = cursor->pixmap.base;
@@ -110,35 +184,31 @@ static void sti_cursor_init(struct sti_cursor *cursor)
110 (b * 5); 184 (b * 5);
111} 185}
112 186
113static void sti_cursor_atomic_update(struct drm_plane *drm_plane, 187static int sti_cursor_atomic_check(struct drm_plane *drm_plane,
114 struct drm_plane_state *oldstate) 188 struct drm_plane_state *state)
115{ 189{
116 struct drm_plane_state *state = drm_plane->state;
117 struct sti_plane *plane = to_sti_plane(drm_plane); 190 struct sti_plane *plane = to_sti_plane(drm_plane);
118 struct sti_cursor *cursor = to_sti_cursor(plane); 191 struct sti_cursor *cursor = to_sti_cursor(plane);
119 struct drm_crtc *crtc = state->crtc; 192 struct drm_crtc *crtc = state->crtc;
120 struct sti_mixer *mixer = to_sti_mixer(crtc);
121 struct drm_framebuffer *fb = state->fb; 193 struct drm_framebuffer *fb = state->fb;
122 struct drm_display_mode *mode = &crtc->mode; 194 struct drm_crtc_state *crtc_state;
123 int dst_x = state->crtc_x; 195 struct drm_display_mode *mode;
124 int dst_y = state->crtc_y; 196 int dst_x, dst_y, dst_w, dst_h;
125 int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x); 197 int src_w, src_h;
126 int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y); 198
199 /* no need for further checks if the plane is being disabled */
200 if (!crtc || !fb)
201 return 0;
202
203 crtc_state = drm_atomic_get_crtc_state(state->state, crtc);
204 mode = &crtc_state->mode;
205 dst_x = state->crtc_x;
206 dst_y = state->crtc_y;
207 dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
208 dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
127 /* src_x are in 16.16 format */ 209 /* src_x are in 16.16 format */
128 int src_w = state->src_w >> 16; 210 src_w = state->src_w >> 16;
129 int src_h = state->src_h >> 16; 211 src_h = state->src_h >> 16;
130 bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false;
131 struct drm_gem_cma_object *cma_obj;
132 u32 y, x;
133 u32 val;
134
135 DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n",
136 crtc->base.id, sti_mixer_to_str(mixer),
137 drm_plane->base.id, sti_plane_to_str(plane));
138 DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", dst_w, dst_h, dst_x, dst_y);
139
140 dev_dbg(cursor->dev, "%s %s\n", __func__,
141 sti_plane_to_str(plane));
142 212
143 if (src_w < STI_CURS_MIN_SIZE || 213 if (src_w < STI_CURS_MIN_SIZE ||
144 src_h < STI_CURS_MIN_SIZE || 214 src_h < STI_CURS_MIN_SIZE ||
@@ -146,7 +216,7 @@ static void sti_cursor_atomic_update(struct drm_plane *drm_plane,
146 src_h > STI_CURS_MAX_SIZE) { 216 src_h > STI_CURS_MAX_SIZE) {
147 DRM_ERROR("Invalid cursor size (%dx%d)\n", 217 DRM_ERROR("Invalid cursor size (%dx%d)\n",
148 src_w, src_h); 218 src_w, src_h);
149 return; 219 return -EINVAL;
150 } 220 }
151 221
152 /* If the cursor size has changed, re-allocated the pixmap */ 222 /* If the cursor size has changed, re-allocated the pixmap */
@@ -170,16 +240,46 @@ static void sti_cursor_atomic_update(struct drm_plane *drm_plane,
170 GFP_KERNEL | GFP_DMA); 240 GFP_KERNEL | GFP_DMA);
171 if (!cursor->pixmap.base) { 241 if (!cursor->pixmap.base) {
172 DRM_ERROR("Failed to allocate memory for pixmap\n"); 242 DRM_ERROR("Failed to allocate memory for pixmap\n");
173 return; 243 return -EINVAL;
174 } 244 }
175 } 245 }
176 246
177 cma_obj = drm_fb_cma_get_gem_obj(fb, 0); 247 if (!drm_fb_cma_get_gem_obj(fb, 0)) {
178 if (!cma_obj) {
179 DRM_ERROR("Can't get CMA GEM object for fb\n"); 248 DRM_ERROR("Can't get CMA GEM object for fb\n");
180 return; 249 return -EINVAL;
181 } 250 }
182 251
252 DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n",
253 crtc->base.id, sti_mixer_to_str(to_sti_mixer(crtc)),
254 drm_plane->base.id, sti_plane_to_str(plane));
255 DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", dst_w, dst_h, dst_x, dst_y);
256
257 return 0;
258}
259
260static void sti_cursor_atomic_update(struct drm_plane *drm_plane,
261 struct drm_plane_state *oldstate)
262{
263 struct drm_plane_state *state = drm_plane->state;
264 struct sti_plane *plane = to_sti_plane(drm_plane);
265 struct sti_cursor *cursor = to_sti_cursor(plane);
266 struct drm_crtc *crtc = state->crtc;
267 struct drm_framebuffer *fb = state->fb;
268 struct drm_display_mode *mode;
269 int dst_x, dst_y;
270 struct drm_gem_cma_object *cma_obj;
271 u32 y, x;
272 u32 val;
273
274 if (!crtc || !fb)
275 return;
276
277 mode = &crtc->mode;
278 dst_x = state->crtc_x;
279 dst_y = state->crtc_y;
280
281 cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
282
183 /* Convert ARGB8888 to CLUT8 */ 283 /* Convert ARGB8888 to CLUT8 */
184 sti_cursor_argb8888_to_clut8(cursor, (u32 *)cma_obj->vaddr); 284 sti_cursor_argb8888_to_clut8(cursor, (u32 *)cma_obj->vaddr);
185 285
@@ -193,21 +293,21 @@ static void sti_cursor_atomic_update(struct drm_plane *drm_plane,
193 val = y << 16 | x; 293 val = y << 16 | x;
194 writel(val, cursor->regs + CUR_AWE); 294 writel(val, cursor->regs + CUR_AWE);
195 295
196 if (first_prepare) {
197 /* Set and fetch CLUT */
198 writel(cursor->clut_paddr, cursor->regs + CUR_CML);
199 writel(CUR_CTL_CLUT_UPDATE, cursor->regs + CUR_CTL);
200 }
201
202 /* Set memory location, size, and position */ 296 /* Set memory location, size, and position */
203 writel(cursor->pixmap.paddr, cursor->regs + CUR_PML); 297 writel(cursor->pixmap.paddr, cursor->regs + CUR_PML);
204 writel(cursor->width, cursor->regs + CUR_PMP); 298 writel(cursor->width, cursor->regs + CUR_PMP);
205 writel(cursor->height << 16 | cursor->width, cursor->regs + CUR_SIZE); 299 writel(cursor->height << 16 | cursor->width, cursor->regs + CUR_SIZE);
206 300
207 y = sti_vtg_get_line_number(*mode, dst_y); 301 y = sti_vtg_get_line_number(*mode, dst_y);
208 x = sti_vtg_get_pixel_number(*mode, dst_y); 302 x = sti_vtg_get_pixel_number(*mode, dst_x);
209 writel((y << 16) | x, cursor->regs + CUR_VPO); 303 writel((y << 16) | x, cursor->regs + CUR_VPO);
210 304
305 /* Set and fetch CLUT */
306 writel(cursor->clut_paddr, cursor->regs + CUR_CML);
307 writel(CUR_CTL_CLUT_UPDATE, cursor->regs + CUR_CTL);
308
309 sti_plane_update_fps(plane, true, false);
310
211 plane->status = STI_PLANE_UPDATED; 311 plane->status = STI_PLANE_UPDATED;
212} 312}
213 313
@@ -215,7 +315,6 @@ static void sti_cursor_atomic_disable(struct drm_plane *drm_plane,
215 struct drm_plane_state *oldstate) 315 struct drm_plane_state *oldstate)
216{ 316{
217 struct sti_plane *plane = to_sti_plane(drm_plane); 317 struct sti_plane *plane = to_sti_plane(drm_plane);
218 struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
219 318
220 if (!drm_plane->crtc) { 319 if (!drm_plane->crtc) {
221 DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", 320 DRM_DEBUG_DRIVER("drm plane:%d not enabled\n",
@@ -224,13 +323,15 @@ static void sti_cursor_atomic_disable(struct drm_plane *drm_plane,
224 } 323 }
225 324
226 DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n", 325 DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n",
227 drm_plane->crtc->base.id, sti_mixer_to_str(mixer), 326 drm_plane->crtc->base.id,
327 sti_mixer_to_str(to_sti_mixer(drm_plane->crtc)),
228 drm_plane->base.id, sti_plane_to_str(plane)); 328 drm_plane->base.id, sti_plane_to_str(plane));
229 329
230 plane->status = STI_PLANE_DISABLING; 330 plane->status = STI_PLANE_DISABLING;
231} 331}
232 332
233static const struct drm_plane_helper_funcs sti_cursor_helpers_funcs = { 333static const struct drm_plane_helper_funcs sti_cursor_helpers_funcs = {
334 .atomic_check = sti_cursor_atomic_check,
234 .atomic_update = sti_cursor_atomic_update, 335 .atomic_update = sti_cursor_atomic_update,
235 .atomic_disable = sti_cursor_atomic_disable, 336 .atomic_disable = sti_cursor_atomic_disable,
236}; 337};
@@ -283,6 +384,9 @@ struct drm_plane *sti_cursor_create(struct drm_device *drm_dev,
283 384
284 sti_plane_init_property(&cursor->plane, DRM_PLANE_TYPE_CURSOR); 385 sti_plane_init_property(&cursor->plane, DRM_PLANE_TYPE_CURSOR);
285 386
387 if (cursor_debugfs_init(cursor, drm_dev->primary))
388 DRM_ERROR("CURSOR debugfs setup failed\n");
389
286 return &cursor->plane.drm_plane; 390 return &cursor->plane.drm_plane;
287 391
288err_plane: 392err_plane:
diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c
index 506b5626f3ed..6bd6abaa5a70 100644
--- a/drivers/gpu/drm/sti/sti_drv.c
+++ b/drivers/gpu/drm/sti/sti_drv.c
@@ -20,6 +20,7 @@
20 20
21#include "sti_crtc.h" 21#include "sti_crtc.h"
22#include "sti_drv.h" 22#include "sti_drv.h"
23#include "sti_plane.h"
23 24
24#define DRIVER_NAME "sti" 25#define DRIVER_NAME "sti"
25#define DRIVER_DESC "STMicroelectronics SoC DRM" 26#define DRIVER_DESC "STMicroelectronics SoC DRM"
@@ -30,6 +31,130 @@
30#define STI_MAX_FB_HEIGHT 4096 31#define STI_MAX_FB_HEIGHT 4096
31#define STI_MAX_FB_WIDTH 4096 32#define STI_MAX_FB_WIDTH 4096
32 33
34static int sti_drm_fps_get(void *data, u64 *val)
35{
36 struct drm_device *drm_dev = data;
37 struct drm_plane *p;
38 unsigned int i = 0;
39
40 *val = 0;
41 list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) {
42 struct sti_plane *plane = to_sti_plane(p);
43
44 *val |= plane->fps_info.output << i;
45 i++;
46 }
47
48 return 0;
49}
50
51static int sti_drm_fps_set(void *data, u64 val)
52{
53 struct drm_device *drm_dev = data;
54 struct drm_plane *p;
55 unsigned int i = 0;
56
57 list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) {
58 struct sti_plane *plane = to_sti_plane(p);
59
60 plane->fps_info.output = (val >> i) & 1;
61 i++;
62 }
63
64 return 0;
65}
66
67DEFINE_SIMPLE_ATTRIBUTE(sti_drm_fps_fops,
68 sti_drm_fps_get, sti_drm_fps_set, "%llu\n");
69
70static int sti_drm_fps_dbg_show(struct seq_file *s, void *data)
71{
72 struct drm_info_node *node = s->private;
73 struct drm_device *dev = node->minor->dev;
74 struct drm_plane *p;
75 int ret;
76
77 ret = mutex_lock_interruptible(&dev->struct_mutex);
78 if (ret)
79 return ret;
80
81 list_for_each_entry(p, &dev->mode_config.plane_list, head) {
82 struct sti_plane *plane = to_sti_plane(p);
83
84 seq_printf(s, "%s%s\n",
85 plane->fps_info.fps_str,
86 plane->fps_info.fips_str);
87 }
88
89 mutex_unlock(&dev->struct_mutex);
90 return 0;
91}
92
93static struct drm_info_list sti_drm_dbg_list[] = {
94 {"fps_get", sti_drm_fps_dbg_show, 0},
95};
96
97static int sti_drm_debugfs_create(struct dentry *root,
98 struct drm_minor *minor,
99 const char *name,
100 const struct file_operations *fops)
101{
102 struct drm_device *dev = minor->dev;
103 struct drm_info_node *node;
104 struct dentry *ent;
105
106 ent = debugfs_create_file(name, S_IRUGO | S_IWUSR, root, dev, fops);
107 if (IS_ERR(ent))
108 return PTR_ERR(ent);
109
110 node = kmalloc(sizeof(*node), GFP_KERNEL);
111 if (!node) {
112 debugfs_remove(ent);
113 return -ENOMEM;
114 }
115
116 node->minor = minor;
117 node->dent = ent;
118 node->info_ent = (void *)fops;
119
120 mutex_lock(&minor->debugfs_lock);
121 list_add(&node->list, &minor->debugfs_list);
122 mutex_unlock(&minor->debugfs_lock);
123
124 return 0;
125}
126
127static int sti_drm_dbg_init(struct drm_minor *minor)
128{
129 int ret;
130
131 ret = drm_debugfs_create_files(sti_drm_dbg_list,
132 ARRAY_SIZE(sti_drm_dbg_list),
133 minor->debugfs_root, minor);
134 if (ret)
135 goto err;
136
137 ret = sti_drm_debugfs_create(minor->debugfs_root, minor, "fps_show",
138 &sti_drm_fps_fops);
139 if (ret)
140 goto err;
141
142 DRM_INFO("%s: debugfs installed\n", DRIVER_NAME);
143 return 0;
144err:
145 DRM_ERROR("%s: cannot install debugfs\n", DRIVER_NAME);
146 return ret;
147}
148
149void sti_drm_dbg_cleanup(struct drm_minor *minor)
150{
151 drm_debugfs_remove_files(sti_drm_dbg_list,
152 ARRAY_SIZE(sti_drm_dbg_list), minor);
153
154 drm_debugfs_remove_files((struct drm_info_list *)&sti_drm_fps_fops,
155 1, minor);
156}
157
33static void sti_atomic_schedule(struct sti_private *private, 158static void sti_atomic_schedule(struct sti_private *private,
34 struct drm_atomic_state *state) 159 struct drm_atomic_state *state)
35{ 160{
@@ -181,18 +306,9 @@ static const struct file_operations sti_driver_fops = {
181 .release = drm_release, 306 .release = drm_release,
182}; 307};
183 308
184static struct dma_buf *sti_gem_prime_export(struct drm_device *dev,
185 struct drm_gem_object *obj,
186 int flags)
187{
188 /* we want to be able to write in mmapped buffer */
189 flags |= O_RDWR;
190 return drm_gem_prime_export(dev, obj, flags);
191}
192
193static struct drm_driver sti_driver = { 309static struct drm_driver sti_driver = {
194 .driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET | 310 .driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET |
195 DRIVER_GEM | DRIVER_PRIME, 311 DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC,
196 .load = sti_load, 312 .load = sti_load,
197 .gem_free_object = drm_gem_cma_free_object, 313 .gem_free_object = drm_gem_cma_free_object,
198 .gem_vm_ops = &drm_gem_cma_vm_ops, 314 .gem_vm_ops = &drm_gem_cma_vm_ops,
@@ -207,7 +323,7 @@ static struct drm_driver sti_driver = {
207 323
208 .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 324 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
209 .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 325 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
210 .gem_prime_export = sti_gem_prime_export, 326 .gem_prime_export = drm_gem_prime_export,
211 .gem_prime_import = drm_gem_prime_import, 327 .gem_prime_import = drm_gem_prime_import,
212 .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, 328 .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
213 .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, 329 .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
@@ -215,6 +331,9 @@ static struct drm_driver sti_driver = {
215 .gem_prime_vunmap = drm_gem_cma_prime_vunmap, 331 .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
216 .gem_prime_mmap = drm_gem_cma_prime_mmap, 332 .gem_prime_mmap = drm_gem_cma_prime_mmap,
217 333
334 .debugfs_init = sti_drm_dbg_init,
335 .debugfs_cleanup = sti_drm_dbg_cleanup,
336
218 .name = DRIVER_NAME, 337 .name = DRIVER_NAME,
219 .desc = DRIVER_DESC, 338 .desc = DRIVER_DESC,
220 .date = DRIVER_DATE, 339 .date = DRIVER_DATE,
diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c
index 45cbe2bf7dd6..25f76632002c 100644
--- a/drivers/gpu/drm/sti/sti_dvo.c
+++ b/drivers/gpu/drm/sti/sti_dvo.c
@@ -6,6 +6,7 @@
6 6
7#include <linux/clk.h> 7#include <linux/clk.h>
8#include <linux/component.h> 8#include <linux/component.h>
9#include <linux/debugfs.h>
9#include <linux/module.h> 10#include <linux/module.h>
10#include <linux/of_gpio.h> 11#include <linux/of_gpio.h>
11#include <linux/platform_device.h> 12#include <linux/platform_device.h>
@@ -156,6 +157,69 @@ static void dvo_awg_configure(struct sti_dvo *dvo, u32 *awg_ram_code, int nb)
156 writel(DVO_AWG_CTRL_EN, dvo->regs + DVO_AWG_DIGSYNC_CTRL); 157 writel(DVO_AWG_CTRL_EN, dvo->regs + DVO_AWG_DIGSYNC_CTRL);
157} 158}
158 159
160#define DBGFS_DUMP(reg) seq_printf(s, "\n %-25s 0x%08X", #reg, \
161 readl(dvo->regs + reg))
162
163static void dvo_dbg_awg_microcode(struct seq_file *s, void __iomem *reg)
164{
165 unsigned int i;
166
167 seq_puts(s, "\n\n");
168 seq_puts(s, " DVO AWG microcode:");
169 for (i = 0; i < AWG_MAX_INST; i++) {
170 if (i % 8 == 0)
171 seq_printf(s, "\n %04X:", i);
172 seq_printf(s, " %04X", readl(reg + i * 4));
173 }
174}
175
176static int dvo_dbg_show(struct seq_file *s, void *data)
177{
178 struct drm_info_node *node = s->private;
179 struct sti_dvo *dvo = (struct sti_dvo *)node->info_ent->data;
180 struct drm_device *dev = node->minor->dev;
181 int ret;
182
183 ret = mutex_lock_interruptible(&dev->struct_mutex);
184 if (ret)
185 return ret;
186
187 seq_printf(s, "DVO: (vaddr = 0x%p)", dvo->regs);
188 DBGFS_DUMP(DVO_AWG_DIGSYNC_CTRL);
189 DBGFS_DUMP(DVO_DOF_CFG);
190 DBGFS_DUMP(DVO_LUT_PROG_LOW);
191 DBGFS_DUMP(DVO_LUT_PROG_MID);
192 DBGFS_DUMP(DVO_LUT_PROG_HIGH);
193 dvo_dbg_awg_microcode(s, dvo->regs + DVO_DIGSYNC_INSTR_I);
194 seq_puts(s, "\n");
195
196 mutex_unlock(&dev->struct_mutex);
197 return 0;
198}
199
200static struct drm_info_list dvo_debugfs_files[] = {
201 { "dvo", dvo_dbg_show, 0, NULL },
202};
203
204static void dvo_debugfs_exit(struct sti_dvo *dvo, struct drm_minor *minor)
205{
206 drm_debugfs_remove_files(dvo_debugfs_files,
207 ARRAY_SIZE(dvo_debugfs_files),
208 minor);
209}
210
211static int dvo_debugfs_init(struct sti_dvo *dvo, struct drm_minor *minor)
212{
213 unsigned int i;
214
215 for (i = 0; i < ARRAY_SIZE(dvo_debugfs_files); i++)
216 dvo_debugfs_files[i].data = dvo;
217
218 return drm_debugfs_create_files(dvo_debugfs_files,
219 ARRAY_SIZE(dvo_debugfs_files),
220 minor->debugfs_root, minor);
221}
222
159static void sti_dvo_disable(struct drm_bridge *bridge) 223static void sti_dvo_disable(struct drm_bridge *bridge)
160{ 224{
161 struct sti_dvo *dvo = bridge->driver_private; 225 struct sti_dvo *dvo = bridge->driver_private;
@@ -345,12 +409,14 @@ sti_dvo_connector_detect(struct drm_connector *connector, bool force)
345 409
346 DRM_DEBUG_DRIVER("\n"); 410 DRM_DEBUG_DRIVER("\n");
347 411
348 if (!dvo->panel) 412 if (!dvo->panel) {
349 dvo->panel = of_drm_find_panel(dvo->panel_node); 413 dvo->panel = of_drm_find_panel(dvo->panel_node);
414 if (dvo->panel)
415 drm_panel_attach(dvo->panel, connector);
416 }
350 417
351 if (dvo->panel) 418 if (dvo->panel)
352 if (!drm_panel_attach(dvo->panel, connector)) 419 return connector_status_connected;
353 return connector_status_connected;
354 420
355 return connector_status_disconnected; 421 return connector_status_disconnected;
356} 422}
@@ -453,6 +519,9 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data)
453 goto err_sysfs; 519 goto err_sysfs;
454 } 520 }
455 521
522 if (dvo_debugfs_init(dvo, drm_dev->primary))
523 DRM_ERROR("DVO debugfs setup failed\n");
524
456 return 0; 525 return 0;
457 526
458err_sysfs: 527err_sysfs:
@@ -467,6 +536,9 @@ static void sti_dvo_unbind(struct device *dev,
467 struct device *master, void *data) 536 struct device *master, void *data)
468{ 537{
469 struct sti_dvo *dvo = dev_get_drvdata(dev); 538 struct sti_dvo *dvo = dev_get_drvdata(dev);
539 struct drm_device *drm_dev = data;
540
541 dvo_debugfs_exit(dvo, drm_dev->primary);
470 542
471 drm_bridge_remove(dvo->bridge); 543 drm_bridge_remove(dvo->bridge);
472} 544}
diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c
index f9a1d92c9d95..67f606a41c3f 100644
--- a/drivers/gpu/drm/sti/sti_gdp.c
+++ b/drivers/gpu/drm/sti/sti_gdp.c
@@ -6,9 +6,7 @@
6 * License terms: GNU General Public License (GPL), version 2 6 * License terms: GNU General Public License (GPL), version 2
7 */ 7 */
8 8
9#include <linux/clk.h> 9#include <drm/drm_atomic.h>
10#include <linux/dma-mapping.h>
11
12#include <drm/drm_fb_cma_helper.h> 10#include <drm/drm_fb_cma_helper.h>
13#include <drm/drm_gem_cma_helper.h> 11#include <drm/drm_gem_cma_helper.h>
14 12
@@ -32,10 +30,23 @@
32#define GDP_ABGR8888 (GDP_ARGB8888 | BIGNOTLITTLE | ALPHASWITCH) 30#define GDP_ABGR8888 (GDP_ARGB8888 | BIGNOTLITTLE | ALPHASWITCH)
33#define GDP_ARGB1555 0x06 31#define GDP_ARGB1555 0x06
34#define GDP_ARGB4444 0x07 32#define GDP_ARGB4444 0x07
35#define GDP_CLUT8 0x0B 33
36#define GDP_YCBR888 0x10 34#define GDP2STR(fmt) { GDP_ ## fmt, #fmt }
37#define GDP_YCBR422R 0x12 35
38#define GDP_AYCBR8888 0x15 36static struct gdp_format_to_str {
37 int format;
38 char name[20];
39} gdp_format_to_str[] = {
40 GDP2STR(RGB565),
41 GDP2STR(RGB888),
42 GDP2STR(RGB888_32),
43 GDP2STR(XBGR8888),
44 GDP2STR(ARGB8565),
45 GDP2STR(ARGB8888),
46 GDP2STR(ABGR8888),
47 GDP2STR(ARGB1555),
48 GDP2STR(ARGB4444)
49 };
39 50
40#define GAM_GDP_CTL_OFFSET 0x00 51#define GAM_GDP_CTL_OFFSET 0x00
41#define GAM_GDP_AGC_OFFSET 0x04 52#define GAM_GDP_AGC_OFFSET 0x04
@@ -97,6 +108,7 @@ struct sti_gdp_node_list {
97 * @vtg_field_nb: callback for VTG FIELD (top or bottom) notification 108 * @vtg_field_nb: callback for VTG FIELD (top or bottom) notification
98 * @is_curr_top: true if the current node processed is the top field 109 * @is_curr_top: true if the current node processed is the top field
99 * @node_list: array of node list 110 * @node_list: array of node list
111 * @vtg: registered vtg
100 */ 112 */
101struct sti_gdp { 113struct sti_gdp {
102 struct sti_plane plane; 114 struct sti_plane plane;
@@ -108,6 +120,7 @@ struct sti_gdp {
108 struct notifier_block vtg_field_nb; 120 struct notifier_block vtg_field_nb;
109 bool is_curr_top; 121 bool is_curr_top;
110 struct sti_gdp_node_list node_list[GDP_NODE_NB_BANK]; 122 struct sti_gdp_node_list node_list[GDP_NODE_NB_BANK];
123 struct sti_vtg *vtg;
111}; 124};
112 125
113#define to_sti_gdp(x) container_of(x, struct sti_gdp, plane) 126#define to_sti_gdp(x) container_of(x, struct sti_gdp, plane)
@@ -121,12 +134,224 @@ static const uint32_t gdp_supported_formats[] = {
121 DRM_FORMAT_ARGB1555, 134 DRM_FORMAT_ARGB1555,
122 DRM_FORMAT_RGB565, 135 DRM_FORMAT_RGB565,
123 DRM_FORMAT_RGB888, 136 DRM_FORMAT_RGB888,
124 DRM_FORMAT_AYUV,
125 DRM_FORMAT_YUV444,
126 DRM_FORMAT_VYUY,
127 DRM_FORMAT_C8,
128}; 137};
129 138
139#define DBGFS_DUMP(reg) seq_printf(s, "\n %-25s 0x%08X", #reg, \
140 readl(gdp->regs + reg ## _OFFSET))
141
142static void gdp_dbg_ctl(struct seq_file *s, int val)
143{
144 int i;
145
146 seq_puts(s, "\tColor:");
147 for (i = 0; i < ARRAY_SIZE(gdp_format_to_str); i++) {
148 if (gdp_format_to_str[i].format == (val & 0x1F)) {
149 seq_printf(s, gdp_format_to_str[i].name);
150 break;
151 }
152 }
153 if (i == ARRAY_SIZE(gdp_format_to_str))
154 seq_puts(s, "<UNKNOWN>");
155
156 seq_printf(s, "\tWaitNextVsync:%d", val & WAIT_NEXT_VSYNC ? 1 : 0);
157}
158
159static void gdp_dbg_vpo(struct seq_file *s, int val)
160{
161 seq_printf(s, "\txdo:%4d\tydo:%4d", val & 0xFFFF, (val >> 16) & 0xFFFF);
162}
163
164static void gdp_dbg_vps(struct seq_file *s, int val)
165{
166 seq_printf(s, "\txds:%4d\tyds:%4d", val & 0xFFFF, (val >> 16) & 0xFFFF);
167}
168
169static void gdp_dbg_size(struct seq_file *s, int val)
170{
171 seq_printf(s, "\t%d x %d", val & 0xFFFF, (val >> 16) & 0xFFFF);
172}
173
174static void gdp_dbg_nvn(struct seq_file *s, struct sti_gdp *gdp, int val)
175{
176 void *base = NULL;
177 unsigned int i;
178
179 for (i = 0; i < GDP_NODE_NB_BANK; i++) {
180 if (gdp->node_list[i].top_field_paddr == val) {
181 base = gdp->node_list[i].top_field;
182 break;
183 }
184 if (gdp->node_list[i].btm_field_paddr == val) {
185 base = gdp->node_list[i].btm_field;
186 break;
187 }
188 }
189
190 if (base)
191 seq_printf(s, "\tVirt @: %p", base);
192}
193
194static void gdp_dbg_ppt(struct seq_file *s, int val)
195{
196 if (val & GAM_GDP_PPT_IGNORE)
197 seq_puts(s, "\tNot displayed on mixer!");
198}
199
200static void gdp_dbg_mst(struct seq_file *s, int val)
201{
202 if (val & 1)
203 seq_puts(s, "\tBUFFER UNDERFLOW!");
204}
205
206static int gdp_dbg_show(struct seq_file *s, void *data)
207{
208 struct drm_info_node *node = s->private;
209 struct sti_gdp *gdp = (struct sti_gdp *)node->info_ent->data;
210 struct drm_device *dev = node->minor->dev;
211 struct drm_plane *drm_plane = &gdp->plane.drm_plane;
212 struct drm_crtc *crtc = drm_plane->crtc;
213 int ret;
214
215 ret = mutex_lock_interruptible(&dev->struct_mutex);
216 if (ret)
217 return ret;
218
219 seq_printf(s, "%s: (vaddr = 0x%p)",
220 sti_plane_to_str(&gdp->plane), gdp->regs);
221
222 DBGFS_DUMP(GAM_GDP_CTL);
223 gdp_dbg_ctl(s, readl(gdp->regs + GAM_GDP_CTL_OFFSET));
224 DBGFS_DUMP(GAM_GDP_AGC);
225 DBGFS_DUMP(GAM_GDP_VPO);
226 gdp_dbg_vpo(s, readl(gdp->regs + GAM_GDP_VPO_OFFSET));
227 DBGFS_DUMP(GAM_GDP_VPS);
228 gdp_dbg_vps(s, readl(gdp->regs + GAM_GDP_VPS_OFFSET));
229 DBGFS_DUMP(GAM_GDP_PML);
230 DBGFS_DUMP(GAM_GDP_PMP);
231 DBGFS_DUMP(GAM_GDP_SIZE);
232 gdp_dbg_size(s, readl(gdp->regs + GAM_GDP_SIZE_OFFSET));
233 DBGFS_DUMP(GAM_GDP_NVN);
234 gdp_dbg_nvn(s, gdp, readl(gdp->regs + GAM_GDP_NVN_OFFSET));
235 DBGFS_DUMP(GAM_GDP_KEY1);
236 DBGFS_DUMP(GAM_GDP_KEY2);
237 DBGFS_DUMP(GAM_GDP_PPT);
238 gdp_dbg_ppt(s, readl(gdp->regs + GAM_GDP_PPT_OFFSET));
239 DBGFS_DUMP(GAM_GDP_CML);
240 DBGFS_DUMP(GAM_GDP_MST);
241 gdp_dbg_mst(s, readl(gdp->regs + GAM_GDP_MST_OFFSET));
242
243 seq_puts(s, "\n\n");
244 if (!crtc)
245 seq_puts(s, " Not connected to any DRM CRTC\n");
246 else
247 seq_printf(s, " Connected to DRM CRTC #%d (%s)\n",
248 crtc->base.id, sti_mixer_to_str(to_sti_mixer(crtc)));
249
250 mutex_unlock(&dev->struct_mutex);
251 return 0;
252}
253
254static void gdp_node_dump_node(struct seq_file *s, struct sti_gdp_node *node)
255{
256 seq_printf(s, "\t@:0x%p", node);
257 seq_printf(s, "\n\tCTL 0x%08X", node->gam_gdp_ctl);
258 gdp_dbg_ctl(s, node->gam_gdp_ctl);
259 seq_printf(s, "\n\tAGC 0x%08X", node->gam_gdp_agc);
260 seq_printf(s, "\n\tVPO 0x%08X", node->gam_gdp_vpo);
261 gdp_dbg_vpo(s, node->gam_gdp_vpo);
262 seq_printf(s, "\n\tVPS 0x%08X", node->gam_gdp_vps);
263 gdp_dbg_vps(s, node->gam_gdp_vps);
264 seq_printf(s, "\n\tPML 0x%08X", node->gam_gdp_pml);
265 seq_printf(s, "\n\tPMP 0x%08X", node->gam_gdp_pmp);
266 seq_printf(s, "\n\tSIZE 0x%08X", node->gam_gdp_size);
267 gdp_dbg_size(s, node->gam_gdp_size);
268 seq_printf(s, "\n\tNVN 0x%08X", node->gam_gdp_nvn);
269 seq_printf(s, "\n\tKEY1 0x%08X", node->gam_gdp_key1);
270 seq_printf(s, "\n\tKEY2 0x%08X", node->gam_gdp_key2);
271 seq_printf(s, "\n\tPPT 0x%08X", node->gam_gdp_ppt);
272 gdp_dbg_ppt(s, node->gam_gdp_ppt);
273 seq_printf(s, "\n\tCML 0x%08X", node->gam_gdp_cml);
274 seq_puts(s, "\n");
275}
276
277static int gdp_node_dbg_show(struct seq_file *s, void *arg)
278{
279 struct drm_info_node *node = s->private;
280 struct sti_gdp *gdp = (struct sti_gdp *)node->info_ent->data;
281 struct drm_device *dev = node->minor->dev;
282 unsigned int b;
283 int ret;
284
285 ret = mutex_lock_interruptible(&dev->struct_mutex);
286 if (ret)
287 return ret;
288
289 for (b = 0; b < GDP_NODE_NB_BANK; b++) {
290 seq_printf(s, "\n%s[%d].top", sti_plane_to_str(&gdp->plane), b);
291 gdp_node_dump_node(s, gdp->node_list[b].top_field);
292 seq_printf(s, "\n%s[%d].btm", sti_plane_to_str(&gdp->plane), b);
293 gdp_node_dump_node(s, gdp->node_list[b].btm_field);
294 }
295
296 mutex_unlock(&dev->struct_mutex);
297 return 0;
298}
299
300static struct drm_info_list gdp0_debugfs_files[] = {
301 { "gdp0", gdp_dbg_show, 0, NULL },
302 { "gdp0_node", gdp_node_dbg_show, 0, NULL },
303};
304
305static struct drm_info_list gdp1_debugfs_files[] = {
306 { "gdp1", gdp_dbg_show, 0, NULL },
307 { "gdp1_node", gdp_node_dbg_show, 0, NULL },
308};
309
310static struct drm_info_list gdp2_debugfs_files[] = {
311 { "gdp2", gdp_dbg_show, 0, NULL },
312 { "gdp2_node", gdp_node_dbg_show, 0, NULL },
313};
314
315static struct drm_info_list gdp3_debugfs_files[] = {
316 { "gdp3", gdp_dbg_show, 0, NULL },
317 { "gdp3_node", gdp_node_dbg_show, 0, NULL },
318};
319
320static int gdp_debugfs_init(struct sti_gdp *gdp, struct drm_minor *minor)
321{
322 unsigned int i;
323 struct drm_info_list *gdp_debugfs_files;
324 int nb_files;
325
326 switch (gdp->plane.desc) {
327 case STI_GDP_0:
328 gdp_debugfs_files = gdp0_debugfs_files;
329 nb_files = ARRAY_SIZE(gdp0_debugfs_files);
330 break;
331 case STI_GDP_1:
332 gdp_debugfs_files = gdp1_debugfs_files;
333 nb_files = ARRAY_SIZE(gdp1_debugfs_files);
334 break;
335 case STI_GDP_2:
336 gdp_debugfs_files = gdp2_debugfs_files;
337 nb_files = ARRAY_SIZE(gdp2_debugfs_files);
338 break;
339 case STI_GDP_3:
340 gdp_debugfs_files = gdp3_debugfs_files;
341 nb_files = ARRAY_SIZE(gdp3_debugfs_files);
342 break;
343 default:
344 return -EINVAL;
345 }
346
347 for (i = 0; i < nb_files; i++)
348 gdp_debugfs_files[i].data = gdp;
349
350 return drm_debugfs_create_files(gdp_debugfs_files,
351 nb_files,
352 minor->debugfs_root, minor);
353}
354
130static int sti_gdp_fourcc2format(int fourcc) 355static int sti_gdp_fourcc2format(int fourcc)
131{ 356{
132 switch (fourcc) { 357 switch (fourcc) {
@@ -146,14 +371,6 @@ static int sti_gdp_fourcc2format(int fourcc)
146 return GDP_RGB565; 371 return GDP_RGB565;
147 case DRM_FORMAT_RGB888: 372 case DRM_FORMAT_RGB888:
148 return GDP_RGB888; 373 return GDP_RGB888;
149 case DRM_FORMAT_AYUV:
150 return GDP_AYCBR8888;
151 case DRM_FORMAT_YUV444:
152 return GDP_YCBR888;
153 case DRM_FORMAT_VYUY:
154 return GDP_YCBR422R;
155 case DRM_FORMAT_C8:
156 return GDP_CLUT8;
157 } 374 }
158 return -1; 375 return -1;
159} 376}
@@ -163,7 +380,6 @@ static int sti_gdp_get_alpharange(int format)
163 switch (format) { 380 switch (format) {
164 case GDP_ARGB8565: 381 case GDP_ARGB8565:
165 case GDP_ARGB8888: 382 case GDP_ARGB8888:
166 case GDP_AYCBR8888:
167 case GDP_ABGR8888: 383 case GDP_ABGR8888:
168 return GAM_GDP_ALPHARANGE_255; 384 return GAM_GDP_ALPHARANGE_255;
169 } 385 }
@@ -240,9 +456,6 @@ end:
240 */ 456 */
241static void sti_gdp_disable(struct sti_gdp *gdp) 457static void sti_gdp_disable(struct sti_gdp *gdp)
242{ 458{
243 struct drm_plane *drm_plane = &gdp->plane.drm_plane;
244 struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
245 struct sti_compositor *compo = dev_get_drvdata(gdp->dev);
246 unsigned int i; 459 unsigned int i;
247 460
248 DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(&gdp->plane)); 461 DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(&gdp->plane));
@@ -253,8 +466,7 @@ static void sti_gdp_disable(struct sti_gdp *gdp)
253 gdp->node_list[i].btm_field->gam_gdp_ppt |= GAM_GDP_PPT_IGNORE; 466 gdp->node_list[i].btm_field->gam_gdp_ppt |= GAM_GDP_PPT_IGNORE;
254 } 467 }
255 468
256 if (sti_vtg_unregister_client(mixer->id == STI_MIXER_MAIN ? 469 if (sti_vtg_unregister_client(gdp->vtg, &gdp->vtg_field_nb))
257 compo->vtg_main : compo->vtg_aux, &gdp->vtg_field_nb))
258 DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n"); 470 DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n");
259 471
260 if (gdp->clk_pix) 472 if (gdp->clk_pix)
@@ -380,20 +592,140 @@ static void sti_gdp_init(struct sti_gdp *gdp)
380 } 592 }
381} 593}
382 594
383static void sti_gdp_atomic_update(struct drm_plane *drm_plane, 595/**
384 struct drm_plane_state *oldstate) 596 * sti_gdp_get_dst
597 * @dev: device
598 * @dst: requested destination size
599 * @src: source size
600 *
601 * Return the cropped / clamped destination size
602 *
603 * RETURNS:
604 * cropped / clamped destination size
605 */
606static int sti_gdp_get_dst(struct device *dev, int dst, int src)
607{
608 if (dst == src)
609 return dst;
610
611 if (dst < src) {
612 dev_dbg(dev, "WARNING: GDP scale not supported, will crop\n");
613 return dst;
614 }
615
616 dev_dbg(dev, "WARNING: GDP scale not supported, will clamp\n");
617 return src;
618}
619
620static int sti_gdp_atomic_check(struct drm_plane *drm_plane,
621 struct drm_plane_state *state)
385{ 622{
386 struct drm_plane_state *state = drm_plane->state;
387 struct sti_plane *plane = to_sti_plane(drm_plane); 623 struct sti_plane *plane = to_sti_plane(drm_plane);
388 struct sti_gdp *gdp = to_sti_gdp(plane); 624 struct sti_gdp *gdp = to_sti_gdp(plane);
389 struct drm_crtc *crtc = state->crtc; 625 struct drm_crtc *crtc = state->crtc;
390 struct sti_compositor *compo = dev_get_drvdata(gdp->dev); 626 struct sti_compositor *compo = dev_get_drvdata(gdp->dev);
391 struct drm_framebuffer *fb = state->fb; 627 struct drm_framebuffer *fb = state->fb;
392 bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false; 628 bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false;
629 struct drm_crtc_state *crtc_state;
393 struct sti_mixer *mixer; 630 struct sti_mixer *mixer;
394 struct drm_display_mode *mode; 631 struct drm_display_mode *mode;
395 int dst_x, dst_y, dst_w, dst_h; 632 int dst_x, dst_y, dst_w, dst_h;
396 int src_x, src_y, src_w, src_h; 633 int src_x, src_y, src_w, src_h;
634 int format;
635
636 /* no need for further checks if the plane is being disabled */
637 if (!crtc || !fb)
638 return 0;
639
640 mixer = to_sti_mixer(crtc);
641 crtc_state = drm_atomic_get_crtc_state(state->state, crtc);
642 mode = &crtc_state->mode;
643 dst_x = state->crtc_x;
644 dst_y = state->crtc_y;
645 dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
646 dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
647 /* src_x are in 16.16 format */
648 src_x = state->src_x >> 16;
649 src_y = state->src_y >> 16;
650 src_w = clamp_val(state->src_w >> 16, 0, GAM_GDP_SIZE_MAX);
651 src_h = clamp_val(state->src_h >> 16, 0, GAM_GDP_SIZE_MAX);
652
653 format = sti_gdp_fourcc2format(fb->pixel_format);
654 if (format == -1) {
655 DRM_ERROR("Format not supported by GDP %.4s\n",
656 (char *)&fb->pixel_format);
657 return -EINVAL;
658 }
659
660 if (!drm_fb_cma_get_gem_obj(fb, 0)) {
661 DRM_ERROR("Can't get CMA GEM object for fb\n");
662 return -EINVAL;
663 }
664
665 if (first_prepare) {
666 /* Register gdp callback */
667 gdp->vtg = mixer->id == STI_MIXER_MAIN ?
668 compo->vtg_main : compo->vtg_aux;
669 if (sti_vtg_register_client(gdp->vtg,
670 &gdp->vtg_field_nb, crtc)) {
671 DRM_ERROR("Cannot register VTG notifier\n");
672 return -EINVAL;
673 }
674
675 /* Set and enable gdp clock */
676 if (gdp->clk_pix) {
677 struct clk *clkp;
678 int rate = mode->clock * 1000;
679 int res;
680
681 /*
682 * According to the mixer used, the gdp pixel clock
683 * should have a different parent clock.
684 */
685 if (mixer->id == STI_MIXER_MAIN)
686 clkp = gdp->clk_main_parent;
687 else
688 clkp = gdp->clk_aux_parent;
689
690 if (clkp)
691 clk_set_parent(gdp->clk_pix, clkp);
692
693 res = clk_set_rate(gdp->clk_pix, rate);
694 if (res < 0) {
695 DRM_ERROR("Cannot set rate (%dHz) for gdp\n",
696 rate);
697 return -EINVAL;
698 }
699
700 if (clk_prepare_enable(gdp->clk_pix)) {
701 DRM_ERROR("Failed to prepare/enable gdp\n");
702 return -EINVAL;
703 }
704 }
705 }
706
707 DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n",
708 crtc->base.id, sti_mixer_to_str(mixer),
709 drm_plane->base.id, sti_plane_to_str(plane));
710 DRM_DEBUG_KMS("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n",
711 sti_plane_to_str(plane),
712 dst_w, dst_h, dst_x, dst_y,
713 src_w, src_h, src_x, src_y);
714
715 return 0;
716}
717
718static void sti_gdp_atomic_update(struct drm_plane *drm_plane,
719 struct drm_plane_state *oldstate)
720{
721 struct drm_plane_state *state = drm_plane->state;
722 struct sti_plane *plane = to_sti_plane(drm_plane);
723 struct sti_gdp *gdp = to_sti_gdp(plane);
724 struct drm_crtc *crtc = state->crtc;
725 struct drm_framebuffer *fb = state->fb;
726 struct drm_display_mode *mode;
727 int dst_x, dst_y, dst_w, dst_h;
728 int src_x, src_y, src_w, src_h;
397 struct drm_gem_cma_object *cma_obj; 729 struct drm_gem_cma_object *cma_obj;
398 struct sti_gdp_node_list *list; 730 struct sti_gdp_node_list *list;
399 struct sti_gdp_node_list *curr_list; 731 struct sti_gdp_node_list *curr_list;
@@ -403,13 +735,10 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane,
403 int format; 735 int format;
404 unsigned int depth, bpp; 736 unsigned int depth, bpp;
405 u32 ydo, xdo, yds, xds; 737 u32 ydo, xdo, yds, xds;
406 int res;
407 738
408 /* Manage the case where crtc is null (disabled) */ 739 if (!crtc || !fb)
409 if (!crtc)
410 return; 740 return;
411 741
412 mixer = to_sti_mixer(crtc);
413 mode = &crtc->mode; 742 mode = &crtc->mode;
414 dst_x = state->crtc_x; 743 dst_x = state->crtc_x;
415 dst_y = state->crtc_y; 744 dst_y = state->crtc_y;
@@ -418,16 +747,8 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane,
418 /* src_x are in 16.16 format */ 747 /* src_x are in 16.16 format */
419 src_x = state->src_x >> 16; 748 src_x = state->src_x >> 16;
420 src_y = state->src_y >> 16; 749 src_y = state->src_y >> 16;
421 src_w = state->src_w >> 16; 750 src_w = clamp_val(state->src_w >> 16, 0, GAM_GDP_SIZE_MAX);
422 src_h = state->src_h >> 16; 751 src_h = clamp_val(state->src_h >> 16, 0, GAM_GDP_SIZE_MAX);
423
424 DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n",
425 crtc->base.id, sti_mixer_to_str(mixer),
426 drm_plane->base.id, sti_plane_to_str(plane));
427 DRM_DEBUG_KMS("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n",
428 sti_plane_to_str(plane),
429 dst_w, dst_h, dst_x, dst_y,
430 src_w, src_h, src_x, src_y);
431 752
432 list = sti_gdp_get_free_nodes(gdp); 753 list = sti_gdp_get_free_nodes(gdp);
433 top_field = list->top_field; 754 top_field = list->top_field;
@@ -440,20 +761,11 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane,
440 top_field->gam_gdp_agc = GAM_GDP_AGC_FULL_RANGE; 761 top_field->gam_gdp_agc = GAM_GDP_AGC_FULL_RANGE;
441 top_field->gam_gdp_ctl = WAIT_NEXT_VSYNC; 762 top_field->gam_gdp_ctl = WAIT_NEXT_VSYNC;
442 format = sti_gdp_fourcc2format(fb->pixel_format); 763 format = sti_gdp_fourcc2format(fb->pixel_format);
443 if (format == -1) {
444 DRM_ERROR("Format not supported by GDP %.4s\n",
445 (char *)&fb->pixel_format);
446 return;
447 }
448 top_field->gam_gdp_ctl |= format; 764 top_field->gam_gdp_ctl |= format;
449 top_field->gam_gdp_ctl |= sti_gdp_get_alpharange(format); 765 top_field->gam_gdp_ctl |= sti_gdp_get_alpharange(format);
450 top_field->gam_gdp_ppt &= ~GAM_GDP_PPT_IGNORE; 766 top_field->gam_gdp_ppt &= ~GAM_GDP_PPT_IGNORE;
451 767
452 cma_obj = drm_fb_cma_get_gem_obj(fb, 0); 768 cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
453 if (!cma_obj) {
454 DRM_ERROR("Can't get CMA GEM object for fb\n");
455 return;
456 }
457 769
458 DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id, 770 DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id,
459 (char *)&fb->pixel_format, 771 (char *)&fb->pixel_format,
@@ -465,12 +777,9 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane,
465 top_field->gam_gdp_pml += src_x * (bpp >> 3); 777 top_field->gam_gdp_pml += src_x * (bpp >> 3);
466 top_field->gam_gdp_pml += src_y * fb->pitches[0]; 778 top_field->gam_gdp_pml += src_y * fb->pitches[0];
467 779
468 /* input parameters */ 780 /* output parameters (clamped / cropped) */
469 top_field->gam_gdp_pmp = fb->pitches[0]; 781 dst_w = sti_gdp_get_dst(gdp->dev, dst_w, src_w);
470 top_field->gam_gdp_size = clamp_val(src_h, 0, GAM_GDP_SIZE_MAX) << 16 | 782 dst_h = sti_gdp_get_dst(gdp->dev, dst_h, src_h);
471 clamp_val(src_w, 0, GAM_GDP_SIZE_MAX);
472
473 /* output parameters */
474 ydo = sti_vtg_get_line_number(*mode, dst_y); 783 ydo = sti_vtg_get_line_number(*mode, dst_y);
475 yds = sti_vtg_get_line_number(*mode, dst_y + dst_h - 1); 784 yds = sti_vtg_get_line_number(*mode, dst_y + dst_h - 1);
476 xdo = sti_vtg_get_pixel_number(*mode, dst_x); 785 xdo = sti_vtg_get_pixel_number(*mode, dst_x);
@@ -478,6 +787,11 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane,
478 top_field->gam_gdp_vpo = (ydo << 16) | xdo; 787 top_field->gam_gdp_vpo = (ydo << 16) | xdo;
479 top_field->gam_gdp_vps = (yds << 16) | xds; 788 top_field->gam_gdp_vps = (yds << 16) | xds;
480 789
790 /* input parameters */
791 src_w = dst_w;
792 top_field->gam_gdp_pmp = fb->pitches[0];
793 top_field->gam_gdp_size = src_h << 16 | src_w;
794
481 /* Same content and chained together */ 795 /* Same content and chained together */
482 memcpy(btm_field, top_field, sizeof(*btm_field)); 796 memcpy(btm_field, top_field, sizeof(*btm_field));
483 top_field->gam_gdp_nvn = list->btm_field_paddr; 797 top_field->gam_gdp_nvn = list->btm_field_paddr;
@@ -488,44 +802,6 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane,
488 btm_field->gam_gdp_pml = top_field->gam_gdp_pml + 802 btm_field->gam_gdp_pml = top_field->gam_gdp_pml +
489 fb->pitches[0]; 803 fb->pitches[0];
490 804
491 if (first_prepare) {
492 /* Register gdp callback */
493 if (sti_vtg_register_client(mixer->id == STI_MIXER_MAIN ?
494 compo->vtg_main : compo->vtg_aux,
495 &gdp->vtg_field_nb, crtc)) {
496 DRM_ERROR("Cannot register VTG notifier\n");
497 return;
498 }
499
500 /* Set and enable gdp clock */
501 if (gdp->clk_pix) {
502 struct clk *clkp;
503 int rate = mode->clock * 1000;
504
505 /* According to the mixer used, the gdp pixel clock
506 * should have a different parent clock. */
507 if (mixer->id == STI_MIXER_MAIN)
508 clkp = gdp->clk_main_parent;
509 else
510 clkp = gdp->clk_aux_parent;
511
512 if (clkp)
513 clk_set_parent(gdp->clk_pix, clkp);
514
515 res = clk_set_rate(gdp->clk_pix, rate);
516 if (res < 0) {
517 DRM_ERROR("Cannot set rate (%dHz) for gdp\n",
518 rate);
519 return;
520 }
521
522 if (clk_prepare_enable(gdp->clk_pix)) {
523 DRM_ERROR("Failed to prepare/enable gdp\n");
524 return;
525 }
526 }
527 }
528
529 /* Update the NVN field of the 'right' field of the current GDP node 805 /* Update the NVN field of the 'right' field of the current GDP node
530 * (being used by the HW) with the address of the updated ('free') top 806 * (being used by the HW) with the address of the updated ('free') top
531 * field GDP node. 807 * field GDP node.
@@ -574,6 +850,8 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane,
574 } 850 }
575 851
576end: 852end:
853 sti_plane_update_fps(plane, true, false);
854
577 plane->status = STI_PLANE_UPDATED; 855 plane->status = STI_PLANE_UPDATED;
578} 856}
579 857
@@ -581,7 +859,6 @@ static void sti_gdp_atomic_disable(struct drm_plane *drm_plane,
581 struct drm_plane_state *oldstate) 859 struct drm_plane_state *oldstate)
582{ 860{
583 struct sti_plane *plane = to_sti_plane(drm_plane); 861 struct sti_plane *plane = to_sti_plane(drm_plane);
584 struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
585 862
586 if (!drm_plane->crtc) { 863 if (!drm_plane->crtc) {
587 DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", 864 DRM_DEBUG_DRIVER("drm plane:%d not enabled\n",
@@ -590,13 +867,15 @@ static void sti_gdp_atomic_disable(struct drm_plane *drm_plane,
590 } 867 }
591 868
592 DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n", 869 DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n",
593 drm_plane->crtc->base.id, sti_mixer_to_str(mixer), 870 drm_plane->crtc->base.id,
871 sti_mixer_to_str(to_sti_mixer(drm_plane->crtc)),
594 drm_plane->base.id, sti_plane_to_str(plane)); 872 drm_plane->base.id, sti_plane_to_str(plane));
595 873
596 plane->status = STI_PLANE_DISABLING; 874 plane->status = STI_PLANE_DISABLING;
597} 875}
598 876
599static const struct drm_plane_helper_funcs sti_gdp_helpers_funcs = { 877static const struct drm_plane_helper_funcs sti_gdp_helpers_funcs = {
878 .atomic_check = sti_gdp_atomic_check,
600 .atomic_update = sti_gdp_atomic_update, 879 .atomic_update = sti_gdp_atomic_update,
601 .atomic_disable = sti_gdp_atomic_disable, 880 .atomic_disable = sti_gdp_atomic_disable,
602}; 881};
@@ -640,6 +919,9 @@ struct drm_plane *sti_gdp_create(struct drm_device *drm_dev,
640 919
641 sti_plane_init_property(&gdp->plane, type); 920 sti_plane_init_property(&gdp->plane, type);
642 921
922 if (gdp_debugfs_init(gdp, drm_dev->primary))
923 DRM_ERROR("GDP debugfs setup failed\n");
924
643 return &gdp->plane.drm_plane; 925 return &gdp->plane.drm_plane;
644 926
645err: 927err:
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
index 49cce833f2c8..ec0d017eaf1a 100644
--- a/drivers/gpu/drm/sti/sti_hda.c
+++ b/drivers/gpu/drm/sti/sti_hda.c
@@ -326,6 +326,103 @@ static void hda_enable_hd_dacs(struct sti_hda *hda, bool enable)
326 } 326 }
327} 327}
328 328
329#define DBGFS_DUMP(reg) seq_printf(s, "\n %-25s 0x%08X", #reg, \
330 readl(hda->regs + reg))
331
332static void hda_dbg_cfg(struct seq_file *s, int val)
333{
334 seq_puts(s, "\tAWG ");
335 seq_puts(s, val & CFG_AWG_ASYNC_EN ? "enabled" : "disabled");
336}
337
338static void hda_dbg_awg_microcode(struct seq_file *s, void __iomem *reg)
339{
340 unsigned int i;
341
342 seq_puts(s, "\n\n");
343 seq_puts(s, " HDA AWG microcode:");
344 for (i = 0; i < AWG_MAX_INST; i++) {
345 if (i % 8 == 0)
346 seq_printf(s, "\n %04X:", i);
347 seq_printf(s, " %04X", readl(reg + i * 4));
348 }
349}
350
351static void hda_dbg_video_dacs_ctrl(struct seq_file *s, void __iomem *reg)
352{
353 u32 val = readl(reg);
354 u32 mask;
355
356 switch ((u32)reg & VIDEO_DACS_CONTROL_MASK) {
357 case VIDEO_DACS_CONTROL_SYSCFG2535:
358 mask = DAC_CFG_HD_OFF_MASK;
359 break;
360 case VIDEO_DACS_CONTROL_SYSCFG5072:
361 mask = DAC_CFG_HD_HZUVW_OFF_MASK;
362 break;
363 default:
364 DRM_DEBUG_DRIVER("Warning: DACS ctrl register not supported!");
365 return;
366 }
367
368 seq_puts(s, "\n");
369 seq_printf(s, "\n %-25s 0x%08X", "VIDEO_DACS_CONTROL", val);
370 seq_puts(s, "\tHD DACs ");
371 seq_puts(s, val & mask ? "disabled" : "enabled");
372}
373
374static int hda_dbg_show(struct seq_file *s, void *data)
375{
376 struct drm_info_node *node = s->private;
377 struct sti_hda *hda = (struct sti_hda *)node->info_ent->data;
378 struct drm_device *dev = node->minor->dev;
379 int ret;
380
381 ret = mutex_lock_interruptible(&dev->struct_mutex);
382 if (ret)
383 return ret;
384
385 seq_printf(s, "HD Analog: (vaddr = 0x%p)", hda->regs);
386 DBGFS_DUMP(HDA_ANA_CFG);
387 hda_dbg_cfg(s, readl(hda->regs + HDA_ANA_CFG));
388 DBGFS_DUMP(HDA_ANA_SCALE_CTRL_Y);
389 DBGFS_DUMP(HDA_ANA_SCALE_CTRL_CB);
390 DBGFS_DUMP(HDA_ANA_SCALE_CTRL_CR);
391 DBGFS_DUMP(HDA_ANA_ANC_CTRL);
392 DBGFS_DUMP(HDA_ANA_SRC_Y_CFG);
393 DBGFS_DUMP(HDA_ANA_SRC_C_CFG);
394 hda_dbg_awg_microcode(s, hda->regs + HDA_SYNC_AWGI);
395 if (hda->video_dacs_ctrl)
396 hda_dbg_video_dacs_ctrl(s, hda->video_dacs_ctrl);
397 seq_puts(s, "\n");
398
399 mutex_unlock(&dev->struct_mutex);
400 return 0;
401}
402
403static struct drm_info_list hda_debugfs_files[] = {
404 { "hda", hda_dbg_show, 0, NULL },
405};
406
407static void hda_debugfs_exit(struct sti_hda *hda, struct drm_minor *minor)
408{
409 drm_debugfs_remove_files(hda_debugfs_files,
410 ARRAY_SIZE(hda_debugfs_files),
411 minor);
412}
413
414static int hda_debugfs_init(struct sti_hda *hda, struct drm_minor *minor)
415{
416 unsigned int i;
417
418 for (i = 0; i < ARRAY_SIZE(hda_debugfs_files); i++)
419 hda_debugfs_files[i].data = hda;
420
421 return drm_debugfs_create_files(hda_debugfs_files,
422 ARRAY_SIZE(hda_debugfs_files),
423 minor->debugfs_root, minor);
424}
425
329/** 426/**
330 * Configure AWG, writing instructions 427 * Configure AWG, writing instructions
331 * 428 *
@@ -685,6 +782,12 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
685 goto err_sysfs; 782 goto err_sysfs;
686 } 783 }
687 784
785 /* force to disable hd dacs at startup */
786 hda_enable_hd_dacs(hda, false);
787
788 if (hda_debugfs_init(hda, drm_dev->primary))
789 DRM_ERROR("HDA debugfs setup failed\n");
790
688 return 0; 791 return 0;
689 792
690err_sysfs: 793err_sysfs:
@@ -697,7 +800,10 @@ err_connector:
697static void sti_hda_unbind(struct device *dev, 800static void sti_hda_unbind(struct device *dev,
698 struct device *master, void *data) 801 struct device *master, void *data)
699{ 802{
700 /* do nothing */ 803 struct sti_hda *hda = dev_get_drvdata(dev);
804 struct drm_device *drm_dev = data;
805
806 hda_debugfs_exit(hda, drm_dev->primary);
701} 807}
702 808
703static const struct component_ops sti_hda_ops = { 809static const struct component_ops sti_hda_ops = {
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
index cd501563c0cc..6ef0715bd5b9 100644
--- a/drivers/gpu/drm/sti/sti_hdmi.c
+++ b/drivers/gpu/drm/sti/sti_hdmi.c
@@ -6,6 +6,7 @@
6 6
7#include <linux/clk.h> 7#include <linux/clk.h>
8#include <linux/component.h> 8#include <linux/component.h>
9#include <linux/debugfs.h>
9#include <linux/hdmi.h> 10#include <linux/hdmi.h>
10#include <linux/module.h> 11#include <linux/module.h>
11#include <linux/of_gpio.h> 12#include <linux/of_gpio.h>
@@ -51,9 +52,18 @@
51#define HDMI_SW_DI_2_PKT_WORD4 0x0614 52#define HDMI_SW_DI_2_PKT_WORD4 0x0614
52#define HDMI_SW_DI_2_PKT_WORD5 0x0618 53#define HDMI_SW_DI_2_PKT_WORD5 0x0618
53#define HDMI_SW_DI_2_PKT_WORD6 0x061C 54#define HDMI_SW_DI_2_PKT_WORD6 0x061C
55#define HDMI_SW_DI_3_HEAD_WORD 0x0620
56#define HDMI_SW_DI_3_PKT_WORD0 0x0624
57#define HDMI_SW_DI_3_PKT_WORD1 0x0628
58#define HDMI_SW_DI_3_PKT_WORD2 0x062C
59#define HDMI_SW_DI_3_PKT_WORD3 0x0630
60#define HDMI_SW_DI_3_PKT_WORD4 0x0634
61#define HDMI_SW_DI_3_PKT_WORD5 0x0638
62#define HDMI_SW_DI_3_PKT_WORD6 0x063C
54 63
55#define HDMI_IFRAME_SLOT_AVI 1 64#define HDMI_IFRAME_SLOT_AVI 1
56#define HDMI_IFRAME_SLOT_AUDIO 2 65#define HDMI_IFRAME_SLOT_AUDIO 2
66#define HDMI_IFRAME_SLOT_VENDOR 3
57 67
58#define XCAT(prefix, x, suffix) prefix ## x ## suffix 68#define XCAT(prefix, x, suffix) prefix ## x ## suffix
59#define HDMI_SW_DI_N_HEAD_WORD(x) XCAT(HDMI_SW_DI_, x, _HEAD_WORD) 69#define HDMI_SW_DI_N_HEAD_WORD(x) XCAT(HDMI_SW_DI_, x, _HEAD_WORD)
@@ -65,6 +75,8 @@
65#define HDMI_SW_DI_N_PKT_WORD5(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD5) 75#define HDMI_SW_DI_N_PKT_WORD5(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD5)
66#define HDMI_SW_DI_N_PKT_WORD6(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD6) 76#define HDMI_SW_DI_N_PKT_WORD6(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD6)
67 77
78#define HDMI_SW_DI_MAX_WORD 7
79
68#define HDMI_IFRAME_DISABLED 0x0 80#define HDMI_IFRAME_DISABLED 0x0
69#define HDMI_IFRAME_SINGLE_SHOT 0x1 81#define HDMI_IFRAME_SINGLE_SHOT 0x1
70#define HDMI_IFRAME_FIELD 0x2 82#define HDMI_IFRAME_FIELD 0x2
@@ -117,6 +129,8 @@ struct sti_hdmi_connector {
117 struct drm_connector drm_connector; 129 struct drm_connector drm_connector;
118 struct drm_encoder *encoder; 130 struct drm_encoder *encoder;
119 struct sti_hdmi *hdmi; 131 struct sti_hdmi *hdmi;
132 struct drm_property *colorspace_property;
133 struct drm_property *hdmi_mode_property;
120}; 134};
121 135
122#define to_sti_hdmi_connector(x) \ 136#define to_sti_hdmi_connector(x) \
@@ -217,8 +231,10 @@ static void hdmi_config(struct sti_hdmi *hdmi)
217 /* Clear overrun and underrun fifo */ 231 /* Clear overrun and underrun fifo */
218 conf = HDMI_CFG_FIFO_OVERRUN_CLR | HDMI_CFG_FIFO_UNDERRUN_CLR; 232 conf = HDMI_CFG_FIFO_OVERRUN_CLR | HDMI_CFG_FIFO_UNDERRUN_CLR;
219 233
220 /* Enable HDMI mode not DVI */ 234 /* Select encryption type and the framing mode */
221 conf |= HDMI_CFG_HDMI_NOT_DVI | HDMI_CFG_ESS_NOT_OESS; 235 conf |= HDMI_CFG_ESS_NOT_OESS;
236 if (hdmi->hdmi_mode == HDMI_MODE_HDMI)
237 conf |= HDMI_CFG_HDMI_NOT_DVI;
222 238
223 /* Enable sink term detection */ 239 /* Enable sink term detection */
224 conf |= HDMI_CFG_SINK_TERM_DET_EN; 240 conf |= HDMI_CFG_SINK_TERM_DET_EN;
@@ -241,6 +257,47 @@ static void hdmi_config(struct sti_hdmi *hdmi)
241 hdmi_write(hdmi, conf, HDMI_CFG); 257 hdmi_write(hdmi, conf, HDMI_CFG);
242} 258}
243 259
260/*
261 * Helper to reset info frame
262 *
263 * @hdmi: pointer on the hdmi internal structure
264 * @slot: infoframe to reset
265 */
266static void hdmi_infoframe_reset(struct sti_hdmi *hdmi,
267 u32 slot)
268{
269 u32 val, i;
270 u32 head_offset, pack_offset;
271
272 switch (slot) {
273 case HDMI_IFRAME_SLOT_AVI:
274 head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AVI);
275 pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AVI);
276 break;
277 case HDMI_IFRAME_SLOT_AUDIO:
278 head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AUDIO);
279 pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AUDIO);
280 break;
281 case HDMI_IFRAME_SLOT_VENDOR:
282 head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_VENDOR);
283 pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_VENDOR);
284 break;
285 default:
286 DRM_ERROR("unsupported infoframe slot: %#x\n", slot);
287 return;
288 }
289
290 /* Disable transmission for the selected slot */
291 val = hdmi_read(hdmi, HDMI_SW_DI_CFG);
292 val &= ~HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, slot);
293 hdmi_write(hdmi, val, HDMI_SW_DI_CFG);
294
295 /* Reset info frame registers */
296 hdmi_write(hdmi, 0x0, head_offset);
297 for (i = 0; i < HDMI_SW_DI_MAX_WORD; i += sizeof(u32))
298 hdmi_write(hdmi, 0x0, pack_offset + i);
299}
300
244/** 301/**
245 * Helper to concatenate infoframe in 32 bits word 302 * Helper to concatenate infoframe in 32 bits word
246 * 303 *
@@ -266,12 +323,13 @@ static inline unsigned int hdmi_infoframe_subpack(const u8 *ptr, size_t size)
266 * @data: infoframe to write 323 * @data: infoframe to write
267 * @size: size to write 324 * @size: size to write
268 */ 325 */
269static void hdmi_infoframe_write_infopack(struct sti_hdmi *hdmi, const u8 *data) 326static void hdmi_infoframe_write_infopack(struct sti_hdmi *hdmi,
327 const u8 *data,
328 size_t size)
270{ 329{
271 const u8 *ptr = data; 330 const u8 *ptr = data;
272 u32 val, slot, mode, i; 331 u32 val, slot, mode, i;
273 u32 head_offset, pack_offset; 332 u32 head_offset, pack_offset;
274 size_t size;
275 333
276 switch (*ptr) { 334 switch (*ptr) {
277 case HDMI_INFOFRAME_TYPE_AVI: 335 case HDMI_INFOFRAME_TYPE_AVI:
@@ -279,17 +337,19 @@ static void hdmi_infoframe_write_infopack(struct sti_hdmi *hdmi, const u8 *data)
279 mode = HDMI_IFRAME_FIELD; 337 mode = HDMI_IFRAME_FIELD;
280 head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AVI); 338 head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AVI);
281 pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AVI); 339 pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AVI);
282 size = HDMI_AVI_INFOFRAME_SIZE;
283 break; 340 break;
284
285 case HDMI_INFOFRAME_TYPE_AUDIO: 341 case HDMI_INFOFRAME_TYPE_AUDIO:
286 slot = HDMI_IFRAME_SLOT_AUDIO; 342 slot = HDMI_IFRAME_SLOT_AUDIO;
287 mode = HDMI_IFRAME_FRAME; 343 mode = HDMI_IFRAME_FRAME;
288 head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AUDIO); 344 head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AUDIO);
289 pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AUDIO); 345 pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AUDIO);
290 size = HDMI_AUDIO_INFOFRAME_SIZE;
291 break; 346 break;
292 347 case HDMI_INFOFRAME_TYPE_VENDOR:
348 slot = HDMI_IFRAME_SLOT_VENDOR;
349 mode = HDMI_IFRAME_FRAME;
350 head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_VENDOR);
351 pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_VENDOR);
352 break;
293 default: 353 default:
294 DRM_ERROR("unsupported infoframe type: %#x\n", *ptr); 354 DRM_ERROR("unsupported infoframe type: %#x\n", *ptr);
295 return; 355 return;
@@ -308,8 +368,9 @@ static void hdmi_infoframe_write_infopack(struct sti_hdmi *hdmi, const u8 *data)
308 /* 368 /*
309 * Each subpack contains 4 bytes 369 * Each subpack contains 4 bytes
310 * The First Bytes of the first subpacket must contain the checksum 370 * The First Bytes of the first subpacket must contain the checksum
311 * Packet size in increase by one. 371 * Packet size is increase by one.
312 */ 372 */
373 size = size - HDMI_INFOFRAME_HEADER_SIZE + 1;
313 for (i = 0; i < size; i += sizeof(u32)) { 374 for (i = 0; i < size; i += sizeof(u32)) {
314 size_t num; 375 size_t num;
315 376
@@ -321,7 +382,7 @@ static void hdmi_infoframe_write_infopack(struct sti_hdmi *hdmi, const u8 *data)
321 382
322 /* Enable transmission slot for updated infoframe */ 383 /* Enable transmission slot for updated infoframe */
323 val = hdmi_read(hdmi, HDMI_SW_DI_CFG); 384 val = hdmi_read(hdmi, HDMI_SW_DI_CFG);
324 val |= HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_FIELD, slot); 385 val |= HDMI_IFRAME_CFG_DI_N(mode, slot);
325 hdmi_write(hdmi, val, HDMI_SW_DI_CFG); 386 hdmi_write(hdmi, val, HDMI_SW_DI_CFG);
326} 387}
327 388
@@ -352,7 +413,7 @@ static int hdmi_avi_infoframe_config(struct sti_hdmi *hdmi)
352 } 413 }
353 414
354 /* fixed infoframe configuration not linked to the mode */ 415 /* fixed infoframe configuration not linked to the mode */
355 infoframe.colorspace = HDMI_COLORSPACE_RGB; 416 infoframe.colorspace = hdmi->colorspace;
356 infoframe.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT; 417 infoframe.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT;
357 infoframe.colorimetry = HDMI_COLORIMETRY_NONE; 418 infoframe.colorimetry = HDMI_COLORIMETRY_NONE;
358 419
@@ -362,7 +423,7 @@ static int hdmi_avi_infoframe_config(struct sti_hdmi *hdmi)
362 return ret; 423 return ret;
363 } 424 }
364 425
365 hdmi_infoframe_write_infopack(hdmi, buffer); 426 hdmi_infoframe_write_infopack(hdmi, buffer, ret);
366 427
367 return 0; 428 return 0;
368} 429}
@@ -398,7 +459,49 @@ static int hdmi_audio_infoframe_config(struct sti_hdmi *hdmi)
398 return ret; 459 return ret;
399 } 460 }
400 461
401 hdmi_infoframe_write_infopack(hdmi, buffer); 462 hdmi_infoframe_write_infopack(hdmi, buffer, ret);
463
464 return 0;
465}
466
467/*
468 * Prepare and configure the VS infoframe
469 *
470 * Vendor Specific infoframe are transmitted once per frame and
471 * contains vendor specific information.
472 *
473 * @hdmi: pointer on the hdmi internal structure
474 *
475 * Return negative value if error occurs
476 */
477#define HDMI_VENDOR_INFOFRAME_MAX_SIZE 6
478static int hdmi_vendor_infoframe_config(struct sti_hdmi *hdmi)
479{
480 struct drm_display_mode *mode = &hdmi->mode;
481 struct hdmi_vendor_infoframe infoframe;
482 u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_VENDOR_INFOFRAME_MAX_SIZE];
483 int ret;
484
485 DRM_DEBUG_DRIVER("\n");
486
487 ret = drm_hdmi_vendor_infoframe_from_display_mode(&infoframe, mode);
488 if (ret < 0) {
489 /*
490 * Going into that statement does not means vendor infoframe
491 * fails. It just informed us that vendor infoframe is not
492 * needed for the selected mode. Only 4k or stereoscopic 3D
493 * mode requires vendor infoframe. So just simply return 0.
494 */
495 return 0;
496 }
497
498 ret = hdmi_vendor_infoframe_pack(&infoframe, buffer, sizeof(buffer));
499 if (ret < 0) {
500 DRM_ERROR("failed to pack VS infoframe: %d\n", ret);
501 return ret;
502 }
503
504 hdmi_infoframe_write_infopack(hdmi, buffer, ret);
402 505
403 return 0; 506 return 0;
404} 507}
@@ -448,6 +551,172 @@ static void hdmi_swreset(struct sti_hdmi *hdmi)
448 clk_disable_unprepare(hdmi->clk_audio); 551 clk_disable_unprepare(hdmi->clk_audio);
449} 552}
450 553
554#define DBGFS_PRINT_STR(str1, str2) seq_printf(s, "%-24s %s\n", str1, str2)
555#define DBGFS_PRINT_INT(str1, int2) seq_printf(s, "%-24s %d\n", str1, int2)
556#define DBGFS_DUMP(str, reg) seq_printf(s, "%s %-25s 0x%08X", str, #reg, \
557 hdmi_read(hdmi, reg))
558#define DBGFS_DUMP_DI(reg, slot) DBGFS_DUMP("\n", reg(slot))
559
560static void hdmi_dbg_cfg(struct seq_file *s, int val)
561{
562 int tmp;
563
564 seq_puts(s, "\t");
565 tmp = val & HDMI_CFG_HDMI_NOT_DVI;
566 DBGFS_PRINT_STR("mode:", tmp ? "HDMI" : "DVI");
567 seq_puts(s, "\t\t\t\t\t");
568 tmp = val & HDMI_CFG_HDCP_EN;
569 DBGFS_PRINT_STR("HDCP:", tmp ? "enable" : "disable");
570 seq_puts(s, "\t\t\t\t\t");
571 tmp = val & HDMI_CFG_ESS_NOT_OESS;
572 DBGFS_PRINT_STR("HDCP mode:", tmp ? "ESS enable" : "OESS enable");
573 seq_puts(s, "\t\t\t\t\t");
574 tmp = val & HDMI_CFG_SINK_TERM_DET_EN;
575 DBGFS_PRINT_STR("Sink term detection:", tmp ? "enable" : "disable");
576 seq_puts(s, "\t\t\t\t\t");
577 tmp = val & HDMI_CFG_H_SYNC_POL_NEG;
578 DBGFS_PRINT_STR("Hsync polarity:", tmp ? "inverted" : "normal");
579 seq_puts(s, "\t\t\t\t\t");
580 tmp = val & HDMI_CFG_V_SYNC_POL_NEG;
581 DBGFS_PRINT_STR("Vsync polarity:", tmp ? "inverted" : "normal");
582 seq_puts(s, "\t\t\t\t\t");
583 tmp = val & HDMI_CFG_422_EN;
584 DBGFS_PRINT_STR("YUV422 format:", tmp ? "enable" : "disable");
585}
586
587static void hdmi_dbg_sta(struct seq_file *s, int val)
588{
589 int tmp;
590
591 seq_puts(s, "\t");
592 tmp = (val & HDMI_STA_DLL_LCK);
593 DBGFS_PRINT_STR("pll:", tmp ? "locked" : "not locked");
594 seq_puts(s, "\t\t\t\t\t");
595 tmp = (val & HDMI_STA_HOT_PLUG);
596 DBGFS_PRINT_STR("hdmi cable:", tmp ? "connected" : "not connected");
597}
598
599static void hdmi_dbg_sw_di_cfg(struct seq_file *s, int val)
600{
601 int tmp;
602 char *const en_di[] = {"no transmission",
603 "single transmission",
604 "once every field",
605 "once every frame"};
606
607 seq_puts(s, "\t");
608 tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 1));
609 DBGFS_PRINT_STR("Data island 1:", en_di[tmp]);
610 seq_puts(s, "\t\t\t\t\t");
611 tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 2)) >> 4;
612 DBGFS_PRINT_STR("Data island 2:", en_di[tmp]);
613 seq_puts(s, "\t\t\t\t\t");
614 tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 3)) >> 8;
615 DBGFS_PRINT_STR("Data island 3:", en_di[tmp]);
616 seq_puts(s, "\t\t\t\t\t");
617 tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 4)) >> 12;
618 DBGFS_PRINT_STR("Data island 4:", en_di[tmp]);
619 seq_puts(s, "\t\t\t\t\t");
620 tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 5)) >> 16;
621 DBGFS_PRINT_STR("Data island 5:", en_di[tmp]);
622 seq_puts(s, "\t\t\t\t\t");
623 tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 6)) >> 20;
624 DBGFS_PRINT_STR("Data island 6:", en_di[tmp]);
625}
626
627static int hdmi_dbg_show(struct seq_file *s, void *data)
628{
629 struct drm_info_node *node = s->private;
630 struct sti_hdmi *hdmi = (struct sti_hdmi *)node->info_ent->data;
631 struct drm_device *dev = node->minor->dev;
632 int ret;
633
634 ret = mutex_lock_interruptible(&dev->struct_mutex);
635 if (ret)
636 return ret;
637
638 seq_printf(s, "HDMI: (vaddr = 0x%p)", hdmi->regs);
639 DBGFS_DUMP("\n", HDMI_CFG);
640 hdmi_dbg_cfg(s, hdmi_read(hdmi, HDMI_CFG));
641 DBGFS_DUMP("", HDMI_INT_EN);
642 DBGFS_DUMP("\n", HDMI_STA);
643 hdmi_dbg_sta(s, hdmi_read(hdmi, HDMI_STA));
644 DBGFS_DUMP("", HDMI_ACTIVE_VID_XMIN);
645 seq_puts(s, "\t");
646 DBGFS_PRINT_INT("Xmin:", hdmi_read(hdmi, HDMI_ACTIVE_VID_XMIN));
647 DBGFS_DUMP("", HDMI_ACTIVE_VID_XMAX);
648 seq_puts(s, "\t");
649 DBGFS_PRINT_INT("Xmax:", hdmi_read(hdmi, HDMI_ACTIVE_VID_XMAX));
650 DBGFS_DUMP("", HDMI_ACTIVE_VID_YMIN);
651 seq_puts(s, "\t");
652 DBGFS_PRINT_INT("Ymin:", hdmi_read(hdmi, HDMI_ACTIVE_VID_YMIN));
653 DBGFS_DUMP("", HDMI_ACTIVE_VID_YMAX);
654 seq_puts(s, "\t");
655 DBGFS_PRINT_INT("Ymax:", hdmi_read(hdmi, HDMI_ACTIVE_VID_YMAX));
656 DBGFS_DUMP("", HDMI_SW_DI_CFG);
657 hdmi_dbg_sw_di_cfg(s, hdmi_read(hdmi, HDMI_SW_DI_CFG));
658
659 seq_printf(s, "\n AVI Infoframe (Data Island slot N=%d):",
660 HDMI_IFRAME_SLOT_AVI);
661 DBGFS_DUMP_DI(HDMI_SW_DI_N_HEAD_WORD, HDMI_IFRAME_SLOT_AVI);
662 DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD0, HDMI_IFRAME_SLOT_AVI);
663 DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD1, HDMI_IFRAME_SLOT_AVI);
664 DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD2, HDMI_IFRAME_SLOT_AVI);
665 DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD3, HDMI_IFRAME_SLOT_AVI);
666 DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD4, HDMI_IFRAME_SLOT_AVI);
667 DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD5, HDMI_IFRAME_SLOT_AVI);
668 DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD6, HDMI_IFRAME_SLOT_AVI);
669 seq_puts(s, "\n");
670 seq_printf(s, "\n AUDIO Infoframe (Data Island slot N=%d):",
671 HDMI_IFRAME_SLOT_AUDIO);
672 DBGFS_DUMP_DI(HDMI_SW_DI_N_HEAD_WORD, HDMI_IFRAME_SLOT_AUDIO);
673 DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD0, HDMI_IFRAME_SLOT_AUDIO);
674 DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD1, HDMI_IFRAME_SLOT_AUDIO);
675 DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD2, HDMI_IFRAME_SLOT_AUDIO);
676 DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD3, HDMI_IFRAME_SLOT_AUDIO);
677 DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD4, HDMI_IFRAME_SLOT_AUDIO);
678 DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD5, HDMI_IFRAME_SLOT_AUDIO);
679 DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD6, HDMI_IFRAME_SLOT_AUDIO);
680 seq_puts(s, "\n");
681 seq_printf(s, "\n VENDOR SPECIFIC Infoframe (Data Island slot N=%d):",
682 HDMI_IFRAME_SLOT_VENDOR);
683 DBGFS_DUMP_DI(HDMI_SW_DI_N_HEAD_WORD, HDMI_IFRAME_SLOT_VENDOR);
684 DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD0, HDMI_IFRAME_SLOT_VENDOR);
685 DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD1, HDMI_IFRAME_SLOT_VENDOR);
686 DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD2, HDMI_IFRAME_SLOT_VENDOR);
687 DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD3, HDMI_IFRAME_SLOT_VENDOR);
688 DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD4, HDMI_IFRAME_SLOT_VENDOR);
689 DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD5, HDMI_IFRAME_SLOT_VENDOR);
690 DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD6, HDMI_IFRAME_SLOT_VENDOR);
691 seq_puts(s, "\n");
692
693 mutex_unlock(&dev->struct_mutex);
694 return 0;
695}
696
697static struct drm_info_list hdmi_debugfs_files[] = {
698 { "hdmi", hdmi_dbg_show, 0, NULL },
699};
700
701static void hdmi_debugfs_exit(struct sti_hdmi *hdmi, struct drm_minor *minor)
702{
703 drm_debugfs_remove_files(hdmi_debugfs_files,
704 ARRAY_SIZE(hdmi_debugfs_files),
705 minor);
706}
707
708static int hdmi_debugfs_init(struct sti_hdmi *hdmi, struct drm_minor *minor)
709{
710 unsigned int i;
711
712 for (i = 0; i < ARRAY_SIZE(hdmi_debugfs_files); i++)
713 hdmi_debugfs_files[i].data = hdmi;
714
715 return drm_debugfs_create_files(hdmi_debugfs_files,
716 ARRAY_SIZE(hdmi_debugfs_files),
717 minor->debugfs_root, minor);
718}
719
451static void sti_hdmi_disable(struct drm_bridge *bridge) 720static void sti_hdmi_disable(struct drm_bridge *bridge)
452{ 721{
453 struct sti_hdmi *hdmi = bridge->driver_private; 722 struct sti_hdmi *hdmi = bridge->driver_private;
@@ -468,6 +737,11 @@ static void sti_hdmi_disable(struct drm_bridge *bridge)
468 /* Stop the phy */ 737 /* Stop the phy */
469 hdmi->phy_ops->stop(hdmi); 738 hdmi->phy_ops->stop(hdmi);
470 739
740 /* Reset info frame transmission */
741 hdmi_infoframe_reset(hdmi, HDMI_IFRAME_SLOT_AVI);
742 hdmi_infoframe_reset(hdmi, HDMI_IFRAME_SLOT_AUDIO);
743 hdmi_infoframe_reset(hdmi, HDMI_IFRAME_SLOT_VENDOR);
744
471 /* Set the default channel data to be a dark red */ 745 /* Set the default channel data to be a dark red */
472 hdmi_write(hdmi, 0x0000, HDMI_DFLT_CHL0_DAT); 746 hdmi_write(hdmi, 0x0000, HDMI_DFLT_CHL0_DAT);
473 hdmi_write(hdmi, 0x0000, HDMI_DFLT_CHL1_DAT); 747 hdmi_write(hdmi, 0x0000, HDMI_DFLT_CHL1_DAT);
@@ -523,6 +797,10 @@ static void sti_hdmi_pre_enable(struct drm_bridge *bridge)
523 if (hdmi_audio_infoframe_config(hdmi)) 797 if (hdmi_audio_infoframe_config(hdmi))
524 DRM_ERROR("Unable to configure AUDIO infoframe\n"); 798 DRM_ERROR("Unable to configure AUDIO infoframe\n");
525 799
800 /* Program VS infoframe */
801 if (hdmi_vendor_infoframe_config(hdmi))
802 DRM_ERROR("Unable to configure VS infoframe\n");
803
526 /* Sw reset */ 804 /* Sw reset */
527 hdmi_swreset(hdmi); 805 hdmi_swreset(hdmi);
528} 806}
@@ -664,12 +942,97 @@ static void sti_hdmi_connector_destroy(struct drm_connector *connector)
664 kfree(hdmi_connector); 942 kfree(hdmi_connector);
665} 943}
666 944
945static void sti_hdmi_connector_init_property(struct drm_device *drm_dev,
946 struct drm_connector *connector)
947{
948 struct sti_hdmi_connector *hdmi_connector
949 = to_sti_hdmi_connector(connector);
950 struct sti_hdmi *hdmi = hdmi_connector->hdmi;
951 struct drm_property *prop;
952
953 /* colorspace property */
954 hdmi->colorspace = DEFAULT_COLORSPACE_MODE;
955 prop = drm_property_create_enum(drm_dev, 0, "colorspace",
956 colorspace_mode_names,
957 ARRAY_SIZE(colorspace_mode_names));
958 if (!prop) {
959 DRM_ERROR("fails to create colorspace property\n");
960 return;
961 }
962 hdmi_connector->colorspace_property = prop;
963 drm_object_attach_property(&connector->base, prop, hdmi->colorspace);
964
965 /* hdmi_mode property */
966 hdmi->hdmi_mode = DEFAULT_HDMI_MODE;
967 prop = drm_property_create_enum(drm_dev, 0, "hdmi_mode",
968 hdmi_mode_names,
969 ARRAY_SIZE(hdmi_mode_names));
970 if (!prop) {
971 DRM_ERROR("fails to create colorspace property\n");
972 return;
973 }
974 hdmi_connector->hdmi_mode_property = prop;
975 drm_object_attach_property(&connector->base, prop, hdmi->hdmi_mode);
976
977}
978
979static int
980sti_hdmi_connector_set_property(struct drm_connector *connector,
981 struct drm_connector_state *state,
982 struct drm_property *property,
983 uint64_t val)
984{
985 struct sti_hdmi_connector *hdmi_connector
986 = to_sti_hdmi_connector(connector);
987 struct sti_hdmi *hdmi = hdmi_connector->hdmi;
988
989 if (property == hdmi_connector->colorspace_property) {
990 hdmi->colorspace = val;
991 return 0;
992 }
993
994 if (property == hdmi_connector->hdmi_mode_property) {
995 hdmi->hdmi_mode = val;
996 return 0;
997 }
998
999 DRM_ERROR("failed to set hdmi connector property\n");
1000 return -EINVAL;
1001}
1002
1003static int
1004sti_hdmi_connector_get_property(struct drm_connector *connector,
1005 const struct drm_connector_state *state,
1006 struct drm_property *property,
1007 uint64_t *val)
1008{
1009 struct sti_hdmi_connector *hdmi_connector
1010 = to_sti_hdmi_connector(connector);
1011 struct sti_hdmi *hdmi = hdmi_connector->hdmi;
1012
1013 if (property == hdmi_connector->colorspace_property) {
1014 *val = hdmi->colorspace;
1015 return 0;
1016 }
1017
1018 if (property == hdmi_connector->hdmi_mode_property) {
1019 *val = hdmi->hdmi_mode;
1020 return 0;
1021 }
1022
1023 DRM_ERROR("failed to get hdmi connector property\n");
1024 return -EINVAL;
1025}
1026
667static const struct drm_connector_funcs sti_hdmi_connector_funcs = { 1027static const struct drm_connector_funcs sti_hdmi_connector_funcs = {
668 .dpms = drm_atomic_helper_connector_dpms, 1028 .dpms = drm_atomic_helper_connector_dpms,
669 .fill_modes = drm_helper_probe_single_connector_modes, 1029 .fill_modes = drm_helper_probe_single_connector_modes,
670 .detect = sti_hdmi_connector_detect, 1030 .detect = sti_hdmi_connector_detect,
671 .destroy = sti_hdmi_connector_destroy, 1031 .destroy = sti_hdmi_connector_destroy,
672 .reset = drm_atomic_helper_connector_reset, 1032 .reset = drm_atomic_helper_connector_reset,
1033 .set_property = drm_atomic_helper_connector_set_property,
1034 .atomic_set_property = sti_hdmi_connector_set_property,
1035 .atomic_get_property = sti_hdmi_connector_get_property,
673 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 1036 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
674 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 1037 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
675}; 1038};
@@ -729,6 +1092,9 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
729 drm_connector_helper_add(drm_connector, 1092 drm_connector_helper_add(drm_connector,
730 &sti_hdmi_connector_helper_funcs); 1093 &sti_hdmi_connector_helper_funcs);
731 1094
1095 /* initialise property */
1096 sti_hdmi_connector_init_property(drm_dev, drm_connector);
1097
732 err = drm_connector_register(drm_connector); 1098 err = drm_connector_register(drm_connector);
733 if (err) 1099 if (err)
734 goto err_connector; 1100 goto err_connector;
@@ -742,6 +1108,9 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
742 /* Enable default interrupts */ 1108 /* Enable default interrupts */
743 hdmi_write(hdmi, HDMI_DEFAULT_INT, HDMI_INT_EN); 1109 hdmi_write(hdmi, HDMI_DEFAULT_INT, HDMI_INT_EN);
744 1110
1111 if (hdmi_debugfs_init(hdmi, drm_dev->primary))
1112 DRM_ERROR("HDMI debugfs setup failed\n");
1113
745 return 0; 1114 return 0;
746 1115
747err_sysfs: 1116err_sysfs:
@@ -755,7 +1124,10 @@ err_connector:
755static void sti_hdmi_unbind(struct device *dev, 1124static void sti_hdmi_unbind(struct device *dev,
756 struct device *master, void *data) 1125 struct device *master, void *data)
757{ 1126{
758 /* do nothing */ 1127 struct sti_hdmi *hdmi = dev_get_drvdata(dev);
1128 struct drm_device *drm_dev = data;
1129
1130 hdmi_debugfs_exit(hdmi, drm_dev->primary);
759} 1131}
760 1132
761static const struct component_ops sti_hdmi_ops = { 1133static const struct component_ops sti_hdmi_ops = {
diff --git a/drivers/gpu/drm/sti/sti_hdmi.h b/drivers/gpu/drm/sti/sti_hdmi.h
index 3d22390e1f3b..ef3a94583bbd 100644
--- a/drivers/gpu/drm/sti/sti_hdmi.h
+++ b/drivers/gpu/drm/sti/sti_hdmi.h
@@ -7,15 +7,14 @@
7#ifndef _STI_HDMI_H_ 7#ifndef _STI_HDMI_H_
8#define _STI_HDMI_H_ 8#define _STI_HDMI_H_
9 9
10#include <linux/hdmi.h>
10#include <linux/platform_device.h> 11#include <linux/platform_device.h>
11 12
12#include <drm/drmP.h> 13#include <drm/drmP.h>
13 14
14#define HDMI_STA 0x0010 15#define HDMI_STA 0x0010
15#define HDMI_STA_DLL_LCK BIT(5) 16#define HDMI_STA_DLL_LCK BIT(5)
16 17#define HDMI_STA_HOT_PLUG BIT(4)
17#define HDMI_STA_HOT_PLUG_SHIFT 4
18#define HDMI_STA_HOT_PLUG (1 << HDMI_STA_HOT_PLUG_SHIFT)
19 18
20struct sti_hdmi; 19struct sti_hdmi;
21 20
@@ -24,6 +23,27 @@ struct hdmi_phy_ops {
24 void (*stop)(struct sti_hdmi *hdmi); 23 void (*stop)(struct sti_hdmi *hdmi);
25}; 24};
26 25
26/* values for the framing mode property */
27enum sti_hdmi_modes {
28 HDMI_MODE_HDMI,
29 HDMI_MODE_DVI,
30};
31
32static const struct drm_prop_enum_list hdmi_mode_names[] = {
33 { HDMI_MODE_HDMI, "hdmi" },
34 { HDMI_MODE_DVI, "dvi" },
35};
36
37#define DEFAULT_HDMI_MODE HDMI_MODE_HDMI
38
39static const struct drm_prop_enum_list colorspace_mode_names[] = {
40 { HDMI_COLORSPACE_RGB, "rgb" },
41 { HDMI_COLORSPACE_YUV422, "yuv422" },
42 { HDMI_COLORSPACE_YUV444, "yuv444" },
43};
44
45#define DEFAULT_COLORSPACE_MODE HDMI_COLORSPACE_RGB
46
27/** 47/**
28 * STI hdmi structure 48 * STI hdmi structure
29 * 49 *
@@ -44,6 +64,9 @@ struct hdmi_phy_ops {
44 * @wait_event: wait event 64 * @wait_event: wait event
45 * @event_received: wait event status 65 * @event_received: wait event status
46 * @reset: reset control of the hdmi phy 66 * @reset: reset control of the hdmi phy
67 * @ddc_adapt: i2c ddc adapter
68 * @colorspace: current colorspace selected
69 * @hdmi_mode: select framing for HDMI or DVI
47 */ 70 */
48struct sti_hdmi { 71struct sti_hdmi {
49 struct device dev; 72 struct device dev;
@@ -64,6 +87,8 @@ struct sti_hdmi {
64 bool event_received; 87 bool event_received;
65 struct reset_control *reset; 88 struct reset_control *reset;
66 struct i2c_adapter *ddc_adapt; 89 struct i2c_adapter *ddc_adapt;
90 enum hdmi_colorspace colorspace;
91 enum sti_hdmi_modes hdmi_mode;
67}; 92};
68 93
69u32 hdmi_read(struct sti_hdmi *hdmi, int offset); 94u32 hdmi_read(struct sti_hdmi *hdmi, int offset);
diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c
index 43861b52261d..d7c1f427811d 100644
--- a/drivers/gpu/drm/sti/sti_hqvdp.c
+++ b/drivers/gpu/drm/sti/sti_hqvdp.c
@@ -4,14 +4,11 @@
4 * License terms: GNU General Public License (GPL), version 2 4 * License terms: GNU General Public License (GPL), version 2
5 */ 5 */
6 6
7#include <linux/clk.h>
8#include <linux/component.h> 7#include <linux/component.h>
9#include <linux/firmware.h> 8#include <linux/firmware.h>
10#include <linux/module.h>
11#include <linux/platform_device.h>
12#include <linux/reset.h> 9#include <linux/reset.h>
13 10
14#include <drm/drmP.h> 11#include <drm/drm_atomic.h>
15#include <drm/drm_fb_cma_helper.h> 12#include <drm/drm_fb_cma_helper.h>
16#include <drm/drm_gem_cma_helper.h> 13#include <drm/drm_gem_cma_helper.h>
17 14
@@ -329,8 +326,6 @@ struct sti_hqvdp_cmd {
329 * @reset: reset control 326 * @reset: reset control
330 * @vtg_nb: notifier to handle VTG Vsync 327 * @vtg_nb: notifier to handle VTG Vsync
331 * @btm_field_pending: is there any bottom field (interlaced frame) to display 328 * @btm_field_pending: is there any bottom field (interlaced frame) to display
332 * @curr_field_count: number of field updates
333 * @last_field_count: number of field updates since last fps measure
334 * @hqvdp_cmd: buffer of commands 329 * @hqvdp_cmd: buffer of commands
335 * @hqvdp_cmd_paddr: physical address of hqvdp_cmd 330 * @hqvdp_cmd_paddr: physical address of hqvdp_cmd
336 * @vtg: vtg for main data path 331 * @vtg: vtg for main data path
@@ -346,10 +341,8 @@ struct sti_hqvdp {
346 struct reset_control *reset; 341 struct reset_control *reset;
347 struct notifier_block vtg_nb; 342 struct notifier_block vtg_nb;
348 bool btm_field_pending; 343 bool btm_field_pending;
349 unsigned int curr_field_count;
350 unsigned int last_field_count;
351 void *hqvdp_cmd; 344 void *hqvdp_cmd;
352 dma_addr_t hqvdp_cmd_paddr; 345 u32 hqvdp_cmd_paddr;
353 struct sti_vtg *vtg; 346 struct sti_vtg *vtg;
354 bool xp70_initialized; 347 bool xp70_initialized;
355}; 348};
@@ -372,8 +365,8 @@ static const uint32_t hqvdp_supported_formats[] = {
372 */ 365 */
373static int sti_hqvdp_get_free_cmd(struct sti_hqvdp *hqvdp) 366static int sti_hqvdp_get_free_cmd(struct sti_hqvdp *hqvdp)
374{ 367{
375 int curr_cmd, next_cmd; 368 u32 curr_cmd, next_cmd;
376 dma_addr_t cmd = hqvdp->hqvdp_cmd_paddr; 369 u32 cmd = hqvdp->hqvdp_cmd_paddr;
377 int i; 370 int i;
378 371
379 curr_cmd = readl(hqvdp->regs + HQVDP_MBX_CURRENT_CMD); 372 curr_cmd = readl(hqvdp->regs + HQVDP_MBX_CURRENT_CMD);
@@ -400,8 +393,8 @@ static int sti_hqvdp_get_free_cmd(struct sti_hqvdp *hqvdp)
400 */ 393 */
401static int sti_hqvdp_get_curr_cmd(struct sti_hqvdp *hqvdp) 394static int sti_hqvdp_get_curr_cmd(struct sti_hqvdp *hqvdp)
402{ 395{
403 int curr_cmd; 396 u32 curr_cmd;
404 dma_addr_t cmd = hqvdp->hqvdp_cmd_paddr; 397 u32 cmd = hqvdp->hqvdp_cmd_paddr;
405 unsigned int i; 398 unsigned int i;
406 399
407 curr_cmd = readl(hqvdp->regs + HQVDP_MBX_CURRENT_CMD); 400 curr_cmd = readl(hqvdp->regs + HQVDP_MBX_CURRENT_CMD);
@@ -417,6 +410,246 @@ static int sti_hqvdp_get_curr_cmd(struct sti_hqvdp *hqvdp)
417} 410}
418 411
419/** 412/**
413 * sti_hqvdp_get_next_cmd
414 * @hqvdp: hqvdp structure
415 *
416 * Look for the next hqvdp_cmd that will be used by the FW.
417 *
418 * RETURNS:
419 * the offset of the next command that will be used.
420 * -1 in error cases
421 */
422static int sti_hqvdp_get_next_cmd(struct sti_hqvdp *hqvdp)
423{
424 int next_cmd;
425 dma_addr_t cmd = hqvdp->hqvdp_cmd_paddr;
426 unsigned int i;
427
428 next_cmd = readl(hqvdp->regs + HQVDP_MBX_NEXT_CMD);
429
430 for (i = 0; i < NB_VDP_CMD; i++) {
431 if (cmd == next_cmd)
432 return i * sizeof(struct sti_hqvdp_cmd);
433
434 cmd += sizeof(struct sti_hqvdp_cmd);
435 }
436
437 return -1;
438}
439
440#define DBGFS_DUMP(reg) seq_printf(s, "\n %-25s 0x%08X", #reg, \
441 readl(hqvdp->regs + reg))
442
443static const char *hqvdp_dbg_get_lut(u32 *coef)
444{
445 if (!memcmp(coef, coef_lut_a_legacy, 16))
446 return "LUT A";
447 if (!memcmp(coef, coef_lut_b, 16))
448 return "LUT B";
449 if (!memcmp(coef, coef_lut_c_y_legacy, 16))
450 return "LUT C Y";
451 if (!memcmp(coef, coef_lut_c_c_legacy, 16))
452 return "LUT C C";
453 if (!memcmp(coef, coef_lut_d_y_legacy, 16))
454 return "LUT D Y";
455 if (!memcmp(coef, coef_lut_d_c_legacy, 16))
456 return "LUT D C";
457 if (!memcmp(coef, coef_lut_e_y_legacy, 16))
458 return "LUT E Y";
459 if (!memcmp(coef, coef_lut_e_c_legacy, 16))
460 return "LUT E C";
461 if (!memcmp(coef, coef_lut_f_y_legacy, 16))
462 return "LUT F Y";
463 if (!memcmp(coef, coef_lut_f_c_legacy, 16))
464 return "LUT F C";
465 return "<UNKNOWN>";
466}
467
468static void hqvdp_dbg_dump_cmd(struct seq_file *s, struct sti_hqvdp_cmd *c)
469{
470 int src_w, src_h, dst_w, dst_h;
471
472 seq_puts(s, "\n\tTOP:");
473 seq_printf(s, "\n\t %-20s 0x%08X", "Config", c->top.config);
474 switch (c->top.config) {
475 case TOP_CONFIG_PROGRESSIVE:
476 seq_puts(s, "\tProgressive");
477 break;
478 case TOP_CONFIG_INTER_TOP:
479 seq_puts(s, "\tInterlaced, top field");
480 break;
481 case TOP_CONFIG_INTER_BTM:
482 seq_puts(s, "\tInterlaced, bottom field");
483 break;
484 default:
485 seq_puts(s, "\t<UNKNOWN>");
486 break;
487 }
488
489 seq_printf(s, "\n\t %-20s 0x%08X", "MemFormat", c->top.mem_format);
490 seq_printf(s, "\n\t %-20s 0x%08X", "CurrentY", c->top.current_luma);
491 seq_printf(s, "\n\t %-20s 0x%08X", "CurrentC", c->top.current_chroma);
492 seq_printf(s, "\n\t %-20s 0x%08X", "YSrcPitch", c->top.luma_src_pitch);
493 seq_printf(s, "\n\t %-20s 0x%08X", "CSrcPitch",
494 c->top.chroma_src_pitch);
495 seq_printf(s, "\n\t %-20s 0x%08X", "InputFrameSize",
496 c->top.input_frame_size);
497 seq_printf(s, "\t%dx%d",
498 c->top.input_frame_size & 0x0000FFFF,
499 c->top.input_frame_size >> 16);
500 seq_printf(s, "\n\t %-20s 0x%08X", "InputViewportSize",
501 c->top.input_viewport_size);
502 src_w = c->top.input_viewport_size & 0x0000FFFF;
503 src_h = c->top.input_viewport_size >> 16;
504 seq_printf(s, "\t%dx%d", src_w, src_h);
505
506 seq_puts(s, "\n\tHVSRC:");
507 seq_printf(s, "\n\t %-20s 0x%08X", "OutputPictureSize",
508 c->hvsrc.output_picture_size);
509 dst_w = c->hvsrc.output_picture_size & 0x0000FFFF;
510 dst_h = c->hvsrc.output_picture_size >> 16;
511 seq_printf(s, "\t%dx%d", dst_w, dst_h);
512 seq_printf(s, "\n\t %-20s 0x%08X", "ParamCtrl", c->hvsrc.param_ctrl);
513
514 seq_printf(s, "\n\t %-20s %s", "yh_coef",
515 hqvdp_dbg_get_lut(c->hvsrc.yh_coef));
516 seq_printf(s, "\n\t %-20s %s", "ch_coef",
517 hqvdp_dbg_get_lut(c->hvsrc.ch_coef));
518 seq_printf(s, "\n\t %-20s %s", "yv_coef",
519 hqvdp_dbg_get_lut(c->hvsrc.yv_coef));
520 seq_printf(s, "\n\t %-20s %s", "cv_coef",
521 hqvdp_dbg_get_lut(c->hvsrc.cv_coef));
522
523 seq_printf(s, "\n\t %-20s", "ScaleH");
524 if (dst_w > src_w)
525 seq_printf(s, " %d/1", dst_w / src_w);
526 else
527 seq_printf(s, " 1/%d", src_w / dst_w);
528
529 seq_printf(s, "\n\t %-20s", "tScaleV");
530 if (dst_h > src_h)
531 seq_printf(s, " %d/1", dst_h / src_h);
532 else
533 seq_printf(s, " 1/%d", src_h / dst_h);
534
535 seq_puts(s, "\n\tCSDI:");
536 seq_printf(s, "\n\t %-20s 0x%08X\t", "Config", c->csdi.config);
537 switch (c->csdi.config) {
538 case CSDI_CONFIG_PROG:
539 seq_puts(s, "Bypass");
540 break;
541 case CSDI_CONFIG_INTER_DIR:
542 seq_puts(s, "Deinterlace, directional");
543 break;
544 default:
545 seq_puts(s, "<UNKNOWN>");
546 break;
547 }
548
549 seq_printf(s, "\n\t %-20s 0x%08X", "Config2", c->csdi.config2);
550 seq_printf(s, "\n\t %-20s 0x%08X", "DcdiConfig", c->csdi.dcdi_config);
551}
552
553static int hqvdp_dbg_show(struct seq_file *s, void *data)
554{
555 struct drm_info_node *node = s->private;
556 struct sti_hqvdp *hqvdp = (struct sti_hqvdp *)node->info_ent->data;
557 struct drm_device *dev = node->minor->dev;
558 int cmd, cmd_offset, infoxp70;
559 void *virt;
560 int ret;
561
562 ret = mutex_lock_interruptible(&dev->struct_mutex);
563 if (ret)
564 return ret;
565
566 seq_printf(s, "%s: (vaddr = 0x%p)",
567 sti_plane_to_str(&hqvdp->plane), hqvdp->regs);
568
569 DBGFS_DUMP(HQVDP_MBX_IRQ_TO_XP70);
570 DBGFS_DUMP(HQVDP_MBX_INFO_HOST);
571 DBGFS_DUMP(HQVDP_MBX_IRQ_TO_HOST);
572 DBGFS_DUMP(HQVDP_MBX_INFO_XP70);
573 infoxp70 = readl(hqvdp->regs + HQVDP_MBX_INFO_XP70);
574 seq_puts(s, "\tFirmware state: ");
575 if (infoxp70 & INFO_XP70_FW_READY)
576 seq_puts(s, "idle and ready");
577 else if (infoxp70 & INFO_XP70_FW_PROCESSING)
578 seq_puts(s, "processing a picture");
579 else if (infoxp70 & INFO_XP70_FW_INITQUEUES)
580 seq_puts(s, "programming queues");
581 else
582 seq_puts(s, "NOT READY");
583
584 DBGFS_DUMP(HQVDP_MBX_SW_RESET_CTRL);
585 DBGFS_DUMP(HQVDP_MBX_STARTUP_CTRL1);
586 if (readl(hqvdp->regs + HQVDP_MBX_STARTUP_CTRL1)
587 & STARTUP_CTRL1_RST_DONE)
588 seq_puts(s, "\tReset is done");
589 else
590 seq_puts(s, "\tReset is NOT done");
591 DBGFS_DUMP(HQVDP_MBX_STARTUP_CTRL2);
592 if (readl(hqvdp->regs + HQVDP_MBX_STARTUP_CTRL2)
593 & STARTUP_CTRL2_FETCH_EN)
594 seq_puts(s, "\tFetch is enabled");
595 else
596 seq_puts(s, "\tFetch is NOT enabled");
597 DBGFS_DUMP(HQVDP_MBX_GP_STATUS);
598 DBGFS_DUMP(HQVDP_MBX_NEXT_CMD);
599 DBGFS_DUMP(HQVDP_MBX_CURRENT_CMD);
600 DBGFS_DUMP(HQVDP_MBX_SOFT_VSYNC);
601 if (!(readl(hqvdp->regs + HQVDP_MBX_SOFT_VSYNC) & 3))
602 seq_puts(s, "\tHW Vsync");
603 else
604 seq_puts(s, "\tSW Vsync ?!?!");
605
606 /* Last command */
607 cmd = readl(hqvdp->regs + HQVDP_MBX_CURRENT_CMD);
608 cmd_offset = sti_hqvdp_get_curr_cmd(hqvdp);
609 if (cmd_offset == -1) {
610 seq_puts(s, "\n\n Last command: unknown");
611 } else {
612 virt = hqvdp->hqvdp_cmd + cmd_offset;
613 seq_printf(s, "\n\n Last command: address @ 0x%x (0x%p)",
614 cmd, virt);
615 hqvdp_dbg_dump_cmd(s, (struct sti_hqvdp_cmd *)virt);
616 }
617
618 /* Next command */
619 cmd = readl(hqvdp->regs + HQVDP_MBX_NEXT_CMD);
620 cmd_offset = sti_hqvdp_get_next_cmd(hqvdp);
621 if (cmd_offset == -1) {
622 seq_puts(s, "\n\n Next command: unknown");
623 } else {
624 virt = hqvdp->hqvdp_cmd + cmd_offset;
625 seq_printf(s, "\n\n Next command address: @ 0x%x (0x%p)",
626 cmd, virt);
627 hqvdp_dbg_dump_cmd(s, (struct sti_hqvdp_cmd *)virt);
628 }
629
630 seq_puts(s, "\n");
631
632 mutex_unlock(&dev->struct_mutex);
633 return 0;
634}
635
636static struct drm_info_list hqvdp_debugfs_files[] = {
637 { "hqvdp", hqvdp_dbg_show, 0, NULL },
638};
639
640static int hqvdp_debugfs_init(struct sti_hqvdp *hqvdp, struct drm_minor *minor)
641{
642 unsigned int i;
643
644 for (i = 0; i < ARRAY_SIZE(hqvdp_debugfs_files); i++)
645 hqvdp_debugfs_files[i].data = hqvdp;
646
647 return drm_debugfs_create_files(hqvdp_debugfs_files,
648 ARRAY_SIZE(hqvdp_debugfs_files),
649 minor->debugfs_root, minor);
650}
651
652/**
420 * sti_hqvdp_update_hvsrc 653 * sti_hqvdp_update_hvsrc
421 * @orient: horizontal or vertical 654 * @orient: horizontal or vertical
422 * @scale: scaling/zoom factor 655 * @scale: scaling/zoom factor
@@ -580,7 +813,7 @@ int sti_hqvdp_vtg_cb(struct notifier_block *nb, unsigned long evt, void *data)
580 btm_cmd_offset = sti_hqvdp_get_free_cmd(hqvdp); 813 btm_cmd_offset = sti_hqvdp_get_free_cmd(hqvdp);
581 top_cmd_offest = sti_hqvdp_get_curr_cmd(hqvdp); 814 top_cmd_offest = sti_hqvdp_get_curr_cmd(hqvdp);
582 if ((btm_cmd_offset == -1) || (top_cmd_offest == -1)) { 815 if ((btm_cmd_offset == -1) || (top_cmd_offest == -1)) {
583 DRM_ERROR("Cannot get cmds, skip btm field\n"); 816 DRM_DEBUG_DRIVER("Warning: no cmd, will skip field\n");
584 return -EBUSY; 817 return -EBUSY;
585 } 818 }
586 819
@@ -599,11 +832,12 @@ int sti_hqvdp_vtg_cb(struct notifier_block *nb, unsigned long evt, void *data)
599 writel(hqvdp->hqvdp_cmd_paddr + btm_cmd_offset, 832 writel(hqvdp->hqvdp_cmd_paddr + btm_cmd_offset,
600 hqvdp->regs + HQVDP_MBX_NEXT_CMD); 833 hqvdp->regs + HQVDP_MBX_NEXT_CMD);
601 834
602 hqvdp->curr_field_count++;
603 hqvdp->btm_field_pending = false; 835 hqvdp->btm_field_pending = false;
604 836
605 dev_dbg(hqvdp->dev, "%s Posted command:0x%x\n", 837 dev_dbg(hqvdp->dev, "%s Posted command:0x%x\n",
606 __func__, hqvdp->hqvdp_cmd_paddr); 838 __func__, hqvdp->hqvdp_cmd_paddr);
839
840 sti_plane_update_fps(&hqvdp->plane, false, true);
607 } 841 }
608 842
609 return 0; 843 return 0;
@@ -612,19 +846,21 @@ int sti_hqvdp_vtg_cb(struct notifier_block *nb, unsigned long evt, void *data)
612static void sti_hqvdp_init(struct sti_hqvdp *hqvdp) 846static void sti_hqvdp_init(struct sti_hqvdp *hqvdp)
613{ 847{
614 int size; 848 int size;
849 dma_addr_t dma_addr;
615 850
616 hqvdp->vtg_nb.notifier_call = sti_hqvdp_vtg_cb; 851 hqvdp->vtg_nb.notifier_call = sti_hqvdp_vtg_cb;
617 852
618 /* Allocate memory for the VDP commands */ 853 /* Allocate memory for the VDP commands */
619 size = NB_VDP_CMD * sizeof(struct sti_hqvdp_cmd); 854 size = NB_VDP_CMD * sizeof(struct sti_hqvdp_cmd);
620 hqvdp->hqvdp_cmd = dma_alloc_writecombine(hqvdp->dev, size, 855 hqvdp->hqvdp_cmd = dma_alloc_writecombine(hqvdp->dev, size,
621 &hqvdp->hqvdp_cmd_paddr, 856 &dma_addr,
622 GFP_KERNEL | GFP_DMA); 857 GFP_KERNEL | GFP_DMA);
623 if (!hqvdp->hqvdp_cmd) { 858 if (!hqvdp->hqvdp_cmd) {
624 DRM_ERROR("Failed to allocate memory for VDP cmd\n"); 859 DRM_ERROR("Failed to allocate memory for VDP cmd\n");
625 return; 860 return;
626 } 861 }
627 862
863 hqvdp->hqvdp_cmd_paddr = (u32)dma_addr;
628 memset(hqvdp->hqvdp_cmd, 0, size); 864 memset(hqvdp->hqvdp_cmd, 0, size);
629} 865}
630 866
@@ -670,7 +906,7 @@ static void sti_hqvdp_start_xp70(struct sti_hqvdp *hqvdp)
670 DRM_DEBUG_DRIVER("\n"); 906 DRM_DEBUG_DRIVER("\n");
671 907
672 if (hqvdp->xp70_initialized) { 908 if (hqvdp->xp70_initialized) {
673 DRM_INFO("HQVDP XP70 already initialized\n"); 909 DRM_DEBUG_DRIVER("HQVDP XP70 already initialized\n");
674 return; 910 return;
675 } 911 }
676 912
@@ -775,53 +1011,131 @@ out:
775 release_firmware(firmware); 1011 release_firmware(firmware);
776} 1012}
777 1013
778static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane, 1014static int sti_hqvdp_atomic_check(struct drm_plane *drm_plane,
779 struct drm_plane_state *oldstate) 1015 struct drm_plane_state *state)
780{ 1016{
781 struct drm_plane_state *state = drm_plane->state;
782 struct sti_plane *plane = to_sti_plane(drm_plane); 1017 struct sti_plane *plane = to_sti_plane(drm_plane);
783 struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane); 1018 struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane);
784 struct drm_crtc *crtc = state->crtc; 1019 struct drm_crtc *crtc = state->crtc;
785 struct sti_mixer *mixer = to_sti_mixer(crtc);
786 struct drm_framebuffer *fb = state->fb; 1020 struct drm_framebuffer *fb = state->fb;
787 struct drm_display_mode *mode = &crtc->mode;
788 int dst_x = state->crtc_x;
789 int dst_y = state->crtc_y;
790 int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
791 int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
792 /* src_x are in 16.16 format */
793 int src_x = state->src_x >> 16;
794 int src_y = state->src_y >> 16;
795 int src_w = state->src_w >> 16;
796 int src_h = state->src_h >> 16;
797 bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false; 1021 bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false;
798 struct drm_gem_cma_object *cma_obj; 1022 struct drm_crtc_state *crtc_state;
799 struct sti_hqvdp_cmd *cmd; 1023 struct drm_display_mode *mode;
800 int scale_h, scale_v; 1024 int dst_x, dst_y, dst_w, dst_h;
801 int cmd_offset; 1025 int src_x, src_y, src_w, src_h;
1026
1027 /* no need for further checks if the plane is being disabled */
1028 if (!crtc || !fb)
1029 return 0;
1030
1031 crtc_state = drm_atomic_get_crtc_state(state->state, crtc);
1032 mode = &crtc_state->mode;
1033 dst_x = state->crtc_x;
1034 dst_y = state->crtc_y;
1035 dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
1036 dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
1037 /* src_x are in 16.16 format */
1038 src_x = state->src_x >> 16;
1039 src_y = state->src_y >> 16;
1040 src_w = state->src_w >> 16;
1041 src_h = state->src_h >> 16;
1042
1043 if (!sti_hqvdp_check_hw_scaling(hqvdp, mode,
1044 src_w, src_h,
1045 dst_w, dst_h)) {
1046 DRM_ERROR("Scaling beyond HW capabilities\n");
1047 return -EINVAL;
1048 }
1049
1050 if (!drm_fb_cma_get_gem_obj(fb, 0)) {
1051 DRM_ERROR("Can't get CMA GEM object for fb\n");
1052 return -EINVAL;
1053 }
1054
1055 /*
1056 * Input / output size
1057 * Align to upper even value
1058 */
1059 dst_w = ALIGN(dst_w, 2);
1060 dst_h = ALIGN(dst_h, 2);
1061
1062 if ((src_w > MAX_WIDTH) || (src_w < MIN_WIDTH) ||
1063 (src_h > MAX_HEIGHT) || (src_h < MIN_HEIGHT) ||
1064 (dst_w > MAX_WIDTH) || (dst_w < MIN_WIDTH) ||
1065 (dst_h > MAX_HEIGHT) || (dst_h < MIN_HEIGHT)) {
1066 DRM_ERROR("Invalid in/out size %dx%d -> %dx%d\n",
1067 src_w, src_h,
1068 dst_w, dst_h);
1069 return -EINVAL;
1070 }
1071
1072 if (first_prepare) {
1073 /* Start HQVDP XP70 coprocessor */
1074 sti_hqvdp_start_xp70(hqvdp);
1075
1076 /* Prevent VTG shutdown */
1077 if (clk_prepare_enable(hqvdp->clk_pix_main)) {
1078 DRM_ERROR("Failed to prepare/enable pix main clk\n");
1079 return -EINVAL;
1080 }
1081
1082 /* Register VTG Vsync callback to handle bottom fields */
1083 if (sti_vtg_register_client(hqvdp->vtg,
1084 &hqvdp->vtg_nb,
1085 crtc)) {
1086 DRM_ERROR("Cannot register VTG notifier\n");
1087 return -EINVAL;
1088 }
1089 }
802 1090
803 DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n", 1091 DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n",
804 crtc->base.id, sti_mixer_to_str(mixer), 1092 crtc->base.id, sti_mixer_to_str(to_sti_mixer(crtc)),
805 drm_plane->base.id, sti_plane_to_str(plane)); 1093 drm_plane->base.id, sti_plane_to_str(plane));
806 DRM_DEBUG_KMS("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n", 1094 DRM_DEBUG_KMS("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n",
807 sti_plane_to_str(plane), 1095 sti_plane_to_str(plane),
808 dst_w, dst_h, dst_x, dst_y, 1096 dst_w, dst_h, dst_x, dst_y,
809 src_w, src_h, src_x, src_y); 1097 src_w, src_h, src_x, src_y);
810 1098
1099 return 0;
1100}
1101
1102static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane,
1103 struct drm_plane_state *oldstate)
1104{
1105 struct drm_plane_state *state = drm_plane->state;
1106 struct sti_plane *plane = to_sti_plane(drm_plane);
1107 struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane);
1108 struct drm_crtc *crtc = state->crtc;
1109 struct drm_framebuffer *fb = state->fb;
1110 struct drm_display_mode *mode;
1111 int dst_x, dst_y, dst_w, dst_h;
1112 int src_x, src_y, src_w, src_h;
1113 struct drm_gem_cma_object *cma_obj;
1114 struct sti_hqvdp_cmd *cmd;
1115 int scale_h, scale_v;
1116 int cmd_offset;
1117
1118 if (!crtc || !fb)
1119 return;
1120
1121 mode = &crtc->mode;
1122 dst_x = state->crtc_x;
1123 dst_y = state->crtc_y;
1124 dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
1125 dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
1126 /* src_x are in 16.16 format */
1127 src_x = state->src_x >> 16;
1128 src_y = state->src_y >> 16;
1129 src_w = state->src_w >> 16;
1130 src_h = state->src_h >> 16;
1131
811 cmd_offset = sti_hqvdp_get_free_cmd(hqvdp); 1132 cmd_offset = sti_hqvdp_get_free_cmd(hqvdp);
812 if (cmd_offset == -1) { 1133 if (cmd_offset == -1) {
813 DRM_ERROR("No available hqvdp_cmd now\n"); 1134 DRM_DEBUG_DRIVER("Warning: no cmd, will skip frame\n");
814 return; 1135 return;
815 } 1136 }
816 cmd = hqvdp->hqvdp_cmd + cmd_offset; 1137 cmd = hqvdp->hqvdp_cmd + cmd_offset;
817 1138
818 if (!sti_hqvdp_check_hw_scaling(hqvdp, mode,
819 src_w, src_h,
820 dst_w, dst_h)) {
821 DRM_ERROR("Scaling beyond HW capabilities\n");
822 return;
823 }
824
825 /* Static parameters, defaulting to progressive mode */ 1139 /* Static parameters, defaulting to progressive mode */
826 cmd->top.config = TOP_CONFIG_PROGRESSIVE; 1140 cmd->top.config = TOP_CONFIG_PROGRESSIVE;
827 cmd->top.mem_format = TOP_MEM_FORMAT_DFLT; 1141 cmd->top.mem_format = TOP_MEM_FORMAT_DFLT;
@@ -836,10 +1150,6 @@ static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane,
836 cmd->iqi.pxf_conf = IQI_PXF_CONF_DFLT; 1150 cmd->iqi.pxf_conf = IQI_PXF_CONF_DFLT;
837 1151
838 cma_obj = drm_fb_cma_get_gem_obj(fb, 0); 1152 cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
839 if (!cma_obj) {
840 DRM_ERROR("Can't get CMA GEM object for fb\n");
841 return;
842 }
843 1153
844 DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id, 1154 DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id,
845 (char *)&fb->pixel_format, 1155 (char *)&fb->pixel_format,
@@ -860,16 +1170,6 @@ static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane,
860 dst_w = ALIGN(dst_w, 2); 1170 dst_w = ALIGN(dst_w, 2);
861 dst_h = ALIGN(dst_h, 2); 1171 dst_h = ALIGN(dst_h, 2);
862 1172
863 if ((src_w > MAX_WIDTH) || (src_w < MIN_WIDTH) ||
864 (src_h > MAX_HEIGHT) || (src_h < MIN_HEIGHT) ||
865 (dst_w > MAX_WIDTH) || (dst_w < MIN_WIDTH) ||
866 (dst_h > MAX_HEIGHT) || (dst_h < MIN_HEIGHT)) {
867 DRM_ERROR("Invalid in/out size %dx%d -> %dx%d\n",
868 src_w, src_h,
869 dst_w, dst_h);
870 return;
871 }
872
873 cmd->top.input_viewport_size = src_h << 16 | src_w; 1173 cmd->top.input_viewport_size = src_h << 16 | src_w;
874 cmd->top.input_frame_size = src_h << 16 | src_w; 1174 cmd->top.input_frame_size = src_h << 16 | src_w;
875 cmd->hvsrc.output_picture_size = dst_h << 16 | dst_w; 1175 cmd->hvsrc.output_picture_size = dst_h << 16 | dst_w;
@@ -900,30 +1200,9 @@ static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane,
900 scale_v = SCALE_FACTOR * dst_h / src_h; 1200 scale_v = SCALE_FACTOR * dst_h / src_h;
901 sti_hqvdp_update_hvsrc(HVSRC_VERT, scale_v, &cmd->hvsrc); 1201 sti_hqvdp_update_hvsrc(HVSRC_VERT, scale_v, &cmd->hvsrc);
902 1202
903 if (first_prepare) {
904 /* Start HQVDP XP70 coprocessor */
905 sti_hqvdp_start_xp70(hqvdp);
906
907 /* Prevent VTG shutdown */
908 if (clk_prepare_enable(hqvdp->clk_pix_main)) {
909 DRM_ERROR("Failed to prepare/enable pix main clk\n");
910 return;
911 }
912
913 /* Register VTG Vsync callback to handle bottom fields */
914 if (sti_vtg_register_client(hqvdp->vtg,
915 &hqvdp->vtg_nb,
916 crtc)) {
917 DRM_ERROR("Cannot register VTG notifier\n");
918 return;
919 }
920 }
921
922 writel(hqvdp->hqvdp_cmd_paddr + cmd_offset, 1203 writel(hqvdp->hqvdp_cmd_paddr + cmd_offset,
923 hqvdp->regs + HQVDP_MBX_NEXT_CMD); 1204 hqvdp->regs + HQVDP_MBX_NEXT_CMD);
924 1205
925 hqvdp->curr_field_count++;
926
927 /* Interlaced : get ready to display the bottom field at next Vsync */ 1206 /* Interlaced : get ready to display the bottom field at next Vsync */
928 if (fb->flags & DRM_MODE_FB_INTERLACED) 1207 if (fb->flags & DRM_MODE_FB_INTERLACED)
929 hqvdp->btm_field_pending = true; 1208 hqvdp->btm_field_pending = true;
@@ -931,6 +1210,8 @@ static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane,
931 dev_dbg(hqvdp->dev, "%s Posted command:0x%x\n", 1210 dev_dbg(hqvdp->dev, "%s Posted command:0x%x\n",
932 __func__, hqvdp->hqvdp_cmd_paddr + cmd_offset); 1211 __func__, hqvdp->hqvdp_cmd_paddr + cmd_offset);
933 1212
1213 sti_plane_update_fps(plane, true, true);
1214
934 plane->status = STI_PLANE_UPDATED; 1215 plane->status = STI_PLANE_UPDATED;
935} 1216}
936 1217
@@ -938,7 +1219,6 @@ static void sti_hqvdp_atomic_disable(struct drm_plane *drm_plane,
938 struct drm_plane_state *oldstate) 1219 struct drm_plane_state *oldstate)
939{ 1220{
940 struct sti_plane *plane = to_sti_plane(drm_plane); 1221 struct sti_plane *plane = to_sti_plane(drm_plane);
941 struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
942 1222
943 if (!drm_plane->crtc) { 1223 if (!drm_plane->crtc) {
944 DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", 1224 DRM_DEBUG_DRIVER("drm plane:%d not enabled\n",
@@ -947,13 +1227,15 @@ static void sti_hqvdp_atomic_disable(struct drm_plane *drm_plane,
947 } 1227 }
948 1228
949 DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n", 1229 DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n",
950 drm_plane->crtc->base.id, sti_mixer_to_str(mixer), 1230 drm_plane->crtc->base.id,
1231 sti_mixer_to_str(to_sti_mixer(drm_plane->crtc)),
951 drm_plane->base.id, sti_plane_to_str(plane)); 1232 drm_plane->base.id, sti_plane_to_str(plane));
952 1233
953 plane->status = STI_PLANE_DISABLING; 1234 plane->status = STI_PLANE_DISABLING;
954} 1235}
955 1236
956static const struct drm_plane_helper_funcs sti_hqvdp_helpers_funcs = { 1237static const struct drm_plane_helper_funcs sti_hqvdp_helpers_funcs = {
1238 .atomic_check = sti_hqvdp_atomic_check,
957 .atomic_update = sti_hqvdp_atomic_update, 1239 .atomic_update = sti_hqvdp_atomic_update,
958 .atomic_disable = sti_hqvdp_atomic_disable, 1240 .atomic_disable = sti_hqvdp_atomic_disable,
959}; 1241};
@@ -983,6 +1265,9 @@ static struct drm_plane *sti_hqvdp_create(struct drm_device *drm_dev,
983 1265
984 sti_plane_init_property(&hqvdp->plane, DRM_PLANE_TYPE_OVERLAY); 1266 sti_plane_init_property(&hqvdp->plane, DRM_PLANE_TYPE_OVERLAY);
985 1267
1268 if (hqvdp_debugfs_init(hqvdp, drm_dev->primary))
1269 DRM_ERROR("HQVDP debugfs setup failed\n");
1270
986 return &hqvdp->plane.drm_plane; 1271 return &hqvdp->plane.drm_plane;
987} 1272}
988 1273
diff --git a/drivers/gpu/drm/sti/sti_mixer.c b/drivers/gpu/drm/sti/sti_mixer.c
index 49db835dce03..e7425c38fc93 100644
--- a/drivers/gpu/drm/sti/sti_mixer.c
+++ b/drivers/gpu/drm/sti/sti_mixer.c
@@ -75,6 +75,145 @@ static inline void sti_mixer_reg_write(struct sti_mixer *mixer,
75 writel(val, mixer->regs + reg_id); 75 writel(val, mixer->regs + reg_id);
76} 76}
77 77
78#define DBGFS_DUMP(reg) seq_printf(s, "\n %-25s 0x%08X", #reg, \
79 sti_mixer_reg_read(mixer, reg))
80
81static void mixer_dbg_ctl(struct seq_file *s, int val)
82{
83 unsigned int i;
84 int count = 0;
85 char *const disp_layer[] = {"BKG", "VID0", "VID1", "GDP0",
86 "GDP1", "GDP2", "GDP3"};
87
88 seq_puts(s, "\tEnabled: ");
89 for (i = 0; i < 7; i++) {
90 if (val & 1) {
91 seq_printf(s, "%s ", disp_layer[i]);
92 count++;
93 }
94 val = val >> 1;
95 }
96
97 val = val >> 2;
98 if (val & 1) {
99 seq_puts(s, "CURS ");
100 count++;
101 }
102 if (!count)
103 seq_puts(s, "Nothing");
104}
105
106static void mixer_dbg_crb(struct seq_file *s, int val)
107{
108 int i;
109
110 seq_puts(s, "\tDepth: ");
111 for (i = 0; i < GAM_MIXER_NB_DEPTH_LEVEL; i++) {
112 switch (val & GAM_DEPTH_MASK_ID) {
113 case GAM_DEPTH_VID0_ID:
114 seq_puts(s, "VID0");
115 break;
116 case GAM_DEPTH_VID1_ID:
117 seq_puts(s, "VID1");
118 break;
119 case GAM_DEPTH_GDP0_ID:
120 seq_puts(s, "GDP0");
121 break;
122 case GAM_DEPTH_GDP1_ID:
123 seq_puts(s, "GDP1");
124 break;
125 case GAM_DEPTH_GDP2_ID:
126 seq_puts(s, "GDP2");
127 break;
128 case GAM_DEPTH_GDP3_ID:
129 seq_puts(s, "GDP3");
130 break;
131 default:
132 seq_puts(s, "---");
133 }
134
135 if (i < GAM_MIXER_NB_DEPTH_LEVEL - 1)
136 seq_puts(s, " < ");
137 val = val >> 3;
138 }
139}
140
141static void mixer_dbg_mxn(struct seq_file *s, void *addr)
142{
143 int i;
144
145 for (i = 1; i < 8; i++)
146 seq_printf(s, "-0x%08X", (int)readl(addr + i * 4));
147}
148
149static int mixer_dbg_show(struct seq_file *s, void *arg)
150{
151 struct drm_info_node *node = s->private;
152 struct sti_mixer *mixer = (struct sti_mixer *)node->info_ent->data;
153 struct drm_device *dev = node->minor->dev;
154 int ret;
155
156 ret = mutex_lock_interruptible(&dev->struct_mutex);
157 if (ret)
158 return ret;
159
160 seq_printf(s, "%s: (vaddr = 0x%p)",
161 sti_mixer_to_str(mixer), mixer->regs);
162
163 DBGFS_DUMP(GAM_MIXER_CTL);
164 mixer_dbg_ctl(s, sti_mixer_reg_read(mixer, GAM_MIXER_CTL));
165 DBGFS_DUMP(GAM_MIXER_BKC);
166 DBGFS_DUMP(GAM_MIXER_BCO);
167 DBGFS_DUMP(GAM_MIXER_BCS);
168 DBGFS_DUMP(GAM_MIXER_AVO);
169 DBGFS_DUMP(GAM_MIXER_AVS);
170 DBGFS_DUMP(GAM_MIXER_CRB);
171 mixer_dbg_crb(s, sti_mixer_reg_read(mixer, GAM_MIXER_CRB));
172 DBGFS_DUMP(GAM_MIXER_ACT);
173 DBGFS_DUMP(GAM_MIXER_MBP);
174 DBGFS_DUMP(GAM_MIXER_MX0);
175 mixer_dbg_mxn(s, mixer->regs + GAM_MIXER_MX0);
176 seq_puts(s, "\n");
177
178 mutex_unlock(&dev->struct_mutex);
179 return 0;
180}
181
182static struct drm_info_list mixer0_debugfs_files[] = {
183 { "mixer_main", mixer_dbg_show, 0, NULL },
184};
185
186static struct drm_info_list mixer1_debugfs_files[] = {
187 { "mixer_aux", mixer_dbg_show, 0, NULL },
188};
189
190static int mixer_debugfs_init(struct sti_mixer *mixer, struct drm_minor *minor)
191{
192 unsigned int i;
193 struct drm_info_list *mixer_debugfs_files;
194 int nb_files;
195
196 switch (mixer->id) {
197 case STI_MIXER_MAIN:
198 mixer_debugfs_files = mixer0_debugfs_files;
199 nb_files = ARRAY_SIZE(mixer0_debugfs_files);
200 break;
201 case STI_MIXER_AUX:
202 mixer_debugfs_files = mixer1_debugfs_files;
203 nb_files = ARRAY_SIZE(mixer1_debugfs_files);
204 break;
205 default:
206 return -EINVAL;
207 }
208
209 for (i = 0; i < nb_files; i++)
210 mixer_debugfs_files[i].data = mixer;
211
212 return drm_debugfs_create_files(mixer_debugfs_files,
213 nb_files,
214 minor->debugfs_root, minor);
215}
216
78void sti_mixer_set_background_status(struct sti_mixer *mixer, bool enable) 217void sti_mixer_set_background_status(struct sti_mixer *mixer, bool enable)
79{ 218{
80 u32 val = sti_mixer_reg_read(mixer, GAM_MIXER_CTL); 219 u32 val = sti_mixer_reg_read(mixer, GAM_MIXER_CTL);
@@ -237,7 +376,9 @@ void sti_mixer_set_matrix(struct sti_mixer *mixer)
237 mixerColorSpaceMatIdentity[i]); 376 mixerColorSpaceMatIdentity[i]);
238} 377}
239 378
240struct sti_mixer *sti_mixer_create(struct device *dev, int id, 379struct sti_mixer *sti_mixer_create(struct device *dev,
380 struct drm_device *drm_dev,
381 int id,
241 void __iomem *baseaddr) 382 void __iomem *baseaddr)
242{ 383{
243 struct sti_mixer *mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL); 384 struct sti_mixer *mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
@@ -258,5 +399,8 @@ struct sti_mixer *sti_mixer_create(struct device *dev, int id,
258 DRM_DEBUG_DRIVER("%s created. Regs=%p\n", 399 DRM_DEBUG_DRIVER("%s created. Regs=%p\n",
259 sti_mixer_to_str(mixer), mixer->regs); 400 sti_mixer_to_str(mixer), mixer->regs);
260 401
402 if (mixer_debugfs_init(mixer, drm_dev->primary))
403 DRM_ERROR("MIXER debugfs setup failed\n");
404
261 return mixer; 405 return mixer;
262} 406}
diff --git a/drivers/gpu/drm/sti/sti_mixer.h b/drivers/gpu/drm/sti/sti_mixer.h
index efb1a9a5ba86..6f35fc086873 100644
--- a/drivers/gpu/drm/sti/sti_mixer.h
+++ b/drivers/gpu/drm/sti/sti_mixer.h
@@ -42,7 +42,9 @@ struct sti_mixer {
42 42
43const char *sti_mixer_to_str(struct sti_mixer *mixer); 43const char *sti_mixer_to_str(struct sti_mixer *mixer);
44 44
45struct sti_mixer *sti_mixer_create(struct device *dev, int id, 45struct sti_mixer *sti_mixer_create(struct device *dev,
46 struct drm_device *drm_dev,
47 int id,
46 void __iomem *baseaddr); 48 void __iomem *baseaddr);
47 49
48int sti_mixer_set_plane_status(struct sti_mixer *mixer, 50int sti_mixer_set_plane_status(struct sti_mixer *mixer,
diff --git a/drivers/gpu/drm/sti/sti_plane.c b/drivers/gpu/drm/sti/sti_plane.c
index 2e5c751910c5..f10c98d3f012 100644
--- a/drivers/gpu/drm/sti/sti_plane.c
+++ b/drivers/gpu/drm/sti/sti_plane.c
@@ -43,6 +43,69 @@ const char *sti_plane_to_str(struct sti_plane *plane)
43 } 43 }
44} 44}
45 45
46#define STI_FPS_INTERVAL_MS 3000
47
48static 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
58void sti_plane_update_fps(struct sti_plane *plane,
59 bool new_frame,
60 bool new_field)
61{
62 struct timespec now;
63 struct sti_fps_info *fps;
64 int fpks, fipks, ms_since_last, num_frames, num_fields;
65
66 getrawmonotonic(&now);
67
68 /* Compute number of frame updates */
69 fps = &plane->fps_info;
70
71 if (new_field)
72 fps->curr_field_counter++;
73
74 /* do not perform fps calcul if new_frame is false */
75 if (!new_frame)
76 return;
77
78 fps->curr_frame_counter++;
79 ms_since_last = sti_plane_timespec_ms_diff(now, fps->last_timestamp);
80 num_frames = fps->curr_frame_counter - fps->last_frame_counter;
81
82 if (num_frames <= 0 || ms_since_last < STI_FPS_INTERVAL_MS)
83 return;
84
85 fps->last_timestamp = now;
86 fps->last_frame_counter = fps->curr_frame_counter;
87 fpks = (num_frames * 1000000) / ms_since_last;
88 snprintf(plane->fps_info.fps_str, FPS_LENGTH, "%-6s @ %d.%.3d fps",
89 sti_plane_to_str(plane), fpks / 1000, fpks % 1000);
90
91 if (fps->curr_field_counter) {
92 /* Compute number of field updates */
93 num_fields = fps->curr_field_counter - fps->last_field_counter;
94 fps->last_field_counter = fps->curr_field_counter;
95 fipks = (num_fields * 1000000) / ms_since_last;
96 snprintf(plane->fps_info.fips_str,
97 FPS_LENGTH, " - %d.%.3d field/sec",
98 fipks / 1000, fipks % 1000);
99 } else {
100 plane->fps_info.fips_str[0] = '\0';
101 }
102
103 if (fps->output)
104 DRM_INFO("%s%s\n",
105 plane->fps_info.fps_str,
106 plane->fps_info.fips_str);
107}
108
46static void sti_plane_destroy(struct drm_plane *drm_plane) 109static void sti_plane_destroy(struct drm_plane *drm_plane)
47{ 110{
48 DRM_DEBUG_DRIVER("\n"); 111 DRM_DEBUG_DRIVER("\n");
diff --git a/drivers/gpu/drm/sti/sti_plane.h b/drivers/gpu/drm/sti/sti_plane.h
index 86f1e6fc81b9..c50a3b9f5d37 100644
--- a/drivers/gpu/drm/sti/sti_plane.h
+++ b/drivers/gpu/drm/sti/sti_plane.h
@@ -50,6 +50,18 @@ enum sti_plane_status {
50 STI_PLANE_DISABLED, 50 STI_PLANE_DISABLED,
51}; 51};
52 52
53#define FPS_LENGTH 64
54struct sti_fps_info {
55 bool output;
56 unsigned int curr_frame_counter;
57 unsigned int last_frame_counter;
58 unsigned int curr_field_counter;
59 unsigned int last_field_counter;
60 struct timespec last_timestamp;
61 char fps_str[FPS_LENGTH];
62 char fips_str[FPS_LENGTH];
63};
64
53/** 65/**
54 * STI plane structure 66 * STI plane structure
55 * 67 *
@@ -57,15 +69,20 @@ enum sti_plane_status {
57 * @desc: plane type & id 69 * @desc: plane type & id
58 * @status: to know the status of the plane 70 * @status: to know the status of the plane
59 * @zorder: plane z-order 71 * @zorder: plane z-order
72 * @fps_info: frame per second info
60 */ 73 */
61struct sti_plane { 74struct sti_plane {
62 struct drm_plane drm_plane; 75 struct drm_plane drm_plane;
63 enum sti_plane_desc desc; 76 enum sti_plane_desc desc;
64 enum sti_plane_status status; 77 enum sti_plane_status status;
65 int zorder; 78 int zorder;
79 struct sti_fps_info fps_info;
66}; 80};
67 81
68const char *sti_plane_to_str(struct sti_plane *plane); 82const char *sti_plane_to_str(struct sti_plane *plane);
83void sti_plane_update_fps(struct sti_plane *plane,
84 bool new_frame,
85 bool new_field);
69void sti_plane_init_property(struct sti_plane *plane, 86void sti_plane_init_property(struct sti_plane *plane,
70 enum drm_plane_type type); 87 enum drm_plane_type type);
71#endif 88#endif
diff --git a/drivers/gpu/drm/sti/sti_tvout.c b/drivers/gpu/drm/sti/sti_tvout.c
index 24a3735b88fd..2c99016443e5 100644
--- a/drivers/gpu/drm/sti/sti_tvout.c
+++ b/drivers/gpu/drm/sti/sti_tvout.c
@@ -17,6 +17,7 @@
17#include <drm/drm_crtc_helper.h> 17#include <drm/drm_crtc_helper.h>
18 18
19#include "sti_crtc.h" 19#include "sti_crtc.h"
20#include "sti_vtg.h"
20 21
21/* glue registers */ 22/* glue registers */
22#define TVO_CSC_MAIN_M0 0x000 23#define TVO_CSC_MAIN_M0 0x000
@@ -85,19 +86,7 @@
85#define TVO_VIP_SEL_INPUT_BYPASSED 1 86#define TVO_VIP_SEL_INPUT_BYPASSED 1
86 87
87#define TVO_SYNC_MAIN_VTG_SET_REF 0x00 88#define TVO_SYNC_MAIN_VTG_SET_REF 0x00
88#define TVO_SYNC_MAIN_VTG_SET_1 0x01
89#define TVO_SYNC_MAIN_VTG_SET_2 0x02
90#define TVO_SYNC_MAIN_VTG_SET_3 0x03
91#define TVO_SYNC_MAIN_VTG_SET_4 0x04
92#define TVO_SYNC_MAIN_VTG_SET_5 0x05
93#define TVO_SYNC_MAIN_VTG_SET_6 0x06
94#define TVO_SYNC_AUX_VTG_SET_REF 0x10 89#define TVO_SYNC_AUX_VTG_SET_REF 0x10
95#define TVO_SYNC_AUX_VTG_SET_1 0x11
96#define TVO_SYNC_AUX_VTG_SET_2 0x12
97#define TVO_SYNC_AUX_VTG_SET_3 0x13
98#define TVO_SYNC_AUX_VTG_SET_4 0x14
99#define TVO_SYNC_AUX_VTG_SET_5 0x15
100#define TVO_SYNC_AUX_VTG_SET_6 0x16
101 90
102#define TVO_SYNC_HD_DCS_SHIFT 8 91#define TVO_SYNC_HD_DCS_SHIFT 8
103 92
@@ -106,6 +95,8 @@
106 95
107#define ENCODER_CRTC_MASK (BIT(0) | BIT(1)) 96#define ENCODER_CRTC_MASK (BIT(0) | BIT(1))
108 97
98#define TVO_MIN_HD_HEIGHT 720
99
109/* enum listing the supported output data format */ 100/* enum listing the supported output data format */
110enum sti_tvout_video_out_type { 101enum sti_tvout_video_out_type {
111 STI_TVOUT_VIDEO_OUT_RGB, 102 STI_TVOUT_VIDEO_OUT_RGB,
@@ -269,6 +260,31 @@ static void tvout_vip_set_in_vid_fmt(struct sti_tvout *tvout,
269} 260}
270 261
271/** 262/**
263 * Set preformatter matrix
264 *
265 * @tvout: tvout structure
266 * @mode: display mode structure
267 */
268static void tvout_preformatter_set_matrix(struct sti_tvout *tvout,
269 struct drm_display_mode *mode)
270{
271 unsigned int i;
272 const u32 *pf_matrix;
273
274 if (mode->vdisplay >= TVO_MIN_HD_HEIGHT)
275 pf_matrix = rgb_to_ycbcr_709;
276 else
277 pf_matrix = rgb_to_ycbcr_601;
278
279 for (i = 0; i < 8; i++) {
280 tvout_write(tvout, *(pf_matrix + i),
281 TVO_CSC_MAIN_M0 + (i * 4));
282 tvout_write(tvout, *(pf_matrix + i),
283 TVO_CSC_AUX_M0 + (i * 4));
284 }
285}
286
287/**
272 * Start VIP block for DVO output 288 * Start VIP block for DVO output
273 * 289 *
274 * @tvout: pointer on tvout structure 290 * @tvout: pointer on tvout structure
@@ -280,24 +296,26 @@ static void tvout_dvo_start(struct sti_tvout *tvout, bool main_path)
280 struct device_node *node = tvout->dev->of_node; 296 struct device_node *node = tvout->dev->of_node;
281 bool sel_input_logic_inverted = false; 297 bool sel_input_logic_inverted = false;
282 u32 tvo_in_vid_format; 298 u32 tvo_in_vid_format;
283 int val; 299 int val, tmp;
284 300
285 dev_dbg(tvout->dev, "%s\n", __func__); 301 dev_dbg(tvout->dev, "%s\n", __func__);
286 302
287 if (main_path) { 303 if (main_path) {
288 DRM_DEBUG_DRIVER("main vip for DVO\n"); 304 DRM_DEBUG_DRIVER("main vip for DVO\n");
289 /* Select the input sync for dvo = VTG set 4 */ 305 /* Select the input sync for dvo */
290 val = TVO_SYNC_MAIN_VTG_SET_4 << TVO_SYNC_DVO_PAD_VSYNC_SHIFT; 306 tmp = TVO_SYNC_MAIN_VTG_SET_REF | VTG_SYNC_ID_DVO;
291 val |= TVO_SYNC_MAIN_VTG_SET_4 << TVO_SYNC_DVO_PAD_HSYNC_SHIFT; 307 val = tmp << TVO_SYNC_DVO_PAD_VSYNC_SHIFT;
292 val |= TVO_SYNC_MAIN_VTG_SET_4; 308 val |= tmp << TVO_SYNC_DVO_PAD_HSYNC_SHIFT;
309 val |= tmp;
293 tvout_write(tvout, val, TVO_DVO_SYNC_SEL); 310 tvout_write(tvout, val, TVO_DVO_SYNC_SEL);
294 tvo_in_vid_format = TVO_MAIN_IN_VID_FORMAT; 311 tvo_in_vid_format = TVO_MAIN_IN_VID_FORMAT;
295 } else { 312 } else {
296 DRM_DEBUG_DRIVER("aux vip for DVO\n"); 313 DRM_DEBUG_DRIVER("aux vip for DVO\n");
297 /* Select the input sync for dvo = VTG set 4 */ 314 /* Select the input sync for dvo */
298 val = TVO_SYNC_AUX_VTG_SET_4 << TVO_SYNC_DVO_PAD_VSYNC_SHIFT; 315 tmp = TVO_SYNC_AUX_VTG_SET_REF | VTG_SYNC_ID_DVO;
299 val |= TVO_SYNC_AUX_VTG_SET_4 << TVO_SYNC_DVO_PAD_HSYNC_SHIFT; 316 val = tmp << TVO_SYNC_DVO_PAD_VSYNC_SHIFT;
300 val |= TVO_SYNC_AUX_VTG_SET_4; 317 val |= tmp << TVO_SYNC_DVO_PAD_HSYNC_SHIFT;
318 val |= tmp;
301 tvout_write(tvout, val, TVO_DVO_SYNC_SEL); 319 tvout_write(tvout, val, TVO_DVO_SYNC_SEL);
302 tvo_in_vid_format = TVO_AUX_IN_VID_FORMAT; 320 tvo_in_vid_format = TVO_AUX_IN_VID_FORMAT;
303 } 321 }
@@ -308,9 +326,8 @@ static void tvout_dvo_start(struct sti_tvout *tvout, bool main_path)
308 TVO_VIP_REORDER_Y_G_SEL, 326 TVO_VIP_REORDER_Y_G_SEL,
309 TVO_VIP_REORDER_CB_B_SEL); 327 TVO_VIP_REORDER_CB_B_SEL);
310 328
311 /* Set clipping mode (Limited range RGB/Y) */ 329 /* Set clipping mode */
312 tvout_vip_set_clip_mode(tvout, TVO_VIP_DVO, 330 tvout_vip_set_clip_mode(tvout, TVO_VIP_DVO, TVO_VIP_CLIP_DISABLED);
313 TVO_VIP_CLIP_LIMITED_RANGE_RGB_Y);
314 331
315 /* Set round mode (rounded to 8-bit per component) */ 332 /* Set round mode (rounded to 8-bit per component) */
316 tvout_vip_set_rnd(tvout, TVO_VIP_DVO, TVO_VIP_RND_8BIT_ROUNDED); 333 tvout_vip_set_rnd(tvout, TVO_VIP_DVO, TVO_VIP_RND_8BIT_ROUNDED);
@@ -345,13 +362,17 @@ static void tvout_hdmi_start(struct sti_tvout *tvout, bool main_path)
345 362
346 if (main_path) { 363 if (main_path) {
347 DRM_DEBUG_DRIVER("main vip for hdmi\n"); 364 DRM_DEBUG_DRIVER("main vip for hdmi\n");
348 /* select the input sync for hdmi = VTG set 1 */ 365 /* select the input sync for hdmi */
349 tvout_write(tvout, TVO_SYNC_MAIN_VTG_SET_1, TVO_HDMI_SYNC_SEL); 366 tvout_write(tvout,
367 TVO_SYNC_MAIN_VTG_SET_REF | VTG_SYNC_ID_HDMI,
368 TVO_HDMI_SYNC_SEL);
350 tvo_in_vid_format = TVO_MAIN_IN_VID_FORMAT; 369 tvo_in_vid_format = TVO_MAIN_IN_VID_FORMAT;
351 } else { 370 } else {
352 DRM_DEBUG_DRIVER("aux vip for hdmi\n"); 371 DRM_DEBUG_DRIVER("aux vip for hdmi\n");
353 /* select the input sync for hdmi = VTG set 1 */ 372 /* select the input sync for hdmi */
354 tvout_write(tvout, TVO_SYNC_AUX_VTG_SET_1, TVO_HDMI_SYNC_SEL); 373 tvout_write(tvout,
374 TVO_SYNC_AUX_VTG_SET_REF | VTG_SYNC_ID_HDMI,
375 TVO_HDMI_SYNC_SEL);
355 tvo_in_vid_format = TVO_AUX_IN_VID_FORMAT; 376 tvo_in_vid_format = TVO_AUX_IN_VID_FORMAT;
356 } 377 }
357 378
@@ -361,9 +382,8 @@ static void tvout_hdmi_start(struct sti_tvout *tvout, bool main_path)
361 TVO_VIP_REORDER_Y_G_SEL, 382 TVO_VIP_REORDER_Y_G_SEL,
362 TVO_VIP_REORDER_CB_B_SEL); 383 TVO_VIP_REORDER_CB_B_SEL);
363 384
364 /* set clipping mode (Limited range RGB/Y) */ 385 /* set clipping mode */
365 tvout_vip_set_clip_mode(tvout, TVO_VIP_HDMI, 386 tvout_vip_set_clip_mode(tvout, TVO_VIP_HDMI, TVO_VIP_CLIP_DISABLED);
366 TVO_VIP_CLIP_LIMITED_RANGE_RGB_Y);
367 387
368 /* set round mode (rounded to 8-bit per component) */ 388 /* set round mode (rounded to 8-bit per component) */
369 tvout_vip_set_rnd(tvout, TVO_VIP_HDMI, TVO_VIP_RND_8BIT_ROUNDED); 389 tvout_vip_set_rnd(tvout, TVO_VIP_HDMI, TVO_VIP_RND_8BIT_ROUNDED);
@@ -397,13 +417,19 @@ static void tvout_hda_start(struct sti_tvout *tvout, bool main_path)
397 dev_dbg(tvout->dev, "%s\n", __func__); 417 dev_dbg(tvout->dev, "%s\n", __func__);
398 418
399 if (main_path) { 419 if (main_path) {
400 val = TVO_SYNC_MAIN_VTG_SET_2 << TVO_SYNC_HD_DCS_SHIFT; 420 DRM_DEBUG_DRIVER("main vip for HDF\n");
401 val |= TVO_SYNC_MAIN_VTG_SET_3; 421 /* Select the input sync for HD analog and HD DCS */
422 val = TVO_SYNC_MAIN_VTG_SET_REF | VTG_SYNC_ID_HDDCS;
423 val = val << TVO_SYNC_HD_DCS_SHIFT;
424 val |= TVO_SYNC_MAIN_VTG_SET_REF | VTG_SYNC_ID_HDF;
402 tvout_write(tvout, val, TVO_HD_SYNC_SEL); 425 tvout_write(tvout, val, TVO_HD_SYNC_SEL);
403 tvo_in_vid_format = TVO_MAIN_IN_VID_FORMAT; 426 tvo_in_vid_format = TVO_MAIN_IN_VID_FORMAT;
404 } else { 427 } else {
405 val = TVO_SYNC_AUX_VTG_SET_2 << TVO_SYNC_HD_DCS_SHIFT; 428 DRM_DEBUG_DRIVER("aux vip for HDF\n");
406 val |= TVO_SYNC_AUX_VTG_SET_3; 429 /* Select the input sync for HD analog and HD DCS */
430 val = TVO_SYNC_AUX_VTG_SET_REF | VTG_SYNC_ID_HDDCS;
431 val = val << TVO_SYNC_HD_DCS_SHIFT;
432 val |= TVO_SYNC_AUX_VTG_SET_REF | VTG_SYNC_ID_HDF;
407 tvout_write(tvout, val, TVO_HD_SYNC_SEL); 433 tvout_write(tvout, val, TVO_HD_SYNC_SEL);
408 tvo_in_vid_format = TVO_AUX_IN_VID_FORMAT; 434 tvo_in_vid_format = TVO_AUX_IN_VID_FORMAT;
409 } 435 }
@@ -414,8 +440,8 @@ static void tvout_hda_start(struct sti_tvout *tvout, bool main_path)
414 TVO_VIP_REORDER_Y_G_SEL, 440 TVO_VIP_REORDER_Y_G_SEL,
415 TVO_VIP_REORDER_CB_B_SEL); 441 TVO_VIP_REORDER_CB_B_SEL);
416 442
417 /* set clipping mode (EAV/SAV clipping) */ 443 /* set clipping mode */
418 tvout_vip_set_clip_mode(tvout, TVO_VIP_HDF, TVO_VIP_CLIP_EAV_SAV); 444 tvout_vip_set_clip_mode(tvout, TVO_VIP_HDF, TVO_VIP_CLIP_DISABLED);
419 445
420 /* set round mode (rounded to 10-bit per component) */ 446 /* set round mode (rounded to 10-bit per component) */
421 tvout_vip_set_rnd(tvout, TVO_VIP_HDF, TVO_VIP_RND_10BIT_ROUNDED); 447 tvout_vip_set_rnd(tvout, TVO_VIP_HDF, TVO_VIP_RND_10BIT_ROUNDED);
@@ -436,6 +462,157 @@ static void tvout_hda_start(struct sti_tvout *tvout, bool main_path)
436 tvout_write(tvout, 0, TVO_HD_DAC_CFG_OFF); 462 tvout_write(tvout, 0, TVO_HD_DAC_CFG_OFF);
437} 463}
438 464
465#define DBGFS_DUMP(reg) seq_printf(s, "\n %-25s 0x%08X", #reg, \
466 readl(tvout->regs + reg))
467
468static void tvout_dbg_vip(struct seq_file *s, int val)
469{
470 int r, g, b, tmp, mask;
471 char *const reorder[] = {"Y_G", "Cb_B", "Cr_R"};
472 char *const clipping[] = {"No", "EAV/SAV", "Limited range RGB/Y",
473 "Limited range Cb/Cr", "decided by register"};
474 char *const round[] = {"8-bit", "10-bit", "12-bit"};
475 char *const input_sel[] = {"Main (color matrix enabled)",
476 "Main (color matrix by-passed)",
477 "", "", "", "", "", "",
478 "Aux (color matrix enabled)",
479 "Aux (color matrix by-passed)",
480 "", "", "", "", "", "Force value"};
481
482 seq_puts(s, "\t");
483 mask = TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_R_SHIFT;
484 r = (val & mask) >> TVO_VIP_REORDER_R_SHIFT;
485 mask = TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_G_SHIFT;
486 g = (val & mask) >> TVO_VIP_REORDER_G_SHIFT;
487 mask = TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_B_SHIFT;
488 b = (val & mask) >> TVO_VIP_REORDER_B_SHIFT;
489 seq_printf(s, "%-24s %s->%s %s->%s %s->%s\n", "Reorder:",
490 reorder[r], reorder[TVO_VIP_REORDER_CR_R_SEL],
491 reorder[g], reorder[TVO_VIP_REORDER_Y_G_SEL],
492 reorder[b], reorder[TVO_VIP_REORDER_CB_B_SEL]);
493 seq_puts(s, "\t\t\t\t\t");
494 mask = TVO_VIP_CLIP_MASK << TVO_VIP_CLIP_SHIFT;
495 tmp = (val & mask) >> TVO_VIP_CLIP_SHIFT;
496 seq_printf(s, "%-24s %s\n", "Clipping:", clipping[tmp]);
497 seq_puts(s, "\t\t\t\t\t");
498 mask = TVO_VIP_RND_MASK << TVO_VIP_RND_SHIFT;
499 tmp = (val & mask) >> TVO_VIP_RND_SHIFT;
500 seq_printf(s, "%-24s input data rounded to %s per component\n",
501 "Round:", round[tmp]);
502 seq_puts(s, "\t\t\t\t\t");
503 tmp = (val & TVO_VIP_SEL_INPUT_MASK);
504 seq_printf(s, "%-24s %s", "Input selection:", input_sel[tmp]);
505}
506
507static void tvout_dbg_hd_dac_cfg(struct seq_file *s, int val)
508{
509 seq_printf(s, "\t%-24s %s", "HD DAC:",
510 val & 1 ? "disabled" : "enabled");
511}
512
513static int tvout_dbg_show(struct seq_file *s, void *data)
514{
515 struct drm_info_node *node = s->private;
516 struct sti_tvout *tvout = (struct sti_tvout *)node->info_ent->data;
517 struct drm_device *dev = node->minor->dev;
518 struct drm_crtc *crtc;
519 int ret;
520
521 ret = mutex_lock_interruptible(&dev->struct_mutex);
522 if (ret)
523 return ret;
524
525 seq_printf(s, "TVOUT: (vaddr = 0x%p)", tvout->regs);
526
527 seq_puts(s, "\n\n HDMI encoder: ");
528 crtc = tvout->hdmi->crtc;
529 if (crtc) {
530 seq_printf(s, "connected to %s path",
531 sti_crtc_is_main(crtc) ? "main" : "aux");
532 DBGFS_DUMP(TVO_HDMI_SYNC_SEL);
533 DBGFS_DUMP(TVO_VIP_HDMI);
534 tvout_dbg_vip(s, readl(tvout->regs + TVO_VIP_HDMI));
535 } else {
536 seq_puts(s, "disabled");
537 }
538
539 seq_puts(s, "\n\n DVO encoder: ");
540 crtc = tvout->dvo->crtc;
541 if (crtc) {
542 seq_printf(s, "connected to %s path",
543 sti_crtc_is_main(crtc) ? "main" : "aux");
544 DBGFS_DUMP(TVO_DVO_SYNC_SEL);
545 DBGFS_DUMP(TVO_DVO_CONFIG);
546 DBGFS_DUMP(TVO_VIP_DVO);
547 tvout_dbg_vip(s, readl(tvout->regs + TVO_VIP_DVO));
548 } else {
549 seq_puts(s, "disabled");
550 }
551
552 seq_puts(s, "\n\n HDA encoder: ");
553 crtc = tvout->hda->crtc;
554 if (crtc) {
555 seq_printf(s, "connected to %s path",
556 sti_crtc_is_main(crtc) ? "main" : "aux");
557 DBGFS_DUMP(TVO_HD_SYNC_SEL);
558 DBGFS_DUMP(TVO_HD_DAC_CFG_OFF);
559 tvout_dbg_hd_dac_cfg(s,
560 readl(tvout->regs + TVO_HD_DAC_CFG_OFF));
561 DBGFS_DUMP(TVO_VIP_HDF);
562 tvout_dbg_vip(s, readl(tvout->regs + TVO_VIP_HDF));
563 } else {
564 seq_puts(s, "disabled");
565 }
566
567 seq_puts(s, "\n\n main path configuration");
568 DBGFS_DUMP(TVO_CSC_MAIN_M0);
569 DBGFS_DUMP(TVO_CSC_MAIN_M1);
570 DBGFS_DUMP(TVO_CSC_MAIN_M2);
571 DBGFS_DUMP(TVO_CSC_MAIN_M3);
572 DBGFS_DUMP(TVO_CSC_MAIN_M4);
573 DBGFS_DUMP(TVO_CSC_MAIN_M5);
574 DBGFS_DUMP(TVO_CSC_MAIN_M6);
575 DBGFS_DUMP(TVO_CSC_MAIN_M7);
576 DBGFS_DUMP(TVO_MAIN_IN_VID_FORMAT);
577
578 seq_puts(s, "\n\n auxiliary path configuration");
579 DBGFS_DUMP(TVO_CSC_AUX_M0);
580 DBGFS_DUMP(TVO_CSC_AUX_M2);
581 DBGFS_DUMP(TVO_CSC_AUX_M3);
582 DBGFS_DUMP(TVO_CSC_AUX_M4);
583 DBGFS_DUMP(TVO_CSC_AUX_M5);
584 DBGFS_DUMP(TVO_CSC_AUX_M6);
585 DBGFS_DUMP(TVO_CSC_AUX_M7);
586 DBGFS_DUMP(TVO_AUX_IN_VID_FORMAT);
587 seq_puts(s, "\n");
588
589 mutex_unlock(&dev->struct_mutex);
590 return 0;
591}
592
593static struct drm_info_list tvout_debugfs_files[] = {
594 { "tvout", tvout_dbg_show, 0, NULL },
595};
596
597static void tvout_debugfs_exit(struct sti_tvout *tvout, struct drm_minor *minor)
598{
599 drm_debugfs_remove_files(tvout_debugfs_files,
600 ARRAY_SIZE(tvout_debugfs_files),
601 minor);
602}
603
604static int tvout_debugfs_init(struct sti_tvout *tvout, struct drm_minor *minor)
605{
606 unsigned int i;
607
608 for (i = 0; i < ARRAY_SIZE(tvout_debugfs_files); i++)
609 tvout_debugfs_files[i].data = tvout;
610
611 return drm_debugfs_create_files(tvout_debugfs_files,
612 ARRAY_SIZE(tvout_debugfs_files),
613 minor->debugfs_root, minor);
614}
615
439static void sti_tvout_encoder_dpms(struct drm_encoder *encoder, int mode) 616static void sti_tvout_encoder_dpms(struct drm_encoder *encoder, int mode)
440{ 617{
441} 618}
@@ -446,10 +623,6 @@ static void sti_tvout_encoder_mode_set(struct drm_encoder *encoder,
446{ 623{
447} 624}
448 625
449static void sti_tvout_encoder_prepare(struct drm_encoder *encoder)
450{
451}
452
453static void sti_tvout_encoder_destroy(struct drm_encoder *encoder) 626static void sti_tvout_encoder_destroy(struct drm_encoder *encoder)
454{ 627{
455 struct sti_tvout_encoder *sti_encoder = to_sti_tvout_encoder(encoder); 628 struct sti_tvout_encoder *sti_encoder = to_sti_tvout_encoder(encoder);
@@ -462,10 +635,12 @@ static const struct drm_encoder_funcs sti_tvout_encoder_funcs = {
462 .destroy = sti_tvout_encoder_destroy, 635 .destroy = sti_tvout_encoder_destroy,
463}; 636};
464 637
465static void sti_dvo_encoder_commit(struct drm_encoder *encoder) 638static void sti_dvo_encoder_enable(struct drm_encoder *encoder)
466{ 639{
467 struct sti_tvout *tvout = to_sti_tvout(encoder); 640 struct sti_tvout *tvout = to_sti_tvout(encoder);
468 641
642 tvout_preformatter_set_matrix(tvout, &encoder->crtc->mode);
643
469 tvout_dvo_start(tvout, sti_crtc_is_main(encoder->crtc)); 644 tvout_dvo_start(tvout, sti_crtc_is_main(encoder->crtc));
470} 645}
471 646
@@ -480,8 +655,7 @@ static void sti_dvo_encoder_disable(struct drm_encoder *encoder)
480static const struct drm_encoder_helper_funcs sti_dvo_encoder_helper_funcs = { 655static const struct drm_encoder_helper_funcs sti_dvo_encoder_helper_funcs = {
481 .dpms = sti_tvout_encoder_dpms, 656 .dpms = sti_tvout_encoder_dpms,
482 .mode_set = sti_tvout_encoder_mode_set, 657 .mode_set = sti_tvout_encoder_mode_set,
483 .prepare = sti_tvout_encoder_prepare, 658 .enable = sti_dvo_encoder_enable,
484 .commit = sti_dvo_encoder_commit,
485 .disable = sti_dvo_encoder_disable, 659 .disable = sti_dvo_encoder_disable,
486}; 660};
487 661
@@ -512,10 +686,12 @@ sti_tvout_create_dvo_encoder(struct drm_device *dev,
512 return drm_encoder; 686 return drm_encoder;
513} 687}
514 688
515static void sti_hda_encoder_commit(struct drm_encoder *encoder) 689static void sti_hda_encoder_enable(struct drm_encoder *encoder)
516{ 690{
517 struct sti_tvout *tvout = to_sti_tvout(encoder); 691 struct sti_tvout *tvout = to_sti_tvout(encoder);
518 692
693 tvout_preformatter_set_matrix(tvout, &encoder->crtc->mode);
694
519 tvout_hda_start(tvout, sti_crtc_is_main(encoder->crtc)); 695 tvout_hda_start(tvout, sti_crtc_is_main(encoder->crtc));
520} 696}
521 697
@@ -533,8 +709,7 @@ static void sti_hda_encoder_disable(struct drm_encoder *encoder)
533static const struct drm_encoder_helper_funcs sti_hda_encoder_helper_funcs = { 709static const struct drm_encoder_helper_funcs sti_hda_encoder_helper_funcs = {
534 .dpms = sti_tvout_encoder_dpms, 710 .dpms = sti_tvout_encoder_dpms,
535 .mode_set = sti_tvout_encoder_mode_set, 711 .mode_set = sti_tvout_encoder_mode_set,
536 .prepare = sti_tvout_encoder_prepare, 712 .commit = sti_hda_encoder_enable,
537 .commit = sti_hda_encoder_commit,
538 .disable = sti_hda_encoder_disable, 713 .disable = sti_hda_encoder_disable,
539}; 714};
540 715
@@ -563,10 +738,12 @@ static struct drm_encoder *sti_tvout_create_hda_encoder(struct drm_device *dev,
563 return drm_encoder; 738 return drm_encoder;
564} 739}
565 740
566static void sti_hdmi_encoder_commit(struct drm_encoder *encoder) 741static void sti_hdmi_encoder_enable(struct drm_encoder *encoder)
567{ 742{
568 struct sti_tvout *tvout = to_sti_tvout(encoder); 743 struct sti_tvout *tvout = to_sti_tvout(encoder);
569 744
745 tvout_preformatter_set_matrix(tvout, &encoder->crtc->mode);
746
570 tvout_hdmi_start(tvout, sti_crtc_is_main(encoder->crtc)); 747 tvout_hdmi_start(tvout, sti_crtc_is_main(encoder->crtc));
571} 748}
572 749
@@ -581,8 +758,7 @@ static void sti_hdmi_encoder_disable(struct drm_encoder *encoder)
581static const struct drm_encoder_helper_funcs sti_hdmi_encoder_helper_funcs = { 758static const struct drm_encoder_helper_funcs sti_hdmi_encoder_helper_funcs = {
582 .dpms = sti_tvout_encoder_dpms, 759 .dpms = sti_tvout_encoder_dpms,
583 .mode_set = sti_tvout_encoder_mode_set, 760 .mode_set = sti_tvout_encoder_mode_set,
584 .prepare = sti_tvout_encoder_prepare, 761 .commit = sti_hdmi_encoder_enable,
585 .commit = sti_hdmi_encoder_commit,
586 .disable = sti_hdmi_encoder_disable, 762 .disable = sti_hdmi_encoder_disable,
587}; 763};
588 764
@@ -628,26 +804,24 @@ static void sti_tvout_destroy_encoders(struct sti_tvout *tvout)
628 if (tvout->hda) 804 if (tvout->hda)
629 drm_encoder_cleanup(tvout->hda); 805 drm_encoder_cleanup(tvout->hda);
630 tvout->hda = NULL; 806 tvout->hda = NULL;
807
808 if (tvout->dvo)
809 drm_encoder_cleanup(tvout->dvo);
810 tvout->dvo = NULL;
631} 811}
632 812
633static int sti_tvout_bind(struct device *dev, struct device *master, void *data) 813static int sti_tvout_bind(struct device *dev, struct device *master, void *data)
634{ 814{
635 struct sti_tvout *tvout = dev_get_drvdata(dev); 815 struct sti_tvout *tvout = dev_get_drvdata(dev);
636 struct drm_device *drm_dev = data; 816 struct drm_device *drm_dev = data;
637 unsigned int i;
638 817
639 tvout->drm_dev = drm_dev; 818 tvout->drm_dev = drm_dev;
640 819
641 /* set preformatter matrix */
642 for (i = 0; i < 8; i++) {
643 tvout_write(tvout, rgb_to_ycbcr_601[i],
644 TVO_CSC_MAIN_M0 + (i * 4));
645 tvout_write(tvout, rgb_to_ycbcr_601[i],
646 TVO_CSC_AUX_M0 + (i * 4));
647 }
648
649 sti_tvout_create_encoders(drm_dev, tvout); 820 sti_tvout_create_encoders(drm_dev, tvout);
650 821
822 if (tvout_debugfs_init(tvout, drm_dev->primary))
823 DRM_ERROR("TVOUT debugfs setup failed\n");
824
651 return 0; 825 return 0;
652} 826}
653 827
@@ -655,8 +829,11 @@ static void sti_tvout_unbind(struct device *dev, struct device *master,
655 void *data) 829 void *data)
656{ 830{
657 struct sti_tvout *tvout = dev_get_drvdata(dev); 831 struct sti_tvout *tvout = dev_get_drvdata(dev);
832 struct drm_device *drm_dev = data;
658 833
659 sti_tvout_destroy_encoders(tvout); 834 sti_tvout_destroy_encoders(tvout);
835
836 tvout_debugfs_exit(tvout, drm_dev->primary);
660} 837}
661 838
662static const struct component_ops sti_tvout_ops = { 839static const struct component_ops sti_tvout_ops = {
diff --git a/drivers/gpu/drm/sti/sti_vid.c b/drivers/gpu/drm/sti/sti_vid.c
index a8254cc362a1..5a2c5dc3687b 100644
--- a/drivers/gpu/drm/sti/sti_vid.c
+++ b/drivers/gpu/drm/sti/sti_vid.c
@@ -42,6 +42,104 @@
42#define VID_MPR1_BT709 0x0AC50000 42#define VID_MPR1_BT709 0x0AC50000
43#define VID_MPR2_BT709 0x07150545 43#define VID_MPR2_BT709 0x07150545
44#define VID_MPR3_BT709 0x00000AE8 44#define VID_MPR3_BT709 0x00000AE8
45/* YCbCr to RGB BT709:
46 * R = Y+1.3711Cr
47 * G = Y-0.6992Cr-0.3359Cb
48 * B = Y+1.7344Cb
49 */
50#define VID_MPR0_BT601 0x0A800000
51#define VID_MPR1_BT601 0x0AAF0000
52#define VID_MPR2_BT601 0x094E0754
53#define VID_MPR3_BT601 0x00000ADD
54
55#define VID_MIN_HD_HEIGHT 720
56
57#define DBGFS_DUMP(reg) seq_printf(s, "\n %-25s 0x%08X", #reg, \
58 readl(vid->regs + reg))
59
60static void vid_dbg_ctl(struct seq_file *s, int val)
61{
62 val = val >> 30;
63 seq_puts(s, "\t");
64
65 if (!(val & 1))
66 seq_puts(s, "NOT ");
67 seq_puts(s, "ignored on main mixer - ");
68
69 if (!(val & 2))
70 seq_puts(s, "NOT ");
71 seq_puts(s, "ignored on aux mixer");
72}
73
74static void vid_dbg_vpo(struct seq_file *s, int val)
75{
76 seq_printf(s, "\txdo:%4d\tydo:%4d", val & 0x0FFF, (val >> 16) & 0x0FFF);
77}
78
79static void vid_dbg_vps(struct seq_file *s, int val)
80{
81 seq_printf(s, "\txds:%4d\tyds:%4d", val & 0x0FFF, (val >> 16) & 0x0FFF);
82}
83
84static void vid_dbg_mst(struct seq_file *s, int val)
85{
86 if (val & 1)
87 seq_puts(s, "\tBUFFER UNDERFLOW!");
88}
89
90static int vid_dbg_show(struct seq_file *s, void *arg)
91{
92 struct drm_info_node *node = s->private;
93 struct sti_vid *vid = (struct sti_vid *)node->info_ent->data;
94 struct drm_device *dev = node->minor->dev;
95 int ret;
96
97 ret = mutex_lock_interruptible(&dev->struct_mutex);
98 if (ret)
99 return ret;
100
101 seq_printf(s, "VID: (vaddr= 0x%p)", vid->regs);
102
103 DBGFS_DUMP(VID_CTL);
104 vid_dbg_ctl(s, readl(vid->regs + VID_CTL));
105 DBGFS_DUMP(VID_ALP);
106 DBGFS_DUMP(VID_CLF);
107 DBGFS_DUMP(VID_VPO);
108 vid_dbg_vpo(s, readl(vid->regs + VID_VPO));
109 DBGFS_DUMP(VID_VPS);
110 vid_dbg_vps(s, readl(vid->regs + VID_VPS));
111 DBGFS_DUMP(VID_KEY1);
112 DBGFS_DUMP(VID_KEY2);
113 DBGFS_DUMP(VID_MPR0);
114 DBGFS_DUMP(VID_MPR1);
115 DBGFS_DUMP(VID_MPR2);
116 DBGFS_DUMP(VID_MPR3);
117 DBGFS_DUMP(VID_MST);
118 vid_dbg_mst(s, readl(vid->regs + VID_MST));
119 DBGFS_DUMP(VID_BC);
120 DBGFS_DUMP(VID_TINT);
121 DBGFS_DUMP(VID_CSAT);
122 seq_puts(s, "\n");
123
124 mutex_unlock(&dev->struct_mutex);
125 return 0;
126}
127
128static struct drm_info_list vid_debugfs_files[] = {
129 { "vid", vid_dbg_show, 0, NULL },
130};
131
132static int vid_debugfs_init(struct sti_vid *vid, struct drm_minor *minor)
133{
134 unsigned int i;
135
136 for (i = 0; i < ARRAY_SIZE(vid_debugfs_files); i++)
137 vid_debugfs_files[i].data = vid;
138
139 return drm_debugfs_create_files(vid_debugfs_files,
140 ARRAY_SIZE(vid_debugfs_files),
141 minor->debugfs_root, minor);
142}
45 143
46void sti_vid_commit(struct sti_vid *vid, 144void sti_vid_commit(struct sti_vid *vid,
47 struct drm_plane_state *state) 145 struct drm_plane_state *state)
@@ -52,6 +150,7 @@ void sti_vid_commit(struct sti_vid *vid,
52 int dst_y = state->crtc_y; 150 int dst_y = state->crtc_y;
53 int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x); 151 int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
54 int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y); 152 int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
153 int src_h = state->src_h >> 16;
55 u32 val, ydo, xdo, yds, xds; 154 u32 val, ydo, xdo, yds, xds;
56 155
57 /* Input / output size 156 /* Input / output size
@@ -71,6 +170,19 @@ void sti_vid_commit(struct sti_vid *vid,
71 170
72 writel((ydo << 16) | xdo, vid->regs + VID_VPO); 171 writel((ydo << 16) | xdo, vid->regs + VID_VPO);
73 writel((yds << 16) | xds, vid->regs + VID_VPS); 172 writel((yds << 16) | xds, vid->regs + VID_VPS);
173
174 /* Color conversion parameters */
175 if (src_h >= VID_MIN_HD_HEIGHT) {
176 writel(VID_MPR0_BT709, vid->regs + VID_MPR0);
177 writel(VID_MPR1_BT709, vid->regs + VID_MPR1);
178 writel(VID_MPR2_BT709, vid->regs + VID_MPR2);
179 writel(VID_MPR3_BT709, vid->regs + VID_MPR3);
180 } else {
181 writel(VID_MPR0_BT601, vid->regs + VID_MPR0);
182 writel(VID_MPR1_BT601, vid->regs + VID_MPR1);
183 writel(VID_MPR2_BT601, vid->regs + VID_MPR2);
184 writel(VID_MPR3_BT601, vid->regs + VID_MPR3);
185 }
74} 186}
75 187
76void sti_vid_disable(struct sti_vid *vid) 188void sti_vid_disable(struct sti_vid *vid)
@@ -91,20 +203,14 @@ static void sti_vid_init(struct sti_vid *vid)
91 /* Opaque */ 203 /* Opaque */
92 writel(VID_ALP_OPAQUE, vid->regs + VID_ALP); 204 writel(VID_ALP_OPAQUE, vid->regs + VID_ALP);
93 205
94 /* Color conversion parameters */
95 writel(VID_MPR0_BT709, vid->regs + VID_MPR0);
96 writel(VID_MPR1_BT709, vid->regs + VID_MPR1);
97 writel(VID_MPR2_BT709, vid->regs + VID_MPR2);
98 writel(VID_MPR3_BT709, vid->regs + VID_MPR3);
99
100 /* Brightness, contrast, tint, saturation */ 206 /* Brightness, contrast, tint, saturation */
101 writel(VID_BC_DFLT, vid->regs + VID_BC); 207 writel(VID_BC_DFLT, vid->regs + VID_BC);
102 writel(VID_TINT_DFLT, vid->regs + VID_TINT); 208 writel(VID_TINT_DFLT, vid->regs + VID_TINT);
103 writel(VID_CSAT_DFLT, vid->regs + VID_CSAT); 209 writel(VID_CSAT_DFLT, vid->regs + VID_CSAT);
104} 210}
105 211
106struct sti_vid *sti_vid_create(struct device *dev, int id, 212struct sti_vid *sti_vid_create(struct device *dev, struct drm_device *drm_dev,
107 void __iomem *baseaddr) 213 int id, void __iomem *baseaddr)
108{ 214{
109 struct sti_vid *vid; 215 struct sti_vid *vid;
110 216
@@ -120,5 +226,8 @@ struct sti_vid *sti_vid_create(struct device *dev, int id,
120 226
121 sti_vid_init(vid); 227 sti_vid_init(vid);
122 228
229 if (vid_debugfs_init(vid, drm_dev->primary))
230 DRM_ERROR("VID debugfs setup failed\n");
231
123 return vid; 232 return vid;
124} 233}
diff --git a/drivers/gpu/drm/sti/sti_vid.h b/drivers/gpu/drm/sti/sti_vid.h
index 5dea4791f1d6..6c842344f3d8 100644
--- a/drivers/gpu/drm/sti/sti_vid.h
+++ b/drivers/gpu/drm/sti/sti_vid.h
@@ -23,7 +23,7 @@ struct sti_vid {
23void sti_vid_commit(struct sti_vid *vid, 23void sti_vid_commit(struct sti_vid *vid,
24 struct drm_plane_state *state); 24 struct drm_plane_state *state);
25void sti_vid_disable(struct sti_vid *vid); 25void sti_vid_disable(struct sti_vid *vid);
26struct sti_vid *sti_vid_create(struct device *dev, int id, 26struct sti_vid *sti_vid_create(struct device *dev, struct drm_device *drm_dev,
27 void __iomem *baseaddr); 27 int id, void __iomem *baseaddr);
28 28
29#endif 29#endif
diff --git a/drivers/gpu/drm/sti/sti_vtg.c b/drivers/gpu/drm/sti/sti_vtg.c
index d56630c60039..32c7986b63ab 100644
--- a/drivers/gpu/drm/sti/sti_vtg.c
+++ b/drivers/gpu/drm/sti/sti_vtg.c
@@ -15,8 +15,8 @@
15 15
16#include "sti_vtg.h" 16#include "sti_vtg.h"
17 17
18#define VTG_TYPE_MASTER 0 18#define VTG_MODE_MASTER 0
19#define VTG_TYPE_SLAVE_BY_EXT0 1 19#define VTG_MODE_SLAVE_BY_EXT0 1
20 20
21/* registers offset */ 21/* registers offset */
22#define VTG_MODE 0x0000 22#define VTG_MODE 0x0000
@@ -64,6 +64,9 @@
64/* Delay introduced by the HDMI in nb of pixel */ 64/* Delay introduced by the HDMI in nb of pixel */
65#define HDMI_DELAY (5) 65#define HDMI_DELAY (5)
66 66
67/* Delay introduced by the DVO in nb of pixel */
68#define DVO_DELAY (2)
69
67/* delay introduced by the Arbitrary Waveform Generator in nb of pixels */ 70/* delay introduced by the Arbitrary Waveform Generator in nb of pixels */
68#define AWG_DELAY_HD (-9) 71#define AWG_DELAY_HD (-9)
69#define AWG_DELAY_ED (-8) 72#define AWG_DELAY_ED (-8)
@@ -71,13 +74,61 @@
71 74
72LIST_HEAD(vtg_lookup); 75LIST_HEAD(vtg_lookup);
73 76
77/*
78 * STI VTG register offset structure
79 *
80 *@h_hd: stores the VTG_H_HD_x register offset
81 *@top_v_vd: stores the VTG_TOP_V_VD_x register offset
82 *@bot_v_vd: stores the VTG_BOT_V_VD_x register offset
83 *@top_v_hd: stores the VTG_TOP_V_HD_x register offset
84 *@bot_v_hd: stores the VTG_BOT_V_HD_x register offset
85 */
86struct sti_vtg_regs_offs {
87 u32 h_hd;
88 u32 top_v_vd;
89 u32 bot_v_vd;
90 u32 top_v_hd;
91 u32 bot_v_hd;
92};
93
94#define VTG_MAX_SYNC_OUTPUT 4
95static const struct sti_vtg_regs_offs vtg_regs_offs[VTG_MAX_SYNC_OUTPUT] = {
96 { VTG_H_HD_1,
97 VTG_TOP_V_VD_1, VTG_BOT_V_VD_1, VTG_TOP_V_HD_1, VTG_BOT_V_HD_1 },
98 { VTG_H_HD_2,
99 VTG_TOP_V_VD_2, VTG_BOT_V_VD_2, VTG_TOP_V_HD_2, VTG_BOT_V_HD_2 },
100 { VTG_H_HD_3,
101 VTG_TOP_V_VD_3, VTG_BOT_V_VD_3, VTG_TOP_V_HD_3, VTG_BOT_V_HD_3 },
102 { VTG_H_HD_4,
103 VTG_TOP_V_VD_4, VTG_BOT_V_VD_4, VTG_TOP_V_HD_4, VTG_BOT_V_HD_4 }
104};
105
106/*
107 * STI VTG synchronisation parameters structure
108 *
109 *@hsync: sample number falling and rising edge
110 *@vsync_line_top: vertical top field line number falling and rising edge
111 *@vsync_line_bot: vertical bottom field line number falling and rising edge
112 *@vsync_off_top: vertical top field sample number rising and falling edge
113 *@vsync_off_bot: vertical bottom field sample number rising and falling edge
114 */
115struct sti_vtg_sync_params {
116 u32 hsync;
117 u32 vsync_line_top;
118 u32 vsync_line_bot;
119 u32 vsync_off_top;
120 u32 vsync_off_bot;
121};
122
74/** 123/**
75 * STI VTG structure 124 * STI VTG structure
76 * 125 *
77 * @dev: pointer to device driver 126 * @dev: pointer to device driver
78 * @data: data associated to the device 127 * @np: device node
128 * @regs: register mapping
129 * @sync_params: synchronisation parameters used to generate timings
79 * @irq: VTG irq 130 * @irq: VTG irq
80 * @type: VTG type (main or aux) 131 * @irq_status: store the IRQ status value
81 * @notifier_list: notifier callback 132 * @notifier_list: notifier callback
82 * @crtc: the CRTC for vblank event 133 * @crtc: the CRTC for vblank event
83 * @slave: slave vtg 134 * @slave: slave vtg
@@ -87,6 +138,7 @@ struct sti_vtg {
87 struct device *dev; 138 struct device *dev;
88 struct device_node *np; 139 struct device_node *np;
89 void __iomem *regs; 140 void __iomem *regs;
141 struct sti_vtg_sync_params sync_params[VTG_MAX_SYNC_OUTPUT];
90 int irq; 142 int irq;
91 u32 irq_status; 143 u32 irq_status;
92 struct raw_notifier_head notifier_list; 144 struct raw_notifier_head notifier_list;
@@ -146,13 +198,69 @@ static void vtg_set_output_window(void __iomem *regs,
146 writel(video_bottom_field_stop, regs + VTG_VID_BFS); 198 writel(video_bottom_field_stop, regs + VTG_VID_BFS);
147} 199}
148 200
201static void vtg_set_hsync_vsync_pos(struct sti_vtg_sync_params *sync,
202 int delay,
203 const struct drm_display_mode *mode)
204{
205 long clocksperline, start, stop;
206 u32 risesync_top, fallsync_top;
207 u32 risesync_offs_top, fallsync_offs_top;
208
209 clocksperline = mode->htotal;
210
211 /* Get the hsync position */
212 start = 0;
213 stop = mode->hsync_end - mode->hsync_start;
214
215 start += delay;
216 stop += delay;
217
218 if (start < 0)
219 start += clocksperline;
220 else if (start >= clocksperline)
221 start -= clocksperline;
222
223 if (stop < 0)
224 stop += clocksperline;
225 else if (stop >= clocksperline)
226 stop -= clocksperline;
227
228 sync->hsync = (stop << 16) | start;
229
230 /* Get the vsync position */
231 if (delay >= 0) {
232 risesync_top = 1;
233 fallsync_top = risesync_top;
234 fallsync_top += mode->vsync_end - mode->vsync_start;
235
236 fallsync_offs_top = (u32)delay;
237 risesync_offs_top = (u32)delay;
238 } else {
239 risesync_top = mode->vtotal;
240 fallsync_top = mode->vsync_end - mode->vsync_start;
241
242 fallsync_offs_top = clocksperline + delay;
243 risesync_offs_top = clocksperline + delay;
244 }
245
246 sync->vsync_line_top = (fallsync_top << 16) | risesync_top;
247 sync->vsync_off_top = (fallsync_offs_top << 16) | risesync_offs_top;
248
249 /* Only progressive supported for now */
250 sync->vsync_line_bot = sync->vsync_line_top;
251 sync->vsync_off_bot = sync->vsync_off_top;
252}
253
149static void vtg_set_mode(struct sti_vtg *vtg, 254static void vtg_set_mode(struct sti_vtg *vtg,
150 int type, const struct drm_display_mode *mode) 255 int type,
256 struct sti_vtg_sync_params *sync,
257 const struct drm_display_mode *mode)
151{ 258{
152 u32 tmp; 259 unsigned int i;
153 260
154 if (vtg->slave) 261 if (vtg->slave)
155 vtg_set_mode(vtg->slave, VTG_TYPE_SLAVE_BY_EXT0, mode); 262 vtg_set_mode(vtg->slave, VTG_MODE_SLAVE_BY_EXT0,
263 vtg->sync_params, mode);
156 264
157 /* Set the number of clock cycles per line */ 265 /* Set the number of clock cycles per line */
158 writel(mode->htotal, vtg->regs + VTG_CLKLN); 266 writel(mode->htotal, vtg->regs + VTG_CLKLN);
@@ -163,57 +271,31 @@ static void vtg_set_mode(struct sti_vtg *vtg,
163 /* Program output window */ 271 /* Program output window */
164 vtg_set_output_window(vtg->regs, mode); 272 vtg_set_output_window(vtg->regs, mode);
165 273
166 /* prepare VTG set 1 for HDMI */ 274 /* Set hsync and vsync position for HDMI */
167 tmp = (mode->hsync_end - mode->hsync_start + HDMI_DELAY) << 16; 275 vtg_set_hsync_vsync_pos(&sync[VTG_SYNC_ID_HDMI - 1], HDMI_DELAY, mode);
168 tmp |= HDMI_DELAY; 276
169 writel(tmp, vtg->regs + VTG_H_HD_1); 277 /* Set hsync and vsync position for HD DCS */
170 278 vtg_set_hsync_vsync_pos(&sync[VTG_SYNC_ID_HDDCS - 1], 0, mode);
171 tmp = (mode->vsync_end - mode->vsync_start + 1) << 16; 279
172 tmp |= 1; 280 /* Set hsync and vsync position for HDF */
173 writel(tmp, vtg->regs + VTG_TOP_V_VD_1); 281 vtg_set_hsync_vsync_pos(&sync[VTG_SYNC_ID_HDF - 1], AWG_DELAY_HD, mode);
174 writel(tmp, vtg->regs + VTG_BOT_V_VD_1); 282
175 283 /* Set hsync and vsync position for DVO */
176 tmp = HDMI_DELAY << 16; 284 vtg_set_hsync_vsync_pos(&sync[VTG_SYNC_ID_DVO - 1], DVO_DELAY, mode);
177 tmp |= HDMI_DELAY; 285
178 writel(tmp, vtg->regs + VTG_TOP_V_HD_1); 286 /* Progam the syncs outputs */
179 writel(tmp, vtg->regs + VTG_BOT_V_HD_1); 287 for (i = 0; i < VTG_MAX_SYNC_OUTPUT ; i++) {
180 288 writel(sync[i].hsync,
181 /* prepare VTG set 2 for for HD DCS */ 289 vtg->regs + vtg_regs_offs[i].h_hd);
182 tmp = (mode->hsync_end - mode->hsync_start) << 16; 290 writel(sync[i].vsync_line_top,
183 writel(tmp, vtg->regs + VTG_H_HD_2); 291 vtg->regs + vtg_regs_offs[i].top_v_vd);
184 292 writel(sync[i].vsync_line_bot,
185 tmp = (mode->vsync_end - mode->vsync_start + 1) << 16; 293 vtg->regs + vtg_regs_offs[i].bot_v_vd);
186 tmp |= 1; 294 writel(sync[i].vsync_off_top,
187 writel(tmp, vtg->regs + VTG_TOP_V_VD_2); 295 vtg->regs + vtg_regs_offs[i].top_v_hd);
188 writel(tmp, vtg->regs + VTG_BOT_V_VD_2); 296 writel(sync[i].vsync_off_bot,
189 writel(0, vtg->regs + VTG_TOP_V_HD_2); 297 vtg->regs + vtg_regs_offs[i].bot_v_hd);
190 writel(0, vtg->regs + VTG_BOT_V_HD_2); 298 }
191
192 /* prepare VTG set 3 for HD Analog in HD mode */
193 tmp = (mode->hsync_end - mode->hsync_start + AWG_DELAY_HD) << 16;
194 tmp |= mode->htotal + AWG_DELAY_HD;
195 writel(tmp, vtg->regs + VTG_H_HD_3);
196
197 tmp = (mode->vsync_end - mode->vsync_start) << 16;
198 tmp |= mode->vtotal;
199 writel(tmp, vtg->regs + VTG_TOP_V_VD_3);
200 writel(tmp, vtg->regs + VTG_BOT_V_VD_3);
201
202 tmp = (mode->htotal + AWG_DELAY_HD) << 16;
203 tmp |= mode->htotal + AWG_DELAY_HD;
204 writel(tmp, vtg->regs + VTG_TOP_V_HD_3);
205 writel(tmp, vtg->regs + VTG_BOT_V_HD_3);
206
207 /* Prepare VTG set 4 for DVO */
208 tmp = (mode->hsync_end - mode->hsync_start) << 16;
209 writel(tmp, vtg->regs + VTG_H_HD_4);
210
211 tmp = (mode->vsync_end - mode->vsync_start + 1) << 16;
212 tmp |= 1;
213 writel(tmp, vtg->regs + VTG_TOP_V_VD_4);
214 writel(tmp, vtg->regs + VTG_BOT_V_VD_4);
215 writel(0, vtg->regs + VTG_TOP_V_HD_4);
216 writel(0, vtg->regs + VTG_BOT_V_HD_4);
217 299
218 /* mode */ 300 /* mode */
219 writel(type, vtg->regs + VTG_MODE); 301 writel(type, vtg->regs + VTG_MODE);
@@ -231,7 +313,7 @@ void sti_vtg_set_config(struct sti_vtg *vtg,
231 const struct drm_display_mode *mode) 313 const struct drm_display_mode *mode)
232{ 314{
233 /* write configuration */ 315 /* write configuration */
234 vtg_set_mode(vtg, VTG_TYPE_MASTER, mode); 316 vtg_set_mode(vtg, VTG_MODE_MASTER, vtg->sync_params, mode);
235 317
236 vtg_reset(vtg); 318 vtg_reset(vtg);
237 319
diff --git a/drivers/gpu/drm/sti/sti_vtg.h b/drivers/gpu/drm/sti/sti_vtg.h
index cd2439f89d05..f1dcdf9c2342 100644
--- a/drivers/gpu/drm/sti/sti_vtg.h
+++ b/drivers/gpu/drm/sti/sti_vtg.h
@@ -10,6 +10,11 @@
10#define VTG_TOP_FIELD_EVENT 1 10#define VTG_TOP_FIELD_EVENT 1
11#define VTG_BOTTOM_FIELD_EVENT 2 11#define VTG_BOTTOM_FIELD_EVENT 2
12 12
13#define VTG_SYNC_ID_HDMI 1
14#define VTG_SYNC_ID_HDDCS 2
15#define VTG_SYNC_ID_HDF 3
16#define VTG_SYNC_ID_DVO 4
17
13struct sti_vtg; 18struct sti_vtg;
14struct drm_display_mode; 19struct drm_display_mode;
15struct notifier_block; 20struct notifier_block;