1 | /* |
---|---|
2 | * Copyright(c) 2011-2016 Intel Corporation. All rights reserved. |
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 FROM, |
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
21 | * SOFTWARE. |
22 | * |
23 | * Authors: |
24 | * Ke Yu |
25 | * Zhiyuan Lv <zhiyuan.lv@intel.com> |
26 | * |
27 | * Contributors: |
28 | * Terrence Xu <terrence.xu@intel.com> |
29 | * Changbin Du <changbin.du@intel.com> |
30 | * Bing Niu <bing.niu@intel.com> |
31 | * Zhi Wang <zhi.a.wang@intel.com> |
32 | * |
33 | */ |
34 | |
35 | #include "display/intel_dp_aux_regs.h" |
36 | #include "display/intel_gmbus_regs.h" |
37 | #include "gvt.h" |
38 | #include "i915_drv.h" |
39 | #include "i915_reg.h" |
40 | |
41 | #define GMBUS1_TOTAL_BYTES_SHIFT 16 |
42 | #define GMBUS1_TOTAL_BYTES_MASK 0x1ff |
43 | #define gmbus1_total_byte_count(v) (((v) >> \ |
44 | GMBUS1_TOTAL_BYTES_SHIFT) & GMBUS1_TOTAL_BYTES_MASK) |
45 | #define gmbus1_slave_addr(v) (((v) & 0xff) >> 1) |
46 | #define gmbus1_slave_index(v) (((v) >> 8) & 0xff) |
47 | #define gmbus1_bus_cycle(v) (((v) >> 25) & 0x7) |
48 | |
49 | /* GMBUS0 bits definitions */ |
50 | #define _GMBUS_PIN_SEL_MASK (0x7) |
51 | |
52 | static unsigned char edid_get_byte(struct intel_vgpu *vgpu) |
53 | { |
54 | struct intel_vgpu_i2c_edid *edid = &vgpu->display.i2c_edid; |
55 | unsigned char chr = 0; |
56 | |
57 | if (edid->state == I2C_NOT_SPECIFIED || !edid->slave_selected) { |
58 | gvt_vgpu_err("Driver tries to read EDID without proper sequence!\n"); |
59 | return 0; |
60 | } |
61 | if (edid->current_edid_read >= EDID_SIZE) { |
62 | gvt_vgpu_err("edid_get_byte() exceeds the size of EDID!\n"); |
63 | return 0; |
64 | } |
65 | |
66 | if (!edid->edid_available) { |
67 | gvt_vgpu_err("Reading EDID but EDID is not available!\n"); |
68 | return 0; |
69 | } |
70 | |
71 | if (intel_vgpu_has_monitor_on_port(vgpu, edid->port)) { |
72 | struct intel_vgpu_edid_data *edid_data = |
73 | intel_vgpu_port(vgpu, edid->port)->edid; |
74 | |
75 | chr = edid_data->edid_block[edid->current_edid_read]; |
76 | edid->current_edid_read++; |
77 | } else { |
78 | gvt_vgpu_err("No EDID available during the reading?\n"); |
79 | } |
80 | return chr; |
81 | } |
82 | |
83 | static inline int cnp_get_port_from_gmbus0(u32 gmbus0) |
84 | { |
85 | int port_select = gmbus0 & _GMBUS_PIN_SEL_MASK; |
86 | int port = -EINVAL; |
87 | |
88 | if (port_select == GMBUS_PIN_1_BXT) |
89 | port = PORT_B; |
90 | else if (port_select == GMBUS_PIN_2_BXT) |
91 | port = PORT_C; |
92 | else if (port_select == GMBUS_PIN_3_BXT) |
93 | port = PORT_D; |
94 | else if (port_select == GMBUS_PIN_4_CNP) |
95 | port = PORT_E; |
96 | return port; |
97 | } |
98 | |
99 | static inline int bxt_get_port_from_gmbus0(u32 gmbus0) |
100 | { |
101 | int port_select = gmbus0 & _GMBUS_PIN_SEL_MASK; |
102 | int port = -EINVAL; |
103 | |
104 | if (port_select == GMBUS_PIN_1_BXT) |
105 | port = PORT_B; |
106 | else if (port_select == GMBUS_PIN_2_BXT) |
107 | port = PORT_C; |
108 | else if (port_select == GMBUS_PIN_3_BXT) |
109 | port = PORT_D; |
110 | return port; |
111 | } |
112 | |
113 | static inline int get_port_from_gmbus0(u32 gmbus0) |
114 | { |
115 | int port_select = gmbus0 & _GMBUS_PIN_SEL_MASK; |
116 | int port = -EINVAL; |
117 | |
118 | if (port_select == GMBUS_PIN_VGADDC) |
119 | port = PORT_E; |
120 | else if (port_select == GMBUS_PIN_DPC) |
121 | port = PORT_C; |
122 | else if (port_select == GMBUS_PIN_DPB) |
123 | port = PORT_B; |
124 | else if (port_select == GMBUS_PIN_DPD) |
125 | port = PORT_D; |
126 | return port; |
127 | } |
128 | |
129 | static void reset_gmbus_controller(struct intel_vgpu *vgpu) |
130 | { |
131 | vgpu_vreg_t(vgpu, PCH_GMBUS2) = GMBUS_HW_RDY; |
132 | if (!vgpu->display.i2c_edid.edid_available) |
133 | vgpu_vreg_t(vgpu, PCH_GMBUS2) |= GMBUS_SATOER; |
134 | vgpu->display.i2c_edid.gmbus.phase = GMBUS_IDLE_PHASE; |
135 | } |
136 | |
137 | /* GMBUS0 */ |
138 | static int gmbus0_mmio_write(struct intel_vgpu *vgpu, |
139 | unsigned int offset, void *p_data, unsigned int bytes) |
140 | { |
141 | struct drm_i915_private *i915 = vgpu->gvt->gt->i915; |
142 | int port, pin_select; |
143 | |
144 | memcpy(&vgpu_vreg(vgpu, offset), p_data, bytes); |
145 | |
146 | pin_select = vgpu_vreg(vgpu, offset) & _GMBUS_PIN_SEL_MASK; |
147 | |
148 | intel_vgpu_init_i2c_edid(vgpu); |
149 | |
150 | if (pin_select == 0) |
151 | return 0; |
152 | |
153 | if (IS_BROXTON(i915)) |
154 | port = bxt_get_port_from_gmbus0(gmbus0: pin_select); |
155 | else if (IS_COFFEELAKE(i915) || IS_COMETLAKE(i915)) |
156 | port = cnp_get_port_from_gmbus0(gmbus0: pin_select); |
157 | else |
158 | port = get_port_from_gmbus0(gmbus0: pin_select); |
159 | if (drm_WARN_ON(&i915->drm, port < 0)) |
160 | return 0; |
161 | |
162 | vgpu->display.i2c_edid.state = I2C_GMBUS; |
163 | vgpu->display.i2c_edid.gmbus.phase = GMBUS_IDLE_PHASE; |
164 | |
165 | vgpu_vreg_t(vgpu, PCH_GMBUS2) &= ~GMBUS_ACTIVE; |
166 | vgpu_vreg_t(vgpu, PCH_GMBUS2) |= GMBUS_HW_RDY | GMBUS_HW_WAIT_PHASE; |
167 | |
168 | if (intel_vgpu_has_monitor_on_port(vgpu, port) && |
169 | !intel_vgpu_port_is_dp(vgpu, port)) { |
170 | vgpu->display.i2c_edid.port = port; |
171 | vgpu->display.i2c_edid.edid_available = true; |
172 | vgpu_vreg_t(vgpu, PCH_GMBUS2) &= ~GMBUS_SATOER; |
173 | } else |
174 | vgpu_vreg_t(vgpu, PCH_GMBUS2) |= GMBUS_SATOER; |
175 | return 0; |
176 | } |
177 | |
178 | static int gmbus1_mmio_write(struct intel_vgpu *vgpu, unsigned int offset, |
179 | void *p_data, unsigned int bytes) |
180 | { |
181 | struct intel_vgpu_i2c_edid *i2c_edid = &vgpu->display.i2c_edid; |
182 | u32 slave_addr; |
183 | u32 wvalue = *(u32 *)p_data; |
184 | |
185 | if (vgpu_vreg(vgpu, offset) & GMBUS_SW_CLR_INT) { |
186 | if (!(wvalue & GMBUS_SW_CLR_INT)) { |
187 | vgpu_vreg(vgpu, offset) &= ~GMBUS_SW_CLR_INT; |
188 | reset_gmbus_controller(vgpu); |
189 | } |
190 | /* |
191 | * TODO: "This bit is cleared to zero when an event |
192 | * causes the HW_RDY bit transition to occur " |
193 | */ |
194 | } else { |
195 | /* |
196 | * per bspec setting this bit can cause: |
197 | * 1) INT status bit cleared |
198 | * 2) HW_RDY bit asserted |
199 | */ |
200 | if (wvalue & GMBUS_SW_CLR_INT) { |
201 | vgpu_vreg_t(vgpu, PCH_GMBUS2) &= ~GMBUS_INT; |
202 | vgpu_vreg_t(vgpu, PCH_GMBUS2) |= GMBUS_HW_RDY; |
203 | } |
204 | |
205 | /* For virtualization, we suppose that HW is always ready, |
206 | * so GMBUS_SW_RDY should always be cleared |
207 | */ |
208 | if (wvalue & GMBUS_SW_RDY) |
209 | wvalue &= ~GMBUS_SW_RDY; |
210 | |
211 | i2c_edid->gmbus.total_byte_count = |
212 | gmbus1_total_byte_count(wvalue); |
213 | slave_addr = gmbus1_slave_addr(wvalue); |
214 | |
215 | /* vgpu gmbus only support EDID */ |
216 | if (slave_addr == EDID_ADDR) { |
217 | i2c_edid->slave_selected = true; |
218 | } else if (slave_addr != 0) { |
219 | gvt_dbg_dpy( |
220 | "vgpu%d: unsupported gmbus slave addr(0x%x)\n" |
221 | " gmbus operations will be ignored.\n", |
222 | vgpu->id, slave_addr); |
223 | } |
224 | |
225 | if (wvalue & GMBUS_CYCLE_INDEX) |
226 | i2c_edid->current_edid_read = |
227 | gmbus1_slave_index(wvalue); |
228 | |
229 | i2c_edid->gmbus.cycle_type = gmbus1_bus_cycle(wvalue); |
230 | switch (gmbus1_bus_cycle(wvalue)) { |
231 | case GMBUS_NOCYCLE: |
232 | break; |
233 | case GMBUS_STOP: |
234 | /* From spec: |
235 | * This can only cause a STOP to be generated |
236 | * if a GMBUS cycle is generated, the GMBUS is |
237 | * currently in a data/wait/idle phase, or it is in a |
238 | * WAIT phase |
239 | */ |
240 | if (gmbus1_bus_cycle(vgpu_vreg(vgpu, offset)) |
241 | != GMBUS_NOCYCLE) { |
242 | intel_vgpu_init_i2c_edid(vgpu); |
243 | /* After the 'stop' cycle, hw state would become |
244 | * 'stop phase' and then 'idle phase' after a |
245 | * few milliseconds. In emulation, we just set |
246 | * it as 'idle phase' ('stop phase' is not |
247 | * visible in gmbus interface) |
248 | */ |
249 | i2c_edid->gmbus.phase = GMBUS_IDLE_PHASE; |
250 | vgpu_vreg_t(vgpu, PCH_GMBUS2) &= ~GMBUS_ACTIVE; |
251 | } |
252 | break; |
253 | case NIDX_NS_W: |
254 | case IDX_NS_W: |
255 | case NIDX_STOP: |
256 | case IDX_STOP: |
257 | /* From hw spec the GMBUS phase |
258 | * transition like this: |
259 | * START (-->INDEX) -->DATA |
260 | */ |
261 | i2c_edid->gmbus.phase = GMBUS_DATA_PHASE; |
262 | vgpu_vreg_t(vgpu, PCH_GMBUS2) |= GMBUS_ACTIVE; |
263 | break; |
264 | default: |
265 | gvt_vgpu_err("Unknown/reserved GMBUS cycle detected!\n"); |
266 | break; |
267 | } |
268 | /* |
269 | * From hw spec the WAIT state will be |
270 | * cleared: |
271 | * (1) in a new GMBUS cycle |
272 | * (2) by generating a stop |
273 | */ |
274 | vgpu_vreg(vgpu, offset) = wvalue; |
275 | } |
276 | return 0; |
277 | } |
278 | |
279 | static int gmbus3_mmio_write(struct intel_vgpu *vgpu, unsigned int offset, |
280 | void *p_data, unsigned int bytes) |
281 | { |
282 | struct drm_i915_private *i915 = vgpu->gvt->gt->i915; |
283 | |
284 | drm_WARN_ON(&i915->drm, 1); |
285 | return 0; |
286 | } |
287 | |
288 | static int gmbus3_mmio_read(struct intel_vgpu *vgpu, unsigned int offset, |
289 | void *p_data, unsigned int bytes) |
290 | { |
291 | int i; |
292 | unsigned char byte_data; |
293 | struct intel_vgpu_i2c_edid *i2c_edid = &vgpu->display.i2c_edid; |
294 | int byte_left = i2c_edid->gmbus.total_byte_count - |
295 | i2c_edid->current_edid_read; |
296 | int byte_count = byte_left; |
297 | u32 reg_data = 0; |
298 | |
299 | /* Data can only be recevied if previous settings correct */ |
300 | if (vgpu_vreg_t(vgpu, PCH_GMBUS1) & GMBUS_SLAVE_READ) { |
301 | if (byte_left <= 0) { |
302 | memcpy(p_data, &vgpu_vreg(vgpu, offset), bytes); |
303 | return 0; |
304 | } |
305 | |
306 | if (byte_count > 4) |
307 | byte_count = 4; |
308 | for (i = 0; i < byte_count; i++) { |
309 | byte_data = edid_get_byte(vgpu); |
310 | reg_data |= (byte_data << (i << 3)); |
311 | } |
312 | |
313 | memcpy(&vgpu_vreg(vgpu, offset), ®_data, byte_count); |
314 | memcpy(p_data, &vgpu_vreg(vgpu, offset), bytes); |
315 | |
316 | if (byte_left <= 4) { |
317 | switch (i2c_edid->gmbus.cycle_type) { |
318 | case NIDX_STOP: |
319 | case IDX_STOP: |
320 | i2c_edid->gmbus.phase = GMBUS_IDLE_PHASE; |
321 | break; |
322 | case NIDX_NS_W: |
323 | case IDX_NS_W: |
324 | default: |
325 | i2c_edid->gmbus.phase = GMBUS_WAIT_PHASE; |
326 | break; |
327 | } |
328 | intel_vgpu_init_i2c_edid(vgpu); |
329 | } |
330 | /* |
331 | * Read GMBUS3 during send operation, |
332 | * return the latest written value |
333 | */ |
334 | } else { |
335 | memcpy(p_data, &vgpu_vreg(vgpu, offset), bytes); |
336 | gvt_vgpu_err("warning: gmbus3 read with nothing returned\n"); |
337 | } |
338 | return 0; |
339 | } |
340 | |
341 | static int gmbus2_mmio_read(struct intel_vgpu *vgpu, unsigned int offset, |
342 | void *p_data, unsigned int bytes) |
343 | { |
344 | u32 value = vgpu_vreg(vgpu, offset); |
345 | |
346 | if (!(vgpu_vreg(vgpu, offset) & GMBUS_INUSE)) |
347 | vgpu_vreg(vgpu, offset) |= GMBUS_INUSE; |
348 | memcpy(p_data, (void *)&value, bytes); |
349 | return 0; |
350 | } |
351 | |
352 | static int gmbus2_mmio_write(struct intel_vgpu *vgpu, unsigned int offset, |
353 | void *p_data, unsigned int bytes) |
354 | { |
355 | u32 wvalue = *(u32 *)p_data; |
356 | |
357 | if (wvalue & GMBUS_INUSE) |
358 | vgpu_vreg(vgpu, offset) &= ~GMBUS_INUSE; |
359 | /* All other bits are read-only */ |
360 | return 0; |
361 | } |
362 | |
363 | /** |
364 | * intel_gvt_i2c_handle_gmbus_read - emulate gmbus register mmio read |
365 | * @vgpu: a vGPU |
366 | * @offset: reg offset |
367 | * @p_data: data return buffer |
368 | * @bytes: access data length |
369 | * |
370 | * This function is used to emulate gmbus register mmio read |
371 | * |
372 | * Returns: |
373 | * Zero on success, negative error code if failed. |
374 | * |
375 | */ |
376 | int intel_gvt_i2c_handle_gmbus_read(struct intel_vgpu *vgpu, |
377 | unsigned int offset, void *p_data, unsigned int bytes) |
378 | { |
379 | struct drm_i915_private *i915 = vgpu->gvt->gt->i915; |
380 | |
381 | if (drm_WARN_ON(&i915->drm, bytes > 8 && (offset & (bytes - 1)))) |
382 | return -EINVAL; |
383 | |
384 | if (offset == i915_mmio_reg_offset(PCH_GMBUS2)) |
385 | return gmbus2_mmio_read(vgpu, offset, p_data, bytes); |
386 | else if (offset == i915_mmio_reg_offset(PCH_GMBUS3)) |
387 | return gmbus3_mmio_read(vgpu, offset, p_data, bytes); |
388 | |
389 | memcpy(p_data, &vgpu_vreg(vgpu, offset), bytes); |
390 | return 0; |
391 | } |
392 | |
393 | /** |
394 | * intel_gvt_i2c_handle_gmbus_write - emulate gmbus register mmio write |
395 | * @vgpu: a vGPU |
396 | * @offset: reg offset |
397 | * @p_data: data return buffer |
398 | * @bytes: access data length |
399 | * |
400 | * This function is used to emulate gmbus register mmio write |
401 | * |
402 | * Returns: |
403 | * Zero on success, negative error code if failed. |
404 | * |
405 | */ |
406 | int intel_gvt_i2c_handle_gmbus_write(struct intel_vgpu *vgpu, |
407 | unsigned int offset, void *p_data, unsigned int bytes) |
408 | { |
409 | struct drm_i915_private *i915 = vgpu->gvt->gt->i915; |
410 | |
411 | if (drm_WARN_ON(&i915->drm, bytes > 8 && (offset & (bytes - 1)))) |
412 | return -EINVAL; |
413 | |
414 | if (offset == i915_mmio_reg_offset(PCH_GMBUS0)) |
415 | return gmbus0_mmio_write(vgpu, offset, p_data, bytes); |
416 | else if (offset == i915_mmio_reg_offset(PCH_GMBUS1)) |
417 | return gmbus1_mmio_write(vgpu, offset, p_data, bytes); |
418 | else if (offset == i915_mmio_reg_offset(PCH_GMBUS2)) |
419 | return gmbus2_mmio_write(vgpu, offset, p_data, bytes); |
420 | else if (offset == i915_mmio_reg_offset(PCH_GMBUS3)) |
421 | return gmbus3_mmio_write(vgpu, offset, p_data, bytes); |
422 | |
423 | memcpy(&vgpu_vreg(vgpu, offset), p_data, bytes); |
424 | return 0; |
425 | } |
426 | |
427 | enum { |
428 | AUX_CH_CTL = 0, |
429 | AUX_CH_DATA1, |
430 | AUX_CH_DATA2, |
431 | AUX_CH_DATA3, |
432 | AUX_CH_DATA4, |
433 | AUX_CH_DATA5 |
434 | }; |
435 | |
436 | static inline int get_aux_ch_reg(unsigned int offset) |
437 | { |
438 | int reg; |
439 | |
440 | switch (offset & 0xff) { |
441 | case 0x10: |
442 | reg = AUX_CH_CTL; |
443 | break; |
444 | case 0x14: |
445 | reg = AUX_CH_DATA1; |
446 | break; |
447 | case 0x18: |
448 | reg = AUX_CH_DATA2; |
449 | break; |
450 | case 0x1c: |
451 | reg = AUX_CH_DATA3; |
452 | break; |
453 | case 0x20: |
454 | reg = AUX_CH_DATA4; |
455 | break; |
456 | case 0x24: |
457 | reg = AUX_CH_DATA5; |
458 | break; |
459 | default: |
460 | reg = -1; |
461 | break; |
462 | } |
463 | return reg; |
464 | } |
465 | |
466 | /** |
467 | * intel_gvt_i2c_handle_aux_ch_write - emulate AUX channel register write |
468 | * @vgpu: a vGPU |
469 | * @port_idx: port index |
470 | * @offset: reg offset |
471 | * @p_data: write ptr |
472 | * |
473 | * This function is used to emulate AUX channel register write |
474 | * |
475 | */ |
476 | void intel_gvt_i2c_handle_aux_ch_write(struct intel_vgpu *vgpu, |
477 | int port_idx, |
478 | unsigned int offset, |
479 | void *p_data) |
480 | { |
481 | struct drm_i915_private *i915 = vgpu->gvt->gt->i915; |
482 | struct intel_vgpu_i2c_edid *i2c_edid = &vgpu->display.i2c_edid; |
483 | int msg_length, ret_msg_size; |
484 | int msg, addr, ctrl, op; |
485 | u32 value = *(u32 *)p_data; |
486 | int aux_data_for_write = 0; |
487 | int reg = get_aux_ch_reg(offset); |
488 | |
489 | if (reg != AUX_CH_CTL) { |
490 | vgpu_vreg(vgpu, offset) = value; |
491 | return; |
492 | } |
493 | |
494 | msg_length = REG_FIELD_GET(DP_AUX_CH_CTL_MESSAGE_SIZE_MASK, value); |
495 | |
496 | // check the msg in DATA register. |
497 | msg = vgpu_vreg(vgpu, offset + 4); |
498 | addr = (msg >> 8) & 0xffff; |
499 | ctrl = (msg >> 24) & 0xff; |
500 | op = ctrl >> 4; |
501 | if (!(value & DP_AUX_CH_CTL_SEND_BUSY)) { |
502 | /* The ctl write to clear some states */ |
503 | return; |
504 | } |
505 | |
506 | /* Always set the wanted value for vms. */ |
507 | ret_msg_size = (((op & 0x1) == GVT_AUX_I2C_READ) ? 2 : 1); |
508 | vgpu_vreg(vgpu, offset) = |
509 | DP_AUX_CH_CTL_DONE | |
510 | DP_AUX_CH_CTL_MESSAGE_SIZE(ret_msg_size); |
511 | |
512 | if (msg_length == 3) { |
513 | if (!(op & GVT_AUX_I2C_MOT)) { |
514 | /* stop */ |
515 | intel_vgpu_init_i2c_edid(vgpu); |
516 | } else { |
517 | /* start or restart */ |
518 | i2c_edid->aux_ch.i2c_over_aux_ch = true; |
519 | i2c_edid->aux_ch.aux_ch_mot = true; |
520 | if (addr == 0) { |
521 | /* reset the address */ |
522 | intel_vgpu_init_i2c_edid(vgpu); |
523 | } else if (addr == EDID_ADDR) { |
524 | i2c_edid->state = I2C_AUX_CH; |
525 | i2c_edid->port = port_idx; |
526 | i2c_edid->slave_selected = true; |
527 | if (intel_vgpu_has_monitor_on_port(vgpu, |
528 | port_idx) && |
529 | intel_vgpu_port_is_dp(vgpu, port_idx)) |
530 | i2c_edid->edid_available = true; |
531 | } |
532 | } |
533 | } else if ((op & 0x1) == GVT_AUX_I2C_WRITE) { |
534 | /* TODO |
535 | * We only support EDID reading from I2C_over_AUX. And |
536 | * we do not expect the index mode to be used. Right now |
537 | * the WRITE operation is ignored. It is good enough to |
538 | * support the gfx driver to do EDID access. |
539 | */ |
540 | } else { |
541 | if (drm_WARN_ON(&i915->drm, (op & 0x1) != GVT_AUX_I2C_READ)) |
542 | return; |
543 | if (drm_WARN_ON(&i915->drm, msg_length != 4)) |
544 | return; |
545 | if (i2c_edid->edid_available && i2c_edid->slave_selected) { |
546 | unsigned char val = edid_get_byte(vgpu); |
547 | |
548 | aux_data_for_write = (val << 16); |
549 | } else |
550 | aux_data_for_write = (0xff << 16); |
551 | } |
552 | /* write the return value in AUX_CH_DATA reg which includes: |
553 | * ACK of I2C_WRITE |
554 | * returned byte if it is READ |
555 | */ |
556 | aux_data_for_write |= GVT_AUX_I2C_REPLY_ACK << 24; |
557 | vgpu_vreg(vgpu, offset + 4) = aux_data_for_write; |
558 | } |
559 | |
560 | /** |
561 | * intel_vgpu_init_i2c_edid - initialize vGPU i2c edid emulation |
562 | * @vgpu: a vGPU |
563 | * |
564 | * This function is used to initialize vGPU i2c edid emulation stuffs |
565 | * |
566 | */ |
567 | void intel_vgpu_init_i2c_edid(struct intel_vgpu *vgpu) |
568 | { |
569 | struct intel_vgpu_i2c_edid *edid = &vgpu->display.i2c_edid; |
570 | |
571 | edid->state = I2C_NOT_SPECIFIED; |
572 | |
573 | edid->port = -1; |
574 | edid->slave_selected = false; |
575 | edid->edid_available = false; |
576 | edid->current_edid_read = 0; |
577 | |
578 | memset(&edid->gmbus, 0, sizeof(struct intel_vgpu_i2c_gmbus)); |
579 | |
580 | edid->aux_ch.i2c_over_aux_ch = false; |
581 | edid->aux_ch.aux_ch_mot = false; |
582 | } |
583 |
Definitions
- edid_get_byte
- cnp_get_port_from_gmbus0
- bxt_get_port_from_gmbus0
- get_port_from_gmbus0
- reset_gmbus_controller
- gmbus0_mmio_write
- gmbus1_mmio_write
- gmbus3_mmio_write
- gmbus3_mmio_read
- gmbus2_mmio_read
- gmbus2_mmio_write
- intel_gvt_i2c_handle_gmbus_read
- intel_gvt_i2c_handle_gmbus_write
- get_aux_ch_reg
- intel_gvt_i2c_handle_aux_ch_write
Improve your Profiling and Debugging skills
Find out more