brcm2708: update linux 4.4 patches to latest version
[openwrt/openwrt.git] / target / linux / brcm2708 / patches-4.4 / 0522-drm-vc4-Set-up-the-AVI-and-SPD-infoframes.patch
1 From 76359522fa9c449fb715d1933523c153cc1871f3 Mon Sep 17 00:00:00 2001
2 From: Eric Anholt <eric@anholt.net>
3 Date: Thu, 29 Sep 2016 10:34:21 -0700
4 Subject: [PATCH] drm/vc4: Set up the AVI and SPD infoframes.
5
6 Fixes a purple bar on the left side of the screen with my Dell
7 2408WFP. It will also be required for supporting the double-clocked
8 video modes.
9
10 Signed-off-by: Eric Anholt <eric@anholt.net>
11 ---
12 drivers/gpu/drm/vc4/vc4_hdmi.c | 136 +++++++++++++++++++++++++++++++++++++++--
13 drivers/gpu/drm/vc4/vc4_regs.h | 5 ++
14 2 files changed, 136 insertions(+), 5 deletions(-)
15
16 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c
17 +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
18 @@ -62,6 +62,8 @@ struct vc4_hdmi {
19 struct vc4_hdmi_encoder {
20 struct vc4_encoder base;
21 bool hdmi_monitor;
22 + bool limited_rgb_range;
23 + bool rgb_range_selectable;
24 };
25
26 static inline struct vc4_hdmi_encoder *
27 @@ -205,6 +207,12 @@ static int vc4_hdmi_connector_get_modes(
28 return -ENODEV;
29
30 vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
31 +
32 + if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
33 + vc4_encoder->rgb_range_selectable =
34 + drm_rgb_quant_range_selectable(edid);
35 + }
36 +
37 drm_mode_connector_update_edid_property(connector, edid);
38 ret = drm_add_edid_modes(connector, edid);
39
40 @@ -281,6 +289,117 @@ static const struct drm_encoder_funcs vc
41 .destroy = vc4_hdmi_encoder_destroy,
42 };
43
44 +static int vc4_hdmi_stop_packet(struct drm_encoder *encoder,
45 + enum hdmi_infoframe_type type)
46 +{
47 + struct drm_device *dev = encoder->dev;
48 + struct vc4_dev *vc4 = to_vc4_dev(dev);
49 + u32 packet_id = type - 0x80;
50 +
51 + HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
52 + HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) & ~BIT(packet_id));
53 +
54 + return wait_for(!(HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) &
55 + BIT(packet_id)), 100);
56 +}
57 +
58 +static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder,
59 + union hdmi_infoframe *frame)
60 +{
61 + struct drm_device *dev = encoder->dev;
62 + struct vc4_dev *vc4 = to_vc4_dev(dev);
63 + u32 packet_id = frame->any.type - 0x80;
64 + u32 packet_reg = VC4_HDMI_GCP_0 + VC4_HDMI_PACKET_STRIDE * packet_id;
65 + uint8_t buffer[VC4_HDMI_PACKET_STRIDE];
66 + ssize_t len, i;
67 + int ret;
68 +
69 + WARN_ONCE(!(HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) &
70 + VC4_HDMI_RAM_PACKET_ENABLE),
71 + "Packet RAM has to be on to store the packet.");
72 +
73 + len = hdmi_infoframe_pack(frame, buffer, sizeof(buffer));
74 + if (len < 0)
75 + return;
76 +
77 + ret = vc4_hdmi_stop_packet(encoder, frame->any.type);
78 + if (ret) {
79 + DRM_ERROR("Failed to wait for infoframe to go idle: %d\n", ret);
80 + return;
81 + }
82 +
83 + for (i = 0; i < len; i += 7) {
84 + HDMI_WRITE(packet_reg,
85 + buffer[i + 0] << 0 |
86 + buffer[i + 1] << 8 |
87 + buffer[i + 2] << 16);
88 + packet_reg += 4;
89 +
90 + HDMI_WRITE(packet_reg,
91 + buffer[i + 3] << 0 |
92 + buffer[i + 4] << 8 |
93 + buffer[i + 5] << 16 |
94 + buffer[i + 6] << 24);
95 + packet_reg += 4;
96 + }
97 +
98 + HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
99 + HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) | BIT(packet_id));
100 + ret = wait_for((HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) &
101 + BIT(packet_id)), 100);
102 + if (ret)
103 + DRM_ERROR("Failed to wait for infoframe to start: %d\n", ret);
104 +}
105 +
106 +static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
107 +{
108 + struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
109 + struct drm_crtc *crtc = encoder->crtc;
110 + const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
111 + union hdmi_infoframe frame;
112 + int ret;
113 +
114 + ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode);
115 + if (ret < 0) {
116 + DRM_ERROR("couldn't fill AVI infoframe\n");
117 + return;
118 + }
119 +
120 + if (vc4_encoder->rgb_range_selectable) {
121 + if (vc4_encoder->limited_rgb_range) {
122 + frame.avi.quantization_range =
123 + HDMI_QUANTIZATION_RANGE_LIMITED;
124 + } else {
125 + frame.avi.quantization_range =
126 + HDMI_QUANTIZATION_RANGE_FULL;
127 + }
128 + }
129 +
130 + vc4_hdmi_write_infoframe(encoder, &frame);
131 +}
132 +
133 +static void vc4_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
134 +{
135 + union hdmi_infoframe frame;
136 + int ret;
137 +
138 + ret = hdmi_spd_infoframe_init(&frame.spd, "Broadcom", "Videocore");
139 + if (ret < 0) {
140 + DRM_ERROR("couldn't fill SPD infoframe\n");
141 + return;
142 + }
143 +
144 + frame.spd.sdi = HDMI_SPD_SDI_PC;
145 +
146 + vc4_hdmi_write_infoframe(encoder, &frame);
147 +}
148 +
149 +static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder)
150 +{
151 + vc4_hdmi_set_avi_infoframe(encoder);
152 + vc4_hdmi_set_spd_infoframe(encoder);
153 +}
154 +
155 static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
156 struct drm_display_mode *unadjusted_mode,
157 struct drm_display_mode *mode)
158 @@ -349,8 +468,9 @@ static void vc4_hdmi_encoder_mode_set(st
159
160 if (vc4_encoder->hdmi_monitor && drm_match_cea_mode(mode) > 1) {
161 /* CEA VICs other than #1 requre limited range RGB
162 - * output. Apply a colorspace conversion to squash
163 - * 0-255 down to 16-235. The matrix here is:
164 + * output unless overridden by an AVI infoframe.
165 + * Apply a colorspace conversion to squash 0-255 down
166 + * to 16-235. The matrix here is:
167 *
168 * [ 0 0 0.8594 16]
169 * [ 0 0.8594 0 16]
170 @@ -368,6 +488,9 @@ static void vc4_hdmi_encoder_mode_set(st
171 HD_WRITE(VC4_HD_CSC_24_23, (0x100 << 16) | 0x000);
172 HD_WRITE(VC4_HD_CSC_32_31, (0x000 << 16) | 0x6e0);
173 HD_WRITE(VC4_HD_CSC_34_33, (0x100 << 16) | 0x000);
174 + vc4_encoder->limited_rgb_range = true;
175 + } else {
176 + vc4_encoder->limited_rgb_range = false;
177 }
178
179 /* The RGB order applies even when CSC is disabled. */
180 @@ -386,6 +509,8 @@ static void vc4_hdmi_encoder_disable(str
181 struct drm_device *dev = encoder->dev;
182 struct vc4_dev *vc4 = to_vc4_dev(dev);
183
184 + HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, 0);
185 +
186 HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16);
187 HD_WRITE(VC4_HD_VID_CTL,
188 HD_READ(VC4_HD_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE);
189 @@ -438,9 +563,10 @@ static void vc4_hdmi_encoder_enable(stru
190 HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) |
191 VC4_HDMI_SCHEDULER_CONTROL_VERT_ALWAYS_KEEPOUT);
192
193 - /* XXX: Set HDMI_RAM_PACKET_CONFIG (1 << 16) and set
194 - * up the infoframe.
195 - */
196 + HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
197 + VC4_HDMI_RAM_PACKET_ENABLE);
198 +
199 + vc4_hdmi_set_infoframes(encoder);
200
201 drift = HDMI_READ(VC4_HDMI_FIFO_CTL);
202 drift &= VC4_HDMI_FIFO_VALID_WRITE_MASK;
203 --- a/drivers/gpu/drm/vc4/vc4_regs.h
204 +++ b/drivers/gpu/drm/vc4/vc4_regs.h
205 @@ -443,6 +443,8 @@
206 #define VC4_HDMI_RAM_PACKET_CONFIG 0x0a0
207 # define VC4_HDMI_RAM_PACKET_ENABLE BIT(16)
208
209 +#define VC4_HDMI_RAM_PACKET_STATUS 0x0a4
210 +
211 #define VC4_HDMI_HORZA 0x0c4
212 # define VC4_HDMI_HORZA_VPOS BIT(14)
213 # define VC4_HDMI_HORZA_HPOS BIT(13)
214 @@ -504,6 +506,9 @@
215
216 #define VC4_HDMI_TX_PHY_RESET_CTL 0x2c0
217
218 +#define VC4_HDMI_GCP_0 0x400
219 +#define VC4_HDMI_PACKET_STRIDE 0x24
220 +
221 #define VC4_HD_M_CTL 0x00c
222 # define VC4_HD_M_REGISTER_FILE_STANDBY (3 << 6)
223 # define VC4_HD_M_RAM_STANDBY (3 << 4)