]> git.ipfire.org Git - thirdparty/kernel/stable.git/blame - drivers/gpu/drm/i915/icl_dsi.c
drm/i915/icl: DSI vswing programming sequence
[thirdparty/kernel/stable.git] / drivers / gpu / drm / i915 / icl_dsi.c
CommitLineData
fcfe0bdc
MC
1/*
2 * Copyright © 2018 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 *
23 * Authors:
24 * Madhav Chauhan <madhav.chauhan@intel.com>
25 * Jani Nikula <jani.nikula@intel.com>
26 */
27
28#include "intel_dsi.h"
29
3f4b9d9d
MC
30static void dsi_program_swing_and_deemphasis(struct intel_encoder *encoder)
31{
32 struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
33 struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
34 enum port port;
35 u32 tmp;
36 int lane;
37
38 for_each_dsi_port(port, intel_dsi->ports) {
39
40 /*
41 * Program voltage swing and pre-emphasis level values as per
42 * table in BSPEC under DDI buffer programing
43 */
44 tmp = I915_READ(ICL_PORT_TX_DW5_LN0(port));
45 tmp &= ~(SCALING_MODE_SEL_MASK | RTERM_SELECT_MASK);
46 tmp |= SCALING_MODE_SEL(0x2);
47 tmp |= TAP2_DISABLE | TAP3_DISABLE;
48 tmp |= RTERM_SELECT(0x6);
49 I915_WRITE(ICL_PORT_TX_DW5_GRP(port), tmp);
50
51 tmp = I915_READ(ICL_PORT_TX_DW5_AUX(port));
52 tmp &= ~(SCALING_MODE_SEL_MASK | RTERM_SELECT_MASK);
53 tmp |= SCALING_MODE_SEL(0x2);
54 tmp |= TAP2_DISABLE | TAP3_DISABLE;
55 tmp |= RTERM_SELECT(0x6);
56 I915_WRITE(ICL_PORT_TX_DW5_AUX(port), tmp);
57
58 tmp = I915_READ(ICL_PORT_TX_DW2_LN0(port));
59 tmp &= ~(SWING_SEL_LOWER_MASK | SWING_SEL_UPPER_MASK |
60 RCOMP_SCALAR_MASK);
61 tmp |= SWING_SEL_UPPER(0x2);
62 tmp |= SWING_SEL_LOWER(0x2);
63 tmp |= RCOMP_SCALAR(0x98);
64 I915_WRITE(ICL_PORT_TX_DW2_GRP(port), tmp);
65
66 tmp = I915_READ(ICL_PORT_TX_DW2_AUX(port));
67 tmp &= ~(SWING_SEL_LOWER_MASK | SWING_SEL_UPPER_MASK |
68 RCOMP_SCALAR_MASK);
69 tmp |= SWING_SEL_UPPER(0x2);
70 tmp |= SWING_SEL_LOWER(0x2);
71 tmp |= RCOMP_SCALAR(0x98);
72 I915_WRITE(ICL_PORT_TX_DW2_AUX(port), tmp);
73
74 tmp = I915_READ(ICL_PORT_TX_DW4_AUX(port));
75 tmp &= ~(POST_CURSOR_1_MASK | POST_CURSOR_2_MASK |
76 CURSOR_COEFF_MASK);
77 tmp |= POST_CURSOR_1(0x0);
78 tmp |= POST_CURSOR_2(0x0);
79 tmp |= CURSOR_COEFF(0x3f);
80 I915_WRITE(ICL_PORT_TX_DW4_AUX(port), tmp);
81
82 for (lane = 0; lane <= 3; lane++) {
83 /* Bspec: must not use GRP register for write */
84 tmp = I915_READ(ICL_PORT_TX_DW4_LN(port, lane));
85 tmp &= ~(POST_CURSOR_1_MASK | POST_CURSOR_2_MASK |
86 CURSOR_COEFF_MASK);
87 tmp |= POST_CURSOR_1(0x0);
88 tmp |= POST_CURSOR_2(0x0);
89 tmp |= CURSOR_COEFF(0x3f);
90 I915_WRITE(ICL_PORT_TX_DW4_LN(port, lane), tmp);
91 }
92 }
93}
94
fcfe0bdc
MC
95static void gen11_dsi_program_esc_clk_div(struct intel_encoder *encoder)
96{
97 struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
98 struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
99 enum port port;
100 u32 bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
101 u32 afe_clk_khz; /* 8X Clock */
102 u32 esc_clk_div_m;
103
104 afe_clk_khz = DIV_ROUND_CLOSEST(intel_dsi->pclk * bpp,
105 intel_dsi->lane_count);
106
107 esc_clk_div_m = DIV_ROUND_UP(afe_clk_khz, DSI_MAX_ESC_CLK);
108
109 for_each_dsi_port(port, intel_dsi->ports) {
110 I915_WRITE(ICL_DSI_ESC_CLK_DIV(port),
111 esc_clk_div_m & ICL_ESC_CLK_DIV_MASK);
112 POSTING_READ(ICL_DSI_ESC_CLK_DIV(port));
113 }
114
115 for_each_dsi_port(port, intel_dsi->ports) {
116 I915_WRITE(ICL_DPHY_ESC_CLK_DIV(port),
117 esc_clk_div_m & ICL_ESC_CLK_DIV_MASK);
118 POSTING_READ(ICL_DPHY_ESC_CLK_DIV(port));
119 }
120}
121
b1cb21a5
MC
122static void gen11_dsi_enable_io_power(struct intel_encoder *encoder)
123{
124 struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
125 struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
126 enum port port;
127 u32 tmp;
128
129 for_each_dsi_port(port, intel_dsi->ports) {
130 tmp = I915_READ(ICL_DSI_IO_MODECTL(port));
131 tmp |= COMBO_PHY_MODE_DSI;
132 I915_WRITE(ICL_DSI_IO_MODECTL(port), tmp);
133 }
134
135 for_each_dsi_port(port, intel_dsi->ports) {
136 intel_display_power_get(dev_priv, port == PORT_A ?
137 POWER_DOMAIN_PORT_DDI_A_IO :
138 POWER_DOMAIN_PORT_DDI_B_IO);
139 }
140}
141
45f09f7a
MC
142static void gen11_dsi_power_up_lanes(struct intel_encoder *encoder)
143{
144 struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
145 struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
146 enum port port;
147 u32 tmp;
148 u32 lane_mask;
149
150 switch (intel_dsi->lane_count) {
151 case 1:
152 lane_mask = PWR_DOWN_LN_3_1_0;
153 break;
154 case 2:
155 lane_mask = PWR_DOWN_LN_3_1;
156 break;
157 case 3:
158 lane_mask = PWR_DOWN_LN_3;
159 break;
160 case 4:
161 default:
162 lane_mask = PWR_UP_ALL_LANES;
163 break;
164 }
165
166 for_each_dsi_port(port, intel_dsi->ports) {
167 tmp = I915_READ(ICL_PORT_CL_DW10(port));
168 tmp &= ~PWR_DOWN_LN_MASK;
169 I915_WRITE(ICL_PORT_CL_DW10(port), tmp | lane_mask);
170 }
171}
172
fc41001d
MC
173static void gen11_dsi_config_phy_lanes_sequence(struct intel_encoder *encoder)
174{
175 struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
176 struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
177 enum port port;
178 u32 tmp;
179 int lane;
180
181 /* Step 4b(i) set loadgen select for transmit and aux lanes */
182 for_each_dsi_port(port, intel_dsi->ports) {
183 tmp = I915_READ(ICL_PORT_TX_DW4_AUX(port));
184 tmp &= ~LOADGEN_SELECT;
185 I915_WRITE(ICL_PORT_TX_DW4_AUX(port), tmp);
186 for (lane = 0; lane <= 3; lane++) {
187 tmp = I915_READ(ICL_PORT_TX_DW4_LN(port, lane));
188 tmp &= ~LOADGEN_SELECT;
189 if (lane != 2)
190 tmp |= LOADGEN_SELECT;
191 I915_WRITE(ICL_PORT_TX_DW4_LN(port, lane), tmp);
192 }
193 }
194
195 /* Step 4b(ii) set latency optimization for transmit and aux lanes */
196 for_each_dsi_port(port, intel_dsi->ports) {
197 tmp = I915_READ(ICL_PORT_TX_DW2_AUX(port));
198 tmp &= ~FRC_LATENCY_OPTIM_MASK;
199 tmp |= FRC_LATENCY_OPTIM_VAL(0x5);
200 I915_WRITE(ICL_PORT_TX_DW2_AUX(port), tmp);
201 tmp = I915_READ(ICL_PORT_TX_DW2_LN0(port));
202 tmp &= ~FRC_LATENCY_OPTIM_MASK;
203 tmp |= FRC_LATENCY_OPTIM_VAL(0x5);
204 I915_WRITE(ICL_PORT_TX_DW2_GRP(port), tmp);
205 }
206
207}
208
3f4b9d9d
MC
209static void gen11_dsi_voltage_swing_program_seq(struct intel_encoder *encoder)
210{
211 struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
212 struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
213 u32 tmp;
214 enum port port;
215
216 /* clear common keeper enable bit */
217 for_each_dsi_port(port, intel_dsi->ports) {
218 tmp = I915_READ(ICL_PORT_PCS_DW1_LN0(port));
219 tmp &= ~COMMON_KEEPER_EN;
220 I915_WRITE(ICL_PORT_PCS_DW1_GRP(port), tmp);
221 tmp = I915_READ(ICL_PORT_PCS_DW1_AUX(port));
222 tmp &= ~COMMON_KEEPER_EN;
223 I915_WRITE(ICL_PORT_PCS_DW1_AUX(port), tmp);
224 }
225
226 /*
227 * Set SUS Clock Config bitfield to 11b
228 * Note: loadgen select program is done
229 * as part of lane phy sequence configuration
230 */
231 for_each_dsi_port(port, intel_dsi->ports) {
232 tmp = I915_READ(ICL_PORT_CL_DW5(port));
233 tmp |= SUS_CLOCK_CONFIG;
234 I915_WRITE(ICL_PORT_CL_DW5(port), tmp);
235 }
236
237 /* Clear training enable to change swing values */
238 for_each_dsi_port(port, intel_dsi->ports) {
239 tmp = I915_READ(ICL_PORT_TX_DW5_LN0(port));
240 tmp &= ~TX_TRAINING_EN;
241 I915_WRITE(ICL_PORT_TX_DW5_GRP(port), tmp);
242 tmp = I915_READ(ICL_PORT_TX_DW5_AUX(port));
243 tmp &= ~TX_TRAINING_EN;
244 I915_WRITE(ICL_PORT_TX_DW5_AUX(port), tmp);
245 }
246
247 /* Program swing and de-emphasis */
248 dsi_program_swing_and_deemphasis(encoder);
249
250 /* Set training enable to trigger update */
251 for_each_dsi_port(port, intel_dsi->ports) {
252 tmp = I915_READ(ICL_PORT_TX_DW5_LN0(port));
253 tmp |= TX_TRAINING_EN;
254 I915_WRITE(ICL_PORT_TX_DW5_GRP(port), tmp);
255 tmp = I915_READ(ICL_PORT_TX_DW5_AUX(port));
256 tmp |= TX_TRAINING_EN;
257 I915_WRITE(ICL_PORT_TX_DW5_AUX(port), tmp);
258 }
259}
260
45f09f7a
MC
261static void gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder)
262{
263 /* step 4a: power up all lanes of the DDI used by DSI */
264 gen11_dsi_power_up_lanes(encoder);
fc41001d
MC
265
266 /* step 4b: configure lane sequencing of the Combo-PHY transmitters */
267 gen11_dsi_config_phy_lanes_sequence(encoder);
3f4b9d9d
MC
268
269 /* step 4c: configure voltage swing and skew */
270 gen11_dsi_voltage_swing_program_seq(encoder);
45f09f7a
MC
271}
272
fcfe0bdc
MC
273static void __attribute__((unused))
274gen11_dsi_pre_enable(struct intel_encoder *encoder,
275 const struct intel_crtc_state *pipe_config,
276 const struct drm_connector_state *conn_state)
277{
b1cb21a5
MC
278 /* step2: enable IO power */
279 gen11_dsi_enable_io_power(encoder);
280
fcfe0bdc
MC
281 /* step3: enable DSI PLL */
282 gen11_dsi_program_esc_clk_div(encoder);
45f09f7a
MC
283
284 /* step4: enable DSI port and DPHY */
285 gen11_dsi_enable_port_and_phy(encoder);
fcfe0bdc 286}