7974471e37
Change-Id: I05d6d22664155ac8478e665733f816776e277c22 Signed-off-by: Edward O'Callaghan <eocallaghan@alterapraxis.com> Reviewed-on: http://review.coreboot.org/6200 Tested-by: build bot (Jenkins) Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
166 lines
4.8 KiB
C
166 lines
4.8 KiB
C
/*
|
|
* Copyright 2013 Google Inc.
|
|
* Copyright © 2008 Intel Corporation
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice (including the next
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
* Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
* IN THE SOFTWARE.
|
|
*
|
|
* Authors:
|
|
* Keith Packard <keithp@keithp.com>
|
|
*
|
|
*/
|
|
|
|
#include <console/console.h>
|
|
#include <stdint.h>
|
|
#include <delay.h>
|
|
#include "i915io.h"
|
|
|
|
u32
|
|
pack_aux(u32 *src32, int src_bytes)
|
|
{
|
|
u8 *src = (u8 *)src32;
|
|
int i;
|
|
u32 v = 0;
|
|
|
|
if (src_bytes > 4)
|
|
src_bytes = 4;
|
|
for (i = 0; i < src_bytes; i++)
|
|
v |= ((u32) src[i]) << ((3-i) * 8);
|
|
return v;
|
|
}
|
|
|
|
void
|
|
unpack_aux(u32 src, u32 *dst32, int dst_bytes)
|
|
{
|
|
u8 *dst = (u8 *)dst32;
|
|
|
|
int i;
|
|
if (dst_bytes > 4)
|
|
dst_bytes = 4;
|
|
for (i = 0; i < dst_bytes; i++)
|
|
dst[i] = src >> ((3-i) * 8);
|
|
}
|
|
|
|
int
|
|
intel_dp_aux_ch(u32 ch_ctl, u32 ch_data, u32 *send, int send_bytes,
|
|
u32 *recv, int recv_size)
|
|
{
|
|
int i;
|
|
int recv_bytes;
|
|
u32 status;
|
|
u32 aux_clock_divider;
|
|
int try, precharge = 5;
|
|
|
|
/* The clock divider is based off the hrawclk,
|
|
* and would like to run at 2MHz. So, take the
|
|
* hrawclk value and divide by 2 and use that
|
|
*
|
|
* Note that PCH attached eDP panels should use a 125MHz input
|
|
* clock divider.
|
|
*/
|
|
/* 200 on link */
|
|
aux_clock_divider = 200; /* SNB & IVB eDP input clock at 400Mhz */
|
|
|
|
/* Try to wait for any previous AUX channel activity */
|
|
for (try = 0; try < 3; try++) {
|
|
status = io_i915_READ32(ch_ctl);
|
|
if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0)
|
|
break;
|
|
udelay(1000);
|
|
}
|
|
|
|
if (try == 3) {
|
|
printk(BIOS_SPEW, "[000000.0] [drm:%s], ", __func__);
|
|
printk(BIOS_SPEW, "dp_aux_ch not started status 0x%08lx\n",
|
|
io_i915_READ32(ch_ctl));
|
|
return -1;
|
|
}
|
|
|
|
/* Must try at least 3 times according to DP spec */
|
|
for (try = 0; try < 5; try++) {
|
|
/* Load the send data into the aux channel data registers */
|
|
for (i = 0; i < send_bytes; i += 4)
|
|
io_i915_WRITE32(send[i], ch_data + i);
|
|
|
|
/* Send the command and wait for it to complete */
|
|
io_i915_WRITE32(
|
|
DP_AUX_CH_CTL_SEND_BUSY |
|
|
DP_AUX_CH_CTL_TIME_OUT_400us |
|
|
(send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
|
|
(precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
|
|
(aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT) |
|
|
DP_AUX_CH_CTL_DONE |
|
|
DP_AUX_CH_CTL_TIME_OUT_ERROR |
|
|
DP_AUX_CH_CTL_RECEIVE_ERROR, ch_ctl);
|
|
for (;;) {
|
|
status = io_i915_READ32(ch_ctl);
|
|
if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0)
|
|
break;
|
|
udelay(100);
|
|
}
|
|
|
|
/* Clear done status and any errors */
|
|
io_i915_WRITE32(
|
|
status |
|
|
DP_AUX_CH_CTL_DONE |
|
|
DP_AUX_CH_CTL_TIME_OUT_ERROR |
|
|
DP_AUX_CH_CTL_RECEIVE_ERROR, ch_ctl);
|
|
|
|
if (status & (DP_AUX_CH_CTL_TIME_OUT_ERROR |
|
|
DP_AUX_CH_CTL_RECEIVE_ERROR))
|
|
continue;
|
|
if (status & DP_AUX_CH_CTL_DONE)
|
|
break;
|
|
}
|
|
|
|
if ((status & DP_AUX_CH_CTL_DONE) == 0) {
|
|
printk(BIOS_SPEW, "[000000.0] [drm:%s], ", __func__);
|
|
printk(BIOS_SPEW, "dp_aux_ch not done status 0x%08x\n", status);
|
|
return -1;
|
|
}
|
|
|
|
/* Check for timeout or receive error.
|
|
* Timeouts occur when the sink is not connected
|
|
*/
|
|
if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
|
|
printk(BIOS_SPEW, "[000000.0] [drm:%s], ", __func__);
|
|
printk(BIOS_SPEW, "dp_aux_ch receive error status 0x%08x\n", status);
|
|
return -1;
|
|
}
|
|
|
|
/* Timeouts occur when the device isn't connected, so they're
|
|
* "normal" -- don't fill the kernel log with these */
|
|
if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) {
|
|
printk(BIOS_SPEW, "[000000.0] [drm:%s], ", __func__);
|
|
printk(BIOS_SPEW, "dp_aux_ch timeout status 0x%08x\n", status);
|
|
return -1;
|
|
}
|
|
|
|
/* Unload any bytes sent back from the other side */
|
|
recv_bytes = ((status & DP_AUX_CH_CTL_MESSAGE_SIZE_MASK) >>
|
|
DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT);
|
|
if (recv_bytes > recv_size)
|
|
recv_bytes = recv_size;
|
|
|
|
for (i = 0; i < recv_bytes; i += 4)
|
|
unpack_aux(io_i915_READ32(ch_data + i),
|
|
recv + i, recv_bytes - i);
|
|
|
|
return recv_bytes;
|
|
}
|