blob: 9127060ecee2095c9c7e84197f0b1ac493fafd68 [file] [log] [blame]
Ronald G. Minnich01ab2d12013-06-30 20:30:58 -07001/*
2 * Copyright 2013 Google Inc.
3 * Copyright © 2012 Intel Corporation
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 *
24 * Authors:
25 * Eugeni Dodonov <eugeni.dodonov@intel.com>
26 *
27 */
28#include <types.h>
29#include <string.h>
30#include <stdlib.h>
31#include <device/device.h>
32#include <device/device.h>
33#include <device/pci_def.h>
34#include <device/pci_ops.h>
35#include <console/console.h>
36#include <delay.h>
37#include <pc80/mc146818rtc.h>
38#include <arch/acpi.h>
39#include <arch/io.h>
40#include <arch/interrupt.h>
41#include <boot/coreboot_tables.h>
42#include <smbios.h>
43#include <device/pci.h>
44#include <ec/google/chromeec/ec.h>
Ronald G. Minnich01ab2d12013-06-30 20:30:58 -070045
46#include <cpu/x86/tsc.h>
47#include <cpu/x86/cache.h>
48#include <cpu/x86/mtrr.h>
49#include <cpu/x86/msr.h>
50#include <edid.h>
51#include <drivers/intel/gma/i915.h>
52
53/* HDMI/DVI modes ignore everything but the last 2 items. So we share
54 * them for both DP and FDI transports, allowing those ports to
55 * automatically adapt to HDMI connections as well.
56 */
57static u32 hsw_ddi_translations_dp[] = {
58 0x00FFFFFF, 0x0006000E, /* DP parameters */
59 0x00D75FFF, 0x0005000A,
60 0x00C30FFF, 0x00040006,
61 0x80AAAFFF, 0x000B0000,
62 0x00FFFFFF, 0x0005000A,
63 0x00D75FFF, 0x000C0004,
64 0x80C30FFF, 0x000B0000,
65 0x00FFFFFF, 0x00040006,
66 0x80D75FFF, 0x000B0000,
67 0x00FFFFFF, 0x00040006 /* HDMI parameters */
68};
69
70static u32 hsw_ddi_translations_fdi[] = {
71 0x00FFFFFF, 0x0007000E, /* FDI parameters */
72 0x00D75FFF, 0x000F000A,
73 0x00C30FFF, 0x00060006,
74 0x00AAAFFF, 0x001E0000,
75 0x00FFFFFF, 0x000F000A,
76 0x00D75FFF, 0x00160004,
77 0x00C30FFF, 0x001E0000,
78 0x00FFFFFF, 0x00060006,
79 0x00D75FFF, 0x001E0000,
80 0x00FFFFFF, 0x00040006 /* HDMI parameters */
81};
82
83/* On Haswell, DDI port buffers must be programmed with correct values
84 * in advance. The buffer values are different for FDI and DP modes,
85 * but the HDMI/DVI fields are shared among those. So we program the DDI
86 * in either FDI or DP modes only, as HDMI connections will work with both
87 * of those.
88 */
Furquan Shaikh77f48cd2013-08-19 10:16:50 -070089static void intel_prepare_ddi_buffers(int port, int use_fdi_mode)
Ronald G. Minnich01ab2d12013-06-30 20:30:58 -070090{
91 u32 reg;
92 int i;
93 u32 *ddi_translations = ((use_fdi_mode) ?
94 hsw_ddi_translations_fdi :
95 hsw_ddi_translations_dp);
96
97 printk(BIOS_SPEW, "Initializing DDI buffers for port %d in %s mode\n",
98 port,
99 use_fdi_mode ? "FDI" : "DP");
100
101 for (i=0,reg=DDI_BUF_TRANS(port);i < ARRAY_SIZE(hsw_ddi_translations_fdi);i++) {
Furquan Shaikh77f48cd2013-08-19 10:16:50 -0700102 gtt_write(reg,ddi_translations[i]);
Ronald G. Minnich01ab2d12013-06-30 20:30:58 -0700103 reg += 4;
104 }
105}
106
Furquan Shaikh77f48cd2013-08-19 10:16:50 -0700107void intel_prepare_ddi(void)
108{
109 int port;
110 u32 use_fdi = 1;
111
112 for (port = PORT_A; port < PORT_E; port++)
113 intel_prepare_ddi_buffers(port, !use_fdi);
114
115 intel_prepare_ddi_buffers(PORT_E, use_fdi);
116}
117
Ronald G. Minnich45df5962013-07-08 14:02:57 -0700118static void intel_wait_ddi_buf_idle(int port)
119{
120 uint32_t reg = DDI_BUF_CTL(port);
121 int i;
122
123 for (i = 0; i < 8; i++) {
124 udelay(1);
Furquan Shaikh77f48cd2013-08-19 10:16:50 -0700125 if (gtt_read(reg) & DDI_BUF_IS_IDLE){
Ronald G. Minnich45df5962013-07-08 14:02:57 -0700126 printk(BIOS_SPEW, "%s: buf is idle (success)\n", __func__);
127 return;
128 }
129 }
130 printk(BIOS_ERR, "Timeout waiting for DDI BUF %d idle bit\n", port);
131}
132
133
134void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp, int port)
135{
Edward O'Callaghanb0cbb2c2014-06-17 15:04:36 +1000136 int wait = 0;
Ronald G. Minnich45df5962013-07-08 14:02:57 -0700137 uint32_t val;
138
Furquan Shaikh77f48cd2013-08-19 10:16:50 -0700139 if (gtt_read(DP_TP_CTL(port)) & DP_TP_CTL_ENABLE) {
140 val = gtt_read(DDI_BUF_CTL(port));
Ronald G. Minnich45df5962013-07-08 14:02:57 -0700141 if (val & DDI_BUF_CTL_ENABLE) {
142 val &= ~DDI_BUF_CTL_ENABLE;
Furquan Shaikh77f48cd2013-08-19 10:16:50 -0700143 gtt_write(val,DDI_BUF_CTL(port));
Ronald G. Minnich45df5962013-07-08 14:02:57 -0700144 wait = 1;
145 }
146
Furquan Shaikh77f48cd2013-08-19 10:16:50 -0700147 val = gtt_read(DP_TP_CTL(port));
Ronald G. Minnich45df5962013-07-08 14:02:57 -0700148 val &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK);
149 val |= DP_TP_CTL_LINK_TRAIN_PAT1;
Furquan Shaikh77f48cd2013-08-19 10:16:50 -0700150 gtt_write(val,DP_TP_CTL(port));
Ronald G. Minnich45df5962013-07-08 14:02:57 -0700151 //POSTING_READ(DP_TP_CTL(port));
152
153 if (wait)
154 intel_wait_ddi_buf_idle(port);
155 }
156
157 val = DP_TP_CTL_ENABLE | DP_TP_CTL_MODE_SST |
158 DP_TP_CTL_LINK_TRAIN_PAT1 | DP_TP_CTL_SCRAMBLE_DISABLE;
159 if (intel_dp->link_configuration[1] & DP_LANE_COUNT_ENHANCED_FRAME_EN)
160 val |= DP_TP_CTL_ENHANCED_FRAME_ENABLE;
Furquan Shaikh77f48cd2013-08-19 10:16:50 -0700161 gtt_write(val,DP_TP_CTL(port));
Ronald G. Minnich45df5962013-07-08 14:02:57 -0700162 //POSTING_READ(DP_TP_CTL(port));
163
164 intel_dp->DP |= DDI_BUF_CTL_ENABLE;
Furquan Shaikh77f48cd2013-08-19 10:16:50 -0700165 gtt_write(intel_dp->DP,DDI_BUF_CTL(port));
Ronald G. Minnich45df5962013-07-08 14:02:57 -0700166 //POSTING_READ(DDI_BUF_CTL(port));
167
168 udelay(600);
169}
Furquan Shaikhd0a81f72013-07-30 12:41:08 -0700170
171u32 intel_ddi_calc_transcoder_flags(u32 pipe_bpp,
172 enum port port,
173 enum pipe pipe,
174 int type,
175 int lane_count,
Furquan Shaikh771c3ac2013-08-01 13:58:17 -0700176 int pf_sz,
177 u8 phsync,
178 u8 pvsync)
Furquan Shaikhd0a81f72013-07-30 12:41:08 -0700179{
180 u32 temp;
181
182 temp = TRANS_DDI_FUNC_ENABLE;
183 temp |= TRANS_DDI_SELECT_PORT(port);
184
185 switch (pipe_bpp) {
186 case 18:
187 temp |= TRANS_DDI_BPC_6;
188 break;
189 case 24:
190 temp |= TRANS_DDI_BPC_8;
191 break;
192 case 30:
193 temp |= TRANS_DDI_BPC_10;
194 break;
195 case 36:
196 temp |= TRANS_DDI_BPC_12;
197 break;
198 default:
Elyes HAOUASe34a6272014-07-21 08:11:18 +0200199 printk(BIOS_ERR, "Invalid pipe_bpp: %d, *** Initialization will not succeed ***\n", pipe_bpp);
Furquan Shaikhd0a81f72013-07-30 12:41:08 -0700200 }
201
202 if (port == PORT_A) {
203 switch (pipe) {
204 case PIPE_A:
205 if (pf_sz)
206 temp |= TRANS_DDI_EDP_INPUT_A_ONOFF;
207 else
208 temp |= TRANS_DDI_EDP_INPUT_A_ON;
209 break;
210 case PIPE_B:
211 temp |= TRANS_DDI_EDP_INPUT_B_ONOFF;
212 break;
213 case PIPE_C:
214 temp |= TRANS_DDI_EDP_INPUT_C_ONOFF;
215 break;
216 default:
217 printk(BIOS_ERR, "Invalid pipe %d\n", pipe);
218 }
219 }
220
Furquan Shaikh771c3ac2013-08-01 13:58:17 -0700221 if (phsync)
222 temp |= TRANS_DDI_PHSYNC;
223
224 if (pvsync)
225 temp |= TRANS_DDI_PVSYNC;
Furquan Shaikhd0a81f72013-07-30 12:41:08 -0700226
227 if (type == INTEL_OUTPUT_HDMI) {
228 /* Need to understand when to set TRANS_DDI_MODE_SELECT_HDMI / TRANS_DDI_MODE_SELECT_DVI */
229 } else if (type == INTEL_OUTPUT_ANALOG) {
230 /* Set TRANS_DDI_MODE_SELECT_FDI with lane_count */
231 } else if (type == INTEL_OUTPUT_DISPLAYPORT ||
232 type == INTEL_OUTPUT_EDP) {
233 temp |= TRANS_DDI_MODE_SELECT_DP_SST;
234
235 temp |= DDI_PORT_WIDTH(lane_count);
236 } else {
237 printk(BIOS_ERR, "Invalid type %d for pipe\n", type);
238 }
239
240 return temp;
241}
Furquan Shaikhdb3157c2013-07-31 16:47:31 -0700242
243enum transcoder intel_ddi_get_transcoder(enum port port,
244 enum pipe pipe)
245{
246 if (port == PORT_A)
247 return TRANSCODER_EDP;
248 return (enum transcoder)pipe;
249}
Furquan Shaikh77f48cd2013-08-19 10:16:50 -0700250
251void intel_ddi_set_pipe_settings(struct intel_dp *intel_dp)
252{
253 u32 val = TRANS_MSA_SYNC_CLK;
254
Ronald G. Minnich9518b562013-09-19 16:45:22 -0700255 switch (intel_dp->pipe_bits_per_pixel) {
Furquan Shaikh77f48cd2013-08-19 10:16:50 -0700256 case 18:
257 val |= TRANS_MSA_6_BPC;
258 break;
259 case 24:
260 val |= TRANS_MSA_8_BPC;
261 break;
262 case 30:
263 val |= TRANS_MSA_10_BPC;
264 break;
265 case 36:
266 val |= TRANS_MSA_12_BPC;
267 break;
268 default:
Ronald G. Minnich9518b562013-09-19 16:45:22 -0700269 printk(BIOS_ERR, "Invalid bpp settings %d\n", intel_dp->pipe_bits_per_pixel);
Furquan Shaikh77f48cd2013-08-19 10:16:50 -0700270 }
271 gtt_write(TRANS_MSA_MISC(intel_dp->transcoder),val);
272}