| /* |
| * Copyright 2013 Google Inc. |
| * Copyright © 2009 Keith Packard |
| * |
| * Permission to use, copy, modify, distribute, and sell this software and its |
| * documentation for any purpose is hereby granted without fee, provided that |
| * the above copyright notice appear in all copies and that both that copyright |
| * notice and this permission notice appear in supporting documentation, and |
| * that the name of the copyright holders not be used in advertising or |
| * publicity pertaining to distribution of the software without specific, |
| * written prior permission. The copyright holders make no representations |
| * about the suitability of this software for any purpose. It is provided "as |
| * is" without express or implied warranty. |
| * |
| * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
| * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO |
| * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
| * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
| * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
| * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE |
| * OF THIS SOFTWARE. |
| */ |
| |
| #include <console/console.h> |
| #include <stdint.h> |
| #include <delay.h> |
| #include <drivers/intel/gma/i915.h> |
| #include <string.h> |
| |
| #include <edid.h> |
| |
| /* reduced a lot for coreboot. */ |
| /** |
| * DOC: dp helpers |
| * |
| * These functions contain some common logic and helpers at various |
| * abstraction levels to deal with Display Port sink devices and |
| * related things like DP aux channel transfers, EDID reading over DP |
| * aux channels, decoding certain DPCD blocks, ... |
| */ |
| |
| |
| /* Helpers for DP link training */ |
| static u8 dp_link_status(u8 link_status[DP_LINK_STATUS_SIZE], int r) |
| { |
| printk(BIOS_SPEW, "%s: %d, %d, %d\n", __func__, |
| r, r - DP_LANE0_1_STATUS, |
| link_status[r - DP_LANE0_1_STATUS]); |
| return link_status[r - DP_LANE0_1_STATUS]; |
| } |
| |
| static u8 dp_get_lane_status(u8 link_status[DP_LINK_STATUS_SIZE], |
| int lane) |
| { |
| int i = DP_LANE0_1_STATUS + (lane >> 1); |
| int s = (lane & 1) * 4; |
| u8 l = dp_link_status(link_status, i); |
| return (l >> s) & 0xf; |
| } |
| |
| int drm_dp_channel_eq_ok(u8 link_status[DP_LINK_STATUS_SIZE], |
| int lane_count) |
| { |
| u8 lane_align; |
| u8 lane_status; |
| int lane; |
| |
| lane_align = dp_link_status(link_status, |
| DP_LANE_ALIGN_STATUS_UPDATED); |
| if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0) |
| return 0; |
| for (lane = 0; lane < lane_count; lane++) { |
| lane_status = dp_get_lane_status(link_status, lane); |
| if ((lane_status & DP_CHANNEL_EQ_BITS) != DP_CHANNEL_EQ_BITS) |
| return 0; |
| } |
| return 1; |
| } |
| |
| int drm_dp_clock_recovery_ok(u8 link_status[DP_LINK_STATUS_SIZE], |
| int lane_count) |
| { |
| int lane; |
| u8 lane_status; |
| |
| for (lane = 0; lane < lane_count; lane++) { |
| lane_status = dp_get_lane_status(link_status, lane); |
| if ((lane_status & DP_LANE_CR_DONE) == 0) |
| return 0; |
| } |
| return 1; |
| } |
| |
| u8 drm_dp_get_adjust_request_voltage(u8 link_status[DP_LINK_STATUS_SIZE], |
| int lane) |
| { |
| int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); |
| int s = ((lane & 1) ? |
| DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT : |
| DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT); |
| u8 l = dp_link_status(link_status, i); |
| |
| printk(BIOS_SPEW, "%s: i %d s %d l %d return %d\n", |
| __func__, i, s, l, |
| ((l >> s) & 0x3) << DP_TRAIN_VOLTAGE_SWING_SHIFT); |
| return ((l >> s) & 0x3) << DP_TRAIN_VOLTAGE_SWING_SHIFT; |
| } |
| |
| u8 drm_dp_get_adjust_request_pre_emphasis(u8 link_status[DP_LINK_STATUS_SIZE], |
| int lane) |
| { |
| int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); |
| int s = ((lane & 1) ? |
| DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT : |
| DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT); |
| u8 l = dp_link_status(link_status, i); |
| |
| return ((l >> s) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT; |
| } |