Ronald G. Minnich | 2a66d6b | 2013-03-28 17:01:43 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2013 Google Inc. |
| 3 | * Copyright © 2008 Intel Corporation |
| 4 | * |
| 5 | * |
| 6 | * Permission is hereby granted, free of charge, to any person obtaining a |
| 7 | * copy of this software and associated documentation files (the "Software"), |
| 8 | * to deal in the Software without restriction, including without limitation |
| 9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| 10 | * and/or sell copies of the Software, and to permit persons to whom the |
| 11 | * Software is furnished to do so, subject to the following conditions: |
| 12 | * |
| 13 | * The above copyright notice and this permission notice (including the next |
| 14 | * paragraph) shall be included in all copies or substantial portions of the |
| 15 | * Software. |
| 16 | * |
| 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| 20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| 22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
| 23 | * IN THE SOFTWARE. |
| 24 | * |
| 25 | * Authors: |
| 26 | * Keith Packard <keithp@keithp.com> |
| 27 | * |
| 28 | */ |
| 29 | |
| 30 | #include <console/console.h> |
| 31 | #include <stdint.h> |
| 32 | #include <delay.h> |
Ronald G. Minnich | 78c3e33 | 2013-04-24 09:50:56 -0700 | [diff] [blame] | 33 | #include <device/i915.h> |
Ronald G. Minnich | 2a66d6b | 2013-03-28 17:01:43 -0700 | [diff] [blame] | 34 | |
| 35 | u32 |
| 36 | pack_aux(u32 *src32, int src_bytes) |
| 37 | { |
| 38 | u8 *src = (u8 *)src32; |
| 39 | int i; |
| 40 | u32 v = 0; |
| 41 | |
| 42 | if (src_bytes > 4) |
| 43 | src_bytes = 4; |
| 44 | for (i = 0; i < src_bytes; i++) |
| 45 | v |= ((u32) src[i]) << ((3-i) * 8); |
| 46 | return v; |
| 47 | } |
| 48 | |
| 49 | void |
Ronald G. Minnich | 4f78b18 | 2013-04-17 16:57:30 -0700 | [diff] [blame] | 50 | unpack_aux(u32 src, u8 *dst, int dst_bytes) |
Ronald G. Minnich | 2a66d6b | 2013-03-28 17:01:43 -0700 | [diff] [blame] | 51 | { |
Ronald G. Minnich | 2a66d6b | 2013-03-28 17:01:43 -0700 | [diff] [blame] | 52 | |
| 53 | int i; |
| 54 | if (dst_bytes > 4) |
| 55 | dst_bytes = 4; |
| 56 | for (i = 0; i < dst_bytes; i++) |
| 57 | dst[i] = src >> ((3-i) * 8); |
| 58 | } |
| 59 | |
| 60 | int |
| 61 | intel_dp_aux_ch(u32 ch_ctl, u32 ch_data, u32 *send, int send_bytes, |
Ronald G. Minnich | 4f78b18 | 2013-04-17 16:57:30 -0700 | [diff] [blame] | 62 | u8 *recv, int recv_size) |
Ronald G. Minnich | 2a66d6b | 2013-03-28 17:01:43 -0700 | [diff] [blame] | 63 | { |
| 64 | int i; |
| 65 | int recv_bytes; |
| 66 | u32 status; |
| 67 | u32 aux_clock_divider; |
| 68 | int try, precharge = 5; |
| 69 | |
| 70 | /* The clock divider is based off the hrawclk, |
| 71 | * and would like to run at 2MHz. So, take the |
| 72 | * hrawclk value and divide by 2 and use that |
| 73 | * |
| 74 | * Note that PCH attached eDP panels should use a 125MHz input |
| 75 | * clock divider. |
| 76 | */ |
| 77 | /* 200 on link */ |
| 78 | aux_clock_divider = 200; /* SNB & IVB eDP input clock at 400Mhz */ |
| 79 | |
| 80 | /* Try to wait for any previous AUX channel activity */ |
| 81 | for (try = 0; try < 3; try++) { |
Ronald G. Minnich | 78c3e33 | 2013-04-24 09:50:56 -0700 | [diff] [blame] | 82 | status = io_i915_read32(ch_ctl); |
Ronald G. Minnich | 2a66d6b | 2013-03-28 17:01:43 -0700 | [diff] [blame] | 83 | if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0) |
| 84 | break; |
| 85 | udelay(1000); |
| 86 | } |
| 87 | |
| 88 | if (try == 3) { |
| 89 | printk(BIOS_SPEW, "[000000.0] [drm:%s], ", __func__); |
Ronald G. Minnich | 78c3e33 | 2013-04-24 09:50:56 -0700 | [diff] [blame] | 90 | status = io_i915_read32(ch_ctl); |
| 91 | printk(BIOS_SPEW, "dp_aux_ch not started status 0x%08x\n", |
| 92 | status); |
Ronald G. Minnich | 2a66d6b | 2013-03-28 17:01:43 -0700 | [diff] [blame] | 93 | return -1; |
| 94 | } |
| 95 | |
| 96 | /* Must try at least 3 times according to DP spec */ |
| 97 | for (try = 0; try < 5; try++) { |
| 98 | /* Load the send data into the aux channel data registers */ |
| 99 | for (i = 0; i < send_bytes; i += 4) |
Ronald G. Minnich | 78c3e33 | 2013-04-24 09:50:56 -0700 | [diff] [blame] | 100 | io_i915_write32(send[i], ch_data + i); |
Ronald G. Minnich | 2a66d6b | 2013-03-28 17:01:43 -0700 | [diff] [blame] | 101 | |
| 102 | /* Send the command and wait for it to complete */ |
Ronald G. Minnich | 78c3e33 | 2013-04-24 09:50:56 -0700 | [diff] [blame] | 103 | io_i915_write32( |
Ronald G. Minnich | 2a66d6b | 2013-03-28 17:01:43 -0700 | [diff] [blame] | 104 | DP_AUX_CH_CTL_SEND_BUSY | |
| 105 | DP_AUX_CH_CTL_TIME_OUT_400us | |
| 106 | (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) | |
| 107 | (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) | |
| 108 | (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT) | |
| 109 | DP_AUX_CH_CTL_DONE | |
| 110 | DP_AUX_CH_CTL_TIME_OUT_ERROR | |
| 111 | DP_AUX_CH_CTL_RECEIVE_ERROR, ch_ctl); |
| 112 | for (;;) { |
Ronald G. Minnich | 78c3e33 | 2013-04-24 09:50:56 -0700 | [diff] [blame] | 113 | status = io_i915_read32(ch_ctl); |
Ronald G. Minnich | 2a66d6b | 2013-03-28 17:01:43 -0700 | [diff] [blame] | 114 | if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0) |
| 115 | break; |
| 116 | udelay(100); |
| 117 | } |
| 118 | |
| 119 | /* Clear done status and any errors */ |
Ronald G. Minnich | 78c3e33 | 2013-04-24 09:50:56 -0700 | [diff] [blame] | 120 | io_i915_write32( |
Ronald G. Minnich | 2a66d6b | 2013-03-28 17:01:43 -0700 | [diff] [blame] | 121 | status | |
| 122 | DP_AUX_CH_CTL_DONE | |
| 123 | DP_AUX_CH_CTL_TIME_OUT_ERROR | |
| 124 | DP_AUX_CH_CTL_RECEIVE_ERROR, ch_ctl); |
| 125 | |
| 126 | if (status & (DP_AUX_CH_CTL_TIME_OUT_ERROR | |
| 127 | DP_AUX_CH_CTL_RECEIVE_ERROR)) |
| 128 | continue; |
| 129 | if (status & DP_AUX_CH_CTL_DONE) |
| 130 | break; |
| 131 | } |
| 132 | |
| 133 | if ((status & DP_AUX_CH_CTL_DONE) == 0) { |
| 134 | printk(BIOS_SPEW, "[000000.0] [drm:%s], ", __func__); |
| 135 | printk(BIOS_SPEW, "dp_aux_ch not done status 0x%08x\n", status); |
| 136 | return -1; |
| 137 | } |
| 138 | |
| 139 | /* Check for timeout or receive error. |
| 140 | * Timeouts occur when the sink is not connected |
| 141 | */ |
| 142 | if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) { |
| 143 | printk(BIOS_SPEW, "[000000.0] [drm:%s], ", __func__); |
| 144 | printk(BIOS_SPEW, "dp_aux_ch receive error status 0x%08x\n", status); |
| 145 | return -1; |
| 146 | } |
| 147 | |
| 148 | /* Timeouts occur when the device isn't connected, so they're |
| 149 | * "normal" -- don't fill the kernel log with these */ |
| 150 | if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) { |
| 151 | printk(BIOS_SPEW, "[000000.0] [drm:%s], ", __func__); |
| 152 | printk(BIOS_SPEW, "dp_aux_ch timeout status 0x%08x\n", status); |
| 153 | return -1; |
| 154 | } |
| 155 | |
| 156 | /* Unload any bytes sent back from the other side */ |
| 157 | recv_bytes = ((status & DP_AUX_CH_CTL_MESSAGE_SIZE_MASK) >> |
| 158 | DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT); |
| 159 | if (recv_bytes > recv_size) |
| 160 | recv_bytes = recv_size; |
| 161 | |
| 162 | for (i = 0; i < recv_bytes; i += 4) |
Ronald G. Minnich | 78c3e33 | 2013-04-24 09:50:56 -0700 | [diff] [blame] | 163 | unpack_aux(io_i915_read32(ch_data + i), |
Ronald G. Minnich | 2a66d6b | 2013-03-28 17:01:43 -0700 | [diff] [blame] | 164 | recv + i, recv_bytes - i); |
| 165 | |
| 166 | return recv_bytes; |
| 167 | } |